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 new file mode 100644 index 00000000000..d2b3f9087b0 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,33 @@ +// 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 +{ + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + "onCreateCommand": "/bin/bash ./.devcontainer/setup.sh", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "bungcip.better-toml", + "ms-vscode.cpptools", + "GitHub.copilot", + "dustypomerleau.rust-syntax", + "serayuzgur.crates", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "mutantdino.resourcemonitor", + "DavidAnson.vscode-markdownlint" + ] + } + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100644 index 00000000000..1c753fddfd7 --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo "🚀 Setting up Rushstack codespace..." + +# Set local git config +echo "🔑 Setting up local git config..." +git config --local user.email ${GITHUB_USER}@users.noreply.github.com +git config --local user.name "$(git config --system user.name)" + +# Install Rush and Heft Dependencies +echo "📦 Installing Rush, Heft, & Prettier dependencies..." +npm install -g @microsoft/rush @rushstack/heft prettier + +# Install Rush Dependencies +echo "📦 Installing monorepo dependencies..." +rush install + +echo "🚀 Codespace setup complete! " +echo "🙏 Thank you for contributing to Rushstack! " \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 79c416bb9fb..ef65b43d255 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ -# Prevent Git to auto detect text files and perform LF normalization. -* -text +# Set default behavior to automatically normalize line endings. +* text=auto # The item with `binary` is treated as binary file. # The item with `eol=lf` is converted to LF on checkin, back to LF on checkout. @@ -17,45 +17,17 @@ # > git add .gitattributes # > git commit -m "Apply end-of-line normalization based on updated .gitattributes file" -*.aspx text eol=crlf -*.bowerrc text eol=lf *.cmd text eol=crlf -*.command text eol=lf -*.config text eol=crlf -*.cs text eol=crlf -*.csproj text eol=crlf -*.css text eol=crlf *.dll binary -*.editorconfig text eol=lf *.eot binary -*.example text eol=crlf *.exe binary *.gif binary -*.gitattributes text eol=lf -*.gitignore text eol=lf -*.gitmodules text eol=lf -*.html text eol=crlf *.ico binary *.jpg binary -*.js text eol=crlf -*.json text eol=crlf -*.less text eol=crlf -*.map text eol=lf -*.md text eol=crlf -*.npmignore text eol=lf *.png binary -*.ps1 text eol=crlf -*.rels text eol=crlf -*.resx text eol=crlf -*.scss text eol=crlf -*.sln text eol=crlf -*.svg text elf=lf -*.ts text eol=crlf -*.tsx text eol=crlf *.ttf binary *.woff binary *.wsp binary -*.xml text eol=crlf # NPM "bin" scripts MUST have LF, or else the executable fails to run on Mac. # This fnmatch expression only matches files in a "bin" folder and without @@ -64,7 +36,7 @@ # Don't allow people to merge changes to these generated files, because the result # may be invalid. You need to run "rush update" again. -pnpm-lock.yaml merge=binary +pnpm-lock.yaml merge=text shrinkwrap.yaml merge=binary npm-shrinkwrap.json merge=binary yarn.lock merge=binary @@ -75,4 +47,4 @@ yarn.lock merge=binary # # For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088 # -*.json linguist-language=JSON-with-Comments +*.json linguist-language=JSON-with-Comments diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9e27f21779f..935ac6772e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,17 +1,24 @@ -.github/CODEOWNERS @iclanton @octogonz @patmill @apostolisms -common/config/**/* @iclanton @octogonz @patmill @apostolisms +.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 -common/reviews/**/* @iclanton @octogonz @apostolisms +common/reviews/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -apps/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -build-tests/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -core-build/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -libraries/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -stack/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -webpack/**/* @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -rush.json @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -.gitattributes @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -.gitignore @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L -README.md @iclanton @octogonz @apostolisms @halfnibble @sachinjoseph @D4N14L +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 @dzearing @apostolisms +libraries/load-themed-styles/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @dzearing diff --git a/.github/ISSUE_TEMPLATE/api-documenter.md b/.github/ISSUE_TEMPLATE/api-documenter.md new file mode 100644 index 00000000000..0cf2a0f98c8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-documenter.md @@ -0,0 +1,64 @@ +--- +name: 'API Documenter' +about: Report an issue related to the `@microsoft/api-documenter` project and associated packages +title: '[api-documenter] ' +labels: '' +assignees: '' +--- + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@microsoft/api-documenter` version? | | +| Operating system? | | +| Documentation target? | | +| Would you consider contributing a PR? | | +| TypeScript compiler version? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/api-extractor.md b/.github/ISSUE_TEMPLATE/api-extractor.md new file mode 100644 index 00000000000..bef0bd3f251 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-extractor.md @@ -0,0 +1,66 @@ +--- +name: 'API Extractor' +about: Report an issue related to the '@microsoft/api-extractor' project and associated packages +title: '[api-extractor] ' +labels: '' +assignees: '' +--- + + + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@microsoft/api-extractor` version? | | +| Operating system? | | +| API Extractor scenario? | | +| Would you consider contributing a PR? | | +| TypeScript compiler version? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..1bb48adf306 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: '💬 Chat room' + about: Need answers? Want to propose an idea? Please discuss it in the chat room before creating a GitHub issue. + url: https://rushstack.zulipchat.com/ + - name: '👉 READ FIRST: Contributor guidelines' + about: Instructions for building the projects, debugging, and submitting a PR. + url: https://rushstack.io/pages/contributing/get_started/ diff --git a/.github/ISSUE_TEMPLATE/eslint-config.md b/.github/ISSUE_TEMPLATE/eslint-config.md new file mode 100644 index 00000000000..f9c393cf04f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/eslint-config.md @@ -0,0 +1,63 @@ +--- +name: 'ESLint config' +about: Report an issue with the '@rushstack/eslint-config' project and associated packages +title: '[eslint-config] ' +labels: '' +assignees: '' +--- + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@rushstack/eslint-config` version? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| TypeScript compiler version? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/eslint-plugin-packlets.md b/.github/ISSUE_TEMPLATE/eslint-plugin-packlets.md new file mode 100644 index 00000000000..a94f46894f1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/eslint-plugin-packlets.md @@ -0,0 +1,63 @@ +--- +name: 'ESLint Packlets' +about: Report an issue with the '@rushstack/eslint-plugin-packlets' project +title: '[eslint-plugin-packlets] ' +labels: '' +assignees: '' +--- + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@rushstack/eslint-plugin-packlets` version? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| TypeScript compiler version? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/heft.md b/.github/ISSUE_TEMPLATE/heft.md new file mode 100644 index 00000000000..bb742312596 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/heft.md @@ -0,0 +1,64 @@ +--- +name: 'Heft' +about: Report an issue with the '@rushstack/heft' project and associated packages +title: '[heft] ' +labels: '' +assignees: '' +--- + + + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@rushstack/heft` version? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md deleted file mode 100644 index af86364d364..00000000000 --- a/.github/ISSUE_TEMPLATE/issue-template.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: New Issue -about: Information needed when opening a new issue -title: '' -labels: '' -assignees: '' ---- - -## Please prefix the issue title with the project name i.e. [rush], [api-extractor] etc. ## - -**Is this a feature or a bug?** - -- [ ] Feature -- [ ] Bug - -**Please describe the actual behavior.** - -**If the issue is a bug, how can we reproduce it? Please provide detailed steps and include a GitHub branch if applicable. Your issue will get resolved faster if you can make it easy to investigate.** - -**What is the expected behavior?** - -**If this is a bug, please provide the tool version, Node.js version, and OS.** - -* **Tool:** -* **Tool Version:** -* **Node Version:** - * **Is this a LTS version?** - * **Have you tested on a LTS version?** -* **OS:** diff --git a/.github/ISSUE_TEMPLATE/lockfile-explorer.md b/.github/ISSUE_TEMPLATE/lockfile-explorer.md new file mode 100644 index 00000000000..dc8c2b7d8a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/lockfile-explorer.md @@ -0,0 +1,62 @@ +--- +name: 'Lockfile Explorer' +about: Report an issue with the '@rushstack/lockfile-explorer' app +title: '[lockfile-explorer] ' +labels: '' +assignees: '' +--- + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@rushstack/lockfile-explorer` version? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/rush.md b/.github/ISSUE_TEMPLATE/rush.md new file mode 100644 index 00000000000..0958df66671 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rush.md @@ -0,0 +1,66 @@ +--- +name: 'Rush' +about: Report an issue with the '@microsoft/rush' project and associated packages +title: '[rush] ' +labels: '' +assignees: '' +--- + + + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| `@microsoft/rush` globally installed version? | | +| `rushVersion` from rush.json? | | +| `useWorkspaces` from rush.json? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| Node.js version (`node -v`)? | | diff --git a/.github/ISSUE_TEMPLATE/z-other-project.md b/.github/ISSUE_TEMPLATE/z-other-project.md new file mode 100644 index 00000000000..9c3ba470318 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/z-other-project.md @@ -0,0 +1,67 @@ +--- +name: 'Other project' +about: Report an issue with another project in this repo +title: '[the-package-name] ' +labels: '' +assignees: '' +--- + + + + + +## Summary + + + +## Repro steps + + + + **Expected result:** + + **Actual result:** + +## Details + + + +## Standard questions + +Please answer these questions to help us investigate your issue more quickly: + +| Question | Answer | +| -------- | -------- | +| Package name: | | +| Package version? | | +| Operating system? | | +| Would you consider contributing a PR? | | +| Node.js version (`node -v`)? | | diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..43b751b318f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,81 @@ + + + + + + +## Summary + + + +## Details + + + +## How it was tested + + + +## Impacted documentation + + + + + + + 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 new file mode 100644 index 00000000000..f2953f73fa0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,105 @@ +name: CI +on: + push: + branches: ['main'] + pull_request: + branches: ['main'] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - NodeVersion: 18.20.x + NodeVersionDisplayName: 18 + OS: ubuntu-latest + - NodeVersion: 20.18.x + NodeVersionDisplayName: 20 + OS: ubuntu-latest + - NodeVersion: 22.19.x + NodeVersionDisplayName: 22 + OS: ubuntu-latest + - NodeVersion: 22.19.x + NodeVersionDisplayName: 22 + OS: windows-latest + name: Node.js v${{ matrix.NodeVersionDisplayName }} (${{ matrix.OS }}) + runs-on: ${{ matrix.OS }} + steps: + - name: Create ~/.rush-user/settings.json + shell: pwsh + # Create a .rush-user/settings.json file that looks like this: + # + # { "buildCacheFolder": "//rush-cache" } + # + # This configures the local cache to be shared between all Rush repos. This allows us to run a build in + # one clone of the repo (repo-a), and restore from the cache in another clone of the repo (repo-b) to test + # the build cache. + run: | + mkdir -p $HOME/.rush-user + @{ buildCacheFolder = Join-Path ${{ github.workspace }} rush-cache } | ConvertTo-Json > $HOME/.rush-user/settings.json + + - uses: actions/checkout@v3 + with: + fetch-depth: 2 + path: repo-a + + - name: Git config user + run: | + git config --local user.name "Rushbot" + git config --local user.email "rushbot@users.noreply.github.com" + working-directory: repo-a + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.NodeVersion }} + + - name: Verify Change Logs + run: node common/scripts/install-run-rush.js change --verify + working-directory: repo-a + + - name: Rush Install + run: node common/scripts/install-run-rush.js install + working-directory: repo-a + + # - if: runner.os == 'Linux' + # name: Start xvfb + # run: /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + # working-directory: repo-a + + - name: Rush retest (install-run-rush) + run: node common/scripts/install-run-rush.js retest --verbose --production + working-directory: repo-a + + - name: Ensure repo README is up-to-date + run: node repo-scripts/repo-toolbox/lib/start.js readme --verify + working-directory: repo-a + + - name: Collect JSON schemas + run: node repo-scripts/repo-toolbox/lib/start.js collect-json-schemas --output-path ${GITHUB_WORKSPACE}/artifacts/json-schemas + working-directory: repo-a + + - name: Clone another copy of the repo to test the build cache + uses: actions/checkout@v3 + with: + fetch-depth: 1 + path: repo-b + + - name: Git config user + run: | + git config --local user.name "Rushbot" + git config --local user.email "rushbot@users.noreply.github.com" + working-directory: repo-b + + - name: Rush update (rush-lib) + run: node ${{ github.workspace }}/repo-a/apps/rush/lib/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 + working-directory: repo-b + + - name: Rush test (rush-lib) again to verify build cache hits + run: node ${{ github.workspace }}/repo-a/apps/rush/lib/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 new file mode 100644 index 00000000000..a22ca91016d --- /dev/null +++ b/.github/workflows/file-doc-tickets.yml @@ -0,0 +1,86 @@ +################################################################################ +# When pull requests are merged to the main branch, evaluate the pull request +# body and file a documentation ticket against the rushstack-websites repo +# with a corresponding documentation task. +# +# The pull request body must contain non-comment, non-whitespace text below +# the "Impacted documentation" header in the PR template to file a +# documentation ticket. +################################################################################ +name: File Doc Tickets + +on: + pull_request: + branches: + - main + types: + - closed + +jobs: + file-tickets: + name: File Tickets + if: ${{ github.event.pull_request.merged }} + runs-on: ubuntu-latest + steps: + - name: Use nodejs + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Parse PR body + run: | + cat <<-"EOF" > event.json + ${{ toJson(github.event) }} + EOF + + cat <<-"EOF" | node + const fs = require('fs'); + + const EVENT_FILE = 'event.json'; + const RESULT_FILE = 'issue.md'; + const DELIMITER = '## Impacted documentation'; + + const event = JSON.parse(fs.readFileSync(EVENT_FILE, 'utf8')); + const strippedBody = (event.pull_request.body || '').replace(//g, ''); + const delimIndex = strippedBody.indexOf(DELIMITER); + + if (delimIndex < 0) { + console.log('No documentation tasks detected -- skipping doc ticket.'); + process.exit(0); + } + + const delimBody = strippedBody.substring(delimIndex + DELIMITER.length).trim(); + + if (delimBody.length === 0) { + console.log('No documentation tasks detected -- skipping doc ticket.'); + process.exit(0); + } + + const quotedBody = delimBody.split('\n').map(line => `> ${line}`).join('\n'); + fs.writeFileSync(RESULT_FILE, [ + '### Summary', + '', + 'Follow up on documentation tasks from ' + event.pull_request.html_url + '.', + '', + '### Details', + '', + 'This ticket was generated automatically. Suggested documentation updates:', + '', + quotedBody, + '' + ].join('\n'), 'utf8'); + + EOF + + if [ -f issue.md ]; then + echo "FILE_TICKET=1" >> $GITHUB_ENV + fi + - name: File ticket + if: ${{ env.FILE_TICKET == '1' }} + uses: peter-evans/create-issue-from-file@af31b99c72f9e91877aea8a2d96fd613beafac84 # @v4 (locked) + with: + repository: microsoft/rushstack-websites + token: '${{ secrets.RUSHSTACK_WEBSITES_PR_TOKEN }}' + title: '[doc] ${{ github.event.pull_request.title }}' + content-filepath: ./issue.md + labels: | + automated diff --git a/.gitignore b/.gitignore index d1fc6c480eb..220378d072b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data *.pid @@ -10,35 +14,39 @@ yarn-error.log* *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover -lib-cov +lib-cov/ # Coverage directory used by tools like istanbul -coverage +coverage/ # nyc test coverage -.nyc_output +.nyc_output/ # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt +.grunt/ # Bower dependency directory (https://bower.io/) -bower_components +bower_components/ # node-waf configuration -.lock-wscript +.lock-wscript/ # Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release +build/Release/ # Dependency directories node_modules/ +**/.storybook/node_modules jspm_packages/ +# TypeScript cache +*.tsbuildinfo + # Optional npm cache directory -.npm +.npm/ # Optional eslint cache -.eslintcache +.eslintcache/ # Optional REPL history .node_repl_history @@ -51,28 +59,72 @@ jspm_packages/ # dotenv environment variables file .env +.env.development.local +.env.test.local +.env.production.local +.env.local # next.js build output -.next +.next/ + +# Docusaurus cache and generated files +.docusaurus/ + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# yarn v2 +.yarn/cache/ +.yarn/unplugged/ +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* # OS X temporary files .DS_Store +# IntelliJ IDEA project files; if you want to commit IntelliJ settings, this recipe may be helpful: +# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +.idea/ +*.iml + +# Visual Studio Code +.vscode/ +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/debug-certificate-manager.json + # Rush temporary files +common/deploy/ common/temp/ +common/autoinstallers/*/.npmrc **/.rush/temp/ +*.lock # Common toolchain intermediate files -temp -lib -lib-amd -lib-es6 -dist -*.scss.ts -*.sass.ts - -# Visual Studio Code -.vscode - -# Remove eventually -package-deps.json +build/ +temp/ +lib/ +lib-amd/ +lib-dts/ +lib-es6/ +lib-esm/ +lib-esnext/ +lib-commonjs/ +lib-shim/ +dist/ +dist-storybook/ +*.tsbuildinfo + +# Heft temporary files +.cache/ +.heft/ + +# VS Code test runner files +.vscode-test/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..5f92ce14d67 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,157 @@ +#------------------------------------------------------------------------------------------------------------------- +# Keep this section in sync with .gitignore +#------------------------------------------------------------------------------------------------------------------- + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov/ + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output/ + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt/ + +# Bower dependency directory (https://bower.io/) +bower_components/ + +# node-waf configuration +.lock-wscript/ + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release/ + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm/ + +# Optional eslint cache +.eslintcache/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# next.js build output +.next/ + +# Docusaurus cache and generated files +.docusaurus/ + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# yarn v2 +.yarn/cache/ +.yarn/unplugged/ +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# OS X temporary files +.DS_Store + +# IntelliJ IDEA project files; if you want to commit IntelliJ settings, this recipe may be helpful: +# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +.idea/ +*.iml + +# Visual Studio Code +.vscode/ +!.vscode/tasks.json +!.vscode/launch.json + +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +**/.rush/temp/ +*.lock + +# Common toolchain intermediate files +temp/ +lib/ +lib-amd/ +lib-es6/ +lib-esnext/ +lib-commonjs/ +lib-shim/ +dist/ +dist-storybook/ +*.tsbuildinfo + +# Heft temporary files +.cache/ +.heft/ + +#------------------------------------------------------------------------------------------------------------------- +# Prettier-specific overrides +#------------------------------------------------------------------------------------------------------------------- + +# Machine-egnerated files +common/reviews/ +common/changes/ +common/scripts/ +common/config/rush/browser-approved-packages.json +common/config/rush/nonbrowser-approved-packages.json +CHANGELOG.* +pnpm-lock.yaml +build-tests/*/etc +dist-dev/ +dist-prod/ + +# Prettier doesn't understand the /*[LINE "HYPOTHETICAL"]*/ macros in these files: +libraries/rush-lib/assets/rush-init/ + +# These are intentionally invalid files +libraries/heft-config-file/src/test/errorCases/invalidJson/config.json + +# common scripts in sandbox repo +build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/ + +# We'll consider enabling this later; Prettier reformats code blocks, which affects end-user content +*.md + +# Don't format these YAML files - they were generated by pnpm and are used in unit tests +libraries/rush-lib/src/logic/test/shrinkwrapFile/*.yaml diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000000..738cb45f517 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,13 @@ +// Documentation for this file: https://prettier.io/docs/en/configuration.html +module.exports = { + // We use a larger print width because Prettier's word-wrapping seems to be tuned + // for plain JavaScript without type annotations + printWidth: 110, + // Microsoft style quotes + singleQuote: true, + // Preserve existing newlines + endOfLine: 'auto', + // For ES5, trailing commas cannot be used in function parameters; it is counterintuitive + // to use them for arrays only + trailingComma: 'none' +}; 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 aa60c38f8df..a143932c7a5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,52 +2,121 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch", + "name": "Rush Debug", "type": "node", "request": "launch", - "program": "${workspaceRoot}/common/node_modules/gulp/bin/gulp.js", - "stopOnEntry": false, + "program": "${workspaceRoot}/apps/rush/lib/start-dev.js", + "stopOnEntry": true, "args": [ + "start" ], - "cwd": "${workspaceRoot}/gulp-core-build", + "cwd": "${workspaceRoot}", "runtimeExecutable": null, "runtimeArgs": [ - "--nolazy" + "--nolazy", + "--inspect-brk" ], + "skipFiles": ["/**"], + // Don't scan the file system on startup + "outFiles": [], + // Evaluate source maps for all workspace-local files + "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "env": { "NODE_ENV": "development" }, - "externalConsole": false, - "sourceMaps": false, - "outDir": null + "sourceMaps": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" }, { - "name": "Rush Debug", "type": "node", "request": "launch", - "program": "${workspaceRoot}/apps/rush-lib/lib/start.js", - "stopOnEntry": true, - "args": [ - "update", - "--variant", - "test" + "name": "Debug Selected Test File (Heft)", + "cwd": "${fileDirname}", + "runtimeArgs": [ + "--nolazy", + "--inspect-brk", + "${workspaceFolder}/apps/heft/lib/start.js", + "--debug", + "test", + "--test-path-pattern", + "${fileBasenameNoExtension}" ], - "cwd": "${workspaceRoot}", - "runtimeExecutable": null, + "skipFiles": ["/**"], + "outFiles": [], + "sourceMaps": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "type": "node", + "request": "launch", + "name": "Debug Build in Selected Project (Heft)", + "cwd": "${fileDirname}", "runtimeArgs": [ "--nolazy", - "--debug" + "--inspect-brk", + "${workspaceFolder}/apps/heft/lib/start.js", + "--debug", + "build" ], - "env": { - "NODE_ENV": "development" - }, - "sourceMaps": true + "skipFiles": ["/**"], + "outFiles": [], + "sourceMaps": true, + "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/start.js", + "--debug", + "build", + "--clean" + ], + "skipFiles": ["/**"], + "outFiles": [], + "sourceMaps": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" }, { "name": "Attach", "type": "node", "request": "attach", - "port": 5858 + "port": 9229, + "outFiles": [], + }, + { + "name": "Launch Rush Extension", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/vscode-extensions/rush-vscode-extension", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/rush-vscode-extension/dist/vsix/unpacked" + ], + "outFiles": [ + "${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/**" + ] } ] } diff --git a/.vscode/redis-cobuild.code-workspace b/.vscode/redis-cobuild.code-workspace new file mode 100644 index 00000000000..c51d9ed6da0 --- /dev/null +++ b/.vscode/redis-cobuild.code-workspace @@ -0,0 +1,20 @@ +{ + "folders": [ + { + "name": "rush-redis-cobuild-plugin-integration-test", + "path": "../build-tests/rush-redis-cobuild-plugin-integration-test" + }, + { + "name": "rush-redis-cobuild-plugin", + "path": "../rush-plugins/rush-redis-cobuild-plugin" + }, + { + "name": "rush-lib", + "path": "../libraries/rush-lib" + }, + { + "name": ".vscode", + "path": "../.vscode" + } + ] +} 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/LICENSE b/LICENSE new file mode 100644 index 00000000000..340d63d1fa3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +This is a monorepo, with each published package containing its own license. The +license for each package can be found in the package's folder. + +The projects in this monorepo are licensed under the MIT license. + +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/README.md b/README.md index 69b20532596..676bc4bdc14 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,44 @@

https://rushstack.io/

-[![Join the chat at https://gitter.im/rushstack](https://badges.gitter.im/rushstack.svg)](https://gitter.im/rushstack?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)   [![Build Status](https://dev.azure.com/RushStack/GitHubProjects/_apis/build/status/rushstack/rushstack%20CI%20Build?branchName=master)](https://dev.azure.com/RushStack/GitHubProjects/_build/latest?definitionId=3&branchName=master) -The home for various projects maintained by the Rush Stack community, whose mission is to develop reusable tooling + +[![Zulip chat room](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rushstack.zulipchat.com/)   [![Build Status](https://github.com/microsoft/rushstack/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/microsoft/rushstack/actions/workflows/ci.yml?query=branch%3Amain) + + +The home for projects maintained by the Rush Stack community. Our mission is to develop reusable tooling for large scale TypeScript monorepos. +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=69618902&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestUs2) + +
+ Open in VS Code web view +
## Documentation Links - [What is Rush Stack?](https://rushstack.io/) - learn about the mission behind these projects -- [API reference](https://rushstack.io/pages/api/) - browse API documentation for NPM packages -- [Gitter chat room](https://gitter.im/rushstack/rushstack) - chat with the Rush Stack developers +- [API reference](https://api.rushstack.io/) - browse API documentation for NPM packages +- [Zulip chat room](https://rushstack.zulipchat.com/) - chat with the Rush Stack developers - [Rush](https://rushjs.io/) - a build orchestrator for large scale TypeScript monorepos +- [Heft](https://heft.rushstack.io/) - our recommended tool that integrates with Rush - [API Extractor](https://api-extractor.com/) - create .d.ts rollups and track your TypeScript API signatures - [API Documenter](https://api-extractor.com/pages/setup/generating_docs/) - use TSDoc comments to publish an API documentation website +- [Lockfile Explorer](https://lfx.rushstack.io/) - investigate and solve version conflicts for PNPM lockfiles +- [TSDoc](https://tsdoc.org/) - the standard for doc comments in TypeScript code +## Related Repos + +These GitHub repositories provide supplementary resources for Rush Stack: + +- [rushstack-samples](https://github.com/microsoft/rushstack-samples) - a monoprepo with sample projects that + illustrate various project setups, including how to use Heft with other popular JavaScript frameworks +- [rush-example](https://github.com/microsoft/rush-example) - a minimal Rush repo that demonstrates the fundamentals + of Rush without relying on any other Rush Stack tooling +- [rushstack-websites](https://github.com/microsoft/rushstack-websites) - Docusaurus monorepo for our websites + + + ## Published Packages @@ -27,43 +50,84 @@ for large scale TypeScript monorepos. | ------ | ------- | --------- | ------- | | [/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/api-extractor-model](./apps/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](./apps/api-extractor-model/CHANGELOG.md) | [@microsoft/api-extractor-model](https://www.npmjs.com/package/@microsoft/api-extractor-model) | +| [/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/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-buildxl](./apps/rush-buildxl/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-buildxl.svg)](https://badge.fury.io/js/%40microsoft%2Frush-buildxl) | | [@microsoft/rush-buildxl](https://www.npmjs.com/package/@microsoft/rush-buildxl) | -| [/apps/rush-lib](./apps/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) | -| [/core-build/gulp-core-build](./core-build/gulp-core-build/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build) | [changelog](./core-build/gulp-core-build/CHANGELOG.md) | [@microsoft/gulp-core-build](https://www.npmjs.com/package/@microsoft/gulp-core-build) | -| [/core-build/gulp-core-build-mocha](./core-build/gulp-core-build-mocha/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-mocha.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-mocha) | [changelog](./core-build/gulp-core-build-mocha/CHANGELOG.md) | [@microsoft/gulp-core-build-mocha](https://www.npmjs.com/package/@microsoft/gulp-core-build-mocha) | -| [/core-build/gulp-core-build-sass](./core-build/gulp-core-build-sass/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-sass.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-sass) | [changelog](./core-build/gulp-core-build-sass/CHANGELOG.md) | [@microsoft/gulp-core-build-sass](https://www.npmjs.com/package/@microsoft/gulp-core-build-sass) | -| [/core-build/gulp-core-build-serve](./core-build/gulp-core-build-serve/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-serve.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-serve) | [changelog](./core-build/gulp-core-build-serve/CHANGELOG.md) | [@microsoft/gulp-core-build-serve](https://www.npmjs.com/package/@microsoft/gulp-core-build-serve) | -| [/core-build/gulp-core-build-typescript](./core-build/gulp-core-build-typescript/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-typescript.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-typescript) | [changelog](./core-build/gulp-core-build-typescript/CHANGELOG.md) | [@microsoft/gulp-core-build-typescript](https://www.npmjs.com/package/@microsoft/gulp-core-build-typescript) | -| [/core-build/gulp-core-build-webpack](./core-build/gulp-core-build-webpack/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-webpack.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-webpack) | [changelog](./core-build/gulp-core-build-webpack/CHANGELOG.md) | [@microsoft/gulp-core-build-webpack](https://www.npmjs.com/package/@microsoft/gulp-core-build-webpack) | -| [/core-build/node-library-build](./core-build/node-library-build/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fnode-library-build.svg)](https://badge.fury.io/js/%40microsoft%2Fnode-library-build) | [changelog](./core-build/node-library-build/CHANGELOG.md) | [@microsoft/node-library-build](https://www.npmjs.com/package/@microsoft/node-library-build) | -| [/core-build/web-library-build](./core-build/web-library-build/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fweb-library-build.svg)](https://badge.fury.io/js/%40microsoft%2Fweb-library-build) | [changelog](./core-build/web-library-build/CHANGELOG.md) | [@microsoft/web-library-build](https://www.npmjs.com/package/@microsoft/web-library-build) | +| [/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) | +| [/eslint/eslint-plugin](./eslint/eslint-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-plugin) | [changelog](./eslint/eslint-plugin/CHANGELOG.md) | [@rushstack/eslint-plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin) | +| [/eslint/eslint-plugin-packlets](./eslint/eslint-plugin-packlets/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-plugin-packlets.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-plugin-packlets) | [changelog](./eslint/eslint-plugin-packlets/CHANGELOG.md) | [@rushstack/eslint-plugin-packlets](https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets) | +| [/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-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) | +| [/libraries/localization-utilities](./libraries/localization-utilities/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flocalization-utilities.svg)](https://badge.fury.io/js/%40rushstack%2Flocalization-utilities) | [changelog](./libraries/localization-utilities/CHANGELOG.md) | [@rushstack/localization-utilities](https://www.npmjs.com/package/@rushstack/localization-utilities) | +| [/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-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) | +| [/libraries/tree-pattern](./libraries/tree-pattern/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftree-pattern.svg)](https://badge.fury.io/js/%40rushstack%2Ftree-pattern) | [changelog](./libraries/tree-pattern/CHANGELOG.md) | [@rushstack/tree-pattern](https://www.npmjs.com/package/@rushstack/tree-pattern) | | [/libraries/ts-command-line](./libraries/ts-command-line/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fts-command-line.svg)](https://badge.fury.io/js/%40rushstack%2Fts-command-line) | [changelog](./libraries/ts-command-line/CHANGELOG.md) | [@rushstack/ts-command-line](https://www.npmjs.com/package/@rushstack/ts-command-line) | | [/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) | -| [/stack/eslint-config](./stack/eslint-config/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-config.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-config) | [changelog](./stack/eslint-config/CHANGELOG.md) | [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) | -| [/stack/eslint-plugin](./stack/eslint-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-plugin) | [changelog](./stack/eslint-plugin/CHANGELOG.md) | [@rushstack/eslint-plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin) | -| [/stack/rush-stack-compiler-2.4](./stack/rush-stack-compiler-2.4/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.4.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.4) | [changelog](./stack/rush-stack-compiler-2.4/CHANGELOG.md) | [@microsoft/rush-stack-compiler-2.4](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-2.4) | -| [/stack/rush-stack-compiler-2.7](./stack/rush-stack-compiler-2.7/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.7.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.7) | [changelog](./stack/rush-stack-compiler-2.7/CHANGELOG.md) | [@microsoft/rush-stack-compiler-2.7](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-2.7) | -| [/stack/rush-stack-compiler-2.8](./stack/rush-stack-compiler-2.8/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.8.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.8) | [changelog](./stack/rush-stack-compiler-2.8/CHANGELOG.md) | [@microsoft/rush-stack-compiler-2.8](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-2.8) | -| [/stack/rush-stack-compiler-2.9](./stack/rush-stack-compiler-2.9/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.9.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-2.9) | [changelog](./stack/rush-stack-compiler-2.9/CHANGELOG.md) | [@microsoft/rush-stack-compiler-2.9](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-2.9) | -| [/stack/rush-stack-compiler-3.0](./stack/rush-stack-compiler-3.0/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.0.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.0) | [changelog](./stack/rush-stack-compiler-3.0/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.0](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.0) | -| [/stack/rush-stack-compiler-3.1](./stack/rush-stack-compiler-3.1/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.1.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.1) | [changelog](./stack/rush-stack-compiler-3.1/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.1](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.1) | -| [/stack/rush-stack-compiler-3.2](./stack/rush-stack-compiler-3.2/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.2.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.2) | [changelog](./stack/rush-stack-compiler-3.2/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.2](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.2) | -| [/stack/rush-stack-compiler-3.3](./stack/rush-stack-compiler-3.3/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.3.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.3) | [changelog](./stack/rush-stack-compiler-3.3/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.3](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.3) | -| [/stack/rush-stack-compiler-3.4](./stack/rush-stack-compiler-3.4/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.4.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.4) | [changelog](./stack/rush-stack-compiler-3.4/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.4](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.4) | -| [/stack/rush-stack-compiler-3.5](./stack/rush-stack-compiler-3.5/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.5.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.5) | [changelog](./stack/rush-stack-compiler-3.5/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.5](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.5) | -| [/stack/rush-stack-compiler-3.6](./stack/rush-stack-compiler-3.6/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.6.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.6) | [changelog](./stack/rush-stack-compiler-3.6/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.6](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.6) | -| [/stack/rush-stack-compiler-3.7](./stack/rush-stack-compiler-3.7/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.7.svg)](https://badge.fury.io/js/%40microsoft%2Frush-stack-compiler-3.7) | [changelog](./stack/rush-stack-compiler-3.7/CHANGELOG.md) | [@microsoft/rush-stack-compiler-3.7](https://www.npmjs.com/package/@microsoft/rush-stack-compiler-3.7) | +| [/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-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) | +| [/webpack/hashed-folder-copy-plugin](./webpack/hashed-folder-copy-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fhashed-folder-copy-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fhashed-folder-copy-plugin) | [changelog](./webpack/hashed-folder-copy-plugin/CHANGELOG.md) | [@rushstack/hashed-folder-copy-plugin](https://www.npmjs.com/package/@rushstack/hashed-folder-copy-plugin) | | [/webpack/loader-load-themed-styles](./webpack/loader-load-themed-styles/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Floader-load-themed-styles.svg)](https://badge.fury.io/js/%40microsoft%2Floader-load-themed-styles) | [changelog](./webpack/loader-load-themed-styles/CHANGELOG.md) | [@microsoft/loader-load-themed-styles](https://www.npmjs.com/package/@microsoft/loader-load-themed-styles) | | [/webpack/loader-raw-script](./webpack/loader-raw-script/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Floader-raw-script.svg)](https://badge.fury.io/js/%40rushstack%2Floader-raw-script) | [changelog](./webpack/loader-raw-script/CHANGELOG.md) | [@rushstack/loader-raw-script](https://www.npmjs.com/package/@rushstack/loader-raw-script) | -| [/webpack/localization-plugin](./webpack/localization-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flocalization-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Flocalization-plugin) | [changelog](./webpack/localization-plugin/CHANGELOG.md) | [@rushstack/localization-plugin](https://www.npmjs.com/package/@rushstack/localization-plugin) | +| [/webpack/preserve-dynamic-require-plugin](./webpack/preserve-dynamic-require-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-preserve-dynamic-require-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-preserve-dynamic-require-plugin) | [changelog](./webpack/preserve-dynamic-require-plugin/CHANGELOG.md) | [@rushstack/webpack-preserve-dynamic-require-plugin](https://www.npmjs.com/package/@rushstack/webpack-preserve-dynamic-require-plugin) | | [/webpack/set-webpack-public-path-plugin](./webpack/set-webpack-public-path-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fset-webpack-public-path-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fset-webpack-public-path-plugin) | [changelog](./webpack/set-webpack-public-path-plugin/CHANGELOG.md) | [@rushstack/set-webpack-public-path-plugin](https://www.npmjs.com/package/@rushstack/set-webpack-public-path-plugin) | +| [/webpack/webpack-embedded-dependencies-plugin](./webpack/webpack-embedded-dependencies-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-embedded-dependencies-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-embedded-dependencies-plugin) | [changelog](./webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md) | [@rushstack/webpack-embedded-dependencies-plugin](https://www.npmjs.com/package/@rushstack/webpack-embedded-dependencies-plugin) | +| [/webpack/webpack-plugin-utilities](./webpack/webpack-plugin-utilities/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-plugin-utilities.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-plugin-utilities) | [changelog](./webpack/webpack-plugin-utilities/CHANGELOG.md) | [@rushstack/webpack-plugin-utilities](https://www.npmjs.com/package/@rushstack/webpack-plugin-utilities) | +| [/webpack/webpack-workspace-resolve-plugin](./webpack/webpack-workspace-resolve-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack-workspace-resolve-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack-workspace-resolve-plugin) | [changelog](./webpack/webpack-workspace-resolve-plugin/CHANGELOG.md) | [@rushstack/webpack-workspace-resolve-plugin](https://www.npmjs.com/package/@rushstack/webpack-workspace-resolve-plugin) | +| [/webpack/webpack4-localization-plugin](./webpack/webpack4-localization-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack4-localization-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack4-localization-plugin) | [changelog](./webpack/webpack4-localization-plugin/CHANGELOG.md) | [@rushstack/webpack4-localization-plugin](https://www.npmjs.com/package/@rushstack/webpack4-localization-plugin) | +| [/webpack/webpack4-module-minifier-plugin](./webpack/webpack4-module-minifier-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack4-module-minifier-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack4-module-minifier-plugin) | [changelog](./webpack/webpack4-module-minifier-plugin/CHANGELOG.md) | [@rushstack/webpack4-module-minifier-plugin](https://www.npmjs.com/package/@rushstack/webpack4-module-minifier-plugin) | +| [/webpack/webpack5-load-themed-styles-loader](./webpack/webpack5-load-themed-styles-loader/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fwebpack5-load-themed-styles-loader.svg)](https://badge.fury.io/js/%40microsoft%2Fwebpack5-load-themed-styles-loader) | [changelog](./webpack/webpack5-load-themed-styles-loader/CHANGELOG.md) | [@microsoft/webpack5-load-themed-styles-loader](https://www.npmjs.com/package/@microsoft/webpack5-load-themed-styles-loader) | +| [/webpack/webpack5-localization-plugin](./webpack/webpack5-localization-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack5-localization-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack5-localization-plugin) | [changelog](./webpack/webpack5-localization-plugin/CHANGELOG.md) | [@rushstack/webpack5-localization-plugin](https://www.npmjs.com/package/@rushstack/webpack5-localization-plugin) | +| [/webpack/webpack5-module-minifier-plugin](./webpack/webpack5-module-minifier-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fwebpack5-module-minifier-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fwebpack5-module-minifier-plugin) | [changelog](./webpack/webpack5-module-minifier-plugin/CHANGELOG.md) | [@rushstack/webpack5-module-minifier-plugin](https://www.npmjs.com/package/@rushstack/webpack5-module-minifier-plugin) | ## Unpublished Local Projects @@ -72,39 +136,101 @@ for large scale TypeScript monorepos. | Folder | Description | | ------ | -----------| +| [/apps/lockfile-explorer-web](./apps/lockfile-explorer-web/) | Rush Lockfile Explorer: helper project for building the React web application component | +| [/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-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 | +| [/build-tests-samples/packlets-tutorial](./build-tests-samples/packlets-tutorial/) | (Copy of sample project) Building this project is a regression test for @rushstack/eslint-plugin-packlets | +| [/build-tests-subspace/rush-lib-test](./build-tests-subspace/rush-lib-test/) | A minimal example project that imports APIs from @rushstack/rush-lib | +| [/build-tests-subspace/rush-sdk-test](./build-tests-subspace/rush-sdk-test/) | A minimal example project that imports APIs from @rushstack/rush-sdk | +| [/build-tests-subspace/typescript-newest-test](./build-tests-subspace/typescript-newest-test/) | Building this project tests Heft with the newest supported TypeScript compiler version | +| [/build-tests-subspace/typescript-v4-test](./build-tests-subspace/typescript-v4-test/) | Building this project tests Heft with TypeScript v4 | +| [/build-tests/api-documenter-scenarios](./build-tests/api-documenter-scenarios/) | Building this project is a regression test for api-documenter | | [/build-tests/api-documenter-test](./build-tests/api-documenter-test/) | Building this project is a regression test for api-documenter | +| [/build-tests/api-extractor-d-cts-test](./build-tests/api-extractor-d-cts-test/) | Building this project is a regression test for api-extractor | +| [/build-tests/api-extractor-d-mts-test](./build-tests/api-extractor-d-mts-test/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-lib1-test](./build-tests/api-extractor-lib1-test/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-lib2-test](./build-tests/api-extractor-lib2-test/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-lib3-test](./build-tests/api-extractor-lib3-test/) | Building this project is a regression test for api-extractor | +| [/build-tests/api-extractor-lib4-test](./build-tests/api-extractor-lib4-test/) | Building this project is a regression test for api-extractor | +| [/build-tests/api-extractor-lib5-test](./build-tests/api-extractor-lib5-test/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-scenarios](./build-tests/api-extractor-scenarios/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-test-01](./build-tests/api-extractor-test-01/) | Building this project is a regression test for api-extractor | | [/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/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 | +| [/build-tests/heft-typescript-v4-test](./build-tests/heft-typescript-v4-test/) | Building this project tests building with TypeScript v4 | +| [/build-tests/heft-web-rig-library-test](./build-tests/heft-web-rig-library-test/) | A test project for Heft that exercises the '@rushstack/heft-web-rig' package | +| [/build-tests/heft-webpack4-everything-test](./build-tests/heft-webpack4-everything-test/) | Building this project tests every task and config file for Heft when targeting the web browser runtime using Webpack 4 | +| [/build-tests/heft-webpack5-everything-test](./build-tests/heft-webpack5-everything-test/) | Building this project tests every task and config file for Heft when targeting the web browser runtime using Webpack 5 | | [/build-tests/localization-plugin-test-01](./build-tests/localization-plugin-test-01/) | Building this project exercises @microsoft/localization-plugin. This tests that the plugin works correctly without any localized resources. | | [/build-tests/localization-plugin-test-02](./build-tests/localization-plugin-test-02/) | Building this project exercises @microsoft/localization-plugin. This tests that the loader works correctly with the exportAsDefault option unset. | | [/build-tests/localization-plugin-test-03](./build-tests/localization-plugin-test-03/) | Building this project exercises @microsoft/localization-plugin. This tests that the plugin works correctly with the exportAsDefault option set to true. | -| [/build-tests/node-library-build-eslint-test](./build-tests/node-library-build-eslint-test/) | | -| [/build-tests/node-library-build-tslint-test](./build-tests/node-library-build-tslint-test/) | | -| [/build-tests/rush-stack-compiler-2.4-library-test](./build-tests/rush-stack-compiler-2.4-library-test/) | | -| [/build-tests/rush-stack-compiler-2.7-library-test](./build-tests/rush-stack-compiler-2.7-library-test/) | | -| [/build-tests/rush-stack-compiler-2.8-library-test](./build-tests/rush-stack-compiler-2.8-library-test/) | | -| [/build-tests/rush-stack-compiler-2.9-library-test](./build-tests/rush-stack-compiler-2.9-library-test/) | | -| [/build-tests/rush-stack-compiler-3.0-library-test](./build-tests/rush-stack-compiler-3.0-library-test/) | | -| [/build-tests/rush-stack-compiler-3.1-library-test](./build-tests/rush-stack-compiler-3.1-library-test/) | | -| [/build-tests/rush-stack-compiler-3.2-library-test](./build-tests/rush-stack-compiler-3.2-library-test/) | | -| [/build-tests/rush-stack-compiler-3.3-library-test](./build-tests/rush-stack-compiler-3.3-library-test/) | | -| [/build-tests/rush-stack-compiler-3.4-library-test](./build-tests/rush-stack-compiler-3.4-library-test/) | | -| [/build-tests/rush-stack-compiler-3.5-library-test](./build-tests/rush-stack-compiler-3.5-library-test/) | | -| [/build-tests/rush-stack-compiler-3.6-library-test](./build-tests/rush-stack-compiler-3.6-library-test/) | | -| [/build-tests/rush-stack-compiler-3.7-library-test](./build-tests/rush-stack-compiler-3.7-library-test/) | | -| [/build-tests/web-library-build-test](./build-tests/web-library-build-test/) | | +| [/build-tests/package-extractor-test-01](./build-tests/package-extractor-test-01/) | This project is used by tests in the @rushstack/package-extractor package. | +| [/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/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-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/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 | -| [/stack/rush-stack-compiler-shared](./stack/rush-stack-compiler-shared/) | | - +| [/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/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. | + ## Contributor Notice diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..f7b89984f0f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). + + \ No newline at end of file diff --git a/apps/api-documenter/.eslintrc.js b/apps/api-documenter/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/apps/api-documenter/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/apps/api-documenter/.npmignore b/apps/api-documenter/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/apps/api-documenter/.npmignore +++ b/apps/api-documenter/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/apps/api-documenter/CHANGELOG.json b/apps/api-documenter/CHANGELOG.json index 093ba9b8b01..8b981a10968 100644 --- a/apps/api-documenter/CHANGELOG.json +++ b/apps/api-documenter/CHANGELOG.json @@ -1,6 +1,7848 @@ { "name": "@microsoft/api-documenter", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "7.26.2", + "tag": "@microsoft/api-documenter_v7.26.2", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "7.26.1", + "tag": "@microsoft/api-documenter_v7.26.1", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "7.26.0", + "tag": "@microsoft/api-documenter_v7.26.0", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "minor": [ + { + "comment": "Update TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "7.25.22", + "tag": "@microsoft/api-documenter_v7.25.22", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "7.25.21", + "tag": "@microsoft/api-documenter_v7.25.21", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "7.25.20", + "tag": "@microsoft/api-documenter_v7.25.20", + "date": "Mon, 21 Oct 2024 18:50:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "7.25.19", + "tag": "@microsoft/api-documenter_v7.25.19", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "7.25.18", + "tag": "@microsoft/api-documenter_v7.25.18", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "7.25.17", + "tag": "@microsoft/api-documenter_v7.25.17", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "7.25.16", + "tag": "@microsoft/api-documenter_v7.25.16", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "7.25.15", + "tag": "@microsoft/api-documenter_v7.25.15", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "7.25.14", + "tag": "@microsoft/api-documenter_v7.25.14", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "7.25.13", + "tag": "@microsoft/api-documenter_v7.25.13", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "7.25.12", + "tag": "@microsoft/api-documenter_v7.25.12", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "7.25.11", + "tag": "@microsoft/api-documenter_v7.25.11", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "7.25.10", + "tag": "@microsoft/api-documenter_v7.25.10", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "7.25.9", + "tag": "@microsoft/api-documenter_v7.25.9", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "7.25.8", + "tag": "@microsoft/api-documenter_v7.25.8", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "7.25.7", + "tag": "@microsoft/api-documenter_v7.25.7", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "7.25.6", + "tag": "@microsoft/api-documenter_v7.25.6", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "7.25.5", + "tag": "@microsoft/api-documenter_v7.25.5", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "7.25.4", + "tag": "@microsoft/api-documenter_v7.25.4", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "7.25.3", + "tag": "@microsoft/api-documenter_v7.25.3", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "7.25.2", + "tag": "@microsoft/api-documenter_v7.25.2", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "7.25.1", + "tag": "@microsoft/api-documenter_v7.25.1", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "7.25.0", + "tag": "@microsoft/api-documenter_v7.25.0", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Bump TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "7.24.13", + "tag": "@microsoft/api-documenter_v7.24.13", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "7.24.12", + "tag": "@microsoft/api-documenter_v7.24.12", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "7.24.11", + "tag": "@microsoft/api-documenter_v7.24.11", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "7.24.10", + "tag": "@microsoft/api-documenter_v7.24.10", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "7.24.9", + "tag": "@microsoft/api-documenter_v7.24.9", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "7.24.8", + "tag": "@microsoft/api-documenter_v7.24.8", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "7.24.7", + "tag": "@microsoft/api-documenter_v7.24.7", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "7.24.6", + "tag": "@microsoft/api-documenter_v7.24.6", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "7.24.5", + "tag": "@microsoft/api-documenter_v7.24.5", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "7.24.4", + "tag": "@microsoft/api-documenter_v7.24.4", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "7.24.3", + "tag": "@microsoft/api-documenter_v7.24.3", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "7.24.2", + "tag": "@microsoft/api-documenter_v7.24.2", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "7.24.1", + "tag": "@microsoft/api-documenter_v7.24.1", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "7.24.0", + "tag": "@microsoft/api-documenter_v7.24.0", + "date": "Sat, 16 Mar 2024 00:11:37 GMT", + "comments": { + "minor": [ + { + "comment": "Emit HTML tags for tables instead of Markdown code." + } + ] + } + }, + { + "version": "7.23.38", + "tag": "@microsoft/api-documenter_v7.23.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "7.23.37", + "tag": "@microsoft/api-documenter_v7.23.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "7.23.36", + "tag": "@microsoft/api-documenter_v7.23.36", + "date": "Sun, 03 Mar 2024 20:58:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "7.23.35", + "tag": "@microsoft/api-documenter_v7.23.35", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "7.23.34", + "tag": "@microsoft/api-documenter_v7.23.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "7.23.33", + "tag": "@microsoft/api-documenter_v7.23.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "7.23.32", + "tag": "@microsoft/api-documenter_v7.23.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "7.23.31", + "tag": "@microsoft/api-documenter_v7.23.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "7.23.30", + "tag": "@microsoft/api-documenter_v7.23.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "7.23.29", + "tag": "@microsoft/api-documenter_v7.23.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "7.23.28", + "tag": "@microsoft/api-documenter_v7.23.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "7.23.27", + "tag": "@microsoft/api-documenter_v7.23.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "7.23.26", + "tag": "@microsoft/api-documenter_v7.23.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "7.23.25", + "tag": "@microsoft/api-documenter_v7.23.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "7.23.24", + "tag": "@microsoft/api-documenter_v7.23.24", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "7.23.23", + "tag": "@microsoft/api-documenter_v7.23.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "7.23.22", + "tag": "@microsoft/api-documenter_v7.23.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "7.23.21", + "tag": "@microsoft/api-documenter_v7.23.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "7.23.20", + "tag": "@microsoft/api-documenter_v7.23.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "7.23.19", + "tag": "@microsoft/api-documenter_v7.23.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "7.23.18", + "tag": "@microsoft/api-documenter_v7.23.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "7.23.17", + "tag": "@microsoft/api-documenter_v7.23.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "7.23.16", + "tag": "@microsoft/api-documenter_v7.23.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "7.23.15", + "tag": "@microsoft/api-documenter_v7.23.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "7.23.14", + "tag": "@microsoft/api-documenter_v7.23.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "7.23.13", + "tag": "@microsoft/api-documenter_v7.23.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "7.23.12", + "tag": "@microsoft/api-documenter_v7.23.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "7.23.11", + "tag": "@microsoft/api-documenter_v7.23.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "7.23.10", + "tag": "@microsoft/api-documenter_v7.23.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "7.23.9", + "tag": "@microsoft/api-documenter_v7.23.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "7.23.8", + "tag": "@microsoft/api-documenter_v7.23.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "patch": [ + { + "comment": "Add notes for @alpha items when encountered. Mimics the existing behavior for @beta items." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "7.23.7", + "tag": "@microsoft/api-documenter_v7.23.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "7.23.6", + "tag": "@microsoft/api-documenter_v7.23.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "7.23.5", + "tag": "@microsoft/api-documenter_v7.23.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "7.23.4", + "tag": "@microsoft/api-documenter_v7.23.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "7.23.3", + "tag": "@microsoft/api-documenter_v7.23.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "7.23.2", + "tag": "@microsoft/api-documenter_v7.23.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "7.23.1", + "tag": "@microsoft/api-documenter_v7.23.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "7.23.0", + "tag": "@microsoft/api-documenter_v7.23.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "7.22.33", + "tag": "@microsoft/api-documenter_v7.22.33", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "7.22.32", + "tag": "@microsoft/api-documenter_v7.22.32", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "7.22.31", + "tag": "@microsoft/api-documenter_v7.22.31", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "7.22.30", + "tag": "@microsoft/api-documenter_v7.22.30", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "7.22.29", + "tag": "@microsoft/api-documenter_v7.22.29", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "7.22.28", + "tag": "@microsoft/api-documenter_v7.22.28", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "7.22.27", + "tag": "@microsoft/api-documenter_v7.22.27", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "7.22.26", + "tag": "@microsoft/api-documenter_v7.22.26", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "7.22.25", + "tag": "@microsoft/api-documenter_v7.22.25", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "7.22.24", + "tag": "@microsoft/api-documenter_v7.22.24", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "7.22.23", + "tag": "@microsoft/api-documenter_v7.22.23", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "7.22.22", + "tag": "@microsoft/api-documenter_v7.22.22", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "7.22.21", + "tag": "@microsoft/api-documenter_v7.22.21", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "7.22.20", + "tag": "@microsoft/api-documenter_v7.22.20", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "7.22.19", + "tag": "@microsoft/api-documenter_v7.22.19", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "7.22.18", + "tag": "@microsoft/api-documenter_v7.22.18", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "7.22.17", + "tag": "@microsoft/api-documenter_v7.22.17", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "7.22.16", + "tag": "@microsoft/api-documenter_v7.22.16", + "date": "Fri, 09 Jun 2023 18:05:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "7.22.15", + "tag": "@microsoft/api-documenter_v7.22.15", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "7.22.14", + "tag": "@microsoft/api-documenter_v7.22.14", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "7.22.13", + "tag": "@microsoft/api-documenter_v7.22.13", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "7.22.12", + "tag": "@microsoft/api-documenter_v7.22.12", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "7.22.11", + "tag": "@microsoft/api-documenter_v7.22.11", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "7.22.10", + "tag": "@microsoft/api-documenter_v7.22.10", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "7.22.9", + "tag": "@microsoft/api-documenter_v7.22.9", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "7.22.8", + "tag": "@microsoft/api-documenter_v7.22.8", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "7.22.7", + "tag": "@microsoft/api-documenter_v7.22.7", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "7.22.6", + "tag": "@microsoft/api-documenter_v7.22.6", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "7.22.5", + "tag": "@microsoft/api-documenter_v7.22.5", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "7.22.4", + "tag": "@microsoft/api-documenter_v7.22.4", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "7.22.3", + "tag": "@microsoft/api-documenter_v7.22.3", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "7.22.2", + "tag": "@microsoft/api-documenter_v7.22.2", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "7.22.1", + "tag": "@microsoft/api-documenter_v7.22.1", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "7.22.0", + "tag": "@microsoft/api-documenter_v7.22.0", + "date": "Thu, 27 Apr 2023 00:22:57 GMT", + "comments": { + "minor": [ + { + "comment": "Update OfficeYamlDocumenter to label all samples as TypeScript and no longer escape asterisks." + } + ] + } + }, + { + "version": "7.21.7", + "tag": "@microsoft/api-documenter_v7.21.7", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "7.21.6", + "tag": "@microsoft/api-documenter_v7.21.6", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "7.21.5", + "tag": "@microsoft/api-documenter_v7.21.5", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "7.21.4", + "tag": "@microsoft/api-documenter_v7.21.4", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "7.21.3", + "tag": "@microsoft/api-documenter_v7.21.3", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "7.21.2", + "tag": "@microsoft/api-documenter_v7.21.2", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "7.21.1", + "tag": "@microsoft/api-documenter_v7.21.1", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "7.21.0", + "tag": "@microsoft/api-documenter_v7.21.0", + "date": "Sun, 29 Jan 2023 20:09:58 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where ``/`` tags sometimes interfered with parsing of other Markdown on the same line; italics and boldface are now emitted using `*` and `_`" + } + ] + } + }, + { + "version": "7.20.1", + "tag": "@microsoft/api-documenter_v7.20.1", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "7.20.0", + "tag": "@microsoft/api-documenter_v7.20.0", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "minor": [ + { + "comment": "Display the 'abstract' modifier for classes and members (GitHub #3661)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "7.19.28", + "tag": "@microsoft/api-documenter_v7.19.28", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "7.19.27", + "tag": "@microsoft/api-documenter_v7.19.27", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "7.19.26", + "tag": "@microsoft/api-documenter_v7.19.26", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "7.19.25", + "tag": "@microsoft/api-documenter_v7.19.25", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "7.19.24", + "tag": "@microsoft/api-documenter_v7.19.24", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "7.19.23", + "tag": "@microsoft/api-documenter_v7.19.23", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "patch": [ + { + "comment": "Update the @microsoft/tsdoc dependency version to 0.14.2." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "7.19.22", + "tag": "@microsoft/api-documenter_v7.19.22", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "7.19.21", + "tag": "@microsoft/api-documenter_v7.19.21", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "7.19.20", + "tag": "@microsoft/api-documenter_v7.19.20", + "date": "Fri, 14 Oct 2022 15:26:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "7.19.19", + "tag": "@microsoft/api-documenter_v7.19.19", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "7.19.18", + "tag": "@microsoft/api-documenter_v7.19.18", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "7.19.17", + "tag": "@microsoft/api-documenter_v7.19.17", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "7.19.16", + "tag": "@microsoft/api-documenter_v7.19.16", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "7.19.15", + "tag": "@microsoft/api-documenter_v7.19.15", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "7.19.14", + "tag": "@microsoft/api-documenter_v7.19.14", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "7.19.13", + "tag": "@microsoft/api-documenter_v7.19.13", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "7.19.12", + "tag": "@microsoft/api-documenter_v7.19.12", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "7.19.11", + "tag": "@microsoft/api-documenter_v7.19.11", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "7.19.10", + "tag": "@microsoft/api-documenter_v7.19.10", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "7.19.9", + "tag": "@microsoft/api-documenter_v7.19.9", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "7.19.8", + "tag": "@microsoft/api-documenter_v7.19.8", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "7.19.7", + "tag": "@microsoft/api-documenter_v7.19.7", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "7.19.6", + "tag": "@microsoft/api-documenter_v7.19.6", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "7.19.5", + "tag": "@microsoft/api-documenter_v7.19.5", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "7.19.4", + "tag": "@microsoft/api-documenter_v7.19.4", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "7.19.3", + "tag": "@microsoft/api-documenter_v7.19.3", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "7.19.2", + "tag": "@microsoft/api-documenter_v7.19.2", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "7.19.1", + "tag": "@microsoft/api-documenter_v7.19.1", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "7.19.0", + "tag": "@microsoft/api-documenter_v7.19.0", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "minor": [ + { + "comment": "Add showInheritedMembers config to api-documenter that allows it to show an API item's inherited members." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "7.18.4", + "tag": "@microsoft/api-documenter_v7.18.4", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "7.18.3", + "tag": "@microsoft/api-documenter_v7.18.3", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "7.18.2", + "tag": "@microsoft/api-documenter_v7.18.2", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "7.18.1", + "tag": "@microsoft/api-documenter_v7.18.1", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "7.18.0", + "tag": "@microsoft/api-documenter_v7.18.0", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "minor": [ + { + "comment": "Show protected and readonly modifiers for relevant API items" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "7.17.26", + "tag": "@microsoft/api-documenter_v7.17.26", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "7.17.25", + "tag": "@microsoft/api-documenter_v7.17.25", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "7.17.24", + "tag": "@microsoft/api-documenter_v7.17.24", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "7.17.23", + "tag": "@microsoft/api-documenter_v7.17.23", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "patch": [ + { + "comment": "Minor change to support the new ApiInitializerMixin mixin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "7.17.22", + "tag": "@microsoft/api-documenter_v7.17.22", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "7.17.21", + "tag": "@microsoft/api-documenter_v7.17.21", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "7.17.20", + "tag": "@microsoft/api-documenter_v7.17.20", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "7.17.19", + "tag": "@microsoft/api-documenter_v7.17.19", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "7.17.18", + "tag": "@microsoft/api-documenter_v7.17.18", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "7.17.17", + "tag": "@microsoft/api-documenter_v7.17.17", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "7.17.16", + "tag": "@microsoft/api-documenter_v7.17.16", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "7.17.15", + "tag": "@microsoft/api-documenter_v7.17.15", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "7.17.14", + "tag": "@microsoft/api-documenter_v7.17.14", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "7.17.13", + "tag": "@microsoft/api-documenter_v7.17.13", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "7.17.12", + "tag": "@microsoft/api-documenter_v7.17.12", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "7.17.11", + "tag": "@microsoft/api-documenter_v7.17.11", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "7.17.10", + "tag": "@microsoft/api-documenter_v7.17.10", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "7.17.9", + "tag": "@microsoft/api-documenter_v7.17.9", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "7.17.8", + "tag": "@microsoft/api-documenter_v7.17.8", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "7.17.7", + "tag": "@microsoft/api-documenter_v7.17.7", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "7.17.6", + "tag": "@microsoft/api-documenter_v7.17.6", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "patch": [ + { + "comment": "Update TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "7.17.5", + "tag": "@microsoft/api-documenter_v7.17.5", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "7.17.4", + "tag": "@microsoft/api-documenter_v7.17.4", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "7.17.3", + "tag": "@microsoft/api-documenter_v7.17.3", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "7.17.2", + "tag": "@microsoft/api-documenter_v7.17.2", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "7.17.1", + "tag": "@microsoft/api-documenter_v7.17.1", + "date": "Tue, 05 Apr 2022 15:12:22 GMT", + "comments": { + "patch": [ + { + "comment": "Update requirement set links in OfficeYamlDocumenter" + } + ] + } + }, + { + "version": "7.17.0", + "tag": "@microsoft/api-documenter_v7.17.0", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "minor": [ + { + "comment": "Updated api-documenter to surface whether a parameter is optional." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "7.16.0", + "tag": "@microsoft/api-documenter_v7.16.0", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "minor": [ + { + "comment": "Add --yaml-format flag for `api-documenter yaml` command, which allows for choosing between UDP (DocFX 2.x) and SDP (DocFX 3.x)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "7.15.4", + "tag": "@microsoft/api-documenter_v7.15.4", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "7.15.3", + "tag": "@microsoft/api-documenter_v7.15.3", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "7.15.2", + "tag": "@microsoft/api-documenter_v7.15.2", + "date": "Wed, 09 Feb 2022 16:18:11 GMT", + "comments": { + "patch": [ + { + "comment": "Adding PowerPoint option to OfficeYamlDocumenter API set mapping" + } + ] + } + }, + { + "version": "7.15.1", + "tag": "@microsoft/api-documenter_v7.15.1", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "7.15.0", + "tag": "@microsoft/api-documenter_v7.15.0", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for type aliases to the YAML output format." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "7.14.2", + "tag": "@microsoft/api-documenter_v7.14.2", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "7.14.1", + "tag": "@microsoft/api-documenter_v7.14.1", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "7.14.0", + "tag": "@microsoft/api-documenter_v7.14.0", + "date": "Wed, 05 Jan 2022 01:09:53 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for @example when generating yaml" + } + ] + } + }, + { + "version": "7.13.78", + "tag": "@microsoft/api-documenter_v7.13.78", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "7.13.77", + "tag": "@microsoft/api-documenter_v7.13.77", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "7.13.76", + "tag": "@microsoft/api-documenter_v7.13.76", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "7.13.75", + "tag": "@microsoft/api-documenter_v7.13.75", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "7.13.74", + "tag": "@microsoft/api-documenter_v7.13.74", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "7.13.73", + "tag": "@microsoft/api-documenter_v7.13.73", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "7.13.72", + "tag": "@microsoft/api-documenter_v7.13.72", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "7.13.71", + "tag": "@microsoft/api-documenter_v7.13.71", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "7.13.70", + "tag": "@microsoft/api-documenter_v7.13.70", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "7.13.69", + "tag": "@microsoft/api-documenter_v7.13.69", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "7.13.68", + "tag": "@microsoft/api-documenter_v7.13.68", + "date": "Tue, 09 Nov 2021 01:09:37 GMT", + "comments": { + "patch": [ + { + "comment": "Links to enum members go to the enum page in markdown output" + } + ] + } + }, + { + "version": "7.13.67", + "tag": "@microsoft/api-documenter_v7.13.67", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "7.13.66", + "tag": "@microsoft/api-documenter_v7.13.66", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "7.13.65", + "tag": "@microsoft/api-documenter_v7.13.65", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "7.13.64", + "tag": "@microsoft/api-documenter_v7.13.64", + "date": "Wed, 27 Oct 2021 00:08:14 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "7.13.63", + "tag": "@microsoft/api-documenter_v7.13.63", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "7.13.62", + "tag": "@microsoft/api-documenter_v7.13.62", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "7.13.61", + "tag": "@microsoft/api-documenter_v7.13.61", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "7.13.60", + "tag": "@microsoft/api-documenter_v7.13.60", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "7.13.59", + "tag": "@microsoft/api-documenter_v7.13.59", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "7.13.58", + "tag": "@microsoft/api-documenter_v7.13.58", + "date": "Wed, 06 Oct 2021 15:08:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "7.13.57", + "tag": "@microsoft/api-documenter_v7.13.57", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "7.13.56", + "tag": "@microsoft/api-documenter_v7.13.56", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "7.13.55", + "tag": "@microsoft/api-documenter_v7.13.55", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "7.13.54", + "tag": "@microsoft/api-documenter_v7.13.54", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "7.13.53", + "tag": "@microsoft/api-documenter_v7.13.53", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "7.13.52", + "tag": "@microsoft/api-documenter_v7.13.52", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "7.13.51", + "tag": "@microsoft/api-documenter_v7.13.51", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "7.13.50", + "tag": "@microsoft/api-documenter_v7.13.50", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "7.13.49", + "tag": "@microsoft/api-documenter_v7.13.49", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "7.13.48", + "tag": "@microsoft/api-documenter_v7.13.48", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "7.13.47", + "tag": "@microsoft/api-documenter_v7.13.47", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "7.13.46", + "tag": "@microsoft/api-documenter_v7.13.46", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "7.13.45", + "tag": "@microsoft/api-documenter_v7.13.45", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "7.13.44", + "tag": "@microsoft/api-documenter_v7.13.44", + "date": "Fri, 03 Sep 2021 00:09:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "7.13.43", + "tag": "@microsoft/api-documenter_v7.13.43", + "date": "Thu, 02 Sep 2021 00:06:51 GMT", + "comments": { + "patch": [ + { + "comment": "Remove redundant newline in fenced code blocks" + } + ] + } + }, + { + "version": "7.13.42", + "tag": "@microsoft/api-documenter_v7.13.42", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "7.13.41", + "tag": "@microsoft/api-documenter_v7.13.41", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "7.13.40", + "tag": "@microsoft/api-documenter_v7.13.40", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "7.13.39", + "tag": "@microsoft/api-documenter_v7.13.39", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "7.13.38", + "tag": "@microsoft/api-documenter_v7.13.38", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "7.13.37", + "tag": "@microsoft/api-documenter_v7.13.37", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "7.13.36", + "tag": "@microsoft/api-documenter_v7.13.36", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "7.13.35", + "tag": "@microsoft/api-documenter_v7.13.35", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "7.13.34", + "tag": "@microsoft/api-documenter_v7.13.34", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "7.13.33", + "tag": "@microsoft/api-documenter_v7.13.33", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "7.13.32", + "tag": "@microsoft/api-documenter_v7.13.32", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "7.13.31", + "tag": "@microsoft/api-documenter_v7.13.31", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "7.13.30", + "tag": "@microsoft/api-documenter_v7.13.30", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "7.13.29", + "tag": "@microsoft/api-documenter_v7.13.29", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "7.13.28", + "tag": "@microsoft/api-documenter_v7.13.28", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "7.13.27", + "tag": "@microsoft/api-documenter_v7.13.27", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "7.13.26", + "tag": "@microsoft/api-documenter_v7.13.26", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "7.13.25", + "tag": "@microsoft/api-documenter_v7.13.25", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "7.13.24", + "tag": "@microsoft/api-documenter_v7.13.24", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "7.13.23", + "tag": "@microsoft/api-documenter_v7.13.23", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "7.13.22", + "tag": "@microsoft/api-documenter_v7.13.22", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "7.13.21", + "tag": "@microsoft/api-documenter_v7.13.21", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "7.13.20", + "tag": "@microsoft/api-documenter_v7.13.20", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "7.13.19", + "tag": "@microsoft/api-documenter_v7.13.19", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "7.13.18", + "tag": "@microsoft/api-documenter_v7.13.18", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "7.13.17", + "tag": "@microsoft/api-documenter_v7.13.17", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "7.13.16", + "tag": "@microsoft/api-documenter_v7.13.16", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "7.13.15", + "tag": "@microsoft/api-documenter_v7.13.15", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "7.13.14", + "tag": "@microsoft/api-documenter_v7.13.14", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "7.13.13", + "tag": "@microsoft/api-documenter_v7.13.13", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "7.13.12", + "tag": "@microsoft/api-documenter_v7.13.12", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "7.13.11", + "tag": "@microsoft/api-documenter_v7.13.11", + "date": "Fri, 28 May 2021 06:19:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "7.13.10", + "tag": "@microsoft/api-documenter_v7.13.10", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "7.13.9", + "tag": "@microsoft/api-documenter_v7.13.9", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "7.13.8", + "tag": "@microsoft/api-documenter_v7.13.8", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "7.13.7", + "tag": "@microsoft/api-documenter_v7.13.7", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "7.13.6", + "tag": "@microsoft/api-documenter_v7.13.6", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "7.13.5", + "tag": "@microsoft/api-documenter_v7.13.5", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "7.13.4", + "tag": "@microsoft/api-documenter_v7.13.4", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "7.13.3", + "tag": "@microsoft/api-documenter_v7.13.3", + "date": "Fri, 23 Apr 2021 22:00:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "7.13.2", + "tag": "@microsoft/api-documenter_v7.13.2", + "date": "Fri, 23 Apr 2021 15:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "7.13.1", + "tag": "@microsoft/api-documenter_v7.13.1", + "date": "Wed, 21 Apr 2021 15:12:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "7.13.0", + "tag": "@microsoft/api-documenter_v7.13.0", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for projects that define custom tags using a tsdoc.json file" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "7.12.22", + "tag": "@microsoft/api-documenter_v7.12.22", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "7.12.21", + "tag": "@microsoft/api-documenter_v7.12.21", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "patch": [ + { + "comment": "split events from properties" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "7.12.20", + "tag": "@microsoft/api-documenter_v7.12.20", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "7.12.19", + "tag": "@microsoft/api-documenter_v7.12.19", + "date": "Thu, 08 Apr 2021 06:05:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "7.12.18", + "tag": "@microsoft/api-documenter_v7.12.18", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "7.12.17", + "tag": "@microsoft/api-documenter_v7.12.17", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "7.12.16", + "tag": "@microsoft/api-documenter_v7.12.16", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "7.12.15", + "tag": "@microsoft/api-documenter_v7.12.15", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "7.12.14", + "tag": "@microsoft/api-documenter_v7.12.14", + "date": "Fri, 19 Mar 2021 22:31:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "7.12.13", + "tag": "@microsoft/api-documenter_v7.12.13", + "date": "Wed, 17 Mar 2021 05:04:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "7.12.12", + "tag": "@microsoft/api-documenter_v7.12.12", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "7.12.11", + "tag": "@microsoft/api-documenter_v7.12.11", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "7.12.10", + "tag": "@microsoft/api-documenter_v7.12.10", + "date": "Wed, 10 Mar 2021 05:10:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "7.12.9", + "tag": "@microsoft/api-documenter_v7.12.9", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "7.12.8", + "tag": "@microsoft/api-documenter_v7.12.8", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "7.12.7", + "tag": "@microsoft/api-documenter_v7.12.7", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "7.12.6", + "tag": "@microsoft/api-documenter_v7.12.6", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "7.12.5", + "tag": "@microsoft/api-documenter_v7.12.5", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "7.12.4", + "tag": "@microsoft/api-documenter_v7.12.4", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "7.12.3", + "tag": "@microsoft/api-documenter_v7.12.3", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "7.12.2", + "tag": "@microsoft/api-documenter_v7.12.2", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "7.12.1", + "tag": "@microsoft/api-documenter_v7.12.1", + "date": "Mon, 14 Dec 2020 16:12:20 GMT", + "comments": { + "patch": [ + { + "comment": "change udp to sdp" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "7.12.0", + "tag": "@microsoft/api-documenter_v7.12.0", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "minor": [ + { + "comment": "Implement rendering of the \"@decorator\" TSDoc tag" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "7.11.3", + "tag": "@microsoft/api-documenter_v7.11.3", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "7.11.2", + "tag": "@microsoft/api-documenter_v7.11.2", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "7.11.1", + "tag": "@microsoft/api-documenter_v7.11.1", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "7.11.0", + "tag": "@microsoft/api-documenter_v7.11.0", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "minor": [ + { + "comment": "Both methods and properties can now be displayed as \"optional\" in the documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "7.10.1", + "tag": "@microsoft/api-documenter_v7.10.1", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "7.10.0", + "tag": "@microsoft/api-documenter_v7.10.0", + "date": "Wed, 18 Nov 2020 03:15:22 GMT", + "comments": { + "patch": [ + { + "comment": "Marking optional properties on interface reference docs" + } + ], + "minor": [ + { + "comment": "Support for generating hyperlinks from type aliases" + } + ] + } + }, + { + "version": "7.9.33", + "tag": "@microsoft/api-documenter_v7.9.33", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "7.9.32", + "tag": "@microsoft/api-documenter_v7.9.32", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "7.9.31", + "tag": "@microsoft/api-documenter_v7.9.31", + "date": "Fri, 13 Nov 2020 01:11:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "7.9.30", + "tag": "@microsoft/api-documenter_v7.9.30", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "7.9.29", + "tag": "@microsoft/api-documenter_v7.9.29", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "7.9.28", + "tag": "@microsoft/api-documenter_v7.9.28", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "7.9.27", + "tag": "@microsoft/api-documenter_v7.9.27", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "7.9.26", + "tag": "@microsoft/api-documenter_v7.9.26", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "7.9.25", + "tag": "@microsoft/api-documenter_v7.9.25", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "7.9.24", + "tag": "@microsoft/api-documenter_v7.9.24", + "date": "Tue, 03 Nov 2020 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "7.9.23", + "tag": "@microsoft/api-documenter_v7.9.23", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "7.9.22", + "tag": "@microsoft/api-documenter_v7.9.22", + "date": "Fri, 30 Oct 2020 06:38:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "7.9.21", + "tag": "@microsoft/api-documenter_v7.9.21", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "7.9.20", + "tag": "@microsoft/api-documenter_v7.9.20", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "7.9.19", + "tag": "@microsoft/api-documenter_v7.9.19", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "7.9.18", + "tag": "@microsoft/api-documenter_v7.9.18", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "7.9.17", + "tag": "@microsoft/api-documenter_v7.9.17", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "7.9.16", + "tag": "@microsoft/api-documenter_v7.9.16", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "7.9.15", + "tag": "@microsoft/api-documenter_v7.9.15", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "7.9.14", + "tag": "@microsoft/api-documenter_v7.9.14", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "7.9.13", + "tag": "@microsoft/api-documenter_v7.9.13", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "7.9.12", + "tag": "@microsoft/api-documenter_v7.9.12", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "7.9.11", + "tag": "@microsoft/api-documenter_v7.9.11", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "7.9.10", + "tag": "@microsoft/api-documenter_v7.9.10", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "7.9.9", + "tag": "@microsoft/api-documenter_v7.9.9", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "7.9.8", + "tag": "@microsoft/api-documenter_v7.9.8", + "date": "Fri, 09 Oct 2020 15:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "7.9.7", + "tag": "@microsoft/api-documenter_v7.9.7", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "7.9.6", + "tag": "@microsoft/api-documenter_v7.9.6", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "7.9.5", + "tag": "@microsoft/api-documenter_v7.9.5", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "7.9.4", + "tag": "@microsoft/api-documenter_v7.9.4", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "7.9.3", + "tag": "@microsoft/api-documenter_v7.9.3", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "7.9.2", + "tag": "@microsoft/api-documenter_v7.9.2", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "7.9.1", + "tag": "@microsoft/api-documenter_v7.9.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "7.9.0", + "tag": "@microsoft/api-documenter_v7.9.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "minor": [ + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "7.8.56", + "tag": "@microsoft/api-documenter_v7.8.56", + "date": "Tue, 22 Sep 2020 05:45:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "7.8.55", + "tag": "@microsoft/api-documenter_v7.8.55", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "7.8.54", + "tag": "@microsoft/api-documenter_v7.8.54", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "7.8.53", + "tag": "@microsoft/api-documenter_v7.8.53", + "date": "Sat, 19 Sep 2020 04:37:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "7.8.52", + "tag": "@microsoft/api-documenter_v7.8.52", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "7.8.51", + "tag": "@microsoft/api-documenter_v7.8.51", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "7.8.50", + "tag": "@microsoft/api-documenter_v7.8.50", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "7.8.49", + "tag": "@microsoft/api-documenter_v7.8.49", + "date": "Wed, 16 Sep 2020 05:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "7.8.48", + "tag": "@microsoft/api-documenter_v7.8.48", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "7.8.47", + "tag": "@microsoft/api-documenter_v7.8.47", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "7.8.46", + "tag": "@microsoft/api-documenter_v7.8.46", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "7.8.45", + "tag": "@microsoft/api-documenter_v7.8.45", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "7.8.44", + "tag": "@microsoft/api-documenter_v7.8.44", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "7.8.43", + "tag": "@microsoft/api-documenter_v7.8.43", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "7.8.42", + "tag": "@microsoft/api-documenter_v7.8.42", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "7.8.41", + "tag": "@microsoft/api-documenter_v7.8.41", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.20`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "7.8.40", + "tag": "@microsoft/api-documenter_v7.8.40", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "7.8.39", + "tag": "@microsoft/api-documenter_v7.8.39", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "7.8.38", + "tag": "@microsoft/api-documenter_v7.8.38", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "7.8.37", + "tag": "@microsoft/api-documenter_v7.8.37", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "7.8.36", + "tag": "@microsoft/api-documenter_v7.8.36", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "7.8.35", + "tag": "@microsoft/api-documenter_v7.8.35", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "7.8.34", + "tag": "@microsoft/api-documenter_v7.8.34", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "7.8.33", + "tag": "@microsoft/api-documenter_v7.8.33", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "7.8.32", + "tag": "@microsoft/api-documenter_v7.8.32", + "date": "Fri, 21 Aug 2020 01:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "7.8.31", + "tag": "@microsoft/api-documenter_v7.8.31", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "7.8.30", + "tag": "@microsoft/api-documenter_v7.8.30", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "7.8.29", + "tag": "@microsoft/api-documenter_v7.8.29", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "7.8.28", + "tag": "@microsoft/api-documenter_v7.8.28", + "date": "Tue, 18 Aug 2020 03:03:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "7.8.27", + "tag": "@microsoft/api-documenter_v7.8.27", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "7.8.26", + "tag": "@microsoft/api-documenter_v7.8.26", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an error was sometimes incorrectly reported: \"The constructed subclass was not an instance of MarkdownDocumenterFeature\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "7.8.25", + "tag": "@microsoft/api-documenter_v7.8.25", + "date": "Thu, 13 Aug 2020 09:26:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "7.8.24", + "tag": "@microsoft/api-documenter_v7.8.24", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "7.8.23", + "tag": "@microsoft/api-documenter_v7.8.23", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "7.8.22", + "tag": "@microsoft/api-documenter_v7.8.22", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "7.8.21", + "tag": "@microsoft/api-documenter_v7.8.21", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.11` to `7.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + } + ] + } + }, + { + "version": "7.8.20", + "tag": "@microsoft/api-documenter_v7.8.20", + "date": "Fri, 03 Jul 2020 05:46:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.5` to `4.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "7.8.19", + "tag": "@microsoft/api-documenter_v7.8.19", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "7.8.18", + "tag": "@microsoft/api-documenter_v7.8.18", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "7.8.17", + "tag": "@microsoft/api-documenter_v7.8.17", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.10` to `7.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.4` to `4.4.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "7.8.16", + "tag": "@microsoft/api-documenter_v7.8.16", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.9` to `7.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.3` to `4.4.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "7.8.15", + "tag": "@microsoft/api-documenter_v7.8.15", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.8` to `7.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.2` to `4.4.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "7.8.14", + "tag": "@microsoft/api-documenter_v7.8.14", + "date": "Sun, 21 Jun 2020 04:21:01 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the Markdown target to show hyperlinked \"extends\" and \"implements\" types for class and interface APIs" + } + ] + } + }, + { + "version": "7.8.13", + "tag": "@microsoft/api-documenter_v7.8.13", + "date": "Mon, 15 Jun 2020 22:17:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "7.8.12", + "tag": "@microsoft/api-documenter_v7.8.12", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "7.8.11", + "tag": "@microsoft/api-documenter_v7.8.11", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.7` to `7.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + } + ] + } + }, + { + "version": "7.8.10", + "tag": "@microsoft/api-documenter_v7.8.10", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.1` to `4.4.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "7.8.9", + "tag": "@microsoft/api-documenter_v7.8.9", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.6` to `7.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + } + ] + } + }, + { + "version": "7.8.8", + "tag": "@microsoft/api-documenter_v7.8.8", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.5` to `7.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + } + ] + } + }, + { + "version": "7.8.7", + "tag": "@microsoft/api-documenter_v7.8.7", + "date": "Wed, 27 May 2020 05:15:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.4` to `7.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.0` to `4.4.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "7.8.6", + "tag": "@microsoft/api-documenter_v7.8.6", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.3` to `7.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + } + ] + } + }, + { + "version": "7.8.5", + "tag": "@microsoft/api-documenter_v7.8.5", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.2` to `7.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + } + ] + } + }, + { + "version": "7.8.4", + "tag": "@microsoft/api-documenter_v7.8.4", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.1` to `7.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + } + ] + } + }, + { + "version": "7.8.3", + "tag": "@microsoft/api-documenter_v7.8.3", + "date": "Thu, 21 May 2020 15:41:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.0` to `7.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "7.8.2", + "tag": "@microsoft/api-documenter_v7.8.2", + "date": "Tue, 19 May 2020 15:08:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "7.8.1", + "tag": "@microsoft/api-documenter_v7.8.1", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.14` to `4.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "7.8.0", + "tag": "@microsoft/api-documenter_v7.8.0", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "minor": [ + { + "comment": "For markdown output, parameter types and return types are now hyperlinked to the corresponding API item" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.11` to `7.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "7.7.20", + "tag": "@microsoft/api-documenter_v7.7.20", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "7.7.19", + "tag": "@microsoft/api-documenter_v7.7.19", + "date": "Fri, 24 Apr 2020 15:09:06 GMT", + "comments": { + "patch": [ + { + "comment": "Properly encode xrefs that contain '#' characters." + } + ] + } + }, + { + "version": "7.7.18", + "tag": "@microsoft/api-documenter_v7.7.18", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.10` to `7.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.13` to `4.3.14`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "7.7.17", + "tag": "@microsoft/api-documenter_v7.7.17", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "7.7.16", + "tag": "@microsoft/api-documenter_v7.7.16", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "7.7.15", + "tag": "@microsoft/api-documenter_v7.7.15", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to TSdoc 0.12.19" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.9` to `7.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.12` to `4.3.13`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "7.7.14", "tag": "@microsoft/api-documenter_v7.7.14", diff --git a/apps/api-documenter/CHANGELOG.md b/apps/api-documenter/CHANGELOG.md index 62af73328b5..2df8e9808f1 100644 --- a/apps/api-documenter/CHANGELOG.md +++ b/apps/api-documenter/CHANGELOG.md @@ -1,11 +1,2315 @@ # Change Log - @microsoft/api-documenter -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 7.26.2 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 7.26.1 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 7.26.0 +Sat, 23 Nov 2024 01:18:55 GMT + +### Minor changes + +- Update TSDoc dependencies. + +## 7.25.22 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 7.25.21 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 7.25.20 +Mon, 21 Oct 2024 18:50:09 GMT + +_Version update only_ + +## 7.25.19 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 7.25.18 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 7.25.17 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 7.25.16 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 7.25.15 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 7.25.14 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 7.25.13 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 7.25.12 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 7.25.11 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 7.25.10 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 7.25.9 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 7.25.8 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 7.25.7 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 7.25.6 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 7.25.5 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 7.25.4 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 7.25.3 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 7.25.2 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 7.25.1 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 7.25.0 +Wed, 29 May 2024 00:10:52 GMT + +### Minor changes + +- Bump TSDoc dependencies. + +## 7.24.13 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 7.24.12 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 7.24.11 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 7.24.10 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 7.24.9 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 7.24.8 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 7.24.7 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 7.24.6 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 7.24.5 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 7.24.4 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 7.24.3 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 7.24.2 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 7.24.1 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 7.24.0 +Sat, 16 Mar 2024 00:11:37 GMT + +### Minor changes + +- Emit HTML tags for tables instead of Markdown code. + +## 7.23.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 7.23.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 7.23.36 +Sun, 03 Mar 2024 20:58:12 GMT + +_Version update only_ + +## 7.23.35 +Sat, 02 Mar 2024 02:22:23 GMT + +_Version update only_ + +## 7.23.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 7.23.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 7.23.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 7.23.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 7.23.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 7.23.29 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 7.23.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 7.23.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 7.23.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 7.23.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 7.23.24 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 7.23.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 7.23.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 7.23.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 7.23.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 7.23.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 7.23.18 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 7.23.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 7.23.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 7.23.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 7.23.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 7.23.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 7.23.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 7.23.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 7.23.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 7.23.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 7.23.8 +Sat, 30 Sep 2023 00:20:51 GMT + +### Patches + +- Add notes for @alpha items when encountered. Mimics the existing behavior for @beta items. + +## 7.23.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 7.23.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 7.23.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 7.23.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 7.23.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 7.23.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 7.23.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 7.23.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 7.22.33 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 7.22.32 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 7.22.31 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 7.22.30 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 7.22.29 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 7.22.28 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 7.22.27 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 7.22.26 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 7.22.25 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 7.22.24 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 7.22.23 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 7.22.22 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 7.22.21 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 7.22.20 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 7.22.19 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 7.22.18 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 7.22.17 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 7.22.16 +Fri, 09 Jun 2023 18:05:34 GMT + +_Version update only_ + +## 7.22.15 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 7.22.14 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 7.22.13 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 7.22.12 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 7.22.11 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 7.22.10 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 7.22.9 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 7.22.8 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 7.22.7 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 7.22.6 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 7.22.5 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 7.22.4 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 7.22.3 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 7.22.2 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 7.22.1 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 7.22.0 +Thu, 27 Apr 2023 00:22:57 GMT + +### Minor changes + +- Update OfficeYamlDocumenter to label all samples as TypeScript and no longer escape asterisks. + +## 7.21.7 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 7.21.6 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 7.21.5 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 7.21.4 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 7.21.3 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 7.21.2 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 7.21.1 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 7.21.0 +Sun, 29 Jan 2023 20:09:58 GMT + +### Minor changes + +- Fix an issue where ``/`` tags sometimes interfered with parsing of other Markdown on the same line; italics and boldface are now emitted using `*` and `_` + +## 7.20.1 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 7.20.0 +Wed, 25 Jan 2023 07:26:55 GMT + +### Minor changes + +- Display the 'abstract' modifier for classes and members (GitHub #3661) + +## 7.19.28 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 7.19.27 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 7.19.26 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 7.19.25 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 7.19.24 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 7.19.23 +Wed, 26 Oct 2022 00:16:16 GMT + +### Patches + +- Update the @microsoft/tsdoc dependency version to 0.14.2. + +## 7.19.22 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 7.19.21 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 7.19.20 +Fri, 14 Oct 2022 15:26:31 GMT + +_Version update only_ + +## 7.19.19 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 7.19.18 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 7.19.17 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 7.19.16 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 7.19.15 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 7.19.14 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 7.19.13 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 7.19.12 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 7.19.11 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 7.19.10 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 7.19.9 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 7.19.8 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 7.19.7 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 7.19.6 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 7.19.5 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 7.19.4 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 7.19.3 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 7.19.2 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 7.19.1 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 7.19.0 +Thu, 21 Jul 2022 23:30:27 GMT + +### Minor changes + +- Add showInheritedMembers config to api-documenter that allows it to show an API item's inherited members. + +## 7.18.4 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 7.18.3 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 7.18.2 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 7.18.1 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 7.18.0 +Thu, 30 Jun 2022 04:48:53 GMT + +### Minor changes + +- Show protected and readonly modifiers for relevant API items + +## 7.17.26 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 7.17.25 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 7.17.24 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 7.17.23 +Sat, 25 Jun 2022 21:00:40 GMT + +### Patches + +- Minor change to support the new ApiInitializerMixin mixin. + +## 7.17.22 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 7.17.21 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 7.17.20 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 7.17.19 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 7.17.18 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 7.17.17 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 7.17.16 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 7.17.15 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 7.17.14 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 7.17.13 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 7.17.12 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 7.17.11 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 7.17.10 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 7.17.9 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 7.17.8 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 7.17.7 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 7.17.6 +Tue, 12 Apr 2022 02:58:32 GMT + +### Patches + +- Update TSDoc dependencies. + +## 7.17.5 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 7.17.4 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 7.17.3 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 7.17.2 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 7.17.1 +Tue, 05 Apr 2022 15:12:22 GMT + +### Patches + +- Update requirement set links in OfficeYamlDocumenter + +## 7.17.0 +Thu, 31 Mar 2022 02:06:05 GMT + +### Minor changes + +- Updated api-documenter to surface whether a parameter is optional. + +## 7.16.0 +Sat, 19 Mar 2022 08:05:37 GMT + +### Minor changes + +- Add --yaml-format flag for `api-documenter yaml` command, which allows for choosing between UDP (DocFX 2.x) and SDP (DocFX 3.x) + +## 7.15.4 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 7.15.3 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 7.15.2 +Wed, 09 Feb 2022 16:18:11 GMT + +### Patches + +- Adding PowerPoint option to OfficeYamlDocumenter API set mapping + +## 7.15.1 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 7.15.0 +Fri, 21 Jan 2022 01:10:41 GMT + +### Minor changes + +- Add support for type aliases to the YAML output format. + +## 7.14.2 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 7.14.1 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 7.14.0 +Wed, 05 Jan 2022 01:09:53 GMT + +### Minor changes + +- Add support for @example when generating yaml + +## 7.13.78 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 7.13.77 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 7.13.76 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 7.13.75 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 7.13.74 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 7.13.73 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 7.13.72 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 7.13.71 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 7.13.70 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 7.13.69 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 7.13.68 +Tue, 09 Nov 2021 01:09:37 GMT + +### Patches + +- Links to enum members go to the enum page in markdown output + +## 7.13.67 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 7.13.66 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 7.13.65 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 7.13.64 +Wed, 27 Oct 2021 00:08:14 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 7.13.63 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 7.13.62 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 7.13.61 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 7.13.60 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 7.13.59 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 7.13.58 +Wed, 06 Oct 2021 15:08:25 GMT + +_Version update only_ + +## 7.13.57 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 7.13.56 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 7.13.55 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 7.13.54 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 7.13.53 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 7.13.52 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 7.13.51 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 7.13.50 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 7.13.49 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 7.13.48 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 7.13.47 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 7.13.46 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 7.13.45 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 7.13.44 +Fri, 03 Sep 2021 00:09:09 GMT + +_Version update only_ + +## 7.13.43 +Thu, 02 Sep 2021 00:06:51 GMT + +### Patches + +- Remove redundant newline in fenced code blocks + +## 7.13.42 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 7.13.41 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 7.13.40 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 7.13.39 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 7.13.38 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 7.13.37 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 7.13.36 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 7.13.35 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 7.13.34 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 7.13.33 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 7.13.32 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 7.13.31 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 7.13.30 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 7.13.29 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 7.13.28 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 7.13.27 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 7.13.26 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 7.13.25 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 7.13.24 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 7.13.23 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 7.13.22 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 7.13.21 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 7.13.20 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 7.13.19 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 7.13.18 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 7.13.17 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 7.13.16 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 7.13.15 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 7.13.14 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 7.13.13 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 7.13.12 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 7.13.11 +Fri, 28 May 2021 06:19:57 GMT + +_Version update only_ + +## 7.13.10 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 7.13.9 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 7.13.8 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 7.13.7 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 7.13.6 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 7.13.5 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 7.13.4 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 7.13.3 +Fri, 23 Apr 2021 22:00:06 GMT + +_Version update only_ + +## 7.13.2 +Fri, 23 Apr 2021 15:11:20 GMT + +_Version update only_ + +## 7.13.1 +Wed, 21 Apr 2021 15:12:27 GMT + +_Version update only_ + +## 7.13.0 +Tue, 20 Apr 2021 04:59:51 GMT + +### Minor changes + +- Add support for projects that define custom tags using a tsdoc.json file + +## 7.12.22 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 7.12.21 +Mon, 12 Apr 2021 15:10:28 GMT + +### Patches + +- split events from properties + +## 7.12.20 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 7.12.19 +Thu, 08 Apr 2021 06:05:31 GMT + +_Version update only_ + +## 7.12.18 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 7.12.17 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 7.12.16 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 7.12.15 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 7.12.14 +Fri, 19 Mar 2021 22:31:37 GMT + +_Version update only_ + +## 7.12.13 +Wed, 17 Mar 2021 05:04:37 GMT + +_Version update only_ + +## 7.12.12 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 7.12.11 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 7.12.10 +Wed, 10 Mar 2021 05:10:05 GMT + +_Version update only_ + +## 7.12.9 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 7.12.8 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 7.12.7 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 7.12.6 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 7.12.5 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 7.12.4 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 7.12.3 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 7.12.2 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 7.12.1 +Mon, 14 Dec 2020 16:12:20 GMT + +### Patches + +- change udp to sdp + +## 7.12.0 +Thu, 10 Dec 2020 23:25:49 GMT + +### Minor changes + +- Implement rendering of the "@decorator" TSDoc tag + +## 7.11.3 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 7.11.2 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 7.11.1 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 7.11.0 +Wed, 18 Nov 2020 08:19:54 GMT + +### Minor changes + +- Both methods and properties can now be displayed as "optional" in the documentation + +## 7.10.1 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 7.10.0 +Wed, 18 Nov 2020 03:15:22 GMT + +### Minor changes + +- Support for generating hyperlinks from type aliases + +### Patches + +- Marking optional properties on interface reference docs + +## 7.9.33 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 7.9.32 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 7.9.31 +Fri, 13 Nov 2020 01:11:00 GMT + +_Version update only_ + +## 7.9.30 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 7.9.29 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 7.9.28 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 7.9.27 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 7.9.26 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 7.9.25 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 7.9.24 +Tue, 03 Nov 2020 01:11:18 GMT + +_Version update only_ + +## 7.9.23 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 7.9.22 +Fri, 30 Oct 2020 06:38:38 GMT + +_Version update only_ + +## 7.9.21 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 7.9.20 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 7.9.19 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 7.9.18 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 7.9.17 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 7.9.16 +Sat, 24 Oct 2020 00:11:18 GMT + +_Version update only_ + +## 7.9.15 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 7.9.14 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 7.9.13 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 7.9.12 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 7.9.11 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 7.9.10 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 7.9.9 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 7.9.8 +Fri, 09 Oct 2020 15:11:08 GMT + +_Version update only_ + +## 7.9.7 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 7.9.6 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 7.9.5 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 7.9.4 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 7.9.3 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 7.9.2 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 7.9.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 7.9.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 7.8.56 +Tue, 22 Sep 2020 05:45:56 GMT + +_Version update only_ + +## 7.8.55 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 7.8.54 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 7.8.53 +Sat, 19 Sep 2020 04:37:26 GMT + +_Version update only_ + +## 7.8.52 +Sat, 19 Sep 2020 03:33:06 GMT + +_Version update only_ + +## 7.8.51 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 7.8.50 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 7.8.49 +Wed, 16 Sep 2020 05:30:25 GMT + +_Version update only_ + +## 7.8.48 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 7.8.47 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 7.8.46 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 7.8.45 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 7.8.44 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 7.8.43 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 7.8.42 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 7.8.41 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 7.8.40 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 7.8.39 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 7.8.38 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 7.8.37 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 7.8.36 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 7.8.35 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 7.8.34 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 7.8.33 +Sat, 22 Aug 2020 05:55:42 GMT + +_Version update only_ + +## 7.8.32 +Fri, 21 Aug 2020 01:21:17 GMT + +_Version update only_ + +## 7.8.31 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 7.8.30 +Thu, 20 Aug 2020 15:13:52 GMT + +_Version update only_ + +## 7.8.29 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 7.8.28 +Tue, 18 Aug 2020 03:03:23 GMT + +_Version update only_ + +## 7.8.27 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 7.8.26 +Mon, 17 Aug 2020 04:53:23 GMT + +### Patches + +- Fix an issue where an error was sometimes incorrectly reported: "The constructed subclass was not an instance of MarkdownDocumenterFeature" + +## 7.8.25 +Thu, 13 Aug 2020 09:26:39 GMT + +_Version update only_ + +## 7.8.24 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 7.8.23 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 7.8.22 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 7.8.21 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 7.8.20 +Fri, 03 Jul 2020 05:46:41 GMT + +_Version update only_ + +## 7.8.19 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 7.8.18 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 7.8.17 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 7.8.16 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 7.8.15 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 7.8.14 +Sun, 21 Jun 2020 04:21:01 GMT + +### Patches + +- Improve the Markdown target to show hyperlinked "extends" and "implements" types for class and interface APIs + +## 7.8.13 +Mon, 15 Jun 2020 22:17:17 GMT + +_Version update only_ + +## 7.8.12 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 7.8.11 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 7.8.10 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 7.8.9 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 7.8.8 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 7.8.7 +Wed, 27 May 2020 05:15:10 GMT + +_Version update only_ + +## 7.8.6 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 7.8.5 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 7.8.4 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 7.8.3 +Thu, 21 May 2020 15:41:59 GMT + +_Version update only_ + +## 7.8.2 +Tue, 19 May 2020 15:08:19 GMT + +_Version update only_ + +## 7.8.1 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 7.8.0 +Wed, 06 May 2020 08:23:45 GMT + +### Minor changes + +- For markdown output, parameter types and return types are now hyperlinked to the corresponding API item + +## 7.7.20 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 7.7.19 +Fri, 24 Apr 2020 15:09:06 GMT + +### Patches + +- Properly encode xrefs that contain '#' characters. + +## 7.7.18 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 7.7.17 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 7.7.16 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 7.7.15 +Sat, 28 Mar 2020 00:37:16 GMT + +### Patches + +- Upgrade to TSdoc 0.12.19 ## 7.7.14 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 7.7.13 Tue, 17 Mar 2020 23:55:58 GMT @@ -17,22 +2321,22 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 7.7.12 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 7.7.11 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 7.7.10 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 7.7.9 Tue, 21 Jan 2020 21:56:13 GMT -*Version update only* +_Version update only_ ## 7.7.8 Sun, 19 Jan 2020 02:26:52 GMT @@ -44,37 +2348,37 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 7.7.7 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 7.7.6 Tue, 14 Jan 2020 01:34:15 GMT -*Version update only* +_Version update only_ ## 7.7.5 Sat, 11 Jan 2020 05:18:23 GMT -*Version update only* +_Version update only_ ## 7.7.4 Thu, 09 Jan 2020 06:44:12 GMT -*Version update only* +_Version update only_ ## 7.7.3 Wed, 08 Jan 2020 00:11:30 GMT -*Version update only* +_Version update only_ ## 7.7.2 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 7.7.1 Tue, 03 Dec 2019 03:17:43 GMT -*Version update only* +_Version update only_ ## 7.7.0 Sun, 24 Nov 2019 00:54:04 GMT @@ -87,7 +2391,7 @@ Sun, 24 Nov 2019 00:54:04 GMT ## 7.6.1 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 7.6.0 Fri, 15 Nov 2019 04:50:50 GMT @@ -99,42 +2403,42 @@ Fri, 15 Nov 2019 04:50:50 GMT ## 7.5.8 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 7.5.7 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 7.5.6 Tue, 05 Nov 2019 06:49:28 GMT -*Version update only* +_Version update only_ ## 7.5.5 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 7.5.4 Fri, 25 Oct 2019 15:08:54 GMT -*Version update only* +_Version update only_ ## 7.5.3 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 7.5.2 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 7.5.1 Fri, 18 Oct 2019 15:15:00 GMT -*Version update only* +_Version update only_ ## 7.5.0 Sun, 06 Oct 2019 00:27:39 GMT @@ -146,7 +2450,7 @@ Sun, 06 Oct 2019 00:27:39 GMT ## 7.4.9 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 7.4.8 Sun, 29 Sep 2019 23:56:29 GMT @@ -165,17 +2469,17 @@ Wed, 25 Sep 2019 15:15:31 GMT ## 7.4.6 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 7.4.5 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 7.4.4 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 7.4.3 Wed, 11 Sep 2019 19:56:23 GMT @@ -219,7 +2523,7 @@ Thu, 05 Sep 2019 15:15:09 GMT ## 7.3.19 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 7.3.18 Wed, 04 Sep 2019 15:15:37 GMT @@ -231,7 +2535,7 @@ Wed, 04 Sep 2019 15:15:37 GMT ## 7.3.17 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 7.3.16 Tue, 13 Aug 2019 00:14:22 GMT @@ -243,27 +2547,27 @@ Tue, 13 Aug 2019 00:14:22 GMT ## 7.3.15 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 7.3.14 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 7.3.13 Thu, 08 Aug 2019 00:49:05 GMT -*Version update only* +_Version update only_ ## 7.3.12 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 7.3.11 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 7.3.10 Tue, 23 Jul 2019 01:13:01 GMT @@ -275,27 +2579,27 @@ Tue, 23 Jul 2019 01:13:01 GMT ## 7.3.9 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 7.3.8 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 7.3.7 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 7.3.6 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 7.3.5 Mon, 08 Jul 2019 19:12:18 GMT -*Version update only* +_Version update only_ ## 7.3.4 Sat, 29 Jun 2019 02:30:10 GMT @@ -307,7 +2611,7 @@ Sat, 29 Jun 2019 02:30:10 GMT ## 7.3.3 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 7.3.2 Tue, 11 Jun 2019 00:48:06 GMT @@ -319,7 +2623,7 @@ Tue, 11 Jun 2019 00:48:06 GMT ## 7.3.1 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 7.3.0 Wed, 05 Jun 2019 19:12:34 GMT @@ -335,7 +2639,7 @@ Wed, 05 Jun 2019 19:12:34 GMT ## 7.2.2 Tue, 04 Jun 2019 05:51:53 GMT -*Version update only* +_Version update only_ ## 7.2.1 Mon, 27 May 2019 04:13:44 GMT @@ -354,27 +2658,27 @@ Thu, 16 May 2019 22:15:20 GMT ## 7.1.7 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 7.1.6 Mon, 06 May 2019 20:46:21 GMT -*Version update only* +_Version update only_ ## 7.1.5 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 7.1.4 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 7.1.3 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 7.1.2 Mon, 29 Apr 2019 19:13:03 GMT @@ -404,12 +2708,12 @@ Tue, 16 Apr 2019 11:01:37 GMT ## 7.0.51 Fri, 12 Apr 2019 06:13:16 GMT -*Version update only* +_Version update only_ ## 7.0.50 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 7.0.49 Tue, 09 Apr 2019 05:31:01 GMT @@ -421,27 +2725,27 @@ Tue, 09 Apr 2019 05:31:01 GMT ## 7.0.48 Mon, 08 Apr 2019 19:12:52 GMT -*Version update only* +_Version update only_ ## 7.0.47 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 7.0.46 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 7.0.45 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 7.0.44 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 7.0.43 Sat, 30 Mar 2019 22:27:16 GMT @@ -453,7 +2757,7 @@ Sat, 30 Mar 2019 22:27:16 GMT ## 7.0.42 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 7.0.41 Wed, 27 Mar 2019 19:57:45 GMT @@ -465,37 +2769,37 @@ Wed, 27 Mar 2019 19:57:45 GMT ## 7.0.40 Tue, 26 Mar 2019 20:54:18 GMT -*Version update only* +_Version update only_ ## 7.0.39 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 7.0.38 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 7.0.37 Thu, 21 Mar 2019 01:15:32 GMT -*Version update only* +_Version update only_ ## 7.0.36 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 7.0.35 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 7.0.34 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 7.0.33 Wed, 13 Mar 2019 19:13:14 GMT @@ -521,47 +2825,47 @@ Mon, 11 Mar 2019 16:13:36 GMT ## 7.0.30 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 7.0.29 Mon, 04 Mar 2019 17:13:19 GMT -*Version update only* +_Version update only_ ## 7.0.28 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 7.0.27 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 7.0.26 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 7.0.25 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 7.0.24 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 7.0.23 Mon, 11 Feb 2019 08:55:57 GMT -*Version update only* +_Version update only_ ## 7.0.22 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 7.0.21 Thu, 31 Jan 2019 17:03:49 GMT @@ -574,12 +2878,12 @@ Thu, 31 Jan 2019 17:03:49 GMT ## 7.0.20 Wed, 30 Jan 2019 20:49:11 GMT -*Version update only* +_Version update only_ ## 7.0.19 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 7.0.18 Sat, 19 Jan 2019 01:17:51 GMT @@ -598,17 +2902,17 @@ Fri, 18 Jan 2019 22:04:59 GMT ## 7.0.16 Fri, 18 Jan 2019 00:52:21 GMT -*Version update only* +_Version update only_ ## 7.0.15 Thu, 17 Jan 2019 00:37:54 GMT -*Version update only* +_Version update only_ ## 7.0.14 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 7.0.13 Thu, 10 Jan 2019 01:57:52 GMT @@ -627,12 +2931,12 @@ Wed, 09 Jan 2019 22:04:17 GMT ## 7.0.11 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 7.0.10 Thu, 20 Dec 2018 17:04:08 GMT -*Version update only* +_Version update only_ ## 7.0.9 Wed, 19 Dec 2018 05:57:33 GMT @@ -651,7 +2955,7 @@ Fri, 14 Dec 2018 19:43:46 GMT ## 7.0.7 Thu, 13 Dec 2018 02:58:10 GMT -*Version update only* +_Version update only_ ## 7.0.6 Wed, 12 Dec 2018 17:04:19 GMT @@ -663,7 +2967,7 @@ Wed, 12 Dec 2018 17:04:19 GMT ## 7.0.5 Sat, 08 Dec 2018 06:35:35 GMT -*Version update only* +_Version update only_ ## 7.0.4 Fri, 07 Dec 2018 17:04:56 GMT @@ -675,17 +2979,17 @@ Fri, 07 Dec 2018 17:04:56 GMT ## 7.0.3 Wed, 05 Dec 2018 19:57:03 GMT -*Version update only* +_Version update only_ ## 7.0.2 Wed, 05 Dec 2018 17:04:18 GMT -*Version update only* +_Version update only_ ## 7.0.1 Fri, 30 Nov 2018 23:34:57 GMT -*Version update only* +_Version update only_ ## 7.0.0 Thu, 29 Nov 2018 07:02:09 GMT @@ -697,12 +3001,12 @@ Thu, 29 Nov 2018 07:02:09 GMT ## 1.5.59 Thu, 29 Nov 2018 00:35:38 GMT -*Version update only* +_Version update only_ ## 1.5.58 Wed, 28 Nov 2018 19:29:53 GMT -*Version update only* +_Version update only_ ## 1.5.57 Wed, 28 Nov 2018 02:17:11 GMT @@ -714,17 +3018,17 @@ Wed, 28 Nov 2018 02:17:11 GMT ## 1.5.56 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 1.5.55 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 1.5.54 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 1.5.53 Fri, 09 Nov 2018 17:03:15 GMT @@ -737,92 +3041,92 @@ Fri, 09 Nov 2018 17:03:15 GMT ## 1.5.52 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 1.5.51 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 1.5.50 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 1.5.49 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 1.5.48 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 1.5.47 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 1.5.46 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 1.5.45 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 1.5.44 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 1.5.43 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 1.5.42 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 1.5.41 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 1.5.40 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 1.5.39 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 1.5.38 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 1.5.37 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 1.5.36 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 1.5.35 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 1.5.34 Thu, 11 Oct 2018 21:04:51 GMT @@ -834,57 +3138,57 @@ Thu, 11 Oct 2018 21:04:51 GMT ## 1.5.33 Tue, 09 Oct 2018 06:58:01 GMT -*Version update only* +_Version update only_ ## 1.5.32 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 1.5.31 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 1.5.30 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 1.5.29 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 1.5.28 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 1.5.27 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 1.5.26 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 1.5.25 Thu, 20 Sep 2018 23:57:21 GMT -*Version update only* +_Version update only_ ## 1.5.24 Tue, 18 Sep 2018 21:04:55 GMT -*Version update only* +_Version update only_ ## 1.5.23 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 1.5.22 Thu, 06 Sep 2018 01:25:25 GMT @@ -896,37 +3200,37 @@ Thu, 06 Sep 2018 01:25:25 GMT ## 1.5.21 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 1.5.20 Mon, 03 Sep 2018 16:04:45 GMT -*Version update only* +_Version update only_ ## 1.5.19 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 1.5.18 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 1.5.17 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 1.5.16 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 1.5.15 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 1.5.14 Thu, 23 Aug 2018 18:18:53 GMT @@ -938,12 +3242,12 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 1.5.13 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 1.5.12 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 1.5.11 Tue, 21 Aug 2018 16:04:38 GMT @@ -962,22 +3266,22 @@ Mon, 20 Aug 2018 16:04:29 GMT ## 1.5.9 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 1.5.8 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 1.5.7 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 1.5.6 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 1.5.5 Wed, 01 Aug 2018 21:02:43 GMT @@ -989,22 +3293,22 @@ Wed, 01 Aug 2018 21:02:43 GMT ## 1.5.4 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 1.5.3 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 1.5.2 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 1.5.1 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 1.5.0 Tue, 17 Jul 2018 16:02:52 GMT @@ -1016,7 +3320,7 @@ Tue, 17 Jul 2018 16:02:52 GMT ## 1.4.4 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 1.4.3 Thu, 12 Jul 2018 16:03:26 GMT @@ -1028,12 +3332,12 @@ Thu, 12 Jul 2018 16:03:26 GMT ## 1.4.2 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 1.4.1 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 1.4.0 Tue, 26 Jun 2018 23:54:17 GMT @@ -1063,17 +3367,17 @@ Sat, 23 Jun 2018 02:21:20 GMT ## 1.2.8 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 1.2.7 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 1.2.6 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 1.2.5 Fri, 15 Jun 2018 16:05:34 GMT @@ -1085,12 +3389,12 @@ Fri, 15 Jun 2018 16:05:34 GMT ## 1.2.4 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 1.2.3 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 1.2.2 Thu, 24 May 2018 16:03:20 GMT @@ -1102,7 +3406,7 @@ Thu, 24 May 2018 16:03:20 GMT ## 1.2.1 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 1.2.0 Tue, 15 May 2018 00:18:10 GMT @@ -1114,37 +3418,37 @@ Tue, 15 May 2018 00:18:10 GMT ## 1.1.40 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 1.1.39 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 1.1.38 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 1.1.37 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 1.1.36 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 1.1.35 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 1.1.34 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 1.1.33 Fri, 06 Apr 2018 16:03:14 GMT @@ -1156,7 +3460,7 @@ Fri, 06 Apr 2018 16:03:14 GMT ## 1.1.32 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 1.1.31 Mon, 02 Apr 2018 16:05:24 GMT @@ -1168,17 +3472,17 @@ Mon, 02 Apr 2018 16:05:24 GMT ## 1.1.30 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 1.1.29 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 1.1.28 Sun, 25 Mar 2018 01:26:19 GMT -*Version update only* +_Version update only_ ## 1.1.27 Fri, 23 Mar 2018 00:34:53 GMT @@ -1190,7 +3494,7 @@ Fri, 23 Mar 2018 00:34:53 GMT ## 1.1.26 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 1.1.25 Wed, 21 Mar 2018 21:05:22 GMT @@ -1204,12 +3508,12 @@ Wed, 21 Mar 2018 21:05:22 GMT ## 1.1.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 1.1.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 1.1.22 Thu, 15 Mar 2018 20:00:50 GMT @@ -1223,12 +3527,12 @@ Thu, 15 Mar 2018 20:00:50 GMT ## 1.1.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 1.1.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 1.1.19 Mon, 12 Mar 2018 20:36:19 GMT @@ -1240,52 +3544,52 @@ Mon, 12 Mar 2018 20:36:19 GMT ## 1.1.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 1.1.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 1.1.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 1.1.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 1.1.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 1.1.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 1.1.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 1.1.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.1.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.1.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 1.1.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1297,37 +3601,37 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 1.1.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 1.1.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 1.1.5 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 1.1.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.1.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 1.1.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 1.1.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 1.1.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1339,12 +3643,12 @@ Wed, 10 Jan 2018 20:40:01 GMT ## 1.0.17 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 1.0.16 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 1.0.15 Fri, 05 Jan 2018 00:48:41 GMT @@ -1356,42 +3660,42 @@ Fri, 05 Jan 2018 00:48:41 GMT ## 1.0.14 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 1.0.13 Tue, 12 Dec 2017 03:33:26 GMT -*Version update only* +_Version update only_ ## 1.0.12 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 1.0.11 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 1.0.10 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 1.0.9 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 1.0.8 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 1.0.7 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 1.0.6 Thu, 02 Nov 2017 16:05:24 GMT @@ -1403,17 +3707,17 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 1.0.5 Wed, 01 Nov 2017 21:06:08 GMT -*Version update only* +_Version update only_ ## 1.0.4 Tue, 31 Oct 2017 21:04:04 GMT -*Version update only* +_Version update only_ ## 1.0.3 Tue, 31 Oct 2017 16:04:55 GMT -*Version update only* +_Version update only_ ## 1.0.2 Wed, 25 Oct 2017 20:03:59 GMT @@ -1425,7 +3729,7 @@ Wed, 25 Oct 2017 20:03:59 GMT ## 1.0.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 1.0.0 Mon, 23 Oct 2017 21:53:12 GMT diff --git a/apps/api-documenter/README.md b/apps/api-documenter/README.md index 2bfc77c040d..ad3ecfd0e25 100644 --- a/apps/api-documenter/README.md +++ b/apps/api-documenter/README.md @@ -9,4 +9,11 @@ For usage information, see the [Generating Docs](https://api-extractor.com/pages/setup/generating_docs/) article from the API Extractor documentation. -API documentation for this package: https://rushstack.io/pages/api/api-documenter/ +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/api-documenter/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/api-documenter/) + +API Documenter is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/api-documenter/bin/api-documenter b/apps/api-documenter/bin/api-documenter index 783bb806fce..aee68e80224 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/start.js'); diff --git a/apps/api-documenter/config/api-extractor.json b/apps/api-documenter/config/api-extractor.json index 3e8571b570b..aa9d8f810fd 100644 --- a/apps/api-documenter/config/api-extractor.json +++ b/apps/api-documenter/config/api-extractor.json @@ -15,6 +15,6 @@ "dtsRollup": { "enabled": true, - "untrimmedFilePath": "/dist/rollup.d.ts", + "untrimmedFilePath": "/dist/rollup.d.ts" } } 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/config/jest.config.json b/apps/api-documenter/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/api-documenter/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/api-documenter/config/jest.json b/apps/api-documenter/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/apps/api-documenter/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/apps/api-documenter/config/rig.json b/apps/api-documenter/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/api-documenter/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/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/gulpfile.js b/apps/api-documenter/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/apps/api-documenter/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/apps/api-documenter/package.json b/apps/api-documenter/package.json index 41fbec5a67a..a570c9930c0 100644 --- a/apps/api-documenter/package.json +++ b/apps/api-documenter/package.json @@ -1,15 +1,18 @@ { "name": "@microsoft/api-documenter", - "version": "7.7.14", + "version": "7.28.2", "description": "Read JSON files from api-extractor, generate documentation pages", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/api-documenter" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/api-documenter" }, "homepage": "https://api-extractor.com/", "license": "MIT", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "bin": { "api-documenter": "./bin/api-documenter" @@ -17,23 +20,19 @@ "main": "lib/index.js", "typings": "dist/rollup.d.ts", "dependencies": { - "@microsoft/api-extractor-model": "7.7.9", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/ts-command-line": "4.3.12", - "@microsoft/tsdoc": "0.12.14", - "colors": "~1.2.1", - "js-yaml": "~3.13.1", - "resolve": "1.8.1" + "@microsoft/api-extractor-model": "workspace:*", + "@microsoft/tsdoc": "~0.16.0", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "js-yaml": "~4.1.0", + "resolve": "~1.22.1" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", - "@types/js-yaml": "3.12.1", - "@types/node": "10.17.13", - "@types/resolve": "0.0.8", - "gulp": "~4.0.2", - "jest": "~23.6.0" + "@rushstack/heft": "workspace:*", + "@types/js-yaml": "4.0.9", + "@types/resolve": "1.20.2", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts index 6b466c0e1b2..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'; @@ -10,16 +11,13 @@ export class ApiDocumenterCommandLine extends CommandLineParser { public constructor() { super({ toolFilename: 'api-documenter', - toolDescription: 'Reads *.api.json files produced by api-extractor, ' - + ' and generates API documentation in various output formats.' + toolDescription: + 'Reads *.api.json files produced by api-extractor, ' + + ' and generates API documentation in various output formats.' }); this._populateActions(); } - protected onDefineParameters(): void { // override - // No parameters - } - private _populateActions(): void { this.addAction(new MarkdownAction(this)); this.addAction(new YamlAction(this)); diff --git a/apps/api-documenter/src/cli/BaseAction.ts b/apps/api-documenter/src/cli/BaseAction.ts index 02944450990..fbd3f10a14f 100644 --- a/apps/api-documenter/src/cli/BaseAction.ts +++ b/apps/api-documenter/src/cli/BaseAction.ts @@ -1,99 +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 path from 'path'; -import * as tsdoc from '@microsoft/tsdoc'; -import * as colors from 'colors'; +import * as path from 'node:path'; +import type * as tsdoc from '@microsoft/tsdoc'; import { CommandLineAction, - CommandLineStringParameter + type CommandLineStringParameter, + type ICommandLineActionOptions } from '@rushstack/ts-command-line'; import { FileSystem } from '@rushstack/node-core-library'; import { ApiModel, - ApiItem, + type ApiItem, ApiItemContainerMixin, ApiDocumentedItem, - IResolveDeclarationReferenceResult + type IResolveDeclarationReferenceResult } from '@microsoft/api-extractor-model'; +import { Colorize } from '@rushstack/terminal'; + +export interface IBuildApiModelResult { + apiModel: ApiModel; + inputFolder: string; + outputFolder: string; +} export abstract class BaseAction extends CommandLineAction { - protected inputFolder: string; - protected outputFolder: string; + private readonly _inputFolderParameter: CommandLineStringParameter; + private readonly _outputFolderParameter: CommandLineStringParameter; - private _inputFolderParameter: CommandLineStringParameter; - private _outputFolderParameter: CommandLineStringParameter; + protected constructor(options: ICommandLineActionOptions) { + super(options); - protected onDefineParameters(): void { // override this._inputFolderParameter = this.defineStringParameter({ parameterLongName: '--input-folder', parameterShortName: '-i', argumentName: 'FOLDER1', - description: `Specifies the input folder containing the *.api.json files to be processed.` - + ` If omitted, the default is "./input"` + description: + `Specifies the input folder containing the *.api.json files to be processed.` + + ` If omitted, the default is "./input"` }); this._outputFolderParameter = this.defineStringParameter({ parameterLongName: '--output-folder', parameterShortName: '-o', argumentName: 'FOLDER2', - description: `Specifies the output folder where the documentation will be written.` - + ` ANY EXISTING CONTENTS WILL BE DELETED!` - + ` If omitted, the default is "./${this.actionName}"` + description: + `Specifies the output folder where the documentation will be written.` + + ` ANY EXISTING CONTENTS WILL BE DELETED!` + + ` If omitted, the default is "./${this.actionName}"` }); } - protected buildApiModel(): ApiModel { + protected buildApiModel(): IBuildApiModelResult { const apiModel: ApiModel = new ApiModel(); - this.inputFolder = this._inputFolderParameter.value || './input'; - if (!FileSystem.exists(this.inputFolder)) { - throw new Error('The input folder does not exist: ' + this.inputFolder); + const inputFolder: string = this._inputFolderParameter.value || './input'; + if (!FileSystem.exists(inputFolder)) { + throw new Error('The input folder does not exist: ' + inputFolder); } - this.outputFolder = this._outputFolderParameter.value || `./${this.actionName}`; - FileSystem.ensureFolder(this.outputFolder); + const outputFolder: string = this._outputFolderParameter.value || `./${this.actionName}`; + FileSystem.ensureFolder(outputFolder); - for (const filename of FileSystem.readFolder(this.inputFolder)) { + for (const filename of FileSystem.readFolderItemNames(inputFolder)) { if (filename.match(/\.api\.json$/i)) { console.log(`Reading ${filename}`); - const filenamePath: string = path.join(this.inputFolder, filename); + const filenamePath: string = path.join(inputFolder, filename); apiModel.loadPackage(filenamePath); } } this._applyInheritDoc(apiModel, apiModel); - return apiModel; + return { apiModel, inputFolder, outputFolder }; } // TODO: This is a temporary workaround. The long term plan is for API Extractor's DocCommentEnhancer // to apply all @inheritDoc tags before the .api.json file is written. // See DocCommentEnhancer._applyInheritDoc() for more info. private _applyInheritDoc(apiItem: ApiItem, apiModel: ApiModel): void { - if (apiItem instanceof ApiDocumentedItem) { if (apiItem.tsdocComment) { const inheritDocTag: tsdoc.DocInheritDocTag | undefined = apiItem.tsdocComment.inheritDocTag; if (inheritDocTag && inheritDocTag.declarationReference) { // Attempt to resolve the declaration reference - const result: IResolveDeclarationReferenceResult - = apiModel.resolveDeclarationReference(inheritDocTag.declarationReference, apiItem); + const result: IResolveDeclarationReferenceResult = apiModel.resolveDeclarationReference( + inheritDocTag.declarationReference, + apiItem + ); if (result.errorMessage) { - console.log(colors.yellow(`Warning: Unresolved @inheritDoc tag for ${apiItem.displayName}: ` - + result.errorMessage)); + console.log( + Colorize.yellow( + `Warning: Unresolved @inheritDoc tag for ${apiItem.displayName}: ` + result.errorMessage + ) + ); } else { - if (result.resolvedApiItem instanceof ApiDocumentedItem - && result.resolvedApiItem.tsdocComment - && result.resolvedApiItem !== apiItem) { + if ( + result.resolvedApiItem instanceof ApiDocumentedItem && + result.resolvedApiItem.tsdocComment && + result.resolvedApiItem !== apiItem + ) { this._copyInheritedDocs(apiItem.tsdocComment, result.resolvedApiItem.tsdocComment); } } } - } } @@ -124,5 +137,4 @@ export abstract class BaseAction extends CommandLineAction { targetDocComment.inheritDocTag = undefined; } - } diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index 330a4bbde06..155b22320d1 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -1,15 +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 { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; +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 { ApiModel } from '@microsoft/api-extractor-model'; -import { FileSystem } from '@rushstack/node-core-library'; import { MarkdownDocumenter } from '../documenters/MarkdownDocumenter'; export class GenerateAction extends BaseAction { @@ -17,12 +16,13 @@ export class GenerateAction extends BaseAction { super({ actionName: 'generate', summary: 'EXPERIMENTAL', - documentation: 'EXPERIMENTAL - This action is a prototype of a new config file driven mode of operation for' - + ' API Documenter. It is not ready for general usage yet. Its design may change in the future.' + documentation: + 'EXPERIMENTAL - This action is a prototype of a new config file driven mode of operation for' + + ' API Documenter. It is not ready for general usage yet. Its design may change in the future.' }); } - protected 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); @@ -32,22 +32,29 @@ export class GenerateAction extends BaseAction { // Otherwise try the standard "config" subfolder configFilePath = path.join(process.cwd(), 'config', DocumenterConfig.FILENAME); if (!FileSystem.exists(configFilePath)) { - throw new Error(`Unable to find ${DocumenterConfig.FILENAME} in the current folder or in a "config" subfolder`); + throw new Error( + `Unable to find ${DocumenterConfig.FILENAME} in the current folder or in a "config" subfolder` + ); } } const documenterConfig: DocumenterConfig = DocumenterConfig.loadFile(configFilePath); - const apiModel: ApiModel = this.buildApiModel(); + const { apiModel, outputFolder } = this.buildApiModel(); if (documenterConfig.configFile.outputTarget === 'markdown') { - const markdownDocumenter: MarkdownDocumenter = new MarkdownDocumenter(apiModel, documenterConfig); - markdownDocumenter.generateFiles(this.outputFolder); + const markdownDocumenter: MarkdownDocumenter = new MarkdownDocumenter({ + apiModel, + documenterConfig, + outputFolder + }); + markdownDocumenter.generateFiles(); } else { - const yamlDocumenter: ExperimentalYamlDocumenter = new ExperimentalYamlDocumenter(apiModel, documenterConfig); - yamlDocumenter.generateFiles(this.outputFolder); + const yamlDocumenter: ExperimentalYamlDocumenter = new ExperimentalYamlDocumenter( + apiModel, + documenterConfig + ); + yamlDocumenter.generateFiles(outputFolder); } - - return Promise.resolve(); } } diff --git a/apps/api-documenter/src/cli/MarkdownAction.ts b/apps/api-documenter/src/cli/MarkdownAction.ts index 4df97df2c41..6dba1d3ac6d 100644 --- a/apps/api-documenter/src/cli/MarkdownAction.ts +++ b/apps/api-documenter/src/cli/MarkdownAction.ts @@ -1,26 +1,29 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; +import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; import { MarkdownDocumenter } from '../documenters/MarkdownDocumenter'; -import { ApiModel } from '@microsoft/api-extractor-model'; export class MarkdownAction extends BaseAction { public constructor(parser: ApiDocumenterCommandLine) { super({ actionName: 'markdown', summary: 'Generate documentation as Markdown files (*.md)', - documentation: 'Generates API documentation as a collection of files in' - + ' Markdown format, suitable for example for publishing on a GitHub site.' + documentation: + 'Generates API documentation as a collection of files in' + + ' Markdown format, suitable for example for publishing on a GitHub site.' }); } - protected onExecute(): Promise { // override - const apiModel: ApiModel = this.buildApiModel(); + protected override async onExecuteAsync(): Promise { + const { apiModel, outputFolder } = this.buildApiModel(); - const markdownDocumenter: MarkdownDocumenter = new MarkdownDocumenter(apiModel, undefined); - markdownDocumenter.generateFiles(this.outputFolder); - return Promise.resolve(); + const markdownDocumenter: MarkdownDocumenter = new MarkdownDocumenter({ + apiModel, + documenterConfig: undefined, + outputFolder + }); + markdownDocumenter.generateFiles(); } } diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 74cb85d98a0..7ed4161fb2d 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -1,33 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - CommandLineFlagParameter +import type { + CommandLineFlagParameter, + IRequiredCommandLineChoiceParameter } from '@rushstack/ts-command-line'; -import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; +import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; - -import { YamlDocumenter } from '../documenters/YamlDocumenter'; +import { YamlDocumenter, type YamlFormat } from '../documenters/YamlDocumenter'; import { OfficeYamlDocumenter } from '../documenters/OfficeYamlDocumenter'; -import { ApiModel } from '@microsoft/api-extractor-model'; export class YamlAction extends BaseAction { - private _officeParameter: CommandLineFlagParameter; - private _newDocfxNamespacesParameter: CommandLineFlagParameter; + private readonly _officeParameter: CommandLineFlagParameter; + private readonly _newDocfxNamespacesParameter: CommandLineFlagParameter; + private readonly _yamlFormatParameter: IRequiredCommandLineChoiceParameter; public constructor(parser: ApiDocumenterCommandLine) { super({ actionName: 'yaml', summary: 'Generate documentation as universal reference YAML files (*.yml)', - documentation: 'Generates API documentation as a collection of files conforming' - + ' to the universal reference YAML format, which is used by the docs.microsoft.com' - + ' pipeline.' + documentation: + 'Generates API documentation as a collection of files conforming' + + ' to the universal reference YAML format, which is used by the docs.microsoft.com' + + ' pipeline.' }); - } - - protected onDefineParameters(): void { // override - super.onDefineParameters(); this._officeParameter = this.defineFlagParameter({ parameterLongName: '--office', @@ -35,21 +32,34 @@ export class YamlAction extends BaseAction { }); this._newDocfxNamespacesParameter = this.defineFlagParameter({ parameterLongName: '--new-docfx-namespaces', - description: `This enables an experimental feature that will be officially released with the next major version` - + ` of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and` - + ` adds them to the table of contents. This will also affect file layout as namespaced items will be nested` - + ` under a directory for the namespace instead of just within the package.` + description: + `This enables an experimental feature that will be officially released with the next major version` + + ` of API Documenter. It requires DocFX 2.46 or newer. It enables documentation for namespaces and` + + ` adds them to the table of contents. This will also affect file layout as namespaced items will be nested` + + ` under a directory for the namespace instead of just within the package.` + }); + this._yamlFormatParameter = this.defineChoiceParameter({ + parameterLongName: '--yaml-format', + alternatives: ['udp', 'sdp'], + defaultValue: 'sdp', + description: + `Specifies the YAML format - udp or sdp. Universal Document Processor (udp) should be used if you generating` + + ` YAML files for DocFX 2.x. Schema Driven Processor (sdp) should be used with DocFX 3.x.` + + ` NOTE: This parameter is ignored if you use --office.` }); } - protected onExecute(): Promise { // override - const apiModel: ApiModel = this.buildApiModel(); + protected override async onExecuteAsync(): Promise { + const { apiModel, inputFolder, outputFolder } = this.buildApiModel(); const yamlDocumenter: YamlDocumenter = this._officeParameter.value - ? new OfficeYamlDocumenter(apiModel, this.inputFolder, this._newDocfxNamespacesParameter.value) - : new YamlDocumenter(apiModel, this._newDocfxNamespacesParameter.value); + ? new OfficeYamlDocumenter(apiModel, inputFolder, this._newDocfxNamespacesParameter.value) + : new YamlDocumenter( + apiModel, + this._newDocfxNamespacesParameter.value, + this._yamlFormatParameter.value + ); - yamlDocumenter.generateFiles(this.outputFolder); - return Promise.resolve(); + yamlDocumenter.generateFiles(outputFolder); } } diff --git a/apps/api-documenter/src/documenters/DocumenterConfig.ts b/apps/api-documenter/src/documenters/DocumenterConfig.ts index 6adff8aaf6b..3a0e32c3736 100644 --- a/apps/api-documenter/src/documenters/DocumenterConfig.ts +++ b/apps/api-documenter/src/documenters/DocumenterConfig.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 { JsonSchema, JsonFile, NewlineKind } from '@rushstack/node-core-library'; -import { IConfigFile } from './IConfigFile'; + +import type { IConfigFile } from './IConfigFile'; +import apiDocumenterSchema from '../schemas/api-documenter.schema.json'; /** * Helper for loading the api-documenter.json file format. Later when the schema is more mature, @@ -21,13 +24,12 @@ export class DocumenterConfig { public readonly newlineKind: NewlineKind; /** - * The JSON Schema for API Extractor config file (api-extractor.schema.json). + * The JSON Schema for API Documenter config file (api-documenter.schema.json). */ - public static readonly jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '..', 'schemas', 'api-documenter.schema.json')); + public static readonly jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(apiDocumenterSchema); /** - * The config file name "api-extractor.json". + * The config file name "api-documenter.json". */ public static readonly FILENAME: string = 'api-documenter.json'; diff --git a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index 0fea06fa1b6..5f8769d3720 100644 --- a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.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 { DocComment, DocInlineTag } from '@microsoft/tsdoc'; -import { ApiModel, ApiItem, ApiItemKind, ApiDocumentedItem } from '@microsoft/api-extractor-model'; +import { type DocComment, DocInlineTag } from '@microsoft/tsdoc'; +import { type ApiModel, type ApiItem, ApiItemKind, ApiDocumentedItem } from '@microsoft/api-extractor-model'; -import { IConfigTableOfContents } from './IConfigFile'; -import { IYamlTocItem, IYamlTocFile } from '../yaml/IYamlTocFile'; +import type { IConfigTableOfContents } from './IConfigFile'; +import type { IYamlTocItem, IYamlTocFile } from '../yaml/IYamlTocFile'; import { YamlDocumenter } from './YamlDocumenter'; -import { DocumenterConfig } from './DocumenterConfig'; +import type { DocumenterConfig } from './DocumenterConfig'; /** * EXPERIMENTAL - This documenter is a prototype of a new config file driven mode of operation for @@ -16,7 +16,7 @@ import { DocumenterConfig } from './DocumenterConfig'; export class ExperimentalYamlDocumenter extends YamlDocumenter { private _config: IConfigTableOfContents; private _tocPointerMap: { [key: string]: IYamlTocItem }; - private _catchAllPointer: IYamlTocItem; + private _catchAllPointer: IYamlTocItem | undefined; public constructor(apiModel: ApiModel, documenterConfig: DocumenterConfig) { super(apiModel, documenterConfig.configFile.newDocfxNamespaces); @@ -98,10 +98,9 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { // First we attempt to filter by inline tag if provided. if (apiItem instanceof ApiDocumentedItem) { - const docInlineTag: DocInlineTag | undefined = - categoryInlineTag - ? this._findInlineTagByName(categoryInlineTag, apiItem.tsdocComment) - : undefined; + const docInlineTag: DocInlineTag | undefined = categoryInlineTag + ? this._findInlineTagByName(categoryInlineTag, apiItem.tsdocComment) + : undefined; const tagContent: string | undefined = docInlineTag && docInlineTag.tagContent && docInlineTag.tagContent.trim(); @@ -134,7 +133,10 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { // This is a direct copy of a @docCategory inline tag finder in office-ui-fabric-react, // but is generic enough to be used for any inline tag - private _findInlineTagByName(tagName: string, docComment: DocComment | undefined): DocInlineTag | undefined { + private _findInlineTagByName( + tagName: string, + docComment: DocComment | undefined + ): DocInlineTag | undefined { const tagNameToCheck: string = `@${tagName}`; if (docComment instanceof DocInlineTag) { diff --git a/apps/api-documenter/src/documenters/IConfigFile.ts b/apps/api-documenter/src/documenters/IConfigFile.ts index c3116b6f119..5f617a33276 100644 --- a/apps/api-documenter/src/documenters/IConfigFile.ts +++ b/apps/api-documenter/src/documenters/IConfigFile.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 { IYamlTocFile } from '../yaml/IYamlTocFile'; +import type { IYamlTocFile } from '../yaml/IYamlTocFile'; /** * Typescript interface describing the config schema for toc.yml file format. @@ -103,4 +103,9 @@ export interface IConfigFile { /** {@inheritDoc IConfigTableOfContents} */ tableOfContents?: IConfigTableOfContents; + + /** + * Specifies whether inherited members should also be shown on an API item's page. + */ + showInheritedMembers?: boolean; } diff --git a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts index 4e636a091ee..0deb6ed6edf 100644 --- a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts +++ b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts @@ -1,32 +1,29 @@ // 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 { PackageName, FileSystem, NewlineKind } from '@rushstack/node-core-library'; import { DocSection, DocPlainText, DocLinkTag, - TSDocConfiguration, + type TSDocConfiguration, StringBuilder, DocNodeKind, DocParagraph, DocCodeSpan, DocFencedCode, StandardTags, - DocBlock, - DocComment + type DocBlock, + type DocComment, + type DocNodeContainer } from '@microsoft/tsdoc'; import { - ApiModel, - ApiItem, - ApiEnum, - ApiPackage, + type ApiModel, + type ApiItem, + type ApiEnum, + type ApiPackage, ApiItemKind, ApiReleaseTagMixin, ApiDocumentedItem, @@ -35,11 +32,21 @@ import { ApiStaticMixin, ApiPropertyItem, ApiInterface, - Excerpt, + type Excerpt, + ApiAbstractMixin, ApiParameterListMixin, ApiReturnTypeMixin, ApiDeclaredItem, - ApiNamespace + type ApiNamespace, + ExcerptTokenKind, + type IResolveDeclarationReferenceResult, + ApiTypeAlias, + type ExcerptToken, + ApiOptionalMixin, + ApiInitializerMixin, + ApiProtectedMixin, + ApiReadonlyMixin, + type IFindApiItemsResult } from '@microsoft/api-extractor-model'; import { CustomDocNodes } from '../nodes/CustomDocNodeKind'; @@ -53,12 +60,18 @@ import { Utilities } from '../utils/Utilities'; import { CustomMarkdownEmitter } from '../markdown/CustomMarkdownEmitter'; import { PluginLoader } from '../plugin/PluginLoader'; import { - IMarkdownDocumenterFeatureOnBeforeWritePageArgs, + type IMarkdownDocumenterFeatureOnBeforeWritePageArgs, MarkdownDocumenterFeatureContext } from '../plugin/MarkdownDocumenterFeature'; -import { DocumenterConfig } from './DocumenterConfig'; +import type { DocumenterConfig } from './DocumenterConfig'; import { MarkdownDocumenterAccessor } from '../plugin/MarkdownDocumenterAccessor'; +export interface IMarkdownDocumenterOptions { + apiModel: ApiModel; + documenterConfig: DocumenterConfig | undefined; + outputFolder: string; +} + /** * Renders API documentation in the Markdown file format. * For more info: https://en.wikipedia.org/wiki/Markdown @@ -68,26 +81,25 @@ export class MarkdownDocumenter { private readonly _documenterConfig: DocumenterConfig | undefined; private readonly _tsdocConfiguration: TSDocConfiguration; private readonly _markdownEmitter: CustomMarkdownEmitter; - private _outputFolder: string; + private readonly _outputFolder: string; private readonly _pluginLoader: PluginLoader; - public constructor(apiModel: ApiModel, documenterConfig: DocumenterConfig | undefined) { - this._apiModel = apiModel; - this._documenterConfig = documenterConfig; + public constructor(options: IMarkdownDocumenterOptions) { + this._apiModel = options.apiModel; + this._documenterConfig = options.documenterConfig; + this._outputFolder = options.outputFolder; this._tsdocConfiguration = CustomDocNodes.configuration; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._pluginLoader = new PluginLoader(); } - public generateFiles(outputFolder: string): void { - this._outputFolder = outputFolder; - + public generateFiles(): void { if (this._documenterConfig) { this._pluginLoader.load(this._documenterConfig, () => { return new MarkdownDocumenterFeatureContext({ apiModel: this._apiModel, - outputFolder: outputFolder, + outputFolder: this._outputFolder, documenter: new MarkdownDocumenterAccessor({ getLinkForApiItem: (apiItem: ApiItem) => { return this._getLinkFilenameForApiItem(apiItem); @@ -103,13 +115,13 @@ export class MarkdownDocumenter { this._writeApiItemPage(this._apiModel); if (this._pluginLoader.markdownDocumenterFeature) { - this._pluginLoader.markdownDocumenterFeature.onFinished({ }); + this._pluginLoader.markdownDocumenterFeature.onFinished({}); } } private _writeApiItemPage(apiItem: ApiItem): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const output: DocSection = new DocSection({ configuration: this._tsdocConfiguration }); + const output: DocSection = new DocSection({ configuration }); this._writeBreadcrumb(output, apiItem); @@ -162,29 +174,36 @@ export class MarkdownDocumenter { } if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) { - if (apiItem.releaseTag === ReleaseTag.Beta) { + if (apiItem.releaseTag === ReleaseTag.Alpha) { + this._writeAlphaWarning(output); + } else if (apiItem.releaseTag === ReleaseTag.Beta) { this._writeBetaWarning(output); } } + const decoratorBlocks: DocBlock[] = []; + if (apiItem instanceof ApiDocumentedItem) { const tsdocComment: DocComment | undefined = apiItem.tsdocComment; if (tsdocComment) { + decoratorBlocks.push( + ...tsdocComment.customBlocks.filter( + (block) => block.blockTag.tagNameWithUpperCase === StandardTags.decorator.tagNameWithUpperCase + ) + ); if (tsdocComment.deprecatedBlock) { output.appendNode( - new DocNoteBox({ configuration: this._tsdocConfiguration }, - [ - new DocParagraph({ configuration: this._tsdocConfiguration }, [ - new DocPlainText({ - configuration: this._tsdocConfiguration, - text: 'Warning: This API is now obsolete. ' - }) - ]), - ...tsdocComment.deprecatedBlock.content.nodes - ] - ) + new DocNoteBox({ configuration }, [ + new DocParagraph({ configuration }, [ + new DocPlainText({ + configuration, + text: 'Warning: This API is now obsolete. ' + }) + ]), + ...tsdocComment.deprecatedBlock.content.nodes + ]) ); } @@ -196,15 +215,34 @@ export class MarkdownDocumenter { if (apiItem.excerpt.text.length > 0) { output.appendNode( new DocParagraph({ configuration }, [ - new DocEmphasisSpan({ configuration, bold: true}, [ + new DocEmphasisSpan({ configuration, bold: true }, [ new DocPlainText({ configuration, text: 'Signature:' }) ]) ]) ); output.appendNode( - new DocFencedCode({ configuration, code: apiItem.getExcerptWithModifiers(), language: 'typescript' }) + new DocFencedCode({ + configuration, + code: apiItem.getExcerptWithModifiers(), + language: 'typescript' + }) ); } + + this._writeHeritageTypes(output, apiItem); + } + + if (decoratorBlocks.length > 0) { + output.appendNode( + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'Decorators:' }) + ]) + ]) + ); + for (const decoratorBlock of decoratorBlocks) { + output.appendNodes(decoratorBlock.content.nodes); + } } let appendRemarks: boolean = true; @@ -257,13 +295,15 @@ export class MarkdownDocumenter { } if (appendRemarks) { - this._writeRemarksSection(output, apiItem); + this._writeRemarksSection(output, apiItem); } const filename: string = path.join(this._outputFolder, this._getFilenameForApiItem(apiItem)); const stringBuilder: StringBuilder = new StringBuilder(); - stringBuilder.append('\n\n'); + stringBuilder.append( + '\n\n' + ); this._markdownEmitter.emit(stringBuilder, output, { contextApiItem: apiItem, @@ -290,26 +330,112 @@ export class MarkdownDocumenter { }); } + private _writeHeritageTypes(output: DocSection, apiItem: ApiDeclaredItem): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + if (apiItem instanceof ApiClass) { + if (apiItem.extendsType) { + const extendsParagraph: DocParagraph = new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'Extends: ' }) + ]) + ]); + this._appendExcerptWithHyperlinks(extendsParagraph, apiItem.extendsType.excerpt); + output.appendNode(extendsParagraph); + } + if (apiItem.implementsTypes.length > 0) { + const implementsParagraph: DocParagraph = new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'Implements: ' }) + ]) + ]); + let needsComma: boolean = false; + for (const implementsType of apiItem.implementsTypes) { + if (needsComma) { + implementsParagraph.appendNode(new DocPlainText({ configuration, text: ', ' })); + } + this._appendExcerptWithHyperlinks(implementsParagraph, implementsType.excerpt); + needsComma = true; + } + output.appendNode(implementsParagraph); + } + } + + if (apiItem instanceof ApiInterface) { + if (apiItem.extendsTypes.length > 0) { + const extendsParagraph: DocParagraph = new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'Extends: ' }) + ]) + ]); + let needsComma: boolean = false; + for (const extendsType of apiItem.extendsTypes) { + if (needsComma) { + extendsParagraph.appendNode(new DocPlainText({ configuration, text: ', ' })); + } + this._appendExcerptWithHyperlinks(extendsParagraph, extendsType.excerpt); + needsComma = true; + } + output.appendNode(extendsParagraph); + } + } + + if (apiItem instanceof ApiTypeAlias) { + const refs: ExcerptToken[] = apiItem.excerptTokens.filter( + (token) => + token.kind === ExcerptTokenKind.Reference && + token.canonicalReference && + this._apiModel.resolveDeclarationReference(token.canonicalReference, undefined).resolvedApiItem + ); + if (refs.length > 0) { + const referencesParagraph: DocParagraph = new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'References: ' }) + ]) + ]); + let needsComma: boolean = false; + const visited: Set = new Set(); + for (const ref of refs) { + if (visited.has(ref.text)) { + continue; + } + visited.add(ref.text); + + if (needsComma) { + referencesParagraph.appendNode(new DocPlainText({ configuration, text: ', ' })); + } + + this._appendExcerptTokenWithHyperlinks(referencesParagraph, ref); + needsComma = true; + } + output.appendNode(referencesParagraph); + } + } + } + private _writeRemarksSection(output: DocSection, apiItem: ApiItem): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + if (apiItem instanceof ApiDocumentedItem) { const tsdocComment: DocComment | undefined = apiItem.tsdocComment; if (tsdocComment) { // Write the @remarks block if (tsdocComment.remarksBlock) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Remarks' })); + output.appendNode(new DocHeading({ configuration, title: 'Remarks' })); this._appendSection(output, tsdocComment.remarksBlock.content); } // Write the @example blocks - const exampleBlocks: DocBlock[] = tsdocComment.customBlocks.filter(x => x.blockTag.tagNameWithUpperCase - === StandardTags.example.tagNameWithUpperCase); + const exampleBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.example.tagNameWithUpperCase + ); let exampleNumber: number = 1; for (const exampleBlock of exampleBlocks) { const heading: string = exampleBlocks.length > 1 ? `Example ${exampleNumber}` : 'Example'; - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: heading })); + output.appendNode(new DocHeading({ configuration, title: heading })); this._appendSection(output, exampleBlock.content); @@ -320,17 +446,20 @@ export class MarkdownDocumenter { } private _writeThrowsSection(output: DocSection, apiItem: ApiItem): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + if (apiItem instanceof ApiDocumentedItem) { const tsdocComment: DocComment | undefined = apiItem.tsdocComment; if (tsdocComment) { // Write the @throws blocks - const throwsBlocks: DocBlock[] = tsdocComment.customBlocks.filter(x => x.blockTag.tagNameWithUpperCase - === StandardTags.throws.tagNameWithUpperCase); + const throwsBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.throws.tagNameWithUpperCase + ); if (throwsBlocks.length > 0) { const heading: string = 'Exceptions'; - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: heading })); + output.appendNode(new DocHeading({ configuration, title: heading })); for (const throwsBlock of throwsBlocks) { this._appendSection(output, throwsBlock.content); @@ -346,12 +475,12 @@ export class MarkdownDocumenter { private _writeModelTable(output: DocSection, apiModel: ApiModel): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const packagesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Package', 'Description' ] + const packagesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Package', 'Description'] }); for (const apiMember of apiModel.members) { - const row: DocTableRow = new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), this._createDescriptionCell(apiMember) @@ -366,7 +495,7 @@ export class MarkdownDocumenter { } if (packagesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Packages' })); + output.appendNode(new DocHeading({ configuration, title: 'Packages' })); output.appendNode(packagesTable); } } @@ -377,40 +506,52 @@ export class MarkdownDocumenter { private _writePackageOrNamespaceTables(output: DocSection, apiContainer: ApiPackage | ApiNamespace): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const classesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Class', 'Description' ] + const abstractClassesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Abstract Class', 'Description'] }); - const enumerationsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Enumeration', 'Description' ] + const classesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Class', 'Description'] }); - const functionsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Function', 'Description' ] + const enumerationsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Enumeration', 'Description'] }); - const interfacesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Interface', 'Description' ] + const functionsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Function', 'Description'] }); - const namespacesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Namespace', 'Description' ] + const interfacesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Interface', 'Description'] }); - const variablesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Variable', 'Description' ] + const namespacesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Namespace', 'Description'] }); - const typeAliasesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Type Alias', 'Description' ] + const variablesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Variable', 'Description'] }); - const apiMembers: ReadonlyArray = apiContainer.kind === ApiItemKind.Package ? - (apiContainer as ApiPackage).entryPoints[0].members - : (apiContainer as ApiNamespace).members; + const typeAliasesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Type Alias', 'Description'] + }); - for (const apiMember of apiMembers) { + const apiMembers: ReadonlyArray = + apiContainer.kind === ApiItemKind.Package + ? (apiContainer as ApiPackage).entryPoints[0].members + : (apiContainer as ApiNamespace).members; + for (const apiMember of apiMembers) { const row: DocTableRow = new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), this._createDescriptionCell(apiMember) @@ -418,7 +559,11 @@ export class MarkdownDocumenter { switch (apiMember.kind) { case ApiItemKind.Class: - classesTable.addRow(row); + if (ApiAbstractMixin.isBaseClassOf(apiMember) && apiMember.isAbstract) { + abstractClassesTable.addRow(row); + } else { + classesTable.addRow(row); + } this._writeApiItemPage(apiMember); break; @@ -455,36 +600,41 @@ export class MarkdownDocumenter { } if (classesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Classes' })); + output.appendNode(new DocHeading({ configuration, title: 'Classes' })); output.appendNode(classesTable); } + if (abstractClassesTable.rows.length > 0) { + output.appendNode(new DocHeading({ configuration, title: 'Abstract Classes' })); + output.appendNode(abstractClassesTable); + } + if (enumerationsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Enumerations' })); + output.appendNode(new DocHeading({ configuration, title: 'Enumerations' })); output.appendNode(enumerationsTable); } if (functionsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Functions' })); + output.appendNode(new DocHeading({ configuration, title: 'Functions' })); output.appendNode(functionsTable); } if (interfacesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Interfaces' })); + output.appendNode(new DocHeading({ configuration, title: 'Interfaces' })); output.appendNode(interfacesTable); } if (namespacesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Namespaces' })); + output.appendNode(new DocHeading({ configuration, title: 'Namespaces' })); output.appendNode(namespacesTable); } if (variablesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Variables' })); + output.appendNode(new DocHeading({ configuration, title: 'Variables' })); output.appendNode(variablesTable); } if (typeAliasesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Type Aliases' })); + output.appendNode(new DocHeading({ configuration, title: 'Type Aliases' })); output.appendNode(typeAliasesTable); } } @@ -495,31 +645,36 @@ export class MarkdownDocumenter { private _writeClassTables(output: DocSection, apiClass: ApiClass): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const eventsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Property', 'Modifiers', 'Type', 'Description' ] + const eventsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Property', 'Modifiers', 'Type', 'Description'] }); - const constructorsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Constructor', 'Modifiers', 'Description' ] + const constructorsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Constructor', 'Modifiers', 'Description'] }); - const propertiesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Property', 'Modifiers', 'Type', 'Description' ] + const propertiesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Property', 'Modifiers', 'Type', 'Description'] }); - const methodsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Method', 'Modifiers', 'Description' ] + const methodsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Method', 'Modifiers', 'Description'] }); - for (const apiMember of apiClass.members) { - + const apiMembers: readonly ApiItem[] = this._getMembersAndWriteIncompleteWarning(apiClass, output); + for (const apiMember of apiMembers) { + const isInherited: boolean = apiMember.parent !== apiClass; switch (apiMember.kind) { case ApiItemKind.Constructor: { constructorsTable.addRow( new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), this._createModifiersCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); @@ -531,7 +686,7 @@ export class MarkdownDocumenter { new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), this._createModifiersCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); @@ -539,14 +694,13 @@ export class MarkdownDocumenter { break; } case ApiItemKind.Property: { - if ((apiMember as ApiPropertyItem).isEventProperty) { eventsTable.addRow( new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), this._createModifiersCell(apiMember), this._createPropertyTypeCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); } else { @@ -555,7 +709,7 @@ export class MarkdownDocumenter { this._createTitleCell(apiMember), this._createModifiersCell(apiMember), this._createPropertyTypeCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); } @@ -563,27 +717,26 @@ export class MarkdownDocumenter { this._writeApiItemPage(apiMember); break; } - } } if (eventsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Events' })); + output.appendNode(new DocHeading({ configuration, title: 'Events' })); output.appendNode(eventsTable); } if (constructorsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Constructors' })); + output.appendNode(new DocHeading({ configuration, title: 'Constructors' })); output.appendNode(constructorsTable); } if (propertiesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Properties' })); + output.appendNode(new DocHeading({ configuration, title: 'Properties' })); output.appendNode(propertiesTable); } if (methodsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Methods' })); + output.appendNode(new DocHeading({ configuration, title: 'Methods' })); output.appendNode(methodsTable); } } @@ -594,33 +747,27 @@ export class MarkdownDocumenter { private _writeEnumTables(output: DocSection, apiEnum: ApiEnum): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const enumMembersTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Member', 'Value', 'Description' ] + const enumMembersTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Member', 'Value', 'Description'] }); for (const apiEnumMember of apiEnum.members) { enumMembersTable.addRow( new DocTableRow({ configuration }, [ - new DocTableCell({ configuration }, [ new DocParagraph({ configuration }, [ new DocPlainText({ configuration, text: Utilities.getConciseSignature(apiEnumMember) }) ]) ]), - - new DocTableCell({ configuration }, [ - new DocParagraph({ configuration }, [ - new DocCodeSpan({ configuration, code: apiEnumMember.initializerExcerpt.text }) - ]) - ]), - + this._createInitializerCell(apiEnumMember), this._createDescriptionCell(apiEnumMember) ]) ); } if (enumMembersTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Enumeration Members' })); + output.appendNode(new DocHeading({ configuration, title: 'Enumeration Members' })); output.appendNode(enumMembersTable); } } @@ -628,30 +775,34 @@ export class MarkdownDocumenter { /** * GENERATE PAGE: INTERFACE */ - private _writeInterfaceTables(output: DocSection, apiClass: ApiInterface): void { + private _writeInterfaceTables(output: DocSection, apiInterface: ApiInterface): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const eventsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Property', 'Type', 'Description' ] + const eventsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Property', 'Modifiers', 'Type', 'Description'] }); - const propertiesTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Property', 'Type', 'Description' ] + const propertiesTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Property', 'Modifiers', 'Type', 'Description'] }); - const methodsTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Method', 'Description' ] + const methodsTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Method', 'Description'] }); - for (const apiMember of apiClass.members) { - + const apiMembers: readonly ApiItem[] = this._getMembersAndWriteIncompleteWarning(apiInterface, output); + for (const apiMember of apiMembers) { + const isInherited: boolean = apiMember.parent !== apiInterface; switch (apiMember.kind) { case ApiItemKind.ConstructSignature: case ApiItemKind.MethodSignature: { methodsTable.addRow( new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); @@ -659,21 +810,22 @@ export class MarkdownDocumenter { break; } case ApiItemKind.PropertySignature: { - if ((apiMember as ApiPropertyItem).isEventProperty) { eventsTable.addRow( new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), + this._createModifiersCell(apiMember), this._createPropertyTypeCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); } else { propertiesTable.addRow( new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), + this._createModifiersCell(apiMember), this._createPropertyTypeCell(apiMember), - this._createDescriptionCell(apiMember) + this._createDescriptionCell(apiMember, isInherited) ]) ); } @@ -681,22 +833,21 @@ export class MarkdownDocumenter { this._writeApiItemPage(apiMember); break; } - } } if (eventsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Events' })); + output.appendNode(new DocHeading({ configuration, title: 'Events' })); output.appendNode(eventsTable); } if (propertiesTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Properties' })); + output.appendNode(new DocHeading({ configuration, title: 'Properties' })); output.appendNode(propertiesTable); } if (methodsTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Methods' })); + output.appendNode(new DocHeading({ configuration, title: 'Methods' })); output.appendNode(methodsTable); } } @@ -707,35 +858,43 @@ export class MarkdownDocumenter { private _writeParameterTables(output: DocSection, apiParameterListMixin: ApiParameterListMixin): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const parametersTable: DocTable = new DocTable({ configuration, - headerTitles: [ 'Parameter', 'Type', 'Description' ] + const parametersTable: DocTable = new DocTable({ + configuration, + headerTitles: ['Parameter', 'Type', 'Description'] }); - for (const apiParameter of apiParameterListMixin.parameters) { - const parameterDescription: DocSection = new DocSection({ configuration } ); + const parameterDescription: DocSection = new DocSection({ configuration }); + + if (apiParameter.isOptional) { + parameterDescription.appendNodesInParagraph([ + new DocEmphasisSpan({ configuration, italic: true }, [ + new DocPlainText({ configuration, text: '(Optional)' }) + ]), + new DocPlainText({ configuration, text: ' ' }) + ]); + } + if (apiParameter.tsdocParamBlock) { - this._appendSection(parameterDescription, apiParameter.tsdocParamBlock.content); + this._appendAndMergeSection(parameterDescription, apiParameter.tsdocParamBlock.content); } parametersTable.addRow( new DocTableRow({ configuration }, [ - new DocTableCell({configuration}, [ + new DocTableCell({ configuration }, [ new DocParagraph({ configuration }, [ new DocPlainText({ configuration, text: apiParameter.name }) ]) ]), - new DocTableCell({configuration}, [ - new DocParagraph({ configuration }, [ - new DocCodeSpan({ configuration, code: apiParameter.parameterTypeExcerpt.text }) - ]) + new DocTableCell({ configuration }, [ + this._createParagraphForTypeExcerpt(apiParameter.parameterTypeExcerpt) ]), - new DocTableCell({configuration}, parameterDescription.nodes) + new DocTableCell({ configuration }, parameterDescription.nodes) ]) ); } if (parametersTable.rows.length > 0) { - output.appendNode(new DocHeading({ configuration: this._tsdocConfiguration, title: 'Parameters' })); + output.appendNode(new DocHeading({ configuration, title: 'Parameters' })); output.appendNode(parametersTable); } @@ -743,17 +902,13 @@ export class MarkdownDocumenter { const returnTypeExcerpt: Excerpt = apiParameterListMixin.returnTypeExcerpt; output.appendNode( new DocParagraph({ configuration }, [ - new DocEmphasisSpan({ configuration, bold: true}, [ + new DocEmphasisSpan({ configuration, bold: true }, [ new DocPlainText({ configuration, text: 'Returns:' }) ]) ]) ); - output.appendNode( - new DocParagraph({ configuration }, [ - new DocCodeSpan({ configuration, code: returnTypeExcerpt.text.trim() || '(not declared)' }) - ]) - ); + output.appendNode(this._createParagraphForTypeExcerpt(returnTypeExcerpt)); if (apiParameterListMixin instanceof ApiDocumentedItem) { if (apiParameterListMixin.tsdocComment && apiParameterListMixin.tsdocComment.returnsBlock) { @@ -763,15 +918,72 @@ export class MarkdownDocumenter { } } + private _createParagraphForTypeExcerpt(excerpt: Excerpt): DocParagraph { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + const paragraph: DocParagraph = new DocParagraph({ configuration }); + + if (!excerpt.text.trim()) { + paragraph.appendNode(new DocPlainText({ configuration, text: '(not declared)' })); + } else { + this._appendExcerptWithHyperlinks(paragraph, excerpt); + } + + return paragraph; + } + + private _appendExcerptWithHyperlinks(docNodeContainer: DocNodeContainer, excerpt: Excerpt): void { + for (const token of excerpt.spannedTokens) { + this._appendExcerptTokenWithHyperlinks(docNodeContainer, token); + } + } + + private _appendExcerptTokenWithHyperlinks(docNodeContainer: DocNodeContainer, token: ExcerptToken): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + // Markdown doesn't provide a standardized syntax for hyperlinks inside code spans, so we will render + // the type expression as DocPlainText. Instead of creating multiple DocParagraphs, we can simply + // discard any newlines and let the renderer do normal word-wrapping. + const unwrappedTokenText: string = token.text.replace(/[\r\n]+/g, ' '); + + // If it's hyperlinkable, then append a DocLinkTag + if (token.kind === ExcerptTokenKind.Reference && token.canonicalReference) { + const apiItemResult: IResolveDeclarationReferenceResult = this._apiModel.resolveDeclarationReference( + token.canonicalReference, + undefined + ); + + if (apiItemResult.resolvedApiItem) { + docNodeContainer.appendNode( + new DocLinkTag({ + configuration, + tagName: '@link', + linkText: unwrappedTokenText, + urlDestination: this._getLinkFilenameForApiItem(apiItemResult.resolvedApiItem) + }) + ); + return; + } + } + + // Otherwise append non-hyperlinked text + docNodeContainer.appendNode(new DocPlainText({ configuration, text: unwrappedTokenText })); + } + private _createTitleCell(apiItem: ApiItem): DocTableCell { const configuration: TSDocConfiguration = this._tsdocConfiguration; + let linkText: string = Utilities.getConciseSignature(apiItem); + if (ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional) { + linkText += '?'; + } + return new DocTableCell({ configuration }, [ new DocParagraph({ configuration }, [ new DocLinkTag({ configuration, tagName: '@link', - linkText: Utilities.getConciseSignature(apiItem), + linkText: linkText, urlDestination: this._getLinkFilenameForApiItem(apiItem) }) ]) @@ -785,28 +997,55 @@ export class MarkdownDocumenter { * We mostly assume that the input is an ApiDocumentedItem, but it's easier to perform this as a runtime * check than to have each caller perform a type cast. */ - private _createDescriptionCell(apiItem: ApiItem): DocTableCell { + private _createDescriptionCell(apiItem: ApiItem, isInherited: boolean = false): DocTableCell { const configuration: TSDocConfiguration = this._tsdocConfiguration; const section: DocSection = new DocSection({ configuration }); if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) { - if (apiItem.releaseTag === ReleaseTag.Beta) { + if (apiItem.releaseTag === ReleaseTag.Alpha || apiItem.releaseTag === ReleaseTag.Beta) { section.appendNodesInParagraph([ new DocEmphasisSpan({ configuration, bold: true, italic: true }, [ - new DocPlainText({ configuration, text: '(BETA)' }) + new DocPlainText({ + configuration, + text: `(${apiItem.releaseTag === ReleaseTag.Alpha ? 'ALPHA' : 'BETA'})` + }) ]), new DocPlainText({ configuration, text: ' ' }) ]); } } + if (ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional) { + section.appendNodesInParagraph([ + new DocEmphasisSpan({ configuration, italic: true }, [ + new DocPlainText({ configuration, text: '(Optional)' }) + ]), + new DocPlainText({ configuration, text: ' ' }) + ]); + } + if (apiItem instanceof ApiDocumentedItem) { if (apiItem.tsdocComment !== undefined) { this._appendAndMergeSection(section, apiItem.tsdocComment.summarySection); } } + if (isInherited && apiItem.parent) { + section.appendNode( + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: '(Inherited from ' }), + new DocLinkTag({ + configuration, + tagName: '@link', + linkText: apiItem.parent.displayName, + urlDestination: this._getLinkFilenameForApiItem(apiItem.parent) + }), + new DocPlainText({ configuration, text: ')' }) + ]) + ); + } + return new DocTableCell({ configuration }, section.nodes); } @@ -815,9 +1054,39 @@ export class MarkdownDocumenter { const section: DocSection = new DocSection({ configuration }); + // Output modifiers in syntactically correct order: first access modifier (here: `protected`), then + // `static` or `abstract` (no member can be both, so the order between the two of them does not matter), + // last `readonly`. If `override` was supported, it would go directly before `readonly`. + + if (ApiProtectedMixin.isBaseClassOf(apiItem)) { + if (apiItem.isProtected) { + section.appendNode( + new DocParagraph({ configuration }, [new DocCodeSpan({ configuration, code: 'protected' })]) + ); + } + } + if (ApiStaticMixin.isBaseClassOf(apiItem)) { if (apiItem.isStatic) { - section.appendNodeInParagraph(new DocCodeSpan({ configuration, code: 'static' })); + section.appendNode( + new DocParagraph({ configuration }, [new DocCodeSpan({ configuration, code: 'static' })]) + ); + } + } + + if (ApiAbstractMixin.isBaseClassOf(apiItem)) { + if (apiItem.isAbstract) { + section.appendNode( + new DocParagraph({ configuration }, [new DocCodeSpan({ configuration, code: 'abstract' })]) + ); + } + } + + if (ApiReadonlyMixin.isBaseClassOf(apiItem)) { + if (apiItem.isReadonly) { + section.appendNode( + new DocParagraph({ configuration }, [new DocCodeSpan({ configuration, code: 'readonly' })]) + ); } } @@ -830,19 +1099,39 @@ export class MarkdownDocumenter { const section: DocSection = new DocSection({ configuration }); if (apiItem instanceof ApiPropertyItem) { - section.appendNodeInParagraph(new DocCodeSpan({ configuration, code: apiItem.propertyTypeExcerpt.text })); + section.appendNode(this._createParagraphForTypeExcerpt(apiItem.propertyTypeExcerpt)); + } + + return new DocTableCell({ configuration }, section.nodes); + } + + private _createInitializerCell(apiItem: ApiItem): DocTableCell { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + const section: DocSection = new DocSection({ configuration }); + + if (ApiInitializerMixin.isBaseClassOf(apiItem)) { + if (apiItem.initializerExcerpt) { + section.appendNodeInParagraph( + new DocCodeSpan({ configuration, code: apiItem.initializerExcerpt.text }) + ); + } } return new DocTableCell({ configuration }, section.nodes); } private _writeBreadcrumb(output: DocSection, apiItem: ApiItem): void { - output.appendNodeInParagraph(new DocLinkTag({ - configuration: this._tsdocConfiguration, - tagName: '@link', - linkText: 'Home', - urlDestination: this._getLinkFilenameForApiItem(this._apiModel) - })); + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + output.appendNodeInParagraph( + new DocLinkTag({ + configuration, + tagName: '@link', + linkText: 'Home', + urlDestination: this._getLinkFilenameForApiItem(this._apiModel) + }) + ); for (const hierarchyItem of apiItem.getHierarchy()) { switch (hierarchyItem.kind) { @@ -855,11 +1144,11 @@ export class MarkdownDocumenter { default: output.appendNodesInParagraph([ new DocPlainText({ - configuration: this._tsdocConfiguration, + configuration, text: ' > ' }), new DocLinkTag({ - configuration: this._tsdocConfiguration, + configuration, tagName: '@link', linkText: hierarchyItem.displayName, urlDestination: this._getLinkFilenameForApiItem(hierarchyItem) @@ -869,15 +1158,26 @@ export class MarkdownDocumenter { } } + private _writeAlphaWarning(output: DocSection): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + const betaWarning: string = + 'This API is provided as an alpha preview for developers and may change' + + ' based on feedback that we receive. Do not use this API in a production environment.'; + output.appendNode( + new DocNoteBox({ configuration }, [ + new DocParagraph({ configuration }, [new DocPlainText({ configuration, text: betaWarning })]) + ]) + ); + } + private _writeBetaWarning(output: DocSection): void { const configuration: TSDocConfiguration = this._tsdocConfiguration; - const betaWarning: string = 'This API is provided as a preview for developers and may change' - + ' based on feedback that we receive. Do not use this API in a production environment.'; + const betaWarning: string = + 'This API is provided as a beta preview for developers and may change' + + ' based on feedback that we receive. Do not use this API in a production environment.'; output.appendNode( new DocNoteBox({ configuration }, [ - new DocParagraph({ configuration }, [ - new DocPlainText({ configuration, text: betaWarning }) - ]) + new DocParagraph({ configuration }, [new DocPlainText({ configuration, text: betaWarning })]) ]) ); } @@ -904,6 +1204,40 @@ export class MarkdownDocumenter { } } + private _getMembersAndWriteIncompleteWarning( + apiClassOrInterface: ApiClass | ApiInterface, + output: DocSection + ): readonly ApiItem[] { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + const showInheritedMembers: boolean = !!this._documenterConfig?.configFile.showInheritedMembers; + if (!showInheritedMembers) { + return apiClassOrInterface.members; + } + + const result: IFindApiItemsResult = apiClassOrInterface.findMembersWithInheritance(); + + // If the result is potentially incomplete, write a short warning communicating this. + if (result.maybeIncompleteResult) { + output.appendNode( + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, italic: true }, [ + new DocPlainText({ + configuration, + text: '(Some inherited members may not be shown because they are not represented in the documentation.)' + }) + ]) + ]) + ); + } + + // Log the messages for diagnostic purposes. + for (const message of result.messages) { + console.log(`Diagnostic message for findMembersWithInheritance: ${message.text}`); + } + + return result.items; + } + private _getFilenameForApiItem(apiItem: ApiItem): string { if (apiItem.kind === ApiItemKind.Model) { return 'index.md'; @@ -924,6 +1258,7 @@ export class MarkdownDocumenter { switch (hierarchyItem.kind) { case ApiItemKind.Model: case ApiItemKind.EntryPoint: + case ApiItemKind.EnumMember: break; case ApiItemKind.Package: baseName = Utilities.getSafeFilenameForName(PackageName.getUnscopedName(hierarchyItem.displayName)); diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index b494e3d8ba5..b8b178a9ce1 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.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 colors from 'colors'; -import * as path from 'path'; +import * as path from 'node:path'; + import yaml = require('js-yaml'); -import { ApiModel } from '@microsoft/api-extractor-model'; -import { Text, FileSystem } from '@rushstack/node-core-library'; +import type { ApiModel } from '@microsoft/api-extractor-model'; +import { FileSystem } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; -import { IYamlTocItem } from '../yaml/IYamlTocFile'; -import { IYamlItem } from '../yaml/IYamlApiFile'; +import type { IYamlTocItem } from '../yaml/IYamlTocFile'; +import type { IYamlItem } from '../yaml/IYamlApiFile'; import { YamlDocumenter } from './YamlDocumenter'; interface ISnippetsFile { @@ -32,11 +33,12 @@ export class OfficeYamlDocumenter extends YamlDocumenter { // Hash set of API Set URLs based on product. private _apiSetUrls: Record = { - 'Excel': '/office/dev/add-ins/reference/requirement-sets/excel-api-requirement-sets', - 'OneNote': '/office/dev/add-ins/reference/requirement-sets/onenote-api-requirement-sets', - 'Visio': '/office/dev/add-ins/reference/overview/visio-javascript-reference-overview', - 'Outlook': '/office/dev/add-ins/reference/requirement-sets/outlook-api-requirement-sets', - 'Word': '/office/dev/add-ins/reference/requirement-sets/word-api-requirement-sets' + Excel: '/javascript/api/requirement-sets/excel/excel-api-requirement-sets', + OneNote: '/javascript/api/requirement-sets/onenote/onenote-api-requirement-sets', + Outlook: '/javascript/api/requirement-sets/outlook/outlook-api-requirement-sets', + PowerPoint: '/javascript/api/requirement-sets/powerpoint/powerpoint-api-requirement-sets', + Visio: '/office/dev/add-ins/reference/overview/visio-javascript-reference-overview', + Word: '/javascript/api/requirement-sets/word/word-api-requirement-sets' }; public constructor(apiModel: ApiModel, inputFolder: string, newDocfxNamespaces?: boolean) { @@ -47,8 +49,8 @@ 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 */ @@ -58,16 +60,16 @@ export class OfficeYamlDocumenter extends YamlDocumenter { // After we generate everything, check for any unused snippets console.log(); for (const apiName of Object.keys(this._snippets)) { - console.error(colors.yellow('Warning: Unused snippet ' + apiName)); + console.error(Colorize.yellow('Warning: Unused snippet ' + apiName)); } } /** @override */ - protected onGetTocRoot(): IYamlTocItem { // override + protected onGetTocRoot(): IYamlTocItem { return { name: 'API reference', - href: '~/docs-ref-autogen/overview/office.md', - items: [ ] + href: 'overview.md', + items: [] }; } @@ -76,18 +78,9 @@ export class OfficeYamlDocumenter extends YamlDocumenter { const nameWithoutPackage: string = yamlItem.uid.replace(/^[^.]+\!/, ''); if (yamlItem.summary) { yamlItem.summary = this._fixupApiSet(yamlItem.summary, yamlItem.uid); - yamlItem.summary = this._fixBoldAndItalics(yamlItem.summary); } if (yamlItem.remarks) { yamlItem.remarks = this._fixupApiSet(yamlItem.remarks, yamlItem.uid); - yamlItem.remarks = this._fixBoldAndItalics(yamlItem.remarks); - } - if (yamlItem.syntax && yamlItem.syntax.parameters) { - yamlItem.syntax.parameters.forEach(part => { - if (part.description) { - part.description = this._fixBoldAndItalics(part.description); - } - }); } const snippets: string[] | undefined = this._snippetsAll[nameWithoutPackage]; @@ -117,34 +110,22 @@ export class OfficeYamlDocumenter extends YamlDocumenter { return markup.replace(/\\\[(API set:[^\]]+)\\\]/, '\\[ [$1](' + this._getApiSetUrl(uid) + ') \\]'); } - // Gets the link to the API set based on product context. Seeks a case-insensitve match in the hash set. + // Gets the link to the API set based on product context. Seeks a case-insensitive match in the hash set. private _getApiSetUrl(uid: string): string { for (const key of Object.keys(this._apiSetUrls)) { const regexp: RegExp = new RegExp(key, 'i'); if (regexp.test(uid)) { - return this._apiSetUrls[key]; + return this._apiSetUrls[key]; } } return this._apiSetUrlDefault; // match not found. } - private _fixBoldAndItalics(text: string): string { - return Text.replaceAll(text, '\\*', '*'); - } - private _generateExampleSnippetText(snippets: string[]): string { const text: string[] = ['\n\n#### Examples\n']; for (const snippet of snippets) { - if (snippet.search(/await/) === -1) { - text.push('```javascript'); - - } else { - text.push('```typescript'); - } - - text.push(snippet); - text.push('```'); + text.push(`\`\`\`TypeScript\n${snippet}\n\`\`\``); } return text.join('\n'); } -} \ No newline at end of file +} diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 6d672bcbd00..3ca47d82954 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, @@ -12,39 +13,46 @@ import { NewlineKind, InternalError } from '@rushstack/node-core-library'; -import { StringBuilder, DocSection, DocComment } from '@microsoft/tsdoc'; import { - ApiModel, - ApiItem, + StringBuilder, + type DocSection, + type DocComment, + type DocBlock, + StandardTags +} from '@microsoft/tsdoc'; +import { + type ApiModel, + type ApiItem, ApiItemKind, ApiDocumentedItem, ApiReleaseTagMixin, ReleaseTag, - ApiPropertyItem, + type ApiPropertyItem, ApiItemContainerMixin, - ApiPackage, - ApiEnumMember, + type ApiPackage, + type ApiEnumMember, ApiClass, ApiInterface, - ApiMethod, - ApiMethodSignature, - ApiConstructor, - ApiFunction, + type ApiMethod, + type ApiMethodSignature, + type ApiConstructor, + type ApiFunction, ApiReturnTypeMixin, ApiTypeParameterListMixin, - Excerpt, - ExcerptToken, + type Excerpt, + type ExcerptToken, ExcerptTokenKind, - HeritageType, - ApiVariable, - ApiTypeAlias + type HeritageType, + type ApiVariable, + type ApiTypeAlias } from '@microsoft/api-extractor-model'; import { - DeclarationReference, + type DeclarationReference, Navigation, Meaning -} from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import type { IYamlApiFile, IYamlItem, IYamlSyntax, @@ -53,14 +61,13 @@ import { IYamlReferenceSpec, IYamlInheritanceTree } from '../yaml/IYamlApiFile'; -import { - IYamlTocFile, - IYamlTocItem -} from '../yaml/IYamlTocFile'; +import type { IYamlTocFile, IYamlTocItem } from '../yaml/IYamlTocFile'; import { Utilities } from '../utils/Utilities'; -import { CustomMarkdownEmitter} from '../markdown/CustomMarkdownEmitter'; +import { CustomMarkdownEmitter } from '../markdown/CustomMarkdownEmitter'; +import { convertUDPYamlToSDP } from '../utils/ToSdpConvertHelper'; +import typescriptSchema from '../yaml/typescript.schema.json'; -const yamlApiSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, '..', 'yaml', 'typescript.schema.json')); +const yamlApiSchema: JsonSchema = JsonSchema.fromLoadedObject(typescriptSchema); interface IYamlReferences { references: IYamlReference[]; @@ -68,7 +75,7 @@ interface IYamlReferences { uidTypeReferenceCounters: Map; } -const enum FlattenMode { +enum FlattenMode { /** Include entries for nested namespaces and non-namespace children. */ NestedNamespacesAndChildren, /** Include entries for nested namespaces only. */ @@ -84,21 +91,28 @@ interface INameOptions { includeNamespace?: boolean; } +export type YamlFormat = 'udp' | 'sdp'; + /** * Writes documentation in the Universal Reference YAML file format, as defined by typescript.schema.json. */ export class YamlDocumenter { protected readonly newDocfxNamespaces: boolean; + private readonly _yamlFormat: string; private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; private _apiItemsByCanonicalReference: Map; private _yamlReferences: IYamlReferences | undefined; - private _outputFolder: string; - public constructor(apiModel: ApiModel, newDocfxNamespaces: boolean = false) { + public constructor( + apiModel: ApiModel, + newDocfxNamespaces: boolean = false, + yamlFormat: YamlFormat = 'sdp' + ) { this._apiModel = apiModel; this.newDocfxNamespaces = newDocfxNamespaces; + this._yamlFormat = yamlFormat; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByCanonicalReference = new Map(); @@ -107,17 +121,19 @@ export class YamlDocumenter { /** @virtual */ public generateFiles(outputFolder: string): void { - this._outputFolder = outputFolder; - console.log(); - this._deleteOldOutputFiles(); + this._deleteOldOutputFiles(outputFolder); for (const apiPackage of this._apiModel.packages) { console.log(`Writing ${apiPackage.name} package`); - this._visitApiItems(apiPackage, undefined); + this._visitApiItems(outputFolder, apiPackage, undefined); + } + + if (this._yamlFormat === 'sdp') { + convertUDPYamlToSDP(outputFolder); } - this._writeTocFile(this._apiModel.packages); + this._writeTocFile(outputFolder, this._apiModel.packages); } /** @virtual */ @@ -125,16 +141,21 @@ export class YamlDocumenter { return { name: 'SharePoint Framework reference', href: '~/overview/sharepoint.md', - items: [ ] + items: [] }; } /** @virtual */ - protected onCustomizeYamlItem(yamlItem: IYamlItem): void { // virtual + protected onCustomizeYamlItem(yamlItem: IYamlItem): void { + // virtual // (overridden by child class) } - private _visitApiItems(apiItem: ApiDocumentedItem, parentYamlFile: IYamlApiFile | undefined): boolean { + private _visitApiItems( + outputFolder: string, + apiItem: ApiDocumentedItem, + parentYamlFile: IYamlApiFile | undefined + ): boolean { let savedYamlReferences: IYamlReferences | undefined; if (!this._shouldEmbed(apiItem.kind)) { savedYamlReferences = this._yamlReferences; @@ -162,7 +183,7 @@ export class YamlDocumenter { const children: ApiItem[] = this._getLogicalChildren(apiItem); for (const child of children) { if (child instanceof ApiDocumentedItem) { - if (this._visitApiItems(child, newYamlFile)) { + if (this._visitApiItems(outputFolder, child, newYamlFile)) { if (!yamlItem.children) { yamlItem.children = []; } @@ -177,7 +198,7 @@ export class YamlDocumenter { this._yamlReferences = savedYamlReferences; - const yamlFilePath: string = this._getYamlFilePath(apiItem); + const yamlFilePath: string = this._getYamlFilePath(outputFolder, apiItem); if (apiItem.kind === ApiItemKind.Package) { console.log('Writing ' + yamlFilePath); @@ -191,8 +212,12 @@ export class YamlDocumenter { this._recordYamlReference( this._ensureYamlReferences(), this._getUid(apiItem), - this._getYamlItemName(apiItem, { includeNamespace: !this.newDocfxNamespaces, includeSignature: true }), - this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true })); + this._getYamlItemName(apiItem, { + includeNamespace: !this.newDocfxNamespaces, + includeSignature: true + }), + this._getYamlItemName(apiItem, { includeNamespace: true, includeSignature: true }) + ); } } @@ -203,11 +228,17 @@ export class YamlDocumenter { const children: ApiItem[] = []; if (apiItem.kind === ApiItemKind.Package) { // Skip over the entry point, since it's not part of the documentation hierarchy - this._flattenNamespaces(apiItem.members[0].members, children, - this.newDocfxNamespaces ? FlattenMode.NestedNamespacesAndChildren : FlattenMode.NestedChildren); + this._flattenNamespaces( + apiItem.members[0].members, + children, + this.newDocfxNamespaces ? FlattenMode.NestedNamespacesAndChildren : FlattenMode.NestedChildren + ); } else { - this._flattenNamespaces(apiItem.members, children, - this.newDocfxNamespaces ? FlattenMode.ImmediateChildren : FlattenMode.NestedChildren); + this._flattenNamespaces( + apiItem.members, + children, + this.newDocfxNamespaces ? FlattenMode.ImmediateChildren : FlattenMode.NestedChildren + ); } return children; } @@ -218,7 +249,11 @@ export class YamlDocumenter { // - X // - X.Y // - X.Y.Z - private _flattenNamespaces(items: ReadonlyArray, childrenOut: ApiItem[], mode: FlattenMode): boolean { + private _flattenNamespaces( + items: ReadonlyArray, + childrenOut: ApiItem[], + mode: FlattenMode + ): boolean { let hasNonNamespaceChildren: boolean = false; for (const item of items) { if (item.kind === ApiItemKind.Namespace) { @@ -260,10 +295,10 @@ export class YamlDocumenter { /** * Write the table of contents */ - private _writeTocFile(apiItems: ReadonlyArray): void { + private _writeTocFile(outputFolder: string, apiItems: ReadonlyArray): void { const tocFile: IYamlTocFile = this.buildYamlTocFile(apiItems); - const tocFilePath: string = path.join(this._outputFolder, 'toc.yml'); + const tocFilePath: string = path.join(outputFolder, 'toc.yml'); console.log('Writing ' + tocFilePath); this._writeYamlFile(tocFile, tocFilePath, '', undefined); } @@ -271,7 +306,7 @@ export class YamlDocumenter { /** @virtual */ protected buildYamlTocFile(apiItems: ReadonlyArray): IYamlTocFile { const tocFile: IYamlTocFile = { - items: [ ] + items: [] }; const rootItem: IYamlTocItem = this.onGetTocRoot(); @@ -334,6 +369,7 @@ export class YamlDocumenter { case ApiItemKind.Package: case ApiItemKind.Interface: case ApiItemKind.Enum: + case ApiItemKind.TypeAlias: return false; case ApiItemKind.Namespace: return !this.newDocfxNamespaces; @@ -379,6 +415,20 @@ export class YamlDocumenter { } } + if (tsdocComment) { + // Write the @example blocks + const exampleBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.example.tagNameWithUpperCase + ); + + for (const exampleBlock of exampleBlocks) { + const example: string = this._renderMarkdown(exampleBlock.content, apiItem); + if (example) { + yamlItem.example = [...(yamlItem.example || []), example]; + } + } + } + if (tsdocComment.deprecatedBlock) { const deprecatedMessage: string = this._renderMarkdown(tsdocComment.deprecatedBlock.content, apiItem); if (deprecatedMessage.length > 0) { @@ -388,20 +438,26 @@ export class YamlDocumenter { } if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) { - if (apiItem.releaseTag === ReleaseTag.Beta) { + if (apiItem.releaseTag === ReleaseTag.Alpha || apiItem.releaseTag === ReleaseTag.Beta) { yamlItem.isPreview = true; } } - yamlItem.name = this._getYamlItemName(apiItem, { includeSignature: true, - includeNamespace: !this.newDocfxNamespaces }); + yamlItem.name = this._getYamlItemName(apiItem, { + includeSignature: true, + includeNamespace: !this.newDocfxNamespaces + }); yamlItem.fullName = this._getYamlItemName(apiItem, { includeSignature: true, includeNamespace: true }); - yamlItem.langs = [ 'typeScript' ]; + yamlItem.langs = ['typeScript']; // Add the namespace of the item if it is contained in one. // Do not add the namespace parent of a namespace as they are flattened in the documentation. - if (apiItem.kind !== ApiItemKind.Namespace && apiItem.parent && apiItem.parent.kind === ApiItemKind.Namespace && - this.newDocfxNamespaces) { + if ( + apiItem.kind !== ApiItemKind.Namespace && + apiItem.parent && + apiItem.parent.kind === ApiItemKind.Namespace && + this.newDocfxNamespaces + ) { yamlItem.namespace = apiItem.parent.canonicalReference.toString(); } @@ -413,7 +469,7 @@ export class YamlDocumenter { yamlItem.type = 'field'; const enumMember: ApiEnumMember = apiItem as ApiEnumMember; - if (enumMember.initializerExcerpt.text.length > 0) { + if (enumMember.initializerExcerpt && enumMember.initializerExcerpt.text.length > 0) { yamlItem.numericValue = enumMember.initializerExcerpt.text; } @@ -484,9 +540,10 @@ export class YamlDocumenter { return yamlItem as IYamlItem; } - private _populateYamlTypeParameters(contextUid: DeclarationReference, apiItem: ApiTypeParameterListMixin): - IYamlParameter[] { - + private _populateYamlTypeParameters( + contextUid: DeclarationReference, + apiItem: ApiTypeParameterListMixin + ): IYamlParameter[] { const typeParameters: IYamlParameter[] = []; for (const apiTypeParameter of apiItem.typeParameters) { const typeParameter: IYamlParameter = { @@ -494,11 +551,14 @@ export class YamlDocumenter { }; if (apiTypeParameter.tsdocTypeParamBlock) { - typeParameter.description = this._renderMarkdown(apiTypeParameter.tsdocTypeParamBlock.content, apiItem); + typeParameter.description = this._renderMarkdown( + apiTypeParameter.tsdocTypeParamBlock.content, + apiItem + ); } if (!apiTypeParameter.constraintExcerpt.isEmpty) { - typeParameter.type = [ this._renderType(contextUid, apiTypeParameter.constraintExcerpt) ]; + typeParameter.type = [this._renderType(contextUid, apiTypeParameter.constraintExcerpt)]; } typeParameters.push(typeParameter); @@ -506,12 +566,14 @@ export class YamlDocumenter { return typeParameters; } - private _populateYamlClassOrInterface(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiClass | - ApiInterface): void { - + private _populateYamlClassOrInterface( + uid: DeclarationReference, + yamlItem: Partial, + apiItem: ApiClass | ApiInterface + ): void { if (apiItem instanceof ApiClass) { if (apiItem.extendsType) { - yamlItem.extends = [ this._renderType(uid, apiItem.extendsType.excerpt) ]; + yamlItem.extends = [this._renderType(uid, apiItem.extendsType.excerpt)]; yamlItem.inheritance = this._renderInheritance(uid, [apiItem.extendsType]); } if (apiItem.implementsTypes.length > 0) { @@ -552,9 +614,11 @@ export class YamlDocumenter { } } - private _populateYamlFunctionLike(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiMethod | - ApiMethodSignature | ApiConstructor | ApiFunction): void { - + private _populateYamlFunctionLike( + uid: DeclarationReference, + yamlItem: Partial, + apiItem: ApiMethod | ApiMethodSignature | ApiConstructor | ApiFunction + ): void { const syntax: IYamlSyntax = { content: apiItem.getExcerptWithModifiers() }; @@ -573,7 +637,7 @@ export class YamlDocumenter { if (returnType || returnDescription) { syntax.return = { - type: [ returnType ], + type: [returnType], description: returnDescription }; } @@ -586,13 +650,12 @@ export class YamlDocumenter { parameterDescription = this._renderMarkdown(apiParameter.tsdocParamBlock.content, apiItem); } - parameters.push( - { - id: apiParameter.name, - description: parameterDescription, - type: [ this._renderType(uid, apiParameter.parameterTypeExcerpt) ] - } as IYamlParameter - ); + parameters.push({ + id: apiParameter.name, + description: parameterDescription, + type: [this._renderType(uid, apiParameter.parameterTypeExcerpt)], + optional: apiParameter.isOptional + } as IYamlParameter); } if (parameters.length) { @@ -605,12 +668,13 @@ export class YamlDocumenter { syntax.typeParameters = typeParameters; } } - } - private _populateYamlProperty(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiPropertyItem): - void { - + private _populateYamlProperty( + uid: DeclarationReference, + yamlItem: Partial, + apiItem: ApiPropertyItem + ): void { const syntax: IYamlSyntax = { content: apiItem.getExcerptWithModifiers() }; @@ -618,14 +682,16 @@ export class YamlDocumenter { if (apiItem.propertyTypeExcerpt.text) { syntax.return = { - type: [ this._renderType(uid, apiItem.propertyTypeExcerpt) ] + type: [this._renderType(uid, apiItem.propertyTypeExcerpt)] }; } } - private _populateYamlVariable(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiVariable): - void { - + private _populateYamlVariable( + uid: DeclarationReference, + yamlItem: Partial, + apiItem: ApiVariable + ): void { const syntax: IYamlSyntax = { content: apiItem.getExcerptWithModifiers() }; @@ -633,14 +699,16 @@ export class YamlDocumenter { if (apiItem.variableTypeExcerpt.text) { syntax.return = { - type: [ this._renderType(uid, apiItem.variableTypeExcerpt) ] + type: [this._renderType(uid, apiItem.variableTypeExcerpt)] }; } } - private _populateYamlTypeAlias(uid: DeclarationReference, yamlItem: Partial, apiItem: ApiTypeAlias): - void { - + private _populateYamlTypeAlias( + uid: DeclarationReference, + yamlItem: Partial, + apiItem: ApiTypeAlias + ): void { const syntax: IYamlSyntax = { content: apiItem.getExcerptWithModifiers() }; @@ -653,7 +721,7 @@ export class YamlDocumenter { if (apiItem.typeExcerpt.text) { syntax.return = { - type: [ this._renderType(uid, apiItem.typeExcerpt) ] + type: [this._renderType(uid, apiItem.typeExcerpt)] }; } } @@ -666,19 +734,31 @@ export class YamlDocumenter { onGetFilenameForApiItem: (apiItem: ApiItem) => { // NOTE: GitHub's markdown renderer does not resolve relative hyperlinks correctly // unless they start with "./" or "../". - return `xref:${this._getUid(apiItem)}`; + + // To ensure the xref is properly escaped, we first encode the entire xref + // to handle escaping of reserved characters. Then we must replace '#' and '?' + // characters so that they are not interpreted as a querystring or hash. + // We must also backslash-escape unbalanced `(` and `)` characters as the + // markdown spec insists that they are only valid when balanced. To reduce + // the overhead we only support balanced parenthesis with a depth of 1. + return encodeURI(`xref:${this._getUid(apiItem)}`) + .replace(/[#?]/g, (s) => encodeURIComponent(s)) + .replace(/(\([^(]*\))|[()]/g, (s, balanced) => balanced || '\\' + s); } }); return stringBuilder.toString().trim(); } - private _writeYamlFile(dataObject: {}, filePath: string, yamlMimeType: string, - schema: JsonSchema|undefined): void { - + private _writeYamlFile( + dataObject: {}, + filePath: string, + yamlMimeType: string, + schema: JsonSchema | undefined + ): void { JsonFile.validateNoUndefinedMembers(dataObject); - let stringified: string = yaml.safeDump(dataObject, { + let stringified: string = yaml.dump(dataObject, { lineWidth: 120 }); @@ -742,9 +822,10 @@ export class YamlDocumenter { return this._yamlReferences; } - private _renderInheritance(contextUid: DeclarationReference, heritageTypes: ReadonlyArray): - IYamlInheritanceTree[] { - + private _renderInheritance( + contextUid: DeclarationReference, + heritageTypes: ReadonlyArray + ): IYamlInheritanceTree[] { const result: IYamlInheritanceTree[] = []; for (const heritageType of heritageTypes) { const type: string = this._renderType(contextUid, heritageType.excerpt); @@ -753,11 +834,16 @@ export class YamlDocumenter { if (apiItem) { if (apiItem instanceof ApiClass) { if (apiItem.extendsType) { - yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), [apiItem.extendsType]); + yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), [ + apiItem.extendsType + ]); } } else if (apiItem instanceof ApiInterface) { if (apiItem.extendsTypes.length > 0) { - yamlInheritance.inheritance = this._renderInheritance(this._getUidObject(apiItem), apiItem.extendsTypes); + yamlInheritance.inheritance = this._renderInheritance( + this._getUidObject(apiItem), + apiItem.extendsTypes + ); } } } @@ -767,9 +853,7 @@ export class YamlDocumenter { } private _renderType(contextUid: DeclarationReference, typeExcerpt: Excerpt): string { - const excerptTokens: ExcerptToken[] = typeExcerpt.tokens.slice( - typeExcerpt.tokenRange.startIndex, - typeExcerpt.tokenRange.endIndex); + const excerptTokens: ExcerptToken[] = [...typeExcerpt.spannedTokens]; // copy the read-only array if (excerptTokens.length === 0) { return ''; @@ -787,7 +871,7 @@ export class YamlDocumenter { const typeName: string = typeExcerpt.text.trim(); // If there are no references to be used for a complex type, return the type name. - if (!excerptTokens.some(tok => tok.kind === ExcerptTokenKind.Reference && !!tok.canonicalReference)) { + if (!excerptTokens.some((tok) => tok.kind === ExcerptTokenKind.Reference && !!tok.canonicalReference)) { return typeName; } @@ -800,9 +884,11 @@ export class YamlDocumenter { } // If the excerpt consists of a single reference token, record the reference. - if (excerptTokens.length === 1 && + if ( + excerptTokens.length === 1 && excerptTokens[0].kind === ExcerptTokenKind.Reference && - excerptTokens[0].canonicalReference) { + excerptTokens[0].canonicalReference + ) { const excerptRef: string = excerptTokens[0].canonicalReference.toString(); const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(excerptRef); return this._recordYamlReference( @@ -815,10 +901,7 @@ export class YamlDocumenter { // Otherwise, the type is complex and consists of one or more reference tokens. Record a reference // and return its uid. - const baseUid: string = contextUid - .withMeaning(undefined) - .withOverloadIndex(undefined) - .toString(); + const baseUid: string = contextUid.withMeaning(undefined).withOverloadIndex(undefined).toString(); // Keep track of the count for the base uid (without meaning or overload index) to ensure // that each complex type reference is unique. @@ -834,10 +917,14 @@ export class YamlDocumenter { return this._recordYamlReference(yamlReferences, uid, typeName, typeName, excerptTokens); } - private _recordYamlReference(yamlReferences: IYamlReferences, uid: string, name: string, fullName: string, - excerptTokens?: ExcerptToken[]): string { - - if (yamlReferences.references.some(ref => ref.uid === uid)) { + private _recordYamlReference( + yamlReferences: IYamlReferences, + uid: string, + name: string, + fullName: string, + excerptTokens?: ExcerptToken[] + ): string { + if (yamlReferences.references.some((ref) => ref.uid === uid)) { return uid; } @@ -846,37 +933,44 @@ export class YamlDocumenter { if (excerptTokens) { for (const token of excerptTokens) { if (token.kind === ExcerptTokenKind.Reference) { - const spec: IYamlReferenceSpec = { }; + const spec: IYamlReferenceSpec = {}; const specUid: string | undefined = token.canonicalReference && token.canonicalReference.toString(); - const apiItem: ApiItem | undefined = specUid ? this._apiItemsByCanonicalReference.get(specUid) : undefined; + const apiItem: ApiItem | undefined = specUid + ? this._apiItemsByCanonicalReference.get(specUid) + : undefined; if (specUid) { spec.uid = specUid; } spec.name = token.text; - spec.fullName = - apiItem ? apiItem.getScopedNameWithinPackage() : - token.canonicalReference ? token.canonicalReference - .withSource(undefined) - .withMeaning(undefined) - .withOverloadIndex(undefined) - .toString() : - token.text; + spec.fullName = apiItem + ? apiItem.getScopedNameWithinPackage() + : token.canonicalReference + ? token.canonicalReference + .withSource(undefined) + .withMeaning(undefined) + .withOverloadIndex(undefined) + .toString() + : token.text; specs.push(spec); } else { - specs.push( - { - name: token.text, - fullName: token.text - } - ); + specs.push({ + name: token.text, + fullName: token.text + }); } } } const yamlReference: IYamlReference = { uid }; if (specs.length > 0) { - yamlReference.name = specs.map(s => s.name).join('').trim(); - yamlReference.fullName = specs.map(s => s.fullName || s.name).join('').trim(); + yamlReference.name = specs + .map((s) => s.name) + .join('') + .trim(); + yamlReference.fullName = specs + .map((s) => s.fullName || s.name) + .join('') + .trim(); yamlReference['spec.typeScript'] = specs; } else { if (name !== uid) { @@ -894,8 +988,11 @@ export class YamlDocumenter { private _getYamlItemName(apiItem: ApiItem, options: INameOptions = {}): string { const { includeSignature, includeNamespace } = options; const baseName: string = includeSignature ? Utilities.getConciseSignature(apiItem) : apiItem.displayName; - if ((includeNamespace || apiItem.kind === ApiItemKind.Namespace) && apiItem.parent && - apiItem.parent.kind === ApiItemKind.Namespace) { + if ( + (includeNamespace || apiItem.kind === ApiItemKind.Namespace) && + apiItem.parent && + apiItem.parent.kind === ApiItemKind.Namespace + ) { // If the immediate parent is a namespace, then add the namespaces to the name. For example: // // // Name: "N1" @@ -922,7 +1019,7 @@ export class YamlDocumenter { // embeds this entry in the web page for "N1.N2.C", so the container is obvious. Whereas "N1.N2.f(x,y)" // needs to be qualified because the DocFX template doesn't make pages for namespaces. Instead, they get // flattened into the package's page. - const nameParts: string[] = [ baseName ]; + const nameParts: string[] = [baseName]; for (let current: ApiItem | undefined = apiItem.parent; current; current = current.parent) { if (current.kind !== ApiItemKind.Namespace) { @@ -938,7 +1035,7 @@ export class YamlDocumenter { } } - private _getYamlFilePath(apiItem: ApiItem): string { + private _getYamlFilePath(outputFolder: string, apiItem: ApiItem): string { let result: string = ''; for (const current of apiItem.getHierarchy()) { @@ -965,11 +1062,11 @@ export class YamlDocumenter { disambiguator = `-${apiItem.kind.toLowerCase()}`; } - return path.join(this._outputFolder, result + disambiguator + '.yml'); + return path.join(outputFolder, result + disambiguator + '.yml'); } - private _deleteOldOutputFiles(): void { - console.log('Deleting old output from ' + this._outputFolder); - FileSystem.ensureEmptyFolder(this._outputFolder); + private _deleteOldOutputFiles(outputFolder: string): void { + console.log('Deleting old output from ' + outputFolder); + FileSystem.ensureEmptyFolder(outputFolder); } } diff --git a/apps/api-documenter/src/index.ts b/apps/api-documenter/src/index.ts index 514ff7a7994..fe1f9a6a206 100644 --- a/apps/api-documenter/src/index.ts +++ b/apps/api-documenter/src/index.ts @@ -9,19 +9,12 @@ * @packageDocumentation */ -export { - IFeatureDefinition, - IApiDocumenterPluginManifest -} from './plugin/IApiDocumenterPluginManifest'; +export type { IFeatureDefinition, IApiDocumenterPluginManifest } from './plugin/IApiDocumenterPluginManifest'; export { MarkdownDocumenterAccessor } from './plugin/MarkdownDocumenterAccessor'; export { MarkdownDocumenterFeatureContext, - IMarkdownDocumenterFeatureOnBeforeWritePageArgs, - IMarkdownDocumenterFeatureOnFinishedArgs, + type IMarkdownDocumenterFeatureOnBeforeWritePageArgs, + type IMarkdownDocumenterFeatureOnFinishedArgs, MarkdownDocumenterFeature } from './plugin/MarkdownDocumenterFeature'; -export { - PluginFeature, - PluginFeatureContext, - PluginFeatureInitialization -} from './plugin/PluginFeature'; +export { PluginFeature, PluginFeatureContext, PluginFeatureInitialization } from './plugin/PluginFeature'; diff --git a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts index 005075b50ea..5ec5bc9e90f 100644 --- a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts +++ b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts @@ -1,29 +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 colors from 'colors'; - -import { - DocNode, DocLinkTag, StringBuilder -} from '@microsoft/tsdoc'; -import { - ApiModel, - IResolveDeclarationReferenceResult, - ApiItem -} from '@microsoft/api-extractor-model'; +import type { DocNode, DocLinkTag, StringBuilder } from '@microsoft/tsdoc'; +import type { ApiModel, IResolveDeclarationReferenceResult, ApiItem } from '@microsoft/api-extractor-model'; +import { Colorize } from '@rushstack/terminal'; import { CustomDocNodeKind } from '../nodes/CustomDocNodeKind'; -import { DocHeading } from '../nodes/DocHeading'; -import { DocNoteBox } from '../nodes/DocNoteBox'; -import { DocTable } from '../nodes/DocTable'; -import { DocTableCell } from '../nodes/DocTableCell'; -import { DocEmphasisSpan } from '../nodes/DocEmphasisSpan'; +import type { DocHeading } from '../nodes/DocHeading'; +import type { DocNoteBox } from '../nodes/DocNoteBox'; +import type { DocTable } from '../nodes/DocTable'; +import type { DocTableCell } from '../nodes/DocTableCell'; +import type { DocEmphasisSpan } from '../nodes/DocEmphasisSpan'; import { MarkdownEmitter, - IMarkdownEmitterContext, - IMarkdownEmitterOptions + type IMarkdownEmitterContext, + type IMarkdownEmitterOptions } from './MarkdownEmitter'; -import { IndentedWriter } from '../utils/IndentedWriter'; +import type { IndentedWriter } from '../utils/IndentedWriter'; export interface ICustomMarkdownEmitterOptions extends IMarkdownEmitterOptions { contextApiItem: ApiItem | undefined; @@ -34,13 +27,17 @@ export interface ICustomMarkdownEmitterOptions extends IMarkdownEmitterOptions { export class CustomMarkdownEmitter extends MarkdownEmitter { private _apiModel: ApiModel; - public constructor (apiModel: ApiModel) { + public constructor(apiModel: ApiModel) { super(); this._apiModel = apiModel; } - public emit(stringBuilder: StringBuilder, docNode: DocNode, options: ICustomMarkdownEmitterOptions): string { + public emit( + stringBuilder: StringBuilder, + docNode: DocNode, + options: ICustomMarkdownEmitterOptions + ): string { return super.emit(stringBuilder, docNode, options); } @@ -55,9 +52,15 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { let prefix: string; switch (docHeading.level) { - case 1: prefix = '##'; break; - case 2: prefix = '###'; break; - case 3: prefix = '###'; break; + case 1: + prefix = '##'; + break; + case 2: + prefix = '###'; + break; + case 3: + prefix = '###'; + break; default: prefix = '####'; } @@ -86,8 +89,6 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { // whereas VS Code's renderer is totally fine with it. writer.ensureSkippedLine(); - context.insideTable = true; - // Markdown table rows can have inconsistent cell counts. Size the table based on the longest row. let columnCount: number = 0; if (docTable.header) { @@ -99,39 +100,43 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { } } - // write the table header (which is required by Markdown) - writer.write('| '); - for (let i: number = 0; i < columnCount; ++i) { - writer.write(' '); - if (docTable.header) { + writer.write(''); + if (docTable.header) { + writer.write(''); + for (let i: number = 0; i < columnCount; ++i) { + writer.write(''); } - writer.write(' |'); - } - writer.writeLine(); - - // write the divider - writer.write('| '); - for (let i: number = 0; i < columnCount; ++i) { - writer.write(' --- |'); + writer.write(''); } writer.writeLine(); + writer.write(''); for (const row of docTable.rows) { - writer.write('| '); + writer.write(''); for (const cell of row.cells) { - writer.write(' '); + writer.write(''); } + writer.write(''); writer.writeLine(); } - writer.writeLine(); - - context.insideTable = false; + writer.write(''); + writer.write('
'); + writer.ensureNewLine(); + writer.writeLine(); const cell: DocTableCell | undefined = docTable.header.cells[i]; if (cell) { this.writeNode(cell.content, context, false); } + writer.ensureNewLine(); + writer.writeLine(); + writer.write('
'); + writer.ensureNewLine(); + writer.writeLine(); this.writeNode(cell.content, context, false); - writer.write(' |'); + writer.ensureNewLine(); + writer.writeLine(); + writer.write('
'); + writer.ensureSkippedLine(); break; } @@ -147,18 +152,21 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { break; } default: - super.writeNode(docNode, context, false); + super.writeNode(docNode, context, docNodeSiblings); } } /** @override */ - protected writeLinkTagWithCodeDestination(docLinkTag: DocLinkTag, - context: IMarkdownEmitterContext): void { - + protected writeLinkTagWithCodeDestination( + docLinkTag: DocLinkTag, + context: IMarkdownEmitterContext + ): void { const options: ICustomMarkdownEmitterOptions = context.options; - const result: IResolveDeclarationReferenceResult - = this._apiModel.resolveDeclarationReference(docLinkTag.codeDestination!, options.contextApiItem); + const result: IResolveDeclarationReferenceResult = this._apiModel.resolveDeclarationReference( + docLinkTag.codeDestination!, + options.contextApiItem + ); if (result.resolvedApiItem) { const filename: string | undefined = options.onGetFilenameForApiItem(result.resolvedApiItem); @@ -166,7 +174,6 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { if (filename) { let linkText: string = docLinkTag.linkText || ''; if (linkText.length === 0) { - // Generate a name such as Namespace1.Namespace2.MyClass.myMethod() linkText = result.resolvedApiItem.getScopedNameWithinPackage(); } @@ -177,13 +184,16 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { context.writer.write(encodedLinkText); context.writer.write(`](${filename!})`); } else { - console.log(colors.yellow('WARNING: Unable to determine link text')); + console.log(Colorize.yellow('WARNING: Unable to determine link text')); } } } else if (result.errorMessage) { - console.log(colors.yellow(`WARNING: Unable to resolve reference "${docLinkTag.codeDestination!.emitAsTsdoc()}": ` - + result.errorMessage)); + console.log( + Colorize.yellow( + `WARNING: Unable to resolve reference "${docLinkTag.codeDestination!.emitAsTsdoc()}": ` + + result.errorMessage + ) + ); } } - } diff --git a/apps/api-documenter/src/markdown/MarkdownEmitter.ts b/apps/api-documenter/src/markdown/MarkdownEmitter.ts index 33cb36cf1c4..663eee17f1e 100644 --- a/apps/api-documenter/src/markdown/MarkdownEmitter.ts +++ b/apps/api-documenter/src/markdown/MarkdownEmitter.ts @@ -2,32 +2,30 @@ // See LICENSE in the project root for license information. import { - DocNode, + type DocNode, DocNodeKind, - StringBuilder, - DocPlainText, - DocHtmlStartTag, - DocHtmlEndTag, - DocCodeSpan, - DocLinkTag, - DocParagraph, - DocFencedCode, - DocSection, + type StringBuilder, + type DocPlainText, + type DocHtmlStartTag, + type DocHtmlEndTag, + type DocCodeSpan, + type DocLinkTag, + type DocParagraph, + type DocFencedCode, + type DocSection, DocNodeTransforms, - DocEscapedText, - DocErrorText, - DocBlockTag + type DocEscapedText, + type DocErrorText, + type DocBlockTag } from '@microsoft/tsdoc'; import { InternalError } from '@rushstack/node-core-library'; import { IndentedWriter } from '../utils/IndentedWriter'; -export interface IMarkdownEmitterOptions { -} +export interface IMarkdownEmitterOptions {} export interface IMarkdownEmitterContext { writer: IndentedWriter; - insideTable: boolean; boldRequested: boolean; italicRequested: boolean; @@ -43,13 +41,11 @@ export interface IMarkdownEmitterContext { * For more info: https://en.wikipedia.org/wiki/Markdown */ export class MarkdownEmitter { - public emit(stringBuilder: StringBuilder, docNode: DocNode, options: IMarkdownEmitterOptions): string { const writer: IndentedWriter = new IndentedWriter(stringBuilder); const context: IMarkdownEmitterContext = { writer, - insideTable: false, boldRequested: false, italicRequested: false, @@ -69,7 +65,7 @@ export class MarkdownEmitter { protected getEscapedText(text: string): string { const textWithBackslashes: string = text - .replace(/\\/g, '\\\\') // first replace the escape character + .replace(/\\/g, '\\\\') // first replace the escape character .replace(/[*#[\]_|`~]/g, (x) => '\\' + x) // then escape any special characters .replace(/---/g, '\\-\\-\\-') // hyphens only if it's 3 or more .replace(/&/g, '&') @@ -108,23 +104,9 @@ export class MarkdownEmitter { } case DocNodeKind.CodeSpan: { const docCodeSpan: DocCodeSpan = docNode as DocCodeSpan; - if (context.insideTable) { - writer.write(''); - } else { - writer.write('`'); - } - if (context.insideTable) { - const code: string = this.getTableEscapedText(docCodeSpan.code); - const parts: string[] = code.split(/\r?\n/g); - writer.write(parts.join('
')); - } else { - writer.write(docCodeSpan.code); - } - if (context.insideTable) { - writer.write(''); - } else { - writer.write('`'); - } + writer.write('`'); + writer.write(docCodeSpan.code); + writer.write('`'); break; } case DocNodeKind.LinkTag: { @@ -141,20 +123,10 @@ export class MarkdownEmitter { case DocNodeKind.Paragraph: { const docParagraph: DocParagraph = docNode as DocParagraph; const trimmedParagraph: DocParagraph = DocNodeTransforms.trimSpacesInParagraph(docParagraph); - if (context.insideTable) { - if (docNodeSiblings) { - writer.write('

'); - this.writeNodes(trimmedParagraph.nodes, context); - writer.write('

'); - } else { - // Special case: If we are the only element inside this table cell, then we can omit the

container. - this.writeNodes(trimmedParagraph.nodes, context); - } - } else { - this.writeNodes(trimmedParagraph.nodes, context); - writer.ensureNewLine(); - writer.writeLine(); - } + + this.writeNodes(trimmedParagraph.nodes, context); + writer.ensureNewLine(); + writer.writeLine(); break; } case DocNodeKind.FencedCode: { @@ -164,7 +136,7 @@ export class MarkdownEmitter { writer.write(docFencedCode.language); writer.writeLine(); writer.write(docFencedCode.code); - writer.writeLine(); + writer.ensureNewLine(); writer.writeLine('```'); break; } @@ -204,15 +176,14 @@ export class MarkdownEmitter { /** @virtual */ protected writeLinkTagWithCodeDestination(docLinkTag: DocLinkTag, context: IMarkdownEmitterContext): void { - // The subclass needs to implement this to support code destinations throw new InternalError('writeLinkTagWithCodeDestination()'); } /** @virtual */ protected writeLinkTagWithUrlDestination(docLinkTag: DocLinkTag, context: IMarkdownEmitterContext): void { - const linkText: string = docLinkTag.linkText !== undefined ? docLinkTag.linkText - : docLinkTag.urlDestination!; + const linkText: string = + docLinkTag.linkText !== undefined ? docLinkTag.linkText : docLinkTag.urlDestination!; const encodedLinkText: string = this.getEscapedText(linkText.replace(/\s+/g, ' ')); @@ -227,7 +198,7 @@ export class MarkdownEmitter { // split out the [ leading whitespace, content, trailing whitespace ] const parts: string[] = text.match(/^(\s*)(.*?)(\s*)$/) || []; - writer.write(parts[1]); // write leading whitespace + writer.write(parts[1]); // write leading whitespace const middle: string = parts[2]; @@ -249,23 +220,23 @@ export class MarkdownEmitter { } if (context.boldRequested) { - writer.write(''); + writer.write('**'); } if (context.italicRequested) { - writer.write(''); + writer.write('_'); } writer.write(this.getEscapedText(middle)); if (context.italicRequested) { - writer.write(''); + writer.write('_'); } if (context.boldRequested) { - writer.write(''); + writer.write('**'); } } - writer.write(parts[3]); // write trailing whitespace + writer.write(parts[3]); // write trailing whitespace } protected writeNodes(docNodes: ReadonlyArray, 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 a0dfe7d5a1c..5e545c8d39b 100644 --- a/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts +++ b/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts @@ -3,7 +3,7 @@ import { DocSection, - TSDocConfiguration, + type TSDocConfiguration, DocPlainText, StringBuilder, DocParagraph, @@ -21,7 +21,7 @@ import { DocTable } from '../../nodes/DocTable'; import { DocTableRow } from '../../nodes/DocTableRow'; import { DocTableCell } from '../../nodes/DocTableCell'; import { CustomMarkdownEmitter } from '../CustomMarkdownEmitter'; -import { ApiModel, ApiItem } from '@microsoft/api-extractor-model'; +import { ApiModel, type ApiItem } from '@microsoft/api-extractor-model'; test('render Markdown from TSDoc', () => { const configuration: TSDocConfiguration = CustomDocNodes.configuration; @@ -30,137 +30,97 @@ test('render Markdown from TSDoc', () => { output.appendNodes([ new DocHeading({ configuration, title: 'Simple bold test' }), - new DocParagraph({ configuration }, - [ - new DocPlainText({ configuration, text: 'This is a ' }), - new DocEmphasisSpan({ configuration, bold: true }, - [ - new DocPlainText({ configuration, text: 'bold' }) - ] - ), - new DocPlainText({ configuration, text: ' word.' }) - ] - ) + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: 'This is a ' }), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'bold' })]), + new DocPlainText({ configuration, text: ' word.' }) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'All whitespace bold' }), - new DocParagraph({ configuration }, - [ - new DocEmphasisSpan({ configuration, bold: true }, - [ - new DocPlainText({ configuration, text: ' ' }) - ] - ) - ] - ) + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: ' ' })]) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Newline bold' }), - new DocParagraph({ configuration }, - [ - new DocEmphasisSpan({ configuration, bold: true }, - [ - new DocPlainText({ configuration, text: 'line 1' }), - new DocSoftBreak({ configuration }), - new DocPlainText({ configuration, text: 'line 2' }) - ] - ) - ] - ) + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'line 1' }), + new DocSoftBreak({ configuration }), + new DocPlainText({ configuration, text: 'line 2' }) + ]) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Newline bold with spaces' }), - new DocParagraph({ configuration }, - [ - new DocEmphasisSpan({ configuration, bold: true }, - [ - new DocPlainText({ configuration, text: ' line 1 ' }), - new DocSoftBreak({ configuration }), - new DocPlainText({ configuration, text: ' line 2 ' }), - new DocSoftBreak({ configuration }), - new DocPlainText({ configuration, text: ' line 3 ' }) - ] - ) - ] - ) + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: ' line 1 ' }), + new DocSoftBreak({ configuration }), + new DocPlainText({ configuration, text: ' line 2 ' }), + new DocSoftBreak({ configuration }), + new DocPlainText({ configuration, text: ' line 3 ' }) + ]) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Adjacent bold regions' }), - new DocParagraph({ configuration }, - [ - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'one' }) ] - ), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'two' }) ] - ), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: ' three ' }) ] - ), - new DocPlainText({ configuration, text: '' }), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'four' }) ] - ), - new DocPlainText({ configuration, text: 'non-bold' }), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'five' }) ] - ) - ] - ) + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'one' })]), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'two' })]), + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: ' three ' }) + ]), + new DocPlainText({ configuration, text: '' }), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'four' })]), + new DocPlainText({ configuration, text: 'non-bold' }), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'five' })]) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Adjacent to other characters' }), - new DocParagraph({ configuration }, - [ - new DocLinkTag({ - configuration, - tagName: '@link', - linkText: 'a link', - urlDestination: './index.md' - }), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'bold' }) ] - ), - new DocPlainText({ configuration, text: 'non-bold' }), - new DocPlainText({ configuration, text: 'more-non-bold' }) - ] - ) + new DocParagraph({ configuration }, [ + new DocLinkTag({ + configuration, + tagName: '@link', + linkText: 'a link', + urlDestination: './index.md' + }), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'bold' })]), + new DocPlainText({ configuration, text: 'non-bold' }), + new DocPlainText({ configuration, text: 'more-non-bold' }) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Unknown block tag' }), - new DocParagraph({ configuration }, - [ - new DocBlockTag({ - configuration, - tagName: '@unknown' - }), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'bold' }) ] - ), - new DocPlainText({ configuration, text: 'non-bold' }), - new DocPlainText({ configuration, text: 'more-non-bold' }) - ] - ) + new DocParagraph({ configuration }, [ + new DocBlockTag({ + configuration, + tagName: '@unknown' + }), + new DocEmphasisSpan({ configuration, bold: true }, [new DocPlainText({ configuration, text: 'bold' })]), + new DocPlainText({ configuration, text: 'non-bold' }), + new DocPlainText({ configuration, text: 'more-non-bold' }) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Bad characters' }), - new DocParagraph({ configuration }, - [ - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: '*one*two*' }) ] - ), - new DocEmphasisSpan({ configuration, bold: true }, - [ new DocPlainText({ configuration, text: 'three*four' }) ] - ) - ] - ) + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: '*one*two*' }) + ]), + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'three*four' }) + ]) + ]) ]); output.appendNodes([ @@ -168,46 +128,53 @@ test('render Markdown from TSDoc', () => { new DocParagraph({ configuration }, [ new DocPlainText({ configuration, text: 'Double-encoded JSON: "{ \\"A\\": 123}"' }) ]), - new DocParagraph({ configuration }, - [ new DocPlainText({ configuration, text: 'HTML chars: ' }) ] - ), - new DocParagraph({ configuration }, - [ new DocPlainText({ configuration, text: 'HTML escape: "' }) ] - ), - new DocParagraph({ configuration }, - [ new DocPlainText({ configuration, text: '3 or more hyphens: - -- --- ---- ----- ------' }) ] - ) + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: 'HTML chars: ' }) + ]), + new DocParagraph({ configuration }, [new DocPlainText({ configuration, text: 'HTML escape: "' })]), + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: '3 or more hyphens: - -- --- ---- ----- ------' }) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'HTML tag' }), - new DocParagraph({ configuration }, - [ - new DocHtmlStartTag({ configuration, name: 'b' }), - new DocPlainText({ configuration, text: 'bold' }), - new DocHtmlEndTag({ configuration, name: 'b' }) - ] - ) + new DocParagraph({ configuration }, [ + new DocHtmlStartTag({ configuration, name: 'b' }), + new DocPlainText({ configuration, text: 'bold' }), + new DocHtmlEndTag({ configuration, name: 'b' }) + ]) ]); output.appendNodes([ new DocHeading({ configuration, title: 'Table' }), - new DocTable({ + new DocTable( + { configuration, - headerTitles: [ 'Header 1', 'Header 2' ] - }, [ - new DocTableRow({ configuration }, [ - new DocTableCell({ configuration }, [ - new DocParagraph({ configuration }, - [ new DocPlainText({ configuration, text: 'Cell 1' }) ] - ) - ]), - new DocTableCell({ configuration }, [ - new DocParagraph({ configuration }, - [ new DocPlainText({ configuration, text: 'Cell 2' }) ] - ) + headerTitles: ['Header 1', 'Header 2'] + }, + [ + new DocTableRow({ configuration }, [ + new DocTableCell({ configuration }, [ + new DocParagraph({ configuration }, [new DocPlainText({ configuration, text: 'Cell 1' })]) + ]), + new DocTableCell({ configuration }, [ + new DocParagraph({ configuration }, [new DocPlainText({ configuration, text: 'Cell 2' })]), + new DocParagraph({ configuration }, [ + new DocEmphasisSpan({ configuration, bold: true }, [ + new DocPlainText({ configuration, text: 'bold text' }) + ]) + ]) + ]) ]) - ]) + ] + ) + ]); + + output.appendNodes([ + new DocHeading({ configuration, title: 'After a table' }), + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: 'just checking lines after a table' }) ]) ]); @@ -221,5 +188,6 @@ test('render Markdown from TSDoc', () => { } }); - expect(stringBuilder).toMatchSnapshot(); + expect(stringBuilder.toString()).toMatchSnapshot(); + console.log(stringBuilder.toString()); }); 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 ae459a5a8d7..2616cbebe24 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,12 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`render Markdown from TSDoc 1`] = ` -StringBuilder { - "_chunks": Array [ - " +" ## Simple bold test -This is a bold word. +This is a **bold** word. ## All whitespace bold @@ -14,27 +12,27 @@ This is a bold word. ## Newline bold -line 1 line 2 +**line 1** **line 2** ## Newline bold with spaces - line 1 line 2 line 3 + **line 1** **line 2** **line 3** ## Adjacent bold regions -onetwo three fournon-boldfive +**one****two** **three** **four**non-bold**five** ## Adjacent to other characters -[a link](./index.md)boldnon-boldmore-non-bold +[a link](./index.md)**bold**non-boldmore-non-bold ## Unknown block tag -boldnon-boldmore-non-bold +**bold**non-boldmore-non-bold ## Bad characters -\\\\*one\\\\*two\\\\*three\\\\*four +**\\\\*one\\\\*two\\\\*****three\\\\*four** ## Characters that should be escaped @@ -52,11 +50,35 @@ HTML escape: &quot; ## Table -| Header 1 | Header 2 | -| --- | --- | -| Cell 1 | Cell 2 | + + +
-", - ], -} +Header 1 + + + + +Header 2 + + +
+ +Cell 1 + + + + +Cell 2 + +**bold text** + + +
+ +## 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 94bb644ac6a..9d0af5fdab8 100644 --- a/apps/api-documenter/src/nodes/CustomDocNodeKind.ts +++ b/apps/api-documenter/src/nodes/CustomDocNodeKind.ts @@ -1,4 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; @@ -6,19 +10,16 @@ import { DocTable } from './DocTable'; import { DocTableCell } from './DocTableCell'; import { DocTableRow } from './DocTableRow'; -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - /** * Identifies custom subclasses of {@link DocNode}. */ -export const enum CustomDocNodeKind { - EmphasisSpan = 'EmphasisSpan', - Heading = 'Heading', - NoteBox = 'NoteBox', - Table = 'Table', - TableCell = 'TableCell', - TableRow = 'TableRow' +export enum CustomDocNodeKind { + EmphasisSpan = 'EmphasisSpan', + Heading = 'Heading', + NoteBox = 'NoteBox', + Table = 'Table', + TableCell = 'TableCell', + TableRow = 'TableRow' } export class CustomDocNodes { diff --git a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts index 986d5029a41..bc2197689fc 100644 --- a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts +++ b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts @@ -1,11 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - DocNode, - DocNodeContainer, - IDocNodeContainerParameters -} from '@microsoft/tsdoc'; +import { type DocNode, DocNodeContainer, type IDocNodeContainerParameters } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocHeading.ts b/apps/api-documenter/src/nodes/DocHeading.ts index 7109dbfb409..ee40a8bb6bc 100644 --- a/apps/api-documenter/src/nodes/DocHeading.ts +++ b/apps/api-documenter/src/nodes/DocHeading.ts @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - IDocNodeParameters, - DocNode -} from '@microsoft/tsdoc'; +import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** diff --git a/apps/api-documenter/src/nodes/DocNoteBox.ts b/apps/api-documenter/src/nodes/DocNoteBox.ts index 302112d45f3..cccece1460c 100644 --- a/apps/api-documenter/src/nodes/DocNoteBox.ts +++ b/apps/api-documenter/src/nodes/DocNoteBox.ts @@ -1,18 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - IDocNodeParameters, - DocNode, - DocSection -} from '@microsoft/tsdoc'; +import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** * Constructor parameters for {@link DocNoteBox}. */ -export interface IDocNoteBoxParameters extends IDocNodeParameters { -} +export interface IDocNoteBoxParameters extends IDocNodeParameters {} /** * Represents a note box, which is typically displayed as a bordered box containing informational text. diff --git a/apps/api-documenter/src/nodes/DocTable.ts b/apps/api-documenter/src/nodes/DocTable.ts index 0d74003c59d..945098a4adb 100644 --- a/apps/api-documenter/src/nodes/DocTable.ts +++ b/apps/api-documenter/src/nodes/DocTable.ts @@ -1,13 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - IDocNodeParameters, - DocNode -} from '@microsoft/tsdoc'; +import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableRow } from './DocTableRow'; -import { DocTableCell } from './DocTableCell'; +import type { DocTableCell } from './DocTableCell'; /** * Constructor parameters for {@link DocTable}. @@ -34,8 +32,10 @@ export class DocTable extends DocNode { if (parameters) { if (parameters.headerTitles) { if (parameters.headerCells) { - throw new Error('IDocTableParameters.headerCells and IDocTableParameters.headerTitles' - + ' cannot both be specified'); + throw new Error( + 'IDocTableParameters.headerCells and IDocTableParameters.headerTitles' + + ' cannot both be specified' + ); } for (const cellText of parameters.headerTitles) { this.header.addPlainTextCell(cellText); diff --git a/apps/api-documenter/src/nodes/DocTableCell.ts b/apps/api-documenter/src/nodes/DocTableCell.ts index 23b679d8c5f..f0911dbfd59 100644 --- a/apps/api-documenter/src/nodes/DocTableCell.ts +++ b/apps/api-documenter/src/nodes/DocTableCell.ts @@ -1,18 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - IDocNodeParameters, - DocNode, - DocSection -} from '@microsoft/tsdoc'; +import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** * Constructor parameters for {@link DocTableCell}. */ -export interface IDocTableCellParameters extends IDocNodeParameters { -} +export interface IDocTableCellParameters extends IDocNodeParameters {} /** * Represents table cell, similar to an HTML `` element. diff --git a/apps/api-documenter/src/nodes/DocTableRow.ts b/apps/api-documenter/src/nodes/DocTableRow.ts index 2391b01f14d..85bd873d907 100644 --- a/apps/api-documenter/src/nodes/DocTableRow.ts +++ b/apps/api-documenter/src/nodes/DocTableRow.ts @@ -1,19 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - IDocNodeParameters, - DocNode, - DocPlainText -} from '@microsoft/tsdoc'; +import { type IDocNodeParameters, DocNode, DocPlainText } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableCell } from './DocTableCell'; /** * Constructor parameters for {@link DocTableRow}. */ -export interface IDocTableRowParameters extends IDocNodeParameters { -} +export interface IDocTableRowParameters extends IDocNodeParameters {} /** * Represents table row, similar to an HTML `` element. @@ -53,10 +49,12 @@ export class DocTableRow extends DocNode { public addPlainTextCell(cellContent: string): DocTableCell { const cell: DocTableCell = this.createAndAddCell(); - cell.content.appendNodeInParagraph(new DocPlainText({ - configuration: this.configuration, - text: cellContent - })); + cell.content.appendNodeInParagraph( + new DocPlainText({ + configuration: this.configuration, + text: cellContent + }) + ); return cell; } diff --git a/apps/api-documenter/src/plugin/IApiDocumenterPluginManifest.ts b/apps/api-documenter/src/plugin/IApiDocumenterPluginManifest.ts index 501f4f65a2f..c01e7c195e9 100644 --- a/apps/api-documenter/src/plugin/IApiDocumenterPluginManifest.ts +++ b/apps/api-documenter/src/plugin/IApiDocumenterPluginManifest.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 { MarkdownDocumenterFeature } from './MarkdownDocumenterFeature'; -import { PluginFeatureInitialization } from './PluginFeature'; +import type { MarkdownDocumenterFeature } from './MarkdownDocumenterFeature'; +import type { PluginFeatureInitialization } from './PluginFeature'; /** * Defines a "feature" that is provided by an API Documenter plugin. A feature is a user-defined module @@ -30,7 +30,7 @@ export interface IFeatureDefinition { /** * Your subclass that extends from the base class. */ - subclass: { new(initialization: PluginFeatureInitialization): MarkdownDocumenterFeature }; + subclass: { new (initialization: PluginFeatureInitialization): MarkdownDocumenterFeature }; } /** diff --git a/apps/api-documenter/src/plugin/MarkdownDocumenterAccessor.ts b/apps/api-documenter/src/plugin/MarkdownDocumenterAccessor.ts index d1f7062b568..8f6c176e094 100644 --- a/apps/api-documenter/src/plugin/MarkdownDocumenterAccessor.ts +++ b/apps/api-documenter/src/plugin/MarkdownDocumenterAccessor.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 { ApiItem } from '@microsoft/api-extractor-model'; +import type { ApiItem } from '@microsoft/api-extractor-model'; /** @internal */ export interface IMarkdownDocumenterAccessorImplementation { @@ -21,7 +21,7 @@ export class MarkdownDocumenterAccessor { private _implementation: IMarkdownDocumenterAccessorImplementation; /** @internal */ - public constructor (implementation: IMarkdownDocumenterAccessorImplementation) { + public constructor(implementation: IMarkdownDocumenterAccessorImplementation) { this._implementation = implementation; } diff --git a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts index 28149c4e9dd..0666b8097b3 100644 --- a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts +++ b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.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 { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; +import { TypeUuid } from '@rushstack/node-core-library'; + import { PluginFeature } from './PluginFeature'; -import { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; -import { MarkdownDocumenterAccessor } from './MarkdownDocumenterAccessor'; +import type { MarkdownDocumenterAccessor } from './MarkdownDocumenterAccessor'; /** * Context object for {@link MarkdownDocumenterFeature}. @@ -61,8 +63,9 @@ export interface IMarkdownDocumenterFeatureOnBeforeWritePageArgs { * Event arguments for MarkdownDocumenterFeature.onFinished() * @public */ -export interface IMarkdownDocumenterFeatureOnFinishedArgs { -} +export interface IMarkdownDocumenterFeatureOnFinishedArgs {} + +const uuidMarkdownDocumenterFeature: string = '34196154-9eb3-4de0-a8c8-7e9539dfe216'; /** * Inherit from this base class to implement an API Documenter plugin feature that customizes @@ -72,7 +75,7 @@ export interface IMarkdownDocumenterFeatureOnFinishedArgs { */ export class MarkdownDocumenterFeature extends PluginFeature { /** {@inheritdoc PluginFeature.context} */ - public context: MarkdownDocumenterFeatureContext; + public context!: MarkdownDocumenterFeatureContext; /** * This event occurs before each markdown file is written. It provides an opportunity to customize the @@ -90,4 +93,10 @@ export class MarkdownDocumenterFeature extends PluginFeature { public onFinished(eventArgs: IMarkdownDocumenterFeatureOnFinishedArgs): void { // (implemented by child class) } + + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidMarkdownDocumenterFeature); + } } + +TypeUuid.registerClass(MarkdownDocumenterFeature, uuidMarkdownDocumenterFeature); diff --git a/apps/api-documenter/src/plugin/PluginFeature.ts b/apps/api-documenter/src/plugin/PluginFeature.ts index 9609d34087c..adc1389989c 100644 --- a/apps/api-documenter/src/plugin/PluginFeature.ts +++ b/apps/api-documenter/src/plugin/PluginFeature.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 { TypeUuid } from '@rushstack/node-core-library'; + /** * This is an internal part of the plugin infrastructure. * @@ -11,7 +13,7 @@ */ export class PluginFeatureInitialization { /** @internal */ - public _context: PluginFeatureContext; + public _context!: PluginFeatureContext; /** @internal */ public constructor() { @@ -25,8 +27,9 @@ export class PluginFeatureInitialization { * * @public */ -export class PluginFeatureContext { -} +export class PluginFeatureContext {} + +const uuidPluginFeature: string = '56876472-7134-4812-819e-533de0ee10e6'; /** * The abstract base class for all API Documenter plugin features. @@ -56,4 +59,10 @@ export abstract class PluginFeature { public onInitialized(): void { // (implemented by child class) } + + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidPluginFeature); + } } + +TypeUuid.registerClass(PluginFeature, uuidPluginFeature); diff --git a/apps/api-documenter/src/plugin/PluginLoader.ts b/apps/api-documenter/src/plugin/PluginLoader.ts index 8fd6cbe1c1d..6d926f6ea66 100644 --- a/apps/api-documenter/src/plugin/PluginLoader.ts +++ b/apps/api-documenter/src/plugin/PluginLoader.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 resolve from 'resolve'; -import { IApiDocumenterPluginManifest, IFeatureDefinition } from './IApiDocumenterPluginManifest'; -import { MarkdownDocumenterFeature, MarkdownDocumenterFeatureContext } from './MarkdownDocumenterFeature'; +import type { IApiDocumenterPluginManifest, IFeatureDefinition } from './IApiDocumenterPluginManifest'; +import { + MarkdownDocumenterFeature, + type MarkdownDocumenterFeatureContext +} from './MarkdownDocumenterFeature'; import { PluginFeatureInitialization } from './PluginFeature'; -import { DocumenterConfig } from '../documenters/DocumenterConfig'; +import type { DocumenterConfig } from '../documenters/DocumenterConfig'; interface ILoadedPlugin { packageName: string; @@ -17,9 +21,12 @@ interface ILoadedPlugin { export class PluginLoader { public markdownDocumenterFeature: MarkdownDocumenterFeature | undefined; - public load(documenterConfig: DocumenterConfig, createContext: () => MarkdownDocumenterFeatureContext): void { + public load( + documenterConfig: DocumenterConfig, + createContext: () => MarkdownDocumenterFeatureContext + ): void { const configFileFolder: string = path.dirname(documenterConfig.configFilePath); - for (const configPlugin of (documenterConfig.configFile.plugins || [])) { + for (const configPlugin of documenterConfig.configFile.plugins || []) { try { // Look for the package name in the same place as the config file const resolvedEntryPointPath: string = resolve.sync(configPlugin.packageName, { @@ -27,25 +34,28 @@ export class PluginLoader { }); // Load the package - // eslint-disable-next-line @typescript-eslint/no-var-requires - const entryPoint: object | undefined = require(resolvedEntryPointPath); + const entryPoint: + | { apiDocumenterPluginManifest?: IApiDocumenterPluginManifest } + | undefined = require(resolvedEntryPointPath); if (!entryPoint) { throw new Error('Invalid entry point'); } - const manifest: IApiDocumenterPluginManifest - // eslint-disable-next-line dot-notation - = entryPoint['apiDocumenterPluginManifest'] as IApiDocumenterPluginManifest; - - if (!manifest) { - throw new Error(`The package is not an API documenter plugin;` - + ` the "apiDocumenterPluginManifest" export was not found`); + if (!entryPoint.apiDocumenterPluginManifest) { + throw new Error( + `The package is not an API documenter plugin;` + + ` the "apiDocumenterPluginManifest" export was not found` + ); } + const manifest: IApiDocumenterPluginManifest = entryPoint.apiDocumenterPluginManifest; + if (manifest.manifestVersion !== 1000) { - throw new Error(`The plugin is not compatible with this version of API Documenter;` - + ` unsupported manifestVersion`); + throw new Error( + `The plugin is not compatible with this version of API Documenter;` + + ` unsupported manifestVersion` + ); } const loadedPlugin: ILoadedPlugin = { @@ -53,7 +63,10 @@ export class PluginLoader { manifest }; - const featureDefinitionsByName: Map = new Map(); + const featureDefinitionsByName: Map = new Map< + string, + IFeatureDefinition + >(); for (const featureDefinition of manifest.features) { featureDefinitionsByName.set(featureDefinition.featureName, featureDefinition); } @@ -61,8 +74,9 @@ export class PluginLoader { for (const featureName of configPlugin.enabledFeatureNames) { const featureDefinition: IFeatureDefinition | undefined = featureDefinitionsByName.get(featureName); if (!featureDefinition) { - throw new Error(`The plugin ${loadedPlugin.packageName} does not have` - + ` a feature with name "${featureName}"`); + throw new Error( + `The plugin ${loadedPlugin.packageName} does not have a feature with name "${featureName}"` + ); } if (featureDefinition.kind === 'MarkdownDocumenterFeature') { @@ -70,14 +84,14 @@ export class PluginLoader { throw new Error('A MarkdownDocumenterFeature is already loaded'); } - const initialization: PluginFeatureInitialization = new PluginFeatureInitialization(); + const initialization: PluginFeatureInitialization = new PluginFeatureInitialization(); initialization._context = createContext(); let markdownDocumenterFeature: MarkdownDocumenterFeature | undefined = undefined; try { markdownDocumenterFeature = new featureDefinition.subclass(initialization); } catch (e) { - throw new Error(`Failed to construct feature subclass:\n` + e.toString()); + throw new Error(`Failed to construct feature subclass:\n` + (e as Error).toString()); } if (!(markdownDocumenterFeature instanceof MarkdownDocumenterFeature)) { throw new Error('The constructed subclass was not an instance of MarkdownDocumenterFeature'); @@ -86,7 +100,7 @@ export class PluginLoader { try { markdownDocumenterFeature.onInitialized(); } catch (e) { - throw new Error('Error occurred during the onInitialized() event: ' + e.toString()); + throw new Error('Error occurred during the onInitialized() event: ' + (e as Error).toString()); } this.markdownDocumenterFeature = markdownDocumenterFeature; @@ -95,9 +109,8 @@ export class PluginLoader { } } } catch (e) { - throw new Error(`Error loading plugin ${configPlugin.packageName}: ` + e.message); + throw new Error(`Error loading plugin ${configPlugin.packageName}: ` + (e as Error).message); } } } - } diff --git a/apps/api-documenter/src/schemas/api-documenter-template.json b/apps/api-documenter/src/schemas/api-documenter-template.json index ec893c904c6..cab40e42c74 100644 --- a/apps/api-documenter/src/schemas/api-documenter-template.json +++ b/apps/api-documenter/src/schemas/api-documenter-template.json @@ -28,7 +28,7 @@ * This setting currently only affects the 'docfx' output target. It is equivalent to the `--new-docfx-namespaces` * command-line parameter. */ - // "newDocfxNamespaces": false, + // "newDocfxNamespaces": false, /** * Describes plugin packages to be loaded, and which features to enable. @@ -58,7 +58,6 @@ // ] // } // ], - /** * Optional category name that is recommended to include in the `tocConfig`, * along with one of the filters: `filterByApiItemName` or `filterByInlineTag`. @@ -68,7 +67,6 @@ * DEFAULT VALUE: (none) */ // "catchAllCategory": "References", - /** * When loading more than one api.json files that might include the same API items, * toggle either to show duplicates or not. @@ -76,7 +74,6 @@ * DEFAULT VALUE: false */ // "noDuplicateEntries": true, - /** * Toggle either sorting of the API items should be made based on category name presence * in the API item's name. @@ -84,7 +81,6 @@ * DEFAULT VALUE: false */ // "filterByApiItemName": false, - /** * Filter that can be used to sort the API items according to an inline custom tag * that is present on them. @@ -93,4 +89,11 @@ */ // "filterByInlineTag": "@docCategory" } + + /** + * Specifies whether inherited members should also be shown on an API item's page. + * + * DEFAULT VALUE: false + */ + // "showInheritedMembers": false } diff --git a/apps/api-documenter/src/schemas/api-documenter.schema.json b/apps/api-documenter/src/schemas/api-documenter.schema.json index e8ccd2d477d..a61c9894a8f 100644 --- a/apps/api-documenter/src/schemas/api-documenter.schema.json +++ b/apps/api-documenter/src/schemas/api-documenter.schema.json @@ -11,10 +11,7 @@ "outputTarget": { "description": "Specifies what type of documentation will be generated", "type": "string", - "enum": [ - "docfx", - "markdown" - ] + "enum": ["docfx", "markdown"] }, "newlineKind": { @@ -38,6 +35,11 @@ "description": "Configures how the table of contents is generated.", "type": "object", "additionalProperties": true + }, + + "showInheritedMembers": { + "description": "Specifies whether inherited members should also be shown on an API item's page.", + "type": "boolean" } }, diff --git a/apps/api-documenter/src/start.ts b/apps/api-documenter/src/start.ts index 8b2b17ad884..e6266aa99fa 100644 --- a/apps/api-documenter/src/start.ts +++ b/apps/api-documenter/src/start.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 os from 'os'; -import * as colors from 'colors'; +import * as os from 'node:os'; import { PackageJsonLookup } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { ApiDocumenterCommandLine } from './cli/ApiDocumenterCommandLine'; const myPackageVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version; -console.log(os.EOL + colors.bold(`api-documenter ${myPackageVersion} ` - + colors.cyan(' - https://api-extractor.com/') + os.EOL)); +console.log( + os.EOL + + Colorize.bold( + `api-documenter ${myPackageVersion} ` + Colorize.cyan(' - https://api-extractor.com/') + os.EOL + ) +); const parser: ApiDocumenterCommandLine = new ApiDocumenterCommandLine(); -parser.execute().catch(console.error); // CommandLineParser.execute() should never reject the promise +parser.executeAsync().catch(console.error); // CommandLineParser.executeAsync() should never reject the promise diff --git a/apps/api-documenter/src/utils/IndentedWriter.ts b/apps/api-documenter/src/utils/IndentedWriter.ts index 5c37ea55624..d751ac1682e 100644 --- a/apps/api-documenter/src/utils/IndentedWriter.ts +++ b/apps/api-documenter/src/utils/IndentedWriter.ts @@ -1,35 +1,35 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { StringBuilder, IStringBuilder } from '@rushstack/node-core-library'; +import { StringBuilder, type IStringBuilder } from '@rushstack/node-core-library'; /** - * A utility for writing indented text. - * - * @remarks - * - * Note that the indentation is inserted at the last possible opportunity. - * For example, this code... - * - * ```ts - * writer.write('begin\n'); - * writer.increaseIndent(); - * writer.write('one\ntwo\n'); - * writer.decreaseIndent(); - * writer.increaseIndent(); - * writer.decreaseIndent(); - * writer.write('end'); - * ``` - * - * ...would produce this output: - * - * ``` - * begin - * one - * two - * end - * ``` - */ + * A utility for writing indented text. + * + * @remarks + * + * Note that the indentation is inserted at the last possible opportunity. + * For example, this code... + * + * ```ts + * writer.write('begin\n'); + * writer.increaseIndent(); + * writer.write('one\ntwo\n'); + * writer.decreaseIndent(); + * writer.increaseIndent(); + * writer.decreaseIndent(); + * writer.write('end'); + * ``` + * + * ...would produce this output: + * + * ``` + * begin + * one + * two + * end + * ``` + */ export class IndentedWriter { /** * The text characters used to create one level of indentation. @@ -46,6 +46,9 @@ export class IndentedWriter { private readonly _indentStack: string[]; private _indentText: string; + private _beforeStack: string[]; + private _isWritingBeforeStack: boolean; + public constructor(builder?: IStringBuilder) { this._builder = builder === undefined ? new StringBuilder() : builder; @@ -55,6 +58,9 @@ export class IndentedWriter { this._indentStack = []; this._indentText = ''; + + this._beforeStack = []; + this._isWritingBeforeStack = false; } /** @@ -149,6 +155,30 @@ export class IndentedWriter { return ''; } + /** + * Writes `before` and `after` messages if and only if `mayWrite` writes anything. + * + * If `mayWrite` writes "CONTENT", this method will write "CONTENT". + * If `mayWrite` writes nothing, this method will write nothing. + */ + public writeTentative(before: string, after: string, mayWrite: () => void): void { + this._beforeStack.push(before); + + // If this function writes anything, then _all_ messages in the "before stack" will also be + // written. This means that the stack will be empty (as when we write a message from the stack, + // we remove it from the stack). + mayWrite(); + + // If the stack is not empty, it means that `mayWrite` didn't write anything. Pop the last- + // added message from the stack, we'll never write it. Otherwise, if the stack is empty, then + // write the "after" message. + if (this._beforeStack.length > 0) { + this._beforeStack.pop(); + } else { + this.write(after); + } + } + /** * Writes some text to the internal string buffer, applying indentation according * to the current indentation level. If the string contains multiple newlines, @@ -159,6 +189,10 @@ export class IndentedWriter { return; } + if (!this._isWritingBeforeStack) { + this._writeBeforeStack(); + } + // If there are no newline characters, then append the string verbatim if (!/[\r\n]/.test(message)) { this._writeLinePart(message); @@ -186,7 +220,10 @@ export class IndentedWriter { public writeLine(message: string = ''): void { if (message.length > 0) { this.write(message); + } else if (!this._isWritingBeforeStack) { + this._writeBeforeStack(); } + this._writeNewLine(); } @@ -218,6 +255,21 @@ export class IndentedWriter { this._builder.append(s); } + /** + * Writes all messages in our before stack, processing them in FIFO order. This stack is + * populated by the `writeTentative` method. + */ + private _writeBeforeStack(): void { + this._isWritingBeforeStack = true; + + for (const message of this._beforeStack) { + this.write(message); + } + + this._isWritingBeforeStack = false; + this._beforeStack = []; + } + private _updateIndentText(): void { this._indentText = this._indentStack.join(''); } diff --git a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts new file mode 100644 index 00000000000..8d12f9df7f8 --- /dev/null +++ b/apps/api-documenter/src/utils/ToSdpConvertHelper.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. + +import path from 'node:path'; + +import yaml = require('js-yaml'); + +import { FileSystem, Encoding, NewlineKind } from '@rushstack/node-core-library'; + +import type { + IYamlItem, + IYamlApiFile, + IYamlSyntax, + IYamlReferenceSpec, + IYamlReference +} from '../yaml/IYamlApiFile'; +import type { + PackageYamlModel, + EnumYamlModel, + TypeAliasYamlModel, + TypeYamlModel, + FieldYamlModel, + FunctionYamlModel, + CommonYamlModel +} from '../yaml/ISDPYamlFile'; + +export function convertUDPYamlToSDP(folderPath: string): void { + convert(folderPath, folderPath); +} + +function convert(inputPath: string, outputPath: string): void { + console.log(); + if (!FileSystem.exists(inputPath)) { + console.error(`input path: ${inputPath} is not exist`); + return; + } + + FileSystem.readFolderItemNames(inputPath).forEach((name) => { + const fpath: string = path.join(inputPath, name); + if (FileSystem.getStatistics(fpath).isFile()) { + // only convert yaml + if (!name.endsWith('.yml')) { + return; + } + // parse file + const yamlContent: string = FileSystem.readFile(fpath, { encoding: Encoding.Utf8 }); + // only convert universalreference yaml + const isLegacyYaml: boolean = yamlContent.startsWith('### YamlMime:UniversalReference'); + if (!isLegacyYaml) { + return; + } + + console.log(`convert file ${fpath} from udp to sdp`); + + 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.dump(result.model, { + lineWidth: 120 + })}`; + FileSystem.writeFile(`${outputPath}/${name}`, stringified, { + convertLineEndings: NewlineKind.CrLf, + ensureFolderExists: true + }); + } else { + console.log('not target file ', fpath); + } + } else { + // read contents + convert(fpath, path.join(outputPath, name)); + } + }); +} + +function convertToPackageSDP(transfomredClass: IYamlApiFile): PackageYamlModel { + const element: IYamlItem = transfomredClass.items[0]; + const packageModel: PackageYamlModel = { + uid: element.uid, + name: element.name!, + type: 'package' + }; + if (element.summary) { + packageModel.summary = element.summary; + } else { + packageModel.summary = ''; + } + + // search in children + if (element.children) { + element.children.forEach((child) => { + if (child.endsWith(':class')) { + assignPackageModelFields(packageModel, 'classes', child); + } else if (child.endsWith(':interface')) { + assignPackageModelFields(packageModel, 'interfaces', child); + } else if (child.endsWith(':enum')) { + assignPackageModelFields(packageModel, 'enums', child); + } else if (child.endsWith(':type')) { + assignPackageModelFields(packageModel, 'typeAliases', child); + } else { + // console.log("other type: ", child) + } + }); + } + + for (let i: number = 1; i < transfomredClass.items.length; i++) { + const ele: IYamlItem = transfomredClass.items[i]; + switch (ele.type) { + case 'typealias': + // need generate typeAlias file for this + break; + case 'function': + if (!packageModel.functions) { + packageModel.functions = []; + } + packageModel.functions.push(convertToFunctionSDP(ele, element.uid, transfomredClass)); + break; + default: + // console.log(transfomredClass.items[0].name) + console.log('[warning] not applied type(package): ', ele.type); + } + } + + return packageModel; +} + +function assignPackageModelFields( + packageModel: PackageYamlModel, + name: 'classes' | 'interfaces' | 'enums' | 'typeAliases', + uid: string +): void { + if (!packageModel[name]) { + packageModel[name] = []; + } + packageModel[name]!.push(uid); +} + +function convertToSDP(transfomredClass: IYamlApiFile): { model: CommonYamlModel; type: string } | undefined { + const element: IYamlItem = transfomredClass.items[0]; + switch (element.type) { + case 'class': + case 'interface': + return { + model: convertToTypeSDP(transfomredClass, element.type === 'class'), + type: 'Type' + }; + case 'enum': + if (transfomredClass.items.length < 2) { + console.log(`[warning] enum ${element.uid}/${element.name} does not have fields`); + return undefined; + } + return { model: convertToEnumSDP(transfomredClass), type: 'Enum' }; + case 'typealias': + return { model: convertToTypeAliasSDP(element, transfomredClass), type: 'TypeAlias' }; + case 'package': + return { + model: convertToPackageSDP(transfomredClass), + type: 'Package' + }; + default: + console.log('not applied type: ', element.type); + return undefined; + } +} + +function convertToEnumSDP(transfomredClass: IYamlApiFile): EnumYamlModel { + const element: IYamlItem = transfomredClass.items[0]; + const fields: FieldYamlModel[] = []; + for (let i: number = 1; i < transfomredClass.items.length; i++) { + const ele: IYamlItem = transfomredClass.items[i]; + const field: FieldYamlModel = { + name: ele.name!, + uid: ele.uid, + package: element.package! + }; + + if (ele.summary) { + field.summary = ele.summary; + } else { + field.summary = ''; + } + + if (ele.numericValue) { + field.value = ele.numericValue; + } + fields.push(field); + } + + const result: EnumYamlModel = { + ...convertCommonYamlModel(element, element.package!, transfomredClass), + fields: fields + }; + return result; +} + +function convertToTypeAliasSDP(element: IYamlItem, transfomredClass: IYamlApiFile): TypeAliasYamlModel { + const result: TypeAliasYamlModel = { + ...convertCommonYamlModel(element, element.package!, transfomredClass) + } as TypeAliasYamlModel; + + if (element.syntax) { + result.syntax = element.syntax.content!; + } + return result; +} + +function convertToTypeSDP(transfomredClass: IYamlApiFile, isClass: boolean): TypeYamlModel { + const element: IYamlItem = transfomredClass.items[0]; + const constructors: CommonYamlModel[] = []; + const properties: CommonYamlModel[] = []; + const methods: CommonYamlModel[] = []; + const events: CommonYamlModel[] = []; + for (let i: number = 1; i < transfomredClass.items.length; i++) { + const ele: IYamlItem = transfomredClass.items[i]; + const item: CommonYamlModel = convertCommonYamlModel(ele, element.package!, transfomredClass); + if (ele.type === 'constructor') { + // interface does not need this field + if (isClass) { + constructors.push(item); + } + } else if (ele.type === 'property') { + properties.push(item); + } else if (ele.type === 'method') { + methods.push(item); + } else if (ele.type === 'event') { + events.push(item); + } else { + console.log(`[warning] ${ele.uid}#${ele.name} is not applied sub type ${ele.type} for type yaml`); + } + } + const result: TypeYamlModel = { + ...convertCommonYamlModel(element, element.package!, transfomredClass), + type: isClass ? 'class' : 'interface' + }; + delete result.syntax; + + if (constructors.length > 0) { + result.constructors = constructors; + } + + if (properties.length > 0) { + result.properties = properties; + } + + if (methods.length > 0) { + result.methods = methods; + } + + if (events.length > 0) { + result.events = events; + } + + if (element.extends && element.extends.length > 0) { + result.extends = convertSelfTypeToXref(element.extends[0] as string, transfomredClass); + } + return result; +} + +function convertToFunctionSDP( + element: IYamlItem, + packageName: string, + transfomredClass: IYamlApiFile +): FunctionYamlModel { + const model: CommonYamlModel = convertCommonYamlModel(element, packageName, transfomredClass); + // don't need these fields + delete model.fullName; + return model; +} + +function convertCommonYamlModel( + element: IYamlItem, + packageName: string, + transfomredClass: IYamlApiFile +): CommonYamlModel { + const result: CommonYamlModel = { + name: element.name!, + uid: element.uid, + package: packageName + }; + + if (element.fullName) { + result.fullName = element.fullName; + } + + if (element.summary) { + result.summary = element.summary; + } else { + result.summary = ''; + } + + // because mustache meet same variable in different level + // such as: { "pre": true, "list": [{}]} + // if item in list wants to use pre but the pre is not assigned, it will use outer pre field. + // so, there need to set below variable explict + + if (element.remarks) { + result.remarks = element.remarks; + } else { + result.remarks = ''; + } + + if (element.example) { + result.example = element.example; + } else { + result.example = []; + } + + result.isPreview = element.isPreview; + if (!result.isPreview) { + result.isPreview = false; + } + + if (element.deprecated) { + result.isDeprecated = true; + result.customDeprecatedMessage = element.deprecated.content; + } else { + result.isDeprecated = false; + } + + if (element.syntax) { + result.syntax = {}; + + const syntax: IYamlSyntax = element.syntax; + result.syntax.content = syntax.content; + if (syntax.parameters && syntax.parameters.length > 0) { + syntax.parameters?.forEach((it) => { + delete it.optional; + delete it.defaultValue; + }); + result.syntax.parameters = syntax.parameters.map((it) => { + return { + ...it, + id: it.id!, + type: convertSelfTypeToXref(escapeMarkdown(it.type![0] as string), transfomredClass) + }; + }); + } + + if (syntax.return) { + result.syntax.return = { + ...syntax.return, + type: convertSelfTypeToXref(escapeMarkdown(syntax.return.type![0] as string), transfomredClass) + }; + } + } + + return result; +} + +function escapeMarkdown(name: string): string { + // eg: [key: string]: string + const markdownLinkRegEx: RegExp = /^\s*(\[.+\]):(.+)/g; + return name.replace(markdownLinkRegEx, `$1\\:$2`); +} + +function convertSelfTypeToXref(name: string, transfomredClass: IYamlApiFile): string { + let result: string = name; + + // if complex type, need to get real type from references + if (result.endsWith(':complex')) { + const specs: IYamlReferenceSpec[] | undefined = transfomredClass.references?.find((item) => { + return item.uid === name; + })?.['spec.typeScript']; + + if (specs && specs.length > 0) { + result = ''; + for (const spec of specs) { + // start with ! will be node base type + if (spec.uid && !spec.uid.startsWith('!')) { + result += spec.uid; + } else { + result += spec.name; + } + } + } + } else if (result.startsWith('!')) { + // uid: '!Object:interface' + // name: Object + // start with !, not complex type, use reference name directly + const ref: IYamlReference | undefined = transfomredClass.references?.find((item) => { + return item.uid === name; + }); + if (ref && ref.name) { + result = ref.name; + } + } + // parse < > + result = result.replace(//g, '>'); + const uidRegEx: RegExp = /(@?[\w\d\-/!~\.]+\:[\w\d\-\(/]+)/g; + + return result.replace(uidRegEx, ``); +} diff --git a/apps/api-documenter/src/utils/Utilities.ts b/apps/api-documenter/src/utils/Utilities.ts index aff2fe1c24d..2c9bc2556a6 100644 --- a/apps/api-documenter/src/utils/Utilities.ts +++ b/apps/api-documenter/src/utils/Utilities.ts @@ -1,19 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - ApiParameterListMixin, - ApiItem -} from '@microsoft/api-extractor-model'; +import { ApiParameterListMixin, type ApiItem } from '@microsoft/api-extractor-model'; export class Utilities { - private static readonly _badFilenameCharsRegExp: RegExp = /[^a-z0-9_\-\.]/ig; + private static readonly _badFilenameCharsRegExp: RegExp = /[^a-z0-9_\-\.]/gi; /** * Generates a concise signature for a function. Example: "getArea(width, height)" */ public static getConciseSignature(apiItem: ApiItem): string { if (ApiParameterListMixin.isBaseClassOf(apiItem)) { - return apiItem.displayName + '(' + apiItem.parameters.map(x => x.name).join(', ') + ')'; + return apiItem.displayName + '(' + apiItem.parameters.map((x) => x.name).join(', ') + ')'; } return apiItem.displayName; } diff --git a/apps/api-documenter/src/utils/test/IndentedWriter.test.ts b/apps/api-documenter/src/utils/test/IndentedWriter.test.ts index 8ca09139a4b..f6ac6e7a85a 100644 --- a/apps/api-documenter/src/utils/test/IndentedWriter.test.ts +++ b/apps/api-documenter/src/utils/test/IndentedWriter.test.ts @@ -21,15 +21,15 @@ test('02 Indent something', () => { indentedWriter.write('a'); indentedWriter.write('b'); indentedWriter.increaseIndent(); - indentedWriter.writeLine('c'); - indentedWriter.writeLine('d'); + indentedWriter.writeLine('c'); + indentedWriter.writeLine('d'); indentedWriter.decreaseIndent(); indentedWriter.writeLine('e'); indentedWriter.increaseIndent('>>> '); - indentedWriter.writeLine(); - indentedWriter.writeLine(); - indentedWriter.writeLine('g'); + indentedWriter.writeLine(); + indentedWriter.writeLine(); + indentedWriter.writeLine('g'); indentedWriter.decreaseIndent(); expect(indentedWriter.toString()).toMatchSnapshot(); diff --git a/apps/api-documenter/src/yaml/ISDPYamlFile.ts b/apps/api-documenter/src/yaml/ISDPYamlFile.ts new file mode 100644 index 00000000000..413d73e8d6b --- /dev/null +++ b/apps/api-documenter/src/yaml/ISDPYamlFile.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. + +interface IBaseYamlModel { + uid: string; + name: string; + package?: string; + summary?: string; +} + +export type CommonYamlModel = IBaseYamlModel & { + syntax?: ISyntax; + fullName?: string; + isPreview?: boolean; + isDeprecated?: boolean; + remarks?: string; + example?: string[]; + customDeprecatedMessage?: string; +}; + +export type PackageYamlModel = CommonYamlModel & { + classes?: Array; + interfaces?: Array; + enums?: Array; + typeAliases?: Array; + properties?: Array; + type?: 'package' | 'module'; + functions?: Array; +}; + +export type FunctionYamlModel = CommonYamlModel; + +export type TypeAliasYamlModel = CommonYamlModel & { + syntax: string; +}; + +export type TypeYamlModel = CommonYamlModel & { + constructors?: Array; + properties?: Array; + methods?: Array; + events?: Array; + type: 'class' | 'interface'; + extends?: IType | string; +}; + +export type EnumYamlModel = CommonYamlModel & { + fields: Array; +}; + +export type FieldYamlModel = IBaseYamlModel & { + numericValue?: number; + value?: string; +}; + +export interface ISyntax { + parameters?: Array; + content?: string; + return?: IReturn; +} + +export interface IYamlParameter { + id: string; + type: IType | string; + description?: string; +} + +interface IReturn { + type: IType | string; + description?: string; +} + +export interface IType { + typeName?: string; + typeId?: number; + reflectedType?: IReflectedType; + genericType?: IGenericType; + intersectionType?: IIntersectionType; + unionType?: IUnionType; + arrayType?: IType | string; +} + +export interface IUnionType { + types: Types; +} + +export interface IIntersectionType { + types: Types; +} + +export interface IGenericType { + outter: IType | string; + inner: Types; +} + +export interface IReflectedType { + key: IType | string; + value: IType | string; +} + +export interface IException { + type: string; + description: string; +} + +type Types = IType[] | string[]; diff --git a/apps/api-documenter/src/yaml/IYamlApiFile.ts b/apps/api-documenter/src/yaml/IYamlApiFile.ts index 66fcb5d8129..58048a50d41 100644 --- a/apps/api-documenter/src/yaml/IYamlApiFile.ts +++ b/apps/api-documenter/src/yaml/IYamlApiFile.ts @@ -188,7 +188,7 @@ export interface IYamlItem { * * NOTE: Corresponds to `ItemViewModel.Examples` in DocFX. */ - examples?: string[]; + example?: string[]; /** * The syntax for this item. This value itself cannot vary by development language, but @@ -345,15 +345,12 @@ export type YamlTypeId = | 'event' | 'typealias' | 'variable' - | 'namespace' - ; + | 'namespace'; /** * Development languages supported by the Universal Reference file format, as defined by typescript.schema.json. */ -export type YamlDevLangs = - | 'typeScript' - ; +export type YamlDevLangs = 'typeScript'; /** * Part of the IYamlApiFile structure. Documents the source file where an IYamlItem is defined. diff --git a/apps/api-documenter/src/yaml/typescript.schema.json b/apps/api-documenter/src/yaml/typescript.schema.json index 83e55daf678..cc1ad42ccf0 100644 --- a/apps/api-documenter/src/yaml/typescript.schema.json +++ b/apps/api-documenter/src/yaml/typescript.schema.json @@ -1,633 +1,643 @@ { - "title": "Universal Reference YAML Schema for DocFX", - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "additionalProperties": false, - "required": [ - "items" - ], - "properties": { - "items": { - "description": "This collection represents the main item (the first element) and it's possible children items.", - "type": "array", - "items": { - "$ref": "#/definitions/item" - }, - "minItems": 1, - "uniqueItems": true - }, - "references": { - "description": "References to other items.", - "type": "array", - "items": { - "$ref": "#/definitions/reference" - }, - "minItems": 1, - "uniqueItems": true - }, - "shouldSkipMarkup": { - "type": "boolean" - } - }, - "definitions":{ - "item": { - "description": "Represents basic API elements such as classes, interfaces, members, etc.", - "type": "object", - "additionalProperties": false, - "required": [ - "uid" - ], - "properties": { - "uid": { - "description": "A value that uniquely identifies this item among all other documentation elements. (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2)", - "type": "string" - }, - "commentId": { - "description": "A Roslyn comment ID.", - "type": "string" - }, - "id": { - "description": "An ID for the item.", - "type": "string" - }, - "parent": { - "description": "A UID reference to the parent of this item.", - "type": "string" - }, - "children": { - "description": "A list of UID references to the children of this item.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "href": { - "description": "A link URL for the item.", - "type": "string" - }, - "langs": { - "description": "The development languages supported by this item", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "name": { - "description": "The local name of the item (ex: AnonymousObject). This name should generally not be namespace qualified and should not include parent type information.", - "type": "string" - }, - "nameWithType": { - "description": "The name of the item including its parent type (ex: Colors.Red). This name should generally not be namespace qualified.", - "type": "string" - }, - "fullName": { - "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject).", - "type": "string" - }, - "type": { - "description": "The type of source element this item represents", - "enum": [ "class", "constructor", "enum", "field", "function", "interface", "method", "package", "property", "event", "typealias", "variable", "namespace" ] - }, - "source": { - "description": "The source details for the item", - "$ref": "#/definitions/source" - }, - "documentation": { - "description": "Overrides the source details for the item.", - "$ref": "#/definitions/source" - }, - "assemblies": { - "description": "The names of managed assemblies that contain this item.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "namespace": { - "description": "The UID of the namespace that contains this item.", - "type": "string" - }, - "summary": { - "description": "The summary for the item. Markdown is permitted", - "type": "string" - }, - "remarks": { - "description": "The remarks for the item. Markdown is permitted", - "type": "string" - }, - "examples": { - "description": "The examples for the item. Markdown is permitted", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "syntax": { - "description": "The syntax for this item.", - "$ref": "#/definitions/syntax" - }, - "overridden": { - "description": "The UID of the member this item overrides.", - "type": "string" - }, - "overload": { - "description": "The UID of the member this item overloads.", - "type": "string" - }, - "exceptions": { - "description": "The exceptions thrown by this item.", - "type": "array", - "items": { - "$ref": "#/definitions/exception" - }, - "minItems": 1, - "uniqueItems": true - }, - "seealso": { - "description": "Links to additional content related to this item.", - "type": "array", - "items": { - "$ref": "#/definitions/link" - }, - "minItems": 1, - "uniqueItems": true - }, - "seealsoContent": { - "description": "Additional information about other content related to this item. Markdown is permitted.", - "type": "string" - }, - "see": { - "description": "Links to additional content related to this item.", - "type": "array", - "items": { - "$ref": "#/definitions/link" - }, - "minItems": 1, - "uniqueItems": true - }, - "inheritance": { - "description": "The inheritance tree for this item. Multiple inherited is permitted if the underlying language supports it.", - "type": "array", - "items": { - "$ref": "#/definitions/inheritance" - }, - "minItems": 1, - "uniqueItems": true - }, - "derivedClasses": { - "description": "A list of UIDs for items derived from this item.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "implements": { - "description": "A list of UIDs for the items this item implements.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "inheritedMembers": { - "description": "A list of UIDs for the members this item inherits.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "extensionMethods": { - "description": "A list of UIDs for extension methods for this item.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "conceptual": { - "description": "The conceptual text for this item.", - "type": "string" - }, - "platform": { - "description": "The platforms supported by this item.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, + "title": "Universal Reference YAML Schema for DocFX", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "additionalProperties": false, + "required": ["items"], + "properties": { + "items": { + "description": "This collection represents the main item (the first element) and it's possible children items.", + "type": "array", + "items": { + "$ref": "#/definitions/item" + }, + "minItems": 1, + "uniqueItems": true + }, + "references": { + "description": "References to other items.", + "type": "array", + "items": { + "$ref": "#/definitions/reference" + }, + "minItems": 1, + "uniqueItems": true + }, + "shouldSkipMarkup": { + "type": "boolean" + } + }, + "definitions": { + "item": { + "description": "Represents basic API elements such as classes, interfaces, members, etc.", + "type": "object", + "additionalProperties": false, + "required": ["uid"], + "properties": { + "uid": { + "description": "A value that uniquely identifies this item among all other documentation elements. (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject`2)", + "type": "string" + }, + "commentId": { + "description": "A Roslyn comment ID.", + "type": "string" + }, + "id": { + "description": "An ID for the item.", + "type": "string" + }, + "parent": { + "description": "A UID reference to the parent of this item.", + "type": "string" + }, + "children": { + "description": "A list of UID references to the children of this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "href": { + "description": "A link URL for the item.", + "type": "string" + }, + "langs": { + "description": "The development languages supported by this item", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "name": { + "description": "The local name of the item (ex: AnonymousObject). This name should generally not be namespace qualified and should not include parent type information.", + "type": "string" + }, + "nameWithType": { + "description": "The name of the item including its parent type (ex: Colors.Red). This name should generally not be namespace qualified.", + "type": "string" + }, + "fullName": { + "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject).", + "type": "string" + }, + "type": { + "description": "The type of source element this item represents", + "enum": [ + "class", + "constructor", + "enum", + "field", + "function", + "interface", + "method", + "package", + "property", + "event", + "typealias", + "variable", + "namespace" + ] + }, + "source": { + "description": "The source details for the item", + "$ref": "#/definitions/source" + }, + "documentation": { + "description": "Overrides the source details for the item.", + "$ref": "#/definitions/source" + }, + "assemblies": { + "description": "The names of managed assemblies that contain this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "namespace": { + "description": "The UID of the namespace that contains this item.", + "type": "string" + }, + "summary": { + "description": "The summary for the item. Markdown is permitted", + "type": "string" + }, + "remarks": { + "description": "The remarks for the item. Markdown is permitted", + "type": "string" + }, + "example": { + "description": "The examples for the item. Markdown is permitted", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "syntax": { + "description": "The syntax for this item.", + "$ref": "#/definitions/syntax" + }, + "overridden": { + "description": "The UID of the member this item overrides.", + "type": "string" + }, + "overload": { + "description": "The UID of the member this item overloads.", + "type": "string" + }, + "exceptions": { + "description": "The exceptions thrown by this item.", + "type": "array", + "items": { + "$ref": "#/definitions/exception" + }, + "minItems": 1, + "uniqueItems": true + }, + "seealso": { + "description": "Links to additional content related to this item.", + "type": "array", + "items": { + "$ref": "#/definitions/link" + }, + "minItems": 1, + "uniqueItems": true + }, + "seealsoContent": { + "description": "Additional information about other content related to this item. Markdown is permitted.", + "type": "string" + }, + "see": { + "description": "Links to additional content related to this item.", + "type": "array", + "items": { + "$ref": "#/definitions/link" + }, + "minItems": 1, + "uniqueItems": true + }, + "inheritance": { + "description": "The inheritance tree for this item. Multiple inherited is permitted if the underlying language supports it.", + "type": "array", + "items": { + "$ref": "#/definitions/inheritance" + }, + "minItems": 1, + "uniqueItems": true + }, + "derivedClasses": { + "description": "A list of UIDs for items derived from this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "implements": { + "description": "A list of UIDs for the items this item implements.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "inheritedMembers": { + "description": "A list of UIDs for the members this item inherits.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "extensionMethods": { + "description": "A list of UIDs for extension methods for this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "conceptual": { + "description": "The conceptual text for this item.", + "type": "string" + }, + "platform": { + "description": "The platforms supported by this item.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, - "deprecated": { - "$ref": "#/definitions/deprecated" - }, - "extends": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "isPreview": { - "type": "boolean" - }, - "numericValue": { - "type": "string", - "description": "Used for Enum fields" - }, - "package": { - "type": "string" - } - }, - "patternProperties": { - "^parent\\.": { - "description": "A UID reference to the parent of this item for a specific development language.", - "type": "string" - }, - "^children\\.": { - "description": "A list of UID references to the children of this item for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^name\\.": { - "description": "The local name of the item (ex: AnonymousObject) for a specific development language. This name should generally not be namespace qualified and should not include parent type information.", - "type": "string" - }, - "^nameWithType\\.": { - "description": "The name of the item including its parent type (ex: Colors.Red) for a specific development language. This name should generally not be namespace qualified.", - "type": "string" - }, - "^fullName\\.": { - "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject) for a specific development language.", - "type": "string" - }, - "^source\\.": { - "description": "The source details for the item for a specific development language.", - "$ref": "#/definitions/source" - }, - "^assemblies\\.": { - "description": "The names of managed assemblies that contain this item for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^namespace\\.": { - "description": "The UID of the namespace that contains this item for a specific development language.", - "type": "string" - }, - "^overridden\\.": { - "description": "The UID of the member this item overrides for a specific development language.", - "type": "string" - }, - "^overload\\.": { - "description": "The UID of the member this item overloads for a specific development language.", - "type": "string" - }, - "^exceptions\\.": { - "description": "The exceptions thrown by this item for a specific development language.", - "type": "array", - "items": { - "$ref": "#/definitions/exception" - }, - "minItems": 1, - "uniqueItems": true - }, - "^inheritance\\.": { - "description": "The inheritance tree for this item for a specific development language. Multiple inherited is permitted if the underlying language supports it.", - "type": "array", - "items": { - "$ref": "#/definitions/inheritance" - }, - "minItems": 1, - "uniqueItems": true - }, - "^derivedClasses\\.": { - "description": "A list of UIDs for items derived from this item for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^implements\\.": { - "description": "A list of UIDs for the items this item implements for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^inheritedMembers\\.": { - "description": "A list of UIDs for the members this item inherits for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^extensionMethods\\.": { - "description": "A list of UIDs for extension methods for this item for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "^platform\\.": { - "description": "The platforms supported by this item for a specific development language.", - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - } - } - }, - "source": { - "type": "object", - "properties": { - "remote": { - "$ref": "#/definitions/remote" - }, - "basePath": { - "type": "string" - }, - "id": { - "type": "string" - }, - "href": { - "type": "string" - }, - "path": { - "type": "string" - }, - "startLine": { - "type": "integer" - }, - "endLine": { - "type": "integer" - }, - "content": { - "type": "string" - }, - "isExternal": { - "type": "boolean" - } - } - }, - "remote": { - "type": "object", - "additionalProperties": false, - "properties": { - "path": { - "type": "string" - }, - "branch": { - "type": "string" - }, - "repo": { - "type": "string" - } - } - }, - "syntax": { - "type": "object", - "additionalProperties": false, - "properties": { - "content": { - "type": "string" - }, - "parameters": { - "type": "array", - "items": { - "$ref": "#/definitions/parameter" - }, - "minItems": 1, - "uniqueItems": true - }, - "typeParameters": { - "type": "array", - "items": { - "$ref": "#/definitions/parameter" - }, - "minItems": 1, - "uniqueItems": true - }, - "return": { - "$ref": "#/definitions/return" - } - }, - "patternProperties": { - "^content\\.": { - "type": "string" - }, - "^return\\.": { - "$ref": "#/definitions/return" - } - } - }, - "parameter": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "type": "string" - }, - "optional": { - "type": "boolean" - }, - "defaultValue": { - "type": "string" - } - } - }, - "return": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "type": "string" - } - } - }, - "exception": { - "type": "object", - "additionalProperties": false, - "properties": { - "type": { - "type": "string" - }, - "description": { - "type": "string" - } - } - }, - "link": { - "type": "object", - "additionalProperties": false, - "required": [ "linkType", "linkId" ], - "properties": { - "linkType": { - "enum": [ "CRef", "HRef" ] - }, - "linkId": { - "type": "string" - }, - "commentId": { - "type": "string" - }, - "altText": { - "type": "string" - } - } - }, - "inheritance": { - "type": "object", - "additionalProperties": false, - "required": [ "type" ], - "properties": { - "type": { - "type": "string" - }, - "inheritance": { - "type": "array", - "items": { - "$ref": "#/definitions/inheritance" - }, - "minItems": 1, - "uniqueItems": true - }, - "level": { - "type": "number" - } - } - }, - "reference": { - "type": "object", - "additionalProperties": false, - "properties": { - "uid": { - "type": "string" - }, - "commentId": { - "type": "string" - }, - "parent": { - "type": "string" - }, - "definition": { - "type": "string" - }, - "isExternal": { - "type": "boolean" - }, - "href": { - "type": "string" - }, - "name": { - "type": "string" - }, - "nameWithType": { - "type": "string" - }, - "fullName": { - "type": "string" - } - }, - "patternProperties": { - "^name\\.": { - "type": "string" - }, - "^nameWithType\\.": { - "type": "string" - }, - "^fullName\\.": { - "type": "string" - }, - "^spec\\.": { - "type": "array", - "items": { - "$ref": "#/definitions/spec" - } - } - } - }, - "spec": { - "type": "object", - "additionalProperties": false, - "properties": { - "uid": { - "type": "string" - }, - "name": { - "type": "string" - }, - "nameWithType": { - "type": "string" - }, - "fullName": { - "type": "string" - }, - "isExternal": { - "type": "boolean" - }, - "href": { - "type": "string" - } - } - }, + "deprecated": { + "$ref": "#/definitions/deprecated" + }, + "extends": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "isPreview": { + "type": "boolean" + }, + "numericValue": { + "type": "string", + "description": "Used for Enum fields" + }, + "package": { + "type": "string" + } + }, + "patternProperties": { + "^parent\\.": { + "description": "A UID reference to the parent of this item for a specific development language.", + "type": "string" + }, + "^children\\.": { + "description": "A list of UID references to the children of this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^name\\.": { + "description": "The local name of the item (ex: AnonymousObject) for a specific development language. This name should generally not be namespace qualified and should not include parent type information.", + "type": "string" + }, + "^nameWithType\\.": { + "description": "The name of the item including its parent type (ex: Colors.Red) for a specific development language. This name should generally not be namespace qualified.", + "type": "string" + }, + "^fullName\\.": { + "description": "The full-qualified name of the item (ex: Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject) for a specific development language.", + "type": "string" + }, + "^source\\.": { + "description": "The source details for the item for a specific development language.", + "$ref": "#/definitions/source" + }, + "^assemblies\\.": { + "description": "The names of managed assemblies that contain this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^namespace\\.": { + "description": "The UID of the namespace that contains this item for a specific development language.", + "type": "string" + }, + "^overridden\\.": { + "description": "The UID of the member this item overrides for a specific development language.", + "type": "string" + }, + "^overload\\.": { + "description": "The UID of the member this item overloads for a specific development language.", + "type": "string" + }, + "^exceptions\\.": { + "description": "The exceptions thrown by this item for a specific development language.", + "type": "array", + "items": { + "$ref": "#/definitions/exception" + }, + "minItems": 1, + "uniqueItems": true + }, + "^inheritance\\.": { + "description": "The inheritance tree for this item for a specific development language. Multiple inherited is permitted if the underlying language supports it.", + "type": "array", + "items": { + "$ref": "#/definitions/inheritance" + }, + "minItems": 1, + "uniqueItems": true + }, + "^derivedClasses\\.": { + "description": "A list of UIDs for items derived from this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^implements\\.": { + "description": "A list of UIDs for the items this item implements for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^inheritedMembers\\.": { + "description": "A list of UIDs for the members this item inherits for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^extensionMethods\\.": { + "description": "A list of UIDs for extension methods for this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "^platform\\.": { + "description": "The platforms supported by this item for a specific development language.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + } + }, + "source": { + "type": "object", + "properties": { + "remote": { + "$ref": "#/definitions/remote" + }, + "basePath": { + "type": "string" + }, + "id": { + "type": "string" + }, + "href": { + "type": "string" + }, + "path": { + "type": "string" + }, + "startLine": { + "type": "integer" + }, + "endLine": { + "type": "integer" + }, + "content": { + "type": "string" + }, + "isExternal": { + "type": "boolean" + } + } + }, + "remote": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + }, + "branch": { + "type": "string" + }, + "repo": { + "type": "string" + } + } + }, + "syntax": { + "type": "object", + "additionalProperties": false, + "properties": { + "content": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameter" + }, + "minItems": 1, + "uniqueItems": true + }, + "typeParameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameter" + }, + "minItems": 1, + "uniqueItems": true + }, + "return": { + "$ref": "#/definitions/return" + } + }, + "patternProperties": { + "^content\\.": { + "type": "string" + }, + "^return\\.": { + "$ref": "#/definitions/return" + } + } + }, + "parameter": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "defaultValue": { + "type": "string" + } + } + }, + "return": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": { + "type": "string" + } + } + }, + "exception": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "link": { + "type": "object", + "additionalProperties": false, + "required": ["linkType", "linkId"], + "properties": { + "linkType": { + "enum": ["CRef", "HRef"] + }, + "linkId": { + "type": "string" + }, + "commentId": { + "type": "string" + }, + "altText": { + "type": "string" + } + } + }, + "inheritance": { + "type": "object", + "additionalProperties": false, + "required": ["type"], + "properties": { + "type": { + "type": "string" + }, + "inheritance": { + "type": "array", + "items": { + "$ref": "#/definitions/inheritance" + }, + "minItems": 1, + "uniqueItems": true + }, + "level": { + "type": "number" + } + } + }, + "reference": { + "type": "object", + "additionalProperties": false, + "properties": { + "uid": { + "type": "string" + }, + "commentId": { + "type": "string" + }, + "parent": { + "type": "string" + }, + "definition": { + "type": "string" + }, + "isExternal": { + "type": "boolean" + }, + "href": { + "type": "string" + }, + "name": { + "type": "string" + }, + "nameWithType": { + "type": "string" + }, + "fullName": { + "type": "string" + } + }, + "patternProperties": { + "^name\\.": { + "type": "string" + }, + "^nameWithType\\.": { + "type": "string" + }, + "^fullName\\.": { + "type": "string" + }, + "^spec\\.": { + "type": "array", + "items": { + "$ref": "#/definitions/spec" + } + } + } + }, + "spec": { + "type": "object", + "additionalProperties": false, + "properties": { + "uid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "nameWithType": { + "type": "string" + }, + "fullName": { + "type": "string" + }, + "isExternal": { + "type": "boolean" + }, + "href": { + "type": "string" + } + } + }, - "deprecated": { - "type": "object", - "additionalProperties": false, - "properties": { - "content": { - "description": "The string following the default obsolete message. Supports markdown.", - "type": "string" - } - } - } - } + "deprecated": { + "type": "object", + "additionalProperties": false, + "properties": { + "content": { + "description": "The string following the default obsolete message. Supports markdown.", + "type": "string" + } + } + } + } } diff --git a/apps/api-documenter/tsconfig.json b/apps/api-documenter/tsconfig.json index 47e75f9f181..dac21d04081 100644 --- a/apps/api-documenter/tsconfig.json +++ b/apps/api-documenter/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "jest" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/apps/api-extractor-model/.eslintrc.js b/apps/api-extractor-model/.eslintrc.js deleted file mode 100644 index b00435d3a51..00000000000 --- a/apps/api-extractor-model/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require("@rushstack/eslint-config/patch-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, - - rules: { - // api-extractor-model uses namespaces to represent mixins - "@typescript-eslint/no-namespace": "off" - } -}; diff --git a/apps/api-extractor-model/.npmignore b/apps/api-extractor-model/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/apps/api-extractor-model/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/apps/api-extractor-model/CHANGELOG.json b/apps/api-extractor-model/CHANGELOG.json deleted file mode 100644 index 4dac06f13a1..00000000000 --- a/apps/api-extractor-model/CHANGELOG.json +++ /dev/null @@ -1,517 +0,0 @@ -{ - "name": "@microsoft/api-extractor-model", - "entries": [ - { - "version": "7.7.9", - "tag": "@microsoft/api-extractor-model_v7.7.9", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "7.7.8", - "tag": "@microsoft/api-extractor-model_v7.7.8", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - } - ] - } - }, - { - "version": "7.7.7", - "tag": "@microsoft/api-extractor-model_v7.7.7", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" - } - ] - } - }, - { - "version": "7.7.6", - "tag": "@microsoft/api-extractor-model_v7.7.6", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" - } - ] - } - }, - { - "version": "7.7.5", - "tag": "@microsoft/api-extractor-model_v7.7.5", - "date": "Tue, 21 Jan 2020 21:56:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "7.7.4", - "tag": "@microsoft/api-extractor-model_v7.7.4", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "7.7.3", - "tag": "@microsoft/api-extractor-model_v7.7.3", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "7.7.2", - "tag": "@microsoft/api-extractor-model_v7.7.2", - "date": "Thu, 09 Jan 2020 06:44:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "7.7.1", - "tag": "@microsoft/api-extractor-model_v7.7.1", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "7.7.0", - "tag": "@microsoft/api-extractor-model_v7.7.0", - "date": "Tue, 03 Dec 2019 03:17:43 GMT", - "comments": { - "minor": [ - { - "comment": "Improve declaration reference syntax to allow linking to overloaded functions/methods" - } - ] - } - }, - { - "version": "7.6.0", - "tag": "@microsoft/api-extractor-model_v7.6.0", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "minor": [ - { - "comment": "Added support for `@throws`" - } - ] - } - }, - { - "version": "7.5.6", - "tag": "@microsoft/api-extractor-model_v7.5.6", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" - } - ] - } - }, - { - "version": "7.5.5", - "tag": "@microsoft/api-extractor-model_v7.5.5", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "7.5.4", - "tag": "@microsoft/api-extractor-model_v7.5.4", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" - } - ] - } - }, - { - "version": "7.5.3", - "tag": "@microsoft/api-extractor-model_v7.5.3", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "patch": [ - { - "comment": "Clarified an error message" - } - ] - } - }, - { - "version": "7.5.2", - "tag": "@microsoft/api-extractor-model_v7.5.2", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "7.5.1", - "tag": "@microsoft/api-extractor-model_v7.5.1", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" - } - ] - } - }, - { - "version": "7.5.0", - "tag": "@microsoft/api-extractor-model_v7.5.0", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "minor": [ - { - "comment": "Add ApiItem.getMergedSiblings() API" - } - ] - } - }, - { - "version": "7.4.2", - "tag": "@microsoft/api-extractor-model_v7.4.2", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unnecessary dependency on @types/node" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" - } - ] - } - }, - { - "version": "7.4.1", - "tag": "@microsoft/api-extractor-model_v7.4.1", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "patch": [ - { - "comment": "Update documentation" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" - } - ] - } - }, - { - "version": "7.4.0", - "tag": "@microsoft/api-extractor-model_v7.4.0", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "minor": [ - { - "comment": "Add 'canonicalReference' to ExcerptToken" - } - ] - } - }, - { - "version": "7.3.4", - "tag": "@microsoft/api-extractor-model_v7.3.4", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" - } - ] - } - }, - { - "version": "7.3.3", - "tag": "@microsoft/api-extractor-model_v7.3.3", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "patch": [ - { - "comment": "Update TSDoc dependency to 0.12.14" - } - ] - } - }, - { - "version": "7.3.2", - "tag": "@microsoft/api-extractor-model_v7.3.2", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" - } - ] - } - }, - { - "version": "7.3.1", - "tag": "@microsoft/api-extractor-model_v7.3.1", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "patch": [ - { - "comment": "(Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation" - } - ] - } - }, - { - "version": "7.3.0", - "tag": "@microsoft/api-extractor-model_v7.3.0", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "minor": [ - { - "comment": "Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()`" - } - ] - } - }, - { - "version": "7.2.0", - "tag": "@microsoft/api-extractor-model_v7.2.0", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "patch": [ - { - "comment": "Improve the .api.json deserializer to validate the schema version and support backwards compatibility" - } - ], - "minor": [ - { - "comment": "Add API support for type parameters and type alias types" - } - ] - } - }, - { - "version": "7.1.3", - "tag": "@microsoft/api-extractor-model_v7.1.3", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number" - } - ] - } - }, - { - "version": "7.1.2", - "tag": "@microsoft/api-extractor-model_v7.1.2", - "date": "Tue, 04 Jun 2019 05:51:53 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static" - } - ] - } - }, - { - "version": "7.1.1", - "tag": "@microsoft/api-extractor-model_v7.1.1", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "patch": [ - { - "comment": "Make the strings returned by ApiItem.displayName less verbose" - }, - { - "comment": "Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage()" - } - ] - } - }, - { - "version": "7.1.0", - "tag": "@microsoft/api-extractor-model_v7.1.0", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "minor": [ - { - "comment": "Initial stable release of API Extractor 7" - } - ] - } - }, - { - "version": "7.0.28", - "tag": "@microsoft/api-extractor-model_v7.0.28", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" - } - ] - } - }, - { - "version": "7.0.27", - "tag": "@microsoft/api-extractor-model_v7.0.27", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "patch": [ - { - "comment": "Add helper functions for ReleaseTag" - }, - { - "comment": "Export IApiItemConstructor to eliminate the ae-forgotten-export warning" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" - } - ] - } - }, - { - "version": "7.0.26", - "tag": "@microsoft/api-extractor-model_v7.0.26", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter" - } - ] - } - }, - { - "version": "7.0.25", - "tag": "@microsoft/api-extractor-model_v7.0.25", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade TSDoc" - } - ] - } - }, - { - "version": "7.0.24", - "tag": "@microsoft/api-extractor-model_v7.0.24", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "patch": [ - { - "comment": "Initial setup of new package @microsoft/api-extractor-model" - } - ] - } - } - ] -} diff --git a/apps/api-extractor-model/CHANGELOG.md b/apps/api-extractor-model/CHANGELOG.md deleted file mode 100644 index 7f4f5739463..00000000000 --- a/apps/api-extractor-model/CHANGELOG.md +++ /dev/null @@ -1,240 +0,0 @@ -# Change Log - @microsoft/api-extractor-model - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 7.7.9 -Wed, 18 Mar 2020 15:07:47 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 7.7.8 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 7.7.7 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 7.7.6 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 7.7.5 -Tue, 21 Jan 2020 21:56:14 GMT - -*Version update only* - -## 7.7.4 -Sun, 19 Jan 2020 02:26:52 GMT - -### Patches - -- Upgrade Node typings to Node 10 - -## 7.7.3 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 7.7.2 -Thu, 09 Jan 2020 06:44:13 GMT - -*Version update only* - -## 7.7.1 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 7.7.0 -Tue, 03 Dec 2019 03:17:43 GMT - -### Minor changes - -- Improve declaration reference syntax to allow linking to overloaded functions/methods - -## 7.6.0 -Sun, 24 Nov 2019 00:54:04 GMT - -### Minor changes - -- Added support for `@throws` - -## 7.5.6 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 7.5.5 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 7.5.4 -Tue, 05 Nov 2019 06:49:28 GMT - -### Patches - -- Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552) - -## 7.5.3 -Tue, 05 Nov 2019 01:08:39 GMT - -### Patches - -- Clarified an error message - -## 7.5.2 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 7.5.1 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 7.5.0 -Wed, 25 Sep 2019 15:15:31 GMT - -### Minor changes - -- Add ApiItem.getMergedSiblings() API - -## 7.4.2 -Mon, 23 Sep 2019 15:14:55 GMT - -### Patches - -- Remove unnecessary dependency on @types/node - -## 7.4.1 -Tue, 10 Sep 2019 22:32:23 GMT - -### Patches - -- Update documentation - -## 7.4.0 -Tue, 10 Sep 2019 20:38:33 GMT - -### Minor changes - -- Add 'canonicalReference' to ExcerptToken - -## 7.3.4 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 7.3.3 -Wed, 04 Sep 2019 15:15:37 GMT - -### Patches - -- Update TSDoc dependency to 0.12.14 - -## 7.3.2 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 7.3.1 -Thu, 08 Aug 2019 00:49:05 GMT - -### Patches - -- (Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation - -## 7.3.0 -Mon, 22 Jul 2019 19:13:10 GMT - -### Minor changes - -- Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()` - -## 7.2.0 -Tue, 11 Jun 2019 00:48:06 GMT - -### Minor changes - -- Add API support for type parameters and type alias types - -### Patches - -- Improve the .api.json deserializer to validate the schema version and support backwards compatibility - -## 7.1.3 -Wed, 05 Jun 2019 19:12:34 GMT - -### Patches - -- Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number - -## 7.1.2 -Tue, 04 Jun 2019 05:51:53 GMT - -### Patches - -- Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static - -## 7.1.1 -Mon, 27 May 2019 04:13:44 GMT - -### Patches - -- Make the strings returned by ApiItem.displayName less verbose -- Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage() - -## 7.1.0 -Tue, 16 Apr 2019 11:01:37 GMT - -### Minor changes - -- Initial stable release of API Extractor 7 - -## 7.0.28 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 7.0.27 -Mon, 18 Mar 2019 04:28:43 GMT - -### Patches - -- Add helper functions for ReleaseTag -- Export IApiItemConstructor to eliminate the ae-forgotten-export warning - -## 7.0.26 -Wed, 13 Mar 2019 19:13:14 GMT - -### Patches - -- Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter - -## 7.0.25 -Wed, 13 Mar 2019 01:14:05 GMT - -### Patches - -- Upgrade TSDoc - -## 7.0.24 -Mon, 11 Mar 2019 16:13:36 GMT - -### Patches - -- Initial setup of new package @microsoft/api-extractor-model - diff --git a/apps/api-extractor-model/LICENSE b/apps/api-extractor-model/LICENSE deleted file mode 100644 index d9cfa3eb077..00000000000 --- a/apps/api-extractor-model/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/api-extractor - -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/api-extractor-model/README.md b/apps/api-extractor-model/README.md deleted file mode 100644 index 1b6a55706a1..00000000000 --- a/apps/api-extractor-model/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# @microsoft/api-extractor-model - -Use this library to read and write *.api.json files as defined by the [API Extractor](https://api-extractor.com/) tool. -These files are used to generate a documentation website for your TypeScript package. The files store the -API signatures and doc comments that were extracted from your package. - -API documentation for this package: https://rushstack.io/pages/api/api-extractor-model/ - -## Example Usage - -The following code sample shows how to load `example.api.json`, which would be generated by API Extractor -when it analyzes a hypothetical NPM package called `example`: - -```ts -import { ApiModel, ApiPackage } from '@microsoft/api-extractor-model'; - -const apiModel: ApiModel = new ApiModel(); -const apiPackage: ApiPackage = apiModel.loadPackage('example.api.json'); - -for (const member of apiPackage.members) { - console.log(member.displayName); -} -``` - -The `ApiModel` is acts as a container for various packages that are loaded and operated on as a group. -For example, a documentation tool may need to resolve `@link` references across different packages. -In this case we would load the various packages into the `ApiModel`, and then use -the `ApiModel.resolveDeclarationReference()` to resolve the `@link` targets. - -The data structure forms a tree of various classes that start with the `Api` prefix. The nesting hierarchy -might look like this: - -``` -- ApiModel - - ApiPackage - - ApiEntryPoint - - ApiClass - - ApiMethod - - ApiProperty - - ApiEnum - - ApiEnumMember - - ApiInterface - - ApiMethodSignature - - ApiPropertySignature - - ApiNamespace - - (ApiClass, ApiEnum, ApiInterace, ...) -``` - -You can use the `ApiItem.members` property to traverse this tree. - -Note that the non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use -TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various -features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class -to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: -the function that generates a subclass, an interface that describes the members of the subclass, and -a namespace containing static members of the class. - -> For a complete project that uses these APIs to generate an API reference web site, -> see the [@microsoft/api-documenter](https://www.npmjs.com/package/@microsoft/api-documenter) source code. diff --git a/apps/api-extractor-model/config/api-extractor.json b/apps/api-extractor-model/config/api-extractor.json deleted file mode 100644 index 3e8571b570b..00000000000 --- a/apps/api-extractor-model/config/api-extractor.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$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, - "untrimmedFilePath": "/dist/rollup.d.ts", - } -} diff --git a/apps/api-extractor-model/config/jest.json b/apps/api-extractor-model/config/jest.json deleted file mode 100644 index 0c42a30d2f6..00000000000 --- a/apps/api-extractor-model/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": false -} \ No newline at end of file diff --git a/apps/api-extractor-model/gulpfile.js b/apps/api-extractor-model/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/apps/api-extractor-model/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/apps/api-extractor-model/package.json b/apps/api-extractor-model/package.json deleted file mode 100644 index d4cc3104da1..00000000000 --- a/apps/api-extractor-model/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@microsoft/api-extractor-model", - "version": "7.7.9", - "description": "A helper library for loading and saving the .api.json files created by API Extractor", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/api-extractor-model" - }, - "homepage": "https://api-extractor.com", - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", - "license": "MIT", - "scripts": { - "build": "gulp test --clean" - }, - "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@microsoft/tsdoc": "0.12.14" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/apps/api-extractor-model/src/aedoc/ReleaseTag.ts b/apps/api-extractor-model/src/aedoc/ReleaseTag.ts deleted file mode 100644 index c5cab848b84..00000000000 --- a/apps/api-extractor-model/src/aedoc/ReleaseTag.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * A "release tag" is a custom TSDoc tag that is applied to an API to communicate the level of support - * provided for third-party developers. - * - * @remarks - * - * The four release tags are: `@internal`, `@alpha`, `@beta`, and `@public`. They are applied to API items such - * as classes, member functions, enums, etc. The release tag applies recursively to members of a container - * (e.g. class or interface). For example, if a class is marked as `@beta`, then all of its members automatically - * have this status; you DON'T need add the `@beta` tag to each member function. However, you could add - * `@internal` to a member function to give it a different release status. - * - * @public - */ -export enum ReleaseTag { - /** - * No release tag was specified in the AEDoc summary. - */ - None = 0, - /** - * Indicates that an API item is meant only for usage by other NPM packages from the same - * maintainer. Third parties should never use "internal" APIs. (To emphasize this, their - * names are prefixed by underscores.) - */ - Internal = 1, - /** - * Indicates that an API item is eventually intended to be public, but currently is in an - * early stage of development. Third parties should not use "alpha" APIs. - */ - Alpha = 2, - /** - * Indicates that an API item has been released in an experimental state. Third parties are - * encouraged to try it and provide feedback. However, a "beta" API should NOT be used - * in production. - */ - Beta = 3, - /** - * Indicates that an API item has been officially released. It is part of the supported - * contract (e.g. SemVer) for a package. - */ - Public = 4 -} - -/** - * Helper functions for working with the `ReleaseTag` enum. - * @public - */ -export namespace ReleaseTag { - /** - * Returns the TSDoc tag name for a `ReleaseTag` value. - * - * @remarks - * For example, `getTagName(ReleaseTag.Internal)` would return the string `@internal`. - */ - export function getTagName(releaseTag: ReleaseTag): string { - switch (releaseTag) { - case ReleaseTag.None: return '(none)'; - case ReleaseTag.Internal: return '@internal'; - case ReleaseTag.Alpha: return '@alpha'; - case ReleaseTag.Beta: return '@beta'; - case ReleaseTag.Public: return '@public'; - } - throw new Error('Unsupported release tag'); - } - - /** - * Compares two `ReleaseTag` values. Their values must not be `ReleaseTag.None`. - * @returns 0 if `a` and `b` are equal, a positive number if `a` is more public than `b`, - * and a negative number if `a` is less public than `b`. - * @remarks - * For example, `compareReleaseTag(ReleaseTag.Beta, ReleaseTag.Alpha)` will return a positive - * number because beta is more public than alpha. - */ - export function compare(a: ReleaseTag, b: ReleaseTag): number { - return a - b; - } - -} diff --git a/apps/api-extractor-model/src/index.ts b/apps/api-extractor-model/src/index.ts deleted file mode 100644 index 8107ea4eb3f..00000000000 --- a/apps/api-extractor-model/src/index.ts +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Use this library to read and write *.api.json files as defined by the - * {@link https://api-extractor.com/ | API Extractor} tool. These files are used to generate a documentation - * website for your TypeScript package. The files store the API signatures and doc comments that were extracted - * from your package. - * - * @packageDocumentation - */ - -export { AedocDefinitions } from './aedoc/AedocDefinitions'; -export { ReleaseTag } from './aedoc/ReleaseTag'; - -// items -export { - IApiDeclaredItemOptions, - ApiDeclaredItem -} from './items/ApiDeclaredItem'; -export { - IApiDocumentedItemOptions, - ApiDocumentedItem -} from './items/ApiDocumentedItem'; -export { - ApiItemKind, - IApiItemOptions, - ApiItem, - IApiItemConstructor -} from './items/ApiItem'; -export { - IApiPropertyItemOptions, - ApiPropertyItem -} from './items/ApiPropertyItem'; - -// mixins -export { - IApiParameterListMixinOptions, - IApiParameterOptions, - ApiParameterListMixin -} from './mixins/ApiParameterListMixin'; -export { - IApiTypeParameterOptions, - IApiTypeParameterListMixinOptions, - ApiTypeParameterListMixin -} from './mixins/ApiTypeParameterListMixin'; -export { - IApiItemContainerMixinOptions, - ApiItemContainerMixin -} from './mixins/ApiItemContainerMixin'; -export { - IApiReleaseTagMixinOptions, - ApiReleaseTagMixin -} from './mixins/ApiReleaseTagMixin'; -export { - IApiReturnTypeMixinOptions, - ApiReturnTypeMixin -} from './mixins/ApiReturnTypeMixin'; -export { - IApiStaticMixinOptions, - ApiStaticMixin -} from './mixins/ApiStaticMixin'; -export { - IApiNameMixinOptions, - ApiNameMixin -} from './mixins/ApiNameMixin'; -export { - ExcerptTokenKind, - IExcerptTokenRange, - IExcerptToken, - ExcerptToken, - Excerpt -} from './mixins/Excerpt'; -export { - Constructor, - PropertiesOf -} from './mixins/Mixin'; - -// model -export { - IApiCallSignatureOptions, - ApiCallSignature -} from './model/ApiCallSignature'; -export { - IApiClassOptions, - ApiClass -} from './model/ApiClass'; -export { - IApiConstructorOptions, - ApiConstructor -} from './model/ApiConstructor'; -export { - IApiConstructSignatureOptions, - ApiConstructSignature -} from './model/ApiConstructSignature'; -export { - IApiEntryPointOptions, - ApiEntryPoint -} from './model/ApiEntryPoint'; -export { - IApiEnumOptions, - ApiEnum -} from './model/ApiEnum'; -export { - IApiEnumMemberOptions, - ApiEnumMember -} from './model/ApiEnumMember'; -export { - IApiFunctionOptions, - ApiFunction -} from './model/ApiFunction'; -export { - IApiIndexSignatureOptions, - ApiIndexSignature -} from './model/ApiIndexSignature'; -export { - IApiInterfaceOptions, - ApiInterface -} from './model/ApiInterface'; -export { - IApiMethodOptions, - ApiMethod -} from './model/ApiMethod'; -export { - IApiMethodSignatureOptions, - ApiMethodSignature -} from './model/ApiMethodSignature'; -export { - ApiModel -} from './model/ApiModel'; -export { - IApiNamespaceOptions, - ApiNamespace -} from './model/ApiNamespace'; -export { - IApiPackageOptions, - ApiPackage, - IApiPackageSaveOptions -} from './model/ApiPackage'; -export { - IParameterOptions, - Parameter -} from './model/Parameter'; -export { - IApiPropertyOptions, - ApiProperty -} from './model/ApiProperty'; -export { - IApiPropertySignatureOptions, - ApiPropertySignature -} from './model/ApiPropertySignature'; -export { - IApiTypeAliasOptions, - ApiTypeAlias -} from './model/ApiTypeAlias'; -export { - ITypeParameterOptions, - TypeParameter -} from './model/TypeParameter'; -export { - IApiVariableOptions, - ApiVariable -} from './model/ApiVariable'; -export { - IResolveDeclarationReferenceResult -} from './model/ModelReferenceResolver'; -export { - HeritageType -} from './model/HeritageType'; diff --git a/apps/api-extractor-model/src/items/ApiDeclaredItem.ts b/apps/api-extractor-model/src/items/ApiDeclaredItem.ts deleted file mode 100644 index da75b36e9d7..00000000000 --- a/apps/api-extractor-model/src/items/ApiDeclaredItem.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information.s - -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiDocumentedItem, IApiDocumentedItemJson, IApiDocumentedItemOptions } from './ApiDocumentedItem'; -import { Excerpt, ExcerptToken, IExcerptTokenRange, IExcerptToken } from '../mixins/Excerpt'; -import { DeserializerContext } from '../model/DeserializerContext'; - -/** - * Constructor options for {@link ApiDeclaredItem}. - * @public - */ -export interface IApiDeclaredItemOptions extends IApiDocumentedItemOptions { - excerptTokens: IExcerptToken[]; -} - -export interface IApiDeclaredItemJson extends IApiDocumentedItemJson { - excerptTokens: IExcerptToken[]; -} - -/** - * The base class for API items that have an associated source code excerpt containing a TypeScript declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * Most `ApiItem` subclasses have declarations and thus extend `ApiDeclaredItem`. Counterexamples include - * `ApiModel` and `ApiPackage`, which do not have any corresponding TypeScript source code. - * - * @public - */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix -export class ApiDeclaredItem extends ApiDocumentedItem { - private _excerptTokens: ExcerptToken[]; - private _excerpt: Excerpt; - - public constructor(options: IApiDeclaredItemOptions) { - super(options); - - this._excerptTokens = options.excerptTokens.map(token => { - const canonicalReference: DeclarationReference | undefined = token.canonicalReference === undefined ? undefined : - DeclarationReference.parse(token.canonicalReference); - return new ExcerptToken(token.kind, token.text, canonicalReference); - }); - this._excerpt = new Excerpt(this.excerptTokens, { startIndex: 0, endIndex: this.excerptTokens.length }); - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiDeclaredItemJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.excerptTokens = jsonObject.excerptTokens; - } - - /** - * The source code excerpt where the API item is declared. - */ - public get excerpt(): Excerpt { - return this._excerpt; - } - - /** - * The individual source code tokens that comprise the main excerpt. - */ - public get excerptTokens(): ReadonlyArray { - return this._excerptTokens; - } - - /** - * If the API item has certain important modifier tags such as `@sealed`, `@virtual`, or `@override`, - * this prepends them as a doc comment above the excerpt. - */ - public getExcerptWithModifiers(): string { - const excerpt: string = this.excerpt.text; - const modifierTags: string[] = []; - - if (excerpt.length > 0) { - if (this instanceof ApiDocumentedItem) { - if (this.tsdocComment) { - if (this.tsdocComment.modifierTagSet.isSealed()) { - modifierTags.push('@sealed'); - } - if (this.tsdocComment.modifierTagSet.isVirtual()) { - modifierTags.push('@virtual'); - } - if (this.tsdocComment.modifierTagSet.isOverride()) { - modifierTags.push('@override'); - } - } - if (modifierTags.length > 0) { - return '/** ' + modifierTags.join(' ') + ' */\n' - + excerpt; - } - } - } - - return excerpt; - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - jsonObject.excerptTokens = this.excerptTokens.map(x => { - const excerptToken: IExcerptToken = { kind: x.kind, text: x.text }; - if (x.canonicalReference !== undefined) { - excerptToken.canonicalReference = x.canonicalReference.toString(); - } - return excerptToken; - }); - } - - /** - * Constructs a new {@link Excerpt} corresponding to the provided token range. - */ - public buildExcerpt(tokenRange: IExcerptTokenRange): Excerpt { - return new Excerpt(this.excerptTokens, tokenRange); - } -} diff --git a/apps/api-extractor-model/src/items/ApiPropertyItem.ts b/apps/api-extractor-model/src/items/ApiPropertyItem.ts deleted file mode 100644 index c0bb2228146..00000000000 --- a/apps/api-extractor-model/src/items/ApiPropertyItem.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; -import { IApiDeclaredItemOptions, ApiDeclaredItem, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { DeserializerContext } from '../model/DeserializerContext'; - -/** - * Constructor options for {@link ApiPropertyItem}. - * @public - */ -export interface IApiPropertyItemOptions extends - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { - - propertyTypeTokenRange: IExcerptTokenRange; -} - -export interface IApiPropertyItemJson extends IApiDeclaredItemJson { - propertyTypeTokenRange: IExcerptTokenRange; -} - -/** - * The abstract base class for {@link ApiProperty} and {@link ApiPropertySignature}. - * - * @public - */ -export class ApiPropertyItem extends ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem)) { - /** - * An {@link Excerpt} that describes the type of the property. - */ - public readonly propertyTypeExcerpt: Excerpt; - - public constructor(options: IApiPropertyItemOptions) { - super(options); - - this.propertyTypeExcerpt = this.buildExcerpt(options.propertyTypeTokenRange); - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiPropertyItemJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.propertyTypeTokenRange = jsonObject.propertyTypeTokenRange; - } - - /** - * Returns true if this property should be documented as an event. - * - * @remarks - * The `@eventProperty` TSDoc modifier can be added to readonly properties to indicate that they return an - * event object that event handlers can be attached to. The event-handling API is implementation-defined, but - * typically the return type would be a class with members such as `addHandler()` and `removeHandler()`. - * The documentation should display such properties under an "Events" heading instead of the - * usual "Properties" heading. - */ - public get isEventProperty(): boolean { - if (this.tsdocComment) { - return this.tsdocComment.modifierTagSet.isEventProperty(); - } - return false; - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - jsonObject.propertyTypeTokenRange = this.propertyTypeExcerpt.tokenRange; - } -} diff --git a/apps/api-extractor-model/src/mixins/ApiItemContainerMixin.ts b/apps/api-extractor-model/src/mixins/ApiItemContainerMixin.ts deleted file mode 100644 index c92c50f93f5..00000000000 --- a/apps/api-extractor-model/src/mixins/ApiItemContainerMixin.ts +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information.s - -import { - ApiItem, - apiItem_onParentChanged, - IApiItemJson, - IApiItemOptions, - IApiItemConstructor, - ApiItemKind -} from '../items/ApiItem'; -import { ApiNameMixin } from './ApiNameMixin'; -import { DeserializerContext } from '../model/DeserializerContext'; -import { InternalError, LegacyAdapters } from '@rushstack/node-core-library'; - -/** - * Constructor options for {@link (ApiItemContainerMixin:interface)}. - * @public - */ -export interface IApiItemContainerMixinOptions extends IApiItemOptions { - members?: ApiItem[]; -} - -export interface IApiItemContainerJson extends IApiItemJson { - members: IApiItemJson[]; -} - -const _members: unique symbol = Symbol('ApiItemContainerMixin._members'); -const _membersSorted: unique symbol = Symbol('ApiItemContainerMixin._membersSorted'); -const _membersByContainerKey: unique symbol = Symbol('ApiItemContainerMixin._membersByContainerKey'); -const _membersByName: unique symbol = Symbol('ApiItemContainerMixin._membersByName'); -const _membersByKind: unique symbol = Symbol('ApiItemContainerMixin._membersByKind'); - -/** - * The mixin base class for API items that act as containers for other child items. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use - * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various - * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class - * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: - * the function that generates a subclass, an interface that describes the members of the subclass, and - * a namespace containing static members of the class. - * - * Examples of `ApiItemContainerMixin` child classes include `ApiModel`, `ApiPackage`, `ApiEntryPoint`, - * and `ApiEnum`. But note that `Parameter` is not considered a "member" of an `ApiMethod`; this relationship - * is modeled using {@link (ApiParameterListMixin:interface).parameters} instead - * of {@link (ApiItemContainerMixin:interface).members}. - * - * @public - */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix -export interface ApiItemContainerMixin extends ApiItem { - /** - * Returns the members of this container, sorted alphabetically. - */ - readonly members: ReadonlyArray; - - /** - * Adds a new member to the container. - * - * @remarks - * An ApiItem cannot be added to more than one container. - */ - addMember(member: ApiItem): void; - - /** - * Attempts to retrieve a member using its containerKey, or returns `undefined` if no matching member was found. - * - * @remarks - * Use the `getContainerKey()` static member to construct the key. Each subclass has a different implementation - * of this function, according to the aspects that are important for identifying it. - * - * See {@link ApiItem.containerKey} for more information. - */ - tryGetMemberByKey(containerKey: string): ApiItem | undefined; - - /** - * Returns a list of members with the specified name. - */ - findMembersByName(name: string): ReadonlyArray; - - /** - * For a given member of this container, return its `ApiItem.getMergedSiblings()` list. - * @internal - */ - _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray; - - /** @override */ - serializeInto(jsonObject: Partial): void; -} - -/** - * Mixin function for {@link ApiDeclaredItem}. - * - * @param baseClass - The base class to be extended - * @returns A child class that extends baseClass, adding the {@link (ApiItemContainerMixin:interface)} functionality. - * - * @public - */ -export function ApiItemContainerMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiItemContainerMixin { - public readonly [_members]: ApiItem[]; - public [_membersSorted]: boolean; - public [_membersByContainerKey]: Map; - - // For members of this container that extend ApiNameMixin, this stores the list of members with a given name. - // Examples include merged declarations, overloaded functions, etc. - public [_membersByName]: Map | undefined; - - // For members of this container that do NOT extend ApiNameMixin, this stores the list of members - // that share a common ApiItemKind. Examples include overloaded constructors or index signatures. - public [_membersByKind]: Map | undefined; // key is ApiItemKind - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public constructor(...args: any[]) { - super(...args); - const options: IApiItemContainerMixinOptions = args[0] as IApiItemContainerMixinOptions; - - this[_members] = []; - this[_membersByContainerKey] = new Map(); - - if (options.members) { - for (const member of options.members) { - this.addMember(member); - } - } - } - - /** @override */ - public static onDeserializeInto(options: Partial, - context: DeserializerContext, jsonObject: IApiItemContainerJson): void { - - baseClass.onDeserializeInto(options, context, jsonObject); - - options.members = []; - for (const memberObject of jsonObject.members) { - options.members.push(ApiItem.deserialize(memberObject, context)); - } - } - - public get members(): ReadonlyArray { - if (!this[_membersSorted]) { - LegacyAdapters.sortStable(this[_members], (x, y) => x.getSortKey().localeCompare(y.getSortKey())); - this[_membersSorted] = true; - } - - return this[_members]; - } - - public addMember(member: ApiItem): void { - if (this[_membersByContainerKey].has(member.containerKey)) { - throw new Error(`Another member has already been added with the same name (${member.displayName})` + - ` and containerKey (${member.containerKey})`); - } - - const existingParent: ApiItem | undefined = member.parent; - if (existingParent !== undefined) { - throw new Error(`This item has already been added to another container: "${existingParent.displayName}"`); - } - - this[_members].push(member); - this[_membersByName] = undefined; // invalidate the lookup - this[_membersByKind] = undefined; // invalidate the lookup - this[_membersSorted] = false; - this[_membersByContainerKey].set(member.containerKey, member); - - member[apiItem_onParentChanged](this); - } - - public tryGetMemberByKey(containerKey: string): ApiItem | undefined { - return this[_membersByContainerKey].get(containerKey); - } - - public findMembersByName(name: string): ReadonlyArray { - this._ensureMemberMaps(); - return this[_membersByName]!.get(name) || []; - } - - /** @internal */ - public _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray { - this._ensureMemberMaps(); - let result: ApiItem[] | undefined; - if (ApiNameMixin.isBaseClassOf(memberApiItem)) { - result = this[_membersByName]!.get(memberApiItem.name); - } else { - result = this[_membersByKind]!.get(memberApiItem.kind); - } - if (!result) { - throw new InternalError('Item was not found in the _membersByName/_membersByKind lookup'); - } - return result; - } - - /** @internal */ - public _ensureMemberMaps(): void { - // Build the _membersByName and _membersByKind tables if they don't already exist - if (this[_membersByName] === undefined) { - const membersByName: Map = new Map(); - const membersByKind: Map = new Map(); - - for (const member of this[_members]) { - let map: Map | Map; - let key: string | ApiItemKind; - - if (ApiNameMixin.isBaseClassOf(member)) { - map = membersByName; - key = member.name; - } else { - map = membersByKind; - key = member.kind; - } - - let list: ApiItem[] | undefined = map.get(key); - if (list === undefined) { - list = []; - map.set(key, list); - } - list.push(member); - } - - this[_membersByName] = membersByName; - this[_membersByKind] = membersByKind; - } - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - const memberObjects: IApiItemJson[] = []; - - for (const member of this.members) { - const memberJsonObject: Partial = {}; - member.serializeInto(memberJsonObject); - memberObjects.push(memberJsonObject as IApiItemJson); - } - - jsonObject.members = memberObjects; - } - } - - return MixedClass; -} - -/** - * Static members for {@link (ApiItemContainerMixin:interface)}. - * @public - */ -export namespace ApiItemContainerMixin { - /** - * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiItemContainerMixin` mixin. - * - * @remarks - * - * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of - * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however - * the TypeScript type system cannot invoke a runtime test.) - */ - export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiItemContainerMixin { - return apiItem.hasOwnProperty(_members); - } -} diff --git a/apps/api-extractor-model/src/mixins/Excerpt.ts b/apps/api-extractor-model/src/mixins/Excerpt.ts deleted file mode 100644 index d8b81c2c5fd..00000000000 --- a/apps/api-extractor-model/src/mixins/Excerpt.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { Text } from '@rushstack/node-core-library'; - -/** @public */ -export const enum ExcerptTokenKind { - /** - * Generic text without any special properties - */ - Content = 'Content', - - /** - * A reference to an API declaration - */ - Reference = 'Reference' -} - -/** @public */ -export interface IExcerptTokenRange { - startIndex: number; - endIndex: number; -} - -/** @public */ -export interface IExcerptToken { - readonly kind: ExcerptTokenKind; - text: string; - canonicalReference?: string; -} - -/** @public */ -export class ExcerptToken { - private readonly _kind: ExcerptTokenKind; - private readonly _text: string; - private readonly _canonicalReference: DeclarationReference | undefined; - - public constructor(kind: ExcerptTokenKind, text: string, canonicalReference?: DeclarationReference) { - this._kind = kind; - - // Standardize the newlines across operating systems. Even though this may deviate from the actual - // input source file that was parsed, it's useful because the newline gets serialized inside - // a string literal in .api.json, which cannot be automatically normalized by Git. - this._text = Text.convertToLf(text); - this._canonicalReference = canonicalReference; - } - - public get kind(): ExcerptTokenKind { - return this._kind; - } - - public get text(): string { - return this._text; - } - - public get canonicalReference(): DeclarationReference | undefined { - return this._canonicalReference; - } -} - -/** - * This class is used by {@link ApiDeclaredItem} to represent a source code excerpt containing - * a TypeScript declaration. - * - * @remarks - * - * The main excerpt is parsed into an array of tokens, and the main excerpt's token range will span all of these - * tokens. The declaration may also have have "captured" excerpts, which are other subranges of tokens. - * For example, if the main excerpt is a function declaration, it will also have a captured excerpt corresponding - * to the return type of the function. - * - * An excerpt may be empty (i.e. a token range containing zero tokens). For example, if a function's return value - * is not explicitly declared, then the returnTypeExcerpt will be empty. By contrast, a class constructor cannot - * have a return value, so ApiConstructor has no returnTypeExcerpt property at all. - * - * @public - */ -export class Excerpt { - public readonly tokenRange: Readonly; - - public readonly tokens: ReadonlyArray; - - private _text: string | undefined; - - public constructor(tokens: ReadonlyArray, tokenRange: IExcerptTokenRange) { - this.tokens = tokens; - this.tokenRange = tokenRange; - - if (this.tokenRange.startIndex < 0 || this.tokenRange.endIndex > this.tokens.length - || this.tokenRange.startIndex > this.tokenRange.endIndex) { - throw new Error('Invalid token range'); - } - } - - public get text(): string { - if (this._text === undefined) { - this._text = this.tokens.slice(this.tokenRange.startIndex, this.tokenRange.endIndex) - .map(x => x.text).join(''); - } - return this._text; - } - - public get isEmpty(): boolean { - return this.tokenRange.startIndex === this.tokenRange.endIndex; - } -} diff --git a/apps/api-extractor-model/src/model/ApiCallSignature.ts b/apps/api-extractor-model/src/model/ApiCallSignature.ts deleted file mode 100644 index aadd9e2a41d..00000000000 --- a/apps/api-extractor-model/src/model/ApiCallSignature.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; -import { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; -import { IApiTypeParameterListMixinOptions, ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin'; - -/** - * Constructor options for {@link ApiCallSignature}. - * @public - */ -export interface IApiCallSignatureOptions extends - IApiTypeParameterListMixinOptions, - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript function call signature. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiCallSignature` represents a TypeScript declaration such as `(x: number, y: number): number` - * in this example: - * - * ```ts - * export interface IChooser { - * // A call signature: - * (x: number, y: number): number; - * - * // Another overload for this call signature: - * (x: string, y: string): string; - * } - * - * function chooseFirst(x: T, y: T): T { - * return x; - * } - * - * let chooser: IChooser = chooseFirst; - * ``` - * - * @public - */ -export class ApiCallSignature extends ApiTypeParameterListMixin(ApiParameterListMixin(ApiReleaseTagMixin( - ApiReturnTypeMixin(ApiDeclaredItem)))) { - - public constructor(options: IApiCallSignatureOptions) { - super(options); - } - - public static getContainerKey(overloadIndex: number): string { - return `|${ApiItemKind.CallSignature}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.CallSignature; - } - - /** @override */ - public get containerKey(): string { - return ApiCallSignature.getContainerKey(this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const parent: DeclarationReference = this.parent - ? this.parent.canonicalReference - // .withMeaning() requires some kind of component - : DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); - return parent - .withMeaning(Meaning.CallSignature) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiClass.ts b/apps/api-extractor-model/src/model/ApiClass.ts deleted file mode 100644 index 654bb398641..00000000000 --- a/apps/api-extractor-model/src/model/ApiClass.ts +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IExcerptTokenRange } from '../mixins/Excerpt'; -import { HeritageType } from './HeritageType'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { ApiTypeParameterListMixin, IApiTypeParameterListMixinOptions, IApiTypeParameterListMixinJson - } from '../mixins/ApiTypeParameterListMixin'; -import { DeserializerContext } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiClass}. - * @public - */ -export interface IApiClassOptions extends - IApiItemContainerMixinOptions, - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions, - IApiTypeParameterListMixinOptions { - - extendsTokenRange: IExcerptTokenRange | undefined; - implementsTokenRanges: IExcerptTokenRange[]; -} - -export interface IApiClassJson extends - IApiDeclaredItemJson, - IApiTypeParameterListMixinJson { - extendsTokenRange?: IExcerptTokenRange; - implementsTokenRanges: IExcerptTokenRange[]; -} - -/** - * Represents a TypeScript class declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiClass` represents a TypeScript declaration such as this: - * - * ```ts - * export class X { } - * ``` - * - * @public - */ -export class ApiClass extends ApiItemContainerMixin(ApiNameMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin( - ApiDeclaredItem)))) { - - /** - * The base class that this class inherits from (using the `extends` keyword), or undefined if there is no base class. - */ - public readonly extendsType: HeritageType | undefined; - - private readonly _implementsTypes: HeritageType[] = []; - - public constructor(options: IApiClassOptions) { - super(options); - - if (options.extendsTokenRange) { - this.extendsType = new HeritageType(this.buildExcerpt(options.extendsTokenRange)); - } else { - this.extendsType = undefined; - } - - for (const implementsTokenRange of options.implementsTokenRanges) { - this._implementsTypes.push(new HeritageType(this.buildExcerpt(implementsTokenRange))); - } - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.Class}`; - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiClassJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.extendsTokenRange = jsonObject.extendsTokenRange; - options.implementsTokenRanges = jsonObject.implementsTokenRanges; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Class; - } - - /** @override */ - public get containerKey(): string { - return ApiClass.getContainerKey(this.name); - } - - /** - * The list of interfaces that this class implements using the `implements` keyword. - */ - public get implementsTypes(): ReadonlyArray { - return this._implementsTypes; - } - - /** @override */ - public 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 - if (this.extendsType) { - jsonObject.extendsTokenRange = this.extendsType.excerpt.tokenRange; - } - - jsonObject.implementsTokenRanges = this.implementsTypes.map(x => x.excerpt.tokenRange); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Class); - } -} diff --git a/apps/api-extractor-model/src/model/ApiConstructSignature.ts b/apps/api-extractor-model/src/model/ApiConstructSignature.ts deleted file mode 100644 index 66eb5f2fa08..00000000000 --- a/apps/api-extractor-model/src/model/ApiConstructSignature.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; -import { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; -import { ApiTypeParameterListMixin, IApiTypeParameterListMixinOptions } from '../mixins/ApiTypeParameterListMixin'; - -/** - * Constructor options for {@link ApiConstructor}. - * @public - */ -export interface IApiConstructSignatureOptions extends - IApiTypeParameterListMixinOptions, - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript construct signature that belongs to an `ApiInterface`. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiConstructSignature` represents a construct signature using the `new` keyword such as in this example: - * - * ```ts - * export interface IVector { - * x: number; - * y: number; - * } - * - * export interface IVectorConstructor { - * // A construct signature: - * new(x: number, y: number): IVector; - * } - * - * export function createVector(vectorConstructor: IVectorConstructor, - * x: number, y: number): IVector { - * return new vectorConstructor(x, y); - * } - * - * class Vector implements IVector { - * public x: number; - * public y: number; - * public constructor(x: number, y: number) { - * this.x = x; - * this.y = y; - * } - * } - * - * let vector: Vector = createVector(Vector, 1, 2); - * ``` - * - * Compare with {@link ApiConstructor}, which describes the class constructor itself. - * - * @public - */ -export class ApiConstructSignature extends ApiTypeParameterListMixin(ApiParameterListMixin(ApiReleaseTagMixin( - ApiReturnTypeMixin(ApiDeclaredItem)))) { - - public constructor(options: IApiConstructSignatureOptions) { - super(options); - } - - public static getContainerKey(overloadIndex: number): string { - return `|${ApiItemKind.ConstructSignature}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.ConstructSignature; - } - - /** @override */ - public get containerKey(): string { - return ApiConstructSignature.getContainerKey(this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const parent: DeclarationReference = this.parent - ? this.parent.canonicalReference - // .withMeaning() requires some kind of component - : DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); - return parent - .withMeaning(Meaning.ConstructSignature) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiConstructor.ts b/apps/api-extractor-model/src/model/ApiConstructor.ts deleted file mode 100644 index ec5a57db401..00000000000 --- a/apps/api-extractor-model/src/model/ApiConstructor.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; - -/** - * Constructor options for {@link ApiConstructor}. - * @public - */ -export interface IApiConstructorOptions extends - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript class constructor declaration that belongs to an `ApiClass`. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiConstructor` represents a declaration using the `constructor` keyword such as in this example: - * - * ```ts - * export class Vector { - * public x: number; - * public y: number; - * - * // A class constructor: - * public constructor(x: number, y: number) { - * this.x = x; - * this.y = y; - * } - * } - * ``` - * - * Compare with {@link ApiConstructSignature}, which describes the construct signature for a class constructor. - * - * @public - */ -export class ApiConstructor extends ApiParameterListMixin(ApiReleaseTagMixin(ApiDeclaredItem)) { - - public constructor(options: IApiConstructorOptions) { - super(options); - } - - public static getContainerKey(overloadIndex: number): string { - return `|${ApiItemKind.Constructor}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Constructor; - } - - /** @override */ - public get containerKey(): string { - return ApiConstructor.getContainerKey(this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const parent: DeclarationReference = this.parent - ? this.parent.canonicalReference - // .withMeaning() requires some kind of component - : DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); - return parent - .withMeaning(Meaning.Constructor) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiEnum.ts b/apps/api-extractor-model/src/model/ApiEnum.ts deleted file mode 100644 index 8e7f07d456f..00000000000 --- a/apps/api-extractor-model/src/model/ApiEnum.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; -import { ApiEnumMember } from './ApiEnumMember'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; - -/** - * Constructor options for {@link ApiEnum}. - * @public - */ -export interface IApiEnumOptions extends - IApiItemContainerMixinOptions, - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript enum declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiEnum` represents an enum declaration such as `FontSizes` in the example below: - * - * ```ts - * export enum FontSizes { - * Small = 100, - * Medium = 200, - * Large = 300 - * } - * ``` - * - * @public - */ -export class ApiEnum extends ApiItemContainerMixin(ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem))) { - - public constructor(options: IApiEnumOptions) { - super(options); - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.Enum}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Enum; - } - - /** @override */ - public get members(): ReadonlyArray { - return super.members as ReadonlyArray; - } - - /** @override */ - public get containerKey(): string { - return ApiEnum.getContainerKey(this.name); - } - - /** @override */ - public 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 { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Enum); - } -} diff --git a/apps/api-extractor-model/src/model/ApiEnumMember.ts b/apps/api-extractor-model/src/model/ApiEnumMember.ts deleted file mode 100644 index 6c19afc3a5c..00000000000 --- a/apps/api-extractor-model/src/model/ApiEnumMember.ts +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { DeserializerContext } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiEnumMember}. - * @public - */ -export interface IApiEnumMemberOptions extends - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { - - initializerTokenRange: IExcerptTokenRange; -} - -export interface IApiEnumMemberJson extends IApiDeclaredItemJson { - initializerTokenRange: IExcerptTokenRange; -} - -/** - * Represents a member of a TypeScript enum declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiEnumMember` represents an enum member such as `Small = 100` in the example below: - * - * ```ts - * export enum FontSizes { - * Small = 100, - * Medium = 200, - * Large = 300 - * } - * ``` - * - * @public - */ -export class ApiEnumMember extends ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem)) { - /** - * An {@link Excerpt} that describes the value of the enum member. - */ - public readonly initializerExcerpt: Excerpt; - - public constructor(options: IApiEnumMemberOptions) { - super(options); - - this.initializerExcerpt = this.buildExcerpt(options.initializerTokenRange); - } - - public static getContainerKey(name: string): string { - // No prefix needed, because ApiEnumMember is the only possible member of an ApiEnum - return name; - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiEnumMemberJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.initializerTokenRange = jsonObject.initializerTokenRange; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.EnumMember; - } - - /** @override */ - public get containerKey(): string { - return ApiEnumMember.getContainerKey(this.name); - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - jsonObject.initializerTokenRange = this.initializerExcerpt.tokenRange; - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Member); - } -} diff --git a/apps/api-extractor-model/src/model/ApiFunction.ts b/apps/api-extractor-model/src/model/ApiFunction.ts deleted file mode 100644 index 07e872cf261..00000000000 --- a/apps/api-extractor-model/src/model/ApiFunction.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; -import { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { IApiTypeParameterListMixinOptions, ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin'; - -/** - * Constructor options for {@link ApiFunction}. - * @public - */ -export interface IApiFunctionOptions extends - IApiNameMixinOptions, - IApiTypeParameterListMixinOptions, - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript function declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiFunction` represents a TypeScript declaration such as this example: - * - * ```ts - * export function getAverage(x: number, y: number): number { - * return (x + y) / 2.0; - * } - * ``` - * - * Functions are exported by an entry point module or by a namespace. Compare with {@link ApiMethod}, which - * represents a function that is a member of a class. - * - * @public - */ -export class ApiFunction extends ApiNameMixin(ApiTypeParameterListMixin(ApiParameterListMixin(ApiReleaseTagMixin( - ApiReturnTypeMixin(ApiDeclaredItem))))) { - - public constructor(options: IApiFunctionOptions) { - super(options); - } - - public static getContainerKey(name: string, overloadIndex: number): string { - return `${name}|${ApiItemKind.Function}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Function; - } - - /** @override */ - public get containerKey(): string { - return ApiFunction.getContainerKey(this.name, this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Function) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiIndexSignature.ts b/apps/api-extractor-model/src/model/ApiIndexSignature.ts deleted file mode 100644 index 4fde269fe15..00000000000 --- a/apps/api-extractor-model/src/model/ApiIndexSignature.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; -import { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; - -/** - * Constructor options for {@link ApiIndexSignature}. - * @public - */ -export interface IApiIndexSignatureOptions extends - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript index signature. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiIndexSignature` represents a TypeScript declaration such as `[x: number]: number` in this example: - * - * ```ts - * export interface INumberTable { - * // An index signature - * [value: number]: number; - * - * // An overloaded index signature - * [name: string]: number; - * } - * ``` - * - * @public - */ -export class ApiIndexSignature extends ApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))) { - public constructor(options: IApiIndexSignatureOptions) { - super(options); - } - - public static getContainerKey(overloadIndex: number): string { - return `|${ApiItemKind.IndexSignature}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.IndexSignature; - } - - /** @override */ - public get containerKey(): string { - return ApiIndexSignature.getContainerKey(this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const parent: DeclarationReference = this.parent - ? this.parent.canonicalReference - // .withMeaning() requires some kind of component - : DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); - return parent - .withMeaning(Meaning.IndexSignature) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiInterface.ts b/apps/api-extractor-model/src/model/ApiInterface.ts deleted file mode 100644 index a16eff138a8..00000000000 --- a/apps/api-extractor-model/src/model/ApiInterface.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions, IApiItemContainerJson - } from '../mixins/ApiItemContainerMixin'; -import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin, IApiReleaseTagMixinJson } from '../mixins/ApiReleaseTagMixin'; -import { IExcerptTokenRange } from '../mixins/Excerpt'; -import { HeritageType } from './HeritageType'; -import { IApiNameMixinOptions, ApiNameMixin, IApiNameMixinJson } from '../mixins/ApiNameMixin'; -import { IApiTypeParameterListMixinOptions, IApiTypeParameterListMixinJson, ApiTypeParameterListMixin - } from '../mixins/ApiTypeParameterListMixin'; -import { DeserializerContext } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiInterface}. - * @public - */ -export interface IApiInterfaceOptions extends - IApiItemContainerMixinOptions, - IApiNameMixinOptions, - IApiTypeParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { - - extendsTokenRanges: IExcerptTokenRange[]; -} - -export interface IApiInterfaceJson extends - IApiItemContainerJson, - IApiNameMixinJson, - IApiTypeParameterListMixinJson, - IApiReleaseTagMixinJson, - IApiDeclaredItemJson { - - extendsTokenRanges: IExcerptTokenRange[]; -} - -/** - * Represents a TypeScript class declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiInterface` represents a TypeScript declaration such as this: - * - * ```ts - * export interface X extends Y { - * } - * ``` - * - * @public - */ -export class ApiInterface extends ApiItemContainerMixin(ApiNameMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin( - ApiDeclaredItem)))) { - - private readonly _extendsTypes: HeritageType[] = []; - - public constructor(options: IApiInterfaceOptions) { - super(options); - - for (const extendsTokenRange of options.extendsTokenRanges) { - this._extendsTypes.push(new HeritageType(this.buildExcerpt(extendsTokenRange))); - } - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.Interface}`; - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiInterfaceJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.extendsTokenRanges = jsonObject.extendsTokenRanges; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Interface; - } - - /** @override */ - public get containerKey(): string { - return ApiInterface.getContainerKey(this.name); - } - - /** - * The list of base interfaces that this interface inherits from using the `extends` keyword. - */ - public get extendsTypes(): ReadonlyArray { - return this._extendsTypes; - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - jsonObject.extendsTokenRanges = this.extendsTypes.map(x => x.excerpt.tokenRange); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Interface); - } -} diff --git a/apps/api-extractor-model/src/model/ApiMethod.ts b/apps/api-extractor-model/src/model/ApiMethod.ts deleted file mode 100644 index e241a9cca38..00000000000 --- a/apps/api-extractor-model/src/model/ApiMethod.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiStaticMixin, IApiStaticMixinOptions } from '../mixins/ApiStaticMixin'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; -import { ApiReturnTypeMixin, IApiReturnTypeMixinOptions } from '../mixins/ApiReturnTypeMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { ApiTypeParameterListMixin, IApiTypeParameterListMixinOptions } from '../mixins/ApiTypeParameterListMixin'; - -/** - * Constructor options for {@link ApiMethod}. - * @public - */ -export interface IApiMethodOptions extends - IApiNameMixinOptions, - IApiTypeParameterListMixinOptions, - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiStaticMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript member function declaration that belongs to an `ApiClass`. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiMethod` represents a TypeScript declaration such as the `render` member function in this example: - * - * ```ts - * export class Widget { - * public render(): void { } - * } - * ``` - * - * Compare with {@link ApiMethodSignature}, which represents a method belonging to an interface. - * For example, a class method can be `static` but an interface method cannot. - * - * @public - */ -export class ApiMethod extends ApiNameMixin(ApiTypeParameterListMixin(ApiParameterListMixin( - ApiReleaseTagMixin(ApiReturnTypeMixin(ApiStaticMixin(ApiDeclaredItem)))))) { - - public constructor(options: IApiMethodOptions) { - super(options); - } - - public static getContainerKey(name: string, isStatic: boolean, overloadIndex: number): string { - if (isStatic) { - return `${name}|${ApiItemKind.Method}|static|${overloadIndex}`; - } else { - return `${name}|${ApiItemKind.Method}|instance|${overloadIndex}`; - } - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Method; - } - - /** @override */ - public get containerKey(): string { - return ApiMethod.getContainerKey(this.name, this.isStatic, this.overloadIndex); - } - - /** @beta @override */ - public 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) - .withMeaning(Meaning.Member) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiMethodSignature.ts b/apps/api-extractor-model/src/model/ApiMethodSignature.ts deleted file mode 100644 index 143f0a48b64..00000000000 --- a/apps/api-extractor-model/src/model/ApiMethodSignature.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions } from '../items/ApiDeclaredItem'; -import { ApiParameterListMixin, IApiParameterListMixinOptions } from '../mixins/ApiParameterListMixin'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { IApiTypeParameterListMixinOptions, ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin'; - -/** @public */ -export interface IApiMethodSignatureOptions extends - IApiNameMixinOptions, - IApiTypeParameterListMixinOptions, - IApiParameterListMixinOptions, - IApiReleaseTagMixinOptions, - IApiReturnTypeMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript member function declaration that belongs to an `ApiInterface`. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiMethodSignature` represents a TypeScript declaration such as the `render` member function in this example: - * - * ```ts - * export interface IWidget { - * render(): void; - * } - * ``` - * - * Compare with {@link ApiMethod}, which represents a method belonging to a class. - * For example, a class method can be `static` but an interface method cannot. - * - * @public - */ -export class ApiMethodSignature extends ApiNameMixin(ApiTypeParameterListMixin(ApiParameterListMixin( - ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))))) { - - public constructor(options: IApiMethodSignatureOptions) { - super(options); - } - - public static getContainerKey(name: string, overloadIndex: number): string { - return `${name}|${ApiItemKind.MethodSignature}|${overloadIndex}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.MethodSignature; - } - - /** @override */ - public get containerKey(): string { - return ApiMethodSignature.getContainerKey(this.name, this.overloadIndex); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Members, nameComponent) - .withMeaning(Meaning.Member) - .withOverloadIndex(this.overloadIndex); - } -} diff --git a/apps/api-extractor-model/src/model/ApiModel.ts b/apps/api-extractor-model/src/model/ApiModel.ts deleted file mode 100644 index 29bcb1aa3b8..00000000000 --- a/apps/api-extractor-model/src/model/ApiModel.ts +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItem, ApiItemKind } from '../items/ApiItem'; -import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; -import { ApiPackage } from './ApiPackage'; -import { PackageName } from '@rushstack/node-core-library'; -import { ModelReferenceResolver, IResolveDeclarationReferenceResult } from './ModelReferenceResolver'; -import { DocDeclarationReference } from '@microsoft/tsdoc'; - -/** - * A serializable representation of a collection of API declarations. - * - * @remarks - * - * An `ApiModel` represents a collection of API declarations that can be serialized to disk. It captures all the - * important information needed to generate documentation, without any reliance on the TypeScript compiler engine. - * - * An `ApiModel` acts as the root of a tree of objects that all inherit from the `ApiItem` base class. - * The tree children are determined by the {@link (ApiItemContainerMixin:interface)} mixin base class. The model - * contains packages. Packages have an entry point (today, only one). And the entry point can contain various types - * of API declarations. The container relationships might look like this: - * - * ``` - * Things that can contain other things: - * - * - ApiModel - * - ApiPackage - * - ApiEntryPoint - * - ApiClass - * - ApiMethod - * - ApiProperty - * - ApiEnum - * - ApiEnumMember - * - ApiInterface - * - ApiMethodSignature - * - ApiPropertySignature - * - ApiNamespace - * - (ApiClass, ApiEnum, ApiInterace, ...) - * - * ``` - * - * Normally, API Extractor writes an .api.json file to disk for each project that it builds. Then, a tool like - * API Documenter can load the various `ApiPackage` objects into a single `ApiModel` and process them as a group. - * This is useful because compilation generally occurs separately (e.g. because projects may reside in different - * Git repos, or because they build with different TypeScript compiler configurations that may be incompatible), - * whereas API Documenter cannot detect broken hyperlinks without seeing the entire documentation set. - * - * @public - */ -export class ApiModel extends ApiItemContainerMixin(ApiItem) { - private readonly _resolver: ModelReferenceResolver; - - private _packagesByName: Map | undefined = undefined; - - public constructor() { - super({ }); - - this._resolver = new ModelReferenceResolver(this); - } - - public loadPackage(apiJsonFilename: string): ApiPackage { - const apiPackage: ApiPackage = ApiPackage.loadFromJsonFile(apiJsonFilename); - this.addMember(apiPackage); - return apiPackage; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Model; - } - - /** @override */ - public get containerKey(): string { - return ''; - } - - public get packages(): ReadonlyArray { - return this.members as ReadonlyArray; - } - - /** @override */ - public addMember(member: ApiPackage): void { - if (member.kind !== ApiItemKind.Package) { - throw new Error('Only items of type ApiPackage may be added to an ApiModel'); - } - super.addMember(member); - - this._packagesByName = undefined; // invalidate the cache - } - - /** - * Efficiently finds a package by the NPM package name. - * - * @remarks - * - * If the NPM scope is omitted in the package name, it will still be found provided that it is an unambiguous match. - * For example, it's often convenient to write `{@link node-core-library#JsonFile}` instead of - * `{@link @rushstack/node-core-library#JsonFile}`. - */ - public tryGetPackageByName(packageName: string): ApiPackage | undefined { - // Build the lookup on demand - if (this._packagesByName === undefined) { - this._packagesByName = new Map(); - - const unscopedMap: Map = new Map(); - - for (const apiPackage of this.packages) { - if (this._packagesByName.get(apiPackage.name)) { - // This should not happen - throw new Error(`The model contains multiple packages with the name ${apiPackage.name}`); - } - - this._packagesByName.set(apiPackage.name, apiPackage); - - const unscopedName: string = PackageName.parse(apiPackage.name).unscopedName; - - if (unscopedMap.has(unscopedName)) { - // If another package has the same unscoped name, then we won't register it - unscopedMap.set(unscopedName, undefined); - } else { - unscopedMap.set(unscopedName, apiPackage); - } - } - - for (const [unscopedName, apiPackage] of unscopedMap) { - if (apiPackage) { - if (!this._packagesByName.has(unscopedName)) { - // If the unscoped name is unambiguous, then we can also use it as a lookup - this._packagesByName.set(unscopedName, apiPackage); - } - } - } - } - - return this._packagesByName.get(packageName); - } - - public resolveDeclarationReference(declarationReference: DocDeclarationReference, - contextApiItem: ApiItem | undefined): IResolveDeclarationReferenceResult { - return this._resolver.resolve(declarationReference, contextApiItem); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - return DeclarationReference.empty(); - } -} diff --git a/apps/api-extractor-model/src/model/ApiNamespace.ts b/apps/api-extractor-model/src/model/ApiNamespace.ts deleted file mode 100644 index 6745f00733d..00000000000 --- a/apps/api-extractor-model/src/model/ApiNamespace.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; -import { IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; - -/** - * Constructor options for {@link ApiClass}. - * @public - */ -export interface IApiNamespaceOptions extends - IApiItemContainerMixinOptions, - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { -} - -/** - * Represents a TypeScript namespace declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiNamespace` represents a TypeScript declaration such `X` or `Y` in this example: - * - * ```ts - * export namespace X { - * export namespace Y { - * export interface IWidget { - * render(): void; - * } - * } - * } - * ``` - * - * @public - */ -export class ApiNamespace extends ApiItemContainerMixin(ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem))) { - - public constructor(options: IApiNamespaceOptions) { - super(options); - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.Namespace}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Namespace; - } - - /** @override */ - public get containerKey(): string { - return ApiNamespace.getContainerKey(this.name); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Namespace); - } -} diff --git a/apps/api-extractor-model/src/model/ApiPackage.ts b/apps/api-extractor-model/src/model/ApiPackage.ts deleted file mode 100644 index fa6f5255c24..00000000000 --- a/apps/api-extractor-model/src/model/ApiPackage.ts +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItem, ApiItemKind, IApiItemJson } from '../items/ApiItem'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; -import { JsonFile, IJsonFileSaveOptions, PackageJsonLookup, IPackageJson } from '@rushstack/node-core-library'; -import { ApiDocumentedItem, IApiDocumentedItemOptions } from '../items/ApiDocumentedItem'; -import { ApiEntryPoint } from './ApiEntryPoint'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiPackage}. - * @public - */ -export interface IApiPackageOptions extends - IApiItemContainerMixinOptions, - IApiNameMixinOptions, - IApiDocumentedItemOptions { -} - -export interface IApiPackageMetadataJson { - /** - * The NPM package name for the tool that wrote the *.api.json file. - * For informational purposes only. - */ - toolPackage: string; - - /** - * The NPM package version for the tool that wrote the *.api.json file. - * For informational purposes only. - */ - toolVersion: string; - - /** - * The schema version for the .api.json file format. Used for determining whether the file format is - * supported, and for backwards compatibility. - */ - schemaVersion: ApiJsonSchemaVersion; - - /** - * To support forwards compatibility, the `oldestForwardsCompatibleVersion` field tracks the oldest schema version - * whose corresponding deserializer could safely load this file. - * - * @remarks - * Normally api-extractor-model should refuse to load a schema version that is newer than the latest version - * that its deserializer understands. However, sometimes a schema change may merely introduce some new fields - * without modifying or removing any existing fields. In this case, an older api-extractor-model library can - * safely deserialize the newer version (by ignoring the extra fields that it doesn't recognize). The newer - * serializer can use this field to communicate that. - * - * If present, the `oldestForwardsCompatibleVersion` must be less than or equal to - * `IApiPackageMetadataJson.schemaVersion`. - */ - oldestForwardsCompatibleVersion?: ApiJsonSchemaVersion; -} - -export interface IApiPackageJson extends IApiItemJson { - /** - * A file header that stores metadata about the tool that wrote the *.api.json file. - */ - metadata: IApiPackageMetadataJson; -} - -/** - * Options for {@link ApiPackage.saveToJsonFile}. - * @public - */ -export interface IApiPackageSaveOptions extends IJsonFileSaveOptions { - /** - * Optionally specifies a value for the "toolPackage" field in the output .api.json data file; - * otherwise, the value will be "api-extractor-model". - */ - toolPackage?: string; - - /** - * Optionally specifies a value for the "toolVersion" field in the output .api.json data file; - * otherwise, the value will be the current version of the api-extractor-model package. - */ - toolVersion?: string; - - /** - * Set to true only when invoking API Extractor's test harness. - * - * @remarks - * 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. - */ - testMode?: boolean; -} - -/** - * Represents an NPM package containing API declarations. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * @public - */ -export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumentedItem)) { - - public constructor(options: IApiPackageOptions) { - super(options); - } - - public static loadFromJsonFile(apiJsonFilename: string): ApiPackage { - const jsonObject: IApiPackageJson = JsonFile.load(apiJsonFilename); - - if (!jsonObject - || !jsonObject.metadata - || typeof jsonObject.metadata.schemaVersion !== 'number') { - throw new Error(`Error loading ${apiJsonFilename}:` - + `\nThe file format is not recognized; the "metadata.schemaVersion" field is missing or invalid`); - } - - const schemaVersion: number = jsonObject.metadata.schemaVersion; - - if (schemaVersion < ApiJsonSchemaVersion.OLDEST_SUPPORTED) { - throw new Error(`Error loading ${apiJsonFilename}:` - + `\nThe file format is version ${schemaVersion},` - + ` whereas ${ApiJsonSchemaVersion.OLDEST_SUPPORTED} is the oldest version supported by this tool`); - } - - let oldestForwardsCompatibleVersion: number = schemaVersion; - if (jsonObject.metadata.oldestForwardsCompatibleVersion) { - // Sanity check - if (jsonObject.metadata.oldestForwardsCompatibleVersion > schemaVersion) { - throw new Error(`Error loading ${apiJsonFilename}:` - + `\nInvalid file format; "oldestForwardsCompatibleVersion" cannot be newer than "schemaVersion"`); - } - oldestForwardsCompatibleVersion = jsonObject.metadata.oldestForwardsCompatibleVersion; - } - - let versionToDeserialize: number = schemaVersion; - if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) { - // If the file format is too new, can we treat it as some earlier compatible version - // as indicated by oldestForwardsCompatibleVersion? - versionToDeserialize = Math.max(oldestForwardsCompatibleVersion, ApiJsonSchemaVersion.LATEST); - - if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) { - // Nope, still too new - throw new Error(`Error loading ${apiJsonFilename}:` - + `\nThe file format version ${schemaVersion} was written by a newer release of` - + ` the api-extractor-model library; you may need to upgrade your software`); - } - } - - const context: DeserializerContext = new DeserializerContext({ - apiJsonFilename, - toolPackage: jsonObject.metadata.toolPackage, - toolVersion: jsonObject.metadata.toolVersion, - versionToDeserialize: versionToDeserialize - }); - - return ApiItem.deserialize(jsonObject, context) as ApiPackage; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Package; - } - - /** @override */ - public get containerKey(): string { - // No prefix needed, because ApiPackage is the only possible member of an ApiModel - return this.name; - } - - public get entryPoints(): ReadonlyArray { - return this.members as ReadonlyArray; - } - - /** @override */ - public addMember(member: ApiEntryPoint): void { - if (member.kind !== ApiItemKind.EntryPoint) { - throw new Error('Only items of type ApiEntryPoint may be added to an ApiPackage'); - } - super.addMember(member); - } - - public findEntryPointsByPath(importPath: string): ReadonlyArray { - return this.findMembersByName(importPath) as ReadonlyArray; - } - - public saveToJsonFile(apiJsonFilename: string, options?: IApiPackageSaveOptions): void { - if (!options) { - options = {}; - } - - const packageJson: IPackageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); - - const jsonObject: IApiPackageJson = { - metadata: { - toolPackage: options.toolPackage || packageJson.name, - // In test mode, we don't write the real version, since that would cause spurious diffs whenever - // the version is bumped. Instead we write a placeholder string. - toolVersion: options.testMode ? '[test mode]' : options.toolVersion || packageJson.version, - schemaVersion: ApiJsonSchemaVersion.LATEST, - oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE - } - } as IApiPackageJson; - this.serializeInto(jsonObject); - JsonFile.save(jsonObject, apiJsonFilename, options); - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - return DeclarationReference.package(this.name); - } -} diff --git a/apps/api-extractor-model/src/model/ApiProperty.ts b/apps/api-extractor-model/src/model/ApiProperty.ts deleted file mode 100644 index 909a9f815ef..00000000000 --- a/apps/api-extractor-model/src/model/ApiProperty.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiStaticMixin, IApiStaticMixinOptions } from '../mixins/ApiStaticMixin'; -import { ApiPropertyItem, IApiPropertyItemOptions } from '../items/ApiPropertyItem'; - -/** - * Constructor options for {@link ApiProperty}. - * @public - */ -export interface IApiPropertyOptions extends IApiPropertyItemOptions, - IApiStaticMixinOptions { -} - -/** - * Represents a TypeScript property declaration that belongs to an `ApiClass`. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiProperty` represents a TypeScript declaration such as the `width` and `height` members in this example: - * - * ```ts - * export class Widget { - * public width: number = 100; - * - * public get height(): number { - * if (this.isSquashed()) { - * return 0; - * } else { - * return this.clientArea.height; - * } - * } - * } - * ``` - * - * Note that member variables are also considered to be properties. - * - * If the property has both a getter function and setter function, they will be represented by a single `ApiProperty` - * and must have a single documentation comment. - * - * Compare with {@link ApiPropertySignature}, which represents a property belonging to an interface. - * For example, a class property can be `static` but an interface property cannot. - * - * @public - */ -export class ApiProperty extends ApiStaticMixin(ApiPropertyItem) { - - public constructor(options: IApiPropertyOptions) { - super(options); - } - - public static getContainerKey(name: string, isStatic: boolean): string { - if (isStatic) { - return `${name}|${ApiItemKind.Property}|static`; - } else { - return `${name}|${ApiItemKind.Property}|instance`; - } - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Property; - } - - /** @override */ - public get containerKey(): string { - return ApiProperty.getContainerKey(this.name, this.isStatic); - } - - /** @beta @override */ - public 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) - .withMeaning(Meaning.Member); - } -} diff --git a/apps/api-extractor-model/src/model/ApiTypeAlias.ts b/apps/api-extractor-model/src/model/ApiTypeAlias.ts deleted file mode 100644 index 47e61c354c9..00000000000 --- a/apps/api-extractor-model/src/model/ApiTypeAlias.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { ApiTypeParameterListMixin, IApiTypeParameterListMixinOptions, IApiTypeParameterListMixinJson - } from '../mixins/ApiTypeParameterListMixin'; -import { DeserializerContext } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiTypeAlias}. - * @public - */ -export interface IApiTypeAliasOptions extends - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions, - IApiTypeParameterListMixinOptions { - typeTokenRange: IExcerptTokenRange; -} - -export interface IApiTypeAliasJson extends - IApiDeclaredItemJson, - IApiTypeParameterListMixinJson { - typeTokenRange: IExcerptTokenRange; -} - -/** - * Represents a TypeScript type alias declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiTypeAlias` represents a definition such as one of these examples: - * - * ```ts - * // A union type: - * export type Shape = Square | Triangle | Circle; - * - * // A generic type alias: - * export type BoxedValue = { value: T }; - * - * export type BoxedArray = { array: T[] }; - * - * // A conditional type alias: - * export type Boxed = T extends any[] ? BoxedArray : BoxedValue; - * - * ``` - * - * @public - */ -export class ApiTypeAlias extends ApiTypeParameterListMixin(ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem))) { - /** - * An {@link Excerpt} that describes the type of the alias. - * - * @remarks - * In the example below, the `typeExcerpt` would correspond to the subexpression - * `T extends any[] ? BoxedArray : BoxedValue;`: - * - * ```ts - * export type Boxed = T extends any[] ? BoxedArray : BoxedValue; - * ``` - */ - public readonly typeExcerpt: Excerpt; - - public constructor(options: IApiTypeAliasOptions) { - super(options); - - this.typeExcerpt = this.buildExcerpt(options.typeTokenRange); - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiTypeAliasJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.typeTokenRange = jsonObject.typeTokenRange; - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.TypeAlias}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.TypeAlias; - } - - /** @override */ - public get containerKey(): string { - return ApiTypeAlias.getContainerKey(this.name); - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - jsonObject.typeTokenRange = this.typeExcerpt.tokenRange; - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.TypeAlias); - } -} diff --git a/apps/api-extractor-model/src/model/ApiVariable.ts b/apps/api-extractor-model/src/model/ApiVariable.ts deleted file mode 100644 index d2323611a29..00000000000 --- a/apps/api-extractor-model/src/model/ApiVariable.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { ApiItemKind } from '../items/ApiItem'; -import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; -import { IExcerptTokenRange, Excerpt } from '../mixins/Excerpt'; -import { DeserializerContext } from './DeserializerContext'; - -/** - * Constructor options for {@link ApiVariable}. - * @public - */ -export interface IApiVariableOptions extends - IApiNameMixinOptions, - IApiReleaseTagMixinOptions, - IApiDeclaredItemOptions { - - variableTypeTokenRange: IExcerptTokenRange; -} - -export interface IApiVariableJson extends IApiDeclaredItemJson { - variableTypeTokenRange: IExcerptTokenRange; -} - -/** - * Represents a TypeScript variable declaration. - * - * @remarks - * - * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of - * API declarations. - * - * `ApiVariable` represents an exported `const` or `let` object such as these examples: - * - * ```ts - * // A variable declaration - * export let verboseLogging: boolean; - * - * // A constant variable declaration with an initializer - * export const canvas: IWidget = createCanvas(); - * ``` - * - * @public - */ -export class ApiVariable extends ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem)) { - /** - * An {@link Excerpt} that describes the type of the variable. - */ - public readonly variableTypeExcerpt: Excerpt; - - public constructor(options: IApiVariableOptions) { - super(options); - - this.variableTypeExcerpt = this.buildExcerpt(options.variableTypeTokenRange); - } - - /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiVariableJson): void { - - super.onDeserializeInto(options, context, jsonObject); - - options.variableTypeTokenRange = jsonObject.variableTypeTokenRange; - } - - public static getContainerKey(name: string): string { - return `${name}|${ApiItemKind.Variable}`; - } - - /** @override */ - public get kind(): ApiItemKind { - return ApiItemKind.Variable; - } - - /** @override */ - public get containerKey(): string { - return ApiVariable.getContainerKey(this.name); - } - - /** @override */ - public serializeInto(jsonObject: Partial): void { - super.serializeInto(jsonObject); - - jsonObject.variableTypeTokenRange = this.variableTypeExcerpt.tokenRange; - } - - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { - const nameComponent: Component = DeclarationReference.parseComponent(this.name); - return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) - .addNavigationStep(Navigation.Exports, nameComponent) - .withMeaning(Meaning.Variable); - } -} diff --git a/apps/api-extractor-model/src/model/Deserializer.ts b/apps/api-extractor-model/src/model/Deserializer.ts deleted file mode 100644 index 50a22c0146f..00000000000 --- a/apps/api-extractor-model/src/model/Deserializer.ts +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { IApiItemJson, IApiItemOptions, ApiItem, ApiItemKind } from '../items/ApiItem'; -import { ApiClass, IApiClassOptions, IApiClassJson } from './ApiClass'; -import { ApiEntryPoint, IApiEntryPointOptions } from './ApiEntryPoint'; -import { ApiMethod, IApiMethodOptions } from './ApiMethod'; -import { ApiModel } from './ApiModel'; -import { ApiNamespace, IApiNamespaceOptions } from './ApiNamespace'; -import { ApiPackage, IApiPackageOptions } from './ApiPackage'; -import { ApiInterface, IApiInterfaceOptions, IApiInterfaceJson } from './ApiInterface'; -import { ApiPropertySignature, IApiPropertySignatureOptions } from './ApiPropertySignature'; -import { ApiMethodSignature, IApiMethodSignatureOptions } from './ApiMethodSignature'; -import { ApiProperty, IApiPropertyOptions } from './ApiProperty'; -import { ApiEnumMember, IApiEnumMemberOptions, IApiEnumMemberJson } from './ApiEnumMember'; -import { ApiEnum, IApiEnumOptions } from './ApiEnum'; -import { IApiPropertyItemJson } from '../items/ApiPropertyItem'; -import { ApiConstructor, IApiConstructorOptions } from './ApiConstructor'; -import { ApiConstructSignature, IApiConstructSignatureOptions } from './ApiConstructSignature'; -import { ApiFunction, IApiFunctionOptions } from './ApiFunction'; -import { ApiCallSignature, IApiCallSignatureOptions } from './ApiCallSignature'; -import { ApiIndexSignature, IApiIndexSignatureOptions } from './ApiIndexSignature'; -import { ApiTypeAlias, IApiTypeAliasOptions, IApiTypeAliasJson } from './ApiTypeAlias'; -import { ApiVariable, IApiVariableOptions, IApiVariableJson } from './ApiVariable'; -import { IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; -import { DeserializerContext } from './DeserializerContext'; - -export class Deserializer { - public static deserialize(context: DeserializerContext, jsonObject: IApiItemJson): ApiItem { - const options: Partial = { }; - - switch (jsonObject.kind) { - case ApiItemKind.Class: - ApiClass.onDeserializeInto(options, context, jsonObject as IApiClassJson); - return new ApiClass(options as IApiClassOptions); - case ApiItemKind.CallSignature: - ApiCallSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiCallSignature(options as IApiCallSignatureOptions); - case ApiItemKind.Constructor: - ApiConstructor.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiConstructor(options as IApiConstructorOptions); - case ApiItemKind.ConstructSignature: - ApiConstructSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiConstructSignature(options as IApiConstructSignatureOptions); - case ApiItemKind.EntryPoint: - ApiEntryPoint.onDeserializeInto(options, context, jsonObject); - return new ApiEntryPoint(options as IApiEntryPointOptions); - case ApiItemKind.Enum: - ApiEnum.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiEnum(options as IApiEnumOptions); - case ApiItemKind.EnumMember: - ApiEnumMember.onDeserializeInto(options, context, jsonObject as IApiEnumMemberJson); - return new ApiEnumMember(options as IApiEnumMemberOptions); - case ApiItemKind.Function: - ApiFunction.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiFunction(options as IApiFunctionOptions); - case ApiItemKind.IndexSignature: - ApiIndexSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiIndexSignature(options as IApiIndexSignatureOptions); - case ApiItemKind.Interface: - ApiInterface.onDeserializeInto(options, context, jsonObject as IApiInterfaceJson); - return new ApiInterface(options as IApiInterfaceOptions); - case ApiItemKind.Method: - ApiMethod.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiMethod(options as IApiMethodOptions); - case ApiItemKind.MethodSignature: - ApiMethodSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiMethodSignature(options as IApiMethodSignatureOptions); - case ApiItemKind.Model: - return new ApiModel(); - case ApiItemKind.Namespace: - ApiNamespace.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); - return new ApiNamespace(options as IApiNamespaceOptions); - case ApiItemKind.Package: - ApiPackage.onDeserializeInto(options, context, jsonObject); - return new ApiPackage(options as IApiPackageOptions); - case ApiItemKind.Property: - ApiProperty.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson); - return new ApiProperty(options as IApiPropertyOptions); - case ApiItemKind.PropertySignature: - ApiPropertySignature.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson); - return new ApiPropertySignature(options as IApiPropertySignatureOptions); - case ApiItemKind.TypeAlias: - ApiTypeAlias.onDeserializeInto(options, context, jsonObject as IApiTypeAliasJson); - return new ApiTypeAlias(options as IApiTypeAliasOptions); - case ApiItemKind.Variable: - ApiVariable.onDeserializeInto(options, context, jsonObject as IApiVariableJson); - return new ApiVariable(options as IApiVariableOptions); - default: - throw new Error(`Failed to deserialize unsupported API item type ${JSON.stringify(jsonObject.kind)}`); - } - } -} diff --git a/apps/api-extractor-model/src/model/DeserializerContext.ts b/apps/api-extractor-model/src/model/DeserializerContext.ts deleted file mode 100644 index 62fa4f81391..00000000000 --- a/apps/api-extractor-model/src/model/DeserializerContext.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export enum ApiJsonSchemaVersion { - /** - * The initial release. - */ - V_1000 = 1000, - - /** - * Add support for type parameters and type alias types. - */ - V_1001 = 1001, - - /** - * Remove "canonicalReference" field. This field was for diagnostic purposes only and was never deserialized. - */ - V_1002 = 1002, - - /** - * Reintroduce the "canonicalReference" field using the experimental new TSDoc declaration reference notation. - * - * This is not a breaking change because this field is never deserialized; it is provided for informational - * purposes only. - */ - V_1003 = 1003, - - /** - * The current latest .api.json schema version. - * - * IMPORTANT: When incrementing this number, consider whether `OLDEST_SUPPORTED` or `OLDEST_FORWARDS_COMPATIBLE` - * should be updated. - */ - LATEST = V_1003, - - /** - * The oldest .api.json schema version that is still supported for backwards compatibility. - * - * This must be updated if you change to the file format and do not implement compatibility logic for - * deserializing the older representation. - */ - OLDEST_SUPPORTED = V_1001, - - /** - * Used to assign `IApiPackageMetadataJson.oldestForwardsCompatibleVersion`. - * - * This value must be \<= `ApiJsonSchemaVersion.LATEST`. It must be reset to the `LATEST` value - * if the older library would not be able to deserialize your new file format. Adding a nonessential field - * is generally okay. Removing, modifying, or reinterpreting existing fields is NOT safe. - */ - OLDEST_FORWARDS_COMPATIBLE = V_1001 -} - -export class DeserializerContext { - /** - * The path of the file being deserialized, which may be useful for diagnostic purposes. - */ - public readonly apiJsonFilename: string; - - /** - * Metadata from `IApiPackageMetadataJson.toolPackage`. - */ - public readonly toolPackage: string; - - /** - * Metadata from `IApiPackageMetadataJson.toolVersion`. - */ - public readonly toolVersion: string; - - /** - * The version of the schema being deserialized, as obtained from `IApiPackageMetadataJson.schemaVersion`. - */ - public readonly versionToDeserialize: ApiJsonSchemaVersion; - - public constructor(options: DeserializerContext) { - this.apiJsonFilename = options.apiJsonFilename; - this.toolPackage = options.toolPackage; - this.toolVersion = options.toolVersion; - this.versionToDeserialize = options.versionToDeserialize; - } -} diff --git a/apps/api-extractor-model/src/model/ModelReferenceResolver.ts b/apps/api-extractor-model/src/model/ModelReferenceResolver.ts deleted file mode 100644 index 49608560616..00000000000 --- a/apps/api-extractor-model/src/model/ModelReferenceResolver.ts +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { DocDeclarationReference, SelectorKind } from '@microsoft/tsdoc'; -import { ApiItem } from '../items/ApiItem'; -import { ApiModel } from './ApiModel'; -import { ApiPackage } from './ApiPackage'; -import { ApiEntryPoint } from './ApiEntryPoint'; -import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; -import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; - -/** - * Result object for {@link ApiModel.resolveDeclarationReference}. - * - * @public - */ -export interface IResolveDeclarationReferenceResult { - /** - * The referenced ApiItem, if the declaration reference could be resolved. - */ - resolvedApiItem: ApiItem | undefined; - - /** - * If resolvedApiItem is undefined, then this will always contain an error message explaining why the - * resolution failed. - */ - errorMessage: string | undefined; -} - -/** - * This resolves a TSDoc declaration reference by walking the `ApiModel` hierarchy. - * - * @remarks - * - * This class is analogous to `AstReferenceResolver` from the `@microsoft/api-extractor` project, - * which resolves declaration references by walking the compiler state. - */ -export class ModelReferenceResolver { - private readonly _apiModel: ApiModel; - - public constructor(apiModel: ApiModel) { - this._apiModel = apiModel; - } - - public resolve(declarationReference: DocDeclarationReference, - contextApiItem: ApiItem | undefined): IResolveDeclarationReferenceResult { - - const result: IResolveDeclarationReferenceResult = { - resolvedApiItem: undefined, - errorMessage: undefined - }; - - let apiPackage: ApiPackage | undefined = undefined; - - // Is this an absolute reference? - if (declarationReference.packageName !== undefined) { - apiPackage = this._apiModel.tryGetPackageByName(declarationReference.packageName); - if (apiPackage === undefined) { - result.errorMessage = `The package "${declarationReference.packageName}" could not be located`; - return result; - } - } else { - // If the package name is omitted, try to infer it from the context - if (contextApiItem !== undefined) { - apiPackage = contextApiItem.getAssociatedPackage(); - } - - if (apiPackage === undefined) { - result.errorMessage = `The reference does not include a package name, and the package could not be inferred` - + ` from the context`; - return result; - } - } - - const importPath: string = declarationReference.importPath || ''; - - const foundEntryPoints: ReadonlyArray = apiPackage.findEntryPointsByPath(importPath); - if (foundEntryPoints.length !== 1) { - result.errorMessage = `The import path "${importPath}" could not be resolved`; - return result; - } - - let currentItem: ApiItem = foundEntryPoints[0]; - - // Now search for the member reference - for (const memberReference of declarationReference.memberReferences) { - if (memberReference.memberSymbol !== undefined) { - result.errorMessage = `Symbols are not yet supported in declaration references` ; - return result; - } - - if (memberReference.memberIdentifier === undefined) { - result.errorMessage = `Missing member identifier`; - return result; - } - - const identifier: string = memberReference.memberIdentifier.identifier; - - if (!ApiItemContainerMixin.isBaseClassOf(currentItem)) { - // For example, {@link MyClass.myMethod.X} is invalid because methods cannot contain members - result.errorMessage = `Unable to resolve ${JSON.stringify(identifier)} because ${JSON.stringify(currentItem)}` - + ` cannot act as a container`; - return result; - } - - const foundMembers: ReadonlyArray = currentItem.findMembersByName(identifier); - if (foundMembers.length === 0) { - result.errorMessage = `The member reference ${JSON.stringify(identifier)} was not found` ; - return result; - } - if (foundMembers.length > 1) { - if (memberReference.selector && memberReference.selector.selectorKind === SelectorKind.Index) { - const selectedMembers: ApiItem[] = []; - - const selectorOverloadIndex: number = parseInt(memberReference.selector.selector); - for (const foundMember of foundMembers) { - if (ApiParameterListMixin.isBaseClassOf(foundMember)) { - if (foundMember.overloadIndex === selectorOverloadIndex) { - selectedMembers.push(foundMember); - } - } - } - - if (selectedMembers.length === 0) { - result.errorMessage = `An overload for ${JSON.stringify(identifier)} was not found that matches` - + ` the TSDoc selector ":${selectorOverloadIndex}"`; - return result; - } - - if (selectedMembers.length === 1) { - result.resolvedApiItem = selectedMembers[0]; - return result; - } - } - - // TODO: Support other TSDoc selectors - result.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous` ; - return result; - } - - currentItem = foundMembers[0]; - } - result.resolvedApiItem = currentItem; - return result; - } - -} diff --git a/apps/api-extractor-model/tsconfig.json b/apps/api-extractor-model/tsconfig.json deleted file mode 100644 index 824a88b71e5..00000000000 --- a/apps/api-extractor-model/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } -} diff --git a/apps/api-extractor/.eslintrc.js b/apps/api-extractor/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/apps/api-extractor/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/apps/api-extractor/.npmignore b/apps/api-extractor/.npmignore index e2cbe1efa92..8b61d7caa66 100644 --- a/apps/api-extractor/.npmignore +++ b/apps/api-extractor/.npmignore @@ -1,24 +1,33 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- +!/extends/*.json diff --git a/apps/api-extractor/.vscode/launch.json b/apps/api-extractor/.vscode/launch.json index a5b20c7e2e4..b9c74c3b15e 100644 --- a/apps/api-extractor/.vscode/launch.json +++ b/apps/api-extractor/.vscode/launch.json @@ -4,17 +4,32 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Run in specified folder", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "(your project path)", + "args": ["--debug", "run", "--local"], + "sourceMaps": true + }, { "type": "node", "request": "launch", "name": "test-01", "program": "${workspaceFolder}/lib/start.js", "cwd": "${workspaceFolder}/../../build-tests/api-extractor-test-01", - "args": [ - "--debug", - "run", - "--local" - ], + "args": ["--debug", "run", "--local"], "sourceMaps": true }, { @@ -23,11 +38,7 @@ "name": "test-02", "program": "${workspaceFolder}/lib/start.js", "cwd": "${workspaceFolder}/../../build-tests/api-extractor-test-02", - "args": [ - "--debug", - "run", - "--local" - ], + "args": ["--debug", "run", "--local"], "sourceMaps": true }, { @@ -36,11 +47,7 @@ "name": "test-03", "program": "${workspaceFolder}/lib/start.js", "cwd": "${workspaceFolder}/../../build-tests/api-extractor-test-03", - "args": [ - "--debug", - "run", - "--local" - ], + "args": ["--debug", "run", "--local"], "sourceMaps": true }, { @@ -49,11 +56,7 @@ "name": "test-04", "program": "${workspaceFolder}/lib/start.js", "cwd": "${workspaceFolder}/../../build-tests/api-extractor-test-04", - "args": [ - "--debug", - "run", - "--local" - ], + "args": ["--debug", "run", "--local"], "sourceMaps": true }, { @@ -62,11 +65,7 @@ "name": "test-05", "program": "${workspaceFolder}/lib/start.js", "cwd": "${workspaceFolder}/../../build-tests/api-extractor-test-05", - "args": [ - "--debug", - "run", - "--local" - ], + "args": ["--debug", "run", "--local"], "sourceMaps": true }, { @@ -80,20 +79,7 @@ "run", "--local", "--config", - "./temp/configs/api-extractor-typeof.json" - ], - "sourceMaps": true - }, - { - "type": "node", - "request": "launch", - "name": "scratch", - "program": "${workspaceFolder}/lib/start.js", - "cwd": "(your project path)", - "args": [ - "--debug", - "run", - "--local" + "./temp/configs/api-extractor-spanSorting.json" ], "sourceMaps": true } diff --git a/apps/api-extractor/CHANGELOG.json b/apps/api-extractor/CHANGELOG.json index 842f4383f7b..a714ac42023 100644 --- a/apps/api-extractor/CHANGELOG.json +++ b/apps/api-extractor/CHANGELOG.json @@ -1,6 +1,4566 @@ { "name": "@microsoft/api-extractor", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + } + ] + } + }, + { + "version": "7.48.0", + "tag": "@microsoft/api-extractor_v7.48.0", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "minor": [ + { + "comment": "Update TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.0`" + } + ] + } + }, + { + "version": "7.47.12", + "tag": "@microsoft/api-extractor_v7.47.12", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + } + ] + } + }, + { + "version": "7.47.11", + "tag": "@microsoft/api-extractor_v7.47.11", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + } + ] + } + }, + { + "version": "7.47.10", + "tag": "@microsoft/api-extractor_v7.47.10", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a compatibility issue with usage of `getModeForUsageLocation` in TypeScript 5.6" + } + ] + } + }, + { + "version": "7.47.9", + "tag": "@microsoft/api-extractor_v7.47.9", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + } + ] + } + }, + { + "version": "7.47.8", + "tag": "@microsoft/api-extractor_v7.47.8", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + } + ] + } + }, + { + "version": "7.47.7", + "tag": "@microsoft/api-extractor_v7.47.7", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + } + ] + } + }, + { + "version": "7.47.6", + "tag": "@microsoft/api-extractor_v7.47.6", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + } + ] + } + }, + { + "version": "7.47.5", + "tag": "@microsoft/api-extractor_v7.47.5", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + } + ] + } + }, + { + "version": "7.47.4", + "tag": "@microsoft/api-extractor_v7.47.4", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + } + ] + } + }, + { + "version": "7.47.3", + "tag": "@microsoft/api-extractor_v7.47.3", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an edge case when discarding the file extension from the \"reportFileName\" setting and improve its documentation" + } + ] + } + }, + { + "version": "7.47.2", + "tag": "@microsoft/api-extractor_v7.47.2", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + } + ] + } + }, + { + "version": "7.47.1", + "tag": "@microsoft/api-extractor_v7.47.1", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + } + ] + } + }, + { + "version": "7.47.0", + "tag": "@microsoft/api-extractor_v7.47.0", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for re-exporting modules using syntax such as `export * as ns from './file'` (GitHub #2780)" + } + ] + } + }, + { + "version": "7.46.2", + "tag": "@microsoft/api-extractor_v7.46.2", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.0`" + } + ] + } + }, + { + "version": "7.46.1", + "tag": "@microsoft/api-extractor_v7.46.1", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.5`" + } + ] + } + }, + { + "version": "7.46.0", + "tag": "@microsoft/api-extractor_v7.46.0", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Bump TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.29.0`" + } + ] + } + }, + { + "version": "7.45.1", + "tag": "@microsoft/api-extractor_v7.45.1", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.4`" + } + ] + } + }, + { + "version": "7.45.0", + "tag": "@microsoft/api-extractor_v7.45.0", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "minor": [ + { + "comment": "Improve support for resolving the `tsdoc-metadata.json` to include the folder referenced by a `types` field in an `\"exports\"` field and an `\"typesVersions\"` field in addition to `\"types\"`, `\"typings\"`, and `\"tsdocMetadata\"` fields." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.3`" + } + ] + } + }, + { + "version": "7.44.1", + "tag": "@microsoft/api-extractor_v7.44.1", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.2`" + } + ] + } + }, + { + "version": "7.44.0", + "tag": "@microsoft/api-extractor_v7.44.0", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for \"variants\" of API reports which include or exclude items by release tag" + } + ] + } + }, + { + "version": "7.43.8", + "tag": "@microsoft/api-extractor_v7.43.8", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.1`" + } + ] + } + }, + { + "version": "7.43.7", + "tag": "@microsoft/api-extractor_v7.43.7", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.0`" + } + ] + } + }, + { + "version": "7.43.6", + "tag": "@microsoft/api-extractor_v7.43.6", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.1`" + } + ] + } + }, + { + "version": "7.43.5", + "tag": "@microsoft/api-extractor_v7.43.5", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.0`" + } + ] + } + }, + { + "version": "7.43.4", + "tag": "@microsoft/api-extractor_v7.43.4", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.5`" + } + ] + } + }, + { + "version": "7.43.3", + "tag": "@microsoft/api-extractor_v7.43.3", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.4`" + } + ] + } + }, + { + "version": "7.43.2", + "tag": "@microsoft/api-extractor_v7.43.2", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.3`" + } + ] + } + }, + { + "version": "7.43.1", + "tag": "@microsoft/api-extractor_v7.43.1", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.2`" + } + ] + } + }, + { + "version": "7.43.0", + "tag": "@microsoft/api-extractor_v7.43.0", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.4.2" + } + ] + } + }, + { + "version": "7.42.3", + "tag": "@microsoft/api-extractor_v7.42.3", + "date": "Sun, 03 Mar 2024 20:58:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.1`" + } + ] + } + }, + { + "version": "7.42.2", + "tag": "@microsoft/api-extractor_v7.42.2", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.0`" + } + ] + } + }, + { + "version": "7.42.1", + "tag": "@microsoft/api-extractor_v7.42.1", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.1`" + } + ] + } + }, + { + "version": "7.42.0", + "tag": "@microsoft/api-extractor_v7.42.0", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "patch": [ + { + "comment": "Don't mark items documented with {@inheritDoc} references to package-external items as \"undocumented\"" + } + ], + "minor": [ + { + "comment": "Add glob support in `bundledPackages`" + } + ] + } + }, + { + "version": "7.41.1", + "tag": "@microsoft/api-extractor_v7.41.1", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.0`" + } + ] + } + }, + { + "version": "7.41.0", + "tag": "@microsoft/api-extractor_v7.41.0", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "minor": [ + { + "comment": "Replace const enums with conventional enums to allow for compatibility with JavaScript consumers." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.4`" + } + ] + } + }, + { + "version": "7.40.6", + "tag": "@microsoft/api-extractor_v7.40.6", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.3`" + } + ] + } + }, + { + "version": "7.40.5", + "tag": "@microsoft/api-extractor_v7.40.5", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where imports were trimmed from external packages based when generating .d.ts rollups" + } + ] + } + }, + { + "version": "7.40.4", + "tag": "@microsoft/api-extractor_v7.40.4", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + } + ] + } + }, + { + "version": "7.40.3", + "tag": "@microsoft/api-extractor_v7.40.3", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + } + ] + } + }, + { + "version": "7.40.2", + "tag": "@microsoft/api-extractor_v7.40.2", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.2`" + } + ] + } + }, + { + "version": "7.40.1", + "tag": "@microsoft/api-extractor_v7.40.1", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + } + ] + } + }, + { + "version": "7.40.0", + "tag": "@microsoft/api-extractor_v7.40.0", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "minor": [ + { + "comment": "Classify arrow functions as `function` kind in the doc model export." + } + ] + } + }, + { + "version": "7.39.5", + "tag": "@microsoft/api-extractor_v7.39.5", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + } + ] + } + }, + { + "version": "7.39.4", + "tag": "@microsoft/api-extractor_v7.39.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + } + ] + } + }, + { + "version": "7.39.3", + "tag": "@microsoft/api-extractor_v7.39.3", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + } + ] + } + }, + { + "version": "7.39.2", + "tag": "@microsoft/api-extractor_v7.39.2", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + } + ] + } + }, + { + "version": "7.39.1", + "tag": "@microsoft/api-extractor_v7.39.1", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + } + ] + } + }, + { + "version": "7.39.0", + "tag": "@microsoft/api-extractor_v7.39.0", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "minor": [ + { + "comment": "Update API Extractor to support TypeScript 5.3.3" + } + ] + } + }, + { + "version": "7.38.5", + "tag": "@microsoft/api-extractor_v7.38.5", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + } + ] + } + }, + { + "version": "7.38.4", + "tag": "@microsoft/api-extractor_v7.38.4", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "patch": [ + { + "comment": "Don't export trimmed namespace members during rollup (#2791)" + } + ] + } + }, + { + "version": "7.38.3", + "tag": "@microsoft/api-extractor_v7.38.3", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where \"ae-undocumented\" was incorrectly reported for private members" + } + ] + } + }, + { + "version": "7.38.2", + "tag": "@microsoft/api-extractor_v7.38.2", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.1`" + } + ] + } + }, + { + "version": "7.38.1", + "tag": "@microsoft/api-extractor_v7.38.1", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.0`" + } + ] + } + }, + { + "version": "7.38.0", + "tag": "@microsoft/api-extractor_v7.38.0", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new message \"ae-undocumented\" to support logging of undocumented API items" + } + ] + } + }, + { + "version": "7.37.3", + "tag": "@microsoft/api-extractor_v7.37.3", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "patch": [ + { + "comment": "Don't strip out @alpha items when generating API reports." + } + ] + } + }, + { + "version": "7.37.2", + "tag": "@microsoft/api-extractor_v7.37.2", + "date": "Thu, 28 Sep 2023 20:53:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + } + ] + } + }, + { + "version": "7.37.1", + "tag": "@microsoft/api-extractor_v7.37.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.1`" + } + ] + } + }, + { + "version": "7.37.0", + "tag": "@microsoft/api-extractor_v7.37.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "7.36.4", + "tag": "@microsoft/api-extractor_v7.36.4", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "7.36.3", + "tag": "@microsoft/api-extractor_v7.36.3", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + } + ] + } + }, + { + "version": "7.36.2", + "tag": "@microsoft/api-extractor_v7.36.2", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "patch": [ + { + "comment": "Add api-extractor support for .d.mts and .d.cts files" + } + ] + } + }, + { + "version": "7.36.1", + "tag": "@microsoft/api-extractor_v7.36.1", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + } + ] + } + }, + { + "version": "7.36.0", + "tag": "@microsoft/api-extractor_v7.36.0", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "minor": [ + { + "comment": "Use the `IRigConfig` interface in the `IExtractorConfigLoadForFolderOptions` object insteacd of the `RigConfig` class." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.0`" + } + ] + } + }, + { + "version": "7.35.4", + "tag": "@microsoft/api-extractor_v7.35.4", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "7.35.3", + "tag": "@microsoft/api-extractor_v7.35.3", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.0`" + } + ] + } + }, + { + "version": "7.35.2", + "tag": "@microsoft/api-extractor_v7.35.2", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "7.35.1", + "tag": "@microsoft/api-extractor_v7.35.1", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + } + ] + } + }, + { + "version": "7.35.0", + "tag": "@microsoft/api-extractor_v7.35.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the TypeScript dependency to ~5.0.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "7.34.9", + "tag": "@microsoft/api-extractor_v7.34.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + } + ] + } + }, + { + "version": "7.34.8", + "tag": "@microsoft/api-extractor_v7.34.8", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.8`" + } + ] + } + }, + { + "version": "7.34.7", + "tag": "@microsoft/api-extractor_v7.34.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + } + ] + } + }, + { + "version": "7.34.6", + "tag": "@microsoft/api-extractor_v7.34.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + } + ] + } + }, + { + "version": "7.34.5", + "tag": "@microsoft/api-extractor_v7.34.5", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + } + ] + } + }, + { + "version": "7.34.4", + "tag": "@microsoft/api-extractor_v7.34.4", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "7.34.3", + "tag": "@microsoft/api-extractor_v7.34.3", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + } + ] + } + }, + { + "version": "7.34.2", + "tag": "@microsoft/api-extractor_v7.34.2", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + } + ] + } + }, + { + "version": "7.34.1", + "tag": "@microsoft/api-extractor_v7.34.1", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + } + ] + } + }, + { + "version": "7.34.0", + "tag": "@microsoft/api-extractor_v7.34.0", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "minor": [ + { + "comment": "Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.26.0`" + } + ] + } + }, + { + "version": "7.33.8", + "tag": "@microsoft/api-extractor_v7.33.8", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "patch": [ + { + "comment": "Use ts.getCheckFlags to fix TS 5.0" + } + ] + } + }, + { + "version": "7.33.7", + "tag": "@microsoft/api-extractor_v7.33.7", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + } + ] + } + }, + { + "version": "7.33.6", + "tag": "@microsoft/api-extractor_v7.33.6", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.1`" + } + ] + } + }, + { + "version": "7.33.5", + "tag": "@microsoft/api-extractor_v7.33.5", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "patch": [ + { + "comment": "Update the @microsoft/tsdoc dependency version to 0.14.2." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.2`" + } + ] + } + }, + { + "version": "7.33.4", + "tag": "@microsoft/api-extractor_v7.33.4", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.0`" + } + ] + } + }, + { + "version": "7.33.3", + "tag": "@microsoft/api-extractor_v7.33.3", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where the \"fileUrlPath\" property would contain a malformed path when API Extractor is run on Windows." + } + ] + } + }, + { + "version": "7.33.2", + "tag": "@microsoft/api-extractor_v7.33.2", + "date": "Fri, 14 Oct 2022 15:26:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix references from computed properties #3629" + } + ] + } + }, + { + "version": "7.33.1", + "tag": "@microsoft/api-extractor_v7.33.1", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + } + ] + } + }, + { + "version": "7.33.0", + "tag": "@microsoft/api-extractor_v7.33.0", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "minor": [ + { + "comment": "Extract the original source file path for relevant API items and add a new projectFolderUrl setting to the api-extractor.json config that allows one to specify what URL their project folder can be found at." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.25.0`" + } + ] + } + }, + { + "version": "7.32.1", + "tag": "@microsoft/api-extractor_v7.32.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "7.32.0", + "tag": "@microsoft/api-extractor_v7.32.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Update parser to TypeScript 4.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "7.31.2", + "tag": "@microsoft/api-extractor_v7.31.2", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + } + ] + } + }, + { + "version": "7.31.1", + "tag": "@microsoft/api-extractor_v7.31.1", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "7.31.0", + "tag": "@microsoft/api-extractor_v7.31.0", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where aliased classes sometimes had incorrect canonical references in *.api.json (GitHub #3593)" + } + ] + } + }, + { + "version": "7.30.1", + "tag": "@microsoft/api-extractor_v7.30.1", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a recent regression where items exported from both the entry point and from an exported namespace appeared only once in the API doc model (GitHub #3619)" + } + ] + } + }, + { + "version": "7.30.0", + "tag": "@microsoft/api-extractor_v7.30.0", + "date": "Fri, 02 Sep 2022 17:48:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add new \"apiReport.includeForgottenExports\" and \"docModel.includeForgottenExports\" properties to control whether forgotten exports are included in the API report and doc model files." + }, + { + "comment": "Fix incorrect declaration references for symbols not exported from the package's entry point." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.24.0`" + } + ] + } + }, + { + "version": "7.29.5", + "tag": "@microsoft/api-extractor_v7.29.5", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + } + ] + } + }, + { + "version": "7.29.4", + "tag": "@microsoft/api-extractor_v7.29.4", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "patch": [ + { + "comment": "Remove use of LegacyAdapters.sortStable" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + } + ] + } + }, + { + "version": "7.29.3", + "tag": "@microsoft/api-extractor_v7.29.3", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + } + ] + } + }, + { + "version": "7.29.2", + "tag": "@microsoft/api-extractor_v7.29.2", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "patch": [ + { + "comment": "Fix incorrect declaration references for local symbols within namespaces" + } + ] + } + }, + { + "version": "7.29.1", + "tag": "@microsoft/api-extractor_v7.29.1", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where .api.json excerpts were sometimes missing tokens (GitHub #3561), and generally improve the quality of excerpt generation" + } + ] + } + }, + { + "version": "7.29.0", + "tag": "@microsoft/api-extractor_v7.29.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript dependency to 4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "7.28.7", + "tag": "@microsoft/api-extractor_v7.28.7", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + } + ] + } + }, + { + "version": "7.28.6", + "tag": "@microsoft/api-extractor_v7.28.6", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.1`" + } + ] + } + }, + { + "version": "7.28.5", + "tag": "@microsoft/api-extractor_v7.28.5", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.22.0`" + } + ] + } + }, + { + "version": "7.28.4", + "tag": "@microsoft/api-extractor_v7.28.4", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "patch": [ + { + "comment": "Update api-extractor-template.json to \"testMode\" and \"enumMemberOrder\" comment sections." + } + ] + } + }, + { + "version": "7.28.3", + "tag": "@microsoft/api-extractor_v7.28.3", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "patch": [ + { + "comment": "Make enumMemberOrder configuration field optional" + } + ] + } + }, + { + "version": "7.28.2", + "tag": "@microsoft/api-extractor_v7.28.2", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "patch": [ + { + "comment": "Improve logic that determines whether an API item is readonly" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.21.0`" + } + ] + } + }, + { + "version": "7.28.1", + "tag": "@microsoft/api-extractor_v7.28.1", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + } + ] + } + }, + { + "version": "7.28.0", + "tag": "@microsoft/api-extractor_v7.28.0", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for the \"ignoreMissingEntryPoint\" ExtractorConfig option to allow for loading an ExtractorConfig before the target project is built." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "7.27.1", + "tag": "@microsoft/api-extractor_v7.27.1", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + } + ] + } + }, + { + "version": "7.27.0", + "tag": "@microsoft/api-extractor_v7.27.0", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "minor": [ + { + "comment": "API Extractor now populates an initializerTokenRange field for ApiProperty and ApiVariable items." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.20.0`" + } + ] + } + }, + { + "version": "7.26.1", + "tag": "@microsoft/api-extractor_v7.26.1", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + } + ] + } + }, + { + "version": "7.26.0", + "tag": "@microsoft/api-extractor_v7.26.0", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "minor": [ + { + "comment": "Include new configuration option for preserving enum member order" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.19.0`" + } + ] + } + }, + { + "version": "7.25.3", + "tag": "@microsoft/api-extractor_v7.25.3", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.0`" + } + ] + } + }, + { + "version": "7.25.2", + "tag": "@microsoft/api-extractor_v7.25.2", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + } + ] + } + }, + { + "version": "7.25.1", + "tag": "@microsoft/api-extractor_v7.25.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "none": [ + { + "comment": "Fix a mistake in the config/api-extractor.json template's default." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "7.25.0", + "tag": "@microsoft/api-extractor_v7.25.0", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add an \"isReadonly\" field to the doc model to indicate whether a property or variable is readonly" + }, + { + "comment": "Add an \"isProtected\" field to the doc model to indicate protected class members" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.18.0`" + } + ] + } + }, + { + "version": "7.24.2", + "tag": "@microsoft/api-extractor_v7.24.2", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where API Extractor would fail to run on a project where `\"moduleResolution\"` is set to `\"Node16\"` in `tsconfig.json`" + } + ] + } + }, + { + "version": "7.24.1", + "tag": "@microsoft/api-extractor_v7.24.1", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a recent regression that produced an error \"Cannot read properties of undefined\" (GitHub #3423)" + } + ] + } + }, + { + "version": "7.24.0", + "tag": "@microsoft/api-extractor_v7.24.0", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "minor": [ + { + "comment": "Throw an error early if API Extractor will attempt to process non-.d.ts files" + }, + { + "comment": "Generate API doc model nodes for setters without getters" + } + ], + "patch": [ + { + "comment": "Address edge case in excerptBuilder token range logic" + } + ] + } + }, + { + "version": "7.23.2", + "tag": "@microsoft/api-extractor_v7.23.2", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.0`" + } + ] + } + }, + { + "version": "7.23.1", + "tag": "@microsoft/api-extractor_v7.23.1", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "patch": [ + { + "comment": "Update the global variable analyzer to add support for changes to the TypeScript internals coming in v4.7" + } + ] + } + }, + { + "version": "7.23.0", + "tag": "@microsoft/api-extractor_v7.23.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "7.22.2", + "tag": "@microsoft/api-extractor_v7.22.2", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "7.22.1", + "tag": "@microsoft/api-extractor_v7.22.1", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.17.0`" + } + ] + } + }, + { + "version": "7.22.0", + "tag": "@microsoft/api-extractor_v7.22.0", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "minor": [ + { + "comment": "Add an alphaTrimmedFilePath option that adds support for generating a DTS rollup that inclues @alpha, @beta, and @public members." + } + ] + } + }, + { + "version": "7.21.3", + "tag": "@microsoft/api-extractor_v7.21.3", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "patch": [ + { + "comment": "Update TSDoc dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.2`" + } + ] + } + }, + { + "version": "7.21.2", + "tag": "@microsoft/api-extractor_v7.21.2", + "date": "Sat, 09 Apr 2022 19:07:47 GMT", + "comments": { + "patch": [ + { + "comment": "Fix ambient modules bug caused by #3321." + } + ] + } + }, + { + "version": "7.21.1", + "tag": "@microsoft/api-extractor_v7.21.1", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "7.21.0", + "tag": "@microsoft/api-extractor_v7.21.0", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for projects that use tsconfig.json \"baseUrl\" and \"paths\" settings to remap imports of local files (GitHub #3291)" + } + ] + } + }, + { + "version": "7.20.1", + "tag": "@microsoft/api-extractor_v7.20.1", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where .api.json excerpt text included extra whitespace (GitHub #3316)" + } + ] + } + }, + { + "version": "7.20.0", + "tag": "@microsoft/api-extractor_v7.20.0", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "minor": [ + { + "comment": "Updated api-extractor to extract whether a parameter is optional." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.16.0`" + } + ] + } + }, + { + "version": "7.19.5", + "tag": "@microsoft/api-extractor_v7.19.5", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "7.19.4", + "tag": "@microsoft/api-extractor_v7.19.4", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + } + ] + } + }, + { + "version": "7.19.3", + "tag": "@microsoft/api-extractor_v7.19.3", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "7.19.2", + "tag": "@microsoft/api-extractor_v7.19.2", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + } + ] + } + }, + { + "version": "7.19.1", + "tag": "@microsoft/api-extractor_v7.19.1", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.15.0`" + } + ] + } + }, + { + "version": "7.19.0", + "tag": "@microsoft/api-extractor_v7.19.0", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.5" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.14.0`" + } + ] + } + }, + { + "version": "7.18.21", + "tag": "@microsoft/api-extractor_v7.18.21", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "7.18.20", + "tag": "@microsoft/api-extractor_v7.18.20", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + } + ] + } + }, + { + "version": "7.18.19", + "tag": "@microsoft/api-extractor_v7.18.19", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + } + ] + } + }, + { + "version": "7.18.18", + "tag": "@microsoft/api-extractor_v7.18.18", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "7.18.17", + "tag": "@microsoft/api-extractor_v7.18.17", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "7.18.16", + "tag": "@microsoft/api-extractor_v7.18.16", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "7.18.15", + "tag": "@microsoft/api-extractor_v7.18.15", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + } + ] + } + }, + { + "version": "7.18.14", + "tag": "@microsoft/api-extractor_v7.18.14", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "7.18.13", + "tag": "@microsoft/api-extractor_v7.18.13", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + } + ] + } + }, + { + "version": "7.18.12", + "tag": "@microsoft/api-extractor_v7.18.12", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.0`" + } + ] + } + }, + { + "version": "7.18.11", + "tag": "@microsoft/api-extractor_v7.18.11", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + } + ] + } + }, + { + "version": "7.18.10", + "tag": "@microsoft/api-extractor_v7.18.10", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "7.18.9", + "tag": "@microsoft/api-extractor_v7.18.9", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + } + ] + } + }, + { + "version": "7.18.8", + "tag": "@microsoft/api-extractor_v7.18.8", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + } + ] + } + }, + { + "version": "7.18.7", + "tag": "@microsoft/api-extractor_v7.18.7", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.0`" + } + ] + } + }, + { + "version": "7.18.6", + "tag": "@microsoft/api-extractor_v7.18.6", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.0`" + } + ] + } + }, + { + "version": "7.18.5", + "tag": "@microsoft/api-extractor_v7.18.5", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + } + ] + } + }, + { + "version": "7.18.4", + "tag": "@microsoft/api-extractor_v7.18.4", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the .d.ts rollup sometimes used \"default\" as an identifier name causing a syntax error (GitHub #2804)" + } + ] + } + }, + { + "version": "7.18.3", + "tag": "@microsoft/api-extractor_v7.18.3", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "patch": [ + { + "comment": "Revert a workaround for TypeScript issue #44422 which was fixed in 4.3.3" + } + ] + } + }, + { + "version": "7.18.2", + "tag": "@microsoft/api-extractor_v7.18.2", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "7.18.1", + "tag": "@microsoft/api-extractor_v7.18.1", + "date": "Thu, 08 Jul 2021 23:41:16 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a recent regression that reported \"Internal Error: indentDocComment cannot be nested\" (GitHub #2797)" + } + ] + } + }, + { + "version": "7.18.0", + "tag": "@microsoft/api-extractor_v7.18.0", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for import() type expressions (GitHub #1050) -- Thank you @javier-garcia-meteologica and @adventure-yunfei for solving this difficult problem!" + }, + { + "comment": "Improve formatting of declarations in .d.ts rollup and .api.md files, fixing some indentation issues" + } + ] + } + }, + { + "version": "7.17.1", + "tag": "@microsoft/api-extractor_v7.17.1", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.0`" + } + ] + } + }, + { + "version": "7.17.0", + "tag": "@microsoft/api-extractor_v7.17.0", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "minor": [ + { + "comment": "Added support for \"import * as module from './local/module';\" (GitHub #1029) -- Big thanks to @adventure-yunfei, @mckn, @rbuckton, and @octogonz who all helped with this difficult PR!" + } + ], + "patch": [ + { + "comment": "Include /// directives in API report" + } + ] + } + }, + { + "version": "7.16.1", + "tag": "@microsoft/api-extractor_v7.16.1", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + } + ] + } + }, + { + "version": "7.16.0", + "tag": "@microsoft/api-extractor_v7.16.0", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 4.3" + } + ] + } + }, + { + "version": "7.15.2", + "tag": "@microsoft/api-extractor_v7.15.2", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + } + ] + } + }, + { + "version": "7.15.1", + "tag": "@microsoft/api-extractor_v7.15.1", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + } + ] + } + }, + { + "version": "7.15.0", + "tag": "@microsoft/api-extractor_v7.15.0", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 4.2" + } + ] + } + }, + { + "version": "7.14.0", + "tag": "@microsoft/api-extractor_v7.14.0", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "minor": [ + { + "comment": "Projects can now define custom tags using a tsdoc.json file" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.13.0`" + } + ] + } + }, + { + "version": "7.13.5", + "tag": "@microsoft/api-extractor_v7.13.5", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "7.13.4", + "tag": "@microsoft/api-extractor_v7.13.4", + "date": "Thu, 08 Apr 2021 06:05:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.4`" + } + ] + } + }, + { + "version": "7.13.3", + "tag": "@microsoft/api-extractor_v7.13.3", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "7.13.2", + "tag": "@microsoft/api-extractor_v7.13.2", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.10`" + } + ] + } + }, + { + "version": "7.13.1", + "tag": "@microsoft/api-extractor_v7.13.1", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + } + ] + } + }, + { + "version": "7.13.0", + "tag": "@microsoft/api-extractor_v7.13.0", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 4.1" + } + ] + } + }, + { + "version": "7.12.1", + "tag": "@microsoft/api-extractor_v7.12.1", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to TSDoc 0.12.24" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "7.12.0", + "tag": "@microsoft/api-extractor_v7.12.0", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "minor": [ + { + "comment": "The \"isOptional\" .api.json field is now applied to both methods and properties" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.12.0`" + } + ] + } + }, + { + "version": "7.11.5", + "tag": "@microsoft/api-extractor_v7.11.5", + "date": "Wed, 18 Nov 2020 06:21:57 GMT", + "comments": { + "patch": [ + { + "comment": "Update .api.json file format to store a new field \"isOptional\" for documenting optional properties" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.11.0`" + } + ] + } + }, + { + "version": "7.11.4", + "tag": "@microsoft/api-extractor_v7.11.4", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "7.11.3", + "tag": "@microsoft/api-extractor_v7.11.3", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + } + ] + } + }, + { + "version": "7.11.2", + "tag": "@microsoft/api-extractor_v7.11.2", + "date": "Fri, 30 Oct 2020 06:38:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "7.11.1", + "tag": "@microsoft/api-extractor_v7.11.1", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "7.11.0", + "tag": "@microsoft/api-extractor_v7.11.0", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 4.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.6`" + } + ] + } + }, + { + "version": "7.10.6", + "tag": "@microsoft/api-extractor_v7.10.6", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "7.10.5", + "tag": "@microsoft/api-extractor_v7.10.5", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + } + ] + } + }, + { + "version": "7.10.4", + "tag": "@microsoft/api-extractor_v7.10.4", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + } + ] + } + }, + { + "version": "7.10.3", + "tag": "@microsoft/api-extractor_v7.10.3", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + } + ] + } + }, + { + "version": "7.10.2", + "tag": "@microsoft/api-extractor_v7.10.2", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.2`" + } + ] + } + }, + { + "version": "7.10.1", + "tag": "@microsoft/api-extractor_v7.10.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + } + ] + } + }, + { + "version": "7.10.0", + "tag": "@microsoft/api-extractor_v7.10.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an InternalError reported when a declaration referred to itself using \"tyepof\"" + }, + { + "comment": "Update README.md" + } + ], + "minor": [ + { + "comment": "API Extractor now supports the config/rig.json system, as defined by @rushstack/rig-package" + }, + { + "comment": "Add IExtractorConfigPrepareOptions.projectFolderLookupToken" + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "7.9.22", + "tag": "@microsoft/api-extractor_v7.9.22", + "date": "Tue, 22 Sep 2020 05:45:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "7.9.21", + "tag": "@microsoft/api-extractor_v7.9.21", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "7.9.20", + "tag": "@microsoft/api-extractor_v7.9.20", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "7.9.19", + "tag": "@microsoft/api-extractor_v7.9.19", + "date": "Sat, 19 Sep 2020 04:37:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "7.9.18", + "tag": "@microsoft/api-extractor_v7.9.18", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "7.9.17", + "tag": "@microsoft/api-extractor_v7.9.17", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "7.9.16", + "tag": "@microsoft/api-extractor_v7.9.16", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + } + ] + } + }, + { + "version": "7.9.15", + "tag": "@microsoft/api-extractor_v7.9.15", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.9.0`" + } + ] + } + }, + { + "version": "7.9.14", + "tag": "@microsoft/api-extractor_v7.9.14", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + } + ] + } + }, + { + "version": "7.9.13", + "tag": "@microsoft/api-extractor_v7.9.13", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + } + ] + } + }, + { + "version": "7.9.12", + "tag": "@microsoft/api-extractor_v7.9.12", + "date": "Sat, 05 Sep 2020 18:56:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.20`" + } + ] + } + }, + { + "version": "7.9.11", + "tag": "@microsoft/api-extractor_v7.9.11", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + }, + { + "version": "7.9.10", + "tag": "@microsoft/api-extractor_v7.9.10", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + } + ] + } + }, + { + "version": "7.9.9", + "tag": "@microsoft/api-extractor_v7.9.9", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + } + ] + } + }, + { + "version": "7.9.8", + "tag": "@microsoft/api-extractor_v7.9.8", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.1`" + } + ] + } + }, + { + "version": "7.9.7", + "tag": "@microsoft/api-extractor_v7.9.7", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.0`" + } + ] + } + }, + { + "version": "7.9.6", + "tag": "@microsoft/api-extractor_v7.9.6", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.5.0`" + } + ] + } + }, + { + "version": "7.9.5", + "tag": "@microsoft/api-extractor_v7.9.5", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "none": [ + { + "comment": "Add keywords to package.json for discoverability" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + } + ] + } + }, + { + "version": "7.9.4", + "tag": "@microsoft/api-extractor_v7.9.4", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + } + ] + } + }, + { + "version": "7.9.3", + "tag": "@microsoft/api-extractor_v7.9.3", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + } + ] + } + }, + { + "version": "7.9.2", + "tag": "@microsoft/api-extractor_v7.9.2", + "date": "Thu, 09 Jul 2020 04:58:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with handling of \"export { default } from 'package';\" (GitHub #2014)" + } + ] + } + }, + { + "version": "7.9.1", + "tag": "@microsoft/api-extractor_v7.9.1", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.11` to `7.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + } + ] + } + }, + { + "version": "7.9.0", + "tag": "@microsoft/api-extractor_v7.9.0", + "date": "Fri, 03 Jul 2020 05:46:41 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where chained compiler errors were not formatted correctly" + }, + { + "comment": "Log the TypeScript bundled compiler version, and warn if it is outdated" + } + ], + "minor": [ + { + "comment": "Add support for ECMAScript private fields (new in TypeScript 3.8)" + }, + { + "comment": "Add support for \"import type\" imports (new in TypeScript 3.8)" + }, + { + "comment": "Upgrade the bundled compiler engine to TypeScript 3.9" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.5` to `4.4.6`" + } + ] + } + }, + { + "version": "7.8.15", + "tag": "@microsoft/api-extractor_v7.8.15", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.10` to `7.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.4` to `4.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "7.8.14", + "tag": "@microsoft/api-extractor_v7.8.14", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.9` to `7.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.3` to `4.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "7.8.13", + "tag": "@microsoft/api-extractor_v7.8.13", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.8` to `7.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.2` to `4.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "7.8.12", + "tag": "@microsoft/api-extractor_v7.8.12", + "date": "Mon, 15 Jun 2020 22:17:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where documentation hyperlinks were sometimes missing when using the \"bundledPackages\" feature (GitHub #1933)" + } + ] + } + }, + { + "version": "7.8.11", + "tag": "@microsoft/api-extractor_v7.8.11", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.7` to `7.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + } + ] + } + }, + { + "version": "7.8.10", + "tag": "@microsoft/api-extractor_v7.8.10", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.1` to `4.4.2`" + } + ] + } + }, + { + "version": "7.8.9", + "tag": "@microsoft/api-extractor_v7.8.9", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.6` to `7.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + } + ] + } + }, + { + "version": "7.8.8", + "tag": "@microsoft/api-extractor_v7.8.8", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.5` to `7.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + } + ] + } + }, + { + "version": "7.8.7", + "tag": "@microsoft/api-extractor_v7.8.7", + "date": "Wed, 27 May 2020 05:15:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.4` to `7.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.4.0` to `4.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "7.8.6", + "tag": "@microsoft/api-extractor_v7.8.6", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.3` to `7.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + } + ] + } + }, + { + "version": "7.8.5", + "tag": "@microsoft/api-extractor_v7.8.5", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.2` to `7.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + } + ] + } + }, + { + "version": "7.8.4", + "tag": "@microsoft/api-extractor_v7.8.4", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.1` to `7.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + } + ] + } + }, + { + "version": "7.8.3", + "tag": "@microsoft/api-extractor_v7.8.3", + "date": "Thu, 21 May 2020 15:41:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.8.0` to `7.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + } + ] + } + }, + { + "version": "7.8.2", + "tag": "@microsoft/api-extractor_v7.8.2", + "date": "Tue, 19 May 2020 15:08:19 GMT", + "comments": { + "patch": [ + { + "comment": "Report an error to indicate that \"import()\" types are not supported" + } + ] + } + }, + { + "version": "7.8.1", + "tag": "@microsoft/api-extractor_v7.8.1", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.14` to `4.4.0`" + } + ] + } + }, + { + "version": "7.8.0", + "tag": "@microsoft/api-extractor_v7.8.0", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "minor": [ + { + "comment": "Version update only" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.11` to `7.8.0`" + } + ] + } + }, + { + "version": "7.7.13", + "tag": "@microsoft/api-extractor_v7.7.13", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.10` to `7.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.13` to `4.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "7.7.12", + "tag": "@microsoft/api-extractor_v7.7.12", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "patch": [ + { + "comment": "Improve analysis of types exposed via global variables (fixes GitHub issues #1765, #1095, and #1316)" + } + ] + } + }, + { + "version": "7.7.11", + "tag": "@microsoft/api-extractor_v7.7.11", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to TSdoc 0.12.19 to fix an issue where `

` wasn't allowed as an HTML tag in a doc comment" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" from `7.7.9` to `7.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" from `4.3.12` to `4.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "7.7.10", "tag": "@microsoft/api-extractor_v7.7.10", @@ -1107,7 +5667,7 @@ "comments": { "patch": [ { - "comment": "(Breaking change) The file extension for API review files has changed from \".api.ts\" to \"api.md\". For details see https://github.com/Microsoft/web-build-tools/issues/1123" + "comment": "(Breaking change) The file extension for API review files has changed from \".api.ts\" to \"api.md\". For details see https://github.com/microsoft/web-build-tools/issues/1123" } ] } @@ -1393,7 +5953,7 @@ "comments": { "patch": [ { - "comment": "Fix an issue with rolling up default exports (https://github.com/Microsoft/web-build-tools/issues/1007)" + "comment": "Fix an issue with rolling up default exports (https://github.com/microsoft/web-build-tools/issues/1007)" } ], "dependency": [ @@ -1786,7 +6346,7 @@ "comments": { "major": [ { - "comment": "(Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax! Please see https://api-extractor.com/ for documentation. To learn more about the TSDoc standard, check out https://github.com/Microsoft/tsdoc" + "comment": "(Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax! Please see https://api-extractor.com/ for documentation. To learn more about the TSDoc standard, check out https://github.com/microsoft/tsdoc" } ], "dependency": [ diff --git a/apps/api-extractor/CHANGELOG.md b/apps/api-extractor/CHANGELOG.md index c2c7dcddab9..12ce5517f77 100644 --- a/apps/api-extractor/CHANGELOG.md +++ b/apps/api-extractor/CHANGELOG.md @@ -1,6 +1,1559 @@ # Change Log - @microsoft/api-extractor -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 7.48.0 +Sat, 23 Nov 2024 01:18:55 GMT + +### Minor changes + +- Update TSDoc dependencies. + +## 7.47.12 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 7.47.11 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 7.47.10 +Tue, 15 Oct 2024 00:12:31 GMT + +### Patches + +- Fix a compatibility issue with usage of `getModeForUsageLocation` in TypeScript 5.6 + +## 7.47.9 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 7.47.8 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 7.47.7 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 7.47.6 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 7.47.5 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 7.47.4 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 7.47.3 +Wed, 24 Jul 2024 00:12:14 GMT + +### Patches + +- Fix an edge case when discarding the file extension from the "reportFileName" setting and improve its documentation + +## 7.47.2 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 7.47.1 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 7.47.0 +Mon, 03 Jun 2024 23:43:15 GMT + +### Minor changes + +- Add support for re-exporting modules using syntax such as `export * as ns from './file'` (GitHub #2780) + +## 7.46.2 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 7.46.1 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 7.46.0 +Wed, 29 May 2024 00:10:52 GMT + +### Minor changes + +- Bump TSDoc dependencies. + +## 7.45.1 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 7.45.0 +Tue, 28 May 2024 00:09:47 GMT + +### Minor changes + +- Improve support for resolving the `tsdoc-metadata.json` to include the folder referenced by a `types` field in an `"exports"` field and an `"typesVersions"` field in addition to `"types"`, `"typings"`, and `"tsdocMetadata"` fields. + +## 7.44.1 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 7.44.0 +Fri, 24 May 2024 00:15:08 GMT + +### Minor changes + +- Add support for "variants" of API reports which include or exclude items by release tag + +## 7.43.8 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 7.43.7 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 7.43.6 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 7.43.5 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 7.43.4 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 7.43.3 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 7.43.2 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 7.43.1 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 7.43.0 +Tue, 19 Mar 2024 15:10:18 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 5.4.2 + +## 7.42.3 +Sun, 03 Mar 2024 20:58:12 GMT + +_Version update only_ + +## 7.42.2 +Sat, 02 Mar 2024 02:22:23 GMT + +_Version update only_ + +## 7.42.1 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 7.42.0 +Thu, 29 Feb 2024 07:11:45 GMT + +### Minor changes + +- Add glob support in `bundledPackages` + +### Patches + +- Don't mark items documented with {@inheritDoc} references to package-external items as "undocumented" + +## 7.41.1 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 7.41.0 +Sat, 24 Feb 2024 23:02:51 GMT + +### Minor changes + +- Replace const enums with conventional enums to allow for compatibility with JavaScript consumers. + +## 7.40.6 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 7.40.5 +Wed, 21 Feb 2024 08:55:47 GMT + +### Patches + +- Fix an issue where imports were trimmed from external packages based when generating .d.ts rollups + +## 7.40.4 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 7.40.3 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 7.40.2 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 7.40.1 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 7.40.0 +Wed, 07 Feb 2024 01:11:18 GMT + +### Minor changes + +- Classify arrow functions as `function` kind in the doc model export. + +## 7.39.5 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 7.39.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 7.39.3 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 7.39.2 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 7.39.1 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 7.39.0 +Wed, 20 Dec 2023 01:09:45 GMT + +### Minor changes + +- Update API Extractor to support TypeScript 5.3.3 + +## 7.38.5 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 7.38.4 +Tue, 05 Dec 2023 01:10:16 GMT + +### Patches + +- Don't export trimmed namespace members during rollup (#2791) + +## 7.38.3 +Fri, 10 Nov 2023 18:02:04 GMT + +### Patches + +- Fix an issue where "ae-undocumented" was incorrectly reported for private members + +## 7.38.2 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 7.38.1 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 7.38.0 +Sun, 01 Oct 2023 02:56:29 GMT + +### Minor changes + +- Add a new message "ae-undocumented" to support logging of undocumented API items + +## 7.37.3 +Sat, 30 Sep 2023 00:20:51 GMT + +### Patches + +- Don't strip out @alpha items when generating API reports. + +## 7.37.2 +Thu, 28 Sep 2023 20:53:16 GMT + +_Version update only_ + +## 7.37.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 7.37.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 7.36.4 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 7.36.3 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 7.36.2 +Wed, 12 Jul 2023 15:20:39 GMT + +### Patches + +- Add api-extractor support for .d.mts and .d.cts files + +## 7.36.1 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 7.36.0 +Mon, 19 Jun 2023 22:40:21 GMT + +### Minor changes + +- Use the `IRigConfig` interface in the `IExtractorConfigLoadForFolderOptions` object insteacd of the `RigConfig` class. + +## 7.35.4 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 7.35.3 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 7.35.2 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 7.35.1 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 7.35.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the TypeScript dependency to ~5.0.4 + +## 7.34.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 7.34.8 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 7.34.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 7.34.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 7.34.5 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 7.34.4 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 7.34.3 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 7.34.2 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 7.34.1 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 7.34.0 +Wed, 25 Jan 2023 07:26:55 GMT + +### Minor changes + +- Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661) + +## 7.33.8 +Wed, 18 Jan 2023 22:44:12 GMT + +### Patches + +- Use ts.getCheckFlags to fix TS 5.0 + +## 7.33.7 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 7.33.6 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 7.33.5 +Wed, 26 Oct 2022 00:16:16 GMT + +### Patches + +- Update the @microsoft/tsdoc dependency version to 0.14.2. + +## 7.33.4 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 7.33.3 +Mon, 17 Oct 2022 15:16:00 GMT + +### Patches + +- Fix a regression where the "fileUrlPath" property would contain a malformed path when API Extractor is run on Windows. + +## 7.33.2 +Fri, 14 Oct 2022 15:26:31 GMT + +### Patches + +- Fix references from computed properties #3629 + +## 7.33.1 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 7.33.0 +Tue, 11 Oct 2022 23:49:12 GMT + +### Minor changes + +- Extract the original source file path for relevant API items and add a new projectFolderUrl setting to the api-extractor.json config that allows one to specify what URL their project folder can be found at. + +## 7.32.1 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 7.32.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Update parser to TypeScript 4.8. + +## 7.31.2 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 7.31.1 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 7.31.0 +Tue, 13 Sep 2022 00:16:55 GMT + +### Minor changes + +- Fix an issue where aliased classes sometimes had incorrect canonical references in *.api.json (GitHub #3593) + +## 7.30.1 +Mon, 12 Sep 2022 22:27:48 GMT + +### Patches + +- Fix a recent regression where items exported from both the entry point and from an exported namespace appeared only once in the API doc model (GitHub #3619) + +## 7.30.0 +Fri, 02 Sep 2022 17:48:42 GMT + +### Minor changes + +- Add new "apiReport.includeForgottenExports" and "docModel.includeForgottenExports" properties to control whether forgotten exports are included in the API report and doc model files. +- Fix incorrect declaration references for symbols not exported from the package's entry point. + +## 7.29.5 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 7.29.4 +Wed, 24 Aug 2022 00:14:38 GMT + +### Patches + +- Remove use of LegacyAdapters.sortStable + +## 7.29.3 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 7.29.2 +Wed, 10 Aug 2022 09:52:12 GMT + +### Patches + +- Fix incorrect declaration references for local symbols within namespaces + +## 7.29.1 +Wed, 10 Aug 2022 08:12:16 GMT + +### Patches + +- Fix a regression where .api.json excerpts were sometimes missing tokens (GitHub #3561), and generally improve the quality of excerpt generation + +## 7.29.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript dependency to 4.7 + +## 7.28.7 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 7.28.6 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 7.28.5 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 7.28.4 +Fri, 08 Jul 2022 15:17:46 GMT + +### Patches + +- Update api-extractor-template.json to "testMode" and "enumMemberOrder" comment sections. + +## 7.28.3 +Mon, 04 Jul 2022 15:15:13 GMT + +### Patches + +- Make enumMemberOrder configuration field optional + +## 7.28.2 +Thu, 30 Jun 2022 04:48:53 GMT + +### Patches + +- Improve logic that determines whether an API item is readonly + +## 7.28.1 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 7.28.0 +Tue, 28 Jun 2022 00:23:32 GMT + +### Minor changes + +- Add support for the "ignoreMissingEntryPoint" ExtractorConfig option to allow for loading an ExtractorConfig before the target project is built. + +## 7.27.1 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 7.27.0 +Sat, 25 Jun 2022 21:00:40 GMT + +### Minor changes + +- API Extractor now populates an initializerTokenRange field for ApiProperty and ApiVariable items. + +## 7.26.1 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 7.26.0 +Fri, 24 Jun 2022 07:16:47 GMT + +### Minor changes + +- Include new configuration option for preserving enum member order + +## 7.25.3 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 7.25.2 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 7.25.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 7.25.0 +Tue, 07 Jun 2022 09:37:04 GMT + +### Minor changes + +- Add an "isReadonly" field to the doc model to indicate whether a property or variable is readonly +- Add an "isProtected" field to the doc model to indicate protected class members + +## 7.24.2 +Wed, 25 May 2022 22:25:07 GMT + +### Patches + +- Fix an issue where API Extractor would fail to run on a project where `"moduleResolution"` is set to `"Node16"` in `tsconfig.json` + +## 7.24.1 +Thu, 19 May 2022 15:13:20 GMT + +### Patches + +- Fix a recent regression that produced an error "Cannot read properties of undefined" (GitHub #3423) + +## 7.24.0 +Sat, 14 May 2022 03:01:27 GMT + +### Minor changes + +- Throw an error early if API Extractor will attempt to process non-.d.ts files +- Generate API doc model nodes for setters without getters + +### Patches + +- Address edge case in excerptBuilder token range logic + +## 7.23.2 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 7.23.1 +Wed, 04 May 2022 23:29:13 GMT + +### Patches + +- Update the global variable analyzer to add support for changes to the TypeScript internals coming in v4.7 + +## 7.23.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Update to TypeScript 4.6 + +## 7.22.2 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 7.22.1 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 7.22.0 +Tue, 12 Apr 2022 23:29:34 GMT + +### Minor changes + +- Add an alphaTrimmedFilePath option that adds support for generating a DTS rollup that inclues @alpha, @beta, and @public members. + +## 7.21.3 +Tue, 12 Apr 2022 02:58:32 GMT + +### Patches + +- Update TSDoc dependencies. + +## 7.21.2 +Sat, 09 Apr 2022 19:07:47 GMT + +### Patches + +- Fix ambient modules bug caused by #3321. + +## 7.21.1 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 7.21.0 +Fri, 08 Apr 2022 20:05:59 GMT + +### Minor changes + +- Add support for projects that use tsconfig.json "baseUrl" and "paths" settings to remap imports of local files (GitHub #3291) + +## 7.20.1 +Wed, 06 Apr 2022 22:35:23 GMT + +### Patches + +- Fix an issue where .api.json excerpt text included extra whitespace (GitHub #3316) + +## 7.20.0 +Thu, 31 Mar 2022 02:06:05 GMT + +### Minor changes + +- Updated api-extractor to extract whether a parameter is optional. + +## 7.19.5 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 7.19.4 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 7.19.3 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 7.19.2 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 7.19.1 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 7.19.0 +Wed, 08 Dec 2021 16:14:05 GMT + +### Minor changes + +- Update to TypeScript 4.5 + +## 7.18.21 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 7.18.20 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 7.18.19 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 7.18.18 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 7.18.17 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 7.18.16 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 7.18.15 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 7.18.14 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 7.18.13 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 7.18.12 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 7.18.11 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 7.18.10 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 7.18.9 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 7.18.8 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 7.18.7 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 7.18.6 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 7.18.5 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 7.18.4 +Wed, 14 Jul 2021 15:06:29 GMT + +### Patches + +- Fix an issue where the .d.ts rollup sometimes used "default" as an identifier name causing a syntax error (GitHub #2804) + +## 7.18.3 +Tue, 13 Jul 2021 23:00:33 GMT + +### Patches + +- Revert a workaround for TypeScript issue #44422 which was fixed in 4.3.3 + +## 7.18.2 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 7.18.1 +Thu, 08 Jul 2021 23:41:16 GMT + +### Patches + +- Fix a recent regression that reported "Internal Error: indentDocComment cannot be nested" (GitHub #2797) + +## 7.18.0 +Thu, 08 Jul 2021 06:00:48 GMT + +### Minor changes + +- Add support for import() type expressions (GitHub #1050) -- Thank you @javier-garcia-meteologica and @adventure-yunfei for solving this difficult problem! +- Improve formatting of declarations in .d.ts rollup and .api.md files, fixing some indentation issues + +## 7.17.1 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 7.17.0 +Wed, 30 Jun 2021 15:06:54 GMT + +### Minor changes + +- Added support for "import * as module from './local/module';" (GitHub #1029) -- Big thanks to @adventure-yunfei, @mckn, @rbuckton, and @octogonz who all helped with this difficult PR! + +### Patches + +- Include /// directives in API report + +## 7.16.1 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 7.16.0 +Fri, 04 Jun 2021 15:08:20 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 4.3 + +## 7.15.2 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 7.15.1 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 7.15.0 +Thu, 29 Apr 2021 23:26:50 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 4.2 + +## 7.14.0 +Tue, 20 Apr 2021 04:59:51 GMT + +### Minor changes + +- Projects can now define custom tags using a tsdoc.json file + +## 7.13.5 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 7.13.4 +Thu, 08 Apr 2021 06:05:31 GMT + +_Version update only_ + +## 7.13.3 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 7.13.2 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 7.13.1 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 7.13.0 +Wed, 13 Jan 2021 01:11:06 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 4.1 + +## 7.12.1 +Thu, 10 Dec 2020 23:25:49 GMT + +### Patches + +- Upgrade to TSDoc 0.12.24 + +## 7.12.0 +Wed, 18 Nov 2020 08:19:54 GMT + +### Minor changes + +- The "isOptional" .api.json field is now applied to both methods and properties + +## 7.11.5 +Wed, 18 Nov 2020 06:21:57 GMT + +### Patches + +- Update .api.json file format to store a new field "isOptional" for documenting optional properties + +## 7.11.4 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 7.11.3 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 7.11.2 +Fri, 30 Oct 2020 06:38:38 GMT + +_Version update only_ + +## 7.11.1 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 7.11.0 +Thu, 29 Oct 2020 06:14:19 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 4.0 + +## 7.10.6 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 7.10.5 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 7.10.4 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 7.10.3 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 7.10.2 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 7.10.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 7.10.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- API Extractor now supports the config/rig.json system, as defined by @rushstack/rig-package +- Add IExtractorConfigPrepareOptions.projectFolderLookupToken +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Fix an InternalError reported when a declaration referred to itself using "tyepof" +- Update README.md + +## 7.9.22 +Tue, 22 Sep 2020 05:45:56 GMT + +_Version update only_ + +## 7.9.21 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 7.9.20 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 7.9.19 +Sat, 19 Sep 2020 04:37:26 GMT + +_Version update only_ + +## 7.9.18 +Sat, 19 Sep 2020 03:33:06 GMT + +_Version update only_ + +## 7.9.17 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 7.9.16 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 7.9.15 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 7.9.14 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 7.9.13 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 7.9.12 +Sat, 05 Sep 2020 18:56:34 GMT + +_Version update only_ + +## 7.9.11 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 7.9.10 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 7.9.9 +Sat, 22 Aug 2020 05:55:42 GMT + +_Version update only_ + +## 7.9.8 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 7.9.7 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 7.9.6 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 7.9.5 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 7.9.4 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 7.9.3 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 7.9.2 +Thu, 09 Jul 2020 04:58:36 GMT + +### Patches + +- Fix an issue with handling of "export { default } from 'package';" (GitHub #2014) + +## 7.9.1 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 7.9.0 +Fri, 03 Jul 2020 05:46:41 GMT + +### Minor changes + +- Add support for ECMAScript private fields (new in TypeScript 3.8) +- Add support for "import type" imports (new in TypeScript 3.8) +- Upgrade the bundled compiler engine to TypeScript 3.9 + +### Patches + +- Fix an issue where chained compiler errors were not formatted correctly +- Log the TypeScript bundled compiler version, and warn if it is outdated + +## 7.8.15 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 7.8.14 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 7.8.13 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 7.8.12 +Mon, 15 Jun 2020 22:17:17 GMT + +### Patches + +- Fix an issue where documentation hyperlinks were sometimes missing when using the "bundledPackages" feature (GitHub #1933) + +## 7.8.11 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 7.8.10 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 7.8.9 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 7.8.8 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 7.8.7 +Wed, 27 May 2020 05:15:10 GMT + +_Version update only_ + +## 7.8.6 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 7.8.5 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 7.8.4 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 7.8.3 +Thu, 21 May 2020 15:41:59 GMT + +_Version update only_ + +## 7.8.2 +Tue, 19 May 2020 15:08:19 GMT + +### Patches + +- Report an error to indicate that "import()" types are not supported + +## 7.8.1 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 7.8.0 +Wed, 06 May 2020 08:23:45 GMT + +### Minor changes + +- Version update only + +## 7.7.13 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 7.7.12 +Sun, 29 Mar 2020 00:04:12 GMT + +### Patches + +- Improve analysis of types exposed via global variables (fixes GitHub issues #1765, #1095, and #1316) + +## 7.7.11 +Sat, 28 Mar 2020 00:37:16 GMT + +### Patches + +- Upgrade to TSdoc 0.12.19 to fix an issue where `

` wasn't allowed as an HTML tag in a doc comment ## 7.7.10 Wed, 18 Mar 2020 15:07:47 GMT @@ -19,17 +1572,17 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 7.7.8 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 7.7.7 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 7.7.6 Tue, 21 Jan 2020 21:56:13 GMT -*Version update only* +_Version update only_ ## 7.7.5 Sun, 19 Jan 2020 02:26:52 GMT @@ -41,7 +1594,7 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 7.7.4 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 7.7.3 Tue, 14 Jan 2020 01:34:15 GMT @@ -60,7 +1613,7 @@ Thu, 09 Jan 2020 06:44:12 GMT ## 7.7.1 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 7.7.0 Tue, 03 Dec 2019 03:17:43 GMT @@ -73,7 +1626,7 @@ Tue, 03 Dec 2019 03:17:43 GMT ## 7.6.2 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 7.6.1 Wed, 20 Nov 2019 06:14:28 GMT @@ -92,7 +1645,7 @@ Fri, 15 Nov 2019 04:50:50 GMT ## 7.5.6 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 7.5.5 Wed, 06 Nov 2019 22:44:18 GMT @@ -111,17 +1664,17 @@ Tue, 05 Nov 2019 06:49:28 GMT ## 7.5.3 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 7.5.2 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 7.5.1 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 7.5.0 Sun, 06 Oct 2019 00:27:39 GMT @@ -148,17 +1701,17 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 7.4.5 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 7.4.4 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 7.4.3 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 7.4.2 Wed, 11 Sep 2019 19:56:23 GMT @@ -184,7 +1737,7 @@ Tue, 10 Sep 2019 20:38:33 GMT ## 7.3.11 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 7.3.10 Wed, 04 Sep 2019 15:15:37 GMT @@ -203,12 +1756,12 @@ Fri, 30 Aug 2019 00:14:32 GMT ## 7.3.8 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 7.3.7 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 7.3.6 Thu, 08 Aug 2019 00:49:05 GMT @@ -276,7 +1829,7 @@ Sat, 29 Jun 2019 02:30:10 GMT ## 7.2.1 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 7.2.0 Tue, 11 Jun 2019 00:48:06 GMT @@ -317,7 +1870,7 @@ Mon, 13 May 2019 02:08:35 GMT ## 7.1.4 Mon, 06 May 2019 20:46:21 GMT -*Version update only* +_Version update only_ ## 7.1.3 Mon, 06 May 2019 19:34:54 GMT @@ -470,7 +2023,7 @@ Fri, 15 Mar 2019 19:13:25 GMT ### Patches -- (Breaking change) The file extension for API review files has changed from ".api.ts" to "api.md". For details see https://github.com/Microsoft/web-build-tools/issues/1123 +- (Breaking change) The file extension for API review files has changed from ".api.ts" to "api.md". For details see https://github.com/microsoft/web-build-tools/issues/1123 ## 7.0.26 Wed, 13 Mar 2019 19:13:14 GMT @@ -516,12 +2069,12 @@ Mon, 04 Mar 2019 17:13:19 GMT ## 7.0.21 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 7.0.20 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 7.0.19 Mon, 18 Feb 2019 17:13:23 GMT @@ -607,7 +2160,7 @@ Thu, 10 Jan 2019 01:57:52 GMT ### Patches -- Fix an issue with rolling up default exports (https://github.com/Microsoft/web-build-tools/issues/1007) +- Fix an issue with rolling up default exports (https://github.com/microsoft/web-build-tools/issues/1007) ## 7.0.8 Thu, 20 Dec 2018 17:04:08 GMT @@ -711,7 +2264,7 @@ Fri, 09 Nov 2018 23:07:39 GMT ## 6.1.3 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 6.1.2 Mon, 05 Nov 2018 17:04:24 GMT @@ -737,7 +2290,7 @@ Wed, 31 Oct 2018 17:00:54 GMT ## 6.0.9 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 6.0.8 Thu, 25 Oct 2018 08:56:02 GMT @@ -749,7 +2302,7 @@ Thu, 25 Oct 2018 08:56:02 GMT ## 6.0.7 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 6.0.6 Thu, 18 Oct 2018 01:32:20 GMT @@ -761,7 +2314,7 @@ Thu, 18 Oct 2018 01:32:20 GMT ## 6.0.5 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 6.0.4 Wed, 17 Oct 2018 14:43:24 GMT @@ -789,19 +2342,19 @@ Tue, 09 Oct 2018 06:58:01 GMT ## 6.0.1 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 6.0.0 Sun, 07 Oct 2018 06:15:56 GMT ### Breaking changes -- (Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax! Please see https://api-extractor.com/ for documentation. To learn more about the TSDoc standard, check out https://github.com/Microsoft/tsdoc +- (Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax! Please see https://api-extractor.com/ for documentation. To learn more about the TSDoc standard, check out https://github.com/microsoft/tsdoc ## 5.13.1 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 5.13.0 Wed, 26 Sep 2018 21:39:40 GMT @@ -855,7 +2408,7 @@ Mon, 03 Sep 2018 16:04:45 GMT ## 5.10.8 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 5.10.7 Thu, 23 Aug 2018 18:18:53 GMT @@ -867,12 +2420,12 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 5.10.6 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 5.10.5 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 5.10.4 Tue, 21 Aug 2018 16:04:38 GMT @@ -884,7 +2437,7 @@ Tue, 21 Aug 2018 16:04:38 GMT ## 5.10.3 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 5.10.2 Thu, 09 Aug 2018 16:04:24 GMT @@ -896,7 +2449,7 @@ Thu, 09 Aug 2018 16:04:24 GMT ## 5.10.1 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 5.10.0 Tue, 17 Jul 2018 16:02:52 GMT @@ -908,7 +2461,7 @@ Tue, 17 Jul 2018 16:02:52 GMT ## 5.9.1 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 5.9.0 Sat, 23 Jun 2018 02:21:20 GMT @@ -921,7 +2474,7 @@ Sat, 23 Jun 2018 02:21:20 GMT ## 5.8.1 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 5.8.0 Tue, 19 Jun 2018 19:35:11 GMT @@ -937,17 +2490,17 @@ Tue, 19 Jun 2018 19:35:11 GMT ## 5.7.3 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 5.7.2 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 5.7.1 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 5.7.0 Tue, 15 May 2018 00:18:10 GMT @@ -973,12 +2526,12 @@ Tue, 01 May 2018 22:03:20 GMT ## 5.6.6 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 5.6.5 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 5.6.4 Thu, 19 Apr 2018 17:02:06 GMT @@ -990,7 +2543,7 @@ Thu, 19 Apr 2018 17:02:06 GMT ## 5.6.3 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 5.6.2 Mon, 02 Apr 2018 16:05:24 GMT @@ -1060,7 +2613,7 @@ Thu, 15 Mar 2018 20:00:50 GMT ## 5.3.9 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 5.3.8 Mon, 12 Mar 2018 20:36:19 GMT @@ -1079,22 +2632,22 @@ Tue, 06 Mar 2018 17:04:51 GMT ## 5.3.6 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 5.3.5 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 5.3.4 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 5.3.3 Wed, 21 Feb 2018 03:13:28 GMT -*Version update only* +_Version update only_ ## 5.3.2 Sat, 17 Feb 2018 02:53:49 GMT @@ -1106,7 +2659,7 @@ Sat, 17 Feb 2018 02:53:49 GMT ## 5.3.1 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 5.3.0 Fri, 16 Feb 2018 17:05:11 GMT @@ -1123,12 +2676,12 @@ Fri, 16 Feb 2018 17:05:11 GMT ## 5.2.7 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 5.2.6 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 5.2.5 Fri, 26 Jan 2018 17:53:38 GMT @@ -1140,12 +2693,12 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 5.2.4 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 5.2.3 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 5.2.2 Thu, 18 Jan 2018 03:23:46 GMT @@ -1157,7 +2710,7 @@ Thu, 18 Jan 2018 03:23:46 GMT ## 5.2.1 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 5.2.0 Thu, 18 Jan 2018 00:27:23 GMT @@ -1169,7 +2722,7 @@ Thu, 18 Jan 2018 00:27:23 GMT ## 5.1.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 5.1.2 Fri, 12 Jan 2018 03:35:22 GMT @@ -1181,7 +2734,7 @@ Fri, 12 Jan 2018 03:35:22 GMT ## 5.1.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 5.1.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1215,7 +2768,7 @@ Sun, 07 Jan 2018 05:12:08 GMT ## 4.3.7 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 4.3.6 Fri, 05 Jan 2018 00:48:41 GMT @@ -1234,22 +2787,22 @@ Fri, 22 Dec 2017 17:04:46 GMT ## 4.3.4 Tue, 12 Dec 2017 03:33:26 GMT -*Version update only* +_Version update only_ ## 4.3.3 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 4.3.2 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 4.3.1 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 4.3.0 Tue, 28 Nov 2017 23:43:55 GMT @@ -1265,12 +2818,12 @@ Tue, 28 Nov 2017 23:43:55 GMT ## 4.2.6 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 4.2.5 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 4.2.4 Thu, 02 Nov 2017 16:05:24 GMT @@ -1289,12 +2842,12 @@ Wed, 01 Nov 2017 21:06:08 GMT ## 4.2.2 Tue, 31 Oct 2017 21:04:04 GMT -*Version update only* +_Version update only_ ## 4.2.1 Tue, 31 Oct 2017 16:04:55 GMT -*Version update only* +_Version update only_ ## 4.2.0 Wed, 25 Oct 2017 20:03:59 GMT @@ -1306,7 +2859,7 @@ Wed, 25 Oct 2017 20:03:59 GMT ## 4.1.2 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 4.1.1 Mon, 23 Oct 2017 21:53:12 GMT @@ -1343,7 +2896,7 @@ Fri, 20 Oct 2017 01:04:44 GMT ## 3.4.2 Thu, 05 Oct 2017 01:05:02 GMT -*Version update only* +_Version update only_ ## 3.4.1 Fri, 29 Sep 2017 01:03:42 GMT @@ -1374,7 +2927,7 @@ Fri, 22 Sep 2017 01:04:02 GMT ## 3.2.6 Wed, 20 Sep 2017 22:10:17 GMT -*Version update only* +_Version update only_ ## 3.2.5 Mon, 11 Sep 2017 13:04:55 GMT @@ -1443,7 +2996,7 @@ Thu, 31 Aug 2017 17:46:25 GMT ## 2.3.6 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 2.3.5 Thu, 24 Aug 2017 22:44:12 GMT @@ -1455,7 +3008,7 @@ Thu, 24 Aug 2017 22:44:12 GMT ## 2.3.4 Thu, 24 Aug 2017 01:04:33 GMT -*Version update only* +_Version update only_ ## 2.3.3 Tue, 22 Aug 2017 13:04:22 GMT @@ -1696,7 +3249,7 @@ Tue, 24 Jan 2017 01:36:35 GMT ## 1.1.2 Fri, 20 Jan 2017 01:46:41 GMT -*Version update only* +_Version update only_ ## 1.1.1 Thu, 19 Jan 2017 20:04:40 GMT @@ -1723,7 +3276,7 @@ Mon, 16 Jan 2017 20:04:15 GMT ## 1.0.1 Fri, 13 Jan 2017 06:46:05 GMT -*Version update only* +_Version update only_ ## 1.0.0 Wed, 11 Jan 2017 14:11:26 GMT diff --git a/apps/api-extractor/README.md b/apps/api-extractor/README.md index 13c744a42e8..69c1846fc1d 100644 --- a/apps/api-extractor/README.md +++ b/apps/api-extractor/README.md @@ -1,7 +1,7 @@ # @microsoft/api-extractor -![API Extractor](https://github.com/microsoft/rushstack/raw/master/common/wiki-images/api-extractor-title.png?raw=true) +![API Extractor](https://github.com/microsoft/rushstack/raw/main/common/wiki-images/api-extractor-title.png?raw=true)
      https://api-extractor.com/ @@ -37,8 +37,15 @@ Best of all, **API Extractor** is free and open source. Join the community and -# Getting Started +## Getting Started For more details and support resources, please visit: https://api-extractor.com/ -API documentation for this package: https://rushstack.io/pages/api/api-extractor/ +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/api-extractor/) + +API Extractor is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/api-extractor/bin/api-extractor b/apps/api-extractor/bin/api-extractor index 783bb806fce..aee68e80224 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/start.js'); diff --git a/apps/api-extractor/build-tests.cmd b/apps/api-extractor/build-tests.cmd index 9dd00a55271..cc33d4a4554 100644 --- a/apps/api-extractor/build-tests.cmd +++ b/apps/api-extractor/build-tests.cmd @@ -1,3 +1,3 @@ @ECHO OFF @SETLOCAL -rush build -t api-extractor-lib1-test -t api-extractor-lib2-test -t api-extractor-lib3-test -t api-extractor-scenarios -t api-extractor-test-01 -t api-extractor-test-02 -t api-extractor-test-03 -t api-extractor-test-04 -t api-documenter-test +rush test -t tag:api-extractor-tests diff --git a/apps/api-extractor/config/api-extractor.json b/apps/api-extractor/config/api-extractor.json index 3e8571b570b..aa9d8f810fd 100644 --- a/apps/api-extractor/config/api-extractor.json +++ b/apps/api-extractor/config/api-extractor.json @@ -15,6 +15,6 @@ "dtsRollup": { "enabled": true, - "untrimmedFilePath": "/dist/rollup.d.ts", + "untrimmedFilePath": "/dist/rollup.d.ts" } } diff --git a/apps/api-extractor/config/heft.json b/apps/api-extractor/config/heft.json new file mode 100644 index 00000000000..a36ac2cf4c0 --- /dev/null +++ b/apps/api-extractor/config/heft.json @@ -0,0 +1,53 @@ +/** + * 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": "decoupled-local-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"], + "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 new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/apps/api-extractor/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/api-extractor/config/jest.json b/apps/api-extractor/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/apps/api-extractor/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/apps/api-extractor/config/rig.json b/apps/api-extractor/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/apps/api-extractor/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/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/extends/tsdoc-base.json b/apps/api-extractor/extends/tsdoc-base.json new file mode 100644 index 00000000000..0aad9822873 --- /dev/null +++ b/apps/api-extractor/extends/tsdoc-base.json @@ -0,0 +1,72 @@ +/** + * This file defines the TSDoc custom tags for use with API Extractor. + * + * If your project has a custom tsdoc.json file, then it should use the "extends" field to + * inherit the definitions from this file. For example: + * + * ``` + * { + * "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + * "extends": [ "@microsoft/api-extractor/extends/tsdoc-config.json" ], + * . . . + * } + * ``` + * + * For details about this config file, please see: https://tsdoc.org/pages/packages/tsdoc-config/ + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + + /** + * The "AEDoc" custom tags: + */ + "tagDefinitions": [ + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + + /** + * TSDoc tags implemented by API Extractor: + */ + "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 + } +} diff --git a/apps/api-extractor/gulpfile.js b/apps/api-extractor/gulpfile.js deleted file mode 100644 index cf8fd436e63..00000000000 --- a/apps/api-extractor/gulpfile.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.jest.setConfig({ coverageReporters: ['json'] }); // Temporary - until the Handlebars issue is fixed - -build.initialize(require('gulp')); diff --git a/apps/api-extractor/package.json b/apps/api-extractor/package.json index dec38eeae29..5cb4392e35d 100644 --- a/apps/api-extractor/package.json +++ b/apps/api-extractor/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-extractor", - "version": "7.7.10", + "version": "7.55.2", "description": "Analyze the exported API for a TypeScript library and generate reviews, documentation, and .d.ts rollups", "keywords": [ "typescript", @@ -11,15 +11,18 @@ "generate", "documentation", "declaration", + "dts", ".d.ts", "rollup", + "bundle", "compiler", "alpha", "beta" ], "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/api-extractor" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/api-extractor" }, "homepage": "https://api-extractor.com", "main": "lib/index.js", @@ -29,26 +32,33 @@ }, "license": "MIT", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "@microsoft/api-extractor-model": "7.7.9", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/ts-command-line": "4.3.12", - "@microsoft/tsdoc": "0.12.14", - "colors": "~1.2.1", + "@microsoft/api-extractor-model": "workspace:*", + "@microsoft/tsdoc-config": "~0.18.0", + "@microsoft/tsdoc": "~0.16.0", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rig-package": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "diff": "~8.0.2", "lodash": "~4.17.15", - "resolve": "1.8.1", + "minimatch": "10.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", "source-map": "~0.6.1", - "typescript": "~3.7.2" + "typescript": "5.8.2" }, "devDependencies": { - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", + "@rushstack/heft": "1.1.4", "@types/lodash": "4.14.116", - "@types/node": "10.17.13", - "gulp": "~4.0.2" + "@types/resolve": "1.20.2", + "@types/semver": "7.5.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*" } } diff --git a/apps/api-extractor/src/aedoc/PackageDocComment.ts b/apps/api-extractor/src/aedoc/PackageDocComment.ts index c6bc4360ef0..3cc10e34526 100644 --- a/apps/api-extractor/src/aedoc/PackageDocComment.ts +++ b/apps/api-extractor/src/aedoc/PackageDocComment.ts @@ -2,16 +2,18 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { Collector } from '../collector/Collector'; + +import type { Collector } from '../collector/Collector'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; export class PackageDocComment { /** * For the given source file, see if it starts with a TSDoc comment containing the `@packageDocumentation` tag. */ - public static tryFindInSourceFile(sourceFile: ts.SourceFile, - collector: Collector): ts.TextRange | undefined { - + public static tryFindInSourceFile( + sourceFile: ts.SourceFile, + collector: Collector + ): ts.TextRange | undefined { // The @packageDocumentation comment is special because it is not attached to an AST // definition. Instead, it is part of the "trivia" tokens that the compiler treats // as irrelevant white space. @@ -47,8 +49,8 @@ export class PackageDocComment { // wrong place? This sanity check helps people to figure out why there comment isn't working. for (const statement of sourceFile.statements) { const ranges: ts.CommentRange[] = []; - ranges.push(...ts.getLeadingCommentRanges(sourceFile.text, statement.getFullStart()) || []); - ranges.push(...ts.getTrailingCommentRanges(sourceFile.text, statement.getEnd()) || []); + ranges.push(...(ts.getLeadingCommentRanges(sourceFile.text, statement.getFullStart()) || [])); + ranges.push(...(ts.getTrailingCommentRanges(sourceFile.text, statement.getEnd()) || [])); for (const commentRange of ranges) { const commentBody: string = sourceFile.text.substring(commentRange.pos, commentRange.end); @@ -57,7 +59,8 @@ export class PackageDocComment { collector.messageRouter.addAnalyzerIssueForPosition( ExtractorMessageId.MisplacedPackageTag, 'The @packageDocumentation comment must appear at the top of entry point *.d.ts file', - sourceFile, commentRange.pos + sourceFile, + commentRange.pos ); break; } @@ -67,5 +70,4 @@ export class PackageDocComment { return packageCommentRange; } - } diff --git a/apps/api-extractor/src/analyzer/AstDeclaration.ts b/apps/api-extractor/src/analyzer/AstDeclaration.ts index 10e906081ae..78cc4ed7337 100644 --- a/apps/api-extractor/src/analyzer/AstDeclaration.ts +++ b/apps/api-extractor/src/analyzer/AstDeclaration.ts @@ -2,10 +2,12 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { AstSymbol } from './AstSymbol'; -import { Span } from './Span'; + import { InternalError } from '@rushstack/node-core-library'; -import { AstEntity } from './AstSymbolTable'; + +import type { AstSymbol } from './AstSymbol'; +import { Span } from './Span'; +import type { AstEntity } from './AstEntity'; /** * Constructor options for AstDeclaration @@ -82,6 +84,18 @@ export class AstDeclaration { } this.modifierFlags = ts.getCombinedModifierFlags(this.declaration); + + // Check for ECMAScript private fields, for example: + // + // class Person { #name: string; } + // + const declarationName: ts.DeclarationName | undefined = ts.getNameOfDeclaration(this.declaration); + if (declarationName) { + if (ts.isPrivateIdentifier(declarationName)) { + // eslint-disable-next-line no-bitwise + this.modifierFlags |= ts.ModifierFlags.Private; + } + } } /** @@ -238,21 +252,21 @@ export class AstDeclaration { switch (kind) { case ts.SyntaxKind.CallSignature: case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.ConstructSignature: // Example: "new(x: number): IMyClass" - case ts.SyntaxKind.Constructor: // Example: "constructor(x: number)" + case ts.SyntaxKind.ConstructSignature: // Example: "new(x: number): IMyClass" + case ts.SyntaxKind.Constructor: // Example: "constructor(x: number)" case ts.SyntaxKind.EnumDeclaration: case ts.SyntaxKind.EnumMember: - case ts.SyntaxKind.FunctionDeclaration: // Example: "(x: number): number" + case ts.SyntaxKind.FunctionDeclaration: // Example: "(x: number): number" case ts.SyntaxKind.GetAccessor: case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.IndexSignature: // Example: "[key: string]: string" + case ts.SyntaxKind.IndexSignature: // Example: "[key: string]: string" case ts.SyntaxKind.InterfaceDeclaration: case ts.SyntaxKind.MethodDeclaration: case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.ModuleDeclaration: // Used for both "module" and "namespace" declarations + case ts.SyntaxKind.ModuleDeclaration: // Used for both "module" and "namespace" declarations case ts.SyntaxKind.PropertyDeclaration: case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.TypeAliasDeclaration: // Example: "type Shape = Circle | Square" + case ts.SyntaxKind.TypeAliasDeclaration: // Example: "type Shape = Circle | Square" case ts.SyntaxKind.VariableDeclaration: return true; @@ -268,5 +282,4 @@ export class AstDeclaration { return false; } - } diff --git a/apps/api-extractor/src/analyzer/AstEntity.ts b/apps/api-extractor/src/analyzer/AstEntity.ts new file mode 100644 index 00000000000..b3c6ceeda1b --- /dev/null +++ b/apps/api-extractor/src/analyzer/AstEntity.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * `AstEntity` is the abstract base class for analyzer objects that can become a `CollectorEntity`. + * + * @remarks + * + * The subclasses are: + * ``` + * - AstEntity + * - AstSymbol + * - AstSyntheticEntity + * - AstImport + * - AstNamespaceImport + * ``` + */ +export abstract class AstEntity { + /** + * The original name of the symbol, as exported from the module (i.e. source file) + * containing the original TypeScript definition. Constructs such as + * `import { X as Y } from` may introduce other names that differ from the local name. + * + * @remarks + * For the most part, `localName` corresponds to `followedSymbol.name`, but there + * are some edge cases. For example, the ts.Symbol.name for `export default class X { }` + * is actually `"default"`, not `"X"`. + */ + public abstract readonly localName: string; +} + +/** + * `AstSyntheticEntity` is the abstract base class for analyzer objects whose emitted declarations + * are not text transformations performed by the `Span` helper. + * + * @remarks + * Most of API Extractor's output is produced by using the using the `Span` utility to regurgitate strings from + * the input .d.ts files. If we need to rename an identifier, the `Span` visitor can pick out an interesting + * node and rewrite its string, but otherwise the transformation operates on dumb text and not compiler concepts. + * (Historically we did this because the compiler's emitter was an internal API, but it still has some advantages, + * for example preserving syntaxes generated by an older compiler to avoid incompatibilities.) + * + * This strategy does not work for cases where the output looks very different from the input. Today these + * cases are always kinds of `import` statements, but that may change in the future. + */ +export abstract class AstSyntheticEntity extends AstEntity {} diff --git a/apps/api-extractor/src/analyzer/AstImport.ts b/apps/api-extractor/src/analyzer/AstImport.ts index 7d7a6b5fb7a..38d4b1928a9 100644 --- a/apps/api-extractor/src/analyzer/AstImport.ts +++ b/apps/api-extractor/src/analyzer/AstImport.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 { AstSymbol } from './AstSymbol'; import { InternalError } from '@rushstack/node-core-library'; +import type { AstSymbol } from './AstSymbol'; +import { AstSyntheticEntity } from './AstEntity'; + /** * Indicates the import kind for an `AstImport`. */ @@ -26,7 +28,12 @@ export enum AstImportKind { /** * An import statement such as `import x = require("y");`. */ - EqualsImport + EqualsImport, + + /** + * An import statement such as `interface foo { foo: import("bar").a.b.c }`. + */ + ImportType } /** @@ -42,13 +49,14 @@ export interface IAstImportOptions { readonly importKind: AstImportKind; readonly modulePath: string; readonly exportName: string; + readonly isTypeOnly: boolean; } /** * For a symbol that was imported from an external package, this tracks the import * statement that was used to reach it. */ -export class AstImport { +export class AstImport extends AstSyntheticEntity { public readonly importKind: AstImportKind; /** @@ -78,10 +86,24 @@ export class AstImport { * * // For AstImportKind.EqualsImport style, exportName would be "x" in this example: * import x = require("y"); + * + * // For AstImportKind.ImportType style, exportName would be "a.b.c" in this example: + * interface foo { foo: import('bar').a.b.c }; * ``` */ public readonly exportName: string; + /** + * Whether it is a type-only import, for example: + * + * ```ts + * import type { X } from "y"; + * ``` + * + * This is set to true ONLY if the type-only form is used in *every* reference to this AstImport. + */ + public isTypeOnlyEverywhere: boolean; + /** * If this import statement refers to an API from an external package that is tracked by API Extractor * (according to `PackageMetadataManager.isAedocSupportedFor()`), then this property will return the @@ -98,18 +120,21 @@ export class AstImport { public readonly key: string; public constructor(options: IAstImportOptions) { + super(); + this.importKind = options.importKind; this.modulePath = options.modulePath; this.exportName = options.exportName; + // We start with this assumption, but it may get changed later if non-type-only import is encountered. + this.isTypeOnlyEverywhere = options.isTypeOnly; + this.key = AstImport.getKey(options); } - /** - * Allows `AstEntity.localName` to be used as a convenient generalization of `AstSymbol.localName` and - * `AstImport.exportName`. - */ + /** {@inheritdoc} */ public get localName(): string { + // abstract return this.exportName; } @@ -126,6 +151,14 @@ export class AstImport { return `${options.modulePath}:*`; case AstImportKind.EqualsImport: return `${options.modulePath}:=`; + case AstImportKind.ImportType: { + const subKey: string = !options.exportName + ? '*' // Equivalent to StarImport + : options.exportName.includes('.') // Equivalent to a named export + ? options.exportName.split('.')[0] + : options.exportName; + return `${options.modulePath}:${subKey}`; + } default: throw new InternalError('Unknown AstImportKind'); } diff --git a/apps/api-extractor/src/analyzer/AstModule.ts b/apps/api-extractor/src/analyzer/AstModule.ts index f18efb60a42..1ae3c2e91a3 100644 --- a/apps/api-extractor/src/analyzer/AstModule.ts +++ b/apps/api-extractor/src/analyzer/AstModule.ts @@ -1,21 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as ts from 'typescript'; +import type * as ts from 'typescript'; -import { AstSymbol } from './AstSymbol'; -import { AstEntity } from './AstSymbolTable'; +import type { AstSymbol } from './AstSymbol'; +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; } /** * Constructor parameters for AstModule + * + * @privateRemarks + * Our naming convention is to use I____Parameters for constructor options and + * I____Options for general function options. However the word "parameters" is + * confusingly similar to the terminology for function parameters modeled by API Extractor, + * so we use I____Options for both cases in this code base. */ export interface IAstModuleOptions { sourceFile: ts.SourceFile; @@ -25,12 +32,6 @@ export interface IAstModuleOptions { /** * An internal data structure that represents a source file that is analyzed by AstSymbolTable. - * - * @privateRemarks - * Our naming convention is to use I____Parameters for constructor options and - * I____Options for general function options. However the word "parameters" is - * confusingly similar to the terminology for function parameters modeled by API Extractor, - * so we use I____Options for both cases in this code base. */ export class AstModule { /** @@ -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/AstNamespaceExport.ts b/apps/api-extractor/src/analyzer/AstNamespaceExport.ts new file mode 100644 index 00000000000..f339bf6dbbb --- /dev/null +++ b/apps/api-extractor/src/analyzer/AstNamespaceExport.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 { AstNamespaceImport, type IAstNamespaceImportOptions } from './AstNamespaceImport'; + +export interface IAstNamespaceExportOptions extends IAstNamespaceImportOptions {} + +/** + * `AstNamespaceExport` represents a namespace that is created implicitly and exported by a statement + * such as `export * as example from "./file";` + * + * @remarks + * + * A typical input looks like this: + * ```ts + * // Suppose that example.ts exports two functions f1() and f2(). + * export * as example from "./file"; + * ``` + * + * API Extractor's .d.ts rollup will transform it into an explicit namespace, like this: + * ```ts + * declare f1(): void; + * declare f2(): void; + * + * export declare namespace example { + * export { + * f1, + * f2 + * } + * } + * ``` + * + * The current implementation does not attempt to relocate f1()/f2() to be inside the `namespace` + * because other type signatures may reference them directly (without using the namespace qualifier). + * The AstNamespaceExports behaves the same as AstNamespaceImport, it just also has the inline export for the craeted namespace. + */ + +export class AstNamespaceExport extends AstNamespaceImport { + public constructor(options: IAstNamespaceExportOptions) { + super(options); + } +} diff --git a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts new file mode 100644 index 00000000000..09304b9efcb --- /dev/null +++ b/apps/api-extractor/src/analyzer/AstNamespaceImport.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. + +import type * as ts from 'typescript'; + +import type { AstModule, IAstModuleExportInfo } from './AstModule'; +import { AstSyntheticEntity } from './AstEntity'; +import type { Collector } from '../collector/Collector'; + +export interface IAstNamespaceImportOptions { + readonly astModule: AstModule; + readonly namespaceName: string; + readonly declaration: ts.Declaration; + readonly symbol: ts.Symbol; +} + +/** + * `AstNamespaceImport` represents a namespace that is created implicitly by a statement + * such as `import * as example from "./file";` + * + * @remarks + * + * A typical input looks like this: + * ```ts + * // Suppose that example.ts exports two functions f1() and f2(). + * import * as example from "./file"; + * export { example }; + * ``` + * + * API Extractor's .d.ts rollup will transform it into an explicit namespace, like this: + * ```ts + * declare f1(): void; + * declare f2(): void; + * + * declare namespace example { + * export { + * f1, + * f2 + * } + * } + * ``` + * + * The current implementation does not attempt to relocate f1()/f2() to be inside the `namespace` + * because other type signatures may reference them directly (without using the namespace qualifier). + * The `declare namespace example` is a synthetic construct represented by `AstNamespaceImport`. + */ +export class AstNamespaceImport extends AstSyntheticEntity { + /** + * Returns true if the AstSymbolTable.analyze() was called for this object. + * See that function for details. + */ + public analyzed: boolean = false; + + /** + * For example, if the original statement was `import * as example from "./file";` + * then `astModule` refers to the `./file.d.ts` file. + */ + public readonly astModule: AstModule; + + /** + * For example, if the original statement was `import * as example from "./file";` + * then `namespaceName` would be `example`. + */ + public readonly namespaceName: string; + + /** + * The original `ts.SyntaxKind.NamespaceImport` which can be used as a location for error messages. + */ + public readonly declaration: ts.Declaration; + + /** + * The original `ts.SymbolFlags.Namespace` symbol. + */ + public readonly symbol: ts.Symbol; + + public constructor(options: IAstNamespaceImportOptions) { + super(); + this.astModule = options.astModule; + this.namespaceName = options.namespaceName; + this.declaration = options.declaration; + this.symbol = options.symbol; + } + + /** {@inheritdoc} */ + public get localName(): string { + // abstract + return this.namespaceName; + } + + 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 724f97148d4..e51de2f1934 100644 --- a/apps/api-extractor/src/analyzer/AstReferenceResolver.ts +++ b/apps/api-extractor/src/analyzer/AstReferenceResolver.ts @@ -2,15 +2,17 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import * as tsdoc from '@microsoft/tsdoc'; -import { AstSymbolTable, AstEntity } from './AstSymbolTable'; -import { AstDeclaration } from './AstDeclaration'; -import { WorkingPackage } from '../collector/WorkingPackage'; -import { AstModule } from './AstModule'; -import { AstImport } from './AstImport'; -import { Collector } from '../collector/Collector'; -import { DeclarationMetadata } from '../collector/DeclarationMetadata'; +import type { AstSymbolTable } from './AstSymbolTable'; +import type { AstEntity } from './AstEntity'; +import type { AstDeclaration } from './AstDeclaration'; +import type { WorkingPackage } from '../collector/WorkingPackage'; +import type { AstModule } from './AstModule'; +import type { Collector } from '../collector/Collector'; +import type { DeclarationMetadata } from '../collector/DeclarationMetadata'; +import { AstSymbol } from './AstSymbol'; /** * Used by `AstReferenceResolver` to report a failed resolution. @@ -52,8 +54,10 @@ export class AstReferenceResolver { public resolve(declarationReference: tsdoc.DocDeclarationReference): AstDeclaration | ResolverFailure { // Is it referring to the working package? - if (declarationReference.packageName !== undefined - && declarationReference.packageName !== this._workingPackage.name) { + if ( + declarationReference.packageName !== undefined && + declarationReference.packageName !== this._workingPackage.name + ) { return new ResolverFailure('External package references are not supported'); } @@ -63,7 +67,8 @@ export class AstReferenceResolver { } const astModule: AstModule = this._astSymbolTable.fetchAstModuleFromWorkingPackage( - this._workingPackage.entryPointSourceFile); + this._workingPackage.entryPointSourceFile + ); if (declarationReference.memberReferences.length === 0) { return new ResolverFailure('Package references are not supported'); @@ -77,18 +82,25 @@ export class AstReferenceResolver { } const rootAstEntity: AstEntity | undefined = this._astSymbolTable.tryGetExportOfAstModule( - exportName, astModule); + exportName, + astModule + ); if (rootAstEntity === undefined) { - return new ResolverFailure(`The package "${this._workingPackage.name}" does not have an export "${exportName}"`); + return new ResolverFailure( + `The package "${this._workingPackage.name}" does not have an export "${exportName}"` + ); } - if (rootAstEntity instanceof AstImport) { - return new ResolverFailure('Reexported declarations are not supported'); + if (!(rootAstEntity instanceof AstSymbol)) { + return new ResolverFailure('This type of declaration is not supported yet by the resolver'); } - let currentDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration(rootAstEntity.astDeclarations, - rootMemberReference, rootAstEntity.localName); + let currentDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration( + rootAstEntity.astDeclarations, + rootMemberReference, + rootAstEntity.localName + ); if (currentDeclaration instanceof ResolverFailure) { return currentDeclaration; @@ -102,13 +114,17 @@ export class AstReferenceResolver { return memberName; } - const matchingChildren: ReadonlyArray = currentDeclaration.findChildrenWithName(memberName); + const matchingChildren: ReadonlyArray = + currentDeclaration.findChildrenWithName(memberName); if (matchingChildren.length === 0) { return new ResolverFailure(`No member was found with name "${memberName}"`); } - const selectedDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration(matchingChildren, - memberReference, memberName); + const selectedDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration( + matchingChildren, + memberReference, + memberName + ); if (selectedDeclaration instanceof ResolverFailure) { return selectedDeclaration; @@ -130,9 +146,11 @@ export class AstReferenceResolver { return memberReference.memberIdentifier.identifier; } - private _selectDeclaration(astDeclarations: ReadonlyArray, - memberReference: tsdoc.DocMemberReference, astSymbolName: string): AstDeclaration | ResolverFailure { - + private _selectDeclaration( + astDeclarations: ReadonlyArray, + memberReference: tsdoc.DocMemberReference, + astSymbolName: string + ): AstDeclaration | ResolverFailure { const memberSelector: tsdoc.DocMemberSelector | undefined = memberReference.selector; if (memberSelector === undefined) { @@ -141,13 +159,16 @@ export class AstReferenceResolver { } else { // If we found multiple matches, but the extra ones are all ancillary declarations, // then return the main declaration. - const nonAncillaryMatch: AstDeclaration | undefined = this._tryDisambiguateAncillaryMatches(astDeclarations); + const nonAncillaryMatch: AstDeclaration | undefined = + this._tryDisambiguateAncillaryMatches(astDeclarations); if (nonAncillaryMatch) { return nonAncillaryMatch; } - return new ResolverFailure(`The reference is ambiguous because "${astSymbolName}"` - + ` has more than one declaration; you need to add a TSDoc member reference selector`); + return new ResolverFailure( + `The reference is ambiguous because "${astSymbolName}"` + + ` has more than one declaration; you need to add a TSDoc member reference selector` + ); } } @@ -161,9 +182,11 @@ export class AstReferenceResolver { return new ResolverFailure(`The selector "${memberSelector.selector}" is not a supported selector type`); } - private _selectUsingSystemSelector(astDeclarations: ReadonlyArray, - memberSelector: tsdoc.DocMemberSelector, astSymbolName: string): AstDeclaration | ResolverFailure { - + private _selectUsingSystemSelector( + astDeclarations: ReadonlyArray, + memberSelector: tsdoc.DocMemberSelector, + astSymbolName: string + ): AstDeclaration | ResolverFailure { const selectorName: string = memberSelector.selector; let selectorSyntaxKind: ts.SyntaxKind; @@ -194,10 +217,14 @@ export class AstReferenceResolver { return new ResolverFailure(`Unsupported system selector "${selectorName}"`); } - const matches: AstDeclaration[] = astDeclarations.filter(x => x.declaration.kind === selectorSyntaxKind); + const matches: AstDeclaration[] = astDeclarations.filter( + (x) => x.declaration.kind === selectorSyntaxKind + ); if (matches.length === 0) { - return new ResolverFailure(`A declaration for "${astSymbolName}" was not found that matches the` - + ` TSDoc selector "${selectorName}"`); + return new ResolverFailure( + `A declaration for "${astSymbolName}" was not found that matches the` + + ` TSDoc selector "${selectorName}"` + ); } if (matches.length > 1) { // If we found multiple matches, but the extra ones are all ancillary declarations, @@ -207,16 +234,19 @@ export class AstReferenceResolver { return nonAncillaryMatch; } - return new ResolverFailure(`More than one declaration "${astSymbolName}" matches the` - + ` TSDoc selector "${selectorName}"`); + return new ResolverFailure( + `More than one declaration "${astSymbolName}" matches the TSDoc selector "${selectorName}"` + ); } return matches[0]; } - private _selectUsingIndexSelector(astDeclarations: ReadonlyArray, - memberSelector: tsdoc.DocMemberSelector, astSymbolName: string): AstDeclaration | ResolverFailure { - - const selectorOverloadIndex: number = parseInt(memberSelector.selector); + private _selectUsingIndexSelector( + astDeclarations: ReadonlyArray, + memberSelector: tsdoc.DocMemberSelector, + astSymbolName: string + ): AstDeclaration | ResolverFailure { + const selectorOverloadIndex: number = parseInt(memberSelector.selector, 10); const matches: AstDeclaration[] = []; for (const astDeclaration of astDeclarations) { @@ -227,8 +257,10 @@ export class AstReferenceResolver { } if (matches.length === 0) { - return new ResolverFailure(`An overload for "${astSymbolName}" was not found that matches the` - + ` TSDoc selector ":${selectorOverloadIndex}"`); + return new ResolverFailure( + `An overload for "${astSymbolName}" was not found that matches the` + + ` TSDoc selector ":${selectorOverloadIndex}"` + ); } if (matches.length > 1) { // If we found multiple matches, but the extra ones are all ancillary declarations, @@ -238,8 +270,10 @@ export class AstReferenceResolver { return nonAncillaryMatch; } - return new ResolverFailure(`More than one declaration for "${astSymbolName}" matches the` - + ` TSDoc selector ":${selectorOverloadIndex}"`); + return new ResolverFailure( + `More than one declaration for "${astSymbolName}" matches the` + + ` TSDoc selector ":${selectorOverloadIndex}"` + ); } return matches[0]; } @@ -248,7 +282,9 @@ export class AstReferenceResolver { * This resolves an ambiguous match in the case where the extra matches are all ancillary declarations, * except for one match that is the main declaration. */ - private _tryDisambiguateAncillaryMatches(matches: ReadonlyArray): AstDeclaration | undefined { + private _tryDisambiguateAncillaryMatches( + matches: ReadonlyArray + ): AstDeclaration | undefined { let result: AstDeclaration | undefined = undefined; for (const match of matches) { diff --git a/apps/api-extractor/src/analyzer/AstSymbol.ts b/apps/api-extractor/src/analyzer/AstSymbol.ts index ce9d2861c1d..c8052d13dbb 100644 --- a/apps/api-extractor/src/analyzer/AstSymbol.ts +++ b/apps/api-extractor/src/analyzer/AstSymbol.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. -import * as ts from 'typescript'; -import { AstDeclaration } from './AstDeclaration'; +import type * as ts from 'typescript'; + import { InternalError } from '@rushstack/node-core-library'; +import type { AstDeclaration } from './AstDeclaration'; +import { AstEntity } from './AstEntity'; + /** * Constructor options for AstSymbol */ @@ -50,18 +53,9 @@ export interface IAstSymbolOptions { * - g * ``` */ -export class AstSymbol { - /** - * The original name of the symbol, as exported from the module (i.e. source file) - * containing the original TypeScript definition. Constructs such as - * `import { X as Y } from` may introduce other names that differ from the local name. - * - * @remarks - * For the most part, `localName` corresponds to `followedSymbol.name`, but there - * are some edge cases. For example, the symbol name for `export default class X { }` - * is actually `"default"`, not `"X"`. - */ - public readonly localName: string; +export class AstSymbol extends AstEntity { + /** {@inheritdoc} */ + public readonly localName: string; // abstract /** * If true, then the `followedSymbol` (i.e. original declaration) of this symbol @@ -121,6 +115,8 @@ export class AstSymbol { private _analyzed: boolean = false; public constructor(options: IAstSymbolOptions) { + super(); + this.followedSymbol = options.followedSymbol; this.localName = options.localName; this.isExternal = options.isExternal; diff --git a/apps/api-extractor/src/analyzer/AstSymbolTable.ts b/apps/api-extractor/src/analyzer/AstSymbolTable.ts index 19b998eb265..1bfa982b578 100644 --- a/apps/api-extractor/src/analyzer/AstSymbolTable.ts +++ b/apps/api-extractor/src/analyzer/AstSymbolTable.ts @@ -1,21 +1,24 @@ // 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 */ // for ts.SymbolFlags + import * as ts from 'typescript'; -import { PackageJsonLookup, InternalError } from '@rushstack/node-core-library'; + +import { type PackageJsonLookup, InternalError } from '@rushstack/node-core-library'; import { AstDeclaration } from './AstDeclaration'; import { TypeScriptHelpers } from './TypeScriptHelpers'; import { AstSymbol } from './AstSymbol'; -import { AstModule, AstModuleExportInfo } from './AstModule'; +import type { AstModule, IAstModuleExportInfo } from './AstModule'; import { PackageMetadataManager } from './PackageMetadataManager'; import { ExportAnalyzer } from './ExportAnalyzer'; -import { AstImport } from './AstImport'; -import { MessageRouter } from '../collector/MessageRouter'; -import { TypeScriptInternals } from './TypeScriptInternals'; -import { StringChecks } from './StringChecks'; - -export type AstEntity = AstSymbol | AstImport; +import type { AstEntity } from './AstEntity'; +import { AstNamespaceImport } from './AstNamespaceImport'; +import type { MessageRouter } from '../collector/MessageRouter'; +import { TypeScriptInternals, type IGlobalVariableAnalyzer } from './TypeScriptInternals'; +import { SyntaxHelpers } from './SyntaxHelpers'; +import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; /** * Options for `AstSymbolTable._fetchAstSymbol()` @@ -61,8 +64,11 @@ export interface IFetchAstSymbolOptions { export class AstSymbolTable { private readonly _program: ts.Program; private readonly _typeChecker: ts.TypeChecker; + private readonly _messageRouter: MessageRouter; + private readonly _globalVariableAnalyzer: IGlobalVariableAnalyzer; private readonly _packageMetadataManager: PackageMetadataManager; private readonly _exportAnalyzer: ExportAnalyzer; + private readonly _alreadyWarnedGlobalNames: Set; /** * A mapping from ts.Symbol --> AstSymbol @@ -76,43 +82,50 @@ export class AstSymbolTable { /** * A mapping from ts.Declaration --> AstDeclaration */ - private readonly _astDeclarationsByDeclaration: Map - = new Map(); + private readonly _astDeclarationsByDeclaration: Map = new Map< + ts.Node, + AstDeclaration + >(); // Note that this is a mapping from specific AST nodes that we analyzed, based on the underlying symbol // for that node. - private readonly _entitiesByIdentifierNode: Map - = new Map(); - - public constructor(program: ts.Program, typeChecker: ts.TypeChecker, packageJsonLookup: PackageJsonLookup, - bundledPackageNames: Set, messageRouter: MessageRouter) { - + private readonly _entitiesByNode: Map = new Map< + ts.Identifier, + AstEntity | undefined + >(); + + public constructor( + program: ts.Program, + typeChecker: ts.TypeChecker, + packageJsonLookup: PackageJsonLookup, + bundledPackageNames: ReadonlySet, + messageRouter: MessageRouter + ) { this._program = program; this._typeChecker = typeChecker; + this._messageRouter = messageRouter; + this._globalVariableAnalyzer = TypeScriptInternals.getGlobalVariableAnalyzer(program); this._packageMetadataManager = new PackageMetadataManager(packageJsonLookup, messageRouter); - this._exportAnalyzer = new ExportAnalyzer( - this._program, - this._typeChecker, - bundledPackageNames, - { - analyze: this.analyze.bind(this), - fetchAstSymbol: this._fetchAstSymbol.bind(this) - } - ); + this._exportAnalyzer = new ExportAnalyzer(this._program, this._typeChecker, bundledPackageNames, { + analyze: this.analyze.bind(this), + fetchAstSymbol: this._fetchAstSymbol.bind(this) + }); + + this._alreadyWarnedGlobalNames = new Set(); } /** * Used to analyze an entry point that belongs to the working package. */ public fetchAstModuleFromWorkingPackage(sourceFile: ts.SourceFile): AstModule { - return this._exportAnalyzer.fetchAstModuleFromSourceFile(sourceFile, undefined); + return this._exportAnalyzer.fetchAstModuleFromSourceFile(sourceFile, undefined, false); } /** * 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); } @@ -137,43 +150,13 @@ export class AstSymbolTable { * or members. (We do always construct its parents however, since AstDefinition.parent * is immutable, and needed e.g. to calculate release tag inheritance.) */ - public analyze(astSymbol: AstSymbol): void { - if (astSymbol.analyzed) { - return; + public analyze(astEntity: AstEntity): void { + if (astEntity instanceof AstSymbol) { + return this._analyzeAstSymbol(astEntity); } - if (astSymbol.nominalAnalysis) { - // We don't analyze nominal symbols - astSymbol._notifyAnalyzed(); - return; - } - - // Start at the root of the tree - const rootAstSymbol: AstSymbol = astSymbol.rootAstSymbol; - - // Calculate the full child tree for each definition - for (const astDeclaration of rootAstSymbol.astDeclarations) { - this._analyzeChildTree(astDeclaration.declaration, astDeclaration); - } - - rootAstSymbol._notifyAnalyzed(); - - if (!astSymbol.isExternal) { - // If this symbol is non-external (i.e. it belongs to the working package), then we also analyze any - // referencedAstSymbols that are non-external. For example, this ensures that forgotten exports - // get analyzed. - rootAstSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { - for (const referencedAstEntity of astDeclaration.referencedAstEntities) { - - // Walk up to the root of the tree, looking for any imports along the way - if (referencedAstEntity instanceof AstSymbol) { - if (!referencedAstEntity.isExternal) { - this.analyze(referencedAstEntity); - } - } - - } - }); + if (astEntity instanceof AstNamespaceImport) { + return this._analyzeAstNamespaceImport(astEntity); } } @@ -205,11 +188,11 @@ export class AstSymbolTable { * @remarks * Throws an Error if the ts.Identifier is not part of node tree that was analyzed. */ - public tryGetEntityForIdentifierNode(identifier: ts.Identifier): AstEntity | undefined { - if (!this._entitiesByIdentifierNode.has(identifier)) { + public tryGetEntityForNode(identifier: ts.Identifier | ts.ImportTypeNode): AstEntity | undefined { + if (!this._entitiesByNode.has(identifier)) { throw new InternalError('tryGetEntityForIdentifier() called for an identifier that was not analyzed'); } - return this._entitiesByIdentifierNode.get(identifier); + return this._entitiesByNode.get(identifier); } /** @@ -230,7 +213,9 @@ export class AstSymbolTable { public static getLocalNameForSymbol(symbol: ts.Symbol): string { // TypeScript binds well-known ECMAScript symbols like "[Symbol.iterator]" as "__@iterator". // Decode it back into "[Symbol.iterator]". - const wellKnownSymbolName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName(symbol.escapedName); + const wellKnownSymbolName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName( + symbol.escapedName + ); if (wellKnownSymbolName) { return wellKnownSymbolName; } @@ -277,7 +262,7 @@ export class AstSymbolTable { // Otherwise that name may come from a quoted string or pseudonym like `__constructor`. // If the string is not a safe identifier, then we must add quotes. // Note that if it was quoted but did not need to be quoted, here we will remove the quotes. - if (!StringChecks.isSafeUnquotedMemberIdentifier(unquotedName)) { + if (!SyntaxHelpers.isSafeUnquotedMemberIdentifier(unquotedName)) { // For API Extractor's purposes, a canonical form is more appropriate than trying to reflect whatever // appeared in the source code. The code is not even guaranteed to be consistent, for example: // @@ -292,6 +277,67 @@ export class AstSymbolTable { return unquotedName; } + private _analyzeAstNamespaceImport(astNamespaceImport: AstNamespaceImport): void { + if (astNamespaceImport.analyzed) { + return; + } + + // mark before actual analyzing, to handle module cyclic reexport + astNamespaceImport.analyzed = true; + + const exportedLocalEntities: Map = this.fetchAstModuleExportInfo( + astNamespaceImport.astModule + ).exportedLocalEntities; + + for (const exportedEntity of exportedLocalEntities.values()) { + this.analyze(exportedEntity); + } + } + + private _analyzeAstSymbol(astSymbol: AstSymbol): void { + if (astSymbol.analyzed) { + return; + } + + if (astSymbol.nominalAnalysis) { + // We don't analyze nominal symbols + astSymbol._notifyAnalyzed(); + return; + } + + // Start at the root of the tree + const rootAstSymbol: AstSymbol = astSymbol.rootAstSymbol; + + // Calculate the full child tree for each definition + for (const astDeclaration of rootAstSymbol.astDeclarations) { + this._analyzeChildTree(astDeclaration.declaration, astDeclaration); + } + + rootAstSymbol._notifyAnalyzed(); + + if (!astSymbol.isExternal) { + // If this symbol is non-external (i.e. it belongs to the working package), then we also analyze any + // referencedAstSymbols that are non-external. For example, this ensures that forgotten exports + // get analyzed. + rootAstSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { + for (const referencedAstEntity of astDeclaration.referencedAstEntities) { + // Walk up to the root of the tree, looking for any imports along the way + if (referencedAstEntity instanceof AstSymbol) { + if (!referencedAstEntity.isExternal) { + this._analyzeAstSymbol(referencedAstEntity); + } + } + + if (referencedAstEntity instanceof AstNamespaceImport) { + if (!referencedAstEntity.astModule.isExternal) { + this._analyzeAstNamespaceImport(referencedAstEntity); + } + } + } + }); + } + } + /** * Used by analyze to recursively analyze the entire child tree. */ @@ -303,27 +349,71 @@ export class AstSymbolTable { // Is this a reference to another AstSymbol? case ts.SyntaxKind.TypeReference: // general type references case ts.SyntaxKind.ExpressionWithTypeArguments: // special case for e.g. the "extends" keyword - case ts.SyntaxKind.ComputedPropertyName: // used for EcmaScript "symbols", e.g. "[toPrimitive]". + case ts.SyntaxKind.ComputedPropertyName: // used for EcmaScript "symbols", e.g. "[toPrimitive]". case ts.SyntaxKind.TypeQuery: // represents for "typeof X" as a type { // Sometimes the type reference will involve multiple identifiers, e.g. "a.b.C". // In this case, we only need to worry about importing the first identifier, // so do a depth-first search for it: const identifierNode: ts.Identifier | undefined = TypeScriptHelpers.findFirstChildNode( - node, ts.SyntaxKind.Identifier); + node, + ts.SyntaxKind.Identifier + ); if (identifierNode) { - let referencedAstEntity: AstEntity | undefined = this._entitiesByIdentifierNode.get(identifierNode); + let referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(identifierNode); if (!referencedAstEntity) { const symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(identifierNode); if (!symbol) { throw new Error('Symbol not found for identifier: ' + identifierNode.getText()); } - referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(symbol, - governingAstDeclaration.astSymbol.isExternal); + // Normally we expect getSymbolAtLocation() to take us to a declaration within the same source + // file, or else to an explicit "import" statement within the same source file. But in certain + // situations (e.g. a global variable) the symbol will refer to a declaration in some other + // source file. We'll call that case a "displaced symbol". + // + // For more info, see this discussion: + // https://github.com/microsoft/rushstack/issues/1765#issuecomment-595559849 + let displacedSymbol: boolean = true; + for (const declaration of symbol.declarations || []) { + if (declaration.getSourceFile() === identifierNode.getSourceFile()) { + displacedSymbol = false; + break; + } + } - this._entitiesByIdentifierNode.set(identifierNode, referencedAstEntity); + if (displacedSymbol) { + if (this._globalVariableAnalyzer.hasGlobalName(identifierNode.text)) { + // If the displaced symbol is a global variable, then API Extractor simply ignores it. + // Ambient declarations typically describe the runtime environment (provided by an API consumer), + // so we don't bother analyzing them as an API contract. (There are probably some packages + // that include interesting global variables in their API, but API Extractor doesn't support + // that yet; it would be a feature request.) + + if (this._messageRouter.showDiagnostics) { + if (!this._alreadyWarnedGlobalNames.has(identifierNode.text)) { + this._alreadyWarnedGlobalNames.add(identifierNode.text); + this._messageRouter.logDiagnostic( + `Ignoring reference to global variable "${identifierNode.text}"` + + ` in ` + + SourceFileLocationFormatter.formatDeclaration(identifierNode) + ); + } + } + } else { + // If you encounter this, please report a bug with a repro. We're interested to know + // how it can occur. + throw new InternalError(`Unable to follow symbol for "${identifierNode.text}"`); + } + } else { + referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity( + symbol, + governingAstDeclaration.astSymbol.isExternal + ); + + this._entitiesByNode.set(identifierNode, referencedAstEntity); + } } if (referencedAstEntity) { @@ -337,44 +427,78 @@ export class AstSymbolTable { case ts.SyntaxKind.Identifier: { const identifierNode: ts.Identifier = node as ts.Identifier; - if (!this._entitiesByIdentifierNode.has(identifierNode)) { + if (!this._entitiesByNode.has(identifierNode)) { const symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(identifierNode); let referencedAstEntity: AstEntity | undefined = undefined; if (symbol === governingAstDeclaration.astSymbol.followedSymbol) { - referencedAstEntity = this._fetchEntityForIdentifierNode(identifierNode, governingAstDeclaration); + referencedAstEntity = this._fetchEntityForNode(identifierNode, governingAstDeclaration); } - this._entitiesByIdentifierNode.set(identifierNode, referencedAstEntity); + this._entitiesByNode.set(identifierNode, referencedAstEntity); + } + } + break; + + case ts.SyntaxKind.ImportType: + { + const importTypeNode: ts.ImportTypeNode = node as ts.ImportTypeNode; + let referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(importTypeNode); + + if (!this._entitiesByNode.has(importTypeNode)) { + referencedAstEntity = this._fetchEntityForNode(importTypeNode, governingAstDeclaration); + + if (!referencedAstEntity) { + // This should never happen + throw new Error('Failed to fetch entity for import() type node: ' + importTypeNode.getText()); + } + + this._entitiesByNode.set(importTypeNode, referencedAstEntity); + } + + if (referencedAstEntity) { + governingAstDeclaration._notifyReferencedAstEntity(referencedAstEntity); } } break; } // Is this node declaring a new AstSymbol? - const newGoverningAstDeclaration: AstDeclaration | undefined = this._fetchAstDeclaration(node, - governingAstDeclaration.astSymbol.isExternal); + const newGoverningAstDeclaration: AstDeclaration | undefined = this._fetchAstDeclaration( + node, + governingAstDeclaration.astSymbol.isExternal + ); for (const childNode of node.getChildren()) { this._analyzeChildTree(childNode, newGoverningAstDeclaration || governingAstDeclaration); } } - private _fetchEntityForIdentifierNode(identifierNode: ts.Identifier, - governingAstDeclaration: AstDeclaration): AstEntity | undefined { - - let referencedAstEntity: AstEntity | undefined = this._entitiesByIdentifierNode.get(identifierNode); + private _fetchEntityForNode( + node: ts.Identifier | ts.ImportTypeNode, + governingAstDeclaration: AstDeclaration + ): AstEntity | undefined { + let referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(node); if (!referencedAstEntity) { - const symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(identifierNode); - if (!symbol) { - throw new Error('Symbol not found for identifier: ' + identifierNode.getText()); - } + if (node.kind === ts.SyntaxKind.ImportType) { + referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntityFromImportTypeNode( + node, + governingAstDeclaration.astSymbol.isExternal + ); + } else { + const symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(node); + if (!symbol) { + throw new Error('Symbol not found for identifier: ' + node.getText()); + } - referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(symbol, - governingAstDeclaration.astSymbol.isExternal); + referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity( + symbol, + governingAstDeclaration.astSymbol.isExternal + ); + } - this._entitiesByIdentifierNode.set(identifierNode, referencedAstEntity); + this._entitiesByNode.set(node, referencedAstEntity); } return referencedAstEntity; } @@ -384,8 +508,10 @@ export class AstSymbolTable { return undefined; } - const symbol: ts.Symbol | undefined = TypeScriptHelpers.getSymbolForDeclaration(node as ts.Declaration, - this._typeChecker); + const symbol: ts.Symbol | undefined = TypeScriptHelpers.getSymbolForDeclaration( + node as ts.Declaration, + this._typeChecker + ); if (!symbol) { throw new InternalError('Unable to find symbol for node'); } @@ -414,16 +540,19 @@ export class AstSymbolTable { const followedSymbol: ts.Symbol = options.followedSymbol; // Filter out symbols representing constructs that we don't care about - if (!TypeScriptHelpers.hasAnyDeclarations(followedSymbol)) { + const arbitraryDeclaration: ts.Declaration | undefined = + TypeScriptHelpers.tryGetADeclaration(followedSymbol); + if (!arbitraryDeclaration) { return undefined; } - const arbitraryDeclaration: ts.Declaration = followedSymbol.declarations[0]; - - // eslint-disable-next-line no-bitwise - if (followedSymbol.flags & (ts.SymbolFlags.TypeParameter | ts.SymbolFlags.TypeLiteral | ts.SymbolFlags.Transient) - && !TypeScriptInternals.isLateBoundSymbol(followedSymbol)) { - return undefined; + if ( + followedSymbol.flags & + (ts.SymbolFlags.TypeParameter | ts.SymbolFlags.TypeLiteral | ts.SymbolFlags.Transient) + ) { + if (!TypeScriptInternals.isLateBoundSymbol(followedSymbol)) { + return undefined; + } } // API Extractor doesn't analyze ambient declarations at all @@ -467,9 +596,11 @@ export class AstSymbolTable { if (!nominalAnalysis) { for (const declaration of followedSymbol.declarations || []) { if (!AstDeclaration.isSupportedSyntaxKind(declaration.kind)) { - throw new InternalError(`The "${followedSymbol.name}" symbol has a` - + ` ts.SyntaxKind.${ts.SyntaxKind[declaration.kind]} declaration which is not (yet?)` - + ` supported by API Extractor`); + throw new InternalError( + `The "${followedSymbol.name}" symbol has a` + + ` ts.SyntaxKind.${ts.SyntaxKind[declaration.kind]} declaration which is not (yet?)` + + ` supported by API Extractor` + ); } } @@ -485,28 +616,31 @@ export class AstSymbolTable { // - but P1 and P2 may be different (e.g. merged namespaces containing merged interfaces) // Is there a parent AstSymbol? First we check to see if there is a parent declaration: - const arbitraryParentDeclaration: ts.Node | undefined - = this._tryFindFirstAstDeclarationParent(followedSymbol.declarations[0]); - - if (arbitraryParentDeclaration) { - const parentSymbol: ts.Symbol = TypeScriptHelpers.getSymbolForDeclaration( - arbitraryParentDeclaration as ts.Declaration, - this._typeChecker); - - parentAstSymbol = this._fetchAstSymbol({ - followedSymbol: parentSymbol, - isExternal: options.isExternal, - includeNominalAnalysis: false, - addIfMissing: true - }); - if (!parentAstSymbol) { - throw new InternalError('Unable to construct a parent AstSymbol for ' - + followedSymbol.name); + if (arbitraryDeclaration) { + const arbitraryParentDeclaration: ts.Node | undefined = + this._tryFindFirstAstDeclarationParent(arbitraryDeclaration); + + if (arbitraryParentDeclaration) { + const parentSymbol: ts.Symbol = TypeScriptHelpers.getSymbolForDeclaration( + arbitraryParentDeclaration as ts.Declaration, + this._typeChecker + ); + + parentAstSymbol = this._fetchAstSymbol({ + followedSymbol: parentSymbol, + isExternal: options.isExternal, + includeNominalAnalysis: false, + addIfMissing: true + }); + if (!parentAstSymbol) { + throw new InternalError('Unable to construct a parent AstSymbol for ' + followedSymbol.name); + } } } } - const localName: string | undefined = options.localName || AstSymbolTable.getLocalNameForSymbol(followedSymbol); + const localName: string | undefined = + options.localName || AstSymbolTable.getLocalNameForSymbol(followedSymbol); astSymbol = new AstSymbol({ followedSymbol: followedSymbol, @@ -522,7 +656,6 @@ export class AstSymbolTable { // Okay, now while creating the declarations we will wire them up to the // their corresponding parent declarations for (const declaration of followedSymbol.declarations || []) { - let parentAstDeclaration: AstDeclaration | undefined = undefined; if (parentAstSymbol) { const parentDeclaration: ts.Node | undefined = this._tryFindFirstAstDeclarationParent(declaration); @@ -538,16 +671,21 @@ export class AstSymbolTable { } const astDeclaration: AstDeclaration = new AstDeclaration({ - declaration, astSymbol, parent: parentAstDeclaration}); + declaration, + astSymbol, + parent: parentAstDeclaration + }); this._astDeclarationsByDeclaration.set(declaration, astDeclaration); } } if (options.isExternal !== astSymbol.isExternal) { - throw new InternalError(`Cannot assign isExternal=${options.isExternal} for` - + ` the symbol ${astSymbol.localName} because it was previously registered` - + ` with isExternal=${astSymbol.isExternal}`); + throw new InternalError( + `Cannot assign isExternal=${options.isExternal} for` + + ` the symbol ${astSymbol.localName} because it was previously registered` + + ` with isExternal=${astSymbol.isExternal}` + ); } return astSymbol; diff --git a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index 4e9b36e1918..0bc6236aa4d 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -2,15 +2,20 @@ // 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, IAstImportOptions, AstImportKind } from './AstImport'; -import { AstModule, AstModuleExportInfo } from './AstModule'; +import { AstImport, type IAstImportOptions, AstImportKind } from './AstImport'; +import { AstModule, type IAstModuleExportInfo } from './AstModule'; import { TypeScriptInternals } from './TypeScriptInternals'; -import { TypeScriptMessageFormatter } from './TypeScriptMessageFormatter'; -import { IFetchAstSymbolOptions, AstEntity } from './AstSymbolTable'; +import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; +import type { IFetchAstSymbolOptions } from './AstSymbolTable'; +import type { AstEntity } from './AstEntity'; +import { AstNamespaceImport } from './AstNamespaceImport'; +import { SyntaxHelpers } from './SyntaxHelpers'; +import { AstNamespaceExport } from './AstNamespaceExport'; /** * Exposes the minimal APIs from AstSymbolTable that are needed by ExportAnalyzer. @@ -21,7 +26,7 @@ import { IFetchAstSymbolOptions, AstEntity } from './AstSymbolTable'; export interface IAstSymbolTable { fetchAstSymbol(options: IFetchAstSymbolOptions): AstSymbol | undefined; - analyze(astSymbol: AstSymbol): void; + analyze(astEntity: AstEntity): void; } /** @@ -53,29 +58,25 @@ interface IAstModuleReference { * generating .d.ts rollups. */ export class ExportAnalyzer { - // Captures "@a/b" or "d" from these examples: - // @a/b - // @a/b/c - // d - // d/ - // d/e - private static _modulePathRegExp: RegExp = /^((?:@[^@\/\s]+\/)?[^@\/\s]+)(?:.*)$/; - private readonly _program: ts.Program; private readonly _typeChecker: ts.TypeChecker; - private readonly _bundledPackageNames: Set; + private readonly _bundledPackageNames: ReadonlySet; private readonly _astSymbolTable: IAstSymbolTable; - private readonly _astModulesByModuleSymbol: Map - = new Map(); + private readonly _astModulesByModuleSymbol: Map = new Map(); // Used with isImportableAmbientSourceFile() private readonly _importableAmbientSourceFiles: Set = new Set(); private readonly _astImportsByKey: Map = new Map(); - - public constructor(program: ts.Program, typeChecker: ts.TypeChecker, bundledPackageNames: Set, - astSymbolTable: IAstSymbolTable) { + private readonly _astNamespaceImportByModule: Map = new Map(); + + public constructor( + program: ts.Program, + typeChecker: ts.TypeChecker, + bundledPackageNames: ReadonlySet, + astSymbolTable: IAstSymbolTable + ) { this._program = program; this._typeChecker = typeChecker; this._bundledPackageNames = bundledPackageNames; @@ -87,10 +88,13 @@ export class ExportAnalyzer { * * @param moduleReference - contextual information about the import statement that took us to this source file. * or `undefined` if this source file is the initial entry point + * @param isExternal - whether the given `moduleReference` is external. */ - public fetchAstModuleFromSourceFile(sourceFile: ts.SourceFile, - moduleReference: IAstModuleReference | undefined): AstModule { - + public fetchAstModuleFromSourceFile( + sourceFile: ts.SourceFile, + moduleReference: IAstModuleReference | undefined, + isExternal: boolean + ): AstModule { const moduleSymbol: ts.Symbol = this._getModuleSymbolFromSourceFile(sourceFile, moduleReference); // Don't traverse into a module that we already processed before: @@ -98,33 +102,32 @@ export class ExportAnalyzer { // even if m2 and m3 both have "export * from 'm4'". let astModule: AstModule | undefined = this._astModulesByModuleSymbol.get(moduleSymbol); if (!astModule) { - // (If moduleReference === undefined, then this is the entry point of the local project being analyzed.) - let externalModulePath: string | undefined = undefined; - if (moduleReference !== undefined) { - // Match: "@microsoft/sp-lodash-subset" or "lodash/has" - // but ignore: "../folder/LocalFile" - if (this._isExternalModulePath(moduleReference.moduleSpecifier)) { - externalModulePath = moduleReference.moduleSpecifier; - } - } + const externalModulePath: string | undefined = + moduleReference !== undefined && isExternal ? moduleReference.moduleSpecifier : undefined; - astModule = new AstModule({ sourceFile, moduleSymbol, externalModulePath }); + astModule = new AstModule({ sourceFile, moduleSymbol, externalModulePath }); this._astModulesByModuleSymbol.set(moduleSymbol, astModule); if (astModule.isExternal) { // It's an external package, so do the special simplified analysis that doesn't crawl into referenced modules for (const exportedSymbol of this._typeChecker.getExportsOfModule(moduleSymbol)) { - if (externalModulePath === undefined) { - throw new InternalError('Failed assertion: externalModulePath=undefined but astModule.isExternal=true'); + throw new InternalError( + 'Failed assertion: externalModulePath=undefined but astModule.isExternal=true' + ); } - const followedSymbol: ts.Symbol = TypeScriptHelpers.followAliases(exportedSymbol, this._typeChecker); + const followedSymbol: ts.Symbol = TypeScriptHelpers.followAliases( + exportedSymbol, + this._typeChecker + ); // Ignore virtual symbols that don't have any declarations - if (TypeScriptHelpers.hasAnyDeclarations(followedSymbol)) { + const arbitraryDeclaration: ts.Declaration | undefined = + TypeScriptHelpers.tryGetADeclaration(followedSymbol); + if (arbitraryDeclaration) { const astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({ followedSymbol: followedSymbol, isExternal: astModule.isExternal, @@ -133,8 +136,10 @@ export class ExportAnalyzer { }); if (!astSymbol) { - throw new Error(`Unsupported export ${JSON.stringify(exportedSymbol.name)} in ` - + TypeScriptMessageFormatter.formatFileAndLineNumber(followedSymbol.declarations[0])); + throw new Error( + `Unsupported export ${JSON.stringify(exportedSymbol.name)}:\n` + + SourceFileLocationFormatter.formatDeclaration(arbitraryDeclaration) + ); } astModule.cachedExportedEntities.set(exportedSymbol.name, astSymbol); @@ -146,13 +151,16 @@ export class ExportAnalyzer { if (moduleSymbol.exports) { // The "export * from 'module-name';" declarations are all attached to a single virtual symbol // whose name is InternalSymbolName.ExportStar - const exportStarSymbol: ts.Symbol | undefined = moduleSymbol.exports.get(ts.InternalSymbolName.ExportStar); + const exportStarSymbol: ts.Symbol | undefined = moduleSymbol.exports.get( + ts.InternalSymbolName.ExportStar + ); if (exportStarSymbol) { for (const exportStarDeclaration of exportStarSymbol.getDeclarations() || []) { if (ts.isExportDeclaration(exportStarDeclaration)) { - - const starExportedModule: AstModule | undefined = this._fetchSpecifierAstModule(exportStarDeclaration, - exportStarSymbol); + const starExportedModule: AstModule | undefined = this._fetchSpecifierAstModule( + exportStarDeclaration, + exportStarSymbol + ); if (starExportedModule !== undefined) { astModule.starExportedModules.add(starExportedModule); @@ -164,7 +172,6 @@ export class ExportAnalyzer { } } } - } } @@ -179,11 +186,14 @@ export class ExportAnalyzer { * (This is a deprecated construct and mainly used for typings such as `@types/node`.) In this situation, * `moduleReference` helps us to fish out the correct module symbol. */ - private _getModuleSymbolFromSourceFile(sourceFile: ts.SourceFile, - moduleReference: IAstModuleReference | undefined): ts.Symbol { - - const moduleSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(sourceFile, - this._typeChecker); + private _getModuleSymbolFromSourceFile( + sourceFile: ts.SourceFile, + moduleReference: IAstModuleReference | undefined + ): ts.Symbol { + const moduleSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( + sourceFile, + this._typeChecker + ); if (moduleSymbol !== undefined) { // This is the normal case. The SourceFile acts is a module and has a symbol. return moduleSymbol; @@ -197,7 +207,9 @@ export class ExportAnalyzer { if ((moduleReference.moduleSpecifierSymbol.flags & ts.SymbolFlags.Alias) !== 0) { // Follow the import/export declaration to one hop the exported item inside the target module let followedSymbol: ts.Symbol | undefined = TypeScriptInternals.getImmediateAliasedSymbol( - moduleReference.moduleSpecifierSymbol, this._typeChecker); + moduleReference.moduleSpecifierSymbol, + this._typeChecker + ); if (followedSymbol === undefined) { // This is a workaround for a compiler bug where getImmediateAliasedSymbol() sometimes returns undefined @@ -226,16 +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; } @@ -245,29 +260,56 @@ export class ExportAnalyzer { /** * Returns true if the module specifier refers to an external package. Ignores packages listed in the * "bundledPackages" setting from the api-extractor.json config file. - * - * @remarks - * Examples: - * - * - NO: `./file1` - * - YES: `library1/path/path` - * - YES: `@my-scope/my-package` */ - private _isExternalModulePath(moduleSpecifier: string): boolean { - if (ts.isExternalModuleNameRelative(moduleSpecifier)) { + private _isExternalModulePath( + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, + moduleSpecifier: string + ): boolean { + 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( + importOrExportDeclaration.getSourceFile(), + specifier, + this._program.getCompilerOptions() + ) + : undefined; + + const resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule( + this._program, + importOrExportDeclaration.getSourceFile(), + moduleSpecifier, + mode + ); + + if (resolvedModule === undefined) { + // The TS compiler API `getResolvedModule` cannot resolve ambient modules. Thus, to match API Extractor's + // previous behavior, simply treat all ambient modules as external. This bug is tracked by + // https://github.com/microsoft/rushstack/issues/3335. + return true; + } + + // Either something like `jquery` or `@microsoft/api-extractor`. + const packageName: string | undefined = resolvedModule.packageId?.name; + if (packageName !== undefined && this._bundledPackageNames.has(packageName)) { return false; } - const match: RegExpExecArray | null = ExportAnalyzer._modulePathRegExp.exec(moduleSpecifier); - if (match) { - // Extract "@my-scope/my-package" from "@my-scope/my-package/path/module" - const packageName: string = match[1]; - if (this._bundledPackageNames.has(packageName)) { - return false; - } + if (resolvedModule.isExternalLibraryImport === undefined) { + // This presumably means the compiler couldn't figure out whether the module was external, but we're not + // sure how this can happen. + throw new InternalError( + `Cannot determine whether the module ${JSON.stringify(moduleSpecifier)} is external\n` + + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) + ); } - return true; + return resolvedModule.isExternalLibraryImport; } /** @@ -280,16 +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) { @@ -301,14 +342,18 @@ 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) { this._astSymbolTable.analyze(astEntity); } - astModuleExportInfo.exportedLocalEntities.set(exportSymbol.name, astEntity); + if (astEntity instanceof AstNamespaceImport && !astEntity.astModule.isExternal) { + this._astSymbolTable.analyze(astEntity); + } + + exportedLocalEntities.set(exportSymbol.name, astEntity); } } break; @@ -317,7 +362,7 @@ export class ExportAnalyzer { } for (const starExportedModule of astModule.starExportedModules) { - this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule, visitedAstModules); + this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule); } } } @@ -327,16 +372,29 @@ export class ExportAnalyzer { * refers to. For example, if a particular interface describes the return value of a function, this API can help * us determine a TSDoc declaration reference for that symbol (if the symbol is exported). */ - public fetchReferencedAstEntity(symbol: ts.Symbol, referringModuleIsExternal: boolean): AstEntity | undefined { + public fetchReferencedAstEntity( + symbol: ts.Symbol, + referringModuleIsExternal: boolean + ): AstEntity | undefined { + // eslint-disable-next-line no-bitwise + if ((symbol.flags & ts.SymbolFlags.FunctionScopedVariable) !== 0) { + // If a symbol refers back to part of its own definition, don't follow that rabbit hole + // Example: + // + // function f(x: number): typeof x { + // return 123; + // } + return undefined; + } + let current: ts.Symbol = symbol; if (referringModuleIsExternal) { current = TypeScriptHelpers.followAliases(symbol, this._typeChecker); } else { - for (; ;) { + for (;;) { // Is this symbol an import/export that we need to follow to find the real declaration? for (const declaration of current.declarations || []) { - let matchedAstEntity: AstEntity | undefined; matchedAstEntity = this._tryMatchExportDeclaration(declaration, current); if (matchedAstEntity !== undefined) { @@ -348,11 +406,15 @@ export class ExportAnalyzer { } } - if (!(current.flags & ts.SymbolFlags.Alias)) { // eslint-disable-line no-bitwise + // eslint-disable-next-line no-bitwise + if (!(current.flags & ts.SymbolFlags.Alias)) { break; } - const currentAlias: ts.Symbol = TypeScriptInternals.getImmediateAliasedSymbol(current, this._typeChecker); + const currentAlias: ts.Symbol = TypeScriptInternals.getImmediateAliasedSymbol( + current, + this._typeChecker + ); // Stop if we reach the end of the chain if (!currentAlias || currentAlias === current) { break; @@ -373,9 +435,105 @@ export class ExportAnalyzer { return astSymbol; } - private _tryMatchExportDeclaration(declaration: ts.Declaration, declarationSymbol: ts.Symbol): AstEntity | undefined { - const exportDeclaration: ts.ExportDeclaration | undefined - = TypeScriptHelpers.findFirstParent(declaration, ts.SyntaxKind.ExportDeclaration); + public fetchReferencedAstEntityFromImportTypeNode( + node: ts.ImportTypeNode, + referringModuleIsExternal: boolean + ): AstEntity | undefined { + const externalModulePath: string | undefined = this._tryGetExternalModulePath(node); + + if (externalModulePath) { + let exportName: string; + if (node.qualifier) { + // Example input: + // import('api-extractor-lib1-test').Lib1GenericType + // + // Extracted qualifier: + // Lib1GenericType + exportName = node.qualifier.getText().trim(); + } else { + // Example input: + // import('api-extractor-lib1-test') + // + // Extracted qualifier: + // apiExtractorLib1Test + + exportName = SyntaxHelpers.makeCamelCaseIdentifier(externalModulePath); + } + + return this._fetchAstImport(undefined, { + importKind: AstImportKind.ImportType, + exportName: exportName, + modulePath: externalModulePath, + isTypeOnly: false + }); + } + + // Internal reference: AstSymbol + const rightMostToken: ts.Identifier | ts.ImportTypeNode = node.qualifier + ? node.qualifier.kind === ts.SyntaxKind.QualifiedName + ? node.qualifier.right + : node.qualifier + : node; + + // There is no symbol property in a ImportTypeNode, obtain the associated export symbol + const exportSymbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(rightMostToken); + if (!exportSymbol) { + throw new InternalError( + `Symbol not found for identifier: ${node.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(node) + ); + } + + let followedSymbol: ts.Symbol = exportSymbol; + for (;;) { + const referencedAstEntity: AstEntity | undefined = this.fetchReferencedAstEntity( + followedSymbol, + referringModuleIsExternal + ); + + if (referencedAstEntity) { + return referencedAstEntity; + } + + const followedSymbolNode: ts.Node | ts.ImportTypeNode | undefined = + followedSymbol.declarations && (followedSymbol.declarations[0] as ts.Node | undefined); + + if (followedSymbolNode && followedSymbolNode.kind === ts.SyntaxKind.ImportType) { + return this.fetchReferencedAstEntityFromImportTypeNode( + followedSymbolNode as ts.ImportTypeNode, + referringModuleIsExternal + ); + } + + // eslint-disable-next-line no-bitwise + if (!(followedSymbol.flags & ts.SymbolFlags.Alias)) { + break; + } + + const currentAlias: ts.Symbol = this._typeChecker.getAliasedSymbol(followedSymbol); + if (!currentAlias || currentAlias === followedSymbol) { + break; + } + + followedSymbol = currentAlias; + } + + const astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({ + followedSymbol: followedSymbol, + isExternal: referringModuleIsExternal, + includeNominalAnalysis: false, + addIfMissing: true + }); + + return astSymbol; + } + + private _tryMatchExportDeclaration( + declaration: ts.Declaration, + declarationSymbol: ts.Symbol + ): AstEntity | undefined { + const exportDeclaration: ts.ExportDeclaration | undefined = + TypeScriptHelpers.findFirstParent(declaration, ts.SyntaxKind.ExportDeclaration); if (exportDeclaration) { let exportName: string | undefined = undefined; @@ -399,20 +557,41 @@ export class ExportAnalyzer { // Example: " ExportName as RenamedName" const exportSpecifier: ts.ExportSpecifier = declaration as ts.ExportSpecifier; exportName = (exportSpecifier.propertyName || exportSpecifier.name).getText().trim(); + } else if (declaration.kind === ts.SyntaxKind.NamespaceExport) { + // EXAMPLE: + // "export * as theLib from 'the-lib';" + // + // ExportDeclaration: + // ExportKeyword: pre=[export] sep=[ ] + // NamespaceExport: + // AsteriskToken: pre=[*] sep=[ ] + // AsKeyword: pre=[as] sep=[ ] + // Identifier: pre=[theLib] sep=[ ] + // FromKeyword: pre=[from] sep=[ ] + // StringLiteral: pre=['the-lib'] + // SemicolonToken: pre=[;] + + // Issue tracking this feature: https://github.com/microsoft/rushstack/issues/2780 + + const astModule: AstModule = this._fetchSpecifierAstModule(exportDeclaration, declarationSymbol); + return this._getAstNamespaceExport(astModule, declarationSymbol, declaration); } else { - throw new InternalError('Unimplemented export declaration kind: ' + declaration.getText()); + throw new InternalError( + `Unimplemented export declaration kind: ${declaration.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(declaration) + ); } // Ignore "export { A }" without a module specifier if (exportDeclaration.moduleSpecifier) { - const externalModulePath: string | undefined = this._tryGetExternalModulePath(exportDeclaration, - declarationSymbol); + const externalModulePath: string | undefined = this._tryGetExternalModulePath(exportDeclaration); if (externalModulePath !== undefined) { return this._fetchAstImport(declarationSymbol, { importKind: AstImportKind.NamedImport, modulePath: externalModulePath, - exportName: exportName + exportName: exportName, + isTypeOnly: false }); } @@ -423,13 +602,34 @@ export class ExportAnalyzer { return undefined; } - private _tryMatchImportDeclaration(declaration: ts.Declaration, declarationSymbol: ts.Symbol): AstEntity | undefined { - const importDeclaration: ts.ImportDeclaration | undefined - = TypeScriptHelpers.findFirstParent(declaration, ts.SyntaxKind.ImportDeclaration); + private _getAstNamespaceExport( + astModule: AstModule, + declarationSymbol: ts.Symbol, + declaration: ts.Declaration + ): AstNamespaceExport { + const imoprtNamespace: AstNamespaceImport = this._getAstNamespaceImport( + astModule, + declarationSymbol, + declaration + ); + + return new AstNamespaceExport({ + namespaceName: imoprtNamespace.localName, + astModule: astModule, + declaration, + symbol: declarationSymbol + }); + } + + private _tryMatchImportDeclaration( + declaration: ts.Declaration, + declarationSymbol: ts.Symbol + ): AstEntity | undefined { + const importDeclaration: ts.ImportDeclaration | undefined = + TypeScriptHelpers.findFirstParent(declaration, ts.SyntaxKind.ImportDeclaration); if (importDeclaration) { - const externalModulePath: string | undefined = this._tryGetExternalModulePath(importDeclaration, - declarationSymbol); + const externalModulePath: string | undefined = this._tryGetExternalModulePath(importDeclaration); if (declaration.kind === ts.SyntaxKind.NamespaceImport) { // EXAMPLE: @@ -447,10 +647,8 @@ export class ExportAnalyzer { // SemicolonToken: pre=[;] if (externalModulePath === undefined) { - // The implementation here only works when importing from an external module. - // The full solution is tracked by: https://github.com/microsoft/rushstack/issues/1029 - throw new Error('"import * as ___ from ___;" is not supported yet for local files.' - + '\nFailure in: ' + importDeclaration.getSourceFile().fileName); + const astModule: AstModule = this._fetchSpecifierAstModule(importDeclaration, declarationSymbol); + return this._getAstNamespaceImport(astModule, declarationSymbol, declaration); } // Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for @@ -458,7 +656,8 @@ export class ExportAnalyzer { return this._fetchAstImport(undefined, { importKind: AstImportKind.StarImport, exportName: declarationSymbol.name, - modulePath: externalModulePath + modulePath: externalModulePath, + isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) }); } @@ -490,7 +689,8 @@ export class ExportAnalyzer { return this._fetchAstImport(declarationSymbol, { importKind: AstImportKind.NamedImport, modulePath: externalModulePath, - exportName: exportName + exportName: exportName, + isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) }); } @@ -515,20 +715,29 @@ export class ExportAnalyzer { // SemicolonToken: pre=[;] const importClause: ts.ImportClause = declaration as ts.ImportClause; - const exportName: string = importClause.name ? - importClause.name.getText().trim() : ts.InternalSymbolName.Default; + const exportName: string = importClause.name + ? importClause.name.getText().trim() + : ts.InternalSymbolName.Default; if (externalModulePath !== undefined) { return this._fetchAstImport(declarationSymbol, { importKind: AstImportKind.DefaultImport, modulePath: externalModulePath, - exportName + exportName, + isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) }); } - return this._getExportOfSpecifierAstModule(ts.InternalSymbolName.Default, importDeclaration, declarationSymbol); + return this._getExportOfSpecifierAstModule( + ts.InternalSymbolName.Default, + importDeclaration, + declarationSymbol + ); } else { - throw new InternalError('Unimplemented import declaration kind: ' + declaration.getText()); + throw new InternalError( + `Unimplemented import declaration kind: ${declaration.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(declaration) + ); } } @@ -548,15 +757,16 @@ export class ExportAnalyzer { // SemicolonToken: pre=[;] if (ts.isExternalModuleReference(declaration.moduleReference)) { if (ts.isStringLiteralLike(declaration.moduleReference.expression)) { - const variableName: string = TypeScriptInternals.getTextOfIdentifierOrLiteral( - declaration.name); + const variableName: string = TypeScriptInternals.getTextOfIdentifierOrLiteral(declaration.name); const externalModuleName: string = TypeScriptInternals.getTextOfIdentifierOrLiteral( - declaration.moduleReference.expression); + declaration.moduleReference.expression + ); return this._fetchAstImport(declarationSymbol, { importKind: AstImportKind.EqualsImport, modulePath: externalModuleName, - exportName: variableName + exportName: variableName, + isTypeOnly: false }); } } @@ -565,23 +775,56 @@ export class ExportAnalyzer { return undefined; } - private _getExportOfSpecifierAstModule(exportName: string, - importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, - exportSymbol: ts.Symbol): AstEntity { + private _getAstNamespaceImport( + astModule: AstModule, + declarationSymbol: ts.Symbol, + declaration: ts.Declaration + ): AstNamespaceImport { + let namespaceImport: AstNamespaceImport | undefined = this._astNamespaceImportByModule.get(astModule); + if (namespaceImport === undefined) { + namespaceImport = new AstNamespaceImport({ + namespaceName: declarationSymbol.name, + astModule: astModule, + declaration: declaration, + symbol: declarationSymbol + }); + this._astNamespaceImportByModule.set(astModule, namespaceImport); + } + + return namespaceImport; + } + + private static _getIsTypeOnly(importDeclaration: ts.ImportDeclaration): boolean { + if (importDeclaration.importClause) { + return !!importDeclaration.importClause.isTypeOnly; + } + return false; + } - const specifierAstModule: AstModule = this._fetchSpecifierAstModule(importOrExportDeclaration, exportSymbol); + private _getExportOfSpecifierAstModule( + exportName: string, + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, + exportSymbol: ts.Symbol + ): AstEntity { + const specifierAstModule: AstModule = this._fetchSpecifierAstModule( + importOrExportDeclaration, + exportSymbol + ); const astEntity: AstEntity = this._getExportOfAstModule(exportName, specifierAstModule); return astEntity; } private _getExportOfAstModule(exportName: string, astModule: AstModule): AstEntity { - const visitedAstModules: Set = new Set(); - const astEntity: AstEntity | undefined = this._tryGetExportOfAstModule(exportName, astModule, - visitedAstModules); + const astEntity: AstEntity | undefined = this._tryGetExportOfAstModule( + exportName, + astModule, + visitedAstModules + ); if (astEntity === undefined) { - throw new InternalError(`Unable to analyze the export ${JSON.stringify(exportName)} in\n` - + astModule.sourceFile.fileName); + throw new InternalError( + `Unable to analyze the export ${JSON.stringify(exportName)} in\n` + astModule.sourceFile.fileName + ); } return astEntity; } @@ -591,13 +834,14 @@ export class ExportAnalyzer { */ public tryGetExportOfAstModule(exportName: string, astModule: AstModule): AstEntity | undefined { const visitedAstModules: Set = new Set(); - return this._tryGetExportOfAstModule(exportName, astModule, - visitedAstModules); + return this._tryGetExportOfAstModule(exportName, astModule, visitedAstModules); } - private _tryGetExportOfAstModule(exportName: string, astModule: AstModule, - visitedAstModules: Set): AstEntity | undefined { - + private _tryGetExportOfAstModule( + exportName: string, + astModule: AstModule, + visitedAstModules: Set + ): AstEntity | undefined { if (visitedAstModules.has(astModule)) { return undefined; } @@ -627,14 +871,14 @@ export class ExportAnalyzer { astEntity = this._tryGetExportOfAstModule(exportName, starExportedModule, visitedAstModules); if (astEntity !== undefined) { - if (starExportedModule.externalModulePath !== undefined) { // This entity was obtained from an external module, so return an AstImport instead const astSymbol: AstSymbol = astEntity as AstSymbol; return this._fetchAstImport(astSymbol.followedSymbol, { importKind: AstImportKind.NamedImport, modulePath: starExportedModule.externalModulePath, - exportName: exportName + exportName: exportName, + isTypeOnly: false }); } @@ -645,18 +889,11 @@ export class ExportAnalyzer { return undefined; } - private _tryGetExternalModulePath(importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, - exportSymbol: ts.Symbol): string | undefined { - - // The name of the module, which could be like "./SomeLocalFile' or like 'external-package/entry/point' - const moduleSpecifier: string | undefined = TypeScriptHelpers.getModuleSpecifier(importOrExportDeclaration); - if (!moduleSpecifier) { - throw new InternalError('Unable to parse module specifier'); - } - - // Match: "@microsoft/sp-lodash-subset" or "lodash/has" - // but ignore: "../folder/LocalFile" - if (this._isExternalModulePath(moduleSpecifier)) { + private _tryGetExternalModulePath( + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode + ): string | undefined { + const moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration); + if (this._isExternalModulePath(importOrExportDeclaration, moduleSpecifier)) { return moduleSpecifier; } @@ -667,38 +904,63 @@ export class ExportAnalyzer { * Given an ImportDeclaration of the form `export { X } from "___";`, this interprets the module specifier (`"___"`) * and fetches the corresponding AstModule object. */ - private _fetchSpecifierAstModule(importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, - exportSymbol: ts.Symbol): AstModule { - - // The name of the module, which could be like "./SomeLocalFile' or like 'external-package/entry/point' - const moduleSpecifier: string | undefined = TypeScriptHelpers.getModuleSpecifier(importOrExportDeclaration); - if (!moduleSpecifier) { - throw new InternalError('Unable to parse module specifier'); - } - + private _fetchSpecifierAstModule( + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, + exportSymbol: ts.Symbol + ): AstModule { + const moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration); + const mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined = + importOrExportDeclaration.moduleSpecifier && + ts.isStringLiteralLike(importOrExportDeclaration.moduleSpecifier) + ? TypeScriptInternals.getModeForUsageLocation( + importOrExportDeclaration.getSourceFile(), + importOrExportDeclaration.moduleSpecifier, + this._program.getCompilerOptions() + ) + : undefined; const resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule( - importOrExportDeclaration.getSourceFile(), moduleSpecifier); + this._program, + importOrExportDeclaration.getSourceFile(), + moduleSpecifier, + mode + ); if (resolvedModule === undefined) { - // This should not happen, since getResolvedModule() specifically looks up names that the compiler - // found in export declarations for this source file - throw new InternalError('getResolvedModule() could not resolve module name ' + JSON.stringify(moduleSpecifier)); + // Encountered in https://github.com/microsoft/rushstack/issues/1914. + // + // It's also possible for this to occur with ambient modules. However, in practice this doesn't happen + // as API Extractor treats all ambient modules as external per the logic in `_isExternalModulePath`, and + // thus this code path is never reached for ambient modules. + throw new InternalError( + `getResolvedModule() could not resolve module name ${JSON.stringify(moduleSpecifier)}\n` + + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) + ); } // Map the filename back to the corresponding SourceFile. This circuitous approach is needed because // we have no way to access the compiler's internal resolveExternalModuleName() function - const moduleSourceFile: ts.SourceFile | undefined = this._program.getSourceFile(resolvedModule.resolvedFileName); + const moduleSourceFile: ts.SourceFile | undefined = this._program.getSourceFile( + resolvedModule.resolvedFileName + ); if (!moduleSourceFile) { // This should not happen, since getResolvedModule() specifically looks up names that the compiler // found in export declarations for this source file - throw new InternalError('getSourceFile() failed to locate ' + JSON.stringify(resolvedModule.resolvedFileName)); + throw new InternalError( + `getSourceFile() failed to locate ${JSON.stringify(resolvedModule.resolvedFileName)}\n` + + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) + ); } + const isExternal: boolean = this._isExternalModulePath(importOrExportDeclaration, moduleSpecifier); const moduleReference: IAstModuleReference = { moduleSpecifier: moduleSpecifier, moduleSpecifierSymbol: exportSymbol }; - const specifierAstModule: AstModule = this.fetchAstModuleFromSourceFile(moduleSourceFile, moduleReference); + const specifierAstModule: AstModule = this.fetchAstModuleFromSourceFile( + moduleSourceFile, + moduleReference, + isExternal + ); return specifierAstModule; } @@ -722,8 +984,31 @@ export class ExportAnalyzer { addIfMissing: true }); } + } else { + // If we encounter at least one import that does not use the type-only form, + // then the .d.ts rollup will NOT use "import type". + if (!options.isTypeOnly) { + astImport.isTypeOnlyEverywhere = false; + } } return astImport; } + + private _getModuleSpecifier( + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode + ): string { + // The name of the module, which could be like "./SomeLocalFile' or like 'external-package/entry/point' + const moduleSpecifier: string | undefined = + TypeScriptHelpers.getModuleSpecifier(importOrExportDeclaration); + + if (!moduleSpecifier) { + throw new InternalError( + 'Unable to parse module specifier\n' + + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) + ); + } + + return moduleSpecifier; + } } diff --git a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts b/apps/api-extractor/src/analyzer/PackageMetadataManager.ts index 8de8edc14cf..22b9be7e891 100644 --- a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts +++ b/apps/api-extractor/src/analyzer/PackageMetadataManager.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 path from 'node:path'; + +import semver from 'semver'; import { - PackageJsonLookup, + type PackageJsonLookup, FileSystem, JsonFile, - NewlineKind, - INodePackageJson, - JsonObject + type NewlineKind, + type INodePackageJson, + type JsonObject, + type IPackageJsonExports } from '@rushstack/node-core-library'; + import { Extractor } from '../api/Extractor'; -import { MessageRouter } from '../collector/MessageRouter'; +import type { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from '../api/ConsoleMessageId'; /** @@ -42,6 +46,134 @@ export class PackageMetadata { } } +const TSDOC_METADATA_FILENAME: 'tsdoc-metadata.json' = 'tsdoc-metadata.json'; + +/** + * 1. If package.json a `"tsdocMetadata": "./path1/path2/tsdoc-metadata.json"` field + * then that takes precedence. This convention will be rarely needed, since the other rules below generally + * produce a good result. + */ +function _tryResolveTsdocMetadataFromTsdocMetadataField({ + tsdocMetadata +}: INodePackageJson): string | undefined { + return tsdocMetadata; +} + +/** + * 2. If package.json contains a `"exports": { ".": { "types": "./path1/path2/index.d.ts" } }` field, + * then we look for the file under "./path1/path2/tsdoc-metadata.json" + * + * This always looks for a "." and then a "*" entry in the exports field, and then evaluates for + * a "types" field in that entry. + */ + +function _tryResolveTsdocMetadataFromExportsField({ exports }: INodePackageJson): string | undefined { + switch (typeof exports) { + case 'string': { + return `${path.dirname(exports)}/${TSDOC_METADATA_FILENAME}`; + } + + case 'object': { + if (Array.isArray(exports)) { + const [firstExport] = exports; + // Take the first entry in the array + if (firstExport) { + return `${path.dirname(exports[0])}/${TSDOC_METADATA_FILENAME}`; + } + } else { + const rootExport: IPackageJsonExports | string | null | undefined = exports['.'] ?? exports['*']; + switch (typeof rootExport) { + case 'string': { + return `${path.dirname(rootExport)}/${TSDOC_METADATA_FILENAME}`; + } + + case 'object': { + let typesExport: IPackageJsonExports | string | undefined = rootExport?.types; + while (typesExport) { + switch (typeof typesExport) { + case 'string': { + return `${path.dirname(typesExport)}/${TSDOC_METADATA_FILENAME}`; + } + + case 'object': { + typesExport = typesExport?.types; + break; + } + } + } + } + } + } + break; + } + } +} + +/** + * 3. If package.json contains a `typesVersions` field, look for the version + * matching the highest minimum version that either includes a "." or "*" entry. + */ +function _tryResolveTsdocMetadataFromTypesVersionsField({ + typesVersions +}: INodePackageJson): string | undefined { + if (typesVersions) { + let highestMinimumMatchingSemver: semver.SemVer | undefined; + let latestMatchingPath: string | undefined; + for (const [version, paths] of Object.entries(typesVersions)) { + let range: semver.Range; + try { + range = new semver.Range(version); + } catch { + continue; + } + + const minimumMatchingSemver: semver.SemVer | null = semver.minVersion(range); + if ( + minimumMatchingSemver && + (!highestMinimumMatchingSemver || semver.gt(minimumMatchingSemver, highestMinimumMatchingSemver)) + ) { + const pathEntry: string[] | undefined = paths['.'] ?? paths['*']; + const firstPath: string | undefined = pathEntry?.[0]; + if (firstPath) { + highestMinimumMatchingSemver = minimumMatchingSemver; + latestMatchingPath = firstPath; + } + } + } + + if (latestMatchingPath) { + return `${path.dirname(latestMatchingPath)}/${TSDOC_METADATA_FILENAME}`; + } + } +} + +/** + * 4. If package.json contains a `"types": "./path1/path2/index.d.ts"` or a `"typings": "./path1/path2/index.d.ts"` + * field, then we look for the file under "./path1/path2/tsdoc-metadata.json". + * + * @remarks + * `types` takes precedence over `typings`. + */ +function _tryResolveTsdocMetadataFromTypesOrTypingsFields({ + typings, + types +}: INodePackageJson): string | undefined { + const typesField: string | undefined = types ?? typings; + if (typesField) { + return `${path.dirname(typesField)}/${TSDOC_METADATA_FILENAME}`; + } +} + +/** + * 5. If package.json contains a `"main": "./path1/path2/index.js"` field, then we look for the file under + * "./path1/path2/tsdoc-metadata.json". + */ +function _tryResolveTsdocMetadataFromMainField({ main }: INodePackageJson): string | undefined { + if (main) { + return `${path.dirname(main)}/${TSDOC_METADATA_FILENAME}`; + } +} + /** * This class maintains a cache of analyzed information obtained from package.json * files. It is built on top of the PackageJsonLookup class. @@ -56,56 +188,43 @@ export class PackageMetadata { * Use ts.program.isSourceFileFromExternalLibrary() to test source files before passing the to PackageMetadataManager. */ export class PackageMetadataManager { - public static tsdocMetadataFilename: string = 'tsdoc-metadata.json'; + public static tsdocMetadataFilename: string = TSDOC_METADATA_FILENAME; private readonly _packageJsonLookup: PackageJsonLookup; private readonly _messageRouter: MessageRouter; - private readonly _packageMetadataByPackageJsonPath: Map - = new Map(); + private readonly _packageMetadataByPackageJsonPath: Map = new Map< + string, + PackageMetadata + >(); public constructor(packageJsonLookup: PackageJsonLookup, messageRouter: MessageRouter) { this._packageJsonLookup = packageJsonLookup; 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 tsdocMetadataFilename: string = PackageMetadataManager.tsdocMetadataFilename; - - let tsdocMetadataRelativePath: string; - - if (packageJson.tsdocMetadata) { - // 1. If package.json contains a field such as "tsdocMetadata": "./path1/path2/tsdoc-metadata.json", - // then that takes precedence. This convention will be rarely needed, since the other rules below generally - // produce a good result. - tsdocMetadataRelativePath = packageJson.tsdocMetadata; - } else if (packageJson.typings) { - // 2. If package.json contains a field such as "typings": "./path1/path2/index.d.ts", then we look - // for the file under "./path1/path2/tsdoc-metadata.json" - tsdocMetadataRelativePath = path.join( - path.dirname(packageJson.typings), - tsdocMetadataFilename - ); - } else if (packageJson.main) { - // 3. If package.json contains a field such as "main": "./path1/path2/index.js", then we look for - // the file under "./path1/path2/tsdoc-metadata.json" - tsdocMetadataRelativePath = path.join( - path.dirname(packageJson.main), - tsdocMetadataFilename - ); - } else { - // 4. If none of the above rules apply, then by default we look for the file under "./tsdoc-metadata.json" - // since the default entry point is "./index.js" - tsdocMetadataRelativePath = tsdocMetadataFilename; - } + /** + * 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, - tsdocMetadataRelativePath + // This non-null assertion is safe because the last entry in TSDOC_METADATA_RESOLUTION_FUNCTIONS + // returns a non-undefined value. + tsdocMetadataRelativePath! ); return tsdocMetadataPath; } @@ -123,10 +242,8 @@ export class PackageMetadataManager { if (tsdocMetadataPath) { return path.resolve(packageFolder, tsdocMetadataPath); } - return PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson( - packageFolder, - packageJson - ); + + return PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson(packageFolder, packageJson); } /** @@ -160,13 +277,13 @@ export class PackageMetadataManager { * is returned. The results are cached. */ public tryFetchPackageMetadata(sourceFilePath: string): PackageMetadata | undefined { - const packageJsonFilePath: string | undefined - = this._packageJsonLookup.tryGetPackageJsonFilePathFor(sourceFilePath); + const packageJsonFilePath: string | undefined = + this._packageJsonLookup.tryGetPackageJsonFilePathFor(sourceFilePath); if (!packageJsonFilePath) { return undefined; } - let packageMetadata: PackageMetadata | undefined - = this._packageMetadataByPackageJsonPath.get(packageJsonFilePath); + let packageMetadata: PackageMetadata | undefined = + this._packageMetadataByPackageJsonPath.get(packageJsonFilePath); if (!packageMetadata) { const packageJson: INodePackageJson = this._packageJsonLookup.loadNodePackageJson(packageJsonFilePath); @@ -181,7 +298,10 @@ export class PackageMetadataManager { ); if (FileSystem.exists(tsdocMetadataPath)) { - this._messageRouter.logVerbose(ConsoleMessageId.FoundTSDocMetadata, 'Found metadata in ' + tsdocMetadataPath); + this._messageRouter.logVerbose( + ConsoleMessageId.FoundTSDocMetadata, + 'Found metadata in ' + tsdocMetadataPath + ); // If the file exists at all, assume it was written by API Extractor aedocSupported = true; } diff --git a/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts new file mode 100644 index 00000000000..939f9aa5ba2 --- /dev/null +++ b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.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. + +import * as path from 'node:path'; + +import type * as ts from 'typescript'; + +import { Path, Text } from '@rushstack/node-core-library'; + +export interface ISourceFileLocationFormatOptions { + sourceFileLine?: number; + sourceFileColumn?: number; + workingPackageFolderPath?: string; +} + +export class SourceFileLocationFormatter { + /** + * Returns a string such as this, based on the context information in the provided node: + * "[C:\Folder\File.ts#123]" + */ + public static formatDeclaration(node: ts.Node, workingPackageFolderPath?: string): string { + const sourceFile: ts.SourceFile = node.getSourceFile(); + const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + + return SourceFileLocationFormatter.formatPath(sourceFile.fileName, { + sourceFileLine: lineAndCharacter.line + 1, + sourceFileColumn: lineAndCharacter.character + 1, + workingPackageFolderPath + }); + } + + public static formatPath(sourceFilePath: string, options?: ISourceFileLocationFormatOptions): string { + if (!options) { + options = {}; + } + + let result: string = ''; + + // Make the path relative to the workingPackageFolderPath + let scrubbedPath: string = sourceFilePath; + + if (options.workingPackageFolderPath) { + // If it's under the working folder, make it a relative path + if (Path.isUnderOrEqual(sourceFilePath, options.workingPackageFolderPath)) { + scrubbedPath = path.relative(options.workingPackageFolderPath, sourceFilePath); + } + } + + // Convert it to a Unix-style path + scrubbedPath = Text.replaceAll(scrubbedPath, '\\', '/'); + result += scrubbedPath; + + if (options.sourceFileLine) { + result += `:${options.sourceFileLine}`; + + if (options.sourceFileColumn) { + result += `:${options.sourceFileColumn}`; + } + } + + return result; + } +} diff --git a/apps/api-extractor/src/analyzer/Span.ts b/apps/api-extractor/src/analyzer/Span.ts index da41839e55e..e4d1f2970ab 100644 --- a/apps/api-extractor/src/analyzer/Span.ts +++ b/apps/api-extractor/src/analyzer/Span.ts @@ -2,8 +2,55 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { StringBuilder } from '@microsoft/tsdoc'; -import { Sort } from '@rushstack/node-core-library'; + +import { InternalError, Sort, Text } from '@rushstack/node-core-library'; + +import { IndentedWriter } from '../generators/IndentedWriter'; + +interface IWriteModifiedTextOptions { + writer: IndentedWriter; + separatorOverride: string | undefined; + indentDocCommentState: IndentDocCommentState; +} + +enum IndentDocCommentState { + /** + * `indentDocComment` was not requested for this subtree. + */ + Inactive = 0, + /** + * `indentDocComment` was requested and we are looking for the opening `/` `*` + */ + AwaitingOpenDelimiter = 1, + /** + * `indentDocComment` was requested and we are looking for the closing `*` `/` + */ + AwaitingCloseDelimiter = 2, + /** + * `indentDocComment` was requested and we have finished indenting the comment. + */ + Done = 3 +} + +/** + * Choices for SpanModification.indentDocComment. + */ +export enum IndentDocCommentScope { + /** + * Do not detect and indent comments. + */ + None = 0, + + /** + * Look for one doc comment in the {@link Span.prefix} text only. + */ + PrefixOnly = 1, + + /** + * Look for one doc comment potentially distributed across the Span and its children. + */ + SpanAndChildren = 2 +} /** * Specifies various transformations that will be performed by Span.getModifiedText(). @@ -33,6 +80,21 @@ export class SpanModification { */ public sortKey: string | undefined; + /** + * Optionally configures getModifiedText() to search for a "/*" doc comment and indent it. + * At most one comment is detected. + * + * @remarks + * The indentation can be applied to the `Span.modifier.prefix` only, or it can be applied to the + * full subtree of nodes (as needed for `ts.SyntaxKind.JSDocComment` trees). However the enabled + * scopes must not overlap. + * + * This feature is enabled selectively because (1) we do not want to accidentally match `/*` appearing + * in a string literal or other expression that is not a comment, and (2) parsing comments is relatively + * expensive. + */ + public indentDocComment: IndentDocCommentScope = IndentDocCommentScope.None; + private readonly _span: Span; private _prefix: string | undefined; private _suffix: string | undefined; @@ -74,6 +136,9 @@ export class SpanModification { this.sortKey = undefined; this._prefix = undefined; this._suffix = undefined; + if (this._span.kind === ts.SyntaxKind.JSDocComment) { + this.indentDocComment = IndentDocCommentScope.SpanAndChildren; + } } /** @@ -161,7 +226,7 @@ export class Span { if (childSpan.endIndex > this.endIndex) { // This has never been observed empirically, but here's how we would handle it this.endIndex = childSpan.endIndex; - throw new Error('Unexpected AST case'); + throw new InternalError('Unexpected AST case'); } if (previousChildSpan) { @@ -285,44 +350,6 @@ export class Span { return undefined; } - /** - * Starting from the first character of this span, walk backwards until we find the start of the line, - * and return whitespace after that position. - * - * @remarks - * For example, suppose the character buffer contains this text: - * ``` - * 1111111111222222 - * 012345 6 7890123456789012345 - * "line 1\r\n line 2 Example" - * ``` - * - * And suppose the span starts at index 17, i.e. the the "E" in example. The `getIndent()` method would return - * two spaces corresponding to the range from index 8 through and including index 9. - */ - public getIndent(): string { - const buffer: string = this.node.getSourceFile().text; - - let lineStartIndex: number = 0; - let firstNonSpaceIndex: number = this.startIndex; - - let i: number = this.startIndex - 1; - while (i >= 0) { - const c: number = buffer.charCodeAt(i); - if (c === 13 /* \r */ || c === 10 /* \n */) { - lineStartIndex = i + 1; - break; - } - if (c !== 32 /* space */ && c !== 9 /* tab */) { - // We encountered a non-spacing character, so move the firstNonSpaceIndex backwards - firstNonSpaceIndex = i; - } - --i; - } - - return buffer.substring(lineStartIndex, firstNonSpaceIndex); - } - /** * Recursively invokes the callback on this Span and all its children. The callback * can make changes to Span.modification for each node. @@ -355,20 +382,23 @@ export class Span { * Returns the text represented by this Span, after applying all requested modifications. */ public getModifiedText(): string { - const output: StringBuilder = new StringBuilder(); + const writer: IndentedWriter = new IndentedWriter(); + writer.trimLeadingSpaces = true; this._writeModifiedText({ - output, - separatorOverride: undefined + writer: writer, + separatorOverride: undefined, + indentDocCommentState: IndentDocCommentState.Inactive }); - return output.toString(); + return writer.getText(); } - public writeModifiedText(output: StringBuilder): void { + public writeModifiedText(output: IndentedWriter): void { this._writeModifiedText({ - output, - separatorOverride: undefined + writer: output, + separatorOverride: undefined, + indentDocCommentState: IndentDocCommentState.Inactive }); } @@ -397,104 +427,218 @@ export class Span { return result; } - private _writeModifiedText(options: IWriteModifiedTextOptions): void { - options.output.append(this.modification.prefix); + /** + * Returns a diagnostic dump of the tree, showing the SpanModification settings for each nodde. + */ + public getModifiedDump(indent: string = ''): string { + let result: string = indent + ts.SyntaxKind[this.node.kind] + ': '; - const childCount: number = this.children.length; + if (this.prefix) { + result += ' pre=[' + this._getTrimmed(this.modification.prefix) + ']'; + } + if (this.suffix) { + result += ' suf=[' + this._getTrimmed(this.modification.suffix) + ']'; + } + if (this.separator) { + result += ' sep=[' + this._getTrimmed(this.separator) + ']'; + } + if (this.modification.indentDocComment !== IndentDocCommentScope.None) { + result += ' indentDocComment=' + IndentDocCommentScope[this.modification.indentDocComment]; + } + if (this.modification.omitChildren) { + result += ' omitChildren'; + } + if (this.modification.omitSeparatorAfter) { + result += ' omitSeparatorAfter'; + } + if (this.modification.sortChildren) { + result += ' sortChildren'; + } + if (this.modification.sortKey !== undefined) { + result += ` sortKey="${this.modification.sortKey}"`; + } + result += '\n'; if (!this.modification.omitChildren) { + for (const child of this.children) { + result += child.getModifiedDump(indent + ' '); + } + } else { + result += `${indent} (${this.children.length} children)\n`; + } + + return result; + } + + /** + * Recursive implementation of `getModifiedText()` and `writeModifiedText()`. + */ + private _writeModifiedText(options: IWriteModifiedTextOptions): void { + // Apply indentation based on "{" and "}" + if (this.prefix === '{') { + options.writer.increaseIndent(); + } else if (this.prefix === '}') { + options.writer.decreaseIndent(); + } + + if (this.modification.indentDocComment !== IndentDocCommentScope.None) { + this._beginIndentDocComment(options); + } + + this._write(this.modification.prefix, options); + + if (this.modification.indentDocComment === IndentDocCommentScope.PrefixOnly) { + this._endIndentDocComment(options); + } - if (this.modification.sortChildren && childCount > 1) { + let sortedSubset: Span[] | undefined; + + if (!this.modification.omitChildren) { + if (this.modification.sortChildren) { // We will only sort the items with a sortKey - const sortedSubset: Span[] = this.children.filter(x => x.modification.sortKey !== undefined); - const sortedSubsetCount: number = sortedSubset.length; + const filtered: Span[] = this.children.filter((x) => x.modification.sortKey !== undefined); // Is there at least one of them? - if (sortedSubsetCount > 1) { + if (filtered.length > 1) { + sortedSubset = filtered; + } + } + } + + if (sortedSubset) { + // This is the complicated special case that sorts an arbitrary subset of the child nodes, + // preserving the surrounding nodes. + + const sortedSubsetCount: number = sortedSubset.length; + // Remember the separator for the first and last ones + const firstSeparator: string = sortedSubset[0].getLastInnerSeparator(); + const lastSeparator: string = sortedSubset[sortedSubsetCount - 1].getLastInnerSeparator(); + + Sort.sortBy(sortedSubset, (x) => x.modification.sortKey); - // Remember the separator for the first and last ones - const firstSeparator: string = sortedSubset[0].getLastInnerSeparator(); - const lastSeparator: string = sortedSubset[sortedSubsetCount - 1].getLastInnerSeparator(); + const childOptions: IWriteModifiedTextOptions = { ...options }; - Sort.sortBy(sortedSubset, x => x.modification.sortKey); + let sortedSubsetIndex: number = 0; + for (let index: number = 0; index < this.children.length; ++index) { + let current: Span; - const childOptions: IWriteModifiedTextOptions = { ...options }; + // Is this an item that we sorted? + if (this.children[index].modification.sortKey === undefined) { + // No, take the next item from the original array + current = this.children[index]; + childOptions.separatorOverride = undefined; + } else { + // Yes, take the next item from the sortedSubset + current = sortedSubset[sortedSubsetIndex++]; - let sortedSubsetIndex: number = 0; - for (let index: number = 0; index < childCount; ++index) { - let current: Span; + if (sortedSubsetIndex < sortedSubsetCount) { + childOptions.separatorOverride = firstSeparator; + } else { + childOptions.separatorOverride = lastSeparator; + } + } - // Is this an item that we sorted? - if (this.children[index].modification.sortKey === undefined) { - // No, take the next item from the original array - current = this.children[index]; + current._writeModifiedText(childOptions); + } + } else { + // This is the normal case that does not need to sort children + const childrenLength: number = this.children.length; + + if (!this.modification.omitChildren) { + if (options.separatorOverride !== undefined) { + // Special case where the separatorOverride is passed down to the "last inner separator" span + for (let i: number = 0; i < childrenLength; ++i) { + const child: Span = this.children[i]; + + if ( + // Only the last child inherits the separatorOverride, because only it can contain + // the "last inner separator" span + i < childrenLength - 1 || + // If this.separator is specified, then we will write separatorOverride below, so don't pass it along + this.separator + ) { + const childOptions: IWriteModifiedTextOptions = { ...options }; childOptions.separatorOverride = undefined; + child._writeModifiedText(childOptions); } else { - // Yes, take the next item from the sortedSubset - current = sortedSubset[sortedSubsetIndex++]; - - if (sortedSubsetIndex < sortedSubsetCount) { - childOptions.separatorOverride = firstSeparator; - } else { - childOptions.separatorOverride = lastSeparator; - } + child._writeModifiedText(options); } - - current._writeModifiedText(childOptions); } - - return; + } else { + // The normal simple case + for (const child of this.children) { + child._writeModifiedText(options); + } } - // (fall through to the other implementations) } + this._write(this.modification.suffix, options); + if (options.separatorOverride !== undefined) { - // Special case where the separatorOverride is passed down to the "last inner separator" span - for (let i: number = 0; i < childCount; ++i) { - const child: Span = this.children[i]; - - if ( - // Only the last child inherits the separatorOverride, because only it can contain - // the "last inner separator" span - i < childCount - 1 - // If this.separator is specified, then we will write separatorOverride below, so don't pass it along - || this.separator - ) { - const childOptions: IWriteModifiedTextOptions = { ...options }; - childOptions.separatorOverride = undefined; - child._writeModifiedText(childOptions); - } else { - child._writeModifiedText(options); - } + if (this.separator || childrenLength === 0) { + this._write(options.separatorOverride, options); } } else { - // The normal simple case - for (const child of this.children) { - child._writeModifiedText(options); + if (!this.modification.omitSeparatorAfter) { + this._write(this.separator, options); } } } - options.output.append(this.modification.suffix); + if (this.modification.indentDocComment === IndentDocCommentScope.SpanAndChildren) { + this._endIndentDocComment(options); + } + } + + private _beginIndentDocComment(options: IWriteModifiedTextOptions): void { + if (options.indentDocCommentState !== IndentDocCommentState.Inactive) { + throw new InternalError('indentDocComment cannot be nested'); + } + options.indentDocCommentState = IndentDocCommentState.AwaitingOpenDelimiter; + } + + private _endIndentDocComment(options: IWriteModifiedTextOptions): void { + if (options.indentDocCommentState === IndentDocCommentState.AwaitingCloseDelimiter) { + throw new InternalError('missing "*/" delimiter for comment block'); + } + options.indentDocCommentState = IndentDocCommentState.Inactive; + } - if (options.separatorOverride !== undefined) { - if (this.separator || childCount === 0) { - options.output.append(options.separatorOverride); + /** + * Writes one chunk of `text` to the `options.writer`, applying the `indentDocComment` rewriting. + */ + private _write(text: string, options: IWriteModifiedTextOptions): void { + let parsedText: string = text; + + if (options.indentDocCommentState === IndentDocCommentState.AwaitingOpenDelimiter) { + let index: number = parsedText.indexOf('/*'); + if (index >= 0) { + index += '/*'.length; + options.writer.write(parsedText.substring(0, index)); + parsedText = parsedText.substring(index); + options.indentDocCommentState = IndentDocCommentState.AwaitingCloseDelimiter; + + options.writer.increaseIndent(' '); } - } else { - if (!this.modification.omitSeparatorAfter) { - options.output.append(this.separator); + } + + if (options.indentDocCommentState === IndentDocCommentState.AwaitingCloseDelimiter) { + let index: number = parsedText.indexOf('*/'); + if (index >= 0) { + index += '*/'.length; + options.writer.write(parsedText.substring(0, index)); + parsedText = parsedText.substring(index); + options.indentDocCommentState = IndentDocCommentState.Done; + + options.writer.decreaseIndent(); } } + + options.writer.write(parsedText); } private _getTrimmed(text: string): string { - const trimmed: string = text.replace(/\r?\n/g, '\\n'); - - if (trimmed.length > 100) { - return trimmed.substr(0, 97) + '...'; - } - return trimmed; + return Text.truncateWithEllipsis(Text.convertToLf(text), 100); } private _getSubstring(startIndex: number, endIndex: number): string { @@ -504,8 +648,3 @@ export class Span { return this.node.getSourceFile().text.substring(startIndex, endIndex); } } - -interface IWriteModifiedTextOptions { - output: StringBuilder; - separatorOverride: string | undefined; -} \ No newline at end of file diff --git a/apps/api-extractor/src/analyzer/StringChecks.ts b/apps/api-extractor/src/analyzer/StringChecks.ts deleted file mode 100644 index eec6f81a795..00000000000 --- a/apps/api-extractor/src/analyzer/StringChecks.ts +++ /dev/null @@ -1,44 +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 ts from 'typescript'; - -/** - * Helpers for validating various text string formats. - */ -export class StringChecks { - /** - * Tests whether the input string is safe to use as an ECMAScript identifier without quotes. - * - * @remarks - * For example: - * - * ```ts - * class X { - * public okay: number = 1; - * public "not okay!": number = 2; - * } - * ``` - * - * A precise check is extremely complicated and highly dependent on the ECMAScript standard version - * and how faithfully the interpreter implements it. To keep things simple, `isSafeUnquotedMemberIdentifier()` - * conservatively accepts any identifier that would be valid with ECMAScript 5, and returns false otherwise. - */ - public static isSafeUnquotedMemberIdentifier(identifier: string): boolean { - if (identifier.length === 0) { - return false; // cannot be empty - } - - if (!ts.isIdentifierStart(identifier.charCodeAt(0), ts.ScriptTarget.ES5)) { - return false; - } - - for (let i: number = 1; i < identifier.length; i++) { - if (!ts.isIdentifierPart(identifier.charCodeAt(i), ts.ScriptTarget.ES5)) { - return false; - } - } - - return true; - } -} diff --git a/apps/api-extractor/src/analyzer/SyntaxHelpers.ts b/apps/api-extractor/src/analyzer/SyntaxHelpers.ts new file mode 100644 index 00000000000..42ebdffc822 --- /dev/null +++ b/apps/api-extractor/src/analyzer/SyntaxHelpers.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 * as ts from 'typescript'; + +/** + * Helpers for validating various text string formats. + */ +export class SyntaxHelpers { + /** + * Tests whether the input string is safe to use as an ECMAScript identifier without quotes. + * + * @remarks + * For example: + * + * ```ts + * class X { + * public okay: number = 1; + * public "not okay!": number = 2; + * } + * ``` + * + * A precise check is extremely complicated and highly dependent on the ECMAScript standard version + * and how faithfully the interpreter implements it. To keep things simple, `isSafeUnquotedMemberIdentifier()` + * conservatively accepts any identifier that would be valid with ECMAScript 5, and returns false otherwise. + */ + public static isSafeUnquotedMemberIdentifier(identifier: string): boolean { + if (identifier.length === 0) { + return false; // cannot be empty + } + + if (!ts.isIdentifierStart(identifier.charCodeAt(0), ts.ScriptTarget.ES5)) { + return false; + } + + for (let i: number = 1; i < identifier.length; i++) { + if (!ts.isIdentifierPart(identifier.charCodeAt(i), ts.ScriptTarget.ES5)) { + return false; + } + } + + return true; + } + + /** + * Given an arbitrary input string, return a regular TypeScript identifier name. + * + * @remarks + * Example input: "api-extractor-lib1-test" + * Example output: "apiExtractorLib1Test" + */ + public static makeCamelCaseIdentifier(input: string): string { + const parts: string[] = input.split(/\W+/).filter((x) => x.length > 0); + if (parts.length === 0) { + return '_'; + } + + for (let i: number = 0; i < parts.length; ++i) { + let part: string = parts[i]; + if (part.toUpperCase() === part) { + // Preserve existing case unless the part is all upper-case + part = part.toLowerCase(); + } + if (i === 0) { + // If the first part starts with a number, prepend "_" + if (/[0-9]/.test(part.charAt(0))) { + part = '_' + part; + } + } else { + // Capitalize the first letter of each part, except for the first one + part = part.charAt(0).toUpperCase() + part.slice(1); + } + parts[i] = part; + } + return parts.join(''); + } +} diff --git a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts index 7dc5a3cda89..5c28b30d354 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts @@ -4,7 +4,10 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; -import { TypeScriptMessageFormatter } from './TypeScriptMessageFormatter'; + +import { InternalError } from '@rushstack/node-core-library'; + +import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; import { TypeScriptInternals } from './TypeScriptInternals'; export class TypeScriptHelpers { @@ -65,8 +68,11 @@ export class TypeScriptHelpers { * sometimes return a "prototype" symbol for an object, even though there is no corresponding declaration in the * source code. API Extractor generally ignores such symbols. */ - public static hasAnyDeclarations(symbol: ts.Symbol): boolean { - return symbol.declarations && symbol.declarations.length > 0; + public static tryGetADeclaration(symbol: ts.Symbol): ts.Declaration | undefined { + if (symbol.declarations && symbol.declarations.length > 0) { + return symbol.declarations[0]; + } + return undefined; } /** @@ -79,8 +85,10 @@ export class TypeScriptHelpers { const firstDeclaration: ts.Declaration = followedSymbol.declarations[0]; // Test 1: Are we inside the sinister "declare global {" construct? - const highestModuleDeclaration: ts.ModuleDeclaration | undefined - = TypeScriptHelpers.findHighestParent(firstDeclaration, ts.SyntaxKind.ModuleDeclaration); + const highestModuleDeclaration: ts.ModuleDeclaration | undefined = TypeScriptHelpers.findHighestParent( + firstDeclaration, + ts.SyntaxKind.ModuleDeclaration + ); if (highestModuleDeclaration) { if (highestModuleDeclaration.name.getText().trim() === 'global') { return true; @@ -105,21 +113,45 @@ export class TypeScriptHelpers { * cannot be found. */ public static getSymbolForDeclaration(declaration: ts.Declaration, checker: ts.TypeChecker): ts.Symbol { - const symbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(declaration, checker); + const symbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( + declaration, + checker + ); if (!symbol) { - throw new Error(TypeScriptMessageFormatter.formatFileAndLineNumber(declaration) + ': ' - + 'Unable to determine semantic information for this declaration'); + throw new InternalError( + 'Unable to determine semantic information for declaration:\n' + + SourceFileLocationFormatter.formatDeclaration(declaration) + ); } return symbol; } // Return name of the module, which could be like "./SomeLocalFile' or like 'external-package/entry/point' - public static getModuleSpecifier(declarationWithModuleSpecifier: ts.ImportDeclaration - | ts.ExportDeclaration): string | undefined { + public static getModuleSpecifier( + nodeWithModuleSpecifier: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode + ): string | undefined { + if (nodeWithModuleSpecifier.kind === ts.SyntaxKind.ImportType) { + // As specified internally in typescript:/src/compiler/types.ts#ValidImportTypeNode + if ( + nodeWithModuleSpecifier.argument.kind !== ts.SyntaxKind.LiteralType || + (nodeWithModuleSpecifier.argument as ts.LiteralTypeNode).literal.kind !== ts.SyntaxKind.StringLiteral + ) { + throw new InternalError( + `Invalid ImportTypeNode: ${nodeWithModuleSpecifier.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(nodeWithModuleSpecifier) + ); + } + const literalTypeNode: ts.LiteralTypeNode = nodeWithModuleSpecifier.argument as ts.LiteralTypeNode; + const stringLiteral: ts.StringLiteral = literalTypeNode.literal as ts.StringLiteral; + return stringLiteral.text.trim(); + } - if (declarationWithModuleSpecifier.moduleSpecifier - && ts.isStringLiteralLike(declarationWithModuleSpecifier.moduleSpecifier)) { - return TypeScriptInternals.getTextOfIdentifierOrLiteral(declarationWithModuleSpecifier.moduleSpecifier); + // Node is a declaration + if ( + nodeWithModuleSpecifier.moduleSpecifier && + ts.isStringLiteralLike(nodeWithModuleSpecifier.moduleSpecifier) + ) { + return TypeScriptInternals.getTextOfIdentifierOrLiteral(nodeWithModuleSpecifier.moduleSpecifier); } return undefined; @@ -138,7 +170,10 @@ export class TypeScriptHelpers { * * Calling _matchAncestor(C, [ExportDeclaration]) would return C. */ - public static matchAncestor(node: ts.Node, kindsToMatch: ts.SyntaxKind[]): T | undefined { + public static matchAncestor( + node: ts.Node, + kindsToMatch: ts.SyntaxKind[] + ): T | undefined { // (slice(0) clones an array) const reversedParentKinds: ts.SyntaxKind[] = kindsToMatch.slice(0).reverse(); @@ -167,7 +202,10 @@ export class TypeScriptHelpers { * Does a depth-first search of the children of the specified node. Returns the first child * with the specified kind, or undefined if there is no match. */ - public static findFirstChildNode(node: ts.Node, kindToMatch: ts.SyntaxKind): T | undefined { + public static findFirstChildNode( + node: ts.Node, + kindToMatch: ts.SyntaxKind + ): T | undefined { for (const child of node.getChildren()) { if (child.kind === kindToMatch) { return child as T; @@ -203,7 +241,10 @@ export class TypeScriptHelpers { * @remarks * Whereas findFirstParent() returns the first match, findHighestParent() returns the last match. */ - public static findHighestParent(node: ts.Node, kindToMatch: ts.SyntaxKind): T | undefined { + public static findHighestParent( + node: ts.Node, + kindToMatch: ts.SyntaxKind + ): T | undefined { let current: ts.Node | undefined = node; let highest: T | undefined = undefined; @@ -248,15 +289,19 @@ export class TypeScriptHelpers { public static tryGetLateBoundName(declarationName: ts.ComputedPropertyName): string | undefined { // Create a node printer that ignores comments and indentation that we can use to convert // declarationName to a string. - const printer: ts.Printer = ts.createPrinter({ removeComments: true }, { - onEmitNode(hint: ts.EmitHint, node: ts.Node | undefined, - emit: (hint: ts.EmitHint, node: ts.Node | undefined) => void): void { - if (node) { + const printer: ts.Printer = ts.createPrinter( + { removeComments: true }, + { + onEmitNode( + hint: ts.EmitHint, + node: ts.Node, + emitCallback: (hint: ts.EmitHint, node: ts.Node) => void + ): void { ts.setEmitFlags(declarationName, ts.EmitFlags.NoIndentation | ts.EmitFlags.SingleLine); + emitCallback(hint, node); } - emit(hint, node); } - }); + ); const sourceFile: ts.SourceFile = declarationName.getSourceFile(); const text: string = printer.printNode(ts.EmitHint.Unspecified, declarationName, sourceFile); // clean up any emit flags we've set on any nodes in the tree. diff --git a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts index b5e1f72c2f7..00d04aa07fe 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts @@ -5,12 +5,20 @@ import * as ts from 'typescript'; -export class TypeScriptInternals { +import { InternalError } from '@rushstack/node-core-library'; + +/** + * Exposes the TypeScript compiler internals for detecting global variable names. + */ +export interface IGlobalVariableAnalyzer { + hasGlobalName(name: string): boolean; +} +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 + return (typeChecker as any).getImmediateAliasedSymbol(symbol); } /** @@ -21,12 +29,14 @@ export class TypeScriptInternals { * @returns The associated Symbol. If there is no semantic information (e.g. if the * declaration is an extra semicolon somewhere), then "undefined" is returned. */ - public static tryGetSymbolForDeclaration(declaration: ts.Declaration, checker: ts.TypeChecker): ts.Symbol - | undefined { + public static tryGetSymbolForDeclaration( + declaration: ts.Declaration, + checker: ts.TypeChecker + ): ts.Symbol | undefined { let symbol: ts.Symbol | undefined = (declaration as any).symbol; if (symbol && symbol.escapedName === ts.InternalSymbolName.Computed) { const name: ts.DeclarationName | undefined = ts.getNameOfDeclaration(declaration); - symbol = name && checker.getSymbolAtLocation(name) || symbol; + symbol = (name && checker.getSymbolAtLocation(name)) || symbol; } return symbol; } @@ -36,9 +46,11 @@ export class TypeScriptInternals { * for a computed property based on its type, rather than by the Binder). */ public static isLateBoundSymbol(symbol: ts.Symbol): boolean { - // eslint-disable-next-line no-bitwise - if (symbol.flags & ts.SymbolFlags.Transient && - (symbol as any).checkFlags === (ts as any).CheckFlags.Late) { + if ( + // eslint-disable-next-line no-bitwise + symbol.flags & ts.SymbolFlags.Transient && + (ts as any).getCheckFlags(symbol) === (ts as any).CheckFlags.Late + ) { return true; } return false; @@ -57,7 +69,9 @@ export class TypeScriptInternals { /** * Retrieves the (unescaped) value of an string literal, numeric literal, or identifier. */ - public static getTextOfIdentifierOrLiteral(node: ts.Identifier | ts.StringLiteralLike | ts.NumericLiteral): string { + public static getTextOfIdentifierOrLiteral( + node: ts.Identifier | ts.StringLiteralLike | ts.NumericLiteral + ): string { // Compiler internal: // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/utilities.ts#L2721 @@ -68,13 +82,34 @@ export class TypeScriptInternals { * Retrieves the (cached) module resolution information for a module name that was exported from a SourceFile. * The compiler populates this cache as part of analyzing the source file. */ - public static getResolvedModule(sourceFile: ts.SourceFile, moduleNameText: string): ts.ResolvedModuleFull - | undefined { + public static getResolvedModule( + program: ts.Program, + sourceFile: ts.SourceFile, + moduleNameText: string, + 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 + const result: ts.ResolvedModuleWithFailedLookupLocations | undefined = (program as any).getResolvedModule( + sourceFile, + moduleNameText, + mode + ); + return result?.resolvedModule; + } + /** + * Gets the mode required for module resolution required with the addition of Node16/nodenext + */ + public static getModeForUsageLocation( + file: ts.SourceFile, + usage: ts.StringLiteralLike, + compilerOptions: ts.CompilerOptions + ): ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/utilities.ts#L218 + // https://github.com/microsoft/TypeScript/blob/v5.8.2/src/compiler/program.ts#L931 - return (ts as any).getResolvedModule(sourceFile, moduleNameText); + return ts.getModeForUsageLocation?.(file, usage, compilerOptions); } /** @@ -92,4 +127,30 @@ export class TypeScriptInternals { return (declaration as any).localSymbol; } + public static getGlobalVariableAnalyzer(program: ts.Program): IGlobalVariableAnalyzer { + const anyProgram: any = program; + const typeCheckerInstance: any = + anyProgram.getDiagnosticsProducingTypeChecker ?? anyProgram.getTypeChecker; + + if (!typeCheckerInstance) { + throw new InternalError('Missing Program.getDiagnosticsProducingTypeChecker or Program.getTypeChecker'); + } + const typeChecker: any = typeCheckerInstance(); + if (!typeChecker.getEmitResolver) { + throw new InternalError('Missing TypeChecker.getEmitResolver'); + } + const resolver: any = typeChecker.getEmitResolver(); + if (!resolver.hasGlobalName) { + throw new InternalError('Missing EmitResolver.hasGlobalName'); + } + return resolver; + } + + /** + * Returns whether a variable is declared with the const keyword + */ + public static isVarConst(node: ts.VariableDeclaration | ts.VariableDeclarationList): boolean { + // Compiler internal: https://github.com/microsoft/TypeScript/blob/71286e3d49c10e0e99faac360a6bbd40f12db7b6/src/compiler/utilities.ts#L925 + return (ts as any).isVarConst(node); + } } diff --git a/apps/api-extractor/src/analyzer/TypeScriptMessageFormatter.ts b/apps/api-extractor/src/analyzer/TypeScriptMessageFormatter.ts deleted file mode 100644 index cffe7bd6479..00000000000 --- a/apps/api-extractor/src/analyzer/TypeScriptMessageFormatter.ts +++ /dev/null @@ -1,16 +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 ts from 'typescript'; - -export class TypeScriptMessageFormatter { - /** - * Returns a string such as this, based on the context information in the provided node: - * "[C:\Folder\File.ts#123]" - */ - public static formatFileAndLineNumber(node: ts.Node): string { - const sourceFile: ts.SourceFile = node.getSourceFile(); - const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - return `[${sourceFile.fileName}#${lineAndCharacter.line}]`; - } -} diff --git a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts index 3bb872cb81d..7f5acef9c2f 100644 --- a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts +++ b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts @@ -1,40 +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 'path'; -import { PackageMetadataManager } from '../PackageMetadataManager'; -import { FileSystem, PackageJsonLookup, INodePackageJson, NewlineKind } from '@rushstack/node-core-library'; - -const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - -function resolveInTestPackage(testPackageName: string, ...args: string[]): string { - return path.resolve(__dirname, 'test-data/tsdoc-metadata-path-inference', testPackageName, ...args); -} +jest.mock('node:path', () => { + const actualPath: typeof import('path') = jest.requireActual('node:path'); + return { + ...actualPath, + resolve: actualPath.posix.resolve + }; +}); -function getPackageMetadata(testPackageName: string): { packageFolder: string, packageJson: INodePackageJson } { - const packageFolder: string = resolveInTestPackage(testPackageName); - const packageJson: INodePackageJson | undefined = packageJsonLookup.tryLoadPackageJsonFor(packageFolder); - if (!packageJson) { - throw new Error('There should be a package.json file in the test package'); - } - return { packageFolder, packageJson }; -} +import { PackageMetadataManager } from '../PackageMetadataManager'; +import { FileSystem, type INodePackageJson, NewlineKind } from '@rushstack/node-core-library'; // eslint-disable-next-line @typescript-eslint/no-explicit-any function firstArgument(mockFn: jest.Mock): any { return mockFn.mock.calls[0][0]; } -/* eslint-disable @typescript-eslint/typedef */ +const PACKAGE_FOLDER: '/pkg' = '/pkg'; -describe('PackageMetadataManager', () => { - describe('.writeTsdocMetadataFile()', () => { +describe(PackageMetadataManager.name, () => { + describe(PackageMetadataManager.writeTsdocMetadataFile.name, () => { const originalWriteFile = FileSystem.writeFile; const mockWriteFile: jest.Mock = jest.fn(); beforeAll(() => { FileSystem.writeFile = mockWriteFile; }); + afterEach(() => { mockWriteFile.mockClear(); }); + afterAll(() => { FileSystem.writeFile = originalWriteFile; }); @@ -45,94 +41,404 @@ describe('PackageMetadataManager', () => { }); }); - describe('.resolveTsdocMetadataPath()', () => { - describe('when an empty tsdocMetadataPath is provided', () => { - const tsdocMetadataPath: string = ''; + describe(PackageMetadataManager.resolveTsdocMetadataPath.name, () => { + describe.each([ + { + tsdocMetadataPath: '', + label: 'when an empty tsdocMetadataPath is provided' + }, + { + tsdocMetadataPath: 'path/to/custom-tsdoc-metadata.json', + label: 'when a non-empty tsdocMetadataPath is provided', + itValue: + 'outputs the tsdoc metadata file at the provided path in the folder where package.json is located', + overrideExpected: `${PACKAGE_FOLDER}/path/to/custom-tsdoc-metadata.json` + } + ])('$label', ({ tsdocMetadataPath, itValue, overrideExpected }) => { + function testForPackageJson( + packageJson: INodePackageJson, + options: + | { expectsPackageRoot: true } + | { + expectedPathInsidePackage: string; + } + ): void { + const { expectsPackageRoot, expectedPathInsidePackage } = options as { + expectsPackageRoot: true; + } & { + expectedPathInsidePackage: string; + }; + const resolvedTsdocMetadataPath: string = PackageMetadataManager.resolveTsdocMetadataPath( + PACKAGE_FOLDER, + packageJson, + tsdocMetadataPath + ); + if (overrideExpected) { + expect(resolvedTsdocMetadataPath).toBe(overrideExpected); + } else if (expectsPackageRoot) { + expect(resolvedTsdocMetadataPath).toBe(`${PACKAGE_FOLDER}/tsdoc-metadata.json`); + } else { + expect(resolvedTsdocMetadataPath).toBe( + `${PACKAGE_FOLDER}/${expectedPathInsidePackage}/tsdoc-metadata.json` + ); + } + } + describe('given a package.json where the field "tsdocMetadata" is defined', () => { - it('outputs the tsdoc metadata path as given by "tsdocMetadata" relative to the folder of package.json', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-tsdoc-metadata'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, packageJson.tsdocMetadata as string)); - }); + it( + itValue ?? + 'outputs the tsdoc metadata path as given by "tsdocMetadata" relative to the folder of package.json', + () => { + testForPackageJson( + { + name: 'package-inferred-from-tsdoc-metadata', + version: '1.0.0', + main: 'path/to/main.js', + typings: 'path/to/typings/typings.d.ts', + tsdocMetadata: 'path/to/tsdoc-metadata/tsdoc-metadata.json' + }, + { + expectedPathInsidePackage: 'path/to/tsdoc-metadata' + } + ); + } + ); }); - describe('given a package.json where the field "typings" is defined and "tsdocMetadata" is not defined', () => { - it('outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "typings"', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-typings'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, path.dirname(packageJson.typings!), 'tsdoc-metadata.json')); + + describe('given a package.json where the field "exports" is defined', () => { + describe('with a string value', () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: 'path/to/exports/exports.js' + }, + { expectedPathInsidePackage: 'path/to/exports' } + ); }); - }); - describe('given a package.json where the field "main" is defined but not "typings" nor "tsdocMetadata"', () => { - it('outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "main"', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-main'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, path.dirname(packageJson.main!), 'tsdoc-metadata.json')); + + describe('with an array value', () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: ['path/to/exports/exports.js', 'path/to/exports2/exports.js'] + }, + { expectedPathInsidePackage: 'path/to/exports' } + ); }); - }); - describe('given a package.json where the fields "main", "typings" and "tsdocMetadata" are not defined', () => { - it('outputs the tsdoc metadata file "tsdoc-metadata.json" in the folder where package.json is located', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-default'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, 'tsdoc-metadata.json')); + + describe.each(['.', '*'])('with an exports field that contains a "%s" key', (exportsKey) => { + describe('with a string value', () => { + it( + itValue ?? + `outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "${exportsKey}"`, + () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: { + [exportsKey]: 'path/to/exports/exports.js' + } + }, + { expectedPathInsidePackage: 'path/to/exports' } + ); + } + ); + }); + + describe('with an object value that does not include a "types" key', () => { + it(itValue ?? 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the package root', () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: { + [exportsKey]: { + import: 'path/to/exports/exports.js' + } + } + }, + { expectsPackageRoot: true } + ); + }); + }); + + describe('with an object value that does include a "types" key', () => { + it( + itValue ?? + `outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "${exportsKey}"`, + () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: { + [exportsKey]: { + types: 'path/to/types-exports/exports.d.ts' + } + } + }, + { expectedPathInsidePackage: 'path/to/types-exports' } + ); + } + ); + }); + + describe('that nests into an object that doesn\'t contain a "types" key', () => { + it(itValue ?? 'outputs the tsdoc metadata file "tsdoc-metadata.json" package root', () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: { + [exportsKey]: { + types: { + import: 'path/to/types-exports/exports.js' + } + } + } + }, + { expectsPackageRoot: true } + ); + }); + }); + + describe('that nests into an object that contains a "types" key', () => { + it(itValue ?? 'outputs the tsdoc metadata file "tsdoc-metadata.json" package root', () => { + testForPackageJson( + { + name: 'package-inferred-from-exports', + version: '1.0.0', + exports: { + [exportsKey]: { + types: { + types: 'path/to/types-exports/exports.d.ts' + } + } + } + }, + { expectedPathInsidePackage: 'path/to/types-exports' } + ); + }); + }); }); }); - }); - describe('when a non-empty tsdocMetadataPath is provided', () => { - const tsdocMetadataPath: string = 'path/to/custom-tsdoc-metadata.json'; - describe('given a package.json where the field "tsdocMetadata" is defined', () => { - it('outputs the tsdoc metadata file at the provided path in the folder where package.json is located', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-tsdocMetadata'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, tsdocMetadataPath)); + + describe('given a package.json where the field "typesVersions" is defined', () => { + describe('with an exports field that contains a "%s" key', () => { + describe('with no selectors', () => { + it(itValue ?? 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the package root', () => { + testForPackageJson( + { + name: 'package-inferred-from-typesVersions', + version: '1.0.0', + typesVersions: {} + }, + { expectsPackageRoot: true } + ); + }); + }); + + describe.each(['.', '*'])('with a %s selector', (pathSelector) => { + it( + itValue ?? 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the path selected', + () => { + testForPackageJson( + { + name: 'package-inferred-from-typesVersions', + version: '1.0.0', + typesVersions: { + '>=3.0': { + [pathSelector]: ['path/to/types-exports/exports.d.ts'] + } + } + }, + { expectedPathInsidePackage: 'path/to/types-exports' } + ); + } + ); + }); + + describe('with multiple TypeScript versions', () => { + describe.each(['.', '*'])('with a %s selector', (pathSelector) => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the path selected for the latest TypeScript version', + () => { + testForPackageJson( + { + name: 'package-inferred-from-typesVersions', + version: '1.0.0', + typesVersions: { + '>=3.6': { + [pathSelector]: ['path/to/types-exports-3.6/exports.d.ts'] + }, + '>=3.0': { + [pathSelector]: ['path/to/types-exports-3.0/exports.d.ts'] + }, + '~4.0': { + [pathSelector]: ['path/to/types-exports-4.0/exports.d.ts'] + } + } + }, + { expectedPathInsidePackage: 'path/to/types-exports-4.0' } + ); + } + ); + }); + }); }); }); - describe('given a package.json where the field "typings" is defined and "tsdocMetadata" is not defined', () => { - it('outputs the tsdoc metadata file at the provided path in the folder where package.json is located', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-typings'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, tsdocMetadataPath)); - }); + + describe('given a package.json where the field "types" is defined', () => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "types"', + () => { + testForPackageJson( + { + name: 'package-inferred-from-types', + version: '1.0.0', + main: 'path/to/main.js', + types: 'path/to/types/types.d.ts' + }, + { expectedPathInsidePackage: 'path/to/types' } + ); + } + ); }); - describe('given a package.json where the field "main" is defined but not "typings" nor "tsdocMetadata"', () => { - it('outputs the tsdoc metadata file at the provided path in the folder where package.json is located', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-inferred-from-main'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, tsdocMetadataPath)); - }); + + describe('given a package.json where the field "types" and "typings" are defined', () => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "types"', + () => { + testForPackageJson( + { + name: 'package-inferred-from-types', + version: '1.0.0', + main: 'path/to/main.js', + types: 'path/to/types/types.d.ts', + typings: 'path/to/typings/typings.d.ts' + }, + { expectedPathInsidePackage: 'path/to/types' } + ); + } + ); }); - describe('given a package.json where the fields "main", "typings" and "tsdocMetadata" are not defined', () => { - it('outputs the tsdoc metadata file at the provided path in the folder where package.json is located', () => { - const { - packageFolder, - packageJson - } = getPackageMetadata('package-default'); - expect(PackageMetadataManager.resolveTsdocMetadataPath(packageFolder, packageJson, tsdocMetadataPath)) - .toBe(path.resolve(packageFolder, tsdocMetadataPath)); - }); + + describe('given a package.json where the field "typings" is defined and "types" is not defined', () => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "typings"', + () => { + testForPackageJson( + { + name: 'package-inferred-from-typings', + version: '1.0.0', + main: 'path/to/main.js', + typings: 'path/to/typings/typings.d.ts' + }, + { expectedPathInsidePackage: 'path/to/typings' } + ); + } + ); }); + + describe('given a package.json where the field "main" is defined', () => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the same folder as the path of "main"', + () => { + testForPackageJson( + { + name: 'package-inferred-from-main', + version: '1.0.0', + main: 'path/to/main/main.js' + }, + { expectedPathInsidePackage: 'path/to/main' } + ); + } + ); + }); + + describe( + 'given a package.json where the fields "exports", "typesVersions", "types", "main", "typings" ' + + 'and "tsdocMetadata" are not defined', + () => { + it( + itValue ?? + 'outputs the tsdoc metadata file "tsdoc-metadata.json" in the folder where package.json is located', + () => { + testForPackageJson( + { + name: 'package-default', + version: '1.0.0' + }, + { expectsPackageRoot: true } + ); + } + ); + } + ); + }); + + it('correctly resolves the tsdoc-metadata with the right precedence', () => { + const packageJson: INodePackageJson = { + name: 'package-inferred-tsdoc-metadata', + tsdocMetadata: 'path/to/tsdoc-metadata/tsdoc-metadata.json', + exports: { + '.': 'path/to/exports-dot/exports.js', + '*': 'path/to/exports-star/*.js' + }, + typesVersions: { + '>=3.0': { + '.': ['path/to/typesVersions-dot/exports.d.ts'], + '*': ['path/to/typesVersions-star/*.d.ts'] + } + }, + types: 'path/to/types/types.d.ts', + typings: 'path/to/typings/typings.d.ts', + main: 'path/to/main/main.js' + }; + + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/tsdoc-metadata/tsdoc-metadata.json` + ); + delete packageJson.tsdocMetadata; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/exports-dot/tsdoc-metadata.json` + ); + delete (packageJson.exports as { '.': unknown })!['.']; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/exports-star/tsdoc-metadata.json` + ); + delete packageJson.exports; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/typesVersions-dot/tsdoc-metadata.json` + ); + delete packageJson.typesVersions!['>=3.0']!['.']; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/typesVersions-star/tsdoc-metadata.json` + ); + delete packageJson.typesVersions; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/types/tsdoc-metadata.json` + ); + delete packageJson.types; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/typings/tsdoc-metadata.json` + ); + delete packageJson.typings; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/path/to/main/tsdoc-metadata.json` + ); + delete packageJson.main; + expect(PackageMetadataManager.resolveTsdocMetadataPath(PACKAGE_FOLDER, packageJson)).toBe( + `${PACKAGE_FOLDER}/tsdoc-metadata.json` + ); }); }); }); - -/* eslint-enable @typescript-eslint/typedef */ diff --git a/apps/api-extractor/src/analyzer/test/SyntaxHelpers.test.ts b/apps/api-extractor/src/analyzer/test/SyntaxHelpers.test.ts new file mode 100644 index 00000000000..ab2665b7192 --- /dev/null +++ b/apps/api-extractor/src/analyzer/test/SyntaxHelpers.test.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 { SyntaxHelpers } from '../SyntaxHelpers'; + +describe(SyntaxHelpers.name, () => { + it(SyntaxHelpers.makeCamelCaseIdentifier.name, () => { + // prettier-ignore + const inputs:string[] = [ + '', + '@#(&*^', + 'api-extractor-lib1-test', + 'one', + 'one-two', + 'ONE-TWO', + 'ONE/two/ /three/FOUR', + '01234' + ]; + + expect( + inputs.map((x) => { + return { input: x, output: SyntaxHelpers.makeCamelCaseIdentifier(x) }; + }) + ).toMatchInlineSnapshot(` + Array [ + Object { + "input": "", + "output": "_", + }, + Object { + "input": "@#(&*^", + "output": "_", + }, + Object { + "input": "api-extractor-lib1-test", + "output": "apiExtractorLib1Test", + }, + Object { + "input": "one", + "output": "one", + }, + Object { + "input": "one-two", + "output": "oneTwo", + }, + Object { + "input": "ONE-TWO", + "output": "oneTwo", + }, + Object { + "input": "ONE/two/ /three/FOUR", + "output": "oneTwoThreeFour", + }, + Object { + "input": "01234", + "output": "_01234", + }, + ] + `); + }); +}); diff --git a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-default/package.json b/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-default/package.json deleted file mode 100644 index 1a58930cee9..00000000000 --- a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-default/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "package-default", - "version": "1.0.0" -} diff --git a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-main/package.json b/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-main/package.json deleted file mode 100644 index 30a7f604a96..00000000000 --- a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-main/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "package-inferred-from-main", - "version": "1.0.0", - "main": "path/to/main.js" -} diff --git a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-tsdoc-metadata/package.json b/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-tsdoc-metadata/package.json deleted file mode 100644 index fbb048f47ef..00000000000 --- a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-tsdoc-metadata/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "package-inferred-from-tsdoc-metadata", - "version": "1.0.0", - "main": "path/to/main.js", - "typings": "path/to/typings.d.ts", - "tsdocMetadata": "path/to/tsdoc-metadata.json" -} diff --git a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-typings/package.json b/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-typings/package.json deleted file mode 100644 index bb73979d054..00000000000 --- a/apps/api-extractor/src/analyzer/test/test-data/tsdoc-metadata-path-inference/package-inferred-from-typings/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "package-inferred-from-typings", - "version": "1.0.0", - "main": "path/to/main.js", - "typings": "path/to/typings.d.ts" -} diff --git a/apps/api-extractor/src/api/CompilerState.ts b/apps/api-extractor/src/api/CompilerState.ts index e56bff07b8d..7862c1c2e85 100644 --- a/apps/api-extractor/src/api/CompilerState.ts +++ b/apps/api-extractor/src/api/CompilerState.ts @@ -1,16 +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 colors = require('colors'); -import { - JsonFile -} from '@rushstack/node-core-library'; +import { JsonFile } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { ExtractorConfig } from './ExtractorConfig'; -import { IExtractorInvokeOptions } from './Extractor'; +import type { IExtractorInvokeOptions } from './Extractor'; /** * Options for {@link CompilerState.create} @@ -45,8 +44,10 @@ export class CompilerState { /** * Create a compiler state for use with the specified `IExtractorInvokeOptions`. */ - public static create(extractorConfig: ExtractorConfig, options?: ICompilerStateCreateOptions): CompilerState { - + public static create( + extractorConfig: ExtractorConfig, + options?: ICompilerStateCreateOptions + ): CompilerState { let tsconfig: {} | undefined = extractorConfig.overrideTsconfig; let configBasePath: string = extractorConfig.projectFolder; if (!tsconfig) { @@ -55,20 +56,27 @@ export class CompilerState { configBasePath = path.resolve(path.dirname(extractorConfig.tsconfigFilePath)); } - const commandLine: ts.ParsedCommandLine = ts.parseJsonConfigFileContent( - tsconfig, - ts.sys, - configBasePath - ); + const commandLine: ts.ParsedCommandLine = ts.parseJsonConfigFileContent(tsconfig, ts.sys, configBasePath); if (!commandLine.options.skipLibCheck && extractorConfig.skipLibCheck) { commandLine.options.skipLibCheck = true; - console.log(colors.cyan( - 'API Extractor was invoked with skipLibCheck. This is not recommended and may cause ' + - 'incorrect type analysis.' - )); + console.log( + Colorize.cyan( + 'API Extractor was invoked with skipLibCheck. This is not recommended and may cause ' + + 'incorrect type analysis.' + ) + ); } + // 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); @@ -82,7 +90,7 @@ export class CompilerState { const program: ts.Program = ts.createProgram(analysisFilePaths, commandLine.options, compilerHost); if (commandLine.errors.length > 0) { - const errorText: string = `${commandLine.errors[0].messageText}`; + const errorText: string = ts.flattenDiagnosticMessageText(commandLine.errors[0].messageText, '\n'); throw new Error(`Error parsing tsconfig.json content: ${errorText}`); } @@ -91,7 +99,7 @@ export class CompilerState { }); } - /** + /** * Given a list of absolute file paths, return a list containing only the declaration * files. Duplicates are also eliminated. * @@ -128,9 +136,10 @@ export class CompilerState { return analysisFilePaths; } - private static _createCompilerHost(commandLine: ts.ParsedCommandLine, - options: IExtractorInvokeOptions | undefined): ts.CompilerHost { - + 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); diff --git a/apps/api-extractor/src/api/ConsoleMessageId.ts b/apps/api-extractor/src/api/ConsoleMessageId.ts index 82d04b07ce7..5d1345a2093 100644 --- a/apps/api-extractor/src/api/ConsoleMessageId.ts +++ b/apps/api-extractor/src/api/ConsoleMessageId.ts @@ -11,7 +11,23 @@ * * @public */ -export const enum ConsoleMessageId { +export enum ConsoleMessageId { + /** + * "Analysis will use the bundled TypeScript version ___" + */ + Preamble = 'console-preamble', + + /** + * "The target project appears to use TypeScript ___ which is newer than the bundled compiler engine; + * consider upgrading API Extractor." + */ + CompilerVersionNotice = 'console-compiler-version-notice', + + /** + * "Using custom TSDoc config from ___" + */ + UsingCustomTSDocConfig = 'console-using-custom-tsdoc-config', + /** * "Found metadata in ___" */ @@ -27,6 +43,11 @@ export const enum ConsoleMessageId { */ WritingDtsRollup = 'console-writing-dts-rollup', + /** + * "Generating ___ API report: ___" + */ + WritingApiReport = 'console-writing-api-report', + /** * "You have changed the public API signature for this project. * Please copy the file ___ to ___, or perform a local build (which does this automatically). @@ -40,6 +61,12 @@ export const 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 9aa5ca666e4..b48a323b094 100644 --- a/apps/api-extractor/src/api/Extractor.ts +++ b/apps/api-extractor/src/api/Extractor.ts @@ -1,28 +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 '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, NewlineKind, PackageJsonLookup, - IPackageJson + type IPackageJson, + type INodePackageJson, + Path } from '@rushstack/node-core-library'; -import { ExtractorConfig } from './ExtractorConfig'; +import { ExtractorConfig, type IExtractorConfigApiReport } from './ExtractorConfig'; import { Collector } from '../collector/Collector'; import { DtsRollupGenerator, DtsRollupKind } from '../generators/DtsRollupGenerator'; import { ApiModelGenerator } from '../generators/ApiModelGenerator'; -import { ApiPackage } from '@microsoft/api-extractor-model'; import { ApiReportGenerator } from '../generators/ApiReportGenerator'; import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { ValidationEnhancer } from '../enhancers/ValidationEnhancer'; import { DocCommentEnhancer } from '../enhancers/DocCommentEnhancer'; import { CompilerState } from './CompilerState'; -import { ExtractorMessage } from './ExtractorMessage'; +import type { ExtractorMessage } from './ExtractorMessage'; import { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from './ConsoleMessageId'; +import { SourceMapper } from '../collector/SourceMapper'; /** * Runtime options for Extractor. @@ -83,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; } /** @@ -171,7 +188,10 @@ export class Extractor { /** * Load the api-extractor.json config file from the specified path, and then invoke API Extractor. */ - public static loadConfigAndInvoke(configFilePath: string, options?: IExtractorInvokeOptions): ExtractorResult { + public static loadConfigAndInvoke( + configFilePath: string, + options?: IExtractorInvokeOptions + ): ExtractorResult { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(configFilePath); return Extractor.invoke(extractorConfig, options); @@ -181,43 +201,86 @@ export class Extractor { * Invoke API Extractor using an already prepared `ExtractorConfig` object. */ public static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult { + 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(); - if (!options) { - options = { }; - } - - const localBuild: boolean = options.localBuild || false; + const messageRouter: MessageRouter = new MessageRouter({ + workingPackageFolder: packageFolder, + messageCallback, + messagesConfig: messages || {}, + showVerboseMessages, + showDiagnostics, + tsdocConfiguration, + sourceMapper + }); - let compilerState: CompilerState | undefined; - if (options.compilerState) { - compilerState = options.compilerState; - } else { - compilerState = CompilerState.create(extractorConfig, options); + if (tsdocConfigFilePath && !tsdocConfigFileNotFound) { + if (!Path.isEqual(tsdocConfigFilePath, ExtractorConfig._tsdocBaseFilePath)) { + messageRouter.logVerbose( + ConsoleMessageId.UsingCustomTSDocConfig, + `Using custom TSDoc config from ${tsdocConfigFilePath}` + ); + } } - const messageRouter: MessageRouter = new MessageRouter({ - workingPackageFolder: extractorConfig.packageFolder, - messageCallback: options.messageCallback, - messagesConfig: extractorConfig.messages || { }, - showVerboseMessages: !!options.showVerboseMessages, - showDiagnostics: !!options.showDiagnostics - }); + this._checkCompilerCompatibility(extractorConfig, messageRouter); if (messageRouter.showDiagnostics) { + messageRouter.logDiagnostic(''); messageRouter.logDiagnosticHeader('Final prepared ExtractorConfig'); messageRouter.logDiagnostic(extractorConfig.getDiagnosticDump()); messageRouter.logDiagnosticFooter(); messageRouter.logDiagnosticHeader('Compiler options'); - const serializedOptions: object = MessageRouter.buildJsonDumpObject((compilerState.program as ts.Program).getCompilerOptions()); - messageRouter.logDiagnostic(JSON.stringify(serializedOptions, undefined, 2)); + const serializedCompilerOptions: object = MessageRouter.buildJsonDumpObject( + (compilerState.program as ts.Program).getCompilerOptions() + ); + messageRouter.logDiagnostic(JSON.stringify(serializedCompilerOptions, undefined, 2)); + messageRouter.logDiagnosticFooter(); + + messageRouter.logDiagnosticHeader('TSDoc configuration'); + // Convert the TSDocConfiguration into a tsdoc.json representation + const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(tsdocConfiguration); + const serializedTSDocConfig: object = MessageRouter.buildJsonDumpObject( + combinedConfigFile.saveToObject() + ); + messageRouter.logDiagnostic(JSON.stringify(serializedTSDocConfig, undefined, 2)); messageRouter.logDiagnosticFooter(); } const collector: Collector = new Collector({ program: compilerState.program as ts.Program, messageRouter, - extractorConfig: extractorConfig + extractorConfig, + sourceMapper }); collector.analyze(); @@ -225,115 +288,75 @@ 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 (extractorConfig.docModelEnabled) { - messageRouter.logVerbose(ConsoleMessageId.WritingDocModelFile, 'Writing: ' + extractorConfig.apiJsonFilePath); - apiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, { + if (messageRouter.showDiagnostics) { + messageRouter.logDiagnostic(''); // skip a line after any diagnostic messages + } + + 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 }); } - let apiReportChanged: boolean = false; - - if (extractorConfig.apiReportEnabled) { - const actualApiReportPath: string = extractorConfig.reportTempFilePath; - const actualApiReportShortPath: string = extractorConfig._getShortFilePath(extractorConfig.reportTempFilePath); - - const expectedApiReportPath: string = extractorConfig.reportFilePath; - const expectedApiReportShortPath: string = extractorConfig._getShortFilePath(extractorConfig.reportFilePath); - - const actualApiReportContent: string = ApiReportGenerator.generateReviewFileContent(collector); - - // 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); - - 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 public 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 public 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. - apiReportChanged = true; + function writeApiReport(reportConfig: IExtractorConfigApiReport): boolean { + return Extractor._writeApiReport( + collector, + extractorConfig, + messageRouter, + reportTempFolder, + reportFolder, + reportConfig, + localBuild, + printApiReportDiff + ); + } - 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 - ); - } - } + let anyReportChanged: boolean = false; + if (apiReportEnabled) { + for (const reportConfig of reportConfigs) { + anyReportChanged = writeApiReport(reportConfig) || anyReportChanged; } } - if (extractorConfig.rollupEnabled) { + if (rollupEnabled) { Extractor._generateRollupDtsFile( - collector, extractorConfig.publicTrimmedFilePath, DtsRollupKind.PublicRelease, extractorConfig.newlineKind); + collector, + publicTrimmedFilePath, + DtsRollupKind.PublicRelease, + newlineKind + ); Extractor._generateRollupDtsFile( - collector, extractorConfig.betaTrimmedFilePath, DtsRollupKind.BetaRelease, extractorConfig.newlineKind); + collector, + alphaTrimmedFilePath, + DtsRollupKind.AlphaRelease, + newlineKind + ); Extractor._generateRollupDtsFile( - collector, extractorConfig.untrimmedFilePath, DtsRollupKind.InternalRelease, extractorConfig.newlineKind); + collector, + betaTrimmedFilePath, + DtsRollupKind.BetaRelease, + newlineKind + ); + Extractor._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 @@ -353,17 +376,206 @@ export class Extractor { compilerState, extractorConfig, succeeded, - apiReportChanged, + apiReportChanged: anyReportChanged, errorCount: messageRouter.errorCount, 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}. + * @param printApiReportDiff - {@link IExtractorInvokeOptions.printApiReportDiff} + * + * @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, + 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 + }); + + 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 + }); + } + + 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; + } + + private static _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.` + ); + } + } + } 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 + collector: Collector, + outputPath: string, + dtsKind: DtsRollupKind, + newlineKind: NewlineKind ): void { if (outputPath !== '') { - collector.messageRouter.logVerbose(ConsoleMessageId.WritingDtsRollup, `Writing package typings: ${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 5c3010653bf..47f16e6c020 100644 --- a/apps/api-extractor/src/api/ExtractorConfig.ts +++ b/apps/api-extractor/src/api/ExtractorConfig.ts @@ -1,28 +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 * 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, PackageJsonLookup, - INodePackageJson, + type INodePackageJson, PackageName, Text, InternalError, Path, NewlineKind } from '@rushstack/node-core-library'; -import { + +import type { + ApiReportVariant, + IConfigApiReport, IConfigFile, IExtractorMessagesConfig } from './IConfigFile'; import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { MessageRouter } from '../collector/MessageRouter'; +import type { IApiModelGenerationOptions } from '../generators/ApiModelGenerator'; +import apiExtractorSchema from '../schemas/api-extractor.schema.json'; /** * Tokens used during variable expansion of path fields from api-extractor.json. @@ -44,9 +54,35 @@ interface IExtractorConfigTokenContext { */ packageName: string; + /** + * The `` token returns the expanded `"projectFolder"` setting from api-extractor.json. + */ projectFolder: string; } +/** + * Options for {@link ExtractorConfig.tryLoadForFolder}. + * + * @public + */ +export interface IExtractorConfigLoadForFolderOptions { + /** + * The folder path to start from when searching for api-extractor.json. + */ + startingFolder: string; + + /** + * An already constructed `PackageJsonLookup` cache object to use. If omitted, a temporary one will + * be constructed. + */ + packageJsonLookup?: PackageJsonLookup; + + /** + * An already constructed `RigConfig` object. If omitted, then a new `RigConfig` object will be constructed. + */ + rigConfig?: IRigConfig; +} + /** * Options for {@link ExtractorConfig.prepare}. * @@ -64,7 +100,8 @@ export interface IExtractorConfigPrepareOptions { * * @remarks * - * If this is omitted, then the `projectFolder` must not be specified using the `` token. + * If `configObjectFullPath` and `projectFolderLookupToken` are both unspecified, then the api-extractor.json + * config file must explicitly specify a `projectFolder` setting rather than relying on the `` token. */ configObjectFullPath: string | undefined; @@ -89,8 +126,73 @@ export interface IExtractorConfigPrepareOptions { * If `packageJsonFullPath` is specified but `packageJson` is omitted, the file will be loaded automatically. */ packageJsonFullPath: string | undefined; + + /** + * The default value for the `projectFolder` setting is the `` token, which uses a heuristic to guess + * an appropriate project folder. Use `projectFolderLookupValue` to manually specify the `` token value + * instead. + * + * @remarks + * If the `projectFolder` setting is explicitly specified in api-extractor.json file, it should take precedence + * over a value specified via the API. Thus the `projectFolderLookupToken` option provides a way to override + * the default value for `projectFolder` setting while still honoring a manually specified value. + */ + projectFolderLookupToken?: string; + + /** + * Allow customization of the tsdoc.json config file. If omitted, this file will be loaded from its default + * location. If the file does not exist, then the standard definitions will be used from + * `@microsoft/api-extractor/extends/tsdoc-base.json`. + */ + tsdocConfigFile?: TSDocConfigFile; + + /** + * When preparing the configuration object, folder and file paths referenced in the configuration are checked + * for existence, and an error is reported if they are not found. This option can be used to disable this + * check for the main entry point module. This may be useful when preparing a configuration file for an + * un-built project. + */ + ignoreMissingEntryPoint?: boolean; +} + +/** + * Configuration for a single API report, including its {@link IExtractorConfigApiReport.variant}. + * + * @public + */ +export interface IExtractorConfigApiReport { + /** + * Report variant. + * Determines which API items will be included in the report output, based on their tagged release levels. + */ + variant: ApiReportVariant; + + /** + * Name of the output report file. + * @remarks Relative to the configured report directory path. + */ + 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; @@ -98,45 +200,66 @@ interface IExtractorConfigParameters { mainEntryPointFilePath: string; bundledPackages: string[]; tsconfigFilePath: string; - overrideTsconfig: { } | undefined; + overrideTsconfig: {} | undefined; skipLibCheck: boolean; apiReportEnabled: boolean; - reportFilePath: string; - reportTempFilePath: string; - docModelEnabled: boolean; + reportConfigs: readonly IExtractorConfigApiReport[]; + reportFolder: string; + reportTempFolder: string; + apiReportIncludeForgottenExports: boolean; + tagsToReport: Readonly>; + docModelGenerationOptions: IApiModelGenerationOptions | undefined; apiJsonFilePath: string; + docModelIncludeForgottenExports: boolean; + projectFolderUrl: string | undefined; rollupEnabled: boolean; untrimmedFilePath: string; + alphaTrimmedFilePath: string; betaTrimmedFilePath: string; publicTrimmedFilePath: string; omitTrimmingComments: boolean; tsdocMetadataEnabled: boolean; tsdocMetadataFilePath: string; + tsdocConfigFile: TSDocConfigFile; + tsdocConfiguration: TSDocConfiguration; newlineKind: NewlineKind; messages: IExtractorMessagesConfig; testMode: boolean; + enumMemberOrder: EnumMemberOrder; } /** * The `ExtractorConfig` class loads, validates, interprets, and represents the api-extractor.json config file. + * @sealed * @public */ export class ExtractorConfig { /** * The JSON Schema for API Extractor config file (api-extractor.schema.json). */ - public static readonly jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '../schemas/api-extractor.schema.json')); + public static readonly jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(apiExtractorSchema); /** * The config file name "api-extractor.json". */ - public static readonly FILENAME: string = 'api-extractor.json'; + public static readonly FILENAME: 'api-extractor.json' = 'api-extractor.json'; + + /** + * The full path to `extends/tsdoc-base.json` which contains the standard TSDoc configuration + * for API Extractor. + * @internal + */ + public static readonly _tsdocBaseFilePath: string = path.resolve( + __dirname, + '../../extends/tsdoc-base.json' + ); - private static readonly _defaultConfig: Partial = JsonFile.load(path.join(__dirname, - '../schemas/api-extractor-defaults.json')); + private static readonly _defaultConfig: Partial = JsonFile.load( + path.join(__dirname, '../schemas/api-extractor-defaults.json') + ); - private static readonly _declarationFileExtensionRegExp: RegExp = /\.d\.ts$/i; + /** 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; @@ -163,7 +286,7 @@ export class ExtractorConfig { public readonly tsconfigFilePath: string; /** {@inheritDoc IConfigCompiler.overrideTsconfig} */ - public readonly overrideTsconfig: { } | undefined; + public readonly overrideTsconfig: {} | undefined; /** {@inheritDoc IConfigCompiler.skipLibCheck} */ public readonly skipLibCheck: boolean; @@ -171,20 +294,59 @@ export class ExtractorConfig { /** {@inheritDoc IConfigApiReport.enabled} */ public readonly apiReportEnabled: boolean; - /** The `reportFolder` path combined with the `reportFileName`. */ - public readonly reportFilePath: string; - /** The `reportTempFolder` path combined with the `reportFileName`. */ - public readonly reportTempFilePath: string; + /** + * List of configurations for report files to be generated. + * @remarks Derived from {@link IConfigApiReport.reportFileName} and {@link IConfigApiReport.reportVariants}. + */ + public readonly reportConfigs: readonly IExtractorConfigApiReport[]; + /** {@inheritDoc IConfigApiReport.reportFolder} */ + 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. + * Otherwise, returns an empty string. + * @deprecated Use {@link ExtractorConfig.reportConfigs} to access all report configurations. + */ + public get reportFilePath(): string { + const completeConfig: IExtractorConfigApiReport | undefined = this._getCompleteReportConfig(); + return completeConfig === undefined ? '' : path.join(this.reportFolder, completeConfig.fileName); + } + + /** + * Gets the temp file path for the "complete" (default) report configuration, if one was specified. + * Otherwise, returns an empty string. + * @deprecated Use {@link ExtractorConfig.reportConfigs} to access all report configurations. + */ + public get reportTempFilePath(): string { + const completeConfig: IExtractorConfigApiReport | undefined = this._getCompleteReportConfig(); + return completeConfig === undefined ? '' : path.join(this.reportTempFolder, completeConfig.fileName); + } + + /** {@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} */ + public readonly docModelIncludeForgottenExports: boolean; + /** {@inheritDoc IConfigDocModel.projectFolderUrl} */ + public readonly projectFolderUrl: string | undefined; /** {@inheritDoc IConfigDtsRollup.enabled} */ public readonly rollupEnabled: boolean; /** {@inheritDoc IConfigDtsRollup.untrimmedFilePath} */ public readonly untrimmedFilePath: string; + /** {@inheritDoc IConfigDtsRollup.alphaTrimmedFilePath} */ + public readonly alphaTrimmedFilePath: string; /** {@inheritDoc IConfigDtsRollup.betaTrimmedFilePath} */ public readonly betaTrimmedFilePath: string; /** {@inheritDoc IConfigDtsRollup.publicTrimmedFilePath} */ @@ -197,6 +359,16 @@ export class ExtractorConfig { /** {@inheritDoc IConfigTsdocMetadata.tsdocMetadataFilePath} */ public readonly tsdocMetadataFilePath: string; + /** + * The tsdoc.json configuration that will be used when parsing doc comments. + */ + public readonly tsdocConfigFile: TSDocConfigFile; + + /** + * The `TSDocConfiguration` loaded from {@link ExtractorConfig.tsdocConfigFile}. + */ + public readonly tsdocConfiguration: TSDocConfiguration; + /** * 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. @@ -209,30 +381,75 @@ export class ExtractorConfig { /** {@inheritDoc IConfigFile.testMode} */ public readonly testMode: boolean; - 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.reportFilePath = parameters.reportFilePath; - this.reportTempFilePath = parameters.reportTempFilePath; - this.docModelEnabled = parameters.docModelEnabled; - this.apiJsonFilePath = parameters.apiJsonFilePath; - this.rollupEnabled = parameters.rollupEnabled; - this.untrimmedFilePath = parameters.untrimmedFilePath; - this.betaTrimmedFilePath = parameters.betaTrimmedFilePath; - this.publicTrimmedFilePath = parameters.publicTrimmedFilePath; - this.omitTrimmingComments = parameters.omitTrimmingComments; - this.tsdocMetadataEnabled = parameters.tsdocMetadataEnabled; - this.tsdocMetadataFilePath = parameters.tsdocMetadataFilePath; - this.newlineKind = parameters.newlineKind; - this.messages = parameters.messages; - this.testMode = parameters.testMode; + /** {@inheritDoc IConfigFile.enumMemberOrder} */ + public readonly enumMemberOrder: 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; } /** @@ -244,7 +461,19 @@ export class ExtractorConfig { * its format may be changed at any time. */ public getDiagnosticDump(): string { - const result: object = MessageRouter.buildJsonDumpObject(this); + // Handle the simple JSON-serializable properties using buildJsonDumpObject() + const result: object = MessageRouter.buildJsonDumpObject(this, { + keyNamesToOmit: ['tsdocConfigFile', 'tsdocConfiguration'] + }); + + // Implement custom formatting for tsdocConfigFile and tsdocConfiguration + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (result as any).tsdocConfigFile = { + filePath: this.tsdocConfigFile.filePath, + log: this.tsdocConfigFile.log.messages.map((x) => x.toString()) + }; + return JSON.stringify(result, undefined, 2); } @@ -257,11 +486,108 @@ export class ExtractorConfig { throw new InternalError('Expected absolute path: ' + absolutePath); } if (Path.isUnderOrEqual(absolutePath, this.projectFolder)) { - return path.relative(this.projectFolder, absolutePath).replace(/\\/g, '/'); + return Path.convertToSlashes(path.relative(this.projectFolder, absolutePath)); } return absolutePath; } + /** + * Searches for the api-extractor.json config file associated with the specified starting folder, + * and loads the file if found. This lookup supports + * {@link https://www.npmjs.com/package/@rushstack/rig-package | rig packages}. + * + * @remarks + * The search will first look for a package.json file in a parent folder of the starting folder; + * if found, that will be used as the base folder instead of the starting folder. If the config + * file is not found in `/api-extractor.json` or `/config/api-extractor.json`, + * then `/api-extractor.json or /config/api-extractor.json + // then check for a rig package + if (packageFolder) { + let rigConfig: IRigConfig; + if (options.rigConfig) { + // The caller provided an already solved RigConfig. Double-check that it is for the right project. + if (!Path.isEqual(options.rigConfig.projectFolderPath, packageFolder)) { + throw new Error( + 'The provided ILoadForFolderOptions.rigConfig is for the wrong project folder:\n' + + '\nExpected path: ' + + packageFolder + + '\nProvided path: ' + + options.rigConfig.projectFolderOriginalPath + ); + } + rigConfig = options.rigConfig; + } else { + rigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: packageFolder + }); + } + + if (rigConfig.rigFound) { + configFilename = path.join(rigConfig.getResolvedProfileFolder(), ExtractorConfig.FILENAME); + + // If the "projectFolder" setting isn't specified in api-extractor.json, it defaults to the + // "" token which will probe for the tsconfig.json nearest to the api-extractor.json path. + // But this won't work if api-extractor.json belongs to the rig. So instead "" should be + // the "" that referenced the rig. + projectFolderLookupToken = packageFolder; + } + } + if (!FileSystem.exists(configFilename)) { + // API Extractor does not seem to be configured for this folder + return undefined; + } + } + } + + const configObjectFullPath: string = path.resolve(configFilename); + const configObject: IConfigFile = ExtractorConfig.loadFile(configObjectFullPath); + + return { + configObject, + configObjectFullPath, + packageJsonFullPath, + projectFolderLookupToken + }; + } + /** * Loads the api-extractor.json config file from the specified file path, and prepares an `ExtractorConfig` object. * @@ -276,8 +602,8 @@ export class ExtractorConfig { const configObject: IConfigFile = ExtractorConfig.loadFile(configObjectFullPath); const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - const packageJsonFullPath: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor( - configObjectFullPath); + const packageJsonFullPath: string | undefined = + packageJsonLookup.tryGetPackageJsonFilePathFor(configObjectFullPath); const extractorConfig: ExtractorConfig = ExtractorConfig.prepare({ configObject, @@ -300,15 +626,28 @@ export class ExtractorConfig { // Set to keep track of config files which have been processed. const visitedPaths: Set = new Set(); - let currentConfigFilePath: string = path.resolve(process.cwd(), jsonFilePath); - let configObject: Partial = { }; + let currentConfigFilePath: string = path.resolve(jsonFilePath); + let configObject: Partial = {}; + + // Lodash merges array values by default, which is unintuitive for config files (and makes it impossible for derived configurations to overwrite arrays). + // For example, given a base config containing an array property with value ["foo", "bar"] and a derived config that specifies ["baz"] for that property, lodash will produce ["baz", "bar"], which is unintuitive. + // This customizer function ensures that arrays are always overwritten. + const mergeCustomizer: lodash.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. if (visitedPaths.has(currentConfigFilePath)) { - throw new Error(`The API Extractor "extends" setting contains a cycle.` - + ` This file is included twice: "${currentConfigFilePath}"`); + throw new Error( + `The API Extractor "extends" setting contains a cycle.` + + ` This file is included twice: "${currentConfigFilePath}"` + ); } visitedPaths.add(currentConfigFilePath); @@ -331,14 +670,11 @@ export class ExtractorConfig { // // Resolve "my-package" from the perspective of the current folder. try { - extendsField = resolve.sync( - extendsField, - { - basedir: currentConfigFolderPath - } - ); + extendsField = resolve.sync(extendsField, { + basedir: currentConfigFolderPath + }); } catch (e) { - throw new Error(`Error resolving NodeJS path "${extendsField}": ${e.message}`); + throw new Error(`Error resolving NodeJS path "${extendsField}": ${(e as Error).message}`); } } } @@ -348,18 +684,21 @@ export class ExtractorConfig { ExtractorConfig._resolveConfigFileRelativePaths(baseConfig, currentConfigFolderPath); // Merge extractorConfig into baseConfig, mutating baseConfig - lodash.merge(baseConfig, configObject); + lodash.mergeWith(baseConfig, configObject, mergeCustomizer); configObject = baseConfig; currentConfigFilePath = extendsField; } while (currentConfigFilePath); - } catch (e) { - throw new Error(`Error loading ${currentConfigFilePath}:\n` + e.message); + throw new Error(`Error loading ${currentConfigFilePath}:\n` + (e as Error).message); } // Lastly, apply the defaults - configObject = lodash.merge(lodash.cloneDeep(ExtractorConfig._defaultConfig), configObject); + configObject = lodash.mergeWith( + lodash.cloneDeep(ExtractorConfig._defaultConfig), + configObject, + mergeCustomizer + ); ExtractorConfig.jsonSchema.validateObject(configObject, jsonFilePath); @@ -367,69 +706,110 @@ export class ExtractorConfig { return configObject as IConfigFile; } - private static _resolveConfigFileRelativePaths(configFile: IConfigFile, currentConfigFolderPath: string): void { - + private static _resolveConfigFileRelativePaths( + configFile: IConfigFile, + currentConfigFolderPath: string + ): void { if (configFile.projectFolder) { configFile.projectFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'projectFolder', configFile.projectFolder, currentConfigFolderPath); + 'projectFolder', + configFile.projectFolder, + currentConfigFolderPath + ); } if (configFile.mainEntryPointFilePath) { configFile.mainEntryPointFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'mainEntryPointFilePath', configFile.mainEntryPointFilePath, currentConfigFolderPath); + 'mainEntryPointFilePath', + configFile.mainEntryPointFilePath, + currentConfigFolderPath + ); } if (configFile.compiler) { if (configFile.compiler.tsconfigFilePath) { configFile.compiler.tsconfigFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'tsconfigFilePath', configFile.compiler.tsconfigFilePath, currentConfigFolderPath); + 'tsconfigFilePath', + configFile.compiler.tsconfigFilePath, + currentConfigFolderPath + ); } } if (configFile.apiReport) { if (configFile.apiReport.reportFolder) { configFile.apiReport.reportFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'reportFolder', configFile.apiReport.reportFolder, currentConfigFolderPath); + 'reportFolder', + configFile.apiReport.reportFolder, + currentConfigFolderPath + ); } if (configFile.apiReport.reportTempFolder) { configFile.apiReport.reportTempFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'reportTempFolder', configFile.apiReport.reportTempFolder, currentConfigFolderPath); + 'reportTempFolder', + configFile.apiReport.reportTempFolder, + currentConfigFolderPath + ); } } if (configFile.docModel) { if (configFile.docModel.apiJsonFilePath) { configFile.docModel.apiJsonFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'apiJsonFilePath', configFile.docModel.apiJsonFilePath, currentConfigFolderPath); + 'apiJsonFilePath', + configFile.docModel.apiJsonFilePath, + currentConfigFolderPath + ); } } if (configFile.dtsRollup) { if (configFile.dtsRollup.untrimmedFilePath) { configFile.dtsRollup.untrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'untrimmedFilePath', configFile.dtsRollup.untrimmedFilePath, currentConfigFolderPath); + '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); + 'betaTrimmedFilePath', + configFile.dtsRollup.betaTrimmedFilePath, + currentConfigFolderPath + ); } if (configFile.dtsRollup.publicTrimmedFilePath) { configFile.dtsRollup.publicTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'publicTrimmedFilePath', configFile.dtsRollup.publicTrimmedFilePath, currentConfigFolderPath); + 'publicTrimmedFilePath', + configFile.dtsRollup.publicTrimmedFilePath, + currentConfigFolderPath + ); } } if (configFile.tsdocMetadata) { if (configFile.tsdocMetadata.tsdocMetadataFilePath) { configFile.tsdocMetadata.tsdocMetadataFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'tsdocMetadataFilePath', configFile.tsdocMetadata.tsdocMetadataFilePath, currentConfigFolderPath); + 'tsdocMetadataFilePath', + configFile.tsdocMetadata.tsdocMetadataFilePath, + currentConfigFolderPath + ); } } } - private static _resolveConfigFileRelativePath(fieldName: string, fieldValue: string, - currentConfigFolderPath: string): string { - + 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 @@ -451,7 +831,9 @@ export class ExtractorConfig { const configObject: Partial = options.configObject; if (configObject.extends) { - throw new Error('The IConfigFile.extends field must be expanded before calling ExtractorConfig.prepare()'); + throw new Error( + 'The IConfigFile.extends field must be expanded before calling ExtractorConfig.prepare()' + ); } if (options.configObjectFullPath) { @@ -485,8 +867,11 @@ export class ExtractorConfig { packageFolder = path.dirname(packageJsonFullPath); } - try { + // "tsdocConfigFile" and "tsdocConfiguration" are prepared outside the try-catch block, + // so that if exceptions are thrown, it will not get the "Error parsing api-extractor.json:" header + let extractorConfigParameters: Omit; + try { if (!configObject.compiler) { // A merged configuration should have this throw new Error('The "compiler" section is missing'); @@ -499,29 +884,45 @@ export class ExtractorConfig { let projectFolder: string; if (configObject.projectFolder.trim() === '') { - if (!options.configObjectFullPath) { - throw new Error('The "projectFolder" setting uses the "" token, but it cannot be expanded because' - + ' the "configObjectFullPath" setting was not specified'); - } - - // "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." - - let currentFolder: string = path.dirname(options.configObjectFullPath); - for (; ; ) { - const tsconfigPath: string = path.join(currentFolder, 'tsconfig.json'); - if (FileSystem.exists(tsconfigPath)) { - projectFolder = currentFolder; - break; + if (options.projectFolderLookupToken) { + // Use the manually specified "" value + projectFolder = options.projectFolderLookupToken; + + if (!FileSystem.exists(options.projectFolderLookupToken)) { + throw new Error( + 'The specified "projectFolderLookupToken" path does not exist: ' + + options.projectFolderLookupToken + ); } - const parentFolder: string = path.dirname(currentFolder); - if (parentFolder === '' || parentFolder === currentFolder) { - throw new Error('The "projectFolder" setting uses the "" token, but a tsconfig.json file cannot be' - + ' found in this folder or any parent folder.'); + } else { + if (!options.configObjectFullPath) { + throw new Error( + 'The "projectFolder" setting uses the "" token, but it cannot be expanded because' + + ' the "configObjectFullPath" setting was not specified' + ); + } + + // "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." + + let currentFolder: string = path.dirname(options.configObjectFullPath); + for (;;) { + const tsconfigPath: string = path.join(currentFolder, 'tsconfig.json'); + if (FileSystem.exists(tsconfigPath)) { + projectFolder = currentFolder; + break; + } + const parentFolder: string = path.dirname(currentFolder); + if (parentFolder === '' || parentFolder === currentFolder) { + throw new Error( + 'The "projectFolder" setting uses the "" token, but a tsconfig.json file cannot be' + + ' found in this folder or any parent folder.' + ); + } + currentFolder = parentFolder; } - currentFolder = parentFolder; } } else { ExtractorConfig._rejectAnyTokensInPath(configObject.projectFolder, 'projectFolder'); @@ -548,26 +949,32 @@ export class ExtractorConfig { // A merged configuration should have this throw new Error('The "mainEntryPointFilePath" setting is missing'); } - const mainEntryPointFilePath: string = ExtractorConfig._resolvePathWithTokens('mainEntryPointFilePath', - configObject.mainEntryPointFilePath, tokenContext); + const mainEntryPointFilePath: string = ExtractorConfig._resolvePathWithTokens( + 'mainEntryPointFilePath', + configObject.mainEntryPointFilePath, + tokenContext + ); if (!ExtractorConfig.hasDtsFileExtension(mainEntryPointFilePath)) { - throw new Error('The "mainEntryPointFilePath" value is not a declaration file: ' + mainEntryPointFilePath); + throw new Error( + 'The "mainEntryPointFilePath" value is not a declaration file: ' + mainEntryPointFilePath + ); } - if (!FileSystem.exists(mainEntryPointFilePath)) { + if (!options.ignoreMissingEntryPoint && !FileSystem.exists(mainEntryPointFilePath)) { throw new Error('The "mainEntryPointFilePath" path does not exist: ' + mainEntryPointFilePath); } const bundledPackages: string[] = configObject.bundledPackages || []; - for (const bundledPackage of bundledPackages) { - if (!PackageName.isValidName(bundledPackage)) { - throw new Error(`The "bundledPackages" list contains an invalid package name: "${bundledPackage}"`); - } - } - const tsconfigFilePath: string = ExtractorConfig._resolvePathWithTokens('tsconfigFilePath', - configObject.compiler.tsconfigFilePath, tokenContext); + // 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( + 'tsconfigFilePath', + configObject.compiler.tsconfigFilePath, + tokenContext + ); if (configObject.compiler.overrideTsconfig === undefined) { if (!tsconfigFilePath) { @@ -578,39 +985,140 @@ export class ExtractorConfig { } } - let apiReportEnabled: boolean = false; - let reportFilePath: string = ''; - let reportTempFilePath: string = ''; - if (configObject.apiReport) { - apiReportEnabled = !!configObject.apiReport.enabled; + 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!; + + const reportFileNameSuffix: string = '.api.md'; + let reportFileNameBase: string; + if (apiReportConfig.reportFileName) { + if ( + apiReportConfig.reportFileName.indexOf('/') >= 0 || + apiReportConfig.reportFileName.indexOf('\\') >= 0 + ) { + throw new Error( + `The "reportFileName" setting contains invalid characters: "${apiReportConfig.reportFileName}"` + ); + } - const reportFilename: string = ExtractorConfig._expandStringWithTokens('reportFileName', - configObject.apiReport.reportFileName || '', tokenContext); + if (!apiReportConfig.reportFileName.endsWith(reportFileNameSuffix)) { + // `.api.md` extension was not specified. Use provided file name base as is. + reportFileNameBase = apiReportConfig.reportFileName; + } else { + // The system previously asked users to specify their filenames in a form containing the `.api.md` extension. + // This guidance has changed, but to maintain backwards compatibility, we will temporarily support input + // that ends with the `.api.md` extension specially, by stripping it out. + // This should be removed in version 8, possibly replaced with an explicit error to help users + // migrate their configs. + reportFileNameBase = apiReportConfig.reportFileName.slice(0, -reportFileNameSuffix.length); + } + } else { + // Default value + reportFileNameBase = ''; + } - if (!reportFilename) { - // A merged configuration should have this - throw new Error('The "reportFilename" setting is missing'); + 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( + 'reportFileName', + fileNameWithTokens, + tokenContext + ); + + reportConfigs.push({ + fileName: normalizedFileName, + variant: reportVariantKind + }); } - if (reportFilename.indexOf('/') >= 0 || reportFilename.indexOf('\\') >= 0) { - // A merged configuration should have this - throw new Error(`The "reportFilename" setting contains invalid characters: "${reportFilename}"`); + + if (apiReportConfig.reportFolder) { + reportFolder = ExtractorConfig._resolvePathWithTokens( + 'reportFolder', + apiReportConfig.reportFolder, + tokenContext + ); } - const reportFolder: string = ExtractorConfig._resolvePathWithTokens('reportFolder', - configObject.apiReport.reportFolder, tokenContext); - const reportTempFolder: string = ExtractorConfig._resolvePathWithTokens('reportTempFolder', - configObject.apiReport.reportTempFolder, tokenContext); + if (apiReportConfig.reportTempFolder) { + reportTempFolder = ExtractorConfig._resolvePathWithTokens( + 'reportTempFolder', + apiReportConfig.reportTempFolder, + tokenContext + ); + } - reportFilePath = path.join(reportFolder, reportFilename); - reportTempFilePath = path.join(reportTempFolder, reportFilename); + tagsToReport = { + ...defaultTagsToReport, + ...apiReportConfig.tagsToReport + }; } - let docModelEnabled: boolean = false; + let docModelGenerationOptions: IApiModelGenerationOptions | undefined = undefined; let apiJsonFilePath: string = ''; - if (configObject.docModel) { - docModelEnabled = !!configObject.docModel.enabled; - apiJsonFilePath = ExtractorConfig._resolvePathWithTokens('apiJsonFilePath', - configObject.docModel.apiJsonFilePath, tokenContext); + let docModelIncludeForgottenExports: boolean = false; + let projectFolderUrl: string | undefined; + if (configObject.docModel?.enabled) { + apiJsonFilePath = ExtractorConfig._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; @@ -623,25 +1131,34 @@ export class ExtractorConfig { if (tsdocMetadataFilePath.trim() === '') { if (!packageJson) { - throw new Error('The "" token cannot be used with the "tsdocMetadataFilePath" setting because' - + ' the "packageJson" option was not provided'); + throw new Error( + 'The "" token cannot be used with the "tsdocMetadataFilePath" setting because' + + ' the "packageJson" option was not provided' + ); } if (!packageJsonFullPath) { - throw new Error('The "" token cannot be used with "tsdocMetadataFilePath" because' - + 'the "packageJsonFullPath" option was not provided'); + throw new Error( + 'The "" token cannot be used with "tsdocMetadataFilePath" because' + + 'the "packageJsonFullPath" option was not provided' + ); } tsdocMetadataFilePath = PackageMetadataManager.resolveTsdocMetadataPath( path.dirname(packageJsonFullPath), packageJson ); } else { - tsdocMetadataFilePath = ExtractorConfig._resolvePathWithTokens('tsdocMetadataFilePath', - configObject.tsdocMetadata.tsdocMetadataFilePath, tokenContext); + tsdocMetadataFilePath = ExtractorConfig._resolvePathWithTokens( + 'tsdocMetadataFilePath', + configObject.tsdocMetadata.tsdocMetadataFilePath, + tokenContext + ); } if (!tsdocMetadataFilePath) { - throw new Error('The "tsdocMetadata.enabled" setting is enabled,' - + ' but "tsdocMetadataFilePath" is not specified'); + throw new Error( + 'The "tsdocMetadata.enabled" setting is enabled,' + + ' but "tsdocMetadataFilePath" is not specified' + ); } } } @@ -649,17 +1166,32 @@ export class ExtractorConfig { let rollupEnabled: boolean = false; let untrimmedFilePath: string = ''; let betaTrimmedFilePath: string = ''; + let alphaTrimmedFilePath: string = ''; let publicTrimmedFilePath: string = ''; let omitTrimmingComments: boolean = false; if (configObject.dtsRollup) { rollupEnabled = !!configObject.dtsRollup.enabled; - untrimmedFilePath = ExtractorConfig._resolvePathWithTokens('untrimmedFilePath', - configObject.dtsRollup.untrimmedFilePath, tokenContext); - betaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens('betaTrimmedFilePath', - configObject.dtsRollup.betaTrimmedFilePath, tokenContext); - publicTrimmedFilePath = ExtractorConfig._resolvePathWithTokens('publicTrimmedFilePath', - configObject.dtsRollup.publicTrimmedFilePath, tokenContext); + untrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + 'untrimmedFilePath', + configObject.dtsRollup.untrimmedFilePath, + tokenContext + ); + alphaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + 'alphaTrimmedFilePath', + configObject.dtsRollup.alphaTrimmedFilePath, + tokenContext + ); + betaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + 'betaTrimmedFilePath', + configObject.dtsRollup.betaTrimmedFilePath, + tokenContext + ); + publicTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + 'publicTrimmedFilePath', + configObject.dtsRollup.publicTrimmedFilePath, + tokenContext + ); omitTrimmingComments = !!configObject.dtsRollup.omitTrimmingComments; } @@ -676,7 +1208,9 @@ export class ExtractorConfig { break; } - return new ExtractorConfig({ + const enumMemberOrder: EnumMemberOrder = configObject.enumMemberOrder ?? EnumMemberOrder.ByName; + + extractorConfigParameters = { projectFolder: projectFolder, packageJson, packageFolder, @@ -686,30 +1220,78 @@ export class ExtractorConfig { overrideTsconfig: configObject.compiler.overrideTsconfig, skipLibCheck: !!configObject.compiler.skipLibCheck, apiReportEnabled, - reportFilePath, - reportTempFilePath, - docModelEnabled, + reportConfigs, + reportFolder, + reportTempFolder, + apiReportIncludeForgottenExports, + tagsToReport, + docModelGenerationOptions, apiJsonFilePath, + docModelIncludeForgottenExports, + projectFolderUrl, rollupEnabled, untrimmedFilePath, + alphaTrimmedFilePath, betaTrimmedFilePath, publicTrimmedFilePath, omitTrimmingComments, tsdocMetadataEnabled, tsdocMetadataFilePath, newlineKind, - messages: configObject.messages || { }, - testMode: !!configObject.testMode - }); - + messages: configObject.messages || {}, + testMode: !!configObject.testMode, + enumMemberOrder + }; } catch (e) { - throw new Error(`Error parsing ${filenameForErrors}:\n` + e.message); + throw new Error(`Error parsing ${filenameForErrors}:\n` + (e as Error).message); + } + + let tsdocConfigFile: TSDocConfigFile | undefined = options.tsdocConfigFile; + + if (!tsdocConfigFile) { + // Example: "my-project/tsdoc.json" + let packageTSDocConfigPath: string = TSDocConfigFile.findConfigPathForFolder( + extractorConfigParameters.projectFolder + ); + + if (!packageTSDocConfigPath || !FileSystem.exists(packageTSDocConfigPath)) { + // If the project does not have a tsdoc.json config file, then use API Extractor's base file. + packageTSDocConfigPath = ExtractorConfig._tsdocBaseFilePath; + if (!FileSystem.exists(packageTSDocConfigPath)) { + throw new InternalError('Unable to load the built-in TSDoc config file: ' + packageTSDocConfigPath); + } + } + tsdocConfigFile = TSDocConfigFile.loadFile(packageTSDocConfigPath); + } + + // IMPORTANT: After calling TSDocConfigFile.loadFile(), we need to check for errors. + if (tsdocConfigFile.hasErrors) { + throw new Error(tsdocConfigFile.getErrorSummary()); } + + const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration(); + tsdocConfigFile.configureParser(tsdocConfiguration); + + // IMPORTANT: After calling TSDocConfigFile.configureParser(), we need to check for errors a second time. + if (tsdocConfigFile.hasErrors) { + throw new Error(tsdocConfigFile.getErrorSummary()); + } + + return new ExtractorConfig({ ...extractorConfigParameters, tsdocConfigFile, tsdocConfiguration }); } - private static _resolvePathWithTokens(fieldName: string, value: string | undefined, - tokenContext: IExtractorConfigTokenContext): string { + /** + * Gets the report configuration for the "complete" (default) report configuration, if one was specified. + */ + private _getCompleteReportConfig(): IExtractorConfigApiReport | undefined { + 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); @@ -717,8 +1299,11 @@ export class ExtractorConfig { return value; } - private static _expandStringWithTokens(fieldName: string, value: string | undefined, - tokenContext: IExtractorConfigTokenContext): string { + private static _expandStringWithTokens( + fieldName: string, + value: string | undefined, + tokenContext: IExtractorConfigTokenContext + ): string { value = value ? value.trim() : ''; if (value !== '') { value = Text.replaceAll(value, '', tokenContext.unscopedPackageName); @@ -732,8 +1317,10 @@ export class ExtractorConfig { 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.`); + throw new Error( + `The "${fieldName}" value incorrectly uses the "" token.` + + ` It must appear at the start of the string.` + ); } if (value.indexOf('') >= 0) { @@ -769,3 +1356,47 @@ export class ExtractorConfig { 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/ExtractorLogLevel.ts b/apps/api-extractor/src/api/ExtractorLogLevel.ts index 40a687aa3a0..9670889bf78 100644 --- a/apps/api-extractor/src/api/ExtractorLogLevel.ts +++ b/apps/api-extractor/src/api/ExtractorLogLevel.ts @@ -9,7 +9,7 @@ * * @public */ -export const enum ExtractorLogLevel { +export enum ExtractorLogLevel { /** * The message will be displayed as an error. * diff --git a/apps/api-extractor/src/api/ExtractorMessage.ts b/apps/api-extractor/src/api/ExtractorMessage.ts index 49150b4eb24..1238a1a9c04 100644 --- a/apps/api-extractor/src/api/ExtractorMessage.ts +++ b/apps/api-extractor/src/api/ExtractorMessage.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 * as tsdoc from '@microsoft/tsdoc'; -import * as path from 'path'; -import { ExtractorMessageId } from './ExtractorMessageId'; -import { Path, Text } from '@rushstack/node-core-library'; +import type * as tsdoc from '@microsoft/tsdoc'; + +import type { ExtractorMessageId } from './ExtractorMessageId'; import { ExtractorLogLevel } from './ExtractorLogLevel'; -import { ConsoleMessageId } from './ConsoleMessageId'; +import type { ConsoleMessageId } from './ConsoleMessageId'; +import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; /** * Used by {@link ExtractorMessage.properties}. @@ -14,7 +14,6 @@ import { ConsoleMessageId } from './ConsoleMessageId'; * @public */ export interface IExtractorMessageProperties { - /** * A declaration can have multiple names if it is exported more than once. * If an `ExtractorMessage` applies to a specific export name, this property can indicate that. @@ -30,7 +29,7 @@ export interface IExtractorMessageProperties { * Specifies a category of messages for use with {@link ExtractorMessage}. * @public */ -export const enum ExtractorMessageCategory { +export enum ExtractorMessageCategory { /** * Messages originating from the TypeScript compiler. * @@ -139,7 +138,7 @@ export class ExtractorMessage { this.sourceFilePath = options.sourceFilePath; this.sourceFileLine = options.sourceFileLine; this.sourceFileColumn = options.sourceFileColumn; - this.properties = options.properties || { }; + this.properties = options.properties || {}; this._handled = false; this._logLevel = options.logLevel || ExtractorLogLevel.None; @@ -163,7 +162,9 @@ export class ExtractorMessage { public set handled(value: boolean) { if (this._handled && !value) { - throw new Error('One a message has been marked as handled, the "handled" property cannot be set to false'); + throw new Error( + 'One a message has been marked as handled, the "handled" property cannot be set to false' + ); } this._handled = value; } @@ -211,27 +212,11 @@ export class ExtractorMessage { let result: string = ''; if (this.sourceFilePath) { - // Make the path relative to the workingPackageFolderPath - let scrubbedPath: string = this.sourceFilePath; - - if (workingPackageFolderPath !== undefined) { - // If it's under the working folder, make it a relative path - if (Path.isUnderOrEqual(this.sourceFilePath, workingPackageFolderPath)) { - scrubbedPath = path.relative(workingPackageFolderPath, this.sourceFilePath); - } - } - - // Convert it to a Unix-style path - scrubbedPath = Text.replaceAll(scrubbedPath, '\\', '/'); - result += scrubbedPath; - - if (this.sourceFileLine) { - result += `:${this.sourceFileLine}`; - - if (this.sourceFileColumn) { - result += `:${this.sourceFileColumn}`; - } - } + result += SourceFileLocationFormatter.formatPath(this.sourceFilePath, { + sourceFileLine: this.sourceFileLine, + sourceFileColumn: this.sourceFileColumn, + workingPackageFolderPath + }); if (result.length > 0) { result += ' - '; diff --git a/apps/api-extractor/src/api/ExtractorMessageId.ts b/apps/api-extractor/src/api/ExtractorMessageId.ts index 6caf70a2496..9e423d9a420 100644 --- a/apps/api-extractor/src/api/ExtractorMessageId.ts +++ b/apps/api-extractor/src/api/ExtractorMessageId.ts @@ -11,12 +11,31 @@ * * @public */ -export const enum ExtractorMessageId { +export enum ExtractorMessageId { /** * "The doc comment should not contain more than one release tag." */ ExtraReleaseTag = 'ae-extra-release-tag', + /** + * "Missing documentation for ___." + * @remarks + * The `ae-undocumented` message is only generated if the API report feature is enabled. + * + * Because the API report file already annotates undocumented items with `// (undocumented)`, + * the `ae-undocumented` message is not logged by default. To see it, add a setting such as: + * ```json + * "messages": { + * "extractorMessageReporting": { + * "ae-undocumented": { + * "logLevel": "warning" + * } + * } + * } + * ``` + */ + Undocumented = 'ae-undocumented', + /** * "This symbol has another declaration with a different release tag." */ @@ -28,7 +47,7 @@ export const enum ExtractorMessageId { IncompatibleReleaseTags = 'ae-incompatible-release-tags', /** - * "___ is exported by the package, but it is missing a release tag (`@alpha`, `@beta`, `@public`, or `@internal`)." + * "___ is part of the package's API, but it is missing a release tag (`@alpha`, `@beta`, `@public`, or `@internal`)." */ MissingReleaseTag = 'ae-missing-release-tag', @@ -96,10 +115,17 @@ export const enum ExtractorMessageId { * "The property ___ has a setter but no getter." */ MissingGetter = 'ae-missing-getter', + + /** + * "Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension. + * Troubleshooting tips: `https://api-extractor.com/link/dts-error`" + */ + WrongInputFileType = 'ae-wrong-input-file-type' } export const allExtractorMessageIds: Set = new Set([ 'ae-extra-release-tag', + 'ae-undocumented', 'ae-different-release-tags', 'ae-incompatible-release-tags', 'ae-missing-release-tag', @@ -114,5 +140,6 @@ export const allExtractorMessageIds: Set = new Set([ 'ae-cyclic-inherit-doc', 'ae-unresolved-link', 'ae-setter-with-docs', - 'ae-missing-getter' + 'ae-missing-getter', + 'ae-wrong-input-file-type' ]); diff --git a/apps/api-extractor/src/api/IConfigFile.ts b/apps/api-extractor/src/api/IConfigFile.ts index e37281b3879..f05b943f796 100644 --- a/apps/api-extractor/src/api/IConfigFile.ts +++ b/apps/api-extractor/src/api/IConfigFile.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 { ExtractorLogLevel } from './ExtractorLogLevel'; +import type { EnumMemberOrder } from '@microsoft/api-extractor-model'; + +import type { ExtractorLogLevel } from './ExtractorLogLevel'; /** * Determines how the TypeScript compiler engine will be invoked by API Extractor. @@ -33,7 +35,7 @@ export interface IConfigCompiler { * * If omitted, then the tsconfig.json file will instead be read from the projectFolder. */ - overrideTsconfig?: { }; + overrideTsconfig?: {}; /** * This option causes the compiler to be invoked with the `--skipLibCheck` option. @@ -47,6 +49,13 @@ export interface IConfigCompiler { skipLibCheck?: boolean; } +/** + * The allowed variations of API reports. + * + * @public + */ +export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; + /** * Configures how the API report files (*.api.md) will be generated. * @@ -62,14 +71,39 @@ export interface IConfigApiReport { enabled: boolean; /** - * The filename for the API report files. It will be combined with `reportFolder` or `reportTempFolder` to produce - * a full output filename. + * The base filename for the API report files, to be combined with {@link IConfigApiReport.reportFolder} or + * {@link IConfigApiReport.reportTempFolder} to produce the full file path. * * @remarks - * The file extension should be ".api.md", and the string should not contain a path separator such as `\` or `/`. + * The `reportFileName` should not include any path separators such as `\` or `/`. The `reportFileName` should + * not include a file extension, since API Extractor will automatically append an appropriate file extension such + * as `.api.md`. If the {@link IConfigApiReport.reportVariants} setting is used, then the file extension includes + * the variant name, for example `my-report.public.api.md` or `my-report.beta.api.md`. The `complete` variant always + * uses the simple extension `my-report.api.md`. + * + * Previous versions of API Extractor required `reportFileName` to include the `.api.md` extension explicitly; + * for backwards compatibility, that is still accepted but will be discarded before applying the above rules. + * + * @defaultValue `` */ reportFileName?: string; + /** + * The set of report variants to generate. + * + * @remarks + * To support different approval requirements for different API levels, multiple "variants" of the API report can + * be generated. The `reportVariants` setting specifies a list of variants to be generated. If omitted, + * by default only the `complete` variant will be generated, which includes all `@internal`, `@alpha`, `@beta`, + * and `@public` items. Other possible variants are `alpha` (`@alpha` + `@beta` + `@public`), + * `beta` (`@beta` + `@public`), and `public` (`@public only`). + * + * The resulting API report file names will be derived from the {@link IConfigApiReport.reportFileName}. + * + * @defaultValue `[ "complete" ]` + */ + reportVariants?: ApiReportVariant[]; + /** * Specifies the folder where the API report file is written. The file name portion is determined by * the `reportFileName` setting. @@ -95,8 +129,60 @@ export interface IConfigApiReport { * prepend a folder token such as ``. */ reportTempFolder?: string; + + /** + * Whether "forgotten exports" should be included in the API report file. + * + * @remarks + * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See + * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. + * + * @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. * @@ -119,6 +205,38 @@ export interface IConfigDocModel { * prepend a folder token such as ``. */ apiJsonFilePath?: string; + + /** + * Whether "forgotten exports" should be included in the doc model file. + * + * @remarks + * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See + * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more. + * + * @defaultValue `false` + */ + includeForgottenExports?: boolean; + + /** + * 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. + * + * @remarks + * 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. + */ + projectFolderUrl?: string; + + /** + * Specifies a list of release tags that will be trimmed from the doc model. + * + * @defaultValue `["@internal"]` + */ + releaseTagsToTrim?: ReleaseTagForTrim[]; } /** @@ -148,6 +266,17 @@ export interface IConfigDtsRollup { */ untrimmedFilePath?: string; + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. + * + * @remarks + * 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 ``. + */ + alphaTrimmedFilePath?: string; + /** * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. * @@ -303,10 +432,15 @@ export interface IConfigFile { * * 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. + * The default value for `projectFolder` is the token ``, which means the folder is determined using + * the following heuristics: + * + * If the config/rig.json system is used (as defined by {@link https://www.npmjs.com/package/@rushstack/rig-package + * | @rushstack/rig-package}), then the `` value will be the package folder that referenced the rig. + * + * Otherwise, the `` value 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. */ projectFolder?: string; @@ -325,8 +459,17 @@ export interface IConfigFile { * A list of NPM package names whose exports should be treated as part of this package. * * @remarks + * Also supports glob patterns. + * Note: glob patterns will **only** be resolved against dependencies listed in the project's package.json file. + * + * * This is both a safety and a performance precaution. + * + * Exact package names will be applied against any dependency encountered while walking the type graph, regardless of + * dependencies listed in the package.json. * - * For example, suppose that Webpack is used to generate a distributed bundle for the project `library1`, + * @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: @@ -340,6 +483,35 @@ export interface IConfigFile { */ bundledPackages?: string[]; + /** + * Specifies what type of newlines API Extractor should use when writing output files. + * + * @remarks + * 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". + */ + newlineKind?: 'crlf' | 'lf' | 'os'; + + /** + * Set to true when invoking API Extractor's test harness. + * @remarks + * 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. + */ + testMode?: boolean; + + /** + * Specifies how API Extractor sorts members of an enum when generating the .api.json file. + * + * @remarks + * By default, the output files will be sorted alphabetically, which is "by-name". + * To keep the ordering in the source code, specify "preserve". + * + * @defaultValue `by-name` + */ + enumMemberOrder?: EnumMemberOrder; + /** * {@inheritDoc IConfigCompiler} */ @@ -367,26 +539,8 @@ export interface IConfigFile { */ tsdocMetadata?: IConfigTsdocMetadata; - /** - * Specifies what type of newlines API Extractor should use when writing output files. - * - * @remarks - * 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". - */ - newlineKind?: 'crlf' | 'lf' | 'os'; - /** * {@inheritDoc IExtractorMessagesConfig} */ messages?: IExtractorMessagesConfig; - - /** - * Set to true when invoking API Extractor's test harness. - * @remarks - * 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. - */ - testMode?: boolean; } 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 new file mode 100644 index 00000000000..357e7c1dc00 --- /dev/null +++ b/apps/api-extractor/src/api/test/Extractor-custom-tags.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 { StandardTags } from '@microsoft/tsdoc'; +import * as path from 'node:path'; + +import { ExtractorConfig } from '../ExtractorConfig'; + +const testDataFolder: string = path.join(__dirname, 'test-data'); + +describe('Extractor-custom-tags', () => { + describe('should use a TSDocConfiguration', () => { + 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') + ); + const { tsdocConfiguration } = extractorConfig; + + expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined); + expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined); + expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined); + }); + 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') + ); + const { tsdocConfiguration } = extractorConfig; + const block = tsdocConfiguration.tryGetTagDefinition('@block')!; + const inline = tsdocConfiguration.tryGetTagDefinition('@inline')!; + const modifier = tsdocConfiguration.tryGetTagDefinition('@modifier')!; + + expect(tsdocConfiguration.isTagSupported(block)).toBe(true); + expect(tsdocConfiguration.isTagSupported(inline)).toBe(true); + expect(tsdocConfiguration.isTagSupported(modifier)).toBe(false); + }); + 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') + ); + const { tsdocConfiguration } = extractorConfig; + + expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined); + expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined); + expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined); + + StandardTags.allDefinitions + .concat([ + tsdocConfiguration.tryGetTagDefinition('@betaDocumentation')!, + tsdocConfiguration.tryGetTagDefinition('@internalRemarks')!, + tsdocConfiguration.tryGetTagDefinition('@preapproved')! + ]) + .forEach((tag) => { + expect(tsdocConfiguration.tagDefinitions.includes(tag)); + expect(tsdocConfiguration.supportedTagDefinitions.includes(tag)); + }); + }); + }); +}); diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts new file mode 100644 index 00000000000..e93e1d8b4ed --- /dev/null +++ b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.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 path from 'node:path'; +import { Path } from '@rushstack/node-core-library'; + +import { ExtractorConfig } from '../ExtractorConfig'; + +const testDataFolder: string = path.join(__dirname, 'test-data'); + +function expectEqualPaths(path1: string, path2: string): void { + if (!Path.isEqual(path1, path2)) { + fail('Expected paths to be equal:\npath1: ' + path1 + '\npath2: ' + path2); + } +} + +// Tests for expanding the "" token for the "projectFolder" setting in api-extractor.json +describe(`${ExtractorConfig.name}.${ExtractorConfig.loadFileAndPrepare.name}`, () => { + 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('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('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') + ); + expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup3/src/test/')); + }); +}); 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..c941fd94308 --- /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') + ) + ).toThrowError(expectedErrorMessage); + }); +}); diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup1/api-extractor.json b/apps/api-extractor/src/api/test/test-data/config-lookup1/api-extractor.json new file mode 100644 index 00000000000..abf864f30f5 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/api-extractor.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/config-lookup1/index.d.ts b/apps/api-extractor/src/api/test/test-data/config-lookup1/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup1/package.json b/apps/api-extractor/src/api/test/test-data/config-lookup1/package.json new file mode 100644 index 00000000000..77b62df1952 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/package.json @@ -0,0 +1,4 @@ +{ + "name": "config-lookup1", + "version": "1.0.0" +} 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 new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup2/config/api-extractor.json b/apps/api-extractor/src/api/test/test-data/config-lookup2/config/api-extractor.json new file mode 100644 index 00000000000..abf864f30f5 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/config/api-extractor.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/config-lookup2/index.d.ts b/apps/api-extractor/src/api/test/test-data/config-lookup2/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup2/package.json b/apps/api-extractor/src/api/test/test-data/config-lookup2/package.json new file mode 100644 index 00000000000..09ec7608475 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/package.json @@ -0,0 +1,4 @@ +{ + "name": "config-lookup2", + "version": "1.0.0" +} 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 new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/config/api-extractor.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/config/api-extractor.json new file mode 100644 index 00000000000..abf864f30f5 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/config/api-extractor.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/config-lookup3/index.d.ts b/apps/api-extractor/src/api/test/test-data/config-lookup3/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/package.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/package.json new file mode 100644 index 00000000000..f884361a7b9 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/package.json @@ -0,0 +1,4 @@ +{ + "name": "config-lookup3", + "version": "1.0.0" +} diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/config/api-extractor.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/config/api-extractor.json new file mode 100644 index 00000000000..abf864f30f5 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/config/api-extractor.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/config-lookup3/src/test/index.d.ts b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/index.d.ts @@ -0,0 +1 @@ +// empty file 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 new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} 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 new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/api-extractor.json b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/api-extractor.json new file mode 100644 index 00000000000..abf864f30f5 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/api-extractor.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/custom-tsdoc-tags/index.d.ts b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/index.d.ts new file mode 100644 index 00000000000..8d125dc716d --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/index.d.ts @@ -0,0 +1,7 @@ +/** + * @block + * + * @inline test + * @modifier + */ +interface CustomTagsTestInterface {} diff --git a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/package.json b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/package.json new file mode 100644 index 00000000000..77b62df1952 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/package.json @@ -0,0 +1,4 @@ +{ + "name": "config-lookup1", + "version": "1.0.0" +} 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 new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsdoc.json b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsdoc.json new file mode 100644 index 00000000000..e744a0311bd --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsdoc.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../../../../extends/tsdoc-base.json"], + "tagDefinitions": [ + { + "tagName": "@block", + "syntaxKind": "block" + }, + { + "tagName": "@inline", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@modifier", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@block": true, + "@inline": true, + "@modifier": false + } +} 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 60e04681d43..2c434e32cec 100644 --- a/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts +++ b/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts @@ -1,31 +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 colors from 'colors'; -import * as os from 'os'; +import * as os from 'node:os'; -import { CommandLineParser, CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { InternalError } from '@rushstack/node-core-library'; +import { CommandLineParser, type CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { RunAction } from './RunAction'; import { InitAction } from './InitAction'; export class ApiExtractorCommandLine extends CommandLineParser { - private _debugParameter: CommandLineFlagParameter; + private readonly _debugParameter: CommandLineFlagParameter; public constructor() { super({ toolFilename: 'api-extractor', - toolDescription: 'API Extractor helps you build better TypeScript libraries. It analyzes the main entry' - + ' point for your package, collects the inventory of exported declarations, and then generates three kinds' - + ' of output: an API report file (.api.md) to facilitate reviews, a declaration rollup (.d.ts) to be' - + ' published with your NPM package, and a doc model file (.api.json) to be used with a documentation' - + ' tool such as api-documenter. For details, please visit the web site.' + toolDescription: + 'API Extractor helps you build better TypeScript libraries. It analyzes the main entry' + + ' point for your package, collects the inventory of exported declarations, and then generates three kinds' + + ' of output: an API report file (.api.md) to facilitate reviews, a declaration rollup (.d.ts) to be' + + ' published with your NPM package, and a doc model file (.api.json) to be used with a documentation' + + ' tool such as api-documenter. For details, please visit the web site.' }); this._populateActions(); - } - protected onDefineParameters(): void { // override this._debugParameter = this.defineFlagParameter({ parameterLongName: '--debug', parameterShortName: '-d', @@ -33,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 + colors.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 120918d1a2f..834e2a7660f 100644 --- a/apps/api-extractor/src/cli/InitAction.ts +++ b/apps/api-extractor/src/cli/InitAction.ts @@ -1,49 +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 colors from 'colors'; -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'; -import { ApiExtractorCommandLine } from './ApiExtractorCommandLine'; +import type { ApiExtractorCommandLine } from './ApiExtractorCommandLine'; import { ExtractorConfig } from '../api/ExtractorConfig'; export class InitAction extends CommandLineAction { - public constructor(parser: ApiExtractorCommandLine) { super({ actionName: 'init', summary: `Create an ${ExtractorConfig.FILENAME} config file`, - documentation: `Use this command when setting up API Extractor for a new project. It writes an` - + ` ${ExtractorConfig.FILENAME} config file template with code comments that describe all the settings.` - + ` The file will be written in the current directory.` + documentation: + `Use this command when setting up API Extractor for a new project. It writes an` + + ` ${ExtractorConfig.FILENAME} config file template with code comments that describe all the settings.` + + ` The file will be written in the current directory.` }); } - protected onDefineParameters(): void { // override - // No parameters yet - } - - protected 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); if (FileSystem.exists(outputFilePath)) { - console.log(colors.red('The output file already exists:')); + console.log(Colorize.red('The output file already exists:')); console.log('\n ' + outputFilePath + '\n'); throw new Error('Unable to write output file'); } - console.log(colors.green('Writing file: ') + outputFilePath); + console.log(Colorize.green('Writing file: ') + outputFilePath); FileSystem.copyFile({ sourcePath: inputFilePath, destinationPath: outputFilePath }); - console.log('\nThe recommended location for this file is in the project\'s "config" subfolder,\n' - + 'or else in the top-level folder with package.json.'); - - return Promise.resolve(); + console.log( + '\nThe recommended location for this file is in the project\'s "config" subfolder,\n' + + 'or else in the top-level folder with package.json.' + ); } } diff --git a/apps/api-extractor/src/cli/RunAction.ts b/apps/api-extractor/src/cli/RunAction.ts index 7866391c531..d0e60bb9326 100644 --- a/apps/api-extractor/src/cli/RunAction.ts +++ b/apps/api-extractor/src/cli/RunAction.ts @@ -1,33 +1,34 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as colors from 'colors'; -import * as os from 'os'; -import * as path from 'path'; +import * as os from 'node:os'; +import * as path from 'node:path'; + import { PackageJsonLookup, FileSystem, - IPackageJson + type IPackageJson, + Path, + AlreadyReportedError } from '@rushstack/node-core-library'; - +import { Colorize } from '@rushstack/terminal'; import { CommandLineAction, - CommandLineStringParameter, - CommandLineFlagParameter + type CommandLineStringParameter, + type CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { Extractor, ExtractorResult } from '../api/Extractor'; -import { IConfigFile } from '../api/IConfigFile'; - -import { ApiExtractorCommandLine } from './ApiExtractorCommandLine'; -import { ExtractorConfig } from '../api/ExtractorConfig'; +import { Extractor, type ExtractorResult } from '../api/Extractor'; +import type { ApiExtractorCommandLine } from './ApiExtractorCommandLine'; +import { ExtractorConfig, type IExtractorConfigPrepareOptions } from '../api/ExtractorConfig'; export class RunAction extends CommandLineAction { - private _configFileParameter: CommandLineStringParameter; - private _localParameter: CommandLineFlagParameter; - private _verboseParameter: CommandLineFlagParameter; - private _diagnosticsParameter: CommandLineFlagParameter; - private _typescriptCompilerFolder: CommandLineStringParameter; + private readonly _configFileParameter: CommandLineStringParameter; + private readonly _localFlag: CommandLineFlagParameter; + private readonly _verboseFlag: CommandLineFlagParameter; + private readonly _diagnosticsParameter: CommandLineFlagParameter; + private readonly _typescriptCompilerFolderParameter: CommandLineStringParameter; + private readonly _printApiReportDiffFlag: CommandLineFlagParameter; public constructor(parser: ApiExtractorCommandLine) { super({ @@ -35,9 +36,7 @@ export class RunAction extends CommandLineAction { summary: 'Invoke API Extractor on a project', documentation: 'Invoke API Extractor on a project' }); - } - protected onDefineParameters(): void { // override this._configFileParameter = this.defineStringParameter({ parameterLongName: '--config', parameterShortName: '-c', @@ -45,16 +44,17 @@ 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: 'Indicates that API Extractor is running as part of a local build,' - + ' e.g. on a developer\'s machine. This disables certain validation that would' - + ' normally be performed for a ship/production build. For example, the *.api.md' - + ' report file is automatically copied in a local build.' + description: + 'Indicates that API Extractor is running as part of a local build,' + + " e.g. on a developer's machine. This disables certain validation that would" + + ' normally be performed for a ship/production build. For example, the *.api.md' + + ' 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.' @@ -62,26 +62,36 @@ export class RunAction extends CommandLineAction { this._diagnosticsParameter = this.defineFlagParameter({ parameterLongName: '--diagnostics', - description: 'Show diagnostic messages used for troubleshooting problems with API Extractor.' - + ' This flag also enables the "--verbose" flag.' + description: + 'Show diagnostic messages used for troubleshooting problems with API Extractor.' + + ' This flag also enables the "--verbose" flag.' }); - this._typescriptCompilerFolder = this.defineStringParameter({ + this._typescriptCompilerFolderParameter = this.defineStringParameter({ parameterLongName: '--typescript-compiler-folder', argumentName: 'PATH', - description: 'API Extractor uses its own TypeScript compiler engine to analyze your project. If your project' - + ' is built with a significantly different TypeScript version, sometimes API Extractor may report compilation' - + ' errors due to differences in the system typings (e.g. lib.dom.d.ts). You can use the' - + ' "--typescriptCompilerFolder" option to specify the folder path where you installed the TypeScript package,' - + ' and API Extractor\'s compiler will use those system typings instead.' + description: + 'API Extractor uses its own TypeScript compiler engine to analyze your project. If your project' + + ' is built with a significantly different TypeScript version, sometimes API Extractor may report compilation' + + ' errors due to differences in the system typings (e.g. lib.dom.d.ts). You can use the' + + ' "--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 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); @@ -92,82 +102,65 @@ 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` - + ' compiler package.' + `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.` ); } } + let extractorConfig: ExtractorConfig; + if (this._configFileParameter.value) { configFilename = path.normalize(this._configFileParameter.value); if (!FileSystem.exists(configFilename)) { throw new Error('Config file not found: ' + this._configFileParameter.value); } + + extractorConfig = ExtractorConfig.loadFileAndPrepare(configFilename); } else { - // Otherwise, figure out which project we're in and look for the config file - // at the project root - const packageFolder: string | undefined = lookup.tryGetPackageFolderFor('.'); - - // If there is no package, then try the current directory - const baseFolder: string = packageFolder ? packageFolder : process.cwd(); - - // First try the standard "config" subfolder: - configFilename = path.join(baseFolder, 'config', ExtractorConfig.FILENAME); - if (FileSystem.exists(configFilename)) { - if (FileSystem.exists(path.join(baseFolder, ExtractorConfig.FILENAME))) { - throw new Error(`Found conflicting ${ExtractorConfig.FILENAME} files in "." and "./config" folders`); - } - } else { - // Otherwise try the top-level folder - configFilename = path.join(baseFolder, ExtractorConfig.FILENAME); + const prepareOptions: IExtractorConfigPrepareOptions | undefined = ExtractorConfig.tryLoadForFolder({ + startingFolder: '.' + }); - if (!FileSystem.exists(configFilename)) { - throw new Error(`Unable to find an ${ExtractorConfig.FILENAME} file`); - } + if (!prepareOptions || !prepareOptions.configObjectFullPath) { + throw new Error(`Unable to find an ${ExtractorConfig.FILENAME} file`); } - console.log(`Using configuration from ${configFilename}` + os.EOL); - } + const configObjectShortPath: string = Path.formatConcisely({ + pathToConvert: prepareOptions.configObjectFullPath, + baseFolder: process.cwd() + }); + console.log(`Using configuration from ${configObjectShortPath}`); - const configObjectFullPath: string = path.resolve(configFilename); - const configObject: IConfigFile = ExtractorConfig.loadFile(configObjectFullPath); + extractorConfig = ExtractorConfig.prepare(prepareOptions); + } - const extractorConfig: ExtractorConfig = ExtractorConfig.prepare({ - configObject: configObject, - configObjectFullPath: configObjectFullPath, - packageJsonFullPath: lookup.tryGetPackageJsonFilePathFor(configObjectFullPath) + const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { + localBuild: this._localFlag.value, + showVerboseMessages: this._verboseFlag.value, + showDiagnostics: this._diagnosticsParameter.value, + typescriptCompilerFolder: typescriptCompilerFolder, + printApiReportDiff: this._printApiReportDiffFlag.value }); - const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, - { - localBuild: this._localParameter.value, - showVerboseMessages: this._verboseParameter.value, - showDiagnostics: this._diagnosticsParameter.value, - typescriptCompilerFolder: typescriptCompilerFolder - } - ); - if (extractorResult.succeeded) { console.log(os.EOL + 'API Extractor completed successfully'); } else { - process.exitCode = 1; - if (extractorResult.errorCount > 0) { - console.log(os.EOL + colors.red('API Extractor completed with errors')); + console.log(os.EOL + Colorize.red('API Extractor completed with errors')); } else { - console.log(os.EOL + colors.yellow('API Extractor completed with warnings')); + console.log(os.EOL + Colorize.yellow('API Extractor completed with warnings')); } + throw new AlreadyReportedError(); } - - return Promise.resolve(); } } diff --git a/apps/api-extractor/src/collector/ApiItemMetadata.ts b/apps/api-extractor/src/collector/ApiItemMetadata.ts index 738e58619dc..4448f416b63 100644 --- a/apps/api-extractor/src/collector/ApiItemMetadata.ts +++ b/apps/api-extractor/src/collector/ApiItemMetadata.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 tsdoc from '@microsoft/tsdoc'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; +import type * as tsdoc from '@microsoft/tsdoc'; +import type { ReleaseTag } from '@microsoft/api-extractor-model'; + import { VisitorState } from './VisitorState'; /** @@ -75,8 +76,20 @@ export class ApiItemMetadata { */ public tsdocComment: tsdoc.DocComment | undefined; - // Assigned by DocCommentEnhancer - public needsDocumentation: boolean = true; + /** + * Tracks whether or not the associated API item is known to be missing sufficient documentation. + * + * @remarks + * + * An "undocumented" item is one whose TSDoc comment which either does not contain a summary comment block, or + * has an `@inheritDoc` tag that resolves to another "undocumented" API member. + * + * If there is any ambiguity (e.g. if an `@inheritDoc` comment points to an external API member, whose documentation, + * we can't parse), "undocumented" will be `false`. + * + * @remarks Assigned by {@link DocCommentEnhancer}. + */ + public undocumented: boolean = true; public docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited; diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index 343e55a665b..b2e872565f6 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -2,34 +2,38 @@ // 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, - InternalError + InternalError, + type INodePackageJson, + PackageName } from '@rushstack/node-core-library'; -import { - ReleaseTag, - AedocDefinitions -} from '@microsoft/api-extractor-model'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; - import { CollectorEntity } from './CollectorEntity'; -import { AstSymbolTable, AstEntity } from '../analyzer/AstSymbolTable'; -import { AstModule, AstModuleExportInfo } from '../analyzer/AstModule'; +import { AstSymbolTable } from '../analyzer/AstSymbolTable'; +import type { AstEntity } from '../analyzer/AstEntity'; +import type { AstModule, IAstModuleExportInfo } from '../analyzer/AstModule'; import { AstSymbol } from '../analyzer/AstSymbol'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; +import type { AstDeclaration } from '../analyzer/AstDeclaration'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; import { WorkingPackage } from './WorkingPackage'; import { PackageDocComment } from '../aedoc/PackageDocComment'; -import { DeclarationMetadata, InternalDeclarationMetadata } from './DeclarationMetadata'; -import { ApiItemMetadata, IApiItemMetadataOptions } from './ApiItemMetadata'; +import { type DeclarationMetadata, InternalDeclarationMetadata } from './DeclarationMetadata'; +import { ApiItemMetadata, type IApiItemMetadataOptions } from './ApiItemMetadata'; import { SymbolMetadata } from './SymbolMetadata'; -import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; -import { MessageRouter } from './MessageRouter'; +import { TypeScriptInternals, type IGlobalVariableAnalyzer } from '../analyzer/TypeScriptInternals'; +import type { MessageRouter } from './MessageRouter'; import { AstReferenceResolver } from '../analyzer/AstReferenceResolver'; import { ExtractorConfig } from '../api/ExtractorConfig'; +import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; +import { AstImport } from '../analyzer/AstImport'; +import type { SourceMapper } from './SourceMapper'; /** * Options for Collector constructor. @@ -48,6 +52,8 @@ export interface ICollectorOptions { messageRouter: MessageRouter; extractorConfig: ExtractorConfig; + + sourceMapper: SourceMapper; } /** @@ -59,6 +65,7 @@ export interface ICollectorOptions { export class Collector { public readonly program: ts.Program; public readonly typeChecker: ts.TypeChecker; + public readonly globalVariableAnalyzer: IGlobalVariableAnalyzer; public readonly astSymbolTable: AstSymbolTable; public readonly astReferenceResolver: AstReferenceResolver; @@ -69,6 +76,13 @@ export class Collector { public readonly extractorConfig: ExtractorConfig; + public readonly sourceMapper: SourceMapper; + + /** + * The `ExtractorConfig.bundledPackages` names in a set. + */ + public readonly bundledPackageNames: ReadonlySet; + private readonly _program: ts.Program; private readonly _tsdocParser: tsdoc.TSDocParser; @@ -76,7 +90,11 @@ export class Collector { private _astEntryPoint: AstModule | undefined; private readonly _entities: CollectorEntity[] = []; - private readonly _entitiesByAstEntity: Map = new Map(); + private readonly _entitiesByAstEntity: Map = new Map< + AstEntity, + CollectorEntity + >(); + private readonly _entitiesBySymbol: Map = new Map(); private readonly _starExportedExternalModulePaths: string[] = []; @@ -91,9 +109,11 @@ export class Collector { this._program = options.program; this.extractorConfig = options.extractorConfig; + this.sourceMapper = options.sourceMapper; const entryPointSourceFile: ts.SourceFile | undefined = options.program.getSourceFile( - this.extractorConfig.mainEntryPointFilePath); + this.extractorConfig.mainEntryPointFilePath + ); if (!entryPointSourceFile) { throw new Error('Unable to load file: ' + this.extractorConfig.mainEntryPointFilePath); @@ -115,19 +135,78 @@ export class Collector { this.program = options.program; this.typeChecker = options.program.getTypeChecker(); - - this._tsdocParser = new tsdoc.TSDocParser(AedocDefinitions.tsdocConfiguration); - - const bundledPackageNames: Set = new Set(this.extractorConfig.bundledPackages); - - this.astSymbolTable = new AstSymbolTable(this.program, this.typeChecker, this.packageJsonLookup, - bundledPackageNames, this.messageRouter); + 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.extractorConfig.bundledPackages, + this.extractorConfig.packageJson + ); + + this.astSymbolTable = new AstSymbolTable( + this.program, + this.typeChecker, + this.packageJsonLookup, + this.bundledPackageNames, + this.messageRouter + ); this.astReferenceResolver = new AstReferenceResolver(this); 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: * * ``` @@ -176,6 +255,8 @@ export class Collector { this.messageRouter.addCompilerDiagnostic(diagnostic); } + const sourceFiles: readonly ts.SourceFile[] = this.program.getSourceFiles(); + if (this.messageRouter.showDiagnostics) { this.messageRouter.logDiagnosticHeader('Root filenames'); for (const fileName of this.program.getRootFileNames()) { @@ -184,66 +265,107 @@ export class Collector { this.messageRouter.logDiagnosticFooter(); this.messageRouter.logDiagnosticHeader('Files analyzed by compiler'); - for (const sourceFile of this.program.getSourceFiles()) { + for (const sourceFile of sourceFiles) { this.messageRouter.logDiagnostic(sourceFile.fileName); } this.messageRouter.logDiagnosticFooter(); } + // We can throw this error earlier in CompilerState.ts, but intentionally wait until after we've logged the + // associated diagnostic message above to make debugging easier for developers. + // Typically there will be many such files -- to avoid too much noise, only report the first one. + const badSourceFile: ts.SourceFile | undefined = sourceFiles.find( + ({ fileName }) => !ExtractorConfig.hasDtsFileExtension(fileName) + ); + if (badSourceFile) { + this.messageRouter.addAnalyzerIssueForPosition( + ExtractorMessageId.WrongInputFileType, + 'Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension. ' + + 'Troubleshooting tips: https://api-extractor.com/link/dts-error', + badSourceFile, + 0 + ); + } + // Build the entry point const entryPointSourceFile: ts.SourceFile = this.workingPackage.entryPointSourceFile; - const astEntryPoint: AstModule = this.astSymbolTable.fetchAstModuleFromWorkingPackage( - entryPointSourceFile); + const astEntryPoint: AstModule = + this.astSymbolTable.fetchAstModuleFromWorkingPackage(entryPointSourceFile); this._astEntryPoint = astEntryPoint; const packageDocCommentTextRange: ts.TextRange | undefined = PackageDocComment.tryFindInSourceFile( - entryPointSourceFile, this); + entryPointSourceFile, + this + ); if (packageDocCommentTextRange) { - const range: tsdoc.TextRange = tsdoc.TextRange.fromStringRange(entryPointSourceFile.text, - packageDocCommentTextRange.pos, packageDocCommentTextRange.end); + const range: tsdoc.TextRange = tsdoc.TextRange.fromStringRange( + entryPointSourceFile.text, + packageDocCommentTextRange.pos, + packageDocCommentTextRange.end + ); this.workingPackage.tsdocParserContext = this._tsdocParser.parseRange(range); - this.messageRouter.addTsdocMessages(this.workingPackage.tsdocParserContext, - entryPointSourceFile); + this.messageRouter.addTsdocMessages(this.workingPackage.tsdocParserContext, entryPointSourceFile); this.workingPackage.tsdocComment = this.workingPackage.tsdocParserContext!.docComment; } - const exportedAstEntities: AstEntity[] = []; - - // Create a CollectorEntity for each top-level export + const { exportedLocalEntities, starExportedExternalModules, visitedAstModules }: IAstModuleExportInfo = + this.astSymbolTable.fetchAstModuleExportInfo(astEntryPoint); - const astModuleExportInfo: AstModuleExportInfo = this.astSymbolTable.fetchAstModuleExportInfo(astEntryPoint); - for (const [exportName, astEntity] of astModuleExportInfo.exportedLocalEntities) { + // Create a CollectorEntity for each top-level export. + const processedAstEntities: AstEntity[] = []; + for (const [exportName, astEntity] of exportedLocalEntities) { this._createCollectorEntity(astEntity, exportName); - - exportedAstEntities.push(astEntity); + processedAstEntities.push(astEntity); } - // Create a CollectorEntity for each indirectly referenced export. - // Note that we do this *after* the above loop, so that references to exported AstSymbols - // are encountered first as exports. - const alreadySeenAstSymbols: Set = new Set(); - for (const exportedAstEntity of exportedAstEntities) { - this._createEntityForIndirectReferences(exportedAstEntity, alreadySeenAstSymbols); + // Recursively create the remaining CollectorEntities after the top-level entities + // have been processed. + const alreadySeenAstEntities: Set = new Set(); + for (const astEntity of processedAstEntities) { + this._recursivelyCreateEntities(astEntity, alreadySeenAstEntities); + if (astEntity instanceof AstSymbol) { + this.fetchSymbolMetadata(astEntity); + } + } - if (exportedAstEntity instanceof AstSymbol) { - this.fetchSymbolMetadata(exportedAstEntity); + // 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); } } - Sort.sortBy(this._entities, x => x.getSortKey()); + Sort.sortBy(this._entities, (x) => x.getSortKey()); Sort.sortSet(this._dtsTypeReferenceDirectives); Sort.sortSet(this._dtsLibReferenceDirectives); this._starExportedExternalModulePaths.sort(); @@ -255,14 +377,22 @@ export class Collector { * @remarks * Throws an Error if the ts.Identifier is not part of node tree that was analyzed. */ - public tryGetEntityForIdentifierNode(identifier: ts.Identifier): CollectorEntity | undefined { - const astEntity: AstEntity | undefined = this.astSymbolTable.tryGetEntityForIdentifierNode(identifier); + public tryGetEntityForNode(identifier: ts.Identifier | ts.ImportTypeNode): CollectorEntity | undefined { + const astEntity: AstEntity | undefined = this.astSymbolTable.tryGetEntityForNode(identifier); if (astEntity) { return this._entitiesByAstEntity.get(astEntity); } return undefined; } + /** + * For a given analyzed ts.Symbol, return the CollectorEntity that it refers to. Returns undefined if it + * doesn't refer to anything interesting. + */ + public tryGetEntityForSymbol(symbol: ts.Symbol): CollectorEntity | undefined { + return this._entitiesBySymbol.get(symbol); + } + /** * Returns the associated `CollectorEntity` for the given `astEntity`, if one was created during analysis. */ @@ -297,8 +427,10 @@ export class Collector { if (astEntity instanceof AstSymbol) { return this.fetchSymbolMetadata(astEntity); } - if (astEntity.astSymbol) { // astImport - return this.fetchSymbolMetadata(astEntity.astSymbol); + if (astEntity instanceof AstImport) { + if (astEntity.astSymbol) { + return this.fetchSymbolMetadata(astEntity.astSymbol); + } } return undefined; } @@ -327,7 +459,9 @@ export class Collector { * initially ignoring the underscore prefix, while still deterministically comparing it. * The star is used as a delimiter because it is not a legal identifier character. */ - public static getSortKeyIgnoringUnderscore(identifier: string): string { + public static getSortKeyIgnoringUnderscore(identifier: string | undefined): string { + if (!identifier) return ''; + let parts: string[]; if (identifier[0] === '_') { @@ -374,49 +508,76 @@ export class Collector { return overloadIndex; } - private _createCollectorEntity(astEntity: AstEntity, exportedName: string | undefined): void { + private _createCollectorEntity( + astEntity: AstEntity, + exportName?: string, + parent?: CollectorEntity + ): CollectorEntity { let entity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astEntity); if (!entity) { entity = new CollectorEntity(astEntity); this._entitiesByAstEntity.set(astEntity, entity); - this._entities.push(entity); - if (astEntity instanceof AstSymbol) { - this._collectReferenceDirectives(astEntity); + this._entitiesBySymbol.set(astEntity.followedSymbol, entity); + } else if (astEntity instanceof AstNamespaceImport) { + this._entitiesBySymbol.set(astEntity.symbol, entity); } + this._entities.push(entity); + this._collectReferenceDirectives(astEntity); } - if (exportedName) { - entity.addExportName(exportedName); + if (exportName) { + if (parent) { + entity.addLocalExportName(exportName, parent); + } else { + entity.addExportName(exportName); + } } + + return entity; } - private _createEntityForIndirectReferences(astEntity: AstEntity, alreadySeenAstEntities: Set): void { - if (alreadySeenAstEntities.has(astEntity)) { - return; - } + private _recursivelyCreateEntities(astEntity: AstEntity, alreadySeenAstEntities: Set): void { + if (alreadySeenAstEntities.has(astEntity)) return; alreadySeenAstEntities.add(astEntity); if (astEntity instanceof AstSymbol) { astEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { for (const referencedAstEntity of astDeclaration.referencedAstEntities) { if (referencedAstEntity instanceof AstSymbol) { - // We only create collector entities for root-level symbols. - // For example, if a symbols is nested inside a namespace, only the root-level namespace - // get a collector entity + // We only create collector entities for root-level symbols. For example, if a symbol is + // nested inside a namespace, only the namespace gets a collector entity. Note that this + // is not true for AstNamespaceImports below. if (referencedAstEntity.parentAstSymbol === undefined) { - this._createCollectorEntity(referencedAstEntity, undefined); + this._createCollectorEntity(referencedAstEntity); } } else { - this._createCollectorEntity(referencedAstEntity, undefined); + this._createCollectorEntity(referencedAstEntity); } - this._createEntityForIndirectReferences(referencedAstEntity, alreadySeenAstEntities); + this._recursivelyCreateEntities(referencedAstEntity, alreadySeenAstEntities); } }); } + + if (astEntity instanceof AstNamespaceImport) { + 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. + throw new InternalError( + `Failed to get CollectorEntity for AstNamespaceImport with namespace name "${astEntity.namespaceName}"` + ); + } + + for (const [localExportName, localAstEntity] of astModuleExportInfo.exportedLocalEntities) { + // Create a CollectorEntity for each local export within an AstNamespaceImport entity. + this._createCollectorEntity(localAstEntity, localExportName, parentEntity); + this._recursivelyCreateEntities(localAstEntity, alreadySeenAstEntities); + } + } } /** @@ -455,36 +616,36 @@ export class Collector { } } - // Next, add in the global names - const globalNames: Set = new Set(); - this._collectGlobalNames(globalNames); - - for (const globalName of globalNames) { - // Note that globalName may conflict with an exported name. - // We'll check for this conflict below. - usedNames.add(globalName); - } - // Ensure that each entity has a unique nameForEmit for (const entity of this._entities) { - // What name would we ideally want to emit it as? let idealNameForEmit: string; // If this entity is exported exactly once, then we prefer the exported name - if (entity.singleExportName !== undefined && entity.singleExportName !== ts.InternalSymbolName.Default) { + if ( + entity.singleExportName !== undefined && + entity.singleExportName !== ts.InternalSymbolName.Default + ) { idealNameForEmit = entity.singleExportName; } else { // otherwise use the local name idealNameForEmit = entity.astEntity.localName; } + if (idealNameForEmit.includes('.')) { + // For an ImportType with a namespace chain, only the top namespace is imported. + idealNameForEmit = idealNameForEmit.split('.')[0]; + } + // If the idealNameForEmit happens to be the same as one of the exports, then we're safe to use that... if (entity.exportNames.has(idealNameForEmit)) { // ...except that if it conflicts with a global name, then the global name wins - if (!globalNames.has(idealNameForEmit)) { - entity.nameForEmit = idealNameForEmit; - continue; + if (!this.globalVariableAnalyzer.hasGlobalName(idealNameForEmit)) { + // ...also avoid "default" which can interfere with "export { default } from 'some-module;'" + if (idealNameForEmit !== 'default') { + entity.nameForEmit = idealNameForEmit; + continue; + } } } @@ -492,8 +653,12 @@ export class Collector { let suffix: number = 1; let nameForEmit: string = idealNameForEmit; - // Choose a name that doesn't conflict with usedNames - while (usedNames.has(nameForEmit)) { + // Choose a name that doesn't conflict with usedNames or a global name + while ( + nameForEmit === 'default' || + usedNames.has(nameForEmit) || + this.globalVariableAnalyzer.hasGlobalName(nameForEmit) + ) { nameForEmit = `${idealNameForEmit}_${++suffix}`; } entity.nameForEmit = nameForEmit; @@ -501,73 +666,6 @@ export class Collector { } } - /** - * Adds global names to the usedNames set, to prevent API Extractor from emitting names that conflict with - * a global name. - */ - private _collectGlobalNames(usedNames: Set): void { - // As a temporary workaround, this a short list of names that appear in typical projects. - // The full solution is tracked by this issue: - // https://github.com/microsoft/rushstack/issues/1095 - const globalNames: string[] = [ - 'Array', - 'ArrayConstructor', - 'Console', - 'Date', - 'DateConstructor', - 'Error', - 'ErrorConstructor', - 'Float32Array', - 'Float32ArrayConstructor', - 'Float64Array', - 'Float64ArrayConstructor', - 'IArguments', - 'Int16Array', - 'Int16ArrayConstructor', - 'Int32Array', - 'Int32ArrayConstructor', - 'Int8Array', - 'Int8ArrayConstructor', - 'Iterable', - 'IterableIterator', - 'Iterator', - 'IteratorResult', - 'Map', - 'MapConstructor', - 'Promise', - 'PromiseConstructor', - 'ReadonlyArray', - 'ReadonlyMap', - 'ReadonlySet', - 'Set', - 'SetConstructor', - 'String', - 'Symbol', - 'SymbolConstructor', - 'Uint16Array', - 'Uint16ArrayConstructor', - 'Uint32Array', - 'Uint32ArrayConstructor', - 'Uint8Array', - 'Uint8ArrayConstructor', - 'Uint8ClampedArray', - 'Uint8ClampedArrayConstructor', - 'WeakMap', - 'WeakMapConstructor', - 'WeakSet', - 'WeakSetConstructor', - 'clearInterval', - 'clearTimeout', - 'console', - 'setInterval', - 'setTimeout', - 'undefined' - ]; - for (const globalName of globalNames) { - usedNames.add(globalName); - } - } - private _fetchSymbolMetadata(astSymbol: AstSymbol): void { if (astSymbol.symbolMetadata) { return; @@ -611,7 +709,9 @@ export class Collector { // Initialize DeclarationMetadata for each declaration for (const astDeclaration of astSymbol.astDeclarations) { if (astDeclaration.declarationMetadata) { - throw new InternalError('AstDeclaration.declarationMetadata is not expected to have been initialized yet'); + throw new InternalError( + 'AstDeclaration.declarationMetadata is not expected to have been initialized yet' + ); } const metadata: InternalDeclarationMetadata = new InternalDeclarationMetadata(); @@ -622,7 +722,6 @@ export class Collector { // Detect ancillary declarations for (const astDeclaration of astSymbol.astDeclarations) { - // For a getter/setter pair, make the setter ancillary to the getter if (astDeclaration.declaration.kind === ts.SyntaxKind.SetAccessor) { let foundGetter: boolean = false; @@ -639,38 +738,51 @@ export class Collector { this.messageRouter.addAnalyzerIssue( ExtractorMessageId.MissingGetter, `The property "${astDeclaration.astSymbol.localName}" has a setter but no getter.`, - astDeclaration); + astDeclaration + ); } } - } } - private _addAncillaryDeclaration(mainAstDeclaration: AstDeclaration, ancillaryAstDeclaration: AstDeclaration): void { - const mainMetadata: InternalDeclarationMetadata = mainAstDeclaration.declarationMetadata as InternalDeclarationMetadata; - const ancillaryMetadata: InternalDeclarationMetadata = ancillaryAstDeclaration.declarationMetadata as InternalDeclarationMetadata; + private _addAncillaryDeclaration( + mainAstDeclaration: AstDeclaration, + ancillaryAstDeclaration: AstDeclaration + ): void { + const mainMetadata: InternalDeclarationMetadata = + mainAstDeclaration.declarationMetadata as InternalDeclarationMetadata; + const ancillaryMetadata: InternalDeclarationMetadata = + ancillaryAstDeclaration.declarationMetadata as InternalDeclarationMetadata; if (mainMetadata.ancillaryDeclarations.indexOf(ancillaryAstDeclaration) >= 0) { - return; // already added + return; // already added } if (mainAstDeclaration.astSymbol !== ancillaryAstDeclaration.astSymbol) { - throw new InternalError('Invalid call to _addAncillaryDeclaration() because declarations do not' - + ' belong to the same symbol'); + throw new InternalError( + 'Invalid call to _addAncillaryDeclaration() because declarations do not' + + ' belong to the same symbol' + ); } if (mainMetadata.isAncillary) { - throw new InternalError('Invalid call to _addAncillaryDeclaration() because the target is ancillary itself'); + throw new InternalError( + 'Invalid call to _addAncillaryDeclaration() because the target is ancillary itself' + ); } if (ancillaryMetadata.isAncillary) { - throw new InternalError('Invalid call to _addAncillaryDeclaration() because source is already ancillary' - + ' to another declaration'); + throw new InternalError( + 'Invalid call to _addAncillaryDeclaration() because source is already ancillary' + + ' to another declaration' + ); } if (mainAstDeclaration.apiItemMetadata || ancillaryAstDeclaration.apiItemMetadata) { - throw new InternalError('Invalid call to _addAncillaryDeclaration() because the API item metadata' - + ' has already been constructed'); + throw new InternalError( + 'Invalid call to _addAncillaryDeclaration() because the API item metadata' + + ' has already been constructed' + ); } ancillaryMetadata.isAncillary = true; @@ -678,15 +790,17 @@ export class Collector { } private _calculateApiItemMetadata(astDeclaration: AstDeclaration): void { - const declarationMetadata: InternalDeclarationMetadata = astDeclaration.declarationMetadata as InternalDeclarationMetadata; + const declarationMetadata: InternalDeclarationMetadata = + astDeclaration.declarationMetadata as InternalDeclarationMetadata; if (declarationMetadata.isAncillary) { - if (astDeclaration.declaration.kind === ts.SyntaxKind.SetAccessor) { if (declarationMetadata.tsdocParserContext) { - this.messageRouter.addAnalyzerIssue(ExtractorMessageId.SetterWithDocs, - `The doc comment for the property "${astDeclaration.astSymbol.localName}"` - + ` must appear on the getter, not the setter.`, - astDeclaration); + this.messageRouter.addAnalyzerIssue( + ExtractorMessageId.SetterWithDocs, + `The doc comment for the property "${astDeclaration.astSymbol.localName}"` + + ` must appear on the getter, not the setter.`, + astDeclaration + ); } } @@ -739,11 +853,13 @@ export class Collector { } if (extraReleaseTags) { - if (!astDeclaration.astSymbol.isExternal) { // for now, don't report errors for external code + if (!astDeclaration.astSymbol.isExternal) { + // for now, don't report errors for external code this.messageRouter.addAnalyzerIssue( ExtractorMessageId.ExtraReleaseTag, 'The doc comment should not contain more than one release tag', - astDeclaration); + astDeclaration + ); } } @@ -753,8 +869,10 @@ export class Collector { options.isOverride = modifierTagSet.isOverride(); options.isSealed = modifierTagSet.isSealed(); options.isVirtual = modifierTagSet.isVirtual(); + const preapprovedTag: tsdoc.TSDocTagDefinition | void = + this.extractorConfig.tsdocConfiguration.tryGetTagDefinition('@preapproved'); - if (modifierTagSet.hasTag(AedocDefinitions.preapprovedTag)) { + if (preapprovedTag && modifierTagSet.hasTag(preapprovedTag)) { // This feature only makes sense for potentially big declarations. switch (astDeclaration.declaration.kind) { case ts.SyntaxKind.ClassDeclaration: @@ -766,8 +884,8 @@ export class Collector { } else { this.messageRouter.addAnalyzerIssue( ExtractorMessageId.PreapprovedBadReleaseTag, - `The @preapproved tag cannot be applied to "${astDeclaration.astSymbol.localName}"` - + ` without an @internal release tag`, + `The @preapproved tag cannot be applied to "${astDeclaration.astSymbol.localName}"` + + ` without an @internal release tag`, astDeclaration ); } @@ -775,8 +893,8 @@ export class Collector { default: this.messageRouter.addAnalyzerIssue( ExtractorMessageId.PreapprovedUnsupportedType, - `The @preapproved tag cannot be applied to "${astDeclaration.astSymbol.localName}"` - + ` because it is not a supported declaration type`, + `The @preapproved tag cannot be applied to "${astDeclaration.astSymbol.localName}"` + + ` because it is not a supported declaration type`, astDeclaration ); break; @@ -787,29 +905,37 @@ export class Collector { // This needs to be set regardless of whether or not a parserContext exists if (astDeclaration.parent) { const parentApiItemMetadata: ApiItemMetadata = this.fetchApiItemMetadata(astDeclaration.parent); - options.effectiveReleaseTag = options.declaredReleaseTag === ReleaseTag.None - ? parentApiItemMetadata.effectiveReleaseTag - : options.declaredReleaseTag; + options.effectiveReleaseTag = + options.declaredReleaseTag === ReleaseTag.None + ? parentApiItemMetadata.effectiveReleaseTag + : options.declaredReleaseTag; - options.releaseTagSameAsParent = + options.releaseTagSameAsParent = parentApiItemMetadata.effectiveReleaseTag === options.effectiveReleaseTag; } else { options.effectiveReleaseTag = options.declaredReleaseTag; } if (options.effectiveReleaseTag === ReleaseTag.None) { - if (!astDeclaration.astSymbol.isExternal) { // for now, don't report errors for external code - // Don't report missing release tags for forgotten exports + if (!astDeclaration.astSymbol.isExternal) { + // for now, don't report errors for external code + // Don't report missing release tags for forgotten exports (unless we're including forgotten exports + // in either the API report or doc model). const astSymbol: AstSymbol = astDeclaration.astSymbol; const entity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astSymbol.rootAstSymbol); - if (entity && entity.exported) { + if ( + entity && + (entity.consumable || + this.extractorConfig.apiReportIncludeForgottenExports || + this.extractorConfig.docModelIncludeForgottenExports) + ) { // We also don't report errors for the default export of an entry point, since its doc comment // isn't easy to obtain from the .d.ts file if (astSymbol.rootAstSymbol.localName !== '_default') { this.messageRouter.addAnalyzerIssue( ExtractorMessageId.MissingReleaseTag, - `"${entity.astEntity.localName}" is exported by the package, but it is missing ` - + `a release tag (@alpha, @beta, @public, or @internal)`, + `"${entity.astEntity.localName}" is part of the package's API, but it is missing ` + + `a release tag (@alpha, @beta, @public, or @internal)`, astSymbol ); } @@ -848,8 +974,10 @@ export class Collector { // // But _getReleaseTagForDeclaration() still receives a node corresponding to "x", so we need to walk upwards // and find the containing statement in order for getJSDocCommentRanges() to read the comment that we expect. - const statement: ts.VariableStatement | undefined = TypeScriptHelpers.findFirstParent(declaration, - ts.SyntaxKind.VariableStatement) as ts.VariableStatement | undefined; + const statement: ts.VariableStatement | undefined = TypeScriptHelpers.findFirstParent( + declaration, + ts.SyntaxKind.VariableStatement + ) as ts.VariableStatement | undefined; if (statement !== undefined) { // For a compound declaration, fall back to looking for C instead of A if (statement.declarationList.declarations.length === 1) { @@ -859,7 +987,8 @@ export class Collector { } const sourceFileText: string = declaration.getSourceFile().text; - const ranges: ts.CommentRange[] = TypeScriptInternals.getJSDocCommentRanges(nodeForComment, sourceFileText) || []; + const ranges: ts.CommentRange[] = + TypeScriptInternals.getJSDocCommentRanges(nodeForComment, sourceFileText) || []; if (ranges.length === 0) { return undefined; @@ -869,8 +998,11 @@ export class Collector { // the last one preceding it const range: ts.TextRange = ranges[ranges.length - 1]; - const tsdocTextRange: tsdoc.TextRange = tsdoc.TextRange.fromStringRange(sourceFileText, - range.pos, range.end); + const tsdocTextRange: tsdoc.TextRange = tsdoc.TextRange.fromStringRange( + sourceFileText, + range.pos, + range.end + ); const parserContext: tsdoc.ParserContext = this._tsdocParser.parseRange(tsdocTextRange); @@ -883,27 +1015,83 @@ export class Collector { return parserContext; } - private _collectReferenceDirectives(astSymbol: AstSymbol): void { + 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, false); + } + + if (astEntity instanceof AstNamespaceImport) { + const sourceFiles: ts.SourceFile[] = [astEntity.astModule.sourceFile]; + return this._collectReferenceDirectivesFromSourceFiles(sourceFiles, false); + } + } + + private _collectReferenceDirectivesFromSourceFiles( + sourceFiles: Iterable, + onlyIncludeExplicitlyPreserved: boolean + ): void { const seenFilenames: Set = new Set(); - for (const astDeclaration of astSymbol.astDeclarations) { - const sourceFile: ts.SourceFile = astDeclaration.declaration.getSourceFile(); - 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); - this._dtsTypeReferenceDirectives.add(name); + for (const sourceFile of sourceFiles) { + 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 + ); + if (name) { + this._dtsTypeReferenceDirectives.add(name); + } } - for (const libReferenceDirective of sourceFile.libReferenceDirectives) { - const name: string = sourceFile.text.substring(libReferenceDirective.pos, libReferenceDirective.end); - this._dtsLibReferenceDirectives.add(name); + for (const libReferenceDirective of libReferenceDirectives) { + const reference: string | undefined = this._getReferenceDirectiveFromSourceFile( + sourceFileText, + libReferenceDirective, + onlyIncludeExplicitlyPreserved + ); + 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; + } + } } diff --git a/apps/api-extractor/src/collector/CollectorEntity.ts b/apps/api-extractor/src/collector/CollectorEntity.ts index f23fd22f1a5..36bb07353d9 100644 --- a/apps/api-extractor/src/collector/CollectorEntity.ts +++ b/apps/api-extractor/src/collector/CollectorEntity.ts @@ -3,10 +3,12 @@ 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 { AstEntity } from '../analyzer/AstSymbolTable'; +import type { AstEntity } from '../analyzer/AstEntity'; +import { AstNamespaceExport } from '../analyzer/AstNamespaceExport'; /** * This is a data structure used by the Collector to track an AstEntity that may be emitted in the *.d.ts file. @@ -15,7 +17,7 @@ import { AstEntity } from '../analyzer/AstSymbolTable'; * The additional contextual state beyond AstSymbol is: * - Whether it's an export of this entry point or not * - The nameForEmit, which may get renamed by DtsRollupGenerator._makeUniqueNames() - * - The export name (or names, if the same declaration is exported multiple times) + * - The export name (or names, if the same symbol is exported multiple times) */ export class CollectorEntity { /** @@ -23,9 +25,10 @@ export class CollectorEntity { */ public readonly astEntity: AstEntity; - private _exportNames: Set = new Set(); + private _exportNames: Set = new Set(); private _exportNamesSorted: boolean = false; private _singleExportName: string | undefined = undefined; + private _localExportNamesByParent: Map> = new Map(); private _nameForEmit: string | undefined = undefined; @@ -36,9 +39,9 @@ export class CollectorEntity { } /** - * The declaration name that will be emitted in a .d.ts rollup. For non-exported declarations, - * Collector._makeUniqueNames() may need to rename the declaration to avoid conflicts with other declarations - * in that module. + * The declaration name that will be emitted in the .d.ts rollup, .api.md, and .api.json files. Generated by + * `Collector._makeUniqueNames`. Be aware that the declaration may be renamed to avoid conflicts with (1) + * global names (e.g. `Promise`) and (2) if local, other local names across different files. */ public get nameForEmit(): string | undefined { return this._nameForEmit; @@ -50,7 +53,7 @@ export class CollectorEntity { } /** - * If this symbol is exported from the entry point, the list of export names. + * The list of export names if this symbol is exported from the entry point. * * @remarks * Note that a given symbol may be exported more than once: @@ -73,7 +76,7 @@ export class CollectorEntity { * In all other cases, it is undefined. */ public get singleExportName(): string | undefined { - return this._singleExportName; + return this._singleExportName; } /** @@ -81,6 +84,11 @@ export class CollectorEntity { * such as "export class X { }" instead of "export { X }". */ public get shouldInlineExport(): boolean { + // We export the namespace directly + if (this.astEntity instanceof AstNamespaceExport) { + return true; + } + // We don't inline an AstImport if (this.astEntity instanceof AstSymbol) { // We don't inline a symbol with more than one exported name @@ -95,14 +103,100 @@ export class CollectorEntity { } /** - * Returns true if this symbol is an export for the entry point being analyzed. + * Indicates that this entity is exported from the package entry point. Compare to `CollectorEntity.exported`. */ - public get exported(): boolean { + public get exportedFromEntryPoint(): boolean { return this.exportNames.size > 0; } /** - * Adds a new exportName to the exportNames set. + * Indicates that this entity is exported from its parent module (i.e. either the package entry point or + * a local namespace). Compare to `CollectorEntity.consumable`. + * + * @remarks + * In the example below: + * + * ```ts + * declare function add(): void; + * declare namespace calculator { + * export { + * add + * } + * } + * ``` + * + * Namespace `calculator` is neither exported nor consumable, function `add` is exported (from `calculator`) + * but not consumable. + */ + public get exported(): boolean { + // Exported from top-level? + if (this.exportedFromEntryPoint) return true; + + // Exported from parent? + for (const localExportNames of this._localExportNamesByParent.values()) { + if (localExportNames.size > 0) { + return true; + } + } + + return false; + } + + /** + * Indicates that it is possible for a consumer of the API to "consume" this entity, either by importing + * it directly or via a namespace. If an entity is not consumable, then API Extractor will report an + * `ae-forgotten-export` warning. Compare to `CollectorEntity.exported`. + * + * @remarks + * An API item is consumable if: + * + * 1. It is exported from the top-level entry point OR + * 2. It is exported from a consumable parent entity. + * + * For an example of #2, consider how `AstNamespaceImport` entities are processed. A generated rollup.d.ts + * might look like this: + * + * ```ts + * declare function add(): void; + * declare namespace calculator { + * export { + * add + * } + * } + * export { calculator } + * ``` + * + * In this example, `add` is exported via the consumable `calculator` namespace. + */ + public get consumable(): boolean { + // Exported from top-level? + if (this.exportedFromEntryPoint) return true; + + // Exported from consumable parent? + for (const [parent, localExportNames] of this._localExportNamesByParent) { + if (localExportNames.size > 0 && parent.consumable) { + return true; + } + } + + return false; + } + + /** + * Return the first consumable parent that exports this entity. If there is none, returns + * `undefined`. + */ + public getFirstExportingConsumableParent(): CollectorEntity | undefined { + for (const [parent, localExportNames] of this._localExportNamesByParent) { + if (parent.consumable && localExportNames.size > 0) { + return parent; + } + } + return undefined; + } + + /** + * Adds a new export name to the entity. */ public addExportName(exportName: string): void { if (!this._exportNames.has(exportName)) { @@ -117,6 +211,30 @@ export class CollectorEntity { } } + /** + * Adds a new local export name to the entity. + * + * @remarks + * In the example below: + * + * ```ts + * declare function add(): void; + * declare namespace calculator { + * export { + * add + * } + * } + * ``` + * + * `add` is the local export name for the `CollectorEntity` for `add`. + */ + public addLocalExportName(localExportName: string, parent: CollectorEntity): void { + const localExportNames: Set = this._localExportNamesByParent.get(parent) || new Set(); + localExportNames.add(localExportName); + + this._localExportNamesByParent.set(parent, localExportNames); + } + /** * A sorting key used by DtsRollupGenerator._makeUniqueNames() */ diff --git a/apps/api-extractor/src/collector/DeclarationMetadata.ts b/apps/api-extractor/src/collector/DeclarationMetadata.ts index f4510795a8b..f3d44de3a17 100644 --- a/apps/api-extractor/src/collector/DeclarationMetadata.ts +++ b/apps/api-extractor/src/collector/DeclarationMetadata.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 tsdoc from '@microsoft/tsdoc'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; +import type * as tsdoc from '@microsoft/tsdoc'; + +import type { AstDeclaration } from '../analyzer/AstDeclaration'; /** * Stores the Collector's additional analysis for a specific `AstDeclaration` signature. This object is assigned to diff --git a/apps/api-extractor/src/collector/MessageRouter.ts b/apps/api-extractor/src/collector/MessageRouter.ts index c121db012e2..bc09397c084 100644 --- a/apps/api-extractor/src/collector/MessageRouter.ts +++ b/apps/api-extractor/src/collector/MessageRouter.ts @@ -1,26 +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 colors from 'colors'; import * as ts from 'typescript'; -import * as tsdoc from '@microsoft/tsdoc'; -import { Sort, InternalError, LegacyAdapters } from '@rushstack/node-core-library'; -import { AedocDefinitions } from '@microsoft/api-extractor-model'; + +import type * as tsdoc from '@microsoft/tsdoc'; +import { Sort, InternalError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { AstSymbol } from '../analyzer/AstSymbol'; +import type { AstSymbol } from '../analyzer/AstSymbol'; import { ExtractorMessage, ExtractorMessageCategory, - IExtractorMessageOptions, - IExtractorMessageProperties + type IExtractorMessageOptions, + type IExtractorMessageProperties } from '../api/ExtractorMessage'; -import { ExtractorMessageId, allExtractorMessageIds } from '../api/ExtractorMessageId'; -import { - IExtractorMessagesConfig, - IConfigMessageReportingRule -} from '../api/IConfigFile'; -import { SourceMapper } from './SourceMapper'; +import { type ExtractorMessageId, allExtractorMessageIds } from '../api/ExtractorMessageId'; +import type { IExtractorMessagesConfig, IConfigMessageReportingRule } from '../api/IConfigFile'; +import type { ISourceLocation, SourceMapper } from './SourceMapper'; import { ExtractorLogLevel } from '../api/ExtractorLogLevel'; import { ConsoleMessageId } from '../api/ConsoleMessageId'; @@ -35,10 +32,20 @@ export interface IMessageRouterOptions { messagesConfig: IExtractorMessagesConfig; showVerboseMessages: boolean; showDiagnostics: boolean; + tsdocConfiguration: tsdoc.TSDocConfiguration; + sourceMapper: SourceMapper; +} + +export interface IBuildJsonDumpObjectOptions { + /** + * {@link MessageRouter.buildJsonDumpObject} will omit any objects keys with these names. + */ + keyNamesToOmit?: string[]; } export class MessageRouter { - public static readonly DIAGNOSTICS_LINE: string = '============================================================'; + public static readonly DIAGNOSTICS_LINE: string = + '============================================================'; private readonly _workingPackageFolder: string | undefined; private readonly _messageCallback: ((message: ExtractorMessage) => void) | undefined; @@ -51,14 +58,19 @@ export class MessageRouter { private readonly _sourceMapper: SourceMapper; + private readonly _tsdocConfiguration: tsdoc.TSDocConfiguration; + // Normalized representation of the routing rules from api-extractor.json private _reportingRuleByMessageId: Map = new Map(); - private _compilerDefaultRule: IReportingRule = { logLevel: ExtractorLogLevel.None, - addToApiReportFile: false }; - private _extractorDefaultRule: IReportingRule = { logLevel: ExtractorLogLevel.None, - addToApiReportFile: false }; - private _tsdocDefaultRule: IReportingRule = { logLevel: ExtractorLogLevel.None, - addToApiReportFile: false }; + private _compilerDefaultRule: IReportingRule = { + logLevel: ExtractorLogLevel.None, + addToApiReportFile: false + }; + private _extractorDefaultRule: IReportingRule = { + logLevel: ExtractorLogLevel.None, + addToApiReportFile: false + }; + private _tsdocDefaultRule: IReportingRule = { logLevel: ExtractorLogLevel.None, addToApiReportFile: false }; public errorCount: number = 0; public warningCount: number = 0; @@ -79,7 +91,8 @@ export class MessageRouter { this._messages = []; this._associatedMessagesForAstDeclaration = new Map(); - this._sourceMapper = new SourceMapper(); + this._sourceMapper = options.sourceMapper; + this._tsdocConfiguration = options.tsdocConfiguration; // showDiagnostics implies showVerboseMessages this.showVerboseMessages = options.showVerboseMessages || options.showDiagnostics; @@ -95,13 +108,16 @@ export class MessageRouter { if (messagesConfig.compilerMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.compilerMessageReporting)) { const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( - messagesConfig.compilerMessageReporting[messageId]); + messagesConfig.compilerMessageReporting[messageId] + ); if (messageId === 'default') { this._compilerDefaultRule = reportingRule; } else if (!/^TS[0-9]+$/.test(messageId)) { - throw new Error(`Error in API Extractor config: The messages.compilerMessageReporting table contains` - + ` an invalid entry "${messageId}". The identifier format is "TS" followed by an integer.`); + throw new Error( + `Error in API Extractor config: The messages.compilerMessageReporting table contains` + + ` an invalid entry "${messageId}". The identifier format is "TS" followed by an integer.` + ); } else { this._reportingRuleByMessageId.set(messageId, reportingRule); } @@ -111,16 +127,21 @@ export class MessageRouter { if (messagesConfig.extractorMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.extractorMessageReporting)) { const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( - messagesConfig.extractorMessageReporting[messageId]); + messagesConfig.extractorMessageReporting[messageId] + ); if (messageId === 'default') { this._extractorDefaultRule = reportingRule; } else if (!/^ae-/.test(messageId)) { - throw new Error(`Error in API Extractor config: The messages.extractorMessageReporting table contains` - + ` an invalid entry "${messageId}". The name should begin with the "ae-" prefix.`); + throw new Error( + `Error in API Extractor config: The messages.extractorMessageReporting table contains` + + ` an invalid entry "${messageId}". The name should begin with the "ae-" prefix.` + ); } else if (!allExtractorMessageIds.has(messageId)) { - throw new Error(`Error in API Extractor config: The messages.extractorMessageReporting table contains` - + ` an unrecognized identifier "${messageId}". Is it spelled correctly?`); + throw new Error( + `Error in API Extractor config: The messages.extractorMessageReporting table contains` + + ` an unrecognized identifier "${messageId}". Is it spelled correctly?` + ); } else { this._reportingRuleByMessageId.set(messageId, reportingRule); } @@ -130,16 +151,21 @@ export class MessageRouter { if (messagesConfig.tsdocMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.tsdocMessageReporting)) { const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( - messagesConfig.tsdocMessageReporting[messageId]); + messagesConfig.tsdocMessageReporting[messageId] + ); if (messageId === 'default') { this._tsdocDefaultRule = reportingRule; } else if (!/^tsdoc-/.test(messageId)) { - throw new Error(`Error in API Extractor config: The messages.tsdocMessageReporting table contains` - + ` an invalid entry "${messageId}". The name should begin with the "tsdoc-" prefix.`); - } else if (!AedocDefinitions.tsdocConfiguration.isKnownMessageId(messageId)) { - throw new Error(`Error in API Extractor config: The messages.tsdocMessageReporting table contains` - + ` an unrecognized identifier "${messageId}". Is it spelled correctly?`); + throw new Error( + `Error in API Extractor config: The messages.tsdocMessageReporting table contains` + + ` an invalid entry "${messageId}". The name should begin with the "tsdoc-" prefix.` + ); + } else if (!this._tsdocConfiguration.isKnownMessageId(messageId)) { + throw new Error( + `Error in API Extractor config: The messages.tsdocMessageReporting table contains` + + ` an unrecognized identifier "${messageId}". Is it spelled correctly?` + ); } else { this._reportingRuleByMessageId.set(messageId, reportingRule); } @@ -165,10 +191,10 @@ export class MessageRouter { switch (diagnostic.category) { case ts.DiagnosticCategory.Suggestion: case ts.DiagnosticCategory.Message: - return; // ignore noise + return; // ignore noise } - const messageText: string = `${diagnostic.messageText}`; + const messageText: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); const options: IExtractorMessageOptions = { category: ExtractorMessageCategory.Compiler, messageId: `TS${diagnostic.code}`, @@ -176,26 +202,31 @@ export class MessageRouter { }; if (diagnostic.file) { + // NOTE: Since compiler errors pertain to issues specific to the .d.ts files, + // we do not apply source mappings for them. const sourceFile: ts.SourceFile = diagnostic.file; - const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition( - diagnostic.start || 0); - - options.sourceFilePath = sourceFile.fileName; - options.sourceFileLine = lineAndCharacter.line + 1; - options.sourceFileColumn = lineAndCharacter.character + 1; + const sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({ + sourceFile, + pos: diagnostic.start || 0, + useDtsLocation: true + }); + options.sourceFilePath = sourceLocation.sourceFilePath; + options.sourceFileLine = sourceLocation.sourceFileLine; + options.sourceFileColumn = sourceLocation.sourceFileColumn; } - // NOTE: Since compiler errors pertain to issues specific to the .d.ts files, - // we do not apply source mappings for them. this._messages.push(new ExtractorMessage(options)); } /** * Add a message from the API Extractor analysis */ - public addAnalyzerIssue(messageId: ExtractorMessageId, messageText: string, - astDeclarationOrSymbol: AstDeclaration | AstSymbol, properties?: IExtractorMessageProperties): void { - + public addAnalyzerIssue( + messageId: ExtractorMessageId, + messageText: string, + astDeclarationOrSymbol: AstDeclaration | AstSymbol, + properties?: IExtractorMessageProperties + ): void { let astDeclaration: AstDeclaration; if (astDeclarationOrSymbol instanceof AstDeclaration) { astDeclaration = astDeclarationOrSymbol; @@ -204,8 +235,12 @@ export class MessageRouter { } const extractorMessage: ExtractorMessage = this.addAnalyzerIssueForPosition( - messageId, messageText, astDeclaration.declaration.getSourceFile(), - astDeclaration.declaration.getStart(), properties); + messageId, + messageText, + astDeclaration.declaration.getSourceFile(), + astDeclaration.declaration.getStart(), + properties + ); this._associateMessageWithAstDeclaration(extractorMessage, astDeclaration); } @@ -214,23 +249,26 @@ export class MessageRouter { * Add all messages produced from an invocation of the TSDoc parser, assuming they refer to * code in the specified source file. */ - public addTsdocMessages(parserContext: tsdoc.ParserContext, sourceFile: ts.SourceFile, - astDeclaration?: AstDeclaration): void { - + public addTsdocMessages( + parserContext: tsdoc.ParserContext, + sourceFile: ts.SourceFile, + astDeclaration?: AstDeclaration + ): void { for (const message of parserContext.log.messages) { - const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition( - message.textRange.pos); - const options: IExtractorMessageOptions = { category: ExtractorMessageCategory.TSDoc, messageId: message.messageId, - text: message.unformattedText, - sourceFilePath: sourceFile.fileName, - sourceFileLine: lineAndCharacter.line + 1, - sourceFileColumn: lineAndCharacter.character + 1 + text: message.unformattedText }; - this._sourceMapper.updateExtractorMessageOptions(options); + const sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({ + sourceFile, + pos: message.textRange.pos + }); + options.sourceFilePath = sourceLocation.sourceFilePath; + options.sourceFileLine = sourceLocation.sourceFileLine; + options.sourceFileColumn = sourceLocation.sourceFileColumn; + const extractorMessage: ExtractorMessage = new ExtractorMessage(options); if (astDeclaration) { @@ -249,9 +287,19 @@ export class MessageRouter { * or `undefined` if the input cannot be represented as JSON */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static buildJsonDumpObject(input: any): any | undefined { + public static buildJsonDumpObject(input: any, options?: IBuildJsonDumpObjectOptions): any | undefined { + if (!options) { + options = {}; + } + + 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) { - // eslint-disable-next-line @rushstack/no-null return null; // JSON uses null instead of undefined } @@ -266,7 +314,7 @@ export class MessageRouter { const outputArray: any[] = []; for (const element of input) { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const serializedElement: any = MessageRouter.buildJsonDumpObject(element); + const serializedElement: any = MessageRouter._buildJsonDumpObject(element, keyNamesToOmit); if (serializedElement !== undefined) { outputArray.push(serializedElement); } @@ -274,16 +322,21 @@ export class MessageRouter { return outputArray; } - const outputObject: object = { }; + 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); + const serializedValue: any = MessageRouter._buildJsonDumpObject(value, keyNamesToOmit); if (serializedValue !== undefined) { - outputObject[key] = serializedValue; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (outputObject as any)[key] = serializedValue; } } return outputObject; @@ -295,11 +348,12 @@ export class MessageRouter { /** * Record this message in _associatedMessagesForAstDeclaration */ - private _associateMessageWithAstDeclaration(extractorMessage: ExtractorMessage, - astDeclaration: AstDeclaration): void { - - let associatedMessages: ExtractorMessage[] | undefined - = this._associatedMessagesForAstDeclaration.get(astDeclaration); + private _associateMessageWithAstDeclaration( + extractorMessage: ExtractorMessage, + astDeclaration: AstDeclaration + ): void { + let associatedMessages: ExtractorMessage[] | undefined = + this._associatedMessagesForAstDeclaration.get(astDeclaration); if (!associatedMessages) { associatedMessages = []; @@ -311,23 +365,28 @@ export class MessageRouter { /** * Add a message for a location in an arbitrary source file. */ - public addAnalyzerIssueForPosition(messageId: ExtractorMessageId, messageText: string, - sourceFile: ts.SourceFile, pos: number, properties?: IExtractorMessageProperties): ExtractorMessage { - - const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition( - pos); - + public addAnalyzerIssueForPosition( + messageId: ExtractorMessageId, + messageText: string, + sourceFile: ts.SourceFile, + pos: number, + properties?: IExtractorMessageProperties + ): ExtractorMessage { const options: IExtractorMessageOptions = { category: ExtractorMessageCategory.Extractor, messageId, text: messageText, - sourceFilePath: sourceFile.fileName, - sourceFileLine: lineAndCharacter.line + 1, - sourceFileColumn: lineAndCharacter.character + 1, properties }; - this._sourceMapper.updateExtractorMessageOptions(options); + const sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({ + sourceFile, + pos + }); + options.sourceFilePath = sourceLocation.sourceFilePath; + options.sourceFileLine = sourceLocation.sourceFileLine; + options.sourceFileColumn = sourceLocation.sourceFileColumn; + const extractorMessage: ExtractorMessage = new ExtractorMessage(options); this._messages.push(extractorMessage); @@ -342,22 +401,19 @@ export class MessageRouter { public fetchAssociatedMessagesForReviewFile(astDeclaration: AstDeclaration): ExtractorMessage[] { const messagesForApiReportFile: ExtractorMessage[] = []; - const associatedMessages: ExtractorMessage[] = this._associatedMessagesForAstDeclaration.get(astDeclaration) || []; + const associatedMessages: ExtractorMessage[] = + this._associatedMessagesForAstDeclaration.get(astDeclaration) || []; for (const associatedMessage of associatedMessages) { - // Make sure we didn't already report this message for some reason if (!associatedMessage.handled) { - // Is this message type configured to go in the API report file? const reportingRule: IReportingRule = this._getRuleForMessage(associatedMessage); if (reportingRule.addToApiReportFile) { - // Include it in the result, and record that it went to the API report file messagesForApiReportFile.push(associatedMessage); associatedMessage.handled = true; } } - } this._sortMessagesForOutput(messagesForApiReportFile); @@ -366,26 +422,22 @@ 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[] = []; for (const unassociatedMessage of this.messages) { - // Make sure we didn't already report this message for some reason if (!unassociatedMessage.handled) { - // Is this message type configured to go in the API report file? const reportingRule: IReportingRule = this._getRuleForMessage(unassociatedMessage); if (reportingRule.addToApiReportFile) { - // Include it in the result, and record that it went to the API report file messagesForApiReportFile.push(unassociatedMessage); unassociatedMessage.handled = true; } } - } this._sortMessagesForOutput(messagesForApiReportFile); @@ -414,44 +466,68 @@ export class MessageRouter { } } - public logError(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void { - this._handleMessage(new ExtractorMessage({ - category: ExtractorMessageCategory.Console, - messageId, - text: message, - properties, - logLevel: ExtractorLogLevel.Error - })); + public logError( + messageId: ConsoleMessageId, + message: string, + properties?: IExtractorMessageProperties + ): void { + this._handleMessage( + new ExtractorMessage({ + category: ExtractorMessageCategory.Console, + messageId, + text: message, + properties, + logLevel: ExtractorLogLevel.Error + }) + ); } - public logWarning(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void { - this._handleMessage(new ExtractorMessage({ - category: ExtractorMessageCategory.Console, - messageId, - text: message, - properties, - logLevel: ExtractorLogLevel.Warning - })); + public logWarning( + messageId: ConsoleMessageId, + message: string, + properties?: IExtractorMessageProperties + ): void { + this._handleMessage( + new ExtractorMessage({ + category: ExtractorMessageCategory.Console, + messageId, + text: message, + properties, + logLevel: ExtractorLogLevel.Warning + }) + ); } - public logInfo(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void { - this._handleMessage(new ExtractorMessage({ - category: ExtractorMessageCategory.Console, - messageId, - text: message, - properties, - logLevel: ExtractorLogLevel.Info - })); + public logInfo( + messageId: ConsoleMessageId, + message: string, + properties?: IExtractorMessageProperties + ): void { + this._handleMessage( + new ExtractorMessage({ + category: ExtractorMessageCategory.Console, + messageId, + text: message, + properties, + logLevel: ExtractorLogLevel.Info + }) + ); } - public logVerbose(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void { - this._handleMessage(new ExtractorMessage({ - category: ExtractorMessageCategory.Console, - messageId, - text: message, - properties, - logLevel: ExtractorLogLevel.Verbose - })); + public logVerbose( + messageId: ConsoleMessageId, + message: string, + properties?: IExtractorMessageProperties + ): void { + this._handleMessage( + new ExtractorMessage({ + category: ExtractorMessageCategory.Console, + messageId, + text: message, + properties, + logLevel: ExtractorLogLevel.Verbose + }) + ); } public logDiagnosticHeader(title: string): void { @@ -465,7 +541,9 @@ export class MessageRouter { } public logDiagnostic(message: string): void { - this.logVerbose(ConsoleMessageId.Diagnostics, message); + if (this.showDiagnostics) { + this.logVerbose(ConsoleMessageId.Diagnostics, message); + } } /** @@ -520,17 +598,17 @@ export class MessageRouter { switch (message.logLevel) { case ExtractorLogLevel.Error: - console.error(colors.red('Error: ' + messageText)); + console.error(Colorize.red('Error: ' + messageText)); break; case ExtractorLogLevel.Warning: - console.warn(colors.yellow('Warning: ' + messageText)); + console.warn(Colorize.yellow('Warning: ' + messageText)); break; case ExtractorLogLevel.Info: console.log(messageText); break; case ExtractorLogLevel.Verbose: if (this.showVerboseMessages) { - console.log(colors.cyan(messageText)); + console.log(Colorize.cyan(messageText)); } break; default: @@ -562,7 +640,7 @@ export class MessageRouter { * Sorts an array of messages according to a reasonable ordering */ private _sortMessagesForOutput(messages: ExtractorMessage[]): void { - LegacyAdapters.sortStable(messages, (a, b) => { + messages.sort((a, b) => { let diff: number; // First sort by file name diff = Sort.compareByValue(a.sourceFilePath, b.sourceFilePath); diff --git a/apps/api-extractor/src/collector/SourceMapper.ts b/apps/api-extractor/src/collector/SourceMapper.ts index 58ba28d2246..368ea15fa07 100644 --- a/apps/api-extractor/src/collector/SourceMapper.ts +++ b/apps/api-extractor/src/collector/SourceMapper.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 path from 'path'; -import { SourceMapConsumer, RawSourceMap, MappingItem, Position } from 'source-map'; -import { IExtractorMessageOptions } from '../api/ExtractorMessage'; +import * as path from 'node:path'; + +import { SourceMapConsumer, type RawSourceMap, type MappingItem, type Position } from 'source-map'; +import type ts from 'typescript'; + import { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library'; interface ISourceMap { @@ -24,38 +26,161 @@ interface IOriginalFileInfo { maxColumnForLine: number[]; } +export interface ISourceLocation { + /** + * The absolute path to the source file. + */ + sourceFilePath: string; + + /** + * The line number in the source file. The first line number is 1. + */ + sourceFileLine: number; + + /** + * The column number in the source file. The first column number is 1. + */ + sourceFileColumn: number; +} + +export interface IGetSourceLocationOptions { + /** + * The source file to get the source location from. + */ + sourceFile: ts.SourceFile; + + /** + * The position within the source file to get the source location from. + */ + pos: number; + + /** + * If `false` or not provided, then we attempt to follow source maps in order to resolve the + * location to the original `.ts` file. If resolution isn't possible for some reason, we fall + * back to the `.d.ts` location. + * + * If `true`, then we don't bother following source maps, and the location refers to the `.d.ts` + * location. + */ + useDtsLocation?: boolean; +} + export class SourceMapper { // Map from .d.ts file path --> ISourceMap if a source map was found, or null if not found - private _sourceMapByFilePath: Map - = new Map(); + private _sourceMapByFilePath: Map = new Map(); // Cache the FileSystem.exists() result for mapped .ts files private _originalFileInfoByPath: Map = new Map(); /** - * If the `IExtractorMessageOptions` refers to a `.d.ts` file, look for a `.d.ts.map` and - * if possible update the coordinates to refer to the original `.ts` file. + * Given a `.d.ts` source file and a specific position within the file, return the corresponding + * `ISourceLocation`. */ - public updateExtractorMessageOptions(options: IExtractorMessageOptions): void { - if (!options.sourceFilePath) { - return; + public getSourceLocation(options: IGetSourceLocationOptions): ISourceLocation { + const lineAndCharacter: ts.LineAndCharacter = options.sourceFile.getLineAndCharacterOfPosition( + options.pos + ); + const sourceLocation: ISourceLocation = { + sourceFilePath: options.sourceFile.fileName, + sourceFileLine: lineAndCharacter.line + 1, + sourceFileColumn: lineAndCharacter.character + 1 + }; + + if (options.useDtsLocation) { + return sourceLocation; } - if (!FileSystem.exists(options.sourceFilePath)) { + const mappedSourceLocation: ISourceLocation | undefined = this._getMappedSourceLocation(sourceLocation); + return mappedSourceLocation || sourceLocation; + } + + private _getMappedSourceLocation(sourceLocation: ISourceLocation): ISourceLocation | undefined { + const { sourceFilePath, sourceFileLine, sourceFileColumn } = sourceLocation; + + if (!FileSystem.exists(sourceFilePath)) { // Sanity check - throw new InternalError('The referenced path was not found: ' + options.sourceFilePath); + throw new InternalError('The referenced path was not found: ' + sourceFilePath); + } + + const sourceMap: ISourceMap | null = this._getSourceMap(sourceFilePath); + if (!sourceMap) return; + + const nearestMappingItem: MappingItem | undefined = SourceMapper._findNearestMappingItem( + sourceMap.mappingItems, + { + line: sourceFileLine, + column: sourceFileColumn + } + ); + + if (!nearestMappingItem) return; + + const mappedFilePath: string = path.resolve(path.dirname(sourceFilePath), nearestMappingItem.source); + + // Does the mapped filename exist? Use a cache to remember the answer. + let originalFileInfo: IOriginalFileInfo | undefined = this._originalFileInfoByPath.get(mappedFilePath); + if (originalFileInfo === undefined) { + originalFileInfo = { + fileExists: FileSystem.exists(mappedFilePath), + maxColumnForLine: [] + }; + + if (originalFileInfo.fileExists) { + // Read the file and measure the length of each line + originalFileInfo.maxColumnForLine = FileSystem.readFile(mappedFilePath, { + convertLineEndings: NewlineKind.Lf + }) + .split('\n') + .map((x) => x.length + 1); // +1 since columns are 1-based + originalFileInfo.maxColumnForLine.unshift(0); // Extra item since lines are 1-based + } + + this._originalFileInfoByPath.set(mappedFilePath, originalFileInfo); + } + + // Don't translate coordinates to a file that doesn't exist + if (!originalFileInfo.fileExists) return; + + // The nearestMappingItem anchor may be above/left of the real position, due to gaps in the mapping. Calculate + // the delta and apply it to the original position. + const guessedPosition: Position = { + line: nearestMappingItem.originalLine + sourceFileLine - nearestMappingItem.generatedLine, + column: nearestMappingItem.originalColumn + sourceFileColumn - nearestMappingItem.generatedColumn + }; + + // Verify that the result is not out of bounds, in cause our heuristic failed + if ( + guessedPosition.line >= 1 && + guessedPosition.line < originalFileInfo.maxColumnForLine.length && + guessedPosition.column >= 1 && + guessedPosition.column <= originalFileInfo.maxColumnForLine[guessedPosition.line] + ) { + return { + sourceFilePath: mappedFilePath, + sourceFileLine: guessedPosition.line, + sourceFileColumn: guessedPosition.column + }; + } else { + // The guessed position was out of bounds, so use the nearestMappingItem position instead. + return { + sourceFilePath: mappedFilePath, + sourceFileLine: nearestMappingItem.originalLine, + sourceFileColumn: nearestMappingItem.originalColumn + }; } + } - let sourceMap: ISourceMap | null | undefined = this._sourceMapByFilePath.get(options.sourceFilePath); + private _getSourceMap(sourceFilePath: string): ISourceMap | null { + let sourceMap: ISourceMap | null | undefined = this._sourceMapByFilePath.get(sourceFilePath); if (sourceMap === undefined) { // Normalize the path and redo the lookup - const normalizedPath: string = FileSystem.getRealPath(options.sourceFilePath); + const normalizedPath: string = FileSystem.getRealPath(sourceFilePath); sourceMap = this._sourceMapByFilePath.get(normalizedPath); if (sourceMap !== undefined) { // Copy the result from the normalized to the non-normalized key - this._sourceMapByFilePath.set(options.sourceFilePath, sourceMap); + this._sourceMapByFilePath.set(sourceFilePath, sourceMap); } else { // Given "folder/file.d.ts", check for a corresponding "folder/file.d.ts.map" const sourceMapPath: string = normalizedPath + '.map'; @@ -81,100 +206,30 @@ export class SourceMapper { SourceMapConsumer.GENERATED_ORDER ); - sourceMap = { sourceMapConsumer, mappingItems}; + sourceMap = { sourceMapConsumer, mappingItems }; } else { // No source map for this filename - sourceMap = null; // eslint-disable-line @rushstack/no-null + sourceMap = null; } this._sourceMapByFilePath.set(normalizedPath, sourceMap); - if (options.sourceFilePath !== normalizedPath) { + if (sourceFilePath !== normalizedPath) { // Add both keys to the map - this._sourceMapByFilePath.set(options.sourceFilePath, sourceMap); + this._sourceMapByFilePath.set(sourceFilePath, sourceMap); } } } - if (sourceMap === null) { - // No source map for this filename - return; - } - - // Make sure sourceFileLine and sourceFileColumn are defined - if (options.sourceFileLine === undefined) { - options.sourceFileLine = 1; - } - if (options.sourceFileColumn === undefined) { - options.sourceFileColumn = 1; - } - - const nearestMappingItem: MappingItem | undefined = SourceMapper._findNearestMappingItem(sourceMap.mappingItems, - { - line: options.sourceFileLine, - column: options.sourceFileColumn - } - ); - - if (nearestMappingItem === undefined) { - // No mapping for this location - return; - } - - const mappedFilePath: string = path.resolve(path.dirname(options.sourceFilePath), nearestMappingItem.source); - - // Does the mapped filename exist? Use a cache to remember the answer. - let originalFileInfo: IOriginalFileInfo | undefined = this._originalFileInfoByPath.get(mappedFilePath); - if (originalFileInfo === undefined) { - originalFileInfo = { - fileExists: FileSystem.exists(mappedFilePath), - maxColumnForLine: [] - }; - - if (originalFileInfo.fileExists) { - // Read the file and measure the length of each line - originalFileInfo.maxColumnForLine = - FileSystem.readFile(mappedFilePath, { convertLineEndings: NewlineKind.Lf }) - .split('\n') - .map(x => x.length + 1); // +1 since columns are 1-based - originalFileInfo.maxColumnForLine.unshift(0); // Extra item since lines are 1-based - } - - this._originalFileInfoByPath.set(mappedFilePath, originalFileInfo); - } - - if (!originalFileInfo.fileExists) { - // Don't translate coordinates to a file that doesn't exist - return; - } - - // The nearestMappingItem anchor may be above/left of the real position, due to gaps in the mapping. Calculate - // the delta and apply it to the original position. - const guessedPosition: Position = { - line: nearestMappingItem.originalLine + options.sourceFileLine - nearestMappingItem.generatedLine, - column: nearestMappingItem.originalColumn + options.sourceFileColumn - nearestMappingItem.generatedColumn - }; - - // Verify that the result is not out of bounds, in cause our heuristic failed - if (guessedPosition.line >= 1 - && guessedPosition.line < originalFileInfo.maxColumnForLine.length - && guessedPosition.column >= 1 - && guessedPosition.column <= originalFileInfo.maxColumnForLine[guessedPosition.line]) { - - options.sourceFilePath = mappedFilePath; - options.sourceFileLine = guessedPosition.line; - options.sourceFileColumn = guessedPosition.column; - } else { - // The guessed position was out of bounds, so use the nearestMappingItem position instead. - options.sourceFilePath = mappedFilePath; - options.sourceFileLine = nearestMappingItem.originalLine; - options.sourceFileColumn = nearestMappingItem.originalColumn; - } + 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 { + private static _findNearestMappingItem( + mappingItems: MappingItem[], + position: Position + ): MappingItem | undefined { if (mappingItems.length === 0) { return undefined; } diff --git a/apps/api-extractor/src/collector/SymbolMetadata.ts b/apps/api-extractor/src/collector/SymbolMetadata.ts index ee942f80fab..8a467219360 100644 --- a/apps/api-extractor/src/collector/SymbolMetadata.ts +++ b/apps/api-extractor/src/collector/SymbolMetadata.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 { ReleaseTag } from '@microsoft/api-extractor-model'; +import type { ReleaseTag } from '@microsoft/api-extractor-model'; /** * Constructor parameters for `SymbolMetadata`. @@ -19,7 +19,7 @@ export class SymbolMetadata { // `ApiItemMetadata.effectiveReleaseTag` value that is most public. public readonly maxEffectiveReleaseTag: ReleaseTag; - public constructor (options: ISymbolMetadataOptions) { + public constructor(options: ISymbolMetadataOptions) { this.maxEffectiveReleaseTag = options.maxEffectiveReleaseTag; } } diff --git a/apps/api-extractor/src/collector/WorkingPackage.ts b/apps/api-extractor/src/collector/WorkingPackage.ts index 3ae47076705..d85e88e4c11 100644 --- a/apps/api-extractor/src/collector/WorkingPackage.ts +++ b/apps/api-extractor/src/collector/WorkingPackage.ts @@ -1,12 +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 ts from 'typescript'; -import * as tsdoc from '@microsoft/tsdoc'; +import type * as ts from 'typescript'; -import { - INodePackageJson -} from '@rushstack/node-core-library'; +import type * as tsdoc from '@microsoft/tsdoc'; +import type { INodePackageJson } from '@rushstack/node-core-library'; /** * Constructor options for WorkingPackage diff --git a/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts b/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts index f25afd093a9..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 { Collector } from '../collector/Collector'; +import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ApiItemMetadata } from '../collector/ApiItemMetadata'; -import { AedocDefinitions, ReleaseTag } from '@microsoft/api-extractor-model'; +import type { AstDeclaration } from '../analyzer/AstDeclaration'; +import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; import { VisitorState } from '../collector/VisitorState'; import { ResolverFailure } from '../analyzer/AstReferenceResolver'; @@ -28,7 +29,11 @@ export class DocCommentEnhancer { public analyze(): void { for (const entity of this._collector.entities) { if (entity.astEntity instanceof AstSymbol) { - if (entity.exported) { + if ( + entity.consumable || + this._collector.extractorConfig.apiReportIncludeForgottenExports || + this._collector.extractorConfig.docModelIncludeForgottenExports + ) { entity.astEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { this._analyzeApiItem(astDeclaration); }); @@ -65,17 +70,16 @@ export class DocCommentEnhancer { } private _analyzeNeedsDocumentation(astDeclaration: AstDeclaration, metadata: ApiItemMetadata): void { - if (astDeclaration.declaration.kind === ts.SyntaxKind.Constructor) { // Constructors always do pretty much the same thing, so it's annoying to require people to write // descriptions for them. Instead, if the constructor lacks a TSDoc summary, then API Extractor // will auto-generate one. - metadata.needsDocumentation = false; + metadata.undocumented = false; // The class that contains this constructor const classDeclaration: AstDeclaration = astDeclaration.parent!; - const configuration: tsdoc.TSDocConfiguration = AedocDefinitions.tsdocConfiguration; + const configuration: tsdoc.TSDocConfiguration = this._collector.extractorConfig.tsdocConfiguration; if (!metadata.tsdocComment) { metadata.tsdocComment = new tsdoc.DocComment({ configuration }); @@ -115,8 +119,9 @@ export class DocCommentEnhancer { new tsdoc.DocParagraph({ configuration }, [ new tsdoc.DocPlainText({ configuration, - text: `The constructor for this class is marked as internal. Third-party code should not` - + ` call the constructor directly or create subclasses that extend the ` + text: + `The constructor for this class is marked as internal. Third-party code should not` + + ` call the constructor directly or create subclasses that extend the ` }), new tsdoc.DocCodeSpan({ configuration, @@ -125,17 +130,45 @@ export class DocCommentEnhancer { new tsdoc.DocPlainText({ configuration, text: ' class.' }) ]) ); - } return; - } - - if (metadata.tsdocComment) { - // Require the summary to contain at least 10 non-spacing characters - metadata.needsDocumentation = !tsdoc.PlainTextEmitter.hasAnyTextContent( - metadata.tsdocComment.summarySection, 10); } else { - metadata.needsDocumentation = true; + // For non-constructor items, we will determine whether or not the item is documented as follows: + // 1. If it contains a summary section with at least 10 characters, then it is considered "documented". + // 2. If it contains an @inheritDoc tag, then it *may* be considered "documented", depending on whether or not + // the tag resolves to a "documented" API member. + // - Note: for external members, we cannot currently determine this, so we will consider the "documented" + // status to be unknown. + if (metadata.tsdocComment) { + if (tsdoc.PlainTextEmitter.hasAnyTextContent(metadata.tsdocComment.summarySection, 10)) { + // If the API item has a summary comment block (with at least 10 characters), mark it as "documented". + metadata.undocumented = false; + } else if (metadata.tsdocComment.inheritDocTag) { + if ( + this._refersToDeclarationInWorkingPackage( + metadata.tsdocComment.inheritDocTag.declarationReference + ) + ) { + // If the API item has an `@inheritDoc` comment that points to an API item in the working package, + // then the documentation contents should have already been copied from the target via `_applyInheritDoc`. + // The continued existence of the tag indicates that the declaration reference was invalid, and not + // documentation contents could be copied. + // An analyzer issue will have already been logged for this. + // We will treat such an API as "undocumented". + metadata.undocumented = true; + } else { + // If the API item has an `@inheritDoc` comment that points to an external API item, we cannot currently + // determine whether or not the target is "documented", so we cannot say definitively that this is "undocumented". + metadata.undocumented = false; + } + } else { + // If the API item has neither a summary comment block, nor an `@inheritDoc` comment, mark it as "undocumented". + metadata.undocumented = true; + } + } else { + // If there is no tsdoc comment at all, mark "undocumented". + metadata.undocumented = true; + } } } @@ -149,22 +182,20 @@ export class DocCommentEnhancer { private _checkForBrokenLinksRecursive(astDeclaration: AstDeclaration, node: tsdoc.DocNode): void { if (node instanceof tsdoc.DocLinkTag) { if (node.codeDestination) { - // Is it referring to the working package? If not, we don't do any link validation, because // AstReferenceResolver doesn't support it yet (but ModelReferenceResolver does of course). // Tracked by: https://github.com/microsoft/rushstack/issues/1195 - if (node.codeDestination.packageName === undefined - || node.codeDestination.packageName === this._collector.workingPackage.name) { - - const referencedAstDeclaration: AstDeclaration | ResolverFailure = this._collector.astReferenceResolver - .resolve(node.codeDestination); + if (this._refersToDeclarationInWorkingPackage(node.codeDestination)) { + const referencedAstDeclaration: AstDeclaration | ResolverFailure = + this._collector.astReferenceResolver.resolve(node.codeDestination); if (referencedAstDeclaration instanceof ResolverFailure) { - this._collector.messageRouter.addAnalyzerIssue(ExtractorMessageId.UnresolvedLink, + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.UnresolvedLink, 'The @link reference could not be resolved: ' + referencedAstDeclaration.reason, - astDeclaration); + astDeclaration + ); } - } } } @@ -176,38 +207,43 @@ export class DocCommentEnhancer { /** * Follow an `{@inheritDoc ___}` reference and copy the content that we find in the referenced comment. */ - private _applyInheritDoc(astDeclaration: AstDeclaration, docComment: tsdoc.DocComment, - inheritDocTag: tsdoc.DocInheritDocTag): void { - + private _applyInheritDoc( + astDeclaration: AstDeclaration, + docComment: tsdoc.DocComment, + inheritDocTag: tsdoc.DocInheritDocTag + ): void { if (!inheritDocTag.declarationReference) { - this._collector.messageRouter.addAnalyzerIssue(ExtractorMessageId.UnresolvedInheritDocBase, + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.UnresolvedInheritDocBase, 'The @inheritDoc tag needs a TSDoc declaration reference; signature matching is not supported yet', - astDeclaration); + astDeclaration + ); return; } - // Is it referring to the working package? - if (!(inheritDocTag.declarationReference.packageName === undefined - || inheritDocTag.declarationReference.packageName === this._collector.workingPackage.name)) { - - // It's referencing an external package, so skip this inheritDoc tag, since AstReferenceResolver doesn't + if (!this._refersToDeclarationInWorkingPackage(inheritDocTag.declarationReference)) { + // The `@inheritDoc` tag is referencing an external package. Skip it, since AstReferenceResolver doesn't // support it yet. As a workaround, this tag will get handled later by api-documenter. // Tracked by: https://github.com/microsoft/rushstack/issues/1195 return; } - const referencedAstDeclaration: AstDeclaration | ResolverFailure = this._collector.astReferenceResolver - .resolve(inheritDocTag.declarationReference); + const referencedAstDeclaration: AstDeclaration | ResolverFailure = + this._collector.astReferenceResolver.resolve(inheritDocTag.declarationReference); if (referencedAstDeclaration instanceof ResolverFailure) { - this._collector.messageRouter.addAnalyzerIssue(ExtractorMessageId.UnresolvedInheritDocReference, - 'The @inheritDoc reference could not be resolved: ' + referencedAstDeclaration.reason, astDeclaration); + this._collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.UnresolvedInheritDocReference, + 'The @inheritDoc reference could not be resolved: ' + referencedAstDeclaration.reason, + astDeclaration + ); return; } this._analyzeApiItem(referencedAstDeclaration); - const referencedMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(referencedAstDeclaration); + const referencedMetadata: ApiItemMetadata = + this._collector.fetchApiItemMetadata(referencedAstDeclaration); if (referencedMetadata.tsdocComment) { this._copyInheritedDocs(docComment, referencedMetadata.tsdocComment); @@ -233,4 +269,15 @@ export class DocCommentEnhancer { targetDocComment.inheritDocTag = undefined; } + /** + * Determines whether or not the provided declaration reference points to an item in the working package. + */ + private _refersToDeclarationInWorkingPackage( + declarationReference: tsdoc.DocDeclarationReference | undefined + ): boolean { + return ( + declarationReference?.packageName === undefined || + declarationReference.packageName === this._collector.workingPackage.name + ); + } } diff --git a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts index 94bed1b2588..09d80f862cc 100644 --- a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts +++ b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts @@ -1,33 +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 path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; -import { Collector } from '../collector/Collector'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; + +import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ApiItemMetadata } from '../collector/ApiItemMetadata'; -import { SymbolMetadata } from '../collector/SymbolMetadata'; -import { CollectorEntity } from '../collector/CollectorEntity'; +import type { AstDeclaration } from '../analyzer/AstDeclaration'; +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 { IAstModuleExportInfo } from '../analyzer/AstModule'; +import type { AstEntity } from '../analyzer/AstEntity'; export class ValidationEnhancer { - public static analyze(collector: Collector): void { - const alreadyWarnedSymbols: Set = new Set(); + const alreadyWarnedEntities: Set = new Set(); for (const entity of collector.entities) { + if ( + !( + entity.consumable || + collector.extractorConfig.apiReportIncludeForgottenExports || + collector.extractorConfig.docModelIncludeForgottenExports + ) + ) { + continue; + } + if (entity.astEntity instanceof AstSymbol) { - if (entity.exported) { - entity.astEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { - ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedSymbols); - }); - - const symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(entity.astEntity); - ValidationEnhancer._checkForInternalUnderscore(collector, entity, entity.astEntity, symbolMetadata); - ValidationEnhancer._checkForInconsistentReleaseTags(collector, entity.astEntity, symbolMetadata); + // A regular exported AstSymbol + + const astSymbol: AstSymbol = entity.astEntity; + + astSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { + ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities); + }); + + const symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); + ValidationEnhancer._checkForInternalUnderscore(collector, entity, astSymbol, symbolMetadata); + ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); + } else if (entity.astEntity instanceof AstNamespaceImport) { + // A namespace created using "import * as ___ from ___" + const astNamespaceImport: AstNamespaceImport = entity.astEntity; + + const astModuleExportInfo: IAstModuleExportInfo = + astNamespaceImport.fetchAstModuleExportInfo(collector); + + for (const namespaceMemberAstEntity of astModuleExportInfo.exportedLocalEntities.values()) { + if (namespaceMemberAstEntity instanceof AstSymbol) { + const astSymbol: AstSymbol = namespaceMemberAstEntity; + + astSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { + ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities); + }); + + const symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); + + // (Don't apply ValidationEnhancer._checkForInternalUnderscore() for AstNamespaceImport members) + + ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); + } } } } @@ -39,12 +77,11 @@ export class ValidationEnhancer { 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 and underscore. + // 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 */ @@ -82,8 +119,8 @@ export class ValidationEnhancer { if (exportName[0] !== '_') { collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.InternalMissingUnderscore, - `The name "${exportName}" should be prefixed with an underscore` - + ` because the declaration is marked as @internal`, + `The name "${exportName}" should be prefixed with an underscore` + + ` because the declaration is marked as @internal`, astSymbol, { exportName } ); @@ -150,7 +187,7 @@ export class ValidationEnhancer { collector.messageRouter.addAnalyzerIssue( ExtractorMessageId.InternalMixedReleaseTag, `Mixed release tags are not allowed for "${astSymbol.localName}" because one of its declarations` + - ` is marked as @internal`, + ` is marked as @internal`, astSymbol ); } @@ -160,12 +197,15 @@ export class ValidationEnhancer { private static _checkReferences( collector: Collector, astDeclaration: AstDeclaration, - alreadyWarnedSymbols: Set + 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 @@ -174,39 +214,57 @@ export class ValidationEnhancer { // TODO: Technically we should also check each of the nested scopes along the way. const rootSymbol: AstSymbol = referencedEntity.rootAstSymbol; - if (!rootSymbol.isExternal) { - const collectorEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity(rootSymbol); - - if (collectorEntity && collectorEntity.exported) { - const referencedMetadata: SymbolMetadata = collector.fetchSymbolMetadata(referencedEntity); - const referencedReleaseTag: ReleaseTag = referencedMetadata.maxEffectiveReleaseTag; - - 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 "${referencedEntity.localName}"` - + ` which is marked as ${ReleaseTag.getTagName(referencedReleaseTag)}`, - astDeclaration); - } - } else { - const entryPointFilename: string = path.basename(collector.workingPackage.entryPointSourceFile.fileName); + if (rootSymbol.isExternal) { + continue; + } - if (!alreadyWarnedSymbols.has(referencedEntity)) { - alreadyWarnedSymbols.add(referencedEntity); + collectorEntity = collector.tryGetCollectorEntity(rootSymbol); + localName = collectorEntity?.nameForEmit || rootSymbol.localName; - // 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. - if (!ValidationEnhancer._isEcmaScriptSymbol(referencedEntity)) { + const referencedMetadata: SymbolMetadata = collector.fetchSymbolMetadata(referencedEntity); + referencedReleaseTag = referencedMetadata.maxEffectiveReleaseTag; + } else if (referencedEntity instanceof AstNamespaceImport) { + collectorEntity = collector.tryGetCollectorEntity(referencedEntity); - collector.messageRouter.addAnalyzerIssue(ExtractorMessageId.ForgottenExport, - `The symbol "${rootSymbol.localName}" needs to be exported` - + ` by the entry point ${entryPointFilename}`, - astDeclaration); - } + // TODO: Currently the "import * as ___ from ___" syntax does not yet support doc comments + referencedReleaseTag = ReleaseTag.Public; - } + localName = collectorEntity?.nameForEmit || referencedEntity.localName; + } else { + continue; + } + 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 && + 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 + ); } } } @@ -243,5 +301,4 @@ export class ValidationEnhancer { return false; } - } diff --git a/apps/api-extractor/src/generators/ApiModelGenerator.ts b/apps/api-extractor/src/generators/ApiModelGenerator.ts index aaaeb3935fb..1ca3c340f9a 100644 --- a/apps/api-extractor/src/generators/ApiModelGenerator.ts +++ b/apps/api-extractor/src/generators/ApiModelGenerator.ts @@ -3,8 +3,11 @@ /* eslint-disable no-bitwise */ +import * as path from 'node:path'; + import * as ts from 'typescript'; -import * as tsdoc from '@microsoft/tsdoc'; + +import type * as tsdoc from '@microsoft/tsdoc'; import { ApiModel, ApiClass, @@ -14,15 +17,15 @@ import { ApiNamespace, ApiInterface, ApiPropertySignature, - ApiItemContainerMixin, + type ApiItemContainerMixin, ReleaseTag, ApiProperty, ApiMethodSignature, - IApiParameterOptions, + type IApiParameterOptions, ApiEnum, ApiEnumMember, - IExcerptTokenRange, - IExcerptToken, + type IExcerptTokenRange, + type IExcerptToken, ApiConstructor, ApiConstructSignature, ApiFunction, @@ -30,30 +33,62 @@ import { ApiVariable, ApiTypeAlias, ApiCallSignature, - IApiTypeParameterOptions + type IApiTypeParameterOptions, + EnumMemberOrder } from '@microsoft/api-extractor-model'; +import { Path } from '@rushstack/node-core-library'; -import { Collector } from '../collector/Collector'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ExcerptBuilder, IExcerptBuilderNodeToCapture } from './ExcerptBuilder'; +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 { AstSymbol } from '../analyzer/AstSymbol'; import { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; -import { ApiItemMetadata } from '../collector/ApiItemMetadata'; -import { DeclarationMetadata } from '../collector/DeclarationMetadata'; +import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; +import type { DeclarationMetadata } from '../collector/DeclarationMetadata'; +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'; + +interface IProcessAstEntityContext { + name: string; + isExported: boolean; + 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 readonly docModelEnabled: boolean; - public constructor(collector: Collector) { + public constructor(collector: Collector, extractorConfig: ExtractorConfig) { this._collector = collector; this._apiModel = new ApiModel(); - this._referenceGenerator = new DeclarationReferenceGenerator( - collector.packageJsonLookup, - collector.workingPackage.name, - collector.program, - collector.typeChecker); + 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 { @@ -65,152 +100,245 @@ export class ApiModelGenerator { const apiPackage: ApiPackage = new ApiPackage({ name: this._collector.workingPackage.name, - docComment: packageDocComment + docComment: packageDocComment, + tsdocConfiguration: this._collector.extractorConfig.tsdocConfiguration, + projectFolderUrl: this._collector.extractorConfig.projectFolderUrl }); this._apiModel.addMember(apiPackage); const apiEntryPoint: ApiEntryPoint = new ApiEntryPoint({ name: '' }); apiPackage.addMember(apiEntryPoint); - // Create a CollectorEntity for each top-level export for (const entity of this._collector.entities) { - if (entity.exported) { - if (entity.astEntity instanceof AstSymbol) { - // Skip ancillary declarations; we will process them with the main declaration - for (const astDeclaration of this._collector.getNonAncillaryDeclarations(entity.astEntity)) { - this._processDeclaration(astDeclaration, entity.nameForEmit, apiEntryPoint); - } - } else { - // TODO: Figure out how to represent reexported AstImport objects. Basically we need to introduce a new - // ApiItem subclass for "export alias", similar to a type alias, but representing declarations of the - // form "export { X } from 'external-package'". We can also use this to solve GitHub issue #950. - } + // Only process entities that are exported from the entry point. Entities that are exported from + // `AstNamespaceImport` entities will be processed by `_processAstNamespaceImport`. However, if + // we are including forgotten exports, then process everything. + if (entity.exportedFromEntryPoint || this._collector.extractorConfig.docModelIncludeForgottenExports) { + this._processAstEntity(entity.astEntity, { + name: entity.nameForEmit!, + isExported: entity.exportedFromEntryPoint, + parentApiItem: apiEntryPoint + }); } } return apiPackage; } - private _processDeclaration(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { + private _processAstEntity(astEntity: AstEntity, context: IProcessAstEntityContext): void { + if (astEntity instanceof AstSymbol) { + // Skip ancillary declarations; we will process them with the main declaration + for (const astDeclaration of this._collector.getNonAncillaryDeclarations(astEntity)) { + this._processDeclaration(astDeclaration, context); + } + return; + } + + if (astEntity instanceof AstNamespaceImport) { + // Note that a single API item can belong to two different AstNamespaceImport namespaces. For example: + // + // // file.ts defines "thing()" + // import * as example1 from "./file"; + // import * as example2 from "./file"; + // + // // ...so here we end up with example1.thing() and example2.thing() + // export { example1, example2 } + // + // The current logic does not try to associate "thing()" with a specific parent. Instead + // the API documentation will show duplicated entries for example1.thing() and example2.thing(). + // + // This could be improved in the future, but it requires a stable mechanism for choosing an associated parent. + // For thoughts about this: https://github.com/microsoft/rushstack/issues/1308 + this._processAstNamespaceImport(astEntity, context); + return; + } + + // TODO: Figure out how to represent reexported AstImport objects. Basically we need to introduce a new + // ApiItem subclass for "export alias", similar to a type alias, but representing declarations of the + // form "export { X } from 'external-package'". We can also use this to solve GitHub issue #950. + } + + private _processAstNamespaceImport( + astNamespaceImport: AstNamespaceImport, + context: IProcessAstEntityContext + ): void { + const astModule: AstModule = astNamespaceImport.astModule; + const { name, isExported, parentApiItem } = context; + const containerKey: string = ApiNamespace.getContainerKey(name); + const fileUrlPath: string = this._getFileUrlPath(astNamespaceImport.declaration); + + let apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiNamespace; + + if (apiNamespace === undefined) { + apiNamespace = new ApiNamespace({ + name, + docComment: undefined, + releaseTag: ReleaseTag.None, + excerptTokens: [], + isExported, + fileUrlPath + }); + parentApiItem.addMember(apiNamespace); + } + + astModule.astModuleExportInfo!.exportedLocalEntities.forEach( + (exportedEntity: AstEntity, exportedName: string) => { + this._processAstEntity(exportedEntity, { + name: exportedName, + isExported: true, + parentApiItem: apiNamespace! + }); + } + ); + } + private _processDeclaration(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { if ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) { return; // trim out private declarations } const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; - if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) { - return; // trim out items marked as "@internal" or "@alpha" + if (this._releaseTagsToTrim?.has(releaseTag)) { + return; } switch (astDeclaration.declaration.kind) { case ts.SyntaxKind.CallSignature: - this._processApiCallSignature(astDeclaration, exportedName, parentApiItem); + this._processApiCallSignature(astDeclaration, context); break; case ts.SyntaxKind.Constructor: - this._processApiConstructor(astDeclaration, exportedName, parentApiItem); + this._processApiConstructor(astDeclaration, context); break; case ts.SyntaxKind.ConstructSignature: - this._processApiConstructSignature(astDeclaration, exportedName, parentApiItem); + this._processApiConstructSignature(astDeclaration, context); break; case ts.SyntaxKind.ClassDeclaration: - this._processApiClass(astDeclaration, exportedName, parentApiItem); + this._processApiClass(astDeclaration, context); break; case ts.SyntaxKind.EnumDeclaration: - this._processApiEnum(astDeclaration, exportedName, parentApiItem); + this._processApiEnum(astDeclaration, context); break; case ts.SyntaxKind.EnumMember: - this._processApiEnumMember(astDeclaration, exportedName, parentApiItem); + this._processApiEnumMember(astDeclaration, context); break; case ts.SyntaxKind.FunctionDeclaration: - this._processApiFunction(astDeclaration, exportedName, parentApiItem); + this._processApiFunction(astDeclaration, context); break; case ts.SyntaxKind.GetAccessor: - this._processApiProperty(astDeclaration, exportedName, parentApiItem); + this._processApiProperty(astDeclaration, context); + break; + + case ts.SyntaxKind.SetAccessor: + this._processApiProperty(astDeclaration, context); break; case ts.SyntaxKind.IndexSignature: - this._processApiIndexSignature(astDeclaration, exportedName, parentApiItem); + this._processApiIndexSignature(astDeclaration, context); break; case ts.SyntaxKind.InterfaceDeclaration: - this._processApiInterface(astDeclaration, exportedName, parentApiItem); + this._processApiInterface(astDeclaration, context); break; case ts.SyntaxKind.MethodDeclaration: - this._processApiMethod(astDeclaration, exportedName, parentApiItem); + this._processApiMethod(astDeclaration, context); break; case ts.SyntaxKind.MethodSignature: - this._processApiMethodSignature(astDeclaration, exportedName, parentApiItem); + this._processApiMethodSignature(astDeclaration, context); break; case ts.SyntaxKind.ModuleDeclaration: - this._processApiNamespace(astDeclaration, exportedName, parentApiItem); + this._processApiNamespace(astDeclaration, context); break; case ts.SyntaxKind.PropertyDeclaration: - this._processApiProperty(astDeclaration, exportedName, parentApiItem); + this._processApiProperty(astDeclaration, context); break; case ts.SyntaxKind.PropertySignature: - this._processApiPropertySignature(astDeclaration, exportedName, parentApiItem); + this._processApiPropertySignature(astDeclaration, context); break; case ts.SyntaxKind.TypeAliasDeclaration: - this._processApiTypeAlias(astDeclaration, exportedName, parentApiItem); + this._processApiTypeAlias(astDeclaration, context); break; case ts.SyntaxKind.VariableDeclaration: - this._processApiVariable(astDeclaration, exportedName, parentApiItem); + // check for arrow functions in variable declaration + const functionDeclaration: ts.FunctionDeclaration | undefined = + this._tryFindFunctionDeclaration(astDeclaration); + if (functionDeclaration) { + this._processApiFunction(astDeclaration, context, functionDeclaration); + } else { + this._processApiVariable(astDeclaration, context); + } break; default: - // ignore unknown types + // ignore unknown types } } - private _processChildDeclarations(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { + private _tryFindFunctionDeclaration(astDeclaration: AstDeclaration): ts.FunctionDeclaration | undefined { + const children: readonly ts.Node[] = astDeclaration.declaration.getChildren( + astDeclaration.declaration.getSourceFile() + ); + return children.find(ts.isFunctionTypeNode) as ts.FunctionDeclaration | undefined; + } + + private _processChildDeclarations(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { for (const childDeclaration of astDeclaration.children) { - this._processDeclaration(childDeclaration, undefined, parentApiItem); + this._processDeclaration(childDeclaration, { + ...context, + name: childDeclaration.astSymbol.localName + }); } } - private _processApiCallSignature(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - + private _processApiCallSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiCallSignature.getContainerKey(overloadIndex); - let apiCallSignature: ApiCallSignature | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiCallSignature; + let apiCallSignature: ApiCallSignature | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiCallSignature; if (apiCallSignature === undefined) { - const callSignature: ts.CallSignatureDeclaration = astDeclaration.declaration as ts.CallSignatureDeclaration; + const callSignature: ts.CallSignatureDeclaration = + astDeclaration.declaration as ts.CallSignatureDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: callSignature.type, tokenRange: returnTypeTokenRange }); - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - callSignature.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + callSignature.typeParameters + ); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, callSignature.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + callSignature.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(callSignature); apiCallSignature = new ApiCallSignature({ docComment, @@ -219,50 +347,57 @@ export class ApiModelGenerator { parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + fileUrlPath }); parentApiItem.addMember(apiCallSignature); } } - private _processApiConstructor(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - + private _processApiConstructor(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiConstructor.getContainerKey(overloadIndex); - let apiConstructor: ApiConstructor | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiConstructor; + let apiConstructor: ApiConstructor | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiConstructor; if (apiConstructor === undefined) { - const constructorDeclaration: ts.ConstructorDeclaration = astDeclaration.declaration as ts.ConstructorDeclaration; + const constructorDeclaration: ts.ConstructorDeclaration = + astDeclaration.declaration as ts.ConstructorDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, - constructorDeclaration.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + constructorDeclaration.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0; + const fileUrlPath: string = this._getFileUrlPath(constructorDeclaration); apiConstructor = new ApiConstructor({ docComment, releaseTag, + isProtected, parameters, overloadIndex, - excerptTokens + excerptTokens, + fileUrlPath }); parentApiItem.addMember(apiConstructor); } } - private _processApiClass(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiClass(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiClass.getContainerKey(name); let apiClass: ApiClass | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiClass; @@ -272,8 +407,10 @@ export class ApiModelGenerator { const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - classDeclaration.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + classDeclaration.typeParameters + ); let extendsTokenRange: IExcerptTokenRange | undefined = undefined; const implementsTokenRanges: IExcerptTokenRange[] = []; @@ -282,13 +419,13 @@ 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}); + nodesToCapture.push({ node: heritageClause.types[0], tokenRange: 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}); + nodesToCapture.push({ node: heritageType, tokenRange: implementsTokenRange }); } } } @@ -297,50 +434,68 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isAbstract: boolean = + (ts.getCombinedModifierFlags(classDeclaration) & ts.ModifierFlags.Abstract) !== 0; + const fileUrlPath: string = this._getFileUrlPath(classDeclaration); apiClass = new ApiClass({ name, + isAbstract, docComment, releaseTag, excerptTokens, typeParameters, extendsTokenRange, - implementsTokenRanges + implementsTokenRanges, + isExported, + fileUrlPath }); parentApiItem.addMember(apiClass); } - this._processChildDeclarations(astDeclaration, exportedName, apiClass); + this._processChildDeclarations(astDeclaration, { + ...context, + parentApiItem: apiClass + }); } - private _processApiConstructSignature(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - + private _processApiConstructSignature( + astDeclaration: AstDeclaration, + context: IProcessAstEntityContext + ): void { + const { parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiConstructSignature.getContainerKey(overloadIndex); - let apiConstructSignature: ApiConstructSignature | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiConstructSignature; + let apiConstructSignature: ApiConstructSignature | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiConstructSignature; if (apiConstructSignature === undefined) { - const constructSignature: ts.ConstructSignatureDeclaration = astDeclaration.declaration as - ts.ConstructSignatureDeclaration; + const constructSignature: ts.ConstructSignatureDeclaration = + astDeclaration.declaration as ts.ConstructSignatureDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: constructSignature.type, tokenRange: returnTypeTokenRange }); - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - constructSignature.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + constructSignature.typeParameters + ); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, constructSignature.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + constructSignature.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(constructSignature); apiConstructSignature = new ApiConstructSignature({ docComment, @@ -349,17 +504,16 @@ export class ApiModelGenerator { parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + fileUrlPath }); parentApiItem.addMember(apiConstructSignature); } } - private _processApiEnum(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiEnum(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiEnum.getContainerKey(name); let apiEnum: ApiEnum | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnum; @@ -369,79 +523,102 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const preserveMemberOrder: boolean = + this._collector.extractorConfig.enumMemberOrder === EnumMemberOrder.Preserve; + const fileUrlPath: string = this._getFileUrlPath(astDeclaration.declaration); - apiEnum = new ApiEnum({ name, docComment, releaseTag, excerptTokens }); + apiEnum = new ApiEnum({ + name, + docComment, + releaseTag, + excerptTokens, + preserveMemberOrder, + isExported, + fileUrlPath + }); parentApiItem.addMember(apiEnum); } - this._processChildDeclarations(astDeclaration, exportedName, apiEnum); + this._processChildDeclarations(astDeclaration, { + ...context, + parentApiItem: apiEnum + }); } - private _processApiEnumMember(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiEnumMember(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, parentApiItem } = context; const containerKey: string = ApiEnumMember.getContainerKey(name); - let apiEnumMember: ApiEnumMember | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnumMember; + let apiEnumMember: ApiEnumMember | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiEnumMember; if (apiEnumMember === undefined) { const enumMember: ts.EnumMember = astDeclaration.declaration as ts.EnumMember; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; - const initializerTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange }); + let initializerTokenRange: IExcerptTokenRange | undefined = undefined; + if (enumMember.initializer) { + initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); + nodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange }); + } const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(enumMember); apiEnumMember = new ApiEnumMember({ name, docComment, releaseTag, excerptTokens, - initializerTokenRange + initializerTokenRange, + fileUrlPath }); parentApiItem.addMember(apiEnumMember); } } - private _processApiFunction(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiFunction( + astDeclaration: AstDeclaration, + context: IProcessAstEntityContext, + altFunctionDeclaration?: ts.FunctionDeclaration + ): void { + const { name, isExported, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiFunction.getContainerKey(name, overloadIndex); - let apiFunction: ApiFunction | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiFunction; + let apiFunction: ApiFunction | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiFunction; if (apiFunction === undefined) { - const functionDeclaration: ts.FunctionDeclaration = astDeclaration.declaration as ts.FunctionDeclaration; + const functionDeclaration: ts.FunctionDeclaration = + altFunctionDeclaration ?? (astDeclaration.declaration as ts.FunctionDeclaration); const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: functionDeclaration.type, tokenRange: returnTypeTokenRange }); - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - functionDeclaration.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + functionDeclaration.typeParameters + ); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, - functionDeclaration.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + functionDeclaration.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; - if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) { - return; // trim out items marked as "@internal" or "@alpha" - } + const fileUrlPath: string = this._getFileUrlPath(functionDeclaration); apiFunction = new ApiFunction({ name, @@ -451,36 +628,44 @@ export class ApiModelGenerator { parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + isExported, + fileUrlPath }); parentApiItem.addMember(apiFunction); } } - private _processApiIndexSignature(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - + private _processApiIndexSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiIndexSignature.getContainerKey(overloadIndex); - let apiIndexSignature: ApiIndexSignature | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiIndexSignature; + let apiIndexSignature: ApiIndexSignature | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiIndexSignature; if (apiIndexSignature === undefined) { - const indexSignature: ts.IndexSignatureDeclaration = astDeclaration.declaration as ts.IndexSignatureDeclaration; + const indexSignature: ts.IndexSignatureDeclaration = + astDeclaration.declaration as ts.IndexSignatureDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: indexSignature.type, tokenRange: returnTypeTokenRange }); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, indexSignature.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + indexSignature.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isReadonly: boolean = this._isReadonly(astDeclaration); + const fileUrlPath: string = this._getFileUrlPath(indexSignature); apiIndexSignature = new ApiIndexSignature({ docComment, @@ -488,28 +673,33 @@ export class ApiModelGenerator { parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + isReadonly, + fileUrlPath }); parentApiItem.addMember(apiIndexSignature); } } - private _processApiInterface(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiInterface(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiInterface.getContainerKey(name); - let apiInterface: ApiInterface | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiInterface; + let apiInterface: ApiInterface | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiInterface; if (apiInterface === undefined) { - const interfaceDeclaration: ts.InterfaceDeclaration = astDeclaration.declaration as ts.InterfaceDeclaration; + const interfaceDeclaration: ts.InterfaceDeclaration = + astDeclaration.declaration as ts.InterfaceDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - interfaceDeclaration.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + interfaceDeclaration.typeParameters + ); const extendsTokenRanges: IExcerptTokenRange[] = []; @@ -518,7 +708,7 @@ export class ApiModelGenerator { for (const heritageType of heritageClause.types) { const extendsTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); extendsTokenRanges.push(extendsTokenRange); - nodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange}); + nodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange }); } } } @@ -527,6 +717,7 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(interfaceDeclaration); apiInterface = new ApiInterface({ name, @@ -534,20 +725,22 @@ export class ApiModelGenerator { releaseTag, excerptTokens, typeParameters, - extendsTokenRanges + extendsTokenRanges, + isExported, + fileUrlPath }); parentApiItem.addMember(apiInterface); } - this._processChildDeclarations(astDeclaration, exportedName, apiInterface); + this._processChildDeclarations(astDeclaration, { + ...context, + parentApiItem: apiInterface + }); } - private _processApiMethod(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; - + private _processApiMethod(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, parentApiItem } = context; const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiMethod.getContainerKey(name, isStatic, overloadIndex); @@ -562,10 +755,15 @@ export class ApiModelGenerator { const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange }); - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - methodDeclaration.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + methodDeclaration.typeParameters + ); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodDeclaration.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + methodDeclaration.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); @@ -574,33 +772,43 @@ export class ApiModelGenerator { if (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) { return; // trim out items marked as "@internal" or "@alpha" } + const isOptional: boolean = + (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; + const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0; + const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0; + const fileUrlPath: string = this._getFileUrlPath(methodDeclaration); apiMethod = new ApiMethod({ name, + isAbstract, docComment, releaseTag, + isProtected, isStatic, + isOptional, typeParameters, parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + fileUrlPath }); parentApiItem.addMember(apiMethod); } } - private _processApiMethodSignature(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; - + private _processApiMethodSignature( + astDeclaration: AstDeclaration, + context: IProcessAstEntityContext + ): void { + const { name, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiMethodSignature.getContainerKey(name, overloadIndex); - let apiMethodSignature: ApiMethodSignature | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiMethodSignature; + let apiMethodSignature: ApiMethodSignature | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiMethodSignature; if (apiMethodSignature === undefined) { const methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature; @@ -610,78 +818,129 @@ export class ApiModelGenerator { const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange }); - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - methodSignature.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + methodSignature.typeParameters + ); - const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, methodSignature.parameters); + const parameters: IApiParameterOptions[] = this._captureParameters( + nodesToCapture, + methodSignature.parameters + ); const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isOptional: boolean = + (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; + const fileUrlPath: string = this._getFileUrlPath(methodSignature); apiMethodSignature = new ApiMethodSignature({ name, docComment, releaseTag, + isOptional, typeParameters, parameters, overloadIndex, excerptTokens, - returnTypeTokenRange + returnTypeTokenRange, + fileUrlPath }); parentApiItem.addMember(apiMethodSignature); } } - private _processApiNamespace(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiNamespace(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiNamespace.getContainerKey(name); - let apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiNamespace; + let apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiNamespace; if (apiNamespace === undefined) { const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, []); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(astDeclaration.declaration); - apiNamespace = new ApiNamespace({ name, docComment, releaseTag, excerptTokens }); + apiNamespace = new ApiNamespace({ + name, + docComment, + releaseTag, + excerptTokens, + isExported, + fileUrlPath + }); parentApiItem.addMember(apiNamespace); } - this._processChildDeclarations(astDeclaration, exportedName, apiNamespace); + this._processChildDeclarations(astDeclaration, { + ...context, + parentApiItem: apiNamespace + }); } - private _processApiProperty(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; - + private _processApiProperty(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, parentApiItem } = context; const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0; - const containerKey: string = ApiProperty.getContainerKey(name, isStatic); - let apiProperty: ApiProperty | undefined - = parentApiItem.tryGetMemberByKey(containerKey) as ApiProperty; + let apiProperty: ApiProperty | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiProperty; if (apiProperty === undefined) { - const propertyDeclaration: ts.PropertyDeclaration = astDeclaration.declaration as ts.PropertyDeclaration; - + const declaration: ts.Declaration = astDeclaration.declaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: propertyDeclaration.type, tokenRange: propertyTypeTokenRange }); + let propertyTypeNode: ts.TypeNode | undefined; + + if (ts.isPropertyDeclaration(declaration) || ts.isGetAccessorDeclaration(declaration)) { + propertyTypeNode = declaration.type; + } + + if (ts.isSetAccessorDeclaration(declaration)) { + // Note that TypeScript always reports an error if a setter does not have exactly one parameter. + propertyTypeNode = declaration.parameters[0].type; + } + + nodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange }); + + let initializerTokenRange: IExcerptTokenRange | undefined = undefined; + if (ts.isPropertyDeclaration(declaration) && declaration.initializer) { + initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); + nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange }); + } const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; - - apiProperty = new ApiProperty({ name, docComment, releaseTag, isStatic, excerptTokens, propertyTypeTokenRange }); + const isOptional: boolean = + (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; + const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0; + const isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0; + const isReadonly: boolean = this._isReadonly(astDeclaration); + const fileUrlPath: string = this._getFileUrlPath(declaration); + + apiProperty = new ApiProperty({ + name, + docComment, + releaseTag, + isAbstract, + isProtected, + isStatic, + isOptional, + isReadonly, + excerptTokens, + propertyTypeTokenRange, + initializerTokenRange, + fileUrlPath + }); parentApiItem.addMember(apiProperty); } else { // If the property was already declared before (via a merged interface declaration), @@ -689,14 +948,16 @@ export class ApiModelGenerator { } } - private _processApiPropertySignature(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiPropertySignature( + astDeclaration: AstDeclaration, + context: IProcessAstEntityContext + ): void { + const { name, parentApiItem } = context; const containerKey: string = ApiPropertySignature.getContainerKey(name); - let apiPropertySignature: ApiPropertySignature | undefined - = parentApiItem.tryGetMemberByKey(containerKey) as ApiPropertySignature; + let apiPropertySignature: ApiPropertySignature | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiPropertySignature; if (apiPropertySignature === undefined) { const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature; @@ -710,13 +971,20 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isOptional: boolean = + (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0; + const isReadonly: boolean = this._isReadonly(astDeclaration); + const fileUrlPath: string = this._getFileUrlPath(propertySignature); apiPropertySignature = new ApiPropertySignature({ name, docComment, releaseTag, + isOptional, excerptTokens, - propertyTypeTokenRange + propertyTypeTokenRange, + isReadonly, + fileUrlPath }); parentApiItem.addMember(apiPropertySignature); @@ -726,23 +994,25 @@ export class ApiModelGenerator { } } - private _processApiTypeAlias(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiTypeAlias(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiTypeAlias.getContainerKey(name); - let apiTypeAlias: ApiTypeAlias | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiTypeAlias; + let apiTypeAlias: ApiTypeAlias | undefined = parentApiItem.tryGetMemberByKey( + containerKey + ) as ApiTypeAlias; if (apiTypeAlias === undefined) { - const typeAliasDeclaration: ts.TypeAliasDeclaration = astDeclaration.declaration as ts.TypeAliasDeclaration; + const typeAliasDeclaration: ts.TypeAliasDeclaration = + astDeclaration.declaration as ts.TypeAliasDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; - const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(nodesToCapture, - typeAliasDeclaration.typeParameters); + const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( + nodesToCapture, + typeAliasDeclaration.typeParameters + ); const typeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: typeAliasDeclaration.type, tokenRange: typeTokenRange }); @@ -751,6 +1021,7 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const fileUrlPath: string = this._getFileUrlPath(typeAliasDeclaration); apiTypeAlias = new ApiTypeAlias({ name, @@ -758,37 +1029,55 @@ export class ApiModelGenerator { typeParameters, releaseTag, excerptTokens, - typeTokenRange + typeTokenRange, + isExported, + fileUrlPath }); parentApiItem.addMember(apiTypeAlias); } } - private _processApiVariable(astDeclaration: AstDeclaration, exportedName: string | undefined, - parentApiItem: ApiItemContainerMixin): void { - - const name: string = exportedName ? exportedName : astDeclaration.astSymbol.localName; + private _processApiVariable(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { + const { name, isExported, parentApiItem } = context; const containerKey: string = ApiVariable.getContainerKey(name); - let apiVariable: ApiVariable | undefined = parentApiItem.tryGetMemberByKey(containerKey) as - ApiVariable; + let apiVariable: ApiVariable | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiVariable; if (apiVariable === undefined) { - const variableDeclaration: ts.VariableDeclaration = astDeclaration.declaration as ts.VariableDeclaration; + const variableDeclaration: ts.VariableDeclaration = + astDeclaration.declaration as ts.VariableDeclaration; const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; const variableTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: variableDeclaration.type, tokenRange: variableTypeTokenRange }); + let initializerTokenRange: IExcerptTokenRange | undefined = undefined; + if (variableDeclaration.initializer) { + initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); + nodesToCapture.push({ node: variableDeclaration.initializer, tokenRange: initializerTokenRange }); + } + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + const isReadonly: boolean = this._isReadonly(astDeclaration); + const fileUrlPath: string = this._getFileUrlPath(variableDeclaration); - apiVariable = new ApiVariable({ name, docComment, releaseTag, excerptTokens, variableTypeTokenRange }); + apiVariable = new ApiVariable({ + name, + docComment, + releaseTag, + excerptTokens, + variableTypeTokenRange, + initializerTokenRange, + isReadonly, + isExported, + fileUrlPath + }); parentApiItem.addMember(apiVariable); } @@ -797,9 +1086,10 @@ export class ApiModelGenerator { /** * @param nodesToCapture - A list of child nodes whose token ranges we want to capture */ - private _buildExcerptTokens(astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[]): IExcerptToken[] { - + private _buildExcerptTokens( + astDeclaration: AstDeclaration, + nodesToCapture: IExcerptBuilderNodeToCapture[] + ): IExcerptToken[] { const excerptTokens: IExcerptToken[] = []; // Build the main declaration @@ -810,15 +1100,21 @@ export class ApiModelGenerator { // Add any ancillary declarations for (const ancillaryDeclaration of declarationMetadata.ancillaryDeclarations) { ExcerptBuilder.addBlankLine(excerptTokens); - ExcerptBuilder.addDeclaration(excerptTokens, ancillaryDeclaration, nodesToCapture, this._referenceGenerator); + ExcerptBuilder.addDeclaration( + excerptTokens, + ancillaryDeclaration, + nodesToCapture, + this._referenceGenerator + ); } return excerptTokens; } - private _captureTypeParameters(nodesToCapture: IExcerptBuilderNodeToCapture[], typeParameterNodes: - ts.NodeArray | undefined): IApiTypeParameterOptions[] { - + private _captureTypeParameters( + nodesToCapture: IExcerptBuilderNodeToCapture[], + typeParameterNodes: ts.NodeArray | undefined + ): IApiTypeParameterOptions[] { const typeParameters: IApiTypeParameterOptions[] = []; if (typeParameterNodes) { for (const typeParameter of typeParameterNodes) { @@ -838,18 +1134,66 @@ export class ApiModelGenerator { return typeParameters; } - private _captureParameters(nodesToCapture: IExcerptBuilderNodeToCapture[], - parameterNodes: ts.NodeArray): IApiParameterOptions[] { - + private _captureParameters( + nodesToCapture: IExcerptBuilderNodeToCapture[], + 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 + parameterTypeTokenRange, + isOptional: this._collector.typeChecker.isOptionalParameter(parameter) }); } return parameters; } + + private _isReadonly(astDeclaration: AstDeclaration): boolean { + switch (astDeclaration.declaration.kind) { + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.IndexSignature: + case ts.SyntaxKind.PropertyDeclaration: + case ts.SyntaxKind.PropertySignature: + case ts.SyntaxKind.SetAccessor: + case ts.SyntaxKind.VariableDeclaration: { + const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); + const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; + const declarationMetadata: DeclarationMetadata = + this._collector.fetchDeclarationMetadata(astDeclaration); + + const hasReadonlyModifier: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Readonly) !== 0; + const hasReadonlyDocTag: boolean = !!docComment?.modifierTagSet?.hasTagName('@readonly'); + const isGetterWithNoSetter: boolean = + ts.isGetAccessorDeclaration(astDeclaration.declaration) && + declarationMetadata.ancillaryDeclarations.length === 0; + const isVarConst: boolean = + ts.isVariableDeclaration(astDeclaration.declaration) && + TypeScriptInternals.isVarConst(astDeclaration.declaration); + + return hasReadonlyModifier || hasReadonlyDocTag || isGetterWithNoSetter || isVarConst; + } + default: { + // Readonly-ness does not make sense for any other declaration kind. + return false; + } + } + } + + private _getFileUrlPath(declaration: ts.Declaration): string { + const sourceFile: ts.SourceFile = declaration.getSourceFile(); + const sourceLocation: ISourceLocation = this._collector.sourceMapper.getSourceLocation({ + sourceFile, + pos: declaration.pos + }); + + let result: string = path.relative( + this._collector.extractorConfig.projectFolder, + sourceLocation.sourceFilePath + ); + result = Path.convertToSlashes(result); + return result; + } } diff --git a/apps/api-extractor/src/generators/ApiReportGenerator.ts b/apps/api-extractor/src/generators/ApiReportGenerator.ts index 2d76419f6c7..e59d7603ba6 100644 --- a/apps/api-extractor/src/generators/ApiReportGenerator.ts +++ b/apps/api-extractor/src/generators/ApiReportGenerator.ts @@ -2,23 +2,31 @@ // 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'; import { Span } from '../analyzer/Span'; -import { CollectorEntity } from '../collector/CollectorEntity'; +import type { CollectorEntity } from '../collector/CollectorEntity'; import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ApiItemMetadata } from '../collector/ApiItemMetadata'; +import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; import { AstImport } from '../analyzer/AstImport'; import { AstSymbol } from '../analyzer/AstSymbol'; -import { ExtractorMessage } from '../api/ExtractorMessage'; -import { StringWriter } from './StringWriter'; +import type { ExtractorMessage } from '../api/ExtractorMessage'; +import { IndentedWriter } from './IndentedWriter'; import { DtsEmitHelpers } from './DtsEmitHelpers'; +import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; +import type { AstEntity } from '../analyzer/AstEntity'; +import type { IAstModuleExportInfo } from '../analyzer/AstModule'; +import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +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; + private static _trimSpacesRegExp: RegExp = / +$/gm; /** * Compares the contents of two API files that were created using ApiFileGenerator, @@ -27,43 +35,74 @@ export class ApiReportGenerator { * might be introduced by a tool, e.g. Git newline normalization or an editor that strips * whitespace when saving. */ - public static areEquivalentApiFileContents(actualFileContent: string, expectedFileContent: string): boolean { + public static areEquivalentApiFileContents( + actualFileContent: string, + expectedFileContent: string + ): boolean { // NOTE: "\s" also matches "\r" and "\n" const normalizedActual: string = actualFileContent.replace(/[\s]+/g, ' '); const normalizedExpected: string = expectedFileContent.replace(/[\s]+/g, ' '); return normalizedActual === normalizedExpected; } - public static generateReviewFileContent(collector: Collector): string { - const stringWriter: StringWriter = new StringWriter(); + /** + * Generates and returns the API report contents as a string. + * + * @param reportVariant - The release level with which the report is associated. + * Can also be viewed as the minimal release level of items that should be included in the report. + */ + public static generateReviewFileContent(collector: Collector, reportVariant: ApiReportVariant): string { + const writer: IndentedWriter = new IndentedWriter(); + writer.trimLeadingSpaces = true; - stringWriter.writeLine([ - `## API Report File for "${collector.workingPackage.name}"`, - ``, - `> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).`, - `` - ].join('\n')); + function capitalizeFirstLetter(input: string): string { + return input === '' ? '' : `${input[0].toLocaleUpperCase()}${input.slice(1)}`; + } + + // For backwards compatibility, don't emit "complete" in report text for untrimmed reports. + const releaseLevelPrefix: string = + reportVariant === 'complete' ? '' : `${capitalizeFirstLetter(reportVariant)} `; + writer.writeLine( + [ + `## ${releaseLevelPrefix}API Report File for "${collector.workingPackage.name}"`, + ``, + `> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).`, + `` + ].join('\n') + ); // Write the opening delimiter for the Markdown code fence - stringWriter.writeLine('```ts\n'); + writer.writeLine('```ts\n'); + + // Emit the triple slash directives + for (const typeDirectiveReference of Array.from(collector.dtsTypeReferenceDirectives).sort()) { + // https://github.com/microsoft/TypeScript/blob/611ebc7aadd7a44a4c0447698bfda9222a78cb66/src/compiler/declarationEmitter.ts#L162 + writer.writeLine(`/// `); + } + for (const libDirectiveReference of Array.from(collector.dtsLibReferenceDirectives).sort()) { + writer.writeLine(`/// `); + } + writer.ensureSkippedLine(); // Emit the imports - let importsEmitted: boolean = false; for (const entity of collector.entities) { if (entity.astEntity instanceof AstImport) { - DtsEmitHelpers.emitImport(stringWriter, entity, entity.astEntity); - importsEmitted = true; + DtsEmitHelpers.emitImport(writer, entity, entity.astEntity); } } - - if (importsEmitted) { - stringWriter.writeLine(); - } + writer.ensureSkippedLine(); // Emit the regular declarations for (const entity of collector.entities) { - if (entity.exported) { + const astEntity: AstEntity = entity.astEntity; + const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity); + const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata?.maxEffectiveReleaseTag ?? ReleaseTag.None; + + if (!this._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 // the associated export statement. @@ -79,13 +118,12 @@ export class ApiReportGenerator { } } - if (entity.astEntity instanceof AstSymbol) { + if (astEntity instanceof AstSymbol) { // Emit all the declarations for this entity - for (const astDeclaration of entity.astEntity.astDeclarations || []) { - + for (const astDeclaration of astEntity.astDeclarations || []) { // Get the messages associated with this declaration - const fetchedMessages: ExtractorMessage[] = collector.messageRouter - .fetchAssociatedMessagesForReviewFile(astDeclaration); + const fetchedMessages: ExtractorMessage[] = + collector.messageRouter.fetchAssociatedMessagesForReviewFile(astDeclaration); // Peel off the messages associated with an export statement and store them // in IExportToEmit.associatedMessages (to be processed later). The remaining messages will @@ -93,7 +131,9 @@ export class ApiReportGenerator { const messagesToReport: ExtractorMessage[] = []; for (const message of fetchedMessages) { if (message.properties.exportName) { - const exportToEmit: IExportToEmit | undefined = exportsToEmit.get(message.properties.exportName); + const exportToEmit: IExportToEmit | undefined = exportsToEmit.get( + message.properties.exportName + ); if (exportToEmit) { exportToEmit.associatedMessages.push(message); continue; @@ -102,72 +142,149 @@ export class ApiReportGenerator { messagesToReport.push(message); } - stringWriter.write(ApiReportGenerator._getAedocSynopsis(collector, astDeclaration, messagesToReport)); + if (this._shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) { + writer.ensureSkippedLine(); + writer.write(ApiReportGenerator._getAedocSynopsis(collector, astDeclaration, messagesToReport)); - const span: Span = new Span(astDeclaration.declaration); + const span: Span = new Span(astDeclaration.declaration); - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - if (apiItemMetadata.isPreapproved) { - ApiReportGenerator._modifySpanForPreapproved(span); - } else { - ApiReportGenerator._modifySpan(collector, span, entity, astDeclaration, false); + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + if (apiItemMetadata.isPreapproved) { + ApiReportGenerator._modifySpanForPreapproved(span); + } else { + ApiReportGenerator._modifySpan(collector, span, entity, astDeclaration, false, reportVariant); + } + + span.writeModifiedText(writer); + writer.ensureNewLine(); } + } + } - span.writeModifiedText(stringWriter.stringBuilder); - stringWriter.writeLine('\n'); + if (astEntity instanceof AstNamespaceImport) { + const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); + + if (entity.nameForEmit === undefined) { + // This should never happen + throw new InternalError('referencedEntry.nameForEmit is undefined'); + } + + 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 star export, which is not supported:\n` + + SourceFileLocationFormatter.formatDeclaration(astEntity.declaration) + ); } + + // 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). + + writer.ensureSkippedLine(); + 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 (collectorEntity.nameForEmit === exportedName) { + exportClauses.push(collectorEntity.nameForEmit); + } else { + exportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`); + } + } + writer.writeLine(exportClauses.join(',\n')); + + writer.decreaseIndent(); + writer.writeLine('}'); // end of "export { ... }" + writer.decreaseIndent(); + writer.writeLine('}'); // end of "declare namespace { ... }" } // Now emit the export statements for this entity. for (const exportToEmit of exportsToEmit.values()) { // Write any associated messages - for (const message of exportToEmit.associatedMessages) { - ApiReportGenerator._writeLineAsComments(stringWriter, - 'Warning: ' + message.formatMessageWithoutLocation()); + if (exportToEmit.associatedMessages.length > 0) { + writer.ensureSkippedLine(); + for (const message of exportToEmit.associatedMessages) { + ApiReportGenerator._writeLineAsComments( + writer, + 'Warning: ' + message.formatMessageWithoutLocation() + ); + } } - DtsEmitHelpers.emitNamedExport(stringWriter, exportToEmit.exportName, entity); - stringWriter.writeLine(); + DtsEmitHelpers.emitNamedExport(writer, exportToEmit.exportName, entity); } + writer.ensureSkippedLine(); } } - DtsEmitHelpers.emitStarExports(stringWriter, collector); + DtsEmitHelpers.emitStarExports(writer, collector); // Write the unassociated warnings at the bottom of the file - const unassociatedMessages: ExtractorMessage[] = collector.messageRouter - .fetchUnassociatedMessagesForReviewFile(); + const unassociatedMessages: ExtractorMessage[] = + collector.messageRouter.fetchUnassociatedMessagesForReviewFile(); if (unassociatedMessages.length > 0) { - stringWriter.writeLine(); - ApiReportGenerator._writeLineAsComments(stringWriter, 'Warnings were encountered during analysis:'); - ApiReportGenerator._writeLineAsComments(stringWriter, ''); + writer.ensureSkippedLine(); + ApiReportGenerator._writeLineAsComments(writer, 'Warnings were encountered during analysis:'); + ApiReportGenerator._writeLineAsComments(writer, ''); for (const unassociatedMessage of unassociatedMessages) { - ApiReportGenerator._writeLineAsComments(stringWriter, unassociatedMessage.formatMessageWithLocation( - collector.workingPackage.packageFolder - )); + ApiReportGenerator._writeLineAsComments( + writer, + unassociatedMessage.formatMessageWithLocation(collector.workingPackage.packageFolder) + ); } } if (collector.workingPackage.tsdocComment === undefined) { - stringWriter.writeLine(); - ApiReportGenerator._writeLineAsComments(stringWriter, '(No @packageDocumentation comment for this package)'); + writer.ensureSkippedLine(); + ApiReportGenerator._writeLineAsComments(writer, '(No @packageDocumentation comment for this package)'); } // Write the closing delimiter for the Markdown code fence - stringWriter.writeLine('\n```'); + writer.ensureSkippedLine(); + writer.writeLine('```'); // Remove any trailing spaces - return stringWriter.toString().replace(ApiReportGenerator._TrimSpacesRegExp, ''); + return writer.toString().replace(ApiReportGenerator._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): void { - + private static _modifySpan( + collector: Collector, + span: Span, + entity: CollectorEntity, + astDeclaration: AstDeclaration, + insideTypeLiteral: boolean, + reportVariant: ApiReportVariant + ): void { // Should we process this declaration at all? - if ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) { // eslint-disable-line no-bitwise + if (!ApiReportGenerator._shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) { span.modification.skipAll(); return; } @@ -228,7 +345,7 @@ export class ApiReportGenerator { } break; - case ts.SyntaxKind.VariableDeclaration: + 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 @@ -237,14 +354,17 @@ export class ApiReportGenerator { // 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]); + 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()); + const listPrefix: string = list + .getSourceFile() + .text.substring(list.getStart(), list.declarations[0].getStart()); span.modification.prefix = listPrefix + span.modification.prefix; span.modification.suffix = ';'; @@ -255,7 +375,7 @@ export class ApiReportGenerator { break; case ts.SyntaxKind.Identifier: - const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForIdentifierNode( + const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( span.node as ts.Identifier ); @@ -278,6 +398,24 @@ export class ApiReportGenerator { case ts.SyntaxKind.TypeLiteral: insideTypeLiteral = true; break; + + case ts.SyntaxKind.ImportType: + DtsEmitHelpers.modifyImportTypeSpan( + collector, + span, + astDeclaration, + (childSpan, childAstDeclaration) => { + ApiReportGenerator._modifySpan( + collector, + childSpan, + entity, + childAstDeclaration, + insideTypeLiteral, + reportVariant + ); + } + ); + break; } if (recurseChildren) { @@ -285,31 +423,93 @@ export class ApiReportGenerator { let childAstDeclaration: AstDeclaration = astDeclaration; if (AstDeclaration.isSupportedSyntaxKind(child.kind)) { - childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode(child.node, astDeclaration); + childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( + child.node, + astDeclaration + ); + + if (ApiReportGenerator._shouldIncludeDeclaration(collector, childAstDeclaration, reportVariant)) { + if (sortChildren) { + span.modification.sortChildren = true; + child.modification.sortKey = Collector.getSortKeyIgnoringUnderscore( + childAstDeclaration.astSymbol.localName + ); + } - 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); - const aedocSynopsis: string = ApiReportGenerator._getAedocSynopsis(collector, childAstDeclaration, - messagesToReport); - const indentedAedocSynopsis: string = ApiReportGenerator._addIndentAfterNewlines(aedocSynopsis, - child.getIndent()); + // NOTE: This generates ae-undocumented messages as a side effect + const aedocSynopsis: string = ApiReportGenerator._getAedocSynopsis( + collector, + childAstDeclaration, + messagesToReport + ); - child.modification.prefix = indentedAedocSynopsis + child.modification.prefix; + child.modification.prefix = aedocSynopsis + child.modification.prefix; + } } } - ApiReportGenerator._modifySpan(collector, child, entity, childAstDeclaration, insideTypeLiteral); + ApiReportGenerator._modifySpan( + collector, + child, + entity, + childAstDeclaration, + insideTypeLiteral, + reportVariant + ); } } } + private static _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); + + return this._shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, reportVariant); + } + + private static _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}`); + } + } + /** * For declarations marked as `@preapproved`, this is used instead of _modifySpan(). */ @@ -348,9 +548,7 @@ export class ApiReportGenerator { let skipRest: boolean = false; for (const child of span.children) { - if (skipRest - || child.kind === ts.SyntaxKind.SyntaxList - || child.kind === ts.SyntaxKind.JSDocComment) { + if (skipRest || child.kind === ts.SyntaxKind.SyntaxList || child.kind === ts.SyntaxKind.JSDocComment) { child.modification.skipAll(); } if (child.kind === ts.SyntaxKind.Identifier) { @@ -366,75 +564,99 @@ export class ApiReportGenerator { * 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 stringWriter: StringWriter = new StringWriter(); + private static _getAedocSynopsis( + collector: Collector, + astDeclaration: AstDeclaration, + messagesToReport: ExtractorMessage[] + ): string { + const writer: IndentedWriter = new IndentedWriter(); for (const message of messagesToReport) { - ApiReportGenerator._writeLineAsComments(stringWriter, 'Warning: ' + message.formatMessageWithoutLocation()); + ApiReportGenerator._writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation()); } if (!collector.isAncillaryDeclaration(astDeclaration)) { const footerParts: string[] = []; const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + + // 1. Release tag (if present) if (!apiItemMetadata.releaseTagSameAsParent) { if (apiItemMetadata.effectiveReleaseTag !== ReleaseTag.None) { footerParts.push(ReleaseTag.getTagName(apiItemMetadata.effectiveReleaseTag)); } } - if (apiItemMetadata.isSealed) { + // 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 (apiItemMetadata.isVirtual) { + if (reportVirtualTag && apiItemMetadata.isVirtual) { footerParts.push('@virtual'); } - - if (apiItemMetadata.isOverride) { + if (reportOverrideTag && apiItemMetadata.isOverride) { footerParts.push('@override'); } - - if (apiItemMetadata.isEventProperty) { + 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.needsDocumentation) { + // 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(stringWriter, ''); // skip a line after the warnings + ApiReportGenerator._writeLineAsComments(writer, ''); // skip a line after the warnings } - ApiReportGenerator._writeLineAsComments(stringWriter, footerParts.join(' ')); + ApiReportGenerator._writeLineAsComments(writer, footerParts.join(' ')); } } - return stringWriter.toString(); + return writer.toString(); } - private static _writeLineAsComments(stringWriter: StringWriter, line: string): void { + private static _writeLineAsComments(writer: IndentedWriter, line: string): void { const lines: string[] = Text.convertToLf(line).split('\n'); for (const realLine of lines) { - stringWriter.write('// '); - stringWriter.write(realLine); - stringWriter.writeLine(); + writer.write('// '); + writer.write(realLine); + writer.writeLine(); } } - - private static _addIndentAfterNewlines(text: string, indent: string): string { - if (text.length === 0 || indent.length === 0) { - return text; - } - return Text.replaceAll(text, '\n', '\n' + indent); - } - } diff --git a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts index 77b2b8383f2..6f136fb9829 100644 --- a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -3,126 +3,143 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; + import { DeclarationReference, ModuleSource, GlobalSource, Navigation, Meaning -} from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { PackageJsonLookup, INodePackageJson, InternalError } from '@rushstack/node-core-library'; +} 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'; +import type { CollectorEntity } from '../collector/CollectorEntity'; +import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; export class DeclarationReferenceGenerator { public static readonly unknownReference: string = '?'; - private _packageJsonLookup: PackageJsonLookup; - private _workingPackageName: string; - private _program: ts.Program; - private _typeChecker: ts.TypeChecker; + private _collector: Collector; - public constructor(packageJsonLookup: PackageJsonLookup, workingPackageName: string, program: ts.Program, - typeChecker: ts.TypeChecker) { - - this._packageJsonLookup = packageJsonLookup; - this._workingPackageName = workingPackageName; - this._program = program; - this._typeChecker = typeChecker; + public constructor(collector: Collector) { + this._collector = collector; } /** * Gets the UID for a TypeScript Identifier that references a type. */ public getDeclarationReferenceForIdentifier(node: ts.Identifier): DeclarationReference | undefined { - const symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(node); + const symbol: ts.Symbol | undefined = this._collector.typeChecker.getSymbolAtLocation(node); if (symbol !== undefined) { const isExpression: boolean = DeclarationReferenceGenerator._isInExpressionContext(node); - return this.getDeclarationReferenceForSymbol(symbol, isExpression ? ts.SymbolFlags.Value : ts.SymbolFlags.Type) - || this.getDeclarationReferenceForSymbol(symbol, isExpression ? ts.SymbolFlags.Type : ts.SymbolFlags.Value) - || this.getDeclarationReferenceForSymbol(symbol, ts.SymbolFlags.Namespace); + return ( + this.getDeclarationReferenceForSymbol( + symbol, + isExpression ? ts.SymbolFlags.Value : ts.SymbolFlags.Type + ) || + this.getDeclarationReferenceForSymbol( + symbol, + isExpression ? ts.SymbolFlags.Type : ts.SymbolFlags.Value + ) || + this.getDeclarationReferenceForSymbol(symbol, ts.SymbolFlags.Namespace) + ); } } /** * Gets the DeclarationReference for a TypeScript Symbol for a given meaning. */ - public getDeclarationReferenceForSymbol(symbol: ts.Symbol, meaning: ts.SymbolFlags - ): DeclarationReference | undefined { + public getDeclarationReferenceForSymbol( + symbol: ts.Symbol, + meaning: ts.SymbolFlags + ): DeclarationReference | undefined { return this._symbolToDeclarationReference(symbol, meaning, /*includeModuleSymbols*/ false); } private static _isInExpressionContext(node: ts.Node): boolean { switch (node.parent.kind) { - case ts.SyntaxKind.TypeQuery: return true; - case ts.SyntaxKind.QualifiedName: return DeclarationReferenceGenerator._isInExpressionContext(node.parent); - default: return false; + 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); + 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); + return ( + left === right || + !!( + left && + left.valueDeclaration && + right.valueDeclaration && + left.valueDeclaration === right.valueDeclaration + ) + ); } - private static _getNavigationToSymbol(symbol: ts.Symbol): Navigation | 'global' { + private _getNavigationToSymbol(symbol: ts.Symbol): Navigation { + const declaration: ts.Declaration | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); + const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); const parent: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol); - // First, try to determine navigation to symbol via its parent. - if (parent) { - if (parent.exports && DeclarationReferenceGenerator._isSameSymbol(parent.exports.get(symbol.escapedName), symbol)) { - return Navigation.Exports; - } - if (parent.members && DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol)) { + + // If it's global or from an external library, then use either Members or Exports. It's not possible for + // global symbols or external library symbols to be Locals. + const isGlobal: boolean = !!sourceFile && !ts.isExternalModule(sourceFile); + const isFromExternalLibrary: boolean = + !!sourceFile && this._collector.program.isSourceFileFromExternalLibrary(sourceFile); + if (isGlobal || isFromExternalLibrary) { + if ( + parent && + parent.members && + DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol) + ) { return Navigation.Members; } - if (parent.globalExports && DeclarationReferenceGenerator._isSameSymbol(parent.globalExports.get(symbol.escapedName), symbol)) { - return 'global'; - } + + return Navigation.Exports; } - // Next, try determining navigation to symbol by its node - if (symbol.valueDeclaration) { - const declaration: ts.Declaration = ts.isBindingElement(symbol.valueDeclaration) - ? ts.walkUpBindingElementsAndPatterns(symbol.valueDeclaration) - : symbol.valueDeclaration; - if (ts.isClassElement(declaration) && ts.isClassLike(declaration.parent)) { - // class members are an "export" if they have the static modifier. - return ts.getCombinedModifierFlags(declaration) & ts.ModifierFlags.Static - ? Navigation.Exports - : Navigation.Members; - } - if (ts.isTypeElement(declaration) || ts.isObjectLiteralElement(declaration)) { - // type and object literal element members are just members - return Navigation.Members; - } - if (ts.isEnumMember(declaration)) { - // enum members are exports - return Navigation.Exports; - } - if (ts.isExportSpecifier(declaration) - || ts.isExportAssignment(declaration) - || ts.isExportSpecifier(declaration) - || ts.isExportDeclaration(declaration) - || ts.isNamedExports(declaration) + // Otherwise, this symbol is from the current package. If we've found an associated consumable + // `CollectorEntity`, then use Exports. We use `consumable` here instead of `exported` because + // if the symbol is exported from a non-consumable `AstNamespaceImport`, we don't want to use + // Exports. We should use Locals instead. + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol); + if (entity?.consumable) { + return Navigation.Exports; + } + + // 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) ) { - return Navigation.Exports; - } - // declarations are exports if they have an `export` modifier. - if (ts.getCombinedModifierFlags(declaration) & ts.ModifierFlags.Export) { - return Navigation.Exports; - } - if (ts.isSourceFile(declaration.parent) && !ts.isExternalModule(declaration.parent)) { - // declarations in a source file are global if the source file is not a module. - return 'global'; + return Navigation.Members; } + + return Navigation.Exports; } - // all other declarations are locals + + // Otherwise, we have a local symbol, so use a Locals navigation. These are either: + // + // 1. Symbols that are exported from a file module but not the package entry point. + // 2. Symbols that are not exported from their parent module. return Navigation.Locals; } @@ -175,25 +192,32 @@ export class DeclarationReferenceGenerator { return undefined; } - private _symbolToDeclarationReference(symbol: ts.Symbol, meaning: ts.SymbolFlags, includeModuleSymbols: boolean - ): DeclarationReference | undefined { + private _symbolToDeclarationReference( + symbol: ts.Symbol, + meaning: ts.SymbolFlags, + includeModuleSymbols: boolean + ): DeclarationReference | undefined { + const declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); + const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); let followedSymbol: ts.Symbol = symbol; if (followedSymbol.flags & ts.SymbolFlags.ExportValue) { - followedSymbol = this._typeChecker.getExportSymbolOfSymbol(followedSymbol); + followedSymbol = this._collector.typeChecker.getExportSymbolOfSymbol(followedSymbol); } if (followedSymbol.flags & ts.SymbolFlags.Alias) { - followedSymbol = this._typeChecker.getAliasedSymbol(followedSymbol); + followedSymbol = this._collector.typeChecker.getAliasedSymbol(followedSymbol); + + // Without this logic, we end up following the symbol `ns` in `import * as ns from './file'` to + // the actual file `file.ts`. We don't want to do this, so revert to the original symbol. + if (followedSymbol.flags & ts.SymbolFlags.ValueModule) { + followedSymbol = symbol; + } } if (DeclarationReferenceGenerator._isExternalModuleSymbol(followedSymbol)) { if (!includeModuleSymbols) { return undefined; } - const sourceFile: ts.SourceFile | undefined = - followedSymbol.declarations - && followedSymbol.declarations[0] - && followedSymbol.declarations[0].getSourceFile(); return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); } @@ -202,32 +226,23 @@ export class DeclarationReferenceGenerator { return undefined; } - const parent: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(followedSymbol); - let parentRef: DeclarationReference | undefined; - if (parent) { - parentRef = this._symbolToDeclarationReference(parent, ts.SymbolFlags.Namespace, /*includeModuleSymbols*/ true); - } else { - // this may be a local symbol in a module... - const sourceFile: ts.SourceFile | undefined = - followedSymbol.declarations - && followedSymbol.declarations[0] - && followedSymbol.declarations[0].getSourceFile(); - if (sourceFile && ts.isExternalModule(sourceFile)) { - parentRef = new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); - } else { - parentRef = new DeclarationReference(GlobalSource.instance); - } - } - - if (parentRef === undefined) { + let parentRef: DeclarationReference | undefined = this._getParentReference(followedSymbol); + if (!parentRef) { return undefined; } let localName: string = followedSymbol.name; + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(followedSymbol); + if (entity?.nameForEmit) { + localName = entity.nameForEmit; + } + if (followedSymbol.escapedName === ts.InternalSymbolName.Constructor) { localName = 'constructor'; } else { - const wellKnownName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName(followedSymbol.escapedName); + const wellKnownName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName( + followedSymbol.escapedName + ); if (wellKnownName) { // TypeScript binds well-known ECMAScript symbols like 'Symbol.iterator' as '__@iterator'. // This converts a string like '__@iterator' into the property name '[Symbol.iterator]'. @@ -246,12 +261,11 @@ export class DeclarationReferenceGenerator { } } - let navigation: Navigation | 'global' = DeclarationReferenceGenerator._getNavigationToSymbol(followedSymbol); - if (navigation === 'global') { - if (parentRef.source !== GlobalSource.instance) { - parentRef = new DeclarationReference(GlobalSource.instance); - } - navigation = Navigation.Exports; + const navigation: Navigation = this._getNavigationToSymbol(followedSymbol); + + // If the symbol is a global, ensure the source is global. + if (sourceFile && !ts.isExternalModule(sourceFile) && parentRef.source !== GlobalSource.instance) { + parentRef = new DeclarationReference(GlobalSource.instance); } return parentRef @@ -259,24 +273,110 @@ export class DeclarationReferenceGenerator { .withMeaning(DeclarationReferenceGenerator._getMeaningOfSymbol(followedSymbol, meaning)); } + private _getParentReference(symbol: ts.Symbol): DeclarationReference | undefined { + const declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); + const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); + + // Note that it's possible for a symbol to be exported from an entry point as well as one or more + // namespaces. In that case, it's not clear what to choose as its parent. Today's logic is neither + // perfect nor particularly stable to API items being renamed and shuffled around. + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol); + if (entity) { + if (entity.exportedFromEntryPoint) { + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + } + + const firstExportingConsumableParent: CollectorEntity | undefined = + entity.getFirstExportingConsumableParent(); + if ( + firstExportingConsumableParent && + firstExportingConsumableParent.astEntity instanceof AstNamespaceImport + ) { + const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( + firstExportingConsumableParent.astEntity.declaration, + this._collector.typeChecker + ); + if (parentSymbol) { + return this._symbolToDeclarationReference( + parentSymbol, + parentSymbol.flags, + /*includeModuleSymbols*/ true + ); + } + } + } + + // Next, try to find a parent symbol via the symbol tree. + const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol); + if (parentSymbol) { + return this._symbolToDeclarationReference( + parentSymbol, + parentSymbol.flags, + /*includeModuleSymbols*/ true + ); + } + + // If that doesn't work, try to find a parent symbol via the node tree. As far as we can tell, + // this logic is only needed for local symbols within namespaces. For example: + // + // ``` + // export namespace n { + // type SomeType = number; + // export function someFunction(): SomeType { return 5; } + // } + // ``` + // + // In the example above, `SomeType` doesn't have a parent symbol per the TS internal API above, + // but its reference still needs to be qualified with the parent reference for `n`. + const grandParent: ts.Node | undefined = declaration?.parent?.parent; + if (grandParent && ts.isModuleDeclaration(grandParent)) { + const grandParentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( + grandParent, + this._collector.typeChecker + ); + if (grandParentSymbol) { + return this._symbolToDeclarationReference( + grandParentSymbol, + grandParentSymbol.flags, + /*includeModuleSymbols*/ true + ); + } + } + + // At this point, we have a local symbol in a module. + if (sourceFile && ts.isExternalModule(sourceFile)) { + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + } else { + return new DeclarationReference(GlobalSource.instance); + } + } + private _getPackageName(sourceFile: ts.SourceFile): string { - if (this._program.isSourceFileFromExternalLibrary(sourceFile)) { - const packageJson: INodePackageJson | undefined = this._packageJsonLookup - .tryLoadNodePackageJsonFor(sourceFile.fileName); + if (this._collector.program.isSourceFileFromExternalLibrary(sourceFile)) { + const packageJson: INodePackageJson | undefined = + this._collector.packageJsonLookup.tryLoadNodePackageJsonFor(sourceFile.fileName); if (packageJson && packageJson.name) { return packageJson.name; } return DeclarationReferenceGenerator.unknownReference; } - return this._workingPackageName; + return this._collector.workingPackage.name; } private _sourceFileToModuleSource(sourceFile: ts.SourceFile | undefined): GlobalSource | ModuleSource { if (sourceFile && ts.isExternalModule(sourceFile)) { - return new ModuleSource(this._getPackageName(sourceFile)); + const packageName: string = this._getPackageName(sourceFile); + + if (this._collector.bundledPackageNames.has(packageName)) { + // The api-extractor.json config file has a "bundledPackages" setting, which causes imports from + // certain NPM packages to be treated as part of the working project. In this case, we need to + // substitute the working package name. + return new ModuleSource(this._collector.workingPackage.name); + } else { + return new ModuleSource(packageName); + } } return GlobalSource.instance; } } - diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 3405b661c98..6cbb23c71b0 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -4,56 +4,170 @@ import * as ts from 'typescript'; import { InternalError } from '@rushstack/node-core-library'; -import { CollectorEntity } from '../collector/CollectorEntity'; + +import type { CollectorEntity } from '../collector/CollectorEntity'; import { AstImport, AstImportKind } from '../analyzer/AstImport'; -import { StringWriter } from './StringWriter'; -import { Collector } from '../collector/Collector'; +import { AstDeclaration } from '../analyzer/AstDeclaration'; +import type { Collector } from '../collector/Collector'; +import type { Span } from '../analyzer/Span'; +import type { IndentedWriter } from './IndentedWriter'; +import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; /** * Some common code shared between DtsRollupGenerator and ApiReportGenerator. */ export class DtsEmitHelpers { - public static emitImport(stringWriter: StringWriter, collectorEntity: CollectorEntity, astImport: AstImport): void { + public static emitImport( + writer: IndentedWriter, + collectorEntity: CollectorEntity, + astImport: AstImport + ): void { + const importPrefix: string = astImport.isTypeOnlyEverywhere ? 'import type' : 'import'; + switch (astImport.importKind) { case AstImportKind.DefaultImport: - stringWriter.writeLine(`import ${astImport.exportName} from '${astImport.modulePath}';`); + if (collectorEntity.nameForEmit !== astImport.exportName) { + writer.write(`${importPrefix} { default as ${collectorEntity.nameForEmit} }`); + } else { + writer.write(`${importPrefix} ${astImport.exportName}`); + } + writer.writeLine(` from '${astImport.modulePath}';`); break; case AstImportKind.NamedImport: - if (collectorEntity.nameForEmit !== astImport.exportName) { - stringWriter.write(`import { ${astImport.exportName} as ${collectorEntity.nameForEmit} }`); + if (collectorEntity.nameForEmit === astImport.exportName) { + writer.write(`${importPrefix} { ${astImport.exportName} }`); } else { - stringWriter.write(`import { ${astImport.exportName} }`); + writer.write(`${importPrefix} { ${astImport.exportName} as ${collectorEntity.nameForEmit} }`); } - stringWriter.writeLine(` from '${astImport.modulePath}';`); + writer.writeLine(` from '${astImport.modulePath}';`); break; case AstImportKind.StarImport: - stringWriter.writeLine(`import * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';`); + writer.writeLine( + `${importPrefix} * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';` + ); break; case AstImportKind.EqualsImport: - stringWriter.writeLine(`import ${collectorEntity.nameForEmit} = require('${astImport.modulePath}');`); + writer.writeLine( + `${importPrefix} ${collectorEntity.nameForEmit} = require('${astImport.modulePath}');` + ); + break; + case AstImportKind.ImportType: + if (!astImport.exportName) { + writer.writeLine( + `${importPrefix} * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';` + ); + } else { + const topExportName: string = astImport.exportName.split('.')[0]; + if (collectorEntity.nameForEmit === topExportName) { + writer.write(`${importPrefix} { ${topExportName} }`); + } else { + writer.write(`${importPrefix} { ${topExportName} as ${collectorEntity.nameForEmit} }`); + } + writer.writeLine(` from '${astImport.modulePath}';`); + } break; default: throw new InternalError('Unimplemented AstImportKind'); } } - public static emitNamedExport(stringWriter: StringWriter, exportName: string, - collectorEntity: CollectorEntity): void { - + public static emitNamedExport( + writer: IndentedWriter, + exportName: string, + collectorEntity: CollectorEntity + ): void { if (exportName === ts.InternalSymbolName.Default) { - stringWriter.writeLine(`export default ${collectorEntity.nameForEmit};`); + writer.writeLine(`export default ${collectorEntity.nameForEmit};`); } else if (collectorEntity.nameForEmit !== exportName) { - stringWriter.writeLine(`export { ${collectorEntity.nameForEmit} as ${exportName} }`); + writer.writeLine(`export { ${collectorEntity.nameForEmit} as ${exportName} }`); } else { - stringWriter.writeLine(`export { ${exportName} }`); + writer.writeLine(`export { ${exportName} }`); } } - public static emitStarExports(stringWriter: StringWriter, collector: Collector): void { + public static emitStarExports(writer: IndentedWriter, collector: Collector): void { if (collector.starExportedExternalModulePaths.length > 0) { - stringWriter.writeLine(); + writer.writeLine(); for (const starExportedExternalModulePath of collector.starExportedExternalModulePaths) { - stringWriter.writeLine(`export * from "${starExportedExternalModulePath}";`); + writer.writeLine(`export * from "${starExportedExternalModulePath}";`); + } + } + } + + public static modifyImportTypeSpan( + collector: Collector, + span: Span, + astDeclaration: AstDeclaration, + modifyNestedSpan: (childSpan: Span, childAstDeclaration: AstDeclaration) => void + ): void { + const node: ts.ImportTypeNode = span.node as ts.ImportTypeNode; + const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode(node); + + if (referencedEntity) { + if (!referencedEntity.nameForEmit) { + // This should never happen + + throw new InternalError('referencedEntry.nameForEmit is undefined'); + } + + let typeArgumentsText: string = ''; + + if (node.typeArguments && node.typeArguments.length > 0) { + // Type arguments have to be processed and written to the document + const lessThanTokenPos: number = span.children.findIndex( + (childSpan) => childSpan.node.kind === ts.SyntaxKind.LessThanToken + ); + const greaterThanTokenPos: number = span.children.findIndex( + (childSpan) => childSpan.node.kind === ts.SyntaxKind.GreaterThanToken + ); + + if (lessThanTokenPos < 0 || greaterThanTokenPos <= lessThanTokenPos) { + throw new InternalError( + `Invalid type arguments: ${node.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(node) + ); + } + + const typeArgumentsSpans: Span[] = span.children.slice(lessThanTokenPos + 1, greaterThanTokenPos); + + // Apply modifications to Span elements of typeArguments + typeArgumentsSpans.forEach((childSpan) => { + const childAstDeclaration: AstDeclaration = AstDeclaration.isSupportedSyntaxKind(childSpan.kind) + ? collector.astSymbolTable.getChildAstDeclarationByNode(childSpan.node, astDeclaration) + : astDeclaration; + + modifyNestedSpan(childSpan, childAstDeclaration); + }); + + const typeArgumentsStrings: string[] = typeArgumentsSpans.map((childSpan) => + childSpan.getModifiedText() + ); + typeArgumentsText = `<${typeArgumentsStrings.join(', ')}>`; + } + + const separatorAfter: string = /(\s*)$/.exec(span.getText())?.[1] ?? ''; + + if ( + referencedEntity.astEntity instanceof AstImport && + referencedEntity.astEntity.importKind === AstImportKind.ImportType && + referencedEntity.astEntity.exportName + ) { + // For an ImportType with a namespace chain, only the top namespace is imported. + // Must add the original nested qualifiers to the rolled up import. + const qualifiersText: string = node.qualifier?.getText() ?? ''; + const nestedQualifiersStart: number = qualifiersText.indexOf('.'); + // Including the leading "." + const nestedQualifiersText: string = + nestedQualifiersStart >= 0 ? qualifiersText.substring(nestedQualifiersStart) : ''; + + const replacement: string = `${referencedEntity.nameForEmit}${nestedQualifiersText}${typeArgumentsText}${separatorAfter}`; + + span.modification.skipAll(); + span.modification.prefix = replacement; + } else { + // Replace with internal symbol or AstImport + span.modification.skipAll(); + span.modification.prefix = `${referencedEntity.nameForEmit}${typeArgumentsText}${separatorAfter}`; } } } diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index dca08949d42..baa933c9440 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -1,24 +1,27 @@ // 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, 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 { Collector } from '../collector/Collector'; +import type { Collector } from '../collector/Collector'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; -import { Span, SpanModification } from '../analyzer/Span'; +import { IndentDocCommentScope, Span, type SpanModification } from '../analyzer/Span'; import { AstImport } from '../analyzer/AstImport'; -import { CollectorEntity } from '../collector/CollectorEntity'; +import type { CollectorEntity } from '../collector/CollectorEntity'; import { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ApiItemMetadata } from '../collector/ApiItemMetadata'; +import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; import { AstSymbol } from '../analyzer/AstSymbol'; -import { SymbolMetadata } from '../collector/SymbolMetadata'; -import { StringWriter } from './StringWriter'; +import type { SymbolMetadata } from '../collector/SymbolMetadata'; +import { IndentedWriter } from './IndentedWriter'; import { DtsEmitHelpers } from './DtsEmitHelpers'; -import { DeclarationMetadata } from '../collector/DeclarationMetadata'; +import type { DeclarationMetadata } from '../collector/DeclarationMetadata'; +import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; +import type { IAstModuleExportInfo } from '../analyzer/AstModule'; +import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import type { AstEntity } from '../analyzer/AstEntity'; /** * Used with DtsRollupGenerator.writeTypingsFile() @@ -30,6 +33,13 @@ export enum DtsRollupKind { */ InternalRelease, + /** + * Generate a *.d.ts file for a preview release. + * This output file will contain all definitions that are reachable from the entry point, + * except definitions marked as \@internal. + */ + AlphaRelease, + /** * Generate a *.d.ts file for a preview release. * This output file will contain all definitions that are reachable from the entry point, @@ -52,108 +62,198 @@ export class DtsRollupGenerator { * @param dtsFilename - The *.d.ts output filename */ public static writeTypingsFile( - collector: Collector, dtsFilename: string, dtsKind: DtsRollupKind, newlineKind: NewlineKind + collector: Collector, + dtsFilename: string, + dtsKind: DtsRollupKind, + newlineKind: NewlineKind ): void { - const stringWriter: StringWriter = new StringWriter(); + const writer: IndentedWriter = new IndentedWriter(); + writer.trimLeadingSpaces = true; - DtsRollupGenerator._generateTypingsFileContent(collector, stringWriter, dtsKind); + DtsRollupGenerator._generateTypingsFileContent(collector, writer, dtsKind); - FileSystem.writeFile(dtsFilename, stringWriter.toString(), { + FileSystem.writeFile(dtsFilename, writer.toString(), { convertLineEndings: newlineKind, ensureFolderExists: true }); } - private static _generateTypingsFileContent(collector: Collector, stringWriter: StringWriter, - dtsKind: DtsRollupKind): void { - + private static _generateTypingsFileContent( + collector: Collector, + writer: IndentedWriter, + dtsKind: DtsRollupKind + ): void { + // Emit the @packageDocumentation comment at the top of the file if (collector.workingPackage.tsdocParserContext) { - stringWriter.writeLine(collector.workingPackage.tsdocParserContext.sourceRange.toString()); - stringWriter.writeLine(); + 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 - stringWriter.writeLine(`/// `); + writer.writeLine(`/// `); } - for (const libDirectiveReference of collector.dtsLibReferenceDirectives) { - stringWriter.writeLine(`/// `); + 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; - - // For example, if the imported API comes from an external package that supports AEDoc, - // and it was marked as `@internal`, then don't emit it. - const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astImport); - const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata - ? symbolMetadata.maxEffectiveReleaseTag : ReleaseTag.None; - - if (this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) { - DtsEmitHelpers.emitImport(stringWriter, entity, astImport); - } + DtsEmitHelpers.emitImport(writer, entity, astImport); } } + writer.ensureSkippedLine(); // Emit the regular declarations for (const entity of collector.entities) { - const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(entity.astEntity); + const astEntity: AstEntity = entity.astEntity; + const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity); const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata - ? symbolMetadata.maxEffectiveReleaseTag : ReleaseTag.None; + ? symbolMetadata.maxEffectiveReleaseTag + : ReleaseTag.None; if (!this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) { if (!collector.extractorConfig.omitTrimmingComments) { - stringWriter.writeLine(); - stringWriter.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`); + writer.ensureSkippedLine(); + writer.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`); } continue; } - if (entity.astEntity instanceof AstSymbol) { + if (astEntity instanceof AstSymbol) { // Emit all the declarations for this entry - for (const astDeclaration of entity.astEntity.astDeclarations || []) { + for (const astDeclaration of astEntity.astDeclarations || []) { const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); if (!this._shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, dtsKind)) { if (!collector.extractorConfig.omitTrimmingComments) { - stringWriter.writeLine(); - stringWriter.writeLine(`/* Excluded declaration from this release type: ${entity.nameForEmit} */`); + 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); - stringWriter.writeLine(); - stringWriter.writeLine(span.getModifiedText()); + writer.ensureSkippedLine(); + span.writeModifiedText(writer); + writer.ensureNewLine(); + } + } + } + + if (astEntity instanceof AstNamespaceImport) { + const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); + + if (entity.nameForEmit === undefined) { + // This should never happen + throw new InternalError('referencedEntry.nameForEmit is undefined'); + } + + 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) + ); + } + + // 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). + + writer.ensureSkippedLine(); + if (entity.shouldInlineExport) { + writer.write('export '); + } + 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}`); } } + 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(stringWriter, exportName, entity); + DtsEmitHelpers.emitNamedExport(writer, exportName, entity); } } + + writer.ensureSkippedLine(); } - DtsEmitHelpers.emitStarExports(stringWriter, collector); + DtsEmitHelpers.emitStarExports(writer, collector); // Emit "export { }" which is a special directive that prevents consumers from importing declarations // that don't have an explicit "export" modifier. - stringWriter.writeLine(); - stringWriter.writeLine('export { }'); + 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 { - + private static _modifySpan( + collector: Collector, + span: Span, + entity: CollectorEntity, + astDeclaration: AstDeclaration, + dtsKind: DtsRollupKind + ): void { const previousSpan: Span | undefined = span.previousSibling; let recurseChildren: boolean = true; @@ -217,14 +317,17 @@ export class DtsRollupGenerator { // 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]); + 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()); + const listPrefix: string = list + .getSourceFile() + .text.substring(list.getStart(), list.declarations[0].getStart()); span.modification.prefix = 'declare ' + listPrefix + span.modification.prefix; span.modification.suffix = ';'; @@ -241,30 +344,43 @@ export class DtsRollupGenerator { 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.tryGetEntityForIdentifierNode( - span.node as ts.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'); + } - 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*/'; } - - span.modification.prefix = referencedEntity.nameForEmit; - // For debugging: - // span.modification.prefix += '/*R=FIX*/'; - } else { - // For debugging: - // span.modification.prefix += '/*R=KEEP*/'; } + break; + case ts.SyntaxKind.ImportType: + DtsEmitHelpers.modifyImportTypeSpan( + collector, + span, + astDeclaration, + (childSpan, childAstDeclaration) => { + DtsRollupGenerator._modifySpan(collector, childSpan, entity, childAstDeclaration, dtsKind); + } + ); break; } @@ -275,8 +391,12 @@ export class DtsRollupGenerator { // 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; + childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( + child.node, + astDeclaration + ); + const releaseTag: ReleaseTag = + collector.fetchApiItemMetadata(childAstDeclaration).effectiveReleaseTag; if (!this._shouldIncludeReleaseTag(releaseTag, dtsKind)) { let nodeToTrim: Span = child; @@ -284,8 +404,9 @@ export class DtsRollupGenerator { // 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); + const variableStatement: Span | undefined = child.findFirstParent( + ts.SyntaxKind.VariableStatement + ); if (variableStatement !== undefined) { nodeToTrim = variableStatement; } @@ -332,17 +453,28 @@ export class DtsRollupGenerator { } 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: - // NOTE: If the release tag is "None", then we don't have enough information to trim it - return releaseTag === ReleaseTag.Beta || releaseTag === ReleaseTag.Public || releaseTag === ReleaseTag.None; + 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`); } - - 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 1266d70e63a..8b10b4674d1 100644 --- a/apps/api-extractor/src/generators/ExcerptBuilder.ts +++ b/apps/api-extractor/src/generators/ExcerptBuilder.ts @@ -2,16 +2,17 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; + +import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { ExcerptTokenKind, - IExcerptToken, - IExcerptTokenRange + type IExcerptToken, + type IExcerptTokenRange } from '@microsoft/api-extractor-model'; import { Span } from '../analyzer/Span'; -import { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; -import { AstDeclaration } from '../analyzer/AstDeclaration'; +import type { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; +import type { AstDeclaration } from '../analyzer/AstDeclaration'; /** * Used to provide ExcerptBuilder with a list of nodes whose token range we want to capture. @@ -53,11 +54,10 @@ interface IBuildSpanState { tokenRangesByNode: Map; /** - * Normally adjacent tokens of the same kind get merged, to avoid creating lots of unnecessary extra tokens. - * However when an captured excerpt needs to start/end at a specific character, we temporarily disable merging by - * setting this flag. After the new token is added, this flag is cleared. + * Tracks whether the last appended token was a separator. If so, and we're in the middle of + * capturing a token range, then omit the separator from the range. */ - disableMergingForNextToken: boolean; + lastAppendedTokenIsSeparator: boolean; } export class ExcerptBuilder { @@ -82,9 +82,12 @@ export class ExcerptBuilder { * @param excerptTokens - The target token list to append to * @param nodesToCapture - A list of child nodes whose token ranges we want to capture */ - public static addDeclaration(excerptTokens: IExcerptToken[], astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[], referenceGenerator: DeclarationReferenceGenerator): void { - + public static addDeclaration( + excerptTokens: IExcerptToken[], + astDeclaration: AstDeclaration, + nodesToCapture: IExcerptBuilderNodeToCapture[], + referenceGenerator: DeclarationReferenceGenerator + ): void { let stopBeforeChildKind: ts.SyntaxKind | undefined = undefined; switch (astDeclaration.declaration.kind) { @@ -114,8 +117,9 @@ export class ExcerptBuilder { startingNode: span.node, stopBeforeChildKind, tokenRangesByNode, - disableMergingForNextToken: false + lastAppendedTokenIsSeparator: false }); + ExcerptBuilder._condenseTokens(excerptTokens, [...tokenRangesByNode.values()]); } public static createEmptyTokenRange(): IExcerptTokenRange { @@ -135,7 +139,6 @@ export class ExcerptBuilder { if (capturedTokenRange) { // We will assign capturedTokenRange.startIndex to be the index of the next token to be appended excerptStartIndex = excerptTokens.length; - state.disableMergingForNextToken = true; } if (span.prefix) { @@ -149,18 +152,22 @@ export class ExcerptBuilder { } if (canonicalReference) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, - span.prefix, state, canonicalReference); + ExcerptBuilder._appendToken( + excerptTokens, + ExcerptTokenKind.Reference, + span.prefix, + canonicalReference + ); } else { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, - span.prefix, state); + ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix); } + state.lastAppendedTokenIsSeparator = false; } for (const child of span.children) { if (span.node === state.startingNode) { if (state.stopBeforeChildKind && child.kind === state.stopBeforeChildKind) { - // We reached the a child whose kind is stopBeforeChildKind, so stop traversing + // We reached a child whose kind is stopBeforeChildKind, so stop traversing return false; } } @@ -171,69 +178,135 @@ export class ExcerptBuilder { } if (span.suffix) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix, state); + ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix); + state.lastAppendedTokenIsSeparator = false; } if (span.separator) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.separator, state); + 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; - // We will assign capturedTokenRange.startIndex to be the index after the last token that was appended so far - capturedTokenRange.endIndex = excerptTokens.length; + // 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--; + } - state.disableMergingForNextToken = true; + capturedTokenRange.endIndex = excerptEndIndex; } return true; } - private static _appendToken(excerptTokens: IExcerptToken[], excerptTokenKind: ExcerptTokenKind, - text: string, state: IBuildSpanState, canonicalReference?: DeclarationReference): void { - + private static _appendToken( + excerptTokens: IExcerptToken[], + excerptTokenKind: ExcerptTokenKind, + text: string, + canonicalReference?: DeclarationReference + ): void { if (text.length === 0) { return; } - if (excerptTokenKind !== ExcerptTokenKind.Content) { - if (excerptTokenKind === ExcerptTokenKind.Reference && excerptTokens.length > 1 - && !state.disableMergingForNextToken) { - // If the previous two tokens were a Reference and a '.', then concatenate - // all three tokens as a qualified name Reference. - const previousTokenM1: IExcerptToken = excerptTokens[excerptTokens.length - 1]; - const previousTokenM2: IExcerptToken = excerptTokens[excerptTokens.length - 2]; - if (previousTokenM1.kind === ExcerptTokenKind.Content - && previousTokenM1.text.trim() === '.' - && previousTokenM2.kind === ExcerptTokenKind.Reference) { - - previousTokenM2.text += '.' + text; - if (canonicalReference !== undefined) { - previousTokenM2.canonicalReference = canonicalReference.toString(); - } - excerptTokens.pop(); // remove previousTokenM1; - return; - } - } - } else { - // If someone referenced this index, then we need to start a new token - if (excerptTokens.length > 0 && !state.disableMergingForNextToken) { - // Otherwise, can we merge with the previous token? - const previousToken: IExcerptToken = excerptTokens[excerptTokens.length - 1]; - if (previousToken.kind === excerptTokenKind) { - previousToken.text += text; - return; - } - } - } - const excerptToken: IExcerptToken = { kind: excerptTokenKind, text: text }; if (canonicalReference !== undefined) { excerptToken.canonicalReference = canonicalReference.toString(); } excerptTokens.push(excerptToken); - state.disableMergingForNextToken = false; + } + + /** + * 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); + } + + 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); + } + } + } } private static _isDeclarationName(name: ts.Identifier): boolean { @@ -266,5 +339,4 @@ export class ExcerptBuilder { return false; } } - } diff --git a/apps/api-extractor/src/generators/IndentedWriter.ts b/apps/api-extractor/src/generators/IndentedWriter.ts new file mode 100644 index 00000000000..84c2a91e35b --- /dev/null +++ b/apps/api-extractor/src/generators/IndentedWriter.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 { StringBuilder, type IStringBuilder } from '@rushstack/node-core-library'; + +/** + * A utility for writing indented text. + * + * @remarks + * + * Note that the indentation is inserted at the last possible opportunity. + * For example, this code... + * + * ```ts + * writer.write('begin\n'); + * writer.increaseIndent(); + * writer.write('one\ntwo\n'); + * writer.decreaseIndent(); + * writer.increaseIndent(); + * writer.decreaseIndent(); + * writer.write('end'); + * ``` + * + * ...would produce this output: + * + * ``` + * begin + * one + * two + * end + * ``` + */ +export class IndentedWriter { + /** + * The text characters used to create one level of indentation. + * Two spaces by default. + */ + public defaultIndentPrefix: string = ' '; + + /** + * Whether to indent blank lines + */ + public indentBlankLines: boolean = false; + + /** + * Trims leading spaces from the input text before applying the indent. + * + * @remarks + * Consider the following example: + * + * ```ts + * indentedWriter.increaseIndent(' '); // four spaces + * indentedWriter.write(' a\n b c\n'); + * indentedWriter.decreaseIndent(); + * ``` + * + * Normally the output would be indented by 6 spaces: 4 from `increaseIndent()`, plus the 2 spaces + * from `write()`: + * ``` + * a + * b c + * ``` + * + * Setting `trimLeadingSpaces=true` will trim the leading spaces, so that the lines are indented + * by 4 spaces only: + * ``` + * a + * b c + * ``` + */ + public trimLeadingSpaces: boolean = false; + + private readonly _builder: IStringBuilder; + + private _latestChunk: string | undefined; + private _previousChunk: string | undefined; + private _atStartOfLine: boolean; + + private readonly _indentStack: string[]; + private _indentText: string; + + private _previousLineIsBlank: boolean; + private _currentLineIsBlank: boolean; + + public constructor(builder?: IStringBuilder) { + this._builder = builder === undefined ? new StringBuilder() : builder; + this._latestChunk = undefined; + this._previousChunk = undefined; + this._atStartOfLine = true; + this._previousLineIsBlank = true; + this._currentLineIsBlank = true; + + this._indentStack = []; + this._indentText = ''; + } + + /** + * Retrieves the output that was built so far. + */ + public getText(): string { + return this._builder.toString(); + } + + public toString(): string { + return this.getText(); + } + + /** + * Increases the indentation. Normally the indentation is two spaces, + * however an arbitrary prefix can optional be specified. (For example, + * the prefix could be "// " to indent and comment simultaneously.) + * Each call to IndentedWriter.increaseIndent() must be followed by a + * corresponding call to IndentedWriter.decreaseIndent(). + */ + public increaseIndent(indentPrefix?: string): void { + this._indentStack.push(indentPrefix !== undefined ? indentPrefix : this.defaultIndentPrefix); + this._updateIndentText(); + } + + /** + * Decreases the indentation, reverting the effect of the corresponding call + * to IndentedWriter.increaseIndent(). + */ + public decreaseIndent(): void { + this._indentStack.pop(); + this._updateIndentText(); + } + + /** + * A shorthand for ensuring that increaseIndent()/decreaseIndent() occur + * in pairs. + */ + public indentScope(scope: () => void, indentPrefix?: string): void { + this.increaseIndent(indentPrefix); + scope(); + this.decreaseIndent(); + } + + /** + * Adds a newline if the file pointer is not already at the start of the line (or start of the stream). + */ + public ensureNewLine(): void { + const lastCharacter: string = this.peekLastCharacter(); + if (lastCharacter !== '\n' && lastCharacter !== '') { + this._writeNewLine(); + } + } + + /** + * Adds up to two newlines to ensure that there is a blank line above the current position. + * The start of the stream is considered to be a blank line, so `ensureSkippedLine()` has no effect + * unless some text has been written. + */ + public ensureSkippedLine(): void { + this.ensureNewLine(); + if (!this._previousLineIsBlank) { + this._writeNewLine(); + } + } + + /** + * Returns the last character that was written, or an empty string if no characters have been written yet. + */ + public peekLastCharacter(): string { + if (this._latestChunk !== undefined) { + return this._latestChunk.substr(-1, 1); + } + return ''; + } + + /** + * Returns the second to last character that was written, or an empty string if less than one characters + * have been written yet. + */ + public peekSecondLastCharacter(): string { + if (this._latestChunk !== undefined) { + if (this._latestChunk.length > 1) { + return this._latestChunk.substr(-2, 1); + } + if (this._previousChunk !== undefined) { + return this._previousChunk.substr(-1, 1); + } + } + return ''; + } + + /** + * Writes some text to the internal string buffer, applying indentation according + * to the current indentation level. If the string contains multiple newlines, + * each line will be indented separately. + */ + public write(message: string): void { + if (message.length === 0) { + return; + } + + // If there are no newline characters, then append the string verbatim + if (!/[\r\n]/.test(message)) { + this._writeLinePart(message); + return; + } + + // Otherwise split the lines and write each one individually + let first: boolean = true; + for (const linePart of message.split('\n')) { + if (!first) { + this._writeNewLine(); + } else { + first = false; + } + if (linePart) { + this._writeLinePart(linePart.replace(/[\r]/g, '')); + } + } + } + + /** + * A shorthand for writing an optional message, followed by a newline. + * Indentation is applied following the semantics of IndentedWriter.write(). + */ + public writeLine(message: string = ''): void { + if (message.length > 0) { + this.write(message); + } + this._writeNewLine(); + } + + /** + * Writes a string that does not contain any newline characters. + */ + private _writeLinePart(message: string): void { + let trimmedMessage: string = message; + + if (this.trimLeadingSpaces && this._atStartOfLine) { + trimmedMessage = message.replace(/^ +/, ''); + } + + if (trimmedMessage.length > 0) { + if (this._atStartOfLine && this._indentText.length > 0) { + this._write(this._indentText); + } + this._write(trimmedMessage); + if (this._currentLineIsBlank) { + if (/\S/.test(trimmedMessage)) { + this._currentLineIsBlank = false; + } + } + this._atStartOfLine = false; + } + } + + private _writeNewLine(): void { + if (this.indentBlankLines) { + if (this._atStartOfLine && this._indentText.length > 0) { + this._write(this._indentText); + } + } + + this._previousLineIsBlank = this._currentLineIsBlank; + this._write('\n'); + this._currentLineIsBlank = true; + this._atStartOfLine = true; + } + + private _write(s: string): void { + this._previousChunk = this._latestChunk; + this._latestChunk = s; + this._builder.append(s); + } + + private _updateIndentText(): void { + this._indentText = this._indentStack.join(''); + } +} diff --git a/apps/api-extractor/src/generators/StringWriter.ts b/apps/api-extractor/src/generators/StringWriter.ts deleted file mode 100644 index 80eae783836..00000000000 --- a/apps/api-extractor/src/generators/StringWriter.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. - -import { StringBuilder } from '@microsoft/tsdoc'; - -// A small helper used by the generators -export class StringWriter { - public readonly stringBuilder: StringBuilder = new StringBuilder(); - - public write(s: string): void { - this.stringBuilder.append(s); - } - - public writeLine(s: string = ''): void { - if (s.length > 0) { - this.stringBuilder.append(s); - } - this.stringBuilder.append('\n'); - } - - public toString(): string { - return this.stringBuilder.toString(); - } -} diff --git a/apps/api-extractor/src/generators/test/IndentedWriter.test.ts b/apps/api-extractor/src/generators/test/IndentedWriter.test.ts new file mode 100644 index 00000000000..7a9145625ed --- /dev/null +++ b/apps/api-extractor/src/generators/test/IndentedWriter.test.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 { IndentedWriter } from '../IndentedWriter'; + +test('01 Demo from docs', () => { + const indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.write('begin\n'); + indentedWriter.increaseIndent(); + indentedWriter.write('one\ntwo\n'); + indentedWriter.decreaseIndent(); + indentedWriter.increaseIndent(); + indentedWriter.decreaseIndent(); + indentedWriter.write('end'); + + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('02 Indent something', () => { + const indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.write('a'); + indentedWriter.write('b'); + indentedWriter.increaseIndent(); + indentedWriter.writeLine('c'); + indentedWriter.writeLine('d'); + indentedWriter.decreaseIndent(); + indentedWriter.writeLine('e'); + + indentedWriter.increaseIndent('>>> '); + indentedWriter.writeLine(); + indentedWriter.writeLine(); + indentedWriter.writeLine('g'); + indentedWriter.decreaseIndent(); + + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('03 Indent something with indentBlankLines=true', () => { + const indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.indentBlankLines = true; + + indentedWriter.write('a'); + indentedWriter.write('b'); + indentedWriter.increaseIndent(); + indentedWriter.writeLine('c'); + indentedWriter.writeLine('d'); + indentedWriter.decreaseIndent(); + indentedWriter.writeLine('e'); + + indentedWriter.increaseIndent('>>> '); + indentedWriter.writeLine(); + indentedWriter.writeLine(); + indentedWriter.writeLine('g'); + indentedWriter.decreaseIndent(); + + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('04 Two kinds of indents', () => { + const indentedWriter: IndentedWriter = new IndentedWriter(); + + indentedWriter.writeLine('---'); + indentedWriter.indentScope(() => { + indentedWriter.write('a\nb'); + indentedWriter.indentScope(() => { + indentedWriter.write('c\nd\n'); + }); + indentedWriter.write('e\n'); + }, '> '); + indentedWriter.writeLine('---'); + + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('05 Edge cases for ensureNewLine()', () => { + let indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.ensureNewLine(); + indentedWriter.write('line'); + expect(indentedWriter.toString()).toMatchSnapshot(); + + indentedWriter = new IndentedWriter(); + indentedWriter.write('previous'); + indentedWriter.ensureNewLine(); + indentedWriter.write('line'); + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('06 Edge cases for ensureSkippedLine()', () => { + let indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.ensureSkippedLine(); + indentedWriter.write('line'); + expect(indentedWriter.toString()).toMatchSnapshot(); + + indentedWriter = new IndentedWriter(); + indentedWriter.write('previous'); + indentedWriter.ensureSkippedLine(); + indentedWriter.write('line'); + indentedWriter.ensureSkippedLine(); + expect(indentedWriter.toString()).toMatchSnapshot(); +}); + +test('06 trimLeadingSpaces=true', () => { + const indentedWriter: IndentedWriter = new IndentedWriter(); + indentedWriter.trimLeadingSpaces = true; + + // Example from doc comment + indentedWriter.increaseIndent(' '); + indentedWriter.write(' a\n b c\n'); + indentedWriter.decreaseIndent(); + indentedWriter.ensureSkippedLine(); + indentedWriter.increaseIndent('>>'); + indentedWriter.write(' '); + indentedWriter.write(' '); + indentedWriter.write(' a'); + indentedWriter.writeLine(' b'); + indentedWriter.writeLine('\ttab'); // does not get indented + indentedWriter.writeLine('c '); + expect(indentedWriter.toString()).toMatchSnapshot(); +}); 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 new file mode 100644 index 00000000000..6803fe9f220 --- /dev/null +++ b/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`01 Demo from docs 1`] = ` +"begin + one + two +end" +`; + +exports[`02 Indent something 1`] = ` +"abc + d +e + + +>>> g +" +`; + +exports[`03 Indent something with indentBlankLines=true 1`] = ` +"abc + d +e +>>> +>>> +>>> g +" +`; + +exports[`04 Two kinds of indents 1`] = ` +"--- +> a +> bc +> d +> e +--- +" +`; + +exports[`05 Edge cases for ensureNewLine() 1`] = `"line"`; + +exports[`05 Edge cases for ensureNewLine() 2`] = ` +"previous +line" +`; + +exports[`06 Edge cases for ensureSkippedLine() 1`] = `"line"`; + +exports[`06 Edge cases for ensureSkippedLine() 2`] = ` +"previous + +line + +" +`; + +exports[`06 trimLeadingSpaces=true 1`] = ` +" a + b c + +>>a b +>> tab +>>c +" +`; diff --git a/apps/api-extractor/src/index.ts b/apps/api-extractor/src/index.ts index e6d162ea6e9..657d112b6d9 100644 --- a/apps/api-extractor/src/index.ts +++ b/apps/api-extractor/src/index.ts @@ -11,30 +11,31 @@ export { ConsoleMessageId } from './api/ConsoleMessageId'; -export { CompilerState, ICompilerStateCreateOptions } from './api/CompilerState'; +export { CompilerState, type ICompilerStateCreateOptions } from './api/CompilerState'; -export { - Extractor, - IExtractorInvokeOptions, - ExtractorResult -} from './api/Extractor'; +export { Extractor, type IExtractorInvokeOptions, ExtractorResult } from './api/Extractor'; export { - IExtractorConfigPrepareOptions, + type IExtractorConfigApiReport, + type IExtractorConfigPrepareOptions, + type IExtractorConfigLoadForFolderOptions, ExtractorConfig } from './api/ExtractorConfig'; +export type { IApiModelGenerationOptions } from './generators/ApiModelGenerator'; + export { ExtractorLogLevel } from './api/ExtractorLogLevel'; export { ExtractorMessage, - IExtractorMessageProperties, + type IExtractorMessageProperties, ExtractorMessageCategory } from './api/ExtractorMessage'; export { ExtractorMessageId } from './api/ExtractorMessageId'; -export { +export type { + ApiReportVariant, IConfigCompiler, IConfigApiReport, IConfigDocModel, @@ -43,5 +44,6 @@ export { 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 d732795edbf..bb6b6157aaf 100644 --- a/apps/api-extractor/src/schemas/api-extractor-defaults.json +++ b/apps/api-extractor/src/schemas/api-extractor-defaults.json @@ -3,10 +3,12 @@ // ("mainEntryPointFilePath" is required) - "bundledPackages": [ ], + "bundledPackages": [], "newlineKind": "crlf", + "enumMemberOrder": "by-name", + "compiler": { "tsconfigFilePath": "/tsconfig.json", "skipLibCheck": false @@ -16,18 +18,20 @@ // ("enabled" is required) "reportFileName": ".api.md", "reportFolder": "/etc/", - "reportTempFolder": "/temp/" + "reportTempFolder": "/temp/", + "includeForgottenExports": false }, "docModel": { // ("enabled" is required) - "apiJsonFilePath": "/temp/.api.json" + "apiJsonFilePath": "/temp/.api.json", + "includeForgottenExports": false }, "dtsRollup": { // ("enabled" is required) - "untrimmedFilePath": "/dist/.d.ts", + "alphaTrimmedFilePath": "", "betaTrimmedFilePath": "", "publicTrimmedFilePath": "", "omitTrimmingComments": false @@ -64,6 +68,9 @@ "logLevel": "warning", "addToApiReportFile": true }, + "ae-undocumented": { + "logLevel": "none" + }, "ae-unresolved-inheritdoc-reference": { "logLevel": "warning", "addToApiReportFile": true @@ -71,6 +78,9 @@ "ae-unresolved-inheritdoc-base": { "logLevel": "warning", "addToApiReportFile": true + }, + "ae-wrong-input-file-type": { + "logLevel": "error" } }, "tsdocMessageReporting": { diff --git a/apps/api-extractor/src/schemas/api-extractor-template.json b/apps/api-extractor/src/schemas/api-extractor-template.json index edd97d910bb..4e1f7be9e12 100644 --- a/apps/api-extractor/src/schemas/api-extractor-template.json +++ b/apps/api-extractor/src/schemas/api-extractor-template.json @@ -53,14 +53,47 @@ * 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: + * imports library2. To avoid this, we might 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. + * + * The "bundledPackages" elements may specify glob patterns using minimatch syntax. To ensure deterministic + * output, globs are expanded by matching explicitly declared top-level dependencies only. For example, + * the pattern below will NOT match "@my-company/example" unless it appears in a field such as "dependencies" + * or "devDependencies" of the project's package.json file: + * + * "bundledPackages": [ "@my-company/*" ], + */ + "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", + + /** + * 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", + + /** + * 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" */ - "bundledPackages": [ ], + // "testMode": false, /** * Determines how the TypeScript compiler engine will be invoked by API Extractor. @@ -78,7 +111,6 @@ * 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: @@ -92,7 +124,6 @@ // "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 @@ -111,18 +142,34 @@ /** * (REQUIRED) Whether to generate an API report. */ - "enabled": true, + "enabled": true /** - * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce - * a full file path. + * The base filename for the API report files, to be combined with "reportFolder" or "reportTempFolder" + * to produce the full file path. The "reportFileName" should not include any path separators such as + * "\" or "/". The "reportFileName" should not include a file extension, since API Extractor will automatically + * append an appropriate file extension such as ".api.md". If the "reportVariants" setting is used, then the + * file extension includes the variant name, for example "my-report.public.api.md" or "my-report.beta.api.md". + * The "complete" variant always uses the simple extension "my-report.api.md". * - * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". + * Previous versions of API Extractor required "reportFileName" to include the ".api.md" extension explicitly; + * for backwards compatibility, that is still accepted but will be discarded before applying the above rules. * * SUPPORTED TOKENS: , - * DEFAULT VALUE: ".api.md" + * DEFAULT VALUE: "" */ - // "reportFileName": ".api.md", + // "reportFileName": "", + + /** + * To support different approval requirements for different API levels, multiple "variants" of the API report can + * be generated. The "reportVariants" setting specifies a list of variants to be generated. If omitted, + * by default only the "complete" variant will be generated, which includes all @internal, @alpha, @beta, + * and @public items. Other possible variants are "alpha" (@alpha + @beta + @public), "beta" (@beta + @public), + * and "public" (@public only). + * + * DEFAULT VALUE: [ "complete" ] + */ + // "reportVariants": ["public", "beta"], /** * Specifies the folder where the API report file is written. The file name portion is determined by @@ -152,7 +199,16 @@ * SUPPORTED TOKENS: , , * DEFAULT VALUE: "/temp/" */ - // "reportTempFolder": "/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 }, /** @@ -162,7 +218,7 @@ /** * (REQUIRED) Whether to generate a doc model file. */ - "enabled": true, + "enabled": true /** * The output path for the doc model file. The file extension should be ".api.json". @@ -173,7 +229,32 @@ * SUPPORTED TOKENS: , , * DEFAULT VALUE: "/temp/.api.json" */ - // "apiJsonFilePath": "/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". + * + * This setting 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" }, /** @@ -183,7 +264,7 @@ /** * (REQUIRED) Whether to generate the .d.ts rollup file. */ - "enabled": true, + "enabled": true /** * Specifies the output path for a .d.ts rollup file to be generated without any trimming. @@ -199,10 +280,26 @@ */ // "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". + * + * 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: "" + */ + // "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". * + * 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 "". * @@ -211,7 +308,6 @@ */ // "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". @@ -246,7 +342,6 @@ * DEFAULT VALUE: true */ // "enabled": true, - /** * Specifies where the TSDoc metadata file should be written. * @@ -263,15 +358,6 @@ // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" }, - /** - * 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", - /** * Configures how API Extractor reports error and warning messages produced during analysis. * @@ -303,7 +389,7 @@ * * DEFAULT VALUE: "warning" */ - "logLevel": "warning", + "logLevel": "warning" /** * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), @@ -313,7 +399,7 @@ * DEFAULT VALUE: false */ // "addToApiReportFile": false - }, + } // "TS2551": { // "logLevel": "warning", @@ -332,9 +418,9 @@ */ "extractorMessageReporting": { "default": { - "logLevel": "warning", + "logLevel": "warning" // "addToApiReportFile": false - }, + } // "ae-extra-release-tag": { // "logLevel": "warning", @@ -353,7 +439,7 @@ */ "tsdocMessageReporting": { "default": { - "logLevel": "warning", + "logLevel": "warning" // "addToApiReportFile": false } @@ -365,5 +451,4 @@ // . . . } } - } diff --git a/apps/api-extractor/src/schemas/api-extractor.schema.json b/apps/api-extractor/src/schemas/api-extractor.schema.json index 153b3739000..20773498c59 100644 --- a/apps/api-extractor/src/schemas/api-extractor.schema.json +++ b/apps/api-extractor/src/schemas/api-extractor.schema.json @@ -14,7 +14,7 @@ }, "projectFolder": { - "description": "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.", + "description": "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 using the following heuristics:\n\nIf the config/rig.json system is used (as defined by @rushstack/rig-package), then the \"\" value will be the package folder that referenced the rig.\n\nOtherwise, the \"\" value 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.", "type": "string" }, @@ -24,13 +24,32 @@ }, "bundledPackages": { - "description": "A list of NPM package names whose exports should be treated as part of this package.", + "description": "A list of NPM package names whose exports should be treated as part of this package. Also supports glob patterns.", "type": "array", "items": { "type": "string" } }, + "newlineKind": { + "description": "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\".", + "type": "string", + "enum": ["crlf", "lf", "os"], + "default": "crlf" + }, + + "enumMemberOrder": { + "description": "Specifies how API Extractor sorts the members of an enum when generating the .api.json doc model. \n 'by-name': sort the items according to the enum member name \n 'preserve': keep the original order that items appear in the source code", + "type": "string", + "enum": ["by-name", "preserve"], + "default": "by-name" + }, + + "testMode": { + "description": "Set to true 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.", + "type": "boolean" + }, + "compiler": { "description": "Determines how the TypeScript compiler engine will be invoked by API Extractor.", "type": "object", @@ -61,8 +80,17 @@ }, "reportFileName": { - "description": "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 \"/\".", - "type": "string" + "description": "The base filename for the API report files, to be combined with \"reportFolder\" or \"reportTempFolder\" to produce the full file path. The \"reportFileName\" should not include any path separators such as \"\\\" or \"/\". The \"reportFileName\" should not include a file extension, since API Extractor will automatically append an appropriate file extension such as \".api.md\". If the \"reportVariants\" setting is used, then the file extension includes the variant name, for example \"my-report.public.api.md\" or \"my-report.beta.api.md\". The \"complete\" variant always uses the simple extension \"my-report.api.md\".\n\nPrevious versions of API Extractor required \"reportFileName\" to include the \".api.md\" extension explicitly; for backwards compatibility, that is still accepted but will be discarded before applying the above rules.", + "type": ["string"] + }, + + "reportVariants": { + "description": "To support different approval requirements for different API levels, multiple \"variants\" of the API report can be generated. The \"reportVariants\" setting specifies a list of variants to be generated. If omitted, by default only the \"complete\" variant will be generated, which includes all @internal, @alpha, @beta, and @public items. Other possible variants are \"alpha\" (@alpha + @beta + @public), \"beta\" (@beta + @public), and \"public\" (@public only).", + "type": "array", + "items": { + "type": "string", + "enum": ["public", "beta", "alpha", "complete"] + } }, "reportFolder": { @@ -73,10 +101,25 @@ "reportTempFolder": { "description": "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 \"\".", "type": "string" - } + }, + + "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" ], + "required": ["enabled"], "additionalProperties": false }, @@ -91,9 +134,25 @@ "apiJsonFilePath": { "description": "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 \"\".", "type": "string" + }, + "includeForgottenExports": { + "description": "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.", + "type": "boolean" + }, + "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" ], + "required": ["enabled"], "additionalProperties": false }, @@ -109,6 +168,10 @@ "description": "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 \"\".", "type": "string" }, + "alphaTrimmedFilePath": { + "description": "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 \"\".", + "type": "string" + }, "betaTrimmedFilePath": { "description": "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 \"\".", "type": "string" @@ -122,7 +185,7 @@ "type": "boolean" } }, - "required": [ "enabled" ], + "required": ["enabled"], "additionalProperties": false }, @@ -142,13 +205,6 @@ "additionalProperties": false }, - "newlineKind": { - "description": "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\".", - "type": "string", - "enum": ["crlf", "lf", "os"], - "default": "crlf" - }, - "messages": { "description": "Configures how API Extractor reports error and warning messages produced during analysis.", "type": "object", @@ -167,19 +223,14 @@ } }, "additionalProperties": false - }, - - "testMode": { - "description": "Set to true 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.", - "type": "boolean" } }, - "required": [ "mainEntryPointFilePath" ], + "required": ["mainEntryPointFilePath"], "additionalProperties": false, "definitions": { "extractorMessageReportingTable": { - "type":"object", + "type": "object", "description": "Specifies a table of reporting rules for different message identifiers, and also the default rule used for identifiers that do not appear in the table. The key is a message identifier for the associated type of message, or \"default\" to specify the default policy. For example, the key might be \"TS2551\" (a compiler message), \"tsdoc-link-tag-unescaped-text\" (a TSDOc message), or \"ae-extra-release-tag\" (a message related to the API Extractor analysis).", "patternProperties": { ".+": { @@ -189,7 +240,7 @@ "logLevel": { "type": "string", "description": "Specifies whether the message should be written to the the tool's output log. Note that the \"addToApiReportFile\" property may supersede this option.", - "enum": [ "error", "warning", "none" ] + "enum": ["error", "warning", "none"] }, "addToApiReportFile": { "type": "boolean", @@ -197,7 +248,7 @@ } }, "additionalProperties": false, - "required": [ "logLevel" ] + "required": ["logLevel"] } }, "additionalProperties": false diff --git a/apps/api-extractor/src/start.ts b/apps/api-extractor/src/start.ts index 8fce9a0b64a..2274fea6b22 100644 --- a/apps/api-extractor/src/start.ts +++ b/apps/api-extractor/src/start.ts @@ -1,18 +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 os from 'os'; -import * as colors from 'colors'; +import * as os from 'node:os'; + +import { Colorize } from '@rushstack/terminal'; import { ApiExtractorCommandLine } from './cli/ApiExtractorCommandLine'; import { Extractor } from './api/Extractor'; -console.log(os.EOL + colors.bold(`api-extractor ${Extractor.version} ` - + colors.cyan(' - https://api-extractor.com/') + os.EOL)); +console.log( + os.EOL + + Colorize.bold( + `api-extractor ${Extractor.version} ` + Colorize.cyan(' - https://api-extractor.com/') + os.EOL + ) +); const parser: ApiExtractorCommandLine = new ApiExtractorCommandLine(); -parser.execute().catch((error) => { - console.error(colors.red(`An unexpected error occurred: ${error}`)); +parser.executeAsync().catch((error) => { + console.error(Colorize.red(`An unexpected error occurred: ${error}`)); process.exit(1); }); diff --git a/apps/api-extractor/tsconfig.json b/apps/api-extractor/tsconfig.json index 824a88b71e5..1a33d17b873 100644 --- a/apps/api-extractor/tsconfig.json +++ b/apps/api-extractor/tsconfig.json @@ -1,10 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } + "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..bc349f9a4be --- /dev/null +++ b/apps/cpu-profile-summarizer/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..5d1fbf739b6 --- /dev/null +++ b/apps/cpu-profile-summarizer/CHANGELOG.json @@ -0,0 +1,602 @@ +{ + "name": "@rushstack/cpu-profile-summarizer", + "entries": [ + { + "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..857c892f84c --- /dev/null +++ b/apps/cpu-profile-summarizer/CHANGELOG.md @@ -0,0 +1,191 @@ +# Change Log - @rushstack/cpu-profile-summarizer + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..aee68e80224 --- /dev/null +++ b/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/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..78e8c788ff5 --- /dev/null +++ b/apps/cpu-profile-summarizer/package.json @@ -0,0 +1,29 @@ +{ + "name": "@rushstack/cpu-profile-summarizer", + "version": "0.1.36", + "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:*" + } +} 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/.npmignore b/apps/heft/.npmignore new file mode 100644 index 00000000000..3b7d5ed9526 --- /dev/null +++ b/apps/heft/.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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** +!UPGRADING.md + diff --git a/apps/heft/.vscode/launch.json b/apps/heft/.vscode/launch.json new file mode 100644 index 00000000000..eb6f0400882 --- /dev/null +++ b/apps/heft/.vscode/launch.json @@ -0,0 +1,95 @@ +{ + // 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": [ + { + "name": "Attach by Process ID", + "processId": "${command:PickProcess}", + "request": "attach", + "skipFiles": ["/**"], + "type": "pwa-node" + }, + { + "type": "node", + "request": "launch", + "name": "Run in specified folder", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "(your project path)", + "args": ["--debug", "build", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Debug Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "node-basic build", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../build-tests/heft-node-basic-test/", + "args": ["--debug", "build", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "node-basic test", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../tutorials/heft-node-basic-tutorial/", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "node-basic test --watch", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../tutorials/heft-node-basic-tutorial/", + "args": ["--debug", "test", "--watch", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "webpack-basic build", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../tutorials/heft-webpack-basic-tutorial/", + "args": ["--debug", "build", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "webpack-basic test", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../tutorials/heft-webpack-basic-tutorial/", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "webpack-basic start", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../tutorials/heft-webpack-basic-tutorial/", + "args": ["--debug", "start", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + } + ] +} diff --git a/apps/heft/CHANGELOG.json b/apps/heft/CHANGELOG.json new file mode 100644 index 00000000000..15f45ed6116 --- /dev/null +++ b/apps/heft/CHANGELOG.json @@ -0,0 +1,6982 @@ +{ + "name": "@rushstack/heft", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + } + ] + } + }, + { + "version": "0.68.10", + "tag": "@rushstack/heft_v0.68.10", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.1`" + } + ] + } + }, + { + "version": "0.68.9", + "tag": "@rushstack/heft_v0.68.9", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.68.8", + "tag": "@rushstack/heft_v0.68.8", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + } + ] + } + }, + { + "version": "0.68.7", + "tag": "@rushstack/heft_v0.68.7", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + } + ] + } + }, + { + "version": "0.68.6", + "tag": "@rushstack/heft_v0.68.6", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.8`" + } + ] + } + }, + { + "version": "0.68.5", + "tag": "@rushstack/heft_v0.68.5", + "date": "Mon, 21 Oct 2024 18:50:09 GMT", + "comments": { + "patch": [ + { + "comment": "Remove usage of true-case-path in favor of manually adjusting the drive letter casing to avoid confusing file system tracing tools with unnecessary directory enumerations." + } + ] + } + }, + { + "version": "0.68.4", + "tag": "@rushstack/heft_v0.68.4", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + } + ] + } + }, + { + "version": "0.68.3", + "tag": "@rushstack/heft_v0.68.3", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + } + ] + } + }, + { + "version": "0.68.2", + "tag": "@rushstack/heft_v0.68.2", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure `configHash` for file copy incremental cache file is portable." + } + ] + } + }, + { + "version": "0.68.1", + "tag": "@rushstack/heft_v0.68.1", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "patch": [ + { + "comment": "Include all previous `inputFileVersions` in incremental copy files cache file during watch mode. Fix incorrect serialization of cache file for file copy." + } + ] + } + }, + { + "version": "0.68.0", + "tag": "@rushstack/heft_v0.68.0", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "minor": [ + { + "comment": "Update file copy logic to use an incremental cache file in the temp directory for the current task to avoid unnecessary file writes." + } + ] + } + }, + { + "version": "0.67.2", + "tag": "@rushstack/heft_v0.67.2", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + } + ] + } + }, + { + "version": "0.67.1", + "tag": "@rushstack/heft_v0.67.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + } + ] + } + }, + { + "version": "0.67.0", + "tag": "@rushstack/heft_v0.67.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `slashNormalizedBuildFolderPath` property to `HeftConfiguration`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + } + ] + } + }, + { + "version": "0.66.26", + "tag": "@rushstack/heft_v0.66.26", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + } + ] + } + }, + { + "version": "0.66.25", + "tag": "@rushstack/heft_v0.66.25", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + } + ] + } + }, + { + "version": "0.66.24", + "tag": "@rushstack/heft_v0.66.24", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + } + ] + } + }, + { + "version": "0.66.23", + "tag": "@rushstack/heft_v0.66.23", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + } + ] + } + }, + { + "version": "0.66.22", + "tag": "@rushstack/heft_v0.66.22", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + } + ] + } + }, + { + "version": "0.66.21", + "tag": "@rushstack/heft_v0.66.21", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.27`" + } + ] + } + }, + { + "version": "0.66.20", + "tag": "@rushstack/heft_v0.66.20", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update schemas/templates/heft.json to reflect new settings" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + } + ] + } + }, + { + "version": "0.66.19", + "tag": "@rushstack/heft_v0.66.19", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.66.18", + "tag": "@rushstack/heft_v0.66.18", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + } + ] + } + }, + { + "version": "0.66.17", + "tag": "@rushstack/heft_v0.66.17", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + } + ] + } + }, + { + "version": "0.66.16", + "tag": "@rushstack/heft_v0.66.16", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + } + ] + } + }, + { + "version": "0.66.15", + "tag": "@rushstack/heft_v0.66.15", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + } + ] + } + }, + { + "version": "0.66.14", + "tag": "@rushstack/heft_v0.66.14", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + } + ] + } + }, + { + "version": "0.66.13", + "tag": "@rushstack/heft_v0.66.13", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + } + ] + } + }, + { + "version": "0.66.12", + "tag": "@rushstack/heft_v0.66.12", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + } + ] + } + }, + { + "version": "0.66.11", + "tag": "@rushstack/heft_v0.66.11", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + } + ] + } + }, + { + "version": "0.66.10", + "tag": "@rushstack/heft_v0.66.10", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "patch": [ + { + "comment": "Update schema definitions to conform to strict schema-type validation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + } + ] + } + }, + { + "version": "0.66.9", + "tag": "@rushstack/heft_v0.66.9", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + } + ] + } + }, + { + "version": "0.66.8", + "tag": "@rushstack/heft_v0.66.8", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + } + ] + } + }, + { + "version": "0.66.7", + "tag": "@rushstack/heft_v0.66.7", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + } + ] + } + }, + { + "version": "0.66.6", + "tag": "@rushstack/heft_v0.66.6", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + } + ] + } + }, + { + "version": "0.66.5", + "tag": "@rushstack/heft_v0.66.5", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + } + ] + } + }, + { + "version": "0.66.4", + "tag": "@rushstack/heft_v0.66.4", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + } + ] + } + }, + { + "version": "0.66.3", + "tag": "@rushstack/heft_v0.66.3", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + } + ] + } + }, + { + "version": "0.66.2", + "tag": "@rushstack/heft_v0.66.2", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + } + ] + } + }, + { + "version": "0.66.1", + "tag": "@rushstack/heft_v0.66.1", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "patch": [ + { + "comment": "Fix internal error when run 'heft clean'" + } + ] + } + }, + { + "version": "0.66.0", + "tag": "@rushstack/heft_v0.66.0", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "minor": [ + { + "comment": "Add new metrics value `bootDurationMs` to track the boot overhead of Heft before the action starts executing the subtasks. Update the start time used to compute `taskTotalExecutionMs` to be the beginning of operation graph execution. Fix the value of `taskTotalExecutionMs` field to be in milliseconds instead of seconds. Add new metrics value `totalUptimeMs` to track how long watch mode sessions are kept alive." + } + ] + } + }, + { + "version": "0.65.10", + "tag": "@rushstack/heft_v0.65.10", + "date": "Sun, 03 Mar 2024 20:58:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + } + ] + } + }, + { + "version": "0.65.9", + "tag": "@rushstack/heft_v0.65.9", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + } + ] + } + }, + { + "version": "0.65.8", + "tag": "@rushstack/heft_v0.65.8", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + } + ] + } + }, + { + "version": "0.65.7", + "tag": "@rushstack/heft_v0.65.7", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + } + ] + } + }, + { + "version": "0.65.6", + "tag": "@rushstack/heft_v0.65.6", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + } + ] + } + }, + { + "version": "0.65.5", + "tag": "@rushstack/heft_v0.65.5", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + } + ] + } + }, + { + "version": "0.65.4", + "tag": "@rushstack/heft_v0.65.4", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.13`" + } + ] + } + }, + { + "version": "0.65.3", + "tag": "@rushstack/heft_v0.65.3", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + } + ] + } + }, + { + "version": "0.65.2", + "tag": "@rushstack/heft_v0.65.2", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + } + ] + } + }, + { + "version": "0.65.1", + "tag": "@rushstack/heft_v0.65.1", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a recent regression causing `Error: Cannot find module 'colors/safe'` (GitHub #4525)" + }, + { + "comment": "Remove a no longer needed dependency on the `chokidar` package" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + } + ] + } + }, + { + "version": "0.65.0", + "tag": "@rushstack/heft_v0.65.0", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Add a built-in `set-environment-variables-plugin` task plugin to set environment variables." + } + ] + } + }, + { + "version": "0.64.8", + "tag": "@rushstack/heft_v0.64.8", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + } + ] + } + }, + { + "version": "0.64.7", + "tag": "@rushstack/heft_v0.64.7", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + } + ] + } + }, + { + "version": "0.64.6", + "tag": "@rushstack/heft_v0.64.6", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + } + ] + } + }, + { + "version": "0.64.5", + "tag": "@rushstack/heft_v0.64.5", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + } + ] + } + }, + { + "version": "0.64.4", + "tag": "@rushstack/heft_v0.64.4", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + } + ] + } + }, + { + "version": "0.64.3", + "tag": "@rushstack/heft_v0.64.3", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + } + ] + } + }, + { + "version": "0.64.2", + "tag": "@rushstack/heft_v0.64.2", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + } + ] + } + }, + { + "version": "0.64.1", + "tag": "@rushstack/heft_v0.64.1", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + } + ] + } + }, + { + "version": "0.64.0", + "tag": "@rushstack/heft_v0.64.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.63.6", + "tag": "@rushstack/heft_v0.63.6", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + } + ] + } + }, + { + "version": "0.63.5", + "tag": "@rushstack/heft_v0.63.5", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + } + ] + } + }, + { + "version": "0.63.4", + "tag": "@rushstack/heft_v0.63.4", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + } + ] + } + }, + { + "version": "0.63.3", + "tag": "@rushstack/heft_v0.63.3", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + } + ] + } + }, + { + "version": "0.63.2", + "tag": "@rushstack/heft_v0.63.2", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + } + ] + } + }, + { + "version": "0.63.1", + "tag": "@rushstack/heft_v0.63.1", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + } + ] + } + }, + { + "version": "0.63.0", + "tag": "@rushstack/heft_v0.63.0", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with parsing of the \"--debug\" and \"--unmanaged\" flags for Heft" + } + ], + "minor": [ + { + "comment": "[BREAKING CHANGE] Remove \"heft run\" short-parameters for \"--to\" (\"-t\"), \"--to-except\" (\"-T\"), and \"--only\" (\"-o\")." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + } + ] + } + }, + { + "version": "0.62.3", + "tag": "@rushstack/heft_v0.62.3", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + } + ] + } + }, + { + "version": "0.62.2", + "tag": "@rushstack/heft_v0.62.2", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + } + ] + } + }, + { + "version": "0.62.1", + "tag": "@rushstack/heft_v0.62.1", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + } + ] + } + }, + { + "version": "0.62.0", + "tag": "@rushstack/heft_v0.62.0", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING API CHANGE) Remove the deprecated `cancellationToken` property of `IHeftTaskRunHookOptions`. Use `abortSignal` on that object instead." + } + ] + } + }, + { + "version": "0.61.3", + "tag": "@rushstack/heft_v0.61.3", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where `heft clean` would crash with `ERR_ILLEGAL_CONSTRUCTOR`." + } + ] + } + }, + { + "version": "0.61.2", + "tag": "@rushstack/heft_v0.61.2", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + } + ] + } + }, + { + "version": "0.61.1", + "tag": "@rushstack/heft_v0.61.1", + "date": "Mon, 25 Sep 2023 23:38:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.61.0", + "tag": "@rushstack/heft_v0.61.0", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE): Rename task temp folder from \".\" to \"/\" to simplify caching phase outputs." + } + ] + } + }, + { + "version": "0.60.0", + "tag": "@rushstack/heft_v0.60.0", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "minor": [ + { + "comment": "Allow Heft to communicate via IPC with a host process when running in watch mode. The host controls scheduling of incremental re-runs." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.59.0", + "tag": "@rushstack/heft_v0.59.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "patch": [ + { + "comment": "Migrate plugin name collision detection to the InternalHeftSession instance to allow multiple Heft sessions in the same process." + } + ], + "none": [ + { + "comment": "Avoid mutating config files after reading." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "0.58.2", + "tag": "@rushstack/heft_v0.58.2", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "0.58.1", + "tag": "@rushstack/heft_v0.58.1", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the `toolFinish` lifecycle hook so that it is invoked after the `recordMetrics` hook, rather than before. Ensure that the `toolFinish` lifecycle hook is invoked if the user performs a graceful shutdown of Heft (e.g. via Ctrl+C)." + } + ] + } + }, + { + "version": "0.58.0", + "tag": "@rushstack/heft_v0.58.0", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "minor": [ + { + "comment": "BREAKING CHANGE: Update the heft.json \"cleanFiles\" property and the delete-files-plugin to delete the contents of folders specified by \"sourcePath\" instead of deleting the folders themselves. To delete the folders, use the \"includeGlobs\" property to specify the folder to delete." + } + ] + } + }, + { + "version": "0.57.1", + "tag": "@rushstack/heft_v0.57.1", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + } + ] + } + }, + { + "version": "0.57.0", + "tag": "@rushstack/heft_v0.57.0", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "minor": [ + { + "comment": "Support `--clean` in watch mode. Cleaning in watch mode is now performed only during the first-pass of lifecycle or phase operations. Once the clean has been completed, `--clean` will be ignored until the command is restarted" + } + ] + } + }, + { + "version": "0.56.3", + "tag": "@rushstack/heft_v0.56.3", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + } + ] + } + }, + { + "version": "0.56.2", + "tag": "@rushstack/heft_v0.56.2", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "patch": [ + { + "comment": "Revise README.md and UPGRADING.md documentation" + } + ] + } + }, + { + "version": "0.56.1", + "tag": "@rushstack/heft_v0.56.1", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + } + ] + } + }, + { + "version": "0.56.0", + "tag": "@rushstack/heft_v0.56.0", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "minor": [ + { + "comment": "Use the `IRigConfig` interface in the `HeftConfiguration` object insteacd of the `RigConfig` class." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + } + ] + } + }, + { + "version": "0.55.2", + "tag": "@rushstack/heft_v0.55.2", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "0.55.1", + "tag": "@rushstack/heft_v0.55.1", + "date": "Wed, 14 Jun 2023 00:19:41 GMT", + "comments": { + "patch": [ + { + "comment": "Add MockScopedLogger to help plugin authors with unit testing." + } + ] + } + }, + { + "version": "0.55.0", + "tag": "@rushstack/heft_v0.55.0", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "minor": [ + { + "comment": "Remove the deprecated `cacheFolderPath` property from the session object." + } + ] + } + }, + { + "version": "0.54.0", + "tag": "@rushstack/heft_v0.54.0", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "minor": [ + { + "comment": "Add plugin support for parameter short-names." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + } + ] + } + }, + { + "version": "0.53.1", + "tag": "@rushstack/heft_v0.53.1", + "date": "Fri, 09 Jun 2023 18:05:34 GMT", + "comments": { + "patch": [ + { + "comment": "Revise CHANGELOG.md to more clearly identify the breaking changes" + } + ] + } + }, + { + "version": "0.53.0", + "tag": "@rushstack/heft_v0.53.0", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "patch": [ + { + "comment": "Update UPGRADING.md with new JSON schema URLs" + } + ], + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove \"taskEvents\" heft.json configuration option, and replace it with directly referencing the included plugins. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md" + } + ] + } + }, + { + "version": "0.52.2", + "tag": "@rushstack/heft_v0.52.2", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "patch": [ + { + "comment": "Provide a useful error message when encountering legacy Heft configurations" + } + ] + } + }, + { + "version": "0.52.1", + "tag": "@rushstack/heft_v0.52.1", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "patch": [ + { + "comment": "Remove the concept of the cache folder, since it mostly just causes bugs." + } + ] + } + }, + { + "version": "0.52.0", + "tag": "@rushstack/heft_v0.52.0", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new API IHeftTaskSession.parsedCommandLine for accessing the invoked command name" + }, + { + "comment": "(BREAKING CHANGE) The built-in task NodeServicePlugin now supports the \"--serve\" mode with semantics similar to heft-webpack5-plugin. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md" + } + ], + "patch": [ + { + "comment": "Add action aliases support. Action aliases can be used to create custom \"heft \" commands which call existing Heft commands with optional default arguments." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.14.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "0.51.0", + "tag": "@rushstack/heft_v0.51.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Overhaul to support splitting single-project builds into more phases than \"build\" and \"test\", to align with Rush phased commands. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md" + } + ] + } + }, + { + "version": "0.50.7", + "tag": "@rushstack/heft_v0.50.7", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + } + ] + } + }, + { + "version": "0.50.6", + "tag": "@rushstack/heft_v0.50.6", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "0.50.5", + "tag": "@rushstack/heft_v0.50.5", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + } + ] + } + }, + { + "version": "0.50.4", + "tag": "@rushstack/heft_v0.50.4", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + } + ] + } + }, + { + "version": "0.50.3", + "tag": "@rushstack/heft_v0.50.3", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + } + ] + } + }, + { + "version": "0.50.2", + "tag": "@rushstack/heft_v0.50.2", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "patch": [ + { + "comment": "Fix issues where a terminal logging prefix may be added multiple times to the same line, or only to the first line" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + } + ] + } + }, + { + "version": "0.50.1", + "tag": "@rushstack/heft_v0.50.1", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + } + ] + } + }, + { + "version": "0.50.0", + "tag": "@rushstack/heft_v0.50.0", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "minor": [ + { + "comment": "Remove monkey-patching of TypeScript for compatibility with 5.0. Refactors how the multi-emit logic works." + } + ] + } + }, + { + "version": "0.49.7", + "tag": "@rushstack/heft_v0.49.7", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "0.49.6", + "tag": "@rushstack/heft_v0.49.6", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + } + ] + } + }, + { + "version": "0.49.5", + "tag": "@rushstack/heft_v0.49.5", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + } + ] + } + }, + { + "version": "0.49.4", + "tag": "@rushstack/heft_v0.49.4", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + } + ] + } + }, + { + "version": "0.49.3", + "tag": "@rushstack/heft_v0.49.3", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.5`" + } + ] + } + }, + { + "version": "0.49.2", + "tag": "@rushstack/heft_v0.49.2", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + } + ] + } + }, + { + "version": "0.49.1", + "tag": "@rushstack/heft_v0.49.1", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + } + ] + } + }, + { + "version": "0.49.0", + "tag": "@rushstack/heft_v0.49.0", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "minor": [ + { + "comment": "Replace Terminal with ITerminal in the API." + } + ] + } + }, + { + "version": "0.48.9", + "tag": "@rushstack/heft_v0.48.9", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + } + ] + } + }, + { + "version": "0.48.8", + "tag": "@rushstack/heft_v0.48.8", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + } + ] + } + }, + { + "version": "0.48.7", + "tag": "@rushstack/heft_v0.48.7", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + } + ] + } + }, + { + "version": "0.48.6", + "tag": "@rushstack/heft_v0.48.6", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + } + ] + } + }, + { + "version": "0.48.5", + "tag": "@rushstack/heft_v0.48.5", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + } + ] + } + }, + { + "version": "0.48.4", + "tag": "@rushstack/heft_v0.48.4", + "date": "Fri, 14 Oct 2022 15:26:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + } + ] + } + }, + { + "version": "0.48.3", + "tag": "@rushstack/heft_v0.48.3", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + } + ] + } + }, + { + "version": "0.48.2", + "tag": "@rushstack/heft_v0.48.2", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + } + ] + } + }, + { + "version": "0.48.1", + "tag": "@rushstack/heft_v0.48.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "0.48.0", + "tag": "@rushstack/heft_v0.48.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "0.47.11", + "tag": "@rushstack/heft_v0.47.11", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.47.10", + "tag": "@rushstack/heft_v0.47.10", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + } + ] + } + }, + { + "version": "0.47.9", + "tag": "@rushstack/heft_v0.47.9", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "0.47.8", + "tag": "@rushstack/heft_v0.47.8", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + } + ] + } + }, + { + "version": "0.47.7", + "tag": "@rushstack/heft_v0.47.7", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + } + ] + } + }, + { + "version": "0.47.6", + "tag": "@rushstack/heft_v0.47.6", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + } + ] + } + }, + { + "version": "0.47.5", + "tag": "@rushstack/heft_v0.47.5", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + } + ] + } + }, + { + "version": "0.47.4", + "tag": "@rushstack/heft_v0.47.4", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + } + ] + } + }, + { + "version": "0.47.3", + "tag": "@rushstack/heft_v0.47.3", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + } + ] + } + }, + { + "version": "0.47.2", + "tag": "@rushstack/heft_v0.47.2", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + } + ] + } + }, + { + "version": "0.47.1", + "tag": "@rushstack/heft_v0.47.1", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + } + ] + } + }, + { + "version": "0.47.0", + "tag": "@rushstack/heft_v0.47.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Update the highest supported version of TypeScript to 4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "0.46.7", + "tag": "@rushstack/heft_v0.46.7", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + } + ] + } + }, + { + "version": "0.46.6", + "tag": "@rushstack/heft_v0.46.6", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + } + ] + } + }, + { + "version": "0.46.5", + "tag": "@rushstack/heft_v0.46.5", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + } + ] + } + }, + { + "version": "0.46.4", + "tag": "@rushstack/heft_v0.46.4", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.46.3", + "tag": "@rushstack/heft_v0.46.3", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + } + ] + } + }, + { + "version": "0.46.2", + "tag": "@rushstack/heft_v0.46.2", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the `locales` build property. The property is now undefined if no `--locale` parameters are specified." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + } + ] + } + }, + { + "version": "0.46.1", + "tag": "@rushstack/heft_v0.46.1", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + } + ] + } + }, + { + "version": "0.46.0", + "tag": "@rushstack/heft_v0.46.0", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Update the --locale build parameter to support multiple values and replace the `locale?: string` parameter in `IBuildStageProperties` with a `locales?: readonly string[]` parameter." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + } + ] + } + }, + { + "version": "0.45.14", + "tag": "@rushstack/heft_v0.45.14", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "0.45.13", + "tag": "@rushstack/heft_v0.45.13", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + } + ] + } + }, + { + "version": "0.45.12", + "tag": "@rushstack/heft_v0.45.12", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + } + ] + } + }, + { + "version": "0.45.11", + "tag": "@rushstack/heft_v0.45.11", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + } + ] + } + }, + { + "version": "0.45.10", + "tag": "@rushstack/heft_v0.45.10", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + } + ] + } + }, + { + "version": "0.45.9", + "tag": "@rushstack/heft_v0.45.9", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + } + ] + } + }, + { + "version": "0.45.8", + "tag": "@rushstack/heft_v0.45.8", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + } + ] + } + }, + { + "version": "0.45.7", + "tag": "@rushstack/heft_v0.45.7", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "0.45.6", + "tag": "@rushstack/heft_v0.45.6", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + } + ] + } + }, + { + "version": "0.45.5", + "tag": "@rushstack/heft_v0.45.5", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + } + ] + } + }, + { + "version": "0.45.4", + "tag": "@rushstack/heft_v0.45.4", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + } + ] + } + }, + { + "version": "0.45.3", + "tag": "@rushstack/heft_v0.45.3", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + } + ] + } + }, + { + "version": "0.45.2", + "tag": "@rushstack/heft_v0.45.2", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + } + ] + } + }, + { + "version": "0.45.1", + "tag": "@rushstack/heft_v0.45.1", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + } + ] + } + }, + { + "version": "0.45.0", + "tag": "@rushstack/heft_v0.45.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "0.44.13", + "tag": "@rushstack/heft_v0.44.13", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "0.44.12", + "tag": "@rushstack/heft_v0.44.12", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + } + ] + } + }, + { + "version": "0.44.11", + "tag": "@rushstack/heft_v0.44.11", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + } + ] + } + }, + { + "version": "0.44.10", + "tag": "@rushstack/heft_v0.44.10", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + } + ] + } + }, + { + "version": "0.44.9", + "tag": "@rushstack/heft_v0.44.9", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + } + ] + } + }, + { + "version": "0.44.8", + "tag": "@rushstack/heft_v0.44.8", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "0.44.7", + "tag": "@rushstack/heft_v0.44.7", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + } + ] + } + }, + { + "version": "0.44.6", + "tag": "@rushstack/heft_v0.44.6", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + } + ] + } + }, + { + "version": "0.44.5", + "tag": "@rushstack/heft_v0.44.5", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + } + ] + } + }, + { + "version": "0.44.4", + "tag": "@rushstack/heft_v0.44.4", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.44.3", + "tag": "@rushstack/heft_v0.44.3", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "0.44.2", + "tag": "@rushstack/heft_v0.44.2", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + } + ] + } + }, + { + "version": "0.44.1", + "tag": "@rushstack/heft_v0.44.1", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "0.44.0", + "tag": "@rushstack/heft_v0.44.0", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "minor": [ + { + "comment": "Remove Jest-specific CLI arguments from Heft. These parameters have been moved to @rushstack/heft-jest-plugin." + } + ] + } + }, + { + "version": "0.43.2", + "tag": "@rushstack/heft_v0.43.2", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + } + ] + } + }, + { + "version": "0.43.1", + "tag": "@rushstack/heft_v0.43.1", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + } + ] + } + }, + { + "version": "0.43.0", + "tag": "@rushstack/heft_v0.43.0", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.5" + } + ] + } + }, + { + "version": "0.42.6", + "tag": "@rushstack/heft_v0.42.6", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + } + ] + } + }, + { + "version": "0.42.5", + "tag": "@rushstack/heft_v0.42.5", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "0.42.4", + "tag": "@rushstack/heft_v0.42.4", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + } + ] + } + }, + { + "version": "0.42.3", + "tag": "@rushstack/heft_v0.42.3", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "patch": [ + { + "comment": "Remove an unused dependency." + } + ] + } + }, + { + "version": "0.42.2", + "tag": "@rushstack/heft_v0.42.2", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.19`" + } + ] + } + }, + { + "version": "0.42.1", + "tag": "@rushstack/heft_v0.42.1", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "0.42.0", + "tag": "@rushstack/heft_v0.42.0", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "minor": [ + { + "comment": "Add environment variables for common heft test parameters" + } + ] + } + }, + { + "version": "0.41.8", + "tag": "@rushstack/heft_v0.41.8", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "0.41.7", + "tag": "@rushstack/heft_v0.41.7", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "0.41.6", + "tag": "@rushstack/heft_v0.41.6", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fix reuse of TypeScript program to avoid breaking on older versions of @typescript-eslint/typescript-estree" + } + ] + } + }, + { + "version": "0.41.5", + "tag": "@rushstack/heft_v0.41.5", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.15`" + } + ] + } + }, + { + "version": "0.41.4", + "tag": "@rushstack/heft_v0.41.4", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "patch": [ + { + "comment": "Re-use the compiler TypeScript program when running ESLint to reduce overhead" + } + ] + } + }, + { + "version": "0.41.3", + "tag": "@rushstack/heft_v0.41.3", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix support for TypeScript 4.4 in --watch mode." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "0.41.2", + "tag": "@rushstack/heft_v0.41.2", + "date": "Wed, 06 Oct 2021 15:08:25 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the HeftSession.commandLine.registerParameter interface and add support for choice and choice list parameters. " + } + ] + } + }, + { + "version": "0.41.1", + "tag": "@rushstack/heft_v0.41.1", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "patch": [ + { + "comment": "Replace ITerminal with Terminal in data structure values to preserve compatability with plugins written before ITerminal." + } + ] + } + }, + { + "version": "0.41.0", + "tag": "@rushstack/heft_v0.41.0", + "date": "Tue, 05 Oct 2021 15:08:37 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.13`" + } + ] + } + }, + { + "version": "0.40.0", + "tag": "@rushstack/heft_v0.40.0", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Add register custom parameters feature to Heft." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.12`" + } + ] + } + }, + { + "version": "0.39.2", + "tag": "@rushstack/heft_v0.39.2", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.11`" + } + ] + } + }, + { + "version": "0.39.1", + "tag": "@rushstack/heft_v0.39.1", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "0.39.0", + "tag": "@rushstack/heft_v0.39.0", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"encounteredErrors\" boolean to IMetricsData." + } + ], + "patch": [ + { + "comment": "Fix typo in temp folder path." + } + ] + } + }, + { + "version": "0.38.2", + "tag": "@rushstack/heft_v0.38.2", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "patch": [ + { + "comment": "Fix formatting of tsBuildInfoFile tsconfig option. TypeScript uses an exact string match for change detection and normalizes slashes to '/' upon saving the file. Therefore the inputs need to be normalized as well." + } + ] + } + }, + { + "version": "0.38.1", + "tag": "@rushstack/heft_v0.38.1", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where setting the emitMjsExtensionForESModule typescript.json option in a project whose tsconfig emits CommonJS will only emit .mjs files." + } + ] + } + }, + { + "version": "0.38.0", + "tag": "@rushstack/heft_v0.38.0", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "minor": [ + { + "comment": "Temoprarily introduce a \"--storybook\" CLI parameter to support the experimental heft-storybook-plugin" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.9`" + } + ] + } + }, + { + "version": "0.37.4", + "tag": "@rushstack/heft_v0.37.4", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.8`" + } + ] + } + }, + { + "version": "0.37.3", + "tag": "@rushstack/heft_v0.37.3", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "patch": [ + { + "comment": "Support ESLint configuration in .eslintrc.cjs (instead of .eslintrc.js) to support projects with ESM modules (\"type\": \"module\" in package.json)." + } + ] + } + }, + { + "version": "0.37.2", + "tag": "@rushstack/heft_v0.37.2", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.37.1", + "tag": "@rushstack/heft_v0.37.1", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "patch": [ + { + "comment": "Fix building for Typescript 4.4 (Error: directoryExists is not a function)" + }, + { + "comment": "Ensure `process.cwd()` is set to the project root with correct file path casing." + } + ] + } + }, + { + "version": "0.37.0", + "tag": "@rushstack/heft_v0.37.0", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add commandParameters to IMetricsData for recording parameter usage" + } + ] + } + }, + { + "version": "0.36.4", + "tag": "@rushstack/heft_v0.36.4", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.7`" + } + ] + } + }, + { + "version": "0.36.3", + "tag": "@rushstack/heft_v0.36.3", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.6`" + } + ] + } + }, + { + "version": "0.36.2", + "tag": "@rushstack/heft_v0.36.2", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the TypeScript compilation when Heft is invoked in a terminal with incorrect casing in the CWD." + } + ] + } + }, + { + "version": "0.36.1", + "tag": "@rushstack/heft_v0.36.1", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "patch": [ + { + "comment": "Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior." + } + ] + } + }, + { + "version": "0.36.0", + "tag": "@rushstack/heft_v0.36.0", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "minor": [ + { + "comment": "Add support to TypeScriptPlugin for composite TypeScript projects, with behavior analogous to \"tsc --build\"." + }, + { + "comment": "Retired the use of the .heft/build-cache folder for persisting build state across the \"heft clean\" or \"--clean\" invocation. Incremental TypeScript compilation is now performed either by running \"heft build\" (without \"--clean\"), or using watch mode, and requires the tsconfig to manually opt in. The feature reduced performance of cold builds and introduced bugs due to stale caches that confused users." + } + ], + "none": [ + { + "comment": "Remove copyFromCacheMode in typescript.json" + } + ] + } + }, + { + "version": "0.35.1", + "tag": "@rushstack/heft_v0.35.1", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.5`" + } + ] + } + }, + { + "version": "0.35.0", + "tag": "@rushstack/heft_v0.35.0", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Extract default Sass plugin to separate @rushstack/heft-sass-plugin package" + } + ] + } + }, + { + "version": "0.34.8", + "tag": "@rushstack/heft_v0.34.8", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.4`" + } + ] + } + }, + { + "version": "0.34.7", + "tag": "@rushstack/heft_v0.34.7", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.3`" + } + ] + } + }, + { + "version": "0.34.6", + "tag": "@rushstack/heft_v0.34.6", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "patch": [ + { + "comment": "Disable eslint for no-unused-vars" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "0.34.5", + "tag": "@rushstack/heft_v0.34.5", + "date": "Thu, 08 Jul 2021 23:41:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.1`" + } + ] + } + }, + { + "version": "0.34.4", + "tag": "@rushstack/heft_v0.34.4", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.0`" + } + ] + } + }, + { + "version": "0.34.3", + "tag": "@rushstack/heft_v0.34.3", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.1`" + } + ] + } + }, + { + "version": "0.34.2", + "tag": "@rushstack/heft_v0.34.2", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.0`" + } + ] + } + }, + { + "version": "0.34.1", + "tag": "@rushstack/heft_v0.34.1", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.34.0", + "tag": "@rushstack/heft_v0.34.0", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "minor": [ + { + "comment": "Add RunScriptPlugin to allow for running custom scripts specified in \"heft.json\". Specified as a \"runScript\" event in the \"heftEvents\" field, paths to scripts are resolved relative to the root of the project they are specified in." + } + ] + } + }, + { + "version": "0.33.1", + "tag": "@rushstack/heft_v0.33.1", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where Heft sometimes failed with \"No tests found, exiting with code 1\"" + } + ] + } + }, + { + "version": "0.33.0", + "tag": "@rushstack/heft_v0.33.0", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Simplify the plugin event hook lifecycle by eliminating an experimental feature that enabled side-by-side compiler configurations. We decided that this scenario is better approached by splitting the files into separate projects." + }, + { + "comment": "(BREAKING CHANGE) Remove the \"afterEachIteration\" compile substage and replace its functionality with a more versatile \"afterRecompile\" compile substage hook." + } + ] + } + }, + { + "version": "0.32.0", + "tag": "@rushstack/heft_v0.32.0", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove Jest plugin from Heft. To consume the Jest plugin, add @rushstack/heft-jest-plugin as a dependency and include it in heft.json. See UPGRADING.md for more information." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.31.5", + "tag": "@rushstack/heft_v0.31.5", + "date": "Thu, 10 Jun 2021 15:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the version compatibility warning to indicate that TypeScript 4.x is supported by Heft" + } + ] + } + }, + { + "version": "0.31.4", + "tag": "@rushstack/heft_v0.31.4", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "patch": [ + { + "comment": "Add IBuildStage output property 'isTypeScriptProject' and populate in TypeScriptPlugin" + }, + { + "comment": "Fix bug in CopyFilesPlugin that caused 0-length files to be generated" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.1`" + } + ] + } + }, + { + "version": "0.31.3", + "tag": "@rushstack/heft_v0.31.3", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.0`" + } + ] + } + }, + { + "version": "0.31.2", + "tag": "@rushstack/heft_v0.31.2", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.4.1`" + } + ] + } + }, + { + "version": "0.31.1", + "tag": "@rushstack/heft_v0.31.1", + "date": "Tue, 01 Jun 2021 18:29:25 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where NodeServicePlugin launched the service when \"heft build --watch\" was invoked" + } + ] + } + }, + { + "version": "0.31.0", + "tag": "@rushstack/heft_v0.31.0", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new \"node-service\" task that enables \"heft start\" to launch a Node.js service (GitHub #2717)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.30.7", + "tag": "@rushstack/heft_v0.30.7", + "date": "Fri, 28 May 2021 06:19:57 GMT", + "comments": { + "patch": [ + { + "comment": "Prepare to split JestPlugin into a dedicated package" + } + ] + } + }, + { + "version": "0.30.6", + "tag": "@rushstack/heft_v0.30.6", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "patch": [ + { + "comment": "Report an error to prevent two different TypeScript module kinds from being emitted into nested folders" + } + ] + } + }, + { + "version": "0.30.5", + "tag": "@rushstack/heft_v0.30.5", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.2`" + } + ] + } + }, + { + "version": "0.30.4", + "tag": "@rushstack/heft_v0.30.4", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where Heft would return only the sourcemap if the compiled .js file is missing the sourceMappingURL comment." + } + ] + } + }, + { + "version": "0.30.3", + "tag": "@rushstack/heft_v0.30.3", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the \"sources\" paths in emitted sourcemap files." + } + ] + } + }, + { + "version": "0.30.2", + "tag": "@rushstack/heft_v0.30.2", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "patch": [ + { + "comment": "Move forEachLimitAsync implementation out of heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.1`" + } + ] + } + }, + { + "version": "0.30.1", + "tag": "@rushstack/heft_v0.30.1", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.0`" + } + ] + } + }, + { + "version": "0.30.0", + "tag": "@rushstack/heft_v0.30.0", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "patch": [ + { + "comment": "Implement a workaround for an intermittent Jest error \"A worker process has failed to exit gracefully and has been force exited.\" (Jest issue #11354)" + } + ], + "minor": [ + { + "comment": "Add a command-line option \"--detect-open-handles\" for troubleshooting Jest issues" + } + ] + } + }, + { + "version": "0.29.1", + "tag": "@rushstack/heft_v0.29.1", + "date": "Fri, 23 Apr 2021 22:00:06 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure TypeScript uses file paths with correct casing." + } + ] + } + }, + { + "version": "0.29.0", + "tag": "@rushstack/heft_v0.29.0", + "date": "Fri, 23 Apr 2021 15:11:20 GMT", + "comments": { + "minor": [ + { + "comment": "Add emitCjsExtensionForCommonJS and emitMjsExtensionForESModule options to config/typescript.json to support emitting commonJS and ESModule output files with the \".cjs\" and \".mjs\" respectively, alongside the normal \".js\" output files." + } + ] + } + }, + { + "version": "0.28.5", + "tag": "@rushstack/heft_v0.28.5", + "date": "Wed, 21 Apr 2021 15:12:27 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an exception is thrown when running multiple TypeScript compilations in --debug mode" + } + ] + } + }, + { + "version": "0.28.4", + "tag": "@rushstack/heft_v0.28.4", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.14.0`" + } + ] + } + }, + { + "version": "0.28.3", + "tag": "@rushstack/heft_v0.28.3", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "patch": [ + { + "comment": "Fix incremental TypeScript compilation, optimize architecture" + } + ] + } + }, + { + "version": "0.28.2", + "tag": "@rushstack/heft_v0.28.2", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "0.28.1", + "tag": "@rushstack/heft_v0.28.1", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "patch": [ + { + "comment": "Include mention of heft-webpack5-plugin in an error message." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.19`" + } + ] + } + }, + { + "version": "0.28.0", + "tag": "@rushstack/heft_v0.28.0", + "date": "Thu, 08 Apr 2021 06:05:31 GMT", + "comments": { + "minor": [ + { + "comment": "Fix parameter name typo." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.4`" + } + ] + } + }, + { + "version": "0.27.0", + "tag": "@rushstack/heft_v0.27.0", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING) Move Webpack functionality into its own package (@rushstack/heft-webpack4-plugin)." + } + ] + } + }, + { + "version": "0.26.0", + "tag": "@rushstack/heft_v0.26.0", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "minor": [ + { + "comment": "Add an \"afterCompile\" hook that runs after compilation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "0.25.5", + "tag": "@rushstack/heft_v0.25.5", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an outdated path in an error message." + } + ] + } + }, + { + "version": "0.25.4", + "tag": "@rushstack/heft_v0.25.4", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.2`" + } + ] + } + }, + { + "version": "0.25.3", + "tag": "@rushstack/heft_v0.25.3", + "date": "Fri, 19 Mar 2021 22:31:37 GMT", + "comments": { + "patch": [ + { + "comment": "Improve README.md" + } + ] + } + }, + { + "version": "0.25.2", + "tag": "@rushstack/heft_v0.25.2", + "date": "Wed, 17 Mar 2021 05:04:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where heft would crash when copying static assets in --watch mode." + } + ] + } + }, + { + "version": "0.25.1", + "tag": "@rushstack/heft_v0.25.1", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "patch": [ + { + "comment": "Update node-sass to support Node 15." + } + ] + } + }, + { + "version": "0.25.0", + "tag": "@rushstack/heft_v0.25.0", + "date": "Wed, 10 Mar 2021 05:10:05 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Change the logic that resolves typescript, eslint, tslint, and api-extractor to look for a devDependency in the current project, and then for a dependency in the rig project, and then as any kind of dependency in the current project." + } + ] + } + }, + { + "version": "0.24.4", + "tag": "@rushstack/heft_v0.24.4", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.2`" + } + ] + } + }, + { + "version": "0.24.3", + "tag": "@rushstack/heft_v0.24.3", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where build would continue even if TS reported errors." + }, + { + "comment": "Determine the default static assets destination folder from the TSConfig's \"outDir\" property, instead of hardcoding \"lib.\"" + } + ] + } + }, + { + "version": "0.24.2", + "tag": "@rushstack/heft_v0.24.2", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.1`" + } + ] + } + }, + { + "version": "0.24.1", + "tag": "@rushstack/heft_v0.24.1", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with webpack in \"heft start\" mode where \"bundle\" would continue too quickly." + } + ] + } + }, + { + "version": "0.24.0", + "tag": "@rushstack/heft_v0.24.0", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "minor": [ + { + "comment": "Update jest-shared.config.json to specify a default \"collectCoverageFrom\" that includes all \"src\" files excluding test files" + }, + { + "comment": "Update jest-shared.config.json to configure \"coverageDirectory\" to use \"./temp/coverage\" (instead of \"./coverage\")" + } + ] + } + }, + { + "version": "0.23.2", + "tag": "@rushstack/heft_v0.23.2", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.0`" + } + ] + } + }, + { + "version": "0.23.1", + "tag": "@rushstack/heft_v0.23.1", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.23.0", + "tag": "@rushstack/heft_v0.23.0", + "date": "Mon, 14 Dec 2020 16:12:20 GMT", + "comments": { + "minor": [ + { + "comment": "Delay build stages in --watch mode until the previous stage reports an initial completion." + } + ] + } + }, + { + "version": "0.22.7", + "tag": "@rushstack/heft_v0.22.7", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where using CTRL+C to terminate \"--watch\" mode would sometimes leave a background process running (GitHub #2387)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "0.22.6", + "tag": "@rushstack/heft_v0.22.6", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.31`" + } + ] + } + }, + { + "version": "0.22.5", + "tag": "@rushstack/heft_v0.22.5", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a typo in a logging message." + } + ] + } + }, + { + "version": "0.22.4", + "tag": "@rushstack/heft_v0.22.4", + "date": "Mon, 30 Nov 2020 16:11:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.30`" + } + ] + } + }, + { + "version": "0.22.3", + "tag": "@rushstack/heft_v0.22.3", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.0`" + } + ] + } + }, + { + "version": "0.22.2", + "tag": "@rushstack/heft_v0.22.2", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.5`" + } + ] + } + }, + { + "version": "0.22.1", + "tag": "@rushstack/heft_v0.22.1", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where .map files were not being published" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.14`" + } + ] + } + }, + { + "version": "0.22.0", + "tag": "@rushstack/heft_v0.22.0", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where API Extractor errors/warnings did not show the message ID" + } + ], + "minor": [ + { + "comment": "Add \"webpack-dev-server\" as a dependency since its types are part of Heft's API contract" + } + ] + } + }, + { + "version": "0.21.3", + "tag": "@rushstack/heft_v0.21.3", + "date": "Fri, 13 Nov 2020 01:11:00 GMT", + "comments": { + "patch": [ + { + "comment": "Update Sass typings generation to update in watch mode when a dependency changes." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.27`" + } + ] + } + }, + { + "version": "0.21.2", + "tag": "@rushstack/heft_v0.21.2", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a minor issue with heft.schema.json" + } + ] + } + }, + { + "version": "0.21.1", + "tag": "@rushstack/heft_v0.21.1", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "0.21.0", + "tag": "@rushstack/heft_v0.21.0", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add new built-in Heft action \"copyFiles\" to copy or hardlink files during specified Heft events" + } + ], + "patch": [ + { + "comment": "Fix an incorrectly formatted error message" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.3`" + } + ] + } + }, + { + "version": "0.20.1", + "tag": "@rushstack/heft_v0.20.1", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "patch": [ + { + "comment": "Improve error handling and make --debug print stacks of errors that occur in heft's internal initialization." + } + ] + } + }, + { + "version": "0.20.0", + "tag": "@rushstack/heft_v0.20.0", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "minor": [ + { + "comment": "Update jest-shared.config.json with more file extension mappings for \"jest-string-mock-transform\"" + } + ] + } + }, + { + "version": "0.19.5", + "tag": "@rushstack/heft_v0.19.5", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an extended \"typescript.json\" config file with omitted optional staticAssetsToCopy fields would cause schema validation to fail." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.11`" + } + ] + } + }, + { + "version": "0.19.4", + "tag": "@rushstack/heft_v0.19.4", + "date": "Tue, 03 Nov 2020 01:11:18 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ] + } + }, + { + "version": "0.19.3", + "tag": "@rushstack/heft_v0.19.3", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "patch": [ + { + "comment": "Honor jest reporters specified in config/jest.config.json" + } + ] + } + }, + { + "version": "0.19.2", + "tag": "@rushstack/heft_v0.19.2", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "0.19.1", + "tag": "@rushstack/heft_v0.19.1", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.19.0", + "tag": "@rushstack/heft_v0.19.0", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @types/tapable and @types/webpack" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.0`" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/heft_v0.18.0", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to ~4.44.2" + } + ] + } + }, + { + "version": "0.17.4", + "tag": "@rushstack/heft_v0.17.4", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.17.3", + "tag": "@rushstack/heft_v0.17.3", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.5`" + } + ] + } + }, + { + "version": "0.17.2", + "tag": "@rushstack/heft_v0.17.2", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "patch": [ + { + "comment": "Add fileExtensions config to SassTypingsGenerator. " + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.19`" + } + ] + } + }, + { + "version": "0.17.1", + "tag": "@rushstack/heft_v0.17.1", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "patch": [ + { + "comment": "Bump downstream dependencies." + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/heft_v0.17.0", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "minor": [ + { + "comment": "Allow the Webpack dev server configuration to be customized." + } + ] + } + }, + { + "version": "0.16.1", + "tag": "@rushstack/heft_v0.16.1", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/heft_v0.16.0", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Rename \"includePaths\" to \"importIncludePaths\" in sass.json." + } + ], + "patch": [ + { + "comment": "Add an \"exclude\" option to sass.json." + } + ] + } + }, + { + "version": "0.15.8", + "tag": "@rushstack/heft_v0.15.8", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where heftSession.debugMode isn't set properly." + } + ] + } + }, + { + "version": "0.15.7", + "tag": "@rushstack/heft_v0.15.7", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "patch": [ + { + "comment": "Include additionalModuleKindsToEmit in the copy-static-assets plugin destination folders." + }, + { + "comment": "Throw if jest config file doesn't exist" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/heft_v0.15.6", + "date": "Fri, 09 Oct 2020 15:11:08 GMT", + "comments": { + "patch": [ + { + "comment": "Support relative imports in the Sass typings generator." + } + ] + } + }, + { + "version": "0.15.5", + "tag": "@rushstack/heft_v0.15.5", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/heft_v0.15.4", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/heft_v0.15.3", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/heft_v0.15.2", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "patch": [ + { + "comment": "Include UPGRADING.md in npm package publish." + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/heft_v0.15.1", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/heft_v0.15.0", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "minor": [ + { + "comment": "Add functionality to automatically generate typings for *.scss, *.sass, and *.css files." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.13`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/heft_v0.14.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + }, + { + "comment": "Reclassify compiler messages TS2564 and TS7053 as warnings instead of errors" + }, + { + "comment": "Print a warning if the API Extractor version is too old" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/heft_v0.14.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Collapse copy-static-assets.json into typescript.json." + }, + { + "comment": "(BREAKING CHANGE) Move the config files from the \".heft\" folder to the \"config\" folder and print a warning if an unexpected file is found in the \".heft\" folder." + }, + { + "comment": "(BREAKING CHANGE) Consolidate the clean.json and plugins.json files into a new heft.json file." + }, + { + "comment": "(BREAKING CHANGE) Rename \"emitFolderNameForJest\" to \"emitFolderNameForTests\" in typescript.json" + }, + { + "comment": "Heft now supports the config/rig.json system as defined by @rushstack/rig-package" + }, + { + "comment": "Enable api-extractor.json to be provided by a rig package" + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "patch": [ + { + "comment": "Update README.md" + }, + { + "comment": "Fix an issue where \"heft build --help\" printed incorrect help" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/heft_v0.13.9", + "date": "Tue, 22 Sep 2020 05:45:56 GMT", + "comments": { + "patch": [ + { + "comment": "Make the \"plugins\" field of \"plugins.json\" optional." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/heft_v0.13.8", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/heft_v0.13.7", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/heft_v0.13.6", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "0.13.5", + "tag": "@rushstack/heft_v0.13.5", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/heft_v0.13.4", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where folders listed in pathsToDelete in clean.json weren't deleted on Windows." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/heft_v0.13.3", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "patch": [ + { + "comment": "Add a missing field to the template config files." + }, + { + "comment": "Fix an issue where, if an \"extends\" field pointed to a module that didn't exist, the error was silently ignored." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.15`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/heft_v0.13.2", + "date": "Wed, 16 Sep 2020 05:30:25 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing \"extends\" properties to schemas." + }, + { + "comment": "Fix an issue where console.log() did not get formatted by HeftJestReporter" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/heft_v0.13.1", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "patch": [ + { + "comment": "Improve reliability of jest-build-transform.js by only comparing timestamps when in \"--watch\" mode" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/heft_v0.13.0", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "minor": [ + { + "comment": "Enable support for Jest inline snapshots" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/heft_v0.12.0", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "minor": [ + { + "comment": "Update plugins to load configuration via heft-configuration-loader instead of in central plugins." + }, + { + "comment": "Remove the loading of common/config/heft/* config files." + }, + { + "comment": "(BREAKING CHANGE) Rename the \"outFolderPath\" and \"emitFolderPathForJest\" properties in typescript.json to \"outFolderName\" and \"emitFolderNameForJest\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.14`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft_v0.11.1", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.13`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft_v0.11.0", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "minor": [ + { + "comment": "Add --max-workers option to the \"test\" action to control the maximum number of worker processes the test process can use." + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/heft_v0.10.5", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a typo in an error message to read that plugins must define a \"pluginName\" property, rather than the former \"displayName\" property" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/heft_v0.10.4", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with WebpackPlugin loading webpack-dev-server in non-serve mode and setting the \"WEBPACK_DEV_SERVER\" environment variable." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.12`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/heft_v0.10.3", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix parsing of the --max-old-space-size build parameter." + }, + { + "comment": "Fix parsing of the --plugin heft parameter." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.11`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/heft_v0.10.2", + "date": "Fri, 04 Sep 2020 15:06:27 GMT", + "comments": { + "patch": [ + { + "comment": "Fix issues with parsing of tslint.json config files, including adding support for an array provided to \"extends\" and proper Node module resolution to extended config files." + }, + { + "comment": "Fix a sourcemap issue that caused the debugger to show Jest files in a duplicate editor window (with the same path as the real file)" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/heft_v0.10.1", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with Heft not printing an error message." + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft_v0.10.0", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "minor": [ + { + "comment": "Add a simple way to specify a custom action." + }, + { + "comment": "Remove the dev-deploy action from Heft" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft_v0.9.0", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "minor": [ + { + "comment": "Add a method for plugins to hook into other plugins." + }, + { + "comment": "BREAKING CHANGE: Rename the \"displayName\" plugin property to \"pluginName\"" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft_v0.8.0", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "minor": [ + { + "comment": "Formalize the way extendable configuration files are loaded." + }, + { + "comment": "Add a \"setupFiles\" setting to jest-shared.config.json, which implements the helper APIs from the @types/heft-jest package" + }, + { + "comment": "Add a \"roots\" setting to jest-shared.config.json, which enables \"src/__mocks__\" to be used for manually mocking Node.js system modules" + } + ], + "patch": [ + { + "comment": "Add a \"modulePathIgnorePatterns\" setting to jest-shared.config.json, which fixes a warning that was sometimes shown due to Jest loading extraneous files" + }, + { + "comment": "Add a \"resolver\" setting to jest-shared-config.json, which fixes an issue with importing manual mocks from a \"__mocks__\" subfolder. (See jest-improved-resolver.js for details.)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft_v0.7.0", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "minor": [ + { + "comment": "Adds a \"--update-snapshots\" command line flag which, when included, causes the test action to update the Jest snapshots. If this flag is omitted, tests with conditions that do not match the snapshots will fail. This replaces the older logic of using --production to prevent updating snapshots, which were otherwise updated." + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/heft_v0.6.6", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/heft_v0.6.5", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft_v0.6.4", + "date": "Fri, 21 Aug 2020 01:21:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with Heft exiting with exit code 0 after a CLI error." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.7`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft_v0.6.3", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where failed test suites aren't listed as failures." + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft_v0.6.2", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "patch": [ + { + "comment": "Add the --notest parameter back to \"heft test\" temporarily." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.6`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft_v0.6.1", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft_v0.6.0", + "date": "Tue, 18 Aug 2020 03:03:23 GMT", + "comments": { + "minor": [ + { + "comment": "Add a \"version selector\" feature so that if a globally installed Heft binary is invoked, it will try to load the project's locally installed version of Heft" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft_v0.5.1", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a broken dependency" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft_v0.5.0", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "patch": [ + { + "comment": "Normalize the way file paths are printed in errors and warnings." + }, + { + "comment": "Ensure build steps that depend on emitted TS output aren't triggered until TS has written output to disk." + }, + { + "comment": "Fix an issue where Heft could complete with errors but not return a nonzero process exit code" + }, + { + "comment": "Reclassify TypeScript messages such as \"X is declared but never used\" to be reported as warnings instead of errors" + } + ], + "minor": [ + { + "comment": "Formalize the way errors and warnings are emitted." + }, + { + "comment": "Expose some useful Jest CLI parameters as \"heft test\" parameters" + }, + { + "comment": "Rename \"--notest\" to \"--no--test\"" + }, + { + "comment": "Improve \"heft test\" to show console output from tests" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft_v0.4.7", + "date": "Thu, 13 Aug 2020 09:26:39 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a race condition where .js files were sometimes read by Jest before they were written by TypeScript" + }, + { + "comment": "Fix an issue where the TypeScript incremental build cache sometimes did not work correctly in \"--watch\" mode" + }, + { + "comment": "Add support for \"additionalModuleKindsToEmit\" in watch mode" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft_v0.4.6", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with incorrect source maps for the Jest transform" + }, + { + "comment": "Fix a watch mode race condition where \"--clean\" ran in parallel with \"heft test\" (GitHub #2078)" + }, + { + "comment": "Fix an issue where \"The transpiler output folder does not exist\" was sometimes printed erroneously" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft_v0.4.5", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft_v0.4.4", + "date": "Tue, 11 Aug 2020 00:36:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where emitted .js.map sourcemaps had an incorrect relative path (GitHub #2086)" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft_v0.4.3", + "date": "Wed, 05 Aug 2020 18:27:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft_v0.4.2", + "date": "Tue, 04 Aug 2020 07:27:25 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md logo" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft_v0.4.1", + "date": "Mon, 03 Aug 2020 15:09:51 GMT", + "comments": { + "patch": [ + { + "comment": "Add specific support for handling binary assets in Jest tests." + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft_v0.4.0", + "date": "Mon, 03 Aug 2020 06:55:14 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where jest-shared.config.json did not match .tsx file extensions" + }, + { + "comment": "Standardize how jest-shared.config.json references path-based imports" + }, + { + "comment": "Enable Jest \"runInBand\" when invoking Heft with \"--debug\"" + }, + { + "comment": "Fix an issue where \"heft clean\" did not clean Jest's unreliable cache" + } + ], + "minor": [ + { + "comment": "Add jest-identity-mock-transform for mocking .css imports in Webpack projects" + }, + { + "comment": "Add new \"emitFolderPathForJest\" setting in typescript.json, which simplifies how Webpack projects emit CommonJS for Jest" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft_v0.3.1", + "date": "Thu, 30 Jul 2020 15:09:35 GMT", + "comments": { + "patch": [ + { + "comment": "Emit errors and warnings from webpack." + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft_v0.3.0", + "date": "Fri, 24 Jul 2020 20:40:38 GMT", + "comments": { + "minor": [ + { + "comment": "Enable Heft to be used without the \"@microsoft/rush-stack-compiler-n.n\" system" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft_v0.2.2", + "date": "Tue, 21 Jul 2020 00:54:55 GMT", + "comments": { + "patch": [ + { + "comment": "Rename .heft/api-extractor.json to .heft/api-extractor-task.json to avoid confusion with API Extractor's config file" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft_v0.2.1", + "date": "Tue, 21 Jul 2020 00:10:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft_v0.2.0", + "date": "Mon, 20 Jul 2020 06:52:33 GMT", + "comments": { + "minor": [ + { + "comment": "Make API Extractor's typescriptCompilerFolder option configurable." + }, + { + "comment": "Include basic support for webpack-dev-server." + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft_v0.1.2", + "date": "Thu, 16 Jul 2020 18:34:08 GMT", + "comments": { + "patch": [ + { + "comment": "Republish to fix incorrect dependency specifier" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft_v0.1.1", + "date": "Thu, 16 Jul 2020 17:53:35 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for TypeScript compilers older than version 3.6 (which do not support incremental compilation)" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft_v0.1.0", + "date": "Wed, 15 Jul 2020 18:29:28 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/apps/heft/CHANGELOG.md b/apps/heft/CHANGELOG.md new file mode 100644 index 00000000000..81fd7c712f6 --- /dev/null +++ b/apps/heft/CHANGELOG.md @@ -0,0 +1,2386 @@ +# Change Log - @rushstack/heft + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.68.10 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.68.9 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.68.8 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.68.7 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.68.6 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 0.68.5 +Mon, 21 Oct 2024 18:50:09 GMT + +### Patches + +- Remove usage of true-case-path in favor of manually adjusting the drive letter casing to avoid confusing file system tracing tools with unnecessary directory enumerations. + +## 0.68.4 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.68.3 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.68.2 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure `configHash` for file copy incremental cache file is portable. + +## 0.68.1 +Tue, 01 Oct 2024 00:11:28 GMT + +### Patches + +- Include all previous `inputFileVersions` in incremental copy files cache file during watch mode. Fix incorrect serialization of cache file for file copy. + +## 0.68.0 +Mon, 30 Sep 2024 15:12:19 GMT + +### Minor changes + +- Update file copy logic to use an incremental cache file in the temp directory for the current task to avoid unnecessary file writes. + +## 0.67.2 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 0.67.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.67.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Add a `slashNormalizedBuildFolderPath` property to `HeftConfiguration`. + +## 0.66.26 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.66.25 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.66.24 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.66.23 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.66.22 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.66.21 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.66.20 +Tue, 16 Jul 2024 00:36:21 GMT + +### Patches + +- Update schemas/templates/heft.json to reflect new settings + +## 0.66.19 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.66.18 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.66.17 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.66.16 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.66.15 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.66.14 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.66.13 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.66.12 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.66.11 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.66.10 +Thu, 23 May 2024 02:26:56 GMT + +### Patches + +- Update schema definitions to conform to strict schema-type validation. + +## 0.66.9 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.66.8 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.66.7 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.66.6 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 0.66.5 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.66.4 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.66.3 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.66.2 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.66.1 +Fri, 15 Mar 2024 00:12:40 GMT + +### Patches + +- Fix internal error when run 'heft clean' + +## 0.66.0 +Tue, 05 Mar 2024 01:19:24 GMT + +### Minor changes + +- Add new metrics value `bootDurationMs` to track the boot overhead of Heft before the action starts executing the subtasks. Update the start time used to compute `taskTotalExecutionMs` to be the beginning of operation graph execution. Fix the value of `taskTotalExecutionMs` field to be in milliseconds instead of seconds. Add new metrics value `totalUptimeMs` to track how long watch mode sessions are kept alive. + +## 0.65.10 +Sun, 03 Mar 2024 20:58:12 GMT + +_Version update only_ + +## 0.65.9 +Sat, 02 Mar 2024 02:22:23 GMT + +_Version update only_ + +## 0.65.8 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.65.7 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.65.6 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.65.5 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.65.4 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.65.3 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.65.2 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.65.1 +Tue, 20 Feb 2024 21:45:10 GMT + +### Patches + +- Fix a recent regression causing `Error: Cannot find module 'colors/safe'` (GitHub #4525) +- Remove a no longer needed dependency on the `chokidar` package + +## 0.65.0 +Tue, 20 Feb 2024 16:10:52 GMT + +### Minor changes + +- Add a built-in `set-environment-variables-plugin` task plugin to set environment variables. + +## 0.64.8 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.64.7 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.64.6 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.64.5 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.64.4 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.64.3 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.64.2 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.64.1 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.64.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 + +## 0.63.6 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.63.5 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.63.4 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.63.3 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.63.2 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.63.1 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.63.0 +Mon, 30 Oct 2023 23:36:37 GMT + +### Minor changes + +- [BREAKING CHANGE] Remove "heft run" short-parameters for "--to" ("-t"), "--to-except" ("-T"), and "--only" ("-o"). + +### Patches + +- Fix an issue with parsing of the "--debug" and "--unmanaged" flags for Heft + +## 0.62.3 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 0.62.2 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.62.1 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.62.0 +Wed, 27 Sep 2023 00:21:38 GMT + +### Minor changes + +- (BREAKING API CHANGE) Remove the deprecated `cancellationToken` property of `IHeftTaskRunHookOptions`. Use `abortSignal` on that object instead. + +## 0.61.3 +Tue, 26 Sep 2023 21:02:30 GMT + +### Patches + +- Fix an issue where `heft clean` would crash with `ERR_ILLEGAL_CONSTRUCTOR`. + +## 0.61.2 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.61.1 +Mon, 25 Sep 2023 23:38:27 GMT + +_Version update only_ + +## 0.61.0 +Fri, 22 Sep 2023 00:05:50 GMT + +### Minor changes + +- (BREAKING CHANGE): Rename task temp folder from "." to "/" to simplify caching phase outputs. + +## 0.60.0 +Tue, 19 Sep 2023 15:21:51 GMT + +### Minor changes + +- Allow Heft to communicate via IPC with a host process when running in watch mode. The host controls scheduling of incremental re-runs. + +## 0.59.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +### Patches + +- Migrate plugin name collision detection to the InternalHeftSession instance to allow multiple Heft sessions in the same process. + +## 0.58.2 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 0.58.1 +Sat, 29 Jul 2023 00:22:50 GMT + +### Patches + +- Fix the `toolFinish` lifecycle hook so that it is invoked after the `recordMetrics` hook, rather than before. Ensure that the `toolFinish` lifecycle hook is invoked if the user performs a graceful shutdown of Heft (e.g. via Ctrl+C). + +## 0.58.0 +Thu, 20 Jul 2023 20:47:28 GMT + +### Minor changes + +- BREAKING CHANGE: Update the heft.json "cleanFiles" property and the delete-files-plugin to delete the contents of folders specified by "sourcePath" instead of deleting the folders themselves. To delete the folders, use the "includeGlobs" property to specify the folder to delete. + +## 0.57.1 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.57.0 +Thu, 13 Jul 2023 00:22:37 GMT + +### Minor changes + +- Support `--clean` in watch mode. Cleaning in watch mode is now performed only during the first-pass of lifecycle or phase operations. Once the clean has been completed, `--clean` will be ignored until the command is restarted + +## 0.56.3 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.56.2 +Fri, 07 Jul 2023 00:19:32 GMT + +### Patches + +- Revise README.md and UPGRADING.md documentation + +## 0.56.1 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.56.0 +Mon, 19 Jun 2023 22:40:21 GMT + +### Minor changes + +- Use the `IRigConfig` interface in the `HeftConfiguration` object insteacd of the `RigConfig` class. + +## 0.55.2 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 0.55.1 +Wed, 14 Jun 2023 00:19:41 GMT + +### Patches + +- Add MockScopedLogger to help plugin authors with unit testing. + +## 0.55.0 +Tue, 13 Jun 2023 15:17:20 GMT + +### Minor changes + +- Remove the deprecated `cacheFolderPath` property from the session object. + +## 0.54.0 +Tue, 13 Jun 2023 01:49:01 GMT + +### Minor changes + +- Add plugin support for parameter short-names. + +## 0.53.1 +Fri, 09 Jun 2023 18:05:34 GMT + +### Patches + +- Revise CHANGELOG.md to more clearly identify the breaking changes + +## 0.53.0 +Fri, 09 Jun 2023 00:19:49 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove "taskEvents" heft.json configuration option, and replace it with directly referencing the included plugins. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md + +### Patches + +- Update UPGRADING.md with new JSON schema URLs + +## 0.52.2 +Thu, 08 Jun 2023 15:21:17 GMT + +### Patches + +- Provide a useful error message when encountering legacy Heft configurations + +## 0.52.1 +Thu, 08 Jun 2023 00:20:02 GMT + +### Patches + +- Remove the concept of the cache folder, since it mostly just causes bugs. + +## 0.52.0 +Wed, 07 Jun 2023 22:45:16 GMT + +### Minor changes + +- Add a new API IHeftTaskSession.parsedCommandLine for accessing the invoked command name +- (BREAKING CHANGE) The built-in task NodeServicePlugin now supports the "--serve" mode with semantics similar to heft-webpack5-plugin. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md + +### Patches + +- Add action aliases support. Action aliases can be used to create custom "heft " commands which call existing Heft commands with optional default arguments. + +## 0.51.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- (BREAKING CHANGE) Overhaul to support splitting single-project builds into more phases than "build" and "test", to align with Rush phased commands. Please read https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md + +## 0.50.7 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.50.6 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.50.5 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.50.4 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.50.3 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.50.2 +Sat, 29 Apr 2023 00:23:02 GMT + +### Patches + +- Fix issues where a terminal logging prefix may be added multiple times to the same line, or only to the first line + +## 0.50.1 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.50.0 +Sat, 18 Mar 2023 00:20:56 GMT + +### Minor changes + +- Remove monkey-patching of TypeScript for compatibility with 5.0. Refactors how the multi-emit logic works. + +## 0.49.7 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.49.6 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.49.5 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.49.4 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 0.49.3 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.49.2 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.49.1 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.49.0 +Tue, 20 Dec 2022 01:18:22 GMT + +### Minor changes + +- Replace Terminal with ITerminal in the API. + +## 0.48.9 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.48.8 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 0.48.7 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.48.6 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.48.5 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.48.4 +Fri, 14 Oct 2022 15:26:31 GMT + +_Version update only_ + +## 0.48.3 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.48.2 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.48.1 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.48.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.8. + +## 0.47.11 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.47.10 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.47.9 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.47.8 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.47.7 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.47.6 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.47.5 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.47.4 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.47.3 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.47.2 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.47.1 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.47.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Update the highest supported version of TypeScript to 4.7 + +## 0.46.7 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.46.6 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.46.5 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.46.4 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.46.3 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 0.46.2 +Mon, 04 Jul 2022 15:15:13 GMT + +### Patches + +- Fix an issue with the `locales` build property. The property is now undefined if no `--locale` parameters are specified. + +## 0.46.1 +Thu, 30 Jun 2022 04:48:53 GMT + +_Version update only_ + +## 0.46.0 +Tue, 28 Jun 2022 22:47:13 GMT + +### Minor changes + +- (BREAKING CHANGE) Update the --locale build parameter to support multiple values and replace the `locale?: string` parameter in `IBuildStageProperties` with a `locales?: readonly string[]` parameter. + +## 0.45.14 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.45.13 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.45.12 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.45.11 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.45.10 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.45.9 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.45.8 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.45.7 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.45.6 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 0.45.5 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.45.4 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.45.3 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.45.2 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.45.1 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.45.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.6 + +## 0.44.13 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.44.12 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 0.44.11 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.44.10 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.44.9 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.44.8 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.44.7 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.44.6 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.44.5 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.44.4 +Sat, 19 Mar 2022 08:05:37 GMT + +_Version update only_ + +## 0.44.3 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.44.2 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.44.1 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.44.0 +Tue, 14 Dec 2021 19:27:51 GMT + +### Minor changes + +- Remove Jest-specific CLI arguments from Heft. These parameters have been moved to @rushstack/heft-jest-plugin. + +## 0.43.2 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.43.1 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.43.0 +Wed, 08 Dec 2021 19:05:08 GMT + +### Minor changes + +- Add support for TypeScript 4.5 + +## 0.42.6 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.42.5 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 0.42.4 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.42.3 +Mon, 29 Nov 2021 07:26:16 GMT + +### Patches + +- Remove an unused dependency. + +## 0.42.2 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.42.1 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.42.0 +Thu, 28 Oct 2021 00:08:22 GMT + +### Minor changes + +- Add environment variables for common heft test parameters + +## 0.41.8 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.41.7 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.41.6 +Fri, 08 Oct 2021 09:35:07 GMT + +### Patches + +- Fix reuse of TypeScript program to avoid breaking on older versions of @typescript-eslint/typescript-estree + +## 0.41.5 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.41.4 +Thu, 07 Oct 2021 23:43:12 GMT + +### Patches + +- Re-use the compiler TypeScript program when running ESLint to reduce overhead + +## 0.41.3 +Thu, 07 Oct 2021 07:13:35 GMT + +### Patches + +- Fix support for TypeScript 4.4 in --watch mode. + +## 0.41.2 +Wed, 06 Oct 2021 15:08:25 GMT + +### Patches + +- Improve the HeftSession.commandLine.registerParameter interface and add support for choice and choice list parameters. + +## 0.41.1 +Wed, 06 Oct 2021 02:41:48 GMT + +### Patches + +- Replace ITerminal with Terminal in data structure values to preserve compatability with plugins written before ITerminal. + +## 0.41.0 +Tue, 05 Oct 2021 15:08:37 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 0.40.0 +Mon, 04 Oct 2021 15:10:18 GMT + +### Minor changes + +- Add register custom parameters feature to Heft. + +## 0.39.2 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.39.1 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.39.0 +Wed, 22 Sep 2021 03:27:12 GMT + +### Minor changes + +- Add "encounteredErrors" boolean to IMetricsData. + +### Patches + +- Fix typo in temp folder path. + +## 0.38.2 +Wed, 22 Sep 2021 00:09:32 GMT + +### Patches + +- Fix formatting of tsBuildInfoFile tsconfig option. TypeScript uses an exact string match for change detection and normalizes slashes to '/' upon saving the file. Therefore the inputs need to be normalized as well. + +## 0.38.1 +Sat, 18 Sep 2021 03:05:57 GMT + +### Patches + +- Fix an issue where setting the emitMjsExtensionForESModule typescript.json option in a project whose tsconfig emits CommonJS will only emit .mjs files. + +## 0.38.0 +Tue, 14 Sep 2021 01:17:04 GMT + +### Minor changes + +- Temoprarily introduce a "--storybook" CLI parameter to support the experimental heft-storybook-plugin + +## 0.37.4 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.37.3 +Fri, 10 Sep 2021 15:08:28 GMT + +### Patches + +- Support ESLint configuration in .eslintrc.cjs (instead of .eslintrc.js) to support projects with ESM modules ("type": "module" in package.json). + +## 0.37.2 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.37.1 +Wed, 08 Sep 2021 00:08:03 GMT + +### Patches + +- Fix building for Typescript 4.4 (Error: directoryExists is not a function) +- Ensure `process.cwd()` is set to the project root with correct file path casing. + +## 0.37.0 +Tue, 31 Aug 2021 00:07:11 GMT + +### Minor changes + +- Add commandParameters to IMetricsData for recording parameter usage + +## 0.36.4 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.36.3 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.36.2 +Thu, 12 Aug 2021 18:11:18 GMT + +### Patches + +- Fix an issue with the TypeScript compilation when Heft is invoked in a terminal with incorrect casing in the CWD. + +## 0.36.1 +Thu, 12 Aug 2021 01:28:38 GMT + +### Patches + +- Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior. + +## 0.36.0 +Wed, 11 Aug 2021 23:14:17 GMT + +### Minor changes + +- Add support to TypeScriptPlugin for composite TypeScript projects, with behavior analogous to "tsc --build". +- Retired the use of the .heft/build-cache folder for persisting build state across the "heft clean" or "--clean" invocation. Incremental TypeScript compilation is now performed either by running "heft build" (without "--clean"), or using watch mode, and requires the tsconfig to manually opt in. The feature reduced performance of cold builds and introduced bugs due to stale caches that confused users. + +## 0.35.1 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.35.0 +Sat, 31 Jul 2021 00:52:11 GMT + +### Minor changes + +- (BREAKING CHANGE) Extract default Sass plugin to separate @rushstack/heft-sass-plugin package + +## 0.34.8 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.34.7 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.34.6 +Mon, 12 Jul 2021 23:08:26 GMT + +### Patches + +- Disable eslint for no-unused-vars + +## 0.34.5 +Thu, 08 Jul 2021 23:41:16 GMT + +_Version update only_ + +## 0.34.4 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.34.3 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.34.2 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.34.1 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.34.0 +Fri, 25 Jun 2021 00:08:28 GMT + +### Minor changes + +- Add RunScriptPlugin to allow for running custom scripts specified in "heft.json". Specified as a "runScript" event in the "heftEvents" field, paths to scripts are resolved relative to the root of the project they are specified in. + +## 0.33.1 +Fri, 18 Jun 2021 06:23:05 GMT + +### Patches + +- Fix a regression where Heft sometimes failed with "No tests found, exiting with code 1" + +## 0.33.0 +Wed, 16 Jun 2021 15:07:24 GMT + +### Minor changes + +- (BREAKING CHANGE) Simplify the plugin event hook lifecycle by eliminating an experimental feature that enabled side-by-side compiler configurations. We decided that this scenario is better approached by splitting the files into separate projects. +- (BREAKING CHANGE) Remove the "afterEachIteration" compile substage and replace its functionality with a more versatile "afterRecompile" compile substage hook. + +## 0.32.0 +Fri, 11 Jun 2021 00:34:02 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove Jest plugin from Heft. To consume the Jest plugin, add @rushstack/heft-jest-plugin as a dependency and include it in heft.json. See UPGRADING.md for more information. + +## 0.31.5 +Thu, 10 Jun 2021 15:08:15 GMT + +### Patches + +- Update the version compatibility warning to indicate that TypeScript 4.x is supported by Heft + +## 0.31.4 +Fri, 04 Jun 2021 19:59:53 GMT + +### Patches + +- Add IBuildStage output property 'isTypeScriptProject' and populate in TypeScriptPlugin +- Fix bug in CopyFilesPlugin that caused 0-length files to be generated + +## 0.31.3 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 0.31.2 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.31.1 +Tue, 01 Jun 2021 18:29:25 GMT + +### Patches + +- Fix an issue where NodeServicePlugin launched the service when "heft build --watch" was invoked + +## 0.31.0 +Sat, 29 May 2021 01:05:06 GMT + +### Minor changes + +- Add a new "node-service" task that enables "heft start" to launch a Node.js service (GitHub #2717) + +## 0.30.7 +Fri, 28 May 2021 06:19:57 GMT + +### Patches + +- Prepare to split JestPlugin into a dedicated package + +## 0.30.6 +Tue, 25 May 2021 00:12:21 GMT + +### Patches + +- Report an error to prevent two different TypeScript module kinds from being emitted into nested folders + +## 0.30.5 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.30.4 +Thu, 13 May 2021 01:52:46 GMT + +### Patches + +- Fix an issue where Heft would return only the sourcemap if the compiled .js file is missing the sourceMappingURL comment. + +## 0.30.3 +Tue, 11 May 2021 22:19:17 GMT + +### Patches + +- Fix the "sources" paths in emitted sourcemap files. + +## 0.30.2 +Mon, 03 May 2021 15:10:28 GMT + +### Patches + +- Move forEachLimitAsync implementation out of heft + +## 0.30.1 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.30.0 +Thu, 29 Apr 2021 01:07:29 GMT + +### Minor changes + +- Add a command-line option "--detect-open-handles" for troubleshooting Jest issues + +### Patches + +- Implement a workaround for an intermittent Jest error "A worker process has failed to exit gracefully and has been force exited." (Jest issue #11354) + +## 0.29.1 +Fri, 23 Apr 2021 22:00:06 GMT + +### Patches + +- Ensure TypeScript uses file paths with correct casing. + +## 0.29.0 +Fri, 23 Apr 2021 15:11:20 GMT + +### Minor changes + +- Add emitCjsExtensionForCommonJS and emitMjsExtensionForESModule options to config/typescript.json to support emitting commonJS and ESModule output files with the ".cjs" and ".mjs" respectively, alongside the normal ".js" output files. + +## 0.28.5 +Wed, 21 Apr 2021 15:12:27 GMT + +### Patches + +- Fix an issue where an exception is thrown when running multiple TypeScript compilations in --debug mode + +## 0.28.4 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.28.3 +Thu, 15 Apr 2021 02:59:25 GMT + +### Patches + +- Fix incremental TypeScript compilation, optimize architecture + +## 0.28.2 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.28.1 +Thu, 08 Apr 2021 20:41:54 GMT + +### Patches + +- Include mention of heft-webpack5-plugin in an error message. + +## 0.28.0 +Thu, 08 Apr 2021 06:05:31 GMT + +### Minor changes + +- Fix parameter name typo. + +## 0.27.0 +Thu, 08 Apr 2021 00:10:18 GMT + +### Minor changes + +- (BREAKING) Move Webpack functionality into its own package (@rushstack/heft-webpack4-plugin). + +## 0.26.0 +Tue, 06 Apr 2021 15:14:22 GMT + +### Minor changes + +- Add an "afterCompile" hook that runs after compilation. + +## 0.25.5 +Wed, 31 Mar 2021 15:10:36 GMT + +### Patches + +- Fix an outdated path in an error message. + +## 0.25.4 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 0.25.3 +Fri, 19 Mar 2021 22:31:37 GMT + +### Patches + +- Improve README.md + +## 0.25.2 +Wed, 17 Mar 2021 05:04:37 GMT + +### Patches + +- Fix an issue where heft would crash when copying static assets in --watch mode. + +## 0.25.1 +Fri, 12 Mar 2021 01:13:27 GMT + +### Patches + +- Update node-sass to support Node 15. + +## 0.25.0 +Wed, 10 Mar 2021 05:10:05 GMT + +### Minor changes + +- (BREAKING CHANGE) Change the logic that resolves typescript, eslint, tslint, and api-extractor to look for a devDependency in the current project, and then for a dependency in the rig project, and then as any kind of dependency in the current project. + +## 0.24.4 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.24.3 +Tue, 02 Mar 2021 23:25:05 GMT + +### Patches + +- Fix an issue where build would continue even if TS reported errors. +- Determine the default static assets destination folder from the TSConfig's "outDir" property, instead of hardcoding "lib." + +## 0.24.2 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.24.1 +Fri, 22 Jan 2021 05:39:22 GMT + +### Patches + +- Fix an issue with webpack in "heft start" mode where "bundle" would continue too quickly. + +## 0.24.0 +Thu, 21 Jan 2021 04:19:00 GMT + +### Minor changes + +- Update jest-shared.config.json to specify a default "collectCoverageFrom" that includes all "src" files excluding test files +- Update jest-shared.config.json to configure "coverageDirectory" to use "./temp/coverage" (instead of "./coverage") + +## 0.23.2 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.23.1 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.23.0 +Mon, 14 Dec 2020 16:12:20 GMT + +### Minor changes + +- Delay build stages in --watch mode until the previous stage reports an initial completion. + +## 0.22.7 +Thu, 10 Dec 2020 23:25:49 GMT + +### Patches + +- Fix an issue where using CTRL+C to terminate "--watch" mode would sometimes leave a background process running (GitHub #2387) + +## 0.22.6 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.22.5 +Tue, 01 Dec 2020 01:10:38 GMT + +### Patches + +- Fix a typo in a logging message. + +## 0.22.4 +Mon, 30 Nov 2020 16:11:49 GMT + +_Version update only_ + +## 0.22.3 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.22.2 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.22.1 +Tue, 17 Nov 2020 01:17:38 GMT + +### Patches + +- Fix an issue where .map files were not being published + +## 0.22.0 +Mon, 16 Nov 2020 01:57:58 GMT + +### Minor changes + +- Add "webpack-dev-server" as a dependency since its types are part of Heft's API contract + +### Patches + +- Fix an issue where API Extractor errors/warnings did not show the message ID + +## 0.21.3 +Fri, 13 Nov 2020 01:11:00 GMT + +### Patches + +- Update Sass typings generation to update in watch mode when a dependency changes. + +## 0.21.2 +Thu, 12 Nov 2020 01:11:10 GMT + +### Patches + +- Fix a minor issue with heft.schema.json + +## 0.21.1 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.21.0 +Tue, 10 Nov 2020 23:13:11 GMT + +### Minor changes + +- Add new built-in Heft action "copyFiles" to copy or hardlink files during specified Heft events + +### Patches + +- Fix an incorrectly formatted error message + +## 0.20.1 +Tue, 10 Nov 2020 16:11:42 GMT + +### Patches + +- Improve error handling and make --debug print stacks of errors that occur in heft's internal initialization. + +## 0.20.0 +Sun, 08 Nov 2020 22:52:49 GMT + +### Minor changes + +- Update jest-shared.config.json with more file extension mappings for "jest-string-mock-transform" + +## 0.19.5 +Fri, 06 Nov 2020 16:09:30 GMT + +### Patches + +- Fix an issue where an extended "typescript.json" config file with omitted optional staticAssetsToCopy fields would cause schema validation to fail. + +## 0.19.4 +Tue, 03 Nov 2020 01:11:18 GMT + +### Patches + +- Update README.md + +## 0.19.3 +Mon, 02 Nov 2020 16:12:05 GMT + +### Patches + +- Honor jest reporters specified in config/jest.config.json + +## 0.19.2 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.19.1 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.19.0 +Thu, 29 Oct 2020 06:14:19 GMT + +### Minor changes + +- Upgrade @types/tapable and @types/webpack + +## 0.18.0 +Thu, 29 Oct 2020 00:11:33 GMT + +### Minor changes + +- Update Webpack dependency to ~4.44.2 + +## 0.17.4 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.17.3 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 0.17.2 +Sat, 24 Oct 2020 00:11:18 GMT + +### Patches + +- Add fileExtensions config to SassTypingsGenerator. + +## 0.17.1 +Wed, 21 Oct 2020 05:09:44 GMT + +### Patches + +- Bump downstream dependencies. + +## 0.17.0 +Fri, 16 Oct 2020 23:32:58 GMT + +### Minor changes + +- Allow the Webpack dev server configuration to be customized. + +## 0.16.1 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.16.0 +Wed, 14 Oct 2020 23:30:14 GMT + +### Minor changes + +- (BREAKING CHANGE) Rename "includePaths" to "importIncludePaths" in sass.json. + +### Patches + +- Add an "exclude" option to sass.json. + +## 0.15.8 +Tue, 13 Oct 2020 15:11:28 GMT + +### Patches + +- Fix an issue where heftSession.debugMode isn't set properly. + +## 0.15.7 +Mon, 12 Oct 2020 15:11:16 GMT + +### Patches + +- Include additionalModuleKindsToEmit in the copy-static-assets plugin destination folders. +- Throw if jest config file doesn't exist + +## 0.15.6 +Fri, 09 Oct 2020 15:11:08 GMT + +### Patches + +- Support relative imports in the Sass typings generator. + +## 0.15.5 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.15.4 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.15.3 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 0.15.2 +Fri, 02 Oct 2020 00:10:59 GMT + +### Patches + +- Include UPGRADING.md in npm package publish. + +## 0.15.1 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.15.0 +Thu, 01 Oct 2020 18:51:21 GMT + +### Minor changes + +- Add functionality to automatically generate typings for *.scss, *.sass, and *.css files. + +## 0.14.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig +- Reclassify compiler messages TS2564 and TS7053 as warnings instead of errors +- Print a warning if the API Extractor version is too old + +## 0.14.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- (BREAKING CHANGE) Collapse copy-static-assets.json into typescript.json. +- (BREAKING CHANGE) Move the config files from the ".heft" folder to the "config" folder and print a warning if an unexpected file is found in the ".heft" folder. +- (BREAKING CHANGE) Consolidate the clean.json and plugins.json files into a new heft.json file. +- (BREAKING CHANGE) Rename "emitFolderNameForJest" to "emitFolderNameForTests" in typescript.json +- Heft now supports the config/rig.json system as defined by @rushstack/rig-package +- Enable api-extractor.json to be provided by a rig package +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md +- Fix an issue where "heft build --help" printed incorrect help + +## 0.13.9 +Tue, 22 Sep 2020 05:45:56 GMT + +### Patches + +- Make the "plugins" field of "plugins.json" optional. + +## 0.13.8 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.13.7 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.13.6 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.13.5 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.13.4 +Fri, 18 Sep 2020 22:57:24 GMT + +### Patches + +- Fix an issue where folders listed in pathsToDelete in clean.json weren't deleted on Windows. + +## 0.13.3 +Fri, 18 Sep 2020 21:49:53 GMT + +### Patches + +- Add a missing field to the template config files. +- Fix an issue where, if an "extends" field pointed to a module that didn't exist, the error was silently ignored. + +## 0.13.2 +Wed, 16 Sep 2020 05:30:25 GMT + +### Patches + +- Add missing "extends" properties to schemas. +- Fix an issue where console.log() did not get formatted by HeftJestReporter + +## 0.13.1 +Tue, 15 Sep 2020 01:51:37 GMT + +### Patches + +- Improve reliability of jest-build-transform.js by only comparing timestamps when in "--watch" mode + +## 0.13.0 +Mon, 14 Sep 2020 15:09:48 GMT + +### Minor changes + +- Enable support for Jest inline snapshots + +## 0.12.0 +Sun, 13 Sep 2020 01:53:20 GMT + +### Minor changes + +- Update plugins to load configuration via heft-configuration-loader instead of in central plugins. +- Remove the loading of common/config/heft/* config files. +- (BREAKING CHANGE) Rename the "outFolderPath" and "emitFolderPathForJest" properties in typescript.json to "outFolderName" and "emitFolderNameForJest" + +## 0.11.1 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.11.0 +Wed, 09 Sep 2020 03:29:01 GMT + +### Minor changes + +- Add --max-workers option to the "test" action to control the maximum number of worker processes the test process can use. + +## 0.10.5 +Wed, 09 Sep 2020 00:38:48 GMT + +### Patches + +- Fix a typo in an error message to read that plugins must define a "pluginName" property, rather than the former "displayName" property + +## 0.10.4 +Mon, 07 Sep 2020 07:37:37 GMT + +### Patches + +- Fix an issue with WebpackPlugin loading webpack-dev-server in non-serve mode and setting the "WEBPACK_DEV_SERVER" environment variable. + +## 0.10.3 +Sat, 05 Sep 2020 18:56:35 GMT + +### Patches + +- Fix parsing of the --max-old-space-size build parameter. +- Fix parsing of the --plugin heft parameter. + +## 0.10.2 +Fri, 04 Sep 2020 15:06:27 GMT + +### Patches + +- Fix issues with parsing of tslint.json config files, including adding support for an array provided to "extends" and proper Node module resolution to extended config files. +- Fix a sourcemap issue that caused the debugger to show Jest files in a duplicate editor window (with the same path as the real file) + +## 0.10.1 +Thu, 03 Sep 2020 15:09:59 GMT + +### Patches + +- Fix an issue with Heft not printing an error message. + +## 0.10.0 +Wed, 02 Sep 2020 23:01:13 GMT + +### Minor changes + +- Add a simple way to specify a custom action. +- Remove the dev-deploy action from Heft + +## 0.9.0 +Wed, 02 Sep 2020 15:10:17 GMT + +### Minor changes + +- Add a method for plugins to hook into other plugins. +- BREAKING CHANGE: Rename the "displayName" plugin property to "pluginName" + +## 0.8.0 +Thu, 27 Aug 2020 11:27:06 GMT + +### Minor changes + +- Formalize the way extendable configuration files are loaded. +- Add a "setupFiles" setting to jest-shared.config.json, which implements the helper APIs from the @types/heft-jest package +- Add a "roots" setting to jest-shared.config.json, which enables "src/__mocks__" to be used for manually mocking Node.js system modules + +### Patches + +- Add a "modulePathIgnorePatterns" setting to jest-shared.config.json, which fixes a warning that was sometimes shown due to Jest loading extraneous files +- Add a "resolver" setting to jest-shared-config.json, which fixes an issue with importing manual mocks from a "__mocks__" subfolder. (See jest-improved-resolver.js for details.) + +## 0.7.0 +Tue, 25 Aug 2020 00:10:12 GMT + +### Minor changes + +- Adds a "--update-snapshots" command line flag which, when included, causes the test action to update the Jest snapshots. If this flag is omitted, tests with conditions that do not match the snapshots will fail. This replaces the older logic of using --production to prevent updating snapshots, which were otherwise updated. + +## 0.6.6 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 0.6.5 +Sat, 22 Aug 2020 05:55:42 GMT + +_Version update only_ + +## 0.6.4 +Fri, 21 Aug 2020 01:21:17 GMT + +### Patches + +- Fix an issue with Heft exiting with exit code 0 after a CLI error. + +## 0.6.3 +Thu, 20 Aug 2020 18:41:47 GMT + +### Patches + +- Fix an issue where failed test suites aren't listed as failures. + +## 0.6.2 +Thu, 20 Aug 2020 15:13:52 GMT + +### Patches + +- Add the --notest parameter back to "heft test" temporarily. + +## 0.6.1 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 0.6.0 +Tue, 18 Aug 2020 03:03:23 GMT + +### Minor changes + +- Add a "version selector" feature so that if a globally installed Heft binary is invoked, it will try to load the project's locally installed version of Heft + +## 0.5.1 +Mon, 17 Aug 2020 05:31:53 GMT + +### Patches + +- Fix a broken dependency + +## 0.5.0 +Mon, 17 Aug 2020 04:53:23 GMT + +### Minor changes + +- Formalize the way errors and warnings are emitted. +- Expose some useful Jest CLI parameters as "heft test" parameters +- Rename "--notest" to "--no--test" +- Improve "heft test" to show console output from tests + +### Patches + +- Normalize the way file paths are printed in errors and warnings. +- Ensure build steps that depend on emitted TS output aren't triggered until TS has written output to disk. +- Fix an issue where Heft could complete with errors but not return a nonzero process exit code +- Reclassify TypeScript messages such as "X is declared but never used" to be reported as warnings instead of errors + +## 0.4.7 +Thu, 13 Aug 2020 09:26:39 GMT + +### Patches + +- Fix a race condition where .js files were sometimes read by Jest before they were written by TypeScript +- Fix an issue where the TypeScript incremental build cache sometimes did not work correctly in "--watch" mode +- Add support for "additionalModuleKindsToEmit" in watch mode + +## 0.4.6 +Thu, 13 Aug 2020 04:57:38 GMT + +### Patches + +- Fix an issue with incorrect source maps for the Jest transform +- Fix a watch mode race condition where "--clean" ran in parallel with "heft test" (GitHub #2078) +- Fix an issue where "The transpiler output folder does not exist" was sometimes printed erroneously + +## 0.4.5 +Wed, 12 Aug 2020 00:10:05 GMT + +_Version update only_ + +## 0.4.4 +Tue, 11 Aug 2020 00:36:22 GMT + +### Patches + +- Fix an issue where emitted .js.map sourcemaps had an incorrect relative path (GitHub #2086) + +## 0.4.3 +Wed, 05 Aug 2020 18:27:33 GMT + +_Version update only_ + +## 0.4.2 +Tue, 04 Aug 2020 07:27:25 GMT + +### Patches + +- Update README.md logo + +## 0.4.1 +Mon, 03 Aug 2020 15:09:51 GMT + +### Patches + +- Add specific support for handling binary assets in Jest tests. + +## 0.4.0 +Mon, 03 Aug 2020 06:55:14 GMT + +### Minor changes + +- Add jest-identity-mock-transform for mocking .css imports in Webpack projects +- Add new "emitFolderPathForJest" setting in typescript.json, which simplifies how Webpack projects emit CommonJS for Jest + +### Patches + +- Fix an issue where jest-shared.config.json did not match .tsx file extensions +- Standardize how jest-shared.config.json references path-based imports +- Enable Jest "runInBand" when invoking Heft with "--debug" +- Fix an issue where "heft clean" did not clean Jest's unreliable cache + +## 0.3.1 +Thu, 30 Jul 2020 15:09:35 GMT + +### Patches + +- Emit errors and warnings from webpack. + +## 0.3.0 +Fri, 24 Jul 2020 20:40:38 GMT + +### Minor changes + +- Enable Heft to be used without the "@microsoft/rush-stack-compiler-n.n" system + +## 0.2.2 +Tue, 21 Jul 2020 00:54:55 GMT + +### Patches + +- Rename .heft/api-extractor.json to .heft/api-extractor-task.json to avoid confusion with API Extractor's config file + +## 0.2.1 +Tue, 21 Jul 2020 00:10:21 GMT + +### Patches + +- Update documentation + +## 0.2.0 +Mon, 20 Jul 2020 06:52:33 GMT + +### Minor changes + +- Make API Extractor's typescriptCompilerFolder option configurable. +- Include basic support for webpack-dev-server. + +## 0.1.2 +Thu, 16 Jul 2020 18:34:08 GMT + +### Patches + +- Republish to fix incorrect dependency specifier + +## 0.1.1 +Thu, 16 Jul 2020 17:53:35 GMT + +### Patches + +- Add support for TypeScript compilers older than version 3.6 (which do not support incremental compilation) + +## 0.1.0 +Wed, 15 Jul 2020 18:29:28 GMT + +### Minor changes + +- Initial release + diff --git a/apps/heft/LICENSE b/apps/heft/LICENSE new file mode 100644 index 00000000000..b0bd7c63a19 --- /dev/null +++ b/apps/heft/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft + +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/apps/heft/README.md b/apps/heft/README.md new file mode 100644 index 00000000000..fd224141575 --- /dev/null +++ b/apps/heft/README.md @@ -0,0 +1,90 @@ +# @rushstack/heft + +
+
+ + + +

+

+ + + + + +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 web applications, Node.js services, command-line tools, libraries, +and more. Heft builds all your JavaScript projects the same way: A way that works. + +Heft is typically launched by **package.json** commands such as `"npm run build"` or `"npm run test"`. It's designed +for use in a monorepo with potentially hundreds of projects, where the [Rush](https://rushjs.io/) orchestrator invokes +these commands separately in each project folder. In this situation, everything must execute as fast as possible. +Special purpose scripts become a headache to maintain, so it's better to replace them with a reusable engine that's +driven by config files. In a large repo, you'll want to minimize duplication of these config files across projects. +Ultimately, you'll want to define a small set of stereotypical project types +(["rigs"](https://rushstack.io/pages/heft/rig_packages/)) to officially support, then discourage projects from +overriding the rig configuration. Being consistent ensures that any person can easily contribute to any project. +Heft is a ready-made implementation of all these concepts. + +You don't need a monorepo to use Heft, however. It also works well for small standalone projects. Compared to other +similar systems, Heft has some unique design goals: + +- **Scalable**: Heft interfaces with the [Rush Stack](https://rushstack.io/) family of tools, which are tailored + for large monorepos with many people and projects. Heft doesn't require Rush, though. + +- **Optimized**: Heft tracks fine-grained performance metrics at each step. The TypeScript plugin implements + sophisticated optimizations such as: filesystem caching, incremental compilation, simultaneous multi-target emit, + and a unified compiler pass for Jest/Webpack/ESLint. JSON config files and plugin manifests enable fast + querying of metadata without evaluating potentially inefficient script code. + +- **Complete**: Rush Stack aspires to establish a fully worked out solution for building typical TypeScript + projects. Unopinionated task abstractions often work against this goal: It is expensive to optimize and support + (and document!) every possible cocktail of tech choices. The best optimizations and integrations + make deep assumptions about how tasks will interact. Although the Heft engine itself is very flexible, + our philosophy is to agree on a standard approach that covers a broad range of scenarios, then invest in + making the best possible experience for that approach. + +- **Extensible**: Most projects require at least a few specialized tasks such as preprocessors, postprocessors, + or loaders. Heft is organized around plugins using the [tapable](https://www.npmjs.com/package/tapable) + hook system (familiar from Webpack). Strongly typed APIs make it easy to write your own plugins. Compared to + loose architectures such as Grunt or Gulp, Heft's plugin-system is organized around explicit easy-to-read + config files. Customizations generally will extend a standard rig rather than starting from scratch. + +- **Familiar**: Like Rush, Heft is a regular Node.js application -- developers don't need to install native + prerequisites such as Python, MSYS2, or the .NET Framework. Heft's source code is easy to understand and debug + because it's 100% TypeScript, the same programming language as your web projects. Developing for native targets + is still possible, of course. + +- **Professional**: The Rush Stack projects are developed by and for engineers who ship large scale commercial + apps. Each feature is designed, discussed in the open, and thoughtfully code reviewed. Breaking changes + require us to migrate thousands of our own projects, so upgrades are relatively painless compared to typical + Node.js tooling. + + + + + +Heft has not yet reached its 1.0 milestone, however the following tasks are already available: + +- **Compiler**: [TypeScript](https://www.typescriptlang.org/) with incremental compilation, with "watch" mode +- **Linter**: [TypeScript-ESLint](https://github.com/typescript-eslint/typescript-eslint), plus legacy support + for projects that still use [TSLint](https://palantir.github.io/tslint/) +- **Test runner**: [Jest](https://www.npmjs.com/package/jest) +- **Bundler**: [Webpack](https://webpack.js.org/), including`webpack-dev-server` with watch mode +- **.d.ts bundler**: [API Extractor](https://api-extractor.com/) +- **Asset management**: Heft also includes a `copy-static-assets` helper supporting arbitrary globs, with "watch" mode + +For more detailed documentation, please see the [Heft topic](https://rushstack.io/pages/heft/overview/) on +the Rush Stack website. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/heft/CHANGELOG.md) - Find + out what's new in the latest version +- [UPGRADING.md]( + https://github.com/microsoft/rushstack/blob/main/apps/heft/UPGRADING.md) - Instructions + for migrating existing projects to use a newer version of Heft +- [API Reference](https://api.rushstack.io/pages/heft/) + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/heft/UPGRADING.md b/apps/heft/UPGRADING.md new file mode 100644 index 00000000000..fa6a9bc7af3 --- /dev/null +++ b/apps/heft/UPGRADING.md @@ -0,0 +1,285 @@ +# Upgrade notes for @rushstack/heft + +### Heft 0.53.0 +The `taskEvent` configuration option in heft.json has been removed, and use of any `taskEvent`-based functionality is now accomplished by referencing the plugins directly within the `@rushstack/heft` package. + +Plugin name mappings for previously-existing task events are: +- `copyFiles` -> `copy-files-plugin` +- `deleteFiles` -> `delete-files-plugin` +- `runScript` -> `run-script-plugin` +- `nodeService` -> `node-service-plugin` + +Example diff of a heft.json file that uses the `copyFiles` task event: +```diff +{ + "phasesByName": { + "build": { + "tasksbyName": { + "perform-copy": { +- "taskEvent": { +- "eventKind": "copyFiles", ++ "taskPlugin": { ++ "pluginPackage": "@rushstack/heft", ++ "pluginName": "copy-files-plugin", + "options": { + ... + } + } + } + } + } + } +} +``` + +### Heft 0.52.0 + +The `nodeService` built-in plugin now supports the `--serve` parameter, to be consistent with the `@rushstack/heft-webpack5-plugin` dev server. + +Old behavior: +- `nodeService` was always enabled, but would have no effect unless Heft was in watch mode (`heft start`) +- If `config/node-service.json` was omitted, the plugin would silently be disabled + +New behavior: +- `nodeService` is always loaded by `@rushstack/heft-node-rig` but for a custom `heft.json` you need to load it manually +- `nodeService` has no effect unless you specify `--serve`, for example: `heft build-watch --serve` +- If `--serve` is specified and `config/node-service.json` is omitted, then Heft fails with a hard error + +### Heft 0.51.0 + +⭐ This release included significant breaking changes. ⭐ + +For details, please see our two blog posts: + +- [What's New in Heft 0.51](https://rushstack.io/blog/2023/06/15/heft-whats-new/) + +- [Heft 0.51 Migration Guide](https://rushstack.io/blog/2023/06/16/heft-migration-guide/) + +### Heft 0.35.0 + +This release of Heft removed the Sass plugin from the `@rushstack/heft` package +and moved it into its own package (`@rushstack/heft-sass-plugin`). To reenable +Sass support in a project, include a dependency on `@rushstack/heft-sass-plugin` +and add the following option to the project's `config/heft.json` file: + +```JSON +{ + "heftPlugins": [ + { + "plugin": "@rushstack/heft-sass-plugin" + } + ] +} +``` + +If you are using `@rushstack/heft-web-rig`, upgrading the rig package will bring +Sass support automatically. + +### Heft 0.32.0 + +Breaking change for Jest: This release of Heft enables rig support for Jest config files. +It also reduces Heft's installation footprint by removing the Jest plugin from `@rushstack/heft` +and moving it to its own package `@rushstack/heft-jest-plugin`. As a result, Jest is now +disabled by default. + +To reenable Jest support for your project, follow these steps: + +1. If you are using `@rushstack/heft-node-rig` or `@rushstack/heft-web-rig`, the Jest + plugin is already enabled. Skip to step 4. + +2. Add the `@rushstack/heft-jest-plugin` dependency to your project's **package.json** file. + +3. Load the plugin by adding this setting to your `config/heft.json` file: + + ```js + { + "heftPlugins": [ + { + "plugin": "@rushstack/heft-jest-plugin" + } + ] + } + ``` + +4. Update your `config/jest.config.json` file, replacing the `preset` field with + an equivalent `extends` field. This enables Heft to perform module resolution + with support for rigs. + + For example, this setting... + + ```js + { + "preset": "./node_modules/@rushstack/heft/includes/jest-shared.config.json" + } + ``` + + ...should be changed to this: + + ```js + { + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json" + } + ``` + + As another example, if you are using a rig, then this... + + ```js + { + "preset": "./node_modules/@rushstack/heft-web-rig/profiles/library/config/jest.config.json" + } + ``` + + ...should be changed to this: + + ```js + { + "extends": "@rushstack/heft-web-rig/profiles/library/config/jest.config.json" + } + ``` + +This `extends` field is a Heft-specific enhancement that will not work if the Jest command line +is invoked without Heft. (Doing so was not generally useful; in our configuration Jest relies +on Heft to invoke the compiler and any other preprocessing steps.) + +If for some reason your `jest.config.json` needs to be directly readable by Jest, the +`disableConfigurationModuleResolution` setting can be used to restore the old behavior. +For example: + + ```js + { + "heftPlugins": [ + { + "plugin": "@rushstack/heft-jest-plugin", + "options": { + // (Not recommended) Disable Heft's support for rigs and the "extends" field + "disableConfigurationModuleResolution": true + } + } + ] + } + ``` + + +### Heft 0.26.0 + +This release of Heft removed the Webpack plugins from the `@rushstack/heft` package +and moved them into their own package (`@rushstack/heft-webpack4-plugin`). To reenable +Webpack support in a project, include a dependency on `@rushstack/heft-webpack4-plugin` +and add the following option to the project's `config/heft.json` file: + +```JSON +{ + "heftPlugins": [ + { + "plugin": "@rushstack/heft-webpack4-plugin" + } + ] +} +``` + +If you are using `@rushstack/heft-web-rig`, upgrading the rig package will bring +Webpack support automatically. + +### Heft 0.14.0 + +This release of Heft consolidated several config files and introduced support +for [rig packages](https://www.npmjs.com/package/@rushstack/rig-package). + +The major changes were: + +- `.heft/typescript.json` has moved to a different folder `config/typescript.json`. Going forward + config files will no longer be stored in the hidden `.heft` folder. + +- The `emitFolderNameForJest` setting in `typescript.json` has been renamed to `emitFolderNameForTests` + +- `clean.json` has been removed. If your file previously looked like this: + + **.heft/clean.json** (OLD) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/clean.schema.json", + + "pathsToDelete": ["dist", "lib", "temp"] + } + ``` + + ...these settings are now specified in the new `heft.json` file like this: + + **config/heft.json** (NEW) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/heft.schema.json", + + "eventActions": [ + { + "actionKind": "deleteGlobs", + "heftEvent": "clean", + "actionId": "defaultClean", + "globsToDelete": ["dist", "lib", "temp"] + } + ] + + . . . + } + ``` + +- `copy-static-assets.json` has been removed. If your file previously looked like this: + + **.heft/copy-static-assets.json** (OLD) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/copy-static-assets.schema.json", + "fileExtensions": [".css", ".png"] + } + ``` + + ...these settings are now specified in the `typescript.json` file like this: + + **config/typescript.json** (NEW) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/typescript.schema.json", + + . . . + + "staticAssetsToCopy": { + "fileExtensions": [".css", ".png"] + } + } + ``` + +- `plugins.json` has been removed. If your file previously looked like this: + + **.heft/plugins.json** (OLD) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/plugins.schema.json", + + "plugins": [ + { + "plugin": "path/to/my-plugin", + } + ] + } + + ``` + + ...these settings are now specified in the `heft.json` file like this: + + **config/heft.json** (NEW) + ```js + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/typescript.schema.json", + + . . . + + "heftPlugins": [ + { + "plugin": "path/to/my-plugin", + } + ] + } + ``` + +Complete documentation for Heft config file formats can be found on +the [project website](https://rushstack.io/pages/heft/overview/). diff --git a/apps/heft/bin/heft b/apps/heft/bin/heft new file mode 100755 index 00000000000..ef67d5db050 --- /dev/null +++ b/apps/heft/bin/heft @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/startWithVersionSelector.js'); diff --git a/apps/heft/config/api-extractor.json b/apps/heft/config/api-extractor.json new file mode 100644 index 00000000000..34fb7776c9d --- /dev/null +++ b/apps/heft/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$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, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/apps/heft/config/heft.json b/apps/heft/config/heft.json new file mode 100644 index 00000000000..8d1359f022f --- /dev/null +++ b/apps/heft/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/apps/heft/config/jest.config.json b/apps/heft/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/apps/heft/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/apps/heft/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/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 new file mode 100644 index 00000000000..d7c161a404f --- /dev/null +++ b/apps/heft/heft-plugin.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "lifecyclePlugins": [], + + "taskPlugins": [ + { + "pluginName": "copy-files-plugin", + "entryPoint": "./lib/plugins/CopyFilesPlugin", + "optionsSchema": "./lib/schemas/copy-files-options.schema.json" + }, + { + "pluginName": "delete-files-plugin", + "entryPoint": "./lib/plugins/DeleteFilesPlugin", + "optionsSchema": "./lib/schemas/delete-files-options.schema.json" + }, + { + "pluginName": "node-service-plugin", + "entryPoint": "./lib/plugins/NodeServicePlugin", + "parameterScope": "node-service", + "parameters": [ + { + "longName": "--serve", + "parameterKind": "flag", + "description": "Start a local web server for testing purposes. This parameter is only available when running in watch mode." + } + ] + }, + { + "pluginName": "run-script-plugin", + "entryPoint": "./lib/plugins/RunScriptPlugin", + "optionsSchema": "./lib/schemas/run-script-options.schema.json" + }, + { + "entryPoint": "./lib/plugins/SetEnvironmentVariablesPlugin", + "pluginName": "set-environment-variables-plugin", + "optionsSchema": "./lib/schemas/set-environment-variables-plugin.schema.json" + } + ] +} diff --git a/apps/heft/package.json b/apps/heft/package.json new file mode 100644 index 00000000000..008892445b7 --- /dev/null +++ b/apps/heft/package.json @@ -0,0 +1,57 @@ +{ + "name": "@rushstack/heft", + "version": "1.1.7", + "description": "Build all your JavaScript projects the same way: A way that works.", + "keywords": [ + "toolchain", + "watch", + "bundle", + "Webpack", + "typescript", + "eslint", + "compiler", + "incremental" + ], + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/heft" + }, + "engines": { + "node": ">=10.13.0" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "lib/index.js", + "types": "dist/heft.d.ts", + "bin": { + "heft": "./bin/heft" + }, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/heft-config-file": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/operation-graph": "workspace:*", + "@rushstack/rig-package": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "@types/tapable": "1.0.6", + "fast-glob": "~3.3.1", + "git-repo-info": "~2.1.0", + "ignore": "~5.1.6", + "tapable": "1.1.3", + "watchpack": "2.4.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "1.1.4", + "@types/watchpack": "2.4.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/apps/heft/src/cli/HeftActionRunner.ts b/apps/heft/src/cli/HeftActionRunner.ts new file mode 100644 index 00000000000..b9d5c7f7f26 --- /dev/null +++ b/apps/heft/src/cli/HeftActionRunner.ts @@ -0,0 +1,645 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; +import { + type IOperationExecutionOptions, + type IWatchLoopState, + Operation, + OperationExecutionManager, + OperationGroupRecord, + type OperationRequestRunCallback, + OperationStatus, + WatchLoop +} from '@rushstack/operation-graph'; +import type { + CommandLineFlagParameter, + CommandLineParameterProvider, + CommandLineStringListParameter +} from '@rushstack/ts-command-line'; + +import type { InternalHeftSession } from '../pluginFramework/InternalHeftSession'; +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { LoggingManager } from '../pluginFramework/logging/LoggingManager'; +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 { IHeftPhase, HeftPhase } from '../pluginFramework/HeftPhase'; +import type { IHeftAction, IHeftActionOptions } from './actions/IHeftAction'; +import type { + IHeftLifecycleCleanHookOptions, + IHeftLifecycleSession, + IHeftLifecycleToolFinishHookOptions, + IHeftLifecycleToolStartHookOptions +} from '../pluginFramework/HeftLifecycleSession'; +import type { HeftLifecycle } from '../pluginFramework/HeftLifecycle'; +import type { IHeftTask, HeftTask } from '../pluginFramework/HeftTask'; +import { deleteFilesAsync, type IDeleteOperation } from '../plugins/DeleteFilesPlugin'; +import { Constants } from '../utilities/Constants'; + +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, + isVerbose: boolean +): void { + // Ensure that verbose is enabled on the terminal if requested. terminalProvider.verboseEnabled + // should already be `true` if the `--debug` flag was provided. This is set in HeftCommandLineParser + if (heftConfiguration.terminalProvider instanceof ConsoleTerminalProvider) { + heftConfiguration.terminalProvider.verboseEnabled = + heftConfiguration.terminalProvider.verboseEnabled || isVerbose; + } + + // Log some information about the execution + const projectPackageJson: IPackageJson = heftConfiguration.projectPackageJson; + terminal.writeVerboseLine(`Project: ${projectPackageJson.name}@${projectPackageJson.version}`); + terminal.writeVerboseLine(`Project build folder: ${heftConfiguration.buildFolderPath}`); + if (heftConfiguration.rigConfig.rigFound) { + terminal.writeVerboseLine(`Rig package: ${heftConfiguration.rigConfig.rigPackageName}`); + terminal.writeVerboseLine(`Rig profile: ${heftConfiguration.rigConfig.rigProfile}`); + } + terminal.writeVerboseLine(`Heft version: ${heftConfiguration.heftPackageJson.version}`); + terminal.writeVerboseLine(`Node version: ${process.version}`); + terminal.writeVerboseLine(''); +} + +let _cliAbortSignal: AbortSignal | undefined; +export function ensureCliAbortSignal(terminal: ITerminal): AbortSignal { + if (!_cliAbortSignal) { + // Set up the ability to terminate the build via Ctrl+C and have it exit gracefully if pressed once, + // less gracefully if pressed a second time. + const cliAbortController: AbortController = new AbortController(); + _cliAbortSignal = cliAbortController.signal; + const cli: ReadlineInterface = createInterface(process.stdin, undefined, undefined, true); + let forceTerminate: boolean = false; + cli.on('SIGINT', () => { + cli.close(); + + if (forceTerminate) { + terminal.writeErrorLine(`Forcibly terminating.`); + process.exit(1); + } else { + terminal.writeLine( + Colorize.yellow(Colorize.bold(`Canceling... Press Ctrl+C again to forcibly terminate.`)) + ); + } + + forceTerminate = true; + cliAbortController.abort(); + }); + } + + return _cliAbortSignal; +} + +export async function runWithLoggingAsync( + fn: () => Promise, + action: IHeftAction, + loggingManager: LoggingManager, + terminal: ITerminal, + metricsCollector: MetricsCollector, + abortSignal: AbortSignal, + throwOnFailure?: boolean +): Promise { + const startTime: number = performance.now(); + loggingManager.resetScopedLoggerErrorsAndWarnings(); + + let result: OperationStatus = OperationStatus.Failure; + + // Execute the action operations + let encounteredError: boolean = false; + try { + result = await fn(); + if (result === OperationStatus.Failure) { + encounteredError = true; + } + } catch (e) { + encounteredError = true; + throw e; + } finally { + const warningStrings: string[] = loggingManager.getWarningStrings(); + const errorStrings: string[] = loggingManager.getErrorStrings(); + + const wasAborted: boolean = abortSignal.aborted; + const encounteredWarnings: boolean = warningStrings.length > 0 || wasAborted; + encounteredError = encounteredError || errorStrings.length > 0; + + await metricsCollector.recordAsync( + action.actionName, + { + encounteredError + }, + action.getParameterStringMap() + ); + + const finishedLoggingWord: string = encounteredError ? 'Failed' : wasAborted ? 'Aborted' : 'Finished'; + const duration: number = performance.now() - startTime; + const durationSeconds: number = Math.round(duration) / 1000; + const finishedLoggingLine: string = `-------------------- ${finishedLoggingWord} (${durationSeconds}s) --------------------`; + terminal.writeLine( + Colorize.bold( + (encounteredError ? Colorize.red : encounteredWarnings ? Colorize.yellow : Colorize.green)( + finishedLoggingLine + ) + ) + ); + + if (warningStrings.length > 0) { + terminal.writeWarningLine( + `Encountered ${warningStrings.length} warning${warningStrings.length === 1 ? '' : 's'}` + ); + for (const warningString of warningStrings) { + terminal.writeWarningLine(` ${warningString}`); + } + } + + if (errorStrings.length > 0) { + terminal.writeErrorLine( + `Encountered ${errorStrings.length} error${errorStrings.length === 1 ? '' : 's'}` + ); + for (const errorString of errorStrings) { + terminal.writeErrorLine(` ${errorString}`); + } + } + } + + if (encounteredError && throwOnFailure) { + throw new AlreadyReportedError(); + } + + return result; +} + +export class HeftActionRunner { + private readonly _action: IHeftAction; + private readonly _terminal: ITerminal; + private readonly _internalHeftSession: InternalHeftSession; + private readonly _metricsCollector: MetricsCollector; + private readonly _loggingManager: LoggingManager; + private readonly _heftConfiguration: HeftConfiguration; + private _parameterManager: HeftParameterManager | undefined; + private readonly _parallelism: number; + + public constructor(options: IHeftActionRunnerOptions) { + 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 = heftConfiguration.numberOfCores; + + // 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 Node 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. + this._parallelism = Math.max(numberOfCores - 1, 1); + } else { + // Unix-like operating systems have more balanced scheduling, so default + // to the number of CPU cores + this._parallelism = numberOfCores; + } + } + + protected get parameterManager(): HeftParameterManager { + if (!this._parameterManager) { + throw new InternalError(`HeftActionRunner.defineParameters() has not been called.`); + } + return this._parameterManager; + } + + public defineParameters(parameterProvider?: CommandLineParameterProvider | undefined): void { + if (!this._parameterManager) { + // Use the provided parameter provider if one was provided. This is used by the RunAction + // to allow for the Heft plugin parameters to be applied as scoped parameters. + parameterProvider = parameterProvider || this._action; + } else { + throw new InternalError(`HeftActionParameters.defineParameters() has already been called.`); + } + + const verboseFlag: CommandLineFlagParameter = parameterProvider.defineFlagParameter({ + parameterLongName: Constants.verboseParameterLongName, + parameterShortName: Constants.verboseParameterShortName, + description: 'If specified, log information useful for debugging.' + }); + const productionFlag: CommandLineFlagParameter = parameterProvider.defineFlagParameter({ + parameterLongName: Constants.productionParameterLongName, + description: 'If specified, run Heft in production mode.' + }); + const localesParameter: CommandLineStringListParameter = parameterProvider.defineStringListParameter({ + parameterLongName: Constants.localesParameterLongName, + argumentName: 'LOCALE', + description: 'Use the specified locale for this run, if applicable.' + }); + + let cleanFlagDescription: string = + 'If specified, clean the outputs at the beginning of the lifecycle and before running each phase.'; + if (this._action.watch) { + cleanFlagDescription = + `${cleanFlagDescription} Cleaning will only be performed once for the lifecycle and each phase, ` + + `and further incremental runs will not be cleaned for the duration of execution.`; + } + const cleanFlag: CommandLineFlagParameter = parameterProvider.defineFlagParameter({ + parameterLongName: Constants.cleanParameterLongName, + description: cleanFlagDescription + }); + + const parameterManager: HeftParameterManager = new HeftParameterManager({ + getIsDebug: () => this._internalHeftSession.debug, + getIsVerbose: () => verboseFlag.value, + getIsProduction: () => productionFlag.value, + getIsWatch: () => this._action.watch, + getLocales: () => localesParameter.values, + getIsClean: () => !!cleanFlag?.value + }); + + // Add all the lifecycle parameters for the action + for (const lifecyclePluginDefinition of this._internalHeftSession.lifecycle.pluginDefinitions) { + parameterManager.addPluginParameters(lifecyclePluginDefinition); + } + + // Add all the task parameters for the action + for (const phase of this._action.selectedPhases) { + for (const task of phase.tasks) { + parameterManager.addPluginParameters(task.pluginDefinition); + } + } + + // Finalize and apply to the CommandLineParameterProvider + parameterManager.finalizeParameters(parameterProvider); + this._parameterManager = parameterManager; + } + + public async executeAsync(): Promise { + const terminal: ITerminal = this._terminal; + // Set the parameter manager on the internal session, which is used to provide the selected + // parameters to plugins. Set this in onExecute() since we now know that this action is being + // executed, and the session should be populated with the executing parameters. + this._internalHeftSession.parameterManager = this.parameterManager; + + initializeHeft(this._heftConfiguration, terminal, this.parameterManager.defaultParameters.verbose); + + const operations: ReadonlySet> = + this._generateOperations(); + + const executionManager: OperationExecutionManager< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = new OperationExecutionManager(operations); + + const cliAbortSignal: AbortSignal = ensureCliAbortSignal(this._terminal); + + try { + await _startLifecycleAsync(this._internalHeftSession); + + if (this._action.watch) { + const watchLoop: WatchLoop = this._createWatchLoop(executionManager); + + if (process.send) { + await watchLoop.runIPCAsync(); + } else { + await watchLoop.runUntilAbortedAsync(cliAbortSignal, () => { + terminal.writeLine(Colorize.bold('Waiting for changes. Press CTRL + C to exit...')); + terminal.writeLine(''); + }); + } + } else { + await this._executeOnceAsync(executionManager, cliAbortSignal); + } + } finally { + // Invoke this here both to ensure it always runs and that it does so after recordMetrics + // This is treated as a finalizer for any assets created in lifecycle plugins. + // It is the responsibility of the lifecycle plugin to ensure that finish gracefully handles + // aborted runs. + await _finishLifecycleAsync(this._internalHeftSession); + } + } + + private _createWatchLoop(executionManager: OperationExecutionManager): WatchLoop { + const { _terminal: terminal } = this; + const watchLoop: WatchLoop = new WatchLoop({ + onBeforeExecute: () => { + // Write an empty line to the terminal for separation between iterations. We've already iterated + // at this point, so log out that we're about to start a new run. + terminal.writeLine(''); + terminal.writeLine(Colorize.bold('Starting incremental build...')); + }, + executeAsync: (state: IWatchLoopState): Promise => { + return this._executeOnceAsync(executionManager, state.abortSignal, state.requestRun); + }, + onRequestRun: (requestor?: string) => { + terminal.writeLine(Colorize.bold(`New run requested by ${requestor || 'unknown task'}`)); + }, + onAbort: () => { + terminal.writeLine(Colorize.bold(`Cancelling incremental build...`)); + } + }); + return watchLoop; + } + + private async _executeOnceAsync( + executionManager: OperationExecutionManager, + abortSignal: AbortSignal, + 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< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = { + terminal: this._terminal, + parallelism: this._parallelism, + abortSignal, + 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); + }, + this._action, + this._loggingManager, + this._terminal, + this._metricsCollector, + abortSignal, + !requestRun + ); + } + + private _generateOperations(): Set> { + const { selectedPhases } = this._action; + + const operations: Map< + string, + Operation + > = new Map(); + const operationGroups: Map> = new Map(); + const internalHeftSession: InternalHeftSession = this._internalHeftSession; + + let hasWarnedAboutSkippedPhases: boolean = false; + for (const phase of selectedPhases) { + // Warn if any dependencies are excluded from the list of selected phases + if (!hasWarnedAboutSkippedPhases) { + for (const dependencyPhase of phase.dependencyPhases) { + if (!selectedPhases.has(dependencyPhase)) { + // Only write once, and write with yellow to make it stand out without writing a warning to stderr + hasWarnedAboutSkippedPhases = true; + this._terminal.writeLine( + Colorize.bold( + 'The provided list of phases does not contain all phase dependencies. You may need to run the ' + + 'excluded phases manually.' + ) + ); + break; + } + } + } + + // Create operation for the phase start node + 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, + 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, operationGroups) + ); + } + + // Set all tasks in a in a phase as dependencies of the consuming phase + for (const consumingPhase of phase.consumingPhases) { + if (this._action.selectedPhases.has(consumingPhase)) { + // Set all tasks in a dependency phase as dependencies of the consuming phase to ensure the dependency + // tasks run first + const consumingPhaseOperation: Operation = _getOrCreatePhaseOperation( + internalHeftSession, + consumingPhase, + operations, + operationGroups + ); + consumingPhaseOperation.addDependency(taskOperation); + // This is purely to simplify the reported graph for phase circularities + consumingPhaseOperation.addDependency(phaseOperation); + } + } + } + } + + return new Set(operations.values()); + } +} + +function _getOrCreatePhaseOperation( + this: void, + internalHeftSession: InternalHeftSession, + phase: HeftPhase, + 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({ + group, + name: phase.phaseName, + runner: new PhaseOperationRunner({ phase, internalHeftSession }) + }); + operations.set(key, operation); + } + return operation; +} + +function _getOrCreateTaskOperation( + this: void, + internalHeftSession: InternalHeftSession, + task: HeftTask, + operations: Map, + operationGroups: Map> +): Operation { + const key: string = `${task.parentPhase.phaseName}.${task.taskName}`; + + 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({ + group, + runner: new TaskOperationRunner({ + internalHeftSession, + task + }), + name: task.taskName, + metadata: { task, phase: task.parentPhase } + }); + operations.set(key, operation); + } + return operation; +} + +async function _startLifecycleAsync(this: void, internalHeftSession: InternalHeftSession): Promise { + const { clean } = internalHeftSession.parameterManager.defaultParameters; + + // Load and apply the lifecycle plugins + const lifecycle: HeftLifecycle = internalHeftSession.lifecycle; + const { lifecycleLogger } = lifecycle; + await lifecycle.applyPluginsAsync(lifecycleLogger.terminal); + + if (lifecycleLogger.hasErrors) { + throw new AlreadyReportedError(); + } + + if (clean) { + const startTime: number = performance.now(); + lifecycleLogger.terminal.writeVerboseLine('Starting clean'); + + // Grab the additional clean operations from the phase + const deleteOperations: IDeleteOperation[] = []; + + // Delete all temp folders for tasks by default + for (const pluginDefinition of lifecycle.pluginDefinitions) { + const lifecycleSession: IHeftLifecycleSession = + await lifecycle.getSessionForPluginDefinitionAsync(pluginDefinition); + deleteOperations.push({ sourcePath: lifecycleSession.tempFolderPath }); + } + + // Create the options and provide a utility method to obtain paths to delete + const cleanHookOptions: IHeftLifecycleCleanHookOptions = { + addDeleteOperations: (...deleteOperationsToAdd: IDeleteOperation[]) => + deleteOperations.push(...deleteOperationsToAdd) + }; + + // Run the plugin clean hook + if (lifecycle.hooks.clean.isUsed()) { + try { + await lifecycle.hooks.clean.promise(cleanHookOptions); + } catch (e) { + // Log out using the clean logger, and return an error status + if (!(e instanceof AlreadyReportedError)) { + lifecycleLogger.emitError(e as Error); + } + throw new AlreadyReportedError(); + } + } + + // Delete the files if any were specified + if (deleteOperations.length) { + const rootFolderPath: string = internalHeftSession.heftConfiguration.buildFolderPath; + await deleteFilesAsync(rootFolderPath, deleteOperations, lifecycleLogger.terminal); + } + + lifecycleLogger.terminal.writeVerboseLine(`Finished clean (${performance.now() - startTime}ms)`); + + if (lifecycleLogger.hasErrors) { + throw new AlreadyReportedError(); + } + } + + // Run the start hook + if (lifecycle.hooks.toolStart.isUsed()) { + const lifecycleToolStartHookOptions: IHeftLifecycleToolStartHookOptions = {}; + await lifecycle.hooks.toolStart.promise(lifecycleToolStartHookOptions); + + if (lifecycleLogger.hasErrors) { + throw new AlreadyReportedError(); + } + } +} + +async function _finishLifecycleAsync(internalHeftSession: InternalHeftSession): Promise { + const lifecycleToolFinishHookOptions: IHeftLifecycleToolFinishHookOptions = {}; + await internalHeftSession.lifecycle.hooks.toolFinish.promise(lifecycleToolFinishHookOptions); +} diff --git a/apps/heft/src/cli/HeftCommandLineParser.ts b/apps/heft/src/cli/HeftCommandLineParser.ts new file mode 100644 index 00000000000..67389a7d053 --- /dev/null +++ b/apps/heft/src/cli/HeftCommandLineParser.ts @@ -0,0 +1,259 @@ +// 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, + type CommandLineFlagParameter, + type CommandLineAction +} from '@rushstack/ts-command-line'; +import { InternalError, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Terminal, ConsoleTerminalProvider, type ITerminal } from '@rushstack/terminal'; + +import { MetricsCollector } from '../metrics/MetricsCollector'; +import { HeftConfiguration } from '../configuration/HeftConfiguration'; +import { InternalHeftSession } from '../pluginFramework/InternalHeftSession'; +import { LoggingManager } from '../pluginFramework/logging/LoggingManager'; +import { CleanAction } from './actions/CleanAction'; +import { PhaseAction } from './actions/PhaseAction'; +import { RunAction } from './actions/RunAction'; +import type { IHeftActionOptions } from './actions/IHeftAction'; +import { AliasAction } from './actions/AliasAction'; +import { getToolParameterNamesFromArgs } from '../utilities/CliUtilities'; +import { Constants } from '../utilities/Constants'; + +/** + * This interfaces specifies values for parameters that must be parsed before the CLI + * is fully initialized. + */ +interface IPreInitializationArgumentValues { + debug?: boolean; + unmanaged?: boolean; +} + +const HEFT_TOOL_FILENAME: 'heft' = 'heft'; + +export class HeftCommandLineParser extends CommandLineParser { + public readonly globalTerminal: ITerminal; + + private readonly _debugFlag: CommandLineFlagParameter; + private readonly _unmanagedFlag: CommandLineFlagParameter; + private readonly _debug: boolean; + private readonly _terminalProvider: ConsoleTerminalProvider; + private readonly _loggingManager: LoggingManager; + private readonly _metricsCollector: MetricsCollector; + private readonly _heftConfiguration: HeftConfiguration; + private _internalHeftSession: InternalHeftSession | undefined; + + public constructor() { + super({ + toolFilename: HEFT_TOOL_FILENAME, + toolDescription: 'Heft is a pluggable build system designed for web projects.' + }); + + // Initialize the debug flag as a parameter on the tool itself + this._debugFlag = this.defineFlagParameter({ + parameterLongName: Constants.debugParameterLongName, + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + // Initialize the unmanaged flag as a parameter on the tool itself. While this parameter + // is only used during version selection, we need to support parsing it here so that we + // don't throw due to an unrecognized parameter. + this._unmanagedFlag = this.defineFlagParameter({ + parameterLongName: Constants.unmanagedParameterLongName, + description: + 'Disables the Heft version selector: When Heft is invoked via the shell path, normally it' + + " will examine the project's package.json dependencies and try to use the locally installed version" + + ' of Heft. Specify "--unmanaged" to force the invoked version of Heft to be used. This is useful for' + + ' example if you want to test a different version of Heft.' + }); + + // Pre-initialize with known argument values to determine state of "--debug" + const preInitializationArgumentValues: IPreInitializationArgumentValues = + this._getPreInitializationArgumentValues(); + this._debug = !!preInitializationArgumentValues.debug; + + // Enable debug and verbose logging if the "--debug" flag is set + this._terminalProvider = new ConsoleTerminalProvider({ + debugEnabled: this._debug, + verboseEnabled: this._debug + }); + this.globalTerminal = new Terminal(this._terminalProvider); + this._loggingManager = new LoggingManager({ terminalProvider: this._terminalProvider }); + if (this._debug) { + // Enable printing stacktraces if the "--debug" flag is set + this._loggingManager.enablePrintStacks(); + InternalError.breakInDebugger = true; + } + + const numberOfCores: number = os.availableParallelism?.() ?? os.cpus().length; + this._heftConfiguration = HeftConfiguration.initialize({ + cwd: process.cwd(), + terminalProvider: this._terminalProvider, + numberOfCores + }); + + this._metricsCollector = new MetricsCollector(); + } + + public async executeAsync(args?: string[]): Promise { + // Defensively set the exit code to 1 so if the tool crashes for whatever reason, + // we'll have a nonzero exit code. + process.exitCode = 1; + + try { + this._normalizeCwd(); + + const internalHeftSession: InternalHeftSession = await InternalHeftSession.initializeAsync({ + debug: this._debug, + heftConfiguration: this._heftConfiguration, + loggingManager: this._loggingManager, + metricsCollector: this._metricsCollector + }); + this._internalHeftSession = internalHeftSession; + + const actionOptions: IHeftActionOptions = { + internalHeftSession: internalHeftSession, + terminal: this.globalTerminal, + loggingManager: this._loggingManager, + metricsCollector: this._metricsCollector, + heftConfiguration: this._heftConfiguration + }; + + // Add the clean action, the run action, and the individual phase actions + this.addAction(new CleanAction(actionOptions)); + this.addAction(new RunAction(actionOptions)); + for (const phase of internalHeftSession.phases) { + this.addAction(new PhaseAction({ ...actionOptions, phase })); + } + + // Add the watch variant of the run action and the individual phase actions + this.addAction(new RunAction({ ...actionOptions, watch: true })); + for (const phase of internalHeftSession.phases) { + this.addAction(new PhaseAction({ ...actionOptions, phase, watch: true })); + } + + // Add the action aliases last, since we need the targets to be defined before we can add the aliases + const aliasActions: AliasCommandLineAction[] = []; + for (const [ + aliasName, + { actionName, defaultParameters } + ] of internalHeftSession.actionReferencesByAlias) { + const existingAction: CommandLineAction | undefined = this.tryGetAction(aliasName); + if (existingAction) { + throw new Error( + `The alias "${aliasName}" specified in heft.json cannot be used because an action ` + + 'with that name already exists.' + ); + } + const targetAction: CommandLineAction | undefined = this.tryGetAction(actionName); + if (!targetAction) { + throw new Error( + `The action "${actionName}" referred to by alias "${aliasName}" in heft.json could not be found.` + ); + } + aliasActions.push( + new AliasAction({ + terminal: this.globalTerminal, + toolFilename: HEFT_TOOL_FILENAME, + aliasName, + targetAction, + defaultParameters + }) + ); + } + // Add the alias actions. Do this in a second pass to disallow aliases that refer to other aliases. + for (const aliasAction of aliasActions) { + this.addAction(aliasAction); + } + + return await super.executeAsync(args); + } catch (e) { + await this._reportErrorAndSetExitCodeAsync(e as Error); + return false; + } + } + + protected override async onExecuteAsync(): Promise { + try { + const selectedAction: CommandLineAction | undefined = this.selectedAction; + + let commandName: string = ''; + let unaliasedCommandName: string = ''; + + if (selectedAction) { + commandName = selectedAction.actionName; + if (selectedAction instanceof AliasAction) { + unaliasedCommandName = selectedAction.targetAction.actionName; + } else { + unaliasedCommandName = selectedAction.actionName; + } + } + + this._internalHeftSession!.parsedCommandLine = { + commandName, + unaliasedCommandName + }; + await super.onExecuteAsync(); + } catch (e) { + await this._reportErrorAndSetExitCodeAsync(e as Error); + } + + // If we make it here, things are fine and reset the exit code back to 0 + process.exitCode = 0; + } + + private _normalizeCwd(): void { + const buildFolder: string = this._heftConfiguration.buildFolderPath; + const currentCwd: string = process.cwd(); + if (currentCwd !== buildFolder) { + // Update the CWD to the project's build root. Some tools, like Jest, use process.cwd() + this.globalTerminal.writeVerboseLine(`CWD is "${currentCwd}". Normalizing to "${buildFolder}".`); + // If `process.cwd()` and `buildFolder` differ only by casing on Windows, the chdir operation will not fix the casing, which is the entire purpose of the exercise. + // As such, chdir to a different directory first. That directory needs to exist, so use the parent of the current directory. + // This will not work if the current folder is the drive root, but that is a rather exotic case. + process.chdir(__dirname); + process.chdir(buildFolder); + } + } + + private _getPreInitializationArgumentValues( + args: string[] = process.argv + ): IPreInitializationArgumentValues { + if (!this._debugFlag) { + // The `this._debugFlag` parameter (the parameter itself, not its value) + // has not yet been defined. Parameters need to be defined before we + // 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('parameters have not yet been defined.'); + } + + const toolParameters: Set = getToolParameterNamesFromArgs(args); + return { + debug: toolParameters.has(this._debugFlag.longName), + unmanaged: toolParameters.has(this._unmanagedFlag.longName) + }; + } + + private async _reportErrorAndSetExitCodeAsync(error: Error): Promise { + if (!(error instanceof AlreadyReportedError)) { + this.globalTerminal.writeErrorLine(error.toString()); + } + + if (this._debug) { + this.globalTerminal.writeLine(); + this.globalTerminal.writeErrorLine(error.stack!); + } + + 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 new file mode 100644 index 00000000000..71fd1e52af3 --- /dev/null +++ b/apps/heft/src/cli/actions/AliasAction.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 type { ITerminal } from '@rushstack/terminal'; +import { + AliasCommandLineAction, + type IAliasCommandLineActionOptions, + type CommandLineAction +} from '@rushstack/ts-command-line'; + +export interface IAliasActionOptions extends IAliasCommandLineActionOptions { + terminal: ITerminal; +} + +export class AliasAction extends AliasCommandLineAction { + private readonly _toolFilename: string; + private readonly _terminal: ITerminal; + + public constructor(options: IAliasActionOptions) { + super(options); + this._toolFilename = options.toolFilename; + this._terminal = options.terminal; + } + + protected override async onExecuteAsync(): Promise { + const toolFilename: string = this._toolFilename; + const actionName: string = this.actionName; + const targetAction: CommandLineAction = this.targetAction; + const defaultParameters: ReadonlyArray = this.defaultParameters; + const defaultParametersString: string = defaultParameters.join(' '); + + this._terminal.writeLine( + `The "${toolFilename} ${actionName}" alias was expanded to "${toolFilename} ${targetAction.actionName}` + + `${defaultParametersString ? ` ${defaultParametersString}` : ''}".` + ); + + await super.onExecuteAsync(); + } +} diff --git a/apps/heft/src/cli/actions/CleanAction.ts b/apps/heft/src/cli/actions/CleanAction.ts new file mode 100644 index 00000000000..11d1c8e4c2b --- /dev/null +++ b/apps/heft/src/cli/actions/CleanAction.ts @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + CommandLineAction, + type CommandLineFlagParameter, + type CommandLineStringListParameter +} from '@rushstack/ts-command-line'; +import type { ITerminal } from '@rushstack/terminal'; +import { OperationStatus } from '@rushstack/operation-graph'; + +import type { IHeftAction, IHeftActionOptions } from './IHeftAction'; +import type { HeftPhase } from '../../pluginFramework/HeftPhase'; +import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; +import type { MetricsCollector } from '../../metrics/MetricsCollector'; +import type { HeftPhaseSession } from '../../pluginFramework/HeftPhaseSession'; +import type { HeftTaskSession } from '../../pluginFramework/HeftTaskSession'; +import { Constants } from '../../utilities/Constants'; +import { definePhaseScopingParameters, expandPhases } from './RunAction'; +import { deleteFilesAsync, type IDeleteOperation } from '../../plugins/DeleteFilesPlugin'; +import { ensureCliAbortSignal, initializeHeft, runWithLoggingAsync } from '../HeftActionRunner'; + +export class CleanAction extends CommandLineAction implements IHeftAction { + public readonly watch: boolean = false; + private readonly _internalHeftSession: InternalHeftSession; + private readonly _terminal: ITerminal; + private readonly _metricsCollector: MetricsCollector; + private readonly _verboseFlag: CommandLineFlagParameter; + private readonly _toParameter: CommandLineStringListParameter; + private readonly _toExceptParameter: CommandLineStringListParameter; + private readonly _onlyParameter: CommandLineStringListParameter; + private _selectedPhases: ReadonlySet | undefined; + + public constructor(options: IHeftActionOptions) { + super({ + actionName: 'clean', + documentation: 'Clean the project, removing temporary task folders and specified clean paths.', + summary: 'Clean the project, removing temporary task folders and specified clean paths.' + }); + + this._terminal = options.terminal; + this._metricsCollector = options.metricsCollector; + this._internalHeftSession = options.internalHeftSession; + + const { toParameter, toExceptParameter, onlyParameter } = definePhaseScopingParameters(this); + this._toParameter = toParameter; + this._toExceptParameter = toExceptParameter; + this._onlyParameter = onlyParameter; + + this._verboseFlag = this.defineFlagParameter({ + parameterLongName: Constants.verboseParameterLongName, + parameterShortName: Constants.verboseParameterShortName, + description: 'If specified, log information useful for debugging.' + }); + } + + public get selectedPhases(): ReadonlySet { + if (!this._selectedPhases) { + if ( + this._onlyParameter.values.length || + this._toParameter.values.length || + this._toExceptParameter.values.length + ) { + this._selectedPhases = expandPhases( + this._onlyParameter, + this._toParameter, + this._toExceptParameter, + this._internalHeftSession, + this._terminal + ); + } else { + // No selected phases, clean everything + this._selectedPhases = this._internalHeftSession.phases; + } + } + return this._selectedPhases; + } + + protected override async onExecuteAsync(): Promise { + const { heftConfiguration } = this._internalHeftSession; + const abortSignal: AbortSignal = ensureCliAbortSignal(this._terminal); + + // Record this as the start of task execution. + this._metricsCollector.setStartTime(); + initializeHeft(heftConfiguration, this._terminal, this._verboseFlag.value); + await runWithLoggingAsync( + this._cleanFilesAsync.bind(this), + this, + this._internalHeftSession.loggingManager, + this._terminal, + this._metricsCollector, + abortSignal + ); + } + + private async _cleanFilesAsync(): Promise { + const deleteOperations: IDeleteOperation[] = []; + for (const phase of this.selectedPhases) { + // Add the temp folder and cache folder (if requested) for each task + const phaseSession: HeftPhaseSession = this._internalHeftSession.getSessionForPhase(phase); + for (const task of phase.tasks) { + const taskSession: HeftTaskSession = phaseSession.getSessionForTask(task); + deleteOperations.push({ sourcePath: taskSession.tempFolderPath }); + } + // Add the manually specified clean operations + deleteOperations.push(...phase.cleanFiles); + } + + // Delete the files + if (deleteOperations.length) { + const rootFolderPath: string = this._internalHeftSession.heftConfiguration.buildFolderPath; + await deleteFilesAsync(rootFolderPath, deleteOperations, this._terminal); + } + + return deleteOperations.length === 0 ? OperationStatus.NoOp : OperationStatus.Success; + } +} diff --git a/apps/heft/src/cli/actions/IHeftAction.ts b/apps/heft/src/cli/actions/IHeftAction.ts new file mode 100644 index 00000000000..ad4a91468da --- /dev/null +++ b/apps/heft/src/cli/actions/IHeftAction.ts @@ -0,0 +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 { CommandLineAction } from '@rushstack/ts-command-line'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { HeftConfiguration } from '../../configuration/HeftConfiguration'; +import type { MetricsCollector } from '../../metrics/MetricsCollector'; +import type { LoggingManager } from '../../pluginFramework/logging/LoggingManager'; +import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; +import type { HeftPhase } from '../../pluginFramework/HeftPhase'; + +export interface IHeftActionOptions { + readonly internalHeftSession: InternalHeftSession; + readonly heftConfiguration: HeftConfiguration; + readonly terminal: ITerminal; + readonly loggingManager: LoggingManager; + readonly metricsCollector: MetricsCollector; + readonly watch?: boolean; +} + +export interface IHeftAction extends CommandLineAction { + readonly watch: boolean; + readonly selectedPhases: ReadonlySet; +} diff --git a/apps/heft/src/cli/actions/PhaseAction.ts b/apps/heft/src/cli/actions/PhaseAction.ts new file mode 100644 index 00000000000..b3891514529 --- /dev/null +++ b/apps/heft/src/cli/actions/PhaseAction.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 { CommandLineAction } from '@rushstack/ts-command-line'; + +import { HeftActionRunner } from '../HeftActionRunner'; +import { Selection } from '../../utilities/Selection'; +import type { IHeftAction, IHeftActionOptions } from './IHeftAction'; +import type { HeftPhase } from '../../pluginFramework/HeftPhase'; + +export interface IPhaseActionOptions extends IHeftActionOptions { + phase: HeftPhase; +} + +export class PhaseAction extends CommandLineAction implements IHeftAction { + public readonly watch: boolean; + + private readonly _actionRunner: HeftActionRunner; + private readonly _phase: HeftPhase; + private _selectedPhases: Set | undefined; + + public constructor(options: IPhaseActionOptions) { + super({ + actionName: `${options.phase.phaseName}${options.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}` : ''), + summary: + `Runs to the ${options.phase.phaseName} phase, including all transitive dependencies` + + (options.watch ? ', in watch mode.' : '.') + }); + + this.watch = options.watch ?? false; + this._phase = options.phase; + this._actionRunner = new HeftActionRunner({ action: this, ...options }); + this._actionRunner.defineParameters(); + } + + public get selectedPhases(): ReadonlySet { + if (!this._selectedPhases) { + this._selectedPhases = Selection.recursiveExpand( + [this._phase], + (phase: HeftPhase) => phase.dependencyPhases + ); + } + return this._selectedPhases; + } + + 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 new file mode 100644 index 00000000000..6454ea5b901 --- /dev/null +++ b/apps/heft/src/cli/actions/RunAction.ts @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + ScopedCommandLineAction, + type CommandLineParameterProvider, + type CommandLineStringListParameter +} from '@rushstack/ts-command-line'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { Selection } from '../../utilities/Selection'; +import { HeftActionRunner } from '../HeftActionRunner'; +import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; +import type { IHeftAction, IHeftActionOptions } from './IHeftAction'; +import type { HeftPhase } from '../../pluginFramework/HeftPhase'; +import { Constants } from '../../utilities/Constants'; + +export function expandPhases( + onlyParameter: CommandLineStringListParameter, + toParameter: CommandLineStringListParameter, + toExceptParameter: CommandLineStringListParameter, + internalHeftSession: InternalHeftSession, + terminal: ITerminal +): Set { + const onlyPhases: Set = evaluatePhaseParameter(onlyParameter, internalHeftSession, terminal); + const toPhases: Set = evaluatePhaseParameter(toParameter, internalHeftSession, terminal); + const toExceptPhases: Set = evaluatePhaseParameter( + toExceptParameter, + internalHeftSession, + terminal + ); + + const expandFn: (phase: HeftPhase) => ReadonlySet = (phase: HeftPhase) => phase.dependencyPhases; + const selectedPhases: Set = Selection.union( + Selection.recursiveExpand(toPhases, expandFn), + Selection.recursiveExpand(Selection.directDependenciesOf(toExceptPhases, expandFn), expandFn), + onlyPhases + ); + if (selectedPhases.size === 0) { + throw new Error( + 'No phases were selected. Provide at least one phase to the ' + + `${JSON.stringify(Constants.toParameterLongName)}, ` + + `${JSON.stringify(Constants.toExceptParameterLongName)}, or ` + + `${JSON.stringify(Constants.onlyParameterLongName)} parameters.` + ); + } + return selectedPhases; +} + +function evaluatePhaseParameter( + phaseParameter: CommandLineStringListParameter, + internalHeftSession: InternalHeftSession, + terminal: ITerminal +): Set { + const parameterName: string = phaseParameter.longName; + const selection: Set = new Set(); + for (const rawSelector of phaseParameter.values) { + const phase: HeftPhase | undefined = internalHeftSession.phasesByName.get(rawSelector); + if (!phase) { + terminal.writeErrorLine( + `The phase name ${JSON.stringify(rawSelector)} passed to ${JSON.stringify(parameterName)} does ` + + 'not exist in heft.json.' + ); + throw new AlreadyReportedError(); + } + selection.add(phase); + } + return selection; +} + +export interface IScopingParameters { + toParameter: CommandLineStringListParameter; + toExceptParameter: CommandLineStringListParameter; + onlyParameter: CommandLineStringListParameter; +} + +export function definePhaseScopingParameters(action: IHeftAction): IScopingParameters { + return { + toParameter: action.defineStringListParameter({ + parameterLongName: Constants.toParameterLongName, + description: `The phase to ${action.actionName} to, including all transitive dependencies.`, + argumentName: 'PHASE', + parameterGroup: ScopedCommandLineAction.ScopingParameterGroup + }), + toExceptParameter: action.defineStringListParameter({ + parameterLongName: Constants.toExceptParameterLongName, + description: `The phase to ${action.actionName} to (but not include), including all transitive dependencies.`, + argumentName: 'PHASE', + parameterGroup: ScopedCommandLineAction.ScopingParameterGroup + }), + onlyParameter: action.defineStringListParameter({ + parameterLongName: Constants.onlyParameterLongName, + description: `The phase to ${action.actionName}.`, + argumentName: 'PHASE', + parameterGroup: ScopedCommandLineAction.ScopingParameterGroup + }) + }; +} + +export class RunAction extends ScopedCommandLineAction implements IHeftAction { + public readonly watch: boolean; + + private readonly _internalHeftSession: InternalHeftSession; + private readonly _terminal: ITerminal; + private readonly _actionRunner: HeftActionRunner; + private readonly _toParameter: CommandLineStringListParameter; + private readonly _toExceptParameter: CommandLineStringListParameter; + private readonly _onlyParameter: CommandLineStringListParameter; + private _selectedPhases: Set | undefined; + + public constructor(options: IHeftActionOptions) { + super({ + actionName: `run${options.watch ? '-watch' : ''}`, + documentation: `Run a provided selection of Heft phases${options.watch ? ' in watch mode.' : ''}.`, + summary: `Run a provided selection of Heft phases${options.watch ? ' in watch mode.' : ''}.` + }); + + this.watch = options.watch ?? false; + this._terminal = options.terminal; + this._internalHeftSession = options.internalHeftSession; + + const { toParameter, toExceptParameter, onlyParameter } = definePhaseScopingParameters(this); + this._toParameter = toParameter; + this._toExceptParameter = toExceptParameter; + this._onlyParameter = onlyParameter; + + this._actionRunner = new HeftActionRunner({ action: this, ...options }); + } + + public get selectedPhases(): ReadonlySet { + if (!this._selectedPhases) { + this._selectedPhases = expandPhases( + this._onlyParameter, + this._toParameter, + this._toExceptParameter, + this._internalHeftSession, + this._terminal + ); + } + return this._selectedPhases; + } + + protected onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void { + this._actionRunner.defineParameters(scopedParameterProvider); + } + + 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 new file mode 100644 index 00000000000..e6079a8a3f6 --- /dev/null +++ b/apps/heft/src/configuration/HeftConfiguration.ts @@ -0,0 +1,251 @@ +// 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 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'; +import { RigPackageResolver, type IRigPackageResolver } from './RigPackageResolver'; + +/** + * @internal + */ +export interface IHeftConfigurationInitializationOptions { + /** + * The working directory the tool was executed in. + */ + cwd: string; + + /** + * 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 _slashNormalizedBuildFolderPath: string | undefined; + private _projectConfigFolderPath: string | undefined; + private _tempFolderPath: string | undefined; + private _rigConfig: IRigConfig | undefined; + 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 readonly buildFolderPath: string; + + /** + * {@link HeftConfiguration.buildFolderPath} with all path separators converted to forward slashes. + */ + public get slashNormalizedBuildFolderPath(): string { + if (!this._slashNormalizedBuildFolderPath) { + this._slashNormalizedBuildFolderPath = Path.convertToSlashes(this.buildFolderPath); + } + + return this._slashNormalizedBuildFolderPath; + } + + /** + * The path to the project's "config" folder. + */ + public get projectConfigFolderPath(): string { + if (!this._projectConfigFolderPath) { + this._projectConfigFolderPath = path.join(this.buildFolderPath, Constants.projectConfigFolderName); + } + + return this._projectConfigFolderPath; + } + + /** + * The project's temporary folder. + * + * @remarks This folder exists at \/temp. In general, this folder is used to store temporary + * output from tasks under task-specific subfolders, and is not intended to be directly written to. + * Instead, plugins should write to the directory provided by HeftTaskSession.taskTempFolderPath + */ + public get tempFolderPath(): string { + if (!this._tempFolderPath) { + this._tempFolderPath = path.join(this.buildFolderPath, Constants.tempFolderName); + } + + return this._tempFolderPath; + } + + /** + * The rig.json configuration for this project, if present. + */ + public get rigConfig(): IRigConfig { + if (!this._rigConfig) { + throw new InternalError( + 'The rigConfig cannot be accessed until HeftConfiguration.checkForRigAsync() has been called' + ); + } + return this._rigConfig; + } + + /** + * The rig package resolver, which can be used to rig-resolve a requested package. + */ + public get rigPackageResolver(): IRigPackageResolver { + if (!this._rigPackageResolver) { + this._rigPackageResolver = new RigPackageResolver({ + buildFolder: this.buildFolderPath, + projectPackageJson: this.projectPackageJson, + rigConfig: this.rigConfig + }); + } + + return this._rigPackageResolver; + } + + /** + * Terminal instance to facilitate logging. + */ + public readonly globalTerminal: ITerminal; + + /** + * Terminal provider for the provided terminal. + */ + public readonly terminalProvider: ITerminalProvider; + + /** + * The Heft tool's package.json + */ + public get heftPackageJson(): IPackageJson { + return PackageJsonLookup.instance.tryLoadPackageJsonFor(__dirname)!; + } + + /** + * The package.json of the project being built + */ + public get projectPackageJson(): IPackageJson { + return PackageJsonLookup.instance.tryLoadPackageJsonFor(this.buildFolderPath)!; + } + + /** + * 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. + * @internal + */ + public async _checkForRigAsync(): Promise { + if (!this._rigConfig) { + this._rigConfig = await RigConfig.loadForProjectFolderAsync({ + 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 packageJsonPath: string | undefined = PackageJsonLookup.instance.tryGetPackageJsonFilePathFor( + options.cwd + ); + let buildFolderPath: string; + if (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; + } else { + throw new Error('No package.json file found. Are you in a project folder?'); + } + + 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 new file mode 100644 index 00000000000..4bda7fd937a --- /dev/null +++ b/apps/heft/src/configuration/HeftPluginConfiguration.ts @@ -0,0 +1,233 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import { + HeftLifecyclePluginDefinition, + type HeftPluginDefinitionBase, + HeftTaskPluginDefinition, + type IHeftLifecyclePluginDefinitionJson, + type IHeftTaskPluginDefinitionJson +} from './HeftPluginDefinition'; +import type { IHeftConfigurationJsonPluginSpecifier } from '../utilities/CoreConfigFiles'; +import heftPluginSchema from '../schemas/heft-plugin.schema.json'; + +export interface IHeftPluginConfigurationJson { + lifecyclePlugins?: IHeftLifecyclePluginDefinitionJson[]; + taskPlugins?: IHeftTaskPluginDefinitionJson[]; +} + +const HEFT_PLUGIN_CONFIGURATION_FILENAME: 'heft-plugin.json' = 'heft-plugin.json'; + +/** + * 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; + private _taskPluginDefinitions: Set | undefined; + private _taskPluginDefinitionsMap: Map | undefined; + + /** + * The path to the root of the package that contains the heft-plugin.json file. + */ + public readonly packageRoot: string; + + /** + * The package name of the package that contains the heft-plugin.json file. + */ + public readonly packageName: string; + + private constructor( + heftPluginConfigurationJson: IHeftPluginConfigurationJson, + packageRoot: string, + packageName: string + ) { + this._heftPluginConfigurationJson = heftPluginConfigurationJson; + this.packageRoot = packageRoot; + this.packageName = packageName; + this._validate(heftPluginConfigurationJson, packageName); + } + + /** + * Load the heft-plugin.json file from the specified package. + */ + public static async loadFromPackageAsync( + packageRoot: string, + packageName: string + ): Promise { + const resolvedHeftPluginConfigurationJsonFilename: string = `${packageRoot}/${HEFT_PLUGIN_CONFIGURATION_FILENAME}`; + let heftPluginConfigurationPromise: Promise | undefined = + HeftPluginConfiguration._pluginConfigurationPromises.get(packageRoot); + if (!heftPluginConfigurationPromise) { + heftPluginConfigurationPromise = (async () => { + const heftPluginConfigurationJson: IHeftPluginConfigurationJson = await JsonFile.loadAndValidateAsync( + resolvedHeftPluginConfigurationJsonFilename, + HeftPluginConfiguration._jsonSchema + ); + return new HeftPluginConfiguration(heftPluginConfigurationJson, packageRoot, packageName); + })(); + HeftPluginConfiguration._pluginConfigurationPromises.set(packageRoot, heftPluginConfigurationPromise); + } + + return await heftPluginConfigurationPromise; + } + + /** + * Returns a loaded plugin definition for the provided specifier. Specifiers are normally obtained from the + * heft.json file. + */ + public getPluginDefinitionBySpecifier( + pluginSpecifier: IHeftConfigurationJsonPluginSpecifier + ): HeftPluginDefinitionBase { + if (!pluginSpecifier.pluginName) { + const pluginDefinitions: HeftPluginDefinitionBase[] = ([] as HeftPluginDefinitionBase[]).concat( + Array.from(this._getLifecyclePluginDefinitions()), + Array.from(this._getTaskPluginDefinitions()) + ); + // Make an attempt at resolving the plugin without the name by looking for the first plugin + if (pluginDefinitions.length > 1) { + throw new Error( + `The specified plugin package ${JSON.stringify(pluginSpecifier.pluginPackage)} contains ` + + 'multiple plugins. You must specify a plugin name.' + ); + } + return pluginDefinitions[0]; + } else { + // Try resolving to a lifecycle plugin first + const pluginDefinition: HeftPluginDefinitionBase | undefined = + this.tryGetLifecyclePluginDefinitionByName(pluginSpecifier.pluginName) || + this.tryGetTaskPluginDefinitionByName(pluginSpecifier.pluginName); + if (!pluginDefinition) { + throw new Error( + `The specified plugin package ${JSON.stringify(pluginSpecifier.pluginPackage)} does not contain ` + + `a plugin named ${JSON.stringify(pluginSpecifier.pluginName)}.` + ); + } + return pluginDefinition; + } + } + + /** + * Returns if the provided plugin definition is a lifecycle plugin definition. + */ + public isLifecyclePluginDefinition( + pluginDefinition: HeftPluginDefinitionBase + ): pluginDefinition is HeftLifecyclePluginDefinition { + return this._getLifecyclePluginDefinitions().has(pluginDefinition); + } + + /** + * Returns if the provided plugin definition is a task plugin definition. + */ + public isTaskPluginDefinition( + pluginDefinition: HeftPluginDefinitionBase + ): pluginDefinition is HeftTaskPluginDefinition { + return this._getTaskPluginDefinitions().has(pluginDefinition); + } + + /** + * Returns a loaded lifecycle plugin definition for the provided plugin name. If one can't be found, + * returns undefined. + */ + public tryGetLifecyclePluginDefinitionByName( + lifecyclePluginName: string + ): HeftLifecyclePluginDefinition | undefined { + if (!this._lifecyclePluginDefinitionsMap) { + this._lifecyclePluginDefinitionsMap = new Map( + Array.from(this._getLifecyclePluginDefinitions()).map((d: HeftLifecyclePluginDefinition) => [ + d.pluginName, + d + ]) + ); + } + return this._lifecyclePluginDefinitionsMap.get(lifecyclePluginName); + } + + /** + * Returns a loaded task plugin definition for the provided plugin name. If one can't be found, + * returns undefined. + */ + public tryGetTaskPluginDefinitionByName(taskPluginName: string): HeftTaskPluginDefinition | undefined { + if (!this._taskPluginDefinitionsMap) { + this._taskPluginDefinitionsMap = new Map( + Array.from(this._getTaskPluginDefinitions()).map((d: HeftTaskPluginDefinition) => [d.pluginName, d]) + ); + } + return this._taskPluginDefinitionsMap.get(taskPluginName); + } + + private _getLifecyclePluginDefinitions(): ReadonlySet { + if (!this._lifecyclePluginDefinitions) { + this._lifecyclePluginDefinitions = new Set(); + for (const lifecyclePluginDefinitionJson of this._heftPluginConfigurationJson.lifecyclePlugins || []) { + this._lifecyclePluginDefinitions.add( + HeftLifecyclePluginDefinition.loadFromObject({ + heftPluginDefinitionJson: lifecyclePluginDefinitionJson, + packageRoot: this.packageRoot, + packageName: this.packageName + }) + ); + } + } + return this._lifecyclePluginDefinitions; + } + + /** + * Task plugin definitions sourced from the heft-plugin.json file. + */ + private _getTaskPluginDefinitions(): ReadonlySet { + if (!this._taskPluginDefinitions) { + this._taskPluginDefinitions = new Set(); + for (const taskPluginDefinitionJson of this._heftPluginConfigurationJson.taskPlugins || []) { + this._taskPluginDefinitions.add( + HeftTaskPluginDefinition.loadFromObject({ + heftPluginDefinitionJson: taskPluginDefinitionJson, + packageRoot: this.packageRoot, + packageName: this.packageName + }) + ); + } + } + return this._taskPluginDefinitions; + } + + private _validate(heftPluginConfigurationJson: IHeftPluginConfigurationJson, packageName: string): void { + if ( + !heftPluginConfigurationJson.lifecyclePlugins?.length && + !heftPluginConfigurationJson.taskPlugins?.length + ) { + throw new Error( + `The specified plugin package ${JSON.stringify(packageName)} does not contain any plugins.` + ); + } + + // Prevent duplicate plugin names. This is done because parameter scopes default to the plugin name + // when none are provided, and we want to avoid conflicting parameter scopes. Additionally, scoped loggers + // on lifecycle plugins are mapped to "[lifecycle:]", and scoped loggers must be unique. + const lifecyclePluginNames: Set = new Set(); + for (const lifecyclePluginDefinitionJson of heftPluginConfigurationJson.lifecyclePlugins || []) { + if (lifecyclePluginNames.has(lifecyclePluginDefinitionJson.pluginName)) { + throw new Error(`Duplicate plugin name: ${lifecyclePluginDefinitionJson.pluginName}`); + } + lifecyclePluginNames.add(lifecyclePluginDefinitionJson.pluginName); + } + + const taskPluginNames: Set = new Set(); + for (const taskPluginDefinitionJson of heftPluginConfigurationJson.taskPlugins || []) { + // Also check that the name doesn't conflict with the lifecycle plugins + if ( + taskPluginNames.has(taskPluginDefinitionJson.pluginName) || + lifecyclePluginNames.has(taskPluginDefinitionJson.pluginName) + ) { + throw new Error(`Duplicate plugin name: ${taskPluginDefinitionJson.pluginName}`); + } + taskPluginNames.add(taskPluginDefinitionJson.pluginName); + } + } +} diff --git a/apps/heft/src/configuration/HeftPluginDefinition.ts b/apps/heft/src/configuration/HeftPluginDefinition.ts new file mode 100644 index 00000000000..4ce4bd0c19a --- /dev/null +++ b/apps/heft/src/configuration/HeftPluginDefinition.ts @@ -0,0 +1,362 @@ +// 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 { InternalError, JsonSchema } from '@rushstack/node-core-library'; + +import type { IHeftPlugin } from '../pluginFramework/IHeftPlugin'; +import type { IScopedLogger } from '../pluginFramework/logging/ScopedLogger'; +import type { HeftLifecycleSession } from '../pluginFramework/HeftLifecycleSession'; +import type { HeftTaskSession } from '../pluginFramework/HeftTaskSession'; + +/** + * "baseParameter" from heft-plugin.schema.json + * @public + */ +export interface IBaseParameterJson { + /** + * Indicates the kind of syntax for this command-line parameter. + */ + parameterKind: 'choice' | 'choiceList' | 'flag' | 'integer' | 'integerList' | 'string' | 'stringList'; + /** + * The name of the parameter (e.g. \"--verbose\"). This is a required field. + */ + longName: string; + /** + * An optional short form of the parameter (e.g. \"-v\" instead of \"--verbose\"). + */ + shortName?: string; + /** + * A detailed description of the parameter, which appears when requesting help for the command (e.g. \"rush --help my-command\"). + */ + description: string; + /** + * If true, then this parameter must be included on the command line. + */ + required?: boolean; +} + +/** + * Part of "choiceParameter" from command-line.schema.json + * @public + */ +export interface IChoiceParameterAlternativeJson { + /** + * A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\". + */ + name: string; + /** + * A detailed description for the alternative that will be shown in the command-line help. + */ + description: string; +} + +/** + * A custom command-line parameter whose list of arguments must be chosen from a list of allowable alternatives. + * @public + */ +export interface IChoiceListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a choice list parameter. + */ + parameterKind: 'choiceList'; + /** + * A list of alternative argument values that can be chosen for this parameter. + */ + alternatives: IChoiceParameterAlternativeJson[]; +} + +/** + * A custom command-line parameter whose argument must be chosen from a list of allowable alternatives. + * @public + */ +export interface IChoiceParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a choice parameter. + */ + parameterKind: 'choice'; + /** + * A list of alternative argument values that can be chosen for this parameter. + */ + alternatives: IChoiceParameterAlternativeJson[]; + /** + * If the parameter is omitted from the command line, this value will be inserted by default. + */ + defaultValue?: string; +} + +/** + * A custom command-line parameter whose presence acts as an on/off switch. + * @public + */ +export interface IFlagParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a flag (boolean) parameter. + */ + parameterKind: 'flag'; +} + +/** + * A custom command-line parameter whose list of values are interpreted as integers. + * @public + */ +export interface IIntegerListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is an integer list parameter. + */ + parameterKind: 'integerList'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} + +/** + * A custom command-line parameter whose value is interpreted as an integer. + * @public + */ +export interface IIntegerParameterJson extends IBaseParameterJson { + /** + * Denotes that this is an integer parameter. + */ + parameterKind: 'integer'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; + /** + * If the parameter is omitted from the command line, this value will be inserted by default. + */ + defaultValue?: number; +} + +/** + * A custom command-line parameter whose list of values are interpreted as strings. + * @public + */ +export interface IStringListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a string list parameter. + */ + parameterKind: 'stringList'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} + +/** + * A custom command-line parameter whose value is interpreted as a string. + * @public + */ +export interface IStringParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a string parameter. + */ + parameterKind: 'string'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; + /** + * If the parameter is omitted from the command line, this value will be inserted by default. + */ + defaultValue?: string; +} + +export type IParameterJson = + | IChoiceListParameterJson + | IChoiceParameterJson + | IFlagParameterJson + | IIntegerListParameterJson + | IIntegerParameterJson + | IStringListParameterJson + | IStringParameterJson; + +export interface IHeftPluginDefinitionJson { + pluginName: string; + entryPoint: string; + optionsSchema?: string; + parameterScope?: string; + parameters?: IParameterJson[]; +} + +export interface IHeftLifecyclePluginDefinitionJson extends IHeftPluginDefinitionJson {} + +export interface IHeftTaskPluginDefinitionJson extends IHeftPluginDefinitionJson {} + +export interface IHeftPluginDefinitionOptions { + heftPluginDefinitionJson: IHeftPluginDefinitionJson; + packageName: string; + packageRoot: string; +} + +export abstract class HeftPluginDefinitionBase { + private _heftPluginDefinitionJson: IHeftPluginDefinitionJson; + private _pluginPackageName: string; + private _resolvedEntryPoint: string; + private _optionsSchema: JsonSchema | undefined; + + protected constructor(options: IHeftPluginDefinitionOptions) { + this._heftPluginDefinitionJson = options.heftPluginDefinitionJson; + this._pluginPackageName = options.packageName; + this._resolvedEntryPoint = path.resolve(options.packageRoot, this._heftPluginDefinitionJson.entryPoint); + + // Ensure that the plugin parameters are unique + const seenParameters: Set = new Set(); + for (const parameter of this.pluginParameters) { + if (seenParameters.has(parameter.longName)) { + throw new Error( + `Parameter ${JSON.stringify(parameter.longName)} is defined multiple times by the providing ` + + `plugin ${JSON.stringify(this.pluginName)} in package ` + + `${JSON.stringify(this.pluginPackageName)}.` + ); + } + seenParameters.add(parameter.longName); + } + + // Unfortunately loading the schema is a synchronous process. + if (options.heftPluginDefinitionJson.optionsSchema) { + const resolvedSchemaPath: string = path.resolve( + options.packageRoot, + options.heftPluginDefinitionJson.optionsSchema + ); + this._optionsSchema = JsonSchema.fromFile(resolvedSchemaPath); + } + } + + /** + * The package name containing the target plugin. + */ + public get pluginPackageName(): string { + return this._pluginPackageName; + } + + /** + * The name of the target plugin. + */ + public get pluginName(): string { + return this._heftPluginDefinitionJson.pluginName; + } + + /** + * The resolved entry point to the plugin. + */ + public get entryPoint(): string { + return this._resolvedEntryPoint; + } + + /** + * The scope for all parameters defined by this plugin. + */ + public get pluginParameterScope(): string { + // Default to the plugin name for the parameter scope. Plugin names should be unique within any run + // of Heft. Additionally, plugin names have the same naming restrictions as parameter scopes so can + // be used without modification. + return this._heftPluginDefinitionJson.parameterScope || this.pluginName; + } + + /** + * The parameters that are defined for this plugin. + */ + public get pluginParameters(): ReadonlyArray { + return this._heftPluginDefinitionJson.parameters || []; + } + + /** + * Load the plugin associated with the definition. + */ + public async loadPluginAsync(logger: IScopedLogger): Promise { + // Do not memoize the plugin here, since we want a new instance of the plugin each time it is loaded + // from the definition + let heftPlugin: IHeftPlugin | undefined; + const entryPointPath: string = this.entryPoint; + try { + const loadedPluginModule: (new () => IHeftPlugin) | { default: new () => IHeftPlugin } = await import( + entryPointPath + ); + const heftPluginConstructor: new () => IHeftPlugin = + (loadedPluginModule as { default: new () => IHeftPlugin }).default || loadedPluginModule; + heftPlugin = new heftPluginConstructor(); + } catch (e: unknown) { + const error: Error = e as Error; + if (error.message === 'heftPluginConstructor is not a constructor') { + // Common error scenario, give a more helpful error message + throw new Error( + `Could not load plugin from "${entryPointPath}": The target module does not ` + + 'export a plugin class with a parameterless constructor.' + ); + } else { + throw new InternalError(`Could not load plugin from "${entryPointPath}": ${error}`); + } + } + + if (!heftPlugin) { + throw new InternalError( + `Plugin ${JSON.stringify(this.pluginName)} loaded from "${entryPointPath}" is null or undefined.` + ); + } + + logger.terminal.writeVerboseLine(`Loaded plugin from "${entryPointPath}"`); + + if (typeof heftPlugin.apply !== 'function') { + throw new InternalError( + `The plugin ${JSON.stringify(this.pluginName)} loaded from "${entryPointPath}" ` + + 'doesn\'t define an "apply" function.' + ); + } + + return heftPlugin; + } + + /** + * Validate the provided plugin options against the plugin's options schema, if one is provided. + */ + public validateOptions(options: unknown): void { + if (this._optionsSchema) { + try { + this._optionsSchema.validateObject(options || {}, ''); + } catch (error) { + throw new Error( + `Provided options for plugin ${JSON.stringify(this.pluginName)} did not match the provided ` + + `plugin schema.\n${error}` + ); + } + } + } +} + +export class HeftLifecyclePluginDefinition extends HeftPluginDefinitionBase { + /** + * Load a lifecycle plugin definition given the provided plugin definition options. + */ + public static loadFromObject(options: IHeftPluginDefinitionOptions): HeftLifecyclePluginDefinition { + return new HeftLifecyclePluginDefinition(options); + } + + /** + * {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync} + * @override + */ + public loadPluginAsync(logger: IScopedLogger): Promise> { + return super.loadPluginAsync(logger); + } +} + +export class HeftTaskPluginDefinition extends HeftPluginDefinitionBase { + /** + * Load a task plugin definition given the provided plugin definition options. + */ + public static loadFromObject(options: IHeftPluginDefinitionOptions): HeftTaskPluginDefinition { + return new HeftTaskPluginDefinition(options); + } + + /** + * {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync} + * @override + */ + public loadPluginAsync(logger: IScopedLogger): Promise> { + return super.loadPluginAsync(logger); + } +} diff --git a/apps/heft/src/configuration/RigPackageResolver.ts b/apps/heft/src/configuration/RigPackageResolver.ts new file mode 100644 index 00000000000..03a70db6dc4 --- /dev/null +++ b/apps/heft/src/configuration/RigPackageResolver.ts @@ -0,0 +1,155 @@ +// 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 { + PackageJsonLookup, + Import, + type INodePackageJson, + type IPackageJson +} from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import type { IRigConfig } from '@rushstack/rig-package'; + +/** + * Rig resolves requested tools from the project's Heft rig. + * + * @remarks For more information on rig resolution, see + * https://rushstack.io/pages/heft/rig_packages/#3-riggable-dependencies + * + * @public + */ +export interface IRigPackageResolver { + resolvePackageAsync(packageName: string, terminal: ITerminal): Promise; +} + +/** + * Options for creating a RigPackageResolver. + */ +export interface IRigPackageResolverOptions { + buildFolder: string; + projectPackageJson: IPackageJson; + rigConfig: IRigConfig; +} + +/** + * Rig resolves requested tools from the project's Heft rig. + */ +export class RigPackageResolver implements IRigPackageResolver { + private readonly _buildFolder: string; + private readonly _projectPackageJson: IPackageJson; + private readonly _rigConfig: IRigConfig; + private readonly _packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + private readonly _resolverCache: Map> = new Map(); + + public constructor(options: IRigPackageResolverOptions) { + this._buildFolder = options.buildFolder; + this._projectPackageJson = options.projectPackageJson; + this._rigConfig = options.rigConfig; + } + + /** + * Rig resolve the path to a specific package. + * + * The following rules will apply when rig resolving a package: + * - If the local project has a devDependency (not regular or peer dependency) on the tool, + * that has highest precedence. + * - OTHERWISE if there is a rig.json file, then look at the rig's package.json. Does it have a + * regular dependency (not dev or peer dependency) on the tool? If yes, then + * resolve the tool from the rig package folder. + * - OTHERWISE try to resolve it from the current project. + */ + public async resolvePackageAsync(packageName: string, terminal: ITerminal): Promise { + const buildFolder: string = this._buildFolder; + const projectFolder: string | undefined = this._packageJsonLookup.tryGetPackageFolderFor(buildFolder); + if (!projectFolder) { + throw new Error(`Unable to find a package.json file for "${buildFolder}".`); + } + + const cacheKey: string = `${projectFolder};${packageName}`; + let resolutionPromise: Promise | undefined = this._resolverCache.get(cacheKey); + if (!resolutionPromise) { + resolutionPromise = this._resolvePackageInnerAsync(packageName, terminal); + this._resolverCache.set(cacheKey, resolutionPromise); + } + + return await resolutionPromise; + } + + private async _resolvePackageInnerAsync(toolPackageName: string, terminal: ITerminal): Promise { + // See if the project has a devDependency on the package + if ( + this._projectPackageJson.devDependencies && + this._projectPackageJson.devDependencies[toolPackageName] + ) { + try { + const resolvedPackageFolder: string = Import.resolvePackage({ + packageName: toolPackageName, + baseFolderPath: this._buildFolder + }); + terminal.writeVerboseLine( + `Resolved ${JSON.stringify(toolPackageName)} as a direct devDependency of the project.` + ); + return resolvedPackageFolder; + } catch (e) { + throw new Error( + `${JSON.stringify(toolPackageName)} is listed as a direct devDependency of the project, but ` + + 'could not be resolved. Have dependencies been installed?' + ); + } + } + + // See if the project rig has a regular dependency on the package + const rigConfiguration: IRigConfig = this._rigConfig; + if (rigConfiguration.rigFound) { + const rigFolder: string = rigConfiguration.getResolvedProfileFolder(); + const rigPackageJsonPath: string | undefined = + this._packageJsonLookup.tryGetPackageJsonFilePathFor(rigFolder); + if (!rigPackageJsonPath) { + throw new Error( + 'Unable to resolve the package.json file for the ' + + `${JSON.stringify(rigConfiguration.rigPackageName)} rig package.` + ); + } + const rigPackageJson: INodePackageJson = + this._packageJsonLookup.loadNodePackageJson(rigPackageJsonPath); + if (rigPackageJson.dependencies && rigPackageJson.dependencies[toolPackageName]) { + try { + const resolvedPackageFolder: string = Import.resolvePackage({ + packageName: toolPackageName, + baseFolderPath: path.dirname(rigPackageJsonPath) + }); + terminal.writeVerboseLine( + `Resolved ${JSON.stringify(toolPackageName)} as a dependency of the ` + + `${JSON.stringify(rigConfiguration.rigPackageName)} rig package.` + ); + return resolvedPackageFolder; + } catch (e) { + throw new Error( + `${JSON.stringify(toolPackageName)} is listed as a dependency of the ` + + `${JSON.stringify(rigConfiguration.rigPackageName)} rig package, but could not be resolved. ` + + 'Have dependencies been installed?' + ); + } + } + } + + // Last attempt, try to resolve it from the current project using node resolution + try { + const resolvedPackageFolder: string = Import.resolvePackage({ + packageName: toolPackageName, + baseFolderPath: this._buildFolder + }); + terminal.writeVerboseLine( + `Resolved ${JSON.stringify(toolPackageName)} from "${resolvedPackageFolder}".` + ); + return resolvedPackageFolder; + } catch (e) { + throw new Error( + `Unable to resolve ${JSON.stringify(toolPackageName)}. For more information on riggable ` + + 'dependency resolution, see https://rushstack.io/pages/heft/rig_packages/#3-riggable-dependencies' + ); + } + } +} 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 new file mode 100644 index 00000000000..0c6006dfc8c --- /dev/null +++ b/apps/heft/src/index.ts @@ -0,0 +1,91 @@ +// 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 + * web applications, Node.js services, command-line tools, libraries, and more. + * + * @packageDocumentation + */ + +import type * as ConfigurationFile from './configuration/types'; +export type { ConfigurationFile }; + +export { + HeftConfiguration, + type IHeftConfigurationInitializationOptions as _IHeftConfigurationInitializationOptions +} from './configuration/HeftConfiguration'; + +export type { IRigPackageResolver } from './configuration/RigPackageResolver'; + +export type { IHeftPlugin, IHeftTaskPlugin, IHeftLifecyclePlugin } from './pluginFramework/IHeftPlugin'; + +export type { IHeftParameters, IHeftDefaultParameters } from './pluginFramework/HeftParameterManager'; + +export type { + IHeftLifecycleSession, + IHeftLifecycleHooks, + IHeftLifecycleCleanHookOptions, + IHeftLifecycleToolStartHookOptions, + IHeftLifecycleToolFinishHookOptions, + IHeftTaskStartHookOptions, + IHeftTaskFinishHookOptions, + IHeftPhaseStartHookOptions, + IHeftPhaseFinishHookOptions +} from './pluginFramework/HeftLifecycleSession'; + +export type { + IHeftParsedCommandLine, + IHeftTaskSession, + IHeftTaskHooks, + IHeftTaskFileOperations, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions +} from './pluginFramework/HeftTaskSession'; + +export type { ICopyOperation, IIncrementalCopyOperation } from './plugins/CopyFilesPlugin'; + +export type { IDeleteOperation } from './plugins/DeleteFilesPlugin'; + +export type { IRunScript, IRunScriptOptions } from './plugins/RunScriptPlugin'; + +export type { IFileSelectionSpecifier, IGlobOptions, GlobFn, WatchGlobFn } from './plugins/FileGlobSpecifier'; + +export type { + IWatchedFileState, + IWatchFileSystem, + ReaddirDirentCallback, + ReaddirStringCallback, + StatCallback, + IReaddirOptions +} from './utilities/WatchFileSystemAdapter'; + +export { + type IHeftRecordMetricsHookOptions, + type IMetricsData, + type IPerformanceData as _IPerformanceData, + MetricsCollector as _MetricsCollector +} from './metrics/MetricsCollector'; + +export type { IScopedLogger } from './pluginFramework/logging/ScopedLogger'; + +// Re-export types required to use custom command-line parameters +export type { + CommandLineParameter, + CommandLineChoiceListParameter, + CommandLineChoiceParameter, + CommandLineFlagParameter, + CommandLineIntegerListParameter, + CommandLineIntegerParameter, + 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/metrics/MetricsCollector.ts b/apps/heft/src/metrics/MetricsCollector.ts new file mode 100644 index 00000000000..b7f6352387d --- /dev/null +++ b/apps/heft/src/metrics/MetricsCollector.ts @@ -0,0 +1,171 @@ +// 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 { performance } from 'node:perf_hooks'; + +import { AsyncParallelHook } from 'tapable'; + +import { InternalError } from '@rushstack/node-core-library'; + +/** + * @public + */ +export interface IMetricsData { + /** + * The command that was executed. + */ + command: string; + + /** + * Whether or not the command ran into errors + */ + encounteredError?: boolean; + + /** + * The total execution duration of all user-defined tasks from `heft.json`, in milliseconds. + * This metric is for measuring the cumulative time spent on the underlying build steps for a project. + * If running in watch mode, this will be the duration of the most recent incremental build. + */ + taskTotalExecutionMs: number; + + /** + * The total duration before Heft started executing user-defined tasks, in milliseconds. + * This metric is for tracking the contribution of Heft itself to total build duration. + */ + bootDurationMs: number; + + /** + * How long the process has been alive, in milliseconds. + * This metric is for watch mode, to analyze how long developers leave individual Heft sessions running. + */ + totalUptimeMs: number; + + /** + * The name of the operating system provided by NodeJS. + */ + machineOs: string; + + /** + * The processor's architecture. + */ + machineArch: string; + + /** + * The number of processor cores. + */ + machineCores: number; + + /** + * The processor's model name. + */ + machineProcessor: string; + + /** + * The total amount of memory the machine has, in megabytes. + */ + machineTotalMemoryMB: number; + + /** + * A map of commandline parameter names to their effective values + */ + commandParameters: Record; +} + +/** + * @public + */ +export interface IHeftRecordMetricsHookOptions { + /** + * @public + */ + metricName: string; + + /** + * @public + */ + metricData: IMetricsData; +} + +/** + * @internal + */ +export interface IPerformanceData { + taskTotalExecutionMs: number; + encounteredError?: boolean; +} + +/** + * @internal + * A simple performance metrics collector. A plugin is required to pipe data anywhere. + */ +export class MetricsCollector { + public readonly recordMetricsHook: AsyncParallelHook = + new AsyncParallelHook(['recordMetricsHookOptions']); + + private _bootDurationMs: number | undefined; + private _startTimeMs: number | undefined; + + /** + * Start metrics log timer. + */ + public setStartTime(): void { + if (this._bootDurationMs === undefined) { + // Only set this once. This is for tracking boot overhead. + this._bootDurationMs = process.uptime() * 1000; + } + this._startTimeMs = performance.now(); + } + + /** + * Record metrics to the installed plugin(s). + * + * @param command - Describe the user command, e.g. `start` or `build` + * @param parameterMap - Optional map of parameters to their values + * @param performanceData - Optional performance data + */ + public async recordAsync( + command: string, + performanceData?: Partial, + parameters?: Record + ): Promise { + const { _bootDurationMs, _startTimeMs } = this; + if (_bootDurationMs === undefined || _startTimeMs === undefined) { + throw new InternalError('MetricsCollector has not been initialized with setStartTime() yet'); + } + + if (!command) { + throw new InternalError('The command name must be specified.'); + } + + const filledPerformanceData: IPerformanceData = { + taskTotalExecutionMs: performance.now() - _startTimeMs, + ...(performanceData || {}) + }; + + const { taskTotalExecutionMs } = filledPerformanceData; + + const cpus: os.CpuInfo[] = os.cpus(); + + const metricData: IMetricsData = { + command: command, + encounteredError: filledPerformanceData.encounteredError, + bootDurationMs: _bootDurationMs, + taskTotalExecutionMs: taskTotalExecutionMs, + totalUptimeMs: process.uptime() * 1000, + machineOs: process.platform, + machineArch: process.arch, + 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 || {} + }; + + await this.recordMetricsHook.promise({ + metricName: 'inner_loop_heft', + metricData + }); + } +} diff --git a/apps/heft/src/operations/runners/PhaseOperationRunner.ts b/apps/heft/src/operations/runners/PhaseOperationRunner.ts new file mode 100644 index 00000000000..f6f1ba3ed0d --- /dev/null +++ b/apps/heft/src/operations/runners/PhaseOperationRunner.ts @@ -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 { + type IOperationRunner, + type IOperationRunnerContext, + OperationStatus +} from '@rushstack/operation-graph'; + +import { deleteFilesAsync, type IDeleteOperation } from '../../plugins/DeleteFilesPlugin'; +import type { HeftPhase } from '../../pluginFramework/HeftPhase'; +import type { HeftPhaseSession } from '../../pluginFramework/HeftPhaseSession'; +import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; + +export interface IPhaseOperationRunnerOptions { + internalHeftSession: InternalHeftSession; + phase: HeftPhase; +} + +export class PhaseOperationRunner implements IOperationRunner { + public readonly silent: boolean = true; + + private readonly _options: IPhaseOperationRunnerOptions; + private _isClean: boolean = false; + + public get name(): string { + return `Phase ${JSON.stringify(this._options.phase.phaseName)}`; + } + + public constructor(options: IPhaseOperationRunnerOptions) { + this._options = options; + } + + public async executeAsync(context: IOperationRunnerContext): Promise { + const { internalHeftSession, phase } = this._options; + const { clean } = internalHeftSession.parameterManager.defaultParameters; + + // Load and apply the plugins for this phase only + const phaseSession: HeftPhaseSession = internalHeftSession.getSessionForPhase(phase); + const { phaseLogger, cleanLogger } = phaseSession; + await phaseSession.applyPluginsAsync(phaseLogger.terminal); + + if (this._isClean || !clean) { + return OperationStatus.NoOp; + } + + // Run the clean hook + const startTime: number = performance.now(); + + // Grab the additional clean operations from the phase + cleanLogger.terminal.writeVerboseLine('Starting clean'); + const deleteOperations: IDeleteOperation[] = Array.from(phase.cleanFiles); + + // Delete all temp folders for tasks by default + const tempFolderGlobs: string[] = [ + /* heft@>0.60.0 */ phase.phaseName, + /* heft@<=0.60.0 */ `${phase.phaseName}.*` + ]; + deleteOperations.push({ + sourcePath: internalHeftSession.heftConfiguration.tempFolderPath, + includeGlobs: tempFolderGlobs + }); + + // Delete the files if any were specified + if (deleteOperations.length) { + const rootFolderPath: string = internalHeftSession.heftConfiguration.buildFolderPath; + await deleteFilesAsync(rootFolderPath, deleteOperations, cleanLogger.terminal); + } + + // Ensure we only run the clean operation once + this._isClean = true; + + cleanLogger.terminal.writeVerboseLine(`Finished clean (${performance.now() - startTime}ms)`); + + // Return success and allow for the TaskOperationRunner to execute tasks + return OperationStatus.Success; + } +} diff --git a/apps/heft/src/operations/runners/TaskOperationRunner.ts b/apps/heft/src/operations/runners/TaskOperationRunner.ts new file mode 100644 index 00000000000..5cdd397d9b4 --- /dev/null +++ b/apps/heft/src/operations/runners/TaskOperationRunner.ts @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; +import { + copyFilesAsync, + type ICopyOperation, + asAbsoluteCopyOperation, + asRelativeCopyOperation +} from '../../plugins/CopyFilesPlugin'; +import { deleteFilesAsync } from '../../plugins/DeleteFilesPlugin'; +import type { + HeftTaskSession, + IHeftTaskFileOperations, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions +} from '../../pluginFramework/HeftTaskSession'; +import type { HeftPhaseSession } from '../../pluginFramework/HeftPhaseSession'; +import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; +import { watchGlobAsync, type IGlobOptions } from '../../plugins/FileGlobSpecifier'; +import { + type IWatchedFileState, + type IWatchFileSystem, + WatchFileSystemAdapter +} from '../../utilities/WatchFileSystemAdapter'; + +export interface ITaskOperationRunnerOptions { + internalHeftSession: InternalHeftSession; + task: HeftTask; +} + +/** + * Log out a start message, run a provided function, and log out an end message + */ +export async function runAndMeasureAsync( + fn: () => Promise, + startMessageFn: () => string, + endMessageFn: () => string, + logFn: (message: string) => void +): Promise { + logFn(startMessageFn()); + const startTime: number = performance.now(); + try { + return await fn(); + } finally { + const endTime: number = performance.now(); + logFn(`${endMessageFn()} (${endTime - startTime}ms)`); + } +} + +export class TaskOperationRunner implements IOperationRunner { + private readonly _options: ITaskOperationRunnerOptions; + + private _fileOperations: IHeftTaskFileOperations | undefined = undefined; + private _copyConfigHash: string | undefined; + private _watchFileSystemAdapter: WatchFileSystemAdapter | undefined = undefined; + + public readonly silent: boolean = false; + + public get name(): string { + const { taskName, parentPhase } = this._options.task; + return `Task ${JSON.stringify(taskName)} of phase ${JSON.stringify(parentPhase.phaseName)}`; + } + + public constructor(options: ITaskOperationRunnerOptions) { + this._options = options; + } + + public async executeAsync(context: IOperationRunnerContext): Promise { + const { internalHeftSession, task } = this._options; + const { parentPhase } = task; + const phaseSession: HeftPhaseSession = internalHeftSession.getSessionForPhase(parentPhase); + const taskSession: HeftTaskSession = phaseSession.getSessionForTask(task); + return await this._executeTaskAsync(context, taskSession); + } + + private async _executeTaskAsync( + context: IOperationRunnerContext, + taskSession: HeftTaskSession + ): Promise { + const { abortSignal, requestRun } = context; + const { hooks, logger } = taskSession; + + // Need to clear any errors or warnings from the previous invocation, particularly + // if this is an immediate rerun + logger.resetErrorsAndWarnings(); + + const rootFolderPath: string = this._options.internalHeftSession.heftConfiguration.buildFolderPath; + const isWatchMode: boolean = taskSession.parameters.watch && !!requestRun; + + const { terminal } = logger; + + // Exit the task early if cancellation is requested + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + if (!this._fileOperations && hooks.registerFileOperations.isUsed()) { + const fileOperations: IHeftTaskFileOperations = await hooks.registerFileOperations.promise({ + copyOperations: new Set(), + deleteOperations: new Set() + }); + + let copyConfigHash: string | undefined; + const { copyOperations } = fileOperations; + if (copyOperations.size > 0) { + // Do this here so that we only need to do it once for each Heft invocation + const hasher: Hash | undefined = createHash('sha256'); + const absolutePathCopyOperations: Set = new Set(); + for (const copyOperation of fileOperations.copyOperations) { + // The paths in the `fileOperations` object may be either absolute or relative + // For execution we need absolute paths. + const absoluteOperation: ICopyOperation = asAbsoluteCopyOperation(rootFolderPath, copyOperation); + absolutePathCopyOperations.add(absoluteOperation); + + // For portability of the hash we need relative paths. + const portableCopyOperation: ICopyOperation = asRelativeCopyOperation( + rootFolderPath, + absoluteOperation + ); + hasher.update(JSON.stringify(portableCopyOperation)); + } + fileOperations.copyOperations = absolutePathCopyOperations; + copyConfigHash = hasher.digest('base64'); + } + + this._fileOperations = fileOperations; + this._copyConfigHash = copyConfigHash; + } + + const shouldRunIncremental: boolean = isWatchMode && hooks.runIncremental.isUsed(); + let watchFileSystemAdapter: WatchFileSystemAdapter | undefined; + const getWatchFileSystemAdapter = (): WatchFileSystemAdapter => { + if (!watchFileSystemAdapter) { + watchFileSystemAdapter = this._watchFileSystemAdapter ||= new WatchFileSystemAdapter(); + watchFileSystemAdapter.setBaseline(); + } + return watchFileSystemAdapter; + }; + + const shouldRun: boolean = hooks.run.isUsed() || shouldRunIncremental; + if (!shouldRun && !this._fileOperations) { + terminal.writeVerboseLine('Task execution skipped, no implementation provided'); + return OperationStatus.NoOp; + } + + const runResult: OperationStatus = shouldRun + ? await runAndMeasureAsync( + async (): Promise => { + // Create the options and provide a utility method to obtain paths to copy + const runHookOptions: IHeftTaskRunHookOptions = { + abortSignal, + globAsync: glob + }; + + // Run the plugin run hook + try { + if (shouldRunIncremental) { + const runIncrementalHookOptions: IHeftTaskRunIncrementalHookOptions = { + ...runHookOptions, + watchGlobAsync: ( + pattern: string | string[], + options: IGlobOptions = {} + ): Promise> => { + return watchGlobAsync(pattern, { + ...options, + fs: getWatchFileSystemAdapter() + }); + }, + get watchFs(): IWatchFileSystem { + return getWatchFileSystemAdapter(); + }, + requestRun: requestRun! + }; + await hooks.runIncremental.promise(runIncrementalHookOptions); + } else { + await hooks.run.promise(runHookOptions); + } + } catch (e) { + // Log out using the task logger, and return an error status + if (!(e instanceof AlreadyReportedError)) { + logger.emitError(e as Error); + } + return OperationStatus.Failure; + } + + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + return OperationStatus.Success; + }, + () => `Starting ${shouldRunIncremental ? 'incremental ' : ''}task execution`, + () => { + const finishedWord: string = abortSignal.aborted ? 'Aborted' : 'Finished'; + return `${finishedWord} ${shouldRunIncremental ? 'incremental ' : ''}task execution`; + }, + terminal.writeVerboseLine.bind(terminal) + ) + : // This branch only occurs if only file operations are defined. + OperationStatus.Success; + + if (this._fileOperations) { + const { copyOperations, deleteOperations } = this._fileOperations; + const copyConfigHash: string | undefined = this._copyConfigHash; + + await Promise.all([ + copyConfigHash + ? copyFilesAsync( + copyOperations, + logger.terminal, + `${taskSession.tempFolderPath}/file-copy.json`, + copyConfigHash, + isWatchMode ? getWatchFileSystemAdapter() : undefined + ) + : Promise.resolve(), + deleteOperations.size > 0 + ? deleteFilesAsync(rootFolderPath, deleteOperations, logger.terminal) + : Promise.resolve() + ]); + } + + if (watchFileSystemAdapter) { + if (!requestRun) { + throw new InternalError(`watchFileSystemAdapter was initialized but requestRun is not defined!`); + } + watchFileSystemAdapter.watch(requestRun); + } + + // Even if the entire process has completed, we should mark the operation as cancelled if + // cancellation has been requested. + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + if (logger.hasErrors) { + return OperationStatus.Failure; + } + + return runResult; + } +} diff --git a/apps/heft/src/pluginFramework/HeftLifecycle.ts b/apps/heft/src/pluginFramework/HeftLifecycle.ts new file mode 100644 index 00000000000..b762e23f238 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftLifecycle.ts @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AsyncParallelHook, SyncHook } from 'tapable'; + +import { InternalError } from '@rushstack/node-core-library'; + +import { HeftPluginConfiguration } from '../configuration/HeftPluginConfiguration'; +import { HeftPluginHost } from './HeftPluginHost'; +import type { InternalHeftSession } from './InternalHeftSession'; +import type { IHeftConfigurationJsonPluginSpecifier } from '../utilities/CoreConfigFiles'; +import type { + HeftLifecyclePluginDefinition, + HeftPluginDefinitionBase +} from '../configuration/HeftPluginDefinition'; +import type { IHeftLifecyclePlugin, IHeftPlugin } from './IHeftPlugin'; +import { + HeftLifecycleSession, + type IHeftLifecycleCleanHookOptions, + type IHeftLifecycleHooks, + type IHeftLifecycleToolStartHookOptions, + type IHeftLifecycleToolFinishHookOptions, + type IHeftLifecycleSession, + type IHeftTaskStartHookOptions, + type IHeftTaskFinishHookOptions, + type IHeftPhaseStartHookOptions, + type IHeftPhaseFinishHookOptions +} from './HeftLifecycleSession'; +import type { ScopedLogger } from './logging/ScopedLogger'; + +export interface IHeftLifecycleContext { + lifecycleSession?: HeftLifecycleSession; + pluginOptions?: object; +} + +export class HeftLifecycle extends HeftPluginHost { + private readonly _internalHeftSession: InternalHeftSession; + private readonly _lifecyclePluginSpecifiers: IHeftConfigurationJsonPluginSpecifier[]; + private readonly _lifecycleHooks: IHeftLifecycleHooks; + private readonly _lifecycleContextByDefinition: Map = + new Map(); + private readonly _lifecyclePluginsByDefinition: Map< + HeftLifecyclePluginDefinition, + IHeftLifecyclePlugin + > = new Map(); + private _lifecycleLogger: ScopedLogger | undefined; + + private _isInitialized: boolean = false; + + public get hooks(): IHeftLifecycleHooks { + return this._lifecycleHooks; + } + + public get pluginDefinitions(): Iterable { + if (!this._isInitialized) { + throw new InternalError( + 'HeftLifecycle.ensureInitializedAsync() must be called before accessing HeftLifecycle.pluginDefinitions.' + ); + } + return this._lifecycleContextByDefinition.keys(); + } + + public constructor( + internalHeftSession: InternalHeftSession, + lifecyclePluginSpecifiers: IHeftConfigurationJsonPluginSpecifier[] + ) { + super(); + this._internalHeftSession = internalHeftSession; + this._lifecyclePluginSpecifiers = lifecyclePluginSpecifiers; + + this._lifecycleHooks = { + clean: new AsyncParallelHook(), + toolStart: new AsyncParallelHook(), + toolFinish: new AsyncParallelHook(), + recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook, + taskStart: new SyncHook(['task']), + taskFinish: new SyncHook(['task']), + phaseStart: new SyncHook(['phase']), + phaseFinish: new SyncHook(['phase']) + }; + } + + protected async applyPluginsInternalAsync(): Promise { + await this.ensureInitializedAsync(); + + // Load up all plugins concurrently + const loadPluginPromises: Promise>[] = []; + for (const [pluginDefinition, lifecycleContext] of this._lifecycleContextByDefinition) { + if (!lifecycleContext.lifecycleSession) { + // Generate the plugin-specific session + lifecycleContext.lifecycleSession = new HeftLifecycleSession({ + debug: this._internalHeftSession.debug, + heftConfiguration: this._internalHeftSession.heftConfiguration, + loggingManager: this._internalHeftSession.loggingManager, + metricsCollector: this._internalHeftSession.metricsCollector, + logger: this._internalHeftSession.loggingManager.requestScopedLogger( + `lifecycle:${pluginDefinition.pluginName}` + ), + lifecycleHooks: this.hooks, + lifecycleParameters: + this._internalHeftSession.parameterManager.getParametersForPlugin(pluginDefinition), + pluginDefinition: pluginDefinition, + pluginHost: this + }); + } + loadPluginPromises.push( + this._getLifecyclePluginForPluginDefinitionAsync(pluginDefinition, lifecycleContext.lifecycleSession) + ); + } + + // Promise.all maintains the order of the input array + const plugins: IHeftLifecyclePlugin[] = await Promise.all(loadPluginPromises); + + // Iterate through and apply the plugins + let pluginIndex: number = 0; + for (const [pluginDefinition, lifecycleContext] of this._lifecycleContextByDefinition) { + const lifecyclePlugin: IHeftLifecyclePlugin = plugins[pluginIndex++]; + try { + // Apply the plugin. We know the session should exist because we generated it above. + lifecyclePlugin.apply( + lifecycleContext.lifecycleSession!, + this._internalHeftSession.heftConfiguration, + lifecycleContext.pluginOptions + ); + } catch (error) { + throw new Error( + `Error applying plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` + + `${JSON.stringify(pluginDefinition.pluginPackageName)}: ${error}` + ); + } + } + + // Do a second pass to apply the plugin access requests for each plugin + pluginIndex = 0; + for (const [pluginDefinition] of this._lifecycleContextByDefinition) { + const lifecyclePlugin: IHeftLifecyclePlugin = plugins[pluginIndex++]; + this.resolvePluginAccessRequests(lifecyclePlugin, pluginDefinition); + } + } + + public async ensureInitializedAsync(): Promise { + if (!this._isInitialized) { + this._isInitialized = true; + + // Load up all plugin configurations concurrently + const pluginConfigurationPromises: Promise[] = []; + for (const pluginSpecifier of this._lifecyclePluginSpecifiers) { + const { pluginPackageRoot, pluginPackage } = pluginSpecifier; + pluginConfigurationPromises.push( + HeftPluginConfiguration.loadFromPackageAsync(pluginPackageRoot, pluginPackage) + ); + } + + // Promise.all maintains the order of the input array + const pluginConfigurations: HeftPluginConfiguration[] = await Promise.all(pluginConfigurationPromises); + + // Iterate through and generate the lifecycle context for each plugin + let pluginConfigurationIndex: number = 0; + for (const pluginSpecifier of this._lifecyclePluginSpecifiers) { + const pluginConfiguration: HeftPluginConfiguration = pluginConfigurations[pluginConfigurationIndex++]; + const pluginDefinition: HeftPluginDefinitionBase = + pluginConfiguration.getPluginDefinitionBySpecifier(pluginSpecifier); + + // Ensure the plugin is a lifecycle plugin + const isLifecyclePlugin: boolean = pluginConfiguration.isLifecyclePluginDefinition(pluginDefinition); + if (!isLifecyclePlugin) { + throw new Error( + `Plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` + + `${JSON.stringify(pluginSpecifier.pluginPackage)} is not a lifecycle plugin.` + ); + } + + // Ensure there are no duplicate plugin names within the same package + if (this._lifecycleContextByDefinition.has(pluginDefinition)) { + throw new Error( + `Lifecycle plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` + + `${JSON.stringify(pluginSpecifier.pluginPackage)} cannot be specified more than once.` + ); + } + + // Validate the plugin options + const pluginOptions: object | undefined = pluginSpecifier.options; + pluginDefinition.validateOptions(pluginOptions); + + // Partially populate the context. The session will be populated while applying the plugins. + const lifecycleContext: IHeftLifecycleContext = { pluginOptions }; + this._lifecycleContextByDefinition.set(pluginDefinition, lifecycleContext); + } + } + } + + public get lifecycleLogger(): ScopedLogger { + let logger: ScopedLogger | undefined = this._lifecycleLogger; + if (!logger) { + logger = this._internalHeftSession.loggingManager.requestScopedLogger(`lifecycle`); + this._lifecycleLogger = logger; + } + return logger; + } + + public async getSessionForPluginDefinitionAsync( + pluginDefinition: HeftLifecyclePluginDefinition + ): Promise { + await this.ensureInitializedAsync(); + const lifecycleContext: IHeftLifecycleContext | undefined = + this._lifecycleContextByDefinition.get(pluginDefinition); + if (!lifecycleContext) { + throw new InternalError( + `Could not find lifecycle context for plugin ${JSON.stringify(pluginDefinition.pluginName)}.` + ); + } + if (!lifecycleContext.lifecycleSession) { + throw new InternalError( + `Lifecycle session for plugin ${JSON.stringify( + pluginDefinition.pluginName + )} has not been created yet.` + ); + } + return lifecycleContext.lifecycleSession; + } + + private async _getLifecyclePluginForPluginDefinitionAsync( + pluginDefinition: HeftLifecyclePluginDefinition, + lifecycleSession: IHeftLifecycleSession + ): Promise> { + let lifecyclePlugin: IHeftPlugin | undefined = + this._lifecyclePluginsByDefinition.get(pluginDefinition); + if (!lifecyclePlugin) { + lifecyclePlugin = await pluginDefinition.loadPluginAsync(lifecycleSession.logger); + this._lifecyclePluginsByDefinition.set(pluginDefinition, lifecyclePlugin); + } + return lifecyclePlugin; + } +} diff --git a/apps/heft/src/pluginFramework/HeftLifecycleSession.ts b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts new file mode 100644 index 00000000000..b95d20d5e16 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts @@ -0,0 +1,263 @@ +// 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 { 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'; +import type { IInternalHeftSessionOptions } from './InternalHeftSession'; +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 + * plugins. The session provides access to the hooks that Heft will run as part of lifecycle execution, + * as well as access to parameters provided via the CLI. The session is also how you request access to + * other lifecycle plugins. + * + * @public + */ +export interface IHeftLifecycleSession { + /** + * The hooks available to the lifecycle plugin. + * + * @public + */ + readonly hooks: IHeftLifecycleHooks; + + /** + * Contains default parameters provided by Heft, as well as CLI parameters requested by the lifecycle + * plugin. + * + * @public + */ + readonly parameters: IHeftParameters; + + /** + * The temp folder for the lifecycle plugin. This folder is unique for each lifecycle plugin, + * and will be cleaned when Heft is run with `--clean`. + * + * @public + */ + readonly tempFolderPath: string; + + /** + * The scoped logger for the lifecycle plugin. Messages logged with this logger will be prefixed + * with the plugin name, in the format `[lifecycle:]`. It is highly recommended that + * writing to the console be performed via the logger, as it will ensure that logging messages + * are labeled with the source of the message. + * + * @public + */ + readonly logger: IScopedLogger; + + /** + * Set a a callback which will be called if and after the specified plugin has been applied. + * This can be used to tap hooks on another lifecycle plugin that exists within the same phase. + * + * @public + */ + requestAccessToPluginByName( + pluginToAccessPackage: string, + pluginToAccessName: string, + pluginApply: (pluginAccessor: T) => void + ): 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. + * + * @public + */ +export interface IHeftLifecycleHooks { + /** + * The `clean` hook is called at the beginning of Heft execution. It can be used to clean up + * any files or folders that may be produced by the plugin. To use it, call + * `clean.tapPromise(, )`. + * + * @public + */ + clean: AsyncParallelHook; + + /** + * The `toolStart` hook is called at the beginning of Heft execution, after the `clean` hook. It is + * called before any phases have begun to execute. To use it, call + * `toolStart.tapPromise(, )`. + * + * @public + */ + toolStart: AsyncParallelHook; + + /** + * The `toolFinish` hook is called at the end of Heft execution. It is called after all phases have + * completed execution. Plugins that tap this hook are resposible for handling the scenario in which + * `toolStart` threw an error, since this hook is used to clean up any resources allocated earlier + * in the lifecycle and therefore runs even in error conditions. To use it, call + * `toolFinish.tapPromise(, )`. + * + * @public + */ + toolFinish: AsyncParallelHook; + + /** + * The `recordMetrics` hook is called at the end of every Heft execution pass. It is called after all + * phases have completed execution (or been canceled). In a watch run, it will be called several times + * in between `toolStart` and (if the session is gracefully interrupted via Ctrl+C), `toolFinish`. + * In a non-watch run, it will be invoked exactly once between `toolStart` and `toolFinish`. + * To use it, call `recordMetrics.tapPromise(, )`. + * @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; +} + +/** + * Options provided to the clean hook. + * + * @public + */ +export interface IHeftLifecycleCleanHookOptions { + /** + * Add delete operations, which will be performed at the beginning of Heft execution. + * + * @public + */ + addDeleteOperations: (...deleteOperations: IDeleteOperation[]) => void; +} + +/** + * Options provided to the toolStart hook. + * + * @public + */ +export interface IHeftLifecycleToolStartHookOptions {} + +/** + * Options provided to the toolFinish hook. + * + * @public + */ +export interface IHeftLifecycleToolFinishHookOptions {} + +export interface IHeftLifecycleSessionOptions extends IInternalHeftSessionOptions { + logger: ScopedLogger; + lifecycleHooks: IHeftLifecycleHooks; + lifecycleParameters: IHeftParameters; + pluginDefinition: HeftPluginDefinitionBase; + pluginHost: HeftPluginHost; +} + +export class HeftLifecycleSession implements IHeftLifecycleSession { + private _options: IHeftLifecycleSessionOptions; + private _pluginHost: HeftPluginHost; + + public readonly hooks: IHeftLifecycleHooks; + public readonly parameters: IHeftParameters; + public readonly tempFolderPath: string; + public readonly logger: IScopedLogger; + public readonly debug: boolean; + + /** + * @internal + */ + public readonly metricsCollector: MetricsCollector; + + 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; + + // 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}`; + + // /temp/. + this.tempFolderPath = path.join(options.heftConfiguration.tempFolderPath, uniquePluginFolderName); + + this._pluginHost = options.pluginHost; + } + + public requestAccessToPluginByName( + pluginToAccessPackage: string, + pluginToAccessName: string, + pluginApply: (pluginAccessor: T) => void + ): void { + const { pluginPackageName, pluginName } = this._options.pluginDefinition; + const pluginHookName: string = this._pluginHost.getPluginHookName(pluginPackageName, pluginName); + this._pluginHost.requestAccessToPluginByName( + pluginHookName, + pluginToAccessPackage, + pluginToAccessName, + pluginApply + ); + } +} diff --git a/apps/heft/src/pluginFramework/HeftParameterManager.ts b/apps/heft/src/pluginFramework/HeftParameterManager.ts new file mode 100644 index 00000000000..edf79c00fd4 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftParameterManager.ts @@ -0,0 +1,399 @@ +// 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, + type CommandLineParameterProvider, + CommandLineParameterKind, + type CommandLineChoiceParameter, + type CommandLineChoiceListParameter, + type CommandLineFlagParameter, + type CommandLineIntegerParameter, + type CommandLineIntegerListParameter, + type CommandLineStringParameter, + type CommandLineStringListParameter +} from '@rushstack/ts-command-line'; + +import type { + HeftPluginDefinitionBase, + IChoiceParameterAlternativeJson, + IParameterJson +} from '../configuration/HeftPluginDefinition'; + +/** + * The default parameters provided by Heft. + * + * @public + */ +export interface IHeftDefaultParameters { + /** + * Whether or not the `--clean` flag was passed to Heft. + * + * @public + */ + readonly clean: boolean; + + /** + * Whether or not the `--debug` flag was passed to Heft. + * + * @public + */ + readonly debug: boolean; + + /** + * Whether or not the `--verbose` flag was passed to the Heft action. + * + * @public + */ + readonly verbose: boolean; + + /** + * Whether or not the `--production` flag was passed to the Heft action. + * + * @public + */ + readonly production: boolean; + + /** + * The locales provided to the Heft action via the `--locales` parameter. + * + * @public + */ + readonly locales: Iterable; + + /** + * Whether or not the Heft action is running in watch mode. + */ + readonly watch: boolean; +} + +/** + * Parameters provided to a Heft plugin. + * + * @public + */ +export interface IHeftParameters extends IHeftDefaultParameters { + /** + * Get a choice parameter that has been defined in heft-plugin.json. + * + * @public + */ + getChoiceParameter(parameterLongName: string): CommandLineChoiceParameter; + + /** + * Get a choice list parameter that has been defined in heft-plugin.json. + * + * @public + */ + getChoiceListParameter(parameterLongName: string): CommandLineChoiceListParameter; + + /** + * Get a flag parameter that has been defined in heft-plugin.json. + * + * @public + */ + getFlagParameter(parameterLongName: string): CommandLineFlagParameter; + + /** + * Get an integer parameter that has been defined in heft-plugin.json. + * + * @public + */ + getIntegerParameter(parameterLongName: string): CommandLineIntegerParameter; + + /** + * Get an integer list parameter that has been defined in heft-plugin.json. + * + * @public + */ + getIntegerListParameter(parameterLongName: string): CommandLineIntegerListParameter; + + /** + * Get a string parameter that has been defined in heft-plugin.json. + * + * @public + */ + getStringParameter(parameterLongName: string): CommandLineStringParameter; + + /** + * Get a string list parameter that has been defined in heft-plugin.json. + * + * @public + */ + getStringListParameter(parameterLongName: string): CommandLineStringListParameter; +} + +export interface IHeftParameterManagerOptions { + getIsClean: () => boolean; + getIsDebug: () => boolean; + getIsVerbose: () => boolean; + getIsProduction: () => boolean; + getIsWatch: () => boolean; + getLocales: () => Iterable; +} + +export class HeftParameterManager { + private readonly _options: IHeftParameterManagerOptions; + // plugin definition => parameter accessors and defaults + private readonly _heftParametersByDefinition: Map = new Map(); + // plugin definition => Map< parameter long name => applied parameter > + private readonly _parametersByDefinition: Map> = + new Map(); + // parameter scope => plugin definition + private readonly _pluginDefinitionsByScope: Map = new Map(); + + private _isFinalized: boolean = false; + + private _defaultParameters: IHeftDefaultParameters | undefined; + public get defaultParameters(): IHeftDefaultParameters { + if (!this._isFinalized) { + throw new InternalError('Parameters have not yet been finalized.'); + } + + if (!this._defaultParameters) { + this._defaultParameters = { + clean: this._options.getIsClean(), + debug: this._options.getIsDebug(), + verbose: this._options.getIsVerbose(), + production: this._options.getIsProduction(), + locales: this._options.getLocales(), + watch: this._options.getIsWatch() + }; + } + return this._defaultParameters; + } + + public constructor(options: IHeftParameterManagerOptions) { + this._options = options; + } + + /** + * Add parameters provided by the specified plugin definition. Parameters will be registered with the + * command line parameter provider after finalization. + */ + public addPluginParameters(pluginDefinition: HeftPluginDefinitionBase): void { + if (this._isFinalized) { + throw new InternalError('Parameters have already been finalized.'); + } + if (!this._parametersByDefinition.has(pluginDefinition)) { + this._parametersByDefinition.set(pluginDefinition, new Map()); + } + } + + /** + * Finalize and register parameters with the specified parameter provider. The parameter manager + * can only be finalized once. + */ + public finalizeParameters(commandLineParameterProvider: CommandLineParameterProvider): void { + if (this._isFinalized) { + throw new InternalError('Parameters have already been finalized.'); + } + this._isFinalized = true; + for (const pluginDefinition of this._parametersByDefinition.keys()) { + this._addParametersToProvider(pluginDefinition, commandLineParameterProvider); + } + } + + /** + * Get the finalized parameters for the specified plugin definition. + */ + public getParametersForPlugin(pluginDefinition: HeftPluginDefinitionBase): IHeftParameters { + if (!this._isFinalized) { + throw new InternalError('Parameters have not yet been finalized.'); + } + + let heftParameters: IHeftParameters | undefined = this._heftParametersByDefinition.get(pluginDefinition); + if (!heftParameters) { + const parameters: Map | undefined = + this._parametersByDefinition.get(pluginDefinition); + if (!parameters) { + throw new InternalError( + `Parameters from plugin ${JSON.stringify(pluginDefinition.pluginName)} in package ` + + `${JSON.stringify(pluginDefinition.pluginPackageName)} were not added before finalization.` + ); + } + + heftParameters = { + ...this.defaultParameters, + + getChoiceParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.Choice), + getChoiceListParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.ChoiceList), + getFlagParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.Flag), + getIntegerParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.Integer), + getIntegerListParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.IntegerList), + getStringParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.String), + getStringListParameter: (parameterLongName: string) => + this._getParameter(parameters, parameterLongName, CommandLineParameterKind.StringList) + }; + this._heftParametersByDefinition.set(pluginDefinition, heftParameters); + } + return heftParameters; + } + + /** + * 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 referenceable by the CLI argument + * "--:". If there is no duplicate parameter, it will also be + * 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(parameterScope); + if (existingDefinitionWithScope && existingDefinitionWithScope !== pluginDefinition) { + const { pluginName: existingScopePluginName, pluginPackageName: existingScopePluginPackageName } = + existingDefinitionWithScope; + throw new Error( + `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(parameterScope, pluginDefinition); + } + + const definedPluginParametersByName: Map = + this._parametersByDefinition.get(pluginDefinition)!; + + 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, + required, + alternatives: alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'choice': { + const { alternatives, defaultValue } = parameter; + definedParameter = commandLineParameterProvider.defineChoiceParameter({ + description, + required, + alternatives: alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), + defaultValue, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'flag': { + definedParameter = commandLineParameterProvider.defineFlagParameter({ + description, + required, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'integerList': { + const { argumentName } = parameter; + definedParameter = commandLineParameterProvider.defineIntegerListParameter({ + description, + required, + argumentName, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'integer': { + const { argumentName, defaultValue } = parameter; + definedParameter = commandLineParameterProvider.defineIntegerParameter({ + description, + required, + argumentName, + defaultValue, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'stringList': { + const { argumentName } = parameter; + definedParameter = commandLineParameterProvider.defineStringListParameter({ + description, + required, + argumentName, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + case 'string': { + const { argumentName, defaultValue } = parameter; + definedParameter = commandLineParameterProvider.defineStringParameter({ + description, + required, + argumentName, + defaultValue, + parameterLongName, + parameterShortName, + parameterScope + }); + break; + } + default: { + // Need to cast to IParameterJson since it's inferred to be type 'never' + throw new InternalError( + `Unrecognized parameter kind: ${(parameter as IParameterJson).parameterKind}` + ); + } + } + + // Add the parameter to the map using the original long name, so that it can be retrieved by plugins + // under the original long name. + definedPluginParametersByName.set(parameter.longName, definedParameter); + } + } + + private _getParameter( + parametersByLongName: Map, + parameterLongName: string, + expectedParameterKind: CommandLineParameterKind + ): T { + const parameter: CommandLineParameter | undefined = parametersByLongName.get(parameterLongName); + if (!parameter) { + throw new Error( + `Parameter ${JSON.stringify(parameterLongName)} not found. Are you sure it was defined in ` + + 'heft-plugin.json?' + ); + } else if (parameter.kind !== expectedParameterKind) { + throw new Error( + `Parameter ${JSON.stringify(parameterLongName)} is of kind ` + + `${JSON.stringify(CommandLineParameterKind[parameter.kind])}, not of kind ` + + `${JSON.stringify(CommandLineParameterKind[expectedParameterKind])}.` + ); + } + return parameter as T; + } +} diff --git a/apps/heft/src/pluginFramework/HeftPhase.ts b/apps/heft/src/pluginFramework/HeftPhase.ts new file mode 100644 index 00000000000..e7ac8e65ca6 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftPhase.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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']); + +/** + * @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; + private _consumingPhases: Set | undefined; + private _dependencyPhases: Set | undefined; + private _cleanFiles: Set | undefined; + private _tasks: Set | undefined; + private _tasksByName: Map | undefined; + + public constructor( + internalHeftSession: InternalHeftSession, + phaseName: string, + phaseSpecifier: IHeftConfigurationJsonPhaseSpecifier + ) { + this._internalHeftSession = internalHeftSession; + this._phaseName = phaseName; + this._phaseSpecifier = phaseSpecifier; + + this._validate(); + } + + /** + * The name of the phase. + */ + public get phaseName(): string { + return this._phaseName; + } + + /** + * The description of the phase. + */ + public get phaseDescription(): string | undefined { + return this._phaseSpecifier.phaseDescription; + } + + /** + * Returns delete operations that are specified on the phase. + */ + public get cleanFiles(): ReadonlySet { + if (!this._cleanFiles) { + this._cleanFiles = new Set(this._phaseSpecifier.cleanFiles || []); + } + return this._cleanFiles; + } + + /** + * Returns the set of phases that depend on this phase. + */ + public get consumingPhases(): ReadonlySet { + if (!this._consumingPhases) { + // Force initialize all dependency relationships + // This needs to operate on every phase in the set because the relationships are only specified + // in the consuming phase. + const { phases } = this._internalHeftSession; + + for (const phase of phases) { + phase._consumingPhases = new Set(); + } + + for (const phase of phases) { + for (const dependency of phase.dependencyPhases) { + dependency._consumingPhases!.add(phase); + } + } + } + return this._consumingPhases!; + } + + /** + * Returns the set of phases that this phase depends on. + */ + public get dependencyPhases(): ReadonlySet { + let dependencyPhases: Set | undefined = this._dependencyPhases; + if (!dependencyPhases) { + this._dependencyPhases = dependencyPhases = new Set(); + const dependencyNamesSet: Set = new Set(this._phaseSpecifier.phaseDependencies || []); + for (const dependencyName of dependencyNamesSet) { + // Skip if we can't find the dependency + const dependencyPhase: HeftPhase | undefined = + this._internalHeftSession.phasesByName.get(dependencyName); + if (!dependencyPhase) { + throw new Error(`Could not find dependency phase ${JSON.stringify(dependencyName)}.`); + } + dependencyPhases.add(dependencyPhase); + } + } + return dependencyPhases; + } + + /** + * Returns the set of tasks contained by this phase. + */ + public get tasks(): ReadonlySet { + this._ensureTasks(); + return this._tasks!; + } + + /** + * Returns a map of tasks by name. + */ + public get tasksByName(): ReadonlyMap { + this._ensureTasks(); + return this._tasksByName!; + } + + private _ensureTasks(): void { + if (!this._tasks || !this._tasksByName) { + this._tasks = new Set(); + this._tasksByName = new Map(); + for (const [taskName, taskSpecifier] of Object.entries(this._phaseSpecifier.tasksByName || {})) { + const task: HeftTask = new HeftTask(this, taskName, taskSpecifier); + this._tasks.add(task); + this._tasksByName.set(taskName, task); + } + } + } + + private _validate(): void { + if (RESERVED_PHASE_NAMES.has(this.phaseName)) { + throw new Error( + `Phase name ${JSON.stringify(this.phaseName)} is reserved and cannot be used as a phase name.` + ); + } + } +} diff --git a/apps/heft/src/pluginFramework/HeftPhaseSession.ts b/apps/heft/src/pluginFramework/HeftPhaseSession.ts new file mode 100644 index 00000000000..4482827883a --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftPhaseSession.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { HeftTaskSession } from './HeftTaskSession'; +import { HeftPluginHost } from './HeftPluginHost'; +import type { ScopedLogger } from './logging/ScopedLogger'; +import type { InternalHeftSession } from './InternalHeftSession'; +import type { HeftPhase } from './HeftPhase'; +import type { HeftTask } from './HeftTask'; +import type { IHeftTaskPlugin } from './IHeftPlugin'; +import type { LoggingManager } from './logging/LoggingManager'; + +export interface IHeftPhaseSessionOptions { + internalHeftSession: InternalHeftSession; + phase: HeftPhase; +} + +export class HeftPhaseSession extends HeftPluginHost { + public readonly phaseLogger: ScopedLogger; + public readonly cleanLogger: ScopedLogger; + + private readonly _options: IHeftPhaseSessionOptions; + private readonly _taskSessionsByTask: Map = new Map(); + + public constructor(options: IHeftPhaseSessionOptions) { + super(); + this._options = options; + + const loggingManager: LoggingManager = options.internalHeftSession.loggingManager; + this.phaseLogger = loggingManager.requestScopedLogger(options.phase.phaseName); + this.cleanLogger = loggingManager.requestScopedLogger(`${options.phase.phaseName}:clean`); + } + + /** + * Get a task session for the given task. + */ + public getSessionForTask(task: HeftTask): HeftTaskSession { + let taskSession: HeftTaskSession | undefined = this._taskSessionsByTask.get(task); + if (!taskSession) { + taskSession = new HeftTaskSession({ + ...this._options, + task, + pluginHost: this + }); + this._taskSessionsByTask.set(task, taskSession); + } + return taskSession; + } + + /** + * Apply all task plugins specified by the phase. + */ + protected async applyPluginsInternalAsync(): Promise { + const { + internalHeftSession: { heftConfiguration }, + phase: { tasks } + } = this._options; + + // Load up all plugins concurrently + const loadPluginPromises: Promise>[] = []; + for (const task of tasks) { + const taskSession: HeftTaskSession = this.getSessionForTask(task); + loadPluginPromises.push(task.getPluginAsync(taskSession.logger)); + } + + // Promise.all maintains the order of the input array + const plugins: IHeftTaskPlugin[] = await Promise.all(loadPluginPromises); + + // Iterate through and apply the plugins + let pluginIndex: number = 0; + for (const task of tasks) { + const taskSession: HeftTaskSession = this.getSessionForTask(task); + const taskPlugin: IHeftTaskPlugin = plugins[pluginIndex++]; + try { + taskPlugin.apply(taskSession, heftConfiguration, task.pluginOptions); + } catch (error) { + throw new Error( + `Error applying plugin ${JSON.stringify(task.pluginDefinition.pluginName)} from package ` + + `${JSON.stringify(task.pluginDefinition.pluginPackageName)}: ${error}` + ); + } + } + + // Do a second pass to apply the plugin access requests for each plugin + pluginIndex = 0; + for (const task of tasks) { + const taskPlugin: IHeftTaskPlugin = plugins[pluginIndex++]; + this.resolvePluginAccessRequests(taskPlugin, task.pluginDefinition); + } + } +} diff --git a/apps/heft/src/pluginFramework/HeftPluginHost.ts b/apps/heft/src/pluginFramework/HeftPluginHost.ts new file mode 100644 index 00000000000..9f3dad8edcc --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftPluginHost.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 { SyncHook } from 'tapable'; + +import { InternalError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; +import type { IHeftPlugin } from './IHeftPlugin'; + +export abstract class HeftPluginHost { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private readonly _pluginAccessRequestHooks: Map> = new Map(); + private _pluginsApplied: boolean = false; + + public async applyPluginsAsync(terminal: ITerminal): Promise { + if (this._pluginsApplied) { + // No need to apply them a second time. + return; + } + terminal.writeVerboseLine('Applying plugins'); + await this.applyPluginsInternalAsync(); + this._pluginsApplied = true; + } + + protected abstract applyPluginsInternalAsync(): Promise; + + /** + * Registers a callback used to provide access to a requested plugin via the plugin accessor. + */ + public requestAccessToPluginByName( + requestorName: string, + pluginToAccessPackage: string, + pluginToAccessName: string, + accessorCallback: (pluginAccessor: T) => void + ): void { + if (this._pluginsApplied) { + throw new Error( + `Requestor ${JSON.stringify(requestorName)} cannot request access to plugin ` + + `${JSON.stringify(pluginToAccessName)} from package ${JSON.stringify(pluginToAccessPackage)} ` + + `after plugins have been applied.` + ); + } + + const pluginHookName: string = this.getPluginHookName(pluginToAccessPackage, pluginToAccessName); + let pluginAccessRequestHook: SyncHook | undefined = this._pluginAccessRequestHooks.get(pluginHookName); + if (!pluginAccessRequestHook) { + pluginAccessRequestHook = new SyncHook(['pluginAccessor']); + this._pluginAccessRequestHooks.set(pluginHookName, pluginAccessRequestHook); + } + if (pluginAccessRequestHook.taps.some((t) => t.name === requestorName)) { + throw new Error( + `Plugin ${JSON.stringify(pluginToAccessName)} from ${JSON.stringify(pluginToAccessPackage)} has ` + + `already been accessed by ${JSON.stringify(requestorName)}.` + ); + } + pluginAccessRequestHook.tap(requestorName, accessorCallback); + } + + /** + * Gets the name of the hook that is registered with the plugin access request hook. + */ + public getPluginHookName(pluginPackageName: string, pluginName: string): string { + return `${pluginPackageName};${pluginName}`; + } + + /** + * Resolves all plugin requests for the specified plugin. All plugins that requested access to the + * specified plugin will have their callbacks invoked, and will be provided with the accessor for + * the specified plugin. + */ + protected resolvePluginAccessRequests( + plugin: IHeftPlugin, + pluginDefinition: HeftPluginDefinitionBase + ): void { + if (this._pluginsApplied) { + throw new InternalError('Cannot resolve plugin access requests after plugins have been applied.'); + } + const pluginHookName: string = this.getPluginHookName( + pluginDefinition.pluginPackageName, + pluginDefinition.pluginName + ); + const pluginAccessRequestHook: SyncHook | undefined = + this._pluginAccessRequestHooks.get(pluginHookName); + if (pluginAccessRequestHook?.isUsed()) { + const accessor: object | undefined = plugin.accessor; + if (accessor) { + pluginAccessRequestHook.call(accessor); + } else { + throw new Error( + `Plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` + + `${JSON.stringify(pluginDefinition.pluginPackageName)} does not provide an accessor property, ` + + `so it does not provide access to other plugins.` + ); + } + } + } +} diff --git a/apps/heft/src/pluginFramework/HeftTask.ts b/apps/heft/src/pluginFramework/HeftTask.ts new file mode 100644 index 00000000000..d5f098bd1d8 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftTask.ts @@ -0,0 +1,164 @@ +// 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 { HeftPluginConfiguration } from '../configuration/HeftPluginConfiguration'; +import type { + HeftTaskPluginDefinition, + HeftPluginDefinitionBase +} from '../configuration/HeftPluginDefinition'; +import type { HeftPhase, IHeftPhase } from './HeftPhase'; +import type { + IHeftConfigurationJsonTaskSpecifier, + IHeftConfigurationJsonPluginSpecifier +} from '../utilities/CoreConfigFiles'; +import type { IHeftTaskPlugin } from './IHeftPlugin'; +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 implements IHeftTask { + private _parentPhase: HeftPhase; + private _taskName: string; + private _taskSpecifier: IHeftConfigurationJsonTaskSpecifier; + private _consumingTasks: Set | undefined; + private _dependencyTasks: Set | undefined; + + private _taskPluginDefinition: HeftTaskPluginDefinition | undefined; + private _taskPlugin: IHeftTaskPlugin | undefined; + + public get parentPhase(): HeftPhase { + return this._parentPhase; + } + + public get taskName(): string { + return this._taskName; + } + + public get consumingTasks(): ReadonlySet { + if (!this._consumingTasks) { + // Force initialize all dependency relationships + // This needs to operate on every phase in the set because the relationships are only specified + // in the consuming phase. + const { tasks } = this._parentPhase; + + for (const task of tasks) { + task._consumingTasks = new Set(); + } + for (const task of tasks) { + for (const dependency of task.dependencyTasks) { + dependency._consumingTasks!.add(task); + } + } + } + + return this._consumingTasks!; + } + + public get pluginDefinition(): HeftTaskPluginDefinition { + if (!this._taskPluginDefinition) { + throw new InternalError( + 'HeftTask.ensureInitializedAsync() must be called before accessing HeftTask.pluginDefinition.' + ); + } + return this._taskPluginDefinition; + } + + public get pluginOptions(): object | undefined { + return this._taskSpecifier.taskPlugin.options; + } + + public get dependencyTasks(): Set { + if (!this._dependencyTasks) { + this._dependencyTasks = new Set(); + const dependencyNamesSet: Set = new Set(this._taskSpecifier.taskDependencies || []); + + for (const dependencyName of dependencyNamesSet) { + // Skip if we can't find the dependency + const dependencyTask: HeftTask | undefined = this._parentPhase.tasksByName.get(dependencyName); + if (!dependencyTask) { + throw new Error( + `Could not find dependency task ${JSON.stringify(dependencyName)} within phase ` + + `${JSON.stringify(this._parentPhase.phaseName)}.` + ); + } + this._dependencyTasks.add(dependencyTask); + } + } + + return this._dependencyTasks!; + } + + public constructor( + parentPhase: HeftPhase, + taskName: string, + taskSpecifier: IHeftConfigurationJsonTaskSpecifier + ) { + this._parentPhase = parentPhase; + this._taskName = taskName; + this._taskSpecifier = taskSpecifier; + + this._validate(); + } + + public async ensureInitializedAsync(): Promise { + if (!this._taskPluginDefinition) { + this._taskPluginDefinition = await this._loadTaskPluginDefinitionAsync(); + this.pluginDefinition.validateOptions(this.pluginOptions); + } + } + + public async getPluginAsync(logger: IScopedLogger): Promise> { + await this.ensureInitializedAsync(); + if (!this._taskPlugin) { + this._taskPlugin = await this._taskPluginDefinition!.loadPluginAsync(logger); + } + return this._taskPlugin; + } + + private async _loadTaskPluginDefinitionAsync(): Promise { + // taskPlugin.pluginPackage should already be resolved to the package root. + // See CoreConfigFiles.heftConfigFileLoader + const pluginSpecifier: IHeftConfigurationJsonPluginSpecifier = this._taskSpecifier.taskPlugin; + const pluginConfiguration: HeftPluginConfiguration = await HeftPluginConfiguration.loadFromPackageAsync( + pluginSpecifier.pluginPackageRoot, + pluginSpecifier.pluginPackage + ); + const pluginDefinition: HeftPluginDefinitionBase = + pluginConfiguration.getPluginDefinitionBySpecifier(pluginSpecifier); + + const isTaskPluginDefinition: boolean = pluginConfiguration.isTaskPluginDefinition(pluginDefinition); + if (!isTaskPluginDefinition) { + throw new Error( + `Plugin ${JSON.stringify(pluginSpecifier.pluginName)} specified by task ` + + `${JSON.stringify(this._taskName)} is not a task plugin.` + ); + } + return pluginDefinition; + } + + private _validate(): void { + if (RESERVED_TASK_NAMES.has(this.taskName)) { + throw new Error( + `Task name ${JSON.stringify(this.taskName)} is reserved and cannot be used as a task name.` + ); + } + if (!this._taskSpecifier.taskPlugin) { + throw new Error(`Task ${JSON.stringify(this.taskName)} has no specified task plugin.`); + } + } +} diff --git a/apps/heft/src/pluginFramework/HeftTaskSession.ts b/apps/heft/src/pluginFramework/HeftTaskSession.ts new file mode 100644 index 00000000000..9898b11a492 --- /dev/null +++ b/apps/heft/src/pluginFramework/HeftTaskSession.ts @@ -0,0 +1,316 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; +import type { IHeftPhaseSessionOptions } from './HeftPhaseSession'; +import type { HeftParameterManager, IHeftParameters } from './HeftParameterManager'; +import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; +import type { ICopyOperation } from '../plugins/CopyFilesPlugin'; +import type { HeftPluginHost } from './HeftPluginHost'; +import type { GlobFn, WatchGlobFn } from '../plugins/FileGlobSpecifier'; +import type { IWatchFileSystem } from '../utilities/WatchFileSystemAdapter'; + +/** + * The type of {@link IHeftTaskSession.parsedCommandLine}, which exposes details about the + * command line that was used to invoke Heft. + * @public + */ +export interface IHeftParsedCommandLine { + /** + * Returns the subcommand passed on the Heft command line, before any aliases have been expanded. + * This can be useful when printing error messages that need to refer to the invoked command line. + * + * @remarks + * For example, if the invoked command was `heft test --verbose`, then `commandName` + * would be `test`. + * + * Suppose the invoked command was `heft start` which is an alias for `heft build-watch --serve`. + * In this case, the `commandName` would be `start`. To get the expanded name `build-watch`, + * use {@link IHeftParsedCommandLine.unaliasedCommandName} instead. + * + * When invoking phases directly using `heft run`, the `commandName` is `run`. + * + * @see {@link IHeftParsedCommandLine.unaliasedCommandName} + */ + readonly commandName: string; + + /** + * Returns the subcommand passed on the Heft command line, after any aliases have been expanded. + * This can be useful when printing error messages that need to refer to the invoked command line. + * + * @remarks + * For example, if the invoked command was `heft test --verbose`, then `unaliasedCommandName` + * would be `test`. + * + * Suppose the invoked command was `heft start` which is an alias for `heft build-watch --serve`. + * In this case, the `unaliasedCommandName` would be `build-watch`. To get the alias name + * `start`, use @see {@link IHeftParsedCommandLine.commandName} instead. + * + * When invoking phases directly using `heft run`, the `unaliasedCommandName` is `run`. + * + * @see {@link IHeftParsedCommandLine.commandName} + */ + readonly unaliasedCommandName: string; +} + +/** + * The task session is responsible for providing session-specific information to Heft task plugins. + * The session provides access to the hooks that Heft will run as part of task execution, as well as + * access to parameters provided via the CLI. The session is also how you request access to other task + * plugins. + * + * @public + */ +export interface IHeftTaskSession { + /** + * The name of the task. This is defined in "heft.json". + * + * @public + */ + readonly taskName: string; + + /** + * The hooks available to the task plugin. + * + * @public + */ + readonly hooks: IHeftTaskHooks; + + /** + * Contains default parameters provided by Heft, as well as CLI parameters requested by the task + * plugin. + * + * @public + */ + readonly parameters: IHeftParameters; + + /** + * Exposes details about the command line that was used to invoke Heft. + * This value is initially `undefined` and later filled in after the command line has been parsed. + */ + readonly parsedCommandLine: IHeftParsedCommandLine; + + /** + * The temp folder for the task. This folder is unique for each task, and will be cleaned + * when Heft is run with `--clean`. + * + * @public + */ + readonly tempFolderPath: string; + + /** + * The scoped logger for the task. Messages logged with this logger will be prefixed with + * the phase and task name, in the format `[:]`. It is highly recommended + * that writing to the console be performed via the logger, as it will ensure that logging messages + * are labeled with the source of the message. + * + * @public + */ + readonly logger: IScopedLogger; + + /** + * Set a a callback which will be called if and after the specified plugin has been applied. + * This can be used to tap hooks on another plugin that exists within the same phase. + * + * @public + */ + requestAccessToPluginByName( + pluginToAccessPackage: string, + pluginToAccessName: string, + pluginApply: (pluginAccessor: T) => void + ): void; +} + +/** + * Hooks that are available to the task plugin. + * + * @public + */ +export interface IHeftTaskHooks { + /** + * The `run` hook is called after all dependency task executions have completed during a normal + * run, or during a watch mode run when no `runIncremental` hook is provided. It is where the + * plugin can perform its work. To use it, call `run.tapPromise(, )`. + * + * @public + */ + readonly run: AsyncParallelHook; + + /** + * If provided, the `runIncremental` hook is called after all dependency task executions have completed + * during a watch mode run. It is where the plugin can perform incremental work. To use it, call + * `run.tapPromise(, )`. + */ + readonly runIncremental: AsyncParallelHook; + + /** + * If provided, the `registerFileOperations` hook is called exactly once before the first time either + * `run` or `runIncremental` would be invoked to provide the plugin an opportunity to request + * dynamic file copy or deletion operations. + */ + readonly registerFileOperations: AsyncSeriesWaterfallHook; +} + +/** + * Options provided to the `run` hook. + * + * @public + */ +export interface IHeftTaskRunHookOptions { + /** + * An abort signal that is used to abort the build. This can be used to stop operations early and allow + * for a new build to be started. + * + * @beta + */ + readonly abortSignal: AbortSignal; + + /** + * Reads the specified globs and returns the result. + */ + readonly globAsync: GlobFn; +} + +/** + * Options provided to the 'runIncremental' hook. + * + * @public + */ +export interface IHeftTaskRunIncrementalHookOptions extends IHeftTaskRunHookOptions { + /** + * A callback that can be invoked to tell the Heft runtime to schedule an incremental run of this + * task. If a run is already pending, does nothing. + */ + readonly requestRun: () => void; + + /** + * Reads the specified globs and returns the result, filtering out files that have not changed since the last execution. + * All file system calls while reading the glob are tracked and will be watched for changes. + * + * 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; +} + +/** + * Options provided to the `registerFileOperations` hook. + * + * @public + */ +export interface IHeftTaskFileOperations { + /** + * Copy operations to be performed following the `run` or `runIncremental` hook. These operations will be + * performed after the task `run` or `runIncremental` hook has completed. + * + * @public + */ + copyOperations: Set; + + /** + * Delete operations to be performed following the `run` or `runIncremental` hook. These operations will be + * performed after the task `run` or `runIncremental` hook has completed. + * + * @public + */ + deleteOperations: Set; +} + +export interface IHeftTaskSessionOptions extends IHeftPhaseSessionOptions { + task: HeftTask; + pluginHost: HeftPluginHost; +} + +export class HeftTaskSession implements IHeftTaskSession { + public readonly taskName: string; + public readonly hooks: IHeftTaskHooks; + public readonly tempFolderPath: string; + public readonly logger: IScopedLogger; + + private readonly _options: IHeftTaskSessionOptions; + private _parameters: IHeftParameters | undefined; + private _parsedCommandLine: IHeftParsedCommandLine; + + /** + * @internal + */ + public readonly metricsCollector: MetricsCollector; + + public get parameters(): IHeftParameters { + // Delay loading the parameters for the task until they're actually needed + if (!this._parameters) { + const parameterManager: HeftParameterManager = this._options.internalHeftSession.parameterManager; + const task: HeftTask = this._options.task; + this._parameters = parameterManager.getParametersForPlugin(task.pluginDefinition); + } + return this._parameters; + } + + public get parsedCommandLine(): IHeftParsedCommandLine { + return this._parsedCommandLine; + } + + public constructor(options: IHeftTaskSessionOptions) { + const { + internalHeftSession: { + heftConfiguration: { tempFolderPath: tempFolder }, + loggingManager, + metricsCollector + }, + phase, + task + } = options; + + if (!options.internalHeftSession.parsedCommandLine) { + // This should not happen + throw new InternalError('Attempt to construct HeftTaskSession before command line has been parsed'); + } + this._parsedCommandLine = options.internalHeftSession.parsedCommandLine; + + this.logger = loggingManager.requestScopedLogger(`${phase.phaseName}:${task.taskName}`); + this.metricsCollector = metricsCollector; + this.taskName = task.taskName; + this.hooks = { + run: new AsyncParallelHook(['runHookOptions']), + runIncremental: new AsyncParallelHook(['runIncrementalHookOptions']), + registerFileOperations: new AsyncSeriesWaterfallHook(['fileOperations']) + }; + + // Guaranteed to be unique since phases are uniquely named, tasks are uniquely named within + // phases, and neither can have '/' in their names. We will also use the phase name and + // task name as the folder name (instead of the plugin name) since we want to enable re-use + // of plugins in multiple phases and tasks while maintaining unique temp/cache folders for + // each task. + // Having a parent folder for the phase simplifies interaction with the Rush build cache. + const uniqueTaskFolderName: string = `${phase.phaseName}/${task.taskName}`; + + // /temp// + this.tempFolderPath = `${tempFolder}/${uniqueTaskFolderName}`; + + this._options = options; + } + + public requestAccessToPluginByName( + pluginToAccessPackage: string, + pluginToAccessName: string, + pluginApply: (pluginAccessor: T) => void + ): void { + this._options.pluginHost.requestAccessToPluginByName( + this.taskName, + pluginToAccessPackage, + pluginToAccessName, + pluginApply + ); + } +} diff --git a/apps/heft/src/pluginFramework/IHeftPlugin.ts b/apps/heft/src/pluginFramework/IHeftPlugin.ts new file mode 100644 index 00000000000..34664fc3340 --- /dev/null +++ b/apps/heft/src/pluginFramework/IHeftPlugin.ts @@ -0,0 +1,50 @@ +// 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 '../configuration/HeftConfiguration'; +import type { IHeftTaskSession } from './HeftTaskSession'; +import type { IHeftLifecycleSession } from './HeftLifecycleSession'; + +/** + * The interface used for all Heft plugins. + * + * @public + */ +export interface IHeftPlugin< + TSession extends IHeftLifecycleSession | IHeftTaskSession = IHeftLifecycleSession | IHeftTaskSession, + TOptions = void +> { + /** + * The accessor provided by the plugin. This accessor can be obtained by other plugins within the same + * phase by calling `session.requestAccessToPlugin(...)`, and is used by other plugins to interact with + * hooks or properties provided by the host plugin. + */ + readonly accessor?: object; + + /** + * Apply the plugin to the session. Plugins are expected to hook into session hooks to provide plugin + * implementation. The `apply(...)` method is called once per phase. + * + * @param session - The session to apply the plugin to. + * @param heftConfiguration - The Heft configuration. + * @param pluginOptions - Options for the plugin, specified in heft.json. + */ + apply(session: TSession, heftConfiguration: HeftConfiguration, pluginOptions?: TOptions): void; +} + +/** + * The interface that Heft lifecycle plugins must implement. Lifecycle plugins are used to provide + * functionality that affects the lifecycle of the Heft run. As such, they do not belong to any particular + * Heft phase. + * + * @public + */ +export interface IHeftLifecyclePlugin extends IHeftPlugin {} + +/** + * The interface that Heft task plugins must implement. Task plugins are used to provide the implementation + * of a specific task. + * + * @public + */ +export interface IHeftTaskPlugin extends IHeftPlugin {} diff --git a/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts new file mode 100644 index 00000000000..3c30d07cec5 --- /dev/null +++ b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts @@ -0,0 +1,212 @@ +// 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, Path } from '@rushstack/node-core-library'; + +/** + * Information about an incremental build. This information is used to determine which files need to be rebuilt. + * @beta + */ +export interface IIncrementalBuildInfo { + /** + * A string that represents the configuration inputs for the build. + * If the configuration changes, the old build info object should be discarded. + */ + configHash: string; + + /** + * A map of absolute input file paths to their version strings. + * The version string should change if the file changes. + */ + inputFileVersions: Map; + + /** + * A map of absolute output file paths to the input files they were computed from. + */ + fileDependencies?: Map; +} + +/** + * Serialized version of {@link IIncrementalBuildInfo}. + * @beta + */ +export interface ISerializedIncrementalBuildInfo { + /** + * A string that represents the configuration inputs for the build. + * If the configuration changes, the old build info object should be discarded. + */ + configHash: string; + + /** + * A map of input files to their version strings. + * File paths are specified relative to the folder containing the build info file. + */ + inputFileVersions: Record; + + /** + * Map of output file names to the corresponding index in `Object.entries(inputFileVersions)`. + * File paths are specified relative to the folder containing the build info file. + */ + fileDependencies?: Record; +} + +/** + * Converts an absolute path to a path relative to a base path. + */ +export const makePathRelative: (absolutePath: string, basePath: string) => string = + process.platform === 'win32' + ? (absolutePath: string, basePath: string) => { + // On Windows, need to normalize slashes + return Path.convertToSlashes(path.win32.relative(basePath, absolutePath)); + } + : (absolutePath: string, basePath: string) => { + // On POSIX, can preserve existing slashes + return path.posix.relative(basePath, absolutePath); + }; + +/** + * Serializes a build info object to a portable format that can be written to disk. + * @param state - The build info to serialize + * @param makePathPortable - A function that converts an absolute path to a portable path. This is a separate argument to support cross-platform tests. + * @returns The serialized build info + * @beta + */ +export function serializeBuildInfo( + state: IIncrementalBuildInfo, + makePathPortable: (absolutePath: string) => string +): ISerializedIncrementalBuildInfo { + const fileIndices: Map = new Map(); + const inputFileVersions: Record = {}; + + for (const [absolutePath, version] of state.inputFileVersions) { + const relativePath: string = makePathPortable(absolutePath); + fileIndices.set(absolutePath, fileIndices.size); + inputFileVersions[relativePath] = version; + } + + const { fileDependencies: newFileDependencies } = state; + let fileDependencies: Record | undefined; + if (newFileDependencies) { + fileDependencies = {}; + for (const [absolutePath, dependencies] of newFileDependencies) { + const relativePath: string = makePathPortable(absolutePath); + const indices: number[] = []; + for (const dependency of dependencies) { + const index: number | undefined = fileIndices.get(dependency); + if (index === undefined) { + throw new Error(`Dependency not found: ${dependency}`); + } + indices.push(index); + } + + fileDependencies[relativePath] = indices; + } + } + + const serializedBuildInfo: ISerializedIncrementalBuildInfo = { + configHash: state.configHash, + inputFileVersions, + fileDependencies + }; + + return serializedBuildInfo; +} + +/** + * Deserializes a build info object from its portable format. + * @param serializedBuildInfo - The build info to deserialize + * @param makePathAbsolute - A function that converts a portable path to an absolute path. This is a separate argument to support cross-platform tests. + * @returns The deserialized build info + */ +export function deserializeBuildInfo( + serializedBuildInfo: ISerializedIncrementalBuildInfo, + makePathAbsolute: (relativePath: string) => string +): IIncrementalBuildInfo { + const inputFileVersions: Map = new Map(); + const absolutePathByIndex: string[] = []; + for (const [relativePath, version] of Object.entries(serializedBuildInfo.inputFileVersions)) { + const absolutePath: string = makePathAbsolute(relativePath); + absolutePathByIndex.push(absolutePath); + inputFileVersions.set(absolutePath, version); + } + + let fileDependencies: Map | undefined; + const { fileDependencies: serializedFileDependencies } = serializedBuildInfo; + if (serializedFileDependencies) { + fileDependencies = new Map(); + for (const [relativeOutputFile, indices] of Object.entries(serializedFileDependencies)) { + const absoluteOutputFile: string = makePathAbsolute(relativeOutputFile); + const dependencies: string[] = []; + for (const index of Array.isArray(indices) ? indices : [indices]) { + const dependencyAbsolutePath: string | undefined = absolutePathByIndex[index]; + if (dependencyAbsolutePath === undefined) { + throw new Error(`Dependency index not found: ${index}`); + } + dependencies.push(dependencyAbsolutePath); + } + fileDependencies.set(absoluteOutputFile, dependencies); + } + } + + const buildInfo: IIncrementalBuildInfo = { + configHash: serializedBuildInfo.configHash, + inputFileVersions, + fileDependencies + }; + + return buildInfo; +} + +/** + * Writes a build info object to disk. + * @param state - The build info to write + * @param filePath - The file path to write the build info to + * @beta + */ +export async function writeBuildInfoAsync(state: IIncrementalBuildInfo, filePath: string): Promise { + const basePath: string = path.dirname(filePath); + + const serializedBuildInfo: ISerializedIncrementalBuildInfo = serializeBuildInfo( + state, + (absolutePath: string) => { + return makePathRelative(absolutePath, basePath); + } + ); + + // This file is meant only for machine reading, so don't pretty-print it. + const stringified: string = JSON.stringify(serializedBuildInfo); + + await FileSystem.writeFileAsync(filePath, stringified, { ensureFolderExists: true }); +} + +/** + * Reads a build info object from disk. + * @param filePath - The file path to read the build info from + * @returns The build info object, or undefined if the file does not exist or cannot be parsed + * @beta + */ +export async function tryReadBuildInfoAsync(filePath: string): Promise { + let serializedBuildInfo: ISerializedIncrementalBuildInfo | undefined; + try { + const fileContents: string = await FileSystem.readFileAsync(filePath); + serializedBuildInfo = JSON.parse(fileContents) as ISerializedIncrementalBuildInfo; + } catch (error) { + if (FileSystem.isNotExistError(error)) { + return; + } + throw error; + } + + const basePath: string = path.dirname(filePath); + + const buildInfo: IIncrementalBuildInfo = deserializeBuildInfo( + serializedBuildInfo, + (relativePath: string) => { + return path.resolve(basePath, relativePath); + } + ); + + return buildInfo; +} diff --git a/apps/heft/src/pluginFramework/InternalHeftSession.ts b/apps/heft/src/pluginFramework/InternalHeftSession.ts new file mode 100644 index 00000000000..93905e3e94f --- /dev/null +++ b/apps/heft/src/pluginFramework/InternalHeftSession.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 { Async, InternalError } from '@rushstack/node-core-library'; + +import { Constants } from '../utilities/Constants'; +import { HeftLifecycle } from './HeftLifecycle'; +import { HeftPhaseSession } from './HeftPhaseSession'; +import { HeftPhase } from './HeftPhase'; +import { + CoreConfigFiles, + type IHeftConfigurationJson, + type IHeftConfigurationJsonActionReference +} from '../utilities/CoreConfigFiles'; +import type { MetricsCollector } from '../metrics/MetricsCollector'; +import type { LoggingManager } from './logging/LoggingManager'; +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; +import type { HeftTask } from './HeftTask'; +import type { HeftParameterManager } from './HeftParameterManager'; +import type { IHeftParsedCommandLine } from './HeftTaskSession'; + +export interface IInternalHeftSessionOptions { + heftConfiguration: HeftConfiguration; + loggingManager: LoggingManager; + metricsCollector: MetricsCollector; + + debug: boolean; +} + +function* getAllTasks(phases: Iterable): IterableIterator { + for (const phase of phases) { + yield* phase.tasks; + } +} + +export class InternalHeftSession { + private readonly _phaseSessionsByPhase: Map = new Map(); + private readonly _heftConfigurationJson: IHeftConfigurationJson; + private _actionReferencesByAlias: ReadonlyMap | undefined; + private _lifecycle: HeftLifecycle | undefined; + private _phases: Set | undefined; + private _phasesByName: Map | undefined; + private _parameterManager: HeftParameterManager | undefined; + + public readonly heftConfiguration: HeftConfiguration; + + public readonly loggingManager: LoggingManager; + + public readonly metricsCollector: MetricsCollector; + + public parsedCommandLine: IHeftParsedCommandLine | undefined; + + public readonly debug: boolean; + + private constructor(heftConfigurationJson: IHeftConfigurationJson, options: IInternalHeftSessionOptions) { + this.heftConfiguration = options.heftConfiguration; + this.loggingManager = options.loggingManager; + this.metricsCollector = options.metricsCollector; + this.debug = options.debug; + this._heftConfigurationJson = heftConfigurationJson; + } + + public static async initializeAsync(options: IInternalHeftSessionOptions): Promise { + // Initialize the rig. Must be done before the HeftConfiguration.rigConfig is used. + await options.heftConfiguration._checkForRigAsync(); + + const heftConfigurationJson: IHeftConfigurationJson = + await CoreConfigFiles.loadHeftConfigurationFileForProjectAsync( + options.heftConfiguration.globalTerminal, + options.heftConfiguration.buildFolderPath, + options.heftConfiguration.rigConfig + ); + + const internalHeftSession: InternalHeftSession = new InternalHeftSession(heftConfigurationJson, options); + + // Initialize the lifecycle and the tasks. This will ensure that we throw an error if a plugin is improperly + // specified, or if the options provided to a plugin are invalid. We will avoid loading the actual plugins + // until they are needed. + await internalHeftSession.lifecycle.ensureInitializedAsync(); + const tasks: Iterable = getAllTasks(internalHeftSession.phases); + await Async.forEachAsync( + tasks, + async (task: HeftTask) => { + await task.ensureInitializedAsync(); + }, + { concurrency: Constants.maxParallelism } + ); + + function* getAllPluginDefinitions(): IterableIterator { + yield* internalHeftSession.lifecycle.pluginDefinitions; + for (const task of getAllTasks(internalHeftSession.phases)) { + yield task.pluginDefinition; + } + } + + const loadedPluginPathsByName: Map> = new Map(); + for (const { pluginName, entryPoint } of getAllPluginDefinitions()) { + let existingPluginPaths: Set | undefined = loadedPluginPathsByName.get(pluginName); + if (!existingPluginPaths) { + existingPluginPaths = new Set(); + loadedPluginPathsByName.set(pluginName, existingPluginPaths); + } + + existingPluginPaths.add(entryPoint); + } + + for (const [pluginName, pluginPaths] of loadedPluginPathsByName) { + if (pluginPaths.size > 1) { + throw new Error( + `Multiple plugins named ${JSON.stringify(pluginName)} were loaded from different paths: ` + + `${Array.from(pluginPaths, (x) => JSON.stringify(x)).join(', ')}. Plugins must have unique names.` + ); + } + } + + return internalHeftSession; + } + + public get parameterManager(): HeftParameterManager { + if (!this._parameterManager) { + throw new InternalError('A parameter manager for the session has not been provided.'); + } + return this._parameterManager; + } + + public set parameterManager(value: HeftParameterManager) { + this._parameterManager = value; + } + + public get actionReferencesByAlias(): ReadonlyMap { + if (!this._actionReferencesByAlias) { + this._actionReferencesByAlias = new Map( + Object.entries(this._heftConfigurationJson.aliasesByName || {}) + ); + } + return this._actionReferencesByAlias; + } + + public get lifecycle(): HeftLifecycle { + if (!this._lifecycle) { + this._lifecycle = new HeftLifecycle(this, this._heftConfigurationJson.heftPlugins || []); + } + return this._lifecycle; + } + + public get phases(): ReadonlySet { + this._ensurePhases(); + return this._phases!; + } + + public get phasesByName(): ReadonlyMap { + this._ensurePhases(); + return this._phasesByName!; + } + + public getSessionForPhase(phase: HeftPhase): HeftPhaseSession { + let phaseSession: HeftPhaseSession | undefined = this._phaseSessionsByPhase.get(phase); + if (!phaseSession) { + phaseSession = new HeftPhaseSession({ internalHeftSession: this, phase }); + this._phaseSessionsByPhase.set(phase, phaseSession); + } + return phaseSession; + } + + private _ensurePhases(): void { + if (!this._phases || !this._phasesByName) { + this._phasesByName = new Map(); + for (const [phaseName, phaseSpecifier] of Object.entries( + this._heftConfigurationJson.phasesByName || {} + )) { + const phase: HeftPhase = new HeftPhase(this, phaseName, phaseSpecifier); + this._phasesByName.set(phaseName, phase); + } + this._phases = new Set(this._phasesByName.values()); + } + } +} diff --git a/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts new file mode 100644 index 00000000000..89129078af2 --- /dev/null +++ b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts @@ -0,0 +1,242 @@ +// 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 'node:fs'; +import * as path from 'node:path'; + +import type { FileSystemAdapter } from 'fast-glob'; + +import { Path } from '@rushstack/node-core-library'; + +interface IVirtualFileSystemEntry { + name: string; + children?: Set; +} + +interface IReaddirOptions { + 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; +/* eslint-enable @rushstack/no-new-null */ + +const IS_WINDOWS: boolean = process.platform === 'win32'; + +/** + * A filesystem adapter for use with the "fast-glob" package. This adapter uses a static set of paths + * to provide a virtual filesystem. + * + * @remarks This adapter only implements methods required to allow for globbing. This means that it + * does not support returning true-to-disk file stats or dirent objects. Instead, the returned file + * stats and dirent objects only implement the `isDirectory` and `isFile` methods, which are + * required for filesystem traversal performed by the globber. + */ +export class StaticFileSystemAdapter implements FileSystemAdapter { + private _directoryMap: Map = new Map(); + + /** { @inheritdoc fs.lstat } */ + public lstat: FileSystemAdapter['lstat'] = ((filePath: string, callback: StatCallback) => { + process.nextTick(() => { + let result: fs.Stats; + try { + result = this.lstatSync(filePath); + } catch (e) { + callback(e, {} as fs.Stats); + return; + } + + callback(null, result); + }); + }) as FileSystemAdapter['lstat']; + + /** { @inheritdoc fs.lstatSync } */ + public lstatSync: FileSystemAdapter['lstatSync'] = ((filePath: string) => { + filePath = this._normalizePath(filePath); + const entry: IVirtualFileSystemEntry | undefined = this._directoryMap.get(filePath); + if (!entry) { + const error: NodeJS.ErrnoException = new Error(`ENOENT: no such file or directory, stat '${filePath}'`); + error.code = 'ENOENT'; + error.syscall = 'stat'; + error.errno = -4058; + error.path = filePath; + throw error; + } + // We should only need to implement these methods for the purposes of fast-glob + return { + isFile: () => !entry.children, + isDirectory: () => !!entry.children, + isBlockDevice: () => false, + isCharacterDevice: () => false, + isSymbolicLink: () => false, + isFIFO: () => false, + isSocket: () => false + }; + }) as FileSystemAdapter['lstatSync']; + + /** { @inheritdoc fs.stat } */ + public stat: FileSystemAdapter['stat'] = ((filePath: string, callback: StatCallback) => { + this.lstat(filePath, callback); + }) as FileSystemAdapter['stat']; + + /** { @inheritdoc fs.statSync } */ + public statSync: FileSystemAdapter['statSync'] = ((filePath: string) => { + return this.lstatSync(filePath); + }) as FileSystemAdapter['statSync']; + + /** { @inheritdoc fs.readdir } */ + public readdir: FileSystemAdapter['readdir'] = (( + filePath: string, + optionsOrCallback: IReaddirOptions | ReaddirStringCallback, + callback?: ReaddirDirentCallback | ReaddirStringCallback + ) => { + // Default to no options, which will return a string callback + let options: IReaddirOptions | undefined; + if (typeof optionsOrCallback === 'object') { + options = optionsOrCallback; + } else if (typeof optionsOrCallback === 'function') { + callback = optionsOrCallback; + } + + // Perform the readdir on the next tick to avoid blocking the event loop + process.nextTick(() => { + let result: fs.Dirent[] | string[]; + try { + if (options?.withFileTypes) { + result = this.readdirSync(filePath, options) as fs.Dirent[]; + } else { + result = this.readdirSync(filePath); + } + } catch (e) { + callback!(e, []); + return; + } + + // 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) { + (callback as ReaddirDirentCallback)(null, result as fs.Dirent[]); + } else { + (callback as ReaddirStringCallback)(null, result as string[]); + } + }); + }) as FileSystemAdapter['readdir']; + + /** { @inheritdoc fs.readdirSync } */ + public readdirSync: FileSystemAdapter['readdirSync'] = ((filePath: string, options?: IReaddirOptions) => { + filePath = this._normalizePath(filePath); + const virtualDirectory: IVirtualFileSystemEntry | undefined = this._directoryMap.get(filePath); + if (!virtualDirectory) { + // Immitate a missing directory read from fs.readdir + const error: NodeJS.ErrnoException = new Error( + `ENOENT: no such file or directory, scandir '${filePath}'` + ); + error.code = 'ENOENT'; + error.syscall = 'scandir'; + error.errno = -4058; + error.path = filePath; + throw error; + } else if (!virtualDirectory.children) { + // Immitate a directory read of a file from fs.readdir + const error: NodeJS.ErrnoException = new Error(`ENOTDIR: not a directory, scandir '${filePath}'`); + error.code = 'ENOTDIR'; + error.syscall = 'scandir'; + error.errno = -4052; + error.path = filePath; + throw error; + } + + // When "withFileTypes" is false or undefined, the method is expected to return a string array. + // Otherwise, we return a fs.Dirent array. + const result: IVirtualFileSystemEntry[] = Array.from(virtualDirectory.children); + if (options?.withFileTypes) { + return result.map((entry: IVirtualFileSystemEntry) => { + // Partially implement the fs.Dirent interface, only including the properties used by fast-glob + return { + name: entry.name, + isFile: () => !entry.children, + isDirectory: () => !!entry.children, + isBlockDevice: () => false, + isCharacterDevice: () => false, + isSymbolicLink: () => false, + isFIFO: () => false, + isSocket: () => false + }; + }); + } else { + return result.map((entry: IVirtualFileSystemEntry) => entry.name); + } + }) as FileSystemAdapter['readdirSync']; + + /** + * Create a new StaticFileSystemAdapter instance with the provided file paths. + */ + public constructor(filePaths?: Iterable) { + for (const filePath of filePaths || []) { + this.addFile(filePath); + } + } + + /** + * Add a file and it's parent directories to the static virtual filesystem. + */ + public addFile(filePath: string): void { + filePath = this._normalizePath(filePath); + const existingPath: IVirtualFileSystemEntry | undefined = this._directoryMap.get(filePath); + if (!existingPath) { + // Set an entry without children for the file. Entries with undefined children are assumed to be files. + let childPath: string = filePath; + let childEntry: IVirtualFileSystemEntry = { name: path.basename(childPath) }; + this._directoryMap.set(childPath, childEntry); + + // Loop through the path segments and create entries for each directory, if they don't already exist. + // If they do, append to the existing children set and continue. + let parentPath: string | undefined; + while ((parentPath = path.dirname(childPath)) !== childPath) { + const existingParentEntry: IVirtualFileSystemEntry | undefined = this._directoryMap.get(parentPath); + if (existingParentEntry) { + // If there is already an existing parent entry, add the child entry to the existing children set + // and exit early, since the parent entries already exist. + existingParentEntry.children!.add(childEntry); + break; + } else { + // If there is no existing parent entry, create a new entry with the child entry as the only child. + const parentEntry: IVirtualFileSystemEntry = { + name: path.basename(parentPath), + children: new Set([childEntry]) + }; + this._directoryMap.set(parentPath, parentEntry); + childEntry = parentEntry; + childPath = parentPath; + } + } + } + } + + /** + * Remove a file from the static virtual filesystem. + */ + public removeFile(filePath: string): void { + filePath = this._normalizePath(filePath); + const existingEntry: IVirtualFileSystemEntry | undefined = this._directoryMap.get(filePath); + if (existingEntry) { + // Remove the entry from the map and the parent's children set + this._directoryMap.delete(filePath); + this._directoryMap.get(path.dirname(filePath))!.children!.delete(existingEntry); + } + } + + /** + * Remove all files from the static virtual filesystem. + */ + public removeAllFiles(): void { + this._directoryMap.clear(); + } + + private _normalizePath(filePath: string): string { + // On Windows, normalize to backslashes so that errors have the correct path format + return IS_WINDOWS ? Path.convertToBackslashes(filePath) : filePath; + } +} diff --git a/apps/heft/src/pluginFramework/logging/LoggingManager.ts b/apps/heft/src/pluginFramework/logging/LoggingManager.ts new file mode 100644 index 00000000000..36c243a8084 --- /dev/null +++ b/apps/heft/src/pluginFramework/logging/LoggingManager.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 { + 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; +} + +export class LoggingManager { + private _options: ILoggingManagerOptions; + private _scopedLoggers: Map = new Map(); + private _shouldPrintStacks: boolean = false; + private _hasAnyWarnings: boolean = false; + private _hasAnyErrors: boolean = false; + + public get errorsHaveBeenEmitted(): boolean { + return this._hasAnyErrors; + } + + public get warningsHaveBeenEmitted(): boolean { + return this._hasAnyWarnings; + } + + public constructor(options: ILoggingManagerOptions) { + this._options = options; + } + + public enablePrintStacks(): void { + this._shouldPrintStacks = true; + } + + public resetScopedLoggerErrorsAndWarnings(): void { + this._hasAnyErrors = false; + this._hasAnyWarnings = false; + for (const scopedLogger of this._scopedLoggers.values()) { + scopedLogger.resetErrorsAndWarnings(); + } + } + + public requestScopedLogger(loggerName: string): ScopedLogger { + const existingScopedLogger: ScopedLogger | undefined = this._scopedLoggers.get(loggerName); + if (existingScopedLogger) { + throw new Error(`A named logger with name ${JSON.stringify(loggerName)} has already been requested.`); + } else { + const scopedLogger: ScopedLogger = new ScopedLogger({ + loggerName, + terminalProvider: this._options.terminalProvider, + getShouldPrintStacks: () => this._shouldPrintStacks, + errorHasBeenEmittedCallback: () => (this._hasAnyErrors = true), + warningHasBeenEmittedCallback: () => (this._hasAnyWarnings = true) + }); + this._scopedLoggers.set(loggerName, scopedLogger); + return scopedLogger; + } + } + + public getErrorStrings(fileLocationStyle?: FileLocationStyle): string[] { + const result: string[] = []; + + for (const scopedLogger of this._scopedLoggers.values()) { + result.push( + ...scopedLogger.errors.map( + (error) => + `[${scopedLogger.loggerName}] ` + + LoggingManager.getErrorMessage(error, { format: fileLocationStyle }) + ) + ); + } + + return result; + } + + public getWarningStrings(fileErrorFormat?: FileLocationStyle): string[] { + const result: string[] = []; + + for (const scopedLogger of this._scopedLoggers.values()) { + result.push( + ...scopedLogger.warnings.map( + (warning) => + `[${scopedLogger.loggerName}] ` + + LoggingManager.getErrorMessage(warning, { format: fileErrorFormat }) + ) + ); + } + + return result; + } + + public static getErrorMessage(error: Error, options?: IFileErrorFormattingOptions): string { + if (error instanceof FileError) { + return error.getFormattedErrorMessage(options); + } else { + return error.message; + } + } +} diff --git a/apps/heft/src/pluginFramework/logging/MockScopedLogger.ts b/apps/heft/src/pluginFramework/logging/MockScopedLogger.ts new file mode 100644 index 00000000000..1ffe5ec6c3d --- /dev/null +++ b/apps/heft/src/pluginFramework/logging/MockScopedLogger.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 type { ITerminal } from '@rushstack/terminal'; + +import type { IScopedLogger } from './ScopedLogger'; + +/** + * Implementation of IScopedLogger for use by unit tests. + * + * @internal + */ +export class MockScopedLogger implements IScopedLogger { + public errors: Error[] = []; + public warnings: Error[] = []; + + public loggerName: string = 'mockLogger'; + + public terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this.terminal = terminal; + } + public get hasErrors(): boolean { + return this.errors.length > 0; + } + + public emitError(error: Error): void { + this.errors.push(error); + } + public emitWarning(warning: Error): void { + this.warnings.push(warning); + } + + public resetErrorsAndWarnings(): void { + this.errors.length = 0; + this.warnings.length = 0; + } +} diff --git a/apps/heft/src/pluginFramework/logging/ScopedLogger.ts b/apps/heft/src/pluginFramework/logging/ScopedLogger.ts new file mode 100644 index 00000000000..357289ecc5d --- /dev/null +++ b/apps/heft/src/pluginFramework/logging/ScopedLogger.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + PrefixProxyTerminalProvider, + Terminal, + type ITerminalProvider, + type ITerminal +} from '@rushstack/terminal'; + +import { LoggingManager } from './LoggingManager'; + +/** + * A logger which is used to emit errors and warnings to the console, as well as to write + * to the console. Messaged emitted by the scoped logger are prefixed with the name of the + * scoped logger. + * + * @public + */ +export interface IScopedLogger { + /** + * The name of the scoped logger. Logging messages will be prefixed with this name. + */ + readonly loggerName: string; + /** + * The terminal used to write messages to the console. + */ + readonly terminal: ITerminal; + + /** + * Indicates if the logger has emitted any errors. + */ + readonly hasErrors: boolean; + + /** + * Call this function to emit an error to the heft runtime. + */ + emitError(error: Error): void; + + /** + * Call this function to emit an warning to the heft runtime. + */ + emitWarning(warning: Error): void; + + /** + * Reset the errors and warnings for this scoped logger. + */ + resetErrorsAndWarnings(): void; +} + +export interface IScopedLoggerOptions { + loggerName: string; + terminalProvider: ITerminalProvider; + getShouldPrintStacks: () => boolean; + errorHasBeenEmittedCallback: () => void; + warningHasBeenEmittedCallback: () => void; +} + +export class ScopedLogger implements IScopedLogger { + private readonly _options: IScopedLoggerOptions; + private _errors: Error[] = []; + private _warnings: Error[] = []; + + private get _shouldPrintStacks(): boolean { + // TODO: Consider dumping stacks and more verbose logging to a file + return this._options.getShouldPrintStacks(); + } + + public get errors(): ReadonlyArray { + return [...this._errors]; + } + + public get warnings(): ReadonlyArray { + return [...this._warnings]; + } + + public readonly loggerName: string; + + public readonly terminalProvider: ITerminalProvider; + + public readonly terminal: ITerminal; + + /** + * @internal + */ + public constructor(options: IScopedLoggerOptions) { + this._options = options; + this.loggerName = options.loggerName; + + this.terminalProvider = new PrefixProxyTerminalProvider({ + terminalProvider: options.terminalProvider, + prefix: `[${this.loggerName}] ` + }); + this.terminal = new Terminal(this.terminalProvider); + } + + /** + * {@inheritdoc IScopedLogger.hasErrors} + */ + public get hasErrors(): boolean { + return this._errors.length > 0; + } + + /** + * {@inheritdoc IScopedLogger.emitError} + */ + public emitError(error: Error): void { + this._options.errorHasBeenEmittedCallback(); + this._errors.push(error); + this.terminal.writeErrorLine(`Error: ${LoggingManager.getErrorMessage(error)}`); + if (this._shouldPrintStacks && error.stack) { + this.terminal.writeErrorLine(error.stack); + } + } + + /** + * {@inheritdoc IScopedLogger.emitWarning} + */ + public emitWarning(warning: Error): void { + this._options.warningHasBeenEmittedCallback(); + this._warnings.push(warning); + this.terminal.writeWarningLine(`Warning: ${LoggingManager.getErrorMessage(warning)}`); + if (this._shouldPrintStacks && warning.stack) { + this.terminal.writeWarningLine(warning.stack); + } + } + + /** + * {@inheritdoc IScopedLogger.resetErrorsAndWarnings} + */ + public resetErrorsAndWarnings(): void { + this._errors = []; + this._warnings = []; + } +} diff --git a/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts new file mode 100644 index 00000000000..0a5d3be7f65 --- /dev/null +++ b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts @@ -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. + +import path from 'node:path'; + +import { Path } from '@rushstack/node-core-library'; + +import { + serializeBuildInfo, + deserializeBuildInfo, + type IIncrementalBuildInfo, + type ISerializedIncrementalBuildInfo +} from '../IncrementalBuildInfo'; + +const posixBuildInfo: IIncrementalBuildInfo = { + configHash: 'foobar', + inputFileVersions: new Map([ + ['/a/b/c/file1', '1'], + ['/a/b/c/file2', '2'] + ]), + fileDependencies: new Map([ + ['/a/b/c/output1', ['/a/b/c/file1']], + ['/a/b/c/output2', ['/a/b/c/file1', '/a/b/c/file2']] + ]) +}; + +const win32BuildInfo: IIncrementalBuildInfo = { + configHash: 'foobar', + inputFileVersions: new Map([ + ['A:\\b\\c\\file1', '1'], + ['A:\\b\\c\\file2', '2'] + ]), + fileDependencies: new Map([ + ['A:\\b\\c\\output1', ['A:\\b\\c\\file1']], + ['A:\\b\\c\\output2', ['A:\\b\\c\\file1', 'A:\\b\\c\\file2']] + ]) +}; + +const posixBasePath: string = '/a/b/temp'; +const win32BasePath: string = 'A:\\b\\temp'; + +function posixToPortable(absolutePath: string): string { + return path.posix.relative(posixBasePath, absolutePath); +} +function portableToPosix(portablePath: string): string { + return path.posix.resolve(posixBasePath, portablePath); +} + +function win32ToPortable(absolutePath: string): string { + return Path.convertToSlashes(path.win32.relative(win32BasePath, absolutePath)); +} +function portableToWin32(portablePath: string): string { + return path.win32.resolve(win32BasePath, portablePath); +} + +describe(serializeBuildInfo.name, () => { + it('Round trips correctly (POSIX)', () => { + const serialized: ISerializedIncrementalBuildInfo = serializeBuildInfo(posixBuildInfo, posixToPortable); + + const deserialized: IIncrementalBuildInfo = deserializeBuildInfo(serialized, portableToPosix); + + expect(deserialized).toEqual(posixBuildInfo); + }); + + it('Round trips correctly (Win32)', () => { + const serialized: ISerializedIncrementalBuildInfo = serializeBuildInfo(win32BuildInfo, win32ToPortable); + + const deserialized: IIncrementalBuildInfo = deserializeBuildInfo(serialized, portableToWin32); + + expect(deserialized).toEqual(win32BuildInfo); + }); + + it('Converts (POSIX to Win32)', () => { + const serialized: ISerializedIncrementalBuildInfo = serializeBuildInfo(posixBuildInfo, posixToPortable); + + const deserialized: IIncrementalBuildInfo = deserializeBuildInfo(serialized, portableToWin32); + + expect(deserialized).toEqual(win32BuildInfo); + }); + + it('Converts (Win32 to POSIX)', () => { + const serialized: ISerializedIncrementalBuildInfo = serializeBuildInfo(win32BuildInfo, win32ToPortable); + + const deserialized: IIncrementalBuildInfo = deserializeBuildInfo(serialized, portableToPosix); + + expect(deserialized).toEqual(posixBuildInfo); + }); + + it('Has expected serialized format', () => { + const serializedPosix: ISerializedIncrementalBuildInfo = serializeBuildInfo( + posixBuildInfo, + posixToPortable + ); + const serializedWin32: ISerializedIncrementalBuildInfo = serializeBuildInfo( + win32BuildInfo, + win32ToPortable + ); + + expect(serializedPosix).toMatchSnapshot('posix'); + expect(serializedWin32).toMatchSnapshot('win32'); + + expect(serializedPosix).toEqual(serializedWin32); + }); +}); diff --git a/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap new file mode 100644 index 00000000000..390725566a9 --- /dev/null +++ b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`serializeBuildInfo Has expected serialized format: posix 1`] = ` +Object { + "configHash": "foobar", + "fileDependencies": Object { + "../c/output1": Array [ + 0, + ], + "../c/output2": Array [ + 0, + 1, + ], + }, + "inputFileVersions": Object { + "../c/file1": "1", + "../c/file2": "2", + }, +} +`; + +exports[`serializeBuildInfo Has expected serialized format: win32 1`] = ` +Object { + "configHash": "foobar", + "fileDependencies": Object { + "../c/output1": Array [ + 0, + ], + "../c/output2": Array [ + 0, + 1, + ], + }, + "inputFileVersions": Object { + "../c/file1": "1", + "../c/file2": "2", + }, +} +`; diff --git a/apps/heft/src/plugins/CopyFilesPlugin.ts b/apps/heft/src/plugins/CopyFilesPlugin.ts new file mode 100644 index 00000000000..2c9d47347a1 --- /dev/null +++ b/apps/heft/src/plugins/CopyFilesPlugin.ts @@ -0,0 +1,308 @@ +// 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 * as fs from 'node:fs'; +import * as path from 'node:path'; + +import { AlreadyExistsBehavior, FileSystem, Async } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { Constants } from '../utilities/Constants'; +import { + asAbsoluteFileSelectionSpecifier, + getFileSelectionSpecifierPathsAsync, + type IFileSelectionSpecifier +} from './FileGlobSpecifier'; +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; +import type { IHeftTaskSession, IHeftTaskFileOperations } from '../pluginFramework/HeftTaskSession'; +import type { WatchFileSystemAdapter } from '../utilities/WatchFileSystemAdapter'; +import { + type IIncrementalBuildInfo, + makePathRelative, + tryReadBuildInfoAsync, + writeBuildInfoAsync +} from '../pluginFramework/IncrementalBuildInfo'; + +/** + * Used to specify a selection of files to copy from a specific source folder to one + * or more destination folders. + * + * @public + */ +export interface ICopyOperation extends IFileSelectionSpecifier { + /** + * Absolute paths to folders which files or folders should be copied to. + */ + destinationFolders: string[]; + + /** + * Copy only the file and discard the relative path from the source folder. + */ + flatten?: boolean; + + /** + * Hardlink files instead of copying. + * + * @remarks + * If the sourcePath is a folder, the contained directory structure will be re-created + * and all files will be individually hardlinked. This means that folders will be new + * filesystem entities and will have separate folder metadata, while the contained files + * will maintain normal hardlink behavior. This is done since folders do not have a + * cross-platform equivalent of a hardlink, and since file symlinks provide fundamentally + * different functionality in comparison to hardlinks. + */ + hardlink?: boolean; +} + +/** + * Used to specify a selection of files to copy from a specific source folder to one + * or more destination folders. + * + * @public + */ +export interface IIncrementalCopyOperation extends ICopyOperation { + /** + * If true, the file will be copied only if the source file is contained in the + * IHeftTaskRunIncrementalHookOptions.changedFiles map. + */ + onlyIfChanged?: boolean; +} + +interface ICopyFilesPluginOptions { + copyOperations: ICopyOperation[]; +} + +interface ICopyDescriptor { + sourcePath: string; + destinationPath: string; + hardlink: boolean; +} + +export function asAbsoluteCopyOperation( + rootFolderPath: string, + copyOperation: ICopyOperation +): ICopyOperation { + const absoluteCopyOperation: ICopyOperation = asAbsoluteFileSelectionSpecifier( + rootFolderPath, + copyOperation + ); + absoluteCopyOperation.destinationFolders = copyOperation.destinationFolders.map((folder) => + path.resolve(rootFolderPath, folder) + ); + return absoluteCopyOperation; +} + +export function asRelativeCopyOperation( + rootFolderPath: string, + copyOperation: ICopyOperation +): ICopyOperation { + return { + ...copyOperation, + destinationFolders: copyOperation.destinationFolders.map((folder) => + makePathRelative(folder, rootFolderPath) + ), + sourcePath: copyOperation.sourcePath && makePathRelative(copyOperation.sourcePath, rootFolderPath) + }; +} + +export async function copyFilesAsync( + copyOperations: Iterable, + terminal: ITerminal, + buildInfoPath: string, + configHash: string, + watchFileSystemAdapter?: WatchFileSystemAdapter +): Promise { + const copyDescriptorByDestination: Map = await _getCopyDescriptorsAsync( + copyOperations, + watchFileSystemAdapter + ); + + await _copyFilesInnerAsync(copyDescriptorByDestination, configHash, buildInfoPath, terminal); +} + +async function _getCopyDescriptorsAsync( + copyConfigurations: Iterable, + fileSystemAdapter: WatchFileSystemAdapter | undefined +): Promise> { + // Create a map to deduplicate and prevent double-writes + // resolvedDestinationFilePath -> descriptor + const copyDescriptorByDestination: Map = new Map(); + + await Async.forEachAsync( + copyConfigurations, + async (copyConfiguration: ICopyOperation) => { + // "sourcePath" is required to be a folder. To copy a single file, put the parent folder in "sourcePath" + // and the filename in "includeGlobs". + const sourceFolder: string = copyConfiguration.sourcePath!; + const sourceFiles: Map = await getFileSelectionSpecifierPathsAsync({ + fileGlobSpecifier: copyConfiguration, + fileSystemAdapter + }); + + // Dedupe and throw if a double-write is detected + for (const destinationFolderPath of copyConfiguration.destinationFolders) { + // We only need to care about the keys of the map since we know all the keys are paths to files + for (const sourceFilePath of sourceFiles.keys()) { + // Only include the relative path from the sourceFolder if flatten is false + const resolvedDestinationPath: string = path.resolve( + destinationFolderPath, + copyConfiguration.flatten + ? path.basename(sourceFilePath) + : path.relative(sourceFolder, sourceFilePath) + ); + + // Throw if a duplicate copy target with a different source or options is specified + const existingDestinationCopyDescriptor: ICopyDescriptor | undefined = + copyDescriptorByDestination.get(resolvedDestinationPath); + if (existingDestinationCopyDescriptor) { + if ( + existingDestinationCopyDescriptor.sourcePath === sourceFilePath && + existingDestinationCopyDescriptor.hardlink === !!copyConfiguration.hardlink + ) { + // Found a duplicate, avoid adding again + continue; + } + throw new Error( + `Cannot copy multiple files to the same destination "${resolvedDestinationPath}".` + ); + } + + // Finally, default hardlink to false, add to the result, and add to the map for deduping + const processedCopyDescriptor: ICopyDescriptor = { + sourcePath: sourceFilePath, + destinationPath: resolvedDestinationPath, + hardlink: !!copyConfiguration.hardlink + }; + + copyDescriptorByDestination.set(resolvedDestinationPath, processedCopyDescriptor); + } + } + }, + { concurrency: Constants.maxParallelism } + ); + + return copyDescriptorByDestination; +} + +async function _copyFilesInnerAsync( + copyDescriptors: Map, + configHash: string, + buildInfoPath: string, + terminal: ITerminal +): Promise { + if (copyDescriptors.size === 0) { + return; + } + + let oldBuildInfo: IIncrementalBuildInfo | undefined = await tryReadBuildInfoAsync(buildInfoPath); + if (oldBuildInfo && oldBuildInfo.configHash !== configHash) { + terminal.writeVerboseLine(`File copy configuration changed, discarding incremental state.`); + oldBuildInfo = undefined; + } + + // Since in watch mode only changed files will get passed in, need to ensure that all files from + // the previous build are still tracked. + const inputFileVersions: Map = new Map(oldBuildInfo?.inputFileVersions); + + const buildInfo: IIncrementalBuildInfo = { + configHash, + inputFileVersions + }; + + const allInputFiles: Set = new Set(); + for (const copyDescriptor of copyDescriptors.values()) { + allInputFiles.add(copyDescriptor.sourcePath); + } + + await Async.forEachAsync( + allInputFiles, + async (inputFilePath: string) => { + const fileContent: Buffer = await FileSystem.readFileToBufferAsync(inputFilePath); + const fileHash: string = createHash('sha256').update(fileContent).digest('base64'); + inputFileVersions.set(inputFilePath, fileHash); + }, + { + concurrency: Constants.maxParallelism + } + ); + + const copyDescriptorsWithWork: ICopyDescriptor[] = []; + for (const copyDescriptor of copyDescriptors.values()) { + const { sourcePath } = copyDescriptor; + + const sourceFileHash: string | undefined = inputFileVersions.get(sourcePath); + if (!sourceFileHash) { + throw new Error(`Missing hash for input file: ${sourcePath}`); + } + + if (oldBuildInfo?.inputFileVersions.get(sourcePath) === sourceFileHash) { + continue; + } + + copyDescriptorsWithWork.push(copyDescriptor); + } + + if (copyDescriptorsWithWork.length === 0) { + terminal.writeLine('All requested file copy operations are up to date. Nothing to do.'); + return; + } + + let copiedFileCount: number = 0; + let linkedFileCount: number = 0; + await Async.forEachAsync( + copyDescriptorsWithWork, + async (copyDescriptor: ICopyDescriptor) => { + if (copyDescriptor.hardlink) { + linkedFileCount++; + await FileSystem.createHardLinkAsync({ + linkTargetPath: copyDescriptor.sourcePath, + newLinkPath: copyDescriptor.destinationPath, + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite + }); + terminal.writeVerboseLine( + `Linked "${copyDescriptor.sourcePath}" to "${copyDescriptor.destinationPath}".` + ); + } else { + copiedFileCount++; + await FileSystem.copyFilesAsync({ + sourcePath: copyDescriptor.sourcePath, + destinationPath: copyDescriptor.destinationPath, + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite + }); + terminal.writeVerboseLine( + `Copied "${copyDescriptor.sourcePath}" to "${copyDescriptor.destinationPath}".` + ); + } + }, + { concurrency: Constants.maxParallelism } + ); + + terminal.writeLine( + `Copied ${copiedFileCount} file${copiedFileCount === 1 ? '' : 's'} and ` + + `linked ${linkedFileCount} file${linkedFileCount === 1 ? '' : 's'}` + ); + + await writeBuildInfoAsync(buildInfo, buildInfoPath); +} + +const PLUGIN_NAME: 'copy-files-plugin' = 'copy-files-plugin'; + +export default class CopyFilesPlugin implements IHeftTaskPlugin { + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: ICopyFilesPluginOptions + ): void { + taskSession.hooks.registerFileOperations.tap( + PLUGIN_NAME, + (operations: IHeftTaskFileOperations): IHeftTaskFileOperations => { + for (const operation of pluginOptions.copyOperations) { + operations.copyOperations.add(operation); + } + return operations; + } + ); + } +} diff --git a/apps/heft/src/plugins/DeleteFilesPlugin.ts b/apps/heft/src/plugins/DeleteFilesPlugin.ts new file mode 100644 index 00000000000..73976dad8f4 --- /dev/null +++ b/apps/heft/src/plugins/DeleteFilesPlugin.ts @@ -0,0 +1,169 @@ +// 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 'node:fs'; + +import { FileSystem, Async } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { Constants } from '../utilities/Constants'; +import { + getFileSelectionSpecifierPathsAsync, + asAbsoluteFileSelectionSpecifier, + type IFileSelectionSpecifier +} from './FileGlobSpecifier'; +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; +import type { IHeftTaskSession, IHeftTaskFileOperations } from '../pluginFramework/HeftTaskSession'; + +/** + * Used to specify a selection of source files to delete from the specified source folder. + * + * @public + */ +export interface IDeleteOperation extends IFileSelectionSpecifier {} + +interface IDeleteFilesPluginOptions { + deleteOperations: IDeleteOperation[]; +} + +interface IGetPathsToDeleteResult { + filesToDelete: Set; + foldersToDelete: Set; +} + +async function _getPathsToDeleteAsync( + rootFolderPath: string, + deleteOperations: Iterable +): Promise { + const result: IGetPathsToDeleteResult = { + filesToDelete: new Set(), + foldersToDelete: new Set() + }; + + await Async.forEachAsync( + deleteOperations, + async (deleteOperation: IDeleteOperation) => { + const absoluteSpecifier: IDeleteOperation = asAbsoluteFileSelectionSpecifier( + rootFolderPath, + deleteOperation + ); + + // Glob the files under the source path and add them to the set of files to delete + const sourcePaths: Map = await getFileSelectionSpecifierPathsAsync({ + fileGlobSpecifier: absoluteSpecifier, + includeFolders: true + }); + for (const [sourcePath, dirent] of sourcePaths) { + // If the sourcePath is a folder, add it to the foldersToDelete set. Otherwise, add it to + // the filesToDelete set. Symlinks and junctions are treated as files, and thus will fall + // into the filesToDelete set. + if (dirent.isDirectory()) { + result.foldersToDelete.add(sourcePath); + } else { + result.filesToDelete.add(sourcePath); + } + } + }, + { concurrency: Constants.maxParallelism } + ); + + return result; +} + +export async function deleteFilesAsync( + rootFolderPath: string, + deleteOperations: Iterable, + terminal: ITerminal +): Promise { + const pathsToDelete: IGetPathsToDeleteResult = await _getPathsToDeleteAsync( + rootFolderPath, + deleteOperations + ); + await _deleteFilesInnerAsync(pathsToDelete, terminal); +} + +async function _deleteFilesInnerAsync( + pathsToDelete: IGetPathsToDeleteResult, + terminal: ITerminal +): Promise { + let deletedFiles: number = 0; + let deletedFolders: number = 0; + + const { filesToDelete, foldersToDelete } = pathsToDelete; + + await Async.forEachAsync( + filesToDelete, + async (pathToDelete: string) => { + try { + await FileSystem.deleteFileAsync(pathToDelete, { throwIfNotExists: true }); + terminal.writeVerboseLine(`Deleted "${pathToDelete}".`); + deletedFiles++; + } catch (error) { + // If it doesn't exist, we can ignore the error. + if (!FileSystem.isNotExistError(error)) { + throw error; + } + } + }, + { concurrency: Constants.maxParallelism } + ); + + // Reverse the list of matching folders. Assuming that the list of folders came from + // the globber, the folders will be specified in tree-walk order, so by reversing the + // list we delete the deepest folders first and avoid not-exist errors for subfolders + // of an already-deleted parent folder. + const reversedFoldersToDelete: string[] = Array.from(foldersToDelete).reverse(); + + // Clear out any folders that were encountered during the file deletion process. This + // will recursively delete the folder and it's contents. There are two scenarios that + // this handles: + // - Deletions of empty folder structures (ex. when the delete glob is '**/*') + // - Deletions of folders that still contain files (ex. when the delete glob is 'lib') + // In the latter scenario, the count of deleted files will not be tracked. However, + // this is a fair trade-off for the performance benefit of not having to glob the + // folder structure again. + await Async.forEachAsync( + reversedFoldersToDelete, + async (folderToDelete: string) => { + try { + await FileSystem.deleteFolderAsync(folderToDelete); + terminal.writeVerboseLine(`Deleted folder "${folderToDelete}".`); + deletedFolders++; + } catch (error) { + // If it doesn't exist, we can ignore the error. + if (!FileSystem.isNotExistError(error)) { + throw error; + } + } + }, + { concurrency: Constants.maxParallelism } + ); + + if (deletedFiles > 0 || deletedFolders > 0) { + terminal.writeLine( + `Deleted ${deletedFiles} file${deletedFiles !== 1 ? 's' : ''} ` + + `and ${deletedFolders} folder${deletedFolders !== 1 ? 's' : ''}` + ); + } +} + +const PLUGIN_NAME: 'delete-files-plugin' = 'delete-files-plugin'; + +export default class DeleteFilesPlugin implements IHeftTaskPlugin { + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IDeleteFilesPluginOptions + ): void { + taskSession.hooks.registerFileOperations.tap( + PLUGIN_NAME, + (fileOperations: IHeftTaskFileOperations): IHeftTaskFileOperations => { + for (const deleteOperation of pluginOptions.deleteOperations) { + fileOperations.deleteOperations.add(deleteOperation); + } + return fileOperations; + } + ); + } +} diff --git a/apps/heft/src/plugins/FileGlobSpecifier.ts b/apps/heft/src/plugins/FileGlobSpecifier.ts new file mode 100644 index 00000000000..96d3223dd5a --- /dev/null +++ b/apps/heft/src/plugins/FileGlobSpecifier.ts @@ -0,0 +1,229 @@ +// 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 'node:fs'; +import * as path from 'node:path'; + +import glob, { type FileSystemAdapter, type Entry } from 'fast-glob'; + +import { Async } from '@rushstack/node-core-library'; + +import type { IWatchFileSystemAdapter, IWatchedFileState } from '../utilities/WatchFileSystemAdapter'; + +/** + * Used to specify a selection of one or more files. + * + * @public + */ +export interface IFileSelectionSpecifier { + /** + * Absolute path to the target. The provided sourcePath can be to a file or a folder. If + * fileExtensions, excludeGlobs, or includeGlobs are specified, the sourcePath is assumed + * to be a folder. If it is not a folder, an error will be thrown. + */ + sourcePath?: string; + + /** + * File extensions that should be included from the source folder. Only supported when the sourcePath + * is a folder. + */ + fileExtensions?: string[]; + + /** + * Globs that should be explicitly excluded. This takes precedence over globs listed in "includeGlobs" and + * files that match the file extensions provided in "fileExtensions". Only supported when the sourcePath + * is a folder. + */ + excludeGlobs?: string[]; + + /** + * Globs that should be explicitly included. Only supported when the sourcePath is a folder. + */ + includeGlobs?: string[]; +} + +/** + * A supported subset of options used when globbing files. + * + * @public + */ +export interface IGlobOptions { + /** + * Current working directory that the glob pattern will be applied to. + */ + cwd?: string; + + /** + * Whether or not the returned file paths should be absolute. + * + * @defaultValue false + */ + absolute?: boolean; + + /** + * Patterns to ignore when globbing. + */ + ignore?: string[]; + + /** + * Whether or not to include dot files when globbing. + * + * @defaultValue false + */ + dot?: boolean; +} + +export interface IGetFileSelectionSpecifierPathsOptions { + fileGlobSpecifier: IFileSelectionSpecifier; + includeFolders?: boolean; + fileSystemAdapter?: FileSystemAdapter; +} + +/** + * Glob a set of files and return a list of paths that match the provided patterns. + * + * @param patterns - Glob patterns to match against. + * @param options - Options that are used when globbing the set of files. + * + * @public + */ +export type GlobFn = (pattern: string | string[], options?: IGlobOptions | undefined) => Promise; +/** + * Glob a set of files and return a map of paths that match the provided patterns to their current state in the watcher. + * + * @param patterns - Glob patterns to match against. + * @param options - Options that are used when globbing the set of files. + * + * @public + */ +export type WatchGlobFn = ( + pattern: string | string[], + options?: IGlobOptions | undefined +) => Promise>; + +function isWatchFileSystemAdapter(adapter: FileSystemAdapter): adapter is IWatchFileSystemAdapter { + return !!(adapter as IWatchFileSystemAdapter).getStateAndTrackAsync; +} + +export interface IWatchGlobOptions extends IGlobOptions { + fs: IWatchFileSystemAdapter; +} + +export async function watchGlobAsync( + pattern: string | string[], + options: IWatchGlobOptions +): Promise> { + const { fs, cwd, absolute } = options; + if (!cwd) { + throw new Error(`"cwd" must be set in the options passed to "watchGlobAsync"`); + } + + const rawFiles: string[] = await glob(pattern, options); + + const results: Map = new Map(); + await Async.forEachAsync( + rawFiles, + async (file: string) => { + const state: IWatchedFileState = await fs.getStateAndTrackAsync( + absolute ? path.normalize(file) : path.resolve(cwd, file) + ); + results.set(file, state); + }, + { + concurrency: 20 + } + ); + + return results; +} + +export async function getFileSelectionSpecifierPathsAsync( + options: IGetFileSelectionSpecifierPathsOptions +): Promise> { + const { fileGlobSpecifier, includeFolders, fileSystemAdapter } = options; + const rawEntries: Entry[] = await glob(fileGlobSpecifier.includeGlobs!, { + fs: fileSystemAdapter, + cwd: fileGlobSpecifier.sourcePath, + ignore: fileGlobSpecifier.excludeGlobs, + onlyFiles: !includeFolders, + dot: true, + absolute: true, + objectMode: true + }); + + let results: Map; + if (fileSystemAdapter && isWatchFileSystemAdapter(fileSystemAdapter)) { + results = new Map(); + await Async.forEachAsync( + rawEntries, + async (entry: Entry) => { + const { path: filePath, dirent } = entry; + if (entry.dirent.isDirectory()) { + return; + } + const state: IWatchedFileState = await fileSystemAdapter.getStateAndTrackAsync( + path.normalize(filePath) + ); + if (state.changed) { + results.set(filePath, dirent as fs.Dirent); + } + }, + { + concurrency: 20 + } + ); + } else { + results = new Map(rawEntries.map((entry) => [entry.path, entry.dirent as fs.Dirent])); + } + + return results; +} + +export function asAbsoluteFileSelectionSpecifier( + rootPath: string, + fileGlobSpecifier: TSpecifier +): TSpecifier { + const { sourcePath } = fileGlobSpecifier; + return { + ...fileGlobSpecifier, + sourcePath: sourcePath ? path.resolve(rootPath, sourcePath) : rootPath, + includeGlobs: getIncludedGlobPatterns(fileGlobSpecifier), + fileExtensions: undefined + }; +} + +function getIncludedGlobPatterns(fileGlobSpecifier: IFileSelectionSpecifier): string[] { + const patternsToGlob: Set = new Set(); + + // Glob file extensions with a specific glob to increase perf + const escapedFileExtensions: Set = new Set(); + for (const fileExtension of fileGlobSpecifier.fileExtensions || []) { + let escapedFileExtension: string; + if (fileExtension.charAt(0) === '.') { + escapedFileExtension = fileExtension.slice(1); + } else { + escapedFileExtension = fileExtension; + } + + escapedFileExtension = glob.escapePath(escapedFileExtension); + escapedFileExtensions.add(escapedFileExtension); + } + + if (escapedFileExtensions.size > 1) { + patternsToGlob.add(`**/*.{${[...escapedFileExtensions].join(',')}}`); + } else if (escapedFileExtensions.size === 1) { + patternsToGlob.add(`**/*.${[...escapedFileExtensions][0]}`); + } + + // Now include the other globs as well + for (const include of fileGlobSpecifier.includeGlobs || []) { + patternsToGlob.add(include); + } + + // Include a default glob if none are specified + if (!patternsToGlob.size) { + patternsToGlob.add('**/*'); + } + + return [...patternsToGlob]; +} diff --git a/apps/heft/src/plugins/NodeServicePlugin.ts b/apps/heft/src/plugins/NodeServicePlugin.ts new file mode 100644 index 00000000000..dfb8e42760f --- /dev/null +++ b/apps/heft/src/plugins/NodeServicePlugin.ts @@ -0,0 +1,414 @@ +// 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 'node:child_process'; +import * as process from 'node:process'; + +import { InternalError, SubprocessTerminator } from '@rushstack/node-core-library'; + +import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { + IHeftTaskSession, + IHeftTaskRunIncrementalHookOptions +} from '../pluginFramework/HeftTaskSession'; +import type { IScopedLogger } from '../pluginFramework/logging/ScopedLogger'; +import { CoreConfigFiles } from '../utilities/CoreConfigFiles'; + +const PLUGIN_NAME: 'node-service-plugin' = 'node-service-plugin'; +const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; + +export interface INodeServicePluginCompleteConfiguration { + commandName: string; + ignoreMissingScript: boolean; + waitForTerminateMs: number; + waitForKillMs: number; +} + +export interface INodeServicePluginConfiguration extends Partial {} + +enum State { + /** + * The service process is not running, and _activeChildProcess is undefined. + * + * In this state, there may or may not be a timeout scheduled that will later restart the service. + */ + Stopped, + + /** + * The service process is running normally. + */ + Running, + + /** + * The SIGTERM signal has been sent to the service process, and we are waiting for it + * to shut down gracefully. + * + * NOTE: On Windows OS, SIGTERM is skipped and we proceed directly to SIGKILL. + */ + Stopping, + + /** + * The SIGKILL signal has been sent to forcibly terminate the service process, and we are waiting + * to confirm that the operation has completed. + */ + Killing +} + +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; + private _childProcessExitPromiseRejectFn: ((e: unknown) => void) | undefined; + private _state: State = State.Stopped; + private _logger!: IScopedLogger; + + /** + * The state machine schedules at most one setInterval() timeout at any given time. It is for: + * + * - waitForTerminateMs in State.Stopping + * - waitForKillMs in State.Killing + */ + private _timeout: NodeJS.Timeout | undefined = undefined; + + /** + * The data read from the node-service.json config file, or "undefined" if the file is missing. + */ + private _rawConfiguration: INodeServicePluginConfiguration | undefined = undefined; + + /** + * The effective configuration, with defaults applied. + */ + private _configuration!: INodeServicePluginCompleteConfiguration; + + /** + * The script body obtained from the "scripts" section in the project's package.json. + */ + private _shellCommand: string | undefined; + + private _pluginEnabled: boolean = false; + + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + // Set this immediately to make it available to the internal methods that use it + this._logger = taskSession.logger; + + const isServeMode: boolean = taskSession.parameters.getFlagParameter(SERVE_PARAMETER_LONG_NAME).value; + + if (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.` + ); + } + + if (!isServeMode) { + taskSession.logger.terminal.writeVerboseLine( + `Not launching the service because the "${SERVE_PARAMETER_LONG_NAME}" parameter was not specified` + ); + return; + } + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runCommandAsync(taskSession, heftConfiguration); + } + ); + } + + private async _loadStageConfigurationAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + if (!this._rawConfiguration) { + this._rawConfiguration = await CoreConfigFiles.tryLoadNodeServiceConfigurationFileAsync( + taskSession.logger.terminal, + heftConfiguration.buildFolderPath, + heftConfiguration.rigConfig + ); + + // defaults + this._configuration = { + commandName: 'serve', + ignoreMissingScript: false, + waitForTerminateMs: 2000, + waitForKillMs: 2000 + }; + + // TODO: @rushstack/heft-config-file should be able to read a *.defaults.json file + if (this._rawConfiguration) { + this._pluginEnabled = true; + + if (this._rawConfiguration.commandName !== undefined) { + this._configuration.commandName = this._rawConfiguration.commandName; + } + if (this._rawConfiguration.ignoreMissingScript !== undefined) { + this._configuration.ignoreMissingScript = this._rawConfiguration.ignoreMissingScript; + } + if (this._rawConfiguration.waitForTerminateMs !== undefined) { + this._configuration.waitForTerminateMs = this._rawConfiguration.waitForTerminateMs; + } + if (this._rawConfiguration.waitForKillMs !== undefined) { + this._configuration.waitForKillMs = this._rawConfiguration.waitForKillMs; + } + + this._shellCommand = (heftConfiguration.projectPackageJson.scripts || {})[ + this._configuration.commandName + ]; + + if (this._shellCommand === undefined) { + if (this._configuration.ignoreMissingScript) { + taskSession.logger.terminal.writeLine( + `The node service cannot be started because the project's package.json` + + ` does not have a "${this._configuration.commandName}" script` + ); + } else { + throw new Error( + `The node service cannot be started because the project's package.json ` + + `does not have a "${this._configuration.commandName}" script` + ); + } + this._pluginEnabled = false; + } + } else { + throw new Error( + 'The node service cannot be started because the task config file was not found: ' + + CoreConfigFiles.nodeServiceConfigurationProjectRelativeFilePath + ); + } + } + } + + private async _runCommandAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + await this._loadStageConfigurationAsync(taskSession, heftConfiguration); + if (!this._pluginEnabled) { + return; + } + + this._logger.terminal.writeLine(`Starting Node service...`); + await this._stopChildAsync(); + this._startChild(); + } + + private async _stopChildAsync(): Promise { + if (this._state !== State.Running) { + if (this._childProcessExitPromise) { + // If we have an active process but are not in the running state, we must be in the process of + // terminating or the process is already stopped. + await this._childProcessExitPromise; + } + return; + } + + if (NodeServicePlugin._isWindows) { + // On Windows, SIGTERM can kill Cmd.exe and leave its children running in the background + this._transitionToKilling(); + } else { + if (!this._activeChildProcess) { + // All the code paths that set _activeChildProcess=undefined should also leave the Running state + throw new InternalError('_activeChildProcess should not be undefined'); + } + + this._state = State.Stopping; + this._logger.terminal.writeVerboseLine('Sending SIGTERM to gracefully shut down the service process'); + + // Passing a negative PID terminates the entire group instead of just the one process. + // This works because we set detached=true for child_process.spawn() + + const pid: number | undefined = this._activeChildProcess.pid; + if (pid !== undefined) { + // If pid was undefined, the process failed to spawn + process.kill(-pid, 'SIGTERM'); + } + + this._clearTimeout(); + this._timeout = setTimeout(() => { + try { + if (this._state !== State.Stopped) { + this._logger.terminal.writeWarningLine('The service process is taking too long to terminate'); + this._transitionToKilling(); + } + } catch (e: unknown) { + this._childProcessExitPromiseRejectFn!(e); + } + }, this._configuration.waitForTerminateMs); + } + + await this._childProcessExitPromise; + } + + private _transitionToKilling(): void { + this._state = State.Killing; + + if (!this._activeChildProcess) { + // All the code paths that set _activeChildProcess=undefined should also leave the Running state + throw new InternalError('_activeChildProcess should not be undefined'); + } + + this._logger.terminal.writeVerboseLine('Attempting to killing the service process'); + + SubprocessTerminator.killProcessTree(this._activeChildProcess, SubprocessTerminator.RECOMMENDED_OPTIONS); + + this._clearTimeout(); + this._timeout = setTimeout(() => { + try { + if (this._state !== State.Stopped) { + this._logger.terminal.writeErrorLine( + 'Abandoning the service process because it could not be killed' + ); + this._transitionToStopped(); + } + } catch (e: unknown) { + this._childProcessExitPromiseRejectFn!(e); + } + }, this._configuration.waitForKillMs); + } + + private _transitionToStopped(): void { + // Failed to start + this._state = State.Stopped; + this._clearTimeout(); + this._activeChildProcess = undefined; + this._childProcessExitPromiseResolveFn!(); + } + + private _startChild(): void { + if (this._state !== State.Stopped) { + throw new InternalError('Invalid state'); + } + + this._state = State.Running; + this._clearTimeout(); + this._logger.terminal.writeLine(`Invoking command: "${this._shellCommand!}"`); + + const childProcess: child_process.ChildProcess = child_process.spawn(this._shellCommand!, { + shell: true, + ...SubprocessTerminator.RECOMMENDED_OPTIONS + }); + SubprocessTerminator.killProcessTreeOnExit(childProcess, SubprocessTerminator.RECOMMENDED_OPTIONS); + + const childPid: number | undefined = childProcess.pid; + if (childPid === undefined) { + throw new InternalError(`Failed to spawn child process`); + } + this._logger.terminal.writeVerboseLine(`Started service process #${childPid}`); + + // Create a promise that resolves when the child process exits + this._childProcessExitPromise = new Promise((resolve, reject) => { + this._childProcessExitPromiseResolveFn = resolve; + this._childProcessExitPromiseRejectFn = reject; + + childProcess.stdout?.on('data', (data: Buffer) => { + this._logger.terminal.write(data.toString()); + }); + + childProcess.stderr?.on('data', (data: Buffer) => { + this._logger.terminal.writeError(data.toString()); + }); + + childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null): void => { + try { + // The 'close' event is emitted after a process has ended and the stdio streams of a child process + // have been closed. This is distinct from the 'exit' event, since multiple processes might share the + // same stdio streams. The 'close' event will always emit after 'exit' was already emitted, + // or 'error' if the child failed to spawn. + + if (this._state === State.Running) { + this._logger.terminal.writeWarningLine( + `The service process #${childPid} terminated unexpectedly` + + this._formatCodeOrSignal(exitCode, signal) + ); + this._transitionToStopped(); + return; + } + + if (this._state === State.Stopping || this._state === State.Killing) { + this._logger.terminal.writeVerboseLine( + `The service process #${childPid} terminated successfully` + + this._formatCodeOrSignal(exitCode, signal) + ); + this._transitionToStopped(); + return; + } + } catch (e: unknown) { + reject(e); + } + }); + + childProcess.on('exit', (code: number | null, signal: string | null) => { + try { + // Under normal conditions we don't reject the promise here, because 'data' events can continue + // to fire as data is flushed, before finally concluding with the 'close' event. + this._logger.terminal.writeVerboseLine( + `The service process fired its "exit" event` + this._formatCodeOrSignal(code, signal) + ); + } catch (e: unknown) { + reject(e); + } + }); + + childProcess.on('error', (err: Error) => { + try { + // "The 'error' event is emitted whenever: + // 1. The process could not be spawned, or + // 2. The process could not be killed, or + // 3. Sending a message to the child process failed. + // + // The 'exit' event may or may not fire after an error has occurred. When listening to both the 'exit' + // and 'error' events, guard against accidentally invoking handler functions multiple times." + + if (this._state === State.Running) { + this._logger.terminal.writeErrorLine(`Failed to start: ` + err.toString()); + this._transitionToStopped(); + return; + } + + if (this._state === State.Stopping) { + this._logger.terminal.writeWarningLine( + `The service process #${childPid} rejected the shutdown signal: ` + err.toString() + ); + this._transitionToKilling(); + return; + } + + if (this._state === State.Killing) { + this._logger.terminal.writeErrorLine( + `The service process #${childPid} could not be killed: ` + err.toString() + ); + this._transitionToStopped(); + return; + } + } catch (e: unknown) { + reject(e); + } + }); + }); + + this._activeChildProcess = childProcess; + } + + private _clearTimeout(): void { + if (this._timeout) { + clearTimeout(this._timeout); + this._timeout = undefined; + } + } + + private _formatCodeOrSignal(code: number | null | undefined, signal: string | null | undefined): string { + if (signal) { + return ` (signal=${code})`; + } + if (typeof code === 'number') { + return ` (exit code ${code})`; + } + return ''; + } +} diff --git a/apps/heft/src/plugins/RunScriptPlugin.ts b/apps/heft/src/plugins/RunScriptPlugin.ts new file mode 100644 index 00000000000..6c74d9dfd56 --- /dev/null +++ b/apps/heft/src/plugins/RunScriptPlugin.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 * as path from 'node:path'; + +import type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; +import type { IHeftTaskSession, IHeftTaskRunHookOptions } from '../pluginFramework/HeftTaskSession'; + +interface IRunScriptPluginOptions { + scriptPath: string; + scriptOptions: Record; +} + +/** + * Options provided to scripts that are run using the RunScriptPlugin. + * + * @beta + */ +export interface IRunScriptOptions { + heftTaskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + runOptions: IHeftTaskRunHookOptions; + scriptOptions: Record; +} + +/** + * Interface used by scripts that are run by the RunScriptPlugin. + * + * @beta + */ +export interface IRunScript { + /** + * The method that is called by the RunScriptPlugin to run the script. + */ + runAsync: (options: IRunScriptOptions) => Promise; +} + +const PLUGIN_NAME: 'run-script-plugin' = 'run-script-plugin'; + +export default class RunScriptPlugin implements IHeftTaskPlugin { + public apply( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IRunScriptPluginOptions + ): void { + heftTaskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + await this._runScriptAsync(heftTaskSession, heftConfiguration, pluginOptions, runOptions); + }); + } + + private async _runScriptAsync( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IRunScriptPluginOptions, + runOptions: IHeftTaskRunHookOptions + ): Promise { + const resolvedModulePath: string = path.resolve( + heftConfiguration.buildFolderPath, + pluginOptions.scriptPath + ); + const runScript: IRunScript = await import(resolvedModulePath); + if (!runScript.runAsync) { + throw new Error( + `The script at ${JSON.stringify(resolvedModulePath)} doesn\'t export a "runAsync" function.` + ); + } + + const runScriptOptions: IRunScriptOptions = { + heftTaskSession, + heftConfiguration, + runOptions, + scriptOptions: pluginOptions.scriptOptions + }; + await runScript.runAsync(runScriptOptions); + } +} diff --git a/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts b/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.ts new file mode 100644 index 00000000000..fb83903b83b --- /dev/null +++ b/apps/heft/src/plugins/SetEnvironmentVariablesPlugin.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 type { HeftConfiguration } from '../configuration/HeftConfiguration'; +import type { IHeftTaskSession } from '../pluginFramework/HeftTaskSession'; +import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; + +export const PLUGIN_NAME: string = 'set-environment-variables-plugin'; + +export interface ISetEnvironmentVariablesPluginOptions { + environmentVariablesToSet: Record; +} + +export default class SetEnvironmentVariablesPlugin + implements IHeftTaskPlugin +{ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + { environmentVariablesToSet }: ISetEnvironmentVariablesPluginOptions + ): void { + taskSession.hooks.run.tap( + { + name: PLUGIN_NAME, + stage: Number.MIN_SAFE_INTEGER + }, + () => { + for (const [key, value] of Object.entries(environmentVariablesToSet)) { + taskSession.logger.terminal.writeLine(`Setting environment variable ${key}=${value}`); + process.env[key] = value; + } + } + ); + } +} diff --git a/apps/heft/src/schemas/README-ModifyingSchemas.md b/apps/heft/src/schemas/README-ModifyingSchemas.md new file mode 100644 index 00000000000..1819095e9d0 --- /dev/null +++ b/apps/heft/src/schemas/README-ModifyingSchemas.md @@ -0,0 +1,4 @@ +## Important + +If you change the Heft schemas, be sure to update the example files under **schemas/templates**. +The templates are used as a reference when updating the website documentation. diff --git a/apps/heft/src/schemas/anything.schema.json b/apps/heft/src/schemas/anything.schema.json new file mode 100644 index 00000000000..15e4861463a --- /dev/null +++ b/apps/heft/src/schemas/anything.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Schema that matches anything", + + "oneOf": [ + { + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "integer" + }, + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ] +} diff --git a/apps/heft/src/schemas/copy-files-options.schema.json b/apps/heft/src/schemas/copy-files-options.schema.json new file mode 100644 index 00000000000..f42d46af61c --- /dev/null +++ b/apps/heft/src/schemas/copy-files-options.schema.json @@ -0,0 +1,88 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "CopyFiles Heft Task Event Options", + "description": "Defines configuration used by the \"copyFiles\" Heft task event.", + "type": "object", + + "additionalProperties": false, + "required": ["copyOperations"], + + "properties": { + "copyOperations": { + "type": "array", + "description": "An array of copy operations to perform during the specified Heft event.", + + "items": { + "type": "object", + "additionalProperties": false, + "required": ["destinationFolders"], + "anyOf": [ + { "required": ["sourcePath"] }, + { "required": ["fileExtensions"] }, + { "required": ["includeGlobs"] }, + { "required": ["excludeGlobs"] } + ], + "properties": { + "sourcePath": { + "title": "Source Path", + "type": "string", + "description": "The target folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be copied. To copy a single file, set \"includeGlobs\" to an array containing the exact name of the file. If this parameter is not provided, defaults to the project root.", + "pattern": "[^\\\\]" + }, + + "destinationFolders": { + "title": "Destination Folders", + "type": "array", + "description": "One or more folders that files and folders will be copied into, relative to the project root.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "fileExtensions": { + "title": "File Extensions", + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + + "excludeGlobs": { + "title": "Exclude Globs", + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being copied. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "includeGlobs": { + "title": "Include Globs", + "type": "array", + "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "flatten": { + "title": "Flatten", + "type": "boolean", + "description": "Normally, copying will preserve the path relative to \"sourcePath\" under the destination folder (e.g. if \"sourcePath\" is \"src/test\" and \"destinationFolders\" is [\"out\"], \"src/test/a/b/c.txt\" will be copied to \"out/a/b/c.txt\"). Specify \"flatten=true\" to discard path information and keep only the filename (e.g. \"out/c.txt\". If two files have the same name an error will be reported. The default value is false." + }, + + "hardlink": { + "title": "Hardlink", + "type": "boolean", + "description": "If true, filesystem hard links will be created instead of copying the file. Depending on the operating system, this may be faster. The default value is false. NOTE: This may cause unexpected behavior if a tool modifies the link. The contained directory structure will be re-created and all files will be individually hardlinked. This means that folders will be new filesystem entities and will have separate folder metadata, while the contained files will maintain normal hardlink behavior. This is done since folders do not have a cross-platform equivalent of a hardlink, and since file symlinks provide fundamentally different functionality in comparison to hardlinks." + } + } + } + } + } +} diff --git a/apps/heft/src/schemas/delete-files-options.schema.json b/apps/heft/src/schemas/delete-files-options.schema.json new file mode 100644 index 00000000000..0e6c0a9ccae --- /dev/null +++ b/apps/heft/src/schemas/delete-files-options.schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "DeleteFiles Heft Task Event Options", + "description": "Defines configuration used by the \"deleteFiles\" Heft task event.", + "type": "object", + + "additionalProperties": false, + "required": ["deleteOperations"], + + "properties": { + "deleteOperations": { + "type": "array", + "description": "An array of delete operations to perform during the specified Heft event.", + + "items": { + "type": "object", + "additionalProperties": false, + "anyOf": [ + { "required": ["sourcePath"] }, + { "required": ["fileExtensions"] }, + { "required": ["includeGlobs"] }, + { "required": ["excludeGlobs"] } + ], + "properties": { + "sourcePath": { + "title": "Source Path", + "type": "string", + "description": "The base folder that files will be deleted from, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the folder will be deleted.", + "pattern": "[^\\\\]" + }, + + "fileExtensions": { + "title": "File Extensions", + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + + "excludeGlobs": { + "title": "Exclude Globs", + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being deleted. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "includeGlobs": { + "title": "Include Globs", + "type": "array", + "description": "A list of glob patterns that select files to be deleted. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + } + } + } + } + } +} diff --git a/apps/heft/src/schemas/heft-legacy.schema.json b/apps/heft/src/schemas/heft-legacy.schema.json new file mode 100644 index 00000000000..45d26aa00f0 --- /dev/null +++ b/apps/heft/src/schemas/heft-legacy.schema.json @@ -0,0 +1,211 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Legacy Heft Configuration", + "description": "Defines configuration used by the legacy version of Heft.", + "type": "object", + + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { "$ref": "#/definitions/anything" } + } + }, + + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "eventActions": { + "type": "array", + "description": "An array of actions (such as deleting files or folders) that should occur during a Heft run.", + + "items": { + "type": "object", + "required": ["actionKind", "heftEvent", "actionId"], + "allOf": [ + { + "properties": { + "actionKind": { + "type": "string", + "description": "The kind of built-in operation that should be performed.", + "enum": ["deleteGlobs", "copyFiles", "runScript"] + }, + + "heftEvent": { + "type": "string", + "description": "The Heft stage when this action should be performed. Note that heft.json event actions are scheduled after any plugin tasks have processed the event. For example, a \"compile\" event action will be performed after the TypeScript compiler has been invoked.", + "enum": ["clean", "pre-compile", "compile", "bundle", "post-build", "test"] + }, + + "actionId": { + "type": "string", + "description": "A user-defined tag whose purpose is to allow configs to replace/delete handlers that were added by other configs." + } + } + }, + { + "oneOf": [ + { + "required": ["globsToDelete"], + "properties": { + "actionKind": { + "type": "string", + "enum": ["deleteGlobs"] + }, + + "heftEvent": { + "type": "string", + "enum": ["clean", "pre-compile", "compile", "bundle", "post-build"] + }, + + "globsToDelete": { + "type": "array", + "description": "Glob patterns to be deleted. The paths are resolved relative to the project folder.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + } + } + }, + { + "required": ["copyOperations"], + "properties": { + "actionKind": { + "type": "string", + "enum": ["copyFiles"] + }, + + "heftEvent": { + "type": "string", + "enum": ["pre-compile", "compile", "bundle", "post-build"] + }, + + "copyOperations": { + "type": "array", + "description": "An array of copy operations to run perform during the specified Heft event.", + "items": { + "type": "object", + "required": ["sourceFolder", "destinationFolders"], + "properties": { + "sourceFolder": { + "type": "string", + "description": "The base folder that files will be copied from, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. NOTE: Assigning \"sourceFolder\" does not by itself select any files to be copied.", + "pattern": "[^\\\\]" + }, + + "destinationFolders": { + "type": "array", + "description": "One or more folders that files will be copied into, relative to the project root. If you specify more than one destination folder, Heft will read the input files only once, using streams to efficiently write multiple outputs.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "fileExtensions": { + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourceFolder\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + + "excludeGlobs": { + "type": "array", + "description": "A list of glob patterns that exclude files/folders from being copied. The paths are resolved relative to \"sourceFolder\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "includeGlobs": { + "type": "array", + "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourceFolder\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "flatten": { + "type": "boolean", + "description": "Normally, when files are selected under a child folder, a corresponding folder will be created in the destination folder. Specify flatten=true to discard the source path and copy all matching files to the same folder. If two files have the same name an error will be reported. The default value is false." + }, + + "hardlink": { + "type": "boolean", + "description": "If true, filesystem hard links will be created instead of copying the file. Depending on the operating system, this may be faster. (But note that it may cause unexpected behavior if a tool modifies the link.) The default value is false." + } + } + } + } + } + }, + { + "required": ["scriptPath"], + "properties": { + "actionKind": { + "type": "string", + "enum": ["runScript"] + }, + + "heftEvent": { + "type": "string", + "enum": ["pre-compile", "compile", "bundle", "post-build", "test"] + }, + + "scriptPath": { + "type": "string", + "description": "Path to the script that will be run, relative to the project root.", + "pattern": "[^\\\\]" + }, + + "scriptOptions": { + "type": "object", + "description": "Optional parameters that will be passed to the script at runtime.", + "patternProperties": { + "^.*$": { "$ref": "#/definitions/anything" } + } + } + } + } + ] + } + ] + } + }, + + "heftPlugins": { + "type": "array", + "description": "Defines heft plugins that are used by a project.", + + "items": { + "type": "object", + "required": ["plugin"], + "properties": { + "plugin": { + "description": "Path to the plugin package, relative to the project root.", + "type": "string", + "pattern": "[^\\\\]" + }, + + "options": { + "type": "object" + } + } + } + } + } +} diff --git a/apps/heft/src/schemas/heft-plugin.schema.json b/apps/heft/src/schemas/heft-plugin.schema.json new file mode 100644 index 00000000000..37dd45012d7 --- /dev/null +++ b/apps/heft/src/schemas/heft-plugin.schema.json @@ -0,0 +1,438 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Configuration", + "description": "Defines configuration used by core Heft.", + "type": "object", + + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { "$ref": "#/definitions/anything" } + }, + + "baseParameter": { + "type": "object", + "additionalProperties": true, + "required": ["parameterKind", "longName", "description"], + "properties": { + "parameterKind": { + "title": "Parameter Kind", + "description": "Indicates the kind of syntax for this command-line parameter", + "type": "string", + "enum": ["choice", "choiceList", "flag", "integer", "integerList", "string", "stringList"] + }, + "longName": { + "title": "Long Name", + "description": "The name of the parameter (e.g. \"--verbose\"). This is a required field.", + "type": "string", + "pattern": "^-(-[a-z0-9]+)+$" + }, + "shortName": { + "title": "Short Name", + "description": "A optional short form of the parameter (e.g. \"-v\" instead of \"--verbose\")", + "type": "string", + "pattern": "^-[a-zA-Z]$" + }, + "description": { + "title": "Parameter Description", + "description": "A detailed description of the parameter, which appears when requesting help for the command (e.g. \"heft phaseName --help my-command\").", + "type": "string" + }, + "required": { + "title": "Required", + "description": "If true, then this parameter must be included on the command line", + "type": "boolean" + } + } + }, + + "choiceParameter": { + "title": "Choice Parameter", + "description": "A command-line parameter whose argument must be chosen from a list of allowable alternatives", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choice"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" + } + } + } + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "alternatives": { "$ref": "#/definitions/anything" }, + "defaultValue": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "choiceListParameter": { + "title": "Choice List Parameter", + "description": "A command-line parameter whose arguments must be chosen from a list of allowable alternatives", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choiceList"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" + } + } + } + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "alternatives": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "flagParameter": { + "title": "Flag Parameter", + "description": "A command-line parameter whose presence acts as an on/off switch", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "parameterKind": { + "enum": ["flag"] + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "integerParameter": { + "title": "Integer Parameter", + "description": "A command-line parameter whose value is interpreted as an integer", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integer"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "integer" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" }, + "defaultValue": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "integerListParameter": { + "title": "Integer List Parameter", + "description": "A command-line parameter whose value is interpreted as a list of integers", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integerList"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "stringParameter": { + "title": "String Parameter", + "description": "A command-line parameter whose value is interpreted as a string", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["string"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" }, + "defaultValue": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "stringListParameter": { + "title": "String List Parameter", + "description": "A command-line parameter whose value is interpreted as a string list", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["stringList"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "heft-plugin-base": { + "type": "object", + "additionalProperties": false, + "required": ["pluginName", "entryPoint"], + "properties": { + "pluginName": { + "title": "Plugin Name", + "type": "string", + "description": "Name of the plugin to load from the package.", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + }, + + "entryPoint": { + "title": "Entry Point", + "description": "The entry point path. This path is resolved relative to the package folder.", + "type": "string", + "pattern": "[^\\\\]" + }, + + "optionsSchema": { + "title": "Options Schema", + "type": "string", + "description": "Path to the schema that defines the options for the plugin. This schema should be a valid JSON schema. This path is resolved relative to the package folder.", + "pattern": "[^\\\\]" + }, + + "parameterScope": { + "title": "Parameter Scope", + "type": "string", + "description": "The scope of the parameters for the plugin. This scope is used to provide alternate names for parameters if there is a conflict between identical long names. For example, if scope \"my-scope\" is provided and parameter \"--parameter\" is defined, it may be referenced as \"--parameter\" or \"--my-scope:parameter\" on the CLI. When multiple \"--parameter\" parameters are defined with different scopes, they can only be referenced by their scoped long name. If no scope is provided, the scope will default to the plugin name.", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + }, + + "parameters": { + "title": "Plugin Parameters", + "description": "A list of command-line parameters.", + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { "$ref": "#/definitions/flagParameter" }, + { "$ref": "#/definitions/integerParameter" }, + { "$ref": "#/definitions/integerListParameter" }, + { "$ref": "#/definitions/choiceParameter" }, + { "$ref": "#/definitions/choiceListParameter" }, + { "$ref": "#/definitions/stringParameter" }, + { "$ref": "#/definitions/stringListParameter" } + ] + } + } + } + }, + + "heft-lifecycle-plugin": { + "$ref": "#/definitions/heft-plugin-base" + }, + + "heft-task-plugin": { + "$ref": "#/definitions/heft-plugin-base" + } + }, + + "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" + }, + + "lifecyclePlugins": { + "title": "Lifecycle Plugins", + "description": "A list of plugins that will be loaded and used for Heft lifecycle hooks.", + "type": "array", + "items": { "$ref": "#/definitions/heft-lifecycle-plugin" } + }, + + "taskPlugins": { + "title": "Task Plugins", + "description": "A list of plugins that will be loaded and used for Heft task hooks.", + "type": "array", + "items": { "$ref": "#/definitions/heft-task-plugin" } + } + } +} diff --git a/apps/heft/src/schemas/heft.schema.json b/apps/heft/src/schemas/heft.schema.json new file mode 100644 index 00000000000..cba91630724 --- /dev/null +++ b/apps/heft/src/schemas/heft.schema.json @@ -0,0 +1,205 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Configuration", + "description": "Defines configuration used by core Heft.", + "type": "object", + + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { "$ref": "#/definitions/anything" } + }, + + "heft-plugin": { + "description": "A plugin that can be used to extend Heft functionality.", + "type": "object", + "required": ["pluginPackage"], + "additionalProperties": false, + "properties": { + "pluginPackage": { + "description": "The plugin package name.", + "type": "string", + "pattern": "[^\\\\]" + }, + "pluginName": { + "description": "Name of the plugin to load from the specified package. If not specified and the plugin package provides a single plugin, that plugin will be loaded.", + "type": "string", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + }, + "options": { + "description": "Options to pass to the plugin.", + "type": "object" + } + } + }, + + "heft-event": { + "description": "An event that can be used to extend Heft functionality.", + "type": "object", + "required": ["eventKind"], + "additionalProperties": false, + "properties": { + "eventKind": { + "description": "Name of the event to trigger.", + "type": "string", + "enum": ["copyFiles", "deleteFiles", "runScript", "nodeService"] + }, + "options": { + "description": "Options to pass to the event.", + "type": "object" + } + } + }, + + "delete-operation": { + "type": "object", + "additionalProperties": false, + "anyOf": [ + { "required": ["sourcePath"] }, + { "required": ["fileExtensions"] }, + { "required": ["includeGlobs"] }, + { "required": ["excludeGlobs"] } + ], + "properties": { + "sourcePath": { + "title": "Source Path", + "type": "string", + "description": "The target file or folder, relative to the project root. Settings such as \"includeGlobs\" and \"excludeGlobs\" will be resolved relative to this folder. If no globs or file extensions are specified, the file or folder will be deleted.", + "pattern": "[^\\\\]" + }, + "fileExtensions": { + "type": "array", + "description": "If specified, this option recursively scans all folders under \"sourcePath\" and includes any files that match the specified extensions. (If \"fileExtensions\" and \"includeGlobs\" are both specified, their selections are added together.)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + "excludeGlobs": { + "type": "array", + "description": "A list of glob patterns that exclude files or folders from being copied. The paths are resolved relative to \"sourcePath\". These exclusions eliminate items that were selected by the \"includeGlobs\" or \"fileExtensions\" setting.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + "includeGlobs": { + "type": "array", + "description": "A list of glob patterns that select files to be copied. The paths are resolved relative to \"sourcePath\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + } + } + } + }, + + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "heftPlugins": { + "type": "array", + "description": "List of Heft plugins that are used by a project.", + "items": { "$ref": "#/definitions/heft-plugin" } + }, + + "aliasesByName": { + "type": "object", + "description": "Defines aliases for existing Heft actions, and allows them to be invoked by name with default parameters.", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9]*([-][a-z0-9]+)*$": { + "description": "Defines a Heft action alias.", + "type": "object", + "additionalProperties": false, + "required": ["actionName"], + "properties": { + "actionName": { + "description": "The name of the Heft action to invoke.", + "type": "string", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + }, + "defaultParameters": { + "description": "Parameters to pass to the Heft action by default. These parameters will be appended after the specified action and before any user-specified parameters.", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + + "phasesByName": { + "type": "object", + "description": "Heft phases that can be run during an execution of Heft.", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9]*([-][a-z0-9]+)*$": { + "description": "Defines a Heft phase.", + "type": "object", + "additionalProperties": false, + "properties": { + "phaseDescription": { + "description": "A description of the purpose of the Heft phase.", + "type": "string" + }, + + "phaseDependencies": { + "type": "array", + "description": "List of phase names that must be run before this phase.", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + } + }, + + "cleanFiles": { + "description": "List of delete operations to perform when cleaning at the beginning of phase execution.", + "type": "array", + "items": { "$ref": "#/definitions/delete-operation" } + }, + + "tasksByName": { + "description": "Heft tasks that are run during an execution of the Heft phase.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9]*([-][a-z0-9]+)*$": { + "type": "object", + "description": "Defines a Heft task.", + "additionalProperties": false, + "required": ["taskPlugin"], + "properties": { + "taskPlugin": { "$ref": "#/definitions/heft-plugin" }, + + "taskDependencies": { + "type": "array", + "description": "List of task names that must be run before this task.", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9]*([-][a-z0-9]+)*$" + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/apps/heft/src/schemas/node-service.schema.json b/apps/heft/src/schemas/node-service.schema.json new file mode 100644 index 00000000000..67af1bc48a9 --- /dev/null +++ b/apps/heft/src/schemas/node-service.schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Node Service Configuration", + "description": "Configures the Node Service plugin for Heft", + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "commandName": { + "description": "Specifies the name of a \"scripts\" command from the project's package.json file. When \"heft start\" is invoked, it will use this shell command to launch the service process.", + "type": "string" + }, + + "ignoreMissingScript": { + "description": "If false, then an error is reported if the \"scripts\" command is not found in the project's package.json. If true, then no action will be taken.", + "type": "boolean" + }, + + "waitForTerminateMs": { + "description": "Customizes the number of milliseconds to wait for the child process to be terminated (SIGTERM) before forcibly killing it.", + "type": "number" + }, + + "waitForKillMs": { + "description": "Customizes the number of milliseconds to wait for the child process to be killed (SIGKILL) before giving up and abandoning it.", + "type": "number" + } + } +} diff --git a/apps/heft/src/schemas/run-script-options.schema.json b/apps/heft/src/schemas/run-script-options.schema.json new file mode 100644 index 00000000000..1a42badddbb --- /dev/null +++ b/apps/heft/src/schemas/run-script-options.schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RunScript Heft Task Event Options", + "description": "Defines configuration used by the \"runScript\" Heft task event.", + "type": "object", + + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { "$ref": "#/definitions/anything" } + } + }, + + "additionalProperties": false, + "required": ["scriptPath"], + + "properties": { + "scriptPath": { + "title": "Script Path", + "type": "string", + "description": "Path to the script that will be run, relative to the project root.", + "pattern": "[^\\\\]" + }, + + "scriptOptions": { + "title": "Script Options", + "type": "object", + "description": "Optional parameters that will be passed to the script at runtime.", + "patternProperties": { + "^.*$": { "$ref": "#/definitions/anything" } + } + } + } +} diff --git a/apps/heft/src/schemas/set-environment-variables-plugin.schema.json b/apps/heft/src/schemas/set-environment-variables-plugin.schema.json new file mode 100644 index 00000000000..7ffa21d2967 --- /dev/null +++ b/apps/heft/src/schemas/set-environment-variables-plugin.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "CopyFiles Heft Task Event Options", + "description": "Defines configuration used by the \"copyFiles\" Heft task event.", + "type": "object", + + "additionalProperties": false, + "required": ["environmentVariablesToSet"], + + "properties": { + "environmentVariablesToSet": { + "type": "object", + "additionalProperties": { + "type": "string", + "pattern": ".+" + } + } + } +} diff --git a/apps/heft/src/schemas/templates/heft.json b/apps/heft/src/schemas/templates/heft.json new file mode 100644 index 00000000000..870a1a538a3 --- /dev/null +++ b/apps/heft/src/schemas/templates/heft.json @@ -0,0 +1,174 @@ +/** + * 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": "base-project/config/heft.json", + + /** + * Defines aliases for existing Heft actions, and allows them to be invoked by + * name with default parameters. The JSON keys is are user-defined names. + * + * For example, the "heft start" alias is conventionally defined to invoke + * "heft build-watch --serve" using a definition like this: + * + * "aliasesByName": { "start": { "actionName": "build-watch", "defaultParameters": [ "--serve" ] } } + */ + "aliasesByName": { + // /** + // * The command-line action name of the Heft alias that is being defined. + // * This JSON key is a user-defined value. + // */ + // "example-alias-name": { + // /** + // * The name of the existing Heft command-line action to be invoked by this alias. + // */ + // "actionName": "example-action", + // + // /** + // * A list of command-line parameters to pass to the Heft action by default. + // * These parameters will be appended after the specified action and before + // * any user-specified parameters. + // */ + // "defaultParameters": [ "--do-some-thing" ] + // } + }, + + /** + * List of Heft lifecycle plugins to be loaded for this project. + */ + "heftPlugins": [ + // { + // /** + // * (REQUIRED) The NPM package name for the plugin. + // */ + // "pluginPackage": "@mycorp/heft-example-plugin", + // + // /** + // * The name of the plugin to load from the NPM package's heft-plugin.json manifest. + // * If not specified, and if the plugin package provides a single plugin, then that + // * plugin will be loaded. + // */ + // // "pluginName": "example-plugin", + // + // /** + // * Options to pass to the plugin. This is a custom object whose structure + // * is defined by the plugin. + // */ + // // "options": { "example-key": "example-value" } + // } + ], + + /** + * Heft phases that can be run during an execution of Heft. + * The JSON keys is are user-defined names. + */ + "phasesByName": { + /** + * The name of the phase, which is used by other fields such as "phaseDependencies". + * This JSON key is a user-defined value. + */ + "example-phase": { + /** + * A description to be shown in the command-line help. + */ + "phaseDescription": "An example phase", + + /** + * A list of delete operations to perform when cleaning at the beginning of phase execution. + * Their structure is similar the options used by the delete-files-plugin. + */ + "cleanFiles": [ + // { + // /** + // * Absolute path to the source file or folder, relative to the project root. + // * If "fileExtensions", "excludeGlobs", or "includeGlobs" are specified, then "sourcePath" + // * is assumed to be a folder; if it is not a folder, an error will be thrown. + // * Settings such as "includeGlobs" and "excludeGlobs" will be resolved relative to this path. + // * If no globs or file extensions are specified, the entire folder will be copied. + // * If this parameter is not provided, it defaults to the project root. + // */ + // // "sourcePath": "lib", + // + // /** + // * If specified, this option recursively scans all folders under "sourcePath" and includes + // * any files that match the specified extensions. If "fileExtensions" and "includeGlobs" + // * are both specified, their selections are added together. + // */ + // // "fileExtensions": [ ".png" ], + // + // /** + // * A list of glob patterns that select files to be copied. The paths are resolved relative + // * to "sourcePath", which must be a folder path. If "fileExtensions" and "includeGlobs" + // * are both specified, their selections are added together. + // * + // * For glob syntax, refer to: https://www.npmjs.com/package/fast-glob + // */ + // // "excludeGlobs": [], + // + // + // /** + // * A list of glob patterns that exclude files or folders from being copied. The paths are resolved + // * relative to "sourcePath", which must be a folder path. These exclusions eliminate items that + // * were selected by the "includeGlobs" or "fileExtensions" setting. + // * + // * For glob syntax, refer to: https://www.npmjs.com/package/fast-glob + // */ + // // "includeGlobs": [ "**/temp" ] + // } + ], + + /** + * A list of phase names that must be run before this phase can start. + */ + "phaseDependencies": [], + + /** + * Heft tasks that are run during an execution of the Heft phase. + * The JSON keys is are user-defined names. + */ + "tasksByName": { + /** + * The name of the task, which is used by other fields such as "taskDependencies". + * This JSON key is a user-defined value. + */ + "example-task": { + /** + * A list of task names that must be run before this task can start. + */ + "taskDependencies": [], + + /** + * (REQUIRED) The Heft plugin to be loaded, which will perform the operation for this task. + */ + "taskPlugin": { + /** + * (REQUIRED) The NPM package name for the plugin. + */ + "pluginPackage": "@mycorp/heft-example-plugin" + + /** + * The name of the plugin to load from the NPM package's heft-plugin.json manifest. + * If not specified, and if the plugin package provides a single plugin, then that + * plugin will be loaded. + */ + // "pluginName": "example-plugin", + + /** + * Options to pass to the plugin. This is a custom object whose structure + * is defined by the plugin. + */ + // "options": { "example-key": "example-value" } + } + } + } + } + } +} diff --git a/apps/heft/src/start.ts b/apps/heft/src/start.ts new file mode 100644 index 00000000000..b6c5f1e9391 --- /dev/null +++ b/apps/heft/src/start.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { HeftCommandLineParser } from './cli/HeftCommandLineParser'; + +// Launching via lib/start.js bypasses the version selector. Use that for debugging Heft. + +const parser: HeftCommandLineParser = new HeftCommandLineParser(); + +parser + .executeAsync() + .then(() => { + // This should be removed when the issue with aria not tearing down + process.exit(process.exitCode === undefined ? 0 : process.exitCode); + }) + .catch((error) => { + parser.globalTerminal.writeErrorLine(error.toString()); + process.exit(1); + }); diff --git a/apps/heft/src/startWithVersionSelector.ts b/apps/heft/src/startWithVersionSelector.ts new file mode 100644 index 00000000000..d4a3a3dc150 --- /dev/null +++ b/apps/heft/src/startWithVersionSelector.ts @@ -0,0 +1,117 @@ +// 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 */ + +// 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 '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'; + +// Excerpted from PackageJsonLookup.tryGetPackageFolderFor() +function tryGetPackageFolderFor(resolvedFileOrFolderPath: string): string | undefined { + // Two lookups are required, because get() cannot distinguish the undefined value + // versus a missing key. + // if (this._packageFolderCache.has(resolvedFileOrFolderPath)) { + // return this._packageFolderCache.get(resolvedFileOrFolderPath); + // } + + // Is resolvedFileOrFolderPath itself a folder with a package.json file? If so, return it. + if (fs.existsSync(path.join(resolvedFileOrFolderPath, 'package.json'))) { + // this._packageFolderCache.set(resolvedFileOrFolderPath, resolvedFileOrFolderPath); + return resolvedFileOrFolderPath; + } + + // Otherwise go up one level + const parentFolder: string | undefined = path.dirname(resolvedFileOrFolderPath); + if (!parentFolder || parentFolder === resolvedFileOrFolderPath) { + // We reached the root directory without finding a package.json file, + // so cache the negative result + // this._packageFolderCache.set(resolvedFileOrFolderPath, undefined); + return undefined; // no match + } + + // Recurse upwards, caching every step along the way + const parentResult: string | undefined = tryGetPackageFolderFor(parentFolder); + // Cache the parent's answer as well + // this._packageFolderCache.set(resolvedFileOrFolderPath, parentResult); + + return parentResult; +} + +/** + * When Heft is invoked via the shell path, we examine the project's package.json dependencies and try to load + * the locally installed version of Heft. This avoids accidentally building using the wrong version of Heft. + * Use "heft --unmanaged" to bypass this feature. + */ +function tryStartLocalHeft(): boolean { + const toolParameters: Set = getToolParameterNamesFromArgs(); + if (toolParameters.has(Constants.unmanagedParameterLongName)) { + console.log( + `Bypassing the Heft version selector because ${JSON.stringify(Constants.unmanagedParameterLongName)} ` + + 'was specified.' + ); + console.log(); + return false; + } else if (toolParameters.has(Constants.debugParameterLongName)) { + // The unmanaged flag could be undiscoverable if it's not in their locally installed version + console.log( + 'Searching for a locally installed version of Heft. Use the ' + + `${JSON.stringify(Constants.unmanagedParameterLongName)} flag if you want to avoid this.` + ); + } + + // Find the package.json file that governs the current folder location + const projectFolder: string | undefined = tryGetPackageFolderFor(process.cwd()); + if (projectFolder) { + let heftEntryPoint: string; + try { + const packageJsonPath: string = path.join(projectFolder, 'package.json'); + const packageJsonContent: string = fs.readFileSync(packageJsonPath).toString(); + let packageJson: IPackageJson; + try { + packageJson = JSON.parse(packageJsonContent); + } catch (error) { + throw new Error(`Error parsing ${packageJsonPath}:` + (error as Error).message); + } + + // Does package.json have a dependency on Heft? + if ( + !(packageJson.dependencies && packageJson.dependencies[Constants.heftPackageName]) && + !(packageJson.devDependencies && packageJson.devDependencies[Constants.heftPackageName]) + ) { + // No explicit dependency on Heft + return false; + } + + // To avoid a loading the "resolve" NPM package, let's assume that the Heft dependency must be + // 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); + } + } catch (error) { + throw new Error('Error probing for local Heft version: ' + (error as Error).message); + } + + require(heftEntryPoint); + + // We found and successfully invoked the local Heft + return true; + } + + // We couldn't find the package folder + return false; +} + +if (!tryStartLocalHeft()) { + // A project Heft dependency was not found, so launch the unmanaged version. + require('./start.js'); +} diff --git a/apps/heft/src/utilities/CliUtilities.ts b/apps/heft/src/utilities/CliUtilities.ts new file mode 100644 index 00000000000..d322dc45e1f --- /dev/null +++ b/apps/heft/src/utilities/CliUtilities.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. + +/** + * Parse the arguments to the tool being executed and return the tool argument names. + * + * @param argv - The arguments to parse. Defaults to `process.argv`. + */ +export function getToolParameterNamesFromArgs(argv: string[] = process.argv): Set { + const toolParameters: Set = new Set(); + // Skip the first two arguments, which are the path to the Node executable and the path to the Heft + // entrypoint. The remaining arguments are the tool arguments. Grab them until we reach a non-"-"-prefixed + // argument. We can do this simple parsing because the Heft tool only has simple optional flags. + for (let i: number = 2; i < argv.length; ++i) { + const arg: string = argv[i]; + if (!arg.startsWith('-')) { + break; + } + toolParameters.add(arg); + } + return toolParameters; +} diff --git a/apps/heft/src/utilities/Constants.ts b/apps/heft/src/utilities/Constants.ts new file mode 100644 index 00000000000..60e929519e6 --- /dev/null +++ b/apps/heft/src/utilities/Constants.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. + +export class Constants { + public static projectConfigFolderName: string = 'config'; + + public static cacheFolderName: string = '.cache'; + + public static tempFolderName: string = 'temp'; + + public static heftConfigurationFilename: string = 'heft.json'; + + public static nodeServiceConfigurationFilename: string = 'node-service.json'; + + public static cleanParameterLongName: string = '--clean'; + + public static debugParameterLongName: string = '--debug'; + + public static localesParameterLongName: string = '--locales'; + + public static onlyParameterLongName: string = '--only'; + + public static productionParameterLongName: string = '--production'; + + public static toParameterLongName: string = '--to'; + + public static toExceptParameterLongName: string = '--to-except'; + + public static unmanagedParameterLongName: string = '--unmanaged'; + + public static verboseParameterLongName: string = '--verbose'; + + public static verboseParameterShortName: string = '-v'; + + public static maxParallelism: number = 100; + + public static heftPackageName: string = '@rushstack/heft'; +} diff --git a/apps/heft/src/utilities/CoreConfigFiles.ts b/apps/heft/src/utilities/CoreConfigFiles.ts new file mode 100644 index 00000000000..3ad45c6fda9 --- /dev/null +++ b/apps/heft/src/utilities/CoreConfigFiles.ts @@ -0,0 +1,251 @@ +// 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 { + ProjectConfigurationFile, + InheritanceType, + PathResolutionMethod, + type IJsonPathMetadataResolverOptions +} from '@rushstack/heft-config-file'; +import { Import, PackageJsonLookup, InternalError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import type { IRigConfig } from '@rushstack/rig-package'; + +import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; +import type { INodeServicePluginConfiguration } from '../plugins/NodeServicePlugin'; +import { Constants } from './Constants'; + +export interface IHeftConfigurationJsonActionReference { + actionName: string; + defaultParameters?: string[]; +} + +export interface IHeftConfigurationJsonAliases { + [aliasName: string]: IHeftConfigurationJsonActionReference; +} + +export interface IHeftConfigurationJsonPluginSpecifier { + pluginPackage: string; + pluginPackageRoot: string; + pluginName?: string; + options?: object; +} + +export interface IHeftConfigurationJsonTaskSpecifier { + taskDependencies?: string[]; + taskPlugin: IHeftConfigurationJsonPluginSpecifier; +} + +export interface IHeftConfigurationJsonTasks { + [taskName: string]: IHeftConfigurationJsonTaskSpecifier; +} + +export interface IHeftConfigurationJsonPhaseSpecifier { + phaseDescription?: string; + phaseDependencies?: string[]; + cleanFiles?: IDeleteOperation[]; + tasksByName?: IHeftConfigurationJsonTasks; +} + +export interface IHeftConfigurationJsonPhases { + [phaseName: string]: IHeftConfigurationJsonPhaseSpecifier; +} + +export interface IHeftConfigurationJson { + heftPlugins?: IHeftConfigurationJsonPluginSpecifier[]; + aliasesByName?: IHeftConfigurationJsonAliases; + phasesByName?: IHeftConfigurationJsonPhases; +} + +export class CoreConfigFiles { + private static _heftConfigFileLoader: ProjectConfigurationFile | undefined; + private static _nodeServiceConfigurationLoader: + | ProjectConfigurationFile + | undefined; + + public static heftConfigurationProjectRelativeFilePath: string = `${Constants.projectConfigFolderName}/${Constants.heftConfigurationFilename}`; + + public static nodeServiceConfigurationProjectRelativeFilePath: string = `${Constants.projectConfigFolderName}/${Constants.nodeServiceConfigurationFilename}`; + + /** + * Returns the loader for the `config/heft.json` config file. + */ + public static async loadHeftConfigurationFileForProjectAsync( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig | undefined + ): Promise { + if (!CoreConfigFiles._heftConfigFileLoader) { + let heftPluginPackageFolder: string | undefined; + + const pluginPackageResolver: ( + options: IJsonPathMetadataResolverOptions + ) => string = (options: IJsonPathMetadataResolverOptions) => { + const { propertyValue, configurationFilePath } = options; + if (propertyValue === Constants.heftPackageName) { + // If the value is "@rushstack/heft", then resolve to the Heft package that is + // installed in the project folder. This avoids issues with mismatched versions + // between the project and the globally installed Heft. Use the PackageJsonLookup + // class to find the package folder to avoid hardcoding the path for compatibility + // with bundling. + if (!heftPluginPackageFolder) { + heftPluginPackageFolder = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); + } + + if (!heftPluginPackageFolder) { + // This should never happen + throw new InternalError('Unable to find the @rushstack/heft package folder'); + } + + return heftPluginPackageFolder; + } else { + const configurationFileDirectory: string = path.dirname(configurationFilePath); + return Import.resolvePackage({ + packageName: propertyValue, + baseFolderPath: configurationFileDirectory, + allowSelfReference: true + }); + } + }; + + const schemaObject: object = await import('../schemas/heft.schema.json'); + CoreConfigFiles._heftConfigFileLoader = new ProjectConfigurationFile({ + projectRelativeFilePath: CoreConfigFiles.heftConfigurationProjectRelativeFilePath, + jsonSchemaObject: schemaObject, + propertyInheritanceDefaults: { + array: { inheritanceType: InheritanceType.append }, + object: { inheritanceType: InheritanceType.merge } + }, + jsonPathMetadata: { + // Use a custom resolver for the plugin packages, since the NodeResolve algorithm will resolve to the + // package.json exports/module property, which may or may not exist. + '$.heftPlugins.*.pluginPackage': { + pathResolutionMethod: PathResolutionMethod.custom, + customResolver: pluginPackageResolver + }, + // Use a custom resolver for the plugin packages, since the NodeResolve algorithm will resolve to the + // package.json exports/module property, which may or may not exist. + '$.phasesByName.*.tasksByName.*.taskPlugin.pluginPackage': { + pathResolutionMethod: PathResolutionMethod.custom, + customResolver: pluginPackageResolver + } + } + }); + } + + const heftConfigFileLoader: ProjectConfigurationFile = + CoreConfigFiles._heftConfigFileLoader; + + let configurationFile: IHeftConfigurationJson; + try { + configurationFile = await heftConfigFileLoader.loadConfigurationFileForProjectAsync( + terminal, + projectPath, + rigConfig + ); + } catch (e: unknown) { + if ( + !(e instanceof Error) || + !e.message.startsWith('Resolved configuration object does not match schema') + ) { + throw e; + } + + try { + // If the config file doesn't match the schema, then we should check to see if it does + // match the legacy schema. We don't need to worry about the resulting object, we just + // want to see if it parses. We will use the ConfigurationFile class to load it to ensure + // that we follow the "extends" chain for the entire config file. + const legacySchemaObject: object = await import('../schemas/heft-legacy.schema.json'); + const legacyConfigFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: CoreConfigFiles.heftConfigurationProjectRelativeFilePath, + jsonSchemaObject: legacySchemaObject + }); + await legacyConfigFileLoader.loadConfigurationFileForProjectAsync(terminal, projectPath, rigConfig); + } catch (e2) { + // It doesn't match the legacy schema either. Throw the original error. + throw e; + } + // Matches the legacy schema, so throw a more helpful error. + throw new Error( + "This project's Heft configuration appears to be using an outdated schema.\n\n" + + 'Heft 0.51.0 introduced a major breaking change for Heft configuration files. ' + + 'Your project appears to be using the older file format. You will need to ' + + 'migrate your project to the new format. Follow these instructions: ' + + 'https://rushstack.io/link/heft-0.51' + ); + } + + // The pluginPackage field was resolved to the root of the package, but we also want to have + // the original plugin package name in the config file. + function getUpdatedPluginSpecifier( + rawSpecifier: IHeftConfigurationJsonPluginSpecifier + ): IHeftConfigurationJsonPluginSpecifier { + const pluginPackageName: string = heftConfigFileLoader.getPropertyOriginalValue({ + parentObject: rawSpecifier, + propertyName: 'pluginPackage' + })!; + const newSpecifier: IHeftConfigurationJsonPluginSpecifier = { + ...rawSpecifier, + pluginPackageRoot: rawSpecifier.pluginPackage, + pluginPackage: pluginPackageName + }; + return newSpecifier; + } + + const phasesByName: IHeftConfigurationJsonPhases = {}; + + const normalizedConfigurationFile: IHeftConfigurationJson = { + ...configurationFile, + heftPlugins: configurationFile.heftPlugins?.map(getUpdatedPluginSpecifier) ?? [], + phasesByName + }; + + for (const [phaseName, phase] of Object.entries(configurationFile.phasesByName || {})) { + const tasksByName: IHeftConfigurationJsonTasks = {}; + phasesByName[phaseName] = { + ...phase, + tasksByName + }; + + for (const [taskName, task] of Object.entries(phase.tasksByName || {})) { + if (task.taskPlugin) { + tasksByName[taskName] = { + ...task, + taskPlugin: getUpdatedPluginSpecifier(task.taskPlugin) + }; + } else { + tasksByName[taskName] = task; + } + } + } + + return normalizedConfigurationFile; + } + + public static async tryLoadNodeServiceConfigurationFileAsync( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig | undefined + ): Promise { + if (!CoreConfigFiles._nodeServiceConfigurationLoader) { + const schemaObject: object = await import('../schemas/node-service.schema.json'); + CoreConfigFiles._nodeServiceConfigurationLoader = + new ProjectConfigurationFile({ + projectRelativeFilePath: CoreConfigFiles.nodeServiceConfigurationProjectRelativeFilePath, + jsonSchemaObject: schemaObject + }); + } + + const configurationFile: INodeServicePluginConfiguration | undefined = + await CoreConfigFiles._nodeServiceConfigurationLoader.tryLoadConfigurationFileForProjectAsync( + terminal, + projectPath, + rigConfig + ); + return configurationFile; + } +} diff --git a/apps/heft/src/utilities/GitUtilities.ts b/apps/heft/src/utilities/GitUtilities.ts new file mode 100644 index 00000000000..3877f9255df --- /dev/null +++ b/apps/heft/src/utilities/GitUtilities.ts @@ -0,0 +1,429 @@ +// 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, SpawnSyncReturns } from 'node:child_process'; + +import { default as getGitRepoInfo, type GitRepoInfo as IGitRepoInfo } from 'git-repo-info'; +import { default as ignore, type Ignore as IIgnoreMatcher } from 'ignore'; + +import { Executable, FileSystem, InternalError, Path, Text } from '@rushstack/node-core-library'; + +// Matches lines starting with "#" and whitepace lines +const GITIGNORE_IGNORABLE_LINE_REGEX: RegExp = /^(?:(?:#.*)|(?:\s+))$/; +const UNINITIALIZED: 'UNINITIALIZED' = 'UNINITIALIZED'; + +export interface IGitVersion { + major: number; + minor: number; + patch: number; +} + +export type GitignoreFilterFn = (filePath: string) => boolean; + +interface IExecuteGitCommandOptions { + command: string; + args?: string[]; + delimiter?: string; +} + +export class GitUtilities { + private readonly _workingDirectory: string; + private _ignoreMatcherByGitignoreFolder: Map | undefined; + private _gitPath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED; + private _gitInfo: IGitRepoInfo | undefined | typeof UNINITIALIZED = UNINITIALIZED; + private _gitVersion: IGitVersion | undefined | typeof UNINITIALIZED = UNINITIALIZED; + + public constructor(workingDirectory: string) { + this._workingDirectory = path.resolve(process.cwd(), workingDirectory); + } + + /** + * Returns the path to the Git binary if found. Otherwise, return undefined. + */ + public get gitPath(): string | undefined { + if (this._gitPath === UNINITIALIZED) { + this._gitPath = Executable.tryResolve('git'); + } + return this._gitPath; + } + + /** + * Get information about the current Git working tree. + * Returns undefined if the current path is not under a Git working tree. + */ + public getGitInfo(): Readonly | undefined { + if (this._gitInfo === UNINITIALIZED) { + let repoInfo: IGitRepoInfo | undefined; + try { + // getGitRepoInfo() shouldn't usually throw, but wrapping in a try/catch just in case + repoInfo = getGitRepoInfo(); + } catch (ex) { + // if there's an error, assume we're not in a Git working tree + } + this._gitInfo = repoInfo && this.isPathUnderGitWorkingTree(repoInfo) ? repoInfo : undefined; + } + return this._gitInfo; + } + + /** + * Gets the Git version and returns it. + */ + public getGitVersion(): IGitVersion | undefined { + if (this._gitVersion === UNINITIALIZED) { + if (this.gitPath) { + const result: SpawnSyncReturns = Executable.spawnSync(this.gitPath, ['version']); + if (result.status !== 0) { + throw new Error( + `While validating the Git installation, the "git version" command failed with ` + + `status ${result.status}: ${result.stderr}` + ); + } + this._gitVersion = this._parseGitVersion(result.stdout); + } else { + this._gitVersion = undefined; + } + } + return this._gitVersion; + } + + /** + * Returns true if the Git binary can be found. + */ + public isGitPresent(): boolean { + return !!this.gitPath; + } + + /** + * Returns true if the Git binary was found and the current path is under a Git working tree. + * @param repoInfo - If provided, do the check based on this Git repo info. If not provided, + * the result of `this.getGitInfo()` is used. + */ + public isPathUnderGitWorkingTree(repoInfo?: IGitRepoInfo): boolean { + if (this.isGitPresent()) { + // Do we even have a Git binary? + if (!repoInfo) { + repoInfo = this.getGitInfo(); + } + return !!(repoInfo && repoInfo.sha); + } else { + return false; + } + } + + /** + * Returns an asynchronous filter function which can be used to filter out files that are ignored by Git. + */ + public async tryCreateGitignoreFilterAsync(): Promise { + let gitInfo: IGitRepoInfo | undefined; + if (!this.isGitPresent() || !(gitInfo = this.getGitInfo())?.sha) { + return; + } + const gitRepoRootPath: string = gitInfo.root; + const ignoreMatcherMap: Map = await this._getIgnoreMatchersAsync(gitRepoRootPath); + + const matcherFiltersByMatcher: Map boolean> = new Map(); + return (filePath: string) => { + const matcher: IIgnoreMatcher = this._findIgnoreMatcherForFilePath(filePath, ignoreMatcherMap); + let matcherFilter: ((filePath: string) => boolean) | undefined = matcherFiltersByMatcher.get(matcher); + if (!matcherFilter) { + matcherFilter = matcher.createFilter(); + matcherFiltersByMatcher.set(matcher, matcherFilter); + } + + // Now that we have the matcher, we can finally check to see if the file is ignored. We need to use + // the path relative to the git repo root, since all produced matchers are relative to the git repo + // root. Additionally, the ignore library expects relative paths to be sourced from the path library, + // so use path.relative() to ensure the path is correctly normalized. + const relativeFilePath: string = path.relative(gitRepoRootPath, filePath); + return matcherFilter(relativeFilePath); + }; + } + + private _findIgnoreMatcherForFilePath( + filePath: string, + ignoreMatcherMap: Map + ): IIgnoreMatcher { + if (!path.isAbsolute(filePath)) { + throw new Error(`The filePath must be an absolute path: "${filePath}"`); + } + const normalizedFilePath: string = Path.convertToSlashes(filePath); + + // Find the best matcher for the file path by finding the longest matcher path that is a prefix to + // the file path + // TODO: Use LookupByPath to make this more efficient. Currently not possible because LookupByPath + // does not have support for leaf node traversal. + let longestMatcherPath: string | undefined; + let foundMatcher: IIgnoreMatcher | undefined; + + for (const [matcherPath, matcher] of ignoreMatcherMap) { + if ( + normalizedFilePath.startsWith(matcherPath) && + matcherPath.length > (longestMatcherPath?.length || 0) + ) { + longestMatcherPath = matcherPath; + foundMatcher = matcher; + } + } + if (!foundMatcher) { + throw new InternalError(`Unable to find a gitignore matcher for "${filePath}"`); + } + + return foundMatcher; + } + + private async _getIgnoreMatchersAsync(gitRepoRootPath: string): Promise> { + // Return early if we've already parsed the .gitignore matchers + if (this._ignoreMatcherByGitignoreFolder !== undefined) { + return this._ignoreMatcherByGitignoreFolder; + } else { + this._ignoreMatcherByGitignoreFolder = new Map(); + } + + // Store the raw loaded ignore patterns in a map, keyed by the directory they were loaded from + const rawIgnorePatternsByGitignoreFolder: Map = new Map(); + + // Load the .gitignore files for the working directory and all parent directories. We can loop through + // and compare the currentPath length to the gitRepoRootPath length because we know the currentPath + // must be under the gitRepoRootPath + const normalizedWorkingDirectory: string = Path.convertToSlashes(this._workingDirectory); + let currentPath: string = normalizedWorkingDirectory; + while (currentPath.length >= gitRepoRootPath.length) { + const gitIgnoreFilePath: string = `${currentPath}/.gitignore`; + const gitIgnorePatterns: string[] | undefined = + await this._tryReadGitIgnoreFileAsync(gitIgnoreFilePath); + if (gitIgnorePatterns) { + rawIgnorePatternsByGitignoreFolder.set(currentPath, gitIgnorePatterns); + } + currentPath = currentPath.slice(0, currentPath.lastIndexOf('/')); + } + + // Load the .gitignore files for all subdirectories + const gitignoreRelativeFilePaths: string[] = await this._findUnignoredFilesAsync('*.gitignore'); + for (const gitignoreRelativeFilePath of gitignoreRelativeFilePaths) { + const gitignoreFilePath: string = `${normalizedWorkingDirectory}/${gitignoreRelativeFilePath}`; + const gitIgnorePatterns: string[] | undefined = + await this._tryReadGitIgnoreFileAsync(gitignoreFilePath); + if (gitIgnorePatterns) { + const parentPath: string = gitignoreFilePath.slice(0, gitignoreFilePath.lastIndexOf('/')); + rawIgnorePatternsByGitignoreFolder.set(parentPath, gitIgnorePatterns); + } + } + + // Create the ignore matchers for each found .gitignore file + for (const gitIgnoreParentPath of rawIgnorePatternsByGitignoreFolder.keys()) { + let ignoreMatcherPatterns: string[] = []; + currentPath = gitIgnoreParentPath; + + // Travel up the directory tree, adding the ignore patterns from each .gitignore file + while (currentPath.length >= gitRepoRootPath.length) { + // Get the root-relative path of the .gitignore file directory. Replace backslashes with forward + // slashes if backslashes are the system default path separator, since gitignore patterns use + // forward slashes. + const rootRelativePath: string = Path.convertToSlashes(path.relative(gitRepoRootPath, currentPath)); + + // Parse the .gitignore patterns according to the Git documentation: + // https://git-scm.com/docs/gitignore#_pattern_format + const resolvedGitIgnorePatterns: string[] = []; + const gitIgnorePatterns: string[] | undefined = rawIgnorePatternsByGitignoreFolder.get(currentPath); + for (let gitIgnorePattern of gitIgnorePatterns || []) { + // If the pattern is negated, track this and trim the negation so that we can do path resolution + let isNegated: boolean = false; + if (gitIgnorePattern.startsWith('!')) { + isNegated = true; + gitIgnorePattern = gitIgnorePattern.substring(1); + } + + // Validate if the path is a relative path. If so, make the path relative to the root directory + // of the Git repo. Slashes at the end of the path indicate that the pattern targets a directory + // and do not indicate the pattern is relative to the gitignore file. Non-relative patterns are + // not processed here since they are valid for all subdirectories at or below the gitignore file + // directory. + const slashIndex: number = gitIgnorePattern.indexOf('/'); + if (slashIndex >= 0 && slashIndex !== gitIgnorePattern.length - 1) { + // Trim the leading slash (if present) and append to the root relative path + if (slashIndex === 0) { + gitIgnorePattern = gitIgnorePattern.substring(1); + } + gitIgnorePattern = `${rootRelativePath}/${gitIgnorePattern}`; + } + + // Add the negation back to the pattern if it was negated + if (isNegated) { + gitIgnorePattern = `!${gitIgnorePattern}`; + } + + // Add the pattern to the list of resolved patterns in the order they are read, since the order + // of declaration of patterns in a .gitignore file matters for negations + resolvedGitIgnorePatterns.push(gitIgnorePattern); + } + + // Add the patterns to the ignore matcher patterns. Since we are crawling up the directory tree to + // the root of the Git repo we need to prepend the patterns, since the order of declaration of + // patterns in a .gitignore file matters for negations. Do this using Array.concat so that we can + // avoid stack overflows due to the variadic nature of Array.unshift. + ignoreMatcherPatterns = ([] as string[]).concat(resolvedGitIgnorePatterns, ignoreMatcherPatterns); + currentPath = currentPath.slice(0, currentPath.lastIndexOf('/')); + } + + this._ignoreMatcherByGitignoreFolder.set(gitIgnoreParentPath, ignore().add(ignoreMatcherPatterns)); + } + + return this._ignoreMatcherByGitignoreFolder; + } + + private async _tryReadGitIgnoreFileAsync(filePath: string): Promise { + let gitIgnoreContent: string | undefined; + try { + gitIgnoreContent = await FileSystem.readFileAsync(filePath); + } catch (error: unknown) { + if (!FileSystem.isFileDoesNotExistError(error as Error)) { + throw error; + } + } + + const foundIgnorePatterns: string[] = []; + if (gitIgnoreContent) { + const gitIgnorePatterns: string[] = Text.splitByNewLines(gitIgnoreContent); + for (const gitIgnorePattern of gitIgnorePatterns) { + // Ignore whitespace-only lines and comments + if (gitIgnorePattern.length === 0 || GITIGNORE_IGNORABLE_LINE_REGEX.test(gitIgnorePattern)) { + continue; + } + // Push them into the array in the order that they are read, since order matters + foundIgnorePatterns.push(gitIgnorePattern); + } + } + + // Only return if we found any valid patterns + return foundIgnorePatterns.length ? foundIgnorePatterns : undefined; + } + + private async _findUnignoredFilesAsync(searchPattern: string | undefined): Promise { + this._ensureGitMinimumVersion({ major: 2, minor: 22, patch: 0 }); + this._ensurePathIsUnderGitWorkingTree(); + + const args: string[] = [ + '--cached', + '--modified', + '--others', + '--deduplicate', + '--exclude-standard', + '-z' + ]; + if (searchPattern) { + args.push(searchPattern); + } + return await this._executeGitCommandAndCaptureOutputAsync({ + command: 'ls-files', + args, + delimiter: '\0' + }); + } + + private async _executeGitCommandAndCaptureOutputAsync( + options: IExecuteGitCommandOptions + ): Promise { + const gitPath: string = this._getGitPathOrThrow(); + const processArgs: string[] = [options.command].concat(options.args || []); + const childProcess: ChildProcess = Executable.spawn(gitPath, processArgs, { + currentWorkingDirectory: this._workingDirectory, + stdio: ['ignore', 'pipe', 'pipe'] + }); + if (!childProcess.stdout || !childProcess.stderr) { + throw new Error(`Failed to spawn Git process: ${gitPath} ${processArgs.join(' ')}`); + } + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + + return await new Promise((resolve: (value: string[]) => void, reject: (error: Error) => void) => { + const output: string[] = []; + const stdoutBuffer: string[] = []; + let errorMessage: string = ''; + + childProcess.stdout!.on('data', (chunk: Buffer) => { + stdoutBuffer.push(chunk.toString()); + }); + childProcess.stderr!.on('data', (chunk: Buffer) => { + errorMessage += chunk.toString(); + }); + childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { + if (exitCode) { + reject( + new Error(`git exited with error code ${exitCode}${errorMessage ? `: ${errorMessage}` : ''}`) + ); + } else if (signal) { + reject(new Error(`git terminated by signal ${signal}`)); + } + let remainder: string = ''; + for (let chunk of stdoutBuffer) { + let delimiterIndex: number | undefined; + while ((delimiterIndex = chunk.indexOf(options.delimiter || '\n')) >= 0) { + output.push(`${remainder}${chunk.slice(0, delimiterIndex)}`); + remainder = ''; + chunk = chunk.slice(delimiterIndex + 1); + } + remainder = chunk; + } + resolve(output); + }); + }); + } + + private _getGitPathOrThrow(): string { + const gitPath: string | undefined = this.gitPath; + if (!gitPath) { + throw new Error('Git is not present'); + } else { + return gitPath; + } + } + + private _ensureGitMinimumVersion(minimumGitVersion: IGitVersion): void { + const gitVersion: IGitVersion | undefined = this.getGitVersion(); + if (!gitVersion) { + throw new Error('Git is not present'); + } else if ( + gitVersion.major < minimumGitVersion.major || + (gitVersion.major === minimumGitVersion.major && gitVersion.minor < minimumGitVersion.minor) || + (gitVersion.major === minimumGitVersion.major && + gitVersion.minor === minimumGitVersion.minor && + gitVersion.patch < minimumGitVersion.patch) + ) { + throw new Error( + `The minimum Git version required is ` + + `${minimumGitVersion.major}.${minimumGitVersion.minor}.${minimumGitVersion.patch}. ` + + `Your version is ${gitVersion.major}.${gitVersion.minor}.${gitVersion.patch}.` + ); + } + } + + private _ensurePathIsUnderGitWorkingTree(): void { + if (!this.isPathUnderGitWorkingTree()) { + throw new Error(`The path "${this._workingDirectory}" is not under a Git working tree`); + } + } + + private _parseGitVersion(gitVersionOutput: string): IGitVersion { + // This regexp matches output of "git version" that looks like + // `git version ..(+whatever)` + // Examples: + // - git version 1.2.3 + // - git version 1.2.3.4.5 + // - git version 1.2.3windows.1 + // - git version 1.2.3.windows.1 + const versionRegex: RegExp = /^git version (\d+)\.(\d+)\.(\d+)/; + const match: RegExpMatchArray | null = versionRegex.exec(gitVersionOutput); + if (!match) { + throw new Error( + `While validating the Git installation, the "git version" command produced ` + + `unexpected output: ${JSON.stringify(gitVersionOutput)}` + ); + } + return { + major: parseInt(match[1], 10), + minor: parseInt(match[2], 10), + patch: parseInt(match[3], 10) + }; + } +} diff --git a/apps/heft/src/utilities/Selection.ts b/apps/heft/src/utilities/Selection.ts new file mode 100644 index 00000000000..28dca04ea70 --- /dev/null +++ b/apps/heft/src/utilities/Selection.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * This namespace contains functions for manipulating sets of projects + */ +export class Selection { + /** + * Computes the set of projects that are not in the input set. + */ + public static difference(first: Iterable, ...rest: ReadonlySet[]): Set { + return new Set(generateDifference(first, ...rest)); + } + + /** + * Computes the set of direct dependencies of the listed projects. + */ + public static directDependenciesOf(input: Iterable, expandFn: (target: T) => ReadonlySet): Set { + const result: Set = new Set(); + for (const item of input) { + expandInto(result, item, expandFn); + } + return result; + } + + /** + * Computes the intersection of two or more sets. + */ + public static intersection(first: Iterable, ...rest: ReadonlySet[]): Set { + return new Set(generateIntersection(first, ...rest)); + } + + /** + * Computes the union of two or more sets. + */ + public static union(...sets: Iterable[]): Set { + return new Set(generateConcatenation(...sets)); + } + + /** + * Computes a set that contains all inputs and recursively expanded inputs. + */ + public static recursiveExpand(input: Iterable, expandFn: (target: T) => ReadonlySet): Set { + return expandAll(input, expandFn); + } +} + +function* generateDifference(first: Iterable, ...rest: ReadonlySet[]): Iterable { + for (const item of first) { + if (rest.every((set: ReadonlySet) => !set.has(item))) { + yield item; + } + } +} + +function* generateIntersection(first: Iterable, ...rest: ReadonlySet[]): Iterable { + for (const item of first) { + if (rest.every((set: ReadonlySet) => set.has(item))) { + yield item; + } + } +} + +function* generateConcatenation(...sets: Iterable[]): Iterable { + for (const set of sets) { + yield* set; + } +} + +function expandInto(targetSet: Set, input: T, expandFn: (target: T) => ReadonlySet): void { + for (const child of expandFn(input)) { + targetSet.add(child); + } +} + +/** + * Computes a set derived from the input by cloning it, then iterating over every member of the new set and + * calling a step function that may add more elements to the set. + */ +function expandAll(input: Iterable, expandFn: (target: T) => ReadonlySet): Set { + const result: Set = new Set(input); + for (const item of result) { + expandInto(result, item, expandFn); + } + return result; +} diff --git a/apps/heft/src/utilities/WatchFileSystemAdapter.ts b/apps/heft/src/utilities/WatchFileSystemAdapter.ts new file mode 100644 index 00000000000..97c1ae5bdd3 --- /dev/null +++ b/apps/heft/src/utilities/WatchFileSystemAdapter.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 Watchpack from 'watchpack'; + +/** + * 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 */ +/** + * 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 */ + +/** + * Information about the state of a watched file. + * @public + */ +export interface IWatchedFileState { + /** + * If the file has changed since the last invocation. + */ + 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 IWatchFileSystem { + /** + * Prepares for incoming glob requests. Any file changed after this method is called + * 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. + */ + setBaseline(): void; + /** + * Watches all files that have been accessed since `prepare()` was called. + * Clears the tracked file lists. + */ + watch(onChange: () => void): void; +} + +interface ITimeEntry { + timestamp: number; + safeTime: number; +} + +/** + * A filesystem adapter for use with the "fast-glob" package. This adapter tracks file system accesses + * to initialize `watchpack`. + */ +export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { + private _files: Map = new Map(); + private _contexts: Map = new Map(); + private _missing: Map = new Map(); + + private _watcher: Watchpack | undefined; + + private _lastFiles: Map | undefined; + private _lastQueryTime: number | undefined; + private _times: Map | undefined; + + /** { @inheritdoc fs.readdirSync } */ + public readdirSync: IWatchFileSystemAdapter['readdirSync'] = (( + filePath: string, + options?: IReaddirOptions + ) => { + filePath = path.normalize(filePath); + + try { + if (options?.withFileTypes) { + const results: fs.Dirent[] = fs.readdirSync(filePath, options); + this._contexts.set(filePath, Date.now()); + return results; + } else { + const results: string[] = fs.readdirSync(filePath); + this._contexts.set(filePath, Date.now()); + return results; + } + } catch (err) { + this._missing.set(filePath, Date.now()); + throw err; + } + }) as IWatchFileSystemAdapter['readdirSync']; + + /** { @inheritdoc fs.readdir } */ + public readdir: IWatchFileSystemAdapter['readdir'] = ( + filePath: string, + optionsOrCallback: IReaddirOptions | ReaddirStringCallback, + callback?: ReaddirDirentCallback | ReaddirStringCallback + ) => { + filePath = path.normalize(filePath); + // Default to no options, which will return a string callback + let options: IReaddirOptions | undefined; + if (typeof optionsOrCallback === 'object') { + options = optionsOrCallback; + } else if (typeof optionsOrCallback === 'function') { + callback = optionsOrCallback; + } + + if (options?.withFileTypes) { + fs.readdir(filePath, options, (err: NodeJS.ErrnoException | null, entries: fs.Dirent[]) => { + if (err) { + this._missing.set(filePath, Date.now()); + } else { + this._contexts.set(filePath, Date.now()); + } + (callback as ReaddirDirentCallback)(err, entries); + }); + } else { + fs.readdir(filePath, (err: NodeJS.ErrnoException | null, entries: string[]) => { + if (err) { + this._missing.set(filePath, Date.now()); + } else { + this._contexts.set(filePath, Date.now()); + } + (callback as ReaddirStringCallback)(err, entries); + }); + } + }; + + /** { @inheritdoc fs.lstat } */ + 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) { + this._missing.set(filePath, Date.now()); + } else { + this._files.set(filePath, stats.mtime.getTime() || stats.ctime.getTime() || Date.now()); + } + callback(err, stats); + }); + }; + + /** { @inheritdoc fs.lstatSync } */ + public lstatSync: IWatchFileSystemAdapter['lstatSync'] = (filePath: string): fs.Stats => { + filePath = path.normalize(filePath); + try { + const stats: fs.Stats = fs.lstatSync(filePath); + this._files.set(filePath, stats.mtime.getTime() || stats.ctime.getTime() || Date.now()); + return stats; + } catch (err) { + this._missing.set(filePath, Date.now()); + throw err; + } + }; + + /** { @inheritdoc fs.stat } */ + 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) { + this._missing.set(filePath, Date.now()); + } else { + this._files.set(filePath, stats.mtime.getTime() || stats.ctime.getTime() || Date.now()); + } + callback(err, stats); + }); + }; + + /** { @inheritdoc fs.statSync } */ + public statSync: IWatchFileSystemAdapter['statSync'] = (filePath: string) => { + filePath = path.normalize(filePath); + try { + const stats: fs.Stats = fs.statSync(filePath); + this._files.set(filePath, stats.mtime.getTime() || stats.ctime.getTime() || Date.now()); + return stats; + } catch (err) { + this._missing.set(filePath, Date.now()); + throw err; + } + }; + + /** + * @inheritdoc + */ + public setBaseline(): void { + this._lastQueryTime = Date.now(); + + if (this._watcher) { + const times: Map = new Map(); + this._watcher.pause(); + this._watcher.collectTimeInfoEntries(times, times); + this._times = times; + } + } + + /** + * @inheritdoc + */ + public watch(onChange: () => void): void { + if (this._files.size === 0 && this._contexts.size === 0 && this._missing.size === 0) { + return; + } + + const watcher: Watchpack = new Watchpack({ + aggregateTimeout: 0, + followSymlinks: false + }); + + this._watcher = watcher; + watcher.watch({ + files: this._files.keys(), + directories: this._contexts.keys(), + missing: this._missing.keys(), + startTime: this._lastQueryTime + }); + + this._lastFiles = this._files; + this._files = new Map(); + this._contexts.clear(); + this._missing.clear(); + + watcher.once('aggregated', onChange); + } + + /** + * @inheritdoc + */ + public async getStateAndTrackAsync(filePath: string): Promise { + 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 + try { + const stats: fs.Stats = await fs.promises.lstat(normalizedSourcePath); + const rounded: number = stats.mtime.getTime() || stats.ctime.getTime() || Date.now(); + newTimeEntry = { + timestamp: rounded, + safeTime: rounded + }; + } catch (err) { + 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 + }; + } + + /** + * @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 new file mode 100644 index 00000000000..9b51b6d1f1d --- /dev/null +++ b/apps/heft/src/utilities/test/GitUtilities.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 * as path from 'node:path'; +import { GitUtilities, type GitignoreFilterFn } from '../GitUtilities'; +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +describe('GitUtilities', () => { + describe('checkIgnoreAsync', () => { + const projectRoot: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; + + const testFoldersBasePath: string = `${projectRoot}/src/utilities/test/checkIgnoreTests`; + + it('returns all files are ignored', async () => { + const testFolderPath: string = path.join(testFoldersBasePath, 'allIgnored'); + const git = new GitUtilities(testFolderPath); + const isUnignoredAsync: GitignoreFilterFn = (await git.tryCreateGitignoreFilterAsync())!; + expect(await isUnignoredAsync(path.join(testFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'b.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'c.txt'))).toEqual(false); + }); + + it('returns some files are ignored', async () => { + const testFolderPath: string = path.join(testFoldersBasePath, 'someIgnored'); + const git = new GitUtilities(testFolderPath); + const isUnignoredAsync: GitignoreFilterFn = (await git.tryCreateGitignoreFilterAsync())!; + expect(await isUnignoredAsync(path.join(testFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'b', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'b', 'd.txt'))).toEqual(true); + expect(await isUnignoredAsync(path.join(testFolderPath, 'e.txt'))).toEqual(true); + expect(await isUnignoredAsync(path.join(testFolderPath, 'f', 'g.txt'))).toEqual(true); + }); + + it('returns non-negated files are ignored', async () => { + const testFolderPath: string = path.join(testFoldersBasePath, 'negateIgnore'); + const git = new GitUtilities(testFolderPath); + const isUnignoredAsync: GitignoreFilterFn = (await git.tryCreateGitignoreFilterAsync())!; + expect(await isUnignoredAsync(path.join(testFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'a', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'b', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(testFolderPath, 'a', 'b.txt'))).toEqual(true); + }); + + it('returns ignored files specified in the repo gitignore', async () => { + // /apps/heft + const git = new GitUtilities(projectRoot); + const isUnignoredAsync: GitignoreFilterFn = (await git.tryCreateGitignoreFilterAsync())!; + expect(await isUnignoredAsync(path.join(projectRoot, 'lib', 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(projectRoot, 'temp', 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(projectRoot, 'dist', 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(projectRoot, 'src', 'a.txt'))).toEqual(true); + + const ignoredFolderPath: string = path.join(testFoldersBasePath, 'allIgnored'); + expect(await isUnignoredAsync(path.join(ignoredFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(ignoredFolderPath, 'b.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(ignoredFolderPath, 'c.txt'))).toEqual(false); + + const someIgnoredFolderPath: string = path.join(testFoldersBasePath, 'someIgnored'); + expect(await isUnignoredAsync(path.join(someIgnoredFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(someIgnoredFolderPath, 'b', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(someIgnoredFolderPath, 'b', 'd.txt'))).toEqual(true); + expect(await isUnignoredAsync(path.join(someIgnoredFolderPath, 'e.txt'))).toEqual(true); + expect(await isUnignoredAsync(path.join(someIgnoredFolderPath, 'f', 'g.txt'))).toEqual(true); + + const negateIgnoreFolderPath: string = path.join(testFoldersBasePath, 'negateIgnore'); + expect(await isUnignoredAsync(path.join(negateIgnoreFolderPath, 'a.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(negateIgnoreFolderPath, 'a', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(negateIgnoreFolderPath, 'b', 'c.txt'))).toEqual(false); + expect(await isUnignoredAsync(path.join(negateIgnoreFolderPath, 'a', 'b.txt'))).toEqual(true); + }); + }); +}); diff --git a/apps/heft/src/utilities/test/checkIgnoreTests/allIgnored/.gitignore b/apps/heft/src/utilities/test/checkIgnoreTests/allIgnored/.gitignore new file mode 100644 index 00000000000..4eccfb86bec --- /dev/null +++ b/apps/heft/src/utilities/test/checkIgnoreTests/allIgnored/.gitignore @@ -0,0 +1 @@ +**/*.txt \ No newline at end of file diff --git a/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/.gitignore b/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/.gitignore new file mode 100644 index 00000000000..4eccfb86bec --- /dev/null +++ b/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/.gitignore @@ -0,0 +1 @@ +**/*.txt \ No newline at end of file diff --git a/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/a/.gitignore b/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/a/.gitignore new file mode 100644 index 00000000000..546b8a83d52 --- /dev/null +++ b/apps/heft/src/utilities/test/checkIgnoreTests/negateIgnore/a/.gitignore @@ -0,0 +1 @@ +!b.txt \ No newline at end of file diff --git a/apps/heft/src/utilities/test/checkIgnoreTests/someIgnored/.gitignore b/apps/heft/src/utilities/test/checkIgnoreTests/someIgnored/.gitignore new file mode 100644 index 00000000000..803c3909681 --- /dev/null +++ b/apps/heft/src/utilities/test/checkIgnoreTests/someIgnored/.gitignore @@ -0,0 +1,2 @@ +a.txt +b/c.txt \ No newline at end of file diff --git a/apps/heft/tsconfig.json b/apps/heft/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/apps/heft/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/lockfile-explorer-web/LICENSE b/apps/lockfile-explorer-web/LICENSE new file mode 100644 index 00000000000..2ccf6ca490d --- /dev/null +++ b/apps/lockfile-explorer-web/LICENSE @@ -0,0 +1,24 @@ +@rushstack/lockfile-explorer-web + +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/apps/lockfile-explorer-web/README.md b/apps/lockfile-explorer-web/README.md new file mode 100644 index 00000000000..98c015a459f --- /dev/null +++ b/apps/lockfile-explorer-web/README.md @@ -0,0 +1,5 @@ +# @rushstack/lockfile-explorer-web + +This is the React web application component of [Rush Lockfile Explorer](../lockfile-explorer/) project. + +This package is not published; the output bundle is copied and published with the `@rushstack/lockfile-explorer` package. diff --git a/apps/lockfile-explorer-web/assets/index.html b/apps/lockfile-explorer-web/assets/index.html new file mode 100644 index 00000000000..1c5d6f471a0 --- /dev/null +++ b/apps/lockfile-explorer-web/assets/index.html @@ -0,0 +1,17 @@ + + + + + + Lockfile Explorer + + + + + +
+ + diff --git a/apps/lockfile-explorer-web/config/heft.json b/apps/lockfile-explorer-web/config/heft.json new file mode 100644 index 00000000000..e031c98a5c5 --- /dev/null +++ b/apps/lockfile-explorer-web/config/heft.json @@ -0,0 +1,42 @@ +/** + * 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-web-rig/profiles/app/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-stub": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "lib/stub", + "destinationFolders": ["dist"], + "fileExtensions": [".js"] + }, + { + "sourcePath": "node_modules/@rushstack/rush-themed-ui/dist", + "destinationFolders": ["dist"], + "fileExtensions": [".js", ".svg", ".css", ".txt"] + } + ] + } + } + } + } + } + } +} diff --git a/apps/lockfile-explorer-web/config/jest.config.json b/apps/lockfile-explorer-web/config/jest.config.json new file mode 100644 index 00000000000..dd440826f6c --- /dev/null +++ b/apps/lockfile-explorer-web/config/jest.config.json @@ -0,0 +1,6 @@ +{ + "extends": "local-web-rig/profiles/app/config/jest.config.json", + + // Load the initappcontext.js stub when running tests + "setupFiles": ["../lib-commonjs/stub/initappcontext.js"] +} diff --git a/apps/lockfile-explorer-web/config/rig.json b/apps/lockfile-explorer-web/config/rig.json new file mode 100644 index 00000000000..26f617ab3fc --- /dev/null +++ b/apps/lockfile-explorer-web/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/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 new file mode 100644 index 00000000000..fa3f62a8fba --- /dev/null +++ b/apps/lockfile-explorer-web/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rushstack/lockfile-explorer-web", + "description": "Rush Lockfile Explorer: helper project for building the React web application component", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft test --clean", + "start": "heft start", + "test": "heft test", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@reduxjs/toolkit": "~1.8.6", + "@rushstack/rush-themed-ui": "workspace:*", + "prism-react-renderer": "~2.4.1", + "react-dom": "~17.0.2", + "react-redux": "~8.0.4", + "react": "~17.0.2", + "redux": "~4.2.0", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/react": "17.0.74", + "@types/react-dom": "17.0.25", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*", + "typescript": "5.8.2" + } +} diff --git a/apps/lockfile-explorer-web/src/App.scss b/apps/lockfile-explorer-web/src/App.scss new file mode 100644 index 00000000000..01c58049d37 --- /dev/null +++ b/apps/lockfile-explorer-web/src/App.scss @@ -0,0 +1,26 @@ +@use './styles/base'; + +.ContainerCard { + padding: 12px; + @include base.card; +} + +.AppContainer { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + & > * { + width: 100%; + } +} + +.AppGrid { + flex-grow: 1; +} + +.BodyContainer { + height: 100vh; + display: flex; + flex-direction: column; + overflow-y: scroll; +} diff --git a/apps/lockfile-explorer-web/src/App.tsx b/apps/lockfile-explorer-web/src/App.tsx new file mode 100644 index 00000000000..ac1c2fbdbb6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/App.tsx @@ -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 React, { useEffect } from 'react'; + +import styles from './App.scss'; +import { readLockfileAsync } from './parsing/readLockfile'; +import { LockfileViewer } from './containers/LockfileViewer'; +import { PackageJsonViewer } from './containers/PackageJsonViewer'; +import { useAppDispatch } from './store/hooks'; +import { loadEntries } from './store/slices/entrySlice'; +import { LockfileEntryDetailsView } from './containers/LockfileEntryDetailsView'; +import { BookmarksSidebar } from './containers/BookmarksSidebar'; +import { SelectedEntryPreview } from './containers/SelectedEntryPreview'; +import { LogoPanel } from './containers/LogoPanel'; +import { ConnectionModal } from './components/ConnectionModal'; + +/** + * This React component renders the application page. + */ +export const App = (): JSX.Element => { + const dispatch = useAppDispatch(); + + useEffect(() => { + async function loadLockfileAsync(): Promise { + const lockfile = await readLockfileAsync(); + dispatch(loadEntries(lockfile)); + } + loadLockfileAsync().catch((e) => { + // eslint-disable-next-line no-console + console.log(`Failed to read lockfile: ${e}`); + }); + }, [dispatch]); + + return ( + <> + +
+
+
+
+ +
+
+ + + +
+
+ + +
+
+
+
+ + ); +}; diff --git a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx new file mode 100644 index 00000000000..1215e47d612 --- /dev/null +++ b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx @@ -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. + +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 '../../helpers/lfxApiClient'; +import type { ReactNull } from '../../types/ReactNull'; + +export const ConnectionModal = (): JSX.Element | ReactNull => { + const [isAlive, setIsAlive] = useState(true); + const [checking, setChecking] = useState(false); + const [manualChecked, setManualChecked] = useState(false); + + async function keepAliveAsync(): Promise { + if (await checkAliveAsync()) { + setIsAlive(true); + } else { + setIsAlive(false); + } + setChecking(false); + } + + useEffect(() => { + window.setInterval(keepAliveAsync, 2000); + }, []); + + const checkAliveManual = useCallback(() => { + setChecking(true); + setManualChecked(true); + keepAliveAsync().catch((e) => { + // Keep alive cannot fail + // eslint-disable-next-line no-console + console.error(`Unexpected exception: ${e}`); + }); + }, []); + + if (isAlive) { + return null; + } + + return ( +
+
+ + The Lockfile Explorer server has disconnected! + + {manualChecked ? ( + + We were still not able to connect to the server. Are you sure the "lockfile-explorer" + shell command is running? + + ) : ( + + Please restart the "lockfile-explorer" shell command to continue using this application. + + )} +
+ + {checking ? Checking... : null} +
+
+
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/components/ConnectionModal/styles.scss b/apps/lockfile-explorer-web/src/components/ConnectionModal/styles.scss new file mode 100644 index 00000000000..adc39f82071 --- /dev/null +++ b/apps/lockfile-explorer-web/src/components/ConnectionModal/styles.scss @@ -0,0 +1,27 @@ +.DisconnectOverlayBackground { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 10; + background-color: #00000040; +} + +.DisconnectOverlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + & > * + * { + margin-top: 12px; + } +} + +.DisconnectCheckRow { + display: flex; + align-items: center; + & > * + * { + margin-left: 8px; + } +} diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx new file mode 100644 index 00000000000..4e975aafe19 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx @@ -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 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 { LfxGraphEntry } from '../../packlets/lfx-shared'; +import { clearStackAndPush, removeBookmark } from '../../store/slices/entrySlice'; + +export const BookmarksSidebar = (): JSX.Element => { + const bookmarks = useAppSelector((state) => state.entry.bookmarkedEntries); + const dispatch = useAppDispatch(); + + const clear = useCallback( + (entry: LfxGraphEntry) => () => { + dispatch(clearStackAndPush(entry)); + }, + [dispatch] + ); + const deleteEntry = useCallback( + (entry: LfxGraphEntry) => () => { + dispatch(removeBookmark(entry)); + }, + [dispatch] + ); + + return ( +
+ + Bookmarks +
+ {bookmarks.map((bookmarkedEntry) => ( +
+
+ {bookmarkedEntry.displayText} +
+ +
+ ))} +
+
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/styles.scss b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/styles.scss new file mode 100644 index 00000000000..08b03e0a3b4 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/styles.scss @@ -0,0 +1,19 @@ +.BookmarksWrapper { + margin: 12px 0; + height: calc(100vh - 94px - 44px); +} + +.BookmarkEntry { + padding: 4px 0; + margin-top: 8px; + cursor: pointer; + & > * + * { + margin-top: 8px; + } +} + +.BookmarkLabel { + &:hover { + background: #dff6dd; + } +} diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx new file mode 100644 index 00000000000..a61b85fb1f1 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx @@ -0,0 +1,360 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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 { 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 { logDiagnosticInfo } from '../../helpers/logDiagnosticInfo'; +import { displaySpecChanges } from '../../helpers/displaySpecChanges'; +import type { IPackageJson } from '../../types/IPackageJson'; + +enum DependencyType { + Determinant, + TransitiveReferrer +} + +enum DependencyKey { + Regular = 'dependencies', + Dev = 'devDependencies', + Peer = 'peerDependencies' +} + +interface IInfluencerType { + entry: LfxGraphEntry; + type: DependencyType; +} + +export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { + const selectedEntry = useAppSelector(selectCurrentEntry); + const specChanges = useAppSelector((state) => state.workspace.specChanges); + const dispatch = useAppDispatch(); + + const [inspectDependency, setInspectDependency] = useState(null); + const [influencers, setInfluencers] = useState([]); + const [directRefsPackageJSON, setDirectRefsPackageJSON] = useState>( + new Map() + ); + + useEffect(() => { + async function loadPackageJson(referrers: LfxGraphEntry[]): Promise { + const referrersJsonMap = new Map(); + await Promise.all( + referrers.map(async (ref) => { + const packageJson = await readPackageJsonAsync(ref.packageJsonFolderPath); + referrersJsonMap.set(ref.rawEntryId, packageJson); + return packageJson; + }) + ); + + setDirectRefsPackageJSON(referrersJsonMap); + } + + loadPackageJson(selectedEntry?.referrers || []).catch((e) => { + // eslint-disable-next-line no-console + console.error(`Failed to load referrers package.json: ${e}`); + }); + if (selectedEntry) { + setInspectDependency(null); + } + }, [selectedEntry]); + + const selectResolvedEntry = useCallback( + (dependencyToTrace) => () => { + if (inspectDependency && inspectDependency.entryId === dependencyToTrace.entryId) { + if (dependencyToTrace.resolvedEntry) { + dispatch(pushToStack(dependencyToTrace.resolvedEntry)); + } else { + logDiagnosticInfo('No resolved entry for dependency:', dependencyToTrace); + } + } else if (selectedEntry) { + // eslint-disable-next-line no-console + console.log('dependency to trace: ', dependencyToTrace); + setInspectDependency(dependencyToTrace); + + // Check if we need to calculate influencers. + // If the current dependencyToTrace is a peer dependency then we do + if (dependencyToTrace.dependencyType !== LfxDependencyKind.Peer) { + return; + } + + // calculate influencers + const stack = [selectedEntry]; + const determinants = new Set(); + const transitiveReferrers = new Set(); + const visitedNodes = new Set(); + visitedNodes.add(selectedEntry); + while (stack.length) { + const currEntry = stack.pop(); + if (currEntry) { + for (const referrer1 of currEntry.referrers) { + let hasDependency = false; + for (const dependency of referrer1.dependencies) { + if (dependency.name === dependencyToTrace.name) { + determinants.add(referrer1); + hasDependency = true; + break; + } + } + if (!hasDependency) { + if (referrer1.transitivePeerDependencies.has(dependencyToTrace.name)) { + transitiveReferrers.add(referrer1); + } else { + // Since this referrer does not declare "dependency", it is a + // transitive peer dependency, and we call the referrer a "transitive referrer". + // PNPM should have added it to the "transitivePeerDependencies" list in the + // YAML file. If not, either something is wrong with our algorithm, or else + // something has changed about how PNPM manages its "transitivePeerDependencies" + // field. + // eslint-disable-next-line no-console + console.error( + 'Error analyzing influencers: A referrer appears to be missing its "transitivePeerDependencies" field in the YAML file: ', + dependencyToTrace, + referrer1, + currEntry + ); + } + + for (const referrer2 of currEntry.referrers) { + if (!visitedNodes.has(referrer2)) { + stack.push(referrer2); + visitedNodes.add(referrer2); + } + } + } + } + } + } + const newInfluencers: IInfluencerType[] = []; + for (const determinant of determinants.values()) { + newInfluencers.push({ + entry: determinant, + type: DependencyType.Determinant + }); + } + for (const referrer of transitiveReferrers.values()) { + newInfluencers.push({ + entry: referrer, + type: DependencyType.TransitiveReferrer + }); + } + setInfluencers(newInfluencers); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [selectedEntry, inspectDependency] + ); + + const selectResolvedReferencer = useCallback( + (referrer) => () => { + dispatch(pushToStack(referrer)); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [selectedEntry] + ); + + const renderDependencyMetadata = (): JSX.Element | ReactNull => { + if (!inspectDependency) { + return ReactNull; + } + return ( +
+ +
+ + Selected Dependency:{' '} + + + {inspectDependency.name}: {inspectDependency.versionPath} + +
+
+ + package.json spec:{' '} + + + {inspectDependency.dependencyKind === LfxDependencyKind.Peer + ? `"${inspectDependency.peerDependencyMeta.version}" ${ + inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required' + } Peer` + : inspectDependency.versionPath} + +
+
+ + .pnpmfile.cjs:{' '} + + + {specChanges.has(inspectDependency.name) + ? displaySpecChanges(specChanges, inspectDependency.name) + : 'No Effect'} + +
+
+
+ ); + }; + + const renderPeerDependencies = (): JSX.Element | ReactNull => { + if (!selectedEntry) return ReactNull; + const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyKind === LfxDependencyKind.Peer); + if (!peerDeps.length) { + return ( +
+ No peer dependencies. +
+ ); + } + if (!inspectDependency || inspectDependency.dependencyKind !== LfxDependencyKind.Peer) { + return ( +
+ Select a peer dependency to view its influencers +
+ ); + } + + const determinants = influencers.filter((inf) => inf.type === DependencyType.Determinant); + const transitiveReferrers = influencers.filter((inf) => inf.type === DependencyType.TransitiveReferrer); + + return ( +
+ + + Determinants: + + {determinants.length ? ( + determinants.map(({ entry }) => ( + + {entry.displayText} + + )) + ) : ( + (none) + )} + + Transitive Referencers: + + {transitiveReferrers.length ? ( + transitiveReferrers.map(({ entry }) => ( + + {entry.displayText} + + )) + ) : ( + (none) + )} + +
+ ); + }; + + const getDependencyInfo = ( + rawEntryId: string, + entryPackageName: string + ): { type: DependencyKey; version: string } | undefined => { + const packageJson = directRefsPackageJSON.get(rawEntryId); + if (!packageJson) return undefined; + + const dependencyTypes = [DependencyKey.Regular, DependencyKey.Dev, DependencyKey.Peer]; + + for (const type of dependencyTypes) { + const version = packageJson[type]?.[entryPackageName]; + if (version) { + return { type, version }; + } + } + return undefined; + }; + + if (!selectedEntry) { + return ( +
+ + Select an entry to view its details + +
+ ); + } + + return ( + <> +
+
+ + Direct Referrers + +
+ + {selectedEntry.referrers?.map((referrer: LfxGraphEntry) => ( +
+ + Name: {referrer.displayText} + +
+ Entry ID: {referrer.rawEntryId} + + {'Dependency version: '} + {getDependencyInfo(referrer.rawEntryId, selectedEntry.entryPackageName)?.version} + +
+
+ ))} +
+
+
+
+ + Direct Dependencies + +
+ + {selectedEntry.dependencies?.map((dependency: LfxGraphDependency) => ( +
+ + Name: {dependency.name}{' '} + {dependency.dependencyKind === LfxDependencyKind.Peer + ? `${ + dependency.peerDependencyMeta.optional ? '(Optional)' : '(Non-optional)' + } Peer Dependency` + : ''} + +
+ Version: {dependency.versionPath} + Entry ID: {dependency.entryId} +
+
+ ))} +
+
+
+
+ {renderDependencyMetadata()} + {renderPeerDependencies()} + + ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/styles.scss b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/styles.scss new file mode 100644 index 00000000000..5cdbee54471 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/styles.scss @@ -0,0 +1,64 @@ +@use '../../styles/base'; + +.LockfileEntryListView { + display: flex; + justify-content: space-between; + min-height: 400px; + flex: 1; + padding-top: 12px; + & > * { + width: calc(50% - 24px - 12px); + } +} + +.DependencyListWrapper { + margin-top: 8px; + height: calc(100% - 24px); +} + +.DependencyItem { + border: 1px solid white; + cursor: pointer; + margin-top: 12px; + &:hover { + border: 1px solid #107c10; + } + & > * + * { + margin-top: 8px; + } +} + +.SelectedDependencyItem { + background-color: #dff6dd; +} + +.InfluencerList { + margin: 12px 0; +} + +.DependencyDetails { + @include base.card; + padding: 12px; + margin-top: 12px; +} + +.InfluencerEntry { + display: block; + cursor: pointer; + &:hover { + color: #107c10; + text-decoration: underline; + } +} + +.DependencyDetailInfo { + display: flex; + align-items: center; + span { + margin-left: 4px; + } +} + +.TransitiveReferencersHeader { + margin-top: 12px; +} diff --git a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx new file mode 100644 index 00000000000..2d1ed77775b --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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 LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; +import { ReactNull } from '../../types/ReactNull'; +import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { + pushToStack, + selectCurrentEntry, + selectFilteredEntries, + setFilter as selectFilter +} from '../../store/slices/entrySlice'; +import { getFilterFromLocalStorage, saveFilterToLocalStorage } from '../../helpers/localStorage'; + +interface ILockfileEntryGroup { + entryName: string; + versions: LfxGraphEntry[]; +} + +const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element => { + const selectedEntry = useAppSelector(selectCurrentEntry); + const activeFilters = useAppSelector((state) => state.entry.filters); + const dispatch = useAppDispatch(); + const fieldRef = useRef() as React.MutableRefObject; + const clear = useCallback( + (entry: LfxGraphEntry) => () => { + dispatch(pushToStack(entry)); + }, + [dispatch] + ); + + useEffect(() => { + if (selectedEntry && selectedEntry.entryPackageName === group.entryName) { + fieldRef.current.scrollIntoView({ + behavior: 'smooth' + }); + } + }, [selectedEntry, group]); + + if (activeFilters[LfxGraphEntryKind.Project]) { + return ( +
+ {group.versions.map((entry) => ( +
+ {entry.entryPackageName} +
+ ))} +
+ ); + } + + return ( +
+ + {group.entryName} + + {group.versions.map((entry) => ( +
+ + {entry.entryPackageVersion} {entry.entrySuffix && `[${entry.entrySuffix}]`} + +
+ ))} +
+ ); +}; + +const multipleVersions = (entries: LfxGraphEntry[]): boolean => { + const set = new Set(); + for (const entry of entries) { + if (set.has(entry.entryPackageVersion)) return true; + set.add(entry.entryPackageVersion); + } + return false; +}; + +export const LockfileViewer = (): JSX.Element | 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: LfxGraphEntryKind) => (e: React.ChangeEvent) => { + if (type === LfxGraphEntryKind.Project) { + setProjectFilter(e.target.value); + } else { + setPackageFilter(e.target.value); + } + saveFilterToLocalStorage(e.target.value, type); + }, + [] + ); + + useEffect(() => { + setProjectFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Project)); + setPackageFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Package)); + }, []); + + const getEntriesToShow = (): ILockfileEntryGroup[] => { + let filteredEntries: LfxGraphEntry[] = entries; + if (projectFilter && activeFilters[LfxGraphEntryKind.Project]) { + filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(projectFilter) !== -1); + } else if (packageFilter && activeFilters[LfxGraphEntryKind.Package]) { + filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(packageFilter) !== -1); + } + + const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LfxGraphEntry[] }, item) => { + const group = groups[item.entryPackageName] || []; + group.push(item); + groups[item.entryPackageName] = group; + return groups; + }, {}); + let groupedEntries: ILockfileEntryGroup[] = []; + for (const [packageName, versions] of Object.entries(reducedEntries)) { + groupedEntries.push({ + entryName: packageName, + versions + }); + } + + if (activeFilters[LfxGraphEntryKind.SideBySide]) { + groupedEntries = groupedEntries.filter((entry) => entry.versions.length > 1); + } + if (activeFilters[LfxGraphEntryKind.Doppelganger]) { + groupedEntries = groupedEntries.filter((entry) => multipleVersions(entry.versions)); + } + + if (activeFilters[LfxGraphEntryKind.Project]) { + groupedEntries = groupedEntries.sort((a, b) => + a.entryName > b.entryName ? 1 : b.entryName > a.entryName ? -1 : 0 + ); + } + + return groupedEntries; + }; + + const changeFilter = useCallback( + (filter: LfxGraphEntryKind, enabled: boolean) => (): void => { + dispatch(selectFilter({ filter, state: enabled })); + }, + [dispatch] + ); + + const togglePackageView = useCallback( + (selected: string) => { + if (selected === 'Projects') { + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: false })); + } else { + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: false })); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [dispatch, activeFilters] + ); + + if (!entries) { + return ReactNull; + } else { + return ( +
+
+ + + + {getEntriesToShow().map((lockfileEntryGroup) => ( + + ))} + + {activeFilters[LfxGraphEntryKind.Package] ? ( +
+ + Filters + + + +
+ ) : null} +
+
+ ); + } +}; diff --git a/apps/lockfile-explorer-web/src/containers/LockfileViewer/styles.scss b/apps/lockfile-explorer-web/src/containers/LockfileViewer/styles.scss new file mode 100644 index 00000000000..51321ffa193 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LockfileViewer/styles.scss @@ -0,0 +1,58 @@ +@use '../../styles/base'; + +.ViewWrapper { + height: calc(100% - 24px); + @include base.card; + padding: 0 12px; + margin-top: 12px; +} + +.ViewContents { + display: flex; + flex-direction: column; + height: calc(100% - 35px); + & > * + * { + margin-top: 12px; + } +} + +.LockfileEntryListViewWrapper { + cursor: pointer; + border: 1px solid #fff; + padding: 4px 8px; + + &:hover { + border: 1px solid black; + } +} + +.packageGroup { + & > * + * { + margin-top: 4px; + } +} + +.lockfileEntries { + cursor: pointer; + padding: 4px 8px; + &:hover { + background: #dff6dd; + } +} + +.lockfileSelectedEntry { + background-color: #dff6dd; +} + +.lockfileEntriesWrapper { + flex: 1; + height: 100%; +} + +.filterSection { + border-top: 1px solid #000; + padding-top: 24px; + & > * + * { + margin-top: 4px; + } +} diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx new file mode 100644 index 00000000000..330be195eb6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx @@ -0,0 +1,48 @@ +// 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 styles from './styles.scss'; + +export const LogoPanel = (): JSX.Element => { + // TODO: Add a mechanism to keep this in sync with the @rushstack/lockfile-explorer + // package version. + const appPackageVersion: string = window.appContext.appVersion; + + return ( + + ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-icon.svg b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-icon.svg new file mode 100644 index 00000000000..95e50e9404d --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-icon.svg @@ -0,0 +1,4 @@ + + + +Rush Lockfile Explorerimage/svg+xmlRush Lockfile Explorerhttps://github.com/octogonzCopyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-1.svg b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-1.svg new file mode 100644 index 00000000000..27849842332 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-1.svg @@ -0,0 +1,4 @@ + + + +lockfileimage/svg+xmlRush Lockfile Explorerhttps://github.com/octogonzCopyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-2.svg b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-2.svg new file mode 100644 index 00000000000..e7193665905 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/lockfile-explorer-title-2.svg @@ -0,0 +1,4 @@ + + + +explorerimage/svg+xmlRush Lockfile Explorerhttps://github.com/octogonzCopyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/styles.scss b/apps/lockfile-explorer-web/src/containers/LogoPanel/styles.scss new file mode 100644 index 00000000000..a668bfaf689 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/styles.scss @@ -0,0 +1,36 @@ +.LogoPanel { + display: flex; + & > * + * { + margin-left: 12px; + } + a { + text-decoration: none; + } +} + +.Icon { + padding-top: 5px; + height: 64px; +} + +.Title1 { + padding-top: 7px; + height: 20px; +} + +.Title2 { + padding-top: 5px; + height: 20px; +} + +.Image { + height: 100%; + object-fit: contain; +} + +.Detail { + color: #ab9e8e; + font-family: Tahoma, sans-serif; + font-size: 14px; + padding-top: 4px; +} 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..627dab524f1 --- /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 }): JSX.Element => { + 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 new file mode 100644 index 00000000000..736e4749d76 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx @@ -0,0 +1,278 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import React, { useCallback, useEffect, useState } from 'react'; + +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'; +import { compareSpec } from '../../parsing/compareSpec'; +import { loadSpecChanges } from '../../store/slices/workspaceSlice'; +import { displaySpecChanges } from '../../helpers/displaySpecChanges'; +import { isEntryModified } from '../../helpers/isEntryModified'; +import { LfxGraphEntryKind } from '../../packlets/lfx-shared'; +import { CodeBox } from './CodeBox'; +import styles from './styles.scss'; + +const PackageView: { [key: string]: string } = { + PACKAGE_JSON: 'PACKAGE_JSON', + PACKAGE_SPEC: 'PACKAGE_SPEC', + PARSED_PACKAGE_JSON: 'PARSED_PACKAGE_JSON' +}; + +export const PackageJsonViewer = (): JSX.Element => { + const dispatch = useAppDispatch(); + const [packageJSON, setPackageJSON] = useState(undefined); + const [parsedPackageJSON, setParsedPackageJSON] = useState(undefined); + const [pnpmfile, setPnpmfile] = useState(''); + const selectedEntry = useAppSelector(selectCurrentEntry); + + const specChanges = useAppSelector((state) => state.workspace.specChanges); + + const [selection, setSelection] = useState(PackageView.PARSED_PACKAGE_JSON); + + const cb = useCallback((s: string) => { + setSelection(s); + }, []); + + useEffect(() => { + async function loadPnpmFileAsync(): Promise { + const repoPnpmfile = await readPnpmfileAsync(); + setPnpmfile(repoPnpmfile); + } + loadPnpmFileAsync().catch((e) => { + // eslint-disable-next-line no-console + console.error(`Failed to load project's pnpm file: ${e}`); + }); + }, []); + + useEffect(() => { + async function loadPackageDetailsAsync(packageName: string): Promise { + const packageJSONFile: IPackageJson | undefined = await readPackageJsonAsync(packageName); + setPackageJSON(packageJSONFile); + const parsedJSON: IPackageJson | undefined = await readPackageSpecAsync(packageName); + setParsedPackageJSON(parsedJSON); + + if (packageJSONFile && parsedJSON) { + const diffDeps = compareSpec(packageJSONFile, parsedJSON); + dispatch(loadSpecChanges(diffDeps)); + } + } + if (selectedEntry) { + if (selectedEntry.entryPackageName) { + loadPackageDetailsAsync(selectedEntry.packageJsonFolderPath).catch((e) => { + // eslint-disable-next-line no-console + console.error(`Failed to load project information: ${e}`); + }); + } else { + // This is used to develop the lockfile explorer application in case there is a mistake in our logic + // eslint-disable-next-line no-console + console.log('The selected entry has no entry name: ', selectedEntry.entryPackageName); + } + } + }, [dispatch, selectedEntry]); + + const renderDep = + (name: boolean): ((dependencyDetails: [string, string]) => JSX.Element) => + (dependencyDetails) => { + const [dep, version] = dependencyDetails; + if (specChanges.has(dep)) { + switch (specChanges.get(dep)?.type) { + case 'add': + if (name) { + return ( + + {dep} + + ); + } else { + return ( + + {version} {displaySpecChanges(specChanges, dep)} + + ); + } + case 'diff': + if (name) { + return ( + + {dep} + + ); + } else { + return ( + + {version} {displaySpecChanges(specChanges, dep)} + + ); + } + case 'remove': + if (name) { + return ( + + {dep} + + ); + } else { + return ( + + {version} {displaySpecChanges(specChanges, dep)} + + ); + } + default: + if (name) { + return ( + + {dep}: + + ); + } else { + return ( + + {version} + + ); + } + } + } else { + if (name) { + return ( + + {dep}: + + ); + } else { + return ( + + {version} + + ); + } + } + }; + + const renderFile = (): JSX.Element | null => { + switch (selection) { + case PackageView.PACKAGE_JSON: + if (!packageJSON) + return ( + + Please select a Project or Package to view it's package.json + + ); + return ; + case PackageView.PACKAGE_SPEC: + if (!pnpmfile) { + return ( + + Couldn't load the pnpmfile.cjs file - does it exist in the expected location? + (/common/config/rush/.pnpmfile.cjs) + + ); + } + return ; + case PackageView.PARSED_PACKAGE_JSON: + if (!parsedPackageJSON) + return ( + + Please select a Project or Package to view the parsed package.json + + ); + return ( +
+
+ + Package Name: + + + {selectedEntry?.kind === LfxGraphEntryKind.Project + ? parsedPackageJSON.name + : selectedEntry?.displayText} + +
+
+ + Version: + + {selectedEntry?.entryPackageVersion || parsedPackageJSON.version} +
+
+
+ + Dependencies + + {parsedPackageJSON.dependencies && + Object.entries(parsedPackageJSON.dependencies).map(renderDep(true))} + + + Dev Dependencies + + {parsedPackageJSON.devDependencies && + Object.entries(parsedPackageJSON.devDependencies).map(renderDep(true))} + + + Peer Dependencies + + {parsedPackageJSON.peerDependencies && + Object.entries(parsedPackageJSON.peerDependencies).map(renderDep(true))} +
+
+ +   + + {parsedPackageJSON.dependencies && + Object.entries(parsedPackageJSON.dependencies).map(renderDep(false))} + + +   + + {parsedPackageJSON.devDependencies && + Object.entries(parsedPackageJSON.devDependencies).map(renderDep(false))} + + +   + + {parsedPackageJSON.peerDependencies && + Object.entries(parsedPackageJSON.peerDependencies).map(renderDep(false))} +
+
+
+ ); + default: + return null; + } + }; + + return ( +
+ + +
+ +
{renderFile()}
+
+
+
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/styles.scss b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/styles.scss new file mode 100644 index 00000000000..bf4530d422e --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/styles.scss @@ -0,0 +1,69 @@ +@use '../../styles/base'; + +.PackageJsonWrapper { + @include base.card; + min-height: 400px; + flex: 1; + margin-top: 12px; +} + +.FileContents { + height: calc(100% - 46px); + padding: 0 12px; +} + +.FileInnerContent { + padding-top: 12px; +} + +@mixin SpecWrapper { + padding: 2px 4px; + border-radius: 2px; + color: white; +} + +.AddedSpec { + background-color: #107c10; + @include SpecWrapper; +} + +.DeletedSpec { + background-color: red; + @include SpecWrapper; +} + +.ChangedSpec { + background-color: darkgoldenrod; + @include SpecWrapper; +} + +.PackageSpecWrapper { + h5 { + margin-bottom: 8px; + } + & > * + * { + margin-top: 8px; + } +} + +.PackageSpecEntry { + & > * { + display: inline; + } + & > * + * { + margin-left: 12px; + } +} + +.DependencyRows { + display: flex; + align-items: flex-start; + & > * + * { + margin-left: 12px; + } + div { + & > * + * { + margin-top: 4px; + } + } +} diff --git a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx new file mode 100644 index 00000000000..a6f1f4a4e9d --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx @@ -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. + +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 { + addBookmark, + forwardStack, + popStack, + removeBookmark, + selectCurrentEntry +} from '../../store/slices/entrySlice'; + +export const SelectedEntryPreview = (): JSX.Element => { + const selectedEntry = useAppSelector(selectCurrentEntry); + const isBookmarked = useAppSelector((state) => + selectedEntry ? state.entry.bookmarkedEntries.includes(selectedEntry) : false + ); + + const entryStack = useAppSelector((state) => state.entry.selectedEntryStack); + const entryForwardStack = useAppSelector((state) => state.entry.selectedEntryForwardStack); + const dispatch = useAppDispatch(); + + const bookmark = useCallback(() => { + if (selectedEntry) dispatch(addBookmark(selectedEntry)); + }, [dispatch, selectedEntry]); + const deleteEntry = useCallback(() => { + if (selectedEntry) dispatch(removeBookmark(selectedEntry)); + }, [dispatch, selectedEntry]); + + const pop = useCallback(() => { + dispatch(popStack()); + }, [dispatch]); + const forward = useCallback(() => { + dispatch(forwardStack()); + }, [dispatch]); + + const renderButtonRow = (): JSX.Element => { + return ( +
+ + + {isBookmarked ? ( + + ) : ( + + )} +
+ ); + }; + + if (!selectedEntry) { + return ( +
+
+ + No Entry Selected + + {renderButtonRow()} +
+
+ ); + } + + return ( +
+ +
+
+ + Selected entry: + + {selectedEntry.displayText} +
+ {renderButtonRow()} +
+
+ Package Entry: {selectedEntry.rawEntryId} + Package JSON path: {selectedEntry.packageJsonFolderPath} +
+
+
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/styles.scss b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/styles.scss new file mode 100644 index 00000000000..591fc4c2274 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/styles.scss @@ -0,0 +1,33 @@ +@use '../../styles/base'; + +.SelectedEntryCard { + margin-top: 12px; + @include base.card; + padding: 12px; + & > * + * { + margin-top: 8px; + } +} + +.SelectedEntryBookmarkRow { + display: flex; + justify-content: space-between; +} + +.SelectedEntryHeader { + display: flex; + align-items: center; + & > * + * { + margin-left: 8px; + } +} + +.NavigationButtonRow { + display: flex; + & > * { + height: 21px; + } + & > * + * { + margin-left: 8px; + } +} diff --git a/apps/lockfile-explorer-web/src/helpers/displaySpecChanges.ts b/apps/lockfile-explorer-web/src/helpers/displaySpecChanges.ts new file mode 100644 index 00000000000..e10bfb54c1b --- /dev/null +++ b/apps/lockfile-explorer-web/src/helpers/displaySpecChanges.ts @@ -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. + +import type { ISpecChange } from '../parsing/compareSpec'; + +export const displaySpecChanges = (specChanges: Map, dep: string): string => { + switch (specChanges.get(dep)?.type) { + case 'add': + return '[Added by .pnpmfile.cjs]'; + case 'diff': + return `[Changed from ${specChanges.get(dep)?.from}]`; + case 'remove': + return '[Deleted by .pnpmfile.cjs]'; + default: + return 'No Change'; + } +}; diff --git a/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts b/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts new file mode 100644 index 00000000000..9750281021a --- /dev/null +++ b/apps/lockfile-explorer-web/src/helpers/isEntryModified.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 type { ISpecChange } from '../parsing/compareSpec'; +import type { LfxGraphEntry } from '../packlets/lfx-shared'; + +export const isEntryModified = ( + entry: LfxGraphEntry | undefined, + specChanges: Map +): boolean => { + if (!entry) return false; + for (const dep of entry.dependencies) { + if (specChanges.has(dep.name)) { + return true; + } + } + return false; +}; diff --git a/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts new file mode 100644 index 00000000000..9cc6f469556 --- /dev/null +++ b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.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 type { IPackageJson } from '../types/IPackageJson'; +import type { IJsonLfxWorkspace } from '../packlets/lfx-shared'; + +const SERVICE_URL: string = window.appContext.serviceUrl; + +export async function checkAliveAsync(): Promise { + try { + await fetch(`${SERVICE_URL}/api/health`); + return true; + } catch (e) { + return false; + } +} + +/** + * Read the contents of a text file under the workspace directory. + * @param relativePath - a file path that is relative to the working directory. + */ +export async function readWorkspaceConfigAsync(): Promise { + let response: Response; + + try { + response = await fetch(`${SERVICE_URL}/api/workspace`); + if (!response.ok) { + const responseText: string = await response.text(); + const error = new Error( + 'The operation failed: ' + (responseText.trim() || 'An unknown error occurred') + ); + // eslint-disable-next-line no-console + console.error('readWorkspaceConfigAsync() failed: ', error); + throw error; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Network error in readWorkspaceConfigAsync(): ', e); + throw new Error('Network error: ' + (e.message || 'An unknown error occurred')); + } + + const responseJson: IJsonLfxWorkspace = await response.json(); + return responseJson; +} + +/** + * Fetches a projects configuration files from the local file system + * + * @returns a json object representing a package.json or a text file to be rendered (in the case of readPnpmfile) + */ +export async function readPnpmfileAsync(): Promise { + try { + const response = await fetch(`${SERVICE_URL}/api/pnpmfile`); + return await response.text(); + } catch (e) { + // eslint-disable-next-line no-console + console.error('Could not load cjs file: ', e); + return 'Missing CJS'; + } +} + +export async function readPackageJsonAsync(projectPath: string): Promise { + try { + const response = await fetch(`${SERVICE_URL}/api/package-json`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + projectPath + }) + }); + return await response.json(); + } catch (e) { + // eslint-disable-next-line no-console + console.error('Could not load package json file: ', e); + return undefined; + } +} + +export async function readPackageSpecAsync(projectPath: string): Promise { + try { + const response = await fetch(`${SERVICE_URL}/api/package-spec`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + projectPath + }) + }); + return await response.json(); + } catch (e) { + // eslint-disable-next-line no-console + console.error('Could not load cjs file: ', e); + return undefined; + } +} diff --git a/apps/lockfile-explorer-web/src/helpers/localStorage.ts b/apps/lockfile-explorer-web/src/helpers/localStorage.ts new file mode 100644 index 00000000000..5242b4e368b --- /dev/null +++ b/apps/lockfile-explorer-web/src/helpers/localStorage.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 LfxGraphEntry, LfxGraphEntryKind } from '../packlets/lfx-shared'; + +const BOOKMARK_KEY: string = 'LOCKFILE_EXPLORER_BOOKMARKS'; + +export const getBookmarksFromStorage = (): Set => { + const currBookmarks = JSON.parse(localStorage.getItem(BOOKMARK_KEY) || '{}'); + const bookmarkSet = new Set(); + for (const key of Object.keys(currBookmarks)) { + bookmarkSet.add(key); + } + return bookmarkSet; +}; + +export const saveBookmarkToLocalStorage = (entry: LfxGraphEntry): void => { + const key = entry.rawEntryId; + const currBookmarks = JSON.parse(localStorage.getItem(BOOKMARK_KEY) || '{}'); + currBookmarks[key] = true; + localStorage.setItem(BOOKMARK_KEY, JSON.stringify(currBookmarks)); +}; + +export const removeBookmarkFromLocalStorage = (entry: LfxGraphEntry): void => { + const key = entry.rawEntryId; + const currBookmarks = JSON.parse(localStorage.getItem(BOOKMARK_KEY) || '{}'); + delete currBookmarks[key]; + localStorage.setItem(BOOKMARK_KEY, JSON.stringify(currBookmarks)); +}; + +const PROJECT_FILTER_KEY: string = 'LOCKFILE_EXPLORER_PROJECT_FILTER'; +const PACKAGE_FILTER_KEY: string = 'LOCKFILE_EXPLORER_PACKAGE_FILTER'; +export const saveFilterToLocalStorage = (filter: string, type: LfxGraphEntryKind): void => { + if (type === LfxGraphEntryKind.Project) { + localStorage.setItem(PROJECT_FILTER_KEY, filter); + } else { + localStorage.setItem(PACKAGE_FILTER_KEY, filter); + } +}; + +export const getFilterFromLocalStorage = (type: LfxGraphEntryKind): string => { + if (type === LfxGraphEntryKind.Project) { + return localStorage.getItem(PROJECT_FILTER_KEY) || ''; + } else { + return localStorage.getItem(PACKAGE_FILTER_KEY) || ''; + } +}; diff --git a/apps/lockfile-explorer-web/src/helpers/logDiagnosticInfo.ts b/apps/lockfile-explorer-web/src/helpers/logDiagnosticInfo.ts new file mode 100644 index 00000000000..771dd26e8a4 --- /dev/null +++ b/apps/lockfile-explorer-web/src/helpers/logDiagnosticInfo.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Used to log diagnostics that may be useful when troubleshooting +// problems with the algorithm. +export const logDiagnosticInfo = (...args: string[]): void => { + if (window.appContext.debugMode) { + // eslint-disable-next-line no-console + console.log('Diagnostic: ', ...args); + } +}; diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/IAppContext.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IAppContext.ts new file mode 100644 index 00000000000..93792c57b59 --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IAppContext.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. + +/** + * 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; +} diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts new file mode 100644 index 00000000000..35baa33daca --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.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. + +import type { IJsonLfxWorkspace } from './IJsonLfxWorkspace'; + +export enum LfxGraphEntryKind { + Project = 1, + Package = 2, + SideBySide = 3, + Doppelganger = 4 +} + +export interface IJsonPeerDependencyMeta { + name?: string; + version?: string; + optional?: boolean; +} + +export interface IJsonLfxDependency { + name: string; + versionPath: string; + entryId: string; + originalSpecifier: string; + dependencyKind: LfxDependencyKind; + peerDependencyMeta: IJsonPeerDependencyMeta; + + resolvedEntryJsonId?: number; +} + +export enum LfxDependencyKind { + Regular = 'regular', + Dev = 'dev', + Peer = 'peer' +} + +export interface IJsonLfxEntry { + /** + * A unique ID used when serializing graph links. + * + * @remarks + * This is just the `IJsonLfxGraph.entries` array index, but debugging is easier if we include + * it in the serialized representation. + */ + jsonId: number; + + kind: LfxGraphEntryKind; + entryId: string; + rawEntryId: string; + packageJsonFolderPath: string; + entryPackageName: string; + displayText: string; + entryPackageVersion: string; + entrySuffix: string; + + // Lists + dependencies: IJsonLfxDependency[]; + transitivePeerDependencies: string[]; + referrerJsonIds: number[]; +} + +export interface IJsonLfxGraph { + workspace: IJsonLfxWorkspace; + entries: IJsonLfxEntry[]; +} diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts new file mode 100644 index 00000000000..d5115c1b33b --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IJsonLfxWorkspaceRushConfig { + /** + * The `rushVersion` field from rush.json. + */ + readonly rushVersion: string; + + /** + * If the subspaces feature is enabled and a subspace was loaded, the name of the subspace. + * Otherwise this will be an empty string. + */ + readonly subspaceName: string; + + /** + * The path to Rush's input file `.pnpmfile.cjs`, relative to `workspaceRootFullPath` + * and normalized to use forward slashes without a leading slash. In a Rush workspace, + * {@link IJsonLfxWorkspace.pnpmfilePath} is a temporary file that is generated from `rushPnpmfilePath`. + * + * @example `"common/config/my-subspace/pnpm-lock.yaml"` + */ + readonly rushPnpmfilePath: string; +} + +export interface IJsonLfxWorkspace { + /** + * Absolute path to the workspace folder that is opened by the app, normalized to use forward slashes + * without a trailing slash. + * + * @example `"C:/path/to/MyRepo"` + */ + readonly workspaceRootFullPath: string; + + /** + * The path to the "pnpm-lock.yaml" file, relative to `workspaceRootFullPath` + * and normalized to use forward slashes without a leading slash. + * + * @example `"common/temp/my-subspace/pnpm-lock.yaml"` + * @example `"pnpm-lock.yaml"` + */ + readonly pnpmLockfilePath: string; + + /** + * The path to the folder of "pnpm-lock.yaml" file, relative to `workspaceRootFullPath` + * and normalized to use forward slashes without a leading slash. + * + * If `pnpm-lack.yaml` is in the `workspaceRootFullPath` folder, then pnpmLockfileFolder + * is the empty string. + * + * @example `"common/temp/my-subspace"` + * @example `""` + */ + readonly pnpmLockfileFolder: string; + + /** + * The path to the `.pnpmfile.cjs` file that is loaded by PNPM. In a Rush workspace, + * this is a temporary file that is generated from `rushPnpmfilePath`. + * + * @example `"common/temp/my-subspace/.pnpmfile.cjs"` + */ + readonly pnpmfilePath: string; + + /** + * This section will be defined only if this is a Rush workspace (versus a plain PNPM workspace). + */ + readonly rushConfig: IJsonLfxWorkspaceRushConfig | undefined; +} diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts new file mode 100644 index 00000000000..a45371b7ba3 --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LfxDependencyKind, IJsonPeerDependencyMeta, LfxGraphEntryKind } from './IJsonLfxGraph'; +import type { IJsonLfxWorkspace } from './IJsonLfxWorkspace'; + +export interface ILfxGraphDependencyOptions { + name: string; + versionPath: string; + + entryId: string; + + originalSpecifier: string; + dependencyKind: LfxDependencyKind; + peerDependencyMeta: IJsonPeerDependencyMeta; + + containingEntry: LfxGraphEntry; +} + +/** + * Represents an graph edge, which is an exact dependency version obtained from the lockfile. + */ +export class LfxGraphDependency { + /** + * The referenced package name. + * Example: `@scope/package-name` + */ + public readonly name: string; + + /** + * The lockfile's raw string that either indicates an external reference such as `link:../target-folder`, + * or else can be combined with the `name` field to construct an `entryId` found in the lockfile. + * The exact syntax varies between lockfile file format versions. + * + * Example: `link:../target-folder` + * + * Example: `1.0.0` + * + * Example: `1.0.0_@rushstack+m@1.0.0` (version 5.4) + * Example: `1.0.0(@rushstack/m@1.0.0)` (version 6.0 and 9.0) + */ + public readonly versionPath: string; + + /** + * If this dependency refers to an entry in the lockfile, this field should match a corresponding + * {@link LfxGraphEntry.entryId} and `resolvedEntry` will be defined (unless the loader encountered an error). + * + * For external references such as `link:../target-folder`, the `entryId` is the empty string. + */ + public readonly entryId: string; + + /** + * The lockfile sometimes records the original SemVer specifier that was used to choose the versionPath, + * usually either because it can change (e.g. a workspace project's dependencies) or because it's a peer dependency + * that affects graph relationships beyond the current node. If not, then `originalSpecifier` will be the + * empty string. + * + * @remarks + * Because this field is only available for certain dependencies, it is generally less useful than specifiers + * obtained from the package.json files. + */ + public readonly originalSpecifier: string; + public readonly dependencyKind: LfxDependencyKind; + public readonly peerDependencyMeta: IJsonPeerDependencyMeta; + + public readonly containingEntry: LfxGraphEntry; + public resolvedEntry: LfxGraphEntry | undefined = undefined; + + public constructor(options: ILfxGraphDependencyOptions) { + this.name = options.name; + this.versionPath = options.versionPath; + this.entryId = options.entryId; + this.originalSpecifier = options.originalSpecifier; + this.dependencyKind = options.dependencyKind; + this.peerDependencyMeta = options.peerDependencyMeta; + + this.containingEntry = options.containingEntry; + } +} + +export interface ILfxGraphEntryOptions { + kind: LfxGraphEntryKind; + entryId: string; + rawEntryId: string; + packageJsonFolderPath: string; + entryPackageName: string; + displayText: string; + entryPackageVersion: string; + entrySuffix: string; +} + +/** + * Represents a project or package listed in the pnpm lockfile. + * + * @remarks + * Each project or package will have its own LockfileEntry, which is created when the lockfile is first parsed. + * The fields for the LockfileEntry are outlined below: + */ +export class LfxGraphEntry { + /** + * Whether this entry is a project or a package (specified by importers or packages in the lockfile). + */ + public readonly kind: LfxGraphEntryKind; + + /** + * A unique identifier for this lockfile entry, based on `rawEntryId` but adjusted to be unique for both + * project and external package entries. + */ + public readonly entryId: string; + + /** + * The unique identifier assigned to this project/package in the lockfile. + * e.g. `/@emotion/core/10.3.1_qjwx5m6wssz3lnb35xwkc3pz6q:` + * + * @remarks + * In the `pnpm-lock.yaml` file, "importers" (workspace projects) and "packages" (external packages) + * are tracked separately, so it's not required for their keys to be unique. `entryId` solves this problem + * by adding a `project:` prefix for importers. + */ + public readonly rawEntryId: string; + + /** + * Where the package.json is for this project or package. + */ + public readonly packageJsonFolderPath: string; + + /** + * Just the name of the package with no specifiers. + */ + public readonly entryPackageName: string; + + /** + * A human friendly name for the project or package. + */ + public readonly displayText: string; + + public readonly entryPackageVersion: string; + public readonly entrySuffix: string; + + /** + * A list of all the dependencies for this entry. + * Note that dependencies, dev dependencies, as well as peer dependencies are all included. + */ + public readonly dependencies: LfxGraphDependency[] = []; + + /** + * A list of dependencies that are listed under the "transitivePeerDependencies" in the pnpm lockfile. + */ + public readonly transitivePeerDependencies: Set = new Set(); + + /** + * A list of entries that specify this entry as a dependency. + */ + public readonly referrers: LfxGraphEntry[] = []; + + public constructor(options: ILfxGraphEntryOptions) { + this.kind = options.kind; + this.entryId = options.entryId; + this.rawEntryId = options.rawEntryId; + this.packageJsonFolderPath = options.packageJsonFolderPath; + this.entryPackageName = options.entryPackageName; + this.displayText = options.displayText; + this.entryPackageVersion = options.entryPackageVersion; + this.entrySuffix = options.entrySuffix; + } +} + +export class LfxGraph { + public readonly workspace: IJsonLfxWorkspace; + public readonly entries: LfxGraphEntry[] = []; + + public constructor(workspace: IJsonLfxWorkspace) { + this.workspace = { ...workspace }; + } +} diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/index.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/index.ts new file mode 100644 index 00000000000..c060ea5e6b6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/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 * from './IAppContext'; +export * from './IJsonLfxGraph'; +export * from './IJsonLfxWorkspace'; +export * from './LfxGraph'; +export * as lfxGraphSerializer from './lfxGraphSerializer'; diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts new file mode 100644 index 00000000000..f2f4be485e9 --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.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 type { IJsonLfxDependency, IJsonLfxEntry, IJsonLfxGraph } from './IJsonLfxGraph'; +import { type ILfxGraphEntryOptions, LfxGraph, LfxGraphDependency, LfxGraphEntry } from './LfxGraph'; + +export function serializeToJson(graph: LfxGraph): IJsonLfxGraph { + const jsonLfxEntries: IJsonLfxEntry[] = []; + + const jsonIdByEntry: Map = new Map(); + + function toJsonId(entry: LfxGraphEntry): number { + const result: number | undefined = jsonIdByEntry.get(entry); + if (result === undefined) { + throw new Error('Attempt to serialize disconnected object'); + } + return result; + } + + // First create the jsonId mapping + for (const entry of graph.entries) { + const nextIndex: number = jsonLfxEntries.length; + + const jsonLfxEntry: IJsonLfxEntry = { + jsonId: nextIndex, + + kind: entry.kind, + entryId: entry.entryId, + rawEntryId: entry.rawEntryId, + packageJsonFolderPath: entry.packageJsonFolderPath, + entryPackageName: entry.entryPackageName, + displayText: entry.displayText, + entryPackageVersion: entry.entryPackageVersion, + entrySuffix: entry.entrySuffix, + + // Lists will be added in the second loop + dependencies: [], + transitivePeerDependencies: [], + referrerJsonIds: [] + }; + + jsonLfxEntries.push(jsonLfxEntry); + jsonIdByEntry.set(entry, jsonLfxEntry.jsonId); + } + + // Use the jsonId mapping to serialize the lists + for (let i: number = 0; i < jsonLfxEntries.length; ++i) { + const jsonLfxEntry: IJsonLfxEntry = jsonLfxEntries[i]; + const entry: LfxGraphEntry = graph.entries[i]; + + for (const dependency of entry.dependencies) { + const jsonLfxDependency: IJsonLfxDependency = { + name: dependency.name, + versionPath: dependency.versionPath, + entryId: dependency.entryId, + originalSpecifier: dependency.originalSpecifier, + dependencyKind: dependency.dependencyKind, + peerDependencyMeta: { + name: dependency.peerDependencyMeta.name, + version: dependency.peerDependencyMeta.version, + optional: dependency.peerDependencyMeta.optional + } + }; + if (dependency.resolvedEntry) { + jsonLfxDependency.resolvedEntryJsonId = toJsonId(dependency.resolvedEntry); + } + + jsonLfxEntry.dependencies.push(jsonLfxDependency); + } + jsonLfxEntry.transitivePeerDependencies = Array.from(entry.transitivePeerDependencies); + jsonLfxEntry.referrerJsonIds = entry.referrers.map((x) => toJsonId(x)); + } + + return { workspace: graph.workspace, entries: jsonLfxEntries }; +} + +export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph { + const graph: LfxGraph = new LfxGraph(jsonLfxGraph.workspace); + + const entries: LfxGraphEntry[] = graph.entries; + + function fromJsonId(jsonId: number): LfxGraphEntry { + const result: LfxGraphEntry | undefined = entries[jsonId]; + if (result === undefined) { + throw new Error('Invalid jsonId'); + } + return result; + } + + const jsonLfxEntries: IJsonLfxEntry[] = jsonLfxGraph.entries; + + // First create the jsonId mapping + for (const jsonLfxEntry of jsonLfxEntries) { + const options: ILfxGraphEntryOptions = { + kind: jsonLfxEntry.kind, + entryId: jsonLfxEntry.entryId, + rawEntryId: jsonLfxEntry.rawEntryId, + packageJsonFolderPath: jsonLfxEntry.packageJsonFolderPath, + entryPackageName: jsonLfxEntry.entryPackageName, + displayText: jsonLfxEntry.displayText, + entryPackageVersion: jsonLfxEntry.entryPackageVersion, + entrySuffix: jsonLfxEntry.entrySuffix + }; + entries.push(new LfxGraphEntry(options)); + } + + // Use the jsonId mapping to deserialize the lists + for (let i: number = 0; i < jsonLfxEntries.length; ++i) { + const jsonLfxEntry: IJsonLfxEntry = jsonLfxEntries[i]; + const entry: LfxGraphEntry = graph.entries[i]; + + for (const jsonLfxDependency of jsonLfxEntry.dependencies) { + const dependency: LfxGraphDependency = new LfxGraphDependency({ + name: jsonLfxDependency.name, + versionPath: jsonLfxDependency.versionPath, + entryId: jsonLfxDependency.entryId, + originalSpecifier: jsonLfxDependency.originalSpecifier, + dependencyKind: jsonLfxDependency.dependencyKind, + peerDependencyMeta: { + name: jsonLfxDependency.peerDependencyMeta.name, + version: jsonLfxDependency.peerDependencyMeta.version, + optional: jsonLfxDependency.peerDependencyMeta.optional + }, + containingEntry: entry + }); + + if (jsonLfxDependency.resolvedEntryJsonId) { + dependency.resolvedEntry = fromJsonId(jsonLfxDependency.resolvedEntryJsonId); + } + + entry.dependencies.push(dependency); + } + + for (const item of jsonLfxEntry.transitivePeerDependencies) { + entry.transitivePeerDependencies.add(item); + } + + for (const referrerJsonId of jsonLfxEntry.referrerJsonIds) { + entry.referrers.push(fromJsonId(referrerJsonId)); + } + } + + return graph; +} diff --git a/apps/lockfile-explorer-web/src/parsing/compareSpec.ts b/apps/lockfile-explorer-web/src/parsing/compareSpec.ts new file mode 100644 index 00000000000..d7a11759170 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/compareSpec.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 type { IPackageJson } from '../types/IPackageJson'; + +export interface ISpecChange { + type: 'add' | 'remove' | 'diff'; + packageName: string; + from?: string; + to?: string; +} + +/** + * Calculate the diff between a package.json file and its transformed "package spec". + * + * @remarks + * During installation, PNPM applies various transforms to `package.json` files, for example + * .pnpmfile.cjs may add/remove/rewrite version ranges. The transformed result is called + * the "package spec" by Lockfile Explorer, and its tab pane displays the diff between + * the original `package.json` and the final spec. + * + * @returns A map of `ISpecChange` differences, looked up by package name. For example: + * + * 'react' --> { packageName: 'react', type: 'diff', from: '^16.0.0', to: '~16.2.0' } + */ +export const compareSpec = ( + packageJson: IPackageJson, + packageSpec: IPackageJson +): Map => { + // packageName -> packageVersion (For all dependencies in a package.json file) + const packageJsonMap: Map = new Map(); + // packageName -> packageVersion (For all dependencies in a parsed package.json file) + const packageSpecMap: Map = new Map(); + for (const [entry, version] of Object.entries({ + ...packageJson.dependencies, + ...packageJson.devDependencies, + ...packageJson.peerDependencies + })) { + packageJsonMap.set(entry, version); + } + for (const [entry, version] of Object.entries({ + ...packageSpec.dependencies, + ...packageSpec.devDependencies, + ...packageSpec.peerDependencies + })) { + packageSpecMap.set(entry, version); + } + const differentDependencies: Map = new Map(); + + for (const dependency of packageJsonMap.keys()) { + if (!packageSpecMap.has(dependency)) { + differentDependencies.set(dependency, { + type: 'remove', + packageName: dependency + }); + } else if (packageSpecMap.get(dependency) !== packageJsonMap.get(dependency)) { + differentDependencies.set(dependency, { + type: 'diff', + packageName: dependency, + from: packageJsonMap.get(dependency), + to: packageSpecMap.get(dependency) + }); + } + } + + for (const dependency of packageSpecMap.keys()) { + if (!packageJsonMap.has(dependency)) { + differentDependencies.set(dependency, { + type: 'add', + packageName: dependency + }); + } + } + return differentDependencies; +}; diff --git a/apps/lockfile-explorer-web/src/parsing/readLockfile.ts b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts new file mode 100644 index 00000000000..5c44f0887c6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts @@ -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. + +import { + type LfxGraph, + lfxGraphSerializer, + type IJsonLfxGraph, + type LfxGraphEntry +} from '../packlets/lfx-shared'; + +const serviceUrl: string = window.appContext.serviceUrl; + +export async function readLockfileAsync(): Promise { + // eslint-disable-next-line no-console + console.log('Loading graph'); + + const response = await fetch(`${serviceUrl}/api/graph`); + const jsonGraph: IJsonLfxGraph = await response.json(); + const graph: LfxGraph = lfxGraphSerializer.deserializeFromJson(jsonGraph); + return graph.entries; +} diff --git a/apps/lockfile-explorer-web/src/parsing/test/compareSpec.test.ts b/apps/lockfile-explorer-web/src/parsing/test/compareSpec.test.ts new file mode 100644 index 00000000000..76af0c0889e --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/test/compareSpec.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 type { IPackageJson } from '../../types/IPackageJson'; +import { compareSpec } from '../compareSpec'; + +const packageJson: IPackageJson = { + name: 'testPackage', + version: '0.0.0', + dependencies: { + package1: '0.0.0' + }, + devDependencies: { + package2: '0.0.0' + }, + peerDependencies: {} +}; + +const parsedPackageJson: IPackageJson = { + name: 'testPackage', + version: '0.0.0', + dependencies: { + package1: '1.0.0' + }, + devDependencies: { + package3: '2.0.0' + }, + peerDependencies: {} +}; + +describe('Compare package.json and parsed package.json', () => { + it('calculates the differences between the two package.jsons correctly', () => { + const changes = compareSpec(packageJson, parsedPackageJson); + + expect(changes.get('package1')).toEqual({ + type: 'diff', + packageName: 'package1', + from: '0.0.0', + to: '1.0.0' + }); + + expect(changes.get('package3')).toEqual({ + type: 'add', + packageName: 'package3' + }); + + expect(changes.get('package2')).toEqual({ + type: 'remove', + packageName: 'package2' + }); + }); +}); diff --git a/apps/lockfile-explorer-web/src/start.css b/apps/lockfile-explorer-web/src/start.css new file mode 100644 index 00000000000..43f0b44e3f4 --- /dev/null +++ b/apps/lockfile-explorer-web/src/start.css @@ -0,0 +1,12 @@ +/** + * 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: #f3f2f1; + font-family: Tahoma, sans-serif; + box-sizing: border-box; +} diff --git a/apps/lockfile-explorer-web/src/start.tsx b/apps/lockfile-explorer-web/src/start.tsx new file mode 100644 index 00000000000..acc11f30b48 --- /dev/null +++ b/apps/lockfile-explorer-web/src/start.tsx @@ -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 * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; + +import { App } from './App'; +import './start.css'; +import { store } from './store'; + +const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; +ReactDOM.render( + + + , + rootDiv +); diff --git a/apps/lockfile-explorer-web/src/store/hooks.ts b/apps/lockfile-explorer-web/src/store/hooks.ts new file mode 100644 index 00000000000..2dd2721fbb1 --- /dev/null +++ b/apps/lockfile-explorer-web/src/store/hooks.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 { type TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; + +import type { RootState, AppDispatch } from '.'; + +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/apps/lockfile-explorer-web/src/store/index.ts b/apps/lockfile-explorer-web/src/store/index.ts new file mode 100644 index 00000000000..769dcea9e3b --- /dev/null +++ b/apps/lockfile-explorer-web/src/store/index.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { configureStore } from '@reduxjs/toolkit'; + +import { entryReducer } from './slices/entrySlice'; +import { workspaceReducer } from './slices/workspaceSlice'; + +/* eslint @rushstack/typedef-var: off */ +export const store = configureStore({ + reducer: { + entry: entryReducer, + workspace: workspaceReducer + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: false + }) +}); + +// Infer the `RootState` and `AppDispatch` types from the store itself +export type RootState = ReturnType; +// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} +export type AppDispatch = typeof store.dispatch; diff --git a/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts b/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts new file mode 100644 index 00000000000..72f07827db2 --- /dev/null +++ b/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createSlice, type PayloadAction, type Reducer } from '@reduxjs/toolkit'; + +import { type LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; +import type { RootState } from '../index'; +import { + getBookmarksFromStorage, + removeBookmarkFromLocalStorage, + saveBookmarkToLocalStorage +} from '../../helpers/localStorage'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type EntryState = { + allEntries: LfxGraphEntry[]; + filters: { + [key in LfxGraphEntryKind]: boolean; + }; + selectedEntryStack: LfxGraphEntry[]; + selectedEntryForwardStack: LfxGraphEntry[]; + bookmarkedEntries: LfxGraphEntry[]; +}; + +const initialState: EntryState = { + allEntries: [], + filters: { + [LfxGraphEntryKind.Project]: false, + [LfxGraphEntryKind.Package]: true, + [LfxGraphEntryKind.SideBySide]: false, + [LfxGraphEntryKind.Doppelganger]: false + }, + selectedEntryStack: [], + selectedEntryForwardStack: [], + bookmarkedEntries: [] +}; + +/* eslint @rushstack/typedef-var: off */ +const entrySlice = createSlice({ + name: 'entry', + initialState, + reducers: { + loadEntries: (state, payload: PayloadAction) => { + state.allEntries = payload.payload; + // Hydrate the bookmarks state + const bookmarkSet = getBookmarksFromStorage(); + for (const entry of payload.payload) { + if (bookmarkSet.has(entry.rawEntryId)) { + state.bookmarkedEntries.push(entry); + } + } + }, + setFilter: (state, payload: PayloadAction<{ filter: LfxGraphEntryKind; state: boolean }>) => { + state.filters[payload.payload.filter] = payload.payload.state; + }, + clearStackAndPush: (state, payload: PayloadAction) => { + state.selectedEntryStack = [payload.payload]; + state.selectedEntryForwardStack = []; + }, + pushToStack: (state, payload: PayloadAction) => { + state.selectedEntryStack.push(payload.payload); + state.selectedEntryForwardStack = []; + if (payload.payload.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; + } else { + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; + } + }, + popStack: (state) => { + if (state.selectedEntryStack.length > 1) { + const poppedEntry = state.selectedEntryStack.pop() as LfxGraphEntry; + state.selectedEntryForwardStack.push(poppedEntry); + + if (state.selectedEntryStack.length >= 1) { + const currEntry = state.selectedEntryStack[state.selectedEntryStack.length - 1]; + if (currEntry.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; + } else { + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; + } + } + } + }, + forwardStack: (state) => { + if (state.selectedEntryForwardStack.length > 0) { + const poppedEntry = state.selectedEntryForwardStack.pop() as LfxGraphEntry; + state.selectedEntryStack.push(poppedEntry); + if (poppedEntry.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; + } else { + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; + } + } + }, + addBookmark: (state, payload: PayloadAction) => { + if (!state.bookmarkedEntries.includes(payload.payload)) { + state.bookmarkedEntries.push(payload.payload); + saveBookmarkToLocalStorage(payload.payload); + } + }, + removeBookmark: (state, payload: PayloadAction) => { + state.bookmarkedEntries = state.bookmarkedEntries.filter( + (entry: LfxGraphEntry) => entry.rawEntryId !== payload.payload.rawEntryId + ); + removeBookmarkFromLocalStorage(payload.payload); + } + } +}); + +export const selectCurrentEntry = (state: RootState): LfxGraphEntry | undefined => { + if (state.entry.selectedEntryStack.length) { + return state.entry.selectedEntryStack[state.entry.selectedEntryStack.length - 1]; + } else { + return undefined; + } +}; + +export const selectFilteredEntries = (state: RootState): LfxGraphEntry[] => { + const filteredEntries: LfxGraphEntry[] = []; + if (state.entry.filters[LfxGraphEntryKind.Package]) { + filteredEntries.push( + ...state.entry.allEntries.filter((entry) => entry.kind === LfxGraphEntryKind.Package) + ); + } else if (state.entry.filters[LfxGraphEntryKind.Project]) { + filteredEntries.push( + ...state.entry.allEntries.filter((entry) => entry.kind === LfxGraphEntryKind.Project) + ); + } + return filteredEntries; +}; + +export const { + loadEntries, + setFilter, + clearStackAndPush, + pushToStack, + popStack, + forwardStack, + addBookmark, + removeBookmark +} = entrySlice.actions; + +export const entryReducer: Reducer = entrySlice.reducer; diff --git a/apps/lockfile-explorer-web/src/store/slices/workspaceSlice.ts b/apps/lockfile-explorer-web/src/store/slices/workspaceSlice.ts new file mode 100644 index 00000000000..6b202997ef0 --- /dev/null +++ b/apps/lockfile-explorer-web/src/store/slices/workspaceSlice.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 { createSlice, type PayloadAction, type Reducer } from '@reduxjs/toolkit'; + +import type { ISpecChange } from '../../parsing/compareSpec'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type WorkspaceState = { + specChanges: Map; +}; + +const initialState: WorkspaceState = { + specChanges: new Map() +}; + +/* eslint @rushstack/typedef-var: off */ +const workspaceSlice = createSlice({ + name: 'workspace', + initialState, + reducers: { + loadSpecChanges: (state, payload: PayloadAction>) => { + state.specChanges = payload.payload; + } + } +}); + +export const { loadSpecChanges } = workspaceSlice.actions; + +export const workspaceReducer: Reducer = workspaceSlice.reducer; diff --git a/apps/lockfile-explorer-web/src/stub/initappcontext.ts b/apps/lockfile-explorer-web/src/stub/initappcontext.ts new file mode 100644 index 00000000000..75197e6d747 --- /dev/null +++ b/apps/lockfile-explorer-web/src/stub/initappcontext.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 file is copied into the dist folder when the web app is being loaded +// from Webpack dev server. In a production release, a generated script is served by the +// Node.js service with the live context object. + +// eslint-disable-next-line no-console +console.log('Loaded stub/initappcontext.js'); + +window.appContext = { + serviceUrl: 'http://localhost:8091', + appVersion: '(dev)', + debugMode: true +}; diff --git a/apps/lockfile-explorer-web/src/styles/_base.scss b/apps/lockfile-explorer-web/src/styles/_base.scss new file mode 100644 index 00000000000..5799704e1e3 --- /dev/null +++ b/apps/lockfile-explorer-web/src/styles/_base.scss @@ -0,0 +1,7 @@ +$shadow: 0 2px 10px hsla(0, 0%, 0%, 0.141); +$background-primary: white; + +@mixin card { + box-shadow: $shadow; + background-color: $background-primary; +} diff --git a/apps/lockfile-explorer-web/src/types/AppContext.ts b/apps/lockfile-explorer-web/src/types/AppContext.ts new file mode 100644 index 00000000000..5bd79089f4c --- /dev/null +++ b/apps/lockfile-explorer-web/src/types/AppContext.ts @@ -0,0 +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 { IAppContext } from '../packlets/lfx-shared'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + appContext: IAppContext; + } +} diff --git a/apps/lockfile-explorer-web/src/types/IPackageJson.ts b/apps/lockfile-explorer-web/src/types/IPackageJson.ts new file mode 100644 index 00000000000..3f575a99f52 --- /dev/null +++ b/apps/lockfile-explorer-web/src/types/IPackageJson.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. + +export interface IPackageJson { + name: string; + version: string; + dependencies: { + [key: string]: string; + }; + devDependencies: { + [key: string]: string; + }; + peerDependencies: { + [key: string]: string; + }; +} diff --git a/apps/lockfile-explorer-web/src/types/ReactNull.ts b/apps/lockfile-explorer-web/src/types/ReactNull.ts new file mode 100644 index 00000000000..4b1f3c96301 --- /dev/null +++ b/apps/lockfile-explorer-web/src/types/ReactNull.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. + +// eslint-disable-next-line @rushstack/no-new-null +export type ReactNull = null; +// eslint-disable-next-line @rushstack/no-new-null, @typescript-eslint/no-redeclare +export const ReactNull: null = null; diff --git a/apps/lockfile-explorer-web/tsconfig.json b/apps/lockfile-explorer-web/tsconfig.json new file mode 100644 index 00000000000..9688e20399b --- /dev/null +++ b/apps/lockfile-explorer-web/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/app/tsconfig-base.json" +} diff --git a/apps/lockfile-explorer-web/webpack.config.js b/apps/lockfile-explorer-web/webpack.config.js new file mode 100644 index 00000000000..7b09bf573cd --- /dev/null +++ b/apps/lockfile-explorer-web/webpack.config.js @@ -0,0 +1,45 @@ +'use strict'; + +const path = require('path'); +const createWebpackConfig = require('local-web-rig/profiles/app/webpack-base.config'); + +module.exports = function createConfig(env, argv) { + return createWebpackConfig({ + env: env, + argv: argv, + projectRoot: __dirname, + // Documentation: https://webpack.js.org/configuration/ + configOverride: { + resolve: { + alias: { + // Don't rebundle this large library + '@rushstack/rush-themed-ui': '@rushstack/rush-themed-ui/dist/rush-themed-ui.js' + } + }, + performance: { + hints: env.production ? 'error' : false, + // 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: Infinity, + maxAssetSize: Infinity + }, + devServer: { + port: 8096, + + open: '/', + // Disable HTTPS to simplify Fiddler configuration + server: { type: 'http' }, + //hot: false, + + static: { + directory: path.join(__dirname, 'dist') + }, + client: { + webSocketURL: { + port: 8096 + } + } + } + } + }); +}; diff --git a/apps/lockfile-explorer/.npmignore b/apps/lockfile-explorer/.npmignore new file mode 100644 index 00000000000..538016c27d7 --- /dev/null +++ b/apps/lockfile-explorer/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +# heft.json copies this folder from lockfile-explorer-web: +!/build/lfx-shared/** diff --git a/apps/lockfile-explorer/.vscode/launch.json b/apps/lockfile-explorer/.vscode/launch.json new file mode 100644 index 00000000000..34810e71664 --- /dev/null +++ b/apps/lockfile-explorer/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // 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": "All Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Single Jest test", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": [ + "--debug", + "test", + "--clean", + "-u", + "--test-path-pattern", + "lfxGraph-website-sample-1-v5.4.test" + ], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Run LAST BUILD in specified folder", + "program": "${workspaceFolder}/lib/start-explorer.js", + "cwd": "(your project path)", + //"cwd": "C:\\Git\\lockfile-explorer-demos", + "args": ["--debug"], + "sourceMaps": true + } + ] +} diff --git a/apps/lockfile-explorer/CHANGELOG.json b/apps/lockfile-explorer/CHANGELOG.json new file mode 100644 index 00000000000..9bf0fe0f02c --- /dev/null +++ b/apps/lockfile-explorer/CHANGELOG.json @@ -0,0 +1,2838 @@ +{ + "name": "@rushstack/lockfile-explorer", + "entries": [ + { + "version": "2.0.8", + "tag": "@rushstack/lockfile-explorer_v2.0.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\" to `1.1.7`" + } + ] + } + }, + { + "version": "2.0.7", + "tag": "@rushstack/lockfile-explorer_v2.0.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\" to `1.1.6`" + } + ] + } + }, + { + "version": "2.0.6", + "tag": "@rushstack/lockfile-explorer_v2.0.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "2.0.5", + "tag": "@rushstack/lockfile-explorer_v2.0.5", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "2.0.4", + "tag": "@rushstack/lockfile-explorer_v2.0.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\" to `1.1.3`" + } + ] + } + }, + { + "version": "2.0.3", + "tag": "@rushstack/lockfile-explorer_v2.0.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\" to `1.1.2`" + } + ] + } + }, + { + "version": "2.0.2", + "tag": "@rushstack/lockfile-explorer_v2.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/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "2.0.1", + "tag": "@rushstack/lockfile-explorer_v2.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/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@rushstack/lockfile-explorer_v2.0.0", + "date": "Fri, 03 Oct 2025 17:28:43 GMT", + "comments": { + "major": [ + { + "comment": "Add support for PNPM 10 lockfile format" + } + ], + "patch": [ + { + "comment": "Numerous improvements to the lockfile parser" + } + ] + } + }, + { + "version": "1.8.1", + "tag": "@rushstack/lockfile-explorer_v1.8.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`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.8.0", + "tag": "@rushstack/lockfile-explorer_v1.8.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "patch": [ + { + "comment": "Bump \"express\" to 4.21.1 to address reported vulnerabilities in 4.20.0." + }, + { + "comment": "Upgraded `js-yaml` dependency" + }, + { + "comment": "Improve support for PNPM lockfile format V6.0" + }, + { + "comment": "Refactoring to support future work" + } + ], + "minor": [ + { + "comment": "Add syntax highlighter" + }, + { + "comment": "Isolate .pnpmcfile.cjs evaluation" + } + ], + "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": "1.7.42", + "tag": "@rushstack/lockfile-explorer_v1.7.42", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "1.7.41", + "tag": "@rushstack/lockfile-explorer_v1.7.41", + "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": "1.7.40", + "tag": "@rushstack/lockfile-explorer_v1.7.40", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "1.7.39", + "tag": "@rushstack/lockfile-explorer_v1.7.39", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "1.7.38", + "tag": "@rushstack/lockfile-explorer_v1.7.38", + "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": "1.7.37", + "tag": "@rushstack/lockfile-explorer_v1.7.37", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "1.7.36", + "tag": "@rushstack/lockfile-explorer_v1.7.36", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "1.7.35", + "tag": "@rushstack/lockfile-explorer_v1.7.35", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "1.7.34", + "tag": "@rushstack/lockfile-explorer_v1.7.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/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "1.7.33", + "tag": "@rushstack/lockfile-explorer_v1.7.33", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "1.7.32", + "tag": "@rushstack/lockfile-explorer_v1.7.32", + "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": "1.7.31", + "tag": "@rushstack/lockfile-explorer_v1.7.31", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation for `extends`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "1.7.30", + "tag": "@rushstack/lockfile-explorer_v1.7.30", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "1.7.29", + "tag": "@rushstack/lockfile-explorer_v1.7.29", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "1.7.28", + "tag": "@rushstack/lockfile-explorer_v1.7.28", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "1.7.27", + "tag": "@rushstack/lockfile-explorer_v1.7.27", + "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": "1.7.26", + "tag": "@rushstack/lockfile-explorer_v1.7.26", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "1.7.25", + "tag": "@rushstack/lockfile-explorer_v1.7.25", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "1.7.24", + "tag": "@rushstack/lockfile-explorer_v1.7.24", + "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\" to `0.70.0`" + } + ] + } + }, + { + "version": "1.7.23", + "tag": "@rushstack/lockfile-explorer_v1.7.23", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "1.7.22", + "tag": "@rushstack/lockfile-explorer_v1.7.22", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "1.7.21", + "tag": "@rushstack/lockfile-explorer_v1.7.21", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "1.7.20", + "tag": "@rushstack/lockfile-explorer_v1.7.20", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "1.7.19", + "tag": "@rushstack/lockfile-explorer_v1.7.19", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "1.7.18", + "tag": "@rushstack/lockfile-explorer_v1.7.18", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "1.7.17", + "tag": "@rushstack/lockfile-explorer_v1.7.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/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "1.7.16", + "tag": "@rushstack/lockfile-explorer_v1.7.16", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "1.7.15", + "tag": "@rushstack/lockfile-explorer_v1.7.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/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "1.7.14", + "tag": "@rushstack/lockfile-explorer_v1.7.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/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "1.7.13", + "tag": "@rushstack/lockfile-explorer_v1.7.13", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "1.7.12", + "tag": "@rushstack/lockfile-explorer_v1.7.12", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "1.7.11", + "tag": "@rushstack/lockfile-explorer_v1.7.11", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "1.7.10", + "tag": "@rushstack/lockfile-explorer_v1.7.10", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "1.7.9", + "tag": "@rushstack/lockfile-explorer_v1.7.9", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "1.7.8", + "tag": "@rushstack/lockfile-explorer_v1.7.8", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "1.7.7", + "tag": "@rushstack/lockfile-explorer_v1.7.7", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "1.7.6", + "tag": "@rushstack/lockfile-explorer_v1.7.6", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "1.7.5", + "tag": "@rushstack/lockfile-explorer_v1.7.5", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "1.7.4", + "tag": "@rushstack/lockfile-explorer_v1.7.4", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "1.7.3", + "tag": "@rushstack/lockfile-explorer_v1.7.3", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "1.7.2", + "tag": "@rushstack/lockfile-explorer_v1.7.2", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "1.7.1", + "tag": "@rushstack/lockfile-explorer_v1.7.1", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "1.7.0", + "tag": "@rushstack/lockfile-explorer_v1.7.0", + "date": "Thu, 26 Sep 2024 21:47:44 GMT", + "comments": { + "minor": [ + { + "comment": "Update to use a new API from rush-sdk." + } + ] + } + }, + { + "version": "1.6.0", + "tag": "@rushstack/lockfile-explorer_v1.6.0", + "date": "Tue, 24 Sep 2024 00:11:19 GMT", + "comments": { + "minor": [ + { + "comment": "Bump express dependency to 4.20.0" + } + ] + } + }, + { + "version": "1.5.11", + "tag": "@rushstack/lockfile-explorer_v1.5.11", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "1.5.10", + "tag": "@rushstack/lockfile-explorer_v1.5.10", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "1.5.9", + "tag": "@rushstack/lockfile-explorer_v1.5.9", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "1.5.8", + "tag": "@rushstack/lockfile-explorer_v1.5.8", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "1.5.7", + "tag": "@rushstack/lockfile-explorer_v1.5.7", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "1.5.6", + "tag": "@rushstack/lockfile-explorer_v1.5.6", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "1.5.5", + "tag": "@rushstack/lockfile-explorer_v1.5.5", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "1.5.4", + "tag": "@rushstack/lockfile-explorer_v1.5.4", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "1.5.3", + "tag": "@rushstack/lockfile-explorer_v1.5.3", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "1.5.2", + "tag": "@rushstack/lockfile-explorer_v1.5.2", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "1.5.1", + "tag": "@rushstack/lockfile-explorer_v1.5.1", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/lockfile-explorer_v1.5.0", + "date": "Tue, 25 Jun 2024 06:01:28 GMT", + "comments": { + "minor": [ + { + "comment": "Add new \"lockfile-lint\" command" + } + ] + } + }, + { + "version": "1.4.17", + "tag": "@rushstack/lockfile-explorer_v1.4.17", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "1.4.16", + "tag": "@rushstack/lockfile-explorer_v1.4.16", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "1.4.15", + "tag": "@rushstack/lockfile-explorer_v1.4.15", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "1.4.14", + "tag": "@rushstack/lockfile-explorer_v1.4.14", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "1.4.13", + "tag": "@rushstack/lockfile-explorer_v1.4.13", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "1.4.12", + "tag": "@rushstack/lockfile-explorer_v1.4.12", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "1.4.11", + "tag": "@rushstack/lockfile-explorer_v1.4.11", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "1.4.10", + "tag": "@rushstack/lockfile-explorer_v1.4.10", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "1.4.9", + "tag": "@rushstack/lockfile-explorer_v1.4.9", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "1.4.8", + "tag": "@rushstack/lockfile-explorer_v1.4.8", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "1.4.7", + "tag": "@rushstack/lockfile-explorer_v1.4.7", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "1.4.6", + "tag": "@rushstack/lockfile-explorer_v1.4.6", + "date": "Wed, 15 May 2024 15:09:57 GMT", + "comments": { + "patch": [ + { + "comment": "Update the exit code to 0 for `lockfile-explorer --help`." + } + ] + } + }, + { + "version": "1.4.5", + "tag": "@rushstack/lockfile-explorer_v1.4.5", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "1.4.4", + "tag": "@rushstack/lockfile-explorer_v1.4.4", + "date": "Wed, 15 May 2024 03:05:43 GMT", + "comments": { + "patch": [ + { + "comment": "Fix some issues when parsing certain lockfile syntaxes" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/lockfile-explorer_v1.4.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/lockfile-explorer_v1.4.2", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/lockfile-explorer_v1.4.1", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/lockfile-explorer_v1.4.0", + "date": "Tue, 30 Apr 2024 05:42:40 GMT", + "comments": { + "minor": [ + { + "comment": "Add `--subspace` command-line parameter to support Rush subspaces" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/lockfile-explorer_v1.3.1", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/lockfile-explorer_v1.3.0", + "date": "Tue, 02 Apr 2024 00:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Bump express." + } + ] + } + }, + { + "version": "1.2.39", + "tag": "@rushstack/lockfile-explorer_v1.2.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "1.2.38", + "tag": "@rushstack/lockfile-explorer_v1.2.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "1.2.37", + "tag": "@rushstack/lockfile-explorer_v1.2.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "1.2.36", + "tag": "@rushstack/lockfile-explorer_v1.2.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "1.2.35", + "tag": "@rushstack/lockfile-explorer_v1.2.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "1.2.34", + "tag": "@rushstack/lockfile-explorer_v1.2.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "1.2.33", + "tag": "@rushstack/lockfile-explorer_v1.2.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "1.2.32", + "tag": "@rushstack/lockfile-explorer_v1.2.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "1.2.31", + "tag": "@rushstack/lockfile-explorer_v1.2.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "1.2.30", + "tag": "@rushstack/lockfile-explorer_v1.2.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "1.2.29", + "tag": "@rushstack/lockfile-explorer_v1.2.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "1.2.28", + "tag": "@rushstack/lockfile-explorer_v1.2.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "1.2.27", + "tag": "@rushstack/lockfile-explorer_v1.2.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "1.2.26", + "tag": "@rushstack/lockfile-explorer_v1.2.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "1.2.25", + "tag": "@rushstack/lockfile-explorer_v1.2.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "1.2.24", + "tag": "@rushstack/lockfile-explorer_v1.2.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "1.2.23", + "tag": "@rushstack/lockfile-explorer_v1.2.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/lockfile-explorer_v1.2.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/lockfile-explorer_v1.2.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/lockfile-explorer_v1.2.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/lockfile-explorer_v1.2.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/lockfile-explorer_v1.2.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/lockfile-explorer_v1.2.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/lockfile-explorer_v1.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/lockfile-explorer_v1.2.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/lockfile-explorer_v1.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/lockfile-explorer_v1.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/lockfile-explorer_v1.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/lockfile-explorer_v1.2.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/lockfile-explorer_v1.2.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/lockfile-explorer_v1.2.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/lockfile-explorer_v1.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/lockfile-explorer_v1.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/lockfile-explorer_v1.2.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/lockfile-explorer_v1.2.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/lockfile-explorer_v1.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/lockfile-explorer_v1.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/lockfile-explorer_v1.2.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/lockfile-explorer_v1.2.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/lockfile-explorer_v1.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/lockfile-explorer_v1.1.0", + "date": "Thu, 14 Sep 2023 15:32:38 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for the V6 lockfile used by PNPM 8." + } + ] + } + }, + { + "version": "1.0.43", + "tag": "@rushstack/lockfile-explorer_v1.0.43", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + } + ] + } + }, + { + "version": "1.0.42", + "tag": "@rushstack/lockfile-explorer_v1.0.42", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "1.0.41", + "tag": "@rushstack/lockfile-explorer_v1.0.41", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + } + ] + } + }, + { + "version": "1.0.40", + "tag": "@rushstack/lockfile-explorer_v1.0.40", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + } + ] + } + }, + { + "version": "1.0.39", + "tag": "@rushstack/lockfile-explorer_v1.0.39", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + } + ] + } + }, + { + "version": "1.0.38", + "tag": "@rushstack/lockfile-explorer_v1.0.38", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "1.0.37", + "tag": "@rushstack/lockfile-explorer_v1.0.37", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + } + ] + } + }, + { + "version": "1.0.36", + "tag": "@rushstack/lockfile-explorer_v1.0.36", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + } + ] + } + }, + { + "version": "1.0.35", + "tag": "@rushstack/lockfile-explorer_v1.0.35", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "1.0.34", + "tag": "@rushstack/lockfile-explorer_v1.0.34", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + } + ] + } + }, + { + "version": "1.0.33", + "tag": "@rushstack/lockfile-explorer_v1.0.33", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + } + ] + } + }, + { + "version": "1.0.32", + "tag": "@rushstack/lockfile-explorer_v1.0.32", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "1.0.31", + "tag": "@rushstack/lockfile-explorer_v1.0.31", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + } + ] + } + }, + { + "version": "1.0.30", + "tag": "@rushstack/lockfile-explorer_v1.0.30", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + } + ] + } + }, + { + "version": "1.0.29", + "tag": "@rushstack/lockfile-explorer_v1.0.29", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + } + ] + } + }, + { + "version": "1.0.28", + "tag": "@rushstack/lockfile-explorer_v1.0.28", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + } + ] + } + }, + { + "version": "1.0.27", + "tag": "@rushstack/lockfile-explorer_v1.0.27", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + } + ] + } + }, + { + "version": "1.0.26", + "tag": "@rushstack/lockfile-explorer_v1.0.26", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + } + ] + } + }, + { + "version": "1.0.25", + "tag": "@rushstack/lockfile-explorer_v1.0.25", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "1.0.24", + "tag": "@rushstack/lockfile-explorer_v1.0.24", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + } + ] + } + }, + { + "version": "1.0.23", + "tag": "@rushstack/lockfile-explorer_v1.0.23", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/lockfile-explorer_v1.0.22", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/lockfile-explorer_v1.0.21", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/lockfile-explorer_v1.0.20", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/lockfile-explorer_v1.0.19", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/lockfile-explorer_v1.0.18", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/lockfile-explorer_v1.0.17", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/lockfile-explorer_v1.0.16", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/lockfile-explorer_v1.0.15", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/lockfile-explorer_v1.0.14", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/lockfile-explorer_v1.0.13", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/lockfile-explorer_v1.0.12", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/lockfile-explorer_v1.0.11", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/lockfile-explorer_v1.0.10", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/lockfile-explorer_v1.0.9", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/lockfile-explorer_v1.0.8", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/lockfile-explorer_v1.0.7", + "date": "Wed, 08 Feb 2023 19:58:16 GMT", + "comments": { + "patch": [ + { + "comment": "Support context parameter in pnpmfile readPackage" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/lockfile-explorer_v1.0.6", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/lockfile-explorer_v1.0.5", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/lockfile-explorer_v1.0.4", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/lockfile-explorer_v1.0.3", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/lockfile-explorer_v1.0.2", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/lockfile-explorer_v1.0.1", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/lockfile-explorer_v1.0.0", + "date": "Wed, 25 Jan 2023 03:01:43 GMT", + "comments": { + "major": [ + { + "comment": "Initial feature-complete release of Lockfile Explorer" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/lockfile-explorer_v0.2.2", + "date": "Tue, 24 Jan 2023 00:16:54 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the tab component" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/lockfile-explorer_v0.2.1", + "date": "Sun, 22 Jan 2023 20:37:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the upgrade notice wasn't displayed until after pressing CTRL+C" + }, + { + "comment": "Fix a regression where some CSS styles were not being loaded properly" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/lockfile-explorer_v0.2.0", + "date": "Sat, 21 Jan 2023 04:36:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"lfx\" as an alias for the \"lockfile-explorer\" shell command" + } + ], + "patch": [ + { + "comment": "Add some basic command-line help and improve some message strings" + }, + { + "comment": "Add support for rush components" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/lockfile-explorer_v0.1.8", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/lockfile-explorer_v0.1.7", + "date": "Wed, 18 Jan 2023 05:02:16 GMT", + "comments": { + "patch": [ + { + "comment": "Print an upgrade notice when there is a newer release of the @rushstack/lockfile-explorer package" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/lockfile-explorer_v0.1.6", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/lockfile-explorer_v0.1.5", + "date": "Fri, 16 Dec 2022 16:20:52 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an Error is thrown when a pnpmfile does not exist." + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/lockfile-explorer_v0.1.4", + "date": "Fri, 09 Dec 2022 23:31:28 GMT", + "comments": { + "patch": [ + { + "comment": "Lockfile Explorer now displays a disconnection message if the client / server is disconnected" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/lockfile-explorer_v0.1.3", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/lockfile-explorer_v0.1.2", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/lockfile-explorer_v0.1.1", + "date": "Fri, 18 Nov 2022 06:06:02 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where some assets were not packaged in the production release" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/lockfile-explorer_v0.1.0", + "date": "Fri, 18 Nov 2022 00:55:17 GMT", + "comments": { + "minor": [ + { + "comment": "Fixed issues related to influencer resolution in lockfile explorer; Cleaned up UI & improved UX." + } + ] + } + }, + { + "version": "0.0.3", + "tag": "@rushstack/lockfile-explorer_v0.0.3", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + } + ] + } + }, + { + "version": "0.0.2", + "tag": "@rushstack/lockfile-explorer_v0.0.2", + "date": "Mon, 07 Nov 2022 16:22:32 GMT", + "comments": { + "patch": [ + { + "comment": "The CLI now supports a \"--debug\" parameter for troubleshooting" + } + ] + } + }, + { + "version": "0.0.1", + "tag": "@rushstack/lockfile-explorer_v0.0.1", + "date": "Fri, 04 Nov 2022 17:48:07 GMT", + "comments": { + "patch": [ + { + "comment": "Initial preview release" + } + ] + } + } + ] +} diff --git a/apps/lockfile-explorer/CHANGELOG.md b/apps/lockfile-explorer/CHANGELOG.md new file mode 100644 index 00000000000..b109bac407e --- /dev/null +++ b/apps/lockfile-explorer/CHANGELOG.md @@ -0,0 +1,1013 @@ +# Change Log - @rushstack/lockfile-explorer + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 2.0.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 2.0.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 2.0.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 2.0.5 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 2.0.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 2.0.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 2.0.2 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 2.0.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 2.0.0 +Fri, 03 Oct 2025 17:28:43 GMT + +### Breaking changes + +- Add support for PNPM 10 lockfile format + +### Patches + +- Numerous improvements to the lockfile parser + +## 1.8.1 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 1.8.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Add syntax highlighter +- Isolate .pnpmcfile.cjs evaluation + +### Patches + +- Bump "express" to 4.21.1 to address reported vulnerabilities in 4.20.0. +- Upgraded `js-yaml` dependency +- Improve support for PNPM lockfile format V6.0 +- Refactoring to support future work + +## 1.7.42 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 1.7.41 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 1.7.40 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 1.7.39 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 1.7.38 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 1.7.37 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 1.7.36 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 1.7.35 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 1.7.34 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 1.7.33 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 1.7.32 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 1.7.31 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 1.7.30 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 1.7.29 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 1.7.28 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 1.7.27 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 1.7.26 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 1.7.25 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 1.7.24 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 1.7.23 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 1.7.22 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 1.7.21 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 1.7.20 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 1.7.19 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 1.7.18 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 1.7.17 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 1.7.16 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 1.7.15 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 1.7.14 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 1.7.13 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 1.7.12 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 1.7.11 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 1.7.10 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 1.7.9 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 1.7.8 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 1.7.7 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 1.7.6 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 1.7.5 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 1.7.4 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 1.7.3 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 1.7.2 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 1.7.1 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 1.7.0 +Thu, 26 Sep 2024 21:47:44 GMT + +### Minor changes + +- Update to use a new API from rush-sdk. + +## 1.6.0 +Tue, 24 Sep 2024 00:11:19 GMT + +### Minor changes + +- Bump express dependency to 4.20.0 + +## 1.5.11 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 1.5.10 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 1.5.9 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 1.5.8 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 1.5.7 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 1.5.6 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 1.5.5 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 1.5.4 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 1.5.3 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 1.5.2 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 1.5.1 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 1.5.0 +Tue, 25 Jun 2024 06:01:28 GMT + +### Minor changes + +- Add new "lockfile-lint" command + +## 1.4.17 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 1.4.16 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 1.4.15 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 1.4.14 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 1.4.13 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 1.4.12 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 1.4.11 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 1.4.10 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 1.4.9 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 1.4.8 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 1.4.7 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 1.4.6 +Wed, 15 May 2024 15:09:57 GMT + +### Patches + +- Update the exit code to 0 for `lockfile-explorer --help`. + +## 1.4.5 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 1.4.4 +Wed, 15 May 2024 03:05:43 GMT + +### Patches + +- Fix some issues when parsing certain lockfile syntaxes + +## 1.4.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 1.4.2 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 1.4.1 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 1.4.0 +Tue, 30 Apr 2024 05:42:40 GMT + +### Minor changes + +- Add `--subspace` command-line parameter to support Rush subspaces + +## 1.3.1 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 1.3.0 +Tue, 02 Apr 2024 00:09:59 GMT + +### Minor changes + +- Bump express. + +## 1.2.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 1.2.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 1.2.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 1.2.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 1.2.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 1.2.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 1.2.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 1.2.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 1.2.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 1.2.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 1.2.29 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 1.2.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 1.2.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 1.2.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 1.2.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 1.2.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 1.2.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 1.2.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 1.2.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 1.2.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 1.2.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 1.2.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 1.2.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 1.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 1.2.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 1.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 1.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 1.2.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 1.2.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 1.2.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 1.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 1.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 1.2.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 1.2.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 1.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 1.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 1.2.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 1.2.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 1.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 1.1.0 +Thu, 14 Sep 2023 15:32:38 GMT + +### Minor changes + +- Add support for the V6 lockfile used by PNPM 8. + +## 1.0.43 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 1.0.42 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 1.0.41 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 1.0.40 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 1.0.39 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 1.0.38 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 1.0.37 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 1.0.36 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 1.0.35 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 1.0.34 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 1.0.33 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 1.0.32 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 1.0.31 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 1.0.30 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 1.0.29 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 1.0.28 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 1.0.27 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 1.0.26 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 1.0.25 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 1.0.24 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 1.0.23 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 1.0.22 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 1.0.21 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 1.0.20 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 1.0.19 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 1.0.18 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 1.0.17 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 1.0.16 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 1.0.15 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 1.0.14 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 1.0.13 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 1.0.12 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 1.0.11 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 1.0.10 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 1.0.9 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 1.0.8 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 1.0.7 +Wed, 08 Feb 2023 19:58:16 GMT + +### Patches + +- Support context parameter in pnpmfile readPackage + +## 1.0.6 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 1.0.5 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 1.0.4 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 1.0.3 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 1.0.2 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 1.0.1 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 1.0.0 +Wed, 25 Jan 2023 03:01:43 GMT + +### Breaking changes + +- Initial feature-complete release of Lockfile Explorer + +## 0.2.2 +Tue, 24 Jan 2023 00:16:54 GMT + +### Patches + +- Fix an issue with the tab component + +## 0.2.1 +Sun, 22 Jan 2023 20:37:08 GMT + +### Patches + +- Fix an issue where the upgrade notice wasn't displayed until after pressing CTRL+C +- Fix a regression where some CSS styles were not being loaded properly + +## 0.2.0 +Sat, 21 Jan 2023 04:36:33 GMT + +### Minor changes + +- Add "lfx" as an alias for the "lockfile-explorer" shell command + +### Patches + +- Add some basic command-line help and improve some message strings +- Add support for rush components + +## 0.1.8 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.7 +Wed, 18 Jan 2023 05:02:16 GMT + +### Patches + +- Print an upgrade notice when there is a newer release of the @rushstack/lockfile-explorer package + +## 0.1.6 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.5 +Fri, 16 Dec 2022 16:20:52 GMT + +### Patches + +- Fix an issue where an Error is thrown when a pnpmfile does not exist. + +## 0.1.4 +Fri, 09 Dec 2022 23:31:28 GMT + +### Patches + +- Lockfile Explorer now displays a disconnection message if the client / server is disconnected + +## 0.1.3 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.2 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.1 +Fri, 18 Nov 2022 06:06:02 GMT + +### Patches + +- Fix an issue where some assets were not packaged in the production release + +## 0.1.0 +Fri, 18 Nov 2022 00:55:17 GMT + +### Minor changes + +- Fixed issues related to influencer resolution in lockfile explorer; Cleaned up UI & improved UX. + +## 0.0.3 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.0.2 +Mon, 07 Nov 2022 16:22:32 GMT + +### Patches + +- The CLI now supports a "--debug" parameter for troubleshooting + +## 0.0.1 +Fri, 04 Nov 2022 17:48:07 GMT + +### Patches + +- Initial preview release + diff --git a/apps/lockfile-explorer/LICENSE b/apps/lockfile-explorer/LICENSE new file mode 100644 index 00000000000..e6b6c3080e6 --- /dev/null +++ b/apps/lockfile-explorer/LICENSE @@ -0,0 +1,24 @@ +@rushstack/lockfile-explorer + +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/apps/lockfile-explorer/README.md b/apps/lockfile-explorer/README.md new file mode 100644 index 00000000000..28a196676ae --- /dev/null +++ b/apps/lockfile-explorer/README.md @@ -0,0 +1,76 @@ +# @rushstack/lockfile-explorer + +
+
+ + Rush Lockfile Explorer + +

+

+ +**Rush Lockfile Explorer** helps you investigate and solve version conflicts when working in a monorepo +that uses the [PNPM package manager](https://pnpm.io/). It's designed for the [Rush](https://rushjs.io) +build orchestrator, but you can also use it to analyze a standalone PNPM workspace without Rush. + +Lockfile Explorer helps with problems such as: + +- Understanding why multiple versions of an NPM package are appearing in your `node_modules` folder +- Tracing dependencies to determine which project caused an NPM package to be installed +- Finding and eliminating "doppelgangers" (multiple installations of the same version + of the same package) +- Troubleshooting problems involving peer dependencies + +> This project is a new idea whose design is still evolving. +> Please provide feedback by +> [creating a GitHub issue](https://github.com/microsoft/rushstack/issues/new/choose) +> or posting in the Rush Stack +> [Zulip chat room](https://rushstack.zulipchat.com/). Thank you! + +## Usage + +Here's how to invoke the **Rush Lockfile Explorer** tool: + +```bash +# Install the NPM package globally. +# +# (You could substitute "pnpm" or "yarn" instead of "npm" here. To avoid confusing +# duplicate installs, always use the same tool for global installations!) +npm install -g @rushstack/lockfile-explorer + +# Go to your monorepo folder +cd my-rush-repo + +# Run "rush install" to ensure common/temp/node_modules is up to date. +# (If your monorepo is using PNPM without Rush, substitute "pnpm install" for this step.) +rush install + +# Launch the Lockfile Explorer command line interface (CLI). +# It expects to find a Rush/PNPM workspace in your shell's current working directory. +# As a shorthand, the "lfx" alias can be used here instead of "lockfile-explorer". +lockfile-explorer +``` + +The CLI will start a Node.js service on `http://localhost/` and launch your default web browser: + +screenshot
+_Lockfile Explorer main window_ + +## How it works + +The web app will expect to find a Rush/PNPM workspace in the current working directory where +the `lockfile-explorer` command was invoked. It will read files such as: + +- **common/config/rush/pnpm-lock.yaml** - the PNPM lockfile for your monorepo +- **common/config/rush/.pnpmfile.cjs** - which transforms **package.json** files during installation +- The **package.json** files for your local workspace projects +- The **package.json** files for external packages installed in the `node_modules` folders. + +## Links + +- [Documentation and tutorials](https://lfx.rushstack.io/) on the Lockfile Explorer project website +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/lockfile-explorer/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/trace-import](https://www.npmjs.com/package/@rushstack/trace-import) - + a command-line tool for troubleshooting how modules are resolved by `import` and `require()` + +Rush Lockfile Explorer is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/lockfile-explorer/assets/favicon.ico b/apps/lockfile-explorer/assets/favicon.ico new file mode 100644 index 00000000000..2c959bc8668 Binary files /dev/null and b/apps/lockfile-explorer/assets/favicon.ico differ diff --git a/apps/lockfile-explorer/bin/lockfile-explorer b/apps/lockfile-explorer/bin/lockfile-explorer new file mode 100755 index 00000000000..55f974d6de8 --- /dev/null +++ b/apps/lockfile-explorer/bin/lockfile-explorer @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start-explorer.js'); diff --git a/apps/lockfile-explorer/bin/lockfile-lint b/apps/lockfile-explorer/bin/lockfile-lint new file mode 100644 index 00000000000..44c9dbf8bdd --- /dev/null +++ b/apps/lockfile-explorer/bin/lockfile-lint @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start-lint.js'); diff --git a/apps/lockfile-explorer/config/heft.json b/apps/lockfile-explorer/config/heft.json new file mode 100644 index 00000000000..ca7a8305599 --- /dev/null +++ b/apps/lockfile-explorer/config/heft.json @@ -0,0 +1,86 @@ +/** + * 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": ["build"] }], + + "tasksByName": { + "copy-app-bundle": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "node_modules/@rushstack/lockfile-explorer-web/dist", + "destinationFolders": ["dist"], + "fileExtensions": [".js", ".html", ".svg", ".css", ".txt", ".css", ".txt"] + }, + { + "sourcePath": "assets", + "destinationFolders": ["dist"], + "includeGlobs": ["favicon.ico"] + } + ] + } + } + }, + + "pre-compile-copy": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "node_modules/@rushstack/lockfile-explorer-web/lib/packlets/lfx-shared", + "destinationFolders": ["build/lfx-shared"], + "includeGlobs": ["*.d.ts"] + }, + { + "sourcePath": "node_modules/@rushstack/lockfile-explorer-web/lib-commonjs/packlets/lfx-shared", + "destinationFolders": ["build/lfx-shared"], + "includeGlobs": ["*.js", "*.map"] + } + ] + } + } + }, + + "typescript": { + // The "typescript" task should not run until after "pre-compile-copy" completes. + "taskDependencies": ["pre-compile-copy"] + }, + + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/lockfile-explorer"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/apps/lockfile-explorer/config/jest.config.json b/apps/lockfile-explorer/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/lockfile-explorer/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/lockfile-explorer/config/node-service.json b/apps/lockfile-explorer/config/node-service.json new file mode 100644 index 00000000000..ba18df29aaf --- /dev/null +++ b/apps/lockfile-explorer/config/node-service.json @@ -0,0 +1,48 @@ +/** + * Configures "heft start" to launch a shell command such as a Node.js service. + * Heft will watch for changes and restart the service process whenever it gets rebuilt. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/node-service.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": "base-project/config/serve-command.json", + + /** + * Specifies the name of a "scripts" command from the project's package.json file. + * When "heft start" is invoked, it will use this shell command to launch the + * service process. + * + * Default value: "serve" + */ + // "commandName": "serve", + + /** + * If false, then an error is reported if the "scripts" command is not found in the + * project's package.json. If true, then no action will be taken. + * + * Default value: false + */ + // "ignoreMissingScript": false, + + /** + * Customizes the number of milliseconds to wait for the child process to be terminated (SIGTERM) + * before forcibly killing it. + * + * Default value: 2000 + */ + // "waitForTerminateMs": 2000, + + /** + * Customizes the number of milliseconds to wait for the child process to be killed (SIGKILL) + * before giving up and abandoning it. + * + * Default value: 2000 + */ + // "waitForKillMs": 2000 +} diff --git a/apps/lockfile-explorer/config/rig.json b/apps/lockfile-explorer/config/rig.json new file mode 100644 index 00000000000..a54e3862565 --- /dev/null +++ b/apps/lockfile-explorer/config/rig.json @@ -0,0 +1,18 @@ +// 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", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "local-node-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/apps/lockfile-explorer/eslint.config.js b/apps/lockfile-explorer/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/lockfile-explorer/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/lockfile-explorer/package.json b/apps/lockfile-explorer/package.json new file mode 100644 index 00000000000..6a5e4edfa0e --- /dev/null +++ b/apps/lockfile-explorer/package.json @@ -0,0 +1,77 @@ +{ + "name": "@rushstack/lockfile-explorer", + "version": "2.0.8", + "description": "Rush Lockfile Explorer: The UI for solving version conflicts quickly in a large monorepo", + "keywords": [ + "conflict", + "dependency", + "doppelganger", + "interactive", + "lockfile", + "monorepo", + "package", + "phantom", + "tool", + "version", + "visualization", + "visualize", + "visualizer" + ], + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/lockfile-explorer" + }, + "homepage": "https://lfx.rushstack.io/", + "license": "MIT", + "bin": { + "lockfile-explorer": "./bin/lockfile-explorer", + "lfx": "./bin/lockfile-explorer", + "lockfile-lint": "./bin/lockfile-lint", + "lflint": "./bin/lockfile-lint" + }, + "scripts": { + "build": "heft build --clean", + "start": "heft start", + "serve": "node ./lib/start.js --debug", + "test": "heft test", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@types/express": "^5.0.3" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/lockfile-explorer-web": "workspace:*", + "@types/cors": "~2.8.12", + "@types/express": "4.17.21", + "@types/js-yaml": "4.0.9", + "@types/update-notifier": "~6.0.1", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "@pnpm/lockfile.types": "1002.0.1", + "@pnpm/types": "1000.8.0", + "@types/semver": "7.5.0" + }, + "dependencies": { + "tslib": "~2.8.1", + "@microsoft/rush-lib": "workspace:*", + "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "cors": "~2.8.5", + "express": "4.21.1", + "js-yaml": "~4.1.0", + "open": "~8.4.0", + "semver": "~7.5.4", + "update-notifier": "~5.1.0" + } +} diff --git a/apps/lockfile-explorer/src/assets/lint-init/lockfile-lint-template.json b/apps/lockfile-explorer/src/assets/lint-init/lockfile-lint-template.json new file mode 100644 index 00000000000..72449103987 --- /dev/null +++ b/apps/lockfile-explorer/src/assets/lint-init/lockfile-lint-template.json @@ -0,0 +1,42 @@ +/** + * Config file for Lockfile Lint. For more info, please visit: https://lfx.rushstack.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/lockfile-explorer/lockfile-lint.schema.json", + + /** + * The list of rules to be checked by Lockfile Lint. For each rule configuration, the + * type of rule is determined by the `rule` field. + */ + "rules": [ + // /** + // * The `restrict-versions` rule enforces that direct and indirect dependencies must + // * satisfy a specified version range. + // */ + // { + // "rule": "restrict-versions", + // + // /** + // * The name of a workspace project to analyze. + // */ + // "project": "@my-company/my-app", + // + // /** + // * Indicates the package versions to be checked. The `requiredVersions` key is + // * the name of an NPM package, and the value is a SemVer range. If the project has + // * that NPM package as a dependency, then its version must satisfy the SemVer range. + // * This check also applies to devDependencies and peerDependencies, as well as any + // * indirect dependencies of the project. + // */ + // "requiredVersions": { + // /** + // * For example, if `react-router` appears anywhere in the dependency graph of + // * `@my-company/my-app`, then it must be version 5 or 6. + // */ + // "react-router": "5.x || 6.x", + // "react": "^18.3.0", + // "react-dom": "^18.3.0" + // } + // } + ] +} diff --git a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts new file mode 100644 index 00000000000..1add863add5 --- /dev/null +++ b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts @@ -0,0 +1,262 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import process from 'node:process'; +import * as path from 'node:path'; + +import express from 'express'; +import yaml from 'js-yaml'; +import cors from 'cors'; +import open from 'open'; +import updateNotifier from 'update-notifier'; + +import { FileSystem, type IPackageJson, JsonFile, PackageJsonLookup } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, type ITerminal, Terminal, Colorize } from '@rushstack/terminal'; +import { + type CommandLineFlagParameter, + CommandLineParser, + type IRequiredCommandLineStringParameter +} from '@rushstack/ts-command-line'; + +import { + type LfxGraph, + lfxGraphSerializer, + type IAppContext, + type IJsonLfxGraph, + type IJsonLfxWorkspace +} from '../../../build/lfx-shared'; +import * as lockfilePath from '../../graph/lockfilePath'; +import type { IAppState } from '../../state'; +import { init } from '../../utils/init'; +import { PnpmfileRunner } from '../../graph/PnpmfileRunner'; +import * as lfxGraphLoader from '../../graph/lfxGraphLoader'; + +const EXPLORER_TOOL_FILENAME: 'lockfile-explorer' = 'lockfile-explorer'; + +export class ExplorerCommandLineParser extends CommandLineParser { + public readonly globalTerminal: ITerminal; + private readonly _terminalProvider: ConsoleTerminalProvider; + private readonly _debugParameter: CommandLineFlagParameter; + + private readonly _subspaceParameter: IRequiredCommandLineStringParameter; + + public constructor() { + super({ + toolFilename: EXPLORER_TOOL_FILENAME, + toolDescription: + 'Lockfile Explorer is a desktop app for investigating and solving version conflicts in a PNPM workspace.' + }); + + this._debugParameter = this.defineFlagParameter({ + parameterLongName: '--debug', + parameterShortName: '-d', + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + this._subspaceParameter = this.defineStringParameter({ + parameterLongName: '--subspace', + argumentName: 'SUBSPACE_NAME', + description: 'Specifies an individual Rush subspace to check.', + defaultValue: 'default' + }); + + this._terminalProvider = new ConsoleTerminalProvider(); + this.globalTerminal = new Terminal(this._terminalProvider); + } + + public get isDebug(): boolean { + return this._debugParameter.value; + } + + protected override async onExecuteAsync(): Promise { + const lockfileExplorerProjectRoot: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; + const lockfileExplorerPackageJson: IPackageJson = JsonFile.load( + `${lockfileExplorerProjectRoot}/package.json` + ); + const appVersion: string = lockfileExplorerPackageJson.version; + + this.globalTerminal.writeLine( + Colorize.bold(`\nRush Lockfile Explorer ${appVersion}`) + + Colorize.cyan(' - https://lfx.rushstack.io/\n') + ); + + updateNotifier({ + pkg: lockfileExplorerPackageJson, + // Normally update-notifier waits a day or so before it starts displaying upgrade notices. + // In debug mode, show the notice right away. + updateCheckInterval: this.isDebug ? 0 : undefined + }).notify({ + // Make sure it says "-g" in the "npm install" example command line + isGlobal: true, + // Show the notice immediately, rather than waiting for process.onExit() + defer: false + }); + + const PORT: number = 8091; + // Must not have a trailing slash + const SERVICE_URL: string = `http://localhost:${PORT}`; + + const appState: IAppState = init({ + lockfileExplorerProjectRoot, + appVersion, + debugMode: this.isDebug, + subspaceName: this._subspaceParameter.value + }); + + const lfxWorkspace: IJsonLfxWorkspace = appState.lfxWorkspace; + + // Important: This must happen after init() reads the current working directory + process.chdir(appState.lockfileExplorerProjectRoot); + + const distFolderPath: string = `${appState.lockfileExplorerProjectRoot}/dist`; + const app: express.Application = express(); + app.use(express.json()); + app.use(cors()); + + // Variable used to check if the front-end client is still connected + let awaitingFirstConnect: boolean = true; + let isClientConnected: boolean = false; + let disconnected: boolean = false; + setInterval(() => { + if (!isClientConnected && !awaitingFirstConnect && !disconnected) { + console.log(Colorize.red('The client has disconnected!')); + console.log(`Please open a browser window at http://localhost:${PORT}/app`); + disconnected = true; + } else if (!awaitingFirstConnect) { + isClientConnected = false; + } + }, 4000); + + // This takes precedence over the `/app` static route, which also has an `initappcontext.js` file. + app.get('/initappcontext.js', (req: express.Request, res: express.Response) => { + const appContext: IAppContext = { + serviceUrl: SERVICE_URL, + appVersion: appState.appVersion, + debugMode: this.isDebug + }; + const sourceCode: string = [ + `console.log('Loaded initappcontext.js');`, + `appContext = ${JSON.stringify(appContext)}` + ].join('\n'); + + res.type('application/javascript').send(sourceCode); + }); + + app.use('/', express.static(distFolderPath)); + + app.use('/favicon.ico', express.static(distFolderPath, { index: 'favicon.ico' })); + + app.get('/api/health', (req: express.Request, res: express.Response) => { + awaitingFirstConnect = false; + isClientConnected = true; + if (disconnected) { + disconnected = false; + console.log(Colorize.green('The client has reconnected!')); + } + res.status(200).send(); + }); + + app.get('/api/graph', async (req: express.Request, res: express.Response) => { + const pnpmLockfileText: string = await FileSystem.readFileAsync(appState.pnpmLockfileLocation); + const lockfile: unknown = yaml.load(pnpmLockfileText) as unknown; + + const graph: LfxGraph = lfxGraphLoader.generateLockfileGraph(lockfile, lfxWorkspace); + + const jsonGraph: IJsonLfxGraph = lfxGraphSerializer.serializeToJson(graph); + res.type('application/json').send(jsonGraph); + }); + + app.post( + '/api/package-json', + async (req: express.Request<{}, {}, { projectPath: string }, {}>, res: express.Response) => { + const { projectPath } = req.body; + const fileLocation: string = `${appState.projectRoot}/${projectPath}/package.json`; + let packageJsonText: string; + try { + packageJsonText = await FileSystem.readFileAsync(fileLocation); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return res.status(404).send({ + message: `Could not load package.json file for this package. Have you installed all the dependencies for this workspace?`, + error: `No package.json in location: ${projectPath}` + }); + } else { + throw e; + } + } + + res.send(packageJsonText); + } + ); + + app.get('/api/pnpmfile', async (req: express.Request, res: express.Response) => { + const pnpmfilePath: string = lockfilePath.join( + lfxWorkspace.workspaceRootFullPath, + lfxWorkspace.rushConfig?.rushPnpmfilePath ?? lfxWorkspace.pnpmfilePath + ); + + let pnpmfile: string; + try { + pnpmfile = await FileSystem.readFileAsync(pnpmfilePath); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return res.status(404).send({ + message: `Could not load .pnpmfile.cjs file in this repo: "${pnpmfilePath}"`, + error: `No .pnpmifile.cjs found.` + }); + } else { + throw e; + } + } + + res.send(pnpmfile); + }); + + app.post( + '/api/package-spec', + async (req: express.Request<{}, {}, { projectPath: string }, {}>, res: express.Response) => { + const { projectPath } = req.body; + const fileLocation: string = `${appState.projectRoot}/${projectPath}/package.json`; + let packageJson: IPackageJson; + try { + packageJson = await JsonFile.loadAsync(fileLocation); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return res.status(404).send({ + message: `Could not load package.json file in location: ${projectPath}` + }); + } else { + throw e; + } + } + + let parsedPackage: IPackageJson = packageJson; + + const pnpmfilePath: string = path.join(lfxWorkspace.workspaceRootFullPath, lfxWorkspace.pnpmfilePath); + if (await FileSystem.existsAsync(pnpmfilePath)) { + const pnpmFileRunner: PnpmfileRunner = new PnpmfileRunner(pnpmfilePath); + try { + parsedPackage = await pnpmFileRunner.transformPackageAsync(packageJson, fileLocation); + } finally { + await pnpmFileRunner.disposeAsync(); + } + } + + res.send(parsedPackage); + } + ); + + app.listen(PORT, async () => { + console.log(`App launched on ${SERVICE_URL}`); + + if (!appState.debugMode) { + try { + // Launch the web browser + await open(SERVICE_URL); + } catch (e) { + this.globalTerminal.writeError('Error launching browser: ' + e.toString()); + } + } + }); + } +} diff --git a/apps/lockfile-explorer/src/cli/lint/LintCommandLineParser.ts b/apps/lockfile-explorer/src/cli/lint/LintCommandLineParser.ts new file mode 100644 index 00000000000..dfd9ae1b4e6 --- /dev/null +++ b/apps/lockfile-explorer/src/cli/lint/LintCommandLineParser.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ConsoleTerminalProvider, type ITerminal, Terminal, Colorize } from '@rushstack/terminal'; +import { CommandLineParser } from '@rushstack/ts-command-line'; +import { type IPackageJson, JsonFile, PackageJsonLookup } from '@rushstack/node-core-library'; + +import { InitAction } from './actions/InitAction'; +import { CheckAction } from './actions/CheckAction'; + +const LINT_TOOL_FILENAME: 'lockfile-lint' = 'lockfile-lint'; + +export class LintCommandLineParser extends CommandLineParser { + public readonly globalTerminal: ITerminal; + private readonly _terminalProvider: ConsoleTerminalProvider; + + public constructor() { + super({ + toolFilename: LINT_TOOL_FILENAME, + toolDescription: + 'Lockfile Lint applies configured policies to find and report dependency issues in your PNPM workspace.' + }); + + this._terminalProvider = new ConsoleTerminalProvider(); + this.globalTerminal = new Terminal(this._terminalProvider); + + this._populateActions(); + } + + protected override async onExecuteAsync(): Promise { + const lockfileExplorerProjectRoot: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; + const lockfileExplorerPackageJson: IPackageJson = JsonFile.load( + `${lockfileExplorerProjectRoot}/package.json` + ); + const appVersion: string = lockfileExplorerPackageJson.version; + + this.globalTerminal.writeLine( + Colorize.bold(`\nRush Lockfile Lint ${appVersion}`) + Colorize.cyan(' - https://lfx.rushstack.io/\n') + ); + + await super.onExecuteAsync(); + } + + private _populateActions(): void { + this.addAction(new InitAction(this)); + this.addAction(new CheckAction(this)); + } +} diff --git a/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts new file mode 100644 index 00000000000..261af43cf7e --- /dev/null +++ b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.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 path from 'node:path'; + +import yaml from 'js-yaml'; +import semver from 'semver'; +import type * as lockfileTypes from '@pnpm/lockfile.types'; +import type * as pnpmTypes from '@pnpm/types'; + +import { RushConfiguration, type RushConfigurationProject, type Subspace } from '@rushstack/rush-sdk'; +import { CommandLineAction } from '@rushstack/ts-command-line'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { AlreadyReportedError, Async, FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import lockfileLintSchema from '../../../schemas/lockfile-lint.schema.json'; +import { LOCKFILE_EXPLORER_FOLDERNAME, LOCKFILE_LINT_JSON_FILENAME } from '../../../constants/common'; +import type { LintCommandLineParser } from '../LintCommandLineParser'; +import { + getShrinkwrapFileMajorVersion, + parseDependencyPath, + splicePackageWithVersion +} from '../../../utils/shrinkwrap'; + +export interface ILintRule { + rule: 'restrict-versions'; + project: string; + requiredVersions: Record; +} + +export interface ILockfileLint { + rules: ILintRule[]; +} + +export interface ILintIssue { + project: string; + rule: string; + message: string; +} + +export class CheckAction extends CommandLineAction { + private readonly _terminal: ITerminal; + + private _rushConfiguration!: RushConfiguration; + private _checkedProjects: Set; + private _docMap: Map; + + public constructor(parser: LintCommandLineParser) { + super({ + actionName: 'check', + summary: 'Check and report dependency issues in your workspace', + documentation: + 'This command applies the policies that are configured in ' + + LOCKFILE_LINT_JSON_FILENAME + + ', reporting any problems found in your PNPM workspace.' + }); + + this._terminal = parser.globalTerminal; + this._checkedProjects = new Set(); + this._docMap = new Map(); + } + + private async _checkVersionCompatibilityAsync( + shrinkwrapFileMajorVersion: number, + packages: lockfileTypes.PackageSnapshots | undefined, + dependencyPath: pnpmTypes.DepPath, + requiredVersions: Record, + checkedDependencyPaths: Set + ): Promise { + if (packages && packages[dependencyPath] && !checkedDependencyPaths.has(dependencyPath)) { + checkedDependencyPaths.add(dependencyPath); + const { name, version } = parseDependencyPath(shrinkwrapFileMajorVersion, dependencyPath); + if (name in requiredVersions && !semver.satisfies(version, requiredVersions[name])) { + throw new Error( + `The version of "${name}" should match "${requiredVersions[name]}";` + + ` actual version is "${version}"` + ); + } + + await Promise.all( + Object.entries(packages[dependencyPath].dependencies ?? {}).map( + async ([dependencyPackageName, dependencyPackageVersion]) => { + await this._checkVersionCompatibilityAsync( + shrinkwrapFileMajorVersion, + packages, + splicePackageWithVersion( + shrinkwrapFileMajorVersion, + dependencyPackageName, + dependencyPackageVersion + ) as pnpmTypes.DepPath, + requiredVersions, + checkedDependencyPaths + ); + } + ) + ); + } + } + + private async _searchAndValidateDependenciesAsync( + project: RushConfigurationProject, + requiredVersions: Record + ): Promise { + this._terminal.writeLine(`Checking project "${project.packageName}"`); + + const projectFolder: string = project.projectFolder; + const subspace: Subspace = project.subspace; + const shrinkwrapFilename: string = subspace.getCommittedShrinkwrapFilePath(); + let doc: lockfileTypes.LockfileObject; + if (this._docMap.has(shrinkwrapFilename)) { + doc = this._docMap.get(shrinkwrapFilename)!; + } else { + const pnpmLockfileText: string = await FileSystem.readFileAsync(shrinkwrapFilename); + doc = yaml.load(pnpmLockfileText) as lockfileTypes.LockfileObject; + this._docMap.set(shrinkwrapFilename, doc); + } + const { importers, lockfileVersion, packages } = doc; + const shrinkwrapFileMajorVersion: number = getShrinkwrapFileMajorVersion(lockfileVersion); + const checkedDependencyPaths: Set = new Set(); + + await Promise.all( + Object.entries(importers).map(async ([relativePath, { dependencies }]) => { + if (path.resolve(projectFolder, relativePath) === projectFolder) { + const dependenciesEntries: [string, unknown][] = Object.entries(dependencies ?? {}); + for (const [dependencyName, dependencyValue] of dependenciesEntries) { + const fullDependencyPath: pnpmTypes.DepPath = splicePackageWithVersion( + shrinkwrapFileMajorVersion, + dependencyName, + typeof dependencyValue === 'string' + ? dependencyValue + : ( + dependencyValue as { + version: string; + specifier: string; + } + ).version + ) as pnpmTypes.DepPath; + if (fullDependencyPath.includes('link:')) { + const dependencyProject: RushConfigurationProject | undefined = + this._rushConfiguration.getProjectByName(dependencyName); + if (dependencyProject && !this._checkedProjects?.has(dependencyProject)) { + this._checkedProjects!.add(project); + await this._searchAndValidateDependenciesAsync(dependencyProject, requiredVersions); + } + } else { + await this._checkVersionCompatibilityAsync( + shrinkwrapFileMajorVersion, + packages, + fullDependencyPath, + requiredVersions, + checkedDependencyPaths + ); + } + } + } + }) + ); + } + + private async _performVersionRestrictionCheckAsync( + requiredVersions: Record, + projectName: string + ): Promise { + try { + const project: RushConfigurationProject | undefined = + this._rushConfiguration?.getProjectByName(projectName); + if (!project) { + throw new Error( + `Specified project "${projectName}" does not exist in ${LOCKFILE_LINT_JSON_FILENAME}` + ); + } + this._checkedProjects.add(project); + await this._searchAndValidateDependenciesAsync(project, requiredVersions); + return undefined; + } catch (e) { + return e.message; + } + } + + protected override async onExecuteAsync(): Promise { + const rushConfiguration: RushConfiguration | undefined = RushConfiguration.tryLoadFromDefaultLocation(); + if (!rushConfiguration) { + throw new Error( + 'The "lockfile-explorer check" must be executed in a folder that is under a Rush workspace folder' + ); + } + this._rushConfiguration = rushConfiguration!; + + const lintingFile: string = path.resolve( + this._rushConfiguration.commonFolder, + 'config', + LOCKFILE_EXPLORER_FOLDERNAME, + LOCKFILE_LINT_JSON_FILENAME + ); + const { rules }: ILockfileLint = await JsonFile.loadAndValidateAsync( + lintingFile, + JsonSchema.fromLoadedObject(lockfileLintSchema) + ); + const issues: ILintIssue[] = []; + await Async.forEachAsync( + rules, + async ({ requiredVersions, project, rule }) => { + switch (rule) { + case 'restrict-versions': { + const message: string | undefined = await this._performVersionRestrictionCheckAsync( + requiredVersions, + project + ); + if (message) { + issues.push({ project, rule, message }); + } + break; + } + + default: { + throw new Error('Unsupported rule name: ' + rule); + } + } + }, + { concurrency: 50 } + ); + if (issues.length > 0) { + this._terminal.writeLine(); + + // Deterministic order + for (const issue of issues.sort((a, b): number => { + let diff: number = a.project.localeCompare(b.project); + if (diff !== 0) { + return diff; + } + diff = a.rule.localeCompare(b.rule); + if (diff !== 0) { + return diff; + } + return a.message.localeCompare(b.message); + })) { + this._terminal.writeLine( + Colorize.red('PROBLEM: ') + Colorize.cyan(`[${issue.rule}] `) + issue.message + '\n' + ); + } + + throw new AlreadyReportedError(); + } + this._terminal.writeLine(Colorize.green('SUCCESS: ') + 'All checks passed.'); + } +} diff --git a/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts b/apps/lockfile-explorer/src/cli/lint/actions/InitAction.ts new file mode 100644 index 00000000000..c848dc47734 --- /dev/null +++ b/apps/lockfile-explorer/src/cli/lint/actions/InitAction.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 path from 'node:path'; + +import { CommandLineAction } from '@rushstack/ts-command-line'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { RushConfiguration } from '@rushstack/rush-sdk'; +import { FileSystem } from '@rushstack/node-core-library'; + +import type { LintCommandLineParser } from '../LintCommandLineParser'; +import { LOCKFILE_EXPLORER_FOLDERNAME, LOCKFILE_LINT_JSON_FILENAME } from '../../../constants/common'; + +export class InitAction extends CommandLineAction { + private readonly _terminal: ITerminal; + + public constructor(parser: LintCommandLineParser) { + super({ + actionName: 'init', + summary: `Create a new ${LOCKFILE_LINT_JSON_FILENAME} config file`, + documentation: + `This command initializes a new ${LOCKFILE_LINT_JSON_FILENAME} config file.` + + ` The created template file includes source code comments that document the settings.` + }); + this._terminal = parser.globalTerminal; + } + + protected override async onExecuteAsync(): Promise { + const rushConfiguration: RushConfiguration | undefined = RushConfiguration.tryLoadFromDefaultLocation(); + if (!rushConfiguration) { + throw new Error( + 'The "lockfile-explorer check" must be executed in a folder that is under a Rush workspace folder' + ); + } + const inputFilePath: string = path.resolve( + __dirname, + '../../../assets/lint-init/lockfile-lint-template.json' + ); + const outputFilePath: string = path.resolve( + rushConfiguration.commonFolder, + 'config', + LOCKFILE_EXPLORER_FOLDERNAME, + LOCKFILE_LINT_JSON_FILENAME + ); + + if (await FileSystem.existsAsync(outputFilePath)) { + this._terminal.writeError('The output file already exists:'); + this._terminal.writeLine('\n ' + outputFilePath + '\n'); + throw new Error('Unable to write output file'); + } + + this._terminal.writeLine(Colorize.green('Writing file: ') + outputFilePath); + await FileSystem.copyFileAsync({ + sourcePath: inputFilePath, + destinationPath: outputFilePath + }); + } +} diff --git a/apps/lockfile-explorer/src/constants/common.ts b/apps/lockfile-explorer/src/constants/common.ts new file mode 100644 index 00000000000..37e8a75b1c3 --- /dev/null +++ b/apps/lockfile-explorer/src/constants/common.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 LOCKFILE_LINT_JSON_FILENAME: 'lockfile-lint.json' = 'lockfile-lint.json'; + +export const LOCKFILE_EXPLORER_FOLDERNAME: 'lockfile-explorer' = 'lockfile-explorer'; diff --git a/apps/lockfile-explorer/src/graph/IPnpmfileModule.ts b/apps/lockfile-explorer/src/graph/IPnpmfileModule.ts new file mode 100644 index 00000000000..05ee1eae2e7 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/IPnpmfileModule.ts @@ -0,0 +1,24 @@ +// 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'; + +export interface IReadPackageContext { + log: (message: string) => void; +} + +export type IReadPackageHook = ( + packageJson: IPackageJson, + context: IReadPackageContext +) => IPackageJson | Promise; + +export interface IPnpmHooks { + readPackage?: IReadPackageHook; +} + +/** + * Type of the `.pnpmfile.cjs` module. + */ +export interface IPnpmfileModule { + hooks?: IPnpmHooks; +} diff --git a/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts b/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts new file mode 100644 index 00000000000..10c09e7d40b --- /dev/null +++ b/apps/lockfile-explorer/src/graph/PnpmfileRunner.ts @@ -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. + +import { Worker } from 'node:worker_threads'; +import * as path from 'node:path'; + +import type { IPackageJson } from '@rushstack/node-core-library'; + +import type { IRequestMessage, ResponseMessage } from './pnpmfileRunnerWorkerThread'; + +interface IPromise { + resolve: (r: IPackageJson) => void; + reject: (e: Error) => void; +} + +/** + * Evals `.pnpmfile.cjs` in an isolated thread, so `transformPackageAsync()` can be used to rewrite + * package.json files. Calling `disposeAsync()` will free the loaded modules. + */ +export class PnpmfileRunner { + private _worker: Worker; + private _nextId: number = 1000; + private _promisesById: Map = new Map(); + private _disposed: boolean = false; + + public logger: ((message: string) => void) | undefined = undefined; + + public constructor(pnpmfilePath: string) { + this._worker = new Worker(path.join(`${__dirname}/pnpmfileRunnerWorkerThread.js`), { + workerData: { pnpmfilePath } + }); + + this._worker.on('message', (message: ResponseMessage) => { + const id: number = message.id; + const promise: IPromise | undefined = this._promisesById.get(id); + if (!promise) { + return; + } + + if (message.kind === 'return') { + this._promisesById.delete(id); + // TODO: Validate the user's readPackage() return value + const result: IPackageJson = message.result as IPackageJson; + promise.resolve(result); + } else if (message.kind === 'log') { + // No this._promisesById.delete(id) for this case + if (this.logger) { + this.logger(message.log); + } else { + console.log('.pnpmfile.cjs: ' + message.log); + } + } else { + this._promisesById.delete(id); + promise.reject(new Error(message.error || 'An unknown error occurred')); + } + }); + + this._worker.on('error', (err) => { + for (const promise of this._promisesById.values()) { + promise.reject(err); + } + this._promisesById.clear(); + }); + + this._worker.on('exit', (code) => { + if (!this._disposed) { + const error: Error = new Error( + `PnpmfileRunner worker thread terminated unexpectedly with exit code ${code}` + ); + console.error(error); + for (const promise of this._promisesById.values()) { + promise.reject(error); + } + this._promisesById.clear(); + } + }); + } + + /** + * Invokes the readPackage() hook from .pnpmfile.cjs + */ + public transformPackageAsync( + packageJson: IPackageJson, + packageJsonFullPath: string + ): Promise { + if (this._disposed) { + return Promise.reject(new Error('The operation failed because PnpmfileRunner has been disposed')); + } + + const id: number = this._nextId++; + return new Promise((resolve, reject) => { + this._promisesById.set(id, { resolve, reject }); + this._worker.postMessage({ id, packageJson, packageJsonFullPath } satisfies IRequestMessage); + }); + } + + public async disposeAsync(): Promise { + if (this._disposed) { + return; + } + for (const pending of this._promisesById.values()) { + pending.reject(new Error('Aborted because PnpmfileRunner was disposed')); + } + this._promisesById.clear(); + this._disposed = true; + await this._worker.terminate(); + } +} diff --git a/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts new file mode 100644 index 00000000000..732548d9743 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts @@ -0,0 +1,612 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as lockfileTypes from '@pnpm/lockfile.types'; +import type * as pnpmTypes from '@pnpm/types'; + +import { Text } from '@rushstack/node-core-library'; + +import { + type ILfxGraphDependencyOptions, + type ILfxGraphEntryOptions, + LfxGraph, + LfxGraphEntry, + LfxGraphEntryKind, + LfxDependencyKind, + LfxGraphDependency, + type IJsonLfxWorkspace +} from '../../build/lfx-shared'; +import * as lockfilePath from './lockfilePath'; + +type PnpmLockfileVersion = 54 | 60 | 90; +type PeerDependenciesMeta = lockfileTypes.LockfilePackageInfo['peerDependenciesMeta']; + +function createPackageLockfileDependency(options: { + name: string; + versionPath: string; + originalSpecifier: string; + kind: LfxDependencyKind; + containingEntry: LfxGraphEntry; + peerDependenciesMeta?: PeerDependenciesMeta; + pnpmLockfileVersion: PnpmLockfileVersion; + workspace: IJsonLfxWorkspace; +}): LfxGraphDependency { + const { + name, + versionPath, + originalSpecifier, + kind: dependencyKind, + containingEntry, + peerDependenciesMeta, + pnpmLockfileVersion + } = options; + + const result: ILfxGraphDependencyOptions = { + name, + versionPath, + entryId: '', + originalSpecifier, + dependencyKind, + peerDependencyMeta: {}, + containingEntry + }; + + if (versionPath.startsWith('link:')) { + const relativePath: string = versionPath.substring('link:'.length); + + if (containingEntry.kind === LfxGraphEntryKind.Project) { + // TODO: Here we assume it's a "workspace:" link and try to resolve it to another workspace project, + // but it could also be a link to an arbitrary folder (in which case this entryId will fail to resolve). + // In the future, we should distinguish these cases. + const selfRelativePath: string = lockfilePath.getAbsolute( + containingEntry.packageJsonFolderPath, + relativePath + ); + result.entryId = 'project:' + selfRelativePath.toString(); + } else { + // This could be a link to anywhere on the local computer, so we don't expect it to have a lockfile entry + result.entryId = ''; + } + } else if (result.versionPath.startsWith('/')) { + result.entryId = versionPath; + } else { + // Version 5.4: /@rushstack/m/1.0.0: + // Version 6.0: /@rushstack/m@1.0.0: + // Version 9.0: @rushstack/m@1.0.0: + // + // Version 5.4: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + // Version 6.0: /@rushstack/j@1.0.0(@rushstack/n@2.0.0) + // Version 9.0: @rushstack/j@1.0.0(@rushstack/n@2.0.0) + const versionDelimiter: string = pnpmLockfileVersion < 60 ? '/' : '@'; + result.entryId = + (pnpmLockfileVersion < 90 ? '/' : '') + result.name + versionDelimiter + result.versionPath; + } + + if (result.dependencyKind === LfxDependencyKind.Peer) { + result.peerDependencyMeta = { + name: result.name, + version: versionPath, + optional: peerDependenciesMeta?.[result.name] ? peerDependenciesMeta[result.name].optional : false + }; + } + return new LfxGraphDependency(result); +} + +function parsePackageDependencies(options: { + dependencies: LfxGraphDependency[]; + lockfileEntry: LfxGraphEntry; + /** + * Used to obtain versionPath exact references. + */ + mainEntry: lockfileTypes.LockfilePackageSnapshot; + /** + * Used to obtain informational version ranges. + */ + specifierEntry: lockfileTypes.LockfilePackageInfo | undefined; + pnpmLockfileVersion: PnpmLockfileVersion; + workspace: IJsonLfxWorkspace; +}): void { + const { dependencies, lockfileEntry, mainEntry, specifierEntry, pnpmLockfileVersion, workspace } = options; + + const node: Partial = + mainEntry as unknown as Partial; + + function createDependency(kind: LfxDependencyKind, packageName: string, versionPath: string): void { + let originalSpecifier: string | undefined = undefined; + + if (specifierEntry && specifierEntry.peerDependencies) { + originalSpecifier = specifierEntry.peerDependencies[packageName]; + if (originalSpecifier) { + kind = LfxDependencyKind.Peer; + } + } + + dependencies.push( + createPackageLockfileDependency({ + kind, + name: packageName, + versionPath, + originalSpecifier: originalSpecifier ?? '', + containingEntry: lockfileEntry, + peerDependenciesMeta: specifierEntry?.peerDependenciesMeta, + pnpmLockfileVersion, + workspace + }) + ); + } + + if (node.dependencies) { + for (const [packageName, versionPath] of Object.entries(node.dependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, versionPath); + } + } + if (node.optionalDependencies) { + for (const [packageName, versionPath] of Object.entries(node.optionalDependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, versionPath); + } + } + if (node.devDependencies) { + for (const [packageName, versionPath] of Object.entries(node.devDependencies)) { + createDependency(LfxDependencyKind.Dev, packageName, versionPath); + } + } + + if (node.transitivePeerDependencies) { + for (const dep of node.transitivePeerDependencies) { + lockfileEntry.transitivePeerDependencies.add(dep); + } + } +} + +function parseProjectDependencies54(options: { + dependencies: LfxGraphDependency[]; + lockfileEntry: LfxGraphEntry; + /** + * Used to obtain versionPath exact references and informational version ranges + */ + mainEntry: lockfileTypes.ProjectSnapshot; + pnpmLockfileVersion: PnpmLockfileVersion; + workspace: IJsonLfxWorkspace; +}): void { + const { dependencies, lockfileEntry, mainEntry, pnpmLockfileVersion, workspace } = options; + + const node: Partial = + mainEntry as unknown as Partial; + + function createDependency(kind: LfxDependencyKind, packageName: string, versionPath: string): void { + let originalSpecifier: string | undefined = undefined; + + if (mainEntry.specifiers) { + originalSpecifier = mainEntry.specifiers[packageName]; + } + + dependencies.push( + createPackageLockfileDependency({ + kind, + name: packageName, + versionPath, + originalSpecifier: originalSpecifier ?? '', + containingEntry: lockfileEntry, + pnpmLockfileVersion, + workspace + }) + ); + } + + if (node.dependencies) { + for (const [packageName, versionPath] of Object.entries(node.dependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, versionPath); + } + } + if (node.optionalDependencies) { + for (const [packageName, versionPath] of Object.entries(node.optionalDependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, versionPath); + } + } + if (node.devDependencies) { + for (const [packageName, versionPath] of Object.entries(node.devDependencies)) { + createDependency(LfxDependencyKind.Dev, packageName, versionPath); + } + } +} + +function parseProjectDependencies60( + dependencies: LfxGraphDependency[], + lockfileEntry: LfxGraphEntry, + snapshot: lockfileTypes.LockfileFileProjectSnapshot, + pnpmLockfileVersion: PnpmLockfileVersion, + workspace: IJsonLfxWorkspace +): void { + function createDependency( + kind: LfxDependencyKind, + packageName: string, + specifierAndResolution: lockfileTypes.SpecifierAndResolution + ): void { + dependencies.push( + createPackageLockfileDependency({ + kind, + name: packageName, + versionPath: specifierAndResolution.version, + originalSpecifier: specifierAndResolution.specifier, + containingEntry: lockfileEntry, + pnpmLockfileVersion, + workspace + }) + ); + } + + if (snapshot.dependencies) { + for (const [packageName, specifierAndResolution] of Object.entries(snapshot.dependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, specifierAndResolution); + } + } + if (snapshot.optionalDependencies) { + for (const [packageName, specifierAndResolution] of Object.entries(snapshot.optionalDependencies)) { + createDependency(LfxDependencyKind.Regular, packageName, specifierAndResolution); + } + } + if (snapshot.devDependencies) { + for (const [packageName, specifierAndResolution] of Object.entries(snapshot.devDependencies)) { + createDependency(LfxDependencyKind.Dev, packageName, specifierAndResolution); + } + } +} + +function createProjectLockfileEntry(options: { + rawEntryId: string; + duplicates?: Set; + workspace: IJsonLfxWorkspace; + pnpmLockfileVersion: PnpmLockfileVersion; +}): LfxGraphEntry { + const { rawEntryId, duplicates, workspace } = options; + + const result: ILfxGraphEntryOptions = { + kind: LfxGraphEntryKind.Project, + entryId: '', + rawEntryId: '', + packageJsonFolderPath: '', + entryPackageName: '', + displayText: '', + entryPackageVersion: '', + entrySuffix: '' + }; + + result.rawEntryId = rawEntryId; + + // Example: pnpmLockfilePath = 'common/temp/my-subspace/pnpm-lock.yaml' + // Example: pnpmLockfileFolder = 'common/temp/my-subspace' + const pnpmLockfileFolder: string = workspace.pnpmLockfileFolder; + + // Example: rawEntryId = '../../../projects/a' + // Example: packageJsonFolderPath = 'projects/a' + result.packageJsonFolderPath = lockfilePath.getAbsolute(pnpmLockfileFolder, rawEntryId); + result.entryId = 'project:' + result.packageJsonFolderPath; + + const projectFolderName: string = lockfilePath.getBaseNameOf(rawEntryId); + + if (!duplicates?.has(projectFolderName)) { + // TODO: The actual package.json name might not match its directory name, + // but we have to load package.json to determine it. + result.entryPackageName = projectFolderName; + } else { + result.entryPackageName = `${projectFolderName} (${result.packageJsonFolderPath})`; + } + result.displayText = `Project: ${result.entryPackageName}`; + + const lockfileEntry: LfxGraphEntry = new LfxGraphEntry(result); + return lockfileEntry; +} + +function createPackageLockfileEntry(options: { + rawEntryId: string; + workspace: IJsonLfxWorkspace; + pnpmLockfileVersion: PnpmLockfileVersion; +}): LfxGraphEntry { + const { rawEntryId, pnpmLockfileVersion, workspace } = options; + + const result: ILfxGraphEntryOptions = { + kind: LfxGraphEntryKind.Package, + entryId: rawEntryId, + rawEntryId: rawEntryId, + packageJsonFolderPath: '', + entryPackageName: '', + displayText: rawEntryId, + entryPackageVersion: '', + entrySuffix: '' + }; + + // Example: pnpmLockfilePath = 'common/temp/my-subspace/pnpm-lock.yaml' + // Example: pnpmLockfileFolder = 'common/temp/my-subspace' + const pnpmLockfileFolder: string = workspace.pnpmLockfileFolder; + + let slashlessRawEntryId: string; + + if (pnpmLockfileVersion >= 90) { + // The leading slash is omitted starting in V9.0 + if (rawEntryId.startsWith('/')) { + throw new Error('Not expecting leading "/" in path: ' + JSON.stringify(rawEntryId)); + } + slashlessRawEntryId = rawEntryId; + } else { + if (!rawEntryId.startsWith('/')) { + throw new Error('Expecting leading "/" in path: ' + JSON.stringify(rawEntryId)); + } + slashlessRawEntryId = rawEntryId.substring(1); + } + + let dotPnpmSubfolder: string; + + if (pnpmLockfileVersion < 60) { + const lastSlashIndex: number = rawEntryId.lastIndexOf('/'); + if (lastSlashIndex < 0) { + throw new Error('Expecting "/" in path: ' + JSON.stringify(rawEntryId)); + } + const packageName: string = rawEntryId.substring(1, lastSlashIndex); + result.entryPackageName = packageName; + + // /@rushstack/eslint-config/3.0.1_eslint@8.21.0+typescript@4.7.4 + // --> @rushstack/eslint-config 3.0.1 (eslint@8.21.0+typescript@4.7.4) + const underscoreIndex: number = rawEntryId.indexOf('_', lastSlashIndex); + if (underscoreIndex > 0) { + const version: string = rawEntryId.substring(lastSlashIndex + 1, underscoreIndex); + const suffix: string = rawEntryId.substring(underscoreIndex + 1); + result.displayText = packageName + ' ' + version + ' (' + suffix + ')'; + result.entryPackageVersion = version; + result.entrySuffix = suffix; + } else { + // /@rushstack/eslint-config/3.0.1 + // --> @rushstack/eslint-config 3.0.1 + const version: string = rawEntryId.substring(lastSlashIndex + 1); + result.displayText = packageName + ' ' + version; + result.entryPackageVersion = version; + } + + // Example: @babel+register@7.17.7_@babel+core@7.17.12 + dotPnpmSubfolder = + result.entryPackageName.replace('/', '+') + + '@' + + result.entryPackageVersion + + (result.entrySuffix ? `_${result.entrySuffix}` : ''); + } else { + // Example inputs: + // @rushstack/eslint-config@3.0.1 + // @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + let versionAtSignIndex: number; + if (slashlessRawEntryId.startsWith('@')) { + versionAtSignIndex = slashlessRawEntryId.indexOf('@', 1); + } else { + versionAtSignIndex = slashlessRawEntryId.indexOf('@'); + } + + const packageName: string = slashlessRawEntryId.substring(0, versionAtSignIndex); + result.entryPackageName = packageName; + + const leftParenIndex: number = slashlessRawEntryId.indexOf('(', versionAtSignIndex); + if (leftParenIndex < 0) { + const version: string = slashlessRawEntryId.substring(versionAtSignIndex + 1); + result.entryPackageVersion = version; + + // @rushstack/eslint-config@3.0.1 + // --> @rushstack/eslint-config 3.0.1 + result.displayText = packageName + ' ' + version; + } else { + const version: string = slashlessRawEntryId.substring(versionAtSignIndex + 1, leftParenIndex); + result.entryPackageVersion = version; + + // "(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)" + let suffix: string = slashlessRawEntryId.substring(leftParenIndex); + + // Rewrite to: + // "@rushstack/m@1.0.0; @rushstack/n@2.0.0" + suffix = Text.replaceAll(suffix, ')(', '; '); + suffix = Text.replaceAll(suffix, '(', ''); + suffix = Text.replaceAll(suffix, ')', ''); + result.entrySuffix = suffix; + + // @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + // --> @rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0] + result.displayText = packageName + ' ' + version + ' [' + suffix + ']'; + } + + // Example: @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + // --> @rushstack+l@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0 + + // @rushstack/l 1.0.0 (@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + dotPnpmSubfolder = Text.replaceAll(slashlessRawEntryId, '/', '+'); + dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, ')(', '_'); + dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, '(', '_'); + dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, ')', ''); + } + + // Example: + // common/temp/default/node_modules/.pnpm + // /@babel+register@7.17.7_@babel+core@7.17.12 + // /node_modules/@babel/register + result.packageJsonFolderPath = lockfilePath.join( + pnpmLockfileFolder, + `node_modules/.pnpm/` + dotPnpmSubfolder + '/node_modules/' + result.entryPackageName + ); + + const lockfileEntry: LfxGraphEntry = new LfxGraphEntry(result); + return lockfileEntry; +} + +/** + * Parse through the lockfile and create all the corresponding LockfileEntries and LockfileDependencies + * to construct the lockfile graph. + * + * @returns A list of all the LockfileEntries in the lockfile. + */ +export function generateLockfileGraph(lockfileJson: unknown, workspace: IJsonLfxWorkspace): LfxGraph { + const lockfile: lockfileTypes.LockfileObject | lockfileTypes.LockfileFile = lockfileJson as + | lockfileTypes.LockfileObject + | lockfileTypes.LockfileFile; + + let pnpmLockfileVersion: PnpmLockfileVersion; + switch (lockfile.lockfileVersion.toString()) { + case '5.4': + pnpmLockfileVersion = 54; + break; + case '6': + case '6.0': + pnpmLockfileVersion = 60; + break; + case '9': + case '9.0': + pnpmLockfileVersion = 90; + break; + default: + throw new Error('Unsupported PNPM lockfile version ' + JSON.stringify(lockfile.lockfileVersion)); + } + + const lfxGraph: LfxGraph = new LfxGraph(workspace); + const allEntries: LfxGraphEntry[] = lfxGraph.entries; + const allEntriesById: Map = new Map(); + + const allImporters: LfxGraphEntry[] = []; + + // "Importers" are the local workspace projects + if (lockfile.importers) { + // Normally the UX shows the concise project folder name. However in the case of duplicates + // (where two projects use the same folder name), then we will need to disambiguate. + const baseNames: Set = new Set(); + const duplicates: Set = new Set(); + for (const importerKey of Object.keys(lockfile.importers)) { + const baseName: string = lockfilePath.getBaseNameOf(importerKey); + if (baseNames.has(baseName)) { + duplicates.add(baseName); + } + baseNames.add(baseName); + } + + const isRushWorkspace: boolean = workspace.rushConfig !== undefined; + + for (const importerKey of Object.keys(lockfile.importers)) { + if (isRushWorkspace && importerKey === '.') { + // Discard the synthetic package.json file created by Rush under common/temp + continue; + } + + const importer: LfxGraphEntry = createProjectLockfileEntry({ + rawEntryId: importerKey, + duplicates, + workspace, + pnpmLockfileVersion + }); + + if (pnpmLockfileVersion < 60) { + const lockfile54: lockfileTypes.LockfileObject = lockfileJson as lockfileTypes.LockfileObject; + const importerValue: lockfileTypes.ProjectSnapshot = + lockfile54.importers[importerKey as pnpmTypes.ProjectId]; + + parseProjectDependencies54({ + dependencies: importer.dependencies, + lockfileEntry: importer, + mainEntry: importerValue, + pnpmLockfileVersion, + workspace + }); + } else { + const lockfile60: lockfileTypes.LockfileFile = lockfileJson as lockfileTypes.LockfileFile; + if (lockfile60.importers) { + const importerValue: lockfileTypes.LockfileFileProjectSnapshot = + lockfile60.importers[importerKey as pnpmTypes.ProjectId]; + parseProjectDependencies60( + importer.dependencies, + importer, + importerValue, + pnpmLockfileVersion, + workspace + ); + } + } + + allImporters.push(importer); + allEntries.push(importer); + allEntriesById.set(importer.entryId, importer); + } + } + + if (pnpmLockfileVersion < 90) { + if (lockfile.packages) { + for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) { + const lockfileEntry: LfxGraphEntry = createPackageLockfileEntry({ + rawEntryId: dependencyKey, + workspace, + pnpmLockfileVersion + }); + parsePackageDependencies({ + dependencies: lockfileEntry.dependencies, + lockfileEntry: lockfileEntry, + mainEntry: dependencyValue, + specifierEntry: dependencyValue, + pnpmLockfileVersion, + workspace + }); + allEntries.push(lockfileEntry); + allEntriesById.set(dependencyKey, lockfileEntry); + } + } + } else { + const packagesByKey: Map = new Map(); + if (lockfile.packages) { + for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) { + packagesByKey.set(dependencyKey, dependencyValue); + } + } + + // In v9.0 format, the dependency graph for non-workspace packages is found under "snapshots" not "packages". + // (The "packages" section now stores other fields that are unrelated to the graph itself.) + const lockfile90: lockfileTypes.LockfileFile = lockfileJson as lockfileTypes.LockfileFile; + if (lockfile90.snapshots) { + for (const [dependencyKey, dependencyValue] of Object.entries(lockfile90.snapshots)) { + const lockfileEntry: LfxGraphEntry = createPackageLockfileEntry({ + rawEntryId: dependencyKey, + workspace, + pnpmLockfileVersion + }); + + // Example: "@scope/my-package@1.0.0" + const packageInfoKey: string = + lockfileEntry.entryPackageName + '@' + lockfileEntry.entryPackageVersion; + const packageInfo: lockfileTypes.LockfilePackageInfo | undefined = packagesByKey.get(packageInfoKey); + + parsePackageDependencies({ + dependencies: lockfileEntry.dependencies, + lockfileEntry, + mainEntry: dependencyValue, + specifierEntry: packageInfo, + pnpmLockfileVersion, + workspace + }); + + allEntries.push(lockfileEntry); + allEntriesById.set(lockfileEntry.entryId, lockfileEntry); + } + } + } + + // Construct the graph + for (const entry of allEntries) { + for (const dependency of entry.dependencies) { + // Peer dependencies do not have a matching entry + if (dependency.dependencyKind === LfxDependencyKind.Peer) { + continue; + } + + const matchedEntry: LfxGraphEntry | undefined = allEntriesById.get(dependency.entryId); + if (matchedEntry) { + // Create a two-way link between the dependency and the entry + dependency.resolvedEntry = matchedEntry; + matchedEntry.referrers.push(entry); + } else { + if (dependency.entryId.startsWith('/')) { + // Local package + console.error('Could not resolve dependency entryId: ', dependency.entryId, dependency); + } + } + } + } + + return lfxGraph; +} diff --git a/apps/lockfile-explorer/src/graph/lockfilePath.ts b/apps/lockfile-explorer/src/graph/lockfilePath.ts new file mode 100644 index 00000000000..1a03e4c58f3 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/lockfilePath.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. + +/** + * For example, retrieves `d` from `/a/b/c/d`. + */ +export function getBaseNameOf(importerPath: string): string { + if (importerPath.length === 0) { + return ''; + } + + const index: number = importerPath.lastIndexOf('/'); + if (index === importerPath.length - 1) { + throw new Error('Error: Path has a trailing slash'); + } + if (index >= 0) { + return importerPath.substring(index + 1); + } + return importerPath; +} + +/** + * For example, retrieves `/a/b/c` from `/a/b/c/d`. + */ +export function getParentOf(importerPath: string): string { + if (importerPath === '' || importerPath === '.' || importerPath === '/') { + throw new Error('Error: Path has no parent'); + } + + const index: number = importerPath.lastIndexOf('/'); + if (index === importerPath.length - 1) { + throw new Error('Error: Path has a trailing slash'); + } + if (index === 0) { + return '/'; + } + if (index < 0) { + return '.'; + } + return importerPath.substring(0, index); +} + +/** + * Cheaply resolves a relative path against a base path, assuming the paths are delimited by `/`, + * and assuming the basePath is already in normal form. An error occurs if the relative path + * goes above the root folder. + * + * @example + * ```ts + * getAbsolutePath(`a/b/c`, `d/e`) === `a/b/c/d/e` + * getAbsolutePath(`/a/b/c`, `d/e`) === `/a/b/c/d/e` + * getAbsolutePath(`/a/b/c`, `/d/e`) === `/d/e` + * getAbsolutePath(`a/b/c`, `../../f`) === `a/f` + * getAbsolutePath(`a/b/c`, `.././/f`) === `a/b/f` + * getAbsolutePath(`a/b/c`, `../../..`) === `.` + * getAbsolutePath(`C:/a/b`, `../d`) === `C:/a/d` + * getAbsolutePath(`a/b/c`, `../../../..`) === ERROR + * + * // Degenerate cases: + * getAbsolutePath(`a/b/c/`, `d/`) === `a/b/c/d` // trailing slashes are discarded + * getAbsolutePath(`./../c`, `d`) === `./../c/d` // basePath assumed to be normal form + * getAbsolutePath(`C:\\`, `\\a`) === `C:\\/\\a` // backslashes not supported + * ``` + */ +export function getAbsolute(basePath: string, relativePath: string): string { + let leadingSlash: boolean; + let stack: string[]; + + // Discard intermediary slashes + const relativeParts: string[] = relativePath.split('/').filter((part: string) => part.length > 0); + if (relativePath.startsWith('/')) { + stack = []; + leadingSlash = true; + } else { + // Discard intermediary slashes + stack = basePath.split('/').filter((part: string) => part.length > 0); + leadingSlash = basePath.startsWith('/'); + } + + for (const part of relativeParts) { + if (part === '.') { + // current directory, do nothing + continue; + } else if (part === '..') { + if (stack.length === 0) { + throw new Error('getAbsolutePath(): relativePath goes above the root folder'); + } + stack.pop(); + } else { + stack.push(part); + } + } + if (leadingSlash) { + return '/' + stack.join('/'); + } else { + return stack.length === 0 ? '.' : stack.join('/'); + } +} + +/** + * Returns the two parts joined by exactly one `/`, assuming the parts are already + * in normalized form. The `/` is not added if either part is an empty string. + */ +export function join(leftPart: string, rightPart: string): string { + if (leftPart.length === 0) { + return rightPart; + } + if (rightPart.length === 0) { + return leftPart; + } + + const leftEndsWithSlash: boolean = leftPart[leftPart.length - 1] === '/'; + const rightStartsWithSlash: boolean = rightPart[0] === '/'; + + if (leftEndsWithSlash && rightStartsWithSlash) { + return leftPart + rightPart.substring(1); + } + if (leftEndsWithSlash || rightStartsWithSlash) { + return leftPart + rightPart; + } + return leftPart + '/' + rightPart; +} diff --git a/apps/lockfile-explorer/src/graph/pnpmfileRunnerWorkerThread.ts b/apps/lockfile-explorer/src/graph/pnpmfileRunnerWorkerThread.ts new file mode 100644 index 00000000000..a49ff655aae --- /dev/null +++ b/apps/lockfile-explorer/src/graph/pnpmfileRunnerWorkerThread.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 { parentPort, workerData, type MessagePort } from 'node:worker_threads'; +import * as path from 'node:path'; + +import type { IPackageJson } from '@rushstack/node-core-library'; + +import type { IPnpmfileModule, IReadPackageContext } from './IPnpmfileModule'; + +export interface IRequestMessage { + id: number; + packageJson: IPackageJson; + packageJsonFullPath: string; +} + +export interface IResponseMessageLog { + kind: 'log'; + id: number; + log: string; +} +export interface IResponseMessageError { + kind: 'error'; + id: number; + error: string; +} +export interface IResponseMessageReturn { + kind: 'return'; + id: number; + result?: unknown; +} +export type ResponseMessage = IResponseMessageLog | IResponseMessageError | IResponseMessageReturn; + +// debugger; + +const { pnpmfilePath } = workerData; +const resolvedPath: string = path.resolve(pnpmfilePath); + +let pnpmfileModule: IPnpmfileModule | undefined = undefined; +let pnpmfileModuleError: Error | undefined = undefined; + +try { + pnpmfileModule = require(resolvedPath); +} catch (error) { + pnpmfileModuleError = error; +} + +// eslint-disable-next-line @rushstack/no-new-null +const threadParentPort: null | MessagePort = parentPort; + +if (!threadParentPort) { + throw new Error('Not running in a worker thread'); +} + +threadParentPort.on('message', async (message: IRequestMessage) => { + const { id, packageJson } = message; + + if (pnpmfileModuleError) { + threadParentPort.postMessage({ + kind: 'error', + id, + error: pnpmfileModuleError.message + } satisfies IResponseMessageError); + return; + } + + try { + if (!pnpmfileModule || !pnpmfileModule.hooks || typeof pnpmfileModule.hooks.readPackage !== 'function') { + // No transformation needed + threadParentPort.postMessage({ + kind: 'return', + id, + result: packageJson + } satisfies IResponseMessageReturn); + return; + } + + const pnpmContext: IReadPackageContext = { + log: (logMessage) => + threadParentPort.postMessage({ + kind: 'log', + id, + log: logMessage + } satisfies IResponseMessageLog) + }; + + const result: IPackageJson = await pnpmfileModule.hooks.readPackage({ ...packageJson }, pnpmContext); + + threadParentPort.postMessage({ kind: 'return', id, result } satisfies IResponseMessageReturn); + } catch (e) { + threadParentPort.postMessage({ + kind: 'error', + id, + error: (e as Error).message + } satisfies IResponseMessageError); + } +}); diff --git a/apps/lockfile-explorer/src/graph/test/PnpmfileRunner.test.ts b/apps/lockfile-explorer/src/graph/test/PnpmfileRunner.test.ts new file mode 100644 index 00000000000..4e87d88cc0a --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/PnpmfileRunner.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 inspector from 'node:inspector'; +import { Path } from '@rushstack/node-core-library'; +import { PnpmfileRunner } from '../PnpmfileRunner'; + +const isDebuggerAttached: boolean = inspector.url() !== undefined; + +// Since we're spawning another thread, increase the timeout to 10s. +// For debugging, use an infinite timeout. +jest.setTimeout(isDebuggerAttached ? 1e9 : 10000); + +describe(PnpmfileRunner.name, () => { + it('transforms a package.json file', async () => { + const dirname: string = Path.convertToSlashes(__dirname); + const libIndex: number = dirname.lastIndexOf('/lib/'); + if (libIndex < 0) { + throw new Error('Unexpected file path'); + } + const srcDirname: string = + dirname.substring(0, libIndex) + '/src/' + dirname.substring(libIndex + '/lib/'.length); + + const pnpmfilePath: string = srcDirname + '/fixtures/PnpmfileRunner/.pnpmfile.cjs'; + const logMessages: string[] = []; + + const pnpmfileRunner: PnpmfileRunner = new PnpmfileRunner(pnpmfilePath); + try { + pnpmfileRunner.logger = (message) => { + logMessages.push(message); + }; + expect( + await pnpmfileRunner.transformPackageAsync( + { + name: '@types/karma', + version: '1.0.0', + dependencies: { + 'example-dependency': '1.0.0' + } + }, + pnpmfilePath + ) + ).toMatchInlineSnapshot(` +Object { + "dependencies": Object { + "example-dependency": "1.0.0", + "log4js": "0.6.38", + }, + "name": "@types/karma", + "version": "1.0.0", +} +`); + } finally { + await pnpmfileRunner.disposeAsync(); + } + + expect(logMessages).toMatchInlineSnapshot(` +Array [ + "Fixed up dependencies for @types/karma", +] +`); + + await expect( + pnpmfileRunner.transformPackageAsync({ name: 'name', version: '1.0.0' }, '') + ).rejects.toThrow('disposed'); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap new file mode 100644 index 00000000000..a8af1106857 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap @@ -0,0 +1,287 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-edge-cases-v5.4 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: /mime-db/1.54.0 + name: mime-db + originalSpecifier: ^1.52.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + versionPath: 1.54.0 + - dependencyKind: dev + entryId: /color-string/2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: dev-dependencies' + entryId: project:packages/dev-dependencies + entryPackageName: dev-dependencies + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: packages/dev-dependencies + rawEntryId: packages/dev-dependencies + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color/5.0.2 + name: color + originalSpecifier: ^5.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 5.0.2 + displayText: 'Project: duplicate (packages/duplicate-1/duplicate)' + entryId: project:packages/duplicate-1/duplicate + entryPackageName: duplicate (packages/duplicate-1/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: packages/duplicate-1/duplicate + rawEntryId: packages/duplicate-1/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-string/2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: duplicate (packages/duplicate-2/duplicate)' + entryId: project:packages/duplicate-2/duplicate + entryPackageName: duplicate (packages/duplicate-2/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: packages/duplicate-2/duplicate + rawEntryId: packages/duplicate-2/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /has-symbols/1.0.2 + name: has-symbols + originalSpecifier: 1.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 1.0.2 + - dependencyKind: regular + entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder + name: target-folder + originalSpecifier: link:packages/link-specifier/target-folder + peerDependencyMeta: {} + versionPath: link:packages/link-specifier/target-folder + displayText: 'Project: linker' + entryId: project:packages/link-specifier/linker + entryPackageName: linker + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: packages/link-specifier/linker + rawEntryId: packages/link-specifier/linker + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /address/1.2.2 + name: address + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.2.2 + - dependencyKind: regular + entryId: /uri-js/4.4.1 + name: uri-js + originalSpecifier: ^4.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 13 + versionPath: 4.4.1 + displayText: 'Project: pnpmfile-transforms' + entryId: project:packages/pnpmfile-transforms + entryPackageName: pnpmfile-transforms + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: packages/pnpmfile-transforms + rawEntryId: packages/pnpmfile-transforms + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: [] + displayText: address 1.2.2 + entryId: /address/1.2.2 + entryPackageName: address + entryPackageVersion: 1.2.2 + entrySuffix: '' + jsonId: 5 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address + rawEntryId: /address/1.2.2 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-name/2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-convert 3.1.2 + entryId: /color-convert/3.1.2 + entryPackageName: color-convert + entryPackageVersion: 3.1.2 + entrySuffix: '' + jsonId: 6 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert + rawEntryId: /color-convert/3.1.2 + referrerJsonIds: + - 9 + transitivePeerDependencies: [] + - dependencies: [] + displayText: color-name 2.0.2 + entryId: /color-name/2.0.2 + entryPackageName: color-name + entryPackageVersion: 2.0.2 + entrySuffix: '' + jsonId: 7 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name + rawEntryId: /color-name/2.0.2 + referrerJsonIds: + - 6 + - 8 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-name/2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-string 2.1.2 + entryId: /color-string/2.1.2 + entryPackageName: color-string + entryPackageVersion: 2.1.2 + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string + rawEntryId: /color-string/2.1.2 + referrerJsonIds: + - 0 + - 2 + - 9 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-convert/3.1.2 + name: color-convert + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 3.1.2 + - dependencyKind: regular + entryId: /color-string/2.1.2 + name: color-string + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: color 5.0.2 + entryId: /color/5.0.2 + entryPackageName: color + entryPackageVersion: 5.0.2 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color + rawEntryId: /color/5.0.2 + referrerJsonIds: + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: '' + name: target-folder + originalSpecifier: '' + peerDependencyMeta: {} + versionPath: link:link-specifier/target-folder + displayText: has-symbols 1.0.2 + entryId: /has-symbols/1.0.2 + entryPackageName: has-symbols + entryPackageVersion: 1.0.2 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols + rawEntryId: /has-symbols/1.0.2 + referrerJsonIds: + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: mime-db 1.54.0 + entryId: /mime-db/1.54.0 + entryPackageName: mime-db + entryPackageVersion: 1.54.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db + rawEntryId: /mime-db/1.54.0 + referrerJsonIds: + - 0 + transitivePeerDependencies: [] + - dependencies: [] + displayText: punycode 2.3.1 + entryId: /punycode/2.3.1 + entryPackageName: punycode + entryPackageVersion: 2.3.1 + entrySuffix: '' + jsonId: 12 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode + rawEntryId: /punycode/2.3.1 + referrerJsonIds: + - 13 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /punycode/2.3.1 + name: punycode + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + versionPath: 2.3.1 + displayText: uri-js 4.4.1 + entryId: /uri-js/4.4.1 + entryPackageName: uri-js + entryPackageVersion: 4.4.1 + entrySuffix: '' + jsonId: 13 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js + rawEntryId: /uri-js/4.4.1 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: '' + pnpmLockfilePath: pnpm-lock.yaml + pnpmfilePath: .pnpmfile.cjs + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap new file mode 100644 index 00000000000..fd6f0c80fdd --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap @@ -0,0 +1,287 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-edge-cases-v6.0 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: /mime-db@1.54.0 + name: mime-db + originalSpecifier: ^1.52.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + versionPath: 1.54.0 + - dependencyKind: dev + entryId: /color-string@2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: dev-dependencies' + entryId: project:packages/dev-dependencies + entryPackageName: dev-dependencies + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: packages/dev-dependencies + rawEntryId: packages/dev-dependencies + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color@5.0.2 + name: color + originalSpecifier: ^5.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 5.0.2 + displayText: 'Project: duplicate (packages/duplicate-1/duplicate)' + entryId: project:packages/duplicate-1/duplicate + entryPackageName: duplicate (packages/duplicate-1/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: packages/duplicate-1/duplicate + rawEntryId: packages/duplicate-1/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-string@2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: duplicate (packages/duplicate-2/duplicate)' + entryId: project:packages/duplicate-2/duplicate + entryPackageName: duplicate (packages/duplicate-2/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: packages/duplicate-2/duplicate + rawEntryId: packages/duplicate-2/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /has-symbols@1.0.2 + name: has-symbols + originalSpecifier: 1.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 1.0.2 + - dependencyKind: regular + entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder + name: target-folder + originalSpecifier: link:packages/link-specifier/target-folder + peerDependencyMeta: {} + versionPath: link:packages/link-specifier/target-folder + displayText: 'Project: linker' + entryId: project:packages/link-specifier/linker + entryPackageName: linker + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: packages/link-specifier/linker + rawEntryId: packages/link-specifier/linker + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /address@1.2.2 + name: address + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.2.2 + - dependencyKind: regular + entryId: /uri-js@4.4.1 + name: uri-js + originalSpecifier: ^4.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 13 + versionPath: 4.4.1 + displayText: 'Project: pnpmfile-transforms' + entryId: project:packages/pnpmfile-transforms + entryPackageName: pnpmfile-transforms + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: packages/pnpmfile-transforms + rawEntryId: packages/pnpmfile-transforms + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: [] + displayText: address 1.2.2 + entryId: /address@1.2.2 + entryPackageName: address + entryPackageVersion: 1.2.2 + entrySuffix: '' + jsonId: 5 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address + rawEntryId: /address@1.2.2 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-name@2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-convert 3.1.2 + entryId: /color-convert@3.1.2 + entryPackageName: color-convert + entryPackageVersion: 3.1.2 + entrySuffix: '' + jsonId: 6 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert + rawEntryId: /color-convert@3.1.2 + referrerJsonIds: + - 9 + transitivePeerDependencies: [] + - dependencies: [] + displayText: color-name 2.0.2 + entryId: /color-name@2.0.2 + entryPackageName: color-name + entryPackageVersion: 2.0.2 + entrySuffix: '' + jsonId: 7 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name + rawEntryId: /color-name@2.0.2 + referrerJsonIds: + - 6 + - 8 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-name@2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-string 2.1.2 + entryId: /color-string@2.1.2 + entryPackageName: color-string + entryPackageVersion: 2.1.2 + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string + rawEntryId: /color-string@2.1.2 + referrerJsonIds: + - 0 + - 2 + - 9 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /color-convert@3.1.2 + name: color-convert + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 3.1.2 + - dependencyKind: regular + entryId: /color-string@2.1.2 + name: color-string + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: color 5.0.2 + entryId: /color@5.0.2 + entryPackageName: color + entryPackageVersion: 5.0.2 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color + rawEntryId: /color@5.0.2 + referrerJsonIds: + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: '' + name: target-folder + originalSpecifier: '' + peerDependencyMeta: {} + versionPath: link:link-specifier/target-folder + displayText: has-symbols 1.0.2 + entryId: /has-symbols@1.0.2 + entryPackageName: has-symbols + entryPackageVersion: 1.0.2 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols + rawEntryId: /has-symbols@1.0.2 + referrerJsonIds: + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: mime-db 1.54.0 + entryId: /mime-db@1.54.0 + entryPackageName: mime-db + entryPackageVersion: 1.54.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db + rawEntryId: /mime-db@1.54.0 + referrerJsonIds: + - 0 + transitivePeerDependencies: [] + - dependencies: [] + displayText: punycode 2.3.1 + entryId: /punycode@2.3.1 + entryPackageName: punycode + entryPackageVersion: 2.3.1 + entrySuffix: '' + jsonId: 12 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode + rawEntryId: /punycode@2.3.1 + referrerJsonIds: + - 13 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /punycode@2.3.1 + name: punycode + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + versionPath: 2.3.1 + displayText: uri-js 4.4.1 + entryId: /uri-js@4.4.1 + entryPackageName: uri-js + entryPackageVersion: 4.4.1 + entrySuffix: '' + jsonId: 13 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js + rawEntryId: /uri-js@4.4.1 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: '' + pnpmLockfilePath: pnpm-lock.yaml + pnpmfilePath: .pnpmfile.cjs + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap new file mode 100644 index 00000000000..e2683f0e50d --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap @@ -0,0 +1,287 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-edge-cases-v9.0 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: mime-db@1.54.0 + name: mime-db + originalSpecifier: ^1.52.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + versionPath: 1.54.0 + - dependencyKind: dev + entryId: color-string@2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: dev-dependencies' + entryId: project:packages/dev-dependencies + entryPackageName: dev-dependencies + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: packages/dev-dependencies + rawEntryId: packages/dev-dependencies + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: color@5.0.2 + name: color + originalSpecifier: ^5.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 5.0.2 + displayText: 'Project: duplicate (packages/duplicate-1/duplicate)' + entryId: project:packages/duplicate-1/duplicate + entryPackageName: duplicate (packages/duplicate-1/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: packages/duplicate-1/duplicate + rawEntryId: packages/duplicate-1/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: color-string@2.1.2 + name: color-string + originalSpecifier: ^2.1.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: 'Project: duplicate (packages/duplicate-2/duplicate)' + entryId: project:packages/duplicate-2/duplicate + entryPackageName: duplicate (packages/duplicate-2/duplicate) + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: packages/duplicate-2/duplicate + rawEntryId: packages/duplicate-2/duplicate + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: has-symbols@1.0.2 + name: has-symbols + originalSpecifier: 1.0.2 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 1.0.2 + - dependencyKind: regular + entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder + name: target-folder + originalSpecifier: link:packages/link-specifier/target-folder + peerDependencyMeta: {} + versionPath: link:packages/link-specifier/target-folder + displayText: 'Project: linker' + entryId: project:packages/link-specifier/linker + entryPackageName: linker + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: packages/link-specifier/linker + rawEntryId: packages/link-specifier/linker + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: address@1.2.2 + name: address + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.2.2 + - dependencyKind: regular + entryId: uri-js@4.4.1 + name: uri-js + originalSpecifier: ^4.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 13 + versionPath: 4.4.1 + displayText: 'Project: pnpmfile-transforms' + entryId: project:packages/pnpmfile-transforms + entryPackageName: pnpmfile-transforms + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: packages/pnpmfile-transforms + rawEntryId: packages/pnpmfile-transforms + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: [] + displayText: address 1.2.2 + entryId: address@1.2.2 + entryPackageName: address + entryPackageVersion: 1.2.2 + entrySuffix: '' + jsonId: 5 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address + rawEntryId: address@1.2.2 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: color-name@2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-convert 3.1.2 + entryId: color-convert@3.1.2 + entryPackageName: color-convert + entryPackageVersion: 3.1.2 + entrySuffix: '' + jsonId: 6 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert + rawEntryId: color-convert@3.1.2 + referrerJsonIds: + - 9 + transitivePeerDependencies: [] + - dependencies: [] + displayText: color-name 2.0.2 + entryId: color-name@2.0.2 + entryPackageName: color-name + entryPackageVersion: 2.0.2 + entrySuffix: '' + jsonId: 7 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name + rawEntryId: color-name@2.0.2 + referrerJsonIds: + - 6 + - 8 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: color-name@2.0.2 + name: color-name + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 2.0.2 + displayText: color-string 2.1.2 + entryId: color-string@2.1.2 + entryPackageName: color-string + entryPackageVersion: 2.1.2 + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string + rawEntryId: color-string@2.1.2 + referrerJsonIds: + - 0 + - 2 + - 9 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: color-convert@3.1.2 + name: color-convert + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 3.1.2 + - dependencyKind: regular + entryId: color-string@2.1.2 + name: color-string + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 2.1.2 + displayText: color 5.0.2 + entryId: color@5.0.2 + entryPackageName: color + entryPackageVersion: 5.0.2 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color + rawEntryId: color@5.0.2 + referrerJsonIds: + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: '' + name: target-folder + originalSpecifier: '' + peerDependencyMeta: {} + versionPath: link:link-specifier/target-folder + displayText: has-symbols 1.0.2 + entryId: has-symbols@1.0.2 + entryPackageName: has-symbols + entryPackageVersion: 1.0.2 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols + rawEntryId: has-symbols@1.0.2 + referrerJsonIds: + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: mime-db 1.54.0 + entryId: mime-db@1.54.0 + entryPackageName: mime-db + entryPackageVersion: 1.54.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db + rawEntryId: mime-db@1.54.0 + referrerJsonIds: + - 0 + transitivePeerDependencies: [] + - dependencies: [] + displayText: punycode 2.3.1 + entryId: punycode@2.3.1 + entryPackageName: punycode + entryPackageVersion: 2.3.1 + entrySuffix: '' + jsonId: 12 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode + rawEntryId: punycode@2.3.1 + referrerJsonIds: + - 13 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: punycode@2.3.1 + name: punycode + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + versionPath: 2.3.1 + displayText: uri-js 4.4.1 + entryId: uri-js@4.4.1 + entryPackageName: uri-js + entryPackageVersion: 4.4.1 + entrySuffix: '' + jsonId: 13 + kind: 2 + packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js + rawEntryId: uri-js@4.4.1 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: '' + pnpmLockfilePath: pnpm-lock.yaml + pnpmfilePath: .pnpmfile.cjs + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap new file mode 100644 index 00000000000..804e1219938 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap @@ -0,0 +1,315 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + displayText: 'Project: a' + entryId: project:projects/a + entryPackageName: a + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: projects/a + rawEntryId: ../../projects/a + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + - dependencyKind: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + versionPath: 2.0.0 + displayText: 'Project: b' + entryId: project:projects/b + entryPackageName: b + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: projects/b + rawEntryId: ../../projects/b + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0 + name: '@rushstack/k' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 1.0.0_@rushstack+m@1.0.0 + - dependencyKind: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + originalSpecifier: ~1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 1.0.0 + displayText: 'Project: c' + entryId: project:projects/c + entryPackageName: c + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: projects/c + rawEntryId: ../../projects/c + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + name: '@rushstack/j' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.0.0_@rushstack+n@2.0.0 + - dependencyKind: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + versionPath: 2.0.0 + displayText: 'Project: d' + entryId: project:projects/d + entryPackageName: d + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: projects/d + rawEntryId: ../../projects/d + referrerJsonIds: + - 0 + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/n/3.0.0 + name: '@rushstack/n' + originalSpecifier: ^3.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + versionPath: 3.0.0 + displayText: 'Project: e' + entryId: project:projects/e + entryPackageName: e + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: projects/e + rawEntryId: ../../projects/e + referrerJsonIds: + - 2 + - 3 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu + name: '@rushstack/k' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 1.0.0_wxpgugna4ivthu7yyu4fmciltu + - dependencyKind: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 1.0.0 + displayText: '@rushstack/j 1.0.0 (@rushstack+n@2.0.0)' + entryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + entryPackageName: '@rushstack/j' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+n@2.0.0' + jsonId: 5 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+j@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/j + rawEntryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + referrerJsonIds: + - 3 + transitivePeerDependencies: + - '@rushstack/n' + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0 + name: '@rushstack/l' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 1.0.0_@rushstack+m@1.0.0 + displayText: '@rushstack/k 1.0.0 (@rushstack+m@1.0.0)' + entryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0 + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+m@1.0.0' + jsonId: 6 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+k@1.0.0_@rushstack+m@1.0.0/node_modules/@rushstack/k + rawEntryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0 + referrerJsonIds: + - 2 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu + name: '@rushstack/l' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 1.0.0_wxpgugna4ivthu7yyu4fmciltu + displayText: '@rushstack/k 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)' + entryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: wxpgugna4ivthu7yyu4fmciltu + jsonId: 7 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+k@1.0.0_wxpgugna4ivthu7yyu4fmciltu/node_modules/@rushstack/k + rawEntryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu + referrerJsonIds: + - 5 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyKind: peer + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + originalSpecifier: ^1.0.0 + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: 1.0.0 + versionPath: 1.0.0 + displayText: '@rushstack/l 1.0.0 (@rushstack+m@1.0.0)' + entryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0 + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+m@1.0.0' + jsonId: 8 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+l@1.0.0_@rushstack+m@1.0.0/node_modules/@rushstack/l + rawEntryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0 + referrerJsonIds: + - 6 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: peer + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + originalSpecifier: ^1.0.0 + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: 1.0.0 + versionPath: 1.0.0 + - dependencyKind: peer + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: 2.0.0 + versionPath: 2.0.0 + displayText: '@rushstack/l 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)' + entryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: wxpgugna4ivthu7yyu4fmciltu + jsonId: 9 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+l@1.0.0_wxpgugna4ivthu7yyu4fmciltu/node_modules/@rushstack/l + rawEntryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu + referrerJsonIds: + - 7 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/m 1.0.0' + entryId: /@rushstack/m/1.0.0 + entryPackageName: '@rushstack/m' + entryPackageVersion: 1.0.0 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m + rawEntryId: /@rushstack/m/1.0.0 + referrerJsonIds: + - 2 + - 5 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 2.0.0' + entryId: /@rushstack/n/2.0.0 + entryPackageName: '@rushstack/n' + entryPackageVersion: 2.0.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/2.0.0 + referrerJsonIds: + - 1 + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 3.0.0' + entryId: /@rushstack/n/3.0.0 + entryPackageName: '@rushstack/n' + entryPackageVersion: 3.0.0 + entrySuffix: '' + jsonId: 12 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/3.0.0 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: common/temp + pnpmLockfilePath: common/temp/pnpm-lock.yaml + pnpmfilePath: common/temp/.pnpmfile.cjs + rushConfig: + rushPnpmfilePath: common/config/.pnpmfile.cjs + rushVersion: 5.83.3 + subspaceName: '' + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap new file mode 100644 index 00000000000..f53e290cbcd --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap @@ -0,0 +1,274 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + displayText: 'Project: a' + entryId: project:projects/a + entryPackageName: a + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: projects/a + rawEntryId: ../../projects/a + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + - dependencyKind: regular + entryId: /@rushstack/n@2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 2.0.0 + displayText: 'Project: b' + entryId: project:projects/b + entryPackageName: b + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: projects/b + rawEntryId: ../../projects/b + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/k' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: /@rushstack/m@1.0.0 + name: '@rushstack/m' + originalSpecifier: ~1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 1.0.0 + displayText: 'Project: c' + entryId: project:projects/c + entryPackageName: c + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: projects/c + rawEntryId: ../../projects/c + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: /@rushstack/j@1.0.0(@rushstack/n@2.0.0) + name: '@rushstack/j' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.0.0(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: /@rushstack/n@2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 2.0.0 + displayText: 'Project: d' + entryId: project:projects/d + entryPackageName: d + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: projects/d + rawEntryId: ../../projects/d + referrerJsonIds: + - 0 + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/n@3.0.0 + name: '@rushstack/n' + originalSpecifier: ^3.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 3.0.0 + displayText: 'Project: e' + entryId: project:projects/e + entryPackageName: e + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: projects/e + rawEntryId: ../../projects/e + referrerJsonIds: + - 2 + - 3 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/k' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: /@rushstack/m@1.0.0 + name: '@rushstack/m' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 1.0.0 + displayText: '@rushstack/j 1.0.0 [@rushstack/n@2.0.0]' + entryId: /@rushstack/j@1.0.0(@rushstack/n@2.0.0) + entryPackageName: '@rushstack/j' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/n@2.0.0' + jsonId: 5 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+j@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/j + rawEntryId: /@rushstack/j@1.0.0(@rushstack/n@2.0.0) + referrerJsonIds: + - 3 + transitivePeerDependencies: + - '@rushstack/n' + - dependencies: + - dependencyKind: regular + entryId: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/l' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + displayText: '@rushstack/k 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]' + entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0' + jsonId: 6 + kind: 2 + packageJsonFolderPath: >- + common/temp/node_modules/.pnpm/@rushstack+k@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/k + rawEntryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + referrerJsonIds: + - 2 + - 5 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyKind: peer + entryId: /@rushstack/m@1.0.0 + name: '@rushstack/m' + originalSpecifier: ^1.0.0 + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: 1.0.0 + versionPath: 1.0.0 + - dependencyKind: peer + entryId: /@rushstack/n@2.0.0 + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: 2.0.0 + versionPath: 2.0.0 + displayText: '@rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]' + entryId: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0' + jsonId: 7 + kind: 2 + packageJsonFolderPath: >- + common/temp/node_modules/.pnpm/@rushstack+l@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/l + rawEntryId: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + referrerJsonIds: + - 6 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/m 1.0.0' + entryId: /@rushstack/m@1.0.0 + entryPackageName: '@rushstack/m' + entryPackageVersion: 1.0.0 + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m + rawEntryId: /@rushstack/m@1.0.0 + referrerJsonIds: + - 2 + - 5 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 2.0.0' + entryId: /@rushstack/n@2.0.0 + entryPackageName: '@rushstack/n' + entryPackageVersion: 2.0.0 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n@2.0.0 + referrerJsonIds: + - 1 + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 3.0.0' + entryId: /@rushstack/n@3.0.0 + entryPackageName: '@rushstack/n' + entryPackageVersion: 3.0.0 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n@3.0.0 + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: common/temp + pnpmLockfilePath: common/temp/pnpm-lock.yaml + pnpmfilePath: common/temp/.pnpmfile.cjs + rushConfig: + rushPnpmfilePath: common/config/.pnpmcfile.cjs + rushVersion: 5.158.1 + subspaceName: '' + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap new file mode 100644 index 00000000000..852a55ba2d2 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap @@ -0,0 +1,274 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-website-sample-1-v9.0 loads a workspace 1`] = ` +"entries: + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + displayText: 'Project: a' + entryId: project:projects/a + entryPackageName: a + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: projects/a + rawEntryId: ../../projects/a + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/d + name: '@rushstack/d' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 3 + versionPath: link:../d + - dependencyKind: regular + entryId: '@rushstack/n@2.0.0' + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 2.0.0 + displayText: 'Project: b' + entryId: project:projects/b + entryPackageName: b + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: projects/b + rawEntryId: ../../projects/b + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + name: '@rushstack/k' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: '@rushstack/m@1.0.0' + name: '@rushstack/m' + originalSpecifier: ~1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 1.0.0 + displayText: 'Project: c' + entryId: project:projects/c + entryPackageName: c + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: projects/c + rawEntryId: ../../projects/c + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: project:projects/e + name: '@rushstack/e' + originalSpecifier: workspace:* + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + versionPath: link:../e + - dependencyKind: regular + entryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)' + name: '@rushstack/j' + originalSpecifier: ^1.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + versionPath: 1.0.0(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: '@rushstack/n@2.0.0' + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + versionPath: 2.0.0 + displayText: 'Project: d' + entryId: project:projects/d + entryPackageName: d + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: projects/d + rawEntryId: ../../projects/d + referrerJsonIds: + - 0 + - 1 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: '@rushstack/n@3.0.0' + name: '@rushstack/n' + originalSpecifier: ^3.0.0 + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + versionPath: 3.0.0 + displayText: 'Project: e' + entryId: project:projects/e + entryPackageName: e + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: projects/e + rawEntryId: ../../projects/e + referrerJsonIds: + - 2 + - 3 + transitivePeerDependencies: [] + - dependencies: + - dependencyKind: regular + entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + name: '@rushstack/k' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyKind: regular + entryId: '@rushstack/m@1.0.0' + name: '@rushstack/m' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + versionPath: 1.0.0 + displayText: '@rushstack/j 1.0.0 [@rushstack/n@2.0.0]' + entryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)' + entryPackageName: '@rushstack/j' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/n@2.0.0' + jsonId: 5 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+j@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/j + rawEntryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)' + referrerJsonIds: + - 3 + transitivePeerDependencies: + - '@rushstack/n' + - dependencies: + - dependencyKind: regular + entryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + name: '@rushstack/l' + originalSpecifier: '' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + displayText: '@rushstack/k 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]' + entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0' + jsonId: 6 + kind: 2 + packageJsonFolderPath: >- + common/temp/node_modules/.pnpm/@rushstack+k@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/k + rawEntryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + referrerJsonIds: + - 2 + - 5 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyKind: peer + entryId: '@rushstack/m@1.0.0' + name: '@rushstack/m' + originalSpecifier: ^1.0.0 + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: 1.0.0 + versionPath: 1.0.0 + - dependencyKind: peer + entryId: '@rushstack/n@2.0.0' + name: '@rushstack/n' + originalSpecifier: ^2.0.0 + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: 2.0.0 + versionPath: 2.0.0 + displayText: '@rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]' + entryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0' + jsonId: 7 + kind: 2 + packageJsonFolderPath: >- + common/temp/node_modules/.pnpm/@rushstack+l@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/l + rawEntryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)' + referrerJsonIds: + - 6 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/m 1.0.0' + entryId: '@rushstack/m@1.0.0' + entryPackageName: '@rushstack/m' + entryPackageVersion: 1.0.0 + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m + rawEntryId: '@rushstack/m@1.0.0' + referrerJsonIds: + - 2 + - 5 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 2.0.0' + entryId: '@rushstack/n@2.0.0' + entryPackageName: '@rushstack/n' + entryPackageVersion: 2.0.0 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n + rawEntryId: '@rushstack/n@2.0.0' + referrerJsonIds: + - 1 + - 3 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 3.0.0' + entryId: '@rushstack/n@3.0.0' + entryPackageName: '@rushstack/n' + entryPackageVersion: 3.0.0 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n + rawEntryId: '@rushstack/n@3.0.0' + referrerJsonIds: + - 4 + transitivePeerDependencies: [] +workspace: + pnpmLockfileFolder: common/temp + pnpmLockfilePath: common/temp/pnpm-lock.yaml + pnpmfilePath: common/temp/.pnpmfile.cjs + rushConfig: + rushPnpmfilePath: common/config/.pnpmcfile.cjs + rushVersion: 5.158.1 + subspaceName: '' + workspaceRootFullPath: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/PnpmfileRunner/.pnpmfile.cjs b/apps/lockfile-explorer/src/graph/test/fixtures/PnpmfileRunner/.pnpmfile.cjs new file mode 100644 index 00000000000..d7998d79e50 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/PnpmfileRunner/.pnpmfile.cjs @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = { + hooks: { + readPackage + } +}; + +/** + * This hook is invoked during installation before a package's dependencies + * are selected. + * The `packageJson` parameter is the deserialized package.json + * contents for the package that is about to be installed. + * The `context` parameter provides a log() function. + * The return value is the updated object. + */ +function readPackage(packageJson, context) { + if (packageJson.name === '@types/karma') { + context.log('Fixed up dependencies for @types/karma'); + packageJson.dependencies['log4js'] = '0.6.38'; + } + + return packageJson; +} diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md new file mode 100644 index 00000000000..6e71f8e1492 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md @@ -0,0 +1,7 @@ +# fixtures/edge-cases + +This test fixture is a PNPM workspace crafted to reproduce interesting edge cases in the `lfxGraphLoader` algorithm. + +The lockfiles were built from this repistory: + +https://github.com/octogonz/lockfile-explorer-edge-cases diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml new file mode 100644 index 00000000000..73c960a6c85 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml @@ -0,0 +1,122 @@ +lockfileVersion: 5.4 + +importers: + packages/dev-dependencies: + specifiers: + color-string: ^2.1.2 + mime-db: ^1.52.0 + optionalDependencies: + mime-db: 1.54.0 + devDependencies: + color-string: 2.1.2 + + packages/duplicate-1/duplicate: + specifiers: + color: ^5.0.2 + dependencies: + color: 5.0.2 + + packages/duplicate-2/duplicate: + specifiers: + color-string: ^2.1.2 + dependencies: + color-string: 2.1.2 + + packages/link-specifier/linker: + specifiers: + has-symbols: 1.0.2 + target-folder: link:packages/link-specifier/target-folder + dependencies: + has-symbols: 1.0.2 + target-folder: link:packages/link-specifier/target-folder + + packages/pnpmfile-transforms: + specifiers: + address: ^1.0.0 + uri-js: ^4.0.0 + dependencies: + address: 1.2.2 + uri-js: 4.4.1 + +packages: + /address/1.2.2: + resolution: + { + integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== + } + engines: { node: '>= 10.0.0' } + dev: false + + /color-convert/3.1.2: + resolution: + { + integrity: sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg== + } + engines: { node: '>=14.6' } + dependencies: + color-name: 2.0.2 + dev: false + + /color-name/2.0.2: + resolution: + { + integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A== + } + engines: { node: '>=12.20' } + + /color-string/2.1.2: + resolution: + { + integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA== + } + engines: { node: '>=18' } + dependencies: + color-name: 2.0.2 + + /color/5.0.2: + resolution: + { + integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA== + } + engines: { node: '>=18' } + dependencies: + color-convert: 3.1.2 + color-string: 2.1.2 + dev: false + + /has-symbols/1.0.2: + resolution: + { + integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + } + engines: { node: '>= 0.4' } + dependencies: + target-folder: link:link-specifier/target-folder + dev: false + + /mime-db/1.54.0: + resolution: + { + integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + } + engines: { node: '>= 0.6' } + requiresBuild: true + dev: false + optional: true + + /punycode/2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + } + engines: { node: '>=6' } + dev: false + + /uri-js/4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + } + dependencies: + punycode: 2.3.1 + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml new file mode 100644 index 00000000000..97159b9ae54 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml @@ -0,0 +1,129 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + packages/dev-dependencies: + optionalDependencies: + mime-db: + specifier: ^1.52.0 + version: 1.54.0 + devDependencies: + color-string: + specifier: ^2.1.2 + version: 2.1.2 + + packages/duplicate-1/duplicate: + dependencies: + color: + specifier: ^5.0.2 + version: 5.0.2 + + packages/duplicate-2/duplicate: + dependencies: + color-string: + specifier: ^2.1.2 + version: 2.1.2 + + packages/link-specifier/linker: + dependencies: + has-symbols: + specifier: 1.0.2 + version: 1.0.2 + target-folder: + specifier: link:packages/link-specifier/target-folder + version: link:packages/link-specifier/target-folder + + packages/pnpmfile-transforms: + dependencies: + address: + specifier: ^1.0.0 + version: 1.2.2 + uri-js: + specifier: ^4.0.0 + version: 4.4.1 + +packages: + /address@1.2.2: + resolution: + { + integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== + } + engines: { node: '>= 10.0.0' } + dev: false + + /color-convert@3.1.2: + resolution: + { + integrity: sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg== + } + engines: { node: '>=14.6' } + dependencies: + color-name: 2.0.2 + dev: false + + /color-name@2.0.2: + resolution: + { + integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A== + } + engines: { node: '>=12.20' } + + /color-string@2.1.2: + resolution: + { + integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA== + } + engines: { node: '>=18' } + dependencies: + color-name: 2.0.2 + + /color@5.0.2: + resolution: + { + integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA== + } + engines: { node: '>=18' } + dependencies: + color-convert: 3.1.2 + color-string: 2.1.2 + dev: false + + /has-symbols@1.0.2: + resolution: + { + integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + } + engines: { node: '>= 0.4' } + dependencies: + target-folder: link:link-specifier/target-folder + dev: false + + /mime-db@1.54.0: + resolution: + { + integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + } + engines: { node: '>= 0.6' } + requiresBuild: true + dev: false + optional: true + + /punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + } + engines: { node: '>=6' } + dev: false + + /uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + } + dependencies: + punycode: 2.3.1 + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml new file mode 100644 index 00000000000..291e25e638d --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml @@ -0,0 +1,142 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +pnpmfileChecksum: sha256-tednqUPPat9y98NmpwR8320vxu2TlSor2aoYTxiNCdU= + +importers: + packages/dev-dependencies: + devDependencies: + color-string: + specifier: ^2.1.2 + version: 2.1.2 + optionalDependencies: + mime-db: + specifier: ^1.52.0 + version: 1.54.0 + + packages/duplicate-1/duplicate: + dependencies: + color: + specifier: ^5.0.2 + version: 5.0.2 + + packages/duplicate-2/duplicate: + dependencies: + color-string: + specifier: ^2.1.2 + version: 2.1.2 + + packages/link-specifier/linker: + dependencies: + has-symbols: + specifier: 1.0.2 + version: 1.0.2 + target-folder: + specifier: link:packages/link-specifier/target-folder + version: link:packages/link-specifier/target-folder + + packages/pnpmfile-transforms: + dependencies: + address: + specifier: ^1.0.0 + version: 1.2.2 + uri-js: + specifier: ^4.0.0 + version: 4.4.1 + +packages: + address@1.2.2: + resolution: + { + integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== + } + engines: { node: '>= 10.0.0' } + + color-convert@3.1.2: + resolution: + { + integrity: sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg== + } + engines: { node: '>=14.6' } + + color-name@2.0.2: + resolution: + { + integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A== + } + engines: { node: '>=12.20' } + + color-string@2.1.2: + resolution: + { + integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA== + } + engines: { node: '>=18' } + + color@5.0.2: + resolution: + { + integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA== + } + engines: { node: '>=18' } + + has-symbols@1.0.2: + resolution: + { + integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + } + engines: { node: '>= 0.4' } + + mime-db@1.54.0: + resolution: + { + integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + } + engines: { node: '>= 0.6' } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + } + engines: { node: '>=6' } + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + } + +snapshots: + address@1.2.2: {} + + color-convert@3.1.2: + dependencies: + color-name: 2.0.2 + + color-name@2.0.2: {} + + color-string@2.1.2: + dependencies: + color-name: 2.0.2 + + color@5.0.2: + dependencies: + color-convert: 3.1.2 + color-string: 2.1.2 + + has-symbols@1.0.2: + dependencies: + target-folder: link:link-specifier/target-folder + + mime-db@1.54.0: + optional: true + + punycode@2.3.1: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml new file mode 100644 index 00000000000..f1fb1554c57 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml @@ -0,0 +1,134 @@ +lockfileVersion: 5.4 + +importers: + .: + specifiers: {} + + ../../projects/a: + specifiers: + '@rushstack/d': workspace:* + dependencies: + '@rushstack/d': link:../d + + ../../projects/b: + specifiers: + '@rushstack/d': workspace:* + '@rushstack/n': ^2.0.0 + dependencies: + '@rushstack/d': link:../d + '@rushstack/n': 2.0.0 + + ../../projects/c: + specifiers: + '@rushstack/e': workspace:* + '@rushstack/k': ^1.0.0 + '@rushstack/m': ~1.0.0 + dependencies: + '@rushstack/e': link:../e + '@rushstack/k': 1.0.0_@rushstack+m@1.0.0 + '@rushstack/m': 1.0.0 + + ../../projects/d: + specifiers: + '@rushstack/e': workspace:* + '@rushstack/j': ^1.0.0 + '@rushstack/n': ^2.0.0 + dependencies: + '@rushstack/e': link:../e + '@rushstack/j': 1.0.0_@rushstack+n@2.0.0 + '@rushstack/n': 2.0.0 + + ../../projects/e: + specifiers: + '@rushstack/n': ^3.0.0 + dependencies: + '@rushstack/n': 3.0.0 + +packages: + /@rushstack/j/1.0.0_@rushstack+n@2.0.0: + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + dependencies: + '@rushstack/k': 1.0.0_wxpgugna4ivthu7yyu4fmciltu + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + dev: false + + /@rushstack/k/1.0.0_@rushstack+m@1.0.0: + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0_@rushstack+m@1.0.0 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu: + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0_wxpgugna4ivthu7yyu4fmciltu + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/l/1.0.0_@rushstack+m@1.0.0: + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + dev: false + + /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu: + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + '@rushstack/n': 2.0.0 + dev: false + + /@rushstack/m/1.0.0: + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + dev: false + + /@rushstack/n/2.0.0: + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + dev: false + + /@rushstack/n/3.0.0: + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml new file mode 100644 index 00000000000..8a8bc8077ac --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml @@ -0,0 +1,115 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../projects/a: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + + ../../projects/b: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/c: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/k': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': + specifier: ~1.0.0 + version: 1.0.0 + + ../../projects/d: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/j': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/n@2.0.0) + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/e: + dependencies: + '@rushstack/n': + specifier: ^3.0.0 + version: 3.0.0 + +packages: + /@rushstack/j@1.0.0(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + dependencies: + '@rushstack/k': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + dev: false + + /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + '@rushstack/n': 2.0.0 + dev: false + + /@rushstack/m@1.0.0: + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + dev: false + + /@rushstack/n@2.0.0: + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + dev: false + + /@rushstack/n@3.0.0: + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml new file mode 100644 index 00000000000..3318a2a7837 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml @@ -0,0 +1,125 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +pnpmfileChecksum: sha256-La8sfCMI7irxJPTW6u4mJb4vNiyLrXeEbKaXv5G3dL0= + +importers: + .: {} + + ../../projects/a: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + + ../../projects/b: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/c: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/k': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': + specifier: ~1.0.0 + version: 1.0.0 + + ../../projects/d: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/j': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/n@2.0.0) + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/e: + dependencies: + '@rushstack/n': + specifier: ^3.0.0 + version: 3.0.0 + +packages: + '@rushstack/j@1.0.0': + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + + '@rushstack/k@1.0.0': + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + + '@rushstack/l@1.0.0': + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + + '@rushstack/m@1.0.0': + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + + '@rushstack/n@2.0.0': + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + + '@rushstack/n@3.0.0': + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + +snapshots: + '@rushstack/j@1.0.0(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/k': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + + '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/l': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + + '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/m': 1.0.0 + optionalDependencies: + '@rushstack/n': 2.0.0 + + '@rushstack/m@1.0.0': {} + + '@rushstack/n@2.0.0': {} + + '@rushstack/n@3.0.0': {} diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md new file mode 100644 index 00000000000..62e16149c48 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md @@ -0,0 +1,12 @@ +# fixtures/website-sample-1 + +This test fixture uses the `demos/sample-1` branch from the Lockfile Explorer website demos repistory: + +https://github.com/microsoft/lockfile-explorer-demos/tree/demo/sample-1 + +There are three versions of the lockfile: + + +- `pnpm-lock-v5.4-rush.yaml`: The old 5.4 YAML format generated using PNPM 7.16.1 and Rush 5.83.3 from [`ee8a06e`](https://github.com/microsoft/lockfile-explorer-demos/commit/ee8a06e71b63feb806f240de01e57d42854d02af). +- `pnpm-lock-v6.0-rush.yaml`: The 6.0 YAML format generated using PNPM 8.15.9 and Rush 5.158.1 from [`8c3ad3c`](https://github.com/microsoft/lockfile-explorer-demos/commit/8c3ad3cad68a921baa4eb6d264d293e928a962f5) +- `pnpm-lock-v9.0-pnpm.yaml`: For comparison, a lockfile generated using a PNPM 9.15.9 with a plain PNPM workspace (without Rush). Rush doesn't support this format yet. diff --git a/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts new file mode 100644 index 00000000000..3c270234e73 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.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 * as path from 'node:path'; + +import yaml from 'js-yaml'; + +import { FileSystem, NewlineKind } from '@rushstack/node-core-library'; + +import { + type IJsonLfxGraph, + type IJsonLfxWorkspace, + lfxGraphSerializer, + type LfxGraph +} from '../../../build/lfx-shared'; +import * as lfxGraphLoader from '../lfxGraphLoader'; + +const FIXTURES_FOLDER: string = path.resolve(__dirname, '../../../src/graph/test/fixtures/'); + +export async function loadAndSerializeLfxGraphAsync(options: { + workspace: IJsonLfxWorkspace; + lockfilePathUnderFixtures: string; +}): Promise { + const lockfileYaml: string = await FileSystem.readFileAsync( + FIXTURES_FOLDER + options.lockfilePathUnderFixtures, + { convertLineEndings: NewlineKind.Lf } + ); + const lockfileObject = yaml.load(lockfileYaml); + const graph: LfxGraph = lfxGraphLoader.generateLockfileGraph(lockfileObject, options.workspace); + const serializedObject: IJsonLfxGraph = lfxGraphSerializer.serializeToJson(graph); + const serializedYaml: string = yaml.dump(serializedObject, { + noRefs: true, + sortKeys: true, + noCompatMode: true, + lineWidth: 110 + }); + return serializedYaml; +} diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts new file mode 100644 index 00000000000..be8ce686c4a --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'pnpm-lock.yaml', + pnpmLockfileFolder: '', + pnpmfilePath: '.pnpmfile.cjs', + rushConfig: undefined +}; + +describe('lfxGraph-edge-cases-v5.4', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v5.4.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts new file mode 100644 index 00000000000..06ed7a48b0a --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'pnpm-lock.yaml', + pnpmLockfileFolder: '', + pnpmfilePath: '.pnpmfile.cjs', + rushConfig: undefined +}; + +describe('lfxGraph-edge-cases-v6.0', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v6.0.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts new file mode 100644 index 00000000000..2e27262e8c9 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'pnpm-lock.yaml', + pnpmLockfileFolder: '', + pnpmfilePath: '.pnpmfile.cjs', + rushConfig: undefined +}; + +describe('lfxGraph-edge-cases-v9.0', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v9.0.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts new file mode 100644 index 00000000000..874661d6d19 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.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 { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'common/temp/pnpm-lock.yaml', + pnpmLockfileFolder: 'common/temp', + pnpmfilePath: 'common/temp/.pnpmfile.cjs', + rushConfig: { + rushVersion: '5.83.3', + subspaceName: '', + rushPnpmfilePath: 'common/config/.pnpmfile.cjs' + } +}; + +describe('lfxGraph-website-sample-1-v5.4', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v5.4-rush.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts new file mode 100644 index 00000000000..12503e64921 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.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 { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'common/temp/pnpm-lock.yaml', + pnpmLockfileFolder: 'common/temp', + pnpmfilePath: 'common/temp/.pnpmfile.cjs', + rushConfig: { + rushVersion: '5.158.1', + subspaceName: '', + rushPnpmfilePath: 'common/config/.pnpmcfile.cjs' + } +}; + +describe('lfxGraph-website-sample-1-v6.0', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v6.0-rush.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.ts new file mode 100644 index 00000000000..70986c66c8e --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.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 type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'common/temp/pnpm-lock.yaml', + pnpmLockfileFolder: 'common/temp', + pnpmfilePath: 'common/temp/.pnpmfile.cjs', + rushConfig: { + rushVersion: '5.158.1', + subspaceName: '', + rushPnpmfilePath: 'common/config/.pnpmcfile.cjs' + } +}; + +describe('lfxGraph-website-sample-1-v9.0', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({ + // NOTE: Rush does not yet support v9.0; this file was generated by invoking the PNPM CLI manually + // under the common/temp folder. + lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v9.0-rush.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lockfile.test.ts b/apps/lockfile-explorer/src/graph/test/lockfile.test.ts new file mode 100644 index 00000000000..7e1a92a090c --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lockfile.test.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 type { LfxGraphEntry } from '../../../build/lfx-shared'; + +import { TEST_WORKSPACE, TEST_LOCKFILE } from './testLockfile'; +import * as lfxGraphLoader from '../lfxGraphLoader'; + +describe('LockfileGeneration', () => { + it('creates a valid bi-directional graph', () => { + const resolvedPackages = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE, TEST_WORKSPACE).entries; + + // Mapping of all the lockfile entries created by the lockfile + const resolvedPackagesMap: { [key: string]: LfxGraphEntry } = {}; + for (const resolvedPackage of resolvedPackages) { + resolvedPackagesMap[resolvedPackage.entryPackageName] = resolvedPackage; + } + + const exampleLockfileImporter = resolvedPackagesMap.testApp1; + + // Ensure validity of the example lockfile entry + expect(exampleLockfileImporter.rawEntryId).toBe('../../../apps/testApp1'); + expect(exampleLockfileImporter.entryId).toBe('project:apps/testApp1'); + + // Test that dependencies are linked in the importer project + expect(exampleLockfileImporter.dependencies.length).toBe(2); + const [testPackage, testPackage2] = exampleLockfileImporter.dependencies; + expect(testPackage.name).toBe('@testPackage/core'); + expect(testPackage2.name).toBe('@testPackage2/core'); + + // Test linking between the packages and the importer project + expect(testPackage.containingEntry).toBe(exampleLockfileImporter); + expect(testPackage2.containingEntry).toBe(exampleLockfileImporter); + + // Test that the linked packages exists as lockfileEntries + expect(testPackage.resolvedEntry).toBe(resolvedPackagesMap[testPackage.name]); + expect(testPackage2.resolvedEntry).toBe(resolvedPackagesMap[testPackage2.name]); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lockfilePath.test.ts b/apps/lockfile-explorer/src/graph/test/lockfilePath.test.ts new file mode 100644 index 00000000000..008e3b848f1 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lockfilePath.test.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 * as lockfilePath from '../lockfilePath'; + +describe('lockfilePath', () => { + it('getBaseNameOf', () => { + expect(lockfilePath.getBaseNameOf('/a/b/c/d')).toBe('d'); + expect(lockfilePath.getBaseNameOf('.')).toBe('.'); + expect(lockfilePath.getBaseNameOf('')).toBe(''); + + expect(() => lockfilePath.getParentOf('/a/')).toThrowError('has a trailing slash'); + }); + + it('getParentOf', () => { + expect(lockfilePath.getParentOf('a/b/c/d')).toBe('a/b/c'); + expect(lockfilePath.getParentOf('/a/b/c')).toBe('/a/b'); + expect(lockfilePath.getParentOf('/a/b')).toBe('/a'); + expect(lockfilePath.getParentOf('/a')).toBe('/'); + expect(lockfilePath.getParentOf('a')).toBe('.'); + + expect(() => lockfilePath.getParentOf('')).toThrowError('has no parent'); + expect(() => lockfilePath.getParentOf('/')).toThrowError('has no parent'); + expect(() => lockfilePath.getParentOf('.')).toThrowError('has no parent'); + expect(() => lockfilePath.getParentOf('/a/')).toThrowError('has a trailing slash'); + }); + + it('getAbsolute', () => { + expect(lockfilePath.getAbsolute('a/b/c', 'd/e')).toBe('a/b/c/d/e'); + expect(lockfilePath.getAbsolute('/a/b/c', 'd/e')).toBe('/a/b/c/d/e'); + expect(lockfilePath.getAbsolute('/a/b/c', '/d/e')).toBe('/d/e'); + expect(lockfilePath.getAbsolute('a/b/c', '../../f')).toBe('a/f'); + expect(lockfilePath.getAbsolute('a/b/c', '.././/f')).toBe('a/b/f'); + expect(lockfilePath.getAbsolute('a/b/c', '../../..')).toBe('.'); + expect(lockfilePath.getAbsolute('C:/a/b', '../d')).toBe('C:/a/d'); + + // Error case + expect(() => lockfilePath.getAbsolute('a/b/c', '../../../..')).toThrowError('goes above the root folder'); + + // Degenerate cases + expect(lockfilePath.getAbsolute('a/b/c/', 'd/')).toBe('a/b/c/d'); + expect(lockfilePath.getAbsolute('./../c', 'd')).toBe('./../c/d'); + expect(lockfilePath.getAbsolute('C:\\', '\\a')).toBe('C:\\/\\a'); + }); + + it('join', () => { + expect(lockfilePath.join('', 'a')).toBe('a'); + expect(lockfilePath.join('b', '')).toBe('b'); + expect(lockfilePath.join('a', 'b')).toBe('a/b'); + expect(lockfilePath.join('a/', 'b')).toBe('a/b'); + expect(lockfilePath.join('a', '/b')).toBe('a/b'); + expect(lockfilePath.join('a/', '/b')).toBe('a/b'); + + // Degenerate cases + expect(lockfilePath.join('a//', '/b')).toBe('a//b'); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts b/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts new file mode 100644 index 00000000000..a6be195f847 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { lfxGraphSerializer, type LfxGraph } from '../../../build/lfx-shared'; + +import * as lfxGraphLoader from '../lfxGraphLoader'; +import { TEST_WORKSPACE, TEST_LOCKFILE } from './testLockfile'; + +describe('serializeToJson', () => { + it('serializes a simple graph', () => { + const graph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE, TEST_WORKSPACE); + + expect(lfxGraphSerializer.serializeToJson(graph)).toMatchInlineSnapshot(` +Object { + "entries": Array [ + Object { + "dependencies": Array [ + Object { + "dependencyKind": "regular", + "entryId": "/@testPackage/core/1.7.1", + "name": "@testPackage/core", + "originalSpecifier": "1.7.1", + "peerDependencyMeta": Object { + "name": undefined, + "optional": undefined, + "version": undefined, + }, + "resolvedEntryJsonId": 1, + "versionPath": "1.7.1", + }, + Object { + "dependencyKind": "regular", + "entryId": "/@testPackage2/core/1.7.1", + "name": "@testPackage2/core", + "originalSpecifier": "1.7.1", + "peerDependencyMeta": Object { + "name": undefined, + "optional": undefined, + "version": undefined, + }, + "resolvedEntryJsonId": 2, + "versionPath": "1.7.1", + }, + ], + "displayText": "Project: testApp1", + "entryId": "project:apps/testApp1", + "entryPackageName": "testApp1", + "entryPackageVersion": "", + "entrySuffix": "", + "jsonId": 0, + "kind": 1, + "packageJsonFolderPath": "apps/testApp1", + "rawEntryId": "../../../apps/testApp1", + "referrerJsonIds": Array [], + "transitivePeerDependencies": Array [], + }, + Object { + "dependencies": Array [], + "displayText": "@testPackage/core 1.7.1", + "entryId": "/@testPackage/core/1.7.1", + "entryPackageName": "@testPackage/core", + "entryPackageVersion": "1.7.1", + "entrySuffix": "", + "jsonId": 1, + "kind": 2, + "packageJsonFolderPath": "common/temp/my-subspace/node_modules/.pnpm/@testPackage+core@1.7.1/node_modules/@testPackage/core", + "rawEntryId": "/@testPackage/core/1.7.1", + "referrerJsonIds": Array [ + 0, + ], + "transitivePeerDependencies": Array [], + }, + Object { + "dependencies": Array [], + "displayText": "@testPackage2/core 1.7.1", + "entryId": "/@testPackage2/core/1.7.1", + "entryPackageName": "@testPackage2/core", + "entryPackageVersion": "1.7.1", + "entrySuffix": "", + "jsonId": 2, + "kind": 2, + "packageJsonFolderPath": "common/temp/my-subspace/node_modules/.pnpm/@testPackage2+core@1.7.1/node_modules/@testPackage2/core", + "rawEntryId": "/@testPackage2/core/1.7.1", + "referrerJsonIds": Array [ + 0, + ], + "transitivePeerDependencies": Array [], + }, + ], + "workspace": Object { + "pnpmLockfileFolder": "common/temp/my-subspace", + "pnpmLockfilePath": "common/temp/my-subspace/pnpm-lock.yaml", + "pnpmfilePath": "common/temp/my-subspace/.pnpmfile.cjs", + "rushConfig": Object { + "rushPnpmfilePath": "common/config/subspaces/my-subspace/.pnpmfile.cjs", + "rushVersion": "0.0.0", + "subspaceName": "my-subspace", + }, + "workspaceRootFullPath": "/repo", + }, +} +`); + }); + + it('deserializes a simple graph', () => { + const originalGraph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE, TEST_WORKSPACE); + + const serialized: string = JSON.stringify( + lfxGraphSerializer.serializeToJson(originalGraph), + undefined, + 2 + ); + + const deserialized: LfxGraph = lfxGraphSerializer.deserializeFromJson(JSON.parse(serialized)); + + expect(deserialized.entries.length === originalGraph.entries.length); + + const reserialized: string = JSON.stringify( + lfxGraphSerializer.serializeToJson(deserialized), + undefined, + 2 + ); + + expect(reserialized).toEqual(serialized); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/testLockfile.ts b/apps/lockfile-explorer/src/graph/test/testLockfile.ts new file mode 100644 index 00000000000..038133be61c --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/testLockfile.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 type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +export const TEST_WORKSPACE: IJsonLfxWorkspace = { + workspaceRootFullPath: '/repo', + pnpmLockfilePath: 'common/temp/my-subspace/pnpm-lock.yaml', + pnpmLockfileFolder: 'common/temp/my-subspace', + pnpmfilePath: 'common/temp/my-subspace/.pnpmfile.cjs', + rushConfig: { + rushVersion: '0.0.0', + subspaceName: 'my-subspace', + rushPnpmfilePath: 'common/config/subspaces/my-subspace/.pnpmfile.cjs' + } +}; + +export const TEST_LOCKFILE = { + lockfileVersion: 5.4, + importers: { + '.': { + specifiers: {} + }, + '../../../apps/testApp1': { + specifiers: { + '@testPackage/core': '1.7.1', + '@testPackage2/core': '1.7.1' + }, + dependencies: { + '@testPackage/core': '1.7.1', + '@testPackage2/core': '1.7.1' + }, + devDependencies: {} + } + }, + packages: { + '/@testPackage/core/1.7.1': { + resolution: { + integrity: + 'sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg==' + }, + dependencies: {}, + dev: false + }, + '/@testPackage2/core/1.7.1': { + resolution: { + integrity: + 'sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg==' + }, + peerDependencies: {}, + dependencies: {}, + dev: false + } + } +}; diff --git a/apps/lockfile-explorer/src/schemas/lockfile-lint.schema.json b/apps/lockfile-explorer/src/schemas/lockfile-lint.schema.json new file mode 100644 index 00000000000..0e383a91bd1 --- /dev/null +++ b/apps/lockfile-explorer/src/schemas/lockfile-lint.schema.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Lockfile Lint Configuration", + "description": "The lockfile-explorer.json configuration file for lockfile-lint tool.", + "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" + }, + "rules": { + "description": "The rules adopted by Monorepo and the lockfile-lint will help to check.", + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": ["rule", "project", "requiredVersions"], + "properties": { + "rule": { + "description": "Rule name applied to the project.", + "const": "restrict-versions" + }, + "project": { + "description": "Project name.", + "type": "string" + }, + "requiredVersions": { + "description": "List of restrict dependency version.", + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + } + } + } + ] + } + } + } +} diff --git a/apps/lockfile-explorer/src/start-explorer.ts b/apps/lockfile-explorer/src/start-explorer.ts new file mode 100644 index 00000000000..217080ff9d5 --- /dev/null +++ b/apps/lockfile-explorer/src/start-explorer.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. + +import { ExplorerCommandLineParser } from './cli/explorer/ExplorerCommandLineParser'; + +const parser: ExplorerCommandLineParser = new ExplorerCommandLineParser(); + +parser.executeAsync().catch(console.error); // CommandLineParser.executeAsync() should never reject the promise diff --git a/apps/lockfile-explorer/src/start-lint.ts b/apps/lockfile-explorer/src/start-lint.ts new file mode 100644 index 00000000000..f911d04dfde --- /dev/null +++ b/apps/lockfile-explorer/src/start-lint.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. + +import { LintCommandLineParser } from './cli/lint/LintCommandLineParser'; + +const parser: LintCommandLineParser = new LintCommandLineParser(); + +parser.executeAsync().catch(console.error); // CommandLineParser.executeAsync() should never reject the promise diff --git a/apps/lockfile-explorer/src/state/index.ts b/apps/lockfile-explorer/src/state/index.ts new file mode 100644 index 00000000000..481d2812655 --- /dev/null +++ b/apps/lockfile-explorer/src/state/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. + +import type { IJsonLfxWorkspace } from '../../build/lfx-shared'; + +export interface IAppState { + lockfileExplorerProjectRoot: string; + currentWorkingDirectory: string; + projectRoot: string; + pnpmLockfileLocation: string; + pnpmfileLocation: string; + appVersion: string; + debugMode: boolean; + lfxWorkspace: IJsonLfxWorkspace; +} diff --git a/apps/lockfile-explorer/src/test/__snapshots__/help.test.ts.snap b/apps/lockfile-explorer/src/test/__snapshots__/help.test.ts.snap new file mode 100644 index 00000000000..f9a9e3e57eb --- /dev/null +++ b/apps/lockfile-explorer/src/test/__snapshots__/help.test.ts.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI Tool Tests should display help for "lockfile-explorer --help" 1`] = ` +"usage: lockfile-explorer [-h] [-d] [--subspace SUBSPACE_NAME] + +Lockfile Explorer is a desktop app for investigating and solving version +conflicts in a PNPM workspace. + +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 + --subspace SUBSPACE_NAME + Specifies an individual Rush subspace to check. The + default value is \\"default\\". + +For detailed help about a specific command, use: lockfile-explorer + -h +" +`; + +exports[`CLI Tool Tests should display help for "lockfile-lint --help" 1`] = ` +"usage: lockfile-lint [-h] ... + +Lockfile Lint applies configured policies to find and report dependency +issues in your PNPM workspace. + +Positional arguments: + + init Create a new lockfile-lint.json config file + check Check and report dependency issues in your workspace + +Optional arguments: + -h, --help Show this help message and exit. + +For detailed help about a specific command, use: lockfile-lint +-h +" +`; + +exports[`CLI Tool Tests should display help for "lockfile-lint check --help" 1`] = ` +"usage: lockfile-lint check [-h] + +This command applies the policies that are configured in lockfile-lint.json, +reporting any problems found in your PNPM workspace. + +Optional arguments: + -h, --help Show this help message and exit. +" +`; + +exports[`CLI Tool Tests should display help for "lockfile-lint init --help" 1`] = ` +"usage: lockfile-lint init [-h] + +This command initializes a new lockfile-lint.json config file. The created +template file includes source code comments that document the settings. + +Optional arguments: + -h, --help Show this help message and exit. +" +`; diff --git a/apps/lockfile-explorer/src/test/help.test.ts b/apps/lockfile-explorer/src/test/help.test.ts new file mode 100644 index 00000000000..bbfd935f88b --- /dev/null +++ b/apps/lockfile-explorer/src/test/help.test.ts @@ -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 { execSync } from 'node:child_process'; + +describe('CLI Tool Tests', () => { + it('should display help for "lockfile-explorer --help"', () => { + const startOutput = execSync('node lib/start-explorer.js --help').toString(); + expect(startOutput).toMatchSnapshot(); + }); + + it('should display help for "lockfile-lint --help"', () => { + const lintOutput = execSync('node lib/start-lint.js --help').toString(); + expect(lintOutput).toMatchSnapshot(); + }); + + it('should display help for "lockfile-lint init --help"', () => { + const lintOutput = execSync('node lib/start-lint.js init --help').toString(); + expect(lintOutput).toMatchSnapshot(); + }); + + it('should display help for "lockfile-lint check --help"', () => { + const lintOutput = execSync('node lib/start-lint.js check --help').toString(); + expect(lintOutput).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/typings.d.ts b/apps/lockfile-explorer/src/typings.d.ts new file mode 100644 index 00000000000..8cb293272ce --- /dev/null +++ b/apps/lockfile-explorer/src/typings.d.ts @@ -0,0 +1 @@ +declare module '*.json'; diff --git a/apps/lockfile-explorer/src/utils/init.ts b/apps/lockfile-explorer/src/utils/init.ts new file mode 100644 index 00000000000..0fe6c7f9eb6 --- /dev/null +++ b/apps/lockfile-explorer/src/utils/init.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. + +// This function will read the current directory and try to figure out if it's a rush project or regular pnpm workspace +// Currently it will throw error if neither can be determined + +import path from 'node:path'; + +import { FileSystem, Path } from '@rushstack/node-core-library'; +import { RushConfiguration } from '@microsoft/rush-lib/lib/api/RushConfiguration'; +import type { Subspace } from '@microsoft/rush-lib/lib/api/Subspace'; + +import * as lockfilePath from '../graph/lockfilePath'; +import type { IAppState } from '../state'; + +export const init = (options: { + lockfileExplorerProjectRoot: string; + appVersion: string; + debugMode: boolean; + subspaceName: string; +}): Omit => { + const { lockfileExplorerProjectRoot, appVersion, debugMode, subspaceName } = options; + const currentWorkingDirectory: string = path.resolve(process.cwd()); + + let appState: IAppState | undefined; + let currentFolder: string = Path.convertToSlashes(currentWorkingDirectory); + while (currentFolder.includes('/')) { + // Look for a rush.json [rush project] or pnpm-lock.yaml file [regular pnpm workspace] + const rushJsonPath: string = currentFolder + '/rush.json'; + const pnpmLockPath: string = currentFolder + '/pnpm-lock.yaml'; + if (FileSystem.exists(rushJsonPath)) { + console.log('Found a Rush workspace: ', rushJsonPath); + + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonPath); + const subspace: Subspace = rushConfiguration.getSubspace(subspaceName); + const commonTempFolder: string = subspace.getSubspaceTempFolderPath(); + const pnpmLockfileAbsolutePath: string = path.join(commonTempFolder, 'pnpm-lock.yaml'); + + const relativeCommonTempFolder: string = Path.convertToSlashes( + path.relative(currentFolder, subspace.getSubspaceTempFolderPath()) + ); + const pnpmLockfileRelativePath: string = lockfilePath.join(relativeCommonTempFolder, 'pnpm-lock.yaml'); + const pnpmFileRelativePath: string = lockfilePath.join(relativeCommonTempFolder, '.pnpmfile.cjs'); + + const relativeCommonConfigFolder: string = Path.convertToSlashes( + path.relative(currentFolder, subspace.getSubspaceConfigFolderPath()) + ); + const rushPnpmFileRelativePath: string = lockfilePath.join(relativeCommonConfigFolder, '.pnpmfile.cjs'); + + appState = { + currentWorkingDirectory, + appVersion, + debugMode, + lockfileExplorerProjectRoot, + pnpmLockfileLocation: pnpmLockfileAbsolutePath, + pnpmfileLocation: commonTempFolder + '/.pnpmfile.cjs', + projectRoot: currentFolder, + lfxWorkspace: { + workspaceRootFullPath: currentFolder, + pnpmLockfilePath: Path.convertToSlashes(pnpmLockfileRelativePath), + pnpmLockfileFolder: Path.convertToSlashes(path.dirname(pnpmLockfileRelativePath)), + pnpmfilePath: Path.convertToSlashes(pnpmFileRelativePath), + rushConfig: { + rushVersion: rushConfiguration.rushConfigurationJson.rushVersion, + subspaceName: subspaceName ?? '', + rushPnpmfilePath: rushPnpmFileRelativePath + } + } + }; + break; + } else if (FileSystem.exists(pnpmLockPath)) { + appState = { + currentWorkingDirectory, + appVersion, + debugMode, + lockfileExplorerProjectRoot, + pnpmLockfileLocation: currentFolder + '/pnpm-lock.yaml', + pnpmfileLocation: currentFolder + '/.pnpmfile.cjs', + projectRoot: currentFolder, + lfxWorkspace: { + workspaceRootFullPath: currentFolder, + pnpmLockfilePath: Path.convertToSlashes(path.relative(currentFolder, pnpmLockPath)), + pnpmLockfileFolder: '', + pnpmfilePath: '.pnpmfile.cjs', + rushConfig: undefined + } + }; + + break; + } + + currentFolder = currentFolder.substring(0, currentFolder.lastIndexOf('/')); + } + + if (!appState) { + throw new Error('Could not find a Rush or PNPM workspace!'); + } + + return appState; +}; diff --git a/apps/lockfile-explorer/src/utils/shrinkwrap.ts b/apps/lockfile-explorer/src/utils/shrinkwrap.ts new file mode 100644 index 00000000000..12792e3cebd --- /dev/null +++ b/apps/lockfile-explorer/src/utils/shrinkwrap.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. + +import * as dependencyPathLockfilePreV9 from '@pnpm/dependency-path-lockfile-pre-v9'; + +interface IPackageInfo { + name: string; + peersSuffix: string | undefined; + version: string; +} + +export function 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; + return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; +} + +export function parseDependencyPath(shrinkwrapFileMajorVersion: number, newDepPath: string): IPackageInfo { + let dependencyPath: string = newDepPath; + if (shrinkwrapFileMajorVersion === 6) { + dependencyPath = convertLockfileV6DepPathToV5DepPath(newDepPath); + } + const packageInfo: ReturnType = + dependencyPathLockfilePreV9.parse(dependencyPath); + return { + name: packageInfo.name as string, + peersSuffix: packageInfo.peersSuffix, + version: packageInfo.version as string + }; +} + +export function getShrinkwrapFileMajorVersion(lockfileVersion: string | number): number { + let shrinkwrapFileMajorVersion: number; + if (typeof lockfileVersion === 'string') { + const isDotIncluded: boolean = lockfileVersion.includes('.'); + shrinkwrapFileMajorVersion = parseInt( + lockfileVersion.substring(0, isDotIncluded ? lockfileVersion.indexOf('.') : undefined), + 10 + ); + } else if (typeof lockfileVersion === 'number') { + shrinkwrapFileMajorVersion = Math.floor(lockfileVersion); + } else { + shrinkwrapFileMajorVersion = 0; + } + + if (shrinkwrapFileMajorVersion < 5 || shrinkwrapFileMajorVersion > 6) { + throw new Error('The current lockfile version is not supported.'); + } + + return shrinkwrapFileMajorVersion; +} + +export function splicePackageWithVersion( + shrinkwrapFileMajorVersion: number, + dependencyPackageName: string, + dependencyPackageVersion: string +): string { + return `/${dependencyPackageName}${ + shrinkwrapFileMajorVersion === 6 ? '@' : '/' + }${dependencyPackageVersion}`; +} diff --git a/apps/lockfile-explorer/tsconfig.json b/apps/lockfile-explorer/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/lockfile-explorer/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/rundown/.npmignore b/apps/rundown/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/apps/rundown/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/rundown/.vscode/launch.json b/apps/rundown/.vscode/launch.json new file mode 100644 index 00000000000..d0d66e3d08b --- /dev/null +++ b/apps/rundown/.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": "rundown snapshot", + "program": "${workspaceFolder}/lib/start.js", + "args": [ + "snapshot", + "--script", + "./lib/start.js" // <--- your entry point here + ], + "cwd": "${workspaceFolder}/../rush-lib/", // <--- your project folder here + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "rundown inspect", + "program": "${workspaceFolder}/lib/start.js", + "args": [ + "snapshot", + "--script", + "./lib/start.js" // <--- your entry point here + ], + "cwd": "${workspaceFolder}/../rush-lib/", // <--- your project folder here + "sourceMaps": true + } + ] +} \ No newline at end of file diff --git a/apps/rundown/CHANGELOG.json b/apps/rundown/CHANGELOG.json new file mode 100644 index 00000000000..ffd09bf23f8 --- /dev/null +++ b/apps/rundown/CHANGELOG.json @@ -0,0 +1,6363 @@ +{ + "name": "@rushstack/rundown", + "entries": [ + { + "version": "1.2.7", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/rundown_v1.2.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/rundown_v1.2.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/rundown_v1.2.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/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.1.110", + "tag": "@rushstack/rundown_v1.1.110", + "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/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.1.109", + "tag": "@rushstack/rundown_v1.1.109", + "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/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "1.1.108", + "tag": "@rushstack/rundown_v1.1.108", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "1.1.107", + "tag": "@rushstack/rundown_v1.1.107", + "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/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "1.1.106", + "tag": "@rushstack/rundown_v1.1.106", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "1.1.105", + "tag": "@rushstack/rundown_v1.1.105", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "1.1.104", + "tag": "@rushstack/rundown_v1.1.104", + "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/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "1.1.103", + "tag": "@rushstack/rundown_v1.1.103", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "1.1.102", + "tag": "@rushstack/rundown_v1.1.102", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "1.1.101", + "tag": "@rushstack/rundown_v1.1.101", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "1.1.100", + "tag": "@rushstack/rundown_v1.1.100", + "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/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "1.1.99", + "tag": "@rushstack/rundown_v1.1.99", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "1.1.98", + "tag": "@rushstack/rundown_v1.1.98", + "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": "1.1.97", + "tag": "@rushstack/rundown_v1.1.97", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "1.1.96", + "tag": "@rushstack/rundown_v1.1.96", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "1.1.95", + "tag": "@rushstack/rundown_v1.1.95", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "1.1.94", + "tag": "@rushstack/rundown_v1.1.94", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "1.1.93", + "tag": "@rushstack/rundown_v1.1.93", + "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/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "1.1.92", + "tag": "@rushstack/rundown_v1.1.92", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "1.1.91", + "tag": "@rushstack/rundown_v1.1.91", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "1.1.90", + "tag": "@rushstack/rundown_v1.1.90", + "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/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "1.1.89", + "tag": "@rushstack/rundown_v1.1.89", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "1.1.88", + "tag": "@rushstack/rundown_v1.1.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "1.1.87", + "tag": "@rushstack/rundown_v1.1.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "1.1.86", + "tag": "@rushstack/rundown_v1.1.86", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "1.1.85", + "tag": "@rushstack/rundown_v1.1.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "1.1.84", + "tag": "@rushstack/rundown_v1.1.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "1.1.83", + "tag": "@rushstack/rundown_v1.1.83", + "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/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "1.1.82", + "tag": "@rushstack/rundown_v1.1.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "1.1.81", + "tag": "@rushstack/rundown_v1.1.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/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "1.1.80", + "tag": "@rushstack/rundown_v1.1.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/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "1.1.79", + "tag": "@rushstack/rundown_v1.1.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "1.1.78", + "tag": "@rushstack/rundown_v1.1.78", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "1.1.77", + "tag": "@rushstack/rundown_v1.1.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "1.1.76", + "tag": "@rushstack/rundown_v1.1.76", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "1.1.75", + "tag": "@rushstack/rundown_v1.1.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "1.1.74", + "tag": "@rushstack/rundown_v1.1.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "1.1.73", + "tag": "@rushstack/rundown_v1.1.73", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "1.1.72", + "tag": "@rushstack/rundown_v1.1.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "1.1.71", + "tag": "@rushstack/rundown_v1.1.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "1.1.70", + "tag": "@rushstack/rundown_v1.1.70", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "1.1.69", + "tag": "@rushstack/rundown_v1.1.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "1.1.68", + "tag": "@rushstack/rundown_v1.1.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "1.1.67", + "tag": "@rushstack/rundown_v1.1.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "1.1.66", + "tag": "@rushstack/rundown_v1.1.66", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "1.1.65", + "tag": "@rushstack/rundown_v1.1.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "1.1.64", + "tag": "@rushstack/rundown_v1.1.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "1.1.63", + "tag": "@rushstack/rundown_v1.1.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "1.1.62", + "tag": "@rushstack/rundown_v1.1.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "1.1.61", + "tag": "@rushstack/rundown_v1.1.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "1.1.60", + "tag": "@rushstack/rundown_v1.1.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "1.1.59", + "tag": "@rushstack/rundown_v1.1.59", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "1.1.58", + "tag": "@rushstack/rundown_v1.1.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "1.1.57", + "tag": "@rushstack/rundown_v1.1.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "1.1.56", + "tag": "@rushstack/rundown_v1.1.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "1.1.55", + "tag": "@rushstack/rundown_v1.1.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "1.1.54", + "tag": "@rushstack/rundown_v1.1.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "1.1.53", + "tag": "@rushstack/rundown_v1.1.53", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "1.1.52", + "tag": "@rushstack/rundown_v1.1.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "1.1.51", + "tag": "@rushstack/rundown_v1.1.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "1.1.50", + "tag": "@rushstack/rundown_v1.1.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "1.1.49", + "tag": "@rushstack/rundown_v1.1.49", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "1.1.48", + "tag": "@rushstack/rundown_v1.1.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "1.1.47", + "tag": "@rushstack/rundown_v1.1.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "patch": [ + { + "comment": "Eliminate an arbitrary 500ms delay during process shutdown" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "1.1.46", + "tag": "@rushstack/rundown_v1.1.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "1.1.45", + "tag": "@rushstack/rundown_v1.1.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "1.1.44", + "tag": "@rushstack/rundown_v1.1.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "1.1.43", + "tag": "@rushstack/rundown_v1.1.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "1.1.42", + "tag": "@rushstack/rundown_v1.1.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "1.1.41", + "tag": "@rushstack/rundown_v1.1.41", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "1.1.40", + "tag": "@rushstack/rundown_v1.1.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "1.1.39", + "tag": "@rushstack/rundown_v1.1.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "1.1.38", + "tag": "@rushstack/rundown_v1.1.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "1.1.37", + "tag": "@rushstack/rundown_v1.1.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "1.1.36", + "tag": "@rushstack/rundown_v1.1.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "1.1.35", + "tag": "@rushstack/rundown_v1.1.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "1.1.34", + "tag": "@rushstack/rundown_v1.1.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "1.1.33", + "tag": "@rushstack/rundown_v1.1.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "1.1.32", + "tag": "@rushstack/rundown_v1.1.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "1.1.31", + "tag": "@rushstack/rundown_v1.1.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "1.1.30", + "tag": "@rushstack/rundown_v1.1.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "1.1.29", + "tag": "@rushstack/rundown_v1.1.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "1.1.28", + "tag": "@rushstack/rundown_v1.1.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "1.1.27", + "tag": "@rushstack/rundown_v1.1.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "1.1.26", + "tag": "@rushstack/rundown_v1.1.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "1.1.25", + "tag": "@rushstack/rundown_v1.1.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "1.1.24", + "tag": "@rushstack/rundown_v1.1.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "1.1.23", + "tag": "@rushstack/rundown_v1.1.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "1.1.22", + "tag": "@rushstack/rundown_v1.1.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "1.1.21", + "tag": "@rushstack/rundown_v1.1.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "1.1.20", + "tag": "@rushstack/rundown_v1.1.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "1.1.19", + "tag": "@rushstack/rundown_v1.1.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/rundown_v1.1.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/rundown_v1.1.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/rundown_v1.1.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/rundown_v1.1.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/rundown_v1.1.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/rundown_v1.1.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/rundown_v1.1.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/rundown_v1.1.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/rundown_v1.1.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/rundown_v1.1.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/rundown_v1.1.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/rundown_v1.1.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/rundown_v1.1.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/rundown_v1.1.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/rundown_v1.1.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/rundown_v1.1.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/rundown_v1.1.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/rundown_v1.1.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/rundown_v1.1.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "1.0.277", + "tag": "@rushstack/rundown_v1.0.277", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "1.0.276", + "tag": "@rushstack/rundown_v1.0.276", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "1.0.275", + "tag": "@rushstack/rundown_v1.0.275", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "1.0.274", + "tag": "@rushstack/rundown_v1.0.274", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "1.0.273", + "tag": "@rushstack/rundown_v1.0.273", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "1.0.272", + "tag": "@rushstack/rundown_v1.0.272", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "1.0.271", + "tag": "@rushstack/rundown_v1.0.271", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "1.0.270", + "tag": "@rushstack/rundown_v1.0.270", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "1.0.269", + "tag": "@rushstack/rundown_v1.0.269", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "1.0.268", + "tag": "@rushstack/rundown_v1.0.268", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "1.0.267", + "tag": "@rushstack/rundown_v1.0.267", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "1.0.266", + "tag": "@rushstack/rundown_v1.0.266", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "1.0.265", + "tag": "@rushstack/rundown_v1.0.265", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "1.0.264", + "tag": "@rushstack/rundown_v1.0.264", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "1.0.263", + "tag": "@rushstack/rundown_v1.0.263", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "1.0.262", + "tag": "@rushstack/rundown_v1.0.262", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "1.0.261", + "tag": "@rushstack/rundown_v1.0.261", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "1.0.260", + "tag": "@rushstack/rundown_v1.0.260", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "1.0.259", + "tag": "@rushstack/rundown_v1.0.259", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "1.0.258", + "tag": "@rushstack/rundown_v1.0.258", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "1.0.257", + "tag": "@rushstack/rundown_v1.0.257", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "1.0.256", + "tag": "@rushstack/rundown_v1.0.256", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "1.0.255", + "tag": "@rushstack/rundown_v1.0.255", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "1.0.254", + "tag": "@rushstack/rundown_v1.0.254", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "1.0.253", + "tag": "@rushstack/rundown_v1.0.253", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "1.0.252", + "tag": "@rushstack/rundown_v1.0.252", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "1.0.251", + "tag": "@rushstack/rundown_v1.0.251", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "1.0.250", + "tag": "@rushstack/rundown_v1.0.250", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "1.0.249", + "tag": "@rushstack/rundown_v1.0.249", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "1.0.248", + "tag": "@rushstack/rundown_v1.0.248", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "1.0.247", + "tag": "@rushstack/rundown_v1.0.247", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "1.0.246", + "tag": "@rushstack/rundown_v1.0.246", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "1.0.245", + "tag": "@rushstack/rundown_v1.0.245", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "1.0.244", + "tag": "@rushstack/rundown_v1.0.244", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "1.0.243", + "tag": "@rushstack/rundown_v1.0.243", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "1.0.242", + "tag": "@rushstack/rundown_v1.0.242", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "1.0.241", + "tag": "@rushstack/rundown_v1.0.241", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "1.0.240", + "tag": "@rushstack/rundown_v1.0.240", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "1.0.239", + "tag": "@rushstack/rundown_v1.0.239", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "1.0.238", + "tag": "@rushstack/rundown_v1.0.238", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "1.0.237", + "tag": "@rushstack/rundown_v1.0.237", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "1.0.236", + "tag": "@rushstack/rundown_v1.0.236", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "1.0.235", + "tag": "@rushstack/rundown_v1.0.235", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "1.0.234", + "tag": "@rushstack/rundown_v1.0.234", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "1.0.233", + "tag": "@rushstack/rundown_v1.0.233", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "1.0.232", + "tag": "@rushstack/rundown_v1.0.232", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "1.0.231", + "tag": "@rushstack/rundown_v1.0.231", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "1.0.230", + "tag": "@rushstack/rundown_v1.0.230", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "1.0.229", + "tag": "@rushstack/rundown_v1.0.229", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "1.0.228", + "tag": "@rushstack/rundown_v1.0.228", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "1.0.227", + "tag": "@rushstack/rundown_v1.0.227", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "1.0.226", + "tag": "@rushstack/rundown_v1.0.226", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "1.0.225", + "tag": "@rushstack/rundown_v1.0.225", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "1.0.224", + "tag": "@rushstack/rundown_v1.0.224", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "1.0.223", + "tag": "@rushstack/rundown_v1.0.223", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "1.0.222", + "tag": "@rushstack/rundown_v1.0.222", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "1.0.221", + "tag": "@rushstack/rundown_v1.0.221", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "1.0.220", + "tag": "@rushstack/rundown_v1.0.220", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "1.0.219", + "tag": "@rushstack/rundown_v1.0.219", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "1.0.218", + "tag": "@rushstack/rundown_v1.0.218", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "1.0.217", + "tag": "@rushstack/rundown_v1.0.217", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "1.0.216", + "tag": "@rushstack/rundown_v1.0.216", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "1.0.215", + "tag": "@rushstack/rundown_v1.0.215", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "1.0.214", + "tag": "@rushstack/rundown_v1.0.214", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "1.0.213", + "tag": "@rushstack/rundown_v1.0.213", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "1.0.212", + "tag": "@rushstack/rundown_v1.0.212", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "1.0.211", + "tag": "@rushstack/rundown_v1.0.211", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "1.0.210", + "tag": "@rushstack/rundown_v1.0.210", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "1.0.209", + "tag": "@rushstack/rundown_v1.0.209", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "1.0.208", + "tag": "@rushstack/rundown_v1.0.208", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "1.0.207", + "tag": "@rushstack/rundown_v1.0.207", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "1.0.206", + "tag": "@rushstack/rundown_v1.0.206", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "1.0.205", + "tag": "@rushstack/rundown_v1.0.205", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "1.0.204", + "tag": "@rushstack/rundown_v1.0.204", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "1.0.203", + "tag": "@rushstack/rundown_v1.0.203", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "1.0.202", + "tag": "@rushstack/rundown_v1.0.202", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "1.0.201", + "tag": "@rushstack/rundown_v1.0.201", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "1.0.200", + "tag": "@rushstack/rundown_v1.0.200", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "1.0.199", + "tag": "@rushstack/rundown_v1.0.199", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "1.0.198", + "tag": "@rushstack/rundown_v1.0.198", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "1.0.197", + "tag": "@rushstack/rundown_v1.0.197", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "1.0.196", + "tag": "@rushstack/rundown_v1.0.196", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "1.0.195", + "tag": "@rushstack/rundown_v1.0.195", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "1.0.194", + "tag": "@rushstack/rundown_v1.0.194", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "1.0.193", + "tag": "@rushstack/rundown_v1.0.193", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "1.0.192", + "tag": "@rushstack/rundown_v1.0.192", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "1.0.191", + "tag": "@rushstack/rundown_v1.0.191", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "1.0.190", + "tag": "@rushstack/rundown_v1.0.190", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "1.0.189", + "tag": "@rushstack/rundown_v1.0.189", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "1.0.188", + "tag": "@rushstack/rundown_v1.0.188", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "1.0.187", + "tag": "@rushstack/rundown_v1.0.187", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "1.0.186", + "tag": "@rushstack/rundown_v1.0.186", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "1.0.185", + "tag": "@rushstack/rundown_v1.0.185", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "1.0.184", + "tag": "@rushstack/rundown_v1.0.184", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "1.0.183", + "tag": "@rushstack/rundown_v1.0.183", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "1.0.182", + "tag": "@rushstack/rundown_v1.0.182", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "1.0.181", + "tag": "@rushstack/rundown_v1.0.181", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "1.0.180", + "tag": "@rushstack/rundown_v1.0.180", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "1.0.179", + "tag": "@rushstack/rundown_v1.0.179", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "1.0.178", + "tag": "@rushstack/rundown_v1.0.178", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "1.0.177", + "tag": "@rushstack/rundown_v1.0.177", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "1.0.176", + "tag": "@rushstack/rundown_v1.0.176", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "1.0.175", + "tag": "@rushstack/rundown_v1.0.175", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "1.0.174", + "tag": "@rushstack/rundown_v1.0.174", + "date": "Tue, 15 Mar 2022 19:15:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "1.0.173", + "tag": "@rushstack/rundown_v1.0.173", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "1.0.172", + "tag": "@rushstack/rundown_v1.0.172", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "1.0.171", + "tag": "@rushstack/rundown_v1.0.171", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "1.0.170", + "tag": "@rushstack/rundown_v1.0.170", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "1.0.169", + "tag": "@rushstack/rundown_v1.0.169", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "1.0.168", + "tag": "@rushstack/rundown_v1.0.168", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "1.0.167", + "tag": "@rushstack/rundown_v1.0.167", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "1.0.166", + "tag": "@rushstack/rundown_v1.0.166", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "1.0.165", + "tag": "@rushstack/rundown_v1.0.165", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "1.0.164", + "tag": "@rushstack/rundown_v1.0.164", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "1.0.163", + "tag": "@rushstack/rundown_v1.0.163", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "1.0.162", + "tag": "@rushstack/rundown_v1.0.162", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "1.0.161", + "tag": "@rushstack/rundown_v1.0.161", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "1.0.160", + "tag": "@rushstack/rundown_v1.0.160", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "1.0.159", + "tag": "@rushstack/rundown_v1.0.159", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "1.0.158", + "tag": "@rushstack/rundown_v1.0.158", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "1.0.157", + "tag": "@rushstack/rundown_v1.0.157", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "1.0.156", + "tag": "@rushstack/rundown_v1.0.156", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "1.0.155", + "tag": "@rushstack/rundown_v1.0.155", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "1.0.154", + "tag": "@rushstack/rundown_v1.0.154", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "1.0.153", + "tag": "@rushstack/rundown_v1.0.153", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "1.0.152", + "tag": "@rushstack/rundown_v1.0.152", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "1.0.151", + "tag": "@rushstack/rundown_v1.0.151", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "1.0.150", + "tag": "@rushstack/rundown_v1.0.150", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "1.0.149", + "tag": "@rushstack/rundown_v1.0.149", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "1.0.148", + "tag": "@rushstack/rundown_v1.0.148", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "1.0.147", + "tag": "@rushstack/rundown_v1.0.147", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "1.0.146", + "tag": "@rushstack/rundown_v1.0.146", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "1.0.145", + "tag": "@rushstack/rundown_v1.0.145", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "1.0.144", + "tag": "@rushstack/rundown_v1.0.144", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "1.0.143", + "tag": "@rushstack/rundown_v1.0.143", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "1.0.142", + "tag": "@rushstack/rundown_v1.0.142", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "1.0.141", + "tag": "@rushstack/rundown_v1.0.141", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "1.0.140", + "tag": "@rushstack/rundown_v1.0.140", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "1.0.139", + "tag": "@rushstack/rundown_v1.0.139", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "1.0.138", + "tag": "@rushstack/rundown_v1.0.138", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "1.0.137", + "tag": "@rushstack/rundown_v1.0.137", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "1.0.136", + "tag": "@rushstack/rundown_v1.0.136", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "1.0.135", + "tag": "@rushstack/rundown_v1.0.135", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "1.0.134", + "tag": "@rushstack/rundown_v1.0.134", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "1.0.133", + "tag": "@rushstack/rundown_v1.0.133", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "1.0.132", + "tag": "@rushstack/rundown_v1.0.132", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "1.0.131", + "tag": "@rushstack/rundown_v1.0.131", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "1.0.130", + "tag": "@rushstack/rundown_v1.0.130", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "1.0.129", + "tag": "@rushstack/rundown_v1.0.129", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.0.128", + "tag": "@rushstack/rundown_v1.0.128", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "1.0.127", + "tag": "@rushstack/rundown_v1.0.127", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "1.0.126", + "tag": "@rushstack/rundown_v1.0.126", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "1.0.125", + "tag": "@rushstack/rundown_v1.0.125", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "1.0.124", + "tag": "@rushstack/rundown_v1.0.124", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "1.0.123", + "tag": "@rushstack/rundown_v1.0.123", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "1.0.122", + "tag": "@rushstack/rundown_v1.0.122", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "1.0.121", + "tag": "@rushstack/rundown_v1.0.121", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.0.120", + "tag": "@rushstack/rundown_v1.0.120", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "1.0.119", + "tag": "@rushstack/rundown_v1.0.119", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.0.118", + "tag": "@rushstack/rundown_v1.0.118", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.0.117", + "tag": "@rushstack/rundown_v1.0.117", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.0.116", + "tag": "@rushstack/rundown_v1.0.116", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.0.115", + "tag": "@rushstack/rundown_v1.0.115", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.0.114", + "tag": "@rushstack/rundown_v1.0.114", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.0.113", + "tag": "@rushstack/rundown_v1.0.113", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.112", + "tag": "@rushstack/rundown_v1.0.112", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.111", + "tag": "@rushstack/rundown_v1.0.111", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "1.0.110", + "tag": "@rushstack/rundown_v1.0.110", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "1.0.109", + "tag": "@rushstack/rundown_v1.0.109", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "1.0.108", + "tag": "@rushstack/rundown_v1.0.108", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "1.0.107", + "tag": "@rushstack/rundown_v1.0.107", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "1.0.106", + "tag": "@rushstack/rundown_v1.0.106", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "1.0.105", + "tag": "@rushstack/rundown_v1.0.105", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "1.0.104", + "tag": "@rushstack/rundown_v1.0.104", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "1.0.103", + "tag": "@rushstack/rundown_v1.0.103", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "1.0.102", + "tag": "@rushstack/rundown_v1.0.102", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "1.0.101", + "tag": "@rushstack/rundown_v1.0.101", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "1.0.100", + "tag": "@rushstack/rundown_v1.0.100", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "1.0.99", + "tag": "@rushstack/rundown_v1.0.99", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "1.0.98", + "tag": "@rushstack/rundown_v1.0.98", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "1.0.97", + "tag": "@rushstack/rundown_v1.0.97", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "1.0.96", + "tag": "@rushstack/rundown_v1.0.96", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "1.0.95", + "tag": "@rushstack/rundown_v1.0.95", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "1.0.94", + "tag": "@rushstack/rundown_v1.0.94", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "1.0.93", + "tag": "@rushstack/rundown_v1.0.93", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "1.0.92", + "tag": "@rushstack/rundown_v1.0.92", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "1.0.91", + "tag": "@rushstack/rundown_v1.0.91", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "1.0.90", + "tag": "@rushstack/rundown_v1.0.90", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "1.0.89", + "tag": "@rushstack/rundown_v1.0.89", + "date": "Thu, 08 Apr 2021 20:41:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "1.0.88", + "tag": "@rushstack/rundown_v1.0.88", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "1.0.87", + "tag": "@rushstack/rundown_v1.0.87", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "1.0.86", + "tag": "@rushstack/rundown_v1.0.86", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "1.0.85", + "tag": "@rushstack/rundown_v1.0.85", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "1.0.84", + "tag": "@rushstack/rundown_v1.0.84", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "1.0.83", + "tag": "@rushstack/rundown_v1.0.83", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "1.0.82", + "tag": "@rushstack/rundown_v1.0.82", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "1.0.81", + "tag": "@rushstack/rundown_v1.0.81", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "1.0.80", + "tag": "@rushstack/rundown_v1.0.80", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.0.79", + "tag": "@rushstack/rundown_v1.0.79", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.0.78", + "tag": "@rushstack/rundown_v1.0.78", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "1.0.77", + "tag": "@rushstack/rundown_v1.0.77", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "1.0.76", + "tag": "@rushstack/rundown_v1.0.76", + "date": "Wed, 10 Feb 2021 01:31:21 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an error \"process.on() is not a function\" caused by an incorrect import" + }, + { + "comment": "Fix a race condition that sometimes caused an error \"Child process terminated without completing IPC handshake\"" + } + ] + } + }, + { + "version": "1.0.75", + "tag": "@rushstack/rundown_v1.0.75", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "1.0.74", + "tag": "@rushstack/rundown_v1.0.74", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "1.0.73", + "tag": "@rushstack/rundown_v1.0.73", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "1.0.72", + "tag": "@rushstack/rundown_v1.0.72", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "1.0.71", + "tag": "@rushstack/rundown_v1.0.71", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "1.0.70", + "tag": "@rushstack/rundown_v1.0.70", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "1.0.69", + "tag": "@rushstack/rundown_v1.0.69", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "1.0.68", + "tag": "@rushstack/rundown_v1.0.68", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "1.0.67", + "tag": "@rushstack/rundown_v1.0.67", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "1.0.66", + "tag": "@rushstack/rundown_v1.0.66", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "1.0.65", + "tag": "@rushstack/rundown_v1.0.65", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "1.0.64", + "tag": "@rushstack/rundown_v1.0.64", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "1.0.63", + "tag": "@rushstack/rundown_v1.0.63", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "1.0.62", + "tag": "@rushstack/rundown_v1.0.62", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "1.0.61", + "tag": "@rushstack/rundown_v1.0.61", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "1.0.60", + "tag": "@rushstack/rundown_v1.0.60", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "1.0.59", + "tag": "@rushstack/rundown_v1.0.59", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "1.0.58", + "tag": "@rushstack/rundown_v1.0.58", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "1.0.57", + "tag": "@rushstack/rundown_v1.0.57", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "1.0.56", + "tag": "@rushstack/rundown_v1.0.56", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "1.0.55", + "tag": "@rushstack/rundown_v1.0.55", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "1.0.54", + "tag": "@rushstack/rundown_v1.0.54", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "1.0.53", + "tag": "@rushstack/rundown_v1.0.53", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "1.0.52", + "tag": "@rushstack/rundown_v1.0.52", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "1.0.51", + "tag": "@rushstack/rundown_v1.0.51", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "1.0.50", + "tag": "@rushstack/rundown_v1.0.50", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "1.0.49", + "tag": "@rushstack/rundown_v1.0.49", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "1.0.48", + "tag": "@rushstack/rundown_v1.0.48", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "1.0.47", + "tag": "@rushstack/rundown_v1.0.47", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "1.0.46", + "tag": "@rushstack/rundown_v1.0.46", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "1.0.45", + "tag": "@rushstack/rundown_v1.0.45", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "1.0.44", + "tag": "@rushstack/rundown_v1.0.44", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "1.0.43", + "tag": "@rushstack/rundown_v1.0.43", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "1.0.42", + "tag": "@rushstack/rundown_v1.0.42", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "1.0.41", + "tag": "@rushstack/rundown_v1.0.41", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "1.0.40", + "tag": "@rushstack/rundown_v1.0.40", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "1.0.39", + "tag": "@rushstack/rundown_v1.0.39", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "1.0.38", + "tag": "@rushstack/rundown_v1.0.38", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "1.0.37", + "tag": "@rushstack/rundown_v1.0.37", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "1.0.36", + "tag": "@rushstack/rundown_v1.0.36", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "1.0.35", + "tag": "@rushstack/rundown_v1.0.35", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "1.0.34", + "tag": "@rushstack/rundown_v1.0.34", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "1.0.33", + "tag": "@rushstack/rundown_v1.0.33", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "1.0.32", + "tag": "@rushstack/rundown_v1.0.32", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "1.0.31", + "tag": "@rushstack/rundown_v1.0.31", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "1.0.30", + "tag": "@rushstack/rundown_v1.0.30", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "1.0.29", + "tag": "@rushstack/rundown_v1.0.29", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing \"License\" field." + }, + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "1.0.28", + "tag": "@rushstack/rundown_v1.0.28", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "1.0.27", + "tag": "@rushstack/rundown_v1.0.27", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "1.0.26", + "tag": "@rushstack/rundown_v1.0.26", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "1.0.25", + "tag": "@rushstack/rundown_v1.0.25", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "1.0.24", + "tag": "@rushstack/rundown_v1.0.24", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "1.0.23", + "tag": "@rushstack/rundown_v1.0.23", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/rundown_v1.0.22", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/rundown_v1.0.21", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/rundown_v1.0.20", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/rundown_v1.0.19", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/rundown_v1.0.18", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/rundown_v1.0.17", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/rundown_v1.0.16", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/rundown_v1.0.15", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/rundown_v1.0.14", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/rundown_v1.0.13", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/rundown_v1.0.12", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/rundown_v1.0.11", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/rundown_v1.0.10", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/rundown_v1.0.9", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/rundown_v1.0.8", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/rundown_v1.0.7", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/rundown_v1.0.6", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/rundown_v1.0.5", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/rundown_v1.0.4", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/rundown_v1.0.3", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/rundown_v1.0.2", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/rundown_v1.0.1", + "date": "Thu, 20 Aug 2020 04:47:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix incorrect behavior when the \"--args\" parameter was omitted" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/rundown_v1.0.0", + "date": "Thu, 20 Aug 2020 01:17:28 GMT", + "comments": { + "major": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/apps/rundown/CHANGELOG.md b/apps/rundown/CHANGELOG.md new file mode 100644 index 00000000000..831a3f8224b --- /dev/null +++ b/apps/rundown/CHANGELOG.md @@ -0,0 +1,2017 @@ +# Change Log - @rushstack/rundown + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 1.2.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.2.6 +Fri, 21 Nov 2025 16:13:56 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:15 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 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.2.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.1.110 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 1.1.109 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 1.1.108 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 1.1.107 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 1.1.106 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 1.1.105 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 1.1.104 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 1.1.103 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 1.1.102 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 1.1.101 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 1.1.100 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 1.1.99 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 1.1.98 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 1.1.97 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 1.1.96 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 1.1.95 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 1.1.94 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 1.1.93 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 1.1.92 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 1.1.91 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 1.1.90 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 1.1.89 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 1.1.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 1.1.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 1.1.86 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 1.1.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 1.1.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 1.1.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 1.1.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 1.1.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 1.1.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 1.1.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 1.1.78 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 1.1.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 1.1.76 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 1.1.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 1.1.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 1.1.73 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 1.1.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 1.1.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 1.1.70 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 1.1.69 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 1.1.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 1.1.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 1.1.66 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 1.1.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 1.1.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 1.1.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 1.1.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 1.1.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 1.1.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 1.1.59 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 1.1.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 1.1.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 1.1.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 1.1.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 1.1.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 1.1.53 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 1.1.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 1.1.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 1.1.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 1.1.49 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 1.1.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 1.1.47 +Thu, 23 May 2024 02:26:56 GMT + +### Patches + +- Eliminate an arbitrary 500ms delay during process shutdown + +## 1.1.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 1.1.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 1.1.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 1.1.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 1.1.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 1.1.41 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 1.1.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 1.1.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 1.1.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 1.1.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 1.1.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 1.1.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 1.1.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 1.1.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 1.1.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 1.1.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 1.1.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 1.1.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 1.1.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 1.1.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 1.1.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 1.1.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 1.1.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 1.1.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 1.1.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 1.1.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 1.1.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 1.1.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 1.1.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 1.1.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 1.1.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 1.1.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 1.1.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 1.1.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 1.1.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 1.1.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 1.1.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 1.1.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 1.1.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 1.1.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 1.1.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 1.1.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 1.1.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 1.1.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 1.1.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 1.1.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 1.1.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 1.0.277 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 1.0.276 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 1.0.275 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 1.0.274 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 1.0.273 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 1.0.272 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 1.0.271 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 1.0.270 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 1.0.269 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 1.0.268 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 1.0.267 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 1.0.266 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 1.0.265 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 1.0.264 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 1.0.263 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 1.0.262 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 1.0.261 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 1.0.260 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 1.0.259 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 1.0.258 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 1.0.257 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 1.0.256 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 1.0.255 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 1.0.254 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 1.0.253 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 1.0.252 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 1.0.251 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 1.0.250 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 1.0.249 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 1.0.248 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 1.0.247 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 1.0.246 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 1.0.245 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 1.0.244 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 1.0.243 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 1.0.242 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 1.0.241 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 1.0.240 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 1.0.239 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 1.0.238 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 1.0.237 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 1.0.236 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 1.0.235 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 1.0.234 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 1.0.233 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 1.0.232 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 1.0.231 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 1.0.230 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 1.0.229 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 1.0.228 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 1.0.227 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 1.0.226 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 1.0.225 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 1.0.224 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 1.0.223 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 1.0.222 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 1.0.221 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 1.0.220 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 1.0.219 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.0.218 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.0.217 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.0.216 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.0.215 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.0.214 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.0.213 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.0.212 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 1.0.211 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.0.210 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.0.209 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 1.0.208 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.0.207 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 1.0.206 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.0.205 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 1.0.204 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 1.0.203 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.0.202 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 1.0.201 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 1.0.200 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.0.199 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.0.198 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.0.197 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.0.196 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.0.195 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 1.0.194 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.0.193 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 1.0.192 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 1.0.191 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 1.0.190 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 1.0.189 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.0.188 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.0.187 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.0.186 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.0.185 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 1.0.184 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.0.183 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 1.0.182 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.0.181 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.0.180 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.0.179 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.0.178 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.0.177 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.0.176 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.0.175 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 1.0.174 +Tue, 15 Mar 2022 19:15:54 GMT + +_Version update only_ + +## 1.0.173 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 1.0.172 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 1.0.171 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 1.0.170 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 1.0.169 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.0.168 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.0.167 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 1.0.166 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.0.165 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.0.164 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.0.163 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 1.0.162 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 1.0.161 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.0.160 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 1.0.159 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.0.158 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.0.157 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.0.156 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.0.155 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.0.154 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 1.0.153 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.0.152 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.0.151 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.0.150 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.0.149 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 1.0.148 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.0.147 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 1.0.146 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.0.145 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.0.144 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 1.0.143 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.0.142 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.0.141 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.0.140 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.0.139 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.0.138 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.0.137 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.0.136 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.0.135 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 1.0.134 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.0.133 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.0.132 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.0.131 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 1.0.130 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.0.129 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 1.0.128 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 1.0.127 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.0.126 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.0.125 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.0.124 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.0.123 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.0.122 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.0.121 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.0.120 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.0.119 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.0.118 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.0.117 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.0.116 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.0.115 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.0.114 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.0.113 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.0.112 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 1.0.111 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.0.110 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 1.0.109 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.0.108 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.0.107 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.0.106 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.0.105 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.0.104 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.0.103 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 1.0.102 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.0.101 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.0.100 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 1.0.99 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.0.98 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.0.97 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.0.96 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.0.95 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 1.0.94 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 1.0.93 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 1.0.92 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.0.91 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 1.0.90 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.0.89 +Thu, 08 Apr 2021 20:41:55 GMT + +_Version update only_ + +## 1.0.88 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.0.87 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.0.86 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.0.85 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.0.84 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 1.0.83 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 1.0.82 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.0.81 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.0.80 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 1.0.79 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 1.0.78 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 1.0.77 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 1.0.76 +Wed, 10 Feb 2021 01:31:21 GMT + +### Patches + +- Fix an error "process.on() is not a function" caused by an incorrect import +- Fix a race condition that sometimes caused an error "Child process terminated without completing IPC handshake" + +## 1.0.75 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 1.0.74 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 1.0.73 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 1.0.72 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 1.0.71 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 1.0.70 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 1.0.69 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 1.0.68 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 1.0.67 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 1.0.66 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 1.0.65 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 1.0.64 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 1.0.63 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 1.0.62 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 1.0.61 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 1.0.60 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 1.0.59 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 1.0.58 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 1.0.57 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 1.0.56 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 1.0.55 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 1.0.54 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 1.0.53 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 1.0.52 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 1.0.51 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 1.0.50 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 1.0.49 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 1.0.48 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 1.0.47 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 1.0.46 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 1.0.45 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 1.0.44 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 1.0.43 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 1.0.42 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 1.0.41 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 1.0.40 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 1.0.39 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 1.0.38 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 1.0.37 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 1.0.36 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 1.0.35 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 1.0.34 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 1.0.33 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 1.0.32 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 1.0.31 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 1.0.30 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 1.0.29 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Include missing "License" field. +- Update README.md + +## 1.0.28 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 1.0.27 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 1.0.26 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 1.0.25 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 1.0.24 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 1.0.23 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 1.0.22 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 1.0.21 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 1.0.20 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 1.0.19 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 1.0.18 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 1.0.17 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 1.0.16 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 1.0.15 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 1.0.14 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 1.0.13 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 1.0.12 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 1.0.11 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 1.0.10 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 1.0.9 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 1.0.8 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 1.0.7 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 1.0.6 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 1.0.5 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 1.0.4 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 1.0.3 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 1.0.2 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 1.0.1 +Thu, 20 Aug 2020 04:47:08 GMT + +### Patches + +- Fix incorrect behavior when the "--args" parameter was omitted + +## 1.0.0 +Thu, 20 Aug 2020 01:17:28 GMT + +### Breaking changes + +- Initial release + diff --git a/apps/rundown/LICENSE b/apps/rundown/LICENSE new file mode 100644 index 00000000000..291e4216a86 --- /dev/null +++ b/apps/rundown/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rundown + +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/apps/rundown/README.md b/apps/rundown/README.md new file mode 100644 index 00000000000..0de5df263e2 --- /dev/null +++ b/apps/rundown/README.md @@ -0,0 +1,230 @@ +# @rushstack/rundown + +Slow startup times for Node.js commands or services? **Rundown** can invoke a Node.js process and: + +1. **View imported files:** Intercept all `require()` calls and show which paths were loaded. +2. **Find culprits:** Show the chain for `require()` calls for each import, explaining why it was imported. +3. **Detect regressions over time:** Generate a concise "snapshot" report that can be committed to Git. Changes + to this file may indicate potential performance regressions. + + +## Installation + +You can install this tool globally: + +```shell +$ npm install --global @rushstack/rundown + +# View command line help +$ rundown --help +``` + +If you will generate rundown snapshots during your build, it is recommended to install via `devDependencies`: + +```shell +$ cd my-tool +$ npm install @rushstack/rundown --save-dev +``` + + +## Viewing imported files + +Suppose you maintain a small NPM project that is invoked as follows: + +```shell +# The folder where your tool is developed +$ cd my-tool + +# When you invoke "my-tool --my-option 123 --verbose" from the shell, let's suppose that it invokes +# this Node.js command: +$ node lib/start.js --my-option 123 --verbose +``` + +And suppose that your tool's startup time is rather slow, because the code calls `require()` to load many different +NPM packages. We can create a report to see all the imports: + +```shell +# We use "--args" to pass the command-line arguments for "my-tool" +$ rundown inspect --script lib/start.js --args="--my-option 123 --verbose" +``` + +The report may look like this: + +**rundown-inspect.log** +``` +/path/to/my-tool/lib/start.js +/path/to/my-tool/node_modules/at-least-node/index.js +/path/to/my-tool/node_modules/fs-extra/lib/copy-sync/copy-sync.js +/path/to/my-tool/node_modules/fs-extra/lib/copy-sync/index.js +/path/to/my-tool/node_modules/fs-extra/lib/copy/copy.js +/path/to/my-tool/node_modules/fs-extra/lib/copy/index.js +/path/to/my-tool/node_modules/fs-extra/lib/empty/index.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/file.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/index.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/link.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/symlink-paths.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/symlink-type.js +/path/to/my-tool/node_modules/fs-extra/lib/ensure/symlink.js +/path/to/my-tool/node_modules/fs-extra/lib/fs/index.js +/path/to/my-tool/node_modules/fs-extra/lib/index.js +/path/to/my-tool/node_modules/fs-extra/lib/json/jsonfile.js +/path/to/my-tool/node_modules/fs-extra/lib/json/output-json-sync.js +/path/to/my-tool/node_modules/fs-extra/lib/json/output-json.js +/path/to/my-tool/node_modules/fs-extra/lib/mkdirs/index.js +/path/to/my-tool/node_modules/fs-extra/lib/mkdirs/make-dir.js +/path/to/my-tool/node_modules/fs-extra/lib/move-sync/index.js +/path/to/my-tool/node_modules/fs-extra/lib/move-sync/move-sync.js +/path/to/my-tool/node_modules/fs-extra/lib/move/index.js +/path/to/my-tool/node_modules/fs-extra/lib/move/move.js +/path/to/my-tool/node_modules/fs-extra/lib/output/index.js +/path/to/my-tool/node_modules/fs-extra/lib/path-exists/index.js +/path/to/my-tool/node_modules/fs-extra/lib/remove/index.js +/path/to/my-tool/node_modules/fs-extra/lib/remove/rimraf.js +/path/to/my-tool/node_modules/fs-extra/lib/util/stat.js +/path/to/my-tool/node_modules/fs-extra/lib/util/utimes.js +/path/to/my-tool/node_modules/graceful-fs/clone.js +/path/to/my-tool/node_modules/graceful-fs/graceful-fs.js +/path/to/my-tool/node_modules/graceful-fs/legacy-streams.js +/path/to/my-tool/node_modules/graceful-fs/polyfills.js +/path/to/my-tool/node_modules/jsonfile/index.js +/path/to/my-tool/node_modules/jsonfile/utils.js +/path/to/my-tool/node_modules/universalify/index.js +``` + +## Finding callers + +To see how each file is imported, you can add the `--trace-imports` switch. +```shell +# We use "--args" to pass the command-line arguments for "my-tool" +$ rundown inspect --script lib/start.js --args="--my-option 123 --verbose" --trace-imports +``` + +The report now shows more detail: + +**rundown-inspect.log** +``` +. . . +/path/to/my-tool/node_modules/graceful-fs/legacy-streams.js + imported by /path/to/my-tool/node_modules/graceful-fs/graceful-fs.js + imported by /path/to/my-tool/node_modules/fs-extra/lib/fs/index.js + imported by /path/to/my-tool/node_modules/fs-extra/lib/index.js + imported by /path/to/my-tool/lib/start.js + imported by /rundown/lib/launcher.js + +/path/to/my-tool/node_modules/graceful-fs/polyfills.js + imported by /path/to/my-tool/node_modules/graceful-fs/graceful-fs.js + imported by /path/to/my-tool/node_modules/fs-extra/lib/fs/index.js + imported by /path/to/my-tool/node_modules/fs-extra/lib/index.js + imported by /path/to/my-tool/lib/start.js + imported by rundown/lib/launcher.js +. . . +``` + +## Fixing problems + +It may be the case that many of these imports are not actually used. You can avoid preloading them +by converting them to lazy imports using the `Import.lazy()` from +[@rushstack/node-core-library](https://www.npmjs.com/package/@rushstack/node-core-library) +or [import-lazy](https://www.npmjs.com/package/import-lazy). + + +## Generating a snapshot + +To detect future regressions, use the `rundown snapshot` command to write a snapshot file: + +```shell +# We use "--args" to pass the command-line arguments for "my-tool" +$ rundown snapshot --script lib/start.js --args="--my-option 123 --verbose" + +# This file can be committed to Git to track regressions +$ git add rundown-snapshot.log +``` + +The snapshot file format eliminates spurious diffs, by showing only the names of the imported packages. +For local projects in a monorepo, it will show relative paths. Example output: + +**rundown-snapshot.log** +``` +../path/to/monorepo-sibling +at-least-node +fs-extra +graceful-fs +jsonfile +universalify +``` + +## Command-line reference + +``` +usage: rundown [-h] ... + +Detect load time regressions by running an app, tracing require() calls, and +generating a deterministic report + +Positional arguments: + + snapshot Invoke a Node.js script and generate a test snapshot + inspect Invoke a Node.js script and generate detailed diagnostic output + +Optional arguments: + -h, --help Show this help message and exit. + +For detailed help about a specific command, use: rundown -h +``` + +``` +usage: rundown snapshot [-h] -s PATH [-a STRING] [-q] [-i] + +Invoke a Node.js script and generate a test snapshot. This command creates a +concise report that can be added to Git, so that its diff can be used to +detect performance regressions + +Optional arguments: + -h, --help Show this help message and exit. + -s PATH, --script PATH + The path to a .js file that will be the entry point + for the target Node.js process + -a STRING, --args STRING + Specifies command-line arguments to be passed to the + target Node.js process. The value should be a single + text string delimited by spaces. Example: rundown + inspect --scripts ./example.js --args="--flag + --option=123" + -q, --quiet Suppress STDOUT/STDERR for the target Node.js process + -i, --ignore-exit-code + Do not report an error if the target Node.js process + returns a nonzero exit code +``` + +``` +usage: rundown inspect [-h] -s PATH [-a STRING] [-q] [-i] [-t] + +Invoke a Node.js script and generate detailed diagnostic output. This command +is used to inspect performance regressions. + +Optional arguments: + -h, --help Show this help message and exit. + -s PATH, --script PATH + The path to a .js file that will be the entry point + for the target Node.js process + -a STRING, --args STRING + Specifies command-line arguments to be passed to the + target Node.js process. The value should be a single + text string delimited by spaces. Example: rundown + inspect --scripts ./example.js --args="--flag + --option=123" + -q, --quiet Suppress STDOUT/STDERR for the target Node.js process + -i, --ignore-exit-code + Do not report an error if the target Node.js process + returns a nonzero exit code + -t, --trace-imports Reports the call chain for each module path, showing + how it was imported +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/rundown/CHANGELOG.md) - Find + out what's new in the latest version + +Rundown is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/rundown/bin/rundown b/apps/rundown/bin/rundown new file mode 100644 index 00000000000..aee68e80224 --- /dev/null +++ b/apps/rundown/bin/rundown @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js'); diff --git a/apps/rundown/config/rig.json b/apps/rundown/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/rundown/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/rundown/eslint.config.js b/apps/rundown/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/rundown/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/rundown/package.json b/apps/rundown/package.json new file mode 100644 index 00000000000..8f7385feb16 --- /dev/null +++ b/apps/rundown/package.json @@ -0,0 +1,33 @@ +{ + "name": "@rushstack/rundown", + "version": "1.2.7", + "description": "Detect load time regressions by running an app, tracing require() calls, and generating a deterministic report", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/rundown" + }, + "engines": { + "node": ">=10.0.0" + }, + "engineStrict": true, + "homepage": "https://rushstack.io", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "bin": { + "rundown": "./bin/rundown" + }, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "string-argv": "~0.3.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/apps/rundown/src/LauncherTypes.ts b/apps/rundown/src/LauncherTypes.ts new file mode 100644 index 00000000000..734746ba7cf --- /dev/null +++ b/apps/rundown/src/LauncherTypes.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. + +export enum LauncherAction { + Snapshot = 'snapshot', + Inspect = 'inspect' +} + +export interface IIpcTraceRecord { + importedModule: string; + callingModule: string; +} + +export interface IIpcTrace { + id: 'trace'; + records: IIpcTraceRecord[]; +} + +export interface IIpcDone { + id: 'done'; +} + +export type IpcMessage = IIpcTrace | IIpcDone; diff --git a/apps/rundown/src/Rundown.ts b/apps/rundown/src/Rundown.ts new file mode 100644 index 00000000000..9b63ac8438f --- /dev/null +++ b/apps/rundown/src/Rundown.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. + +import * as child_process from 'node:child_process'; +import * as path from 'node:path'; + +import stringArgv from 'string-argv'; + +import { FileSystem, PackageJsonLookup, Sort, Text } from '@rushstack/node-core-library'; + +import type { IpcMessage } from './LauncherTypes'; + +export class Rundown { + // Map from required path --> caller path + private _importedModuleMap: Map = new Map(); + + public async invokeAsync( + scriptPath: string, + args: string | undefined, + quiet: boolean, + ignoreExitCode: boolean + ): Promise { + if (!FileSystem.exists(scriptPath)) { + throw new Error('The specified script path does not exist: ' + scriptPath); + } + const absoluteScriptPath: string = path.resolve(scriptPath); + + const expandedArgs: string[] = args === undefined ? [] : stringArgv(args); + + console.log('Starting process: ' + [absoluteScriptPath, ...expandedArgs].join(' ')); + console.log(); + + // Example process.argv: + // ["path/to/launcher.js", "path/to/target-script.js", "first-target-arg"] + const nodeArgs: string[] = [path.join(__dirname, 'launcher.js'), absoluteScriptPath, ...expandedArgs]; + + await this._spawnLauncherAsync(nodeArgs, quiet, ignoreExitCode); + + if (!quiet) { + console.log(); + } + } + + public writeSnapshotReport(): void { + const reportPath: string = 'rundown-snapshot.log'; + console.log('Writing report file: ' + reportPath); + + const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + const importedPaths: string[] = [...this._importedModuleMap.keys()]; + const importedPackageFolders: Set = new Set(); + + for (const importedPath of importedPaths) { + const importedPackageFolder: string | undefined = + packageJsonLookup.tryGetPackageFolderFor(importedPath); + if (importedPackageFolder) { + if (/[\\/]node_modules[\\/]/i.test(importedPackageFolder)) { + importedPackageFolders.add(path.basename(importedPackageFolder)); + } else { + const relativePath: string = path.relative(process.cwd(), importedPackageFolder); + importedPackageFolders.add(Text.replaceAll(relativePath, '\\', '/')); + } + } else { + // If the importedPath does not belong to an NPM package, then rundown-snapshot.log can ignore it. + // In other words, treat it the same way as the local project's source files. + } + } + + Sort.sortSet(importedPackageFolders); + const data: string = [...importedPackageFolders].join('\n') + '\n'; + + FileSystem.writeFile(reportPath, data); + } + + public writeInspectReport(traceImports: boolean): void { + const reportPath: string = 'rundown-inspect.log'; + console.log('Writing report file: ' + reportPath); + + const importedPaths: string[] = [...this._importedModuleMap.keys()]; + importedPaths.sort(); + + let data: string = ''; + + if (traceImports) { + for (const importedPath of importedPaths) { + data += importedPath + '\n'; + + let current: string = importedPath; + const visited: Set = new Set(); + for (;;) { + const callerPath: string | undefined = this._importedModuleMap.get(current); + if (!callerPath) { + break; + } + if (visited.has(callerPath)) { + break; + } + visited.add(callerPath); + data += ' imported by ' + callerPath + '\n'; + current = callerPath; + } + data += '\n'; + } + } else { + data = importedPaths.join('\n') + '\n'; + } + + FileSystem.writeFile(reportPath, data); + } + + private async _spawnLauncherAsync( + nodeArgs: string[], + quiet: boolean, + ignoreExitCode: boolean + ): Promise { + const childProcess: child_process.ChildProcess = child_process.spawn(process.execPath, nodeArgs, { + stdio: quiet ? ['inherit', 'ignore', 'ignore', 'ipc'] : ['inherit', 'inherit', 'inherit', 'ipc'] + }); + + let completedNormally: boolean = false; + + childProcess.on('message', (message: IpcMessage): void => { + switch (message.id) { + case 'trace': + for (const record of message.records) { + this._importedModuleMap.set(record.importedModule, record.callingModule); + } + break; + case 'done': + completedNormally = true; + break; + default: + throw new Error('Unknown IPC message: ' + JSON.stringify(message)); + } + }); + + await new Promise((resolve, reject) => { + childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null): void => { + if (signal) { + reject(new Error('Child process terminated by ' + signal)); + } else if (exitCode !== 0 && !ignoreExitCode) { + reject(new Error('Child process terminated with exit code ' + exitCode)); + } else if (!completedNormally) { + reject(new Error('Child process terminated without completing IPC handshake')); + } else { + resolve(); + } + }); + }); + } +} diff --git a/apps/rundown/src/cli/BaseReportAction.ts b/apps/rundown/src/cli/BaseReportAction.ts new file mode 100644 index 00000000000..94269535acd --- /dev/null +++ b/apps/rundown/src/cli/BaseReportAction.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + CommandLineAction, + type ICommandLineActionOptions, + type CommandLineStringParameter, + type CommandLineFlagParameter, + type IRequiredCommandLineStringParameter +} from '@rushstack/ts-command-line'; + +export abstract class BaseReportAction extends CommandLineAction { + protected readonly scriptParameter: IRequiredCommandLineStringParameter; + protected readonly argsParameter: CommandLineStringParameter; + protected readonly quietParameter: CommandLineFlagParameter; + protected readonly ignoreExitCodeParameter: CommandLineFlagParameter; + + public constructor(options: ICommandLineActionOptions) { + super(options); + + this.scriptParameter = this.defineStringParameter({ + parameterLongName: '--script', + parameterShortName: '-s', + argumentName: 'PATH', + description: 'The path to a .js file that will be the entry point for the target Node.js process', + required: true + }); + this.argsParameter = this.defineStringParameter({ + parameterLongName: '--args', + parameterShortName: '-a', + argumentName: 'STRING', + description: + 'Specifies command-line arguments to be passed to the target Node.js process. The value' + + ' should be a single text string delimited by spaces.' + + ' Example: rundown inspect --scripts ./example.js --args="--flag --option=123"' + }); + this.quietParameter = this.defineFlagParameter({ + parameterLongName: '--quiet', + parameterShortName: '-q', + description: 'Suppress STDOUT/STDERR for the target Node.js process' + }); + this.ignoreExitCodeParameter = this.defineFlagParameter({ + parameterLongName: '--ignore-exit-code', + parameterShortName: '-i', + description: 'Do not report an error if the target Node.js process returns a nonzero exit code' + }); + } +} diff --git a/apps/rundown/src/cli/InspectAction.ts b/apps/rundown/src/cli/InspectAction.ts new file mode 100644 index 00000000000..9c14086c55e --- /dev/null +++ b/apps/rundown/src/cli/InspectAction.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 type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseReportAction } from './BaseReportAction'; +import { Rundown } from '../Rundown'; + +export class InspectAction extends BaseReportAction { + private readonly _traceParameter: CommandLineFlagParameter; + + public constructor() { + super({ + actionName: 'inspect', + summary: 'Invoke a Node.js script and generate detailed diagnostic output', + documentation: + 'Invoke a Node.js script and generate detailed diagnostic output. This command is used' + + ' to inspect performance regressions.' + }); + + this._traceParameter = this.defineFlagParameter({ + parameterLongName: '--trace-imports', + parameterShortName: '-t', + description: 'Reports the call chain for each module path, showing how it was imported' + }); + } + + protected override async onExecuteAsync(): Promise { + const rundown: Rundown = new Rundown(); + await rundown.invokeAsync( + this.scriptParameter.value, + this.argsParameter.value, + this.quietParameter.value, + this.ignoreExitCodeParameter.value + ); + rundown.writeInspectReport(this._traceParameter.value); + } +} diff --git a/apps/rundown/src/cli/RundownCommandLine.ts b/apps/rundown/src/cli/RundownCommandLine.ts new file mode 100644 index 00000000000..60c054c4eb1 --- /dev/null +++ b/apps/rundown/src/cli/RundownCommandLine.ts @@ -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. + +import { CommandLineParser } from '@rushstack/ts-command-line'; + +import { SnapshotAction } from './SnapshotAction'; +import { InspectAction } from './InspectAction'; + +export class RundownCommandLine extends CommandLineParser { + public constructor() { + super({ + toolFilename: 'rundown', + toolDescription: + 'Detect load time regressions by running an app, tracing require() calls,' + + ' and generating a deterministic report' + }); + + this.addAction(new SnapshotAction()); + this.addAction(new InspectAction()); + } +} diff --git a/apps/rundown/src/cli/SnapshotAction.ts b/apps/rundown/src/cli/SnapshotAction.ts new file mode 100644 index 00000000000..3d5983a6370 --- /dev/null +++ b/apps/rundown/src/cli/SnapshotAction.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 { BaseReportAction } from './BaseReportAction'; +import { Rundown } from '../Rundown'; + +export class SnapshotAction extends BaseReportAction { + public constructor() { + super({ + actionName: 'snapshot', + summary: 'Invoke a Node.js script and generate a test snapshot', + documentation: + 'Invoke a Node.js script and generate a test snapshot. This command creates a concise report that can be' + + ' added to Git, so that its diff can be used to detect performance regressions' + }); + } + + protected override async onExecuteAsync(): Promise { + const rundown: Rundown = new Rundown(); + await rundown.invokeAsync( + this.scriptParameter.value, + this.argsParameter.value, + this.quietParameter.value, + this.ignoreExitCodeParameter.value + ); + rundown.writeSnapshotReport(); + } +} diff --git a/apps/rundown/src/launcher.ts b/apps/rundown/src/launcher.ts new file mode 100644 index 00000000000..0804e456618 --- /dev/null +++ b/apps/rundown/src/launcher.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. + +import moduleApi = require('module'); +import process from 'node:process'; + +import { LauncherAction } from './LauncherTypes'; // "import type" doesn't work with const enums +import type { IIpcTrace, IIpcDone, IIpcTraceRecord } from './LauncherTypes'; + +// The _ipcTraceRecordsBatch will get transmitted when this many items are accumulated +const IPC_BATCH_SIZE: number = 300; + +class Launcher { + public action: LauncherAction = LauncherAction.Inspect; + public targetScriptPathArg: string = ''; + public reportPath: string = ''; + private _importedModules: Set = new Set(); + private _importedModulePaths: Set = new Set(); + private _ipcTraceRecordsBatch: IIpcTraceRecord[] = []; + + public transformArgs(argv: ReadonlyArray): string[] { + let nodeArg: string; + let remainderArgs: string[]; + + // Example process.argv: + // ["path/to/node.exe", "path/to/launcher.js", "path/to/target-script.js", "first-target-arg"] + [nodeArg, , this.targetScriptPathArg, ...remainderArgs] = argv; + + // Example process.argv: + // ["path/to/node.exe", "path/to/target-script.js", "first-target-arg"] + return [nodeArg, this.targetScriptPathArg, ...remainderArgs]; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private static _copyProperties(dst: any, src: any): void { + for (const prop of Object.keys(src)) { + dst[prop] = src[prop]; + } + } + + private _sendIpcTraceBatch(): void { + if (this._ipcTraceRecordsBatch.length > 0) { + const batch: IIpcTraceRecord[] = [...this._ipcTraceRecordsBatch]; + this._ipcTraceRecordsBatch.length = 0; + + process.send!({ + id: 'trace', + records: batch + } as IIpcTrace); + } + } + + public installHook(): void { + const realRequire: typeof moduleApi.Module.prototype.require = moduleApi.Module.prototype.require; + + const importedModules: Set = this._importedModules; // for closure + const importedModulePaths: Set = this._importedModulePaths; // for closure + const ipcTraceRecordsBatch: IIpcTraceRecord[] = this._ipcTraceRecordsBatch; // for closure + const sendIpcTraceBatch: () => void = this._sendIpcTraceBatch.bind(this); // for closure + + function hookedRequire(this: NodeModule, moduleName: string): unknown { + // NOTE: The "this" pointer is the calling NodeModule, so we rely on closure + // variable here. + const callingModuleInfo: NodeModule = this; + + // Paranoidly use "arguments" in case some implementor passes additional undocumented arguments + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const importedModule: unknown = (realRequire as any).apply(callingModuleInfo, arguments); + + if (!importedModules.has(importedModule)) { + importedModules.add(importedModule); + + // Find the info for the imported module + let importedModuleInfo: NodeModule | undefined = undefined; + const children: NodeModule[] = callingModuleInfo.children || []; + for (const child of children) { + if (child.exports === importedModule) { + importedModuleInfo = child; + break; + } + } + + if (importedModuleInfo === undefined) { + // It's a built-in module like "os" + } else { + if (!importedModuleInfo.filename) { + throw new Error('Missing filename for ' + moduleName); + } + + if (!importedModulePaths.has(importedModuleInfo.filename)) { + importedModulePaths.add(importedModuleInfo.filename); + ipcTraceRecordsBatch.push({ + importedModule: importedModuleInfo.filename, + callingModule: callingModuleInfo.filename + }); + if (ipcTraceRecordsBatch.length >= IPC_BATCH_SIZE) { + sendIpcTraceBatch(); + } + } + } + } + + return importedModule; + } + + moduleApi.Module.prototype.require = hookedRequire as NodeJS.Require; + Launcher._copyProperties(hookedRequire, realRequire); + + process.on('exit', () => { + this._sendIpcTraceBatch(); + process.send!({ + id: 'done' + } as IIpcDone); + }); + } +} + +if (!process.send) { + throw new Error('launcher.js must be invoked via IPC'); +} + +const launcher: Launcher = new Launcher(); + +const originalArgv: ReadonlyArray = [...process.argv]; +process.argv.length = 0; +process.argv.push(...launcher.transformArgs(originalArgv)); + +launcher.installHook(); + +// Start the app +require(launcher.targetScriptPathArg); diff --git a/apps/rundown/src/start.ts b/apps/rundown/src/start.ts new file mode 100644 index 00000000000..fa246c0968f --- /dev/null +++ b/apps/rundown/src/start.ts @@ -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. + +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +import { RundownCommandLine } from './cli/RundownCommandLine'; + +const toolVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version; + +console.log(); +console.log(`Rundown ${toolVersion} - https://rushstack.io`); +console.log(); + +const commandLine: RundownCommandLine = new RundownCommandLine(); +commandLine.executeAsync().catch((error) => { + console.error(error); +}); diff --git a/apps/rundown/tsconfig.json b/apps/rundown/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/rundown/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/rush-buildxl/.eslintrc.js b/apps/rush-buildxl/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/apps/rush-buildxl/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/apps/rush-buildxl/.npmignore b/apps/rush-buildxl/.npmignore deleted file mode 100644 index 36e9146f882..00000000000 --- a/apps/rush-buildxl/.npmignore +++ /dev/null @@ -1,22 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- diff --git a/apps/rush-buildxl/README.md b/apps/rush-buildxl/README.md deleted file mode 100644 index aa3dedc31db..00000000000 --- a/apps/rush-buildxl/README.md +++ /dev/null @@ -1,7 +0,0 @@ -## @microsoft/rush-buildxl - -This is an experimental companion package for the Rush tool. See the -[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) -package for details. - -The **rush-buildxl** package provides support for BuildXL in Rush. diff --git a/apps/rush-buildxl/bin/rush-buildxl b/apps/rush-buildxl/bin/rush-buildxl deleted file mode 100644 index 783bb806fce..00000000000 --- a/apps/rush-buildxl/bin/rush-buildxl +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('../lib/start.js') diff --git a/apps/rush-buildxl/config/jest.json b/apps/rush-buildxl/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/apps/rush-buildxl/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/apps/rush-buildxl/gulpfile.js b/apps/rush-buildxl/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/apps/rush-buildxl/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/apps/rush-buildxl/package.json b/apps/rush-buildxl/package.json deleted file mode 100644 index 4f614b0f6c9..00000000000 --- a/apps/rush-buildxl/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@microsoft/rush-buildxl", - "version": "5.22.0", - "description": "An experimental tool that connects Rush and BuildXL", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/rush-buildxl" - }, - "engines": { - "node": ">=5.6.0" - }, - "engineStrict": true, - "homepage": "https://rushjs.io", - "scripts": { - "build": "gulp test --clean" - }, - "bin": { - "rush-buildxl": "./bin/rush-buildxl" - }, - "license": "MIT", - "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@microsoft/rush-lib": "5.22.0", - "@rushstack/ts-command-line": "4.3.12" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/apps/rush-buildxl/src/cli/RushBuildXLCommandLineParser.ts b/apps/rush-buildxl/src/cli/RushBuildXLCommandLineParser.ts deleted file mode 100644 index 2b6ee11c295..00000000000 --- a/apps/rush-buildxl/src/cli/RushBuildXLCommandLineParser.ts +++ /dev/null @@ -1,35 +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 } from '@rushstack/ts-command-line'; -import { Terminal } from '@rushstack/node-core-library'; - -import { CleanAction } from './actions/CleanAction'; -import { GenerateAction } from './actions/GenerateAction'; - -export class RushBuildXLCommandLineParser extends CommandLineParser { - private _terminal: Terminal; - - public constructor(terminal: Terminal) { - super({ - toolFilename: 'rush-buildlx', - toolDescription: 'This experimental tool allows Rush to interact with BuildXL.' - }); - - this._terminal = terminal; - - this.addAction(new CleanAction(this._terminal)); - this.addAction(new GenerateAction(this._terminal)); - } - - protected onDefineParameters(): void { /* no global parameters */ } - - protected onExecute(): Promise { // override - return super.onExecute().catch((error) => { - this._terminal.writeErrorLine(); - this._terminal.writeErrorLine('ERROR: ' + error.message.trim()); - - process.exitCode = 1; - }); - } -} diff --git a/apps/rush-buildxl/src/cli/actions/CleanAction.ts b/apps/rush-buildxl/src/cli/actions/CleanAction.ts deleted file mode 100644 index dc416d068da..00000000000 --- a/apps/rush-buildxl/src/cli/actions/CleanAction.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 * as path from 'path'; -import { CommandLineAction } from '@rushstack/ts-command-line'; -import { - Terminal, - FileSystem -} from '@rushstack/node-core-library'; -import { RushConfiguration } from '@microsoft/rush-lib'; - -export class CleanAction extends CommandLineAction { - private _terminal: Terminal; - - public constructor(terminal: Terminal) { - super({ - actionName: 'clean', - summary: 'Cleans up generated BuildXL configuration for the current Rush repository.', - documentation: 'Cleans up generated BuildXL configuration for the current Rush repository.' - }); - - this._terminal = terminal; - } - - public onDefineParameters(): void { - /* This action doesn't take any parameters*/ - } - - protected async onExecute(): Promise { - const rushConfig: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); - - FileSystem.deleteFolder(path.resolve(rushConfig.commonTempFolder, 'bxl', 'modules')); - - this._terminal.writeLine(`Successfully cleaned BuildXL configuration.`); - } -} diff --git a/apps/rush-buildxl/src/cli/actions/GenerateAction.ts b/apps/rush-buildxl/src/cli/actions/GenerateAction.ts deleted file mode 100644 index 48052120334..00000000000 --- a/apps/rush-buildxl/src/cli/actions/GenerateAction.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CommandLineAction } from '@rushstack/ts-command-line'; -import { Terminal } from '@rushstack/node-core-library'; -import { RushConfiguration } from '@microsoft/rush-lib'; - -import { BxlModulesGenerator } from '../../logic/BxlModulesGenerator'; - -export class GenerateAction extends CommandLineAction { - private _terminal: Terminal; - - public constructor(terminal: Terminal) { - super({ - actionName: 'generate', - summary: 'Generates a BuildXL configuration for the current Rush repository.', - documentation: 'Generates a BuildXL configuration for the current Rush repository.' - }); - - this._terminal = terminal; - } - - public onDefineParameters(): void { - /* This action doesn't take any parameters*/ - } - - protected async onExecute(): Promise { - if (process.env.BUILDXL_BIN === undefined) { - throw new Error('Environment variable BUILDXL_BIN not defined'); - } - - const generator: BxlModulesGenerator = - new BxlModulesGenerator( - RushConfiguration.loadFromDefaultLocation(), - process.env.BUILDXL_BIN); - - await generator.run(); - this._terminal.writeLine(`Successfully generated BuildXL configuration.`); - } -} diff --git a/apps/rush-buildxl/src/logic/BxlConfig.ts b/apps/rush-buildxl/src/logic/BxlConfig.ts deleted file mode 100644 index d2ee5ac1dec..00000000000 --- a/apps/rush-buildxl/src/logic/BxlConfig.ts +++ /dev/null @@ -1,60 +0,0 @@ -// 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 { BxlModule } from './BxlModule'; - -export class BxlConfig { - private _bxlRoot: string; - private _modulesFolder: string; - private _modules: BxlModule[]; - private _commonRushConfigFolder: string; - - public constructor(bxlRoot: string, modulesFolder: string, modules: BxlModule[], commonRushConfigFolder: string) { - this._bxlRoot = bxlRoot; - this._modulesFolder = modulesFolder; - this._modules = modules; - this._commonRushConfigFolder = commonRushConfigFolder; - } - - public get bxlConfigFilePath(): string { - return `${this._modulesFolder}/config.dsc`; - } - - public async writeFile(): Promise { - const contents: string = -`config({ - modules: [ - f\`${this._modules[0].configFilePath}\`, - ], - resolvers: [ - { - kind: "SourceResolver", - packages: [ - f\`${this._bxlRoot}/sdk/sdk.transformers/package.config.dsc\`, - f\`${this._bxlRoot}/sdk/sdk.prelude/package.config.dsc\`, - ] - } - ], - mounts: [ - { - name: a\`CommonRushConfig\`, - path: p\`${this._commonRushConfigFolder}\`, - trackSourceFileChanges: true, - isWritable: false, - isReadable: true - }, - { - name: a\`Out\`, - path: p\`../out\`, - trackSourceFileChanges: true, - isWritable: true, - isReadable: true - }, - ] -});`; - - FileSystem.writeFile(this.bxlConfigFilePath, contents, { ensureFolderExists: true }); - } -} diff --git a/apps/rush-buildxl/src/logic/BxlModule.ts b/apps/rush-buildxl/src/logic/BxlModule.ts deleted file mode 100644 index 9d98ab2dc9c..00000000000 --- a/apps/rush-buildxl/src/logic/BxlModule.ts +++ /dev/null @@ -1,96 +0,0 @@ -// 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 { BxlModuleConfig } from './BxlModuleConfig'; - -export interface IBxlModuleInfo { - name: string; - packageRoot: string; - moduleFolder: string; -} - -export class BxlModule { - private _name: string; - private _moduleFolder: string; - private _config: BxlModuleConfig; - private _projectFolder: string; - private _rushJsonPath: string; - - public constructor(name: string, projectFolder: string, rushJsonPath: string, moduleFolder: string) { - this._name = name; - this._projectFolder = projectFolder; - this._rushJsonPath = rushJsonPath; - this._moduleFolder = moduleFolder; - this._config = new BxlModuleConfig(name, moduleFolder, this.moduleFilePath); - } - - public get configFilePath(): string { - return this._config.moduleConfigFilePath; - } - - public get moduleFilePath(): string { - return `${this._moduleFolder}/${this._name}.dsc`; - } - - public async writeFile(): Promise { - const contents: string = -`import { Cmd, Transformer } from "Sdk.Transformers"; - -export const cmdTool: Transformer.ToolDefinition = { - exe: f\`\${Environment.getPathValue("COMSPEC")}\`, - dependsOnWindowsDirectories: true, -}; - -const packageRoot: Directory = d\`${this._projectFolder}\`; -const packageJson: File = f\`${this._projectFolder}/package.json\`; -const rushJsonPath: File = f\`${this._rushJsonPath}\`; -const outFile: File = f\`\${Context.getMount("Out").path}\\${this._name}.snt\`; - -const commonRushConfig: StaticDirectory = Transformer.sealSourceDirectory( - d\`\${Context.getMount("CommonRushConfig").path}\`, - Transformer.SealSourceDirectoryOption.allDirectories -); - -// Invoke the rushx build command for the package -export const buildPip = Transformer.execute({ - tool: cmdTool, - arguments: [ - Cmd.argument("/D"), - Cmd.argument("/C"), - Cmd.argument("rushx.cmd build"), - ], - dependencies: [ - packageJson, - rushJsonPath, - commonRushConfig, - ], - environmentVariables: [], - outputs: [ - outFile - ], - // BuildXL ignores changes to these paths and variables. Unsafe options reduce determinism and can - // cause distributed build failures if used too broadly. - unsafe: { - passThroughEnvironmentVariables : [ - "PATH", - "USERPROFILE", - ], - untrackedScopes: [ - d\`\${Environment.getPathValue("USERPROFILE").path}/.rush\`, - d\`\${Context.getMount("AppData").path}\`, - d\`\${Context.getMount("ProgramFiles").path}\`, - d\`\${Context.getMount("ProgramFilesX86").path}\`, - ], - }, - workingDirectory: packageRoot, -}); -`; - - FileSystem.writeFile(this.moduleFilePath, contents, { ensureFolderExists: true }); - - // Also write the module config file - await this._config.writeFile(); - } -} diff --git a/apps/rush-buildxl/src/logic/BxlModuleConfig.ts b/apps/rush-buildxl/src/logic/BxlModuleConfig.ts deleted file mode 100644 index c66bda23269..00000000000 --- a/apps/rush-buildxl/src/logic/BxlModuleConfig.ts +++ /dev/null @@ -1,35 +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 { FileSystem } from '@rushstack/node-core-library'; - -export class BxlModuleConfig { - private _name: string; - private _moduleFilePath: string; - private _moduleFolder: string; - - public constructor(name: string, moduleFolder: string, moduleFilePath: string) { - this._name = name; - this._moduleFolder = moduleFolder; - this._moduleFilePath = moduleFilePath; - } - - public get moduleConfigFilePath(): string { - return path.resolve(this._moduleFolder, 'module.config.dsc'); - } - - public async writeFile(): Promise { - const contents: string = -`package({ - name: "${this._name}", - nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences, - projects: [ - f\`${this._moduleFilePath}\` - ] -});`; - - FileSystem.writeFile(this.moduleConfigFilePath, contents, { ensureFolderExists: true }); - } -} \ No newline at end of file diff --git a/apps/rush-buildxl/src/logic/BxlModulesGenerator.ts b/apps/rush-buildxl/src/logic/BxlModulesGenerator.ts deleted file mode 100644 index 4f9f94f73d6..00000000000 --- a/apps/rush-buildxl/src/logic/BxlModulesGenerator.ts +++ /dev/null @@ -1,52 +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 { RushConfiguration } from '@microsoft/rush-lib'; - -import { BxlModule } from './BxlModule'; -import { BxlConfig } from './BxlConfig'; - -export class BxlModulesGenerator { - private _rushConfiguration: RushConfiguration; - private _buildXLRoot: string; - - public constructor(rushConfiguration: RushConfiguration, buildXLRoot: string) { - this._rushConfiguration = rushConfiguration; - this._buildXLRoot = this._normalizePathSeparator(buildXLRoot); - } - - public async run(): Promise { - const modulesRoot: string = this._normalizePathSeparator( - path.resolve(this._rushConfiguration.commonTempFolder, 'bxl', 'modules') - ); - const rushJsonFilePath: string = this._normalizePathSeparator(this._rushConfiguration.rushJsonFile); - const commonRushConfigFolder: string = this._normalizePathSeparator(this._rushConfiguration.commonRushConfigFolder); - - const modules: BxlModule[] = this._rushConfiguration.projects.map((project) => { - const name: string = this._packageNameToModuleName(project.packageName); - const moduleRoot: string = path.resolve(modulesRoot, name); - const projDir: string = this._normalizePathSeparator(project.projectFolder); - - return new BxlModule(name, projDir, rushJsonFilePath, moduleRoot); - }); - - const bxlConfig: BxlConfig = new BxlConfig(this._buildXLRoot, modulesRoot, modules, commonRushConfigFolder); - - // Write individual module dsc files - const tasks: Promise[] = modules.map(module => module.writeFile()); - await Promise.all(tasks); - - // Write config.dsc - await bxlConfig.writeFile(); - } - - private _packageNameToModuleName(packageName: string): string { - return packageName.replace('/', '_'); - } - - private _normalizePathSeparator(str: string): string { - return str.replace(/\\/g, '/'); - } -} \ No newline at end of file diff --git a/apps/rush-buildxl/src/start.ts b/apps/rush-buildxl/src/start.ts deleted file mode 100644 index 492c1497328..00000000000 --- a/apps/rush-buildxl/src/start.ts +++ /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. - -import { - Terminal, - ConsoleTerminalProvider -} from '@rushstack/node-core-library'; - -import { RushBuildXLCommandLineParser } from './cli/RushBuildXLCommandLineParser'; - -const terminal: Terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); -const parser: RushBuildXLCommandLineParser = new RushBuildXLCommandLineParser(terminal); -parser.execute().catch((error) => terminal.writeErrorLine(error)); diff --git a/apps/rush-buildxl/src/test/ExampleTest.test.ts b/apps/rush-buildxl/src/test/ExampleTest.test.ts deleted file mode 100644 index a878fa0fdfb..00000000000 --- a/apps/rush-buildxl/src/test/ExampleTest.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -describe('Example Test', () => { - it('does stuff', () => { - expect(true).toBe(true); - }); -}); diff --git a/apps/rush-buildxl/tsconfig.json b/apps/rush-buildxl/tsconfig.json deleted file mode 100644 index 76f0d945025..00000000000 --- a/apps/rush-buildxl/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } -} diff --git a/apps/rush-lib/.eslintrc.js b/apps/rush-lib/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/apps/rush-lib/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/apps/rush-lib/.gitignore b/apps/rush-lib/.gitignore deleted file mode 100644 index 618684c2905..00000000000 --- a/apps/rush-lib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Keep temp folders in mocked 'repos' that are used for unit tests -!**/test/**/temp diff --git a/apps/rush-lib/.npmignore b/apps/rush-lib/.npmignore deleted file mode 100644 index 0a4c848fafb..00000000000 --- a/apps/rush-lib/.npmignore +++ /dev/null @@ -1,25 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) -!/assets/** diff --git a/apps/rush-lib/LICENSE b/apps/rush-lib/LICENSE deleted file mode 100644 index 1f55ba16d8f..00000000000 --- a/apps/rush-lib/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/rush-lib - -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/rush-lib/README.md b/apps/rush-lib/README.md deleted file mode 100644 index 73317697e29..00000000000 --- a/apps/rush-lib/README.md +++ /dev/null @@ -1,16 +0,0 @@ -## @microsoft/rush-lib - -This is a companion package for the Rush tool. See the -[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) -package for details. - -The **rush-lib** package implements the rush.json config file loader -and some other helpful utilities. Tools that want to reuse this -functionality can install **rush-lib** alone to avoid inadvertently -adding another "rush" executable to the command-line path (which -might interfere with the globally installed Rush). - -The **@microsoft/rush** version number is always exactly equal -to the **@microsoft/rush-lib** version number that it depends on. - -API documentation for this package: https://rushstack.io/pages/api/rush-lib/ diff --git a/apps/rush-lib/__mocks__/child_process.js b/apps/rush-lib/__mocks__/child_process.js deleted file mode 100644 index b08594fb498..00000000000 --- a/apps/rush-lib/__mocks__/child_process.js +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -const EventEmitter = require('events'); - -const childProcess = 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) { - 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) { - spawnMockConfig = normalizeSpawnMockConfig(spawnConfig); -} - -/** - * Mock of `spawn`. - */ -function spawn(file, args, 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/apps/rush-lib/assets/rush-init/[dot]gitignore b/apps/rush-lib/assets/rush-init/[dot]gitignore deleted file mode 100644 index 498da968cdd..00000000000 --- a/apps/rush-lib/assets/rush-init/[dot]gitignore +++ /dev/null @@ -1,63 +0,0 @@ -# Logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# next.js build output -.next - -# OS X temporary files -.DS_Store - -# Rush temporary files -common/temp/ -**/.rush/temp/ diff --git a/apps/rush-lib/assets/rush-init/[dot]travis.yml b/apps/rush-lib/assets/rush-init/[dot]travis.yml deleted file mode 100644 index 2e2cff4aca8..00000000000 --- a/apps/rush-lib/assets/rush-init/[dot]travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: node_js -node_js: - - '8.9.4' -script: - - set -e - - - echo 'Checking for missing change logs...' && echo -en 'travis_fold:start:change\\r' - - git fetch origin master:refs/remotes/origin/master -a - - node common/scripts/install-run-rush.js change -v - - echo -en 'travis_fold:end:change\\r' - - - echo 'Installing...' && echo -en 'travis_fold:start:install\\r' - - node common/scripts/install-run-rush.js install - - echo -en 'travis_fold:end:install\\r' - - - echo 'Building...' && echo -en 'travis_fold:start:build\\r' - - node common/scripts/install-run-rush.js rebuild --verbose - - echo -en 'travis_fold:end:build\\r' diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc b/apps/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc deleted file mode 100644 index 237d30461dc..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc +++ /dev/null @@ -1,12 +0,0 @@ -# Rush uses this file to configure the package registry, regardless of whether the -# package manager is PNPM, NPM, or Yarn. Prior to invoking the package manager, -# Rush will always copy this file to the folder where installation is performed. -# When NPM is the package manager, Rush works around NPM's processing of -# undefined environment variables by deleting any lines that reference undefined -# environment variables. -# -# DO NOT SPECIFY AUTHENTICATION CREDENTIALS IN THIS FILE. It should only be used -# to configure registry sources. - -registry=https://registry.npmjs.org/ -always-auth=false diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/command-line.json b/apps/rush-lib/assets/rush-init/common/config/rush/command-line.json deleted file mode 100644 index 9c1a4f3671a..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/command-line.json +++ /dev/null @@ -1,257 +0,0 @@ -/** - * This configuration file defines custom commands for the "rush" command-line. - * For full documentation, please see https://rushjs.io - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - - /** - * Custom "commands" introduce new verbs for the command-line. To see the help for these - * example commands, try "rush --help", "rush my-bulk-command --help", or - * "rush my-global-command --help". - */ - "commands": [ - /*[BEGIN "DEMO"]*/ - { - /** - * (Required) Determines the type of custom command. - * Rush's "bulk" commands are invoked separately for each project. Rush will look in - * each project's package.json file for a "scripts" entry whose name matches the - * command name. By default, the command will run for every project in the repo, - * according to the dependency graph (similar to how "rush build" works). - * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. - */ - "commandKind": "bulk", - - /** - * (Required) The name that will be typed as part of the command line. This is also the name - * of the "scripts" hook in the project's package.json file. - * The name should be comprised of lower case words separated by hyphens or colons. The name should include an - * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands - * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). - */ - "name": "my-bulk-command", - - /** - * (Required) A short summary of the custom command to be shown when printing command line - * help, e.g. "rush --help". - */ - "summary": "Example bulk custom command", - - /** - * A detailed description of the command to be shown when printing command line - * help (e.g. "rush --help my-command"). - * If omitted, the "summary" text will be shown instead. - * - * Whenever you introduce commands/parameters, taking a little time to write meaningful - * documentation can make a big difference for the developer experience in your repo. - */ - "description": "This is an example custom command that runs separately for each project", - - /** - * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously - * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the - * same time.) If your command makes sense to run concurrently with other operations, - * set "safeForSimultaneousRushProcesses" to true to disable this protection. - * - * In particular, this is needed for custom scripts that invoke other Rush commands. - */ - "safeForSimultaneousRushProcesses": false, - - /** - * (Required) If true, then this command is safe to be run in parallel, i.e. executed - * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism - * projects will not start processing until their dependencies have completed processing. - */ - "enableParallelism": 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 - * you can set "ignoreDependencyOrder" to true to increase parallelism. - */ - "ignoreDependencyOrder": false, - - /** - * Normally Rush requires that each project's package.json has a "scripts" entry matching - * the custom command name. To disable this check, set "ignoreMissingScript" to true; - * projects with a missing definition will be skipped. - */ - "ignoreMissingScript": false, - - /** - * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: - * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". - * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. - * - If the shell script returns a zero process exit code but writes something to its stderr stream, - * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent - * Rush from processing downstream projects. - * - * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because - * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. - * In an active monorepo, we've found that if you allow any warnings in your master branch, it inadvertently - * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings - * have accumulated that warnings no longer serve any useful purpose. - * - * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. - * In that case, it's strongly recommended to fix the task. However, as a workaround you can set - * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. - * - * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. - */ - "allowWarningsInSuccessfulBuild": false - }, - - { - /** - * (Required) Determines the type of custom command. - * Rush's "global" commands are invoked once for the entire repo. - */ - "commandKind": "global", - - "name": "my-global-command", - "summary": "Example global custom command", - "description": "This is an example custom command that runs once for the entire repo", - - "safeForSimultaneousRushProcesses": false, - - /** - * A script that will be invoked using the OS shell. The working directory will be the folder - * that contains rush.json. If custom parameters are associated with this command, their - * values will be appended to the end of this string. - */ - "shellCommand": "node common/scripts/my-global-command.js" - } - /*[END "DEMO"]*/ - ], - - /** - * Custom "parameters" introduce new parameters for specified Rush command-line commands. - * For example, you might define a "--production" parameter for the "rush build" command. - */ - "parameters": [ - /*[BEGIN "DEMO"]*/ - { - /** - * (Required) Determines the type of custom parameter. - * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. - */ - "parameterKind": "flag", - - /** - * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. - */ - "longName": "--my-flag", - - /** - * An optional alternative short name for the parameter. It must be a dash followed by a single - * lower-case or upper-case letter, which is case-sensitive. - * - * NOTE: The Rush developers recommend that automation scripts should always use the long name - * to improve readability. The short name is only intended as a convenience for humans. - * The alphabet letters run out quickly, and are difficult to memorize, so *only* use - * a short name if you expect the parameter to be needed very often in everyday operations. - */ - "shortName": "-m", - - /** - * (Required) A long description to be shown in the command-line help. - * - * Whenever you introduce commands/parameters, taking a little time to write meaningful - * documentation can make a big difference for the developer experience in your repo. - */ - "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", - - /** - * (Required) A list of custom commands and/or built-in Rush commands that this parameter may - * be used with. The parameter will be appended to the shell command that Rush invokes. - */ - "associatedCommands": [ "build", "rebuild" ] - }, - - { - /** - * (Required) Determines the type of custom parameter. - * A "string" is a custom command-line parameter whose value is a simple text string. - */ - "parameterKind": "string", - "longName": "--my-string", - "description": "A custom string parameter for the \"my-global-command\" custom command", - - "associatedCommands": [ "my-global-command" ], - - /** - * The name of the argument, which will be shown in the command-line help. - * - * For example, if the parameter name is '--count" and the argument name is "NUMBER", - * then the command-line help would display "--count NUMBER". The argument name must - * be comprised of upper-case letters, numbers, and underscores. It should be kept short. - */ - "argumentName": "SOME_TEXT", - - /** - * If true, this parameter must be included with the command. The default is false. - */ - "required": false - }, - - { - /** - * (Required) Determines the type of custom parameter. - * A "choice" is a custom command-line parameter whose argument must be chosen from a list of - * allowable alternatives. - */ - "parameterKind": "choice", - "longName": "--my-choice", - "description": "A custom choice parameter for the \"my-global-command\" custom command", - - "associatedCommands": [ "my-global-command" ], - - /** - * If true, this parameter must be included with the command. The default is false. - */ - "required": false, - - /** - * Normally if a parameter is omitted from the command line, it will not be passed - * to the shell command. this value will be inserted by default. Whereas if a "defaultValue" - * is defined, the parameter will always be passed to the shell command, and will use the - * default value if unspecified. The value must be one of the defined alternatives. - */ - "defaultValue": "vanilla", - - /** - * (Required) A list of alternative argument values that can be chosen for this parameter. - */ - "alternatives": [ - { - /** - * A token that is one of the alternatives that can be used with the choice parameter, - * e.g. "vanilla" in "--flavor vanilla". - */ - "name": "vanilla", - - /** - * A detailed description for the alternative that can be shown in the command-line help. - * - * Whenever you introduce commands/parameters, taking a little time to write meaningful - * documentation can make a big difference for the developer experience in your repo. - */ - "description": "Use the vanilla flavor (the default)" - }, - - { - "name": "chocolate", - "description": "Use the chocolate flavor" - }, - - { - "name": "strawberry", - "description": "Use the strawberry flavor" - } - ] - } - /*[END "DEMO"]*/ - ] -} diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/common-versions.json b/apps/rush-lib/assets/rush-init/common/config/rush/common-versions.json deleted file mode 100644 index 33a8251abfc..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/common-versions.json +++ /dev/null @@ -1,64 +0,0 @@ -/** - * This configuration file specifies NPM dependency version selections that affect all projects - * in a Rush repo. For full documentation, please see https://rushjs.io - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", - - /** - * A table that specifies a "preferred version" for a given NPM package. This feature is typically used - * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. - * - * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into - * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager - * will calculate versions. The specific effect depends on your package manager. Generally it will have no - * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be - * achieved using the pnpmfile.js hook. See the Rush documentation for more details. - * - * After modifying this field, it's recommended to run "rush update --full" so that the package manager - * will recalculate all version selections. - */ - "preferredVersions": { - - /** - * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, - * instead of the latest version. - */ - /*[LINE "HYPOTHETICAL"]*/ "some-library": "1.2.3" - }, - - /** - * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, - * except in cases where different projects specify different version ranges for a given dependency. For older - * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause - * trouble for indirect dependencies with incompatible peerDependencies ranges. - * - * The default value is true. If you're encountering installation errors related to peer dependencies, - * it's recommended to set this to false. - * - * After modifying this field, it's recommended to run "rush update --full" so that the package manager - * will recalculate all version selections. - */ - /*[LINE "HYPOTHETICAL"]*/ "implicitlyPreferredVersions": false, - - /** - * The "rush check" command can be used to enforce that every project in the repo must specify - * the same SemVer range for a given dependency. However, sometimes exceptions are needed. - * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be - * accepted by "rush check" for a given dependency. - * - * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE - * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). - * This design avoids unnecessary churn in this file. - */ - "allowedAlternativeVersions": { - - /** - * 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): - */ - /*[LINE "HYPOTHETICAL"]*/ "typescript": [ - /*[LINE "HYPOTHETICAL"]*/ "~2.4.0" - /*[LINE "HYPOTHETICAL"]*/ ] - } -} diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/experiments.json b/apps/rush-lib/assets/rush-init/common/config/rush/experiments.json deleted file mode 100644 index 151a9047bec..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/experiments.json +++ /dev/null @@ -1,16 +0,0 @@ -/** - * This configuration file allows repo maintainers to enable and disable experimental - * Rush features. For full documentation, please see https://rushjs.io - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", - - /** - * Rush 5.14.0 improved incremental builds to ignore spurious changes in the pnpm-lock.json file. - * This optimization is enabled by default. If you encounter a problem where "rush build" is neglecting - * to build some projects, please open a GitHub issue. As a workaround you can uncomment this line - * to temporarily restore the old behavior where everything must be rebuilt whenever pnpm-lock.json - * is modified. - */ - /*[LINE "HYPOTHETICAL"]*/ "legacyIncrementalBuildDependencyDetection": true -} diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/pnpmfile.js b/apps/rush-lib/assets/rush-init/common/config/rush/pnpmfile.js deleted file mode 100644 index e93d4a4b0ed..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/pnpmfile.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -/** - * When using the PNPM package manager, you can use pnpmfile.js to workaround - * dependencies that have mistakes in their package.json file. (This feature is - * functionally similar to Yarn's "resolutions".) - * - * For details, see the PNPM documentation: - * https://pnpm.js.org/docs/en/hooks.html - * - * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE - * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run - * "rush update --full" so that PNPM will recalculate all version selections. - */ -module.exports = { - hooks: { - readPackage - } -}; - -/** - * This hook is invoked during installation before a package's dependencies - * are selected. - * The `packageJson` parameter is the deserialized package.json - * contents for the package that is about to be installed. - * The `context` parameter provides a log() function. - * The return value is the updated object. - */ -function readPackage(packageJson, context) { - - /*[LINE "HYPOTHETICAL"]*/ // The karma types have a missing dependency on typings from the log4js package. - /*[LINE "HYPOTHETICAL"]*/ if (packageJson.name === '@types/karma') { - /*[LINE "HYPOTHETICAL"]*/ context.log('Fixed up dependencies for @types/karma'); - /*[LINE "HYPOTHETICAL"]*/ packageJson.dependencies['log4js'] = '0.6.38'; - /*[LINE "HYPOTHETICAL"]*/ } - - return packageJson; -} diff --git a/apps/rush-lib/assets/rush-init/common/config/rush/version-policies.json b/apps/rush-lib/assets/rush-init/common/config/rush/version-policies.json deleted file mode 100644 index aefb14ac0c3..00000000000 --- a/apps/rush-lib/assets/rush-init/common/config/rush/version-policies.json +++ /dev/null @@ -1,92 +0,0 @@ -/** - * This is configuration file is used for advanced publishing configurations with Rush. - * For full documentation, please see https://rushjs.io - */ - - /** - * A list of version policy definitions. A "version policy" is a custom package versioning - * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies - * to a set of projects that are specified using the "versionPolicyName" field in rush.json. - */ -[ - /*[BEGIN "DEMO"]*/ - { - /** - * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). - * - * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This - * strategy is appropriate for a set of packages that act as selectable components of a - * unified product. The entire set of packages are always published together, and always share - * the same NPM version number. When the packages depend on other packages in the set, the - * SemVer range is usually restricted to a single version. - */ - "definitionName": "lockStepVersion", - - /** - * (Required) The name that will be used for the "versionPolicyName" field in rush.json. - * This name is also used command-line parameters such as "--version-policy" - * and "--to-version-policy". - */ - "policyName": "MyBigFramework", - - /** - * (Required) The current version. All packages belonging to the set should have this version - * in the current branch. When bumping versions, Rush uses this to determine the next version. - * (The "version" field in package.json is NOT considered.) - */ - "version": "1.0.0", - - /** - * (Required) The type of bump that will be performed when publishing the next release. - * When creating a release branch in Git, this field should be updated according to the - * type of release. - * - * Valid values are: "prerelease", "release", "minor", "patch", "major" - */ - "nextBump": "prerelease", - - /** - * (Optional) If specified, all packages in the set share a common CHANGELOG.md file. - * This file is stored with the specified "main" project, which must be a member of the set. - * - * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each - * package in the set. - */ - "mainProject": "my-app" - }, - - { - /** - * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). - * - * The "individualVersion" mode specifies that the projects will use "individual versioning". - * This is the typical NPM model where each package has an independent version number - * and CHANGELOG.md file. Although a single CI definition is responsible for publishing the - * packages, they otherwise don't have any special relationship. The version bumping will - * depend on how developers answer the "rush change" questions for each package that - * is changed. - */ - "definitionName": "individualVersion", - - "policyName": "MyRandomLibraries", - - /** - * (Optional) This can be used to enforce that all packages in the set must share a common - * major version number, e.g. because they are from the same major release branch. - * It can also be used to discourage people from accidentally making "MAJOR" SemVer changes - * inappropriately. The minor/patch version parts will be bumped independently according - * to the types of changes made to each project, according to the "rush change" command. - */ - "lockedMajor": 3, - - /** - * (Optional) When publishing is managed by Rush, by default the "rush change" command will - * request changes for any projects that are modified by a pull request. These change entries - * will produce a CHANGELOG.md file. If you author your CHANGELOG.md manually or announce updates - * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects - * belonging to this version policy. - */ - "exemptFromRushChange": false - } - /*[END "DEMO"]*/ -] diff --git a/apps/rush-lib/assets/rush-init/rush.json b/apps/rush-lib/assets/rush-init/rush.json deleted file mode 100644 index 920b87dfa6f..00000000000 --- a/apps/rush-lib/assets/rush-init/rush.json +++ /dev/null @@ -1,402 +0,0 @@ -/** - * This is the main configuration file for Rush. - * For full documentation, please see https://rushjs.io - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", - - /** - * (Required) This specifies the version of the Rush engine to be used in this repo. - * Rush's "version selector" feature ensures that the globally installed tool will - * behave like this release, regardless of which version is installed globally. - * - * The common/scripts/install-run-rush.js automation script also uses this version. - * - * NOTE: If you upgrade to a new major version of Rush, you should replace the "v5" - * path segment in the "$schema" field for all your Rush config files. This will ensure - * correct error-underlining and tab-completion for editors such as VS Code. - */ - "rushVersion": "[%RUSH_VERSION%]", - - /** - * The next field selects which package manager should be installed and determines its version. - * Rush installs its own local copy of the package manager to ensure that your build process - * is fully isolated from whatever tools are present in the local environment. - * - * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation - * for details about these alternatives. - */ - "pnpmVersion": "2.15.1", - - /*[LINE "HYPOTHETICAL"]*/ "npmVersion": "4.5.0", - /*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4", - - /** - * Options that are only used when the PNPM package manager is selected - */ - "pnpmOptions": { - /** - * Specifies the location of the PNPM store. There are two possible values: - * - * - "local" - use the "pnpm-store" folder in the current configured temp folder: - * "common/temp/pnpm-store" by default. - * - "global" - use PNPM's global store, which has the benefit of being shared - * across multiple repo folders, but the disadvantage of less isolation for builds - * (e.g. bugs or incompatibilities when two repos use different releases of PNPM) - * - * RUSH_PNPM_STORE_PATH will override the directory that will be used as the store - * - * In all cases, the store path will be overridden by the environment variable RUSH_PNPM_STORE_PATH. - * - * The default value is "local". - */ - /*[LINE "HYPOTHETICAL"]*/ "pnpmStore": "local", - - /** - * If true, then Rush will add the "--strict-peer-dependencies" option when invoking PNPM. - * This causes "rush install" to fail if there are unsatisfied peer dependencies, which is - * an invalid state that can cause build failures or incompatible dependency versions. - * (For historical reasons, JavaScript package managers generally do not treat this invalid - * state as an error.) - * - * The default value is false to avoid legacy compatibility issues. - * It is strongly recommended to set strictPeerDependencies=true. - */ - /*[LINE "DEMO"]*/ "strictPeerDependencies": true, - - - /** - * Configures the strategy used to select versions during installation. - * - * This feature requires PNPM version 3.1 or newer. It corresponds to the "--resolution-strategy" command-line - * option for PNPM. Possible values are "fast" and "fewer-dependencies". PNPM's default is "fast", but this may - * be incompatible with certain packages, for example the "@types" packages from DefinitelyTyped. Rush's default - * is "fewer-dependencies", which causes PNPM to avoid installing a newer version if an already installed version - * can be reused; this is more similar to NPM's algorithm. - * - * After modifying this field, it's recommended to run "rush update --full" so that the package manager - * will recalculate all version selections. - */ - /*[LINE "HYPOTHETICAL"]*/ "resolutionStrategy": "fast" - }, - - /** - * Older releases of the Node.js engine may be missing features required by your system. - * Other releases may have bugs. In particular, the "latest" version will not be a - * Long Term Support (LTS) version and is likely to have regressions. - * - * Specify a SemVer range to ensure developers use a Node.js version that is appropriate - * for your repo. - */ - "nodeSupportedVersionRange": ">=10.13.0 <11.0.0", - - /** - * Odd-numbered major versions of Node.js are experimental. Even-numbered releases - * spend six months in a stabilization period before the first Long Term Support (LTS) version. - * For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended - * for production usage because they frequently have bugs. They may cause Rush itself - * to malfunction. - * - * Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing - * pre-LTS versions in preparation for supporting the first LTS version, you can use this setting - * to disable Rush's warning. - */ - /*[LINE "HYPOTHETICAL"]*/ "suppressNodeLtsWarning": false, - - /** - * If you would like the version specifiers for your dependencies to be consistent, then - * uncomment this line. This is effectively similar to running "rush check" before any - * of the following commands: - * - * rush install, rush update, rush link, rush version, rush publish - * - * In some cases you may want this turned on, but need to allow certain packages to use a different - * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" - * section of the common-versions.json. - */ - /*[LINE "HYPOTHETICAL"]*/ "ensureConsistentVersions": true, - - /** - * Large monorepos can become intimidating for newcomers if project folder paths don't follow - * a consistent and recognizable pattern. When the system allows nested folder trees, - * we've found that teams will often use subfolders to create islands that isolate - * their work from others ("shipping the org"). This hinders collaboration and code sharing. - * - * The Rush developers recommend a "category folder" model, where buildable project folders - * must always be exactly two levels below the repo root. The parent folder acts as the category. - * This provides a basic facility for grouping related projects (e.g. "apps", "libaries", - * "tools", "prototypes") while still encouraging teams to organize their projects into - * a unified taxonomy. Limiting to 2 levels seems very restrictive at first, but if you have - * 20 categories and 20 projects in each category, this scheme can easily accommodate hundreds - * of projects. In practice, you will find that the folder hierarchy needs to be rebalanced - * occasionally, but if that's painful, it's a warning sign that your development style may - * discourage refactoring. Reorganizing the categories should be an enlightening discussion - * that brings people together, and maybe also identifies poor coding practices (e.g. file - * references that reach into other project's folders without using Node.js module resolution). - * - * The defaults are projectFolderMinDepth=1 and projectFolderMaxDepth=2. - * - * To remove these restrictions, you could set projectFolderMinDepth=1 - * and set projectFolderMaxDepth to a large number. - */ - /*[LINE "HYPOTHETICAL"]*/ "projectFolderMinDepth": 2, - /*[LINE "HYPOTHETICAL"]*/ "projectFolderMaxDepth": 2, - - /** - * This feature helps you to review and approve new packages before they are introduced - * to your monorepo. For example, you may be concerned about licensing, code quality, - * performance, or simply accumulating too many libraries with overlapping functionality. - * The approvals are tracked in two config files "browser-approved-packages.json" - * and "nonbrowser-approved-packages.json". See the Rush documentation for details. - */ - /*[BEGIN "DEMO"]*/ - "approvedPackagesPolicy": { - /** - * The review categories allow you to say for example "This library is approved for usage - * in prototypes, but not in production code." - * - * Each project can be associated with one review category, by assigning the "reviewCategory" field - * in the "projects" section of rush.json. The approval is then recorded in the files - * "common/config/rush/browser-approved-packages.json" and "nonbrowser-approved-packages.json" - * which are automatically generated during "rush update". - * - * Designate categories with whatever granularity is appropriate for your review process, - * or you could just have a single category called "default". - */ - "reviewCategories": [ - // Some example categories: - "production", // projects that ship to production - "tools", // non-shipping projects that are part of the developer toolchain - "prototypes" // experiments that should mostly be ignored by the review process - ], - - /** - * A list of NPM package scopes that will be excluded from review. - * We recommend to exclude TypeScript typings (the "@types" scope), because - * if the underlying package was already approved, this would imply that the typings - * are also approved. - */ - /*[LINE "HYPOTHETICAL"]*/ "ignoredNpmScopes": [ "@types" ] - }, - /*[END "DEMO"]*/ - - /** - * If you use Git as your version control system, this section has some additional - * optional features you can use. - */ - "gitPolicy": { - /** - * Work at a big company? Tired of finding Git commits at work with unprofessional Git - * emails such as "beer-lover@my-college.edu"? Rush can validate people's Git email address - * before they get started. - * - * Define a list of regular expressions describing allowable e-mail patterns for Git commits. - * They are case-insensitive anchored JavaScript RegExps. Example: ".*@example\.com" - * - * IMPORTANT: Because these are regular expressions encoded as JSON string literals, - * RegExp escapes need two backspashes, and ordinary periods should be "\\.". - */ - /*[BEGIN "DEMO"]*/ - "allowedEmailRegExps": [ - "[^@]+@users\\.noreply\\.github\\.com", - "travis@example\\.org" - ], - /*[END "DEMO"]*/ - - /** - * When Rush reports that the address is malformed, the notice can include an example - * of a recommended email. Make sure it conforms to one of the allowedEmailRegExps - * expressions. - */ - /*[LINE "DEMO"]*/ "sampleEmail": "mrexample@users.noreply.github.com", - - /** - * The commit message to use when committing changes during 'rush publish'. - * - * For example, if you want to prevent these commits from triggering a CI build, - * you might configure your system's trigger to look for a special string such as "[skip-ci]" - * in the commit message, and then customize Rush's message to contain that string. - */ - /*[LINE "DEMO"]*/ "versionBumpCommitMessage": "Applying package updates. [skip-ci]" - }, - - "repository": { - /** - * The URL of this Git repository, used by "rush change" to determine the base branch for your PR. - * - * The "rush change" command needs to determine which files are affected by your PR diff. - * If you merged or cherry-picked commits from the master branch into your PR branch, those commits - * should be excluded from this diff (since they belong to some other PR). In order to do that, - * Rush needs to know where to find the base branch for your PR. This information cannot be - * determined from Git alone, since the "pull request" feature is not a Git concept. Ideally - * Rush would use a vendor-specific protocol to query the information from GitHub, Azure DevOps, etc. - * But to keep things simple, "rush change" simply assumes that your PR is against the "master" branch - * of the Git remote indicated by the repository.url setting in rush.json. If you are working in - * a GitHub "fork" of the real repo, this setting will be different from the repository URL of your - * your PR branch, and in this situation "rush change" will also automatically invoke "git fetch" - * to retrieve the latest activity for the remote master branch. - */ - /*[LINE "HYPOTHETICAL"]*/ "url": "https://github.com/microsoft/rush-example", - - /** - * The default branch name. This tells "rush change" which remote branch to compare against. - * The default value is "master" - */ - /*[LINE "HYPOTHETICAL"]*/ "defaultBranch": "master", - - /** - * The default remote. This tells "rush change" which remote to compare against if the remote URL is - * not set or if a remote matching the provided remote URL is not found. - */ - /*[LINE "HYPOTHETICAL"]*/ "defaultRemote": "origin" - }, - - /** - * Event hooks are customized script actions that Rush executes when specific events occur - */ - "eventHooks": { - /** - * The list of shell commands to run before the Rush installation starts - */ - "preRushInstall": [ - /*[LINE "HYPOTHETICAL"]*/ "common/scripts/pre-rush-install.js" - ], - - /** - * The list of shell commands to run after the Rush installation finishes - */ - "postRushInstall": [], - - /** - * The list of shell commands to run before the Rush build command starts - */ - "preRushBuild": [], - - /** - * The list of shell commands to run after the Rush build command finishes - */ - "postRushBuild": [] - }, - - /** - * Installation variants allow you to maintain a parallel set of configuration files that can be - * used to build the entire monorepo with an alternate set of dependencies. For example, suppose - * you upgrade all your projects to use a new release of an important framework, but during a transition period - * you intend to maintain compability with the old release. In this situation, you probably want your - * CI validation to build the entire repo twice: once with the old release, and once with the new release. - * - * Rush "installation variants" correspond to sets of config files located under this folder: - * - * common/config/rush/variants/ - * - * The variant folder can contain an alternate common-versions.json file. Its "preferredVersions" field can be used - * to select older versions of dependencies (within a loose SemVer range specified in your package.json files). - * To install a variant, run "rush install --variant ". - * - * For more details and instructions, see this article: https://rushjs.io/pages/advanced/installation_variants/ - */ - "variants": [ - /*[BEGIN "HYPOTHETICAL"]*/ - { - /** - * The folder name for this variant. - */ - "variantName": "old-sdk", - - /** - * An informative description - */ - "description": "Build this repo using the previous release of the SDK" - } - /*[END "HYPOTHETICAL"]*/ - ], - - /** - * Rush can collect anonymous telemetry about everyday developer activity such as - * success/failure of installs, builds, and other operations. You can use this to identify - * problems with your toolchain or Rush itself. THIS TELEMETRY IS NOT SHARED WITH MICROSOFT. - * It is written into JSON files in the common/temp folder. It's up to you to write scripts - * that read these JSON files and do something with them. These scripts are typically registered - * in the "eventHooks" section. - */ - /*[LINE "HYPOTHETICAL"]*/ "telemetryEnabled": false, - - /** - * Allows creation of hotfix changes. This feature is experimental so it is disabled by default. - * If this is set, 'rush change' only allows a 'hotfix' change type to be specified. This change type - * will be used when publishing subsequent changes from the monorepo. - */ - /*[LINE "HYPOTHETICAL"]*/ "hotfixChangeEnabled": false, - - /** - * (Required) This is the inventory of projects to be managed by Rush. - * - * Rush does not automatically scan for projects using wildcards, for a few reasons: - * 1. Depth-first scans are expensive, particularly when tools need to repeatedly collect the list. - * 2. On a caching CI machine, scans can accidentally pick up files left behind from a previous build. - * 3. It's useful to have a centralized inventory of all projects and their important metadata. - */ - "projects": [ - /*[BEGIN "DEMO"]*/ - { - /** - * The NPM package name of the project (must match package.json) - */ - "packageName": "my-app", - - /** - * The path to the project folder, relative to the rush.json config file. - */ - "projectFolder": "apps/my-app", - - /** - * An optional category for usage in the "browser-approved-packages.json" - * and "nonbrowser-approved-packages.json" files. The value must be one of the - * strings from the "reviewCategories" defined above. - */ - "reviewCategory": "production", - - /** - * A list of local projects that appear as devDependencies for this project, but cannot be - * locally linked because it would create a cyclic dependency; instead, the last published - * version will be installed in the Common folder. - */ - "cyclicDependencyProjects": [ - /*[LINE "HYPOTHETICAL"]*/ "my-toolchain" - ], - - /** - * If true, then this project will be ignored by the "rush check" command. - * The default value is false. - */ - /*[LINE "HYPOTHETICAL"]*/ "skipRushCheck": false, - - /** - * A flag indicating that changes to this project will be published to npm, which affects - * the Rush change and publish workflows. The default value is false. - * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. - */ - /*[LINE "HYPOTHETICAL"]*/ "shouldPublish": false, - - /** - * An optional version policy associated with the project. Version policies are defined - * in "version-policies.json" file. See the "rush publish" documentation for more info. - * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. - */ - /*[LINE "HYPOTHETICAL"]*/ "versionPolicyName": "" - }, - - { - "packageName": "my-controls", - "projectFolder": "libraries/my-controls", - "reviewCategory": "production" - }, - - { - "packageName": "my-toolchain", - "projectFolder": "tools/my-toolchain", - "reviewCategory": "tools" - } - /*[END "DEMO"]*/ - ] -} diff --git a/apps/rush-lib/config/jest.json b/apps/rush-lib/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/apps/rush-lib/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/apps/rush-lib/gulpfile.js b/apps/rush-lib/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/apps/rush-lib/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/apps/rush-lib/package.json b/apps/rush-lib/package.json deleted file mode 100644 index 2d53d0d7b72..00000000000 --- a/apps/rush-lib/package.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "@microsoft/rush-lib", - "version": "5.22.0", - "description": "A library for writing scripts that interact with the Rush tool", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/rush-lib" - }, - "engines": { - "node": ">=5.6.0" - }, - "engineStrict": true, - "homepage": "https://rushjs.io", - "main": "lib/index.js", - "typings": "dist/rush-lib.d.ts", - "scripts": { - "build": "gulp test --clean" - }, - "license": "MIT", - "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@rushstack/package-deps-hash": "2.4.6", - "@rushstack/stream-collator": "3.2.6", - "@rushstack/ts-command-line": "4.3.12", - "@pnpm/link-bins": "~5.1.0", - "@yarnpkg/lockfile": "~1.0.2", - "builtin-modules": "~3.1.0", - "cli-table": "~0.3.1", - "colors": "~1.2.1", - "git-repo-info": "~2.1.0", - "glob": "~7.0.5", - "glob-escape": "~0.0.1", - "https-proxy-agent": "~2.2.1", - "inquirer": "~6.2.0", - "js-yaml": "~3.13.1", - "lodash": "~4.17.15", - "minimatch": "~3.0.2", - "node-fetch": "~2.1.2", - "npm-package-arg": "~6.1.0", - "read-package-tree": "~5.1.5", - "semver": "~5.3.0", - "strict-uri-encode": "~2.0.0", - "tar": "~4.4.1", - "true-case-path": "~2.2.1", - "wordwrap": "~1.0.0", - "z-schema": "~3.18.3" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/glob": "7.1.1", - "@types/inquirer": "0.0.43", - "@types/jest": "23.3.11", - "@types/js-yaml": "3.12.1", - "@types/lodash": "4.14.116", - "@types/minimatch": "2.0.29", - "@types/node": "10.17.13", - "@types/node-fetch": "1.6.9", - "@types/semver": "5.3.33", - "@types/tar": "4.0.0", - "@types/npm-package-arg": "6.1.0", - "@types/strict-uri-encode": "2.0.0", - "@types/read-package-tree": "5.1.0", - "@types/wordwrap": "1.0.0", - "@types/z-schema": "3.16.31", - "gulp": "~4.0.2", - "jest": "~23.6.0" - } -} diff --git a/apps/rush-lib/src/api/ApprovedPackagesPolicy.ts b/apps/rush-lib/src/api/ApprovedPackagesPolicy.ts deleted file mode 100644 index 3da76833f48..00000000000 --- a/apps/rush-lib/src/api/ApprovedPackagesPolicy.ts +++ /dev/null @@ -1,110 +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 { ApprovedPackagesConfiguration } from './ApprovedPackagesConfiguration'; -import { RushConstants } from '../logic/RushConstants'; -import { RushConfiguration, IRushConfigurationJson, IApprovedPackagesPolicyJson } from './RushConfiguration'; - -/** - * This is a helper object for RushConfiguration. - * It exposes the "approvedPackagesPolicy" feature from rush.json. - * @public - */ -export class ApprovedPackagesPolicy { - private _enabled: boolean; - private _ignoredNpmScopes: Set; - private _reviewCategories: Set; - private _browserApprovedPackages: ApprovedPackagesConfiguration; - private _nonbrowserApprovedPackages: ApprovedPackagesConfiguration; - - /** @internal */ - public constructor(rushConfiguration: RushConfiguration, rushConfigurationJson: IRushConfigurationJson) { - const approvedPackagesPolicy: IApprovedPackagesPolicyJson = rushConfigurationJson.approvedPackagesPolicy || {}; - - this._enabled = !!rushConfigurationJson.approvedPackagesPolicy; - this._ignoredNpmScopes = new Set(approvedPackagesPolicy.ignoredNpmScopes); - this._reviewCategories = new Set(approvedPackagesPolicy.reviewCategories); - - if (this._enabled) { - if (!this.reviewCategories.size) { - throw new Error(`The "approvedPackagesPolicy" feature is enabled rush.json, but the reviewCategories` - + ` list is not configured.`); - } - } - - // Load browser-approved-packages.json - const browserApprovedPackagesPath: string = path.join( - rushConfiguration.commonRushConfigFolder, - RushConstants.browserApprovedPackagesFilename - ); - this._browserApprovedPackages = new ApprovedPackagesConfiguration(browserApprovedPackagesPath); - this._browserApprovedPackages.tryLoadFromFile(this._enabled); - - // Load nonbrowser-approved-packages.json - const nonbrowserApprovedPackagesPath: string = path.join( - rushConfiguration.commonRushConfigFolder, - RushConstants.nonbrowserApprovedPackagesFilename - ); - this._nonbrowserApprovedPackages = new ApprovedPackagesConfiguration(nonbrowserApprovedPackagesPath); - this._nonbrowserApprovedPackages.tryLoadFromFile(this._enabled); - } - - /** - * Whether the feature is enabled. The feature is enabled if the "approvedPackagesPolicy" - * field is assigned in rush.json. - */ - public get enabled(): boolean { - return this._enabled; - } - - /** - * A list of NPM package scopes that will be excluded from review (e.g. `@types`) - */ - public get ignoredNpmScopes(): Set { - return this._ignoredNpmScopes; - } - - /** - * A list of category names that are valid for usage as the RushConfigurationProject.reviewCategory field. - * This array will never be undefined. - */ - public get reviewCategories(): Set { - return this._reviewCategories; - } - - /** - * Packages approved for usage in a web browser. This is the stricter of the two types, so by default - * all new packages are added to this file. - * - * @remarks - * - * This is part of an optional approval workflow, whose purpose is to review any new dependencies - * that are introduced (e.g. maybe a legal review is required, or maybe we are trying to minimize bloat). - * When Rush discovers a new dependency has been added to package.json, it will update the file. - * The intent is that the file will be stored in Git and tracked by a branch policy that notifies - * reviewers when a PR attempts to modify the file. - * - * Example filename: `C:\MyRepo\common\config\rush\browser-approved-packages.json` - */ - public get browserApprovedPackages(): ApprovedPackagesConfiguration { - return this._browserApprovedPackages; - } - - /** - * Packages approved for usage everywhere *except* in a web browser. - * - * @remarks - * - * This is part of an optional approval workflow, whose purpose is to review any new dependencies - * that are introduced (e.g. maybe a legal review is required, or maybe we are trying to minimize bloat). - * The intent is that the file will be stored in Git and tracked by a branch policy that notifies - * reviewers when a PR attempts to modify the file. - * - * Example filename: `C:\MyRepo\common\config\rush\browser-approved-packages.json` - */ - public get nonbrowserApprovedPackages(): ApprovedPackagesConfiguration { - return this._nonbrowserApprovedPackages; - } -} diff --git a/apps/rush-lib/src/api/ChangeManager.ts b/apps/rush-lib/src/api/ChangeManager.ts deleted file mode 100644 index e8bea93133d..00000000000 --- a/apps/rush-lib/src/api/ChangeManager.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { RushConfiguration } from './RushConfiguration'; -import { RushConfigurationProject } from './RushConfigurationProject'; -import { ChangeFile } from './ChangeFile'; -import { IChangeFile } from './ChangeManagement'; - -/** - * A class that helps with programatically interacting with Rush's change files. - * @public - */ -export class ChangeManager { - /** - * Creates a change file that has a 'none' type. - * @param rushConfiguration - The rush configuration we are working with - * @param projectName - The name of the project for which to create a change file - * @param emailAddress - The email address which should be associated with this change - * @returns the path to the file that was created, or undefined if no file was written - */ - public static createEmptyChangeFiles( - rushConfiguration: RushConfiguration, - projectName: string, - emailAddress: string): string | undefined { - const projectInfo: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); - if (projectInfo && projectInfo.shouldPublish) { - - const changefile: IChangeFile = { // eslint-disable-line @typescript-eslint/no-explicit-any - 'changes': [{ - comment: '', - packageName: projectName, - type: 'none' - }], - 'packageName': projectName, - 'email': emailAddress - }; - - return new ChangeFile(changefile, rushConfiguration).writeSync(); - } - return undefined; - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/api/Changelog.ts b/apps/rush-lib/src/api/Changelog.ts deleted file mode 100644 index 5bdbc193ade..00000000000 --- a/apps/rush-lib/src/api/Changelog.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Interface respresenting a changelog json object for a package used to represent the parsed - * content of CHANGELOG.json - */ -export interface IChangelog { - /** - * Name of the project - */ - name: string; - - /** - * Entries within the changelog corresponding to each published version. - */ - entries: IChangeLogEntry[]; -} - -/** - * Interface representing a single published entry in the changelog. - */ -export interface IChangeLogEntry { - /** - * Published version for the entry. (Example: 1.0.0) - */ - version: string; - - /** - * Git tag used to identify the published commit. (Example: b7f55611e54910327a206476b185265498c66acf) - */ - tag: string; - - /** - * The UTC date when the publish was applied. (Example: Fri, 02 Dec 2016 22:27:16 GMT) - */ - date: string | undefined; - - /** - * Comments for the entry, where key respresents the ChangeType string (Example: major) - */ - comments: { - /** Describes changes which cause a patch-level SemVer bump */ - patch?: IChangeLogComment[]; - /** Describes changes which cause a minor-level SemVer bump */ - minor?: IChangeLogComment[]; - /** Describes changes which cause a major-level SemVer bump */ - major?: IChangeLogComment[]; - /** Describes changes to the package's dependencies */ - dependency?: IChangeLogComment[]; - /** Describe changes that do not have version information */ - none?: IChangeLogComment[]; - }; -} - -/** - * Interface representing a single changelog comment within an entry. - */ -export interface IChangeLogComment { - /** - * The given comment. (supports markdown.) - */ - comment: string; - - /** - * The author, if applicable, that created the change request. - */ - author?: string; - - /** - * The commit, if applicable, including the change request. - */ - commit?: string; -} diff --git a/apps/rush-lib/src/api/CommandLineConfiguration.ts b/apps/rush-lib/src/api/CommandLineConfiguration.ts deleted file mode 100644 index 8bfa4380fd3..00000000000 --- a/apps/rush-lib/src/api/CommandLineConfiguration.ts +++ /dev/null @@ -1,150 +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 { - JsonFile, - JsonSchema, - FileSystem -} from '@rushstack/node-core-library'; - -import { RushConstants } from '../logic/RushConstants'; - -import { - CommandJson, - ICommandLineJson, - ParameterJson -} from './CommandLineJson'; - -/** - * Custom Commands and Options for the Rush Command Line - */ -export class CommandLineConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '../schemas/command-line.schema.json') - ); - - public readonly commands: CommandJson[] = []; - public readonly parameters: ParameterJson[] = []; - - public static readonly defaultBuildCommandJson: CommandJson = { - commandKind: RushConstants.bulkCommandKind, - name: RushConstants.buildCommandName, - summary: 'Build all projects that haven\'t been built, or have changed since they were last built.', - description: 'This command is similar to "rush rebuild", except that "rush build" performs' - + ' an incremental build. In other words, it only builds projects whose source files have changed' - + ' since the last successful build. The analysis requires a Git working tree, and only considers' - + ' source files that are tracked by Git and whose path is under the project folder. (For more details' - + ' about this algorithm, see the documentation for the "package-deps-hash" NPM package.) The incremental' - + ' build state is tracked in a per-project folder called ".rush/temp" which should NOT be added to Git. The' - + ' build command is tracked by the "arguments" field in the "package-deps_build.json" file contained' - + ' therein; a full rebuild is forced whenever the command has changed (e.g. "--production" or not).', - enableParallelism: true, - ignoreMissingScript: false, - ignoreDependencyOrder: false, - incremental: true, - allowWarningsInSuccessfulBuild: false, - safeForSimultaneousRushProcesses: false - }; - - public static readonly defaultRebuildCommandJson: CommandJson = { - commandKind: RushConstants.bulkCommandKind, - name: RushConstants.rebuildCommandName, - summary: 'Clean and rebuild the entire set of projects', - description: 'This command assumes that the package.json file for each project contains' - + ' a "scripts" entry for "npm run build" that performs a full clean build.' - + ' Rush invokes this script to build each project that is registered in rush.json.' - + ' Projects are built in parallel where possible, but always respecting the dependency' - + ' graph for locally linked projects. The number of simultaneous processes will be' - + ' based on the number of machine cores unless overridden by the --parallelism flag.' - + ' (For an incremental build, see "rush build" instead of "rush rebuild".)', - enableParallelism: true, - ignoreMissingScript: false, - ignoreDependencyOrder: false, - incremental: false, - allowWarningsInSuccessfulBuild: false, - safeForSimultaneousRushProcesses: false - }; - - /** - * Use CommandLineConfiguration.loadFromFile() - */ - private constructor(commandLineJson: ICommandLineJson | undefined) { - if (commandLineJson) { - if (commandLineJson.commands) { - for (const command of commandLineJson.commands) { - this.commands.push(command); - } - } - - if (commandLineJson.parameters) { - for (const parameter of commandLineJson.parameters) { - this.parameters.push(parameter); - - // Do some basic validation - switch (parameter.parameterKind) { - case 'choice': - const alternativeNames: string[] = parameter.alternatives.map(x => x.name); - - if (parameter.defaultValue && alternativeNames.indexOf(parameter.defaultValue) < 0) { - throw new Error(`In ${RushConstants.commandLineFilename}, the parameter "${parameter.longName}",` - + ` specifies a default value "${parameter.defaultValue}"` - + ` which is not one of the defined alternatives: "${alternativeNames.toString()}"`); - } - break; - } - } - } - } - } - - /** - * Loads the configuration from the specified file and applies any omitted default build - * settings. If the file does not exist, then an empty default instance is returned. - * If the file contains errors, then an exception is thrown. - */ - public static loadFromFileOrDefault(jsonFilename: string): CommandLineConfiguration { - let commandLineJson: ICommandLineJson | undefined = undefined; - if (FileSystem.exists(jsonFilename)) { - commandLineJson = JsonFile.load(jsonFilename); - - // 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 && 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.bulkCommandKind: { - switch (command.name) { - case RushConstants.buildCommandName: { - commandDefaultDefinition = CommandLineConfiguration.defaultBuildCommandJson - break; - } - - case RushConstants.rebuildCommandName: { - commandDefaultDefinition = CommandLineConfiguration.defaultRebuildCommandJson; - break; - } - } - break; - } - } - - // Merge the default parameters into the repo-specified parameters - commandLineJson.commands[i] = { - ...commandDefaultDefinition, - ...command - } - } - - CommandLineConfiguration._jsonSchema.validateObject(commandLineJson, jsonFilename); - } - } - - return new CommandLineConfiguration(commandLineJson); - } -} diff --git a/apps/rush-lib/src/api/CommandLineJson.ts b/apps/rush-lib/src/api/CommandLineJson.ts deleted file mode 100644 index 80e4a289499..00000000000 --- a/apps/rush-lib/src/api/CommandLineJson.ts +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * "baseCommand" from command-line.schema.json - */ -export interface IBaseCommandJson { - commandKind: 'bulk' | 'global'; - name: string; - summary: string; - /** - * If omitted, the summary will be used instead. - */ - description?: string; - safeForSimultaneousRushProcesses: boolean; -} - -/** - * "bulkCommand" from command-line.schema.json - */ -export interface IBulkCommandJson extends IBaseCommandJson { - commandKind: 'bulk'; - enableParallelism: boolean; - ignoreDependencyOrder?: boolean; - ignoreMissingScript?: boolean; - incremental?: boolean; - allowWarningsInSuccessfulBuild?: boolean; -} - -/** - * "globalCommand" from command-line.schema.json - */ -export interface IGlobalCommandJson extends IBaseCommandJson { - commandKind: 'global'; - shellCommand: string; -} - -export type CommandJson = IBulkCommandJson | IGlobalCommandJson; - -/** - * "baseParameter" from command-line.schema.json - */ -export interface IBaseParameterJson { - parameterKind: 'flag' | 'choice' | 'string'; - longName: string; - shortName?: string; - description: string; - associatedCommands: string[]; - required?: boolean; -} - -/** - * "flagParameter" from command-line.schema.json - */ -export interface IFlagParameterJson extends IBaseParameterJson { - parameterKind: 'flag'; -} - -/** - * Part of "choiceParameter" from command-line.schema.json - */ -export interface IChoiceParameterAlternativeJson { - name: string; - description: string; -} - -/** - * "choiceParameter" from command-line.schema.json - */ -export interface IChoiceParameterJson extends IBaseParameterJson { - parameterKind: 'choice'; - alternatives: IChoiceParameterAlternativeJson[]; - defaultValue?: string; -} - -export interface IStringParameterJson extends IBaseParameterJson { - parameterKind: 'string'; - argumentName: string; -} - -export type ParameterJson = IFlagParameterJson | IChoiceParameterJson | IStringParameterJson; - -/** - * Interfaces for the file format described by command-line.schema.json - */ -export interface ICommandLineJson { - commands?: CommandJson[]; - parameters?: ParameterJson[]; -} diff --git a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts b/apps/rush-lib/src/api/CommonVersionsConfiguration.ts deleted file mode 100644 index 8d53aa18bac..00000000000 --- a/apps/rush-lib/src/api/CommonVersionsConfiguration.ts +++ /dev/null @@ -1,269 +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 { - JsonFile, - JsonSchema, - MapExtensions, - PackageName, - ProtectableMap, - FileSystem -} from '@rushstack/node-core-library'; -import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; - -/** - * Part of the ICommonVersionsJson structure. - */ -export declare interface ICommonVersionsJsonVersionMap { - /** - * The key is the name of a dependency. The value is a Semantic Versioning (SemVer) - * range specifier. - */ - [dependencyName: string]: string; -} - -/** - * Part of the ICommonVersionsJson structure. - */ -export declare interface ICommonVersionsJsonVersionsMap { - /** - * The key is the name of a dependency. The value is a list of Semantic Versioning (SemVer) - * range specifiers. - */ - [dependencyName: string]: string[]; -} - -/** - * Describes the file structure for the "common/config/rush/common-versions.json" config file. - */ -interface ICommonVersionsJson { - $schema?: string; - - preferredVersions?: ICommonVersionsJsonVersionMap; - - implicitlyPreferredVersions?: boolean; - - xstitchPreferredVersions?: ICommonVersionsJsonVersionMap; - - allowedAlternativeVersions?: ICommonVersionsJsonVersionsMap; -} - -/** - * 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.fromFile( - path.join(__dirname, '../schemas/common-versions.schema.json')); - - private _filePath: string; - private _preferredVersions: ProtectableMap; - private _implicitlyPreferredVersions: boolean | undefined; - private _xstitchPreferredVersions: ProtectableMap; - private _allowedAlternativeVersions: ProtectableMap; - private _modified: boolean; - - private constructor(commonVersionsJson: ICommonVersionsJson | undefined, filePath: string) { - this._preferredVersions = new ProtectableMap( - { onSet: this._onSetPreferredVersions.bind(this) }); - - if (commonVersionsJson && commonVersionsJson.implicitlyPreferredVersions !== undefined) { - this._implicitlyPreferredVersions = commonVersionsJson.implicitlyPreferredVersions; - } else { - this._implicitlyPreferredVersions = undefined; - } - - this._xstitchPreferredVersions = new ProtectableMap( - { onSet: this._onSetPreferredVersions.bind(this) }); - - this._allowedAlternativeVersions = new ProtectableMap( - { onSet: this._onSetAllowedAlternativeVersions.bind(this) }); - - if (commonVersionsJson) { - try { - CommonVersionsConfiguration._deserializeTable(this.preferredVersions, - commonVersionsJson.preferredVersions); - CommonVersionsConfiguration._deserializeTable(this.xstitchPreferredVersions, - commonVersionsJson.xstitchPreferredVersions); - CommonVersionsConfiguration._deserializeTable(this.allowedAlternativeVersions, - commonVersionsJson.allowedAlternativeVersions); - } catch (e) { - throw new Error(`Error loading "${path.basename(filePath)}": ${e.message}`); - } - } - this._filePath = filePath; - } - - /** - * 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 loadFromFile(jsonFilename: string): CommonVersionsConfiguration { - let commonVersionsJson: ICommonVersionsJson | undefined = undefined; - - if (FileSystem.exists(jsonFilename)) { - commonVersionsJson = JsonFile.loadAndValidate(jsonFilename, CommonVersionsConfiguration._jsonSchema); - } - - return new CommonVersionsConfiguration(commonVersionsJson, jsonFilename); - } - - private static _deserializeTable(map: Map, object: {} | undefined): void { - if (object) { - for (const key of Object.getOwnPropertyNames(object)) { - const value: TValue = object[key]; - map.set(key, value); - } - } - } - - private static _serializeTable(map: Map): { } { - const table: { } = { }; - - const keys: string[] = [...map.keys()]; - keys.sort(); - for (const key of keys) { - table[key] = map.get(key); - } - - return table; - } - - /** - * Get the absolute file path of the common-versions.json file. - */ - public get filePath(): string { - return this._filePath; - } - - /** - * Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile(). - */ - public save(): boolean { - if (this._modified) { - JsonFile.save(this._serialize(), this._filePath, { updateExistingFile: true }); - this._modified = false; - return true; - } - - return false; - } - - /** - * A table that specifies a "preferred version" for a given NPM package. This feature is typically used - * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. - * - * @remarks - * The "preferredVersions" value can be any SemVer range specifier (e.g. `~1.2.3`). Rush injects these values into - * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager - * will calculate versions. The specific effect depends on your package manager. Generally it will have no - * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be - * achieved using the pnpmfile.js hook. See the Rush documentation for more details. - * - * After modifying this field, it's recommended to run `rush update --full` so that the package manager - * will recalculate all version selections. - */ - public get preferredVersions(): Map { - return this._preferredVersions.protectedView; - } - - /** - * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, - * except in cases where different projects specify different version ranges for a given dependency. For older - * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause - * trouble for indirect dependencies with incompatible peerDependencies ranges. - * - * If the value is `undefined`, then the default value is `true`. - */ - public get implicitlyPreferredVersions(): boolean | undefined { - return this._implicitlyPreferredVersions; - } - - /** - * A table of specifies preferred versions maintained by the XStitch tool. - * - * @remarks - * This property has the same behavior as the "preferredVersions" property, except these entries - * are automatically managed by the XStitch tool. It is an error for the same dependency name - * to appear in both tables. - */ - public get xstitchPreferredVersions(): Map { - return this._xstitchPreferredVersions.protectedView; - } - - /** - * A table that stores, for a given dependency, a list of SemVer ranges that will be accepted - * by "rush check" in addition to the normal version range. - * - * @remarks - * The "rush check" command can be used to enforce that every project in the repo - * must specify the same SemVer range for a given dependency. However, sometimes - * exceptions are needed. The allowedAlternativeVersions table allows you to list - * other SemVer ranges that will be accepted by "rush check" for a given dependency. - * Note that the normal version range (as inferred by looking at all projects in the repo) - * should NOT be included in this list. - */ - public get allowedAlternativeVersions(): Map> { - return this._allowedAlternativeVersions.protectedView; - } - - /** - * Returns the union of preferredVersions and xstitchPreferredVersions. - */ - public getAllPreferredVersions(): Map { - const allPreferredVersions: Map = new Map(); - MapExtensions.mergeFromMap(allPreferredVersions, this.preferredVersions); - MapExtensions.mergeFromMap(allPreferredVersions, this.xstitchPreferredVersions); - return allPreferredVersions; - } - - private _onSetPreferredVersions(source: ProtectableMap, key: string, value: string): string { - PackageName.validate(key); - - if (source === this._preferredVersions) { - if (this._xstitchPreferredVersions.has(key)) { - throw new Error(`The package "${key}" cannot be added to preferredVersions because it was already` - + ` added to xstitchPreferredVersions`); - } - } else { - if (this._preferredVersions.has(key)) { - throw new Error(`The package "${key}" cannot be added to xstitchPreferredVersions because it was already` - + ` added to preferredVersions`); - } - } - - this._modified = true; - - return value; - } - - private _onSetAllowedAlternativeVersions(source: ProtectableMap, key: string, value: string): string { - PackageName.validate(key); - - this._modified = true; - - return value; - } - - private _serialize(): ICommonVersionsJson { - const result: ICommonVersionsJson = { - $schema: JsonSchemaUrls.commonVersions - }; - - if (this._preferredVersions.size) { - result.preferredVersions = CommonVersionsConfiguration._serializeTable(this.preferredVersions); - } - - if (this._xstitchPreferredVersions.size) { - result.xstitchPreferredVersions = CommonVersionsConfiguration._serializeTable(this.xstitchPreferredVersions); - } - - if (this._allowedAlternativeVersions.size) { - result.allowedAlternativeVersions = CommonVersionsConfiguration._serializeTable(this.allowedAlternativeVersions); - } - - return result; - } -} diff --git a/apps/rush-lib/src/api/EnvironmentConfiguration.ts b/apps/rush-lib/src/api/EnvironmentConfiguration.ts deleted file mode 100644 index 63afdf1dcc6..00000000000 --- a/apps/rush-lib/src/api/EnvironmentConfiguration.ts +++ /dev/null @@ -1,233 +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'; -import * as path from 'path'; -import { trueCasePathSync } from 'true-case-path'; - -export interface IEnvironmentConfigurationInitializeOptions { - doNotNormalizePaths?: boolean; -} - -/** - * Names of environment variables used by Rush. - * @public - */ -export const enum EnvironmentVariableNames { - /** - * This variable overrides the temporary folder used by Rush. - * The default value is "common/temp" under the repository root. - */ - RUSH_TEMP_FOLDER = 'RUSH_TEMP_FOLDER', - - /** - * This variable overrides the version of Rush that will be installed by - * the version selector. The default value is determined by the "rushVersion" - * field from rush.json. - */ - RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION', - - /** - * If this variable is set to "true", Rush will not fail the build when running a version - * of Node that does not match the criteria specified in the "nodeSupportedVersionRange" - * field from rush.json. - */ - RUSH_ALLOW_UNSUPPORTED_NODEJS = 'RUSH_ALLOW_UNSUPPORTED_NODEJS', - - /** - * This variable selects a specific installation variant for Rush to use when installing - * and linking package dependencies. For more information, see this article: - * https://rushjs.io/pages/advanced/installation_variants/ - */ - RUSH_VARIANT = 'RUSH_VARIANT', - - /** - * If this variable is set to "true", Rush will create symlinks with absolute paths instead - * of relative paths. This can be necessary when a repository is moved during a build or - * if parts of a repository are moved into a sandbox. - */ - RUSH_ABSOLUTE_SYMLINKS = 'RUSH_ABSOLUTE_SYMLINKS', - - /** - * When using PNPM as the package manager, this variable can be used to configure the path that - * PNPM will use as the store directory. - * - * If a relative path is used, then the store path will be resolved relative to the process's - * current working directory. An absolute path is recommended. - */ - RUSH_PNPM_STORE_PATH = 'RUSH_PNPM_STORE_PATH' -} - -/** - * Provides Rush-specific environment variable data. All Rush environment variables must start with "RUSH_". This class - * is designed to be used by RushConfiguration. - * - * @remarks - * Initialize will throw if any unknown parameters are present. - */ -export class EnvironmentConfiguration { - private static _hasBeenInitialized: boolean = false; - - private static _rushTempFolderOverride: string | undefined; - - private static _absoluteSymlinks: boolean = false; - - private static _allowUnsupportedNodeVersion: boolean = false; - - private static _pnpmStorePathOverride: string | undefined; - - /** - * An override for the common/temp folder path. - */ - public static get rushTempFolderOverride(): string | undefined { - EnvironmentConfiguration._ensureInitialized(); - return EnvironmentConfiguration._rushTempFolderOverride; - } - - /** - * If "true", create symlinks with absolute paths instead of relative paths. - * See {@link EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS} - */ - public static get absoluteSymlinks(): boolean { - EnvironmentConfiguration._ensureInitialized(); - return EnvironmentConfiguration._absoluteSymlinks; - } - - /** - * If this environment variable is set to "true", the Node.js version check will print a warning - * instead of causing a hard error if the environment's Node.js version doesn't match the - * version specifier in `rush.json`'s "nodeSupportedVersionRange" property. - * - * See {@link EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS}. - */ - public static get allowUnsupportedNodeVersion(): boolean { - EnvironmentConfiguration._ensureInitialized(); - return EnvironmentConfiguration._allowUnsupportedNodeVersion; - } - - /** - * An override for the PNPM store path, if `pnpmStore` configuration is set to 'path' - * See {@link EnvironmentVariableNames.RUSH_PNPM_STORE_PATH} - */ - public static get pnpmStorePathOverride(): string | undefined { - EnvironmentConfiguration._ensureInitialized(); - return EnvironmentConfiguration._pnpmStorePathOverride; - } - - /** - * Reads and validates environment variables. If any are invalid, this function will throw. - */ - public static initialize(options: IEnvironmentConfigurationInitializeOptions = {}): void { - EnvironmentConfiguration.reset(); - - const unknownEnvVariables: string[] = []; - for (const envVarName in process.env) { - 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; - switch (normalizedEnvVarName) { - case EnvironmentVariableNames.RUSH_TEMP_FOLDER: { - EnvironmentConfiguration._rushTempFolderOverride = (value && !options.doNotNormalizePaths) - ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value - : value; - break; - } - - case EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS: { - EnvironmentConfiguration._absoluteSymlinks = value === 'true'; - break; - } - - case EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS: { - EnvironmentConfiguration._allowUnsupportedNodeVersion = value === 'true'; - break; - } - - case EnvironmentVariableNames.RUSH_PNPM_STORE_PATH: { - EnvironmentConfiguration._pnpmStorePathOverride = (value && !options.doNotNormalizePaths) - ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value - : value; - break; - } - - case EnvironmentVariableNames.RUSH_PREVIEW_VERSION: - case EnvironmentVariableNames.RUSH_VARIANT: - // Handled by @microsoft/rush front end - break; - default: - unknownEnvVariables.push(envVarName); - break; - } - } - } - - // This strictness intends to catch mistakes where variables are misspelled or not used correctly. - if (unknownEnvVariables.length > 0) { - throw new Error( - 'The following environment variables were found with the "RUSH_" prefix, but they are not ' + - `recognized by this version of Rush: ${unknownEnvVariables.join(', ')}` - ); - } - - EnvironmentConfiguration._hasBeenInitialized = true; - } - - /** - * Resets EnvironmentConfiguration into an un-initialized state. - */ - public static reset(): void { - EnvironmentConfiguration._rushTempFolderOverride = undefined; - - EnvironmentConfiguration._hasBeenInitialized = false; - } - - private static _ensureInitialized(): void { - if (!EnvironmentConfiguration._hasBeenInitialized) { - throw new Error('The EnvironmentConfiguration must be initialized before values can be accessed.'); - } - } - - /** - * 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 - } - } - - return undefined; - } -} diff --git a/apps/rush-lib/src/api/EventHooks.ts b/apps/rush-lib/src/api/EventHooks.ts deleted file mode 100644 index 1ff99d0844a..00000000000 --- a/apps/rush-lib/src/api/EventHooks.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { IEventHooksJson } from './RushConfiguration'; - -/** - * Events happen during Rush runs. - * @beta - */ -export enum Event { - /** - * Pre Rush install event - */ - preRushInstall = 1, - /** - * Post Rush install event - */ - postRushInstall = 2, - /** - * Pre Rush build event - */ - preRushBuild = 3, - /** - * Post Rush build event - */ - postRushBuild = 4 -} - -/** - * This class represents Rush event hooks configured for this repo. - * Hooks are customized script actions that Rush executes when specific events occur. - * The actions are expressed as a command-line that is executed using the operating system shell. - * @beta - */ -export class EventHooks { - private _hooks: Map; - - /** - * @internal - */ - public constructor(eventHooksJson: IEventHooksJson) { - this._hooks = new Map(); - Object.getOwnPropertyNames(eventHooksJson).forEach((name) => { - const eventName: Event = Event[name]; - if (eventName) { - const foundHooks: string[] = []; - if (eventHooksJson[name]) { - eventHooksJson[name].forEach((hook) => { - foundHooks.push(hook); - }); - } - this._hooks.set(eventName, foundHooks); - } - }); - } - - /** - * Return all the scripts associated with the specified event. - * @param event - Rush event - */ - public get(event: Event): string[] { - return this._hooks.get(event) || []; - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/api/ExperimentsConfiguration.ts b/apps/rush-lib/src/api/ExperimentsConfiguration.ts deleted file mode 100644 index 421379d9cea..00000000000 --- a/apps/rush-lib/src/api/ExperimentsConfiguration.ts +++ /dev/null @@ -1,60 +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 { - JsonFile, - JsonSchema, - FileSystem -} from '@rushstack/node-core-library'; - -/** - * This interface represents the raw experiments.json file which allows repo - * maintainers to enable and disable experimental Rush features. - * @beta - */ -export interface IExperimentsJson { - /** - * If this setting is enabled, incremental builds should use repo-wide dependency tracking - * instead of project-specific tracking. - */ - legacyIncrementalBuildDependencyDetection?: boolean; -} - -/** - * Use this class to load the "common/config/rush/experiments.json" config file. - * This file allows repo maintainers to enable and disable experimental Rush features. - * @beta - */ -export class ExperimentsConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromFile( - path.resolve(__dirname, '..', 'schemas', 'experiments.schema.json') - ); - - private _experimentConfiguration: IExperimentsJson; - private _jsonFileName: string; - - /** - * @internal - */ - public constructor(jsonFileName: string) { - this._jsonFileName = jsonFileName; - this._experimentConfiguration = {}; - - if (!FileSystem.exists(this._jsonFileName)) { - this._experimentConfiguration = {}; - } else { - this._experimentConfiguration = JsonFile.loadAndValidate( - this._jsonFileName, - ExperimentsConfiguration._jsonSchema - ); - } - } - - /** - * Get the experiments configuration. - */ - public get configuration(): Readonly { - return this._experimentConfiguration; - } -} diff --git a/apps/rush-lib/src/api/LastInstallFlag.ts b/apps/rush-lib/src/api/LastInstallFlag.ts deleted file mode 100644 index 4a27a9bc07a..00000000000 --- a/apps/rush-lib/src/api/LastInstallFlag.ts +++ /dev/null @@ -1,110 +0,0 @@ -import * as path from 'path'; -import * as _ from 'lodash'; -import { FileSystem, JsonFile, JsonObject } from '@rushstack/node-core-library'; - -import { PackageManagerName } from './packageManager/PackageManager' - -export const LAST_INSTALL_FLAG_FILE_NAME: string = 'last-install.flag'; - -/** - * A helper class for managing last-install flags, which are persistent and - * indicate that something installed in the folder was successfully completed. - * It also compares state, so that if something like the Node.js version has changed, - * it can invalidate the last install. - * @internal - */ -export class LastInstallFlag { - private _path: string; - private _state: JsonObject; - - /** - * Creates a new LastInstall flag - * @param folderPath - the folder that this flag is managing - * @param state - optional, the state that should be managed or compared - */ - public constructor(folderPath: string, state: JsonObject = {}) { - this._path = path.join(folderPath, LAST_INSTALL_FLAG_FILE_NAME); - this._state = state; - } - - /** - * Returns true if the file exists and the contents match the current state. - */ - public isValid(): boolean { - return this._isValid(false); - } - - /** - * Same as isValid(), but with an additional check: If the current state is not equal to the previous - * state, and an the current state causes an error, then throw an exception with a friendly message. - */ - public checkValidAndReportStoreIssues(): boolean { - return this._isValid(true); - } - - private _isValid(checkValidAndReportStoreIssues: boolean): boolean { - if (!FileSystem.exists(this._path)) { - return false; - } - - let oldState: JsonObject; - try { - oldState = JsonFile.load(this._path); - } catch (err) { - return false; - } - - const newState: JsonObject = this._state; - - if (!_.isEqual(oldState, newState)) { - if (checkValidAndReportStoreIssues) { - const pkgManager: PackageManagerName = newState.packageManager; - if (pkgManager === 'pnpm') { - if ( - ( // Only throw an error if the package manager hasn't changed from PNPM - oldState.packageManager === pkgManager - ) && ( // Throw if the store path changed - oldState.storePath && - oldState.storePath !== newState.storePath - ) - ) { - const oldStorePath: string = oldState.storePath || ''; - const newStorePath: string = newState.storePath || ''; - - throw new Error("Current PNPM store path does not match the last one used." + - " This may cause inconsistency in your builds.\n\n" + - "If you wish to install with the new store path, please run \"rush update --purge\"\n\n" + - `Old Path: ${oldStorePath}\n` + - `New Path: ${newStorePath}`); - } - } - } - return false; - } - - return true; - } - - /** - * Writes the flag file to disk with the current state - */ - public create(): void { - JsonFile.save(this._state, this._path, { - ensureFolderExists: true - }); - } - - /** - * Removes the flag file - */ - public clear(): void { - FileSystem.deleteFile(this._path); - } - - /** - * Returns the full path to the flag file - */ - public get path(): string { - return this._path; - } -} diff --git a/apps/rush-lib/src/api/PackageJsonEditor.ts b/apps/rush-lib/src/api/PackageJsonEditor.ts deleted file mode 100644 index f308bc7415c..00000000000 --- a/apps/rush-lib/src/api/PackageJsonEditor.ts +++ /dev/null @@ -1,253 +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 semver from 'semver'; - -import { - IPackageJson, - JsonFile, - Sort -} from '@rushstack/node-core-library'; - -/** - * @beta - */ -export const enum DependencyType { - Regular = 'dependencies', - Dev = 'devDependencies', - Optional = 'optionalDependencies', - Peer = 'peerDependencies' -} - -/** - * @beta - */ -export class PackageJsonDependency { - private _type: DependencyType; - private _name: string; - private _version: string; - private _onChange: () => void; - - public constructor(name: string, - version: string, - type: DependencyType, - onChange: () => void) { - this._name = name; - this._version = version; - this._type = type; - this._onChange = onChange; - } - - public get name(): string { - return this._name; - } - - public get version(): string { - return this._version; - } - - public setVersion(newVersion: string): void { - if (!semver.valid(newVersion) && !semver.validRange(newVersion)) { - throw new Error(`Cannot set version to invalid value: "${newVersion}"`); - } - this._version = newVersion; - this._onChange(); - } - - public get dependencyType(): DependencyType { - return this._type; - } -} - -/** - * @beta - */ -export class PackageJsonEditor { - private readonly _filePath: string; - private readonly _data: IPackageJson; - private readonly _dependencies: Map; - - // NOTE: The "devDependencies" section is tracked separately because sometimes people - // will specify a specific version for development, while *also* specifying a broader - // SemVer range in one of the other fields for consumers. Thus "dependencies", "optionalDependencies", - // and "peerDependencies" are mutually exclusive, but "devDependencies" is not. - private readonly _devDependencies: Map; - private _modified: boolean; - - private constructor(filepath: string, data: IPackageJson) { - this._filePath = filepath; - this._data = data; - this._modified = false; - - this._dependencies = new Map(); - this._devDependencies = 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 _onChange: () => void = this._onChange.bind(this); - - 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"`); - } - - this._dependencies.set(packageName, - new PackageJsonDependency(packageName, dependencies[packageName], DependencyType.Regular, _onChange)); - }); - - Object.keys(optionalDependencies || {}).forEach((packageName: string) => { - if (Object.prototype.hasOwnProperty.call(peerDependencies, packageName)) { - throw new Error(`The package "${packageName}" cannot be listed in both ` - + `"optionalDependencies" and "peerDependencies"`); - } - this._dependencies.set(packageName, - new PackageJsonDependency(packageName, optionalDependencies[packageName], DependencyType.Optional, _onChange) - ); - }); - - Object.keys(peerDependencies || {}).forEach((packageName: string) => { - this._dependencies.set(packageName, - new PackageJsonDependency(packageName, peerDependencies[packageName], DependencyType.Peer, _onChange)); - }); - - Object.keys(devDependencies || {}).forEach((packageName: string) => { - this._devDependencies.set(packageName, - new PackageJsonDependency(packageName, devDependencies[packageName], DependencyType.Dev, _onChange)); - }); - - Sort.sortMapKeys(this._dependencies); - Sort.sortMapKeys(this._devDependencies); - - } catch (e) { - throw new Error(`Error loading "${filepath}": ${e.message}`); - } - } - - public static load(filePath: string): PackageJsonEditor { - return new PackageJsonEditor(filePath, JsonFile.load(filePath)); - } - - public static fromObject(object: IPackageJson, filename: string): PackageJsonEditor { - return new PackageJsonEditor(filename, object); - } - - public get name(): string { - return this._data.name; - } - - public get version(): string { - return this._data.version; - } - - public get filePath(): string { - return this._filePath; - } - - /** - * The list of dependencies of type DependencyType.Regular, DependencyType.Optional, or DependencyType.Peer. - */ - public get dependencyList(): ReadonlyArray { - return [...this._dependencies.values()]; - } - - /** - * The list of dependencies of type DependencyType.Dev. - */ - public get devDependencyList(): ReadonlyArray { - return [...this._devDependencies.values()]; - } - - public tryGetDependency(packageName: string): PackageJsonDependency | undefined { - return this._dependencies.get(packageName); - } - - public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { - return this._devDependencies.get(packageName); - } - - public addOrUpdateDependency(packageName: string, newVersion: string, dependencyType: DependencyType): void { - const dependency: PackageJsonDependency = new PackageJsonDependency( - packageName, - newVersion, - dependencyType, - this._onChange.bind(this) - ); - - if (dependencyType === DependencyType.Regular || dependencyType === DependencyType.Optional) { - this._dependencies.set(packageName, dependency); - } else { - this._devDependencies.set(packageName, dependency); - } - this._modified = true; - } - - public saveIfModified(): boolean { - if (this._modified) { - JsonFile.save(this._normalize(), this._filePath, { updateExistingFile: true }); - this._modified = false; - return true; - } - return false; - } - - private _onChange(): void { - this._modified = true; - } - - private _normalize(): IPackageJson { - delete this._data.dependencies; - delete this._data.optionalDependencies; - delete this._data.peerDependencies; - delete this._data.devDependencies; - - const keys: string[] = [...this._dependencies.keys()].sort(); - - for (const packageName of keys) { - const dependency: PackageJsonDependency = this._dependencies.get(packageName)!; - - if (dependency.dependencyType === DependencyType.Regular) { - if (!this._data.dependencies) { - this._data.dependencies = {}; - } - this._data.dependencies[dependency.name] = dependency.version; - } - - if (dependency.dependencyType === DependencyType.Optional) { - if (!this._data.optionalDependencies) { - this._data.optionalDependencies = {}; - } - this._data.optionalDependencies[dependency.name] = dependency.version; - } - - if (dependency.dependencyType === DependencyType.Peer) { - if (!this._data.peerDependencies) { - this._data.peerDependencies = {}; - } - this._data.peerDependencies[dependency.name] = dependency.version; - } - } - - const devDependenciesKeys: string[] = [...this._devDependencies.keys()].sort(); - - for (const packageName of devDependenciesKeys) { - const dependency: PackageJsonDependency = this._devDependencies.get(packageName)!; - - if (!this._data.devDependencies) { - this._data.devDependencies = {}; - } - this._data.devDependencies[dependency.name] = dependency.version; - } - - return this._data; - } -} diff --git a/apps/rush-lib/src/api/Rush.ts b/apps/rush-lib/src/api/Rush.ts deleted file mode 100644 index 8f437d780e4..00000000000 --- a/apps/rush-lib/src/api/Rush.ts +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { EOL } from 'os'; -import * as colors from 'colors'; -import { PackageJsonLookup } from '@rushstack/node-core-library'; - -import { RushCommandLineParser } from '../cli/RushCommandLineParser'; -import { RushConstants } from '../logic/RushConstants'; -import { RushXCommandLine } from '../cli/RushXCommandLine'; -import { CommandLineMigrationAdvisor } from '../cli/CommandLineMigrationAdvisor'; -import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; - -/** - * Options to pass to the rush "launch" functions. - * - * @public - */ -export interface ILaunchOptions { - /** - * True if the tool was invoked from within a project with a rush.json file, otherwise false. We - * consider a project without a rush.json to be "unmanaged" and we'll print that to the command line when - * the tool is executed. This is mainly used for debugging purposes. - */ - isManaged: boolean; - - /** - * If true, the wrapper process already printed a warning that the version of Node.js hasn't been tested - * with this version of Rush, so we shouldn't print a similar error. - */ - alreadyReportedNodeTooNewError?: boolean; -} - -/** - * General operations for the Rush engine. - * - * @public - */ -export class Rush { - /** - * 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 - * and start a new Node.js process. - * - * @param launcherVersion - The version of the `@microsoft/rush` wrapper used to call invoke the CLI. - * - * @remarks - * Earlier versions of the rush frontend used a different API contract. In the old contract, - * the second argument was the `isManaged` value of the {@link ILaunchOptions} object. - * - * Even though this API isn't documented, it is still supported for legacy compatibility. - */ - public static launch(launcherVersion: string, arg: ILaunchOptions): void { - const options: ILaunchOptions = Rush._normalizeLaunchOptions(arg); - - Rush._printStartupBanner(options.isManaged); - - if (!CommandLineMigrationAdvisor.checkArgv(process.argv)) { - // The migration advisor recognized an obsolete command-line - process.exitCode = 1; - return; - } - - const parser: RushCommandLineParser = new RushCommandLineParser({ - alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError - }); - parser.execute().catch(console.error); // CommandLineParser.execute() should never reject the promise - } - - /** - * This API is used by the `@microsoft/rush` front end to launch the "rushx" command-line. - * Third-party tools should not use this API. Instead, they should execute the "rushx" binary - * and start a new Node.js process. - * - * @param launcherVersion - The version of the `@microsoft/rush` wrapper used to call invoke the CLI. - */ - public static launchRushX(launcherVersion: string, options: ILaunchOptions): void { - options = Rush._normalizeLaunchOptions(options); - - Rush._printStartupBanner(options.isManaged); - - RushXCommandLine._launchRushXInternal(launcherVersion, { ...options }); - } - - /** - * The currently executing version of the "rush-lib" library. - * This is the same as the Rush tool version for that release. - */ - public static get version(): string { - return PackageJsonLookup.loadOwnPackageJson(__dirname).version; - } - - /** - * 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; - } - - private static _printStartupBanner(isManaged: boolean): void { - const nodeVersion: string = process.versions.node; - const nodeReleaseLabel: string = (NodeJsCompatibility.isOddNumberedVersion) - ? 'unstable' - : (NodeJsCompatibility.isLtsVersion ? 'LTS' : 'pre-LTS'); - - console.log( - EOL + - colors.bold(`Rush Multi-Project Build Tool ${Rush.version}` + colors.yellow(isManaged ? '' : ' (unmanaged)')) + - colors.cyan(` - ${RushConstants.rushWebSiteUrl}`) + - EOL + - `Node.js version is ${nodeVersion} (${nodeReleaseLabel})` + - EOL - ); - } -} diff --git a/apps/rush-lib/src/api/RushConfiguration.ts b/apps/rush-lib/src/api/RushConfiguration.ts deleted file mode 100644 index 96c313a3199..00000000000 --- a/apps/rush-lib/src/api/RushConfiguration.ts +++ /dev/null @@ -1,1457 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/* eslint max-lines: off */ - -import * as path from 'path'; -import * as fs from 'fs'; -import * as semver from 'semver'; -import { - JsonFile, - JsonSchema, - Path, - PackageName, - FileSystem -} from '@rushstack/node-core-library'; -import { trueCasePathSync } from 'true-case-path'; - -import { Rush } from '../api/Rush'; -import { RushConfigurationProject, IRushConfigurationProjectJson } from './RushConfigurationProject'; -import { RushConstants } from '../logic/RushConstants'; -import { ApprovedPackagesPolicy } from './ApprovedPackagesPolicy'; -import { EventHooks } from './EventHooks'; -import { VersionPolicyConfiguration } from './VersionPolicyConfiguration'; -import { EnvironmentConfiguration } from './EnvironmentConfiguration'; -import { CommonVersionsConfiguration } from './CommonVersionsConfiguration'; -import { Utilities } from '../utilities/Utilities'; -import { PackageManagerName, PackageManager } from './packageManager/PackageManager'; -import { NpmPackageManager } from './packageManager/NpmPackageManager'; -import { YarnPackageManager } from './packageManager/YarnPackageManager'; -import { PnpmPackageManager } from './packageManager/PnpmPackageManager'; -import { ExperimentsConfiguration } from './ExperimentsConfiguration'; - -const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0'; -const DEFAULT_BRANCH: string = 'master'; -const DEFAULT_REMOTE: string = 'origin'; - -/** - * A list of known config filenames that are expected to appear in the "./common/config/rush" folder. - * To avoid confusion/mistakes, any extra files will be reported as an error. - */ -const knownRushConfigFilenames: string[] = [ - '.npmrc', - '.npmrc-publish', - RushConstants.pinnedVersionsFilename, - RushConstants.commonVersionsFilename, - RushConstants.browserApprovedPackagesFilename, - RushConstants.nonbrowserApprovedPackagesFilename, - RushConstants.versionPoliciesFilename, - RushConstants.commandLineFilename, - RushConstants.experimentsFilename -]; - -/** - * Part of IRushConfigurationJson. - */ -export interface IApprovedPackagesPolicyJson { - reviewCategories?: string[]; - ignoredNpmScopes?: string[]; -} - -/** - * Part of IRushConfigurationJson. - */ -export interface IRushGitPolicyJson { - allowedEmailRegExps?: string[]; - sampleEmail?: string; - versionBumpCommitMessage?: string; -} - -/** - * Part of IRushConfigurationJson. - * @beta - */ -export interface IEventHooksJson { - /** - * The list of scripts to run after every Rush build command finishes - */ - postRushBuild?: string[]; -} - -/** - * Part of IRushConfigurationJson. - */ -export interface IRushRepositoryJson { - /** - * The remote url of the repository. This helps "rush change" find the right remote to compare against. - */ - url?: string; - - /** - * The default branch name. This tells "rush change" which remote branch to compare against. - */ - defaultBranch?: string; - - /** - * The default remote. This tells "rush change" which remote to compare against if the remote URL is not set - * or if a remote matching the provided remote URL is not found. - */ - defaultRemote?: string; -} - -/** - * This represents the available PNPM store options - * @public - */ -export type PnpmStoreOptions = 'local' | 'global'; - -/** - * Options for the package manager. - * @public - */ -export interface IPackageManagerOptionsJsonBase { - /** - * Enviroment variables for the package manager - */ - environmentVariables?: IConfigurationEnvironment -} - -/** - * A collection of environment variables - * @public - */ -export interface IConfigurationEnvironment { - /** - * Environment variables - */ - [environmentVariableName: string]: IConfigurationEnvironmentVariable; -} - -/** - * Represents the value of an environment variable, and if the value should be overridden if the variable is set - * in the parent environment. - * @public - */ -export interface IConfigurationEnvironmentVariable { - /** - * Value of the environment variable - */ - value: string; - - /** - * Set to true to override the environment variable even if it is set in the parent environment. - * The default value is false. - */ - override?: boolean; -} - -/** - * Part of IRushConfigurationJson. - * @internal - */ -export interface INpmOptionsJson extends IPackageManagerOptionsJsonBase { -} - -/** - * Part of IRushConfigurationJson. - * @internal - */ -export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { - /** - * The store resolution method for PNPM to use - */ - pnpmStore?: PnpmStoreOptions; - /** - * Should PNPM fail if peer dependencies aren't installed? - */ - strictPeerDependencies?: boolean; - /** - * Defines the dependency resolution strategy PNPM will use - */ - resolutionStrategy?: ResolutionStrategy; -} - -/** - * Part of IRushConfigurationJson. - * @internal - */ -export interface IYarnOptionsJson extends IPackageManagerOptionsJsonBase { - /** - * If true, then Rush will add the "--ignore-engines" option when invoking Yarn. - * This allows "rush install" to succeed if there are dependencies with engines defined in - * package.json which do not match the current environment. - * - * The default value is false. - */ - ignoreEngines?: boolean; -} - -/** - * Options defining an allowed variant as part of IRushConfigurationJson. - */ -export interface IRushVariantOptionsJson { - variantName: string; - description: string; -} - -/** - * This represents the JSON data structure for the "rush.json" configuration file. - * See rush.schema.json for documentation. - */ -export interface IRushConfigurationJson { - $schema: string; - npmVersion?: string; - pnpmVersion?: string; - yarnVersion?: string; - rushVersion: string; - repository?: IRushRepositoryJson; - nodeSupportedVersionRange?: string; - suppressNodeLtsWarning?: boolean; - projectFolderMinDepth?: number; - projectFolderMaxDepth?: number; - approvedPackagesPolicy?: IApprovedPackagesPolicyJson; - gitPolicy?: IRushGitPolicyJson; - telemetryEnabled?: boolean; - projects: IRushConfigurationProjectJson[]; - eventHooks?: IEventHooksJson; - hotfixChangeEnabled?: boolean; - npmOptions?: INpmOptionsJson; - pnpmOptions?: IPnpmOptionsJson; - yarnOptions?: IYarnOptionsJson; - ensureConsistentVersions?: boolean; - variants?: IRushVariantOptionsJson[]; -} - -/** - * This represents the JSON data structure for the "rush-link.json" data file. - */ -export interface IRushLinkJson { - localLinks: { - [name: string]: string[] - }; -} - -/** - * This represents the JSON data structure for the "current-variant.json" data file. - */ -export interface ICurrentVariantJson { - variant: string | null; // Use `null` instead of `undefined` because `undefined` is not handled by JSON. -} - -/** - * Options that all package managers share. - * - * @public - */ -export abstract class PackageManagerOptionsConfigurationBase implements IPackageManagerOptionsJsonBase { - /** - * Enviroment variables for the package manager - */ - public readonly environmentVariables?: IConfigurationEnvironment - - /** @internal */ - protected constructor(json: IPackageManagerOptionsJsonBase) { - this.environmentVariables = json.environmentVariables; - } -} - -/** - * Options that are only used when the NPM package manager is selected. - * - * @remarks - * It is valid to define these options in rush.json even if the NPM package manager - * is not being used. - * - * @public - */ -export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { - /** @internal */ - public constructor(json: INpmOptionsJson) { - super(json); - } -} - -/** - * Options that are only used when the PNPM package manager is selected. - * - * @remarks - * It is valid to define these options in rush.json even if the PNPM package manager - * is not being used. - * - * @public - */ -export class PnpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { - /** - * The method used to resolve the store used by PNPM. - * - * @remarks - * Available options: - * - local: Use the standard Rush store path: common/temp/pnpm-store - * - global: Use PNPM's global store path - */ - public readonly pnpmStore: PnpmStoreOptions; - - /** - * The path for PNPM to use as the store directory. - * - * Will be overridden by environment variable RUSH_PNPM_STORE_PATH - */ - public readonly pnpmStorePath: string; - - /** - * If true, then Rush will add the "--strict-peer-dependencies" option when invoking PNPM. - * - * @remarks - * This causes "rush install" to fail if there are unsatisfied peer dependencies, which is - * an invalid state that can cause build failures or incompatible dependency versions. - * (For historical reasons, JavaScript package managers generally do not treat this invalid state - * as an error.) - * - * The default value is false. (For now.) - */ - public readonly strictPeerDependencies: boolean; - - /** - * The resolution strategy that will be used by PNPM. - * - * @remarks - * Configures the strategy used to select versions during installation. - * - * This feature requires PNPM version 3.1 or newer. It corresponds to the `--resolution-strategy` command-line - * option for PNPM. Possible values are `"fast"` and `"fewer-dependencies"`. PNPM's default is `"fast"`, but this - * may be incompatible with certain packages, for example the `@types` packages from DefinitelyTyped. Rush's default - * is `"fewer-dependencies"`, which causes PNPM to avoid installing a newer version if an already installed version - * can be reused; this is more similar to NPM's algorithm. - * - * For more background, see this discussion: {@link https://github.com/pnpm/pnpm/issues/1187} - */ - public readonly resolutionStrategy: ResolutionStrategy; - - /** @internal */ - public constructor(json: IPnpmOptionsJson, commonTempFolder: string) { - super(json); - this.pnpmStore = json.pnpmStore || 'local'; - if (EnvironmentConfiguration.pnpmStorePathOverride) { - this.pnpmStorePath = EnvironmentConfiguration.pnpmStorePathOverride; - } else if (this.pnpmStore === 'global') { - this.pnpmStorePath = ''; - } else { - this.pnpmStorePath = path.resolve(path.join(commonTempFolder, 'pnpm-store')); - } - this.strictPeerDependencies = !!json.strictPeerDependencies; - this.resolutionStrategy = json.resolutionStrategy || 'fewer-dependencies'; - } -} - -/** - * Options that are only used when the yarn package manager is selected. - * - * @remarks - * It is valid to define these options in rush.json even if the yarn package manager - * is not being used. - * - * @public - */ -export class YarnOptionsConfiguration extends PackageManagerOptionsConfigurationBase { - /** - * If true, then Rush will add the "--ignore-engines" option when invoking Yarn. - * This allows "rush install" to succeed if there are dependencies with engines defined in - * package.json which do not match the current environment. - * - * The default value is false. - */ - public readonly ignoreEngines: boolean; - - /** @internal */ - public constructor(json: IYarnOptionsJson) { - super(json); - this.ignoreEngines = !!json.ignoreEngines; - } -} - -/** - * Options for `RushConfiguration.tryFindRushJsonLocation`. - * @public - */ -export interface ITryFindRushJsonLocationOptions { - /** - * Whether to show verbose console messages. Defaults to false. - */ - showVerbose?: boolean; // Defaults to false (inverse of old `verbose` parameter) - - /** - * The folder path where the search will start. Defaults tot he current working directory. - */ - startingFolder?: string; // Defaults to cwd -} - -/** - * This represents the available PNPM resolution strategies as a string - * @public - */ -export type ResolutionStrategy = 'fewer-dependencies' | 'fast'; - -/** - * This represents the Rush configuration for a repository, based on the "rush.json" - * configuration file. - * @public - */ -export class RushConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, '../schemas/rush.schema.json')); - - private _rushJsonFile: string; - private _rushJsonFolder: string; - private _changesFolder: string; - private _commonFolder: string; - private _commonTempFolder: string; - private _commonScriptsFolder: string; - private _commonRushConfigFolder: string; - private _packageManager: PackageManagerName; - private _packageManagerWrapper: PackageManager; - private _npmCacheFolder: string; - private _npmTmpFolder: string; - private _yarnCacheFolder: string; - private _shrinkwrapFilename: string; - private _tempShrinkwrapFilename: string; - private _tempShrinkwrapPreinstallFilename: string; - private _rushLinkJsonFilename: string; - private _currentVariantJsonFilename: string; - private _packageManagerToolVersion: string; - private _packageManagerToolFilename: string; - private _projectFolderMinDepth: number; - private _projectFolderMaxDepth: number; - private _ensureConsistentVersions: boolean; - private _suppressNodeLtsWarning: boolean; - private _variants: { - [variantName: string]: boolean; - }; - - // "approvedPackagesPolicy" feature - private _approvedPackagesPolicy: ApprovedPackagesPolicy; - - // "gitPolicy" feature - private _gitAllowedEmailRegExps: string[]; - private _gitSampleEmail: string; - private _gitVersionBumpCommitMessage: string | undefined; - - // "hotfixChangeEnabled" feature - private _hotfixChangeEnabled: boolean; - - // Repository info - private _repositoryUrl: string | undefined; - private _repositoryDefaultBranch: string; - private _repositoryDefaultRemote: string; - - private _npmOptions: NpmOptionsConfiguration; - private _pnpmOptions: PnpmOptionsConfiguration; - private _yarnOptions: YarnOptionsConfiguration; - - // Rush hooks - private _eventHooks: EventHooks; - - private _telemetryEnabled: boolean; - - private _projects: RushConfigurationProject[]; - private _projectsByName: Map; - - private _versionPolicyConfiguration: VersionPolicyConfiguration; - private _experimentsConfiguration: ExperimentsConfiguration; - - /** - * Use RushConfiguration.loadFromConfigurationFile() or Use RushConfiguration.loadFromDefaultLocation() - * instead. - */ - private constructor(rushConfigurationJson: IRushConfigurationJson, rushJsonFilename: string) { - EnvironmentConfiguration.initialize(); - - if (rushConfigurationJson.nodeSupportedVersionRange) { - if (!semver.validRange(rushConfigurationJson.nodeSupportedVersionRange)) { - throw new Error('Error parsing the node-semver expression in the "nodeSupportedVersionRange"' - + ` field from rush.json: "${rushConfigurationJson.nodeSupportedVersionRange}"`); - } - if (!semver.satisfies(process.version, rushConfigurationJson.nodeSupportedVersionRange)) { - const message: string = `Your dev environment is running Node.js version ${process.version} which does` - + ` not meet the requirements for building this repository. (The rush.json configuration` - + ` requires nodeSupportedVersionRange="${rushConfigurationJson.nodeSupportedVersionRange}")`; - if (EnvironmentConfiguration.allowUnsupportedNodeVersion) { - console.warn(message); - } else { - throw new Error(message); - } - } - } - - this._rushJsonFile = rushJsonFilename; - this._rushJsonFolder = path.dirname(rushJsonFilename); - - this._commonFolder = path.resolve(path.join(this._rushJsonFolder, RushConstants.commonFolderName)); - - this._commonRushConfigFolder = path.join(this._commonFolder, 'config', 'rush'); - - this._commonTempFolder = EnvironmentConfiguration.rushTempFolderOverride || - path.join(this._commonFolder, RushConstants.rushTempFolderName); - - this._commonScriptsFolder = path.join(this._commonFolder, 'scripts'); - - this._npmCacheFolder = path.resolve(path.join(this._commonTempFolder, 'npm-cache')); - this._npmTmpFolder = path.resolve(path.join(this._commonTempFolder, 'npm-tmp')); - this._yarnCacheFolder = path.resolve(path.join(this._commonTempFolder, 'yarn-cache')); - - this._changesFolder = path.join(this._commonFolder, RushConstants.changeFilesFolderName); - - this._rushLinkJsonFilename = path.join(this._commonTempFolder, 'rush-link.json'); - this._currentVariantJsonFilename = path.join(this._commonTempFolder, 'current-variant.json'); - - this._suppressNodeLtsWarning = !!rushConfigurationJson.suppressNodeLtsWarning; - - this._ensureConsistentVersions = !!rushConfigurationJson.ensureConsistentVersions; - - const experimentsConfigFile: string = path.join( - this._commonRushConfigFolder, - RushConstants.experimentsFilename - ); - this._experimentsConfiguration = new ExperimentsConfiguration(experimentsConfigFile); - - this._npmOptions = new NpmOptionsConfiguration(rushConfigurationJson.npmOptions || {}); - this._pnpmOptions = new PnpmOptionsConfiguration(rushConfigurationJson.pnpmOptions || {}, - this._commonTempFolder); - this._yarnOptions = new YarnOptionsConfiguration(rushConfigurationJson.yarnOptions || {}); - - // TODO: Add an actual "packageManager" field in rush.json - const packageManagerFields: string[] = []; - - if (rushConfigurationJson.npmVersion) { - this._packageManager = 'npm'; - packageManagerFields.push('npmVersion'); - } - if (rushConfigurationJson.pnpmVersion) { - this._packageManager = 'pnpm'; - packageManagerFields.push('pnpmVersion'); - } - if (rushConfigurationJson.yarnVersion) { - this._packageManager = 'yarn'; - packageManagerFields.push('yarnVersion'); - } - - if (packageManagerFields.length === 0) { - throw new Error(`The rush.json configuration must specify one of: npmVersion, pnpmVersion, or yarnVersion`); - } - - if (packageManagerFields.length > 1) { - throw new Error(`The rush.json configuration cannot specify both ${packageManagerFields[0]}` - + ` and ${packageManagerFields[1]} `); - } - - if (this._packageManager === 'npm') { - this._packageManagerToolVersion = rushConfigurationJson.npmVersion!; - this._packageManagerWrapper = new NpmPackageManager(this._packageManagerToolVersion); - } else if (this._packageManager === 'pnpm') { - this._packageManagerToolVersion = rushConfigurationJson.pnpmVersion!; - this._packageManagerWrapper = new PnpmPackageManager(this._packageManagerToolVersion); - } else { - this._packageManagerToolVersion = rushConfigurationJson.yarnVersion!; - this._packageManagerWrapper = new YarnPackageManager(this._packageManagerToolVersion); - } - - this._shrinkwrapFilename = this._packageManagerWrapper.shrinkwrapFilename; - - this._tempShrinkwrapFilename = path.join( - this._commonTempFolder, this._shrinkwrapFilename - ); - this._packageManagerToolFilename = path.resolve(path.join( - this._commonTempFolder, `${this.packageManager}-local`, 'node_modules', '.bin', `${this.packageManager}` - )); - - /// From "C:\repo\common\temp\pnpm-lock.yaml" --> "C:\repo\common\temp\pnpm-lock-preinstall.yaml" - const parsedPath: path.ParsedPath = path.parse(this._tempShrinkwrapFilename); - this._tempShrinkwrapPreinstallFilename = path.join(parsedPath.dir, - parsedPath.name + '-preinstall' + parsedPath.ext); - - RushConfiguration._validateCommonRushConfigFolder( - this._commonRushConfigFolder, - this.packageManager, - this._shrinkwrapFilename - ); - - this._projectFolderMinDepth = rushConfigurationJson.projectFolderMinDepth !== undefined - ? rushConfigurationJson.projectFolderMinDepth : 1; - if (this._projectFolderMinDepth < 1) { - throw new Error('Invalid projectFolderMinDepth; the minimum possible value is 1'); - } - - this._projectFolderMaxDepth = rushConfigurationJson.projectFolderMaxDepth !== undefined - ? rushConfigurationJson.projectFolderMaxDepth : 2; - if (this._projectFolderMaxDepth < this._projectFolderMinDepth) { - throw new Error('The projectFolderMaxDepth cannot be smaller than the projectFolderMinDepth'); - } - - this._approvedPackagesPolicy = new ApprovedPackagesPolicy(this, rushConfigurationJson); - - this._gitAllowedEmailRegExps = []; - this._gitSampleEmail = ''; - if (rushConfigurationJson.gitPolicy) { - if (rushConfigurationJson.gitPolicy.sampleEmail) { - this._gitSampleEmail = rushConfigurationJson.gitPolicy.sampleEmail; - } - - if (rushConfigurationJson.gitPolicy.allowedEmailRegExps) { - this._gitAllowedEmailRegExps = rushConfigurationJson.gitPolicy.allowedEmailRegExps; - - if (this._gitSampleEmail.trim().length < 1) { - throw new Error('The rush.json file is missing the "sampleEmail" option, ' + - 'which is required when using "allowedEmailRegExps"'); - } - } - - if (rushConfigurationJson.gitPolicy.versionBumpCommitMessage) { - this._gitVersionBumpCommitMessage = rushConfigurationJson.gitPolicy.versionBumpCommitMessage; - } - } - - this._hotfixChangeEnabled = false; - if (rushConfigurationJson.hotfixChangeEnabled) { - this._hotfixChangeEnabled = rushConfigurationJson.hotfixChangeEnabled; - } - - - if (!rushConfigurationJson.repository) { - rushConfigurationJson.repository = {}; - } - - this._repositoryUrl = rushConfigurationJson.repository.url; - this._repositoryDefaultBranch = rushConfigurationJson.repository.defaultBranch || DEFAULT_BRANCH; - this._repositoryDefaultRemote = rushConfigurationJson.repository.defaultRemote || DEFAULT_REMOTE; - - this._telemetryEnabled = !!rushConfigurationJson.telemetryEnabled; - if (rushConfigurationJson.eventHooks) { - this._eventHooks = new EventHooks(rushConfigurationJson.eventHooks); - } - - const versionPolicyConfigFile: string = path.join( - this._commonRushConfigFolder, - RushConstants.versionPoliciesFilename - ); - this._versionPolicyConfiguration = new VersionPolicyConfiguration(versionPolicyConfigFile); - - this._projects = []; - this._projectsByName = new Map(); - - // We sort the projects array in alphabetical order. This ensures that the packages - // are processed in a deterministic order by the various Rush algorithms. - const sortedProjectJsons: IRushConfigurationProjectJson[] = rushConfigurationJson.projects.slice(0); - sortedProjectJsons.sort( - (a: IRushConfigurationProjectJson, b: IRushConfigurationProjectJson) => a.packageName.localeCompare(b.packageName) - ); - - const tempNamesByProject: Map - = RushConfiguration._generateTempNamesForProjects(sortedProjectJsons); - - for (const projectJson of sortedProjectJsons) { - const tempProjectName: string | undefined = tempNamesByProject.get(projectJson); - if (tempProjectName) { - const project: RushConfigurationProject = new RushConfigurationProject(projectJson, this, tempProjectName); - this._projects.push(project); - if (this._projectsByName.get(project.packageName)) { - throw new Error(`The project name "${project.packageName}" was specified more than once` - + ` in the rush.json configuration file.`); - } - this._projectsByName.set(project.packageName, project); - } - } - - for (const project of this._projects) { - project.cyclicDependencyProjects.forEach((cyclicDependencyProject: string) => { - if (!this.getProjectByName(cyclicDependencyProject)) { - throw new Error(`In rush.json, the "${cyclicDependencyProject}" project does not exist,` - + ` but was referenced by the cyclicDependencyProjects for ${project.packageName}`); - } - }); - - // Compute the downstream dependencies within the list of Rush projects. - this._populateDownstreamDependencies(project.packageJson.dependencies, project.packageName); - this._populateDownstreamDependencies(project.packageJson.devDependencies, project.packageName); - this._versionPolicyConfiguration.validate(this._projectsByName); - } - - const variants: { - [variantName: string]: boolean; - } = {}; - - if (rushConfigurationJson.variants) { - for (const variantOptions of rushConfigurationJson.variants) { - const { - variantName - } = variantOptions; - - if (variants[variantName]) { - throw new Error(`Duplicate variant named '${variantName}' specified in configuration.`); - } - - variants[variantName] = true; - } - } - - this._variants = variants; - } - - /** - * Loads the configuration data from an Rush.json configuration file and returns - * an RushConfiguration object. - */ - public static loadFromConfigurationFile(rushJsonFilename: string): RushConfiguration { - let resolvedRushJsonFilename: string = path.resolve(rushJsonFilename); - // Load the rush.json before we fix the casing. If the case is wrong on a case-sensitive filesystem, - // the next line show throw. - const rushConfigurationJson: IRushConfigurationJson = JsonFile.load(resolvedRushJsonFilename); - - try { - resolvedRushJsonFilename = trueCasePathSync(resolvedRushJsonFilename); - } catch (error) { - /* ignore errors from true-case-path */ - } - - // Check the Rush version *before* we validate the schema, since if the version is outdated - // then the schema may have changed. This should no longer be a problem after Rush 4.0 and the C2R wrapper, - // but we'll validate anyway. - const expectedRushVersion: string = rushConfigurationJson.rushVersion; - - const rushJsonBaseName: string = path.basename(resolvedRushJsonFilename); - - // If the version is missing or malformed, fall through and let the schema handle it. - if (expectedRushVersion && semver.valid(expectedRushVersion)) { - // Make sure the requested version isn't too old - if (semver.lt(expectedRushVersion, MINIMUM_SUPPORTED_RUSH_JSON_VERSION)) { - throw new Error(`${rushJsonBaseName} is version ${expectedRushVersion}, which is too old for this tool. ` + - `The minimum supported version is ${MINIMUM_SUPPORTED_RUSH_JSON_VERSION}.`); - } - - // Make sure the requested version isn't too new. - // - // If the major/minor versions are the same, then we consider the file to be compatible. - // This is somewhat lax, e.g. "5.0.2-dev.3" will be assumed to be loadable by rush-lib 5.0.0. - // - // IMPORTANT: Whenever a breaking change is introduced for one of the config files, we must - // increment the minor version number for Rush. - if (semver.major(Rush.version) !== semver.major(expectedRushVersion) - || semver.minor(Rush.version) !== semver.minor(expectedRushVersion)) { - - // If the major/minor are different, then make sure it's an older version. - if (semver.lt(Rush.version, expectedRushVersion)) { - throw new Error(`Unable to load ${rushJsonBaseName} because its RushVersion is` - + ` ${rushConfigurationJson.rushVersion}, whereas @microsoft/rush-lib is version ${Rush.version}.` - + ` Consider upgrading the library.`); - } - } - } - - RushConfiguration._jsonSchema.validateObject(rushConfigurationJson, resolvedRushJsonFilename); - - return new RushConfiguration(rushConfigurationJson, resolvedRushJsonFilename); - } - - public static loadFromDefaultLocation(options?: ITryFindRushJsonLocationOptions): RushConfiguration { - const rushJsonLocation: string | undefined = RushConfiguration.tryFindRushJsonLocation(options); - - if (rushJsonLocation) { - return RushConfiguration.loadFromConfigurationFile(rushJsonLocation); - } else { - throw Utilities.getRushConfigNotFoundError(); - } - } - - /** - * Find the rush.json location and return the path, or undefined if a rush.json can't be found. - */ - public static tryFindRushJsonLocation(options?: ITryFindRushJsonLocationOptions): string | undefined { - const optionsIn: ITryFindRushJsonLocationOptions = options || {}; - const verbose: boolean = optionsIn.showVerbose || false; - let currentFolder: string = optionsIn.startingFolder || process.cwd(); - - // Look upwards at parent folders until we find a folder containing rush.json - for (let i: number = 0; i < 10; ++i) { - const rushJsonFilename: string = path.join(currentFolder, 'rush.json'); - - if (FileSystem.exists(rushJsonFilename)) { - if (i > 0 && verbose) { - console.log('Found configuration in ' + rushJsonFilename); - } - - if (verbose) { - console.log(''); - } - - return rushJsonFilename; - } - - const parentFolder: string = path.dirname(currentFolder); - if (parentFolder === currentFolder) { - break; - } - - currentFolder = parentFolder; - } - - 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 _generateTempNamesForProjects(sortedProjectJsons: IRushConfigurationProjectJson[]): - Map { - - const tempNamesByProject: Map = - new Map(); - const usedTempNames: Set = new Set(); - - // NOTE: projectJsons was already sorted in alphabetical order by the caller. - for (const projectJson of sortedProjectJsons) { - // If the name is "@ms/MyProject", extract the "MyProject" part - const unscopedName: string = PackageName.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); - tempNamesByProject.set(projectJson, tempProjectName); - } - - return tempNamesByProject; - } - - /** - * 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, - packageManager: PackageManagerName, - shrinkwrapFilename: string - ): void { - if (!FileSystem.exists(commonRushConfigFolder)) { - console.log(`Creating folder: ${commonRushConfigFolder}`); - FileSystem.ensureFolder(commonRushConfigFolder); - return; - } - - for (const filename of FileSystem.readFolder(commonRushConfigFolder)) { - - // Ignore things that aren't actual files - const stat: fs.Stats = 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; - } - - const knownSet: Set = new Set(knownRushConfigFilenames.map(x => x.toUpperCase())); - - // Add the shrinkwrap filename for the package manager to the known set. - knownSet.add(shrinkwrapFilename.toUpperCase()); - - // If the package manager is pnpm, then also add the pnpm file to the known set. - if (packageManager === 'pnpm') { - knownSet.add(RushConstants.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 name of the package manager being used to install dependencies - */ - public get packageManager(): PackageManagerName { - return this._packageManager; - } - - /** - * {@inheritdoc PackageManager} - * - * @privateremarks - * In the next major breaking API change, we will rename this property to "packageManager" and eliminate the - * old property with that name. - * - * @beta - */ - public get packageManagerWrapper(): PackageManager { - return this._packageManagerWrapper; - } - - /** - * The absolute path to the "rush.json" configuration file that was loaded to construct this object. - */ - public get rushJsonFile(): string { - return this._rushJsonFile; - } - - /** - * The absolute path of the folder that contains rush.json for this project. - */ - public get rushJsonFolder(): string { - return this._rushJsonFolder; - } - - /** - * The folder that contains all change files. - */ - public get changesFolder(): string { - return this._changesFolder; - } - - /** - * The fully resolved path for the "common" folder where Rush will store settings that - * affect all Rush projects. This is always a subfolder of the folder containing "rush.json". - * Example: `C:\MyRepo\common` - */ - public get commonFolder(): string { - return this._commonFolder; - } - - /** - * The folder where Rush's additional config files are stored. This folder is always a - * subfolder called `config\rush` inside the common folder. (The `common\config` folder - * is reserved for configuration files used by other tools.) To avoid confusion or mistakes, - * Rush will report an error if this this folder contains any unrecognized files. - * - * Example: `C:\MyRepo\common\config\rush` - */ - public get commonRushConfigFolder(): string { - return this._commonRushConfigFolder; - } - - /** - * The folder where temporary files will be stored. This is always a subfolder called "temp" - * under the common folder. - * Example: `C:\MyRepo\common\temp` - */ - public get commonTempFolder(): string { - return this._commonTempFolder; - } - - /** - * The folder where automation scripts are stored. This is always a subfolder called "scripts" - * under the common folder. - * Example: `C:\MyRepo\common\scripts` - */ - public get commonScriptsFolder(): string { - return this._commonScriptsFolder; - } - - /** - * The local folder that will store the NPM package cache. Rush does not rely on the - * npm's default global cache folder, because npm's caching implementation does not - * reliably handle multiple processes. (For example, if a build box is running - * "rush install" simultaneously for two different working folders, it may fail randomly.) - * - * Example: `C:\MyRepo\common\temp\npm-cache` - */ - public get npmCacheFolder(): string { - return this._npmCacheFolder; - } - - /** - * The local folder where npm's temporary files will be written during installation. - * Rush does not rely on the global default folder, because it may be on a different - * hard disk. - * - * Example: `C:\MyRepo\common\temp\npm-tmp` - */ - public get npmTmpFolder(): string { - return this._npmTmpFolder; - } - - /** - * The local folder that will store the Yarn package cache. - * - * Example: `C:\MyRepo\common\temp\yarn-cache` - */ - public get yarnCacheFolder(): string { - return this._yarnCacheFolder; - } - - /** - * The full path of the shrinkwrap file that is tracked by Git. (The "rush install" - * command uses a temporary copy, whose path is tempShrinkwrapFilename.) - * @remarks - * This property merely reports the filename; the file itself may not actually exist. - * Example: `C:\MyRepo\common\npm-shrinkwrap.json` or `C:\MyRepo\common\pnpm-lock.yaml` - * - * @deprecated Use `getCommittedShrinkwrapFilename` instead, which gets the correct common - * shrinkwrap file name for a given active variant. - */ - public get committedShrinkwrapFilename(): string { - return this.getCommittedShrinkwrapFilename(); - } - - /** - * The filename (without any path) of the shrinkwrap file that is used by the package manager. - * @remarks - * This property merely reports the filename; the file itself may not actually exist. - * Example: `npm-shrinkwrap.json` or `pnpm-lock.yaml` - */ - public get shrinkwrapFilename(): string { - return this._shrinkwrapFilename; - } - - /** - * The full path of the temporary shrinkwrap file that is used during "rush install". - * This file may get rewritten by the package manager during installation. - * @remarks - * This property merely reports the filename; the file itself may not actually exist. - * Example: `C:\MyRepo\common\temp\npm-shrinkwrap.json` or `C:\MyRepo\common\temp\pnpm-lock.yaml` - */ - public get tempShrinkwrapFilename(): string { - return this._tempShrinkwrapFilename; - } - - /** - * The full path of a backup copy of tempShrinkwrapFilename. This backup copy is made - * before installation begins, and can be compared to determine how the package manager - * modified tempShrinkwrapFilename. - * @remarks - * This property merely reports the filename; the file itself may not actually exist. - * Example: `C:\MyRepo\common\temp\npm-shrinkwrap-preinstall.json` - * or `C:\MyRepo\common\temp\pnpm-lock-preinstall.yaml` - */ - public get tempShrinkwrapPreinstallFilename(): string { - return this._tempShrinkwrapPreinstallFilename; - } - - /** - * Returns an English phrase such as "shrinkwrap file" that can be used in logging messages - * to refer to the shrinkwrap file using appropriate terminology for the currently selected - * package manager. - */ - public get shrinkwrapFilePhrase(): string { - if (this._packageManager === 'yarn') { - // Eventually we'd like to be consistent with Yarn's terminology of calling this a "lock file", - // but a lot of Rush documentation uses "shrinkwrap" file and would all need to be updated. - return 'shrinkwrap file (yarn.lock)'; - } else { - return 'shrinkwrap file'; - } - } - - /** - * The filename of the build dependency data file. By default this is - * called 'rush-link.json' resides in the Rush common folder. - * Its data structure is defined by IRushLinkJson. - * - * Example: `C:\MyRepo\common\temp\rush-link.json` - */ - public get rushLinkJsonFilename(): string { - return this._rushLinkJsonFilename; - } - - /** - * The filename of the variant dependency data file. By default this is - * called 'current-variant.json' resides in the Rush common folder. - * Its data structure is defined by ICurrentVariantJson. - * - * Example: `C:\MyRepo\common\temp\current-variant.json` - */ - public get currentVariantJsonFilename(): string { - return this._currentVariantJsonFilename; - } - - /** - * The version of the locally installed NPM tool. (Example: "1.2.3") - */ - public get packageManagerToolVersion(): string { - return this._packageManagerToolVersion; - } - - /** - * The absolute path to the locally installed NPM tool. If "rush install" has not - * been run, then this file may not exist yet. - * Example: `C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm` - */ - public get packageManagerToolFilename(): string { - return this._packageManagerToolFilename; - } - - /** - * The minimum allowable folder depth for the projectFolder field in the rush.json file. - * This setting provides a way for repository maintainers to discourage nesting of project folders - * that makes the directory tree more difficult to navigate. The default value is 2, - * which implements a standard 2-level hierarchy of //package.json. - */ - public get projectFolderMinDepth(): number { - return this._projectFolderMinDepth; - } - - /** - * The maximum allowable folder depth for the projectFolder field in the rush.json file. - * This setting provides a way for repository maintainers to discourage nesting of project folders - * that makes the directory tree more difficult to navigate. The default value is 2, - * which implements on a standard convention of //package.json. - */ - public get projectFolderMaxDepth(): number { - return this._projectFolderMaxDepth; - } - - /** - * The "approvedPackagesPolicy" settings. - */ - public get approvedPackagesPolicy(): ApprovedPackagesPolicy { - return this._approvedPackagesPolicy; - } - - /** - * [Part of the "gitPolicy" feature.] - * A list of regular expressions describing allowable email patterns for Git commits. - * They are case-insensitive anchored JavaScript RegExps. - * Example: `".*@example\.com"` - * This array will never be undefined. - */ - public get gitAllowedEmailRegExps(): string[] { - return this._gitAllowedEmailRegExps; - } - - /** - * [Part of the "gitPolicy" feature.] - * An example valid email address that conforms to one of the allowedEmailRegExps. - * Example: `"foxtrot@example\.com"` - * This will never be undefined, and will always be nonempty if gitAllowedEmailRegExps is used. - */ - public get gitSampleEmail(): string { - return this._gitSampleEmail; - } - - /** - * [Part of the "gitPolicy" feature.] - * The commit message to use when committing changes during 'rush publish' - */ - public get gitVersionBumpCommitMessage(): string | undefined { - return this._gitVersionBumpCommitMessage; - } - - /** - * [Part of the "hotfixChange" feature.] - * Enables creating hotfix changes - */ - public get hotfixChangeEnabled(): boolean { - return this._hotfixChangeEnabled; - } - - /** - * The remote url of the repository. This helps "rush change" find the right remote to compare against. - */ - public get repositoryUrl(): string | undefined { - return this._repositoryUrl; - } - - /** - * The default branch name. This tells "rush change" which remote branch to compare against. - */ - public get repositoryDefaultBranch(): string { - return this._repositoryDefaultBranch; - } - - /** - * The default remote. This tells "rush change" which remote to compare against if the remote URL is not set - * or if a remote matching the provided remote URL is not found. - */ - public get repositoryDefaultRemote(): string { - return this._repositoryDefaultRemote; - } - - /** - * The default fully-qualified git remote branch of the repository. This helps "rush change" find the right branch to compare against. - */ - public get repositoryDefaultFullyQualifiedRemoteBranch(): string { - return `${this.repositoryDefaultRemote}/${this.repositoryDefaultBranch}`; - } - - /** - * Odd-numbered major versions of Node.js are experimental. Even-numbered releases - * spend six months in a stabilization period before the first Long Term Support (LTS) version. - * For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended - * for production usage because they frequently have bugs. They may cause Rush itself - * to malfunction. - * - * Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing - * pre-LTS versions in preparation for supporting the first LTS version, you can use this setting - * to disable Rush's warning. - */ - public get suppressNodeLtsWarning(): boolean { - return this._suppressNodeLtsWarning; - } - - /** - * If true, then consistent version specifiers for dependencies will be enforced. - * I.e. "rush check" is run before some commands. - */ - public get ensureConsistentVersions(): boolean { - return this._ensureConsistentVersions; - } - - /** - * Indicates whether telemetry collection is enabled for Rush runs. - * @beta - */ - public get telemetryEnabled(): boolean { - return this._telemetryEnabled; - } - - public get projects(): RushConfigurationProject[] { - return this._projects; - } - - public get projectsByName(): Map { - return this._projectsByName; - } - - /** - * {@inheritDoc NpmOptionsConfiguration} - */ - public get npmOptions(): NpmOptionsConfiguration { - return this._npmOptions; - } - - /** - * {@inheritDoc PnpmOptionsConfiguration} - */ - public get pnpmOptions(): PnpmOptionsConfiguration { - return this._pnpmOptions; - } - - /** - * {@inheritDoc YarnOptionsConfiguration} - */ - public get yarnOptions(): YarnOptionsConfiguration { - return this._yarnOptions; - } - - /** - * Settings from the common-versions.json config file. - * @remarks - * If the common-versions.json file is missing, this property will not be undefined. - * Instead it will be initialized in an empty state, and calling CommonVersionsConfiguration.save() - * will create the file. - * - * @deprecated Use `getCommonVersions` instead, which gets the correct common version data - * for a given active variant. - */ - public get commonVersions(): CommonVersionsConfiguration { - return this.getCommonVersions(); - } - - /** - * Gets the currently-installed variant, if an installation has occurred. - * For Rush operations which do not take a --variant parameter, this method - * determines which variant, if any, was last specified when performing "rush install" - * or "rush update". - */ - public get currentInstalledVariant(): string | undefined { - let variant: string | undefined; - - if (FileSystem.exists(this._currentVariantJsonFilename)) { - const currentVariantJson: ICurrentVariantJson = JsonFile.load(this._currentVariantJsonFilename); - - variant = currentVariantJson.variant || undefined; - } - - return variant; - } - - /** - * The rush hooks. It allows customized scripts to run at the specified point. - * @beta - */ - public get eventHooks(): EventHooks { - return this._eventHooks; - } - - /** - * Gets the path to the common-versions.json config file for a specific variant. - * @param variant - The name of the current variant in use by the active command. - */ - public getCommonVersionsFilePath(variant?: string | undefined): string { - const commonVersionsFilename: string = path.join(this.commonRushConfigFolder, - ...(variant ? [RushConstants.rushVariantsFolderName, variant] : []), - RushConstants.commonVersionsFilename); - return commonVersionsFilename; - } - - /** - * Gets the settings from the common-versions.json config file for a specific variant. - * @param variant - The name of the current variant in use by the active command. - */ - public getCommonVersions(variant?: string | undefined): CommonVersionsConfiguration { - const commonVersionsFilename: string = this.getCommonVersionsFilePath(variant); - return CommonVersionsConfiguration.loadFromFile(commonVersionsFilename); - } - - /** - * Gets the committed shrinkwrap file name for a specific variant. - * @param variant - The name of the current variant in use by the active command. - */ - public getCommittedShrinkwrapFilename(variant?: string | undefined): string { - if (variant) { - if (!this._variants[variant]) { - throw new Error( - `Invalid variant name '${variant}'. The provided variant parameter needs to be ` + - `one of the following from rush.json: ` + - `${Object.keys(this._variants).map((name: string) => `"${name}"`).join(', ')}.`); - } - } - - const variantConfigFolderPath: string = this._getVariantConfigFolderPath(variant); - - return path.join(variantConfigFolderPath, this._shrinkwrapFilename); - } - - /** - * Gets the absolute path for "pnpmfile.js" for a specific variant. - * @param variant - The name of the current variant in use by the active command. - * @remarks - * The file path is returned even if PNPM is not configured as the package manager. - */ - public getPnpmfilePath(variant?: string | undefined): string { - const variantConfigFolderPath: string = this._getVariantConfigFolderPath(variant); - - return path.join( - variantConfigFolderPath, - RushConstants.pnpmfileFilename); - } - - /** - * Looks up a project in the projectsByName map. If the project is not found, - * then undefined is returned. - */ - public getProjectByName(projectName: string): RushConfigurationProject | undefined { - return this._projectsByName.get(projectName); - } - - /** - * This is used e.g. by command-line interfaces such as "rush build --to example". - * If "example" is not a project name, then it also looks for a scoped name - * like `@something/example`. If exactly one project matches this heuristic, it - * is returned. Otherwise, undefined is returned. - */ - public findProjectByShorthandName(shorthandProjectName: string): RushConfigurationProject | undefined { - // Is there an exact match? - let result: RushConfigurationProject | undefined = this._projectsByName.get(shorthandProjectName); - if (result) { - return result; - } - - // Is there an approximate match? - for (const project of this._projects) { - if (PackageName.getUnscopedName(project.packageName) === shorthandProjectName) { - if (result) { - // Ambiguous -- there is more than one match - return undefined; - } else { - result = project; - } - } - } - return result; - } - - /** - * Looks up a project by its RushConfigurationProject.tempProjectName field. - * @returns The found project, or undefined if no match was found. - */ - public findProjectByTempName(tempProjectName: string): RushConfigurationProject | undefined { - // Is there an approximate match? - for (const project of this._projects) { - if (project.tempProjectName === tempProjectName) { - return project; - } - } - return undefined; - } - - /** - * @beta - */ - public get versionPolicyConfiguration(): VersionPolicyConfiguration { - return this._versionPolicyConfiguration; - } - - /** - * This configuration object contains settings repo maintainers have specified to enable - * and disable experimental Rush features. - * - * @beta - */ - public get experimentsConfiguration(): ExperimentsConfiguration { - return this._experimentsConfiguration; - } - - /** - * Returns the project for which the specified path is underneath that project's folder. - * If the path is not under any project's folder, returns undefined. - */ - public tryGetProjectForPath(currentFolderPath: string): RushConfigurationProject | undefined { - const resolvedPath: string = path.resolve(currentFolderPath); - for (const project of this.projects) { - if (Path.isUnderOrEqual(resolvedPath, project.projectFolder)) { - return project; - } - } - return undefined; - } - - private _populateDownstreamDependencies( - dependencies: { [key: string]: string } | undefined, - packageName: string): void { - - if (!dependencies) { - return; - } - Object.keys(dependencies).forEach(dependencyName => { - const depProject: RushConfigurationProject | undefined = this._projectsByName.get(dependencyName); - - if (depProject) { - depProject.downstreamDependencyProjects.push(packageName); - } - }); - } - - private _getVariantConfigFolderPath(variant?: string | undefined): string { - if (variant) { - if (!this._variants[variant]) { - throw new Error( - `Invalid variant name '${variant}'. The provided variant parameter needs to be ` + - `one of the following from rush.json: ` + - `${Object.keys(this._variants).map((name: string) => `"${name}"`).join(', ')}.`); - } - } - - return path.join( - this._commonRushConfigFolder, - ...(variant ? [RushConstants.rushVariantsFolderName, variant] : []) - ); - } -} diff --git a/apps/rush-lib/src/api/RushConfigurationProject.ts b/apps/rush-lib/src/api/RushConfigurationProject.ts deleted file mode 100644 index f879e1e60de..00000000000 --- a/apps/rush-lib/src/api/RushConfigurationProject.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 * as path from 'path'; -import { - JsonFile, - IPackageJson, - PackageName, - FileSystem, - FileConstants -} from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { VersionPolicy, LockStepVersionPolicy } from './VersionPolicy'; -import { PackageJsonEditor } from './PackageJsonEditor'; -import { RushConstants } from '../logic/RushConstants'; - -/** - * This represents the JSON data object for a project entry in the rush.json configuration file. - */ -export interface IRushConfigurationProjectJson { - packageName: string; - projectFolder: string; - reviewCategory?: string; - cyclicDependencyProjects: string[]; - versionPolicyName?: string; - shouldPublish?: boolean; - skipRushCheck?: boolean; -} - -/** - * This represents the configuration of a project that is built by Rush, based on - * the Rush.json configuration file. - * @public - */ -export class RushConfigurationProject { - private _packageName: string; - private _projectFolder: string; - private _projectRelativeFolder: string; - private _projectRushTempFolder: string; - private _reviewCategory: string; - private _packageJson: IPackageJson; - private _packageJsonEditor: PackageJsonEditor; - private _tempProjectName: string; - private _unscopedTempProjectName: string; - private _cyclicDependencyProjects: Set; - private _versionPolicyName: string | undefined; - private _versionPolicy: VersionPolicy; - private _shouldPublish: boolean; - private _skipRushCheck: boolean; - private _downstreamDependencyProjects: string[]; - private readonly _rushConfiguration: RushConfiguration; - - /** @internal */ - public constructor( - projectJson: IRushConfigurationProjectJson, - rushConfiguration: RushConfiguration, - tempProjectName: string - ) { - this._rushConfiguration = rushConfiguration; - this._packageName = projectJson.packageName; - this._projectRelativeFolder = projectJson.projectFolder; - - // For example, the depth of "a/b/c" would be 3. The depth of "a" is 1. - const projectFolderDepth: number = projectJson.projectFolder.split('/').length; - if (projectFolderDepth < rushConfiguration.projectFolderMinDepth) { - throw new Error(`To keep things organized, this repository has a projectFolderMinDepth policy` - + ` requiring project folders to be at least ${rushConfiguration.projectFolderMinDepth} levels deep.` - + ` Problem folder: "${projectJson.projectFolder}"`); - } - if (projectFolderDepth > rushConfiguration.projectFolderMaxDepth) { - throw new Error(`To keep things organized, this repository has a projectFolderMaxDepth policy` - + ` preventing project folders from being deeper than ${rushConfiguration.projectFolderMaxDepth} levels.` - + ` Problem folder: "${projectJson.projectFolder}"`); - } - - this._projectFolder = path.join(rushConfiguration.rushJsonFolder, projectJson.projectFolder); - - if (!FileSystem.exists(this._projectFolder)) { - throw new Error(`Project folder not found: ${projectJson.projectFolder}`); - } - - this._projectRushTempFolder = path.join( - this._projectFolder, - RushConstants.projectRushFolderName, - RushConstants.rushTempFolderName - ); - - // Are we using a package review file? - if (rushConfiguration.approvedPackagesPolicy.enabled) { - // If so, then every project needs to have a reviewCategory that was defined - // by the reviewCategories array. - if (!projectJson.reviewCategory) { - throw new Error(`The "approvedPackagesPolicy" feature is enabled rush.json, but a reviewCategory` + - ` was not specified for the project "${projectJson.packageName}".`); - } - if (!rushConfiguration.approvedPackagesPolicy.reviewCategories.has(projectJson.reviewCategory)) { - throw new Error(`The project "${projectJson.packageName}" specifies its reviewCategory as` - + `"${projectJson.reviewCategory}" which is not one of the defined reviewCategories.`); - } - this._reviewCategory = projectJson.reviewCategory; - } - - const packageJsonFilename: string = path.join(this._projectFolder, FileConstants.PackageJson); - this._packageJson = JsonFile.load(packageJsonFilename); - - if (this._packageJson.name !== this._packageName) { - throw new Error(`The package name "${this._packageName}" specified in rush.json does not` - + ` match the name "${this._packageJson.name}" from package.json`); - } - - this._packageJsonEditor = PackageJsonEditor.load(packageJsonFilename); - - this._tempProjectName = tempProjectName; - - // The "rushProject.tempProjectName" is guaranteed to be unique name (e.g. by adding the "-2" - // suffix). Even after we strip the NPM scope, it will still be unique. - // Example: "my-project-2" - this._unscopedTempProjectName = PackageName.getUnscopedName(tempProjectName); - - this._cyclicDependencyProjects = new Set(); - if (projectJson.cyclicDependencyProjects) { - for (const cyclicDependencyProject of projectJson.cyclicDependencyProjects) { - this._cyclicDependencyProjects.add(cyclicDependencyProject); - } - } - this._shouldPublish = !!projectJson.shouldPublish; - this._skipRushCheck = !!projectJson.skipRushCheck; - this._downstreamDependencyProjects = []; - this._versionPolicyName = projectJson.versionPolicyName; - } - - /** - * The name of the NPM package. An error is reported if this name is not - * identical to packageJson.name. - * - * Example: `@scope/MyProject` - */ - public get packageName(): string { - return this._packageName; - } - - /** - * The full path of the folder that contains the project to be built by Rush. - * - * Example: `C:\MyRepo\libraries\my-project` - */ - public get projectFolder(): string { - return this._projectFolder; - } - - /** - * The relative path of the folder that contains the project to be built by Rush. - * - * Example: `libraries\my-project` - */ - public get projectRelativeFolder(): string { - return this._projectRelativeFolder; - } - - /** - * The project-specific Rush temp folder. This folder is used to store Rush-specific temporary files. - * - * Example: `C:\MyRepo\libraries\my-project\.rush\temp` - */ - public get projectRushTempFolder(): string { - return this._projectRushTempFolder; - } - - /** - * The Rush configuration for the monorepo that the project belongs to. - */ - public get rushConfiguration(): RushConfiguration { - return this._rushConfiguration; - } - - /** - * The review category name, or undefined if no category was assigned. - * This name must be one of the valid choices listed in RushConfiguration.reviewCategories. - */ - public get reviewCategory(): string { - return this._reviewCategory; - } - - /** - * A list of local projects that appear as devDependencies for this project, but cannot be - * locally linked because it would create a cyclic dependency; instead, the last published - * version will be installed in the Common folder. - * - * These are package names that would be found by RushConfiguration.getProjectByName(). - */ - public get cyclicDependencyProjects(): Set { - return this._cyclicDependencyProjects; - } - - /** - * A list of projects within the Rush configuration which directly depend on this package. - */ - public get downstreamDependencyProjects(): string[] { - return this._downstreamDependencyProjects; - } - - /** - * The parsed NPM "package.json" file from projectFolder. - * @deprecated Use packageJsonEditor instead - */ - public get packageJson(): IPackageJson { - return this._packageJson; - } - - /** - * A useful wrapper around the package.json file for making modifications - * @beta - */ - public get packageJsonEditor(): PackageJsonEditor { - return this._packageJsonEditor; - } - - /** - * The unique name for the temporary project that will be generated in the Common folder. - * For example, if the project name is `@scope/MyProject`, the temporary project name - * might be `@rush-temp/MyProject-2`. - * - * Example: `@rush-temp/MyProject-2` - */ - public get tempProjectName(): string { - return this._tempProjectName; - } - - /** - * The unscoped temporary project name - * - * Example: `my-project-2` - */ - public get unscopedTempProjectName(): string { - return this._unscopedTempProjectName; - } - - /** - * A flag which indicates whether changes to this project should be published. This controls - * whether or not the project would show up when running `rush change`, and whether or not it - * should be published during `rush publish`. - */ - public get shouldPublish(): boolean { - return this._shouldPublish || !!this._versionPolicyName; - } - - /** - * If true, then this project will be ignored by the "rush check" command. - * The default value is false. - */ - public get skipRushCheck(): boolean { - return this._skipRushCheck; - } - - /** - * Name of the version policy used by this project. - * @beta - */ - public get versionPolicyName(): string | undefined { - return this._versionPolicyName; - } - - /** - * Version policy of the project - * @beta - */ - public get versionPolicy(): VersionPolicy | undefined { - if (!this._versionPolicy) { - if (this.versionPolicyName && this._rushConfiguration.versionPolicyConfiguration) { - this._versionPolicy = this._rushConfiguration.versionPolicyConfiguration.getVersionPolicy( - this.versionPolicyName); - } - } - return this._versionPolicy; - } - - /** - * Indicate whether this project is the main project for the related version policy. - * - * False if the project is not for publishing. - * True if the project is individually versioned or if its lockstep version policy does not specify main project. - * False if the project is lockstepped and is not the main project for its version policy. - * - * @beta - */ - public get isMainProject(): boolean { - if (!this.shouldPublish) { - return false; - } - let isMain: boolean = true; - if (this.versionPolicy && this.versionPolicy.isLockstepped) { - const lockStepPolicy: LockStepVersionPolicy = this.versionPolicy as LockStepVersionPolicy; - if (lockStepPolicy.mainProject && lockStepPolicy.mainProject !== this.packageName) { - isMain = false; - } - } - return isMain; - } -} diff --git a/apps/rush-lib/src/api/RushGlobalFolder.ts b/apps/rush-lib/src/api/RushGlobalFolder.ts deleted file mode 100644 index d003ef2556e..00000000000 --- a/apps/rush-lib/src/api/RushGlobalFolder.ts +++ /dev/null @@ -1,39 +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 { Utilities } from '../utilities/Utilities'; - -/** - * This class provides global folders that are used for rush's internal install locations. - * - * @internal - */ -export class RushGlobalFolder { - private _rushUserFolder: string; - private _rushNodeSpecificUserFolder: string; - - /** - * The absolute path to Rush's storage in the home directory for the current user, independent of node version. - * On Windows, it would be something like `C:\Users\YourName\.rush\`. - */ - public get path(): string { - return this._rushUserFolder; - } - - /** - * The absolute path to Rush's storage in the home directory for the current user and node version. - * On Windows, it would be something like `C:\Users\YourName\.rush\node-v3.4.5`. - */ - public get nodeSpecificPath(): string { - return this._rushNodeSpecificUserFolder; - } - - public constructor() { - this._rushUserFolder = path.join(Utilities.getHomeDirectory(), '.rush'); - const normalizedNodeVersion: string = process.version.match(/^[a-z0-9\-\.]+$/i) - ? process.version - : 'unknown-version'; - this._rushNodeSpecificUserFolder = path.join(this._rushUserFolder, `node-${normalizedNodeVersion}`); - } -} diff --git a/apps/rush-lib/src/api/Variants.ts b/apps/rush-lib/src/api/Variants.ts deleted file mode 100644 index 3730cc2e894..00000000000 --- a/apps/rush-lib/src/api/Variants.ts +++ /dev/null @@ -1,19 +0,0 @@ - -import { - ICommandLineStringDefinition -} from '@rushstack/ts-command-line'; - -/** - * Namespace for utilities relating to the Variants feature. - */ -export class Variants { - /** - * Provides the parameter configuration for '--variant'. - */ - public static readonly VARIANT_PARAMETER: ICommandLineStringDefinition = { - parameterLongName: '--variant', - argumentName: 'VARIANT', - description: 'Run command using a variant installation configuration', - environmentVariable: 'RUSH_VARIANT' - }; -} diff --git a/apps/rush-lib/src/api/VersionPolicy.ts b/apps/rush-lib/src/api/VersionPolicy.ts deleted file mode 100644 index 23e32c71b2d..00000000000 --- a/apps/rush-lib/src/api/VersionPolicy.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 { cloneDeep } from 'lodash'; -import * as semver from 'semver'; -import { IPackageJson } from '@rushstack/node-core-library'; - -import { - IVersionPolicyJson, - ILockStepVersionJson, - IIndividualVersionJson, - VersionFormatForCommit, - VersionFormatForPublish, - IVersionPolicyDependencyJson -} from './VersionPolicyConfiguration'; -import { PackageJsonEditor } from './PackageJsonEditor'; -import { RushConfiguration } from './RushConfiguration'; -import { RushConfigurationProject } from './RushConfigurationProject'; - -/** - * Type of version bumps - * @beta - */ -export enum BumpType { - // No version bump - 'none', - // Prerelease version bump - 'prerelease', - // Patch version bump - 'patch', - // Preminor version bump - 'preminor', - // Minor version bump - 'minor', - // Major version bump - 'major' -} - -/** - * Version policy base type names - * @beta - */ -export enum VersionPolicyDefinitionName { - 'lockStepVersion', - 'individualVersion' -} - -/** - * This is the base class for version policy which controls how versions get bumped. - * @beta - */ -export abstract class VersionPolicy { - private _policyName: string; - private _definitionName: VersionPolicyDefinitionName; - private _exemptFromRushChange: boolean; - private _versionFormatForCommit: VersionFormatForCommit; - private _versionFormatForPublish: VersionFormatForPublish; - - /** - * @internal - */ - public constructor(versionPolicyJson: IVersionPolicyJson) { - this._policyName = versionPolicyJson.policyName; - this._definitionName = VersionPolicyDefinitionName[versionPolicyJson.definitionName]; - this._exemptFromRushChange = versionPolicyJson.exemptFromRushChange || false; - - const jsonDependencies: IVersionPolicyDependencyJson = versionPolicyJson.dependencies || { }; - this._versionFormatForCommit = jsonDependencies.versionFormatForCommit || VersionFormatForCommit.original; - this._versionFormatForPublish = jsonDependencies.versionFormatForPublish || VersionFormatForPublish.original; - } - - /** - * Loads from version policy json - * - * @param versionPolicyJson - version policy Json - * - * @internal - */ - public static load(versionPolicyJson: IVersionPolicyJson): VersionPolicy | undefined { - const definition: VersionPolicyDefinitionName = VersionPolicyDefinitionName[versionPolicyJson.definitionName]; - if (definition === VersionPolicyDefinitionName.lockStepVersion) { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - return new LockStepVersionPolicy(versionPolicyJson as ILockStepVersionJson); - } else if (definition === VersionPolicyDefinitionName.individualVersion) { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - return new IndividualVersionPolicy(versionPolicyJson as IIndividualVersionJson); - } - return undefined; - } - - /** - * Version policy name - */ - public get policyName(): string { - return this._policyName; - } - - /** - * Version policy definition name - */ - public get definitionName(): VersionPolicyDefinitionName { - return this._definitionName; - } - - /** - * Whether it is a lockstepped version policy - */ - public get isLockstepped(): boolean { - return this.definitionName === VersionPolicyDefinitionName.lockStepVersion; - } - - /** - * Determines if a version policy wants to opt out of changelog files. - */ - public get exemptFromRushChange(): boolean { - return this._exemptFromRushChange; - } - - /** - * Returns an updated package json that satisfies the policy. - * - * @param project - package json - * @param force - force update even when the project version is higher than the policy version. - */ - public abstract ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined; - - /** - * Bumps version based on the policy - * - * @param bumpType - (optional) override bump type - * @param identifier - (optional) override prerelease Id - */ - 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. - * - * @param versionString - version string - * @param packageName - package name - */ - 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. - */ - public setDependenciesBeforePublish(packageName: string, configuration: RushConfiguration): void { - if (this._versionFormatForPublish === 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); - } - } - - 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('*'); - } - } - - packageJsonEditor.saveIfModified(); - } - } -} - -/** - * This policy indicates all related projects should use the same version. - * @beta - */ -export class LockStepVersionPolicy extends VersionPolicy { - private _version: semver.SemVer; - // 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. - private _nextBump: BumpType; - private _mainProject: string | undefined; - - /** - * @internal - */ - public constructor(versionPolicyJson: ILockStepVersionJson) { - super(versionPolicyJson); - this._version = new semver.SemVer(versionPolicyJson.version); - this._nextBump = BumpType[versionPolicyJson.nextBump]; - this._mainProject = versionPolicyJson.mainProject; - } - - /** - * The value of the lockstep version - */ - public get version(): string { - return this._version.format(); - } - - /** - * The type of bump for next bump. - */ - public get nextBump(): BumpType { - return this._nextBump; - } - - /** - * The main project for the version policy. - * - * 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 get mainProject(): string | undefined { - return this._mainProject; - } - - /** - * Serialized json for this policy - * - * @internal - */ - public get _json(): ILockStepVersionJson { - const json: ILockStepVersionJson = { - policyName: this.policyName, - definitionName: VersionPolicyDefinitionName[this.definitionName], - version: this.version, - nextBump: BumpType[this.nextBump] - }; - if (this._mainProject) { - json.mainProject = this._mainProject; - } - return json; - } - - /** - * Returns an updated package json that satisfies the version policy. - * - * @param project - input package json - * @param force - force update even when the project version is higher than the policy version. - */ - public ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined { - const packageVersion: semver.SemVer = new semver.SemVer(project.version); - const compareResult: number = packageVersion.compare(this._version); - if (compareResult === 0) { - return undefined; - } else if (compareResult > 0 && !force) { - const errorMessage: string = `Version ${project.version} in package ${project.name}` - + ` is higher than locked version ${this._version.format()}.`; - throw new Error(errorMessage); - } - return this._updatePackageVersion(project, this._version); - } - - /** - * Bumps the version of the lockstep policy - * - * @param bumpType - Overwrite bump type in version-policy.json with the provided value. - * @param identifier - Prerelease identifier if bump type is prerelease. - */ - public bump(bumpType?: BumpType, identifier?: string): void { - this._version.inc(this._getReleaseType(bumpType || this.nextBump), identifier); - } - - /** - * Updates the version of the policy directly with a new value - * @param newVersionString - New version - */ - public update(newVersionString: string): boolean { - const newVersion: semver.SemVer = new semver.SemVer(newVersionString); - if (!newVersion || this._version === newVersion) { - return false; - } - this._version = newVersion; - return true; - } - - /** - * Validates the specified version and throws if the version does not satisfy lockstep version. - * - * @param versionString - version string - * @param packageName - package name - */ - public validate(versionString: string, packageName: string): void { - const versionToTest: semver.SemVer = new semver.SemVer(versionString, false); - if (this._version.compare(versionToTest) !== 0) { - throw new Error(`Invalid version ${versionString} in ${packageName}`); - } - } - - private _updatePackageVersion(project: IPackageJson, newVersion: semver.SemVer): IPackageJson { - const updatedProject: IPackageJson = cloneDeep(project); - updatedProject.version = newVersion.format(); - return updatedProject; - } - - private _getReleaseType(bumpType: BumpType): semver.ReleaseType { - // Eventually we should just use ReleaseType and get rid of bump type. - return BumpType[bumpType] as semver.ReleaseType; - } -} - -/** - * This policy indicates all related projects get version bump driven by their own changes. - * @beta - */ -export class IndividualVersionPolicy extends VersionPolicy { - private _lockedMajor: number | undefined; - - /** - * @internal - */ - public constructor(versionPolicyJson: IIndividualVersionJson) { - super(versionPolicyJson); - this._lockedMajor = versionPolicyJson.lockedMajor; - } - - /** - * The major version that has been locked - */ - public get lockedMajor(): number | undefined { - return this._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; - } - - /** - * Returns an updated package json that satisfies the version policy. - * - * @param project - input package json - * @param force - force update even when the project version is higher than the policy version. - */ - public ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined { - if (this.lockedMajor) { - const version: semver.SemVer = new semver.SemVer(project.version); - if (version.major < this.lockedMajor) { - const updatedProject: IPackageJson = cloneDeep(project); - updatedProject.version = `${this._lockedMajor}.0.0`; - return updatedProject; - } else if (version.major > this.lockedMajor) { - const errorMessage: string = `Version ${project.version} in package ${project.name}` - + ` is higher than locked major version ${this._lockedMajor}.`; - throw new Error(errorMessage); - } - } - return undefined; - } - - /** - * Bumps version. - * Individual version policy lets change files drive version bump. This method currently does not do anything. - * - * @param bumpType - bump type - * @param identifier - prerelease id - */ - public bump(bumpType?: BumpType, identifier?: string): void { - // individual version policy lets change files drive version bump. - } - - /** - * Validates the specified version and throws if the version does not satisfy the policy. - * - * @param versionString - version string - * @param packageName - package name - */ - public validate(versionString: string, packageName: string): void { - const versionToTest: semver.SemVer = new semver.SemVer(versionString, false); - if (this._lockedMajor !== undefined) { - if (this._lockedMajor !== versionToTest.major) { - throw new Error(`Invalid major version ${versionString} in ${packageName}`); - } - } - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/api/VersionPolicyConfiguration.ts b/apps/rush-lib/src/api/VersionPolicyConfiguration.ts deleted file mode 100644 index 75801dc9ad9..00000000000 --- a/apps/rush-lib/src/api/VersionPolicyConfiguration.ts +++ /dev/null @@ -1,188 +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 { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; - -import { VersionPolicy, BumpType, LockStepVersionPolicy } from './VersionPolicy'; -import { RushConfigurationProject } from './RushConfigurationProject'; - -/** - * @beta - */ -export interface IVersionPolicyJson { - policyName: string; - definitionName: string; - dependencies?: IVersionPolicyDependencyJson; - exemptFromRushChange?: boolean; -} - -/** - * @beta - */ -export interface ILockStepVersionJson extends IVersionPolicyJson { - version: string; - nextBump: string; - mainProject?: string; -} - -/** - * @beta - */ -export interface IIndividualVersionJson extends IVersionPolicyJson { - lockedMajor?: number; -} - -/** - * @beta - */ -export enum VersionFormatForPublish { - original = 'original', - exact = 'exact' -} - -/** - * @beta - */ -export enum VersionFormatForCommit { - wildcard = 'wildcard', - original = 'original' -} - -/** - * @beta - */ -export interface IVersionPolicyDependencyJson { - versionFormatForPublish?: VersionFormatForPublish; - versionFormatForCommit?: VersionFormatForCommit; -} - -/** - * 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, - * and how their version numbers will be determined. - * @beta - */ -export class VersionPolicyConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '../schemas/version-policies.schema.json')); - - private _versionPolicies: Map; - private _jsonFileName: string; - - /** - * @internal - */ - public constructor(jsonFileName: string) { - this._jsonFileName = jsonFileName; - this._versionPolicies = new Map(); - this._loadFile(); - } - - /** - * Validate the version policy configuration against the rush config - */ - public validate(projectsByName: Map): void { - if (!this.versionPolicies) { - return; - } - this.versionPolicies.forEach((policy) => { - const lockStepPolicy: LockStepVersionPolicy = policy as LockStepVersionPolicy; - if (lockStepPolicy.mainProject && !projectsByName.get(lockStepPolicy.mainProject)) { - throw new Error(`Version policy \"${policy.policyName}\" has a non-existing mainProject:` + - ` ${lockStepPolicy.mainProject}.`); - } - }); - } - - /** - * Gets the version policy by its name. - * Throws error if the version policy is not found. - * @param policyName - Name of the version policy - */ - public getVersionPolicy(policyName: string): VersionPolicy { - const policy: VersionPolicy | undefined = this._versionPolicies.get(policyName); - if (!policy) { - throw new Error(`Failed to find version policy by name \'${policyName}\'`); - } - return policy; - } - - /** - * Gets all the version policies - */ - public get versionPolicies(): Map { - return this._versionPolicies; - } - - /** - * Bumps up versions for the specified version policy or all version policies - * - * @param versionPolicyName - version policy name - * @param bumpType - bump type to override what policy has defined. - * @param identifier - prerelease identifier to override what policy has defined. - * @param shouldCommit - should save to disk - */ - public bump(versionPolicyName?: string, - bumpType?: BumpType, - identifier?: string, - shouldCommit?: boolean - ): void { - if (versionPolicyName) { - const policy: VersionPolicy | undefined = this.versionPolicies.get(versionPolicyName); - if (policy) { - policy.bump(bumpType, identifier); - } - } else { - this.versionPolicies.forEach((versionPolicy) => { - if (versionPolicy) { - versionPolicy.bump(bumpType, identifier); - } - }); - } - this._saveFile(!!shouldCommit); - } - - /** - * Updates the version directly for the specified version policy - * @param versionPolicyName - version policy name - * @param newVersion - new version - */ - public update(versionPolicyName: string, - newVersion: string - ): void { - const policy: VersionPolicy | undefined = this.versionPolicies.get(versionPolicyName); - if (!policy || !policy.isLockstepped) { - throw new Error(`Lockstep Version policy with name "${versionPolicyName}" cannot be found`); - } - const lockStepVersionPolicy: LockStepVersionPolicy = policy as LockStepVersionPolicy; - if (lockStepVersionPolicy.update(newVersion)) { - this._saveFile(true); - } - } - - private _loadFile(): void { - if (!FileSystem.exists(this._jsonFileName)) { - return; - } - const versionPolicyJson: IVersionPolicyJson[] = JsonFile.loadAndValidate(this._jsonFileName, - VersionPolicyConfiguration._jsonSchema); - - versionPolicyJson.forEach(policyJson => { - const policy: VersionPolicy | undefined = VersionPolicy.load(policyJson); - if (policy) { - this._versionPolicies.set(policy.policyName, policy); - } - }); - } - - private _saveFile(shouldCommit: boolean): void { - const versionPolicyJson: IVersionPolicyJson[] = []; - this.versionPolicies.forEach((versionPolicy) => { - versionPolicyJson.push(versionPolicy._json); - }); - if (shouldCommit) { - JsonFile.save(versionPolicyJson, this._jsonFileName, { updateExistingFile: true }); - } - } -} diff --git a/apps/rush-lib/src/api/packageManager/PnpmPackageManager.ts b/apps/rush-lib/src/api/packageManager/PnpmPackageManager.ts deleted file mode 100644 index a7cdcfe3b12..00000000000 --- a/apps/rush-lib/src/api/packageManager/PnpmPackageManager.ts +++ /dev/null @@ -1,52 +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 semver from 'semver'; -import { RushConstants } from '../../logic/RushConstants'; -import { PackageManager } from './PackageManager'; -import * as path from 'path'; - -/** - * Support for interacting with the PNPM package manager. - */ -export class PnpmPackageManager extends PackageManager { - /** - * PNPM only. True if `--resolution-strategy` is supported. - */ - public readonly supportsResolutionStrategy: boolean; - - // example: node_modules/.pnpm/lock.yaml - public readonly internalShrinkwrapRelativePath: string; - - /** @internal */ - public constructor(version: string) { - super(version, 'pnpm'); - - const parsedVersion: semver.SemVer = new semver.SemVer(version); - - this.supportsResolutionStrategy = false; - - if (parsedVersion.major >= 3) { - this._shrinkwrapFilename = RushConstants.pnpmV3ShrinkwrapFilename; - - if (parsedVersion.minor >= 1) { - // Introduced in version 3.1.0-0 - this.supportsResolutionStrategy = true; - } - } else { - this._shrinkwrapFilename = RushConstants.pnpmV1ShrinkwrapFilename; - } - - if (parsedVersion.major <= 2) { - // node_modules/.shrinkwrap.yaml - this.internalShrinkwrapRelativePath = path.join('node_modules', '.shrinkwrap.yaml'); - } else if (parsedVersion.major <= 3) { - // node_modules/.pnpm-lock.yaml - this.internalShrinkwrapRelativePath = path.join('node_modules', '.pnpm-lock.yaml'); - } else { - // node_modules/.pnpm/lock.yaml - // See https://github.com/pnpm/pnpm/releases/tag/v4.0.0 for more details. - this.internalShrinkwrapRelativePath = path.join('node_modules', '.pnpm', 'lock.yaml'); - } - } -} diff --git a/apps/rush-lib/src/api/test/ChangeFile.test.ts b/apps/rush-lib/src/api/test/ChangeFile.test.ts deleted file mode 100644 index dba4d0b9e70..00000000000 --- a/apps/rush-lib/src/api/test/ChangeFile.test.ts +++ /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 path from 'path'; - -import { ChangeFile } from '../ChangeFile'; -import { RushConfiguration } from '../RushConfiguration'; -import { ChangeType } from '../ChangeManagement'; - -describe('ChangeFile', () => { - it('can add a change', () => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-npm.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - const changeFile: ChangeFile = new ChangeFile({ - packageName: 'a', - changes: [], - email: 'fake@microsoft.com' - }, rushConfiguration); - - changeFile.addChange({ - packageName: 'a', - changeType: ChangeType.minor, - comment: 'for minor' - }); - - changeFile.addChange({ - packageName: 'a', - changeType: ChangeType.patch, - comment: 'for patch' - }); - - expect(changeFile.getChanges('a').length).toEqual(2); - expect(changeFile.getChanges('a')[0].comment).toEqual('for minor'); - expect(changeFile.getChanges('a')[1].comment).toEqual('for patch'); - }); -}); \ No newline at end of file diff --git a/apps/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts b/apps/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts deleted file mode 100644 index 20500752c24..00000000000 --- a/apps/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts +++ /dev/null @@ -1,17 +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 { CommonVersionsConfiguration } from '../CommonVersionsConfiguration'; - -describe('CommonVersionsConfiguration', () => { - it('can load the file', () => { - const filename: string = path.resolve(__dirname, 'jsonFiles', 'common-versions.json'); - const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile(filename); - - expect(configuration.preferredVersions.get('@scope/library-1')).toEqual('~3.2.1'); - expect(configuration.xstitchPreferredVersions.get('library-2')).toEqual('1.2.3'); - expect(configuration.allowedAlternativeVersions.get('library-3')).toEqual(['^1.2.3']); - }); -}); diff --git a/apps/rush-lib/src/api/test/EnvironmentConfiguration.test.ts b/apps/rush-lib/src/api/test/EnvironmentConfiguration.test.ts deleted file mode 100644 index 3b6a9d0f901..00000000000 --- a/apps/rush-lib/src/api/test/EnvironmentConfiguration.test.ts +++ /dev/null @@ -1,98 +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 { EnvironmentConfiguration } from '../EnvironmentConfiguration'; - -describe('EnvironmentConfiguration', () => { - let _oldEnv: typeof process.env; - - beforeEach(() => { - EnvironmentConfiguration.reset(); - _oldEnv = process.env; - process.env = {}; - }); - - afterEach(() => { - process.env = _oldEnv; - }); - - describe('initialize', () => { - it('correctly allows no environment variables', () => { - expect(EnvironmentConfiguration.initialize).not.toThrow(); - }); - - it('allows known environment variables', () => { - process.env['RUSH_TEMP_FOLDER'] = '/var/temp'; // eslint-disable-line dot-notation - expect(EnvironmentConfiguration.initialize).not.toThrow(); - }); - - it('does not allow unknown environment variables', () => { - process.env['rush_foobar'] = 'asdf'; // eslint-disable-line dot-notation - expect(EnvironmentConfiguration.initialize).toThrow(); - }); - - it('can be re-initialized', () => { - process.env['RUSH_TEMP_FOLDER'] = '/var/tempA'; // eslint-disable-line dot-notation - EnvironmentConfiguration.initialize({ doNotNormalizePaths: true }); - - expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual('/var/tempA'); - - process.env['RUSH_TEMP_FOLDER'] = '/var/tempB'; // eslint-disable-line dot-notation - EnvironmentConfiguration.initialize({ doNotNormalizePaths: true }); - - expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual('/var/tempB'); - }); - }); - - describe('rushTempDirOverride', () => { - it('throws if EnvironmentConfiguration is not initialized', () => { - expect(() => EnvironmentConfiguration.rushTempFolderOverride).toThrow(); - }); - - it('returns undefined for unset environment variables', () => { - EnvironmentConfiguration.initialize(); - - expect(EnvironmentConfiguration.rushTempFolderOverride).not.toBeDefined(); - }); - - it('returns the value for a set environment variable', () => { - const expectedValue: string = '/var/temp'; - process.env['RUSH_TEMP_FOLDER'] = expectedValue; // eslint-disable-line dot-notation - EnvironmentConfiguration.initialize({ doNotNormalizePaths: true }); - - expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual(expectedValue); - }); - }); - - describe('pnpmStorePathOverride', () => { - const ENV_VAR: string = 'RUSH_PNPM_STORE_PATH'; - it('throws if EnvironmentConfiguration is not initialized', () => { - expect(() => EnvironmentConfiguration.pnpmStorePathOverride).toThrow(); - }); - - it('returns undefined for unset environment variable', () => { - EnvironmentConfiguration.initialize(); - - expect(EnvironmentConfiguration.pnpmStorePathOverride).not.toBeDefined(); - }); - - it('returns the expected path from environment variable without normalization', () => { - const expectedValue: string = '/var/temp'; - process.env[ENV_VAR] = expectedValue; - EnvironmentConfiguration.initialize({ doNotNormalizePaths: true }); - - expect(EnvironmentConfiguration.pnpmStorePathOverride).toEqual(expectedValue); - }) - - it('returns expected path from environment variable with normalization', () => { - const expectedValue: string = path.resolve(path.join(process.cwd(), 'temp')); - const envVar: string = './temp'; - process.env[ENV_VAR] = envVar; - - EnvironmentConfiguration.initialize(); - - expect(EnvironmentConfiguration.pnpmStorePathOverride).toEqual(expectedValue); - }) - }) -}); diff --git a/apps/rush-lib/src/api/test/EventHooks.test.ts b/apps/rush-lib/src/api/test/EventHooks.test.ts deleted file mode 100644 index 5059705cbb9..00000000000 --- a/apps/rush-lib/src/api/test/EventHooks.test.ts +++ /dev/null @@ -1,32 +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 { RushConfiguration } from '../RushConfiguration'; -import { Event, EventHooks } from '../EventHooks'; - -describe('EventHooks', () => { - it('loads a post build hook from rush.json', () => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-npm.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - expect(rushConfiguration.eventHooks.get(Event.postRushBuild)).toEqual(['do something']); - }); - - it('loads empty rush hooks', () => { - const eventHooks: EventHooks = new EventHooks({}); - expect(eventHooks.get(Event.postRushBuild).length).toEqual(0); - }); - - it('loads two rush hooks', () => { - const expectedHooks: string[] = [ - 'do one', - 'do two' - ]; - const eventHooks: EventHooks = new EventHooks({ - postRushBuild: expectedHooks - }); - const resultHooks: string[] = eventHooks.get(Event.postRushBuild); - expect(resultHooks).toEqual(expectedHooks); - }); - -}); \ No newline at end of file diff --git a/apps/rush-lib/src/api/test/LastInstallFlag.test.ts b/apps/rush-lib/src/api/test/LastInstallFlag.test.ts deleted file mode 100644 index 160e4827fa7..00000000000 --- a/apps/rush-lib/src/api/test/LastInstallFlag.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as path from 'path'; - -import { LastInstallFlag } from '../LastInstallFlag'; -import { FileSystem } from '@rushstack/node-core-library'; - -const TEMP_DIR: string = path.join(__dirname, 'temp'); - -describe('LastInstallFlag', () => { - beforeEach(() => { - FileSystem.ensureEmptyFolder(TEMP_DIR); - }); - - afterEach(() => { - FileSystem.ensureEmptyFolder(TEMP_DIR); - }); - - it('can create and remove a flag in an empty directory', () => { - // preparation - const flag: LastInstallFlag = new LastInstallFlag(TEMP_DIR); - FileSystem.deleteFile(flag.path); - - // test state, should be invalid since the file doesn't exist - expect(flag.isValid()).toEqual(false); - - // test creation - flag.create(); - expect(FileSystem.exists(flag.path)).toEqual(true); - expect(flag.isValid()).toEqual(true); - - // test deletion - flag.clear(); - expect(FileSystem.exists(flag.path)).toEqual(false); - expect(flag.isValid()).toEqual(false); - }); - - it('can detect if the last flag was in a different state', () => { - // preparation - const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { node: '5.0.0' }); - const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { node: '8.9.4' }); - FileSystem.deleteFile(flag1.path); - - // test state, should be invalid since the file doesn't exist - expect(flag1.isValid()).toEqual(false); - expect(flag2.isValid()).toEqual(false); - - // test creation - flag1.create(); - expect(FileSystem.exists(flag1.path)).toEqual(true); - expect(flag1.isValid()).toEqual(true); - - // the second flag has different state and should be invalid - expect(flag2.isValid()).toEqual(false); - - // test deletion - flag1.clear(); - expect(FileSystem.exists(flag1.path)).toEqual(false); - expect(flag1.isValid()).toEqual(false); - expect(flag2.isValid()).toEqual(false); - }); - - it('can detect if the last flag was in a corrupted state', () => { - // preparation, write non-json into flag file - const flag: LastInstallFlag = new LastInstallFlag(TEMP_DIR); - FileSystem.writeFile(flag.path, 'sdfjkaklfjksldajgfkld'); - - // test state, should be invalid since the file is not JSON - expect(flag.isValid()).toEqual(false); - FileSystem.deleteFile(flag.path); - }); - - it('throws an error if new storePath doesn\'t match the old one', () => { - const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { - packageManager: 'pnpm', - storePath: path.join(TEMP_DIR, 'pnpm-store') - }); - const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { - packageManager: 'pnpm', - storePath: path.join(TEMP_DIR, 'temp-store') - }); - - flag1.create(); - expect(() => { flag2.checkValidAndReportStoreIssues() }).toThrowError(/PNPM store path/); - }); - - it('doesn\'t throw an error if conditions for error aren\'t met', () => { - const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { - packageManager: 'pnpm', - storePath: path.join(TEMP_DIR, 'pnpm-store') - }); - const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR, { - packageManager: 'npm', - }); - - flag1.create(); - expect(() => { flag2.checkValidAndReportStoreIssues() }).not.toThrow(); - expect(flag2.checkValidAndReportStoreIssues()).toEqual(false); - }) -}); diff --git a/apps/rush-lib/src/api/test/RushConfiguration.test.ts b/apps/rush-lib/src/api/test/RushConfiguration.test.ts deleted file mode 100644 index 9bb3fa5e616..00000000000 --- a/apps/rush-lib/src/api/test/RushConfiguration.test.ts +++ /dev/null @@ -1,297 +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 { Text } from '@rushstack/node-core-library'; -import { RushConfiguration } from '../RushConfiguration'; -import { ApprovedPackagesPolicy } from '../ApprovedPackagesPolicy'; -import { RushConfigurationProject } from '../RushConfigurationProject'; -import { Utilities } from '../../utilities/Utilities'; -import { EnvironmentConfiguration } from '../EnvironmentConfiguration'; - -function normalizePathForComparison(pathToNormalize: string): string { - return Text.replaceAll(pathToNormalize, '\\', '/').toUpperCase(); -} - -function assertPathProperty(validatedPropertyName: string, absolutePath: string, relativePath: string): void { - const resolvedRelativePath: string = path.resolve(__dirname, relativePath); - expect(normalizePathForComparison(absolutePath)).toEqual(normalizePathForComparison(resolvedRelativePath)); -} - -describe('RushConfiguration', () => { - let _oldEnv: typeof process.env; - - beforeEach(() => { - _oldEnv = process.env; - process.env = {}; - - process.env['USERPROFILE'] = _oldEnv['USERPROFILE']; // eslint-disable-line dot-notation - process.env['HOME'] = _oldEnv['HOME']; // eslint-disable-line dot-notation - - }); - - afterEach(() => { - process.env = _oldEnv; - }); - - it('can\'t load too new rush', (done: jest.DoneCallback) => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-too-new.json'); - - expect(() => { - RushConfiguration.loadFromConfigurationFile(rushFilename); - }).toThrow('Unable to load rush-too-new.json because its RushVersion is 99.0.0'); - - done(); - }); - - it('can load repo/rush-npm.json', (done: jest.DoneCallback) => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-npm.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - expect(rushConfiguration.packageManager).toEqual('npm'); - assertPathProperty('committedShrinkwrapFilename', - rushConfiguration.committedShrinkwrapFilename, './repo/common/config/rush/npm-shrinkwrap.json'); - assertPathProperty('commonFolder', - rushConfiguration.commonFolder, './repo/common'); - assertPathProperty('commonRushConfigFolder', - rushConfiguration.commonRushConfigFolder, './repo/common/config/rush'); - assertPathProperty('commonTempFolder', - rushConfiguration.commonTempFolder, './repo/common/temp'); - assertPathProperty('npmCacheFolder', - rushConfiguration.npmCacheFolder, './repo/common/temp/npm-cache'); - assertPathProperty('npmTmpFolder', - rushConfiguration.npmTmpFolder, './repo/common/temp/npm-tmp'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); - assertPathProperty('pnpmStorePath', - rushConfiguration.pnpmOptions.pnpmStorePath, './repo/common/temp/pnpm-store'); - assertPathProperty('packageManagerToolFilename', - rushConfiguration.packageManagerToolFilename, './repo/common/temp/npm-local/node_modules/.bin/npm'); - assertPathProperty('rushJsonFolder', - rushConfiguration.rushJsonFolder, './repo'); - assertPathProperty('rushLinkJsonFilename', - rushConfiguration.rushLinkJsonFilename, './repo/common/temp/rush-link.json'); - - expect(rushConfiguration.packageManagerToolVersion).toEqual('4.5.0'); - - expect(rushConfiguration.repositoryUrl).toEqual('someFakeUrl'); - expect(rushConfiguration.projectFolderMaxDepth).toEqual(99); - expect(rushConfiguration.projectFolderMinDepth).toEqual(1); - expect(rushConfiguration.hotfixChangeEnabled).toEqual(true); - - expect(rushConfiguration.projects.length).toEqual(3); - - // "approvedPackagesPolicy" feature - const approvedPackagesPolicy: ApprovedPackagesPolicy = rushConfiguration.approvedPackagesPolicy; - expect(approvedPackagesPolicy.enabled).toEqual(true); - expect(Utilities.getSetAsArray(approvedPackagesPolicy.reviewCategories)).toEqual( - ['first-party', 'third-party', 'prototype']); - - expect(Utilities.getSetAsArray(approvedPackagesPolicy.ignoredNpmScopes)).toEqual( - ['@types', '@internal']); - - expect(approvedPackagesPolicy.browserApprovedPackages.items[0].packageName).toEqual('example'); - expect(approvedPackagesPolicy.browserApprovedPackages.items[0].allowedCategories.size).toEqual(3); - - expect(rushConfiguration.telemetryEnabled).toBe(false); - - // Validate project1 settings - const project1: RushConfigurationProject = rushConfiguration.getProjectByName('project1')!; - expect(project1).toBeDefined(); - - expect(project1.packageName).toEqual('project1'); - assertPathProperty('project1.projectFolder', project1.projectFolder, './repo/project1'); - expect(project1.tempProjectName).toEqual('@rush-temp/project1'); - expect(project1.unscopedTempProjectName).toEqual('project1'); - expect(project1.skipRushCheck).toEqual(false); - - // Validate project2 settings - const project2: RushConfigurationProject = rushConfiguration.getProjectByName('project2')!; - expect(project2.skipRushCheck).toEqual(true); - - done(); - }); - - it('can load repo/rush-pnpm.json', (done: jest.DoneCallback) => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - assertPathProperty('committedShrinkwrapFilename', - rushConfiguration.committedShrinkwrapFilename, './repo/common/config/rush/pnpm-lock.yaml'); - assertPathProperty('commonFolder', - rushConfiguration.commonFolder, './repo/common'); - assertPathProperty('commonRushConfigFolder', - rushConfiguration.commonRushConfigFolder, './repo/common/config/rush'); - assertPathProperty('commonTempFolder', - rushConfiguration.commonTempFolder, './repo/common/temp'); - assertPathProperty('npmCacheFolder', - rushConfiguration.npmCacheFolder, './repo/common/temp/npm-cache'); - assertPathProperty('npmTmpFolder', - rushConfiguration.npmTmpFolder, './repo/common/temp/npm-tmp'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); - assertPathProperty('pnpmStorePath', - rushConfiguration.pnpmOptions.pnpmStorePath, './repo/common/temp/pnpm-store'); - assertPathProperty('packageManagerToolFilename', - rushConfiguration.packageManagerToolFilename, './repo/common/temp/pnpm-local/node_modules/.bin/pnpm'); - assertPathProperty('rushJsonFolder', - rushConfiguration.rushJsonFolder, './repo'); - assertPathProperty('rushLinkJsonFilename', - rushConfiguration.rushLinkJsonFilename, './repo/common/temp/rush-link.json'); - - expect(rushConfiguration.packageManagerToolVersion).toEqual('4.5.0'); - - expect(rushConfiguration.repositoryUrl).toEqual('someFakeUrl'); - expect(rushConfiguration.projectFolderMaxDepth).toEqual(99); - expect(rushConfiguration.projectFolderMinDepth).toEqual(1); - - expect(rushConfiguration.projects.length).toEqual(3); - - // "approvedPackagesPolicy" feature - const approvedPackagesPolicy: ApprovedPackagesPolicy = rushConfiguration.approvedPackagesPolicy; - expect(approvedPackagesPolicy.enabled).toBe(true); - expect(Utilities.getSetAsArray(approvedPackagesPolicy.reviewCategories)).toEqual( - ['first-party', 'third-party', 'prototype']); - expect(Utilities.getSetAsArray(approvedPackagesPolicy.ignoredNpmScopes)).toEqual( - ['@types', '@internal']); - - expect(approvedPackagesPolicy.browserApprovedPackages.items[0].packageName).toEqual('example'); - expect(approvedPackagesPolicy.browserApprovedPackages.items[0].allowedCategories.size).toEqual(3); - - expect(rushConfiguration.telemetryEnabled).toBe(false); - - // Validate project1 settings - const project1: RushConfigurationProject = rushConfiguration.getProjectByName('project1')!; - expect(project1).toBeDefined(); - - expect(project1.packageName).toEqual('project1'); - assertPathProperty('project1.projectFolder', project1.projectFolder, './repo/project1'); - expect(project1.tempProjectName).toEqual('@rush-temp/project1'); - expect(project1.unscopedTempProjectName).toEqual('project1'); - - done(); - }); - - it('can load repo/rush-pnpm-2.json', (done: jest.DoneCallback) => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm-2.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.packageManagerToolVersion).toEqual('2.0.0'); - expect(rushConfiguration.shrinkwrapFilename).toEqual('shrinkwrap.yaml'); - - done(); - }); - - it('can load repo/rush-pnpm-3.json', (done: jest.DoneCallback) => { - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm-3.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.packageManagerToolVersion).toEqual('3.0.0'); - expect(rushConfiguration.shrinkwrapFilename).toEqual('pnpm-lock.yaml'); - - done(); - }); - - it('allows the temp directory to be set via environment variable', () => { - const expectedValue: string = path.resolve('/var/temp'); - process.env['RUSH_TEMP_FOLDER'] = expectedValue; // eslint-disable-line dot-notation - - const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); - - assertPathProperty('commonTempFolder', rushConfiguration.commonTempFolder, expectedValue); - assertPathProperty('npmCacheFolder', rushConfiguration.npmCacheFolder, path.join(expectedValue, 'npm-cache')); - assertPathProperty('npmTmpFolder', rushConfiguration.npmTmpFolder, path.join(expectedValue, 'npm-tmp')); - - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); - assertPathProperty('pnpmStorePath', rushConfiguration.pnpmOptions.pnpmStorePath, path.join(expectedValue, 'pnpm-store')); - assertPathProperty( - 'packageManagerToolFilename', - rushConfiguration.packageManagerToolFilename, - `${expectedValue}/pnpm-local/node_modules/.bin/pnpm` - ); - assertPathProperty( - 'rushLinkJsonFilename', - rushConfiguration.rushLinkJsonFilename, - path.join(expectedValue, 'rush-link.json') - ); - }); - - describe('PNPM Store Paths', () => { - afterEach(() => { - EnvironmentConfiguration['_pnpmStorePathOverride'] = undefined; - }) - - const PNPM_STORE_PATH_ENV: string = 'RUSH_PNPM_STORE_PATH'; - - describe('Loading repo/rush-pnpm-local.json', () => { - const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-local.json'); - - it(`loads the correct path when pnpmStore = "local"`, (done: jest.DoneCallback) => { - const EXPECT_STORE_PATH: string = path.resolve(__dirname, 'repo', 'common', 'temp', 'pnpm-store'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); - expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); - expect(path.isAbsolute(rushConfiguration.pnpmOptions.pnpmStorePath)).toEqual(true); - - done(); - }); - - it('loads the correct path when environment variable is defined', (done: jest.DoneCallback) => { - const EXPECT_STORE_PATH: string = path.resolve('/var/temp'); - process.env[PNPM_STORE_PATH_ENV] = EXPECT_STORE_PATH; - - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); - expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); - expect(path.isAbsolute(rushConfiguration.pnpmOptions.pnpmStorePath)).toEqual(true); - - done(); - }); - }) - - describe('Loading repo/rush-pnpm-global.json', () => { - const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-global.json'); - - it(`loads the correct path when pnpmStore = "global"`, (done: jest.DoneCallback) => { - const EXPECT_STORE_PATH: string = ""; - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('global'); - expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); - - done(); - }); - - it('loads the correct path when environment variable is defined', (done: jest.DoneCallback) => { - const EXPECT_STORE_PATH: string = path.resolve('/var/temp'); - process.env[PNPM_STORE_PATH_ENV] = EXPECT_STORE_PATH; - - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); - - expect(rushConfiguration.packageManager).toEqual('pnpm'); - expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('global'); - expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); - - done(); - }); - }) - - it(`throws an error when invalid pnpmStore is defined`, (done: jest.DoneCallback) => { - const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-invalid-store.json'); - expect(() => { - //@ts-ignore - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); // eslint-disable-line @typescript-eslint/no-unused-vars - }).toThrow(); - - done(); - }); - }) -}); diff --git a/apps/rush-lib/src/api/test/VersionMismatchFinder.test.ts b/apps/rush-lib/src/api/test/VersionMismatchFinder.test.ts deleted file mode 100644 index 84d54e64ebf..00000000000 --- a/apps/rush-lib/src/api/test/VersionMismatchFinder.test.ts +++ /dev/null @@ -1,379 +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 { RushConfigurationProject } from '../RushConfigurationProject'; -import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; -import { PackageJsonEditor } from '../PackageJsonEditor'; -import { CommonVersionsConfiguration } from '../CommonVersionsConfiguration'; -import { VersionMismatchFinderEntity } from '../../logic/versionMismatch/VersionMismatchFinderEntity'; -import { VersionMismatchFinderProject } from '../../logic/versionMismatch/VersionMismatchFinderProject'; -import { VersionMismatchFinderCommonVersions } from '../../logic/versionMismatch/VersionMismatchFinderCommonVersions'; - -/* eslint-disable @typescript-eslint/no-explicit-any */ -describe('VersionMismatchFinder', () => { - it('finds no mismatches if there are none', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(0); - expect(mismatchFinder.getMismatches().length).toEqual(0); - done(); - }); - - it('finds a mismatch in two packages', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(1); - expect(mismatchFinder.getMismatches().length).toEqual(1); - expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); - expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); - done(); - }); - - it('ignores cyclic dependencies', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set(['@types/foo']) - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(0); - expect(mismatchFinder.getMismatches().length).toEqual(0); - done(); - }); - - it('won\'t let you access mismatches that don\t exist', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.getVersionsOfMismatch('@types/foobar')).toEqual(undefined); - expect(mismatchFinder.getConsumersOfMismatch('@types/fobar', '2.0.0')).toEqual(undefined); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '9.9.9')).toEqual(undefined); - done(); - }); - - it('finds two mismatches in two different pairs of projects', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectC: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'C', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - 'mocha': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectD: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'D', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - 'mocha': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB, projectC, projectD]); - expect(mismatchFinder.numberOfMismatches).toEqual(2); - expect(mismatchFinder.getMismatches().length).toEqual(2); - expect(mismatchFinder.getMismatches()).toMatchObject(['@types/foo', 'mocha']); - expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); - expect(mismatchFinder.getVersionsOfMismatch('mocha')!.sort()).toEqual(['1.2.3', '2.0.0']); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('mocha', '1.2.3')).toEqual([projectC]); - expect(mismatchFinder.getConsumersOfMismatch('mocha', '2.0.0')).toEqual([projectD]); - done(); - }); - - it('finds three mismatches in three projects', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectC: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'C', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '9.9.9', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB, projectC]); - expect(mismatchFinder.numberOfMismatches).toEqual(1); - expect(mismatchFinder.getMismatches().length).toEqual(1); - expect(mismatchFinder.getMismatches()).toMatchObject(['@types/foo']); - expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0', '9.9.9']); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '9.9.9')).toEqual([projectC]); - done(); - }); - - it('checks dev dependencies', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - devDependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - - expect(mismatchFinder.numberOfMismatches).toEqual(1); - expect(mismatchFinder.getMismatches().length).toEqual(1); - expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); - expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); - done(); - }); - - it('does not check peer dependencies', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - peerDependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(0); - done(); - }); - - it('checks optional dependencies', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - optionalDependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(1); - expect(mismatchFinder.getMismatches().length).toEqual(1); - expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); - expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); - done(); - }); - - it('allows alternative versions', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'B', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@types/foo': '2.0.0', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - - const alternatives: Map> = new Map>(); - alternatives.set('@types/foo', ['2.0.0']); - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB], alternatives); - expect(mismatchFinder.numberOfMismatches).toEqual(0); - expect(mismatchFinder.getMismatches().length).toEqual(0); - done(); - }); - - it('handles the common-versions.json file correctly', (done: jest.DoneCallback) => { - const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ - packageName: 'A', - packageJsonEditor: PackageJsonEditor.fromObject({ - dependencies: { - '@scope/library-1': '1.2.3', - 'karma': '0.0.1' - } - } as any, 'foo.json'), - cyclicDependencyProjects: new Set() - } as any as RushConfigurationProject); - const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderCommonVersions( - CommonVersionsConfiguration.loadFromFile( - path.resolve(__dirname, 'jsonFiles', 'common-versions.json') - ) - ); - - const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); - expect(mismatchFinder.numberOfMismatches).toEqual(1); - expect(mismatchFinder.getMismatches().length).toEqual(1); - expect(mismatchFinder.getMismatches()[0]).toEqual('@scope/library-1'); - expect(mismatchFinder.getVersionsOfMismatch('@scope/library-1')!.sort()).toEqual(['1.2.3', '~3.2.1']); - expect(mismatchFinder.getConsumersOfMismatch('@scope/library-1', '~3.2.1')).toEqual([projectB]); - expect(mismatchFinder.getConsumersOfMismatch('@scope/library-1', '1.2.3')).toEqual([projectA]); - done(); - }); -}); diff --git a/apps/rush-lib/src/api/test/VersionPolicy.test.ts b/apps/rush-lib/src/api/test/VersionPolicy.test.ts deleted file mode 100644 index 04740f0f80a..00000000000 --- a/apps/rush-lib/src/api/test/VersionPolicy.test.ts +++ /dev/null @@ -1,142 +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 { IPackageJson } from '@rushstack/node-core-library'; - -import { VersionPolicyConfiguration } from '../VersionPolicyConfiguration'; -import { - VersionPolicy, - LockStepVersionPolicy, - IndividualVersionPolicy, - BumpType -} from '../VersionPolicy'; - -describe('VersionPolicy', () => { - describe('LockStepVersion', () => { - const filename: string = path.resolve(__dirname, 'jsonFiles', 'rushWithLockVersion.json'); - const versionPolicyConfig: VersionPolicyConfiguration = new VersionPolicyConfiguration(filename); - let versionPolicy: VersionPolicy; - - beforeEach(() => { - versionPolicy = versionPolicyConfig.getVersionPolicy('testPolicy1'); - }); - - it('loads configuration.', () => { - expect(versionPolicy).toBeInstanceOf(LockStepVersionPolicy); - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - expect(lockStepVersionPolicy.version).toEqual('1.1.0'); - expect(lockStepVersionPolicy.nextBump).toEqual(BumpType.patch); - }); - - it('skips packageJson if version is already the locked step version', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - expect(lockStepVersionPolicy.ensure({ - name: 'a', - version: '1.1.0' - })).not.toBeDefined(); - }); - - it('updates packageJson if version is lower than the locked step version', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - const expectedPackageJson: IPackageJson = { - name: 'a', - version: '1.1.0' - }; - const originalPackageJson: IPackageJson = { - name: 'a', - version: '1.0.1' - }; - expect(lockStepVersionPolicy.ensure(originalPackageJson)).toEqual(expectedPackageJson); - }); - - it('throws exception if version is higher than the locked step version', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - const originalPackageJson: IPackageJson = { - name: 'a', - version: '2.1.0' - }; - expect(() => { - lockStepVersionPolicy.ensure(originalPackageJson); - }).toThrow(); - }); - - it('update version with force if version is higher than the locked step version', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - const originalPackageJson: IPackageJson = { - name: 'a', - version: '2.1.0' - }; - const expectedPackageJson: IPackageJson = { - name: 'a', - version: '1.1.0' - }; - expect(lockStepVersionPolicy.ensure(originalPackageJson, true)).toEqual(expectedPackageJson); - }); - - it('bumps version for preminor release', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - lockStepVersionPolicy.bump(BumpType.preminor, 'pr'); - expect(lockStepVersionPolicy.version).toEqual('1.2.0-pr.0'); - expect(lockStepVersionPolicy.nextBump).toEqual(BumpType.patch); - }); - - it('bumps version for minor release', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - lockStepVersionPolicy.bump(BumpType.minor); - expect(lockStepVersionPolicy.version).toEqual('1.2.0'); - expect(lockStepVersionPolicy.nextBump).toEqual(BumpType.patch); - }); - - it('can update version directly', () => { - const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; - const newVersion: string = '1.5.6-beta.0'; - lockStepVersionPolicy.update(newVersion); - expect(lockStepVersionPolicy.version).toEqual(newVersion); - }); - }); - - describe('IndividualVersionPolicy', () => { - const fileName: string = path.resolve(__dirname, 'jsonFiles', 'rushWithIndividualVersion.json'); - const versionPolicyConfig: VersionPolicyConfiguration = new VersionPolicyConfiguration(fileName); - const versionPolicy: VersionPolicy = versionPolicyConfig.getVersionPolicy('testPolicy2'); - - it('loads configuration', () => { - expect(versionPolicy).toBeInstanceOf(IndividualVersionPolicy); - const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; - expect(individualVersionPolicy.lockedMajor).toEqual(2); - }); - - it('skips packageJson if no need to change', () => { - const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; - expect(individualVersionPolicy.ensure({ - name: 'a', - version: '2.1.0' - })).not.toBeDefined(); - }); - - it('updates packageJson if version is lower than the locked major', () => { - const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; - const expectedPackageJson: IPackageJson = { - name: 'a', - version: '2.0.0' - }; - const originalPackageJson: IPackageJson = { - name: 'a', - version: '1.0.1' - }; - expect(individualVersionPolicy.ensure(originalPackageJson)).toEqual(expectedPackageJson); - }); - - it('throws exception if version is higher than the locked step version', () => { - const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; - const originalPackageJson: IPackageJson = { - name: 'a', - version: '3.1.0' - }; - expect(() => { - individualVersionPolicy.ensure(originalPackageJson); - }).toThrow(); - }); - }); -}); diff --git a/apps/rush-lib/src/api/test/jsonFiles/common-versions.json b/apps/rush-lib/src/api/test/jsonFiles/common-versions.json deleted file mode 100644 index 8b9d9f581d4..00000000000 --- a/apps/rush-lib/src/api/test/jsonFiles/common-versions.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "preferredVersions": { - "@scope/library-1": "~3.2.1" - }, - "xstitchPreferredVersions": { - "library-2": "1.2.3" - }, - "allowedAlternativeVersions": { - "library-3": [ "^1.2.3" ] - } -} diff --git a/apps/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json b/apps/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json deleted file mode 100644 index 9e7c31fa9a2..00000000000 --- a/apps/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "policyName": "testPolicy1", - "definitionName": "lockStepVersion", - "version": "1.1.0", - "nextBump": "patch" - } -] \ No newline at end of file diff --git a/apps/rush-lib/src/api/test/repo/common/config/rush/browser-approved-packages.json b/apps/rush-lib/src/api/test/repo/common/config/rush/browser-approved-packages.json deleted file mode 100644 index 2ad030df51e..00000000000 --- a/apps/rush-lib/src/api/test/repo/common/config/rush/browser-approved-packages.json +++ /dev/null @@ -1,9 +0,0 @@ -// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. -{ - "packages": [ - { - "name": "example", - "allowedCategories": [ "first-party", "prototype", "third-party" ] - } - ] -} diff --git a/apps/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json b/apps/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json deleted file mode 100644 index 2ad030df51e..00000000000 --- a/apps/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json +++ /dev/null @@ -1,9 +0,0 @@ -// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. -{ - "packages": [ - { - "name": "example", - "allowedCategories": [ "first-party", "prototype", "third-party" ] - } - ] -} diff --git a/apps/rush-lib/src/api/test/repo/rush-npm.json b/apps/rush-lib/src/api/test/repo/rush-npm.json deleted file mode 100644 index e2311e32130..00000000000 --- a/apps/rush-lib/src/api/test/repo/rush-npm.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "npmVersion": "4.5.0", - "rushVersion": "2.5.0-dev.123", - "projectFolderMinDepth": 1, - "projectFolderMaxDepth": 99, - "hotfixChangeEnabled": true, - - "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] - }, - - "repository": { - "url": "someFakeUrl" - }, - - "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], - "sampleEmail": "mrexample@contoso.com" - }, - - "eventHooks": { - "postRushBuild": [ - "do something" - ] - }, - - "projects": [ - - { - "packageName": "project1", - "projectFolder": "project1", - "reviewCategory": "third-party" - }, - - { - "packageName": "project2", - "projectFolder": "project2", - "reviewCategory": "third-party", - "skipRushCheck": true - }, - - { - "packageName": "project3", - "projectFolder": "project3", - "reviewCategory": "prototype" - } - ] -} diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm-2.json b/apps/rush-lib/src/api/test/repo/rush-pnpm-2.json deleted file mode 100644 index 1b3380c71d9..00000000000 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm-2.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "pnpmVersion": "2.0.0", - "rushVersion": "2.5.0", - "projectFolderMinDepth": 1, - "projectFolderMaxDepth": 99, - - "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] - }, - - "repository": { - "url": "someFakeUrl" - }, - - "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], - "sampleEmail": "mrexample@contoso.com" - }, - - "eventHooks": { - "postRushBuild": [ - "do something" - ] - }, - - "projects": [ - - { - "packageName": "project1", - "projectFolder": "project1", - "reviewCategory": "third-party" - }, - - { - "packageName": "project2", - "projectFolder": "project2", - "reviewCategory": "third-party" - }, - - { - "packageName": "project3", - "projectFolder": "project3", - "reviewCategory": "prototype" - } - ] -} diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm-3.json b/apps/rush-lib/src/api/test/repo/rush-pnpm-3.json deleted file mode 100644 index 0216b188529..00000000000 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm-3.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "pnpmVersion": "3.0.0", - "rushVersion": "2.5.0", - "projectFolderMinDepth": 1, - "projectFolderMaxDepth": 99, - - "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] - }, - - "repository": { - "url": "someFakeUrl" - }, - - "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], - "sampleEmail": "mrexample@contoso.com" - }, - - "eventHooks": { - "postRushBuild": [ - "do something" - ] - }, - - "projects": [ - - { - "packageName": "project1", - "projectFolder": "project1", - "reviewCategory": "third-party" - }, - - { - "packageName": "project2", - "projectFolder": "project2", - "reviewCategory": "third-party" - }, - - { - "packageName": "project3", - "projectFolder": "project3", - "reviewCategory": "prototype" - } - ] -} diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm.json b/apps/rush-lib/src/api/test/repo/rush-pnpm.json deleted file mode 100644 index af33bcd18f4..00000000000 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "pnpmVersion": "4.5.0", - "rushVersion": "2.5.0", - "projectFolderMinDepth": 1, - "projectFolderMaxDepth": 99, - - "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] - }, - - "repository": { - "url": "someFakeUrl" - }, - - "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], - "sampleEmail": "mrexample@contoso.com" - }, - - "eventHooks": { - "postRushBuild": [ - "do something" - ] - }, - - "projects": [ - - { - "packageName": "project1", - "projectFolder": "project1", - "reviewCategory": "third-party" - }, - - { - "packageName": "project2", - "projectFolder": "project2", - "reviewCategory": "third-party" - }, - - { - "packageName": "project3", - "projectFolder": "project3", - "reviewCategory": "prototype" - } - ] -} diff --git a/apps/rush-lib/src/cli/CommandLineMigrationAdvisor.ts b/apps/rush-lib/src/cli/CommandLineMigrationAdvisor.ts deleted file mode 100644 index d58a3363cd0..00000000000 --- a/apps/rush-lib/src/cli/CommandLineMigrationAdvisor.ts +++ /dev/null @@ -1,63 +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 colors from 'colors'; - -import { RushConstants } from '../logic/RushConstants'; -import { Utilities } from '../utilities/Utilities'; - -export class CommandLineMigrationAdvisor { - - // NOTE: THIS RUNS BEFORE THE REAL COMMAND-LINE PARSING. - // TAKE EXTREME CARE THAT THE HEURISTICS CANNOT FALSELY MATCH A VALID COMMAND LINE. - public static checkArgv(argv: string[]): boolean { - // 0=node.exe, 1=script name - const args: string[] = process.argv.slice(2); - - if (args.length > 0) { - - if (args[0] === 'generate') { - CommandLineMigrationAdvisor._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".'); - return false; - } - if (args.indexOf('-C') >= 0) { - CommandLineMigrationAdvisor._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".'); - return false; - } - if (args.indexOf('-c') >= 0) { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush install -c", use "rush install --purge".'); - return false; - } - } - } - - // Everything is okay - return true; - } - - private static _reportDeprecated(message: string): void { - console.error(colors.red(Utilities.wrapWords( - 'ERROR: You specified an outdated command-line that is no longer supported by this version of Rush:' - ))); - console.error(colors.yellow(Utilities.wrapWords(message))); - console.error(); - console.error(Utilities.wrapWords(`For command-line help, type "rush -h". For migration instructions,` - + ` please visit ${RushConstants.rushWebSiteUrl}`)); - } - -} diff --git a/apps/rush-lib/src/cli/RushCommandLineParser.ts b/apps/rush-lib/src/cli/RushCommandLineParser.ts deleted file mode 100644 index 7275952f842..00000000000 --- a/apps/rush-lib/src/cli/RushCommandLineParser.ts +++ /dev/null @@ -1,337 +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 colors from 'colors'; -import * as os from 'os'; -import * as path from 'path'; - -import { CommandLineParser, CommandLineFlagParameter, CommandLineAction } from '@rushstack/ts-command-line'; -import { InternalError } from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushConstants } from '../logic/RushConstants'; -import { CommandLineConfiguration } from '../api/CommandLineConfiguration'; -import { CommandJson } from '../api/CommandLineJson'; -import { Utilities } from '../utilities/Utilities'; -import { BaseScriptAction } from '../cli/scriptActions/BaseScriptAction'; - -import { AddAction } from './actions/AddAction'; -import { ChangeAction } from './actions/ChangeAction'; -import { CheckAction } from './actions/CheckAction'; -import { UpdateAction } from './actions/UpdateAction'; -import { InstallAction } from './actions/InstallAction'; -import { InitAction } from './actions/InitAction'; -import { LinkAction } from './actions/LinkAction'; -import { ListAction } from './actions/ListAction'; -import { PublishAction } from './actions/PublishAction'; -import { PurgeAction } from './actions/PurgeAction'; -import { UnlinkAction } from './actions/UnlinkAction'; -import { ScanAction } from './actions/ScanAction'; -import { VersionAction } from './actions/VersionAction'; - -import { BulkScriptAction } from './scriptActions/BulkScriptAction'; -import { GlobalScriptAction } from './scriptActions/GlobalScriptAction'; - -import { Telemetry } from '../logic/Telemetry'; -import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; -import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; - -/** - * Options for `RushCommandLineParser`. - */ -export interface IRushCommandLineParserOptions { - cwd: string; // Defaults to `cwd` - alreadyReportedNodeTooNewError: boolean; -} - -export class RushCommandLineParser extends CommandLineParser { - public telemetry: Telemetry | undefined; - public rushGlobalFolder: RushGlobalFolder; - public rushConfiguration: RushConfiguration; - - private _debugParameter: CommandLineFlagParameter; - private _rushOptions: IRushCommandLineParserOptions; - - public constructor(options?: Partial) { - super({ - toolFilename: 'rush', - toolDescription: 'Rush makes life easier for JavaScript developers who develop, build, and publish' - + ' many packages from a central Git repo. It is designed to handle very large repositories' - + ' supporting many projects and people. Rush provides policies, protections, and customizations' - + ' that help coordinate teams and safely onboard new contributors. Rush also generates change logs' - + ' and automates package publishing. It can manage decoupled subsets of projects with different' - + ' release and versioning strategies. A full API is included to facilitate integration with other' - + ' automation tools. If you are looking for a proven turnkey solution for monorepo management,' - + ' Rush is for you.' - }); - - this._rushOptions = this._normalizeOptions(options || {}); - - try { - const rushJsonFilename: string | undefined = RushConfiguration.tryFindRushJsonLocation({ - startingFolder: this._rushOptions.cwd, - showVerbose: true - }); - if (rushJsonFilename) { - this.rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFilename); - } - } catch (error) { - this._reportErrorAndSetExitCode(error); - } - - NodeJsCompatibility.warnAboutCompatibilityIssues({ - isRushLib: true, - alreadyReportedNodeTooNewError: this._rushOptions.alreadyReportedNodeTooNewError, - rushConfiguration: this.rushConfiguration - }); - - this._populateActions(); - } - - public get isDebug(): boolean { - return this._debugParameter.value; - } - - public flushTelemetry(): void { - if (this.telemetry) { - this.telemetry.flush(); - } - } - - protected onDefineParameters(): void { - this._debugParameter = this.defineFlagParameter({ - parameterLongName: '--debug', - parameterShortName: '-d', - description: 'Show the full call stack if an error occurs while executing the tool' - }); - } - - protected onExecute(): 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. - // Ideally we should do this for all the Rush actions, but "rush build" is the most critical one - // -- if it falsely appears to succeed, we could merge bad PRs, publish empty packages, etc. - process.exitCode = 1; - - if (this._debugParameter.value) { - InternalError.breakInDebugger = true; - } - - return this._wrapOnExecute().catch((error: Error) => { - this._reportErrorAndSetExitCode(error); - }).then(() => { - // If we make it here, everything went fine, so reset the exit code back to 0 - process.exitCode = 0; - }); - } - - private _normalizeOptions(options: Partial): IRushCommandLineParserOptions { - return { - cwd: options.cwd || process.cwd(), - alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError || false - }; - } - - private _wrapOnExecute(): Promise { - try { - if (this.rushConfiguration) { - this.telemetry = new Telemetry(this.rushConfiguration); - } - return super.onExecute().then(() => { - if (this.telemetry) { - this.flushTelemetry(); - } - }); - } catch (error) { - return Promise.reject(error); - } - } - - private _populateActions(): void { - try { - this.rushGlobalFolder = new RushGlobalFolder(); - - this.addAction(new AddAction(this)); - this.addAction(new ChangeAction(this)); - this.addAction(new CheckAction(this)); - this.addAction(new InstallAction(this)); - this.addAction(new InitAction(this)); - this.addAction(new LinkAction(this)); - this.addAction(new ListAction(this)); - this.addAction(new PublishAction(this)); - this.addAction(new PurgeAction(this)); - this.addAction(new ScanAction(this)); - this.addAction(new UpdateAction(this)); - this.addAction(new UnlinkAction(this)); - this.addAction(new VersionAction(this)); - - this._populateScriptActions(); - - } catch (error) { - this._reportErrorAndSetExitCode(error); - } - } - - private _populateScriptActions(): void { - let commandLineConfiguration: CommandLineConfiguration | undefined = undefined; - - // If there is not a rush.json file, we still want "build" and "rebuild" to appear in the - // command-line help - if (this.rushConfiguration) { - const commandLineConfigFile: string = path.join( - this.rushConfiguration.commonRushConfigFolder, - RushConstants.commandLineFilename - ); - - commandLineConfiguration = CommandLineConfiguration.loadFromFileOrDefault(commandLineConfigFile); - } - - // Build actions from the command line configuration supercede default build actions. - this._addCommandLineConfigActions(commandLineConfiguration); - this._addDefaultBuildActions(commandLineConfiguration); - this._validateCommandLineConfigParameterAssociations(commandLineConfiguration); - } - - private _addDefaultBuildActions(commandLineConfiguration?: CommandLineConfiguration): void { - if (!this.tryGetAction(RushConstants.buildCommandName)) { - this._addCommandLineConfigAction(commandLineConfiguration, CommandLineConfiguration.defaultBuildCommandJson); - } - - if (!this.tryGetAction(RushConstants.rebuildCommandName)) { - this._addCommandLineConfigAction(commandLineConfiguration, CommandLineConfiguration.defaultRebuildCommandJson); - } - } - - private _addCommandLineConfigActions(commandLineConfiguration?: CommandLineConfiguration): void { - if (!commandLineConfiguration) { - return; - } - - // Register each custom command - for (const command of commandLineConfiguration.commands) { - this._addCommandLineConfigAction(commandLineConfiguration, command); - } - } - - private _addCommandLineConfigAction( - commandLineConfiguration: CommandLineConfiguration | undefined, - command: CommandJson - ): void { - if (this.tryGetAction(command.name)) { - throw new Error(`${RushConstants.commandLineFilename} defines a command "${command.name}"` - + ` using a name that already exists`); - } - - this._validateCommandLineConfigCommand(command); - - switch (command.commandKind) { - case RushConstants.bulkCommandKind: - this.addAction(new BulkScriptAction({ - actionName: command.name, - - // The rush rebuild and rush build command invoke the same NPM script because they share the same - // package-deps-hash state. - commandToRun: command.name === RushConstants.rebuildCommandName ? 'build' : undefined, - - summary: command.summary, - documentation: command.description || command.summary, - safeForSimultaneousRushProcesses: command.safeForSimultaneousRushProcesses, - - parser: this, - commandLineConfiguration: commandLineConfiguration, - - enableParallelism: command.enableParallelism, - ignoreMissingScript: command.ignoreMissingScript || false, - ignoreDependencyOrder: command.ignoreDependencyOrder || false, - incremental: command.incremental || false, - allowWarningsInSuccessfulBuild: !!command.allowWarningsInSuccessfulBuild - })); - break; - - case RushConstants.globalCommandKind: - this.addAction(new GlobalScriptAction({ - actionName: command.name, - summary: command.summary, - documentation: command.description || command.summary, - safeForSimultaneousRushProcesses: command.safeForSimultaneousRushProcesses, - - parser: this, - commandLineConfiguration: commandLineConfiguration, - - shellCommand: command.shellCommand - })); - break; - default: - throw new Error(`${RushConstants.commandLineFilename} defines a command "${command!.name}"` - + ` using an unsupported command kind "${command!.commandKind}"`); - } - } - - private _validateCommandLineConfigParameterAssociations(commandLineConfiguration?: CommandLineConfiguration): void { - if (!commandLineConfiguration) { - return; - } - - // Check for any invalid associations - for (const parameter of commandLineConfiguration.parameters) { - for (const associatedCommand of parameter.associatedCommands) { - const action: CommandLineAction | undefined = this.tryGetAction(associatedCommand); - if (!action) { - throw new Error(`${RushConstants.commandLineFilename} defines a parameter "${parameter.longName}"` - + ` that is associated with a nonexistent command "${associatedCommand}"`); - } - if (!(action instanceof BaseScriptAction)) { - throw new Error(`${RushConstants.commandLineFilename} defines a parameter "${parameter.longName}"` - + ` that is associated with a command "${associatedCommand}", but that command does not` - + ` support custom parameters`); - } - } - } - } - - private _validateCommandLineConfigCommand(command: CommandJson): void { - // There are some restrictions on the 'build' and 'rebuild' commands. - if (command.name !== RushConstants.buildCommandName && command.name !== RushConstants.rebuildCommandName) { - return; - } - - if (command.commandKind === RushConstants.globalCommandKind) { - throw new Error(`${RushConstants.commandLineFilename} defines a command "${command.name}" using ` + - `the command kind "${RushConstants.globalCommandKind}". This command can only be designated as a command ` + - `kind "${RushConstants.bulkCommandKind}".`); - } - if (command.safeForSimultaneousRushProcesses) { - throw new Error(`${RushConstants.commandLineFilename} defines a command "${command.name}" using ` + - `"safeForSimultaneousRushProcesses=true". This configuration is not supported for "${command.name}".`); - } - } - - private _reportErrorAndSetExitCode(error: Error): void { - if (!(error instanceof AlreadyReportedError)) { - const prefix: string = 'ERROR: '; - console.error(os.EOL + colors.red(Utilities.wrapWords(prefix + error.message))); - } - - if (this._debugParameter.value) { - // If catchSyncErrors() called this, then show a call stack similar to what Node.js - // would show for an uncaught error - console.error(os.EOL + error.stack); - } - - this.flushTelemetry(); - - // Ideally we want to eliminate all calls to process.exit() from our code, and replace them - // with normal control flow that properly cleans up its data structures. - // For this particular call, we have a problem that the RushCommandLineParser constructor - // performs nontrivial work that can throw an exception. Either the Rush class would need - // to handle reporting for those exceptions, or else _populateActions() should be moved - // to a RushCommandLineParser lifecycle stage that can handle it. - if (!process.exitCode || process.exitCode > 0) { - process.exit(process.exitCode); - } else { - process.exit(1); - } - } -} diff --git a/apps/rush-lib/src/cli/RushXCommandLine.ts b/apps/rush-lib/src/cli/RushXCommandLine.ts deleted file mode 100644 index 7f7bd449712..00000000000 --- a/apps/rush-lib/src/cli/RushXCommandLine.ts +++ /dev/null @@ -1,171 +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 colors from 'colors'; -import * as os from 'os'; -import * as path from 'path'; - -import { - PackageJsonLookup, - IPackageJson, - Text - } from '@rushstack/node-core-library'; -import { Utilities } from '../utilities/Utilities'; -import { ProjectCommandSet } from '../logic/ProjectCommandSet'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; - -/** - * @internal - */ -export interface ILaunchRushXInternalOptions { - isManaged: boolean; - alreadyReportedNodeTooNewError?: boolean; -} - -export class RushXCommandLine { - public static launchRushX(launcherVersion: string, isManaged: boolean): void { - RushXCommandLine._launchRushXInternal(launcherVersion, { isManaged }); - } - - /** - * @internal - */ - public static _launchRushXInternal(launcherVersion: string, options: ILaunchRushXInternalOptions): void { - // Node.js can sometimes accidentally terminate with a zero exit code (e.g. for an uncaught - // 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; - - try { - // Are we in a Rush repo? - let rushConfiguration: RushConfiguration | undefined = undefined; - if (RushConfiguration.tryFindRushJsonLocation()) { - rushConfiguration = RushConfiguration.loadFromDefaultLocation({ showVerbose: true }); - } - - NodeJsCompatibility.warnAboutCompatibilityIssues({ - isRushLib: true, - alreadyReportedNodeTooNewError: !!options.alreadyReportedNodeTooNewError, - rushConfiguration - }); - - // Find the governing package.json for this folder: - const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - - const packageJsonFilePath: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor(process.cwd()); - if (!packageJsonFilePath) { - console.log(colors.red('This command should be used inside a project folder.')); - console.log(`Unable to find a package.json file in the current working directory or any of its parents.`); - return; - } - - const packageJson: IPackageJson = packageJsonLookup.loadPackageJson(packageJsonFilePath); - - const projectCommandSet: ProjectCommandSet = new ProjectCommandSet(packageJson); - - // 0 = node.exe - // 1 = rushx - const args: string[] = process.argv.slice(2); - - // Check for the following types of things: - // rush - // rush --help - // rush -h - // rush --unrecognized-option - if (args.length === 0 || args[0][0] === '-') { - RushXCommandLine._showUsage(packageJson, projectCommandSet); - return; - } - - const commandName: string = args[0]; - - const scriptBody: string | undefined = projectCommandSet.tryGetScriptBody(commandName); - - if (scriptBody === undefined) { - console.log(colors.red(`Error: The command "${commandName}" is not defined in the` - + ` package.json file for this project.`)); - - if (projectCommandSet.commandNames.length > 0) { - console.log(os.EOL + 'Available commands for this project are: ' - + projectCommandSet.commandNames.map(x => `"${x}"`).join(', ')); - } - - console.log(`Use ${colors.yellow('"rushx --help"')} for more information.`); - return; - } - - console.log('Executing: ' + JSON.stringify(scriptBody) + os.EOL); - - const packageFolder: string = path.dirname(packageJsonFilePath); - - const exitCode: number = Utilities.executeLifecycleCommand( - scriptBody, - { - 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 - } - } - ); - - if (exitCode > 0) { - console.log(colors.red(`The script failed with exit code ${exitCode}`)); - } - - process.exitCode = exitCode; - - } catch (error) { - console.log(colors.red('Error: ' + error.message)); - } - } - - private static _showUsage(packageJson: IPackageJson, projectCommandSet: ProjectCommandSet): void { - console.log('usage: rushx [-h]'); - console.log(' rushx ...' + os.EOL); - - console.log('Optional arguments:'); - console.log(' -h, --help Show this help message and exit.' + os.EOL); - - if (projectCommandSet.commandNames.length > 0) { - console.log(`Project commands for ${colors.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); - } - - 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 truncateLength: number = Math.max(0, Utilities.getConsoleWidth() - firstPartLength) - 1; - - console.log( - // Example: " command: " - ' ' + colors.cyan(Text.padEnd(commandName + ':', maxLength + 2)) - // Example: "do some thin..." - + Text.truncateWithEllipsis(escapedScriptBody, truncateLength) - ); - } - - if (projectCommandSet.malformedScriptNames.length > 0) { - console.log(os.EOL + colors.yellow('Warning: Some "scripts" entries in the package.json file' - + ' have malformed names: ' - + projectCommandSet.malformedScriptNames.map(x => `"${x}"`).join(', '))); - } - } else { - console.log(colors.yellow('Warning: No commands are defined yet for this project.')); - console.log('You can define a command by adding a "scripts" table to the project\'s package.json file.'); - } - } -} diff --git a/apps/rush-lib/src/cli/actions/AddAction.ts b/apps/rush-lib/src/cli/actions/AddAction.ts deleted file mode 100644 index da93ca6a44e..00000000000 --- a/apps/rush-lib/src/cli/actions/AddAction.ts +++ /dev/null @@ -1,162 +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'; -import * as semver from 'semver'; - -import { - CommandLineFlagParameter, - CommandLineStringParameter -} from '@rushstack/ts-command-line'; - -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { BaseRushAction } from './BaseRushAction'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { PackageJsonUpdater, SemVerStyle } from '../../logic/PackageJsonUpdater'; -import { PackageName } from '@rushstack/node-core-library'; - -export class AddAction extends BaseRushAction { - private _allFlag: CommandLineFlagParameter; - private _exactFlag: CommandLineFlagParameter; - private _caretFlag: CommandLineFlagParameter; - private _devDependencyFlag: CommandLineFlagParameter; - private _makeConsistentFlag: CommandLineFlagParameter; - private _skipUpdateFlag: CommandLineFlagParameter; - private _packageName: CommandLineStringParameter; - - public constructor(parser: RushCommandLineParser) { - const documentation: string[] = [ - 'Adds a specified package as a dependency of the current project (as determined by the current working directory)' - + ' 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 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.' - ]; - super({ - actionName: 'add', - summary: 'Adds a dependency to the package.json and runs rush upgrade.', - documentation: documentation.join(os.EOL), - safeForSimultaneousRushProcesses: false, - parser - }); - } - - public onDefineParameters(): void { - this._packageName = this.defineStringParameter({ - parameterLongName: '--package', - parameterShortName: '-p', - required: true, - argumentName: 'PACKAGE', - description: '(Required) 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".' - }); - this._exactFlag = this.defineFlagParameter({ - parameterLongName: '--exact', - 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', - description: 'If specified, the SemVer specifier added to the' - + ' package.json will be a prepended with a "caret" specifier ("^").' - }); - this._devDependencyFlag = this.defineFlagParameter({ - parameterLongName: '--dev', - description: 'If specified, the package will be added to the "devDependencies" section of' - + ' the package.json' - }); - this._makeConsistentFlag = this.defineFlagParameter({ - parameterLongName: '--make-consistent', - 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._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._allFlag = this.defineFlagParameter({ - parameterLongName: '--all', - description: 'If specified, the dependency will be added to all projects.' - }); - } - - public async run(): Promise { - let projects: RushConfigurationProject[]; - if (this._allFlag.value) { - projects = this.rushConfiguration.projects; - } else { - const currentProject: RushConfigurationProject | undefined = this.rushConfiguration.tryGetProjectForPath( - process.cwd() - ); - - if (!currentProject) { - throw new Error('The "rush add" command must be invoked under a project' - + ` folder that is registered in rush.json unless the ${this._allFlag.longName} is used.`); - } - - projects = [currentProject]; - } - - if (this._caretFlag.value && this._exactFlag.value) { - throw new Error( - `Only one of "${this._caretFlag.longName}" and "${this._exactFlag.longName}" should be specified` - ); - } - - let version: string | undefined = undefined; - let packageName: string | undefined = this._packageName.value!; - const parts: string[] = packageName.split('@'); - - if (parts[0] === '') { - // this is a scoped package - packageName = '@' + parts[1]; - version = parts[2]; - } else { - packageName = parts[0]; - version = parts[1]; - } - - if (!PackageName.isValidName(packageName)) { - throw new Error(`The package name "${packageName}" is not valid.`); - } - - if (version && version !== 'latest' && !semver.validRange(version) && !semver.valid(version)) { - throw new Error(`The SemVer specifier "${version}" is not valid.`); - } - - const updater: PackageJsonUpdater = new PackageJsonUpdater(this.rushConfiguration, this.rushGlobalFolder); - - let rangeStyle: SemVerStyle; - if (version && version !== 'latest') { - 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._packageName.longName} specifier. In this case "${version}" was provided.` - ); - } - - rangeStyle = SemVerStyle.Passthrough; - } else { - rangeStyle = this._caretFlag.value - ? SemVerStyle.Caret - : (this._exactFlag.value ? SemVerStyle.Exact : SemVerStyle.Tilde); - } - - await updater.doRushAdd({ - projects: projects, - packageName: packageName, - initialVersion: version, - devDependency: this._devDependencyFlag.value, - updateOtherPackages: this._makeConsistentFlag.value, - skipUpdate: this._skipUpdateFlag.value, - debugInstall: this.parser.isDebug, - rangeStyle: rangeStyle - }); - } -} diff --git a/apps/rush-lib/src/cli/actions/BaseInstallAction.ts b/apps/rush-lib/src/cli/actions/BaseInstallAction.ts deleted file mode 100644 index 452a2182be9..00000000000 --- a/apps/rush-lib/src/cli/actions/BaseInstallAction.ts +++ /dev/null @@ -1,164 +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 colors from 'colors'; -import * as os from 'os'; - -import { - CommandLineFlagParameter, - CommandLineIntegerParameter, - CommandLineStringParameter -} from '@rushstack/ts-command-line'; - -import { BaseRushAction } from './BaseRushAction'; -import { Event } from '../../api/EventHooks'; -import { InstallManager, IInstallManagerOptions } from '../../logic/InstallManager'; -import { PurgeManager } from '../../logic/PurgeManager'; -import { SetupChecks } from '../../logic/SetupChecks'; -import { StandardScriptUpdater } from '../../logic/StandardScriptUpdater'; -import { Stopwatch } from '../../utilities/Stopwatch'; -import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; -import { Variants } from '../../api/Variants'; -import { RushConstants } from '../../logic/RushConstants'; - -/** - * This is the common base class for InstallAction and UpdateAction. - */ -export abstract class BaseInstallAction extends BaseRushAction { - protected _variant: CommandLineStringParameter; - protected _purgeParameter: CommandLineFlagParameter; - protected _bypassPolicyParameter: CommandLineFlagParameter; - protected _noLinkParameter: CommandLineFlagParameter; - protected _networkConcurrencyParameter: CommandLineIntegerParameter; - protected _debugPackageManagerParameter: CommandLineFlagParameter; - protected _maxInstallAttempts: CommandLineIntegerParameter; - - protected onDefineParameters(): void { - this._purgeParameter = this.defineFlagParameter({ - parameterLongName: '--purge', - parameterShortName: '-p', - description: 'Perform "rush purge" before starting the installation' - }); - this._bypassPolicyParameter = this.defineFlagParameter({ - parameterLongName: '--bypass-policy', - description: 'Overrides enforcement of the "gitPolicy" rules from rush.json (use honorably!)' - }); - this._noLinkParameter = this.defineFlagParameter({ - parameterLongName: '--no-link', - description: 'If "--no-link" is specified, then project symlinks will NOT be created' - + ' after the installation completes. You will need to run "rush link" manually.' - + ' This flag is useful for automated builds that want to report stages individually' - + ' or perform extra operations in between the two stages.' - }); - this._networkConcurrencyParameter = this.defineIntegerParameter({ - parameterLongName: '--network-concurrency', - argumentName: 'COUNT', - description: 'If specified, limits the maximum number of concurrent network requests.' - + ' This is useful when troubleshooting network failures.' - }); - this._debugPackageManagerParameter = this.defineFlagParameter({ - parameterLongName: '--debug-package-manager', - description: 'Activates verbose logging for the package manager. You will probably want to pipe' - + ' the output of Rush to a file when using this command.' - }); - this._maxInstallAttempts = this.defineIntegerParameter({ - parameterLongName: '--max-install-attempts', - argumentName: 'NUMBER', - description: `Overrides the default maximum number of install attempts.`, - defaultValue: RushConstants.defaultMaxInstallAttempts - }); - this._variant = this.defineStringParameter(Variants.VARIANT_PARAMETER); - } - - protected abstract buildInstallOptions(): IInstallManagerOptions; - - protected run(): Promise { - VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, { - variant: this._variant.value - }); - - const stopwatch: Stopwatch = Stopwatch.start(); - - SetupChecks.validate(this.rushConfiguration); - let warnAboutScriptUpdate: boolean = false; - if (this.actionName === 'update') { - warnAboutScriptUpdate = StandardScriptUpdater.update(this.rushConfiguration); - } else { - StandardScriptUpdater.validate(this.rushConfiguration); - } - - this.eventHooksManager.handle(Event.preRushInstall, this.parser.isDebug); - - const purgeManager: PurgeManager = new PurgeManager(this.rushConfiguration, this.rushGlobalFolder); - - if (this._purgeParameter.value!) { - console.log('The --purge flag was specified, so performing "rush purge"'); - purgeManager.purgeNormal(); - console.log(''); - } - - if (this._networkConcurrencyParameter.value) { - if (this.rushConfiguration.packageManager !== 'pnpm') { - throw new Error(`The "${this._networkConcurrencyParameter.longName}" parameter is` - + ` only supported when using the PNPM package manager.`); - } - } - - // Because the 'defautltValue' option on the _maxInstallAttempts parameter is set, - // it is safe to assume that the value is not null - if (this._maxInstallAttempts.value! < 1) { - throw new Error(`The value of "${this._maxInstallAttempts.longName}" must be positive and nonzero.`); - } - - const installManagerOptions: IInstallManagerOptions = this.buildInstallOptions(); - - const installManager: InstallManager = new InstallManager( - this.rushConfiguration, - this.rushGlobalFolder, - purgeManager, - installManagerOptions - ); - - return installManager.doInstall() - .then(() => { - purgeManager.deleteAll(); - stopwatch.stop(); - - this._collectTelemetry(stopwatch, installManagerOptions, true); - this.eventHooksManager.handle(Event.postRushInstall, this.parser.isDebug); - - if (warnAboutScriptUpdate) { - console.log(os.EOL + colors.yellow('Rush refreshed some files in the "common/scripts" folder.' - + ' Please commit this change to Git.')); - } - - console.log(os.EOL + colors.green( - `Rush ${this.actionName} finished successfully. (${stopwatch.toString()})`)); - }) - .catch((error) => { - purgeManager.deleteAll(); - stopwatch.stop(); - - this._collectTelemetry(stopwatch, installManagerOptions, false); - throw error; - }); - } - - private _collectTelemetry(stopwatch: Stopwatch, installManagerOptions: IInstallManagerOptions, - success: boolean): void { - - if (this.parser.telemetry) { - this.parser.telemetry.log({ - name: 'install', - duration: stopwatch.duration, - result: success ? 'Succeeded' : 'Failed', - extraData: { - mode: this.actionName, - clean: (!!this._purgeParameter.value).toString(), - full: installManagerOptions.fullUpgrade.toString() - } - }); - } - } - -} diff --git a/apps/rush-lib/src/cli/actions/BaseRushAction.ts b/apps/rush-lib/src/cli/actions/BaseRushAction.ts deleted file mode 100644 index 6618bd64469..00000000000 --- a/apps/rush-lib/src/cli/actions/BaseRushAction.ts +++ /dev/null @@ -1,123 +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 colors from 'colors'; -import * as os from 'os'; -import * as path from 'path'; - -import { - CommandLineAction, - ICommandLineActionOptions -} from '@rushstack/ts-command-line'; - -import { LockFile } from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { EventHooksManager } from '../../logic/EventHooksManager'; -import { RushCommandLineParser } from './../RushCommandLineParser'; -import { Utilities } from '../../utilities/Utilities'; -import { RushGlobalFolder } from '../../api/RushGlobalFolder'; - -export interface IBaseRushActionOptions extends ICommandLineActionOptions { - /** - * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously - * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the - * same time.) If your command makes sense to run concurrently with other operations, - * set safeForSimultaneousRushProcesses=true to disable this protection. In particular, this is needed for - * custom scripts that invoke other Rush commands. - */ - safeForSimultaneousRushProcesses?: boolean; - - /** - * The rush parser. - */ - parser: RushCommandLineParser; -} - -/** - * The base class for a few specialized Rush command-line actions that - * can be used without a rush.json configuration. - */ -export abstract class BaseConfiglessRushAction extends CommandLineAction { - private _parser: RushCommandLineParser; - private _safeForSimultaneousRushProcesses: boolean; - - protected get rushConfiguration(): RushConfiguration | undefined { - return this._parser.rushConfiguration; - } - - protected get rushGlobalFolder(): RushGlobalFolder { - return this._parser.rushGlobalFolder; - } - - protected get parser(): RushCommandLineParser { - return this._parser; - } - - public constructor(options: IBaseRushActionOptions) { - super(options); - - this._parser = options.parser; - this._safeForSimultaneousRushProcesses = !!options.safeForSimultaneousRushProcesses; - } - - protected onExecute(): Promise { - this._ensureEnvironment(); - - if (this.rushConfiguration) { - if (!this._safeForSimultaneousRushProcesses) { - if (!LockFile.tryAcquire(this.rushConfiguration.commonTempFolder, 'rush')) { - console.log(colors.red(`Another rush command is already running in this repository.`)); - process.exit(1); - } - } - } - - console.log(`Starting "rush ${this.actionName}"${os.EOL}`); - return this.run(); - } - - /** - * All Rush actions need to implement this method. This method runs after - * environment has been set up by the base class. - */ - protected abstract run(): Promise; - - private _ensureEnvironment(): void { - if (this.rushConfiguration) { - // eslint-disable-next-line dot-notation - let environmentPath: string | undefined = process.env['PATH']; - environmentPath = path.join(this.rushConfiguration.commonTempFolder, 'node_modules', '.bin') + - path.delimiter + environmentPath; - // eslint-disable-next-line dot-notation - process.env['PATH'] = environmentPath; - } - } -} - -/** - * The base class that most Rush command-line actions should extend. - */ -export abstract class BaseRushAction extends BaseConfiglessRushAction { - private _eventHooksManager: EventHooksManager; - - protected get rushConfiguration(): RushConfiguration { - return super.rushConfiguration!; - } - - protected onExecute(): Promise { - if (!this.rushConfiguration) { - throw Utilities.getRushConfigNotFoundError(); - } - - return super.onExecute(); - } - - protected get eventHooksManager(): EventHooksManager { - if (!this._eventHooksManager) { - this._eventHooksManager = new EventHooksManager(this.rushConfiguration); - } - - return this._eventHooksManager; - } -} diff --git a/apps/rush-lib/src/cli/actions/ChangeAction.ts b/apps/rush-lib/src/cli/actions/ChangeAction.ts deleted file mode 100644 index effeae10f4a..00000000000 --- a/apps/rush-lib/src/cli/actions/ChangeAction.ts +++ /dev/null @@ -1,665 +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'; -import * as path from 'path'; -import * as child_process from 'child_process'; -import * as colors from 'colors'; -import * as inquirer from 'inquirer'; - -import { - CommandLineFlagParameter, - CommandLineStringParameter, - CommandLineChoiceParameter -} from '@rushstack/ts-command-line'; -import { - FileSystem, - Path -} from '@rushstack/node-core-library'; - -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { - IChangeFile, - IChangeInfo, - ChangeType -} from '../../api/ChangeManagement'; -import { VersionControl } from '../../utilities/VersionControl'; -import { ChangeFile } from '../../api/ChangeFile'; -import { BaseRushAction } from './BaseRushAction'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { ChangeFiles } from '../../logic/ChangeFiles'; -import { - VersionPolicy, - IndividualVersionPolicy, - LockStepVersionPolicy, - VersionPolicyDefinitionName -} from '../../api/VersionPolicy'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; - -export class ChangeAction extends BaseRushAction { - private _verifyParameter: CommandLineFlagParameter; - private _noFetchParameter: CommandLineFlagParameter; - private _targetBranchParameter: CommandLineStringParameter; - private _changeEmailParameter: CommandLineStringParameter; - private _bulkChangeParameter: CommandLineFlagParameter; - private _bulkChangeMessageParameter: CommandLineStringParameter; - private _bulkChangeBumpTypeParameter: CommandLineChoiceParameter; - private _overwriteFlagParameter: CommandLineFlagParameter; - - private _targetBranchName: string; - private _projectHostMap: Map; - - public constructor(parser: RushCommandLineParser) { - const documentation: string[] = [ - 'Asks a series of questions and then generates a -.json file ' + - 'in the common folder. The `publish` command will consume these files and perform the proper ' + - 'version bumps. Note these changes will eventually be published in a changelog.md file in each package.', - '', - 'The possible types of changes are: ', - '', - 'MAJOR - these are breaking changes that are not backwards compatible. ' + - 'Examples are: renaming a public class, adding/removing a non-optional ' + - 'parameter from a public API, or renaming an variable or function that ' + - 'is exported.', - '', - 'MINOR - these are changes that are backwards compatible (but not ' + - 'forwards compatible). Examples are: adding a new public API or adding an ' + - 'optional parameter to a public API', - '', - 'PATCH - these are changes that are backwards and forwards compatible. ' + - 'Examples are: Modifying a private API or fixing a bug in the logic ' + - 'of how an existing API works.', - '', - 'HOTFIX (EXPERIMENTAL) - these are changes that are hotfixes targeting a ' + - 'specific older version of the package. When a hotfix change is added, ' + - 'other changes will not be able to increment the version number.' + - 'Enable this feature by setting \'hotfixChangeEnabled\' in your rush.json.', - '' - ]; - super({ - actionName: 'change', - summary: 'Records changes made to projects, indicating how the package version number should be bumped ' + - 'for the next publish.', - documentation: documentation.join(os.EOL), - safeForSimultaneousRushProcesses: true, - parser - }); - } - - public onDefineParameters(): void { - const BULK_LONG_NAME: string = '--bulk'; - const BULK_MESSAGE_LONG_NAME: string = '--message'; - const BULK_BUMP_TYPE_LONG_NAME: string = '--bump-type'; - - this._verifyParameter = this.defineFlagParameter({ - parameterLongName: '--verify', - parameterShortName: '-v', - description: 'Verify the change file has been generated and that it is a valid JSON file' - }); - - this._noFetchParameter = this.defineFlagParameter({ - parameterLongName: '--no-fetch', - description: 'Skips fetching the baseline branch before running "git diff" to detect changes.' - }); - - this._targetBranchParameter = this.defineStringParameter({ - parameterLongName: '--target-branch', - parameterShortName: '-b', - argumentName: 'BRANCH', - description: 'If this parameter is specified, compare the checked out branch with the specified branch to' + - 'determine which projects were changed. If this parameter is not specified, the checked out branch ' + - 'is compared against the "master" branch.' - }); - - this._overwriteFlagParameter = this.defineFlagParameter({ - parameterLongName: '--overwrite', - description: `If a changefile already exists, overwrite without prompting ` + - `(or erroring in ${BULK_LONG_NAME} mode).` - }); - - this._changeEmailParameter = this.defineStringParameter({ - parameterLongName: '--email', - argumentName: 'EMAIL', - description: 'The email address to use in changefiles. If this parameter is not provided, the email address ' + - 'will be detected or prompted for in interactive mode.' - }); - - this._bulkChangeParameter = this.defineFlagParameter({ - parameterLongName: BULK_LONG_NAME, - description: 'If this flag is specified, apply the same change message and bump type to all changed projects. ' + - `The ${BULK_MESSAGE_LONG_NAME} and the ${BULK_BUMP_TYPE_LONG_NAME} parameters must be specified if the ` + - `${BULK_LONG_NAME} parameter is specified` - }); - - this._bulkChangeMessageParameter = this.defineStringParameter({ - parameterLongName: BULK_MESSAGE_LONG_NAME, - argumentName: 'MESSAGE', - description: `The message to apply to all changed projects if the ${BULK_LONG_NAME} flag is provided.` - }); - - this._bulkChangeBumpTypeParameter = this.defineChoiceParameter({ - parameterLongName: BULK_BUMP_TYPE_LONG_NAME, - alternatives: [...Object.keys(this._getBumpOptions()), ChangeType[ChangeType.none]], - description: `The bump type to apply to all changed projects if the ${BULK_LONG_NAME} flag is provided.` - }); - } - - public async run(): Promise { - console.log(`The target branch is ${this._targetBranch}`); - this._projectHostMap = this._generateHostMap(); - - if (this._verifyParameter.value) { - const errors: string[] = ([ - this._bulkChangeParameter, - this._bulkChangeMessageParameter, - this._bulkChangeBumpTypeParameter, - this._overwriteFlagParameter - ]).map((parameter) => { - return parameter.value - ? ( - `The {${this._bulkChangeParameter.longName} parameter cannot be provided with the ` + - `${this._verifyParameter.longName} parameter` - ) - : ''; - }).filter((error) => error !== ''); - if (errors.length > 0) { - errors.forEach((error) => console.error(error)); - throw new AlreadyReportedError(); - } - - this._verify(); - return; - } - - const sortedProjectList: string[] = this._getChangedPackageNames().sort(); - if (sortedProjectList.length === 0) { - this._logNoChangeFileRequired(); - this._warnUncommittedChanges(); - return; - } - - this._warnUncommittedChanges(); - - const promptModule: inquirer.PromptModule = inquirer.createPromptModule(); - let changeFileData: Map = new Map(); - let interactiveMode: boolean = false; - if (this._bulkChangeParameter.value) { - if ( - !this._bulkChangeBumpTypeParameter.value || - ( - !this._bulkChangeMessageParameter.value && - this._bulkChangeBumpTypeParameter.value !== ChangeType[ChangeType.none] - ) - ) { - throw new Error( - `The ${this._bulkChangeBumpTypeParameter.longName} and ${this._bulkChangeMessageParameter.longName} ` + - `parameters must provided if the ${this._bulkChangeParameter.longName} flag is provided. If the value ` + - `"${ChangeType[ChangeType.none]}" is provided to the ${this._bulkChangeBumpTypeParameter.longName} ` + - `parameter, the ${this._bulkChangeMessageParameter.longName} parameter may be omitted.` - ); - } - - const email: string | undefined = this._changeEmailParameter.value || this._detectEmail(); - if (!email) { - throw new Error( - 'Unable to detect Git email and an email address wasn\'t provided using the ' + - `${this._changeEmailParameter.longName} paramter.` - ); - } - - const errors: string[] = []; - - const comment: string = this._bulkChangeMessageParameter.value || ''; - const changeType: string = this._bulkChangeBumpTypeParameter.value; - for (const packageName of sortedProjectList) { - const allowedBumpTypes: string[] = Object.keys(this._getBumpOptions(packageName)); - let projectChangeType: string = changeType; - if (allowedBumpTypes.length === 0) { - projectChangeType = ChangeType[ChangeType.none]; - } else if ( - projectChangeType !== ChangeType[ChangeType.none] && - allowedBumpTypes.indexOf(projectChangeType) === -1 - ) { - errors.push(`The "${projectChangeType}" change type is not allowed for package "${packageName}".`); - } - - changeFileData.set( - packageName, - { - changes: [ - { - comment, - type: projectChangeType, - packageName - } as IChangeInfo - ], - packageName, - email - } - ); - } - - if (errors.length > 0) { - for (const error of errors) { - console.error(error); - } - - throw new AlreadyReportedError(); - } - } else if (this._bulkChangeBumpTypeParameter.value || this._bulkChangeMessageParameter.value) { - throw new Error( - `The ${this._bulkChangeParameter.longName} flag must be provided with the ` + - `${this._bulkChangeBumpTypeParameter.longName} and ${this._bulkChangeMessageParameter.longName} parameters.` - ); - } else { - interactiveMode = true; - - const existingChangeComments: Map = ChangeFiles.getChangeComments(this._getChangeFiles()); - changeFileData = await this._promptForChangeFileData( - promptModule, - sortedProjectList, - existingChangeComments - ); - - const email: string = this._changeEmailParameter.value - ? this._changeEmailParameter.value - : await this._detectOrAskForEmail(promptModule); - changeFileData.forEach((changeFile: IChangeFile) => { - changeFile.email = email; - }); - } - - try { - return await this._writeChangeFiles( - promptModule, - changeFileData, - this._overwriteFlagParameter.value, - interactiveMode - ); - } catch (error) { - throw new Error(`There was an error creating a change file: ${error.toString()}`); - } - } - - private _generateHostMap(): Map { - const hostMap: Map = new Map(); - this.rushConfiguration.projects.forEach(project => { - let hostProjectName: string = project.packageName; - if (project.versionPolicy && project.versionPolicy.isLockstepped) { - const lockstepPolicy: LockStepVersionPolicy = project.versionPolicy as LockStepVersionPolicy; - hostProjectName = lockstepPolicy.mainProject || project.packageName; - } - - hostMap.set(project.packageName, hostProjectName); - }); - - return hostMap; - } - - private _verify(): void { - const changedPackages: string[] = this._getChangedPackageNames(); - if (changedPackages.length > 0) { - this._validateChangeFile(changedPackages); - } else { - this._logNoChangeFileRequired(); - } - } - - private get _targetBranch(): string { - if (!this._targetBranchName) { - this._targetBranchName = ( - this._targetBranchParameter.value || VersionControl.getRemoteMasterBranch(this.rushConfiguration) - ); - } - - return this._targetBranchName; - } - - private _getChangedPackageNames(): string[] { - const changedFolders: (string | undefined)[] | undefined = VersionControl.getChangedFolders( - this._targetBranch, - this._noFetchParameter.value - ); - if (!changedFolders) { - return []; - } - const changedPackageNames: Set = new Set(); - - const repoRootFolder: string | undefined = VersionControl.getRepositoryRootPath(); - this.rushConfiguration.projects - .filter(project => project.shouldPublish) - .filter(project => !project.versionPolicy || !project.versionPolicy.exemptFromRushChange) - .filter(project => { - const projectFolder: string = repoRootFolder - ? path.relative(repoRootFolder, project.projectFolder) - : project.projectRelativeFolder; - return this._hasProjectChanged(changedFolders, projectFolder); - }) - .forEach(project => { - const hostName: string | undefined = this._projectHostMap.get(project.packageName); - if (hostName) { - changedPackageNames.add(hostName); - } - }); - - return [...changedPackageNames]; - } - - private _validateChangeFile(changedPackages: string[]): void { - const files: string[] = this._getChangeFiles(); - ChangeFiles.validate(files, changedPackages, this.rushConfiguration); - } - - private _getChangeFiles(): string[] { - return VersionControl.getChangedFiles(this._targetBranch, true, `common/changes/`).map(relativePath => { - return path.join(this.rushConfiguration.rushJsonFolder, relativePath); - }); - } - - private _hasProjectChanged( - changedFolders: (string | undefined)[], - projectFolder: string - ): boolean { - for (const folder of changedFolders) { - if (folder && Path.isUnderOrEqual(folder, projectFolder)) { - return true; - } - } - - return false; - } - - /** - * The main loop which prompts the user for information on changed projects. - */ - private async _promptForChangeFileData( - promptModule: inquirer.PromptModule, - sortedProjectList: string[], - existingChangeComments: Map - ): Promise> { - const changedFileData: Map = new Map(); - - for (const projectName of sortedProjectList) { - const changeInfo: IChangeInfo | undefined = await this._askQuestions( - promptModule, - projectName, - existingChangeComments - ); - if (changeInfo) { - // Save the info into the change file - let changeFile: IChangeFile | undefined = changedFileData.get(changeInfo.packageName); - if (!changeFile) { - changeFile = { - changes: [], - packageName: changeInfo.packageName, - email: undefined - }; - changedFileData.set(changeInfo.packageName, changeFile!); - } - - changeFile!.changes.push(changeInfo); - } - } - - return changedFileData; - } - - /** - * Asks all questions which are needed to generate changelist for a project. - */ - private async _askQuestions( - promptModule: inquirer.PromptModule, - packageName: string, - existingChangeComments: Map - ): Promise { - console.log(`${os.EOL}${packageName}`); - const comments: string[] | undefined = existingChangeComments.get(packageName); - if (comments) { - console.log(`Found existing comments:`); - comments.forEach(comment => { - console.log(` > ${comment}`); - }); - const { appendComment }: { appendComment: 'skip' | 'append' } = await promptModule({ - name: 'appendComment', - type: 'list', - default: 'skip', - message: 'Append to existing comments or skip?', - choices: [ - { - 'name': 'Skip', - 'value': 'skip' - }, - { - 'name': 'Append', - 'value': 'append' - } - ] - }); - - if (appendComment === 'skip') { - return undefined; - } else { - return await this._promptForComments(promptModule, packageName); - } - } else { - return await this._promptForComments(promptModule, packageName); - } - } - - private async _promptForComments( - promptModule: inquirer.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:` - }); - - if (Object.keys(bumpOptions).length === 0 || !comment) { - return { - packageName: packageName, - comment: comment || '', - type: ChangeType[ChangeType.none] - } as IChangeInfo; - } else { - const { bumpType }: { bumpType: string } = await promptModule({ - choices: Object.keys(bumpOptions).map(option => { - return { - 'value': option, - 'name': bumpOptions[option] - }; - }), - default: 'patch', - message: 'Select the type of change:', - name: 'bumpType', - type: 'list' - }); - - return { - packageName: packageName, - comment: comment, - type: bumpType - } as IChangeInfo; - } - } - - private _getBumpOptions(packageName?: string): { [type: string]: string } { - let bumpOptions: { [type: string]: string } = (this.rushConfiguration && this.rushConfiguration.hotfixChangeEnabled) - ? { - [ChangeType[ChangeType.hotfix]]: 'hotfix - for changes that need to be published in a separate hotfix package' - } - : { - [ChangeType[ChangeType.major]]: 'major - for changes that break compatibility, e.g. removing an API', - [ChangeType[ChangeType.minor]]: 'minor - for backwards compatible changes, e.g. adding a new API', - [ChangeType[ChangeType.patch]]: 'patch - for changes that do not affect compatibility, e.g. fixing a bug' - }; - - if (packageName) { - const project: RushConfigurationProject | undefined = this.rushConfiguration.getProjectByName(packageName); - const versionPolicy: VersionPolicy | undefined = project!.versionPolicy; - - if (versionPolicy) { - if (versionPolicy.definitionName === VersionPolicyDefinitionName.lockStepVersion) { - // No need to ask for bump types if project is lockstep versioned. - bumpOptions = {}; - } else if (versionPolicy.definitionName === VersionPolicyDefinitionName.individualVersion) { - const individualPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; - if (individualPolicy.lockedMajor !== undefined) { - delete bumpOptions[ChangeType[ChangeType.major]]; - } - } - } - } - - return bumpOptions; - } - - /** - * 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 _detectOrAskForEmail(promptModule: inquirer.PromptModule): Promise { - return await this._detectAndConfirmEmail(promptModule) || await this._promptForEmail(promptModule); - } - - private _detectEmail(): string | undefined { - try { - return child_process.execSync('git config user.email') - .toString() - .replace(/(\r\n|\n|\r)/gm, ''); - } catch (err) { - console.log('There was an issue detecting your Git email...'); - return undefined; - } - } - - /** - * 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 _detectAndConfirmEmail(promptModule: inquirer.PromptModule): 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}?` - } - ]); - return isCorrectEmail ? email : undefined; - } else { - return undefined; - } - } - - /** - * Asks the user for their email address - */ - private async _promptForEmail(promptModule: inquirer.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 - } - } - ]); - return email; - } - - private _warnUncommittedChanges(): void { - try { - if (VersionControl.hasUncommittedChanges()) { - console.log( - os.EOL + - colors.yellow( - 'Warning: You have uncommitted changes, which do not trigger prompting for change ' + - 'descriptions.' - ) - ); - } - } catch (error) { - console.log(`An error occurred when detecting uncommitted changes: ${error}`); - } - } - - /** - * Writes change files to the common/changes folder. Will prompt for overwrite if file already exists. - */ - private async _writeChangeFiles( - promptModule: inquirer.PromptModule, - changeFileData: Map, - overwrite: boolean, - interactiveMode: boolean - ): Promise { - await changeFileData.forEach(async (changeFile: IChangeFile) => { - await this._writeChangeFile(promptModule, changeFile, overwrite, interactiveMode); - }); - } - - private async _writeChangeFile( - promptModule: inquirer.PromptModule, - changeFileData: IChangeFile, - overwrite: boolean, - interactiveMode: boolean - ): Promise { - const output: string = JSON.stringify(changeFileData, undefined, 2); - const changeFile: ChangeFile = new ChangeFile(changeFileData, this.rushConfiguration); - const filePath: string = changeFile.generatePath(); - - const fileExists: boolean = FileSystem.exists(filePath); - const shouldWrite: boolean = ( - !fileExists || - overwrite || - (interactiveMode ? await this._promptForOverwrite(promptModule, filePath) : false) - ); - - if (!interactiveMode && fileExists && !overwrite) { - throw new Error(`Changefile ${filePath} already exists`); - } - - if (shouldWrite) { - this._writeFile(filePath, output, shouldWrite && fileExists); - } - } - - private async _promptForOverwrite(promptModule: inquirer.PromptModule, filePath: string): Promise { - const overwrite: boolean = await promptModule([ - { - name: 'overwrite', - type: 'confirm', - message: `Overwrite ${filePath}?` - } - ]); - - if (overwrite) { - return true; - } else { - console.log(`Not overwriting ${filePath}`); - return false; - } - } - - /** - * Writes a file to disk, ensuring the directory structure up to that point exists - */ - private _writeFile(fileName: string, output: string, isOverwrite: boolean): void { - FileSystem.writeFile(fileName, output, { ensureFolderExists: true }); - if (isOverwrite) { - console.log(`Overwrote file: ${fileName}`); - } else { - console.log(`Created file: ${fileName}`); - } - } - - private _logNoChangeFileRequired(): void { - console.log('No changes were detected to relevant packages on this branch. Nothing to do.'); - } -} diff --git a/apps/rush-lib/src/cli/actions/CheckAction.ts b/apps/rush-lib/src/cli/actions/CheckAction.ts deleted file mode 100644 index c89ba9bf706..00000000000 --- a/apps/rush-lib/src/cli/actions/CheckAction.ts +++ /dev/null @@ -1,55 +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 colors from 'colors'; -import { - CommandLineStringParameter, - CommandLineFlagParameter -} from '@rushstack/ts-command-line'; - -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { BaseRushAction } from './BaseRushAction'; -import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; -import { Variants } from '../../api/Variants'; - -export class CheckAction extends BaseRushAction { - private _variant: CommandLineStringParameter; - private _jsonFlag: CommandLineFlagParameter; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'check', - summary: 'Checks each project\'s package.json files and ensures that all dependencies are of the same ' + - 'version throughout the repository.', - documentation: 'Checks each project\'s package.json files and ensures that all dependencies are of the ' + - 'same version throughout the repository.', - safeForSimultaneousRushProcesses: true, - parser - }); - } - - protected onDefineParameters(): void { - this._variant = this.defineStringParameter(Variants.VARIANT_PARAMETER); - this._jsonFlag = this.defineFlagParameter({ - parameterLongName: '--json', - description: 'If this flag is specified, output will be in JSON format.' - }); - } - - protected run(): Promise { - const variant: string | undefined = this.rushConfiguration.currentInstalledVariant; - - if (!this._variant.value && variant) { - console.log(colors.yellow( - `Variant '${variant}' has been installed, but 'rush check' is currently checking the default variant. ` + - `Use 'rush check --variant '${ variant }' to check the current installation.` - )); - } - - VersionMismatchFinder.rushCheck(this.rushConfiguration, { - variant: this._variant.value, - printAsJson: this._jsonFlag.value - }); - return Promise.resolve(); - } -} diff --git a/apps/rush-lib/src/cli/actions/InitAction.ts b/apps/rush-lib/src/cli/actions/InitAction.ts deleted file mode 100644 index 2265f5f5b50..00000000000 --- a/apps/rush-lib/src/cli/actions/InitAction.ts +++ /dev/null @@ -1,342 +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 colors from 'colors'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; - -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { BaseConfiglessRushAction } from './BaseRushAction'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; -import { FileSystem, NewlineKind, InternalError } from '@rushstack/node-core-library'; -import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { Rush } from '../../api/Rush'; - -export class InitAction extends BaseConfiglessRushAction { - // Matches a well-formed BEGIN macro starting a block section. - // Example: /*[BEGIN "DEMO"]*/ - // - // Group #1 is the indentation spaces before the macro - // Group #2 is the section name - private static _beginMacroRegExp: RegExp = /^(\s*)\/\*\[BEGIN "([A-Z]+)"\]\s*\*\/\s*$/; - - // Matches a well-formed END macro ending a block section. - // Example: /*[END "DEMO"]*/ - // - // Group #1 is the indentation spaces before the macro - // Group #2 is the section name - private static _endMacroRegExp: RegExp = /^(\s*)\/\*\[END "([A-Z]+)"\]\s*\*\/\s*$/; - - // Matches a well-formed single-line section, including the space character after it - // if present. - // Example: /*[LINE "HYPOTHETICAL"]*/ - // - // Group #1 is the section name - private static _lineMacroRegExp: RegExp = /\/\*\[LINE "([A-Z]+)"\]\s*\*\/\s?/; - - // Matches a variable expansion. - // Example: [%RUSH_VERSION%] - // - // Group #1 is the variable name including the dollar sign - private static _variableMacroRegExp: RegExp = /\[(%[A-Z0-9_]+%)\]/; - - // Matches anything that starts with "/*[" and ends with "]*/" - // Used to catch malformed macro expressions - private static _anyMacroRegExp: RegExp = /\/\*\s*\[.*\]\s*\*\//; - - private _overwriteParameter: CommandLineFlagParameter; - private _rushExampleParameter: CommandLineFlagParameter; - - // template section name --> whether it should be commented out - private _commentedBySectionName: Map = new Map(); - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'init', - summary: 'Initializes a new repository to be managed by Rush', - documentation: 'When invoked in an empty folder, this command provisions a standard' - + ' set of config file templates to start managing projects using Rush.', - parser - }); - } - - protected onDefineParameters(): void { // abstract - this._overwriteParameter = this.defineFlagParameter({ - parameterLongName: '--overwrite-existing', - description: 'By default "rush init" will not overwrite existing config files.' - + ' Specify this switch to override that. This can be useful when upgrading' - + ' your repo to a newer release of Rush. WARNING: USE WITH CARE!' - }); - this._rushExampleParameter = this.defineFlagParameter({ - parameterLongName: '--rush-example-repo', - description: 'When copying the template config files, this uncomments fragments that are used' - + ' by the "rush-example" GitHub repo, which is a sample monorepo that illustrates many Rush' - + ' features. This option is primarily intended for maintaining that example.' - }); - } - - protected run(): Promise { - const initFolder: string = process.cwd(); - - if (!this._overwriteParameter.value) { - if (!this._validateFolderIsEmpty(initFolder)) { - return Promise.reject(new AlreadyReportedError()); - } - } - - this._defineMacroSections(); - this._copyTemplateFiles(initFolder); - - return Promise.resolve(); - } - - private _defineMacroSections(): void { - this._commentedBySectionName.clear(); - - // The "HYPOTHETICAL" sections are always commented out by "rush init". - // They are uncommented in the "assets" source folder so that we can easily validate - // that they conform to their JSON schema. - this._commentedBySectionName.set('HYPOTHETICAL', true); - - // The "DEMO" sections are uncommented only when "--rush-example-repo" is specified. - this._commentedBySectionName.set('DEMO', !this._rushExampleParameter.value); - } - - // Check whether it's safe to run "rush init" in the current working directory. - private _validateFolderIsEmpty(initFolder: string): boolean { - if (this.rushConfiguration !== undefined) { - console.error(colors.red('ERROR: Found an existing configuration in: ' - + this.rushConfiguration.rushJsonFile)); - console.log(os.EOL + 'The "rush init" command must be run in a new folder without ' - + 'an existing Rush configuration.'); - return false; - } - - for (const itemName of FileSystem.readFolder(initFolder)) { - if (itemName.substr(0, 1) === '.') { - // Ignore any items that start with ".", for example ".git" - continue; - } - - const itemPath: string = path.join(initFolder, itemName); - - const stats: fs.Stats = FileSystem.getStatistics(itemPath); - // Ignore any loose files in the current folder, e.g. "README.md" - // or "CONTRIBUTING.md" - if (stats.isDirectory()) { - console.error(colors.red(`ERROR: Found a subdirectory: "${itemName}"`)); - console.log(os.EOL + 'The "rush init" command must be run in a new folder with no projects added yet.'); - return false; - } else { - if (itemName.toLowerCase() === 'package.json') { - console.error(colors.red(`ERROR: Found a package.json file in this folder`)); - console.log(os.EOL + 'The "rush init" command must be run in a new folder with no projects added yet.'); - return false; - } - } - } - return true; - } - - private _copyTemplateFiles(initFolder: string): void { - // The "[dot]" base name is used for hidden files to prevent various tools from interpreting them. - // For example, "npm publish" will always exclude the filename ".gitignore" - const templateFilePaths: string[] = [ - 'rush.json', - '[dot]gitattributes', - '[dot]gitignore', - '[dot]travis.yml', - 'common/config/rush/[dot]npmrc', - 'common/config/rush/command-line.json', - 'common/config/rush/common-versions.json', - 'common/config/rush/experiments.json', - 'common/config/rush/pnpmfile.js', - 'common/config/rush/version-policies.json' - ]; - - const assetsSubfolder: string = path.resolve(__dirname, '../../../assets/rush-init'); - - for (const templateFilePath of templateFilePaths) { - const sourcePath: string = path.join(assetsSubfolder, templateFilePath); - - if (!FileSystem.exists(sourcePath)) { - // If this happens, please report a Rush bug - throw new InternalError('Unable to find template input file: ' + sourcePath); - } - - const destinationPath: string = path.join(initFolder, templateFilePath) - .replace('[dot]', '.'); - - this._copyTemplateFile(sourcePath, destinationPath); - } - } - - // Copy the template from sourcePath, transform any macros, and write the output to destinationPath. - // - // We implement a simple template engine. "Single-line section" macros have this form: - // - // /*[LINE "NAME"]*/ (content goes here) - // - // ...and when commented out will look like this: - // - // // (content goes here) - // - // "Block section" macros have this form: - // - // /*[BEGIN "NAME"]*/ - // (content goes - // here) - // /*[END "NAME"]*/ - // - // ...and when commented out will look like this: - // - // // (content goes - // // here) - // - // Lastly, a variable expansion has this form: - // - // // The value is [%NAME%]. - // - // ...and when expanded with e.g. "123" will look like this: - // - // // The value is 123. - // - // The section names must be one of the predefined names used by "rush init". - // A single-line section may appear inside a block section, in which case it will get - // commented twice. - private _copyTemplateFile(sourcePath: string, destinationPath: string): void { - if (!this._overwriteParameter.value) { - if (FileSystem.exists(destinationPath)) { - console.log(colors.yellow('Not overwriting already existing file: ') + destinationPath); - return; - } - } - - if (FileSystem.exists(destinationPath)) { - console.log(colors.yellow(`Overwriting: ${destinationPath}`)); - } else { - console.log(`Generating: ${destinationPath}`); - } - - const outputLines: string[] = []; - const lines: string[] = FileSystem.readFile(sourcePath, { convertLineEndings: NewlineKind.Lf }) - .split('\n'); - - let activeBlockSectionName: string | undefined = undefined; - let activeBlockIndent: string = ''; - - for (const line of lines) { - let match: RegExpMatchArray | null; - - // Check for a block section start - // Example: /*[BEGIN "DEMO"]*/ - match = line.match(InitAction._beginMacroRegExp); - if (match) { - if (activeBlockSectionName) { - // If this happens, please report a Rush bug - throw new InternalError(`The template contains an unmatched BEGIN macro for "${activeBlockSectionName}"`); - } - - activeBlockSectionName = match[2]; - activeBlockIndent = match[1]; - // Remove the entire line containing the macro - continue; - } - - // Check for a block section end - // Example: /*[END "DEMO"]*/ - match = line.match(InitAction._endMacroRegExp); - if (match) { - if (activeBlockSectionName === undefined) { - // If this happens, please report a Rush bug - throw new InternalError(`The template contains an unmatched END macro for "${activeBlockSectionName}"`); - } - - if (activeBlockSectionName !== match[2]) { - // If this happens, please report a Rush bug - throw new InternalError(`The template contains an mismatched END macro for "${activeBlockSectionName}"`); - } - - if (activeBlockIndent !== match[1]) { - // If this happens, please report a Rush bug - throw new InternalError(`The template contains an inconsistently indented section` - + ` "${activeBlockSectionName}"`); - } - - activeBlockSectionName = undefined; - - // Remove the entire line containing the macro - continue; - } - - let transformedLine: string = line; - - // Check for a single-line section - // Example: /*[LINE "HYPOTHETICAL"]*/ - match = transformedLine.match(InitAction._lineMacroRegExp); - if (match) { - const sectionName: string = match[1]; - const replacement: string = this._isSectionCommented(sectionName) ? '// ' : ''; - transformedLine = transformedLine.replace(InitAction._lineMacroRegExp, replacement); - } - - // Check for variable expansions - // Example: [%RUSH_VERSION%] - while ((match = transformedLine.match(InitAction._variableMacroRegExp))) { - const variableName: string = match[1]; - const replacement: string = this._expandMacroVariable(variableName); - transformedLine = transformedLine.replace(InitAction._variableMacroRegExp, replacement); - } - - // Verify that all macros were handled - match = transformedLine.match(InitAction._anyMacroRegExp); - if (match) { - // If this happens, please report a Rush bug - throw new InternalError('The template contains a malformed macro expression: ' + JSON.stringify(match[0])); - } - - // If we are inside a block section that is commented out, then insert the "//" after indentation - if (activeBlockSectionName !== undefined) { - if (this._isSectionCommented(activeBlockSectionName)) { - // Is the line indented properly? - if (transformedLine.substr(0, activeBlockIndent.length).trim().length > 0) { - // If this happens, please report a Rush bug - throw new InternalError(`The template contains inconsistently indented lines inside` - + ` the "${activeBlockSectionName}" section`); - } - - // Insert comment characters after the indentation - const contentAfterIndent: string = transformedLine.substr(activeBlockIndent.length); - transformedLine = activeBlockIndent + '// ' + contentAfterIndent; - } - } - - outputLines.push(transformedLine); - } - - // Write the output - FileSystem.writeFile(destinationPath, outputLines.join('\r\n'), { - ensureFolderExists: true - }); - } - - private _isSectionCommented(sectionName: string): boolean { - const value: boolean | undefined = this._commentedBySectionName.get(sectionName); - if (value === undefined) { - // If this happens, please report a Rush bug - throw new InternalError(`The template references an undefined section name ${sectionName}`); - } - - return value!; - } - - private _expandMacroVariable(variableName: string): string { - switch (variableName) { - case '%RUSH_VERSION%': - return Rush.version; - default: - throw new InternalError(`The template references an undefined variable "${variableName}"`); - } - } -} diff --git a/apps/rush-lib/src/cli/actions/InstallAction.ts b/apps/rush-lib/src/cli/actions/InstallAction.ts deleted file mode 100644 index a3d50ffd772..00000000000 --- a/apps/rush-lib/src/cli/actions/InstallAction.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. - -import { BaseInstallAction } from './BaseInstallAction'; -import { IInstallManagerOptions } from '../../logic/InstallManager'; -import { RushCommandLineParser } from '../RushCommandLineParser'; - -export class InstallAction extends BaseInstallAction { - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'install', - summary: 'Install package dependencies for all projects in the repo according to the shrinkwrap file', - documentation: 'The "rush install" command installs package dependencies for all your projects,' - + ' based on the shrinkwrap file that is created/updated using "rush update".' - + ' (This "shrinkwrap" file stores a central inventory of all dependencies and versions' - + ' for projects in your repo. It is found in the "common/config/rush" folder.)' - + ' If the shrinkwrap file is missing or outdated (e.g. because project package.json files have' - + ' changed), "rush install" will fail and tell you to run "rush update" instead.' - + ' This read-only nature is the main feature: Continuous integration builds should use' - + ' "rush install" instead of "rush update" to catch developers who forgot to commit their' - + ' shrinkwrap changes. Cautious people can also use "rush install" if they want to avoid' - + ' accidentally updating their shrinkwrap file.', - parser - }); - } - - protected buildInstallOptions(): IInstallManagerOptions { - return { - debug: this.parser.isDebug, - allowShrinkwrapUpdates: false, - bypassPolicy: this._bypassPolicyParameter.value!, - noLink: this._noLinkParameter.value!, - fullUpgrade: false, - recheckShrinkwrap: false, - networkConcurrency: this._networkConcurrencyParameter.value, - collectLogFile: this._debugPackageManagerParameter.value!, - variant: this._variant.value, - // Because the 'defautltValue' option on the _maxInstallAttempts parameter is set, - // it is safe to assume that the value is not null - maxInstallAttempts: this._maxInstallAttempts.value! - }; - } -} diff --git a/apps/rush-lib/src/cli/actions/LinkAction.ts b/apps/rush-lib/src/cli/actions/LinkAction.ts deleted file mode 100644 index d910eeb8265..00000000000 --- a/apps/rush-lib/src/cli/actions/LinkAction.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; - -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { LinkManagerFactory } from '../../logic/LinkManagerFactory'; -import { BaseLinkManager } from '../../logic/base/BaseLinkManager'; -import { BaseRushAction } from './BaseRushAction'; - -export class LinkAction extends BaseRushAction { - private _force: CommandLineFlagParameter; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'link', - summary: 'Create node_modules symlinks for all projects', - documentation: 'Create node_modules symlinks for all projects. This operation is normally performed' - + ' automatically as part of "rush install" or "rush update". You should only need to use "rush link"' - + ' if you performed "rush unlink" for some reason, or if you specified the "--no-link" option' - + ' for "rush install" or "rush update".', - parser - }); - } - - protected onDefineParameters(): void { - this._force = this.defineFlagParameter({ - parameterLongName: '--force', - parameterShortName: '-f', - description: 'Deletes and recreates all links, even if the filesystem state seems to indicate that this is ' + - 'unnecessary.' - }); - } - - protected async run(): Promise { - const linkManager: BaseLinkManager = LinkManagerFactory.getLinkManager(this.rushConfiguration); - await linkManager.createSymlinksForProjects(this._force.value); - } -} diff --git a/apps/rush-lib/src/cli/actions/ListAction.ts b/apps/rush-lib/src/cli/actions/ListAction.ts deleted file mode 100644 index cdbb99c2dbf..00000000000 --- a/apps/rush-lib/src/cli/actions/ListAction.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { BaseRushAction } from './BaseRushAction'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import * as Table from 'cli-table'; - - -export interface IJsonEntry { - name: string; - version: string; - path: string; - fullPath: string; -} - -export interface IJsonOutput { - projects: IJsonEntry[]; -} - -export class ListAction extends BaseRushAction { - private _version: CommandLineFlagParameter; - private _path: CommandLineFlagParameter; - private _fullPath: CommandLineFlagParameter; - private _jsonFlag: CommandLineFlagParameter; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'list', - summary: 'List package information for all projects in the repo', - documentation: - 'List package names, and optionally version (--version) and ' + - 'path (--path) or full path (--full-path), for projects in the ' + - 'current rush config.', - parser - }); - } - - protected onDefineParameters(): void { - this._version = this.defineFlagParameter({ - parameterLongName: '--version', - parameterShortName: '-v', - description: - 'If this flag is specified, the project version will be ' + - 'displayed in a column along with the package name.' - }); - - this._path = this.defineFlagParameter({ - parameterLongName: '--path', - parameterShortName: '-p', - description: - 'If this flag is specified, the project path will be ' + - 'displayed in a column along with the package name.' - }); - - this._fullPath = this.defineFlagParameter({ - parameterLongName: '--full-path', - parameterShortName: '-f', - description: - 'If this flag is specified, the project full path will ' + - 'be displayed in a column along with the package name.' - }); - - this._jsonFlag = this.defineFlagParameter({ - parameterLongName: '--json', - description: 'If this flag is specified, output will be in JSON format.' - }); - } - - protected async run(): Promise { - const allPackages: Map = this.rushConfiguration.projectsByName; - if (this._jsonFlag.value) { - this._printJson(allPackages); - } else if (this._version.value || this._path.value || this._fullPath.value) { - this._printListTable(allPackages); - } else { - this._printList(allPackages); - } - } - - private _printJson( - allPackages: Map - ): void { - const projects: IJsonEntry[] = []; - allPackages.forEach((_config: RushConfigurationProject, name: string) => { - const project: IJsonEntry = { - name: name, - version: _config.packageJson.version, - path: _config.projectRelativeFolder, - fullPath: _config.projectFolder - }; - projects.push(project); - }); - - const output: IJsonOutput = { - projects - }; - console.log(JSON.stringify(output, undefined, 2)); - } - - private _printList( - allPackages: Map - ): void { - allPackages.forEach((_config: RushConfigurationProject, name: string) => { - console.log(name); - }); - } - - private _printListTable( - allPackages: Map - ): void { - const tableHeader: string[] = ['Project']; - if (this._version.value) { - tableHeader.push('Version'); - } - if (this._path.value) { - tableHeader.push('Path'); - } - if (this._fullPath.value) { - tableHeader.push('Full Path'); - } - const table: Table = new Table({ - head: tableHeader - }); - - allPackages.forEach((config: RushConfigurationProject, name: string) => { - const packageRow: string[] = [name]; - if (this._version.value) { - packageRow.push(config.packageJson.version); - } - if (this._path.value) { - packageRow.push(config.projectRelativeFolder); - } - if (this._fullPath.value) { - packageRow.push(config.projectFolder); - } - table.push(packageRow); - }); - console.log(table.toString()); - } -} diff --git a/apps/rush-lib/src/cli/actions/PublishAction.ts b/apps/rush-lib/src/cli/actions/PublishAction.ts deleted file mode 100644 index 14077aa5afa..00000000000 --- a/apps/rush-lib/src/cli/actions/PublishAction.ts +++ /dev/null @@ -1,532 +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 colors from 'colors'; -import { EOL } from 'os'; -import * as path from 'path'; -import { - CommandLineFlagParameter, - CommandLineStringParameter, - CommandLineChoiceParameter -} from '@rushstack/ts-command-line'; -import { FileSystem } from '@rushstack/node-core-library'; - -import { - IChangeInfo, - ChangeType -} from '../../api/ChangeManagement'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { Npm } from '../../utilities/Npm'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { PublishUtilities } from '../../logic/PublishUtilities'; -import { ChangelogGenerator } from '../../logic/ChangelogGenerator'; -import { PrereleaseToken } from '../../logic/PrereleaseToken'; -import { ChangeManager } from '../../logic/ChangeManager'; -import { BaseRushAction } from './BaseRushAction'; -import { PublishGit } from '../../logic/PublishGit'; -import { VersionControl } from '../../utilities/VersionControl'; -import { PolicyValidator } from '../../logic/policy/PolicyValidator'; -import { VersionPolicy } from '../../api/VersionPolicy'; -import { DEFAULT_PACKAGE_UPDATE_MESSAGE } from './VersionAction'; -import { Utilities } from '../../utilities/Utilities'; - -export class PublishAction extends BaseRushAction { - private _addCommitDetails: CommandLineFlagParameter; - private _apply: CommandLineFlagParameter; - private _includeAll: CommandLineFlagParameter; - private _npmAuthToken: CommandLineStringParameter; - private _npmTag: CommandLineStringParameter; - private _npmAccessLevel: CommandLineChoiceParameter; - private _publish: CommandLineFlagParameter; - private _regenerateChangelogs: CommandLineFlagParameter; - private _registryUrl: CommandLineStringParameter; - private _targetBranch: CommandLineStringParameter; - private _prereleaseName: CommandLineStringParameter; - private _partialPrerelease: CommandLineFlagParameter; - private _suffix: CommandLineStringParameter; - private _force: CommandLineFlagParameter; - private _versionPolicy: CommandLineStringParameter; - private _applyGitTagsOnPack: CommandLineFlagParameter; - private _commitId: CommandLineStringParameter; - private _releaseFolder: CommandLineStringParameter; - private _pack: CommandLineFlagParameter; - - private _prereleaseToken: PrereleaseToken; - private _hotfixTagOverride: string; - private _targetNpmrcPublishFolder: string; - private _targetNpmrcPublishPath: string; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'publish', - 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 ' + - '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 - }); - } - - protected onDefineParameters(): void { - this._apply = this.defineFlagParameter({ - parameterLongName: '--apply', - parameterShortName: '-a', - description: 'If this flag is specified, the change requests will be applied to package.json files.' - }); - this._targetBranch = this.defineStringParameter({ - parameterLongName: '--target-branch', - parameterShortName: '-b', - argumentName: 'BRANCH', - description: - 'If this flag is specified, applied changes and deleted change requests will be' + - 'committed and merged into the target branch.' - }); - this._publish = this.defineFlagParameter({ - parameterLongName: '--publish', - parameterShortName: '-p', - description: 'If this flag is specified, applied changes will be published to npm.' - }); - this._addCommitDetails = this.defineFlagParameter({ - parameterLongName: '--add-commit-details', - parameterShortName: undefined, - description: 'Adds commit author and hash to the changelog.json files for each change.' - }); - this._regenerateChangelogs = this.defineFlagParameter({ - parameterLongName: '--regenerate-changelogs', - parameterShortName: undefined, - description: 'Regenerates all changelog files based on the current JSON content.' - }); - - // NPM registry related parameters - this._registryUrl = this.defineStringParameter({ - parameterLongName: '--registry', - parameterShortName: '-r', - argumentName: 'REGISTRY', - description: - `Publishes to a specified NPM registry. If this is specified, it will prevent the current commit will not be ` + - 'tagged.' - }); - this._npmAuthToken = this.defineStringParameter({ - parameterLongName: '--npm-auth-token', - parameterShortName: '-n', - argumentName: 'TOKEN', - description: - 'Provide the default scope NPM auth token to be passed into npm publish for global package publishing.' - }); - this._npmTag = this.defineStringParameter({ - parameterLongName: '--tag', - parameterShortName: '-t', - argumentName: 'TAG', - description: - `The tag option to pass to npm publish. By default NPM will publish using the 'latest' tag, even if ` + - `the package is older than the current latest, so in publishing workflows for older releases, providing ` + - `a tag is important. When hotfix changes are made, this parameter defaults to 'hotfix'.` - }); - this._npmAccessLevel = this.defineChoiceParameter({ - alternatives: ['public', 'restricted'], - parameterLongName: '--set-access-level', - parameterShortName: undefined, - description: - `By default, when Rush invokes "npm publish" it will publish scoped packages with an access level ` + - `of "restricted". Scoped packages can be published with an access level of "public" by specifying ` + - `that value for this flag with the initial publication. NPM always publishes unscoped packages with ` + - `an access level of "public". For more information, see the NPM documentation for the "--access" ` + - `option of "npm publish".` - }); - - // NPM pack tarball related parameters - this._pack = this.defineFlagParameter({ - parameterLongName: '--pack', - description: - `Packs projects into tarballs instead of publishing to npm repository. It can only be used when ` + - `--include-all is specified. If this flag is specified, NPM registry related parameters will be ignored.` - }); - this._releaseFolder = this.defineStringParameter({ - parameterLongName: '--release-folder', - argumentName: 'FOLDER', - description: - `This parameter is used with --pack parameter to provide customized location for the tarballs instead of ` + - `the default value. ` - }); - // End of NPM pack tarball related parameters - - this._includeAll = this.defineFlagParameter({ - parameterLongName: '--include-all', - parameterShortName: undefined, - description: 'If this flag is specified, all packages with shouldPublish=true in rush.json ' + - 'or with a specified version policy ' + - 'will be published if their version is newer than published version.' - }); - this._versionPolicy = this.defineStringParameter({ - parameterLongName: '--version-policy', - argumentName: 'POLICY', - description: 'Version policy name. Only projects with this version policy will be published if used ' + - 'with --include-all.' - }); - this._prereleaseName = this.defineStringParameter({ - parameterLongName: '--prerelease-name', - argumentName: 'NAME', - description: 'Bump up to a prerelease version with the provided prerelease name. Cannot be used with --suffix' - }); - this._partialPrerelease = this.defineFlagParameter({ - parameterLongName: '--partial-prerelease', - parameterShortName: undefined, - description: 'Used with --prerelease-name. Only bump packages to a prerelease version if they have changes.' - }); - this._suffix = this.defineStringParameter({ - parameterLongName: '--suffix', - argumentName: 'SUFFIX', - description: 'Append a suffix to all changed versions. Cannot be used with --prerelease-name.' - }); - this._force = this.defineFlagParameter({ - parameterLongName: '--force', - parameterShortName: undefined, - description: 'If this flag is specified with --publish, packages will be published with --force on npm' - }); - this._applyGitTagsOnPack = this.defineFlagParameter({ - parameterLongName: '--apply-git-tags-on-pack', - description: `If specified with --publish and --pack, git tags will be applied for packages` + - ` as if a publish was being run without --pack.` - }); - this._commitId = this.defineStringParameter({ - parameterLongName: '--commit', - parameterShortName: '-c', - argumentName: 'COMMIT_ID', - description: `Used in conjunction with git tagging -- apply git tags at the commit hash` + - ` specified. If not provided, the current HEAD will be tagged.` - }); - } - - /** - * Executes the publish action, which will read change request files, apply changes to package.jsons, - */ - protected run(): Promise { - return Promise.resolve().then(() => { - PolicyValidator.validatePolicy(this.rushConfiguration, false); - - // Example: "common\temp\publish-home" - this._targetNpmrcPublishFolder = path.join(this.rushConfiguration.commonTempFolder, 'publish-home'); - - // Example: "common\temp\publish-home\.npmrc" - this._targetNpmrcPublishPath = path.join(this._targetNpmrcPublishFolder, '.npmrc'); - - const allPackages: Map = this.rushConfiguration.projectsByName; - - if (this._regenerateChangelogs.value) { - console.log('Regenerating changelogs'); - ChangelogGenerator.regenerateChangelogs(allPackages, this.rushConfiguration); - return Promise.resolve(); - } - - this._validate(); - - this._addNpmPublishHome(); - - if (this._includeAll.value) { - this._publishAll(allPackages); - } else { - this._prereleaseToken = new PrereleaseToken( - this._prereleaseName.value, - this._suffix.value, - this._partialPrerelease.value - ); - this._publishChanges(allPackages); - } - - console.log(EOL + colors.green('Rush publish finished successfully.')); - }); - } - - /** - * Validate some input parameters - */ - private _validate(): void { - if (this._pack.value && !this._includeAll.value) { - throw new Error('--pack can only be used with --include-all'); - } - if (this._releaseFolder.value && !this._pack.value) { - throw new Error(`--release-folder can only be used with --pack`); - } - if (this._applyGitTagsOnPack.value && !this._pack.value) { - throw new Error(`${this._applyGitTagsOnPack.longName} must be used ` - + `with ${this._pack.longName}`); - } - } - - private _publishChanges(allPackages: Map): void { - const changeManager: ChangeManager = new ChangeManager(this.rushConfiguration); - changeManager.load(this.rushConfiguration.changesFolder, - this._prereleaseToken, - this._addCommitDetails.value); - - if (changeManager.hasChanges()) { - const orderedChanges: IChangeInfo[] = changeManager.changes; - const git: PublishGit = new PublishGit(this._targetBranch.value); - const tempBranch: string = 'publish-' + new Date().getTime(); - - // Make changes in temp branch. - git.checkout(tempBranch, true); - - this._setDependenciesBeforePublish(); - - // Make changes to package.json and change logs. - changeManager.apply(this._apply.value); - changeManager.updateChangelog(this._apply.value); - - this._setDependenciesBeforeCommit(); - - if (VersionControl.hasUncommittedChanges()) { - // Stage, commit, and push the changes to remote temp branch. - git.addChanges(':/*'); - git.commit(this.rushConfiguration.gitVersionBumpCommitMessage || DEFAULT_PACKAGE_UPDATE_MESSAGE); - git.push(tempBranch); - - this._setDependenciesBeforePublish(); - - // Override tag parameter if there is a hotfix change. - for (const change of orderedChanges) { - if (change.changeType === ChangeType.hotfix) { - this._hotfixTagOverride = 'hotfix'; - break; - } - } - - // npm publish the things that need publishing. - for (const change of orderedChanges) { - if (change.changeType && change.changeType > ChangeType.dependency) { - const project: RushConfigurationProject | undefined = allPackages.get(change.packageName); - if (project) { - if (!this._packageExists(project)) { - this._npmPublish(change.packageName, project.projectFolder); - } else { - console.log(`Skip ${change.packageName}. Package exists.`); - } - } else { - console.log(`Skip ${change.packageName}. Failed to find its project.`); - } - } - } - - this._setDependenciesBeforeCommit(); - - // Create and push appropriate Git tags. - this._gitAddTags(git, orderedChanges); - git.push(tempBranch); - - // Now merge to target branch. - git.checkout(this._targetBranch.value); - git.pull(); - git.merge(tempBranch); - git.push(this._targetBranch.value); - git.deleteBranch(tempBranch); - } else { - git.checkout(this._targetBranch.value); - git.deleteBranch(tempBranch, false); - } - } - } - - private _publishAll(allPackages: Map): void { - console.log(`Rush publish starts with includeAll and version policy ${this._versionPolicy.value}`); - - let updated: boolean = false; - const git: PublishGit = new PublishGit(this._targetBranch.value); - - allPackages.forEach((packageConfig, packageName) => { - if (packageConfig.shouldPublish && - (!this._versionPolicy.value || this._versionPolicy.value === packageConfig.versionPolicyName) - ) { - const applyTag: (apply: boolean) => void = (apply: boolean): void => { - if (!apply) { - return; - } - - const packageVersion: string = packageConfig.packageJson.version; - - // Do not create a new tag if one already exists, this will result in a fatal error - if (git.hasTag(packageConfig)) { - console.log(`Not tagging ${packageName}@${packageVersion}. A tag already exists for this version.`); - return; - } - - git.addTag(!!this._publish.value, packageName, packageVersion, this._commitId.value); - updated = true; - }; - - if (this._pack.value) { - // packs to tarball instead of publishing to NPM repository - this._npmPack(packageName, packageConfig); - applyTag(this._applyGitTagsOnPack.value); - } else if (this._force.value || !this._packageExists(packageConfig)) { - // Publish to npm repository - this._npmPublish(packageName, packageConfig.projectFolder); - applyTag(true); - } else { - console.log(`Skip ${packageName}. Not updated.`); - } - } - }); - if (updated) { - git.push(this._targetBranch.value); - } - } - - private _gitAddTags(git: PublishGit, orderedChanges: IChangeInfo[]): void { - for (const change of orderedChanges) { - if ( - change.changeType && - change.changeType > ChangeType.dependency && - this.rushConfiguration.projectsByName.get(change.packageName)!.shouldPublish - ) { - git.addTag(!!this._publish.value && !this._registryUrl.value, change.packageName, change.newVersion!, this._commitId.value); - } - } - } - - private _npmPublish(packageName: string, packagePath: string): void { - const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); - const args: string[] = ['publish']; - - if (this.rushConfiguration.projectsByName.get(packageName)!.shouldPublish) { - this._addSharedNpmConfig(env, args); - - if (this._npmTag.value) { - args.push(`--tag`, this._npmTag.value); - } else if (this._hotfixTagOverride) { - args.push(`--tag`, this._hotfixTagOverride); - } - - if (this._force.value) { - args.push(`--force`); - } - - if (this._npmAccessLevel.value) { - args.push(`--access`, this._npmAccessLevel.value); - } - - // TODO: Yarn's "publish" command line is fairly different from NPM and PNPM. The right thing to do here - // would be to remap our options to the Yarn equivalents. But until we get around to that, we'll simply invoke - // whatever NPM binary happens to be installed in the global path. - const packageManagerToolFilename: string = this.rushConfiguration.packageManager === 'yarn' - ? 'npm' : this.rushConfiguration.packageManagerToolFilename; - - // If the auth token was specified via the command line, avoid printing it on the console - const secretSubstring: string | undefined = this._npmAuthToken.value; - - PublishUtilities.execCommand( - !!this._publish.value, - packageManagerToolFilename, - args, - packagePath, - env, - secretSubstring); - } - } - - private _packageExists(packageConfig: RushConfigurationProject): boolean { - const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); - const args: string[] = []; - this._addSharedNpmConfig(env, args); - - const publishedVersions: string[] = Npm.publishedVersions(packageConfig.packageName, - packageConfig.projectFolder, - env, - args); - return publishedVersions.indexOf(packageConfig.packageJson.version) >= 0; - } - - private _npmPack(packageName: string, project: RushConfigurationProject): void { - const args: string[] = ['pack']; - const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); - - PublishUtilities.execCommand( - !!this._publish.value, - this.rushConfiguration.packageManagerToolFilename, - args, - project.projectFolder, - env - ); - - if (this._publish.value) { - // Copy the tarball the release folder - const tarballName: string = this._calculateTarballName(project); - const tarballPath: string = path.join(project.projectFolder, tarballName); - const destFolder: string = this._releaseFolder.value ? - this._releaseFolder.value : path.join(this.rushConfiguration.commonTempFolder, 'artifacts', 'packages'); - - FileSystem.move({ - sourcePath: tarballPath, - destinationPath: path.join(destFolder, tarballName), - overwrite: true - }); - } - } - - private _calculateTarballName(project: RushConfigurationProject): string { - // Same logic as how npm forms the tarball name - const packageName: string = project.packageName; - const name: string = packageName[0] === '@' ? packageName.substr(1).replace(/\//g, '-') : packageName; - - if (this.rushConfiguration.packageManager === 'yarn') { - // yarn tarballs have a "v" before the version number - return `${name}-v${project.packageJson.version}.tgz`; - } else { - return `${name}-${project.packageJson.version}.tgz`; - } - } - - 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 _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 _addNpmPublishHome(): void { - // Create "common\temp\publish-home" folder, if it doesn't exist - Utilities.createFolderWithRetry(this._targetNpmrcPublishFolder); - - // Copy down the committed "common\config\rush\.npmrc-publish" file, if there is one - Utilities.syncNpmrc(this.rushConfiguration.commonRushConfigFolder, this._targetNpmrcPublishFolder, true); - } - - private _addSharedNpmConfig(env: { [key: string]: string | undefined }, args: string[]): void { - const userHomeEnvVariable: string = (process.platform === 'win32') ? 'USERPROFILE' : 'HOME'; - let registry: string = '//registry.npmjs.org/'; - - // Check if .npmrc file exists in "common\temp\publish-home" - if (FileSystem.exists(this._targetNpmrcPublishPath)) { - // Redirect userHomeEnvVariable, NPM will use config in "common\temp\publish-home\.npmrc" - env[userHomeEnvVariable] = this._targetNpmrcPublishFolder; - } - - // Check if registryUrl and token are specified via command-line - if (this._registryUrl.value) { - const registryUrl: string = this._registryUrl.value; - env['npm_config_registry'] = registryUrl; // eslint-disable-line dot-notation - registry = registryUrl.substring(registryUrl.indexOf('//')); - } - - if (this._npmAuthToken.value) { - args.push(`--${registry}:_authToken=${this._npmAuthToken.value}`); - } - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/actions/PurgeAction.ts b/apps/rush-lib/src/cli/actions/PurgeAction.ts deleted file mode 100644 index e18b0db4af0..00000000000 --- a/apps/rush-lib/src/cli/actions/PurgeAction.ts +++ /dev/null @@ -1,58 +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 colors from 'colors'; -import * as os from 'os'; - -import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; - -import { BaseRushAction } from './BaseRushAction'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { Stopwatch } from '../../utilities/Stopwatch'; -import { PurgeManager } from '../../logic/PurgeManager'; -import { UnlinkManager } from '../../logic/UnlinkManager'; - -export class PurgeAction extends BaseRushAction { - private _unsafeParameter: CommandLineFlagParameter; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'purge', - summary: 'For diagnostic purposes, use this command to delete caches and other temporary files used by Rush', - documentation: 'The "rush purge" command is used to delete temporary files created by Rush. This is' - + ' useful if you are having problems and suspect that cache files may be corrupt.', - parser - }); - } - - protected onDefineParameters(): void { - this._unsafeParameter = this.defineFlagParameter({ - parameterLongName: '--unsafe', - description: '(UNSAFE!) Also delete shared files such as the package manager instances stored in' - + ' the ".rush" folder in the user\'s home directory. This is a more aggressive fix that is' - + ' NOT SAFE to run in a live environment because it will cause other concurrent Rush processes to fail.' - }); - } - - protected run(): Promise { - return Promise.resolve().then(() => { - const stopwatch: Stopwatch = Stopwatch.start(); - - const unlinkManager: UnlinkManager = new UnlinkManager(this.rushConfiguration); - const purgeManager: PurgeManager = new PurgeManager(this.rushConfiguration, this.rushGlobalFolder); - - unlinkManager.unlink(); - - if (this._unsafeParameter.value!) { - purgeManager.purgeUnsafe(); - } else { - purgeManager.purgeNormal(); - } - - purgeManager.deleteAll(); - - console.log(os.EOL + colors.green(`Rush purge started successfully and will complete asynchronously.` - + ` (${stopwatch.toString()})`)); - }); - } -} diff --git a/apps/rush-lib/src/cli/actions/ScanAction.ts b/apps/rush-lib/src/cli/actions/ScanAction.ts deleted file mode 100644 index c235183081d..00000000000 --- a/apps/rush-lib/src/cli/actions/ScanAction.ts +++ /dev/null @@ -1,125 +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 colors from 'colors'; -import * as glob from 'glob'; -import * as path from 'path'; -import * as builtinPackageNames from 'builtin-modules'; -import { FileSystem } from '@rushstack/node-core-library'; - -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { BaseConfiglessRushAction } from './BaseRushAction'; - -export class ScanAction extends BaseConfiglessRushAction { - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'scan', - summary: 'Scan the current project folder and display a report of imported packages.', - documentation: `The NPM system allows a project to import dependencies without explicitly` - + ` listing them in its package.json file. This is a dangerous practice, because` - + ` there is no guarantee you will get a compatible version. The "rush scan" command` - + ` reports a list of packages that are imported by your code, which you can` - + ` compare against your package.json file to find mistakes. It searches the "./src"` - + ` and "./lib" folders for typical import syntaxes such as "import __ from '__'",` - + ` "require('__')", "System.import('__'), etc. The results are only approximate,` - + ` but generally pretty accurate.`, - safeForSimultaneousRushProcesses: true, - parser - }); - } - - protected onDefineParameters(): void { - // abstract - } - - protected run(): Promise { - const packageJsonFilename: string = path.resolve('./package.json'); - - if (!FileSystem.exists(packageJsonFilename)) { - throw new Error('You must run "rush scan" in a project folder containing a package.json file.'); - } - - const requireRegExps: RegExp[] = [ - // Example: require('someting') - /\brequire\s*\(\s*[']([^']+\s*)[']\)/, - /\brequire\s*\(\s*["]([^"]+)["]\s*\)/, - - // Example: require.ensure('someting') - /\brequire.ensure\s*\(\s*[']([^']+\s*)[']\)/, - /\brequire.ensure\s*\(\s*["]([^"]+)["]\s*\)/, - - // Example: require.resolve('someting') - /\brequire.resolve\s*\(\s*[']([^']+\s*)[']\)/, - /\brequire.resolve\s*\(\s*["]([^"]+)["]\s*\)/, - - // Example: System.import('someting') - /\bSystem.import\s*\(\s*[']([^']+\s*)[']\)/, - /\bSystem.import\s*\(\s*["]([^"]+)["]\s*\)/, - - // Example: - // - // import { - // A, B - // } from 'something'; - /\bfrom\s*[']([^']+)[']/, - /\bfrom\s*["]([^"]+)["]/, - - // Example: import 'something'; - /\bimport\s*[']([^']+)[']\s*\;/, - /\bimport\s*["]([^"]+)["]\s*\;/, - - // Example: - // /// - /\/\/\/\s*<\s*reference\s+types\s*=\s*["]([^"]+)["]\s*\/>/ - ]; - - // Example: "my-package/lad/dee/dah" --> "my-package" - // Example: "@ms/my-package" --> "@ms/my-package" - const packageRegExp: RegExp = /^((@[a-z\-0-9!_]+\/)?[a-z\-0-9!_]+)\/?/; - - const requireMatches: Set = new Set(); - - for (const filename of glob.sync('{./*.{ts,js,tsx,jsx},./{src,lib}/**/*.{ts,js,tsx,jsx}}')) { - try { - const contents: string = FileSystem.readFile(filename); - const lines: string[] = contents.split('\n'); - - for (const line of lines) { - for (const requireRegExp of requireRegExps) { - const requireRegExpResult: RegExpExecArray | null = requireRegExp.exec(line); - if (requireRegExpResult) { - requireMatches.add(requireRegExpResult[1]); - } - } - } - } catch (error) { - console.log(colors.bold('Skipping file due to error: ' + filename)); - } - } - - const packageMatches: Set = new Set(); - - requireMatches.forEach((requireMatch: string) => { - const packageRegExpResult: RegExpExecArray | null = packageRegExp.exec(requireMatch); - if (packageRegExpResult) { - packageMatches.add(packageRegExpResult[1]); - } - }); - - const packageNames: string[] = []; - - packageMatches.forEach((packageName: string) => { - packageNames.push(packageName); - }); - - packageNames.sort(); - - console.log('Detected dependencies:'); - for (const packageName of packageNames) { - if (builtinPackageNames.indexOf(packageName) < 0) { - console.log(' ' + packageName); - } - } - return Promise.resolve(); - } -} diff --git a/apps/rush-lib/src/cli/actions/UnlinkAction.ts b/apps/rush-lib/src/cli/actions/UnlinkAction.ts deleted file mode 100644 index cf0b205815f..00000000000 --- a/apps/rush-lib/src/cli/actions/UnlinkAction.ts +++ /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 os from 'os'; - -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { BaseRushAction } from './BaseRushAction'; -import { UnlinkManager } from '../../logic/UnlinkManager'; - -export class UnlinkAction extends BaseRushAction { - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'unlink', - summary: 'Delete node_modules symlinks for all projects in the repo', - documentation: 'This removes the symlinks created by the "rush link" command. This is useful for' - + ' cleaning a repo using "git clean" without accidentally deleting source files, or for using standard NPM' - + ' commands on a project.', - parser - }); - } - - protected onDefineParameters(): void { - // No parameters - } - - protected run(): Promise { - return Promise.resolve().then(() => { - const unlinkManager: UnlinkManager = new UnlinkManager(this.rushConfiguration); - - if (!unlinkManager.unlink()) { - console.log('Nothing to do.'); - } else { - console.log(os.EOL + 'Done.'); - } - }); - } -} diff --git a/apps/rush-lib/src/cli/actions/UpdateAction.ts b/apps/rush-lib/src/cli/actions/UpdateAction.ts deleted file mode 100644 index e547e28a92f..00000000000 --- a/apps/rush-lib/src/cli/actions/UpdateAction.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; - -import { BaseInstallAction } from './BaseInstallAction'; -import { IInstallManagerOptions } from '../../logic/InstallManager'; -import { RushCommandLineParser } from '../RushCommandLineParser'; - -export class UpdateAction extends BaseInstallAction { - private _fullParameter: CommandLineFlagParameter; - private _recheckParameter: CommandLineFlagParameter; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'update', - summary: 'Install package dependencies for all projects in the repo,' - + ' and create or update the shrinkwrap file as needed', - documentation: 'The "rush update" command installs the dependencies described in your' - + ' package.json files, and updates the shrinkwrap file as needed.' - + ' (This "shrinkwrap" file stores a central inventory of all dependencies and versions' - + ' for projects in your repo. It is found in the "common/config/rush" folder.)' - + ' Note that Rush always performs a single install for all projects in your repo.' - + ' You should run "rush update" whenever you start working in a Rush repo,' - + ' after you pull from Git, and after you modify a package.json file.' - + ' If there is nothing to do, "rush update" is instantaneous.' - + ' NOTE: In certain cases "rush install" should be used instead of "rush update"' - + ' -- for details, see the command help for "rush install".', - parser - }); - } - - protected onDefineParameters(): void { - super.onDefineParameters(); - - this._fullParameter = this.defineFlagParameter({ - parameterLongName: '--full', - description: 'Normally "rush update" tries to preserve your existing installed versions' - + ' and only makes the minimum updates needed to satisfy the package.json files.' - + ' This conservative approach prevents your PR from getting involved with package updates that' - + ' are unrelated to your work. Use "--full" when you really want to update all dependencies' - + ' to the latest SemVer-compatible version. This should be done periodically by a person' - + ' or robot whose role is to deal with potential upgrade regressions.' - }); - this._recheckParameter = this.defineFlagParameter({ - parameterLongName: '--recheck', - description: 'If the shrinkwrap file appears to already satisfy the package.json files,' - + ' then "rush update" will skip invoking the package manager at all. In certain situations' - + ' this heuristic may be inaccurate. Use the "--recheck" flag to force the package manager' - + ' to process the shrinkwrap file. This will also update your shrinkwrap file with Rush\'s fixups.' - + ' (To minimize shrinkwrap churn, these fixups are normally performed only in the temporary folder.)' - }); - } - - protected buildInstallOptions(): IInstallManagerOptions { - return { - debug: this.parser.isDebug, - allowShrinkwrapUpdates: true, - bypassPolicy: this._bypassPolicyParameter.value!, - noLink: this._noLinkParameter.value!, - fullUpgrade: this._fullParameter.value!, - recheckShrinkwrap: this._recheckParameter.value!, - networkConcurrency: this._networkConcurrencyParameter.value, - collectLogFile: this._debugPackageManagerParameter.value!, - variant: this._variant.value, - // Because the 'defautltValue' option on the _maxInstallAttempts parameter is set, - // it is safe to assume that the value is not null - maxInstallAttempts: this._maxInstallAttempts.value! - }; - } -} diff --git a/apps/rush-lib/src/cli/actions/VersionAction.ts b/apps/rush-lib/src/cli/actions/VersionAction.ts deleted file mode 100644 index 4f4a0406331..00000000000 --- a/apps/rush-lib/src/cli/actions/VersionAction.ts +++ /dev/null @@ -1,245 +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 semver from 'semver'; -import { - IPackageJson, - FileConstants -} from '@rushstack/node-core-library'; -import { - CommandLineFlagParameter, - CommandLineStringParameter -} from '@rushstack/ts-command-line'; - -import { BumpType, LockStepVersionPolicy } from '../../api/VersionPolicy'; -import { VersionPolicyConfiguration } from '../../api/VersionPolicyConfiguration'; -import { RushConfiguration } from '../../api/RushConfiguration'; -import { VersionControl } from '../../utilities/VersionControl'; -import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; -import { RushCommandLineParser } from '../RushCommandLineParser'; -import { PolicyValidator } from '../../logic/policy/PolicyValidator'; -import { BaseRushAction } from './BaseRushAction'; -import { VersionManager } from '../../logic/VersionManager'; -import { PublishGit } from '../../logic/PublishGit'; -import { Git } from '../../logic/Git'; - -export const DEFAULT_PACKAGE_UPDATE_MESSAGE: string = 'Applying package updates.'; - -export class VersionAction extends BaseRushAction { - private _ensureVersionPolicy: CommandLineFlagParameter; - private _overrideVersion: CommandLineStringParameter; - private _bumpVersion: CommandLineFlagParameter; - private _versionPolicy: CommandLineStringParameter; - private _bypassPolicy: CommandLineFlagParameter; - private _targetBranch: CommandLineStringParameter; - private _overwriteBump: CommandLineStringParameter; - private _prereleaseIdentifier: CommandLineStringParameter; - - private _versionManager: VersionManager; - - public constructor(parser: RushCommandLineParser) { - super({ - actionName: 'version', - summary: '(EXPERIMENTAL) Manage package versions in the repo.', - documentation: '(EXPERIMENTAL) use this "rush version" command to ensure version policies and bump versions.', - parser - }); - } - - protected onDefineParameters(): void { - this._targetBranch = this.defineStringParameter({ - parameterLongName: '--target-branch', - parameterShortName: '-b', - argumentName: 'BRANCH', - description: - 'If this flag is specified, changes will be committed and merged into the target branch.' - }); - this._ensureVersionPolicy = this.defineFlagParameter({ - parameterLongName: '--ensure-version-policy', - description: 'Updates package versions if needed to satisfy version policies.' - }); - this._overrideVersion = this.defineStringParameter({ - parameterLongName: '--override-version', - argumentName: 'NEW_VERSION', - description: 'Override the version in the specified --version-policy. ' + - 'This setting only works for lock-step version policy and when --ensure-version-policy is specified.' - }); - this._bumpVersion = this.defineFlagParameter({ - parameterLongName: '--bump', - description: 'Bumps package version based on version policies.' - }); - this._bypassPolicy = this.defineFlagParameter({ - parameterLongName: '--bypass-policy', - description: 'Overrides "gitPolicy" enforcement (use honorably!)' - }); - this._versionPolicy = this.defineStringParameter({ - parameterLongName: '--version-policy', - argumentName: 'POLICY', - description: 'The name of the version policy' - }); - this._overwriteBump = this.defineStringParameter({ - parameterLongName: '--override-bump', - argumentName: 'BUMPTYPE', - description: 'Overrides the bump type in the version-policy.json for the specified version policy.' + - 'Valid BUMPTYPE values include: prerelease, patch, preminor, minor, major. ' + - 'This setting only works for lock-step version policy in bump action.' - }); - this._prereleaseIdentifier = this.defineStringParameter({ - parameterLongName: '--override-prerelease-id', - argumentName: 'ID', - description: 'Overrides the prerelease identifier in the version value of version-policy.json ' + - 'for the specified version policy. ' + - 'This setting only works for lock-step version policy. ' + - 'This setting increases to new prerelease id when "--bump" is provided but only replaces the ' + - 'prerelease name when "--ensure-version-policy" is provided.' - }); - } - - protected run(): Promise { - return Promise.resolve().then(() => { - PolicyValidator.validatePolicy(this.rushConfiguration, this._bypassPolicy.value); - const userEmail: string = Git.getGitEmail(this.rushConfiguration); - - this._validateInput(); - - this._versionManager = new VersionManager(this.rushConfiguration, userEmail); - - if (this._ensureVersionPolicy.value) { - this._overwritePolicyVersionIfNeeded(); - const tempBranch: string = 'version/ensure-' + new Date().getTime(); - this._versionManager.ensure(this._versionPolicy.value, true, - !!this._overrideVersion.value || !!this._prereleaseIdentifier.value); - - const updatedPackages: Map = this._versionManager.updatedProjects; - if (updatedPackages.size > 0) { - console.log(`${updatedPackages.size} packages are getting updated.`); - this._gitProcess(tempBranch); - } - } else if (this._bumpVersion.value) { - const tempBranch: string = 'version/bump-' + new Date().getTime(); - this._versionManager.bump(this._versionPolicy.value, - this._overwriteBump.value ? BumpType[this._overwriteBump.value] : undefined, - this._prereleaseIdentifier.value, - true); - this._gitProcess(tempBranch); - } - }); - } - - private _overwritePolicyVersionIfNeeded(): void { - if (!this._overrideVersion.value && !this._prereleaseIdentifier.value) { - // No need to overwrite policy version - return; - } - if (this._overrideVersion.value && this._prereleaseIdentifier.value) { - throw new Error(`The parameters "--override-version" and` + - ` "--override-prerelease-id" cannot be used together.`); - } - - if (this._versionPolicy.value) { - const versionConfig: VersionPolicyConfiguration = this.rushConfiguration.versionPolicyConfiguration; - const policy: LockStepVersionPolicy = versionConfig.getVersionPolicy(this._versionPolicy.value) as - LockStepVersionPolicy; - if (!policy || !policy.isLockstepped) { - throw new Error(`The lockstep version policy "${policy.policyName}" is not found.`); - } - let newVersion: string | undefined = undefined; - if (this._overrideVersion.value) { - newVersion = this._overrideVersion.value; - } else if (this._prereleaseIdentifier.value) { - const newPolicyVersion: semver.SemVer = new semver.SemVer(policy.version); - if (newPolicyVersion.prerelease.length) { - // Update 1.5.0-alpha.10 to 1.5.0-beta.10 - newPolicyVersion.prerelease[0] = this._prereleaseIdentifier.value; - } else { - // Update 1.5.0 to 1.5.0-beta - newPolicyVersion.prerelease.push(this._prereleaseIdentifier.value); - } - newVersion = newPolicyVersion.format(); - } - - if (newVersion) { - console.log(`Update version policy ${policy.policyName} from ${policy.version} to ${newVersion}`); - versionConfig.update(this._versionPolicy.value, newVersion); - } - } else { - throw new Error('Missing --version-policy parameter to specify which version policy should be overwritten.'); - } - } - - private _validateInput(): void { - if (this._bumpVersion.value && this._ensureVersionPolicy.value) { - throw new Error('Please choose --bump or --ensure-version-policy but not together.'); - } - - if (this._overwriteBump.value && !BumpType[this._overwriteBump.value]) { - throw new Error('The value of override-bump is not valid. ' + - 'Valid values include prerelease, patch, preminor, minor, and major'); - } - } - - private _validateResult(): void { - // Load the config from file to avoid using inconsistent in-memory data. - const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile( - this.rushConfiguration.rushJsonFile - ); - - const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches(rushConfig); - if (mismatchFinder.numberOfMismatches) { - throw new Error('Unable to finish version bump because inconsistencies were encountered.' + - ' Run \"rush check\" to find more details.'); - } - } - - private _gitProcess(tempBranch: string): void { - // Validate the result before commit. - this._validateResult(); - - const git: PublishGit = new PublishGit(this._targetBranch.value); - - // Make changes in temp branch. - git.checkout(tempBranch, true); - - const uncommittedChanges: ReadonlyArray = VersionControl.getUncommittedChanges(); - - // Stage, commit, and push the changes to remote temp branch. - // Need to commit the change log updates in its own commit - const changeLogUpdated: boolean = uncommittedChanges.some((changePath) => { - return changePath.indexOf('CHANGELOG.json') > 0; - }); - - if (changeLogUpdated) { - git.addChanges('.', this.rushConfiguration.changesFolder); - git.addChanges(':/**/CHANGELOG.json'); - git.addChanges(':/**/CHANGELOG.md'); - git.commit('Deleting change files and updating change logs for package updates.'); - } - - // Commit the package.json and change files updates. - const packageJsonUpdated: boolean = uncommittedChanges.some((changePath) => { - return changePath.indexOf(FileConstants.PackageJson) > 0; - }); - - if (packageJsonUpdated) { - git.addChanges(':/*'); - git.commit(this.rushConfiguration.gitVersionBumpCommitMessage || DEFAULT_PACKAGE_UPDATE_MESSAGE); - } - - if (changeLogUpdated || packageJsonUpdated) { - git.push(tempBranch); - - // Now merge to target branch. - git.fetch(); - git.checkout(this._targetBranch.value); - git.pull(); - git.merge(tempBranch); - git.push(this._targetBranch.value); - git.deleteBranch(tempBranch); - } else { - // skip commits - git.fetch(); - git.checkout(this._targetBranch.value); - git.deleteBranch(tempBranch, false); - } - } -} diff --git a/apps/rush-lib/src/cli/actions/test/AddAction.test.ts b/apps/rush-lib/src/cli/actions/test/AddAction.test.ts deleted file mode 100644 index e6583af65ee..00000000000 --- a/apps/rush-lib/src/cli/actions/test/AddAction.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import '../../test/mockRushCommandLineParser'; - -import * as path from 'path'; - -import { PackageJsonUpdater } from '../../../logic/PackageJsonUpdater'; -import { RushCommandLineParser } from '../../RushCommandLineParser'; - -describe('AddAction', () => { - describe(`basic "rush add" tests`, () => { - let doRushAddMock: jest.SpyInstance; - let oldExitCode: number | undefined; - let oldArgs: string[]; - - beforeEach(() => { - doRushAddMock = jest.spyOn( - PackageJsonUpdater.prototype, - 'doRushAdd' - ).mockImplementation(() => Promise.resolve()); - jest.spyOn(process, 'exit').mockImplementation(() => { /* stub */ }); - oldExitCode = process.exitCode; - oldArgs = process.argv; - }); - - afterEach(() => { - jest.clearAllMocks(); - process.exitCode = oldExitCode; - process.argv = oldArgs; - }); - - describe(`'add' action`, () => { - it(`adds a dependency to just one repo in the workspace`, () => { - const startPath: string = path.resolve(__dirname, 'addRepo'); - const aPath: string = path.resolve(__dirname, 'addRepo', 'a'); - - // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit - // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test - // repo will fail due to contention over the same lock which is kept until the test runner process - // ends. - const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); - - // Switching to the "a" package of addRepo - jest.spyOn(process, 'cwd').mockReturnValue(aPath); - - // Mock the command - process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'add', '-p', 'assert']; - - return expect(parser.execute()).resolves.toEqual(true) - .then(() => { - expect(doRushAddMock).toHaveBeenCalledTimes(1); - expect(doRushAddMock.mock.calls[0][0].projects.length).toEqual(1); - expect(doRushAddMock.mock.calls[0][0].projects[0].packageName).toEqual('a'); - expect(doRushAddMock.mock.calls[0][0].packageName).toEqual('assert'); - }); - }); - }); - - describe(`'add' action with --all`, () => { - it(`adds a dependency to all repos in the workspace`, () => { - const startPath: string = path.resolve(__dirname, 'addRepo'); - const aPath: string = path.resolve(__dirname, 'addRepo', 'a'); - - // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit - // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test - // repo will fail due to contention over the same lock which is kept until the test runner process - // ends. - const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); - - // Switching to the "a" package of addRepo - jest.spyOn(process, 'cwd').mockReturnValue(aPath); - - // Mock the command - process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'add', '-p', 'assert', '--all']; - - return expect(parser.execute()).resolves.toEqual(true) - .then(() => { - expect(doRushAddMock).toHaveBeenCalledTimes(1); - expect(doRushAddMock.mock.calls[0][0].projects.length).toEqual(2); - expect(doRushAddMock.mock.calls[0][0].projects[0].packageName).toEqual('a'); - expect(doRushAddMock.mock.calls[0][0].projects[1].packageName).toEqual('b'); - expect(doRushAddMock.mock.calls[0][0].packageName).toEqual('assert'); - }); - }); - }); - }); -}); \ No newline at end of file diff --git a/apps/rush-lib/src/cli/scriptActions/BaseScriptAction.ts b/apps/rush-lib/src/cli/scriptActions/BaseScriptAction.ts deleted file mode 100644 index 0f398a12be2..00000000000 --- a/apps/rush-lib/src/cli/scriptActions/BaseScriptAction.ts +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CommandLineParameter } from '@rushstack/ts-command-line'; -import { BaseRushAction, IBaseRushActionOptions } from '../actions/BaseRushAction'; -import { CommandLineConfiguration } from '../../api/CommandLineConfiguration'; -import { RushConstants } from '../../logic/RushConstants'; - -/** - * Constructor parameters for BaseScriptAction - */ -export interface IBaseScriptActionOptions extends IBaseRushActionOptions { - commandLineConfiguration: CommandLineConfiguration | undefined; -} - -/** - * Base class for command-line actions that are implemented using user-defined scripts. - * - * @remarks - * Compared to the normal built-in actions, these actions are special because (1) they - * can be discovered dynamically via common/config/command-line.json, and (2) - * user-defined command-line parameters can be passed through to the script. - * - * The two subclasses are BulkScriptAction and GlobalScriptAction. - */ -export abstract class BaseScriptAction extends BaseRushAction { - protected readonly _commandLineConfiguration: CommandLineConfiguration | undefined; - protected readonly customParameters: CommandLineParameter[] = []; - - public constructor( - options: IBaseScriptActionOptions - ) { - super(options); - this._commandLineConfiguration = options.commandLineConfiguration; - } - - protected defineScriptParameters(): void { - if (!this._commandLineConfiguration) { - return; - } - - // Find any parameters that are associated with this command - for (const parameterJson of this._commandLineConfiguration.parameters) { - let associated: boolean = false; - for (const associatedCommand of parameterJson.associatedCommands) { - if (associatedCommand === this.actionName) { - associated = true; - } - } - - if (associated) { - let customParameter: CommandLineParameter | undefined; - - switch (parameterJson.parameterKind) { - case 'flag': - customParameter = this.defineFlagParameter({ - parameterShortName: parameterJson.shortName, - parameterLongName: parameterJson.longName, - description: parameterJson.description, - required: parameterJson.required - }); - break; - case 'choice': - customParameter = this.defineChoiceParameter({ - parameterShortName: parameterJson.shortName, - parameterLongName: parameterJson.longName, - description: parameterJson.description, - required: parameterJson.required, - alternatives: parameterJson.alternatives.map(x => x.name), - defaultValue: parameterJson.defaultValue - }); - break; - case 'string': - customParameter = this.defineStringParameter({ - parameterLongName: parameterJson.longName, - parameterShortName: parameterJson.shortName, - description: parameterJson.description, - required: parameterJson.required, - argumentName: parameterJson.argumentName - }); - break; - default: - throw new Error(`${RushConstants.commandLineFilename} defines a parameter "${parameterJson!.longName}"` - + ` using an unsupported parameter kind "${parameterJson!.parameterKind}"`); - } - - if (customParameter) { - this.customParameters.push(customParameter); - } - } - } - } -} diff --git a/apps/rush-lib/src/cli/scriptActions/BulkScriptAction.ts b/apps/rush-lib/src/cli/scriptActions/BulkScriptAction.ts deleted file mode 100644 index 9c30effbc01..00000000000 --- a/apps/rush-lib/src/cli/scriptActions/BulkScriptAction.ts +++ /dev/null @@ -1,307 +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'; -import * as colors from 'colors'; - -import { - Event -} from '../../index'; - -import { - CommandLineFlagParameter, - CommandLineStringParameter, - CommandLineStringListParameter, - CommandLineParameterKind -} from '@rushstack/ts-command-line'; - -import { SetupChecks } from '../../logic/SetupChecks'; -import { TaskSelector } from '../../logic/TaskSelector'; -import { Stopwatch } from '../../utilities/Stopwatch'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; -import { BaseScriptAction, IBaseScriptActionOptions } from './BaseScriptAction'; -import { - FileSystem, - PackageJsonLookup, - IPackageJson -} from '@rushstack/node-core-library'; -import { TaskRunner } from '../../logic/taskRunner/TaskRunner'; -import { TaskCollection } from '../../logic/taskRunner/TaskCollection'; -import { Utilities } from '../../utilities/Utilities'; - -/** - * Constructor parameters for BulkScriptAction. - */ -export interface IBulkScriptActionOptions extends IBaseScriptActionOptions { - enableParallelism: boolean; - ignoreMissingScript: boolean; - ignoreDependencyOrder: boolean; - incremental: boolean; - allowWarningsInSuccessfulBuild: boolean; - - /** - * Optional command to run. Otherwise, use the `actionName` as the command to run. - */ - commandToRun?: string; -} - -/** - * This class implements bulk commands which are run individually for each project in the repo, - * possibly in parallel. The action executes a script found in the project's package.json file. - * - * @remarks - * Bulk commands can be defined via common/config/command-line.json. Rush's predefined "build" - * and "rebuild" commands are also modeled as bulk commands, because they essentially just - * execute scripts from package.json in the same as any custom command. - */ -export class BulkScriptAction extends BaseScriptAction { - private _enableParallelism: boolean; - private _ignoreMissingScript: boolean; - private _isIncrementalBuildAllowed: boolean; - private _commandToRun: string; - - private _changedProjectsOnly: CommandLineFlagParameter; - private _fromFlag: CommandLineStringListParameter; - private _toFlag: CommandLineStringListParameter; - private _fromVersionPolicy: CommandLineStringListParameter; - private _toVersionPolicy: CommandLineStringListParameter; - private _verboseParameter: CommandLineFlagParameter; - private _parallelismParameter: CommandLineStringParameter | undefined; - private _ignoreDependencyOrder: boolean; - private _allowWarningsInSuccessfulBuild: boolean; - - public constructor(options: IBulkScriptActionOptions) { - super(options); - this._enableParallelism = options.enableParallelism; - this._ignoreMissingScript = options.ignoreMissingScript; - this._isIncrementalBuildAllowed = options.incremental; - this._commandToRun = options.commandToRun || options.actionName; - this._ignoreDependencyOrder = options.ignoreDependencyOrder; - this._allowWarningsInSuccessfulBuild = options.allowWarningsInSuccessfulBuild; - } - - public run(): Promise { - if (!FileSystem.exists(this.rushConfiguration.rushLinkJsonFilename)) { - throw new Error(`File not found: ${this.rushConfiguration.rushLinkJsonFilename}` + - `${os.EOL}Did you run "rush link"?`); - } - this._doBeforeTask(); - - const stopwatch: Stopwatch = Stopwatch.start(); - - const isQuietMode: boolean = !(this._verboseParameter.value); - - // 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: string | undefined = this._enableParallelism - ? this._parallelismParameter!.value - : '1'; - - // Collect all custom parameter values - const customParameterValues: string[] = []; - for (const customParameter of this.customParameters) { - customParameter.appendToArgList(customParameterValues); - } - - const changedProjectsOnly: boolean = this._isIncrementalBuildAllowed && this._changedProjectsOnly.value; - - const taskSelector: TaskSelector = new TaskSelector({ - rushConfiguration: this.rushConfiguration, - toFlags: this._mergeProjectsWithVersionPolicy(this._toFlag, this._toVersionPolicy), - fromFlags: this._mergeProjectsWithVersionPolicy(this._fromFlag, this._fromVersionPolicy), - commandToRun: this._commandToRun, - customParameterValues, - isQuietMode: isQuietMode, - isIncrementalBuildAllowed: this._isIncrementalBuildAllowed, - ignoreMissingScript: this._ignoreMissingScript, - ignoreDependencyOrder: this._ignoreDependencyOrder, - packageDepsFilename: Utilities.getPackageDepsFilenameForCommand(this._commandToRun) - }); - - // Register all tasks with the task collection - const taskCollection: TaskCollection = taskSelector.registerTasks(); - - const taskRunner: TaskRunner = new TaskRunner( - taskCollection.getOrderedTasks(), - { - quietMode: isQuietMode, - parallelism: parallelism, - changedProjectsOnly: changedProjectsOnly, - allowWarningsInSuccessfulBuild: this._allowWarningsInSuccessfulBuild - } - ); - - return taskRunner.execute().then(() => { - stopwatch.stop(); - console.log(colors.green(`rush ${this.actionName} (${stopwatch.toString()})`)); - this._doAfterTask(stopwatch, true); - }).catch((error: Error) => { - stopwatch.stop(); - if (error instanceof AlreadyReportedError) { - console.log(colors.green(`rush ${this.actionName} (${stopwatch.toString()})`)); - } else { - if (error && error.message) { - console.log('Error: ' + error.message); - } - - console.log(colors.red(`rush ${this.actionName} - Errors! (${stopwatch.toString()})`)); - } - - this._doAfterTask(stopwatch, false); - throw new AlreadyReportedError(); - }); - } - - protected onDefineParameters(): void { - if (this._enableParallelism) { - this._parallelismParameter = this.defineStringParameter({ - parameterLongName: '--parallelism', - parameterShortName: '-p', - argumentName: 'COUNT', - description: 'Specify the number of concurrent build processes' - + ' The value "max" can be specified to indicate the number of CPU cores.' - + ' If this parameter omitted, the default value depends on the operating system and number of CPU cores.' - }); - } - this._toFlag = this.defineStringListParameter({ - parameterLongName: '--to', - parameterShortName: '-t', - argumentName: 'PROJECT1', - description: 'Run command in the specified project and all of its dependencies. "." can be used as shorthand ' + - 'to specify the project in the current working directory.' - }); - this._fromVersionPolicy = this.defineStringListParameter({ - parameterLongName: '--from-version-policy', - argumentName: 'VERSION_POLICY_NAME', - description: 'Run command in all projects with the specified version policy ' - + 'and all projects that directly or indirectly depend on projects with the specified version policy' - }); - this._toVersionPolicy = this.defineStringListParameter({ - parameterLongName: '--to-version-policy', - argumentName: 'VERSION_POLICY_NAME', - description: 'Run command in all projects with the specified version policy and all of their dependencies' - }); - this._fromFlag = this.defineStringListParameter({ - parameterLongName: '--from', - parameterShortName: '-f', - argumentName: 'PROJECT2', - description: 'Run command in all projects that directly or indirectly depend on the specified project. ' + - '"." can be used as shorthand to specify the project in the current working directory.' - }); - this._verboseParameter = this.defineFlagParameter({ - parameterLongName: '--verbose', - parameterShortName: '-v', - 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: '-o', - description: 'If specified, the incremental build will only rebuild projects that have changed, ' - + 'but not any projects that directly or indirectly depend on the changed package.' - }); - } - - this.defineScriptParameters(); - } - - private _mergeProjectsWithVersionPolicy( - projectsParameters: CommandLineStringListParameter, - versionPoliciesParameters: CommandLineStringListParameter - ): string[] { - const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - - const projects: string[] = []; - for (const projectParameter of projectsParameters.values) { - if (projectParameter === '.') { - const packageJson: IPackageJson | undefined = packageJsonLookup.tryLoadPackageJsonFor(process.cwd()); - if (packageJson) { - const projectName: string = packageJson.name; - if (this.rushConfiguration.projectsByName.has(projectName)) { - projects.push(projectName); - } else { - console.log(colors.red( - 'Rush is not currently running in a project directory specified in rush.json. ' + - `The "." value for the ${this._toFlag.longName} parameter or the ${this._fromFlag.longName} parameter ` + - 'is not allowed.' - )); - throw new AlreadyReportedError(); - } - } else { - console.log(colors.red( - 'Rush is not currently running in a project directory. ' + - `The "." value for the ${this._toFlag.longName} parameter or the ${this._fromFlag.longName} parameter ` + - 'is not allowed.' - )); - throw new AlreadyReportedError(); - } - } else { - projects.push(projectParameter); - } - } - - if (versionPoliciesParameters.values && versionPoliciesParameters.values.length > 0) { - this.rushConfiguration.projects.forEach(project => { - const matches: boolean = versionPoliciesParameters.values.some(policyName => { - return project.versionPolicyName === policyName; - }); - if (matches) { - projects.push(project.packageName); - } - }); - } - - return projects; - } - - private _doBeforeTask(): void { - if (this.actionName !== 'build' && this.actionName !== 'rebuild') { - // Only collects information for built-in tasks like build or rebuild. - return; - } - - SetupChecks.validate(this.rushConfiguration); - - this.eventHooksManager.handle(Event.preRushBuild, this.parser.isDebug); - } - - private _doAfterTask(stopwatch: Stopwatch, success: boolean): void { - if (this.actionName !== 'build' && this.actionName !== 'rebuild') { - // Only collects information for built-in tasks like build or rebuild. - return; - } - this._collectTelemetry(stopwatch, success); - this.parser.flushTelemetry(); - this.eventHooksManager.handle(Event.postRushBuild, this.parser.isDebug); - } - - private _collectTelemetry(stopwatch: Stopwatch, success: boolean): void { - const extraData: { [key: string]: string } = { - command_to: (this._toFlag.values.length > 0).toString(), - command_from: (this._fromFlag.values.length > 0).toString() - }; - - for (const customParameter of this.customParameters) { - switch (customParameter.kind) { - case CommandLineParameterKind.Flag: - case CommandLineParameterKind.Choice: - case CommandLineParameterKind.String: - case CommandLineParameterKind.Integer: - // eslint-disable-next-line @typescript-eslint/no-explicit-any - extraData[customParameter.longName] = JSON.stringify((customParameter as any).value); - break; - default: - extraData[customParameter.longName] = '?'; - } - } - - if (this.parser.telemetry) { - this.parser.telemetry.log({ - name: this.actionName, - duration: stopwatch.duration, - result: success ? 'Succeeded' : 'Failed', - extraData - }); - } - } -} diff --git a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts b/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts deleted file mode 100644 index 8cd63520c8c..00000000000 --- a/apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts +++ /dev/null @@ -1,77 +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 colors from 'colors'; -import * as os from 'os'; - -import { BaseScriptAction, IBaseScriptActionOptions } from './BaseScriptAction'; -import { Utilities } from '../../utilities/Utilities'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; - -/** - * Constructor parameters for GlobalScriptAction. - */ -export interface IGlobalScriptActionOptions extends IBaseScriptActionOptions { - shellCommand: string; -} - -/** - * This class implements custom commands that are run once globally for the entire repo - * (versus bulk commands, which run separately for each project). The action executes - * a user-defined script file. - * - * @remarks - * Bulk commands can be defined via common/config/command-line.json. Rush's predefined "build" - * and "rebuild" commands are also modeled as bulk commands, because they essentially just - * invoke scripts from package.json in the same way as a custom command. - */ -export class GlobalScriptAction extends BaseScriptAction { - private _shellCommand: string; - - public constructor( - options: IGlobalScriptActionOptions - ) { - super(options); - this._shellCommand = options.shellCommand; - } - - public run(): Promise { - return Promise.resolve().then(() => { - // Collect all custom parameter values - const customParameterValues: string[] = []; - - for (const customParameter of this.customParameters) { - customParameter.appendToArgList(customParameterValues); - } - - let shellCommand: string = this._shellCommand; - if (customParameterValues.length > 0) { - shellCommand += ' ' + customParameterValues.join(' '); - } - - const exitCode: number = Utilities.executeLifecycleCommand( - shellCommand, - { - rushConfiguration: this.rushConfiguration, - workingDirectory: this.rushConfiguration.rushJsonFolder, - initCwd: this.rushConfiguration.commonTempFolder, - handleOutput: false, - environmentPathOptions: { - includeRepoBin: true - } - } - ); - - process.exitCode = exitCode; - - if (exitCode > 0) { - console.log(os.EOL + colors.red(`The script failed with exit code ${exitCode}`)); - throw new AlreadyReportedError(); - } - }); - } - - protected onDefineParameters(): void { - this.defineScriptParameters(); - } -} diff --git a/apps/rush-lib/src/cli/test/Cli.test.ts b/apps/rush-lib/src/cli/test/Cli.test.ts deleted file mode 100644 index 965100340cb..00000000000 --- a/apps/rush-lib/src/cli/test/Cli.test.ts +++ /dev/null @@ -1,17 +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 { Utilities } from '../../utilities/Utilities'; - -describe('CLI', () => { - it('should not fail when there is no rush.json', () => { - const workingDir: string = '/'; - const startPath: string = path.resolve(path.join(__dirname, '../../start.js')); - - expect(() => { - Utilities.executeCommand('node', [ startPath ], workingDir, undefined, true); - }).not.toThrow(); - }); -}); diff --git a/apps/rush-lib/src/cli/test/CommandLineHelp.test.ts b/apps/rush-lib/src/cli/test/CommandLineHelp.test.ts deleted file mode 100644 index 99362193ae6..00000000000 --- a/apps/rush-lib/src/cli/test/CommandLineHelp.test.ts +++ /dev/null @@ -1,42 +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 colors from 'colors'; -import * as path from 'path'; -import { RushCommandLineParser } from '../RushCommandLineParser'; - -describe('CommandLineHelp', () => { - let oldCwd: string | undefined; - - let parser: RushCommandLineParser; - - beforeEach(() => { - oldCwd = process.cwd(); - const localCwd: string = path.join(__dirname, 'repo'); - - process.chdir(localCwd); - - // This call may terminate the entire test run because it invokes process.exit() - // if it encounters errors. - // TODO Remove the calls to process.exit() or override them for testing. - parser = new RushCommandLineParser(); - }); - - it('prints the global help', () => { - const helpText: string = colors.stripColors(parser.renderHelpText()); - expect(helpText).toMatchSnapshot(); - }); - - it(`prints the help for each action`, () => { - for (const action of parser.actions) { - const helpText: string = colors.stripColors(action.renderHelpText()); - expect(helpText).toMatchSnapshot(action.actionName); - } - }); - - afterEach(() => { - if (oldCwd) { - process.chdir(oldCwd); - } - }); -}); diff --git a/apps/rush-lib/src/cli/test/RushCommandLineParser.test.ts b/apps/rush-lib/src/cli/test/RushCommandLineParser.test.ts deleted file mode 100644 index e1062aa6a8e..00000000000 --- a/apps/rush-lib/src/cli/test/RushCommandLineParser.test.ts +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import './mockRushCommandLineParser'; - -import * as path from 'path'; -import { FileSystem } from '@rushstack/node-core-library'; -import { Interleaver } from '@rushstack/stream-collator'; -import { RushCommandLineParser } from '../RushCommandLineParser'; - -/** - * See `__mocks__/child_process.js`. - */ -interface ISpawnMockConfig { - emitError: boolean; - returnCode: number; -} - -interface IChildProcessModuleMock { - /** - * Initialize the `spawn` mock behavior. - */ - __setSpawnMockConfig(config?: ISpawnMockConfig): void; - - spawn: jest.Mock; -} - -/** - * Interface definition for a test instance for the RushCommandLineParser. - */ -interface IParserTestInstance { - parser: RushCommandLineParser; - spawnMock: jest.Mock; -} - -/** - * Configure the `child_process` `spawn` mock for these tests. This relies on the mock implementation - * in `__mocks__/child_process.js`. - */ -function setSpawnMock(options?: ISpawnMockConfig): jest.Mock { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const cpMocked: IChildProcessModuleMock = require('child_process'); - cpMocked.__setSpawnMockConfig(options); - - const spawnMock: jest.Mock = cpMocked.spawn; - spawnMock.mockName('spawn'); - return spawnMock; -} - -/** - * Helper to set up a test instance for RushCommandLineParser. - */ -function getCommandLineParserInstance(repoName: string, taskName: string): IParserTestInstance { - // Point to the test repo folder - const startPath: string = path.resolve(__dirname, repoName); - - // The `build` task is hard-coded to be incremental. So delete the package-deps file folder in - // the test repo to guarantee the test actually runs. - FileSystem.deleteFolder(path.resolve(__dirname, `${repoName}/a/.rush/temp`)); - FileSystem.deleteFolder(path.resolve(__dirname, `${repoName}/b/.rush/temp`)); - - // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit - // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test - // repo will fail due to contention over the same lock which is kept until the test runner process - // ends. - const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); - - // Mock the command - process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', taskName]; - const spawnMock: jest.Mock = setSpawnMock(); - - return { - parser, - spawnMock - }; -} - -// 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; - -describe('RushCommandLineParser', () => { - describe('execute', () => { - afterEach(() => { - // Reset Interleaver so we can re-register a task with the same name for the tests. - // - // Interleaver retains a static list of writer loggers which must have unique names. The names are the - // names of the packages. Our unit tests use test repos with generic 'a', 'b' package names, so anything after - // the first test that runs an instance of RushCommandLineParser throws an exception complaining of duplicate - // writer names. - Interleaver.reset(); - - jest.clearAllMocks(); - }); - - describe('in basic repo', () => { - describe(`'build' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'basicAndRunBuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'build'); - - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - - describe(`'rebuild' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'basicAndRunRebuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'rebuild'); - - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - }); - - describe(`in repo with 'rebuild' command overridden`, () => { - describe(`'build' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'overrideRebuildAndRunBuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'build'); - - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - - describe(`'rebuild' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'overrideRebuildAndRunRebuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'rebuild'); - - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - }); - - describe(`in repo with 'rebuild' or 'build' partially set`, () => { - describe(`'build' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'overrideAndDefaultBuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'build'); - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - - describe(`'rebuild' action`, () => { - it(`executes the package's 'build' script`, () => { - const repoName: string = 'overrideAndDefaultRebuildActionRepo'; - const instance: IParserTestInstance = getCommandLineParserInstance(repoName, 'rebuild'); - expect.assertions(8); - return expect(instance.parser.execute()).resolves.toEqual(true) - .then(() => { - // There should be 1 build per package - const packageCount: number = instance.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/; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = instance.spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(firstSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/a`)); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = instance.spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual(expect.arrayContaining([ - expect.stringMatching(expectedBuildTaskRegexp) - ])); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - expect(secondSpawn[SPAWN_ARG_OPTIONS].cwd).toEqual(path.resolve(__dirname, `${repoName}/b`)); - }); - }); - }); - }); - - describe(`in repo with 'build' command overridden as a global command`, () => { - it(`throws an error when starting Rush`, () => { - const repoName: string = 'overrideBuildAsGlobalCommandRepo'; - - expect.assertions(1); - return expect(() => { - getCommandLineParserInstance(repoName, 'doesnt-matter'); - }).toThrowError('This command can only be designated as a command kind "bulk"'); - }); - }); - - describe(`in repo with 'rebuild' command overridden as a global command`, () => { - it(`throws an error when starting Rush`, () => { - const repoName: string = 'overrideRebuildAsGlobalCommandRepo'; - - expect.assertions(1); - return expect(() => { - getCommandLineParserInstance(repoName, 'doesnt-matter'); - }).toThrowError('This command can only be designated as a command kind "bulk"'); - }); - }); - - describe(`in repo with 'build' command overridden with 'safeForSimultaneousRushProcesses=true'`, () => { - it(`throws an error when starting Rush`, () => { - const repoName: string = 'overrideBuildWithSimultaneousProcessesRepo'; - - expect.assertions(1); - return expect(() => { - getCommandLineParserInstance(repoName, 'doesnt-matter'); - }).toThrowError('"safeForSimultaneousRushProcesses=true". This configuration is not supported'); - }); - }); - - describe(`in repo with 'rebuild' command overridden with 'safeForSimultaneousRushProcesses=true'`, () => { - it(`throws an error when starting Rush`, () => { - const repoName: string = 'overrideRebuildWithSimultaneousProcessesRepo'; - - expect.assertions(1); - return expect(() => { - getCommandLineParserInstance(repoName, 'doesnt-matter'); - }).toThrowError('"safeForSimultaneousRushProcesses=true". This configuration is not supported'); - }); - }); - }); -}); diff --git a/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap b/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap deleted file mode 100644 index 7c14f2b7c44..00000000000 --- a/apps/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap +++ /dev/null @@ -1,673 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CommandLineHelp prints the global help 1`] = ` -"usage: rush [-h] [-d] ... - -Rush makes life easier for JavaScript developers who develop, build, and -publish many packages from a central Git repo. It is designed to handle very -large repositories supporting many projects and people. Rush provides -policies, protections, and customizations that help coordinate teams and -safely onboard new contributors. Rush also generates change logs and -automates package publishing. It can manage decoupled subsets of projects -with different release and versioning strategies. A full API is included to -facilitate integration with other automation tools. If you are looking for a -proven turnkey solution for monorepo management, Rush is for you. - -Positional arguments: - - add Adds a dependency to the package.json and runs rush upgrade. - change Records changes made to projects, indicating how the - package version number should be bumped for the next - publish. - check Checks each project's package.json files and ensures that - all dependencies are of the same version throughout the - repository. - install Install package dependencies for all projects in the repo - according to the shrinkwrap file - init Initializes a new repository to be managed by Rush - link Create node_modules symlinks for all projects - list List package information for all projects in the repo - publish Reads and processes package publishing change requests - generated by \\"rush change\\". - purge For diagnostic purposes, use this command to delete caches - and other temporary files used by Rush - scan Scan the current project folder and display a report of - imported packages. - update Install package dependencies for all projects in the repo, - and create or update the shrinkwrap file as needed - unlink Delete node_modules symlinks for all projects in the repo - version (EXPERIMENTAL) Manage package versions in the repo. - import-strings - Imports translated strings into each project. - deploy Deploys the build - build Build all projects that haven't been built, or have changed - since they were last built. - rebuild Clean and rebuild the entire set of projects - -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 - -For detailed help about a specific command, use: rush -h -" -`; - -exports[`CommandLineHelp prints the help for each action: add 1`] = ` -"usage: rush add [-h] -p PACKAGE [--exact] [--caret] [--dev] [-m] [-s] [--all] - -Adds a specified package as a dependency of the current project (as -determined by the current working directory) 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 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. - -Optional arguments: - -h, --help Show this help message and exit. - -p PACKAGE, --package PACKAGE - (Required) 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\\". - --exact If specified, the SemVer specifier added to the - package.json will be an exact version (e.g. without - tilde or caret). - --caret If specified, the SemVer specifier added to the - package.json will be a prepended with a \\"caret\\" - specifier (\\"^\\"). - --dev If specified, the package will be added to the - \\"devDependencies\\" section of the package.json - -m, --make-consistent - If specified, other packages with this dependency - will have their package.json files updated to use the - same version of the dependency. - -s, --skip-update If specified, the \\"rush update\\" command will not be - run after updating the package.json files. - --all If specified, the dependency will be added to all - projects. -" -`; - -exports[`CommandLineHelp prints the help for each action: build 1`] = ` -"usage: rush build [-h] [-p COUNT] [-t PROJECT1] - [--from-version-policy VERSION_POLICY_NAME] - [--to-version-policy VERSION_POLICY_NAME] [-f PROJECT2] [-v] - [-o] [-s] [-m] - - -This command is similar to \\"rush rebuild\\", except that \\"rush build\\" performs -an incremental build. In other words, it only builds projects whose source -files have changed since the last successful build. The analysis requires a -Git working tree, and only considers source files that are tracked by Git and -whose path is under the project folder. (For more details about this -algorithm, see the documentation for the \\"package-deps-hash\\" NPM package.) -The incremental build state is tracked in a per-project folder called \\". -rush/temp\\" which should NOT be added to Git. The build command is tracked by -the \\"arguments\\" field in the \\"package-deps_build.json\\" file contained -therein; a full rebuild is forced whenever the command has changed (e.g. -\\"--production\\" or not). - -Optional arguments: - -h, --help Show this help message and exit. - -p COUNT, --parallelism COUNT - Specify the number of concurrent build processes The - value \\"max\\" can be specified to indicate the number - of CPU cores. If this parameter omitted, the default - value depends on the operating system and number of - CPU cores. - -t PROJECT1, --to PROJECT1 - Run command in the specified project and all of its - dependencies. \\".\\" can be used as shorthand to specify - the project in the current working directory. - --from-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all projects that directly or - indirectly depend on projects with the specified - version policy - --to-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all of their dependencies - -f PROJECT2, --from PROJECT2 - Run command in all projects that directly or - indirectly depend on the specified project. \\".\\" can - be used as shorthand to specify the project in the - current working directory. - -v, --verbose Display the logs during the build, rather than just - displaying the build status summary - -o, --changed-projects-only - If specified, the incremental build will only rebuild - projects that have changed, but not any projects that - directly or indirectly depend on the changed package. - -s, --ship Perform a production build, including minification - and localization steps - -m, --minimal Perform a fast build, which disables certain tasks - such as unit tests and linting -" -`; - -exports[`CommandLineHelp prints the help for each action: change 1`] = ` -"usage: rush change [-h] [-v] [--no-fetch] [-b BRANCH] [--overwrite] - [--email EMAIL] [--bulk] [--message MESSAGE] - [--bump-type {major,minor,patch,none}] - - -Asks a series of questions and then generates a -.json -file in the common folder. The \`publish\` command will consume these files and -perform the proper version bumps. Note these changes will eventually be -published in a changelog.md file in each package. The possible types of -changes are: MAJOR - these are breaking changes that are not backwards -compatible. Examples are: renaming a public class, adding/removing a -non-optional parameter from a public API, or renaming an variable or function -that is exported. MINOR - these are changes that are backwards compatible -(but not forwards compatible). Examples are: adding a new public API or -adding an optional parameter to a public API PATCH - these are changes that -are backwards and forwards compatible. Examples are: Modifying a private API -or fixing a bug in the logic of how an existing API works. HOTFIX -(EXPERIMENTAL) - these are changes that are hotfixes targeting a specific -older version of the package. When a hotfix change is added, other changes -will not be able to increment the version number.Enable this feature by -setting 'hotfixChangeEnabled' in your rush.json. - -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 - --no-fetch Skips fetching the baseline branch before running - \\"git diff\\" to detect changes. - -b BRANCH, --target-branch BRANCH - If this parameter is specified, compare the checked - out branch with the specified branch todetermine - which projects were changed. If this parameter is not - specified, the checked out branch is compared against - the \\"master\\" branch. - --overwrite If a changefile already exists, overwrite without - prompting (or erroring in --bulk mode). - --email EMAIL The email address to use in changefiles. If this - parameter is not provided, the email address will be - detected or prompted for in interactive mode. - --bulk If this flag is specified, apply the same change - message and bump type to all changed projects. The - --message and the --bump-type parameters must be - specified if the --bulk parameter is specified - --message MESSAGE The message to apply to all changed projects if the - --bulk flag is provided. - --bump-type {major,minor,patch,none} - The bump type to apply to all changed projects if the - --bulk flag is provided. -" -`; - -exports[`CommandLineHelp prints the help for each action: check 1`] = ` -"usage: rush check [-h] [--variant VARIANT] [--json] - -Checks each project's package.json files and ensures that all dependencies -are of the same version throughout the repository. - -Optional arguments: - -h, --help Show this help message and exit. - --variant VARIANT Run command using a variant installation configuration. - This parameter may alternatively specified via the - RUSH_VARIANT environment variable. - --json If this flag is specified, output will be in JSON format. -" -`; - -exports[`CommandLineHelp prints the help for each action: deploy 1`] = ` -"usage: rush deploy [-h] [--locale {en-us,fr-fr,es-es,zh-cn}] - -Uploads all the built assets to the CDN - -Optional arguments: - -h, --help Show this help message and exit. - --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 - builds. -" -`; - -exports[`CommandLineHelp prints the help for each action: import-strings 1`] = ` -"usage: rush import-strings [-h] [-p COUNT] [-t PROJECT1] - [--from-version-policy VERSION_POLICY_NAME] - [--to-version-policy VERSION_POLICY_NAME] - [-f PROJECT2] [-v] - [--locale {en-us,fr-fr,es-es,zh-cn}] - - -Requests translated strings from the translation service and imports them -into each project. - -Optional arguments: - -h, --help Show this help message and exit. - -p COUNT, --parallelism COUNT - Specify the number of concurrent build processes The - value \\"max\\" can be specified to indicate the number - of CPU cores. If this parameter omitted, the default - value depends on the operating system and number of - CPU cores. - -t PROJECT1, --to PROJECT1 - Run command in the specified project and all of its - dependencies. \\".\\" can be used as shorthand to specify - the project in the current working directory. - --from-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all projects that directly or - indirectly depend on projects with the specified - version policy - --to-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all of their dependencies - -f PROJECT2, --from PROJECT2 - Run command in all projects that directly or - indirectly depend on the specified project. \\".\\" can - be used as shorthand to specify the project in the - current working directory. - -v, --verbose Display the logs during the build, rather than just - displaying the build status summary - --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 - builds. -" -`; - -exports[`CommandLineHelp prints the help for each action: init 1`] = ` -"usage: rush init [-h] [--overwrite-existing] [--rush-example-repo] - -When invoked in an empty folder, this command provisions a standard set of -config file templates to start managing projects using Rush. - -Optional arguments: - -h, --help Show this help message and exit. - --overwrite-existing By default \\"rush init\\" will not overwrite existing - config files. Specify this switch to override that. - This can be useful when upgrading your repo to a - newer release of Rush. WARNING: USE WITH CARE! - --rush-example-repo When copying the template config files, this - uncomments fragments that are used by the - \\"rush-example\\" GitHub repo, which is a sample - monorepo that illustrates many Rush features. This - option is primarily intended for maintaining that - example. -" -`; - -exports[`CommandLineHelp prints the help for each action: install 1`] = ` -"usage: rush install [-h] [-p] [--bypass-policy] [--no-link] - [--network-concurrency COUNT] [--debug-package-manager] - [--max-install-attempts NUMBER] [--variant VARIANT] - - -The \\"rush install\\" command installs package dependencies for all your -projects, based on the shrinkwrap file that is created/updated using \\"rush -update\\". (This \\"shrinkwrap\\" file stores a central inventory of all -dependencies and versions for projects in your repo. It is found in the -\\"common/config/rush\\" folder.) If the shrinkwrap file is missing or outdated -(e.g. because project package.json files have changed), \\"rush install\\" will -fail and tell you to run \\"rush update\\" instead. This read-only nature is the -main feature: Continuous integration builds should use \\"rush install\\" instead -of \\"rush update\\" to catch developers who forgot to commit their shrinkwrap -changes. Cautious people can also use \\"rush install\\" if they want to avoid -accidentally updating their shrinkwrap file. - -Optional arguments: - -h, --help Show this help message and exit. - -p, --purge Perform \\"rush purge\\" before starting the installation - --bypass-policy Overrides enforcement of the \\"gitPolicy\\" rules from - rush.json (use honorably!) - --no-link If \\"--no-link\\" is specified, then project symlinks - will NOT be created after the installation completes. - You will need to run \\"rush link\\" manually. This flag - is useful for automated builds that want to report - stages individually or perform extra operations in - between the two stages. - --network-concurrency COUNT - If specified, limits the maximum number of concurrent - network requests. This is useful when troubleshooting - network failures. - --debug-package-manager - Activates verbose logging for the package manager. - You will probably want to pipe the output of Rush to - a file when using this command. - --max-install-attempts NUMBER - Overrides the default maximum number of install - attempts. The default value is 3. - --variant VARIANT Run command using a variant installation - configuration. This parameter may alternatively - specified via the RUSH_VARIANT environment variable. -" -`; - -exports[`CommandLineHelp prints the help for each action: link 1`] = ` -"usage: rush link [-h] [-f] - -Create node_modules symlinks for all projects. This operation is normally -performed automatically as part of \\"rush install\\" or \\"rush update\\". You -should only need to use \\"rush link\\" if you performed \\"rush unlink\\" for some -reason, or if you specified the \\"--no-link\\" option for \\"rush install\\" or -\\"rush update\\". - -Optional arguments: - -h, --help Show this help message and exit. - -f, --force Deletes and recreates all links, even if the filesystem state - seems to indicate that this is unnecessary. -" -`; - -exports[`CommandLineHelp prints the help for each action: list 1`] = ` -"usage: rush list [-h] [-v] [-p] [-f] [--json] - -List package names, and optionally version (--version) and path (--path) or -full path (--full-path), for projects in the current rush config. - -Optional arguments: - -h, --help Show this help message and exit. - -v, --version If this flag is specified, the project version will be - displayed in a column along with the package name. - -p, --path If this flag is specified, the project path will be - displayed in a column along with the package name. - -f, --full-path If this flag is specified, the project full path will be - displayed in a column along with the package name. - --json If this flag is specified, output will be in JSON format. -" -`; - -exports[`CommandLineHelp prints the help for each action: publish 1`] = ` -"usage: rush publish [-h] [-a] [-b BRANCH] [-p] [--add-commit-details] - [--regenerate-changelogs] [-r REGISTRY] [-n TOKEN] - [-t TAG] [--set-access-level {public,restricted}] [--pack] - [--release-folder FOLDER] [--include-all] - [--version-policy POLICY] [--prerelease-name NAME] - [--partial-prerelease] [--suffix SUFFIX] [--force] - [--apply-git-tags-on-pack] [-c COMMIT_ID] - - -Reads and processes package publishing change requests generated by \\"rush -change\\". This will perform a 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. - -Optional arguments: - -h, --help Show this help message and exit. - -a, --apply If this flag is specified, the change requests will - be applied to package.json files. - -b BRANCH, --target-branch BRANCH - If this flag is specified, applied changes and - deleted change requests will becommitted and merged - into the target branch. - -p, --publish If this flag is specified, applied changes will be - published to npm. - --add-commit-details Adds commit author and hash to the changelog.json - files for each change. - --regenerate-changelogs - Regenerates all changelog files based on the current - JSON content. - -r REGISTRY, --registry REGISTRY - Publishes to a specified NPM registry. If this is - specified, it will prevent the current commit will - not be tagged. - -n TOKEN, --npm-auth-token TOKEN - Provide the default scope NPM auth token to be passed - into npm publish for global package publishing. - -t TAG, --tag TAG The tag option to pass to npm publish. By default NPM - will publish using the 'latest' tag, even if the - package is older than the current latest, so in - publishing workflows for older releases, providing a - tag is important. When hotfix changes are made, this - parameter defaults to 'hotfix'. - --set-access-level {public,restricted} - By default, when Rush invokes \\"npm publish\\" it will - publish scoped packages with an access level of - \\"restricted\\". Scoped packages can be published with - an access level of \\"public\\" by specifying that value - for this flag with the initial publication. NPM - always publishes unscoped packages with an access - level of \\"public\\". For more information, see the NPM - documentation for the \\"--access\\" option of \\"npm - publish\\". - --pack Packs projects into tarballs instead of publishing to - npm repository. It can only be used when - --include-all is specified. If this flag is specified, - NPM registry related parameters will be ignored. - --release-folder FOLDER - This parameter is used with --pack parameter to - provide customized location for the tarballs instead - of the default value. - --include-all If this flag is specified, all packages with - shouldPublish=true in rush.json or with a specified - version policy will be published if their version is - newer than published version. - --version-policy POLICY - Version policy name. Only projects with this version - policy will be published if used with --include-all. - --prerelease-name NAME - Bump up to a prerelease version with the provided - prerelease name. Cannot be used with --suffix - --partial-prerelease Used with --prerelease-name. Only bump packages to a - prerelease version if they have changes. - --suffix SUFFIX Append a suffix to all changed versions. Cannot be - used with --prerelease-name. - --force If this flag is specified with --publish, packages - will be published with --force on npm - --apply-git-tags-on-pack - If specified with --publish and --pack, git tags will - be applied for packages as if a publish was being run - without --pack. - -c COMMIT_ID, --commit COMMIT_ID - Used in conjunction with git tagging -- apply git - tags at the commit hash specified. If not provided, - the current HEAD will be tagged. -" -`; - -exports[`CommandLineHelp prints the help for each action: purge 1`] = ` -"usage: rush purge [-h] [--unsafe] - -The \\"rush purge\\" command is used to delete temporary files created by Rush. -This is useful if you are having problems and suspect that cache files may be -corrupt. - -Optional arguments: - -h, --help Show this help message and exit. - --unsafe (UNSAFE!) Also delete shared files such as the package manager - instances stored in the \\".rush\\" folder in the user's home - directory. This is a more aggressive fix that is NOT SAFE to - run in a live environment because it will cause other - concurrent Rush processes to fail. -" -`; - -exports[`CommandLineHelp prints the help for each action: rebuild 1`] = ` -"usage: rush rebuild [-h] [-p COUNT] [-t PROJECT1] - [--from-version-policy VERSION_POLICY_NAME] - [--to-version-policy VERSION_POLICY_NAME] [-f PROJECT2] - [-v] [-s] [-m] - - -This command assumes that the package.json file for each project contains a -\\"scripts\\" entry for \\"npm run build\\" that performs a full clean build. Rush -invokes this script to build each project that is registered in rush.json. -Projects are built in parallel where possible, but always respecting the -dependency graph for locally linked projects. The number of simultaneous -processes will be based on the number of machine cores unless overridden by -the --parallelism flag. (For an incremental build, see \\"rush build\\" instead -of \\"rush rebuild\\".) - -Optional arguments: - -h, --help Show this help message and exit. - -p COUNT, --parallelism COUNT - Specify the number of concurrent build processes The - value \\"max\\" can be specified to indicate the number - of CPU cores. If this parameter omitted, the default - value depends on the operating system and number of - CPU cores. - -t PROJECT1, --to PROJECT1 - Run command in the specified project and all of its - dependencies. \\".\\" can be used as shorthand to specify - the project in the current working directory. - --from-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all projects that directly or - indirectly depend on projects with the specified - version policy - --to-version-policy VERSION_POLICY_NAME - Run command in all projects with the specified - version policy and all of their dependencies - -f PROJECT2, --from PROJECT2 - Run command in all projects that directly or - indirectly depend on the specified project. \\".\\" can - be used as shorthand to specify the project in the - current working directory. - -v, --verbose Display the logs during the build, rather than just - displaying the build status summary - -s, --ship Perform a production build, including minification - and localization steps - -m, --minimal Perform a fast build, which disables certain tasks - such as unit tests and linting -" -`; - -exports[`CommandLineHelp prints the help for each action: scan 1`] = ` -"usage: rush scan [-h] - -The NPM system allows a project to import dependencies without explicitly -listing them in its package.json file. This is a dangerous practice, because -there is no guarantee you will get a compatible version. The \\"rush scan\\" -command reports a list of packages that are imported by your code, which you -can compare against your package.json file to find mistakes. It searches the -\\"./src\\" and \\"./lib\\" folders for typical import syntaxes such as \\"import __ -from '__'\\", \\"require('__')\\", \\"System.import('__'), etc. The results are only -approximate, but generally pretty accurate. - -Optional arguments: - -h, --help Show this help message and exit. -" -`; - -exports[`CommandLineHelp prints the help for each action: unlink 1`] = ` -"usage: rush unlink [-h] - -This removes the symlinks created by the \\"rush link\\" command. This is useful -for cleaning a repo using \\"git clean\\" without accidentally deleting source -files, or for using standard NPM commands on a project. - -Optional arguments: - -h, --help Show this help message and exit. -" -`; - -exports[`CommandLineHelp prints the help for each action: update 1`] = ` -"usage: rush update [-h] [-p] [--bypass-policy] [--no-link] - [--network-concurrency COUNT] [--debug-package-manager] - [--max-install-attempts NUMBER] [--variant VARIANT] - [--full] [--recheck] - - -The \\"rush update\\" command installs the dependencies described in your package. -json files, and updates the shrinkwrap file as needed. (This \\"shrinkwrap\\" -file stores a central inventory of all dependencies and versions for projects -in your repo. It is found in the \\"common/config/rush\\" folder.) Note that Rush -always performs a single install for all projects in your repo. You should -run \\"rush update\\" whenever you start working in a Rush repo, after you pull -from Git, and after you modify a package.json file. If there is nothing to do, - \\"rush update\\" is instantaneous. NOTE: In certain cases \\"rush install\\" should -be used instead of \\"rush update\\" -- for details, see the command help for -\\"rush install\\". - -Optional arguments: - -h, --help Show this help message and exit. - -p, --purge Perform \\"rush purge\\" before starting the installation - --bypass-policy Overrides enforcement of the \\"gitPolicy\\" rules from - rush.json (use honorably!) - --no-link If \\"--no-link\\" is specified, then project symlinks - will NOT be created after the installation completes. - You will need to run \\"rush link\\" manually. This flag - is useful for automated builds that want to report - stages individually or perform extra operations in - between the two stages. - --network-concurrency COUNT - If specified, limits the maximum number of concurrent - network requests. This is useful when troubleshooting - network failures. - --debug-package-manager - Activates verbose logging for the package manager. - You will probably want to pipe the output of Rush to - a file when using this command. - --max-install-attempts NUMBER - Overrides the default maximum number of install - attempts. The default value is 3. - --variant VARIANT Run command using a variant installation - configuration. This parameter may alternatively - specified via the RUSH_VARIANT environment variable. - --full Normally \\"rush update\\" tries to preserve your - existing installed versions and only makes the - minimum updates needed to satisfy the package.json - files. This conservative approach prevents your PR - from getting involved with package updates that are - unrelated to your work. Use \\"--full\\" when you really - want to update all dependencies to the latest - SemVer-compatible version. This should be done - periodically by a person or robot whose role is to - deal with potential upgrade regressions. - --recheck If the shrinkwrap file appears to already satisfy the - package.json files, then \\"rush update\\" will skip - invoking the package manager at all. In certain - situations this heuristic may be inaccurate. Use the - \\"--recheck\\" flag to force the package manager to - process the shrinkwrap file. This will also update - your shrinkwrap file with Rush's fixups. (To minimize - shrinkwrap churn, these fixups are normally performed - only in the temporary folder.) -" -`; - -exports[`CommandLineHelp prints the help for each action: version 1`] = ` -"usage: rush version [-h] [-b BRANCH] [--ensure-version-policy] - [--override-version NEW_VERSION] [--bump] - [--bypass-policy] [--version-policy POLICY] - [--override-bump BUMPTYPE] [--override-prerelease-id ID] - - -(EXPERIMENTAL) use this \\"rush version\\" command to ensure version policies and -bump versions. - -Optional arguments: - -h, --help Show this help message and exit. - -b BRANCH, --target-branch BRANCH - If this flag is specified, changes will be committed - and merged into the target branch. - --ensure-version-policy - Updates package versions if needed to satisfy version - policies. - --override-version NEW_VERSION - Override the version in the specified - --version-policy. This setting only works for - lock-step version policy and when - --ensure-version-policy is specified. - --bump Bumps package version based on version policies. - --bypass-policy Overrides \\"gitPolicy\\" enforcement (use honorably!) - --version-policy POLICY - The name of the version policy - --override-bump BUMPTYPE - Overrides the bump type in the version-policy.json - for the specified version policy.Valid BUMPTYPE - values include: prerelease, patch, preminor, minor, - major. This setting only works for lock-step version - policy in bump action. - --override-prerelease-id ID - Overrides the prerelease identifier in the version - value of version-policy.json for the specified - version policy. This setting only works for lock-step - version policy. This setting increases to new - prerelease id when \\"--bump\\" is provided but only - replaces the prerelease name when - \\"--ensure-version-policy\\" is provided. -" -`; diff --git a/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/b/package.json b/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json deleted file mode 100644 index 0880b6c8e68..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$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 - }, - { - - "commandKind": "bulk", - "name": "my-bulk-command", - "summary": "Example bulk custom command", - "description": "This is an example custom command that runs separately for each project", - "safeForSimultaneousRushProcesses": false, - "enableParallelism": false, - "ignoreDependencyOrder": false, - "ignoreMissingScript": false, - "allowWarningsInSuccessfulBuild": false - }, - { - "commandKind": "global", - "name": "my-global-command", - "summary": "Example global custom command", - "description": "This is an example custom command that runs once for the entire repo", - "safeForSimultaneousRushProcesses": false, - "shellCommand": "node common/scripts/my-global-command.js" - } - ], - "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" ] - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json deleted file mode 100644 index 0880b6c8e68..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$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 - }, - { - - "commandKind": "bulk", - "name": "my-bulk-command", - "summary": "Example bulk custom command", - "description": "This is an example custom command that runs separately for each project", - "safeForSimultaneousRushProcesses": false, - "enableParallelism": false, - "ignoreDependencyOrder": false, - "ignoreMissingScript": false, - "allowWarningsInSuccessfulBuild": false - }, - { - "commandKind": "global", - "name": "my-global-command", - "summary": "Example global custom command", - "description": "This is an example custom command that runs once for the entire repo", - "safeForSimultaneousRushProcesses": false, - "shellCommand": "node common/scripts/my-global-command.js" - } - ], - "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" ] - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json deleted file mode 100644 index 4d4b12d2919..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "global", - "name": "build", - "summary": "Build", - "description": "This combo is not supported", - "shellCommand": "node fake-build" - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json deleted file mode 100644 index 482b5cf5c07..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "bulk", - "name": "build", - "summary": "Build", - "description": "This combo is not supported", - "enableParallelism": true, - "safeForSimultaneousRushProcesses": true - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json deleted file mode 100644 index cabdccc3e93..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "bulk", - "name": "rebuild", - "summary": "Rebuild the repo", - "description": "Rebuild the repo using the 'rebuild' script command", - "enableParallelism": true - } - ], - "parameters": [ - { - "longName": "--flag-for-build-and-rebuild", - "description": "This flag should be usable for build and rebuild commands.", - "parameterKind": "flag", - "associatedCommands": [ "build", "rebuild" ] - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json deleted file mode 100644 index cabdccc3e93..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "bulk", - "name": "rebuild", - "summary": "Rebuild the repo", - "description": "Rebuild the repo using the 'rebuild' script command", - "enableParallelism": true - } - ], - "parameters": [ - { - "longName": "--flag-for-build-and-rebuild", - "description": "This flag should be usable for build and rebuild commands.", - "parameterKind": "flag", - "associatedCommands": [ "build", "rebuild" ] - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json deleted file mode 100644 index 688c1a7cc4a..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "global", - "name": "rebuild", - "summary": "Rebuild", - "description": "This combo is not supported", - "shellCommand": "node fake-rebuild" - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/b/package.json b/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/b/package.json deleted file mode 100644 index 8f203bb691d..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "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/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json deleted file mode 100644 index ea2fc24ac41..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", - "commands": [ - { - "commandKind": "bulk", - "name": "rebuild", - "summary": "Rebuild", - "description": "This combo is not supported", - "enableParallelism": true, - "safeForSimultaneousRushProcesses": true - } - ] -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/temp/rush-link.json b/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/temp/rush-link.json deleted file mode 100644 index 4e8f3d15203..00000000000 --- a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/temp/rush-link.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "localLinks": { - "a": [], - "b": [] - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/cli/test/repo/common/config/rush/command-line.json b/apps/rush-lib/src/cli/test/repo/common/config/rush/command-line.json deleted file mode 100644 index 55a8ed66278..00000000000 --- a/apps/rush-lib/src/cli/test/repo/common/config/rush/command-line.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "commands": [ - { - "name": "import-strings", - "commandKind": "bulk", - "summary": "Imports translated strings into each project.", - "description": "Requests translated strings from the translation service and imports them into each project.", - "enableParallelism": true - }, - { - "name": "deploy", - "commandKind": "global", - "summary": "Deploys the build", - "description": "Uploads all the built assets to the CDN", - "shellCommand": "node common/scripts/deploy.js" - } - ], - - "parameters": [ - { - "longName": "--locale", - "parameterKind": "choice", - "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", - "associatedCommands": [ "import-strings", "deploy" ], - "alternatives": [ - { - "name": "en-us", - "description": "US English" - }, - { - "name": "fr-fr", - "description": "French (France)" - }, - { - "name": "es-es", - "description": "Spanish (Spain)" - }, - { - "name": "zh-cn", - "description": "Chinese (China)" - } - ] - }, - - { - "longName": "--ship", - "shortName": "-s", - "parameterKind": "flag", - "description": "Perform a production build, including minification and localization steps", - "associatedCommands": [ "build", "rebuild" ] - }, - - { - "longName": "--minimal", - "shortName": "-m", - "parameterKind": "flag", - "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", - "associatedCommands": [ "build", "rebuild" ] - } - ] -} diff --git a/apps/rush-lib/src/cli/test/repo/rush.json b/apps/rush-lib/src/cli/test/repo/rush.json deleted file mode 100644 index fa1af090d5d..00000000000 --- a/apps/rush-lib/src/cli/test/repo/rush.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pnpmVersion": "4.5.0", - "rushVersion": "5.0.0", - "projects": [ - ] -} diff --git a/apps/rush-lib/src/index.ts b/apps/rush-lib/src/index.ts deleted file mode 100644 index 487b027a9d6..00000000000 --- a/apps/rush-lib/src/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -// 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 - */ - -export { - ApprovedPackagesPolicy -} from './api/ApprovedPackagesPolicy'; - -export { - RushConfiguration, - ITryFindRushJsonLocationOptions, - ResolutionStrategy, - IPackageManagerOptionsJsonBase, - IConfigurationEnvironment, - IConfigurationEnvironmentVariable, - INpmOptionsJson as _INpmOptionsJson, - IPnpmOptionsJson as _IPnpmOptionsJson, - IYarnOptionsJson as _IYarnOptionsJson, - PnpmStoreOptions, - PackageManagerOptionsConfigurationBase, - PnpmOptionsConfiguration, - NpmOptionsConfiguration, - YarnOptionsConfiguration -} from './api/RushConfiguration'; - -export { - PackageManagerName, - PackageManager -} from './api/packageManager/PackageManager'; - -export { - EnvironmentVariableNames -} from './api/EnvironmentConfiguration'; - -export { - RushConfigurationProject -} from './api/RushConfigurationProject'; - -export { - RushGlobalFolder as _RushGlobalFolder -} from './api/RushGlobalFolder'; - -export { - ApprovedPackagesItem, - ApprovedPackagesConfiguration -} from './api/ApprovedPackagesConfiguration'; - -export { - CommonVersionsConfiguration -} from './api/CommonVersionsConfiguration'; - -export { - PackageJsonEditor, - PackageJsonDependency, - DependencyType -} from './api/PackageJsonEditor'; - -export { - EventHooks, - Event -} from './api/EventHooks'; - -export { - ChangeManager -} from './api/ChangeManager'; - -export { - LastInstallFlag as _LastInstallFlag -} from './api/LastInstallFlag'; - -export { - VersionPolicyDefinitionName, - BumpType, - LockStepVersionPolicy, - IndividualVersionPolicy, - VersionPolicy -} from './api/VersionPolicy'; - -export { - VersionPolicyConfiguration -} from './api/VersionPolicyConfiguration'; - -export { - ILaunchOptions, - Rush -} from './api/Rush'; - -export { - ExperimentsConfiguration, - IExperimentsJson -} from './api/ExperimentsConfiguration'; diff --git a/apps/rush-lib/src/logic/ChangeFiles.ts b/apps/rush-lib/src/logic/ChangeFiles.ts deleted file mode 100644 index 7fc1dbf94c8..00000000000 --- a/apps/rush-lib/src/logic/ChangeFiles.ts +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { EOL } from 'os'; -import * as glob from 'glob'; - -import { Utilities } from '../utilities/Utilities'; -import { IChangeInfo } from '../api/ChangeManagement'; -import { IChangelog } from '../api/Changelog'; -import { JsonFile } from '@rushstack/node-core-library'; -import { RushConfiguration } from '../api/RushConfiguration'; - -/** - * This class represents the collection of change files existing in the repo and provides operations - * for those change files. - */ -export class ChangeFiles { - - /** - * Change file path relative to changes folder. - */ - private _files: string[]; - private _changesPath: string; - - public constructor(changesPath: string) { - this._changesPath = changesPath; - } - - /** - * Validate if the newly added change files match the changed packages. - */ - public static validate( - newChangeFilePaths: string[], - changedPackages: string[], - rushConfiguration: RushConfiguration - ): void { - const projectsWithChangeDescriptions: Set = new Set(); - newChangeFilePaths.forEach((filePath) => { - console.log(`Found change file: ${filePath}`); - - const changeFile: IChangeInfo = JsonFile.load(filePath); - - 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'.`); - } - } - } - } - - if (changeFile && changeFile.changes) { - changeFile.changes.forEach(change => projectsWithChangeDescriptions.add(change.packageName)); - } else { - throw new Error(`Invalid change file: ${filePath}`); - } - }); - - 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)); - throw new Error([ - 'The following projects have been changed and require change descriptions, but change descriptions were not ' + - 'detected for them:', - ...projectsMissingChangeDescriptionsArray.map((projectName) => `- ${projectName}`), - 'To resolve this error, run "rush change." This will generate change description files that must be ' + - 'committed to source control.' - ].join(EOL)); - } - } - - public static getChangeComments( - newChangeFilePaths: string[] - ): Map { - const changes: Map = new Map(); - - newChangeFilePaths.forEach((filePath) => { - console.log(`Found change file: ${filePath}`); - const changeRequest: IChangeInfo = JsonFile.load(filePath); - if (changeRequest && changeRequest.changes) { - changeRequest.changes!.forEach(change => { - if (!changes.get(change.packageName)) { - changes.set(change.packageName, []); - } - if (change.comment && change.comment.length) { - changes.get(change.packageName)!.push(change.comment); - } - }); - } else { - throw new Error(`Invalid change file: ${filePath}`); - } - }); - return changes; - } - - /** - * Get the array of absolute paths of change files. - */ - public getFiles(): string[] { - if (this._files) { - return this._files; - } - this._files = glob.sync(`${this._changesPath}/**/*.json`); - return this._files || []; - } - - /** - * Get the path of changes folder. - */ - public getChangesPath(): string { - return this._changesPath; - } - - /** - * Delete all change files - */ - public deleteAll(shouldDelete: boolean, updatedChangelogs?: IChangelog[]): number { - if (updatedChangelogs) { - // Skip changes files if the package's change log is not updated. - const packagesToInclude: Set = new Set(); - updatedChangelogs.forEach((changelog) => { - packagesToInclude.add(changelog.name); - }); - - const filesToDelete: string[] = this.getFiles().filter((filePath) => { - const changeRequest: IChangeInfo = JsonFile.load(filePath); - for (const changeInfo of changeRequest.changes!) { - if (!packagesToInclude.has(changeInfo.packageName)) { - return false; - } - } - return true; - }); - - return this._deleteFiles(filesToDelete, shouldDelete); - } else { - // Delete all change files. - return this._deleteFiles(this.getFiles(), shouldDelete); - } - } - - private _deleteFiles(files: string[], shouldDelete: boolean): number { - if (files.length) { - console.log( - `${EOL}* ` + - `${shouldDelete ? 'DELETING:' : 'DRYRUN: Deleting'} ` + - `${files.length} change file(s).` - ); - - for (const filePath of files) { - console.log(` - ${filePath}`); - - if (shouldDelete) { - Utilities.deleteFile(filePath); - } - } - } - return files.length; - } -} diff --git a/apps/rush-lib/src/logic/ChangeManager.ts b/apps/rush-lib/src/logic/ChangeManager.ts deleted file mode 100644 index cdd8db8a8cc..00000000000 --- a/apps/rush-lib/src/logic/ChangeManager.ts +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { IPackageJson } from '@rushstack/node-core-library'; - -import { IChangeInfo } from '../api/ChangeManagement'; -import { IChangelog } from '../api/Changelog'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { VersionPolicyConfiguration } from '../api/VersionPolicyConfiguration'; -import { PublishUtilities, IChangeInfoHash } from './PublishUtilities'; -import { ChangeFiles } from './ChangeFiles'; -import { PrereleaseToken } from './PrereleaseToken'; -import { ChangelogGenerator } from './ChangelogGenerator'; - -/** - * The class manages change files and controls how changes logged by change files - * can be applied to package.json and change logs. - */ -export class ChangeManager { - private _prereleaseToken: PrereleaseToken; - private _orderedChanges: IChangeInfo[]; - private _allPackages: Map; - private _allChanges: IChangeInfoHash; - private _changeFiles: ChangeFiles; - private _rushConfiguration: RushConfiguration; - private _lockStepProjectsToExclude: Set | undefined; - - public constructor( - rushConfiguration: RushConfiguration, - lockStepProjectsToExclude?: Set | undefined - ) { - this._rushConfiguration = rushConfiguration; - this._lockStepProjectsToExclude = lockStepProjectsToExclude; - } - - /** - * 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 load( - changesPath: string, - prereleaseToken: PrereleaseToken = new PrereleaseToken(), - includeCommitDetails: boolean = false - ): void { - this._allPackages = this._rushConfiguration.projectsByName; - - this._prereleaseToken = prereleaseToken; - - this._changeFiles = new ChangeFiles(changesPath); - this._allChanges = PublishUtilities.findChangeRequests( - this._allPackages, - this._rushConfiguration, - this._changeFiles, - includeCommitDetails, - this._prereleaseToken, - this._lockStepProjectsToExclude - ); - this._orderedChanges = PublishUtilities.sortChangeRequests(this._allChanges); - } - - public hasChanges(): boolean { - return this._orderedChanges && this._orderedChanges.length > 0; - } - - public get changes(): IChangeInfo[] { - return this._orderedChanges; - } - - public get allPackages(): Map { - return this._allPackages; - } - - public validateChanges(versionConfig: VersionPolicyConfiguration): void { - Object - .keys(this._allChanges) - .filter((key) => { - const projectInfo: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName(key); - if (projectInfo) { - if (projectInfo.versionPolicy) { - const changeInfo: IChangeInfo = this._allChanges[key]; - projectInfo.versionPolicy.validate(changeInfo.newVersion!, key); - } - } - }); - } - - /** - * Apply changes to package.json - * @param shouldCommit - If the value is true, package.json will be updated. - * If the value is false, package.json and change logs will not be updated. It will only do a dry-run. - */ - public apply(shouldCommit: boolean): Map | undefined { - if (!this.hasChanges()) { - return; - } - - // Apply all changes to package.json files. - const updatedPackages: Map = PublishUtilities.updatePackages( - this._allChanges, - this._allPackages, - this._rushConfiguration, - shouldCommit, - this._prereleaseToken, - this._lockStepProjectsToExclude); - - return updatedPackages; - } - - public updateChangelog(shouldCommit: boolean): void { - // Do not update changelog or delete the change files for prerelease. - // Save them for the official release. - if (!this._prereleaseToken.hasValue) { - // Update changelogs. - const updatedChangelogs: IChangelog[] = ChangelogGenerator.updateChangelogs( - this._allChanges, - this._allPackages, - this._rushConfiguration, - shouldCommit - ); - - // Remove the change request files only if "-a" was provided. - this._changeFiles.deleteAll(shouldCommit, updatedChangelogs); - } - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/ChangelogGenerator.ts b/apps/rush-lib/src/logic/ChangelogGenerator.ts deleted file mode 100644 index 0b3b2c6cdfe..00000000000 --- a/apps/rush-lib/src/logic/ChangelogGenerator.ts +++ /dev/null @@ -1,296 +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 semver from 'semver'; - -import { - FileSystem, - JsonFile -} from '@rushstack/node-core-library'; - -import { - PublishUtilities, - IChangeInfoHash -} from './PublishUtilities'; -import { - IChangeInfo, - ChangeType -} from '../api/ChangeManagement'; -import { - IChangelog, - IChangeLogEntry, - IChangeLogComment -} from '../api/Changelog'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { RushConfiguration } from '../api/RushConfiguration'; - -const CHANGELOG_JSON: string = 'CHANGELOG.json'; -const CHANGELOG_MD: string = 'CHANGELOG.md'; -const EOL: string = '\n'; - -export class ChangelogGenerator { - /** - * Updates the appropriate changelogs with the given changes. - */ - public static updateChangelogs( - allChanges: IChangeInfoHash, - allProjects: Map, - rushConfiguration: RushConfiguration, - shouldCommit: boolean - ): IChangelog[] { - const updatedChangeLogs: IChangelog[] = []; - - for (const packageName in allChanges) { - if (allChanges.hasOwnProperty(packageName)) { - const project: RushConfigurationProject | undefined = allProjects.get(packageName); - - if (project && ChangelogGenerator._shouldUpdateChangeLog(project, allChanges)) { - const changeLog: IChangelog | undefined = ChangelogGenerator.updateIndividualChangelog( - allChanges[packageName], - project.projectFolder, - shouldCommit, - rushConfiguration, - project.versionPolicy && project.versionPolicy.isLockstepped, - project.isMainProject - ); - - if (changeLog) { - updatedChangeLogs.push(changeLog); - } - } - } - } - return updatedChangeLogs; - } - - /** - * Fully regenerate the markdown files based on the current json files. - */ - public static regenerateChangelogs( - allProjects: Map, - rushConfiguration: RushConfiguration - ): void { - allProjects.forEach(project => { - const markdownPath: string = path.resolve(project.projectFolder, CHANGELOG_MD); - const markdownJSONPath: string = path.resolve(project.projectFolder, CHANGELOG_JSON); - - if (FileSystem.exists(markdownPath)) { - console.log('Found: ' + markdownPath); - if (!FileSystem.exists(markdownJSONPath)) { - throw new Error('A CHANGELOG.md without json: ' + markdownPath); - } - - const changelog: IChangelog = ChangelogGenerator._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) - ); - } - - }); - } - - /** - * Updates an individual changelog for a single project. - */ - public static updateIndividualChangelog( - change: IChangeInfo, - projectFolder: string, - shouldCommit: boolean, - rushConfiguration: RushConfiguration, - isLockstepped: boolean = false, - isMain: boolean = true - ): IChangelog | undefined { - if (isLockstepped && !isMain) { - // Early return if the project is lockstepped and does not host change logs - return undefined; - } - const changelog: IChangelog = ChangelogGenerator._getChangelog(change.packageName, projectFolder); - - if ( - !changelog.entries.some(entry => entry.version === change.newVersion)) { - - const changelogEntry: IChangeLogEntry = { - version: change.newVersion!, - tag: PublishUtilities.createTagname(change.packageName, change.newVersion!), - date: new Date().toUTCString(), - comments: {} - }; - - change.changes!.forEach(individualChange => { - if (individualChange.comment) { - - // Initialize the comments array only as necessary. - const changeTypeString: string = ChangeType[individualChange.changeType!]; - const comments: IChangeLogComment[] = - changelogEntry.comments[changeTypeString] = - changelogEntry.comments[changeTypeString] || []; - - const changeLogComment: IChangeLogComment = { - comment: individualChange.comment - }; - if (individualChange.author) { - changeLogComment.author = individualChange.author; - } - if (individualChange.commit) { - changeLogComment.commit = individualChange.commit; - } - comments.push(changeLogComment); - } - }); - - // Add the changelog entry to the start of the list. - changelog.entries.unshift(changelogEntry); - - const changelogFilename: string = path.join(projectFolder, CHANGELOG_JSON); - - console.log( - `${EOL}* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: ` + - `Changelog update for "${change.packageName}@${change.newVersion}".` - ); - - if (shouldCommit) { - // Write markdown transform. - JsonFile.save(changelog, changelogFilename); - - FileSystem.writeFile( - path.join(projectFolder, CHANGELOG_MD), - ChangelogGenerator._translateToMarkdown(changelog, rushConfiguration, isLockstepped) - ); - } - return changelog; - } - // 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.load(changelogFilename); - } - - 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; - } - - return changelog; - } - - /** - * 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}`; - } - - markdown += EOL; - - let comments: string = ''; - - comments += ChangelogGenerator._getChangeComments( - 'Breaking changes', - entry.comments[ChangeType[ChangeType.major]]); - - comments += ChangelogGenerator._getChangeComments( - 'Minor changes', - entry.comments[ChangeType[ChangeType.minor]]); - - comments += ChangelogGenerator._getChangeComments( - 'Patches', - entry.comments[ChangeType[ChangeType.patch]]); - - if (isLockstepped) { - // In lockstepped projects, all changes are of type ChangeType.none. - comments += ChangelogGenerator._getChangeComments( - 'Updates', - entry.comments[ChangeType[ChangeType.none]]); - } - - if (rushConfiguration.hotfixChangeEnabled) { - comments += ChangelogGenerator._getChangeComments( - 'Hotfixes', - entry.comments[ChangeType[ChangeType.hotfix]]); - } - - if (!comments) { - markdown += ((changelog.entries.length === index + 1) ? - '*Initial release*' : - '*Version update only*') + - EOL + EOL; - } else { - markdown += comments; - } - - }); - - return markdown; - } - - /** - * Helper to return the comments string to be appends to the markdown content. - */ - private static _getChangeComments(title: string, commentsArray: IChangeLogComment[]): string { - let comments: string = ''; - - if (commentsArray) { - comments = `### ${title}${EOL + EOL}`; - commentsArray.forEach(comment => { - comments += `- ${comment.comment}${EOL}`; - }); - comments += EOL; - } - - 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 - */ - private static _shouldUpdateChangeLog( - project: RushConfigurationProject, - allChanges: IChangeInfoHash - ): boolean { - - return project.shouldPublish && - (!semver.prerelease(project.packageJson.version) || - allChanges[project.packageName].changeType === ChangeType.hotfix); - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/DependencySpecifier.ts b/apps/rush-lib/src/logic/DependencySpecifier.ts deleted file mode 100644 index 51f653aad58..00000000000 --- a/apps/rush-lib/src/logic/DependencySpecifier.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import npmPackageArg = require('npm-package-arg'); -import { InternalError } from '@rushstack/node-core-library'; - -/** - * 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. - * A "dependency specifier" is the version specifier information, combined with the dependency package name. - */ -export class DependencySpecifier { - /** - * The dependency package name, i.e. the key from a "dependencies" key/value table. - */ - public readonly packageName: string; - - /** - * The dependency version specifier, i.e. the value from a "dependencies" key/value table. - * Example values: `^1.2.3`, `file:./blah.tgz`, `npm:other-package@~1.2.3` - */ - public readonly versionSpecifier: string; - - /** - * The type of `versionSpecifier`: - * - * git - a git repository - * tag - a tagged version, e.g. "example@latest" - * version - A specific version number, e.g. "example@1.2.3" - * range - A version range, e.g. "example@2.x" - * file - A local .tar.gz, .tar or .tgz file - * directory - A local directory - * remote - An HTTP url to a .tar.gz, .tar or .tgz file - * alias - A package alias such as "npm:other-package@^1.2.3" - */ - public readonly specifierType: string; - - /** - * If `specifierType` is `alias`, then this is the parsed target dependency. - * For example, if version specifier i `"npm:other-package@^1.2.3"` then this is the parsed object for - * `other-package@^1.2.3`. - */ - public readonly aliasTarget: DependencySpecifier | undefined; - - public constructor(packageName: string, versionSpecifier: string) { - this.packageName = packageName; - this.versionSpecifier = versionSpecifier; - - const result: npmPackageArg.AliasResult = npmPackageArg.resolve( - packageName, - versionSpecifier - ) as npmPackageArg.AliasResult; - - this.specifierType = result.type; - - if (result.type === 'alias') { - if (!result.subSpec || !result.subSpec.name) { - throw new InternalError('Unexpected result from npm-package-arg'); - } - this.aliasTarget = new DependencySpecifier(result.subSpec.name, result.subSpec.rawSpec); - } else { - this.aliasTarget = undefined; - } - } -} diff --git a/apps/rush-lib/src/logic/EventHooksManager.ts b/apps/rush-lib/src/logic/EventHooksManager.ts deleted file mode 100644 index dc3570c131d..00000000000 --- a/apps/rush-lib/src/logic/EventHooksManager.ts +++ /dev/null @@ -1,61 +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'; -import * as colors from 'colors'; - -import { EventHooks } from '../api/EventHooks'; -import { Utilities } from '../utilities/Utilities'; -import { Event } from '../api/EventHooks'; -import { Stopwatch } from '../utilities/Stopwatch'; -import { RushConfiguration } from '../api/RushConfiguration'; - -export class EventHooksManager { - private _rushConfiguration: RushConfiguration; - private _eventHooks: EventHooks; - private _commonTempFolder: string; - - public constructor(rushConfiguration: RushConfiguration) { - this._rushConfiguration = rushConfiguration; - this._eventHooks = rushConfiguration.eventHooks; - this._commonTempFolder = rushConfiguration.commonTempFolder; - } - - public handle(event: Event, isDebug: boolean): void { - if (!this._eventHooks) { - return; - } - - const scripts: string[] = this._eventHooks.get(event); - if (scripts.length > 0) { - const stopwatch: Stopwatch = Stopwatch.start(); - console.log(os.EOL + colors.green(`Executing event hooks for ${Event[event]}`)); - scripts.forEach((script) => { - try { - Utilities.executeLifecycleCommand( - script, - { - rushConfiguration: this._rushConfiguration, - workingDirectory: this._rushConfiguration.rushJsonFolder, - initCwd: this._commonTempFolder, - handleOutput: true, - environmentPathOptions: { - includeRepoBin: true - } - } - ); - } catch (error) { - console.error( - os.EOL + colors.yellow(`Event hook "${script}" failed. Run "rush" with --debug` + - ` to see detailed error information.`) - ); - if (isDebug) { - console.error(os.EOL + error.message); - } - } - }); - stopwatch.stop(); - console.log(os.EOL + colors.green(`Event hooks finished. (${stopwatch.toString()})`)); - } - } -} diff --git a/apps/rush-lib/src/logic/Git.ts b/apps/rush-lib/src/logic/Git.ts deleted file mode 100644 index 534d4e7dacd..00000000000 --- a/apps/rush-lib/src/logic/Git.ts +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import gitInfo = require('git-repo-info'); -import * as os from 'os'; -import * as path from 'path'; -import { Executable } from '@rushstack/node-core-library'; - -import { Utilities } from '../utilities/Utilities'; -import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; -import { GitEmailPolicy } from './policy/GitEmailPolicy'; -import { RushConfiguration } from '../api/RushConfiguration'; - -interface IResultOrError { - error?: Error; - result?: TResult; -} - -export class Git { - private static _checkedGitPath: boolean = false; - private static _gitPath: string | undefined; - private static _checkedGitInfo: boolean = false; - private static _gitInfo: gitInfo.GitRepoInfo | undefined; - - private static _gitEmailResult: IResultOrError | undefined = undefined; - - /** - * Returns the path to the Git binary if found. Otherwise, return undefined. - */ - public static getGitPath(): string | undefined { - if (!Git._checkedGitPath) { - Git._gitPath = Executable.tryResolve('git'); - Git._checkedGitPath = true; - } - - return Git._gitPath; - } - - /** - * Returns true if the Git binary can be found. - */ - public static isGitPresent(): boolean { - return !!Git.getGitPath(); - } - - /** - * Returns true if the Git binary was found and the current path is under a Git working tree. - * @param repoInfo - If provided, do the check based on this Git repo info. If not provided, - * the result of `Git.getGitInfo()` is used. - */ - public static isPathUnderGitWorkingTree(repoInfo?: gitInfo.GitRepoInfo): boolean { - if (Git.isGitPresent()) { // Do we even have a Git binary? - if (!repoInfo) { - repoInfo = Git.getGitInfo(); - } - return !!(repoInfo && repoInfo.sha); - } else { - return false; - } - } - - /** - * If a Git email address is configured and is nonempty, this returns it. - * Otherwise, undefined is returned. - */ - public static tryGetGitEmail(rushConfiguration: RushConfiguration): string | undefined { - const emailResult: IResultOrError = Git._tryGetGitEmail(); - if (emailResult.result !== undefined && emailResult.result.length > 0) { - return emailResult.result; - } - return undefined; - } - - /** - * If a Git email address is configured and is nonempty, this returns it. - * Otherwise, configuration instructions are printed to the console, - * and AlreadyReportedError is thrown. - */ - public static getGitEmail(rushConfiguration: RushConfiguration): string { - // Determine the user's account - // Ex: "bob@example.com" - const emailResult: IResultOrError = Git._tryGetGitEmail(); - if (emailResult.error) { - console.log( - [ - `Error: ${emailResult.error.message}`, - 'Unable to determine your Git configuration using this command:', - '', - ' git config user.email', - '' - ].join(os.EOL) - ); - throw new AlreadyReportedError(); - } - - if (emailResult.result === undefined || emailResult.result.length === 0) { - console.log([ - 'This operation requires that a Git email be specified.', - '', - `If you didn't configure your email yet, try something like this:`, - '', - ...GitEmailPolicy.getEmailExampleLines(rushConfiguration), - '' - ].join(os.EOL)); - throw new AlreadyReportedError(); - } - - return emailResult.result; - } - - /** - * Get the folder where Git hooks should go for the current working tree. - * Returns undefined if the current path is not under a Git working tree. - */ - public static getHooksFolder(): string | undefined { - const repoInfo: gitInfo.GitRepoInfo | undefined = Git.getGitInfo(); - if (repoInfo && repoInfo.worktreeGitDir) { - return path.join(repoInfo.worktreeGitDir, 'hooks'); - } - return undefined; - } - - /** - * Get information about the current Git working tree. - * Returns undefined if the current path is not under a Git working tree. - */ - public static getGitInfo(): Readonly | undefined { - if (!Git._checkedGitInfo) { - let repoInfo: gitInfo.GitRepoInfo | undefined; - try { - // gitInfo() shouldn't usually throw, but wrapping in a try/catch just in case - repoInfo = gitInfo(); - } catch (ex) { - // if there's an error, assume we're not in a Git working tree - } - - if (repoInfo && Git.isPathUnderGitWorkingTree(repoInfo)) { - Git._gitInfo = repoInfo; - } - Git._checkedGitInfo = true; - } - return Git._gitInfo; - } - - private static _tryGetGitEmail(): IResultOrError { - if (Git._gitEmailResult === undefined) { - if (!Git.isGitPresent()) { - Git._gitEmailResult = { - error: new Error('Git isn\'t present on the path') - }; - } else { - try { - Git._gitEmailResult = { - result: Utilities.executeCommandAndCaptureOutput( - 'git', - ['config', 'user.email'], - '.' - ).trim() - }; - } catch (e) { - Git._gitEmailResult = { - error: e - }; - } - } - } - - return Git._gitEmailResult; - } -} diff --git a/apps/rush-lib/src/logic/InstallManager.ts b/apps/rush-lib/src/logic/InstallManager.ts deleted file mode 100644 index 6e634b531f9..00000000000 --- a/apps/rush-lib/src/logic/InstallManager.ts +++ /dev/null @@ -1,1404 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/* eslint max-lines: off */ - -import * as glob from 'glob'; -import * as colors from 'colors'; -import * as fetch from 'node-fetch'; -import * as http from 'http'; -import HttpsProxyAgent = require('https-proxy-agent'); -import * as os from 'os'; -import * as path from 'path'; -import * as semver from 'semver'; -import * as tar from 'tar'; -import * as globEscape from 'glob-escape'; -import { - JsonFile, - LockFile, - Text, - IPackageJson, - MapExtensions, - FileSystem, - FileConstants, - Sort, - PosixModeBits, - JsonObject -} from '@rushstack/node-core-library'; - -import { ApprovedPackagesChecker } from '../logic/ApprovedPackagesChecker'; -import { AsyncRecycler } from '../utilities/AsyncRecycler'; -import { BaseLinkManager } from '../logic/base/BaseLinkManager'; -import { BaseShrinkwrapFile } from '../logic/base/BaseShrinkwrapFile'; -import { PolicyValidator } from '../logic/policy/PolicyValidator'; -import { IRushTempPackageJson } from '../logic/base/BasePackage'; -import { Git } from '../logic/Git'; -import { LastInstallFlag } from '../api/LastInstallFlag'; -import { LinkManagerFactory } from '../logic/LinkManagerFactory'; -import { PurgeManager } from './PurgeManager'; -import { RushConfiguration, ICurrentVariantJson, IConfigurationEnvironment } from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { RushConstants } from '../logic/RushConstants'; -import { ShrinkwrapFileFactory } from '../logic/ShrinkwrapFileFactory'; -import { Stopwatch } from '../utilities/Stopwatch'; -import { Utilities } from '../utilities/Utilities'; -import { Rush } from '../api/Rush'; -import { PackageJsonEditor, DependencyType, PackageJsonDependency } from '../api/PackageJsonEditor'; -import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; -import { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; - -// The PosixModeBits are intended to be used with bitwise operations. -/* eslint-disable no-bitwise */ - -/** - * The "noMtime" flag is new in tar@4.4.1 and not available yet for \@types/tar. - * As a temporary workaround, augment the type. - */ -import { CreateOptions } from 'tar'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; -import { PackageManagerName } from '../api/packageManager/PackageManager'; -import { PnpmPackageManager } from '../api/packageManager/PnpmPackageManager'; -import { DependencySpecifier } from './DependencySpecifier'; -import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; - -// eslint-disable-next-line @typescript-eslint/interface-name-prefix -export interface CreateOptions { - /** - * "Set to true to omit writing mtime values for entries. Note that this prevents using other - * mtime-based features like tar.update or the keepNewer option with the resulting tar archive." - */ - noMtime?: boolean; -} - -export interface IInstallManagerOptions { - /** - * Whether the global "--debug" flag was specified. - */ - debug: boolean; - /** - * Whether or not Rush will automatically update the shrinkwrap file. - * True for "rush update", false for "rush install". - */ - allowShrinkwrapUpdates: boolean; - /** - * Whether to skip policy checks. - */ - bypassPolicy: boolean; - /** - * Whether to skip linking, i.e. require "rush link" to be done manually later. - */ - noLink: boolean; - /** - * Whether to delete the shrinkwrap file before installation, i.e. so that all dependencies - * will be upgraded to the latest SemVer-compatible version. - */ - fullUpgrade: boolean; - /** - * Whether to force an update to the shrinkwrap file even if it appears to be unnecessary. - * Normally Rush uses heuristics to determine when "pnpm install" can be skipped, - * but sometimes the heuristics can be inaccurate due to external influences - * (pnpmfile.js script logic, registry changes, etc). - */ - recheckShrinkwrap: boolean; - - /** - * The value of the "--network-concurrency" command-line parameter, which - * is a diagnostic option used to troubleshoot network failures. - * - * Currently only supported for PNPM. - */ - networkConcurrency: number | undefined; - - /** - * Whether or not to collect verbose logs from the package manager. - * If specified when using PNPM, the logs will be in /common/temp/pnpm.log - */ - collectLogFile: boolean; - - /** - * The variant to consider when performing installations and validating shrinkwrap updates. - */ - variant?: string | undefined; - - /** - * Retry the install the specified number of times - */ - maxInstallAttempts: number -} - -/** - * This class implements common logic between "rush install" and "rush update". - */ -export class InstallManager { - private _rushConfiguration: RushConfiguration; - private _rushGlobalFolder: RushGlobalFolder; - private _commonNodeModulesMarker: LastInstallFlag; - private _commonTempFolderRecycler: AsyncRecycler; - - private _options: IInstallManagerOptions; - - public constructor( - rushConfiguration: RushConfiguration, - rushGlobalFolder: RushGlobalFolder, - purgeManager: PurgeManager, - options: IInstallManagerOptions - ) { - this._rushConfiguration = rushConfiguration; - this._rushGlobalFolder = rushGlobalFolder; - this._commonTempFolderRecycler = purgeManager.commonTempFolderRecycler; - this._options = options; - - const lastInstallState: JsonObject = { - node: process.versions.node, - packageManager: rushConfiguration.packageManager, - packageManagerVersion: rushConfiguration.packageManagerToolVersion - } - - if (lastInstallState.packageManager === 'pnpm') { - lastInstallState.storePath = rushConfiguration.pnpmOptions.pnpmStorePath; - } - - this._commonNodeModulesMarker = new LastInstallFlag(this._rushConfiguration.commonTempFolder, lastInstallState); - } - - /** - * Returns a map of all direct dependencies that only have a single semantic version specifier. - * Returns a map: dependency name --> version specifier - */ - public static collectImplicitlyPreferredVersions( - rushConfiguration: RushConfiguration, - options: { - variant?: string | undefined - } = {} - ): Map { - // First, collect all the direct dependencies of all local projects, and their versions: - // direct dependency name --> set of version specifiers - const versionsForDependencies: Map> = new Map>(); - - rushConfiguration.projects.forEach((project: RushConfigurationProject) => { - InstallManager._collectVersionsForDependencies( - rushConfiguration, - { - versionsForDependencies, - dependencies: project.packageJsonEditor.dependencyList, - cyclicDependencies: project.cyclicDependencyProjects, - variant: options.variant - }); - - InstallManager._collectVersionsForDependencies( - rushConfiguration, - { - versionsForDependencies, - dependencies: project.packageJsonEditor.devDependencyList, - cyclicDependencies: project.cyclicDependencyProjects, - variant: options.variant - }); - }); - - // If any dependency has more than one version, then filter it out (since we don't know which version - // should be preferred). What remains will be the list of preferred dependencies. - // dependency --> version specifier - const implicitlyPreferred: Map = new Map(); - versionsForDependencies.forEach((versions: Set, dep: string) => { - if (versions.size === 1) { - const version: string = versions.values().next().value; - implicitlyPreferred.set(dep, version); - } - }); - return implicitlyPreferred; - } - - // Helper for collectImplicitlyPreferredVersions() - private static _updateVersionsForDependencies(versionsForDependencies: Map>, - dependency: string, version: string): void { - if (!versionsForDependencies.has(dependency)) { - versionsForDependencies.set(dependency, new Set()); - } - versionsForDependencies.get(dependency)!.add(version); - } - - // Helper for collectImplicitlyPreferredVersions() - private static _collectVersionsForDependencies( - rushConfiguration: RushConfiguration, - options: { - versionsForDependencies: Map>; - dependencies: ReadonlyArray; - cyclicDependencies: Set; - variant: string | undefined; - }): void { - const { - variant, - dependencies, - versionsForDependencies, - cyclicDependencies - } = options; - - const commonVersions: CommonVersionsConfiguration = rushConfiguration.getCommonVersions(variant); - - const allowedAlternativeVersions: Map> - = commonVersions.allowedAlternativeVersions; - - for (const dependency of dependencies) { - const alternativesForThisDependency: ReadonlyArray - = allowedAlternativeVersions.get(dependency.name) || []; - - // For each dependency, collectImplicitlyPreferredVersions() is collecting the set of all version specifiers - // that appear across the repo. If there is only one version specifier, then that's the "preferred" one. - // However, there are a few cases where additional version specifiers can be safely ignored. - let ignoreVersion: boolean = false; - - // 1. If the version specifier was listed in "allowedAlternativeVersions", then it's never a candidate. - // (Even if it's the only version specifier anywhere in the repo, we still ignore it, because - // otherwise the rule would be difficult to explain.) - if (alternativesForThisDependency.indexOf(dependency.version) > 0) { - ignoreVersion = true; - } else { - // Is it a local project? - const localProject: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(dependency.name); - if (localProject) { - // 2. If it's a symlinked local project, then it's not a candidate, because the package manager will - // never even see it. - // However there are two ways that a local project can NOT be symlinked: - // - if the local project doesn't satisfy the referenced semver specifier; OR - // - if the local project was specified in "cyclicDependencyProjects" in rush.json - if (semver.satisfies(localProject.packageJsonEditor.version, dependency.version) - && !cyclicDependencies.has(dependency.name)) { - ignoreVersion = true; - } - } - - if (!ignoreVersion) { - InstallManager._updateVersionsForDependencies(versionsForDependencies, dependency.name, dependency.version); - } - } - } - } - - public get commonNodeModulesMarker(): LastInstallFlag { - return this._commonNodeModulesMarker; - } - - public async doInstall(): Promise { - const options: IInstallManagerOptions = this._options; - - // Check the policies - PolicyValidator.validatePolicy(this._rushConfiguration, options.bypassPolicy); - - // Git hooks are only installed if the repo opts in by including files in /common/git-hooks - const hookSource: string = path.join(this._rushConfiguration.commonFolder, 'git-hooks'); - const hookDestination: string | undefined = Git.getHooksFolder(); - - if (FileSystem.exists(hookSource) && hookDestination) { - const hookFilenames: string[] = FileSystem.readFolder(hookSource); - if (hookFilenames.length > 0) { - console.log(os.EOL + colors.bold('Found files in the "common/git-hooks" folder.')); - - // Clear the currently installed git hooks and install fresh copies - FileSystem.ensureEmptyFolder(hookDestination); - - // Only copy files that look like Git hook names - const filteredHookFilenames: string[] = hookFilenames.filter(x => /^[a-z\-]+/.test(x)); - for (const filename of filteredHookFilenames) { - FileSystem.copyFile({ - sourcePath: path.join(hookSource, filename), - destinationPath: path.join(hookDestination, filename) - }); - FileSystem.changePosixModeBits(path.join(hookDestination, filename), - PosixModeBits.UserRead | PosixModeBits.UserExecute); - } - - console.log('Successfully installed these Git hook scripts: ' + filteredHookFilenames.join(', ') + os.EOL); - } - } - - const approvedPackagesChecker: ApprovedPackagesChecker = new ApprovedPackagesChecker(this._rushConfiguration); - if (approvedPackagesChecker.approvedPackagesFilesAreOutOfDate) { - if (this._options.allowShrinkwrapUpdates) { - approvedPackagesChecker.rewriteConfigFiles(); - console.log(colors.yellow( - 'Approved package files have been updated. These updates should be committed to source control' - )); - } else { - throw new Error(`Approved packages files are out-of date. Run "rush update" to update them.`); - } - } - - // Ensure that the package manager is installed - await this.ensureLocalPackageManager(); - let shrinkwrapFile: BaseShrinkwrapFile | undefined = undefined; - - // (If it's a full update, then we ignore the shrinkwrap from Git since it will be overwritten) - if (!options.fullUpgrade) { - try { - shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile(this._rushConfiguration.packageManager, - this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant)); - } catch (ex) { - console.log(); - console.log(`Unable to load the ${this._shrinkwrapFilePhrase}: ${ex.message}`); - - if (!options.allowShrinkwrapUpdates) { - console.log(); - console.log(colors.red('You need to run "rush update" to fix this problem')); - throw new AlreadyReportedError(); - } - - shrinkwrapFile = undefined; - } - } - - // Write a file indicating which variant is being installed. - // This will be used by bulk scripts to determine the correct Shrinkwrap file to track. - const currentVariantJsonFilename: string = this._rushConfiguration.currentVariantJsonFilename; - const currentVariantJson: ICurrentVariantJson = { - variant: options.variant || null // eslint-disable-line @rushstack/no-null - }; - - // Determine if the variant is already current by updating current-variant.json. - // If nothing is written, the variant has not changed. - const variantIsUpToDate: boolean = !JsonFile.save(currentVariantJson, currentVariantJsonFilename, { - onlyIfChanged: true - }); - - if (options.variant) { - console.log(); - console.log(colors.bold(`Using variant '${options.variant}' for installation.`)); - } else if (!variantIsUpToDate && !options.variant) { - console.log(); - console.log(colors.bold('Using the default variant for installation.')); - } - - const shrinkwrapIsUpToDate: boolean = this._createTempModulesAndCheckShrinkwrap({ - shrinkwrapFile, - variant: options.variant - }) && !options.recheckShrinkwrap; - - if (!shrinkwrapIsUpToDate) { - if (!options.allowShrinkwrapUpdates) { - console.log(); - console.log(colors.red( - `The ${this._shrinkwrapFilePhrase} is out of date. You need to run "rush update".` - )); - throw new AlreadyReportedError(); - } - } - - await this._installCommonModules({ - shrinkwrapIsUpToDate, - variantIsUpToDate, - ...options - }); - - if (!options.noLink) { - const linkManager: BaseLinkManager = LinkManagerFactory.getLinkManager(this._rushConfiguration); - await linkManager.createSymlinksForProjects(false); - } else { - console.log( - os.EOL + colors.yellow('Since "--no-link" was specified, you will need to run "rush link" manually.') - ); - } - } - - /** - * If the "(p)npm-local" symlink hasn't been set up yet, this creates it, installing the - * specified (P)npm version in the user's home directory if needed. - */ - public ensureLocalPackageManager(): Promise { - // Example: "C:\Users\YourName\.rush" - const rushUserFolder: string = this._rushGlobalFolder.nodeSpecificPath; - - if (!FileSystem.exists(rushUserFolder)) { - console.log('Creating ' + rushUserFolder); - FileSystem.ensureFolder(rushUserFolder); - } - - const packageManager: PackageManagerName = this._rushConfiguration.packageManager; - const packageManagerVersion: string = this._rushConfiguration.packageManagerToolVersion; - - const packageManagerAndVersion: string = `${packageManager}-${packageManagerVersion}`; - // Example: "C:\Users\YourName\.rush\pnpm-1.2.3" - const packageManagerToolFolder: string = path.join(rushUserFolder, packageManagerAndVersion); - - const packageManagerMarker: LastInstallFlag = new LastInstallFlag(packageManagerToolFolder, { - node: process.versions.node - }); - - console.log(`Trying to acquire lock for ${packageManagerAndVersion}`); - return LockFile.acquire(rushUserFolder, packageManagerAndVersion).then((lock: LockFile) => { - console.log(`Acquired lock for ${packageManagerAndVersion}`); - - if (!packageManagerMarker.isValid() || lock.dirtyWhenAcquired) { - console.log(colors.bold(`Installing ${packageManager} version ${packageManagerVersion}${os.EOL}`)); - - // note that this will remove the last-install flag from the directory - Utilities.installPackageInDirectory({ - directory: packageManagerToolFolder, - packageName: packageManager, - version: this._rushConfiguration.packageManagerToolVersion, - tempPackageTitle: `${packageManager}-local-install`, - maxInstallAttempts: this._options.maxInstallAttempts, - // This is using a local configuration to install a package in a shared global location. - // Generally that's a bad practice, but in this case if we can successfully install - // the package at all, we can reasonably assume it's good for all the repositories. - // 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: this._rushConfiguration.commonRushConfigFolder - }); - - console.log(`Successfully installed ${packageManager} version ${packageManagerVersion}`); - } else { - console.log(`Found ${packageManager} version ${packageManagerVersion} in ${packageManagerToolFolder}`); - } - - packageManagerMarker.create(); - - // Example: "C:\MyRepo\common\temp" - FileSystem.ensureFolder(this._rushConfiguration.commonTempFolder); - - // Example: "C:\MyRepo\common\temp\pnpm-local" - const localPackageManagerToolFolder: string = - path.join(this._rushConfiguration.commonTempFolder, `${packageManager}-local`); - - console.log(os.EOL + 'Symlinking "' + localPackageManagerToolFolder + '"'); - console.log(' --> "' + packageManagerToolFolder + '"'); - - // 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); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - } - - FileSystem.createSymbolicLinkJunction({ - linkTargetPath: packageManagerToolFolder, - newLinkPath: localPackageManagerToolFolder - }); - - lock.release(); - }); - } - - /** - * Regenerates the common/package.json and all temp_modules projects. - * 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. - */ - private _createTempModulesAndCheckShrinkwrap(options: { - shrinkwrapFile: BaseShrinkwrapFile | undefined; - variant: string | undefined; - }): boolean { - const { - shrinkwrapFile, - variant - } = options; - - const stopwatch: Stopwatch = Stopwatch.start(); - - // Example: "C:\MyRepo\common\temp\projects" - const tempProjectsFolder: string = path.join(this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName); - - console.log(os.EOL + colors.bold('Updating temp projects in ' + tempProjectsFolder)); - - Utilities.createFolderWithRetry(tempProjectsFolder); - - const shrinkwrapWarnings: string[] = []; - - // We will start with the assumption that it's valid, and then set it to false if - // any of the checks fail - let shrinkwrapIsUpToDate: boolean = true; - - if (!shrinkwrapFile) { - shrinkwrapIsUpToDate = false; - } - - // dependency name --> version specifier - const allExplicitPreferredVersions: Map = this._rushConfiguration.getCommonVersions(variant) - .getAllPreferredVersions(); - - if (shrinkwrapFile) { - // Check any (explicitly) preferred dependencies first - allExplicitPreferredVersions.forEach((version: string, dependency: string) => { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependency, version); - - if (!shrinkwrapFile.hasCompatibleTopLevelDependency(dependencySpecifier)) { - shrinkwrapWarnings.push(`"${dependency}" (${version}) required by the preferred versions from ` - + RushConstants.commonVersionsFilename); - shrinkwrapIsUpToDate = false; - } - }); - - if (this._findOrphanedTempProjects(shrinkwrapFile)) { - // If there are any orphaned projects, then "npm install" would fail because the shrinkwrap - // contains references such as "resolved": "file:projects\\project1" that refer to nonexistent - // file paths. - shrinkwrapIsUpToDate = false; - } - } - - // Also copy down the committed .npmrc file, if there is one - // "common\config\rush\.npmrc" --> "common\temp\.npmrc" - // Also ensure that we remove any old one that may be hanging around - Utilities.syncNpmrc(this._rushConfiguration.commonRushConfigFolder, this._rushConfiguration.commonTempFolder); - - // also, copy the pnpmfile.js if it exists - if (this._rushConfiguration.packageManager === 'pnpm') { - const committedPnpmFilePath: string = - this._rushConfiguration.getPnpmfilePath(this._options.variant); - const tempPnpmFilePath: string - = path.join(this._rushConfiguration.commonTempFolder, RushConstants.pnpmfileFilename); - - // ensure that we remove any old one that may be hanging around - this._syncFile(committedPnpmFilePath, tempPnpmFilePath); - } - - const commonPackageJson: IPackageJson = { - dependencies: {}, - description: 'Temporary file generated by the Rush tool', - name: 'rush-common', - private: true, - version: '0.0.0' - }; - - // dependency name --> version specifier - const allPreferredVersions: Map = new Map(); - - // Should we add implicitly preferred versions? - let useImplicitlyPinnedVersions: boolean; - if (this._rushConfiguration.commonVersions.implicitlyPreferredVersions !== undefined) { - // Use the manually configured setting - useImplicitlyPinnedVersions = this._rushConfiguration.commonVersions.implicitlyPreferredVersions; - } else { - // Default to true. - useImplicitlyPinnedVersions = true; - } - - if (useImplicitlyPinnedVersions) { - // Add in the implicitly preferred versions. - // These are any first-level dependencies for which we only consume a single version range - // (e.g. every package that depends on react uses an identical specifier) - const implicitlyPreferredVersions: Map = - InstallManager.collectImplicitlyPreferredVersions(this._rushConfiguration, { variant }); - MapExtensions.mergeFromMap(allPreferredVersions, implicitlyPreferredVersions); - } - - // Add in the explicitly preferred versions. - // Note that these take precedence over implicitly preferred versions. - MapExtensions.mergeFromMap(allPreferredVersions, allExplicitPreferredVersions); - - // Add any preferred versions to the top of the commonPackageJson - // do this in alphabetical order for simpler debugging - for (const dependency of Array.from(allPreferredVersions.keys()).sort()) { - commonPackageJson.dependencies![dependency] = allPreferredVersions.get(dependency)!; - } - - // To make the common/package.json file more readable, sort alphabetically - // according to rushProject.tempProjectName instead of packageName. - const sortedRushProjects: RushConfigurationProject[] = this._rushConfiguration.projects.slice(0); - Sort.sortBy(sortedRushProjects, x => x.tempProjectName); - - for (const rushProject of sortedRushProjects) { - const packageJson: PackageJsonEditor = rushProject.packageJsonEditor; - - // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" - const tarballFile: string = this._getTarballFilePath(rushProject); - - // Example: "my-project-2" - const unscopedTempProjectName: string = rushProject.unscopedTempProjectName; - - // Example: dependencies["@rush-temp/my-project-2"] = "file:./projects/my-project-2.tgz" - commonPackageJson.dependencies![rushProject.tempProjectName] - = `file:./${RushConstants.rushTempProjectsFolderName}/${rushProject.unscopedTempProjectName}.tgz`; - - const tempPackageJson: IRushTempPackageJson = { - name: rushProject.tempProjectName, - version: '0.0.0', - private: true, - dependencies: {} - }; - - // Collect pairs of (packageName, packageVersion) to be added as dependencies of the @rush-temp package.json - const tempDependencies: Map = new Map(); - - // These can be regular, optional, or peer dependencies (but NOT dev dependencies). - // (A given packageName will never appear more than once in this list.) - for (const dependency of packageJson.dependencyList) { - - // If there are any optional dependencies, copy directly into the optionalDependencies field. - if (dependency.dependencyType === DependencyType.Optional) { - if (!tempPackageJson.optionalDependencies) { - tempPackageJson.optionalDependencies = {}; - } - tempPackageJson.optionalDependencies[dependency.name] = dependency.version; - } else { - tempDependencies.set(dependency.name, dependency.version); - } - } - - for (const dependency of packageJson.devDependencyList) { - // If there are devDependencies, we need to merge them with the regular dependencies. If the same - // library appears in both places, then the dev dependency wins (because presumably it's saying what you - // want right now for development, not the range that you support for consumers). - tempDependencies.set(dependency.name, dependency.version); - } - Sort.sortMapKeys(tempDependencies); - - for (const [packageName, packageVersion] of tempDependencies.entries()) { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(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. - // In this case, we don't want "npm install" to process this package, but we do need - // to record this decision for "rush link" later, so we add it to a special 'rushDependencies' field. - const localProject: RushConfigurationProject | undefined = - this._rushConfiguration.getProjectByName(packageName); - - if (localProject) { - // Don't locally link if it's listed in the cyclicDependencyProjects - if (!rushProject.cyclicDependencyProjects.has(packageName)) { - - // Also, don't locally link if the SemVer doesn't match - const localProjectVersion: string = localProject.packageJsonEditor.version; - if (semver.satisfies(localProjectVersion, packageVersion)) { - - // We will locally link this package, so instead add it to our special "rushDependencies" - // field in the package.json file. - if (!tempPackageJson.rushDependencies) { - tempPackageJson.rushDependencies = {}; - } - tempPackageJson.rushDependencies[packageName] = packageVersion; - continue; - } - } - } - - // We will NOT locally link this package; add it as a regular dependency. - tempPackageJson.dependencies![packageName] = packageVersion; - - if (shrinkwrapFile) { - if (!shrinkwrapFile.tryEnsureCompatibleDependency(dependencySpecifier, rushProject.tempProjectName)) { - shrinkwrapWarnings.push(`"${packageName}" (${packageVersion}) required by` - + ` "${rushProject.packageName}"`); - shrinkwrapIsUpToDate = false; - } - } - } - - // NPM expects the root of the tarball to have a directory called 'package' - const npmPackageFolder: string = 'package'; - - // Example: "C:\MyRepo\common\temp\projects\my-project-2" - const tempProjectFolder: string = path.join( - this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName, - unscopedTempProjectName); - - // Example: "C:\MyRepo\common\temp\projects\my-project-2\package.json" - const tempPackageJsonFilename: string = path.join(tempProjectFolder, FileConstants.PackageJson); - - // we only want to overwrite the package if the existing tarball's package.json is different from tempPackageJson - let shouldOverwrite: boolean = true; - try { - // if the tarball and the temp file still exist, then compare the contents - if (FileSystem.exists(tarballFile) && FileSystem.exists(tempPackageJsonFilename)) { - - // compare the extracted package.json with the one we are about to write - const oldBuffer: Buffer = FileSystem.readFileToBuffer(tempPackageJsonFilename); - const newBuffer: Buffer = Buffer.from(JsonFile.stringify(tempPackageJson)); - - if (Buffer.compare(oldBuffer, newBuffer) === 0) { - shouldOverwrite = false; - } - } - } catch (error) { - // ignore the error, we will go ahead and create a new tarball - } - - if (shouldOverwrite) { - try { - // ensure the folder we are about to zip exists - Utilities.createFolderWithRetry(tempProjectFolder); - - // remove the old tarball & old temp package json, this is for any cases where new tarball creation - // fails, and the shouldOverwrite logic is messed up because the my-project-2\package.json - // exists and is updated, but the tarball is not accurate - FileSystem.deleteFile(tarballFile); - FileSystem.deleteFile(tempPackageJsonFilename); - - // write the expected package.json file into the zip staging folder - JsonFile.save(tempPackageJson, tempPackageJsonFilename); - - // create the new tarball - tar.create({ - gzip: true, - file: tarballFile, - cwd: tempProjectFolder, - portable: true, - noMtime: true, - noPax: true, - sync: true, - prefix: npmPackageFolder - } as CreateOptions, [FileConstants.PackageJson]); - - console.log(`Updating ${tarballFile}`); - } catch (error) { - // delete everything in case of any error - FileSystem.deleteFile(tarballFile); - FileSystem.deleteFile(tempPackageJsonFilename); - } - } - } - - // Example: "C:\MyRepo\common\temp\package.json" - const commonPackageJsonFilename: string = path.join(this._rushConfiguration.commonTempFolder, - FileConstants.PackageJson); - - if (shrinkwrapFile) { - // If we have a (possibly incomplete) shrinkwrap file, save it as the temporary file. - shrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapFilename); - shrinkwrapFile.save(this._rushConfiguration.tempShrinkwrapPreinstallFilename); - } else { - // Otherwise delete the temporary file - FileSystem.deleteFile(this._rushConfiguration.tempShrinkwrapFilename); - - if (this._rushConfiguration.packageManager === 'pnpm') { - // Workaround for https://github.com/pnpm/pnpm/issues/1890 - // - // When "rush update --full" is run, rush deletes common/temp/pnpm-lock.yaml so that - // a new lockfile can be generated. But because of the above bug "pnpm install" would - // respect "common/temp/node_modules/.pnpm-lock.yaml" and thus would not generate a - // new lockfile. Deleting this file in addition to deleting common/temp/pnpm-lock.yaml - // ensures that a new lockfile will be generated with "rush update --full". - - const pnpmPackageManager: PnpmPackageManager = - (this._rushConfiguration.packageManagerWrapper as PnpmPackageManager); - - FileSystem.deleteFile(path.join(this._rushConfiguration.commonTempFolder, - pnpmPackageManager.internalShrinkwrapRelativePath)); - } - } - - // Don't update the file timestamp unless the content has changed, since "rush install" - // will consider this timestamp - JsonFile.save(commonPackageJson, commonPackageJsonFilename, { onlyIfChanged: true }); - - stopwatch.stop(); - console.log(`Finished creating temporary modules (${stopwatch.toString()})`); - - if (shrinkwrapWarnings.length > 0) { - console.log(); - console.log(colors.yellow(Utilities.wrapWords( - `The ${this._shrinkwrapFilePhrase} is missing the following dependencies:`))); - - for (const shrinkwrapWarning of shrinkwrapWarnings) { - console.log(colors.yellow(' ' + shrinkwrapWarning)); - } - console.log(); - } - - return shrinkwrapIsUpToDate; - } - - /** - * Runs "npm install" in the common folder. - */ - private _installCommonModules(options: { - shrinkwrapIsUpToDate: boolean; - variantIsUpToDate: boolean; - } & IInstallManagerOptions): Promise { - const { - shrinkwrapIsUpToDate, - variantIsUpToDate - } = options; - - return Promise.resolve().then(() => { - console.log(os.EOL + colors.bold('Checking node_modules in ' + this._rushConfiguration.commonTempFolder) - + os.EOL); - - const commonNodeModulesFolder: string = path.join(this._rushConfiguration.commonTempFolder, - 'node_modules'); - - // This marker file indicates that the last "rush install" completed successfully - const markerFileExistedAndWasValidAtStart: boolean = this._commonNodeModulesMarker.checkValidAndReportStoreIssues(); - - // If "--clean" or "--full-clean" was specified, or if the last install was interrupted, - // then we will need to delete the node_modules folder. Otherwise, we can do an incremental - // install. - const deleteNodeModules: boolean = !markerFileExistedAndWasValidAtStart; - - // Based on timestamps, can we skip this install entirely? - if (shrinkwrapIsUpToDate && !deleteNodeModules && variantIsUpToDate) { - const potentiallyChangedFiles: string[] = []; - - // Consider the timestamp on the node_modules folder; if someone tampered with it - // or deleted it entirely, then we can't skip this install - potentiallyChangedFiles.push(commonNodeModulesFolder); - - // Additionally, if they pulled an updated npm-shrinkwrap.json file from Git, - // then we can't skip this install - potentiallyChangedFiles.push(this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant)); - - if (this._rushConfiguration.packageManager === 'pnpm') { - // If the repo is using pnpmfile.js, consider that also - const pnpmFileFilename: string = this._rushConfiguration.getPnpmfilePath(options.variant); - - if (FileSystem.exists(pnpmFileFilename)) { - potentiallyChangedFiles.push(pnpmFileFilename); - } - } - - // Also consider timestamps for all the temp tarballs. (createTempModulesAndCheckShrinkwrap() will - // carefully preserve these timestamps unless something has changed.) - // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" - potentiallyChangedFiles.push(...this._rushConfiguration.projects.map(x => { - return this._getTarballFilePath(x); - })); - - // NOTE: If commonNodeModulesMarkerFilename (or any of the potentiallyChangedFiles) does not - // exist, then isFileTimestampCurrent() returns false. - if (Utilities.isFileTimestampCurrent(this._commonNodeModulesMarker.path, potentiallyChangedFiles)) { - // Nothing to do, because everything is up to date according to time stamps - return; - } - } - - return this._checkIfReleaseIsPublished() - .catch((error) => { - // If the user is working in an environment that can't reach the registry, - // don't bother them with errors. - return undefined; - }).then((publishedRelease: boolean | undefined) => { - - if (publishedRelease === false) { - console.log(colors.yellow('Warning: This release of the Rush tool was unpublished; it may be unstable.')); - } - - // Since we're going to be tampering with common/node_modules, delete the "rush link" flag file if it exists; - // this ensures that a full "rush link" is required next time - Utilities.deleteFile(this._rushConfiguration.rushLinkJsonFilename); - - // Delete the successful install file to indicate the install transaction has started - this._commonNodeModulesMarker.clear(); - - // NOTE: The PNPM store is supposed to be transactionally safe, so we don't delete it automatically. - // The user must request that via the command line. - if (deleteNodeModules) { - if (this._rushConfiguration.packageManager === 'npm') { - console.log(`Deleting the "npm-cache" folder`); - // This is faster and more thorough than "npm cache clean" - this._commonTempFolderRecycler.moveFolder(this._rushConfiguration.npmCacheFolder); - - console.log(`Deleting the "npm-tmp" folder`); - this._commonTempFolderRecycler.moveFolder(this._rushConfiguration.npmTmpFolder); - } - } - - // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" - const packageManagerFilename: string = this._rushConfiguration.packageManagerToolFilename; - - let packageManagerEnv: NodeJS.ProcessEnv = process.env; - - let configurationEnvironment: IConfigurationEnvironment | undefined = undefined; - - if (this._rushConfiguration.packageManager === 'npm') { - if ( - this._rushConfiguration.npmOptions && - this._rushConfiguration.npmOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.npmOptions.environmentVariables; - } - } else if (this._rushConfiguration.packageManager === 'pnpm') { - if ( - this._rushConfiguration.pnpmOptions && - this._rushConfiguration.pnpmOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.pnpmOptions.environmentVariables; - } - } else if (this._rushConfiguration.packageManager === 'yarn') { - if ( - this._rushConfiguration.yarnOptions && - this._rushConfiguration.yarnOptions.environmentVariables - ) { - configurationEnvironment = this._rushConfiguration.yarnOptions.environmentVariables; - } - } - - packageManagerEnv = this._mergeEnvironmentVariables( - process.env, - configurationEnvironment - ); - - // Is there an existing "node_modules" folder to consider? - if (FileSystem.exists(commonNodeModulesFolder)) { - // Should we delete the entire "node_modules" folder? - if (deleteNodeModules) { - // YES: Delete "node_modules" - - // Explain to the user why we are hosing their node_modules folder - console.log('Deleting files from ' + commonNodeModulesFolder); - - this._commonTempFolderRecycler.moveFolder(commonNodeModulesFolder); - - Utilities.createFolderWithRetry(commonNodeModulesFolder); - } else { - // NO: Prepare to do an incremental install in the "node_modules" folder - - // note: it is not necessary to run "prune" with pnpm - if (this._rushConfiguration.packageManager === 'npm') { - console.log(`Running "${this._rushConfiguration.packageManager} prune"` - + ` in ${this._rushConfiguration.commonTempFolder}`); - const args: string[] = ['prune']; - this._pushConfigurationArgs(args, options); - - Utilities.executeCommandWithRetry(this._options.maxInstallAttempts, packageManagerFilename, args, - this._rushConfiguration.commonTempFolder, packageManagerEnv); - - // Delete the (installed image of) the temp projects, since "npm install" does not - // detect changes for "file:./" references. - // We recognize the temp projects by their names, which always start with "rush-". - - // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp" - const pathToDeleteWithoutStar: string = path.join(commonNodeModulesFolder, - RushConstants.rushTempNpmScope); - console.log(`Deleting ${pathToDeleteWithoutStar}\\*`); - // Glob can't handle Windows paths - const normalizedpathToDeleteWithoutStar: string = Text.replaceAll(pathToDeleteWithoutStar, '\\', '/'); - - // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*" - for (const tempModulePath of glob.sync(globEscape(normalizedpathToDeleteWithoutStar) + '/*')) { - // We could potentially use AsyncRecycler here, but in practice these folders tend - // to be very small - Utilities.dangerouslyDeletePath(tempModulePath); - } - } - } - } - - if (this._rushConfiguration.packageManager === 'yarn') { - // Yarn does not correctly detect changes to a tarball, so we need to forcibly clear its cache - const yarnRushTempCacheFolder: string = path.join( - this._rushConfiguration.yarnCacheFolder, 'v2', 'npm-@rush-temp' - ); - if (FileSystem.exists(yarnRushTempCacheFolder)) { - console.log('Deleting ' + yarnRushTempCacheFolder); - Utilities.dangerouslyDeletePath(yarnRushTempCacheFolder); - } - } - - // Run "npm install" in the common folder - const installArgs: string[] = ['install']; - this._pushConfigurationArgs(installArgs, options); - - console.log(os.EOL + colors.bold(`Running "${this._rushConfiguration.packageManager} install" in` - + ` ${this._rushConfiguration.commonTempFolder}`) + os.EOL); - - // If any diagnostic options were specified, then show the full command-line - if (options.debug || options.collectLogFile || options.networkConcurrency) { - console.log(os.EOL + colors.green('Invoking package manager: ') - + FileSystem.getRealPath(packageManagerFilename) + ' ' + installArgs.join(' ') + os.EOL); - } - - try { - Utilities.executeCommandWithRetry(this._options.maxInstallAttempts, packageManagerFilename, - installArgs, - this._rushConfiguration.commonTempFolder, - packageManagerEnv, - false, () => { - if (this._rushConfiguration.packageManager === 'pnpm') { - console.log(colors.yellow(`Deleting the "node_modules" folder`)); - this._commonTempFolderRecycler.moveFolder(commonNodeModulesFolder); - - // Leave the pnpm-store as is for the retry. This ensures that packages that have already - // been downloaded need not be downloaded again, thereby potentially increasing the chances - // of a subsequent successful install. - - Utilities.createFolderWithRetry(commonNodeModulesFolder); - } - }); - } catch (error) { - // All the install attempts failed. - - if ( - this._rushConfiguration.packageManager === 'pnpm' && - this._rushConfiguration.pnpmOptions.pnpmStore === 'local' - ) { - // If the installation has failed even after the retries, then pnpm store may - // have got into a corrupted, irrecoverable state. Delete the store so that a - // future install can create the store afresh. - console.log(colors.yellow(`Deleting the "pnpm-store" folder`)); - this._commonTempFolderRecycler.moveFolder(this._rushConfiguration.pnpmOptions.pnpmStorePath); - } - - throw error; - } - - if (this._rushConfiguration.packageManager === 'npm') { - - console.log(os.EOL + colors.bold('Running "npm shrinkwrap"...')); - const npmArgs: string[] = ['shrinkwrap']; - this._pushConfigurationArgs(npmArgs, options); - Utilities.executeCommand(this._rushConfiguration.packageManagerToolFilename, - npmArgs, this._rushConfiguration.commonTempFolder); - console.log('"npm shrinkwrap" completed' + os.EOL); - - this._fixupNpm5Regression(); - } - - if (options.allowShrinkwrapUpdates && !shrinkwrapIsUpToDate) { - // Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml - this._syncFile(this._rushConfiguration.tempShrinkwrapFilename, - this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant)); - } else { - // TODO: Validate whether the package manager updated it in a nontrivial way - } - - // Finally, create the marker file to indicate a successful install - this._commonNodeModulesMarker.create(); - - console.log(''); - }); - }); - } - - private _mergeEnvironmentVariables( - baseEnv: NodeJS.ProcessEnv, - environmentVariables?: IConfigurationEnvironment - ): 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; - console.log(`\nProcessing definition for environment variable: ${envVar}`); - - if (baseEnv.hasOwnProperty(envVar)) { - setEnvironmentVariable = false; - console.log(`Environment variable already defined:`); - console.log(` Name: ${envVar}`); - console.log(` Existing value: ${baseEnv[envVar]}`); - console.log(` Value set in rush.json: ${environmentVariables[envVar].value}`); - - if (environmentVariables[envVar].override) { - setEnvironmentVariable = true; - console.log(`Overriding the environment variable with the value set in rush.json.`); - } - else { - console.log(colors.yellow(`WARNING: Not overriding the value of the environment variable.`)); - } - } - - if (setEnvironmentVariable) { - if (this._options.debug) { - console.log(`Setting environment variable for package manager.`); - console.log(` Name: ${envVar}`); - console.log(` Value: ${environmentVariables[envVar].value}`); - } - packageManagerEnv[envVar] = environmentVariables[envVar].value; - } - } - } - - return packageManagerEnv; - } - - private _checkIfReleaseIsPublished(): Promise { - return Promise.resolve().then(() => { - const lastCheckFile: string = path.join(this._rushGlobalFolder.nodeSpecificPath, - 'rush-' + Rush.version, 'last-check.flag'); - - if (FileSystem.exists(lastCheckFile)) { - let cachedResult: boolean | 'error' | undefined = undefined; - try { - // NOTE: mtimeMs is not supported yet in Node.js 6.x - const nowMs: number = new Date().getTime(); - const ageMs: number = nowMs - FileSystem.getStatistics(lastCheckFile).mtime.getTime(); - const HOUR: number = 60 * 60 * 1000; - - // Is the cache too old? - if (ageMs < 24 * HOUR) { - // No, read the cached result - cachedResult = JsonFile.load(lastCheckFile); - } - } catch (e) { - // Unable to parse file - } - if (cachedResult === 'error') { - return Promise.reject(new Error('Unable to contact server')); - } - if (cachedResult === true || cachedResult === false) { - return cachedResult; - } - } - - // Before we start the network operation, record a failed state. If the process exits for some reason, - // this will record the error. It will also update the timestamp to prevent other Rush instances - // from attempting to update the file. - JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); - - // For this check we use the official registry, not the private registry - return this._queryIfReleaseIsPublished('https://registry.npmjs.org:443') - .then((publishedRelease: boolean) => { - // Cache the result - JsonFile.save(publishedRelease, lastCheckFile, { ensureFolderExists: true }); - return publishedRelease; - }) - .catch((error: Error) => { - JsonFile.save('error', lastCheckFile, { ensureFolderExists: true }); - return Promise.reject(error); - }); - }); - } - - private _queryIfReleaseIsPublished(registryUrl: string): Promise { - let queryUrl: string = registryUrl; - if (queryUrl[-1] !== '/') { - queryUrl += '/'; - } - // Note that the "@" symbol does not normally get URL-encoded - queryUrl += RushConstants.rushPackageName.replace('/', '%2F'); - - const userAgent: string = `pnpm/? npm/? node/${process.version} ${os.platform()} ${os.arch()}`; - - const headers: fetch.Headers = new fetch.Headers(); - headers.append('user-agent', userAgent); - headers.append('accept', 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'); - - let agent: http.Agent | undefined = undefined; - if (process.env.HTTP_PROXY) { - agent = new HttpsProxyAgent(process.env.HTTP_PROXY); - } - - return fetch.default(queryUrl, { - headers: headers, - agent: agent - }) - .then((response: fetch.Response) => { - if (!response.ok) { - return Promise.reject(new Error('Failed to query')); - } - return response - .json() - .then((data) => { - let url: string; - try { - if (!data.versions[Rush.version]) { - // Version was not published - return false; - } - url = data.versions[Rush.version].dist.tarball; - if (!url) { - return Promise.reject(new Error(`URL not found`)); - } - } catch (e) { - return Promise.reject(new Error('Error parsing response')); - } - - // Make sure the tarball wasn't deleted from the CDN - headers.set('accept', '*/*'); - return fetch.default(url, { - headers: headers, - agent: agent - }) - .then((response2: fetch.Response) => { - if (!response2.ok) { - if (response2.status === 404) { - return false; - } else { - return Promise.reject(new Error('Failed to fetch')); - } - } - return true; - }); - }); - }); - } - - /** - * Used when invoking the NPM tool. Appends the common configuration options - * to the command-line. - */ - private _pushConfigurationArgs(args: string[], options: IInstallManagerOptions): void { - if (this._rushConfiguration.packageManager === 'npm') { - if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '5.0.0')) { - // NOTE: - // - // When using an npm version older than v5.0.0, we do NOT install optional dependencies for - // Rush, because npm does not generate the shrinkwrap file consistently across platforms. - // - // Consider the "fsevents" package. This is a Mac specific package - // which is an optional second-order dependency. Optional dependencies work by attempting to install - // the package, but removes the package if the install failed. - // This means that someone running generate on a Mac WILL have fsevents included in their shrinkwrap. - // When someone using Windows attempts to install from the shrinkwrap, the install will fail. - // - // If someone generates the shrinkwrap using Windows, then fsevents will NOT be listed in the shrinkwrap. - // When someone using Mac attempts to install from the shrinkwrap, they will NOT have the - // optional dependency installed. - // - // This issue has been fixed as of npm v5.0.0: https://github.com/npm/npm/releases/tag/v5.0.0 - // - // For more context, see https://github.com/microsoft/rushstack/issues/761#issuecomment-428689600 - args.push('--no-optional'); - } - args.push('--cache', this._rushConfiguration.npmCacheFolder); - args.push('--tmp', this._rushConfiguration.npmTmpFolder); - - if (options.collectLogFile) { - args.push('--verbose'); - } - } else if (this._rushConfiguration.packageManager === 'pnpm') { - // Only explicitly define the store path if `pnpmStore` is using the default, or has been set to - // 'local'. If `pnpmStore` = 'global', then allow PNPM to use the system's default - // path. In all cases, this will be overridden by RUSH_PNPM_STORE_PATH - if ( - this._rushConfiguration.pnpmOptions.pnpmStore === 'local' || - EnvironmentConfiguration.pnpmStorePathOverride - ) { - args.push('--store', this._rushConfiguration.pnpmOptions.pnpmStorePath); - } - - // we are using the --no-lock flag for now, which unfortunately prints a warning, but should be OK - // since rush already has its own install lock file which will invalidate the cache for us. - // we theoretically could use the lock file, but we would need to clean the store if the - // lockfile existed, otherwise PNPM would hang indefinitely. it is simpler to rely on Rush's - // last install flag, which encapsulates the entire installation - args.push('--no-lock'); - - // Ensure that Rush's tarball dependencies get synchronized properly with the pnpm-lock.yaml file. - // See this GitHub issue: https://github.com/pnpm/pnpm/issues/1342 - if (semver.gte(this._rushConfiguration.packageManagerToolVersion, '3.0.0')) { - args.push('--no-prefer-frozen-lockfile'); - } else { - args.push('--no-prefer-frozen-shrinkwrap'); - } - - if (options.collectLogFile) { - args.push('--reporter', 'ndjson'); - } - - if (options.networkConcurrency) { - args.push('--network-concurrency', options.networkConcurrency.toString()); - } - - if (this._rushConfiguration.pnpmOptions.strictPeerDependencies) { - args.push('--strict-peer-dependencies'); - } - - if ((this._rushConfiguration.packageManagerWrapper as PnpmPackageManager).supportsResolutionStrategy) { - args.push('--resolution-strategy', this._rushConfiguration.pnpmOptions.resolutionStrategy); - } - } else if (this._rushConfiguration.packageManager === 'yarn') { - args.push('--link-folder', 'yarn-link'); - args.push('--cache-folder', this._rushConfiguration.yarnCacheFolder); - - // Without this option, Yarn will sometimes stop and ask for user input on STDIN - // (e.g. "Which command would you like to run?"). - args.push('--non-interactive'); - - if (options.networkConcurrency) { - args.push('--network-concurrency', options.networkConcurrency.toString()); - } - - if (this._rushConfiguration.yarnOptions.ignoreEngines) { - args.push('--ignore-engines'); - } - } - } - - /** - * Copies the file "sourcePath" to "destinationPath", overwriting the target file location. - * If the source file does not exist, then the target file is deleted. - */ - private _syncFile(sourcePath: string, destinationPath: string): void { - if (FileSystem.exists(sourcePath)) { - console.log('Updating ' + destinationPath); - FileSystem.copyFile({ sourcePath, destinationPath }); - } else { - if (FileSystem.exists(destinationPath)) { - console.log('Deleting ' + destinationPath); - FileSystem.deleteFile(destinationPath); - } - } - } - - /** - * Gets the path to the tarball - * Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" - */ - private _getTarballFilePath(project: RushConfigurationProject): string { - return path.join( - this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName, - `${project.unscopedTempProjectName}.tgz`); - } - - /** - * This is a workaround for a bug introduced in NPM 5 (and still unfixed as of NPM 5.5.1): - * https://github.com/npm/npm/issues/19006 - * - * The regression is that "npm install" sets the package.json "version" field for the - * @rush-temp projects to a value like "file:projects/example.tgz", when it should be "0.0.0". - * This causes "rush link" to fail later, when read-package-tree tries to parse the bad version. - * The error looks like this: - * - * ERROR: Failed to parse package.json for foo: Invalid version: "file:projects/example.tgz" - * - * Our workaround is to rewrite the package.json files for each of the @rush-temp projects - * in the node_modules folder, after "npm install" completes. - */ - private _fixupNpm5Regression(): void { - const pathToDeleteWithoutStar: string = path.join(this._rushConfiguration.commonTempFolder, - 'node_modules', RushConstants.rushTempNpmScope); - // Glob can't handle Windows paths - const normalizedpathToDeleteWithoutStar: string = Text.replaceAll(pathToDeleteWithoutStar, '\\', '/'); - - let anyChanges: boolean = false; - - // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*/package.json" - for (const packageJsonPath of glob.sync(globEscape(normalizedpathToDeleteWithoutStar) + '/*/package.json')) { - // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/example/package.json" - const packageJsonObject: IRushTempPackageJson = JsonFile.load(packageJsonPath); - - // The temp projects always use "0.0.0" as their version - packageJsonObject.version = '0.0.0'; - - if (JsonFile.save(packageJsonObject, packageJsonPath, { onlyIfChanged: true })) { - anyChanges = true; - } - } - - if (anyChanges) { - console.log(os.EOL + colors.yellow(Utilities.wrapWords(`Applied workaround for NPM 5 bug`)) + os.EOL); - } - } - - /** - * Checks for temp projects that exist in the shrinkwrap file, but don't exist - * in rush.json. This might occur, e.g. if a project was recently deleted or renamed. - * - * @returns true if orphans were found, or false if everything is okay - */ - private _findOrphanedTempProjects(shrinkwrapFile: BaseShrinkwrapFile): boolean { - - // We can recognize temp projects because they are under the "@rush-temp" NPM scope. - for (const tempProjectName of shrinkwrapFile.getTempProjectNames()) { - if (!this._rushConfiguration.findProjectByTempName(tempProjectName)) { - console.log(os.EOL + colors.yellow(Utilities.wrapWords( - `Your ${this._shrinkwrapFilePhrase} references a project "${tempProjectName}" which no longer exists.`)) - + os.EOL); - return true; // found one - } - } - - return false; // none found - } - - private get _shrinkwrapFilePhrase(): string { - return this._rushConfiguration.shrinkwrapFilePhrase; - } -} diff --git a/apps/rush-lib/src/logic/JsonSchemaUrls.ts b/apps/rush-lib/src/logic/JsonSchemaUrls.ts deleted file mode 100644 index 7912aaf74cb..00000000000 --- a/apps/rush-lib/src/logic/JsonSchemaUrls.ts +++ /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. - -/** - * JSON schema URLs that Rush writes into config files. - */ -export class JsonSchemaUrls { - public static readonly approvedPackages: string - = 'https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json'; - - public static readonly commonVersions: string - = 'https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json'; -} diff --git a/apps/rush-lib/src/logic/LinkManagerFactory.ts b/apps/rush-lib/src/logic/LinkManagerFactory.ts deleted file mode 100644 index 3118653d9b0..00000000000 --- a/apps/rush-lib/src/logic/LinkManagerFactory.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { RushConfiguration } from '../api/RushConfiguration'; -import { BaseLinkManager } from './base/BaseLinkManager'; -import { NpmLinkManager } from './npm/NpmLinkManager'; -import { PnpmLinkManager } from './pnpm/PnpmLinkManager'; - -export class LinkManagerFactory { - public static getLinkManager( - rushConfiguration: RushConfiguration - ): BaseLinkManager { - - switch (rushConfiguration.packageManager) { - case 'npm': - return new NpmLinkManager(rushConfiguration); - case 'pnpm': - return new PnpmLinkManager(rushConfiguration); - case 'yarn': - // Yarn uses the same node_modules structure as NPM - return new NpmLinkManager(rushConfiguration); - } - - throw new Error(`Unsupported package manager: ${rushConfiguration.packageManager}`); - } -} diff --git a/apps/rush-lib/src/logic/NodeJsCompatibility.ts b/apps/rush-lib/src/logic/NodeJsCompatibility.ts deleted file mode 100644 index d060df61915..00000000000 --- a/apps/rush-lib/src/logic/NodeJsCompatibility.ts +++ /dev/null @@ -1,117 +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 colors from 'colors'; -import * as semver from 'semver'; - -import { RushConfiguration } from '../api/RushConfiguration'; - -/** - * This constant is the major version of the next LTS node Node.js release. This constant should be updated when - * a new LTS version is added to Rush's support matrix. - */ -const UPCOMING_NODE_LTS_VERSION: number = 12; -const nodeVersion: string = process.versions.node; -const nodeMajorVersion: number = semver.major(nodeVersion); - -export interface IWarnAboutVersionTooNewOptions { - isRushLib: boolean; - alreadyReportedNodeTooNewError: boolean; -} - -export interface IWarnAboutCompatibilityIssuesOptions extends IWarnAboutVersionTooNewOptions { - rushConfiguration: RushConfiguration | undefined; -} - -/** - * This class provides useful functions for warning if the current Node.js runtime isn't supported. - * - * @internal - */ -export class NodeJsCompatibility { - public static warnAboutCompatibilityIssues(options: IWarnAboutCompatibilityIssuesOptions): boolean { - // Only show the first warning - return ( - NodeJsCompatibility.warnAboutVersionTooOld() || - NodeJsCompatibility.warnAboutVersionTooNew(options) || - NodeJsCompatibility.warnAboutOddNumberedVersion() || - NodeJsCompatibility.warnAboutNonLtsVersion(options.rushConfiguration) - ); - } - - public static warnAboutVersionTooOld(): boolean { - if (semver.satisfies(nodeVersion, '< 8.9.0')) { - // We are on an ancient version of Node.js that is known not to work with Rush - console.error(colors.red( - `Your version of Node.js (${nodeVersion}) is very old and incompatible with Rush. ` + - `Please upgrade to the latest Long-Term Support (LTS) version.` - )); - - return true; - } else { - return false; - } - } - - public static warnAboutVersionTooNew(options: IWarnAboutVersionTooNewOptions): boolean { - if (!options.alreadyReportedNodeTooNewError && nodeMajorVersion >= (UPCOMING_NODE_LTS_VERSION + 1)) { - // We are on a much newer release than we have tested and support - if (options.isRushLib) { - console.warn(colors.yellow( - `Your version of Node.js (${nodeVersion}) has not been tested with this release ` + - `of the Rush engine. Please consider upgrading the "rushVersion" setting in rush.json, ` + - `or downgrading Node.js.` - )); - } else { - console.warn(colors.yellow( - `Your version of Node.js (${nodeVersion}) has not been tested with this release ` + - `of Rush. Please consider installing a newer version of the "@microsoft/rush" ` + - `package, or downgrading Node.js.` - )); - } - - return true; - } else { - return false; - } - } - - public static warnAboutNonLtsVersion(rushConfiguration: RushConfiguration | undefined): boolean { - if ( - rushConfiguration && - !rushConfiguration.suppressNodeLtsWarning && - !NodeJsCompatibility.isLtsVersion - ) { - console.warn(colors.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.' - )); - - return true; - } else { - return false; - } - } - - public static warnAboutOddNumberedVersion(): boolean { - if (NodeJsCompatibility.isOddNumberedVersion) { - console.warn(colors.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.` - )); - - return true; - } else { - return false; - } - } - - public static get isLtsVersion(): boolean { - return !!process.release.lts; - } - - public static get isOddNumberedVersion(): boolean { - return (nodeMajorVersion % 2) !== 0; - } -} diff --git a/apps/rush-lib/src/logic/PackageChangeAnalyzer.ts b/apps/rush-lib/src/logic/PackageChangeAnalyzer.ts deleted file mode 100644 index 377038c1e1c..00000000000 --- a/apps/rush-lib/src/logic/PackageChangeAnalyzer.ts +++ /dev/null @@ -1,208 +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 colors from 'colors'; - -import { - getPackageDeps, - getGitHashForFiles, - IPackageDeps -} from '@rushstack/package-deps-hash'; -import { - Path, - InternalError, - FileSystem -} from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { Git } from './Git'; -import { PnpmProjectDependencyManifest } from './pnpm/PnpmProjectDependencyManifest'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; - -export class PackageChangeAnalyzer { - // Allow this function to be overwritten during unit tests - public static getPackageDeps: (path: string, ignoredFiles: string[]) => IPackageDeps; - - private _data: Map; - private _rushConfiguration: RushConfiguration; - private _isGitSupported: boolean; - - public constructor(rushConfiguration: RushConfiguration) { - this._rushConfiguration = rushConfiguration; - this._isGitSupported = Git.isPathUnderGitWorkingTree(); - this._data = this._getData(); - } - - public getPackageDepsHash(projectName: string): IPackageDeps | undefined { - if (!this._data) { - this._data = this._getData(); - } - - return this._data.get(projectName); - } - - private _getData(): Map { - // If we are not in a unit test, use the correct resources - if (!PackageChangeAnalyzer.getPackageDeps) { - PackageChangeAnalyzer.getPackageDeps = getPackageDeps; - } - - const projectHashDeps: Map = new Map(); - - // pre-populate the map with the projects from the config - for (const project of this._rushConfiguration.projects) { - projectHashDeps.set(project.packageName, { - files: {} - }); - } - - const noProjectHashes: { [key: string]: string } = {}; - - let repoDeps: IPackageDeps; - try { - if (this._isGitSupported) { - // Load the package deps hash for the whole repository - repoDeps = PackageChangeAnalyzer.getPackageDeps(this._rushConfiguration.rushJsonFolder, []); - } else { - return projectHashDeps; - } - } catch (e) { - // If getPackageDeps fails, don't fail the whole build. Treat this case as if we don't know anything about - // the state of the files in the repo. This can happen if the environment doesn't have Git. - console.log(colors.yellow( - `Error calculating the state of the repo. (inner error: ${e}). Continuing without diffing files.` - )); - - return projectHashDeps; - } - - // Sort each project folder into its own package deps hash - Object.keys(repoDeps.files).forEach((filePath: string) => { - const fileHash: string = repoDeps.files[filePath]; - - const projectName: string | undefined = this._getProjectForFile(filePath); - - // If we found a project for the file, go ahead and store this file's hash - if (projectName) { - projectHashDeps.get(projectName)!.files[filePath] = fileHash; - } else { - noProjectHashes[filePath] = fileHash; - } - }); - - /* Incremental Build notes: - * - * Temporarily revert below code in favor of replacing this solution with something more - * flexible. Idea is essentially that we should have gulp-core-build (or other build tool) - * create the package-deps_.json. The build tool would default to using the 'simple' - * algorithm (e.g. only files that are in a project folder are associated with the project), however it would - * also provide a hook which would allow certain tasks to modify the package-deps-hash before being written. - * At the end of the build, a we would create a package-deps_.json file like so: - * - * { - * commandLine: ["--production"], - * files: { - * "src/index.ts": "478789a7fs8a78989afd8", - * "src/fileOne.ts": "a8sfa8979871fdjiojlk", - * "common/api/review": "324598afasfdsd", // this entry was added by the API Extractor - * // task (for example) - * ".rush/temp/shrinkwrap-deps.json": "3428789dsafdsfaf" // this is a file which will be created by rush - * // link describing the state of the - * // node_modules folder - * } - * } - * - * Verifying this file should be fairly straightforward, we would simply need to check if: - * A) no files were added or deleted from the current folder - * B) all file hashes match - * C) the node_modules hash/contents match - * D) the command line parameters match or are compatible - * - * Notes: - * * We need to store the command line arguments, which is currently done by rush instead of GCB - * * We need to store the hash/text of the a file which describes the state of the node_modules folder - * * The package-deps_.json should be a complete list of dependencies, and it should be extremely cheap - * to validate/check the file (even if creating it is more computationally costly). - */ - - // Add the "NO_PROJECT" files to every project's dependencies - // for (const project of PackageChangeAnalyzer.rushConfig.projects) { - // Object.keys(noProjectHashes).forEach((filePath: string) => { - // const fileHash: string = noProjectHashes[filePath]; - // projectHashDeps.get(project.packageName).files[filePath] = fileHash; - // }); - // } - - if ( - this._rushConfiguration.packageManager === 'pnpm' && - !this._rushConfiguration.experimentsConfiguration.configuration.legacyIncrementalBuildDependencyDetection - ) { - const projects: RushConfigurationProject[] = []; - const projectDependencyManifestPaths: string[] = []; - - for (const project of this._rushConfiguration.projects) { - const dependencyManifestFilePath: string = PnpmProjectDependencyManifest.getFilePathForProject(project); - const relativeDependencyManifestFilePath: string = path.relative( - this._rushConfiguration.rushJsonFolder, - dependencyManifestFilePath - ).replace(/\\/g, '/'); - - if (!FileSystem.exists(dependencyManifestFilePath)) { - throw new Error( - `A project dependency file (${relativeDependencyManifestFilePath}) is missing. You may need to run ` + - '"rush unlink" and "rush link".' - ); - } - - projects.push(project); - projectDependencyManifestPaths.push(relativeDependencyManifestFilePath); - } - - const hashes: Map = getGitHashForFiles( - projectDependencyManifestPaths, - this._rushConfiguration.rushJsonFolder - ); - for (let i: number = 0; i < projects.length; i++) { - const project: RushConfigurationProject = projects[i]; - const projectDependencyManifestPath: string = projectDependencyManifestPaths[i]; - if (!hashes.has(projectDependencyManifestPath)) { - throw new InternalError(`Expected to get a hash for ${projectDependencyManifestPath}`); - } - const hash: string = hashes.get(projectDependencyManifestPath)!; - projectHashDeps.get(project.packageName)!.files[projectDependencyManifestPath] = hash; - } - } else { - // Determine the current variant from the link JSON. - const variant: string | undefined = this._rushConfiguration.currentInstalledVariant; - - // Add the shrinkwrap file to every project's dependencies - const shrinkwrapFile: string = path.relative( - this._rushConfiguration.rushJsonFolder, - this._rushConfiguration.getCommittedShrinkwrapFilename(variant) - ).replace(/\\/g, '/'); - - for (const project of this._rushConfiguration.projects) { - const shrinkwrapHash: string | undefined = noProjectHashes[shrinkwrapFile]; - if (shrinkwrapHash) { - projectHashDeps.get(project.packageName)!.files[shrinkwrapFile] = shrinkwrapHash; - } - } - } - - return projectHashDeps; - } - - private _getProjectForFile(filePath: string): string | undefined { - for (const project of this._rushConfiguration.projects) { - if (this._fileExistsInFolder(filePath, project.projectRelativeFolder)) { - return project.packageName; - } - } - return undefined; - } - - private _fileExistsInFolder(filePath: string, folderPath: string): boolean { - return Path.isUnder(filePath, folderPath); - } -} diff --git a/apps/rush-lib/src/logic/PackageJsonUpdater.ts b/apps/rush-lib/src/logic/PackageJsonUpdater.ts deleted file mode 100644 index 61a8dba3ac3..00000000000 --- a/apps/rush-lib/src/logic/PackageJsonUpdater.ts +++ /dev/null @@ -1,517 +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 colors from 'colors'; -import * as semver from 'semver'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { InstallManager, IInstallManagerOptions } from './InstallManager'; -import { VersionMismatchFinder } from './versionMismatch/VersionMismatchFinder'; -import { PurgeManager } from './PurgeManager'; -import { Utilities } from '../utilities/Utilities'; -import { - DependencyType, - PackageJsonDependency -} from '../api/PackageJsonEditor'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { VersionMismatchFinderEntity } from './versionMismatch/VersionMismatchFinderEntity'; -import { VersionMismatchFinderProject } from './versionMismatch/VersionMismatchFinderProject'; -import { RushConstants } from './RushConstants'; - -/** - * The type of SemVer range specifier that is prepended to the version - */ -export const enum SemVerStyle { - Exact = 'exact', - Caret = 'caret', - Tilde = 'tilde', - Passthrough = 'passthrough' -} - -/** - * Options for adding a dependency to a particular project. - */ -export interface IPackageJsonUpdaterRushAddOptions { - /** - * The projects whose package.jsons should get updated - */ - projects: RushConfigurationProject[]; - /** - * The name of the dependency to be added - */ - packageName: string; - /** - * The initial version specifier. - * If undefined, the latest version will be used (that doesn't break ensureConsistentVersions). - * If specified, the latest version meeting the SemVer specifier will be used as the basis. - */ - initialVersion: string | undefined; - /** - * Whether or not this dependency should be added as a devDependency or a regular dependency. - */ - devDependency: boolean; - /** - * If specified, other packages that use this dependency will also have their package.json's updated. - */ - updateOtherPackages: boolean; - /** - * If specified, "rush update" will not be run after updating the package.json file(s). - */ - skipUpdate: boolean; - /** - * If specified, "rush update" will be run in debug mode. - */ - debugInstall: boolean; - /** - * The style of range that should be used if the version is automatically detected. - */ - rangeStyle: SemVerStyle; - /** - * The variant to consider when performing installations and validating shrinkwrap updates. - */ - variant?: string | undefined; -} - -/** - * Configuration options for adding or updating a dependency in a single project - */ -export interface IUpdateProjectOptions { - /** - * The project which will have its package.json updated - */ - project: VersionMismatchFinderEntity; - /** - * The name of the dependency to be added or updated in the project - */ - packageName: string; - /** - * The new SemVer specifier that should be added to the project's package.json - */ - newVersion: string; - /** - * The type of dependency that should be updated. If left empty, this will be auto-detected. - * If it cannot be auto-detected an exception will be thrown. - */ - dependencyType?: DependencyType; -} - -/** - * A helper class for managing the dependencies of various package.json files. - * @internal - */ -export class PackageJsonUpdater { - private _rushConfiguration: RushConfiguration; - private _rushGlobalFolder: RushGlobalFolder; - - public constructor(rushConfiguration: RushConfiguration, rushGlobalFolder: RushGlobalFolder) { - this._rushConfiguration = rushConfiguration; - this._rushGlobalFolder = rushGlobalFolder; - } - - /** - * Adds a dependency to a particular project. The core business logic for "rush add". - */ - public async doRushAdd(options: IPackageJsonUpdaterRushAddOptions): Promise { - const { - projects, - packageName, - initialVersion, - devDependency, - updateOtherPackages, - skipUpdate, - debugInstall, - rangeStyle, - variant - } = options; - - const implicitlyPinned: Map = InstallManager.collectImplicitlyPreferredVersions( - this._rushConfiguration, - { - variant - } - ); - - const purgeManager: PurgeManager = new PurgeManager(this._rushConfiguration, this._rushGlobalFolder); - const installManagerOptions: IInstallManagerOptions = { - debug: debugInstall, - allowShrinkwrapUpdates: true, - bypassPolicy: false, - noLink: false, - fullUpgrade: false, - recheckShrinkwrap: false, - networkConcurrency: undefined, - collectLogFile: false, - variant: variant, - maxInstallAttempts: RushConstants.defaultMaxInstallAttempts - }; - const installManager: InstallManager = new InstallManager( - this._rushConfiguration, - this._rushGlobalFolder, - purgeManager, - installManagerOptions - ); - - const version: string = await this._getNormalizedVersionSpec( - projects, - installManager, - packageName, - initialVersion, - implicitlyPinned.get(packageName), - rangeStyle - ); - - console.log(); - console.log(colors.green(`Updating projects to use `) + packageName + '@' + colors.cyan(version)); - console.log(); - - const allPackageUpdates: IUpdateProjectOptions[] = []; - - for (const project of projects) { - const currentProjectUpdate: IUpdateProjectOptions = { - project: new VersionMismatchFinderProject(project), - packageName, - newVersion: version, - dependencyType: devDependency ? DependencyType.Dev : undefined - }; - this.updateProject(currentProjectUpdate); - - const otherPackageUpdates: IUpdateProjectOptions[] = []; - - if (this._rushConfiguration.ensureConsistentVersions || updateOtherPackages) { - // we need to do a mismatch check - const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches(this._rushConfiguration, { - variant: variant - }); - - const mismatches: string[] = mismatchFinder.getMismatches().filter((mismatch) => { - return !projects.find((proj) => proj.packageName === mismatch); - }); - if (mismatches.length) { - if (!updateOtherPackages) { - throw new Error(`Adding '${packageName}@${version}' to ${project.packageName}` - + ` causes mismatched dependencies. Use the "--make-consistent" flag to update other packages to use` - + ` this version, or do not specify a SemVer range.`); - } - - // otherwise we need to go update a bunch of other projects - const mismatchedVersions: string[] | undefined = mismatchFinder.getVersionsOfMismatch(packageName); - if (mismatchedVersions) { - for (const mismatchedVersion of mismatchedVersions) { - for (const consumer of mismatchFinder.getConsumersOfMismatch(packageName, mismatchedVersion)!) { - if (consumer instanceof VersionMismatchFinderProject) { - otherPackageUpdates.push({ - project: consumer, - packageName: packageName, - newVersion: version - }); - } - } - } - } - } - } - - this.updateProjects(otherPackageUpdates); - - allPackageUpdates.push(currentProjectUpdate, ...otherPackageUpdates); - } - - for (const { project } of allPackageUpdates) { - if (project.saveIfModified()) { - console.log(colors.green('Wrote ') + project.filePath); - } - } - - if (!skipUpdate) { - console.log(); - console.log(colors.green('Running "rush update"')); - console.log(); - try { - await installManager.doInstall(); - } finally { - purgeManager.deleteAll(); - } - } - } - - /** - * Updates several projects' package.json files - */ - public updateProjects(projectUpdates: IUpdateProjectOptions[]): void { - for (const update of projectUpdates) { - this.updateProject(update); - } - } - - /** - * Updates a single project's package.json file - */ - public updateProject(options: IUpdateProjectOptions): void { - let { dependencyType } = options; - const { - project, - packageName, - newVersion - } = options; - - const oldDependency: PackageJsonDependency | undefined = project.tryGetDependency(packageName); - const oldDevDependency: PackageJsonDependency | undefined = project.tryGetDevDependency(packageName); - - const oldDependencyType: DependencyType | undefined = oldDevDependency - ? oldDevDependency.dependencyType - : (oldDependency ? oldDependency.dependencyType : undefined); - - dependencyType = dependencyType || oldDependencyType || DependencyType.Regular; - - project.addOrUpdateDependency(packageName, newVersion, dependencyType!); - } - - /** - * Selects an appropriate version number for a particular package, given an optional initial SemVer spec. - * If ensureConsistentVersions, tries to pick a version that will be consistent. - * Otherwise, will choose the latest semver matching the initialSpec and append the proper range style. - * @param projects - the projects which will have their package.json's updated - * @param packageName - the name of the package to be used - * @param initialSpec - a semver pattern that should be used to find the latest version matching the spec - * @param implicitlyPinnedVersion - the implicitly preferred (aka common/primary) version of the package in use - * @param rangeStyle - if this version is selected by querying registry, then this range specifier is prepended to - * the selected version. - */ - private async _getNormalizedVersionSpec( - projects: RushConfigurationProject[], - installManager: InstallManager, - packageName: string, - initialSpec: string | undefined, - implicitlyPinnedVersion: string | undefined, - rangeStyle: SemVerStyle - ): Promise { - console.log(colors.gray(`Determining new version for dependency: ${packageName}`)); - if (initialSpec) { - console.log(`Specified version selector: ${colors.cyan(initialSpec)}`); - } else { - console.log(`No version selector was specified, so the version will be determined automatically.`); - } - console.log(); - - // determine if the package is a project in the local repository and if the version exists - const localProject: RushConfigurationProject | undefined = this._tryGetLocalProject(packageName, projects); - - // if ensureConsistentVersions => reuse the pinned version - // else, query the registry and use the latest that satisfies semver spec - if (initialSpec && implicitlyPinnedVersion && initialSpec === implicitlyPinnedVersion) { - console.log(colors.green('Assigning "') - + colors.cyan(initialSpec) - + colors.green(`" for "${packageName}" because it matches what other projects are using in this repo.`)); - return initialSpec; - } - - if (this._rushConfiguration.ensureConsistentVersions && !initialSpec && implicitlyPinnedVersion) { - console.log(`Assigning the version range "${colors.cyan(implicitlyPinnedVersion)}" for "${packageName}" because` - + ` it is already used by other projects in this repo.`); - return implicitlyPinnedVersion; - } - - await installManager.ensureLocalPackageManager(); - let selectedVersion: string | undefined; - - if (initialSpec && initialSpec !== 'latest') { - console.log(colors.gray('Finding versions that satisfy the selector: ') + initialSpec); - console.log(); - - if (localProject !== undefined) { - const version: string = localProject.packageJson.version; - if (semver.satisfies(version, initialSpec)) { - selectedVersion = version; - } else { - throw new Error( - `The dependency being added ("${packageName}") is a project in the local Rush repository, ` + - `but the version specifier provided (${initialSpec}) does not match the local project's version ` + - `(${version}). Correct the version specifier, omit a version specifier, or include "${packageName}" as a ` + - `cyclicDependencyProject if it is intended for "${packageName}" to come from an external feed and not ` + - 'from the local Rush repository.' - ); - } - } else { - console.log(`Querying registry for all versions of "${packageName}"...`); - - let commandArgs: string[]; - if (this._rushConfiguration.packageManager === 'yarn') { - commandArgs = ['info', packageName, 'versions', '--json']; - } else { - commandArgs = ['view', packageName, 'versions', '--json']; - } - - const allVersions: string = - Utilities.executeCommandAndCaptureOutput( - this._rushConfiguration.packageManagerToolFilename, - commandArgs, - this._rushConfiguration.commonTempFolder - ); - - let versionList: string[]; - if (this._rushConfiguration.packageManager === 'yarn') { - versionList = JSON.parse(allVersions).data; - } else { - versionList = JSON.parse(allVersions); - } - - console.log(colors.gray(`Found ${versionList.length} available versions.`)); - - for (const version of versionList) { - if (semver.satisfies(version, initialSpec)) { - selectedVersion = initialSpec; - console.log(`Found a version that satisfies ${initialSpec}: ${colors.cyan(version)}`); - break; - } - } - - if (!selectedVersion) { - throw new Error(`Unable to find a version of "${packageName}" that satisfies` - + ` the version specifier "${initialSpec}"`); - } - } - } else { - if (!this._rushConfiguration.ensureConsistentVersions) { - console.log(colors.gray(`The "ensureConsistentVersions" policy is NOT active,` - + ` so we will assign the latest version.`)); - console.log(); - } - - if (localProject !== undefined) { - selectedVersion = localProject.packageJson.version; - } else { - console.log(`Querying NPM registry for latest version of "${packageName}"...`); - - let commandArgs: string[]; - if (this._rushConfiguration.packageManager === 'yarn') { - commandArgs = ['info', packageName, 'dist-tags.latest', '--silent']; - } else { - commandArgs = ['view', `${packageName}@latest`, 'version']; - } - - selectedVersion = Utilities.executeCommandAndCaptureOutput( - this._rushConfiguration.packageManagerToolFilename, - commandArgs, - this._rushConfiguration.commonTempFolder - ).trim(); - } - - console.log(); - - console.log(`Found latest version: ${colors.cyan(selectedVersion)}`); - } - - console.log(); - - switch (rangeStyle) { - case SemVerStyle.Caret: { - console.log(colors.grey(`Assigning version "^${selectedVersion}" for "${packageName}" because the "--caret"` - + ` flag was specified.`)); - return `^${selectedVersion}`; - } - - case SemVerStyle.Exact: { - console.log(colors.grey(`Assigning version "${selectedVersion}" for "${packageName}" because the "--exact"` - + ` flag was specified.`)); - return selectedVersion; - } - - case SemVerStyle.Tilde: { - console.log(colors.gray(`Assigning version "~${selectedVersion}" for "${packageName}".`)); - return `~${selectedVersion}`; - } - - case SemVerStyle.Passthrough: { - console.log(colors.gray(`Assigning version "${selectedVersion}" for "${packageName}".`)); - return selectedVersion; - } - - default: { - throw new Error(`Unexpected SemVerStyle ${rangeStyle}.`); - } - } - } - - private _collectAllDownstreamDependencies(project: RushConfigurationProject): Set { - const allProjectDownstreamDependencies: Set = new Set(); - - const collectDependencies: (rushProject: RushConfigurationProject) => void = ( - rushProject: RushConfigurationProject - ) => { - for (const downstreamDependencyProject of rushProject.downstreamDependencyProjects) { - const foundProject: RushConfigurationProject | undefined = this._rushConfiguration.projectsByName.get( - downstreamDependencyProject - ); - - if (!foundProject) { - continue; - } - - if (foundProject.cyclicDependencyProjects.has(rushProject.packageName)) { - continue; - } - - if (!allProjectDownstreamDependencies.has(foundProject)) { - allProjectDownstreamDependencies.add(foundProject) - collectDependencies(foundProject); - } - } - } - - collectDependencies(project); - return allProjectDownstreamDependencies; - } - - /** - * Given a package name, this function returns a {@see RushConfigurationProject} if the package is a project - * in the local Rush repo and is not marked as cyclic for any of the projects. - * - * @remarks - * This function throws an error if adding the discovered local project as a dependency - * would create a dependency cycle, or if it would be added to multiple projects. - */ - private _tryGetLocalProject( - packageName: string, - projects: RushConfigurationProject[] - ): RushConfigurationProject | undefined { - const foundProject: RushConfigurationProject | undefined = this._rushConfiguration.projectsByName.get( - packageName - ); - - if (foundProject === undefined) { - return undefined; - } - - if (projects.length > 1) { - throw new Error( - `"rush add" does not support adding a local project as a dependency to multiple projects at once.` - ); - } - - const project: RushConfigurationProject = projects[0]; - - if (project.cyclicDependencyProjects.has(foundProject.packageName)) { - return undefined; - } - - // Are we attempting to add this project to itself? - if (project === foundProject) { - throw new Error( - 'Unable to add a project as a dependency of itself unless the dependency is listed as a cyclic dependency ' + - `in rush.json. This command attempted to add "${foundProject.packageName}" as a dependency of itself.` - ); - } - - // Are we attempting to create a cycle? - const downstreamDependencies: Set = this._collectAllDownstreamDependencies(project); - if (downstreamDependencies.has(foundProject)) { - throw new Error( - `Adding "${foundProject.packageName}" as a direct or indirect dependency of ` + - `"${project.packageName}" would create a dependency cycle.` - ); - } - - return foundProject; - } -} diff --git a/apps/rush-lib/src/logic/PublishGit.ts b/apps/rush-lib/src/logic/PublishGit.ts deleted file mode 100644 index efef2ff4c0f..00000000000 --- a/apps/rush-lib/src/logic/PublishGit.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { PublishUtilities } from './PublishUtilities'; -import { Utilities } from '../utilities/Utilities'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; - -export class PublishGit { - private _targetBranch: string | undefined; - - public constructor(targetBranch: string | undefined) { - - this._targetBranch = targetBranch; - } - - public checkout(branchName: string | undefined, createBranch?: boolean): void { - const params: string = `checkout ${createBranch ? '-b ' : ''}${branchName}`; - - PublishUtilities.execCommand(!!this._targetBranch, 'git', params.split(' ')); - } - - public merge(branchName: string): void { - PublishUtilities.execCommand(!!this._targetBranch, 'git', `merge ${branchName} --no-edit`.split(' ')); - } - - public deleteBranch(branchName: string, hasRemote: boolean = true): void { - PublishUtilities.execCommand(!!this._targetBranch, 'git', `branch -d ${branchName}`.split(' ')); - if (hasRemote) { - PublishUtilities.execCommand(!!this._targetBranch, 'git', `push origin --delete ${branchName}`.split(' ')); - } - } - - public pull(): void { - PublishUtilities.execCommand(!!this._targetBranch, 'git', `pull origin ${this._targetBranch}`.split(' ')); - } - - public fetch(): void { - PublishUtilities.execCommand(!!this._targetBranch, 'git', ['fetch', 'origin']); - } - - public addChanges(pathspec?: string, workingDirectory?: string): void { - const files: string = pathspec ? pathspec : '.'; - PublishUtilities.execCommand(!!this._targetBranch, 'git', ['add', files], - workingDirectory ? workingDirectory : process.cwd()); - } - - public addTag(shouldExecute: boolean, packageName: string, packageVersion: string, commitId: string | undefined): void { - // Tagging only happens if we're publishing to real NPM and committing to git. - const tagName: string = PublishUtilities.createTagname(packageName, packageVersion); - PublishUtilities.execCommand( - !!this._targetBranch && shouldExecute, - 'git', - ['tag', '-a', tagName, '-m', `${packageName} v${packageVersion}`, ...(commitId ? [commitId] : [])]); - } - - public hasTag(packageConfig: RushConfigurationProject): boolean { - const tagName: string = PublishUtilities.createTagname( - packageConfig.packageName, - packageConfig.packageJson.version - ); - const tagOutput: string = Utilities.executeCommandAndCaptureOutput( - 'git', - ['tag', '-l', tagName], - packageConfig.projectFolder, - PublishUtilities.getEnvArgs(), - true - ).replace(/(\r\n|\n|\r)/gm, ''); - - return tagOutput === tagName; - } - - public commit(commitMessage: string): void { - PublishUtilities.execCommand(!!this._targetBranch, 'git', ['commit', '-m', commitMessage]); - } - - public push(branchName: string | undefined): void { - PublishUtilities.execCommand( - !!this._targetBranch, - 'git', - // 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. - ['push', 'origin', 'HEAD:' + branchName, '--follow-tags', '--verbose', '--no-verify']); - } -} diff --git a/apps/rush-lib/src/logic/PublishUtilities.ts b/apps/rush-lib/src/logic/PublishUtilities.ts deleted file mode 100644 index f926a168a79..00000000000 --- a/apps/rush-lib/src/logic/PublishUtilities.ts +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * This file contains a set of helper functions that are unit tested and used with the PublishAction, - * which itself is a thin wrapper around these helpers. - */ - -import { EOL } from 'os'; -import * as path from 'path'; -import * as semver from 'semver'; - -import { - IPackageJson, - JsonFile, - FileConstants, - Text -} from '@rushstack/node-core-library'; - -import { - IChangeInfo, - ChangeType -} from '../api/ChangeManagement'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { Utilities, IEnvironment } from '../utilities/Utilities'; -import { execSync } from 'child_process'; -import { PrereleaseToken } from './PrereleaseToken'; -import { ChangeFiles } from './ChangeFiles'; -import { RushConfiguration } from '../api/RushConfiguration'; - -export interface IChangeInfoHash { - [key: string]: IChangeInfo; -} - -export class PublishUtilities { - /** - * Finds change requests in the given folder. - * @param changesPath Path to the changes folder. - * @returns Dictionary of all change requests, keyed by package name. - */ - public static findChangeRequests( - allPackages: Map, - rushConfiguration: RushConfiguration, - changeFiles: ChangeFiles, - includeCommitDetails?: boolean, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): IChangeInfoHash { - - const allChanges: IChangeInfoHash = {}; - console.log(`Finding changes in: ${changeFiles.getChangesPath()}`); - - const files: string[] = changeFiles.getFiles(); - - // Add the minimum changes defined by the change descriptions. - files.forEach((fullPath: string) => { - const changeRequest: IChangeInfo = JsonFile.load(fullPath); - - if (includeCommitDetails) { - PublishUtilities._updateCommitDetails(fullPath, changeRequest.changes); - } - - for (const change of changeRequest.changes!) { - PublishUtilities._addChange( - change, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - } - }); - - // For each requested package change, ensure downstream dependencies are also updated. - for (const packageName in allChanges) { - if (allChanges.hasOwnProperty(packageName)) { - PublishUtilities._updateDownstreamDependencies( - allChanges[packageName], - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - } - } - - // Update orders so that downstreams are marked to come after upstreams. - for (const packageName in allChanges) { - if (allChanges.hasOwnProperty(packageName)) { - const change: IChangeInfo = allChanges[packageName]; - const project: RushConfigurationProject = allPackages.get(packageName)!; - const pkg: IPackageJson = project.packageJson; - const deps: string[] = project.downstreamDependencyProjects; - - // Write the new version expected for the change. - const skipVersionBump: boolean = PublishUtilities._shouldSkipVersionBump(project, - prereleaseToken, projectsToExclude); - if (skipVersionBump) { - change.newVersion = pkg.version; - } else { - // For hotfix changes, do not re-write new version - change.newVersion = (change.changeType! >= ChangeType.patch) ? - semver.inc(pkg.version, PublishUtilities._getReleaseType(change.changeType!)) : - (change.changeType === ChangeType.hotfix ? change.newVersion : pkg.version); - } - - if (deps) { - for (const depName of deps) { - const depChange: IChangeInfo = allChanges[depName]; - - if (depChange) { - depChange.order = Math.max(change.order! + 1, depChange.order!); - } - } - } - } - } - - return allChanges; - } - - /** - * Given the changes hash, flattens them into a sorted array based on their dependency order. - * @params allChanges - hash of change requests. - * @returns Sorted array of change requests. - */ - public static sortChangeRequests(allChanges: IChangeInfoHash): IChangeInfo[] { - return Object - .keys(allChanges) - .map(key => allChanges[key]) - .sort((a, b) => a.order! < b.order! ? -1 : 1); - } - - /** - * Given a single change request, updates the package json file with updated versions on disk. - */ - public static updatePackages( - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - shouldCommit: boolean, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): Map { - const updatedPackages: Map = new Map(); - - Object.keys(allChanges).forEach(packageName => { - const updatedPackage: IPackageJson = PublishUtilities._writePackageChanges( - allChanges[packageName], - allChanges, - allPackages, - rushConfiguration, - shouldCommit, - prereleaseToken, - projectsToExclude); - updatedPackages.set(updatedPackage.name, updatedPackage); - }); - - return updatedPackages; - } - - /** - * Returns the generated tagname to use for a published commit, given package name and version. - */ - public static createTagname(packageName: string, version: string): string { - return packageName + '_v' + version; - } - - public static isRangeDependency(version: string): boolean { - const LOOSE_PKG_REGEX: RegExp = />=?(?:\d+\.){2}\d+(\-[0-9A-Za-z-.]*)?\s+<(?:\d+\.){2}\d+/; - - return LOOSE_PKG_REGEX.test(version); - } - - public static getEnvArgs(): { [key: string]: string | undefined } { - const env: { [key: string]: string | undefined } = {}; - - // Copy existing process.env values (for nodist) - Object.keys(process.env).forEach((key: string) => { - env[key] = process.env[key]; - }); - return env; - } - - /** - * @param secretSubstring -- if specified, a substring to be replaced by `<>` to avoid printing secrets - * on the console - */ - public static execCommand( - shouldExecute: boolean, - command: string, - args: string[] = [], - workingDirectory: string = process.cwd(), - environment?: IEnvironment, - secretSubstring?: string - ): void { - - let relativeDirectory: string = path.relative(process.cwd(), workingDirectory); - - if (relativeDirectory) { - relativeDirectory = `(${relativeDirectory})`; - } - - let commandArgs: string = args.join(' '); - - if (secretSubstring && secretSubstring.length > 0) { - // Avoid printing the NPM publish token on the console when displaying the commandArgs - commandArgs = Text.replaceAll(commandArgs, secretSubstring, '<>'); - } - - console.log( - `${EOL}* ${shouldExecute ? 'EXECUTING' : 'DRYRUN'}: ${command} ${commandArgs} ${relativeDirectory}` - ); - - if (shouldExecute) { - Utilities.executeCommand( - command, - args, - workingDirectory, - environment, - false, - true); - } - } - - public static getNewDependencyVersion(dependencies: { [key: string]: string; }, - dependencyName: string, - newProjectVersion: string - ): string { - const currentDependencyVersion: string = dependencies[dependencyName]; - let newDependencyVersion: string; - if (PublishUtilities.isRangeDependency(currentDependencyVersion)) { - newDependencyVersion = PublishUtilities._getNewRangeDependency(newProjectVersion); - } else if (currentDependencyVersion.lastIndexOf('~', 0) === 0) { - newDependencyVersion = '~' + newProjectVersion; - } else if (currentDependencyVersion.lastIndexOf('^', 0) === 0) { - newDependencyVersion = '^' + newProjectVersion; - } else { - newDependencyVersion = newProjectVersion; - } - return 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}`); - } - } - - 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}`; - } - - 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; - } - - private static _updateCommitDetails(filename: string, changes: IChangeInfo[] | undefined): void { - try { - const fileLog: string = execSync('git 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. */ } - } - - private static _writePackageChanges( - change: IChangeInfo, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - shouldCommit: boolean, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): IPackageJson { - - const project: RushConfigurationProject = allPackages.get(change.packageName)!; - const pkg: IPackageJson = project.packageJson; - - const shouldSkipVersionBump: boolean = !project.shouldPublish || - !!projectsToExclude && projectsToExclude.has(change.packageName); - - const newVersion: string = shouldSkipVersionBump ? pkg.version : - PublishUtilities._getChangeInfoNewVersion(change, prereleaseToken); - - if (!shouldSkipVersionBump) { - console.log( - `${EOL}* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: ${ChangeType[change.changeType!]} update ` + - `for ${change.packageName} to ${newVersion}` - ); - } else { - console.log( - `${EOL}* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: update for ${change.packageName} at ${newVersion}` - ); - } - - const packagePath: string = path.join(project.projectFolder, FileConstants.PackageJson); - - pkg.version = newVersion; - - // Update the package's dependencies. - PublishUtilities._updateDependencies( - pkg.name, - pkg.dependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - // Update the package's dev dependencies. - PublishUtilities._updateDependencies( - pkg.name, - pkg.devDependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - // Update the package's peer dependencies. - PublishUtilities._updateDependencies( - pkg.name, - pkg.peerDependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - - change.changes!.forEach(subChange => { - if (subChange.comment) { - console.log(` - [${ChangeType[subChange.changeType!]}] ${subChange.comment}`); - } - }); - - if (shouldCommit) { - JsonFile.save(pkg, packagePath, { updateExistingFile: true }); - } - return pkg; - } - - private static _isCyclicDependency( - allPackages: Map, - packageName: string, - dependencyName: string - ): boolean { - const packageConfig: RushConfigurationProject | undefined = allPackages.get(packageName); - return !!packageConfig && packageConfig.cyclicDependencyProjects.has(dependencyName); - } - - private static _updateDependencies( - packageName: string, - dependencies: { [key: string]: string; } | undefined, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): void { - - if (dependencies) { - Object.keys(dependencies).forEach(depName => { - if (!PublishUtilities._isCyclicDependency(allPackages, packageName, depName)) { - const depChange: IChangeInfo = allChanges[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 dependecies with the `prereleaseToken` - // value unless an actual change (hotfix, patch, minor, major) has occured - return; - } else if (depChange && prereleaseToken && prereleaseToken.hasValue) { - // TODO: treat prerelease version the same as non-prerelease version. - // For prelease, the newVersion needs to be appended with prerelease name. - // And dependency should specify the specific prerelease version. - dependencies[depName] = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); - } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { - PublishUtilities._updateDependencyVersion( - packageName, - dependencies, - depName, - depChange, - allChanges, - allPackages, - rushConfiguration - ); - } - } - }); - } - } - - /** - * 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'); - } - return `${newVersion}-${prereleaseToken.name}`; - } else { - return newVersion; - } - } - - /** - * Adds the given change to the allChanges map. - * - * @returns true if the change caused the dependency change type to increase. - */ - private static _addChange( - change: IChangeInfo, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): boolean { - let hasChanged: boolean = false; - const packageName: string = change.packageName; - const project: RushConfigurationProject | undefined = allPackages.get(packageName); - - if (!project) { - console.log(`The package ${packageName} was requested for publishing but ` + - `does not exist. Skip this change.`); - return false; - } - - const pkg: IPackageJson = project.packageJson; - let currentChange: IChangeInfo; - - // If the given change does not have a changeType, derive it from the "type" string. - if (change.changeType === undefined) { - change.changeType = ChangeType[change.type!]; - } - - if (!allChanges[packageName]) { - hasChanged = true; - currentChange = allChanges[packageName] = { - packageName, - changeType: change.changeType, - order: 0, - changes: [change] - }; - } else { - currentChange = allChanges[packageName]; - - const oldChangeType: ChangeType = currentChange.changeType!; - - 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); - } - const skipVersionBump: boolean = PublishUtilities._shouldSkipVersionBump(project, - prereleaseToken, projectsToExclude); - - if (skipVersionBump) { - currentChange.newVersion = pkg.version; - hasChanged = false; - currentChange.changeType = ChangeType.none; - } else { - if (change.changeType === ChangeType.hotfix) { - const prereleaseComponents: string[] = semver.prerelease(pkg.version); - if (!rushConfiguration.hotfixChangeEnabled) { - throw new Error(`Cannot add hotfix change; hotfixChangeEnabled is false in configuration.`); - } - - currentChange.newVersion = pkg.version; - 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 = pkg.version; - if (currentChange.newVersion && semver.gt(currentChange.newVersion, pkg.version)) { - packageVersion = currentChange.newVersion; - } - currentChange.newVersion = change.changeType! >= ChangeType.patch ? - semver.inc(pkg.version, PublishUtilities._getReleaseType(currentChange.changeType!)) : - packageVersion; - } - - // 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; - } - - private static _updateDownstreamDependencies( - change: IChangeInfo, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): void { - - const packageName: string = change.packageName; - const downstreamNames: string[] = allPackages.get(packageName)!.downstreamDependencyProjects; - - // Iterate through all downstream dependencies for the package. - if (downstreamNames) { - if ((change.changeType! >= ChangeType.hotfix) || - (prereleaseToken && prereleaseToken.hasValue)) { - for (const depName of downstreamNames) { - const pkg: IPackageJson = allPackages.get(depName)!.packageJson; - - PublishUtilities._updateDownstreamDependency( - pkg.name, - pkg.dependencies, - change, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - PublishUtilities._updateDownstreamDependency( - pkg.name, - pkg.devDependencies, - change, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - } - } - } - } - - private static _updateDownstreamDependency( - parentPackageName: string, - dependencies: { [packageName: string]: string } | undefined, - change: IChangeInfo, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): void { - - if (dependencies && dependencies[change.packageName] && - !PublishUtilities._isCyclicDependency(allPackages, parentPackageName, change.packageName)) { - const requiredVersion: string = dependencies[change.packageName]; - const alwaysUpdate: boolean = !!prereleaseToken && prereleaseToken.hasValue && - !allChanges.hasOwnProperty(parentPackageName); - - // If the version range exists and has not yet been updated to this version, update it. - if (requiredVersion !== change.newRangeDependency || alwaysUpdate) { - - let changeType: ChangeType; - // 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. - changeType = semver.satisfies(change.newVersion!, requiredVersion) ? - ChangeType.dependency : - ChangeType.patch; - } - - const hasChanged: boolean = PublishUtilities._addChange({ - packageName: parentPackageName, - changeType - }, allChanges, allPackages, rushConfiguration, prereleaseToken, projectsToExclude); - - if (hasChanged || alwaysUpdate) { - // Only re-evaluate downstream dependencies if updating the parent package's dependency - // caused a version bump. - PublishUtilities._updateDownstreamDependencies( - allChanges[parentPackageName], - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - } - } - } - } - - private static _updateDependencyVersion( - packageName: string, - dependencies: { [key: string]: string; }, - dependencyName: string, - dependencyChange: IChangeInfo, - allChanges: IChangeInfoHash, - allPackages: Map, - rushConfiguration: RushConfiguration - ): void { - const currentDependencyVersion: string = dependencies[dependencyName]; - - dependencies[dependencyName] = PublishUtilities.getNewDependencyVersion( - dependencies, - dependencyName, - dependencyChange.newVersion! - ); - - // Add dependency version update comment. - PublishUtilities._addChange( - { - packageName: packageName, - changeType: ChangeType.dependency, - comment: - `Updating dependency "${dependencyName}" from \`${currentDependencyVersion}\`` + - ` to \`${dependencies[dependencyName]}\`` - }, - allChanges, - allPackages, - rushConfiguration - ); - } -} diff --git a/apps/rush-lib/src/logic/PurgeManager.ts b/apps/rush-lib/src/logic/PurgeManager.ts deleted file mode 100644 index 6d4a2a88a5b..00000000000 --- a/apps/rush-lib/src/logic/PurgeManager.ts +++ /dev/null @@ -1,124 +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 colors from 'colors'; -import * as path from 'path'; - -import { AsyncRecycler } from '../utilities/AsyncRecycler'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushConstants } from '../logic/RushConstants'; -import { RushGlobalFolder } from '../api/RushGlobalFolder'; - -/** - * This class implements the logic for "rush purge" - */ -export class PurgeManager { - private _rushConfiguration: RushConfiguration; - private _rushGlobalFolder: RushGlobalFolder; - private _commonTempFolderRecycler: AsyncRecycler; - private _rushUserFolderRecycler: AsyncRecycler; - - public constructor(rushConfiguration: RushConfiguration, rushGlobalFolder: RushGlobalFolder) { - this._rushConfiguration = rushConfiguration; - this._rushGlobalFolder = rushGlobalFolder; - - const commonAsyncRecyclerPath: string = path.join( - this._rushConfiguration.commonTempFolder, - RushConstants.rushRecyclerFolderName - ); - this._commonTempFolderRecycler = new AsyncRecycler(commonAsyncRecyclerPath); - - const rushUserAsyncRecyclerPath: string = path.join( - this._rushGlobalFolder.path, - RushConstants.rushRecyclerFolderName - ); - this._rushUserFolderRecycler = new AsyncRecycler(rushUserAsyncRecyclerPath); - } - - /** - * Performs the AsyncRecycler.deleteAll() operation. This should be called before - * the PurgeManager instance is disposed. - */ - public deleteAll(): void { - this._commonTempFolderRecycler.deleteAll(); - this._rushUserFolderRecycler.deleteAll(); - } - - public get commonTempFolderRecycler(): AsyncRecycler { - return this._commonTempFolderRecycler; - } - - /** - * Delete everything from the common/temp folder - */ - public purgeNormal(): void { - // Delete everything under common\temp except for the recycler folder itself - console.log('Purging ' + this._rushConfiguration.commonTempFolder); - - this._commonTempFolderRecycler.moveAllItemsInFolder(this._rushConfiguration.commonTempFolder, - this._getMembersToExclude(this._rushConfiguration.commonTempFolder, true)); - } - - /** - * In addition to performing the purgeNormal() operation, this method also cleans the - * .rush folder in the user's home directory. - */ - public purgeUnsafe(): void { - this.purgeNormal(); - - // We will delete everything under ~/.rush/ except for the recycler folder itself - console.log('Purging ' + this._rushGlobalFolder.path); - - // If Rush itself is running under a folder such as ~/.rush/node-v4.5.6/rush-1.2.3, - // we cannot delete that folder. - - // First purge the node-specific folder, e.g. ~/.rush/node-v4.5.6/* except for rush-1.2.3: - this._rushUserFolderRecycler.moveAllItemsInFolder(this._rushGlobalFolder.nodeSpecificPath, - this._getMembersToExclude(this._rushGlobalFolder.nodeSpecificPath, true)); - - // Then purge the the global folder, e.g. ~/.rush/* except for node-v4.5.6 - this._rushUserFolderRecycler.moveAllItemsInFolder(this._rushGlobalFolder.path, - this._getMembersToExclude(this._rushGlobalFolder.path, false)); - - if ( - this._rushConfiguration.packageManager === 'pnpm' && - this._rushConfiguration.pnpmOptions.pnpmStore === 'global' && - this._rushConfiguration.pnpmOptions.pnpmStorePath - ) { - console.warn(colors.yellow(`Purging the global pnpm-store`)) - this._rushUserFolderRecycler.moveAllItemsInFolder(this._rushConfiguration.pnpmOptions.pnpmStorePath); - } - - } - - private _getMembersToExclude(folderToRecycle: string, showWarning: boolean): string[] { - // Don't recycle the recycler - const membersToExclude: string[] = [RushConstants.rushRecyclerFolderName]; - - // If the current process is running inside one of the folders, don't recycle that either - // Example: "/home/user/.rush/rush-1.2.3/lib/example.js" - const currentFolderPath: string = path.resolve(__dirname); - - // Example: - // folderToRecycle = "/home/user/.rush/node-v4.5.6" - // relative = "rush-1.2.3/lib/example.js" - const relative: string = path.relative(folderToRecycle, currentFolderPath); - - // (The result can be an absolute path if the two folders are on different drive letters) - if (!path.isAbsolute(relative)) { - // Get the first path segment: - const firstPart: string = relative.split(/[\\\/]/)[0]; - if (firstPart.length > 0 && firstPart !== '..') { - membersToExclude.push(firstPart); - - if (showWarning) { - // Warn that we won't dispose this folder - console.log(colors.yellow('The active process\'s folder will not be deleted: ' - + path.join(folderToRecycle, firstPart))); - } - } - } - - return membersToExclude; - } -} diff --git a/apps/rush-lib/src/logic/RushConstants.ts b/apps/rush-lib/src/logic/RushConstants.ts deleted file mode 100644 index 983511d0848..00000000000 --- a/apps/rush-lib/src/logic/RushConstants.ts +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Constants used by the Rush tool. - * - * @remarks - * - * These are NOT part of the public API surface for rush-lib. - * The rationale is that we don't want people implementing custom parsers for - * the Rush config files; instead, they should rely on the official APIs from rush-lib. - */ -export class RushConstants { - /** - * The filename ("browser-approved-packages.json") for an optional policy configuration file - * that stores a list of NPM packages that have been approved for usage by Rush projects. - * This is part of a pair of config files, one for projects that run in a web browser - * (e.g. whose approval criteria mostly focuses on licensing and code size), and one for everywhere else - * (e.g. tooling projects whose approval criteria mostly focuses on avoiding node_modules sprawl). - */ - public static readonly browserApprovedPackagesFilename: string = 'browser-approved-packages.json'; - - /** - * The folder name ("changes") where change files will be stored. - */ - public static readonly changeFilesFolderName: string = 'changes'; - - /** - * The filename ("nonbrowser-approved-packages.json") for an optional policy configuration file - * that stores a list of NPM packages that have been approved for usage by Rush projects. - * This is part of a pair of config files, one for projects that run in a web browser - * (e.g. whose approval criteria mostly focuses on licensing and code size), and one for everywhere else - * (e.g. tooling projects whose approval criteria mostly focuses on avoiding node_modules sprawl). - */ - public static readonly nonbrowserApprovedPackagesFilename: string = 'nonbrowser-approved-packages.json'; - - /** - * The folder name ("common") where Rush's common data will be stored. - */ - public static readonly commonFolderName: string = 'common'; - - /** - * The NPM scope ("@rush-temp") that is used for Rush's temporary projects. - */ - public static readonly rushTempNpmScope: string = '@rush-temp'; - - /** - * The folder name ("temp") under the common folder, or under the .rush folder in each project's directory where - * temporary files will be stored. - * Example: `C:\MyRepo\common\temp` - */ - public static readonly rushTempFolderName: string = 'temp'; - - /** - * The folder name ("projects") where temporary projects will be stored. - * Example: `C:\MyRepo\common\temp\projects` - */ - public static readonly rushTempProjectsFolderName: string = 'projects'; - - /** - * The folder name ("variants") under which named variant configurations for - * alternate dependency sets may be found. - * Example: "C:\MyRepo\common\config\rush\variants" - */ - public static readonly rushVariantsFolderName: string = 'variants'; - - /** - * The filename ("npm-shrinkwrap.json") used to store an installation plan for the NPM package manger. - */ - public static readonly npmShrinkwrapFilename: string = 'npm-shrinkwrap.json'; - - /** - * The filename ("shrinkwrap.yaml") used to store an installation plan for the PNPM package manger - * (PNPM version 2.x and earlier). - */ - public static readonly pnpmV1ShrinkwrapFilename: string = 'shrinkwrap.yaml'; - - /** - * Number of installation attempts - */ - public static readonly defaultMaxInstallAttempts: number = 3; - - /** - * The filename ("pnpm-lock.yaml") used to store an installation plan for the PNPM package manger - * (PNPM version 3.x and later). - */ - public static readonly pnpmV3ShrinkwrapFilename: string = 'pnpm-lock.yaml'; - - /** - * The filename ("pnpmfile.js") used to add custom configuration to PNPM - */ - public static readonly pnpmfileFilename: string = 'pnpmfile.js'; - - /** - * The filename ("shrinkwrap.yaml") used to store state for pnpm - */ - public static readonly yarnShrinkwrapFilename: string = 'yarn.lock'; - - /** - * The folder name ("node_modules") where NPM installs its packages. - */ - public static readonly nodeModulesFolderName: string = 'node_modules'; - - /** - * The filename ("pinned-versions.json") for an old configuration file that - * that is no longer supported. - * - * @deprecated This feature has been superseded by the "preferredVersions" setting - * in common-versions.json - */ - // NOTE: Although this is marked as "deprecated", we will probably never retire it, - // since we always want to report the warning when someone upgrades an old repo. - public static readonly pinnedVersionsFilename: string = 'pinned-versions.json'; - - /** - * The filename ("common-versions.json") for an optional configuration file - * that stores dependency version information that affects all projects in the repo. - * This configuration file should go in the "common/config/rush" folder. - */ - public static readonly commonVersionsFilename: string = 'common-versions.json'; - - /** - * The name of the per-project folder where project-specific Rush files are stored. For example, - * the package-deps files, which are used by commands to determine if a particular project needs to be rebuilt. - */ - public static readonly projectRushFolderName: string = '.rush'; - - /** - * Custom command line configuration file, which is used by rush for implementing - * custom command and options. - */ - public static readonly commandLineFilename: string = 'command-line.json'; - - public static readonly versionPoliciesFilename: string = 'version-policies.json'; - - /** - * Experiments configuration file, which - */ - public static readonly experimentsFilename: string = 'experiments.json'; - - /** - * The URL ("http://rushjs.io") for the Rush web site. - */ - public static readonly rushWebSiteUrl: string = 'https://rushjs.io'; - - /** - * The name of the NPM package for the Rush tool ("@microsoft/rush"). - */ - public static readonly rushPackageName: string = '@microsoft/rush'; - - /** - * The folder name ("rush-recycler") where Rush moves large folder trees - * before asynchronously deleting them. - */ - public static readonly rushRecyclerFolderName: string = 'rush-recycler'; - - /** - * The name of the file to drop in project-folder/.rush/temp/ containing a listing of the project's direct - * and indirect dependencies. This is used to detect if a project's dependencies have changed since the last build. - */ - public static readonly projectDependencyManifestFilename: string = 'shrinkwrap-deps.json'; - - /** - * The value of the "commandKind" property for a bulk command in command-line.json - */ - public static readonly bulkCommandKind: 'bulk' = 'bulk'; - - /** - * The value of the "commandKind" property for a global command in command-line.json - */ - public static readonly globalCommandKind: 'global' = 'global'; - - /** - * The name of the incremental build command. - */ - public static readonly buildCommandName: string = 'build'; - - /** - * The name of the non-incremental build command. - */ - public static readonly rebuildCommandName: string = 'rebuild'; -} diff --git a/apps/rush-lib/src/logic/SetupChecks.ts b/apps/rush-lib/src/logic/SetupChecks.ts deleted file mode 100644 index 4ab4101a50f..00000000000 --- a/apps/rush-lib/src/logic/SetupChecks.ts +++ /dev/null @@ -1,121 +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 colors from 'colors'; -import * as path from 'path'; -import * as semver from 'semver'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { AlreadyReportedError } from '../utilities/AlreadyReportedError'; -import { Utilities } from '../utilities/Utilities'; -import { RushConstants } from '../logic/RushConstants'; -import { FileSystem } from '@rushstack/node-core-library'; - -// Refuses to run at all if the PNPM version is older than this, because there -// are known bugs or missing features in earlier releases. -const MINIMUM_SUPPORTED_NPM_VERSION: string = '4.5.0'; - -// Refuses to run at all if the PNPM version is older than this, because there -// are known bugs or missing features in earlier releases. -const MINIMUM_SUPPORTED_PNPM_VERSION: string = '2.6.2'; - -/** - * Validate that the developer's setup is good. - * - * These checks are invoked prior to the following commands: - * - rush install - * - rush update - * - rush build - * - rush rebuild - */ -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); - - if (errorMessage) { - console.error(colors.red(Utilities.wrapWords(errorMessage))); - throw new AlreadyReportedError(); - } - } - - private static _validate(rushConfiguration: RushConfiguration): string | undefined { - // Check for outdated tools - if (rushConfiguration.packageManager === 'pnpm') { - if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_PNPM_VERSION)) { - return `The rush.json 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 rush.json 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) { - console.log(colors.yellow(Utilities.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 { - console.log(colors.yellow(Utilities.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) { - console.log(colors.yellow(`"${folder}"`)); - } - 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)) { - phantomFolders.push(nodeModulesFolder); - } - - // 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/apps/rush-lib/src/logic/ShrinkwrapFileFactory.ts b/apps/rush-lib/src/logic/ShrinkwrapFileFactory.ts deleted file mode 100644 index 90c31112a9f..00000000000 --- a/apps/rush-lib/src/logic/ShrinkwrapFileFactory.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { PackageManagerName } from '../api/packageManager/PackageManager'; -import { BaseShrinkwrapFile } from './base/BaseShrinkwrapFile'; -import { NpmShrinkwrapFile } from './npm/NpmShrinkwrapFile'; -import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; -import { YarnShrinkwrapFile } from './yarn/YarnShrinkwrapFile'; - -export class ShrinkwrapFileFactory { - public static getShrinkwrapFile(packageManager: PackageManagerName, - shrinkwrapFilename: string): BaseShrinkwrapFile | undefined { - - switch (packageManager) { - case 'npm': - return NpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); - case 'pnpm': - return PnpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); - case 'yarn': - return YarnShrinkwrapFile.loadFromFile(shrinkwrapFilename); - } - throw new Error(`Invalid package manager: ${packageManager}`); - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/StandardScriptUpdater.ts b/apps/rush-lib/src/logic/StandardScriptUpdater.ts deleted file mode 100644 index c9c2f83045a..00000000000 --- a/apps/rush-lib/src/logic/StandardScriptUpdater.ts +++ /dev/null @@ -1,97 +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 { Text, FileSystem } from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../api/RushConfiguration'; - -/** - * Checks whether the common/scripts files are up to date, and recopies them if needed. - * This is used by the "rush install" and "rush update" commands. - */ -export class StandardScriptUpdater { - private static readonly _scriptNames: string[] = [ - 'install-run.js', - 'install-run-rush.js', - 'install-run-rushx.js' - ]; - - /** - * Recopy the scripts if the scripts are out of date. - * Used by "rush update". - */ - public static update(rushConfiguration: RushConfiguration): boolean { - let anyChanges: boolean = false; - for (const scriptName of StandardScriptUpdater._scriptNames) { - if (StandardScriptUpdater._updateScriptOrThrow(scriptName, rushConfiguration, false)) { - anyChanges = true; - } - } - - if (anyChanges) { - console.log(); // print a newline after the notices - } - return anyChanges; - } - - /** - * Throw an exception if the scripts are out of date. - * Used by "rush install". - */ - public static validate(rushConfiguration: RushConfiguration): void { - for (const scriptName of StandardScriptUpdater._scriptNames) { - StandardScriptUpdater._updateScriptOrThrow(scriptName, rushConfiguration, 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. - */ - private static _updateScriptOrThrow(scriptName: string, rushConfiguration: RushConfiguration, - throwInsteadOfCopy: boolean): boolean { - const targetFilePath: string = path.join(rushConfiguration.commonScriptsFolder, scriptName); - const sourceFilePath: string = path.resolve(__dirname, '../scripts', scriptName); - - FileSystem.ensureFolder(rushConfiguration.commonScriptsFolder); - - // Are the files the same? - let filesAreSame: boolean = false; - - if (FileSystem.exists(targetFilePath)) { - const sourceContent: string = FileSystem.readFile(sourceFilePath); - const targetContent: string = FileSystem.readFile(targetFilePath); - - const sourceNormalized: string = StandardScriptUpdater._normalize(sourceContent); - const targetNormalized: string = StandardScriptUpdater._normalize(targetContent); - - if (sourceNormalized === targetNormalized) { - filesAreSame = true; - } - } - - 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 { - console.log(`Script is out of date; updating "${targetFilePath}"`); - FileSystem.copyFile({ - sourcePath: sourceFilePath, - destinationPath: targetFilePath - }); - } - } - - return !filesAreSame; - } - - private static _normalize(content: string): string { - // Ignore newline differences from .gitattributes - return Text.convertToLf(content) - // Ignore trailing whitespace - .split('\n').map(x => x.trimRight()).join('\n'); - } -} diff --git a/apps/rush-lib/src/logic/TaskSelector.ts b/apps/rush-lib/src/logic/TaskSelector.ts deleted file mode 100644 index f5a7c2fc02a..00000000000 --- a/apps/rush-lib/src/logic/TaskSelector.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { - RushConfiguration, - IRushLinkJson -} from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { JsonFile } from '@rushstack/node-core-library'; - -import { ProjectTask, convertSlashesForWindows } from '../logic/taskRunner/ProjectTask'; -import { PackageChangeAnalyzer } from './PackageChangeAnalyzer'; -import { TaskCollection } from './taskRunner/TaskCollection'; - -export interface ITaskSelectorConstructor { - rushConfiguration: RushConfiguration; - toFlags: ReadonlyArray; - fromFlags: ReadonlyArray; - commandToRun: string; - customParameterValues: string[]; - isQuietMode: boolean; - isIncrementalBuildAllowed: boolean; - ignoreMissingScript: boolean; - ignoreDependencyOrder: boolean; - packageDepsFilename: string; -} - -/** - * This class is responsible for: - * - based on to/from flags, solving the dependency graph and figuring out which projects need to be run - * - creating a ProjectTask for each project that needs to be built - * - registering the necessary ProjectTasks with the TaskRunner, which actually orchestrates execution - */ -export class TaskSelector { - private _taskCollection: TaskCollection; - private _dependentList: Map>; - private _rushLinkJson: IRushLinkJson; - private _options: ITaskSelectorConstructor; - private _packageChangeAnalyzer: PackageChangeAnalyzer; - - public constructor(options: ITaskSelectorConstructor) { - this._options = options; - - this._packageChangeAnalyzer = new PackageChangeAnalyzer(options.rushConfiguration); - this._taskCollection = new TaskCollection({ - quietMode: options.isQuietMode - }); - - try { - this._rushLinkJson = JsonFile.load(this._options.rushConfiguration.rushLinkJsonFilename); - } catch (error) { - throw new Error(`Could not read "${this._options.rushConfiguration.rushLinkJsonFilename}".` - + ` Did you run "rush install" or "rush update"?`); - } - } - - public registerTasks(): TaskCollection { - if (this._options.toFlags.length > 0) { - this._registerToFlags(this._options.toFlags); - } - if (this._options.fromFlags.length > 0) { - this._registerFromFlags(this._options.fromFlags); - } - if (this._options.toFlags.length === 0 && this._options.fromFlags.length === 0) { - this._registerAll(); - } - - return this._taskCollection; - } - - private _registerToFlags(toFlags: ReadonlyArray): void { - const dependencies: Set = new Set(); - - for (const toFlag of toFlags) { - const toProject: RushConfigurationProject | undefined = - this._options.rushConfiguration.findProjectByShorthandName(toFlag); - if (!toProject) { - throw new Error(`The project '${toFlag}' does not exist in rush.json`); - } - - this._collectAllDependencies(toProject.packageName, dependencies); - } - - // Register any dependencies it may have - for (const dependency of dependencies) { - this._registerTask(this._options.rushConfiguration.getProjectByName(dependency)); - } - - if (!this._options.ignoreDependencyOrder) { - // Add ordering relationships for each dependency - for (const dependency of dependencies) { - this._taskCollection.addDependencies( - dependency, - this._rushLinkJson.localLinks[dependency] || [] - ); - } - } - } - - private _registerFromFlags(fromFlags: ReadonlyArray): void { - this._buildDependentGraph(); - const dependents: Set = new Set(); - - for (const fromFlag of fromFlags) { - const fromProject: RushConfigurationProject | undefined - = this._options.rushConfiguration.findProjectByShorthandName(fromFlag); - if (!fromProject) { - throw new Error(`The project '${fromFlag}' does not exist in rush.json`); - } - - this._collectAllDependents(fromProject.packageName, dependents); - } - - // Register all downstream dependents - for (const dependent of dependents) { - this._registerTask(this._options.rushConfiguration.getProjectByName(dependent)); - } - - if (!this._options.ignoreDependencyOrder) { - // Only add ordering relationships for projects which have been registered - // e.g. package C may depend on A & B, but if we are only building A's downstream, we will ignore B - for (const dependent of dependents) { - this._taskCollection.addDependencies( - dependent, - (this._rushLinkJson.localLinks[dependent] || []).filter(dep => dependents.has(dep)) - ); - } - } - } - - private _registerAll(): void { - // Register all tasks - for (const rushProject of this._options.rushConfiguration.projects) { - this._registerTask(rushProject); - } - - if (!this._options.ignoreDependencyOrder) { - // Add ordering relationships for each dependency - for (const projectName of Object.keys(this._rushLinkJson.localLinks)) { - this._taskCollection.addDependencies(projectName, this._rushLinkJson.localLinks[projectName]); - } - } - } - - /** - * Collects all upstream dependencies for a certain project - */ - private _collectAllDependencies(project: string, result: Set): void { - if (!result.has(project)) { - result.add(project); - - for (const dependency of this._rushLinkJson.localLinks[project] || []) { - this._collectAllDependencies(dependency, result); - } - } - } - - /** - * Collects all downstream dependents of a certain project - */ - private _collectAllDependents(project: string, result: Set): void { - if (!result.has(project)) { - result.add(project); - - for (const dependent of (this._dependentList.get(project) || new Set())) { - this._collectAllDependents(dependent, result); - } - } - } - - /** - * Inverts the localLinks to arrive at the dependent graph. This helps when using the --from flag - */ - private _buildDependentGraph(): void { - this._dependentList = new Map>(); - - for (const project of Object.keys(this._rushLinkJson.localLinks)) { - for (const dep of this._rushLinkJson.localLinks[project]) { - if (!this._dependentList.has(dep)) { - this._dependentList.set(dep, new Set()); - } - - this._dependentList.get(dep)!.add(project); - } - } - } - - private _registerTask(project: RushConfigurationProject | undefined): void { - if (project) { - const projectTask: ProjectTask = new ProjectTask({ - rushProject: project, - rushConfiguration: this._options.rushConfiguration, - commandToRun: this._getScriptToRun(project), - isIncrementalBuildAllowed: this._options.isIncrementalBuildAllowed, - packageChangeAnalyzer: this._packageChangeAnalyzer, - packageDepsFilename: this._options.packageDepsFilename - }); - - if (!this._taskCollection.hasTask(projectTask.name)) { - this._taskCollection.addTask(projectTask); - } - } - } - - private _getScriptToRun(rushProject: RushConfigurationProject): string { - const script: string | undefined = this._getScriptCommand(rushProject, this._options.commandToRun); - - if (script === undefined && !this._options.ignoreMissingScript) { - throw new Error(`The project [${rushProject.packageName}] does not define a '${this._options.commandToRun}' command in the 'scripts' section of its package.json`); - } - - if (!script) { - return ''; - } - - const taskCommand: string = `${script} ${this._options.customParameterValues.join(' ')}`; - return process.platform === 'win32' - ? convertSlashesForWindows(taskCommand) - : taskCommand; - } - - private _getScriptCommand(rushProject: RushConfigurationProject, script: string): string | undefined { - if (!rushProject.packageJson.scripts) { - return undefined; - } - - const rawCommand: string = rushProject.packageJson.scripts[script]; - - // eslint-disable-next-line @rushstack/no-null - if (rawCommand === undefined || rawCommand === null) { - return undefined; - } - - return rawCommand; - } -} diff --git a/apps/rush-lib/src/logic/Telemetry.ts b/apps/rush-lib/src/logic/Telemetry.ts deleted file mode 100644 index 8fe2f31ded3..00000000000 --- a/apps/rush-lib/src/logic/Telemetry.ts +++ /dev/null @@ -1,105 +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 fs from 'fs'; -import * as path from 'path'; -import { cloneDeep } from 'lodash'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { Rush } from '../api/Rush'; -import { FileSystem } from '@rushstack/node-core-library'; - -export interface ITelemetryData { - name: string; - duration: number; - result: string; - timestamp?: number; - platform?: string; - rushVersion?: string; - extraData?: { [key: string]: string }; -} - -const MAX_FILE_COUNT: number = 100; - -export class Telemetry { - private _enabled: boolean; - private _store: ITelemetryData[]; - private _dataFolder: string; - private _rushConfiguration: RushConfiguration; - - public constructor(rushConfiguration: RushConfiguration) { - this._rushConfiguration = rushConfiguration; - this._enabled = this._rushConfiguration.telemetryEnabled; - this._store = []; - - const folderName: string = 'telemetry'; - this._dataFolder = path.join(this._rushConfiguration.commonTempFolder, folderName); - } - - public log(telemetryData: ITelemetryData): void { - if (!this._enabled) { - return; - } - const data: ITelemetryData = cloneDeep(telemetryData); - data.timestamp = data.timestamp || new Date().getTime(); - data.platform = data.platform || process.platform; - data.rushVersion = data.rushVersion || Rush.version; - this._store.push(data); - } - - public flush(writeFile: (file: string, data: string) => void = FileSystem.writeFile): void { - if (!this._enabled || this._store.length === 0) { - return; - } - - const fullPath: string = this._getFilePath(); - FileSystem.ensureFolder(this._dataFolder); - writeFile(fullPath, JSON.stringify(this._store)); - this._store = []; - this._cleanUp(); - } - - public get store(): ITelemetryData[] { - return this._store; - } - - /** - * When there are too many log files, delete the old ones. - */ - private _cleanUp(): void { - if (FileSystem.exists(this._dataFolder)) { - const files: string[] = FileSystem.readFolder(this._dataFolder); - if (files.length > MAX_FILE_COUNT) { - const sortedFiles: string[] = files.map(fileName => { - const filePath: string = path.join(this._dataFolder, fileName); - const stats: fs.Stats = FileSystem.getStatistics(filePath); - return { - filePath: filePath, - modifiedTime: stats.mtime.getTime(), - isFile: stats.isFile() - }; - }) - .filter(value => { - // Only delete files - return value.isFile; - }) - .sort((a, b) => { - return a.modifiedTime - b.modifiedTime; - }) - .map(s => { - return s.filePath; - }); - const filesToDelete: number = sortedFiles.length - MAX_FILE_COUNT; - for (let i: number = 0; i < filesToDelete; i++) { - FileSystem.deleteFile(sortedFiles[i]); - } - } - } - } - - private _getFilePath(): string { - let fileName: string = `telemetry_${new Date().toISOString()}`; - fileName = fileName.replace(/[\-\:\.]/g, '_') + '.json'; - return path.join(this._dataFolder, fileName); - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/UnlinkManager.ts b/apps/rush-lib/src/logic/UnlinkManager.ts deleted file mode 100644 index b8a47624f85..00000000000 --- a/apps/rush-lib/src/logic/UnlinkManager.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. - -import * as path from 'path'; -import { FileSystem } from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../api/RushConfiguration'; -import { Utilities } from '../utilities/Utilities'; -import { PnpmProjectDependencyManifest } from './pnpm/PnpmProjectDependencyManifest'; - -/** - * This class implements the logic for "rush unlink" - */ -export class UnlinkManager { - private _rushConfiguration: RushConfiguration; - - public constructor(rushConfiguration: RushConfiguration) { - this._rushConfiguration = rushConfiguration; - } - - /** - * Delete flag file and all the existing node_modules symlinks and all - * project/.rush/temp/shrinkwrap-deps.json files - * - * Returns true if anything was deleted. - */ - public unlink(): boolean { - this._deleteFlagFile(); - return this._deleteProjectFiles(); - } - - /** - * Delete: - * - all the node_modules symlinks of configured Rush projects - * - all of the project/.rush/temp/shrinkwrap-deps.json files of configured Rush projects - * - * Returns true if anything was deleted - * */ - private _deleteProjectFiles(): boolean { - let didDeleteAnything: boolean = false; - - for (const rushProject of this._rushConfiguration.projects) { - const localModuleFolder: string = path.join(rushProject.projectFolder, 'node_modules'); - if (FileSystem.exists(localModuleFolder)) { - console.log(`Purging ${localModuleFolder}`); - Utilities.dangerouslyDeletePath(localModuleFolder); - didDeleteAnything = true; - } - - const projectDependencyManifestFilePath: string = PnpmProjectDependencyManifest.getFilePathForProject( - rushProject - ); - if (FileSystem.exists(projectDependencyManifestFilePath)) { - console.log(`Deleting ${projectDependencyManifestFilePath}`); - FileSystem.deleteFile(projectDependencyManifestFilePath); - didDeleteAnything = true; - } - } - - return didDeleteAnything; - } - - /** - * Delete the flag file if it exists; this will ensure that - * a full "rush link" is required next time - */ - private _deleteFlagFile(): void { - Utilities.deleteFile(this._rushConfiguration.rushLinkJsonFilename); - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/VersionManager.ts b/apps/rush-lib/src/logic/VersionManager.ts deleted file mode 100644 index df818d4c572..00000000000 --- a/apps/rush-lib/src/logic/VersionManager.ts +++ /dev/null @@ -1,348 +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 semver from 'semver'; -import { cloneDeep } from 'lodash'; -import { - IPackageJson, - JsonFile, - FileConstants -} from '@rushstack/node-core-library'; - -import { - VersionPolicy, - BumpType, - LockStepVersionPolicy -} from '../api/VersionPolicy'; -import { ChangeFile } from '../api/ChangeFile'; -import { ChangeType, IChangeInfo } from '../api/ChangeManagement'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; -import { VersionPolicyConfiguration } from '../api/VersionPolicyConfiguration'; -import { PublishUtilities } from './PublishUtilities'; -import { ChangeManager } from './ChangeManager'; - -export class VersionManager { - private _rushConfiguration: RushConfiguration; - private _userEmail: string; - private _versionPolicyConfiguration: VersionPolicyConfiguration; - private _updatedProjects: Map; - private _changeFiles: Map; - - public constructor( - _rushConfiguration: RushConfiguration, - _userEmail: string, - _versionPolicyConfiguration?: VersionPolicyConfiguration - ) { - this._rushConfiguration = _rushConfiguration; - this._userEmail = _userEmail; - this._versionPolicyConfiguration = _versionPolicyConfiguration - ? _versionPolicyConfiguration - : this._rushConfiguration.versionPolicyConfiguration; - - this._updatedProjects = new Map(); - this._changeFiles = new Map(); - } - - /** - * Ensures project versions follow the provided version policy. If version policy is not - * provided, all projects will have their version checked according to the associated version policy. - * package.json files will be updated if needed. - * This method does not commit changes. - * @param versionPolicyName -- version policy name - * @param shouldCommit -- should update files to disk - * @param force -- update even when project version is higher than policy version. - */ - public ensure(versionPolicyName?: string, shouldCommit?: boolean, force?: boolean): void { - this._ensure(versionPolicyName, shouldCommit, force); - } - - /** - * Bumps versions following version policies. - * - * @param lockStepVersionPolicyName - a specified lock step version policy name. Without this value, - * versions for all lock step policies and all individual policies will be bumped. - * With this value, only the specified lock step policy will be bumped along with all individual policies. - * @param bumpType - overrides the default bump type and only works for lock step policy - * @param identifier - overrides the prerelease identifier and only works for lock step policy - * @param shouldCommit - whether the changes will be written to disk - */ - public bump(lockStepVersionPolicyName?: string, - bumpType?: BumpType, - identifier?: string, - shouldCommit?: boolean - ): void { - // Bump all the lock step version policies. - this._versionPolicyConfiguration.bump(lockStepVersionPolicyName, bumpType, identifier, shouldCommit); - - // Update packages and generate change files due to lock step bump. - this._ensure(lockStepVersionPolicyName, shouldCommit); - - // Refresh rush configuration - this._rushConfiguration = RushConfiguration.loadFromConfigurationFile(this._rushConfiguration.rushJsonFile); - - // Update projects based on individual policies - const changeManager: ChangeManager = new ChangeManager(this._rushConfiguration, - this._getLockStepProjects()); - changeManager.load(this._rushConfiguration.changesFolder); - if (changeManager.hasChanges()) { - changeManager.validateChanges(this._versionPolicyConfiguration); - changeManager.apply(!!shouldCommit)!.forEach(packageJson => { - this._updatedProjects.set(packageJson.name, packageJson); - }); - changeManager.updateChangelog(!!shouldCommit); - } - } - - public get updatedProjects(): Map { - return this._updatedProjects; - } - - public get changeFiles(): Map { - return this._changeFiles; - } - - private _ensure(versionPolicyName?: string, shouldCommit?: boolean, force?: boolean): void { - this._updateVersionsByPolicy(versionPolicyName, force); - - // Update all dependencies if needed. - this._updateDependencies(); - - if (shouldCommit) { - this._updatePackageJsonFiles(); - this._changeFiles.forEach((changeFile) => { - changeFile.writeSync(); - }); - } - } - - private _getLockStepProjects(): Set | undefined { - const lockStepVersionPolicyNames: Set = new Set(); - - this._versionPolicyConfiguration.versionPolicies.forEach((versionPolicy) => { - if (versionPolicy instanceof LockStepVersionPolicy) { - lockStepVersionPolicyNames.add(versionPolicy.policyName); - } - }); - const lockStepProjectNames: Set = new Set(); - this._rushConfiguration.projects.forEach((rushProject) => { - if (lockStepVersionPolicyNames.has(rushProject.versionPolicyName!)) { - lockStepProjectNames.add(rushProject.packageName); - } - }); - return lockStepProjectNames; - } - - private _updateVersionsByPolicy(versionPolicyName?: string, force?: boolean): void { - // Update versions based on version policy - this._rushConfiguration.projects.forEach(rushProject => { - const projectVersionPolicyName: string | undefined = rushProject.versionPolicyName; - if (projectVersionPolicyName && - (!versionPolicyName || projectVersionPolicyName === versionPolicyName)) { - const versionPolicy: VersionPolicy = this._versionPolicyConfiguration.getVersionPolicy( - projectVersionPolicyName); - const updatedProject: IPackageJson | undefined = versionPolicy.ensure(rushProject.packageJson, force); - if (updatedProject) { - this._updatedProjects.set(updatedProject.name, updatedProject); - // No need to create an entry for prerelease version bump. - if (!this._isPrerelease(updatedProject.version) && rushProject.isMainProject) { - this._addChangeInfo(updatedProject.name, - [this._createChangeInfo(updatedProject, rushProject)]); - } - } - } - }); - } - - private _isPrerelease(version: string): boolean { - return !!semver.prerelease(version); - } - - private _addChangeInfo(packageName: string, - changeInfos: IChangeInfo[] - ): void { - if (!changeInfos.length) { - return; - } - let changeFile: ChangeFile | undefined = this._changeFiles.get(packageName); - if (!changeFile) { - changeFile = new ChangeFile({ - changes: [], - packageName: packageName, - email: this._userEmail - }, this._rushConfiguration); - this._changeFiles.set(packageName, changeFile); - } - changeInfos.forEach((changeInfo) => { - changeFile!.addChange(changeInfo); - }); - } - - private _updateDependencies(): void { - this._rushConfiguration.projects.forEach(rushProject => { - let clonedProject: IPackageJson | undefined = this._updatedProjects.get(rushProject.packageName); - let projectVersionChanged: boolean = true; - if (!clonedProject) { - clonedProject = cloneDeep(rushProject.packageJson); - projectVersionChanged = false; - } - this._updateProjectAllDependencies(rushProject, clonedProject, projectVersionChanged); - }); - } - - private _updateProjectAllDependencies( - rushProject: RushConfigurationProject, - clonedProject: IPackageJson, - projectVersionChanged: boolean - ): void { - if (!clonedProject.dependencies && !clonedProject.devDependencies) { - return; - } - const changes: IChangeInfo[] = []; - let updated: boolean = false; - if (this._updateProjectDependencies(clonedProject.dependencies, changes, - clonedProject, rushProject, projectVersionChanged) - ) { - updated = true; - } - if (this._updateProjectDependencies(clonedProject.devDependencies, changes, - clonedProject, rushProject, projectVersionChanged) - ) { - updated = true; - } - if (this._updateProjectDependencies(clonedProject.peerDependencies, changes, - clonedProject, rushProject, projectVersionChanged) - ) { - updated = true; - } - - if (updated) { - this._updatedProjects.set(clonedProject.name, clonedProject); - - this._addChangeInfo(clonedProject.name, changes); - } - } - - private _updateProjectDependencies(dependencies: { [key: string]: string; } | undefined, - changes: IChangeInfo[], - clonedProject: IPackageJson, - rushProject: RushConfigurationProject, - projectVersionChanged: boolean - ): boolean { - if (!dependencies) { - return false; - } - let updated: boolean = false; - this._updatedProjects.forEach((updatedDependentProject, updatedDependentProjectName) => { - if (dependencies[updatedDependentProjectName]) { - if (rushProject.cyclicDependencyProjects.has(updatedDependentProjectName)) { - // Skip if cyclic - console.log(`Found cyclic ${rushProject.packageName} ${updatedDependentProjectName}`); - return; - } - - const oldDependencyVersion: string = dependencies[updatedDependentProjectName]; - const newDependencyVersion: string = PublishUtilities.getNewDependencyVersion( - dependencies, - updatedDependentProjectName, - updatedDependentProject.version - ); - - if (newDependencyVersion !== oldDependencyVersion) { - updated = true; - if (this._shouldTrackDependencyChange(rushProject, updatedDependentProjectName)) { - this._trackDependencyChange(changes, clonedProject, projectVersionChanged, - updatedDependentProject, - oldDependencyVersion, - newDependencyVersion - ); - } - dependencies[updatedDependentProjectName] = newDependencyVersion; - } - } - }); - return updated; - } - - private _shouldTrackDependencyChange( - rushProject: RushConfigurationProject, - dependencyName: string - ): boolean { - const dependencyRushProject: RushConfigurationProject | undefined = - this._rushConfiguration.projectsByName.get(dependencyName); - - return !!dependencyRushProject && rushProject.shouldPublish && - (!rushProject.versionPolicy || - !rushProject.versionPolicy.isLockstepped || - rushProject.isMainProject && (dependencyRushProject.versionPolicyName !== rushProject.versionPolicyName)); - } - - private _trackDependencyChange( - changes: IChangeInfo[], - clonedProject: IPackageJson, - projectVersionChanged: boolean, - updatedDependentProject: IPackageJson, - oldDependencyVersion: string, - newDependencyVersion: string - ): void { - if (!semver.satisfies(updatedDependentProject.version, oldDependencyVersion) && !projectVersionChanged) { - this._addChange(changes, - { - changeType: ChangeType.patch, - packageName: clonedProject.name - } - ); - } - - // If current version is not a prerelease version and new dependency is also not a prerelease version, - // add change entry. Otherwise, too many changes will be created for frequent releases. - if (!this._isPrerelease(updatedDependentProject.version) && !this._isPrerelease(clonedProject.version)) { - this._addChange(changes, - { - changeType: ChangeType.dependency, - comment: `Dependency ${updatedDependentProject.name} version bump from ${oldDependencyVersion}` + - ` to ${newDependencyVersion}.`, - packageName: clonedProject.name - } - ); - } - } - - private _addChange(changes: IChangeInfo[], newChange: IChangeInfo): void { - const exists: boolean = changes.some((changeInfo) => { - return (changeInfo.author === newChange.author && - changeInfo.changeType === newChange.changeType && - changeInfo.comment === newChange.comment && - changeInfo.commit === newChange.commit && - changeInfo.packageName === newChange.packageName && - changeInfo.type === newChange.type - ); - }); - if (!exists) { - changes.push(newChange); - } - } - - private _updatePackageJsonFiles(): void { - this._updatedProjects.forEach((newPackageJson, packageName) => { - const rushProject: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName(packageName); - // Update package.json - if (rushProject) { - const packagePath: string = path.join(rushProject.projectFolder, FileConstants.PackageJson); - JsonFile.save(newPackageJson, packagePath, { updateExistingFile: true }); - } - }); - } - - private _createChangeInfo(newPackageJson: IPackageJson, - rushProject: RushConfigurationProject - ): IChangeInfo { - return { - changeType: ChangeType.none, - newVersion: newPackageJson.version, - packageName: newPackageJson.name, - comment: '' - }; - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/base/BaseLinkManager.ts b/apps/rush-lib/src/logic/base/BaseLinkManager.ts deleted file mode 100644 index 406a196b0ba..00000000000 --- a/apps/rush-lib/src/logic/base/BaseLinkManager.ts +++ /dev/null @@ -1,214 +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 colors from 'colors'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; - -import { FileSystem, IFileSystemCreateLinkOptions, InternalError } from '@rushstack/node-core-library'; - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { Utilities } from '../../utilities/Utilities'; -import { Stopwatch } from '../../utilities/Stopwatch'; -import { BasePackage } from './BasePackage'; -import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; - -export enum SymlinkKind { - File, - Directory -} - -export interface IBaseLinkManagerCreateSymlinkOptions extends IFileSystemCreateLinkOptions { - symlinkKind: SymlinkKind; -} - -export abstract class BaseLinkManager { - protected _rushConfiguration: RushConfiguration; - - public constructor(rushConfiguration: RushConfiguration) { - this._rushConfiguration = rushConfiguration; - } - - protected static _createSymlink(options: IBaseLinkManagerCreateSymlinkOptions): void { - const newLinkFolder: string = path.dirname(options.newLinkPath); - FileSystem.ensureFolder(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( - fs.realpathSync(newLinkFolder), - options.linkTargetPath - ); - } - - if (process.platform === 'win32') { - 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 - }); - } else { - // For files, we use a Windows "hard link", because creating a symbolic link requires - // administrator permission. - - // NOTE: We cannot use the relative path for hard links - FileSystem.createHardLink({ - linkTargetPath: options.linkTargetPath, - newLinkPath: options.newLinkPath - }); - } - } 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 - }); - } else { - FileSystem.createSymbolicLinkFile({ - linkTargetPath: targetPath, - newLinkPath: options.newLinkPath - }); - } - } - } - - /** - * For a Package object that represents a top-level Rush project folder - * (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 { - const localModuleFolder: string = path.join(localPackage.folderPath, 'node_modules'); - - // Sanity check - if (localPackage.parent) { - throw new Error('The provided package is not a top-level project'); - } - - // The root-level folder is the project itself, so we simply delete its node_modules - // to start clean - console.log('Purging ' + localModuleFolder); - Utilities.dangerouslyDeletePath(localModuleFolder); - - if (localPackage.children.length > 0) { - 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.readFolder(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: fs.Stats = FileSystem.getLinkStatistics(linkTarget); - - if (linkStats.isSymbolicLink()) { - - const targetStats: fs.Stats = 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); - } - } - } - - /** - * Creates node_modules symlinks for all Rush projects defined in the RushConfiguration. - * @param force - Normally the operation will be skipped if the links are already up to date; - * if true, this option forces the links to be recreated. - */ - public async createSymlinksForProjects(force: boolean): Promise { - if (!force) { - if (FileSystem.exists(this._rushConfiguration.rushLinkJsonFilename)) { - console.log(colors.green(`Skipping linking -- everything is already up to date.`)); - return; - } - } - - console.log('Linking projects together...'); - const stopwatch: Stopwatch = Stopwatch.start(); - - // Delete the flag file if it exists; if we get interrupted, this will ensure that - // a full "rush link" is required next time - Utilities.deleteFile(this._rushConfiguration.rushLinkJsonFilename); - - await this._linkProjects() - - stopwatch.stop(); - console.log(os.EOL + colors.green(`Linking finished successfully. (${stopwatch.toString()})`)); - console.log(os.EOL + 'Next you should probably run "rush build" or "rush rebuild"'); - } - - protected abstract _linkProjects(): Promise; -} diff --git a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts deleted file mode 100644 index 171090e0c29..00000000000 --- a/apps/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ /dev/null @@ -1,157 +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 colors from 'colors'; -import * as semver from 'semver'; -import { PackageName, FileSystem } from '@rushstack/node-core-library'; - -import { RushConstants } from '../../logic/RushConstants'; -import { DependencySpecifier } from '../DependencySpecifier'; - -/** - * This class is a parser for both npm's npm-shrinkwrap.json and pnpm's pnpm-lock.yaml file formats. - */ -export abstract class BaseShrinkwrapFile { - protected _alreadyWarnedSpecs: Set = new Set(); - - protected static tryGetValue(dictionary: { [key2: string]: T }, key: string): T | undefined { - if (dictionary.hasOwnProperty(key)) { - return dictionary[key]; - } - return undefined; - } - - /** - * Serializes and saves the shrinkwrap file to specified location - */ - public save(filePath: string): void { - FileSystem.writeFile(filePath, this.serialize()); - } - - /** - * Returns true if the shrinkwrap file includes a top-level package that would satisfy the specified - * package name and SemVer version range - * - * @virtual - */ - public hasCompatibleTopLevelDependency(dependencySpecifier: DependencySpecifier): boolean { - const shrinkwrapDependency: DependencySpecifier | undefined - = this.getTopLevelDependencyVersion(dependencySpecifier.packageName); - if (!shrinkwrapDependency) { - return false; - } - - return this._checkDependencyVersion(dependencySpecifier, shrinkwrapDependency); - } - - /** - * Returns true if the shrinkwrap file includes a package that would satisfying the specified - * package name and SemVer version range. By default, the dependencies are resolved by looking - * at the root of the node_modules folder described by the shrinkwrap file. However, if - * tempProjectName is specified, then the resolution will start in that subfolder. - * - * Consider this example: - * - * - node_modules\ - * - temp-project\ - * - lib-a@1.2.3 - * - lib-b@1.0.0 - * - lib-b@2.0.0 - * - * In this example, hasCompatibleDependency("lib-b", ">= 1.1.0", "temp-project") would fail - * because it finds lib-b@1.0.0 which does not satisfy the pattern ">= 1.1.0". - * - * @virtual - */ - public tryEnsureCompatibleDependency(dependencySpecifier: DependencySpecifier, tempProjectName: string): boolean { - const shrinkwrapDependency: DependencySpecifier | undefined = - this.tryEnsureDependencyVersion(dependencySpecifier, tempProjectName); - if (!shrinkwrapDependency) { - return false; - } - - return this._checkDependencyVersion(dependencySpecifier, shrinkwrapDependency); - } - - /** - * Returns the list of temp projects defined in this file. - * Example: [ '@rush-temp/project1', '@rush-temp/project2' ] - * - * @virtual - */ - public abstract getTempProjectNames(): ReadonlyArray; - - /** @virtual */ - protected abstract tryEnsureDependencyVersion(dependencySpecifier: DependencySpecifier, - tempProjectName: string): DependencySpecifier | undefined; - - /** @virtual */ - protected abstract getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined; - - /** @virtual */ - protected abstract serialize(): string; - - protected _getTempProjectNames(dependencies: { [key: string]: {} } ): ReadonlyArray { - const result: string[] = []; - for (const key of Object.keys(dependencies)) { - // If it starts with @rush-temp, then include it: - if (PackageName.getScope(key) === RushConstants.rushTempNpmScope) { - result.push(key); - } - } - result.sort(); // make the result deterministic - return result; - } - - private _checkDependencyVersion(projectDependency: DependencySpecifier, - shrinkwrapDependency: DependencySpecifier): boolean { - - let normalizedProjectDependency: DependencySpecifier = projectDependency; - let normalizedShrinkwrapDependency: DependencySpecifier = shrinkwrapDependency; - - // Special handling for NPM package aliases such as this: - // - // "dependencies": { - // "alias-name": "npm:target-name@^1.2.3" - // } - // - // In this case, the shrinkwrap file will have a key equivalent to "npm:target-name@1.2.5", - // and so we need to unwrap the target and compare "1.2.5" with "^1.2.3". - if (projectDependency.specifierType === 'alias') { - // Does the shrinkwrap install it as an alias? - if (shrinkwrapDependency.specifierType === 'alias') { - // Does the shrinkwrap have the right package name? - if (projectDependency.packageName === shrinkwrapDependency.packageName) { - // Yes, the aliases match, so let's compare their targets in the logic below - normalizedProjectDependency = projectDependency.aliasTarget!; - normalizedShrinkwrapDependency = shrinkwrapDependency.aliasTarget!; - } else { - // If the names are different, then it's a mismatch - return false; - } - } else { - // A non-alias cannot satisfy an alias dependency; at least, let's avoid that idea - return false; - } - } - - switch (normalizedProjectDependency.specifierType) { - case 'version': - case 'range': - return semver.satisfies(normalizedShrinkwrapDependency.versionSpecifier, - normalizedProjectDependency.versionSpecifier); - default: - // For other version specifier types like "file:./blah.tgz" or "git://github.com/npm/cli.git#v1.0.27" - // we allow the installation to continue but issue a warning. The "rush install" checks will not work - // correctly. - - // Only warn once for each versionSpecifier - if (!this._alreadyWarnedSpecs.has(projectDependency.versionSpecifier)) { - this._alreadyWarnedSpecs.add(projectDependency.versionSpecifier); - console.log(colors.yellow(`WARNING: Not validating ${projectDependency.specifierType}-based` - + ` specifier: "${projectDependency.versionSpecifier}"`)); - } - return true; - } - } -} diff --git a/apps/rush-lib/src/logic/npm/NpmLinkManager.ts b/apps/rush-lib/src/logic/npm/NpmLinkManager.ts deleted file mode 100644 index 58d669a8cac..00000000000 --- a/apps/rush-lib/src/logic/npm/NpmLinkManager.ts +++ /dev/null @@ -1,326 +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 colors from 'colors'; -import * as os from 'os'; -import * as path from 'path'; -import * as semver from 'semver'; -import * as tar from 'tar'; -import readPackageTree = require('read-package-tree'); - -import { - JsonFile, - PackageName, - FileSystem, - FileConstants, - LegacyAdapters -} from '@rushstack/node-core-library'; - -import { RushConstants } from '../../logic/RushConstants'; -import { IRushLinkJson } from '../../api/RushConfiguration'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { Utilities } from '../../utilities/Utilities'; -import { - NpmPackage, - IResolveOrCreateResult, - PackageDependencyKind -} from './NpmPackage'; -import { PackageLookup } from '../PackageLookup'; -import { - BaseLinkManager, - SymlinkKind -} from '../base/BaseLinkManager'; - -interface IQueueItem { - // A project from somewhere under "common/temp/node_modules" - commonPackage: NpmPackage; - - // A symlinked virtual package that we will create somewhere under "this-project/node_modules" - localPackage: NpmPackage; - - // If we encounter a dependency listed in cyclicDependencyProjects, this will be set to the root - // of the localPackage subtree where we will stop creating local links. - cyclicSubtreeRoot: NpmPackage | undefined; -} - -export class NpmLinkManager extends BaseLinkManager { - protected async _linkProjects(): Promise { - const npmPackage: readPackageTree.Node = ( - await LegacyAdapters.convertCallbackToPromise( - readPackageTree, - this._rushConfiguration.commonTempFolder - ) - ); - - const commonRootPackage: NpmPackage = NpmPackage.createFromNpm(npmPackage); - - const commonPackageLookup: PackageLookup = new PackageLookup(); - commonPackageLookup.loadTree(commonRootPackage); - - const rushLinkJson: IRushLinkJson = { - localLinks: {} - }; - - for (const rushProject of this._rushConfiguration.projects) { - console.log(os.EOL + 'LINKING: ' + rushProject.packageName); - this._linkProject(rushProject, commonRootPackage, commonPackageLookup, rushLinkJson); - } - - console.log(`Writing "${this._rushConfiguration.rushLinkJsonFilename}"`); - JsonFile.save(rushLinkJson, this._rushConfiguration.rushLinkJsonFilename); - } - - /** - * This is called once for each local project from Rush.json. - * @param project The local project that we will create symlinks for - * @param commonRootPackage The common/temp/package.json package - * @param commonPackageLookup A dictionary for finding packages under common/temp/node_modules - * @param rushConfiguration The rush.json file contents - * @param rushLinkJson The common/temp/rush-link.json output file - * @param options Command line options for "rush link" - */ - private _linkProject( - project: RushConfigurationProject, - commonRootPackage: NpmPackage, - commonPackageLookup: PackageLookup, - rushLinkJson: IRushLinkJson): void { - - let commonProjectPackage: NpmPackage | undefined = - commonRootPackage.getChildByName(project.tempProjectName) as NpmPackage; - if (!commonProjectPackage) { - // Normally we would expect the temp project to have been installed into the common\node_modules - // folder. However, if it was recently added, "rush install" doesn't technically require - // this, as long as its dependencies can be found at the root of the NPM shrinkwrap file. - // This avoids the need to run "rush generate" unnecessarily. - - // Example: "project1" - const unscopedTempProjectName: string = PackageName.getUnscopedName(project.tempProjectName); - - // Example: "C:\MyRepo\common\temp\projects\project1 - const extractedFolder: string = path.join(this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName, unscopedTempProjectName); - - // Example: "C:\MyRepo\common\temp\projects\project1.tgz" - const tarballFile: string = path.join(this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName, unscopedTempProjectName + '.tgz'); - - // Example: "C:\MyRepo\common\temp\projects\project1\package.json" - const packageJsonFilename: string = path.join(extractedFolder, 'package', FileConstants.PackageJson); - - Utilities.createFolderWithRetry(extractedFolder); - tar.extract({ - cwd: extractedFolder, - file: tarballFile, - sync: true - }); - - // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp\project1" - const installFolderName: string = path.join(this._rushConfiguration.commonTempFolder, - RushConstants.nodeModulesFolderName, RushConstants.rushTempNpmScope, unscopedTempProjectName); - - commonProjectPackage = NpmPackage.createVirtualTempPackage(packageJsonFilename, installFolderName); - - // remove the extracted tarball contents - FileSystem.deleteFile(packageJsonFilename); - FileSystem.deleteFile(extractedFolder); - - commonRootPackage.addChild(commonProjectPackage); - } - - // TODO: Validate that the project's package.json still matches the common folder - const localProjectPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( - project.packageJsonEditor.name, - commonProjectPackage.version, - commonProjectPackage.dependencies, - project.projectFolder - ); - - const queue: IQueueItem[] = []; - queue.push({ - commonPackage: commonProjectPackage, - localPackage: localProjectPackage, - cyclicSubtreeRoot: undefined - }); - - for (;;) { - const queueItem: IQueueItem | undefined = queue.shift(); - if (!queueItem) { - break; - } - - // A project from somewhere under "common/temp/node_modules" - const commonPackage: NpmPackage = queueItem.commonPackage; - - // A symlinked virtual package somewhere under "this-project/node_modules", - // where "this-project" corresponds to the "project" parameter for linkProject(). - const localPackage: NpmPackage = queueItem.localPackage; - - // If we encounter a dependency listed in cyclicDependencyProjects, this will be set to the root - // of the localPackage subtree where we will stop creating local links. - const cyclicSubtreeRoot: NpmPackage | undefined = queueItem.cyclicSubtreeRoot; - - // NOTE: It's important that this traversal follows the dependencies in the Common folder, - // because for Rush projects this will be the union of - // devDependencies / dependencies / optionalDependencies. - for (const dependency of commonPackage.dependencies) { - let startingCyclicSubtree: boolean = false; - - // Should this be a "local link" to a top-level Rush project (i.e. versus a regular link - // into the Common folder)? - const matchedRushPackage: RushConfigurationProject | undefined = - this._rushConfiguration.getProjectByName(dependency.name); - - if (matchedRushPackage) { - const matchedVersion: string = matchedRushPackage.packageJsonEditor.version; - - // The dependency name matches an Rush project, but are there any other reasons not - // to create a local link? - if (cyclicSubtreeRoot) { - // DO NOT create a local link, because this is part of an existing - // cyclicDependencyProjects subtree - } else if (project.cyclicDependencyProjects.has(dependency.name)) { - // DO NOT create a local link, because we are starting a new - // cyclicDependencyProjects subtree - startingCyclicSubtree = true; - } else if (dependency.kind !== PackageDependencyKind.LocalLink - && !semver.satisfies(matchedVersion, dependency.versionRange)) { - // DO NOT create a local link, because the local project's version isn't SemVer compatible. - - // (Note that in order to make version bumping work as expected, we ignore SemVer for - // immediate dependencies of top-level projects, indicated by PackageDependencyKind.LocalLink. - // Is this wise?) - - console.log(colors.yellow(`Rush will not locally link ${dependency.name} for ${localPackage.name}` - + ` because the requested version "${dependency.versionRange}" is incompatible` - + ` with the local version ${matchedVersion}`)); - } else { - // Yes, it is compatible, so create a symlink to the Rush project. - - // If the link is coming from our top-level Rush project, then record a - // build dependency in rush-link.json: - if (localPackage === localProjectPackage) { - let localLinks: string[] = rushLinkJson.localLinks[localPackage.name]; - if (!localLinks) { - localLinks = []; - rushLinkJson.localLinks[localPackage.name] = localLinks; - } - localLinks.push(dependency.name); - } - - // Is the dependency already resolved? - const resolution: IResolveOrCreateResult = localPackage.resolveOrCreate(dependency.name); - - if (!resolution.found || resolution.found.version !== matchedVersion) { - // We did not find a suitable match, so place a new local package that - // symlinks to the Rush project - const newLocalFolderPath: string = path.join( - resolution.parentForCreate!.folderPath, 'node_modules', dependency.name); - - const newLocalPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( - dependency.name, - matchedVersion, - // Since matchingRushProject does not have a parent, its dependencies are - // guaranteed to be already fully resolved inside its node_modules folder. - [], - newLocalFolderPath - ); - - newLocalPackage.symlinkTargetFolderPath = matchedRushPackage.projectFolder; - - resolution.parentForCreate!.addChild(newLocalPackage); - - // (There are no dependencies, so we do not need to push it onto the queue.) - } - - continue; - } - } - - // We can't symlink to an Rush project, so instead we will symlink to a folder - // under the "Common" folder - const commonDependencyPackage: NpmPackage | undefined = commonPackage.resolve(dependency.name); - if (commonDependencyPackage) { - // This is the version that was chosen when "npm install" ran in the common folder - const effectiveDependencyVersion: string | undefined = commonDependencyPackage.version; - - // Is the dependency already resolved? - let resolution: IResolveOrCreateResult; - if (!cyclicSubtreeRoot || !matchedRushPackage) { - // Perform normal module resolution. - resolution = localPackage.resolveOrCreate(dependency.name); - } else { - // We are inside a cyclicDependencyProjects subtree (i.e. cyclicSubtreeRoot != undefined), - // and the dependency is a local project (i.e. matchedRushPackage != undefined), so - // we use a special module resolution strategy that places everything under the - // cyclicSubtreeRoot. - resolution = localPackage.resolveOrCreate(dependency.name, cyclicSubtreeRoot); - } - - if (!resolution.found || resolution.found.version !== effectiveDependencyVersion) { - // We did not find a suitable match, so place a new local package - - const newLocalFolderPath: string = path.join( - resolution.parentForCreate!.folderPath, 'node_modules', commonDependencyPackage.name); - - const newLocalPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( - commonDependencyPackage.name, - commonDependencyPackage.version, - commonDependencyPackage.dependencies, - newLocalFolderPath - ); - - const commonPackageFromLookup: NpmPackage | undefined = - commonPackageLookup.getPackage(newLocalPackage.nameAndVersion) as NpmPackage; - if (!commonPackageFromLookup) { - throw new Error(`The ${localPackage.name}@${localPackage.version} package was not found` - + ` in the common folder`); - } - newLocalPackage.symlinkTargetFolderPath = commonPackageFromLookup.folderPath; - - let newCyclicSubtreeRoot: NpmPackage | undefined = cyclicSubtreeRoot; - if (startingCyclicSubtree) { - // If we are starting a new subtree, then newLocalPackage will be its root - // NOTE: cyclicSubtreeRoot is guaranteed to be undefined here, since we never start - // a new tree inside an existing tree - newCyclicSubtreeRoot = newLocalPackage; - } - - resolution.parentForCreate!.addChild(newLocalPackage); - queue.push({ - commonPackage: commonDependencyPackage, - localPackage: newLocalPackage, - cyclicSubtreeRoot: newCyclicSubtreeRoot - }); - } - } else { - if (dependency.kind !== PackageDependencyKind.Optional) { - throw new Error(`The dependency "${dependency.name}" needed by "${localPackage.name}"` - + ` was not found in the common folder -- do you need to run "rush install"?`); - } else { - console.log('Skipping optional dependency: ' + dependency.name); - } - } - } - } - - // When debugging, you can uncomment this line to dump the data structure - // to the console: - // localProjectPackage.printTree(); - - NpmLinkManager._createSymlinksForTopLevelProject(localProjectPackage); - - // Also symlink the ".bin" folder - if (localProjectPackage.children.length > 0) { - const commonBinFolder: string = path.join(this._rushConfiguration.commonTempFolder, 'node_modules', '.bin'); - const projectBinFolder: string = path.join(localProjectPackage.folderPath, 'node_modules', '.bin'); - - if (FileSystem.exists(commonBinFolder)) { - NpmLinkManager._createSymlink({ - linkTargetPath: commonBinFolder, - newLinkPath: projectBinFolder, - symlinkKind: SymlinkKind.Directory - }); - } - } - } -} diff --git a/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts b/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts deleted file mode 100644 index 8ac80a66539..00000000000 --- a/apps/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts +++ /dev/null @@ -1,114 +0,0 @@ -import * as os from 'os'; - -import { - JsonFile, - FileSystem -} from '@rushstack/node-core-library'; - -import { - BaseShrinkwrapFile -} from '../base/BaseShrinkwrapFile'; -import { DependencySpecifier } from '../DependencySpecifier'; - -interface INpmShrinkwrapDependencyJson { - version: string; - from: string; - resolved: string; - dependencies: { [dependency: string]: INpmShrinkwrapDependencyJson }; -} - -interface INpmShrinkwrapJson { - name: string; - version: string; - dependencies: { [dependency: string]: INpmShrinkwrapDependencyJson }; -} - -export class NpmShrinkwrapFile extends BaseShrinkwrapFile { - private _shrinkwrapJson: INpmShrinkwrapJson; - - private constructor(shrinkwrapJson: INpmShrinkwrapJson) { - super(); - this._shrinkwrapJson = shrinkwrapJson; - - // Normalize the data - if (!this._shrinkwrapJson.version) { - this._shrinkwrapJson.version = ''; - } - if (!this._shrinkwrapJson.name) { - this._shrinkwrapJson.name = ''; - } - if (!this._shrinkwrapJson.dependencies) { - this._shrinkwrapJson.dependencies = { }; - } - } - - public static loadFromFile(shrinkwrapJsonFilename: string): NpmShrinkwrapFile | undefined { - let data: string | undefined = undefined; - try { - if (!FileSystem.exists(shrinkwrapJsonFilename)) { - return undefined; // file does not exist - } - - // We don't use JsonFile/jju here because shrinkwrap.json is a special NPM file format - // and typically very large, so we want to load it the same way that NPM does. - data = FileSystem.readFile(shrinkwrapJsonFilename); - if (data.charCodeAt(0) === 0xFEFF) { // strip BOM - data = data.slice(1); - } - - return new NpmShrinkwrapFile(JSON.parse(data)); - } catch (error) { - throw new Error(`Error reading "${shrinkwrapJsonFilename}":` + os.EOL + ` ${error.message}`); - } - } - - /** @override */ - public getTempProjectNames(): ReadonlyArray { - return this._getTempProjectNames(this._shrinkwrapJson.dependencies); - } - - /** @override */ - protected serialize(): string { - return JsonFile.stringify(this._shrinkwrapJson); - } - - /** @override */ - protected getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { - // First, check under tempProjectName, as this is the first place "rush link" looks. - const dependencyJson: INpmShrinkwrapDependencyJson | undefined = - NpmShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, dependencyName); - - if (!dependencyJson) { - return undefined; - } - - return new DependencySpecifier(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(dependencySpecifier: DependencySpecifier, - tempProjectName: string): DependencySpecifier | undefined { - - // First, check under tempProjectName, as this is the first place "rush link" looks. - let dependencyJson: INpmShrinkwrapDependencyJson | undefined = undefined; - - const tempDependency: INpmShrinkwrapDependencyJson | undefined = NpmShrinkwrapFile.tryGetValue( - this._shrinkwrapJson.dependencies, tempProjectName); - if (tempDependency && tempDependency.dependencies) { - dependencyJson = NpmShrinkwrapFile.tryGetValue(tempDependency.dependencies, dependencySpecifier.packageName); - } - - // Otherwise look at the root of the shrinkwrap file - if (!dependencyJson) { - return this.getTopLevelDependencyVersion(dependencySpecifier.packageName); - } - - return new DependencySpecifier(dependencySpecifier.packageName, dependencyJson.version); - } - -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts deleted file mode 100644 index 3be5c863252..00000000000 --- a/apps/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ /dev/null @@ -1,347 +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'; -import * as path from 'path'; -import uriEncode = require('strict-uri-encode'); -import pnpmLinkBins from '@pnpm/link-bins'; -import * as semver from 'semver'; -import * as colors from 'colors'; - -import { - JsonFile, - Text, - PackageName, - FileSystem, - FileConstants, - InternalError -} from '@rushstack/node-core-library'; - -import { - BaseLinkManager -} from '../base/BaseLinkManager'; -import { BasePackage } from '../base/BasePackage'; -import { RushConstants } from '../../logic/RushConstants'; -import { IRushLinkJson } from '../../api/RushConfiguration'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { PnpmShrinkwrapFile, IPnpmShrinkwrapDependencyYaml } from './PnpmShrinkwrapFile'; -import { PnpmProjectDependencyManifest } from './PnpmProjectDependencyManifest'; - -// special flag for debugging, will print extra diagnostic information, -// but comes with performance cost -const DEBUG: boolean = false; - -export class PnpmLinkManager extends BaseLinkManager { - - private readonly _pnpmVersion: semver.SemVer = new semver.SemVer(this._rushConfiguration.packageManagerToolVersion); - - protected async _linkProjects(): Promise { - const rushLinkJson: IRushLinkJson = { - localLinks: {} - }; - - // 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.tempShrinkwrapFilename - ); - - if (!pnpmShrinkwrapFile) { - throw new InternalError(`Cannot load shrinkwrap at "${this._rushConfiguration.tempShrinkwrapFilename}"`); - } - - for (const rushProject of this._rushConfiguration.projects) { - console.log(os.EOL + 'LINKING: ' + rushProject.packageName); - await this._linkProject(rushProject, rushLinkJson, pnpmShrinkwrapFile); - } - - console.log(`Writing "${this._rushConfiguration.rushLinkJsonFilename}"`); - JsonFile.save(rushLinkJson, this._rushConfiguration.rushLinkJsonFilename); - } - - /** - * This is called once for each local project from Rush.json. - * @param project The local project that we will create symlinks for - * @param rushLinkJson The common/temp/rush-link.json output file - */ - private async _linkProject( - project: RushConfigurationProject, - rushLinkJson: IRushLinkJson, - pnpmShrinkwrapFile: PnpmShrinkwrapFile - ): Promise { - - // first, read the temp package.json information - - // Example: "project1" - const unscopedTempProjectName: string = PackageName.getUnscopedName(project.tempProjectName); - - // Example: "C:\MyRepo\common\temp\projects\project1 - const extractedFolder: string = path.join(this._rushConfiguration.commonTempFolder, - RushConstants.rushTempProjectsFolderName, unscopedTempProjectName); - - // Example: "C:\MyRepo\common\temp\projects\project1\package.json" - const packageJsonFilename: string = path.join(extractedFolder, FileConstants.PackageJson); - - // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp\project1" - const installFolderName: string = path.join( - this._rushConfiguration.commonTempFolder, - RushConstants.nodeModulesFolderName, - RushConstants.rushTempNpmScope, - unscopedTempProjectName - ); - - const commonPackage: BasePackage = BasePackage.createVirtualTempPackage(packageJsonFilename, installFolderName); - - const localPackage: BasePackage = BasePackage.createLinkedPackage( - project.packageJsonEditor.name, - commonPackage.version, - project.projectFolder - ); - - // now that we have the temp package.json, we can go ahead and link up all the direct dependencies - - // first, start with the rush dependencies, we just need to link to the project folder - for (const dependencyName of Object.keys(commonPackage.packageJson!.rushDependencies || {})) { - const matchedRushPackage: RushConfigurationProject | undefined = - this._rushConfiguration.getProjectByName(dependencyName); - - if (matchedRushPackage) { - // We found a suitable match, so place a new local package that - // symlinks to the Rush project - const matchedVersion: string = matchedRushPackage.packageJsonEditor.version; - - let localLinks: string[] = rushLinkJson.localLinks[localPackage.name]; - if (!localLinks) { - localLinks = []; - rushLinkJson.localLinks[localPackage.name] = localLinks; - } - localLinks.push(dependencyName); - - // e.g. "C:\my-repo\project-a\node_modules\project-b" if project-b is a rush dependency of project-a - const newLocalFolderPath: string = path.join(localPackage.folderPath, 'node_modules', dependencyName); - - const newLocalPackage: BasePackage = BasePackage.createLinkedPackage( - dependencyName, - matchedVersion, - newLocalFolderPath - ); - - newLocalPackage.symlinkTargetFolderPath = matchedRushPackage.projectFolder; - localPackage.children.push(newLocalPackage); - } else { - throw new InternalError( - `Cannot find dependency "${dependencyName}" for "${project.packageName}" in the Rush configuration` - ); - } - } - - // Iterate through all the regular dependencies - - // With npm, it's possible for two different projects to have dependencies on - // the same version of the same library, but end up with different implementations - // of that library, if the library is installed twice and with different secondary - // dependencies.The NpmLinkManager recursively links dependency folders to try to - // honor this. Since PNPM always uses the same physical folder to represent a given - // version of a library, we only need to link directly to the folder that PNPM has chosen, - // and it will have a consistent set of secondary dependencies. - - // each of these dependencies should be linked in a special folder that pnpm - // creates for the installed version of each .TGZ package, all we need to do - // is re-use that symlink in order to get linked to whatever PNPM thought was - // appropriate. This folder is usually something like: - // C:\{uri-encoed-path-to-tgz}\node_modules\{package-name} - - // e.g.: - // file:projects/bentleyjs-core.tgz - // file:projects/build-tools.tgz_dc21d88642e18a947127a751e00b020a - // file:projects/imodel-from-geojson.tgz_request@2.88.0 - const tempProjectDependencyKey: string | undefined = pnpmShrinkwrapFile.getTempProjectDependencyKey( - project.tempProjectName - ); - - if (!tempProjectDependencyKey) { - throw new Error(`Cannot get dependency key for temp project: ${project.tempProjectName}`); - } - // e.g.: file:projects/project-name.tgz - const tarballEntry: string | undefined = pnpmShrinkwrapFile.getTarballPath(tempProjectDependencyKey); - - if (!tarballEntry) { - throw new InternalError(`Cannot find tarball path for "${project.tempProjectName}" in shrinkwrap.`); - } - - // e.g.: projects\api-documenter.tgz - const relativePathToTgzFile: string | undefined = tarballEntry.slice(`file:`.length); - - // e.g.: C:\wbt\common\temp\projects\api-documenter.tgz - const absolutePathToTgzFile: string = path.resolve(this._rushConfiguration.commonTempFolder, relativePathToTgzFile); - - // The folder name in `.local` is constructed as: - // UriEncode(absolutePathToTgzFile) + _suffix - // - // Note that _suffix is not encoded. The tarball attribute of the package 'file:projects/project-name.tgz_suffix' - // holds the tarball path 'file:projects/project-name.tgz', which can be used for the constructing the folder name. - // - // '_suffix' is extracted by stripping the tarball path from top level dependency value. - // tarball path = 'file:projects/project-name.tgz' - // top level dependency = 'file:projects/project-name.tgz_suffix' - - // e.g.: - // '' [empty string] - // _jsdom@11.12.0 - // _2a665c89609864b4e75bc5365d7f8f56 - const folderNameSuffix: string = tarballEntry && tarballEntry.length < tempProjectDependencyKey.length - ? tempProjectDependencyKey.slice(tarballEntry.length) - : ''; - - // e.g.: - // C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz - // C%3A%2Fdev%2Fimodeljs%2Fimodeljs%2Fcommon%2Ftemp%2Fprojects%2Fpresentation-integration-tests.tgz_jsdom@11.12.0 - // C%3A%2Fdev%2Fimodeljs%2Fimodeljs%2Fcommon%2Ftemp%2Fprojects%2Fbuild-tools.tgz_2a665c89609864b4e75bc5365d7f8f56 - const folderNameInLocalInstallationRoot: string = uriEncode(Text.replaceAll(absolutePathToTgzFile, path.sep, '/')) + - folderNameSuffix; - - // e.g.: C:\wbt\common\temp\node_modules\.local\C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz\node_modules - - const pathToLocalInstallation: string = this._getPathToLocalInstallation(folderNameInLocalInstallationRoot); - - const parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml | undefined = - pnpmShrinkwrapFile.getShrinkwrapEntryFromTempProjectDependencyKey(tempProjectDependencyKey); - if (!parentShrinkwrapEntry) { - throw new InternalError( - 'Cannot find shrinkwrap entry using dependency key for temp project: ' + - `${project.tempProjectName}`); - } - - const pnpmProjectDependencyManifest: PnpmProjectDependencyManifest = new PnpmProjectDependencyManifest({ - pnpmShrinkwrapFile, - project - }); - - for (const dependencyName of Object.keys(commonPackage.packageJson!.dependencies || {})) { - const newLocalPackage: BasePackage = this._createLocalPackageForDependency( - pnpmProjectDependencyManifest, - project, - parentShrinkwrapEntry, - localPackage, - pathToLocalInstallation, - dependencyName)!; - localPackage.addChild(newLocalPackage); - } - - // TODO: Rush does not currently handle optional dependencies of projects. This should be uncommented when - // support is added - // for (const dependencyName of Object.keys(commonPackage.packageJson!.optionalDependencies || {})) { - // const newLocalPackage: BasePackage | undefined = this._createLocalPackageForDependency( - // pnpmProjectDependencyManifest, - // project, - // parentShrinkwrapEntry, - // localPackage, - // pathToLocalInstallation, - // dependencyName, - // true); // isOptional - // if (newLocalPackage) { - // localPackage.addChild(newLocalPackage); - // } - // } - - if (DEBUG) { - localPackage.printTree(); - } - - PnpmLinkManager._createSymlinksForTopLevelProject(localPackage); - - if (!this._rushConfiguration.experimentsConfiguration.configuration.legacyIncrementalBuildDependencyDetection) { - pnpmProjectDependencyManifest.save(); - } else { - pnpmProjectDependencyManifest.deleteIfExists(); - } - - // Also symlink the ".bin" folder - const projectFolder: string = path.join(localPackage.folderPath, 'node_modules'); - const projectBinFolder: string = path.join(localPackage.folderPath, 'node_modules', '.bin'); - - await pnpmLinkBins( - projectFolder, - projectBinFolder, - { - warn: (msg: string) => console.warn(colors.yellow(msg)) - } - ); - } - - private _getPathToLocalInstallation(folderNameInLocalInstallationRoot: string): string { - // See https://github.com/pnpm/pnpm/releases/tag/v4.0.0 - if (this._pnpmVersion.major >= 4) { - return path.join(this._rushConfiguration.commonTempFolder, - RushConstants.nodeModulesFolderName, - '.pnpm', - 'local', - folderNameInLocalInstallationRoot, - RushConstants.nodeModulesFolderName); - } else { - return path.join(this._rushConfiguration.commonTempFolder, - RushConstants.nodeModulesFolderName, - '.local', - folderNameInLocalInstallationRoot, - RushConstants.nodeModulesFolderName); - } - } - private _createLocalPackageForDependency( - pnpmProjectDependencyManifest: PnpmProjectDependencyManifest, - project: RushConfigurationProject, - parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, - localPackage: BasePackage, - pathToLocalInstallation: string, - dependencyName: string, - isOptional: boolean = false - ): BasePackage | undefined { - // the dependency we are looking for should have already created a symlink here - - // FYI dependencyName might contain an NPM scope, here it gets converted into a filesystem folder name - // e.g. if the dependency is supi: - // "C:\wbt\common\temp\node_modules\.local\C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz\node_modules\supi" - const dependencyLocalInstallationSymlink: string = path.join( - pathToLocalInstallation, - dependencyName); - - if (!FileSystem.exists(dependencyLocalInstallationSymlink)) { - // if this occurs, it is a bug in Rush algorithm or unexpected PNPM behavior - throw new InternalError(`Cannot find installed dependency "${dependencyName}" in "${pathToLocalInstallation}"`); - } - - if (!FileSystem.getLinkStatistics(dependencyLocalInstallationSymlink).isSymbolicLink()) { - // if this occurs, it is a bug in Rush algorithm or unexpected PNPM behavior - throw new InternalError(`Dependency "${dependencyName}" is not a symlink in "${pathToLocalInstallation}`); - } - - // read the version number from the shrinkwrap entry - const version: string | undefined = isOptional - ? (parentShrinkwrapEntry.optionalDependencies || {})[dependencyName] - : (parentShrinkwrapEntry.dependencies || {})[dependencyName]; - if (!version) { - if (!isOptional) { - throw new InternalError( - `Cannot find shrinkwrap entry dependency "${dependencyName}" for temp project: ` + - `${project.tempProjectName}`); - } - return; - } - - const newLocalFolderPath: string = path.join(localPackage.folderPath, 'node_modules', dependencyName); - const newLocalPackage: BasePackage = BasePackage.createLinkedPackage( - dependencyName, - version, - newLocalFolderPath - ); - - // The dependencyLocalInstallationSymlink is just a symlink to another folder. To reduce the number of filesystem - // reads that are needed, we will link to where that symlink pointed, rather than linking to a link. - newLocalPackage.symlinkTargetFolderPath = FileSystem.getRealPath(dependencyLocalInstallationSymlink); - - if (!this._rushConfiguration.experimentsConfiguration.configuration.legacyIncrementalBuildDependencyDetection) { - pnpmProjectDependencyManifest.addDependency(newLocalPackage, parentShrinkwrapEntry); - } - - return newLocalPackage; - } -} diff --git a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts b/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts deleted file mode 100644 index f3c8d644d89..00000000000 --- a/apps/rush-lib/src/logic/pnpm/PnpmProjectDependencyManifest.ts +++ /dev/null @@ -1,267 +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 semver from 'semver'; -import { - JsonFile, - InternalError, - FileSystem -} from '@rushstack/node-core-library'; - -import { - PnpmShrinkwrapFile, - IPnpmShrinkwrapDependencyYaml, - parsePnpmDependencyKey -} from './PnpmShrinkwrapFile'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { RushConstants } from '../RushConstants'; -import { BasePackage } from '../base/BasePackage'; -import { DependencySpecifier } from '../DependencySpecifier'; - -export interface IPnpmProjectDependencyManifestOptions { - pnpmShrinkwrapFile: PnpmShrinkwrapFile; - project: RushConfigurationProject; -} - -/** - * This class handles creating the project/.rush/temp/shrinkwrap-deps.json file - * which tracks the direct and indirect dependencies that a project consumes. This is used - * to better determine which projects should be rebuilt when dependencies are updated. - */ -export class PnpmProjectDependencyManifest { - /** - * This mapping is used to map all project dependencies and all their dependencies - * to their respective dependency integrity hash. For example, if the project contains - * a dependency A which itself has a dependency on B, the mapping would look like: - * 'A@1.2.3': '{Integrity of A}', - * 'B@4.5.6': '{Integrity of B}', - * ... - */ - private _projectDependencyManifestFile: Map; - - private readonly _projectDependencyManifestFilename: string; - private readonly _pnpmShrinkwrapFile: PnpmShrinkwrapFile; - private readonly _project: RushConfigurationProject; - - public constructor(options: IPnpmProjectDependencyManifestOptions) { - this._pnpmShrinkwrapFile = options.pnpmShrinkwrapFile; - this._project = options.project; - this._projectDependencyManifestFilename = PnpmProjectDependencyManifest.getFilePathForProject(this._project); - - this._projectDependencyManifestFile = new Map(); - } - - /** - * Get the fully-qualified path to the project/.rush/temp/shrinkwrap-deps.json - * for the specified project. - */ - public static getFilePathForProject(project: RushConfigurationProject): string { - return path.join( - project.projectRushTempFolder, - RushConstants.projectDependencyManifestFilename - ); - } - - public addDependency(pkg: BasePackage, parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml): void { - if (!pkg.version) { - throw new InternalError(`Version missing from dependency ${pkg.name}`); - } - - this._addDependencyInternal(pkg.name, pkg.version, parentShrinkwrapEntry); - } - - /** - * Save the current state of the object to project/.rush/temp/shrinkwrap-deps.json - */ - public save(): void { - const file: { [specifier: string]: string } = {}; - const keys: string[] = Array.from(this._projectDependencyManifestFile.keys()).sort(); - for (const key of keys) { - file[key] = this._projectDependencyManifestFile.get(key)!; - } - - JsonFile.save( - file, - this._projectDependencyManifestFilename, - { ensureFolderExists: true } - ); - } - - /** - * If the project/.rush/temp/shrinkwrap-deps.json file exists, delete it. Otherwise, do nothing. - */ - public deleteIfExists(): void { - FileSystem.deleteFile(this._projectDependencyManifestFilename, { throwIfNotExists: false }); - } - - private _addDependencyInternal( - name: string, - version: string, - parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, - throwIfShrinkwrapEntryMissing: boolean = true - ): void { - const shrinkwrapEntry: IPnpmShrinkwrapDependencyYaml | undefined = this._pnpmShrinkwrapFile.getShrinkwrapEntry( - name, - version - ); - - if (!shrinkwrapEntry) { - if (throwIfShrinkwrapEntryMissing) { - throw new InternalError(`Unable to find dependency ${name} with version ${version} in shrinkwrap.`); - } - return; - } - - const specifier: string = `${name}@${version}`; - const integrity: string = shrinkwrapEntry.resolution.integrity; - if (this._projectDependencyManifestFile.has(specifier)) { - if (this._projectDependencyManifestFile.get(specifier) !== integrity) { - throw new Error(`Collision: ${specifier} already exists in with a different integrity`); - } - return; - } - - // Add the current dependency - this._projectDependencyManifestFile.set(specifier, integrity); - - // Add the dependencies of the dependency - for (const dependencyName in shrinkwrapEntry.dependencies) { - if (shrinkwrapEntry.dependencies.hasOwnProperty(dependencyName)) { - const dependencyVersion: string = shrinkwrapEntry.dependencies[dependencyName]; - this._addDependencyInternal(dependencyName, dependencyVersion, shrinkwrapEntry); - } - } - - // Add the optional dependencies of the dependency - for (const optionalDependencyName in shrinkwrapEntry.optionalDependencies) { - if (shrinkwrapEntry.optionalDependencies.hasOwnProperty(optionalDependencyName)) { - // Optional dependencies may not exist. Don't blow up if it can't be found - const dependencyVersion: string = shrinkwrapEntry.optionalDependencies[optionalDependencyName]; - this._addDependencyInternal( - optionalDependencyName, - dependencyVersion, - shrinkwrapEntry, - throwIfShrinkwrapEntryMissing = false); - } - } - - for (const peerDependencyName in shrinkwrapEntry.peerDependencies) { - if (shrinkwrapEntry.peerDependencies.hasOwnProperty(peerDependencyName)) { - // Peer dependencies come in the form of a semantic version range - const dependencySemVer: string = shrinkwrapEntry.peerDependencies[peerDependencyName]; - - // Check the current package to see if the dependency is already satisfied - if ( - shrinkwrapEntry.dependencies && - shrinkwrapEntry.dependencies.hasOwnProperty(peerDependencyName) - ) { - const dependencySpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( - peerDependencyName, - shrinkwrapEntry.dependencies[peerDependencyName] - ); - if (dependencySpecifier) { - if (!semver.valid(dependencySpecifier.versionSpecifier)) { - throw new InternalError( - `The version '${dependencySemVer}' of peer dependency '${peerDependencyName}' is invalid` - ); - } - continue; - } - } - - // If not, check the parent. - if ( - parentShrinkwrapEntry.dependencies && - parentShrinkwrapEntry.dependencies.hasOwnProperty(peerDependencyName) - ) { - const dependencySpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( - peerDependencyName, - parentShrinkwrapEntry.dependencies[peerDependencyName] - ); - if (dependencySpecifier) { - if (!semver.valid(dependencySpecifier.versionSpecifier)) { - throw new InternalError( - `The version '${dependencySemVer}' of peer dependency '${peerDependencyName}' is invalid` - ); - } - continue; - } - } - - // The parent doesn't have a version that satisfies the range. As a last attempt, check - // if it's been hoisted up as a top-level dependency - const topLevelDependencySpecifier: DependencySpecifier | undefined = - this._pnpmShrinkwrapFile.getTopLevelDependencyVersion(peerDependencyName); - - // Sometimes peer dependencies are hoisted but are not represented in the shrinkwrap file - // (such as when implicitlyPreferredVersions is false) so we need to find the correct key - // and add it ourselves - if (!topLevelDependencySpecifier) { - const peerDependencyKeys: { [peerDependencyName: string]: string } = - this._parsePeerDependencyKeysFromSpecifier(specifier); - if (peerDependencyKeys.hasOwnProperty(peerDependencyName)) { - this._addDependencyInternal( - peerDependencyName, - peerDependencyKeys[peerDependencyName], - shrinkwrapEntry - ); - continue; - } - } - - if (!topLevelDependencySpecifier || !semver.valid(topLevelDependencySpecifier.versionSpecifier)) { - if ( - !this._project.rushConfiguration.pnpmOptions || - !this._project.rushConfiguration.pnpmOptions.strictPeerDependencies || - ( - shrinkwrapEntry.peerDependenciesMeta && - shrinkwrapEntry.peerDependenciesMeta.hasOwnProperty(peerDependencyName) && - shrinkwrapEntry.peerDependenciesMeta[peerDependencyName].optional - ) - ) { - // We couldn't find the peer dependency, but we determined it's by design, skip this dependency... - continue; - } - throw new InternalError( - `Could not find peer dependency '${peerDependencyName}' that satisfies version '${dependencySemVer}'` - ); - } - - this._addDependencyInternal( - peerDependencyName, - this._pnpmShrinkwrapFile.getTopLevelDependencyKey(peerDependencyName)!, - shrinkwrapEntry - ); - } - } - } - - /** - * The version specifier for a dependency can sometimes come in the form of - * '{semVer}_peerDep1@1.2.3+peerDep2@4.5.6'. This is parsed and returned as a dictionary mapping - * the peer dependency to it's appropriate PNPM dependency key. - */ - private _parsePeerDependencyKeysFromSpecifier(specifier: string): { [peerDependencyName: string]: string } { - const parsedPeerDependencyKeys: { [peerDependencyName: string]: string } = {}; - - const specifierMatches: RegExpExecArray | null = /^[^_]+_(.+)$/.exec(specifier); - if (specifierMatches) { - const combinedPeerDependencies: string = specifierMatches[1]; - // Parse "eslint@6.6.0+typescript@3.6.4" --> ["eslint@6.6.0", "typescript@3.6.4"] - const peerDependencies: string[] = combinedPeerDependencies.split("+"); - for (const peerDependencySpecifier of peerDependencies) { - // Parse "eslint@6.6.0" --> "eslint", "6.6.0" - const peerMatches: RegExpExecArray | null = /^([^+@]+)@(.+)$/.exec(peerDependencySpecifier); - if (peerMatches) { - const peerDependencyName: string = peerMatches[1]; - const peerDependencyVersion: string = peerMatches[2]; - const peerDependencyKey: string = `/${peerDependencyName}/${peerDependencyVersion}`; - parsedPeerDependencyKeys[peerDependencyName] = peerDependencyKey; - } - } - } - - return parsedPeerDependencyKeys; - } -} diff --git a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts deleted file mode 100644 index 1bbf7d363e3..00000000000 --- a/apps/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ /dev/null @@ -1,456 +0,0 @@ -import * as yaml from 'js-yaml'; -import * as os from 'os'; -import * as semver from 'semver'; -import { FileSystem } from '@rushstack/node-core-library'; - -import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; -import { DependencySpecifier } from '../DependencySpecifier'; - -// This is based on PNPM's own configuration: -// https://github.com/pnpm/pnpm-shrinkwrap/blob/master/src/write.ts -const SHRINKWRAP_YAML_FORMAT: yaml.DumpOptions = { - lineWidth: 1000, - noCompatMode: true, - noRefs: true, - sortKeys: true -}; - -export interface IPeerDependenciesMetaYaml { - optional?: boolean; -} - -export interface IPnpmShrinkwrapDependencyYaml { - /** Information about the resolved package */ - resolution: { - /** The hash of the tarball, to ensure archive integrity */ - integrity: string; - /** The name of the tarball, if this was from a TGX file */ - tarball?: string; - }; - /** The list of dependencies and the resolved version */ - dependencies: { [dependency: string]: string }; - /** The list of optional dependencies and the resolved version */ - optionalDependencies: { [dependency: string]: string }; - /** The list of peer dependencies and the resolved version */ - peerDependencies: { [dependency: string]: string }; - /** - * Used to indicate optional peer dependencies, as described in this RFC: - * https://github.com/yarnpkg/rfcs/blob/master/accepted/0000-optional-peer-dependencies.md - */ - peerDependenciesMeta: { [dependency: string]: IPeerDependenciesMetaYaml }; -} - -/** - * This interface represents the raw pnpm-lock.YAML file - * Example: - * { - * "dependencies": { - * "@rush-temp/project1": "file:./projects/project1.tgz" - * }, - * "packages": { - * "file:projects/library1.tgz": { - * "dependencies: { - * "markdown": "0.5.0" - * }, - * "name": "@rush-temp/library1", - * "resolution": { - * "tarball": "file:projects/library1.tgz" - * }, - * "version": "0.0.0" - * }, - * "markdown/0.5.0": { - * "resolution": { - * "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=" - * } - * } - * }, - * "registry": "http://localhost:4873/", - * "shrinkwrapVersion": 3, - * "specifiers": { - * "@rush-temp/project1": "file:./projects/project1.tgz" - * } - * } - */ -interface IPnpmShrinkwrapYaml { - /** The list of resolved version numbers for direct dependencies */ - dependencies: { [dependency: string]: string }; - /** The description of the solved graph */ - packages: { [dependencyVersion: string]: IPnpmShrinkwrapDependencyYaml }; - /** URL of the registry which was used */ - registry: string; - /** The list of specifiers used to resolve direct dependency versions */ - specifiers: { [dependency: string]: string }; -} - -/** - * Given an encoded "dependency key" from the PNPM shrinkwrap file, this parses it into an equivalent - * DependencySpecifier. - * - * @returns a SemVer string, or undefined if the version specifier cannot be parsed - */ -export function parsePnpmDependencyKey(dependencyName: string, dependencyKey: string): DependencySpecifier | undefined { - if (!dependencyKey) { - return undefined; - } - - if (/^\w+:/.test(dependencyKey)) { - // If it starts with an NPM scheme such as "file:projects/my-app.tgz", we don't support that - return undefined; - } - - // The package name parsed from the dependency key, or dependencyName if it was omitted. - // Example: "@scope/depame" - let parsedPackageName: string; - - // The trailing portion of the dependency key that includes the version and optional peer dependency path. - // Example: "2.8.0/chai@3.5.0+sinon@1.17.7" - let parsedInstallPath: string; - - // Example: "path.pkgs.visualstudio.com/@scope/depame/1.4.0" --> 0="@scope/depame" 1="1.4.0" - // Example: "/isarray/2.0.1" --> 0="isarray" 1="2.0.1" - // Example: "/sinon-chai/2.8.0/chai@3.5.0+sinon@1.17.7" --> 0="sinon-chai" 1="2.8.0/chai@3.5.0+sinon@1.17.7" - const packageNameMatch: RegExpMatchArray | null = /^[^\/]*\/((?:@[^\/]+\/)?[^\/]+)\/(.*)$/.exec(dependencyKey); - if (packageNameMatch) { - parsedPackageName = packageNameMatch[1]; - parsedInstallPath = packageNameMatch[2]; - } else { - parsedPackageName = dependencyName; - - // Example: "23.6.0_babel-core@6.26.3" - // Example: "23.6.0" - parsedInstallPath = dependencyKey; - } - - // The SemVer value - // Example: "2.8.0" - let parsedVersionPart: string; - - // Example: "23.6.0_babel-core@6.26.3" --> "23.6.0" - // Example: "2.8.0/chai@3.5.0+sinon@1.17.7" --> "2.8.0" - const versionMatch: RegExpMatchArray | null = /^([^\/_]+)[\/_]/.exec(parsedInstallPath); - if (versionMatch) { - parsedVersionPart = versionMatch[1]; - } else { - // Example: "2.8.0" - parsedVersionPart = parsedInstallPath; - } - - // By this point, we expect parsedVersionPart to be a valid SemVer range - if (!parsedVersionPart) { - return undefined; - } - - if (!semver.valid(parsedVersionPart)) { - return undefined; - } - - // Is it an alias for a different package? - if (parsedPackageName === dependencyName) { - // No, it's a regular dependency - return new DependencySpecifier(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}`); - } -} - -export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { - /** - * The filename of the shrinkwrap file. - */ - public readonly shrinkwrapFilename: string; - - private _shrinkwrapJson: IPnpmShrinkwrapYaml; - - private constructor(shrinkwrapJson: IPnpmShrinkwrapYaml, shrinkwrapFilename: string) { - super(); - this._shrinkwrapJson = shrinkwrapJson; - this.shrinkwrapFilename = shrinkwrapFilename; - - // Normalize the data - if (!this._shrinkwrapJson.registry) { - this._shrinkwrapJson.registry = ''; - } - if (!this._shrinkwrapJson.dependencies) { - this._shrinkwrapJson.dependencies = { }; - } - if (!this._shrinkwrapJson.specifiers) { - this._shrinkwrapJson.specifiers = { }; - } - if (!this._shrinkwrapJson.packages) { - this._shrinkwrapJson.packages = { }; - } - } - - public static loadFromFile(shrinkwrapYamlFilename: string): PnpmShrinkwrapFile | undefined { - try { - if (!FileSystem.exists(shrinkwrapYamlFilename)) { - return undefined; // file does not exist - } - - // We don't use JsonFile/jju here because shrinkwrap.json is a special NPM file format - // and typically very large, so we want to load it the same way that NPM does. - const parsedData: IPnpmShrinkwrapYaml = yaml.safeLoad(FileSystem.readFile(shrinkwrapYamlFilename).toString()); - - return new PnpmShrinkwrapFile(parsedData, shrinkwrapYamlFilename); - } catch (error) { - throw new Error(`Error reading "${shrinkwrapYamlFilename}":${os.EOL} ${error.message}`); - } - } - - /** @override */ - public getTempProjectNames(): ReadonlyArray { - return this._getTempProjectNames(this._shrinkwrapJson.dependencies); - } - - /** - * Gets the path to the tarball file if the package is a tarball. - * Returns undefined if the package entry doesn't exist or the package isn't a tarball. - * Example of return value: file:projects/build-tools.tgz - */ - public getTarballPath(packageName: string): string | undefined { - const dependency: IPnpmShrinkwrapDependencyYaml = this._shrinkwrapJson.packages[packageName]; - - if (!dependency) { - return undefined; - } - - return dependency.resolution.tarball; - } - - public getTopLevelDependencyKey(dependencyName: string): string | undefined { - return BaseShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, dependencyName); - } - - /** - * Gets the version number from the list of top-level dependencies in the "dependencies" section - * of the shrinkwrap file. Sample return values: - * '2.1.113' - * '1.9.0-dev.27' - * 'file:projects/empty-webpart-project.tgz' - * undefined - * - * @override - */ - public getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { - let value: string | undefined = BaseShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, dependencyName); - if (value) { - - // Getting the top level depenedency version from a PNPM lockfile version 5.1 - // -------------------------------------------------------------------------- - // - // 1) Top-level tarball dependency entries in pnpm-lock.yaml look like: - // '@rush-temp/sp-filepicker': 'file:projects/sp-filepicker.tgz_0ec79d3b08edd81ebf49cd19ca50b3f5' - - // Then, it would be defined below: - // 'file:projects/sp-filepicker.tgz_0ec79d3b08edd81ebf49cd19ca50b3f5': - // dependencies: - // '@microsoft/load-themed-styles': 1.10.7 - // ... - // resolution: - // integrity: sha512-guuoFIc**== - // tarball: 'file:projects/sp-filepicker.tgz' - - // Here, we are interested in the part 'file:projects/sp-filepicker.tgz'. Splitting by underscores is not the - // best way to get this because file names could have underscores in them. Instead, we could use the tarball - // field in the resolution section. - - // 2) Top-level non-tarball dependency entries in pnpm-lock.yaml would look like: - // '@rushstack/set-webpack-public-path-plugin': 2.1.133 - // @microsoft/sp-build-node': 1.9.0-dev.27_typescript@2.9.2 - - // Here, we could just split by underscores and take the first part. - - // The below code is also compatible with lockfile versions < 5.1 - - const dependency: IPnpmShrinkwrapDependencyYaml = this._shrinkwrapJson.packages[value]; - - if (dependency && dependency.resolution && dependency.resolution.tarball && - value.startsWith(dependency.resolution.tarball)) { - return new DependencySpecifier(dependencyName, dependency.resolution.tarball); - } else { - const underscoreIndex: number = value.indexOf('_'); - if (underscoreIndex >= 0) { - value = value.substr(0, underscoreIndex); - } - } - - return new DependencySpecifier(dependencyName, value); - } - return undefined; - } - - /** - * The PNPM shrinkwrap file has top-level dependencies on the temp projects like this: - * - * ``` - * dependencies: - * '@rush-temp/my-app': 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0' - * packages: - * /@types/node/10.14.15: - * dev: false - * 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0': - * dev: false - * name: '@rush-temp/my-app' - * version: 0.0.0 - * ``` - * - * We refer to 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0' as the temp project dependency key - * of the temp project '@rush-temp/my-app'. - */ - public getTempProjectDependencyKey(tempProjectName: string): string | undefined { - const tempProjectDependencyKey: string | undefined = - BaseShrinkwrapFile.tryGetValue(this._shrinkwrapJson.dependencies, tempProjectName); - - if (tempProjectDependencyKey) { - return tempProjectDependencyKey; - } - - return undefined; - } - - public getShrinkwrapEntryFromTempProjectDependencyKey( - tempProjectDependencyKey: string - ): IPnpmShrinkwrapDependencyYaml | undefined { - return this._shrinkwrapJson.packages[tempProjectDependencyKey]; - } - - public getShrinkwrapEntry(name: string, version: string): IPnpmShrinkwrapDependencyYaml | undefined { - // Version can sometimes be in the form of a path that's already in the /name/version format. - const packageId: string = version.indexOf('/') !== -1 - ? version - : `/${name}/${version}`; - return this._shrinkwrapJson.packages[packageId]; - } - - /** - * Serializes the PNPM Shrinkwrap file - * - * @override - */ - protected serialize(): string { - return yaml.safeDump(this._shrinkwrapJson, SHRINKWRAP_YAML_FORMAT); - } - - /** - * 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. - * - * @override - */ - protected tryEnsureDependencyVersion(dependencySpecifier: DependencySpecifier, - tempProjectName: string): DependencySpecifier | undefined { - - // PNPM doesn't have the same advantage of NPM, where we can skip generate as long as the - // shrinkwrap file puts our dependency in either the top of the node_modules folder - // or underneath the package we are looking at. - // This is because the PNPM shrinkwrap file describes the exact links that need to be created - // to recreate the graph.. - // Because of this, we actually need to check for a version that this package is directly - // linked to. - - const packageName: string = dependencySpecifier.packageName; - - const tempProjectDependencyKey: string | undefined = this.getTempProjectDependencyKey(tempProjectName); - if (!tempProjectDependencyKey) { - return undefined; - } - - const packageDescription: IPnpmShrinkwrapDependencyYaml | undefined = - this._getPackageDescription(tempProjectDependencyKey); - if (!packageDescription) { - return undefined; - } - - if (!packageDescription.dependencies.hasOwnProperty(packageName)) { - if (dependencySpecifier.versionSpecifier) { - // this means the current temp project doesn't provide this dependency, - // however, we may be able to use a different version. we prefer the latest version - let latestVersion: string | undefined = undefined; - - for (const otherTempProject of this.getTempProjectNames()) { - const otherVersionSpecifier: DependencySpecifier | undefined = this._getDependencyVersion( - dependencySpecifier.packageName, otherTempProject); - - if (otherVersionSpecifier) { - const otherVersion: string = otherVersionSpecifier.versionSpecifier; - - if (semver.satisfies(otherVersion, dependencySpecifier.versionSpecifier)) { - if (!latestVersion || semver.gt(otherVersion, latestVersion)) { - latestVersion = otherVersion; - } - } - } - } - - if (latestVersion) { - // go ahead and fixup the shrinkwrap file to point at this - const dependencies: { [key: string]: string } | undefined = - this._shrinkwrapJson.packages[tempProjectDependencyKey].dependencies || {}; - dependencies[packageName] = latestVersion; - this._shrinkwrapJson.packages[tempProjectDependencyKey].dependencies = dependencies; - - return new DependencySpecifier(dependencySpecifier.packageName, latestVersion); - } - } - - return undefined; - } - - const dependencyKey: string = packageDescription.dependencies[packageName]; - return this._parsePnpmDependencyKey(packageName, dependencyKey); - } - - /** - * Returns the version of a dependency being used by a given project - */ - private _getDependencyVersion(dependencyName: string, tempProjectName: string): DependencySpecifier | undefined { - const tempProjectDependencyKey: string | undefined = this.getTempProjectDependencyKey(tempProjectName); - if (!tempProjectDependencyKey) { - throw new Error(`Cannot get dependency key for temp project: ${tempProjectName}`); - } - - const packageDescription: IPnpmShrinkwrapDependencyYaml | undefined = - this._getPackageDescription(tempProjectDependencyKey); - if (!packageDescription) { - return undefined; - } - - if (!packageDescription.dependencies.hasOwnProperty(dependencyName)) { - return undefined; - } - - return this._parsePnpmDependencyKey(dependencyName, packageDescription.dependencies[dependencyName]); - } - - /** - * Gets the package description for a tempProject from the shrinkwrap file. - */ - private _getPackageDescription(tempProjectDependencyKey: string): IPnpmShrinkwrapDependencyYaml | undefined { - const packageDescription: IPnpmShrinkwrapDependencyYaml | undefined - = BaseShrinkwrapFile.tryGetValue(this._shrinkwrapJson.packages, tempProjectDependencyKey); - - if (!packageDescription || !packageDescription.dependencies) { - return undefined; - } - - return packageDescription; - } - - private _parsePnpmDependencyKey(dependencyName: string, pnpmDependencyKey: string): DependencySpecifier | undefined { - - if (pnpmDependencyKey) { - const result: DependencySpecifier | undefined = parsePnpmDependencyKey(dependencyName, pnpmDependencyKey); - - if (!result) { - throw new Error(`Cannot parse PNPM shrinkwrap version specifier: "${pnpmDependencyKey}"` - + ` for "${dependencyName}"`); - } - - return result; - } else { - return undefined; - } - } -} diff --git a/apps/rush-lib/src/logic/policy/GitEmailPolicy.ts b/apps/rush-lib/src/logic/policy/GitEmailPolicy.ts deleted file mode 100644 index fc1e585965c..00000000000 --- a/apps/rush-lib/src/logic/policy/GitEmailPolicy.ts +++ /dev/null @@ -1,125 +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 colors from 'colors'; -import * as os from 'os'; - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; -import { Utilities } from '../../utilities/Utilities'; -import { Git } from '../Git'; - -export class GitEmailPolicy { - public static validate(rushConfiguration: RushConfiguration): void { - if (!Git.isGitPresent()) { - // If Git isn't installed, or this Rush project is not under a Git working folder, - // then we don't care about the Git email - console.log(colors.cyan( - 'Ignoring Git validation because the Git binary was not found in the shell path.') + os.EOL); - return; - } - - if (!Git.isPathUnderGitWorkingTree()) { - // If Git isn't installed, or this Rush project is not under a Git working folder, - // then we don't care about the Git email - console.log(colors.cyan( - 'Ignoring Git validation because this is not a Git working folder.' + os.EOL)); - return; - } - - // If there isn't a Git policy, then we don't care whether the person configured - // a Git email address at all. This helps people who don't - if (rushConfiguration.gitAllowedEmailRegExps.length === 0) { - if (Git.tryGetGitEmail(rushConfiguration) === undefined) { - return; - } - - // Otherwise, if an email *is* configured at all, then we still perform the basic - // sanity checks (e.g. no spaces in the address). - } - - let userEmail: string; - try { - userEmail = Git.getGitEmail(rushConfiguration); - - // sanity check; a valid email should not contain any whitespace - // if this fails, then we have another issue to report - if (!userEmail.match(/^\S+$/g)) { - console.log([ - colors.red('Your Git email address is invalid: ' + JSON.stringify(userEmail)), - '', - `To configure your Git email address, try something like this:`, - '', - ...GitEmailPolicy.getEmailExampleLines(rushConfiguration), - '' - ].join(os.EOL)); - throw new AlreadyReportedError(); - } - } catch (e) { - if (e instanceof AlreadyReportedError) { - console.log(colors.red('Aborting, so you can go fix your settings. (Or use --bypass-policy to skip.)')); - throw e; - } else { - throw e; - } - } - - if (rushConfiguration.gitAllowedEmailRegExps.length === 0) { - // If there is no policy, then we're good - return; - } - - console.log('Checking Git policy for this repository.' + os.EOL); - - // If there is a policy, at least one of the RegExp's must match - for (const pattern of rushConfiguration.gitAllowedEmailRegExps) { - const regex: RegExp = new RegExp(`^${pattern}$`, 'i'); - if (userEmail.match(regex)) { - return; - } - } - - // Show the user's name as well. - // Ex. "Mr. Example " - let fancyEmail: string = colors.cyan(userEmail); - const gitPath: string = Git.getGitPath()!; - try { - const userName: string = Utilities.executeCommandAndCaptureOutput( - gitPath, - ['config', 'user.name'], - '.' - ).trim(); - if (userName) { - fancyEmail = `${userName} <${fancyEmail}>`; - } - } catch (e) { - // but if it fails, this isn't critical, so don't bother them about it - } - - console.log([ - 'Hey there! To keep things tidy, this repo asks you to submit your Git commits using an email like ' + - (rushConfiguration.gitAllowedEmailRegExps.length > 1 ? 'one of these patterns:' : 'this pattern:'), - '', - ...rushConfiguration.gitAllowedEmailRegExps.map((pattern) => ' ' + colors.cyan(pattern)), - '', - '...but yours is configured like this:', - '', - ` ${fancyEmail}`, - '', - 'To fix it, you can use commands like this:', - '', - ...GitEmailPolicy.getEmailExampleLines(rushConfiguration), - '' - ].join(os.EOL)); - - console.log(colors.red('Aborting, so you can go fix your settings. (Or use --bypass-policy to skip.)')); - throw new AlreadyReportedError(); - } - - public static getEmailExampleLines(rushConfiguration: RushConfiguration): string[] { - return [ - colors.cyan(' git config --local user.name "Mr. Example"'), - colors.cyan(` git config --local user.email "${rushConfiguration.gitSampleEmail || 'example@contoso.com'}"`) - ]; - } -} diff --git a/apps/rush-lib/src/logic/policy/PolicyValidator.ts b/apps/rush-lib/src/logic/policy/PolicyValidator.ts deleted file mode 100644 index ff982917dd8..00000000000 --- a/apps/rush-lib/src/logic/policy/PolicyValidator.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { GitEmailPolicy } from './GitEmailPolicy'; - -export class PolicyValidator { - public static validatePolicy(rushConfiguration: RushConfiguration, bypassPolicy: boolean): void { - if (bypassPolicy) { - return; - } - - GitEmailPolicy.validate(rushConfiguration); - } -} diff --git a/apps/rush-lib/src/logic/policy/RushPolicy.ts b/apps/rush-lib/src/logic/policy/RushPolicy.ts deleted file mode 100644 index 16bbab6f5ae..00000000000 --- a/apps/rush-lib/src/logic/policy/RushPolicy.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { RushConfiguration } from '../../api/RushConfiguration'; - -export abstract class RushPolicy { - public abstract validate(rushConfiguration: RushConfiguration): void; -} diff --git a/apps/rush-lib/src/logic/taskRunner/ITask.ts b/apps/rush-lib/src/logic/taskRunner/ITask.ts deleted file mode 100644 index d3194ff1257..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/ITask.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { ITaskWriter } from '@rushstack/stream-collator'; - -import { Stopwatch } from '../../utilities/Stopwatch'; -import { TaskStatus } from './TaskStatus'; -import { TaskError } from './TaskError'; - -/** - * A definition for a task, an execute function returning a promise and a unique string name - */ -export interface ITaskDefinition { - /** - * Name of the task definition. - */ - name: string; - - /** - * This flag determines if an incremental build is allowed for the task. - */ - isIncrementalBuildAllowed: boolean; - - /** - * Assigned by execute(). True if the build script was an empty string. Operationally an empty string is - * like a shell command that succeeds instantly, but e.g. it would be odd to report build time statistics for it. - */ - hadEmptyScript: boolean; - - /** - * Method to be executed for the task. - */ - execute: (writer: ITaskWriter) => Promise; -} - -/** - * The interface used internally by TaskRunner, which tracks the dependencies and execution status - */ -export interface ITask extends ITaskDefinition { - /** - * The current execution status of a task. Tasks start in the 'ready' state, - * but can be 'blocked' if an upstream task failed. It is 'executing' when - * the task is executing. Once execution is complete, it is either 'success' or - * 'failure'. - */ - status: TaskStatus; - - /** - * A set of all dependencies which must be executed before this task is complete. - * When dependencies finish execution, they are removed from this list. - */ - dependencies: Set; - - /** - * The inverse of dependencies, lists all projects which are directly dependent on this one. - */ - dependents: Set; - - /** - * This number represents how far away this Task is from the furthest "root" project (i.e. - * a project with no dependents). This helps us to calculate the critical path (i.e. the - * longest chain of projects which must be executed in order, thereby limiting execution speed - * of the entire task tree. - * - * This number is calculated via a memoized recursive function, and when choosing the next - * task to execute, the task with the highest criticalPathLength is chosen. - * - * Example: - * (0) A - * \ - * (1) B C (0) (applications) - * \ /|\ - * \ / | \ - * (2) D | X (1) (utilities) - * | / \ - * |/ \ - * (2) Y Z (2) (other utilities) - * - * All roots (A & C) have a criticalPathLength of 0. - * B has a score of 1, since A depends on it. - * D has a score of 2, since we look at the longest chain (e.g D->B->A is longer than D->C) - * X has a score of 1, since the only package which depends on it is A - * Z has a score of 2, since only X depends on it, and X has a score of 1 - * Y has a score of 2, since the chain Y->X->C is longer than Y->C - * - * The algorithm is implemented in TaskRunner as _calculateCriticalPaths() - */ - criticalPathLength: number | undefined; - - /** - * The error which occurred while executing this task, this is stored in case we need - * it later (for example to re-print errors at end of execution). - */ - error: TaskError | undefined; - - /** - * The task writer which contains information from the output streams of this task - */ - writer: ITaskWriter; - - /** - * The stopwatch which measures how long it takes the task to execute - */ - stopwatch: Stopwatch; -} diff --git a/apps/rush-lib/src/logic/taskRunner/ProjectTask.ts b/apps/rush-lib/src/logic/taskRunner/ProjectTask.ts deleted file mode 100644 index 8ac4e6dbb8b..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/ProjectTask.ts +++ /dev/null @@ -1,291 +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 child_process from 'child_process'; -import * as path from 'path'; -import { JsonFile, Text, FileSystem, JsonObject } from '@rushstack/node-core-library'; -import { ITaskWriter } from '@rushstack/stream-collator'; -import { IPackageDeps } from '@rushstack/package-deps-hash'; - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { Utilities } from '../../utilities/Utilities'; -import { TaskStatus } from './TaskStatus'; -import { TaskError } from './TaskError'; -import { ITaskDefinition } from '../taskRunner/ITask'; -import { PackageChangeAnalyzer } from '../PackageChangeAnalyzer'; - -interface IPackageDependencies extends IPackageDeps { - arguments: string; -} - -export interface IProjectTaskOptions { - rushProject: RushConfigurationProject; - rushConfiguration: RushConfiguration; - commandToRun: string; - isIncrementalBuildAllowed: boolean; - packageChangeAnalyzer: PackageChangeAnalyzer; - packageDepsFilename: string; -} - -function _areShallowEqual(object1: JsonObject, object2: JsonObject, writer: ITaskWriter): boolean { - for (const n in object1) { - if (!(n in object2) || object1[n] !== object2[n]) { - writer.writeLine(`Found mismatch: "${n}": "${object1[n]}" !== "${object2[n]}"`); - return false; - } - } - for (const n in object2) { - if (!(n in object1)) { - writer.writeLine(`Found new prop in obj2: "${n}" value="${object2[n]}"`); - return false; - } - } - return true; -} - -/** - * A TaskRunner task which cleans and builds a project - */ -export class ProjectTask implements ITaskDefinition { - public get name(): string { - return this._rushProject.packageName; - } - - public isIncrementalBuildAllowed: boolean; - public hadEmptyScript: boolean = false; - - private _hasWarningOrError: boolean; - private _rushProject: RushConfigurationProject; - private _rushConfiguration: RushConfiguration; - private _commandToRun: string; - private _packageChangeAnalyzer: PackageChangeAnalyzer; - private _packageDepsFilename: string; - - public constructor(options: IProjectTaskOptions) { - this._rushProject = options.rushProject; - this._rushConfiguration = options.rushConfiguration; - this._commandToRun = options.commandToRun; - this.isIncrementalBuildAllowed = options.isIncrementalBuildAllowed; - this._packageChangeAnalyzer = options.packageChangeAnalyzer; - this._packageDepsFilename = options.packageDepsFilename; -} - - public execute(writer: ITaskWriter): Promise { - try { - if (!this._commandToRun) { - this.hadEmptyScript = true; - } - const deps: IPackageDependencies | undefined = this._getPackageDependencies(writer); - return this._executeTask(writer, deps); - } catch (error) { - return Promise.reject(new TaskError('executing', error.message)); - } - } - - private _getPackageDependencies(writer: ITaskWriter): IPackageDependencies | undefined { - let deps: IPackageDependencies | undefined = undefined; - this._rushConfiguration = this._rushConfiguration; - try { - deps = { - files: this._packageChangeAnalyzer.getPackageDepsHash(this._rushProject.packageName)!.files, - arguments: this._commandToRun - }; - } catch (error) { - writer.writeLine('Unable to calculate incremental build state. ' + - 'Instead running full rebuild. ' + error.toString()); - } - - return deps; - } - - private _executeTask( - writer: ITaskWriter, - currentPackageDeps: IPackageDependencies | undefined - ): Promise { - try { - this._hasWarningOrError = false; - const projectFolder: string = this._rushProject.projectFolder; - let lastPackageDeps: IPackageDependencies | undefined = undefined; - - writer.writeLine(`>>> ${this.name}`); - - // TODO: Remove legacyDepsPath with the next major release of Rush - const legacyDepsPath: string = path.join(this._rushProject.projectFolder, 'package-deps.json'); - - const currentDepsPath: string = path.join(this._rushProject.projectRushTempFolder, this._packageDepsFilename); - - if (FileSystem.exists(currentDepsPath)) { - try { - lastPackageDeps = JsonFile.load(currentDepsPath) as IPackageDependencies; - } catch (e) { - // Warn and ignore - treat failing to load the file as the project being not built. - writer.writeLine( - `Warning: error parsing ${this._packageDepsFilename}: ${e}. Ignoring and ` + - `treating the command "${this._commandToRun}" as not run.` - ); - } - } - - const isPackageUnchanged: boolean = ( - !!( - lastPackageDeps && - currentPackageDeps && - (currentPackageDeps.arguments === lastPackageDeps.arguments && - _areShallowEqual(currentPackageDeps.files, lastPackageDeps.files, writer)) - ) - ); - - if (isPackageUnchanged && this.isIncrementalBuildAllowed) { - return Promise.resolve(TaskStatus.Skipped); - } else { - // If the deps file exists, remove it before starting a build. - FileSystem.deleteFile(currentDepsPath); - - // Delete the legacy package-deps.json - FileSystem.deleteFile(legacyDepsPath); - - if (!this._commandToRun) { - writer.writeLine(`The task command "${this._commandToRun}" was registered in the package.json but is blank,` - + ` so no action will be taken.`); - - // Write deps on success. - if (currentPackageDeps) { - JsonFile.save(currentPackageDeps, currentDepsPath, { - ensureFolderExists: true - }); - } - - return Promise.resolve(TaskStatus.Success); - } - - // Run the task - - writer.writeLine(this._commandToRun); - const task: child_process.ChildProcess = Utilities.executeLifecycleCommandAsync( - this._commandToRun, - { - rushConfiguration: this._rushConfiguration, - workingDirectory: projectFolder, - initCwd: this._rushConfiguration.commonTempFolder, - handleOutput: true, - environmentPathOptions: { - includeProjectBin: true - } - } - ); - - // Hook into events, in order to get live streaming of build log - if (task.stdout !== null) { - task.stdout.on('data', (data: string) => { - writer.write(data); - }); - } - if (task.stderr !== null) { - task.stderr.on('data', (data: string) => { - writer.writeError(data); - this._hasWarningOrError = true; - }); - } - - return new Promise((resolve: (status: TaskStatus) => void, reject: (error: TaskError) => void) => { - task.on('close', (code: number) => { - this._writeLogsToDisk(writer); - - if (code !== 0) { - reject(new TaskError('error', `Returned error code: ${code}`)); - } else if (this._hasWarningOrError) { - resolve(TaskStatus.SuccessWithWarning); - } else { - // Write deps on success. - if (currentPackageDeps) { - JsonFile.save(currentPackageDeps, currentDepsPath, { - ensureFolderExists: true - }); - } - resolve(TaskStatus.Success); - } - }); - }); - } - } catch (error) { - console.log(error); - - this._writeLogsToDisk(writer); - return Promise.reject(new TaskError('error', error.toString())); - } - } - - // @todo #179371: add log files to list of things that get gulp cleaned - private _writeLogsToDisk(writer: ITaskWriter): void { - try { - const logFilename: string = path.basename(this._rushProject.projectFolder); - - // eslint-disable-next-line no-control-regex - const stdout: string = writer.getStdOutput().replace(/\x1B[[(?);]{0,2}(;?\d)*./g, ''); - if (stdout) { - FileSystem.writeFile(path.join(this._rushProject.projectFolder, logFilename + '.build.log'), stdout); - } - - // eslint-disable-next-line no-control-regex - const stderr: string = writer.getStdError().replace(/\x1B[[(?);]{0,2}(;?\d)*./g, ''); - if (stderr) { - FileSystem.writeFile(path.join(this._rushProject.projectFolder, logFilename + '.build.error.log'), stderr); - } - } catch (e) { - console.log(`Error writing logs to disk: ${e}`); - } - } -} - -/** - * When running a command from the "scripts" block in package.json, if the command - * contains Unix-style path slashes and the OS is Windows, the package managers will - * convert slashes to backslashes. This is a complicated undertaking. For example, they - * need to convert "node_modules/bin/this && ./scripts/that --name keep/this" - * to "node_modules\bin\this && .\scripts\that --name keep/this", and they don't want to - * convert ANY of the slashes in "cmd.exe /c echo a/b". NPM and PNPM use npm-lifecycle for this, - * but it unfortunately has a dependency on the entire node-gyp kitchen sink. Yarn has a - * simplified implementation in fix-cmd-win-slashes.js, but it's not exposed as a library. - * - * Fundamentally NPM's whole feature seems misguided: They start by inviting people to write - * shell scripts that will be executed by wildly different shell languages (e.g. cmd.exe and Bash). - * It's very tricky for a developer to guess what's safe to do without testing every OS. - * Even simple path separators are not portable, so NPM added heuristics to figure out which - * slashes are part of a path or not, and convert them. These workarounds end up having tons - * of special cases. They probably could have implemented their own entire minimal cross-platform - * shell language with less code and less confusion than npm-lifecycle's approach. - * - * We've deprecated shell operators inside package.json. Instead, we advise people to move their - * scripts into conventional script files, and put only a file path in package.json. So, for - * Rush's workaround here, we really only care about supporting the small set of cases seen in the - * unit tests. For anything that doesn't fit those patterns, we leave the string untouched - * (i.e. err on the side of not breaking anything). We could revisit this later if someone - * complains about it, but so far nobody has. :-) - */ -export function convertSlashesForWindows(command: string): string { - // The first group will match everything up to the first space, "&", "|", "<", ">", or quote. - // The second group matches the remainder. - const commandRegExp: RegExp = /^([^\s&|<>"]+)(.*)$/; - - const match: RegExpMatchArray | null = commandRegExp.exec(command); - if (match) { - // Example input: "bin/blarg --path ./config/blah.json && a/b" - // commandPart="bin/blarg" - // remainder=" --path ./config/blah.json && a/b" - const commandPart: string = match[1]; - const remainder: string = match[2]; - - // If the command part already contains a backslash, then leave it alone - if (commandPart.indexOf('\\') < 0) { - // Replace all the slashes with backslashes, e.g. to produce: - // "bin\blarg --path ./config/blah.json && a/b" - // - // NOTE: we don't attempt to process the path parameter or stuff after "&&" - return Text.replaceAll(commandPart, '/', '\\') + remainder; - } - } - - // Don't change anything - return command; -} diff --git a/apps/rush-lib/src/logic/taskRunner/TaskCollection.ts b/apps/rush-lib/src/logic/taskRunner/TaskCollection.ts deleted file mode 100644 index 3c5cacd6a1d..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/TaskCollection.ts +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - Terminal, - ConsoleTerminalProvider, - Sort -} from '@rushstack/node-core-library'; - -import { ITask, ITaskDefinition } from './ITask'; -import { TaskStatus } from './TaskStatus'; - -export interface ITaskCollectionOptions { - quietMode: boolean; - terminal?: Terminal; -} - -/** - * This class represents a set of tasks with interdependencies. Any class of task definition - * may be registered, and dependencies between tasks are easily specified. There is a check for - * cyclic dependencies and tasks are ordered based on critical path. - */ -export class TaskCollection { - private _tasks: Map; - private _quietMode: boolean; - private _terminal: Terminal; - - public constructor(options: ITaskCollectionOptions) { - const { - quietMode, - terminal = new Terminal(new ConsoleTerminalProvider()) - } = options; - this._tasks = new Map(); - this._quietMode = quietMode; - this._terminal = terminal; - } - - /** - * Registers a task definition to the map of defined tasks - */ - public addTask(taskDefinition: ITaskDefinition): void { - if (this._tasks.has(taskDefinition.name)) { - throw new Error('A task with that name has already been registered.'); - } - - const task: ITask = taskDefinition as ITask; - task.dependencies = new Set(); - task.dependents = new Set(); - task.status = TaskStatus.Ready; - task.criticalPathLength = undefined; - this._tasks.set(task.name, task); - - if (!this._quietMode) { - this._terminal.writeLine(`Registered ${task.name}`); - } - } - - /** - * Returns true if a task with that name has been registered - */ - public hasTask(taskName: string): boolean { - return this._tasks.has(taskName); - } - - /** - * Defines the list of dependencies for an individual task. - * @param taskName - the string name of the task for which we are defining dependencies. A task with this - * name must already have been registered. - */ - public addDependencies(taskName: string, taskDependencies: string[]): void { - const task: ITask | undefined = this._tasks.get(taskName); - - if (!task) { - throw new Error(`The task '${taskName}' has not been registered`); - } - if (!taskDependencies) { - throw new Error('The list of dependencies must be defined'); - } - - for (const dependencyName of taskDependencies) { - if (!this._tasks.has(dependencyName)) { - throw new Error(`The project '${dependencyName}' has not been registered.`); - } - const dependency: ITask = this._tasks.get(dependencyName)!; - task.dependencies.add(dependency); - dependency.dependents.add(task); - } - } - - /** - * Returns the tasks registered with the collection ordered by the critical path. - * It also makes sure there are no cyclic dependencies in the tasks. - */ - public getOrderedTasks(): ITask[] { - this._checkForCyclicDependencies(this._tasks.values(), [], new Set()); - - // Precalculate the number of dependent packages - this._tasks.forEach((task: ITask) => { - this._calculateCriticalPaths(task); - }); - - const buildQueue: ITask[] = []; - // Add everything to the buildQueue - this._tasks.forEach((task: ITask) => { - buildQueue.push(task); - }); - - // Sort the queue in descending order, nothing will mess with the order - Sort.sortBy(buildQueue, (task: ITask): number => -task.criticalPathLength!); - - return buildQueue; - } - - /** - * Checks for projects that indirectly depend on themselves. - */ - private _checkForCyclicDependencies( - tasks: Iterable, - dependencyChain: string[], - alreadyCheckedProjects: Set - ): void { - for (const task of tasks) { - if (dependencyChain.indexOf(task.name) >= 0) { - throw new Error('A cyclic dependency was encountered:\n' - + ' ' + [...dependencyChain, task.name].reverse().join('\n -> ') - + '\nConsider using the cyclicDependencyProjects option for rush.json.'); - } - - if (!alreadyCheckedProjects.has(task.name)) { - alreadyCheckedProjects.add(task.name); - dependencyChain.push(task.name); - this._checkForCyclicDependencies(task.dependents, dependencyChain, alreadyCheckedProjects); - dependencyChain.pop(); - } - } - } - - /** - * Calculate the number of packages which must be built before we reach - * the furthest away "root" node - */ - private _calculateCriticalPaths(task: ITask): number { - // Return the memoized value - if (task.criticalPathLength !== undefined) { - return task.criticalPathLength; - } - - // If no dependents, we are in a "root" - if (task.dependents.size === 0) { - task.criticalPathLength = 0; - return task.criticalPathLength; - } else { - // Otherwise we are as long as the longest package + 1 - const depsLengths: number[] = []; - task.dependents.forEach(dep => depsLengths.push(this._calculateCriticalPaths(dep))); - task.criticalPathLength = Math.max(...depsLengths) + 1; - return task.criticalPathLength; - } - } -} diff --git a/apps/rush-lib/src/logic/taskRunner/TaskError.ts b/apps/rush-lib/src/logic/taskRunner/TaskError.ts deleted file mode 100644 index 3496edabab5..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/TaskError.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Encapsulates information about an error - */ -export class TaskError extends Error { - protected _type: string; - - public constructor(type: string, message: string) { - super(message); - - this._type = type; - } - - public get message(): string { - return `[${this._type}] '${super.message}'`; - } - - public toString(): string { - return this.message; - } -} - -/** - * TestTaskError extends TaskError - */ -export class BuildTaskError extends TaskError { - protected _file: string; - protected _line: number; - protected _offset: number; - - public constructor(type: string, message: string, file: string, line: number, offset: number) { - super(type, message); - this._file = file; - this._line = line; - this._offset = offset; - } - - public get message(): string { - // Example: "C:\Project\Blah.ts(123,1): [tslint] error no-any: 'any' is not allowed" - return `${this._file}(${this._line},${this._offset}): ${super.message}`; - } - - public toString(): string { - return this.message; - } -} diff --git a/apps/rush-lib/src/logic/taskRunner/TaskRunner.ts b/apps/rush-lib/src/logic/taskRunner/TaskRunner.ts deleted file mode 100644 index 33a05b7f606..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/TaskRunner.ts +++ /dev/null @@ -1,379 +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'; -import { Interleaver } from '@rushstack/stream-collator'; -import { - Terminal, - ConsoleTerminalProvider, - Colors, - IColorableSequence -} from '@rushstack/node-core-library'; - -import { Stopwatch } from '../../utilities/Stopwatch'; -import { ITask } from './ITask'; -import { TaskStatus } from './TaskStatus'; -import { TaskError } from './TaskError'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; - -export interface ITaskRunnerOptions { - quietMode: boolean; - parallelism: string | undefined; - changedProjectsOnly: boolean; - allowWarningsInSuccessfulBuild: boolean; - terminal?: Terminal; -} - -/** - * 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 TaskRunner { - private _tasks: ITask[]; - private _changedProjectsOnly: boolean; - private _allowWarningsInSuccessfulBuild: boolean; - private _buildQueue: ITask[]; - private _quietMode: boolean; - private _hasAnyFailures: boolean; - private _hasAnyWarnings: boolean; - private _parallelism: number; - private _currentActiveTasks: number; - private _totalTasks: number; - private _completedTasks: number; - private _terminal: Terminal; - - public constructor(orderedTasks: ITask[], options: ITaskRunnerOptions) { - const { - quietMode, - parallelism, - changedProjectsOnly, - allowWarningsInSuccessfulBuild, - terminal = new Terminal(new ConsoleTerminalProvider()) - } = options; - this._tasks = orderedTasks; - this._buildQueue = orderedTasks.slice(0); - this._quietMode = quietMode; - this._hasAnyFailures = false; - this._hasAnyWarnings = false; - this._changedProjectsOnly = changedProjectsOnly; - this._allowWarningsInSuccessfulBuild = allowWarningsInSuccessfulBuild; - this._terminal = terminal; - - const numberOfCores: number = os.cpus().length; - - if (parallelism) { - if (parallelism === 'max') { - this._parallelism = numberOfCores; - } else { - const parallelismInt: number = parseInt(parallelism, 10); - - if (isNaN(parallelismInt)) { - throw new Error(`Invalid parallelism value of '${parallelism}', expected a number or 'max'`); - } - - this._parallelism = parallelismInt; - } - } 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. - this._parallelism = Math.max(numberOfCores - 1, 1); - } else { - // Unix-like operating systems have more balanced scheduling, so default - // to the number of CPU cores - this._parallelism = numberOfCores; - } - } - } - - /** - * Executes all tasks which have been registered, returning a promise which is resolved when all the - * tasks are completed successfully, or rejects when any task fails. - */ - public execute(): Promise { - this._currentActiveTasks = 0; - this._completedTasks = 0; - this._totalTasks = this._buildQueue.length; - this._terminal.writeLine(`Executing a maximum of ${this._parallelism} simultaneous processes...${os.EOL}`); - - return this._startAvailableTasks().then(() => { - this._printTaskStatus(); - - if (this._hasAnyFailures) { - return Promise.reject(new Error('Project(s) failed')); - } else if (this._hasAnyWarnings && !this._allowWarningsInSuccessfulBuild) { - this._terminal.writeWarningLine('Project(s) succeeded with warnings'); - return Promise.reject(new AlreadyReportedError()); - } else { - return Promise.resolve(); - } - }); - } - - /** - * Pulls the next task with no dependencies off the build queue - * Removes any non-ready tasks from the build queue (this should only be blocked tasks) - */ - private _getNextTask(): ITask | undefined { - for (let i: number = 0; i < this._buildQueue.length; i++) { - const task: ITask = this._buildQueue[i]; - - if (task.status !== TaskStatus.Ready) { - // It shouldn't be on the queue, remove it - this._buildQueue.splice(i, 1); - // Decrement since we modified the array - i--; - } else if (task.dependencies.size === 0 && task.status === TaskStatus.Ready) { - // this is a task which is ready to go. remove it and return it - return this._buildQueue.splice(i, 1)[0]; - } - // Otherwise task is still waiting - } - return undefined; // There are no tasks ready to go at this time - } - - /** - * Helper function which finds any tasks which are available to run and begins executing them. - * It calls the complete callback when all tasks are completed, or rejects if any task fails. - */ - private _startAvailableTasks(): Promise { - const taskPromises: Promise[] = []; - let ctask: ITask | undefined; - while (this._currentActiveTasks < this._parallelism && (ctask = this._getNextTask())) { - this._currentActiveTasks++; - const task: ITask = ctask; - task.status = TaskStatus.Executing; - this._terminal.writeLine(Colors.white(`[${task.name}] started`)); - - task.stopwatch = Stopwatch.start(); - task.writer = Interleaver.registerTask(task.name, this._quietMode); - - taskPromises.push(task.execute(task.writer) - .then((result: TaskStatus) => { - task.stopwatch.stop(); - task.writer.close(); - - this._currentActiveTasks--; - this._completedTasks++; - switch (result) { - case TaskStatus.Success: - this._markTaskAsSuccess(task); - break; - case TaskStatus.SuccessWithWarning: - this._hasAnyWarnings = true; - this._markTaskAsSuccessWithWarning(task); - break; - case TaskStatus.Skipped: - this._markTaskAsSkipped(task); - break; - case TaskStatus.Failure: - this._hasAnyFailures = true; - this._markTaskAsFailed(task); - break; - } - }).catch((error: TaskError) => { - task.writer.close(); - - this._currentActiveTasks--; - - this._hasAnyFailures = true; - task.error = error; - this._markTaskAsFailed(task); - } - ).then(() => this._startAvailableTasks())); - } - - return Promise.all(taskPromises).then(() => { /* collapse void[] to void */ }); - } - - /** - * Marks a task as having failed and marks each of its dependents as blocked - */ - private _markTaskAsFailed(task: ITask): void { - this._terminal.writeErrorLine(`${os.EOL}${this._getCurrentCompletedTaskString()}[${task.name}] failed!`); - task.status = TaskStatus.Failure; - task.dependents.forEach((dependent: ITask) => { - this._markTaskAsBlocked(dependent, task); - }); - } - - /** - * Marks a task and all its dependents as blocked - */ - private _markTaskAsBlocked(task: ITask, failedTask: ITask): void { - if (task.status === TaskStatus.Ready) { - this._completedTasks++; - this._terminal.writeErrorLine(`${this._getCurrentCompletedTaskString()}` - + `[${task.name}] blocked by [${failedTask.name}]!`); - task.status = TaskStatus.Blocked; - task.dependents.forEach((dependent: ITask) => { - this._markTaskAsBlocked(dependent, failedTask); - }); - } - } - - /** - * Marks a task as being completed, and removes it from the dependencies list of all its dependents - */ - private _markTaskAsSuccess(task: ITask): void { - if (task.hadEmptyScript) { - this._terminal.writeLine(Colors.green(`${this._getCurrentCompletedTaskString()}` - + `[${task.name}] had an empty script`)); - } else { - this._terminal.writeLine(Colors.green(`${this._getCurrentCompletedTaskString()}` - + `[${task.name}] completed successfully in ${task.stopwatch.toString()}`)); - } - task.status = TaskStatus.Success; - - task.dependents.forEach((dependent: ITask) => { - if (!this._changedProjectsOnly) { - dependent.isIncrementalBuildAllowed = false; - } - dependent.dependencies.delete(task); - }); - } - - /** - * Marks a task as being completed, but with warnings written to stderr, and removes it from the dependencies - * list of all its dependents - */ - private _markTaskAsSuccessWithWarning(task: ITask): void { - this._terminal.writeWarningLine(`${this._getCurrentCompletedTaskString()}` - + `[${task.name}] completed with warnings in ${task.stopwatch.toString()}`); - task.status = TaskStatus.SuccessWithWarning; - task.dependents.forEach((dependent: ITask) => { - if (!this._changedProjectsOnly) { - dependent.isIncrementalBuildAllowed = false; - } - dependent.dependencies.delete(task); - }); - } - - /** - * Marks a task as skipped. - */ - private _markTaskAsSkipped(task: ITask): void { - this._terminal.writeLine(Colors.green(`${this._getCurrentCompletedTaskString()}[${task.name}] skipped`)); - task.status = TaskStatus.Skipped; - task.dependents.forEach((dependent: ITask) => { - dependent.dependencies.delete(task); - }); - } - - private _getCurrentCompletedTaskString(): string { - return `${this._completedTasks} of ${this._totalTasks}: `; - } - - /** - * Prints out a report of the status of each project - */ - private _printTaskStatus(): void { - const tasksByStatus: { [status: number]: ITask[] } = {}; - this._tasks.forEach((task: ITask) => { - if (tasksByStatus[task.status]) { - tasksByStatus[task.status].push(task); - } else { - tasksByStatus[task.status] = [task]; - } - }); - - this._terminal.writeLine(''); - - this._printStatus(TaskStatus.Executing, tasksByStatus, Colors.yellow); - this._printStatus(TaskStatus.Ready, tasksByStatus, Colors.white); - this._printStatus(TaskStatus.Skipped, tasksByStatus, Colors.gray); - this._printStatus(TaskStatus.Success, tasksByStatus, Colors.green); - this._printStatus( - TaskStatus.SuccessWithWarning, - tasksByStatus, - (text: string) => Colors.yellow(text), - (text: string) => Colors.yellow(Colors.underline(text)) - ); - this._printStatus(TaskStatus.Blocked, tasksByStatus, Colors.red); - this._printStatus(TaskStatus.Failure, tasksByStatus, Colors.red); - - const tasksWithErrors: ITask[] = tasksByStatus[TaskStatus.Failure]; - if (tasksWithErrors) { - tasksWithErrors.forEach((task: ITask) => { - if (task.error) { - this._terminal.writeErrorLine(`[${task.name}] ${task.error.message}`); - } - }); - } - - this._terminal.writeLine(''); - } - - private _printStatus( - status: TaskStatus, - tasksByStatus: { [status: number]: ITask[] }, - color: (text: string) => IColorableSequence, - headingColor: (text: string) => IColorableSequence = color - ): void { - const tasks: ITask[] = tasksByStatus[status]; - - if (tasks && tasks.length) { - this._terminal.writeLine(headingColor(`${status} (${tasks.length})`)); - this._terminal.writeLine(color('================================')); - for (let i: number = 0; i < tasks.length; i++) { - const task: ITask = tasks[i]; - - switch (status) { - case TaskStatus.Executing: - case TaskStatus.Ready: - case TaskStatus.Skipped: - this._terminal.writeLine(color(task.name)); - break; - - case TaskStatus.Success: - case TaskStatus.SuccessWithWarning: - case TaskStatus.Blocked: - case TaskStatus.Failure: - if (task.stopwatch && !task.hadEmptyScript) { - const time: string = task.stopwatch.toString(); - this._terminal.writeLine(headingColor(`${task.name} (${time})`)); - } else { - this._terminal.writeLine(headingColor(`${task.name}`)); - } - break; - } - - if (task.writer) { - const stderr: string = task.writer.getStdError(); - const shouldPrintDetails: boolean = - task.status === TaskStatus.Failure || task.status === TaskStatus.SuccessWithWarning; - let details: string = stderr ? stderr : task.writer.getStdOutput(); - if (details && shouldPrintDetails) { - details = this._abridgeTaskReport(details); - this._terminal.writeLine(details + (i !== tasks.length - 1 ? os.EOL : '')); - } - } - } - - this._terminal.writeLine(color('================================' + os.EOL)); - } - } - - /** - * Remove trailing blanks, and all middle lines if text is large - */ - private _abridgeTaskReport(text: string): string { - const headSize: number = 10; - const tailSize: number = 20; - const margin: number = 10; - const lines: string[] = text.split(/\s*\r?\n/).filter(line => line); - if (lines.length < headSize + tailSize + margin) { - return lines.join(os.EOL); - } - const amountRemoved: number = lines.length - headSize - tailSize; - const head: string = lines.splice(0, headSize).join(os.EOL); - const tail: string = lines.splice(-tailSize).join(os.EOL); - return `${head}${os.EOL}[...${amountRemoved} lines omitted...]${os.EOL}${tail}`; - } - -} diff --git a/apps/rush-lib/src/logic/taskRunner/TaskStatus.ts b/apps/rush-lib/src/logic/taskRunner/TaskStatus.ts deleted file mode 100644 index cad3fc3a542..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/TaskStatus.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Enumeration defining potential states of a task: not started, executing, or completed - */ -export enum TaskStatus { - Ready = 'READY', - Executing = 'EXECUTING', - Success = 'SUCCESS', - SuccessWithWarning = 'SUCCESS WITH WARNINGS', - Skipped = 'SKIPPED', - Failure = 'FAILURE', - Blocked = 'BLOCKED' -} diff --git a/apps/rush-lib/src/logic/taskRunner/test/ProjectTask.test.ts b/apps/rush-lib/src/logic/taskRunner/test/ProjectTask.test.ts deleted file mode 100644 index 1beb483f039..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/test/ProjectTask.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { convertSlashesForWindows } from '../ProjectTask'; - -describe('convertSlashesForWindows()', () => { - it('converted inputs', () => { - expect(convertSlashesForWindows('./node_modules/.bin/tslint -c config/tslint.json')) - .toEqual('.\\node_modules\\.bin\\tslint -c config/tslint.json'); - expect(convertSlashesForWindows('/blah/bleep&&/bloop')).toEqual('\\blah\\bleep&&/bloop'); - expect(convertSlashesForWindows('/blah/bleep')).toEqual('\\blah\\bleep'); - expect(convertSlashesForWindows('/blah/bleep --path a/b')).toEqual('\\blah\\bleep --path a/b'); - expect(convertSlashesForWindows('/blah/bleep>output.log')).toEqual('\\blah\\bleep>output.log'); - expect(convertSlashesForWindows('/blah/bleep { - expect(convertSlashesForWindows('/blah\\bleep && /bloop')).toEqual('/blah\\bleep && /bloop'); - expect(convertSlashesForWindows('cmd.exe /c blah')).toEqual('cmd.exe /c blah'); - expect(convertSlashesForWindows('"/blah/bleep"')).toEqual('"/blah/bleep"'); - }); -}); diff --git a/apps/rush-lib/src/logic/taskRunner/test/TaskCollection.test.ts b/apps/rush-lib/src/logic/taskRunner/test/TaskCollection.test.ts deleted file mode 100644 index 378c0d9e015..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/test/TaskCollection.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { TaskCollection } from '../TaskCollection'; -import { ITaskWriter } from '@rushstack/stream-collator'; -import { TaskStatus } from '../TaskStatus'; -import { ITaskDefinition, ITask } from '../ITask'; -import { StringBufferTerminalProvider } from '@rushstack/node-core-library'; - -function createDummyTask(name: string, action?: () => void): ITaskDefinition { - return { - name, - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - if (action) { - action(); - } - return Promise.resolve(TaskStatus.Success); - }, - hadEmptyScript: false - }; -} - -function checkConsoleOutput(terminalProvider: StringBufferTerminalProvider): void { - expect(terminalProvider.getOutput()).toMatchSnapshot(); - expect(terminalProvider.getVerbose()).toMatchSnapshot(); - expect(terminalProvider.getWarningOutput()).toMatchSnapshot(); - expect(terminalProvider.getErrorOutput()).toMatchSnapshot(); -} - -describe('TaskCollection', () => { - let terminalProvider: StringBufferTerminalProvider; - let taskCollection: TaskCollection; - - beforeEach(() => { - terminalProvider = new StringBufferTerminalProvider(true); - }); - - describe('Dependencies', () => { - beforeEach(() => { - taskCollection = new TaskCollection({ - quietMode: false - }); - }); - - it('throwsErrorOnNonExistentTask', () => { - expect(() => taskCollection.addDependencies('foo', [])) - .toThrowErrorMatchingSnapshot(); - }); - - it('throwsErrorOnNonExistentDependency', () => { - taskCollection.addTask(createDummyTask('foo')); - expect(() => taskCollection.addDependencies('foo', ['bar'])) - .toThrowErrorMatchingSnapshot(); - }); - - it('detectsDependencyCycle', () => { - taskCollection.addTask(createDummyTask('foo')); - taskCollection.addTask(createDummyTask('bar')); - taskCollection.addDependencies('foo', ['bar']); - taskCollection.addDependencies('bar', ['foo']); - expect(() => taskCollection.getOrderedTasks()).toThrowErrorMatchingSnapshot(); - }); - - it('respectsDependencyOrder', () => { - const result: string[] = []; - taskCollection.addTask(createDummyTask('two', () => result.push('2'))); - taskCollection.addTask(createDummyTask('one', () => result.push('1'))); - taskCollection.addDependencies('two', ['one']); - - const tasks: ITask[] = taskCollection.getOrderedTasks(); - expect(tasks.map((t) => t.name).join(',')).toEqual('one,two'); - checkConsoleOutput(terminalProvider); - }); - }); - - describe('Error logging', () => { - beforeEach(() => { - taskCollection = new TaskCollection({ - quietMode: false - }); - }); - }); -}); diff --git a/apps/rush-lib/src/logic/taskRunner/test/TaskRunner.test.ts b/apps/rush-lib/src/logic/taskRunner/test/TaskRunner.test.ts deleted file mode 100644 index 40c67dfbe53..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/test/TaskRunner.test.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { EOL } from 'os'; -import { TaskRunner, ITaskRunnerOptions } from '../TaskRunner'; -import { ITaskWriter } from '@rushstack/stream-collator'; -import { TaskStatus } from '../TaskStatus'; -import { ITaskDefinition, ITask } from '../ITask'; -import { StringBufferTerminalProvider, Terminal } from '@rushstack/node-core-library'; -import { Utilities } from '../../../utilities/Utilities'; - -// The TaskRunner prints "x.xx seconds" in TestRunner.test.ts.snap; ensure that the Stopwatch timing is deterministic -jest.mock('../../../utilities/Utilities'); -const mockGetTimeInMs: jest.Mock = jest.fn(); -Utilities.getTimeInMs = mockGetTimeInMs; - -let mockTimeInMs: number = 0; -mockGetTimeInMs.mockImplementation(() => { - console.log('CALLED mockGetTimeInMs'); - mockTimeInMs += 100; - return mockTimeInMs; -}); - -function createTaskRunner(taskRunnerOptions: ITaskRunnerOptions, taskDefinition: ITaskDefinition): TaskRunner { - const task: ITask = taskDefinition as ITask; - task.dependencies = new Set(); - task.dependents = new Set(); - task.status = TaskStatus.Ready; - - return new TaskRunner([task], taskRunnerOptions); -} - -function checkConsoleOutput(terminalProvider: StringBufferTerminalProvider): void { - expect(terminalProvider.getOutput()).toMatchSnapshot(); - expect(terminalProvider.getVerbose()).toMatchSnapshot(); - expect(terminalProvider.getWarningOutput()).toMatchSnapshot(); - expect(terminalProvider.getErrorOutput()).toMatchSnapshot(); -} - -describe('TaskRunner', () => { - let terminalProvider: StringBufferTerminalProvider; - let terminal: Terminal; - let taskRunner: TaskRunner; - let taskRunnerOptions: ITaskRunnerOptions; - - beforeEach(() => { - terminalProvider = new StringBufferTerminalProvider(true); - terminal = new Terminal(terminalProvider); - }); - - describe('Constructor', () => { - it('throwsErrorOnInvalidParallelism', () => { - expect(() => new TaskRunner([], { - quietMode: false, - parallelism: 'tequila', - changedProjectsOnly: false, - terminal, - allowWarningsInSuccessfulBuild: false - })).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('Error logging', () => { - beforeEach(() => { - taskRunnerOptions = { - quietMode: false, - parallelism: '1', - changedProjectsOnly: false, - terminal, - allowWarningsInSuccessfulBuild: false - }; - }); - - const EXPECTED_FAIL: string = 'Promise returned by execute() resolved but was expected to fail'; - - it('printedStderrAfterError', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'stdout+stderr', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.write('Build step 1' + EOL); - writer.writeError('Error: step 1 failed' + EOL); - return Promise.resolve(TaskStatus.Failure); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => fail(EXPECTED_FAIL)) - .catch(err => { - expect(err.message).toMatchSnapshot(); - const allMessages: string = terminalProvider.getOutput(); - expect(allMessages).not.toContain('Build step 1'); - expect(allMessages).toContain('Error: step 1 failed'); - checkConsoleOutput(terminalProvider); - }); - }); - - it('printedStdoutAfterErrorWithEmptyStderr', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'stdout only', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.write('Build step 1' + EOL); - writer.write('Error: step 1 failed' + EOL); - return Promise.resolve(TaskStatus.Failure); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => fail(EXPECTED_FAIL)) - .catch(err => { - expect(err.message).toMatchSnapshot(); - expect(terminalProvider.getOutput()).toMatch(/Build step 1.*Error: step 1 failed/); - checkConsoleOutput(terminalProvider); - }); - }); - - it('printedAbridgedStdoutAfterErrorWithEmptyStderr', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'large stdout only', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.write(`Building units...${EOL}`); - for (let i: number = 1; i <= 50; i++) { - writer.write(` - unit #${i};${EOL}`); - } - return Promise.resolve(TaskStatus.Failure); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => fail(EXPECTED_FAIL)) - .catch(err => { - expect(err.message).toMatchSnapshot(); - expect(terminalProvider.getOutput()) - .toMatch(/Building units.* - unit #1;.* - unit #3;.*lines omitted.* - unit #48;.* - unit #50;/); - checkConsoleOutput(terminalProvider); - }); - }); - - it('preservedLeadingBlanksButTrimmedTrailingBlanks', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'large stderr with leading and trailing blanks', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.writeError(`List of errors: ${EOL}`); - for (let i: number = 1; i <= 50; i++) { - writer.writeError(` - error #${i}; ${EOL}`); - } - return Promise.resolve(TaskStatus.Failure); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => fail(EXPECTED_FAIL)) - .catch(err => { - expect(err.message).toMatchSnapshot(); - expect(terminalProvider.getOutput()) - .toMatch(/List of errors:\S.* - error #1;\S.*lines omitted.* - error #48;\S.* - error #50;\S/); - checkConsoleOutput(terminalProvider); - }); - }); - }); - - describe('Warning logging', () => { - describe('Fail on warning', () => { - beforeEach(() => { - taskRunnerOptions = { - quietMode: false, - parallelism: '1', - changedProjectsOnly: false, - terminal, - allowWarningsInSuccessfulBuild: false - }; - }); - - it('Logs warnings correctly', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'success with warnings (failure)', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.write('Build step 1' + EOL); - writer.write('Warning: step 1 succeeded with warnings' + EOL); - return Promise.resolve(TaskStatus.SuccessWithWarning); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => fail('Promise returned by execute() resolved but was expected to fail')) - .catch(err => { - expect(err.message).toMatchSnapshot(); - const allMessages: string = terminalProvider.getOutput(); - expect(allMessages).toContain('Build step 1'); - expect(allMessages).toContain('step 1 succeeded with warnings'); - checkConsoleOutput(terminalProvider); - }); - }); - }); - - describe('Success on warning', () => { - beforeEach(() => { - taskRunnerOptions = { - quietMode: false, - parallelism: '1', - changedProjectsOnly: false, - terminal, - allowWarningsInSuccessfulBuild: true - }; - }); - - it('Logs warnings correctly', () => { - taskRunner = createTaskRunner(taskRunnerOptions, { - name: 'success with warnings (success)', - isIncrementalBuildAllowed: false, - execute: (writer: ITaskWriter) => { - writer.write('Build step 1' + EOL); - writer.write('Warning: step 1 succeeded with warnings' + EOL); - return Promise.resolve(TaskStatus.SuccessWithWarning); - }, - hadEmptyScript: false - }); - - return taskRunner - .execute() - .then(() => { - const allMessages: string = terminalProvider.getOutput(); - expect(allMessages).toContain('Build step 1'); - expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); - checkConsoleOutput(terminalProvider); - }) - .catch(err => fail('Promise returned by execute() rejected but was expected to resolve')); - }); - }); - }); -}); diff --git a/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskCollection.test.ts.snap b/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskCollection.test.ts.snap deleted file mode 100644 index 5953ed6e090..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskCollection.test.ts.snap +++ /dev/null @@ -1,21 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TaskCollection Dependencies detectsDependencyCycle 1`] = ` -"A cyclic dependency was encountered: - foo - -> bar - -> foo -Consider using the cyclicDependencyProjects option for rush.json." -`; - -exports[`TaskCollection Dependencies respectsDependencyOrder 1`] = `""`; - -exports[`TaskCollection Dependencies respectsDependencyOrder 2`] = `""`; - -exports[`TaskCollection Dependencies respectsDependencyOrder 3`] = `""`; - -exports[`TaskCollection Dependencies respectsDependencyOrder 4`] = `""`; - -exports[`TaskCollection Dependencies throwsErrorOnNonExistentDependency 1`] = `"The project 'bar' has not been registered."`; - -exports[`TaskCollection Dependencies throwsErrorOnNonExistentTask 1`] = `"The task 'foo' has not been registered"`; diff --git a/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskRunner.test.ts.snap b/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskRunner.test.ts.snap deleted file mode 100644 index df4428a08e9..00000000000 --- a/apps/rush-lib/src/logic/taskRunner/test/__snapshots__/TaskRunner.test.ts.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TaskRunner Constructor throwsErrorOnInvalidParallelism 1`] = `"Invalid parallelism value of 'tequila', expected a number or 'max'"`; - -exports[`TaskRunner Error logging preservedLeadingBlanksButTrimmedTrailingBlanks 1`] = `"Project(s) failed"`; - -exports[`TaskRunner Error logging preservedLeadingBlanksButTrimmedTrailingBlanks 2`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[large stderr with leading and trailing blanks] started[x][39m[n][n][x][31mFAILURE (1)[x][39m[n][x][31m================================[x][39m[n][x][31mlarge stderr with leading and trailing blanks (0.10 seconds)[x][39m[n]List of errors:[-n-] - error #1;[-n-] - error #2;[-n-] - error #3;[-n-] - error #4;[-n-] - error #5;[-n-] - error #6;[-n-] - error #7;[-n-] - error #8;[-n-] - error #9;[-n-][...21 lines omitted...][-n-] - error #31;[-n-] - error #32;[-n-] - error #33;[-n-] - error #34;[-n-] - error #35;[-n-] - error #36;[-n-] - error #37;[-n-] - error #38;[-n-] - error #39;[-n-] - error #40;[-n-] - error #41;[-n-] - error #42;[-n-] - error #43;[-n-] - error #44;[-n-] - error #45;[-n-] - error #46;[-n-] - error #47;[-n-] - error #48;[-n-] - error #49;[-n-] - error #50;[n][x][31m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Error logging preservedLeadingBlanksButTrimmedTrailingBlanks 3`] = `""`; - -exports[`TaskRunner Error logging preservedLeadingBlanksButTrimmedTrailingBlanks 4`] = `""`; - -exports[`TaskRunner Error logging preservedLeadingBlanksButTrimmedTrailingBlanks 5`] = `"[x][31m[-n-]1 of 1: [large stderr with leading and trailing blanks] failed![x][39m[n]"`; - -exports[`TaskRunner Error logging printedAbridgedStdoutAfterErrorWithEmptyStderr 1`] = `"Project(s) failed"`; - -exports[`TaskRunner Error logging printedAbridgedStdoutAfterErrorWithEmptyStderr 2`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[large stdout only] started[x][39m[n][n][x][31mFAILURE (1)[x][39m[n][x][31m================================[x][39m[n][x][31mlarge stdout only (0.10 seconds)[x][39m[n]Building units...[-n-] - unit #1;[-n-] - unit #2;[-n-] - unit #3;[-n-] - unit #4;[-n-] - unit #5;[-n-] - unit #6;[-n-] - unit #7;[-n-] - unit #8;[-n-] - unit #9;[-n-][...21 lines omitted...][-n-] - unit #31;[-n-] - unit #32;[-n-] - unit #33;[-n-] - unit #34;[-n-] - unit #35;[-n-] - unit #36;[-n-] - unit #37;[-n-] - unit #38;[-n-] - unit #39;[-n-] - unit #40;[-n-] - unit #41;[-n-] - unit #42;[-n-] - unit #43;[-n-] - unit #44;[-n-] - unit #45;[-n-] - unit #46;[-n-] - unit #47;[-n-] - unit #48;[-n-] - unit #49;[-n-] - unit #50;[n][x][31m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Error logging printedAbridgedStdoutAfterErrorWithEmptyStderr 3`] = `""`; - -exports[`TaskRunner Error logging printedAbridgedStdoutAfterErrorWithEmptyStderr 4`] = `""`; - -exports[`TaskRunner Error logging printedAbridgedStdoutAfterErrorWithEmptyStderr 5`] = `"[x][31m[-n-]1 of 1: [large stdout only] failed![x][39m[n]"`; - -exports[`TaskRunner Error logging printedStderrAfterError 1`] = `"Project(s) failed"`; - -exports[`TaskRunner Error logging printedStderrAfterError 2`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[stdout+stderr] started[x][39m[n][n][x][31mFAILURE (1)[x][39m[n][x][31m================================[x][39m[n][x][31mstdout+stderr (0.10 seconds)[x][39m[n]Error: step 1 failed[n][x][31m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Error logging printedStderrAfterError 3`] = `""`; - -exports[`TaskRunner Error logging printedStderrAfterError 4`] = `""`; - -exports[`TaskRunner Error logging printedStderrAfterError 5`] = `"[x][31m[-n-]1 of 1: [stdout+stderr] failed![x][39m[n]"`; - -exports[`TaskRunner Error logging printedStdoutAfterErrorWithEmptyStderr 1`] = `"Project(s) failed"`; - -exports[`TaskRunner Error logging printedStdoutAfterErrorWithEmptyStderr 2`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[stdout only] started[x][39m[n][n][x][31mFAILURE (1)[x][39m[n][x][31m================================[x][39m[n][x][31mstdout only (0.10 seconds)[x][39m[n]Build step 1[-n-]Error: step 1 failed[n][x][31m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Error logging printedStdoutAfterErrorWithEmptyStderr 3`] = `""`; - -exports[`TaskRunner Error logging printedStdoutAfterErrorWithEmptyStderr 4`] = `""`; - -exports[`TaskRunner Error logging printedStdoutAfterErrorWithEmptyStderr 5`] = `"[x][31m[-n-]1 of 1: [stdout only] failed![x][39m[n]"`; - -exports[`TaskRunner Warning logging Fail on warning Logs warnings correctly 1`] = `"An error occurred."`; - -exports[`TaskRunner Warning logging Fail on warning Logs warnings correctly 2`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[success with warnings (failure)] started[x][39m[n][n][x][33m[x][4mSUCCESS WITH WARNINGS (1)[x][24m[x][39m[n][x][33m================================[x][39m[n][x][33m[x][4msuccess with warnings (failure) (0.10 seconds)[x][24m[x][39m[n]Build step 1[-n-]Warning: step 1 succeeded with warnings[n][x][33m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Warning logging Fail on warning Logs warnings correctly 3`] = `""`; - -exports[`TaskRunner Warning logging Fail on warning Logs warnings correctly 4`] = `"[x][33m1 of 1: [success with warnings (failure)] completed with warnings in 0.10 seconds[x][39m[n][x][33mProject(s) succeeded with warnings[x][39m[n]"`; - -exports[`TaskRunner Warning logging Fail on warning Logs warnings correctly 5`] = `""`; - -exports[`TaskRunner Warning logging Success on warning Logs warnings correctly 1`] = `"Executing a maximum of 1 simultaneous processes...[-n-][n][x][37m[success with warnings (success)] started[x][39m[n][n][x][33m[x][4mSUCCESS WITH WARNINGS (1)[x][24m[x][39m[n][x][33m================================[x][39m[n][x][33m[x][4msuccess with warnings (success) (0.10 seconds)[x][24m[x][39m[n]Build step 1[-n-]Warning: step 1 succeeded with warnings[n][x][33m================================[-n-][x][39m[n][n]"`; - -exports[`TaskRunner Warning logging Success on warning Logs warnings correctly 2`] = `""`; - -exports[`TaskRunner Warning logging Success on warning Logs warnings correctly 3`] = `"[x][33m1 of 1: [success with warnings (success)] completed with warnings in 0.10 seconds[x][39m[n]"`; - -exports[`TaskRunner Warning logging Success on warning Logs warnings correctly 4`] = `""`; diff --git a/apps/rush-lib/src/logic/test/ChangeFiles.test.ts b/apps/rush-lib/src/logic/test/ChangeFiles.test.ts deleted file mode 100644 index b8173711c3c..00000000000 --- a/apps/rush-lib/src/logic/test/ChangeFiles.test.ts +++ /dev/null @@ -1,126 +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 { IChangelog } from '../../api/Changelog'; -import { ChangeFiles } from '../ChangeFiles'; -import { RushConfiguration } from '../../api/RushConfiguration'; - -describe('ChangeFiles', () => { - let rushConfiguration: RushConfiguration; - - beforeEach(() => { - rushConfiguration = {} as RushConfiguration; - }); - - describe('getFiles', () => { - it('returns correctly when there is one change file', () => { - const changesPath: string = path.join(__dirname, 'leafChange'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - const expectedPath: string = path.join(changesPath, 'change1.json').replace(/\\/g, '/'); - expect(changeFiles.getFiles()).toEqual([expectedPath]); - }); - - it('returns empty array when no change files', () => { - const changesPath: string = path.join(__dirname, 'noChange'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(changeFiles.getFiles().length).toEqual(0); - }); - - it('returns correctly when change files are categorized', () => { - const changesPath: string = path.join(__dirname, 'categorizedChanges'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - const files: string[] = changeFiles.getFiles(); - expect(files.length).toEqual(3); - - const expectedPathA: string = path.join(changesPath, '@ms', 'a', 'changeA.json').replace(/\\/g, '/'); - const expectedPathB: string = path.join(changesPath, '@ms', 'b', 'changeB.json').replace(/\\/g, '/'); - const expectedPathC: string = path.join(changesPath, 'changeC.json').replace(/\\/g, '/'); - expect(files).toContain(expectedPathA); - expect(files).toContain(expectedPathB); - expect(files).toContain(expectedPathC); - }); - }); - - describe('validate', () => { - it('throws when there is a patch in a hotfix branch.', () => { - const changeFile: string = path.join(__dirname, 'leafChange', 'change1.json'); - const changedPackages: string[] = ['d']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, { hotfixChangeEnabled: true } as RushConfiguration); - }).toThrow(Error); - }); - - it('allows a hotfix in a hotfix branch.', () => { - const changeFile: string = path.join(__dirname, 'multipleHotfixChanges', 'change1.json'); - const changedPackages: string[] = ['a']; - ChangeFiles.validate([changeFile], changedPackages, { hotfixChangeEnabled: true } as RushConfiguration); - }); - - it('throws when there is any missing package.', () => { - const changeFile: string = path.join(__dirname, 'verifyChanges', 'changes.json'); - const changedPackages: string[] = ['a', 'b', 'c']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); - }).toThrow(Error); - }); - - it('does not throw when there is no missing packages', () => { - const changeFile: string = path.join(__dirname, 'verifyChanges', 'changes.json'); - const changedPackages: string[] = ['a']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); - }).not.toThrow(); - }); - - it('throws when missing packages from categorized changes', () => { - const changeFileA: string = path.join(__dirname, 'categorizedChanges', '@ms', 'a', 'changeA.json'); - const changeFileB: string = path.join(__dirname, 'categorizedChanges', '@ms', 'b', 'changeB.json'); - const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; - expect(() => { - ChangeFiles.validate([changeFileA, changeFileB], changedPackages, rushConfiguration); - }).toThrow(Error); - }); - - it('does not throw when no missing packages from categorized changes', () => { - const changeFileA: string = path.join(__dirname, 'categorizedChanges', '@ms', 'a', 'changeA.json'); - const changeFileB: string = path.join(__dirname, 'categorizedChanges', '@ms', 'b', 'changeB.json'); - const changeFileC: string = path.join(__dirname, 'categorizedChanges', 'changeC.json'); - const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; - expect(() => { - ChangeFiles.validate([changeFileA, changeFileB, changeFileC], changedPackages, rushConfiguration); - }).not.toThrow(Error); - }); - }); - - describe('deleteAll', () => { - it('delete all files when there are no prerelease packages', () => { - const changesPath: string = path.join(__dirname, 'multipleChangeFiles'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(changeFiles.deleteAll(false)).toEqual(3); - }); - - it('does not delete change files for package whose change logs do not get updated. ', () => { - const changesPath: string = path.join(__dirname, 'multipleChangeFiles'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - const updatedChangelogs: IChangelog[] = [ - { - name: 'a', - entries: [] - }, - { - name: 'b', - entries: [] - } - ]; - expect(changeFiles.deleteAll(false, updatedChangelogs)).toEqual(2); - }); - - it('delete all files when there are hotfixes', () => { - const changesPath: string = path.join(__dirname, 'multipleHotfixChanges'); - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(changeFiles.deleteAll(false)).toEqual(3); - }); - }); -}); diff --git a/apps/rush-lib/src/logic/test/ChangeManager.test.ts b/apps/rush-lib/src/logic/test/ChangeManager.test.ts deleted file mode 100644 index 4ee6695b2aa..00000000000 --- a/apps/rush-lib/src/logic/test/ChangeManager.test.ts +++ /dev/null @@ -1,170 +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 { RushConfiguration } from '../../api/RushConfiguration'; -import { ChangeManager } from '../ChangeManager'; -import { PrereleaseToken } from '../PrereleaseToken'; - -describe('ChangeManager', () => { - const rushJsonFile: string = path.resolve(__dirname, 'packages', 'rush.json'); - let rushConfiguration: RushConfiguration; - let changeManager: ChangeManager; - - beforeEach(() => { - rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); - changeManager = new ChangeManager(rushConfiguration); - }); - - /* eslint-disable dot-notation */ - it('can apply changes to the package.json files in the dictionary', () => { - changeManager.load(path.join(__dirname, 'multipleChanges')); - changeManager.apply(false); - - expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); - expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1'); - expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( - '>=2.0.0 <3.0.0'); - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0'); - expect(changeManager.allPackages.get('c')!.packageJson.dependencies!['b']).toEqual( - '>=1.0.1 <2.0.0'); - }); - - it('can update explicit version dependency', () => { - changeManager.load(path.join(__dirname, 'explicitVersionChange')); - changeManager.apply(false); - - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); - expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1'); - expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( - '1.0.1'); - }); - - it('can update explicit cyclic dependency', () => { - changeManager.load(path.join(__dirname, 'cyclicDepsExplicit')); - changeManager.apply(false); - - expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual( - '2.0.0'); - expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.dependencies!['cyclic-dep-explicit-2']) - .toEqual( - '>=1.0.0 <2.0.0'); - expect(changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.version).toEqual( - '1.0.0'); - expect(changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.dependencies!['cyclic-dep-explicit-1']) - .toEqual( - '>=1.0.0 <2.0.0'); - }); - - it('can update root with patch change for prerelease', () => { - const prereleaseName: string = 'alpha.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - - changeManager.load(path.join(__dirname, 'rootPatchChange'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual( - '1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual( - '1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( - '1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( - '1.0.1-' + prereleaseName); - }); - - it('can update non-root with patch change for prerelease', () => { - const prereleaseName: string = 'beta.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - - changeManager.load(path.join(__dirname, 'explicitVersionChange'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual( - '1.0.0'); - expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual( - '1.0.0'); - expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( - '>=1.0.0 <2.0.0'); - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( - '1.0.1-' + prereleaseName); - }); - - it('can update cyclic dependency for non-explicit prerelease', () => { - const prereleaseName: string = 'beta.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - - changeManager.load(path.join(__dirname, 'cyclicDeps'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( - '2.0.0-' + prereleaseName); - expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( - '1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual( - '1.0.1-' + prereleaseName); - expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( - '2.0.0-' + prereleaseName); - }); - - it('can update root with patch change for adding version suffix', () => { - const suffix: string = 'dk.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - - changeManager.load(path.join(__dirname, 'rootPatchChange'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); - expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); - expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( - '1.0.0-' + suffix); - }); - - it('can update non-root with patch change for version suffix', () => { - const suffix: string = 'dk.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - - changeManager.load(path.join(__dirname, 'explicitVersionChange'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual( - '1.0.0'); - expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual( - '1.0.0'); - expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( - '>=1.0.0 <2.0.0'); - expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); - expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); - expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( - '1.0.0-' + suffix); - }); - - it('can update cyclic dependency for non-explicit suffix', () => { - const suffix: string = 'dk.1'; - const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - - changeManager.load(path.join(__dirname, 'cyclicDeps'), prereleaseToken); - changeManager.apply(false); - - expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual( - '1.0.0-' + suffix); - expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( - '1.0.0-' + suffix); - }); - /* eslint-enable dot-notation */ -}); diff --git a/apps/rush-lib/src/logic/test/ChangelogGenerator.test.ts b/apps/rush-lib/src/logic/test/ChangelogGenerator.test.ts deleted file mode 100644 index ab0d17d1978..00000000000 --- a/apps/rush-lib/src/logic/test/ChangelogGenerator.test.ts +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { IChangelog } from '../../api/Changelog'; -import { ChangeType } from '../../api/ChangeManagement'; -import { RushConfiguration } from '../../api/RushConfiguration'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { ChangelogGenerator } from '../ChangelogGenerator'; -import { IChangeInfoHash } from '../PublishUtilities'; - -import * as path from 'path'; - -describe('updateIndividualChangelog', () => { - const rushJsonFile: string = path.resolve(__dirname, 'packages', 'rush.json'); - let rushConfiguration: RushConfiguration; - - beforeEach(() => { - rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); - }); - - it('can translate a single change request into a new changelog object', () => { - const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( - { - packageName: 'a', - newVersion: '1.0.0', - changeType: ChangeType.major, - changes: [{ - packageName: 'a', - type: 'major', - changeType: ChangeType.major, - comment: 'Patching a' - }] - }, - 'rootMajorChange', - false, - rushConfiguration - )!; - - const expectedResult: IChangelog = { - name: 'a', - entries: [ - { - version: '1.0.0', - tag: 'a_v1.0.0', - date: '', - comments: { - major: [ - { - author: undefined, - comment: 'Patching a', - commit: undefined - } - ] - } - } - ] - }; - - // Ignore comparing date. - expectedResult.entries[0].date = actualResult.entries[0].date; - - expect(actualResult).toEqual(expectedResult); - }); - - it('can merge a new change request into an existing changelog', () => { - const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( - { - packageName: 'a', - newVersion: '1.0.0', - changeType: ChangeType.major, - changes: [{ - packageName: 'a', - type: 'major', - changeType: ChangeType.major, - comment: 'Patching a' - }] - }, - path.resolve(__dirname, 'exampleChangelog'), - false, - rushConfiguration - )!; - - const expectedResult: IChangelog = { - name: 'a', - entries: [ - { - version: '1.0.0', - tag: 'a_v1.0.0', - date: '', - comments: { - major: [ - { - author: undefined, - comment: 'Patching a', - commit: undefined - } - ] - } - }, - { - version: '0.0.1', - tag: 'a_v0.0.1', - date: 'Wed, 30 Nov 2016 18:37:45 GMT', - comments: { - patch: [ - { - comment: 'Patching a' - } - ] - } - } - ] - }; - - // Ignore comparing date. - expectedResult.entries[0].date = actualResult.entries[0].date; - - expect(actualResult).toEqual(expectedResult); - }); - - it('can avoid adding duplicate entries', () => { - const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( - { - packageName: 'a', - newVersion: '0.0.1', - changeType: ChangeType.patch, - changes: [{ - packageName: 'a', - type: 'patch', - changeType: ChangeType.patch, - comment: 'Patching a' - }] - }, - path.resolve(__dirname, 'exampleChangelog'), - false, - rushConfiguration - )!; - - expect(actualResult).not.toBeDefined(); - }); - - it('can handle dependency bumps', () => { - const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( - { - packageName: 'a', - newVersion: '0.0.2', - changeType: ChangeType.dependency, - changes: [{ - packageName: 'a', - type: 'dependency', - changeType: ChangeType.dependency, - comment: 'Updating a' - }] - }, - path.resolve(__dirname, 'exampleChangelog'), - false, - rushConfiguration - )!; - - const expectedResult: IChangelog = { - name: 'a', - entries: [ - { - version: '0.0.2', - tag: 'a_v0.0.2', - date: undefined, - comments: { - dependency: [ - { - author: undefined, - comment: 'Updating a', - commit: undefined - } - ] - } - }, - { - version: '0.0.1', - tag: 'a_v0.0.1', - date: 'Wed, 30 Nov 2016 18:37:45 GMT', - comments: { - patch: [ - { - comment: 'Patching a' - } - ] - } - } - ] - }; - - // Remove date. - actualResult.entries[0].date = undefined; - - expect(actualResult).toEqual(expectedResult); - }); - - it('skip empty comment', () => { - const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( - { - packageName: 'a', - newVersion: '0.0.2', - changeType: ChangeType.none, - changes: [{ - packageName: 'a', - type: 'none', - changeType: ChangeType.none, - comment: '' - }] - }, - path.resolve(__dirname, 'exampleChangelog'), - false, - rushConfiguration - )!; - - const expectedResult: IChangelog = { - name: 'a', - entries: [ - { - version: '0.0.2', - tag: 'a_v0.0.2', - date: undefined, - comments: {} - }, - { - version: '0.0.1', - tag: 'a_v0.0.1', - date: 'Wed, 30 Nov 2016 18:37:45 GMT', - comments: { - patch: [ - { - comment: 'Patching a' - } - ] - } - } - ] - }; - - // Remove date. - actualResult.entries[0].date = undefined; - - expect(actualResult).toEqual(expectedResult); - }); -}); - -describe('updateChangelogs', () => { - const rushJsonFile: string = path.resolve(__dirname, 'packages', 'rush.json'); - let rushConfiguration: RushConfiguration; - - beforeEach(() => { - rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); - }); - - /* eslint-disable dot-notation */ - it('skips changes logs if the project version is not changed.', () => { - const changeHash: IChangeInfoHash = {}; - // Package a does not have version change. - changeHash['a'] = { - packageName: 'a', - changeType: ChangeType.dependency, - newVersion: '1.0.0', - changes: [] - }; - // Package b has version change. - changeHash['b'] = { - packageName: 'b', - changeType: ChangeType.patch, - newVersion: '1.0.1', - changes: [] - }; - const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( - changeHash, - rushConfiguration.projectsByName, - rushConfiguration, - false - ); - expect(updatedChangeLogs.length).toEqual(1); - expect(updatedChangeLogs[0].name).toEqual('b'); - }); - - it('skips changes logs if the project is in pre-release', () => { - const changeHash: IChangeInfoHash = {}; - // Package a is a prerelease - changeHash['a'] = { - packageName: 'a', - changeType: ChangeType.dependency, - newVersion: '1.0.1-pre.1', - changes: [] - }; - // Package b is not a prerelease - changeHash['b'] = { - packageName: 'b', - changeType: ChangeType.patch, - newVersion: '1.0.1', - changes: [] - }; - // Makes package 'a' prerelease package. - const rushProjectA: RushConfigurationProject = rushConfiguration.projectsByName.get('a')!; - rushProjectA.packageJson.version = '1.0.1-pre.1'; - - const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( - changeHash, - rushConfiguration.projectsByName, - rushConfiguration, - false - ); - expect(updatedChangeLogs.length).toEqual(1); - expect(updatedChangeLogs[0].name).toEqual('b'); - }); - - it('writes changelog for hotfix changes', () => { - const changeHash: IChangeInfoHash = {}; - // Package a is a hotfix - changeHash['a'] = { - packageName: 'a', - changeType: ChangeType.hotfix, - newVersion: '1.0.1-hotfix.1', - changes: [] - }; - // Package b is not a hotfix - changeHash['b'] = { - packageName: 'b', - changeType: ChangeType.patch, - newVersion: '1.0.1', - changes: [] - }; - // Makes package 'a' hotfix package. - const rushProjectA: RushConfigurationProject = rushConfiguration.projectsByName.get('a')!; - rushProjectA.packageJson.version = '1.0.1-hotfix.1'; - - const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( - changeHash, - rushConfiguration.projectsByName, - rushConfiguration, - false - ); - expect(updatedChangeLogs.length).toEqual(2); - expect(updatedChangeLogs[0].name).toEqual('a'); - expect(updatedChangeLogs[1].name).toEqual('b'); - }); - /* eslint-enable dot-notation */ -}); diff --git a/apps/rush-lib/src/logic/test/PackageChangeAnalyzer.test.ts b/apps/rush-lib/src/logic/test/PackageChangeAnalyzer.test.ts deleted file mode 100644 index e76cd297c0b..00000000000 --- a/apps/rush-lib/src/logic/test/PackageChangeAnalyzer.test.ts +++ /dev/null @@ -1,89 +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 { PackageChangeAnalyzer } from '../PackageChangeAnalyzer'; -import { RushConfiguration } from '../../api/RushConfiguration'; - -import { - IPackageDeps -} from '@rushstack/package-deps-hash'; - -const packageA: string = 'project-a'; -const packageAPath: string = path.join('tools', packageA); -const fileA: string = path.join(packageAPath, 'src/index.ts'); -// const packageB: string = 'project-b'; -// const packageBPath: string = path.join('tools', packageB); -// const fileB: string = path.join(packageBPath, 'src/index.ts'); -// const packageBPath: string = path.join('tools', packageB); -const HASH: string = '12345abcdef'; -// const looseFile: string = 'some/other/folder/index.ts'; - -describe('PackageChangeAnalyzer', () => { - it('can associate a file in a project folder with a project', () => { - const repoHashDeps: IPackageDeps = { - files: { - [fileA]: HASH, - [path.posix.join('common', 'config', 'rush', 'pnpm-lock.yaml')]: HASH - } - }; - - PackageChangeAnalyzer.getPackageDeps = (packagePath: string, ignored: string[]) => repoHashDeps; - const rushConfiguration: RushConfiguration = { - commonRushConfigFolder: '', - projects: [{ - packageName: packageA, - projectRelativeFolder: packageAPath - }], - rushJsonFolder: '', - getCommittedShrinkwrapFilename(): string { - return 'common/config/rush/pnpm-lock.yaml'; - } - } as any; // eslint-disable-line @typescript-eslint/no-explicit-any - - const packageChangeAnalyzer: PackageChangeAnalyzer = new PackageChangeAnalyzer(rushConfiguration); - const packageDeps: IPackageDeps | undefined = packageChangeAnalyzer.getPackageDepsHash(packageA); - expect(packageDeps).toEqual(repoHashDeps); - }); - - /* - it('associates a file that is not in a project with all projects', () => { - const repoHashDeps: IPackageDeps = { - files: { - [looseFile]: HASH, - [fileA]: HASH, - [fileB]: HASH - } - }; - - PackageChangeAnalyzer.getPackageDeps = (path: string, ignored: string[]) => repoHashDeps; - PackageChangeAnalyzer.rushConfig = { - projects: [{ - packageName: packageA, - projectRelativeFolder: packageAPath - }, - { - packageName: packageB, - projectRelativeFolder: packageBPath - }] - } as any; // eslint-disable-line @typescript-eslint/no-explicit-any - - let packageDeps: IPackageDeps = PackageChangeAnalyzer.instance.getPackageDepsHash(packageA); - expect(packageDeps).toEqual({ - files: { - [looseFile]: HASH, - [fileA]: HASH - } - }); - - packageDeps = PackageChangeAnalyzer.instance.getPackageDepsHash(packageB); - expect(packageDeps).toEqual({ - files: { - [looseFile]: HASH, - [fileB]: HASH - } - }); - }); - */ -}); diff --git a/apps/rush-lib/src/logic/test/PublishUtilities.test.ts b/apps/rush-lib/src/logic/test/PublishUtilities.test.ts deleted file mode 100644 index bb4f0047845..00000000000 --- a/apps/rush-lib/src/logic/test/PublishUtilities.test.ts +++ /dev/null @@ -1,334 +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 { - IChangeInfo, - ChangeType -} from '../../api/ChangeManagement'; -import { RushConfiguration } from '../../api/RushConfiguration'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { - PublishUtilities, - IChangeInfoHash -} from '../PublishUtilities'; -import { ChangeFiles } from '../ChangeFiles'; - -/* eslint-disable dot-notation */ - -describe('findChangeRequests', () => { - let packagesRushConfiguration: RushConfiguration; - let repoRushConfiguration: RushConfiguration; - - beforeEach(() => { - packagesRushConfiguration = RushConfiguration.loadFromConfigurationFile( - path.resolve(__dirname, 'packages', 'rush.json') - ); - repoRushConfiguration = RushConfiguration.loadFromConfigurationFile( - path.resolve(__dirname, 'repo', 'rush.json') - ); - }); - - it('returns no changes in an empty change folder', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'noChange')) - ); - - expect(Object.keys(allChanges).length).toEqual(0); - }); - - it('returns 1 change when changing a leaf package', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'leafChange')) - ); - - expect(Object.keys(allChanges).length).toEqual(1); - expect(allChanges).toHaveProperty('d'); - expect(allChanges['d'].changeType).toEqual(ChangeType.patch); - }); - - it('returns 2 changes when patching a root package', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'rootPatchChange')) - ); - - expect(Object.keys(allChanges).length).toEqual(2); - - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - - expect(allChanges['a'].changeType).toEqual(ChangeType.patch); - expect(allChanges['b'].changeType).toEqual(ChangeType.dependency); - - expect(allChanges['a'].newVersion).toEqual('1.0.1'); - expect(allChanges['b'].newVersion).toEqual('1.0.0'); - }); - - it('returns 4 changes when hotfixing a root package', () => { - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - packagesRushConfiguration.projectsByName, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'rootHotfixChange')) - ); - - expect(Object.keys(allChanges).length).toEqual(4); - - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - - expect(allChanges['a'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['b'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['c'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['d'].changeType).toEqual(ChangeType.hotfix); - - expect(allChanges['a'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['b'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['c'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['d'].newVersion).toEqual('1.0.0-hotfix.0'); - }); - - it('returns 3 changes when major bumping a root package', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'rootMajorChange')) - ); - - expect(Object.keys(allChanges).length).toEqual(3); - - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - expect(allChanges).toHaveProperty('c'); - - expect(allChanges['a'].changeType).toEqual(ChangeType.major); - expect(allChanges['b'].changeType).toEqual(ChangeType.patch); - expect(allChanges['c'].changeType).toEqual(ChangeType.dependency); - - expect(allChanges['a'].newVersion).toEqual('2.0.0'); - expect(allChanges['b'].newVersion).toEqual('1.0.1'); - expect(allChanges['c'].newVersion).toEqual('1.0.0'); - }); - - it('returns 2 changes when bumping cyclic dependencies', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'cyclicDeps')) - ); - - expect(Object.keys(allChanges).length).toEqual(2); - - expect(allChanges).toHaveProperty('cyclic-dep-1'); - expect(allChanges).toHaveProperty('cyclic-dep-2'); - - expect(allChanges['cyclic-dep-1'].changeType).toEqual(ChangeType.major); - expect(allChanges['cyclic-dep-2'].changeType).toEqual(ChangeType.patch); - }); - - it('returns error when mixing hotfix and non-hotfix changes', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - expect(PublishUtilities.findChangeRequests.bind( - PublishUtilities, - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'hotfixWithPatchChanges')))) - .toThrow('Cannot apply hotfix alongside patch change on same package'); - }); - - it('returns error when adding hotfix with config disabled', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - // Overload hotfixChangeEnabled function - packagesRushConfiguration['_hotfixChangeEnabled'] = false; - - expect(PublishUtilities.findChangeRequests.bind( - PublishUtilities, - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'rootHotfixChange')))) - .toThrow('Cannot add hotfix change; hotfixChangeEnabled is false in configuration.'); - }); - - it('can resolve multiple changes requests on the same package', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'multipleChanges')) - ); - - expect(Object.keys(allChanges).length).toEqual(3); - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - expect(allChanges).toHaveProperty('c'); - expect(allChanges['a'].changeType).toEqual(ChangeType.major); - expect(allChanges['b'].changeType).toEqual(ChangeType.patch); - expect(allChanges['c'].changeType).toEqual(ChangeType.dependency); - expect(allChanges['a'].newVersion).toEqual('2.0.0'); - expect(allChanges['b'].newVersion).toEqual('1.0.1'); - expect(allChanges['c'].newVersion).toEqual('1.0.0'); - }); - - it('can resolve multiple reverse-ordered changes requests on the same package', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'orderedChanges'))); - - expect(Object.keys(allChanges).length).toEqual(3); - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - expect(allChanges).toHaveProperty('c'); - expect(allChanges['a'].changeType).toEqual(ChangeType.major); - expect(allChanges['b'].changeType).toEqual(ChangeType.patch); - expect(allChanges['c'].changeType).toEqual(ChangeType.dependency); - expect(allChanges['a'].newVersion).toEqual('2.0.0'); - expect(allChanges['b'].newVersion).toEqual('1.0.1'); - expect(allChanges['c'].newVersion).toEqual('1.0.0'); - }); - - it('can resolve multiple hotfix changes', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'multipleHotfixChanges'))); - - expect(Object.keys(allChanges).length).toEqual(4); - expect(allChanges).toHaveProperty('a'); - expect(allChanges).toHaveProperty('b'); - expect(allChanges).toHaveProperty('c'); - expect(allChanges).toHaveProperty('d'); - - expect(allChanges['a'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['b'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['c'].changeType).toEqual(ChangeType.hotfix); - expect(allChanges['d'].changeType).toEqual(ChangeType.hotfix); - - expect(allChanges['a'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['b'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['c'].newVersion).toEqual('1.0.0-hotfix.0'); - expect(allChanges['d'].newVersion).toEqual('1.0.0-hotfix.0'); - }); - - it('can update an explicit dependency', () => { - const allPackages: Map = packagesRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - packagesRushConfiguration, - new ChangeFiles(path.join(__dirname, 'explicitVersionChange'))); - - expect(Object.keys(allChanges).length).toEqual(2); - expect(allChanges).toHaveProperty('c'); - expect(allChanges).toHaveProperty('d'); - expect(allChanges['c'].changeType).toEqual(ChangeType.patch); - expect(allChanges['d'].changeType).toEqual(ChangeType.patch); - }); - - it('can exclude lock step projects', () => { - const allPackages: Map = repoRushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - repoRushConfiguration, - new ChangeFiles(path.join(__dirname, 'repo', 'changes')), - false, - undefined, - new Set(['a', 'b', 'e'])); - expect(Object.keys(allChanges).length).toEqual(5); - expect(allChanges['a'].newVersion).toEqual('1.0.0'); - expect(allChanges['b'].newVersion).toEqual('2.0.0'); - expect(allChanges['c'].changeType).toEqual(ChangeType.patch); - expect(allChanges['c'].newVersion).toEqual('3.1.2'); - expect(allChanges['d'].changeType).toEqual(ChangeType.patch); - expect(allChanges['d'].newVersion).toEqual('4.1.2'); - expect(allChanges['e'].newVersion).toEqual(allPackages.get('e')!.packageJson.version); - }); -}); - -describe('sortChangeRequests', () => { - let rushConfiguration: RushConfiguration; - - beforeEach(() => { - rushConfiguration = RushConfiguration.loadFromConfigurationFile(path.resolve(__dirname, 'packages', 'rush.json')); - }); - - it('can return a sorted array of the change requests to be published in the correct order', () => { - const allPackages: Map = rushConfiguration.projectsByName; - const allChanges: IChangeInfoHash = PublishUtilities.findChangeRequests( - allPackages, - rushConfiguration, - new ChangeFiles(path.join(__dirname, 'multipleChanges'))); - const orderedChanges: IChangeInfo[] = PublishUtilities.sortChangeRequests(allChanges); - - expect(orderedChanges.length).toEqual(3); - expect(orderedChanges[0].packageName).toEqual('a'); - expect(orderedChanges[1].packageName).toEqual('b'); - expect(orderedChanges[2].packageName).toEqual('c'); - }); -}); - -describe('isRangeDependency', () => { - it('can test ranges', () => { - expect(PublishUtilities.isRangeDependency('>=1.0.0 <2.0.0')).toEqual(true); - expect(PublishUtilities.isRangeDependency('>=1.0.0-pr.1 <2.0.0')).toEqual(true); - expect(PublishUtilities.isRangeDependency('1.0.0')).toEqual(false); - expect(PublishUtilities.isRangeDependency('^1.0.0')).toEqual(false); - expect(PublishUtilities.isRangeDependency('~1.0.0')).toEqual(false); - }); -}); - -describe('getNewDependencyVersion', () => { - it('can update dependency versions', () => { - const dependencies: { [key: string]: string} = { - 'a': '~1.0.0', - 'b': '^1.0.0', - 'c': '>=1.0.0 <2.0.0' - }; - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'a', '1.1.0')).toEqual('~1.1.0'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'b', '1.2.0')).toEqual('^1.2.0'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'c', '1.3.0')).toEqual('>=1.3.0 <2.0.0'); - }); - - it('can update dependency versions with prereleases', () => { - const dependencies: { [key: string]: string} = { - 'a': '~1.0.0-pr.1', - 'b': '^1.0.0-pr.1', - 'c': '>=1.0.0-pr.1 <2.0.0' - }; - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'a', '1.1.0-pr.1')).toEqual('~1.1.0-pr.1'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'b', '1.2.0-pr.2')).toEqual('^1.2.0-pr.2'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'c', '1.3.0-pr.3')).toEqual('>=1.3.0-pr.3 <2.0.0'); - }); - - it('can update to prerelease', () => { - const dependencies: { [key: string]: string} = { - 'a': '~1.0.0', - 'b': '^1.0.0', - 'c': '>=1.0.0 <2.0.0' - }; - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'a', '1.0.0-hotfix.0')).toEqual('~1.0.0-hotfix.0'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'b', '1.0.0-hotfix.0')).toEqual('^1.0.0-hotfix.0'); - expect(PublishUtilities.getNewDependencyVersion(dependencies, - 'c', '1.0.0-hotfix.0')).toEqual('>=1.0.0-hotfix.0 <2.0.0'); - }); -}); \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/ShrinkwrapFile.test.ts b/apps/rush-lib/src/logic/test/ShrinkwrapFile.test.ts deleted file mode 100644 index 6745e36de1f..00000000000 --- a/apps/rush-lib/src/logic/test/ShrinkwrapFile.test.ts +++ /dev/null @@ -1,134 +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 { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; -import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; -import { parsePnpmDependencyKey } from '../pnpm/PnpmShrinkwrapFile'; -import { DependencySpecifier } from '../DependencySpecifier'; - -describe('npm ShrinkwrapFile', () => { - const filename: string = path.resolve(path.join(__dirname, './shrinkwrapFile/npm-shrinkwrap.json')); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('npm', filename)!; - - it('verifies root-level dependency', () => { - expect(shrinkwrapFile.hasCompatibleTopLevelDependency(new DependencySpecifier('q', '~1.5.0'))).toEqual(true); - }); - - it('verifies temp project dependencies', () => { - // Found locally - expect(shrinkwrapFile.tryEnsureCompatibleDependency(new DependencySpecifier('jquery', '>=2.2.4 <3.0.0'), - '@rush-temp/project2')) - .toEqual(true); - // Found at root - expect(shrinkwrapFile.tryEnsureCompatibleDependency(new DependencySpecifier('q', '~1.5.0'), '@rush-temp/project2')) - .toEqual(true); - }); - - it('extracts temp projects successfully', () => { - const tempProjectNames: ReadonlyArray = shrinkwrapFile.getTempProjectNames(); - - expect(tempProjectNames).toEqual(['@rush-temp/project1', '@rush-temp/project2' ]); - }); -}); - -describe('pnpm ShrinkwrapFile', () => { -const filename: string = path.resolve(path.join( - __dirname, '../../../src/logic/test/shrinkwrapFile/pnpm-lock.yaml')); -const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; - - it('verifies root-level dependency', () => { - expect(shrinkwrapFile.hasCompatibleTopLevelDependency(new DependencySpecifier('q', '~1.5.0'))).toEqual(false); - }); - - it('verifies temp project dependencies', () => { - expect(shrinkwrapFile.tryEnsureCompatibleDependency(new DependencySpecifier('jquery', '>=2.0.0 <3.0.0'), - '@rush-temp/project1')) - .toEqual(true); - expect(shrinkwrapFile.tryEnsureCompatibleDependency( - new DependencySpecifier('q', '~1.5.0'), '@rush-temp/project2')).toEqual(true); - expect(shrinkwrapFile.tryEnsureCompatibleDependency( - new DependencySpecifier('left-pad', '~9.9.9'), '@rush-temp/project1')).toEqual(false); - expect(shrinkwrapFile.tryEnsureCompatibleDependency( - new DependencySpecifier('@scope/testDep', '>=1.0.0 <2.0.0'), '@rush-temp/project3')) - .toEqual(true); - }); - - it('extracts temp projects successfully', () => { - const tempProjectNames: ReadonlyArray = shrinkwrapFile.getTempProjectNames(); - - expect(tempProjectNames).toEqual(['@rush-temp/project1', '@rush-temp/project2', '@rush-temp/project3']); - }); - - it('can reuse the latest version that another temp package is providing', () => { - expect(shrinkwrapFile.tryEnsureCompatibleDependency(new DependencySpecifier('jquery', '>=2.0.0 <3.0.0'), - '@rush-temp/project3')) - .toEqual(true); - }); -}); - -function testParsePnpmDependencyKey(packageName: string, key: string): string | undefined { - const specifier: DependencySpecifier | undefined = parsePnpmDependencyKey(packageName, key); - if (!specifier) { - return undefined; - } - return specifier.versionSpecifier; -} - -describe('extractVersionFromPnpmVersionSpecifier', () => { - it('extracts a simple version with no slashes', () => { - expect(testParsePnpmDependencyKey('anonymous', '0.0.5')) - .toEqual('0.0.5'); - }); - it('extracts a simple package name', () => { - expect(testParsePnpmDependencyKey('isarray', '/isarray/2.0.5')) - .toEqual('2.0.5'); - expect(testParsePnpmDependencyKey('@scope/test-dep', '/@scope/test-dep/1.2.3-beta.3')) - .toEqual('1.2.3-beta.3'); - }); - it('extracts a registry-qualified path', () => { - expect(testParsePnpmDependencyKey('@scope/test-dep', 'example.pkgs.visualstudio.com/@scope/test-dep/1.0.0')) - .toEqual('1.0.0'); - expect(testParsePnpmDependencyKey('@scope/test-dep', 'example.pkgs.visualstudio.com/@scope/test-dep/1.2.3-beta.3')) - .toEqual('1.2.3-beta.3'); - }); - it('extracts a V3 peer dependency path', () => { - expect(testParsePnpmDependencyKey('gulp-karma', '/gulp-karma/0.0.5/karma@0.13.22')) - .toEqual('0.0.5'); - expect(testParsePnpmDependencyKey('sinon-chai', '/sinon-chai/2.8.0/chai@3.5.0+sinon@1.17.7')) - .toEqual('2.8.0'); - expect(testParsePnpmDependencyKey('@ms/sp-client-utilities', '/@ms/sp-client-utilities/3.1.1/foo@13.1.0')) - .toEqual('3.1.1'); - expect(testParsePnpmDependencyKey('tslint-microsoft-contrib', - '/tslint-microsoft-contrib/6.2.0/tslint@5.18.0+typescript@3.5.3')) - .toEqual('6.2.0'); - }); - it('extracts a V5 peer dependency path', () => { - expect(testParsePnpmDependencyKey('anonymous', '23.6.0_babel-core@6.26.3')) - .toEqual('23.6.0'); - expect(testParsePnpmDependencyKey('anonymous', '1.0.7_request@2.88.0')) - .toEqual('1.0.7'); - expect(testParsePnpmDependencyKey('anonymous', '1.0.3_@pnpm+logger@1.0.2')) - .toEqual('1.0.3'); - expect(testParsePnpmDependencyKey('tslint-microsoft-contrib', - '/tslint-microsoft-contrib/6.2.0_tslint@5.18.0+typescript@3.5.3')) - .toEqual('6.2.0'); - }); - it('detects NPM package aliases', () => { - expect(testParsePnpmDependencyKey('alias1', '/isarray/2.0.5')) - .toEqual('npm:isarray@2.0.5'); - expect(testParsePnpmDependencyKey('alias2', '/@ms/sp-client-utilities/3.1.1/foo@13.1.0')) - .toEqual('npm:@ms/sp-client-utilities@3.1.1'); - }); - it('handles bad cases', () => { - expect(testParsePnpmDependencyKey('example', '/foo/gulp-karma/0.0.5/karma@0.13.22')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', '/@ms/3.1.1/foo@13.1.0')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', 'file:projects/my-app.tgz')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', '')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', '/')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', '//')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', '/@/')).toEqual(undefined); - expect(testParsePnpmDependencyKey('example', 'example.pkgs.visualstudio.com/@scope/testDep/')).toEqual(undefined); - }); -}); diff --git a/apps/rush-lib/src/logic/test/Telemetry.test.ts b/apps/rush-lib/src/logic/test/Telemetry.test.ts deleted file mode 100644 index 2685880d048..00000000000 --- a/apps/rush-lib/src/logic/test/Telemetry.test.ts +++ /dev/null @@ -1,99 +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 { RushConfiguration } from '../../api/RushConfiguration'; -import { Rush } from '../../api/Rush'; -import { - Telemetry, - ITelemetryData - } from '../Telemetry'; - -describe('Telemetry', () => { - it('adds data to store if telemetry is enabled', () => { - const filename: string = path.resolve(path.join(__dirname, './telemetry/telemetryEnabled.json')); - const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); - const telemetry: Telemetry = new Telemetry(rushConfig); - const logData1: ITelemetryData = { - name: 'testData1', - duration: 100, - result: 'Succeeded', - timestamp: new Date().getTime(), - platform: process.platform, - rushVersion: Rush.version - }; - - const logData2: ITelemetryData = { - name: 'testData2', - duration: 100, - result: 'Failed', - timestamp: new Date().getTime(), - platform: process.platform, - rushVersion: Rush.version - }; - - telemetry.log(logData1); - telemetry.log(logData2); - expect(telemetry.store).toEqual([logData1, logData2]); - }); - - it('does not add data to store if telemetry is not enabled', () => { - const filename: string = path.resolve(path.join(__dirname, './telemetry/telemetryNotEnabled.json')); - const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); - const telemetry: Telemetry = new Telemetry(rushConfig); - const logData: ITelemetryData = { - name: 'testData', - duration: 100, - result: 'Succeeded', - timestamp: new Date().getTime(), - platform: process.platform, - rushVersion: Rush.version - }; - - telemetry.log(logData); - expect(telemetry.store).toEqual([]); - }); - - it('deletes data after flush', () => { - const filename: string = path.resolve(path.join(__dirname, './telemetry/telemetryEnabled.json')); - const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); - const telemetry: Telemetry = new Telemetry(rushConfig); - const logData: ITelemetryData = { - name: 'testData1', - duration: 100, - result: 'Succeeded', - timestamp: new Date().getTime(), - platform: process.platform, - rushVersion: Rush.version - }; - - telemetry.log(logData); - let logFile: string; - let dataToWrite: string; - telemetry.flush((file, data) => { - logFile = file; - dataToWrite = data; - }); - expect(logFile!.match(/telemetry_.*\.json/)).toBeDefined(); - expect(dataToWrite!).toEqual(JSON.stringify([logData])); - expect(telemetry.store).toEqual([]); - }); - - it('populates default fields', () => { - const filename: string = path.resolve(path.join(__dirname, './telemetry/telemetryEnabled.json')); - const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); - const telemetry: Telemetry = new Telemetry(rushConfig); - const logData: ITelemetryData = { - name: 'testData1', - duration: 100, - result: 'Succeeded' - }; - - telemetry.log(logData); - const result: ITelemetryData = telemetry.store[0]; - expect(result.platform).toEqual(process.platform); - expect(result.rushVersion).toEqual(Rush.version); - expect(result.timestamp).toBeDefined(); - }); -}); \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/VersionManager.test.ts b/apps/rush-lib/src/logic/test/VersionManager.test.ts deleted file mode 100644 index a12307904eb..00000000000 --- a/apps/rush-lib/src/logic/test/VersionManager.test.ts +++ /dev/null @@ -1,98 +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 { IPackageJson } from '@rushstack/node-core-library'; - -import { BumpType } from '../../api/VersionPolicy'; -import { ChangeFile } from '../../api/ChangeFile'; -import { ChangeType, IChangeInfo } from '../../api/ChangeManagement'; -import { RushConfiguration } from '../../api/RushConfiguration'; -import { VersionManager } from '../VersionManager'; - -function _getChanges(changeFiles: Map, - packageName: string): IChangeInfo[] | undefined { - const changeFile: ChangeFile | undefined = changeFiles.get(packageName); - if (!changeFile) { - return undefined; - } - return changeFile.getChanges(packageName); -} - -describe('VersionManager', () => { - const rushJsonFile: string = path.resolve(__dirname, 'repo', 'rush.json'); - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); - let versionManager: VersionManager; - - beforeEach(() => { - versionManager = new VersionManager(rushConfiguration, 'test@microsoft.com', - rushConfiguration.versionPolicyConfiguration); - }); - - /* eslint-disable dot-notation */ - describe('ensure', () => { - it('fixes lock step versions', () => { - versionManager.ensure('testPolicy1'); - const updatedPackages: Map = versionManager.updatedProjects; - const expectedVersion: string = '10.10.0'; - expect(updatedPackages.size).toEqual(6); - expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); - expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); - expect(updatedPackages.get('b')!.dependencies!['a']).toEqual(`~${expectedVersion}`); - expect(updatedPackages.get('c')!.version).toEqual('3.1.1'); - expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`>=10.10.0 <11.0.0`); - expect(updatedPackages.get('d')!.version).toEqual('4.1.1'); - expect(updatedPackages.get('d')!.dependencies!['b']).toEqual(`>=10.10.0 <11.0.0`); - expect(updatedPackages.get('f')!.version).toEqual('1.0.0'); - expect(updatedPackages.get('f')!.dependencies!['a']).toEqual(`~10.10.0`); - expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`~10.10.0`); - - const changeFiles: Map = versionManager.changeFiles; - expect(changeFiles.size).toEqual(4); - expect(_getChanges(changeFiles, 'a')!.length).toEqual(1); - expect(_getChanges(changeFiles, 'a')![0].changeType).toEqual(ChangeType.none); - expect(_getChanges(changeFiles, 'b')!.length).toEqual(1); - expect(_getChanges(changeFiles, 'b')![0].changeType).toEqual(ChangeType.none); - expect(_getChanges(changeFiles, 'c')!.length).toEqual(2); - expect(_getChanges(changeFiles, 'c')![0].changeType).toEqual(ChangeType.patch); - expect(_getChanges(changeFiles, 'c')![1].changeType).toEqual(ChangeType.dependency); - expect(_getChanges(changeFiles, 'd')!.length).toEqual(2); - expect(_getChanges(changeFiles, 'd')![0].changeType).toEqual(ChangeType.patch); - expect(_getChanges(changeFiles, 'd')![1].changeType).toEqual(ChangeType.dependency); - }); - - it('fixes major version for individual version policy', () => { - versionManager.ensure('testPolicy2'); - const updatedPackages: Map = versionManager.updatedProjects; - expect(updatedPackages.size).toEqual(2); - expect(updatedPackages.get('c')!.version).toEqual('5.0.0'); - expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`>=2.0.0 <3.0.0`); - expect(updatedPackages.get('e')!.version).toEqual('10.10.0'); - expect(updatedPackages.get('e')!.dependencies!['c']).toEqual('~5.0.0'); - }); - - it('does not change packageJson if not needed by individual version policy', () => { - versionManager.ensure('testPolicy3'); - const updatedPackages: Map = versionManager.updatedProjects; - expect(updatedPackages.size).toEqual(0); - }); - }); - - describe('bump', () => { - it('bumps to prerelease version', () => { - versionManager.bump('testPolicy1', BumpType.prerelease, 'dev', false); - const updatedPackages: Map = versionManager.updatedProjects; - const expectedVersion: string = '10.10.1-dev.0'; - - const changeFiles: Map = versionManager.changeFiles; - - expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); - expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); - expect(updatedPackages.get('e')!.version).toEqual(expectedVersion); - expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`~${expectedVersion}`); - expect(_getChanges(changeFiles, 'a')).not.toBeDefined(); - expect(_getChanges(changeFiles, 'b')).not.toBeDefined(); - }); - }); - /* eslint-enable dot-notation */ -}); diff --git a/apps/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json b/apps/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json deleted file mode 100644 index ea8d5e5512b..00000000000 --- a/apps/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "@ms/a", - "type": "patch", - "comment": "Patching a" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json b/apps/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json deleted file mode 100644 index 04a08006251..00000000000 --- a/apps/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "@ms/b", - "type": "patch", - "comment": "Patching b" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/categorizedChanges/changeC.json b/apps/rush-lib/src/logic/test/categorizedChanges/changeC.json deleted file mode 100644 index 8c1bb8d1afc..00000000000 --- a/apps/rush-lib/src/logic/test/categorizedChanges/changeC.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "c", - "type": "patch", - "comment": "Patching c" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/cyclicDeps/change.json b/apps/rush-lib/src/logic/test/cyclicDeps/change.json deleted file mode 100644 index a00be2d78f4..00000000000 --- a/apps/rush-lib/src/logic/test/cyclicDeps/change.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "cyclic-dep-1", - "type": "major", - "comment": "Patching cyclic dep" - }] -} diff --git a/apps/rush-lib/src/logic/test/cyclicDepsExplicit/change.json b/apps/rush-lib/src/logic/test/cyclicDepsExplicit/change.json deleted file mode 100644 index 9c2611f595c..00000000000 --- a/apps/rush-lib/src/logic/test/cyclicDepsExplicit/change.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "cyclic-dep-explicit-1", - "type": "major", - "comment": "Patching cyclic dep" - }] -} diff --git a/apps/rush-lib/src/logic/test/explicitVersionChange/change1.json b/apps/rush-lib/src/logic/test/explicitVersionChange/change1.json deleted file mode 100644 index 64fa9ff4758..00000000000 --- a/apps/rush-lib/src/logic/test/explicitVersionChange/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "c", - "type": "patch", - "comment": "Patching c" - }] -} diff --git a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json b/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json deleted file mode 100644 index 5e78e627b42..00000000000 --- a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patch change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json b/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json deleted file mode 100644 index 51599cdb92c..00000000000 --- a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "hotfix", - "comment": "Hotfix change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json b/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json deleted file mode 100644 index 5e78e627b42..00000000000 --- a/apps/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patch change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/leafChange/change1.json b/apps/rush-lib/src/logic/test/leafChange/change1.json deleted file mode 100644 index ae14879c7d5..00000000000 --- a/apps/rush-lib/src/logic/test/leafChange/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "d", - "type": "patch", - "comment": "Patching d" - }] -} diff --git a/apps/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json b/apps/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json deleted file mode 100644 index 2a6c188679c..00000000000 --- a/apps/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "policyName": "lockStep1", - "definitionName": "lockStepVersion", - "version": "1.0.0", - "nextBump": "prerelease", - "mainProject": "b" - } -] \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/multipleChangeFiles/a.json b/apps/rush-lib/src/logic/test/multipleChangeFiles/a.json deleted file mode 100644 index b213de70852..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChangeFiles/a.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patch change to a" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/multipleChangeFiles/b.json b/apps/rush-lib/src/logic/test/multipleChangeFiles/b.json deleted file mode 100644 index 90764025208..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChangeFiles/b.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "b", - "type": "patch", - "comment": "Patch change to b" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/multipleChangeFiles/c.json b/apps/rush-lib/src/logic/test/multipleChangeFiles/c.json deleted file mode 100644 index efd06816e7c..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChangeFiles/c.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "c", - "type": "patch", - "comment": "Patch change to c" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/multipleChanges/change1.json b/apps/rush-lib/src/logic/test/multipleChanges/change1.json deleted file mode 100644 index 5e78e627b42..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChanges/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patch change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/multipleChanges/change2.json b/apps/rush-lib/src/logic/test/multipleChanges/change2.json deleted file mode 100644 index a16b064ca9a..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChanges/change2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "minor", - "comment": "Minor change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/multipleChanges/change3.json b/apps/rush-lib/src/logic/test/multipleChanges/change3.json deleted file mode 100644 index f767def9023..00000000000 --- a/apps/rush-lib/src/logic/test/multipleChanges/change3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "major", - "comment": "Major change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change1.json b/apps/rush-lib/src/logic/test/multipleHotfixChanges/change1.json deleted file mode 100644 index 51599cdb92c..00000000000 --- a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "hotfix", - "comment": "Hotfix change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change2.json b/apps/rush-lib/src/logic/test/multipleHotfixChanges/change2.json deleted file mode 100644 index 857ec56ac76..00000000000 --- a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "b", - "type": "hotfix", - "comment": "Hotfix change to b" - }] -} diff --git a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change3.json b/apps/rush-lib/src/logic/test/multipleHotfixChanges/change3.json deleted file mode 100644 index 51599cdb92c..00000000000 --- a/apps/rush-lib/src/logic/test/multipleHotfixChanges/change3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "hotfix", - "comment": "Hotfix change to a" - }] -} diff --git a/apps/rush-lib/src/logic/test/orderedChanges/change1.json b/apps/rush-lib/src/logic/test/orderedChanges/change1.json deleted file mode 100644 index 6b8fdb90757..00000000000 --- a/apps/rush-lib/src/logic/test/orderedChanges/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "major", - "comment": "Patch change to a" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/orderedChanges/change2.json b/apps/rush-lib/src/logic/test/orderedChanges/change2.json deleted file mode 100644 index c91c5ceab65..00000000000 --- a/apps/rush-lib/src/logic/test/orderedChanges/change2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "none", - "comment": "None change to a" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/packages/rush.json b/apps/rush-lib/src/logic/test/packages/rush.json deleted file mode 100644 index 6b39c9d6742..00000000000 --- a/apps/rush-lib/src/logic/test/packages/rush.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "npmVersion": "3.10.8", - "rushVersion": "1.0.5", - "projectFolderMinDepth": 1, - "hotfixChangeEnabled": true, - "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] - }, - "projects": [ - { - "packageName": "a", - "projectFolder": "a", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "b", - "projectFolder": "b", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "c", - "projectFolder": "c", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "d", - "projectFolder": "d", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "cyclic-dep-1", - "projectFolder": "cyclic-dep-1", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "cyclic-dep-2", - "projectFolder": "cyclic-dep-2", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "cyclic-dep-explicit-1", - "projectFolder": "cyclic-dep-explicit-1", - "reviewCategory": "third-party", - "shouldPublish": true - }, - { - "packageName": "cyclic-dep-explicit-2", - "projectFolder": "cyclic-dep-explicit-2", - "reviewCategory": "third-party", - "shouldPublish": true, - "cyclicDependencyProjects": [ - "cyclic-dep-explicit-1" - ] - } - ] -} diff --git a/apps/rush-lib/src/logic/test/repo/changes/a.json b/apps/rush-lib/src/logic/test/repo/changes/a.json deleted file mode 100644 index a5c3e31e20c..00000000000 --- a/apps/rush-lib/src/logic/test/repo/changes/a.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patching a" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/changes/b.json b/apps/rush-lib/src/logic/test/repo/changes/b.json deleted file mode 100644 index 7376edbe1a2..00000000000 --- a/apps/rush-lib/src/logic/test/repo/changes/b.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "b", - "type": "patch", - "comment": "Patching b" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/changes/c.json b/apps/rush-lib/src/logic/test/repo/changes/c.json deleted file mode 100644 index 8c1bb8d1afc..00000000000 --- a/apps/rush-lib/src/logic/test/repo/changes/c.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "c", - "type": "patch", - "comment": "Patching c" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/changes/d.json b/apps/rush-lib/src/logic/test/repo/changes/d.json deleted file mode 100644 index 6e73cd4e32d..00000000000 --- a/apps/rush-lib/src/logic/test/repo/changes/d.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "d", - "type": "patch", - "comment": "Patching d" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json b/apps/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json deleted file mode 100644 index 389fb704679..00000000000 --- a/apps/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "policyName": "testPolicy1", - "definitionName": "lockStepVersion", - "version": "10.10.0", - "nextBump": "patch" - }, - { - "policyName": "testPolicy2", - "definitionName": "individualVersion", - "lockedMajor": 5 - }, - { - "policyName": "testPolicy3", - "definitionName": "individualVersion" - } -] \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/d/package.json b/apps/rush-lib/src/logic/test/repo/d/package.json deleted file mode 100644 index 5ff594492c4..00000000000 --- a/apps/rush-lib/src/logic/test/repo/d/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "d", - "version": "4.1.1", - "description": "Test package d", - "dependencies": { - "b": ">=2.0.0 <3.0.0" - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/e/package.json b/apps/rush-lib/src/logic/test/repo/e/package.json deleted file mode 100644 index a65f747ce6b..00000000000 --- a/apps/rush-lib/src/logic/test/repo/e/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "e", - "version": "10.10.0", - "description": "Test package e", - "dependencies": { - "c": "~3.1.1" - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/f/package.json b/apps/rush-lib/src/logic/test/repo/f/package.json deleted file mode 100644 index 68dea232055..00000000000 --- a/apps/rush-lib/src/logic/test/repo/f/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "f", - "version": "1.0.0", - "description": "Test package f", - "dependencies": { - "a": "~1.0.0" - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/g/package.json b/apps/rush-lib/src/logic/test/repo/g/package.json deleted file mode 100644 index 6feb6d79954..00000000000 --- a/apps/rush-lib/src/logic/test/repo/g/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "g", - "version": "0.0.1", - "description": "Test package g", - "devDependencies": { - "a": "~1.0.0" - } -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/repo/rush.json b/apps/rush-lib/src/logic/test/repo/rush.json deleted file mode 100644 index c5bc0d96fc2..00000000000 --- a/apps/rush-lib/src/logic/test/repo/rush.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "npmVersion": "3.10.8", - "rushVersion": "1.0.5", - - "projects": [ - { - "packageName": "a", - "projectFolder": "a", - "reviewCategory": "third-party", - "versionPolicyName": "testPolicy1" - }, - { - "packageName": "b", - "projectFolder": "b", - "reviewCategory": "third-party", - "versionPolicyName": "testPolicy1" - }, - { - "packageName": "c", - "projectFolder": "c", - "reviewCategory": "third-party", - "versionPolicyName": "testPolicy2" - }, - { - "packageName": "d", - "projectFolder": "d", - "reviewCategory": "third-party", - "versionPolicyName": "testPolicy3" - }, - { - "packageName": "e", - "projectFolder": "e", - "reviewCategory": "third-party", - "versionPolicyName": "testPolicy1" - }, - { - "packageName": "f", - "projectFolder": "f", - "reviewCategory": "third-party" - }, - { - "packageName": "g", - "projectFolder": "g", - "reviewCategory": "third-party" - } - ] -} diff --git a/apps/rush-lib/src/logic/test/rootHotfixChange/change1.json b/apps/rush-lib/src/logic/test/rootHotfixChange/change1.json deleted file mode 100644 index 36f551fc05a..00000000000 --- a/apps/rush-lib/src/logic/test/rootHotfixChange/change1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "hotfix", - "comment": "Hotfixing a" - }] -} - diff --git a/apps/rush-lib/src/logic/test/rootMajorChange/change1.json b/apps/rush-lib/src/logic/test/rootMajorChange/change1.json deleted file mode 100644 index 6224e378479..00000000000 --- a/apps/rush-lib/src/logic/test/rootMajorChange/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "major", - "comment": "Patching a" - }] -} diff --git a/apps/rush-lib/src/logic/test/rootPatchChange/change1.json b/apps/rush-lib/src/logic/test/rootPatchChange/change1.json deleted file mode 100644 index a1ef3ecbe91..00000000000 --- a/apps/rush-lib/src/logic/test/rootPatchChange/change1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patching a" - }] -} diff --git a/apps/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json b/apps/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json deleted file mode 100644 index d1c9ff8090a..00000000000 --- a/apps/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "example-file", - "version": "1.0.0", - "dependencies": { - "@rush-temp/project1": { - "version": "0.0.0", - "from": "projects\\project1", - "resolved": "file:projects\\project1" - }, - "@rush-temp/project2": { - "version": "0.0.0", - "from": "projects\\project2", - "resolved": "file:projects\\project2", - "dependencies": { - "fbjs": { - "version": "0.8.12", - "from": "fbjs@>=0.8.9 <0.9.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/fbjs/-/fbjs-0.8.12.tgz" - }, - "jquery": { - "version": "2.2.4", - "from": "jquery@>=2.2.4 <3.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/jquery/-/jquery-2.2.4.tgz" - }, - "object-assign": { - "version": "4.1.1", - "from": "object-assign@>=4.1.0 <5.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/object-assign/-/object-assign-4.1.1.tgz" - }, - "react": { - "version": "15.5.4", - "from": "react@>=15.5.4 <16.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/react/-/react-15.5.4.tgz" - } - } - }, - "prop-types": { - "version": "15.5.8", - "from": "prop-types@>=15.5.7 <16.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/prop-types/-/prop-types-15.5.8.tgz", - "dependencies": { - "fbjs": { - "version": "0.8.12", - "from": "fbjs@>=0.8.9 <0.9.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/fbjs/-/fbjs-0.8.12.tgz" - }, - "object-assign": { - "version": "4.1.1", - "from": "object-assign@>=4.1.0 <5.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/object-assign/-/object-assign-4.1.1.tgz" - } - } - }, - "q": { - "version": "1.5.0", - "from": "q@>=1.1.2 <2.0.0", - "resolved": "https://onedrive.pkgs.visualstudio.com/_packaging/odsp-npm/npm/registry/q/-/q-1.5.0.tgz" - } - } -} diff --git a/apps/rush-lib/src/logic/test/shrinkwrapFile/pnpm-lock.yaml b/apps/rush-lib/src/logic/test/shrinkwrapFile/pnpm-lock.yaml deleted file mode 100644 index 9feeff9f1b0..00000000000 --- a/apps/rush-lib/src/logic/test/shrinkwrapFile/pnpm-lock.yaml +++ /dev/null @@ -1,38 +0,0 @@ -dependencies: - '@rush-temp/project1': 'file:projects/project1.tgz' - '@rush-temp/project2': 'file:projects/project2.tgz' - '@rush-temp/project3': 'file:projects/project3.tgz_462eaf34881863298955eb323c130fc7' -packages: - /jquery/1.0.0: - resolution: - integrity: sha1-PjAtxh6zKaIenvrJN9cx8GETTFk= - /jquery/2.9.9: - resolution: - integrity: sha1-PjAtxh6zKaIenvrJN9cx8GETTFk= - /q/1.5.3: - resolution: - integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= - /left-pad/9.9.9: - resolution: - integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= - example.pkgs.visualstudio.com/@scope/testDep/1.0.0: - resolution: - integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= - 'file:projects/project1.tgz': - dependencies: - jquery: 2.9.9 - 'file:projects/project2.tgz': - dependencies: - q: 1.5.3 - jquery: 1.0.0 - 'file:projects/project3.tgz_462eaf34881863298955eb323c130fc7': - dependencies: - q: 1.5.3 - '@scope/testDep': example.pkgs.visualstudio.com/@scope/testDep/1.0.0 -registry: 'http://localhost:4873/' -lockfileVersion: 5 -specifiers: - '@rush-temp/project1': 'file:./projects/project1.tgz' - '@rush-temp/project2': 'file:./projects/project2.tgz' - '@rush-temp/project3': 'file:./projects/project3.tgz' - q: '~1.5.0' diff --git a/apps/rush-lib/src/logic/test/verifyChanges/changes.json b/apps/rush-lib/src/logic/test/verifyChanges/changes.json deleted file mode 100644 index 5ae66e6f832..00000000000 --- a/apps/rush-lib/src/logic/test/verifyChanges/changes.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "changes": [{ - "packageName": "a", - "type": "patch", - "comment": "Patching a" - }, - { - "packageName": "b", - "type": "patch", - "comment": "Patching b" - }] -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts b/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts deleted file mode 100644 index 8f28dc132b9..00000000000 --- a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts +++ /dev/null @@ -1,270 +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 colors from 'colors'; - -import { RushConfiguration } from '../../api/RushConfiguration'; -import { - PackageJsonDependency, - DependencyType -} from '../../api/PackageJsonEditor'; -import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; -import { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; -import { VersionMismatchFinderProject } from './VersionMismatchFinderProject'; -import { VersionMismatchFinderCommonVersions } from './VersionMismatchFinderCommonVersions'; -import { AlreadyReportedError } from '../../utilities/AlreadyReportedError'; - -export interface IVersionMismatchFinderRushCheckOptions { - variant?: string | undefined; - printAsJson?: boolean | undefined; -} - -export interface IVersionMismatchFinderEnsureConsistentVersionsOptions { - variant?: string | undefined; -} - -export interface IVersionMismatchFinderGetMismatchesOptions { - variant?: string | undefined; -} - -export interface IMismatchDependency { - dependencyName: string; - versions: IMismatchDependencyVersion[]; -} - -export interface IMismatchDependencyVersion { - version: string, - projects: string[]; -} - -export interface IMismatchDependencies { - mismatchedVersions: IMismatchDependency[]; -} - -export class VersionMismatchFinder { - /* store it like this: - * { - * "@types/node": { - * "1.0.0": [ '@ms/rush' ] - * } - * } - */ - private _allowedAlternativeVersion: Map>; - private _mismatches: Map>; - private _projects: VersionMismatchFinderEntity[]; - - public constructor( - projects: VersionMismatchFinderEntity[], - allowedAlternativeVersions?: Map> - ) { - this._projects = projects; - this._mismatches = new Map>(); - this._allowedAlternativeVersion = allowedAlternativeVersions || new Map>(); - this._analyze(); - } - - public static rushCheck( - rushConfiguration: RushConfiguration, - options: IVersionMismatchFinderRushCheckOptions = {} - ): void { - VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { - ...options, - isRushCheckCommand: true - }); - } - - public static ensureConsistentVersions( - rushConfiguration: RushConfiguration, - options: IVersionMismatchFinderEnsureConsistentVersionsOptions = {} - ): void { - VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { - ...options, - isRushCheckCommand: false - }); - } - - /** - * Populates a version mismatch finder object given a Rush Configuration. - * Intentionally considers preferred versions. - */ - public static getMismatches( - rushConfiguration: RushConfiguration, - options: IVersionMismatchFinderRushCheckOptions = {} - ): VersionMismatchFinder { - const commonVersions: CommonVersionsConfiguration = rushConfiguration.getCommonVersions(options.variant); - - const projects: VersionMismatchFinderEntity[] = rushConfiguration.projects.map((project) => { - return new VersionMismatchFinderProject(project); - }); - - // Create an object for the purposes of reporting conflicts with preferredVersions - // or xstitchPreferredVersions from common-versions.json - projects.push(new VersionMismatchFinderCommonVersions(commonVersions)); - - return new VersionMismatchFinder( - projects, - commonVersions.allowedAlternativeVersions - ); - } - - private static _checkForInconsistentVersions( - rushConfiguration: RushConfiguration, - options: { - isRushCheckCommand: boolean; - variant?: string | undefined; - printAsJson?: boolean | undefined; - } - ): void { - if (rushConfiguration.ensureConsistentVersions || options.isRushCheckCommand) { - const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches(rushConfiguration, options); - - if (options.printAsJson) { - mismatchFinder.printAsJson(); - } else { - mismatchFinder.print(); - - if (mismatchFinder.numberOfMismatches > 0) { - console.log(colors.red(`Found ${mismatchFinder.numberOfMismatches} mis-matching dependencies!`)); - throw new AlreadyReportedError(); - } else { - if (options.isRushCheckCommand) { - console.log(colors.green(`Found no mis-matching dependencies!`)); - } - } - } - } - } - - public get numberOfMismatches(): number { - return this._mismatches.size; - } - - public getMismatches(): string[] { - return this._getKeys(this._mismatches); - } - - public getVersionsOfMismatch(mismatch: string): string[] | undefined { - return this._mismatches.has(mismatch) - ? this._getKeys(this._mismatches.get(mismatch)) - : undefined; - } - - public getConsumersOfMismatch(mismatch: string, version: string): VersionMismatchFinderEntity[] | undefined { - const mismatchedPackage: Map | undefined = this._mismatches.get(mismatch); - if (!mismatchedPackage) { - return undefined; - } - - const mismatchedVersion: VersionMismatchFinderEntity[] | undefined = mismatchedPackage.get(version); - return mismatchedVersion; - } - - public printAsJson(): void { - const mismatchDependencies: IMismatchDependency[] = []; - - this.getMismatches().forEach((dependency: string) => { - const mismatchDependencyVersionArray: IMismatchDependencyVersion[] = []; - this.getVersionsOfMismatch(dependency)!.forEach((version: string) => { - const projects: string[] = [] - this.getConsumersOfMismatch(dependency, version)!.forEach((project: VersionMismatchFinderEntity) => { - projects.push(project.friendlyName); - }); - const mismatchDependencyVersion: IMismatchDependencyVersion = { - version: version, - projects: projects - }; - mismatchDependencyVersionArray.push(mismatchDependencyVersion); - }); - const mismatchDepency: IMismatchDependency = { - dependencyName: dependency, - versions: mismatchDependencyVersionArray - }; - mismatchDependencies.push(mismatchDepency); - }); - - const output: IMismatchDependencies = { - mismatchedVersions: mismatchDependencies - }; - - console.log(JSON.stringify(output, undefined, 2)); - } - - public print(): void { - // Iterate over the list. For any dependency with mismatching versions, print the projects - this.getMismatches().forEach((dependency: string) => { - console.log(colors.yellow(dependency)); - this.getVersionsOfMismatch(dependency)!.forEach((version: string) => { - console.log(` ${version}`); - this.getConsumersOfMismatch(dependency, version)!.forEach((project: VersionMismatchFinderEntity) => { - console.log(` - ${project.friendlyName}`); - }); - }); - console.log(); - }); - } - - private _analyze(): void { - this._projects.forEach((project: VersionMismatchFinderEntity) => { - if (!project.skipRushCheck) { - // NOTE: We do not consider peer dependencies here. The purpose of "rush check" is - // mainly to avoid side-by-side duplicates in the node_modules folder, whereas - // peer dependencies are just a compatibility statement that will be satisfied by a - // regular dependency. (It might be useful for Rush to help people keep their peer dependency - // patterns consistent, but on the other hand different projects may have different - // levels of compatibility -- we should wait for someone to actually request this feature - // before we get into that.) - project.allDependencies.forEach((dependency: PackageJsonDependency) => { - if (dependency.dependencyType !== DependencyType.Peer) { - const version: string = dependency.version!; - - const isCyclic: boolean = project.cyclicDependencyProjects.has(dependency.name); - - if (this._isVersionAllowedAlternative(dependency.name, version)) { - return; - } - - const name: string = dependency.name + (isCyclic ? ' (cyclic)' : ''); - - if (!this._mismatches.has(name)) { - this._mismatches.set(name, new Map()); - } - - const dependencyVersions: Map = this._mismatches.get(name)!; - - if (!dependencyVersions.has(version)) { - dependencyVersions.set(version, []); - } - - dependencyVersions.get(version)!.push(project); - } - }); - } - }); - - this._mismatches.forEach((mismatches: Map, project: string) => { - if (mismatches.size <= 1) { - this._mismatches.delete(project); - } - }); - } - - private _isVersionAllowedAlternative( - dependency: string, - version: string): boolean { - - const allowedAlternatives: ReadonlyArray | undefined = this._allowedAlternativeVersion.get(dependency); - return Boolean(allowedAlternatives && allowedAlternatives.indexOf(version) > -1); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private _getKeys(iterable: Map | undefined): string[] { - const keys: string[] = []; - if (iterable) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - iterable.forEach((value: any, key: string) => { - keys.push(key); - }); - } - return keys; - } -} diff --git a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts b/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts deleted file mode 100644 index 7b10253147e..00000000000 --- a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { RushConstants } from '../RushConstants'; -import { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; -import { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; -import { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; - -export class VersionMismatchFinderCommonVersions extends VersionMismatchFinderEntity { - private _fileManager: CommonVersionsConfiguration; - - public constructor(commonVersionsConfiguration: CommonVersionsConfiguration) { - super({ - friendlyName: `preferred versions from ${RushConstants.commonVersionsFilename}`, - cyclicDependencyProjects: new Set() - }); - - this._fileManager = commonVersionsConfiguration; - } - - public get filePath(): string { - return this._fileManager.filePath; - } - - public get allDependencies(): ReadonlyArray { - const dependencies: PackageJsonDependency[] = []; - - this._fileManager.getAllPreferredVersions().forEach((version, dependencyName) => { - dependencies.push(this._getPackageJsonDependency(dependencyName, version)); - }); - - return dependencies; - } - - public tryGetDependency(packageName: string): PackageJsonDependency | undefined { - const version: string | undefined = this._fileManager.getAllPreferredVersions().get(packageName); - if (!version) { - return undefined; - } else { - return this._getPackageJsonDependency(packageName, version); - } - } - - public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { - return undefined; // common-versions.json doesn't have a distinction between dev and non-dev dependencies - } - - public addOrUpdateDependency(packageName: string, newVersion: string, dependencyType: DependencyType): void { - if (dependencyType !== DependencyType.Regular) { - throw new Error(`${RushConstants.commonVersionsFilename} only accepts "${DependencyType.Regular}" dependencies`); - } - - if (this._fileManager.xstitchPreferredVersions.has(packageName)) { - this._fileManager.xstitchPreferredVersions.set(packageName, newVersion); - } else { - this._fileManager.preferredVersions.set(packageName, newVersion); - } - } - - public saveIfModified(): boolean { - return this._fileManager.save(); - } - - private _getPackageJsonDependency(dependencyName: string, version: string): PackageJsonDependency { - return new PackageJsonDependency( - dependencyName, - version, - DependencyType.Regular, - () => this.addOrUpdateDependency(dependencyName, version, DependencyType.Regular) - ); - } -} diff --git a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts b/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts deleted file mode 100644 index 1056ed8a4c6..00000000000 --- a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - PackageJsonDependency, - DependencyType -} from '../../api/PackageJsonEditor'; - -export interface IVersionMismatchFinderEntityOptions { - friendlyName: string; - cyclicDependencyProjects: Set; - skipRushCheck?: boolean; -} - -export abstract class VersionMismatchFinderEntity { - public readonly friendlyName: string; - public readonly cyclicDependencyProjects: Set; - public readonly skipRushCheck: boolean | undefined; - - public constructor(options: IVersionMismatchFinderEntityOptions) { - this.friendlyName = options.friendlyName; - this.cyclicDependencyProjects = options.cyclicDependencyProjects; - this.skipRushCheck = options.skipRushCheck; - } - - public abstract filePath: string; - public abstract allDependencies: ReadonlyArray; - - public abstract tryGetDependency(packageName: string): PackageJsonDependency | undefined; - public abstract tryGetDevDependency(packageName: string): PackageJsonDependency | undefined; - public abstract addOrUpdateDependency(packageName: string, newVersion: string, dependencyType: DependencyType): void; - public abstract saveIfModified(): boolean; -} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts b/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts deleted file mode 100644 index a483b427b2d..00000000000 --- a/apps/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.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 { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; -import { - PackageJsonEditor, - PackageJsonDependency, - DependencyType -} from '../../api/PackageJsonEditor'; -import { RushConfigurationProject } from '../../api/RushConfigurationProject'; - -export class VersionMismatchFinderProject extends VersionMismatchFinderEntity { - public packageName: string; - private _fileManager: PackageJsonEditor; - - public constructor(project: RushConfigurationProject) { - super({ - friendlyName: project.packageName, - cyclicDependencyProjects: project.cyclicDependencyProjects, - skipRushCheck: project.skipRushCheck - }); - - this._fileManager = project.packageJsonEditor; - this.packageName = project.packageName; - } - - public get filePath(): string { - return this._fileManager.filePath; - } - - public get allDependencies(): ReadonlyArray { - return [...this._fileManager.dependencyList, ...this._fileManager.devDependencyList]; - } - - public tryGetDependency(packageName: string): PackageJsonDependency | undefined { - return this._fileManager.tryGetDependency(packageName); - } - - public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { - return this._fileManager.tryGetDevDependency(packageName); - } - - public addOrUpdateDependency(packageName: string, newVersion: string, dependencyType: DependencyType): void { - return this._fileManager.addOrUpdateDependency(packageName, newVersion, dependencyType); - } - - public saveIfModified(): boolean { - return this._fileManager.saveIfModified(); - } -} diff --git a/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts b/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts deleted file mode 100644 index 706787cea1a..00000000000 --- a/apps/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts +++ /dev/null @@ -1,232 +0,0 @@ -import * as os from 'os'; -import * as lockfile from '@yarnpkg/lockfile'; -import { - BaseShrinkwrapFile -} from '../base/BaseShrinkwrapFile'; -import { FileSystem, PackageName, IParsedPackageNameOrError, InternalError } from '@rushstack/node-core-library'; -import { RushConstants } from '../RushConstants'; -import { DependencySpecifier } from '../DependencySpecifier'; - -/** - * Used with YarnShrinkwrapFile._encodePackageNameAndSemVer() and _decodePackageNameAndSemVer(). - */ -interface IPackageNameAndSemVer { - packageName: string; - semVerRange: string; -} - -/** - * Part of IYarnShrinkwrapJson - */ -interface IYarnShrinkwrapEntry { - /** - * The specific version that was chosen for this entry (i.e. package name and SemVer range)/ - * - */ - version: string; - - /** - * The source (e.g. registry tarball URL) of the package that was installed - * with the integrity hash as a suffix. - * - * Examples: - * https://registry.yarnpkg.com/@pnpm/types/-/types-1.7.0.tgz#9d66a8bed3fabcd80f288b3e7884b7418b05b5a9 - * file:./projects/api-documenter.tgz#d95f9779aa45df3ef1bbd95dec324793540765ba - */ - resolved: string; - - /** - * Records the original (unsolved) "dependencies" from the package.json. - */ - dependencies?: { [dependency: string]: string }; - - /** - * Records the original (unsolved) "optionalDependencies" from the package.json. - * - * NOTE: Interestingly "peerDependencies" are apparently not tracked by the shrinkwrap file. - * The "devDependencies" are not tracked either, because they are always indirect dependencies - * for the installation. - */ - optionalDependencies?: { [dependency: string]: string }; -} - -/** - * Used by YarnShrinkwrapFile to interpret the `@yarnpkg/lockfile` data structure. - */ -interface IYarnShrinkwrapJson { - /** - * Example keys: - * `js-tokens@^3.0.0 || ^4.0.0` - * `@rush-temp/api-extractor-test-03@file:./projects/api-extractor-test-03.tgz` - * - * The value records how the SemVer range was solved. - */ - [packageNameAndSemVer: string]: IYarnShrinkwrapEntry; -} - -/** - * Support for consuming the "yarn.lock" file. - * - * Yarn refers to its shrinkwrap file as a "lock file", even though it has nothing to do - * with file locking. Apparently this was based on a convention of the Ruby bundler. - * Since Rush has to work interchangeably with 3 different package managers, here we refer - * generically to yarn.lock as a "shrinkwrap file". - * - * If Rush's Yarn support gains popularity, we will try to improve the wording of - * logging messages to use terminology more consistent with Yarn's own documentation. - */ -export class YarnShrinkwrapFile extends BaseShrinkwrapFile { - // 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[]; - - private constructor(shrinkwrapJson: IYarnShrinkwrapJson) { - super(); - this._shrinkwrapJson = shrinkwrapJson; - this._tempProjectNames = []; - - const seenEntries: Set = new Set(); - - for (const key of Object.keys(this._shrinkwrapJson)) { - // Example key: - const packageNameAndSemVer: IPackageNameAndSemVer = YarnShrinkwrapFile._decodePackageNameAndSemVer(key); - - // If it starts with @rush-temp, then include it: - if (PackageName.getScope(packageNameAndSemVer.packageName) === RushConstants.rushTempNpmScope) { - if (!/^file:/i.test(packageNameAndSemVer.semVerRange)) { - // Sanity check to make sure this is a real package. - // (Nobody should ever have an actual dependency on an "@rush-temp/" package. - throw new Error('Unexpected package/semver expression found in the Yarn shrinkwrap file (yarn.lock): ' - + JSON.stringify(key)); - } - - if (!seenEntries.add(packageNameAndSemVer.packageName)) { - // Sanity check -- this should never happen - throw new Error('Duplicate @rush-temp package found in the Yarn shrinkwrap file (yarn.lock): ' - + JSON.stringify(key)); - } - - this._tempProjectNames.push(packageNameAndSemVer.packageName); - - const entry: IYarnShrinkwrapEntry = this._shrinkwrapJson[key]; - - // Yarn fails installation if the integrity hash does not match a "file://" reference to a tarball. - // This is incorrect: Normally a mismatched integrity hash does indicate a corrupted download, - // since an NPM registry normally guarantees that a specific version number cannot be republished - // with different content. But this is NOT true for a "file://" reference, and there are valid - // reasons why someone would update the file. (PNPM handles this correctly, by simply reinstalling - // the tarball if its hash has changed.) - // - // As a workaround, we can simply remove the hashes from the shrinkwrap file. We will convert this: - // "file:./projects/my-project.tgz#80cefe05fd715e65219d1ed481209dc4023408aa" - // ..to this: - // "file:./projects/my-project.tgz" - const indexOfHash: number = entry.resolved.indexOf('#'); - if (indexOfHash >= 0) { - entry.resolved = entry.resolved.substring(0, indexOfHash); - } - } - } - - this._tempProjectNames.sort(); // make the result deterministic - } - - public static loadFromFile(shrinkwrapFilename: string): YarnShrinkwrapFile | undefined { - let shrinkwrapString: string; - let shrinkwrapJson: lockfile.ParseResult; - try { - if (!FileSystem.exists(shrinkwrapFilename)) { - return undefined; // file does not exist - } - - shrinkwrapString = FileSystem.readFile(shrinkwrapFilename); - shrinkwrapJson = lockfile.parse(shrinkwrapString); - } catch (error) { - throw new Error(`Error reading "${shrinkwrapFilename}":` + os.EOL + ` ${error.message}`); - } - - return new YarnShrinkwrapFile(shrinkwrapJson.object as IYarnShrinkwrapJson); - } - - /** - * 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 = PackageName.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 { - return this._tempProjectNames; - } - - /** @override */ - public 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({ - packageName: dependencySpecifier.packageName, - semVerRange: dependencySpecifier.versionSpecifier - }); - - // Check whether this exact key appears in the shrinkwrap file - return Object.hasOwnProperty.call(this._shrinkwrapJson, key); - } - - /** @override */ - public tryEnsureCompatibleDependency(dependencySpecifier: DependencySpecifier, tempProjectName: string): boolean { - return this.hasCompatibleTopLevelDependency(dependencySpecifier); - } - - /** @override */ - protected serialize(): string { - return lockfile.stringify(this._shrinkwrapJson); - } - - /** @override */ - protected getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { - throw new InternalError('Not implemented'); - } - - /** @override */ - protected tryEnsureDependencyVersion(dependencySpecifier: DependencySpecifier, - tempProjectName: string): DependencySpecifier | undefined { - - throw new InternalError('Not implemented'); - } -} diff --git a/apps/rush-lib/src/schemas/command-line.schema.json b/apps/rush-lib/src/schemas/command-line.schema.json deleted file mode 100644 index 496b3b54657..00000000000 --- a/apps/rush-lib/src/schemas/command-line.schema.json +++ /dev/null @@ -1,359 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush command-line.json config file", - "description": "For use with the Rush tool, this file defines custom command line commands. See http://rushjs.io for details.", - - "definitions": { - "anything": { - "type": [ - "array", - "boolean", - "integer", - "number", - "object", - "string" - ], - "items": { "$ref": "#/definitions/anything" } - }, - - "baseCommand": { - "type": "object", - "additionalProperties": true, - "required": [ "commandKind", "name", "summary" ], - "properties": { - "commandKind": { - "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" ] - }, - "name": { - "title": "Custom Command Name", - "description": "The name of the custom command, which can be invoked via \"rush \"", - "type": "string" - }, - "summary": { - "title": "Custom Command Summary", - "description": "A short summary of the custom command, which will appear when printing command line usage (e.g. \"rush --help\")", - "type": "string" - }, - "description": { - "title": "Custom Command Description", - "description": "A detailed description of the command, which appears when requesting help for the command (e.g. \"rush --help my-command\"). If omitted, the summary will be used.", - "type": "string" - }, - "safeForSimultaneousRushProcesses": { - "title": "Safe For Simultaneous Rush Processes", - "description": "By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously in the same repo folder. (For example, it would be a mistake to run \"rush install\" and \"rush build\" at the same time.) If your command makes sense to run concurrently with other operations, set safeForSimultaneousRushProcesses=true to disable this protection. In particular, this is needed for custom scripts that invoke other Rush commands.", - "type": "boolean" - } - } - }, - "bulkCommand": { - "title": "Bulk Command", - "description": "A custom command that is run separately for each project in the repository", - "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseCommand" }, - { - "type": "object", - "additionalProperties": true, - "required": [ "enableParallelism" ], - "properties": { - "commandKind": { - "enum": [ "bulk" ] - }, - "enableParallelism": { - "title": "enableParallelism", - "description": "If true then this command can be run in parallel, i.e. executed simultaneously for multiple projects.", - "type": "boolean" - }, - "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.", - "type": "boolean" - }, - "ignoreMissingScript": { - "title": "Ignore Missing Script", - "description": "Normally Rush requires that each project's package.json has a \"scripts\" entry matching the custom command name. To disable this check, set \"ignoreMissingScript\" to true.", - "type": "boolean" - }, - "incremental": { - "title": "Incremental", - "description": "If true then this command will be incremental like the built-in \"build\" and \"rebuild\" commands", - "type": "boolean" - }, - "allowWarningsInSuccessfulBuild": { - "title": "Allow Warnings in Successful Build", - "description": "By default, Rush returns a nonzero exit code if errors or warnings occur during build. If this option is set to \"true\", Rush will return a zero exit code if warnings occur.", - "type": "boolean" - } - } - }, - { - "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" }, - "allowWarningsInSuccessfulBuild": { "$ref": "#/definitions/anything" }, - - "enableParallelism": { "$ref": "#/definitions/anything" }, - "ignoreDependencyOrder": { "$ref": "#/definitions/anything" }, - "ignoreMissingScript": { "$ref": "#/definitions/anything" }, - "incremental": { "$ref": "#/definitions/anything" } - } - } - ] - }, - "globalCommand": { - "title": "Global Command", - "description": "A custom command that is run once for the entire repository", - "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseCommand" }, - { - "type": "object", - "additionalProperties": true, - "required": [ "shellCommand" ], - "properties": { - "commandKind": { - "enum": [ "global" ] - }, - "shellCommand": { - "title": "Shell Command", - "description": "A command that that will be invoked using the OS shell. The working directory will be the folder that contains rush.json. Additional command-line parameters may be appended to the end of this string.", - "type": "string" - } - } - }, - { - "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" }, - "allowWarningsInSuccessfulBuild": { "$ref": "#/definitions/anything" }, - - "shellCommand": { "$ref": "#/definitions/anything" } - } - } - ] - }, - - "baseParameter": { - "type": "object", - "additionalProperties": true, - "required": [ "parameterKind", "longName", "description", "associatedCommands" ], - "properties": { - "parameterKind": { - "title": "Parameter Kind", - "description": "Indicates the kind of syntax for this command-line parameter: \"flag\" or \"choice\" or \"string\"", - "type": "string", - "enum": [ "flag", "choice", "string" ] - }, - "longName": { - "title": "Long Name", - "description": "The name of the parameter (e.g. \"--verbose\"). This is a required field.", - "type": "string", - "pattern": "^-(-[a-z0-9]+)+$" - }, - "shortName": { - "title": "Short Name", - "description": "A optional short form of the parameter (e.g. \"-v\" instead of \"--verbose\")", - "type": "string", - "pattern": "^-[a-zA-Z]$" - }, - "description": { - "title": "Custom Parameter Description", - "description": "A detailed description of the parameter, which appears when requesting help for the command (e.g. \"rush --help my-command\").", - "type": "string" - }, - "associatedCommands": { - "title": "Associated Commands", - "description": "A list of custom commands and/or built-in Rush commands that this parameter may be used with", - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - }, - "required": { - "title": "Required", - "description": "If true, then this parameter must be included on the command line", - "type": "boolean" - } - } - }, - "flagParameter": { - "title": "Flag Parameter", - "description": "A custom command-line parameter whose presence acts as an on/off switch", - "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "properties": { - "parameterKind": { - "enum": [ "flag" ] - } - } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "associatedCommands": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" } - } - } - ] - }, - "stringParameter": { - "title": "String Parameter", - "description": "A custom command-line parameter whose value is interpreted as a string", - "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": ["argumentName"], - "properties": { - "parameterKind": { - "enum": [ "string" ] - }, - "argumentName": { - "title": "Argument Name", - "description": "The name of the argument for this parameter.", - "type": "string" - } - } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "associatedCommands": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "argumentName": { "$ref": "#/definitions/anything" } - } - } - ] - }, - "choiceParameter": { - "title": "Choice Parameter", - "description": "A custom command-line parameter whose argument must be chosen from a list of allowable alternatives", - "type": "object", - "allOf": [ - { "$ref": "#/definitions/baseParameter" }, - { - "type": "object", - "additionalProperties": true, - "required": [ "alternatives" ], - "properties": { - "parameterKind": { - "enum": [ "choice" ] - }, - "alternatives": { - "title": "Alternatives", - "description": "A list of alternative argument values that can be chosen for this parameter.", - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "additionalProperties": false, - "required": [ "name", "description" ], - "properties": { - "name": { - "title": "Name of Alternative", - "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", - "type": "string" - }, - "description": { - "title": "Description of Alternative", - "description": "A detailed description for the alternative that will be shown in the command-line help.", - "type": "string" - } - } - } - }, - "defaultValue": { - "title": "Default Value", - "description": "If the parameter is omitted from the command line, this value will be inserted by default", - "type": "string" - } - } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "parameterKind": { "$ref": "#/definitions/anything" }, - "longName": { "$ref": "#/definitions/anything" }, - "shortName": { "$ref": "#/definitions/anything" }, - "description": { "$ref": "#/definitions/anything" }, - "associatedCommands": { "$ref": "#/definitions/anything" }, - "required": { "$ref": "#/definitions/anything" }, - - "alternatives": { "$ref": "#/definitions/anything" }, - "defaultValue": { "$ref": "#/definitions/anything" } - } - } - ] - } - }, - - "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" - }, - - "commands": { - "title": "Custom Commands", - "description": "A list of custom commands that affect all projects in the repository. These commands are invoked from the Rush command line.", - "type": "array", - "items": { - "type": "object", - "oneOf": [ - { "$ref": "#/definitions/bulkCommand" }, - { "$ref": "#/definitions/globalCommand" } - ] - } - }, - - "parameters": { - "title": "Custom Parameters", - "description": "A list of custom command-line parameters that can be associated with custom commands and Rush's built-in commands.", - "type": "array", - "items": { - "type": "object", - "oneOf": [ - { "$ref": "#/definitions/flagParameter" }, - { "$ref": "#/definitions/choiceParameter" }, - { "$ref": "#/definitions/stringParameter" } - ] - } - } - } -} diff --git a/apps/rush-lib/src/schemas/experiments.schema.json b/apps/rush-lib/src/schemas/experiments.schema.json deleted file mode 100644 index 1b7ed72ea21..00000000000 --- a/apps/rush-lib/src/schemas/experiments.schema.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush experiments.json config file", - "description": "For use with the Rush tool, this file allows repo maintainers to enable and disable experimental Rush features.", - - "type": "object", - "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" - }, - - "legacyIncrementalBuildDependencyDetection": { - "description": "Rush 5.14.0 improved incremental builds to ignore spurious changes in the pnpm-lock.json file. This optimization is enabled by default. If you encounter a problem where \"rush build\" is neglecting to build some projects, please open a GitHub issue. As a workaround you can uncomment this line to temporarily restore the old behavior where everything must be rebuilt whenever pnpm-lock.json is modified.", - "type": "boolean" - } - }, - "additionalProperties": false -} diff --git a/apps/rush-lib/src/schemas/rush.schema.json b/apps/rush-lib/src/schemas/rush.schema.json deleted file mode 100644 index 923467a637f..00000000000 --- a/apps/rush-lib/src/schemas/rush.schema.json +++ /dev/null @@ -1,307 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush main config File", - "description": "The main configuration file for the Rush multi-project build tool. See http://rushjs.io for details.", - "type": "object", - - "definitions": { - "environmentVariables": { - "description": "Enviroment variables for the package manager", - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "override": { - "type": "boolean" - } - }, - "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" - }, - - "npmVersion": { - "description": "If specified, selects NPM as the package manager and specifies the deterministic version to be installed by Rush.", - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" - }, - - "pnpmVersion": { - "description": "If specified, selects PNPM as the package manager and specifies the deterministic version to be installed by Rush.", - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" - }, - - "yarnVersion": { - "description": "If specified, selects Yarn as the package manager and specifies the deterministic version to be installed by Rush.", - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" - }, - - "rushVersion": { - "description": "The version of the Rush tool that will be used to build this repository.", - "type": "string", - "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" - }, - "nodeSupportedVersionRange": { - "description": "A node-semver expression (e.g. \">=1.2.3 <2.0.0\", see https://github.com/npm/node-semver) indicating which versions of Node.js can safely be used to build this repository. If omitted, no validation is performed.", - "type": "string" - }, - "suppressNodeLtsWarning": { - "description": "Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing pre-LTS versions in preparation for supporting the first LTS version, you can use this setting to disable Rush's warning.", - "type": "boolean" - }, - "projectFolderMinDepth": { - "description": "The minimum folder depth for the projectFolder field. The default value is 1, i.e. no slashes in the path name.", - "type": "number" - }, - "ensureConsistentVersions": { - "description": "If true, consistent version specifiers for dependencies will be enforced (i.e. \"rush check\" is run before some commands).", - "type": "boolean" - }, - "hotfixChangeEnabled": { - "description": "Allows creation of hotfix changes. This feature is experimental so it is disabled by default. If this is set, \"rush change\" only allows a \"hotfix\" change type to be specified. This change type will be used when publishing subsequent changes from the monorepo.", - "type": "boolean" - }, - "npmOptions": { - "description": "Options that are only used when the NPM pacakge manager is selected.", - "type": "object", - "properties": { - "environmentVariables": { - "$ref": "#/definitions/environmentVariables" - } - }, - "additionalProperties": false - }, - "pnpmOptions": { - "description": "Options that are only used when the PNPM pacakge manager is selected.", - "type": "object", - "properties": { - "pnpmStore": { - "description": "Specifies the location of the PNPM store. There are two possible values:\n\n\"local\" - use the \"pnpm-store\" folder in the current configured temp folder: \"common/temp/pnpm-store\" by default.\n\"global\" - use PNPM's global store, which has the benefit of being shared across multiple repo folders, but the disadvantage of less isolation for builds (e.g. bugs or incompatibilities when two repos use different releases of PNPM)\n\nIn all cases, the store path will be overridden by the environment variable RUSH_PNPM_STORE_PATH.\n\nThe default value is \"local\".", - "type": "string", - "enum": [ - "local", - "global" - ] - }, - "strictPeerDependencies": { - "description": "If true, then Rush will add the \"--strict-peer-dependencies\" option when invoking PNPM. This causes \"rush install\" to fail if there are unsatisfied peer dependencies, which is an invalid state that can cause build failures or incompatible dependency versions. (For historical reasons, JavaScript package managers generally do not treat this invalid state as an error.) The default value is false.", - "type": "boolean" - }, - "resolutionStrategy": { - "description": "Configures the strategy used to select versions during installation. This feature requires PNPM version 3.1 or newer. It corresponds to the \"--resolution-strategy\" command-line option for PNPM. Possible values are \"fast\" and \"fewer-dependencies\". PNPM's default is \"fast\", but this may be incompatible with certain packages, for example the \"@types\" packages from DefinitelyTyped. Rush's default is \"fewer-dependencies\", which causes PNPM to avoid installing a newer version if an already installed version can be reused; this is more similar to NPM's algorithm.", - "type": "string", - "enum": [ - "fewer-dependencies", - "fast" - ] - }, - "environmentVariables": { - "$ref": "#/definitions/environmentVariables" - } - }, - "additionalProperties": false - }, - "yarnOptions": { - "description": "Options that are only used when the Yarn pacakge manager is selected.", - "type": "object", - "properties": { - "ignoreEngines": { - "description": "If true, then Rush will add the \"--ignore-engines\" option when invoking Yarn. * This allows \"rush install\" to succeed if there are dependencies with engines defined in package.json which do not match the current environment. The default value is false.", - "type": "boolean" - }, - "environmentVariables": { - "$ref": "#/definitions/environmentVariables" - } - }, - "additionalProperties": false - }, - "projectFolderMaxDepth": { - "description": "The maximum folder depth for the projectFolder field. The default value is 2, i.e. a single slash in the path name.", - "type": "number" - }, - "approvedPackagesPolicy": { - "description": "Controls a package review workflow driven by the two config files \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\"", - "type": "object", - "properties": { - "reviewCategories": { - "description": "A list of category names that can be applied to each project, and then referenced in \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\"", - "type": "array", - "items": { - "type": "string" - } - }, - "ignoredNpmScopes": { - "description": "A list of NPM package scopes that will be excluded from review (e.g. \"@types\")", - "type": "array", - "items": { - "type": "string", - "pattern": "^@" - } - } - }, - "additionalProperties": false - }, - "gitPolicy": { - "description": "If the project is stored in a Git repository, additional settings related to Git", - "type": "object", - "properties": { - "allowedEmailRegExps": { - "description": "A list of regular expressions describing allowable e-mail patterns for Git commits. They are case-insensitive anchored JavaScript RegExps. Example: \".*@example\\.com\"", - "type": "array", - "items": { - "type": "string" - } - }, - "sampleEmail": { - "description": "An example valid e-mail address for \"Mr. Example\" that conforms to one of the allowedEmailRegExps. Example: \"mr-example@contoso\\.com\"", - "type": "string" - }, - "versionBumpCommitMessage": { - "description": "The commit message to use when committing changes during \"rush publish\". Defaults to \"Applying package updates.\"", - "type": "string" - } - }, - "additionalProperties": false - }, - "variants": { - "description": "Defines the list of installation variants for this repository. For more details about this feature, see this article: https://rushjs.io/pages/advanced/installation_variants/", - "type": "array", - "items": { - "type": "object", - "properties": { - "variantName": { - "description": "The name of the variant. Maps to common/rush/variants/{name} under the repository root.", - "type": "string" - }, - "description": { - "description": "", - "type": "string" - } - }, - "required": [ - "variantName", - "description" - ] - } - }, - "repository": { - "description": "The repository location", - "type": "object", - "properties": { - "url": { - "description": "The remote url of the repository. If a value is provided, \"rush change\" will use it to find the right remote to compare against.", - "type": "string" - }, - "defaultBranch": { - "description": "The default branch name. This tells \"rush change\" which remote branch to compare against. The default value is \"master\"", - "type": "string" - }, - "defaultRemote": { - "description": "The default remote. This tells \"rush change\" which remote to compare against if the remote URL is not set or if a remote matching the provided remote URL is not found.", - "type": "string" - } - }, - "additionalProperties": false - }, - "telemetryEnabled": { - "description": "Indicates whether telemetry data should be collected and stored in the Rush temp folder during Rush runs.", - "type": "boolean" - }, - "projects": { - "description": "A list of projects managed by this tool.", - "type": "array", - "items": { - "type": "object", - "properties": { - "packageName": { - "description": "The NPM package name of the project.", - "type": "string" - }, - "projectFolder": { - "description": "The path to the project folder relative to the Rush config file.", - "type": "string" - }, - "reviewCategory": { - "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", - "type": "string" - }, - "cyclicDependencyProjects": { - "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", - "type": "array", - "items": { - "type": "string" - } - }, - "shouldPublish": { - "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", - "type": "boolean" - }, - "skipRushCheck": { - "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", - "type": "boolean" - }, - "versionPolicyName": { - "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "packageName", - "projectFolder" - ] - } - }, - "eventHooks": { - "description": "Hooks are customized script actions that Rush executes when specific events occur.", - "type": "object", - "properties": { - "preRushInstall": { - "description": "The list of scripts to run before the Rush installation starts.", - "type": "array", - "items": { - "type": "string" - } - }, - "postRushInstall": { - "description": "The list of scripts to run after the Rush installation finishes.", - "type": "array", - "items": { - "type": "string" - } - }, - "preRushBuild": { - "description": "The list of scripts to run before the Rush build command starts.", - "type": "array", - "items": { - "type": "string" - } - }, - "postRushBuild": { - "description": "The list of scripts to run after the Rush build command finishes.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false, - "required": [ - "rushVersion", - "projects" - ] -} diff --git a/apps/rush-lib/src/scripts/install-run-rush.ts b/apps/rush-lib/src/scripts/install-run-rush.ts deleted file mode 100644 index 643f408cfdd..00000000000 --- a/apps/rush-lib/src/scripts/install-run-rush.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. - -// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. -// -// This script is intended for usage in an automated build environment where the Rush command may not have -// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush -// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it. -// An example usage would be: -// -// node common/scripts/install-run-rush.js install -// -// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ - -import * as path from 'path'; -import * as fs from 'fs'; - -import { - installAndRun, - findRushJsonFolder, - RUSH_JSON_FILENAME, - runWithErrorAndStatusCode -} from './install-run'; - -const PACKAGE_NAME: string = '@microsoft/rush'; -const RUSH_PREVIEW_VERSION: string = 'RUSH_PREVIEW_VERSION'; - -function _getRushVersion(): string { - const rushPreviewVersion: string | undefined = process.env[RUSH_PREVIEW_VERSION]; - if (rushPreviewVersion !== undefined) { - console.log(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); - return rushPreviewVersion; - } - - const rushJsonFolder: string = findRushJsonFolder(); - const rushJsonPath: string = path.join(rushJsonFolder, RUSH_JSON_FILENAME); - try { - const rushJsonContents: string = fs.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: string[] = 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 (${rushJsonFolder}). ` + - 'The \'rushVersion\' field is either not assigned in rush.json or was specified ' + - 'using an unexpected syntax.' - ); - } -} - -function _run(): void { - const [ - nodePath, /* Ex: /bin/node */ - scriptPath, /* /repo/common/scripts/install-run-rush.js */ - ...packageBinArgs /* [build, --to, myproject] */ - ]: string[] = 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: string = path.basename(scriptPath); - const bin: string = scriptName.toLowerCase() === 'install-run-rushx.js' ? 'rushx' : 'rush'; - if (!nodePath || !scriptPath) { - throw new Error('Unexpected exception: could not detect node path or script path'); - } - - if (process.argv.length < 3) { - console.log(`Usage: ${scriptName} [args...]`); - if (scriptName === 'install-run-rush.js') { - console.log(`Example: ${scriptName} build --to myproject`); - } else { - console.log(`Example: ${scriptName} custom-command`); - } - process.exit(1); - } - - runWithErrorAndStatusCode(() => { - const version: string = _getRushVersion(); - console.log(`The rush.json configuration requests Rush version ${version}`); - - return installAndRun(PACKAGE_NAME, version, bin, packageBinArgs); - }); -} - -_run(); diff --git a/apps/rush-lib/src/scripts/install-run-rushx.ts b/apps/rush-lib/src/scripts/install-run-rushx.ts deleted file mode 100644 index 0e7ec0a0bb5..00000000000 --- a/apps/rush-lib/src/scripts/install-run-rushx.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. - -// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. -// -// This script is intended for usage in an automated build environment where the Rush command may not have -// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush -// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the -// rushx command. -// -// An example usage would be: -// -// node common/scripts/install-run-rushx.js custom-command -// -// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ - -import './install-run-rush'; diff --git a/apps/rush-lib/src/scripts/install-run.ts b/apps/rush-lib/src/scripts/install-run.ts deleted file mode 100644 index 621dddab04c..00000000000 --- a/apps/rush-lib/src/scripts/install-run.ts +++ /dev/null @@ -1,507 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. - -// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. -// -// This script is intended for usage in an automated build environment where a Node tool may not have -// been preinstalled, or may have an unpredictable version. This script will automatically install the specified -// version of the specified tool (if not already installed), and then pass a command-line to it. -// An example usage would be: -// -// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io -// -// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ - -import * as childProcess from 'child_process'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import { IPackageJson } from '@rushstack/node-core-library'; - -export const RUSH_JSON_FILENAME: string = 'rush.json'; -const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME: string = 'RUSH_TEMP_FOLDER'; -const INSTALLED_FLAG_FILENAME: string = 'installed.flag'; -const NODE_MODULES_FOLDER_NAME: string = 'node_modules'; -const PACKAGE_JSON_FILENAME: string = 'package.json'; - -/** - * Parse a package specifier (in the form of name\@version) into name and version parts. - */ -function _parsePackageSpecifier(rawPackageSpecifier: string): IPackageSpecifier { - rawPackageSpecifier = (rawPackageSpecifier || '').trim(); - const separatorIndex: number = rawPackageSpecifier.lastIndexOf('@'); - - let name: string; - let version: string | undefined = undefined; - if (separatorIndex === 0) { - // The specifier starts with a scope and doesn't have a version specified - name = rawPackageSpecifier; - } else if (separatorIndex === -1) { - // The specifier doesn't have a version - name = rawPackageSpecifier; - } else { - name = rawPackageSpecifier.substring(0, separatorIndex); - version = rawPackageSpecifier.substring(separatorIndex + 1); - } - - if (!name) { - throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); - } - - return { name, version }; -} - -/** - * As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims - * unusable lines from the .npmrc file. - * - * Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in - * the .npmrc file to provide different authentication tokens for different registry. - * However, if the environment variable is undefined, it expands to an empty string, which - * produces a valid-looking mapping with an invalid URL that causes an error. Instead, - * we'd prefer to skip that line and continue looking in other places such as the user's - * home directory. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._copyNpmrcFile() - */ -function _copyAndTrimNpmrcFile(sourceNpmrcPath: string, targetNpmrcPath: string): void { - console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`); // Verbose - let npmrcFileLines: string[] = fs.readFileSync(sourceNpmrcPath).toString().split('\n'); - npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); - const resultLines: string[] = []; - // Trim out lines that reference environment variables that aren't defined - for (const line of npmrcFileLines) { - // This finds environment variable tokens that look like "${VAR_NAME}" - const regex: RegExp = /\$\{([^\}]+)\}/g; - const environmentVariables: string[] | null = line.match(regex); - let lineShouldBeTrimmed: boolean = false; - if (environmentVariables) { - for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName: string = token.substring(2, token.length - 1); - if (!process.env[environmentVariableName]) { - 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); - } - } - - fs.writeFileSync(targetNpmrcPath, resultLines.join(os.EOL)); -} - -/** - * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. - * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc() - */ -function _syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string, useNpmrcPublish?: boolean): void { - const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); - const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc'); - try { - if (fs.existsSync(sourceNpmrcPath)) { - _copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath); - } else if (fs.existsSync(targetNpmrcPath)) { - // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target - console.log(`Deleting ${targetNpmrcPath}`); // Verbose - fs.unlinkSync(targetNpmrcPath); - } - } catch (e) { - throw new Error(`Error syncing .npmrc file: ${e}`); - } -} - -let _npmPath: string | undefined = undefined; - -/** - * Get the absolute path to the npm executable - */ -export function getNpmPath(): string { - if (!_npmPath) { - try { - if (os.platform() === 'win32') { - // We're on Windows - const whereOutput: string = childProcess.execSync('where npm', { stdio: [] }).toString(); - const lines: string[] = whereOutput.split(os.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 = childProcess.execSync('which npm', { stdio: [] }).toString(); - } - } catch (e) { - throw new Error(`Unable to determine the path to the NPM tool: ${e}`); - } - - _npmPath = _npmPath.trim(); - if (!fs.existsSync(_npmPath)) { - throw new Error('The NPM executable does not exist'); - } - } - - return _npmPath; -} - -function _ensureFolder(folderPath: string): void { - if (!fs.existsSync(folderPath)) { - const parentDir: string = path.dirname(folderPath); - _ensureFolder(parentDir); - fs.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: string, ...pathSegments: string[]): string { - let joinedPath: string = baseFolder; - try { - for (let pathSegment of pathSegments) { - pathSegment = pathSegment.replace(/[\\\/]/g, '+'); - joinedPath = path.join(joinedPath, pathSegment); - if (!fs.existsSync(joinedPath)) { - fs.mkdirSync(joinedPath); - } - } - } catch (e) { - throw new Error(`Error building local installation folder (${path.join(baseFolder, ...pathSegments)}): ${e}`); - } - - return joinedPath; -} - -function _getRushTempFolder(rushCommonFolder: string): string { - const rushTempFolder: string | undefined = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME]; - if (rushTempFolder !== undefined) { - _ensureFolder(rushTempFolder); - return rushTempFolder; - } else { - return _ensureAndJoinPath(rushCommonFolder, 'temp'); - } -} - -export interface IPackageSpecifier { - name: string; - version: string | undefined; -} - -/** - * Resolve a package specifier to a static version - */ -function _resolvePackageVersion(rushCommonFolder: string, { name, version }: IPackageSpecifier): string { - if (!version) { - version = '*'; // If no version is specified, use the latest version - } - - 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 { - // version resolves to - try { - const rushTempFolder: string = _getRushTempFolder(rushCommonFolder); - const sourceNpmrcFolder: string = path.join(rushCommonFolder, 'config', 'rush'); - - _syncNpmrc(sourceNpmrcFolder, rushTempFolder); - - const npmPath: string = getNpmPath(); - - // This returns something that looks like: - // @microsoft/rush@3.0.0 '3.0.0' - // @microsoft/rush@3.0.1 '3.0.1' - // ... - // @microsoft/rush@3.0.20 '3.0.20' - // - const npmVersionSpawnResult: childProcess.SpawnSyncReturns = childProcess.spawnSync( - npmPath, - ['view', `${name}@${version}`, 'version', '--no-update-notifier'], - { - cwd: rushTempFolder, - stdio: [] - } - ); - - if (npmVersionSpawnResult.status !== 0) { - throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); - } - - const npmViewVersionOutput: string = npmVersionSpawnResult.stdout.toString(); - const versionLines: string[] = npmViewVersionOutput.split('\n').filter((line) => !!line); - const latestVersion: string | undefined = versionLines[versionLines.length - 1]; - if (!latestVersion) { - throw new Error('No versions found for the specified version range.'); - } - - const versionMatches: string[] | null = latestVersion.match(/^.+\s\'(.+)\'$/); - if (!versionMatches) { - throw new Error(`Invalid npm output ${latestVersion}`); - } - - return versionMatches[1]; - } catch (e) { - throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`); - } - } -} - -let _rushJsonFolder: string | undefined; -/** - * Find the absolute path to the folder containing rush.json - */ -export function findRushJsonFolder(): string { - if (!_rushJsonFolder) { - let basePath: string = __dirname; - let tempPath: string = __dirname; - do { - const testRushJsonPath: string = path.join(basePath, RUSH_JSON_FILENAME); - if (fs.existsSync(testRushJsonPath)) { - _rushJsonFolder = basePath; - break; - } else { - basePath = tempPath; - } - } while (basePath !== (tempPath = path.dirname(basePath))); // Exit the loop when we hit the disk root - - if (!_rushJsonFolder) { - throw new Error('Unable to find rush.json.'); - } - } - - return _rushJsonFolder; -} - -/** - * Detects if the package in the specified directory is installed - */ -function _isPackageAlreadyInstalled(packageInstallFolder: string): boolean { - try { - const flagFilePath: string = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - if (!fs.existsSync(flagFilePath)) { - return false; - } - - const fileContents: string = fs.readFileSync(flagFilePath).toString(); - return fileContents.trim() === process.version; - } catch (e) { - return false; - } -} - -/** - * Removes the following files and directories under the specified folder path: - * - installed.flag - * - - * - node_modules - */ -function _cleanInstallFolder(rushTempFolder: string, packageInstallFolder: string): void { - try { - const flagFile: string = path.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); - if (fs.existsSync(flagFile)) { - fs.unlinkSync(flagFile); - } - - const packageLockFile: string = path.resolve(packageInstallFolder, 'package-lock.json'); - if (fs.existsSync(packageLockFile)) { - fs.unlinkSync(packageLockFile); - } - - const nodeModulesFolder: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); - if (fs.existsSync(nodeModulesFolder)) { - const rushRecyclerFolder: string = _ensureAndJoinPath( - rushTempFolder, - 'rush-recycler', - `install-run-${Date.now().toString()}` - ); - fs.renameSync(nodeModulesFolder, rushRecyclerFolder); - } - } catch (e) { - throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); - } -} - -function _createPackageJson(packageInstallFolder: string, name: string, version: string): void { - try { - const packageJsonContents: IPackageJson = { - 'name': 'ci-rush', - 'version': '0.0.0', - 'dependencies': { - [name]: version - }, - 'description': 'DON\'T WARN', - 'repository': 'DON\'T WARN', - 'license': 'MIT' - }; - - const packageJsonPath: string = path.join(packageInstallFolder, PACKAGE_JSON_FILENAME); - fs.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(packageInstallFolder: string, name: string, version: string): void { - try { - console.log(`Installing ${name}...`); - const npmPath: string = getNpmPath(); - const result: childProcess.SpawnSyncReturns = childProcess.spawnSync( - npmPath, - ['install'], - { - stdio: 'inherit', - cwd: packageInstallFolder, - env: process.env - } - ); - - if (result.status !== 0) { - throw new Error('"npm install" encountered an error'); - } - - console.log(`Successfully installed ${name}@${version}`); - } catch (e) { - throw new Error(`Unable to install package: ${e}`); - } -} - -/** - * Get the ".bin" path for the package. - */ -function _getBinPath(packageInstallFolder: string, binName: string): string { - const binFolderPath: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - const resolvedBinName: string = (os.platform() === 'win32') ? `${binName}.cmd` : binName; - return path.resolve(binFolderPath, resolvedBinName); -} - -/** - * Write a flag file to the package's install directory, signifying that the install was successful. - */ -function _writeFlagFile(packageInstallFolder: string): void { - try { - const flagFilePath: string = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - fs.writeFileSync(flagFilePath, process.version); - } catch (e) { - throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`); - } -} - -export function installAndRun( - packageName: string, - packageVersion: string, - packageBinName: string, - packageBinArgs: string[] -): number { - const rushJsonFolder: string = findRushJsonFolder(); - const rushCommonFolder: string = path.join(rushJsonFolder, 'common'); - const rushTempFolder: string = _getRushTempFolder(rushCommonFolder); - const packageInstallFolder: string = _ensureAndJoinPath( - rushTempFolder, - 'install-run', - `${packageName}@${packageVersion}` - ); - - if (!_isPackageAlreadyInstalled(packageInstallFolder)) { - // The package isn't already installed - _cleanInstallFolder(rushTempFolder, packageInstallFolder); - - const sourceNpmrcFolder: string = path.join(rushCommonFolder, 'config', 'rush'); - _syncNpmrc(sourceNpmrcFolder, packageInstallFolder); - - _createPackageJson(packageInstallFolder, packageName, packageVersion); - _installPackage(packageInstallFolder, packageName, packageVersion); - _writeFlagFile(packageInstallFolder); - } - - const statusMessage: string = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; - const statusMessageLine: string = new Array(statusMessage.length + 1).join('-'); - console.log(os.EOL + statusMessage + os.EOL + statusMessageLine + os.EOL); - - const binPath: string = _getBinPath(packageInstallFolder, packageBinName); - const result: childProcess.SpawnSyncReturns = childProcess.spawnSync( - binPath, - packageBinArgs, - { - stdio: 'inherit', - cwd: process.cwd(), - env: process.env - } - ); - - if (result.status !== null) { - return result.status; - } else { - throw result.error || new Error('An unknown error occurred.'); - } -} - -export function runWithErrorAndStatusCode(fn: () => number): void { - process.exitCode = 1; - - try { - const exitCode: number = fn(); - process.exitCode = exitCode; - } catch (e) { - console.error(os.EOL + os.EOL + e.toString() + os.EOL + os.EOL); - } -} - -function _run(): void { - const [ - nodePath, /* Ex: /bin/node */ - scriptPath, /* /repo/common/scripts/install-run-rush.js */ - rawPackageSpecifier, /* qrcode@^1.2.0 */ - packageBinName, /* qrcode */ - ...packageBinArgs /* [-f, myproject/lib] */ - ]: string[] = process.argv; - - if (!nodePath) { - throw new Error('Unexpected exception: could not detect node path'); - } - - if (path.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) { - console.log('Usage: install-run.js @ [args...]'); - console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io'); - process.exit(1); - } - - runWithErrorAndStatusCode(() => { - const rushJsonFolder: string = findRushJsonFolder(); - const rushCommonFolder: string = _ensureAndJoinPath(rushJsonFolder, 'common'); - - const packageSpecifier: IPackageSpecifier = _parsePackageSpecifier(rawPackageSpecifier); - const name: string = packageSpecifier.name; - const version: string = _resolvePackageVersion(rushCommonFolder, packageSpecifier); - - if (packageSpecifier.version !== version) { - console.log(`Resolved to ${name}@${version}`); - } - - return installAndRun(name, version, packageBinName, packageBinArgs); - }); -} - -_run(); diff --git a/apps/rush-lib/src/start.ts b/apps/rush-lib/src/start.ts deleted file mode 100644 index b4da75c1edc..00000000000 --- a/apps/rush-lib/src/start.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Rush } from './api/Rush'; - -Rush.launch(Rush.version, { isManaged: false }); diff --git a/apps/rush-lib/src/utilities/AlreadyReportedError.ts b/apps/rush-lib/src/utilities/AlreadyReportedError.ts deleted file mode 100644 index 062fb6f8643..00000000000 --- a/apps/rush-lib/src/utilities/AlreadyReportedError.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * This exception is thrown to indicate that the operation failed, but an - * appropriate error message was already printed to the console. The catch - * block should not print any error. - */ -export class AlreadyReportedError extends Error { - - public constructor() { - super('An error occurred.'); - - // 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/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work](https://github.com/microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work) - // - // Note: the prototype must also be set on any classes which extend this one - (this as any).__proto__ = AlreadyReportedError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any - } -} diff --git a/apps/rush-lib/src/utilities/AsyncRecycler.ts b/apps/rush-lib/src/utilities/AsyncRecycler.ts deleted file mode 100644 index 579694c8459..00000000000 --- a/apps/rush-lib/src/utilities/AsyncRecycler.ts +++ /dev/null @@ -1,193 +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 child_process from 'child_process'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; - -import { - Text, - Path, - FileSystem -} from '@rushstack/node-core-library'; - -import { Utilities } from './Utilities'; - -/** - * For deleting large folders, AsyncRecycler is significantly faster than Utilities.dangerouslyDeletePath(). - * It works by moving one or more folders into a temporary "recycler" folder, and then launches a separate - * background process to recursively delete that folder. - */ -export class AsyncRecycler { - private _recyclerFolder: string; - private _movedFolderCount: number; - private _deleting: boolean; - - public constructor(recyclerFolder: string) { - this._recyclerFolder = path.resolve(recyclerFolder); - this._movedFolderCount = 0; - this._deleting = false; - } - - /** - * The full path of the recycler folder. - * Example: `C:\MyRepo\common\rush-recycler` - */ - public get recyclerFolder(): string { - return this._recyclerFolder; - } - - /** - * Synchronously moves the specified folder into the recycler folder. If the specified folder - * does not exist, then no operation is performed. After calling this function one or more times, - * deleteAll() must be called to actually delete the contents of the recycler folder. - */ - public moveFolder(folderPath: string): void { - if (this._deleting) { - throw new Error('AsyncRecycler.moveFolder() must not be called after deleteAll() has started'); - } - - if (Path.isUnder(this.recyclerFolder, folderPath)) { - throw new Error('AsyncRecycler.moveFolder() cannot be called on a parent of the recycler folder'); - } - - if (!FileSystem.exists(folderPath)) { - return; - } - - ++this._movedFolderCount; - - // We need to do a simple "FileSystem.move" here, however if the folder we're trying to rename - // has a lock, or if its destination container doesn't exist yet, - // then there seems to be some OS process (virus scanner?) that holds - // a lock on the folder for a split second, which causes renameSync to - // fail. To workaround that, retry for up to 7 seconds before giving up. - const maxWaitTimeMs: number = 7 * 1000; - - const oldFolderName: string = path.basename(folderPath); - const newFolderPath: string = path.join(this.recyclerFolder, `${oldFolderName}_${new Date().getTime()}`); - - if (!FileSystem.exists(this.recyclerFolder)) { - Utilities.createFolderWithRetry(this.recyclerFolder); - } - - Utilities.retryUntilTimeout( - () => FileSystem.move({ sourcePath: folderPath, destinationPath: newFolderPath }), - maxWaitTimeMs, - (e) => new Error(`Error: ${e}${os.EOL}Often this is caused by a file lock ` + - 'from a process like the virus scanner.'), - 'recycleFolder' - ); - } - - /** - * This deletes all items under the specified folder, except for the items in the membersToExclude. - * To be conservative, a case-insensitive comparison is used for membersToExclude. - * The membersToExclude must be file/folder names that would match readdir() results. - */ - public moveAllItemsInFolder(folderPath: string, membersToExclude?: ReadonlyArray): void { - const resolvedFolderPath: string = path.resolve(folderPath); - - const excludeSet: Set = new Set( - (membersToExclude || []).map(x => x.toUpperCase()) - ); - - for (const memberPath of FileSystem.readFolder(resolvedFolderPath, { absolutePaths: true })) { - const normalizedMemberName: string = path.basename(memberPath).toUpperCase(); - if (!excludeSet.has(normalizedMemberName)) { - let shouldMove: boolean = false; - try { - const stats: fs.Stats = FileSystem.getLinkStatistics(memberPath); - shouldMove = stats.isDirectory(); - } catch (error) { - // If we fail to access the item, assume it's not a folder - } - if (shouldMove) { - this.moveFolder(memberPath); - } else { - FileSystem.deleteFolder(memberPath); - } - } - } - } - - /** - * Starts an asynchronous process to delete the recycler folder. Deleting will continue - * even if the current Node.js process is killed. - * - * NOTE: To avoid spawning multiple instances of the same command, moveFolder() - * MUST NOT be called again after deleteAll() has started. - */ - public deleteAll(): void { - if (this._deleting) { - throw new Error('AsyncRecycler.deleteAll() must not be called more than once'); - } - - this._deleting = true; - - if (this._movedFolderCount === 0) { - // Nothing to do - return; - } - - // Asynchronously delete the folder contents. - let command: string; - let args: string[]; - - const options: child_process.SpawnOptions = { - detached: true, - // The child won't stay alive unless we detach its stdio - stdio: 'ignore' - }; - - if (os.platform() === 'win32') { - // PowerShell.exe doesn't work with a detached console, so we need cmd.exe to create - // the new console for us. - command = 'cmd.exe'; - - // In PowerShell single-quote literals, single quotes are escaped by doubling them - const escapedRecyclerFolder: string = Text.replaceAll(this.recyclerFolder, '\'', '\'\''); - - // As of PowerShell 3.0, the "\\?" prefix can be used for paths that exceed MAX_PATH. - // (This prefix does not seem to work for cmd.exe's "rd" command.) - args = [ - '/c', - '"' + - 'PowerShell.exe -Version 3.0 -NoLogo -NonInteractive -WindowStyle Hidden -Command' - + ` Get-ChildItem -Force '${escapedRecyclerFolder}'` - // The "^|" here prevents cmd.exe from interpreting the "|" symbol - + ` ^| ForEach ($_) { Remove-Item -ErrorAction Ignore -Force -Recurse "\\\\?\\$($_.FullName)" }` - + '"' - ]; - - options.windowsVerbatimArguments = true; - } else { - command = 'rm'; - args = [ '-rf' ]; - - let pathCount: number = 0; - - // child_process.spawn() doesn't expand wildcards. To be safe, we will do it manually - // rather than rely on an unknown shell. - for (const filename of FileSystem.readFolder(this.recyclerFolder)) { - // The "." and ".." are supposed to be excluded, but let's be safe - if (filename !== '.' && filename !== '..') { - args.push(path.join(this.recyclerFolder, filename)); - ++pathCount; - } - } - - if (pathCount === 0) { - // Nothing to do - return; - } - } - - const process: child_process.ChildProcess = child_process.spawn(command, args, options); - - // The child won't stay alive unless we unlink it from the parent process - process.unref(); - } - -} diff --git a/apps/rush-lib/src/utilities/Npm.ts b/apps/rush-lib/src/utilities/Npm.ts deleted file mode 100644 index 5d3cb8aaed5..00000000000 --- a/apps/rush-lib/src/utilities/Npm.ts +++ /dev/null @@ -1,55 +0,0 @@ -// 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'; - -export class Npm { - public static publishedVersions( - packageName: string, - cwd: string, - env: { [key: string]: string | undefined }, - extraArgs: string[] = [] - ): string[] { - const versions: string[] = []; - try { - const packageTime: string = Utilities.executeCommandAndCaptureOutput('npm', - ['view', packageName, 'time', '--json', ...extraArgs], - cwd, - env, - true - ); - if (packageTime && packageTime !== '') { - Object.keys(JSON.parse(packageTime)).forEach(v => { - if (semver.valid(v)) { - versions.push(v); - } - }); - } else { - 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 = Utilities.executeCommandAndCaptureOutput('npm', - ['view', packageName, 'versions', '--json', ...extraArgs], - cwd, - env, - true - ); - if (packageVersions && packageVersions.length > 0) { - (JSON.parse(packageVersions)).forEach(v => { - versions.push(v); - }); - } else { - console.log(`No version is found for ${packageName}`); - } - } - } catch (error) { - if (error.message.indexOf('npm ERR! 404') >= 0) { - console.log(`Package ${packageName} does not exist in the registry.`); - } else { - console.log(`Failed to get NPM information about ${packageName}.`); - throw error; - } - } - return versions; - } -} diff --git a/apps/rush-lib/src/utilities/Stopwatch.ts b/apps/rush-lib/src/utilities/Stopwatch.ts deleted file mode 100644 index d31fd754768..00000000000 --- a/apps/rush-lib/src/utilities/Stopwatch.ts +++ /dev/null @@ -1,108 +0,0 @@ -// 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'; - -/** - * Used with the Stopwatch class. - */ -export enum StopwatchState { - Stopped = 1, - Started = 2 -} - -/** - * Represents a typical timer/stopwatch which keeps track - * of elapsed time in between two events. - */ -export class Stopwatch { - private _startTime: number | undefined; - private _endTime: number | undefined; - private _state: StopwatchState; - - private _getTime: () => number; - - public constructor(getTime: () => number = Utilities.getTimeInMs) { - this._startTime = undefined; - this._endTime = undefined; - this._getTime = getTime; - this._state = StopwatchState.Stopped; - } - - /** - * Static helper function which creates a stopwatch which is immediately started - */ - public static start(): Stopwatch { - return new Stopwatch().start(); - } - - public get state(): StopwatchState { - return this._state; - } - - /** - * Starts the stopwatch. Note that if end() has been called, - * reset() should be called before calling start() again. - */ - public start(): Stopwatch { - if (this._startTime !== undefined) { - throw new Error('Call reset() before starting the Stopwatch'); - } - this._startTime = this._getTime(); - this._endTime = undefined; - this._state = StopwatchState.Started; - return this; - } - - /** - * Stops executing the stopwatch and saves the current timestamp - */ - public stop(): Stopwatch { - this._endTime = (this._startTime !== undefined ? this._getTime() : undefined); - this._state = StopwatchState.Stopped; - return this; - } - - /** - * Resets all values of the stopwatch back to the original - */ - public reset(): Stopwatch { - this._endTime = this._startTime = undefined; - this._state = StopwatchState.Stopped; - return this; - } - - /** - * Displays how long the stopwatch has been executing in a human readable format. - */ - public toString(): string { - if (this._state === StopwatchState.Stopped && this._startTime === undefined) { - return '0.00 seconds (stopped)'; - } - const totalSeconds: number = this.duration; - - if (totalSeconds > 60) { - const minutes: number = Math.floor(totalSeconds / 60); - const seconds: number = totalSeconds % 60.0; - - return `${minutes.toFixed(0)} minute${minutes === 1 ? '' : 's'}` + - ` ${seconds.toFixed(1)} seconds`; - } else { - return `${totalSeconds.toFixed(2)} seconds`; - } - } - - /** - * Get the duration in seconds. - */ - public get duration(): number { - if (this._startTime === undefined) { - return 0; - } - const curTime: number = this._endTime !== undefined - ? this._endTime - : this._getTime(); - - return ((curTime - this._startTime) / 1000.0); - } -} diff --git a/apps/rush-lib/src/utilities/Utilities.ts b/apps/rush-lib/src/utilities/Utilities.ts deleted file mode 100644 index 41abb827dee..00000000000 --- a/apps/rush-lib/src/utilities/Utilities.ts +++ /dev/null @@ -1,760 +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 child_process from 'child_process'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as tty from 'tty'; -import * as path from 'path'; -import * as wordwrap from 'wordwrap'; -import { - JsonFile, - IPackageJson, - FileSystem, - FileConstants -} from '@rushstack/node-core-library'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { Stream } from 'stream'; - -export interface IEnvironment { - // NOTE: the process.env doesn't actually support "undefined" as a value. - // If you try to assign it, it will be converted to the text string "undefined". - // But this typing is needed for reading values from the dictionary, and for - // subsets that get combined. - [environmentVariableName: string]: string | undefined; -} - -/** - * Options for Utilities.installPackageInDirectory(). - */ -export interface IInstallPackageInDirectoryOptions { - directory: string; - packageName: string; - version: string; - tempPackageTitle: string; - maxInstallAttempts: number; - commonRushConfigFolder: string | undefined; - suppressOutput?: boolean; -} - -export interface ILifecycleCommandOptions { - /** - * The rush configuration, if the command is running in a rush repo. - */ - rushConfiguration: RushConfiguration | undefined; - - /** - * Working directory for running the command - */ - workingDirectory: string; - - /** - * The folder containing a local .npmrc, which will be used for the INIT_CWD environment variable - */ - initCwd: string; - - /** - * If true, suppress the process's output, but if there is a nonzero exit code then print stderr - */ - handleOutput: boolean; - - /** - * Options for what should be added to the PATH variable - */ - environmentPathOptions: IEnvironmentPathOptions; -} - -export interface IEnvironmentPathOptions { - /** - * If true, include /node_modules/.bin in the PATH. If both this and - * {@link IEnvironmentPathOptions.includeRepoBin} are set, this path will take precedence. - */ - includeProjectBin?: boolean; - - /** - * If true, include /common/temp/node_modules/.bin in the PATH. - */ - includeRepoBin?: boolean; -} - -interface ICreateEnvironmentForRushCommandPathOptions extends IEnvironmentPathOptions { - projectRoot: string | undefined; - commonTempFolder: string | undefined; -} - -interface ICreateEnvironmentForRushCommandOptions { - /** - * The INIT_CWD environment variable - */ - initCwd?: string; - - /** - * an existing environment to copy instead of process.env - */ - initialEnvironment?: IEnvironment; - - /** - * Options for what should be added to the PATH variable - */ - pathOptions?: ICreateEnvironmentForRushCommandPathOptions; -} - -export class Utilities { - /** - * Get the user's home directory. On windows this looks something like "C:\users\username\" and on UNIX - * this looks something like "/usr/username/" - */ - public static getHomeDirectory(): 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); - } - - return homeFolder; - } - - /** - * Node.js equivalent of performance.now(). - */ - public static getTimeInMs(): number { - const [seconds, nanoseconds] = process.hrtime(); - return seconds * 1000 + nanoseconds / 1000000; - } - - /** - * Returns the values from a Set - */ - public static getSetAsArray(set: Set): T[] { - // When ES6 is supported, we can use Array.from() instead. - const result: T[] = []; - set.forEach((value: T) => { - result.push(value); - }); - return result; - } - - /** - * Retries a function until a timeout is reached. The function is expected to throw if it failed and - * should be retried. - */ - public static retryUntilTimeout( - fn: () => TResult, - maxWaitTimeMs: number, - getTimeoutError: (innerError: Error) => Error, - fnName: string - ): TResult { - const startTime: number = Utilities.getTimeInMs(); - let looped: boolean = false; - - let result: TResult; - for (;;) { - try { - result = fn(); - break; - } catch (e) { - looped = true; - const currentTime: number = Utilities.getTimeInMs(); - if (currentTime - startTime > maxWaitTimeMs) { - throw getTimeoutError(e); - } - } - } - - if (looped) { - const currentTime: number = Utilities.getTimeInMs(); - const totalSeconds: string = ((currentTime - startTime) / 1000.0).toFixed(2); - // This logging statement isn't meaningful to the end-user. `fnName` should be updated - // to something like `operationDescription` - console.log(`${fnName}() stalled for ${totalSeconds} seconds`); - } - - return result; - } - - /** - * Creates the specified folder by calling FileSystem.ensureFolder(), but using a - * retry loop to recover from temporary locks that may be held by other processes. - * If the folder already exists, no error occurs. - */ - public static createFolderWithRetry(folderName: string): void { - // Note: If a file exists with the same name, then we fall through and report - // an error. - if (Utilities.directoryExists(folderName)) { - return; - } - - // We need to do a simple "FileSystem.ensureFolder(localModulesFolder)" here, - // however if the folder we deleted above happened to contain any files, - // then there seems to be some OS process (virus scanner?) that holds - // a lock on the folder for a split second, which causes mkdirSync to - // fail. To workaround that, retry for up to 7 seconds before giving up. - const maxWaitTimeMs: number = 7 * 1000; - - return Utilities.retryUntilTimeout( - () => FileSystem.ensureFolder(folderName), - maxWaitTimeMs, - (e) => new Error( - `Error: ${e}${os.EOL}Often this is caused by a file lock ` + - 'from a process such as your text editor, command prompt, ' + - 'or a filesystem watcher.' - ), - 'createFolderWithRetry' - ); - } - - /** - * Determines if the path points to a file and that it exists. - */ - public static fileExists(filePath: string): boolean { - let exists: boolean = false; - - try { - const lstat: fs.Stats = FileSystem.getLinkStatistics(filePath); - exists = lstat.isFile(); - } catch (e) { /* no-op */ } - - return exists; - } - - /** - * Determines if a path points to a directory and that it exists. - */ - public static directoryExists(directoryPath: string): boolean { - let exists: boolean = false; - - try { - const lstat: fs.Stats = FileSystem.getLinkStatistics(directoryPath); - exists = lstat.isDirectory(); - } catch (e) { /* no-op */ } - - return exists; - } - - /** - * BE VERY CAREFUL CALLING THIS FUNCTION! - * If you specify the wrong folderPath (e.g. "/"), it could potentially delete your entire - * hard disk. - */ - public static dangerouslyDeletePath(folderPath: string): void { - try { - FileSystem.deleteFolder(folderPath); - } catch (e) { - throw new Error( - `${e.message}${os.EOL}Often this is caused by a file lock from a process ` + - 'such as your text editor, command prompt, or a filesystem watcher' - ); - } - } - - /** - * Attempts to delete a file. If it does not exist, or the path is not a file, it no-ops. - */ - public static deleteFile(filePath: string): void { - if (Utilities.fileExists(filePath)) { - console.log(`Deleting: ${filePath}`); - FileSystem.deleteFile(filePath); - } - } - - /* - * Returns true if outputFilename has a more recent last modified timestamp - * than all of the inputFilenames, which would imply that we don't need to rebuild it. - * Returns false if any of the files does not exist. - * NOTE: The filenames can also be paths for directories, in which case the directory - * timestamp is compared. - */ - public static isFileTimestampCurrent(outputFilename: string, inputFilenames: string[]): boolean { - if (!FileSystem.exists(outputFilename)) { - return false; - } - const outputStats: fs.Stats = FileSystem.getStatistics(outputFilename); - - for (const inputFilename of inputFilenames) { - if (!FileSystem.exists(inputFilename)) { - return false; - } - - const inputStats: fs.Stats = FileSystem.getStatistics(inputFilename); - if (outputStats.mtime < inputStats.mtime) { - return false; - } - } - - return true; - } - - /** - * Returns the width of the console, measured in columns - */ - public static getConsoleWidth(): number { - const stdout: tty.WriteStream = process.stdout as tty.WriteStream; - if (stdout && stdout.columns) { - return stdout.columns; - } - - return 80; - } - - /** - * Applies word wrapping. If maxLineLength is unspecified, then it defaults to the console - * width. - */ - public static wrapWords(text: string, maxLineLength?: number, indent?: number): string { - if (!indent) { - indent = 0; - } - if (!maxLineLength) { - maxLineLength = Utilities.getConsoleWidth(); - } - - const wrap: (textToWrap: string) => string = wordwrap(indent, maxLineLength, { mode: 'soft' }); - return wrap(text); - } - - /** - * 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 executeCommand(command: string, args: string[], workingDirectory: string, - environment?: IEnvironment, suppressOutput: boolean = false, - keepEnvironment: boolean = false - ): void { - - Utilities._executeCommandInternal(command, args, workingDirectory, - suppressOutput ? undefined : [0, 1, 2], - environment, - keepEnvironment - ); - } - - /** - * 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 executeCommandAndCaptureOutput(command: string, args: string[], workingDirectory: string, - environment?: IEnvironment, - keepEnvironment: boolean = false - ): string { - - const result: child_process.SpawnSyncReturns = Utilities._executeCommandInternal( - command, - args, - workingDirectory, - ['pipe', 'pipe', 'pipe'], - environment, - keepEnvironment - ); - - return result.stdout.toString(); - } - - /** - * Attempts to run Utilities.executeCommand() up to maxAttempts times before giving up. - */ - public static executeCommandWithRetry(maxAttempts: number, command: string, args: string[], - workingDirectory: string, environment?: IEnvironment, suppressOutput: boolean = false, - retryCallback?: () => void): void { - - if (maxAttempts < 1) { - throw new Error('The maxAttempts parameter cannot be less than 1'); - } - - let attemptNumber: number = 1; - - for (;;) { - try { - Utilities.executeCommand(command, args, workingDirectory, environment, suppressOutput); - } catch (error) { - console.log(os.EOL + 'The command failed:'); - console.log(` ${command} ` + args.join(' ')); - console.log(`ERROR: ${error.toString()}`); - - if (attemptNumber < maxAttempts) { - ++attemptNumber; - console.log(`Trying again (attempt #${attemptNumber})...` + os.EOL); - if (retryCallback) { - retryCallback(); - } - - continue; - } else { - console.error(`Giving up after ${attemptNumber} attempts` + os.EOL); - throw error; - } - } - - break; - } - } - - /** - * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS. - * @param command - the command to run on shell - * @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 - ); - - if (options.handleOutput) { - Utilities._processResult(result); - } - - if (result.status !== null) { - return result.status; - } else { - throw result.error || new Error('An unknown error occurred.'); - } - } - - /** - * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS. - * @param command - the command to run on shell - * @param options - options for how the command should be run - */ - public static executeLifecycleCommandAsync( - command: string, - options: ILifecycleCommandOptions - ): child_process.ChildProcess { - return Utilities._executeLifecycleCommandInternal( - command, - child_process.spawn, - options - ); - } - - /** - * 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 { - return `"${parameter}"`; - } - - /** - * Installs a package by name and version in the specified directory. - */ - public static installPackageInDirectory(options: IInstallPackageInDirectoryOptions): void { - const directory: string = path.resolve(options.directory); - if (FileSystem.exists(directory)) { - console.log('Deleting old files from ' + directory); - } - - FileSystem.ensureEmptyFolder(directory); - - const npmPackageJson: IPackageJson = { - dependencies: { - [options.packageName]: options.version - }, - description: 'Temporary file generated by the Rush tool', - name: options.tempPackageTitle, - private: true, - version: '0.0.0' - }; - JsonFile.save(npmPackageJson, path.join(directory, FileConstants.PackageJson)); - - if (options.commonRushConfigFolder) { - Utilities.syncNpmrc(options.commonRushConfigFolder, directory); - } - - console.log(os.EOL + 'Running "npm install" in ' + directory); - - // NOTE: Here we use whatever version of NPM we happen to find in the PATH - Utilities.executeCommandWithRetry( - options.maxInstallAttempts, - 'npm', - ['install'], - directory, - Utilities._createEnvironmentForRushCommand({}), - options.suppressOutput - ); - } - - public static withFinally(options: { promise: Promise, finally: () => void }): Promise { - return options.promise.then((result: T) => { - try { - options.finally(); - } catch (error) { - return Promise.reject(error); - } - return result; - }).catch((error: Error) => { - try { - options.finally(); - } catch (innerError) { - return Promise.reject(innerError); - } - return Promise.reject(error); - }); - } - - /** - * As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims - * unusable lines from the .npmrc file. - * - * Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in - * the .npmrc file to provide different authentication tokens for different registry. - * However, if the environment variable is undefined, it expands to an empty string, which - * produces a valid-looking mapping with an invalid URL that causes an error. Instead, - * we'd prefer to skip that line and continue looking in other places such as the user's - * home directory. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _copyNpmrcFile() FROM scripts/install-run.ts - */ - public static copyAndTrimNpmrcFile(sourceNpmrcPath: string, targetNpmrcPath: string): void { - console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`); // Verbose - let npmrcFileLines: string[] = FileSystem.readFile(sourceNpmrcPath).split('\n'); - npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); - const resultLines: string[] = []; - // Trim out lines that reference environment variables that aren't defined - for (const line of npmrcFileLines) { - // This finds environment variable tokens that look like "${VAR_NAME}" - const regex: RegExp = /\$\{([^\}]+)\}/g; - const environmentVariables: string[] | null = line.match(regex); - let lineShouldBeTrimmed: boolean = false; - if (environmentVariables) { - for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName: string = token.substring(2, token.length - 1); - if (!process.env[environmentVariableName]) { - 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); - } - } - - FileSystem.writeFile(targetNpmrcPath, resultLines.join(os.EOL)); - } - - /** - * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. - * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH _syncNpmrc() FROM scripts/install-run.ts - */ - public static syncNpmrc(sourceNpmrcFolder: string, targetNpmrcFolder: string, useNpmrcPublish?: boolean): void { - const sourceNpmrcPath: string = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); - const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc'); - try { - if (FileSystem.exists(sourceNpmrcPath)) { - Utilities.copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath); - } else if (FileSystem.exists(targetNpmrcPath)) { - // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target - console.log(`Deleting ${targetNpmrcPath}`); // Verbose - FileSystem.deleteFile(targetNpmrcPath); - } - } catch (e) { - throw new Error(`Error syncing .npmrc file: ${e}`); - } - } - - public static getRushConfigNotFoundError(): Error { - return new Error('Unable to find rush.json configuration file'); - } - - public static getPackageDepsFilenameForCommand(command: string): string { - return `package-deps_${command}.json`; - } - - 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') { - shellCommand = 'sh'; - commandFlags = '-c'; - useShell = false; - } - - const environment: IEnvironment = Utilities._createEnvironmentForRushCommand( - { - initCwd: options.initCwd, - pathOptions: { - ...options.environmentPathOptions, - projectRoot: options.workingDirectory, - commonTempFolder: options.rushConfiguration ? options.rushConfiguration.commonTempFolder : undefined - } - } - ); - - return spawnFunction( - shellCommand, - [commandFlags, command], - { - cwd: options.workingDirectory, - shell: useShell, - env: environment, - stdio: options.handleOutput ? ['pipe', 'pipe', 'pipe'] : [0, 1, 2] - } - ); - } - - /** - * Returns a process.env environment suitable for executing lifecycle scripts. - * @param initialEnvironment - an existing environment to copy instead of process.env - */ - private static _createEnvironmentForRushCommand(options: ICreateEnvironmentForRushCommandOptions): IEnvironment { - if (options.initialEnvironment === undefined) { - options.initialEnvironment = process.env; - } - - const environment: IEnvironment = {}; - for (const key of Object.getOwnPropertyNames(options.initialEnvironment)) { - const normalizedKey: string = os.platform() === 'win32' ? 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 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; - } - - // Use the uppercased environment variable name on Windows because environment variable names - // are case-insensitive on Windows - environment[normalizedKey] = options.initialEnvironment[key]; - } - - // 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) { - if (options.pathOptions.includeRepoBin && options.pathOptions.commonTempFolder) { - environment.PATH = Utilities._prependNodeModulesBinToPath( - environment.PATH, - options.pathOptions.commonTempFolder - ); - } - - if (options.pathOptions.includeProjectBin && options.pathOptions.projectRoot) { - environment.PATH = Utilities._prependNodeModulesBinToPath( - environment.PATH, - options.pathOptions.projectRoot - ); - } - } - - return environment; - } - - /** - * 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; - } - } - - /** - * 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 _executeCommandInternal( - command: string, args: string[], workingDirectory: string, - stdio: 'pipe'|'ignore'|'inherit'|(number|'pipe'|'ignore'|'inherit'|'ipc'|Stream|null|undefined)[]|undefined, - environment?: IEnvironment, - keepEnvironment: boolean = false - ): child_process.SpawnSyncReturns { - const options: child_process.SpawnSyncOptions = { - cwd: workingDirectory, - shell: true, - stdio: stdio, - env: keepEnvironment - ? environment - : Utilities._createEnvironmentForRushCommand({ initialEnvironment: environment }) - }; - - // 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 = command.indexOf(' ') < 0 - ? command - : Utilities.escapeShellParameter(command); - - const escapedArgs: string[] = args.map((x) => Utilities.escapeShellParameter(x)); - - let result: child_process.SpawnSyncReturns = child_process.spawnSync(escapedCommand, - escapedArgs, options); - - if (result.error && (result.error as any).errno === 'ENOENT') { // eslint-disable-line @typescript-eslint/no-explicit-any - // This is a workaround for GitHub issue #25330 - // https://github.com/nodejs/node-v0.x-archive/issues/25330 - result = child_process.spawnSync(command + '.cmd', args, options); - } - - Utilities._processResult(result); - return result; - } - - private static _processResult(result: child_process.SpawnSyncReturns): void { - if (result.error) { - result.error.message += os.EOL + (result.stderr ? result.stderr.toString() + os.EOL : ''); - throw result.error; - } - - if (result.status) { - throw new Error('The command failed with exit code ' + result.status + os.EOL + - (result.stderr ? result.stderr.toString() : '')); - } - } -} diff --git a/apps/rush-lib/src/utilities/VersionControl.ts b/apps/rush-lib/src/utilities/VersionControl.ts deleted file mode 100644 index 8b6fb368969..00000000000 --- a/apps/rush-lib/src/utilities/VersionControl.ts +++ /dev/null @@ -1,202 +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 child_process from 'child_process'; -import * as colors from 'colors'; -import { - Executable, - Path -} from '@rushstack/node-core-library'; -import { RushConfiguration } from '../api/RushConfiguration'; - -export class VersionControl { - public static getRepositoryRootPath(): string | undefined { - const output: child_process.SpawnSyncReturns = Executable.spawnSync( - 'git', - ['rev-parse', '--show-toplevel'] - ); - - if (output.status !== 0) { - return undefined; - } else { - return output.stdout.trim(); - } - } - - public static getChangedFolders( - targetBranch: string, - skipFetch: boolean = false - ): (string | undefined)[] | undefined { - if (!skipFetch) { - VersionControl._fetchRemoteBranch(targetBranch); - } - - const output: string = child_process.execSync(`git diff ${targetBranch}... --dirstat=files,0`).toString(); - return output.split('\n').map((line) => { - if (line) { - const delimiterIndex: number = line.indexOf('%'); - if (delimiterIndex > 0 && delimiterIndex + 1 < line.length) { - return line.substring(delimiterIndex + 1).trim(); - } - } - - return undefined; - }); - } - - /** - * @param pathPrefix - An optional path prefix "git diff"s should be filtered by. - * @returns - * An array of paths of repo-root-relative paths of files that are different from - * those in the provided {@param targetBranch}. If a {@param pathPrefix} is provided, - * this function only returns results under the that path. - */ - public static getChangedFiles(targetBranch: string, skipFetch: boolean = false, pathPrefix?: string): string[] { - if (!skipFetch) { - VersionControl._fetchRemoteBranch(targetBranch); - } - - const output: string = child_process.execSync( - `git diff ${targetBranch}... --name-only --no-renames --diff-filter=A` - ).toString(); - return output.split('\n').map((line) => { - if (line) { - const trimmedLine: string = line.trim(); - if (!pathPrefix || Path.isUnderOrEqual(trimmedLine, pathPrefix)) { - return trimmedLine; - } - } else { - return undefined; - } - }).filter((line) => { - return line && line.length > 0; - }) as string[]; - } - - /** - * Gets the remote master branch that maps to the provided repository url. - * This method is used by 'Rush change' to find the default remote branch to compare against. - * If repository url is not provided or if there is no match, returns the default remote - * master branch 'origin/master'. - * If there are more than one matches, returns the first remote's master branch. - * - * @param rushConfiguration - rush configuration - */ - public static getRemoteMasterBranch(rushConfiguration: RushConfiguration): string { - if (rushConfiguration.repositoryUrl) { - const output: string = child_process - .execSync(`git remote`) - .toString(); - const normalizedRepositoryUrl: string = rushConfiguration.repositoryUrl.toUpperCase(); - const matchingRemotes: string[] = output.split('\n').filter((remoteName) => { - if (remoteName) { - const remoteUrl: string = child_process.execSync(`git remote get-url ${remoteName}`) - .toString() - .trim(); - - if (!remoteUrl) { - return false; - } - - const normalizedRemoteUrl: string = remoteUrl.toUpperCase(); - if (normalizedRemoteUrl.toUpperCase() === normalizedRepositoryUrl) { - return true; - } - - // When you copy a URL from the GitHub web site, they append the ".git" file extension to the URL. - // We allow that to be specified in rush.json, even though the file extension gets dropped - // by "git clone". - if (`${normalizedRemoteUrl}.GIT` === normalizedRepositoryUrl) { - return true; - } - } - - return false; - }); - - if (matchingRemotes.length > 0) { - if (matchingRemotes.length > 1) { - console.log( - `More than one git remote matches the repository URL. Using the first remote (${matchingRemotes[0]}).` - ); - } - - return `${matchingRemotes[0]}/${rushConfiguration.repositoryDefaultBranch}`; - } else { - console.log(colors.yellow( - `Unable to find a git remote matching the repository URL (${rushConfiguration.repositoryUrl}). ` + - 'Detected changes are likely to be incorrect.' - )); - - return rushConfiguration.repositoryDefaultFullyQualifiedRemoteBranch; - } - } else { - console.log(colors.yellow( - 'A git remote URL has not been specified in rush.json. Setting the baseline remote URL is recommended.' - )); - return rushConfiguration.repositoryDefaultFullyQualifiedRemoteBranch; - } - } - - public static hasUncommittedChanges(): boolean { - return VersionControl.getUncommittedChanges().length > 0; - } - - /** - * The list of files changed but not committed - */ - public static getUncommittedChanges(): ReadonlyArray { - const changes: string[] = []; - changes.push(...VersionControl._getUntrackedChanges()); - changes.push(...VersionControl._getDiffOnHEAD()); - - return changes.filter(change => { - return change.trim().length > 0; - }); - } - - private static _getUntrackedChanges(): string[] { - const output: string = child_process - .execSync(`git ls-files --exclude-standard --others`) - .toString(); - return output.trim().split('\n'); - } - - private static _getDiffOnHEAD(): string[] { - const output: string = child_process - .execSync(`git diff HEAD --name-only`) - .toString(); - return output.trim().split('\n'); - } - - private static _tryFetchRemoteBranch(remoteBranchName: string): boolean { - const firstSlashIndex: number = remoteBranchName.indexOf('/'); - if (firstSlashIndex === -1) { - throw new Error( - `Unexpected git remote branch format: ${remoteBranchName}. ` + - 'Expected branch to be in the / format.' - ); - } - - const remoteName: string = remoteBranchName.substr(0, firstSlashIndex); - const branchName: string = remoteBranchName.substr(firstSlashIndex + 1); - const spawnResult: child_process.SpawnSyncReturns = Executable.spawnSync( - 'git', - ['fetch', remoteName, branchName], - { - stdio: 'ignore' - } - ); - return spawnResult.status === 0; - } - - private static _fetchRemoteBranch(remoteBranchName: string): void { - console.log(`Checking for updates to ${remoteBranchName}...`); - const fetchResult: boolean = VersionControl._tryFetchRemoteBranch(remoteBranchName); - if (!fetchResult) { - console.log(colors.yellow( - `Error fetching git remote branch ${remoteBranchName}. Detected changed files may be incorrect.` - )); - } - } -} diff --git a/apps/rush-lib/src/utilities/test/Npm.test.ts b/apps/rush-lib/src/utilities/test/Npm.test.ts deleted file mode 100644 index b00e314517f..00000000000 --- a/apps/rush-lib/src/utilities/test/Npm.test.ts +++ /dev/null @@ -1,66 +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 process from 'process'; - -import { Npm } from '../Npm'; -import { Utilities } from '../Utilities'; - -describe('npm', () => { - const packageName: string = '@microsoft/rush-lib-never'; - let stub: jest.SpyInstance; - - beforeEach(() => { - stub = jest.spyOn(Utilities, 'executeCommandAndCaptureOutput'); - }); - - afterEach(() => { - stub.mockReset(); - stub.mockRestore(); - }); - - it('publishedVersions gets versions when package time is available.', () => { - const json: string = `{ - "modified": "2017-03-30T18:37:27.757Z", - "created": "2017-01-03T20:28:10.342Z", - "0.0.0": "2017-01-03T20:28:10.342Z", - "1.4.0": "2017-01-03T21:55:21.249Z", - "1.4.1": "2017-01-09T19:22:00.488Z", - "2.4.0-alpha.1": "2017-03-30T18:37:27.757Z" - }`; - stub.mockImplementationOnce(() => json); - - const versions: string[] = Npm.publishedVersions(packageName, - __dirname, - process.env); - - expect(stub).toHaveBeenCalledWith('npm', `view ${packageName} time --json`.split(' '), - expect.anything(), expect.anything(), expect.anything()); - - expect(versions.length).toEqual(4); - expect(versions).toMatchObject(['0.0.0', '1.4.0', '1.4.1', '2.4.0-alpha.1']); - }); - - it('publishedVersions gets versions when package time is not available', () => { - const json: string = `[ - "0.0.0", - "1.4.0", - "1.4.1", - "2.4.0-alpha.1" - ]`; - stub.mockImplementationOnce(() => ''); - stub.mockImplementationOnce(() => json); - - const versions: string[] = Npm.publishedVersions(packageName, - __dirname, - process.env); - - expect(stub).toHaveBeenCalledWith('npm', `view ${packageName} time --json`.split(' '), - expect.anything(), expect.anything(), expect.anything()); - expect(stub).toHaveBeenCalledWith('npm', `view ${packageName} versions --json`.split(' '), - expect.anything(), expect.anything(), expect.anything()); - - expect(versions.length).toEqual(4); - expect(versions).toMatchObject(['0.0.0', '1.4.0', '1.4.1', '2.4.0-alpha.1']); - }); -}); diff --git a/apps/rush-lib/src/utilities/test/Stopwatch.test.ts b/apps/rush-lib/src/utilities/test/Stopwatch.test.ts deleted file mode 100644 index d370cc6485e..00000000000 --- a/apps/rush-lib/src/utilities/test/Stopwatch.test.ts +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Stopwatch, StopwatchState } from '../Stopwatch'; - -function pseudoTimeMilliseconds(times: number[]): () => number { - return () => times.shift()!; -} - -function pseudoTimeSeconds(times: number[]): () => number { - return pseudoTimeMilliseconds(times.map(time => time * 1000)); -} - -describe('Stopwatch', () => { - it('allows a static invocation as a quick shorthand', (done: jest.DoneCallback) => { - expect(Stopwatch.start().reset().toString()).toEqual('0.00 seconds (stopped)'); - done(); - }); - - it('stopping before starting does nothing', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(); - watch.stop(); - expect(watch.toString()).toEqual('0.00 seconds (stopped)'); - done(); - }); - - it('can\'t start twice', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(); - expect(() => { - watch.start(); - watch.start(); - }).toThrow(); - done(); - }); - - it('reflects the proper state', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(); - expect(watch.state).toEqual(StopwatchState.Stopped); - watch.start(); - expect(watch.state).toEqual(StopwatchState.Started); - watch.stop(); - expect(watch.state).toEqual(StopwatchState.Stopped); - watch.reset(); - expect(watch.state).toEqual(StopwatchState.Stopped); - done(); - }); - - it('gives 0.00 seconds after being reset', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(); - watch.start(); - watch.reset(); - expect(watch.toString()).toEqual('0.00 seconds (stopped)'); - expect(watch.duration).toEqual(0); - done(); - }); - - it('gives 0.00 seconds when not running', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(); - expect(watch.toString()).toEqual('0.00 seconds (stopped)'); - expect(watch.duration).toEqual(0); - done(); - }); - - it('uses the latest time when the clock is not stopped', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); - watch.start(); - expect(watch.toString()).toEqual('1.00 seconds'); - expect(watch.toString()).toEqual('2.00 seconds'); - done(); - }); - - it('uses the stop time when the clock is stopped', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); - watch.start(); - watch.stop(); - expect(watch.toString()).toEqual('1.00 seconds'); - expect(watch.toString()).toEqual('1.00 seconds'); - done(); - }); - - it('gives elapsed seconds when < 1 minute', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2, 3.25])); - watch.start(); - watch.stop(); - expect(watch.toString()).toEqual('1.00 seconds'); - done(); - }); - - it('gives elapsed minutes and seconds when > 1 minute', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 400])); - watch.start(); - watch.stop(); - expect(watch.toString()).toEqual('6 minutes 40.0 seconds'); - done(); - }); - - it('gives elapsed minute and seconds when time >=60 <=119 seconds', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 61.25])); - watch.start(); - watch.stop(); - expect(watch.toString()).toEqual('1 minute 1.3 seconds'); - done(); - }); - - it('uses the latest time when the clock is not stopped', (done: jest.DoneCallback) => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); - watch.start(); - expect(watch.toString()).toEqual('1.00 seconds'); - expect(watch.toString()).toEqual('2.00 seconds'); - done(); - }); - - it('returns duration when the clock is stopped', () => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 61.25])); - watch.start(); - watch.stop(); - expect(watch.duration).toEqual(61.25); - }); - - it('returns duration using the latest time when the clock is not stopped', () => { - const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); - watch.start(); - expect(watch.duration).toEqual(1); - expect(watch.duration).toEqual(2); - }); -}); diff --git a/apps/rush-lib/tsconfig.json b/apps/rush-lib/tsconfig.json deleted file mode 100644 index 76f0d945025..00000000000 --- a/apps/rush-lib/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } -} diff --git a/apps/rush-mcp-server/.npmignore b/apps/rush-mcp-server/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/apps/rush-mcp-server/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/rush-mcp-server/CHANGELOG.json b/apps/rush-mcp-server/CHANGELOG.json new file mode 100644 index 00000000000..6821e17358d --- /dev/null +++ b/apps/rush-mcp-server/CHANGELOG.json @@ -0,0 +1,445 @@ +{ + "name": "@rushstack/mcp-server", + "entries": [ + { + "version": "0.3.7", + "tag": "@rushstack/mcp-server_v0.3.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.3.6", + "tag": "@rushstack/mcp-server_v0.3.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.3.5", + "tag": "@rushstack/mcp-server_v0.3.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/mcp-server_v0.3.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/mcp-server_v0.3.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.3.2", + "tag": "@rushstack/mcp-server_v0.3.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.3.1", + "tag": "@rushstack/mcp-server_v0.3.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.3.0", + "tag": "@rushstack/mcp-server_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/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.2.10", + "tag": "@rushstack/mcp-server_v0.2.10", + "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.2.9", + "tag": "@rushstack/mcp-server_v0.2.9", + "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.2.8", + "tag": "@rushstack/mcp-server_v0.2.8", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/mcp-server_v0.2.7", + "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.2.6", + "tag": "@rushstack/mcp-server_v0.2.6", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/mcp-server_v0.2.5", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/mcp-server_v0.2.4", + "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.2.3", + "tag": "@rushstack/mcp-server_v0.2.3", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/mcp-server_v0.2.2", + "date": "Sat, 14 Jun 2025 00:11:30 GMT", + "comments": { + "patch": [ + { + "comment": "Move the `rush docs` tool to a plugin package `@rushstack/rush-mcp-docs-plugin`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/mcp-server_v0.2.1", + "date": "Fri, 06 Jun 2025 08:20:18 GMT", + "comments": { + "patch": [ + { + "comment": "Fix some errors when loading plugins" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/mcp-server_v0.2.0", + "date": "Fri, 06 Jun 2025 00:11:09 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a plugin system for custom MCP tools" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/mcp-server_v0.1.8", + "date": "Thu, 29 May 2025 15:10:58 GMT", + "comments": { + "patch": [ + { + "comment": "Update the rush mcp server README.md document" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/mcp-server_v0.1.7", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/mcp-server_v0.1.6", + "date": "Wed, 07 May 2025 15:11:17 GMT", + "comments": { + "patch": [ + { + "comment": "Follow-ups to #5215" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/mcp-server_v0.1.5", + "date": "Fri, 02 May 2025 15:11:29 GMT", + "comments": { + "patch": [ + { + "comment": "Add more tools to mcp server" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/mcp-server_v0.1.4", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/mcp-server_v0.1.3", + "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.1.2", + "tag": "@rushstack/mcp-server_v0.1.2", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/mcp-server_v0.1.1", + "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.1.0", + "tag": "@rushstack/mcp-server_v0.1.0", + "date": "Thu, 17 Apr 2025 15:11:16 GMT", + "comments": { + "minor": [ + { + "comment": "Init rush mcp server project" + } + ] + } + } + ] +} diff --git a/apps/rush-mcp-server/CHANGELOG.md b/apps/rush-mcp-server/CHANGELOG.md new file mode 100644 index 00000000000..d98fc56d291 --- /dev/null +++ b/apps/rush-mcp-server/CHANGELOG.md @@ -0,0 +1,160 @@ +# Change Log - @rushstack/mcp-server + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 0.3.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.3.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.3.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.3.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.3.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.3.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 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.10 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.2.9 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.8 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.7 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.6 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.2.5 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.2.4 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.2.3 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.2.2 +Sat, 14 Jun 2025 00:11:30 GMT + +### Patches + +- Move the `rush docs` tool to a plugin package `@rushstack/rush-mcp-docs-plugin` + +## 0.2.1 +Fri, 06 Jun 2025 08:20:18 GMT + +### Patches + +- Fix some errors when loading plugins + +## 0.2.0 +Fri, 06 Jun 2025 00:11:09 GMT + +### Minor changes + +- Introduce a plugin system for custom MCP tools + +## 0.1.8 +Thu, 29 May 2025 15:10:58 GMT + +### Patches + +- Update the rush mcp server README.md document + +## 0.1.7 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.1.6 +Wed, 07 May 2025 15:11:17 GMT + +### Patches + +- Follow-ups to #5215 + +## 0.1.5 +Fri, 02 May 2025 15:11:29 GMT + +### Patches + +- Add more tools to mcp server + +## 0.1.4 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.1.3 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.1.2 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.1 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.1.0 +Thu, 17 Apr 2025 15:11:16 GMT + +### Minor changes + +- Init rush mcp server project + diff --git a/apps/rush-mcp-server/LICENSE b/apps/rush-mcp-server/LICENSE new file mode 100644 index 00000000000..6f51ef8b200 --- /dev/null +++ b/apps/rush-mcp-server/LICENSE @@ -0,0 +1,24 @@ +@rushstack/mcp-server + +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/apps/rush-mcp-server/README.md b/apps/rush-mcp-server/README.md new file mode 100644 index 00000000000..fc0f6f81523 --- /dev/null +++ b/apps/rush-mcp-server/README.md @@ -0,0 +1,37 @@ +# @rushstack/mcp-server + +With the rapid advancement of LLMs, AI applications like Trae, Cursor, Cline, Windsurf, and others have been thriving. However, due to the large scale of monorepos and the context limitations of LLMs, it’s difficult for these models to fully understand your monorepo. This is where @rushstack/mcp-server comes in — by providing a suite of MCP tools, it enables LLMs to better comprehend your monorepo and assist you more effectively with daily development tasks in a Rush-based monorepo environment. + +## Usage + +1. To get the best results, copy the [.cursor](https://github.com/microsoft/rushstack/tree/main/.cursor) directory into the root of your project. + +2. Configure `@rushstack/mcp-server` in your AI application + +``` +{ + "mcpServers": { + "rush": { + "command": "npx", + "args": ["-y", "@rushstack/mcp-server", "your-project-path"] + } + } +} +``` + +3. Congratulations 🎉 You’ve completed the setup — Rush MCP is now ready to use! + +## Available Tools + +- `rush_docs`: Retrieves relevant documentation sections based on your queries +- `rush_workspace_details`: Retrieve detailed workspace information +- `rush_project_details`: Get detailed information about a specific project +- `rush_command_validator`: Validate whether commands are compliant and follow best practices +- `rush_migrate_project`: Migrate a project from one directory to another or into a different subspace +- `rush_pnpm_lock_file_conflict_resolver`: Resolve pnpm-lock.yaml conflicts + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/rush-mcp-server/CHANGELOG.md) - Find + out what's new in the latest version diff --git a/apps/rush-mcp-server/bin/mcp-server b/apps/rush-mcp-server/bin/mcp-server new file mode 100755 index 00000000000..aee68e80224 --- /dev/null +++ b/apps/rush-mcp-server/bin/mcp-server @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js'); diff --git a/apps/rush-lib/config/api-extractor.json b/apps/rush-mcp-server/config/api-extractor.json similarity index 100% rename from apps/rush-lib/config/api-extractor.json rename to apps/rush-mcp-server/config/api-extractor.json diff --git a/apps/rush-mcp-server/config/jest.config.json b/apps/rush-mcp-server/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/rush-mcp-server/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/rush-mcp-server/config/rig.json b/apps/rush-mcp-server/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/rush-mcp-server/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/rush-mcp-server/eslint.config.js b/apps/rush-mcp-server/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/apps/rush-mcp-server/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/rush-mcp-server/package.json b/apps/rush-mcp-server/package.json new file mode 100644 index 00000000000..7e221fc5749 --- /dev/null +++ b/apps/rush-mcp-server/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/mcp-server", + "version": "0.3.7", + "description": "A Model Context Protocol server implementation for Rush", + "keywords": [ + "rush", + "modelcontextprotocol", + "mcp", + "monorepo", + "server" + ], + "main": "lib/index.js", + "typings": "dist/mcp-server.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/rush-mcp-server" + }, + "engines": { + "node": ">=10.0.0" + }, + "engineStrict": true, + "homepage": "https://rushstack.io", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "bin": { + "mcp-server": "./bin/mcp-server" + }, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "@modelcontextprotocol/sdk": "~1.10.2", + "zod": "~3.24.3" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2", + "@types/node": "20.17.19" + } +} diff --git a/apps/rush-mcp-server/src/index.ts b/apps/rush-mcp-server/src/index.ts new file mode 100644 index 00000000000..20b52112e78 --- /dev/null +++ b/apps/rush-mcp-server/src/index.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. + +/** + * API for use by MCP plugins. + * @packageDocumentation + */ + +export * from './pluginFramework/IRushMcpPlugin'; +export * from './pluginFramework/IRushMcpTool'; +export { type IRegisterToolOptions, RushMcpPluginSession } from './pluginFramework/RushMcpPluginSession'; +export * from './pluginFramework/zodTypes'; diff --git a/apps/rush-mcp-server/src/pluginFramework/IRushMcpPlugin.ts b/apps/rush-mcp-server/src/pluginFramework/IRushMcpPlugin.ts new file mode 100644 index 00000000000..0f52c3272c1 --- /dev/null +++ b/apps/rush-mcp-server/src/pluginFramework/IRushMcpPlugin.ts @@ -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. + +import type { RushMcpPluginSession } from './RushMcpPluginSession'; + +/** + * MCP plugins should implement this interface. + * @public + */ +export interface IRushMcpPlugin { + onInitializeAsync(): Promise; +} + +/** + * The plugin's entry point should return this function as its default export. + * @public + */ +export type RushMcpPluginFactory = ( + session: RushMcpPluginSession, + configFile: TConfigFile | undefined +) => IRushMcpPlugin; diff --git a/apps/rush-mcp-server/src/pluginFramework/IRushMcpTool.ts b/apps/rush-mcp-server/src/pluginFramework/IRushMcpTool.ts new file mode 100644 index 00000000000..46f325b0273 --- /dev/null +++ b/apps/rush-mcp-server/src/pluginFramework/IRushMcpTool.ts @@ -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. + +import type * as zod from 'zod'; + +import type { CallToolResult } from './zodTypes'; + +/** + * MCP plugins should implement this interface. + * @public + */ +export interface IRushMcpTool< + TSchema extends zod.ZodObject = zod.ZodObject +> { + readonly schema: TSchema; + executeAsync(input: zod.infer): Promise; +} diff --git a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.ts new file mode 100644 index 00000000000..33603216342 --- /dev/null +++ b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginLoader.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 path from 'node:path'; + +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; + +import { FileSystem, Import, JsonFile, type JsonObject, JsonSchema } from '@rushstack/node-core-library'; +import { Autoinstaller } from '@rushstack/rush-sdk/lib/logic/Autoinstaller'; +import { RushGlobalFolder } from '@rushstack/rush-sdk/lib/api/RushGlobalFolder'; +import { RushConfiguration } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; + +import type { IRushMcpPlugin, RushMcpPluginFactory } from './IRushMcpPlugin'; +import { RushMcpPluginSessionInternal } from './RushMcpPluginSession'; +import rushMcpJsonSchemaObject from '../schemas/rush-mcp.schema.json'; +import rushMcpPluginSchemaObject from '../schemas/rush-mcp-plugin.schema.json'; + +/** + * Configuration for @rushstack/mcp-server in a monorepo. + * Corresponds to the contents of common/config/rush-mcp/rush-mcp.json + */ +export interface IJsonRushMcpConfig { + /** + * The list of plugins that @rushstack/mcp-server should load when processing this monorepo. + */ + mcpPlugins: IJsonRushMcpPlugin[]; +} + +/** + * Describes a single MCP plugin entry. + */ +export interface IJsonRushMcpPlugin { + /** + * The name of an NPM package that appears in the package.json "dependencies" for the autoinstaller. + */ + packageName: string; + + /** + * The name of a Rush autoinstaller with this package as its dependency. + * @rushstack/mcp-server will ensure this folder is installed before loading the plugin. + */ + autoinstaller: string; +} + +/** + * Manifest file for a Rush MCP plugin. + * Every plugin package must contain a "rush-mcp-plugin.json" manifest in the top-level folder. + */ +export interface IJsonRushMcpPluginManifest { + /** + * A name that uniquely identifies your plugin. + * Generally this should match the NPM package name; two plugins with the same pluginName cannot be loaded together. + */ + pluginName: string; + + /** + * Optional. Indicates that your plugin accepts a config file. + * The MCP server will load this schema file and provide it to the plugin. + * Path is typically `/common/config/rush-mcp/.json`. + */ + configFileSchema?: string; + + /** + * The module path to the plugin's entry point. + * Its default export must be a class implementing the MCP plugin interface. + */ + entryPoint: string; +} + +export class RushMcpPluginLoader { + private static readonly _rushMcpJsonSchema: JsonSchema = + JsonSchema.fromLoadedObject(rushMcpJsonSchemaObject); + private static readonly _rushMcpPluginSchemaObject: JsonSchema = + JsonSchema.fromLoadedObject(rushMcpPluginSchemaObject); + + private readonly _rushWorkspacePath: string; + private readonly _mcpServer: McpServer; + + public constructor(rushWorkspacePath: string, mcpServer: McpServer) { + this._rushWorkspacePath = rushWorkspacePath; + this._mcpServer = mcpServer; + } + + private static _formatError(e: Error): string { + return e.stack ?? RushMcpPluginLoader._formatError(e); + } + + public async loadAsync(): Promise { + const rushMcpFilePath: string = path.join( + this._rushWorkspacePath, + 'common/config/rush-mcp/rush-mcp.json' + ); + + if (!(await FileSystem.existsAsync(rushMcpFilePath))) { + return; + } + + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ + startingFolder: this._rushWorkspacePath + }); + + const jsonRushMcpConfig: IJsonRushMcpConfig = await JsonFile.loadAndValidateAsync( + rushMcpFilePath, + RushMcpPluginLoader._rushMcpJsonSchema + ); + + if (jsonRushMcpConfig.mcpPlugins.length === 0) { + return; + } + + const rushGlobalFolder: RushGlobalFolder = new RushGlobalFolder(); + + for (const jsonMcpPlugin of jsonRushMcpConfig.mcpPlugins) { + // Ensure the autoinstaller is installed + const autoinstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName: jsonMcpPlugin.autoinstaller, + rushConfiguration, + rushGlobalFolder, + restrictConsoleOutput: false + }); + await autoinstaller.prepareAsync(); + + // Load the manifest + + // Suppose the autoinstaller is "my-autoinstaller" and the package is "rush-mcp-example-plugin". + // Then the folder will be: + // "/path/to/my-repo/common/autoinstallers/my-autoinstaller/node_modules/rush-mcp-example-plugin" + const installedPluginPackageFolder: string = await Import.resolvePackageAsync({ + baseFolderPath: autoinstaller.folderFullPath, + packageName: jsonMcpPlugin.packageName + }); + + const manifestFilePath: string = path.join(installedPluginPackageFolder, 'rush-mcp-plugin.json'); + if (!(await FileSystem.existsAsync(manifestFilePath))) { + throw new Error( + 'The "rush-mcp-plugin.json" manifest file was not found under ' + installedPluginPackageFolder + ); + } + + const jsonManifest: IJsonRushMcpPluginManifest = await JsonFile.loadAndValidateAsync( + manifestFilePath, + RushMcpPluginLoader._rushMcpPluginSchemaObject + ); + + let rushMcpPluginOptions: JsonObject = {}; + if (jsonManifest.configFileSchema) { + const mcpPluginSchemaFilePath: string = path.resolve( + installedPluginPackageFolder, + jsonManifest.configFileSchema + ); + const mcpPluginSchema: JsonSchema = await JsonSchema.fromFile(mcpPluginSchemaFilePath); + const rushMcpPluginOptionsFilePath: string = path.resolve( + this._rushWorkspacePath, + `common/config/rush-mcp/${jsonManifest.pluginName}.json` + ); + // Example: /path/to/my-repo/common/config/rush-mcp/rush-mcp-example-plugin.json + rushMcpPluginOptions = await JsonFile.loadAndValidateAsync( + rushMcpPluginOptionsFilePath, + mcpPluginSchema + ); + } + + const fullEntryPointPath: string = path.join(installedPluginPackageFolder, jsonManifest.entryPoint); + let pluginFactory: RushMcpPluginFactory; + try { + const entryPointModule: { default?: RushMcpPluginFactory } = require(fullEntryPointPath); + if (entryPointModule.default === undefined) { + throw new Error('The commonJS "default" export is missing'); + } + pluginFactory = entryPointModule.default; + } catch (e) { + throw new Error( + `Unable to load plugin entry point at ${fullEntryPointPath}:\n` + + RushMcpPluginLoader._formatError(e) + ); + } + + const session: RushMcpPluginSessionInternal = new RushMcpPluginSessionInternal(this._mcpServer); + + let plugin: IRushMcpPlugin; + try { + plugin = pluginFactory(session, rushMcpPluginOptions); + } catch (e) { + throw new Error( + `Error invoking entry point for plugin ${jsonManifest.pluginName}:\n` + + RushMcpPluginLoader._formatError(e) + ); + } + + try { + await plugin.onInitializeAsync(); + } catch (e) { + throw new Error( + `Error occurred in onInitializeAsync() for plugin ${jsonManifest.pluginName}:\n` + + RushMcpPluginLoader._formatError(e) + ); + } + } + } +} diff --git a/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts new file mode 100644 index 00000000000..aa46003a8cf --- /dev/null +++ b/apps/rush-mcp-server/src/pluginFramework/RushMcpPluginSession.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as zod from 'zod'; +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; + +import type { IRushMcpTool } from './IRushMcpTool'; +import type { zodModule } from './zodTypes'; + +/** + * Each plugin gets its own session. + * + * @public + */ +export interface IRegisterToolOptions { + toolName: string; + description?: string; +} + +/** + * Each plugin gets its own session. + * + * @public + */ +export abstract class RushMcpPluginSession { + public readonly zod: typeof zodModule = zod; + public abstract registerTool(options: IRegisterToolOptions, tool: IRushMcpTool): void; +} + +export class RushMcpPluginSessionInternal extends RushMcpPluginSession { + private readonly _mcpServer: McpServer; + + public constructor(mcpServer: McpServer) { + super(); + this._mcpServer = mcpServer; + } + + public override registerTool(options: IRegisterToolOptions, tool: IRushMcpTool): void { + if (options.description) { + this._mcpServer.tool( + options.toolName, + options.description, + tool.schema.shape, + tool.executeAsync.bind(tool) + ); + } else { + this._mcpServer.tool(options.toolName, tool.schema.shape, tool.executeAsync.bind(tool)); + } + } +} diff --git a/apps/rush-mcp-server/src/pluginFramework/zodTypes.ts b/apps/rush-mcp-server/src/pluginFramework/zodTypes.ts new file mode 100644 index 00000000000..80dbfa01a51 --- /dev/null +++ b/apps/rush-mcp-server/src/pluginFramework/zodTypes.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. + +import type * as zod from 'zod'; +import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types'; + +export type { zod as zodModule }; +export { CallToolResultSchema }; + +/** + * @public + */ +export type CallToolResult = zod.infer; diff --git a/apps/rush-mcp-server/src/schemas/rush-mcp-plugin.schema.json b/apps/rush-mcp-server/src/schemas/rush-mcp-plugin.schema.json new file mode 100644 index 00000000000..e8e8757d9f1 --- /dev/null +++ b/apps/rush-mcp-server/src/schemas/rush-mcp-plugin.schema.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Rush MCP Plugin Manifest", + "type": "object", + "properties": { + "pluginName": { + "type": "string", + "description": "A name that uniquely identifies your plugin. Generally this should match the NPM package name; two plugins with the same pluginName cannot be loaded together." + }, + "configFileSchema": { + "type": "string", + "description": "Optional. Indicates that your plugin accepts a config file. The MCP server will load this schema file and provide it to the plugin. Path is typically `/common/config/rush-mcp/.json`." + }, + "entryPoint": { + "type": "string", + "description": "The module path to the plugin's entry point. Its default export must be a class implementing the MCP plugin interface." + } + }, + "required": ["pluginName", "entryPoint"], + "additionalProperties": false +} diff --git a/apps/rush-mcp-server/src/schemas/rush-mcp.schema.json b/apps/rush-mcp-server/src/schemas/rush-mcp.schema.json new file mode 100644 index 00000000000..0dd9a9546fe --- /dev/null +++ b/apps/rush-mcp-server/src/schemas/rush-mcp.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "rush-mcp.json Configuration Schema", + "type": "object", + "properties": { + "mcpPlugins": { + "type": "array", + "description": "The list of plugins that `@rushstack/mcp-server` should load when processing this monorepo.", + "items": { + "type": "object", + "properties": { + "packageName": { + "type": "string", + "description": "The name of an NPM package that appears in the package.json \"dependencies\" for the autoinstaller." + }, + "autoinstaller": { + "type": "string", + "description": "The name of a Rush autoinstaller with this package as its dependency." + } + }, + "required": ["packageName", "autoinstaller"], + "additionalProperties": false + } + } + }, + "required": ["mcpPlugins"], + "additionalProperties": false +} diff --git a/apps/rush-mcp-server/src/server.ts b/apps/rush-mcp-server/src/server.ts new file mode 100644 index 00000000000..5eceb116012 --- /dev/null +++ b/apps/rush-mcp-server/src/server.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 { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; + +import { + type BaseTool, + RushConflictResolverTool, + RushMigrateProjectTool, + RushCommandValidatorTool, + RushWorkspaceDetailsTool, + RushProjectDetailsTool +} from './tools'; +import { RushMcpPluginLoader } from './pluginFramework/RushMcpPluginLoader'; + +export class RushMCPServer extends McpServer { + private _rushWorkspacePath: string; + private _tools: BaseTool[] = []; + private _pluginLoader: RushMcpPluginLoader; + + public constructor(rushWorkspacePath: string) { + super({ + name: 'rush', + version: '1.0.0' + }); + + this._rushWorkspacePath = rushWorkspacePath; + this._pluginLoader = new RushMcpPluginLoader(this._rushWorkspacePath, this); + } + + public async startAsync(): Promise { + this._initializeTools(); + this._registerTools(); + + await this._pluginLoader.loadAsync(); + } + + private _initializeTools(): void { + this._tools.push(new RushConflictResolverTool()); + this._tools.push(new RushMigrateProjectTool(this._rushWorkspacePath)); + this._tools.push(new RushCommandValidatorTool()); + this._tools.push(new RushWorkspaceDetailsTool()); + this._tools.push(new RushProjectDetailsTool()); + } + + private _registerTools(): void { + process.chdir(this._rushWorkspacePath); + + for (const tool of this._tools) { + tool.register(this); + } + } +} diff --git a/apps/rush-mcp-server/src/start.ts b/apps/rush-mcp-server/src/start.ts new file mode 100644 index 00000000000..7c191e15582 --- /dev/null +++ b/apps/rush-mcp-server/src/start.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 * as path from 'node:path'; +import * as process from 'node:process'; + +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; + +import { FileSystem } from '@rushstack/node-core-library'; +import { RushSdkLoader } from '@rushstack/rush-sdk/loader'; + +import { log } from './utilities/log'; +import type { RushMCPServer } from './server'; + +const main = async (): Promise => { + const rushWorkspacePath: string | undefined = process.argv[2]; + if (!rushWorkspacePath) { + throw new Error('Please provide workspace root path as the first argument'); + } + + const rushWorkspaceFullPath: string = path.resolve(rushWorkspacePath); + + if (!(await FileSystem.existsAsync(rushWorkspaceFullPath))) { + throw new Error( + 'The specified workspace root path does not exist:\n ' + JSON.stringify(rushWorkspacePath) + ); + } + + // Load rush-sdk from the specified repository + await RushSdkLoader.loadAsync({ + rushJsonSearchFolder: rushWorkspaceFullPath + }); + + const RushMCPServerClass: typeof RushMCPServer = (await import('./server')).RushMCPServer; + + const server: RushMCPServer = new RushMCPServerClass(rushWorkspaceFullPath); + await server.startAsync(); + const transport: StdioServerTransport = new StdioServerTransport(); + await server.connect(transport); + + log('Rush MCP Server running on stdio'); +}; + +main().catch((error) => { + log('Fatal error running server:', error instanceof Error ? error.message : error); + process.exit(1); +}); diff --git a/apps/rush-mcp-server/src/tools/base.tool.ts b/apps/rush-mcp-server/src/tools/base.tool.ts new file mode 100644 index 00000000000..dc9b4d67bdb --- /dev/null +++ b/apps/rush-mcp-server/src/tools/base.tool.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol'; +import type { + CallToolResultSchema, + ServerNotification, + ServerRequest +} from '@modelcontextprotocol/sdk/types'; +import type { z, ZodRawShape, ZodTypeAny } from 'zod'; + +export type CallToolResult = z.infer; + +type ToolCallback = Args extends ZodRawShape + ? ( + args: z.objectOutputType, + extra: RequestHandlerExtra + ) => CallToolResult | Promise + : ( + extra: RequestHandlerExtra + ) => CallToolResult | Promise; + +export interface IBaseToolOptions { + name: string; + description: string; + schema: Args; +} + +export abstract class BaseTool { + private _options: IBaseToolOptions; + + protected constructor(options: IBaseToolOptions) { + this._options = options; + } + + protected abstract executeAsync(...args: Parameters>): ReturnType>; + + public register(server: McpServer): void { + // TODO: remove ts-ignore + // @ts-ignore + server.tool(this._options.name, this._options.description, this._options.schema, async (...args) => { + try { + const result: CallToolResult = await this.executeAsync(...(args as Parameters>)); + return result; + } catch (error: unknown) { + return { + isError: true, + content: [ + { + type: 'text', + text: error instanceof Error ? error.message : error + } + ] + }; + } + }); + } +} diff --git a/apps/rush-mcp-server/src/tools/conflict-resolver.tool.ts b/apps/rush-mcp-server/src/tools/conflict-resolver.tool.ts new file mode 100644 index 00000000000..3c9a085b9f4 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/conflict-resolver.tool.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. + +import { z } from 'zod'; + +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { IExecutableSpawnSyncOptions } from '@rushstack/node-core-library'; + +import { CommandRunner } from '../utilities/command-runner'; +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushConflictResolverTool extends BaseTool { + public constructor() { + super({ + name: 'rush_pnpm_lock_file_conflict_resolver', + description: + 'If a user requests to resolve a pnpm-lock.yaml file conflict, use this tool to automatically fix the conflict directly.', + schema: { + lockfilePath: z.string().describe('The path to the pnpm-lock.yaml file, should pass absolute path') + } + }); + } + + private _tryGetSubspaceNameFromLockfilePath( + lockfilePath: string, + rushConfiguration: RushConfiguration + ): string | null { + for (const subspace of rushConfiguration.subspaces) { + const folderPath: string = subspace.getSubspaceConfigFolderPath(); + if (lockfilePath.startsWith(folderPath)) { + return subspace.subspaceName; + } + } + return null; + } + + public async executeAsync({ lockfilePath }: { lockfilePath: string }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const subspaceName: string | null = this._tryGetSubspaceNameFromLockfilePath( + lockfilePath, + rushConfiguration + ); + if (!subspaceName) { + throw new Error('subspace name not found'); + } + + const options: IExecutableSpawnSyncOptions = { + stdio: 'inherit', + currentWorkingDirectory: rushConfiguration.rushJsonFolder + }; + await CommandRunner.runGitCommandAsync(['checkout', '--theirs', lockfilePath], options); + await CommandRunner.runRushCommandAsync(['update', '--subspace', subspaceName], options); + + return { + content: [ + { + type: 'text', + text: 'Conflict resolved successfully' + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/index.ts b/apps/rush-mcp-server/src/tools/index.ts new file mode 100644 index 00000000000..b0c15c01eee --- /dev/null +++ b/apps/rush-mcp-server/src/tools/index.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. + +export * from './base.tool'; +export * from './migrate-project.tool'; +export * from './project-details.tool'; +export * from './rush-command-validator.tool'; +export * from './workspace-details'; +export * from './conflict-resolver.tool'; diff --git a/apps/rush-mcp-server/src/tools/migrate-project.tool.ts b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts new file mode 100644 index 00000000000..d4069a1d79c --- /dev/null +++ b/apps/rush-mcp-server/src/tools/migrate-project.tool.ts @@ -0,0 +1,136 @@ +// 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 { z } from 'zod'; + +import { FileSystem, JsonFile } from '@rushstack/node-core-library'; +import type { ISubspacesConfigurationJson } from '@rushstack/rush-sdk/lib/api/SubspacesConfiguration'; +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import type { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; +import type { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; + +import { BaseTool, type CallToolResult } from './base.tool'; +import { getRushConfiguration } from '../utilities/common'; + +export class RushMigrateProjectTool extends BaseTool { + private _rushWorkspacePath: string; + + public constructor(rushWorkspacePath: string) { + super({ + name: 'rush_migrate_project', + description: 'Migrate a project to a different location or subspace within the Rush monorepo.', + schema: { + projectName: z.string().describe('The name of the project to be migrated'), + targetProjectPath: z.string().optional().describe('The target path to migrate the project to'), + targetSubspaceName: z.string().optional().describe('The target subspace to migrate the project to') + } + }); + + this._rushWorkspacePath = rushWorkspacePath; + } + + private async _modifyAndSaveSubspaceJsonFileAsync( + rushConfiguration: RushConfiguration, + cb: (subspaceNames: string[]) => Promise | string[] + ): Promise { + const subspacesFolderPath: string = path.resolve( + rushConfiguration.commonRushConfigFolder, + 'subspaces.json' + ); + const subspacesConfiguration: ISubspacesConfigurationJson = await JsonFile.loadAsync(subspacesFolderPath); + const newSubspaceNames: string[] = await cb(subspacesConfiguration.subspaceNames); + subspacesConfiguration.subspaceNames = newSubspaceNames; + await JsonFile.saveAsync(subspacesConfiguration, subspacesFolderPath, { + updateExistingFile: true + }); + } + + private async _modifyAndSaveRushConfigurationAsync( + rushConfiguration: RushConfiguration, + cb: ( + projects: IRushConfigurationProjectJson[] + ) => Promise | IRushConfigurationProjectJson[] + ): Promise { + const rushConfigurationJson: IRushConfigurationJson = rushConfiguration.rushConfigurationJson; + const rushConfigurationFile: string = rushConfiguration.rushJsonFile; + const newRushConfigurationProjectJson: IRushConfigurationProjectJson[] = await cb( + rushConfigurationJson.projects + ); + rushConfigurationJson.projects = newRushConfigurationProjectJson; + await JsonFile.saveAsync(rushConfigurationJson, rushConfigurationFile, { updateExistingFile: true }); + } + + public async executeAsync({ + projectName, + targetSubspaceName, + targetProjectPath + }: { + projectName: string; + targetProjectPath: string; + targetSubspaceName: string; + }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const project: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); + + if (!project) { + return { + isError: true, + content: [{ type: 'text', text: `Project "${projectName}" not found` }] + }; + } + + const rootPath: string = this._rushWorkspacePath; + const sourceProjectSubspaceName: string = project.subspace.subspaceName; + const sourceProjectPath: string = project.projectFolder; + const destinationPath: string = path.resolve(rootPath, targetProjectPath); + const subspacehasOnlyOneProject: boolean = project.subspace.getProjects().length === 1; + + // 1. Remove source subspace folder + if (subspacehasOnlyOneProject) { + const subspaceConfigFolderPath: string = project.subspace.getSubspaceConfigFolderPath(); + await FileSystem.deleteFolderAsync(subspaceConfigFolderPath); + } + + // 2. Move project to target subspace + await FileSystem.moveAsync({ + sourcePath: sourceProjectPath, + destinationPath + }); + + // 3. Update rush configuration + await this._modifyAndSaveRushConfigurationAsync(rushConfiguration, (projects) => { + const projectIndex: number = projects.findIndex(({ packageName }) => packageName === projectName); + projects[projectIndex] = { + ...projects[projectIndex], + subspaceName: targetSubspaceName, + projectFolder: path.relative(rootPath, destinationPath) + }; + return projects; + }); + + // 4. Update `subspaces.json` + await this._modifyAndSaveSubspaceJsonFileAsync(rushConfiguration, (subspaceNames) => { + if (subspacehasOnlyOneProject) { + subspaceNames.splice(subspaceNames.indexOf(sourceProjectSubspaceName), 1); + } + if (!subspaceNames.includes(targetSubspaceName)) { + subspaceNames.push(targetSubspaceName); + } + return subspaceNames; + }); + + return { + content: [ + { + type: 'text', + text: + `Project "${projectName}" migrated to subspace "${targetSubspaceName}" successfully. ` + + `You can ask whether the user wants to run "rush update --subspace ${targetSubspaceName}" to update the project. ` + + `If the user says "yes", you can run "rush update --subspace ${targetSubspaceName}" directly for them.` + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/project-details.tool.ts b/apps/rush-mcp-server/src/tools/project-details.tool.ts new file mode 100644 index 00000000000..b78227398df --- /dev/null +++ b/apps/rush-mcp-server/src/tools/project-details.tool.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 { z } from 'zod'; + +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushProjectDetailsTool extends BaseTool { + public constructor() { + super({ + name: 'rush_project_details', + description: 'Returns the complete project details in JSON format for a given rush project.', + schema: { + projectName: z.string().describe('The name of the project to get details for') + } + }); + } + + public async executeAsync({ projectName }: { projectName: string }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const project: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); + + if (!project) { + throw new Error(`Project ${projectName} not found`); + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify( + { + packageJson: project.packageJson, + /** + * Example: `C:\MyRepo\libraries\my-project` + */ + projectFolder: project.projectFolder, + /** + * Example: `libraries/my-project` + */ + projectRelativeFolder: project.projectRelativeFolder, + /** + * Example: `C:\MyRepo\libraries\my-project\config\rush` + */ + projectRushConfigFolder: project.projectRushConfigFolder, + /** + * Example: `my-subspace` + */ + projectSubspaceName: project.subspace.subspaceName + }, + null, + 2 + ) + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts b/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts new file mode 100644 index 00000000000..196f5570d33 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/rush-command-validator.tool.ts @@ -0,0 +1,115 @@ +// 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 { z } from 'zod'; + +import { JsonFile } from '@rushstack/node-core-library'; +import type { ICommandLineJson } from '@rushstack/rush-sdk/lib/api/CommandLineJson'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export const selectionParamsSet: ReadonlySet = new Set([ + '-t', + '--to', + '--to-except', + '-T', + '--from', + '-f', + '--only', + '-o', + '--impacted-by', + '-i', + '--impacted-by-except', + '-I' +]); + +export class RushCommandValidatorTool extends BaseTool { + public constructor() { + super({ + name: 'rush_command_validator', + description: + 'Validates Rush commands before execution by checking command format and ensuring compliance with Rush command standards. This tool helps prevent invalid command usage and provides guidance on proper parameter selection.', + schema: { + commandName: z.enum(['rush', 'rushx']).describe('The main command to execute (rush or rushx)'), + subCommandName: z + .string() + .describe( + 'The Rush subcommand to validate (install, update, add, remove, purge, list, build, etc.)' + ), + args: z.array(z.string()).describe('The arguments to validate for the subcommand') + } + }); + } + + public async executeAsync({ + commandName, + subCommandName, + args + }: { + commandName: string; + subCommandName: string; + args: string[]; + }): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const commandLineJson: ICommandLineJson = await JsonFile.loadAsync( + path.resolve(rushConfiguration.commonFolder, 'config', 'rush', 'command-line.json') + ); + const conditionSubCommandNames: Set = new Set( + commandLineJson.commands + ?.filter((command) => command.commandKind !== 'global') + .map((command) => command.name) + ); + + if (conditionSubCommandNames.has(subCommandName) && !args.some((arg) => selectionParamsSet.has(arg))) { + return { + isError: true, + content: [ + { + type: 'text', + text: `Please add selection parameters like ${Array.from(selectionParamsSet).join( + ', ' + )} to the command and re-validate. The package name should be retrieved from the package.json file in your project folder.` + } + ] + }; + } + + for (const [index, arg] of args.entries()) { + if (selectionParamsSet.has(arg)) { + const packageName: string = args[index + 1]; + const isValidPackage: boolean = + packageName === '.' || rushConfiguration.projects.some((p) => p.packageName === packageName); + + if (!isValidPackage) { + return { + isError: true, + content: [ + { + type: 'text', + text: `The package "${packageName}" does not exist in the Rush workspace. You can retrieve the package name from the 'package.json' file in the project folder.` + } + ] + }; + } + } + } + + const commandStr: string = `${commandName} ${subCommandName} ${args.join(' ')}`; + const text: string = `Command "${commandStr}" validated successfully, you can ${ + commandName === 'rushx' || subCommandName === 'add' ? 'enter the project folder and ' : '' + }execute it now.`; + + return { + content: [ + { + type: 'text', + text + } + ] + }; + } +} diff --git a/apps/rush-mcp-server/src/tools/workspace-details.ts b/apps/rush-mcp-server/src/tools/workspace-details.ts new file mode 100644 index 00000000000..da93f38abb7 --- /dev/null +++ b/apps/rush-mcp-server/src/tools/workspace-details.ts @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import type { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; + +import { getRushConfiguration } from '../utilities/common'; +import { BaseTool, type CallToolResult } from './base.tool'; + +export class RushWorkspaceDetailsTool extends BaseTool { + public constructor() { + super({ + name: 'rush_workspace_details', + description: + 'Retrieves a comprehensive overview of the Rush monorepo project graph in an LLM-friendly format. Use it to answer questions about the current Rush workspace and architecture.', + schema: {} + }); + } + + public async executeAsync(): Promise { + const rushConfiguration: RushConfiguration = await getRushConfiguration(); + const projects: RushConfigurationProject[] = rushConfiguration.projects; + + return { + content: [ + { + type: 'text', + text: this._getWorkspaceDetailsPrompt(rushConfiguration, projects) + } + ] + }; + } + + private _getWorkspaceDetailsPrompt( + rushConfiguration: RushConfiguration, + projects: RushConfigurationProject[] + ): string { + return ` +The following is a comprehensive representation of the Rush monorepo workspace. The information is organized into two sections: + +1. WORKSPACE LEVEL: Contains global configuration information about the Rush workspace itself. +2. PROJECT LEVEL: Lists all projects in the monorepo with their detailed information. + +WORKSPACE LEVEL information includes Rush version, pnpm version, and overall project count. + +PROJECT LEVEL information is separated by tags. Each project contains: +- its direct workspace dependencies package names, marked by "deps: [...]" +- its package name, marked by "packageName: [...]" +- its project type/category, marked by "projectType: [...]" +- its source file location, marked by "projectFolder: [...]" +- its scripts/commands, marked by "scripts: [...]" +- its version, marked by "version: [...]" +- additional metadata if available + +This data is very important. Use it to analyze the workspace and understand the project graph. The user cannot see this data, so don't reference it directly. It is read-only information to help you understand the workspace. + +${this._getRobotReadableWorkspaceDetails(rushConfiguration.rushConfigurationJson, projects)} +`.trim(); + } + + private _getRobotReadableWorkspaceDetails( + rushConfiguration: IRushConfigurationJson, + projects: RushConfigurationProject[] + ): string { + let serializedWorkspace: string = ''; + + // Add workspace-level information with clearer section marking + serializedWorkspace += `======== WORKSPACE LEVEL INFORMATION ========\n`; + serializedWorkspace += `\n`; + serializedWorkspace += ` rushVersion: [${rushConfiguration.rushVersion}]\n`; + serializedWorkspace += ` pnpmVersion: [${rushConfiguration.pnpmVersion}]\n`; + serializedWorkspace += ` projectCount: [${projects.length}]\n`; + serializedWorkspace += `\n\n`; + serializedWorkspace += `======== PROJECT LEVEL INFORMATION ========\n`; + + projects.forEach((project) => { + serializedWorkspace += `<${project.packageName}>\n`; + + serializedWorkspace += ` packageName: [${project.packageName}]\n`; + serializedWorkspace += ` version: [${project.packageJson.version}]\n`; + serializedWorkspace += ` projectFolder: [${project.projectFolder}]\n`; + serializedWorkspace += ` subspaceName: [${project.subspace.subspaceName}]\n`; + + const projectType: string = project.shouldPublish ? 'publishable' : 'local'; + serializedWorkspace += ` projectType: [${projectType}]\n`; + + const dependencies: ReadonlySet = project.dependencyProjects; + const depNames: string[] = Array.from(dependencies, (dep) => dep.packageName); + + if (depNames.length === 0) { + serializedWorkspace += ` deps: []\n`; + } else if (depNames.length <= 5) { + serializedWorkspace += ` deps: [${depNames.join(', ')}]\n`; + } else { + serializedWorkspace += ` deps: [\n ${depNames.join(',\n ')}\n ]\n`; + } + + if (project.packageJson.scripts) { + const scripts: string[] = Object.keys(project.packageJson.scripts); + if (scripts.length === 0) { + serializedWorkspace += ` scripts: []\n`; + } else if (scripts.length <= 5) { + serializedWorkspace += ` scripts: [${scripts.join(', ')}]\n`; + } else { + serializedWorkspace += ` scripts: [\n ${scripts.join(',\n ')}\n ]\n`; + } + } else { + serializedWorkspace += ` scripts: []\n`; + } + + if (project.versionPolicyName) { + serializedWorkspace += ` versionPolicy: [${project.versionPolicyName}]\n`; + } + + if (project.reviewCategory) { + serializedWorkspace += ` reviewCategory: [${project.reviewCategory}]\n`; + } + + serializedWorkspace += `\n\n`; + }); + + return serializedWorkspace; + } +} diff --git a/apps/rush-mcp-server/src/utilities/command-runner.ts b/apps/rush-mcp-server/src/utilities/command-runner.ts new file mode 100644 index 00000000000..d94424757cb --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/command-runner.ts @@ -0,0 +1,107 @@ +// 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, type IExecutableSpawnSyncOptions } from '@rushstack/node-core-library'; + +interface ICommandResult { + status: number; + stdout: string; + stderr: string; + command: string; + args: string[]; +} + +export class CommandExecutionError extends Error { + public constructor(command: string, args: string[], stderr: string, status: number) { + super(`Command "${command} ${args.join(' ')}" failed with status ${status}:\n${stderr}`); + this.name = 'CommandExecutionError'; + } +} + +export class CommandRunner { + private static readonly _commandCache: Map = new Map(); + + private static _resolveCommand(command: string): string { + const cachedPath: string | null | undefined = this._commandCache.get(command); + if (cachedPath === null) { + throw new Error(`Command "${command}" not found in system PATH`); + } + + if (cachedPath) { + return cachedPath; + } + + const resolvedPath: string | null = Executable.tryResolve(command) ?? null; + this._commandCache.set(command, resolvedPath); + + if (!resolvedPath) { + throw new Error(`Command "${command}" not found in system PATH`); + } + + return resolvedPath; + } + + private static async _executeCommandAsync( + command: string, + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + const commandPath: string = this._resolveCommand(command); + + return new Promise((resolve, reject) => { + const childProcess: ChildProcess = Executable.spawn(commandPath, args, options); + let stdout: string = ''; + let stderr: string = ''; + + childProcess.stdout?.on('data', (data) => { + stdout += data.toString(); + }); + + childProcess.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + + childProcess.on('close', (status) => { + if (status !== 0) { + reject(new CommandExecutionError(command, args, stderr, status ?? 1)); + return; + } + + resolve({ + status: status ?? 0, + stdout, + stderr, + command, + args + }); + }); + + childProcess.on('error', (error) => { + reject(error); + }); + }); + } + + public static async runRushCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('rush', args, options); + } + + public static async runRushXCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('rushx', args, options); + } + + public static async runGitCommandAsync( + args: string[], + options?: IExecutableSpawnSyncOptions + ): Promise { + return this._executeCommandAsync('git', args, options); + } +} diff --git a/apps/rush-mcp-server/src/utilities/common.ts b/apps/rush-mcp-server/src/utilities/common.ts new file mode 100644 index 00000000000..7478d6a5281 --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/common.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. + +import type { RushConfiguration } from '@rushstack/rush-sdk'; + +export const getRushConfiguration = async (): Promise => { + // Since the MCP server is not always started from the directory of the Rush monorepo, + // it’s necessary to use dynamic import to load the Rush SDK. + const Rush: typeof import('@rushstack/rush-sdk') = await import('@rushstack/rush-sdk'); + const rushConfiguration: RushConfiguration = Rush.RushConfiguration.loadFromDefaultLocation(); + return rushConfiguration; +}; diff --git a/apps/rush-mcp-server/src/utilities/log.ts b/apps/rush-mcp-server/src/utilities/log.ts new file mode 100644 index 00000000000..c0595baec77 --- /dev/null +++ b/apps/rush-mcp-server/src/utilities/log.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 { Terminal, ConsoleTerminalProvider, type TerminalWriteParameters } from '@rushstack/terminal'; + +export const terminal: Terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); + +export function log(...messageParts: TerminalWriteParameters): void { + terminal.writeErrorLine(...messageParts); +} diff --git a/apps/rush-mcp-server/tsconfig.json b/apps/rush-mcp-server/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/rush-mcp-server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/rush/.eslintrc.js b/apps/rush/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/apps/rush/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/apps/rush/.npmignore b/apps/rush/.npmignore index e2cbe1efa92..0a36afe312c 100644 --- a/apps/rush/.npmignore +++ b/apps/rush/.npmignore @@ -1,24 +1,35 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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. +# --------------------------------------------------------------------------- +/lib/start-dev.* +/lib/start-dev-docs.* -# (Add your exceptions here) \ No newline at end of file diff --git a/apps/rush/CHANGELOG.json b/apps/rush/CHANGELOG.json index 33d49b5f900..fa2e0e7d1a7 100644 --- a/apps/rush/CHANGELOG.json +++ b/apps/rush/CHANGELOG.json @@ -1,6 +1,5388 @@ { "name": "@microsoft/rush", "entries": [ + { + "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", + "date": "Thu, 12 Dec 2024 01:37:25 GMT", + "comments": { + "none": [ + { + "comment": "Add a new experiment flag `enableSubpathScan` that, when invoking phased script commands with project selection parameters, such as `--to` or `--from`, only hashes files that are needed to compute the cache ids for the selected projects." + } + ] + } + }, + { + "version": "5.146.0", + "tag": "@microsoft/rush_v5.146.0", + "date": "Tue, 10 Dec 2024 21:23:18 GMT", + "comments": { + "none": [ + { + "comment": "Support fallback syntax in `.npmrc` files if the package manager is PNPM. See https://pnpm.io/npmrc" + }, + { + "comment": "Add an `.isPnpm` property to `RushConfiguration` that is set to true if the package manager for the Rush repo is PNPM." + }, + { + "comment": "Support pnpm lockfile v9, which is used by default starting in pnpm v9." + } + ] + } + }, + { + "version": "5.145.0", + "tag": "@microsoft/rush_v5.145.0", + "date": "Tue, 10 Dec 2024 05:14:11 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade `@azure/identity` and `@azure/storage-blob`." + }, + { + "comment": "Add support for Node 22." + }, + { + "comment": "Remove the dependency on node-fetch." + } + ] + } + }, + { + "version": "5.144.1", + "tag": "@microsoft/rush_v5.144.1", + "date": "Mon, 09 Dec 2024 20:32:01 GMT", + "comments": { + "none": [ + { + "comment": "Bump `jsonpath-plus` to `~10.2.0`." + } + ] + } + }, + { + "version": "5.144.0", + "tag": "@microsoft/rush_v5.144.0", + "date": "Wed, 04 Dec 2024 19:32:23 GMT", + "comments": { + "none": [ + { + "comment": "Remove the `node-fetch` dependency from `@rushstack/rush-http-build-cache-plugin`." + } + ] + } + }, + { + "version": "5.143.0", + "tag": "@microsoft/rush_v5.143.0", + "date": "Wed, 04 Dec 2024 03:07:08 GMT", + "comments": { + "none": [ + { + "comment": "Remove the `node-fetch` dependency from @rushstack/rush-amazon-s3-build-cache-plugin." + }, + { + "comment": "(BREAKING API CHANGE) Remove the exported `WebClient` API from @rushstack/rush-amazon-s3-build-cache-plugin." + } + ] + } + }, + { + "version": "5.142.0", + "tag": "@microsoft/rush_v5.142.0", + "date": "Tue, 03 Dec 2024 23:42:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the ability to skip `rush install` may be incorrectly calculated when using the variants feature." + }, + { + "comment": "Add support for an `\"extends\"` property in the `common/config/rush/pnpm-config.json` and `common/config/subspace/*/pnpm-config.json` files." + }, + { + "comment": "Add warning when the `globalIgnoredOptionalDependencies` property is specified in `common/config/rush/pnpm-config.json` and the repo is configured to use pnpm <9.0.0." + } + ] + } + }, + { + "version": "5.141.4", + "tag": "@microsoft/rush_v5.141.4", + "date": "Mon, 02 Dec 2024 20:40:41 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush sometimes incorrectly reported \"fatal: could not open 'packages/xxx/.rush/temp/shrinkwrap-deps.json' for reading: No such file or directory\" when using subspaces" + } + ] + } + }, + { + "version": "5.141.3", + "tag": "@microsoft/rush_v5.141.3", + "date": "Wed, 27 Nov 2024 07:16:50 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush sometimes incorrectly reported \"The overrides settings doesn't match the current shrinkwrap\" when using subspaces" + }, + { + "comment": "Fix an issue where Rush sometimes incorrectly reported \"The package extension hash doesn't match the current shrinkwrap.\" when using subspaces" + } + ] + } + }, + { + "version": "5.141.2", + "tag": "@microsoft/rush_v5.141.2", + "date": "Wed, 27 Nov 2024 03:27:26 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where filtered installs neglected to install dependencies from other subspaces" + } + ] + } + }, + { + "version": "5.141.1", + "tag": "@microsoft/rush_v5.141.1", + "date": "Wed, 20 Nov 2024 00:24:34 GMT", + "comments": { + "none": [ + { + "comment": "Update schema for build-cache.json to include recent updates to the @rushstack/rush-azure-storage-build-cache-plugin." + } + ] + } + }, + { + "version": "5.141.0", + "tag": "@microsoft/rush_v5.141.0", + "date": "Tue, 19 Nov 2024 06:38:33 GMT", + "comments": { + "none": [ + { + "comment": "Adds two new properties to the configuration for `rush-azure-storage-build-cache-plugin`: `loginFlow` selects the flow to use for interactive authentication to Entra ID, and `readRequiresAuthentication` specifies that a SAS token is required for read and therefore expired authentication is always fatal." + }, + { + "comment": "Adds a new `wasExecutedOnThisMachine` property to operation telemetry events, to simplify reporting about cobuilt operations." + }, + { + "comment": "Fix an issue where empty error logs were created for operations that did not write to standard error." + }, + { + "comment": "Fix an issue where incremental building (with LegacySkipPlugin) would not work when no-op operations were present in the process" + }, + { + "comment": "Fix lack of \"local-only\" option for cacheProvider in build-cache.schema.json" + }, + { + "comment": "Fix an issue where if an Operation wrote all logs to stdout, then exited with a non-zero exit code, only the non-zero exit code would show up in the summary." + } + ] + } + }, + { + "version": "5.140.1", + "tag": "@microsoft/rush_v5.140.1", + "date": "Wed, 30 Oct 2024 21:50:51 GMT", + "comments": { + "none": [ + { + "comment": "Update the `jsonpath-plus` indirect dependency to mitigate CVE-2024-21534." + } + ] + } + }, + { + "version": "5.140.0", + "tag": "@microsoft/rush_v5.140.0", + "date": "Tue, 22 Oct 2024 23:59:54 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue when using `rush deploy` where the `node_modules/.bin` folder symlinks were not created for deployed packages when using the \"default\" link creation mode" + }, + { + "comment": "Add support for the `globalIgnoredOptionalDependencies` field in the `common/config/rush/pnpm-config.json` file to allow specifying optional dependencies that should be ignored by PNPM" + } + ] + } + }, + { + "version": "5.139.0", + "tag": "@microsoft/rush_v5.139.0", + "date": "Thu, 17 Oct 2024 20:37:39 GMT", + "comments": { + "none": [ + { + "comment": "Allow rush plugins to extend build cache entries by writing additional files to the metadata folder. Expose the metadata folder path to plugins." + }, + { + "comment": "[CACHE BREAK] Alter the computation of build cache IDs to depend on the graph of operations in the build and therefore account for multiple phases, rather than only the declared dependencies. Ensure that `dependsOnEnvVars` and command line parameters that affect upstream phases impact the cache IDs of downstream operations." + }, + { + "comment": "(BREAKING CHANGE) Replace use of `ProjectChangeAnalyzer` in phased command hooks with a new `InputsSnapshot` data structure that is completely synchronous and does not perform any disk operations. Perform all disk operations and state computation prior to executing the build graph." + }, + { + "comment": "Add a new property `enabled` to `Operation` that when set to false, will cause the execution engine to immediately return `OperationStatus.Skipped` instead of invoking the runner. Use this property to disable operations that are not intended to be executed in the current pass, e.g. those that did not contain changes in the most recent watch iteration, or those excluded by `--only`." + }, + { + "comment": "Add an optional property `cacheHashSalt` to `build-cache.json` to allow repository maintainers to globally force a hash change in build cache entries." + } + ] + } + }, + { + "version": "5.138.0", + "tag": "@microsoft/rush_v5.138.0", + "date": "Thu, 03 Oct 2024 22:31:07 GMT", + "comments": { + "none": [ + { + "comment": "Changes the behavior of phased commands in watch mode to, when running a phase `_phase:` in all iterations after the first, prefer a script entry named `_phase::incremental` if such a script exists. The build cache will expect the outputs from the corresponding `_phase:` script (with otherwise the same inputs) to be equivalent when looking for a cache hit." + } + ] + } + }, + { + "version": "5.137.0", + "tag": "@microsoft/rush_v5.137.0", + "date": "Thu, 03 Oct 2024 19:46:40 GMT", + "comments": { + "patch": [ + { + "comment": "Expose `getChangesByProject` to allow classes that extend ProjectChangeAnalyzer to override file change analysis" + } + ] + } + }, + { + "version": "5.136.1", + "tag": "@microsoft/rush_v5.136.1", + "date": "Thu, 26 Sep 2024 22:59:11 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the `--variant` parameter was missing from a phased command when the command's `alwaysInstall` property was set to `true`." + } + ] + } + }, + { + "version": "5.136.0", + "tag": "@microsoft/rush_v5.136.0", + "date": "Thu, 26 Sep 2024 21:48:00 GMT", + "comments": { + "none": [ + { + "comment": "Bring back the Variants feature that was removed in https://github.com/microsoft/rushstack/pull/4538." + }, + { + "comment": "Bump express dependency to 4.20.0" + } + ] + } + }, + { + "version": "5.135.0", + "tag": "@microsoft/rush_v5.135.0", + "date": "Fri, 20 Sep 2024 20:23:40 GMT", + "comments": { + "none": [ + { + "comment": "Fix a bug that caused rush-resolver-cache-plugin to crash on Windows." + }, + { + "comment": "Make individual Rush log files available via the rush-serve-plugin server at the relative URL specified by \"logServePath\" option. Annotate operations sent over the WebSocket with the URLs of their log files." + }, + { + "comment": "Adds a new experiment 'allowCobuildWithoutCache' for cobuilds to allow uncacheable operations to benefit from cobuild orchestration without using the build cache." + }, + { + "comment": "Deprecate the `sharding.shardOperationSettings` property in the project `config/rush-project.json` in favor of an `operationSettings` entry for an operation with a suffix of `:shard`." + } + ] + } + }, + { + "version": "5.134.0", + "tag": "@microsoft/rush_v5.134.0", + "date": "Fri, 13 Sep 2024 01:02:46 GMT", + "comments": { + "none": [ + { + "comment": "Always update shrinkwrap when `globalPackageExtensions` in `common/config/rush/pnpm-config.json` has been changed." + }, + { + "comment": "Pass the initialized credentials cache to `AzureAuthenticationBase._getCredentialFromTokenAsync` in `@rushstack/rush-azure-storage-build-cache-plugin`." + }, + { + "comment": "Support the `rush-pnpm patch-remove` command." + } + ] + } + }, + { + "version": "5.133.4", + "tag": "@microsoft/rush_v5.133.4", + "date": "Sat, 07 Sep 2024 00:18:08 GMT", + "comments": { + "none": [ + { + "comment": "Mark `AzureAuthenticationBase._credentialCacheId` as protected in `@rushstack/rush-azure-storage-build-cache-plugin`." + } + ] + } + }, + { + "version": "5.133.3", + "tag": "@microsoft/rush_v5.133.3", + "date": "Thu, 29 Aug 2024 22:49:36 GMT", + "comments": { + "none": [ + { + "comment": "Fix Windows compatibility for `@rushstack/rush-resolver-cache-plugin`." + } + ] + } + }, + { + "version": "5.133.2", + "tag": "@microsoft/rush_v5.133.2", + "date": "Wed, 28 Aug 2024 20:46:32 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where running `rush install --resolution-only` followed by `rush install` would not actually install modules." + } + ] + } + }, + { + "version": "5.133.1", + "tag": "@microsoft/rush_v5.133.1", + "date": "Wed, 28 Aug 2024 18:19:55 GMT", + "comments": { + "none": [ + { + "comment": "In rush-resolver-cache-plugin, include the base path in the resolver cache file." + }, + { + "comment": "Support `bundledDependencies` in rush-resolver-cache-plugin." + } + ] + } + }, + { + "version": "5.133.0", + "tag": "@microsoft/rush_v5.133.0", + "date": "Fri, 23 Aug 2024 00:40:08 GMT", + "comments": { + "none": [ + { + "comment": "Always update shrinkwrap when globalOverrides has been changed" + }, + { + "comment": "Add `afterInstall` plugin hook, which runs after any install finishes." + }, + { + "comment": "Add rush.json option \"suppressRushIsPublicVersionCheck\" to allow suppressing hardcoded calls to the npmjs.org registry." + } + ] + } + }, + { + "version": "5.132.0", + "tag": "@microsoft/rush_v5.132.0", + "date": "Wed, 21 Aug 2024 16:25:07 GMT", + "comments": { + "none": [ + { + "comment": "Add a new `rush install-autoinstaller` command that ensures that the specified autoinstaller is installed." + }, + { + "comment": "Emit an error if a `workspace:` specifier is used in a dependency that is listed in `decoupledLocalDependencies`." + }, + { + "comment": "Add support for `--resolution-only` to `rush install` to enforce strict peer dependency resolution." + } + ] + } + }, + { + "version": "5.131.5", + "tag": "@microsoft/rush_v5.131.5", + "date": "Mon, 19 Aug 2024 20:03:03 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where PreferredVersions are ignored when a project contains an overlapping dependency entry (https://github.com/microsoft/rushstack/issues/3205)" + } + ] + } + }, + { + "version": "5.131.4", + "tag": "@microsoft/rush_v5.131.4", + "date": "Sun, 11 Aug 2024 05:02:05 GMT", + "comments": { + "none": [ + { + "comment": "Revert a breaking change in Rush 5.131.3 where pnpm patches were moved from `common/pnpm-patches` to `common/config/rush/pnpm-patches`." + } + ] + } + }, + { + "version": "5.131.3", + "tag": "@microsoft/rush_v5.131.3", + "date": "Sat, 10 Aug 2024 02:27:14 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush-pnpm patch-commit` would not correctly resolve patch files when the subspaces feature is enabled." + } + ] + } + }, + { + "version": "5.131.2", + "tag": "@microsoft/rush_v5.131.2", + "date": "Thu, 08 Aug 2024 23:38:18 GMT", + "comments": { + "none": [ + { + "comment": "Include a missing dependency in `@rushstack/rush-sdk`." + } + ] + } + }, + { + "version": "5.131.1", + "tag": "@microsoft/rush_v5.131.1", + "date": "Thu, 08 Aug 2024 22:08:41 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where rush-sdk can't be bundled by a consuming package." + }, + { + "comment": "Extract LookupByPath to @rushstack/lookup-by-path and load it from there." + } + ] + } + }, + { + "version": "5.131.0", + "tag": "@microsoft/rush_v5.131.0", + "date": "Fri, 02 Aug 2024 17:26:59 GMT", + "comments": { + "none": [ + { + "comment": "Improve Rush alerts with a new \"rush alert\" command and snooze feature" + } + ] + } + }, + { + "version": "5.130.3", + "tag": "@microsoft/rush_v5.130.3", + "date": "Wed, 31 Jul 2024 23:30:13 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush does not detect an outdated lockfile if the `dependenciesMeta` `package.json` field is edited." + }, + { + "comment": "Include CHANGELOG.md in published releases again" + }, + { + "comment": "Fix a bug that caused the build cache to close its terminal writer before execution on error." + } + ] + } + }, + { + "version": "5.130.2", + "tag": "@microsoft/rush_v5.130.2", + "date": "Fri, 19 Jul 2024 03:41:44 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush-pnpm patch-commit` did not work correctly when subspaces are enabled." + } + ] + } + }, + { + "version": "5.130.1", + "tag": "@microsoft/rush_v5.130.1", + "date": "Wed, 17 Jul 2024 07:37:13 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent regression for `rush init`" + } + ] + } + }, + { + "version": "5.130.0", + "tag": "@microsoft/rush_v5.130.0", + "date": "Wed, 17 Jul 2024 06:55:27 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Initial implementation of Rush alerts feature" + }, + { + "comment": "Adjusts how cobuilt operations are added and requeued to the operation graph. Removes the 'RemoteExecuting' status." + } + ] + } + }, + { + "version": "5.129.7", + "tag": "@microsoft/rush_v5.129.7", + "date": "Tue, 16 Jul 2024 04:16:56 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade pnpm-sync-lib to fix an edge case when handling node_modules folder" + }, + { + "comment": "Don't interrupt the installation process if the user hasn't enabled the inject dependencies feature." + }, + { + "comment": "Improve `@rushtack/rush-sdk` and make it reuse `@microsoft/rush-lib` from rush global folder" + }, + { + "comment": "Remove the trailing slash in the `.DS_Store/` line in the `.gitignore` file generated by `rush init`. `.DS_Store` is a file, not a folder." + }, + { + "comment": "Support deep references to internal Apis" + }, + { + "comment": "Fix an issue where `rush add` would ignore the `ensureConsistentVersions` option if that option was set in `rush.json` instead of in `common/config/rush/common-versions.json`." + }, + { + "comment": "Fix an issue where running `rush add` in a project can generate a `package.json` file that uses JSON5 syntax. Package managers expect strict JSON." + }, + { + "comment": "fix spelling of \"committing\" in rush.json init template and schema" + } + ] + } + }, + { + "version": "5.129.6", + "tag": "@microsoft/rush_v5.129.6", + "date": "Thu, 27 Jun 2024 00:44:32 GMT", + "comments": { + "none": [ + { + "comment": "Fix an edge case for workspace peer dependencies when calculating packageJsonInjectedDependenciesHash to improve its accuracy " + }, + { + "comment": "Update a URL in the `.pnpmfile.cjs` generated by `rush init`." + } + ] + } + }, + { + "version": "5.129.5", + "tag": "@microsoft/rush_v5.129.5", + "date": "Tue, 25 Jun 2024 20:13:29 GMT", + "comments": { + "none": [ + { + "comment": "Don't include package.json version field when calculating packageJsonInjectedDependenciesHash" + } + ] + } + }, + { + "version": "5.129.4", + "tag": "@microsoft/rush_v5.129.4", + "date": "Mon, 24 Jun 2024 23:49:10 GMT", + "comments": { + "none": [ + { + "comment": "Normalize the file permissions (644) for Rush plugin files that are committed to Git" + } + ] + } + }, + { + "version": "5.129.3", + "tag": "@microsoft/rush_v5.129.3", + "date": "Fri, 21 Jun 2024 00:15:54 GMT", + "comments": { + "none": [ + { + "comment": "Fixed an issue where DependencyAnalyzer caches the same analysis for all subspaces" + } + ] + } + }, + { + "version": "5.129.2", + "tag": "@microsoft/rush_v5.129.2", + "date": "Wed, 19 Jun 2024 23:59:09 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the `rush pnpm ...` command always terminates with an exit code of 1." + } + ] + } + }, + { + "version": "5.129.1", + "tag": "@microsoft/rush_v5.129.1", + "date": "Wed, 19 Jun 2024 04:20:03 GMT", + "comments": { + "none": [ + { + "comment": "Add logic to remove outdated .pnpm-sync.json files during rush install or update" + } + ] + } + }, + { + "version": "5.129.0", + "tag": "@microsoft/rush_v5.129.0", + "date": "Wed, 19 Jun 2024 03:31:48 GMT", + "comments": { + "none": [ + { + "comment": "Add a new `init-subspace` command to initialize a new subspace." + }, + { + "comment": "Move the `ensureConsistentVersions` setting from `rush.json` to `common/config/rush/common-versions.json`, or to `common/config/rush//common-versions.json` if subspaces are enabled." + } + ] + } + }, + { + "version": "5.128.5", + "tag": "@microsoft/rush_v5.128.5", + "date": "Tue, 18 Jun 2024 04:02:54 GMT", + "comments": { + "none": [ + { + "comment": "Fix a key collision for cobuild clustering for operations that share the same phase name." + } + ] + } + }, + { + "version": "5.128.4", + "tag": "@microsoft/rush_v5.128.4", + "date": "Mon, 17 Jun 2024 23:22:49 GMT", + "comments": { + "none": [ + { + "comment": "Bump the `@azure/identity` package to `~4.2.1` to mitigate GHSA-m5vv-6r4h-3vj9." + } + ] + } + }, + { + "version": "5.128.3", + "tag": "@microsoft/rush_v5.128.3", + "date": "Mon, 17 Jun 2024 20:46:21 GMT", + "comments": { + "none": [ + { + "comment": "Fixed an issue where the --make-consistent flag would affect projects outside the current subspace." + } + ] + } + }, + { + "version": "5.128.2", + "tag": "@microsoft/rush_v5.128.2", + "date": "Mon, 17 Jun 2024 17:08:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where rush-pnpm patch is not working for the subspace scenario" + }, + { + "comment": "Fix an issue where rush update can not detect package.json changes in other subspaces for the injected installation case" + } + ] + } + }, + { + "version": "5.128.1", + "tag": "@microsoft/rush_v5.128.1", + "date": "Wed, 12 Jun 2024 20:07:44 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where running `rush install` in a subspace with only a `--from` selector is treated as selecting all projects." + }, + { + "comment": "Fix an issue where not published packages are not correctly identified as not published when querying a package feed under certain versions of NPM." + }, + { + "comment": "Fix an issue where selection syntax (like `--to` or `--from`) misses project dependencies declared using workspace alias syntax (i.e. - `workspace:alias@1.2.3`)." + }, + { + "comment": "Fix an issue where an error is thrown if a Git email address isn't configured and email validation isn't configured in `rush.json` via `allowedEmailRegExps`." + }, + { + "comment": "Display the name of the subspace when an error is emitted because a dependency hash uses the SHA1 algorithm and the \"disallowInsecureSha1\" option is enabled." + } + ] + } + }, + { + "version": "5.128.0", + "tag": "@microsoft/rush_v5.128.0", + "date": "Fri, 07 Jun 2024 22:59:12 GMT", + "comments": { + "none": [ + { + "comment": "Graduate the `phasedCommands` experiment to a standard feature." + }, + { + "comment": "Improve `rush init` template for `.gitignore`" + }, + { + "comment": "Remove an unnecessary condition in the logic for skipping operations when build cache is disabled." + } + ] + } + }, + { + "version": "5.127.1", + "tag": "@microsoft/rush_v5.127.1", + "date": "Thu, 06 Jun 2024 03:05:21 GMT", + "comments": { + "none": [ + { + "comment": "Remove the second instance of the project name from the project operation filenames in `/rush-logs`. This restores the log filenames to their format before Rush 5.125.0." + } + ] + } + }, + { + "version": "5.127.0", + "tag": "@microsoft/rush_v5.127.0", + "date": "Tue, 04 Jun 2024 00:44:18 GMT", + "comments": { + "none": [ + { + "comment": "Fixes build cache no-op and sharded operation clustering." + }, + { + "comment": "Updated common-veresions.json schema with ensureConsistentVersions property" + } + ] + } + }, + { + "version": "5.126.0", + "tag": "@microsoft/rush_v5.126.0", + "date": "Mon, 03 Jun 2024 02:49:05 GMT", + "comments": { + "none": [ + { + "comment": "Fixes a string schema validation warning message when running `rush deploy`." + }, + { + "comment": "Update the functionality that runs external lifecycle processes to be async." + }, + { + "comment": "Move logs into the project `rush-logs` folder regardless of whether or not the `\"phasedCommands\"` experiment is enabled." + }, + { + "comment": "Update the `nodeSupportedVersionRange` in the `rush init` template to the LTS and current Node versions." + }, + { + "comment": "Update the `pnpmVersion` in the `rush init` template to the latest version of pnpm 8." + }, + { + "comment": "Update the `.gitignore` in the `rush init` template to include some common toolchain output files and folders." + }, + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ] + } + }, + { + "version": "5.125.1", + "tag": "@microsoft/rush_v5.125.1", + "date": "Wed, 29 May 2024 05:39:54 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where if `missingScriptBehavior` is set to `\"error\"` and a script is present and empty, an error would be thrown." + } + ] + } + }, + { + "version": "5.125.0", + "tag": "@microsoft/rush_v5.125.0", + "date": "Sat, 25 May 2024 05:12:20 GMT", + "comments": { + "none": [ + { + "comment": "Fixes a bug where no-op operations were treated as having build cache disabled." + }, + { + "comment": "Adds support for sharding operations during task execution." + }, + { + "comment": "Fix an issue where warnings and errors were not shown in the build summary for all cobuild agents." + }, + { + "comment": "Add a `rush check --subspace` parameter to specify which subspace to analyze" + }, + { + "comment": "Rename the subspace level lockfile from `.pnpmfile-subspace.cjs` to `.pnpmfile.cjs`. This is a breaking change for the experimental feature." + } + ] + } + }, + { + "version": "5.124.7", + "tag": "@microsoft/rush_v5.124.7", + "date": "Thu, 23 May 2024 02:27:13 GMT", + "comments": { + "none": [ + { + "comment": "Improve the `usePnpmSyncForInjectedDependencies` experiment to also include any dependency whose lockfile entry has the `file:` protocol, unless it is a tarball reference" + }, + { + "comment": "Fix an issue where the build cache analysis was incorrect in rare situations due to a race condition (GitHub #4711)" + } + ] + } + }, + { + "version": "5.124.6", + "tag": "@microsoft/rush_v5.124.6", + "date": "Thu, 16 May 2024 01:12:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix an edge case for pnpm-sync when the .pnpm folder is absent but still a valid installation." + } + ] + } + }, + { + "version": "5.124.5", + "tag": "@microsoft/rush_v5.124.5", + "date": "Wed, 15 May 2024 23:43:15 GMT", + "comments": { + "none": [ + { + "comment": "Fix count of completed operations when silent operations are blocked. Add explicit message for child processes terminated by signals. Ensure that errors show up in summarized view." + }, + { + "comment": "Ensure that errors thrown in afterExecuteOperation show up in the summary at the end of the build." + } + ] + } + }, + { + "version": "5.124.4", + "tag": "@microsoft/rush_v5.124.4", + "date": "Wed, 15 May 2024 03:05:57 GMT", + "comments": { + "none": [ + { + "comment": "Improve the detection of PNPM lockfile versions." + }, + { + "comment": "Fix an issue where the `--subspace` CLI parameter would install for all subspaces in a monorepo when passed to the install or update action" + } + ] + } + }, + { + "version": "5.124.3", + "tag": "@microsoft/rush_v5.124.3", + "date": "Wed, 15 May 2024 01:18:25 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush install` and `rush update` will fail with an `ENAMETOOLONG` error on Windows in repos with a large number of projects." + }, + { + "comment": "Fix an issue where installing multiple subspaces consecutively can cause unexpected cross-contamination between pnpmfiles." + } + ], + "patch": [ + { + "comment": "Ensure async telemetry tasks are flushed by error reporter" + } + ] + } + }, + { + "version": "5.124.2", + "tag": "@microsoft/rush_v5.124.2", + "date": "Fri, 10 May 2024 06:35:26 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent regression where `rush deploy` did not correctly apply the `additionalProjectsToInclude` setting (GitHub #4683)" + } + ] + } + }, + { + "version": "5.124.1", + "tag": "@microsoft/rush_v5.124.1", + "date": "Fri, 10 May 2024 05:33:51 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the `disallowInsecureSha1` policy failed to parse certain lockfile entries" + }, + { + "comment": "Fix some minor issues with the \"rush init\" template files" + }, + { + "comment": "Report an error if subspacesFeatureEnabled=true without useWorkspaces=true" + }, + { + "comment": "Fix an issue where operation weights were not respected." + } + ] + } + }, + { + "version": "5.124.0", + "tag": "@microsoft/rush_v5.124.0", + "date": "Wed, 08 May 2024 22:24:08 GMT", + "comments": { + "none": [ + { + "comment": "Add a new setting `alwaysInjectDependenciesFromOtherSubspaces` in pnpm-config.json" + }, + { + "comment": "Fix a issue where rush install/update can not detect pnpm-sync.json is out of date" + }, + { + "comment": "Improve the error message when the pnpm-sync version is outdated" + }, + { + "comment": "Fixes a bug where cobuilds would cause a GC error when waiting for long periods of time." + }, + { + "comment": "Fix an issue where tab competions did not suggest parameter values." + } + ] + } + }, + { + "version": "5.123.1", + "tag": "@microsoft/rush_v5.123.1", + "date": "Tue, 07 May 2024 22:38:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent regression where \"rush install\" would sometimes incorrectly determine whether to skip the install" + } + ] + } + }, + { + "version": "5.123.0", + "tag": "@microsoft/rush_v5.123.0", + "date": "Tue, 07 May 2024 18:32:36 GMT", + "comments": { + "none": [ + { + "comment": "Provide the file path if there is an error parsing a `package.json` file." + }, + { + "comment": "Timeline view will now only show terminal build statuses as cobuilt, all other statuses will reflect their original icons." + }, + { + "comment": "Add a `\"weight\"` property to the `\"operation\"` object in the project `config/rush-project.json` file that defines an integer weight for how much of the allowed parallelism the operation uses." + }, + { + "comment": "Optimize skipping of unnecessary installs when using filters such as \"rush install --to x\"" + } + ] + } + }, + { + "version": "5.122.1", + "tag": "@microsoft/rush_v5.122.1", + "date": "Tue, 30 Apr 2024 23:36:50 GMT", + "comments": { + "none": [ + { + "comment": "Make `disallowInsecureSha1` policy a subspace-level configuration." + }, + { + "comment": "Fix an issue where `rush update` sometimes did not detect changes to pnpm-config.json" + } + ] + } + }, + { + "version": "5.122.0", + "tag": "@microsoft/rush_v5.122.0", + "date": "Thu, 25 Apr 2024 07:33:18 GMT", + "comments": { + "none": [ + { + "comment": "Support rush-pnpm for subspace feature" + }, + { + "comment": "Skip determining merge base if given git hash" + }, + { + "comment": "(BREAKING CHANGE) Improve the `disallowInsecureSha1` policy to support exemptions for certain package versions. This is a breaking change for the `disallowInsecureSha1` field in pnpm-config.json since Rush 5.119.0." + } + ] + } + }, + { + "version": "5.121.0", + "tag": "@microsoft/rush_v5.121.0", + "date": "Mon, 22 Apr 2024 19:11:26 GMT", + "comments": { + "none": [ + { + "comment": "Add support for auth via microsoft/ado-codespaces-auth vscode extension in `@rushstack/rush-azure-storage-build-cache-plugin`" + } + ] + } + }, + { + "version": "5.120.6", + "tag": "@microsoft/rush_v5.120.6", + "date": "Thu, 18 Apr 2024 23:20:02 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush deploy\" did not correctly deploy build outputs combining multiple Rush subspaces" + } + ] + } + }, + { + "version": "5.120.5", + "tag": "@microsoft/rush_v5.120.5", + "date": "Wed, 17 Apr 2024 21:58:17 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where rush add affects all packages in a subspace" + } + ] + } + }, + { + "version": "5.120.4", + "tag": "@microsoft/rush_v5.120.4", + "date": "Tue, 16 Apr 2024 20:04:25 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush deploy` sometimes used an incorrect temp folder when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.120.3", + "tag": "@microsoft/rush_v5.120.3", + "date": "Tue, 16 Apr 2024 02:59:48 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `pnpm-sync copy` was skipped when a build is restored from build cache." + }, + { + "comment": "Upgrade `tar` dependency to 6.2.1" + } + ] + } + }, + { + "version": "5.120.2", + "tag": "@microsoft/rush_v5.120.2", + "date": "Mon, 15 Apr 2024 00:25:04 GMT", + "comments": { + "none": [ + { + "comment": "Fixes an issue where rush install fails in monorepos with subspaces enabled" + } + ] + } + }, + { + "version": "5.120.1", + "tag": "@microsoft/rush_v5.120.1", + "date": "Sat, 13 Apr 2024 18:31:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where install-run-rush.js sometimes incorrectly invoked .cmd files on Windows OS due to a recent Node.js behavior change." + }, + { + "comment": "Fix an issue with the skip install logic when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.120.0", + "tag": "@microsoft/rush_v5.120.0", + "date": "Wed, 10 Apr 2024 21:59:57 GMT", + "comments": { + "none": [ + { + "comment": "Bump express." + }, + { + "comment": "Add support for `optionalDependencies` in transitive injected install in the Subspaces feature." + }, + { + "comment": "Update dependency: pnpm-sync-lib@0.2.2" + }, + { + "comment": "Remove a restriction where the repo root would not be found if the CWD is >10 directory levels deep." + }, + { + "comment": "Improve the error message that is printed in a repo using PNPM workspaces when a non-`workspace:` version is used for a project inside the repo." + }, + { + "comment": "Include a missing space in a logging message printed when running `rush add`." + }, + { + "comment": "Clarify the copyright notice emitted in common/scripts/*.js" + }, + { + "comment": "Fix an issue with loading of implicitly preferred versions when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.119.0", + "tag": "@microsoft/rush_v5.119.0", + "date": "Sat, 30 Mar 2024 04:32:31 GMT", + "comments": { + "none": [ + { + "comment": "Add a policy to forbid sha1 hashes in pnpm-lock.yaml." + }, + { + "comment": "(BREAKING API CHANGE) Refactor phased action execution to analyze the repo after the initial operations are created. This removes the `projectChangeAnalyzer` property from the context parameter passed to the `createOperations` hook." + } + ] + } + }, + { + "version": "5.118.7", + "tag": "@microsoft/rush_v5.118.7", + "date": "Thu, 28 Mar 2024 19:55:27 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where in the previous release, built-in plugins were not included." + } + ] + } + }, + { + "version": "5.118.6", + "tag": "@microsoft/rush_v5.118.6", + "date": "Wed, 27 Mar 2024 05:31:17 GMT", + "comments": { + "none": [ + { + "comment": "Symlinks are now generated for workspace projects in the temp folder when subspaces and splitWorkspaceCompatibility is enabled." + } + ] + } + }, + { + "version": "5.118.5", + "tag": "@microsoft/rush_v5.118.5", + "date": "Tue, 26 Mar 2024 19:58:40 GMT", + "comments": { + "none": [ + { + "comment": "Use pnpm-sync-lib logging APIs to customize the log message for pnpm-sync operations" + } + ] + } + }, + { + "version": "5.118.4", + "tag": "@microsoft/rush_v5.118.4", + "date": "Tue, 26 Mar 2024 02:39:06 GMT", + "comments": { + "none": [ + { + "comment": "Added warnings if there are .npmrc or .pnpmfile.cjs files in project folders after migrating to subspaces" + } + ] + } + }, + { + "version": "5.118.3", + "tag": "@microsoft/rush_v5.118.3", + "date": "Sat, 23 Mar 2024 01:41:10 GMT", + "comments": { + "none": [ + { + "comment": "Fix an edge case for computing the PNPM store path when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.118.2", + "tag": "@microsoft/rush_v5.118.2", + "date": "Fri, 22 Mar 2024 17:30:47 GMT", + "comments": { + "none": [ + { + "comment": "Fix bugs related to path operation in Windows OS for subspace feature" + } + ] + } + }, + { + "version": "5.118.1", + "tag": "@microsoft/rush_v5.118.1", + "date": "Thu, 21 Mar 2024 16:39:32 GMT", + "comments": { + "none": [ + { + "comment": "Support PNPM injected installation in Rush subspace feature" + } + ] + } + }, + { + "version": "5.118.0", + "tag": "@microsoft/rush_v5.118.0", + "date": "Wed, 20 Mar 2024 20:45:18 GMT", + "comments": { + "none": [ + { + "comment": "(BREAKING API CHANGE) Rename `AzureAuthenticationBase._getCredentialFromDeviceCodeAsync` to `AzureAuthenticationBase._getCredentialFromTokenAsync` in `@rushstack/rush-azure-storage-build-cache-plugin`. Adding support for InteractiveBrowserCredential." + } + ] + } + }, + { + "version": "5.117.10", + "tag": "@microsoft/rush_v5.117.10", + "date": "Wed, 20 Mar 2024 04:57:57 GMT", + "comments": { + "none": [ + { + "comment": "Improve the \"splitWorkspaceCompatibility\" setting to simulate hoisted dependencies when the experimental Rush subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.117.9", + "tag": "@microsoft/rush_v5.117.9", + "date": "Tue, 12 Mar 2024 19:15:07 GMT", + "comments": { + "none": [ + { + "comment": "Add functionality to disable filtered installs for specific subspaces" + } + ] + } + }, + { + "version": "5.117.8", + "tag": "@microsoft/rush_v5.117.8", + "date": "Sat, 09 Mar 2024 01:11:16 GMT", + "comments": { + "none": [ + { + "comment": "Fixes a bug where the syncNpmrc function incorrectly uses the folder instead of the path" + } + ] + } + }, + { + "version": "5.117.7", + "tag": "@microsoft/rush_v5.117.7", + "date": "Fri, 08 Mar 2024 23:45:24 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where, when the experimental subspace feature is enabled, the subspace's \".npmrc\" file did not take precedence over \".npmrc-global\"." + } + ] + } + }, + { + "version": "5.117.6", + "tag": "@microsoft/rush_v5.117.6", + "date": "Thu, 07 Mar 2024 19:35:20 GMT", + "comments": { + "none": [ + { + "comment": "Fixes an issue where cobuilds would write success with warnings as successful cache entries." + } + ] + } + }, + { + "version": "5.117.5", + "tag": "@microsoft/rush_v5.117.5", + "date": "Wed, 06 Mar 2024 23:03:27 GMT", + "comments": { + "none": [ + { + "comment": "Add filtered installs for subspaces" + } + ] + } + }, + { + "version": "5.117.4", + "tag": "@microsoft/rush_v5.117.4", + "date": "Tue, 05 Mar 2024 21:15:26 GMT", + "comments": { + "none": [ + { + "comment": "Add support for subspace level scoped pnpm-config.json e.g. `common/config/subspaces/default/pnpm-config.json`" + } + ] + } + }, + { + "version": "5.117.3", + "tag": "@microsoft/rush_v5.117.3", + "date": "Tue, 05 Mar 2024 01:19:42 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where if a patch is removed from `common/pnpm-patches` after `rush install` had already been run with that patch present, pnpm would try to continue applying the patch." + }, + { + "comment": "Intercept the output printed by `rush-pnpm patch` to update the next step's instructions to run `rush-pnpm patch-commit ...` instead of `pnpm patch-commit ...`." + } + ] + } + }, + { + "version": "5.117.2", + "tag": "@microsoft/rush_v5.117.2", + "date": "Fri, 01 Mar 2024 23:12:43 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with the experimental subspaces feature, where version checks incorrectly scanned irrelevant subspaces." + } + ] + } + }, + { + "version": "5.117.1", + "tag": "@microsoft/rush_v5.117.1", + "date": "Thu, 29 Feb 2024 07:34:31 GMT", + "comments": { + "none": [ + { + "comment": "Update \"rush init\" template to document the new build-cache.json constants" + }, + { + "comment": "Remove trailing slashes from `node_modules` and `jspm_packages` paths in the `.gitignore` file generated by `rush init`." + }, + { + "comment": "Introduce a `RushCommandLine` API that exposes an object representing the skeleton of the Rush command-line." + }, + { + "comment": "Fix an issue where, when the experimental subspaces feature was enabled, the lockfile validation would check irrelevant subspaces" + } + ] + } + }, + { + "version": "5.117.0", + "tag": "@microsoft/rush_v5.117.0", + "date": "Mon, 26 Feb 2024 21:39:36 GMT", + "comments": { + "none": [ + { + "comment": "Include the ability to add `[os]` and `[arch]` tokens to cache entry name patterns." + }, + { + "comment": "(BREAKING CHANGE) Remove the 'installation variants' feature and its related APIs, which have been superceded by the Subspaces feature." + }, + { + "comment": "Extract the \"rush.json\" filename to a constant as `RushConstants.rushJsonFilename`." + } + ] + } + }, + { + "version": "5.116.0", + "tag": "@microsoft/rush_v5.116.0", + "date": "Mon, 26 Feb 2024 20:04:02 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade the `pnpm-sync-lib` dependency version." + }, + { + "comment": "Handle `workspace:~` and `workspace:^` wildcard specifiers when publishing. They remain as-is in package.json but get converted to `~${current}` and `^${current}` in changelogs." + }, + { + "comment": "Validate that the \"projectFolder\" and \"publishFolder\" fields in the \"projects\" list in \"rush.json\" are normalized POSIX relative paths that do not end in trailing \"/\" or contain \"\\\\\"." + } + ] + } + }, + { + "version": "5.115.0", + "tag": "@microsoft/rush_v5.115.0", + "date": "Thu, 22 Feb 2024 01:36:27 GMT", + "comments": { + "none": [ + { + "comment": "Add a \"runWithTerminalAsync\" resource lifetime helper to `IOperationRunnerContext` to manage the creation and cleanup of logging for operation execution." + }, + { + "comment": "Adds a new experiment `useIPCScriptsInWatchMode`. When this flag is enabled and Rush is running in watch mode, it will check for npm scripts named `_phase::ipc`, and if found, use them instead of the normal invocation of `_phase:`. When doing so, it will provide an IPC channel to the child process and expect the child to outlive the current build pass." + } + ] + } + }, + { + "version": "5.114.3", + "tag": "@microsoft/rush_v5.114.3", + "date": "Thu, 22 Feb 2024 00:10:32 GMT", + "comments": { + "none": [ + { + "comment": "Replace deprecated function, and fix a path bug in Windows env" + } + ] + } + }, + { + "version": "5.114.2", + "tag": "@microsoft/rush_v5.114.2", + "date": "Wed, 21 Feb 2024 21:45:46 GMT", + "comments": { + "none": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ] + } + }, + { + "version": "5.114.1", + "tag": "@microsoft/rush_v5.114.1", + "date": "Wed, 21 Feb 2024 08:56:05 GMT", + "comments": { + "none": [ + { + "comment": "Improve `rush scan` to analyze APIs such as `Import.lazy()` and `await import()`" + }, + { + "comment": "Fix a recent regression where `@rushstack/rush-sdk` did not declare its dependency on `@rushstack/terminal`" + } + ] + } + }, + { + "version": "5.114.0", + "tag": "@microsoft/rush_v5.114.0", + "date": "Mon, 19 Feb 2024 21:54:44 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Add `enablePnpmSyncForInjectedDependenciesMeta` to experiments.json; it is part of an upcoming feature for managing PNPM \"injected\" dependencies: https://www.npmjs.com/package/pnpm-sync" + }, + { + "comment": "Include a `pnpmPatchesCommonFolderName` constant for the folder name \"pnpm-patches\" that gets placed under \"common\"." + }, + { + "comment": "Add a feature to generate a `project-impact-graph.yaml` file in the repo root. This feature is gated under the new `generateProjectImpactGraphDuringRushUpdate` experiment." + }, + { + "comment": "Fix a formatting issue with the LICENSE." + }, + { + "comment": "Fix an issue with filtered installs when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.113.4", + "tag": "@microsoft/rush_v5.113.4", + "date": "Wed, 31 Jan 2024 22:49:17 GMT", + "comments": { + "none": [ + { + "comment": "Introduce an explicit warning message during `rush install` or `rush update` about `dependenciesMeta` not being up-to-date." + } + ] + } + }, + { + "version": "5.113.3", + "tag": "@microsoft/rush_v5.113.3", + "date": "Wed, 31 Jan 2024 22:25:55 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush update` would sometimes not correctly sync the `pnpm-lock.yaml` file back to `common/config/rush/` after a project's `package.json` has been updated." + } + ] + } + }, + { + "version": "5.113.2", + "tag": "@microsoft/rush_v5.113.2", + "date": "Wed, 31 Jan 2024 18:45:33 GMT", + "comments": { + "none": [ + { + "comment": "Fix some minor issues when the experimental subspaces feature is enabled" + } + ] + } + }, + { + "version": "5.113.1", + "tag": "@microsoft/rush_v5.113.1", + "date": "Wed, 31 Jan 2024 07:07:50 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Enable filtered installs of subspaces and add a \"preventSelectingAllSubspaces\" setting" + } + ] + } + }, + { + "version": "5.113.0", + "tag": "@microsoft/rush_v5.113.0", + "date": "Tue, 30 Jan 2024 22:58:52 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush does not detect changes to the `dependenciesMeta` field in project's `package.json` files, so may incorrectly skip updating/installation." + }, + { + "comment": "Add ability to enable IPC channels in `Utilities#executeLifeCycleCommand`." + }, + { + "comment": "Update `rush init` template to document the \"buildSkipWithAllowWarningsInSuccessfulBuild\" experiment" + }, + { + "comment": "(BREAKING CHANGE) Begin removal of APIs for the deprecated \"installation variants\" feature, since subspaces are a more robust solution for that problem" + }, + { + "comment": "(EXPERIMENTAL) Implement installation for the not-yet-released \"subspaces\" feature (GitHub #4230)" + } + ] + } + }, + { + "version": "5.112.2", + "tag": "@microsoft/rush_v5.112.2", + "date": "Tue, 12 Dec 2023 00:20:51 GMT", + "comments": { + "none": [ + { + "comment": "Bring back the erroneously removed `preminor` bump type for lockstepped packages." + }, + { + "comment": "Fix an issue where the contents of a folder set in the `\"folderToCopy\"` field of the `deploy.json` config file would be copied into a subfolder instead of into the root of the deploy folder." + }, + { + "comment": "(EXPERIMENTAL) Implemented config file loader for the not-yet-released \"subspaces\" feature (GitHub #4230)" + } + ] + } + }, + { + "version": "5.112.1", + "tag": "@microsoft/rush_v5.112.1", + "date": "Wed, 29 Nov 2023 08:59:31 GMT", + "comments": { + "none": [ + { + "comment": "Allow the device code credential options to be extended Azure authentication subclasses, used in advanced authentication scenarios." + } + ] + } + }, + { + "version": "5.112.0", + "tag": "@microsoft/rush_v5.112.0", + "date": "Mon, 27 Nov 2023 23:36:11 GMT", + "comments": { + "none": [ + { + "comment": "Update the `@azure/identity` and `@azure/storage-blob` dependencies of `@rushstack/rush-azure-storage-build-cache-plugin` to eliminate an `EBADENGINE` error when installing Rush on Node 20." + } + ] + } + }, + { + "version": "5.111.0", + "tag": "@microsoft/rush_v5.111.0", + "date": "Sat, 18 Nov 2023 00:06:20 GMT", + "comments": { + "none": [ + { + "comment": "Add experiment `buildSkipWithAllowWarningsInSuccessfulBuild` to allow skipping builds that succeeded with warnings in the previous run." + } + ] + } + }, + { + "version": "5.110.2", + "tag": "@microsoft/rush_v5.110.2", + "date": "Thu, 16 Nov 2023 01:36:10 GMT", + "comments": {} + }, + { + "version": "5.110.1", + "tag": "@microsoft/rush_v5.110.1", + "date": "Wed, 01 Nov 2023 23:29:47 GMT", + "comments": { + "none": [ + { + "comment": "Fix line endings in published package." + } + ] + } + }, + { + "version": "5.110.0", + "tag": "@microsoft/rush_v5.110.0", + "date": "Mon, 30 Oct 2023 23:37:07 GMT", + "comments": { + "none": [ + { + "comment": "Include the filename of the shrinkwrap file in logging messages for all package managers, not just Yarn." + }, + { + "comment": "performance improvements by running asynchronous code concurrently using Promise.all" + } + ] + } + }, + { + "version": "5.109.2", + "tag": "@microsoft/rush_v5.109.2", + "date": "Fri, 20 Oct 2023 01:54:21 GMT", + "comments": { + "none": [ + { + "comment": "Allow the output preservation incremental strategy if the build cache is configured but disabled. When running in verbose mode, log the incremental strategy that is being used." + }, + { + "comment": "Log the cache key in `--verbose` mode when the cache is successfully read from or written to." + }, + { + "comment": "Fix an issue where console colors were sometimes not enabled correctly during `rush install`" + }, + { + "comment": "Fix an issue where running `rush update-cloud-credentials --interactive` sometimes used the wrong working directory when invoked in a repo configured to use the `http` build cache provider (GitHub #4396)" + } + ] + } + }, + { + "version": "5.109.1", + "tag": "@microsoft/rush_v5.109.1", + "date": "Sat, 07 Oct 2023 01:20:56 GMT", + "comments": { + "none": [ + { + "comment": "Fix incorrect capitalization in the \"rush init\" template" + } + ] + } + }, + { + "version": "5.109.0", + "tag": "@microsoft/rush_v5.109.0", + "date": "Sat, 07 Oct 2023 00:25:27 GMT", + "comments": { + "none": [ + { + "comment": "(IMPORTANT) Add a new setting `autoInstallPeers` in pnpm-config.json; be aware that Rush changes PNPM's default if you are using PNPM 8 or newer" + }, + { + "comment": "(IMPORTANT) After upgrading, if `rush install` fails with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`, please run `rush update --recheck`" + }, + { + "comment": "Improve visual formatting of custom tips" + }, + { + "comment": "Add start `preRushx` and `postRushx` event hooks for monitoring the `rushx` command" + }, + { + "comment": "Update the oldest usable Node.js version to 14.18.0, since 14.17.0 fails to load" + } + ] + } + }, + { + "version": "5.108.0", + "tag": "@microsoft/rush_v5.108.0", + "date": "Mon, 02 Oct 2023 20:23:27 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush purge` fails on Linux and Mac if the `common/temp/rush-recycler` folder does not exist." + }, + { + "comment": "Add \"--offline\" parameter for \"rush install\" and \"rush update\"" + }, + { + "comment": "Ignore pause/resume watcher actions when the process is not TTY mode" + } + ] + } + }, + { + "version": "5.107.4", + "tag": "@microsoft/rush_v5.107.4", + "date": "Tue, 26 Sep 2023 21:02:52 GMT", + "comments": { + "none": [ + { + "comment": "Update type-only imports to include the type modifier." + }, + { + "comment": "Make the project watcher status and keyboard commands message more visible." + } + ] + } + }, + { + "version": "5.107.3", + "tag": "@microsoft/rush_v5.107.3", + "date": "Fri, 22 Sep 2023 09:01:38 GMT", + "comments": { + "none": [ + { + "comment": "Fix filtered installs in pnpm@8." + } + ] + } + }, + { + "version": "5.107.2", + "tag": "@microsoft/rush_v5.107.2", + "date": "Fri, 22 Sep 2023 00:06:12 GMT", + "comments": { + "none": [ + { + "comment": "Fix a bug in which an operation failing incorrectly does not block its consumers." + }, + { + "comment": "Add `resolutionMode` to `rush init` template for pnpm-config.json" + } + ] + } + }, + { + "version": "5.107.1", + "tag": "@microsoft/rush_v5.107.1", + "date": "Tue, 19 Sep 2023 21:13:23 GMT", + "comments": { + "none": [ + { + "comment": "Fix pnpm's install status printing when pnpm custom tips are defined." + } + ] + } + }, + { + "version": "5.107.0", + "tag": "@microsoft/rush_v5.107.0", + "date": "Tue, 19 Sep 2023 00:36:50 GMT", + "comments": { + "none": [ + { + "comment": "Update @types/node from 14 to 18" + }, + { + "comment": "Remove previously removed fields from the `custom-tips.json` schema." + }, + { + "comment": "(BREAKING API CHANGE) Refactor the `CustomTipsConfiguration` by removing the `configuration` property and adding a `providedCustomTipsByTipId` map property." + }, + { + "comment": "Fix an issue where pnpm would would not rewrite the current status line on a TTY console, and instead would print a series of separate status lines during installation. Note that this is only fixed when there are no custom PNPM tips provided." + }, + { + "comment": "Add \"Waiting\" operation status for operations that have one or more dependencies still pending. Ensure that the `onOperationStatusChanged` hook fires for every status change." + }, + { + "comment": "Add support for optional build status notifications over a web socket connection to `@rushstack/rush-serve-plugin`." + }, + { + "comment": "Add pause/resume option to project watcher" + } + ] + } + }, + { + "version": "5.106.0", + "tag": "@microsoft/rush_v5.106.0", + "date": "Thu, 14 Sep 2023 09:20:11 GMT", + "comments": { + "none": [ + { + "comment": "(IMPORTANT) Add a new setting `resolutionMode` in pnpm-config.json; be aware that Rush now overrides the default behavior if you are using PNPM 8.0.0 through 8.6.12 (GitHub #4283)" + }, + { + "comment": "Support adding custom tips for pnpm-printed logs" + }, + { + "comment": "(BREAKING CHANGE) Remove the \"defaultMessagePrefix\" config in custom-tips.json" + }, + { + "comment": "Rename the `PnpmStoreOptions` type to `PnpmStoreLocation`." + } + ] + } + }, + { + "version": "5.105.0", + "tag": "@microsoft/rush_v5.105.0", + "date": "Fri, 08 Sep 2023 04:09:06 GMT", + "comments": { + "none": [ + { + "comment": "Disable build cache writes in watch rebuilds." + }, + { + "comment": "Fix the instance of \"ICreateOperationsContext\" passed to the \"beforeExecuteOperations\" hook in watch mode rebuilds to match the instance passed to the \"createOperations\" hook." + }, + { + "comment": "Fix an issue where the error message printed when two phases have overlapping output folders did not mention both phases." + }, + { + "comment": "Update the phase output folders validation to only check for overlapping folders for phases that actually execute an operation in a given project." + }, + { + "comment": "Add the \"disableBuildCache\" option to the schema for phased commands (it is already present for bulk commands). Update the behavior of the \"disableBuildCache\" flag to also disable the legacy skip detection, in the event that the build cache is not configured." + } + ] + } + }, + { + "version": "5.104.1", + "tag": "@microsoft/rush_v5.104.1", + "date": "Tue, 05 Sep 2023 18:53:03 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush init` generated a `cobuild.json` file that reported errors (GitHub #4307)" + } + ] + } + }, + { + "version": "5.104.0", + "tag": "@microsoft/rush_v5.104.0", + "date": "Fri, 01 Sep 2023 04:54:16 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Initial release of the cobuild feature, a cheap way to distribute jobs Rush builds across multiple VMs. (GitHub #3485)" + } + ] + } + }, + { + "version": "5.103.0", + "tag": "@microsoft/rush_v5.103.0", + "date": "Thu, 31 Aug 2023 23:28:28 GMT", + "comments": { + "none": [ + { + "comment": "Add dependencySettings field to Rush deploy.json configurations. This will allow developers to customize how third party dependencies are processed when running `rush deploy`" + }, + { + "comment": "Fix an issue where `rush update-autoinstaller` sometimes did not fully upgrade the lockfile" + }, + { + "comment": "Fix an issue where \"undefined\" was sometimes printed instead of a blank line" + } + ] + } + }, + { + "version": "5.102.0", + "tag": "@microsoft/rush_v5.102.0", + "date": "Tue, 15 Aug 2023 20:09:40 GMT", + "comments": { + "none": [ + { + "comment": "Add a new config file \"custom-tips.json\" for customizing Rush messages (GitHub #4207)" + }, + { + "comment": "Improve \"rush scan\" to recognize module patterns such as \"import get from 'lodash.get'\"" + }, + { + "comment": "Update Node.js version checks to support the new LTS release" + }, + { + "comment": "Update \"rush init\" template to use PNPM 7.33.5" + }, + { + "comment": "Update the \"rush init\" template's .gitignore to avoid spurious diffs for files such as \"autoinstaller.lock\"" + }, + { + "comment": "Fix an issue where a pnpm-lock file would fail to parse if a project used a package alias in a repo using pnpm 8." + }, + { + "comment": "Fix HTTP/1 backwards compatibility in rush-serve-plugin." + }, + { + "comment": "Add experiment \"usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate\" that, when running `rush update`, performs first a `--lockfile-only` update to the lockfile, then a `--frozen-lockfile` installation. This mitigates issues that may arise when using the `afterAllResolved` hook in `.pnpmfile.cjs`." + } + ] + } + }, + { + "version": "5.101.1", + "tag": "@microsoft/rush_v5.101.1", + "date": "Fri, 11 Aug 2023 17:57:55 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression from 5.101.0 where publishing features did not detect changes properly when running on Windows OS (GitHub #4277)" + }, + { + "comment": "Add support in rush-serve-plugin for HTTP/2, gzip compression, and CORS preflight requests." + } + ] + } + }, + { + "version": "5.101.0", + "tag": "@microsoft/rush_v5.101.0", + "date": "Tue, 08 Aug 2023 07:11:02 GMT", + "comments": { + "none": [ + { + "comment": "Enable the \"http\" option for build-cache providers" + }, + { + "comment": "Switch from glob to fast-glob." + }, + { + "comment": "Reduce false positive detections of the pnpm shrinkwrap file being out of date in the presence of the `globalOverrides` setting in `pnpm-config.json`, or when a dependency is listed in both `dependencies` and `devDependencies` in the same package." + }, + { + "comment": "@rushstack/rush-sdk now exposes a secondary API for manually loading the Rush engine and monitoring installation progress" + }, + { + "comment": "Add support for npm aliases in `PnpmShrinkwrapFile._getPackageId`." + }, + { + "comment": "Improve version resolution logic in common/scripts/install-run.js (see https://github.com/microsoft/rushstack/issues/4256)" + }, + { + "comment": "Add `patternsToInclude` and `patternsToExclude` support to Rush deploy.json configurations. This will allow developers to include or exclude provided glob patterns within a local project when running `rush deploy`." + } + ] + } + }, + { + "version": "5.100.2", + "tag": "@microsoft/rush_v5.100.2", + "date": "Mon, 24 Jul 2023 18:54:49 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the git pre-push hook would allow push to go through if the script exited with error." + } + ], + "none": [ + { + "comment": "Updated semver dependency" + } + ] + } + }, + { + "version": "5.100.1", + "tag": "@microsoft/rush_v5.100.1", + "date": "Wed, 14 Jun 2023 19:42:12 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush would attempt to open a project's log file for writing twice." + }, + { + "comment": "Fix an issue where arguments weren't passed to git hook scripts." + } + ] + } + }, + { + "version": "5.100.0", + "tag": "@microsoft/rush_v5.100.0", + "date": "Tue, 13 Jun 2023 01:49:21 GMT", + "comments": { + "none": [ + { + "comment": "(BREAKING API CHANGE) Remove unused members of the `BumpType` API. See https://github.com/microsoft/rushstack/issues/1335 for details." + }, + { + "comment": "Add `--peer` flag to `rush add` command to add peerDependencies" + }, + { + "comment": "Add support for PNPM 8." + }, + { + "comment": "Remove the dependency on `lodash`." + }, + { + "comment": "Add functionality for the Amazon S3 Build Cache Plugin to read credentials from common AWS_* environment variables." + }, + { + "comment": "Write cache logs to their own file(s)." + }, + { + "comment": "Fix an issue where cache logging data was always written to stdout." + }, + { + "comment": "Generate scripts in the Git hooks folder referring to the actual hook implementations in-place in the Rush `common/git-hooks/` folder instead of copying the scripts to the Git hooks folder." + }, + { + "comment": "Bump webpack to v5.82.1" + } + ] + } + }, + { + "version": "5.99.0", + "tag": "@microsoft/rush_v5.99.0", + "date": "Fri, 02 Jun 2023 22:08:28 GMT", + "comments": { + "none": [ + { + "comment": "Use a separate temrinal for logging cache subsystem" + }, + { + "comment": "Expose beforeLog hook" + }, + { + "comment": "Convert to multi-phase Heft" + }, + { + "comment": "Use `JSON.parse` instead of `jju` to parse `package.json` files for faster performance." + } + ] + } + }, + { + "version": "5.98.0", + "tag": "@microsoft/rush_v5.98.0", + "date": "Sun, 21 May 2023 00:18:35 GMT", + "comments": { + "none": [ + { + "comment": "Add a \"forbidPhantomResolvableNodeModuleFolders\" experiment that forbids node_modules folders in the repo root and in parent folders." + }, + { + "comment": "Update the `RushSession.registerCloudBuildCacheProviderFactory` API to allow a cache provider's factory function to return a promise." + }, + { + "comment": "Add built-in plugin rush-http-build-cache-plugin" + }, + { + "comment": "Fix an issue where the last character in a project's path is ignored when determining which files contribute to the project's cache ID." + }, + { + "comment": "Fix a performance bug in `rush version` when using `workspace:` protocol." + }, + { + "comment": "(BREAKING API CHANGE) Add a property `missingScriptBehavior` to phase definitions that can be used to silence missing scripts to reduce log noise. This replaces the `ignoreMissingScript` property visible to the plugin API, although the `ignoreMissingScript` property is still supported in the `common/config/rush/command-line.json` config file for backwards compatibility." + }, + { + "comment": "Flatten watch status into a single line with TTY rewrites." + } + ] + } + }, + { + "version": "5.97.1", + "tag": "@microsoft/rush_v5.97.1", + "date": "Tue, 18 Apr 2023 16:39:03 GMT", + "comments": { + "none": [ + { + "comment": "`rush version` will now respect the `ensureConsistentVersions` field in `rush.json`" + }, + { + "comment": "Bump webpack to 5.78.0" + }, + { + "comment": "Fix file watching on Windows in the presence of Git's fsmonitor by not watching the .git folder." + } + ] + } + }, + { + "version": "5.97.0", + "tag": "@microsoft/rush_v5.97.0", + "date": "Wed, 05 Apr 2023 21:46:37 GMT", + "comments": { + "none": [ + { + "comment": "Convert the `EnvironmentVariableNames` from an enum to a const so that its values can be referred to by type." + } + ] + } + }, + { + "version": "5.96.0", + "tag": "@microsoft/rush_v5.96.0", + "date": "Fri, 31 Mar 2023 00:27:51 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where rush-sdk sometimes failed to load if the globally installed Rush version was older than rushVersion in rush.json (GitHub #4039)" + }, + { + "comment": "Modify the scheduling behavior of phased commands to schedule only the expressly enumerated phases in all selected projects, adding additional phases only where needed to satisfy dependencies." + } + ] + } + }, + { + "version": "5.95.0", + "tag": "@microsoft/rush_v5.95.0", + "date": "Fri, 24 Mar 2023 08:53:43 GMT", + "comments": { + "none": [ + { + "comment": "Add experiment `printEventHooksOutputToConsole` to allow printing outputs from event hooks to the console." + } + ] + } + }, + { + "version": "5.94.1", + "tag": "@microsoft/rush_v5.94.1", + "date": "Wed, 22 Mar 2023 20:48:48 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where rush plugin autoinstallers would fail to install because the Rush global folder had not yet been initialized." + }, + { + "comment": "Fix an issue with `rush update-autoinstaller` where it may fail with an `Cannot install with \"frozen-lockfile\" because pnpm-lock.yaml is not up to date with package.json` error." + } + ] + } + }, + { + "version": "5.94.0", + "tag": "@microsoft/rush_v5.94.0", + "date": "Mon, 20 Mar 2023 20:14:36 GMT", + "comments": { + "none": [ + { + "comment": "Update the `nodeSupportedVersionRange` in `rush.json` generated by `rush init` to remove Node 12 as it is no longer supported and include Node 18 as it is the current LTS version." + }, + { + "comment": "Extend LookupByPath to also be able to obtain the index of the remainder of the matched path." + }, + { + "comment": "Include some more hooks to allow plugins to monitor phased command execution in real-time." + }, + { + "comment": "Fix an issue where running `rush update-autoinstaller` without having run `rush install` or `rush update` first would cause a crash with an unhelpful error message." + } + ] + } + }, + { + "version": "5.93.2", + "tag": "@microsoft/rush_v5.93.2", + "date": "Mon, 06 Mar 2023 20:18:01 GMT", + "comments": { + "none": [ + { + "comment": "Do not delete the local pnpm store after all install attempts has failed. `rush purge` will still delete a local store." + } + ] + } + }, + { + "version": "5.93.1", + "tag": "@microsoft/rush_v5.93.1", + "date": "Fri, 17 Feb 2023 14:46:59 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression where \"rush-sdk\" failed to load older versions of \"rush-lib\" (GitHub #3979)" + } + ] + } + }, + { + "version": "5.93.0", + "tag": "@microsoft/rush_v5.93.0", + "date": "Fri, 17 Feb 2023 02:14:43 GMT", + "comments": { + "none": [ + { + "comment": "Add code path to @rushstack/rush-sdk for inheriting @microsoft/rush-lib location from a parent process via the _RUSH_LIB_PATH environment variable." + } + ] + } + }, + { + "version": "5.92.0", + "tag": "@microsoft/rush_v5.92.0", + "date": "Sun, 12 Feb 2023 02:50:42 GMT", + "comments": { + "none": [ + { + "comment": "Enable @rushstack/rush-sdk to import internal APIs from the proxied @microsoft/rush-lib instance (GitHub #3895)" + } + ] + } + }, + { + "version": "5.91.0", + "tag": "@microsoft/rush_v5.91.0", + "date": "Sat, 11 Feb 2023 02:04:14 GMT", + "comments": { + "none": [ + { + "comment": "Remove runtime dependency on @rushstack/rush-sdk from the AzureStorageAuthentication class in @rushstack/rush-azure-storage-build-cache-plugin so that it can be used in isolation." + }, + { + "comment": "Include operation log files in the cache, and restore them during cache hits." + } + ] + } + }, + { + "version": "5.90.2", + "tag": "@microsoft/rush_v5.90.2", + "date": "Wed, 08 Feb 2023 20:27:06 GMT", + "comments": {} + }, + { + "version": "5.90.1", + "tag": "@microsoft/rush_v5.90.1", + "date": "Wed, 08 Feb 2023 19:58:35 GMT", + "comments": { + "none": [ + { + "comment": "Disable unused depcheck feature for upgrade-interactive." + }, + { + "comment": "Fix an issue where deleting the `common/temp/node_modules` folder encounters an EPERM error and aborts." + } + ], + "patch": [ + { + "comment": "Fix determination of the root of the current Git worktree when in a multi-worktree setup." + } + ] + } + }, + { + "version": "5.90.0", + "tag": "@microsoft/rush_v5.90.0", + "date": "Sun, 29 Jan 2023 20:10:17 GMT", + "comments": { + "none": [ + { + "comment": "Allow \"shellCommand\" to be optionally specified for bulk custom commands, so that a centralized script can be used instead of invoking package.json scripts (GitHub #3819)" + } + ] + } + }, + { + "version": "5.89.1", + "tag": "@microsoft/rush_v5.89.1", + "date": "Thu, 26 Jan 2023 02:55:30 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with `rush add` where the approved packages files aren't updated." + }, + { + "comment": "Revert generation of scripts in the Git hooks folder due to various git-related issues" + }, + { + "comment": "Upgrade to webpack 5.75.0" + } + ] + } + }, + { + "version": "5.89.0", + "tag": "@microsoft/rush_v5.89.0", + "date": "Tue, 24 Jan 2023 22:30:06 GMT", + "comments": { + "none": [ + { + "comment": "Fix linking error due to PNPM v7 local install path breaking change" + }, + { + "comment": "Introduce \"dependsOnAdditionalFiles\" configuration option to operations in rush-project.json. This option allows to pass glob (minimatch) patterns pointing to files outside of .git repository. If provided, the hash values of these files will become part of the final hash when reading and writing from cache." + }, + { + "comment": "Use getRepoStateAsync to optimize performance of calculating repository state." + }, + { + "comment": "Generate scripts in the Git hooks folder referring to the actual hook implementations in-place in the Rush `common/git-hooks/` folder instead of copying the scripts to the Git hooks folder." + } + ] + } + }, + { + "version": "5.88.2", + "tag": "@microsoft/rush_v5.88.2", + "date": "Sun, 22 Jan 2023 04:18:44 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression where the 'dist/scripts' folder name was named 'dist/undefined'" + } + ] + } + }, + { + "version": "5.88.1", + "tag": "@microsoft/rush_v5.88.1", + "date": "Wed, 18 Jan 2023 22:44:31 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `create-scripts.js` does not exist during `rush deploy`." + }, + { + "comment": "Add install-run-rush-pnpm.js script" + }, + { + "comment": "Update JSZip to 3.8.0." + } + ] + } + }, + { + "version": "5.88.0", + "tag": "@microsoft/rush_v5.88.0", + "date": "Thu, 22 Dec 2022 20:11:58 GMT", + "comments": { + "none": [ + { + "comment": "Improve the experience during a rush operation when the cached credentials have expired. Now, a warning is printed instead of an error being thrown and the operation halted." + }, + { + "comment": "(BREAKING API CHANGE IN @rushstack/rush-azure-storage-build-cache-plugin) Change the signature of `AzureAuthenticationBase.tryGetCachedCredentialAsync` to optionally take an object describing the behavior when credentials have expired. The behavior of the function without an argument is unchanged." + } + ] + } + }, + { + "version": "5.87.0", + "tag": "@microsoft/rush_v5.87.0", + "date": "Fri, 16 Dec 2022 19:34:26 GMT", + "comments": { + "none": [ + { + "comment": "Fix a typo in the artifactory.json template" + }, + { + "comment": "Writing local build cache is more robust on a network drive." + }, + { + "comment": "Document default value for the \"watchDebounceMs\" setting" + }, + { + "comment": "Add \"nodeSupportedVersionInstructions\" property to rush.json, allowing maintainers to provide additional instructions if the user's node version is unsupported." + }, + { + "comment": "(IMPORTANT) Fix a regression where the \"strictPeerDependencies\" setting wasn't applied for some versions of PNPM 7 due to unexpected changes of PNPM's default value (GitHub #3828)" + }, + { + "comment": "Fix an issue where if the package manager is PNPM 6.1.0 or newer, and `pnpmStore` is set to `\"local\"`, then a global cache was still used." + }, + { + "comment": "Write local telemetry for global script actions" + }, + { + "comment": "Normalize all newlines in logging statements to LF. On Windows, some newlines were CRLF." + }, + { + "comment": "Upgrade `npm-check` dependency from `~5.9.2` to `~6.0.1`" + }, + { + "comment": "Work towards bundling the files of \"@rushstack/rush-lib\" (Details in GitHub #3837)" + } + ] + } + }, + { + "version": "5.86.0", + "tag": "@microsoft/rush_v5.86.0", + "date": "Tue, 29 Nov 2022 00:10:20 GMT", + "comments": { + "none": [ + { + "comment": "Add new commands \"rush-pnpm patch\" and \"rush-pnpm patch-commit\" for patching NPM packages when using the PNPM package manager (GitHub #3554)" + } + ] + } + }, + { + "version": "5.85.1", + "tag": "@microsoft/rush_v5.85.1", + "date": "Fri, 25 Nov 2022 21:51:32 GMT", + "comments": { + "none": [ + { + "comment": "Fix an intermittent issue when writing tar log files" + } + ] + } + }, + { + "version": "5.85.0", + "tag": "@microsoft/rush_v5.85.0", + "date": "Thu, 24 Nov 2022 03:57:19 GMT", + "comments": { + "none": [ + { + "comment": "Add support for a `credentialMetadata` property in the CredentialCache." + }, + { + "comment": "(BREAKING API CHANGE) Change the signature of `CredentialCache.setCacheEntry` to take the credential ID and an object describing the credential instead of a credential string and an expiration date. The second argument's type now matches the return value of `CredentialCache.tryGetCacheEntry`" + }, + { + "comment": "(BREAKING API CHANGE) Change the return type of `AzureAuthenticationBase.tryGetCachedCredentialAsync` (and, therefore, `AzureStorageAuthentication.tryGetCachedCredentialAsync`) from `string | undefined` to `ICredentialCacheEntry | undefined` to include the credentialMetadata." + } + ] + } + }, + { + "version": "5.84.0", + "tag": "@microsoft/rush_v5.84.0", + "date": "Tue, 22 Nov 2022 23:24:56 GMT", + "comments": { + "none": [ + { + "comment": "Add a \"dependsOnEnvVars\" configuration option to operations in rush-project.json. The variables specified in this option are included in the cache key hash calculation." + }, + { + "comment": "The \"rush setup\" user prompts can now be customized." + }, + { + "comment": "Make autoinstaller logging respect the `--quiet` parameter." + }, + { + "comment": "Add project filtering to the upgrade-interactive UI prompt. Also increases the default page size for project lists in UI to 12." + }, + { + "comment": "Add a feature (behind the \"cleanInstallAfterNpmrcChanges\" experiment) that will cause a clean install to be performed if the common/temp/.npmrc file has changed since the last install." + } + ] + } + }, + { + "version": "5.83.4", + "tag": "@microsoft/rush_v5.83.4", + "date": "Fri, 18 Nov 2022 04:02:43 GMT", + "comments": { + "none": [ + { + "comment": "Change files and change logs can store custom fields." + } + ], + "patch": [ + { + "comment": "Fix performance regression from supporting git submodules" + } + ] + } + }, + { + "version": "5.83.3", + "tag": "@microsoft/rush_v5.83.3", + "date": "Tue, 15 Nov 2022 18:43:51 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where Git submodules were not handled correctly by the build cache (GitHub #1711)" + } + ] + } + }, + { + "version": "5.83.2", + "tag": "@microsoft/rush_v5.83.2", + "date": "Mon, 14 Nov 2022 05:15:22 GMT", + "comments": { + "none": [ + { + "comment": "Ensure autoinstaller lockfiles are not leftover after an error" + } + ] + } + }, + { + "version": "5.83.1", + "tag": "@microsoft/rush_v5.83.1", + "date": "Sat, 12 Nov 2022 04:40:57 GMT", + "comments": { + "none": [ + { + "comment": "Update the \"rush init\" template for command-line.json to add usage examples for integer, integer list, string list, choice list parameter kinds" + } + ] + } + }, + { + "version": "5.83.0", + "tag": "@microsoft/rush_v5.83.0", + "date": "Fri, 11 Nov 2022 03:51:49 GMT", + "comments": { + "none": [ + { + "comment": "Add credentialType option for rush setup command" + }, + { + "comment": "Rush \"setup\" command works even if plugins cannot be installed" + }, + { + "comment": "Add support for integer, integer list, string list, and choice list parameters in plugins." + }, + { + "comment": "Introduce a `rush upgrade-interactive` action that provides an interactive way to upgrade outdated dependencies." + }, + { + "comment": "Fix a regression from Rush 5.79.0 where \"rush init\" did not create the pnpm-config.json file automatically" + } + ] + } + }, + { + "version": "5.82.1", + "tag": "@microsoft/rush_v5.82.1", + "date": "Wed, 19 Oct 2022 23:44:02 GMT", + "comments": {} + }, + { + "version": "5.82.0", + "tag": "@microsoft/rush_v5.82.0", + "date": "Mon, 17 Oct 2022 22:14:39 GMT", + "comments": { + "none": [ + { + "comment": "Replace Travis with GitHub Actions in the `rush init` template.\"" + }, + { + "comment": "Handle case in ProjectWatcher where a project contains no git tracked files or status information is or was unavailable." + }, + { + "comment": "Refactor @rushstack/rush-azure-storage-build-cache-plugin to expose an API for generating and caching Azure credentials for other workloads, in addition to Storage." + }, + { + "comment": "Validate the change type in changefiles during publishing." + } + ] + } + }, + { + "version": "5.81.0", + "tag": "@microsoft/rush_v5.81.0", + "date": "Sat, 08 Oct 2022 02:30:30 GMT", + "comments": { + "none": [ + { + "comment": "Add a `rush remove` command that removes one or more dependencies from a project." + }, + { + "comment": "Support passing a lockfile to \"install-run.js\" and \"install-run-rush.js\" to ensure stable installation on CI." + }, + { + "comment": "Add missing \"environmentVariables\" property to \"pnpm-config.json\" schema to restore feature parity with \"rush.json\" \"pnpmOptions\" field." + } + ] + } + }, + { + "version": "5.80.1", + "tag": "@microsoft/rush_v5.80.1", + "date": "Mon, 03 Oct 2022 23:11:35 GMT", + "comments": { + "none": [ + { + "comment": "Add a more useful error message in cases when a merge base for `rush change` cannot be determined." + } + ] + } + }, + { + "version": "5.80.0", + "tag": "@microsoft/rush_v5.80.0", + "date": "Thu, 29 Sep 2022 07:13:24 GMT", + "comments": { + "none": [ + { + "comment": "Include the operation duration in the telemetry data that was recorded during the non-cached run when a cache hit occurs." + }, + { + "comment": "Fix an error message that always says to run \"rush update --purge\" even if the user only needs to run \"rush install --purge.\"" + }, + { + "comment": "Fix an issue where a \"Current PNPM store path does not match the last one used.\" error will erroneously get thrown on Windows with an unchanged path, but with a forward slash instead of a backslash." + }, + { + "comment": "Remove fallback from tar binary to npm 'tar' package. The npm 'tar' package would sometimes produce invalid output if the cache entry was corrupt." + }, + { + "comment": "Remove gender from the git config example in rush.json" + } + ] + } + }, + { + "version": "5.79.0", + "tag": "@microsoft/rush_v5.79.0", + "date": "Sat, 24 Sep 2022 17:37:03 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `common/config/pnpm-config.json`, which is used to specify fields like `overrides`, `packageExtensions`, and `neverBuiltDependencies` that would otherwise be placed in a PNPM workspace repo's root-level `package.json`'s `pnpm` field." + } + ], + "none": [ + { + "comment": "Add a `--commit` and `--commit-message` flag to `rush change` that commits the change files automatically." + } + ] + } + }, + { + "version": "5.78.1", + "tag": "@microsoft/rush_v5.78.1", + "date": "Fri, 23 Sep 2022 02:54:44 GMT", + "comments": { + "none": [ + { + "comment": "Fix Git detection when the current working directory is unrelated to the Rush workspace." + }, + { + "comment": "Fix an error that ocurred if an autoinstaller's \"node_modules\" folder was manually deleted (GitHub #2987)" + } + ] + } + }, + { + "version": "5.78.0", + "tag": "@microsoft/rush_v5.78.0", + "date": "Sat, 17 Sep 2022 00:56:37 GMT", + "comments": { + "none": [ + { + "comment": "Add a \"beforeInstall\" hook to the plugin API, for plugins to examine the environment immediately before \"rush install\" or \"rush update\" invoke the package manager." + }, + { + "comment": "Fix \"--parallelism XX%\" parsing to return a finite number of CPU cores." + }, + { + "comment": "Update the \"rush init\" template to include .gitignore patterns for IntellJ IDEA" + }, + { + "comment": "Upgrade the @azure/identity and @azure/storage-blob packages to eliminate a deprecation message during installation." + }, + { + "comment": "Define an environment variable RUSH_PNPM_VERIFY_STORE_INTEGRITY that can be used to enable or disable PNPM's store integrity verification during installation for performance." + } + ] + } + }, + { + "version": "5.77.3", + "tag": "@microsoft/rush_v5.77.3", + "date": "Fri, 02 Sep 2022 17:49:09 GMT", + "comments": {} + }, + { + "version": "5.77.2", + "tag": "@microsoft/rush_v5.77.2", + "date": "Wed, 31 Aug 2022 00:43:07 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush add\" sometimes did not work correctly if a project is nested under another project's folder" + } + ] + } + }, + { + "version": "5.77.1", + "tag": "@microsoft/rush_v5.77.1", + "date": "Tue, 30 Aug 2022 17:26:42 GMT", + "comments": { + "none": [ + { + "comment": "Fixed an issue where \"rush add\" was not updating common-versions.json when using \"--make-consistent\"" + } + ] + } + }, + { + "version": "5.77.0", + "tag": "@microsoft/rush_v5.77.0", + "date": "Mon, 29 Aug 2022 21:09:31 GMT", + "comments": { + "none": [ + { + "comment": "Add machine architecture information, dependency graph information, and individual build times and statuses to the telemetry file." + }, + { + "comment": "Add schema validation for change files." + }, + { + "comment": "Fix a minor issue with the \"--rush-example-repo\" template" + }, + { + "comment": "Update CLI docs for \"rush add\"" + }, + { + "comment": "Improve some config file documentation" + }, + { + "comment": "Make the project tag name syntax more strict to avoid error-prone names such as \"tag:$PATH\" or \"tag://\"" + }, + { + "comment": "Add validation to ensure package.json files are strict JSON and the \"version\" field is strict SemVer" + }, + { + "comment": "Add a new setting \"watchOptions.debounceMs\" in command-line.json" + } + ] + } + }, + { + "version": "5.76.1", + "tag": "@microsoft/rush_v5.76.1", + "date": "Mon, 08 Aug 2022 07:32:36 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent regression where \"rush install\" would sometimes fail with \"Unknown option: 'ignore-compatibility-db'\"" + } + ] + } + }, + { + "version": "5.76.0", + "tag": "@microsoft/rush_v5.76.0", + "date": "Sat, 06 Aug 2022 05:35:19 GMT", + "comments": { + "none": [ + { + "comment": "Validate that if shouldPublish is set, private is not set" + }, + { + "comment": "\"rush install/update\" should always set \"ignore-compatibility-db=true\" and print warning if the rush.json pnpmVersion specifies a version affected by this problem. " + }, + { + "comment": "Reorder some initialization logic so that Rush's change analysis is not counted as part of the build time for the first project" + }, + { + "comment": "(BREAKING API CHANGE) Rename cyclicDependencyProjects to decoupledLocalDependencies" + } + ] + } + }, + { + "version": "5.75.0", + "tag": "@microsoft/rush_v5.75.0", + "date": "Tue, 28 Jun 2022 03:31:01 GMT", + "comments": { + "none": [ + { + "comment": "Disable build cache for operations with no corresponding operationSettings entry in rush-project.json, and provide a clear message about why." + }, + { + "comment": "When the `projectName:normalize` token is used in a cache ID, remove the `@` character from the scope." + }, + { + "comment": "Reduce default maxInstallAttempts to 1" + }, + { + "comment": "Improve logging of file locations when using the Heft build tool" + } + ] + } + }, + { + "version": "5.74.0", + "tag": "@microsoft/rush_v5.74.0", + "date": "Fri, 10 Jun 2022 22:17:51 GMT", + "comments": {} + }, + { + "version": "5.73.0", + "tag": "@microsoft/rush_v5.73.0", + "date": "Fri, 10 Jun 2022 21:54:49 GMT", + "comments": {} + }, + { + "version": "5.72.0", + "tag": "@microsoft/rush_v5.72.0", + "date": "Fri, 10 Jun 2022 20:01:47 GMT", + "comments": { + "none": [ + { + "comment": "Introduce a \"rush-pnpm\" shell command for invoking native PNPM commands in a Rush workspace" + } + ] + } + }, + { + "version": "5.71.0", + "tag": "@microsoft/rush_v5.71.0", + "date": "Fri, 27 May 2022 00:50:06 GMT", + "comments": { + "none": [ + { + "comment": "Write local telemetry for all phased commands, including partial runs when running in watch mode." + }, + { + "comment": "Export the list of workspace packages to the pnpmfile shim." + } + ] + } + }, + { + "version": "5.70.0", + "tag": "@microsoft/rush_v5.70.0", + "date": "Wed, 11 May 2022 22:21:40 GMT", + "comments": { + "none": [ + { + "comment": "Add a new `afterExecuteOperations` hook to phased command execution. This hook is used for the console timeline view and the standard result summary." + } + ] + } + }, + { + "version": "5.69.0", + "tag": "@microsoft/rush_v5.69.0", + "date": "Tue, 10 May 2022 01:20:58 GMT", + "comments": { + "none": [ + { + "comment": "Fix handling of erroneous undefined values when printing `rush list --detailed`" + }, + { + "comment": "Update watcher to only schedule operations impacted by the detected change. A behavior difference will only be observed for repositories that define a phase with no dependencies." + }, + { + "comment": "Fix handing of the `strictPeerDependencies` option when using PNPM >= 7.0.0." + }, + { + "comment": "Update the `postRushInstall` hook to always run, and move its execution to after telemetry is written." + }, + { + "comment": "(BREAKING CHANGE) Remove the \"xstitchPreferredVersions\" property from common-versions.json and the CommonVersionsConfiguration API." + }, + { + "comment": "Correct a warning that is printed during \"rush change\" to only be concerned with unstaged changes." + }, + { + "comment": "Include tags in the `rush list` output." + } + ] + } + }, + { + "version": "5.68.2", + "tag": "@microsoft/rush_v5.68.2", + "date": "Fri, 06 May 2022 18:54:55 GMT", + "comments": { + "none": [ + { + "comment": "Provide ability for phased script commands to internally invoke \"rush install\" prior to execution." + } + ] + } + }, + { + "version": "5.68.1", + "tag": "@microsoft/rush_v5.68.1", + "date": "Tue, 03 May 2022 21:52:56 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush list --json\" prints non-json output in a repo that uses rush plugins with autoinstallers." + } + ] + } + }, + { + "version": "5.68.0", + "tag": "@microsoft/rush_v5.68.0", + "date": "Fri, 29 Apr 2022 05:22:05 GMT", + "comments": { + "none": [ + { + "comment": "Disable legacy skip logic when build cache is enabled." + }, + { + "comment": "Report status of projects with an empty script as \"did not define any work,\" instead of as \"from cache.\"" + }, + { + "comment": "Add a -- parameter to git command invocations that accept user input to prevent arbitrary arguments from being passed." + }, + { + "comment": "Remove the @deprecated label from `RushConfigurationProject.packageJson`." + } + ] + } + }, + { + "version": "5.67.0", + "tag": "@microsoft/rush_v5.67.0", + "date": "Sat, 23 Apr 2022 02:13:20 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade \"tar\" dependency to eliminate spurious security vulnerability for \"minimist\" package" + }, + { + "comment": "Remove requirement that custom parameters associated with a phased command must also be associated with one or more phases. This allows for custom parameters that will only be interpreted by plugins." + } + ] + } + }, + { + "version": "5.66.2", + "tag": "@microsoft/rush_v5.66.2", + "date": "Tue, 12 Apr 2022 02:58:47 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where running the \"install-run-rush\" script with the \"--help\" parameter won't install Rush." + } + ] + } + }, + { + "version": "5.66.1", + "tag": "@microsoft/rush_v5.66.1", + "date": "Tue, 12 Apr 2022 01:52:38 GMT", + "comments": { + "none": [ + { + "comment": "Fix watch-mode phased commands when rush.json is not in the repository root. Fix watch-mode change detection on Linux." + } + ] + } + }, + { + "version": "5.66.0", + "tag": "@microsoft/rush_v5.66.0", + "date": "Sat, 09 Apr 2022 02:24:40 GMT", + "comments": { + "none": [ + { + "comment": "(BREAKING CHANGE) Update references to the default branch to reference \"main\" instead of \"master\"." + } + ] + } + }, + { + "version": "5.65.1", + "tag": "@microsoft/rush_v5.65.1", + "date": "Fri, 08 Apr 2022 23:10:18 GMT", + "comments": {} + }, + { + "version": "5.65.0", + "tag": "@microsoft/rush_v5.65.0", + "date": "Fri, 08 Apr 2022 06:16:59 GMT", + "comments": { + "none": [ + { + "comment": "Expose APIs for managing Azure credentials from @rushstack/rush-azure-storage-build-cache-plugin." + }, + { + "comment": "Add flushTelemetry hook" + }, + { + "comment": "Fix an edge case where `rush update` fails in a PNPM workspaces repo with no dependencies." + }, + { + "comment": "Fix some issues with \"rush add\"'s ability to determine which version to use when adding a dependency that is already present in the repo." + }, + { + "comment": "Add support for percentage values for --parallelism flag, eg. \"50%\"." + }, + { + "comment": "Improve retry logic in the Amazon S3 cloud cache plugin and improve reporting when the user is not authenticated." + }, + { + "comment": "Add an additional plugin to rush-azure-storage-build-cache-plugin that can be used to prompt for Azure authentication before a command runs." + }, + { + "comment": "Change the way \"rush change\" prints long lists of package names to include an \"(and more)\" line after the first five listed by name." + }, + { + "comment": "Add a \"tags\" field to project definitions in rush.json. These may be used to select projects, for example, \"rush list --only tag:my-custom-tag\"." + }, + { + "comment": "Fix a typo in output of `rush change -v`" + } + ] + } + }, + { + "version": "5.64.0", + "tag": "@microsoft/rush_v5.64.0", + "date": "Fri, 01 Apr 2022 04:51:31 GMT", + "comments": { + "none": [ + { + "comment": "Add support for suppressing startup information to invocations of `rush`, `rushx`, and the `install-run-rush` scripts." + }, + { + "comment": "Add --timeline option for more detail generated at end of rush build" + }, + { + "comment": "Expose plugin hooks for phased command execution: the \"createOperations\" hook allows customizing the set of operations to execute, and the \"waitingForChanges\" hook gives plugins an opportunity to display data to the console while output is paused." + } + ] + } + }, + { + "version": "5.63.1", + "tag": "@microsoft/rush_v5.63.1", + "date": "Sat, 26 Mar 2022 00:47:39 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the build cache is never written to." + } + ], + "none": [ + { + "comment": "Fix broken README links for @microsoft/rush-lib documentation and API reference." + } + ] + } + }, + { + "version": "5.63.0", + "tag": "@microsoft/rush_v5.63.0", + "date": "Tue, 15 Mar 2022 19:18:12 GMT", + "comments": { + "none": [ + { + "comment": "Reinstall automatically if monorepo folder is moved" + }, + { + "comment": "Fix resolution of change file paths when rush.json is not in the root of the Git repository." + }, + { + "comment": "Fix the \"selected operations\" logging for commands that skipped projects to only display the operations that will be executed." + }, + { + "comment": "For watch mode commands, allow the command to continue even if the initial build fails." + }, + { + "comment": "Allow adding of aliased child packages." + }, + { + "comment": "Add plugin hooks for global and phased commands and allow plugins to tap into command execution by command name, or into the execution of any command by command kind." + }, + { + "comment": "Fix a typo in the \"rush add\" command-line help." + } + ] + } + }, + { + "version": "5.62.4", + "tag": "@microsoft/rush_v5.62.4", + "date": "Tue, 15 Feb 2022 01:40:57 GMT", + "comments": { + "none": [ + { + "comment": "Remove the lib/index.mjs file from the @rushstack/rush-sdk package. This package must be CommonJS." + }, + { + "comment": "Do not load the PowerShell User Profile for running the AsyncRecycler task" + } + ] + } + }, + { + "version": "5.62.3", + "tag": "@microsoft/rush_v5.62.3", + "date": "Fri, 11 Feb 2022 02:18:05 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the git tag would not include the prerelease portion of the version, which will cause subsequent publishes of the same version to not be tagged." + } + ] + } + }, + { + "version": "5.62.2", + "tag": "@microsoft/rush_v5.62.2", + "date": "Thu, 10 Feb 2022 03:21:41 GMT", + "comments": { + "none": [ + { + "comment": "Add the ability to forcibly replace bad cache entries generated by issues in a previous Rush release." + }, + { + "comment": "Fix an issue where the dependencies of lockstep-versioned projects aren't bumped when the lockstep-versioned projects' versions are bumped. This issue only arose in the scenario when the lockstep-versioned projects' version bumps are driven by the change type in the changefiles and not by the \"nextBump\" property in \"common/config/rush/version-policies.json\"" + }, + { + "comment": "Fix an issue where \"rush setup\" reported a TypeError when invoked from Git Bash" + }, + { + "comment": "Fix a bug where `rush change --verify` would not find the correct `common/changes` folder if the `rush.json` is not in the Git repo's root folder." + }, + { + "comment": "Add support for rush-sdk to be bundled with Webpack." + }, + { + "comment": "Add watch mode support to \"phased\" command definitions via the \"watchOptions\" property with a subfield \"watchPhases\". This separates the initial command phases from the phases run by the file watcher, e.g. so that the initial execution can pull from cache and the watch mode execution can use a separate incremental build phase." + } + ] + } + }, + { + "version": "5.62.1", + "tag": "@microsoft/rush_v5.62.1", + "date": "Sun, 06 Feb 2022 04:59:08 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where cache entries in certain circumstances would be missing files in nested subfolders. For full details see https://github.com/microsoft/rushstack/pull/3211." + } + ] + } + }, + { + "version": "5.62.0", + "tag": "@microsoft/rush_v5.62.0", + "date": "Sat, 05 Feb 2022 00:55:18 GMT", + "comments": { + "none": [ + { + "comment": "Add support for directly invoking a script that depends on `rush-sdk` from inside a Rush repo." + }, + { + "comment": "Add support for a new URL-based version specifier in PNPM lockfiles." + }, + { + "comment": "Add support for specifying a custom S3 endpoint. This is useful for using a custom S3 provider." + }, + { + "comment": "Optimize invocation of tar to use stdin instead of a temporary file." + }, + { + "comment": "Revise architecture of symbolic link scan to use a queue and parallel file system calls." + }, + { + "comment": "Create separate tar logs per phase based on cache id." + }, + { + "comment": "Pack tar to a temp file, then move into the cache to ensure cache integrity." + }, + { + "comment": "Fix git-hooks folder check failing when compared paths have different drive letter casing" + } + ] + } + }, + { + "version": "5.61.4", + "tag": "@microsoft/rush_v5.61.4", + "date": "Wed, 02 Feb 2022 04:03:24 GMT", + "comments": { + "none": [ + { + "comment": "Bump tar dependency to have a minimum version of 5.0.10." + } + ] + } + }, + { + "version": "5.61.3", + "tag": "@microsoft/rush_v5.61.3", + "date": "Fri, 28 Jan 2022 21:03:58 GMT", + "comments": { + "none": [ + { + "comment": "Update the built-in cache provider plugins (rush-amazon-s3-build-cache-plugin and rush-azure-storage-build-cache-plugin) to apply for all commands, enabling cloud caching for custom phased and bulk commands." + }, + { + "comment": "Allow build cache to be enabled for custom bulk commands." + } + ] + } + }, + { + "version": "5.61.2", + "tag": "@microsoft/rush_v5.61.2", + "date": "Thu, 27 Jan 2022 02:30:10 GMT", + "comments": { + "none": [ + { + "comment": "Update node-fetch dependency version to address CVE-2022-0235" + } + ] + } + }, + { + "version": "5.61.1", + "tag": "@microsoft/rush_v5.61.1", + "date": "Sat, 22 Jan 2022 04:22:52 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Allow common/config/rush/command-line.json to specify the build command as a phased command without specifying all of the options required by the schema. The remaining options will come from the default. This is already supported when a partially-specified build command has \"commandKind\" set to \"bulk\"." + }, + { + "comment": "Fix an issue where Git Bash \"tar\" does not handle Windows paths correctly." + }, + { + "comment": "(EXPERIMENTAL) Improve the RUSH_BUILD_CACHE_WRITE_ALLOWED environment variable behavior so that it also affects the local build cache. This saves CPU cycles on CI machines that only run a single build. It also avoids cache writes for watch mode commands." + }, + { + "comment": "Refactoring to support upcoming watch mode improvements: Rework the task execution engine to interact with the task queue using the ECMAScript async iteration protocol (GitHub #3043)" + }, + { + "comment": "Fix project change detection when a new project is added to a repo that uses PNPM with useWorkspaces=false (GitHub #3183)" + } + ] + } + }, + { + "version": "5.61.0", + "tag": "@microsoft/rush_v5.61.0", + "date": "Sat, 22 Jan 2022 03:17:59 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Fix a regression for the plugins feature, which caused an error message \"command-line.json defines a command 'build' using a name that already exists\" (GitHub #3155)" + } + ] + } + }, + { + "version": "5.60.0", + "tag": "@microsoft/rush_v5.60.0", + "date": "Thu, 20 Jan 2022 02:46:15 GMT", + "comments": { + "none": [ + { + "comment": "Fix the \"allowWarningsInSuccessfulBuild\" option in bulk commands defined in common/config/command-line.json." + }, + { + "comment": "(BREAKING CHANGE) The experimental config file options \"skipPhasesForCommand\" and \"addPhasesToCommand\" have been temporarily removed until their design can be better formalized." + }, + { + "comment": "Include NodeJS 16 in the range of supported versions (`nodeSupportedVersionRange`) in the `rush.json` file generated by `rush init`." + }, + { + "comment": "(BREAKING CHANGE) Some experimental fields have been renamed in \"config/rush-project.json\". Please see UPGRADING.md for details." + } + ] + } + }, + { + "version": "5.59.2", + "tag": "@microsoft/rush_v5.59.2", + "date": "Fri, 07 Jan 2022 02:34:59 GMT", + "comments": { + "none": [ + { + "comment": "Fixes a regression that broke \"rush build\" completely when not using the \"--only\" parameter." + } + ] + } + }, + { + "version": "5.59.1", + "tag": "@microsoft/rush_v5.59.1", + "date": "Fri, 07 Jan 2022 01:21:44 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes a regression in bulk command execution when using \"unsafe\" selector parameters, e.g. \"--only\". Ensures that only the projects selected by the parameters get included in the build, rather that forcibly including all dependencies." + } + ] + } + }, + { + "version": "5.59.0", + "tag": "@microsoft/rush_v5.59.0", + "date": "Thu, 06 Jan 2022 22:18:13 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue that occurs when running a command with a selection argument with a Git ref (like `--from git:main`) in a repo with a pnpm lockfile larger than 1MB." + }, + { + "comment": "Fix an issue with installing Git hooks that occurs when the rush.json folder isn't at the repo's root." + }, + { + "comment": "(BREAKING CHANGE) Remove the experimental command \"rush write-build-cache\", since it is no longer needed and would be incompatible with phased builds. If you need this command for some reason, please create a GitHub issue." + }, + { + "comment": "Add support for phased commands behind the multiPhaseCommands experiment." + }, + { + "comment": "Update \"rush init\" to write files with OS-default line endings (CRLF on Windows, LF otherwise) instead of always writing CRLF line endings." + } + ], + "minor": [ + { + "comment": "Update the \"rush init\" template to enable pnpm workspaces and to merge the pnpm-lock.yaml file as text." + } + ] + } + }, + { + "version": "5.58.0", + "tag": "@microsoft/rush_v5.58.0", + "date": "Thu, 16 Dec 2021 05:39:21 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush's Git hooks were broken if another tool such as Husky had tampered with the `core.hooksPath` (GitHub #3004)" + }, + { + "comment": "Provide a more useful error message if the git version is too old." + }, + { + "comment": "Allow \"rush list\" to be invoked while other rush processes are running in the same repo." + }, + { + "comment": "For project selection parameters such as \"rush build --to git:REF\", improve the diff analysis to detect which individual projects are impacted by a modification of the PNPM lockfile (GitHub #3050)" + }, + { + "comment": "Allow multiple remote URLs to be specified in the rush.json in the new repository.urls field." + }, + { + "comment": "(BREAKING CHANGE) Replace the RushConfiguration repositoryUrl field with repositoryUrls to support multiple remote URLs specified in rush.json." + } + ] + } + }, + { + "version": "5.57.1", + "tag": "@microsoft/rush_v5.57.1", + "date": "Thu, 09 Dec 2021 00:24:47 GMT", + "comments": {} + }, + { + "version": "5.57.0", + "tag": "@microsoft/rush_v5.57.0", + "date": "Fri, 03 Dec 2021 02:16:10 GMT", + "comments": { + "none": [ + { + "comment": "Add support for the \"filterLog\" hook in common/config/rush/.pnpmfile.cjs" + }, + { + "comment": "(EXPERIMENTAL) Ability to load third-party plugin packages that customize the behavior of Rush" + }, + { + "comment": "Fix an issue where parameter values containing spaces are incorrectly passed to global scripts." + }, + { + "comment": "Parameters such as \"--to\" and \"--from\" now accept selector expressions: \"version-policy:NAME\" indicates the set of projects belonging to a publishing version policy. \"git:REF\" detects the set of projects that have been modified since the specified Git revision; for example, this allows a Rush command to process only the projects modified by a PR branch. (GitHub #2968)" + }, + { + "comment": "Improved the change detection logic to work correctly when a second rush.json appears in a subfolder." + }, + { + "comment": "(EXPERIMENTAL) Add a new NPM package \"@rushstack/rush-sdk\" for use by Rush plugins" + }, + { + "comment": "Stop deleting the pnpm-store after failed workspace installs. Usually a multiple failure is due to a network error or a package that does not exist in the registry, not an issue with the pnpm-store." + } + ] + } + }, + { + "version": "5.56.0", + "tag": "@microsoft/rush_v5.56.0", + "date": "Thu, 28 Oct 2021 23:49:31 GMT", + "comments": { + "none": [ + { + "comment": "Add CI skipping to default version & changelog commits" + }, + { + "comment": "Update suggested version of NPM" + }, + { + "comment": "Fix update-autoinstaller with NPM" + }, + { + "comment": "Streamline rushx output and add quiet flag." + }, + { + "comment": "Include support for adding multiple packages with the \"rush add\" command." + }, + { + "comment": "Update the package.json repository field to include the directory property." + }, + { + "comment": "Fix the error message printed when `--interactive` is passed to `rush update-cloud-credentials` and the cloud cache provider is Amazon S3." + }, + { + "comment": "Mark Node 16 as the current latest LTS version." + }, + { + "comment": "support `--debug-package-manager` install options for yarn" + } + ] + } + }, + { + "version": "5.55.1", + "tag": "@microsoft/rush_v5.55.1", + "date": "Tue, 12 Oct 2021 22:26:25 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where a version field isn't parsed correctly when using NPM version 7 and newer." + } + ] + } + }, + { + "version": "5.55.0", + "tag": "@microsoft/rush_v5.55.0", + "date": "Thu, 07 Oct 2021 23:44:52 GMT", + "comments": { + "none": [ + { + "comment": "Fix typo when project dependencies do not match the current shrinkwrap" + }, + { + "comment": "Use ITerminal in the rush-lib API instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + }, + { + "comment": "Add a new parameter \"--detailed\" for the \"rush list\" command" + }, + { + "comment": "Print the full event hooks output if the --debug paramter is specified." + }, + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ] + } + }, + { + "version": "5.54.0", + "tag": "@microsoft/rush_v5.54.0", + "date": "Wed, 22 Sep 2021 22:54:17 GMT", + "comments": { + "none": [ + { + "comment": "Add a \"--check-only\" parameter to \"rush install\" to check the validity of the shrinkwrap without performing a full install." + }, + { + "comment": "Fix an issue where `rush update-autoinstaller` does not use the repo's .npmrc" + } + ], + "minor": [ + { + "comment": "Add ability to customize tag separator" + } + ], + "patch": [ + { + "comment": "Lock node-fetch dependency to 2.6.2 due to an incompatibility with 2.6.3 in the Azure Cloud Cache Provider." + } + ] + } + }, + { + "version": "5.53.0", + "tag": "@microsoft/rush_v5.53.0", + "date": "Fri, 10 Sep 2021 23:20:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the incremental build should use caching or skipping, but not both (GitHub #2891)" + }, + { + "comment": "Cache rush-project.json reads" + }, + { + "comment": "Fix an issue where the build cache did not respect \"allowWarningsInSuccessfulBuild\" (GitHub #2803)" + }, + { + "comment": "Add an experiment \"buildCacheWithAllowWarningsInSuccessfulBuild\" to allow caching for projects with warnings (GitHub #2803)" + } + ] + } + }, + { + "version": "5.52.0", + "tag": "@microsoft/rush_v5.52.0", + "date": "Mon, 23 Aug 2021 21:34:46 GMT", + "comments": { + "none": [ + { + "comment": "Add properties to the extraData section of the telemetry file for parameter usage in the install commands" + }, + { + "comment": "Add .heft to .gitignore file generated by rush init" + } + ] + } + }, + { + "version": "5.51.1", + "tag": "@microsoft/rush_v5.51.1", + "date": "Fri, 13 Aug 2021 22:45:36 GMT", + "comments": { + "none": [ + { + "comment": "When build cache is enabled in `rush build`, allow projects downstream to be satisfied from the cache if applicable. Cache reads will still be disabled for `rush rebuild`." + } + ] + } + }, + { + "version": "5.51.0", + "tag": "@microsoft/rush_v5.51.0", + "date": "Wed, 11 Aug 2021 23:16:09 GMT", + "comments": { + "none": [ + { + "comment": "The --debug flag now also shows additional diagnostic information." + }, + { + "comment": "Update JSZip dependency." + }, + { + "comment": "Adds support for the project subset selection parameters (\"--to\", \"--from\", etc., documented at https://rushjs.io/pages/developer/selecting_subsets/) to the \"rush list\" command." + }, + { + "comment": "Allow the tar binary path to be overridden via the RUSH_TAR_BINARY_PATH environment variable." + } + ] + } + }, + { + "version": "5.50.0", + "tag": "@microsoft/rush_v5.50.0", + "date": "Sat, 17 Jul 2021 01:16:04 GMT", + "comments": { + "patch": [ + { + "comment": "When the experimental build cache is enabled, \"rush rebuild\" now forces cached projects to be rebuilt (GitHub #2802)" + } + ], + "minor": [ + { + "comment": "(Breaking change) Remove the experimental \"--disable-build-cache\" command line parameter." + } + ] + } + }, + { + "version": "5.49.2", + "tag": "@microsoft/rush_v5.49.2", + "date": "Thu, 15 Jul 2021 01:47:18 GMT", + "comments": { + "none": [ + { + "comment": "Fix incremental build state calculation when using filtered installs" + } + ] + } + }, + { + "version": "5.49.1", + "tag": "@microsoft/rush_v5.49.1", + "date": "Tue, 13 Jul 2021 23:03:01 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the \"--no-fetch\" \"rush change\" parameter would cause a \"git fetch\" and absence of that parameter wouldn't fetch." + } + ] + } + }, + { + "version": "5.49.0", + "tag": "@microsoft/rush_v5.49.0", + "date": "Tue, 13 Jul 2021 06:22:09 GMT", + "comments": { + "none": [ + { + "comment": "Expose APIs useful for determining which projects have changed on the current branch compared to another branch." + } + ] + } + }, + { + "version": "5.48.0", + "tag": "@microsoft/rush_v5.48.0", + "date": "Fri, 09 Jul 2021 01:44:18 GMT", + "comments": { + "none": [ + { + "comment": "Add RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD environment variable" + }, + { + "comment": "Prevent \"rush change\" from prompting for an email address, since this feature was rarely used. To restore the old behavior, enable the \"includeEmailInChangeFile\" setting in version-policies.json" + }, + { + "comment": "The \"rushx\" command now reports a warning when invoked in a project folder that is not registered in rush.json" + }, + { + "comment": "Fix the build-cache.json cacheEntryNamePattern description of the [normalize] token." + }, + { + "comment": "When selection CLI parameters are specified and applying them does not select any projects, log that the selection is empty and immediately exit." + }, + { + "comment": "Fix an issue where files restored by the build cache did not have a current modification time" + }, + { + "comment": "Upgrade the \"rush init\" template to use PNPM version 6.7.1; this avoids an important regression in PNPM 6.3.0 where .pnpmfile.cjs did not work correctly: https://github.com/pnpm/pnpm/issues/3453" + }, + { + "comment": "Fix a JSON schema issue that prevented \"disableBuildCache\" from being specified in command-line.json" + }, + { + "comment": "Removed dependency on chokidar from BulkScriptAction in watch mode, since it adds unnecessary overhead." + } + ] + } + }, + { + "version": "5.47.0", + "tag": "@microsoft/rush_v5.47.0", + "date": "Sat, 15 May 2021 00:02:26 GMT", + "comments": { + "none": [ + { + "comment": "For the experimental build cache feature, eliminate the RUSH_BUILD_CACHE_WRITE_CREDENTIAL environment variable; it is replaced by several new variables RUSH_BUILD_CACHE_CREDENTIAL, RUSH_BUILD_CACHE_WRITE_ALLOWED, and RUSH_BUILD_CACHE_ENABLED" + }, + { + "comment": "Take pnpm-workspace.yaml file into consideration during install skip checks for PNPM" + }, + { + "comment": "Fix a build cache warning that was sometimes displayed on Windows OS: \"'tar' exited with code 1 while attempting to create the cache entry\" (GitHub #2622)" + }, + { + "comment": "Fix an issue where \"rushx\" CLI arguments were not escaped properly (GitHub #2695)" + }, + { + "comment": "Allow rush-project.json to specify incrementalBuildIgnoredGlobs (GitHub issue #2618)" + }, + { + "comment": "Remove support for PNPM < 5.0.0 and remove the \"resolutionStrategy\" option" + }, + { + "comment": "Update \"rush init\" assets to use newer versions of Rush and PNPM. If you are looking to use PNPM < 6, you must rename the initialized \".pnpmfile.cjs\" file to \"pnpmfile.js\". For more information, see: https://pnpm.io/5.x/pnpmfile" + }, + { + "comment": "Transform package.json using pnpmfile before checking if a Rush project is up-to-date" + }, + { + "comment": "Add support for the Yarn \"resolutions\" package.json feature." + } + ] + } + }, + { + "version": "5.46.1", + "tag": "@microsoft/rush_v5.46.1", + "date": "Tue, 04 May 2021 20:26:15 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the buildCacheEnabled setting was not applied correctly" + } + ] + } + }, + { + "version": "5.46.0", + "tag": "@microsoft/rush_v5.46.0", + "date": "Tue, 04 May 2021 02:45:20 GMT", + "comments": { + "none": [ + { + "comment": "Remove \"buildCache\" setting from experiments.json; it is superseded by \"buildCacheEnabled\" in build-cache.json" + }, + { + "comment": "Add a \"rush init\" template for build-cache.json" + }, + { + "comment": "Temporarily downgrade the \"@azure/identity\" to eliminate the keytar native dependency (GitHub issue #2492)" + } + ] + } + }, + { + "version": "5.45.6", + "tag": "@microsoft/rush_v5.45.6", + "date": "Fri, 30 Apr 2021 00:32:16 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression in the S3 cloud build cache provider" + } + ] + } + }, + { + "version": "5.45.5", + "tag": "@microsoft/rush_v5.45.5", + "date": "Wed, 28 Apr 2021 17:54:16 GMT", + "comments": { + "none": [ + { + "comment": "Improve diagnostic messages printed by the rush build cache" + }, + { + "comment": "Fix an issue where Rush fails to run on Windows when the repository absolute path contains a space" + }, + { + "comment": "Use simpler and more accurate check before skipping installs" + } + ] + } + }, + { + "version": "5.45.4", + "tag": "@microsoft/rush_v5.45.4", + "date": "Fri, 23 Apr 2021 22:48:23 GMT", + "comments": {} + }, + { + "version": "5.45.3", + "tag": "@microsoft/rush_v5.45.3", + "date": "Fri, 23 Apr 2021 22:03:08 GMT", + "comments": { + "none": [ + { + "comment": "Allow prerelease versions of PNPM to be used in workspaces mode" + } + ] + } + }, + { + "version": "5.45.2", + "tag": "@microsoft/rush_v5.45.2", + "date": "Thu, 22 Apr 2021 23:07:51 GMT", + "comments": { + "none": [ + { + "comment": "Fix bad installs with when using pnpmfile in PNPM 6" + } + ] + } + }, + { + "version": "5.45.1", + "tag": "@microsoft/rush_v5.45.1", + "date": "Wed, 21 Apr 2021 23:38:22 GMT", + "comments": { + "none": [ + { + "comment": "Ensure that pnpm-workspace.yaml is always fully regenerated during \"rush install\" or \"rush update\"" + }, + { + "comment": "Fix support for pnpmfile in PNPM 6." + } + ] + } + }, + { + "version": "5.45.0", + "tag": "@microsoft/rush_v5.45.0", + "date": "Tue, 20 Apr 2021 19:04:04 GMT", + "comments": { + "none": [ + { + "comment": "Print diagnostic information to a log file \"/.rush/build-cache-tar.log\" when the native \"tar\" is invoked." + }, + { + "comment": "The Amazon S3 build cloud cache provider can now use buckets outside the default region" + }, + { + "comment": "Add support for PNPM 6" + } + ] + } + }, + { + "version": "5.44.0", + "tag": "@microsoft/rush_v5.44.0", + "date": "Sat, 17 Apr 2021 00:17:51 GMT", + "comments": { + "none": [ + { + "comment": "Add --json and --all param to rush scan" + }, + { + "comment": "Fix \"rush deploy\" having \"includeDevDependencies\" turned on to deploy \"devDependencies\" for rush projects only" + } + ] + } + }, + { + "version": "5.43.0", + "tag": "@microsoft/rush_v5.43.0", + "date": "Thu, 08 Apr 2021 06:09:52 GMT", + "comments": { + "none": [ + { + "comment": "Add \"--ignore-git-hooks\" flags to \"publish\" and \"version\" commands to prevent the execution of all git hooks" + }, + { + "comment": "Fix parameter name typo." + }, + { + "comment": "Eliminate a spurious warning that was displayed on Azure DevOps build agents: A phantom \"node_modules\" folder was found." + }, + { + "comment": "Fix an issue where \"rush change\" reported \"Unable to find a git remote matching the repository URL\" when used with SSH auth" + }, + { + "comment": "Fix an issue where \"rush publish\" reported 403 errors if the package version included a SemVer build metadata suffix" + }, + { + "comment": "Partially deprecate RUSH_TEMP_FOLDER environment variable" + }, + { + "comment": "Validate changefiles against a schema when running 'rush change --verify'" + } + ] + } + }, + { + "version": "5.42.4", + "tag": "@microsoft/rush_v5.42.4", + "date": "Mon, 29 Mar 2021 05:57:18 GMT", + "comments": { + "none": [ + { + "comment": "Don't validate the shrinkwrap when running 'rush update'" + }, + { + "comment": "Gracefully handle a simultaneous upload to Azure Storage." + }, + { + "comment": "Update rush publish -p flag description" + } + ] + } + }, + { + "version": "5.42.3", + "tag": "@microsoft/rush_v5.42.3", + "date": "Wed, 17 Mar 2021 05:07:02 GMT", + "comments": { + "none": [ + { + "comment": "Fix installation-time behavior of \"omitImportersFromPreventManualShrinkwrapChanges\" experiment." + }, + { + "comment": "Don't upload build cache entries to Azure if the cache entry already exists." + }, + { + "comment": "Replace the AWS dependencies with use of the Amazon S3 REST API." + }, + { + "comment": "Add support for anonymous read from an Amazon S3-hosted cache." + } + ] + } + }, + { + "version": "5.42.2", + "tag": "@microsoft/rush_v5.42.2", + "date": "Tue, 16 Mar 2021 00:30:38 GMT", + "comments": { + "none": [ + { + "comment": "Add experiment to exclude the \"importers\" section of \"pnpm-lock.yaml\" from the \"preventManualShrinkwrapChanges\" feature." + } + ] + } + }, + { + "version": "5.42.1", + "tag": "@microsoft/rush_v5.42.1", + "date": "Fri, 12 Mar 2021 02:11:24 GMT", + "comments": { + "none": [ + { + "comment": "Temporarily disable the AWS S3 credential provider logic to mitigate a problematic peer dependency (GitHub #2547)" + } + ] + } + }, + { + "version": "5.42.0", + "tag": "@microsoft/rush_v5.42.0", + "date": "Wed, 10 Mar 2021 06:25:44 GMT", + "comments": { + "none": [ + { + "comment": "Add AWS S3 support to the experimental build cache feature" + } + ] + } + }, + { + "version": "5.41.0", + "tag": "@microsoft/rush_v5.41.0", + "date": "Wed, 10 Mar 2021 05:12:41 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush install\" could stall indefinitely because a network request did not handle timeouts properly" + }, + { + "comment": "Allow merge conflicts in repo-state.json to be automatically resolved." + }, + { + "comment": "Add a RUSH_INVOKED_FOLDER environment variable so that custom scripts can determine the folder path where Rush was invoked (GitHub #2497)" + }, + { + "comment": "Add `preferFrozenLockfileForUpdate` option to minimize lockfile churn by passing --prefer-frozen-lockfile to pnpm during default `rush update`." + } + ] + } + }, + { + "version": "5.40.7", + "tag": "@microsoft/rush_v5.40.7", + "date": "Tue, 02 Mar 2021 23:27:41 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression where certain Rush operations reported a TypeError (GitHub #2526)" + } + ] + } + }, + { + "version": "5.40.6", + "tag": "@microsoft/rush_v5.40.6", + "date": "Tue, 02 Mar 2021 06:22:01 GMT", + "comments": { + "none": [ + { + "comment": "Improve cache read/write perf by attempting to use the \"tar\" binary." + }, + { + "comment": "Fix default text in rush.json generated by \"rush init.\"" + }, + { + "comment": "Fix an issue where Rush would fail to restore from cache but report success when Git isn't present." + } + ] + } + }, + { + "version": "5.40.5", + "tag": "@microsoft/rush_v5.40.5", + "date": "Tue, 23 Feb 2021 03:26:25 GMT", + "comments": { + "none": [ + { + "comment": "Account for indirect dependencies when ordering projects in \"rush build\" if the intermediary dependencies are excluded by selection parameters." + } + ] + } + }, + { + "version": "5.40.4", + "tag": "@microsoft/rush_v5.40.4", + "date": "Tue, 23 Feb 2021 00:01:20 GMT", + "comments": { + "none": [ + { + "comment": "Make Rush per-project manifest generation more reliable and remove PNPM shrinkwrap validation" + } + ] + } + }, + { + "version": "5.40.3", + "tag": "@microsoft/rush_v5.40.3", + "date": "Sun, 21 Feb 2021 01:05:53 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush setup\" did not work correctly with NPM 7.x due to an NPM regression" + } + ] + } + }, + { + "version": "5.40.2", + "tag": "@microsoft/rush_v5.40.2", + "date": "Fri, 19 Feb 2021 06:28:28 GMT", + "comments": { + "none": [ + { + "comment": "Allow usage of Node.js 8.x since we received feedback that some projects are still supporting it" + } + ] + } + }, + { + "version": "5.40.1", + "tag": "@microsoft/rush_v5.40.1", + "date": "Fri, 19 Feb 2021 01:45:27 GMT", + "comments": { + "none": [ + { + "comment": "Fix a minor issue with the \"rush init\" template" + } + ] + } + }, + { + "version": "5.40.0", + "tag": "@microsoft/rush_v5.40.0", + "date": "Wed, 17 Feb 2021 01:35:11 GMT", + "comments": {} + }, + { + "version": "5.39.2", + "tag": "@microsoft/rush_v5.39.2", + "date": "Wed, 17 Feb 2021 01:34:11 GMT", + "comments": { + "none": [ + { + "comment": "(EXPERIMENTAL) Add a \"--disable-cache\" parameter for disabling the build cache." + }, + { + "comment": "(EXPERIMENTAL) Add a \"disableBuildCache\" setting in command-line.json for disabling the build cache." + }, + { + "comment": "(EXPERIMENTAL) Add options in rush-project.json for disabling the build cache for entire projects, or for individual commands for that project." + }, + { + "comment": "Normalize selection CLI parameters for \"rush install\"" + }, + { + "comment": "Add experimental \"rush setup\" command" + }, + { + "comment": "Add an experimental new config file common/config/artifactory.json for enabling Artifactory integration" + } + ] + } + }, + { + "version": "5.39.1", + "tag": "@microsoft/rush_v5.39.1", + "date": "Sat, 13 Feb 2021 03:14:52 GMT", + "comments": { + "none": [ + { + "comment": "Disable build cache after initial build when \"--watch\" is specified. This saves disk space, reduces CPU usage, and improves compatibility with downstream file watcher processes (e.g. \"webpack --watch\")." + } + ], + "patch": [ + { + "comment": "Convert the experimental \"--watch\" parameter into a \"watchForChanges: true\" setting in command-line.json, based on user feedback" + } + ] + } + }, + { + "version": "5.39.0", + "tag": "@microsoft/rush_v5.39.0", + "date": "Thu, 11 Feb 2021 04:06:02 GMT", + "comments": { + "none": [ + { + "comment": "Improve the wording of some log messages" + } + ], + "minor": [ + { + "comment": "Add a new parameter \"--watch\" that watches for filesystem changes and rebuilds the affected Rush projects; this feature can also be used with custom bulk commands (GitHub #2458, #1122)" + } + ] + } + }, + { + "version": "5.38.0", + "tag": "@microsoft/rush_v5.38.0", + "date": "Mon, 01 Feb 2021 20:42:04 GMT", + "comments": { + "none": [ + { + "comment": "Add new command-line parameters for bulk commands: \"--to-except\", \"--from\", \"--only\", \"--impacted-by\", \"--impacted-by-except\", and \"--from-version-policy\" (GitHub #2354)" + }, + { + "comment": "Change the short name for \"--changed-projects-only\" to be \"-c\" (so that \"-o\" can be used for the new \"--only\" parameter)" + }, + { + "comment": "Change the \"--from\" parameter so that it now includes all dependencies as people expected. To skip dependencies, use the new \"--impacted-by\" parameter. (GitHub issue #1447)" + } + ] + } + }, + { + "version": "5.37.0", + "tag": "@microsoft/rush_v5.37.0", + "date": "Sat, 30 Jan 2021 01:50:27 GMT", + "comments": { + "none": [ + { + "comment": "Improve performance of association of repo file states with projects to speed up build commands in large repos." + }, + { + "comment": "Add `publishFolder` property to the project configuration to allow publishing a sub-folder of the project" + }, + { + "comment": "Add support for --from flag for filtered installs when using workspaces" + }, + { + "comment": "Fix an issue where the Rush cache feature did not correctly detect files that were both tracked by git and were expected to be cached build output." + }, + { + "comment": "Improve logging for the \"rush write-build-cache\" command" + }, + { + "comment": "Correct some spelling mistakes in rush.json" + }, + { + "comment": "Fix an error \"Cannot get dependency key\" sometimes reported by \"rush install\" (GitHub #2460)" + }, + { + "comment": "Updade the \"rush init\" template to specify PNPM 5.15.2, which fixes a performance regression introduced in PNPM 5.13.7" + } + ] + } + }, + { + "version": "5.36.2", + "tag": "@microsoft/rush_v5.36.2", + "date": "Thu, 21 Jan 2021 04:51:19 GMT", + "comments": { + "none": [ + { + "comment": "Update Node.js version checks to support the new LTS release" + }, + { + "comment": "Update rush.json produced by rush init to use PNPM 5.14.3" + }, + { + "comment": "Use forward slashes when creating deploy zip file for Unix compatibility" + } + ] + } + }, + { + "version": "5.36.1", + "tag": "@microsoft/rush_v5.36.1", + "date": "Fri, 08 Jan 2021 06:12:37 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where projects with empty scripts would still have arguments appended." + } + ] + } + }, + { + "version": "5.36.0", + "tag": "@microsoft/rush_v5.36.0", + "date": "Fri, 08 Jan 2021 05:36:55 GMT", + "comments": { + "none": [ + { + "comment": " Allow the git binary path to be overridden via the RUSH_GIT_BINARY_PATH environment variable." + }, + { + "comment": "Introduce an experimental build cache feature." + }, + { + "comment": "Add the ability to customize the commit message used when \"rush version\" is run." + }, + { + "comment": "Remove the \"experimental\" label from some Rush commands that are now stable." + } + ] + } + }, + { + "version": "5.35.2", + "tag": "@microsoft/rush_v5.35.2", + "date": "Tue, 03 Nov 2020 23:34:30 GMT", + "comments": { + "none": [ + { + "comment": "Fix bug where version process is using a wrong `git.addChanges` signature" + } + ] + } + }, + { + "version": "5.35.1", + "tag": "@microsoft/rush_v5.35.1", + "date": "Fri, 30 Oct 2020 05:17:42 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent \"rush scan\" regression (which resulted from enabling \"esModuleInterop\")" + } + ] + } + }, + { + "version": "5.35.0", + "tag": "@microsoft/rush_v5.35.0", + "date": "Wed, 28 Oct 2020 21:44:10 GMT", + "comments": { + "none": [ + { + "comment": "Adds an --ignore-hooks flag to every rush action that skips event hooks during execution of the action." + }, + { + "comment": "Fix bug where version process was not adding version-policy configuration file changes into the version commit" + } + ] + } + }, + { + "version": "5.34.4", + "tag": "@microsoft/rush_v5.34.4", + "date": "Sat, 17 Oct 2020 00:23:18 GMT", + "comments": { + "none": [ + { + "comment": "When running `rush version --bump`, only include package.json updates in the generated commit" + }, + { + "comment": "Fix Rush peer dependency validation when satisfied with a package alias" + }, + { + "comment": "Prevent `rush unlink` from breaking installs for non-workspace projects" + }, + { + "comment": "Add documentation for incremental option for buld custom commands" + } + ] + } + }, + { + "version": "5.34.3", + "tag": "@microsoft/rush_v5.34.3", + "date": "Wed, 30 Sep 2020 21:04:15 GMT", + "comments": { + "none": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + }, + { + "comment": "Update README.md" + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ] + } + }, + { + "version": "5.34.2", + "tag": "@microsoft/rush_v5.34.2", + "date": "Mon, 21 Sep 2020 22:00:03 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush build\" output was lagged due to stream-collator not activating streams aggressively enough" + }, + { + "comment": "Fix incorrect \"successful\" exit status code" + } + ] + } + }, + { + "version": "5.34.1", + "tag": "@microsoft/rush_v5.34.1", + "date": "Thu, 17 Sep 2020 07:13:04 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression that reported an error \"The EnvironmentConfiguration must be initialized before values can be accessed\"" + } + ] + } + }, + { + "version": "5.34.0", + "tag": "@microsoft/rush_v5.34.0", + "date": "Thu, 17 Sep 2020 01:23:35 GMT", + "comments": { + "none": [ + { + "comment": "Big redesign of \"rush build\" console reporting (fixes GitHub #2135)" + }, + { + "comment": "Implement RUSH_GLOBAL_FOLDER environment variable (GitHub #2187)" + }, + { + "comment": "Use underscores instead of asterisks for italic formatting in changelogs to match the way Prettier formats italics in markdown." + }, + { + "comment": "In PNPM 5, --no-lock and --resolution-strategy flags have been removed. Do not pass these flags if they are not supported by the PNPM version used in the repository." + } + ] + } + }, + { + "version": "5.33.2", + "tag": "@microsoft/rush_v5.33.2", + "date": "Fri, 21 Aug 2020 22:45:58 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where PNPM would sometimes prompt for input during \"rush publish\" (GitHub #1940)" + }, + { + "comment": "Fix an issue that prevented Rush from logging in verbose mode" + } + ] + } + }, + { + "version": "5.33.1", + "tag": "@microsoft/rush_v5.33.1", + "date": "Thu, 20 Aug 2020 18:25:41 GMT", + "comments": { + "none": [ + { + "comment": "Fix issues where installs could fail after running 'rush version' while the 'usePnpmFrozenLockfileForRushInstall' experiment is enabled. See PR #2116 for more details." + }, + { + "comment": "Fix an issue where \"rush deploy\" would sometimes report an \"already exists\" when using the \"files\" setting in package.json (GitHub #2121)" + }, + { + "comment": "Allow multiple simultaneous invocations of \"rush deploy\" (GitHub #2125)" + }, + { + "comment": "Load and validate local projects lazily to further improve Rush startup times." + } + ] + } + }, + { + "version": "5.33.0", + "tag": "@microsoft/rush_v5.33.0", + "date": "Wed, 19 Aug 2020 00:17:48 GMT", + "comments": { + "none": [ + { + "comment": "Add support for shell tab completion. See PR for details: https://github.com/microsoft/rushstack/pull/2060" + }, + { + "comment": "Use Import.lazy() to optimize the startup time for Rush" + } + ] + } + }, + { + "version": "5.32.3", + "tag": "@microsoft/rush_v5.32.3", + "date": "Tue, 18 Aug 2020 03:48:56 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where install-run.js sometimes assigned the shell PATH incorrectly due to inconsistent character case" + } + ] + } + }, + { + "version": "5.32.2", + "tag": "@microsoft/rush_v5.32.2", + "date": "Fri, 14 Aug 2020 21:03:48 GMT", + "comments": { + "none": [ + { + "comment": "Resolve issue with version --bump where the wrong hash would get written to the pnpm-lock file" + } + ] + } + }, + { + "version": "5.32.1", + "tag": "@microsoft/rush_v5.32.1", + "date": "Fri, 14 Aug 2020 04:06:30 GMT", + "comments": { + "none": [ + { + "comment": "Change method used to calculate integrity of tarballs" + } + ] + } + }, + { + "version": "5.32.0", + "tag": "@microsoft/rush_v5.32.0", + "date": "Thu, 13 Aug 2020 00:53:43 GMT", + "comments": { + "patch": [ + { + "comment": "Update temp project tarball integrities during rush bump" + } + ] + } + }, + { + "version": "5.31.0", + "tag": "@microsoft/rush_v5.31.0", + "date": "Wed, 12 Aug 2020 19:33:44 GMT", + "comments": { + "none": [ + { + "comment": "Updated project to build with Heft" + }, + { + "comment": "Fix an issue where \"rushx\" did not pass additional command-line arguments to the package.json script (GitHub #1232)" + } + ] + } + }, + { + "version": "5.30.3", + "tag": "@microsoft/rush_v5.30.3", + "date": "Fri, 07 Aug 2020 21:09:05 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Mac OS sometimes reported \"An unrecognized file .DS_Store was found in the Rush config folder\"" + } + ] + } + }, + { + "version": "5.30.2", + "tag": "@microsoft/rush_v5.30.2", + "date": "Wed, 05 Aug 2020 17:57:07 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where a package version bump would not bump downstream packages with a `workspace:*` dependency specifier." + } + ] + } + }, + { + "version": "5.30.1", + "tag": "@microsoft/rush_v5.30.1", + "date": "Thu, 23 Jul 2020 23:47:59 GMT", + "comments": { + "none": [ + { + "comment": "Fixed an isssue where the \"rush build\" incremental analysis sometimes reported a warning with large diffs (GitHub #501) or filenames that contain spaces, quotes, or other unusual characters (GitHub #2007)" + }, + { + "comment": "Prevent incorrect conversion to \"workspace:\" notation for peer dependencies when running \"rush update --full\"" + } + ] + } + }, + { + "version": "5.30.0", + "tag": "@microsoft/rush_v5.30.0", + "date": "Fri, 17 Jul 2020 05:32:38 GMT", + "comments": { + "minor": [ + { + "comment": "Prepare to deprecate 'rush link' and 'rush unlink' commands, as well as the '--no-link' install argument. As we move toward using package managers more directly in Rush, the package managers will perform the linking during install (if linking is even necessary). Additionally, these commands directly conflict with (and have different meanings than) their package manager counterparts. Lastly, similar goals can be accomplished by running 'rush install' and 'rush purge'. In addition to these changes, rush-link.json deprecated and is replaced with a new API which keeps the local dependency tree in memory." + } + ] + } + }, + { + "version": "5.29.1", + "tag": "@microsoft/rush_v5.29.1", + "date": "Thu, 16 Jul 2020 02:18:39 GMT", + "comments": { + "patch": [ + { + "comment": "Consider package.json when determining if install can be skipped for PNPM workspaces" + } + ] + } + }, + { + "version": "5.29.0", + "tag": "@microsoft/rush_v5.29.0", + "date": "Tue, 14 Jul 2020 05:20:56 GMT", + "comments": { + "none": [ + { + "comment": "Give \\\"rush deploy\\\" the ability to select a subset of dependencies to copy over (#1978)" + }, + { + "comment": "Fix an issue where package binaries where not created by \"rush deploy\" (#1982)" + }, + { + "comment": "Add a new setting \"folderToCopy\" and new command-line parameter \"--create-archive\" for use with \"rush deploy\"" + } + ] + } + }, + { + "version": "5.28.0", + "tag": "@microsoft/rush_v5.28.0", + "date": "Wed, 08 Jul 2020 06:56:47 GMT", + "comments": { + "none": [ + { + "comment": "Add new commands \"rush init-autoinstaller\" and \"rush update-autoinstaller\"" + }, + { + "comment": "Add support for filtered installs when using workspaces" + } + ], + "minor": [ + { + "comment": "Add preliminary workspaces support for PNPM" + } + ] + } + }, + { + "version": "5.27.3", + "tag": "@microsoft/rush_v5.27.3", + "date": "Fri, 03 Jul 2020 06:16:09 GMT", + "comments": { + "none": [ + { + "comment": "Added support for new format used by pnpm for tarball URLs that now begin with an @ symbol" + } + ] + } + }, + { + "version": "5.27.2", + "tag": "@microsoft/rush_v5.27.2", + "date": "Thu, 02 Jul 2020 01:52:18 GMT", + "comments": { + "none": [ + { + "comment": "Improve \"rush deploy\" to copy PNPM workaround links (fixes GitHub #1942 and 1943)" + } + ] + } + }, + { + "version": "5.27.1", + "tag": "@microsoft/rush_v5.27.1", + "date": "Mon, 29 Jun 2020 18:39:59 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where environment variable trimming for .npmrc was unnecessarily performed on comment lines" + }, + { + "comment": "Add a \"rush init\" template for .npmrc-publish" + }, + { + "comment": "Fix a regression affecting GitHub specifiers for package.json dependencies (issue #1749)" + } + ] + } + }, + { + "version": "5.27.0", + "tag": "@microsoft/rush_v5.27.0", + "date": "Sun, 21 Jun 2020 04:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Improve \"rush deploy\" to apply pnpmfile.js when calculating dependencies" + } + ] + } + }, + { + "version": "5.26.0", + "tag": "@microsoft/rush_v5.26.0", + "date": "Mon, 15 Jun 2020 01:26:24 GMT", + "comments": { + "none": [ + { + "comment": "Breaking change for the experimental \"rush deploy\" feature: Simplify the config file design, based on the discussion from GitHub #1906" + } + ] + } + }, + { + "version": "5.25.2", + "tag": "@microsoft/rush_v5.25.2", + "date": "Thu, 11 Jun 2020 05:34:31 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Git hook scripts failed in some environments due to CRLF newlines" + } + ] + } + }, + { + "version": "5.25.1", + "tag": "@microsoft/rush_v5.25.1", + "date": "Thu, 11 Jun 2020 05:05:30 GMT", + "comments": { + "none": [ + { + "comment": "Fix some minor errors in the \"rush init\" template that occured when Prettier reformatted the template file macros" + }, + { + "comment": "Add a sample Git hook file to the \"rush init\" template" + }, + { + "comment": "Fix a minor issue where \"rush link\" failed if no projects were defined yet in rush.json" + }, + { + "comment": "Add \"--no-verify\" for commits performed by \"rush version\", since Git hook scripts may fail on CI machines" + } + ] + } + }, + { + "version": "5.25.0", + "tag": "@microsoft/rush_v5.25.0", + "date": "Wed, 10 Jun 2020 23:53:27 GMT", + "comments": { + "none": [ + { + "comment": "Add new command-line.json setting \"autoinstallerName\"" + } + ] + } + }, + { + "version": "5.24.4", + "tag": "@microsoft/rush_v5.24.4", + "date": "Mon, 08 Jun 2020 18:04:35 GMT", + "comments": { + "none": [ + { + "comment": "Explicitly assigning the option value for --resolution-strategy. This fixes a crash with pnpm v5, which deprecated the option." + }, + { + "comment": "Fix an issue where install-run.js is not able to find its own .bin in PATH" + }, + { + "comment": "Fix an issue where \"rush install\" sometimes skipped regenerating temporary packages, which is incompatible with PNPM's \"--frozen-lockfile\" feature" + } + ] + } + }, + { + "version": "5.24.3", + "tag": "@microsoft/rush_v5.24.3", + "date": "Thu, 04 Jun 2020 22:50:56 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush deploy\" generated incorrect symlinks on Mac OS if the target folder was symlinked (GitHub #1910)" + } + ] + } + }, + { + "version": "5.24.2", + "tag": "@microsoft/rush_v5.24.2", + "date": "Wed, 03 Jun 2020 05:35:19 GMT", + "comments": { + "none": [ + { + "comment": "Expect error when trying to resolve optional dependency during deploy" + } + ] + } + }, + { + "version": "5.24.1", + "tag": "@microsoft/rush_v5.24.1", + "date": "Tue, 02 Jun 2020 03:11:32 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where the \"linkCreation\" defaulted to \"none\" instead of \"default\"" + } + ] + } + }, + { + "version": "5.24.0", + "tag": "@microsoft/rush_v5.24.0", + "date": "Mon, 01 Jun 2020 08:48:49 GMT", + "comments": { + "none": [ + { + "comment": "Set next LTS node version to 14." + }, + { + "comment": "Add new \"rush deploy\" command that copies subsets of files/symlinks to a deployment folder" + } + ] + } + }, + { + "version": "5.23.5", + "tag": "@microsoft/rush_v5.23.5", + "date": "Thu, 28 May 2020 22:49:57 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where Rush cannot reinstall itself on Windows" + } + ] + } + }, + { + "version": "5.23.4", + "tag": "@microsoft/rush_v5.23.4", + "date": "Thu, 21 May 2020 15:41:59 GMT", + "comments": { + "none": [ + { + "comment": "Add a new rush.json setting \"allowMostlyStandardPackageNames\"" + }, + { + "comment": "Add RUSH_PARALLELISM environment variable for specifying the --parallelism default" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "5.23.3", + "tag": "@microsoft/rush_v5.23.3", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "none": [ + { + "comment": "Fix a few instances of missing spaces in --help documentation." + }, + { + "comment": "Provide an option to pass --frozen-lockfile to pnpm for rush install" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "5.23.2", + "tag": "@microsoft/rush_v5.23.2", + "date": "Wed, 22 Apr 2020 18:44:26 GMT", + "comments": { + "none": [ + { + "comment": "Add common-versions.json to the set of files that, when changed, will trigger reinstallation of dependencies." + } + ] + } + }, + { + "version": "5.23.1", + "tag": "@microsoft/rush_v5.23.1", + "date": "Wed, 15 Apr 2020 03:33:55 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression in Rush 5.19.0 where customizing \"rush rebuild\" would call the \"build\" script instead of the \"rebuild\" script." + }, + { + "comment": "Fix an issue where, on some minimal systems, Rush used a missing shell command to detect an application path." + }, + { + "comment": "Fix an issue where the common/temp/*.tgz files resulted in different shrinkwrap files on different operating systems" + } + ] + } + }, + { + "version": "5.23.0", + "tag": "@microsoft/rush_v5.23.0", + "date": "Sat, 04 Apr 2020 00:38:29 GMT", + "comments": { + "none": [ + { + "comment": "Add a new rush.json setting \"preventManualShrinkwrapChanges\" which prevents against accidental mistakes in pnpm-lock.yaml." + }, + { + "comment": "Upgrade node-tar" + }, + { + "comment": "Remove some misleading log output for \"rush build\" (GitHub #1733)" + } + ] + } + }, { "version": "5.22.0", "tag": "@microsoft/rush_v5.22.0", @@ -168,12 +5550,10 @@ "tag": "@microsoft/rush_v5.17.1", "date": "Thu, 21 Nov 2019 00:50:15 GMT", "comments": { - "undefined": [ + "patch": [ { "comment": "Remove an error thrown when the --registry and --pack arguments are used on rush publish, because --registry might be required to check if a package has already been published against a custom registry." - } - ], - "none": [ + }, { "comment": "Fix an issue with Rush add, where Rush was unable to add unpublished local projects as dependencies." } @@ -1494,7 +6874,7 @@ "comments": { "major": [ { - "comment": "Complete release notes are here: https://github.com/Microsoft/web-build-tools/wiki#november-3-2017---rush-4-released" + "comment": "Complete release notes are here: https://github.com/microsoft/web-build-tools/wiki#november-3-2017---rush-4-released" }, { "comment": "Adding custom commands and options." diff --git a/apps/rush/CHANGELOG.md b/apps/rush/CHANGELOG.md index 90a4b141feb..bbee87b702a 100644 --- a/apps/rush/CHANGELOG.md +++ b/apps/rush/CHANGELOG.md @@ -1,6 +1,2815 @@ # Change Log - @microsoft/rush -This log was last generated on Wed, 18 Mar 2020 01:23:22 GMT and should not be manually modified. +This log was last generated on Tue, 25 Nov 2025 17:04:05 GMT and should not be manually modified. + +## 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 + +### Updates + +- Add a new experiment flag `enableSubpathScan` that, when invoking phased script commands with project selection parameters, such as `--to` or `--from`, only hashes files that are needed to compute the cache ids for the selected projects. + +## 5.146.0 +Tue, 10 Dec 2024 21:23:18 GMT + +### Updates + +- Support fallback syntax in `.npmrc` files if the package manager is PNPM. See https://pnpm.io/npmrc +- Add an `.isPnpm` property to `RushConfiguration` that is set to true if the package manager for the Rush repo is PNPM. +- Support pnpm lockfile v9, which is used by default starting in pnpm v9. + +## 5.145.0 +Tue, 10 Dec 2024 05:14:11 GMT + +### Updates + +- Upgrade `@azure/identity` and `@azure/storage-blob`. +- Add support for Node 22. +- Remove the dependency on node-fetch. + +## 5.144.1 +Mon, 09 Dec 2024 20:32:01 GMT + +### Updates + +- Bump `jsonpath-plus` to `~10.2.0`. + +## 5.144.0 +Wed, 04 Dec 2024 19:32:23 GMT + +### Updates + +- Remove the `node-fetch` dependency from `@rushstack/rush-http-build-cache-plugin`. + +## 5.143.0 +Wed, 04 Dec 2024 03:07:08 GMT + +### Updates + +- Remove the `node-fetch` dependency from @rushstack/rush-amazon-s3-build-cache-plugin. +- (BREAKING API CHANGE) Remove the exported `WebClient` API from @rushstack/rush-amazon-s3-build-cache-plugin. + +## 5.142.0 +Tue, 03 Dec 2024 23:42:22 GMT + +### Updates + +- Fix an issue where the ability to skip `rush install` may be incorrectly calculated when using the variants feature. +- Add support for an `"extends"` property in the `common/config/rush/pnpm-config.json` and `common/config/subspace/*/pnpm-config.json` files. +- Add warning when the `globalIgnoredOptionalDependencies` property is specified in `common/config/rush/pnpm-config.json` and the repo is configured to use pnpm <9.0.0. + +## 5.141.4 +Mon, 02 Dec 2024 20:40:41 GMT + +### Updates + +- Fix an issue where Rush sometimes incorrectly reported "fatal: could not open 'packages/xxx/.rush/temp/shrinkwrap-deps.json' for reading: No such file or directory" when using subspaces + +## 5.141.3 +Wed, 27 Nov 2024 07:16:50 GMT + +### Updates + +- Fix an issue where Rush sometimes incorrectly reported "The overrides settings doesn't match the current shrinkwrap" when using subspaces +- Fix an issue where Rush sometimes incorrectly reported "The package extension hash doesn't match the current shrinkwrap." when using subspaces + +## 5.141.2 +Wed, 27 Nov 2024 03:27:26 GMT + +### Updates + +- Fix an issue where filtered installs neglected to install dependencies from other subspaces + +## 5.141.1 +Wed, 20 Nov 2024 00:24:34 GMT + +### Updates + +- Update schema for build-cache.json to include recent updates to the @rushstack/rush-azure-storage-build-cache-plugin. + +## 5.141.0 +Tue, 19 Nov 2024 06:38:33 GMT + +### Updates + +- Adds two new properties to the configuration for `rush-azure-storage-build-cache-plugin`: `loginFlow` selects the flow to use for interactive authentication to Entra ID, and `readRequiresAuthentication` specifies that a SAS token is required for read and therefore expired authentication is always fatal. +- Adds a new `wasExecutedOnThisMachine` property to operation telemetry events, to simplify reporting about cobuilt operations. +- Fix an issue where empty error logs were created for operations that did not write to standard error. +- Fix an issue where incremental building (with LegacySkipPlugin) would not work when no-op operations were present in the process +- Fix lack of "local-only" option for cacheProvider in build-cache.schema.json +- Fix an issue where if an Operation wrote all logs to stdout, then exited with a non-zero exit code, only the non-zero exit code would show up in the summary. + +## 5.140.1 +Wed, 30 Oct 2024 21:50:51 GMT + +### Updates + +- Update the `jsonpath-plus` indirect dependency to mitigate CVE-2024-21534. + +## 5.140.0 +Tue, 22 Oct 2024 23:59:54 GMT + +### Updates + +- Fix an issue when using `rush deploy` where the `node_modules/.bin` folder symlinks were not created for deployed packages when using the "default" link creation mode +- Add support for the `globalIgnoredOptionalDependencies` field in the `common/config/rush/pnpm-config.json` file to allow specifying optional dependencies that should be ignored by PNPM + +## 5.139.0 +Thu, 17 Oct 2024 20:37:39 GMT + +### Updates + +- Allow rush plugins to extend build cache entries by writing additional files to the metadata folder. Expose the metadata folder path to plugins. +- [CACHE BREAK] Alter the computation of build cache IDs to depend on the graph of operations in the build and therefore account for multiple phases, rather than only the declared dependencies. Ensure that `dependsOnEnvVars` and command line parameters that affect upstream phases impact the cache IDs of downstream operations. +- (BREAKING CHANGE) Replace use of `ProjectChangeAnalyzer` in phased command hooks with a new `InputsSnapshot` data structure that is completely synchronous and does not perform any disk operations. Perform all disk operations and state computation prior to executing the build graph. +- Add a new property `enabled` to `Operation` that when set to false, will cause the execution engine to immediately return `OperationStatus.Skipped` instead of invoking the runner. Use this property to disable operations that are not intended to be executed in the current pass, e.g. those that did not contain changes in the most recent watch iteration, or those excluded by `--only`. +- Add an optional property `cacheHashSalt` to `build-cache.json` to allow repository maintainers to globally force a hash change in build cache entries. + +## 5.138.0 +Thu, 03 Oct 2024 22:31:07 GMT + +### Updates + +- Changes the behavior of phased commands in watch mode to, when running a phase `_phase:` in all iterations after the first, prefer a script entry named `_phase::incremental` if such a script exists. The build cache will expect the outputs from the corresponding `_phase:` script (with otherwise the same inputs) to be equivalent when looking for a cache hit. + +## 5.137.0 +Thu, 03 Oct 2024 19:46:40 GMT + +### Patches + +- Expose `getChangesByProject` to allow classes that extend ProjectChangeAnalyzer to override file change analysis + +## 5.136.1 +Thu, 26 Sep 2024 22:59:11 GMT + +### Updates + +- Fix an issue where the `--variant` parameter was missing from a phased command when the command's `alwaysInstall` property was set to `true`. + +## 5.136.0 +Thu, 26 Sep 2024 21:48:00 GMT + +### Updates + +- Bring back the Variants feature that was removed in https://github.com/microsoft/rushstack/pull/4538. +- Bump express dependency to 4.20.0 + +## 5.135.0 +Fri, 20 Sep 2024 20:23:40 GMT + +### Updates + +- Fix a bug that caused rush-resolver-cache-plugin to crash on Windows. +- Make individual Rush log files available via the rush-serve-plugin server at the relative URL specified by "logServePath" option. Annotate operations sent over the WebSocket with the URLs of their log files. +- Adds a new experiment 'allowCobuildWithoutCache' for cobuilds to allow uncacheable operations to benefit from cobuild orchestration without using the build cache. +- Deprecate the `sharding.shardOperationSettings` property in the project `config/rush-project.json` in favor of an `operationSettings` entry for an operation with a suffix of `:shard`. + +## 5.134.0 +Fri, 13 Sep 2024 01:02:46 GMT + +### Updates + +- Always update shrinkwrap when `globalPackageExtensions` in `common/config/rush/pnpm-config.json` has been changed. +- Pass the initialized credentials cache to `AzureAuthenticationBase._getCredentialFromTokenAsync` in `@rushstack/rush-azure-storage-build-cache-plugin`. +- Support the `rush-pnpm patch-remove` command. + +## 5.133.4 +Sat, 07 Sep 2024 00:18:08 GMT + +### Updates + +- Mark `AzureAuthenticationBase._credentialCacheId` as protected in `@rushstack/rush-azure-storage-build-cache-plugin`. + +## 5.133.3 +Thu, 29 Aug 2024 22:49:36 GMT + +### Updates + +- Fix Windows compatibility for `@rushstack/rush-resolver-cache-plugin`. + +## 5.133.2 +Wed, 28 Aug 2024 20:46:32 GMT + +### Updates + +- Fix an issue where running `rush install --resolution-only` followed by `rush install` would not actually install modules. + +## 5.133.1 +Wed, 28 Aug 2024 18:19:55 GMT + +### Updates + +- In rush-resolver-cache-plugin, include the base path in the resolver cache file. +- Support `bundledDependencies` in rush-resolver-cache-plugin. + +## 5.133.0 +Fri, 23 Aug 2024 00:40:08 GMT + +### Updates + +- Always update shrinkwrap when globalOverrides has been changed +- Add `afterInstall` plugin hook, which runs after any install finishes. +- Add rush.json option "suppressRushIsPublicVersionCheck" to allow suppressing hardcoded calls to the npmjs.org registry. + +## 5.132.0 +Wed, 21 Aug 2024 16:25:07 GMT + +### Updates + +- Add a new `rush install-autoinstaller` command that ensures that the specified autoinstaller is installed. +- Emit an error if a `workspace:` specifier is used in a dependency that is listed in `decoupledLocalDependencies`. +- Add support for `--resolution-only` to `rush install` to enforce strict peer dependency resolution. + +## 5.131.5 +Mon, 19 Aug 2024 20:03:03 GMT + +### Updates + +- Fix an issue where PreferredVersions are ignored when a project contains an overlapping dependency entry (https://github.com/microsoft/rushstack/issues/3205) + +## 5.131.4 +Sun, 11 Aug 2024 05:02:05 GMT + +### Updates + +- Revert a breaking change in Rush 5.131.3 where pnpm patches were moved from `common/pnpm-patches` to `common/config/rush/pnpm-patches`. + +## 5.131.3 +Sat, 10 Aug 2024 02:27:14 GMT + +### Updates + +- Fix an issue where `rush-pnpm patch-commit` would not correctly resolve patch files when the subspaces feature is enabled. + +## 5.131.2 +Thu, 08 Aug 2024 23:38:18 GMT + +### Updates + +- Include a missing dependency in `@rushstack/rush-sdk`. + +## 5.131.1 +Thu, 08 Aug 2024 22:08:41 GMT + +### Updates + +- Fix an issue where rush-sdk can't be bundled by a consuming package. +- Extract LookupByPath to @rushstack/lookup-by-path and load it from there. + +## 5.131.0 +Fri, 02 Aug 2024 17:26:59 GMT + +### Updates + +- Improve Rush alerts with a new "rush alert" command and snooze feature + +## 5.130.3 +Wed, 31 Jul 2024 23:30:13 GMT + +### Updates + +- Fix an issue where Rush does not detect an outdated lockfile if the `dependenciesMeta` `package.json` field is edited. +- Include CHANGELOG.md in published releases again +- Fix a bug that caused the build cache to close its terminal writer before execution on error. + +## 5.130.2 +Fri, 19 Jul 2024 03:41:44 GMT + +### Updates + +- Fix an issue where `rush-pnpm patch-commit` did not work correctly when subspaces are enabled. + +## 5.130.1 +Wed, 17 Jul 2024 07:37:13 GMT + +### Updates + +- Fix a recent regression for `rush init` + +## 5.130.0 +Wed, 17 Jul 2024 06:55:27 GMT + +### Updates + +- (EXPERIMENTAL) Initial implementation of Rush alerts feature +- Adjusts how cobuilt operations are added and requeued to the operation graph. Removes the 'RemoteExecuting' status. + +## 5.129.7 +Tue, 16 Jul 2024 04:16:56 GMT + +### Updates + +- Upgrade pnpm-sync-lib to fix an edge case when handling node_modules folder +- Don't interrupt the installation process if the user hasn't enabled the inject dependencies feature. +- Improve `@rushtack/rush-sdk` and make it reuse `@microsoft/rush-lib` from rush global folder +- Remove the trailing slash in the `.DS_Store/` line in the `.gitignore` file generated by `rush init`. `.DS_Store` is a file, not a folder. +- Support deep references to internal Apis +- Fix an issue where `rush add` would ignore the `ensureConsistentVersions` option if that option was set in `rush.json` instead of in `common/config/rush/common-versions.json`. +- Fix an issue where running `rush add` in a project can generate a `package.json` file that uses JSON5 syntax. Package managers expect strict JSON. +- fix spelling of "committing" in rush.json init template and schema + +## 5.129.6 +Thu, 27 Jun 2024 00:44:32 GMT + +### Updates + +- Fix an edge case for workspace peer dependencies when calculating packageJsonInjectedDependenciesHash to improve its accuracy +- Update a URL in the `.pnpmfile.cjs` generated by `rush init`. + +## 5.129.5 +Tue, 25 Jun 2024 20:13:29 GMT + +### Updates + +- Don't include package.json version field when calculating packageJsonInjectedDependenciesHash + +## 5.129.4 +Mon, 24 Jun 2024 23:49:10 GMT + +### Updates + +- Normalize the file permissions (644) for Rush plugin files that are committed to Git + +## 5.129.3 +Fri, 21 Jun 2024 00:15:54 GMT + +### Updates + +- Fixed an issue where DependencyAnalyzer caches the same analysis for all subspaces + +## 5.129.2 +Wed, 19 Jun 2024 23:59:09 GMT + +### Updates + +- Fix an issue where the `rush pnpm ...` command always terminates with an exit code of 1. + +## 5.129.1 +Wed, 19 Jun 2024 04:20:03 GMT + +### Updates + +- Add logic to remove outdated .pnpm-sync.json files during rush install or update + +## 5.129.0 +Wed, 19 Jun 2024 03:31:48 GMT + +### Updates + +- Add a new `init-subspace` command to initialize a new subspace. +- Move the `ensureConsistentVersions` setting from `rush.json` to `common/config/rush/common-versions.json`, or to `common/config/rush//common-versions.json` if subspaces are enabled. + +## 5.128.5 +Tue, 18 Jun 2024 04:02:54 GMT + +### Updates + +- Fix a key collision for cobuild clustering for operations that share the same phase name. + +## 5.128.4 +Mon, 17 Jun 2024 23:22:49 GMT + +### Updates + +- Bump the `@azure/identity` package to `~4.2.1` to mitigate GHSA-m5vv-6r4h-3vj9. + +## 5.128.3 +Mon, 17 Jun 2024 20:46:21 GMT + +### Updates + +- Fixed an issue where the --make-consistent flag would affect projects outside the current subspace. + +## 5.128.2 +Mon, 17 Jun 2024 17:08:00 GMT + +### Updates + +- Fix an issue where rush-pnpm patch is not working for the subspace scenario +- Fix an issue where rush update can not detect package.json changes in other subspaces for the injected installation case + +## 5.128.1 +Wed, 12 Jun 2024 20:07:44 GMT + +### Updates + +- Fix an issue where running `rush install` in a subspace with only a `--from` selector is treated as selecting all projects. +- Fix an issue where not published packages are not correctly identified as not published when querying a package feed under certain versions of NPM. +- Fix an issue where selection syntax (like `--to` or `--from`) misses project dependencies declared using workspace alias syntax (i.e. - `workspace:alias@1.2.3`). +- Fix an issue where an error is thrown if a Git email address isn't configured and email validation isn't configured in `rush.json` via `allowedEmailRegExps`. +- Display the name of the subspace when an error is emitted because a dependency hash uses the SHA1 algorithm and the "disallowInsecureSha1" option is enabled. + +## 5.128.0 +Fri, 07 Jun 2024 22:59:12 GMT + +### Updates + +- Graduate the `phasedCommands` experiment to a standard feature. +- Improve `rush init` template for `.gitignore` +- Remove an unnecessary condition in the logic for skipping operations when build cache is disabled. + +## 5.127.1 +Thu, 06 Jun 2024 03:05:21 GMT + +### Updates + +- Remove the second instance of the project name from the project operation filenames in `/rush-logs`. This restores the log filenames to their format before Rush 5.125.0. + +## 5.127.0 +Tue, 04 Jun 2024 00:44:18 GMT + +### Updates + +- Fixes build cache no-op and sharded operation clustering. +- Updated common-veresions.json schema with ensureConsistentVersions property + +## 5.126.0 +Mon, 03 Jun 2024 02:49:05 GMT + +### Updates + +- Fixes a string schema validation warning message when running `rush deploy`. +- Update the functionality that runs external lifecycle processes to be async. +- Move logs into the project `rush-logs` folder regardless of whether or not the `"phasedCommands"` experiment is enabled. +- Update the `nodeSupportedVersionRange` in the `rush init` template to the LTS and current Node versions. +- Update the `pnpmVersion` in the `rush init` template to the latest version of pnpm 8. +- Update the `.gitignore` in the `rush init` template to include some common toolchain output files and folders. +- Include missing `type` modifiers on type-only exports. + +## 5.125.1 +Wed, 29 May 2024 05:39:54 GMT + +### Updates + +- Fix an issue where if `missingScriptBehavior` is set to `"error"` and a script is present and empty, an error would be thrown. + +## 5.125.0 +Sat, 25 May 2024 05:12:20 GMT + +### Updates + +- Fixes a bug where no-op operations were treated as having build cache disabled. +- Adds support for sharding operations during task execution. +- Fix an issue where warnings and errors were not shown in the build summary for all cobuild agents. +- Add a `rush check --subspace` parameter to specify which subspace to analyze +- Rename the subspace level lockfile from `.pnpmfile-subspace.cjs` to `.pnpmfile.cjs`. This is a breaking change for the experimental feature. + +## 5.124.7 +Thu, 23 May 2024 02:27:13 GMT + +### Updates + +- Improve the `usePnpmSyncForInjectedDependencies` experiment to also include any dependency whose lockfile entry has the `file:` protocol, unless it is a tarball reference +- Fix an issue where the build cache analysis was incorrect in rare situations due to a race condition (GitHub #4711) + +## 5.124.6 +Thu, 16 May 2024 01:12:22 GMT + +### Updates + +- Fix an edge case for pnpm-sync when the .pnpm folder is absent but still a valid installation. + +## 5.124.5 +Wed, 15 May 2024 23:43:15 GMT + +### Updates + +- Fix count of completed operations when silent operations are blocked. Add explicit message for child processes terminated by signals. Ensure that errors show up in summarized view. +- Ensure that errors thrown in afterExecuteOperation show up in the summary at the end of the build. + +## 5.124.4 +Wed, 15 May 2024 03:05:57 GMT + +### Updates + +- Improve the detection of PNPM lockfile versions. +- Fix an issue where the `--subspace` CLI parameter would install for all subspaces in a monorepo when passed to the install or update action + +## 5.124.3 +Wed, 15 May 2024 01:18:25 GMT + +### Patches + +- Ensure async telemetry tasks are flushed by error reporter + +### Updates + +- Fix an issue where `rush install` and `rush update` will fail with an `ENAMETOOLONG` error on Windows in repos with a large number of projects. +- Fix an issue where installing multiple subspaces consecutively can cause unexpected cross-contamination between pnpmfiles. + +## 5.124.2 +Fri, 10 May 2024 06:35:26 GMT + +### Updates + +- Fix a recent regression where `rush deploy` did not correctly apply the `additionalProjectsToInclude` setting (GitHub #4683) + +## 5.124.1 +Fri, 10 May 2024 05:33:51 GMT + +### Updates + +- Fix an issue where the `disallowInsecureSha1` policy failed to parse certain lockfile entries +- Fix some minor issues with the "rush init" template files +- Report an error if subspacesFeatureEnabled=true without useWorkspaces=true +- Fix an issue where operation weights were not respected. + +## 5.124.0 +Wed, 08 May 2024 22:24:08 GMT + +### Updates + +- Add a new setting `alwaysInjectDependenciesFromOtherSubspaces` in pnpm-config.json +- Fix a issue where rush install/update can not detect pnpm-sync.json is out of date +- Improve the error message when the pnpm-sync version is outdated +- Fixes a bug where cobuilds would cause a GC error when waiting for long periods of time. +- Fix an issue where tab competions did not suggest parameter values. + +## 5.123.1 +Tue, 07 May 2024 22:38:00 GMT + +### Updates + +- Fix a recent regression where "rush install" would sometimes incorrectly determine whether to skip the install + +## 5.123.0 +Tue, 07 May 2024 18:32:36 GMT + +### Updates + +- Provide the file path if there is an error parsing a `package.json` file. +- Timeline view will now only show terminal build statuses as cobuilt, all other statuses will reflect their original icons. +- Add a `"weight"` property to the `"operation"` object in the project `config/rush-project.json` file that defines an integer weight for how much of the allowed parallelism the operation uses. +- Optimize skipping of unnecessary installs when using filters such as "rush install --to x" + +## 5.122.1 +Tue, 30 Apr 2024 23:36:50 GMT + +### Updates + +- Make `disallowInsecureSha1` policy a subspace-level configuration. +- Fix an issue where `rush update` sometimes did not detect changes to pnpm-config.json + +## 5.122.0 +Thu, 25 Apr 2024 07:33:18 GMT + +### Updates + +- Support rush-pnpm for subspace feature +- Skip determining merge base if given git hash +- (BREAKING CHANGE) Improve the `disallowInsecureSha1` policy to support exemptions for certain package versions. This is a breaking change for the `disallowInsecureSha1` field in pnpm-config.json since Rush 5.119.0. + +## 5.121.0 +Mon, 22 Apr 2024 19:11:26 GMT + +### Updates + +- Add support for auth via microsoft/ado-codespaces-auth vscode extension in `@rushstack/rush-azure-storage-build-cache-plugin` + +## 5.120.6 +Thu, 18 Apr 2024 23:20:02 GMT + +### Updates + +- Fix an issue where "rush deploy" did not correctly deploy build outputs combining multiple Rush subspaces + +## 5.120.5 +Wed, 17 Apr 2024 21:58:17 GMT + +### Updates + +- Fix an issue where rush add affects all packages in a subspace + +## 5.120.4 +Tue, 16 Apr 2024 20:04:25 GMT + +### Updates + +- Fix an issue where `rush deploy` sometimes used an incorrect temp folder when the experimental subspaces feature is enabled + +## 5.120.3 +Tue, 16 Apr 2024 02:59:48 GMT + +### Updates + +- Fix an issue where `pnpm-sync copy` was skipped when a build is restored from build cache. +- Upgrade `tar` dependency to 6.2.1 + +## 5.120.2 +Mon, 15 Apr 2024 00:25:04 GMT + +### Updates + +- Fixes an issue where rush install fails in monorepos with subspaces enabled + +## 5.120.1 +Sat, 13 Apr 2024 18:31:00 GMT + +### Updates + +- Fix an issue where install-run-rush.js sometimes incorrectly invoked .cmd files on Windows OS due to a recent Node.js behavior change. +- Fix an issue with the skip install logic when the experimental subspaces feature is enabled + +## 5.120.0 +Wed, 10 Apr 2024 21:59:57 GMT + +### Updates + +- Bump express. +- Add support for `optionalDependencies` in transitive injected install in the Subspaces feature. +- Update dependency: pnpm-sync-lib@0.2.2 +- Remove a restriction where the repo root would not be found if the CWD is >10 directory levels deep. +- Improve the error message that is printed in a repo using PNPM workspaces when a non-`workspace:` version is used for a project inside the repo. +- Include a missing space in a logging message printed when running `rush add`. +- Clarify the copyright notice emitted in common/scripts/*.js +- Fix an issue with loading of implicitly preferred versions when the experimental subspaces feature is enabled + +## 5.119.0 +Sat, 30 Mar 2024 04:32:31 GMT + +### Updates + +- Add a policy to forbid sha1 hashes in pnpm-lock.yaml. +- (BREAKING API CHANGE) Refactor phased action execution to analyze the repo after the initial operations are created. This removes the `projectChangeAnalyzer` property from the context parameter passed to the `createOperations` hook. + +## 5.118.7 +Thu, 28 Mar 2024 19:55:27 GMT + +### Updates + +- Fix an issue where in the previous release, built-in plugins were not included. + +## 5.118.6 +Wed, 27 Mar 2024 05:31:17 GMT + +### Updates + +- Symlinks are now generated for workspace projects in the temp folder when subspaces and splitWorkspaceCompatibility is enabled. + +## 5.118.5 +Tue, 26 Mar 2024 19:58:40 GMT + +### Updates + +- Use pnpm-sync-lib logging APIs to customize the log message for pnpm-sync operations + +## 5.118.4 +Tue, 26 Mar 2024 02:39:06 GMT + +### Updates + +- Added warnings if there are .npmrc or .pnpmfile.cjs files in project folders after migrating to subspaces + +## 5.118.3 +Sat, 23 Mar 2024 01:41:10 GMT + +### Updates + +- Fix an edge case for computing the PNPM store path when the experimental subspaces feature is enabled + +## 5.118.2 +Fri, 22 Mar 2024 17:30:47 GMT + +### Updates + +- Fix bugs related to path operation in Windows OS for subspace feature + +## 5.118.1 +Thu, 21 Mar 2024 16:39:32 GMT + +### Updates + +- Support PNPM injected installation in Rush subspace feature + +## 5.118.0 +Wed, 20 Mar 2024 20:45:18 GMT + +### Updates + +- (BREAKING API CHANGE) Rename `AzureAuthenticationBase._getCredentialFromDeviceCodeAsync` to `AzureAuthenticationBase._getCredentialFromTokenAsync` in `@rushstack/rush-azure-storage-build-cache-plugin`. Adding support for InteractiveBrowserCredential. + +## 5.117.10 +Wed, 20 Mar 2024 04:57:57 GMT + +### Updates + +- Improve the "splitWorkspaceCompatibility" setting to simulate hoisted dependencies when the experimental Rush subspaces feature is enabled + +## 5.117.9 +Tue, 12 Mar 2024 19:15:07 GMT + +### Updates + +- Add functionality to disable filtered installs for specific subspaces + +## 5.117.8 +Sat, 09 Mar 2024 01:11:16 GMT + +### Updates + +- Fixes a bug where the syncNpmrc function incorrectly uses the folder instead of the path + +## 5.117.7 +Fri, 08 Mar 2024 23:45:24 GMT + +### Updates + +- Fix an issue where, when the experimental subspace feature is enabled, the subspace's ".npmrc" file did not take precedence over ".npmrc-global". + +## 5.117.6 +Thu, 07 Mar 2024 19:35:20 GMT + +### Updates + +- Fixes an issue where cobuilds would write success with warnings as successful cache entries. + +## 5.117.5 +Wed, 06 Mar 2024 23:03:27 GMT + +### Updates + +- Add filtered installs for subspaces + +## 5.117.4 +Tue, 05 Mar 2024 21:15:26 GMT + +### Updates + +- Add support for subspace level scoped pnpm-config.json e.g. `common/config/subspaces/default/pnpm-config.json` + +## 5.117.3 +Tue, 05 Mar 2024 01:19:42 GMT + +### Updates + +- Fix an issue where if a patch is removed from `common/pnpm-patches` after `rush install` had already been run with that patch present, pnpm would try to continue applying the patch. +- Intercept the output printed by `rush-pnpm patch` to update the next step's instructions to run `rush-pnpm patch-commit ...` instead of `pnpm patch-commit ...`. + +## 5.117.2 +Fri, 01 Mar 2024 23:12:43 GMT + +### Updates + +- Fix an issue with the experimental subspaces feature, where version checks incorrectly scanned irrelevant subspaces. + +## 5.117.1 +Thu, 29 Feb 2024 07:34:31 GMT + +### Updates + +- Update "rush init" template to document the new build-cache.json constants +- Remove trailing slashes from `node_modules` and `jspm_packages` paths in the `.gitignore` file generated by `rush init`. +- Introduce a `RushCommandLine` API that exposes an object representing the skeleton of the Rush command-line. +- Fix an issue where, when the experimental subspaces feature was enabled, the lockfile validation would check irrelevant subspaces + +## 5.117.0 +Mon, 26 Feb 2024 21:39:36 GMT + +### Updates + +- Include the ability to add `[os]` and `[arch]` tokens to cache entry name patterns. +- (BREAKING CHANGE) Remove the 'installation variants' feature and its related APIs, which have been superceded by the Subspaces feature. +- Extract the "rush.json" filename to a constant as `RushConstants.rushJsonFilename`. + +## 5.116.0 +Mon, 26 Feb 2024 20:04:02 GMT + +### Updates + +- Upgrade the `pnpm-sync-lib` dependency version. +- Handle `workspace:~` and `workspace:^` wildcard specifiers when publishing. They remain as-is in package.json but get converted to `~${current}` and `^${current}` in changelogs. +- Validate that the "projectFolder" and "publishFolder" fields in the "projects" list in "rush.json" are normalized POSIX relative paths that do not end in trailing "/" or contain "\\". + +## 5.115.0 +Thu, 22 Feb 2024 01:36:27 GMT + +### Updates + +- Add a "runWithTerminalAsync" resource lifetime helper to `IOperationRunnerContext` to manage the creation and cleanup of logging for operation execution. +- Adds a new experiment `useIPCScriptsInWatchMode`. When this flag is enabled and Rush is running in watch mode, it will check for npm scripts named `_phase::ipc`, and if found, use them instead of the normal invocation of `_phase:`. When doing so, it will provide an IPC channel to the child process and expect the child to outlive the current build pass. + +## 5.114.3 +Thu, 22 Feb 2024 00:10:32 GMT + +### Updates + +- Replace deprecated function, and fix a path bug in Windows env + +## 5.114.2 +Wed, 21 Feb 2024 21:45:46 GMT + +### Updates + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 5.114.1 +Wed, 21 Feb 2024 08:56:05 GMT + +### Updates + +- Improve `rush scan` to analyze APIs such as `Import.lazy()` and `await import()` +- Fix a recent regression where `@rushstack/rush-sdk` did not declare its dependency on `@rushstack/terminal` + +## 5.114.0 +Mon, 19 Feb 2024 21:54:44 GMT + +### Updates + +- (EXPERIMENTAL) Add `enablePnpmSyncForInjectedDependenciesMeta` to experiments.json; it is part of an upcoming feature for managing PNPM "injected" dependencies: https://www.npmjs.com/package/pnpm-sync +- Include a `pnpmPatchesCommonFolderName` constant for the folder name "pnpm-patches" that gets placed under "common". +- Add a feature to generate a `project-impact-graph.yaml` file in the repo root. This feature is gated under the new `generateProjectImpactGraphDuringRushUpdate` experiment. +- Fix a formatting issue with the LICENSE. +- Fix an issue with filtered installs when the experimental subspaces feature is enabled + +## 5.113.4 +Wed, 31 Jan 2024 22:49:17 GMT + +### Updates + +- Introduce an explicit warning message during `rush install` or `rush update` about `dependenciesMeta` not being up-to-date. + +## 5.113.3 +Wed, 31 Jan 2024 22:25:55 GMT + +### Updates + +- Fix an issue where `rush update` would sometimes not correctly sync the `pnpm-lock.yaml` file back to `common/config/rush/` after a project's `package.json` has been updated. + +## 5.113.2 +Wed, 31 Jan 2024 18:45:33 GMT + +### Updates + +- Fix some minor issues when the experimental subspaces feature is enabled + +## 5.113.1 +Wed, 31 Jan 2024 07:07:50 GMT + +### Updates + +- (EXPERIMENTAL) Enable filtered installs of subspaces and add a "preventSelectingAllSubspaces" setting + +## 5.113.0 +Tue, 30 Jan 2024 22:58:52 GMT + +### Updates + +- Fix an issue where Rush does not detect changes to the `dependenciesMeta` field in project's `package.json` files, so may incorrectly skip updating/installation. +- Add ability to enable IPC channels in `Utilities#executeLifeCycleCommand`. +- Update `rush init` template to document the "buildSkipWithAllowWarningsInSuccessfulBuild" experiment +- (BREAKING CHANGE) Begin removal of APIs for the deprecated "installation variants" feature, since subspaces are a more robust solution for that problem +- (EXPERIMENTAL) Implement installation for the not-yet-released "subspaces" feature (GitHub #4230) + +## 5.112.2 +Tue, 12 Dec 2023 00:20:51 GMT + +### Updates + +- Bring back the erroneously removed `preminor` bump type for lockstepped packages. +- Fix an issue where the contents of a folder set in the `"folderToCopy"` field of the `deploy.json` config file would be copied into a subfolder instead of into the root of the deploy folder. +- (EXPERIMENTAL) Implemented config file loader for the not-yet-released "subspaces" feature (GitHub #4230) + +## 5.112.1 +Wed, 29 Nov 2023 08:59:31 GMT + +### Updates + +- Allow the device code credential options to be extended Azure authentication subclasses, used in advanced authentication scenarios. + +## 5.112.0 +Mon, 27 Nov 2023 23:36:11 GMT + +### Updates + +- Update the `@azure/identity` and `@azure/storage-blob` dependencies of `@rushstack/rush-azure-storage-build-cache-plugin` to eliminate an `EBADENGINE` error when installing Rush on Node 20. + +## 5.111.0 +Sat, 18 Nov 2023 00:06:20 GMT + +### Updates + +- Add experiment `buildSkipWithAllowWarningsInSuccessfulBuild` to allow skipping builds that succeeded with warnings in the previous run. + +## 5.110.2 +Thu, 16 Nov 2023 01:36:10 GMT + +_Version update only_ + +## 5.110.1 +Wed, 01 Nov 2023 23:29:47 GMT + +### Updates + +- Fix line endings in published package. + +## 5.110.0 +Mon, 30 Oct 2023 23:37:07 GMT + +### Updates + +- Include the filename of the shrinkwrap file in logging messages for all package managers, not just Yarn. +- performance improvements by running asynchronous code concurrently using Promise.all + +## 5.109.2 +Fri, 20 Oct 2023 01:54:21 GMT + +### Updates + +- Allow the output preservation incremental strategy if the build cache is configured but disabled. When running in verbose mode, log the incremental strategy that is being used. +- Log the cache key in `--verbose` mode when the cache is successfully read from or written to. +- Fix an issue where console colors were sometimes not enabled correctly during `rush install` +- Fix an issue where running `rush update-cloud-credentials --interactive` sometimes used the wrong working directory when invoked in a repo configured to use the `http` build cache provider (GitHub #4396) + +## 5.109.1 +Sat, 07 Oct 2023 01:20:56 GMT + +### Updates + +- Fix incorrect capitalization in the "rush init" template + +## 5.109.0 +Sat, 07 Oct 2023 00:25:27 GMT + +### Updates + +- (IMPORTANT) Add a new setting `autoInstallPeers` in pnpm-config.json; be aware that Rush changes PNPM's default if you are using PNPM 8 or newer +- (IMPORTANT) After upgrading, if `rush install` fails with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`, please run `rush update --recheck` +- Improve visual formatting of custom tips +- Add start `preRushx` and `postRushx` event hooks for monitoring the `rushx` command +- Update the oldest usable Node.js version to 14.18.0, since 14.17.0 fails to load + +## 5.108.0 +Mon, 02 Oct 2023 20:23:27 GMT + +### Updates + +- Fix an issue where `rush purge` fails on Linux and Mac if the `common/temp/rush-recycler` folder does not exist. +- Add "--offline" parameter for "rush install" and "rush update" +- Ignore pause/resume watcher actions when the process is not TTY mode + +## 5.107.4 +Tue, 26 Sep 2023 21:02:52 GMT + +### Updates + +- Update type-only imports to include the type modifier. +- Make the project watcher status and keyboard commands message more visible. + +## 5.107.3 +Fri, 22 Sep 2023 09:01:38 GMT + +### Updates + +- Fix filtered installs in pnpm@8. + +## 5.107.2 +Fri, 22 Sep 2023 00:06:12 GMT + +### Updates + +- Fix a bug in which an operation failing incorrectly does not block its consumers. +- Add `resolutionMode` to `rush init` template for pnpm-config.json + +## 5.107.1 +Tue, 19 Sep 2023 21:13:23 GMT + +### Updates + +- Fix pnpm's install status printing when pnpm custom tips are defined. + +## 5.107.0 +Tue, 19 Sep 2023 00:36:50 GMT + +### Updates + +- Update @types/node from 14 to 18 +- Remove previously removed fields from the `custom-tips.json` schema. +- (BREAKING API CHANGE) Refactor the `CustomTipsConfiguration` by removing the `configuration` property and adding a `providedCustomTipsByTipId` map property. +- Fix an issue where pnpm would would not rewrite the current status line on a TTY console, and instead would print a series of separate status lines during installation. Note that this is only fixed when there are no custom PNPM tips provided. +- Add "Waiting" operation status for operations that have one or more dependencies still pending. Ensure that the `onOperationStatusChanged` hook fires for every status change. +- Add support for optional build status notifications over a web socket connection to `@rushstack/rush-serve-plugin`. +- Add pause/resume option to project watcher + +## 5.106.0 +Thu, 14 Sep 2023 09:20:11 GMT + +### Updates + +- (IMPORTANT) Add a new setting `resolutionMode` in pnpm-config.json; be aware that Rush now overrides the default behavior if you are using PNPM 8.0.0 through 8.6.12 (GitHub #4283) +- Support adding custom tips for pnpm-printed logs +- (BREAKING CHANGE) Remove the "defaultMessagePrefix" config in custom-tips.json +- Rename the `PnpmStoreOptions` type to `PnpmStoreLocation`. + +## 5.105.0 +Fri, 08 Sep 2023 04:09:06 GMT + +### Updates + +- Disable build cache writes in watch rebuilds. +- Fix the instance of "ICreateOperationsContext" passed to the "beforeExecuteOperations" hook in watch mode rebuilds to match the instance passed to the "createOperations" hook. +- Fix an issue where the error message printed when two phases have overlapping output folders did not mention both phases. +- Update the phase output folders validation to only check for overlapping folders for phases that actually execute an operation in a given project. +- Add the "disableBuildCache" option to the schema for phased commands (it is already present for bulk commands). Update the behavior of the "disableBuildCache" flag to also disable the legacy skip detection, in the event that the build cache is not configured. + +## 5.104.1 +Tue, 05 Sep 2023 18:53:03 GMT + +### Updates + +- Fix an issue where `rush init` generated a `cobuild.json` file that reported errors (GitHub #4307) + +## 5.104.0 +Fri, 01 Sep 2023 04:54:16 GMT + +### Updates + +- (EXPERIMENTAL) Initial release of the cobuild feature, a cheap way to distribute jobs Rush builds across multiple VMs. (GitHub #3485) + +## 5.103.0 +Thu, 31 Aug 2023 23:28:28 GMT + +### Updates + +- Add dependencySettings field to Rush deploy.json configurations. This will allow developers to customize how third party dependencies are processed when running `rush deploy` +- Fix an issue where `rush update-autoinstaller` sometimes did not fully upgrade the lockfile +- Fix an issue where "undefined" was sometimes printed instead of a blank line + +## 5.102.0 +Tue, 15 Aug 2023 20:09:40 GMT + +### Updates + +- Add a new config file "custom-tips.json" for customizing Rush messages (GitHub #4207) +- Improve "rush scan" to recognize module patterns such as "import get from 'lodash.get'" +- Update Node.js version checks to support the new LTS release +- Update "rush init" template to use PNPM 7.33.5 +- Update the "rush init" template's .gitignore to avoid spurious diffs for files such as "autoinstaller.lock" +- Fix an issue where a pnpm-lock file would fail to parse if a project used a package alias in a repo using pnpm 8. +- Fix HTTP/1 backwards compatibility in rush-serve-plugin. +- Add experiment "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate" that, when running `rush update`, performs first a `--lockfile-only` update to the lockfile, then a `--frozen-lockfile` installation. This mitigates issues that may arise when using the `afterAllResolved` hook in `.pnpmfile.cjs`. + +## 5.101.1 +Fri, 11 Aug 2023 17:57:55 GMT + +### Updates + +- Fix a regression from 5.101.0 where publishing features did not detect changes properly when running on Windows OS (GitHub #4277) +- Add support in rush-serve-plugin for HTTP/2, gzip compression, and CORS preflight requests. + +## 5.101.0 +Tue, 08 Aug 2023 07:11:02 GMT + +### Updates + +- Enable the "http" option for build-cache providers +- Switch from glob to fast-glob. +- Reduce false positive detections of the pnpm shrinkwrap file being out of date in the presence of the `globalOverrides` setting in `pnpm-config.json`, or when a dependency is listed in both `dependencies` and `devDependencies` in the same package. +- @rushstack/rush-sdk now exposes a secondary API for manually loading the Rush engine and monitoring installation progress +- Add support for npm aliases in `PnpmShrinkwrapFile._getPackageId`. +- Improve version resolution logic in common/scripts/install-run.js (see https://github.com/microsoft/rushstack/issues/4256) +- Add `patternsToInclude` and `patternsToExclude` support to Rush deploy.json configurations. This will allow developers to include or exclude provided glob patterns within a local project when running `rush deploy`. + +## 5.100.2 +Mon, 24 Jul 2023 18:54:49 GMT + +### Patches + +- Fix an issue where the git pre-push hook would allow push to go through if the script exited with error. + +### Updates + +- Updated semver dependency + +## 5.100.1 +Wed, 14 Jun 2023 19:42:12 GMT + +### Updates + +- Fix an issue where Rush would attempt to open a project's log file for writing twice. +- Fix an issue where arguments weren't passed to git hook scripts. + +## 5.100.0 +Tue, 13 Jun 2023 01:49:21 GMT + +### Updates + +- (BREAKING API CHANGE) Remove unused members of the `BumpType` API. See https://github.com/microsoft/rushstack/issues/1335 for details. +- Add `--peer` flag to `rush add` command to add peerDependencies +- Add support for PNPM 8. +- Remove the dependency on `lodash`. +- Add functionality for the Amazon S3 Build Cache Plugin to read credentials from common AWS_* environment variables. +- Write cache logs to their own file(s). +- Fix an issue where cache logging data was always written to stdout. +- Generate scripts in the Git hooks folder referring to the actual hook implementations in-place in the Rush `common/git-hooks/` folder instead of copying the scripts to the Git hooks folder. +- Bump webpack to v5.82.1 + +## 5.99.0 +Fri, 02 Jun 2023 22:08:28 GMT + +### Updates + +- Use a separate temrinal for logging cache subsystem +- Expose beforeLog hook +- Convert to multi-phase Heft +- Use `JSON.parse` instead of `jju` to parse `package.json` files for faster performance. + +## 5.98.0 +Sun, 21 May 2023 00:18:35 GMT + +### Updates + +- Add a "forbidPhantomResolvableNodeModuleFolders" experiment that forbids node_modules folders in the repo root and in parent folders. +- Update the `RushSession.registerCloudBuildCacheProviderFactory` API to allow a cache provider's factory function to return a promise. +- Add built-in plugin rush-http-build-cache-plugin +- Fix an issue where the last character in a project's path is ignored when determining which files contribute to the project's cache ID. +- Fix a performance bug in `rush version` when using `workspace:` protocol. +- (BREAKING API CHANGE) Add a property `missingScriptBehavior` to phase definitions that can be used to silence missing scripts to reduce log noise. This replaces the `ignoreMissingScript` property visible to the plugin API, although the `ignoreMissingScript` property is still supported in the `common/config/rush/command-line.json` config file for backwards compatibility. +- Flatten watch status into a single line with TTY rewrites. + +## 5.97.1 +Tue, 18 Apr 2023 16:39:03 GMT + +### Updates + +- `rush version` will now respect the `ensureConsistentVersions` field in `rush.json` +- Bump webpack to 5.78.0 +- Fix file watching on Windows in the presence of Git's fsmonitor by not watching the .git folder. + +## 5.97.0 +Wed, 05 Apr 2023 21:46:37 GMT + +### Updates + +- Convert the `EnvironmentVariableNames` from an enum to a const so that its values can be referred to by type. + +## 5.96.0 +Fri, 31 Mar 2023 00:27:51 GMT + +### Updates + +- Fix an issue where rush-sdk sometimes failed to load if the globally installed Rush version was older than rushVersion in rush.json (GitHub #4039) +- Modify the scheduling behavior of phased commands to schedule only the expressly enumerated phases in all selected projects, adding additional phases only where needed to satisfy dependencies. + +## 5.95.0 +Fri, 24 Mar 2023 08:53:43 GMT + +### Updates + +- Add experiment `printEventHooksOutputToConsole` to allow printing outputs from event hooks to the console. + +## 5.94.1 +Wed, 22 Mar 2023 20:48:48 GMT + +### Updates + +- Fix an issue where rush plugin autoinstallers would fail to install because the Rush global folder had not yet been initialized. +- Fix an issue with `rush update-autoinstaller` where it may fail with an `Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with package.json` error. + +## 5.94.0 +Mon, 20 Mar 2023 20:14:36 GMT + +### Updates + +- Update the `nodeSupportedVersionRange` in `rush.json` generated by `rush init` to remove Node 12 as it is no longer supported and include Node 18 as it is the current LTS version. +- Extend LookupByPath to also be able to obtain the index of the remainder of the matched path. +- Include some more hooks to allow plugins to monitor phased command execution in real-time. +- Fix an issue where running `rush update-autoinstaller` without having run `rush install` or `rush update` first would cause a crash with an unhelpful error message. + +## 5.93.2 +Mon, 06 Mar 2023 20:18:01 GMT + +### Updates + +- Do not delete the local pnpm store after all install attempts has failed. `rush purge` will still delete a local store. + +## 5.93.1 +Fri, 17 Feb 2023 14:46:59 GMT + +### Updates + +- Fix a regression where "rush-sdk" failed to load older versions of "rush-lib" (GitHub #3979) + +## 5.93.0 +Fri, 17 Feb 2023 02:14:43 GMT + +### Updates + +- Add code path to @rushstack/rush-sdk for inheriting @microsoft/rush-lib location from a parent process via the _RUSH_LIB_PATH environment variable. + +## 5.92.0 +Sun, 12 Feb 2023 02:50:42 GMT + +### Updates + +- Enable @rushstack/rush-sdk to import internal APIs from the proxied @microsoft/rush-lib instance (GitHub #3895) + +## 5.91.0 +Sat, 11 Feb 2023 02:04:14 GMT + +### Updates + +- Remove runtime dependency on @rushstack/rush-sdk from the AzureStorageAuthentication class in @rushstack/rush-azure-storage-build-cache-plugin so that it can be used in isolation. +- Include operation log files in the cache, and restore them during cache hits. + +## 5.90.2 +Wed, 08 Feb 2023 20:27:06 GMT + +_Version update only_ + +## 5.90.1 +Wed, 08 Feb 2023 19:58:35 GMT + +### Patches + +- Fix determination of the root of the current Git worktree when in a multi-worktree setup. + +### Updates + +- Disable unused depcheck feature for upgrade-interactive. +- Fix an issue where deleting the `common/temp/node_modules` folder encounters an EPERM error and aborts. + +## 5.90.0 +Sun, 29 Jan 2023 20:10:17 GMT + +### Updates + +- Allow "shellCommand" to be optionally specified for bulk custom commands, so that a centralized script can be used instead of invoking package.json scripts (GitHub #3819) + +## 5.89.1 +Thu, 26 Jan 2023 02:55:30 GMT + +### Updates + +- Fix an issue with `rush add` where the approved packages files aren't updated. +- Revert generation of scripts in the Git hooks folder due to various git-related issues +- Upgrade to webpack 5.75.0 + +## 5.89.0 +Tue, 24 Jan 2023 22:30:06 GMT + +### Updates + +- Fix linking error due to PNPM v7 local install path breaking change +- Introduce "dependsOnAdditionalFiles" configuration option to operations in rush-project.json. This option allows to pass glob (minimatch) patterns pointing to files outside of .git repository. If provided, the hash values of these files will become part of the final hash when reading and writing from cache. +- Use getRepoStateAsync to optimize performance of calculating repository state. +- Generate scripts in the Git hooks folder referring to the actual hook implementations in-place in the Rush `common/git-hooks/` folder instead of copying the scripts to the Git hooks folder. + +## 5.88.2 +Sun, 22 Jan 2023 04:18:44 GMT + +### Updates + +- Fix a regression where the 'dist/scripts' folder name was named 'dist/undefined' + +## 5.88.1 +Wed, 18 Jan 2023 22:44:31 GMT + +### Updates + +- Fix an issue where `create-scripts.js` does not exist during `rush deploy`. +- Add install-run-rush-pnpm.js script +- Update JSZip to 3.8.0. + +## 5.88.0 +Thu, 22 Dec 2022 20:11:58 GMT + +### Updates + +- Improve the experience during a rush operation when the cached credentials have expired. Now, a warning is printed instead of an error being thrown and the operation halted. +- (BREAKING API CHANGE IN @rushstack/rush-azure-storage-build-cache-plugin) Change the signature of `AzureAuthenticationBase.tryGetCachedCredentialAsync` to optionally take an object describing the behavior when credentials have expired. The behavior of the function without an argument is unchanged. + +## 5.87.0 +Fri, 16 Dec 2022 19:34:26 GMT + +### Updates + +- Fix a typo in the artifactory.json template +- Writing local build cache is more robust on a network drive. +- Document default value for the "watchDebounceMs" setting +- Add "nodeSupportedVersionInstructions" property to rush.json, allowing maintainers to provide additional instructions if the user's node version is unsupported. +- (IMPORTANT) Fix a regression where the "strictPeerDependencies" setting wasn't applied for some versions of PNPM 7 due to unexpected changes of PNPM's default value (GitHub #3828) +- Fix an issue where if the package manager is PNPM 6.1.0 or newer, and `pnpmStore` is set to `"local"`, then a global cache was still used. +- Write local telemetry for global script actions +- Normalize all newlines in logging statements to LF. On Windows, some newlines were CRLF. +- Upgrade `npm-check` dependency from `~5.9.2` to `~6.0.1` +- Work towards bundling the files of "@rushstack/rush-lib" (Details in GitHub #3837) + +## 5.86.0 +Tue, 29 Nov 2022 00:10:20 GMT + +### Updates + +- Add new commands "rush-pnpm patch" and "rush-pnpm patch-commit" for patching NPM packages when using the PNPM package manager (GitHub #3554) + +## 5.85.1 +Fri, 25 Nov 2022 21:51:32 GMT + +### Updates + +- Fix an intermittent issue when writing tar log files + +## 5.85.0 +Thu, 24 Nov 2022 03:57:19 GMT + +### Updates + +- Add support for a `credentialMetadata` property in the CredentialCache. +- (BREAKING API CHANGE) Change the signature of `CredentialCache.setCacheEntry` to take the credential ID and an object describing the credential instead of a credential string and an expiration date. The second argument's type now matches the return value of `CredentialCache.tryGetCacheEntry` +- (BREAKING API CHANGE) Change the return type of `AzureAuthenticationBase.tryGetCachedCredentialAsync` (and, therefore, `AzureStorageAuthentication.tryGetCachedCredentialAsync`) from `string | undefined` to `ICredentialCacheEntry | undefined` to include the credentialMetadata. + +## 5.84.0 +Tue, 22 Nov 2022 23:24:56 GMT + +### Updates + +- Add a "dependsOnEnvVars" configuration option to operations in rush-project.json. The variables specified in this option are included in the cache key hash calculation. +- The "rush setup" user prompts can now be customized. +- Make autoinstaller logging respect the `--quiet` parameter. +- Add project filtering to the upgrade-interactive UI prompt. Also increases the default page size for project lists in UI to 12. +- Add a feature (behind the "cleanInstallAfterNpmrcChanges" experiment) that will cause a clean install to be performed if the common/temp/.npmrc file has changed since the last install. + +## 5.83.4 +Fri, 18 Nov 2022 04:02:43 GMT + +### Patches + +- Fix performance regression from supporting git submodules + +### Updates + +- Change files and change logs can store custom fields. + +## 5.83.3 +Tue, 15 Nov 2022 18:43:51 GMT + +### Patches + +- Fix an issue where Git submodules were not handled correctly by the build cache (GitHub #1711) + +## 5.83.2 +Mon, 14 Nov 2022 05:15:22 GMT + +### Updates + +- Ensure autoinstaller lockfiles are not leftover after an error + +## 5.83.1 +Sat, 12 Nov 2022 04:40:57 GMT + +### Updates + +- Update the "rush init" template for command-line.json to add usage examples for integer, integer list, string list, choice list parameter kinds + +## 5.83.0 +Fri, 11 Nov 2022 03:51:49 GMT + +### Updates + +- Add credentialType option for rush setup command +- Rush "setup" command works even if plugins cannot be installed +- Add support for integer, integer list, string list, and choice list parameters in plugins. +- Introduce a `rush upgrade-interactive` action that provides an interactive way to upgrade outdated dependencies. +- Fix a regression from Rush 5.79.0 where "rush init" did not create the pnpm-config.json file automatically + +## 5.82.1 +Wed, 19 Oct 2022 23:44:02 GMT + +_Version update only_ + +## 5.82.0 +Mon, 17 Oct 2022 22:14:39 GMT + +### Updates + +- Replace Travis with GitHub Actions in the `rush init` template." +- Handle case in ProjectWatcher where a project contains no git tracked files or status information is or was unavailable. +- Refactor @rushstack/rush-azure-storage-build-cache-plugin to expose an API for generating and caching Azure credentials for other workloads, in addition to Storage. +- Validate the change type in changefiles during publishing. + +## 5.81.0 +Sat, 08 Oct 2022 02:30:30 GMT + +### Updates + +- Add a `rush remove` command that removes one or more dependencies from a project. +- Support passing a lockfile to "install-run.js" and "install-run-rush.js" to ensure stable installation on CI. +- Add missing "environmentVariables" property to "pnpm-config.json" schema to restore feature parity with "rush.json" "pnpmOptions" field. + +## 5.80.1 +Mon, 03 Oct 2022 23:11:35 GMT + +### Updates + +- Add a more useful error message in cases when a merge base for `rush change` cannot be determined. + +## 5.80.0 +Thu, 29 Sep 2022 07:13:24 GMT + +### Updates + +- Include the operation duration in the telemetry data that was recorded during the non-cached run when a cache hit occurs. +- Fix an error message that always says to run "rush update --purge" even if the user only needs to run "rush install --purge." +- Fix an issue where a "Current PNPM store path does not match the last one used." error will erroneously get thrown on Windows with an unchanged path, but with a forward slash instead of a backslash. +- Remove fallback from tar binary to npm 'tar' package. The npm 'tar' package would sometimes produce invalid output if the cache entry was corrupt. +- Remove gender from the git config example in rush.json + +## 5.79.0 +Sat, 24 Sep 2022 17:37:03 GMT + +### Minor changes + +- Add a `common/config/pnpm-config.json`, which is used to specify fields like `overrides`, `packageExtensions`, and `neverBuiltDependencies` that would otherwise be placed in a PNPM workspace repo's root-level `package.json`'s `pnpm` field. + +### Updates + +- Add a `--commit` and `--commit-message` flag to `rush change` that commits the change files automatically. + +## 5.78.1 +Fri, 23 Sep 2022 02:54:44 GMT + +### Updates + +- Fix Git detection when the current working directory is unrelated to the Rush workspace. +- Fix an error that ocurred if an autoinstaller's "node_modules" folder was manually deleted (GitHub #2987) + +## 5.78.0 +Sat, 17 Sep 2022 00:56:37 GMT + +### Updates + +- Add a "beforeInstall" hook to the plugin API, for plugins to examine the environment immediately before "rush install" or "rush update" invoke the package manager. +- Fix "--parallelism XX%" parsing to return a finite number of CPU cores. +- Update the "rush init" template to include .gitignore patterns for IntellJ IDEA +- Upgrade the @azure/identity and @azure/storage-blob packages to eliminate a deprecation message during installation. +- Define an environment variable RUSH_PNPM_VERIFY_STORE_INTEGRITY that can be used to enable or disable PNPM's store integrity verification during installation for performance. + +## 5.77.3 +Fri, 02 Sep 2022 17:49:09 GMT + +_Version update only_ + +## 5.77.2 +Wed, 31 Aug 2022 00:43:07 GMT + +### Updates + +- Fix an issue where "rush add" sometimes did not work correctly if a project is nested under another project's folder + +## 5.77.1 +Tue, 30 Aug 2022 17:26:42 GMT + +### Updates + +- Fixed an issue where "rush add" was not updating common-versions.json when using "--make-consistent" + +## 5.77.0 +Mon, 29 Aug 2022 21:09:31 GMT + +### Updates + +- Add machine architecture information, dependency graph information, and individual build times and statuses to the telemetry file. +- Add schema validation for change files. +- Fix a minor issue with the "--rush-example-repo" template +- Update CLI docs for "rush add" +- Improve some config file documentation +- Make the project tag name syntax more strict to avoid error-prone names such as "tag:$PATH" or "tag://" +- Add validation to ensure package.json files are strict JSON and the "version" field is strict SemVer +- Add a new setting "watchOptions.debounceMs" in command-line.json + +## 5.76.1 +Mon, 08 Aug 2022 07:32:36 GMT + +### Updates + +- Fix a recent regression where "rush install" would sometimes fail with "Unknown option: 'ignore-compatibility-db'" + +## 5.76.0 +Sat, 06 Aug 2022 05:35:19 GMT + +### Updates + +- Validate that if shouldPublish is set, private is not set +- "rush install/update" should always set "ignore-compatibility-db=true" and print warning if the rush.json pnpmVersion specifies a version affected by this problem. +- Reorder some initialization logic so that Rush's change analysis is not counted as part of the build time for the first project +- (BREAKING API CHANGE) Rename cyclicDependencyProjects to decoupledLocalDependencies + +## 5.75.0 +Tue, 28 Jun 2022 03:31:01 GMT + +### Updates + +- Disable build cache for operations with no corresponding operationSettings entry in rush-project.json, and provide a clear message about why. +- When the `projectName:normalize` token is used in a cache ID, remove the `@` character from the scope. +- Reduce default maxInstallAttempts to 1 +- Improve logging of file locations when using the Heft build tool + +## 5.74.0 +Fri, 10 Jun 2022 22:17:51 GMT + +_Version update only_ + +## 5.73.0 +Fri, 10 Jun 2022 21:54:49 GMT + +_Version update only_ + +## 5.72.0 +Fri, 10 Jun 2022 20:01:47 GMT + +### Updates + +- Introduce a "rush-pnpm" shell command for invoking native PNPM commands in a Rush workspace + +## 5.71.0 +Fri, 27 May 2022 00:50:06 GMT + +### Updates + +- Write local telemetry for all phased commands, including partial runs when running in watch mode. +- Export the list of workspace packages to the pnpmfile shim. + +## 5.70.0 +Wed, 11 May 2022 22:21:40 GMT + +### Updates + +- Add a new `afterExecuteOperations` hook to phased command execution. This hook is used for the console timeline view and the standard result summary. + +## 5.69.0 +Tue, 10 May 2022 01:20:58 GMT + +### Updates + +- Fix handling of erroneous undefined values when printing `rush list --detailed` +- Update watcher to only schedule operations impacted by the detected change. A behavior difference will only be observed for repositories that define a phase with no dependencies. +- Fix handing of the `strictPeerDependencies` option when using PNPM >= 7.0.0. +- Update the `postRushInstall` hook to always run, and move its execution to after telemetry is written. +- (BREAKING CHANGE) Remove the "xstitchPreferredVersions" property from common-versions.json and the CommonVersionsConfiguration API. +- Correct a warning that is printed during "rush change" to only be concerned with unstaged changes. +- Include tags in the `rush list` output. + +## 5.68.2 +Fri, 06 May 2022 18:54:55 GMT + +### Updates + +- Provide ability for phased script commands to internally invoke "rush install" prior to execution. + +## 5.68.1 +Tue, 03 May 2022 21:52:56 GMT + +### Updates + +- Fix an issue where "rush list --json" prints non-json output in a repo that uses rush plugins with autoinstallers. + +## 5.68.0 +Fri, 29 Apr 2022 05:22:05 GMT + +### Updates + +- Disable legacy skip logic when build cache is enabled. +- Report status of projects with an empty script as "did not define any work," instead of as "from cache." +- Add a -- parameter to git command invocations that accept user input to prevent arbitrary arguments from being passed. +- Remove the @deprecated label from `RushConfigurationProject.packageJson`. + +## 5.67.0 +Sat, 23 Apr 2022 02:13:20 GMT + +### Updates + +- Upgrade "tar" dependency to eliminate spurious security vulnerability for "minimist" package +- Remove requirement that custom parameters associated with a phased command must also be associated with one or more phases. This allows for custom parameters that will only be interpreted by plugins. + +## 5.66.2 +Tue, 12 Apr 2022 02:58:47 GMT + +### Updates + +- Fix an issue where running the "install-run-rush" script with the "--help" parameter won't install Rush. + +## 5.66.1 +Tue, 12 Apr 2022 01:52:38 GMT + +### Updates + +- Fix watch-mode phased commands when rush.json is not in the repository root. Fix watch-mode change detection on Linux. + +## 5.66.0 +Sat, 09 Apr 2022 02:24:40 GMT + +### Updates + +- (BREAKING CHANGE) Update references to the default branch to reference "main" instead of "master". + +## 5.65.1 +Fri, 08 Apr 2022 23:10:18 GMT + +_Version update only_ + +## 5.65.0 +Fri, 08 Apr 2022 06:16:59 GMT + +### Updates + +- Expose APIs for managing Azure credentials from @rushstack/rush-azure-storage-build-cache-plugin. +- Add flushTelemetry hook +- Fix an edge case where `rush update` fails in a PNPM workspaces repo with no dependencies. +- Fix some issues with "rush add"'s ability to determine which version to use when adding a dependency that is already present in the repo. +- Add support for percentage values for --parallelism flag, eg. "50%". +- Improve retry logic in the Amazon S3 cloud cache plugin and improve reporting when the user is not authenticated. +- Add an additional plugin to rush-azure-storage-build-cache-plugin that can be used to prompt for Azure authentication before a command runs. +- Change the way "rush change" prints long lists of package names to include an "(and more)" line after the first five listed by name. +- Add a "tags" field to project definitions in rush.json. These may be used to select projects, for example, "rush list --only tag:my-custom-tag". +- Fix a typo in output of `rush change -v` + +## 5.64.0 +Fri, 01 Apr 2022 04:51:31 GMT + +### Updates + +- Add support for suppressing startup information to invocations of `rush`, `rushx`, and the `install-run-rush` scripts. +- Add --timeline option for more detail generated at end of rush build +- Expose plugin hooks for phased command execution: the "createOperations" hook allows customizing the set of operations to execute, and the "waitingForChanges" hook gives plugins an opportunity to display data to the console while output is paused. + +## 5.63.1 +Sat, 26 Mar 2022 00:47:39 GMT + +### Patches + +- Fix an issue where the build cache is never written to. + +### Updates + +- Fix broken README links for @microsoft/rush-lib documentation and API reference. + +## 5.63.0 +Tue, 15 Mar 2022 19:18:12 GMT + +### Updates + +- Reinstall automatically if monorepo folder is moved +- Fix resolution of change file paths when rush.json is not in the root of the Git repository. +- Fix the "selected operations" logging for commands that skipped projects to only display the operations that will be executed. +- For watch mode commands, allow the command to continue even if the initial build fails. +- Allow adding of aliased child packages. +- Add plugin hooks for global and phased commands and allow plugins to tap into command execution by command name, or into the execution of any command by command kind. +- Fix a typo in the "rush add" command-line help. + +## 5.62.4 +Tue, 15 Feb 2022 01:40:57 GMT + +### Updates + +- Remove the lib/index.mjs file from the @rushstack/rush-sdk package. This package must be CommonJS. +- Do not load the PowerShell User Profile for running the AsyncRecycler task + +## 5.62.3 +Fri, 11 Feb 2022 02:18:05 GMT + +### Updates + +- Fix an issue where the git tag would not include the prerelease portion of the version, which will cause subsequent publishes of the same version to not be tagged. + +## 5.62.2 +Thu, 10 Feb 2022 03:21:41 GMT + +### Updates + +- Add the ability to forcibly replace bad cache entries generated by issues in a previous Rush release. +- Fix an issue where the dependencies of lockstep-versioned projects aren't bumped when the lockstep-versioned projects' versions are bumped. This issue only arose in the scenario when the lockstep-versioned projects' version bumps are driven by the change type in the changefiles and not by the "nextBump" property in "common/config/rush/version-policies.json" +- Fix an issue where "rush setup" reported a TypeError when invoked from Git Bash +- Fix a bug where `rush change --verify` would not find the correct `common/changes` folder if the `rush.json` is not in the Git repo's root folder. +- Add support for rush-sdk to be bundled with Webpack. +- Add watch mode support to "phased" command definitions via the "watchOptions" property with a subfield "watchPhases". This separates the initial command phases from the phases run by the file watcher, e.g. so that the initial execution can pull from cache and the watch mode execution can use a separate incremental build phase. + +## 5.62.1 +Sun, 06 Feb 2022 04:59:08 GMT + +### Updates + +- Fix an issue where cache entries in certain circumstances would be missing files in nested subfolders. For full details see https://github.com/microsoft/rushstack/pull/3211. + +## 5.62.0 +Sat, 05 Feb 2022 00:55:18 GMT + +### Updates + +- Add support for directly invoking a script that depends on `rush-sdk` from inside a Rush repo. +- Add support for a new URL-based version specifier in PNPM lockfiles. +- Add support for specifying a custom S3 endpoint. This is useful for using a custom S3 provider. +- Optimize invocation of tar to use stdin instead of a temporary file. +- Revise architecture of symbolic link scan to use a queue and parallel file system calls. +- Create separate tar logs per phase based on cache id. +- Pack tar to a temp file, then move into the cache to ensure cache integrity. +- Fix git-hooks folder check failing when compared paths have different drive letter casing + +## 5.61.4 +Wed, 02 Feb 2022 04:03:24 GMT + +### Updates + +- Bump tar dependency to have a minimum version of 5.0.10. + +## 5.61.3 +Fri, 28 Jan 2022 21:03:58 GMT + +### Updates + +- Update the built-in cache provider plugins (rush-amazon-s3-build-cache-plugin and rush-azure-storage-build-cache-plugin) to apply for all commands, enabling cloud caching for custom phased and bulk commands. +- Allow build cache to be enabled for custom bulk commands. + +## 5.61.2 +Thu, 27 Jan 2022 02:30:10 GMT + +### Updates + +- Update node-fetch dependency version to address CVE-2022-0235 + +## 5.61.1 +Sat, 22 Jan 2022 04:22:52 GMT + +### Updates + +- (EXPERIMENTAL) Allow common/config/rush/command-line.json to specify the build command as a phased command without specifying all of the options required by the schema. The remaining options will come from the default. This is already supported when a partially-specified build command has "commandKind" set to "bulk". +- Fix an issue where Git Bash "tar" does not handle Windows paths correctly. +- (EXPERIMENTAL) Improve the RUSH_BUILD_CACHE_WRITE_ALLOWED environment variable behavior so that it also affects the local build cache. This saves CPU cycles on CI machines that only run a single build. It also avoids cache writes for watch mode commands. +- Refactoring to support upcoming watch mode improvements: Rework the task execution engine to interact with the task queue using the ECMAScript async iteration protocol (GitHub #3043) +- Fix project change detection when a new project is added to a repo that uses PNPM with useWorkspaces=false (GitHub #3183) + +## 5.61.0 +Sat, 22 Jan 2022 03:17:59 GMT + +### Updates + +- (EXPERIMENTAL) Fix a regression for the plugins feature, which caused an error message "command-line.json defines a command 'build' using a name that already exists" (GitHub #3155) + +## 5.60.0 +Thu, 20 Jan 2022 02:46:15 GMT + +### Updates + +- Fix the "allowWarningsInSuccessfulBuild" option in bulk commands defined in common/config/command-line.json. +- (BREAKING CHANGE) The experimental config file options "skipPhasesForCommand" and "addPhasesToCommand" have been temporarily removed until their design can be better formalized. +- Include NodeJS 16 in the range of supported versions (`nodeSupportedVersionRange`) in the `rush.json` file generated by `rush init`. +- (BREAKING CHANGE) Some experimental fields have been renamed in "config/rush-project.json". Please see UPGRADING.md for details. + +## 5.59.2 +Fri, 07 Jan 2022 02:34:59 GMT + +### Updates + +- Fixes a regression that broke "rush build" completely when not using the "--only" parameter. + +## 5.59.1 +Fri, 07 Jan 2022 01:21:44 GMT + +### Patches + +- Fixes a regression in bulk command execution when using "unsafe" selector parameters, e.g. "--only". Ensures that only the projects selected by the parameters get included in the build, rather that forcibly including all dependencies. + +## 5.59.0 +Thu, 06 Jan 2022 22:18:13 GMT + +### Minor changes + +- Update the "rush init" template to enable pnpm workspaces and to merge the pnpm-lock.yaml file as text. + +### Updates + +- Fix an issue that occurs when running a command with a selection argument with a Git ref (like `--from git:main`) in a repo with a pnpm lockfile larger than 1MB. +- Fix an issue with installing Git hooks that occurs when the rush.json folder isn't at the repo's root. +- (BREAKING CHANGE) Remove the experimental command "rush write-build-cache", since it is no longer needed and would be incompatible with phased builds. If you need this command for some reason, please create a GitHub issue. +- Add support for phased commands behind the multiPhaseCommands experiment. +- Update "rush init" to write files with OS-default line endings (CRLF on Windows, LF otherwise) instead of always writing CRLF line endings. + +## 5.58.0 +Thu, 16 Dec 2021 05:39:21 GMT + +### Updates + +- Fix an issue where Rush's Git hooks were broken if another tool such as Husky had tampered with the `core.hooksPath` (GitHub #3004) +- Provide a more useful error message if the git version is too old. +- Allow "rush list" to be invoked while other rush processes are running in the same repo. +- For project selection parameters such as "rush build --to git:REF", improve the diff analysis to detect which individual projects are impacted by a modification of the PNPM lockfile (GitHub #3050) +- Allow multiple remote URLs to be specified in the rush.json in the new repository.urls field. +- (BREAKING CHANGE) Replace the RushConfiguration repositoryUrl field with repositoryUrls to support multiple remote URLs specified in rush.json. + +## 5.57.1 +Thu, 09 Dec 2021 00:24:47 GMT + +_Version update only_ + +## 5.57.0 +Fri, 03 Dec 2021 02:16:10 GMT + +### Updates + +- Add support for the "filterLog" hook in common/config/rush/.pnpmfile.cjs +- (EXPERIMENTAL) Ability to load third-party plugin packages that customize the behavior of Rush +- Fix an issue where parameter values containing spaces are incorrectly passed to global scripts. +- Parameters such as "--to" and "--from" now accept selector expressions: "version-policy:NAME" indicates the set of projects belonging to a publishing version policy. "git:REF" detects the set of projects that have been modified since the specified Git revision; for example, this allows a Rush command to process only the projects modified by a PR branch. (GitHub #2968) +- Improved the change detection logic to work correctly when a second rush.json appears in a subfolder. +- (EXPERIMENTAL) Add a new NPM package "@rushstack/rush-sdk" for use by Rush plugins +- Stop deleting the pnpm-store after failed workspace installs. Usually a multiple failure is due to a network error or a package that does not exist in the registry, not an issue with the pnpm-store. + +## 5.56.0 +Thu, 28 Oct 2021 23:49:31 GMT + +### Updates + +- Add CI skipping to default version & changelog commits +- Update suggested version of NPM +- Fix update-autoinstaller with NPM +- Streamline rushx output and add quiet flag. +- Include support for adding multiple packages with the "rush add" command. +- Update the package.json repository field to include the directory property. +- Fix the error message printed when `--interactive` is passed to `rush update-cloud-credentials` and the cloud cache provider is Amazon S3. +- Mark Node 16 as the current latest LTS version. +- support `--debug-package-manager` install options for yarn + +## 5.55.1 +Tue, 12 Oct 2021 22:26:25 GMT + +### Updates + +- Fix an issue where a version field isn't parsed correctly when using NPM version 7 and newer. + +## 5.55.0 +Thu, 07 Oct 2021 23:44:52 GMT + +### Updates + +- Fix typo when project dependencies do not match the current shrinkwrap +- Use ITerminal in the rush-lib API instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. +- Add a new parameter "--detailed" for the "rush list" command +- Print the full event hooks output if the --debug paramter is specified. +- Upgrade the `@types/node` dependency to version to version 12. + +## 5.54.0 +Wed, 22 Sep 2021 22:54:17 GMT + +### Minor changes + +- Add ability to customize tag separator + +### Patches + +- Lock node-fetch dependency to 2.6.2 due to an incompatibility with 2.6.3 in the Azure Cloud Cache Provider. + +### Updates + +- Add a "--check-only" parameter to "rush install" to check the validity of the shrinkwrap without performing a full install. +- Fix an issue where `rush update-autoinstaller` does not use the repo's .npmrc + +## 5.53.0 +Fri, 10 Sep 2021 23:20:00 GMT + +### Updates + +- Fix an issue where the incremental build should use caching or skipping, but not both (GitHub #2891) +- Cache rush-project.json reads +- Fix an issue where the build cache did not respect "allowWarningsInSuccessfulBuild" (GitHub #2803) +- Add an experiment "buildCacheWithAllowWarningsInSuccessfulBuild" to allow caching for projects with warnings (GitHub #2803) + +## 5.52.0 +Mon, 23 Aug 2021 21:34:46 GMT + +### Updates + +- Add properties to the extraData section of the telemetry file for parameter usage in the install commands +- Add .heft to .gitignore file generated by rush init + +## 5.51.1 +Fri, 13 Aug 2021 22:45:36 GMT + +### Updates + +- When build cache is enabled in `rush build`, allow projects downstream to be satisfied from the cache if applicable. Cache reads will still be disabled for `rush rebuild`. + +## 5.51.0 +Wed, 11 Aug 2021 23:16:09 GMT + +### Updates + +- The --debug flag now also shows additional diagnostic information. +- Update JSZip dependency. +- Adds support for the project subset selection parameters ("--to", "--from", etc., documented at https://rushjs.io/pages/developer/selecting_subsets/) to the "rush list" command. +- Allow the tar binary path to be overridden via the RUSH_TAR_BINARY_PATH environment variable. + +## 5.50.0 +Sat, 17 Jul 2021 01:16:04 GMT + +### Minor changes + +- (Breaking change) Remove the experimental "--disable-build-cache" command line parameter. + +### Patches + +- When the experimental build cache is enabled, "rush rebuild" now forces cached projects to be rebuilt (GitHub #2802) + +## 5.49.2 +Thu, 15 Jul 2021 01:47:18 GMT + +### Updates + +- Fix incremental build state calculation when using filtered installs + +## 5.49.1 +Tue, 13 Jul 2021 23:03:01 GMT + +### Updates + +- Fix an issue where the "--no-fetch" "rush change" parameter would cause a "git fetch" and absence of that parameter wouldn't fetch. + +## 5.49.0 +Tue, 13 Jul 2021 06:22:09 GMT + +### Updates + +- Expose APIs useful for determining which projects have changed on the current branch compared to another branch. + +## 5.48.0 +Fri, 09 Jul 2021 01:44:18 GMT + +### Updates + +- Add RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD environment variable +- Prevent "rush change" from prompting for an email address, since this feature was rarely used. To restore the old behavior, enable the "includeEmailInChangeFile" setting in version-policies.json +- The "rushx" command now reports a warning when invoked in a project folder that is not registered in rush.json +- Fix the build-cache.json cacheEntryNamePattern description of the [normalize] token. +- When selection CLI parameters are specified and applying them does not select any projects, log that the selection is empty and immediately exit. +- Fix an issue where files restored by the build cache did not have a current modification time +- Upgrade the "rush init" template to use PNPM version 6.7.1; this avoids an important regression in PNPM 6.3.0 where .pnpmfile.cjs did not work correctly: https://github.com/pnpm/pnpm/issues/3453 +- Fix a JSON schema issue that prevented "disableBuildCache" from being specified in command-line.json +- Removed dependency on chokidar from BulkScriptAction in watch mode, since it adds unnecessary overhead. + +## 5.47.0 +Sat, 15 May 2021 00:02:26 GMT + +### Updates + +- For the experimental build cache feature, eliminate the RUSH_BUILD_CACHE_WRITE_CREDENTIAL environment variable; it is replaced by several new variables RUSH_BUILD_CACHE_CREDENTIAL, RUSH_BUILD_CACHE_WRITE_ALLOWED, and RUSH_BUILD_CACHE_ENABLED +- Take pnpm-workspace.yaml file into consideration during install skip checks for PNPM +- Fix a build cache warning that was sometimes displayed on Windows OS: "'tar' exited with code 1 while attempting to create the cache entry" (GitHub #2622) +- Fix an issue where "rushx" CLI arguments were not escaped properly (GitHub #2695) +- Allow rush-project.json to specify incrementalBuildIgnoredGlobs (GitHub issue #2618) +- Remove support for PNPM < 5.0.0 and remove the "resolutionStrategy" option +- Update "rush init" assets to use newer versions of Rush and PNPM. If you are looking to use PNPM < 6, you must rename the initialized ".pnpmfile.cjs" file to "pnpmfile.js". For more information, see: https://pnpm.io/5.x/pnpmfile +- Transform package.json using pnpmfile before checking if a Rush project is up-to-date +- Add support for the Yarn "resolutions" package.json feature. + +## 5.46.1 +Tue, 04 May 2021 20:26:15 GMT + +### Updates + +- Fix an issue where the buildCacheEnabled setting was not applied correctly + +## 5.46.0 +Tue, 04 May 2021 02:45:20 GMT + +### Updates + +- Remove "buildCache" setting from experiments.json; it is superseded by "buildCacheEnabled" in build-cache.json +- Add a "rush init" template for build-cache.json +- Temporarily downgrade the "@azure/identity" to eliminate the keytar native dependency (GitHub issue #2492) + +## 5.45.6 +Fri, 30 Apr 2021 00:32:16 GMT + +### Updates + +- Fix a regression in the S3 cloud build cache provider + +## 5.45.5 +Wed, 28 Apr 2021 17:54:16 GMT + +### Updates + +- Improve diagnostic messages printed by the rush build cache +- Fix an issue where Rush fails to run on Windows when the repository absolute path contains a space +- Use simpler and more accurate check before skipping installs + +## 5.45.4 +Fri, 23 Apr 2021 22:48:23 GMT + +_Version update only_ + +## 5.45.3 +Fri, 23 Apr 2021 22:03:08 GMT + +### Updates + +- Allow prerelease versions of PNPM to be used in workspaces mode + +## 5.45.2 +Thu, 22 Apr 2021 23:07:51 GMT + +### Updates + +- Fix bad installs with when using pnpmfile in PNPM 6 + +## 5.45.1 +Wed, 21 Apr 2021 23:38:22 GMT + +### Updates + +- Ensure that pnpm-workspace.yaml is always fully regenerated during "rush install" or "rush update" +- Fix support for pnpmfile in PNPM 6. + +## 5.45.0 +Tue, 20 Apr 2021 19:04:04 GMT + +### Updates + +- Print diagnostic information to a log file "/.rush/build-cache-tar.log" when the native "tar" is invoked. +- The Amazon S3 build cloud cache provider can now use buckets outside the default region +- Add support for PNPM 6 + +## 5.44.0 +Sat, 17 Apr 2021 00:17:51 GMT + +### Updates + +- Add --json and --all param to rush scan +- Fix "rush deploy" having "includeDevDependencies" turned on to deploy "devDependencies" for rush projects only + +## 5.43.0 +Thu, 08 Apr 2021 06:09:52 GMT + +### Updates + +- Add "--ignore-git-hooks" flags to "publish" and "version" commands to prevent the execution of all git hooks +- Fix parameter name typo. +- Eliminate a spurious warning that was displayed on Azure DevOps build agents: A phantom "node_modules" folder was found. +- Fix an issue where "rush change" reported "Unable to find a git remote matching the repository URL" when used with SSH auth +- Fix an issue where "rush publish" reported 403 errors if the package version included a SemVer build metadata suffix +- Partially deprecate RUSH_TEMP_FOLDER environment variable +- Validate changefiles against a schema when running 'rush change --verify' + +## 5.42.4 +Mon, 29 Mar 2021 05:57:18 GMT + +### Updates + +- Don't validate the shrinkwrap when running 'rush update' +- Gracefully handle a simultaneous upload to Azure Storage. +- Update rush publish -p flag description + +## 5.42.3 +Wed, 17 Mar 2021 05:07:02 GMT + +### Updates + +- Fix installation-time behavior of "omitImportersFromPreventManualShrinkwrapChanges" experiment. +- Don't upload build cache entries to Azure if the cache entry already exists. +- Replace the AWS dependencies with use of the Amazon S3 REST API. +- Add support for anonymous read from an Amazon S3-hosted cache. + +## 5.42.2 +Tue, 16 Mar 2021 00:30:38 GMT + +### Updates + +- Add experiment to exclude the "importers" section of "pnpm-lock.yaml" from the "preventManualShrinkwrapChanges" feature. + +## 5.42.1 +Fri, 12 Mar 2021 02:11:24 GMT + +### Updates + +- Temporarily disable the AWS S3 credential provider logic to mitigate a problematic peer dependency (GitHub #2547) + +## 5.42.0 +Wed, 10 Mar 2021 06:25:44 GMT + +### Updates + +- Add AWS S3 support to the experimental build cache feature + +## 5.41.0 +Wed, 10 Mar 2021 05:12:41 GMT + +### Updates + +- Fix an issue where "rush install" could stall indefinitely because a network request did not handle timeouts properly +- Allow merge conflicts in repo-state.json to be automatically resolved. +- Add a RUSH_INVOKED_FOLDER environment variable so that custom scripts can determine the folder path where Rush was invoked (GitHub #2497) +- Add `preferFrozenLockfileForUpdate` option to minimize lockfile churn by passing --prefer-frozen-lockfile to pnpm during default `rush update`. + +## 5.40.7 +Tue, 02 Mar 2021 23:27:41 GMT + +### Updates + +- Fix a regression where certain Rush operations reported a TypeError (GitHub #2526) + +## 5.40.6 +Tue, 02 Mar 2021 06:22:01 GMT + +### Updates + +- Improve cache read/write perf by attempting to use the "tar" binary. +- Fix default text in rush.json generated by "rush init." +- Fix an issue where Rush would fail to restore from cache but report success when Git isn't present. + +## 5.40.5 +Tue, 23 Feb 2021 03:26:25 GMT + +### Updates + +- Account for indirect dependencies when ordering projects in "rush build" if the intermediary dependencies are excluded by selection parameters. + +## 5.40.4 +Tue, 23 Feb 2021 00:01:20 GMT + +### Updates + +- Make Rush per-project manifest generation more reliable and remove PNPM shrinkwrap validation + +## 5.40.3 +Sun, 21 Feb 2021 01:05:53 GMT + +### Updates + +- Fix an issue where "rush setup" did not work correctly with NPM 7.x due to an NPM regression + +## 5.40.2 +Fri, 19 Feb 2021 06:28:28 GMT + +### Updates + +- Allow usage of Node.js 8.x since we received feedback that some projects are still supporting it + +## 5.40.1 +Fri, 19 Feb 2021 01:45:27 GMT + +### Updates + +- Fix a minor issue with the "rush init" template + +## 5.40.0 +Wed, 17 Feb 2021 01:35:11 GMT + +_Version update only_ + +## 5.39.2 +Wed, 17 Feb 2021 01:34:11 GMT + +### Updates + +- (EXPERIMENTAL) Add a "--disable-cache" parameter for disabling the build cache. +- (EXPERIMENTAL) Add a "disableBuildCache" setting in command-line.json for disabling the build cache. +- (EXPERIMENTAL) Add options in rush-project.json for disabling the build cache for entire projects, or for individual commands for that project. +- Normalize selection CLI parameters for "rush install" +- Add experimental "rush setup" command +- Add an experimental new config file common/config/artifactory.json for enabling Artifactory integration + +## 5.39.1 +Sat, 13 Feb 2021 03:14:52 GMT + +### Patches + +- Convert the experimental "--watch" parameter into a "watchForChanges: true" setting in command-line.json, based on user feedback + +### Updates + +- Disable build cache after initial build when "--watch" is specified. This saves disk space, reduces CPU usage, and improves compatibility with downstream file watcher processes (e.g. "webpack --watch"). + +## 5.39.0 +Thu, 11 Feb 2021 04:06:02 GMT + +### Minor changes + +- Add a new parameter "--watch" that watches for filesystem changes and rebuilds the affected Rush projects; this feature can also be used with custom bulk commands (GitHub #2458, #1122) + +### Updates + +- Improve the wording of some log messages + +## 5.38.0 +Mon, 01 Feb 2021 20:42:04 GMT + +### Updates + +- Add new command-line parameters for bulk commands: "--to-except", "--from", "--only", "--impacted-by", "--impacted-by-except", and "--from-version-policy" (GitHub #2354) +- Change the short name for "--changed-projects-only" to be "-c" (so that "-o" can be used for the new "--only" parameter) +- Change the "--from" parameter so that it now includes all dependencies as people expected. To skip dependencies, use the new "--impacted-by" parameter. (GitHub issue #1447) + +## 5.37.0 +Sat, 30 Jan 2021 01:50:27 GMT + +### Updates + +- Improve performance of association of repo file states with projects to speed up build commands in large repos. +- Add `publishFolder` property to the project configuration to allow publishing a sub-folder of the project +- Add support for --from flag for filtered installs when using workspaces +- Fix an issue where the Rush cache feature did not correctly detect files that were both tracked by git and were expected to be cached build output. +- Improve logging for the "rush write-build-cache" command +- Correct some spelling mistakes in rush.json +- Fix an error "Cannot get dependency key" sometimes reported by "rush install" (GitHub #2460) +- Updade the "rush init" template to specify PNPM 5.15.2, which fixes a performance regression introduced in PNPM 5.13.7 + +## 5.36.2 +Thu, 21 Jan 2021 04:51:19 GMT + +### Updates + +- Update Node.js version checks to support the new LTS release +- Update rush.json produced by rush init to use PNPM 5.14.3 +- Use forward slashes when creating deploy zip file for Unix compatibility + +## 5.36.1 +Fri, 08 Jan 2021 06:12:37 GMT + +### Updates + +- Fix an issue where projects with empty scripts would still have arguments appended. + +## 5.36.0 +Fri, 08 Jan 2021 05:36:55 GMT + +### Updates + +- Allow the git binary path to be overridden via the RUSH_GIT_BINARY_PATH environment variable. +- Introduce an experimental build cache feature. +- Add the ability to customize the commit message used when "rush version" is run. +- Remove the "experimental" label from some Rush commands that are now stable. + +## 5.35.2 +Tue, 03 Nov 2020 23:34:30 GMT + +### Updates + +- Fix bug where version process is using a wrong `git.addChanges` signature + +## 5.35.1 +Fri, 30 Oct 2020 05:17:42 GMT + +### Updates + +- Fix a recent "rush scan" regression (which resulted from enabling "esModuleInterop") + +## 5.35.0 +Wed, 28 Oct 2020 21:44:10 GMT + +### Updates + +- Adds an --ignore-hooks flag to every rush action that skips event hooks during execution of the action. +- Fix bug where version process was not adding version-policy configuration file changes into the version commit + +## 5.34.4 +Sat, 17 Oct 2020 00:23:18 GMT + +### Updates + +- When running `rush version --bump`, only include package.json updates in the generated commit +- Fix Rush peer dependency validation when satisfied with a package alias +- Prevent `rush unlink` from breaking installs for non-workspace projects +- Add documentation for incremental option for buld custom commands + +## 5.34.3 +Wed, 30 Sep 2020 21:04:15 GMT + +### Updates + +- Update to build with @rushstack/heft-node-rig +- Update README.md +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +## 5.34.2 +Mon, 21 Sep 2020 22:00:03 GMT + +### Updates + +- Fix an issue where "rush build" output was lagged due to stream-collator not activating streams aggressively enough +- Fix incorrect "successful" exit status code + +## 5.34.1 +Thu, 17 Sep 2020 07:13:04 GMT + +### Updates + +- Fix a regression that reported an error "The EnvironmentConfiguration must be initialized before values can be accessed" + +## 5.34.0 +Thu, 17 Sep 2020 01:23:35 GMT + +### Updates + +- Big redesign of "rush build" console reporting (fixes GitHub #2135) +- Implement RUSH_GLOBAL_FOLDER environment variable (GitHub #2187) +- Use underscores instead of asterisks for italic formatting in changelogs to match the way Prettier formats italics in markdown. +- In PNPM 5, --no-lock and --resolution-strategy flags have been removed. Do not pass these flags if they are not supported by the PNPM version used in the repository. + +## 5.33.2 +Fri, 21 Aug 2020 22:45:58 GMT + +### Updates + +- Fix an issue where PNPM would sometimes prompt for input during "rush publish" (GitHub #1940) +- Fix an issue that prevented Rush from logging in verbose mode + +## 5.33.1 +Thu, 20 Aug 2020 18:25:41 GMT + +### Updates + +- Fix issues where installs could fail after running 'rush version' while the 'usePnpmFrozenLockfileForRushInstall' experiment is enabled. See PR #2116 for more details. +- Fix an issue where "rush deploy" would sometimes report an "already exists" when using the "files" setting in package.json (GitHub #2121) +- Allow multiple simultaneous invocations of "rush deploy" (GitHub #2125) +- Load and validate local projects lazily to further improve Rush startup times. + +## 5.33.0 +Wed, 19 Aug 2020 00:17:48 GMT + +### Updates + +- Add support for shell tab completion. See PR for details: https://github.com/microsoft/rushstack/pull/2060 +- Use Import.lazy() to optimize the startup time for Rush + +## 5.32.3 +Tue, 18 Aug 2020 03:48:56 GMT + +### Updates + +- Fix an issue where install-run.js sometimes assigned the shell PATH incorrectly due to inconsistent character case + +## 5.32.2 +Fri, 14 Aug 2020 21:03:48 GMT + +### Updates + +- Resolve issue with version --bump where the wrong hash would get written to the pnpm-lock file + +## 5.32.1 +Fri, 14 Aug 2020 04:06:30 GMT + +### Updates + +- Change method used to calculate integrity of tarballs + +## 5.32.0 +Thu, 13 Aug 2020 00:53:43 GMT + +### Patches + +- Update temp project tarball integrities during rush bump + +## 5.31.0 +Wed, 12 Aug 2020 19:33:44 GMT + +### Updates + +- Updated project to build with Heft +- Fix an issue where "rushx" did not pass additional command-line arguments to the package.json script (GitHub #1232) + +## 5.30.3 +Fri, 07 Aug 2020 21:09:05 GMT + +### Updates + +- Fix an issue where Mac OS sometimes reported "An unrecognized file .DS_Store was found in the Rush config folder" + +## 5.30.2 +Wed, 05 Aug 2020 17:57:07 GMT + +### Updates + +- Fix an issue where a package version bump would not bump downstream packages with a `workspace:*` dependency specifier. + +## 5.30.1 +Thu, 23 Jul 2020 23:47:59 GMT + +### Updates + +- Fixed an isssue where the "rush build" incremental analysis sometimes reported a warning with large diffs (GitHub #501) or filenames that contain spaces, quotes, or other unusual characters (GitHub #2007) +- Prevent incorrect conversion to "workspace:" notation for peer dependencies when running "rush update --full" + +## 5.30.0 +Fri, 17 Jul 2020 05:32:38 GMT + +### Minor changes + +- Prepare to deprecate 'rush link' and 'rush unlink' commands, as well as the '--no-link' install argument. As we move toward using package managers more directly in Rush, the package managers will perform the linking during install (if linking is even necessary). Additionally, these commands directly conflict with (and have different meanings than) their package manager counterparts. Lastly, similar goals can be accomplished by running 'rush install' and 'rush purge'. In addition to these changes, rush-link.json deprecated and is replaced with a new API which keeps the local dependency tree in memory. + +## 5.29.1 +Thu, 16 Jul 2020 02:18:39 GMT + +### Patches + +- Consider package.json when determining if install can be skipped for PNPM workspaces + +## 5.29.0 +Tue, 14 Jul 2020 05:20:56 GMT + +### Updates + +- Give \"rush deploy\" the ability to select a subset of dependencies to copy over (#1978) +- Fix an issue where package binaries where not created by "rush deploy" (#1982) +- Add a new setting "folderToCopy" and new command-line parameter "--create-archive" for use with "rush deploy" + +## 5.28.0 +Wed, 08 Jul 2020 06:56:47 GMT + +### Minor changes + +- Add preliminary workspaces support for PNPM + +### Updates + +- Add new commands "rush init-autoinstaller" and "rush update-autoinstaller" +- Add support for filtered installs when using workspaces + +## 5.27.3 +Fri, 03 Jul 2020 06:16:09 GMT + +### Updates + +- Added support for new format used by pnpm for tarball URLs that now begin with an @ symbol + +## 5.27.2 +Thu, 02 Jul 2020 01:52:18 GMT + +### Updates + +- Improve "rush deploy" to copy PNPM workaround links (fixes GitHub #1942 and 1943) + +## 5.27.1 +Mon, 29 Jun 2020 18:39:59 GMT + +### Updates + +- Fix an issue where environment variable trimming for .npmrc was unnecessarily performed on comment lines +- Add a "rush init" template for .npmrc-publish +- Fix a regression affecting GitHub specifiers for package.json dependencies (issue #1749) + +## 5.27.0 +Sun, 21 Jun 2020 04:48:53 GMT + +### Updates + +- Improve "rush deploy" to apply pnpmfile.js when calculating dependencies + +## 5.26.0 +Mon, 15 Jun 2020 01:26:24 GMT + +### Updates + +- Breaking change for the experimental "rush deploy" feature: Simplify the config file design, based on the discussion from GitHub #1906 + +## 5.25.2 +Thu, 11 Jun 2020 05:34:31 GMT + +### Updates + +- Fix an issue where Git hook scripts failed in some environments due to CRLF newlines + +## 5.25.1 +Thu, 11 Jun 2020 05:05:30 GMT + +### Updates + +- Fix some minor errors in the "rush init" template that occured when Prettier reformatted the template file macros +- Add a sample Git hook file to the "rush init" template +- Fix a minor issue where "rush link" failed if no projects were defined yet in rush.json +- Add "--no-verify" for commits performed by "rush version", since Git hook scripts may fail on CI machines + +## 5.25.0 +Wed, 10 Jun 2020 23:53:27 GMT + +### Updates + +- Add new command-line.json setting "autoinstallerName" + +## 5.24.4 +Mon, 08 Jun 2020 18:04:35 GMT + +### Updates + +- Explicitly assigning the option value for --resolution-strategy. This fixes a crash with pnpm v5, which deprecated the option. +- Fix an issue where install-run.js is not able to find its own .bin in PATH +- Fix an issue where "rush install" sometimes skipped regenerating temporary packages, which is incompatible with PNPM's "--frozen-lockfile" feature + +## 5.24.3 +Thu, 04 Jun 2020 22:50:56 GMT + +### Updates + +- Fix an issue where "rush deploy" generated incorrect symlinks on Mac OS if the target folder was symlinked (GitHub #1910) + +## 5.24.2 +Wed, 03 Jun 2020 05:35:19 GMT + +### Updates + +- Expect error when trying to resolve optional dependency during deploy + +## 5.24.1 +Tue, 02 Jun 2020 03:11:32 GMT + +### Updates + +- Fix an issue where the "linkCreation" defaulted to "none" instead of "default" + +## 5.24.0 +Mon, 01 Jun 2020 08:48:49 GMT + +### Updates + +- Set next LTS node version to 14. +- Add new "rush deploy" command that copies subsets of files/symlinks to a deployment folder + +## 5.23.5 +Thu, 28 May 2020 22:49:57 GMT + +### Updates + +- Fix an issue where Rush cannot reinstall itself on Windows + +## 5.23.4 +Thu, 21 May 2020 15:41:59 GMT + +### Updates + +- Add a new rush.json setting "allowMostlyStandardPackageNames" +- Add RUSH_PARALLELISM environment variable for specifying the --parallelism default + +## 5.23.3 +Fri, 15 May 2020 08:10:59 GMT + +### Updates + +- Fix a few instances of missing spaces in --help documentation. +- Provide an option to pass --frozen-lockfile to pnpm for rush install + +## 5.23.2 +Wed, 22 Apr 2020 18:44:26 GMT + +### Updates + +- Add common-versions.json to the set of files that, when changed, will trigger reinstallation of dependencies. + +## 5.23.1 +Wed, 15 Apr 2020 03:33:55 GMT + +### Updates + +- Fix a regression in Rush 5.19.0 where customizing "rush rebuild" would call the "build" script instead of the "rebuild" script. +- Fix an issue where, on some minimal systems, Rush used a missing shell command to detect an application path. +- Fix an issue where the common/temp/*.tgz files resulted in different shrinkwrap files on different operating systems + +## 5.23.0 +Sat, 04 Apr 2020 00:38:29 GMT + +### Updates + +- Add a new rush.json setting "preventManualShrinkwrapChanges" which prevents against accidental mistakes in pnpm-lock.yaml. +- Upgrade node-tar +- Remove some misleading log output for "rush build" (GitHub #1733) ## 5.22.0 Wed, 18 Mar 2020 01:23:22 GMT @@ -39,7 +2848,7 @@ Tue, 28 Jan 2020 03:57:30 GMT ## 5.19.3 Tue, 28 Jan 2020 01:35:53 GMT -*Version update only* +_Version update only_ ## 5.19.2 Tue, 28 Jan 2020 01:08:26 GMT @@ -89,8 +2898,9 @@ Tue, 26 Nov 2019 00:53:52 GMT ## 5.17.1 Thu, 21 Nov 2019 00:50:15 GMT -### Updates +### Patches +- Remove an error thrown when the --registry and --pack arguments are used on rush publish, because --registry might be required to check if a package has already been published against a custom registry. - Fix an issue with Rush add, where Rush was unable to add unpublished local projects as dependencies. ## 5.17.0 @@ -526,7 +3336,7 @@ Wed, 22 Aug 2018 20:58:58 GMT ## 5.0.2 Sat, 18 Aug 2018 01:27:39 GMT -*Version update only* +_Version update only_ ## 5.0.1 Sat, 18 Aug 2018 01:21:59 GMT @@ -656,7 +3466,7 @@ Thu, 18 Jan 2018 19:02:07 GMT ## 4.2.2 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 4.2.1 Fri, 12 Jan 2018 23:35:48 GMT @@ -709,7 +3519,7 @@ Sat, 4 Nov 2017 03:22:28 GMT ### Breaking changes -- Complete release notes are here: https://github.com/Microsoft/web-build-tools/wiki#november-3-2017---rush-4-released +- Complete release notes are here: https://github.com/microsoft/web-build-tools/wiki#november-3-2017---rush-4-released - Adding custom commands and options. - Adding rush version selector. - Updating the semantics of rush change. @@ -911,7 +3721,7 @@ Fri, 24 Feb 2017 22:54:16 GMT ## 2.2.1 Fri, 24 Feb 2017 22:53:18 GMT -*Version update only* +_Version update only_ ## 2.2.0 Fri, 24 Feb 2017 22:44:31 GMT @@ -1129,5 +3939,5 @@ Sat, 03 Dec 2016 07:47:39 GMT ## 1.0.0 -*Initial release* +_Initial release_ diff --git a/apps/rush/README.md b/apps/rush/README.md index c488056d7fc..336d835ef07 100644 --- a/apps/rush/README.md +++ b/apps/rush/README.md @@ -1,7 +1,7 @@ # @microsoft/rush -![rush](https://github.com/microsoft/rushstack/blob/master/common/wiki-images/rush-logo.png?raw=true) +![rush](https://github.com/microsoft/rushstack/blob/main/common/wiki-images/rush-logo.png?raw=true)
      https://rushjs.io @@ -25,7 +25,7 @@ - **Bulk publishing:** When it's time to do a release, Rush can detect which packages have changes, automatically bump all the appropriate version numbers, and run `npm publish` in each folder. If you like, configure your server to automatically run `rush publish` every hour. -- **Changelog tracking:** Whenever a PR is created, you can require developers to provide a major/minor/patch log entry for the affected projects. During publishing, these changes will be automatically aggregated into a nicely formatted [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/master/libraries/node-core-library/CHANGELOG.md) file. +- **Changelog tracking:** Whenever a PR is created, you can require developers to provide a major/minor/patch log entry for the affected projects. During publishing, these changes will be automatically aggregated into a nicely formatted [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) file. - **Enterprise policies:** Want to review new libraries before developers add them to package.json, but avoid hassling people about already approved cases? Want to enforce that all your projects depend on the same library version numbers? Are unprofessional personal e-mail addresses accidentally showing up in your company's Git history? Rush can help maintain a consistent ecosystem when you've got many developers and many projects in the mix. @@ -60,6 +60,18 @@ _(If you don't have a GitHub account set up, you can use `rush install --bypass- -# Getting Started +## Getting Started For more details and support resources, please visit: https://rushjs.io + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/rush/CHANGELOG.md) - Find + out what's new in the latest version +- [UPGRADING.md]( + https://github.com/microsoft/rushstack/blob/main/apps/rush/UPGRADING.md) - Instructions + for migrating existing projects to use a newer version of Rush +- [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/apps/rush/UPGRADING.md b/apps/rush/UPGRADING.md new file mode 100644 index 00000000000..000e3bbb3fc --- /dev/null +++ b/apps/rush/UPGRADING.md @@ -0,0 +1,111 @@ +# Upgrade notes for @microsoft/rush + +### Rush 5.135.0 + +This release of Rush deprecates the `rush-project.json`'s `operationSettings.sharding.shardOperationSettings` +option in favor of defining a separate operation with a `:shard` suffix. This will only affect projects that +have opted into sharding and have custom sharded operation settings. + +To migrate, +**`rush-project.json`** (OLD) +```json +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "sharding": { + "count": 4, + "shardOperationSettings": { + "weight": 4 + } + }, + } + ] +} +``` + +**`rush-project.json`** (NEW) +```json +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "sharding": { + "count": 4, + }, + }, + { + "operationName": "_phase:build:shard", // note the suffix here + "weight": 4 + } + ] +} +``` + +### Rush 5.60.0 + +This release of Rush includes a breaking change for the experiment build cache feature. It only affects +monorepos with `buildCacheEnabled=true` in `experiments.json`. + +The `/config/rush-project.json` file format has changed. The new schema introduces +a concept of "operations" and an `operationSettings` property. An operation +is a command or phase that is invoked in a project. The top-level `projectOutputFolderNames` property +has been removed in favor of a per-operation `outputFolderNames` property. The `phaseOptions` and +`buildCacheOptions` properties have also been removed in favor of a per-operation properties. + +Converting to the new format: Although JSON fields have been moved/renamed, their meanings +are essentially the same. + +**`rush-project.json`** (OLD) + +```js +{ + "incrementalBuildIgnoredGlobs": ["temp/**"], + "projectOutputFolderNames": ["output-folder-1", "output-folder-2"], + "phaseOptions": [ + { + "phaseName": "_phase:build", + "projectOutputFolderNames": ["output-folder-a", "output-folder-b"] + } + ], + "buildCacheOptions": { + "disableBuildCache": false, + "optionsForCommands": [ + { + "commandName": "test", + "disableBuildCache": true + } + ] + } +} +``` + +**`rush-project.json`** (NEW) + +```js +{ + "incrementalBuildIgnoredGlobs": ["temp/**"], + + "disableBuildCacheForProject": false, // formerly buildCacheOptions.disableBuildCache + + "operationSettings": [ // formerly phaseOptions + { + "operationName": "build", + + // The "build" operation's output folder names were previously defined + // in the top-level `projectOutputFolderNames` property. + "outputFolderNames": ["output-folder-1", "output-folder-2"] + }, + { + "operationName": "_phase:build", // formerly phaseName + "outputFolderNames": ["output-folder-a", "output-folder-b"] + }, + { + "operationName": "test", + "disableBuildCacheForOperation": true + } + ] +} +``` + +For details see [issue #2300](https://github.com/microsoft/rushstack/issues/2300#issuecomment-1012622369). diff --git a/apps/rush/bin/rush b/apps/rush/bin/rush index 783bb806fce..aee68e80224 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/start.js'); diff --git a/apps/rush/bin/rush-pnpm b/apps/rush/bin/rush-pnpm new file mode 100755 index 00000000000..aee68e80224 --- /dev/null +++ b/apps/rush/bin/rush-pnpm @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js'); diff --git a/apps/rush/bin/rushx b/apps/rush/bin/rushx old mode 100644 new mode 100755 index 783bb806fce..aee68e80224 --- a/apps/rush/bin/rushx +++ b/apps/rush/bin/rushx @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js') +require('../lib/start.js'); diff --git a/apps/rush/config/jest.config.json b/apps/rush/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/rush/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/rush/config/rig.json b/apps/rush/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/rush/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/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/gulpfile.js b/apps/rush/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/apps/rush/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/apps/rush/package.json b/apps/rush/package.json index d388ac0ddf7..0f3d0b9bdb8 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/rush", - "version": "5.22.0", + "version": "5.163.0", "description": "A professional solution for consolidating all your JavaScript projects in one Git repo", "keywords": [ "install", @@ -15,7 +15,8 @@ "preferGlobal": true, "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/apps/rush" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/rush" }, "engines": { "node": ">=5.6.0" @@ -23,30 +24,31 @@ "engineStrict": true, "homepage": "https://rushjs.io", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "start": "node lib/start-dev-docs.js", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "bin": { "rush": "./bin/rush", + "rush-pnpm": "./bin/rush-pnpm", "rushx": "./bin/rushx" }, "license": "MIT", "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@microsoft/rush-lib": "5.22.0", - "colors": "~1.2.1", - "semver": "~5.3.0" + "@microsoft/rush-lib": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "semver": "~7.5.4" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "@types/semver": "5.3.33", - "@types/sinon": "1.16.34", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "sinon": "~1.17.3" + "@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" } } diff --git a/apps/rush/src/MinimalRushConfiguration.ts b/apps/rush/src/MinimalRushConfiguration.ts index e24ca989eed..902aea3224a 100644 --- a/apps/rush/src/MinimalRushConfiguration.ts +++ b/apps/rush/src/MinimalRushConfiguration.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 { JsonFile } from '@rushstack/node-core-library'; import { RushConfiguration } from '@microsoft/rush-lib'; import { RushConstants } from '@microsoft/rush-lib/lib/logic/RushConstants'; +import { RushCommandLineParser } from '@microsoft/rush-lib/lib/cli/RushCommandLineParser'; interface IMinimalRushConfigurationJson { rushMinimumVersion: string; @@ -21,13 +22,20 @@ export class MinimalRushConfiguration { private _commonRushConfigFolder: string; private constructor(minimalRushConfigurationJson: IMinimalRushConfigurationJson, rushJsonFilename: string) { - this._rushVersion = minimalRushConfigurationJson.rushVersion || minimalRushConfigurationJson.rushMinimumVersion; - this._commonRushConfigFolder = path.join(path.dirname(rushJsonFilename), - RushConstants.commonFolderName, 'config', 'rush'); + this._rushVersion = + minimalRushConfigurationJson.rushVersion || minimalRushConfigurationJson.rushMinimumVersion; + this._commonRushConfigFolder = path.join( + path.dirname(rushJsonFilename), + RushConstants.commonFolderName, + 'config', + 'rush' + ); } public static loadFromDefaultLocation(): MinimalRushConfiguration | undefined { - const rushJsonLocation: string | undefined = RushConfiguration.tryFindRushJsonLocation({ showVerbose: true }); + const rushJsonLocation: string | undefined = RushConfiguration.tryFindRushJsonLocation({ + showVerbose: !RushCommandLineParser.shouldRestrictConsoleOutput() + }); if (rushJsonLocation) { return MinimalRushConfiguration._loadFromConfigurationFile(rushJsonLocation); } else { diff --git a/apps/rush/src/RushCommandSelector.ts b/apps/rush/src/RushCommandSelector.ts index 9e076e161b3..148d07e6d1e 100644 --- a/apps/rush/src/RushCommandSelector.ts +++ b/apps/rush/src/RushCommandSelector.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 colors from 'colors'; -import * as path from 'path'; -import * as rushLib from '@microsoft/rush-lib'; +import * as path from 'node:path'; -type CommandName = 'rush' | 'rushx' | undefined; +import type * as rushLib from '@microsoft/rush-lib'; +import { Colorize } from '@rushstack/terminal'; + +type CommandName = 'rush' | 'rush-pnpm' | 'rushx' | undefined; /** * Both "rush" and "rushx" share the same src/start.ts entry point. This makes it @@ -16,14 +17,20 @@ type CommandName = 'rush' | 'rushx' | undefined; */ export class RushCommandSelector { public static failIfNotInvokedAsRush(version: string): void { - if (RushCommandSelector._getCommandName() === 'rushx') { - RushCommandSelector._failWithError(`This repository is using Rush version ${version}` - + ` which does not support the "rushx" command`); + const commandName: CommandName = RushCommandSelector._getCommandName(); + if (commandName !== 'rush' && commandName !== undefined) { + RushCommandSelector._failWithError( + `This repository is using Rush version ${version} which does not support the ${commandName} command` + ); } } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static execute(launcherVersion: string, selectedRushLib: any, options: rushLib.ILaunchOptions): void { + public static execute( + launcherVersion: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + selectedRushLib: any, + options: rushLib.ILaunchOptions + ): void { const Rush: typeof rushLib.Rush = selectedRushLib.Rush; if (!Rush) { @@ -31,31 +38,34 @@ export class RushCommandSelector { RushCommandSelector._failWithError(`Unable to find the "Rush" entry point in @microsoft/rush-lib`); } - if (RushCommandSelector._getCommandName() === 'rushx') { + const commandName: CommandName = RushCommandSelector._getCommandName(); + + if (commandName === 'rush-pnpm') { + if (!Rush.launchRushPnpm) { + RushCommandSelector._failWithError( + `This repository is using Rush version ${Rush.version}` + + ` which does not support the "rush-pnpm" command` + ); + } + Rush.launchRushPnpm(launcherVersion, { + isManaged: options.isManaged, + alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError + }); + } else if (commandName === 'rushx') { if (!Rush.launchRushX) { - RushCommandSelector._failWithError(`This repository is using Rush version ${Rush.version}` - + ` which does not support the "rushx" command`); + RushCommandSelector._failWithError( + `This repository is using Rush version ${Rush.version}` + + ` which does not support the "rushx" command` + ); } - Rush.launchRushX( - launcherVersion, - { - isManaged: options.isManaged, - alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError - } - ); + Rush.launchRushX(launcherVersion, options); } else { - Rush.launch( - launcherVersion, - { - isManaged: options.isManaged, - alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError - } - ); + Rush.launch(launcherVersion, options); } } private static _failWithError(message: string): never { - console.log(colors.red(message)); + console.log(Colorize.red(message)); return process.exit(1); } @@ -65,12 +75,15 @@ export class RushCommandSelector { // 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 === 'RUSHX') { - return 'rushx'; - } if (basename === 'RUSH') { return 'rush'; } + if (basename === 'RUSH-PNPM') { + return 'rush-pnpm'; + } + if (basename === 'RUSHX') { + return 'rushx'; + } } return undefined; } diff --git a/apps/rush/src/RushVersionSelector.ts b/apps/rush/src/RushVersionSelector.ts index f0f69ed4d6e..1fc8a73b9ce 100644 --- a/apps/rush/src/RushVersionSelector.ts +++ b/apps/rush/src/RushVersionSelector.ts @@ -1,19 +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 { LockFile } from '@rushstack/node-core-library'; import { Utilities } from '@microsoft/rush-lib/lib/utilities/Utilities'; -import { - _LastInstallFlag, - _RushGlobalFolder, - ILaunchOptions -} from '@microsoft/rush-lib'; +import { _FlagFile, _RushGlobalFolder, type ILaunchOptions } from '@microsoft/rush-lib'; import { RushCommandSelector } from './RushCommandSelector'; -import { MinimalRushConfiguration } from './MinimalRushConfiguration'; +import type { MinimalRushConfiguration } from './MinimalRushConfiguration'; const MAX_INSTALL_ATTEMPTS: number = 3; @@ -26,102 +23,73 @@ export class RushVersionSelector { this._currentPackageVersion = currentPackageVersion; } - public ensureRushVersionInstalled( + public async ensureRushVersionInstalledAsync( version: string, configuration: MinimalRushConfiguration | undefined, executeOptions: ILaunchOptions ): Promise { - const isLegacyRushVersion: boolean = semver.lt(version, '4.0.0'); const expectedRushPath: string = path.join(this._rushGlobalFolder.nodeSpecificPath, `rush-${version}`); - const installMarker: _LastInstallFlag = new _LastInstallFlag( - expectedRushPath, - { node: process.versions.node } - ); - - let installPromise: Promise = Promise.resolve(); - - if (!installMarker.isValid()) { - installPromise = installPromise.then(() => { - // Need to install Rush - console.log(`Rush version ${version} is not currently installed. Installing...`); - - const resourceName: string = `rush-${version}`; - - console.log(`Trying to acquire lock for ${resourceName}`); - - return LockFile.acquire(expectedRushPath, resourceName) - .then((lock: LockFile) => { - - if (installMarker.isValid()) { - console.log('Another process performed the installation.'); - } else { - Utilities.installPackageInDirectory({ - directory: expectedRushPath, - packageName: isLegacyRushVersion ? '@microsoft/rush' : '@microsoft/rush-lib', - version: version, - tempPackageTitle: 'rush-local-install', - maxInstallAttempts: MAX_INSTALL_ATTEMPTS, - // This is using a local configuration to install a package in a shared global location. - // Generally that's a bad practice, but in this case if we can successfully install - // the package at all, we can reasonably assume it's good for all the repositories. - // 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: configuration ? configuration.commonRushConfigFolder : undefined, - suppressOutput: true - }); - - console.log(`Successfully installed Rush version ${version} in ${expectedRushPath}.`); - - // If we've made it here without exception, write the flag file - installMarker.create(); - - lock.release(); - } - }); - }); - } + const installMarker: _FlagFile = new _FlagFile(expectedRushPath, 'last-install', { + node: process.versions.node + }); + + let installIsValid: boolean = await installMarker.isValidAsync(); + if (!installIsValid) { + // Need to install Rush + console.log(`Rush version ${version} is not currently installed. Installing...`); + + const resourceName: string = `rush-${version}`; - return installPromise.then(() => { - if (semver.lt(version, '3.0.20')) { - // In old versions, requiring the entry point invoked the command-line parser immediately, - // so fail if "rushx" was used - RushCommandSelector.failIfNotInvokedAsRush(version); - require(path.join( - expectedRushPath, - 'node_modules', - '@microsoft', - 'rush', - 'lib', - 'rush' - )); - } else if (semver.lt(version, '4.0.0')) { - // In old versions, requiring the entry point invoked the command-line parser immediately, - // so fail if "rushx" was used - RushCommandSelector.failIfNotInvokedAsRush(version); - require(path.join( - expectedRushPath, - 'node_modules', - '@microsoft', - 'rush', - 'lib', - 'start' - )); + console.log(`Trying to acquire lock for ${resourceName}`); + + const lock: LockFile = await LockFile.acquire(expectedRushPath, resourceName); + installIsValid = await installMarker.isValidAsync(); + if (installIsValid) { + console.log('Another process performed the installation.'); } else { - // For newer rush-lib, RushCommandSelector can test whether "rushx" is supported or not - // eslint-disable-next-line @typescript-eslint/no-var-requires - const rushCliEntrypoint: { } = require(path.join( - expectedRushPath, - 'node_modules', - '@microsoft', - 'rush-lib', - 'lib', - 'index' - )); - RushCommandSelector.execute(this._currentPackageVersion, rushCliEntrypoint, executeOptions); + await Utilities.installPackageInDirectoryAsync({ + directory: expectedRushPath, + packageName: isLegacyRushVersion ? '@microsoft/rush' : '@microsoft/rush-lib', + version: version, + tempPackageTitle: 'rush-local-install', + maxInstallAttempts: MAX_INSTALL_ATTEMPTS, + // This is using a local configuration to install a package in a shared global location. + // Generally that's a bad practice, but in this case if we can successfully install + // the package at all, we can reasonably assume it's good for all the repositories. + // 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: configuration ? configuration.commonRushConfigFolder : undefined, + suppressOutput: true + }); + + console.log(`Successfully installed Rush version ${version} in ${expectedRushPath}.`); + + // If we've made it here without exception, write the flag file + await installMarker.createAsync(); + + lock.release(); } - }); + } + + if (semver.lt(version, '3.0.20')) { + // In old versions, requiring the entry point invoked the command-line parser immediately, + // so fail if "rushx" or "rush-pnpm" was used + RushCommandSelector.failIfNotInvokedAsRush(version); + require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'rush')); + } else if (semver.lt(version, '4.0.0')) { + // In old versions, requiring the entry point invoked the command-line parser immediately, + // so fail if "rushx" or "rush-pnpm" was used + RushCommandSelector.failIfNotInvokedAsRush(version); + require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'start')); + } else { + // 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 new file mode 100644 index 00000000000..4bd9539a8bb --- /dev/null +++ b/apps/rush/src/start-dev-docs.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 { 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-rush')); diff --git a/apps/rush/src/start-dev.ts b/apps/rush/src/start-dev.ts new file mode 100644 index 00000000000..1660da8628d --- /dev/null +++ b/apps/rush/src/start-dev.ts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// 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 { PackageJsonLookup, Import } from '@rushstack/node-core-library'; + +import { RushCommandSelector } from './RushCommandSelector'; + +const builtInPluginConfigurations: rushLib._IBuiltInPluginConfiguration[] = []; + +function includePlugin(pluginName: string, pluginPackageName?: string): void { + if (!pluginPackageName) { + pluginPackageName = `@rushstack/${pluginName}`; + } + builtInPluginConfigurations.push({ + packageName: pluginPackageName, + pluginName: pluginName, + pluginPackageFolder: Import.resolvePackage({ + packageName: pluginPackageName, + baseFolderPath: __dirname, + useNodeJSResolver: true + }) + }); +} + +includePlugin('rush-amazon-s3-build-cache-plugin'); +includePlugin('rush-azure-storage-build-cache-plugin'); +includePlugin('rush-http-build-cache-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'); + +const currentPackageVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version; +RushCommandSelector.execute(currentPackageVersion, rushLib, { + isManaged: false, + alreadyReportedNodeTooNewError: false, + builtInPluginConfigurations +}); diff --git a/apps/rush/src/start.ts b/apps/rush/src/start.ts index 6600ca8c6e8..14c0dbad96c 100644 --- a/apps/rush/src/start.ts +++ b/apps/rush/src/start.ts @@ -5,10 +5,12 @@ // 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.warnAboutVersionTooOld()) { - // We are on an ancient version of Node.js that is known not to work with Rush +if (NodeJsCompatibility.reportAncientIncompatibleVersion()) { + // The Node.js version is known to have serious incompatibilities. In that situation, the user + // should downgrade Rush to an older release that supported their Node.js version. process.exit(1); } @@ -17,14 +19,12 @@ const alreadyReportedNodeTooNewError: boolean = NodeJsCompatibility.warnAboutVer alreadyReportedNodeTooNewError: false }); -import * as colors from 'colors'; -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 { Text, PackageJsonLookup } from '@rushstack/node-core-library'; +import { Colorize, ConsoleTerminalProvider, type ITerminalProvider } from '@rushstack/terminal'; import { EnvironmentVariableNames } from '@microsoft/rush-lib'; import * as rushLib from '@microsoft/rush-lib'; @@ -33,7 +33,8 @@ import { RushVersionSelector } from './RushVersionSelector'; import { MinimalRushConfiguration } from './MinimalRushConfiguration'; // Load the configuration -const configuration: MinimalRushConfiguration | undefined = MinimalRushConfiguration.loadFromDefaultLocation(); +const configuration: MinimalRushConfiguration | undefined = + MinimalRushConfiguration.loadFromDefaultLocation(); const currentPackageVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version; @@ -43,7 +44,9 @@ const previewVersion: string | undefined = process.env[EnvironmentVariableNames. if (previewVersion) { if (!semver.valid(previewVersion, false)) { - console.error(colors.red(`Invalid value for RUSH_PREVIEW_VERSION environment variable: "${previewVersion}"`)); + console.error( + Colorize.red(`Invalid value for RUSH_PREVIEW_VERSION environment variable: "${previewVersion}"`) + ); process.exit(1); } @@ -58,9 +61,7 @@ if (previewVersion) { ); if (configuration) { - lines.push( - `* The rush.json configuration asks for: ${Text.padEnd(configuration.rushVersion, 25)} *` - ); + lines.push(`* The rush.json configuration asks for: ${Text.padEnd(configuration.rushVersion, 25)} *`); } lines.push( @@ -70,10 +71,7 @@ if (previewVersion) { `*********************************************************************` ); - console.error(lines - .map(line => colors.black(colors.bgYellow(line))) - .join(os.EOL)); - + console.error(lines.map((line) => Colorize.black(Colorize.yellowBackground(line))).join(os.EOL)); } else if (configuration) { rushVersionToLoad = configuration.rushVersion; } @@ -86,15 +84,19 @@ if (rushVersionToLoad && semver.lt(rushVersionToLoad, '5.0.0-dev.18')) { // Rush is "managed" if its version and configuration are dictated by a repo's rush.json const isManaged: boolean = !!configuration; -const launchOptions: rushLib.ILaunchOptions = { isManaged, alreadyReportedNodeTooNewError }; + +const terminalProvider: ITerminalProvider = new ConsoleTerminalProvider(); + +const launchOptions: rushLib.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 if (rushVersionToLoad && rushVersionToLoad !== currentPackageVersion) { const versionSelector: RushVersionSelector = new RushVersionSelector(currentPackageVersion); - versionSelector.ensureRushVersionInstalled(rushVersionToLoad, configuration, launchOptions) + versionSelector + .ensureRushVersionInstalledAsync(rushVersionToLoad, configuration, launchOptions) .catch((error: Error) => { - console.log(colors.red('Error: ' + error.message)); + console.log(Colorize.red('Error: ' + error.message)); }); } else { // Otherwise invoke the rush-lib that came with this rush package diff --git a/apps/rush/src/test/MinimalRushConfiguration.test.ts b/apps/rush/src/test/MinimalRushConfiguration.test.ts index 1e9d614fec1..391c9feeeb2 100644 --- a/apps/rush/src/test/MinimalRushConfiguration.test.ts +++ b/apps/rush/src/test/MinimalRushConfiguration.test.ts @@ -1,44 +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 sinon from 'sinon'; -import * as path from 'path'; -import { assert } from 'chai'; +import * as path from 'node:path'; import { MinimalRushConfiguration } from '../MinimalRushConfiguration'; -describe('MinimalRushConfiguration', () => { - let sandbox: sinon.SinonSandbox; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - }); - +describe(MinimalRushConfiguration.name, () => { afterEach(() => { - sandbox.restore(); + jest.restoreAllMocks(); }); describe('legacy rush config', () => { beforeEach(() => { - sandbox.stub(process, 'cwd', () => path.join(__dirname, 'sandbox', 'legacy-repo', 'project')); + jest.spyOn(process, 'cwd').mockReturnValue(path.join(__dirname, 'sandbox', 'legacy-repo', 'project')); }); it('correctly loads the rush.json file', () => { const config: MinimalRushConfiguration = MinimalRushConfiguration.loadFromDefaultLocation() as MinimalRushConfiguration; - assert.equal(config.rushVersion, '2.5.0'); + expect(config.rushVersion).toEqual('2.5.0'); }); }); describe('non-legacy rush config', () => { beforeEach(() => { - sandbox.stub(process, 'cwd', () => path.join(__dirname, 'sandbox', 'repo', 'project')); + jest.spyOn(process, 'cwd').mockReturnValue(path.join(__dirname, 'sandbox', 'repo', 'project')); }); it('correctly loads the rush.json file', () => { const config: MinimalRushConfiguration = MinimalRushConfiguration.loadFromDefaultLocation() as MinimalRushConfiguration; - assert.equal(config.rushVersion, '4.0.0'); + expect(config.rushVersion).toEqual('4.0.0'); }); }); }); diff --git a/apps/rush/src/test/sandbox/legacy-repo/rush.json b/apps/rush/src/test/sandbox/legacy-repo/rush.json index f975dce05b9..0f78380f94a 100644 --- a/apps/rush/src/test/sandbox/legacy-repo/rush.json +++ b/apps/rush/src/test/sandbox/legacy-repo/rush.json @@ -5,29 +5,18 @@ "projectFolderMinDepth": 1, "projectFolderMaxDepth": 99, "approvedPackagesPolicy": { - "reviewCategories": [ - "first-party", - "third-party", - "prototype" - ], - "ignoredNpmScopes": [ - "@types", - "@internal" - ] + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] }, "repository": { "url": "someFakeUrl" }, "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], "sampleEmail": "mrexample@contoso.com" }, "eventHooks": { - "postRushBuild": [ - "do something" - ] + "postRushBuild": ["do something"] }, "projects": [ { @@ -36,4 +25,4 @@ "reviewCategory": "third-party" } ] -} \ No newline at end of file +} diff --git a/apps/rush/src/test/sandbox/repo/rush.json b/apps/rush/src/test/sandbox/repo/rush.json index 8601f7eadc7..a30846e627c 100644 --- a/apps/rush/src/test/sandbox/repo/rush.json +++ b/apps/rush/src/test/sandbox/repo/rush.json @@ -5,29 +5,18 @@ "projectFolderMinDepth": 1, "projectFolderMaxDepth": 99, "approvedPackagesPolicy": { - "reviewCategories": [ - "first-party", - "third-party", - "prototype" - ], - "ignoredNpmScopes": [ - "@types", - "@internal" - ] + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] }, "repository": { "url": "someFakeUrl" }, "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], "sampleEmail": "mrexample@contoso.com" }, "eventHooks": { - "postRushBuild": [ - "do something" - ] + "postRushBuild": ["do something"] }, "projects": [ { @@ -36,4 +25,4 @@ "reviewCategory": "third-party" } ] -} \ No newline at end of file +} diff --git a/apps/rush/tsconfig.json b/apps/rush/tsconfig.json index b622be5621b..dac21d04081 100644 --- a/apps/rush/tsconfig.json +++ b/apps/rush/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "mocha", - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/apps/trace-import/.npmignore b/apps/trace-import/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/apps/trace-import/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/trace-import/.vscode/launch.json b/apps/trace-import/.vscode/launch.json new file mode 100644 index 00000000000..ae7fe11604d --- /dev/null +++ b/apps/trace-import/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // 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": "trace-import", + "program": "${workspaceFolder}/lib/start.js", + "args": [ + "-r", + "cjs", + "-p", + "resolve" + ], + "cwd": "${workspaceFolder}", + "sourceMaps": true + } + ] +} \ No newline at end of file diff --git a/apps/trace-import/CHANGELOG.json b/apps/trace-import/CHANGELOG.json new file mode 100644 index 00000000000..d05571d5c0e --- /dev/null +++ b/apps/trace-import/CHANGELOG.json @@ -0,0 +1,2667 @@ +{ + "name": "@rushstack/trace-import", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.3.77", + "tag": "@rushstack/trace-import_v0.3.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.3.76", + "tag": "@rushstack/trace-import_v0.3.76", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/trace-import_v0.3.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/trace-import_v0.3.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/trace-import_v0.3.73", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/trace-import_v0.3.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/trace-import_v0.3.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/trace-import_v0.3.70", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/trace-import_v0.3.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/trace-import_v0.3.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/trace-import_v0.3.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/trace-import_v0.3.66", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/trace-import_v0.3.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/trace-import_v0.3.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/trace-import_v0.3.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/trace-import_v0.3.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.3.61", + "tag": "@rushstack/trace-import_v0.3.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/trace-import_v0.3.60", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/trace-import_v0.3.59", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/trace-import_v0.3.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/trace-import_v0.3.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/trace-import_v0.3.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/trace-import_v0.3.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/trace-import_v0.3.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/trace-import_v0.3.53", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/trace-import_v0.3.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/trace-import_v0.3.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/trace-import_v0.3.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/trace-import_v0.3.49", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/trace-import_v0.3.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/trace-import_v0.3.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/trace-import_v0.3.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/trace-import_v0.3.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/trace-import_v0.3.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/trace-import_v0.3.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/trace-import_v0.3.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/trace-import_v0.3.41", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/trace-import_v0.3.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/trace-import_v0.3.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/trace-import_v0.3.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/trace-import_v0.3.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/trace-import_v0.3.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/trace-import_v0.3.35", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/trace-import_v0.3.34", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/trace-import_v0.3.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/trace-import_v0.3.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/trace-import_v0.3.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/trace-import_v0.3.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/trace-import_v0.3.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/trace-import_v0.3.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/trace-import_v0.3.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/trace-import_v0.3.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/trace-import_v0.3.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/trace-import_v0.3.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/trace-import_v0.3.23", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/trace-import_v0.3.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/trace-import_v0.3.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/trace-import_v0.3.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/trace-import_v0.3.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/trace-import_v0.3.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/trace-import_v0.3.17", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade build dependencies" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/trace-import_v0.3.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/trace-import_v0.3.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/trace-import_v0.3.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/trace-import_v0.3.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/trace-import_v0.3.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/trace-import_v0.3.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/trace-import_v0.3.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/trace-import_v0.3.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/trace-import_v0.3.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/trace-import_v0.3.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/trace-import_v0.3.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/trace-import_v0.3.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/trace-import_v0.3.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/trace-import_v0.3.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/trace-import_v0.3.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/trace-import_v0.3.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/trace-import_v0.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/trace-import_v0.2.27", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/trace-import_v0.2.26", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/trace-import_v0.2.25", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/trace-import_v0.2.24", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/trace-import_v0.2.23", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/trace-import_v0.2.22", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/trace-import_v0.2.21", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/trace-import_v0.2.20", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/trace-import_v0.2.19", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/trace-import_v0.2.18", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/trace-import_v0.2.17", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/trace-import_v0.2.16", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/trace-import_v0.2.15", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/trace-import_v0.2.14", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/trace-import_v0.2.13", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/trace-import_v0.2.12", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/trace-import_v0.2.11", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/trace-import_v0.2.10", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/trace-import_v0.2.9", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/trace-import_v0.2.8", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/trace-import_v0.2.7", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/trace-import_v0.2.6", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/trace-import_v0.2.5", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/trace-import_v0.2.4", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/trace-import_v0.2.3", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/trace-import_v0.2.2", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/trace-import_v0.2.1", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/trace-import_v0.2.0", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the TypeScript dependency to ~5.0.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/trace-import_v0.1.18", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/trace-import_v0.1.17", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/trace-import_v0.1.16", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/trace-import_v0.1.15", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/trace-import_v0.1.14", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/trace-import_v0.1.13", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/trace-import_v0.1.12", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/trace-import_v0.1.11", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/trace-import_v0.1.10", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/trace-import_v0.1.9", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/trace-import_v0.1.8", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/trace-import_v0.1.7", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/trace-import_v0.1.6", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/trace-import_v0.1.5", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/trace-import_v0.1.4", + "date": "Sat, 21 Jan 2023 04:36:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/trace-import_v0.1.3", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/trace-import_v0.1.2", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/trace-import_v0.1.1", + "date": "Sat, 10 Dec 2022 20:40:17 GMT", + "comments": { + "patch": [ + { + "comment": "Rename \"-r\" CLI paramater to \"-t\"" + }, + { + "comment": "Fix some issues with resolution of relative import paths" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/trace-import_v0.1.0", + "date": "Fri, 09 Dec 2022 18:45:20 GMT", + "comments": { + "minor": [ + { + "comment": "Initial preview release" + } + ] + } + } + ] +} diff --git a/apps/trace-import/CHANGELOG.md b/apps/trace-import/CHANGELOG.md new file mode 100644 index 00000000000..86f8a247d1a --- /dev/null +++ b/apps/trace-import/CHANGELOG.md @@ -0,0 +1,868 @@ +# Change Log - @rushstack/trace-import + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.3.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.3.76 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.3.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.3.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.3.73 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.3.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.3.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.3.70 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.3.69 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.3.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.3.66 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.3.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.3.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.3.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.3.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.3.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.3.60 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.3.59 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.3.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.3.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.3.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.3.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.3.53 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.3.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.3.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.3.49 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.3.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.3.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.3.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.3.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.3.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.3.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.3.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.3.41 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.3.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.3.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.3.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.3.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.3.35 +Sat, 02 Mar 2024 02:22:23 GMT + +_Version update only_ + +## 0.3.34 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.3.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.3.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.3.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.3.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.3.29 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 0.3.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.3.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.3.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.3.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.3.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.3.23 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.3.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.3.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.3.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.3.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.3.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.3.17 +Tue, 16 Jan 2024 18:30:10 GMT + +### Patches + +- Upgrade build dependencies + +## 0.3.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.3.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.3.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.3.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.3.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.3.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.3.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.3.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.3.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.3.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.3.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.3.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.3.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.3.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.3.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.3.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.2.27 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.2.26 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.2.25 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.2.24 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.2.23 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 0.2.22 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.2.21 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.2.20 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.2.19 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.2.18 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.2.17 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.2.16 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.2.15 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.2.14 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.2.13 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.2.12 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.2.11 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.2.10 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.2.9 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.2.8 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.2.7 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.2.6 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.2.5 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.2.4 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.2.3 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.2.2 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.2.1 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.0 +Mon, 22 May 2023 06:34:33 GMT + +### Minor changes + +- Upgrade the TypeScript dependency to ~5.0.4 + +## 0.1.18 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.1.17 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.1.16 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.1.15 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.1.14 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.1.13 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.1.12 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.1.11 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.1.10 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.1.9 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.1.8 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.7 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.6 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.5 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.1.4 +Sat, 21 Jan 2023 04:36:33 GMT + +### Patches + +- Update README.md + +## 0.1.3 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.2 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.1.1 +Sat, 10 Dec 2022 20:40:17 GMT + +### Patches + +- Rename "-r" CLI paramater to "-t" +- Fix some issues with resolution of relative import paths + +## 0.1.0 +Fri, 09 Dec 2022 18:45:20 GMT + +### Minor changes + +- Initial preview release + diff --git a/apps/trace-import/LICENSE b/apps/trace-import/LICENSE new file mode 100644 index 00000000000..8c9044a328b --- /dev/null +++ b/apps/trace-import/LICENSE @@ -0,0 +1,24 @@ +@rushstack/trace-import + +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/trace-import/README.md b/apps/trace-import/README.md new file mode 100644 index 00000000000..cce9b091799 --- /dev/null +++ b/apps/trace-import/README.md @@ -0,0 +1,155 @@ +# @rushstack/trace-import + +> 🚨 _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 `trace-import` command line tool helps you: + +- Analyze `import`/`require()` statements to understand why they aren't resolving correctly +- Understand the relationships between package folders in your `node_modules` tree +- Ensure that `package.json` files correctly export their .js and .d.ts entry points + +## Usage + +It's recommended to install this package globally: + +``` +# Install the NPM package +npm install -g @rushstack/trace-import + +# View the command-line help +trace-import --help +``` + +## Command line + +``` +usage: trace-import [-h] [-d] -p IMPORT_PATH [-b FOLDER_PATH] [-t {cjs,es,ts}] + +This tool analyzes import module paths, to determine the resolved target +folder. For example, if the "semver" NPM package is installed, "trace-import +--path semver/index" will print output equivalent to the Node.js require. +resolve() API. If "@types/semver" is installed, then "trace-import +--resolution-type ts --path semver/index" will print the .d.ts file path that +would be resolved by a TypeScript import statement. + +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 + -p IMPORT_PATH, --path IMPORT_PATH + The import module path to be analyzed. For example, + "example" in expressions such as: require("example"); + require.resolve("example"); import { Thing } from + "example"; + -b FOLDER_PATH, --base-folder FOLDER_PATH + The "--path" string will be resolved as if the import + statement appeared in a script located in this folder. + If omitted, the current working directory is used. + -t {cjs,es,ts}, --resolution-type {cjs,es,ts} + The type of module resolution to perform: "cjs" for + CommonJS, "es" for ES modules, or "ts" for TypeScript + typings. The default value is "cjs". +``` + +## Sample outputs + +These commands were invoked in the `C:\Git\rushstack\apps\trace-import` folder +where trace-import is developed. + +### Resolving a CommonJS main index + +``` +trace-import --path semver +``` + +Sample output: + +``` +Base folder: C:\Git\rushstack\apps\trace-import +Package name: semver +Package subpath: (not specified) + +Resolving... + +Package folder: C:\Git\rushstack\common\temp\node_modules\.pnpm\semver@7.3.8\node_modules\semver +package.json: semver (7.3.8) +Main index: "main": "index.js" + +Target path: C:\Git\rushstack\common\temp\node_modules\.pnpm\semver@7.3.8\node_modules\semver\index.js +``` + +### Resolving a CommonJS package subpath + +``` +trace-import --path typescript/bin/tsc +``` + +Sample output: + +``` +Base folder: C:\Git\rushstack\apps\trace-import +Package name: typescript +Package subpath: bin/tsc + +Resolving... + +Package folder: C:\Git\rushstack\common\temp\node_modules\.pnpm\typescript@4.8.4\node_modules\typescript +package.json: typescript (4.8.4) + +Target path: C:\Git\rushstack\common\temp\node_modules\.pnpm\typescript@4.8.4\node_modules\typescript\bin\tsc +``` + +### Resolving a TypeScript declaration + +``` +trace-import --resolution-type ts --path semver +``` + +Sample output: + +``` +Base folder: C:\Git\rushstack\apps\trace-import +Package name: semver +Package subpath: (not specified) + +Resolving... + +Package folder: C:\Git\rushstack\common\temp\node_modules\.pnpm\semver@7.3.8\node_modules\semver +package.json: semver (7.3.8) +@types folder: C:\Git\rushstack\common\temp\node_modules\.pnpm\@types+semver@7.3.5\node_modules\@types\semver +@types package.json: @types/semver (7.3.5) +@types main index: "types": "index.d.ts" + +Target path: C:\Git\rushstack\common\temp\node_modules\.pnpm\@types+semver@7.3.5\node_modules\@types\semver\index.d.ts +``` + +### Resolving a relative path + +``` +trace-import --path ./config/rig.json +``` + +Sample output: + +``` +Base folder: C:\Git\rushstack\apps\trace-import +Import path: ./config/rig.json + +The import path does not appear to reference an NPM package. +Resolving... + +Target path: C:\Git\rushstack\apps\trace-import\config\rig.json +``` + +## Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/trace-import/CHANGELOG.md) - Find + out what's new in the latest version +- [Rush Lockfile Explorer](https://lfx.rushstack.io) - The desktop app for troubleshooting PNPM lockfiles + +The `trace-import` tool is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/apps/trace-import/bin/trace-import b/apps/trace-import/bin/trace-import new file mode 100644 index 00000000000..aee68e80224 --- /dev/null +++ b/apps/trace-import/bin/trace-import @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js'); diff --git a/apps/trace-import/config/jest.config.json b/apps/trace-import/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/trace-import/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/trace-import/config/rig.json b/apps/trace-import/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/trace-import/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/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 new file mode 100644 index 00000000000..bfa67041aac --- /dev/null +++ b/apps/trace-import/package.json @@ -0,0 +1,35 @@ +{ + "name": "@rushstack/trace-import", + "version": "0.6.7", + "description": "CLI tool for understanding how require() and \"import\" statements get resolved", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/trace-import" + }, + "bin": { + "trace-import": "./bin/trace-import" + }, + "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/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "typescript": "~5.8.2" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/resolve": "1.20.2", + "@types/semver": "7.5.0", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/apps/trace-import/src/TraceImportCommandLineParser.ts b/apps/trace-import/src/TraceImportCommandLineParser.ts new file mode 100644 index 00000000000..f34cec4a90d --- /dev/null +++ b/apps/trace-import/src/TraceImportCommandLineParser.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + CommandLineParser, + type CommandLineFlagParameter, + type CommandLineStringParameter, + type IRequiredCommandLineStringParameter, + type IRequiredCommandLineChoiceParameter +} from '@rushstack/ts-command-line'; +import { InternalError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { type ResolutionType, traceImport } from './traceImport'; + +export class TraceImportCommandLineParser extends CommandLineParser { + private readonly _debugParameter: CommandLineFlagParameter; + private readonly _pathParameter: IRequiredCommandLineStringParameter; + private readonly _baseFolderParameter: CommandLineStringParameter; + private readonly _resolutionTypeParameter: IRequiredCommandLineChoiceParameter; + + public constructor() { + super({ + toolFilename: 'trace-import', + toolDescription: + 'This tool analyzes import module paths, to determine the resolved target folder. ' + + 'For example, if the "semver" NPM package is installed, "trace-import --path semver/index" will ' + + 'print output equivalent to the Node.js require.resolve() API. ' + + 'If "@types/semver" is installed, then "trace-import --resolution-type ts --path semver/index" will ' + + 'print the .d.ts file path that would be resolved by a TypeScript import statement.' + }); + + this._debugParameter = this.defineFlagParameter({ + parameterLongName: '--debug', + parameterShortName: '-d', + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + this._pathParameter = this.defineStringParameter({ + parameterLongName: '--path', + parameterShortName: '-p', + description: + 'The import module path to be analyzed. For example, ' + + '"example" in expressions such as: require("example"); require.resolve("example"); import { Thing } from "example";', + argumentName: 'IMPORT_PATH', + required: true + }); + + this._baseFolderParameter = this.defineStringParameter({ + parameterLongName: '--base-folder', + parameterShortName: '-b', + description: + 'The "--path" string will be resolved as if the import statement appeared in a script located in this folder. ' + + 'If omitted, the current working directory is used.', + argumentName: 'FOLDER_PATH' + }); + + this._resolutionTypeParameter = this.defineChoiceParameter({ + parameterLongName: '--resolution-type', + parameterShortName: '-t', + description: + 'The type of module resolution to perform: ' + + '"cjs" for CommonJS, "es" for ES modules, or "ts" for TypeScript typings', + alternatives: ['cjs', 'es', 'ts'], + defaultValue: 'cjs' + }); + } + + protected override async onExecuteAsync(): Promise { + if (this._debugParameter.value) { + InternalError.breakInDebugger = true; + } + try { + traceImport({ + importPath: this._pathParameter.value, + baseFolder: this._baseFolderParameter.value, + resolutionType: this._resolutionTypeParameter.value + }); + } catch (error) { + if (this._debugParameter.value) { + console.error('\n' + error.stack); + } else { + console.error('\n' + Colorize.red('ERROR: ' + error.message.trim())); + } + } + } +} diff --git a/apps/trace-import/src/start.ts b/apps/trace-import/src/start.ts new file mode 100644 index 00000000000..a14bfe9247f --- /dev/null +++ b/apps/trace-import/src/start.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 { PackageJsonLookup } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { TraceImportCommandLineParser } from './TraceImportCommandLineParser'; + +const toolVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version; + +console.log(); +console.log(Colorize.bold(`trace-import ${toolVersion}`) + ' - ' + Colorize.cyan('https://rushstack.io')); +console.log(); + +const commandLine: TraceImportCommandLineParser = new TraceImportCommandLineParser(); +commandLine.executeAsync().catch((error) => { + console.error(error); +}); diff --git a/apps/trace-import/src/traceImport.ts b/apps/trace-import/src/traceImport.ts new file mode 100644 index 00000000000..28ae8ddc8a8 --- /dev/null +++ b/apps/trace-import/src/traceImport.ts @@ -0,0 +1,332 @@ +// 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, + type IParsedPackageName, + JsonFile, + PackageName +} from '@rushstack/node-core-library'; + +const jsExtensions: string[] = ['.js', '.cjs', '.jsx', '.json']; +const tsExtensions: string[] = ['.d.ts', '.ts', '.tsx', '.json']; + +export type ResolutionType = 'cjs' | 'es' | 'ts'; + +interface IExecuteOptions { + importPath: string; + baseFolder: string | undefined; + resolutionType: ResolutionType; +} + +// Somewhat loosely matches inputs such as: +// my-package/path/to/file.js +// [group 1 ][group 2 ] +// +// @scope/my-package/path/to/file.js +// [group 1 ][group 2 ] +// +// @scope/my-package +// [group 1 ] +const packageImportPathRegExp: RegExp = /^((?:@[a-z0-9_][a-z0-9\-_\.]*\/)?[a-z0-9_][a-z0-9\-_\.]*)(\/.*)?$/i; + +function logInputField(title: string, value: string): void { + console.log(Colorize.cyan(title.padEnd(25)) + value); +} + +function logOutputField(title: string, value: string): void { + console.log(Colorize.green(title.padEnd(25)) + value); +} + +function traceTypeScriptPackage(options: { + packageSubpath: string; + packageFolder: string; + packageJson: IPackageJson; + warnings: string[]; + atTypes?: boolean; +}): boolean { + const { packageSubpath, packageFolder, packageJson, atTypes, warnings } = options; + + // For example, if we started with importFullPath="semver/index", + // here we may get normalizedImportFullPath="@types/semver/index" + const normalizedImportFullPath: string = packageJson.name + packageSubpath; + + // First try to resolve the .js main index + let cjsTargetPath: string | undefined = undefined; + try { + cjsTargetPath = Resolve.sync(normalizedImportFullPath, { + basedir: packageFolder, + preserveSymlinks: false, + extensions: jsExtensions + }); + } catch (error) { + // not found + } + + const mainIndexTitle: string = atTypes ? '@types main index:' : 'Main index:'; + + if (cjsTargetPath) { + const parsedPath: path.ParsedPath = path.parse(cjsTargetPath); + + // Is the resolved .js extension okay? + if (tsExtensions.indexOf(parsedPath.ext.toLocaleLowerCase()) >= 0) { + logOutputField(mainIndexTitle, '(inferred from .js main index)'); + console.log(); + logOutputField('Target path:', cjsTargetPath); + return true; + } + + // Try to replace the file extension + const dtsTargetPath: string = path.join(parsedPath.dir, parsedPath.name + '.d.ts'); + if (FileSystem.exists(dtsTargetPath)) { + logOutputField(mainIndexTitle, '(inferred from .js entry point)'); + console.log(); + logOutputField('Target path:', dtsTargetPath); + return true; + } + } + + if (!packageSubpath) { + // Try importing the "types"/"typings" main index: + + if (packageJson.types) { + logOutputField(mainIndexTitle, `"types": ${JSON.stringify(packageJson.types)}`); + console.log(); + logOutputField('Target path:', path.join(packageFolder, packageJson.types)); + return true; + } + + if (packageJson.typings) { + logOutputField(mainIndexTitle, `"typings": ${JSON.stringify(packageJson.typings)}`); + console.log(); + logOutputField('Target path:', path.join(packageFolder, packageJson.typings)); + return true; + } + + if (atTypes) { + warnings.push('The @types package does not define "types" or "typings" field.'); + } + } else { + // Try importing the .d.ts file directly + let dtsTargetPath: string | undefined = undefined; + try { + dtsTargetPath = Resolve.sync(normalizedImportFullPath, { + basedir: packageFolder, + preserveSymlinks: false, + extensions: tsExtensions + }); + } catch (error) { + // not found + } + + if (dtsTargetPath) { + console.log(); + logOutputField('Target path:', dtsTargetPath); + return true; + } + } + + return false; +} + +function traceImportInner(options: IExecuteOptions, warnings: string[]): void { + let baseFolder: string; + if (options.baseFolder) { + baseFolder = path.resolve(options.baseFolder); + } else { + baseFolder = process.cwd(); + } + + const importFullPath: string = options.importPath.trim(); + if (!importFullPath) { + throw new Error(`Invalid import path syntax: ${JSON.stringify(importFullPath)}`); + } + const match: RegExpExecArray | null = packageImportPathRegExp.exec(importFullPath); + + logInputField('Base folder:', baseFolder); + + if (match) { + const importPackageName: string = match[1]; + const packageSubpath: string | undefined = match[2]; + const packageSubpathWithoutSlash: string | undefined = packageSubpath + ? packageSubpath.substring(1) + : undefined; + + logInputField('Package name:', importPackageName); + logInputField('Package subpath:', packageSubpathWithoutSlash || '(not specified)'); + + console.log('\nResolving...\n'); + + // Resolve the NPM package first + let packageFolder: string | undefined; + let packageJson: IPackageJson | undefined = undefined; + { + let resolvedPackageJsonPath: string | undefined; + try { + resolvedPackageJsonPath = Resolve.sync(`${importPackageName}/package.json`, { + basedir: baseFolder, + preserveSymlinks: false + }); + } catch (e) { + // Could not find NPM package + } + + if (resolvedPackageJsonPath) { + packageFolder = path.dirname(resolvedPackageJsonPath); + logOutputField('Package folder:', packageFolder); + + packageJson = JsonFile.load(resolvedPackageJsonPath) as IPackageJson; + logOutputField( + 'package.json:', + `${packageJson.name || '(missing name)'} (${packageJson.version || 'missing version'})` + ); + } + } + + // Also try to resolve the @types package + let atTypesPackageFolder: string | undefined = undefined; + let atTypesPackageJson: IPackageJson | undefined = undefined; + + if (options.resolutionType === 'ts') { + if (!importPackageName.startsWith('@types/')) { + const parsedPackageName: IParsedPackageName = PackageName.parse(importPackageName); + let atTypesPackageName: string; + if (parsedPackageName.scope) { + atTypesPackageName = `@types/${parsedPackageName.scope}__${parsedPackageName.unscopedName}`; + } else { + atTypesPackageName = `@types/${parsedPackageName.unscopedName}`; + } + + let atTypesPackageJsonPath: string | undefined; + try { + atTypesPackageJsonPath = Resolve.sync(`${atTypesPackageName}/package.json`, { + basedir: baseFolder, + preserveSymlinks: false + }); + } catch (e) { + // Unable to resolve @types package + } + + if (atTypesPackageJsonPath) { + atTypesPackageFolder = path.dirname(atTypesPackageJsonPath); + logOutputField('@types folder:', atTypesPackageFolder); + + atTypesPackageJson = JsonFile.load(atTypesPackageJsonPath) as IPackageJson; + logOutputField( + '@types package.json:', + `${atTypesPackageJson.name || '(missing name)'} (${ + atTypesPackageJson.version || 'missing version' + })` + ); + } + } + } + + switch (options.resolutionType) { + case 'cjs': + { + if (!packageFolder || !packageJson) { + throw new Error(`Cannot find package "${importPackageName}" from "${baseFolder}".`); + } + + if (!packageSubpath) { + if (packageJson.main) { + logOutputField('Main index:', `"main": ${JSON.stringify(packageJson.main)}`); + } else { + logOutputField('Main index:', '(none)'); + } + } + + let targetPath: string; + try { + targetPath = Resolve.sync(importFullPath, { + basedir: packageFolder, + preserveSymlinks: false, + extensions: jsExtensions + }); + } catch (error) { + // Are we importing the main index? + if (packageSubpath) { + throw new Error(`Unable to resolve the module subpath: ...${packageSubpath}`); + } else { + console.log('\nThis package does not define a main index.'); + return; + } + } + console.log(); + logOutputField('Target path:', targetPath); + } + break; + case 'ts': + if (!packageFolder || (!packageJson && !atTypesPackageFolder && !atTypesPackageJson)) { + throw new Error(`Cannot find package "${importPackageName}" from "${baseFolder}".`); + } + + if (packageFolder && packageJson) { + if (traceTypeScriptPackage({ packageSubpath, packageFolder, packageJson, warnings })) { + if (atTypesPackageFolder) { + warnings.push('An @types package was found but not used.'); + } + + return; + } + } + + if (atTypesPackageFolder && atTypesPackageJson) { + if ( + traceTypeScriptPackage({ + packageSubpath, + packageFolder: atTypesPackageFolder, + packageJson: atTypesPackageJson, + warnings, + atTypes: true + }) + ) { + return; + } + } + + throw new Error(`Unable to resolve the module subpath: ...${packageSubpath}`); + default: + throw new Error(`The "${options.resolutionType}" resolution type is not implemented yet`); + } + } else { + logInputField('Import path:', importFullPath); + console.log(`\nThe import path does not appear to reference an NPM package.`); + console.log('Resolving...\n'); + + let targetPath: string; + try { + targetPath = Resolve.sync(importFullPath, { + basedir: baseFolder, + preserveSymlinks: false, + extensions: options.resolutionType === 'ts' ? tsExtensions : jsExtensions + }); + } catch (error) { + throw new Error(`Unable to resolve the import path: ${importFullPath}`); + } + + logOutputField('Target path:', targetPath); + } +} + +export function traceImport(options: IExecuteOptions): void { + const warnings: string[] = []; + try { + traceImportInner(options, warnings); + } finally { + if (warnings.length) { + console.log(); + for (const warning of warnings) { + console.log(Colorize.yellow('Warning: ' + warning)); + } + } + } +} diff --git a/apps/trace-import/tsconfig.json b/apps/trace-import/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/trace-import/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/zipsync/.npmignore b/apps/zipsync/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/apps/zipsync/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..c0758248b5d --- /dev/null +++ b/apps/zipsync/CHANGELOG.json @@ -0,0 +1,213 @@ +{ + "name": "@rushstack/zipsync", + "entries": [ + { + "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..0235e39e8a4 --- /dev/null +++ b/apps/zipsync/CHANGELOG.md @@ -0,0 +1,58 @@ +# Change Log - @rushstack/zipsync + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..aee68e80224 --- /dev/null +++ b/apps/zipsync/bin/zipsync @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/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..72ba67e300c --- /dev/null +++ b/apps/zipsync/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/zipsync", + "version": "0.2.7", + "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:*" + } +} 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..e005983feb4 --- /dev/null +++ b/apps/zipsync/src/cli/test/__snapshots__/start.test.ts.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..f57f26a3ce6 --- /dev/null +++ b/apps/zipsync/src/cli/test/start.test.ts @@ -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. + +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/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/.vscode/launch.json b/build-tests-samples/heft-node-basic-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..fd7bdc34fb4 --- /dev/null +++ b/build-tests-samples/heft-node-basic-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 Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-node-basic-tutorial/README.md b/build-tests-samples/heft-node-basic-tutorial/README.md new file mode 100644 index 00000000000..7ba01eb27e9 --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-node-basic-tutorial + +This is a copy of the +[heft-node-basic-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-node-basic-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-node-basic-tutorial/config/heft.json b/build-tests-samples/heft-node-basic-tutorial/config/heft.json new file mode 100644 index 00000000000..c1211a3c86c --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/config/heft.json @@ -0,0 +1,38 @@ +/** + * 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"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..8ae16adcbda --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.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-node-basic-tutorial/config/rush-project.json b/build-tests-samples/heft-node-basic-tutorial/config/rush-project.json new file mode 100644 index 00000000000..9042450ba22 --- /dev/null +++ b/build-tests-samples/heft-node-basic-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..f929d22a07f --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/package.json @@ -0,0 +1,24 @@ +{ + "name": "heft-node-basic-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "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:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "@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/index.ts b/build-tests-samples/heft-node-basic-tutorial/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/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-samples/heft-node-basic-tutorial/src/test/ExampleTest.test.ts b/build-tests-samples/heft-node-basic-tutorial/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/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-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 new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests-samples/heft-node-basic-tutorial/tsconfig.json b/build-tests-samples/heft-node-basic-tutorial/tsconfig.json new file mode 100644 index 00000000000..36f4f4267dc --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$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, + + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests-samples/heft-node-jest-tutorial/.vscode/launch.json b/build-tests-samples/heft-node-jest-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..fd7bdc34fb4 --- /dev/null +++ b/build-tests-samples/heft-node-jest-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 Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-node-jest-tutorial/README.md b/build-tests-samples/heft-node-jest-tutorial/README.md new file mode 100644 index 00000000000..938d941ac7d --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-node-jest-tutorial + +This is a copy of the +[heft-node-jest-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-node-jest-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-node-jest-tutorial/config/heft.json b/build-tests-samples/heft-node-jest-tutorial/config/heft.json new file mode 100644 index 00000000000..304ccc96c03 --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/config/heft.json @@ -0,0 +1,35 @@ +{ + "$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" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..09a743c117f --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/config/jest.config.json @@ -0,0 +1,22 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + "coverageThreshold": { + "global": { + "branches": 50, + "functions": 50, + "lines": 50, + "statements": 50 + } + }, + + // 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-node-jest-tutorial/config/rush-project.json b/build-tests-samples/heft-node-jest-tutorial/config/rush-project.json new file mode 100644 index 00000000000..9042450ba22 --- /dev/null +++ b/build-tests-samples/heft-node-jest-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..cb3fea8b244 --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/package.json @@ -0,0 +1,23 @@ +{ + "name": "heft-node-jest-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "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:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "@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 new file mode 100644 index 00000000000..c3a6e1a4d98 --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/01-automatic-mock.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. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks#automatic-mock + +jest.mock('./SoundPlayer'); // SoundPlayer is now a mock constructor + +import { SoundPlayer } from './SoundPlayer'; +import { SoundPlayerConsumer } from './SoundPlayerConsumer'; + +beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + mocked(SoundPlayer).mockClear(); +}); + +it('We can check if the consumer called the class constructor', () => { + new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + // Show that mockClear() is working: + expect(SoundPlayer).not.toHaveBeenCalled(); + + const soundPlayerConsumer: SoundPlayerConsumer = new SoundPlayerConsumer(); + // Constructor should have been called again: + expect(SoundPlayer).toHaveBeenCalledTimes(1); + + const coolSoundFileName: string = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + + // mock.instances is available with automatic mocks: + const mockSoundPlayerInstance: SoundPlayer = mocked(SoundPlayer).mock.instances[0]; + + const mockPlaySoundFile = mocked(mockSoundPlayerInstance.playSoundFile); + expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); + + // Equivalent to above check: + expect(mockPlaySoundFile).toHaveBeenCalledWith(coolSoundFileName); + expect(mockPlaySoundFile).toHaveBeenCalledTimes(1); +}); diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayer.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayer.ts new file mode 100644 index 00000000000..e1459e70e6e --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayer.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. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks + +export class SoundPlayer { + private _foo: string; + + public constructor() { + this._foo = 'bar'; + } + + public playSoundFile(fileName: string): void { + // eslint-disable-next-line no-console + console.log('Playing sound file ' + fileName); + // eslint-disable-next-line no-console + console.log('Foo=' + this._foo); + } +} 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 new file mode 100644 index 00000000000..af79f63945d --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.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. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks#manual-mock + +jest.mock('./SoundPlayer'); // SoundPlayer is now a mock constructor + +import { SoundPlayer } from './SoundPlayer'; +import { mockPlaySoundFile } from './__mocks__/SoundPlayer'; +import { SoundPlayerConsumer } from './SoundPlayerConsumer'; + +beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + mocked(SoundPlayer).mockClear(); + mockPlaySoundFile.mockClear(); +}); + +it('We can check if the consumer called the class constructor', () => { + new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + const soundPlayerConsumer: SoundPlayerConsumer = new SoundPlayerConsumer(); + const coolSoundFileName: string = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + expect(mockPlaySoundFile).toHaveBeenCalledWith(coolSoundFileName); +}); + +// The test below validates that jest-improved-resolver.js is working correctly +import { SoundPlayer as MockSoundPlayer } from './__mocks__/SoundPlayer'; + +it('Importing ./__mocks__/SoundPlayer returns the same object as importing ./SoundPlayer', () => { + expect(SoundPlayer).toBe(MockSoundPlayer); +}); diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.ts new file mode 100644 index 00000000000..c860b9f816a --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks + +import { SoundPlayer } from './SoundPlayer'; + +export class SoundPlayerConsumer { + private _soundPlayer: SoundPlayer; + public constructor() { + this._soundPlayer = new SoundPlayer(); + } + + public playSomethingCool(): void { + const coolSoundFileName: string = 'song.mp3'; + this._soundPlayer.playSoundFile(coolSoundFileName); + } +} diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/__mocks__/SoundPlayer.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/__mocks__/SoundPlayer.ts new file mode 100644 index 00000000000..0541a13992a --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/__mocks__/SoundPlayer.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Import this named export into your test file: +export const mockPlaySoundFile = jest.fn(); + +const SoundPlayer = jest.fn().mockImplementation(() => { + return { playSoundFile: mockPlaySoundFile }; +}); + +export { SoundPlayer }; 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 new file mode 100644 index 00000000000..bcd44bb804f --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/03-factory-constructor-mock.test.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. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks#complete-example + +const mockPlaySoundFile = jest.fn(); + +jest.mock('./SoundPlayer', () => { + return { + SoundPlayer: jest.fn().mockImplementation(() => { + return { playSoundFile: mockPlaySoundFile }; + }) + }; +}); + +import { SoundPlayerConsumer } from './SoundPlayerConsumer'; +import { SoundPlayer } from './SoundPlayer'; + +beforeEach(() => { + mocked(SoundPlayer).mockClear(); + mockPlaySoundFile.mockClear(); +}); + +it('The consumer should be able to call new() on SoundPlayer', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + // Ensure constructor created the object: + expect(soundPlayerConsumer).toBeTruthy(); +}); + +it('We can check if the consumer called the class constructor', () => { + new SoundPlayerConsumer(); + expect(SoundPlayer).toHaveBeenCalledTimes(1); +}); + +it('We can check if the consumer called a method on the class instance', () => { + const soundPlayerConsumer = new SoundPlayerConsumer(); + const coolSoundFileName: string = 'song.mp3'; + soundPlayerConsumer.playSomethingCool(); + expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); +}); diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayer.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayer.ts new file mode 100644 index 00000000000..e1459e70e6e --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayer.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. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks + +export class SoundPlayer { + private _foo: string; + + public constructor() { + this._foo = 'bar'; + } + + public playSoundFile(fileName: string): void { + // eslint-disable-next-line no-console + console.log('Playing sound file ' + fileName); + // eslint-disable-next-line no-console + console.log('Foo=' + this._foo); + } +} diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayerConsumer.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayerConsumer.ts new file mode 100644 index 00000000000..c860b9f816a --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/SoundPlayerConsumer.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks + +import { SoundPlayer } from './SoundPlayer'; + +export class SoundPlayerConsumer { + private _soundPlayer: SoundPlayer; + public constructor() { + this._soundPlayer = new SoundPlayer(); + } + + public playSomethingCool(): void { + const coolSoundFileName: string = 'song.mp3'; + this._soundPlayer.playSoundFile(coolSoundFileName); + } +} diff --git a/build-tests-samples/heft-node-jest-tutorial/src/inlineSnapshot.test.ts b/build-tests-samples/heft-node-jest-tutorial/src/inlineSnapshot.test.ts new file mode 100644 index 00000000000..10b12fbf160 --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/src/inlineSnapshot.test.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This example is adapted from the Jest guide here: +// https://jestjs.io/docs/en/es6-class-mocks#automatic-mock + +it('Generate an inline snapshot', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const thing: any = { + abc: 123, + def: { + ghi: 'test!' + } + }; + + expect(thing).toMatchInlineSnapshot(` + Object { + "abc": 123, + "def": Object { + "ghi": "test!", + }, + } + `); +}); diff --git a/build-tests-samples/heft-node-jest-tutorial/tsconfig.json b/build-tests-samples/heft-node-jest-tutorial/tsconfig.json new file mode 100644 index 00000000000..36f4f4267dc --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$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, + + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests-samples/heft-node-rig-tutorial/.vscode/launch.json b/build-tests-samples/heft-node-rig-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..fd7bdc34fb4 --- /dev/null +++ b/build-tests-samples/heft-node-rig-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 Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-node-rig-tutorial/README.md b/build-tests-samples/heft-node-rig-tutorial/README.md new file mode 100644 index 00000000000..f1d5a4e54fb --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-node-rig-tutorial + +This is a copy of the +[heft-node-rig-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-node-rig-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-node-rig-tutorial/config/jest.config.json b/build-tests-samples/heft-node-rig-tutorial/config/jest.config.json new file mode 100644 index 00000000000..c1f53a85731 --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.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-node-rig-tutorial/config/rig.json b/build-tests-samples/heft-node-rig-tutorial/config/rig.json new file mode 100644 index 00000000000..f6c7b5537dc --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/config/rig.json @@ -0,0 +1,18 @@ +// 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", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@rushstack/heft-node-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/build-tests-samples/heft-node-rig-tutorial/config/rush-project.json b/build-tests-samples/heft-node-rig-tutorial/config/rush-project.json new file mode 100644 index 00000000000..417e302ddcc --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/config/rush-project.json @@ -0,0 +1,15 @@ +// This file exists for caching purposes in the rushstack repo +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "release"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..8bf9f48e2e7 --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/package.json @@ -0,0 +1,21 @@ +{ + "name": "heft-node-rig-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "local-eslint-config": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-node-rig": "workspace:*", + "@types/heft-jest": "1.0.1", + "@types/node": "20.17.19", + "eslint": "~9.37.0" + } +} diff --git a/build-tests-samples/heft-node-rig-tutorial/src/index.ts b/build-tests-samples/heft-node-rig-tutorial/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/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-samples/heft-node-rig-tutorial/src/test/ExampleTest.test.ts b/build-tests-samples/heft-node-rig-tutorial/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/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-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 new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests-samples/heft-node-rig-tutorial/tsconfig.json b/build-tests-samples/heft-node-rig-tutorial/tsconfig.json new file mode 100644 index 00000000000..8c61f6719f3 --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "isolatedModules": true, + "types": ["heft-jest", "node"] + } +} diff --git a/build-tests-samples/heft-serverless-stack-tutorial/.gitignore b/build-tests-samples/heft-serverless-stack-tutorial/.gitignore new file mode 100644 index 00000000000..374b23b3a7b --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/.gitignore @@ -0,0 +1,2 @@ +.sst/ +.build/ diff --git a/build-tests-samples/heft-serverless-stack-tutorial/.sst/stage b/build-tests-samples/heft-serverless-stack-tutorial/.sst/stage new file mode 100644 index 00000000000..c23f7a80886 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/.sst/stage @@ -0,0 +1 @@ +prod \ No newline at end of file diff --git a/build-tests-samples/heft-serverless-stack-tutorial/README.md b/build-tests-samples/heft-serverless-stack-tutorial/README.md new file mode 100644 index 00000000000..60bfebef5fc --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/README.md @@ -0,0 +1,24 @@ +# heft-serverless-stack-tutorial + +This project illustrates usage of the +[@rushstack/heft-serverless-stack-plugin](https://www.npmjs.com/package/@rushstack/heft-serverless-stack-plugin) +plugin. See that documentation for details. + +## Running the demo + +1. [Create an AWS account](https://serverless-stack.com/chapters/create-an-aws-account.html) if you don't already have one. + +2. Follow the Serverless Stack [setup instructions](https://serverless-stack.com/chapters/create-an-iam-user.html) to create an IAM User and provide your access key to `aws configure` + +3. Build the project using the `--sst` switch: + +```shell +# Build the project +$ heft build --sst + +# Deploy the stub lambda and launch the local development client +$ heft start --sst + +# Jest tests are run in the usual way +$ heft test +``` diff --git a/build-tests-samples/heft-serverless-stack-tutorial/config/heft.json b/build-tests-samples/heft-serverless-stack-tutorial/config/heft.json new file mode 100644 index 00000000000..ab858871b9f --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/config/heft.json @@ -0,0 +1,44 @@ +/** + * 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", ".build"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "serverless-stack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-serverless-stack-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..8ae16adcbda --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.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-serverless-stack-tutorial/config/rush-project.json b/build-tests-samples/heft-serverless-stack-tutorial/config/rush-project.json new file mode 100644 index 00000000000..9042450ba22 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..7ae76842a26 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/package.json @@ -0,0 +1,35 @@ +{ + "name": "heft-serverless-stack-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "0.1.0", + "private": true, + "scripts": { + "test": "heft test --clean", + "start": "heft build-watch --sst", + "build": "heft build --clean", + "deploy": "sst deploy", + "remove": "sst remove", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@aws-sdk/client-sso-oidc": "^3.567.0", + "@aws-sdk/client-sts": "^3.567.0", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-serverless-stack-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@serverless-stack/aws-lambda-ric": "^2.0.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": "20.17.19", + "aws-cdk-lib": "2.189.1", + "constructs": "~10.0.98", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests-samples/heft-serverless-stack-tutorial/src/lambda.ts b/build-tests-samples/heft-serverless-stack-tutorial/src/lambda.ts new file mode 100644 index 00000000000..fa6a2bda2b4 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/src/lambda.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. + +import type { APIGatewayProxyHandlerV2 } from 'aws-lambda'; + +export const handler: APIGatewayProxyHandlerV2 = async (event) => { + return { + statusCode: 200, + headers: { 'Content-Type': 'text/plain' }, + body: `Hello, World! Your request was received at ${event.requestContext.time}.` + }; +}; diff --git a/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/MyStack.ts b/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/MyStack.ts new file mode 100644 index 00000000000..93b89b02ba9 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/MyStack.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 * as sst from '@serverless-stack/resources'; + +export default class MyStack extends sst.Stack { + public constructor(scope: sst.App, id: string, props?: sst.StackProps) { + super(scope, id, props); + + // Create a HTTP API + const api = new sst.Api(this, 'Api', { + routes: { + 'GET /': 'lib/lambda.handler' + } + }); + + // Show the endpoint in the output + this.addOutputs({ + ApiEndpoint: api.url + }); + } +} 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 new file mode 100644 index 00000000000..d8e9f7ecc71 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/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. + +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({ + runtime: 'nodejs14.x' + }); + + // eslint-disable-next-line + new MyStack(app, 'my-stack'); + + // Add more stacks +} diff --git a/build-tests-samples/heft-serverless-stack-tutorial/src/test/MyStack.test.ts b/build-tests-samples/heft-serverless-stack-tutorial/src/test/MyStack.test.ts new file mode 100644 index 00000000000..74785d4607a --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/src/test/MyStack.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. + +// TODO: Jest tests should not be invoking ESBuild or making network calls! Reenable this once +// we have a fix for https://github.com/serverless-stack/serverless-stack/issues/1537 + +// import { Template } from 'aws-cdk-lib/assertions'; +// import * as sst from '@serverless-stack/resources'; +// import MyStack from '../stacks/MyStack'; + +test('Test Stack', () => { + // const app = new sst.App(); + // const stack: MyStack = new MyStack(app, 'test-stack'); + // const template = Template.fromStack(stack); + // template.resourceCountIs('AWS::Lambda::Function', 1); +}); diff --git a/build-tests-samples/heft-serverless-stack-tutorial/sst.json b/build-tests-samples/heft-serverless-stack-tutorial/sst.json new file mode 100644 index 00000000000..e8db74fdcdf --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/sst.json @@ -0,0 +1,9 @@ +{ + "name": "heft-serverless-stack-tutorial", + "region": "us-east-1", + "main": "lib/stacks/index.js", + + "//": "Disable lint and typeCheck because they are handled by Heft:", + "lint": false, + "typeCheck": false +} diff --git a/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json b/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json new file mode 100644 index 00000000000..fabb41a31d0 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json @@ -0,0 +1,31 @@ +{ + "$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, + + "skipLibCheck": true, // Some of the AWS dependencies have typings issues + + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017", "DOM"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests-samples/heft-storybook-react-tutorial-app/README.md b/build-tests-samples/heft-storybook-react-tutorial-app/README.md new file mode 100644 index 00000000000..a51453334cc --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-app/README.md @@ -0,0 +1,4 @@ +# 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 new file mode 100644 index 00000000000..47c99bce595 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-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 new file mode 100644 index 00000000000..f3549d52dfd --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial-app/package.json b/build-tests-samples/heft-storybook-react-tutorial-app/package.json new file mode 100644 index 00000000000..837d98a0703 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-app/package.json @@ -0,0 +1,19 @@ +{ + "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:lite-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 new file mode 100644 index 00000000000..68de8a6a8f7 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.cjs @@ -0,0 +1,13 @@ +"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 new file mode 100644 index 00000000000..da28051ed33 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.d.ts @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..230b842e312 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..3d5f4ebba45 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial-storykit/package.json @@ -0,0 +1,38 @@ +{ + "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": "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" + } +} diff --git a/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js b/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js new file mode 100644 index 00000000000..d4d78a64362 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js @@ -0,0 +1,4 @@ +module.exports = { + stories: ['../lib/**/*.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-react-tutorial/.storybook/preview.js new file mode 100644 index 00000000000..30f63ee2960 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/.vscode/launch.json b/build-tests-samples/heft-storybook-react-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..32591233b77 --- /dev/null +++ b/build-tests-samples/heft-storybook-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/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 new file mode 100644 index 00000000000..c79d7763687 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial/README.md @@ -0,0 +1,8 @@ +# 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/assets/index.html b/build-tests-samples/heft-storybook-react-tutorial/assets/index.html new file mode 100644 index 00000000000..9e89ef57d85 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial/assets/index.html @@ -0,0 +1,12 @@ + + + + + + Example Application + + + +
+ + diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/heft.json b/build-tests-samples/heft-storybook-react-tutorial/config/heft.json new file mode 100644 index 00000000000..490f1eb3b74 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-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-react-tutorial/config/jest.config.json new file mode 100644 index 00000000000..5e165f55d1d --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/config/rush-project.json b/build-tests-samples/heft-storybook-react-tutorial/config/rush-project.json new file mode 100644 index 00000000000..9042450ba22 --- /dev/null +++ b/build-tests-samples/heft-storybook-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/typescript.json b/build-tests-samples/heft-storybook-react-tutorial/config/typescript.json new file mode 100644 index 00000000000..80efdd16510 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/eslint.config.js b/build-tests-samples/heft-storybook-react-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/package.json b/build-tests-samples/heft-storybook-react-tutorial/package.json new file mode 100644 index 00000000000..1ec432924a9 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial/package.json @@ -0,0 +1,44 @@ +{ + "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.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/heft-jest": "1.0.1", + "@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-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-react-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/ExampleApp.tsx new file mode 100644 index 00000000000..d81154eaefe --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/src/ToggleSwitch.stories.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.stories.tsx new file mode 100644 index 00000000000..f9b6d3ab7ee --- /dev/null +++ b/build-tests-samples/heft-storybook-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-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-react-tutorial/src/ToggleSwitch.tsx new file mode 100644 index 00000000000..79e43aad327 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/src/index.css b/build-tests-samples/heft-storybook-react-tutorial/src/index.css new file mode 100644 index 00000000000..47cd6d4c1ad --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/src/index.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/index.tsx new file mode 100644 index 00000000000..d2a345895ca --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/src/test/ToggleSwitch.test.ts new file mode 100644 index 00000000000..0891628cc54 --- /dev/null +++ b/build-tests-samples/heft-storybook-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-react-tutorial/tsconfig.json b/build-tests-samples/heft-storybook-react-tutorial/tsconfig.json new file mode 100644 index 00000000000..4d703032a26 --- /dev/null +++ b/build-tests-samples/heft-storybook-react-tutorial/tsconfig.json @@ -0,0 +1,31 @@ +{ + "$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 new file mode 100644 index 00000000000..e509592fe18 --- /dev/null +++ b/build-tests-samples/heft-storybook-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', '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-web-rig-app-tutorial/README.md b/build-tests-samples/heft-web-rig-app-tutorial/README.md new file mode 100644 index 00000000000..11d2ad10171 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-web-rig-app-tutorial + +This is a copy of the +[heft-web-rig-app-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-web-rig-app-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-web-rig-app-tutorial/assets/index.html b/build-tests-samples/heft-web-rig-app-tutorial/assets/index.html new file mode 100644 index 00000000000..9e89ef57d85 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/assets/index.html @@ -0,0 +1,12 @@ + + + + + + Example Application + + + +
+ + diff --git a/build-tests-samples/heft-web-rig-app-tutorial/config/jest.config.json b/build-tests-samples/heft-web-rig-app-tutorial/config/jest.config.json new file mode 100644 index 00000000000..29266733d41 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-web-rig/profiles/app/config/jest.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-web-rig-app-tutorial/config/rig.json b/build-tests-samples/heft-web-rig-app-tutorial/config/rig.json new file mode 100644 index 00000000000..687fc2911bc --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/config/rig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-web-rig", + "rigProfile": "app" +} diff --git a/build-tests-samples/heft-web-rig-app-tutorial/config/rush-project.json b/build-tests-samples/heft-web-rig-app-tutorial/config/rush-project.json new file mode 100644 index 00000000000..852bbf63b9e --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/config/rush-project.json @@ -0,0 +1,15 @@ +// This file exists for caching purposes in the rushstack repo +{ + "extends": "@rushstack/heft-web-rig/profiles/app/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "release"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..f7d300f2f01 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/package.json @@ -0,0 +1,27 @@ +{ + "name": "heft-web-rig-app-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft test --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "heft-web-rig-library-tutorial": "workspace:*", + "react": "~17.0.2", + "react-dom": "~17.0.2", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-web-rig": "workspace:*", + "@types/react": "17.0.74", + "@types/react-dom": "17.0.25", + "@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 new file mode 100644 index 00000000000..1fb8c83d1d4 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/ExampleApp.tsx @@ -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 React from 'react'; +import { ToggleSwitch, type IToggleEventArgs } from 'heft-web-rig-library-tutorial'; + +/** + * 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', + margin: '20px', + borderRadius: '5px', + width: '400px' + }; + + return ( +
+

Hello, world!

+

Here is an example control:

+ + +

Here is an example image:

+ +
+ ); + } + + // 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-web-rig-app-tutorial/src/example-image.png b/build-tests-samples/heft-web-rig-app-tutorial/src/example-image.png new file mode 100644 index 00000000000..94fda081fac Binary files /dev/null and b/build-tests-samples/heft-web-rig-app-tutorial/src/example-image.png differ diff --git a/build-tests-samples/heft-web-rig-app-tutorial/src/start.css b/build-tests-samples/heft-web-rig-app-tutorial/src/start.css new file mode 100644 index 00000000000..47cd6d4c1ad --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/start.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-web-rig-app-tutorial/src/start.tsx b/build-tests-samples/heft-web-rig-app-tutorial/src/start.tsx new file mode 100644 index 00000000000..b7b46cebfa9 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/start.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 './start.css'; + +const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; +ReactDOM.render(, rootDiv); diff --git a/build-tests-samples/heft-web-rig-app-tutorial/src/test/ToggleSwitch.test.ts b/build-tests-samples/heft-web-rig-app-tutorial/src/test/ToggleSwitch.test.ts new file mode 100644 index 00000000000..944b63e898d --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/test/ToggleSwitch.test.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. + +// Note that Jest tests import the CommonJS files (from lib-commonjs/*.js) +// whereas Webpack will import the ESM files (from lib/*.js) +import { ToggleSwitch } from 'heft-web-rig-library-tutorial'; + +describe('ToggleSwitch', () => { + it('can be tested', () => { + expect(ToggleSwitch).toBeDefined(); + }); +}); diff --git a/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json b/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json new file mode 100644 index 00000000000..bb41d01a056 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/@rushstack/heft-web-rig/profiles/app/tsconfig-base.json", + "compilerOptions": { + "types": ["heft-jest", "webpack-env"] + } +} diff --git a/build-tests-samples/heft-web-rig-app-tutorial/webpack.config.js b/build-tests-samples/heft-web-rig-app-tutorial/webpack.config.js new file mode 100644 index 00000000000..7f0f154b813 --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/webpack.config.js @@ -0,0 +1,28 @@ +'use strict'; + +const createWebpackConfig = require('@rushstack/heft-web-rig/profiles/app/webpack-base.config'); + +module.exports = function createConfig(env, argv) { + return createWebpackConfig({ + env: env, + argv: argv, + projectRoot: __dirname, + // Documentation: https://webpack.js.org/configuration/ + configOverride: { + resolve: { + alias: { + // Use the bundled library + 'heft-web-rig-library-tutorial': + 'heft-web-rig-library-tutorial/dist/heft-web-rig-library-tutorial.js' + } + }, + performance: { + hints: env.production ? 'error' : false + // 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: 500000, + // maxAssetSize: 500000 + } + } + }); +}; diff --git a/build-tests-samples/heft-web-rig-library-tutorial/README.md b/build-tests-samples/heft-web-rig-library-tutorial/README.md new file mode 100644 index 00000000000..b34bc56d0b1 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-web-rig-library-tutorial + +This is a copy of the +[heft-web-rig-library-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-web-rig-library-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-web-rig-library-tutorial/config/api-extractor.json b/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json new file mode 100644 index 00000000000..4cd36c3e066 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json @@ -0,0 +1,366 @@ +/** + * 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", + + /** + * 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(). + * + * 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": [], + + /** + * 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": false + + /** + * 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: "/etc/" + */ + // "reportFolder": "/etc/", + + /** + * 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/" + }, + + /** + * 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" + }, + + /** + * 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 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" + }, + + /** + * 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", + + /** + * 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/build-tests-samples/heft-web-rig-library-tutorial/config/jest.config.json b/build-tests-samples/heft-web-rig-library-tutorial/config/jest.config.json new file mode 100644 index 00000000000..105047ade63 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-web-rig/profiles/library/config/jest.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-web-rig-library-tutorial/config/rig.json b/build-tests-samples/heft-web-rig-library-tutorial/config/rig.json new file mode 100644 index 00000000000..d72946b5042 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/config/rig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-web-rig", + "rigProfile": "library" +} diff --git a/build-tests-samples/heft-web-rig-library-tutorial/config/rush-project.json b/build-tests-samples/heft-web-rig-library-tutorial/config/rush-project.json new file mode 100644 index 00000000000..93c1e05a56f --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/config/rush-project.json @@ -0,0 +1,15 @@ +// This file exists for caching purposes in the rushstack repo +{ + "extends": "@rushstack/heft-web-rig/profiles/library/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "release"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..f509ec7f1fc --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/package.json @@ -0,0 +1,29 @@ +{ + "name": "heft-web-rig-library-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "main": "lib-commonjs/index.js", + "module": "lib/heft-web-rig-library-tutorial.js", + "typings": "dist/heft-web-rig-library-tutorial.d.ts", + "scripts": { + "build": "heft test --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "react": "~17.0.2", + "react-dom": "~17.0.2", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@rushstack/heft-web-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/react-dom": "17.0.25", + "@types/react": "17.0.74", + "@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/ToggleSwitch.tsx b/build-tests-samples/heft-web-rig-library-tutorial/src/ToggleSwitch.tsx new file mode 100644 index 00000000000..3d2488fd556 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/src/ToggleSwitch.tsx @@ -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 React from 'react'; + +/** + * Slider positions for `ToggleSwitch`. + * @public + */ +export const enum ToggleSwitchPosition { + Left = 'left', + Right = 'right' +} + +/** + * Event arguments for `IToggleSwitchProps.onToggle`. + * @public + */ +export interface IToggleEventArgs { + sliderPosition: ToggleSwitchPosition; +} + +/** + * @public + */ +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. + * @public + */ +export interface IToggleSwitchState { + sliderPosition: ToggleSwitchPosition; +} + +/** + * An example component that renders a switch whose slider position can be "left" or "right". + * @public + */ +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-web-rig-library-tutorial/src/index.ts b/build-tests-samples/heft-web-rig-library-tutorial/src/index.ts new file mode 100644 index 00000000000..ca9ecd1e116 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/src/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 * from './ToggleSwitch'; diff --git a/build-tests-samples/heft-web-rig-library-tutorial/src/test/ToggleSwitch.test.ts b/build-tests-samples/heft-web-rig-library-tutorial/src/test/ToggleSwitch.test.ts new file mode 100644 index 00000000000..0891628cc54 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-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-web-rig-library-tutorial/tsconfig.json b/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json new file mode 100644 index 00000000000..bb41d01a056 --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/@rushstack/heft-web-rig/profiles/app/tsconfig-base.json", + "compilerOptions": { + "types": ["heft-jest", "webpack-env"] + } +} diff --git a/build-tests-samples/heft-web-rig-library-tutorial/webpack.config.js b/build-tests-samples/heft-web-rig-library-tutorial/webpack.config.js new file mode 100644 index 00000000000..1215f0c5c1f --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/webpack.config.js @@ -0,0 +1,24 @@ +'use strict'; + +const createWebpackConfig = require('@rushstack/heft-web-rig/profiles/library/webpack-base.config'); + +module.exports = function createConfig(env, argv) { + return createWebpackConfig({ + env: env, + argv: argv, + projectRoot: __dirname, + + // Documentation: https://webpack.js.org/configuration/ + configOverride: { + externals: ['react', 'react-dom', 'tslib'], + + performance: { + hints: env.production ? 'error' : false + // 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: 500000, + // maxAssetSize: 500000 + } + } + }); +}; diff --git a/build-tests-samples/heft-webpack-basic-tutorial/.vscode/launch.json b/build-tests-samples/heft-webpack-basic-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..fd7bdc34fb4 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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 Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-webpack-basic-tutorial/README.md b/build-tests-samples/heft-webpack-basic-tutorial/README.md new file mode 100644 index 00000000000..0d9cd69c2de --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-webpack-basic-tutorial + +This is a copy of the +[heft-webpack-basic-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-webpack-basic-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-webpack-basic-tutorial/assets/index.html b/build-tests-samples/heft-webpack-basic-tutorial/assets/index.html new file mode 100644 index 00000000000..9e89ef57d85 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/assets/index.html @@ -0,0 +1,12 @@ + + + + + + Example Application + + + +
+ + diff --git a/build-tests-samples/heft-webpack-basic-tutorial/config/heft.json b/build-tests-samples/heft-webpack-basic-tutorial/config/heft.json new file mode 100644 index 00000000000..b78b27272ac --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/config/heft.json @@ -0,0 +1,44 @@ +/** + * 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"] }], + + "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" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests-samples/heft-webpack-basic-tutorial/config/jest.config.json b/build-tests-samples/heft-webpack-basic-tutorial/config/jest.config.json new file mode 100644 index 00000000000..bfc5ce0d9b7 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/config/jest.config.json @@ -0,0 +1,26 @@ +{ + "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 + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"], + + // Use v8 coverage provider to avoid Babel + "coverageProvider": "v8" +} 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 new file mode 100644 index 00000000000..9042450ba22 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests-samples/heft-webpack-basic-tutorial/config/typescript.json b/build-tests-samples/heft-webpack-basic-tutorial/config/typescript.json new file mode 100644 index 00000000000..80efdd16510 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-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 new file mode 100644 index 00000000000..d0d5899c872 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/package.json @@ -0,0 +1,36 @@ +{ + "name": "heft-webpack-basic-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", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "react-dom": "~17.0.2", + "react": "~17.0.2", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@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": "17.0.74", + "@types/react-dom": "17.0.25", + "@types/webpack-env": "1.18.8", + "css-loader": "~6.6.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.8.2", + "webpack": "~5.98.0" + } +} diff --git a/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx new file mode 100644 index 00000000000..d81154eaefe --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-webpack-basic-tutorial/src/ToggleSwitch.tsx b/build-tests-samples/heft-webpack-basic-tutorial/src/ToggleSwitch.tsx new file mode 100644 index 00000000000..79e43aad327 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-webpack-basic-tutorial/src/index.css b/build-tests-samples/heft-webpack-basic-tutorial/src/index.css new file mode 100644 index 00000000000..47cd6d4c1ad --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-webpack-basic-tutorial/src/index.tsx b/build-tests-samples/heft-webpack-basic-tutorial/src/index.tsx new file mode 100644 index 00000000000..d2a345895ca --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-webpack-basic-tutorial/src/test/ToggleSwitch.test.ts b/build-tests-samples/heft-webpack-basic-tutorial/src/test/ToggleSwitch.test.ts new file mode 100644 index 00000000000..0891628cc54 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-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-webpack-basic-tutorial/tsconfig.json b/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json new file mode 100644 index 00000000000..4d703032a26 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json @@ -0,0 +1,31 @@ +{ + "$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-webpack-basic-tutorial/webpack.config.js b/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js new file mode 100644 index 00000000000..683afc0cc96 --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js @@ -0,0 +1,61 @@ +'use strict'; + +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-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', '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' + }) + ] + }; + + return webpackConfig; +} + +module.exports = createWebpackConfig; diff --git a/build-tests-samples/packlets-tutorial/.eslintrc.js b/build-tests-samples/packlets-tutorial/.eslintrc.js new file mode 100644 index 00000000000..62885de24de --- /dev/null +++ b/build-tests-samples/packlets-tutorial/.eslintrc.js @@ -0,0 +1,7 @@ +// 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', '@rushstack/eslint-config/mixins/packlets'], + parserOptions: { tsconfigRootDir: __dirname } +}; diff --git a/build-tests-samples/packlets-tutorial/README.md b/build-tests-samples/packlets-tutorial/README.md new file mode 100644 index 00000000000..b02751c7652 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/README.md @@ -0,0 +1,8 @@ +# packlets-tutorial + +This is a copy of the +[packlets-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/other/packlets-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/packlets-tutorial/config/heft.json b/build-tests-samples/packlets-tutorial/config/heft.json new file mode 100644 index 00000000000..694f8935bb1 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/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", + + // 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-samples/packlets-tutorial/config/rush-project.json b/build-tests-samples/packlets-tutorial/config/rush-project.json new file mode 100644 index 00000000000..6183592308d --- /dev/null +++ b/build-tests-samples/packlets-tutorial/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:build", + "outputFolderNames": [".heft", "lib", "dist"] + } + ] +} diff --git a/build-tests-samples/packlets-tutorial/package.json b/build-tests-samples/packlets-tutorial/package.json new file mode 100644 index 00000000000..3aa2baa2241 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/package.json @@ -0,0 +1,21 @@ +{ + "name": "packlets-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for @rushstack/eslint-plugin-packlets", + "version": "1.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "node lib/start.js", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~8.57.0", + "typescript": "~5.8.2" + } +} diff --git a/build-tests-samples/packlets-tutorial/src/app/App.ts b/build-tests-samples/packlets-tutorial/src/app/App.ts new file mode 100644 index 00000000000..199225841aa --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/app/App.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 { DataModel, ExampleModel } from '../packlets/data-model'; + +import { Logger, MessageType } from '../packlets/logging'; +import { MainReport } from '../packlets/reports'; + +export class App { + public run(): void { + const logger: Logger = new Logger(); + logger.log(MessageType.Info, 'Starting app...'); + + const dataModel: DataModel = new ExampleModel(logger); + const report: MainReport = new MainReport(logger); + report.showReport(dataModel); + + logger.log(MessageType.Info, 'Operation completed successfully'); + } +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/data-model/DataModel.ts b/build-tests-samples/packlets-tutorial/src/packlets/data-model/DataModel.ts new file mode 100644 index 00000000000..56f50de2f2b --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/data-model/DataModel.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Logger } from '../../packlets/logging'; + +export interface IDataRecord { + firstName: string; + lastName: string; + age: number; +} + +export abstract class DataModel { + protected readonly logger: Logger; + + public constructor(logger: Logger) { + this.logger = logger; + } + public abstract queryRecords(): IDataRecord[]; +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/data-model/ExampleModel.ts b/build-tests-samples/packlets-tutorial/src/packlets/data-model/ExampleModel.ts new file mode 100644 index 00000000000..61ad61c935b --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/data-model/ExampleModel.ts @@ -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. + +import { DataModel, IDataRecord } from './DataModel'; + +export class ExampleModel extends DataModel { + public queryRecords(): IDataRecord[] { + return [ + { + firstName: 'Alice', + lastName: 'Exampleton', + age: 27 + }, + { + firstName: 'Bob', + lastName: 'Examplemeyer', + age: 31 + } + ]; + } +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/data-model/index.ts b/build-tests-samples/packlets-tutorial/src/packlets/data-model/index.ts new file mode 100644 index 00000000000..44c53440756 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/data-model/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 * from './DataModel'; +export * from './ExampleModel'; diff --git a/build-tests-samples/packlets-tutorial/src/packlets/logging/Logger.ts b/build-tests-samples/packlets-tutorial/src/packlets/logging/Logger.ts new file mode 100644 index 00000000000..f7523792898 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/logging/Logger.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 { MessageType } from './MessageType'; + +export class Logger { + public log(messageType: MessageType, message: string): void { + switch (messageType) { + case MessageType.Info: + console.log('[info]: ' + message); + break; + case MessageType.Warning: + console.log('[warning]: ' + message); + break; + case MessageType.Error: + console.log('[error]: ' + message); + break; + } + } +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/logging/MessageType.ts b/build-tests-samples/packlets-tutorial/src/packlets/logging/MessageType.ts new file mode 100644 index 00000000000..ec7ac320a41 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/logging/MessageType.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 enum MessageType { + Info, + Warning, + Error +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/logging/index.ts b/build-tests-samples/packlets-tutorial/src/packlets/logging/index.ts new file mode 100644 index 00000000000..a9cb7beac4d --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/logging/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 * from './Logger'; +export * from './MessageType'; diff --git a/build-tests-samples/packlets-tutorial/src/packlets/reports/MainReport.ts b/build-tests-samples/packlets-tutorial/src/packlets/reports/MainReport.ts new file mode 100644 index 00000000000..2fb96438317 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/reports/MainReport.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { DataModel } from '../data-model'; +import { Logger, MessageType } from '../logging'; + +export class MainReport { + private readonly _logger: Logger; + + public constructor(logger: Logger) { + this._logger = logger; + this._logger.log(MessageType.Info, 'Constructing MainReport'); + } + + public showReport(dataModel: DataModel): void { + console.log('\n---------------------------------------'); + console.log('REPORT'); + console.log('---------------------------------------'); + for (const record of dataModel.queryRecords()) { + console.log(`${record.firstName} ${record.lastName}: Age=${record.age}`); + } + console.log('---------------------------------------\n'); + } +} diff --git a/build-tests-samples/packlets-tutorial/src/packlets/reports/index.ts b/build-tests-samples/packlets-tutorial/src/packlets/reports/index.ts new file mode 100644 index 00000000000..447a3eb6c4c --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/packlets/reports/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 * from './MainReport'; diff --git a/build-tests-samples/packlets-tutorial/src/start.ts b/build-tests-samples/packlets-tutorial/src/start.ts new file mode 100644 index 00000000000..b36a51c36a0 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/src/start.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 { App } from './app/App'; + +const app: App = new App(); +app.run(); diff --git a/build-tests-samples/packlets-tutorial/tsconfig.json b/build-tests-samples/packlets-tutorial/tsconfig.json new file mode 100644 index 00000000000..3a994cbd1c2 --- /dev/null +++ b/build-tests-samples/packlets-tutorial/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$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, + + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests-subspace/rush-lib-test/config/rig.json b/build-tests-subspace/rush-lib-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests-subspace/rush-lib-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-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 new file mode 100644 index 00000000000..b622838bef8 --- /dev/null +++ b/build-tests-subspace/rush-lib-test/package.json @@ -0,0 +1,36 @@ +{ + "name": "rush-lib-test", + "version": "0.0.0", + "private": true, + "description": "A minimal example project that imports APIs from @rushstack/rush-lib", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "node lib/start.js", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.25.1", + "local-node-rig": "workspace:*" + }, + "dependenciesMeta": { + "@microsoft/rush-lib": { + "injected": true + }, + "@rushstack/terminal": { + "injected": true + }, + "@rushstack/heft": { + "injected": true + }, + "local-node-rig": { + "injected": true + } + } +} diff --git a/build-tests-subspace/rush-lib-test/src/start.ts b/build-tests-subspace/rush-lib-test/src/start.ts new file mode 100644 index 00000000000..086a84b52d0 --- /dev/null +++ b/build-tests-subspace/rush-lib-test/src/start.ts @@ -0,0 +1,25 @@ +// 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 */ + +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 +// eslint-disable-next-line import/order +import { RushConfiguration } from '@microsoft/rush-lib/lib/'; + +const config: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); +console.log(config.commonFolder); + +console.log('Calling an internal API...'); + +// Use a path-based import to access an internal API (do so at your own risk!) +import { VersionMismatchFinder } from '@microsoft/rush-lib/lib/logic/versionMismatch/VersionMismatchFinder'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); +VersionMismatchFinder.ensureConsistentVersions(config, terminal); + +console.log(new ConsoleTerminalProvider().supportsColor); diff --git a/build-tests-subspace/rush-lib-test/tsconfig.json b/build-tests-subspace/rush-lib-test/tsconfig.json new file mode 100644 index 00000000000..a79b7380192 --- /dev/null +++ b/build-tests-subspace/rush-lib-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"] + }, + + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-subspace/rush-sdk-test/config/heft.json b/build-tests-subspace/rush-sdk-test/config/heft.json new file mode 100644 index 00000000000..f72878eb953 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/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-start": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./lib/run-start.js" + } + } + } + } + } + } +} diff --git a/build-tests-subspace/rush-sdk-test/config/rig.json b/build-tests-subspace/rush-sdk-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests-subspace/rush-sdk-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-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 new file mode 100644 index 00000000000..cbddd0f8b80 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/package.json @@ -0,0 +1,36 @@ +{ + "name": "rush-sdk-test", + "version": "0.0.0", + "private": true, + "description": "A minimal example project that imports APIs from @rushstack/rush-sdk", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "node lib/start.js", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@rushstack/rush-sdk": "workspace:*" + }, + "devDependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.25.1", + "local-node-rig": "workspace:*" + }, + "dependenciesMeta": { + "@microsoft/rush-lib": { + "injected": true + }, + "@rushstack/rush-sdk": { + "injected": true + }, + "@rushstack/heft": { + "injected": true + }, + "local-node-rig": { + "injected": true + } + } +} diff --git a/build-tests-subspace/rush-sdk-test/src/run-start.ts b/build-tests-subspace/rush-sdk-test/src/run-start.ts new file mode 100644 index 00000000000..a5fcb483473 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/src/run-start.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 async function runAsync(): Promise { + await import('./start.js'); +} diff --git a/build-tests-subspace/rush-sdk-test/src/start.ts b/build-tests-subspace/rush-sdk-test/src/start.ts new file mode 100644 index 00000000000..92517a312f9 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/src/start.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. + +/* eslint-disable no-console */ + +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(); +console.log(config.commonFolder); + +console.log('Calling an internal API...'); + +// Use a path-based import to access an internal API (do so at your own risk!) +import * as GitEmailPolicy from '@rushstack/rush-sdk/lib/logic/policy/GitEmailPolicy'; +console.log(GitEmailPolicy.getEmailExampleLines(config)); diff --git a/build-tests-subspace/rush-sdk-test/tsconfig.json b/build-tests-subspace/rush-sdk-test/tsconfig.json new file mode 100644 index 00000000000..a56f7ca4216 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/tsconfig.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + "skipLibCheck": true // There are issues with importing rush-sdk as an injected dependency + }, + + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-subspace/typescript-newest-test/config/rig.json b/build-tests-subspace/typescript-newest-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests-subspace/typescript-newest-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-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 new file mode 100644 index 00000000000..bf9ef7a48f3 --- /dev/null +++ b/build-tests-subspace/typescript-newest-test/package.json @@ -0,0 +1,26 @@ +{ + "name": "typescript-newest-test", + "description": "Building this project tests Heft with the newest supported TypeScript compiler version", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.25.1", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + }, + "dependenciesMeta": { + "@rushstack/heft": { + "injected": true + }, + "local-node-rig": { + "injected": true + } + } +} diff --git a/build-tests-subspace/typescript-newest-test/src/index.ts b/build-tests-subspace/typescript-newest-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests-subspace/typescript-newest-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-subspace/typescript-newest-test/tsconfig.json b/build-tests-subspace/typescript-newest-test/tsconfig.json new file mode 100644 index 00000000000..d16a11b11ea --- /dev/null +++ b/build-tests-subspace/typescript-newest-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": [] + }, + + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-subspace/typescript-v4-test/config/heft.json b/build-tests-subspace/typescript-v4-test/config/heft.json new file mode 100644 index 00000000000..0413fcc7fec --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/config/heft.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "temp"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + } + } +} diff --git a/build-tests-subspace/typescript-v4-test/config/rush-project.json b/build-tests-subspace/typescript-v4-test/config/rush-project.json new file mode 100644 index 00000000000..11f81b24412 --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/config/rush-project.json @@ -0,0 +1,8 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib", "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 new file mode 100644 index 00000000000..f4b21f5caf8 --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/package.json @@ -0,0 +1,35 @@ +{ + "name": "typescript-v4-test", + "description": "Building this project tests Heft with TypeScript v4", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "typescript": "~4.9.5", + "tslint": "~5.20.1", + "eslint": "~9.25.1" + }, + "dependenciesMeta": { + "@rushstack/eslint-config": { + "injected": true + }, + "@rushstack/heft": { + "injected": true + }, + "@rushstack/heft-lint-plugin": { + "injected": true + }, + "@rushstack/heft-typescript-plugin": { + "injected": true + } + } +} diff --git a/build-tests-subspace/typescript-v4-test/src/index.ts b/build-tests-subspace/typescript-v4-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests-subspace/typescript-v4-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-subspace/typescript-v4-test/tsconfig.json b/build-tests-subspace/typescript-v4-test/tsconfig.json new file mode 100644 index 00000000000..d16a11b11ea --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": [] + }, + + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-subspace/typescript-v4-test/tslint.json b/build-tests-subspace/typescript-v4-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} 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..8a028a3304e --- /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/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/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 new file mode 100644 index 00000000000..58f0d98c22b --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.json @@ -0,0 +1,1133 @@ +{ + "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-documenter-scenarios!", + "docComment": "", + "name": "api-documenter-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-documenter-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!Class1:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Class1 extends " + }, + { + "kind": "Reference", + "text": "Class2", + "canonicalReference": "api-documenter-scenarios!Class2:class" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Class1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-documenter-scenarios!Class1#fourthProp:member", + "docComment": "/**\n * A fourth prop\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "fourthProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "fourthProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-scenarios!Class1#secondProp:member", + "docComment": "/**\n * A second prop. Overrides `Class2.secondProp`.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "secondProp: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "secondProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Method", + "canonicalReference": "api-documenter-scenarios!Class1#someOverload:member(1)", + "docComment": "/**\n * Some overload. Overrides `Class3.someOverload`.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someOverload(x: " + }, + { + "kind": "Content", + "text": "boolean | string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "someOverload" + } + ], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!Class2:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Class2 extends " + }, + { + "kind": "Reference", + "text": "Namespace1.Class3", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "isAbstract": false, + "name": "Class2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-documenter-scenarios!Class2#secondProp:member", + "docComment": "/**\n * A second prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "secondProp: " + }, + { + "kind": "Content", + "text": "boolean | string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "secondProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Method", + "canonicalReference": "api-documenter-scenarios!Class2#someMethod:member(1)", + "docComment": "/**\n * Some method. Overrides `Class3.someMethod`.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someMethod(x: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "someMethod" + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-scenarios!Class2#thirdProp:member", + "docComment": "/**\n * A third prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "thirdProp: " + }, + { + "kind": "Content", + "text": "T" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "thirdProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Variable", + "canonicalReference": "api-documenter-scenarios!ClassLikeVariable:var", + "docComment": "/**\n * Some class-like variable.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "ClassLikeVariable: " + }, + { + "kind": "Content", + "text": "{\n new (): {\n someProp: number;\n };\n}" + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "ClassLikeVariable", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!ExtendsAnonymousClass:class", + "docComment": "/**\n * Some class that extends an anonymous class.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExtendsAnonymousClass extends " + }, + { + "kind": "Reference", + "text": "ExtendsAnonymousClass_base", + "canonicalReference": "api-documenter-scenarios!~ExtendsAnonymousClass_base" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExtendsAnonymousClass", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!ExtendsClassFromAnotherPackage:class", + "docComment": "/**\n * Some class that extends a class from another package. This base class is not in any API doc model.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExtendsClassFromAnotherPackage extends " + }, + { + "kind": "Reference", + "text": "Extractor", + "canonicalReference": "@microsoft/api-extractor!Extractor:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExtendsClassFromAnotherPackage", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!ExtendsClassLikeVariable:class", + "docComment": "/**\n * Some class that extends a class-like variable.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExtendsClassLikeVariable extends " + }, + { + "kind": "Reference", + "text": "ClassLikeVariable", + "canonicalReference": "api-documenter-scenarios!ClassLikeVariable" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExtendsClassLikeVariable", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!ExtendsUnexportedClass:class", + "docComment": "/**\n * Some class that extends an unexported class.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExtendsUnexportedClass extends " + }, + { + "kind": "Reference", + "text": "UnexportedClass", + "canonicalReference": "api-documenter-scenarios!~UnexportedClass:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExtendsUnexportedClass", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-scenarios!IExtendsInterfaceLikeTypeAlias:interface", + "docComment": "/**\n * Some interface that extends an interface-like type alias as well as another interface.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IExtendsInterfaceLikeTypeAlias extends " + }, + { + "kind": "Reference", + "text": "IInterfaceLikeTypeAlias", + "canonicalReference": "api-documenter-scenarios!IInterfaceLikeTypeAlias:type" + }, + { + "kind": "Content", + "text": ", " + }, + { + "kind": "Reference", + "text": "IInterface1", + "canonicalReference": "api-documenter-scenarios!IInterface1:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "IExtendsInterfaceLikeTypeAlias", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 2 + }, + { + "startIndex": 3, + "endIndex": 4 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-scenarios!IExtendsMultipleInterfaces:interface", + "docComment": "/**\n * Some interface that extends multiple interfaces.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IExtendsMultipleInterfaces extends " + }, + { + "kind": "Reference", + "text": "IInterface1", + "canonicalReference": "api-documenter-scenarios!IInterface1:interface" + }, + { + "kind": "Content", + "text": ", " + }, + { + "kind": "Reference", + "text": "IInterface2", + "canonicalReference": "api-documenter-scenarios!IInterface2:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "IExtendsMultipleInterfaces", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-scenarios!IExtendsMultipleInterfaces#secondProp:member", + "docComment": "/**\n * A second prop. Overrides `IInterface1.someProp`.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "secondProp: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "secondProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-scenarios!IExtendsMultipleInterfaces#thirdProp:member", + "docComment": "/**\n * A third prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "thirdProp: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "thirdProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 2 + }, + { + "startIndex": 3, + "endIndex": 4 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-scenarios!IInterface1:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IInterface1 " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "IInterface1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-scenarios!IInterface1#secondProp:member", + "docComment": "/**\n * A second prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "secondProp: " + }, + { + "kind": "Content", + "text": "boolean | string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "secondProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-scenarios!IInterface1#someProp:member", + "docComment": "/**\n * Some prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-scenarios!IInterface2:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IInterface2 " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "IInterface2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-scenarios!IInterface2#someProp:member", + "docComment": "/**\n * Some prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-documenter-scenarios!IInterfaceLikeTypeAlias:type", + "docComment": "/**\n * Some interface-like type alias.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type IInterfaceLikeTypeAlias = " + }, + { + "kind": "Content", + "text": "{\n someProp: number;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "IInterfaceLikeTypeAlias", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Namespace", + "canonicalReference": "api-documenter-scenarios!Namespace1:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace Namespace1 " + } + ], + "fileUrlPath": "src/inheritedMembers/index.ts", + "releaseTag": "Public", + "name": "Namespace1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "class Class3 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "Class3", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3#someMethod:member(1)", + "docComment": "/**\n * Some method.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someMethod(x: " + }, + { + "kind": "Content", + "text": "boolean | string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "someMethod" + }, + { + "kind": "Method", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3#someOverload:member(1)", + "docComment": "/**\n * Some overload.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someOverload(x: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "someOverload" + }, + { + "kind": "Method", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3#someOverload:member(2)", + "docComment": "/**\n * Some overload.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someOverload(x: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 2, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "someOverload" + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-scenarios!Namespace1.Class3#someProp:member", + "docComment": "/**\n * Some prop.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md new file mode 100644 index 00000000000..e3a1dc2acaf --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md @@ -0,0 +1,89 @@ +## API Report File for "api-documenter-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Extractor } from '@microsoft/api-extractor'; + +// @public (undocumented) +export class Class1 extends Class2 { + fourthProp: number; + secondProp: boolean; + someOverload(x: boolean | string): void; +} + +// @public (undocumented) +export class Class2 extends Namespace1.Class3 { + secondProp: boolean | string; + someMethod(x: boolean): void; + thirdProp: T; +} + +// @public +export const ClassLikeVariable: { + new (): { + someProp: number; + }; +}; + +// Warning: (ae-forgotten-export) The symbol "ExtendsAnonymousClass_base" needs to be exported by the entry point index.d.ts +// +// @public +export class ExtendsAnonymousClass extends ExtendsAnonymousClass_base { +} + +// @public +export class ExtendsClassFromAnotherPackage extends Extractor { +} + +// @public +export class ExtendsClassLikeVariable extends ClassLikeVariable { +} + +// Warning: (ae-forgotten-export) The symbol "UnexportedClass" needs to be exported by the entry point index.d.ts +// +// @public +export class ExtendsUnexportedClass extends UnexportedClass { +} + +// @public +export interface IExtendsInterfaceLikeTypeAlias extends IInterfaceLikeTypeAlias, IInterface1 { +} + +// @public +export interface IExtendsMultipleInterfaces extends IInterface1, IInterface2 { + secondProp: boolean; + thirdProp: string; +} + +// @public (undocumented) +export interface IInterface1 { + secondProp: boolean | string; + someProp: number; +} + +// @public (undocumented) +export interface IInterface2 { + someProp: number; +} + +// @public +export type IInterfaceLikeTypeAlias = { + someProp: number; +}; + +// @public (undocumented) +export namespace Namespace1 { + // (undocumented) + export class Class3 { + someMethod(x: boolean | string): void; + someOverload(x: boolean): void; + someOverload(x: string): void; + someProp: number; + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.fourthprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.fourthprop.md new file mode 100644 index 00000000000..62dca05ad18 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.fourthprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class1](./api-documenter-scenarios.class1.md) > [fourthProp](./api-documenter-scenarios.class1.fourthprop.md) + +## Class1.fourthProp property + +A fourth prop + +**Signature:** + +```typescript +fourthProp: number; +``` 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 new file mode 100644 index 00000000000..1bfaa4f7169 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.md @@ -0,0 +1,169 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class1](./api-documenter-scenarios.class1.md) + +## Class1 class + + +**Signature:** + +```typescript +export declare class Class1 extends Class2 +``` +**Extends:** [Class2](./api-documenter-scenarios.class2.md)<number> + +## Properties + + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[fourthProp](./api-documenter-scenarios.class1.fourthprop.md) + + + + + + + +number + + + + +A fourth prop + + +
+ +[secondProp](./api-documenter-scenarios.class1.secondprop.md) + + + + + + + +boolean + + + + +A second prop. Overrides `Class2.secondProp`. + + +
+ +[someProp](./api-documenter-scenarios.namespace1.class3.someprop.md) + + + + + + + +number + + + + +Some prop. + +(Inherited from [Class3](./api-documenter-scenarios.namespace1.class3.md)) + + +
+ +[thirdProp](./api-documenter-scenarios.class2.thirdprop.md) + + + + + + + +T + + + + +A third prop. + +(Inherited from [Class2](./api-documenter-scenarios.class2.md)) + + +
+ +## Methods + + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[someMethod(x)](./api-documenter-scenarios.class2.somemethod.md) + + + + + + + +Some method. Overrides `Class3.someMethod`. + +(Inherited from [Class2](./api-documenter-scenarios.class2.md)) + + +
+ +[someOverload(x)](./api-documenter-scenarios.class1.someoverload.md) + + + + + + + +Some overload. Overrides `Class3.someOverload`. + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.secondprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.secondprop.md new file mode 100644 index 00000000000..d45f01c74dd --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.secondprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class1](./api-documenter-scenarios.class1.md) > [secondProp](./api-documenter-scenarios.class1.secondprop.md) + +## Class1.secondProp property + +A second prop. Overrides `Class2.secondProp`. + +**Signature:** + +```typescript +secondProp: boolean; +``` 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 new file mode 100644 index 00000000000..6b6cd8d0a07 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.someoverload.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class1](./api-documenter-scenarios.class1.md) > [someOverload](./api-documenter-scenarios.class1.someoverload.md) + +## Class1.someOverload() method + +Some overload. Overrides `Class3.someOverload`. + +**Signature:** + +```typescript +someOverload(x: boolean | string): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +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 new file mode 100644 index 00000000000..b952855673a --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.md @@ -0,0 +1,164 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class2](./api-documenter-scenarios.class2.md) + +## Class2 class + + +**Signature:** + +```typescript +export declare class Class2 extends Namespace1.Class3 +``` +**Extends:** [Namespace1.Class3](./api-documenter-scenarios.namespace1.class3.md) + +## Properties + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[secondProp](./api-documenter-scenarios.class2.secondprop.md) + + + + + + + +boolean \| string + + + + +A second prop. + + +
+ +[someProp](./api-documenter-scenarios.namespace1.class3.someprop.md) + + + + + + + +number + + + + +Some prop. + +(Inherited from [Class3](./api-documenter-scenarios.namespace1.class3.md)) + + +
+ +[thirdProp](./api-documenter-scenarios.class2.thirdprop.md) + + + + + + + +T + + + + +A third prop. + + +
+ +## Methods + + + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[someMethod(x)](./api-documenter-scenarios.class2.somemethod.md) + + + + + + + +Some method. Overrides `Class3.someMethod`. + + +
+ +[someOverload(x)](./api-documenter-scenarios.namespace1.class3.someoverload.md) + + + + + + + +Some overload. + +(Inherited from [Class3](./api-documenter-scenarios.namespace1.class3.md)) + + +
+ +[someOverload(x)](./api-documenter-scenarios.namespace1.class3.someoverload_1.md) + + + + + + + +Some overload. + +(Inherited from [Class3](./api-documenter-scenarios.namespace1.class3.md)) + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.secondprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.secondprop.md new file mode 100644 index 00000000000..d27bd64612a --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.secondprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class2](./api-documenter-scenarios.class2.md) > [secondProp](./api-documenter-scenarios.class2.secondprop.md) + +## Class2.secondProp property + +A second prop. + +**Signature:** + +```typescript +secondProp: boolean | string; +``` 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 new file mode 100644 index 00000000000..ddc7fe613a0 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.somemethod.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class2](./api-documenter-scenarios.class2.md) > [someMethod](./api-documenter-scenarios.class2.somemethod.md) + +## Class2.someMethod() method + +Some method. Overrides `Class3.someMethod`. + +**Signature:** + +```typescript +someMethod(x: boolean): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +boolean + + + + + +
+ +**Returns:** + +void + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.thirdprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.thirdprop.md new file mode 100644 index 00000000000..601018a30fc --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.thirdprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Class2](./api-documenter-scenarios.class2.md) > [thirdProp](./api-documenter-scenarios.class2.thirdprop.md) + +## Class2.thirdProp property + +A third prop. + +**Signature:** + +```typescript +thirdProp: T; +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.classlikevariable.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.classlikevariable.md new file mode 100644 index 00000000000..cc7788ea1fb --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.classlikevariable.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [ClassLikeVariable](./api-documenter-scenarios.classlikevariable.md) + +## ClassLikeVariable variable + +Some class-like variable. + +**Signature:** + +```typescript +ClassLikeVariable: { + new (): { + someProp: number; + }; +} +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsanonymousclass.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsanonymousclass.md new file mode 100644 index 00000000000..5deec45ca0d --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsanonymousclass.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [ExtendsAnonymousClass](./api-documenter-scenarios.extendsanonymousclass.md) + +## ExtendsAnonymousClass class + +Some class that extends an anonymous class. + +**Signature:** + +```typescript +export declare class ExtendsAnonymousClass extends ExtendsAnonymousClass_base +``` +**Extends:** ExtendsAnonymousClass\_base + +_(Some inherited members may not be shown because they are not represented in the documentation.)_ + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclassfromanotherpackage.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclassfromanotherpackage.md new file mode 100644 index 00000000000..9e92e1877a7 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclassfromanotherpackage.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [ExtendsClassFromAnotherPackage](./api-documenter-scenarios.extendsclassfromanotherpackage.md) + +## ExtendsClassFromAnotherPackage class + +Some class that extends a class from another package. This base class is not in any API doc model. + +**Signature:** + +```typescript +export declare class ExtendsClassFromAnotherPackage extends Extractor +``` +**Extends:** Extractor + +_(Some inherited members may not be shown because they are not represented in the documentation.)_ + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclasslikevariable.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclasslikevariable.md new file mode 100644 index 00000000000..2681786e781 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsclasslikevariable.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [ExtendsClassLikeVariable](./api-documenter-scenarios.extendsclasslikevariable.md) + +## ExtendsClassLikeVariable class + +Some class that extends a class-like variable. + +**Signature:** + +```typescript +export declare class ExtendsClassLikeVariable extends ClassLikeVariable +``` +**Extends:** ClassLikeVariable + +_(Some inherited members may not be shown because they are not represented in the documentation.)_ + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsunexportedclass.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsunexportedclass.md new file mode 100644 index 00000000000..f7c3a288137 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.extendsunexportedclass.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [ExtendsUnexportedClass](./api-documenter-scenarios.extendsunexportedclass.md) + +## ExtendsUnexportedClass class + +Some class that extends an unexported class. + +**Signature:** + +```typescript +export declare class ExtendsUnexportedClass extends UnexportedClass +``` +**Extends:** UnexportedClass + +_(Some inherited members may not be shown because they are not represented in the documentation.)_ + 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 new file mode 100644 index 00000000000..e8f6984d281 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsinterfaceliketypealias.md @@ -0,0 +1,84 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IExtendsInterfaceLikeTypeAlias](./api-documenter-scenarios.iextendsinterfaceliketypealias.md) + +## IExtendsInterfaceLikeTypeAlias interface + +Some interface that extends an interface-like type alias as well as another interface. + +**Signature:** + +```typescript +export interface IExtendsInterfaceLikeTypeAlias extends IInterfaceLikeTypeAlias, IInterface1 +``` +**Extends:** [IInterfaceLikeTypeAlias](./api-documenter-scenarios.iinterfaceliketypealias.md), [IInterface1](./api-documenter-scenarios.iinterface1.md) + +_(Some inherited members may not be shown because they are not represented in the documentation.)_ + +## Properties + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[secondProp](./api-documenter-scenarios.iinterface1.secondprop.md) + + + + + + + +boolean \| string + + + + +A second prop. + +(Inherited from [IInterface1](./api-documenter-scenarios.iinterface1.md)) + + +
+ +[someProp](./api-documenter-scenarios.iinterface1.someprop.md) + + + + + + + +number + + + + +Some prop. + +(Inherited from [IInterface1](./api-documenter-scenarios.iinterface1.md)) + + +
+ 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 new file mode 100644 index 00000000000..5192a7a9df0 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.md @@ -0,0 +1,99 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IExtendsMultipleInterfaces](./api-documenter-scenarios.iextendsmultipleinterfaces.md) + +## IExtendsMultipleInterfaces interface + +Some interface that extends multiple interfaces. + +**Signature:** + +```typescript +export interface IExtendsMultipleInterfaces extends IInterface1, IInterface2 +``` +**Extends:** [IInterface1](./api-documenter-scenarios.iinterface1.md), [IInterface2](./api-documenter-scenarios.iinterface2.md) + +## Properties + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[secondProp](./api-documenter-scenarios.iextendsmultipleinterfaces.secondprop.md) + + + + + + + +boolean + + + + +A second prop. Overrides `IInterface1.someProp`. + + +
+ +[someProp](./api-documenter-scenarios.iinterface1.someprop.md) + + + + + + + +number + + + + +Some prop. + +(Inherited from [IInterface1](./api-documenter-scenarios.iinterface1.md)) + + +
+ +[thirdProp](./api-documenter-scenarios.iextendsmultipleinterfaces.thirdprop.md) + + + + + + + +string + + + + +A third prop. + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.secondprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.secondprop.md new file mode 100644 index 00000000000..a9ac71ab095 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.secondprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IExtendsMultipleInterfaces](./api-documenter-scenarios.iextendsmultipleinterfaces.md) > [secondProp](./api-documenter-scenarios.iextendsmultipleinterfaces.secondprop.md) + +## IExtendsMultipleInterfaces.secondProp property + +A second prop. Overrides `IInterface1.someProp`. + +**Signature:** + +```typescript +secondProp: boolean; +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.thirdprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.thirdprop.md new file mode 100644 index 00000000000..d522140c0a5 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.thirdprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IExtendsMultipleInterfaces](./api-documenter-scenarios.iextendsmultipleinterfaces.md) > [thirdProp](./api-documenter-scenarios.iextendsmultipleinterfaces.thirdprop.md) + +## IExtendsMultipleInterfaces.thirdProp property + +A third prop. + +**Signature:** + +```typescript +thirdProp: string; +``` 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 new file mode 100644 index 00000000000..015a51957b5 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.md @@ -0,0 +1,76 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterface1](./api-documenter-scenarios.iinterface1.md) + +## IInterface1 interface + + +**Signature:** + +```typescript +export interface IInterface1 +``` + +## Properties + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[secondProp](./api-documenter-scenarios.iinterface1.secondprop.md) + + + + + + + +boolean \| string + + + + +A second prop. + + +
+ +[someProp](./api-documenter-scenarios.iinterface1.someprop.md) + + + + + + + +number + + + + +Some prop. + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.secondprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.secondprop.md new file mode 100644 index 00000000000..f7e8fe6c40e --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.secondprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterface1](./api-documenter-scenarios.iinterface1.md) > [secondProp](./api-documenter-scenarios.iinterface1.secondprop.md) + +## IInterface1.secondProp property + +A second prop. + +**Signature:** + +```typescript +secondProp: boolean | string; +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.someprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.someprop.md new file mode 100644 index 00000000000..fa9cbf2a012 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.someprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterface1](./api-documenter-scenarios.iinterface1.md) > [someProp](./api-documenter-scenarios.iinterface1.someprop.md) + +## IInterface1.someProp property + +Some prop. + +**Signature:** + +```typescript +someProp: number; +``` 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 new file mode 100644 index 00000000000..f3c7c0e45da --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.md @@ -0,0 +1,57 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterface2](./api-documenter-scenarios.iinterface2.md) + +## IInterface2 interface + + +**Signature:** + +```typescript +export interface IInterface2 +``` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[someProp](./api-documenter-scenarios.iinterface2.someprop.md) + + + + + + + +number + + + + +Some prop. + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.someprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.someprop.md new file mode 100644 index 00000000000..bbd551ac110 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.someprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterface2](./api-documenter-scenarios.iinterface2.md) > [someProp](./api-documenter-scenarios.iinterface2.someprop.md) + +## IInterface2.someProp property + +Some prop. + +**Signature:** + +```typescript +someProp: number; +``` diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterfaceliketypealias.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterfaceliketypealias.md new file mode 100644 index 00000000000..6bb472700ea --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterfaceliketypealias.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [IInterfaceLikeTypeAlias](./api-documenter-scenarios.iinterfaceliketypealias.md) + +## IInterfaceLikeTypeAlias type + +Some interface-like type alias. + +**Signature:** + +```typescript +export type IInterfaceLikeTypeAlias = { + someProp: number; +}; +``` 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 new file mode 100644 index 00000000000..30d4ba70736 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.md @@ -0,0 +1,219 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) + +## api-documenter-scenarios package + +## Classes + + + + + + + + +
+ +Class + + + + +Description + + +
+ +[Class1](./api-documenter-scenarios.class1.md) + + + + + + +
+ +[Class2](./api-documenter-scenarios.class2.md) + + + + + + +
+ +[ExtendsAnonymousClass](./api-documenter-scenarios.extendsanonymousclass.md) + + + + +Some class that extends an anonymous class. + + +
+ +[ExtendsClassFromAnotherPackage](./api-documenter-scenarios.extendsclassfromanotherpackage.md) + + + + +Some class that extends a class from another package. This base class is not in any API doc model. + + +
+ +[ExtendsClassLikeVariable](./api-documenter-scenarios.extendsclasslikevariable.md) + + + + +Some class that extends a class-like variable. + + +
+ +[ExtendsUnexportedClass](./api-documenter-scenarios.extendsunexportedclass.md) + + + + +Some class that extends an unexported class. + + +
+ +## Interfaces + + + + + + +
+ +Interface + + + + +Description + + +
+ +[IExtendsInterfaceLikeTypeAlias](./api-documenter-scenarios.iextendsinterfaceliketypealias.md) + + + + +Some interface that extends an interface-like type alias as well as another interface. + + +
+ +[IExtendsMultipleInterfaces](./api-documenter-scenarios.iextendsmultipleinterfaces.md) + + + + +Some interface that extends multiple interfaces. + + +
+ +[IInterface1](./api-documenter-scenarios.iinterface1.md) + + + + + + +
+ +[IInterface2](./api-documenter-scenarios.iinterface2.md) + + + + + + +
+ +## Namespaces + + + +
+ +Namespace + + + + +Description + + +
+ +[Namespace1](./api-documenter-scenarios.namespace1.md) + + + + + + +
+ +## Variables + + + +
+ +Variable + + + + +Description + + +
+ +[ClassLikeVariable](./api-documenter-scenarios.classlikevariable.md) + + + + +Some class-like variable. + + +
+ +## Type Aliases + + + +
+ +Type Alias + + + + +Description + + +
+ +[IInterfaceLikeTypeAlias](./api-documenter-scenarios.iinterfaceliketypealias.md) + + + + +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 new file mode 100644 index 00000000000..923ef2d33ea --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.md @@ -0,0 +1,119 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) > [Class3](./api-documenter-scenarios.namespace1.class3.md) + +## Namespace1.Class3 class + + +**Signature:** + +```typescript +class Class3 +``` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[someProp](./api-documenter-scenarios.namespace1.class3.someprop.md) + + + + + + + +number + + + + +Some prop. + + +
+ +## Methods + + + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[someMethod(x)](./api-documenter-scenarios.namespace1.class3.somemethod.md) + + + + + + + +Some method. + + +
+ +[someOverload(x)](./api-documenter-scenarios.namespace1.class3.someoverload.md) + + + + + + + +Some overload. + + +
+ +[someOverload(x)](./api-documenter-scenarios.namespace1.class3.someoverload_1.md) + + + + + + + +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 new file mode 100644 index 00000000000..fe6ce4e2c5b --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.somemethod.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) > [Class3](./api-documenter-scenarios.namespace1.class3.md) > [someMethod](./api-documenter-scenarios.namespace1.class3.somemethod.md) + +## Namespace1.Class3.someMethod() method + +Some method. + +**Signature:** + +```typescript +someMethod(x: boolean | string): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +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 new file mode 100644 index 00000000000..1229bb41ccd --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) > [Class3](./api-documenter-scenarios.namespace1.class3.md) > [someOverload](./api-documenter-scenarios.namespace1.class3.someoverload.md) + +## Namespace1.Class3.someOverload() method + +Some overload. + +**Signature:** + +```typescript +someOverload(x: boolean): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +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 new file mode 100644 index 00000000000..a6c4c229baa --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload_1.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) > [Class3](./api-documenter-scenarios.namespace1.class3.md) > [someOverload](./api-documenter-scenarios.namespace1.class3.someoverload_1.md) + +## Namespace1.Class3.someOverload() method + +Some overload. + +**Signature:** + +```typescript +someOverload(x: string): void; +``` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +string + + + + + +
+ +**Returns:** + +void + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someprop.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someprop.md new file mode 100644 index 00000000000..651df68d102 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someprop.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) > [Class3](./api-documenter-scenarios.namespace1.class3.md) > [someProp](./api-documenter-scenarios.namespace1.class3.someprop.md) + +## Namespace1.Class3.someProp property + +Some prop. + +**Signature:** + +```typescript +someProp: number; +``` 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 new file mode 100644 index 00000000000..bfe2141e4f6 --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.md @@ -0,0 +1,38 @@ + + +[Home](./index.md) > [api-documenter-scenarios](./api-documenter-scenarios.md) > [Namespace1](./api-documenter-scenarios.namespace1.md) + +## Namespace1 namespace + + +**Signature:** + +```typescript +export declare namespace Namespace1 +``` + +## Classes + + + +
+ +Class + + + + +Description + + +
+ +[Class3](./api-documenter-scenarios.namespace1.class3.md) + + + + + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md new file mode 100644 index 00000000000..3fb30d96fea --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md @@ -0,0 +1,30 @@ + + +[Home](./index.md) + +## API Reference + +## Packages + + + +
+ +Package + + + + +Description + + +
+ +[api-documenter-scenarios](./api-documenter-scenarios.md) + + + + + +
+ diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts b/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts new file mode 100644 index 00000000000..5a2309fcc4f --- /dev/null +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts @@ -0,0 +1,128 @@ +import { Extractor } from '@microsoft/api-extractor'; + +/** @public */ +export declare class Class1 extends Class2 { + /** A second prop. Overrides `Class2.secondProp`. */ + secondProp: boolean; + /** A fourth prop */ + fourthProp: number; + /** Some overload. Overrides `Class3.someOverload`. */ + someOverload(x: boolean | string): void; +} + +/** @public */ +export declare class Class2 extends Namespace1.Class3 { + /** A second prop. */ + secondProp: boolean | string; + /** A third prop. */ + thirdProp: T; + /** Some method. Overrides `Class3.someMethod`. */ + someMethod(x: boolean): void; +} + +/** + * Some class-like variable. + * @public + */ +export declare const ClassLikeVariable: { + new (): { + someProp: number; + }; +}; + +/** + * Some class that extends an anonymous class. + * @public + */ +export declare class ExtendsAnonymousClass extends ExtendsAnonymousClass_base { +} + +declare const ExtendsAnonymousClass_base: { + new (): { + someProp: number; + }; +}; + +/** + * Some class that extends a class from another package. This base class + * is not in any API doc model. + * @public + */ +export declare class ExtendsClassFromAnotherPackage extends Extractor { +} + +/** + * Some class that extends a class-like variable. + * @public + */ +export declare class ExtendsClassLikeVariable extends ClassLikeVariable { +} + +/** + * Some class that extends an unexported class. + * @public + */ +export declare class ExtendsUnexportedClass extends UnexportedClass { +} + +/** + * Some interface that extends an interface-like type alias as well as + * another interface. + * @public + */ +export declare interface IExtendsInterfaceLikeTypeAlias extends IInterfaceLikeTypeAlias, IInterface1 { +} + +/** + * Some interface that extends multiple interfaces. + * @public + */ +export declare interface IExtendsMultipleInterfaces extends IInterface1, IInterface2 { + /** A second prop. Overrides `IInterface1.someProp`. */ + secondProp: boolean; + /** A third prop. */ + thirdProp: string; +} + +/** @public */ +export declare interface IInterface1 { + /** Some prop. */ + someProp: number; + /** A second prop. */ + secondProp: boolean | string; +} + +/** @public */ +export declare interface IInterface2 { + /** Some prop. */ + someProp: number; +} + +/** + * Some interface-like type alias. + * @public + */ +export declare type IInterfaceLikeTypeAlias = { + someProp: number; +}; + +/** @public */ +export declare namespace Namespace1 { + /** @public */ + export class Class3 { + /** Some prop. */ + someProp: number; + /** Some method. */ + someMethod(x: boolean | string): void; + /** Some overload. */ + someOverload(x: boolean): void; + /** Some overload. */ + someOverload(x: string): void; + } +} + +declare class UnexportedClass { + someProp: number; +} + +export { } diff --git a/build-tests/api-documenter-scenarios/package.json b/build-tests/api-documenter-scenarios/package.json new file mode 100644 index 00000000000..13a84a38856 --- /dev/null +++ b/build-tests/api-documenter-scenarios/package.json @@ -0,0 +1,20 @@ +{ + "name": "api-documenter-scenarios", + "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", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft build --clean" + }, + "devDependencies": { + "@microsoft/api-documenter": "workspace:*", + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "run-scenarios-helpers": "workspace:*" + } +} diff --git a/build-tests/api-documenter-scenarios/src/inheritedMembers/config/api-documenter-overrides.json b/build-tests/api-documenter-scenarios/src/inheritedMembers/config/api-documenter-overrides.json new file mode 100644 index 00000000000..f13c2e1fd70 --- /dev/null +++ b/build-tests/api-documenter-scenarios/src/inheritedMembers/config/api-documenter-overrides.json @@ -0,0 +1,3 @@ +{ + "showInheritedMembers": true +} diff --git a/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts b/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts new file mode 100644 index 00000000000..72ecba86fed --- /dev/null +++ b/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts @@ -0,0 +1,146 @@ +// 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 {} + } +} + +/** @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`. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + someMethod(x: boolean): void {} +} + +/** @public */ +export class Class1 extends Class2 { + /** A second prop. Overrides `Class2.secondProp`. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + secondProp: boolean; + + /** A fourth prop */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + fourthProp: number; + + /** Some overload. Overrides `Class3.someOverload`. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + someOverload(x: boolean | string): void {} +} + +/** @public */ +export interface IInterface1 { + /** Some prop. */ + someProp: number; + + /** A second prop. */ + secondProp: boolean | string; +} + +/** @public */ +export interface IInterface2 { + /** Some prop. */ + someProp: number; +} + +/** + * Some interface that extends multiple interfaces. + * @public + */ +export interface IExtendsMultipleInterfaces extends IInterface1, IInterface2 { + /** A second prop. Overrides `IInterface1.someProp`. */ + secondProp: boolean; + + /** A third prop. */ + thirdProp: string; +} + +class UnexportedClass { + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + someProp: number; +} + +/** + * Some class that extends an unexported class. + * @public + */ +export class ExtendsUnexportedClass extends UnexportedClass {} + +/** + * Some class that extends an anonymous class. + * @public + */ +export class ExtendsAnonymousClass extends class { + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + someProp: number; +} {} + +/** + * 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; +}; + +/** + * Some class that extends a class-like variable. + * @public + */ +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; +}; + +/** + * Some interface that extends an interface-like type alias as well as + * another interface. + * @public + */ +export interface IExtendsInterfaceLikeTypeAlias extends IInterfaceLikeTypeAlias, IInterface1 {} + +/** + * Some class that extends a class from another package. This base class + * is not in any API doc model. + * @public + */ +export class ExtendsClassFromAnotherPackage extends Extractor {} diff --git a/build-tests/api-documenter-scenarios/src/runScenarios.ts b/build-tests/api-documenter-scenarios/src/runScenarios.ts new file mode 100644 index 00000000000..1b89ed09e1e --- /dev/null +++ b/build-tests/api-documenter-scenarios/src/runScenarios.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 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}/config/api-documenter.json`; + + try { + 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; + } + } + + 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, + [ + 'node_modules/@microsoft/api-documenter/lib/start', + 'generate', + `--input-folder`, + `temp/etc/${scenarioFolderName}`, + '--output-folder', + `temp/etc/${scenarioFolderName}/markdown` + ], + { + stdio: 'inherit' + } + ); + + await Executable.waitForExitAsync(childProcess, { + throwOnNonZeroExitCode: true, + throwOnSignal: true + }); + } + }); + } finally { + // Delete the transient `api-documenter.json` file before completing, as it'll just be whatever the last scenario + // was, and shouldn't be committed. + await FileSystem.deleteFileAsync(apiDocumenterJsonPath); + } +} diff --git a/build-tests/api-documenter-scenarios/tsconfig.json b/build-tests/api-documenter-scenarios/tsconfig.json new file mode 100644 index 00000000000..d5641d0ba38 --- /dev/null +++ b/build-tests/api-documenter-scenarios/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "strictPropertyInitialization": false + } +} diff --git a/build-tests/api-documenter-test/build.js b/build-tests/api-documenter-test/build.js deleted file mode 100644 index c2bd5b29fd0..00000000000 --- a/build-tests/api-documenter-test/build.js +++ /dev/null @@ -1,33 +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'); -} - -// Run the API Documenter command-line -executeCommand('node node_modules/@microsoft/api-documenter/lib/start ' - + 'generate --input-folder etc --output-folder etc/yaml'); -executeCommand('node node_modules/@microsoft/api-documenter/lib/start ' - + 'markdown --input-folder etc --output-folder etc/markdown'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-documenter-test/config/api-documenter.json b/build-tests/api-documenter-test/config/api-documenter.json index 59dddf06166..59b666c3b35 100644 --- a/build-tests/api-documenter-test/config/api-documenter.json +++ b/build-tests/api-documenter-test/config/api-documenter.json @@ -28,9 +28,7 @@ }, { "name": "References", - "items": [ - { "name": "InjectedCustomItem", "uid": "customUrl" } - ] + "items": [{ "name": "InjectedCustomItem", "uid": "customUrl" }] } ] } diff --git a/build-tests/api-documenter-test/config/api-extractor.json b/build-tests/api-documenter-test/config/api-extractor.json index c5af368ca6a..41ce0c97e47 100644 --- a/build-tests/api-documenter-test/config/api-extractor.json +++ b/build-tests/api-documenter-test/config/api-extractor.json @@ -7,6 +7,9 @@ "apiReport": { "enabled": true, + "tagsToReport": { + "@myCustomTag": true + } }, "docModel": { @@ -21,8 +24,9 @@ "testMode": true, "messages": { - "tsdocMessageReporting": { - "tsdoc-undefined-tag": { + "extractorMessageReporting": { + // Purposefully disabled for the `writeonlyProperty` test case. + "ae-missing-getter": { "logLevel": "none" } } diff --git a/build-tests/api-documenter-test/config/rig.json b/build-tests/api-documenter-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-documenter-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-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 59563388ae6..8c18b181cfa 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 @@ -2,19 +2,283 @@ "metadata": { "toolPackage": "@microsoft/api-extractor", "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 + "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": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + }, + { + "tagName": "@docCategory", + "syntaxKind": "inline" + }, + { + "tagName": "@myCustomTag", + "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, + "@docCategory": true, + "@myCustomTag": true + }, + "reportUnsupportedHtmlElements": false + } }, "kind": "Package", "canonicalReference": "api-documenter-test!", "docComment": "/**\n * api-extractor-test-05\n *\n * This project tests various documentation generation scenarios and doc comment syntaxes.\n *\n * @packageDocumentation\n */\n", "name": "api-documenter-test", + "preserveMemberOrder": false, "members": [ { "kind": "EntryPoint", "canonicalReference": "api-documenter-test!", "name": "", + "preserveMemberOrder": false, "members": [ + { + "kind": "Class", + "canonicalReference": "api-documenter-test!AbstractClass:class", + "docComment": "/**\n * Some abstract class with abstract members.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare abstract class AbstractClass " + } + ], + "fileUrlPath": "src/AbstractClass.ts", + "releaseTag": "Public", + "isAbstract": true, + "name": "AbstractClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-documenter-test!AbstractClass#method:member(1)", + "docComment": "/**\n * Some abstract method.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "abstract method(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": true, + "name": "method" + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-test!AbstractClass#property:member", + "docComment": "/**\n * Some abstract property.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "protected abstract property: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "property", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": true, + "isAbstract": true + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-test!Constraint:interface", + "docComment": "/**\n * Type parameter constraint used by test case below.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Constraint " + } + ], + "fileUrlPath": "src/DocClass1.ts", + "releaseTag": "Public", + "name": "Constraint", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + }, { "kind": "Variable", "canonicalReference": "api-documenter-test!constVariable:var", @@ -29,6 +293,8 @@ "text": "number" } ], + "fileUrlPath": "src/index.ts", + "isReadonly": true, "releaseTag": "Public", "name": "constVariable", "variableTypeTokenRange": { @@ -36,6 +302,73 @@ "endIndex": 2 } }, + { + "kind": "Class", + "canonicalReference": "api-documenter-test!DecoratorExample:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class DecoratorExample " + } + ], + "fileUrlPath": "src/DecoratorExample.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "DecoratorExample", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-documenter-test!DecoratorExample#creationDate:member", + "docComment": "/**\n * The date when the record was created.\n *\n * @remarks\n *\n * Here is a longer description of the property.\n *\n * @decorator\n *\n * `@jsonSerialized`\n *\n * @decorator\n *\n * `@jsonFormat('mm/dd/yy')`\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "creationDate: " + }, + { + "kind": "Reference", + "text": "Date", + "canonicalReference": "!Date:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "creationDate", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-test!DefaultType:interface", + "docComment": "/**\n * Type parameter default type used by test case below.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface DefaultType " + } + ], + "fileUrlPath": "src/DocClass1.ts", + "releaseTag": "Public", + "name": "DefaultType", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + }, { "kind": "Class", "canonicalReference": "api-documenter-test!DocBaseClass:class", @@ -46,8 +379,11 @@ "text": "export declare class DocBaseClass " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", + "isAbstract": false, "name": "DocBaseClass", + "preserveMemberOrder": false, "members": [ { "kind": "Constructor", @@ -60,6 +396,7 @@ } ], "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [] }, @@ -82,6 +419,7 @@ } ], "releaseTag": "Public", + "isProtected": false, "overloadIndex": 2, "parameters": [ { @@ -89,7 +427,8 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ] } @@ -112,11 +451,7 @@ }, { "kind": "Content", - "text": " " - }, - { - "kind": "Content", - "text": "implements " + "text": " implements " }, { "kind": "Reference", @@ -137,8 +472,11 @@ "text": " " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", + "isAbstract": false, "name": "DocClass1", + "preserveMemberOrder": false, "members": [ { "kind": "Method", @@ -164,8 +502,11 @@ "endIndex": 2 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [], + "isOptional": false, + "isAbstract": false, "name": "deprecatedExample" }, { @@ -208,6 +549,7 @@ "endIndex": 6 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [ { @@ -215,16 +557,20 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false }, { "parameterName": "b", "parameterTypeTokenRange": { "startIndex": 3, "endIndex": 4 - } + }, + "isOptional": false } ], + "isOptional": false, + "isAbstract": false, "name": "exampleFunction" }, { @@ -259,6 +605,7 @@ "endIndex": 4 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 2, "parameters": [ { @@ -266,11 +613,93 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ], + "isOptional": false, + "isAbstract": false, "name": "exampleFunction" }, + { + "kind": "Method", + "canonicalReference": "api-documenter-test!DocClass1#genericWithConstraintAndDefault:member(1)", + "docComment": "/**\n * This is a method with a complex type parameter.\n *\n * @param x - some generic parameter.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "genericWithConstraintAndDefault(x: " + }, + { + "kind": "Content", + "text": "T" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "defaultTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "genericWithConstraintAndDefault" + }, { "kind": "Method", "canonicalReference": "api-documenter-test!DocClass1#interestingEdgeCases:member(1)", @@ -295,8 +724,11 @@ "endIndex": 2 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [], + "isOptional": false, + "isAbstract": false, "name": "interestingEdgeCases" }, { @@ -318,13 +750,17 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "malformedEvent", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 2 }, - "isStatic": false + "isStatic": false, + "isProtected": false, + "isAbstract": false }, { "kind": "Property", @@ -345,13 +781,125 @@ "text": ";" } ], + "isReadonly": true, + "isOptional": false, "releaseTag": "Public", "name": "modifiedEvent", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 2 }, - "isStatic": false + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-test!DocClass1.multipleModifiersProperty:member", + "docComment": "/**\n * Some property with multiple modifiers.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "protected static readonly multipleModifiersProperty: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "multipleModifiersProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": true, + "isProtected": true, + "isAbstract": false + }, + { + "kind": "Method", + "canonicalReference": "api-documenter-test!DocClass1#optionalParamFunction:member(1)", + "docComment": "/**\n * This is a function with an optional parameter.\n *\n * @param x - the number\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "optionalParamFunction(x?: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": true + } + ], + "isOptional": false, + "isAbstract": false, + "name": "optionalParamFunction" + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-test!DocClass1#protectedProperty:member", + "docComment": "/**\n * Some protected property.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "protected protectedProperty: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "protectedProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": true, + "isAbstract": false }, { "kind": "Property", @@ -371,13 +919,17 @@ "text": ";" } ], + "isReadonly": true, + "isOptional": false, "releaseTag": "Public", "name": "readonlyProperty", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 2 }, - "isStatic": false + "isStatic": false, + "isProtected": false, + "isAbstract": false }, { "kind": "Property", @@ -398,13 +950,17 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "regularProperty", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 2 }, - "isStatic": false + "isStatic": false, + "isProtected": false, + "isAbstract": false }, { "kind": "Method", @@ -446,6 +1002,7 @@ "endIndex": 6 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [ { @@ -453,16 +1010,20 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false }, { "parameterName": "y", "parameterTypeTokenRange": { "startIndex": 3, "endIndex": 4 - } + }, + "isOptional": false } ], + "isOptional": false, + "isAbstract": false, "name": "sumWithExample" }, { @@ -489,8 +1050,11 @@ "endIndex": 2 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [], + "isOptional": false, + "isAbstract": false, "name": "tableExample" }, { @@ -508,49 +1072,82 @@ }, { "kind": "Content", - "text": ";" + "text": ";\n\nset writeableProperty(value: string);" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "writeableProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-documenter-test!DocClass1#writeonlyProperty:member", + "docComment": "/**\n * API Extractor will surface an `ae-missing-getter` finding for this property.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "set writeonlyProperty(value: " }, { "kind": "Content", - "text": "\n\nset writeableProperty(value: string);" + "text": "string" + }, + { + "kind": "Content", + "text": ");" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", - "name": "writeableProperty", + "name": "writeonlyProperty", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 2 }, - "isStatic": false + "isStatic": false, + "isProtected": false, + "isAbstract": false } ], "extendsTokenRange": { "startIndex": 1, - "endIndex": 3 + "endIndex": 2 }, "implementsTokenRanges": [ { - "startIndex": 4, - "endIndex": 5 + "startIndex": 3, + "endIndex": 4 }, { - "startIndex": 6, - "endIndex": 8 + "startIndex": 5, + "endIndex": 6 } ] }, { "kind": "Class", "canonicalReference": "api-documenter-test!DocClassInterfaceMerge:class", - "docComment": "/**\n * Class that merges with interface\n *\n * @public\n */\n", + "docComment": "/**\n * Class that merges with interface\n *\n * @remarks\n *\n * {@link (DocClassInterfaceMerge:class) | Link to class}\n *\n * {@link (DocClassInterfaceMerge:interface) | Link to interface}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", "text": "export declare class DocClassInterfaceMerge " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", + "isAbstract": false, "name": "DocClassInterfaceMerge", + "preserveMemberOrder": false, "members": [], "implementsTokenRanges": [] }, @@ -564,8 +1161,10 @@ "text": "export interface DocClassInterfaceMerge " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "DocClassInterfaceMerge", + "preserveMemberOrder": false, "members": [], "extendsTokenRanges": [] }, @@ -579,8 +1178,10 @@ "text": "export declare enum DocEnum " } ], + "fileUrlPath": "src/DocEnums.ts", "releaseTag": "Public", "name": "DocEnum", + "preserveMemberOrder": false, "members": [ { "kind": "EnumMember", @@ -596,17 +1197,17 @@ "text": "1" } ], - "releaseTag": "Public", - "name": "One", "initializerTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "releaseTag": "Public", + "name": "One" }, { "kind": "EnumMember", "canonicalReference": "api-documenter-test!DocEnum.Two:member", - "docComment": "/**\n * These are some docs for Two\n */\n", + "docComment": "/**\n * These are some docs for Two.\n *\n * {@link DocEnum.One} is a direct link to another enum member.\n */\n", "excerptTokens": [ { "kind": "Content", @@ -617,12 +1218,12 @@ "text": "2" } ], - "releaseTag": "Public", - "name": "Two", "initializerTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "releaseTag": "Public", + "name": "Two" }, { "kind": "EnumMember", @@ -638,31 +1239,136 @@ "text": "0" } ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, "releaseTag": "Public", - "name": "Zero", + "name": "Zero" + } + ] + }, + { + "kind": "Enum", + "canonicalReference": "api-documenter-test!DocEnumNamespaceMerge:enum", + "docComment": "/**\n * Enum that merges with namespace\n *\n * @remarks\n *\n * {@link (DocEnumNamespaceMerge:enum) | Link to enum}\n *\n * {@link (DocEnumNamespaceMerge:namespace) | Link to namespace}\n *\n * {@link (DocEnumNamespaceMerge:namespace).exampleFunction | Link to function inside namespace}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum DocEnumNamespaceMerge " + } + ], + "fileUrlPath": "src/DocEnums.ts", + "releaseTag": "Public", + "name": "DocEnumNamespaceMerge", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-documenter-test!DocEnumNamespaceMerge.Left:member", + "docComment": "/**\n * These are some docs for Left\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Left = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Left" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-documenter-test!DocEnumNamespaceMerge.Right:member", + "docComment": "/**\n * These are some docs for Right\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Right = " + }, + { + "kind": "Content", + "text": "1" + } + ], "initializerTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "releaseTag": "Public", + "name": "Right" + } + ] + }, + { + "kind": "Namespace", + "canonicalReference": "api-documenter-test!DocEnumNamespaceMerge:namespace", + "docComment": "/**\n * Namespace that merges with enum\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace DocEnumNamespaceMerge " + } + ], + "fileUrlPath": "src/DocEnums.ts", + "releaseTag": "Public", + "name": "DocEnumNamespaceMerge", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)", + "docComment": "/**\n * This is a function inside of a namespace that merges with an enum.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "function exampleFunction(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "exampleFunction" } ] }, { "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": [ { @@ -674,6 +1380,7 @@ "text": "unique symbol" } ], + "isReadonly": true, "releaseTag": "Public", "name": "example", "variableTypeTokenRange": { @@ -683,6 +1390,105 @@ } ] }, + { + "kind": "TypeAlias", + "canonicalReference": "api-documenter-test!ExampleDuplicateTypeAlias:type", + "docComment": "/**\n * A type alias that has duplicate references.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type ExampleDuplicateTypeAlias = " + }, + { + "kind": "Reference", + "text": "SystemEvent", + "canonicalReference": "api-documenter-test!SystemEvent:class" + }, + { + "kind": "Content", + "text": " | typeof " + }, + { + "kind": "Reference", + "text": "SystemEvent", + "canonicalReference": "api-documenter-test!SystemEvent:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/index.ts", + "releaseTag": "Public", + "name": "ExampleDuplicateTypeAlias", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 4 + } + }, + { + "kind": "Function", + "canonicalReference": "api-documenter-test!exampleFunction:function(1)", + "docComment": "/**\n * An exported function with hyperlinked parameters and return value.\n *\n * @param x - an API item that should get hyperlinked\n *\n * @param y - a system type that should NOT get hyperlinked\n *\n * @returns an interface that should get hyperlinked\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function exampleFunction(x: " + }, + { + "kind": "Reference", + "text": "ExampleTypeAlias", + "canonicalReference": "api-documenter-test!ExampleTypeAlias:type" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "IDocInterface1", + "canonicalReference": "api-documenter-test!IDocInterface1:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "exampleFunction" + }, { "kind": "TypeAlias", "canonicalReference": "api-documenter-test!ExampleTypeAlias:type", @@ -690,7 +1496,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare type ExampleTypeAlias = " + "text": "export type ExampleTypeAlias = " }, { "kind": "Reference", @@ -706,6 +1512,7 @@ "text": ";" } ], + "fileUrlPath": "src/index.ts", "releaseTag": "Public", "name": "ExampleTypeAlias", "typeTokenRange": { @@ -713,6 +1520,42 @@ "endIndex": 3 } }, + { + "kind": "TypeAlias", + "canonicalReference": "api-documenter-test!ExampleUnionTypeAlias:type", + "docComment": "/**\n * A type alias that references multiple other types.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type ExampleUnionTypeAlias = " + }, + { + "kind": "Reference", + "text": "IDocInterface1", + "canonicalReference": "api-documenter-test!IDocInterface1:interface" + }, + { + "kind": "Content", + "text": " | " + }, + { + "kind": "Reference", + "text": "IDocInterface3", + "canonicalReference": "api-documenter-test!IDocInterface3:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/index.ts", + "releaseTag": "Public", + "name": "ExampleUnionTypeAlias", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 4 + } + }, { "kind": "Class", "canonicalReference": "api-documenter-test!Generic:class", @@ -723,6 +1566,7 @@ "text": "export declare class Generic " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "typeParameters": [ { @@ -737,7 +1581,9 @@ } } ], + "isAbstract": false, "name": "Generic", + "preserveMemberOrder": false, "members": [], "implementsTokenRanges": [] }, @@ -748,7 +1594,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare type GenericTypeAlias = " + "text": "export type GenericTypeAlias = " }, { "kind": "Content", @@ -759,6 +1605,7 @@ "text": ";" } ], + "fileUrlPath": "src/index.ts", "releaseTag": "Public", "name": "GenericTypeAlias", "typeParameters": [ @@ -779,49 +1626,6 @@ "endIndex": 2 } }, - { - "kind": "Function", - "canonicalReference": "api-documenter-test!globalFunction:function(1)", - "docComment": "/**\n * An exported function\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function globalFunction(x: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "globalFunction" - }, { "kind": "Interface", "canonicalReference": "api-documenter-test!IDocInterface1:interface", @@ -832,8 +1636,10 @@ "text": "export interface IDocInterface1 " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface1", + "preserveMemberOrder": false, "members": [ { "kind": "PropertySignature", @@ -854,6 +1660,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "regularProperty", "propertyTypeTokenRange": { @@ -883,8 +1691,10 @@ "text": " " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface2", + "preserveMemberOrder": false, "members": [ { "kind": "MethodSignature", @@ -904,6 +1714,7 @@ "text": ";" } ], + "isOptional": false, "returnTypeTokenRange": { "startIndex": 1, "endIndex": 2 @@ -917,7 +1728,7 @@ "extendsTokenRanges": [ { "startIndex": 1, - "endIndex": 3 + "endIndex": 2 } ] }, @@ -931,13 +1742,15 @@ "text": "export interface IDocInterface3 " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface3", + "preserveMemberOrder": false, "members": [ { "kind": "PropertySignature", "canonicalReference": "api-documenter-test!IDocInterface3#\"[not.a.symbol]\":member", - "docComment": "/**\n * An identifier that does needs quotes. It misleadingly looks like an ECMAScript symbol.\n */\n", + "docComment": "/**\n * An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol.\n */\n", "excerptTokens": [ { "kind": "Content", @@ -952,6 +1765,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "\"[not.a.symbol]\"", "propertyTypeTokenRange": { @@ -961,7 +1776,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": [ { @@ -970,8 +1785,8 @@ }, { "kind": "Reference", - "text": "EcmaSmbols.example", - "canonicalReference": "api-documenter-test!EcmaSmbols.example" + "text": "EcmaSymbols.example", + "canonicalReference": "api-documenter-test!EcmaSymbols.example" }, { "kind": "Content", @@ -986,8 +1801,10 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", - "name": "[EcmaSmbols.example]", + "name": "[EcmaSymbols.example]", "propertyTypeTokenRange": { "startIndex": 3, "endIndex": 4 @@ -1031,7 +1848,8 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ] }, @@ -1088,6 +1906,7 @@ "text": ";" } ], + "isReadonly": false, "returnTypeTokenRange": { "startIndex": 3, "endIndex": 4 @@ -1100,7 +1919,8 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ] }, @@ -1122,6 +1942,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "redundantQuotes", "propertyTypeTokenRange": { @@ -1142,8 +1964,10 @@ "text": "export interface IDocInterface4 " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface4", + "preserveMemberOrder": false, "members": [ { "kind": "PropertySignature", @@ -1163,6 +1987,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "Context", "propertyTypeTokenRange": { @@ -1193,6 +2019,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "generic", "propertyTypeTokenRange": { @@ -1218,6 +2046,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "numberOrFunction", "propertyTypeTokenRange": { @@ -1243,6 +2073,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "stringOrNumber", "propertyTypeTokenRange": { @@ -1263,8 +2095,10 @@ "text": "export interface IDocInterface5 " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface5", + "preserveMemberOrder": false, "members": [ { "kind": "PropertySignature", @@ -1284,6 +2118,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "regularProperty", "propertyTypeTokenRange": { @@ -1304,8 +2140,10 @@ "text": "export interface IDocInterface6 " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", "name": "IDocInterface6", + "preserveMemberOrder": false, "members": [ { "kind": "PropertySignature", @@ -1330,6 +2168,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "arrayProperty", "propertyTypeTokenRange": { @@ -1363,6 +2203,7 @@ "text": ";" } ], + "isOptional": false, "returnTypeTokenRange": { "startIndex": 3, "endIndex": 4 @@ -1375,7 +2216,8 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ], "typeParameters": [ @@ -1421,6 +2263,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "intersectionProperty", "propertyTypeTokenRange": { @@ -1446,6 +2290,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "regularProperty", "propertyTypeTokenRange": { @@ -1489,6 +2335,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "tupleProperty", "propertyTypeTokenRange": { @@ -1528,6 +2376,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "typeReferenceProperty", "propertyTypeTokenRange": { @@ -1563,6 +2413,8 @@ "text": ";" } ], + "isReadonly": false, + "isOptional": false, "releaseTag": "Public", "name": "unionProperty", "propertyTypeTokenRange": { @@ -1573,6 +2425,133 @@ ], "extendsTokenRanges": [] }, + { + "kind": "Interface", + "canonicalReference": "api-documenter-test!IDocInterface7:interface", + "docComment": "/**\n * Interface for testing optional properties\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IDocInterface7 " + } + ], + "fileUrlPath": "src/DocClass1.ts", + "releaseTag": "Public", + "name": "IDocInterface7", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-test!IDocInterface7#optionalField:member", + "docComment": "/**\n * Description of optionalField\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "optionalField?: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": true, + "releaseTag": "Public", + "name": "optionalField", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "MethodSignature", + "canonicalReference": "api-documenter-test!IDocInterface7#optionalMember:member(1)", + "docComment": "/**\n * Description of optionalMember\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "optionalMember?(): " + }, + { + "kind": "Content", + "text": "any" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isOptional": true, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "optionalMember" + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-test!IDocInterface7#optionalReadonlyField:member", + "docComment": "/**\n * Description of optionalReadonlyField\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly optionalReadonlyField?: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": true, + "releaseTag": "Public", + "name": "optionalReadonlyField", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-documenter-test!IDocInterface7#optionalUndocumentedField:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "optionalUndocumentedField?: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": true, + "releaseTag": "Public", + "name": "optionalUndocumentedField", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, { "kind": "Namespace", "canonicalReference": "api-documenter-test!OuterNamespace:namespace", @@ -1583,8 +2562,10 @@ "text": "export declare namespace OuterNamespace " } ], + "fileUrlPath": "src/index.ts", "releaseTag": "Public", "name": "OuterNamespace", + "preserveMemberOrder": false, "members": [ { "kind": "Namespace", @@ -1598,6 +2579,7 @@ ], "releaseTag": "Public", "name": "InnerNamespace", + "preserveMemberOrder": false, "members": [ { "kind": "Function", @@ -1637,7 +2619,8 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ], "name": "nestedFunction" @@ -1658,6 +2641,7 @@ "text": "boolean" } ], + "isReadonly": false, "releaseTag": "Public", "name": "nestedVariable", "variableTypeTokenRange": { @@ -1670,15 +2654,18 @@ { "kind": "Class", "canonicalReference": "api-documenter-test!SystemEvent:class", - "docComment": "/**\n * A class used to exposed events.\n *\n * {@docCategory SystemEvent}\n *\n * @public\n */\n", + "docComment": "/**\n * A class used to exposed events.\n *\n * {@docCategory SystemEvent}\n *\n * @public @myCustomTag\n */\n", "excerptTokens": [ { "kind": "Content", "text": "export declare class SystemEvent " } ], + "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", + "isAbstract": false, "name": "SystemEvent", + "preserveMemberOrder": false, "members": [ { "kind": "Method", @@ -1712,6 +2699,7 @@ "endIndex": 4 }, "releaseTag": "Public", + "isProtected": false, "overloadIndex": 1, "parameters": [ { @@ -1719,9 +2707,12 @@ "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 - } + }, + "isOptional": false } ], + "isOptional": false, + "isAbstract": false, "name": "addHandler" } ], @@ -1734,7 +2725,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare type TypeAlias = " + "text": "export type TypeAlias = " }, { "kind": "Content", @@ -1745,6 +2736,7 @@ "text": ";" } ], + "fileUrlPath": "src/index.ts", "releaseTag": "Public", "name": "TypeAlias", "typeTokenRange": { @@ -1771,6 +2763,7 @@ "text": ";" } ], + "fileUrlPath": "src/index.ts", "returnTypeTokenRange": { "startIndex": 1, "endIndex": 2 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 0f0ca36e8f5..4b6989eff89 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 @@ -4,9 +4,28 @@ ```ts +// @public +export abstract class AbstractClass { + abstract method(): void; + protected abstract property: number; +} + +// @public +export interface Constraint { +} + // @public export const constVariable: number; +// @public (undocumented) +export class DecoratorExample { + creationDate: Date; +} + +// @public +export interface DefaultType { +} + // @public export class DocBaseClass { constructor(); @@ -21,11 +40,15 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter deprecatedExample(): void; exampleFunction(a: string, b: string): string; exampleFunction(x: number): number; + genericWithConstraintAndDefault(x: T): void; interestingEdgeCases(): void; // @eventProperty malformedEvent: SystemEvent; // @eventProperty readonly modifiedEvent: SystemEvent; + protected static readonly multipleModifiersProperty: boolean; + optionalParamFunction(x?: number): void; + protected protectedProperty: string; // (undocumented) get readonlyProperty(): string; regularProperty: SystemEvent; @@ -34,6 +57,7 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter // (undocumented) get writeableProperty(): string; set writeableProperty(value: string); + set writeonlyProperty(value: string); } // @public @@ -52,13 +76,33 @@ export enum DocEnum { } // @public -export namespace EcmaSmbols { +export enum DocEnumNamespaceMerge { + Left = 0, + Right = 1 +} + +// @public +export namespace DocEnumNamespaceMerge { + export function exampleFunction(): void; +} + +// @public +export namespace EcmaSymbols { const example: unique symbol; } +// @public +export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent; + +// @public +export function exampleFunction(x: ExampleTypeAlias, y: number): IDocInterface1; + // @public export type ExampleTypeAlias = Promise; +// @public +export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; + // @public export class Generic { } @@ -66,9 +110,6 @@ export class Generic { // @public (undocumented) export type GenericTypeAlias = T[]; -// @public -export function globalFunction(x: number): number; - // @public (undocumented) export interface IDocInterface1 { regularProperty: SystemEvent; @@ -83,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; @@ -126,6 +167,15 @@ export interface IDocInterface6 { unionProperty: IDocInterface1 | IDocInterface2; } +// @public +export interface IDocInterface7 { + optionalField?: boolean; + optionalMember?(): any; + readonly optionalReadonlyField?: boolean; + // (undocumented) + optionalUndocumentedField?: boolean; +} + // @public export namespace OuterNamespace { export namespace InnerNamespace { @@ -134,7 +184,7 @@ export namespace OuterNamespace { let nestedVariable: boolean; } -// @public +// @public @myCustomTag export class SystemEvent { addHandler(handler: () => void): void; } @@ -145,5 +195,4 @@ export type TypeAlias = number; // @public (undocumented) export function yamlReferenceUniquenessTest(): IDocInterface1; - ``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.constvariable.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.constvariable.md deleted file mode 100644 index 3eb2979a44b..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.constvariable.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [constVariable](./api-documenter-test.constvariable.md) - -## constVariable variable - -An exported variable declaration. - -Signature: - -```typescript -constVariable: number -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor_.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor_.md deleted file mode 100644 index 9fb39e46aa2..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor_.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) > [(constructor)](./api-documenter-test.docbaseclass._constructor_.md) - -## DocBaseClass.(constructor) - -The simple constructor for `DocBaseClass` - -Signature: - -```typescript -constructor(); -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor__1.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor__1.md deleted file mode 100644 index a8380b80c70..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass._constructor__1.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) > [(constructor)](./api-documenter-test.docbaseclass._constructor__1.md) - -## DocBaseClass.(constructor) - -The overloaded constructor for `DocBaseClass` - -Signature: - -```typescript -constructor(x: number); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | number | | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md deleted file mode 100644 index 792bd688c23..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) - -## DocBaseClass class - -Example base class - - -Signature: - -```typescript -export declare class DocBaseClass -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)()](./api-documenter-test.docbaseclass._constructor_.md) | | The simple constructor for DocBaseClass | -| [(constructor)(x)](./api-documenter-test.docbaseclass._constructor__1.md) | | The overloaded constructor for DocBaseClass | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.deprecatedexample.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.deprecatedexample.md deleted file mode 100644 index 165f827a2f1..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.deprecatedexample.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [deprecatedExample](./api-documenter-test.docclass1.deprecatedexample.md) - -## DocClass1.deprecatedExample() method - -> Warning: This API is now obsolete. -> -> Use `otherThing()` instead. -> - -Signature: - -```typescript -deprecatedExample(): void; -``` -Returns: - -`void` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction.md deleted file mode 100644 index 661fb617adc..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction.md +++ /dev/null @@ -1,31 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [exampleFunction](./api-documenter-test.docclass1.examplefunction.md) - -## DocClass1.exampleFunction() method - -This is an overloaded function. - -Signature: - -```typescript -exampleFunction(a: string, b: string): string; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| a | string | the first string | -| b | string | the second string | - -Returns: - -`string` - -## Exceptions - -`Error` The first throws line - -The second throws line - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction_1.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction_1.md deleted file mode 100644 index a54d37c8548..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.examplefunction_1.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [exampleFunction](./api-documenter-test.docclass1.examplefunction_1.md) - -## DocClass1.exampleFunction() method - -This is also an overloaded function. - -Signature: - -```typescript -exampleFunction(x: number): number; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | number | the number | - -Returns: - -`number` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.interestingedgecases.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.interestingedgecases.md deleted file mode 100644 index 0ab1e611784..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.interestingedgecases.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [interestingEdgeCases](./api-documenter-test.docclass1.interestingedgecases.md) - -## DocClass1.interestingEdgeCases() method - -Example: "{ \\"maxItemsToShow\\": 123 }" - -The regular expression used to validate the constraints is /^\[a-zA-Z0-9\\-\_\]+$/ - -Signature: - -```typescript -interestingEdgeCases(): void; -``` -Returns: - -`void` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.malformedevent.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.malformedevent.md deleted file mode 100644 index 8f399f0611b..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.malformedevent.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [malformedEvent](./api-documenter-test.docclass1.malformedevent.md) - -## DocClass1.malformedEvent property - -This event should have been marked as readonly. - -Signature: - -```typescript -malformedEvent: SystemEvent; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md deleted file mode 100644 index 1804b9795f8..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md +++ /dev/null @@ -1,49 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) - -## DocClass1 class - -This is an example class. - -Signature: - -```typescript -export declare class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInterface2 -``` - -## Remarks - -[Link to overload 1](./api-documenter-test.docclass1.examplefunction.md) - -[Link to overload 2](./api-documenter-test.docclass1.examplefunction_1.md) - - -The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `DocClass1` class. - -## Events - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [malformedEvent](./api-documenter-test.docclass1.malformedevent.md) | | SystemEvent | This event should have been marked as readonly. | -| [modifiedEvent](./api-documenter-test.docclass1.modifiedevent.md) | | SystemEvent | This event is fired whenever the object is modified. | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [readonlyProperty](./api-documenter-test.docclass1.readonlyproperty.md) | | string | | -| [regularProperty](./api-documenter-test.docclass1.regularproperty.md) | | SystemEvent | This is a regular property that happens to use the SystemEvent type. | -| [writeableProperty](./api-documenter-test.docclass1.writeableproperty.md) | | string | | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [deprecatedExample()](./api-documenter-test.docclass1.deprecatedexample.md) | | | -| [exampleFunction(a, b)](./api-documenter-test.docclass1.examplefunction.md) | | This is an overloaded function. | -| [exampleFunction(x)](./api-documenter-test.docclass1.examplefunction_1.md) | | This is also an overloaded function. | -| [interestingEdgeCases()](./api-documenter-test.docclass1.interestingedgecases.md) | | Example: "{ \\"maxItemsToShow\\": 123 }"The regular expression used to validate the constraints is /^\[a-zA-Z0-9\\-\_\]+$/ | -| [sumWithExample(x, y)](./api-documenter-test.docclass1.sumwithexample.md) | static | Returns the sum of two numbers. | -| [tableExample()](./api-documenter-test.docclass1.tableexample.md) | | An example with tables: | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.modifiedevent.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.modifiedevent.md deleted file mode 100644 index 5d20b88e0a2..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.modifiedevent.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [modifiedEvent](./api-documenter-test.docclass1.modifiedevent.md) - -## DocClass1.modifiedEvent property - -This event is fired whenever the object is modified. - -Signature: - -```typescript -readonly modifiedEvent: SystemEvent; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.readonlyproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.readonlyproperty.md deleted file mode 100644 index 44cb15a1324..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.readonlyproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [readonlyProperty](./api-documenter-test.docclass1.readonlyproperty.md) - -## DocClass1.readonlyProperty property - -Signature: - -```typescript -get readonlyProperty(): string; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.regularproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.regularproperty.md deleted file mode 100644 index 3cf536db280..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.regularproperty.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [regularProperty](./api-documenter-test.docclass1.regularproperty.md) - -## DocClass1.regularProperty property - -This is a regular property that happens to use the SystemEvent type. - -Signature: - -```typescript -regularProperty: SystemEvent; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.sumwithexample.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.sumwithexample.md deleted file mode 100644 index 8ea932a1c3b..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.sumwithexample.md +++ /dev/null @@ -1,51 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [sumWithExample](./api-documenter-test.docclass1.sumwithexample.md) - -## DocClass1.sumWithExample() method - -Returns the sum of two numbers. - -Signature: - -```typescript -static sumWithExample(x: number, y: number): number; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | number | the first number to add | -| y | number | the second number to add | - -Returns: - -`number` - -the sum of the two numbers - -## Remarks - -This illustrates usage of the `@example` block tag. - -## Example 1 - -Here's a simple example: - -``` -// Prints "2": -console.log(DocClass1.sumWithExample(1,1)); - -``` - -## Example 2 - -Here's an example with negative numbers: - -``` -// Prints "0": -console.log(DocClass1.sumWithExample(1,-1)); - -``` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.tableexample.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.tableexample.md deleted file mode 100644 index 3b197db94e9..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.tableexample.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [tableExample](./api-documenter-test.docclass1.tableexample.md) - -## DocClass1.tableExample() method - -An example with tables: - -Signature: - -```typescript -tableExample(): void; -``` -Returns: - -`void` - -## Remarks - -
John Doe
- diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.writeableproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.writeableproperty.md deleted file mode 100644 index a5284923d0d..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.writeableproperty.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [writeableProperty](./api-documenter-test.docclass1.writeableproperty.md) - -## DocClass1.writeableProperty property - -Signature: - -```typescript -get writeableProperty(): string; - -set writeableProperty(value: string); -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclassinterfacemerge.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclassinterfacemerge.md deleted file mode 100644 index 50644c01913..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclassinterfacemerge.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) - -## DocClassInterfaceMerge interface - -Interface that merges with class - -Signature: - -```typescript -export interface DocClassInterfaceMerge -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md deleted file mode 100644 index 4cce685c2e7..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocEnum](./api-documenter-test.docenum.md) - -## DocEnum enum - -Docs for DocEnum - - -Signature: - -```typescript -export declare enum DocEnum -``` - -## Enumeration Members - -| Member | Value | Description | -| --- | --- | --- | -| One | 1 | These are some docs for One | -| Two | 2 | These are some docs for Two | -| Zero | 0 | These are some docs for Zero | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.example.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.example.md deleted file mode 100644 index bc53b742377..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.example.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSmbols](./api-documenter-test.ecmasmbols.md) > [example](./api-documenter-test.ecmasmbols.example.md) - -## EcmaSmbols.example variable - -An ECMAScript symbol - -Signature: - -```typescript -example: unique symbol -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.md deleted file mode 100644 index 6dc78e8f8eb..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.ecmasmbols.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSmbols](./api-documenter-test.ecmasmbols.md) - -## EcmaSmbols namespace - -A namespace containing an ECMAScript symbol - -Signature: - -```typescript -export declare namespace EcmaSmbols -``` - -## Variables - -| Variable | Description | -| --- | --- | -| [example](./api-documenter-test.ecmasmbols.example.md) | An ECMAScript symbol | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.exampletypealias.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.exampletypealias.md deleted file mode 100644 index 04ab2642d0d..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.exampletypealias.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [ExampleTypeAlias](./api-documenter-test.exampletypealias.md) - -## ExampleTypeAlias type - -A type alias - -Signature: - -```typescript -export declare type ExampleTypeAlias = Promise; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generic.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generic.md deleted file mode 100644 index 5c9289a7f71..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generic.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [Generic](./api-documenter-test.generic.md) - -## Generic class - -Generic class. - -Signature: - -```typescript -export declare class Generic -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md deleted file mode 100644 index d0ce5a0e31e..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.generictypealias.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [GenericTypeAlias](./api-documenter-test.generictypealias.md) - -## GenericTypeAlias type - - -Signature: - -```typescript -export declare type GenericTypeAlias = T[]; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.globalfunction.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.globalfunction.md deleted file mode 100644 index da15ffde05e..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.globalfunction.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [globalFunction](./api-documenter-test.globalfunction.md) - -## globalFunction() function - -An exported function - -Signature: - -```typescript -export declare function globalFunction(x: number): number; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | number | | - -Returns: - -`number` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.md deleted file mode 100644 index 1e453fdd7ea..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface1](./api-documenter-test.idocinterface1.md) - -## IDocInterface1 interface - - -Signature: - -```typescript -export interface IDocInterface1 -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [regularProperty](./api-documenter-test.idocinterface1.regularproperty.md) | SystemEvent | Does something | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.regularproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.regularproperty.md deleted file mode 100644 index 759d9b9f192..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface1.regularproperty.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface1](./api-documenter-test.idocinterface1.md) > [regularProperty](./api-documenter-test.idocinterface1.regularproperty.md) - -## IDocInterface1.regularProperty property - -Does something - -Signature: - -```typescript -regularProperty: SystemEvent; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.deprecatedexample.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.deprecatedexample.md deleted file mode 100644 index 8fc8a3fe71c..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.deprecatedexample.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface2](./api-documenter-test.idocinterface2.md) > [deprecatedExample](./api-documenter-test.idocinterface2.deprecatedexample.md) - -## IDocInterface2.deprecatedExample() method - -> Warning: This API is now obsolete. -> -> Use `otherThing()` instead. -> - -Signature: - -```typescript -deprecatedExample(): void; -``` -Returns: - -`void` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.md deleted file mode 100644 index c0155f167e1..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface2.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface2](./api-documenter-test.idocinterface2.md) - -## IDocInterface2 interface - - -Signature: - -```typescript -export interface IDocInterface2 extends IDocInterface1 -``` - -## Methods - -| Method | Description | -| --- | --- | -| [deprecatedExample()](./api-documenter-test.idocinterface2.deprecatedexample.md) | | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.__not.a.symbol__.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.__not.a.symbol__.md deleted file mode 100644 index d776773a478..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.__not.a.symbol__.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > ["\[not.a.symbol\]"](./api-documenter-test.idocinterface3.__not.a.symbol__.md) - -## IDocInterface3."\[not.a.symbol\]" property - -An identifier that does needs quotes. It misleadingly looks like an ECMAScript symbol. - -Signature: - -```typescript -"[not.a.symbol]": string; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._ecmasmbols.example_.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._ecmasmbols.example_.md deleted file mode 100644 index 756b8bf970e..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._ecmasmbols.example_.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[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) - -## IDocInterface3.\[EcmaSmbols.example\] property - -ECMAScript symbol - -Signature: - -```typescript -[EcmaSmbols.example]: string; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._new_.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._new_.md deleted file mode 100644 index 0c0df0a79d0..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3._new_.md +++ /dev/null @@ -1,17 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [(new)](./api-documenter-test.idocinterface3._new_.md) - -## IDocInterface3.(new) - -Construct signature - -Signature: - -```typescript -new (): IDocInterface1; -``` -Returns: - -`IDocInterface1` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md deleted file mode 100644 index 28895d133be..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md +++ /dev/null @@ -1,29 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) - -## IDocInterface3 interface - -Some less common TypeScript declaration kinds. - - -Signature: - -```typescript -export interface IDocInterface3 -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| ["\[not.a.symbol\]"](./api-documenter-test.idocinterface3.__not.a.symbol__.md) | string | An identifier that does needs quotes. It misleadingly looks like an ECMAScript symbol. | -| [\[EcmaSmbols.example\]](./api-documenter-test.idocinterface3._ecmasmbols.example_.md) | string | ECMAScript symbol | -| [redundantQuotes](./api-documenter-test.idocinterface3.redundantquotes.md) | string | A quoted identifier with redundant quotes. | - -## Methods - -| Method | Description | -| --- | --- | -| [(new)()](./api-documenter-test.idocinterface3._new_.md) | Construct signature | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.redundantquotes.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.redundantquotes.md deleted file mode 100644 index d777ba79b49..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.redundantquotes.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [redundantQuotes](./api-documenter-test.idocinterface3.redundantquotes.md) - -## IDocInterface3.redundantQuotes property - -A quoted identifier with redundant quotes. - -Signature: - -```typescript -"redundantQuotes": string; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.context.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.context.md deleted file mode 100644 index 325f354140b..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.context.md +++ /dev/null @@ -1,15 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [Context](./api-documenter-test.idocinterface4.context.md) - -## IDocInterface4.Context property - -Test newline rendering when code blocks are used in tables - -Signature: - -```typescript -Context: ({ children }: { - children: string; - }) => boolean; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.generic.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.generic.md deleted file mode 100644 index 7391c2def0b..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.generic.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [generic](./api-documenter-test.idocinterface4.generic.md) - -## IDocInterface4.generic property - -make sure html entities are escaped in tables. - -Signature: - -```typescript -generic: Generic; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md deleted file mode 100644 index 3dda827e5a3..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) - -## IDocInterface4 interface - -Type union in an interface. - - -Signature: - -```typescript -export interface IDocInterface4 -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [Context](./api-documenter-test.idocinterface4.context.md) | ({ children }: {
children: string;
}) => boolean | Test newline rendering when code blocks are used in tables | -| [generic](./api-documenter-test.idocinterface4.generic.md) | Generic<number> | make sure html entities are escaped in tables. | -| [numberOrFunction](./api-documenter-test.idocinterface4.numberorfunction.md) | number | (() => number) | a union type with a function | -| [stringOrNumber](./api-documenter-test.idocinterface4.stringornumber.md) | string | number | a union type | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.numberorfunction.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.numberorfunction.md deleted file mode 100644 index e36e91fd338..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.numberorfunction.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [numberOrFunction](./api-documenter-test.idocinterface4.numberorfunction.md) - -## IDocInterface4.numberOrFunction property - -a union type with a function - -Signature: - -```typescript -numberOrFunction: number | (() => number); -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.stringornumber.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.stringornumber.md deleted file mode 100644 index 814dd1faeb7..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.stringornumber.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [stringOrNumber](./api-documenter-test.idocinterface4.stringornumber.md) - -## IDocInterface4.stringOrNumber property - -a union type - -Signature: - -```typescript -stringOrNumber: string | number; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.md deleted file mode 100644 index 8e5fe1396f3..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface5](./api-documenter-test.idocinterface5.md) - -## IDocInterface5 interface - -Interface without inline tag to test custom TOC - -Signature: - -```typescript -export interface IDocInterface5 -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [regularProperty](./api-documenter-test.idocinterface5.regularproperty.md) | string | Property of type string that does something | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.regularproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.regularproperty.md deleted file mode 100644 index 903ec43e4df..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface5.regularproperty.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface5](./api-documenter-test.idocinterface5.md) > [regularProperty](./api-documenter-test.idocinterface5.regularproperty.md) - -## IDocInterface5.regularProperty property - -Property of type string that does something - -Signature: - -```typescript -regularProperty: string; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.arrayproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.arrayproperty.md deleted file mode 100644 index aee7a495e71..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.arrayproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [arrayProperty](./api-documenter-test.idocinterface6.arrayproperty.md) - -## IDocInterface6.arrayProperty property - -Signature: - -```typescript -arrayProperty: IDocInterface1[]; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.genericreferencemethod.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.genericreferencemethod.md deleted file mode 100644 index a1bacf13445..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.genericreferencemethod.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [genericReferenceMethod](./api-documenter-test.idocinterface6.genericreferencemethod.md) - -## IDocInterface6.genericReferenceMethod() method - -Signature: - -```typescript -genericReferenceMethod(x: T): T; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | T | | - -Returns: - -`T` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.intersectionproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.intersectionproperty.md deleted file mode 100644 index ba405892095..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.intersectionproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [intersectionProperty](./api-documenter-test.idocinterface6.intersectionproperty.md) - -## IDocInterface6.intersectionProperty property - -Signature: - -```typescript -intersectionProperty: IDocInterface1 & IDocInterface2; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.md deleted file mode 100644 index 19b351fe193..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.md +++ /dev/null @@ -1,31 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) - -## IDocInterface6 interface - -Interface without inline tag to test custom TOC with injection - -Signature: - -```typescript -export interface IDocInterface6 -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [arrayProperty](./api-documenter-test.idocinterface6.arrayproperty.md) | IDocInterface1[] | | -| [intersectionProperty](./api-documenter-test.idocinterface6.intersectionproperty.md) | IDocInterface1 & IDocInterface2 | | -| [regularProperty](./api-documenter-test.idocinterface6.regularproperty.md) | number | Property of type number that does something | -| [tupleProperty](./api-documenter-test.idocinterface6.tupleproperty.md) | [IDocInterface1, IDocInterface2] | | -| [typeReferenceProperty](./api-documenter-test.idocinterface6.typereferenceproperty.md) | Generic<IDocInterface1> | | -| [unionProperty](./api-documenter-test.idocinterface6.unionproperty.md) | IDocInterface1 | IDocInterface2 | | - -## Methods - -| Method | Description | -| --- | --- | -| [genericReferenceMethod(x)](./api-documenter-test.idocinterface6.genericreferencemethod.md) | | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.regularproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.regularproperty.md deleted file mode 100644 index 2160d81ba49..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.regularproperty.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [regularProperty](./api-documenter-test.idocinterface6.regularproperty.md) - -## IDocInterface6.regularProperty property - -Property of type number that does something - -Signature: - -```typescript -regularProperty: number; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.tupleproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.tupleproperty.md deleted file mode 100644 index c1732ee3106..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.tupleproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [tupleProperty](./api-documenter-test.idocinterface6.tupleproperty.md) - -## IDocInterface6.tupleProperty property - -Signature: - -```typescript -tupleProperty: [IDocInterface1, IDocInterface2]; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.typereferenceproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.typereferenceproperty.md deleted file mode 100644 index f6df24d6005..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.typereferenceproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [typeReferenceProperty](./api-documenter-test.idocinterface6.typereferenceproperty.md) - -## IDocInterface6.typeReferenceProperty property - -Signature: - -```typescript -typeReferenceProperty: Generic; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.unionproperty.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.unionproperty.md deleted file mode 100644 index 35139d8a9b8..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface6.unionproperty.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [unionProperty](./api-documenter-test.idocinterface6.unionproperty.md) - -## IDocInterface6.unionProperty property - -Signature: - -```typescript -unionProperty: IDocInterface1 | IDocInterface2; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md deleted file mode 100644 index 82b38593d2c..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.md +++ /dev/null @@ -1,66 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) - -## api-documenter-test package - -api-extractor-test-05 - -This project tests various documentation generation scenarios and doc comment syntaxes. - -## Classes - -| Class | Description | -| --- | --- | -| [DocBaseClass](./api-documenter-test.docbaseclass.md) | Example base class | -| [DocClass1](./api-documenter-test.docclass1.md) | This is an example class. | -| [DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) | Class that merges with interface | -| [Generic](./api-documenter-test.generic.md) | Generic class. | -| [SystemEvent](./api-documenter-test.systemevent.md) | A class used to exposed events. | - -## Enumerations - -| Enumeration | Description | -| --- | --- | -| [DocEnum](./api-documenter-test.docenum.md) | Docs for DocEnum | - -## Functions - -| Function | Description | -| --- | --- | -| [globalFunction(x)](./api-documenter-test.globalfunction.md) | An exported function | -| [yamlReferenceUniquenessTest()](./api-documenter-test.yamlreferenceuniquenesstest.md) | | - -## Interfaces - -| Interface | Description | -| --- | --- | -| [DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) | Interface that merges with class | -| [IDocInterface1](./api-documenter-test.idocinterface1.md) | | -| [IDocInterface2](./api-documenter-test.idocinterface2.md) | | -| [IDocInterface3](./api-documenter-test.idocinterface3.md) | Some less common TypeScript declaration kinds. | -| [IDocInterface4](./api-documenter-test.idocinterface4.md) | Type union in an interface. | -| [IDocInterface5](./api-documenter-test.idocinterface5.md) | Interface without inline tag to test custom TOC | -| [IDocInterface6](./api-documenter-test.idocinterface6.md) | Interface without inline tag to test custom TOC with injection | - -## Namespaces - -| Namespace | Description | -| --- | --- | -| [EcmaSmbols](./api-documenter-test.ecmasmbols.md) | A namespace containing an ECMAScript symbol | -| [OuterNamespace](./api-documenter-test.outernamespace.md) | A top-level namespace | - -## Variables - -| Variable | Description | -| --- | --- | -| [constVariable](./api-documenter-test.constvariable.md) | An exported variable declaration. | - -## Type Aliases - -| Type Alias | Description | -| --- | --- | -| [ExampleTypeAlias](./api-documenter-test.exampletypealias.md) | A type alias | -| [GenericTypeAlias](./api-documenter-test.generictypealias.md) | | -| [TypeAlias](./api-documenter-test.typealias.md) | | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.md deleted file mode 100644 index f0898e29ce6..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) - -## OuterNamespace.InnerNamespace namespace - -A nested namespace - -Signature: - -```typescript -namespace InnerNamespace -``` - -## Functions - -| Function | Description | -| --- | --- | -| [nestedFunction(x)](./api-documenter-test.outernamespace.innernamespace.nestedfunction.md) | A function inside a namespace | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.nestedfunction.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.nestedfunction.md deleted file mode 100644 index 6b46ca54670..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.innernamespace.nestedfunction.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) > [nestedFunction](./api-documenter-test.outernamespace.innernamespace.nestedfunction.md) - -## OuterNamespace.InnerNamespace.nestedFunction() function - -A function inside a namespace - -Signature: - -```typescript -function nestedFunction(x: number): number; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| x | number | | - -Returns: - -`number` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.md deleted file mode 100644 index baa5e873882..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) - -## OuterNamespace namespace - -A top-level namespace - -Signature: - -```typescript -export declare namespace OuterNamespace -``` - -## Namespaces - -| Namespace | Description | -| --- | --- | -| [InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) | A nested namespace | - -## Variables - -| Variable | Description | -| --- | --- | -| [nestedVariable](./api-documenter-test.outernamespace.nestedvariable.md) | A variable exported from within a namespace. | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.nestedvariable.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.nestedvariable.md deleted file mode 100644 index b0b93787cd4..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.outernamespace.nestedvariable.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [nestedVariable](./api-documenter-test.outernamespace.nestedvariable.md) - -## OuterNamespace.nestedVariable variable - -A variable exported from within a namespace. - -Signature: - -```typescript -nestedVariable: boolean -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.addhandler.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.addhandler.md deleted file mode 100644 index a73ed0df48f..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.addhandler.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [SystemEvent](./api-documenter-test.systemevent.md) > [addHandler](./api-documenter-test.systemevent.addhandler.md) - -## SystemEvent.addHandler() method - -Adds an handler for the event. - -Signature: - -```typescript -addHandler(handler: () => void): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| handler | () => void | | - -Returns: - -`void` - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md deleted file mode 100644 index 47baad77696..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md +++ /dev/null @@ -1,21 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [SystemEvent](./api-documenter-test.systemevent.md) - -## SystemEvent class - -A class used to exposed events. - - -Signature: - -```typescript -export declare class SystemEvent -``` - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [addHandler(handler)](./api-documenter-test.systemevent.addhandler.md) | | Adds an handler for the event. | - diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md deleted file mode 100644 index 5d36ebd5e69..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.typealias.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [TypeAlias](./api-documenter-test.typealias.md) - -## TypeAlias type - - -Signature: - -```typescript -export declare type TypeAlias = number; -``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.yamlreferenceuniquenesstest.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.yamlreferenceuniquenesstest.md deleted file mode 100644 index 36a15dd3652..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.yamlreferenceuniquenesstest.md +++ /dev/null @@ -1,16 +0,0 @@ - - -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [yamlReferenceUniquenessTest](./api-documenter-test.yamlreferenceuniquenesstest.md) - -## yamlReferenceUniquenessTest() function - - -Signature: - -```typescript -export declare function yamlReferenceUniquenessTest(): IDocInterface1; -``` -Returns: - -`IDocInterface1` - diff --git a/build-tests/api-documenter-test/etc/markdown/index.md b/build-tests/api-documenter-test/etc/markdown/index.md deleted file mode 100644 index 7688a1d4bb3..00000000000 --- a/build-tests/api-documenter-test/etc/markdown/index.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) - -## API Reference - -## Packages - -| Package | Description | -| --- | --- | -| [api-documenter-test](./api-documenter-test.md) | api-extractor-test-05This project tests various documentation generation scenarios and doc comment syntaxes. | - diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml deleted file mode 100644 index f4fff664512..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test.yml +++ /dev/null @@ -1,155 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: api-documenter-test! - summary: |- - api-extractor-test-05 - - This project tests various documentation generation scenarios and doc comment syntaxes. - name: api-documenter-test - fullName: api-documenter-test - langs: - - typeScript - type: package - children: - - 'api-documenter-test!constVariable:var' - - 'api-documenter-test!DocBaseClass:class' - - 'api-documenter-test!DocClass1:class' - - 'api-documenter-test!DocClassInterfaceMerge:class' - - 'api-documenter-test!DocClassInterfaceMerge:interface' - - 'api-documenter-test!DocEnum:enum' - - 'api-documenter-test!EcmaSmbols:namespace' - - 'api-documenter-test!ExampleTypeAlias:type' - - 'api-documenter-test!Generic:class' - - 'api-documenter-test!GenericTypeAlias:type' - - 'api-documenter-test!globalFunction:function(1)' - - '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!OuterNamespace:namespace' - - 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - - 'api-documenter-test!SystemEvent:class' - - 'api-documenter-test!TypeAlias:type' - - 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' - - uid: 'api-documenter-test!constVariable:var' - summary: An exported variable declaration. - name: constVariable - fullName: constVariable - langs: - - typeScript - type: variable - syntax: - content: 'constVariable: number' - return: - type: - - number - - uid: 'api-documenter-test!ExampleTypeAlias:type' - summary: A type alias - name: ExampleTypeAlias - fullName: ExampleTypeAlias - langs: - - typeScript - type: typealias - syntax: - content: export declare type ExampleTypeAlias = Promise; - return: - type: - - 'api-documenter-test!ExampleTypeAlias~0:complex' - - uid: 'api-documenter-test!GenericTypeAlias:type' - name: GenericTypeAlias - fullName: GenericTypeAlias - langs: - - typeScript - type: typealias - syntax: - content: 'export declare type GenericTypeAlias = T[];' - typeParameters: - - id: T - return: - type: - - 'T[]' - - uid: 'api-documenter-test!globalFunction:function(1)' - summary: An exported function - name: globalFunction(x) - fullName: globalFunction(x) - langs: - - typeScript - type: function - syntax: - content: 'export declare function globalFunction(x: number): number;' - return: - type: - - number - description: '' - parameters: - - id: x - description: '' - type: - - number - - uid: 'api-documenter-test!TypeAlias:type' - name: TypeAlias - fullName: TypeAlias - langs: - - typeScript - type: typealias - syntax: - content: export declare type TypeAlias = number; - return: - type: - - number - - uid: 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' - name: yamlReferenceUniquenessTest() - fullName: yamlReferenceUniquenessTest() - langs: - - typeScript - type: function - syntax: - content: 'export declare function yamlReferenceUniquenessTest(): IDocInterface1;' - return: - type: - - 'api-documenter-test!IDocInterface1:interface' - description: '' -references: - - uid: 'api-documenter-test!DocBaseClass:class' - name: DocBaseClass - - uid: 'api-documenter-test!DocClass1:class' - name: DocClass1 - - uid: 'api-documenter-test!DocClassInterfaceMerge:class' - name: DocClassInterfaceMerge - - uid: 'api-documenter-test!DocClassInterfaceMerge:interface' - name: DocClassInterfaceMerge - - uid: 'api-documenter-test!DocEnum:enum' - name: DocEnum - - uid: 'api-documenter-test!EcmaSmbols:namespace' - name: EcmaSmbols - - uid: 'api-documenter-test!ExampleTypeAlias~0:complex' - name: Promise - fullName: Promise - spec.typeScript: - - uid: '!Promise:interface' - name: Promise - fullName: Promise - - name: - fullName: - - uid: 'api-documenter-test!Generic:class' - name: Generic - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - - uid: 'api-documenter-test!IDocInterface3:interface' - name: IDocInterface3 - - uid: 'api-documenter-test!IDocInterface4:interface' - name: IDocInterface4 - - uid: 'api-documenter-test!IDocInterface5:interface' - name: IDocInterface5 - - uid: 'api-documenter-test!IDocInterface6:interface' - name: IDocInterface6 - - uid: 'api-documenter-test!OuterNamespace:namespace' - name: OuterNamespace - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - name: OuterNamespace.InnerNamespace - - uid: 'api-documenter-test!SystemEvent:class' - name: SystemEvent diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docbaseclass.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docbaseclass.yml deleted file mode 100644 index 719ce11403b..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docbaseclass.yml +++ /dev/null @@ -1,36 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!DocBaseClass:class' - summary: Example base class - name: DocBaseClass - fullName: DocBaseClass - langs: - - typeScript - type: class - package: api-documenter-test! - children: - - 'api-documenter-test!DocBaseClass:constructor(1)' - - 'api-documenter-test!DocBaseClass:constructor(2)' - - uid: 'api-documenter-test!DocBaseClass:constructor(1)' - summary: The simple constructor for `DocBaseClass` - name: (constructor)() - fullName: (constructor)() - langs: - - typeScript - type: constructor - syntax: - content: constructor(); - - uid: 'api-documenter-test!DocBaseClass:constructor(2)' - summary: The overloaded constructor for `DocBaseClass` - name: (constructor)(x) - fullName: (constructor)(x) - langs: - - typeScript - type: constructor - syntax: - content: 'constructor(x: number);' - parameters: - - id: x - description: '' - type: - - number diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml deleted file mode 100644 index d5d8e4b0031..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml +++ /dev/null @@ -1,216 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!DocClass1:class' - summary: This is an example class. - remarks: >- - [Link to overload 1](xref:api-documenter-test!DocClass1#exampleFunction:member(1)) - - - [Link to overload 2](xref:api-documenter-test!DocClass1#exampleFunction:member(2)) - - - - The constructor for this class is marked as internal. Third-party code should not call the constructor directly or - create subclasses that extend the `DocClass1` class. - name: DocClass1 - fullName: DocClass1 - langs: - - typeScript - type: class - extends: - - 'api-documenter-test!DocBaseClass:class' - inheritance: - - type: 'api-documenter-test!DocBaseClass:class' - implements: - - 'api-documenter-test!IDocInterface1:interface' - - 'api-documenter-test!IDocInterface2:interface' - package: api-documenter-test! - children: - - 'api-documenter-test!DocClass1#deprecatedExample:member(1)' - - 'api-documenter-test!DocClass1#exampleFunction:member(1)' - - 'api-documenter-test!DocClass1#exampleFunction:member(2)' - - 'api-documenter-test!DocClass1#interestingEdgeCases:member(1)' - - 'api-documenter-test!DocClass1#malformedEvent:member' - - 'api-documenter-test!DocClass1#modifiedEvent:member' - - 'api-documenter-test!DocClass1#readonlyProperty:member' - - 'api-documenter-test!DocClass1#regularProperty:member' - - 'api-documenter-test!DocClass1.sumWithExample:member(1)' - - 'api-documenter-test!DocClass1#tableExample:member(1)' - - 'api-documenter-test!DocClass1#writeableProperty:member' - - uid: 'api-documenter-test!DocClass1#deprecatedExample:member(1)' - deprecated: - content: Use `otherThing()` instead. - name: deprecatedExample() - fullName: deprecatedExample() - langs: - - typeScript - type: method - syntax: - content: 'deprecatedExample(): void;' - return: - type: - - void - description: '' - - uid: 'api-documenter-test!DocClass1#exampleFunction:member(1)' - summary: This is an overloaded function. - name: 'exampleFunction(a, b)' - fullName: 'exampleFunction(a, b)' - langs: - - typeScript - type: method - syntax: - content: 'exampleFunction(a: string, b: string): string;' - return: - type: - - string - description: '' - parameters: - - id: a - description: the first string - type: - - string - - id: b - description: the second string - type: - - string - - uid: 'api-documenter-test!DocClass1#exampleFunction:member(2)' - summary: This is also an overloaded function. - name: exampleFunction(x) - fullName: exampleFunction(x) - langs: - - typeScript - type: method - syntax: - content: 'exampleFunction(x: number): number;' - return: - type: - - number - description: '' - parameters: - - id: x - description: the number - type: - - number - - uid: 'api-documenter-test!DocClass1#interestingEdgeCases:member(1)' - summary: |- - Example: "{ \\"maxItemsToShow\\": 123 }" - - The regular expression used to validate the constraints is /^\[a-zA-Z0-9\\-\_\]+$/ - name: interestingEdgeCases() - fullName: interestingEdgeCases() - langs: - - typeScript - type: method - syntax: - content: 'interestingEdgeCases(): void;' - return: - type: - - void - description: '' - - uid: 'api-documenter-test!DocClass1#malformedEvent:member' - summary: This event should have been marked as readonly. - name: malformedEvent - fullName: malformedEvent - langs: - - typeScript - type: event - syntax: - content: 'malformedEvent: SystemEvent;' - return: - type: - - 'api-documenter-test!SystemEvent:class' - - uid: 'api-documenter-test!DocClass1#modifiedEvent:member' - summary: This event is fired whenever the object is modified. - name: modifiedEvent - fullName: modifiedEvent - langs: - - typeScript - type: event - syntax: - content: 'readonly modifiedEvent: SystemEvent;' - return: - type: - - 'api-documenter-test!SystemEvent:class' - - uid: 'api-documenter-test!DocClass1#readonlyProperty:member' - name: readonlyProperty - fullName: readonlyProperty - langs: - - typeScript - type: property - syntax: - content: 'get readonlyProperty(): string;' - return: - type: - - string - - uid: 'api-documenter-test!DocClass1#regularProperty:member' - summary: This is a regular property that happens to use the SystemEvent type. - name: regularProperty - fullName: regularProperty - langs: - - typeScript - type: property - syntax: - content: 'regularProperty: SystemEvent;' - return: - type: - - 'api-documenter-test!SystemEvent:class' - - uid: 'api-documenter-test!DocClass1.sumWithExample:member(1)' - summary: Returns the sum of two numbers. - remarks: This illustrates usage of the `@example` block tag. - name: 'sumWithExample(x, y)' - fullName: 'sumWithExample(x, y)' - langs: - - typeScript - type: method - syntax: - content: 'static sumWithExample(x: number, y: number): number;' - return: - type: - - number - description: the sum of the two numbers - parameters: - - id: x - description: the first number to add - type: - - number - - id: 'y' - description: the second number to add - type: - - number - - uid: 'api-documenter-test!DocClass1#tableExample:member(1)' - summary: 'An example with tables:' - remarks:
John Doe
- name: tableExample() - fullName: tableExample() - langs: - - typeScript - type: method - syntax: - content: 'tableExample(): void;' - return: - type: - - void - description: '' - - uid: 'api-documenter-test!DocClass1#writeableProperty:member' - name: writeableProperty - fullName: writeableProperty - langs: - - typeScript - type: property - syntax: - content: |- - get writeableProperty(): string; - - set writeableProperty(value: string); - return: - type: - - string -references: - - uid: 'api-documenter-test!DocBaseClass:class' - name: DocBaseClass - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - - uid: 'api-documenter-test!SystemEvent:class' - name: SystemEvent diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-class.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-class.yml deleted file mode 100644 index 8185a4946ff..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-class.yml +++ /dev/null @@ -1,10 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!DocClassInterfaceMerge:class' - summary: Class that merges with interface - name: DocClassInterfaceMerge - fullName: DocClassInterfaceMerge - langs: - - typeScript - type: class - package: api-documenter-test! diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-interface.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-interface.yml deleted file mode 100644 index 7f02423093f..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclassinterfacemerge-interface.yml +++ /dev/null @@ -1,10 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!DocClassInterfaceMerge:interface' - summary: Interface that merges with class - name: DocClassInterfaceMerge - fullName: DocClassInterfaceMerge - langs: - - typeScript - type: interface - package: api-documenter-test! diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docenum.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docenum.yml deleted file mode 100644 index 43b2aa123b1..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docenum.yml +++ /dev/null @@ -1,38 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!DocEnum:enum' - summary: Docs for DocEnum - name: DocEnum - fullName: DocEnum - langs: - - typeScript - type: enum - package: api-documenter-test! - children: - - 'api-documenter-test!DocEnum.One:member' - - 'api-documenter-test!DocEnum.Two:member' - - 'api-documenter-test!DocEnum.Zero:member' - - uid: 'api-documenter-test!DocEnum.One:member' - summary: These are some docs for One - name: One - fullName: One - langs: - - typeScript - type: field - numericValue: '1' - - uid: 'api-documenter-test!DocEnum.Two:member' - summary: These are some docs for Two - name: Two - fullName: Two - langs: - - typeScript - type: field - numericValue: '2' - - uid: 'api-documenter-test!DocEnum.Zero:member' - summary: These are some docs for Zero - name: Zero - fullName: Zero - langs: - - typeScript - type: field - numericValue: '0' diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml deleted file mode 100644 index 1cef2ce3d4c..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/ecmasmbols.yml +++ /dev/null @@ -1,25 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!EcmaSmbols:namespace' - summary: A namespace containing an ECMAScript symbol - name: EcmaSmbols - fullName: EcmaSmbols - langs: - - typeScript - type: namespace - package: api-documenter-test! - children: - - 'api-documenter-test!EcmaSmbols.example:var' - - uid: 'api-documenter-test!EcmaSmbols.example:var' - summary: An ECMAScript symbol - name: example - fullName: EcmaSmbols.example - langs: - - typeScript - namespace: 'api-documenter-test!EcmaSmbols:namespace' - type: variable - syntax: - content: 'example: unique symbol' - return: - type: - - unique symbol diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/generic.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/generic.yml deleted file mode 100644 index ed71c77877b..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/generic.yml +++ /dev/null @@ -1,10 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!Generic:class' - summary: Generic class. - name: Generic - fullName: Generic - langs: - - typeScript - type: class - package: api-documenter-test! diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface1.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface1.yml deleted file mode 100644 index 46167bbe571..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface1.yml +++ /dev/null @@ -1,26 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - langs: - - typeScript - type: interface - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface1#regularProperty:member' - - uid: 'api-documenter-test!IDocInterface1#regularProperty:member' - summary: Does something - name: regularProperty - fullName: regularProperty - langs: - - typeScript - type: property - syntax: - content: 'regularProperty: SystemEvent;' - return: - type: - - 'api-documenter-test!SystemEvent:class' -references: - - uid: 'api-documenter-test!SystemEvent:class' - name: SystemEvent diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml deleted file mode 100644 index 654a3556910..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface2.yml +++ /dev/null @@ -1,32 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - fullName: IDocInterface2 - langs: - - typeScript - type: interface - extends: - - 'api-documenter-test!IDocInterface1:interface' - inheritance: - - type: 'api-documenter-test!IDocInterface1:interface' - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface2#deprecatedExample:member(1)' - - uid: 'api-documenter-test!IDocInterface2#deprecatedExample:member(1)' - deprecated: - content: Use `otherThing()` instead. - name: deprecatedExample() - fullName: deprecatedExample() - langs: - - typeScript - type: method - syntax: - content: 'deprecatedExample(): void;' - return: - type: - - void - description: '' -references: - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface3.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface3.yml deleted file mode 100644 index c9e9d0f7c82..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface3.yml +++ /dev/null @@ -1,50 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface3:interface' - summary: Some less common TypeScript declaration kinds. - name: IDocInterface3 - fullName: IDocInterface3 - langs: - - typeScript - type: interface - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface3#"[not.a.symbol]":member' - - 'api-documenter-test!IDocInterface3#[EcmaSmbols.example]:member' - - 'api-documenter-test!IDocInterface3#redundantQuotes:member' - - uid: 'api-documenter-test!IDocInterface3#"[not.a.symbol]":member' - summary: An identifier that does needs quotes. It misleadingly looks like an ECMAScript symbol. - name: '"[not.a.symbol]"' - fullName: '"[not.a.symbol]"' - langs: - - typeScript - type: property - syntax: - content: '"[not.a.symbol]": string;' - return: - type: - - string - - uid: 'api-documenter-test!IDocInterface3#[EcmaSmbols.example]:member' - summary: ECMAScript symbol - name: '[EcmaSmbols.example]' - fullName: '[EcmaSmbols.example]' - langs: - - typeScript - type: property - syntax: - content: '[EcmaSmbols.example]: string;' - return: - type: - - string - - uid: 'api-documenter-test!IDocInterface3#redundantQuotes:member' - summary: A quoted identifier with redundant quotes. - name: redundantQuotes - fullName: redundantQuotes - langs: - - typeScript - type: property - syntax: - content: '"redundantQuotes": string;' - return: - type: - - string diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface4.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface4.yml deleted file mode 100644 index 0f78d82db0a..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface4.yml +++ /dev/null @@ -1,79 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface4:interface' - summary: Type union in an interface. - name: IDocInterface4 - fullName: IDocInterface4 - langs: - - typeScript - type: interface - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface4#Context:member' - - 'api-documenter-test!IDocInterface4#generic:member' - - 'api-documenter-test!IDocInterface4#numberOrFunction:member' - - 'api-documenter-test!IDocInterface4#stringOrNumber:member' - - uid: 'api-documenter-test!IDocInterface4#Context:member' - summary: Test newline rendering when code blocks are used in tables - name: Context - fullName: Context - langs: - - typeScript - type: property - syntax: - content: |- - Context: ({ children }: { - children: string; - }) => boolean; - return: - type: - - |- - ({ children }: { - children: string; - }) => boolean - - uid: 'api-documenter-test!IDocInterface4#generic:member' - summary: make sure html entities are escaped in tables. - name: generic - fullName: generic - langs: - - typeScript - type: property - syntax: - content: 'generic: Generic;' - return: - type: - - 'api-documenter-test!IDocInterface4#generic~0:complex' - - uid: 'api-documenter-test!IDocInterface4#numberOrFunction:member' - summary: a union type with a function - name: numberOrFunction - fullName: numberOrFunction - langs: - - typeScript - type: property - syntax: - content: 'numberOrFunction: number | (() => number);' - return: - type: - - number | (() => number) - - uid: 'api-documenter-test!IDocInterface4#stringOrNumber:member' - summary: a union type - name: stringOrNumber - fullName: stringOrNumber - langs: - - typeScript - type: property - syntax: - content: 'stringOrNumber: string | number;' - return: - type: - - string | number -references: - - uid: 'api-documenter-test!IDocInterface4#generic~0:complex' - name: Generic - fullName: Generic - spec.typeScript: - - uid: 'api-documenter-test!Generic:class' - name: Generic - fullName: Generic - - name: - fullName: diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface5.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface5.yml deleted file mode 100644 index 13babd39b21..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface5.yml +++ /dev/null @@ -1,24 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface5:interface' - summary: Interface without inline tag to test custom TOC - name: IDocInterface5 - fullName: IDocInterface5 - langs: - - typeScript - type: interface - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface5#regularProperty:member' - - uid: 'api-documenter-test!IDocInterface5#regularProperty:member' - summary: Property of type string that does something - name: regularProperty - fullName: regularProperty - langs: - - typeScript - type: property - syntax: - content: 'regularProperty: string;' - return: - type: - - string diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface6.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface6.yml deleted file mode 100644 index c52c45fcee5..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/idocinterface6.yml +++ /dev/null @@ -1,168 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!IDocInterface6:interface' - summary: Interface without inline tag to test custom TOC with injection - name: IDocInterface6 - fullName: IDocInterface6 - langs: - - typeScript - type: interface - package: api-documenter-test! - children: - - 'api-documenter-test!IDocInterface6#arrayProperty:member' - - 'api-documenter-test!IDocInterface6#genericReferenceMethod:member(1)' - - 'api-documenter-test!IDocInterface6#intersectionProperty:member' - - 'api-documenter-test!IDocInterface6#regularProperty:member' - - 'api-documenter-test!IDocInterface6#tupleProperty:member' - - 'api-documenter-test!IDocInterface6#typeReferenceProperty:member' - - 'api-documenter-test!IDocInterface6#unionProperty:member' - - uid: 'api-documenter-test!IDocInterface6#arrayProperty:member' - name: arrayProperty - fullName: arrayProperty - langs: - - typeScript - type: property - syntax: - content: 'arrayProperty: IDocInterface1[];' - return: - type: - - 'api-documenter-test!IDocInterface6#arrayProperty~0:complex' - - uid: 'api-documenter-test!IDocInterface6#genericReferenceMethod:member(1)' - name: genericReferenceMethod(x) - fullName: genericReferenceMethod(x) - langs: - - typeScript - type: method - syntax: - content: 'genericReferenceMethod(x: T): T;' - return: - type: - - T - description: '' - parameters: - - id: x - description: '' - type: - - T - typeParameters: - - id: T - - uid: 'api-documenter-test!IDocInterface6#intersectionProperty:member' - name: intersectionProperty - fullName: intersectionProperty - langs: - - typeScript - type: property - syntax: - content: 'intersectionProperty: IDocInterface1 & IDocInterface2;' - return: - type: - - 'api-documenter-test!IDocInterface6#intersectionProperty~0:complex' - - uid: 'api-documenter-test!IDocInterface6#regularProperty:member' - summary: Property of type number that does something - name: regularProperty - fullName: regularProperty - langs: - - typeScript - type: property - syntax: - content: 'regularProperty: number;' - return: - type: - - number - - uid: 'api-documenter-test!IDocInterface6#tupleProperty:member' - name: tupleProperty - fullName: tupleProperty - langs: - - typeScript - type: property - syntax: - content: 'tupleProperty: [IDocInterface1, IDocInterface2];' - return: - type: - - 'api-documenter-test!IDocInterface6#tupleProperty~0:complex' - - uid: 'api-documenter-test!IDocInterface6#typeReferenceProperty:member' - name: typeReferenceProperty - fullName: typeReferenceProperty - langs: - - typeScript - type: property - syntax: - content: 'typeReferenceProperty: Generic;' - return: - type: - - 'api-documenter-test!IDocInterface6#typeReferenceProperty~0:complex' - - uid: 'api-documenter-test!IDocInterface6#unionProperty:member' - name: unionProperty - fullName: unionProperty - langs: - - typeScript - type: property - syntax: - content: 'unionProperty: IDocInterface1 | IDocInterface2;' - return: - type: - - 'api-documenter-test!IDocInterface6#unionProperty~0:complex' -references: - - uid: 'api-documenter-test!IDocInterface6#arrayProperty~0:complex' - name: 'IDocInterface1[]' - fullName: 'IDocInterface1[]' - spec.typeScript: - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - - name: '[]' - fullName: '[]' - - uid: 'api-documenter-test!IDocInterface6#intersectionProperty~0:complex' - name: IDocInterface1 & IDocInterface2 - fullName: IDocInterface1 & IDocInterface2 - spec.typeScript: - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - - name: ' & ' - fullName: ' & ' - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - fullName: IDocInterface2 - - uid: 'api-documenter-test!IDocInterface6#tupleProperty~0:complex' - name: '[IDocInterface1, IDocInterface2]' - fullName: '[IDocInterface1, IDocInterface2]' - spec.typeScript: - - name: '[' - fullName: '[' - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - - name: ', ' - fullName: ', ' - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - fullName: IDocInterface2 - - name: ']' - fullName: ']' - - uid: 'api-documenter-test!IDocInterface6#typeReferenceProperty~0:complex' - name: Generic - fullName: Generic - spec.typeScript: - - uid: 'api-documenter-test!Generic:class' - name: Generic - fullName: Generic - - name: < - fullName: < - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - - name: '>' - fullName: '>' - - uid: 'api-documenter-test!IDocInterface6#unionProperty~0:complex' - name: IDocInterface1 | IDocInterface2 - fullName: IDocInterface1 | IDocInterface2 - spec.typeScript: - - uid: 'api-documenter-test!IDocInterface1:interface' - name: IDocInterface1 - fullName: IDocInterface1 - - name: ' | ' - fullName: ' | ' - - uid: 'api-documenter-test!IDocInterface2:interface' - name: IDocInterface2 - fullName: IDocInterface2 diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml deleted file mode 100644 index ccfa0c9e5f6..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.innernamespace.yml +++ /dev/null @@ -1,31 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - summary: A nested namespace - name: OuterNamespace.InnerNamespace - fullName: OuterNamespace.InnerNamespace - langs: - - typeScript - type: namespace - package: api-documenter-test! - children: - - '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' - type: function - syntax: - content: 'function nestedFunction(x: number): number;' - return: - type: - - number - description: '' - parameters: - - id: x - description: '' - type: - - number diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml deleted file mode 100644 index 44145cff45b..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/outernamespace.yml +++ /dev/null @@ -1,25 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!OuterNamespace:namespace' - summary: A top-level namespace - name: OuterNamespace - fullName: OuterNamespace - langs: - - typeScript - type: namespace - package: api-documenter-test! - children: - - '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' - type: variable - syntax: - content: 'nestedVariable: boolean' - return: - type: - - boolean diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/systemevent.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/systemevent.yml deleted file mode 100644 index c44dad0913d..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/systemevent.yml +++ /dev/null @@ -1,30 +0,0 @@ -### YamlMime:UniversalReference -items: - - uid: 'api-documenter-test!SystemEvent:class' - summary: A class used to exposed events. - name: SystemEvent - fullName: SystemEvent - langs: - - typeScript - type: class - package: api-documenter-test! - children: - - 'api-documenter-test!SystemEvent#addHandler:member(1)' - - uid: 'api-documenter-test!SystemEvent#addHandler:member(1)' - summary: Adds an handler for the event. - name: addHandler(handler) - fullName: addHandler(handler) - langs: - - typeScript - type: method - syntax: - content: 'addHandler(handler: () => void): void;' - return: - type: - - void - description: '' - parameters: - - id: handler - description: '' - type: - - () => void diff --git a/build-tests/api-documenter-test/etc/yaml/toc.yml b/build-tests/api-documenter-test/etc/yaml/toc.yml deleted file mode 100644 index 2c391ee5940..00000000000 --- a/build-tests/api-documenter-test/etc/yaml/toc.yml +++ /dev/null @@ -1,57 +0,0 @@ -items: - - name: Test api-documenter - href: ~/homepage/homepage.md - - name: Test Sample for AD - href: api-documenter-test - extended: true - items: - - name: Classes - items: - - name: DocBaseClass - items: - - name: DocBaseClass - uid: 'api-documenter-test!DocBaseClass:class' - - name: IDocInterface1 - uid: 'api-documenter-test!IDocInterface1:interface' - - name: IDocInterface2 - uid: 'api-documenter-test!IDocInterface2:interface' - - name: DocClass1 - items: - - name: DocClass1 - uid: 'api-documenter-test!DocClass1:class' - - name: IDocInterface3 - uid: 'api-documenter-test!IDocInterface3:interface' - - name: IDocInterface4 - uid: 'api-documenter-test!IDocInterface4:interface' - - name: Interfaces - items: - - name: Interface5 - items: - - name: IDocInterface5 - uid: 'api-documenter-test!IDocInterface5:interface' - - name: Interface6 - items: - - name: InjectedCustomInterface - uid: customUid - - name: IDocInterface6 - uid: 'api-documenter-test!IDocInterface6:interface' - - name: References - items: - - name: InjectedCustomItem - uid: customUrl - - name: DocClassInterfaceMerge (Class) - uid: 'api-documenter-test!DocClassInterfaceMerge:class' - - name: DocClassInterfaceMerge (Interface) - uid: 'api-documenter-test!DocClassInterfaceMerge:interface' - - name: DocEnum - uid: 'api-documenter-test!DocEnum:enum' - - name: EcmaSmbols - uid: 'api-documenter-test!EcmaSmbols:namespace' - - name: Generic - uid: 'api-documenter-test!Generic:class' - - name: OuterNamespace - uid: 'api-documenter-test!OuterNamespace:namespace' - - name: OuterNamespace.InnerNamespace - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' - - name: SystemEvent - uid: 'api-documenter-test!SystemEvent:class' diff --git a/build-tests/api-documenter-test/package.json b/build-tests/api-documenter-test/package.json index b78f23ce14a..934d4ad7302 100644 --- a/build-tests/api-documenter-test/package.json +++ b/build-tests/api-documenter-test/package.json @@ -6,14 +6,17 @@ "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "test": "heft test", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@microsoft/api-documenter": "7.7.14", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "@microsoft/api-documenter": "workspace:*", + "@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 new file mode 100644 index 00000000000..db9e37f4865 --- /dev/null +++ b/build-tests/api-documenter-test/src/AbstractClass.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. + +/** + * Some abstract class with abstract members. + * @public + */ +export abstract class AbstractClass { + /** 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 new file mode 100644 index 00000000000..affcfcd961d --- /dev/null +++ b/build-tests/api-documenter-test/src/DecoratorExample.ts @@ -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. + +// 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) {}; +} + +/** @public */ +export class DecoratorExample { + /** + * The date when the record was created. + * + * @remarks + * Here is a longer description of the property. + * + * @decorator `@jsonSerialized` + * @decorator `@jsonFormat('mm/dd/yy')` + */ + @jsonSerialized + @jsonFormat('mm/dd/yy') + public creationDate: Date; +} diff --git a/build-tests/api-documenter-test/src/DocClass1.ts b/build-tests/api-documenter-test/src/DocClass1.ts index ea726712368..fb343b1e1aa 100644 --- a/build-tests/api-documenter-test/src/DocClass1.ts +++ b/build-tests/api-documenter-test/src/DocClass1.ts @@ -1,15 +1,18 @@ +// 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 * {@docCategory SystemEvent} + * + * @myCustomTag */ export class SystemEvent { /** * Adds an handler for the event. */ - public addHandler(handler: () => void): void { - } + public addHandler(handler: () => void): void {} } /** @@ -28,8 +31,7 @@ export class DocBaseClass { */ public constructor(x: number); - public constructor(x?: number) { - } + public constructor(x?: number) {} } /** @@ -58,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'); } /** @@ -80,7 +83,7 @@ export interface IDocInterface3 { /** * Construct signature */ - new(): IDocInterface1; + new (): IDocInterface1; /** * Indexer @@ -91,24 +94,27 @@ export interface IDocInterface3 { /** * ECMAScript symbol */ - [EcmaSmbols.example]: string; + [EcmaSymbols.example]: string; /** * A quoted identifier with redundant quotes. */ + // prettier-ignore "redundantQuotes": string; /** - * An identifier that does needs quotes. It misleadingly looks like an ECMAScript symbol. + * An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol. */ - "[not.a.symbol]": string + // prettier-ignore + "[not.a.symbol]": string; } /** * Generic class. * @public */ -export class Generic { } +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class Generic {} /** * Type union in an interface. @@ -136,6 +142,20 @@ export interface IDocInterface4 { Context: ({ children }: { children: string }) => boolean; } +/** + * 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 {} + /** * This is an example class. * @@ -148,6 +168,33 @@ export interface IDocInterface4 { * {@docCategory DocClass1} */ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInterface2 { + /** + * Some protected property. + */ + protected protectedProperty: string; + + /** + * Some property with multiple modifiers. + */ + 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 @@ -166,18 +213,26 @@ 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 */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility exampleFunction(x: number): number; public exampleFunction(x: number | string, y?: string): string | number { return x; } + /** + * This is a function with an optional parameter. + * @param x - the number + */ + public optionalParamFunction(x?: number): void {} + public get readonlyProperty(): string { return 'hello'; } @@ -185,25 +240,13 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter public get writeableProperty(): string { return 'hello'; } - public set writeableProperty(value: string) { - } - - /** - * This event is fired whenever the object is modified. - * @eventProperty - */ - public readonly modifiedEvent: SystemEvent; + public set writeableProperty(value: string) {} /** - * This event should have been marked as readonly. - * @eventProperty + * API Extractor will surface an `ae-missing-getter` finding for this property. */ - public malformedEvent: SystemEvent; - - /** - * This is a regular property that happens to use the SystemEvent type. - */ - public regularProperty: SystemEvent; + // eslint-disable-next-line accessor-pairs + public set writeonlyProperty(value: string) {} /** * An example with tables: @@ -215,22 +258,21 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter * * */ - tableExample(): void { - } + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + tableExample(): void {} /** * Example: "\{ \\"maxItemsToShow\\": 123 \}" * * The regular expression used to validate the constraints is /^[a-zA-Z0-9\\-_]+$/ */ - interestingEdgeCases(): void { - } + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + interestingEdgeCases(): void {} /** * @deprecated Use `otherThing()` instead. */ - public deprecatedExample(): void { - } + public deprecatedExample(): void {} /** * Returns the sum of two numbers. @@ -258,6 +300,13 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter public static sumWithExample(x: number, y: number): number { return x + y; } + + /** + * 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) {} } /** @@ -294,17 +343,39 @@ export interface IDocInterface6 { typeReferenceProperty: Generic; genericReferenceMethod(x: T): T; } +/** + * Interface for testing optional properties + * @public + */ +export interface IDocInterface7 { + /** Description of optionalField */ + optionalField?: boolean; + + // Missing description + optionalUndocumentedField?: boolean; + + /** Description of optionalReadonlyField */ + readonly optionalReadonlyField?: boolean; + + /** Description of optionalMember */ + optionalMember?(); +} /** * Class that merges with interface + * + * @remarks + * {@link (DocClassInterfaceMerge:class)|Link to class} + * + * {@link (DocClassInterfaceMerge:interface)|Link to interface} + * * @public */ -export class DocClassInterfaceMerge { -} +export class DocClassInterfaceMerge {} /** * Interface that merges with class * @public */ -export interface DocClassInterfaceMerge { -} \ No newline at end of file +// 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 7428c569f15..63c8d2c2f3c 100644 --- a/build-tests/api-documenter-test/src/DocEnums.ts +++ b/build-tests/api-documenter-test/src/DocEnums.ts @@ -18,7 +18,45 @@ export enum DocEnum { One = 1, /** - * These are some docs for Two + * These are some docs for Two. + * + * {@link DocEnum.One} is a direct link to another enum member. */ Two = DocEnum.One + 1 } + +/** + * Enum that merges with namespace + * + * @remarks + * {@link (DocEnumNamespaceMerge:enum)|Link to enum} + * + * {@link (DocEnumNamespaceMerge:namespace)|Link to namespace} + * + * {@link (DocEnumNamespaceMerge:namespace).exampleFunction|Link to function inside namespace} + * + * @public + */ +export enum DocEnumNamespaceMerge { + /** + * These are some docs for Left + */ + Left = 0, + + /** + * These are some docs for Right + */ + Right = 1 +} + +/** + * 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. + */ + export function exampleFunction(): void {} +} diff --git a/build-tests/api-documenter-test/src/index.ts b/build-tests/api-documenter-test/src/index.ts index eb77c9fec79..710adc3c398 100644 --- a/build-tests/api-documenter-test/src/index.ts +++ b/build-tests/api-documenter-test/src/index.ts @@ -12,7 +12,11 @@ export * from './DocClass1'; export * from './DocEnums'; -import { IDocInterface1 } from './DocClass1'; +import type { IDocInterface1, IDocInterface3, SystemEvent } from './DocClass1'; + +export { DecoratorExample } from './DecoratorExample'; + +export { AbstractClass } from './AbstractClass'; /** * A type alias @@ -20,6 +24,18 @@ import { IDocInterface1 } from './DocClass1'; */ export type ExampleTypeAlias = Promise; +/** + * A type alias that references multiple other types. + * @public + */ +export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; + +/** + * A type alias that has duplicate references. + * @public + */ +export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent; + /** * An exported variable declaration. * @public @@ -27,21 +43,27 @@ export type ExampleTypeAlias = Promise; export const constVariable: number = 123; /** - * An exported function + * An exported function with hyperlinked parameters and return value. + * + * @param x - an API item that should get hyperlinked + * @param y - a system type that should NOT get hyperlinked + * @returns an interface that should get hyperlinked * @public */ -export function globalFunction(x: number): number { - return x; +export function exampleFunction(x: ExampleTypeAlias, y: number): IDocInterface1 { + return undefined as unknown as 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 @@ -54,6 +76,7 @@ export namespace OuterNamespace { /** * A variable exported from within a namespace. */ + // eslint-disable-next-line prefer-const export let nestedVariable: boolean = false; } @@ -70,4 +93,4 @@ export type TypeAlias = number; /** * @public */ -export type GenericTypeAlias = T[]; \ No newline at end of file +export type GenericTypeAlias = T[]; 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 new file mode 100644 index 00000000000..fabda2846fd --- /dev/null +++ b/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,4736 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`api-documenter YAML: itemContents 1`] = ` +Object { + "/api-documenter-test.yml": "### YamlMime:TSPackage +uid: api-documenter-test! +name: api-documenter-test +type: package +summary: |- + api-extractor-test-05 + + 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 +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 +enums: + - 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 +functions: + - 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: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'export declare function exampleFunction(x: ExampleTypeAlias, y: number): IDocInterface1;' + parameters: + - id: x + description: an API item that should get hyperlinked + type: + - id: 'y' + description: a system type that should NOT get hyperlinked + type: number + return: + type: + description: an interface that should get hyperlinked + - name: yamlReferenceUniquenessTest() + uid: api-documenter-test!yamlReferenceUniquenessTest:function(1) + package: api-documenter-test! + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'export declare function yamlReferenceUniquenessTest(): IDocInterface1;' + return: + type: + description: '' +", + "/api-documenter-test/abstractclass.yml": "### YamlMime:TSType +name: AbstractClass +uid: api-documenter-test!AbstractClass:class +package: api-documenter-test! +fullName: AbstractClass +summary: Some abstract class with abstract members. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: class +properties: + - name: property + uid: api-documenter-test!AbstractClass#property:member + package: api-documenter-test! + fullName: property + summary: Some abstract property. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'protected abstract property: number;' + return: + type: number +methods: + - name: method() + uid: api-documenter-test!AbstractClass#method:member(1) + package: api-documenter-test! + fullName: method() + summary: Some abstract method. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'abstract method(): void;' + return: + type: void + description: '' +", + "/api-documenter-test/constraint.yml": "### YamlMime:TSType +name: Constraint +uid: api-documenter-test!Constraint:interface +package: api-documenter-test! +fullName: Constraint +summary: Type parameter constraint used by test case below. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +", + "/api-documenter-test/decoratorexample.yml": "### YamlMime:TSType +name: DecoratorExample +uid: api-documenter-test!DecoratorExample:class +package: api-documenter-test! +fullName: DecoratorExample +summary: '' +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: class +properties: + - name: creationDate + uid: api-documenter-test!DecoratorExample#creationDate:member + package: api-documenter-test! + fullName: creationDate + summary: The date when the record was created. + remarks: Here is a longer description of the property. + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'creationDate: Date;' + return: + type: Date +", + "/api-documenter-test/defaulttype.yml": "### YamlMime:TSType +name: DefaultType +uid: api-documenter-test!DefaultType:interface +package: api-documenter-test! +fullName: DefaultType +summary: Type parameter default type used by test case below. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +", + "/api-documenter-test/docbaseclass.yml": "### YamlMime:TSType +name: DocBaseClass +uid: api-documenter-test!DocBaseClass:class +package: api-documenter-test! +fullName: DocBaseClass +summary: Example base class +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: class +constructors: + - name: (constructor)() + uid: api-documenter-test!DocBaseClass:constructor(1) + package: api-documenter-test! + fullName: (constructor)() + summary: The simple constructor for \`DocBaseClass\` + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: constructor(); + - name: (constructor)(x) + uid: api-documenter-test!DocBaseClass:constructor(2) + package: api-documenter-test! + fullName: (constructor)(x) + summary: The overloaded constructor for \`DocBaseClass\` + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'constructor(x: number);' + parameters: + - id: x + description: '' + type: number +", + "/api-documenter-test/docclass1.yml": "### YamlMime:TSType +name: DocClass1 +uid: api-documenter-test!DocClass1:class +package: api-documenter-test! +fullName: DocClass1 +summary: This is an example class. +remarks: >- + [Link to overload 1](xref:api-documenter-test!DocClass1%23exampleFunction:member(1)) + + + [Link to overload 2](xref:api-documenter-test!DocClass1%23exampleFunction:member(2)) + + + + The constructor for this class is marked as internal. Third-party code should not call the constructor directly or + create subclasses that extend the \`DocClass1\` class. +example: [] +isPreview: false +isDeprecated: false +type: class +properties: + - name: multipleModifiersProperty + uid: api-documenter-test!DocClass1.multipleModifiersProperty:member + package: api-documenter-test! + fullName: multipleModifiersProperty + summary: Some property with multiple modifiers. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'protected static readonly multipleModifiersProperty: boolean;' + return: + type: boolean + - name: protectedProperty + uid: api-documenter-test!DocClass1#protectedProperty:member + package: api-documenter-test! + fullName: protectedProperty + summary: Some protected property. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'protected protectedProperty: string;' + return: + type: string + - name: readonlyProperty + uid: api-documenter-test!DocClass1#readonlyProperty:member + package: api-documenter-test! + fullName: readonlyProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'get readonlyProperty(): string;' + return: + type: string + - name: regularProperty + 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. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'regularProperty: SystemEvent;' + return: + type: + - name: writeableProperty + uid: api-documenter-test!DocClass1#writeableProperty:member + package: api-documenter-test! + fullName: writeableProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: |- + get writeableProperty(): string; + + set writeableProperty(value: string); + return: + type: string + - name: writeonlyProperty + 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. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'set writeonlyProperty(value: string);' + return: + type: string +methods: + - name: deprecatedExample() + uid: api-documenter-test!DocClass1#deprecatedExample:member(1) + package: api-documenter-test! + fullName: deprecatedExample() + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: true + customDeprecatedMessage: Use \`otherThing()\` instead. + syntax: + content: 'deprecatedExample(): void;' + return: + type: void + description: '' + - name: exampleFunction(a, b) + uid: api-documenter-test!DocClass1#exampleFunction:member(1) + package: api-documenter-test! + fullName: exampleFunction(a, b) + summary: This is an overloaded function. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'exampleFunction(a: string, b: string): string;' + parameters: + - id: a + description: the first string + type: string + - id: b + description: the second string + type: string + return: + type: string + description: '' + - name: exampleFunction(x) + uid: api-documenter-test!DocClass1#exampleFunction:member(2) + package: api-documenter-test! + fullName: exampleFunction(x) + summary: This is also an overloaded function. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'exampleFunction(x: number): number;' + parameters: + - id: x + description: the number + type: number + return: + type: number + description: '' + - name: genericWithConstraintAndDefault(x) + 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. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'genericWithConstraintAndDefault(x: T): void;' + parameters: + - id: x + description: some generic parameter. + type: T + return: + type: void + description: '' + - name: interestingEdgeCases() + uid: api-documenter-test!DocClass1#interestingEdgeCases:member(1) + package: api-documenter-test! + fullName: interestingEdgeCases() + summary: |- + Example: \\"{ \\\\\\\\\\"maxItemsToShow\\\\\\\\\\": 123 }\\" + + The regular expression used to validate the constraints is /^\\\\[a-zA-Z0-9\\\\\\\\-\\\\_\\\\]+$/ + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'interestingEdgeCases(): void;' + return: + type: void + description: '' + - name: optionalParamFunction(x) + uid: api-documenter-test!DocClass1#optionalParamFunction:member(1) + package: api-documenter-test! + fullName: optionalParamFunction(x) + summary: This is a function with an optional parameter. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'optionalParamFunction(x?: number): void;' + parameters: + - id: x + description: the number + type: number + return: + type: void + description: '' + - name: sumWithExample(x, y) + uid: api-documenter-test!DocClass1.sumWithExample:member(1) + package: api-documenter-test! + fullName: sumWithExample(x, y) + summary: Returns the sum of two numbers. + remarks: This illustrates usage of the \`@example\` block tag. + example: + - |- + Here's a simple example: + + \`\`\` + // Prints \\"2\\": + console.log(DocClass1.sumWithExample(1,1)); + \`\`\` + - |- + Here's an example with negative numbers: + + \`\`\` + // Prints \\"0\\": + console.log(DocClass1.sumWithExample(1,-1)); + \`\`\` + isPreview: false + isDeprecated: false + syntax: + content: 'static sumWithExample(x: number, y: number): number;' + parameters: + - id: x + description: the first number to add + type: number + - id: 'y' + description: the second number to add + type: number + return: + type: number + description: the sum of the two numbers + - name: tableExample() + uid: api-documenter-test!DocClass1#tableExample:member(1) + package: api-documenter-test! + fullName: tableExample() + summary: 'An example with tables:' + remarks:
John Doe
+ example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'tableExample(): void;' + return: + type: void + description: '' +events: + - name: malformedEvent + uid: api-documenter-test!DocClass1#malformedEvent:member + package: api-documenter-test! + fullName: malformedEvent + summary: This event should have been marked as readonly. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'malformedEvent: SystemEvent;' + return: + type: + - name: modifiedEvent + uid: api-documenter-test!DocClass1#modifiedEvent:member + package: api-documenter-test! + fullName: modifiedEvent + summary: This event is fired whenever the object is modified. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'readonly modifiedEvent: SystemEvent;' + return: + type: +extends: +", + "/api-documenter-test/docclassinterfacemerge-class.yml": "### YamlMime:TSType +name: DocClassInterfaceMerge +uid: api-documenter-test!DocClassInterfaceMerge:class +package: api-documenter-test! +fullName: DocClassInterfaceMerge +summary: Class that merges with interface +remarks: |- + [Link to class](xref:api-documenter-test!DocClassInterfaceMerge:class) + + [Link to interface](xref:api-documenter-test!DocClassInterfaceMerge:interface) +example: [] +isPreview: false +isDeprecated: false +type: class +", + "/api-documenter-test/docclassinterfacemerge-interface.yml": "### YamlMime:TSType +name: DocClassInterfaceMerge +uid: api-documenter-test!DocClassInterfaceMerge:interface +package: api-documenter-test! +fullName: DocClassInterfaceMerge +summary: Interface that merges with class +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +", + "/api-documenter-test/docenum.yml": "### YamlMime:TSEnum +name: DocEnum +uid: api-documenter-test!DocEnum:enum +package: api-documenter-test! +fullName: DocEnum +summary: Docs for DocEnum +remarks: '' +example: [] +isPreview: false +isDeprecated: false +fields: + - name: One + 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 + package: api-documenter-test! + summary: |- + These are some docs for Two. + + [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 + 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 +package: api-documenter-test! +fullName: DocEnumNamespaceMerge +summary: Enum that merges with namespace +remarks: |- + [Link to enum](xref:api-documenter-test!DocEnumNamespaceMerge:enum) + + [Link to namespace](xref:api-documenter-test!DocEnumNamespaceMerge:namespace) + + [Link to function inside namespace](xref:api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)) +example: [] +isPreview: false +isDeprecated: false +fields: + - name: Left + 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 + 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 + summary: Namespace that merges with enum + name: DocEnumNamespaceMerge + fullName: DocEnumNamespaceMerge + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 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 + type: function + syntax: + content: 'function exampleFunction(): void;' + return: + type: + - void + description: '' +", + "/api-documenter-test/ecmasymbols.yml": "### YamlMime:UniversalReference +items: + - uid: api-documenter-test!EcmaSymbols:namespace + summary: A namespace containing an ECMAScript symbol + name: EcmaSymbols + fullName: EcmaSymbols + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - api-documenter-test!EcmaSymbols.example:var + - uid: api-documenter-test!EcmaSymbols.example:var + summary: An ECMAScript symbol + name: example + fullName: EcmaSymbols.example + langs: + - typeScript + namespace: api-documenter-test!EcmaSymbols:namespace + type: variable + syntax: + content: 'example: unique symbol' + return: + type: + - unique symbol +", + "/api-documenter-test/exampleduplicatetypealias.yml": "### YamlMime:TSTypeAlias +name: ExampleDuplicateTypeAlias +uid: api-documenter-test!ExampleDuplicateTypeAlias:type +package: api-documenter-test! +fullName: ExampleDuplicateTypeAlias +summary: A type alias that has duplicate references. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +syntax: export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent; +", + "/api-documenter-test/exampletypealias.yml": "### YamlMime:TSTypeAlias +name: ExampleTypeAlias +uid: api-documenter-test!ExampleTypeAlias:type +package: api-documenter-test! +fullName: ExampleTypeAlias +summary: A type alias +remarks: '' +example: [] +isPreview: false +isDeprecated: false +syntax: export type ExampleTypeAlias = Promise; +", + "/api-documenter-test/exampleuniontypealias.yml": "### YamlMime:TSTypeAlias +name: ExampleUnionTypeAlias +uid: api-documenter-test!ExampleUnionTypeAlias:type +package: api-documenter-test! +fullName: ExampleUnionTypeAlias +summary: A type alias that references multiple other types. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +syntax: export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; +", + "/api-documenter-test/generic.yml": "### YamlMime:TSType +name: Generic +uid: api-documenter-test!Generic:class +package: api-documenter-test! +fullName: Generic +summary: Generic class. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: class +", + "/api-documenter-test/generictypealias.yml": "### YamlMime:TSTypeAlias +name: GenericTypeAlias +uid: api-documenter-test!GenericTypeAlias:type +package: api-documenter-test! +fullName: GenericTypeAlias +summary: '' +remarks: '' +example: [] +isPreview: false +isDeprecated: false +syntax: export type GenericTypeAlias = T[]; +", + "/api-documenter-test/idocinterface1.yml": "### YamlMime:TSType +name: IDocInterface1 +uid: api-documenter-test!IDocInterface1:interface +package: api-documenter-test! +fullName: IDocInterface1 +summary: '' +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: regularProperty + uid: api-documenter-test!IDocInterface1#regularProperty:member + package: api-documenter-test! + fullName: regularProperty + summary: Does something + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'regularProperty: SystemEvent;' + return: + type: +", + "/api-documenter-test/idocinterface2.yml": "### YamlMime:TSType +name: IDocInterface2 +uid: api-documenter-test!IDocInterface2:interface +package: api-documenter-test! +fullName: IDocInterface2 +summary: '' +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +methods: + - name: deprecatedExample() + uid: api-documenter-test!IDocInterface2#deprecatedExample:member(1) + package: api-documenter-test! + fullName: deprecatedExample() + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: true + customDeprecatedMessage: Use \`otherThing()\` instead. + syntax: + content: 'deprecatedExample(): void;' + return: + type: void + description: '' +extends: +", + "/api-documenter-test/idocinterface3.yml": "### YamlMime:TSType +name: IDocInterface3 +uid: api-documenter-test!IDocInterface3:interface +package: api-documenter-test! +fullName: IDocInterface3 +summary: Some less common TypeScript declaration kinds. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: '\\"[not.a.symbol]\\"' + 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. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: '\\"[not.a.symbol]\\": string;' + return: + type: string + - name: '[EcmaSymbols.example]' + uid: api-documenter-test!IDocInterface3#[EcmaSymbols.example]:member + package: api-documenter-test! + fullName: '[EcmaSymbols.example]' + summary: ECMAScript symbol + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: '[EcmaSymbols.example]: string;' + return: + type: string + - name: redundantQuotes + uid: api-documenter-test!IDocInterface3#redundantQuotes:member + package: api-documenter-test! + fullName: redundantQuotes + summary: A quoted identifier with redundant quotes. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: '\\"redundantQuotes\\": string;' + return: + type: string +", + "/api-documenter-test/idocinterface4.yml": "### YamlMime:TSType +name: IDocInterface4 +uid: api-documenter-test!IDocInterface4:interface +package: api-documenter-test! +fullName: IDocInterface4 +summary: Type union in an interface. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: Context + uid: api-documenter-test!IDocInterface4#Context:member + package: api-documenter-test! + fullName: Context + summary: Test newline rendering when code blocks are used in tables + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: |- + Context: ({ children }: { + children: string; + }) => boolean; + return: + type: |- + ({ children }: { + children: string; + }) => boolean + - name: generic + uid: api-documenter-test!IDocInterface4#generic:member + package: api-documenter-test! + fullName: generic + summary: make sure html entities are escaped in tables. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'generic: Generic;' + return: + type: <number> + - name: numberOrFunction + uid: api-documenter-test!IDocInterface4#numberOrFunction:member + package: api-documenter-test! + fullName: numberOrFunction + summary: a union type with a function + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'numberOrFunction: number | (() => number);' + return: + type: number | (() => number) + - name: stringOrNumber + uid: api-documenter-test!IDocInterface4#stringOrNumber:member + package: api-documenter-test! + fullName: stringOrNumber + summary: a union type + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'stringOrNumber: string | number;' + return: + type: string | number +", + "/api-documenter-test/idocinterface5.yml": "### YamlMime:TSType +name: IDocInterface5 +uid: api-documenter-test!IDocInterface5:interface +package: api-documenter-test! +fullName: IDocInterface5 +summary: Interface without inline tag to test custom TOC +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: regularProperty + uid: api-documenter-test!IDocInterface5#regularProperty:member + package: api-documenter-test! + fullName: regularProperty + summary: Property of type string that does something + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'regularProperty: string;' + return: + type: string +", + "/api-documenter-test/idocinterface6.yml": "### YamlMime:TSType +name: IDocInterface6 +uid: api-documenter-test!IDocInterface6:interface +package: api-documenter-test! +fullName: IDocInterface6 +summary: Interface without inline tag to test custom TOC with injection +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: arrayProperty + uid: api-documenter-test!IDocInterface6#arrayProperty:member + package: api-documenter-test! + fullName: arrayProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'arrayProperty: IDocInterface1[];' + return: + type: [] + - name: intersectionProperty + uid: api-documenter-test!IDocInterface6#intersectionProperty:member + package: api-documenter-test! + fullName: intersectionProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'intersectionProperty: IDocInterface1 & IDocInterface2;' + return: + type: >- + & + - name: regularProperty + uid: api-documenter-test!IDocInterface6#regularProperty:member + package: api-documenter-test! + fullName: regularProperty + summary: Property of type number that does something + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'regularProperty: number;' + return: + type: number + - name: tupleProperty + uid: api-documenter-test!IDocInterface6#tupleProperty:member + package: api-documenter-test! + fullName: tupleProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'tupleProperty: [IDocInterface1, IDocInterface2];' + return: + type: >- + [, ] + - name: typeReferenceProperty + uid: api-documenter-test!IDocInterface6#typeReferenceProperty:member + package: api-documenter-test! + fullName: typeReferenceProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'typeReferenceProperty: Generic;' + return: + type: >- + <> + - name: unionProperty + uid: api-documenter-test!IDocInterface6#unionProperty:member + package: api-documenter-test! + fullName: unionProperty + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'unionProperty: IDocInterface1 | IDocInterface2;' + return: + type: >- + | +methods: + - name: genericReferenceMethod(x) + uid: api-documenter-test!IDocInterface6#genericReferenceMethod:member(1) + package: api-documenter-test! + fullName: genericReferenceMethod(x) + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'genericReferenceMethod(x: T): T;' + parameters: + - id: x + description: '' + type: T + return: + type: T + description: '' +", + "/api-documenter-test/idocinterface7.yml": "### YamlMime:TSType +name: IDocInterface7 +uid: api-documenter-test!IDocInterface7:interface +package: api-documenter-test! +fullName: IDocInterface7 +summary: Interface for testing optional properties +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: interface +properties: + - name: optionalField + uid: api-documenter-test!IDocInterface7#optionalField:member + package: api-documenter-test! + fullName: optionalField + summary: Description of optionalField + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'optionalField?: boolean;' + return: + type: boolean + - name: optionalReadonlyField + uid: api-documenter-test!IDocInterface7#optionalReadonlyField:member + package: api-documenter-test! + fullName: optionalReadonlyField + summary: Description of optionalReadonlyField + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'readonly optionalReadonlyField?: boolean;' + return: + type: boolean + - name: optionalUndocumentedField + uid: api-documenter-test!IDocInterface7#optionalUndocumentedField:member + package: api-documenter-test! + fullName: optionalUndocumentedField + summary: '' + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'optionalUndocumentedField?: boolean;' + return: + type: boolean +methods: + - name: optionalMember() + uid: api-documenter-test!IDocInterface7#optionalMember:member(1) + package: api-documenter-test! + fullName: optionalMember() + summary: Description of optionalMember + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'optionalMember?(): any;' + return: + type: any + description: '' +", + "/api-documenter-test/outernamespace.innernamespace.yml": "### YamlMime:UniversalReference +items: + - uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace + summary: A nested namespace + name: OuterNamespace.InnerNamespace + fullName: OuterNamespace.InnerNamespace + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 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 + type: function + syntax: + content: 'function nestedFunction(x: number): number;' + return: + type: + - number + description: '' + parameters: + - id: x + description: '' + type: + - number + optional: false +", + "/api-documenter-test/outernamespace.yml": "### YamlMime:UniversalReference +items: + - uid: api-documenter-test!OuterNamespace:namespace + summary: A top-level namespace + name: OuterNamespace + fullName: OuterNamespace + langs: + - typeScript + type: namespace + package: api-documenter-test! + children: + - 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 + type: variable + syntax: + content: 'nestedVariable: boolean' + return: + type: + - boolean +", + "/api-documenter-test/systemevent.yml": "### YamlMime:TSType +name: SystemEvent +uid: api-documenter-test!SystemEvent:class +package: api-documenter-test! +fullName: SystemEvent +summary: A class used to exposed events. +remarks: '' +example: [] +isPreview: false +isDeprecated: false +type: class +methods: + - name: addHandler(handler) + uid: api-documenter-test!SystemEvent#addHandler:member(1) + package: api-documenter-test! + fullName: addHandler(handler) + summary: Adds an handler for the event. + remarks: '' + example: [] + isPreview: false + isDeprecated: false + syntax: + content: 'addHandler(handler: () => void): void;' + parameters: + - id: handler + description: '' + type: () => void + return: + type: void + description: '' +", + "/api-documenter-test/typealias.yml": "### YamlMime:TSTypeAlias +name: TypeAlias +uid: api-documenter-test!TypeAlias:type +package: api-documenter-test! +fullName: TypeAlias +summary: '' +remarks: '' +example: [] +isPreview: false +isDeprecated: false +syntax: export type TypeAlias = number; +", + "/toc.yml": "items: + - name: Test api-documenter + href: ~/homepage/homepage.md + - name: Test Sample for AD + href: api-documenter-test + extended: true + items: + - name: Classes + items: + - name: DocBaseClass + items: + - name: DocBaseClass + uid: api-documenter-test!DocBaseClass:class + - name: IDocInterface1 + uid: api-documenter-test!IDocInterface1:interface + - name: IDocInterface2 + uid: api-documenter-test!IDocInterface2:interface + - name: DocClass1 + items: + - name: DocClass1 + uid: api-documenter-test!DocClass1:class + - name: IDocInterface3 + uid: api-documenter-test!IDocInterface3:interface + - name: IDocInterface4 + uid: api-documenter-test!IDocInterface4:interface + - name: Interfaces + items: + - name: Interface5 + items: + - name: IDocInterface5 + uid: api-documenter-test!IDocInterface5:interface + - name: Interface6 + items: + - name: InjectedCustomInterface + uid: customUid + - name: IDocInterface6 + uid: api-documenter-test!IDocInterface6:interface + - name: References + items: + - name: InjectedCustomItem + uid: customUrl + - name: AbstractClass + uid: api-documenter-test!AbstractClass:class + - name: Constraint + uid: api-documenter-test!Constraint:interface + - name: DecoratorExample + uid: api-documenter-test!DecoratorExample:class + - name: DefaultType + uid: api-documenter-test!DefaultType:interface + - name: DocClassInterfaceMerge (Class) + uid: api-documenter-test!DocClassInterfaceMerge:class + - name: DocClassInterfaceMerge (Interface) + uid: api-documenter-test!DocClassInterfaceMerge:interface + - name: DocEnum + uid: api-documenter-test!DocEnum:enum + - name: DocEnumNamespaceMerge (Enum) + uid: api-documenter-test!DocEnumNamespaceMerge:enum + - name: DocEnumNamespaceMerge (Namespace) + uid: api-documenter-test!DocEnumNamespaceMerge:namespace + - name: EcmaSymbols + uid: api-documenter-test!EcmaSymbols:namespace + - name: ExampleDuplicateTypeAlias + uid: api-documenter-test!ExampleDuplicateTypeAlias:type + - name: ExampleTypeAlias + uid: api-documenter-test!ExampleTypeAlias:type + - name: ExampleUnionTypeAlias + uid: api-documenter-test!ExampleUnionTypeAlias:type + - name: Generic + uid: api-documenter-test!Generic:class + - name: GenericTypeAlias + uid: api-documenter-test!GenericTypeAlias:type + - name: IDocInterface7 + uid: api-documenter-test!IDocInterface7:interface + - name: OuterNamespace + uid: api-documenter-test!OuterNamespace:namespace + - name: OuterNamespace.InnerNamespace + uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace + - name: SystemEvent + uid: api-documenter-test!SystemEvent:class + - name: TypeAlias + uid: api-documenter-test!TypeAlias:type +", +} +`; + +exports[`api-documenter markdown: itemContents 1`] = ` +Object { + "/api-documenter-test.abstractclass.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [AbstractClass](./api-documenter-test.abstractclass.md) + +## AbstractClass class + +Some abstract class with abstract members. + +**Signature:** + +\`\`\`typescript +export declare abstract class AbstractClass +\`\`\` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[property](./api-documenter-test.abstractclass.property.md) + + + + +\`protected\` + +\`abstract\` + + + + +number + + + + +Some abstract property. + + +
+ +## Methods + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[method()](./api-documenter-test.abstractclass.method.md) + + + + +\`abstract\` + + + + +Some abstract method. + + +
+ +", + "/api-documenter-test.abstractclass.method.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [AbstractClass](./api-documenter-test.abstractclass.md) > [method](./api-documenter-test.abstractclass.method.md) + +## AbstractClass.method() method + +Some abstract method. + +**Signature:** + +\`\`\`typescript +abstract method(): void; +\`\`\` +**Returns:** + +void + +", + "/api-documenter-test.abstractclass.property.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [AbstractClass](./api-documenter-test.abstractclass.md) > [property](./api-documenter-test.abstractclass.property.md) + +## AbstractClass.property property + +Some abstract property. + +**Signature:** + +\`\`\`typescript +protected abstract property: number; +\`\`\` +", + "/api-documenter-test.constraint.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [Constraint](./api-documenter-test.constraint.md) + +## Constraint interface + +Type parameter constraint used by test case below. + +**Signature:** + +\`\`\`typescript +export interface Constraint +\`\`\` +", + "/api-documenter-test.constvariable.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [constVariable](./api-documenter-test.constvariable.md) + +## constVariable variable + +An exported variable declaration. + +**Signature:** + +\`\`\`typescript +constVariable: number +\`\`\` +", + "/api-documenter-test.decoratorexample.creationdate.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DecoratorExample](./api-documenter-test.decoratorexample.md) > [creationDate](./api-documenter-test.decoratorexample.creationdate.md) + +## DecoratorExample.creationDate property + +The date when the record was created. + +**Signature:** + +\`\`\`typescript +creationDate: Date; +\`\`\` +**Decorators:** + +\`@jsonSerialized\` + +\`@jsonFormat('mm/dd/yy')\` + +## Remarks + +Here is a longer description of the property. + +", + "/api-documenter-test.decoratorexample.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DecoratorExample](./api-documenter-test.decoratorexample.md) + +## DecoratorExample class + + +**Signature:** + +\`\`\`typescript +export declare class DecoratorExample +\`\`\` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[creationDate](./api-documenter-test.decoratorexample.creationdate.md) + + + + + + + +Date + + + + +The date when the record was created. + + +
+ +", + "/api-documenter-test.defaulttype.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DefaultType](./api-documenter-test.defaulttype.md) + +## DefaultType interface + +Type parameter default type used by test case below. + +**Signature:** + +\`\`\`typescript +export interface DefaultType +\`\`\` +", + "/api-documenter-test.docbaseclass._constructor_.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) > [(constructor)](./api-documenter-test.docbaseclass._constructor_.md) + +## DocBaseClass.(constructor) + +The simple constructor for \`DocBaseClass\` + +**Signature:** + +\`\`\`typescript +constructor(); +\`\`\` +", + "/api-documenter-test.docbaseclass._constructor__1.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) > [(constructor)](./api-documenter-test.docbaseclass._constructor__1.md) + +## DocBaseClass.(constructor) + +The overloaded constructor for \`DocBaseClass\` + +**Signature:** + +\`\`\`typescript +constructor(x: number); +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +number + + + + + +
+ +", + "/api-documenter-test.docbaseclass.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocBaseClass](./api-documenter-test.docbaseclass.md) + +## DocBaseClass class + +Example base class + + +**Signature:** + +\`\`\`typescript +export declare class DocBaseClass +\`\`\` + +## Constructors + + + + +
+ +Constructor + + + + +Modifiers + + + + +Description + + +
+ +[(constructor)()](./api-documenter-test.docbaseclass._constructor_.md) + + + + + + + +The simple constructor for \`DocBaseClass\` + + +
+ +[(constructor)(x)](./api-documenter-test.docbaseclass._constructor__1.md) + + + + + + + +The overloaded constructor for \`DocBaseClass\` + + +
+ +", + "/api-documenter-test.docclass1.deprecatedexample.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [deprecatedExample](./api-documenter-test.docclass1.deprecatedexample.md) + +## DocClass1.deprecatedExample() method + +> Warning: This API is now obsolete. +> +> Use \`otherThing()\` instead. +> + +**Signature:** + +\`\`\`typescript +deprecatedExample(): void; +\`\`\` +**Returns:** + +void + +", + "/api-documenter-test.docclass1.examplefunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [exampleFunction](./api-documenter-test.docclass1.examplefunction.md) + +## DocClass1.exampleFunction() method + +This is an overloaded function. + +**Signature:** + +\`\`\`typescript +exampleFunction(a: string, b: string): string; +\`\`\` + +## Parameters + + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +a + + + + +string + + + + +the first string + + +
+ +b + + + + +string + + + + +the second string + + +
+ +**Returns:** + +string + +## Exceptions + +\`Error\` The first throws line + +The second throws line + +", + "/api-documenter-test.docclass1.examplefunction_1.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [exampleFunction](./api-documenter-test.docclass1.examplefunction_1.md) + +## DocClass1.exampleFunction() method + +This is also an overloaded function. + +**Signature:** + +\`\`\`typescript +exampleFunction(x: number): number; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +number + + + + +the number + + +
+ +**Returns:** + +number + +", + "/api-documenter-test.docclass1.genericwithconstraintanddefault.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [genericWithConstraintAndDefault](./api-documenter-test.docclass1.genericwithconstraintanddefault.md) + +## DocClass1.genericWithConstraintAndDefault() method + +This is a method with a complex type parameter. + +**Signature:** + +\`\`\`typescript +genericWithConstraintAndDefault(x: T): void; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +T + + + + +some generic parameter. + + +
+ +**Returns:** + +void + +", + "/api-documenter-test.docclass1.interestingedgecases.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [interestingEdgeCases](./api-documenter-test.docclass1.interestingedgecases.md) + +## DocClass1.interestingEdgeCases() method + +Example: \\"{ \\\\\\\\\\"maxItemsToShow\\\\\\\\\\": 123 }\\" + +The regular expression used to validate the constraints is /^\\\\[a-zA-Z0-9\\\\\\\\-\\\\_\\\\]+$/ + +**Signature:** + +\`\`\`typescript +interestingEdgeCases(): void; +\`\`\` +**Returns:** + +void + +", + "/api-documenter-test.docclass1.malformedevent.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [malformedEvent](./api-documenter-test.docclass1.malformedevent.md) + +## DocClass1.malformedEvent property + +This event should have been marked as readonly. + +**Signature:** + +\`\`\`typescript +malformedEvent: SystemEvent; +\`\`\` +", + "/api-documenter-test.docclass1.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) + +## DocClass1 class + +This is an example class. + +**Signature:** + +\`\`\`typescript +export declare class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInterface2 +\`\`\` +**Extends:** [DocBaseClass](./api-documenter-test.docbaseclass.md) + +**Implements:** [IDocInterface1](./api-documenter-test.idocinterface1.md), [IDocInterface2](./api-documenter-test.idocinterface2.md) + +## Remarks + +[Link to overload 1](./api-documenter-test.docclass1.examplefunction.md) + +[Link to overload 2](./api-documenter-test.docclass1.examplefunction_1.md) + + +The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the \`DocClass1\` class. + +## Events + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[malformedEvent](./api-documenter-test.docclass1.malformedevent.md) + + + + + + + +[SystemEvent](./api-documenter-test.systemevent.md) + + + + +This event should have been marked as readonly. + + +
+ +[modifiedEvent](./api-documenter-test.docclass1.modifiedevent.md) + + + + +\`readonly\` + + + + +[SystemEvent](./api-documenter-test.systemevent.md) + + + + +This event is fired whenever the object is modified. + + +
+ +## Properties + + + + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[multipleModifiersProperty](./api-documenter-test.docclass1.multiplemodifiersproperty.md) + + + + +\`protected\` + +\`static\` + +\`readonly\` + + + + +boolean + + + + +Some property with multiple modifiers. + + +
+ +[protectedProperty](./api-documenter-test.docclass1.protectedproperty.md) + + + + +\`protected\` + + + + +string + + + + +Some protected property. + + +
+ +[readonlyProperty](./api-documenter-test.docclass1.readonlyproperty.md) + + + + +\`readonly\` + + + + +string + + + + + +
+ +[regularProperty](./api-documenter-test.docclass1.regularproperty.md) + + + + + + + +[SystemEvent](./api-documenter-test.systemevent.md) + + + + +This is a regular property that happens to use the SystemEvent type. + + +
+ +[writeableProperty](./api-documenter-test.docclass1.writeableproperty.md) + + + + + + + +string + + + + + +
+ +[writeonlyProperty](./api-documenter-test.docclass1.writeonlyproperty.md) + + + + + + + +string + + + + +API Extractor will surface an \`ae-missing-getter\` finding for this property. + + +
+ +## Methods + + + + + + + + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[deprecatedExample()](./api-documenter-test.docclass1.deprecatedexample.md) + + + + + + + + +
+ +[exampleFunction(a, b)](./api-documenter-test.docclass1.examplefunction.md) + + + + + + + +This is an overloaded function. + + +
+ +[exampleFunction(x)](./api-documenter-test.docclass1.examplefunction_1.md) + + + + + + + +This is also an overloaded function. + + +
+ +[genericWithConstraintAndDefault(x)](./api-documenter-test.docclass1.genericwithconstraintanddefault.md) + + + + + + + +This is a method with a complex type parameter. + + +
+ +[interestingEdgeCases()](./api-documenter-test.docclass1.interestingedgecases.md) + + + + + + + +Example: \\"{ \\\\\\\\\\"maxItemsToShow\\\\\\\\\\": 123 }\\" + +The regular expression used to validate the constraints is /^\\\\[a-zA-Z0-9\\\\\\\\-\\\\_\\\\]+$/ + + +
+ +[optionalParamFunction(x)](./api-documenter-test.docclass1.optionalparamfunction.md) + + + + + + + +This is a function with an optional parameter. + + +
+ +[sumWithExample(x, y)](./api-documenter-test.docclass1.sumwithexample.md) + + + + +\`static\` + + + + +Returns the sum of two numbers. + + +
+ +[tableExample()](./api-documenter-test.docclass1.tableexample.md) + + + + + + + +An example with tables: + + +
+ +", + "/api-documenter-test.docclass1.modifiedevent.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [modifiedEvent](./api-documenter-test.docclass1.modifiedevent.md) + +## DocClass1.modifiedEvent property + +This event is fired whenever the object is modified. + +**Signature:** + +\`\`\`typescript +readonly modifiedEvent: SystemEvent; +\`\`\` +", + "/api-documenter-test.docclass1.multiplemodifiersproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [multipleModifiersProperty](./api-documenter-test.docclass1.multiplemodifiersproperty.md) + +## DocClass1.multipleModifiersProperty property + +Some property with multiple modifiers. + +**Signature:** + +\`\`\`typescript +protected static readonly multipleModifiersProperty: boolean; +\`\`\` +", + "/api-documenter-test.docclass1.optionalparamfunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [optionalParamFunction](./api-documenter-test.docclass1.optionalparamfunction.md) + +## DocClass1.optionalParamFunction() method + +This is a function with an optional parameter. + +**Signature:** + +\`\`\`typescript +optionalParamFunction(x?: number): void; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +number + + + + +_(Optional)_ the number + + +
+ +**Returns:** + +void + +", + "/api-documenter-test.docclass1.protectedproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [protectedProperty](./api-documenter-test.docclass1.protectedproperty.md) + +## DocClass1.protectedProperty property + +Some protected property. + +**Signature:** + +\`\`\`typescript +protected protectedProperty: string; +\`\`\` +", + "/api-documenter-test.docclass1.readonlyproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [readonlyProperty](./api-documenter-test.docclass1.readonlyproperty.md) + +## DocClass1.readonlyProperty property + +**Signature:** + +\`\`\`typescript +get readonlyProperty(): string; +\`\`\` +", + "/api-documenter-test.docclass1.regularproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [regularProperty](./api-documenter-test.docclass1.regularproperty.md) + +## DocClass1.regularProperty property + +This is a regular property that happens to use the SystemEvent type. + +**Signature:** + +\`\`\`typescript +regularProperty: SystemEvent; +\`\`\` +", + "/api-documenter-test.docclass1.sumwithexample.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [sumWithExample](./api-documenter-test.docclass1.sumwithexample.md) + +## DocClass1.sumWithExample() method + +Returns the sum of two numbers. + +**Signature:** + +\`\`\`typescript +static sumWithExample(x: number, y: number): number; +\`\`\` + +## Parameters + + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +number + + + + +the first number to add + + +
+ +y + + + + +number + + + + +the second number to add + + +
+ +**Returns:** + +number + +the sum of the two numbers + +## Remarks + +This illustrates usage of the \`@example\` block tag. + +## Example 1 + +Here's a simple example: + +\`\`\` +// Prints \\"2\\": +console.log(DocClass1.sumWithExample(1,1)); +\`\`\` + +## Example 2 + +Here's an example with negative numbers: + +\`\`\` +// Prints \\"0\\": +console.log(DocClass1.sumWithExample(1,-1)); +\`\`\` + +", + "/api-documenter-test.docclass1.tableexample.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [tableExample](./api-documenter-test.docclass1.tableexample.md) + +## DocClass1.tableExample() method + +An example with tables: + +**Signature:** + +\`\`\`typescript +tableExample(): void; +\`\`\` +**Returns:** + +void + +## Remarks + +
John Doe
+ +", + "/api-documenter-test.docclass1.writeableproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [writeableProperty](./api-documenter-test.docclass1.writeableproperty.md) + +## DocClass1.writeableProperty property + +**Signature:** + +\`\`\`typescript +get writeableProperty(): string; + +set writeableProperty(value: string); +\`\`\` +", + "/api-documenter-test.docclass1.writeonlyproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [writeonlyProperty](./api-documenter-test.docclass1.writeonlyproperty.md) + +## DocClass1.writeonlyProperty property + +API Extractor will surface an \`ae-missing-getter\` finding for this property. + +**Signature:** + +\`\`\`typescript +set writeonlyProperty(value: string); +\`\`\` +", + "/api-documenter-test.docclassinterfacemerge.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) + +## DocClassInterfaceMerge interface + +Interface that merges with class + +**Signature:** + +\`\`\`typescript +export interface DocClassInterfaceMerge +\`\`\` +", + "/api-documenter-test.docenum.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocEnum](./api-documenter-test.docenum.md) + +## DocEnum enum + +Docs for DocEnum + + +**Signature:** + +\`\`\`typescript +export declare enum DocEnum +\`\`\` + +## Enumeration Members + + + + + +
+ +Member + + + + +Value + + + + +Description + + +
+ +One + + + + +\`1\` + + + + +These are some docs for One + + +
+ +Two + + + + +\`2\` + + + + +These are some docs for Two. + +[DocEnum.One](./api-documenter-test.docenum.md) is a direct link to another enum member. + + +
+ +Zero + + + + +\`0\` + + + + +These are some docs for Zero + + +
+ +", + "/api-documenter-test.docenumnamespacemerge.examplefunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocEnumNamespaceMerge](./api-documenter-test.docenumnamespacemerge.md) > [exampleFunction](./api-documenter-test.docenumnamespacemerge.examplefunction.md) + +## DocEnumNamespaceMerge.exampleFunction() function + +This is a function inside of a namespace that merges with an enum. + +**Signature:** + +\`\`\`typescript +function exampleFunction(): void; +\`\`\` +**Returns:** + +void + +", + "/api-documenter-test.docenumnamespacemerge.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocEnumNamespaceMerge](./api-documenter-test.docenumnamespacemerge.md) + +## DocEnumNamespaceMerge namespace + +Namespace that merges with enum + +**Signature:** + +\`\`\`typescript +export declare namespace DocEnumNamespaceMerge +\`\`\` + +## Functions + + + +
+ +Function + + + + +Description + + +
+ +[exampleFunction()](./api-documenter-test.docenumnamespacemerge.examplefunction.md) + + + + +This is a function inside of a namespace that merges with an enum. + + +
+ +", + "/api-documenter-test.ecmasymbols.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) + +## EcmaSymbols.example variable + +An ECMAScript symbol + +**Signature:** + +\`\`\`typescript +example: unique symbol +\`\`\` +", + "/api-documenter-test.ecmasymbols.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSymbols](./api-documenter-test.ecmasymbols.md) + +## EcmaSymbols namespace + +A namespace containing an ECMAScript symbol + +**Signature:** + +\`\`\`typescript +export declare namespace EcmaSymbols +\`\`\` + +## Variables + + + +
+ +Variable + + + + +Description + + +
+ +[example](./api-documenter-test.ecmasymbols.example.md) + + + + +An ECMAScript symbol + + +
+ +", + "/api-documenter-test.exampleduplicatetypealias.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [ExampleDuplicateTypeAlias](./api-documenter-test.exampleduplicatetypealias.md) + +## ExampleDuplicateTypeAlias type + +A type alias that has duplicate references. + +**Signature:** + +\`\`\`typescript +export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent; +\`\`\` +**References:** [SystemEvent](./api-documenter-test.systemevent.md) + +", + "/api-documenter-test.examplefunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [exampleFunction](./api-documenter-test.examplefunction.md) + +## exampleFunction() function + +An exported function with hyperlinked parameters and return value. + +**Signature:** + +\`\`\`typescript +export declare function exampleFunction(x: ExampleTypeAlias, y: number): IDocInterface1; +\`\`\` + +## Parameters + + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +[ExampleTypeAlias](./api-documenter-test.exampletypealias.md) + + + + +an API item that should get hyperlinked + + +
+ +y + + + + +number + + + + +a system type that should NOT get hyperlinked + + +
+ +**Returns:** + +[IDocInterface1](./api-documenter-test.idocinterface1.md) + +an interface that should get hyperlinked + +", + "/api-documenter-test.exampletypealias.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [ExampleTypeAlias](./api-documenter-test.exampletypealias.md) + +## ExampleTypeAlias type + +A type alias + +**Signature:** + +\`\`\`typescript +export type ExampleTypeAlias = Promise; +\`\`\` +", + "/api-documenter-test.exampleuniontypealias.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [ExampleUnionTypeAlias](./api-documenter-test.exampleuniontypealias.md) + +## ExampleUnionTypeAlias type + +A type alias that references multiple other types. + +**Signature:** + +\`\`\`typescript +export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; +\`\`\` +**References:** [IDocInterface1](./api-documenter-test.idocinterface1.md), [IDocInterface3](./api-documenter-test.idocinterface3.md) + +", + "/api-documenter-test.generic.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [Generic](./api-documenter-test.generic.md) + +## Generic class + +Generic class. + +**Signature:** + +\`\`\`typescript +export declare class Generic +\`\`\` +", + "/api-documenter-test.generictypealias.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [GenericTypeAlias](./api-documenter-test.generictypealias.md) + +## GenericTypeAlias type + + +**Signature:** + +\`\`\`typescript +export type GenericTypeAlias = T[]; +\`\`\` +", + "/api-documenter-test.idocinterface1.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface1](./api-documenter-test.idocinterface1.md) + +## IDocInterface1 interface + + +**Signature:** + +\`\`\`typescript +export interface IDocInterface1 +\`\`\` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[regularProperty](./api-documenter-test.idocinterface1.regularproperty.md) + + + + + + + +[SystemEvent](./api-documenter-test.systemevent.md) + + + + +Does something + + +
+ +", + "/api-documenter-test.idocinterface1.regularproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface1](./api-documenter-test.idocinterface1.md) > [regularProperty](./api-documenter-test.idocinterface1.regularproperty.md) + +## IDocInterface1.regularProperty property + +Does something + +**Signature:** + +\`\`\`typescript +regularProperty: SystemEvent; +\`\`\` +", + "/api-documenter-test.idocinterface2.deprecatedexample.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface2](./api-documenter-test.idocinterface2.md) > [deprecatedExample](./api-documenter-test.idocinterface2.deprecatedexample.md) + +## IDocInterface2.deprecatedExample() method + +> Warning: This API is now obsolete. +> +> Use \`otherThing()\` instead. +> + +**Signature:** + +\`\`\`typescript +deprecatedExample(): void; +\`\`\` +**Returns:** + +void + +", + "/api-documenter-test.idocinterface2.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface2](./api-documenter-test.idocinterface2.md) + +## IDocInterface2 interface + + +**Signature:** + +\`\`\`typescript +export interface IDocInterface2 extends IDocInterface1 +\`\`\` +**Extends:** [IDocInterface1](./api-documenter-test.idocinterface1.md) + +## Methods + + + +
+ +Method + + + + +Description + + +
+ +[deprecatedExample()](./api-documenter-test.idocinterface2.deprecatedexample.md) + + + + + +
+ +", + "/api-documenter-test.idocinterface3.__not.a.symbol__.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [\\"\\\\[not.a.symbol\\\\]\\"](./api-documenter-test.idocinterface3.__not.a.symbol__.md) + +## IDocInterface3.\\"\\\\[not.a.symbol\\\\]\\" property + +An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol. + +**Signature:** + +\`\`\`typescript +\\"[not.a.symbol]\\": string; +\`\`\` +", + "/api-documenter-test.idocinterface3._ecmasymbols.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.\\\\[EcmaSymbols.example\\\\] property + +ECMAScript symbol + +**Signature:** + +\`\`\`typescript +[EcmaSymbols.example]: string; +\`\`\` +", + "/api-documenter-test.idocinterface3._new_.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [(new)](./api-documenter-test.idocinterface3._new_.md) + +## IDocInterface3.(new) + +Construct signature + +**Signature:** + +\`\`\`typescript +new (): IDocInterface1; +\`\`\` +**Returns:** + +[IDocInterface1](./api-documenter-test.idocinterface1.md) + +", + "/api-documenter-test.idocinterface3.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) + +## IDocInterface3 interface + +Some less common TypeScript declaration kinds. + + +**Signature:** + +\`\`\`typescript +export interface IDocInterface3 +\`\`\` + +## Properties + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[\\"\\\\[not.a.symbol\\\\]\\"](./api-documenter-test.idocinterface3.__not.a.symbol__.md) + + + + + + + +string + + + + +An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol. + + +
+ +[\\\\[EcmaSymbols.example\\\\]](./api-documenter-test.idocinterface3._ecmasymbols.example_.md) + + + + + + + +string + + + + +ECMAScript symbol + + +
+ +[redundantQuotes](./api-documenter-test.idocinterface3.redundantquotes.md) + + + + + + + +string + + + + +A quoted identifier with redundant quotes. + + +
+ +## Methods + + + +
+ +Method + + + + +Description + + +
+ +[(new)()](./api-documenter-test.idocinterface3._new_.md) + + + + +Construct signature + + +
+ +", + "/api-documenter-test.idocinterface3.redundantquotes.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [redundantQuotes](./api-documenter-test.idocinterface3.redundantquotes.md) + +## IDocInterface3.redundantQuotes property + +A quoted identifier with redundant quotes. + +**Signature:** + +\`\`\`typescript +\\"redundantQuotes\\": string; +\`\`\` +", + "/api-documenter-test.idocinterface4.context.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [Context](./api-documenter-test.idocinterface4.context.md) + +## IDocInterface4.Context property + +Test newline rendering when code blocks are used in tables + +**Signature:** + +\`\`\`typescript +Context: ({ children }: { + children: string; + }) => boolean; +\`\`\` +", + "/api-documenter-test.idocinterface4.generic.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [generic](./api-documenter-test.idocinterface4.generic.md) + +## IDocInterface4.generic property + +make sure html entities are escaped in tables. + +**Signature:** + +\`\`\`typescript +generic: Generic; +\`\`\` +", + "/api-documenter-test.idocinterface4.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) + +## IDocInterface4 interface + +Type union in an interface. + + +**Signature:** + +\`\`\`typescript +export interface IDocInterface4 +\`\`\` + +## Properties + + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[Context](./api-documenter-test.idocinterface4.context.md) + + + + + + + +({ children }: { children: string; }) => boolean + + + + +Test newline rendering when code blocks are used in tables + + +
+ +[generic](./api-documenter-test.idocinterface4.generic.md) + + + + + + + +[Generic](./api-documenter-test.generic.md)<number> + + + + +make sure html entities are escaped in tables. + + +
+ +[numberOrFunction](./api-documenter-test.idocinterface4.numberorfunction.md) + + + + + + + +number \\\\| (() => number) + + + + +a union type with a function + + +
+ +[stringOrNumber](./api-documenter-test.idocinterface4.stringornumber.md) + + + + + + + +string \\\\| number + + + + +a union type + + +
+ +", + "/api-documenter-test.idocinterface4.numberorfunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [numberOrFunction](./api-documenter-test.idocinterface4.numberorfunction.md) + +## IDocInterface4.numberOrFunction property + +a union type with a function + +**Signature:** + +\`\`\`typescript +numberOrFunction: number | (() => number); +\`\`\` +", + "/api-documenter-test.idocinterface4.stringornumber.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface4](./api-documenter-test.idocinterface4.md) > [stringOrNumber](./api-documenter-test.idocinterface4.stringornumber.md) + +## IDocInterface4.stringOrNumber property + +a union type + +**Signature:** + +\`\`\`typescript +stringOrNumber: string | number; +\`\`\` +", + "/api-documenter-test.idocinterface5.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface5](./api-documenter-test.idocinterface5.md) + +## IDocInterface5 interface + +Interface without inline tag to test custom TOC + +**Signature:** + +\`\`\`typescript +export interface IDocInterface5 +\`\`\` + +## Properties + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[regularProperty](./api-documenter-test.idocinterface5.regularproperty.md) + + + + + + + +string + + + + +Property of type string that does something + + +
+ +", + "/api-documenter-test.idocinterface5.regularproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface5](./api-documenter-test.idocinterface5.md) > [regularProperty](./api-documenter-test.idocinterface5.regularproperty.md) + +## IDocInterface5.regularProperty property + +Property of type string that does something + +**Signature:** + +\`\`\`typescript +regularProperty: string; +\`\`\` +", + "/api-documenter-test.idocinterface6.arrayproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [arrayProperty](./api-documenter-test.idocinterface6.arrayproperty.md) + +## IDocInterface6.arrayProperty property + +**Signature:** + +\`\`\`typescript +arrayProperty: IDocInterface1[]; +\`\`\` +", + "/api-documenter-test.idocinterface6.genericreferencemethod.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [genericReferenceMethod](./api-documenter-test.idocinterface6.genericreferencemethod.md) + +## IDocInterface6.genericReferenceMethod() method + +**Signature:** + +\`\`\`typescript +genericReferenceMethod(x: T): T; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +T + + + + + +
+ +**Returns:** + +T + +", + "/api-documenter-test.idocinterface6.intersectionproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [intersectionProperty](./api-documenter-test.idocinterface6.intersectionproperty.md) + +## IDocInterface6.intersectionProperty property + +**Signature:** + +\`\`\`typescript +intersectionProperty: IDocInterface1 & IDocInterface2; +\`\`\` +", + "/api-documenter-test.idocinterface6.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) + +## IDocInterface6 interface + +Interface without inline tag to test custom TOC with injection + +**Signature:** + +\`\`\`typescript +export interface IDocInterface6 +\`\`\` + +## Properties + + + + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[arrayProperty](./api-documenter-test.idocinterface6.arrayproperty.md) + + + + + + + +[IDocInterface1](./api-documenter-test.idocinterface1.md)\\\\[\\\\] + + + + + +
+ +[intersectionProperty](./api-documenter-test.idocinterface6.intersectionproperty.md) + + + + + + + +[IDocInterface1](./api-documenter-test.idocinterface1.md) & [IDocInterface2](./api-documenter-test.idocinterface2.md) + + + + + +
+ +[regularProperty](./api-documenter-test.idocinterface6.regularproperty.md) + + + + + + + +number + + + + +Property of type number that does something + + +
+ +[tupleProperty](./api-documenter-test.idocinterface6.tupleproperty.md) + + + + + + + +\\\\[[IDocInterface1](./api-documenter-test.idocinterface1.md), [IDocInterface2](./api-documenter-test.idocinterface2.md)\\\\] + + + + + +
+ +[typeReferenceProperty](./api-documenter-test.idocinterface6.typereferenceproperty.md) + + + + + + + +[Generic](./api-documenter-test.generic.md)<[IDocInterface1](./api-documenter-test.idocinterface1.md)> + + + + + +
+ +[unionProperty](./api-documenter-test.idocinterface6.unionproperty.md) + + + + + + + +[IDocInterface1](./api-documenter-test.idocinterface1.md) \\\\| [IDocInterface2](./api-documenter-test.idocinterface2.md) + + + + + +
+ +## Methods + + + +
+ +Method + + + + +Description + + +
+ +[genericReferenceMethod(x)](./api-documenter-test.idocinterface6.genericreferencemethod.md) + + + + + +
+ +", + "/api-documenter-test.idocinterface6.regularproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [regularProperty](./api-documenter-test.idocinterface6.regularproperty.md) + +## IDocInterface6.regularProperty property + +Property of type number that does something + +**Signature:** + +\`\`\`typescript +regularProperty: number; +\`\`\` +", + "/api-documenter-test.idocinterface6.tupleproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [tupleProperty](./api-documenter-test.idocinterface6.tupleproperty.md) + +## IDocInterface6.tupleProperty property + +**Signature:** + +\`\`\`typescript +tupleProperty: [IDocInterface1, IDocInterface2]; +\`\`\` +", + "/api-documenter-test.idocinterface6.typereferenceproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [typeReferenceProperty](./api-documenter-test.idocinterface6.typereferenceproperty.md) + +## IDocInterface6.typeReferenceProperty property + +**Signature:** + +\`\`\`typescript +typeReferenceProperty: Generic; +\`\`\` +", + "/api-documenter-test.idocinterface6.unionproperty.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface6](./api-documenter-test.idocinterface6.md) > [unionProperty](./api-documenter-test.idocinterface6.unionproperty.md) + +## IDocInterface6.unionProperty property + +**Signature:** + +\`\`\`typescript +unionProperty: IDocInterface1 | IDocInterface2; +\`\`\` +", + "/api-documenter-test.idocinterface7.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface7](./api-documenter-test.idocinterface7.md) + +## IDocInterface7 interface + +Interface for testing optional properties + +**Signature:** + +\`\`\`typescript +export interface IDocInterface7 +\`\`\` + +## Properties + + + + + +
+ +Property + + + + +Modifiers + + + + +Type + + + + +Description + + +
+ +[optionalField?](./api-documenter-test.idocinterface7.optionalfield.md) + + + + + + + +boolean + + + + +_(Optional)_ Description of optionalField + + +
+ +[optionalReadonlyField?](./api-documenter-test.idocinterface7.optionalreadonlyfield.md) + + + + +\`readonly\` + + + + +boolean + + + + +_(Optional)_ Description of optionalReadonlyField + + +
+ +[optionalUndocumentedField?](./api-documenter-test.idocinterface7.optionalundocumentedfield.md) + + + + + + + +boolean + + + + +_(Optional)_ + + +
+ +## Methods + + + +
+ +Method + + + + +Description + + +
+ +[optionalMember()?](./api-documenter-test.idocinterface7.optionalmember.md) + + + + +_(Optional)_ Description of optionalMember + + +
+ +", + "/api-documenter-test.idocinterface7.optionalfield.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface7](./api-documenter-test.idocinterface7.md) > [optionalField](./api-documenter-test.idocinterface7.optionalfield.md) + +## IDocInterface7.optionalField property + +Description of optionalField + +**Signature:** + +\`\`\`typescript +optionalField?: boolean; +\`\`\` +", + "/api-documenter-test.idocinterface7.optionalmember.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface7](./api-documenter-test.idocinterface7.md) > [optionalMember](./api-documenter-test.idocinterface7.optionalmember.md) + +## IDocInterface7.optionalMember() method + +Description of optionalMember + +**Signature:** + +\`\`\`typescript +optionalMember?(): any; +\`\`\` +**Returns:** + +any + +", + "/api-documenter-test.idocinterface7.optionalreadonlyfield.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface7](./api-documenter-test.idocinterface7.md) > [optionalReadonlyField](./api-documenter-test.idocinterface7.optionalreadonlyfield.md) + +## IDocInterface7.optionalReadonlyField property + +Description of optionalReadonlyField + +**Signature:** + +\`\`\`typescript +readonly optionalReadonlyField?: boolean; +\`\`\` +", + "/api-documenter-test.idocinterface7.optionalundocumentedfield.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface7](./api-documenter-test.idocinterface7.md) > [optionalUndocumentedField](./api-documenter-test.idocinterface7.optionalundocumentedfield.md) + +## IDocInterface7.optionalUndocumentedField property + +**Signature:** + +\`\`\`typescript +optionalUndocumentedField?: boolean; +\`\`\` +", + "/api-documenter-test.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) + +## api-documenter-test package + +api-extractor-test-05 + +This project tests various documentation generation scenarios and doc comment syntaxes. + +## Classes + + + + + + + + +
+ +Class + + + + +Description + + +
+ +[DecoratorExample](./api-documenter-test.decoratorexample.md) + + + + + + +
+ +[DocBaseClass](./api-documenter-test.docbaseclass.md) + + + + +Example base class + + + +
+ +[DocClass1](./api-documenter-test.docclass1.md) + + + + +This is an example class. + + +
+ +[DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) + + + + +Class that merges with interface + + +
+ +[Generic](./api-documenter-test.generic.md) + + + + +Generic class. + + +
+ +[SystemEvent](./api-documenter-test.systemevent.md) + + + + +A class used to exposed events. + + + +
+ +## Abstract Classes + + + +
+ +Abstract Class + + + + +Description + + +
+ +[AbstractClass](./api-documenter-test.abstractclass.md) + + + + +Some abstract class with abstract members. + + +
+ +## Enumerations + + + + +
+ +Enumeration + + + + +Description + + +
+ +[DocEnum](./api-documenter-test.docenum.md) + + + + +Docs for DocEnum + + + +
+ +[DocEnumNamespaceMerge](./api-documenter-test.docenumnamespacemerge.md) + + + + +Enum that merges with namespace + + +
+ +## Functions + + + + +
+ +Function + + + + +Description + + +
+ +[exampleFunction(x, y)](./api-documenter-test.examplefunction.md) + + + + +An exported function with hyperlinked parameters and return value. + + +
+ +[yamlReferenceUniquenessTest()](./api-documenter-test.yamlreferenceuniquenesstest.md) + + + + + + +
+ +## Interfaces + + + + + + + + + + + + +
+ +Interface + + + + +Description + + +
+ +[Constraint](./api-documenter-test.constraint.md) + + + + +Type parameter constraint used by test case below. + + +
+ +[DefaultType](./api-documenter-test.defaulttype.md) + + + + +Type parameter default type used by test case below. + + +
+ +[DocClassInterfaceMerge](./api-documenter-test.docclassinterfacemerge.md) + + + + +Interface that merges with class + + +
+ +[IDocInterface1](./api-documenter-test.idocinterface1.md) + + + + + + +
+ +[IDocInterface2](./api-documenter-test.idocinterface2.md) + + + + + + +
+ +[IDocInterface3](./api-documenter-test.idocinterface3.md) + + + + +Some less common TypeScript declaration kinds. + + + +
+ +[IDocInterface4](./api-documenter-test.idocinterface4.md) + + + + +Type union in an interface. + + + +
+ +[IDocInterface5](./api-documenter-test.idocinterface5.md) + + + + +Interface without inline tag to test custom TOC + + +
+ +[IDocInterface6](./api-documenter-test.idocinterface6.md) + + + + +Interface without inline tag to test custom TOC with injection + + +
+ +[IDocInterface7](./api-documenter-test.idocinterface7.md) + + + + +Interface for testing optional properties + + +
+ +## Namespaces + + + + + +
+ +Namespace + + + + +Description + + +
+ +[DocEnumNamespaceMerge](./api-documenter-test.docenumnamespacemerge.md) + + + + +Namespace that merges with enum + + +
+ +[EcmaSymbols](./api-documenter-test.ecmasymbols.md) + + + + +A namespace containing an ECMAScript symbol + + +
+ +[OuterNamespace](./api-documenter-test.outernamespace.md) + + + + +A top-level namespace + + +
+ +## Variables + + + +
+ +Variable + + + + +Description + + +
+ +[constVariable](./api-documenter-test.constvariable.md) + + + + +An exported variable declaration. + + +
+ +## Type Aliases + + + + + + + +
+ +Type Alias + + + + +Description + + +
+ +[ExampleDuplicateTypeAlias](./api-documenter-test.exampleduplicatetypealias.md) + + + + +A type alias that has duplicate references. + + +
+ +[ExampleTypeAlias](./api-documenter-test.exampletypealias.md) + + + + +A type alias + + +
+ +[ExampleUnionTypeAlias](./api-documenter-test.exampleuniontypealias.md) + + + + +A type alias that references multiple other types. + + +
+ +[GenericTypeAlias](./api-documenter-test.generictypealias.md) + + + + + + +
+ +[TypeAlias](./api-documenter-test.typealias.md) + + + + + + +
+ +", + "/api-documenter-test.outernamespace.innernamespace.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) + +## OuterNamespace.InnerNamespace namespace + +A nested namespace + +**Signature:** + +\`\`\`typescript +namespace InnerNamespace +\`\`\` + +## Functions + + + +
+ +Function + + + + +Description + + +
+ +[nestedFunction(x)](./api-documenter-test.outernamespace.innernamespace.nestedfunction.md) + + + + +A function inside a namespace + + +
+ +", + "/api-documenter-test.outernamespace.innernamespace.nestedfunction.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) > [nestedFunction](./api-documenter-test.outernamespace.innernamespace.nestedfunction.md) + +## OuterNamespace.InnerNamespace.nestedFunction() function + +A function inside a namespace + +**Signature:** + +\`\`\`typescript +function nestedFunction(x: number): number; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +x + + + + +number + + + + + +
+ +**Returns:** + +number + +", + "/api-documenter-test.outernamespace.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) + +## OuterNamespace namespace + +A top-level namespace + +**Signature:** + +\`\`\`typescript +export declare namespace OuterNamespace +\`\`\` + +## Namespaces + + + +
+ +Namespace + + + + +Description + + +
+ +[InnerNamespace](./api-documenter-test.outernamespace.innernamespace.md) + + + + +A nested namespace + + +
+ +## Variables + + + +
+ +Variable + + + + +Description + + +
+ +[nestedVariable](./api-documenter-test.outernamespace.nestedvariable.md) + + + + +A variable exported from within a namespace. + + +
+ +", + "/api-documenter-test.outernamespace.nestedvariable.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [OuterNamespace](./api-documenter-test.outernamespace.md) > [nestedVariable](./api-documenter-test.outernamespace.nestedvariable.md) + +## OuterNamespace.nestedVariable variable + +A variable exported from within a namespace. + +**Signature:** + +\`\`\`typescript +nestedVariable: boolean +\`\`\` +", + "/api-documenter-test.systemevent.addhandler.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [SystemEvent](./api-documenter-test.systemevent.md) > [addHandler](./api-documenter-test.systemevent.addhandler.md) + +## SystemEvent.addHandler() method + +Adds an handler for the event. + +**Signature:** + +\`\`\`typescript +addHandler(handler: () => void): void; +\`\`\` + +## Parameters + + + +
+ +Parameter + + + + +Type + + + + +Description + + +
+ +handler + + + + +() => void + + + + + +
+ +**Returns:** + +void + +", + "/api-documenter-test.systemevent.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [SystemEvent](./api-documenter-test.systemevent.md) + +## SystemEvent class + +A class used to exposed events. + + +**Signature:** + +\`\`\`typescript +export declare class SystemEvent +\`\`\` + +## Methods + + + +
+ +Method + + + + +Modifiers + + + + +Description + + +
+ +[addHandler(handler)](./api-documenter-test.systemevent.addhandler.md) + + + + + + + +Adds an handler for the event. + + +
+ +", + "/api-documenter-test.typealias.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [TypeAlias](./api-documenter-test.typealias.md) + +## TypeAlias type + + +**Signature:** + +\`\`\`typescript +export type TypeAlias = number; +\`\`\` +", + "/api-documenter-test.yamlreferenceuniquenesstest.md": " + +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [yamlReferenceUniquenessTest](./api-documenter-test.yamlreferenceuniquenesstest.md) + +## yamlReferenceUniquenessTest() function + + +**Signature:** + +\`\`\`typescript +export declare function yamlReferenceUniquenessTest(): IDocInterface1; +\`\`\` +**Returns:** + +[IDocInterface1](./api-documenter-test.idocinterface1.md) + +", + "/index.md": " + +[Home](./index.md) + +## API Reference + +## Packages + + + +
+ +Package + + + + +Description + + +
+ +[api-documenter-test](./api-documenter-test.md) + + + + +api-extractor-test-05 + +This project tests various documentation generation scenarios and doc comment syntaxes. + + +
+ +", +} +`; diff --git a/build-tests/api-documenter-test/src/test/snapshot.test.ts b/build-tests/api-documenter-test/src/test/snapshot.test.ts new file mode 100644 index 00000000000..a1019e7d538 --- /dev/null +++ b/build-tests/api-documenter-test/src/test/snapshot.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 { + Async, + Executable, + FileSystem, + type FolderItem, + PackageJsonLookup +} from '@rushstack/node-core-library'; +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'); + +interface IFolderItem { + absolutePath: string; + relativePath: string; +} +async function* readFolderItemsAsync( + folderAbsolutePath: string, + folderRelativePat: string +): AsyncIterable { + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(folderAbsolutePath); + for (const folderItem of folderItems) { + const itemAbsolutePath: string = `${folderAbsolutePath}/${folderItem.name}`; + const itemRelativePath: string = `${folderRelativePat}/${folderItem.name}`; + if (folderItem.isFile()) { + yield { absolutePath: itemAbsolutePath, relativePath: itemRelativePath }; + } else { + yield* readFolderItemsAsync(itemAbsolutePath, itemRelativePath); + } + } +} + +async function runApiDocumenterAsync(verb: string, outputFolderName: string): Promise { + if (!PROJECT_FOLDER) { + throw new Error('Cannot find package.json'); + } + + const outputPath: string = `${PROJECT_FOLDER}/temp/${outputFolderName}`; + + const apiDocumenterProcess = Executable.spawn( + process.argv0, + [API_DOCUMENTER_PATH, verb, '--input-folder', 'etc', '--output-folder', outputPath], + { + currentWorkingDirectory: PROJECT_FOLDER, + stdio: 'pipe' + } + ); + + const { exitCode } = await Executable.waitForExitAsync(apiDocumenterProcess); + + expect(exitCode).toBe(0); + + const itemContents: Record = {}; + await Async.forEachAsync( + readFolderItemsAsync(outputPath, ''), + async ({ relativePath, absolutePath }) => { + itemContents[relativePath] = await FileSystem.readFileAsync(absolutePath); + }, + { concurrency: 50 } + ); + + const sortedEntries: [string, string][] = Object.entries(itemContents).sort(([a], [b]) => + a.localeCompare(b) + ); + expect(Object.fromEntries(sortedEntries)).toMatchSnapshot('itemContents'); +} + +describe('api-documenter', () => { + it('YAML', async () => { + await runApiDocumenterAsync('generate', 'yaml'); + }); + + it('markdown', async () => { + await runApiDocumenterAsync('markdown', 'markdown'); + }); +}); diff --git a/build-tests/api-documenter-test/tsconfig.json b/build-tests/api-documenter-test/tsconfig.json index de8969fb815..d1f567b6358 100644 --- a/build-tests/api-documenter-test/tsconfig.json +++ b/build-tests/api-documenter-test/tsconfig.json @@ -1,29 +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" - }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "strictPropertyInitialization": false, + "noImplicitAny": false + } +} diff --git a/build-tests/api-documenter-test/tsdoc.json b/build-tests/api-documenter-test/tsdoc.json new file mode 100644 index 00000000000..01b094bee3e --- /dev/null +++ b/build-tests/api-documenter-test/tsdoc.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + + "extends": ["@microsoft/api-extractor/extends/tsdoc-base.json"], + + "tagDefinitions": [ + { + "tagName": "@docCategory", + "syntaxKind": "inline" + }, + { + "tagName": "@myCustomTag", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@myCustomTag": true, + "@docCategory": true + } +} diff --git a/build-tests/api-extractor-d-cts-test/.gitignore b/build-tests/api-extractor-d-cts-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/.gitignore @@ -0,0 +1,4 @@ +# 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-d-cts-test/config/api-extractor.json b/build-tests/api-extractor-d-cts-test/config/api-extractor.json new file mode 100644 index 00000000000..10c1ae9abdc --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/config/api-extractor.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.cts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/dist/.d.cts", + "alphaTrimmedFilePath": "/dist/-alpha.d.cts", + "publicTrimmedFilePath": "/dist/-public.d.cts" + }, + + "testMode": 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/etc/api-extractor-d-cts-test.api.md b/build-tests/api-extractor-d-cts-test/etc/api-extractor-d-cts-test.api.md new file mode 100644 index 00000000000..163443bda1a --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/etc/api-extractor-d-cts-test.api.md @@ -0,0 +1,22 @@ +## API Report File for "api-extractor-d-cts-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +class DefaultClass { +} +export default DefaultClass; + +// @public (undocumented) +export class Lib5Class { + // (undocumented) + prop: number; +} + +// @alpha (undocumented) +export interface Lib5Interface { +} + +``` diff --git a/build-tests/api-extractor-d-cts-test/package.json b/build-tests/api-extractor-d-cts-test/package.json new file mode 100644 index 00000000000..079c283f9f6 --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/package.json @@ -0,0 +1,16 @@ +{ + "name": "api-extractor-d-cts-test", + "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", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/api-extractor-d-cts-test/src/index.cts b/build-tests/api-extractor-d-cts-test/src/index.cts new file mode 100644 index 00000000000..754a8ba3af5 --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/src/index.cts @@ -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. + +/** + * api-extractor-d-cts-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export class Lib5Class { + prop: number; +} + +/** @alpha */ +export interface Lib5Interface {} + +/** @public */ +export default class DefaultClass {} diff --git a/build-tests/api-extractor-d-cts-test/tsconfig.json b/build-tests/api-extractor-d-cts-test/tsconfig.json new file mode 100644 index 00000000000..00f29d003a2 --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "strictPropertyInitialization": false + }, + "include": ["src/**/*.cts", "typings/tsd.d.ts"] +} diff --git a/build-tests/api-extractor-d-mts-test/.gitignore b/build-tests/api-extractor-d-mts-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/.gitignore @@ -0,0 +1,4 @@ +# 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-d-mts-test/config/api-extractor.json b/build-tests/api-extractor-d-mts-test/config/api-extractor.json new file mode 100644 index 00000000000..0d47ad78c14 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/config/api-extractor.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.mts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/dist/.d.mts", + "alphaTrimmedFilePath": "/dist/-alpha.d.mts", + "publicTrimmedFilePath": "/dist/-public.d.mts" + }, + + "testMode": 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/etc/api-extractor-d-mts-test.api.md b/build-tests/api-extractor-d-mts-test/etc/api-extractor-d-mts-test.api.md new file mode 100644 index 00000000000..f1aeecb6710 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/etc/api-extractor-d-mts-test.api.md @@ -0,0 +1,22 @@ +## API Report File for "api-extractor-d-mts-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +class DefaultClass { +} +export default DefaultClass; + +// @public (undocumented) +export class Lib4Class { + // (undocumented) + prop: number; +} + +// @alpha (undocumented) +export interface Lib4Interface { +} + +``` diff --git a/build-tests/api-extractor-d-mts-test/package.json b/build-tests/api-extractor-d-mts-test/package.json new file mode 100644 index 00000000000..519d68ec8d3 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/package.json @@ -0,0 +1,17 @@ +{ + "name": "api-extractor-d-mts-test", + "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", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/api-extractor-d-mts-test/src/index.mts b/build-tests/api-extractor-d-mts-test/src/index.mts new file mode 100644 index 00000000000..6b2966543e7 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/src/index.mts @@ -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. + +/** + * api-extractor-d-mts-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export class Lib4Class { + prop: number; +} + +/** @alpha */ +export interface Lib4Interface {} + +/** @public */ +export default class DefaultClass {} diff --git a/build-tests/api-extractor-d-mts-test/tsconfig.json b/build-tests/api-extractor-d-mts-test/tsconfig.json new file mode 100644 index 00000000000..85306f1bec6 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "strictPropertyInitialization": false + }, + "include": ["src/**/*.mts", "typings/tsd.d.ts"] +} diff --git a/build-tests/api-extractor-lib1-test/.gitignore b/build-tests/api-extractor-lib1-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-lib1-test/.gitignore @@ -0,0 +1,4 @@ +# 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-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 2a20b332f5f..5b20206dabc 100644 --- a/build-tests/api-extractor-lib1-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib1-test/config/api-extractor.json @@ -5,6 +5,7 @@ "apiReport": { "enabled": true, + "reportFileName": "" }, "docModel": { 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-lib1-test/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"] + } + ] +} diff --git a/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts b/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts new file mode 100644 index 00000000000..19117b01216 --- /dev/null +++ b/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts @@ -0,0 +1,39 @@ +/** + * api-extractor-lib1-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export declare class Lib1Class extends Lib1ForgottenExport { + readonly readonlyProperty: string; + writeableProperty: string; +} + +declare class Lib1ForgottenExport { +} + +/** @public */ +export declare type Lib1GenericType = { + one: T1; + two: T2; +}; + +/** @alpha */ +export declare interface Lib1Interface { +} + +/** @public */ +export declare namespace Lib1Namespace { + export namespace Inner { + export class X { + } + } + export class Y { + } +} + +export { } diff --git a/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md b/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md index 5e1bb5628ce..ae7e32783b4 100644 --- a/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md +++ b/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md @@ -14,9 +14,27 @@ export class Lib1Class extends Lib1ForgottenExport { writeableProperty: string; } +// @public (undocumented) +export type Lib1GenericType = { + one: T1; + two: T2; +}; + // @alpha (undocumented) export interface Lib1Interface { } +// @public (undocumented) +export namespace Lib1Namespace { + // (undocumented) + export namespace Inner { + // (undocumented) + export class X { + } + } + // (undocumented) + export class Y { + } +} ``` diff --git a/build-tests/api-extractor-lib1-test/package.json b/build-tests/api-extractor-lib1-test/package.json index fc7091b9c21..365b5a88296 100644 --- a/build-tests/api-extractor-lib1-test/package.json +++ b/build-tests/api-extractor-lib1-test/package.json @@ -6,13 +6,12 @@ "main": "lib/index.js", "typings": "dist/api-extractor-lib1-test.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~2.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*", + "typescript": "~2.9.2" } } diff --git a/build-tests/api-extractor-lib1-test/src/Lib1ForgottenExport.ts b/build-tests/api-extractor-lib1-test/src/Lib1ForgottenExport.ts index 32b51d5afd1..0705243922a 100644 --- a/build-tests/api-extractor-lib1-test/src/Lib1ForgottenExport.ts +++ b/build-tests/api-extractor-lib1-test/src/Lib1ForgottenExport.ts @@ -1,5 +1,4 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -export class Lib1ForgottenExport { -} +export class Lib1ForgottenExport {} diff --git a/build-tests/api-extractor-lib1-test/src/Lib1GenericType.ts b/build-tests/api-extractor-lib1-test/src/Lib1GenericType.ts new file mode 100644 index 00000000000..3fde99577a9 --- /dev/null +++ b/build-tests/api-extractor-lib1-test/src/Lib1GenericType.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. + +/** @public */ +export type Lib1GenericType = { + one: T1; + two: T2; +}; diff --git a/build-tests/api-extractor-lib1-test/src/Lib1Namespace.ts b/build-tests/api-extractor-lib1-test/src/Lib1Namespace.ts new file mode 100644 index 00000000000..2ee886f35e9 --- /dev/null +++ b/build-tests/api-extractor-lib1-test/src/Lib1Namespace.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. + +/** @public */ +export namespace Lib1Namespace { + export namespace Inner { + export class X {} + } + export class Y {} +} diff --git a/build-tests/api-extractor-lib1-test/src/index.ts b/build-tests/api-extractor-lib1-test/src/index.ts index 8ec896a452e..b55be95a87b 100644 --- a/build-tests/api-extractor-lib1-test/src/index.ts +++ b/build-tests/api-extractor-lib1-test/src/index.ts @@ -21,10 +21,11 @@ export class Lib1Class extends Lib1ForgottenExport { public get writeableProperty(): string { return 'hello'; } - public set writeableProperty(value: string) { - } + public set writeableProperty(value: string) {} } /** @alpha */ -export interface Lib1Interface { -} +export interface Lib1Interface {} + +export { Lib1GenericType } from './Lib1GenericType'; +export { Lib1Namespace } from './Lib1Namespace'; diff --git a/build-tests/api-extractor-lib1-test/tsconfig.json b/build-tests/api-extractor-lib1-test/tsconfig.json index 76bd8f2d5ef..d080f1b1613 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,22 +8,8 @@ "sourceMap": true, "experimentalDecorators": true, "strictNullChecks": true, - "types": [ - "node", - "jest" - ], - "lib": [ - "es5", - "scripthost", - "es2015.collection", - "es2015.promise", - "es2015.iterable", - "dom" - ], + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable"], "outDir": "lib" }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "include": ["src/**/*.ts"] +} diff --git a/build-tests/api-extractor-lib2-test/.gitignore b/build-tests/api-extractor-lib2-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-lib2-test/.gitignore @@ -0,0 +1,4 @@ +# 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-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 2a20b332f5f..ee4ca44dae3 100644 --- a/build-tests/api-extractor-lib2-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib2-test/config/api-extractor.json @@ -5,6 +5,8 @@ "apiReport": { "enabled": true, + "reportFileName": ".api.md", + "reportVariants": ["alpha", "public", "complete"] }, "docModel": { 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-lib2-test/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"] + } + ] +} 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 new file mode 100644 index 00000000000..2816f40985f --- /dev/null +++ b/build-tests/api-extractor-lib2-test/dist/api-extractor-lib2-test.d.ts @@ -0,0 +1,24 @@ +/** + * api-extractor-lib2-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @beta */ +declare class DefaultClass { +} +export default DefaultClass; + +/** @public */ +export declare class Lib2Class { + prop: number; +} + +/** @alpha */ +export declare interface Lib2Interface { +} + +export { } 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 new file mode 100644 index 00000000000..145cfdd01b5 --- /dev/null +++ b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.alpha.api.md @@ -0,0 +1,22 @@ +## Alpha API Report File for "api-extractor-lib2-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @beta (undocumented) +class DefaultClass { +} +export default DefaultClass; + +// @public (undocumented) +export class Lib2Class { + // (undocumented) + prop: number; +} + +// @alpha (undocumented) +export interface Lib2Interface { +} + +``` 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 ec34e84c375..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,13 +4,19 @@ ```ts +// @beta (undocumented) +class DefaultClass { +} +export default DefaultClass; + // @public (undocumented) export class Lib2Class { + // (undocumented) + prop: number; } // @alpha (undocumented) export interface Lib2Interface { } - ``` 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 new file mode 100644 index 00000000000..87ca7608c88 --- /dev/null +++ b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.public.api.md @@ -0,0 +1,13 @@ +## Public API Report File for "api-extractor-lib2-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class Lib2Class { + // (undocumented) + prop: number; +} + +``` diff --git a/build-tests/api-extractor-lib2-test/package.json b/build-tests/api-extractor-lib2-test/package.json index 81e1d5f4f8b..37b754bcdc4 100644 --- a/build-tests/api-extractor-lib2-test/package.json +++ b/build-tests/api-extractor-lib2-test/package.json @@ -6,13 +6,11 @@ "main": "lib/index.js", "typings": "dist/api-extractor-lib2-test.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~3.7.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 852d8076d30..616e9f7f9f2 100644 --- a/build-tests/api-extractor-lib2-test/src/index.ts +++ b/build-tests/api-extractor-lib2-test/src/index.ts @@ -12,8 +12,11 @@ /** @public */ export class Lib2Class { + prop: number; } /** @alpha */ -export interface Lib2Interface { -} +export interface Lib2Interface {} + +/** @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 de8969fb815..d5641d0ba38 100644 --- a/build-tests/api-extractor-lib2-test/tsconfig.json +++ b/build-tests/api-extractor-lib2-test/tsconfig.json @@ -1,29 +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" - ] -} \ No newline at end of file + "strictPropertyInitialization": false + } +} diff --git a/build-tests/api-extractor-lib3-test/.gitignore b/build-tests/api-extractor-lib3-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-lib3-test/.gitignore @@ -0,0 +1,4 @@ +# 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-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 2a20b332f5f..25114fb98e4 100644 --- a/build-tests/api-extractor-lib3-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib3-test/config/api-extractor.json @@ -5,6 +5,13 @@ "apiReport": { "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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-lib3-test/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"] + } + ] +} 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 new file mode 100644 index 00000000000..d809db353f7 --- /dev/null +++ b/build-tests/api-extractor-lib3-test/dist/api-extractor-lib3-test.d.ts @@ -0,0 +1,27 @@ +/** + * api-extractor-lib3-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +import { Lib1Class } from 'api-extractor-lib1-test'; + +export { Lib1Class } + +/** + * @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; +} + +export { } 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 b08047ac72e..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,5 +8,10 @@ import { Lib1Class } from 'api-extractor-lib1-test'; export { Lib1Class } +// @public @internalRemarks (undocumented) +export class Lib3Class { + // @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 b0546226475..cbe9648a084 100644 --- a/build-tests/api-extractor-lib3-test/package.json +++ b/build-tests/api-extractor-lib3-test/package.json @@ -6,16 +6,15 @@ "main": "lib/index.js", "typings": "dist/api-extractor-lib3-test.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "api-extractor-lib1-test": "1.0.0" + "api-extractor-lib1-test": "workspace:*" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "@microsoft/api-extractor": "workspace:*", + "@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 c4b8f3ccee4..8d41743a7e8 100644 --- a/build-tests/api-extractor-lib3-test/src/index.ts +++ b/build-tests/api-extractor-lib3-test/src/index.ts @@ -11,3 +11,17 @@ */ export { Lib1Class } from 'api-extractor-lib1-test'; + +/** + * @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 de8969fb815..d5641d0ba38 100644 --- a/build-tests/api-extractor-lib3-test/tsconfig.json +++ b/build-tests/api-extractor-lib3-test/tsconfig.json @@ -1,29 +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" - ] -} \ No newline at end of file + "strictPropertyInitialization": false + } +} diff --git a/build-tests/api-extractor-lib4-test/.gitignore b/build-tests/api-extractor-lib4-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-lib4-test/.gitignore @@ -0,0 +1,4 @@ +# 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-lib4-test/config/api-extractor.json b/build-tests/api-extractor-lib4-test/config/api-extractor.json new file mode 100644 index 00000000000..609b62dc032 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true + }, + + "testMode": 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/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"] + } + ] +} diff --git a/build-tests/api-extractor-lib4-test/dist/api-extractor-lib4-test.d.ts b/build-tests/api-extractor-lib4-test/dist/api-extractor-lib4-test.d.ts new file mode 100644 index 00000000000..372aca18620 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/dist/api-extractor-lib4-test.d.ts @@ -0,0 +1,17 @@ +/** + * api-extractor-lib4-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export declare enum Lib4Enum { + Foo = "Foo", + Bar = "Bar", + Baz = "Baz" +} + +export { } diff --git a/build-tests/api-extractor-lib4-test/etc/api-extractor-lib4-test.api.md b/build-tests/api-extractor-lib4-test/etc/api-extractor-lib4-test.api.md new file mode 100644 index 00000000000..292d6ec7cb3 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/etc/api-extractor-lib4-test.api.md @@ -0,0 +1,17 @@ +## API Report File for "api-extractor-lib4-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export enum Lib4Enum { + // (undocumented) + Bar = "Bar", + // (undocumented) + Baz = "Baz", + // (undocumented) + Foo = "Foo" +} + +``` diff --git a/build-tests/api-extractor-lib4-test/package.json b/build-tests/api-extractor-lib4-test/package.json new file mode 100644 index 00000000000..7be152c199d --- /dev/null +++ b/build-tests/api-extractor-lib4-test/package.json @@ -0,0 +1,16 @@ +{ + "name": "api-extractor-lib4-test", + "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", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/api-extractor-lib4-test/src/index.ts b/build-tests/api-extractor-lib4-test/src/index.ts new file mode 100644 index 00000000000..768db739ed4 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/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. + +/** + * api-extractor-lib4-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export enum Lib4Enum { + Foo = 'Foo', + Bar = 'Bar', + Baz = 'Baz' +} diff --git a/build-tests/api-extractor-lib4-test/tsconfig.json b/build-tests/api-extractor-lib4-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/api-extractor-lib5-test/.gitignore b/build-tests/api-extractor-lib5-test/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-lib5-test/.gitignore @@ -0,0 +1,4 @@ +# 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-lib5-test/config/api-extractor.json b/build-tests/api-extractor-lib5-test/config/api-extractor.json new file mode 100644 index 00000000000..609b62dc032 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true + }, + + "testMode": 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/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"] + } + ] +} diff --git a/build-tests/api-extractor-lib5-test/dist/api-extractor-lib5-test.d.ts b/build-tests/api-extractor-lib5-test/dist/api-extractor-lib5-test.d.ts new file mode 100644 index 00000000000..b7b1090bfe0 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/dist/api-extractor-lib5-test.d.ts @@ -0,0 +1,13 @@ +/** + * api-extractor-lib5-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export declare function lib5Function(): number; + +export { } diff --git a/build-tests/api-extractor-lib5-test/etc/api-extractor-lib5-test.api.md b/build-tests/api-extractor-lib5-test/etc/api-extractor-lib5-test.api.md new file mode 100644 index 00000000000..7c49cb23de0 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/etc/api-extractor-lib5-test.api.md @@ -0,0 +1,10 @@ +## API Report File for "api-extractor-lib5-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export function lib5Function(): number; + +``` diff --git a/build-tests/api-extractor-lib5-test/package.json b/build-tests/api-extractor-lib5-test/package.json new file mode 100644 index 00000000000..f6ae8df3aad --- /dev/null +++ b/build-tests/api-extractor-lib5-test/package.json @@ -0,0 +1,16 @@ +{ + "name": "api-extractor-lib5-test", + "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", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/api-extractor-lib5-test/src/index.ts b/build-tests/api-extractor-lib5-test/src/index.ts new file mode 100644 index 00000000000..92b95d65880 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/src/index.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. + +/** + * api-extractor-lib5-test + * + * @remarks + * This library is consumed by api-extractor-scenarios. + * + * @packageDocumentation + */ + +/** @public */ +export function lib5Function(): number { + return 42; +} diff --git a/build-tests/api-extractor-lib5-test/tsconfig.json b/build-tests/api-extractor-lib5-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/api-extractor-scenarios/build.js b/build-tests/api-extractor-scenarios/build.js deleted file mode 100644 index b15b2f947ca..00000000000 --- a/build-tests/api-extractor-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/test-outputs'); - -// 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-extractor-scenarios/config/build-config.json b/build-tests/api-extractor-scenarios/config/build-config.json deleted file mode 100644 index f8ad516b6bd..00000000000 --- a/build-tests/api-extractor-scenarios/config/build-config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "scenarioFolderNames": [ - "ambientNameConflict", - "ambientNameConflict2", - "ancillaryDeclarations", - "apiItemKinds", - "bundledPackages", - "circularImport", - "circularImport2", - "defaultExportOfEntryPoint", - "defaultExportOfEntryPoint2", - "defaultExportOfEntryPoint3", - "defaultExportOfEntryPoint4", - "docReferences", - "docReferences2", - "docReferences3", - "exportDuplicate", - "exportEquals", - "exportImportedExternal", - "exportImportedExternal2", - "exportStar", - "exportStar2", - "exportStar3", - "functionOverload", - "importEquals", - "inconsistentReleaseTags", - "internationalCharacters", - "preapproved", - "typeOf", - "typeOf2", - "typeParameters" - ] -} diff --git a/build-tests/api-extractor-scenarios/config/heft.json b/build-tests/api-extractor-scenarios/config/heft.json new file mode 100644 index 00000000000..ed5856420ce --- /dev/null +++ b/build-tests/api-extractor-scenarios/config/heft.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "cleanFiles": [ + { + "sourcePath": "temp/etc", + "includeGlobs": ["**/*"] + }, + { + "sourcePath": "temp/configs", + "includeGlobs": ["**/*"] + } + ], + + "tasksByName": { + "copy-dts": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src", + "destinationFolders": ["lib"], + "fileExtensions": [".d.ts"] + } + ] + } + } + }, + + "run-scenarios": { + "taskDependencies": ["typescript", "copy-dts"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./lib/runScenarios.js" + } + } + } + } + } + } +} diff --git a/build-tests/api-extractor-scenarios/config/rig.json b/build-tests/api-extractor-scenarios/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-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-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..174025c1db3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json @@ -0,0 +1,265 @@ +{ + "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!ambientNameConflict:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function ambientNameConflict(p1: " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": ", p2: " + }, + { + "kind": "Reference", + "text": "MyPromise", + "canonicalReference": "api-extractor-scenarios!~Promise_2:class" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/ambientNameConflict/index.ts", + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "p1", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isOptional": false + }, + { + "parameterName": "p2", + "parameterTypeTokenRange": { + "startIndex": 4, + "endIndex": 6 + }, + "isOptional": false + } + ], + "name": "ambientNameConflict" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..570e8a2cc45 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/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 "Promise_2" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function ambientNameConflict(p1: Promise, p2: Promise_2): void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/rollup.d.ts new file mode 100644 index 00000000000..43ea4335316 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/rollup.d.ts @@ -0,0 +1,13 @@ +/** + * @public + */ +export declare function ambientNameConflict(p1: Promise, p2: Promise_2): void; + +/** + * @public + */ +declare class Promise_2 { + notTheRealPromise(arg: T): void; +} + +export { } 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 new file mode 100644 index 00000000000..d949bb58ab1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.json @@ -0,0 +1,241 @@ +{ + "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!Date_2:class", + "docComment": "/**\n * A local class declaration whose name is the same as the system `Date` global symbol.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Date " + } + ], + "fileUrlPath": "src/ambientNameConflict2/Date.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Date_2", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!getDate:function(1)", + "docComment": "/**\n * An API that references the system `Date` global symbol.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function getDate(): " + }, + { + "kind": "Reference", + "text": "Date", + "canonicalReference": "!Date:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/ambientNameConflict2/getDate.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "getDate" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..8d577f6bf86 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.md @@ -0,0 +1,17 @@ +## 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 +class Date_2 { +} +export { Date_2 as Date } + +// @public +export function getDate(): Date; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/rollup.d.ts new file mode 100644 index 00000000000..84bc46b4391 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/rollup.d.ts @@ -0,0 +1,15 @@ +/** + * A local class declaration whose name is the same as the system `Date` global symbol. + * @public + */ +declare class Date_2 { +} +export { Date_2 as Date } + +/** + * An API that references the system `Date` global symbol. + * @public + */ +export declare function getDate(): Date; + +export { } 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 new file mode 100644 index 00000000000..6d63ae3142c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!MyClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class MyClass " + } + ], + "fileUrlPath": "src/ancillaryDeclarations/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MyClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..fcc0a8e2941 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.md @@ -0,0 +1,22 @@ +## 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 + +// @internal (undocumented) +export interface _IInternalThing { + // (undocumented) + title: string; +} + +// @public (undocumented) +export class MyClass { + // @internal (undocumented) + get _thing(): _IInternalThing; + set _thing(value: _IInternalThing); +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/rollup.d.ts new file mode 100644 index 00000000000..0cdab3977cc --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/rollup.d.ts @@ -0,0 +1,13 @@ +/** @internal */ +export declare interface _IInternalThing { + title: string; +} + +/** @public */ +export declare class MyClass { + /** @internal */ + get _thing(): _IInternalThing; + set _thing(value: _IInternalThing); +} + +export { } 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 new file mode 100644 index 00000000000..c22e4d5b525 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.json @@ -0,0 +1,987 @@ +{ + "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!AbstractClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare abstract class AbstractClass " + } + ], + "fileUrlPath": "src/apiItemKinds/classes.ts", + "releaseTag": "Public", + "isAbstract": true, + "name": "AbstractClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!AbstractClass#member:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "abstract member(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": true, + "name": "member" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!ClassWithTypeParameter:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ClassWithTypeParameter " + } + ], + "fileUrlPath": "src/apiItemKinds/classes.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "isAbstract": false, + "name": "ClassWithTypeParameter", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!CONST_VARIABLE:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "CONST_VARIABLE: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/apiItemKinds/variables.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "CONST_VARIABLE", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Enum", + "canonicalReference": "api-extractor-scenarios!ConstEnum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare const enum ConstEnum " + } + ], + "fileUrlPath": "src/apiItemKinds/enums.ts", + "releaseTag": "Public", + "name": "ConstEnum", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.One:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "One = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "One" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.Two:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Two = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Two" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.Zero:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Zero = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Zero" + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!ExtendsClassWithTypeParameter:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExtendsClassWithTypeParameter extends " + }, + { + "kind": "Reference", + "text": "ClassWithTypeParameter", + "canonicalReference": "api-extractor-scenarios!ClassWithTypeParameter:class" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "SimpleClass", + "canonicalReference": "api-extractor-scenarios!SimpleClass:class" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/apiItemKinds/classes.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExtendsClassWithTypeParameter", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 5 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!IInterface:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IInterface " + } + ], + "fileUrlPath": "src/apiItemKinds/interfaces.ts", + "releaseTag": "Public", + "name": "IInterface", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IInterface#member:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "member: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "member", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!n1:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace n1 " + } + ], + "fileUrlPath": "src/apiItemKinds/namespaces.ts", + "releaseTag": "Public", + "name": "n1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!n1.n2:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export namespace n2 " + } + ], + "releaseTag": "Public", + "name": "n2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!n1.n2.SomeClass3:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class SomeClass3 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass3", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!n1.SomeClass1:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class SomeClass1 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass1", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!n1.SomeClass2:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export class SomeClass2 extends " + }, + { + "kind": "Reference", + "text": "SomeClass1", + "canonicalReference": "api-extractor-scenarios!n1~SomeClass1:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass2", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!n1.SomeClass4:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class SomeClass4 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass4", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!nonConstVariable:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "nonConstVariable: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/apiItemKinds/variables.ts", + "isReadonly": false, + "releaseTag": "Public", + "name": "nonConstVariable", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Enum", + "canonicalReference": "api-extractor-scenarios!RegularEnum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum RegularEnum " + } + ], + "fileUrlPath": "src/apiItemKinds/enums.ts", + "releaseTag": "Public", + "name": "RegularEnum", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.One:member", + "docComment": "/**\n * These are some docs for One\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "One = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "One" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.Two:member", + "docComment": "/**\n * These are some docs for Two\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Two = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Two" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.Zero:member", + "docComment": "/**\n * These are some docs for Zero\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Zero = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Zero" + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SimpleClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SimpleClass " + } + ], + "fileUrlPath": "src/apiItemKinds/classes.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SimpleClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!SimpleClass#member:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "member(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "member" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!SimpleClass#optionalParamMethod:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "optionalParamMethod(x?: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": true + } + ], + "isOptional": false, + "isAbstract": false, + "name": "optionalParamMethod" + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!SimpleClass#readonlyProperty:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "get readonlyProperty(): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "readonlyProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!SimpleClass#someReadonlyProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly someReadonlyProp = " + }, + { + "kind": "Content", + "text": "5" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "someReadonlyProp", + "propertyTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!SimpleClass#someReadonlyPropWithType:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly someReadonlyPropWithType: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "someReadonlyPropWithType", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!SimpleClass#writeableProperty:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "get writeableProperty(): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";\n\nset writeableProperty(value: string);" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "writeableProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/apiItemKinds/functions.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction" + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!SomeType:type", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type SomeType = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/apiItemKinds/typeAliases.ts", + "releaseTag": "Public", + "name": "SomeType", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!VARIABLE_WITHOUT_EXPLICIT_TYPE:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "VARIABLE_WITHOUT_EXPLICIT_TYPE = " + }, + { + "kind": "Content", + "text": "\"hello\"" + } + ], + "fileUrlPath": "src/apiItemKinds/variables.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "VARIABLE_WITHOUT_EXPLICIT_TYPE", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] +} 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 new file mode 100644 index 00000000000..c0743f1c37e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md @@ -0,0 +1,102 @@ +## 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 abstract class AbstractClass { + // (undocumented) + abstract member(): void; +} + +// @public (undocumented) +export class ClassWithTypeParameter { +} + +// @public (undocumented) +export const CONST_VARIABLE: string; + +// @public (undocumented) +export const enum ConstEnum { + // (undocumented) + One = 1, + // (undocumented) + Two = 2, + // (undocumented) + Zero = 0 +} + +// @public (undocumented) +export class ExtendsClassWithTypeParameter extends ClassWithTypeParameter { +} + +// @public (undocumented) +export interface IInterface { + // (undocumented) + member: string; +} + +// @public (undocumented) +export namespace n1 { + // (undocumented) + export namespace n2 { + // (undocumented) + export class SomeClass3 { + } + } + // (undocumented) + export class SomeClass1 { + } + // (undocumented) + export class SomeClass2 extends SomeClass1 { + } + {}; +} + +// @public (undocumented) +export namespace n1 { + // (undocumented) + export class SomeClass4 { + } +} + +// @public (undocumented) +export let nonConstVariable: string; + +// @public (undocumented) +export enum RegularEnum { + One = 1, + Two = 2, + Zero = 0 +} + +// @public (undocumented) +export class SimpleClass { + // (undocumented) + member(): void; + // (undocumented) + optionalParamMethod(x?: number): void; + // (undocumented) + get readonlyProperty(): string; + // (undocumented) + readonly someReadonlyProp = 5; + // (undocumented) + readonly someReadonlyPropWithType: number; + // (undocumented) + get writeableProperty(): string; + set writeableProperty(value: string); +} + +// @public (undocumented) +export function someFunction(): void; + +// @public (undocumented) +export type SomeType = number; + +// @public (undocumented) +export const VARIABLE_WITHOUT_EXPLICIT_TYPE = "hello"; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts new file mode 100644 index 00000000000..dbe1c3219c1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts @@ -0,0 +1,87 @@ +/** @public */ +export declare abstract class AbstractClass { + abstract member(): void; +} + +/** @public */ +export declare class ClassWithTypeParameter { +} + +/** @public */ +export declare const CONST_VARIABLE: string; + +/** @public */ +export declare const enum ConstEnum { + Zero = 0, + One = 1, + Two = 2 +} + +/** @public */ +export declare class ExtendsClassWithTypeParameter extends ClassWithTypeParameter { +} + +/** @public */ +export declare interface IInterface { + member: string; +} + +/** @public */ +export declare namespace n1 { + export class SomeClass1 { + } + export class SomeClass2 extends SomeClass1 { + } + export namespace n2 { + export class SomeClass3 { + } + } + {}; +} + +/** @public */ +export declare namespace n1 { + export class SomeClass4 { + } +} + +/** @public */ +export declare let nonConstVariable: string; + +/** @public */ +export declare enum RegularEnum { + /** + * These are some docs for Zero + */ + Zero = 0, + /** + * These are some docs for One + */ + One = 1, + /** + * These are some docs for Two + */ + Two = 2 +} + +/** @public */ +export declare class SimpleClass { + member(): void; + optionalParamMethod(x?: number): void; + get readonlyProperty(): string; + get writeableProperty(): string; + set writeableProperty(value: string); + readonly someReadonlyProp = 5; + readonly someReadonlyPropWithType: number; +} + +/** @public */ +export declare function someFunction(): void; + +/** @public */ +export declare type SomeType = number; + +/** @public */ +export declare const VARIABLE_WITHOUT_EXPLICIT_TYPE = "hello"; + +export { } 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 new file mode 100644 index 00000000000..89ee7044200 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.json @@ -0,0 +1,540 @@ +{ + "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!f:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f(arg1: " + }, + { + "kind": "Reference", + "text": "Lib1Class", + "canonicalReference": "api-extractor-scenarios!Lib1Class:class" + }, + { + "kind": "Content", + "text": ", arg2: " + }, + { + "kind": "Reference", + "text": "Lib2Class", + "canonicalReference": "api-extractor-scenarios!Lib2Class:class" + }, + { + "kind": "Content", + "text": ", arg3: " + }, + { + "kind": "Reference", + "text": "Lib3Class", + "canonicalReference": "api-extractor-lib3-test!Lib3Class:class" + }, + { + "kind": "Content", + "text": ", arg4: " + }, + { + "kind": "Reference", + "text": "Lib4Enum", + "canonicalReference": "api-extractor-scenarios!Lib4Enum:enum" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/bundledPackages/index.ts", + "returnTypeTokenRange": { + "startIndex": 9, + "endIndex": 10 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "arg1", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "arg2", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + }, + { + "parameterName": "arg3", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "isOptional": false + }, + { + "parameterName": "arg4", + "parameterTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + }, + "isOptional": false + } + ], + "name": "f" + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Lib1Class:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Lib1Class extends " + }, + { + "kind": "Reference", + "text": "Lib1ForgottenExport", + "canonicalReference": "api-extractor-scenarios!Lib1ForgottenExport:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "../api-extractor-lib1-test/lib/index.d.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Lib1Class", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Lib1Class#readonlyProperty:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly readonlyProperty: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "readonlyProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Lib1Class#writeableProperty:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "writeableProperty: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "writeableProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Lib2Class:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Lib2Class " + } + ], + "fileUrlPath": "../api-extractor-lib2-test/src/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Lib2Class", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Lib2Class#prop:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "prop: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "prop", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Enum", + "canonicalReference": "api-extractor-scenarios!Lib4Enum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum Lib4Enum " + } + ], + "fileUrlPath": "../api-extractor-lib4-test/src/index.ts", + "releaseTag": "Public", + "name": "Lib4Enum", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!Lib4Enum.Bar:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Bar = " + }, + { + "kind": "Content", + "text": "\"Bar\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Bar" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!Lib4Enum.Baz:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Baz = " + }, + { + "kind": "Content", + "text": "\"Baz\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Baz" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!Lib4Enum.Foo:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Foo = " + }, + { + "kind": "Content", + "text": "\"Foo\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Foo" + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!lib5Function:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function lib5Function(): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "../api-extractor-lib5-test/src/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "lib5Function" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..4e33e833787 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.md @@ -0,0 +1,45 @@ +## 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 + +import { Lib3Class } from 'api-extractor-lib3-test/lib/index'; + +// @public (undocumented) +export function f(arg1: Lib1Class, arg2: Lib2Class, arg3: Lib3Class, arg4: Lib4Enum): void; + +// Warning: (ae-forgotten-export) The symbol "Lib1ForgottenExport" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export class Lib1Class extends Lib1ForgottenExport { + // (undocumented) + readonly readonlyProperty: string; + // (undocumented) + writeableProperty: string; +} + +// @public (undocumented) +export class Lib2Class { + // (undocumented) + prop: number; +} + +export { Lib3Class } + +// @public (undocumented) +export enum Lib4Enum { + // (undocumented) + Bar = "Bar", + // (undocumented) + Baz = "Baz", + // (undocumented) + Foo = "Foo" +} + +// @public (undocumented) +export function lib5Function(): number; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/bundledPackages/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/bundledPackages/rollup.d.ts new file mode 100644 index 00000000000..4b0107ec8dd --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundledPackages/rollup.d.ts @@ -0,0 +1,32 @@ +import { Lib3Class } from 'api-extractor-lib3-test/lib/index'; + +/** @public */ +export declare function f(arg1: Lib1Class, arg2: Lib2Class, arg3: Lib3Class, arg4: Lib4Enum): void; + +/** @public */ +export declare class Lib1Class extends Lib1ForgottenExport { + readonly readonlyProperty: string; + writeableProperty: string; +} + +declare class Lib1ForgottenExport { +} + +/** @public */ +export declare class Lib2Class { + prop: number; +} + +export { Lib3Class } + +/** @public */ +export declare enum Lib4Enum { + Foo = "Foo", + Bar = "Bar", + Baz = "Baz" +} + +/** @public */ +export declare function lib5Function(): number; + +export { } 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 new file mode 100644 index 00000000000..11072d35f10 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.json @@ -0,0 +1,333 @@ +{ + "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!IFile:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class IFile " + } + ], + "fileUrlPath": "src/circularImport/IFile.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "IFile", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFile#containingFolder:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "containingFolder: " + }, + { + "kind": "Reference", + "text": "IFolder", + "canonicalReference": "api-extractor-scenarios!IFolder:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "containingFolder", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!IFolder:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class IFolder " + } + ], + "fileUrlPath": "src/circularImport/IFolder.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "IFolder", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFolder#containingFolder:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "containingFolder: " + }, + { + "kind": "Reference", + "text": "IFolder", + "canonicalReference": "api-extractor-scenarios!IFolder:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "containingFolder", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFolder#files:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "files: " + }, + { + "kind": "Reference", + "text": "IFile", + "canonicalReference": "api-extractor-scenarios!IFile:class" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "files", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..96dc56ea7c9 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## 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 IFile { + // (undocumented) + containingFolder: IFolder; +} + +// @public (undocumented) +export class IFolder { + // (undocumented) + containingFolder: IFolder | undefined; + // (undocumented) + files: IFile[]; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/circularImport/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/circularImport/rollup.d.ts new file mode 100644 index 00000000000..5316051f5d2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport/rollup.d.ts @@ -0,0 +1,12 @@ +/** @public */ +export declare class IFile { + containingFolder: IFolder; +} + +/** @public */ +export declare class IFolder { + containingFolder: IFolder | undefined; + files: IFile[]; +} + +export { } 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 new file mode 100644 index 00000000000..4b4d33f465e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.json @@ -0,0 +1,369 @@ +{ + "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!A:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class A " + } + ], + "fileUrlPath": "src/circularImport2/IFile.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "A", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!B:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class B " + } + ], + "fileUrlPath": "src/circularImport2/IFolder.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "B", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!IFile:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class IFile " + } + ], + "fileUrlPath": "src/circularImport2/IFile.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "IFile", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFile#containingFolder:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "containingFolder: " + }, + { + "kind": "Reference", + "text": "IFolder", + "canonicalReference": "api-extractor-scenarios!IFolder:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "containingFolder", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!IFolder:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class IFolder " + } + ], + "fileUrlPath": "src/circularImport2/IFolder.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "IFolder", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFolder#containingFolder:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "containingFolder: " + }, + { + "kind": "Reference", + "text": "IFolder", + "canonicalReference": "api-extractor-scenarios!IFolder:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "containingFolder", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!IFolder#files:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "files: " + }, + { + "kind": "Reference", + "text": "IFile", + "canonicalReference": "api-extractor-scenarios!IFile:class" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "files", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..d6221af4976 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.md @@ -0,0 +1,31 @@ +## 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 A { +} + +// @public (undocumented) +export class B { +} + +// @public (undocumented) +export class IFile { + // (undocumented) + containingFolder: IFolder; +} + +// @public (undocumented) +export class IFolder { + // (undocumented) + containingFolder: IFolder | undefined; + // (undocumented) + files: IFile[]; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/circularImport2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/circularImport2/rollup.d.ts new file mode 100644 index 00000000000..758e98d8cb2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/circularImport2/rollup.d.ts @@ -0,0 +1,20 @@ +/** @public */ +export declare class A { +} + +/** @public */ +export declare class B { +} + +/** @public */ +export declare class IFile { + containingFolder: IFolder; +} + +/** @public */ +export declare class IFolder { + containingFolder: IFolder | undefined; + files: IFile[]; +} + +export { } 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 new file mode 100644 index 00000000000..c3376538caa --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!DefaultClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default class DefaultClass " + } + ], + "fileUrlPath": "src/defaultExportOfEntryPoint/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "DefaultClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..9673f3534b4 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/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 + +// @public (undocumented) +class DefaultClass { +} +export default DefaultClass; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/rollup.d.ts new file mode 100644 index 00000000000..ed962d82e8c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/rollup.d.ts @@ -0,0 +1,6 @@ +/** @public */ +declare class DefaultClass { +} +export default DefaultClass; + +export { } 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 new file mode 100644 index 00000000000..f6652971c0a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json @@ -0,0 +1,218 @@ +{ + "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!defaultFunctionStatement:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "defaultFunctionStatement: () => " + }, + { + "kind": "Content", + "text": "void" + } + ], + "fileUrlPath": "src/defaultExportOfEntryPoint2/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "defaultFunctionStatement" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..2352c3f766c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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) +const defaultFunctionStatement: () => void; +export default defaultFunctionStatement; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/rollup.d.ts new file mode 100644 index 00000000000..30a82f23737 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/rollup.d.ts @@ -0,0 +1,5 @@ +/** @public */ +declare const defaultFunctionStatement: () => void; +export default defaultFunctionStatement; + +export { } 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 new file mode 100644 index 00000000000..7ca2d175a65 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/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": "Function", + "canonicalReference": "api-extractor-scenarios!defaultFunctionDeclaration:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default function defaultFunctionDeclaration(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/defaultExportOfEntryPoint3/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "defaultFunctionDeclaration" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..7f7c207f6b8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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) +function defaultFunctionDeclaration(): void; +export default defaultFunctionDeclaration; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/rollup.d.ts new file mode 100644 index 00000000000..de8d7154d18 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/rollup.d.ts @@ -0,0 +1,7 @@ +/** + * @public + */ +declare function defaultFunctionDeclaration(): void; +export default defaultFunctionDeclaration; + +export { } 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 new file mode 100644 index 00000000000..be718ee63d0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json @@ -0,0 +1,217 @@ +{ + "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!_default:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "_default: " + }, + { + "kind": "Content", + "text": "\"literal\"" + } + ], + "fileUrlPath": "src/defaultExportOfEntryPoint4/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "_default", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..dde517e8788 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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) +const _default: "literal"; +export default _default; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/rollup.d.ts new file mode 100644 index 00000000000..3ac8fdb87c4 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/rollup.d.ts @@ -0,0 +1,5 @@ +/** @public */ +declare const _default: "literal"; +export default _default; + +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 new file mode 100644 index 00000000000..5f21c8220c2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.json @@ -0,0 +1,389 @@ +{ + "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!failWithBrokenLink:function(1)", + "docComment": "/**\n * {@inheritDoc MyNamespace.MyClass.nonExistentMethod}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function failWithBrokenLink(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "failWithBrokenLink" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!failWithMissingReference:function(1)", + "docComment": "/**\n * {@inheritDoc}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function failWithMissingReference(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "failWithMissingReference" + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!MyNamespace:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace MyNamespace " + } + ], + "fileUrlPath": "src/docReferences/index.ts", + "releaseTag": "Public", + "name": "MyNamespace", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!MyNamespace.MyClass:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class MyClass " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "MyClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!MyNamespace.MyClass#myMethod:member(1)", + "docComment": "/**\n * Summary for myMethod\n *\n * @remarks\n *\n * Remarks for myMethod\n *\n * @param x - the parameter\n *\n * @returns a number\n *\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "myMethod(x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Beta", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "myMethod" + } + ], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!succeedForNow:function(1)", + "docComment": "/**\n * {@inheritDoc nonexistent-package#MyNamespace.MyClass.nonExistentMethod}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function succeedForNow(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "succeedForNow" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testSimple:function(1)", + "docComment": "/**\n * Summary for myMethod\n *\n * @remarks\n *\n * Remarks for myMethod\n *\n * @param x - the parameter\n *\n * @returns a number\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testSimple(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "testSimple" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..14031441b3b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md @@ -0,0 +1,34 @@ +## 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-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: No member was found with name "nonExistentMethod" +// +// @public (undocumented) +export function failWithBrokenLink(): void; + +// Warning: (ae-unresolved-inheritdoc-base) The @inheritDoc tag needs a TSDoc declaration reference; signature matching is not supported yet +// +// @public (undocumented) +export function failWithMissingReference(): void; + +// @public (undocumented) +export namespace MyNamespace { + // (undocumented) + export class MyClass { + // @beta + myMethod(x: number): number; + } +} + +// @public +export function succeedForNow(): void; + +// @public +export function testSimple(): void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts new file mode 100644 index 00000000000..2739af6b264 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts @@ -0,0 +1,50 @@ +/** + * {@inheritDoc MyNamespace.MyClass.nonExistentMethod} + * @public + */ +export declare function failWithBrokenLink(): void; + +/** + * {@inheritDoc} + * @public + */ +export declare function failWithMissingReference(): void; + +/** + * @public + */ +export declare namespace MyNamespace { + export class MyClass { + /** + * Summary for myMethod + * @remarks + * Remarks for myMethod + * @param x - the parameter + * @returns a number + * @beta + */ + myMethod(x: number): number; + } +} + +/** + * {@inheritDoc nonexistent-package#MyNamespace.MyClass.nonExistentMethod} + * + * @privateRemarks + * succeedForNow() should fail due to a broken link, but it's ignored until we fix this issue: + * https://github.com/microsoft/rushstack/issues/1195 + * + * @public + */ +export declare function succeedForNow(): void; + +/** + * {@inheritDoc MyNamespace.MyClass.myMethod} + * @privateRemarks + * The MyClass.myMethod documentation content will get copied, + * but its `@beta` tag will not get copied. + * @public + */ +export declare function testSimple(): void; + +export { } 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 new file mode 100644 index 00000000000..1e5b18c2e4a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.json @@ -0,0 +1,437 @@ +{ + "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!CyclicA:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class CyclicA " + } + ], + "fileUrlPath": "src/docReferences2/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "CyclicA", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!CyclicA#methodA1:member(1)", + "docComment": "/**\n * THE COMMENT\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "methodA1(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "methodA1" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!CyclicA#methodA3:member(1)", + "docComment": "/**\n * THE COMMENT\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "methodA3(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "methodA3" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!CyclicB:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class CyclicB " + } + ], + "fileUrlPath": "src/docReferences2/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "CyclicB", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!CyclicB#methodB2:member(1)", + "docComment": "/**\n * THE COMMENT\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "methodB2(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "methodB2" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!CyclicB#methodB4:member(1)", + "docComment": "/**\n * THE COMMENT\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "methodB4(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "methodB4" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!FailWithSelfReference:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class FailWithSelfReference " + } + ], + "fileUrlPath": "src/docReferences2/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "FailWithSelfReference", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!FailWithSelfReference#method1:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "method1(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "method1" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!FailWithSelfReference#method2:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "method2(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "method2" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..7c4f974a530 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.md @@ -0,0 +1,31 @@ +## 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 CyclicA { + methodA1(): void; + methodA3(): void; +} + +// @public (undocumented) +export class CyclicB { + methodB2(): void; + methodB4(): void; +} + +// @public (undocumented) +export class FailWithSelfReference { + // Warning: (ae-cyclic-inherit-doc) The @inheritDoc tag for "method1" refers to its own declaration + // + // (undocumented) + method1(): void; + // (undocumented) + method2(): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferences2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferences2/rollup.d.ts new file mode 100644 index 00000000000..9be5b8bf965 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences2/rollup.d.ts @@ -0,0 +1,25 @@ +/** @public */ +export declare class CyclicA { + /** {@inheritDoc CyclicB.methodB2} */ + methodA1(): void; + /** {@inheritDoc CyclicB.methodB4} */ + methodA3(): void; +} + +/** @public */ +export declare class CyclicB { + /** {@inheritDoc CyclicA.methodA3} */ + methodB2(): void; + /** THE COMMENT */ + methodB4(): void; +} + +/** @public */ +export declare class FailWithSelfReference { + /** {@inheritDoc FailWithSelfReference.method2} */ + method1(): void; + /** {@inheritDoc FailWithSelfReference.method1} */ + method2(): void; +} + +export { } 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 new file mode 100644 index 00000000000..132c1188dc0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.json @@ -0,0 +1,389 @@ +{ + "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": "Interface", + "canonicalReference": "api-extractor-scenarios!A:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface A " + } + ], + "fileUrlPath": "src/docReferences3/index.ts", + "releaseTag": "Public", + "name": "A", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!A#myProperty:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "myProperty: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "myProperty", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!A:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace A " + } + ], + "fileUrlPath": "src/docReferences3/index.ts", + "releaseTag": "Public", + "name": "A", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!A.B:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class B " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "B", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!A.B#myMethod:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "myMethod(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "myMethod" + } + ], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!failWithAmbiguity:function(1)", + "docComment": "/**\n * {@link MyNamespace.MyClass.myMethod | the method}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function failWithAmbiguity(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences3/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "failWithAmbiguity" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!succeedWithExternalReference:function(1)", + "docComment": "/**\n * NOTE: The broken link checker currently is not able to validate references to external packages. Tracked by: https://github.com/microsoft/rushstack/issues/1195 {@link nonexistent#nonexistent}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function succeedWithExternalReference(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences3/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "succeedWithExternalReference" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!succeedWithSelector:function(1)", + "docComment": "/**\n * {@link (A:namespace).B.myMethod | the method} {@link (A:interface).myProperty | the property}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function succeedWithSelector(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/docReferences3/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "succeedWithSelector" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..cae6a88eaf1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md @@ -0,0 +1,35 @@ +## 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 namespace A { + // (undocumented) + export class B { + // (undocumented) + myMethod(): void; + } +} + +// @public (undocumented) +export interface A { + // (undocumented) + myProperty: string; +} + +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "api-extractor-scenarios" does not have an export "MyNamespace" +// +// @public +export function failWithAmbiguity(): void; + +// @public +export function succeedWithExternalReference(): void; + +// @public +export function succeedWithSelector(): void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts new file mode 100644 index 00000000000..9823fc73ee2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts @@ -0,0 +1,34 @@ +/** @public */ +export declare namespace A { + export class B { + myMethod(): void; + } +} + +/** @public */ +export declare interface A { + myProperty: string; +} + +/** + * {@link MyNamespace.MyClass.myMethod | the method} + * @public + */ +export declare function failWithAmbiguity(): void; + +/** + * NOTE: The broken link checker currently is not able to validate references to external packages. + * Tracked by: https://github.com/microsoft/rushstack/issues/1195 + * {@link nonexistent#nonexistent} + * @public + */ +export declare function succeedWithExternalReference(): void; + +/** + * {@link (A:namespace).B.myMethod | the method} + * {@link (A:interface).myProperty | the property} + * @public + */ +export declare function succeedWithSelector(): void; + +export { } 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 new file mode 100644 index 00000000000..9c65d23e2d6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json @@ -0,0 +1,316 @@ +{ + "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!Item:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default class Item " + } + ], + "fileUrlPath": "src/docReferencesAlias/Item.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Item", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#options:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "options: " + }, + { + "kind": "Reference", + "text": "Options", + "canonicalReference": "api-extractor-scenarios!renamed_Options:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "options", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed_Options:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface Options " + } + ], + "fileUrlPath": "src/docReferencesAlias/Options.ts", + "releaseTag": "Public", + "name": "renamed_Options", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed_Options#color:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "color: " + }, + { + "kind": "Content", + "text": "'red' | 'blue'" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "color", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed_Options#name:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "name: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..e5dbeddb60e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## 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 Item { + // (undocumented) + options: renamed_Options; +} + +// @public (undocumented) +export interface renamed_Options { + // (undocumented) + color: 'red' | 'blue'; + // (undocumented) + name: string; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts new file mode 100644 index 00000000000..36cac4b715d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts @@ -0,0 +1,12 @@ +/** @public */ +export declare class Item { + options: renamed_Options; +} + +/** @public */ +export declare interface renamed_Options { + name: string; + color: 'red' | 'blue'; +} + +export { } 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 new file mode 100644 index 00000000000..aa38a67cebf --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json @@ -0,0 +1,413 @@ +{ + "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!Item:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default class Item " + } + ], + "fileUrlPath": "src/docReferencesNamespaceAlias/Item.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Item", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#options:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "options: " + }, + { + "kind": "Reference", + "text": "Options", + "canonicalReference": "api-extractor-scenarios!renamed.Options:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "options", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!renamed:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/docReferencesNamespaceAlias/index.ts", + "releaseTag": "None", + "name": "renamed", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed.Options:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface Options " + } + ], + "fileUrlPath": "src/docReferencesNamespaceAlias/renamed/Options.ts", + "releaseTag": "Public", + "name": "Options", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#color:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "color: " + }, + { + "kind": "Content", + "text": "'red' | 'blue'" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "color", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#name:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "name: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#subOptions:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "subOptions: " + }, + { + "kind": "Reference", + "text": "SubOptions", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "subOptions", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!renamed.sub:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/docReferencesNamespaceAlias/renamed/index.ts", + "releaseTag": "None", + "name": "sub", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface SubOptions " + } + ], + "fileUrlPath": "src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts", + "releaseTag": "Public", + "name": "SubOptions", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions#count:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "count: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "count", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..090e96727ac --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md @@ -0,0 +1,45 @@ +## 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 Item { + // (undocumented) + options: Options; +} + +// @public (undocumented) +interface Options { + // (undocumented) + color: 'red' | 'blue'; + // (undocumented) + name: string; + // (undocumented) + subOptions: SubOptions; +} + +declare namespace renamed { + export { + sub, + Options + } +} +export { renamed } + +declare namespace sub { + export { + SubOptions + } +} + +// @public (undocumented) +interface SubOptions { + // (undocumented) + count: number; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts new file mode 100644 index 00000000000..0c7a1f4c742 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts @@ -0,0 +1,32 @@ +/** @public */ +export declare class Item { + options: Options; +} + +/** @public */ +declare interface Options { + name: string; + color: 'red' | 'blue'; + subOptions: SubOptions; +} + +declare namespace renamed { + export { + sub, + Options + } +} +export { renamed } + +declare namespace sub { + export { + SubOptions + } +} + +/** @public */ +declare interface SubOptions { + count: number; +} + +export { } 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 new file mode 100644 index 00000000000..f9ae5ecf136 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json @@ -0,0 +1,388 @@ +{ + "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!Item:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Item " + } + ], + "fileUrlPath": "src/dynamicImportType/Item.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Item", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#lib1:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "lib1: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib1-test')." + }, + { + "kind": "Reference", + "text": "Lib1Interface", + "canonicalReference": "api-extractor-lib1-test!Lib1Interface:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "lib1", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#lib2:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "lib2: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib2-test')." + }, + { + "kind": "Reference", + "text": "Lib2Interface", + "canonicalReference": "api-extractor-lib2-test!Lib2Interface:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "lib2", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#lib3:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "lib3: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib3-test')." + }, + { + "kind": "Reference", + "text": "Lib1Class", + "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "lib3", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#options:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "options: " + }, + { + "kind": "Content", + "text": "import('./Options')." + }, + { + "kind": "Reference", + "text": "Options", + "canonicalReference": "api-extractor-scenarios!~Options:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "options", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#reExport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "reExport: " + }, + { + "kind": "Content", + "text": "import('./re-export')." + }, + { + "kind": "Reference", + "text": "Lib2Class", + "canonicalReference": "api-extractor-lib2-test!Lib2Class:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "reExport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..999494f5feb --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md @@ -0,0 +1,35 @@ +## 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 + +import * as Lib1 from 'api-extractor-lib1-test'; +import { Lib1Class } from 'api-extractor-lib3-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; +import { Lib2Interface } from 'api-extractor-lib2-test'; + +// @public (undocumented) +export class Item { + // (undocumented) + lib1: Lib1Interface; + // (undocumented) + lib2: Lib2Interface; + // (undocumented) + lib3: Lib1Class; + // Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts + // + // (undocumented) + options: Options; + // (undocumented) + reExport: Lib2Class; +} + +export { Lib1 } + +export { Lib2Interface } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts new file mode 100644 index 00000000000..93bc8c69f24 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts @@ -0,0 +1,25 @@ +import * as Lib1 from 'api-extractor-lib1-test'; +import { Lib1Class } from 'api-extractor-lib3-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; +import { Lib2Interface } from 'api-extractor-lib2-test'; + +/** @public */ +export declare class Item { + options: Options; + lib1: Lib1Interface; + lib2: Lib2Interface; + lib3: Lib1Class; + reExport: Lib2Class; +} + +export { Lib1 } + +export { Lib2Interface } + +declare interface Options { + name: string; + color: 'red' | 'blue'; +} + +export { } 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 new file mode 100644 index 00000000000..206970f232e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json @@ -0,0 +1,284 @@ +{ + "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": "Interface", + "canonicalReference": "api-extractor-scenarios!IExample:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IExample " + } + ], + "fileUrlPath": "src/dynamicImportType2/index.ts", + "releaseTag": "Public", + "name": "IExample", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#dottedImportType:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "dottedImportType: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib1-test')." + }, + { + "kind": "Reference", + "text": "Lib1Namespace.Inner.X", + "canonicalReference": "api-extractor-lib1-test!Lib1Namespace.Inner.X:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "dottedImportType", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#dottedImportType2:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "dottedImportType2: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib1-test')." + }, + { + "kind": "Reference", + "text": "Lib1Namespace.Y", + "canonicalReference": "api-extractor-lib1-test!Lib1Namespace.Y:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "dottedImportType2", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..46ecc077ba9 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/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 + +import { Lib1Namespace } from 'api-extractor-lib1-test'; + +// @public (undocumented) +export interface IExample { + // (undocumented) + dottedImportType: Lib1Namespace.Inner.X | undefined; + // (undocumented) + dottedImportType2: Lib1Namespace.Y | undefined; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts new file mode 100644 index 00000000000..c8d465c2ca5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts @@ -0,0 +1,9 @@ +import { Lib1Namespace } from 'api-extractor-lib1-test'; + +/** @public */ +export declare interface IExample { + dottedImportType: Lib1Namespace.Inner.X | undefined; + dottedImportType2: Lib1Namespace.Y | undefined; +} + +export { } 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 new file mode 100644 index 00000000000..08d82bdea53 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.json @@ -0,0 +1,257 @@ +{ + "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": "Interface", + "canonicalReference": "api-extractor-scenarios!IExample:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IExample " + } + ], + "fileUrlPath": "src/dynamicImportType3/index.ts", + "releaseTag": "Public", + "name": "IExample", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#generic:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "generic: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib1-test')." + }, + { + "kind": "Reference", + "text": "Lib1GenericType", + "canonicalReference": "api-extractor-lib1-test!Lib1GenericType:type" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "generic", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 6 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..ee8c43fff7c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md @@ -0,0 +1,18 @@ +## 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 + +import { Lib1GenericType } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; + +// @public (undocumented) +export interface IExample { + // (undocumented) + generic: Lib1GenericType; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts new file mode 100644 index 00000000000..dcbb364c050 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts @@ -0,0 +1,9 @@ +import { Lib1GenericType } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; + +/** @public */ +export declare interface IExample { + generic: Lib1GenericType; +} + +export { } 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 new file mode 100644 index 00000000000..7c85d11223b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!Example:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Example " + } + ], + "fileUrlPath": "src/ecmaScriptPrivateFields/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Example", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..b383b3ca1d8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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 Example { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/rollup.d.ts new file mode 100644 index 00000000000..9bd6852aa45 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/rollup.d.ts @@ -0,0 +1,7 @@ +/** @public */ +export declare class Example { + #private; + private _typeScriptPrivate; +} + +export { } 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 new file mode 100644 index 00000000000..021c6a99b03 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.json @@ -0,0 +1,354 @@ +{ + "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": "Enum", + "canonicalReference": "api-extractor-scenarios!ConstEnum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare const enum ConstEnum " + } + ], + "fileUrlPath": "src/enumSorting/index.ts", + "releaseTag": "Public", + "name": "ConstEnum", + "preserveMemberOrder": true, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.Zero:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Zero = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Zero" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.One:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "One = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "One" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!ConstEnum.Two:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "Two = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Two" + } + ] + }, + { + "kind": "Enum", + "canonicalReference": "api-extractor-scenarios!RegularEnum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum RegularEnum " + } + ], + "fileUrlPath": "src/enumSorting/index.ts", + "releaseTag": "Public", + "name": "RegularEnum", + "preserveMemberOrder": true, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.Zero:member", + "docComment": "/**\n * These are some docs for Zero\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Zero = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Zero" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.One:member", + "docComment": "/**\n * These are some docs for One\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "One = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "One" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!RegularEnum.Two:member", + "docComment": "/**\n * These are some docs for Two\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Two = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "Two" + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..a5859ebe449 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.md @@ -0,0 +1,26 @@ +## 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 const enum ConstEnum { + // (undocumented) + One = 1, + // (undocumented) + Two = 2, + // (undocumented) + Zero = 0 +} + +// @public (undocumented) +export enum RegularEnum { + One = 1, + Two = 2, + Zero = 0 +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/enumSorting/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/enumSorting/rollup.d.ts new file mode 100644 index 00000000000..cfc82141ab2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/enumSorting/rollup.d.ts @@ -0,0 +1,24 @@ +/** @public */ +export declare const enum ConstEnum { + Zero = 0, + One = 1, + Two = 2 +} + +/** @public */ +export declare enum RegularEnum { + /** + * These are some docs for Zero + */ + Zero = 0, + /** + * These are some docs for One + */ + One = 1, + /** + * These are some docs for Two + */ + Two = 2 +} + +export { } 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 new file mode 100644 index 00000000000..7a086bfd599 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.json @@ -0,0 +1,300 @@ +{ + "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!MY_CONSTANT:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "MY_CONSTANT : " + }, + { + "kind": "Content", + "text": "number" + } + ], + "fileUrlPath": "lib/excerptTokens/index.d.ts", + "isReadonly": false, + "releaseTag": "Public", + "name": "MY_CONSTANT", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!MyClass:class", + "docComment": "/**\n * This is my class.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export class MyClass " + } + ], + "fileUrlPath": "lib/excerptTokens/index.d.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MyClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!MyClass#someMethod:member(1)", + "docComment": "/**\n * This method does something.\n *\n * @param x - This is x.\n *\n * @param y - This is y.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "someMethod(x : " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": " , y : " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": " ) : " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "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": "someMethod" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..1de9e1ea4d8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.md @@ -0,0 +1,17 @@ +## 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 let MY_CONSTANT : number; + +// @public +export class MyClass { + someMethod(x : number , y : string ) : boolean ; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/excerptTokens/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/excerptTokens/rollup.d.ts new file mode 100644 index 00000000000..a71df0cac97 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/excerptTokens/rollup.d.ts @@ -0,0 +1,16 @@ +/** @public */ +export declare let MY_CONSTANT : number; + +/** + * @public This is my class. + */ +export declare class MyClass { + /** + * This method does something. + * @param x - This is x. + * @param y - This is y. + */ + someMethod(x : number , y : string ) : boolean ; +} + +export { } 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 new file mode 100644 index 00000000000..af560e6437e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!X:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class X " + } + ], + "fileUrlPath": "src/exportDuplicate/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "X", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..06b0635d623 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.md @@ -0,0 +1,25 @@ +## 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 + +// @internal (undocumented) +class A { +} + +// Warning: (ae-internal-missing-underscore) The name "B" should be prefixed with an underscore because the declaration is marked as @internal +export { A as B } + +// Warning: (ae-internal-missing-underscore) The name "C" should be prefixed with an underscore because the declaration is marked as @internal +export { A as C } + +// @public (undocumented) +class X { +} +export { X } +export { X as Y } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportDuplicate/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportDuplicate/rollup.d.ts new file mode 100644 index 00000000000..25585290cd1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportDuplicate/rollup.d.ts @@ -0,0 +1,13 @@ +/** @internal */ +declare class A { +} +export { A as B } +export { A as C } + +/** @public */ +declare class X { +} +export { X } +export { X as Y } + +export { } 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 new file mode 100644 index 00000000000..2af67bcc3e2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.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-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!ITeamsContext:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface ITeamsContext " + } + ], + "fileUrlPath": "src/exportEquals/index.ts", + "releaseTag": "Public", + "name": "ITeamsContext", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!ITeamsContext#context:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "context: " + }, + { + "kind": "Reference", + "text": "Context", + "canonicalReference": "!microsoftTeams.Context:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "context", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..acda22e8a77 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.md @@ -0,0 +1,17 @@ +## 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 + +import { Context } from '@microsoft/teams-js'; + +// @public (undocumented) +export interface ITeamsContext { + // (undocumented) + context: Context; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportEquals/rollup.d.ts similarity index 100% rename from build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/rollup.d.ts rename to build-tests/api-extractor-scenarios/etc/exportEquals/rollup.d.ts 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 new file mode 100644 index 00000000000..d36f5836527 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.json @@ -0,0 +1,508 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!calculator:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportImportStarAs/index.ts", + "releaseTag": "None", + "name": "calculator", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator.add:function(1)", + "docComment": "/**\n * Returns the sum of adding `b` to `a`\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of adding `b` to `a`\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function add(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportImportStarAs/calculator.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "add" + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!calculator.calculatorVersion:var", + "docComment": "/**\n * Returns the version of the calculator.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "calculatorVersion: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/exportImportStarAs/common.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "calculatorVersion", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator.subtract:function(1)", + "docComment": "/**\n * Returns the sum of subtracting `b` from `a`\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of subtract `b` from `a`\n *\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function subtract(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportImportStarAs/calculator.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "subtract" + } + ] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!calculator2:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportImportStarAs/index.ts", + "releaseTag": "None", + "name": "calculator2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator2.add:function(1)", + "docComment": "/**\n * Returns the sum of adding `b` to `a` for large integers\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of adding `b` to `a`\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function add(a: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportImportStarAs/calculator2.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "add" + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!calculator2.calculatorVersion:var", + "docComment": "/**\n * Returns the version of the calculator.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "calculatorVersion: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/exportImportStarAs/common.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "calculatorVersion", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator2.subtract:function(1)", + "docComment": "/**\n * Returns the sum of subtracting `b` from `a` for large integers\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of subtract `b` from `a`\n *\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function subtract(a: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportImportStarAs/calculator2.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "subtract" + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..a05e6f34a4a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.md @@ -0,0 +1,42 @@ +## 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 +function add(a: number, b: number): number; + +// @public +function add_2(a: bigint, b: bigint): bigint; + +declare namespace calculator { + export { + add, + subtract, + calculatorVersion + } +} +export { calculator } + +declare namespace calculator2 { + export { + add_2 as add, + subtract_2 as subtract, + calculatorVersion + } +} +export { calculator2 } + +// @public +const calculatorVersion: string; + +// @beta +function subtract(a: number, b: number): number; + +// @beta +function subtract_2(a: bigint, b: bigint): bigint; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/rollup.d.ts new file mode 100644 index 00000000000..042af626326 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/rollup.d.ts @@ -0,0 +1,61 @@ +/** + * Returns the sum of adding `b` to `a` + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +declare function add(a: number, b: number): number; + +/** + * Returns the sum of adding `b` to `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +declare function add_2(a: bigint, b: bigint): bigint; + +declare namespace calculator { + export { + add, + subtract, + calculatorVersion + } +} +export { calculator } + +declare namespace calculator2 { + export { + add_2 as add, + subtract_2 as subtract, + calculatorVersion + } +} +export { calculator2 } + +/** + * Returns the version of the calculator. + * @public + */ +declare const calculatorVersion: string; + +/** + * Returns the sum of subtracting `b` from `a` + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +declare function subtract(a: number, b: number): number; + +/** + * Returns the sum of subtracting `b` from `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +declare function subtract_2(a: bigint, b: bigint): bigint; + +export { } 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 new file mode 100644 index 00000000000..3fcbf300fb2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json @@ -0,0 +1,235 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!ns:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportImportStarAs2/index.ts", + "releaseTag": "None", + "name": "ns", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!ns.exportedApi:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function exportedApi(): " + }, + { + "kind": "Reference", + "text": "forgottenNs.ForgottenClass", + "canonicalReference": "api-extractor-scenarios!~ForgottenClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportImportStarAs2/ns.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "exportedApi" + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..be6c99dbe02 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 "forgottenNs" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +function exportedApi(): forgottenNs.ForgottenClass; + +declare namespace ns { + export { + exportedApi + } +} +export { ns } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/rollup.d.ts new file mode 100644 index 00000000000..8819a381256 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/rollup.d.ts @@ -0,0 +1,25 @@ +/** + * @public + */ +declare function exportedApi(): forgottenNs.ForgottenClass; + +/** + * @public + */ +declare class ForgottenClass { +} + +declare namespace forgottenNs { + export { + ForgottenClass + } +} + +declare namespace ns { + export { + exportedApi + } +} +export { ns } + +export { } 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 new file mode 100644 index 00000000000..e4d22195cde --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.json @@ -0,0 +1,260 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!NS:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportImportStarAs3/index.ts", + "releaseTag": "None", + "name": "NS", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!NS.NS_BETA:var", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "NS_BETA = " + }, + { + "kind": "Content", + "text": "\"BETA\"" + } + ], + "fileUrlPath": "src/exportImportStarAs3/NamespaceWithTrimming.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Beta", + "name": "NS_BETA", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!NS.NS_PUBLIC:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "NS_PUBLIC = " + }, + { + "kind": "Content", + "text": "\"PUBLIC\"" + } + ], + "fileUrlPath": "src/exportImportStarAs3/NamespaceWithTrimming.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "NS_PUBLIC", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..e9a2e07d1b6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.md @@ -0,0 +1,27 @@ +## 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 + +declare namespace NS { + export { + NS_PUBLIC, + NS_BETA, + NS_INTERNAL + } +} +export { NS } + +// @beta (undocumented) +const NS_BETA = "BETA"; + +// @internal (undocumented) +const NS_INTERNAL = "INTERNAL"; + +// @public (undocumented) +const NS_PUBLIC = "PUBLIC"; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup-public.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup-public.d.ts new file mode 100644 index 00000000000..386f2a3006d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup-public.d.ts @@ -0,0 +1,15 @@ +declare namespace NS { + export { + NS_PUBLIC + } +} +export { NS } + +/* Excluded from this release type: NS_BETA */ + +/* Excluded from this release type: NS_INTERNAL */ + +/** @public */ +declare const NS_PUBLIC = "PUBLIC"; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup.d.ts new file mode 100644 index 00000000000..c2331582e0c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/rollup.d.ts @@ -0,0 +1,19 @@ +declare namespace NS { + export { + NS_PUBLIC, + NS_BETA, + NS_INTERNAL + } +} +export { NS } + +/** @beta */ +declare const NS_BETA = "BETA"; + +/** @internal */ +declare const NS_INTERNAL = "INTERNAL"; + +/** @public */ +declare const NS_PUBLIC = "PUBLIC"; + +export { } 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 new file mode 100644 index 00000000000..f2997df1bb1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.json @@ -0,0 +1,193 @@ +{ + "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": [] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..e153cecf3f5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.md @@ -0,0 +1,20 @@ +## 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 + +import { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; + +export { Lib1Class } + +export { Lib1Interface } + +export { Lib2Class as DoubleRenamedLib2Class } +export { Lib2Class as RenamedLib2Class } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/rollup.d.ts new file mode 100644 index 00000000000..79e923ef215 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/rollup.d.ts @@ -0,0 +1,12 @@ +import { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; + +export { Lib1Class } + +export { Lib1Interface } + +export { Lib2Class as DoubleRenamedLib2Class } +export { Lib2Class as RenamedLib2Class } + +export { } 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 new file mode 100644 index 00000000000..f2997df1bb1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.json @@ -0,0 +1,193 @@ +{ + "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": [] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..5424b29c9f0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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 + +import { Lib1Class } from 'api-extractor-lib3-test'; + +export { Lib1Class } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/rollup.d.ts new file mode 100644 index 00000000000..339ea10875d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/rollup.d.ts @@ -0,0 +1,5 @@ +import { Lib1Class } from 'api-extractor-lib3-test'; + +export { Lib1Class } + +export { } 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 new file mode 100644 index 00000000000..771b403636c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.json @@ -0,0 +1,225 @@ +{ + "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!Child:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Child extends " + }, + { + "kind": "Reference", + "text": "Base", + "canonicalReference": "api-extractor-lib2-test!DefaultClass:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/exportImportedExternalDefault/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Child", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..9fc9ffe785b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.md @@ -0,0 +1,20 @@ +## 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 + +import { default as default_2 } from 'api-extractor-lib2-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; + +// @public (undocumented) +export class Child extends default_2 { +} + +export default default_2; + +export { Lib2Class } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/rollup.d.ts new file mode 100644 index 00000000000..03e36983656 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/rollup.d.ts @@ -0,0 +1,12 @@ +import { default as default_2 } from 'api-extractor-lib2-test'; +import { Lib2Class } from 'api-extractor-lib2-test'; + +/** @public */ +export declare class Child extends default_2 { +} + +export default default_2; + +export { Lib2Class } + +export { } 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 new file mode 100644 index 00000000000..e720c20a841 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.json @@ -0,0 +1,248 @@ +{ + "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!A:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class A " + } + ], + "fileUrlPath": "src/exportStar/localFile.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "A", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!B:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class B " + } + ], + "fileUrlPath": "src/exportStar/localFile.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "B", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!C:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class C " + } + ], + "fileUrlPath": "src/exportStar/reexportStar.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "C", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..58bbf8a2853 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 A { +} + +// @public (undocumented) +export class B { +} + +// @public (undocumented) +export class C { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportStar/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStar/rollup.d.ts new file mode 100644 index 00000000000..82471bcc17b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar/rollup.d.ts @@ -0,0 +1,13 @@ +/** @public */ +export declare class A { +} + +/** @public */ +export declare class B { +} + +/** @public */ +export declare class C { +} + +export { } 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 new file mode 100644 index 00000000000..d199190991d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!A:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class A " + } + ], + "fileUrlPath": "src/exportStar2/reexportStar.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "A", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.md similarity index 100% rename from build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/api-extractor-scenarios.api.md rename to build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.md diff --git a/build-tests/api-extractor-scenarios/etc/exportStar2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStar2/rollup.d.ts new file mode 100644 index 00000000000..55d21f77bf6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar2/rollup.d.ts @@ -0,0 +1,9 @@ +/** @public */ +export declare class A { +} + + +export * from "api-extractor-lib1-test"; +export * from "api-extractor-lib2-test"; + +export { } 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 new file mode 100644 index 00000000000..324740f7367 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.json @@ -0,0 +1,212 @@ +{ + "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!A:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class A " + } + ], + "fileUrlPath": "src/exportStar3/reexportStar.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "A", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..a7ef0c9f1ec --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.md @@ -0,0 +1,20 @@ +## 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 + +import { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib2Interface as RenamedLib2Interface } from 'api-extractor-lib2-test'; + +// @public (undocumented) +export class A { +} + +export { Lib1Class } + +export { RenamedLib2Interface } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportStar3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStar3/rollup.d.ts new file mode 100644 index 00000000000..ab9b252b772 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStar3/rollup.d.ts @@ -0,0 +1,12 @@ +import { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib2Interface as RenamedLib2Interface } from 'api-extractor-lib2-test'; + +/** @public */ +export declare class A { +} + +export { Lib1Class } + +export { RenamedLib2Interface } + +export { } 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 new file mode 100644 index 00000000000..cd930436f06 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.json @@ -0,0 +1,508 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!calculator:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportStarAs/index.ts", + "releaseTag": "None", + "name": "calculator", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator.add:function(1)", + "docComment": "/**\n * Returns the sum of adding `b` to `a`\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of adding `b` to `a`\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function add(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportStarAs/calculator.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "add" + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!calculator.calculatorVersion:var", + "docComment": "/**\n * Returns the version of the calculator.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "calculatorVersion: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/exportStarAs/common.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "calculatorVersion", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator.subtract:function(1)", + "docComment": "/**\n * Returns the sum of subtracting `b` from `a`\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of subtract `b` from `a`\n *\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function subtract(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportStarAs/calculator.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "subtract" + } + ] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!calculator2:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportStarAs/index.ts", + "releaseTag": "None", + "name": "calculator2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator2.add:function(1)", + "docComment": "/**\n * Returns the sum of adding `b` to `a` for large integers\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of adding `b` to `a`\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function add(a: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportStarAs/calculator2.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "add" + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!calculator2.calculatorVersion:var", + "docComment": "/**\n * Returns the version of the calculator.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "calculatorVersion: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/exportStarAs/common.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "calculatorVersion", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!calculator2.subtract:function(1)", + "docComment": "/**\n * Returns the sum of subtracting `b` from `a` for large integers\n *\n * @param a - first number\n *\n * @param b - second number\n *\n * @returns Sum of subtract `b` from `a`\n *\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function subtract(a: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "bigint" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportStarAs/calculator2.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "subtract" + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..fe0c6582f31 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.md @@ -0,0 +1,40 @@ +## 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 +function add(a: number, b: number): number; + +// @public +function add_2(a: bigint, b: bigint): bigint; + +declare namespace calculator { + export { + add, + subtract, + calculatorVersion + } +} + +declare namespace calculator2 { + export { + add_2 as add, + subtract_2 as subtract, + calculatorVersion + } +} + +// @public +const calculatorVersion: string; + +// @beta +function subtract(a: number, b: number): number; + +// @beta +function subtract_2(a: bigint, b: bigint): bigint; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStarAs/rollup.d.ts new file mode 100644 index 00000000000..4376f485243 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs/rollup.d.ts @@ -0,0 +1,59 @@ +/** + * Returns the sum of adding `b` to `a` + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +declare function add(a: number, b: number): number; + +/** + * Returns the sum of adding `b` to `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +declare function add_2(a: bigint, b: bigint): bigint; + +export declare namespace calculator { + export { + add, + subtract, + calculatorVersion + } +} + +export declare namespace calculator2 { + export { + add_2 as add, + subtract_2 as subtract, + calculatorVersion + } +} + +/** + * Returns the version of the calculator. + * @public + */ +declare const calculatorVersion: string; + +/** + * Returns the sum of subtracting `b` from `a` + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +declare function subtract(a: number, b: number): number; + +/** + * Returns the sum of subtracting `b` from `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +declare function subtract_2(a: bigint, b: bigint): bigint; + +export { } 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 new file mode 100644 index 00000000000..291bb916343 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json @@ -0,0 +1,235 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!ns:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportStarAs2/index.ts", + "releaseTag": "None", + "name": "ns", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!ns.exportedApi:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function exportedApi(): " + }, + { + "kind": "Reference", + "text": "forgottenNs.ForgottenClass", + "canonicalReference": "api-extractor-scenarios!~ForgottenClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/exportStarAs2/ns.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "exportedApi" + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..d45af72898d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.md @@ -0,0 +1,20 @@ +## 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 "forgottenNs" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +function exportedApi(): forgottenNs.ForgottenClass; + +declare namespace ns { + export { + exportedApi + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStarAs2/rollup.d.ts new file mode 100644 index 00000000000..47900d36059 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs2/rollup.d.ts @@ -0,0 +1,24 @@ +/** + * @public + */ +declare function exportedApi(): forgottenNs.ForgottenClass; + +/** + * @public + */ +declare class ForgottenClass { +} + +declare namespace forgottenNs { + export { + ForgottenClass + } +} + +export declare namespace ns { + export { + exportedApi + } +} + +export { } 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 new file mode 100644 index 00000000000..0c043e9368a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.json @@ -0,0 +1,260 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!NS:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/exportStarAs3/index.ts", + "releaseTag": "None", + "name": "NS", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!NS.NS_BETA:var", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "NS_BETA = " + }, + { + "kind": "Content", + "text": "\"BETA\"" + } + ], + "fileUrlPath": "src/exportStarAs3/NamespaceWithTrimming.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Beta", + "name": "NS_BETA", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!NS.NS_PUBLIC:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "NS_PUBLIC = " + }, + { + "kind": "Content", + "text": "\"PUBLIC\"" + } + ], + "fileUrlPath": "src/exportStarAs3/NamespaceWithTrimming.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "NS_PUBLIC", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..1741a4e1d27 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.md @@ -0,0 +1,26 @@ +## 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 + +declare namespace NS { + export { + NS_PUBLIC, + NS_BETA, + NS_INTERNAL + } +} + +// @beta (undocumented) +const NS_BETA = "BETA"; + +// @internal (undocumented) +const NS_INTERNAL = "INTERNAL"; + +// @public (undocumented) +const NS_PUBLIC = "PUBLIC"; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup-public.d.ts b/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup-public.d.ts new file mode 100644 index 00000000000..80ea239c15f --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup-public.d.ts @@ -0,0 +1,14 @@ +export declare namespace NS { + export { + NS_PUBLIC + } +} + +/* Excluded from this release type: NS_BETA */ + +/* Excluded from this release type: NS_INTERNAL */ + +/** @public */ +declare const NS_PUBLIC = "PUBLIC"; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup.d.ts new file mode 100644 index 00000000000..1bdfef79947 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs3/rollup.d.ts @@ -0,0 +1,18 @@ +export declare namespace NS { + export { + NS_PUBLIC, + NS_BETA, + NS_INTERNAL + } +} + +/** @beta */ +declare const NS_BETA = "BETA"; + +/** @internal */ +declare const NS_INTERNAL = "INTERNAL"; + +/** @public */ +declare const NS_PUBLIC = "PUBLIC"; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/functionOverload/alpha-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/functionOverload/alpha-rollup.d.ts new file mode 100644 index 00000000000..14850ae7aca --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/alpha-rollup.d.ts @@ -0,0 +1,41 @@ +/** + * @alpha + */ +export declare function combine(x: boolean, y: boolean): boolean; + +/** + * @beta + */ +export declare function combine(x: string, y: string): string; + +/** + * @public + */ +export declare function combine(x: number, y: number): number; + +/** + * @beta + */ +export declare function _combine(x: string, y: string): string; + +/* Excluded declaration from this release type: _combine */ + +/** + * @public + */ +export declare class Combiner { + /** + * @alpha + */ + combine(x: boolean, y: boolean): boolean; + /** + * @beta + */ + combine(x: string, y: string): string; + /** + * @public + */ + combine(x: number, y: number): number; +} + +export { } 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 new file mode 100644 index 00000000000..1b4335b21d6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.json @@ -0,0 +1,585 @@ +{ + "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!_combine:function(1)", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function _combine(x: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/functionOverload/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "_combine" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!combine:function(1)", + "docComment": "/**\n * @alpha\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function combine(x: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/functionOverload/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Alpha", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "combine" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!combine:function(2)", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function combine(x: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/functionOverload/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "overloadIndex": 2, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "combine" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!combine:function(3)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function combine(x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/functionOverload/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 3, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "combine" + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Combiner:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Combiner " + } + ], + "fileUrlPath": "src/functionOverload/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Combiner", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!Combiner#combine:member(2)", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "combine(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": 2, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "combine" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!Combiner#combine:member(3)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "combine(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": 3, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "combine" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..1b2dd4cb96f --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.md @@ -0,0 +1,36 @@ +## 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 + +// @alpha (undocumented) +export function combine(x: boolean, y: boolean): boolean; + +// @beta (undocumented) +export function combine(x: string, y: string): string; + +// @public (undocumented) +export function combine(x: number, y: number): number; + +// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "_combine" because one of its declarations is marked as @internal +// +// @beta (undocumented) +export function _combine(x: string, y: string): string; + +// @internal (undocumented) +export function _combine(x: number, y: number): number; + +// @public (undocumented) +export class Combiner { + // @alpha (undocumented) + combine(x: boolean, y: boolean): boolean; + // @beta (undocumented) + combine(x: string, y: string): string; + // (undocumented) + combine(x: number, y: number): number; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/beta-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/functionOverload/beta-rollup.d.ts similarity index 99% rename from build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/beta-rollup.d.ts rename to build-tests/api-extractor-scenarios/etc/functionOverload/beta-rollup.d.ts index 9a6bf28f512..4a743513621 100644 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/beta-rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/beta-rollup.d.ts @@ -1,4 +1,3 @@ - /* Excluded declaration from this release type: combine */ /** diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/public-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/functionOverload/public-rollup.d.ts similarity index 99% rename from build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/public-rollup.d.ts rename to build-tests/api-extractor-scenarios/etc/functionOverload/public-rollup.d.ts index 1198f5f26b0..eb82c33c9b5 100644 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/public-rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/public-rollup.d.ts @@ -1,4 +1,3 @@ - /* Excluded declaration from this release type: combine */ /* Excluded declaration from this release type: combine */ diff --git a/build-tests/api-extractor-scenarios/etc/functionOverload/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/functionOverload/rollup.d.ts new file mode 100644 index 00000000000..6df60cf456b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/rollup.d.ts @@ -0,0 +1,44 @@ +/** + * @alpha + */ +export declare function combine(x: boolean, y: boolean): boolean; + +/** + * @beta + */ +export declare function combine(x: string, y: string): string; + +/** + * @public + */ +export declare function combine(x: number, y: number): number; + +/** + * @beta + */ +export declare function _combine(x: string, y: string): string; + +/** + * @internal + */ +export declare function _combine(x: number, y: number): number; + +/** + * @public + */ +export declare class Combiner { + /** + * @alpha + */ + combine(x: boolean, y: boolean): boolean; + /** + * @beta + */ + combine(x: string, y: string): string; + /** + * @public + */ + combine(x: number, y: number): number; +} + +export { } 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 new file mode 100644 index 00000000000..c1eb4247d74 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json @@ -0,0 +1,227 @@ +{ + "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!useColors:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function useColors(): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "Colorize.red", + "canonicalReference": "@rushstack/terminal!Colorize.red:member" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/importEquals/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "useColors" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..d6c801106bd --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importEquals/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 + +import { Colorize } from '@rushstack/terminal'; + +// @public (undocumented) +export function useColors(): typeof Colorize.red; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/importEquals/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/importEquals/rollup.d.ts new file mode 100644 index 00000000000..49db8d3d46d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importEquals/rollup.d.ts @@ -0,0 +1,6 @@ +import { Colorize } from '@rushstack/terminal'; + +/** @public */ +export declare function useColors(): typeof Colorize.red; + +export { } 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 new file mode 100644 index 00000000000..b46345fa992 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.json @@ -0,0 +1,287 @@ +{ + "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": "Interface", + "canonicalReference": "api-extractor-scenarios!A:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface A extends " + }, + { + "kind": "Reference", + "text": "Lib1Class", + "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/importType/index.ts", + "releaseTag": "Public", + "name": "A", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 2 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!B:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface B extends " + }, + { + "kind": "Reference", + "text": "Lib1Interface", + "canonicalReference": "api-extractor-lib1-test!Lib1Interface:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/importType/index.ts", + "releaseTag": "Public", + "name": "B", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 2 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!C:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface C extends " + }, + { + "kind": "Reference", + "text": "Renamed", + "canonicalReference": "api-extractor-lib1-test!Lib1Interface:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/importType/index.ts", + "releaseTag": "Public", + "name": "C", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 2 + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..fc1e13919dd --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.md @@ -0,0 +1,24 @@ +## 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 + +import type { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; + +// @public (undocumented) +export interface A extends Lib1Class { +} + +// @public (undocumented) +export interface B extends Lib1Interface { +} + +// @public (undocumented) +export interface C extends Lib1Interface { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/importType/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/importType/rollup.d.ts new file mode 100644 index 00000000000..79be312a695 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/importType/rollup.d.ts @@ -0,0 +1,16 @@ +import type { Lib1Class } from 'api-extractor-lib1-test'; +import { Lib1Interface } from 'api-extractor-lib1-test'; + +/** @public */ +export declare interface A extends Lib1Class { +} + +/** @public */ +export declare interface B extends Lib1Interface { +} + +/** @public */ +export declare interface C extends Lib1Interface { +} + +export { } 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 new file mode 100644 index 00000000000..c7fccc789df --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json @@ -0,0 +1,691 @@ +{ + "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!~AnotherDuplicateName_2:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "declare class AnotherDuplicateName " + } + ], + "fileUrlPath": "src/includeForgottenExports/internal1.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "AnotherDuplicateName_2", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class", + "docComment": "/**\n * This forgotten item has the same name as another forgotten item in another file. They should be given unique names.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "declare class AnotherDuplicateName " + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "AnotherDuplicateName", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!~DuplicateName_2:type", + "docComment": "/**\n * Will be renamed to avoid a name conflict with the exported `DuplicateName` from index.ts.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "type DuplicateName = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/internal1.ts", + "releaseTag": "Public", + "name": "DuplicateName_2", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!DuplicateName:type", + "docComment": "/**\n * This type is exported but has the same name as a forgotten type in './internal.ts'. This forgotten type is also included in the API report and doc model files. The forgotten type will be renamed to avoid a name conflict.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type DuplicateName = " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "name": "DuplicateName", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport1:class", + "docComment": "/**\n * `ForgottenExport2` wants to inherit this doc comment, but unfortunately this isn't supported yet\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "declare class ForgottenExport1 " + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ForgottenExport1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Constructor", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport1:constructor(1)", + "docComment": "/**\n * Constructs a new instance of the `ForgottenExport1` class\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "constructor();" + } + ], + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [] + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport1#prop:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "prop?: " + }, + { + "kind": "Reference", + "text": "ForgottenExport2", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport2:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": true, + "releaseTag": "Public", + "name": "prop", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport2:type", + "docComment": "/**\n * {@inheritDoc ForgottenExport1}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "type ForgottenExport2 = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "name": "ForgottenExport2", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport4:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "declare namespace ForgottenExport4 " + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "name": "ForgottenExport4", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport4~ForgottenExport5:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class ForgottenExport5 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "ForgottenExport5", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport6:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ForgottenExport6 " + } + ], + "fileUrlPath": "src/includeForgottenExports/internal2.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ForgottenExport6", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!~internal2:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "None", + "name": "internal2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!~internal2.ForgottenExport6:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ForgottenExport6 " + } + ], + "fileUrlPath": "src/includeForgottenExports/internal2.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ForgottenExport6", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction1:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction1(): " + }, + { + "kind": "Reference", + "text": "ForgottenExport1", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport1:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction1" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction2:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction2(): " + }, + { + "kind": "Reference", + "text": "DuplicateName", + "canonicalReference": "api-extractor-scenarios!~DuplicateName_2:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/internal1.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction2" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction4:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction4(): " + }, + { + "kind": "Reference", + "text": "ForgottenExport4.ForgottenExport5", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport4.ForgottenExport5:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction4" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction5:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction5(): " + }, + { + "kind": "Reference", + "text": "internal2.ForgottenExport6", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport6:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction5" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction6:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction6(): " + }, + { + "kind": "Reference", + "text": "AnotherDuplicateName", + "canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction6" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction7:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction7(): " + }, + { + "kind": "Reference", + "text": "AnotherDuplicateName", + "canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName_2:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/includeForgottenExports/internal1.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction7" + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!SomeNamespace1:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace SomeNamespace1 " + } + ], + "fileUrlPath": "src/includeForgottenExports/index.ts", + "releaseTag": "Public", + "name": "SomeNamespace1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SomeNamespace1.ForgottenExport3:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class ForgottenExport3 " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "ForgottenExport3", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!SomeNamespace1.someFunction3:function(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export function someFunction3(): " + }, + { + "kind": "Reference", + "text": "ForgottenExport3", + "canonicalReference": "api-extractor-scenarios!SomeNamespace1~ForgottenExport3:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction3" + } + ] + } + ] + } + ] +} 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 new file mode 100644 index 00000000000..43157fe55bb --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md @@ -0,0 +1,94 @@ +## 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 +class AnotherDuplicateName { +} + +// @public (undocumented) +class AnotherDuplicateName_2 { +} + +// @public +export type DuplicateName = boolean; + +// @public +type DuplicateName_2 = number; + +// @public +class ForgottenExport1 { + constructor(); + // Warning: (ae-forgotten-export) The symbol "ForgottenExport2" needs to be exported by the entry point index.d.ts + // + // (undocumented) + prop?: ForgottenExport2; +} + +// Warning: (ae-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: The package "api-extractor-scenarios" does not have an export "ForgottenExport1" +// +// @public (undocumented) +type ForgottenExport2 = number; + +// @public (undocumented) +namespace ForgottenExport4 { + // (undocumented) + class ForgottenExport5 { + } +} + +// @public (undocumented) +class ForgottenExport6 { +} + +declare namespace internal2 { + export { + ForgottenExport6 + } +} + +// Warning: (ae-forgotten-export) The symbol "ForgottenExport1" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction1(): ForgottenExport1; + +// Warning: (ae-forgotten-export) The symbol "DuplicateName_2" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction2(): DuplicateName_2; + +// Warning: (ae-forgotten-export) The symbol "ForgottenExport4" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction4(): ForgottenExport4.ForgottenExport5; + +// Warning: (ae-forgotten-export) The symbol "internal2" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction5(): internal2.ForgottenExport6; + +// Warning: (ae-forgotten-export) The symbol "AnotherDuplicateName" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction6(): AnotherDuplicateName; + +// Warning: (ae-forgotten-export) The symbol "AnotherDuplicateName_2" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function someFunction7(): AnotherDuplicateName_2; + +// @public (undocumented) +export namespace SomeNamespace1 { + // (undocumented) + export class ForgottenExport3 { + } + // (undocumented) + export function someFunction3(): ForgottenExport3; + {}; +} + +// (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 new file mode 100644 index 00000000000..8010e499625 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts @@ -0,0 +1,86 @@ +/** + * This forgotten item has the same name as another forgotten item in another + * file. They should be given unique names. + * @public + */ +declare class AnotherDuplicateName { +} + +/** @public */ +declare class AnotherDuplicateName_2 { +} + +/** + * This type is exported but has the same name as a forgotten type in './internal.ts'. This + * forgotten type is also included in the API report and doc model files. The forgotten type + * will be renamed to avoid a name conflict. + * @public + */ +export declare type DuplicateName = boolean; + +/** + * Will be renamed to avoid a name conflict with the exported `DuplicateName` from + * index.ts. + * @public + */ +declare type DuplicateName_2 = number; + +/** + * `ForgottenExport2` wants to inherit this doc comment, but unfortunately this isn't + * supported yet + * @public + */ +declare class ForgottenExport1 { + prop?: ForgottenExport2; + constructor(); +} + +/** + * @public + * {@inheritDoc ForgottenExport1} + */ +declare type ForgottenExport2 = number; + +/** @public */ +declare namespace ForgottenExport4 { + class ForgottenExport5 { + } +} + +/** @public */ +declare class ForgottenExport6 { +} + +declare namespace internal2 { + export { + ForgottenExport6 + } +} + +/** @public */ +export declare function someFunction1(): ForgottenExport1; + +/** @public */ +export declare function someFunction2(): DuplicateName_2; + +/** @public */ +export declare function someFunction4(): ForgottenExport4.ForgottenExport5; + +/** @public */ +export declare function someFunction5(): internal2.ForgottenExport6; + +/** @public */ +export declare function someFunction6(): AnotherDuplicateName; + +/** @public */ +export declare function someFunction7(): AnotherDuplicateName_2; + +/** @public */ +export declare namespace SomeNamespace1 { + export class ForgottenExport3 { + } + export function someFunction3(): ForgottenExport3; + {}; +} + +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 new file mode 100644 index 00000000000..53b805d5e00 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.json @@ -0,0 +1,297 @@ +{ + "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!alphaFunctionReturnsBeta:function(1)", + "docComment": "/**\n * It's okay for an \"alpha\" function to reference a \"beta\" symbol, because \"beta\" is more public than \"alpha\".\n *\n * @alpha\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function alphaFunctionReturnsBeta(): " + }, + { + "kind": "Reference", + "text": "IBeta", + "canonicalReference": "api-extractor-scenarios!IBeta:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/inconsistentReleaseTags/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Alpha", + "overloadIndex": 1, + "parameters": [], + "name": "alphaFunctionReturnsBeta" + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!IBeta:interface", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface IBeta " + } + ], + "fileUrlPath": "src/inconsistentReleaseTags/index.ts", + "releaseTag": "Beta", + "name": "IBeta", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IBeta#x:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Beta", + "name": "x", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!publicFunctionReturnsBeta:function(1)", + "docComment": "/**\n * It's not okay for a \"public\" function to reference a \"beta\" symbol, because \"beta\" is less public than \"public\".\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function publicFunctionReturnsBeta(): " + }, + { + "kind": "Reference", + "text": "IBeta", + "canonicalReference": "api-extractor-scenarios!IBeta:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/inconsistentReleaseTags/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "publicFunctionReturnsBeta" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..b7d9ece60e4 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## 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 + +// @alpha +export function alphaFunctionReturnsBeta(): IBeta; + +// @beta (undocumented) +export interface IBeta { + // (undocumented) + x: number; +} + +// Warning: (ae-incompatible-release-tags) The symbol "publicFunctionReturnsBeta" is marked as @public, but its signature references "IBeta" which is marked as @beta +// +// @public +export function publicFunctionReturnsBeta(): IBeta; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/rollup.d.ts new file mode 100644 index 00000000000..97cc68d2ebf --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/rollup.d.ts @@ -0,0 +1,20 @@ +/** + * It's okay for an "alpha" function to reference a "beta" symbol, + * because "beta" is more public than "alpha". + * @alpha + */ +export declare function alphaFunctionReturnsBeta(): IBeta; + +/** @beta */ +export declare interface IBeta { + x: number; +} + +/** + * It's not okay for a "public" function to reference a "beta" symbol, + * because "beta" is less public than "public". + * @public + */ +export declare function publicFunctionReturnsBeta(): IBeta; + +export { } 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 new file mode 100644 index 00000000000..c69fe4339a2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.json @@ -0,0 +1,302 @@ +{ + "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!inheritsFromExternal:var", + "docComment": "/**\n * {@inheritDoc some-external-library#foo}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "inheritsFromExternal = " + }, + { + "kind": "Content", + "text": "3" + } + ], + "fileUrlPath": "src/inheritDoc/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "inheritsFromExternal", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!inheritsFromInternal:var", + "docComment": "/**\n * An API item with its own documentation.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "inheritsFromInternal = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "fileUrlPath": "src/inheritDoc/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "inheritsFromInternal", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!inheritsFromInvalidInternal:var", + "docComment": "/**\n * {@inheritDoc nonExistentTarget}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "inheritsFromInvalidInternal = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "fileUrlPath": "src/inheritDoc/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "inheritsFromInvalidInternal", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!withOwnDocs:var", + "docComment": "/**\n * An API item with its own documentation.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "withOwnDocs = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "fileUrlPath": "src/inheritDoc/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "withOwnDocs", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..1144e1838ad --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## 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 +export const inheritsFromExternal = 3; + +// @public +export const inheritsFromInternal = 1; + +// Warning: (ae-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: The package "api-extractor-scenarios" does not have an export "nonExistentTarget" +// +// @public (undocumented) +export const inheritsFromInvalidInternal = 2; + +// @public +export const withOwnDocs = 0; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/inheritDoc/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/inheritDoc/rollup.d.ts new file mode 100644 index 00000000000..4d235f3d54f --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/inheritDoc/rollup.d.ts @@ -0,0 +1,25 @@ +/** + * {@inheritDoc some-external-library#foo} + * @public + */ +export declare const inheritsFromExternal = 3; + +/** + * {@inheritDoc withOwnDocs} + * @public + */ +export declare const inheritsFromInternal = 1; + +/** + * {@inheritDoc nonExistentTarget} + * @public + */ +export declare const inheritsFromInvalidInternal = 2; + +/** + * An API item with its own documentation. + * @public + */ +export declare const withOwnDocs = 0; + +export { } 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 new file mode 100644 index 00000000000..e52b79b4c90 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.json @@ -0,0 +1,346 @@ +{ + "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!ClassΞ:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ClassΞ " + } + ], + "fileUrlPath": "src/internationalCharacters/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ClassΞ", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassΞ#\"invalid chars\":member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "'invalid chars'(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "\"invalid chars\"" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassΞ#memberΔ:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "memberΔ(paramΩ: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "ClassΞ", + "canonicalReference": "api-extractor-scenarios!ClassΞ:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "paramΩ", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "memberΔ" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassΞ#validChars:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "'validChars'(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "validChars" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..4c99c1e4c5c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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) +class ClassΞ { + // (undocumented) + 'invalid chars'(): void; + // (undocumented) + memberΔ(paramΩ: string): ClassΞ; + // (undocumented) + 'validChars'(): void; +} +export { ClassΞ } +export { ClassΞ as ClassΣ } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/internationalCharacters/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/internationalCharacters/rollup.d.ts new file mode 100644 index 00000000000..bc89687eaed --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/internationalCharacters/rollup.d.ts @@ -0,0 +1,10 @@ +/** @public */ +declare class ClassΞ { + memberΔ(paramΩ: string): ClassΞ; + 'invalid chars'(): void; + 'validChars'(): void; +} +export { ClassΞ } +export { ClassΞ as ClassΣ } + +export { } 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 new file mode 100644 index 00000000000..ce3f72c1a0b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.json @@ -0,0 +1,517 @@ +{ + "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!MergedClassAndInterface:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class MergedClassAndInterface " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MergedClassAndInterface", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MergedClassAndInterface#someProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!MergedClassAndInterface:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface MergedClassAndInterface " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "name": "MergedClassAndInterface", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!MergedClassAndInterface#anotherProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "anotherProp: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "anotherProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "MethodSignature", + "canonicalReference": "api-extractor-scenarios!MergedClassAndInterface#someMethod:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "someMethod(x: " + }, + { + "kind": "Content", + "text": "string | boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isOptional": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "someMethod" + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!MergedClassAndNamespace:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class MergedClassAndNamespace " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MergedClassAndNamespace", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MergedClassAndNamespace#someProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!MergedClassAndNamespace:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace MergedClassAndNamespace " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "name": "MergedClassAndNamespace", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!MergedClassAndNamespace.anotherProp:var", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "anotherProp: " + }, + { + "kind": "Content", + "text": "number" + } + ], + "isReadonly": false, + "releaseTag": "Public", + "name": "anotherProp", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!MergedInterfaces:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface MergedInterfaces " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "name": "MergedInterfaces", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!MergedInterfaces#someProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "someProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "someProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!MergedNamespaces:namespace", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace MergedNamespaces " + } + ], + "fileUrlPath": "src/mergedDeclarations/index.ts", + "releaseTag": "Public", + "name": "MergedNamespaces", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!MergedNamespaces.AnotherClass:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class AnotherClass " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "AnotherClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!MergedNamespaces.SomeClass:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class SomeClass " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..16be4bda395 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md @@ -0,0 +1,61 @@ +## 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 MergedClassAndInterface { + // (undocumented) + someProp: number; +} + +// @public (undocumented) +export interface MergedClassAndInterface { + // (undocumented) + anotherProp: boolean; + // (undocumented) + someMethod(x: string | boolean): void; +} + +// @public (undocumented) +export class MergedClassAndNamespace { + // (undocumented) + someProp: number; +} + +// @public (undocumented) +export namespace MergedClassAndNamespace { + let // (undocumented) + anotherProp: number; +} + +// @public (undocumented) +export interface MergedInterfaces { + // (undocumented) + someProp: number; +} + +// @public (undocumented) +export interface MergedInterfaces { + // (undocumented) + someProp: number; +} + +// @public (undocumented) +export namespace MergedNamespaces { + // (undocumented) + export class SomeClass { + } +} + +// @public (undocumented) +export namespace MergedNamespaces { + // (undocumented) + export class AnotherClass { + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts new file mode 100644 index 00000000000..3f28488b2f8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts @@ -0,0 +1,44 @@ +/** @public */ +export declare class MergedClassAndInterface { + someProp: number; +} + +/** @public */ +export declare interface MergedClassAndInterface { + anotherProp: boolean; + someMethod(x: string | boolean): void; +} + +/** @public */ +export declare class MergedClassAndNamespace { + someProp: number; +} + +/** @public */ +export declare namespace MergedClassAndNamespace { + let anotherProp: number; +} + +/** @public */ +export declare interface MergedInterfaces { + someProp: number; +} + +/** @public */ +export declare interface MergedInterfaces { + someProp: number; +} + +/** @public */ +export declare namespace MergedNamespaces { + export class SomeClass { + } +} + +/** @public */ +export declare namespace MergedNamespaces { + export class AnotherClass { + } +} + +export { } 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 new file mode 100644 index 00000000000..48db87ac527 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.json @@ -0,0 +1,274 @@ +{ + "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!A:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class A " + } + ], + "fileUrlPath": "src/mixinPattern/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "A", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!A#prop:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "prop?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": true, + "releaseTag": "Public", + "name": "prop", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!B:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class B extends " + }, + { + "kind": "Reference", + "text": "B_base", + "canonicalReference": "api-extractor-scenarios!~B_base" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/mixinPattern/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "B", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..64c6ad22b66 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 A { + // (undocumented) + prop?: string; +} + +// Warning: (ae-forgotten-export) The symbol "B_base" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export class B extends B_base { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts new file mode 100644 index 00000000000..df49ee9bcab --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts @@ -0,0 +1,16 @@ +/** @public */ +export declare class A { + prop?: string; +} + +/** @public */ +export declare class B extends B_base { +} + +declare const B_base: { + new (...args: any[]): { + mixinProp?: string; + }; +} & typeof A; + +export { } 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 new file mode 100644 index 00000000000..6dc01c4631a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.json @@ -0,0 +1,300 @@ +{ + "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": "Interface", + "canonicalReference": "api-extractor-scenarios!DefaultImportTypes:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface DefaultImportTypes " + } + ], + "fileUrlPath": "src/namedDefaultImport/index.ts", + "releaseTag": "Public", + "name": "DefaultImportTypes", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!DefaultImportTypes#dynamicImport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "dynamicImport: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib2-test')." + }, + { + "kind": "Reference", + "text": "default", + "canonicalReference": "api-extractor-lib2-test!DefaultClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "dynamicImport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!DefaultImportTypes#namedImport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "namedImport: " + }, + { + "kind": "Reference", + "text": "DefaultClass_namedImport", + "canonicalReference": "api-extractor-lib2-test!DefaultClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "namedImport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!DefaultImportTypes#reExport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "reExport: " + }, + { + "kind": "Reference", + "text": "DefaultClass_reExport", + "canonicalReference": "api-extractor-lib2-test!DefaultClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "reExport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..286bbca3991 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 + +import { default as default_2 } from 'api-extractor-lib2-test'; + +// @public (undocumented) +export interface DefaultImportTypes { + // (undocumented) + dynamicImport: default_2; + // (undocumented) + namedImport: default_2; + // (undocumented) + reExport: default_2; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts new file mode 100644 index 00000000000..0bf69c07b82 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts @@ -0,0 +1,10 @@ +import { default as default_2 } from 'api-extractor-lib2-test'; + +/** @public */ +export declare interface DefaultImportTypes { + namedImport: default_2; + reExport: default_2; + dynamicImport: default_2; +} + +export { } 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 new file mode 100644 index 00000000000..c5bc0066f09 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json @@ -0,0 +1,307 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!i1:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/namespaceImports/index.ts", + "releaseTag": "None", + "name": "i1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!i1.internal:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/namespaceImports/intermediate1.ts", + "releaseTag": "None", + "name": "internal", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!i1.internal.SomeClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass " + } + ], + "fileUrlPath": "src/namespaceImports/internal.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!i2:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/namespaceImports/index.ts", + "releaseTag": "None", + "name": "i2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!i2.internal:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/namespaceImports/intermediate1.ts", + "releaseTag": "None", + "name": "internal", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!i2.internal.SomeClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass " + } + ], + "fileUrlPath": "src/namespaceImports/internal.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction(): " + }, + { + "kind": "Reference", + "text": "i1.internal.SomeClass", + "canonicalReference": "api-extractor-scenarios!i1.internal.SomeClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/namespaceImports/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..60f137ad0d4 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.md @@ -0,0 +1,36 @@ +## 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 + +declare namespace i1 { + export { + internal + } +} +export { i1 } + +declare namespace i2 { + export { + internal + } +} +export { i2 } + +declare namespace internal { + export { + SomeClass + } +} + +// @public (undocumented) +class SomeClass { +} + +// @public (undocumented) +export function someFunction(): i1.internal.SomeClass; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namespaceImports/rollup.d.ts new file mode 100644 index 00000000000..e19612205d5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports/rollup.d.ts @@ -0,0 +1,28 @@ +declare namespace i1 { + export { + internal + } +} +export { i1 } + +declare namespace i2 { + export { + internal + } +} +export { i2 } + +declare namespace internal { + export { + SomeClass + } +} + +/** @public */ +declare class SomeClass { +} + +/** @public */ +export declare function someFunction(): i1.internal.SomeClass; + +export { } 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 new file mode 100644 index 00000000000..ebe57a27586 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.json @@ -0,0 +1,271 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!internal:namespace", + "docComment": "", + "excerptTokens": [], + "fileUrlPath": "src/namespaceImports2/index.ts", + "releaseTag": "None", + "name": "internal", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!internal.SomeClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass " + } + ], + "fileUrlPath": "src/namespaceImports2/internal.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SomeClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass " + } + ], + "fileUrlPath": "src/namespaceImports2/internal.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction(): " + }, + { + "kind": "Reference", + "text": "SomeClass", + "canonicalReference": "api-extractor-scenarios!SomeClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/namespaceImports2/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..2c624b8845b --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## 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 + +declare namespace internal { + export { + SomeClass + } +} +export { internal } + +// @public (undocumented) +export class SomeClass { +} + +// @public (undocumented) +export function someFunction(): SomeClass; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namespaceImports2/rollup.d.ts new file mode 100644 index 00000000000..06bf37c06b6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports2/rollup.d.ts @@ -0,0 +1,15 @@ +declare namespace internal { + export { + SomeClass + } +} +export { internal } + +/** @public */ +export declare class SomeClass { +} + +/** @public */ +export declare function someFunction(): SomeClass; + +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 new file mode 100644 index 00000000000..f2997df1bb1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.json @@ -0,0 +1,193 @@ +{ + "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": [] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..48f328febb3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 + +// @internal (undocumented) +class _PreapprovedClass { /* (preapproved) */ } + +// @internal (undocumented) +enum _PreapprovedEnum { /* (preapproved) */ } + +// @internal (undocumented) +interface _PreapprovedInterface { /* (preapproved) */ } + +// @internal (undocumented) +namespace _PreapprovedNamespace { /* (preapproved) */ } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts new file mode 100644 index 00000000000..aff9acaaeb3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts @@ -0,0 +1,24 @@ +/** @internal @preapproved */ +export declare class _PreapprovedClass { + member(): void; +} + +/** @internal @preapproved */ +export declare enum _PreapprovedEnum { + ONE = 1, + TWO = 2 +} + +/** @internal @preapproved */ +export declare interface _PreapprovedInterface { + member(): void; +} + +/** @internal @preapproved */ +export declare namespace _PreapprovedNamespace { + export class X { + } + export function f(): void; +} + +export { } 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 new file mode 100644 index 00000000000..87512f5600a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.json @@ -0,0 +1,213 @@ +{ + "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 + } + }, + "projectFolderUrl": "http://github.com/path/to/some/projectFolder", + "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!MyClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class MyClass " + } + ], + "fileUrlPath": "src/projectFolderUrl/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MyClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..4a25f6d57f6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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 MyClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/projectFolderUrl/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/rollup.d.ts new file mode 100644 index 00000000000..f4071697eda --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/rollup.d.ts @@ -0,0 +1,5 @@ +/** @public */ +export declare class MyClass { +} + +export { } 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 new file mode 100644 index 00000000000..c365d60a23a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.json @@ -0,0 +1,502 @@ +{ + "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!MyClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class MyClass " + } + ], + "fileUrlPath": "src/readonlyDeclarations/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "MyClass", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MyClass#_onlyGetter:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "get _onlyGetter(): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "_onlyGetter", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MyClass#readonlyModifier:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly readonlyModifier: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "readonlyModifier", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MyClass#tsDocReadonly:member", + "docComment": "/**\n * @readonly\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "tsDocReadonly: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "tsDocReadonly", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!MyInterface:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface MyInterface " + } + ], + "fileUrlPath": "src/readonlyDeclarations/index.ts", + "releaseTag": "Public", + "name": "MyInterface", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MyInterface#_onlyGetter:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "get _onlyGetter(): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "_onlyGetter", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "IndexSignature", + "canonicalReference": "api-extractor-scenarios!MyInterface:index(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly [x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "]: " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ] + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!MyInterface#readonlyModifier:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly readonlyModifier: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "readonlyModifier", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!MyInterface#tsDocReadonly:member", + "docComment": "/**\n * @readonly\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "set tsDocReadonly(value: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ");" + } + ], + "isReadonly": true, + "isOptional": false, + "releaseTag": "Public", + "name": "tsDocReadonly", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!READONLY_VARIABLE:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "READONLY_VARIABLE = " + }, + { + "kind": "Content", + "text": "\"Hello world!\"" + } + ], + "fileUrlPath": "src/readonlyDeclarations/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "READONLY_VARIABLE", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!TSDOC_READONLY_VARIABLE:var", + "docComment": "/**\n * @public @readonly\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "TSDOC_READONLY_VARIABLE: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/readonlyDeclarations/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "TSDOC_READONLY_VARIABLE", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..50b0d1f6853 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.md @@ -0,0 +1,37 @@ +## 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 MyClass { + // (undocumented) + get _onlyGetter(): string; + // (undocumented) + readonly readonlyModifier: string; + // (undocumented) + tsDocReadonly: string; +} + +// @public (undocumented) +export interface MyInterface { + // (undocumented) + readonly [x: number]: void; + // (undocumented) + get _onlyGetter(): string; + // (undocumented) + readonly readonlyModifier: string; + // (undocumented) + set tsDocReadonly(value: string); +} + +// @public (undocumented) +export const READONLY_VARIABLE = "Hello world!"; + +// @public (undocumented) +export let TSDOC_READONLY_VARIABLE: string; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/rollup.d.ts new file mode 100644 index 00000000000..34b82b0af57 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/rollup.d.ts @@ -0,0 +1,27 @@ +/** @public */ +export declare class MyClass { + get _onlyGetter(): string; + readonly readonlyModifier: string; + /** @readonly */ + tsDocReadonly: string; +} + +/** @public */ +export declare interface MyInterface { + get _onlyGetter(): string; + readonly readonlyModifier: string; + /** @readonly */ + set tsDocReadonly(value: string); + readonly [x: number]: void; +} + +/** @public */ +export declare const READONLY_VARIABLE = "Hello world!"; + +/** + * @public + * @readonly + */ +export declare let TSDOC_READONLY_VARIABLE: string; + +export { } 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 new file mode 100644 index 00000000000..a25d98c8424 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.json @@ -0,0 +1,996 @@ +{ + "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": "Namespace", + "canonicalReference": "api-extractor-scenarios!n1:namespace", + "docComment": "/**\n * Various namespace scenarios.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace n1 " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "name": "n1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!n1.n2:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export namespace n2 " + } + ], + "releaseTag": "Public", + "name": "n2", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!n1.n2.n3:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export namespace n3 " + } + ], + "releaseTag": "Public", + "name": "n3", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!n1.n2.n3.someFunction3:function(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "function someFunction3(): " + }, + { + "kind": "Reference", + "text": "n2.n3.SomeType3", + "canonicalReference": "api-extractor-scenarios!n1.n2.n3.SomeType3:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction3" + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!n1.n2.n3.SomeType3:type", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "type SomeType3 = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "SomeType3", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!n1.n2.someFunction2:function(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export function someFunction2(): " + }, + { + "kind": "Reference", + "text": "SomeType2", + "canonicalReference": "api-extractor-scenarios!n1.n2~SomeType2:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction2" + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!n1.n2.SomeType2:type", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "type SomeType2 = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "SomeType2", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!n1.someFunction1:function(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export function someFunction1(): " + }, + { + "kind": "Reference", + "text": "SomeType1", + "canonicalReference": "api-extractor-scenarios!n1~SomeType1:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction1" + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!n1.SomeType1:type", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "type SomeType1 = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "SomeType1", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SomeClass1:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass1 " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!SomeClass1.staticProp:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "static staticProp: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "staticProp", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": true, + "isProtected": false, + "isAbstract": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SomeClass3:class", + "docComment": "/**\n * Unexported symbol reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass3 extends " + }, + { + "kind": "Reference", + "text": "SomeClass2", + "canonicalReference": "api-extractor-scenarios!~SomeClass2:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass3", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!SomeClass4:class", + "docComment": "/**\n * Reference to a symbol exported from another file, but not exported from the package.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class SomeClass4 extends " + }, + { + "kind": "Reference", + "text": "SomeClass5", + "canonicalReference": "api-extractor-scenarios!~SomeClass5:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "SomeClass4", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Enum", + "canonicalReference": "api-extractor-scenarios!SomeEnum:enum", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum SomeEnum " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "name": "SomeEnum", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!SomeEnum.A:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "A = " + }, + { + "kind": "Content", + "text": "\"A\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "A" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!SomeEnum.B:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "B = " + }, + { + "kind": "Content", + "text": "\"B\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "B" + }, + { + "kind": "EnumMember", + "canonicalReference": "api-extractor-scenarios!SomeEnum.C:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "C = " + }, + { + "kind": "Content", + "text": "\"C\"" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "name": "C" + } + ] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction5:function(1)", + "docComment": "/**\n * Enum member reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction5(): " + }, + { + "kind": "Reference", + "text": "SomeEnum.A", + "canonicalReference": "api-extractor-scenarios!SomeEnum.A:member" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction5" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction6:function(1)", + "docComment": "/**\n * Static class member reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction6(): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "SomeClass1.staticProp", + "canonicalReference": "api-extractor-scenarios!SomeClass1.staticProp:member" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "someFunction6" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction7:function(1)", + "docComment": "/**\n * Global symbol reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction7({ " + }, + { + "kind": "Reference", + "text": "then", + "canonicalReference": "!Promise#then" + }, + { + "kind": "Content", + "text": ": then2 }: " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "Date.prototype.getDate", + "canonicalReference": "!Date#getDate:member" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "returnTypeTokenRange": { + "startIndex": 6, + "endIndex": 8 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ then: then2 }", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 5 + }, + "isOptional": false + } + ], + "name": "someFunction7" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction8:function(1)", + "docComment": "/**\n * External symbol reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction8({ " + }, + { + "kind": "Reference", + "text": "prop", + "canonicalReference": "api-extractor-lib2-test!Lib2Class#prop" + }, + { + "kind": "Content", + "text": ": prop2 }: " + }, + { + "kind": "Reference", + "text": "Lib2Class", + "canonicalReference": "api-extractor-lib2-test!Lib2Class:class" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ prop: prop2 }", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "someFunction8" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!someFunction9:function(1)", + "docComment": "/**\n * Interface member reference.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function someFunction9({ " + }, + { + "kind": "Reference", + "text": "prop", + "canonicalReference": "api-extractor-scenarios!SomeInterface1#prop" + }, + { + "kind": "Content", + "text": ": prop2 }: " + }, + { + "kind": "Reference", + "text": "SomeInterface1", + "canonicalReference": "api-extractor-scenarios!SomeInterface1:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ prop: prop2 }", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "someFunction9" + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!SomeInterface1:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface SomeInterface1 " + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "releaseTag": "Public", + "name": "SomeInterface1", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!SomeInterface1#[SomeSymbol1]:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "[" + }, + { + "kind": "Reference", + "text": "SomeSymbol1", + "canonicalReference": "api-extractor-scenarios!SomeSymbol1:var" + }, + { + "kind": "Content", + "text": "]: " + }, + { + "kind": "Content", + "text": "() => string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "[SomeSymbol1]", + "propertyTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!SomeInterface1#prop:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "prop: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "prop", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!SomeInterface1#ThisIsSomeVar1:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "[" + }, + { + "kind": "Reference", + "text": "SomeVar1", + "canonicalReference": "api-extractor-scenarios!SomeVar1:var" + }, + { + "kind": "Content", + "text": "]: " + }, + { + "kind": "Content", + "text": "() => string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "ThisIsSomeVar1", + "propertyTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!SomeSymbol1:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "SomeSymbol1: " + }, + { + "kind": "Content", + "text": "unique symbol" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "SomeSymbol1", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!SomeVar1:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "SomeVar1 = " + }, + { + "kind": "Content", + "text": "\"ThisIsSomeVar1\"" + } + ], + "fileUrlPath": "src/referenceTokens/index.ts", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "SomeVar1", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] +} 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 new file mode 100644 index 00000000000..065b8df0b85 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md @@ -0,0 +1,98 @@ +## 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 + +import { Lib2Class } from 'api-extractor-lib2-test'; + +// @public +export namespace n1 { + // (undocumented) + export namespace n2 { + // (undocumented) + export namespace n3 { + // (undocumented) + export function someFunction3(): n2.n3.SomeType3; + // (undocumented) + export type SomeType3 = number; + } + // (undocumented) + export function someFunction2(): SomeType2; + // (undocumented) + export type SomeType2 = number; + {}; + } + // (undocumented) + export function someFunction1(): SomeType1; + // (undocumented) + export type SomeType1 = number; + {}; +} + +// @public (undocumented) +export class SomeClass1 { + // (undocumented) + static staticProp: number; +} + +// Warning: (ae-forgotten-export) The symbol "SomeClass2" needs to be exported by the entry point index.d.ts +// +// @public +export class SomeClass3 extends SomeClass2 { +} + +// Warning: (ae-forgotten-export) The symbol "SomeClass5" needs to be exported by the entry point index.d.ts +// +// @public +export class SomeClass4 extends SomeClass5 { +} + +// @public (undocumented) +export enum SomeEnum { + // (undocumented) + A = "A", + // (undocumented) + B = "B", + // (undocumented) + C = "C" +} + +// @public +export function someFunction5(): SomeEnum.A; + +// @public +export function someFunction6(): typeof SomeClass1.staticProp; + +// @public +export function someFunction7({ then: then2 }: Promise): typeof Date.prototype.getDate; + +// @public +export function someFunction8({ prop: prop2 }: Lib2Class): void; + +// @public +export function someFunction9({ prop: prop2 }: SomeInterface1): void; + +// @public (undocumented) +export interface SomeInterface1 { + // (undocumented) + prop: number; +} + +// @public +export interface SomeInterface1 { + // (undocumented) + [SomeSymbol1]: () => string; + // (undocumented) + [SomeVar1]: () => string; +} + +// @public (undocumented) +export const SomeSymbol1: unique symbol; + +// @public (undocumented) +export const SomeVar1 = "ThisIsSomeVar1"; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts new file mode 100644 index 00000000000..d1e60042702 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts @@ -0,0 +1,104 @@ +import { Lib2Class } from 'api-extractor-lib2-test'; + +/** + * Various namespace scenarios. + * @public + */ +export declare namespace n1 { + export type SomeType1 = number; + export function someFunction1(): SomeType1; + export namespace n2 { + export type SomeType2 = number; + export function someFunction2(): SomeType2; + export namespace n3 { + export type SomeType3 = number; + export function someFunction3(): n2.n3.SomeType3; + } + {}; + } + {}; +} + +/** @public */ +export declare class SomeClass1 { + static staticProp: number; +} + +declare class SomeClass2 { +} + +/** + * Unexported symbol reference. + * @public + */ +export declare class SomeClass3 extends SomeClass2 { +} + +/** + * Reference to a symbol exported from another file, but not exported from the package. + * @public + */ +export declare class SomeClass4 extends SomeClass5 { +} + +declare class SomeClass5 { +} + +/** @public */ +export declare enum SomeEnum { + A = "A", + B = "B", + C = "C" +} + +/** + * Enum member reference. + * @public + */ +export declare function someFunction5(): SomeEnum.A; + +/** + * Static class member reference. + * @public + */ +export declare function someFunction6(): typeof SomeClass1.staticProp; + +/** + * Global symbol reference. + * @public + */ +export declare function someFunction7({ then: then2 }: Promise): typeof Date.prototype.getDate; + +/** + * External symbol reference. + * @public + */ +export declare function someFunction8({ prop: prop2 }: Lib2Class): void; + +/** + * Interface member reference. + * @public + */ +export declare function someFunction9({ prop: prop2 }: SomeInterface1): void; + +/** @public */ +export declare interface SomeInterface1 { + prop: number; +} + +/** + * References to computed properties. + * @public + */ +export declare interface SomeInterface1 { + [SomeVar1]: () => string; + [SomeSymbol1]: () => string; +} + +/** @public */ +export declare const SomeSymbol1: unique symbol; + +/** @public */ +export declare const SomeVar1 = "ThisIsSomeVar1"; + +export { } 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 new file mode 100644 index 00000000000..a6a20a02af3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.json @@ -0,0 +1,437 @@ +{ + "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!ExampleA:class", + "docComment": "/**\n * Doc comment\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExampleA " + } + ], + "fileUrlPath": "src/spanSorting/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExampleA", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!ExampleA#member1:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "member1: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "member1", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ExampleA#member2:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "member2(): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "member2" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!ExampleB:class", + "docComment": "/**\n * Doc comment\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExampleB " + } + ], + "fileUrlPath": "src/spanSorting/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExampleB", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ExampleB#tryLoadFromFile:member(1)", + "docComment": "/**\n * If the file exists, calls loadFromFile().\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "tryLoadFromFile(approvedPackagesPolicyEnabled: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "approvedPackagesPolicyEnabled", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "tryLoadFromFile" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!ExampleC:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ExampleC " + } + ], + "fileUrlPath": "src/spanSorting/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ExampleC", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ExampleC#member1:member(1)", + "docComment": "/**\n * This comment is improperly formatted TSDoc. Note that Prettier doesn't try to format it.\n *\n * @returns the return value\n *\n * @throws\n *\n * an exception\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "member1(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "member1" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!exampleD:function(1)", + "docComment": "/**\n * Outer description\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "exampleD: (o: " + }, + { + "kind": "Content", + "text": "{\n a: number;\n b(): string;\n}" + }, + { + "kind": "Content", + "text": ") => " + }, + { + "kind": "Content", + "text": "void" + } + ], + "fileUrlPath": "src/spanSorting/index.ts", + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "o", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "exampleD" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..9ac078af881 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.md @@ -0,0 +1,33 @@ +## 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 +export class ExampleA { + // (undocumented) + member1: string; + // (undocumented) + member2(): Promise; +} + +// @public +export class ExampleB { + tryLoadFromFile(approvedPackagesPolicyEnabled: boolean): boolean; +} + +// @public (undocumented) +export class ExampleC { + member1(): void; +} + +// @public +export const exampleD: (o: { + a: number; + b(): string; +}) => void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/spanSorting/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/spanSorting/rollup.d.ts new file mode 100644 index 00000000000..fc76f8e283d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/spanSorting/rollup.d.ts @@ -0,0 +1,54 @@ +/** + * Doc comment + * @public + */ +export declare class ExampleA { + private _member3; + member2(): Promise; + member1: string; +} + +/** + * Doc comment + * @public + */ +export declare class ExampleB { + /** + * If the file exists, calls loadFromFile(). + */ + tryLoadFromFile(approvedPackagesPolicyEnabled: boolean): boolean; + /** + * Helper function that adds an already created ApprovedPackagesItem to the + * list and set. + */ + private _addItem; +} + +/** @public */ +export declare class ExampleC { + /** + * This comment is improperly formatted TSDoc. + * Note that Prettier doesn't try to format it. + @returns the return value + @throws an exception + */ + member1(): void; +} + +/** + * Outer description + * @public + */ +export declare const exampleD: (o: { + /** + * Inner description + */ + a: number; + /** + * @returns a string + * {@link http://example.com} + */ + b(): string; +}) => void; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.json deleted file mode 100644 index 655d30ae318..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!ambientNameConflict:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function ambientNameConflict(p1: " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "" - }, - { - "kind": "Content", - "text": ", p2: " - }, - { - "kind": "Reference", - "text": "MyPromise", - "canonicalReference": "api-extractor-scenarios!Promise:class" - }, - { - "kind": "Content", - "text": "" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "p1", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "parameterName": "p2", - "parameterTypeTokenRange": { - "startIndex": 4, - "endIndex": 6 - } - } - ], - "name": "ambientNameConflict" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.md deleted file mode 100644 index c45bb8b36c2..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/api-extractor-scenarios.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## 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 "Promise" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export function ambientNameConflict(p1: Promise, p2: Promise_2): void; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/rollup.d.ts deleted file mode 100644 index 45f4cc1907f..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict/rollup.d.ts +++ /dev/null @@ -1,14 +0,0 @@ - -/** - * @public - */ -export declare function ambientNameConflict(p1: Promise, p2: Promise_2): void; - -/** - * @public - */ -declare class Promise_2 { - notTheRealPromise(arg: T): void; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.json deleted file mode 100644 index e7afa61f5ff..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!Date_2:class", - "docComment": "/**\n * A local class declaration whose name is the same as the system `Date` global symbol.\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class Date " - } - ], - "releaseTag": "Public", - "name": "Date_2", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!getDate:function(1)", - "docComment": "/**\n * An API that references the system `Date` global symbol.\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function getDate(): " - }, - { - "kind": "Reference", - "text": "Date", - "canonicalReference": "!Date:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "getDate" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.md deleted file mode 100644 index 3c0b9adff80..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,19 +0,0 @@ -## 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 -class Date_2 { -} - -export { Date_2 as Date } - -// @public -export function getDate(): Date; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/rollup.d.ts deleted file mode 100644 index e16e801c922..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ambientNameConflict2/rollup.d.ts +++ /dev/null @@ -1,16 +0,0 @@ - -/** - * A local class declaration whose name is the same as the system `Date` global symbol. - * @public - */ -declare class Date_2 { -} -export { Date_2 as Date } - -/** - * An API that references the system `Date` global symbol. - * @public - */ -export declare function getDate(): Date; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.json deleted file mode 100644 index 57eaf238582..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!MyClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class MyClass " - } - ], - "releaseTag": "Public", - "name": "MyClass", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.md deleted file mode 100644 index 3d340e2002e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/api-extractor-scenarios.api.md +++ /dev/null @@ -1,23 +0,0 @@ -## 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 - -// @internal (undocumented) -export interface _IInternalThing { - // (undocumented) - title: string; -} - -// @public (undocumented) -export class MyClass { - // @internal (undocumented) - get _thing(): _IInternalThing; - set _thing(value: _IInternalThing); -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/rollup.d.ts deleted file mode 100644 index 69ca9020e43..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/ancillaryDeclarations/rollup.d.ts +++ /dev/null @@ -1,14 +0,0 @@ - -/** @internal */ -export declare interface _IInternalThing { - title: string; -} - -/** @public */ -export declare class MyClass { - /** @internal */ - get _thing(): _IInternalThing; - set _thing(value: _IInternalThing); -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json deleted file mode 100644 index d1b9bba4e33..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json +++ /dev/null @@ -1,537 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!AbstractClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare abstract class AbstractClass " - } - ], - "releaseTag": "Public", - "name": "AbstractClass", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!AbstractClass#member:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "abstract member(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "member" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class ClassWithTypeLiterals " - } - ], - "releaseTag": "Public", - "name": "ClassWithTypeLiterals", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals#method1:member(1)", - "docComment": "/**\n * type literal in\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "method1(vector: " - }, - { - "kind": "Content", - "text": "{\n x: number;\n y: number;\n }" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "vector", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "method1" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals#method2:member(1)", - "docComment": "/**\n * type literal output\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "method2(): " - }, - { - "kind": "Content", - "text": "{\n classValue: " - }, - { - "kind": "Reference", - "text": "ClassWithTypeLiterals", - "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals:class" - }, - { - "kind": "Content", - "text": ";\n callback: () => number;\n } | undefined" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "method2" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Enum", - "canonicalReference": "api-extractor-scenarios!ConstEnum:enum", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare const enum ConstEnum " - } - ], - "releaseTag": "Public", - "name": "ConstEnum", - "members": [ - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!ConstEnum.One:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "One = " - }, - { - "kind": "Content", - "text": "1" - } - ], - "releaseTag": "Public", - "name": "One", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!ConstEnum.Two:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "Two = " - }, - { - "kind": "Content", - "text": "2" - } - ], - "releaseTag": "Public", - "name": "Two", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!ConstEnum.Zero:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "Zero = " - }, - { - "kind": "Content", - "text": "0" - } - ], - "releaseTag": "Public", - "name": "Zero", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - }, - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!IInterface:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface IInterface " - } - ], - "releaseTag": "Public", - "name": "IInterface", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "api-extractor-scenarios!IInterface#member:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "member: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "member", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Namespace", - "canonicalReference": "api-extractor-scenarios!NamespaceContainingVariable:namespace", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare namespace NamespaceContainingVariable " - } - ], - "releaseTag": "Public", - "name": "NamespaceContainingVariable", - "members": [ - { - "kind": "Variable", - "canonicalReference": "api-extractor-scenarios!NamespaceContainingVariable.constVariable:var", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "constVariable: " - }, - { - "kind": "Content", - "text": "object[]" - } - ], - "releaseTag": "Public", - "name": "constVariable", - "variableTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Variable", - "canonicalReference": "api-extractor-scenarios!NamespaceContainingVariable.variable:var", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "variable: " - }, - { - "kind": "Content", - "text": "object[]" - } - ], - "releaseTag": "Public", - "name": "variable", - "variableTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - }, - { - "kind": "Enum", - "canonicalReference": "api-extractor-scenarios!RegularEnum:enum", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare enum RegularEnum " - } - ], - "releaseTag": "Public", - "name": "RegularEnum", - "members": [ - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.One:member", - "docComment": "/**\n * These are some docs for One\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "One = " - }, - { - "kind": "Content", - "text": "1" - } - ], - "releaseTag": "Public", - "name": "One", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.Two:member", - "docComment": "/**\n * These are some docs for Two\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "Two = " - }, - { - "kind": "Content", - "text": "2" - } - ], - "releaseTag": "Public", - "name": "Two", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.Zero:member", - "docComment": "/**\n * These are some docs for Zero\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "Zero = " - }, - { - "kind": "Content", - "text": "0" - } - ], - "releaseTag": "Public", - "name": "Zero", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!SimpleClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class SimpleClass " - } - ], - "releaseTag": "Public", - "name": "SimpleClass", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!SimpleClass#member:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "member(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "member" - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!SimpleClass#readonlyProperty:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "get readonlyProperty(): " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "readonlyProperty", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!SimpleClass#writeableProperty:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "get writeableProperty(): " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - }, - { - "kind": "Content", - "text": "\n\nset writeableProperty(value: string);" - } - ], - "releaseTag": "Public", - "name": "writeableProperty", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Variable", - "canonicalReference": "api-extractor-scenarios!VARIABLE:var", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "VARIABLE: " - }, - { - "kind": "Content", - "text": "string" - } - ], - "releaseTag": "Public", - "name": "VARIABLE", - "variableTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.md deleted file mode 100644 index f3322988216..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.md +++ /dev/null @@ -1,73 +0,0 @@ -## 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 abstract class AbstractClass { - // (undocumented) - abstract member(): void; -} - -// @public (undocumented) -export class ClassWithTypeLiterals { - method1(vector: { - x: number; - y: number; - }): void; - method2(): { - classValue: ClassWithTypeLiterals; - callback: () => number; - } | undefined; -} - -// @public (undocumented) -export const enum ConstEnum { - // (undocumented) - One = 1, - // (undocumented) - Two = 2, - // (undocumented) - Zero = 0 -} - -// @public (undocumented) -export interface IInterface { - // (undocumented) - member: string; -} - -// @public (undocumented) -export namespace NamespaceContainingVariable { - let // (undocumented) - variable: object[]; - let // (undocumented) - constVariable: object[]; -} - -// @public (undocumented) -export enum RegularEnum { - One = 1, - Two = 2, - Zero = 0 -} - -// @public (undocumented) -export class SimpleClass { - // (undocumented) - member(): void; - // (undocumented) - get readonlyProperty(): string; - // (undocumented) - get writeableProperty(): string; - set writeableProperty(value: string); -} - -// @public (undocumented) -export const VARIABLE: string; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/rollup.d.ts deleted file mode 100644 index 028321bcdaa..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/rollup.d.ts +++ /dev/null @@ -1,66 +0,0 @@ - -/** @public */ -export declare abstract class AbstractClass { - abstract member(): void; -} - -/** @public */ -export declare class ClassWithTypeLiterals { - /** type literal in */ - method1(vector: { - x: number; - y: number; - }): void; - /** type literal output */ - method2(): { - classValue: ClassWithTypeLiterals; - callback: () => number; - } | undefined; -} - -/** @public */ -export declare const enum ConstEnum { - Zero = 0, - One = 1, - Two = 2 -} - -/** @public */ -export declare interface IInterface { - member: string; -} - -/** @public */ -export declare namespace NamespaceContainingVariable { - let variable: object[]; - let constVariable: object[]; -} - -/** @public */ -export declare enum RegularEnum { - /** - * These are some docs for Zero - */ - Zero = 0, - /** - * These are some docs for One - */ - One = 1, - /** - * These are some docs for Two - */ - Two = 2 -} - -/** @public */ -export declare class SimpleClass { - member(): void; - get readonlyProperty(): string; - get writeableProperty(): string; - set writeableProperty(value: string); -} - -/** @public */ -export declare const VARIABLE: string; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json deleted file mode 100644 index 795771c3e6c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!f:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function f(arg1: " - }, - { - "kind": "Reference", - "text": "Lib1Class", - "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" - }, - { - "kind": "Content", - "text": ", arg2: " - }, - { - "kind": "Reference", - "text": "Lib2Class", - "canonicalReference": "api-extractor-lib2-test!Lib2Class:class" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "arg1", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "arg2", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "f" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.md deleted file mode 100644 index cdceb02643d..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.md +++ /dev/null @@ -1,17 +0,0 @@ -## 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 - -import { Lib2Class } from 'api-extractor-lib2-test/lib/index'; - -// Warning: (ae-forgotten-export) The symbol "Lib1Class" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export function f(arg1: Lib1Class, arg2: Lib2Class): void; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/rollup.d.ts deleted file mode 100644 index 8b366c41519..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/rollup.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Lib2Class } from 'api-extractor-lib2-test/lib/index'; - -/** @public */ -export declare function f(arg1: Lib1Class, arg2: Lib2Class): void; - -/** @public */ -declare class Lib1Class extends Lib1ForgottenExport { - readonly readonlyProperty: string; - writeableProperty: string; -} - -declare class Lib1ForgottenExport { -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json deleted file mode 100644 index dca6d2b0978..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!IFile:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class IFile " - } - ], - "releaseTag": "Public", - "name": "IFile", - "members": [ - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFile#containingFolder:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "containingFolder: " - }, - { - "kind": "Reference", - "text": "IFolder", - "canonicalReference": "api-extractor-scenarios!IFolder:class" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "containingFolder", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!IFolder:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class IFolder " - } - ], - "releaseTag": "Public", - "name": "IFolder", - "members": [ - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFolder#containingFolder:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "containingFolder: " - }, - { - "kind": "Reference", - "text": "IFolder", - "canonicalReference": "api-extractor-scenarios!IFolder:class" - }, - { - "kind": "Content", - "text": " | undefined" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "containingFolder", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFolder#files:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "files: " - }, - { - "kind": "Reference", - "text": "IFile", - "canonicalReference": "api-extractor-scenarios!IFile:class" - }, - { - "kind": "Content", - "text": "[]" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "files", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.md deleted file mode 100644 index 1622ba6b582..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.md +++ /dev/null @@ -1,24 +0,0 @@ -## 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 IFile { - // (undocumented) - containingFolder: IFolder; -} - -// @public (undocumented) -export class IFolder { - // (undocumented) - containingFolder: IFolder | undefined; - // (undocumented) - files: IFile[]; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/rollup.d.ts deleted file mode 100644 index 970173bd19f..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/rollup.d.ts +++ /dev/null @@ -1,13 +0,0 @@ - -/** @public */ -export declare class IFile { - containingFolder: IFolder; -} - -/** @public */ -export declare class IFolder { - containingFolder: IFolder | undefined; - files: IFile[]; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json deleted file mode 100644 index 0acf135f11c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,172 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!A:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!B:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class B " - } - ], - "releaseTag": "Public", - "name": "B", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!IFile:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class IFile " - } - ], - "releaseTag": "Public", - "name": "IFile", - "members": [ - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFile#containingFolder:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "containingFolder: " - }, - { - "kind": "Reference", - "text": "IFolder", - "canonicalReference": "api-extractor-scenarios!IFolder:class" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "containingFolder", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!IFolder:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class IFolder " - } - ], - "releaseTag": "Public", - "name": "IFolder", - "members": [ - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFolder#containingFolder:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "containingFolder: " - }, - { - "kind": "Reference", - "text": "IFolder", - "canonicalReference": "api-extractor-scenarios!IFolder:class" - }, - { - "kind": "Content", - "text": " | undefined" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "containingFolder", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!IFolder#files:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "files: " - }, - { - "kind": "Reference", - "text": "IFile", - "canonicalReference": "api-extractor-scenarios!IFile:class" - }, - { - "kind": "Content", - "text": "[]" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "files", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.md deleted file mode 100644 index 03d4ef2fa16..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,32 +0,0 @@ -## 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 A { -} - -// @public (undocumented) -export class B { -} - -// @public (undocumented) -export class IFile { - // (undocumented) - containingFolder: IFolder; -} - -// @public (undocumented) -export class IFolder { - // (undocumented) - containingFolder: IFolder | undefined; - // (undocumented) - files: IFile[]; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/rollup.d.ts deleted file mode 100644 index 50755cfc61a..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/rollup.d.ts +++ /dev/null @@ -1,21 +0,0 @@ - -/** @public */ -export declare class A { -} - -/** @public */ -export declare class B { -} - -/** @public */ -export declare class IFile { - containingFolder: IFolder; -} - -/** @public */ -export declare class IFolder { - containingFolder: IFolder | undefined; - files: IFile[]; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.json deleted file mode 100644 index 7a6e617b407..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!DefaultClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export default class DefaultClass " - } - ], - "releaseTag": "Public", - "name": "DefaultClass", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.md deleted file mode 100644 index 858df9e4285..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/api-extractor-scenarios.api.md +++ /dev/null @@ -1,16 +0,0 @@ -## 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) -class DefaultClass { -} - -export default DefaultClass; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/rollup.d.ts deleted file mode 100644 index 27859c4754c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint/rollup.d.ts +++ /dev/null @@ -1,7 +0,0 @@ - -/** @public */ -declare class DefaultClass { -} -export default DefaultClass; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json deleted file mode 100644 index ee0930c3383..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Variable", - "canonicalReference": "api-extractor-scenarios!defaultFunctionStatement:var", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "defaultFunctionStatement: " - }, - { - "kind": "Content", - "text": "() => void" - } - ], - "releaseTag": "Public", - "name": "defaultFunctionStatement", - "variableTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md deleted file mode 100644 index e796e5e4668..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## 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) -const defaultFunctionStatement: () => void; - -export default defaultFunctionStatement; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/rollup.d.ts deleted file mode 100644 index 517d7f9b02d..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/rollup.d.ts +++ /dev/null @@ -1,6 +0,0 @@ - -/** @public */ -declare const defaultFunctionStatement: () => void; -export default defaultFunctionStatement; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json deleted file mode 100644 index f77ec75f57e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!defaultFunctionDeclaration:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export default function defaultFunctionDeclaration(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "defaultFunctionDeclaration" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md deleted file mode 100644 index 581638fb3ff..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/api-extractor-scenarios.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## 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) -function defaultFunctionDeclaration(): void; - -export default defaultFunctionDeclaration; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/rollup.d.ts deleted file mode 100644 index 8e8478ffded..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint3/rollup.d.ts +++ /dev/null @@ -1,8 +0,0 @@ - -/** - * @public - */ -declare function defaultFunctionDeclaration(): void; -export default defaultFunctionDeclaration; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json deleted file mode 100644 index 4354fcdc45c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Variable", - "canonicalReference": "api-extractor-scenarios!_default:var", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "_default: " - }, - { - "kind": "Content", - "text": "\"literal\"" - } - ], - "releaseTag": "Public", - "name": "_default", - "variableTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md deleted file mode 100644 index 78718dd177e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## 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) -const _default: "literal"; - -export default _default; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/rollup.d.ts deleted file mode 100644 index 15e930b0b63..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/rollup.d.ts +++ /dev/null @@ -1,5 +0,0 @@ - -declare const _default: "literal"; -export default _default; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json deleted file mode 100644 index a6462604260..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!failWithBrokenLink:function(1)", - "docComment": "/**\n * {@inheritDoc MyNamespace.MyClass.nonExistentMethod}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function failWithBrokenLink(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "failWithBrokenLink" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!failWithMissingReference:function(1)", - "docComment": "/**\n * {@inheritDoc}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function failWithMissingReference(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "failWithMissingReference" - }, - { - "kind": "Namespace", - "canonicalReference": "api-extractor-scenarios!MyNamespace:namespace", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare namespace MyNamespace " - } - ], - "releaseTag": "Public", - "name": "MyNamespace", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!MyNamespace.MyClass:class", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "class MyClass " - } - ], - "releaseTag": "Public", - "name": "MyClass", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!MyNamespace.MyClass#myMethod:member(1)", - "docComment": "/**\n * Summary for myMethod\n *\n * @remarks\n *\n * Remarks for myMethod\n *\n * @param x - the parameter\n *\n * @returns a number\n *\n * @beta\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "myMethod(x: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Beta", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "myMethod" - } - ], - "implementsTokenRanges": [] - } - ] - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!succeedForNow:function(1)", - "docComment": "/**\n * {@inheritDoc nonexistent-package#MyNamespace.MyClass.nonExistentMethod}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function succeedForNow(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "succeedForNow" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!testSimple:function(1)", - "docComment": "/**\n * Summary for myMethod\n *\n * @remarks\n *\n * Remarks for myMethod\n *\n * @param x - the parameter\n *\n * @returns a number\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function testSimple(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "testSimple" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.md deleted file mode 100644 index 6fc742a8b0e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.md +++ /dev/null @@ -1,35 +0,0 @@ -## 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-unresolved-inheritdoc-reference) The @inheritDoc reference could not be resolved: No member was found with name "nonExistentMethod" -// -// @public (undocumented) -export function failWithBrokenLink(): void; - -// Warning: (ae-unresolved-inheritdoc-base) The @inheritDoc tag needs a TSDoc declaration reference; signature matching is not supported yet -// -// @public (undocumented) -export function failWithMissingReference(): void; - -// @public (undocumented) -export namespace MyNamespace { - // (undocumented) - export class MyClass { - // @beta - myMethod(x: number): number; - } -} - -// @public (undocumented) -export function succeedForNow(): void; - -// @public -export function testSimple(): void; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/rollup.d.ts deleted file mode 100644 index 94a9b92cd3d..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/rollup.d.ts +++ /dev/null @@ -1,51 +0,0 @@ - -/** - * {@inheritDoc MyNamespace.MyClass.nonExistentMethod} - * @public - */ -export declare function failWithBrokenLink(): void; - -/** - * {@inheritDoc} - * @public - */ -export declare function failWithMissingReference(): void; - -/** - * @public - */ -export declare namespace MyNamespace { - export class MyClass { - /** - * Summary for myMethod - * @remarks - * Remarks for myMethod - * @param x - the parameter - * @returns a number - * @beta - */ - myMethod(x: number): number; - } -} - -/** - * {@inheritDoc nonexistent-package#MyNamespace.MyClass.nonExistentMethod} - * - * @privateRemarks - * succeedForNow() should fail due to a broken link, but it's ignored until we fix this issue: - * https://github.com/microsoft/rushstack/issues/1195 - * - * @public - */ -export declare function succeedForNow(): void; - -/** - * {@inheritDoc MyNamespace.MyClass.myMethod} - * @privateRemarks - * The MyClass.myMethod documentation content will get copied, - * but its `@beta` tag will not get copied. - * @public - */ -export declare function testSimple(): void; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json deleted file mode 100644 index 86d8e196460..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,237 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!CyclicA:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class CyclicA " - } - ], - "releaseTag": "Public", - "name": "CyclicA", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!CyclicA#methodA1:member(1)", - "docComment": "/**\n * THE COMMENT\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "methodA1(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "methodA1" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!CyclicA#methodA3:member(1)", - "docComment": "/**\n * THE COMMENT\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "methodA3(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "methodA3" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!CyclicB:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class CyclicB " - } - ], - "releaseTag": "Public", - "name": "CyclicB", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!CyclicB#methodB2:member(1)", - "docComment": "/**\n * THE COMMENT\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "methodB2(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "methodB2" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!CyclicB#methodB4:member(1)", - "docComment": "/**\n * THE COMMENT\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "methodB4(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "methodB4" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!FailWithSelfReference:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class FailWithSelfReference " - } - ], - "releaseTag": "Public", - "name": "FailWithSelfReference", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!FailWithSelfReference#method1:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "method1(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "method1" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!FailWithSelfReference#method2:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "method2(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "method2" - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.md deleted file mode 100644 index 26ae14da792..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,32 +0,0 @@ -## 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 CyclicA { - methodA1(): void; - methodA3(): void; -} - -// @public (undocumented) -export class CyclicB { - methodB2(): void; - methodB4(): void; -} - -// @public (undocumented) -export class FailWithSelfReference { - // Warning: (ae-cyclic-inherit-doc) The @inheritDoc tag for "method1" refers to its own declaration - // - // (undocumented) - method1(): void; - // (undocumented) - method2(): void; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/rollup.d.ts deleted file mode 100644 index dc073144b53..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/rollup.d.ts +++ /dev/null @@ -1,26 +0,0 @@ - -/** @public */ -export declare class CyclicA { - /** {@inheritDoc CyclicB.methodB2} */ - methodA1(): void; - /** {@inheritDoc CyclicB.methodB4} */ - methodA3(): void; -} - -/** @public */ -export declare class CyclicB { - /** {@inheritDoc CyclicA.methodA3} */ - methodB2(): void; - /** THE COMMENT */ - methodB4(): void; -} - -/** @public */ -export declare class FailWithSelfReference { - /** {@inheritDoc FailWithSelfReference.method2} */ - method1(): void; - /** {@inheritDoc FailWithSelfReference.method1} */ - method2(): void; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json deleted file mode 100644 index b5a0ad94afd..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!A:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "api-extractor-scenarios!A#myProperty:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "myProperty: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "myProperty", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Namespace", - "canonicalReference": "api-extractor-scenarios!A:namespace", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare namespace A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!A.B:class", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "class B " - } - ], - "releaseTag": "Public", - "name": "B", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!A.B#myMethod:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "myMethod(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "myMethod" - } - ], - "implementsTokenRanges": [] - } - ] - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!failWithAmbiguity:function(1)", - "docComment": "/**\n * {@link MyNamespace.MyClass.myMethod | the method}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function failWithAmbiguity(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "failWithAmbiguity" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!succeedWithExternalReference:function(1)", - "docComment": "/**\n * NOTE: The broken link checker currently is not able to validate references to external packages. Tracked by: https://github.com/microsoft/rushstack/issues/1195 {@link nonexistent#nonexistent}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function succeedWithExternalReference(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "succeedWithExternalReference" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!succeedWithSelector:function(1)", - "docComment": "/**\n * {@link (A:namespace).B.myMethod | the method} {@link (A:interface).myProperty | the property}\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function succeedWithSelector(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "succeedWithSelector" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.md deleted file mode 100644 index 65bd4539b87..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.md +++ /dev/null @@ -1,36 +0,0 @@ -## 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 namespace A { - // (undocumented) - export class B { - // (undocumented) - myMethod(): void; - } -} - -// @public (undocumented) -export interface A { - // (undocumented) - myProperty: string; -} - -// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "api-extractor-scenarios" does not have an export "MyNamespace" -// -// @public -export function failWithAmbiguity(): void; - -// @public -export function succeedWithExternalReference(): void; - -// @public -export function succeedWithSelector(): void; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/rollup.d.ts deleted file mode 100644 index 2e05baff7ac..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/rollup.d.ts +++ /dev/null @@ -1,35 +0,0 @@ - -/** @public */ -export declare namespace A { - export class B { - myMethod(): void; - } -} - -/** @public */ -export declare interface A { - myProperty: string; -} - -/** - * {@link MyNamespace.MyClass.myMethod | the method} - * @public - */ -export declare function failWithAmbiguity(): void; - -/** - * NOTE: The broken link checker currently is not able to validate references to external packages. - * Tracked by: https://github.com/microsoft/rushstack/issues/1195 - * {@link nonexistent#nonexistent} - * @public - */ -export declare function succeedWithExternalReference(): void; - -/** - * {@link (A:namespace).B.myMethod | the method} - * {@link (A:interface).myProperty | the property} - * @public - */ -export declare function succeedWithSelector(): void; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.json deleted file mode 100644 index c729a0ebc98..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!X:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class X " - } - ], - "releaseTag": "Public", - "name": "X", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.md deleted file mode 100644 index 99a589939d4..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/api-extractor-scenarios.api.md +++ /dev/null @@ -1,28 +0,0 @@ -## 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 - -// @internal (undocumented) -class A { -} - -// Warning: (ae-internal-missing-underscore) The name "B" should be prefixed with an underscore because the declaration is marked as @internal -export { A as B } - -// Warning: (ae-internal-missing-underscore) The name "C" should be prefixed with an underscore because the declaration is marked as @internal -export { A as C } - -// @public (undocumented) -class X { -} - -export { X } - -export { X as Y } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/rollup.d.ts deleted file mode 100644 index 84d16df510c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportDuplicate/rollup.d.ts +++ /dev/null @@ -1,14 +0,0 @@ - -/** @internal */ -declare class A { -} -export { A as B } -export { A as C } - -/** @public */ -declare class X { -} -export { X } -export { X as Y } - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json deleted file mode 100644 index b8eee943395..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!ITeamsContext:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface ITeamsContext " - } - ], - "releaseTag": "Public", - "name": "ITeamsContext", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "api-extractor-scenarios!ITeamsContext#context:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "context: " - }, - { - "kind": "Reference", - "text": "Context", - "canonicalReference": "!microsoftTeams.Context:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "context", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.md deleted file mode 100644 index 5560228d16a..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.md +++ /dev/null @@ -1,18 +0,0 @@ -## 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 - -import { Context } from '@microsoft/teams-js'; - -// @public (undocumented) -export interface ITeamsContext { - // (undocumented) - context: Context; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.json deleted file mode 100644 index d7e603c111e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.md deleted file mode 100644 index 26040fc4a5d..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/api-extractor-scenarios.api.md +++ /dev/null @@ -1,22 +0,0 @@ -## 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 - -import { Lib1Class } from 'api-extractor-lib1-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; -import { Lib2Class } from 'api-extractor-lib2-test'; - -export { Lib1Class } - -export { Lib1Interface } - -export { Lib2Class as DoubleRenamedLib2Class } - -export { Lib2Class as RenamedLib2Class } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/rollup.d.ts deleted file mode 100644 index 5af60a71e60..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal/rollup.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Lib1Class } from 'api-extractor-lib1-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; -import { Lib2Class } from 'api-extractor-lib2-test'; -export { Lib1Class } -export { Lib1Interface } -export { Lib2Class as DoubleRenamedLib2Class } -export { Lib2Class as RenamedLib2Class } - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.json deleted file mode 100644 index d7e603c111e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.md deleted file mode 100644 index 9fa98baad17..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,14 +0,0 @@ -## 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 - -import { Lib1Class } from 'api-extractor-lib3-test'; - -export { Lib1Class } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/rollup.d.ts deleted file mode 100644 index 58204823153..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportedExternal2/rollup.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Lib1Class } from 'api-extractor-lib3-test'; -export { Lib1Class } - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.json deleted file mode 100644 index 3b7acb4d56b..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!A:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!B:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class B " - } - ], - "releaseTag": "Public", - "name": "B", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!C:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class C " - } - ], - "releaseTag": "Public", - "name": "C", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.md deleted file mode 100644 index 63f0d7a8c31..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/api-extractor-scenarios.api.md +++ /dev/null @@ -1,22 +0,0 @@ -## 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 A { -} - -// @public (undocumented) -export class B { -} - -// @public (undocumented) -export class C { -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/rollup.d.ts deleted file mode 100644 index 47bf36a4473..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar/rollup.d.ts +++ /dev/null @@ -1,14 +0,0 @@ - -/** @public */ -export declare class A { -} - -/** @public */ -export declare class B { -} - -/** @public */ -export declare class C { -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/api-extractor-scenarios.api.json deleted file mode 100644 index 97166819e35..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!A:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/rollup.d.ts deleted file mode 100644 index 8e6bcc58b9b..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar2/rollup.d.ts +++ /dev/null @@ -1,9 +0,0 @@ - -/** @public */ -export declare class A { -} - -export * from "api-extractor-lib1-test"; -export * from "api-extractor-lib2-test"; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.json deleted file mode 100644 index 97166819e35..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!A:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class A " - } - ], - "releaseTag": "Public", - "name": "A", - "members": [], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.md deleted file mode 100644 index e3d8af12f10..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/api-extractor-scenarios.api.md +++ /dev/null @@ -1,21 +0,0 @@ -## 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 - -import { Lib1Class } from 'api-extractor-lib1-test'; -import { Lib2Interface as RenamedLib2Interface } from 'api-extractor-lib2-test'; - -// @public (undocumented) -export class A { -} - -export { Lib1Class } - -export { RenamedLib2Interface } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/rollup.d.ts deleted file mode 100644 index f4a993e0329..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportStar3/rollup.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Lib1Class } from 'api-extractor-lib1-test'; -import { Lib2Interface as RenamedLib2Interface } from 'api-extractor-lib2-test'; - -/** @public */ -export declare class A { -} -export { Lib1Class } -export { RenamedLib2Interface } - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json deleted file mode 100644 index 9f5fe2612fa..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json +++ /dev/null @@ -1,329 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!_combine:function(1)", - "docComment": "/**\n * @beta\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function _combine(x: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", y: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "releaseTag": "Beta", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "y", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "_combine" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!combine:function(2)", - "docComment": "/**\n * @beta\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function combine(x: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", y: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "releaseTag": "Beta", - "overloadIndex": 2, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "y", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "combine" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!combine:function(3)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function combine(x: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": ", y: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - }, - "releaseTag": "Public", - "overloadIndex": 3, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "y", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "combine" - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!Combiner:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class Combiner " - } - ], - "releaseTag": "Public", - "name": "Combiner", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!Combiner#combine:member(2)", - "docComment": "/**\n * @beta\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "combine(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", - "overloadIndex": 2, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "y", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "combine" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!Combiner#combine:member(3)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "combine(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", - "overloadIndex": 3, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "y", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "combine" - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.md deleted file mode 100644 index 6f86d4d4af8..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.md +++ /dev/null @@ -1,37 +0,0 @@ -## 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 - -// @alpha (undocumented) -export function combine(x: boolean, y: boolean): boolean; - -// @beta (undocumented) -export function combine(x: string, y: string): string; - -// @public (undocumented) -export function combine(x: number, y: number): number; - -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "_combine" because one of its declarations is marked as @internal -// -// @beta (undocumented) -export function _combine(x: string, y: string): string; - -// @internal (undocumented) -export function _combine(x: number, y: number): number; - -// @public (undocumented) -export class Combiner { - // @alpha (undocumented) - combine(x: boolean, y: boolean): boolean; - // @beta (undocumented) - combine(x: string, y: string): string; - // (undocumented) - combine(x: number, y: number): number; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/rollup.d.ts deleted file mode 100644 index 53e55722466..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/rollup.d.ts +++ /dev/null @@ -1,45 +0,0 @@ - -/** - * @alpha - */ -export declare function combine(x: boolean, y: boolean): boolean; - -/** - * @beta - */ -export declare function combine(x: string, y: string): string; - -/** - * @public - */ -export declare function combine(x: number, y: number): number; - -/** - * @beta - */ -export declare function _combine(x: string, y: string): string; - -/** - * @internal - */ -export declare function _combine(x: number, y: number): number; - -/** - * @public - */ -export declare class Combiner { - /** - * @alpha - */ - combine(x: boolean, y: boolean): boolean; - /** - * @beta - */ - combine(x: string, y: string): string; - /** - * @public - */ - combine(x: number, y: number): number; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.json deleted file mode 100644 index 98d8fecbf06..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!useColors:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function useColors(): " - }, - { - "kind": "Content", - "text": "typeof colors." - }, - { - "kind": "Reference", - "text": "zebra", - "canonicalReference": "colors!zebra:var" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "useColors" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.md deleted file mode 100644 index 8c75c43b878..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/api-extractor-scenarios.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## 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 - -import colors = require('colors'); - -// @public (undocumented) -export function useColors(): typeof colors.zebra; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/rollup.d.ts deleted file mode 100644 index 144348ae07f..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/importEquals/rollup.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import colors = require('colors'); - -/** @public */ -export declare function useColors(): typeof colors.zebra; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json deleted file mode 100644 index 25962c1f0f7..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!IBeta:interface", - "docComment": "/**\n * @beta\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface IBeta " - } - ], - "releaseTag": "Beta", - "name": "IBeta", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "api-extractor-scenarios!IBeta#x:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "x: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Beta", - "name": "x", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!publicFunctionReturnsBeta:function(1)", - "docComment": "/**\n * It's not okay for a \"public\" function to reference a \"beta\" symbol, because \"beta\" is less public than \"public\".\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function publicFunctionReturnsBeta(): " - }, - { - "kind": "Reference", - "text": "IBeta", - "canonicalReference": "api-extractor-scenarios!IBeta:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "publicFunctionReturnsBeta" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.md deleted file mode 100644 index f93e9672264..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.md +++ /dev/null @@ -1,24 +0,0 @@ -## 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 - -// @alpha -export function alphaFunctionReturnsBeta(): IBeta; - -// @beta (undocumented) -export interface IBeta { - // (undocumented) - x: number; -} - -// Warning: (ae-incompatible-release-tags) The symbol "publicFunctionReturnsBeta" is marked as @public, but its signature references "IBeta" which is marked as @beta -// -// @public -export function publicFunctionReturnsBeta(): IBeta; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/rollup.d.ts deleted file mode 100644 index 11f24f2c58f..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/rollup.d.ts +++ /dev/null @@ -1,21 +0,0 @@ - -/** - * It's okay for an "alpha" function to reference a "beta" symbol, - * because "beta" is more public than "alpha". - * @alpha - */ -export declare function alphaFunctionReturnsBeta(): IBeta; - -/** @beta */ -export declare interface IBeta { - x: number; -} - -/** - * It's not okay for a "public" function to reference a "beta" symbol, - * because "beta" is less public than "public". - * @public - */ -export declare function publicFunctionReturnsBeta(): IBeta; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json deleted file mode 100644 index b0188d160c1..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!ClassΞ:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class ClassΞ " - } - ], - "releaseTag": "Public", - "name": "ClassΞ", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassΞ#\"invalid chars\":member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "'invalid chars'(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "\"invalid chars\"" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassΞ#memberΔ:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "memberΔ(paramΩ: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "ClassΞ", - "canonicalReference": "api-extractor-scenarios!ClassΞ:class" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "paramΩ", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "memberΔ" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassΞ#validChars:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "'validChars'(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "validChars" - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.md deleted file mode 100644 index f67c12b8fc2..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.md +++ /dev/null @@ -1,24 +0,0 @@ -## 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) -class ClassΞ { - // (undocumented) - 'invalid chars'(): void; - // (undocumented) - memberΔ(paramΩ: string): ClassΞ; - // (undocumented) - 'validChars'(): void; -} - -export { ClassΞ } - -export { ClassΞ as ClassΣ } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/rollup.d.ts deleted file mode 100644 index 0a2dfb419af..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/rollup.d.ts +++ /dev/null @@ -1,11 +0,0 @@ - -/** @public */ -declare class ClassΞ { - memberΔ(paramΩ: string): ClassΞ; - 'invalid chars'(): void; - 'validChars'(): void; -} -export { ClassΞ } -export { ClassΞ as ClassΣ } - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.json deleted file mode 100644 index d7e603c111e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.md deleted file mode 100644 index 653ce728039..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/api-extractor-scenarios.api.md +++ /dev/null @@ -1,22 +0,0 @@ -## 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 - -// @internal (undocumented) -class _PreapprovedClass { /* (preapproved) */ } - -// @internal (undocumented) -enum _PreapprovedEnum { /* (preapproved) */ } - -// @internal (undocumented) -interface _PreapprovedInterface { /* (preapproved) */ } - -// @internal (undocumented) -namespace _PreapprovedNamespace { /* (preapproved) */ } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/rollup.d.ts deleted file mode 100644 index 57b5b36ab61..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/preapproved/rollup.d.ts +++ /dev/null @@ -1,25 +0,0 @@ - -/** @internal @preapproved */ -export declare class _PreapprovedClass { - member(): void; -} - -/** @internal @preapproved */ -export declare enum _PreapprovedEnum { - ONE = 1, - TWO = 2 -} - -/** @internal @preapproved */ -export declare interface _PreapprovedInterface { - member(): void; -} - -/** @internal @preapproved */ -export declare namespace _PreapprovedNamespace { - export class X { - } - export function f(): void; -} - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.json deleted file mode 100644 index c15727f370c..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!f:function(1)", - "docComment": "/**\n * Reference Lib1Class via \"typeof\"\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function f(): " - }, - { - "kind": "Content", - "text": "typeof " - }, - { - "kind": "Reference", - "text": "Lib1Class", - "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" - }, - { - "kind": "Content", - "text": " | undefined" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "f" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!g:function(1)", - "docComment": "/**\n * Reference IForgottenExport via \"typeof\"\n *\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function g(): " - }, - { - "kind": "Content", - "text": "typeof " - }, - { - "kind": "Reference", - "text": "ForgottenExport", - "canonicalReference": "api-extractor-scenarios!~ForgottenExport:class" - }, - { - "kind": "Content", - "text": " | undefined" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "g" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.md deleted file mode 100644 index 1946b0ba2bf..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/api-extractor-scenarios.api.md +++ /dev/null @@ -1,20 +0,0 @@ -## 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 - -import { Lib1Class } from 'api-extractor-lib1-test'; - -// @public -export function f(): typeof Lib1Class | undefined; - -// Warning: (ae-forgotten-export) The symbol "ForgottenExport" needs to be exported by the entry point index.d.ts -// -// @public -export function g(): typeof ForgottenExport | undefined; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.json deleted file mode 100644 index 2f55e1cf757..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!f:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function f(): " - }, - { - "kind": "Content", - "text": "{\n a: number;\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "f" - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!g:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function g(callback: " - }, - { - "kind": "Content", - "text": "typeof " - }, - { - "kind": "Reference", - "text": "f", - "canonicalReference": "api-extractor-scenarios!f:function" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "typeof " - }, - { - "kind": "Reference", - "text": "f", - "canonicalReference": "api-extractor-scenarios!f:function" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 4, - "endIndex": 6 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "callback", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - } - ], - "name": "g" - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.md deleted file mode 100644 index 26384c3e2a4..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/api-extractor-scenarios.api.md +++ /dev/null @@ -1,18 +0,0 @@ -## 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 f(): { - a: number; -}; - -// @public (undocumented) -export function g(callback: typeof f): typeof f; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/rollup.d.ts deleted file mode 100644 index 32b7b7dbf14..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf2/rollup.d.ts +++ /dev/null @@ -1,10 +0,0 @@ - -/** @public */ -export declare function f(): { - a: number; -}; - -/** @public */ -export declare function g(callback: typeof f): typeof f; - -export { } diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json deleted file mode 100644 index fa30f8925dd..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!ClassWithGenericMethod:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class ClassWithGenericMethod " - } - ], - "releaseTag": "Public", - "name": "ClassWithGenericMethod", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!ClassWithGenericMethod#method:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "method(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "name": "method" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!GenericClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class GenericClass " - } - ], - "releaseTag": "Public", - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "name": "GenericClass", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!GenericClassWithConstraint:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class GenericClassWithConstraint " - } - ], - "releaseTag": "Public", - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "name": "GenericClassWithConstraint", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!GenericClassWithDefault:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class GenericClassWithDefault " - } - ], - "releaseTag": "Public", - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "GenericClassWithDefault", - "members": [], - "implementsTokenRanges": [] - }, - { - "kind": "Function", - "canonicalReference": "api-extractor-scenarios!genericFunction:function(1)", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare function genericFunction(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "name": "genericFunction" - }, - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!GenericInterface:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface GenericInterface " - } - ], - "releaseTag": "Public", - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "name": "GenericInterface", - "members": [], - "extendsTokenRanges": [] - }, - { - "kind": "TypeAlias", - "canonicalReference": "api-extractor-scenarios!GenericTypeAlias:type", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type GenericTypeAlias = " - }, - { - "kind": "Content", - "text": "T" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "GenericTypeAlias", - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ], - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericCallSignature:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface InterfaceWithGenericCallSignature " - } - ], - "releaseTag": "Public", - "name": "InterfaceWithGenericCallSignature", - "members": [ - { - "kind": "CallSignature", - "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericCallSignature:call(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ] - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericConstructSignature:interface", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface InterfaceWithGenericConstructSignature " - } - ], - "releaseTag": "Public", - "name": "InterfaceWithGenericConstructSignature", - "members": [ - { - "kind": "ConstructSignature", - "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericConstructSignature:new(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "new (): " - }, - { - "kind": "Content", - "text": "T" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "typeParameters": [ - { - "typeParameterName": "T", - "constraintTokenRange": { - "startIndex": 0, - "endIndex": 0 - }, - "defaultTypeTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ] - } - ], - "extendsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.md deleted file mode 100644 index 4661cbbcd0e..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.md +++ /dev/null @@ -1,50 +0,0 @@ -## 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 ClassWithGenericMethod { - // (undocumented) - method(): void; -} - -// @public (undocumented) -export class GenericClass { -} - -// @public (undocumented) -export class GenericClassWithConstraint { -} - -// @public (undocumented) -export class GenericClassWithDefault { -} - -// @public (undocumented) -export function genericFunction(): void; - -// @public (undocumented) -export interface GenericInterface { -} - -// @public (undocumented) -export type GenericTypeAlias = T; - -// @public (undocumented) -export interface InterfaceWithGenericCallSignature { - // (undocumented) - (): void; -} - -// @public (undocumented) -export interface InterfaceWithGenericConstructSignature { - // (undocumented) - new (): T; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/rollup.d.ts deleted file mode 100644 index 763f702b683..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/rollup.d.ts +++ /dev/null @@ -1,39 +0,0 @@ - -/** @public */ -export declare class ClassWithGenericMethod { - method(): void; -} - -/** @public */ -export declare class GenericClass { -} - -/** @public */ -export declare class GenericClassWithConstraint { -} - -/** @public */ -export declare class GenericClassWithDefault { -} - -/** @public */ -export declare function genericFunction(): void; - -/** @public */ -export declare interface GenericInterface { -} - -/** @public */ -export declare type GenericTypeAlias = T; - -/** @public */ -export declare interface InterfaceWithGenericCallSignature { - (): void; -} - -/** @public */ -export declare interface InterfaceWithGenericConstructSignature { - new (): T; -} - -export { } 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 new file mode 100644 index 00000000000..4af8707d08d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.json @@ -0,0 +1,301 @@ +{ + "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!ClassWithTypeLiterals:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ClassWithTypeLiterals " + } + ], + "fileUrlPath": "src/typeLiterals/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ClassWithTypeLiterals", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals#method1:member(1)", + "docComment": "/**\n * type literal in\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "method1(vector: " + }, + { + "kind": "Content", + "text": "{\n x: number;\n y: number;\n }" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "vector", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "method1" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals#method2:member(1)", + "docComment": "/**\n * type literal output\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "method2(): " + }, + { + "kind": "Content", + "text": "{\n classValue: " + }, + { + "kind": "Reference", + "text": "ClassWithTypeLiterals", + "canonicalReference": "api-extractor-scenarios!ClassWithTypeLiterals:class" + }, + { + "kind": "Content", + "text": ";\n callback: () => number;\n } | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "method2" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..ca50c2b171c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.md @@ -0,0 +1,21 @@ +## 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 ClassWithTypeLiterals { + method1(vector: { + x: number; + y: number; + }): void; + method2(): { + classValue: ClassWithTypeLiterals; + callback: () => number; + } | undefined; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/typeLiterals/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/typeLiterals/rollup.d.ts new file mode 100644 index 00000000000..0c3cecaa513 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeLiterals/rollup.d.ts @@ -0,0 +1,15 @@ +/** @public */ +export declare class ClassWithTypeLiterals { + /** type literal in */ + method1(vector: { + x: number; + y: number; + }): void; + /** type literal output */ + method2(): { + classValue: ClassWithTypeLiterals; + callback: () => number; + } | undefined; +} + +export { } 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 new file mode 100644 index 00000000000..febcf6ccf7c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.json @@ -0,0 +1,268 @@ +{ + "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!f:function(1)", + "docComment": "/**\n * Reference Lib1Class via \"typeof\"\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f(): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "Lib1Class", + "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "f" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!g:function(1)", + "docComment": "/**\n * Reference IForgottenExport via \"typeof\"\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function g(): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "ForgottenExport", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport:class" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "g" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..534d503d3f8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf/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 + +import { Lib1Class } from 'api-extractor-lib1-test'; + +// @public +export function f(): typeof Lib1Class | undefined; + +// Warning: (ae-forgotten-export) The symbol "ForgottenExport" needs to be exported by the entry point index.d.ts +// +// @public +export function g(): typeof ForgottenExport | undefined; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/typeOf/rollup.d.ts similarity index 100% rename from build-tests/api-extractor-scenarios/etc/test-outputs/typeOf/rollup.d.ts rename to build-tests/api-extractor-scenarios/etc/typeOf/rollup.d.ts 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 new file mode 100644 index 00000000000..ba35fe47ce2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.json @@ -0,0 +1,277 @@ +{ + "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!f:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f(): " + }, + { + "kind": "Content", + "text": "{\n a: number;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf2/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "f" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!g:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function g(callback: " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "f", + "canonicalReference": "api-extractor-scenarios!f:function" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "f", + "canonicalReference": "api-extractor-scenarios!f:function" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf2/index.ts", + "returnTypeTokenRange": { + "startIndex": 4, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "callback", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isOptional": false + } + ], + "name": "g" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..497ee645dc8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.md @@ -0,0 +1,17 @@ +## 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 f(): { + a: number; +}; + +// @public (undocumented) +export function g(callback: typeof f): typeof f; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/typeOf2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/typeOf2/rollup.d.ts new file mode 100644 index 00000000000..40bc1c49336 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf2/rollup.d.ts @@ -0,0 +1,9 @@ +/** @public */ +export declare function f(): { + a: number; +}; + +/** @public */ +export declare function g(callback: typeof f): typeof f; + +export { } 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 new file mode 100644 index 00000000000..d592718a445 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.json @@ -0,0 +1,331 @@ +{ + "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!f1:function(1)", + "docComment": "/**\n * A function that references its own parameter type.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f1(x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "x", + "canonicalReference": "api-extractor-scenarios!~x:var" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf3/index.ts", + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 5 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "f1" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!f2:function(1)", + "docComment": "/**\n * A function that indirectly references its own parameter type.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f2(x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "keyof typeof " + }, + { + "kind": "Reference", + "text": "x", + "canonicalReference": "api-extractor-scenarios!~x:var" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf3/index.ts", + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 5 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "f2" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!f3:function(1)", + "docComment": "/**\n * A function that references its own type.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function f3(): " + }, + { + "kind": "Content", + "text": "typeof " + }, + { + "kind": "Reference", + "text": "f3", + "canonicalReference": "api-extractor-scenarios!f3:function" + }, + { + "kind": "Content", + "text": " | undefined" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeOf3/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "f3" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..622c88fa443 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.md @@ -0,0 +1,18 @@ +## 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 +export function f1(x: number): typeof x; + +// @public +export function f2(x: number): keyof typeof x; + +// @public +export function f3(): typeof f3 | undefined; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/typeOf3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/typeOf3/rollup.d.ts new file mode 100644 index 00000000000..6b25c9962b0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeOf3/rollup.d.ts @@ -0,0 +1,19 @@ +/** + * A function that references its own parameter type. + * @public + */ +export declare function f1(x: number): typeof x; + +/** + * A function that indirectly references its own parameter type. + * @public + */ +export declare function f2(x: number): keyof typeof x; + +/** + * A function that references its own type. + * @public + */ +export declare function f3(): typeof f3 | undefined; + +export { } 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 new file mode 100644 index 00000000000..ed2b317d221 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.json @@ -0,0 +1,590 @@ +{ + "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!ClassWithGenericMethod:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ClassWithGenericMethod " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "ClassWithGenericMethod", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!ClassWithGenericMethod#method:member(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "method(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [], + "isOptional": false, + "isAbstract": false, + "name": "method" + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!GenericClass:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class GenericClass " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "isAbstract": false, + "name": "GenericClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!GenericClassWithConstraint:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class GenericClassWithConstraint " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "isAbstract": false, + "name": "GenericClassWithConstraint", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!GenericClassWithDefault:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class GenericClassWithDefault " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "isAbstract": false, + "name": "GenericClassWithDefault", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!genericFunction:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function genericFunction(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "name": "genericFunction" + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!GenericInterface:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface GenericInterface " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "name": "GenericInterface", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + }, + { + "kind": "TypeAlias", + "canonicalReference": "api-extractor-scenarios!GenericTypeAlias:type", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export type GenericTypeAlias = " + }, + { + "kind": "Content", + "text": "T" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "name": "GenericTypeAlias", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericCallSignature:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface InterfaceWithGenericCallSignature " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "name": "InterfaceWithGenericCallSignature", + "preserveMemberOrder": false, + "members": [ + { + "kind": "CallSignature", + "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericCallSignature:call(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "(): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericConstructSignature:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface InterfaceWithGenericConstructSignature " + } + ], + "fileUrlPath": "src/typeParameters/index.ts", + "releaseTag": "Public", + "name": "InterfaceWithGenericConstructSignature", + "preserveMemberOrder": false, + "members": [ + { + "kind": "ConstructSignature", + "canonicalReference": "api-extractor-scenarios!InterfaceWithGenericConstructSignature:new(1)", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "new (): " + }, + { + "kind": "Content", + "text": "T" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..d5653c466c3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.md @@ -0,0 +1,49 @@ +## 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 ClassWithGenericMethod { + // (undocumented) + method(): void; +} + +// @public (undocumented) +export class GenericClass { +} + +// @public (undocumented) +export class GenericClassWithConstraint { +} + +// @public (undocumented) +export class GenericClassWithDefault { +} + +// @public (undocumented) +export function genericFunction(): void; + +// @public (undocumented) +export interface GenericInterface { +} + +// @public (undocumented) +export type GenericTypeAlias = T; + +// @public (undocumented) +export interface InterfaceWithGenericCallSignature { + // (undocumented) + (): void; +} + +// @public (undocumented) +export interface InterfaceWithGenericConstructSignature { + // (undocumented) + new (): T; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/typeParameters/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/typeParameters/rollup.d.ts new file mode 100644 index 00000000000..619bb37428a --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/typeParameters/rollup.d.ts @@ -0,0 +1,38 @@ +/** @public */ +export declare class ClassWithGenericMethod { + method(): void; +} + +/** @public */ +export declare class GenericClass { +} + +/** @public */ +export declare class GenericClassWithConstraint { +} + +/** @public */ +export declare class GenericClassWithDefault { +} + +/** @public */ +export declare function genericFunction(): void; + +/** @public */ +export declare interface GenericInterface { +} + +/** @public */ +export declare type GenericTypeAlias = T; + +/** @public */ +export declare interface InterfaceWithGenericCallSignature { + (): void; +} + +/** @public */ +export declare interface InterfaceWithGenericConstructSignature { + new (): T; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/package.json b/build-tests/api-extractor-scenarios/package.json index 2c967a8a18b..226b4e52408 100644 --- a/build-tests/api-extractor-scenarios/package.json +++ b/build-tests/api-extractor-scenarios/package.json @@ -4,21 +4,28 @@ "version": "1.0.0", "private": true, "main": "lib/index.js", - "typings": "dist/internal/api-extractor-test-01.d.ts", + "typings": "dist/internal/some-fake-file.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft build --clean" + }, + "dependencies": { + "api-extractor-lib1-test": "workspace:*" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@rushstack/node-core-library": "3.19.5", + "@microsoft/api-extractor": "workspace:*", "@microsoft/teams-js": "1.3.0-beta.4", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "api-extractor-lib1-test": "1.0.0", - "api-extractor-lib2-test": "1.0.0", - "api-extractor-lib3-test": "1.0.0", - "colors": "~1.2.1", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "api-extractor-lib2-test": "workspace:*", + "api-extractor-lib3-test": "workspace:*", + "api-extractor-lib4-test": "workspace:*", + "api-extractor-lib5-test": "workspace:*", + "local-node-rig": "workspace:*", + "run-scenarios-helpers": "workspace:*" + }, + "peerDependencies": { + "api-extractor-lib5-test": "workspace:*" } } diff --git a/build-tests/api-extractor-scenarios/src/ambientNameConflict/localFile.ts b/build-tests/api-extractor-scenarios/src/ambientNameConflict/localFile.ts index 593832bd5b3..a5745a7f86c 100644 --- a/build-tests/api-extractor-scenarios/src/ambientNameConflict/localFile.ts +++ b/build-tests/api-extractor-scenarios/src/ambientNameConflict/localFile.ts @@ -5,6 +5,5 @@ * @public */ export class Promise { - public notTheRealPromise(arg: T): void { - } + public notTheRealPromise(arg: T): void {} } diff --git a/build-tests/api-extractor-scenarios/src/ambientNameConflict2/Date.ts b/build-tests/api-extractor-scenarios/src/ambientNameConflict2/Date.ts index 0bf5c8ed4ac..30d166a4102 100644 --- a/build-tests/api-extractor-scenarios/src/ambientNameConflict2/Date.ts +++ b/build-tests/api-extractor-scenarios/src/ambientNameConflict2/Date.ts @@ -5,4 +5,4 @@ * A local class declaration whose name is the same as the system `Date` global symbol. * @public */ -export class Date { } +export class Date {} diff --git a/build-tests/api-extractor-scenarios/src/ancillaryDeclarations/index.ts b/build-tests/api-extractor-scenarios/src/ancillaryDeclarations/index.ts index 92773479649..337fc9b47d1 100644 --- a/build-tests/api-extractor-scenarios/src/ancillaryDeclarations/index.ts +++ b/build-tests/api-extractor-scenarios/src/ancillaryDeclarations/index.ts @@ -13,6 +13,5 @@ export class MyClass { return { title: 'thing' }; } // The setter should also be considered @internal because the getter was marked as internal. - public set _thing(value: _IInternalThing) { - } + public set _thing(value: _IInternalThing) {} } diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/classes.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/classes.ts index 9168cd6bd5b..604d0733021 100644 --- a/build-tests/api-extractor-scenarios/src/apiItemKinds/classes.ts +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/classes.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. - /** @public */ export abstract class AbstractClass { public abstract member(): void; @@ -9,8 +8,9 @@ export abstract class AbstractClass { /** @public */ export class SimpleClass { - public member(): void { - } + public member(): void {} + + public optionalParamMethod(x?: number): void {} public get readonlyProperty(): string { return 'hello'; @@ -19,6 +19,14 @@ export class SimpleClass { public get writeableProperty(): string { return 'hello'; } - public set writeableProperty(value: string) { - } + public set writeableProperty(value: string) {} + + public readonly someReadonlyProp = 5; + public readonly someReadonlyPropWithType: number = 5; } + +/** @public */ +export class ClassWithTypeParameter {} + +/** @public */ +export class ExtendsClassWithTypeParameter extends ClassWithTypeParameter {} diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/enums.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/enums.ts index be7f4409a97..d54b26b6412 100644 --- a/build-tests/api-extractor-scenarios/src/apiItemKinds/enums.ts +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/enums.ts @@ -24,4 +24,4 @@ export const enum ConstEnum { Zero, One = 1, Two = RegularEnum.One + 1 -} \ No newline at end of file +} diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/functions.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/functions.ts new file mode 100644 index 00000000000..729f8daa908 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/functions.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. + +/** @public */ +export function someFunction(): void {} diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/index.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/index.ts index cc5a0f21ba2..a380574a7e0 100644 --- a/build-tests/api-extractor-scenarios/src/apiItemKinds/index.ts +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/index.ts @@ -3,6 +3,8 @@ export * from './classes'; export * from './enums'; +export * from './functions'; export * from './interfaces'; -export * from './typeLiterals'; +export * from './namespaces'; +export * from './typeAliases'; export * from './variables'; diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/namespaces.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/namespaces.ts new file mode 100644 index 00000000000..33513d36b1f --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/namespaces.ts @@ -0,0 +1,14 @@ +/** @public */ +export namespace n1 { + class SomeClass1 {} + export class SomeClass2 extends SomeClass1 {} + + export namespace n2 { + export class SomeClass3 {} + } +} + +/** @public */ +export namespace n1 { + export class SomeClass4 {} +} diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/typeAliases.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/typeAliases.ts new file mode 100644 index 00000000000..4bbe90eb1de --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/typeAliases.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. + +/** @public */ +export type SomeType = number; diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/typeLiterals.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/typeLiterals.ts deleted file mode 100644 index 4ae6655cd23..00000000000 --- a/build-tests/api-extractor-scenarios/src/apiItemKinds/typeLiterals.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** @public */ -export class ClassWithTypeLiterals { - /** type literal in */ - public method1(vector: { x :number, y :number}): void { - } - - /** type literal output */ - public method2(): { classValue: ClassWithTypeLiterals, callback: () => number } | undefined { - return undefined; - } -} diff --git a/build-tests/api-extractor-scenarios/src/apiItemKinds/variables.ts b/build-tests/api-extractor-scenarios/src/apiItemKinds/variables.ts index d0d4bf439fa..af31c7aa2cc 100644 --- a/build-tests/api-extractor-scenarios/src/apiItemKinds/variables.ts +++ b/build-tests/api-extractor-scenarios/src/apiItemKinds/variables.ts @@ -2,11 +2,10 @@ // See LICENSE in the project root for license information. /** @public */ -export const VARIABLE: string = 'hello'; +export const CONST_VARIABLE: string = 'hello'; /** @public */ -export namespace NamespaceContainingVariable { - export let variable: object[] = [] +export let nonConstVariable: string = 'hello'; - export let constVariable: object[] = [] -} +/** @public */ +export const VARIABLE_WITHOUT_EXPLICIT_TYPE = 'hello'; diff --git a/build-tests/api-extractor-scenarios/src/bundledPackages/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/bundledPackages/config/api-extractor-overrides.json index ee390b1793d..8f1c25c7572 100644 --- a/build-tests/api-extractor-scenarios/src/bundledPackages/config/api-extractor-overrides.json +++ b/build-tests/api-extractor-scenarios/src/bundledPackages/config/api-extractor-overrides.json @@ -1,5 +1,18 @@ { "bundledPackages": [ - "api-extractor-lib1-test" + // Explicit package name + "api-extractor-lib1-test", + + // Simple glob pattern (resolves to a single package) + "api-extractor-lib2*", + + // Complex glob pattern (resolves to 3 packages: lib2, which is captured above; lib4; and lib5) + "*-lib{2,4,5}**", + + // Explicit package name with no dependency match + "@foo/bar", + + // Glob pattern with no dependency matches + "@baz/*" ] -} \ No newline at end of file +} diff --git a/build-tests/api-extractor-scenarios/src/bundledPackages/index.ts b/build-tests/api-extractor-scenarios/src/bundledPackages/index.ts index f9aad34fe5b..5e13eba2702 100644 --- a/build-tests/api-extractor-scenarios/src/bundledPackages/index.ts +++ b/build-tests/api-extractor-scenarios/src/bundledPackages/index.ts @@ -1,9 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Lib1Class } from "api-extractor-lib1-test/lib/index"; -import { Lib2Class } from "api-extractor-lib2-test/lib/index"; +import { Lib1Class } from 'api-extractor-lib1-test/lib/index'; +import { Lib2Class } from 'api-extractor-lib2-test/lib/index'; +import { Lib3Class } from 'api-extractor-lib3-test/lib/index'; +import { Lib4Enum } from 'api-extractor-lib4-test/lib/index'; +import { lib5Function } from 'api-extractor-lib5-test/lib/index'; /** @public */ -export function f(arg1: Lib1Class, arg2: Lib2Class): void { -} +export function f(arg1: Lib1Class, arg2: Lib2Class, arg3: Lib3Class, arg4: Lib4Enum): void {} + +export { Lib1Class, Lib2Class, Lib3Class, Lib4Enum, lib5Function }; 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/circularImport/IFile.ts b/build-tests/api-extractor-scenarios/src/circularImport/IFile.ts index 95b34b4a458..8137ec7a376 100644 --- a/build-tests/api-extractor-scenarios/src/circularImport/IFile.ts +++ b/build-tests/api-extractor-scenarios/src/circularImport/IFile.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 { IFolder } from "./IFolder"; +import { IFolder } from './IFolder'; /** @public */ export class IFile { diff --git a/build-tests/api-extractor-scenarios/src/circularImport/IFolder.ts b/build-tests/api-extractor-scenarios/src/circularImport/IFolder.ts index 317bfa89814..d8ac129b32c 100644 --- a/build-tests/api-extractor-scenarios/src/circularImport/IFolder.ts +++ b/build-tests/api-extractor-scenarios/src/circularImport/IFolder.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 { IFile } from "./IFile"; +import { IFile } from './IFile'; /** @public */ export class IFolder { diff --git a/build-tests/api-extractor-scenarios/src/circularImport2/IFile.ts b/build-tests/api-extractor-scenarios/src/circularImport2/IFile.ts index 09334c31efc..3ef9e76c9be 100644 --- a/build-tests/api-extractor-scenarios/src/circularImport2/IFile.ts +++ b/build-tests/api-extractor-scenarios/src/circularImport2/IFile.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. -export * from "./IFolder"; -import { IFolder } from "./IFolder"; +export * from './IFolder'; +import { IFolder } from './IFolder'; /** @public */ export class IFile { @@ -10,4 +10,4 @@ export class IFile { } /** @public */ -export class A { } +export class A {} diff --git a/build-tests/api-extractor-scenarios/src/circularImport2/IFolder.ts b/build-tests/api-extractor-scenarios/src/circularImport2/IFolder.ts index 0cfcc5983cc..cc1723a85c2 100644 --- a/build-tests/api-extractor-scenarios/src/circularImport2/IFolder.ts +++ b/build-tests/api-extractor-scenarios/src/circularImport2/IFolder.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. -export * from "./IFile"; -import { IFile } from "./IFile"; +export * from './IFile'; +import { IFile } from './IFile'; /** @public */ export class IFolder { @@ -11,4 +11,4 @@ export class IFolder { } /** @public */ -export class B { } +export class B {} diff --git a/build-tests/api-extractor-scenarios/src/circularImport2/index.ts b/build-tests/api-extractor-scenarios/src/circularImport2/index.ts index 0573a7b0838..eac1858f930 100644 --- a/build-tests/api-extractor-scenarios/src/circularImport2/index.ts +++ b/build-tests/api-extractor-scenarios/src/circularImport2/index.ts @@ -3,4 +3,3 @@ export * from './IFile'; export * from './IFolder'; - diff --git a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint/index.ts b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint/index.ts index 45329c9b987..012b65909e7 100644 --- a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint/index.ts +++ b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint/index.ts @@ -2,4 +2,4 @@ // See LICENSE in the project root for license information. /** @public */ -export default class DefaultClass { }; +export default class DefaultClass {} diff --git a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint2/index.ts b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint2/index.ts index 305a777b919..034bb1bfb7e 100644 --- a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint2/index.ts +++ b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint2/index.ts @@ -2,6 +2,6 @@ // See LICENSE in the project root for license information. /** @public */ -const defaultFunctionStatement = () => { }; +const defaultFunctionStatement = () => {}; export default defaultFunctionStatement; diff --git a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint3/index.ts b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint3/index.ts index e9977a59451..c468b59ad4e 100644 --- a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint3/index.ts +++ b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint3/index.ts @@ -4,4 +4,4 @@ /** * @public */ -export default function defaultFunctionDeclaration() { }; +export default function defaultFunctionDeclaration() {} diff --git a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint4/index.ts b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint4/index.ts index c97b7761d63..4587a388a9c 100644 --- a/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint4/index.ts +++ b/build-tests/api-extractor-scenarios/src/defaultExportOfEntryPoint4/index.ts @@ -2,4 +2,4 @@ // See LICENSE in the project root for license information. /** @public */ -export default "literal"; +export default 'literal'; diff --git a/build-tests/api-extractor-scenarios/src/docReferences/index.ts b/build-tests/api-extractor-scenarios/src/docReferences/index.ts index 7b6f83c618a..e07677f55cf 100644 --- a/build-tests/api-extractor-scenarios/src/docReferences/index.ts +++ b/build-tests/api-extractor-scenarios/src/docReferences/index.ts @@ -27,8 +27,7 @@ export namespace MyNamespace { * but its `@beta` tag will not get copied. * @public */ -export function testSimple(): void { -} +export function testSimple(): void {} /** * {@inheritDoc nonexistent-package#MyNamespace.MyClass.nonExistentMethod} @@ -39,20 +38,16 @@ export function testSimple(): void { * * @public */ -export function succeedForNow(): void { -} - +export function succeedForNow(): void {} /** * {@inheritDoc MyNamespace.MyClass.nonExistentMethod} * @public */ -export function failWithBrokenLink(): void { -} +export function failWithBrokenLink(): void {} /** * {@inheritDoc} * @public */ -export function failWithMissingReference(): void { -} +export function failWithMissingReference(): void {} diff --git a/build-tests/api-extractor-scenarios/src/docReferences2/index.ts b/build-tests/api-extractor-scenarios/src/docReferences2/index.ts index 9c5530e7e1c..0fa5b23018b 100644 --- a/build-tests/api-extractor-scenarios/src/docReferences2/index.ts +++ b/build-tests/api-extractor-scenarios/src/docReferences2/index.ts @@ -4,29 +4,23 @@ /** @public */ export class CyclicA { /** {@inheritDoc CyclicB.methodB2} */ - public methodA1(): void { - } + public methodA1(): void {} /** {@inheritDoc CyclicB.methodB4} */ - public methodA3(): void { - } + public methodA3(): void {} } /** @public */ export class CyclicB { /** {@inheritDoc CyclicA.methodA3} */ - public methodB2(): void { - } + public methodB2(): void {} /** THE COMMENT */ - public methodB4(): void { - } + public methodB4(): void {} } /** @public */ export class FailWithSelfReference { /** {@inheritDoc FailWithSelfReference.method2} */ - public method1(): void { - } + public method1(): void {} /** {@inheritDoc FailWithSelfReference.method1} */ - public method2(): void { - } + public method2(): void {} } diff --git a/build-tests/api-extractor-scenarios/src/docReferences3/index.ts b/build-tests/api-extractor-scenarios/src/docReferences3/index.ts index 967d05b3e23..1b6ba3cd98c 100644 --- a/build-tests/api-extractor-scenarios/src/docReferences3/index.ts +++ b/build-tests/api-extractor-scenarios/src/docReferences3/index.ts @@ -4,8 +4,7 @@ /** @public */ export namespace A { export class B { - public myMethod(): void { - } + public myMethod(): void {} } } @@ -18,16 +17,14 @@ export interface A { * {@link MyNamespace.MyClass.myMethod | the method} * @public */ -export function failWithAmbiguity() { -} +export function failWithAmbiguity() {} /** * {@link (A:namespace).B.myMethod | the method} * {@link (A:interface).myProperty | the property} * @public */ -export function succeedWithSelector() { -} +export function succeedWithSelector() {} /** * NOTE: The broken link checker currently is not able to validate references to external packages. @@ -35,5 +32,4 @@ export function succeedWithSelector() { * {@link nonexistent#nonexistent} * @public */ -export function succeedWithExternalReference(): void { -} +export function succeedWithExternalReference(): void {} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.ts new file mode 100644 index 00000000000..fd9fe5ecfe5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.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 Options from './Options'; + +/** @public */ +export default class Item { + options: Options; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.ts new file mode 100644 index 00000000000..a2586a59a87 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.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. + +/** @public */ +export default interface Options { + name: string; + color: 'red' | 'blue'; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/index.ts new file mode 100644 index 00000000000..889570c3306 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/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 type { default as renamed_Options } from './Options'; +export { default as Item } from './Item'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.ts new file mode 100644 index 00000000000..247b3f48835 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.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 Options from './renamed/Options'; + +/** @public */ +export default class Item { + options: Options; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/index.ts new file mode 100644 index 00000000000..e5ae676d355 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/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. + +import * as renamed from './renamed'; +export { renamed }; +export { default as Item } from './Item'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts new file mode 100644 index 00000000000..d58c03679aa --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import SubOptions from './sub/SubOptions'; + +/** @public */ +export default interface Options { + name: string; + color: 'red' | 'blue'; + subOptions: SubOptions; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/index.ts new file mode 100644 index 00000000000..1066c9b2a0d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/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. + +import * as sub from './sub'; +export { sub }; +export { default as Options } from './Options'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts new file mode 100644 index 00000000000..bc413e17cc0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.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 default interface SubOptions { + count: number; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/index.ts new file mode 100644 index 00000000000..1c21a1ed30e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/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 type { default as SubOptions } from './SubOptions'; diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts new file mode 100644 index 00000000000..5f638c0854c --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** @public */ +export class Item { + options: import('./Options').Options; + lib1: import('api-extractor-lib1-test').Lib1Interface; + lib2: import('api-extractor-lib2-test').Lib2Interface; + lib3: import('api-extractor-lib3-test').Lib1Class; + reExport: import('./re-export').Lib2Class; +} diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts new file mode 100644 index 00000000000..938f0a920d0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.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. + +export interface Options { + name: string; + color: 'red' | 'blue'; +} diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/index.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/index.ts new file mode 100644 index 00000000000..49797b5dcf8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/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. + +import * as Lib1 from 'api-extractor-lib1-test'; +import { Lib2Interface } from 'api-extractor-lib2-test'; + +export { Lib1, Lib2Interface }; +export { Item } from './Item'; diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts new file mode 100644 index 00000000000..6f1dedc68cf --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.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 { Lib2Class } from 'api-extractor-lib2-test'; diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts new file mode 100644 index 00000000000..5d211e8470e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType2/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. + +/** @public */ +export interface IExample { + dottedImportType: import('api-extractor-lib1-test').Lib1Namespace.Inner.X | undefined; + dottedImportType2: import('api-extractor-lib1-test').Lib1Namespace.Y | undefined; +} diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType3/index.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType3/index.ts new file mode 100644 index 00000000000..325f1213ebd --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType3/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. + +/** @public */ +export interface IExample { + generic: import('api-extractor-lib1-test').Lib1GenericType< + number | undefined, + import('api-extractor-lib1-test').Lib1Interface + >; +} diff --git a/build-tests/api-extractor-scenarios/src/ecmaScriptPrivateFields/index.ts b/build-tests/api-extractor-scenarios/src/ecmaScriptPrivateFields/index.ts new file mode 100644 index 00000000000..df20c255930 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/ecmaScriptPrivateFields/index.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. + +/** @public */ +export class Example { + private _typeScriptPrivate: string; + #ecmaScriptField: string; + #ecmaScriptField2: string; +} diff --git a/build-tests/api-extractor-scenarios/src/enumSorting/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/enumSorting/config/api-extractor-overrides.json new file mode 100644 index 00000000000..615b08d99de --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/enumSorting/config/api-extractor-overrides.json @@ -0,0 +1,3 @@ +{ + "enumMemberOrder": "preserve" +} diff --git a/build-tests/api-extractor-scenarios/src/enumSorting/index.ts b/build-tests/api-extractor-scenarios/src/enumSorting/index.ts new file mode 100644 index 00000000000..d54b26b6412 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/enumSorting/index.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. + +/** @public */ +export enum RegularEnum { + /** + * These are some docs for Zero + */ + Zero, + + /** + * These are some docs for One + */ + One = 1, + + /** + * These are some docs for Two + */ + Two = RegularEnum.One + 1 +} + +/** @public */ +export const enum ConstEnum { + Zero, + One = 1, + Two = RegularEnum.One + 1 +} diff --git a/build-tests/api-extractor-scenarios/src/excerptTokens/index.d.ts b/build-tests/api-extractor-scenarios/src/excerptTokens/index.d.ts new file mode 100644 index 00000000000..75cc8805cf7 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/excerptTokens/index.d.ts @@ -0,0 +1,16 @@ +// prettier-ignore +/** @public */ +export let MY_CONSTANT : number ; + +// prettier-ignore +/** + * @public This is my class. + */ +export class MyClass { + /** + * This method does something. + * @param x - This is x. + * @param y - This is y. + */ + someMethod(x : number , y : string ) : boolean ; +} diff --git a/build-tests/api-extractor-scenarios/src/exportDuplicate/index.ts b/build-tests/api-extractor-scenarios/src/exportDuplicate/index.ts index 179b32c7b5d..a1108c2623f 100644 --- a/build-tests/api-extractor-scenarios/src/exportDuplicate/index.ts +++ b/build-tests/api-extractor-scenarios/src/exportDuplicate/index.ts @@ -2,11 +2,11 @@ // See LICENSE in the project root for license information. /** @public */ -export class X { } -export { X as Y } +export class X {} +export { X as Y }; /** @internal */ -class A { } +class A {} // The underscore warning should get printed next to these export statements, not next to the class declaration -export { A as B } -export { A as C } +export { A as B }; +export { A as C }; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator.ts new file mode 100644 index 00000000000..17df6809b45 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator.ts @@ -0,0 +1,23 @@ +/** + * Returns the sum of adding `b` to `a` + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +export function add(a: number, b: number): number { + return a + b; +} + +/** + * Returns the sum of subtracting `b` from `a` + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +export function subtract(a: number, b: number): number { + return a - b; +} + +export * from './common'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator2.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator2.ts new file mode 100644 index 00000000000..38b5ef6950a --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs/calculator2.ts @@ -0,0 +1,23 @@ +/** + * Returns the sum of adding `b` to `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +export function add(a: bigint, b: bigint): bigint { + return a + b; +} + +/** + * Returns the sum of subtracting `b` from `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +export function subtract(a: bigint, b: bigint): bigint { + return a - b; +} + +export * from './common'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs/common.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs/common.ts new file mode 100644 index 00000000000..67d0445901d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs/common.ts @@ -0,0 +1,5 @@ +/** + * Returns the version of the calculator. + * @public + */ +export const calculatorVersion: string = '1.0.0'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs/index.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs/index.ts new file mode 100644 index 00000000000..f2b54960292 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs/index.ts @@ -0,0 +1,5 @@ +import * as calculator from './calculator'; +export { calculator }; + +import * as calculator2 from './calculator2'; +export { calculator2 }; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs2/forgottenNs.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/forgottenNs.ts new file mode 100644 index 00000000000..fc104acc837 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/forgottenNs.ts @@ -0,0 +1,4 @@ +/** + * @public + */ +export class ForgottenClass {} diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs2/index.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/index.ts new file mode 100644 index 00000000000..2e3ab2c86ca --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/index.ts @@ -0,0 +1,2 @@ +import * as ns from './ns'; +export { ns }; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs2/ns.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/ns.ts new file mode 100644 index 00000000000..5ea39d1dc1c --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs2/ns.ts @@ -0,0 +1,8 @@ +import * as forgottenNs from './forgottenNs'; + +/** + * @public + */ +export function exportedApi(): forgottenNs.ForgottenClass { + return new forgottenNs.ForgottenClass(); +} diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs3/NamespaceWithTrimming.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/NamespaceWithTrimming.ts new file mode 100644 index 00000000000..7045c1aa3eb --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/NamespaceWithTrimming.ts @@ -0,0 +1,8 @@ +/** @public */ +export const NS_PUBLIC = 'PUBLIC'; + +/** @beta */ +export const NS_BETA = 'BETA'; + +/** @internal */ +export const NS_INTERNAL = 'INTERNAL'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs3/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/config/api-extractor-overrides.json new file mode 100644 index 00000000000..56d14e1823b --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/config/api-extractor-overrides.json @@ -0,0 +1,7 @@ +{ + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/temp/etc/exportImportStarAs3/rollup.d.ts", + "publicTrimmedFilePath": "/temp/etc/exportImportStarAs3/rollup-public.d.ts" + } +} diff --git a/build-tests/api-extractor-scenarios/src/exportImportStarAs3/index.ts b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/index.ts new file mode 100644 index 00000000000..0afcd1c27ef --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportStarAs3/index.ts @@ -0,0 +1,6 @@ +/** + * Test that when exporting namespaces, we don't export members that got trimmed. + * See this issue: https://github.com/microsoft/rushstack/issues/2791 + */ +import * as NS from './NamespaceWithTrimming'; +export { NS }; diff --git a/build-tests/api-extractor-scenarios/src/exportImportedExternal/index.ts b/build-tests/api-extractor-scenarios/src/exportImportedExternal/index.ts index 78162619ac5..089e8283aa5 100644 --- a/build-tests/api-extractor-scenarios/src/exportImportedExternal/index.ts +++ b/build-tests/api-extractor-scenarios/src/exportImportedExternal/index.ts @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. import { Lib1Interface } from 'api-extractor-lib1-test'; -export { Lib1Interface } +export { Lib1Interface }; import { Lib2Class as RenamedLib2Class } from 'api-extractor-lib2-test'; -export { RenamedLib2Class as DoubleRenamedLib2Class } +export { RenamedLib2Class as DoubleRenamedLib2Class }; export { Lib1Class } from 'api-extractor-lib1-test'; export { Lib2Class as RenamedLib2Class } from 'api-extractor-lib2-test'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/importer.ts b/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/importer.ts new file mode 100644 index 00000000000..227c5fc72c5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/importer.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 { default, Lib2Class } from 'api-extractor-lib2-test'; diff --git a/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/index.ts b/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/index.ts new file mode 100644 index 00000000000..a759cbbd7c2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportImportedExternalDefault/index.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. + +export { default, Lib2Class } from './importer'; + +import { default as Base } from 'api-extractor-lib2-test'; + +/** @public */ +export class Child extends Base {} diff --git a/build-tests/api-extractor-scenarios/src/exportStar/localFile.ts b/build-tests/api-extractor-scenarios/src/exportStar/localFile.ts index 95fbe424bb5..beeb886bd75 100644 --- a/build-tests/api-extractor-scenarios/src/exportStar/localFile.ts +++ b/build-tests/api-extractor-scenarios/src/exportStar/localFile.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. /** @public */ -export class A { } +export class A {} /** @public */ -export class B { } +export class B {} diff --git a/build-tests/api-extractor-scenarios/src/exportStar/reexportStar.ts b/build-tests/api-extractor-scenarios/src/exportStar/reexportStar.ts index b382f373b00..10f0fc318f0 100644 --- a/build-tests/api-extractor-scenarios/src/exportStar/reexportStar.ts +++ b/build-tests/api-extractor-scenarios/src/exportStar/reexportStar.ts @@ -4,4 +4,4 @@ export * from './localFile'; /** @public */ -export class C { } +export class C {} diff --git a/build-tests/api-extractor-scenarios/src/exportStar2/reexportStar.ts b/build-tests/api-extractor-scenarios/src/exportStar2/reexportStar.ts index f2ed3c7966f..4511ea5b7db 100644 --- a/build-tests/api-extractor-scenarios/src/exportStar2/reexportStar.ts +++ b/build-tests/api-extractor-scenarios/src/exportStar2/reexportStar.ts @@ -4,4 +4,4 @@ export * from 'api-extractor-lib1-test'; /** @public */ -export class A { } +export class A {} diff --git a/build-tests/api-extractor-scenarios/src/exportStar3/reexportStar.ts b/build-tests/api-extractor-scenarios/src/exportStar3/reexportStar.ts index b08a7ea8776..4c0cd610a17 100644 --- a/build-tests/api-extractor-scenarios/src/exportStar3/reexportStar.ts +++ b/build-tests/api-extractor-scenarios/src/exportStar3/reexportStar.ts @@ -5,4 +5,4 @@ export * from 'api-extractor-lib1-test'; export * from 'api-extractor-lib2-test'; /** @public */ -export class A { } +export class A {} diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs/calculator.ts b/build-tests/api-extractor-scenarios/src/exportStarAs/calculator.ts new file mode 100644 index 00000000000..17df6809b45 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs/calculator.ts @@ -0,0 +1,23 @@ +/** + * Returns the sum of adding `b` to `a` + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +export function add(a: number, b: number): number { + return a + b; +} + +/** + * Returns the sum of subtracting `b` from `a` + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +export function subtract(a: number, b: number): number { + return a - b; +} + +export * from './common'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs/calculator2.ts b/build-tests/api-extractor-scenarios/src/exportStarAs/calculator2.ts new file mode 100644 index 00000000000..38b5ef6950a --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs/calculator2.ts @@ -0,0 +1,23 @@ +/** + * Returns the sum of adding `b` to `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of adding `b` to `a` + * @public + */ +export function add(a: bigint, b: bigint): bigint { + return a + b; +} + +/** + * Returns the sum of subtracting `b` from `a` for large integers + * @param a - first number + * @param b - second number + * @returns Sum of subtract `b` from `a` + * @beta + */ +export function subtract(a: bigint, b: bigint): bigint { + return a - b; +} + +export * from './common'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs/common.ts b/build-tests/api-extractor-scenarios/src/exportStarAs/common.ts new file mode 100644 index 00000000000..67d0445901d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs/common.ts @@ -0,0 +1,5 @@ +/** + * Returns the version of the calculator. + * @public + */ +export const calculatorVersion: string = '1.0.0'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs/index.ts b/build-tests/api-extractor-scenarios/src/exportStarAs/index.ts new file mode 100644 index 00000000000..22ebe390dc0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs/index.ts @@ -0,0 +1,2 @@ +export * as calculator from './calculator'; +export * as calculator2 from './calculator2'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs2/forgottenNs.ts b/build-tests/api-extractor-scenarios/src/exportStarAs2/forgottenNs.ts new file mode 100644 index 00000000000..fc104acc837 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs2/forgottenNs.ts @@ -0,0 +1,4 @@ +/** + * @public + */ +export class ForgottenClass {} diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs2/index.ts b/build-tests/api-extractor-scenarios/src/exportStarAs2/index.ts new file mode 100644 index 00000000000..497daa5907b --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs2/index.ts @@ -0,0 +1 @@ +export * as ns from './ns'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs2/ns.ts b/build-tests/api-extractor-scenarios/src/exportStarAs2/ns.ts new file mode 100644 index 00000000000..5ea39d1dc1c --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs2/ns.ts @@ -0,0 +1,8 @@ +import * as forgottenNs from './forgottenNs'; + +/** + * @public + */ +export function exportedApi(): forgottenNs.ForgottenClass { + return new forgottenNs.ForgottenClass(); +} diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs3/NamespaceWithTrimming.ts b/build-tests/api-extractor-scenarios/src/exportStarAs3/NamespaceWithTrimming.ts new file mode 100644 index 00000000000..7045c1aa3eb --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs3/NamespaceWithTrimming.ts @@ -0,0 +1,8 @@ +/** @public */ +export const NS_PUBLIC = 'PUBLIC'; + +/** @beta */ +export const NS_BETA = 'BETA'; + +/** @internal */ +export const NS_INTERNAL = 'INTERNAL'; diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs3/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/exportStarAs3/config/api-extractor-overrides.json new file mode 100644 index 00000000000..414a2156393 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs3/config/api-extractor-overrides.json @@ -0,0 +1,7 @@ +{ + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/temp/etc/exportStarAs3/rollup.d.ts", + "publicTrimmedFilePath": "/temp/etc/exportStarAs3/rollup-public.d.ts" + } +} diff --git a/build-tests/api-extractor-scenarios/src/exportStarAs3/index.ts b/build-tests/api-extractor-scenarios/src/exportStarAs3/index.ts new file mode 100644 index 00000000000..6bd5a26a26d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/exportStarAs3/index.ts @@ -0,0 +1,5 @@ +/** + * Test that when exporting namespaces, we don't export members that got trimmed. + * See this issue: https://github.com/microsoft/rushstack/issues/2791 + */ +export * as NS from './NamespaceWithTrimming'; diff --git a/build-tests/api-extractor-scenarios/src/functionOverload/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/functionOverload/config/api-extractor-overrides.json index 3894423ef64..43a683131c6 100644 --- a/build-tests/api-extractor-scenarios/src/functionOverload/config/api-extractor-overrides.json +++ b/build-tests/api-extractor-scenarios/src/functionOverload/config/api-extractor-overrides.json @@ -1,8 +1,9 @@ { "dtsRollup": { "enabled": true, - "untrimmedFilePath": "/etc/test-outputs/functionOverload/rollup.d.ts", - "betaTrimmedFilePath": "/etc/test-outputs/functionOverload/beta-rollup.d.ts", - "publicTrimmedFilePath": "/etc/test-outputs/functionOverload/public-rollup.d.ts" - }, -} \ No newline at end of file + "untrimmedFilePath": "/temp/etc/functionOverload/rollup.d.ts", + "alphaTrimmedFilePath": "/temp/etc/functionOverload/alpha-rollup.d.ts", + "betaTrimmedFilePath": "/temp/etc/functionOverload/beta-rollup.d.ts", + "publicTrimmedFilePath": "/temp/etc/functionOverload/public-rollup.d.ts" + } +} diff --git a/build-tests/api-extractor-scenarios/src/functionOverload/index.ts b/build-tests/api-extractor-scenarios/src/functionOverload/index.ts index 2a6e5093a21..b57f6dc04ee 100644 --- a/build-tests/api-extractor-scenarios/src/functionOverload/index.ts +++ b/build-tests/api-extractor-scenarios/src/functionOverload/index.ts @@ -17,7 +17,10 @@ export function combine(x: string, y: string): string; export function combine(x: number, y: number): number; // implementation -export function combine(x: string|number|boolean, y: string|number|boolean): string|number|boolean { +export function combine( + x: string | number | boolean, + y: string | number | boolean +): string | number | boolean { return 42; } @@ -32,7 +35,7 @@ export function _combine(x: string, y: string): string; export function _combine(x: number, y: number): number; // implementation -export function _combine(x: string|number, y: string|number): string|number { +export function _combine(x: string | number, y: string | number): string | number { return 42; } @@ -56,7 +59,7 @@ export class Combiner { public combine(x: number, y: number): number; // implementation - public combine(x: string|number|boolean, y: string|number|boolean): string|number|boolean { + public combine(x: string | number | boolean, y: string | number | boolean): string | number | boolean { return 42; } -} \ No newline at end of file +} diff --git a/build-tests/api-extractor-scenarios/src/importEquals/index.ts b/build-tests/api-extractor-scenarios/src/importEquals/index.ts index d57b9076617..6af3a22b33f 100644 --- a/build-tests/api-extractor-scenarios/src/importEquals/index.ts +++ b/build-tests/api-extractor-scenarios/src/importEquals/index.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 colors = require('colors'); +import { Colorize } from '@rushstack/terminal'; /** @public */ -export function useColors(): typeof colors.zebra { - return colors.zebra; +export function useColors(): typeof Colorize.red { + return Colorize.red; } diff --git a/build-tests/api-extractor-scenarios/src/importType/index.ts b/build-tests/api-extractor-scenarios/src/importType/index.ts new file mode 100644 index 00000000000..e9f48f45d1e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/importType/index.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 type { Lib1Class, Lib1Interface } from 'api-extractor-lib1-test'; + +// This should prevent Lib1Interface from being emitted as a type-only import, even though B uses it that way. +import { Lib1Interface as Renamed } from 'api-extractor-lib1-test'; + +/** @public */ +export interface A extends Lib1Class {} + +/** @public */ +export interface B extends Lib1Interface {} + +/** @public */ +export interface C extends Renamed {} diff --git a/build-tests/api-extractor-scenarios/src/includeForgottenExports/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/includeForgottenExports/config/api-extractor-overrides.json new file mode 100644 index 00000000000..da3ba9470ba --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/includeForgottenExports/config/api-extractor-overrides.json @@ -0,0 +1,13 @@ +{ + "apiReport": { + "enabled": true, + "reportFolder": "/temp/etc/includeForgottenExports", + "includeForgottenExports": true + }, + + "docModel": { + "enabled": true, + "apiJsonFilePath": "/temp/etc/includeForgottenExports/.api.json", + "includeForgottenExports": true + } +} diff --git a/build-tests/api-extractor-scenarios/src/includeForgottenExports/index.ts b/build-tests/api-extractor-scenarios/src/includeForgottenExports/index.ts new file mode 100644 index 00000000000..908200b2973 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/includeForgottenExports/index.ts @@ -0,0 +1,70 @@ +import * as internal2 from './internal2'; + +/** + * `ForgottenExport2` wants to inherit this doc comment, but unfortunately this isn't + * supported yet + * @public + */ +class ForgottenExport1 { + prop?: ForgottenExport2; + constructor() {} +} + +/** + * @public + * {@inheritDoc ForgottenExport1} + */ +type ForgottenExport2 = number; + +/** @public */ +export function someFunction1(): ForgottenExport1 { + return new ForgottenExport1(); +} + +/** + * This type is exported but has the same name as a forgotten type in './internal.ts'. This + * forgotten type is also included in the API report and doc model files. The forgotten type + * will be renamed to avoid a name conflict. + * @public + */ +export type DuplicateName = boolean; + +export { someFunction2 } from './internal1'; + +/** @public */ +export namespace SomeNamespace1 { + class ForgottenExport3 {} + + export function someFunction3(): ForgottenExport3 { + return new ForgottenExport3(); + } +} + +/** @public */ +namespace ForgottenExport4 { + export class ForgottenExport5 {} +} + +/** @public */ +export function someFunction4(): ForgottenExport4.ForgottenExport5 { + return new ForgottenExport4.ForgottenExport5(); +} + +/** @public */ +export function someFunction5(): internal2.ForgottenExport6 { + return new internal2.ForgottenExport6(); +} + +/** + * This forgotten item has the same name as another forgotten item in another + * file. They should be given unique names. + * @public + */ +class AnotherDuplicateName {} + +/** @public */ +export function someFunction6(): AnotherDuplicateName { + return new AnotherDuplicateName(); +} + +export { someFunction7 } from './internal1'; diff --git a/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal1.ts b/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal1.ts new file mode 100644 index 00000000000..e9adb34de2e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal1.ts @@ -0,0 +1,19 @@ +/** + * Will be renamed to avoid a name conflict with the exported `DuplicateName` from + * index.ts. + * @public + */ +type DuplicateName = number; + +/** @public */ +export function someFunction2(): DuplicateName { + return 5; +} + +/** @public */ +class AnotherDuplicateName {} + +/** @public */ +export function someFunction7(): AnotherDuplicateName { + return new AnotherDuplicateName(); +} diff --git a/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal2.ts b/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal2.ts new file mode 100644 index 00000000000..248395af66b --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/includeForgottenExports/internal2.ts @@ -0,0 +1,2 @@ +/** @public */ +export class ForgottenExport6 {} diff --git a/build-tests/api-extractor-scenarios/src/inconsistentReleaseTags/index.ts b/build-tests/api-extractor-scenarios/src/inconsistentReleaseTags/index.ts index 3814e88e852..c6b73fcf0f9 100644 --- a/build-tests/api-extractor-scenarios/src/inconsistentReleaseTags/index.ts +++ b/build-tests/api-extractor-scenarios/src/inconsistentReleaseTags/index.ts @@ -23,4 +23,3 @@ export function alphaFunctionReturnsBeta(): IBeta { export function publicFunctionReturnsBeta(): IBeta { return { x: 123 }; } - diff --git a/build-tests/api-extractor-scenarios/src/inheritDoc/index.ts b/build-tests/api-extractor-scenarios/src/inheritDoc/index.ts new file mode 100644 index 00000000000..32973b443bc --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/inheritDoc/index.ts @@ -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. + +/** + * An API item with its own documentation. + * @public + */ +export const withOwnDocs = 0; + +/** + * {@inheritDoc withOwnDocs} + * @public + */ +export const inheritsFromInternal = 1; + +/** + * {@inheritDoc nonExistentTarget} + * @public + */ +export const inheritsFromInvalidInternal = 2; + +/** + * {@inheritDoc some-external-library#foo} + * @public + */ +export const inheritsFromExternal = 3; diff --git a/build-tests/api-extractor-scenarios/src/internationalCharacters/index.ts b/build-tests/api-extractor-scenarios/src/internationalCharacters/index.ts index f7dba2bac82..860ab8b9c0f 100644 --- a/build-tests/api-extractor-scenarios/src/internationalCharacters/index.ts +++ b/build-tests/api-extractor-scenarios/src/internationalCharacters/index.ts @@ -7,11 +7,10 @@ export class ClassΞ { return this; } - public 'invalid chars'(): void { - } + public 'invalid chars'(): void {} - public 'validChars'(): void { - } + // prettier-ignore + public 'validChars'(): void {} } -export { ClassΞ as ClassΣ } +export { ClassΞ as ClassΣ }; diff --git a/build-tests/api-extractor-scenarios/src/mergedDeclarations/index.ts b/build-tests/api-extractor-scenarios/src/mergedDeclarations/index.ts new file mode 100644 index 00000000000..6f24b7d751b --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/mergedDeclarations/index.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. + +/** @public */ +export class MergedClassAndInterface { + someProp: number; + someMethod(x: string): void {} +} + +/** @public */ +export interface MergedClassAndInterface { + anotherProp: boolean; + someMethod(x: string | boolean): void; +} + +/** @public */ +export interface MergedInterfaces { + someProp: number; +} + +/** @public */ +export interface MergedInterfaces { + someProp: number; +} + +/** @public */ +export class MergedClassAndNamespace { + someProp: number; +} + +/** @public */ +export namespace MergedClassAndNamespace { + export let anotherProp: number; +} + +/** @public */ +export namespace MergedNamespaces { + export class SomeClass {} +} + +/** @public */ +export namespace MergedNamespaces { + export class AnotherClass {} +} diff --git a/build-tests/api-extractor-scenarios/src/mixinPattern/index.ts b/build-tests/api-extractor-scenarios/src/mixinPattern/index.ts new file mode 100644 index 00000000000..80c1499fd80 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/mixinPattern/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. + +type Constructor = new (...args: any[]) => {}; + +function someMixin(base: Base) { + return class extends base { + mixinProp?: string; + }; +} + +/** @public */ +export class A { + prop?: string; +} + +/** @public */ +export class B extends someMixin(A) {} diff --git a/build-tests/api-extractor-scenarios/src/namedDefaultImport/index.ts b/build-tests/api-extractor-scenarios/src/namedDefaultImport/index.ts new file mode 100644 index 00000000000..46104f65f52 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namedDefaultImport/index.ts @@ -0,0 +1,9 @@ +import { default as DefaultClass_namedImport } from 'api-extractor-lib2-test'; +import { DefaultClass_reExport } from './re-export'; + +/** @public */ +export interface DefaultImportTypes { + namedImport: DefaultClass_namedImport; + reExport: DefaultClass_reExport; + dynamicImport: import('api-extractor-lib2-test').default; +} diff --git a/build-tests/api-extractor-scenarios/src/namedDefaultImport/re-export.ts b/build-tests/api-extractor-scenarios/src/namedDefaultImport/re-export.ts new file mode 100644 index 00000000000..41904089db3 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namedDefaultImport/re-export.ts @@ -0,0 +1 @@ +export { default as DefaultClass_reExport } from 'api-extractor-lib2-test'; diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports/index.ts b/build-tests/api-extractor-scenarios/src/namespaceImports/index.ts new file mode 100644 index 00000000000..5376cd34998 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports/index.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. + +import * as i1 from './intermediate1'; +import * as i2 from './intermediate2'; + +export { i1, i2 }; + +/** @public */ +export function someFunction(): i1.internal.SomeClass { + return new i1.internal.SomeClass(); +} diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate1.ts b/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate1.ts new file mode 100644 index 00000000000..59eb9ff7bc8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate1.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. + +import * as internal from './internal'; +export { internal }; diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate2.ts b/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate2.ts new file mode 100644 index 00000000000..59eb9ff7bc8 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports/intermediate2.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. + +import * as internal from './internal'; +export { internal }; diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports/internal.ts b/build-tests/api-extractor-scenarios/src/namespaceImports/internal.ts new file mode 100644 index 00000000000..6fd90b44eda --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports/internal.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. + +/** @public */ +export class SomeClass {} diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports2/index.ts b/build-tests/api-extractor-scenarios/src/namespaceImports2/index.ts new file mode 100644 index 00000000000..03b57b5c9ab --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports2/index.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. + +import * as internal from './internal'; +import { SomeClass } from './internal'; + +export { internal, SomeClass }; + +/** @public */ +export function someFunction(): SomeClass { + return new SomeClass(); +} diff --git a/build-tests/api-extractor-scenarios/src/namespaceImports2/internal.ts b/build-tests/api-extractor-scenarios/src/namespaceImports2/internal.ts new file mode 100644 index 00000000000..6fd90b44eda --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceImports2/internal.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. + +/** @public */ +export class SomeClass {} diff --git a/build-tests/api-extractor-scenarios/src/preapproved/index.ts b/build-tests/api-extractor-scenarios/src/preapproved/index.ts index 33b61c3f7c3..0e992e43009 100644 --- a/build-tests/api-extractor-scenarios/src/preapproved/index.ts +++ b/build-tests/api-extractor-scenarios/src/preapproved/index.ts @@ -14,15 +14,12 @@ export interface _PreapprovedInterface { /** @internal @preapproved */ export class _PreapprovedClass { - public member(): void { - } + public member(): void {} } /** @internal @preapproved */ export namespace _PreapprovedNamespace { - export class X { - } + export class X {} - export function f(): void { - } + export function f(): void {} } diff --git a/build-tests/api-extractor-scenarios/src/projectFolderUrl/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/projectFolderUrl/config/api-extractor-overrides.json new file mode 100644 index 00000000000..248ad89f144 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/projectFolderUrl/config/api-extractor-overrides.json @@ -0,0 +1,7 @@ +{ + "docModel": { + "enabled": true, + "apiJsonFilePath": "/temp/etc/projectFolderUrl/.api.json", + "projectFolderUrl": "http://github.com/path/to/some/projectFolder" + } +} diff --git a/build-tests/api-extractor-scenarios/src/projectFolderUrl/index.ts b/build-tests/api-extractor-scenarios/src/projectFolderUrl/index.ts new file mode 100644 index 00000000000..97e676767c7 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/projectFolderUrl/index.ts @@ -0,0 +1,2 @@ +/** @public */ +export class MyClass {} diff --git a/build-tests/api-extractor-scenarios/src/readonlyDeclarations/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/config/api-extractor-overrides.json new file mode 100644 index 00000000000..f287d642746 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/config/api-extractor-overrides.json @@ -0,0 +1,10 @@ +{ + "messages": { + "extractorMessageReporting": { + // Purposefully disabled for the `MyInterface.tsDocReadonly` test case. + "ae-missing-getter": { + "logLevel": "none" + } + } + } +} diff --git a/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.ts b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.ts new file mode 100644 index 00000000000..d964044840e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.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. + +/** @public */ +export const READONLY_VARIABLE = 'Hello world!'; + +/** + * @public + * @readonly + */ +export let TSDOC_READONLY_VARIABLE: string; + +/** @public */ +export class MyClass { + get _onlyGetter(): string { + return 'Hello world!'; + } + + readonly readonlyModifier: string; + + /** @readonly */ + tsDocReadonly: string; +} + +/** @public */ +export interface MyInterface { + get _onlyGetter(): string; + + readonly readonlyModifier: string; + + /** @readonly */ + set tsDocReadonly(value: string); + + readonly [x: number]: void; +} diff --git a/build-tests/api-extractor-scenarios/src/referenceTokens/index.ts b/build-tests/api-extractor-scenarios/src/referenceTokens/index.ts new file mode 100644 index 00000000000..4646cbef91f --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/referenceTokens/index.ts @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Lib2Class } from 'api-extractor-lib2-test'; +import { SomeClass5 } from './internal'; + +/** + * Various namespace scenarios. + * @public + */ +export namespace n1 { + type SomeType1 = number; + export function someFunction1(): SomeType1 { + return 5; + } + + export namespace n2 { + type SomeType2 = number; + export function someFunction2(): SomeType2 { + return 5; + } + + export namespace n3 { + export type SomeType3 = number; + export function someFunction3(): n2.n3.SomeType3 { + return 5; + } + } + + namespace n4 { + export type SomeType4 = number; + export function someFunction4(): n4.SomeType4 { + return 5; + } + } + } +} + +/** @public */ +export enum SomeEnum { + A = 'A', + B = 'B', + C = 'C' +} + +/** + * Enum member reference. + * @public + */ +export function someFunction5(): SomeEnum.A { + return SomeEnum.A; +} + +/** @public */ +export class SomeClass1 { + public static staticProp = 5; +} + +/** + * Static class member reference. + * @public + */ +export function someFunction6(): typeof SomeClass1.staticProp { + return 5; +} + +/** @public */ +export interface SomeInterface1 { + prop: number; +} + +/** + * Interface member reference. + * @public + */ +export function someFunction9({ prop: prop2 }: SomeInterface1): void {} + +class SomeClass2 {} + +/** + * Unexported symbol reference. + * @public + */ +export class SomeClass3 extends SomeClass2 {} + +/** + * Global symbol reference. + * @public + */ +export function someFunction7({ then: then2 }: Promise): typeof Date.prototype.getDate { + return () => 5; +} + +/** + * External symbol reference. + * @public + */ +export function someFunction8({ prop: prop2 }: Lib2Class): void {} + +/** + * Reference to a symbol exported from another file, but not exported from the package. + * @public + */ +export class SomeClass4 extends SomeClass5 {} + +/** @public */ +export const SomeSymbol1 = Symbol('ThisIsSomeSymbol1'); +/** @public */ +export const SomeVar1 = 'ThisIsSomeVar1'; +/** + * References to computed properties. + * @public + */ +export interface SomeInterface1 { + [SomeVar1]: () => string; + [SomeSymbol1]: () => string; +} diff --git a/build-tests/api-extractor-scenarios/src/referenceTokens/internal.ts b/build-tests/api-extractor-scenarios/src/referenceTokens/internal.ts new file mode 100644 index 00000000000..0261cad60e4 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/referenceTokens/internal.ts @@ -0,0 +1 @@ +export class SomeClass5 {} diff --git a/build-tests/api-extractor-scenarios/src/runScenarios.ts b/build-tests/api-extractor-scenarios/src/runScenarios.ts index 1fba2a97408..6282ce60443 100644 --- a/build-tests/api-extractor-scenarios/src/runScenarios.ts +++ b/build-tests/api-extractor-scenarios/src/runScenarios.ts @@ -1,112 +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 fs from 'fs'; -import * as path from 'path'; -import { 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); - - const entryPoints: string[] = []; - - // TODO: Eliminate this workaround - // See GitHub issue https://github.com/microsoft/rushstack/issues/1017 - for (const scenarioFolderName of buildConfig.scenarioFolderNames) { - const entryPoint: string = path.resolve(`./lib/${scenarioFolderName}/index.d.ts`); - entryPoints.push(entryPoint); - - const overridesPath = path.resolve(`./src/${scenarioFolderName}/config/api-extractor-overrides.json`); - const apiExtractorJsonOverrides = fs.existsSync(overridesPath) ? JsonFile.load(overridesPath) : {}; - const apiExtractorJson = { - '$schema': 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json', - - 'mainEntryPointFilePath': entryPoint, - - 'apiReport': { - 'enabled': true, - 'reportFolder': `/etc/test-outputs/${scenarioFolderName}` - }, - - 'dtsRollup': { - 'enabled': true, - 'untrimmedFilePath': `/etc/test-outputs/${scenarioFolderName}/rollup.d.ts` - }, - - 'docModel': { - 'enabled': true, - 'apiJsonFilePath': `/etc/test-outputs/${scenarioFolderName}/.api.json` - }, - - 'messages': { - 'extractorMessageReporting': { +import type { IRunScriptOptions } from '@rushstack/heft'; +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 + logLevel: 'warning', + addToApiReportFile: true }, 'ae-unresolved-link': { - 'logLevel': 'warning', - 'addToApiReportFile': true + logLevel: 'warning', + addToApiReportFile: true } } - }, - - 'testMode': true, - ...apiExtractorJsonOverrides - }; - - const apiExtractorJsonPath: string = `./temp/configs/api-extractor-${scenarioFolderName}.json`; - - JsonFile.save(apiExtractorJson, apiExtractorJsonPath, { ensureFolderExists: true }); - } - - let compilerState: CompilerState | undefined = undefined; - let anyErrors: boolean = false; - process.exitCode = 1; - - for (const scenarioFolderName of buildConfig.scenarioFolderNames) { - const apiExtractorJsonPath: string = `./temp/configs/api-extractor-${scenarioFolderName}.json`; - - console.log('Scenario: ' + scenarioFolderName); - - // Run the API Extractor command-line - 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) => { - if (message.messageId === 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; - } - }, - compilerState - }); - - if (extractorResult.errorCount > 0) { - anyErrors = true; + } } - } - - if (!anyErrors) { - process.exitCode = 0; - } + }); } diff --git a/build-tests/api-extractor-scenarios/src/spanSorting/index.ts b/build-tests/api-extractor-scenarios/src/spanSorting/index.ts new file mode 100644 index 00000000000..e87f12d18fb --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/spanSorting/index.ts @@ -0,0 +1,58 @@ +/** + * Doc comment + * @public + */ +export class ExampleA { + private _member3: string = ''; + public member2(): Promise { + return Promise.resolve(); + } + public member1: string = ''; +} + +/** + * Doc comment + * @public + */ +export class ExampleB { + /** + * If the file exists, calls loadFromFile(). + */ + public tryLoadFromFile(approvedPackagesPolicyEnabled: boolean): boolean { + return false; + } + + /** + * Helper function that adds an already created ApprovedPackagesItem to the + * list and set. + */ + private _addItem(): void {} +} + +/** @public */ +export class ExampleC { + /** + * This comment is improperly formatted TSDoc. + * Note that Prettier doesn't try to format it. + @returns the return value + @throws an exception + */ + public member1(): void {} +} + +/** + * Outer description + * @public + */ +export const exampleD = (o: { + /** + * Inner description + */ + a: number; + + /** + * @returns a string + * {@link http://example.com} + */ + b(): string; +}) => {}; diff --git a/build-tests/api-extractor-scenarios/src/typeLiterals/index.ts b/build-tests/api-extractor-scenarios/src/typeLiterals/index.ts new file mode 100644 index 00000000000..42e5f88f785 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/typeLiterals/index.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. + +/** @public */ +export class ClassWithTypeLiterals { + /** type literal in */ + public method1(vector: { x: number; y: number }): void {} + + /** type literal output */ + public method2(): { classValue: ClassWithTypeLiterals; callback: () => number } | undefined { + return undefined; + } +} diff --git a/build-tests/api-extractor-scenarios/src/typeOf/index.ts b/build-tests/api-extractor-scenarios/src/typeOf/index.ts index ba957d977bb..0fc5933058f 100644 --- a/build-tests/api-extractor-scenarios/src/typeOf/index.ts +++ b/build-tests/api-extractor-scenarios/src/typeOf/index.ts @@ -11,7 +11,7 @@ export function f(): typeof Lib1Class | undefined { return undefined; } -class ForgottenExport { } +class ForgottenExport {} /** * Reference IForgottenExport via "typeof" diff --git a/build-tests/api-extractor-scenarios/src/typeOf2/index.ts b/build-tests/api-extractor-scenarios/src/typeOf2/index.ts index 07728912e65..ddc2cf47ebf 100644 --- a/build-tests/api-extractor-scenarios/src/typeOf2/index.ts +++ b/build-tests/api-extractor-scenarios/src/typeOf2/index.ts @@ -3,7 +3,7 @@ /** @public */ export function f(): { a: number } { - return { a: 1}; + return { a: 1 }; } /** @public */ diff --git a/build-tests/api-extractor-scenarios/src/typeOf3/index.ts b/build-tests/api-extractor-scenarios/src/typeOf3/index.ts new file mode 100644 index 00000000000..85b73abb474 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/typeOf3/index.ts @@ -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. + +/** + * A function that references its own parameter type. + * @public + */ +export function f1(x: number): typeof x { + return x; +} + +/** + * A function that indirectly references its own parameter type. + * @public + */ +export function f2(x: number): keyof typeof x { + return 'valueOf'; +} + +/** + * A function that references its own type. + * @public + */ +export function f3(): typeof f3 | undefined { + return undefined; +} diff --git a/build-tests/api-extractor-scenarios/src/typeParameters/index.ts b/build-tests/api-extractor-scenarios/src/typeParameters/index.ts index 34e03e6c81b..40a39219505 100644 --- a/build-tests/api-extractor-scenarios/src/typeParameters/index.ts +++ b/build-tests/api-extractor-scenarios/src/typeParameters/index.ts @@ -2,26 +2,21 @@ // See LICENSE in the project root for license information. /** @public */ -export class GenericClass { -} +export class GenericClass {} /** @public */ -export class GenericClassWithConstraint { -} +export class GenericClassWithConstraint {} /** @public */ -export class GenericClassWithDefault { -} +export class GenericClassWithDefault {} /** @public */ export class ClassWithGenericMethod { - public method() { - } + public method() {} } /** @public */ -export interface GenericInterface { -} +export interface GenericInterface {} /** @public */ export interface InterfaceWithGenericCallSignature { @@ -34,8 +29,7 @@ export interface InterfaceWithGenericConstructSignature { } /** @public */ -export function genericFunction(): void { -} +export function genericFunction(): void {} /** @public */ export type GenericTypeAlias = T; diff --git a/build-tests/api-extractor-scenarios/tsconfig.json b/build-tests/api-extractor-scenarios/tsconfig.json index de8969fb815..2452b093b0e 100644 --- a/build-tests/api-extractor-scenarios/tsconfig.json +++ b/build-tests/api-extractor-scenarios/tsconfig.json @@ -1,29 +1,11 @@ { + "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, + "noImplicitAny": false, + // Intentionally turn this off for this project to test a combination of `export` and `export type` + // with type-only exports + "isolatedModules": false }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "include": ["src/**/*.ts", "typings/tsd.d.ts"] +} diff --git a/build-tests/api-extractor-test-01/.gitignore b/build-tests/api-extractor-test-01/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-test-01/.gitignore @@ -0,0 +1,4 @@ +# 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-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 cfb37d95019..e4725c5edc7 100644 --- a/build-tests/api-extractor-test-01/config/api-extractor.json +++ b/build-tests/api-extractor-test-01/config/api-extractor.json @@ -4,7 +4,7 @@ "mainEntryPointFilePath": "/lib/index.d.ts", "apiReport": { - "enabled": true, + "enabled": true }, "docModel": { @@ -14,6 +14,7 @@ "dtsRollup": { "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", "betaTrimmedFilePath": "/dist/-beta.d.ts", "publicTrimmedFilePath": "/dist/-public.d.ts" }, 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-test-01/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"] + } + ] +} 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 new file mode 100644 index 00000000000..fc9359c3768 --- /dev/null +++ b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-alpha.d.ts @@ -0,0 +1,342 @@ +/** + * api-extractor-test-01 + * + * @remarks + * This library is consumed by api-extractor-test-02 and api-extractor-test-03. + * It tests the basic types of definitions, and all the weird cases for following + * chains of type aliases. + * + * @packageDocumentation + */ + +import { default as Long_2 } from 'long'; +import { MAX_UNSIGNED_VALUE } from 'long'; + +/** + * Example of an abstract class that is directly exported. + * @public + */ +export declare abstract class AbstractClass { + abstract test(): void; +} + +/** + * Example of an abstract class that is exported separately from its + * definition. + * + * @public + */ +export declare abstract class AbstractClass2 { + abstract test2(): void; +} + +/** + * Example of an abstract class that is not the default export + * + * @public + */ +export declare abstract class AbstractClass3 { + abstract test3(): void; +} + +/** + * Test different kinds of ambient definitions + * @public + */ +export declare class AmbientConsumer { + /** + * Found via tsconfig.json's "lib" setting, which specifies the built-in "es2015.collection" + */ + builtinDefinition1(): Map; + /** + * Found via tsconfig.json's "lib" setting, which specifies the built-in "es2015.promise" + */ + builtinDefinition2(): Promise; + /** + * Configured via tsconfig.json's "lib" setting, which specifies `@types/jest`. + * The emitted index.d.ts gets a reference like this: + */ + definitelyTyped(): jest.MockContext; + /** + * Found via tsconfig.json's "include" setting point to a *.d.ts file. + * This is an old-style Definitely Typed definition, which is the worst possible kind, + * because consumers are expected to provide this, with no idea where it came from. + */ + localTypings(): IAmbientInterfaceExample; +} + +/** @public */ +declare namespace ANamespace { + const locallyExportedCustomSymbol: unique symbol; + /** @public */ + const fullyExportedCustomSymbol: unique symbol; +} + +/** + * Referenced by DefaultExportEdgeCaseReferencer. + * @public + */ +export declare class ClassExportedAsDefault { +} + +/** + * This class gets aliased twice before being exported from the package. + * @public + */ +export declare class ClassWithAccessModifiers { + /** Doc comment */ + private _privateField; + /** Doc comment */ + private privateMethod; + /** Doc comment */ + private get privateGetter(); + /** Doc comment */ + private privateSetter; + /** Doc comment */ + private constructor(); + /** Doc comment */ + private static privateStaticMethod; + /** Doc comment */ + protected protectedField: number; + /** Doc comment */ + protected get protectedGetter(): string; + /** Doc comment */ + protected protectedSetter(x: string): void; + /** Doc comment */ + static publicStaticField: number; + /** Doc comment */ + defaultPublicMethod(): void; +} + +/** + * @public + */ +export declare class ClassWithSymbols { + readonly [unexportedCustomSymbol]: number; + get [locallyExportedCustomSymbol](): string; + [fullyExportedCustomSymbol](): void; + get [ANamespace.locallyExportedCustomSymbol](): string; + [ANamespace.fullyExportedCustomSymbol](): void; + get [Symbol.toStringTag](): string; +} + +/** + * This class illustrates some cases involving type literals. + * @public + */ +export declare class ClassWithTypeLiterals { + /** type literal in */ + method1(vector: { + x: number; + y: number; + }): void; + /** type literal output */ + method2(): { + classValue: ClassWithTypeLiterals; + callback: () => number; + } | undefined; +} + +/** + * @public + */ +export declare const enum ConstEnum { + Zero = 0, + One = 1, + Two = 2 +} + +/** + * Tests a decorator + * @public + */ +export declare class DecoratorTest { + /** + * Function with a decorator + */ + test(): void; +} + +/** + * @public + */ +export declare class DefaultExportEdgeCase { + /** + * This reference is encountered before the definition of DefaultExportEdgeCase. + * The symbol.name will be "default" in this situation. + */ + reference: ClassExportedAsDefault; +} + +/** @public */ +export declare class ForgottenExportConsumer1 { + test1(): IForgottenExport | undefined; +} + +/** @public */ +export declare class ForgottenExportConsumer2 { + test2(): IForgottenExport_2 | undefined; +} + +/** + * This class directly consumes IForgottenDirectDependency + * and indirectly consumes IForgottenIndirectDependency. + * @beta + */ +export declare class ForgottenExportConsumer3 { + test2(): IForgottenDirectDependency | undefined; +} + +/** @public */ +export declare const fullyExportedCustomSymbol: unique symbol; + +/** + * This class is directly consumed by ForgottenExportConsumer3. + */ +declare interface IForgottenDirectDependency { + member: IForgottenIndirectDependency; +} + +/** + * The ForgottenExportConsumer1 class relies on this IForgottenExport. + * + * This should end up as a non-exported "IForgottenExport" in the index.d.ts. + */ +declare interface IForgottenExport { + instance1: string; +} + +/** + * The ForgottenExportConsumer2 class relies on this IForgottenExport. + * + * This should end up as a non-exported "IForgottenExport_2" in the index.d.ts. + * It is renamed to avoid a conflict with the IForgottenExport from ForgottenExportConsumer1. + */ +declare interface IForgottenExport_2 { + instance2: string; +} + +/** + * This class is indirectly consumed by ForgottenExportConsumer3. + */ +declare interface IForgottenIndirectDependency { +} + +/** + * This interface is exported as the default export for its source file. + * @public + */ +export declare interface IInterfaceAsDefaultExport { + /** + * A member of the interface + */ + member: string; +} + +/** + * IMergedInterface instance 1. + * @alpha + */ +export declare interface IMergedInterface { + type: string; + reference: IMergedInterfaceReferencee; +} + +/** + * IMergedInterface instance 2. + * @alpha + */ +export declare interface IMergedInterface { + type: string; + reference: IMergedInterfaceReferencee; +} + +/** + * @alpha + */ +export declare interface IMergedInterfaceReferencee { +} + +/** + * A simple, normal definition + * @public + */ +export declare interface ISimpleInterface { +} + +declare const locallyExportedCustomSymbol: unique symbol; + +export { MAX_UNSIGNED_VALUE } + +/** @public */ +export declare namespace NamespaceContainingVariable { + /* Excluded from this release type: variable */ +} + +/** + * This class gets aliased twice before being exported from the package. + * @public + */ +export declare class ReexportedClass { + getSelfReference(): ReexportedClass; + getValue(): string; +} + +/** @public */ +export declare class ReferenceLibDirective extends Intl.PluralRules { +} + +/** + * @public + */ +export declare enum RegularEnum { + /** + * These are some docs for Zero + */ + Zero = 0, + /** + * These are some docs for One + */ + One = 1, + /** + * These are some docs for Two + */ + Two = 2 +} + +/** + * This class has links such as {@link TypeReferencesInAedoc}. + * @public + */ +export declare class TypeReferencesInAedoc { + /** + * Returns a value + * @param arg1 - The input parameter of type {@link TypeReferencesInAedoc}. + * @returns An object of type {@link TypeReferencesInAedoc}. + */ + getValue(arg1: TypeReferencesInAedoc): TypeReferencesInAedoc; + /** {@inheritDoc api-extractor-test-01#TypeReferencesInAedoc.getValue} */ + getValue2(arg1: TypeReferencesInAedoc): TypeReferencesInAedoc; + /** + * @param arg - Malformed param reference. + */ + getValue3(arg1: TypeReferencesInAedoc): TypeReferencesInAedoc; +} + +declare const unexportedCustomSymbol: unique symbol; + +/** @public */ +export declare class UseLong { + use_long(): Long_2; +} + +/** @alpha */ +export declare const VARIABLE: string; + +/** + * Example decorator + * @public + */ +export declare function virtual(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor): void; + +export { } 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 1f17167d167..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,7 @@ * @packageDocumentation */ -/// -/// -/// -import Long from 'long'; +import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; /** @@ -59,7 +56,7 @@ export declare class AmbientConsumer { * Configured via tsconfig.json's "lib" setting, which specifies `@types/jest`. * The emitted index.d.ts gets a reference like this: */ - definitelyTyped(): jest.Context; + definitelyTyped(): jest.MockContext; /** * Found via tsconfig.json's "include" setting point to a *.d.ts file. * This is an old-style Definitely Typed definition, which is the worst possible kind, @@ -248,6 +245,7 @@ export declare interface ISimpleInterface { } declare const locallyExportedCustomSymbol: unique symbol; + export { MAX_UNSIGNED_VALUE } /** @public */ @@ -309,7 +307,7 @@ declare const unexportedCustomSymbol: unique symbol; /** @public */ export declare class UseLong { - use_long(): Long; + use_long(): Long_2; } /* Excluded from this release type: VARIABLE */ 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 567cf66521b..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,7 @@ * @packageDocumentation */ -/// -/// -/// -import Long from 'long'; +import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; /** @@ -59,7 +56,7 @@ export declare class AmbientConsumer { * Configured via tsconfig.json's "lib" setting, which specifies `@types/jest`. * The emitted index.d.ts gets a reference like this: */ - definitelyTyped(): jest.Context; + definitelyTyped(): jest.MockContext; /** * Found via tsconfig.json's "include" setting point to a *.d.ts file. * This is an old-style Definitely Typed definition, which is the worst possible kind, @@ -241,6 +238,7 @@ export declare interface ISimpleInterface { } declare const locallyExportedCustomSymbol: unique symbol; + export { MAX_UNSIGNED_VALUE } /** @public */ @@ -302,7 +300,7 @@ declare const unexportedCustomSymbol: unique symbol; /** @public */ export declare class UseLong { - use_long(): Long; + use_long(): Long_2; } /* Excluded from this release type: VARIABLE */ 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 2456363af22..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,7 @@ * @packageDocumentation */ -/// -/// -/// -import Long from 'long'; +import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; /** @@ -59,7 +56,7 @@ export declare class AmbientConsumer { * Configured via tsconfig.json's "lib" setting, which specifies `@types/jest`. * The emitted index.d.ts gets a reference like this: */ - definitelyTyped(): jest.Context; + definitelyTyped(): jest.MockContext; /** * Found via tsconfig.json's "include" setting point to a *.d.ts file. * This is an old-style Definitely Typed definition, which is the worst possible kind, @@ -268,6 +265,7 @@ export declare interface ISimpleInterface { } declare const locallyExportedCustomSymbol: unique symbol; + export { MAX_UNSIGNED_VALUE } /** @public */ @@ -330,7 +328,7 @@ declare const unexportedCustomSymbol: unique symbol; /** @public */ export declare class UseLong { - use_long(): Long; + use_long(): Long_2; } /** @alpha */ 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 615874583e5..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,7 +4,7 @@ ```ts -import Long from 'long'; +import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; // @public @@ -29,7 +29,7 @@ export abstract class AbstractClass3 { export class AmbientConsumer { builtinDefinition1(): Map; builtinDefinition2(): Promise; - definitelyTyped(): jest.Context; + definitelyTyped(): jest.MockContext; localTypings(): IAmbientInterfaceExample; } @@ -106,7 +106,7 @@ export class ForgottenExportConsumer1 { // @public (undocumented) export class ForgottenExportConsumer2 { - // Warning: (ae-forgotten-export) The symbol "IForgottenExport" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "IForgottenExport_2" needs to be exported by the entry point index.d.ts // // (undocumented) test2(): IForgottenExport_2 | undefined; @@ -190,7 +190,7 @@ export class TypeReferencesInAedoc { // @public (undocumented) export class UseLong { // (undocumented) - use_long(): Long; + use_long(): Long_2; } // @alpha (undocumented) @@ -199,5 +199,4 @@ export const VARIABLE: string; // @public export function virtual(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor): void; - ``` diff --git a/build-tests/api-extractor-test-01/package.json b/build-tests/api-extractor-test-01/package.json index 9acfd50a904..8e165a159ae 100644 --- a/build-tests/api-extractor-test-01/package.json +++ b/build-tests/api-extractor-test-01/package.json @@ -6,17 +6,16 @@ "main": "lib/index.js", "typings": "dist/api-extractor-test-01.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@types/jest": "23.3.11", + "@types/jest": "29.2.5", "@types/long": "4.0.0", "long": "^4.0.0" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-01/src/AccessModifiers.ts b/build-tests/api-extractor-test-01/src/AccessModifiers.ts index faf391265a8..0267dca4171 100644 --- a/build-tests/api-extractor-test-01/src/AccessModifiers.ts +++ b/build-tests/api-extractor-test-01/src/AccessModifiers.ts @@ -10,8 +10,7 @@ export class ClassWithAccessModifiers { private _privateField: number = 123; /** Doc comment */ - private privateMethod(): void { - } + private privateMethod(): void {} /** Doc comment */ private get privateGetter(): string { @@ -19,17 +18,13 @@ export class ClassWithAccessModifiers { } /** Doc comment */ - private privateSetter(x: string) { - } + private privateSetter(x: string) {} /** Doc comment */ - private constructor() { - } + private constructor() {} /** Doc comment */ - private static privateStaticMethod() { - } - + private static privateStaticMethod() {} /** Doc comment */ protected protectedField: number; @@ -40,13 +35,11 @@ export class ClassWithAccessModifiers { } /** Doc comment */ - protected protectedSetter(x: string) { - } + protected protectedSetter(x: string) {} /** Doc comment */ public static publicStaticField: number = 123; /** Doc comment */ - defaultPublicMethod(): void { - } + defaultPublicMethod(): void {} } diff --git a/build-tests/api-extractor-test-01/src/ClassWithTypeLiterals.ts b/build-tests/api-extractor-test-01/src/ClassWithTypeLiterals.ts index 9fe4497ebad..071dc824668 100644 --- a/build-tests/api-extractor-test-01/src/ClassWithTypeLiterals.ts +++ b/build-tests/api-extractor-test-01/src/ClassWithTypeLiterals.ts @@ -7,11 +7,10 @@ */ export class ClassWithTypeLiterals { /** type literal in */ - public method1(vector: { x :number, y :number}): void { - } + public method1(vector: { x: number; y: number }): void {} /** type literal output */ - public method2(): { classValue: ClassWithTypeLiterals, callback: () => number } | undefined { + public method2(): { classValue: ClassWithTypeLiterals; callback: () => number } | undefined { return undefined; } } diff --git a/build-tests/api-extractor-test-01/src/DeclarationMerging.ts b/build-tests/api-extractor-test-01/src/DeclarationMerging.ts index 6a86d38a10b..b9dac3157a2 100644 --- a/build-tests/api-extractor-test-01/src/DeclarationMerging.ts +++ b/build-tests/api-extractor-test-01/src/DeclarationMerging.ts @@ -4,8 +4,7 @@ /** * @alpha */ -export interface IMergedInterfaceReferencee { -} +export interface IMergedInterfaceReferencee {} /** * IMergedInterface instance 1. diff --git a/build-tests/api-extractor-test-01/src/DefaultExportEdgeCase.ts b/build-tests/api-extractor-test-01/src/DefaultExportEdgeCase.ts index a955fed845f..b39682ef1ed 100644 --- a/build-tests/api-extractor-test-01/src/DefaultExportEdgeCase.ts +++ b/build-tests/api-extractor-test-01/src/DefaultExportEdgeCase.ts @@ -16,5 +16,4 @@ export class DefaultExportEdgeCase { * Referenced by DefaultExportEdgeCaseReferencer. * @public */ -export default class ClassExportedAsDefault { -} +export default class ClassExportedAsDefault {} diff --git a/build-tests/api-extractor-test-01/src/EcmaScriptSymbols.ts b/build-tests/api-extractor-test-01/src/EcmaScriptSymbols.ts index be0106bc3d1..ac3a264e29d 100644 --- a/build-tests/api-extractor-test-01/src/EcmaScriptSymbols.ts +++ b/build-tests/api-extractor-test-01/src/EcmaScriptSymbols.ts @@ -29,17 +29,15 @@ export class ClassWithSymbols { return 'hello'; } - public [fullyExportedCustomSymbol](): void { - } + public [fullyExportedCustomSymbol](): void {} public get [ANamespace.locallyExportedCustomSymbol](): string { return 'hello'; } - public [ANamespace.fullyExportedCustomSymbol](): void { - } + public [ANamespace.fullyExportedCustomSymbol](): void {} public get [Symbol.toStringTag](): string { - return "ClassWithSymbols"; + return 'ClassWithSymbols'; } } diff --git a/build-tests/api-extractor-test-01/src/Enums.ts b/build-tests/api-extractor-test-01/src/Enums.ts index 782dd5544d5..f0a937cda1d 100644 --- a/build-tests/api-extractor-test-01/src/Enums.ts +++ b/build-tests/api-extractor-test-01/src/Enums.ts @@ -29,4 +29,3 @@ export const enum ConstEnum { One = 1, Two = RegularEnum.One + 1 } - diff --git a/build-tests/api-extractor-test-01/src/ForgottenExportConsumer3.ts b/build-tests/api-extractor-test-01/src/ForgottenExportConsumer3.ts index 55aa7c04138..433bb2b37e6 100644 --- a/build-tests/api-extractor-test-01/src/ForgottenExportConsumer3.ts +++ b/build-tests/api-extractor-test-01/src/ForgottenExportConsumer3.ts @@ -4,10 +4,7 @@ /** * This class is indirectly consumed by ForgottenExportConsumer3. */ -export interface IForgottenIndirectDependency { - -} - +export interface IForgottenIndirectDependency {} /** * This class is directly consumed by ForgottenExportConsumer3. diff --git a/build-tests/api-extractor-test-01/src/ReexportedClass3/index.ts b/build-tests/api-extractor-test-01/src/ReexportedClass3/index.ts index cc7a6009a8d..02904c4af2a 100644 --- a/build-tests/api-extractor-test-01/src/ReexportedClass3/index.ts +++ b/build-tests/api-extractor-test-01/src/ReexportedClass3/index.ts @@ -1 +1 @@ -export { ReexportedClass2 } from '../ReexportedClass2'; \ No newline at end of file +export { ReexportedClass2 } from '../ReexportedClass2'; diff --git a/build-tests/api-extractor-test-01/src/ReferenceLibDirective.ts b/build-tests/api-extractor-test-01/src/ReferenceLibDirective.ts index eda831c2354..cf3079db914 100644 --- a/build-tests/api-extractor-test-01/src/ReferenceLibDirective.ts +++ b/build-tests/api-extractor-test-01/src/ReferenceLibDirective.ts @@ -4,5 +4,4 @@ /// /** @public */ -export class ReferenceLibDirective extends Intl.PluralRules { -} +export class ReferenceLibDirective extends Intl.PluralRules {} diff --git a/build-tests/api-extractor-test-01/src/index.ts b/build-tests/api-extractor-test-01/src/index.ts index fa99a32bc91..7f45cb7eb03 100644 --- a/build-tests/api-extractor-test-01/src/index.ts +++ b/build-tests/api-extractor-test-01/src/index.ts @@ -16,8 +16,7 @@ * A simple, normal definition * @public */ -export interface ISimpleInterface { -} +export interface ISimpleInterface {} /** * Test different kinds of ambient definitions @@ -35,15 +34,17 @@ export class AmbientConsumer { * Found via tsconfig.json's "lib" setting, which specifies the built-in "es2015.promise" */ public builtinDefinition2(): Promise { - return new Promise(() => { /* */ }); + return new Promise(() => { + /* */ + }); } /** * Configured via tsconfig.json's "lib" setting, which specifies `@types/jest`. * The emitted index.d.ts gets a reference like this: */ - public definitelyTyped(): jest.Context { - return {} as jest.Context; + public definitelyTyped(): jest.MockContext { + return {} as jest.MockContext; } /** @@ -60,8 +61,11 @@ export class AmbientConsumer { * Example decorator * @public */ -export function virtual(target: Object, propertyKey: string | symbol, - descriptor: TypedPropertyDescriptor): void { +export function virtual( + target: Object, + propertyKey: string | symbol, + descriptor: TypedPropertyDescriptor +): void { // Eventually we may implement runtime validation (e.g. in DEBUG builds) // but currently this decorator is only used by the build tools. } @@ -91,15 +95,12 @@ export * from './DeclarationMerging'; export * from './Enums'; -export { - DefaultExportEdgeCase, - default as ClassExportedAsDefault -} from './DefaultExportEdgeCase'; +export { DefaultExportEdgeCase, default as ClassExportedAsDefault } from './DefaultExportEdgeCase'; /** * Test that we can correctly carry default imports into the rollup .d.ts file */ -import Long, { MAX_UNSIGNED_VALUE } from "long"; +import Long, { MAX_UNSIGNED_VALUE } from 'long'; export { MAX_UNSIGNED_VALUE }; /** @public */ export declare class UseLong { @@ -112,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/src/variableDeclarations.ts b/build-tests/api-extractor-test-01/src/variableDeclarations.ts index ed5390ce6ee..bba6ad6f7d3 100644 --- a/build-tests/api-extractor-test-01/src/variableDeclarations.ts +++ b/build-tests/api-extractor-test-01/src/variableDeclarations.ts @@ -7,5 +7,5 @@ export const VARIABLE: string = 'hello'; /** @public */ export namespace NamespaceContainingVariable { /** @internal */ - export let variable: object[] = [] + export let variable: object[] = []; } diff --git a/build-tests/api-extractor-test-01/tsconfig.json b/build-tests/api-extractor-test-01/tsconfig.json index fb5d521a29c..b4f9d8b2945 100644 --- a/build-tests/api-extractor-test-01/tsconfig.json +++ b/build-tests/api-extractor-test-01/tsconfig.json @@ -1,30 +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" - ] -} \ No newline at end of file + "include": ["src/**/*.ts", "typings/tsd.d.ts"] +} diff --git a/build-tests/api-extractor-test-02/.gitignore b/build-tests/api-extractor-test-02/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-test-02/.gitignore @@ -0,0 +1,4 @@ +# 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-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 cfb37d95019..e4725c5edc7 100644 --- a/build-tests/api-extractor-test-02/config/api-extractor.json +++ b/build-tests/api-extractor-test-02/config/api-extractor.json @@ -4,7 +4,7 @@ "mainEntryPointFilePath": "/lib/index.d.ts", "apiReport": { - "enabled": true, + "enabled": true }, "docModel": { @@ -14,6 +14,7 @@ "dtsRollup": { "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", "betaTrimmedFilePath": "/dist/-beta.d.ts", "publicTrimmedFilePath": "/dist/-public.d.ts" }, 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-test-02/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"] + } + ] +} 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 new file mode 100644 index 00000000000..a07f2b9459b --- /dev/null +++ b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-alpha.d.ts @@ -0,0 +1,59 @@ +/** + * api-extractor-test-02 + * + * @remarks + * This library consumes api-extractor-test-01 and is consumed by api-extractor-test-03. + * + * @packageDocumentation + */ + +/// + +import { ISimpleInterface } from 'api-extractor-test-01'; +import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; +import * as semver1 from 'semver'; + +/** + * An interface with a generic parameter. + * @public + */ +export declare interface GenericInterface { + member: T; +} + +/** @public */ +export declare function importDeduping1(arg1: ISimpleInterface, arg2: ISimpleInterface): void; + +/** @public */ +export declare function importDeduping2(arg1: ISimpleInterface, arg2: ISimpleInterface): void; + +/** + * A class that inherits from a type defined in the "semver" module imported from \@types/semver. + * @public + */ +export declare class ImportedModuleAsBaseClass extends semver1.SemVer { +} + +/** + * A generic parameter that references the "semver" module imported from \@types/semver. + * @public + */ +export declare function importedModuleAsGenericParameter(): GenericInterface | undefined; + +/** + * This definition references the "semver" module imported from \@types/semver. + * @public + */ +export declare function importedModuleAsReturnType(): semver1.SemVer | undefined; + +export { RenamedReexportedClass3 } + +/** + * Example of a class that inherits from an externally imported class. + * @public + */ +export declare class SubclassWithImport extends RenamedReexportedClass3 implements ISimpleInterface { + test(): void; +} + +export { } 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 1719534b434..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'; @@ -43,6 +45,7 @@ export declare function importedModuleAsGenericParameter(): GenericInterface + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; @@ -43,6 +45,7 @@ export declare function importedModuleAsGenericParameter(): GenericInterface + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; @@ -43,6 +45,7 @@ export declare function importedModuleAsGenericParameter(): GenericInterface + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; @@ -38,5 +40,4 @@ export class SubclassWithImport extends RenamedReexportedClass3 implements ISimp test(): void; } - ``` diff --git a/build-tests/api-extractor-test-02/package.json b/build-tests/api-extractor-test-02/package.json index 0bc655d4373..5b606031094 100644 --- a/build-tests/api-extractor-test-02/package.json +++ b/build-tests/api-extractor-test-02/package.json @@ -6,17 +6,17 @@ "main": "lib/index.js", "typings": "dist/api-extractor-test-02.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@types/semver": "5.3.33", - "api-extractor-test-01": "1.0.0", - "semver": "~5.3.0" + "@types/long": "4.0.0", + "@types/semver": "7.5.0", + "api-extractor-test-01": "workspace:*", + "semver": "~7.5.4" }, "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@types/node": "10.17.13", - "fs-extra": "~7.0.1", - "typescript": "~3.7.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/RenamedReexportedClass.ts b/build-tests/api-extractor-test-02/src/RenamedReexportedClass.ts index 099c42b60a6..fbd22dcec94 100644 --- a/build-tests/api-extractor-test-02/src/RenamedReexportedClass.ts +++ b/build-tests/api-extractor-test-02/src/RenamedReexportedClass.ts @@ -2,4 +2,3 @@ // See LICENSE in the project root for license information. export { ReexportedClass as RenamedReexportedClass } from 'api-extractor-test-01'; - diff --git a/build-tests/api-extractor-test-02/src/TypeFromImportedModule.ts b/build-tests/api-extractor-test-02/src/TypeFromImportedModule.ts index 066535b759e..466c7012e36 100644 --- a/build-tests/api-extractor-test-02/src/TypeFromImportedModule.ts +++ b/build-tests/api-extractor-test-02/src/TypeFromImportedModule.ts @@ -33,5 +33,4 @@ export function importedModuleAsGenericParameter(): GenericInterface +/// /** * api-extractor-test-02 @@ -13,16 +14,10 @@ */ export { SubclassWithImport } from './SubclassWithImport'; -export * from './TypeFromImportedModule'; +export type * from './TypeFromImportedModule'; 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.config; +export * from './Ambient'; diff --git a/build-tests/api-extractor-test-02/tsconfig.json b/build-tests/api-extractor-test-02/tsconfig.json index bdd84ed39cb..a4616cb045e 100644 --- a/build-tests/api-extractor-test-02/tsconfig.json +++ b/build-tests/api-extractor-test-02/tsconfig.json @@ -1,29 +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" - }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "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/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/package.json b/build-tests/api-extractor-test-03/package.json index ac1015352b6..6583ecd3c83 100644 --- a/build-tests/api-extractor-test-03/package.json +++ b/build-tests/api-extractor-test-03/package.json @@ -4,13 +4,14 @@ "version": "1.0.0", "private": true, "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "api-extractor-test-02": "workspace:*" }, "devDependencies": { - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "api-extractor-test-02": "1.0.0", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-03/tsconfig.json b/build-tests/api-extractor-test-03/tsconfig.json index fb5d521a29c..a4616cb045e 100644 --- a/build-tests/api-extractor-test-03/tsconfig.json +++ b/build-tests/api-extractor-test-03/tsconfig.json @@ -1,30 +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" - }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "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/.gitignore b/build-tests/api-extractor-test-04/.gitignore new file mode 100644 index 00000000000..e730b77542b --- /dev/null +++ b/build-tests/api-extractor-test-04/.gitignore @@ -0,0 +1,4 @@ +# 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-04/beta-consumer/package.json b/build-tests/api-extractor-test-04/beta-consumer/package.json index f0ecf373f40..801df2c3c7a 100644 --- a/build-tests/api-extractor-test-04/beta-consumer/package.json +++ b/build-tests/api-extractor-test-04/beta-consumer/package.json @@ -3,4 +3,4 @@ "description": "Simulates consuming the \"beta\" typings generated by API Extractor for api-extractor-04", "version": "1.0.0", "private": true -} \ No newline at end of file +} 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 3008fed5e56..a2f349c815e 100644 --- a/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json +++ b/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json @@ -8,18 +8,8 @@ "declarationMap": true, "experimentalDecorators": true, "strictNullChecks": true, - "lib": [ - "es5", - "scripthost", - "es2015.collection", - "es2015.promise", - "es2015.iterable", - "dom" - ], + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable"], "outDir": "lib" }, - "include": [ - "src/**/*.ts", - "typings/tsd.d.ts" - ] -} \ No newline at end of file + "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 cfb37d95019..e4725c5edc7 100644 --- a/build-tests/api-extractor-test-04/config/api-extractor.json +++ b/build-tests/api-extractor-test-04/config/api-extractor.json @@ -4,7 +4,7 @@ "mainEntryPointFilePath": "/lib/index.d.ts", "apiReport": { - "enabled": true, + "enabled": true }, "docModel": { @@ -14,6 +14,7 @@ "dtsRollup": { "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", "betaTrimmedFilePath": "/dist/-beta.d.ts", "publicTrimmedFilePath": "/dist/-public.d.ts" }, 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 new file mode 100644 index 00000000000..fd37eb27059 --- /dev/null +++ b/build-tests/api-extractor-test-04/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"] + } + ] +} diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts new file mode 100644 index 00000000000..8e6b3a433e4 --- /dev/null +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts @@ -0,0 +1,176 @@ +/** + * api-extractor-test-04 + * + * Test scenarios for trimming alpha/beta/internal definitions from the generated *.d.ts files. + * + * @packageDocumentation + */ + +import { Lib1Interface } from 'api-extractor-lib1-test'; + +/** + * This is an alpha class. + * @alpha + */ +export declare class AlphaClass { + /** + * This is a comment + */ + undecoratedMember(): void; + /* Excluded from this release type: _internalMember */ +} + +/** + * This is a beta class + * @beta + */ +export declare class BetaClass implements BetaInterface { + /** + * This is a comment + */ + undecoratedMember(): void; + /** + * This is an alpha comment + * @alpha + */ + alphaMember(): void; + /* Excluded from this release type: _internalMember */ +} + +/** + * This is a beta interface + * @beta + */ +export declare interface BetaInterface { + /** + * This is a comment + */ + undecoratedMember(): void; + /** + * This is an alpha comment + * @alpha + */ + alphaMember(): void; + /* Excluded from this release type: _internalMember */ +} + +/** + * This is a const enum marked as \@beta + * @beta + */ +export declare const enum ConstEnum { + /** + * This member inherits its \@beta status from the parent + */ + BetaMember2 = "BetaMember2", + /** + * This member is marked as \@alpha + * @alpha + */ + AlphaMember = "AlphaMember", + /* Excluded from this release type: _InternalMember */ +} + +/** + * This is a "beta" namespace. + * @beta + */ +export declare namespace EntangledNamespace { + /** + * This is a nested namespace. + * The "beta" release tag is inherited from the parent. + */ + export namespace N2 { + /** + * This class is in a nested namespace. + * @alpha + */ + export class ClassX { + /** + * The "alpha" release tag is inherited from the parent. + */ + static a: string; + } + } + /** + * This is a nested namespace. + * The "beta" release tag is inherited from the parent. + */ + export namespace N3 { + /* Excluded from this release type: _ClassY */ + } +} + +/** + * This is an exported type alias. + * @alpha + */ +export declare type ExportedAlias = AlphaClass; + +/* Excluded from this release type: InternalClass */ + +/* Excluded from this release type: IPublicClassInternalParameters */ + +/** + * This is a public class + * @public + */ +export declare interface IPublicComplexInterface { + /* Excluded from this release type: __index */ + /* Excluded from this release type: __new */ +} + +export { Lib1Interface } + +/** + * This is a public class + * @public + */ +export declare class PublicClass { + /* Excluded from this release type: __constructor */ + /** + * This is a beta field + * @beta + */ + betaField: string; + /** + * This is a comment + */ + undecoratedMember(): void; + /** + * This is a beta comment + * @beta + */ + betaMember(): void; + /** + * This is an alpha comment + * @alpha + */ + alphaMember(): void; + /* Excluded from this release type: _internalMember */ +} + +/** + * This is a regular enum marked as \@beta + * @beta + */ +export declare enum RegularEnum { + /** + * This member inherits its \@beta status from the parent + */ + BetaMember = 100, + /** + * This member is marked as \@alpha + * @alpha + */ + AlphaMember = 101, + /* Excluded from this release type: _InternalMember */ +} + +/** + * This is a module-scoped variable. + * @beta + */ +export declare const variableDeclaration: string; + +export { } diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts index 6ab13f957e3..449c8aedea6 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts @@ -6,6 +6,7 @@ * @packageDocumentation */ +import { Lib1Interface } from 'api-extractor-lib1-test'; /* Excluded from this release type: AlphaClass */ diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-public.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-public.d.ts index b5f0587b78d..3f31586f792 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-public.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-public.d.ts @@ -6,6 +6,7 @@ * @packageDocumentation */ +import { Lib1Interface } from 'api-extractor-lib1-test'; /* Excluded from this release type: AlphaClass */ diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts index 82e164a1b0b..5accf4e7216 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts @@ -170,6 +170,7 @@ export declare interface IPublicComplexInterface { */ new (): any; } + export { Lib1Interface } /** diff --git a/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md b/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md index 1e0c766263e..b6f80fc8894 100644 --- a/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md +++ b/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md @@ -61,14 +61,14 @@ export namespace EntangledNamespace { export type ExportedAlias = AlphaClass; // Warning: (ae-internal-missing-underscore) The name "InternalClass" should be prefixed with an underscore because the declaration is marked as @internal -// +// // @internal export class InternalClass { undecoratedMember(): void; } // Warning: (ae-internal-missing-underscore) The name "IPublicClassInternalParameters" should be prefixed with an underscore because the declaration is marked as @internal -// +// // @internal export interface IPublicClassInternalParameters { } @@ -110,5 +110,4 @@ export enum RegularEnum { // @beta export const variableDeclaration: string; - ``` diff --git a/build-tests/api-extractor-test-04/package.json b/build-tests/api-extractor-test-04/package.json index 561ad424e65..958a44833c9 100644 --- a/build-tests/api-extractor-test-04/package.json +++ b/build-tests/api-extractor-test-04/package.json @@ -6,12 +6,14 @@ "main": "lib/index.js", "typings": "dist/api-extractor-test-04.d.ts", "scripts": { - "build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@microsoft/api-extractor": "7.7.10", - "api-extractor-lib1-test": "1.0.0", - "fs-extra": "~7.0.1", - "typescript": "~3.7.2" + "api-extractor-lib1-test": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-04/src/AlphaClass.ts b/build-tests/api-extractor-test-04/src/AlphaClass.ts index a762f97e5c4..3166c1240dc 100644 --- a/build-tests/api-extractor-test-04/src/AlphaClass.ts +++ b/build-tests/api-extractor-test-04/src/AlphaClass.ts @@ -9,13 +9,11 @@ export class AlphaClass { /** * This is a comment */ - public undecoratedMember(): void { - } + public undecoratedMember(): void {} /** * This is an internal member * @internal */ - public _internalMember(): void { - } + public _internalMember(): void {} } diff --git a/build-tests/api-extractor-test-04/src/BetaClass.ts b/build-tests/api-extractor-test-04/src/BetaClass.ts index 3a068b0b43c..2a8251ec1a1 100644 --- a/build-tests/api-extractor-test-04/src/BetaClass.ts +++ b/build-tests/api-extractor-test-04/src/BetaClass.ts @@ -11,20 +11,17 @@ export class BetaClass implements BetaInterface { /** * This is a comment */ - public undecoratedMember(): void { - } + public undecoratedMember(): void {} /** * This is an alpha comment * @alpha */ - public alphaMember(): void { - } + public alphaMember(): void {} /** * This is an internal member * @internal */ - public _internalMember(): void { - } + public _internalMember(): void {} } diff --git a/build-tests/api-extractor-test-04/src/EntangledNamespace.ts b/build-tests/api-extractor-test-04/src/EntangledNamespace.ts index f73a70a6fc5..8f7b3cd5fbe 100644 --- a/build-tests/api-extractor-test-04/src/EntangledNamespace.ts +++ b/build-tests/api-extractor-test-04/src/EntangledNamespace.ts @@ -6,13 +6,11 @@ * @beta */ export namespace EntangledNamespace { - /** * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ export namespace N2 { - /** * This class is in a nested namespace. * @alpha diff --git a/build-tests/api-extractor-test-04/src/IPublicComplexInterface.ts b/build-tests/api-extractor-test-04/src/IPublicComplexInterface.ts index dcd9b70d6ee..7c689feebe5 100644 --- a/build-tests/api-extractor-test-04/src/IPublicComplexInterface.ts +++ b/build-tests/api-extractor-test-04/src/IPublicComplexInterface.ts @@ -18,5 +18,5 @@ export interface IPublicComplexInterface { * Example of trimming a construct signature. * @internal */ - new(); + new (); } diff --git a/build-tests/api-extractor-test-04/src/InternalClass.ts b/build-tests/api-extractor-test-04/src/InternalClass.ts index 00480567960..8bed22c51c1 100644 --- a/build-tests/api-extractor-test-04/src/InternalClass.ts +++ b/build-tests/api-extractor-test-04/src/InternalClass.ts @@ -9,6 +9,5 @@ export class InternalClass { /** * This is a comment */ - public undecoratedMember(): void { - } + public undecoratedMember(): void {} } diff --git a/build-tests/api-extractor-test-04/src/PublicClass.ts b/build-tests/api-extractor-test-04/src/PublicClass.ts index ce66004aef3..d2adf4d8d05 100644 --- a/build-tests/api-extractor-test-04/src/PublicClass.ts +++ b/build-tests/api-extractor-test-04/src/PublicClass.ts @@ -5,8 +5,7 @@ * These are internal constructor parameters for PublicClass's internal constructor. * @internal */ -export interface IPublicClassInternalParameters { -} +export interface IPublicClassInternalParameters {} /** * This is a public class @@ -14,8 +13,7 @@ export interface IPublicClassInternalParameters { */ export class PublicClass { /** @internal */ - constructor(parameters: IPublicClassInternalParameters) { - } + constructor(parameters: IPublicClassInternalParameters) {} /** * This is a beta field @@ -26,27 +24,23 @@ export class PublicClass { /** * This is a comment */ - public undecoratedMember(): void { - } + public undecoratedMember(): void {} /** * This is a beta comment * @beta */ - public betaMember(): void { - } + public betaMember(): void {} /** * This is an alpha comment * @alpha */ - public alphaMember(): void { - } + public alphaMember(): void {} /** * This is an internal member * @internal */ - public _internalMember(): void { - } + public _internalMember(): void {} } 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 f6c01bb8017..86dcc8c8f9e 100644 --- a/build-tests/api-extractor-test-04/tsconfig.json +++ b/build-tests/api-extractor-test-04/tsconfig.json @@ -1,28 +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" - ] -} \ No newline at end of file + "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..770ab0ff8a0 --- /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/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..fd37eb27059 --- /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"] + } + ] +} 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..7690bff4320 --- /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.54.0" + } + ] +} 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..4d707186e5f --- /dev/null +++ b/build-tests/api-extractor-test-05/package.json @@ -0,0 +1,16 @@ +{ + "name": "api-extractor-test-05", + "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-05.d.ts", + "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 new file mode 100644 index 00000000000..00f91351897 --- /dev/null +++ b/build-tests/eslint-7-11-test/.eslintrc.js @@ -0,0 +1,27 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + parserOptions: { tsconfigRootDir: __dirname }, + + overrides: [ + /** + * Override the parser from local-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-7-test package. Overriding the parser + * ensures that the these dependencies come from the eslint-7-test package. See: + * https://github.com/microsoft/rushstack/issues/3021 + */ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser' + } + ] +}; diff --git a/build-tests/eslint-7-11-test/README.md b/build-tests/eslint-7-11-test/README.md new file mode 100644 index 00000000000..7e236873623 --- /dev/null +++ b/build-tests/eslint-7-11-test/README.md @@ -0,0 +1,6 @@ +# eslint-7-11-test + +This project folder is one of the **build-tests** for the Rushstack [ESLint configuration](https://www.npmjs.com/package/@rushstack/eslint-config) (and by extension, the [ESLint plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin)) +package. This project builds using ESLint v7.11.0 and contains a simple index file to ensure that the build runs ESLint successfully against source code. + +Please see the [ESLint Heft task documentation](https://rushstack.io/pages/heft_tasks/eslint/) for documentation and tutorials. 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/config/rig.json b/build-tests/eslint-7-11-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-7-11-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-7-11-test/package.json b/build-tests/eslint-7-11-test/package.json new file mode 100644 index 00000000000..b1e1cae39cc --- /dev/null +++ b/build-tests/eslint-7-11-test/package.json @@ -0,0 +1,21 @@ +{ + "name": "eslint-7-11-test", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "3.7.1", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~6.19.0", + "eslint": "7.11.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-7-11-test/src/index.ts b/build-tests/eslint-7-11-test/src/index.ts new file mode 100644 index 00000000000..428f8caba4f --- /dev/null +++ b/build-tests/eslint-7-11-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. + +export class Foo { + private _bar: string = 'bar'; + public baz: string = this._bar; +} diff --git a/build-tests/eslint-7-11-test/tsconfig.json b/build-tests/eslint-7-11-test/tsconfig.json new file mode 100644 index 00000000000..8a46ac2445e --- /dev/null +++ b/build-tests/eslint-7-11-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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"] +} diff --git a/build-tests/eslint-7-7-test/.eslintrc.js b/build-tests/eslint-7-7-test/.eslintrc.js new file mode 100644 index 00000000000..00f91351897 --- /dev/null +++ b/build-tests/eslint-7-7-test/.eslintrc.js @@ -0,0 +1,27 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + parserOptions: { tsconfigRootDir: __dirname }, + + overrides: [ + /** + * Override the parser from local-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-7-test package. Overriding the parser + * ensures that the these dependencies come from the eslint-7-test package. See: + * https://github.com/microsoft/rushstack/issues/3021 + */ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser' + } + ] +}; diff --git a/build-tests/eslint-7-7-test/README.md b/build-tests/eslint-7-7-test/README.md new file mode 100644 index 00000000000..6002dff592a --- /dev/null +++ b/build-tests/eslint-7-7-test/README.md @@ -0,0 +1,6 @@ +# eslint-7-7-test + +This project folder is one of the **build-tests** for the Rushstack [ESLint configuration](https://www.npmjs.com/package/@rushstack/eslint-config) (and by extension, the [ESLint plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin)) +package. This project builds using ESLint v7.7.0 and contains a simple index file to ensure that the build runs ESLint successfully against source code. + +Please see the [ESLint Heft task documentation](https://rushstack.io/pages/heft_tasks/eslint/) for documentation and tutorials. 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/config/rig.json b/build-tests/eslint-7-7-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-7-7-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-7-7-test/package.json b/build-tests/eslint-7-7-test/package.json new file mode 100644 index 00000000000..8161d5edf79 --- /dev/null +++ b/build-tests/eslint-7-7-test/package.json @@ -0,0 +1,21 @@ +{ + "name": "eslint-7-7-test", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "3.7.1", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~6.19.0", + "eslint": "7.7.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-7-7-test/src/index.ts b/build-tests/eslint-7-7-test/src/index.ts new file mode 100644 index 00000000000..428f8caba4f --- /dev/null +++ b/build-tests/eslint-7-7-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. + +export class Foo { + private _bar: string = 'bar'; + public baz: string = this._bar; +} diff --git a/build-tests/eslint-7-7-test/tsconfig.json b/build-tests/eslint-7-7-test/tsconfig.json new file mode 100644 index 00000000000..8a46ac2445e --- /dev/null +++ b/build-tests/eslint-7-7-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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"] +} diff --git a/build-tests/eslint-7-test/.eslintrc.js b/build-tests/eslint-7-test/.eslintrc.js new file mode 100644 index 00000000000..00f91351897 --- /dev/null +++ b/build-tests/eslint-7-test/.eslintrc.js @@ -0,0 +1,27 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + parserOptions: { tsconfigRootDir: __dirname }, + + overrides: [ + /** + * Override the parser from local-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-7-test package. Overriding the parser + * ensures that the these dependencies come from the eslint-7-test package. See: + * https://github.com/microsoft/rushstack/issues/3021 + */ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser' + } + ] +}; diff --git a/build-tests/eslint-7-test/README.md b/build-tests/eslint-7-test/README.md new file mode 100644 index 00000000000..f4d85f1fdb3 --- /dev/null +++ b/build-tests/eslint-7-test/README.md @@ -0,0 +1,6 @@ +# eslint-7-test + +This project folder is one of the **build-tests** for the Rushstack [ESLint configuration](https://www.npmjs.com/package/@rushstack/eslint-config) (and by extension, the [ESLint plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin)) +package. This project builds using ESLint v7 and contains a simple index file to ensure that the build runs ESLint successfully against source code. + +Please see the [ESLint Heft task documentation](https://rushstack.io/pages/heft_tasks/eslint/) for documentation and tutorials. diff --git a/build-tests/eslint-7-test/config/rig.json b/build-tests/eslint-7-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-7-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-7-test/package.json b/build-tests/eslint-7-test/package.json new file mode 100644 index 00000000000..4c84f0ed5a6 --- /dev/null +++ b/build-tests/eslint-7-test/package.json @@ -0,0 +1,21 @@ +{ + "name": "eslint-7-test", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "3.7.1", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~6.19.0", + "eslint": "~7.30.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-7-test/src/index.ts b/build-tests/eslint-7-test/src/index.ts new file mode 100644 index 00000000000..428f8caba4f --- /dev/null +++ b/build-tests/eslint-7-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. + +export class Foo { + private _bar: string = 'bar'; + public baz: string = this._bar; +} diff --git a/build-tests/eslint-7-test/tsconfig.json b/build-tests/eslint-7-test/tsconfig.json new file mode 100644 index 00000000000..8a46ac2445e --- /dev/null +++ b/build-tests/eslint-7-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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"] +} diff --git a/build-tests/eslint-8-test/.eslintrc.js b/build-tests/eslint-8-test/.eslintrc.js new file mode 100644 index 00000000000..177da749b07 --- /dev/null +++ b/build-tests/eslint-8-test/.eslintrc.js @@ -0,0 +1,27 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + parserOptions: { tsconfigRootDir: __dirname }, + + overrides: [ + /** + * 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 + */ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser' + } + ] +}; diff --git a/build-tests/eslint-8-test/README.md b/build-tests/eslint-8-test/README.md new file mode 100644 index 00000000000..f4d85f1fdb3 --- /dev/null +++ b/build-tests/eslint-8-test/README.md @@ -0,0 +1,6 @@ +# eslint-7-test + +This project folder is one of the **build-tests** for the Rushstack [ESLint configuration](https://www.npmjs.com/package/@rushstack/eslint-config) (and by extension, the [ESLint plugin](https://www.npmjs.com/package/@rushstack/eslint-plugin)) +package. This project builds using ESLint v7 and contains a simple index file to ensure that the build runs ESLint successfully against source code. + +Please see the [ESLint Heft task documentation](https://rushstack.io/pages/heft_tasks/eslint/) for documentation and tutorials. diff --git a/build-tests/eslint-8-test/config/rig.json b/build-tests/eslint-8-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-8-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-8-test/package.json b/build-tests/eslint-8-test/package.json new file mode 100644 index 00000000000..650b4e7e595 --- /dev/null +++ b/build-tests/eslint-8-test/package.json @@ -0,0 +1,21 @@ +{ + "name": "eslint-8-test", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/eslint-config": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~8.46.0", + "eslint": "~8.57.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-8-test/src/index.ts b/build-tests/eslint-8-test/src/index.ts new file mode 100644 index 00000000000..428f8caba4f --- /dev/null +++ b/build-tests/eslint-8-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. + +export class Foo { + private _bar: string = 'bar'; + public baz: string = this._bar; +} diff --git a/build-tests/eslint-8-test/tsconfig.json b/build-tests/eslint-8-test/tsconfig.json new file mode 100644 index 00000000000..8a46ac2445e --- /dev/null +++ b/build-tests/eslint-8-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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"] +} 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..3a6a4b66879 --- /dev/null +++ b/build-tests/eslint-9-test/package.json @@ -0,0 +1,21 @@ +{ + "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/index.js", + "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.46.0", + "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..4dd9678af58 --- /dev/null +++ b/build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap @@ -0,0 +1,111 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..c1e9cd2dd92 --- /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/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/package.json b/build-tests/eslint-bulk-suppressions-test-flat/package.json new file mode 100644 index 00000000000..2c36ddfe4d9 --- /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.46.0", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/server/.eslint-bulk-suppressions-9.37.0.json b/build-tests/eslint-bulk-suppressions-test-flat/server/.eslint-bulk-suppressions-9.37.0.json new file mode 100644 index 00000000000..5d0e82b5147 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/server/.eslint-bulk-suppressions-9.37.0.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-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..174bda15d5c --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/tsconfig.json @@ -0,0 +1,23 @@ +{ + "$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": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/build.js b/build-tests/eslint-bulk-suppressions-test-legacy/build.js new file mode 100644 index 00000000000..00f8fba506c --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/build.js @@ -0,0 +1,107 @@ +// This project is a duplicate of "eslint-bulk-suppressions-test" 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" 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/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', 'eslint-8.23', 'eslint-oldest']; + +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-legacy/client/.eslint-bulk-suppressions-8.23.1.json b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.23.1.json new file mode 100644 index 00000000000..40059c12365 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.23.1.json @@ -0,0 +1,139 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "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/ban-types" + }, + { + "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": ".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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "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-legacy/client/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.0.json new file mode 100644 index 00000000000..40059c12365 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.0.json @@ -0,0 +1,139 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "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/ban-types" + }, + { + "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": ".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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "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-legacy/client/.eslint-bulk-suppressions-8.6.0.json b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.6.0.json new file mode 100644 index 00000000000..40059c12365 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.6.0.json @@ -0,0 +1,139 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "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/ban-types" + }, + { + "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": ".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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "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-legacy/client/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js new file mode 100644 index 00000000000..4cc74b0570a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js @@ -0,0 +1,28 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +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: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + ignorePatterns: ['.eslintrc.js'], + + overrides: [ + /** + * 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 + */ + { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { project: '../tsconfig.json', tsconfigRootDir: __dirname } + } + ] +}; diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/client/src/index.ts b/build-tests/eslint-bulk-suppressions-test-legacy/client/src/index.ts new file mode 100644 index 00000000000..570229800d8 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/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-legacy/config/rig.json b/build-tests/eslint-bulk-suppressions-test-legacy/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/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-legacy/package.json b/build-tests/eslint-bulk-suppressions-test-legacy/package.json new file mode 100644 index 00000000000..d2826697e1e --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/package.json @@ -0,0 +1,22 @@ +{ + "name": "eslint-bulk-suppressions-test-legacy", + "description": "Sample code to test eslint bulk suppressions for versions of eslint < 8.57.0", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "node build.js" + }, + "devDependencies": { + "@rushstack/eslint-bulk": "workspace:*", + "@rushstack/eslint-config": "3.7.1", + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@typescript-eslint/parser": "~8.46.0", + "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.8.2" + } +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.23.1.json b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.23.1.json new file mode 100644 index 00000000000..ab3846d907a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.23.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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleObjectType", + "rule": "@typescript-eslint/consistent-type-definitions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject2", + "rule": "@typescript-eslint/typedef" + } + ] +} 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.0.json new file mode 100644 index 00000000000..ab3846d907a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.57.0.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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleObjectType", + "rule": "@typescript-eslint/consistent-type-definitions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject2", + "rule": "@typescript-eslint/typedef" + } + ] +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.6.0.json b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.6.0.json new file mode 100644 index 00000000000..ab3846d907a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.6.0.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/ban-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleObjectType", + "rule": "@typescript-eslint/consistent-type-definitions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject2", + "rule": "@typescript-eslint/typedef" + } + ] +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js new file mode 100644 index 00000000000..4cc74b0570a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js @@ -0,0 +1,28 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +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: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + ignorePatterns: ['.eslintrc.js'], + + overrides: [ + /** + * 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 + */ + { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { project: '../tsconfig.json', tsconfigRootDir: __dirname } + } + ] +}; diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/src/index.ts b/build-tests/eslint-bulk-suppressions-test-legacy/server/src/index.ts new file mode 100644 index 00000000000..34328698008 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/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-legacy/tsconfig.json b/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json new file mode 100644 index 00000000000..174bda15d5c --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json @@ -0,0 +1,23 @@ +{ + "$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": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/eslint-bulk-suppressions-test/build.js b/build-tests/eslint-bulk-suppressions-test/build.js new file mode 100644 index 00000000000..c1e9cd2dd92 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/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/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/client/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.0.json new file mode 100644 index 00000000000..8852d8bc68f --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.0.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 new file mode 100644 index 00000000000..3d3ed2f7929 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/client/.eslintrc.js @@ -0,0 +1,29 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + ignorePatterns: ['.eslintrc.js'], + + overrides: [ + /** + * 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 + */ + { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { project: '../tsconfig.json', tsconfigRootDir: __dirname } + } + ] +}; diff --git a/build-tests/eslint-bulk-suppressions-test/client/src/index.ts b/build-tests/eslint-bulk-suppressions-test/client/src/index.ts new file mode 100644 index 00000000000..570229800d8 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/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/config/rig.json b/build-tests/eslint-bulk-suppressions-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-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-bulk-suppressions-test/package.json b/build-tests/eslint-bulk-suppressions-test/package.json new file mode 100644 index 00000000000..554d9653b9a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/package.json @@ -0,0 +1,20 @@ +{ + "name": "eslint-bulk-suppressions-test", + "description": "Sample code to test eslint bulk suppressions", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "node build.js" + }, + "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.46.0", + "eslint": "~8.57.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/server/.eslint-bulk-suppressions-8.57.0.json new file mode 100644 index 00000000000..5d0e82b5147 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.0.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 new file mode 100644 index 00000000000..3d3ed2f7929 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/server/.eslintrc.js @@ -0,0 +1,29 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); + +module.exports = { + extends: [ + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' + ], + ignorePatterns: ['.eslintrc.js'], + + overrides: [ + /** + * 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 + */ + { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { project: '../tsconfig.json', tsconfigRootDir: __dirname } + } + ] +}; diff --git a/build-tests/eslint-bulk-suppressions-test/server/src/index.ts b/build-tests/eslint-bulk-suppressions-test/server/src/index.ts new file mode 100644 index 00000000000..34328698008 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/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/tsconfig.json b/build-tests/eslint-bulk-suppressions-test/tsconfig.json new file mode 100644 index 00000000000..174bda15d5c --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/tsconfig.json @@ -0,0 +1,23 @@ +{ + "$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": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/.gitignore b/build-tests/hashed-folder-copy-plugin-webpack5-test/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/blue.png b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/blue.png new file mode 100644 index 00000000000..d9119489cb1 Binary files /dev/null and b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/blue.png differ diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/green.png b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/green.png new file mode 100644 index 00000000000..8ba4f25579b Binary files /dev/null and b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/green.png differ diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/red.png b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/red.png new file mode 100644 index 00000000000..b4e46a0538a Binary files /dev/null and b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/red.png differ diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/subfolder/yellow.png b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/subfolder/yellow.png new file mode 100644 index 00000000000..df897b6e041 Binary files /dev/null and b/build-tests/hashed-folder-copy-plugin-webpack5-test/assets/subfolder/yellow.png differ diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/config/heft.json b/build-tests/hashed-folder-copy-plugin-webpack5-test/config/heft.json new file mode 100644 index 00000000000..09e8cc23d23 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/config/heft.json @@ -0,0 +1,35 @@ +/** + * 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-dev", "dist-prod", "lib"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + + "webpack5": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..543278bebd4 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-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", "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 new file mode 100644 index 00000000000..8741952cecc --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/package.json @@ -0,0 +1,23 @@ +{ + "name": "hashed-folder-copy-plugin-webpack5-test", + "description": "Building this project exercises @rushstack/hashed-folder-copy-plugin with Webpack 5. NOTE - THIS TEST IS CURRENTLY EXPECTED TO BE BROKEN", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "serve": "heft build-watch --serve", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/hashed-folder-copy-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@types/webpack-env": "1.18.8", + "html-webpack-plugin": "~5.5.0", + "typescript": "~5.8.2", + "webpack-bundle-analyzer": "~4.5.0", + "webpack": "~5.98.0" + } +} diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/src/index.ts b/build-tests/hashed-folder-copy-plugin-webpack5-test/src/index.ts new file mode 100644 index 00000000000..72f4cd93c96 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/src/index.ts @@ -0,0 +1,39 @@ +import { ASSETS_BASE_URL2 } from './submodule'; + +const ASSETS_BASE_URL: string = requireFolder({ + outputFolder: 'assets_[hash]', + sources: [ + { + globsBase: '../assets', + globPatterns: ['**/*'] + } + ] +}); + +const HEFT_SRC_FILES_BASE_URL: string = requireFolder({ + outputFolder: 'heft_src_files_[hash]', + sources: [ + { + globsBase: '@rushstack/heft/src', + globPatterns: ['**/*'] + } + ] +}); + +function appendImageToBody(url: string): void { + const image: HTMLImageElement = document.createElement('img'); + image.src = url; + document.body.appendChild(image); +} + +appendImageToBody(`${ASSETS_BASE_URL}/red.png`); +appendImageToBody(`${ASSETS_BASE_URL}/green.png`); +appendImageToBody(`${ASSETS_BASE_URL}/blue.png`); +appendImageToBody(`${ASSETS_BASE_URL}/subfolder/yellow.png`); + +appendImageToBody(`${ASSETS_BASE_URL2}/red.png`); +appendImageToBody(`${ASSETS_BASE_URL2}/green.png`); +appendImageToBody(`${ASSETS_BASE_URL2}/blue.png`); +appendImageToBody(`${ASSETS_BASE_URL2}/subfolder/yellow.png`); + +console.log(HEFT_SRC_FILES_BASE_URL); diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/src/submodule.ts b/build-tests/hashed-folder-copy-plugin-webpack5-test/src/submodule.ts new file mode 100644 index 00000000000..d9a6e6fa8b0 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/src/submodule.ts @@ -0,0 +1,9 @@ +export const ASSETS_BASE_URL2: string = requireFolder({ + outputFolder: 'assets2_[hash]', + sources: [ + { + globsBase: '../assets', + globPatterns: ['**/*'] + } + ] +}); diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json b/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json new file mode 100644 index 00000000000..0c287924501 --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json @@ -0,0 +1,23 @@ +{ + "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", "@rushstack/hashed-folder-copy-plugin/ambientTypes"], + + "outDir": "lib", + "rootDir": "src", + "rootDirs": ["src", "temp/loc-json-ts"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} 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 new file mode 100644 index 00000000000..ebce51bfc9b --- /dev/null +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/webpack.config.js @@ -0,0 +1,40 @@ +'use strict'; + +const path = require('path'); +const webpack = require('webpack'); + +const { HashedFolderCopyPlugin } = require('@rushstack/hashed-folder-copy-plugin'); +const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +function generateConfiguration(mode, outputFolderName) { + return { + mode: mode, + entry: { + test: path.join(__dirname, 'lib', 'index.js') + }, + output: { + path: path.join(__dirname, outputFolderName), + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js' + }, + plugins: [ + new webpack.optimize.ModuleConcatenationPlugin(), + new HashedFolderCopyPlugin(), + new BundleAnalyzerPlugin({ + openAnalyzer: false, + analyzerMode: 'static', + reportFilename: path.resolve(__dirname, 'temp', 'stats.html'), + generateStatsFile: true, + statsFilename: path.resolve(__dirname, 'temp', 'stats.json'), + logLevel: 'error' + }), + new HtmlWebpackPlugin() + ] + }; +} + +module.exports = [ + generateConfiguration('development', 'dist-dev'), + generateConfiguration('production', 'dist-prod') +]; diff --git a/build-tests/heft-copy-files-test/.gitignore b/build-tests/heft-copy-files-test/.gitignore new file mode 100644 index 00000000000..cadca90b0c7 --- /dev/null +++ b/build-tests/heft-copy-files-test/.gitignore @@ -0,0 +1 @@ +out-* diff --git a/build-tests/heft-copy-files-test/config/heft.json b/build-tests/heft-copy-files-test/config/heft.json new file mode 100644 index 00000000000..de160bcccda --- /dev/null +++ b/build-tests/heft-copy-files-test/config/heft.json @@ -0,0 +1,71 @@ +/** + * 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": [ + "out-all", + "out-all-linked", + "out-all-flattened", + "out-all-except-for-images", + "out-images1", + "out-images2", + "out-images3", + "out-images4", + "out-images5" + ] + } + ], + + "tasksByName": { + "perform-copy": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src", + "destinationFolders": ["out-all"] + }, + { + "sourcePath": "src", + "destinationFolders": ["out-all-linked"], + "hardlink": true + }, + { + "sourcePath": "src", + "destinationFolders": ["out-images-flattened"], + "fileExtensions": [".jpg", ".png"], + "flatten": true + }, + { + "sourcePath": "src", + "destinationFolders": ["out-all-except-for-images"], + "excludeGlobs": ["**/*.png", "**/*.jpg"] + }, + { + "sourcePath": "src", + "destinationFolders": [ + "out-images1", + "out-images2", + "out-images3", + "out-images4", + "out-images5" + ], + "fileExtensions": [".jpg", ".png"] + } + ] + } + } + } + } + } + } +} diff --git a/build-tests/heft-copy-files-test/config/rush-project.json b/build-tests/heft-copy-files-test/config/rush-project.json new file mode 100644 index 00000000000..e3df32c4de7 --- /dev/null +++ b/build-tests/heft-copy-files-test/config/rush-project.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:lite-build", + "outputFolderNames": [ + "out-all", + "out-all-except-for-images", + "out-all-linked", + "out-images-flattened", + "out-images1", + "out-images2", + "out-images3", + "out-images4", + "out-images5", + "temp/build" + ] + } + ] +} diff --git a/build-tests/heft-copy-files-test/package.json b/build-tests/heft-copy-files-test/package.json new file mode 100644 index 00000000000..5ef07daffea --- /dev/null +++ b/build-tests/heft-copy-files-test/package.json @@ -0,0 +1,14 @@ +{ + "name": "heft-copy-files-test", + "description": "Building this project tests copying files with Heft", + "version": "1.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:lite-build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*" + } +} diff --git a/build-tests/heft-copy-files-test/src/A/AA/aa1.txt b/build-tests/heft-copy-files-test/src/A/AA/aa1.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/A/a1.txt b/build-tests/heft-copy-files-test/src/A/a1.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/A/a2.txt b/build-tests/heft-copy-files-test/src/A/a2.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/A/a3.png b/build-tests/heft-copy-files-test/src/A/a3.png new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/A/a4.jpg b/build-tests/heft-copy-files-test/src/A/a4.jpg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/B/BB/bb1.txt b/build-tests/heft-copy-files-test/src/B/BB/bb1.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/B/b1.txt b/build-tests/heft-copy-files-test/src/B/b1.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/B/b2.txt b/build-tests/heft-copy-files-test/src/B/b2.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/B/b3.png b/build-tests/heft-copy-files-test/src/B/b3.png new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/heft-copy-files-test/src/B/b4.jpg b/build-tests/heft-copy-files-test/src/B/b4.jpg new file mode 100644 index 00000000000..e69de29bb2d 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..514e557d5eb --- /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", "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..d174b5b769b --- /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/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..996b1d27713 --- /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/index.js", + "typings": "./lib/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..2d179c7173f --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-example-plugin-01/config/heft.json b/build-tests/heft-example-plugin-01/config/heft.json new file mode 100644 index 00000000000..64d969be2eb --- /dev/null +++ b/build-tests/heft-example-plugin-01/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-plugin-01/config/rush-project.json b/build-tests/heft-example-plugin-01/config/rush-project.json new file mode 100644 index 00000000000..514e557d5eb --- /dev/null +++ b/build-tests/heft-example-plugin-01/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", "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 new file mode 100644 index 00000000000..09a64ae81ad --- /dev/null +++ b/build-tests/heft-example-plugin-01/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "example-plugin-01", + "entryPoint": "./lib/index" + } + ] +} diff --git a/build-tests/heft-example-plugin-01/package.json b/build-tests/heft-example-plugin-01/package.json new file mode 100644 index 00000000000..a635fd41233 --- /dev/null +++ b/build-tests/heft-example-plugin-01/package.json @@ -0,0 +1,26 @@ +{ + "name": "heft-example-plugin-01", + "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", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "tapable": "1.1.3" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/node": "20.17.19", + "@types/tapable": "1.0.6", + "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 new file mode 100644 index 00000000000..8bc385908fa --- /dev/null +++ b/build-tests/heft-example-plugin-01/src/index.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { SyncHook } from 'tapable'; + +import type { + IHeftTaskPlugin, + IHeftTaskSession, + HeftConfiguration, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; + +export interface IExamplePlugin01Accessor { + exampleHook: SyncHook; +} + +export const PLUGIN_NAME: 'example-plugin-01' = 'example-plugin-01'; + +export default class ExamplePlugin01 implements IHeftTaskPlugin { + private _accessor: IExamplePlugin01Accessor = { + exampleHook: new SyncHook() + }; + + public get accessor(): IExamplePlugin01Accessor { + return this._accessor; + } + + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (build: IHeftTaskRunHookOptions) => { + this.accessor.exampleHook.call(); + }); + } +} diff --git a/build-tests/heft-example-plugin-01/tsconfig.json b/build-tests/heft-example-plugin-01/tsconfig.json new file mode 100644 index 00000000000..2d179c7173f --- /dev/null +++ b/build-tests/heft-example-plugin-01/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-example-plugin-02/config/heft.json b/build-tests/heft-example-plugin-02/config/heft.json new file mode 100644 index 00000000000..64d969be2eb --- /dev/null +++ b/build-tests/heft-example-plugin-02/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-plugin-02/config/rush-project.json b/build-tests/heft-example-plugin-02/config/rush-project.json new file mode 100644 index 00000000000..514e557d5eb --- /dev/null +++ b/build-tests/heft-example-plugin-02/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", "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 new file mode 100644 index 00000000000..28dfc61a402 --- /dev/null +++ b/build-tests/heft-example-plugin-02/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "example-plugin-02", + "entryPoint": "./lib/index" + } + ] +} diff --git a/build-tests/heft-example-plugin-02/package.json b/build-tests/heft-example-plugin-02/package.json new file mode 100644 index 00000000000..1d7f1b56bfa --- /dev/null +++ b/build-tests/heft-example-plugin-02/package.json @@ -0,0 +1,31 @@ +{ + "name": "heft-example-plugin-02", + "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", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean" + }, + "peerDependencies": { + "heft-example-plugin-01": "workspace:*" + }, + "peerDependenciesMeta": { + "heft-example-plugin-01": { + "optional": true + } + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "heft-example-plugin-01": "workspace:*", + "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 new file mode 100644 index 00000000000..d1382dd8527 --- /dev/null +++ b/build-tests/heft-example-plugin-02/src/index.ts @@ -0,0 +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 { 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'; + +export default class ExamplePlugin02 implements IHeftTaskPlugin { + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + taskSession.requestAccessToPluginByName( + 'heft-example-plugin-01', + EXAMPLE_PLUGIN_01_NAME, + (accessor: IExamplePlugin01Accessor) => { + accessor.exampleHook.tap(PLUGIN_NAME, () => { + taskSession.logger.terminal.writeLine( + `!!!!!!!!!!!!!!! Plugin "${EXAMPLE_PLUGIN_01_NAME}" hook called !!!!!!!!!!!!!!! ` + ); + }); + } + ); + } +} diff --git a/build-tests/heft-example-plugin-02/tsconfig.json b/build-tests/heft-example-plugin-02/tsconfig.json new file mode 100644 index 00000000000..2d179c7173f --- /dev/null +++ b/build-tests/heft-example-plugin-02/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-fastify-test/README.md b/build-tests/heft-fastify-test/README.md new file mode 100644 index 00000000000..f9eaf392cdb --- /dev/null +++ b/build-tests/heft-fastify-test/README.md @@ -0,0 +1,3 @@ +# heft-fastify-test + +This project tests Heft support for the [Fastify](https://www.fastify.io/) framework for Node.js services. diff --git a/build-tests/heft-fastify-test/config/heft.json b/build-tests/heft-fastify-test/config/heft.json new file mode 100644 index 00000000000..d77d65a9b32 --- /dev/null +++ b/build-tests/heft-fastify-test/config/heft.json @@ -0,0 +1,34 @@ +/** + * 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"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "node-service": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "node-service-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-fastify-test/config/node-service.json b/build-tests/heft-fastify-test/config/node-service.json new file mode 100644 index 00000000000..62e904d49ce --- /dev/null +++ b/build-tests/heft-fastify-test/config/node-service.json @@ -0,0 +1,48 @@ +/** + * Configures "heft start" to launch a shell command such as a Node.js service. + * Heft will watch for changes and restart the service process whenever it gets rebuilt. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/node-service.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": "base-project/config/serve-command.json", + + /** + * Specifies the name of a "scripts" command from the project's package.json file. + * When "heft start" is invoked, it will use this shell command to launch the + * service process. + * + * Default value: "serve" + */ + // "commandName": "serve", + + /** + * If true, then an error is reported if the "scripts" command is not found in the + * project's package.json. If false, then no action will be taken. + * + * Default value: false + */ + // "ignoreMissingScript": false, + + /** + * Customizes the number of milliseconds to wait for the child process to be terminated (SIGTERM) + * before forcibly killing it. + * + * Default value: 2000 + */ + // "waitForTerminateMs": 2000, + + /** + * Customizes the number of milliseconds to wait for the child process to be killed (SIGKILL) + * before giving up and abandoning it. + * + * Default value: 2000 + */ + // "waitForKillMs": 2000 +} diff --git a/build-tests/heft-fastify-test/config/rush-project.json b/build-tests/heft-fastify-test/config/rush-project.json new file mode 100644 index 00000000000..11f81b24412 --- /dev/null +++ b/build-tests/heft-fastify-test/config/rush-project.json @@ -0,0 +1,8 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib", "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 new file mode 100644 index 00000000000..3aaac5a4d2b --- /dev/null +++ b/build-tests/heft-fastify-test/package.json @@ -0,0 +1,27 @@ +{ + "name": "heft-fastify-test", + "description": "This project tests Heft support for the Fastify framework for Node.js services", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch --serve", + "serve": "node lib/start.js", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "@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/src/start.ts b/build-tests/heft-fastify-test/src/start.ts new file mode 100644 index 00000000000..99497d954e0 --- /dev/null +++ b/build-tests/heft-fastify-test/src/start.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { fastify, type FastifyInstance } from 'fastify'; + +// eslint-disable-next-line no-console +console.error('CHILD STARTING'); +process.on('beforeExit', () => { + // eslint-disable-next-line no-console + console.error('CHILD BEFOREEXIT'); +}); +process.on('exit', () => { + // eslint-disable-next-line no-console + console.error('CHILD EXITED'); +}); +process.on('SIGINT', function () { + // eslint-disable-next-line no-console + console.error('CHILD SIGINT'); +}); +process.on('SIGTERM', function () { + // eslint-disable-next-line no-console + console.error('CHILD SIGTERM'); +}); + +class MyApp { + public readonly server: FastifyInstance; + + public constructor() { + this.server = fastify({ + logger: true + }); + } + + private async _startAsync(): Promise { + this.server.get('/', async (request, reply) => { + return { hello: 'world' }; + }); + + // eslint-disable-next-line no-console + console.log('Listening on http://localhost:3000'); + await this.server.listen(3000); + } + + public start(): void { + this._startAsync().catch((error) => { + process.exitCode = 1; + this.server.log.error(error); + + if (error.stack) { + // eslint-disable-next-line no-console + console.error(error.stack); + // eslint-disable-next-line no-console + console.error(); + } + // eslint-disable-next-line no-console + console.error('ERROR: ' + error.toString()); + }); + } +} + +const myApp: MyApp = new MyApp(); +myApp.start(); diff --git a/build-tests/heft-fastify-test/tsconfig.json b/build-tests/heft-fastify-test/tsconfig.json new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/build-tests/heft-fastify-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-jest-preset-test/README.md b/build-tests/heft-jest-preset-test/README.md new file mode 100644 index 00000000000..346353fb6be --- /dev/null +++ b/build-tests/heft-jest-preset-test/README.md @@ -0,0 +1,8 @@ +# heft-jest-preset-test + +This project illustrates configuring a Jest preset in a minimal [Heft](https://www.npmjs.com/package/@rushstack/heft) project + + +Please see the [Jest configuration](./config/jest.config.json), +the [Getting started with Heft](https://rushstack.io/pages/heft_tutorials/getting_started/), +and ["jest" task](https://rushstack.io/pages/heft_tasks/jest/) articles for more information. diff --git a/build-tests/heft-jest-preset-test/config/heft.json b/build-tests/heft-jest-preset-test/config/heft.json new file mode 100644 index 00000000000..0a9b64544ef --- /dev/null +++ b/build-tests/heft-jest-preset-test/config/heft.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [ + { + "includeGlobs": ["dist", "lib", "lib-commonjs", "temp"] + } + ], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-jest-preset-test/config/jest-preset.js b/build-tests/heft-jest-preset-test/config/jest-preset.js new file mode 100644 index 00000000000..564abccf7d9 --- /dev/null +++ b/build-tests/heft-jest-preset-test/config/jest-preset.js @@ -0,0 +1,3 @@ +module.exports = { + collectCoverage: true +}; diff --git a/build-tests/heft-jest-preset-test/config/jest.config.json b/build-tests/heft-jest-preset-test/config/jest.config.json new file mode 100644 index 00000000000..f74f91d4645 --- /dev/null +++ b/build-tests/heft-jest-preset-test/config/jest.config.json @@ -0,0 +1,77 @@ +{ + // THIS SHARED JEST CONFIGURATION FILE IS INTENDED TO BE REFERENCED BY THE JEST CONFIGURATION IN + // CONSUMING PACKAGE AND REQUIRES PRESET-RELATIVE MODULE RESOLUTION TO BE ENABLED. IF YOU HAVE + // DISABLED THIS FEATURE YOU MUST CREATE YOUR OWN JEST CONFIGURATION + + "preset": "/config/jest-preset.js", + + // By default, don't hide console output + "silent": false, + + // In order for HeftJestReporter to receive console.log() events, we must set verbose=false + "verbose": false, + + // If mocks are not cleared between tests, it opens the door to accidental reliance on + // ordering of tests or describe blocks, eventually resulting in intermittent failures. + // + // We suggest this setting for any heft project (in a monorepo or not). + "clearMocks": true, + + // "Adding '/lib' here enables lib/__mocks__ to be used for mocking Node.js system modules + "roots": ["/lib"], + + // Retain pre-Jest 29 snapshot behavior + "snapshotFormat": { + "escapeString": true, + "printBasicPrototype": true + }, + + "testEnvironmentOptions": { + "url": "http://localhost/" + }, + + "testMatch": ["/lib/**/*.test.cjs"], + "testPathIgnorePatterns": ["/node_modules/"], + + // Code coverage tracking is disabled by default; set this to true to enable it + // This is set to true in the preset for the "heft" package + // "collectCoverage": false, + + "coverageDirectory": "/coverage", + + "collectCoverageFrom": [ + "lib/**/*.cjs", + "!lib/**/*.test.cjs", + "!lib/**/test/**", + "!lib/**/__tests__/**", + "!lib/**/__fixtures__/**", + "!lib/**/__mocks__/**" + ], + "coveragePathIgnorePatterns": ["/node_modules/"], + + "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 + // 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", + + "\\.(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" + }, + + // The modulePathIgnorePatterns below accepts these sorts of paths: + // - /lib + // - /lib/file.js + // ...and ignores anything else under + "modulePathIgnorePatterns": [], + + // Prefer .cjs to .js to catch explicit commonjs output. Optimize for local files, which will be .cjs + "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" +} diff --git a/build-tests/heft-jest-preset-test/config/rush-project.json b/build-tests/heft-jest-preset-test/config/rush-project.json new file mode 100644 index 00000000000..030d8d0ff0e --- /dev/null +++ b/build-tests/heft-jest-preset-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-jest-preset-test/config/typescript.json b/build-tests/heft-jest-preset-test/config/typescript.json new file mode 100644 index 00000000000..a1e6192d386 --- /dev/null +++ b/build-tests/heft-jest-preset-test/config/typescript.json @@ -0,0 +1,59 @@ +/** + * 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" + // } + ], + + /** + * If true, emit CommonJS module output to the folder specified in the tsconfig "outDir" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + "emitCjsExtensionForCommonJS": true, + + /** + * If true, emit ESNext module output to the folder specified in the tsconfig "outDir" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + // "emitMjsExtensionForESModule": true, + + /** + * 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" + // ] + } +} diff --git a/build-tests/heft-jest-preset-test/config/verify-coverage.js b/build-tests/heft-jest-preset-test/config/verify-coverage.js new file mode 100644 index 00000000000..91c2555cd8f --- /dev/null +++ b/build-tests/heft-jest-preset-test/config/verify-coverage.js @@ -0,0 +1,6 @@ +const fs = require('fs'); +// Verify that the coverage folder exists, since it would only exist +// if the preset was used. +if (!fs.existsSync(`${__dirname}/../coverage`)) { + throw new Error('Coverage folder does not exist'); +} 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 new file mode 100644 index 00000000000..0249b491a60 --- /dev/null +++ b/build-tests/heft-jest-preset-test/package.json @@ -0,0 +1,23 @@ +{ + "name": "heft-jest-preset-test", + "description": "This project illustrates configuring a Jest preset in a minimal Heft project", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft test-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean && node ./config/verify-coverage.js" + }, + "devDependencies": { + "@jest/types": "29.5.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": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/heft-jest-preset-test/src/index.ts b/build-tests/heft-jest-preset-test/src/index.ts new file mode 100644 index 00000000000..ee7c45de9e1 --- /dev/null +++ b/build-tests/heft-jest-preset-test/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 function addThreeStars(input: string): string { + return `${input}***`; +} diff --git a/build-tests/heft-jest-preset-test/src/test/index.test.ts b/build-tests/heft-jest-preset-test/src/test/index.test.ts new file mode 100644 index 00000000000..af48b27f97d --- /dev/null +++ b/build-tests/heft-jest-preset-test/src/test/index.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 { addThreeStars } from '..'; + +describe(addThreeStars.name, () => { + it('adds three stars', () => { + expect(addThreeStars('***Hello World')).toEqual('***Hello World***'); + }); +}); diff --git a/build-tests/heft-jest-preset-test/tsconfig.json b/build-tests/heft-jest-preset-test/tsconfig.json new file mode 100644 index 00000000000..0ad08cab8f8 --- /dev/null +++ b/build-tests/heft-jest-preset-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "types": ["heft-jest"], + + "module": "esnext", + "moduleResolution": "node", + "target": "ES2015", + "lib": ["ES2015"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-jest-reporters-test/README.md b/build-tests/heft-jest-reporters-test/README.md new file mode 100644 index 00000000000..ec5f8821641 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/README.md @@ -0,0 +1,8 @@ +# heft-jest-reporter-test + +This project illustrates configuring Jest reporters in a minimal [Heft](https://www.npmjs.com/package/@rushstack/heft) project + + +Please see the [Jest configuration](./config/jest.config.json), +the [Getting started with Heft](https://rushstack.io/pages/heft_tutorials/getting_started/), +and ["jest" task](https://rushstack.io/pages/heft_tasks/jest/) articles for more information. diff --git a/build-tests/heft-jest-reporters-test/config/heft.json b/build-tests/heft-jest-reporters-test/config/heft.json new file mode 100644 index 00000000000..0394daa977b --- /dev/null +++ b/build-tests/heft-jest-reporters-test/config/heft.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-jest-reporters-test/config/jest.config.json b/build-tests/heft-jest-reporters-test/config/jest.config.json new file mode 100644 index 00000000000..294f12cc0bb --- /dev/null +++ b/build-tests/heft-jest-reporters-test/config/jest.config.json @@ -0,0 +1,15 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "coverageDirectory": "/coverage", + "reporters": ["default", "../lib/test/customJestReporter.cjs"], + "testMatch": ["/lib/**/*.test.cjs"], + "collectCoverageFrom": [ + "lib/**/*.cjs", + "!lib/**/*.d.ts", + "!lib/**/*.test.cjs", + "!lib/**/test/**", + "!lib/**/__tests__/**", + "!lib/**/__fixtures__/**", + "!lib/**/__mocks__/**" + ] +} diff --git a/build-tests/heft-jest-reporters-test/config/rush-project.json b/build-tests/heft-jest-reporters-test/config/rush-project.json new file mode 100644 index 00000000000..030d8d0ff0e --- /dev/null +++ b/build-tests/heft-jest-reporters-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-jest-reporters-test/config/typescript.json b/build-tests/heft-jest-reporters-test/config/typescript.json new file mode 100644 index 00000000000..a1e6192d386 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/config/typescript.json @@ -0,0 +1,59 @@ +/** + * 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" + // } + ], + + /** + * If true, emit CommonJS module output to the folder specified in the tsconfig "outDir" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + "emitCjsExtensionForCommonJS": true, + + /** + * If true, emit ESNext module output to the folder specified in the tsconfig "outDir" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + // "emitMjsExtensionForESModule": true, + + /** + * 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" + // ] + } +} 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 new file mode 100644 index 00000000000..73547e1902f --- /dev/null +++ b/build-tests/heft-jest-reporters-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "heft-jest-reporters-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": { + "@jest/reporters": "~29.5.0", + "@jest/types": "29.5.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", + "@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/src/index.ts b/build-tests/heft-jest-reporters-test/src/index.ts new file mode 100644 index 00000000000..ee7c45de9e1 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/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 function addThreeStars(input: string): string { + return `${input}***`; +} diff --git a/build-tests/heft-jest-reporters-test/src/test/customJestReporter.ts b/build-tests/heft-jest-reporters-test/src/test/customJestReporter.ts new file mode 100644 index 00000000000..3f0166f6208 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/src/test/customJestReporter.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 { Config } from '@jest/types'; +import type { + Reporter, + Test, + TestResult, + AggregatedResult, + TestContext, + ReporterOnStartOptions +} from '@jest/reporters'; + +module.exports = class CustomJestReporter implements Reporter { + public constructor(globalConfig: Config.GlobalConfig, options: unknown) {} + + public onRunStart(results: AggregatedResult, options: ReporterOnStartOptions): void | Promise { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log(`################# Custom Jest reporter: Starting test run #################`); + } + + public onTestStart(test: Test): void | Promise {} + + public onTestResult(test: Test, testResult: TestResult, results: AggregatedResult): void | Promise { + // eslint-disable-next-line no-console + console.log('Custom Jest reporter: Reporting test result'); + + for (const result of testResult.testResults) { + // eslint-disable-next-line no-console + console.log(`${result.title}: ${result.status}`); + } + } + + public onRunComplete(contexts: Set, results: AggregatedResult): void | Promise { + // eslint-disable-next-line no-console + console.log('################# Completing test run #################'); + // eslint-disable-next-line no-console + console.log(); + } + + public getLastError(): void | Error {} +}; diff --git a/build-tests/heft-jest-reporters-test/src/test/index.test.ts b/build-tests/heft-jest-reporters-test/src/test/index.test.ts new file mode 100644 index 00000000000..af48b27f97d --- /dev/null +++ b/build-tests/heft-jest-reporters-test/src/test/index.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 { addThreeStars } from '..'; + +describe(addThreeStars.name, () => { + it('adds three stars', () => { + expect(addThreeStars('***Hello World')).toEqual('***Hello World***'); + }); +}); diff --git a/build-tests/heft-jest-reporters-test/tsconfig.json b/build-tests/heft-jest-reporters-test/tsconfig.json new file mode 100644 index 00000000000..ffed841a228 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "types": ["heft-jest"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es2020", + "lib": ["es2020"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} 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..9ca23a6775b --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json @@ -0,0 +1,24 @@ +{ + "$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"] + } + } + } + } + } + } +} 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..a7ae645f19c --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/package.json @@ -0,0 +1,19 @@ +{ + "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:*" + } +} 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..a0adc753617 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.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 { 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', () => { + it('should generate typings for JSON Schemas', async () => { + const rootFolder: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); + if (!rootFolder) { + throw new Error('Could not find root folder for the test'); + } + + const folderItems: Record = await getFolderItemsAsync( + `${rootFolder}/temp/schema-dts`, + '.' + ); + 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..42c458407d8 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap @@ -0,0 +1,185 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 new file mode 100644 index 00000000000..514e557d5eb --- /dev/null +++ b/build-tests/heft-minimal-rig-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", "dist"] + } + ] +} diff --git a/build-tests/heft-minimal-rig-test/package.json b/build-tests/heft-minimal-rig-test/package.json new file mode 100644 index 00000000000..8b4c68d9859 --- /dev/null +++ b/build-tests/heft-minimal-rig-test/package.json @@ -0,0 +1,19 @@ +{ + "name": "heft-minimal-rig-test", + "description": "This is a minimal rig package that is imported by the 'heft-minimal-rig-usage-test' project", + "version": "1.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "", + "_phase:build": "" + }, + "dependencies": { + "typescript": "~5.8.2", + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*" + } +} diff --git a/build-tests/heft-minimal-rig-test/profiles/default/config/api-extractor.json b/build-tests/heft-minimal-rig-test/profiles/default/config/api-extractor.json new file mode 100644 index 00000000000..00f077c8b87 --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": false + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + }, + "tsdocMetadata": { "enabled": false } +} diff --git a/build-tests/heft-minimal-rig-test/profiles/default/config/heft.json b/build-tests/heft-minimal-rig-test/profiles/default/config/heft.json new file mode 100644 index 00000000000..7ec35fead4f --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/config/heft.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-minimal-rig-test/profiles/default/config/jest.config.json b/build-tests/heft-minimal-rig-test/profiles/default/config/jest.config.json new file mode 100644 index 00000000000..441ad22d6d1 --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json" +} 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-test/profiles/default/config/typescript.json b/build-tests/heft-minimal-rig-test/profiles/default/config/typescript.json new file mode 100644 index 00000000000..5bb725c1781 --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/config/typescript.json @@ -0,0 +1,17 @@ +/** + * 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": [ + { + "moduleKind": "commonjs", + "outFolderName": "lib-commonjs" + } + ] +} diff --git a/build-tests/heft-minimal-rig-test/profiles/default/tsconfig-base.json b/build-tests/heft-minimal-rig-test/profiles/default/tsconfig-base.json new file mode 100644 index 00000000000..6029471917f --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/tsconfig-base.json @@ -0,0 +1,26 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": [], + "moduleResolution": "node", + + "module": "esnext", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["../../../../src/**/*.ts", "../../../../src/**/*.tsx"], + "exclude": ["../../../../node_modules", "../../../../lib"] +} diff --git a/build-tests/heft-minimal-rig-usage-test/config/jest.config.json b/build-tests/heft-minimal-rig-usage-test/config/jest.config.json new file mode 100644 index 00000000000..ac52a5b3dc3 --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "heft-minimal-rig-test/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" +} diff --git a/build-tests/heft-minimal-rig-usage-test/config/rig.json b/build-tests/heft-minimal-rig-usage-test/config/rig.json new file mode 100644 index 00000000000..b4c8b0a6694 --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-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": "heft-minimal-rig-test" +} diff --git a/build-tests/heft-minimal-rig-usage-test/package.json b/build-tests/heft-minimal-rig-usage-test/package.json new file mode 100644 index 00000000000..b170c16c4f7 --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-test/package.json @@ -0,0 +1,19 @@ +{ + "name": "heft-minimal-rig-usage-test", + "description": "A test project for Heft that resolves its compiler from the 'heft-minimal-rig-test' package", + "version": "1.0.0", + "private": true, + "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:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "@types/node": "20.17.19", + "heft-minimal-rig-test": "workspace:*" + } +} diff --git a/build-tests/heft-minimal-rig-usage-test/src/index.ts b/build-tests/heft-minimal-rig-usage-test/src/index.ts new file mode 100644 index 00000000000..e4938bc39ea --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-test/src/index.ts @@ -0,0 +1,11 @@ +// 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 { + public static getTrue(): boolean { + return true; + } +} diff --git a/build-tests/heft-minimal-rig-usage-test/src/test/example.test.ts b/build-tests/heft-minimal-rig-usage-test/src/test/example.test.ts new file mode 100644 index 00000000000..042c99d819c --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-test/src/test/example.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 { TestClass } from '../index'; + +describe('An example test', () => { + it('Is able to import things', () => { + expect(TestClass.getTrue()).toBe(true); + }); +}); diff --git a/build-tests/heft-minimal-rig-usage-test/tsconfig.json b/build-tests/heft-minimal-rig-usage-test/tsconfig.json new file mode 100644 index 00000000000..219354d8484 --- /dev/null +++ b/build-tests/heft-minimal-rig-usage-test/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/heft-minimal-rig-test/profiles/default/tsconfig-base.json", + "compilerOptions": { + "types": ["heft-jest", "node"] + } +} diff --git a/build-tests/heft-node-everything-esm-module-test/.gitignore b/build-tests/heft-node-everything-esm-module-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-node-everything-esm-module-test/config/api-extractor-task.json b/build-tests/heft-node-everything-esm-module-test/config/api-extractor-task.json new file mode 100644 index 00000000000..860479fe991 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/api-extractor-task.json @@ -0,0 +1,21 @@ +/** + * Configures the API Extractor task for the Heft build system. + * + * This optional additional file customizes how the Heft task is invoked. The main analysis is + * controlled by API Extractor's own "api-extractor.json" config file. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json", + + /** + * If set to true, use the project's TypeScript compiler version for API Extractor's + * analysis. API Extractor's included TypeScript compiler can generally correctly + * analyze typings generated by older compilers, and referencing the project's compiler + * can cause issues. If issues are encountered with API Extractor's included compiler, + * set this option to true. + * + * This corresponds to API Extractor's "--typescript-compiler-folder" CLI option and + * "IExtractorInvokeOptions.typescriptCompilerFolder" API option. This option defaults to false. + */ + "useProjectTypescriptVersion": false +} 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 new file mode 100644 index 00000000000..b3969a325c1 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/etc" + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} 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 new file mode 100644 index 00000000000..a82a1fd0bb9 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/heft.json @@ -0,0 +1,53 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + }, + "example-plugin-01": { + "taskPlugin": { + "pluginPackage": "heft-example-plugin-01" + } + }, + "example-plugin-02": { + "taskPlugin": { + "pluginPackage": "heft-example-plugin-02" + } + } + } + } + } +} diff --git a/build-tests/heft-node-everything-esm-module-test/config/jest.config.json b/build-tests/heft-node-everything-esm-module-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-node-everything-esm-module-test/config/rush-project.json b/build-tests/heft-node-everything-esm-module-test/config/rush-project.json new file mode 100644 index 00000000000..a93c6b2720f --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-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": ["dist", "lib", "lib-esnext", "lib-umd"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..7295774598d --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/typescript.json @@ -0,0 +1,25 @@ +/** + * 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": [ + { + "moduleKind": "esnext", + "outFolderName": "lib-esnext" + }, + { + "moduleKind": "umd", + "outFolderName": "lib-umd" + } + ], + + "staticAssetsToCopy": { + "fileExtensions": [".txt"] + } +} 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 new file mode 100644 index 00000000000..9d5bceee423 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/etc/heft-node-everything-esm-module-test.api.md @@ -0,0 +1,13 @@ +## API Report File for "heft-node-everything-esm-module-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class TestClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/heft-node-everything-esm-module-test/package.json b/build-tests/heft-node-everything-esm-module-test/package.json new file mode 100644 index 00000000000..7511a0b5745 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/package.json @@ -0,0 +1,30 @@ +{ + "name": "heft-node-everything-esm-module-test", + "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", + "type": "module", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-api-extractor-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": "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.8.2" + } +} diff --git a/build-tests/heft-node-everything-esm-module-test/src/copiedAsset.txt b/build-tests/heft-node-everything-esm-module-test/src/copiedAsset.txt new file mode 100644 index 00000000000..c9f6b7043cd --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/src/copiedAsset.txt @@ -0,0 +1 @@ +THIS FILE SHOULD GET COPIED TO THE "lib" FOLDER BECAUSE IT IS REFERENCED IN copy-static-assets.json \ No newline at end of file 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 new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-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-node-everything-esm-module-test/src/test/ExampleTest.test.ts b/build-tests/heft-node-everything-esm-module-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-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-node-everything-esm-module-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-node-everything-esm-module-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-node-everything-esm-module-test/tsconfig.json b/build-tests/heft-node-everything-esm-module-test/tsconfig.json new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-node-everything-esm-module-test/tslint.json b/build-tests/heft-node-everything-esm-module-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-node-everything-test/.gitignore b/build-tests/heft-node-everything-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-node-everything-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-node-everything-test/config/api-extractor-task.json b/build-tests/heft-node-everything-test/config/api-extractor-task.json new file mode 100644 index 00000000000..860479fe991 --- /dev/null +++ b/build-tests/heft-node-everything-test/config/api-extractor-task.json @@ -0,0 +1,21 @@ +/** + * Configures the API Extractor task for the Heft build system. + * + * This optional additional file customizes how the Heft task is invoked. The main analysis is + * controlled by API Extractor's own "api-extractor.json" config file. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json", + + /** + * If set to true, use the project's TypeScript compiler version for API Extractor's + * analysis. API Extractor's included TypeScript compiler can generally correctly + * analyze typings generated by older compilers, and referencing the project's compiler + * can cause issues. If issues are encountered with API Extractor's included compiler, + * set this option to true. + * + * This corresponds to API Extractor's "--typescript-compiler-folder" CLI option and + * "IExtractorInvokeOptions.typescriptCompilerFolder" API option. This option defaults to false. + */ + "useProjectTypescriptVersion": false +} diff --git a/build-tests/heft-node-everything-test/config/api-extractor.json b/build-tests/heft-node-everything-test/config/api-extractor.json new file mode 100644 index 00000000000..e451cf705d0 --- /dev/null +++ b/build-tests/heft-node-everything-test/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/etc" + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/build-tests/heft-node-everything-test/config/heft.json b/build-tests/heft-node-everything-test/config/heft.json new file mode 100644 index 00000000000..08d9c72b92e --- /dev/null +++ b/build-tests/heft-node-everything-test/config/heft.json @@ -0,0 +1,70 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$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"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + }, + "metadata-test": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./lib/test-metadata.js" + } + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + }, + "example-plugin-01": { + "taskPlugin": { + "pluginPackage": "heft-example-plugin-01" + } + }, + "example-plugin-02": { + "taskPlugin": { + "pluginPackage": "heft-example-plugin-02" + } + } + } + } + } +} diff --git a/build-tests/heft-node-everything-test/config/jest.config.json b/build-tests/heft-node-everything-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-node-everything-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-node-everything-test/config/rush-project.json b/build-tests/heft-node-everything-test/config/rush-project.json new file mode 100644 index 00000000000..a93c6b2720f --- /dev/null +++ b/build-tests/heft-node-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": ["dist", "lib", "lib-esnext", "lib-umd"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-node-everything-test/config/typescript.json b/build-tests/heft-node-everything-test/config/typescript.json new file mode 100644 index 00000000000..7295774598d --- /dev/null +++ b/build-tests/heft-node-everything-test/config/typescript.json @@ -0,0 +1,25 @@ +/** + * 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": [ + { + "moduleKind": "esnext", + "outFolderName": "lib-esnext" + }, + { + "moduleKind": "umd", + "outFolderName": "lib-umd" + } + ], + + "staticAssetsToCopy": { + "fileExtensions": [".txt"] + } +} 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 new file mode 100644 index 00000000000..73e6e6a967e --- /dev/null +++ b/build-tests/heft-node-everything-test/etc/heft-node-everything-test.api.md @@ -0,0 +1,13 @@ +## API Report File for "heft-node-everything-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class TestClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/heft-node-everything-test/package.json b/build-tests/heft-node-everything-test/package.json new file mode 100644 index 00000000000..7b2fa422c04 --- /dev/null +++ b/build-tests/heft-node-everything-test/package.json @@ -0,0 +1,32 @@ +{ + "name": "heft-node-everything-test", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:build:incremental": "heft run --only build --", + "_phase:test": "heft run --only test -- --clean", + "_phase:test:incremental": "heft run --only test --" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-api-extractor-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": "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.8.2" + } +} diff --git a/build-tests/heft-node-everything-test/src/copiedAsset.txt b/build-tests/heft-node-everything-test/src/copiedAsset.txt new file mode 100644 index 00000000000..c9f6b7043cd --- /dev/null +++ b/build-tests/heft-node-everything-test/src/copiedAsset.txt @@ -0,0 +1 @@ +THIS FILE SHOULD GET COPIED TO THE "lib" FOLDER BECAUSE IT IS REFERENCED IN copy-static-assets.json \ No newline at end of file diff --git a/build-tests/heft-node-everything-test/src/index.ts b/build-tests/heft-node-everything-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-node-everything-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-node-everything-test/src/test-metadata.ts b/build-tests/heft-node-everything-test/src/test-metadata.ts new file mode 100644 index 00000000000..1fd618c599a --- /dev/null +++ b/build-tests/heft-node-everything-test/src/test-metadata.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 fs from 'node:fs/promises'; + +import type { IRunScriptOptions } from '@rushstack/heft'; + +export async function runAsync({ heftConfiguration: { buildFolderPath } }: IRunScriptOptions): Promise { + const metadataFolder: string = `${buildFolderPath}/.rush/temp/operation/_phase_build`; + + await fs.mkdir(metadataFolder, { recursive: true }); + + await fs.writeFile(`${metadataFolder}/test.txt`, new Date().toString(), 'utf-8'); +} 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 new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-node-everything-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-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-node-everything-test/tsconfig.json b/build-tests/heft-node-everything-test/tsconfig.json new file mode 100644 index 00000000000..845c0343e3c --- /dev/null +++ b/build-tests/heft-node-everything-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-node-everything-test/tslint.json b/build-tests/heft-node-everything-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests/heft-node-everything-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-parameter-plugin-test/README.md b/build-tests/heft-parameter-plugin-test/README.md new file mode 100644 index 00000000000..1483ff37657 --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/README.md @@ -0,0 +1,6 @@ +# heft-parameter-plugin-test + +This project folder is one of the **build-tests** for the [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. This project exercises a built-in Heft action with a custom parameter defined for `heft test`. + +Please see the [Heft documentation](https://rushstack.io/pages/heft/overview/) for documentation and tutorials. diff --git a/build-tests/heft-parameter-plugin-test/config/heft.json b/build-tests/heft-parameter-plugin-test/config/heft.json new file mode 100644 index 00000000000..e0863aedb18 --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/config/heft.json @@ -0,0 +1,44 @@ +/** + * 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" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "write-parameters": { + "taskPlugin": { + "pluginPackage": "heft-parameter-plugin" + } + }, + "jest": { + "taskDependencies": ["write-parameters"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-parameter-plugin-test/config/jest.config.json b/build-tests/heft-parameter-plugin-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-parameter-plugin-test/config/rush-project.json b/build-tests/heft-parameter-plugin-test/config/rush-project.json new file mode 100644 index 00000000000..93089856e44 --- /dev/null +++ b/build-tests/heft-parameter-plugin-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"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-parameter-plugin-test/package.json b/build-tests/heft-parameter-plugin-test/package.json new file mode 100644 index 00000000000..d30cf69eaed --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/package.json @@ -0,0 +1,23 @@ +{ + "name": "heft-parameter-plugin-test", + "description": "This project exercises a built-in Heft action with a custom parameter", + "version": "1.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_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-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/node": "20.17.19", + "heft-parameter-plugin": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/heft-parameter-plugin-test/src/test/customParameter.test.ts b/build-tests/heft-parameter-plugin-test/src/test/customParameter.test.ts new file mode 100644 index 00000000000..791e0d7bcbc --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/src/test/customParameter.test.ts @@ -0,0 +1,18 @@ +import { dirname } from 'path'; +import { FileSystem } from '@rushstack/node-core-library'; + +describe('CustomParameterOutput', () => { + it('parses command line arguments and prints output.', async () => { + const outputContent: string = await FileSystem.readFileAsync( + `${dirname(dirname(__dirname))}/temp/test/write-parameters/custom_output.txt` + ); + expect(outputContent).toBe( + 'customIntegerParameter: 5\n' + + 'customIntegerListParameter: 6, 7\n' + + 'customStringParameter: test\n' + + 'customStringListParameter: eevee, togepi, mareep\n' + + 'customChoiceParameter: red\n' + + 'customChoiceListParameter: totodile, gudetama, wobbuffet' + ); + }); +}); diff --git a/build-tests/heft-parameter-plugin-test/tsconfig.json b/build-tests/heft-parameter-plugin-test/tsconfig.json new file mode 100644 index 00000000000..98464e7dfed --- /dev/null +++ b/build-tests/heft-parameter-plugin-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-parameter-plugin/README.md b/build-tests/heft-parameter-plugin/README.md new file mode 100644 index 00000000000..1352cb073bd --- /dev/null +++ b/build-tests/heft-parameter-plugin/README.md @@ -0,0 +1,6 @@ +# heft-parameter-plugin + +This project folder is one of the **build-tests** for the [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. This project contains a Heft plugin that adds a custom parameter to built-in actions. + +Please see the [Heft documentation](https://rushstack.io/pages/heft/overview/) for documentation and tutorials. diff --git a/build-tests/heft-parameter-plugin/config/heft.json b/build-tests/heft-parameter-plugin/config/heft.json new file mode 100644 index 00000000000..8e9ad151053 --- /dev/null +++ b/build-tests/heft-parameter-plugin/config/heft.json @@ -0,0 +1,26 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["lib"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-parameter-plugin/config/rush-project.json b/build-tests/heft-parameter-plugin/config/rush-project.json new file mode 100644 index 00000000000..a3516b19e56 --- /dev/null +++ b/build-tests/heft-parameter-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"] + } + ] +} 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 new file mode 100644 index 00000000000..d7446db30e2 --- /dev/null +++ b/build-tests/heft-parameter-plugin/heft-plugin.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "heft-parameter-plugin", + "entryPoint": "./lib/index", + "parameterScope": "heft-parameter-plugin", + "parameters": [ + { + "longName": "--custom-parameter", + "parameterKind": "flag", + "description": "Test running a custom flag parameter" + }, + { + "longName": "--custom-integer-parameter", + "parameterKind": "integer", + "description": "Test running a custom integer parameter", + "argumentName": "INTEGER" + }, + { + "longName": "--custom-integer-list-parameter", + "parameterKind": "integerList", + "description": "Test running a custom integer list parameter", + "argumentName": "INTEGER" + }, + { + "longName": "--custom-string-parameter", + "parameterKind": "string", + "argumentName": "TEXT", + "description": "Test running a custom string parameter", + "required": true + }, + { + "longName": "--custom-string-list-parameter", + "parameterKind": "stringList", + "argumentName": "LIST_ITEM", + "description": "Test running a custom string list parameter" + }, + { + "longName": "--custom-choice-parameter", + "parameterKind": "choice", + "alternatives": [ + { + "name": "red", + "description": "The red choice" + }, + { + "name": "blue", + "description": "The blue choice" + } + ], + "description": "Test running a custom choice parameter" + }, + { + "longName": "--custom-choice-list-parameter", + "parameterKind": "choiceList", + "alternatives": [ + { + "name": "totodile", + "description": "The totodile choice" + }, + { + "name": "jynx", + "description": "The jynx choice" + }, + { + "name": "gudetama", + "description": "The gudetama choice" + }, + { + "name": "impidimp", + "description": "The impidimp choice" + }, + { + "name": "wobbuffet", + "description": "The wobbuffet choice" + } + ], + "description": "Test running a custom choice list parameter" + } + ] + } + ] +} diff --git a/build-tests/heft-parameter-plugin/package.json b/build-tests/heft-parameter-plugin/package.json new file mode 100644 index 00000000000..9e447a93ec2 --- /dev/null +++ b/build-tests/heft-parameter-plugin/package.json @@ -0,0 +1,24 @@ +{ + "name": "heft-parameter-plugin", + "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", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_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" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests/heft-parameter-plugin/src/index.ts b/build-tests/heft-parameter-plugin/src/index.ts new file mode 100644 index 00000000000..c4dfae328be --- /dev/null +++ b/build-tests/heft-parameter-plugin/src/index.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 } from '@rushstack/node-core-library'; +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + CommandLineFlagParameter, + CommandLineStringParameter, + CommandLineChoiceParameter, + CommandLineStringListParameter, + CommandLineChoiceListParameter, + CommandLineIntegerParameter, + CommandLineIntegerListParameter +} from '@rushstack/heft'; + +const PLUGIN_NAME: string = 'heft-parameter-plugin'; + +export default class HeftParameterPlugin implements IHeftTaskPlugin { + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + const { parameters } = taskSession; + + const customParameter: CommandLineFlagParameter = parameters.getFlagParameter('--custom-parameter'); + const customIntegerParameter: CommandLineIntegerParameter = parameters.getIntegerParameter( + '--custom-integer-parameter' + ); + const customIntegerListParameter: CommandLineIntegerListParameter = parameters.getIntegerListParameter( + '--custom-integer-list-parameter' + ); + const customStringParameter: CommandLineStringParameter = + parameters.getStringParameter('--custom-string-parameter'); + const customStringListParameter: CommandLineStringListParameter = parameters.getStringListParameter( + '--custom-string-list-parameter' + ); + const customChoiceParameter: CommandLineChoiceParameter = + parameters.getChoiceParameter('--custom-choice-parameter'); + const customChoiceListParameter: CommandLineChoiceListParameter = parameters.getChoiceListParameter( + '--custom-choice-list-parameter' + ); + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + if (customParameter.value) { + const customContent: string = + `customIntegerParameter: ${customIntegerParameter.value}\n` + + `customIntegerListParameter: ${customIntegerListParameter.values?.join(', ')}\n` + + `customStringParameter: ${customStringParameter.value}\n` + + `customStringListParameter: ${customStringListParameter.values?.join(', ')}\n` + + `customChoiceParameter: ${customChoiceParameter.value}\n` + + `customChoiceListParameter: ${customChoiceListParameter.values?.join(', ')}`; + await FileSystem.writeFileAsync(`${taskSession.tempFolderPath}/custom_output.txt`, customContent, { + ensureFolderExists: true + }); + } + }); + } +} diff --git a/build-tests/heft-parameter-plugin/tsconfig.json b/build-tests/heft-parameter-plugin/tsconfig.json new file mode 100644 index 00000000000..2d179c7173f --- /dev/null +++ b/build-tests/heft-parameter-plugin/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} 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..7d826b05556 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/heft.json @@ -0,0 +1,66 @@ +/** + * 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"] }], + + "tasksByName": { + "typescript": { + "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..f22bb14d6d1 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/jest.config.json @@ -0,0 +1,12 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // 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/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..030d8d0ff0e --- /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", "dist"] + }, + { + "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..081fc7ac997 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/package.json @@ -0,0 +1,29 @@ +{ + "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-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/heft-jest": "1.0.1", + "@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..fa68d03598f --- /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', 'indexA.js'), + 'heft-test-B': resolve(__dirname, 'lib', '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..3e0315a615d --- /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', 'indexA.js'), + 'heft-test-B': resolve(__dirname, 'lib', '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.d.png.ts b/build-tests/heft-rspack-everything-test/src/chunks/image.d.png.ts new file mode 100644 index 00000000000..f38a285dfd9 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/chunks/image.d.png.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. + +declare const path: string; + +export default path; 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..23c890d36c4 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/test/__snapshots__/SourceMapTest.test.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Source Maps Chunk has a source that matches the sourceFileRegex 1`] = ` +Array [ + "webpack://heft-rspack-everything-test/./lib/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/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/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..1838fa44b78 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "allowArbitraryExtensions": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "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"] +} 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/README.md b/build-tests/heft-sass-test/README.md new file mode 100644 index 00000000000..e026cd51d67 --- /dev/null +++ b/build-tests/heft-sass-test/README.md @@ -0,0 +1,15 @@ +# heft-sass-test + +This project folder is one of the **build-tests** for the [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. It illustrates a realistic small project that targets a web browser runtime, +includes the uses of Sass, SCSS, and CSS, and renders using the [React](https://reactjs.org/) library. + +The following tasks are configured: + +- [TypeScript](https://rushstack.io/pages/heft_tasks/typescript/) compiler +- [ESLint](https://rushstack.io/pages/heft_tasks/eslint/) coding style validator +- [Jest](https://rushstack.io/pages/heft_tasks/jest/) test runner +- [copy-static-assets](https://rushstack.io/pages/heft_tasks/copy-static-assets/) for .css, .scss, and .sass files +- [Webpack](https://rushstack.io/pages/heft_tasks/webpack/) for bundling and optimization + +Please see the [Heft documentation](https://rushstack.io/pages/heft/overview/) for documentation and tutorials. diff --git a/build-tests/heft-sass-test/assets/index.html b/build-tests/heft-sass-test/assets/index.html new file mode 100644 index 00000000000..9e89ef57d85 --- /dev/null +++ b/build-tests/heft-sass-test/assets/index.html @@ -0,0 +1,12 @@ + + + + + + Example Application + + + +
+ + diff --git a/build-tests/heft-sass-test/config/heft.json b/build-tests/heft-sass-test/config/heft.json new file mode 100644 index 00000000000..9ebc1cf87e4 --- /dev/null +++ b/build-tests/heft-sass-test/config/heft.json @@ -0,0 +1,72 @@ +/** + * 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", "lib-css", "temp"] }], + + "tasksByName": { + "set-browserslist-ignore-old-data-env-var": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "set-environment-variables-plugin", + "options": { + "environmentVariablesToSet": { + // Suppress the "Browserslist: caniuse-lite is outdated" warning. Although the warning is + // potentially useful, the check is performed in a way that is nondeterministic and can cause + // Rush pipelines to fail. Moreover, the outdated version is often irrelevant and/or nontrivial + // to upgrade. See this thread for details: https://github.com/microsoft/rushstack/issues/2981 + "BROWSERSLIST_IGNORE_OLD_DATA": "1" + } + } + } + }, + "sass": { + "taskDependencies": ["set-browserslist-ignore-old-data-env-var"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-plugin" + } + }, + "sass-load-styles": { + "taskDependencies": [], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-load-themed-styles-plugin" + } + }, + "typescript": { + "taskDependencies": ["sass"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack4-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-sass-test/config/jest.config.json b/build-tests/heft-sass-test/config/jest.config.json new file mode 100644 index 00000000000..1d798061493 --- /dev/null +++ b/build-tests/heft-sass-test/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // Enable code coverage for Jest + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"], + + // Use v8 coverage provider to avoid Babel + "coverageProvider": "v8", + + "moduleFileExtensions": ["js", "css", "json", "node"] +} diff --git a/build-tests/heft-sass-test/config/rush-project.json b/build-tests/heft-sass-test/config/rush-project.json new file mode 100644 index 00000000000..cd98f0644b5 --- /dev/null +++ b/build-tests/heft-sass-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", "lib-css", "dist", "temp/sass-ts"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-sass-test/config/sass.json b/build-tests/heft-sass-test/config/sass.json new file mode 100644 index 00000000000..a4993854d2f --- /dev/null +++ b/build-tests/heft-sass-test/config/sass.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json", + + "cssOutputFolders": [ + { "folder": "lib", "shimModuleFormat": "esnext" }, + { "folder": "lib-commonjs", "shimModuleFormat": "commonjs" }, + "lib-css" + ], + "secondaryGeneratedTsFolders": ["lib"], + "excludeFiles": ["./ignored1.scss", "ignored2.scss"], + + "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/config/typescript.json b/build-tests/heft-sass-test/config/typescript.json new file mode 100644 index 00000000000..634bd4e7493 --- /dev/null +++ b/build-tests/heft-sass-test/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": [] + + /** + * 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/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 new file mode 100644 index 00000000000..572fa22266e --- /dev/null +++ b/build-tests/heft-sass-test/package.json @@ -0,0 +1,42 @@ +{ + "name": "heft-sass-test", + "description": "This project illustrates a minimal tutorial Heft project targeting the web browser runtime", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch --serve", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "local-eslint-config": "workspace:*", + "@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/node": "20.17.19", + "@types/react-dom": "17.0.25", + "@types/react": "17.0.74", + "@types/webpack-env": "1.18.8", + "autoprefixer": "~10.4.2", + "css-loader": "~5.2.7", + "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", + "style-loader": "~2.0.0", + "typescript": "~5.8.2", + "webpack": "~4.47.0" + }, + "dependencies": { + "buttono": "~1.0.2" + } +} diff --git a/build-tests/heft-sass-test/src/ExampleApp.tsx b/build-tests/heft-sass-test/src/ExampleApp.tsx new file mode 100644 index 00000000000..0fca1af0443 --- /dev/null +++ b/build-tests/heft-sass-test/src/ExampleApp.tsx @@ -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 React from 'react'; + +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'; + +/** + * This React component renders the application page. + */ +export class ExampleApp extends React.Component { + public render(): React.ReactNode { + // Test 3 different style syntaxes: .sass, .css, and .scss, as well as imports. + return ( +
+
+

Hello, world!

+

Here is an example styled buttons:

+ + + Example Anchor + +

Here is an example styled unordered list and list items

+
    +
  • 1st
  • +
  • 2nd
  • +
  • 3rd
  • +
+

This element has a complex class name.

+
+
+ ); + } +} diff --git a/build-tests/heft-sass-test/src/_forwardSyntaxStyles.scss b/build-tests/heft-sass-test/src/_forwardSyntaxStyles.scss new file mode 100644 index 00000000000..8a64ba03d5b --- /dev/null +++ b/build-tests/heft-sass-test/src/_forwardSyntaxStyles.scss @@ -0,0 +1,6 @@ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ + +@forward '~buttono/buttono'; diff --git a/build-tests/heft-sass-test/src/_stylesImport.sass b/build-tests/heft-sass-test/src/_stylesImport.sass new file mode 100644 index 00000000000..11a6a94019d --- /dev/null +++ b/build-tests/heft-sass-test/src/_stylesImport.sass @@ -0,0 +1,8 @@ +/** + * This file is a SASS partial and therefore has no direct output file, but gets embedded into other files. + */ + +// This will be imported by styles.sass +.exampleImport + font-style: italic + color: darkcyan \ No newline at end of file diff --git a/build-tests/heft-sass-test/src/ignored1.scss b/build-tests/heft-sass-test/src/ignored1.scss new file mode 100644 index 00000000000..5a951e022cc --- /dev/null +++ b/build-tests/heft-sass-test/src/ignored1.scss @@ -0,0 +1,3 @@ +.ignoredStyle { + color: green; +} diff --git a/build-tests/heft-sass-test/src/ignored2.scss b/build-tests/heft-sass-test/src/ignored2.scss new file mode 100644 index 00000000000..aa93cd03eb5 --- /dev/null +++ b/build-tests/heft-sass-test/src/ignored2.scss @@ -0,0 +1,3 @@ +.otherIgnoredStyle { + color: blue; +} diff --git a/build-tests/heft-sass-test/src/index.tsx b/build-tests/heft-sass-test/src/index.tsx new file mode 100644 index 00000000000..d6ba6e6cac2 --- /dev/null +++ b/build-tests/heft-sass-test/src/index.tsx @@ -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 * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +import { ExampleApp } from './ExampleApp'; + +const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; +ReactDOM.render(, rootDiv); 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/stylesAltSyntax.global.scss b/build-tests/heft-sass-test/src/stylesAltSyntax.global.scss new file mode 100644 index 00000000000..39e4cce0a9d --- /dev/null +++ b/build-tests/heft-sass-test/src/stylesAltSyntax.global.scss @@ -0,0 +1,11 @@ +/** + * 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; + +.ms-label { + margin-bottom: $marginValue; +} 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/stylesCSS.module.css b/build-tests/heft-sass-test/src/stylesCSS.module.css new file mode 100644 index 00000000000..de4aa4d3ca4 --- /dev/null +++ b/build-tests/heft-sass-test/src/stylesCSS.module.css @@ -0,0 +1,9 @@ +/** + * This file gets picked up 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 CSS styles */ +.container { + padding: 40px; +} diff --git a/build-tests/heft-sass-test/src/stylesUseAltSyntax.module.scss b/build-tests/heft-sass-test/src/stylesUseAltSyntax.module.scss new file mode 100644 index 00000000000..7690261db2f --- /dev/null +++ b/build-tests/heft-sass-test/src/stylesUseAltSyntax.module.scss @@ -0,0 +1,46 @@ +/** + * 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 built-in module using use syntax +@use 'sass:color'; +@use 'sass:list'; + +// Testing Sass imports using use syntax +@use 'forwardSyntaxStyles'; + +// Testing node_modules using use and with syntax +@use 'utilities/configurableModule' as configuration; + +:root { + --list-margin-top: calc(1.25 * 1rem); +} + +.label { + display: block; + color: color.adjust(configuration.$list-foreground-color, $blue: 90); +} + +.exampleList { + list-style-type: circle; + margin-top: var(--list-margin-top); + + $colors: deepskyblue, dodgerblue, darkslateblue; + + @each $color in $colors { + $i: list.index($colors, $color); + + &Item#{$i} { + @if $i == 1 { + color: $color; + } @else if $i == 2 { + background-color: $color; + color: color.invert($color); + } @else { + background-color: color.invert($color); + color: $color; + } + } + } +} diff --git a/build-tests/heft-sass-test/src/stylesUseSyntax.module.sass b/build-tests/heft-sass-test/src/stylesUseSyntax.module.sass new file mode 100644 index 00000000000..6d436309d20 --- /dev/null +++ b/build-tests/heft-sass-test/src/stylesUseSyntax.module.sass @@ -0,0 +1,17 @@ +/** + * 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 built-in module using use syntax +@use 'sass:color' + +// Testing Sass imports using use syntax +@use 'forwardSyntaxStyles' + +// Testing node_modules using use and with syntax +@use 'utilities/configurableModule' as configuration with ($button-background-color: color.adjust(#6b717f, $red: 15)) + +.exampleAnchor + @include forwardSyntaxStyles.buttono-block() + @include forwardSyntaxStyles.buttono-style-modifier($background-color: configuration.$button-background-color) diff --git a/build-tests/heft-sass-test/src/test/ExampleApp.test.ts b/build-tests/heft-sass-test/src/test/ExampleApp.test.ts new file mode 100644 index 00000000000..bbc51e195e9 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/ExampleApp.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 { ExampleApp } from '../ExampleApp'; + +describe('ExampleApp', () => { + it('can be tested', () => { + expect(ExampleApp).toBeDefined(); + }); +}); 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..76f4a418ba1 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib-commonjs.test.ts.snap @@ -0,0 +1,247 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..8da1f9cbaf0 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib-css.test.ts.snap @@ -0,0 +1,220 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..d92edd731ab --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib.test.ts.snap @@ -0,0 +1,281 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..cfe3f5336b5 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/sass-ts.test.ts.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..1fb4a9746e6 --- /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'); + 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 new file mode 100644 index 00000000000..7a20dedcc96 --- /dev/null +++ b/build-tests/heft-sass-test/src/utilities/_configurableModule.sass @@ -0,0 +1,5 @@ +/** + * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * */ +$button-background-color: darkcyan !default +$list-foreground-color: steelblue !default \ No newline at end of file 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 new file mode 100644 index 00000000000..47a15dc473d --- /dev/null +++ b/build-tests/heft-sass-test/src/utilities/_useSyntaxRelativeImport.sass @@ -0,0 +1,5 @@ +/** + * This file is not used by the example component. However, it verifies that relative Sass imports using use syntax are successful. + */ + +@use '../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 new file mode 100644 index 00000000000..aab26ef92a8 --- /dev/null +++ b/build-tests/heft-sass-test/tsconfig.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + "rootDirs": ["src", "temp/sass-ts"], + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": 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/heft-sass-test/webpack.config.js b/build-tests/heft-sass-test/webpack.config.js new file mode 100644 index 00000000000..2e5a69d9dbb --- /dev/null +++ b/build-tests/heft-sass-test/webpack.config.js @@ -0,0 +1,81 @@ +'use strict'; + +const path = require('path'); +const Autoprefixer = require('autoprefixer'); +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', + module: { + rules: [ + { + test: /\.s?css$/, + exclude: /node_modules/, + use: [ + // Creates `style` nodes from JS strings + 'style-loader', + // Translates CSS into CommonJS + { + loader: 'css-loader', + options: { + importLoaders: 2, + modules: true + } + }, + // Autoprefix CSS + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [new Autoprefixer()] + } + } + } + ] + } + ] + }, + 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 + }, + 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/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..eb3025cae7a --- /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", "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..1ca17518793 --- /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/heft-jest": "1.0.1", + "@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..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-swc-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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..e6baff5e52b --- /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": ["heft-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/config/heft.json b/build-tests/heft-typescript-composite-test/config/heft.json new file mode 100644 index 00000000000..c0cc9f94228 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/config/heft.json @@ -0,0 +1,38 @@ +/** + * 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", "lib-commonjs"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-typescript-composite-test/config/jest.config.json b/build-tests/heft-typescript-composite-test/config/jest.config.json new file mode 100644 index 00000000000..ee9b78eb63f --- /dev/null +++ b/build-tests/heft-typescript-composite-test/config/jest.config.json @@ -0,0 +1,23 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // Enable code coverage for Jest + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"], + + // Use v8 coverage provider to avoid Babel + "coverageProvider": "v8", + + "testMatch": ["/lib/**/*.test.cjs"], + + "collectCoverageFrom": [ + "lib/**/*.cjs", + "!lib/**/*.d.ts", + "!lib/**/*.test.cjs", + "!lib/**/test/**", + "!lib/**/__tests__/**", + "!lib/**/__fixtures__/**", + "!lib/**/__mocks__/**" + ] +} diff --git a/build-tests/heft-typescript-composite-test/config/rush-project.json b/build-tests/heft-typescript-composite-test/config/rush-project.json new file mode 100644 index 00000000000..93089856e44 --- /dev/null +++ b/build-tests/heft-typescript-composite-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"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-typescript-composite-test/config/typescript.json b/build-tests/heft-typescript-composite-test/config/typescript.json new file mode 100644 index 00000000000..2979f43bfb0 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/config/typescript.json @@ -0,0 +1,43 @@ +/** + * 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": [], + + "emitCjsExtensionForCommonJS": true, + + "buildProjectReferences": true, + + "project": "./tsconfig.json", + + /** + * 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" + // ] + } +} 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 new file mode 100644 index 00000000000..48dba7975a5 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "heft-typescript-composite-test", + "description": "Building this project tests behavior of Heft when the tsconfig.json file uses project references.", + "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": "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.8", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "tslint": "~5.20.1", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/heft-typescript-composite-test/src/chunks/ChunkClass.ts b/build-tests/heft-typescript-composite-test/src/chunks/ChunkClass.ts new file mode 100644 index 00000000000..ddbf7d148c7 --- /dev/null +++ b/build-tests/heft-typescript-composite-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-typescript-composite-test/src/chunks/image.png b/build-tests/heft-typescript-composite-test/src/chunks/image.png new file mode 100644 index 00000000000..a028cfeb69f Binary files /dev/null and b/build-tests/heft-typescript-composite-test/src/chunks/image.png differ diff --git a/build-tests/heft-typescript-composite-test/src/copiedAsset.css b/build-tests/heft-typescript-composite-test/src/copiedAsset.css new file mode 100644 index 00000000000..e9747e441d3 --- /dev/null +++ b/build-tests/heft-typescript-composite-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-typescript-composite-test/src/indexA.ts b/build-tests/heft-typescript-composite-test/src/indexA.ts new file mode 100644 index 00000000000..4394a4bf61e --- /dev/null +++ b/build-tests/heft-typescript-composite-test/src/indexA.ts @@ -0,0 +1,12 @@ +/* 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); + }); + +export {}; diff --git a/build-tests/heft-typescript-composite-test/src/indexB.ts b/build-tests/heft-typescript-composite-test/src/indexB.ts new file mode 100644 index 00000000000..ffbc71e0a7f --- /dev/null +++ b/build-tests/heft-typescript-composite-test/src/indexB.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. + +// eslint-disable-next-line no-console +console.log('dostuff'); + +export {}; diff --git a/build-tests/heft-typescript-composite-test/src/test/ExampleTest.test.ts b/build-tests/heft-typescript-composite-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..565432eacf5 --- /dev/null +++ b/build-tests/heft-typescript-composite-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-typescript-composite-test/src/test/tsconfig.json b/build-tests/heft-typescript-composite-test/src/test/tsconfig.json new file mode 100644 index 00000000000..74fc6381ca0 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/src/test/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "composite": true + }, + "references": [ + { + "path": "../tsconfig.json" + } + ], + "include": ["./**/*.ts"] +} diff --git a/build-tests/heft-typescript-composite-test/src/tsconfig.json b/build-tests/heft-typescript-composite-test/src/tsconfig.json new file mode 100644 index 00000000000..0781a949a08 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/src/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig-base.json", + "compilerOptions": { + "composite": true + }, + "include": ["./**/*.ts"], + "exclude": ["./test/**/*.ts"] +} diff --git a/build-tests/heft-typescript-composite-test/tsconfig-base.json b/build-tests/heft-typescript-composite-test/tsconfig-base.json new file mode 100644 index 00000000000..b5bf6469742 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/tsconfig-base.json @@ -0,0 +1,27 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "webpack-env"], + + "isolatedModules": true, + "verbatimModuleSyntax": true, + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + } +} diff --git a/build-tests/heft-typescript-composite-test/tsconfig-eslint.json b/build-tests/heft-typescript-composite-test/tsconfig-eslint.json new file mode 100644 index 00000000000..a96b85d9be4 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/tsconfig-eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig-base.json", + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests/heft-typescript-composite-test/tsconfig.json b/build-tests/heft-typescript-composite-test/tsconfig.json new file mode 100644 index 00000000000..f54c89e7d8b --- /dev/null +++ b/build-tests/heft-typescript-composite-test/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig-base.json", + "references": [ + { + "path": "./src" + }, + { + "path": "./src/test" + } + ], + "files": [], + "include": [] +} diff --git a/build-tests/heft-typescript-composite-test/tslint.json b/build-tests/heft-typescript-composite-test/tslint.json new file mode 100644 index 00000000000..7dc059cfb49 --- /dev/null +++ b/build-tests/heft-typescript-composite-test/tslint.json @@ -0,0 +1,97 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + + // This rule throws a DeprecationError exception with TypeScript 5.3.x + // "no-shadowed-variable": true, + + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-typescript-v2-test/.gitignore b/build-tests/heft-typescript-v2-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-typescript-v2-test/config/api-extractor.json b/build-tests/heft-typescript-v2-test/config/api-extractor.json new file mode 100644 index 00000000000..e451cf705d0 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/etc" + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/build-tests/heft-typescript-v2-test/config/heft.json b/build-tests/heft-typescript-v2-test/config/heft.json new file mode 100644 index 00000000000..7a5e5b56ad9 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/config/heft.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd", "temp"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-typescript-v2-test/config/jest.config.json b/build-tests/heft-typescript-v2-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-typescript-v2-test/config/rush-project.json b/build-tests/heft-typescript-v2-test/config/rush-project.json new file mode 100644 index 00000000000..a93c6b2720f --- /dev/null +++ b/build-tests/heft-typescript-v2-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": ["dist", "lib", "lib-esnext", "lib-umd"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-typescript-v2-test/config/typescript.json b/build-tests/heft-typescript-v2-test/config/typescript.json new file mode 100644 index 00000000000..433bdbea198 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/config/typescript.json @@ -0,0 +1,21 @@ +/** + * 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": [ + { + "moduleKind": "esnext", + "outFolderName": "lib-esnext" + }, + { + "moduleKind": "umd", + "outFolderName": "lib-umd" + } + ] +} diff --git a/build-tests/heft-typescript-v2-test/etc/heft-typescript-v2-test.api.md b/build-tests/heft-typescript-v2-test/etc/heft-typescript-v2-test.api.md new file mode 100644 index 00000000000..65d0b27c455 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/etc/heft-typescript-v2-test.api.md @@ -0,0 +1,13 @@ +## API Report File for "heft-typescript-v2-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class TestClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/heft-typescript-v2-test/package.json b/build-tests/heft-typescript-v2-test/package.json new file mode 100644 index 00000000000..c00de02bb22 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "heft-typescript-v2-test", + "description": "Building this project tests building with TypeScript v2", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/jest": "ts2.9", + "@types/node": "ts2.9", + "tslint": "~5.20.1", + "typescript": "~2.9.2" + } +} diff --git a/build-tests/heft-typescript-v2-test/src/index.ts b/build-tests/heft-typescript-v2-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-typescript-v2-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-typescript-v2-test/src/test/ExampleTest.test.ts b/build-tests/heft-typescript-v2-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-typescript-v2-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-typescript-v2-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-typescript-v2-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-typescript-v2-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-typescript-v2-test/tsconfig.json b/build-tests/heft-typescript-v2-test/tsconfig.json new file mode 100644 index 00000000000..4596d666047 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/tsconfig.json @@ -0,0 +1,28 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["jest", "node"], + + "module": "commonjs", + "target": "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"] +} diff --git a/build-tests/heft-typescript-v2-test/tslint.json b/build-tests/heft-typescript-v2-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests/heft-typescript-v2-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-typescript-v3-test/.gitignore b/build-tests/heft-typescript-v3-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-typescript-v3-test/config/api-extractor.json b/build-tests/heft-typescript-v3-test/config/api-extractor.json new file mode 100644 index 00000000000..e451cf705d0 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/etc" + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/build-tests/heft-typescript-v3-test/config/heft.json b/build-tests/heft-typescript-v3-test/config/heft.json new file mode 100644 index 00000000000..7a5e5b56ad9 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/config/heft.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd", "temp"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-typescript-v3-test/config/jest.config.json b/build-tests/heft-typescript-v3-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-typescript-v3-test/config/rush-project.json b/build-tests/heft-typescript-v3-test/config/rush-project.json new file mode 100644 index 00000000000..a93c6b2720f --- /dev/null +++ b/build-tests/heft-typescript-v3-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": ["dist", "lib", "lib-esnext", "lib-umd"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-typescript-v3-test/config/typescript.json b/build-tests/heft-typescript-v3-test/config/typescript.json new file mode 100644 index 00000000000..433bdbea198 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/config/typescript.json @@ -0,0 +1,21 @@ +/** + * 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": [ + { + "moduleKind": "esnext", + "outFolderName": "lib-esnext" + }, + { + "moduleKind": "umd", + "outFolderName": "lib-umd" + } + ] +} diff --git a/build-tests/heft-typescript-v3-test/etc/heft-typescript-v3-test.api.md b/build-tests/heft-typescript-v3-test/etc/heft-typescript-v3-test.api.md new file mode 100644 index 00000000000..6bc9edbaf10 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/etc/heft-typescript-v3-test.api.md @@ -0,0 +1,13 @@ +## API Report File for "heft-typescript-v3-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class TestClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/heft-typescript-v3-test/package.json b/build-tests/heft-typescript-v3-test/package.json new file mode 100644 index 00000000000..18da26383ec --- /dev/null +++ b/build-tests/heft-typescript-v3-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "heft-typescript-v3-test", + "description": "Building this project tests building with TypeScript v3", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/jest": "ts3.9", + "@types/node": "ts3.9", + "tslint": "~5.20.1", + "typescript": "~3.9.10" + } +} diff --git a/build-tests/heft-typescript-v3-test/src/index.ts b/build-tests/heft-typescript-v3-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-typescript-v3-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-typescript-v3-test/src/test/ExampleTest.test.ts b/build-tests/heft-typescript-v3-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-typescript-v3-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-typescript-v3-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-typescript-v3-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-typescript-v3-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-typescript-v3-test/tsconfig.json b/build-tests/heft-typescript-v3-test/tsconfig.json new file mode 100644 index 00000000000..a24c429ddf6 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-typescript-v3-test/tslint.json b/build-tests/heft-typescript-v3-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests/heft-typescript-v3-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-typescript-v4-test/.eslintrc.js b/build-tests/heft-typescript-v4-test/.eslintrc.js new file mode 100644 index 00000000000..5d2d42aa7de --- /dev/null +++ b/build-tests/heft-typescript-v4-test/.eslintrc.js @@ -0,0 +1,9 @@ +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +require('@rushstack/eslint-config/patch/modern-module-resolution'); +// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 +require('@rushstack/eslint-config/patch/custom-config-package-names'); + +module.exports = { + extends: ['@rushstack/eslint-config/profile/node'], + parserOptions: { tsconfigRootDir: __dirname } +}; diff --git a/build-tests/heft-typescript-v4-test/.gitignore b/build-tests/heft-typescript-v4-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-typescript-v4-test/config/api-extractor.json b/build-tests/heft-typescript-v4-test/config/api-extractor.json new file mode 100644 index 00000000000..e451cf705d0 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/etc" + }, + "docModel": { + "enabled": true + }, + "dtsRollup": { + "enabled": true, + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/build-tests/heft-typescript-v4-test/config/heft.json b/build-tests/heft-typescript-v4-test/config/heft.json new file mode 100644 index 00000000000..7a5e5b56ad9 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/config/heft.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd", "temp"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-typescript-v4-test/config/jest.config.json b/build-tests/heft-typescript-v4-test/config/jest.config.json new file mode 100644 index 00000000000..c0687c6d488 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + // 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/heft-typescript-v4-test/config/rush-project.json b/build-tests/heft-typescript-v4-test/config/rush-project.json new file mode 100644 index 00000000000..a93c6b2720f --- /dev/null +++ b/build-tests/heft-typescript-v4-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": ["dist", "lib", "lib-esnext", "lib-umd"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-typescript-v4-test/config/typescript.json b/build-tests/heft-typescript-v4-test/config/typescript.json new file mode 100644 index 00000000000..433bdbea198 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/config/typescript.json @@ -0,0 +1,21 @@ +/** + * 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": [ + { + "moduleKind": "esnext", + "outFolderName": "lib-esnext" + }, + { + "moduleKind": "umd", + "outFolderName": "lib-umd" + } + ] +} diff --git a/build-tests/heft-typescript-v4-test/etc/heft-typescript-v4-test.api.md b/build-tests/heft-typescript-v4-test/etc/heft-typescript-v4-test.api.md new file mode 100644 index 00000000000..a7ac069d53b --- /dev/null +++ b/build-tests/heft-typescript-v4-test/etc/heft-typescript-v4-test.api.md @@ -0,0 +1,13 @@ +## API Report File for "heft-typescript-v4-test" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class TestClass { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/heft-typescript-v4-test/package.json b/build-tests/heft-typescript-v4-test/package.json new file mode 100644 index 00000000000..e510684b98e --- /dev/null +++ b/build-tests/heft-typescript-v4-test/package.json @@ -0,0 +1,28 @@ +{ + "name": "heft-typescript-v4-test", + "description": "Building this project tests building with TypeScript v4", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/eslint-config": "4.5.3", + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/jest": "ts4.9", + "@types/node": "ts4.9", + "eslint": "~8.57.0", + "tslint": "~5.20.1", + "typescript": "~4.9.5" + } +} diff --git a/build-tests/heft-typescript-v4-test/src/index.ts b/build-tests/heft-typescript-v4-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-typescript-v4-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-typescript-v4-test/src/test/ExampleTest.test.ts b/build-tests/heft-typescript-v4-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-typescript-v4-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-typescript-v4-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-typescript-v4-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..1ca0d3b526a --- /dev/null +++ b/build-tests/heft-typescript-v4-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-typescript-v4-test/tsconfig.json b/build-tests/heft-typescript-v4-test/tsconfig.json new file mode 100644 index 00000000000..a24c429ddf6 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["jest", "node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/heft-typescript-v4-test/tslint.json b/build-tests/heft-typescript-v4-test/tslint.json new file mode 100644 index 00000000000..56dfd9f2bb6 --- /dev/null +++ b/build-tests/heft-typescript-v4-test/tslint.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-web-rig-library-test/config/jest.config.json b/build-tests/heft-web-rig-library-test/config/jest.config.json new file mode 100644 index 00000000000..22bfd5895cd --- /dev/null +++ b/build-tests/heft-web-rig-library-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-web-rig/profiles/library/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" +} diff --git a/build-tests/heft-web-rig-library-test/config/rig.json b/build-tests/heft-web-rig-library-test/config/rig.json new file mode 100644 index 00000000000..d72946b5042 --- /dev/null +++ b/build-tests/heft-web-rig-library-test/config/rig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-web-rig", + "rigProfile": "library" +} diff --git a/build-tests/heft-web-rig-library-test/config/rush-project.json b/build-tests/heft-web-rig-library-test/config/rush-project.json new file mode 100644 index 00000000000..5cfd2f72217 --- /dev/null +++ b/build-tests/heft-web-rig-library-test/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "extends": "@rushstack/heft-web-rig/profiles/library/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "release"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} 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 new file mode 100644 index 00000000000..65a9734b44a --- /dev/null +++ b/build-tests/heft-web-rig-library-test/package.json @@ -0,0 +1,18 @@ +{ + "name": "heft-web-rig-library-test", + "description": "A test project for Heft that exercises the '@rushstack/heft-web-rig' package", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "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:*", + "@rushstack/heft-web-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/build-tests/heft-web-rig-library-test/src/index.ts b/build-tests/heft-web-rig-library-test/src/index.ts new file mode 100644 index 00000000000..e4938bc39ea --- /dev/null +++ b/build-tests/heft-web-rig-library-test/src/index.ts @@ -0,0 +1,11 @@ +// 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 { + public static getTrue(): boolean { + return true; + } +} diff --git a/build-tests/heft-web-rig-library-test/src/test/example.test.ts b/build-tests/heft-web-rig-library-test/src/test/example.test.ts new file mode 100644 index 00000000000..042c99d819c --- /dev/null +++ b/build-tests/heft-web-rig-library-test/src/test/example.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 { TestClass } from '../index'; + +describe('An example test', () => { + it('Is able to import things', () => { + expect(TestClass.getTrue()).toBe(true); + }); +}); diff --git a/build-tests/heft-web-rig-library-test/tsconfig.json b/build-tests/heft-web-rig-library-test/tsconfig.json new file mode 100644 index 00000000000..6fc03c3fd16 --- /dev/null +++ b/build-tests/heft-web-rig-library-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-web-rig/profiles/library/tsconfig-base.json" +} diff --git a/build-tests/heft-web-rig-library-test/webpack.config.js b/build-tests/heft-web-rig-library-test/webpack.config.js new file mode 100644 index 00000000000..03cadfeca0e --- /dev/null +++ b/build-tests/heft-web-rig-library-test/webpack.config.js @@ -0,0 +1,21 @@ +'use strict'; + +const createWebpackConfig = require('@rushstack/heft-web-rig/profiles/library/webpack-base.config'); + +module.exports = function createConfig(env, argv) { + return createWebpackConfig({ + env: env, + argv: argv, + projectRoot: __dirname, + // Documentation: https://webpack.js.org/configuration/ + configOverride: { + performance: { + hints: env.production ? 'error' : false + // 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: 500000, + // maxAssetSize: 500000 + } + } + }); +}; diff --git a/build-tests/heft-webpack4-everything-test/config/heft.json b/build-tests/heft-webpack4-everything-test/config/heft.json new file mode 100644 index 00000000000..2f7ae591fd6 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/config/heft.json @@ -0,0 +1,66 @@ +/** + * 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"] }], + + "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" + } + } + } + }, + + "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-webpack4-everything-test/config/jest.config.json b/build-tests/heft-webpack4-everything-test/config/jest.config.json new file mode 100644 index 00000000000..331b9187503 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/config/jest.config.json @@ -0,0 +1,11 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // 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/heft-webpack4-everything-test/config/rush-project.json b/build-tests/heft-webpack4-everything-test/config/rush-project.json new file mode 100644 index 00000000000..030d8d0ff0e --- /dev/null +++ b/build-tests/heft-webpack4-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-webpack4-everything-test/config/typescript.json b/build-tests/heft-webpack4-everything-test/config/typescript.json new file mode 100644 index 00000000000..c9a48461bbc --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/config/typescript.json @@ -0,0 +1,58 @@ +/** + * 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" + // ] + }, + + /** + * If true and "isolatedModules" is configured in tsconfig.json, use a worker thread to run transpilation concurrently with type checking and declaration emit. + */ + "useTranspilerWorker": true +} 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 new file mode 100644 index 00000000000..affffe9d6f7 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/package.json @@ -0,0 +1,33 @@ +{ + "name": "heft-webpack4-everything-test", + "description": "Building this project tests every task and config file for Heft when targeting the web browser runtime using Webpack 4", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "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-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:*", + "@types/heft-jest": "1.0.1", + "@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.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 new file mode 100644 index 00000000000..ddbf7d148c7 --- /dev/null +++ b/build-tests/heft-webpack4-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-webpack4-everything-test/src/chunks/image.png b/build-tests/heft-webpack4-everything-test/src/chunks/image.png new file mode 100644 index 00000000000..a028cfeb69f Binary files /dev/null and b/build-tests/heft-webpack4-everything-test/src/chunks/image.png differ diff --git a/build-tests/heft-webpack4-everything-test/src/copiedAsset.css b/build-tests/heft-webpack4-everything-test/src/copiedAsset.css new file mode 100644 index 00000000000..e9747e441d3 --- /dev/null +++ b/build-tests/heft-webpack4-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-webpack4-everything-test/src/indexA.ts b/build-tests/heft-webpack4-everything-test/src/indexA.ts new file mode 100644 index 00000000000..4394a4bf61e --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/src/indexA.ts @@ -0,0 +1,12 @@ +/* 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); + }); + +export {}; diff --git a/build-tests/heft-webpack4-everything-test/src/indexB.ts b/build-tests/heft-webpack4-everything-test/src/indexB.ts new file mode 100644 index 00000000000..ffbc71e0a7f --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/src/indexB.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. + +// eslint-disable-next-line no-console +console.log('dostuff'); + +export {}; diff --git a/build-tests/heft-webpack4-everything-test/src/test/ExampleTest.test.ts b/build-tests/heft-webpack4-everything-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..565432eacf5 --- /dev/null +++ b/build-tests/heft-webpack4-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-webpack4-everything-test/src/test/SourceMapTest.test.ts b/build-tests/heft-webpack4-everything-test/src/test/SourceMapTest.test.ts new file mode 100644 index 00000000000..d1357f910cb --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/src/test/SourceMapTest.test.ts @@ -0,0 +1,121 @@ +// 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; + sourceFileRegex: RegExp; + map: IMapValue | undefined; +} + +const mapTests: IMapTestEntry[] = [ + { + name: 'Test-A', + mapRegex: /^heft-test-A_[\w\d]*\.js.map$/, + sourceFileRegex: /indexA\.ts$/, + map: undefined + }, + { + name: 'Test-B', + mapRegex: /^heft-test-B_[\w\d]*\.js.map$/, + sourceFileRegex: /indexB\.ts$/, + map: undefined + }, + { + name: 'Chunk', + mapRegex: /^[\w\d\.]*chunk_[\w\d]*\.js.map$/, + sourceFileRegex: /ChunkClass\.ts$/, + 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); + } + }); + + // TODO: remove skip when mapping back to .ts files is debugged + it.skip(`${entry.name} has a source that matches the sourceFileRegex`, () => { + if (map.mapObject.sources) { + expect(map.mapObject.sources).toContainEqual(expect.stringMatching(entry.sourceFileRegex)); + } + }); +} diff --git a/build-tests/heft-webpack4-everything-test/tsconfig.json b/build-tests/heft-webpack4-everything-test/tsconfig.json new file mode 100644 index 00000000000..eb547d1f50d --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/tsconfig.json @@ -0,0 +1,28 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-jest", "webpack-env"], + "incremental": true, + "isolatedModules": true, + + "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/heft-webpack4-everything-test/tslint.json b/build-tests/heft-webpack4-everything-test/tslint.json new file mode 100644 index 00000000000..7dc059cfb49 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/tslint.json @@ -0,0 +1,97 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + + // This rule throws a DeprecationError exception with TypeScript 5.3.x + // "no-shadowed-variable": true, + + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-webpack4-everything-test/webpack.config.js b/build-tests/heft-webpack4-everything-test/webpack.config.js new file mode 100644 index 00000000000..c4be9e959c4 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/webpack.config.js @@ -0,0 +1,54 @@ +'use strict'; + +const path = require('path'); +const { ModuleMinifierPlugin } = require('@rushstack/webpack4-module-minifier-plugin'); +const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); + +module.exports = { + mode: 'development', + module: { + rules: [ + { + test: /\.png$/i, + use: [ + { + loader: 'file-loader' + } + ] + }, + { + test: /\.js$/, + enforce: 'pre', + use: ['source-map-loader'] + } + ] + }, + resolve: { + extensions: ['.js', '.json'] + }, + entry: { + 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), + 'heft-test-B': path.join(__dirname, 'lib', 'indexB.js') + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js' + }, + devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier({ + terserOptions: { + ecma: 2020, + mangle: true + }, + verbose: true + }), + sourceMap: true + }) + ] + } +}; diff --git a/build-tests/heft-webpack5-everything-test/config/heft.json b/build-tests/heft-webpack5-everything-test/config/heft.json new file mode 100644 index 00000000000..db369f8f99d --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/config/heft.json @@ -0,0 +1,66 @@ +/** + * 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"] }], + + "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" + } + } + } + }, + + "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-webpack5-everything-test/config/jest.config.json b/build-tests/heft-webpack5-everything-test/config/jest.config.json new file mode 100644 index 00000000000..f22bb14d6d1 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/config/jest.config.json @@ -0,0 +1,12 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // 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/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 new file mode 100644 index 00000000000..030d8d0ff0e --- /dev/null +++ b/build-tests/heft-webpack5-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", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-webpack5-everything-test/config/typescript.json b/build-tests/heft-webpack5-everything-test/config/typescript.json new file mode 100644 index 00000000000..86a32ee3552 --- /dev/null +++ b/build-tests/heft-webpack5-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-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 new file mode 100644 index 00000000000..2c053526382 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/package.json @@ -0,0 +1,36 @@ +{ + "name": "heft-webpack5-everything-test", + "description": "Building this project tests every task and config file for Heft when targeting the web browser runtime using Webpack 5", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:build:ipc": "heft run-watch --only build -- --clean", + "_phase:test": "heft run --only test -- --clean", + "_phase:test:ipc": "heft run-watch --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft-dev-cert-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/node-core-library": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", + "@rushstack/webpack5-module-minifier-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "@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.8.2", + "webpack": "~5.98.0" + } +} diff --git a/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts b/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts new file mode 100644 index 00000000000..ddbf7d148c7 --- /dev/null +++ b/build-tests/heft-webpack5-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-webpack5-everything-test/src/chunks/image.d.png.ts b/build-tests/heft-webpack5-everything-test/src/chunks/image.d.png.ts new file mode 100644 index 00000000000..f38a285dfd9 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/src/chunks/image.d.png.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. + +declare const path: string; + +export default path; diff --git a/build-tests/heft-webpack5-everything-test/src/chunks/image.png b/build-tests/heft-webpack5-everything-test/src/chunks/image.png new file mode 100644 index 00000000000..a028cfeb69f Binary files /dev/null and b/build-tests/heft-webpack5-everything-test/src/chunks/image.png differ diff --git a/build-tests/heft-webpack5-everything-test/src/copiedAsset.css b/build-tests/heft-webpack5-everything-test/src/copiedAsset.css new file mode 100644 index 00000000000..e9747e441d3 --- /dev/null +++ b/build-tests/heft-webpack5-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-webpack5-everything-test/src/indexA.ts b/build-tests/heft-webpack5-everything-test/src/indexA.ts new file mode 100644 index 00000000000..6b4db719843 --- /dev/null +++ b/build-tests/heft-webpack5-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-webpack5-everything-test/src/indexB.ts b/build-tests/heft-webpack5-everything-test/src/indexB.ts new file mode 100644 index 00000000000..2bcd3820a4b --- /dev/null +++ b/build-tests/heft-webpack5-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-webpack5-everything-test/src/test/ExampleTest.test.ts b/build-tests/heft-webpack5-everything-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..565432eacf5 --- /dev/null +++ b/build-tests/heft-webpack5-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-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/src/test/SourceMapTest.test.ts b/build-tests/heft-webpack5-everything-test/src/test/SourceMapTest.test.ts new file mode 100644 index 00000000000..52171383838 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/src/test/SourceMapTest.test.ts @@ -0,0 +1,120 @@ +// 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; + sourceFileRegex: RegExp; + map: IMapValue | undefined; +} + +const mapTests: IMapTestEntry[] = [ + { + name: 'Test-A', + mapRegex: /^heft-test-A_[\w\d]*\.js.map$/, + sourceFileRegex: /indexA\.ts$/, + map: undefined + }, + { + name: 'Test-B', + mapRegex: /^heft-test-B_[\w\d]*\.js.map$/, + sourceFileRegex: /indexB\.ts$/, + map: undefined + }, + { + name: 'Chunk', + mapRegex: /^[\w\d\.]*chunk_[\w\d]*\.js.map$/, + sourceFileRegex: /ChunkClass\.ts$/, + 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).toContainEqual(expect.stringMatching(entry.sourceFileRegex)); + } + }); +} diff --git a/build-tests/heft-webpack5-everything-test/tsconfig.json b/build-tests/heft-webpack5-everything-test/tsconfig.json new file mode 100644 index 00000000000..a6ce628bed0 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/tsconfig.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + + "allowArbitraryExtensions": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["heft-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"] +} diff --git a/build-tests/heft-webpack5-everything-test/tslint.json b/build-tests/heft-webpack5-everything-test/tslint.json new file mode 100644 index 00000000000..7dc059cfb49 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/tslint.json @@ -0,0 +1,97 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 2], + "interface-name": true, + "label-position": true, + "max-line-length": [true, 120], + "member-access": true, + "member-ordering": [ + true, + { + "order": [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-constructor", + "public-instance-method", + "protected-constructor", + "protected-instance-method", + "private-constructor", + "private-instance-method" + ] + } + ], + "no-arg": true, + "no-any": true, + "no-bitwise": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-null-keyword": true, + + // This rule throws a DeprecationError exception with TypeScript 5.3.x + // "no-shadowed-variable": true, + + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "quotemark": [true, "single", "avoid-escape"], + "prefer-const": true, + "radix": true, + "semicolon": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": [ + true, + "call-signature", + "parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-isnan": true, + "variable-name": [true, "check-format", "allow-leading-underscore", "ban-keywords"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] + } +} diff --git a/build-tests/heft-webpack5-everything-test/webpack.config.js b/build-tests/heft-webpack5-everything-test/webpack.config.js new file mode 100644 index 00000000000..25edbf94925 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/webpack.config.js @@ -0,0 +1,54 @@ +'use strict'; + +const path = require('path'); +const { ModuleMinifierPlugin } = require('@rushstack/webpack5-module-minifier-plugin'); +const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: 'production', + module: { + rules: [ + { + test: /\.png$/i, + type: 'asset/resource' + }, + { + test: /\.js$/, + enforce: 'pre', + use: ['source-map-loader'] + } + ] + }, + target: ['web', 'es2020'], + resolve: { + extensions: ['.js', '.json'] + }, + entry: { + 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), + 'heft-test-B': path.join(__dirname, 'lib', 'indexB.js') + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js', + assetModuleFilename: '[name]_[contenthash][ext][query]' + }, + devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier({ + terserOptions: { + ecma: 2020, + mangle: true + }, + verbose: true + }), + sourceMap: true + }) + ] + }, + plugins: [new HtmlWebpackPlugin()] +}; diff --git a/build-tests/heft-webpack5-everything-test/webpack.dev.config.js b/build-tests/heft-webpack5-everything-test/webpack.dev.config.js new file mode 100644 index 00000000000..504bdc6e13c --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/webpack.dev.config.js @@ -0,0 +1,36 @@ +'use strict'; + +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: 'none', + module: { + rules: [ + { + test: /\.png$/i, + type: 'asset/resource' + } + ] + }, + target: ['web', 'es2020'], + resolve: { + extensions: ['.js', '.json'] + }, + entry: { + 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), + 'heft-test-B': path.join(__dirname, 'lib', 'indexB.js') + }, + output: { + path: path.join(__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 HtmlWebpackPlugin()] +}; diff --git a/build-tests/localization-plugin-test-01/.gitignore b/build-tests/localization-plugin-test-01/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/localization-plugin-test-01/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file 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 18a9cfc503a..00000000000 --- a/build-tests/localization-plugin-test-01/build.js +++ /dev/null @@ -1,20 +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-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 new file mode 100644 index 00000000000..f5d98263c8a --- /dev/null +++ b/build-tests/localization-plugin-test-01/config/rush-project.json @@ -0,0 +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": ["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 1ad75a28ca7..7702df1f1ab 100644 --- a/build-tests/localization-plugin-test-01/package.json +++ b/build-tests/localization-plugin-test-01/package.json @@ -4,20 +4,22 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "node build.js", - "serve": "node serve.js" + "build": "heft build --clean", + "serve": "heft start", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/set-webpack-public-path-plugin": "2.4.2", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/localization-plugin": "0.1.3", - "@types/webpack-env": "1.13.0", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "ts-loader": "6.0.0", - "webpack": "~4.31.0", - "webpack-bundle-analyzer": "~3.6.0", - "webpack-cli": "~3.3.2", - "webpack-dev-server": "~3.9.0", - "html-webpack-plugin": "~3.2.0" + "@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:*", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "html-webpack-plugin": "~4.5.2", + "local-node-rig": "workspace:*", + "webpack": "~4.47.0", + "webpack-bundle-analyzer": "~4.5.0", + "webpack-dev-server": "~4.9.3" } } 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 e2ce851c3fc..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'); } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-01/src/indexA.ts b/build-tests/localization-plugin-test-01/src/indexA.ts index d3980eaf35a..5aaba8afbcd 100644 --- a/build-tests/localization-plugin-test-01/src/indexA.ts +++ b/build-tests/localization-plugin-test-01/src/indexA.ts @@ -1,5 +1,14 @@ +// 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(({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); - chunk.doStuff(); -}); +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 400b3ad0871..2bb989b8efe 100644 --- a/build-tests/localization-plugin-test-01/tsconfig.json +++ b/build-tests/localization-plugin-test-01/tsconfig.json @@ -1,12 +1,8 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-web.json", + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "rootDirs": [ - "./src", - "./temp/loc-json-ts/" - ], - "types": [ - "webpack-env" - ] + "module": "esnext", + "moduleResolution": "node", + "rootDirs": ["src", "temp/loc-json-ts"] } } diff --git a/build-tests/localization-plugin-test-01/webpack.config.js b/build-tests/localization-plugin-test-01/webpack.config.js index 409e1eabc68..e3fb41279fd 100644 --- a/build-tests/localization-plugin-test-01/webpack.config.js +++ b/build-tests/localization-plugin-test-01/webpack.config.js @@ -1,44 +1,29 @@ 'use strict'; -const path = require('path'); -const webpack = require('webpack'); - -const { LocalizationPlugin } = require('@rushstack/localization-plugin'); +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'); -module.exports = function(env) { - const configuration = { - mode: 'production', - module: { - rules: [ - { - test: /\.tsx?$/, - loader: require.resolve('ts-loader'), - exclude: /(node_modules)/, - options: { - compiler: require.resolve('@microsoft/rush-stack-compiler-3.5/node_modules/typescript'), - logLevel: 'ERROR', - configFile: path.resolve(__dirname, 'tsconfig.json') - } - } - ] - }, - resolve: { - extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'] - }, +function generateConfiguration(mode, outputFolderName, webpack) { + return { + 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/indexA.js`, + 'localization-test-B': `${__dirname}/lib/indexB.js` }, output: { - path: path.join(__dirname, 'dist'), + path: `${__dirname}/${outputFolderName}`, filename: '[name]_[locale]_[contenthash].js', chunkFilename: '[id].[name]_[locale]_[contenthash].js' }, optimization: { - minimize: false + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new LocalMinifier() + }) + ] }, plugins: [ new webpack.optimize.ModuleConcatenationPlugin(), @@ -52,19 +37,19 @@ module.exports = function(env) { } }, 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({ @@ -75,6 +60,9 @@ module.exports = function(env) { new HtmlWebpackPlugin() ] }; - - return configuration; } + +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) +]; diff --git a/build-tests/localization-plugin-test-02/.gitignore b/build-tests/localization-plugin-test-02/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/localization-plugin-test-02/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file diff --git a/build-tests/localization-plugin-test-02/build.js b/build-tests/localization-plugin-test-02/build.js deleted file mode 100644 index 18a9cfc503a..00000000000 --- a/build-tests/localization-plugin-test-02/build.js +++ /dev/null @@ -1,20 +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-cli/bin/cli'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/localization-plugin-test-02/config/heft.json b/build-tests/localization-plugin-test-02/config/heft.json new file mode 100644 index 00000000000..6d560f084ee --- /dev/null +++ b/build-tests/localization-plugin-test-02/config/heft.json @@ -0,0 +1,47 @@ +/** + * 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": { + "loc-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-localization-typings-plugin", + "options": { + "generatedTsFolder": "temp/loc-json-ts", + "exportAsDefault": { + "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"] + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack4-plugin" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..f5d98263c8a --- /dev/null +++ b/build-tests/localization-plugin-test-02/config/rush-project.json @@ -0,0 +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": ["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 new file mode 100644 index 00000000000..95ea4894e69 --- /dev/null +++ b/build-tests/localization-plugin-test-02/config/typescript.json @@ -0,0 +1,10 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.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/localization/es-es/strings5.resx b/build-tests/localization-plugin-test-02/localization/es-es/strings5.resx new file mode 100644 index 00000000000..322d788e391 --- /dev/null +++ b/build-tests/localization-plugin-test-02/localization/es-es/strings5.resx @@ -0,0 +1,9 @@ + + + + La primera cadena de texto RESX + + + "cadena de texto RESX con comillas" + + \ No newline at end of file diff --git a/build-tests/localization-plugin-test-02/package.json b/build-tests/localization-plugin-test-02/package.json index 16cb1c4fcf0..970b7f6c087 100644 --- a/build-tests/localization-plugin-test-02/package.json +++ b/build-tests/localization-plugin-test-02/package.json @@ -4,22 +4,25 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "node build.js", - "serve": "node serve.js" + "build": "heft build --clean", + "start": "heft start", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/set-webpack-public-path-plugin": "2.4.2", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/localization-plugin": "0.1.3", - "@types/webpack-env": "1.13.0", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "ts-loader": "6.0.0", - "webpack": "~4.31.0", - "webpack-bundle-analyzer": "~3.6.0", - "webpack-cli": "~3.3.2", - "webpack-dev-server": "~3.9.0", - "html-webpack-plugin": "~3.2.0", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-localization-typings-plugin": "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:*", "@types/lodash": "4.14.116", - "lodash": "~4.17.15" + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "html-webpack-plugin": "~4.5.2", + "lodash": "~4.17.15", + "local-node-rig": "workspace:*", + "webpack": "~4.47.0", + "webpack-bundle-analyzer": "~4.5.0", + "webpack-dev-server": "~4.9.3" } } diff --git a/build-tests/localization-plugin-test-02/serve.js b/build-tests/localization-plugin-test-02/serve.js deleted file mode 100644 index ffa5c333f00..00000000000 --- a/build-tests/localization-plugin-test-02/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-02/src/chunks/chunkWithStrings.ts b/build-tests/localization-plugin-test-02/src/chunks/chunkWithStrings.ts index 1bcb409d023..1291aa604b4 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,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import * as lodash from 'lodash'; -import * as strings from './strings2.loc.json'; +import strings from './strings2.loc.json'; export class ChunkWithStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log(lodash.escape(strings.string1)); } -} \ No newline at end of file +} 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 78470d2bd6f..585e18bd6f7 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,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import * as lodash from 'lodash'; export class ChunkWithoutStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log(lodash.escape('STATIC STRING')); } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-02/src/chunks/strings2.loc.json b/build-tests/localization-plugin-test-02/src/chunks/strings2.loc.json index 1bdda294e59..abc4a74f9df 100644 --- a/build-tests/localization-plugin-test-02/src/chunks/strings2.loc.json +++ b/build-tests/localization-plugin-test-02/src/chunks/strings2.loc.json @@ -3,4 +3,4 @@ "value": "string two", "comment": "the second string" } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-02/src/indexA.ts b/build-tests/localization-plugin-test-02/src/indexA.ts index 85ae7747409..65816657a49 100644 --- a/build-tests/localization-plugin-test-02/src/indexA.ts +++ b/build-tests/localization-plugin-test-02/src/indexA.ts @@ -1,20 +1,60 @@ -import { string1 } from './strings1.loc.json'; -import * as strings3 from './strings3.loc.json'; -import * as strings5 from './strings5.resx'; +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. -console.log(string1); +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 +// Blah @lic Foo +// Foo @cc_on bar +/** + * Stuff + * @lic Blah + */ + +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-with-strings' */ './chunks/chunkWithStrings').then(({ ChunkWithStringsClass }) => { - const chunk = new ChunkWithStringsClass(); - chunk.doStuff(); -}); +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(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then(({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); - chunk.doStuff(); -}); +// @ts-expect-error +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); -console.log(strings5.stringWithQuotes); \ No newline at end of file +// 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 9e42d8dac5d..7eb6c75c7e8 100644 --- a/build-tests/localization-plugin-test-02/src/indexB.ts +++ b/build-tests/localization-plugin-test-02/src/indexB.ts @@ -1,6 +1,14 @@ -import { string2 } from './strings3.loc.json'; +// 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'); -console.log(string2); +// 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 832cce59692..012f244687c 100644 --- a/build-tests/localization-plugin-test-02/src/indexC.ts +++ b/build-tests/localization-plugin-test-02/src/indexC.ts @@ -1,4 +1,14 @@ -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') + // 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/src/strings1.loc.json b/build-tests/localization-plugin-test-02/src/strings1.loc.json index da6f5831d81..823129946fd 100644 --- a/build-tests/localization-plugin-test-02/src/strings1.loc.json +++ b/build-tests/localization-plugin-test-02/src/strings1.loc.json @@ -2,5 +2,9 @@ "string1": { "value": "string one", "comment": "the first string" + }, + "__IGNORED_STRING__": { + "value": "ignored string", + "comment": "ignored string" } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-02/src/strings3.loc.json b/build-tests/localization-plugin-test-02/src/strings3.loc.json deleted file mode 100644 index ef51af18caa..00000000000 --- a/build-tests/localization-plugin-test-02/src/strings3.loc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "string1": { - "value": "string three", - "comment": "the third string" - }, - "string2": { - "value": "string four with an ' apostrophe", - "comment": "the fourth string" - }, - "string3": { - "value": "UNUSED STRING", - "comment": "UNUSED STRING" - } -} \ No newline at end of file diff --git a/build-tests/localization-plugin-test-02/src/strings3.resjson b/build-tests/localization-plugin-test-02/src/strings3.resjson new file mode 100644 index 00000000000..b6a221cc406 --- /dev/null +++ b/build-tests/localization-plugin-test-02/src/strings3.resjson @@ -0,0 +1,10 @@ +{ + "string1": "string three with a \\ backslash", + "_string1.comment": "the third string", + + "string2": "string four with an ' apostrophe", + "_string2.comment": "the fourth string", + + "string3": "UNUSED STRING", + "_string3.comment": "UNUSED STRING" +} diff --git a/build-tests/localization-plugin-test-02/src/strings4.loc.json b/build-tests/localization-plugin-test-02/src/strings4.loc.json index f48eafff641..22b9cd09c5a 100644 --- a/build-tests/localization-plugin-test-02/src/strings4.loc.json +++ b/build-tests/localization-plugin-test-02/src/strings4.loc.json @@ -2,5 +2,9 @@ "string1": { "value": "\"String with quotemarks\"", "comment": "string with quotemarks" + }, + "__IGNORED_STRING__": { + "value": "ignored string", + "comment": "ignored string" } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-02/src/strings5.resx b/build-tests/localization-plugin-test-02/src/strings5.resx index d097a436eb5..f2d6a8dd2bc 100644 --- a/build-tests/localization-plugin-test-02/src/strings5.resx +++ b/build-tests/localization-plugin-test-02/src/strings5.resx @@ -63,6 +63,12 @@ "RESX string with quotemarks" RESX string with quotemarks + + + RESX string with newlines and tabs + + RESX string with quotemarks + UNUSED STRING UNUSED STRING diff --git a/build-tests/localization-plugin-test-02/tsconfig.json b/build-tests/localization-plugin-test-02/tsconfig.json index 400b3ad0871..2bb989b8efe 100644 --- a/build-tests/localization-plugin-test-02/tsconfig.json +++ b/build-tests/localization-plugin-test-02/tsconfig.json @@ -1,12 +1,8 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-web.json", + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "rootDirs": [ - "./src", - "./temp/loc-json-ts/" - ], - "types": [ - "webpack-env" - ] + "module": "esnext", + "moduleResolution": "node", + "rootDirs": ["src", "temp/loc-json-ts"] } } diff --git a/build-tests/localization-plugin-test-02/webpack.config.js b/build-tests/localization-plugin-test-02/webpack.config.js index 80e28a3527d..8e424812e6d 100644 --- a/build-tests/localization-plugin-test-02/webpack.config.js +++ b/build-tests/localization-plugin-test-02/webpack.config.js @@ -1,48 +1,42 @@ 'use strict'; -const path = require('path'); -const webpack = require('webpack'); - -const { LocalizationPlugin } = require('@rushstack/localization-plugin'); +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'); -module.exports = function(env) { - const configuration = { - mode: 'development', - module: { - rules: [ - { - test: /\.tsx?$/, - loader: require.resolve('ts-loader'), - exclude: /(node_modules)/, - options: { - compiler: require.resolve('@microsoft/rush-stack-compiler-3.5/node_modules/typescript'), - logLevel: 'ERROR', - configFile: path.resolve(__dirname, 'tsconfig.json') - } - } - ] - }, - resolve: { - extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'] - }, +function generateConfiguration(mode, outputFolderName, webpack) { + return { + mode: mode, 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-A': `${__dirname}/lib/indexA.js`, + 'localization-test-B': `${__dirname}/lib/indexB.js`, + 'localization-test-C': `${__dirname}/lib/indexC.js` }, output: { - path: path.join(__dirname, 'dist'), + path: `${__dirname}/${outputFolderName}`, filename: '[name]_[locale]_[contenthash].js', chunkFilename: '[id].[name]_[locale]_[contenthash].js' }, optimization: { - minimize: false + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier({ + verbose: true + }), + sourceMap: true, + usePortableModules: true, + compressAsyncImports: true + }) + ] }, + devtool: 'source-map', plugins: [ new webpack.optimize.ModuleConcatenationPlugin(), + new webpack.IgnorePlugin({ + resourceRegExp: /^non-existent$/ + }), new LocalizationPlugin({ localizedData: { defaultLocale: { @@ -50,41 +44,37 @@ module.exports = function(env) { fillMissingTranslationStrings: true }, translatedStrings: { - "es-es": { - "./src/strings1.loc.json": { - "string1": "la primera cadena" + 'es-es': { + './src/strings1.loc.json': { + string1: 'la primera cadena de texto' }, - "./src/chunks/strings2.loc.json": { - "string1": "la segunda cadena" + './src/chunks/strings2.loc.json': { + string1: 'la segunda cadena de texto' }, - "./src/strings4.loc.json": { - "string1": "\"Cadena con comillas\"" + './src/strings4.loc.json': { + string1: '"cadena de texto con comillas"' }, - "./src/strings5.resx": { - "string1": "La primera cadena RESX", - "stringWithQuotes": "\"Cadena RESX con comillas\"" - } + './src/strings5.resx': './localization/es-es/strings5.resx' } }, passthroughLocale: { usePassthroughLocale: true, passthroughLocaleName: 'default' - } - }, - typingsOptions: { - generatedTsFolder: path.resolve(__dirname, 'temp', 'loc-json-ts'), - sourceRoot: path.resolve(__dirname, 'src') + }, + normalizeResxNewlines: 'crlf', + ignoreMissingResxComments: true }, localizationStats: { - dropPath: path.resolve(__dirname, 'temp', 'localization-stats.json') - } + dropPath: `${__dirname}/temp/localization-stats.json` + }, + ignoreString: (filePath, stringName) => stringName === '__IGNORED_STRING__' }), 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({ @@ -95,6 +85,9 @@ module.exports = function(env) { new HtmlWebpackPlugin() ] }; - - return configuration; } + +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) +]; diff --git a/build-tests/localization-plugin-test-03/.gitignore b/build-tests/localization-plugin-test-03/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/localization-plugin-test-03/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file 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 18a9cfc503a..00000000000 --- a/build-tests/localization-plugin-test-03/build.js +++ /dev/null @@ -1,20 +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-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 new file mode 100644 index 00000000000..f5d98263c8a --- /dev/null +++ b/build-tests/localization-plugin-test-03/config/rush-project.json @@ -0,0 +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": ["dist-dev", "dist-prod"] + } + ] +} 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/localization/es-es/chunks/strings2.loc.json b/build-tests/localization-plugin-test-03/localization/es-es/chunks/strings2.loc.json new file mode 100644 index 00000000000..ce2cbb4e739 --- /dev/null +++ b/build-tests/localization-plugin-test-03/localization/es-es/chunks/strings2.loc.json @@ -0,0 +1,5 @@ +{ + "string1": { + "value": "la segunda cadena de texto" + } +} diff --git a/build-tests/localization-plugin-test-03/localization/es-es/combinedStringsData.json b/build-tests/localization-plugin-test-03/localization/es-es/combinedStringsData.json new file mode 100644 index 00000000000..7634744ba4d --- /dev/null +++ b/build-tests/localization-plugin-test-03/localization/es-es/combinedStringsData.json @@ -0,0 +1,7 @@ +{ + "./src/strings3.resx.json": { + "string1": "cadena de texto tres con una \n nueva línea y una \t tabulación", + "string2": "cadena de texto cuatro con un ' apóstrofe", + "string3": "UNUSED STRING!" + } +} diff --git a/build-tests/localization-plugin-test-03/package.json b/build-tests/localization-plugin-test-03/package.json index db9a625052d..3c72df77247 100644 --- a/build-tests/localization-plugin-test-03/package.json +++ b/build-tests/localization-plugin-test-03/package.json @@ -4,20 +4,25 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "node build.js", - "serve": "node serve.js" + "build": "heft build --clean", + "serve": "heft start", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/set-webpack-public-path-plugin": "2.4.2", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/localization-plugin": "0.1.3", - "@types/webpack-env": "1.13.0", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", + "@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.8", + "eslint": "~9.37.0", + "html-webpack-plugin": "~4.5.2", + "local-node-rig": "workspace:*", "ts-loader": "6.0.0", - "webpack": "~4.31.0", - "webpack-bundle-analyzer": "~3.6.0", - "webpack-cli": "~3.3.2", - "webpack-dev-server": "~3.9.0", - "html-webpack-plugin": "~3.2.0" + "typescript": "~5.8.2", + "webpack": "~4.47.0", + "webpack-bundle-analyzer": "~4.5.0", + "webpack-dev-server": "~4.9.3" } } 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 22987fa8c2f..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); } -} \ No newline at end of file +} 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 e2ce851c3fc..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'); } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-03/src/chunks/strings2.loc.json b/build-tests/localization-plugin-test-03/src/chunks/strings2.loc.json index 1bdda294e59..abc4a74f9df 100644 --- a/build-tests/localization-plugin-test-03/src/chunks/strings2.loc.json +++ b/build-tests/localization-plugin-test-03/src/chunks/strings2.loc.json @@ -3,4 +3,4 @@ "value": "string two", "comment": "the second string" } -} \ No newline at end of file +} 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 c153fc75b25..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); } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-03/src/indexA.ts b/build-tests/localization-plugin-test-03/src/indexA.ts index 6ba31eacfe9..37d82ce98d3 100644 --- a/build-tests/localization-plugin-test-03/src/indexA.ts +++ b/build-tests/localization-plugin-test-03/src/indexA.ts @@ -1,25 +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.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(); - chunk.doStuff(); -}); +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(); - chunk.doStuff(); -}); +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 9b2807df803..79a3b5bdc16 100644 --- a/build-tests/localization-plugin-test-03/src/indexB.ts +++ b/build-tests/localization-plugin-test-03/src/indexB.ts @@ -1,6 +1,18 @@ -import strings3 from './strings3.loc.json'; +// 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 3ebb7f0ac61..e26a7272c68 100644 --- a/build-tests/localization-plugin-test-03/src/indexC.ts +++ b/build-tests/localization-plugin-test-03/src/indexC.ts @@ -1,4 +1,13 @@ -import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings').then(({ ChunkWithStringsClass }) => { - const chunk = new ChunkWithStringsClass(); - 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-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 832cce59692..e887b69021f 100644 --- a/build-tests/localization-plugin-test-03/src/indexD.ts +++ b/build-tests/localization-plugin-test-03/src/indexD.ts @@ -1,4 +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/src/invalid-strings.loc.json b/build-tests/localization-plugin-test-03/src/invalid-strings.loc.json new file mode 100644 index 00000000000..f2e95185f39 --- /dev/null +++ b/build-tests/localization-plugin-test-03/src/invalid-strings.loc.json @@ -0,0 +1 @@ +"this file is not a localization file and should be ignored" diff --git a/build-tests/localization-plugin-test-03/src/strings1.loc.json b/build-tests/localization-plugin-test-03/src/strings1.loc.json index da6f5831d81..b997eef7518 100644 --- a/build-tests/localization-plugin-test-03/src/strings1.loc.json +++ b/build-tests/localization-plugin-test-03/src/strings1.loc.json @@ -3,4 +3,4 @@ "value": "string one", "comment": "the first string" } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-03/src/strings3.loc.json b/build-tests/localization-plugin-test-03/src/strings3.loc.json deleted file mode 100644 index ef51af18caa..00000000000 --- a/build-tests/localization-plugin-test-03/src/strings3.loc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "string1": { - "value": "string three", - "comment": "the third string" - }, - "string2": { - "value": "string four with an ' apostrophe", - "comment": "the fourth string" - }, - "string3": { - "value": "UNUSED STRING", - "comment": "UNUSED STRING" - } -} \ No newline at end of file diff --git a/build-tests/localization-plugin-test-03/src/strings3.resx.json b/build-tests/localization-plugin-test-03/src/strings3.resx.json new file mode 100644 index 00000000000..70081042a94 --- /dev/null +++ b/build-tests/localization-plugin-test-03/src/strings3.resx.json @@ -0,0 +1,14 @@ +{ + "string1": { + "value": "string three with a \n newline and a \t tab", + "comment": "the third string" + }, + "string2": { + "value": "string four with an ' apostrophe", + "comment": "the fourth string" + }, + "string3": { + "value": "UNUSED STRING", + "comment": "UNUSED STRING" + } +} diff --git a/build-tests/localization-plugin-test-03/src/strings4.loc.json b/build-tests/localization-plugin-test-03/src/strings4.loc.json index f48eafff641..2215f933c17 100644 --- a/build-tests/localization-plugin-test-03/src/strings4.loc.json +++ b/build-tests/localization-plugin-test-03/src/strings4.loc.json @@ -3,4 +3,4 @@ "value": "\"String with quotemarks\"", "comment": "string with quotemarks" } -} \ No newline at end of file +} diff --git a/build-tests/localization-plugin-test-03/src/strings7.resjson b/build-tests/localization-plugin-test-03/src/strings7.resjson new file mode 100644 index 00000000000..0f2ee5b7223 --- /dev/null +++ b/build-tests/localization-plugin-test-03/src/strings7.resjson @@ -0,0 +1,4 @@ +{ + "string": "resjson string", + "_string.comment": "resjson string comment." +} \ No newline at end of file diff --git a/build-tests/localization-plugin-test-03/tsconfig.json b/build-tests/localization-plugin-test-03/tsconfig.json index 400b3ad0871..5fafb6d9808 100644 --- a/build-tests/localization-plugin-test-03/tsconfig.json +++ b/build-tests/localization-plugin-test-03/tsconfig.json @@ -1,12 +1,9 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-web.json", + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "rootDirs": [ - "./src", - "./temp/loc-json-ts/" - ], - "types": [ - "webpack-env" - ] + "module": "esnext", + "moduleResolution": "node", + "incremental": false, + "rootDirs": ["src", "temp/loc-json-ts"] } } diff --git a/build-tests/localization-plugin-test-03/webpack.config.js b/build-tests/localization-plugin-test-03/webpack.config.js index 3886d884d7f..56d3cf532e8 100644 --- a/build-tests/localization-plugin-test-03/webpack.config.js +++ b/build-tests/localization-plugin-test-03/webpack.config.js @@ -1,16 +1,41 @@ 'use strict'; - const path = require('path'); -const webpack = require('webpack'); +const { JsonFile, FileSystem } = require('@rushstack/node-core-library'); -const { LocalizationPlugin } = require('@rushstack/localization-plugin'); +const { LocalizationPlugin } = require('@rushstack/webpack4-localization-plugin'); const { SetPublicPathPlugin } = require('@rushstack/set-webpack-public-path-plugin'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); 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('.')) { + contextRelativePath = `./${contextRelativePath}`; + } -module.exports = function(env) { - const configuration = { - mode: 'production', + const result = {}; + for (const localeName of localeNames) { + const expectedCombinedStringsPath = `${__dirname}/localization/${localeName}/combinedStringsData.json`; + try { + const loadedCombinedStringsPath = JsonFile.load(expectedCombinedStringsPath); + result[localeName] = loadedCombinedStringsPath[contextRelativePath]; + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + // File exists, but reading failed. + throw e; + } + } + } + + return result; +} + +function generateConfiguration(mode, outputFolderName, webpack) { + return { + mode, module: { rules: [ { @@ -18,29 +43,34 @@ module.exports = function(env) { loader: require.resolve('ts-loader'), exclude: /(node_modules)/, options: { - compiler: require.resolve('@microsoft/rush-stack-compiler-3.5/node_modules/typescript'), + 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, 'dist'), + 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(), @@ -50,30 +80,27 @@ module.exports = function(env) { localeName: 'en-us' }, translatedStrings: { - "es-es": { - "./src/strings1.loc.json": { - "string1": "la primera cadena" - }, - "./src/chunks/strings2.loc.json": { - "string1": "la segunda cadena" + 'es-es': { + './src/strings1.loc.json': { + string1: 'la primera cadena de texto' }, - "./src/strings3.loc.json": { - "string1": "la tercera cadena", - "string2": "cuerda cuatro con un ' apóstrofe", - "string3": "UNUSED STRING!" + './src/chunks/strings2.loc.json': './localization/es-es/chunks/strings2.loc.json', + './src/strings4.loc.json': { + string1: '"cadena de texto con comillas"' }, - "./src/strings4.loc.json": { - "string1": "\"Cadena con comillas\"" + './src/strings5.resx': { + string1: 'La primera cadena de texto RESX', + stringWithQuotes: '"cadena de texto RESX con comillas"' }, - "./src/strings5.resx": { - "string1": "La primera cadena RESX", - "stringWithQuotes": "\"Cadena RESX con comillas\"" + './src/chunks/strings6.resx': { + string: 'cadena de texto RESX' }, - "./src/chunks/strings6.resx": { - "string": "cadena RESX" + './src/strings7.resjson': { + string: 'cadena resjson' } } }, + resolveMissingTranslatedStrings: resolveMissingString, passthroughLocale: { usePassthroughLocale: true }, @@ -86,23 +113,26 @@ module.exports = function(env) { append: '##--!!]', prepend: '[!!--##' } - } + }, + normalizeResxNewlines: 'lf' }, typingsOptions: { - generatedTsFolder: path.resolve(__dirname, 'temp', 'loc-json-ts'), - sourceRoot: path.resolve(__dirname, 'src'), + generatedTsFolder: `${__dirname}/temp/loc-json-ts`, + secondaryGeneratedTsFolders: ['lib'], + 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({ @@ -113,6 +143,9 @@ module.exports = function(env) { new HtmlWebpackPlugin() ] }; - - return configuration; } + +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) +]; diff --git a/build-tests/node-library-build-eslint-test/.eslintrc.js b/build-tests/node-library-build-eslint-test/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/build-tests/node-library-build-eslint-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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/build-tests/node-library-build-eslint-test/.npmignore b/build-tests/node-library-build-eslint-test/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/build-tests/node-library-build-eslint-test/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/build-tests/node-library-build-eslint-test/.vscode/launch.json b/build-tests/node-library-build-eslint-test/.vscode/launch.json deleted file mode 100644 index 035e7ab198a..00000000000 --- a/build-tests/node-library-build-eslint-test/.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": "ESLint", - "program": "${workspaceFolder}/node_modules/@microsoft/rush-stack-compiler-3.5/bin/rush-eslint", - "cwd": "${workspaceFolder}", - "args": [ - "--debug", "-f", "unix", "src/**/*.{ts,tsx}" - ] - } - ] -} \ No newline at end of file diff --git a/build-tests/node-library-build-eslint-test/gulpfile.js b/build-tests/node-library-build-eslint-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/node-library-build-eslint-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/node-library-build-eslint-test/package.json b/build-tests/node-library-build-eslint-test/package.json deleted file mode 100644 index 70d91143010..00000000000 --- a/build-tests/node-library-build-eslint-test/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "node-library-build-eslint-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "scripts": { - "build": "gulp test --clean", - "lint": "node node_modules/@microsoft/rush-stack-compiler-3.5/bin/rush-eslint -f unix \"src/**/*.{ts,tsx}\"" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "@microsoft/rush-stack-compiler-3.5": "0.4.5" - } -} diff --git a/build-tests/node-library-build-eslint-test/src/index.ts b/build-tests/node-library-build-eslint-test/src/index.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/node-library-build-eslint-test/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/node-library-build-eslint-test/tsconfig.json b/build-tests/node-library-build-eslint-test/tsconfig.json deleted file mode 100644 index cac4ac48cb1..00000000000 --- a/build-tests/node-library-build-eslint-test/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "node" - ] - } -} diff --git a/build-tests/node-library-build-tslint-test/.npmignore b/build-tests/node-library-build-tslint-test/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/build-tests/node-library-build-tslint-test/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/build-tests/node-library-build-tslint-test/gulpfile.js b/build-tests/node-library-build-tslint-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/node-library-build-tslint-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/node-library-build-tslint-test/package.json b/build-tests/node-library-build-tslint-test/package.json deleted file mode 100644 index ce5ecfa2f03..00000000000 --- a/build-tests/node-library-build-tslint-test/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "node-library-build-tslint-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "@microsoft/rush-stack-compiler-3.5": "0.4.5" - } -} diff --git a/build-tests/node-library-build-tslint-test/src/index.ts b/build-tests/node-library-build-tslint-test/src/index.ts deleted file mode 100644 index ca48574e62a..00000000000 --- a/build-tests/node-library-build-tslint-test/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -class TestClass { -} diff --git a/build-tests/node-library-build-tslint-test/tsconfig.json b/build-tests/node-library-build-tslint-test/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/build-tests/node-library-build-tslint-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/build-tests/node-library-build-tslint-test/tslint.json b/build-tests/node-library-build-tslint-test/tslint.json deleted file mode 100644 index 60db661e377..00000000000 --- a/build-tests/node-library-build-tslint-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.5/includes/tslint.json" -} diff --git a/build-tests/package-extractor-test-01/package.json b/build-tests/package-extractor-test-01/package.json new file mode 100644 index 00000000000..0868658e9d2 --- /dev/null +++ b/build-tests/package-extractor-test-01/package.json @@ -0,0 +1,16 @@ +{ + "name": "package-extractor-test-01", + "description": "This project is used by tests in the @rushstack/package-extractor package.", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "" + }, + "dependencies": { + "package-extractor-test-02": "workspace:*" + }, + "devDependencies": { + "package-extractor-test-03": "workspace:*", + "@types/node": "20.17.19" + } +} diff --git a/build-tests/package-extractor-test-01/src/index.js b/build-tests/package-extractor-test-01/src/index.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-01/src/index.js @@ -0,0 +1 @@ +export {}; diff --git a/build-tests/package-extractor-test-01/src/subdir/file.js b/build-tests/package-extractor-test-01/src/subdir/file.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-01/src/subdir/file.js @@ -0,0 +1 @@ +export {}; diff --git a/build-tests/package-extractor-test-02/package.json b/build-tests/package-extractor-test-02/package.json new file mode 100644 index 00000000000..89f2ec52a65 --- /dev/null +++ b/build-tests/package-extractor-test-02/package.json @@ -0,0 +1,12 @@ +{ + "name": "package-extractor-test-02", + "description": "This project is used by tests in the @rushstack/package-extractor package.", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "" + }, + "dependencies": { + "package-extractor-test-03": "workspace:*" + } +} diff --git a/build-tests/package-extractor-test-02/src/index.js b/build-tests/package-extractor-test-02/src/index.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-02/src/index.js @@ -0,0 +1 @@ +export {}; diff --git a/build-tests/package-extractor-test-03/package.json b/build-tests/package-extractor-test-03/package.json new file mode 100644 index 00000000000..360aa59fde4 --- /dev/null +++ b/build-tests/package-extractor-test-03/package.json @@ -0,0 +1,12 @@ +{ + "name": "package-extractor-test-03", + "description": "This project is used by tests in the @rushstack/package-extractor package.", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "" + }, + "devDependencies": { + "@types/node": "ts3.9" + } +} diff --git a/build-tests/package-extractor-test-03/src/index.js b/build-tests/package-extractor-test-03/src/index.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-03/src/index.js @@ -0,0 +1 @@ +export {}; diff --git a/build-tests/package-extractor-test-04/package.json b/build-tests/package-extractor-test-04/package.json new file mode 100644 index 00000000000..a410383f18e --- /dev/null +++ b/build-tests/package-extractor-test-04/package.json @@ -0,0 +1,12 @@ +{ + "name": "package-extractor-test-04", + "description": "This project is used by tests in the @rushstack/package-extractor package.", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests/package-extractor-test-04/src/index.js b/build-tests/package-extractor-test-04/src/index.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-04/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..a48ffe38513 --- /dev/null +++ b/build-tests/run-scenarios-helpers/package.json @@ -0,0 +1,21 @@ +{ + "name": "run-scenarios-helpers", + "description": "Helpers for the *-scenarios test projects.", + "version": "1.0.0", + "private": true, + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "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..7fc8b403099 --- /dev/null +++ b/build-tests/run-scenarios-helpers/src/index.ts @@ -0,0 +1,244 @@ +// 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 folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(libFolderPath); + 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: 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/.gitignore b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/.gitignore new file mode 100644 index 00000000000..ebd5e58aef4 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/.gitignore @@ -0,0 +1,2 @@ +s3data/.minio.sys +s3data/rush-build-cache/test diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/README.md b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/README.md new file mode 100644 index 00000000000..00270235838 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/README.md @@ -0,0 +1,47 @@ +# About +This package enables integration testing of the `AmazonS3Client` by conncting to an acutal S3 endpoint created using an [min.io](https://min.io) docker image. + +# Prerequisites +Docker and docker compose must be installed + +# Start the S3 endpoint +In this folder run `docker-compose up -d` + +# Stop the S3 endpoint +In this folder run `docker-compose down` + +# Run the test +```sh +# start the docker container: docker-compose up -d +# build the code: rushx build +rushx read-s3-object +``` + +# Testing retries + +To test that requests can be retried start the proxy server which will fail every second request: + +```bash +rushx start-proxy-server +``` + +Update the build-cache.json file: +```json +{ + "cacheProvider": "amazon-s3", + "amazonS3Configuration": { + "s3Endpoint": "http://localhost:9002", + "s3Region": "us-east-1", + "s3Prefix": "rush-build-cache/test", + "isCacheWriteAllowed": true + } +} +``` + +Run the rush rebuild command + +```bash +cd apps +cd rush +RUSH_BUILD_CACHE_CREDENTIAL="minio:minio123" node lib/start-dev.js --debug rebuild --verbose +``` diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/config/rig.json b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-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-amazon-s3-build-cache-plugin-integration-test/docker-compose.yml b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/docker-compose.yml new file mode 100644 index 00000000000..47086ab2ddb --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.7' + +services: + minio: + image: quay.io/minio/minio:RELEASE.2022-01-28T02-28-16Z + command: server --console-address ":9001" /data + ports: + - '9000:9000' + - '9001:9001' + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live'] + interval: 30s + timeout: 20s + retries: 3 + volumes: + - ./s3data:/data 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 new file mode 100644 index 00000000000..0833997b92a --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "rush-amazon-s3-build-cache-plugin-integration-test", + "description": "Tests connecting to an amazon S3 endpoint", + "version": "1.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "read-s3-object": "node ./lib/readObject.js", + "start-proxy-server": "node ./lib/startProxyServer.js" + }, + "devDependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "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": "20.17.19", + "eslint": "~9.37.0", + "http-proxy": "~1.18.1", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/s3data/rush-build-cache/testfile.txt b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/s3data/rush-build-cache/testfile.txt new file mode 100644 index 00000000000..3ae0078d60f --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/s3data/rush-build-cache/testfile.txt @@ -0,0 +1 @@ +remote file from the rush build cache diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/readObject.ts b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/readObject.ts new file mode 100644 index 00000000000..5501dcf6d72 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/readObject.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 { AmazonS3Client } from '@rushstack/rush-amazon-s3-build-cache-plugin'; +import { WebClient } from '@microsoft/rush-lib/lib/utilities/WebClient'; +import { ConsoleTerminalProvider, type ITerminal, Terminal } from '@rushstack/terminal'; + +const webClient: WebClient = new WebClient(); + +const terminal: ITerminal = new Terminal( + new ConsoleTerminalProvider({ + verboseEnabled: true, + debugEnabled: true + }) +); + +const client: AmazonS3Client = new AmazonS3Client( + { + accessKeyId: 'minio', + secretAccessKey: 'minio123', + sessionToken: undefined + }, + { + s3Endpoint: 'http://localhost:9000', + s3Region: 'eu-west-1', + isCacheWriteAllowed: true, + s3Prefix: undefined + }, + webClient, + terminal +); + +async function main(): Promise { + const response: Buffer | undefined = await client.getObjectAsync('rush-build-cache/testfile.txt'); + if (response) { + if (response.toString().match('remote file from the rush build cache')) { + // eslint-disable-next-line no-console + console.log('✅ Success!'); + } else { + // eslint-disable-next-line no-console + console.log('❌ Error: response does not match the file in s3data/rush-build-cache/testfile.txt'); + process.exit(1); + } + } else { + // eslint-disable-next-line no-console + console.error('❌ Error: no response'); + process.exit(1); + } +} +main().catch((err) => { + // eslint-disable-next-line no-console + console.error(err); + process.exit(1); +}); 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 new file mode 100644 index 00000000000..c7c6a54b9a8 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/startProxyServer.ts @@ -0,0 +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 http from 'node:http'; + +import * as httpProxy from 'http-proxy'; + +const proxy: httpProxy = httpProxy.createProxyServer({}); + +const hasFailed: { [k: string]: boolean } = {}; + +let requestCount: number = 0; +const server: http.Server = http.createServer((req, res) => { + requestCount += 1; + + if (req.url && requestCount % 2 === 0 && !hasFailed[req.url]) { + // eslint-disable-next-line no-console + console.log('failing', req.url); + hasFailed[req.url] = true; + res.statusCode = 500; + res.end(); + return; + } else if (req.url) { + // eslint-disable-next-line no-console + console.log('proxying', req.url); + } + + proxy.web(req, res, { + target: 'http://127.0.0.1:9000' + }); +}); + +server.listen(9002); 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 new file mode 100644 index 00000000000..2d179c7173f --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$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, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/rush-lib-declaration-paths-test/.gitignore b/build-tests/rush-lib-declaration-paths-test/.gitignore new file mode 100644 index 00000000000..ed544ab6c2a --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/.gitignore @@ -0,0 +1,2 @@ +# This is generated by the build +src/ \ No newline at end of file diff --git a/build-tests/rush-lib-declaration-paths-test/config/heft.json b/build-tests/rush-lib-declaration-paths-test/config/heft.json new file mode 100644 index 00000000000..857ca850bcb --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/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": { + "cleanFiles": [{ "includeGlobs": ["src"] }], + + "tasksByName": { + "create-src": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./scripts/createSrc.js" + } + } + }, + + "typescript": { + "taskDependencies": ["create-src"] + } + } + } + } +} diff --git a/build-tests/rush-lib-declaration-paths-test/config/rig.json b/build-tests/rush-lib-declaration-paths-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-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-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 new file mode 100644 index 00000000000..d497ba52b6f --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/package.json @@ -0,0 +1,20 @@ +{ + "name": "rush-lib-declaration-paths-test", + "description": "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.", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@microsoft/rush-lib": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js b/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js new file mode 100644 index 00000000000..85005b72b2b --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js @@ -0,0 +1,43 @@ +'use strict'; + +const { FileSystem, Import } = require('@rushstack/node-core-library'); + +const DTS_EXTENSION = '.d.ts'; + +module.exports = { + runAsync: async ({ heftConfiguration: { buildFolderPath } }) => { + const rushLibPath = Import.resolvePackage({ + packageName: '@microsoft/rush-lib', + baseFolderPath: __dirname + }); + + async function* collectDtsPaths(absoluteFolderPath, relativeFolderPath) { + const folderItems = FileSystem.readFolderItems(absoluteFolderPath); + for (const folderItem of folderItems) { + const folderItemName = folderItem.name; + if (folderItem.isDirectory()) { + yield* collectDtsPaths( + `${absoluteFolderPath}/${folderItemName}`, + `${relativeFolderPath}/${folderItemName}` + ); + } else if (folderItemName.endsWith(DTS_EXTENSION)) { + yield `${relativeFolderPath}/${folderItemName.slice(0, -DTS_EXTENSION.length)}`; + } + } + } + + 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`, '@microsoft/rush-lib/lib')) { + indexFileLines.push(`import '${dtsPath}';`); + } + + const srcFolderPath = `${buildFolderPath}/src`; + await FileSystem.writeFileAsync(`${srcFolderPath}/index.ts`, indexFileLines.join('\n'), { + ensureFolderExists: true + }); + } +}; diff --git a/build-tests/rush-lib-declaration-paths-test/tsconfig.json b/build-tests/rush-lib-declaration-paths-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/rush-mcp-example-plugin/.npmignore b/build-tests/rush-mcp-example-plugin/.npmignore new file mode 100644 index 00000000000..dc4a664618b --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!rush-mcp-plugin.json +!*.schema.json 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..2f16f0b0044 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/package.json @@ -0,0 +1,18 @@ +{ + "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:*" + } +} 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..48ff8a67fb9 --- /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/rush-mcp-example-plugin.schema.json", + + /** + * The entry point, whose default export should be a class that implements + */ + "entryPoint": "./lib/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-project-change-analyzer-test/config/rig.json b/build-tests/rush-project-change-analyzer-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-project-change-analyzer-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-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 new file mode 100644 index 00000000000..5d53df9077e --- /dev/null +++ b/build-tests/rush-project-change-analyzer-test/package.json @@ -0,0 +1,22 @@ +{ + "name": "rush-project-change-analyzer-test", + "description": "This is an example project that uses rush-lib's ProjectChangeAnalyzer to ", + "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" + }, + "dependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/rush-project-change-analyzer-test/src/start.ts b/build-tests/rush-project-change-analyzer-test/src/start.ts new file mode 100644 index 00000000000..b26893d81a3 --- /dev/null +++ b/build-tests/rush-project-change-analyzer-test/src/start.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { RushConfiguration, ProjectChangeAnalyzer, type RushConfigurationProject } from '@microsoft/rush-lib'; +import { Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; + +async function runAsync(): Promise { + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ + startingFolder: process.cwd() + }); + + //#region Step 1: Get the list of changed projects + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + + const changedProjects: Set = await projectChangeAnalyzer.getChangedProjectsAsync({ + targetBranchName: rushConfiguration.repositoryDefaultBranch, + terminal, + + includeExternalDependencies: true, + enableFiltering: false + }); + //#endregion + + //#region Step 2: Expand all consumers + for (const project of changedProjects) { + for (const consumer of project.consumingProjects) { + changedProjects.add(consumer); + } + } + //#endregion + + //#region Step 3: Print the list of projects that were changed and their consumers + terminal.writeLine('Projects needing validation due to changes: '); + const namesOfProjectsNeedingValidation: string[] = Array.from( + changedProjects, + (project) => project.packageName + ).sort(); + for (const nameOfProjectsNeedingValidation of namesOfProjectsNeedingValidation) { + terminal.writeLine(` - ${nameOfProjectsNeedingValidation}`); + } + //#endregion +} + +process.exitCode = 1; +runAsync() + .then(() => { + process.exitCode = 0; + }) + // eslint-disable-next-line no-console + .catch(console.error); diff --git a/build-tests/rush-project-change-analyzer-test/tsconfig.json b/build-tests/rush-project-change-analyzer-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/rush-project-change-analyzer-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/.gitignore b/build-tests/rush-redis-cobuild-plugin-integration-test/.gitignore new file mode 100644 index 00000000000..97e8499abcc --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/.gitignore @@ -0,0 +1 @@ +redis-data/dump.rdb \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/.vscode/tasks.json b/build-tests/rush-redis-cobuild-plugin-integration-test/.vscode/tasks.json new file mode 100644 index 00000000000..93aa001729c --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/.vscode/tasks.json @@ -0,0 +1,83 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "cobuild", + "dependsOrder": "sequence", + "dependsOn": ["update", "_cobuild"], + "problemMatcher": [] + }, + { + "type": "shell", + "label": "_cobuild", + "dependsOn": ["build 1", "build 2"], + "problemMatcher": [] + }, + { + "type": "shell", + "label": "update", + "command": "node ../../lib/runRush.js update", + "problemMatcher": [], + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "dedicated", + "showReuseMessage": true, + "clear": false + }, + "options": { + "cwd": "${workspaceFolder}/sandbox/repo" + } + }, + { + "type": "shell", + "label": "build 1", + "command": "node ../../lib/runRush.js --debug cobuild --timeline --parallelism 1 --verbose", + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}/sandbox/repo", + "env": { + "RUSH_COBUILD_CONTEXT_ID": "integration-test", + "RUSH_COBUILD_RUNNER_ID": "runner1", + "RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED": "1", + "REDIS_PASS": "redis123" + } + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + }, + "group": "build" + }, + { + "type": "shell", + "label": "build 2", + "command": "node ../../lib/runRush.js --debug cobuild --timeline --parallelism 1 --verbose", + "problemMatcher": [], + "options": { + "cwd": "${workspaceFolder}/sandbox/repo", + "env": { + "RUSH_COBUILD_CONTEXT_ID": "integration-test", + "RUSH_COBUILD_RUNNER_ID": "runner2", + "RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED": "1", + "REDIS_PASS": "redis123" + } + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + }, + "group": "build" + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/README.md b/build-tests/rush-redis-cobuild-plugin-integration-test/README.md new file mode 100644 index 00000000000..0412bcc358d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/README.md @@ -0,0 +1,173 @@ +# About + +This package enables integration testing of the `RedisCobuildLockProvider` by connecting to an actual Redis created using an [redis](https://hub.docker.com/_/redis) docker image. + +# Prerequisites + +Docker and docker compose must be installed + +# Start the Redis + +In this folder run `docker-compose up -d` + +# Stop the Redis + +In this folder run `docker-compose down` + +# Install and build the integration test code + +```sh +rush update +rush build -t rush-redis-cobuild-plugin-integration-test +``` + +# Run the test for lock provider + +```sh +# start the docker container: docker-compose up -d +# build the code: rushx build +rushx test-lock-provider +``` + +# Integration test in sandbox repo + +Sandbox repo folder: **build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo** + +```sh +cd sandbox/repo +node ../../lib/runRush.js update +``` + +You can also test sharded operations with cobuilds using the **build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo** +```sh +cd sandbox/sharded-repo +node ../../lib/runRush.js update +``` +You should expect to see multiple shards for operations `a` (15 shards), `b` (75) and `h` (50) and `e` (75). + +#### Case 1: Normal build, Cobuild is disabled because of missing RUSH_COBUILD_CONTEXT_ID + +1. Write to build cache + +```sh +rm -rf common/temp/build-cache && node ../../lib/runRush.js --debug cobuild +``` + +2. Read from build cache + +```sh +node ../../lib/runRush.js --debug cobuild +``` + +Expected behavior: Cobuild feature is disabled. Build cache is saved/restored as normal. + +#### Case 2: Cobuild enabled by specifying RUSH_COBUILD_CONTEXT_ID and Redis authentication + +1. Clear redis server + +```sh +(cd ../.. && docker compose down && docker compose up -d) +``` + +2. Run cobuilds + +```sh +rm -rf common/temp/build-cache && RUSH_COBUILD_CONTEXT_ID=foo REDIS_PASS=redis123 RUSH_COBUILD_RUNNER_ID=runner1 node ../../lib/runRush.js --debug cobuild +``` + +Expected behavior: Cobuild feature is enabled. Run command successfully. +You can also see cobuild related logs in the terminal. + +```sh +Running cobuild (runner foo/runner1) +Analyzing repo state... DONE (0.11 seconds) + +Executing a maximum of 10 simultaneous processes... + +==[ b (build) ]====================================================[ 1 of 9 ]== +Get completed_state(cobuild:completed:foo:2e477baf39a85b28fc40e63b417692fe8afcc023)_package(b)_phase(_phase:build): SUCCESS;2e477baf39a85b28fc40e63b417692fe8afcc023 +Get completed_state(cobuild:completed:foo:cfc620db4e74a6f0db41b1a86d0b5402966b97f3)_package(a)_phase(_phase:build): SUCCESS;cfc620db4e74a6f0db41b1a86d0b5402966b97f3 +Successfully acquired lock(cobuild:lock:foo:4c36160884a7a502f9894e8f0adae05c45c8cc4b)_package(b)_phase(_phase:build) to runner(runner1) and it expires in 30s +``` + +#### Case 3: Cobuild enabled, run two cobuild commands in parallel + +> Note: This test requires Visual Studio Code to be installed. + +1. Open predefined `.vscode/redis-cobuild.code-workspace` in Visual Studio Code. + +2. Clear redis server + +```sh +# Under rushstack/build-tests/rush-redis-cobuild-plugin-integration-test +docker compose down && docker compose up -d +``` + +3. Clear build cache + +```sh +# Under rushstack/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo +rm -rf common/temp/build-cache +``` + +4. Open command palette (Ctrl+Shift+P or Command+Shift+P) and select `Tasks: Run Task` and select `cobuild`. + +> In this step, two dedicated terminal windows will open. Running `rush cobuild` command under sandbox repo respectively. + +Expected behavior: Cobuild feature is enabled, cobuild related logs out in both terminals. + +#### Case 4: Cobuild enabled, run two cobuild commands in parallel, one of them failed + +> Note: This test requires Visual Studio Code to be installed. + +1. Open predefined `.vscode/redis-cobuild.code-workspace` in Visual Studio Code. + +2. Making the cobuild command of project "A" fails + +**sandbox/repo/projects/a/package.json** + +```diff + "scripts": { +- "_phase:build": "node ../build.js a", ++ "_phase:build": "exit 1", + } +``` + +3. Clear redis server + +```sh +# Under rushstack/build-tests/rush-redis-cobuild-plugin-integration-test +docker compose down && docker compose up -d +``` + +4. Clear build cache + +```sh +# Under rushstack/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo +rm -rf common/temp/build-cache +``` + +5. Open command palette (Ctrl+Shift+P or Command+Shift+P) and select `Tasks: Run Task` and select `cobuild`. + +Expected behavior: Cobuild feature is enabled, cobuild related logs out in both terminals. These two cobuild commands fail because of the failing build of project "A". And, one of them restored the failing build cache created by the other one. + +#### Case 5: Sharded cobuilds + +Enable the `allowCobuildWithoutCache` experiment in `experiments.json`. + +Navigate to the sandbox for sharded cobuilds, +```sh +cd sandbox/sharded-repo +``` + +Next, start up your Redis instance, +```sh +docker compose down && docker compose up -d +``` + +Then, open 2 terminals and run this in each (changing the RUSH_COBUILD_RUNNER_ID across the 2 terminals), +```sh +rm -rf common/temp/build-cache && RUSH_COBUILD_CONTEXT_ID=foo REDIS_PASS=redis123 RUSH_COBUILD_RUNNER_ID=runner1 node ../../lib/runRush.js cobuild -p 10 --timeline +``` + +If all goes well, you should see a bunch of operation with `- shard xx/yy`. Operations `h (build)` and `e (build)` are both sharded heavily and should be cobuild compatible. To validate changes you're making, ensure that the timeline view for all of the shards of those 2 operations are cobuilt across both terminals. If they're not, something is wrong with your update. \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/config/rig.json b/build-tests/rush-redis-cobuild-plugin-integration-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-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-redis-cobuild-plugin-integration-test/docker-compose.yml b/build-tests/rush-redis-cobuild-plugin-integration-test/docker-compose.yml new file mode 100644 index 00000000000..2b9a3f3722b --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3.7' + +services: + redis: + image: redis:6.2.10-alpine + command: redis-server --save "" --loglevel warning --requirepass redis123 + ports: + - '6379:6379' + volumes: + - ./redis-data:/data 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 new file mode 100644 index 00000000000..309fe18fd9e --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/package.json @@ -0,0 +1,24 @@ +{ + "name": "rush-redis-cobuild-plugin-integration-test", + "version": "1.0.0", + "private": true, + "description": "Tests connecting to an redis server", + "license": "MIT", + "scripts": { + "_phase:build": "heft build --clean", + "build": "heft build --clean", + "test-lock-provider": "node ./lib/testLockProvider.js" + }, + "devDependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-redis-cobuild-plugin": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/http-proxy": "~1.17.8", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "http-proxy": "~1.18.1", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/.gitignore b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/.gitignore new file mode 100644 index 00000000000..9f8a577215f --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/.gitignore @@ -0,0 +1,8 @@ +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +projects/*/dist/ +*.log +node_modules/ + diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json new file mode 100644 index 00000000000..c27270adc35 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json @@ -0,0 +1,4 @@ +{ + "url": "redis://localhost:6379", + "passwordEnvironmentVariable": "REDIS_PASS" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/build-cache.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/build-cache.json new file mode 100644 index 00000000000..d09eaa6a04c --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/build-cache.json @@ -0,0 +1,92 @@ +/** + * This configuration file manages Rush's build cache feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. + * + * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. + */ + "buildCacheEnabled": true, + + /** + * (Required) Choose where project build outputs will be cached. + * + * Possible values: "local-only", "azure-blob-storage", "amazon-s3" + */ + "cacheProvider": "local-only", + + /** + * Setting this property overrides the cache entry ID. If this property is set, it must contain + * a [hash] token. + * + * Other available tokens: + * - [projectName] + * - [projectName:normalize] + * - [phaseName] + * - [phaseName:normalize] + * - [phaseName:trimPrefix] + */ + // "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]" + + /** + * Use this configuration with "cacheProvider"="azure-blob-storage" + */ + "azureBlobStorageConfiguration": { + /** + * (Required) The name of the the Azure storage account to use for build cache. + */ + // "storageAccountName": "example", + /** + * (Required) The name of the container in the Azure storage account to use for build cache. + */ + // "storageContainerName": "my-container", + /** + * The Azure environment the storage account exists in. Defaults to AzurePublicCloud. + * + * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" + */ + // "azureEnvironment": "AzurePublicCloud", + /** + * An optional prefix for cache item blob names. + */ + // "blobPrefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + }, + + /** + * Use this configuration with "cacheProvider"="amazon-s3" + */ + "amazonS3Configuration": { + /** + * (Required unless s3Endpoint is specified) The name of the bucket to use for build cache. + * Example: "my-bucket" + */ + // "s3Bucket": "my-bucket", + /** + * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. + * This should not include any path; use the s3Prefix to set the path. + * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" + */ + // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", + /** + * (Required) The Amazon S3 region of the bucket to use for build cache. + * Example: "us-east-1" + */ + // "s3Region": "us-east-1", + /** + * An optional prefix ("folder") for cache items. It should not start with "/". + */ + // "s3Prefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/cobuild.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/cobuild.json new file mode 100644 index 00000000000..4626f2211d4 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/cobuild.json @@ -0,0 +1,22 @@ +/** + * This configuration file manages Rush's cobuild feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. + * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, + * otherwise the cobuild feature will be disabled. + */ + "cobuildFeatureEnabled": true, + + /** + * (Required) Choose where cobuild lock will be acquired. + * + * The lock provider is registered by the rush plugins. + * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. + */ + "cobuildLockProvider": "redis" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/command-line.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/command-line.json new file mode 100644 index 00000000000..c8c1ccc022d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/command-line.json @@ -0,0 +1,336 @@ +/** + * This configuration file defines custom commands for the "rush" command-line. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + + /** + * Custom "commands" introduce new verbs for the command-line. To see the help for these + * example commands, try "rush --help", "rush my-bulk-command --help", or + * "rush my-global-command --help". + */ + "commands": [ + { + "commandKind": "phased", + "summary": "Concurrent version of rush build", + "name": "cobuild", + "safeForSimultaneousRushProcesses": true, + "enableParallelism": true, + "incremental": true, + "phases": ["_phase:pre-build", "_phase:build"] + } + + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "bulk" commands are invoked separately for each project. Rush will look in + // * each project's package.json file for a "scripts" entry whose name matches the + // * command name. By default, the command will run for every project in the repo, + // * according to the dependency graph (similar to how "rush build" works). + // * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. + // */ + // "commandKind": "bulk", + // + // /** + // * (Required) The name that will be typed as part of the command line. This is also the name + // * of the "scripts" hook in the project's package.json file. + // * The name should be comprised of lower case words separated by hyphens or colons. The name should include an + // * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands + // * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). + // * + // * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command + // * and will call the "rebuild" script instead of the "build" script. + // */ + // "name": "my-bulk-command", + // + // /** + // * (Required) A short summary of the custom command to be shown when printing command line + // * help, e.g. "rush --help". + // */ + // "summary": "Example bulk custom command", + // + // /** + // * A detailed description of the command to be shown when printing command line + // * help (e.g. "rush --help my-command"). + // * If omitted, the "summary" text will be shown instead. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "This is an example custom command that runs separately for each project", + // + // /** + // * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously + // * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the + // * same time.) If your command makes sense to run concurrently with other operations, + // * set "safeForSimultaneousRushProcesses" to true to disable this protection. + // * + // * In particular, this is needed for custom scripts that invoke other Rush commands. + // */ + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) If true, then this command is safe to be run in parallel, i.e. executed + // * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism + // * projects will not start processing until their dependencies have completed processing. + // */ + // "enableParallelism": 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 + // * you can set "ignoreDependencyOrder" to true to increase parallelism. + // */ + // "ignoreDependencyOrder": false, + // + // /** + // * Normally Rush requires that each project's package.json has a "scripts" entry matching + // * the custom command name. To disable this check, set "ignoreMissingScript" to true; + // * projects with a missing definition will be skipped. + // */ + // "ignoreMissingScript": false, + // + // /** + // * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: + // * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". + // * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. + // * - If the shell script returns a zero process exit code but writes something to its stderr stream, + // * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent + // * Rush from processing downstream projects. + // * + // * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because + // * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. + // * In an active monorepo, we've found that if you allow any warnings in your main branch, it inadvertently + // * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings + // * have accumulated that warnings no longer serve any useful purpose. + // * + // * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. + // * In that case, it's strongly recommended to fix the task. However, as a workaround you can set + // * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. + // * + // * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. + // */ + // "allowWarningsInSuccessfulBuild": false, + // + // /** + // * If true then this command will be incremental like the built-in "build" command + // */ + // "incremental": false, + // + // /** + // * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush + // * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a + // * change is detected, the command will be invoked again for the changed project and any selected projects that + // * directly or indirectly depend on it. + // * + // * For details, refer to the website article "Using watch mode". + // */ + // "watchForChanges": false, + // + // /** + // * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of + // * projects' own folders. + // */ + // "disableBuildCache": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "global" commands are invoked once for the entire repo. + // */ + // "commandKind": "global", + // + // "name": "my-global-command", + // "summary": "Example global custom command", + // "description": "This is an example custom command that runs once for the entire repo", + // + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) A script that will be invoked using the OS shell. The working directory will be + // * the folder that contains rush.json. If custom parameters are associated with this command, their + // * values will be appended to the end of this string. + // */ + // "shellCommand": "node common/scripts/my-global-command.js", + // + // /** + // * If your "shellCommand" script depends on NPM packages, the recommended best practice is + // * to make it into a regular Rush project that builds using your normal toolchain. In cases where + // * the command needs to work without first having to run "rush build", the recommended practice + // * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. + // * + // * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with + // * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to + // * install these dependencies before an associated command is invoked. Autoinstallers have the + // * advantage that they work even in a branch where "rush install" is broken, which makes them a + // * good solution for Git hook scripts. But they have the disadvantages of not being buildable + // * projects, and of increasing the overall installation footprint for your monorepo. + // * + // * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. + // * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and + // * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when + // * invoking the "shellCommand". + // */ + // // "autoinstallerName": "my-task" + // } + ], + + "phases": [ + { + /** + * The name of the phase. Note that this value must start with the \"_phase:\" prefix. + */ + "name": "_phase:build", + /** + * The dependencies of this phase. + */ + "dependencies": { + "upstream": ["_phase:build"], + "self": ["_phase:pre-build"] + } + }, + { + /** + * The name of the phase. Note that this value must start with the \"_phase:\" prefix. + */ + "name": "_phase:pre-build", + /** + * The dependencies of this phase. + */ + "dependencies": { + "upstream": ["_phase:build"] + }, + "missingScriptBehavior": "silent" + } + ], + + /** + * Custom "parameters" introduce new parameters for specified Rush command-line commands. + * For example, you might define a "--production" parameter for the "rush build" command. + */ + "parameters": [ + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. + // */ + // "parameterKind": "flag", + // + // /** + // * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. + // */ + // "longName": "--my-flag", + // + // /** + // * An optional alternative short name for the parameter. It must be a dash followed by a single + // * lower-case or upper-case letter, which is case-sensitive. + // * + // * NOTE: The Rush developers recommend that automation scripts should always use the long name + // * to improve readability. The short name is only intended as a convenience for humans. + // * The alphabet letters run out quickly, and are difficult to memorize, so *only* use + // * a short name if you expect the parameter to be needed very often in everyday operations. + // */ + // "shortName": "-m", + // + // /** + // * (Required) A long description to be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", + // + // /** + // * (Required) A list of custom commands and/or built-in Rush commands that this parameter may + // * be used with. The parameter will be appended to the shell command that Rush invokes. + // */ + // "associatedCommands": ["build", "rebuild"] + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "string" is a custom command-line parameter whose value is a simple text string. + // */ + // "parameterKind": "string", + // "longName": "--my-string", + // "description": "A custom string parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * The name of the argument, which will be shown in the command-line help. + // * + // * For example, if the parameter name is '--count" and the argument name is "NUMBER", + // * then the command-line help would display "--count NUMBER". The argument name must + // * be comprised of upper-case letters, numbers, and underscores. It should be kept short. + // */ + // "argumentName": "SOME_TEXT", + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + // * allowable alternatives. + // */ + // "parameterKind": "choice", + // "longName": "--my-choice", + // "description": "A custom choice parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false, + // + // /** + // * Normally if a parameter is omitted from the command line, it will not be passed + // * to the shell command. this value will be inserted by default. Whereas if a "defaultValue" + // * is defined, the parameter will always be passed to the shell command, and will use the + // * default value if unspecified. The value must be one of the defined alternatives. + // */ + // "defaultValue": "vanilla", + // + // /** + // * (Required) A list of alternative argument values that can be chosen for this parameter. + // */ + // "alternatives": [ + // { + // /** + // * A token that is one of the alternatives that can be used with the choice parameter, + // * e.g. "vanilla" in "--flavor vanilla". + // */ + // "name": "vanilla", + // + // /** + // * A detailed description for the alternative that can be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "Use the vanilla flavor (the default)" + // }, + // + // { + // "name": "chocolate", + // "description": "Use the chocolate flavor" + // }, + // + // { + // "name": "strawberry", + // "description": "Use the strawberry flavor" + // } + // ] + // } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/experiments.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/experiments.json new file mode 100644 index 00000000000..fef826208c3 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/experiments.json @@ -0,0 +1,55 @@ +/** + * This configuration file allows repo maintainers to enable and disable experimental + * Rush features. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", + + /** + * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead for faster installs. + */ + "usePnpmFrozenLockfileForRushInstall": true, + + /** + * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. + */ + "usePnpmPreferFrozenLockfileForRushUpdate": true, + + /** + * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. + * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not + * cause hash changes. + */ + "omitImportersFromPreventManualShrinkwrapChanges": true, + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + // "noChmodFieldInTarHeaderNormalization": true, + + /** + * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. + * This will not replay warnings from the cached build. + */ + // "buildCacheWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, the phased commands feature is enabled. To use this feature, create a "phased" command + * in common/config/rush/command-line.json. + */ + "phasedCommands": true + + /** + * If true, perform a clean install after when running `rush install` or `rush update` if the + * `.npmrc` file has changed since the last install. + */ + // "cleanInstallAfterNpmrcChanges": true, + + /** + * If true, print the outputs of shell commands defined in event hooks to the console. + */ + // "printEventHooksOutputToConsole": true +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/pnpm-lock.yaml b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/pnpm-lock.yaml new file mode 100644 index 00000000000..98b22e9d424 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/pnpm-lock.yaml @@ -0,0 +1,52 @@ +lockfileVersion: 5.4 + +importers: + + .: + specifiers: {} + + ../../projects/a: + specifiers: {} + + ../../projects/b: + specifiers: {} + + ../../projects/c: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/d: + specifiers: + b: workspace:* + c: workspace:* + dependencies: + b: link:../b + c: link:../c + + ../../projects/e: + specifiers: + b: workspace:* + d: workspace:* + dependencies: + b: link:../b + d: link:../d + + ../../projects/f: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/g: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/h: + specifiers: + a: workspace:* + dependencies: + a: link:../a diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/repo-state.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/repo-state.json new file mode 100644 index 00000000000..0e7b144099d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/config/rush/repo-state.json @@ -0,0 +1,4 @@ +// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. +{ + "preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rush-pnpm.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rush-pnpm.js new file mode 100644 index 00000000000..72a7bfdf088 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rush-pnpm.js @@ -0,0 +1,28 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rush-pnpm command. +// +// An example usage would be: +// +// node common/scripts/install-run-rush-pnpm.js pnpm-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ + +/******/ (() => { // 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'); +//# 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/repo/common/scripts/install-run-rush.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rush.js new file mode 100644 index 00000000000..008e64411b7 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rush.js @@ -0,0 +1,215 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run-rush.js install +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ 657147: +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("fs"); + +/***/ }), + +/***/ 371017: +/*!***********************!*\ + !*** external "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. +(() => { +/*!************************************************!*\ + !*** ./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 */ + + +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 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}). ` + + `The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` + + 'using an unexpected syntax.'); + } +} +function _getBin(scriptName) { + switch (scriptName.toLowerCase()) { + case 'install-run-rush-pnpm.js': + return 'rush-pnpm'; + case 'install-run-rushx.js': + return 'rushx'; + default: + 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) { + 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) { + 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 + }; + } + 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) { + 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`); + } + process.exit(1); + } + 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.`); + } + return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); + }); +} +_run(); +//# sourceMappingURL=install-run-rush.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run-rush.js.map \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rushx.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rushx.js new file mode 100644 index 00000000000..0a0235f29a3 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run-rushx.js @@ -0,0 +1,28 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rushx command. +// +// An example usage would be: +// +// node common/scripts/install-run-rushx.js custom-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ + +/******/ (() => { // 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'); +//# 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/repo/common/scripts/install-run.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run.js new file mode 100644 index 00000000000..804dfd390d9 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/common/scripts/install-run.js @@ -0,0 +1,721 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where a Node tool may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the specified +// version of the specified tool (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ + +/******/ (() => { // 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 + + +/** + * 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(sourceNpmrcPath, extraLines = []) { + const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); + if (combinedNpmrcFromCache !== undefined) { + return combinedNpmrcFromCache; + } + let npmrcFileLines = fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n'); + npmrcFileLines.push(...extraLines); + 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; + } + } + } + } + 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; +} +/** + * As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims + * unusable lines from the .npmrc file. + * + * Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in + * the .npmrc file to provide different authentication tokens for different registry. + * However, if the environment variable is undefined, it expands to an empty string, which + * produces a valid-looking mapping with an invalid URL that causes an error. Instead, + * we'd prefer to skip that line and continue looking in other places such as the user's + * home directory. + * + * @returns + * The text of the the .npmrc with lines containing undefined variables commented out. + */ +function _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath, extraLines) { + logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose + logger.info(` --> "${targetNpmrcPath}"`); + const combinedNpmrc = _trimNpmrcFile(sourceNpmrcPath, extraLines); + fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); + return combinedNpmrc; +} +/** + * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. + * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. + * + * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc() + * + * @returns + * The text of the the synced .npmrc, if one exists. If one does not exist, then undefined is returned. + */ +function syncNpmrc(sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish, logger = { + // eslint-disable-next-line no-console + info: console.log, + // eslint-disable-next-line no-console + error: console.error +}, extraLines) { + 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)) { + // Ensure the target folder exists + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + return _copyAndTrimNpmrcFile(logger, sourceNpmrcPath, targetNpmrcPath, extraLines); + } + 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}`); + } +} +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 + +/***/ }), + +/***/ 532081: +/*!********************************!*\ + !*** external "child_process" ***! + \********************************/ +/***/ ((module) => { + +module.exports = require("child_process"); + +/***/ }), + +/***/ 657147: +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("fs"); + +/***/ }), + +/***/ 822037: +/*!*********************!*\ + !*** external "os" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("os"); + +/***/ }), + +/***/ 371017: +/*!***********************!*\ + !*** external "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. +(() => { +/*!*******************************************!*\ + !*** ./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 */ + + + + + +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) { + // The specifier doesn't have a version + name = rawPackageSpecifier; + } + else { + name = rawPackageSpecifier.substring(0, separatorIndex); + version = rawPackageSpecifier.substring(separatorIndex + 1); + } + 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) { + try { + if (os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32') { + // 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'); + } + } + return _npmPath; +} +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 { + 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); + } + } + } + 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 { + 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++) { + if (aParts[i] !== bParts[i]) { + 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) { + version = '*'; // If no version is specified, use the latest version + } + 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 { + // 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, rushTempFolder, undefined, 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 npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(npmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], { + cwd: rushTempFolder, + stdio: [] + }); + 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.'); + } + 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 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; + } + } 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}.`); + } + } + 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; + } + const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); + return fileContents.trim() === process.version; + } + catch (e) { + return false; + } +} +/** + * Delete a file. Fail silently if it does not exist. + */ +function _deleteFile(file) { + try { + fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); + } + catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + 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); + _deleteFile(flagFile); + 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()}`)); + } + } + } + catch (e) { + throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); + } +} +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' + }; + 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 { + logger.info(`Installing ${name}...`); + const npmPath = getNpmPath(); + const result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(npmPath, [command], { + stdio: 'inherit', + cwd: packageInstallFolder, + env: process.env + }); + if (result.status !== 0) { + throw new Error(`"npm ${command}" encountered an error`); + } + logger.info(`Successfully installed ${name}@${version}`); + } + 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 = os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32' ? `${binName}.cmd` : binName; + return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); +} +/** + * 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) { + 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)) { + // 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, packageInstallFolder, undefined, 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 { + // Node.js on Windows can not spawn a file when the path has a space on it + // unless the path gets wrapped in a cmd friendly way and shell mode is used + const shouldUseShell = binPath.includes(' ') && os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32'; + const platformBinPath = shouldUseShell ? `"${binPath}"` : 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: shouldUseShell, + cwd: process.cwd(), + env: process.env + }); + } + finally { + process.env.PATH = originalEnvPath; + } + if (result.status !== null) { + return result.status; + } + else { + throw result.error || new Error('An unknown error occurred.'); + } +} +function runWithErrorAndStatusCode(logger, fn) { + process.exitCode = 1; + try { + const exitCode = fn(); + process.exitCode = exitCode; + } + 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) { + throw new Error('Unexpected exception: could not detect node path'); + } + 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) { + 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 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}`); + } + return installAndRun(logger, name, version, packageBinName, packageBinArgs); + }); +} +_run(); +//# sourceMappingURL=install-run.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run.js.map \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/package.json new file mode 100644 index 00000000000..98957112d5e --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/a/package.json @@ -0,0 +1,10 @@ +{ + "name": "a", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js a", + "build": "node ../build.js a", + "__phase:build": "exit 1", + "_phase:build": "node ../build.js a" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/package.json new file mode 100644 index 00000000000..8b17917b744 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/b/package.json @@ -0,0 +1,9 @@ +{ + "name": "b", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:build": "node ../build.js b" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/build.js new file mode 100644 index 00000000000..15441feef29 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/build.js @@ -0,0 +1,14 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem } = require('@rushstack/node-core-library'); + +const args = process.argv.slice(2); + +console.log('start', args.join(' ')); +setTimeout(() => { + const outputFolder = path.resolve(process.cwd(), 'dist'); + const outputFile = path.resolve(outputFolder, 'output.txt'); + FileSystem.ensureFolder(outputFolder); + FileSystem.writeFile(outputFile, `Hello world! ${args.join(' ')}`); + console.log('done'); +}, 2000); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/package.json new file mode 100644 index 00000000000..738c1444ab0 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/c/package.json @@ -0,0 +1,12 @@ +{ + "name": "c", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:build": "node ../build.js" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/package.json new file mode 100644 index 00000000000..67707275a1e --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/d/package.json @@ -0,0 +1,13 @@ +{ + "name": "d", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:build": "node ../build.js" + }, + "dependencies": { + "b": "workspace:*", + "c": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/package.json new file mode 100644 index 00000000000..0b91c05a805 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/e/package.json @@ -0,0 +1,13 @@ +{ + "name": "e", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:build": "node ../build.js" + }, + "dependencies": { + "b": "workspace:*", + "d": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/config/rush-project.json new file mode 100644 index 00000000000..b2e4e3206a4 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/config/rush-project.json @@ -0,0 +1,13 @@ +{ + "disableBuildCacheForProject": true, + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/package.json new file mode 100644 index 00000000000..7bf2634a508 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/f/package.json @@ -0,0 +1,13 @@ +{ + "name": "f", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:pre-build": "node ../pre-build.js", + "_phase:build": "node ../validate-pre-build.js && node ../build.js f" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/g/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/g/package.json new file mode 100644 index 00000000000..29cd2f39532 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/g/package.json @@ -0,0 +1,13 @@ +{ + "name": "g", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:pre-build": "node ../pre-build.js", + "_phase:build": "node ../validate-pre-build.js && node ../build.js g" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/package.json new file mode 100644 index 00000000000..cb74fb60a7d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/h/package.json @@ -0,0 +1,12 @@ +{ + "name": "h", + "version": "1.0.0", + "scripts": { + "cobuild": "", + "build": "", + "_phase:build": "" + }, + "dependencies": { + "a": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/pre-build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/pre-build.js new file mode 100644 index 00000000000..4d9f43e7afa --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/pre-build.js @@ -0,0 +1,11 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem } = require('@rushstack/node-core-library'); + +setTimeout(() => { + const outputFolder = path.resolve(process.cwd(), 'dist'); + const outputFile = path.resolve(outputFolder, 'pre-build'); + FileSystem.ensureFolder(outputFolder); + FileSystem.writeFile(outputFile, `Hello world!`); + console.log('done'); +}, 2000); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/validate-pre-build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/validate-pre-build.js new file mode 100644 index 00000000000..218484000e3 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/projects/validate-pre-build.js @@ -0,0 +1,13 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem } = require('@rushstack/node-core-library'); + +const outputFolder = path.resolve(process.cwd(), 'dist'); +const outputFile = path.resolve(outputFolder, 'pre-build'); + +if (!FileSystem.exists(outputFile)) { + console.error(`${outputFile} does not exist.`); + process.exit(1); +} + +console.log(`${outputFile} exists`); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/rush.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/rush.json new file mode 100644 index 00000000000..012281bea0d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/repo/rush.json @@ -0,0 +1,41 @@ +{ + "rushVersion": "5.80.0", + "pnpmVersion": "7.13.0", + "pnpmOptions": { + "useWorkspaces": true + }, + "projects": [ + { + "packageName": "a", + "projectFolder": "projects/a" + }, + { + "packageName": "b", + "projectFolder": "projects/b" + }, + { + "packageName": "c", + "projectFolder": "projects/c" + }, + { + "packageName": "d", + "projectFolder": "projects/d" + }, + { + "packageName": "e", + "projectFolder": "projects/e" + }, + { + "packageName": "f", + "projectFolder": "projects/f" + }, + { + "packageName": "g", + "projectFolder": "projects/g" + }, + { + "packageName": "h", + "projectFolder": "projects/h" + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/.gitignore b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/.gitignore new file mode 100644 index 00000000000..f41ed442681 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/.gitignore @@ -0,0 +1,8 @@ +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +projects/*/dist/ +*.log +node_modules/ +.rush diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json new file mode 100644 index 00000000000..c27270adc35 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush-plugins/rush-redis-cobuild-plugin.json @@ -0,0 +1,4 @@ +{ + "url": "redis://localhost:6379", + "passwordEnvironmentVariable": "REDIS_PASS" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/build-cache.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/build-cache.json new file mode 100644 index 00000000000..d09eaa6a04c --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/build-cache.json @@ -0,0 +1,92 @@ +/** + * This configuration file manages Rush's build cache feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. + * + * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. + */ + "buildCacheEnabled": true, + + /** + * (Required) Choose where project build outputs will be cached. + * + * Possible values: "local-only", "azure-blob-storage", "amazon-s3" + */ + "cacheProvider": "local-only", + + /** + * Setting this property overrides the cache entry ID. If this property is set, it must contain + * a [hash] token. + * + * Other available tokens: + * - [projectName] + * - [projectName:normalize] + * - [phaseName] + * - [phaseName:normalize] + * - [phaseName:trimPrefix] + */ + // "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]" + + /** + * Use this configuration with "cacheProvider"="azure-blob-storage" + */ + "azureBlobStorageConfiguration": { + /** + * (Required) The name of the the Azure storage account to use for build cache. + */ + // "storageAccountName": "example", + /** + * (Required) The name of the container in the Azure storage account to use for build cache. + */ + // "storageContainerName": "my-container", + /** + * The Azure environment the storage account exists in. Defaults to AzurePublicCloud. + * + * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" + */ + // "azureEnvironment": "AzurePublicCloud", + /** + * An optional prefix for cache item blob names. + */ + // "blobPrefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + }, + + /** + * Use this configuration with "cacheProvider"="amazon-s3" + */ + "amazonS3Configuration": { + /** + * (Required unless s3Endpoint is specified) The name of the bucket to use for build cache. + * Example: "my-bucket" + */ + // "s3Bucket": "my-bucket", + /** + * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. + * This should not include any path; use the s3Prefix to set the path. + * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" + */ + // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", + /** + * (Required) The Amazon S3 region of the bucket to use for build cache. + * Example: "us-east-1" + */ + // "s3Region": "us-east-1", + /** + * An optional prefix ("folder") for cache items. It should not start with "/". + */ + // "s3Prefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/cobuild.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/cobuild.json new file mode 100644 index 00000000000..4626f2211d4 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/cobuild.json @@ -0,0 +1,22 @@ +/** + * This configuration file manages Rush's cobuild feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. + * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, + * otherwise the cobuild feature will be disabled. + */ + "cobuildFeatureEnabled": true, + + /** + * (Required) Choose where cobuild lock will be acquired. + * + * The lock provider is registered by the rush plugins. + * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. + */ + "cobuildLockProvider": "redis" +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/command-line.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/command-line.json new file mode 100644 index 00000000000..c8c1ccc022d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/command-line.json @@ -0,0 +1,336 @@ +/** + * This configuration file defines custom commands for the "rush" command-line. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + + /** + * Custom "commands" introduce new verbs for the command-line. To see the help for these + * example commands, try "rush --help", "rush my-bulk-command --help", or + * "rush my-global-command --help". + */ + "commands": [ + { + "commandKind": "phased", + "summary": "Concurrent version of rush build", + "name": "cobuild", + "safeForSimultaneousRushProcesses": true, + "enableParallelism": true, + "incremental": true, + "phases": ["_phase:pre-build", "_phase:build"] + } + + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "bulk" commands are invoked separately for each project. Rush will look in + // * each project's package.json file for a "scripts" entry whose name matches the + // * command name. By default, the command will run for every project in the repo, + // * according to the dependency graph (similar to how "rush build" works). + // * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. + // */ + // "commandKind": "bulk", + // + // /** + // * (Required) The name that will be typed as part of the command line. This is also the name + // * of the "scripts" hook in the project's package.json file. + // * The name should be comprised of lower case words separated by hyphens or colons. The name should include an + // * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands + // * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). + // * + // * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command + // * and will call the "rebuild" script instead of the "build" script. + // */ + // "name": "my-bulk-command", + // + // /** + // * (Required) A short summary of the custom command to be shown when printing command line + // * help, e.g. "rush --help". + // */ + // "summary": "Example bulk custom command", + // + // /** + // * A detailed description of the command to be shown when printing command line + // * help (e.g. "rush --help my-command"). + // * If omitted, the "summary" text will be shown instead. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "This is an example custom command that runs separately for each project", + // + // /** + // * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously + // * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the + // * same time.) If your command makes sense to run concurrently with other operations, + // * set "safeForSimultaneousRushProcesses" to true to disable this protection. + // * + // * In particular, this is needed for custom scripts that invoke other Rush commands. + // */ + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) If true, then this command is safe to be run in parallel, i.e. executed + // * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism + // * projects will not start processing until their dependencies have completed processing. + // */ + // "enableParallelism": 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 + // * you can set "ignoreDependencyOrder" to true to increase parallelism. + // */ + // "ignoreDependencyOrder": false, + // + // /** + // * Normally Rush requires that each project's package.json has a "scripts" entry matching + // * the custom command name. To disable this check, set "ignoreMissingScript" to true; + // * projects with a missing definition will be skipped. + // */ + // "ignoreMissingScript": false, + // + // /** + // * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: + // * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". + // * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. + // * - If the shell script returns a zero process exit code but writes something to its stderr stream, + // * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent + // * Rush from processing downstream projects. + // * + // * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because + // * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. + // * In an active monorepo, we've found that if you allow any warnings in your main branch, it inadvertently + // * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings + // * have accumulated that warnings no longer serve any useful purpose. + // * + // * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. + // * In that case, it's strongly recommended to fix the task. However, as a workaround you can set + // * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. + // * + // * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. + // */ + // "allowWarningsInSuccessfulBuild": false, + // + // /** + // * If true then this command will be incremental like the built-in "build" command + // */ + // "incremental": false, + // + // /** + // * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush + // * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a + // * change is detected, the command will be invoked again for the changed project and any selected projects that + // * directly or indirectly depend on it. + // * + // * For details, refer to the website article "Using watch mode". + // */ + // "watchForChanges": false, + // + // /** + // * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of + // * projects' own folders. + // */ + // "disableBuildCache": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "global" commands are invoked once for the entire repo. + // */ + // "commandKind": "global", + // + // "name": "my-global-command", + // "summary": "Example global custom command", + // "description": "This is an example custom command that runs once for the entire repo", + // + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) A script that will be invoked using the OS shell. The working directory will be + // * the folder that contains rush.json. If custom parameters are associated with this command, their + // * values will be appended to the end of this string. + // */ + // "shellCommand": "node common/scripts/my-global-command.js", + // + // /** + // * If your "shellCommand" script depends on NPM packages, the recommended best practice is + // * to make it into a regular Rush project that builds using your normal toolchain. In cases where + // * the command needs to work without first having to run "rush build", the recommended practice + // * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. + // * + // * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with + // * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to + // * install these dependencies before an associated command is invoked. Autoinstallers have the + // * advantage that they work even in a branch where "rush install" is broken, which makes them a + // * good solution for Git hook scripts. But they have the disadvantages of not being buildable + // * projects, and of increasing the overall installation footprint for your monorepo. + // * + // * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. + // * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and + // * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when + // * invoking the "shellCommand". + // */ + // // "autoinstallerName": "my-task" + // } + ], + + "phases": [ + { + /** + * The name of the phase. Note that this value must start with the \"_phase:\" prefix. + */ + "name": "_phase:build", + /** + * The dependencies of this phase. + */ + "dependencies": { + "upstream": ["_phase:build"], + "self": ["_phase:pre-build"] + } + }, + { + /** + * The name of the phase. Note that this value must start with the \"_phase:\" prefix. + */ + "name": "_phase:pre-build", + /** + * The dependencies of this phase. + */ + "dependencies": { + "upstream": ["_phase:build"] + }, + "missingScriptBehavior": "silent" + } + ], + + /** + * Custom "parameters" introduce new parameters for specified Rush command-line commands. + * For example, you might define a "--production" parameter for the "rush build" command. + */ + "parameters": [ + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. + // */ + // "parameterKind": "flag", + // + // /** + // * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. + // */ + // "longName": "--my-flag", + // + // /** + // * An optional alternative short name for the parameter. It must be a dash followed by a single + // * lower-case or upper-case letter, which is case-sensitive. + // * + // * NOTE: The Rush developers recommend that automation scripts should always use the long name + // * to improve readability. The short name is only intended as a convenience for humans. + // * The alphabet letters run out quickly, and are difficult to memorize, so *only* use + // * a short name if you expect the parameter to be needed very often in everyday operations. + // */ + // "shortName": "-m", + // + // /** + // * (Required) A long description to be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", + // + // /** + // * (Required) A list of custom commands and/or built-in Rush commands that this parameter may + // * be used with. The parameter will be appended to the shell command that Rush invokes. + // */ + // "associatedCommands": ["build", "rebuild"] + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "string" is a custom command-line parameter whose value is a simple text string. + // */ + // "parameterKind": "string", + // "longName": "--my-string", + // "description": "A custom string parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * The name of the argument, which will be shown in the command-line help. + // * + // * For example, if the parameter name is '--count" and the argument name is "NUMBER", + // * then the command-line help would display "--count NUMBER". The argument name must + // * be comprised of upper-case letters, numbers, and underscores. It should be kept short. + // */ + // "argumentName": "SOME_TEXT", + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + // * allowable alternatives. + // */ + // "parameterKind": "choice", + // "longName": "--my-choice", + // "description": "A custom choice parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false, + // + // /** + // * Normally if a parameter is omitted from the command line, it will not be passed + // * to the shell command. this value will be inserted by default. Whereas if a "defaultValue" + // * is defined, the parameter will always be passed to the shell command, and will use the + // * default value if unspecified. The value must be one of the defined alternatives. + // */ + // "defaultValue": "vanilla", + // + // /** + // * (Required) A list of alternative argument values that can be chosen for this parameter. + // */ + // "alternatives": [ + // { + // /** + // * A token that is one of the alternatives that can be used with the choice parameter, + // * e.g. "vanilla" in "--flavor vanilla". + // */ + // "name": "vanilla", + // + // /** + // * A detailed description for the alternative that can be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "Use the vanilla flavor (the default)" + // }, + // + // { + // "name": "chocolate", + // "description": "Use the chocolate flavor" + // }, + // + // { + // "name": "strawberry", + // "description": "Use the strawberry flavor" + // } + // ] + // } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/experiments.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/experiments.json new file mode 100644 index 00000000000..14a02ec1f2f --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/experiments.json @@ -0,0 +1,57 @@ +/** + * This configuration file allows repo maintainers to enable and disable experimental + * Rush features. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "../../../../../../../libraries/rush-lib/src/schemas/experiments.schema.json", + + /** + * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead for faster installs. + */ + "usePnpmFrozenLockfileForRushInstall": true, + + /** + * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. + */ + "usePnpmPreferFrozenLockfileForRushUpdate": true, + + /** + * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. + * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not + * cause hash changes. + */ + "omitImportersFromPreventManualShrinkwrapChanges": true, + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + // "noChmodFieldInTarHeaderNormalization": true, + + /** + * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. + * This will not replay warnings from the cached build. + */ + // "buildCacheWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, the phased commands feature is enabled. To use this feature, create a "phased" command + * in common/config/rush/command-line.json. + */ + "phasedCommands": true, + + /** + * If true, perform a clean install after when running `rush install` or `rush update` if the + * `.npmrc` file has changed since the last install. + */ + // "cleanInstallAfterNpmrcChanges": true, + + /** + * If true, print the outputs of shell commands defined in event hooks to the console. + */ + // "printEventHooksOutputToConsole": true + + "allowCobuildWithoutCache": true +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/pnpm-lock.yaml b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/pnpm-lock.yaml new file mode 100644 index 00000000000..98b22e9d424 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/pnpm-lock.yaml @@ -0,0 +1,52 @@ +lockfileVersion: 5.4 + +importers: + + .: + specifiers: {} + + ../../projects/a: + specifiers: {} + + ../../projects/b: + specifiers: {} + + ../../projects/c: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/d: + specifiers: + b: workspace:* + c: workspace:* + dependencies: + b: link:../b + c: link:../c + + ../../projects/e: + specifiers: + b: workspace:* + d: workspace:* + dependencies: + b: link:../b + d: link:../d + + ../../projects/f: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/g: + specifiers: + b: workspace:* + dependencies: + b: link:../b + + ../../projects/h: + specifiers: + a: workspace:* + dependencies: + a: link:../a diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/repo-state.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/repo-state.json new file mode 100644 index 00000000000..0e7b144099d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/config/rush/repo-state.json @@ -0,0 +1,4 @@ +// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. +{ + "preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" +} 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 new file mode 100644 index 00000000000..4b7aad5d586 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush-pnpm.js @@ -0,0 +1,32 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rush-pnpm command. +// +// An example usage would be: +// +// node common/scripts/install-run-rush-pnpm.js pnpm-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// 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__ = {}; + /*!*****************************************************!*\ + !*** ./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'); + //# sourceMappingURL=install-run-rush-pnpm.js.map + module.exports = __webpack_exports__; + /******/ +})(); +//# sourceMappingURL=install-run-rush-pnpm.js.map 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 new file mode 100644 index 00000000000..48da5907f9d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush.js @@ -0,0 +1,245 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run-rush.js install +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// 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: + /*!*********************!*\ + !*** external "fs" ***! + \*********************/ + /***/ (module) => { + module.exports = require('fs'); + + /***/ + }, + + /***/ 371017: + /*!***********************!*\ + !*** external "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. + (() => { + /*!************************************************!*\ + !*** ./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 */ + + 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 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}). ` + + `The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` + + 'using an unexpected syntax.' + ); + } + } + function _getBin(scriptName) { + switch (scriptName.toLowerCase()) { + case 'install-run-rush-pnpm.js': + return 'rush-pnpm'; + case 'install-run-rushx.js': + return 'rushx'; + default: + 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) { + 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) { + 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 + }; + } 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) { + 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`); + } + process.exit(1); + } + 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.` + ); + } + return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); + }); + } + _run(); + //# sourceMappingURL=install-run-rush.js.map + })(); + + 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 new file mode 100644 index 00000000000..f865303a384 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rushx.js @@ -0,0 +1,32 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rushx command. +// +// An example usage would be: +// +// node common/scripts/install-run-rushx.js custom-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// 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__ = {}; + /*!*************************************************!*\ + !*** ./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'); + //# sourceMappingURL=install-run-rushx.js.map + module.exports = __webpack_exports__; + /******/ +})(); +//# sourceMappingURL=install-run-rushx.js.map 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 new file mode 100644 index 00000000000..580ebb343e9 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run.js @@ -0,0 +1,821 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where a Node tool may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the specified +// version of the specified tool (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// 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: + /*!************************************************!*\ + !*** ./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 + + /** + * 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; + } + } + } + } + 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; + } + 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)) { + fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + 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}`); + } + } + 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 + + /***/ + }, + + /***/ 532081: + /*!********************************!*\ + !*** external "child_process" ***! + \********************************/ + /***/ (module) => { + module.exports = require('child_process'); + + /***/ + }, + + /***/ 657147: + /*!*********************!*\ + !*** external "fs" ***! + \*********************/ + /***/ (module) => { + module.exports = require('fs'); + + /***/ + }, + + /***/ 822037: + /*!*********************!*\ + !*** external "os" ***! + \*********************/ + /***/ (module) => { + module.exports = require('os'); + + /***/ + }, + + /***/ 371017: + /*!***********************!*\ + !*** external "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. + (() => { + /*!*******************************************!*\ + !*** ./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 */ + + 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) { + // The specifier doesn't have a version + name = rawPackageSpecifier; + } else { + name = rawPackageSpecifier.substring(0, separatorIndex); + version = rawPackageSpecifier.substring(separatorIndex + 1); + } + 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) { + 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}`); + } + _npmPath = _npmPath.trim(); + if (!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); + _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 { + 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); + } + } + } 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 { + 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++) { + if (aParts[i] !== bParts[i]) { + 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) { + version = '*'; // If no version is specified, use the latest version + } + 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 { + // 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.'); + } + 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 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; + } + } 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}.`); + } + } + 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; + } + const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); + return fileContents.trim() === process.version; + } catch (e) { + return false; + } + } + /** + * Delete a file. Fail silently if it does not exist. + */ + function _deleteFile(file) { + try { + fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + 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 + ); + _deleteFile(flagFile); + 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()}` + ) + ); + } + } + } catch (e) { + throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); + } + } + 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' + }; + 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 { + 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() + }); + if (result.status !== 0) { + throw new Error(`"npm ${command}" encountered an error`); + } + logger.info(`Successfully installed ${name}@${version}`); + } 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 + ); + fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version); + } 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)) { + // 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 + }); + _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 { + // `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 + }); + } finally { + process.env.PATH = originalEnvPath; + } + if (result.status !== null) { + return result.status; + } else { + throw result.error || new Error('An unknown error occurred.'); + } + } + function runWithErrorAndStatusCode(logger, fn) { + process.exitCode = 1; + try { + const exitCode = fn(); + process.exitCode = exitCode; + } 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) { + throw new Error('Unexpected exception: could not detect node path'); + } + 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) { + 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 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}`); + } + return installAndRun(logger, name, version, packageBinName, packageBinArgs); + }); + } + _run(); + //# sourceMappingURL=install-run.js.map + })(); + + module.exports = __webpack_exports__; + /******/ +})(); +//# sourceMappingURL=install-run.js.map diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/config/rush-project.json new file mode 100644 index 00000000000..f6fc90813a8 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/config/rush-project.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../../../../../../libraries/rush-lib/src/schemas/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"], + "sharding": { + "count": 4, + "outputFolderArgumentFormat": "--output-directory=.rush/{phaseName}/shards/{shardIndex}" + } + }, + { + "operationName": "_phase:build:shard", + "weight": 4 + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/package.json new file mode 100644 index 00000000000..005e5fdeaa1 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "a", + "version": "1.0.0", + "scripts": { + "_phase:build:shard": "node ../build.js a", + "_phase:build": "node ../collate a" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/config/rush-project.json new file mode 100644 index 00000000000..105cd2e697c --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/config/rush-project.json @@ -0,0 +1,16 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"], + "sharding": { + "count": 5, + "outputFolderArgumentFormat": "--output-directory=.rush/{phaseName}/shards/{shardIndex}" + } + }, + { + "operationName": "_phase:build:shard", + "weight": 10 + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/package.json new file mode 100644 index 00000000000..3a97f747893 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "1.0.0", + "scripts": { + "_phase:build": "node ../collate.js", + "_phase:build:shard": "node ../build.js b" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/build.js new file mode 100644 index 00000000000..dc1eeac8f81 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/build.js @@ -0,0 +1,30 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem, Async } = require('@rushstack/node-core-library'); + +const args = process.argv.slice(2); + +const getArgument = (argumentName) => { + const index = args.findIndex((e) => e.includes(argumentName)); + return index >= 0 ? args[index].replace(`${argumentName}=`, '') : undefined; +}; + +const shard = getArgument('--shard'); + +const outputDir = getArgument('--output-directory'); + +const shardOutputDir = getArgument('--shard-output-directory'); + +const outputDirectory = shard ? (shardOutputDir ? shardOutputDir : outputDir) : undefined; + +async function runAsync() { + await Async.sleepAsync(500); + const outputFolder = shard ? path.resolve(outputDirectory) : path.resolve('dist'); + const outputFile = path.resolve(outputFolder, 'output.txt'); + FileSystem.writeFile(outputFile, `Hello world! ${args.join(' ')}`, { ensureFolderExists: true }); +} + +void runAsync().catch((err) => { + console.warn(err); + process.exit(1); +}); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/config/rush-project.json new file mode 100644 index 00000000000..78e1555f5a6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/config/rush-project.json @@ -0,0 +1,8 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/package.json new file mode 100644 index 00000000000..93b9d5d950e --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/c/package.json @@ -0,0 +1,10 @@ +{ + "name": "c", + "version": "1.0.0", + "scripts": { + "_phase:build": "node ../build.js" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/collate.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/collate.js new file mode 100644 index 00000000000..b81485c6b35 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/collate.js @@ -0,0 +1,34 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem, Async } = require('@rushstack/node-core-library'); + +const args = process.argv.slice(2); + +const getArgument = (argumentName) => { + const index = args.findIndex((e) => e.includes(argumentName)); + return index >= 0 ? args[index].replace(`${argumentName}=`, '') : undefined; +}; + +const parentFolder = getArgument('--shard-parent-folder'); +const shards = +getArgument('--shard-count'); + +async function runAsync() { + await Async.sleepAsync(500); + + let output = ''; + for (let i = 1; i <= shards; i++) { + const outputFolder = path.resolve(parentFolder, `${i}`); + const outputFile = path.resolve(outputFolder, 'output.txt'); + FileSystem.ensureFolder(outputFolder); + output += FileSystem.readFile(outputFile, 'utf-8'); + output += '\n'; + } + const finalOutputFolder = path.resolve('coverage'); + const outputFile = path.resolve(finalOutputFolder, 'output.txt'); + FileSystem.writeFile(outputFile, output, { ensureFolderExists: true }); +} + +void runAsync().catch((err) => { + console.warn(err); + process.exit(1); +}); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/config/rush-project.json new file mode 100644 index 00000000000..ef7e47275c6 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + }, + { + "operationName": "cobuild", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/package.json new file mode 100644 index 00000000000..c14d4454d2d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/d/package.json @@ -0,0 +1,11 @@ +{ + "name": "d", + "version": "1.0.0", + "scripts": { + "_phase:build": "node ../build.js" + }, + "dependencies": { + "b": "workspace:*", + "c": "workspace:*" + } +} 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 new file mode 100644 index 00000000000..a5e85aedd69 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/config/rush-project.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../../../../../../libraries/rush-lib/src/schemas/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"], + "sharding": { + "count": 75 + } + }, + { + "operationName": "_phase:build:shard", + "weight": 10 + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/package.json new file mode 100644 index 00000000000..b7ae63fe2ae --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/package.json @@ -0,0 +1,12 @@ +{ + "name": "e", + "version": "1.0.0", + "scripts": { + "_phase:build:shard": "node ../build.js e", + "_phase:build": "node ../collate.js" + }, + "dependencies": { + "b": "workspace:*", + "d": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/config/rush-project.json new file mode 100644 index 00000000000..a9e823993d0 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "disableBuildCacheForProject": true, + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/package.json new file mode 100644 index 00000000000..7bf2634a508 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/f/package.json @@ -0,0 +1,13 @@ +{ + "name": "f", + "version": "1.0.0", + "scripts": { + "cobuild": "node ../build.js", + "build": "node ../build.js", + "_phase:pre-build": "node ../pre-build.js", + "_phase:build": "node ../validate-pre-build.js && node ../build.js f" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/g/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/g/package.json new file mode 100644 index 00000000000..96dbe965e96 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/g/package.json @@ -0,0 +1,11 @@ +{ + "name": "g", + "version": "1.0.0", + "scripts": { + "_phase:pre-build": "node ../pre-build.js", + "_phase:build": "node ../validate-pre-build.js && node ../build.js g" + }, + "dependencies": { + "b": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/config/rush-project.json new file mode 100644 index 00000000000..748d3137142 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/config/rush-project.json @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../../../../libraries/rush-lib/src/schemas/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist"], + "sharding": { + "count": 50 + } + } + ] +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/package.json new file mode 100644 index 00000000000..795b1398e5a --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/h/package.json @@ -0,0 +1,11 @@ +{ + "name": "h", + "version": "1.0.0", + "scripts": { + "_phase:build": "node ../collate h", + "_phase:build:shard": "node ../build h" + }, + "dependencies": { + "a": "workspace:*" + } +} diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/pre-build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/pre-build.js new file mode 100644 index 00000000000..9c63cadd273 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/pre-build.js @@ -0,0 +1,17 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem, Async } = require('@rushstack/node-core-library'); + +async function runAsync() { + await Async.sleepAsync(500); + + const outputFolder = path.resolve(process.cwd(), 'dist'); + const outputFile = path.resolve(outputFolder, 'pre-build'); + FileSystem.writeFile(outputFile, `Hello world!`, { ensureFolderExists: true }); + console.log('done'); +} + +void runAsync().catch((err) => { + console.warn(err); + process.exit(1); +}); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/validate-pre-build.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/validate-pre-build.js new file mode 100644 index 00000000000..218484000e3 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/validate-pre-build.js @@ -0,0 +1,13 @@ +/* eslint-env es6 */ +const path = require('path'); +const { FileSystem } = require('@rushstack/node-core-library'); + +const outputFolder = path.resolve(process.cwd(), 'dist'); +const outputFile = path.resolve(outputFolder, 'pre-build'); + +if (!FileSystem.exists(outputFile)) { + console.error(`${outputFile} does not exist.`); + process.exit(1); +} + +console.log(`${outputFile} exists`); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/rush.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/rush.json new file mode 100644 index 00000000000..012281bea0d --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/rush.json @@ -0,0 +1,41 @@ +{ + "rushVersion": "5.80.0", + "pnpmVersion": "7.13.0", + "pnpmOptions": { + "useWorkspaces": true + }, + "projects": [ + { + "packageName": "a", + "projectFolder": "projects/a" + }, + { + "packageName": "b", + "projectFolder": "projects/b" + }, + { + "packageName": "c", + "projectFolder": "projects/c" + }, + { + "packageName": "d", + "projectFolder": "projects/d" + }, + { + "packageName": "e", + "projectFolder": "projects/e" + }, + { + "packageName": "f", + "projectFolder": "projects/f" + }, + { + "packageName": "g", + "projectFolder": "projects/g" + }, + { + "packageName": "h", + "projectFolder": "projects/h" + } + ] +} 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 new file mode 100644 index 00000000000..c3dfdb36914 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/src/paths.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. + +import * as path from 'node:path'; + +const sandboxRepoFolder: string = path.resolve(__dirname, '../sandbox/repo'); + +export { sandboxRepoFolder }; 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 new file mode 100644 index 00000000000..8dd32b0fe81 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/src/runRush.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 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'; + +// Setup redis cobuild plugin +const builtInPluginConfigurations: rushLib._IBuiltInPluginConfiguration[] = []; + +const rushConfiguration: rushLib.RushConfiguration = rushLib.RushConfiguration.loadFromDefaultLocation({ + startingFolder: __dirname +}); +const project: rushLib.RushConfigurationProject | undefined = rushConfiguration.getProjectByName( + '@rushstack/rush-redis-cobuild-plugin' +); +if (!project) { + throw new Error('Project @rushstack/rush-redis-cobuild-plugin not found'); +} +builtInPluginConfigurations.push({ + packageName: '@rushstack/rush-redis-cobuild-plugin', + pluginName: 'rush-redis-cobuild-plugin', + pluginPackageFolder: project.projectFolder +}); + +async function rushRush(args: string[]): Promise { + const options: rushLib.ILaunchOptions = { + isManaged: false, + alreadyReportedNodeTooNewError: false, + builtInPluginConfigurations + }; + const parser: RushCommandLineParser = new RushCommandLineParser({ + alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError, + builtInPluginConfigurations: options.builtInPluginConfigurations + }); + // eslint-disable-next-line no-console + console.log(`Executing: rush ${args.join(' ')}`); + await parser + .executeAsync(args) + // eslint-disable-next-line no-console + .catch(console.error); // CommandLineParser.executeAsync() should never reject the promise +} + +// eslint-disable-next-line no-console +rushRush(process.argv.slice(2)).catch(console.error); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/src/testLockProvider.ts b/build-tests/rush-redis-cobuild-plugin-integration-test/src/testLockProvider.ts new file mode 100644 index 00000000000..1e685b22611 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/src/testLockProvider.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + RedisCobuildLockProvider, + type IRedisCobuildLockProviderOptions +} from '@rushstack/rush-redis-cobuild-plugin'; +import { ConsoleTerminalProvider } from '@rushstack/terminal'; +import { OperationStatus, type ICobuildContext, RushSession } from '@microsoft/rush-lib'; + +const options: IRedisCobuildLockProviderOptions = { + url: 'redis://localhost:6379', + password: 'redis123' // [SuppressMessage("Microsoft.Security", "CS001:SecretInline", Justification="Password used in unit test.")] +}; + +const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => true +}); + +async function main(): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const lockProvider: RedisCobuildLockProvider = new RedisCobuildLockProvider(options, rushSession as any); + await lockProvider.connectAsync(); + const context: ICobuildContext = { + contextId: 'context_id', + cacheId: 'cache_id', + lockKey: 'lock_key', + lockExpireTimeInSeconds: 30, + completedStateKey: 'completed_state_key', + clusterId: 'cluster_id', + runnerId: 'runner_id', + packageName: 'package_name', + phaseName: 'phase_name' + }; + await lockProvider.acquireLockAsync(context); + await lockProvider.renewLockAsync(context); + await lockProvider.setCompletedStateAsync(context, { + status: OperationStatus.Success, + cacheId: 'cache_id' + }); + const completedState = await lockProvider.getCompletedStateAsync(context); + // eslint-disable-next-line no-console + console.log('Completed state: ', completedState); + await lockProvider.disconnectAsync(); +} + +process.exitCode = 1; + +main() + .then(() => { + process.exitCode = 0; + }) + .catch((err) => { + // eslint-disable-next-line no-console + console.error(err); + }) + .finally(() => { + if (process.exitCode !== undefined) { + process.exit(process.exitCode); + } + }); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json b/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json new file mode 100644 index 00000000000..599b3beb19e --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json @@ -0,0 +1,26 @@ +{ + "$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, + "esModuleInterop": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017", "DOM"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "lib"] +} diff --git a/build-tests/rush-stack-compiler-2.4-library-test/.npmignore b/build-tests/rush-stack-compiler-2.4-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-2.4-library-test/gulpfile.js b/build-tests/rush-stack-compiler-2.4-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-2.4-library-test/package.json b/build-tests/rush-stack-compiler-2.4-library-test/package.json deleted file mode 100644 index 53e9f1d1f0c..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-2.4-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-2.4": "0.9.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-2.4-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-2.4-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-2.4-library-test/tsconfig.json b/build-tests/rush-stack-compiler-2.4-library-test/tsconfig.json deleted file mode 100644 index 76c70b643d6..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-2.4/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-2.4-library-test/tslint.json b/build-tests/rush-stack-compiler-2.4-library-test/tslint.json deleted file mode 100644 index 353878f6297..00000000000 --- a/build-tests/rush-stack-compiler-2.4-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-2.4/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-2.7-library-test/.npmignore b/build-tests/rush-stack-compiler-2.7-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-2.7-library-test/gulpfile.js b/build-tests/rush-stack-compiler-2.7-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-2.7-library-test/package.json b/build-tests/rush-stack-compiler-2.7-library-test/package.json deleted file mode 100644 index c3675edb363..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-2.7-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-2.7": "0.9.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-2.7-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-2.7-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-2.7-library-test/tsconfig.json b/build-tests/rush-stack-compiler-2.7-library-test/tsconfig.json deleted file mode 100644 index 39b231960a0..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-2.7/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-2.7-library-test/tslint.json b/build-tests/rush-stack-compiler-2.7-library-test/tslint.json deleted file mode 100644 index c33b8d06067..00000000000 --- a/build-tests/rush-stack-compiler-2.7-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-2.7/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-2.8-library-test/.npmignore b/build-tests/rush-stack-compiler-2.8-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-2.8-library-test/gulpfile.js b/build-tests/rush-stack-compiler-2.8-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-2.8-library-test/package.json b/build-tests/rush-stack-compiler-2.8-library-test/package.json deleted file mode 100644 index 3ebfb26d5cd..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-2.8-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-2.8": "0.4.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-2.8-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-2.8-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-2.8-library-test/tsconfig.json b/build-tests/rush-stack-compiler-2.8-library-test/tsconfig.json deleted file mode 100644 index 0a34739f4a7..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-2.8/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-2.8-library-test/tslint.json b/build-tests/rush-stack-compiler-2.8-library-test/tslint.json deleted file mode 100644 index a99792a2b6d..00000000000 --- a/build-tests/rush-stack-compiler-2.8-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-2.8/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-2.9-library-test/.npmignore b/build-tests/rush-stack-compiler-2.9-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-2.9-library-test/gulpfile.js b/build-tests/rush-stack-compiler-2.9-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-2.9-library-test/package.json b/build-tests/rush-stack-compiler-2.9-library-test/package.json deleted file mode 100644 index eefd9b5147a..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-2.9-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-2.9": "0.10.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-2.9-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-2.9-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-2.9-library-test/tsconfig.json b/build-tests/rush-stack-compiler-2.9-library-test/tsconfig.json deleted file mode 100644 index 427d8c94e67..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-2.9/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-2.9-library-test/tslint.json b/build-tests/rush-stack-compiler-2.9-library-test/tslint.json deleted file mode 100644 index c6d9221de38..00000000000 --- a/build-tests/rush-stack-compiler-2.9-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-2.9/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.0-library-test/.npmignore b/build-tests/rush-stack-compiler-3.0-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.0-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.0-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.0-library-test/package.json b/build-tests/rush-stack-compiler-3.0-library-test/package.json deleted file mode 100644 index fd61461bde8..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.0-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.0": "0.9.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.0-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.0-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.0-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.0-library-test/tsconfig.json deleted file mode 100644 index 7be55808db0..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.0/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.0-library-test/tslint.json b/build-tests/rush-stack-compiler-3.0-library-test/tslint.json deleted file mode 100644 index 30e72fdf8b4..00000000000 --- a/build-tests/rush-stack-compiler-3.0-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.0/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.1-library-test/.npmignore b/build-tests/rush-stack-compiler-3.1-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.1-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.1-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.1-library-test/package.json b/build-tests/rush-stack-compiler-3.1-library-test/package.json deleted file mode 100644 index 61ec538362c..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.1-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.1": "0.9.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.1-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.1-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.1-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.1-library-test/tsconfig.json deleted file mode 100644 index 274d068c868..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.1/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.1-library-test/tslint.json b/build-tests/rush-stack-compiler-3.1-library-test/tslint.json deleted file mode 100644 index cf2395fe8c0..00000000000 --- a/build-tests/rush-stack-compiler-3.1-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.1/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.2-library-test/.npmignore b/build-tests/rush-stack-compiler-3.2-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.2-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.2-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.2-library-test/package.json b/build-tests/rush-stack-compiler-3.2-library-test/package.json deleted file mode 100644 index 27cf64dbbc8..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.2-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.2": "0.6.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.2-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.2-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.2-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.2-library-test/tsconfig.json deleted file mode 100644 index c690935203f..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.2/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.2-library-test/tslint.json b/build-tests/rush-stack-compiler-3.2-library-test/tslint.json deleted file mode 100644 index 04fc5479081..00000000000 --- a/build-tests/rush-stack-compiler-3.2-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.2/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.3-library-test/.npmignore b/build-tests/rush-stack-compiler-3.3-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.3-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.3-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.3-library-test/package.json b/build-tests/rush-stack-compiler-3.3-library-test/package.json deleted file mode 100644 index b0d1bc28aba..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.3-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.3": "0.5.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.3-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.3-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.3-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.3-library-test/tsconfig.json deleted file mode 100644 index 6b243007300..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.3-library-test/tslint.json b/build-tests/rush-stack-compiler-3.3-library-test/tslint.json deleted file mode 100644 index df1da8e163b..00000000000 --- a/build-tests/rush-stack-compiler-3.3-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.3/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.4-library-test/.npmignore b/build-tests/rush-stack-compiler-3.4-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.4-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.4-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.4-library-test/package.json b/build-tests/rush-stack-compiler-3.4-library-test/package.json deleted file mode 100644 index f4c2953dce5..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.4-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.4": "0.4.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.4-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.4-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.4-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.4-library-test/tsconfig.json deleted file mode 100644 index 4db8f3a8b7e..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.4/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.4-library-test/tslint.json b/build-tests/rush-stack-compiler-3.4-library-test/tslint.json deleted file mode 100644 index 9488b2d898b..00000000000 --- a/build-tests/rush-stack-compiler-3.4-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.4/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.5-library-test/.npmignore b/build-tests/rush-stack-compiler-3.5-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.5-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.5-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.5-library-test/package.json b/build-tests/rush-stack-compiler-3.5-library-test/package.json deleted file mode 100644 index d2e5846b628..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.5-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.5-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.5-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.5-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.5-library-test/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.5-library-test/tslint.json b/build-tests/rush-stack-compiler-3.5-library-test/tslint.json deleted file mode 100644 index 60db661e377..00000000000 --- a/build-tests/rush-stack-compiler-3.5-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.5/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.6-library-test/.npmignore b/build-tests/rush-stack-compiler-3.6-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.6-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.6-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.6-library-test/package.json b/build-tests/rush-stack-compiler-3.6-library-test/package.json deleted file mode 100644 index de1b57b6070..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.6-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.6": "0.2.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.6-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.6-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.6-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.6-library-test/tsconfig.json deleted file mode 100644 index d45b8b1037b..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.6/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.6-library-test/tslint.json b/build-tests/rush-stack-compiler-3.6-library-test/tslint.json deleted file mode 100644 index 31286edeb0a..00000000000 --- a/build-tests/rush-stack-compiler-3.6-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.6/includes/tslint.json" -} diff --git a/build-tests/rush-stack-compiler-3.7-library-test/.npmignore b/build-tests/rush-stack-compiler-3.7-library-test/.npmignore deleted file mode 100644 index f7818305f9f..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore everything by default -** diff --git a/build-tests/rush-stack-compiler-3.7-library-test/gulpfile.js b/build-tests/rush-stack-compiler-3.7-library-test/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/build-tests/rush-stack-compiler-3.7-library-test/package.json b/build-tests/rush-stack-compiler-3.7-library-test/package.json deleted file mode 100644 index 0b773126e54..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "rush-stack-compiler-3.7-library-test", - "version": "1.0.0", - "description": "", - "main": "lib/index.js", - "license": "MIT", - "private": true, - "scripts": { - "build": "gulp test --clean" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.7": "0.2.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - } -} diff --git a/build-tests/rush-stack-compiler-3.7-library-test/src/TestClass.ts b/build-tests/rush-stack-compiler-3.7-library-test/src/TestClass.ts deleted file mode 100644 index bdaeb7a05ad..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/src/TestClass.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export class TestClass { -} diff --git a/build-tests/rush-stack-compiler-3.7-library-test/tsconfig.json b/build-tests/rush-stack-compiler-3.7-library-test/tsconfig.json deleted file mode 100644 index 42b2dcde892..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-node.json" -} diff --git a/build-tests/rush-stack-compiler-3.7-library-test/tslint.json b/build-tests/rush-stack-compiler-3.7-library-test/tslint.json deleted file mode 100644 index 0f819d2d024..00000000000 --- a/build-tests/rush-stack-compiler-3.7-library-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.7/includes/tslint.json" -} diff --git a/build-tests/set-webpack-public-path-plugin-test/.gitignore b/build-tests/set-webpack-public-path-plugin-test/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file diff --git a/build-tests/set-webpack-public-path-plugin-test/config/heft.json b/build-tests/set-webpack-public-path-plugin-test/config/heft.json new file mode 100644 index 00000000000..fbb74a0db4e --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-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": ["dist-dev", "dist-prod", "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/set-webpack-public-path-plugin-test/config/rush-project.json b/build-tests/set-webpack-public-path-plugin-test/config/rush-project.json new file mode 100644 index 00000000000..543278bebd4 --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-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", "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 new file mode 100644 index 00000000000..23edb69f4f0 --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/package.json @@ -0,0 +1,25 @@ +{ + "name": "set-webpack-public-path-plugin-test", + "description": "Building this project tests the set-webpack-public-path-plugin", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft 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:*", + "@rushstack/module-minifier": "workspace:*", + "@rushstack/set-webpack-public-path-plugin": "workspace:*", + "@rushstack/webpack5-module-minifier-plugin": "workspace:*", + "@types/webpack-env": "1.18.8", + "eslint": "~8.57.0", + "html-webpack-plugin": "~5.5.0", + "typescript": "~5.8.2", + "webpack": "~5.98.0" + } +} diff --git a/build-tests/set-webpack-public-path-plugin-test/src/chunks/chunk.ts b/build-tests/set-webpack-public-path-plugin-test/src/chunks/chunk.ts new file mode 100644 index 00000000000..c01d8aa9401 --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/src/chunks/chunk.ts @@ -0,0 +1,5 @@ +export class ChunkClass { + public doStuff(): void { + console.log('stuff'); + } +} diff --git a/build-tests/set-webpack-public-path-plugin-test/src/index.ts b/build-tests/set-webpack-public-path-plugin-test/src/index.ts new file mode 100644 index 00000000000..6f5eff3a0d6 --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/src/index.ts @@ -0,0 +1,4 @@ +import(/* webpackChunkName: 'chunk' */ './chunks/chunk').then(({ ChunkClass }) => { + const chunk = new ChunkClass(); + chunk.doStuff(); +}); diff --git a/build-tests/set-webpack-public-path-plugin-test/tsconfig.json b/build-tests/set-webpack-public-path-plugin-test/tsconfig.json new file mode 100644 index 00000000000..dad0392042f --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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, + "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/set-webpack-public-path-plugin-test/webpack.config.js b/build-tests/set-webpack-public-path-plugin-test/webpack.config.js new file mode 100644 index 00000000000..15a2f87d2ab --- /dev/null +++ b/build-tests/set-webpack-public-path-plugin-test/webpack.config.js @@ -0,0 +1,41 @@ +'use strict'; + +const { SetPublicPathPlugin } = require('@rushstack/set-webpack-public-path-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { ModuleMinifierPlugin } = require('@rushstack/webpack5-module-minifier-plugin'); +const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); + +function generateConfiguration(mode, outputFolderName) { + return { + mode: mode, + entry: { + 'test-bundle': `${__dirname}/lib/index.js` + }, + output: { + path: `${__dirname}/${outputFolderName}`, + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js' + }, + plugins: [ + new SetPublicPathPlugin({ + scriptName: { + useAssetName: true + } + }), + new HtmlWebpackPlugin() + ], + optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier(), + useSourceMap: true + }) + ] + } + }; +} + +module.exports = [ + generateConfiguration('development', 'dist-dev'), + generateConfiguration('production', 'dist-prod') +]; diff --git a/build-tests/web-library-build-test/.npmignore b/build-tests/web-library-build-test/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/build-tests/web-library-build-test/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/build-tests/web-library-build-test/config/api-extractor.json b/build-tests/web-library-build-test/config/api-extractor.json deleted file mode 100644 index cc99f8a3e9d..00000000000 --- a/build-tests/web-library-build-test/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/test.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/build-tests/web-library-build-test/config/jest.json b/build-tests/web-library-build-test/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/build-tests/web-library-build-test/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/build-tests/web-library-build-test/config/jest/jest.config.json b/build-tests/web-library-build-test/config/jest/jest.config.json deleted file mode 100644 index e3a1dd341dc..00000000000 --- a/build-tests/web-library-build-test/config/jest/jest.config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "rootDir": "../../", - "globals": { - "ts-jest": { - "skipBabel": true, - "tsConfigFile": "config/jest/tsconfig.json" - } - }, - "moduleFileExtensions": [ - "js" - ], - "moduleNameMapper": { - "ts-jest": "/node_modules/ts-jest/index.js" - }, - "transform": { - "^.+\\.(js|ts|tsx)$": "/node_modules/ts-jest/preprocessor.js" - } -} diff --git a/build-tests/web-library-build-test/config/jest/tsconfig.json b/build-tests/web-library-build-test/config/jest/tsconfig.json deleted file mode 100644 index ff09f000784..00000000000 --- a/build-tests/web-library-build-test/config/jest/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "module": "commonjs", - "allowJs": true - } -} diff --git a/build-tests/web-library-build-test/config/pre-copy.json b/build-tests/web-library-build-test/config/pre-copy.json deleted file mode 100644 index 7f8e3ce6a56..00000000000 --- a/build-tests/web-library-build-test/config/pre-copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "copyTo": { - "lib": [ - "preCopyTest.js" - ] - } -} \ No newline at end of file diff --git a/build-tests/web-library-build-test/config/serve.json b/build-tests/web-library-build-test/config/serve.json deleted file mode 100644 index d13fdf21689..00000000000 --- a/build-tests/web-library-build-test/config/serve.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json", - "port": 4321, - "initialPage": "https://localhost:4321/", - "https": true, - "tryCreateDevCertificate": true -} diff --git a/build-tests/web-library-build-test/gulpfile.js b/build-tests/web-library-build-test/gulpfile.js deleted file mode 100644 index 3cd42315bfa..00000000000 --- a/build-tests/web-library-build-test/gulpfile.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -let path = require('path'); -let build = require('@microsoft/web-library-build'); - -build.sass.setConfig({ useCSSModules: true }); -build.webpack.setConfig({ configPath: null }); - -build.preCopy.cleanMatch = ['src/preCopyTest.ts']; - -build.initialize(require('gulp')); diff --git a/build-tests/web-library-build-test/package.json b/build-tests/web-library-build-test/package.json deleted file mode 100644 index d261d5cc31c..00000000000 --- a/build-tests/web-library-build-test/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "web-library-build-test", - "version": "1.0.21", - "description": "", - "main": "lib/test.js", - "module": "lib-es6/test.js", - "private": true, - "scripts": { - "build": "gulp --clean" - }, - "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/load-themed-styles": "1.10.39", - "@microsoft/web-library-build": "7.4.6", - "@types/jest": "23.3.11", - "gulp": "~4.0.2", - "jest": "~23.6.0", - "ts-jest": "~22.4.6" - } -} diff --git a/build-tests/web-library-build-test/src/.gitignore b/build-tests/web-library-build-test/src/.gitignore deleted file mode 100644 index e1c44845548..00000000000 --- a/build-tests/web-library-build-test/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -preCopyTest.ts \ No newline at end of file diff --git a/build-tests/web-library-build-test/src/TestClass.ts b/build-tests/web-library-build-test/src/TestClass.ts deleted file mode 100644 index 5a41d62ef5c..00000000000 --- a/build-tests/web-library-build-test/src/TestClass.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Test class. - * - * @export - * @class TestClass - */ -export class TestClass { - public log(message: string): void { - console.log(message); - } -} diff --git a/build-tests/web-library-build-test/src/preCopyTest.d.ts b/build-tests/web-library-build-test/src/preCopyTest.d.ts deleted file mode 100644 index 7fe23cb9b62..00000000000 --- a/build-tests/web-library-build-test/src/preCopyTest.d.ts +++ /dev/null @@ -1 +0,0 @@ -export default function preCopyTest(): void; diff --git a/build-tests/web-library-build-test/src/preCopyTest.js b/build-tests/web-library-build-test/src/preCopyTest.js deleted file mode 100644 index 0d1a2a3d122..00000000000 --- a/build-tests/web-library-build-test/src/preCopyTest.js +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function preCopyTest() { - /* no-op */ -} -exports.default = preCopyTest; - diff --git a/build-tests/web-library-build-test/src/test.sass b/build-tests/web-library-build-test/src/test.sass deleted file mode 100644 index 8c4c8c09676..00000000000 --- a/build-tests/web-library-build-test/src/test.sass +++ /dev/null @@ -1,5 +0,0 @@ -body - background: red; - -.foo - border: 1px solid red; diff --git a/build-tests/web-library-build-test/src/test.scss b/build-tests/web-library-build-test/src/test.scss deleted file mode 100644 index a91397f4332..00000000000 --- a/build-tests/web-library-build-test/src/test.scss +++ /dev/null @@ -1,7 +0,0 @@ -body { - background: red; -} - -.foo { - border: 1px solid red; -} diff --git a/build-tests/web-library-build-test/src/test.ts b/build-tests/web-library-build-test/src/test.ts deleted file mode 100644 index a2b064a4121..00000000000 --- a/build-tests/web-library-build-test/src/test.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. - -import testScss from './test.scss'; -import testSass from './test.sass'; -import testFunction from './preCopyTest'; - -/** @public */ -export function log(message: string): void { - console.log(message); -} - -/** @public */ -export function add(num1: number, num2: number): number { - return num1 + num2; -} - -/** @public */ -export function logClass(): void { - console.log(testScss.foo); - console.log(testSass.foo); -} - -testFunction(); diff --git a/build-tests/web-library-build-test/src/test/__snapshots__/foo.test.ts.snap b/build-tests/web-library-build-test/src/test/__snapshots__/foo.test.ts.snap deleted file mode 100644 index b1a1e914736..00000000000 --- a/build-tests/web-library-build-test/src/test/__snapshots__/foo.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`foo test can test snapshot 1`] = `1.4848484848484849`; diff --git a/build-tests/web-library-build-test/src/test/foo.test.ts b/build-tests/web-library-build-test/src/test/foo.test.ts deleted file mode 100644 index 80f237d42f4..00000000000 --- a/build-tests/web-library-build-test/src/test/foo.test.ts +++ /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. - -import { add } from '../test'; - -describe('foo test', () => { - it('can assert using chai', () => { - expect(add(1, 2) === 3); - }); - - it('can assert using jest', () => { - expect(add(1, 2)).toBe(3); - }); - - it('can test snapshot', () => { - expect(add(2 / 3, 9 / 11)).toMatchSnapshot(); - }); -}); diff --git a/build-tests/web-library-build-test/tsconfig.json b/build-tests/web-library-build-test/tsconfig.json deleted file mode 100644 index 27f33d4cc16..00000000000 --- a/build-tests/web-library-build-test/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-web.json", - "compilerOptions": { - "types": [ - "jest" - ] - } -} diff --git a/build-tests/web-library-build-test/tslint.json b/build-tests/web-library-build-test/tslint.json deleted file mode 100644 index 60db661e377..00000000000 --- a/build-tests/web-library-build-test/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@microsoft/rush-stack-compiler-3.5/includes/tslint.json" -} 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..a3516b19e56 --- /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"] + } + ] +} 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..193c50a3ae9 --- /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.98.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..dad0392042f --- /dev/null +++ b/build-tests/webpack-local-version-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$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, + "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..ef670ec1c8d --- /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/index.js` + } + }; +}; diff --git a/common/autoinstallers/rush-prettier/package.json b/common/autoinstallers/rush-prettier/package.json new file mode 100644 index 00000000000..2b3a8597862 --- /dev/null +++ b/common/autoinstallers/rush-prettier/package.json @@ -0,0 +1,9 @@ +{ + "name": "rush-prettier", + "version": "1.0.0", + "private": true, + "dependencies": { + "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 new file mode 100644 index 00000000000..94e04d1885c --- /dev/null +++ b/common/autoinstallers/rush-prettier/pnpm-lock.yaml @@ -0,0 +1,70 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + prettier: + specifier: 3.6.2 + version: 3.6.2 + pretty-quick: + specifier: 4.2.2 + version: 4.2.2(prettier@3.6.2) + +packages: + + /@pkgr/core@0.2.9: + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: false + + /ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + dev: false + + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: false + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: false + + /picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + dev: false + + /prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + dev: false + + /pretty-quick@4.2.2(prettier@3.6.2): + resolution: {integrity: sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + dependencies: + '@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 + tinyexec: 0.3.2 + tslib: 2.8.1 + dev: false + + /tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + dev: false + + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + dev: false diff --git a/common/changes/@microsoft/rush/copilot-fix-resolutions-dependency-hash_2025-11-25-21-27.json b/common/changes/@microsoft/rush/copilot-fix-resolutions-dependency-hash_2025-11-25-21-27.json new file mode 100644 index 00000000000..43883d32b8d --- /dev/null +++ b/common/changes/@microsoft/rush/copilot-fix-resolutions-dependency-hash_2025-11-25-21-27.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Hash full shrinkwrap entry to detect sub-dependency resolution changes", + "type": "minor", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "198982749+Copilot@users.noreply.github.com" +} diff --git a/common/changes/@microsoft/rush/sennyeya-pnpm-catalog_2025-11-25-18-38.json b/common/changes/@microsoft/rush/sennyeya-pnpm-catalog_2025-11-25-18-38.json new file mode 100644 index 00000000000..afcb7b99bb0 --- /dev/null +++ b/common/changes/@microsoft/rush/sennyeya-pnpm-catalog_2025-11-25-18-38.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Add support for defining pnpm catalog config.", + "type": "none", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "aramissennyeydd@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/2025-11-11-01-31.json b/common/changes/@rushstack/eslint-plugin-packlets/2025-11-11-01-31.json new file mode 100644 index 00000000000..a04cd0021ef --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/2025-11-11-01-31.json @@ -0,0 +1,11 @@ +{ + "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/bump-cyclics_2025-10-24-22-51.json b/common/changes/@rushstack/eslint-plugin-packlets/bump-cyclics_2025-10-24-22-51.json new file mode 100644 index 00000000000..a04cd0021ef --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/bump-cyclics_2025-10-24-22-51.json @@ -0,0 +1,11 @@ +{ + "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/main_2025-10-14-22-16.json b/common/changes/@rushstack/eslint-plugin-packlets/main_2025-10-14-22-16.json new file mode 100644 index 00000000000..a04cd0021ef --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/main_2025-10-14-22-16.json @@ -0,0 +1,11 @@ +{ + "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-security/2025-11-11-01-31.json b/common/changes/@rushstack/eslint-plugin-security/2025-11-11-01-31.json new file mode 100644 index 00000000000..e8c34c96411 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/2025-11-11-01-31.json @@ -0,0 +1,11 @@ +{ + "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/bump-cyclics_2025-10-24-22-51.json b/common/changes/@rushstack/eslint-plugin-security/bump-cyclics_2025-10-24-22-51.json new file mode 100644 index 00000000000..e8c34c96411 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/bump-cyclics_2025-10-24-22-51.json @@ -0,0 +1,11 @@ +{ + "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_2025-10-14-22-16.json b/common/changes/@rushstack/eslint-plugin-security/main_2025-10-14-22-16.json new file mode 100644 index 00000000000..e8c34c96411 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/main_2025-10-14-22-16.json @@ -0,0 +1,11 @@ +{ + "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/2025-11-11-01-31.json b/common/changes/@rushstack/eslint-plugin/2025-11-11-01-31.json new file mode 100644 index 00000000000..5669a1df6aa --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/2025-11-11-01-31.json @@ -0,0 +1,11 @@ +{ + "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/localization-plugin/move-terminal_2022-01-20-19-34.json b/common/changes/@rushstack/localization-plugin/move-terminal_2022-01-20-19-34.json new file mode 100644 index 00000000000..c44c0f04e57 --- /dev/null +++ b/common/changes/@rushstack/localization-plugin/move-terminal_2022-01-20-19-34.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/localization-plugin", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/localization-plugin" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/2025-11-11-01-31.json b/common/changes/@rushstack/problem-matcher/2025-11-11-01-31.json new file mode 100644 index 00000000000..a8d616334fa --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/2025-11-11-01-31.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/problem-matcher/bump-cyclics_2025-10-01-02-51.json b/common/changes/@rushstack/problem-matcher/bump-cyclics_2025-10-01-02-51.json new file mode 100644 index 00000000000..222a84da6d7 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/bump-cyclics_2025-10-01-02-51.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/bump-cyclics_2025-10-24-22-51.json b/common/changes/@rushstack/problem-matcher/bump-cyclics_2025-10-24-22-51.json new file mode 100644 index 00000000000..a8d616334fa --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/bump-cyclics_2025-10-24-22-51.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/problem-matcher/bump-eslint_2025-10-07-19-34.json b/common/changes/@rushstack/problem-matcher/bump-eslint_2025-10-07-19-34.json new file mode 100644 index 00000000000..222a84da6d7 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/bump-eslint_2025-10-07-19-34.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/main_2025-10-14-22-16.json b/common/changes/@rushstack/problem-matcher/main_2025-10-14-22-16.json new file mode 100644 index 00000000000..a8d616334fa --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/main_2025-10-14-22-16.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/2025-11-11-01-31.json b/common/changes/@rushstack/rig-package/2025-11-11-01-31.json new file mode 100644 index 00000000000..c66505525a1 --- /dev/null +++ b/common/changes/@rushstack/rig-package/2025-11-11-01-31.json @@ -0,0 +1,11 @@ +{ + "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/rig-package/bump-cyclics_2025-10-24-22-51.json b/common/changes/@rushstack/rig-package/bump-cyclics_2025-10-24-22-51.json new file mode 100644 index 00000000000..c66505525a1 --- /dev/null +++ b/common/changes/@rushstack/rig-package/bump-cyclics_2025-10-24-22-51.json @@ -0,0 +1,11 @@ +{ + "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/rig-package/bump-eslint_2025-10-07-19-34.json b/common/changes/@rushstack/rig-package/bump-eslint_2025-10-07-19-34.json new file mode 100644 index 00000000000..1c1df562afb --- /dev/null +++ b/common/changes/@rushstack/rig-package/bump-eslint_2025-10-07-19-34.json @@ -0,0 +1,10 @@ +{ + "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/json-schemas-artifact_2025-11-04-02-46.json b/common/changes/@rushstack/rig-package/json-schemas-artifact_2025-11-04-02-46.json new file mode 100644 index 00000000000..c66505525a1 --- /dev/null +++ b/common/changes/@rushstack/rig-package/json-schemas-artifact_2025-11-04-02-46.json @@ -0,0 +1,11 @@ +{ + "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/rig-package/main_2025-10-14-22-16.json b/common/changes/@rushstack/rig-package/main_2025-10-14-22-16.json new file mode 100644 index 00000000000..c66505525a1 --- /dev/null +++ b/common/changes/@rushstack/rig-package/main_2025-10-14-22-16.json @@ -0,0 +1,11 @@ +{ + "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/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json b/common/changes/@rushstack/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json new file mode 100644 index 00000000000..0fd5df88305 --- /dev/null +++ b/common/changes/@rushstack/tls-sync-vscode-shared/bmiddha-tls-sync_2025-06-27-01-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/tls-sync-vscode-shared", + "comment": "Add shared utilities for the Workspace and UI TLS Sync VS Code extensions", + "type": "minor" + } + ], + "packageName": "@rushstack/tls-sync-vscode-shared" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/2025-11-11-01-31.json b/common/changes/@rushstack/tree-pattern/2025-11-11-01-31.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/2025-11-11-01-31.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-01-07-39.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-01-07-39.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-01-07-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-11-02-24.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-11-02-24.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-03-11-02-24.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-07-07-23-33.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-07-07-23-33.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-07-07-23-33.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-08-31-01-08.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-08-31-01-08.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-08-31-01-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-10-01-02-51.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-10-01-02-51.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-10-01-02-51.json @@ -0,0 +1,10 @@ +{ + "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/bump-cyclics_2025-10-24-22-51.json b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-10-24-22-51.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-cyclics_2025-10-24-22-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/bump-eslint_2025-10-07-19-34.json b/common/changes/@rushstack/tree-pattern/bump-eslint_2025-10-07-19-34.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-eslint_2025-10-07-19-34.json @@ -0,0 +1,10 @@ +{ + "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/bump-ts_2025-02-19-19-31.json b/common/changes/@rushstack/tree-pattern/bump-ts_2025-02-19-19-31.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/bump-ts_2025-02-19-19-31.json @@ -0,0 +1,10 @@ +{ + "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/clean-up-cyclic-projects_2025-04-04-18-03.json b/common/changes/@rushstack/tree-pattern/clean-up-cyclic-projects_2025-04-04-18-03.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/clean-up-cyclic-projects_2025-04-04-18-03.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ 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/heft-jest-punycode_2024-12-10-05-37.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/heft-jest-punycode_2024-12-10-05-37.json @@ -0,0 +1,10 @@ +{ + "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/main_2024-09-20-22-48.json b/common/changes/@rushstack/tree-pattern/main_2024-09-20-22-48.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2024-09-20-22-48.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file 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 new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2024-11-23-00-43.json @@ -0,0 +1,10 @@ +{ + "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/main_2025-02-25-02-18.json b/common/changes/@rushstack/tree-pattern/main_2025-02-25-02-18.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2025-02-25-02-18.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/main_2025-03-01-05-27.json b/common/changes/@rushstack/tree-pattern/main_2025-03-01-05-27.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2025-03-01-05-27.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/main_2025-04-24-22-13.json b/common/changes/@rushstack/tree-pattern/main_2025-04-24-22-13.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2025-04-24-22-13.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/main_2025-07-23-21-06.json b/common/changes/@rushstack/tree-pattern/main_2025-07-23-21-06.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2025-07-23-21-06.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/main_2025-10-14-22-16.json b/common/changes/@rushstack/tree-pattern/main_2025-10-14-22-16.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/main_2025-10-14-22-16.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/move-heft-plugins-to-decoupled-local-node-rig_2025-04-08-02-35.json b/common/changes/@rushstack/tree-pattern/move-heft-plugins-to-decoupled-local-node-rig_2025-04-08-02-35.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/move-heft-plugins-to-decoupled-local-node-rig_2025-04-08-02-35.json @@ -0,0 +1,10 @@ +{ + "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/octogonz-bump-decoupled_2025-01-07-23-21.json b/common/changes/@rushstack/tree-pattern/octogonz-bump-decoupled_2025-01-07-23-21.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/octogonz-bump-decoupled_2025-01-07-23-21.json @@ -0,0 +1,10 @@ +{ + "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/ts-5.8_2025-03-11-00-18.json b/common/changes/@rushstack/tree-pattern/ts-5.8_2025-03-11-00-18.json new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/ts-5.8_2025-03-11-00-18.json @@ -0,0 +1,10 @@ +{ + "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/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/tree-pattern/update-cyclics_2024-12-04-01-12.json new file mode 100644 index 00000000000..619a10c75e3 --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/update-cyclics_2024-12-04-01-12.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file 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 new file mode 100644 index 00000000000..120c33a1f7e --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/user-danade-BumpEslintUtils_2024-08-13-00-25.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/tree-pattern", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/tree-pattern" +} \ No newline at end of file diff --git a/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json b/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json new file mode 100644 index 00000000000..ea49adc9636 --- /dev/null +++ b/common/changes/tls-sync-vscode-extension-pack/bmiddha-tls-sync_2025-07-01-00-21.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "tls-sync-vscode-extension-pack", + "comment": "Add VSCode Extension to sync TLS certificates when using VS Code remoting.", + "type": "minor" + } + ], + "packageName": "tls-sync-vscode-extension-pack" +} \ No newline at end of file diff --git a/common/config/azure-pipelines/ci.yaml b/common/config/azure-pipelines/ci.yaml deleted file mode 100644 index 35aa8b862c9..00000000000 --- a/common/config/azure-pipelines/ci.yaml +++ /dev/null @@ -1,16 +0,0 @@ -pool: - vmImage: 'ubuntu-latest' -jobs: -- job: PRBuild - condition: succeeded() - strategy: - matrix: - 'NodeJs 8': - NodeVersion: 8 - 'NodeJs 10': - NodeVersion: 10 - 'NodeJs 12': - NodeVersion: 12 - steps: - - checkout: self - - template: templates/build.yaml diff --git a/common/config/azure-pipelines/npm-publish-rush.yaml b/common/config/azure-pipelines/npm-publish-rush.yaml index b1447cf8073..2502d76dbd5 100644 --- a/common/config/azure-pipelines/npm-publish-rush.yaml +++ b/common/config/azure-pipelines/npm-publish-rush.yaml @@ -1,7 +1,66 @@ -pool: - vmImage: 'ubuntu-latest' variables: - NodeVersion: 10 - VersionPolicy: rush -steps: -- template: templates/buildAndPublish.yaml + - name: FORCE_COLOR + value: 1 + - name: SourceBranch + value: $[ replace(replace(resources.repositories.self.ref, 'refs/heads/', ''), 'refs/pull/', 'refs/remotes/pull/') ] + +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + - stage: + jobs: + - job: + pool: + name: publish-rushstack + os: linux + templateContext: + outputs: + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/published-versions + artifactName: published-versions + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/json-schemas + artifactName: json-schemas + steps: + - checkout: self + persistCredentials: true + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - template: /common/config/azure-pipelines/templates/build.yaml@self + + - template: /common/config/azure-pipelines/templates/bump-versions.yaml@self + parameters: + VersionPolicyName: noRush + BranchName: $(SourceBranch) + + - template: /common/config/azure-pipelines/templates/bump-versions.yaml@self + parameters: + VersionPolicyName: rush + BranchName: $(SourceBranch) + + - 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/publish.yaml@self + parameters: + VersionPolicyName: rush + BranchName: $(SourceBranch) + + - 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 5f70e981e75..86f88fa8040 100644 --- a/common/config/azure-pipelines/npm-publish.yaml +++ b/common/config/azure-pipelines/npm-publish.yaml @@ -1,7 +1,56 @@ -pool: - vmImage: 'ubuntu-latest' variables: - NodeVersion: 10 - VersionPolicy: noRush -steps: -- template: templates/buildAndPublish.yaml + - name: FORCE_COLOR + value: 1 + - name: SourceBranch + value: $[ replace(replace(resources.repositories.self.ref, 'refs/heads/', ''), 'refs/pull/', 'refs/remotes/pull/') ] + +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + - stage: + jobs: + - job: + pool: + name: publish-rushstack + os: linux + templateContext: + outputs: + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/published-versions + artifactName: published-versions + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/json-schemas + artifactName: json-schemas + steps: + - checkout: self + persistCredentials: true + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - template: /common/config/azure-pipelines/templates/build.yaml@self + + - template: /common/config/azure-pipelines/templates/bump-versions.yaml@self + parameters: + VersionPolicyName: noRush + BranchName: $(SourceBranch) + + - 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/post-publish.yaml@self diff --git a/common/config/azure-pipelines/templates/build.yaml b/common/config/azure-pipelines/templates/build.yaml index 3a77161242b..05f11e3d677 100644 --- a/common/config/azure-pipelines/templates/build.yaml +++ b/common/config/azure-pipelines/templates/build.yaml @@ -1,16 +1,26 @@ +parameters: + - name: BuildParameters + type: string + default: '' + steps: -- task: NodeTool@0 - displayName: 'Use Node $(NodeVersion).x' - inputs: - versionSpec: '$(NodeVersion).x' - checkLatest: true -- 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' -- script: 'node common/scripts/install-run-rush.js change --verify' - displayName: 'Verify Change Logs' -- script: 'node common/scripts/install-run-rush.js install' - displayName: 'Rush Install' -- script: 'node common/scripts/install-run-rush.js rebuild --verbose --production' - displayName: 'Rush Rebuild' + - 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' + + - script: 'node common/scripts/install-run-rush.js change --verify' + displayName: 'Verify Change Logs' + + - script: 'node common/scripts/install-run-rush.js install' + displayName: 'Rush Install' + + # - bash: | + # /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + # echo ">>> Started xvfb" + # 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)' diff --git a/common/config/azure-pipelines/templates/buildAndPublish.yaml b/common/config/azure-pipelines/templates/buildAndPublish.yaml deleted file mode 100644 index 5675650c399..00000000000 --- a/common/config/azure-pipelines/templates/buildAndPublish.yaml +++ /dev/null @@ -1,10 +0,0 @@ -steps: -- checkout: self - persistCredentials: true -- template: ./build.yaml -- script: 'node common/scripts/install-run-rush.js version --bump --version-policy $(VersionPolicy) --target-branch $(Build.SourceBranchName)' - displayName: 'Rush Version' -- script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --target-branch $(Build.SourceBranchName) --add-commit-details --set-access-level public' - displayName: 'Rush Publish' - env: - NPM_AUTH_TOKEN: $(npmToken) \ No newline at end of file diff --git a/common/config/azure-pipelines/templates/bump-versions.yaml b/common/config/azure-pipelines/templates/bump-versions.yaml new file mode 100644 index 00000000000..b2b461b987a --- /dev/null +++ b/common/config/azure-pipelines/templates/bump-versions.yaml @@ -0,0 +1,10 @@ +parameters: + - name: VersionPolicyName + type: string + - name: BranchName + type: string + 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 }})' diff --git a/common/config/azure-pipelines/templates/install-node.yaml b/common/config/azure-pipelines/templates/install-node.yaml new file mode 100644 index 00000000000..9983a8a311e --- /dev/null +++ b/common/config/azure-pipelines/templates/install-node.yaml @@ -0,0 +1,10 @@ +parameters: + - name: NodeMajorVersion + type: number + default: 20 + +steps: + - task: NodeTool@0 + inputs: + versionSpec: '${{ parameters.NodeMajorVersion }}.x' + displayName: 'Install Node.js ${{ parameters.NodeMajorVersion }}' 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..ecf0da731d2 --- /dev/null +++ b/common/config/azure-pipelines/templates/post-publish.yaml @@ -0,0 +1,5 @@ +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' + - script: 'node repo-scripts/repo-toolbox/lib/start.js collect-json-schemas --output-path $(Build.ArtifactStagingDirectory)/json-schemas' + displayName: 'Collect JSON Schemas' diff --git a/common/config/azure-pipelines/templates/publish.yaml b/common/config/azure-pipelines/templates/publish.yaml new file mode 100644 index 00000000000..281d7edae9b --- /dev/null +++ b/common/config/azure-pipelines/templates/publish.yaml @@ -0,0 +1,12 @@ +parameters: + - name: VersionPolicyName + type: string + - name: BranchName + type: string + 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) diff --git a/common/config/azure-pipelines/vscode-extension-publish.yaml b/common/config/azure-pipelines/vscode-extension-publish.yaml new file mode 100644 index 00000000000..365d0e75020 --- /dev/null +++ b/common/config/azure-pipelines/vscode-extension-publish.yaml @@ -0,0 +1,117 @@ +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: '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 + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + - stage: + jobs: + - job: + 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 + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - template: /common/config/azure-pipelines/templates/build.yaml@self + parameters: + BuildParameters: > + --to tag:vsix + + - ${{ 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/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/start.js publish-vsix --vsix-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.vsixPath }} --publish-unsigned + ${{ else }}: + inlineScript: node node_modules/@rushstack/heft/lib/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/lockfile-explorer/lockfile-lint.json b/common/config/lockfile-explorer/lockfile-lint.json new file mode 100644 index 00000000000..72449103987 --- /dev/null +++ b/common/config/lockfile-explorer/lockfile-lint.json @@ -0,0 +1,42 @@ +/** + * Config file for Lockfile Lint. For more info, please visit: https://lfx.rushstack.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/lockfile-explorer/lockfile-lint.schema.json", + + /** + * The list of rules to be checked by Lockfile Lint. For each rule configuration, the + * type of rule is determined by the `rule` field. + */ + "rules": [ + // /** + // * The `restrict-versions` rule enforces that direct and indirect dependencies must + // * satisfy a specified version range. + // */ + // { + // "rule": "restrict-versions", + // + // /** + // * The name of a workspace project to analyze. + // */ + // "project": "@my-company/my-app", + // + // /** + // * Indicates the package versions to be checked. The `requiredVersions` key is + // * the name of an NPM package, and the value is a SemVer range. If the project has + // * that NPM package as a dependency, then its version must satisfy the SemVer range. + // * This check also applies to devDependencies and peerDependencies, as well as any + // * indirect dependencies of the project. + // */ + // "requiredVersions": { + // /** + // * For example, if `react-router` appears anywhere in the dependency graph of + // * `@my-company/my-app`, then it must be version 5 or 6. + // */ + // "react-router": "5.x || 6.x", + // "react": "^18.3.0", + // "react-dom": "^18.3.0" + // } + // } + ] +} diff --git a/common/config/rush/.npmrc b/common/config/rush/.npmrc deleted file mode 100644 index 237d30461dc..00000000000 --- a/common/config/rush/.npmrc +++ /dev/null @@ -1,12 +0,0 @@ -# Rush uses this file to configure the package registry, regardless of whether the -# package manager is PNPM, NPM, or Yarn. Prior to invoking the package manager, -# Rush will always copy this file to the folder where installation is performed. -# When NPM is the package manager, Rush works around NPM's processing of -# undefined environment variables by deleting any lines that reference undefined -# environment variables. -# -# DO NOT SPECIFY AUTHENTICATION CREDENTIALS IN THIS FILE. It should only be used -# to configure registry sources. - -registry=https://registry.npmjs.org/ -always-auth=false diff --git a/common/config/rush/.npmrc-publish b/common/config/rush/.npmrc-publish index 810cebd3cf6..a0ffdc9d322 100644 --- a/common/config/rush/.npmrc-publish +++ b/common/config/rush/.npmrc-publish @@ -1,13 +1,25 @@ -# Rush uses this file to configure the package registry, regardless of whether the -# package manager is PNPM, NPM, or Yarn. Prior to invoking the package manager, -# Rush will always copy this file to the folder where installation is performed. -# When NPM is the package manager, Rush works around NPM's processing of -# undefined environment variables by deleting any lines that reference undefined -# environment variables. -# -# DO NOT SPECIFY AUTHENTICATION CREDENTIALS IN THIS FILE. It should only be used -# to configure registry sources. - -registry=https://registry.npmjs.org/ -always-auth=true -//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} \ No newline at end of file +# This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish +# is used by the "rush publish" command, as publishing often involves different credentials +# and registries than other operations. +# +# Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc" +# and then temporarily map that folder as the "home directory" for the current user account. +# This enables the same settings to apply for each project folder that gets published. The copied file +# will omit any config lines that reference environment variables that are undefined in that session; +# this avoids problems that would otherwise result due to a missing variable being replaced by +# an empty string. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read the file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# + +registry=https://registry.npmjs.org/ +always-auth=true +//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} + diff --git a/common/config/rush/artifactory.json b/common/config/rush/artifactory.json new file mode 100644 index 00000000000..685fda23c0e --- /dev/null +++ b/common/config/rush/artifactory.json @@ -0,0 +1,103 @@ +/** + * This configuration file manages Rush integration with JFrog Artifactory services. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json", + + "packageRegistry": { + /** + * (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry. + * When enabled, "rush install" will automatically detect when the user's ~/.npmrc + * authentication token is missing or expired. And "rush setup" will prompt the user to + * renew their token. + * + * The default value is false. + */ + "enabled": false, + + /** + * (Required) Specify the URL of your NPM registry. This is the same URL that appears in + * your .npmrc file. It should look something like this example: + * + * https://your-company.jfrog.io/your-project/api/npm/npm-private/ + */ + "registryUrl": "", + + /** + * A list of custom strings that "rush setup" should add to the user's ~/.npmrc file at the time + * when the token is updated. This could be used for example to configure the company registry + * to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush + * operations like "rush add" and "rush install", which get their mappings from the monorepo's + * common/config/rush/.npmrc file). + * + * NOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful + * about adding settings that may interfere with other work outside the monorepo. + */ + "userNpmrcLinesToAdd": [ + // "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/" + ], + + /** + * (Required) Specifies the URL of the Artifactory control panel where the user can generate + * an API key. This URL is printed after the "visitWebsite" message. + * It should look something like this example: https://your-company.jfrog.io/ + * Specify an empty string to suppress this line entirely. + */ + "artifactoryWebsiteUrl": "", + + /** + * Uncomment this line to specify the type of credential to save in the user's ~/.npmrc file. + * The default is "password", which means the user's API token will be traded in for an + * npm password specific to that registry. Optionally you can specify "authToken", which + * will save the user's API token as credentials instead. + */ + // "credentialType": "password", + + /** + * These settings allow the "rush setup" interactive prompts to be customized, for + * example with messages specific to your team or configuration. Specify an empty string + * to suppress that message entirely. + */ + "messageOverrides": { + /** + * Overrides the message that normally says: + * "This monorepo consumes packages from an Artifactory private NPM registry." + */ + // "introduction": "", + /** + * Overrides the message that normally says: + * "Please contact the repository maintainers for help with setting up an Artifactory user account." + */ + // "obtainAnAccount": "", + /** + * Overrides the message that normally says: + * "Please open this URL in your web browser:" + * + * The "artifactoryWebsiteUrl" string is printed after this message. + */ + // "visitWebsite": "", + /** + * Overrides the message that normally says: + * "Your user name appears in the upper-right corner of the JFrog website." + */ + // "locateUserName": "", + /** + * Overrides the message that normally says: + * "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key' + * button if you haven't already done so previously." + */ + // "locateApiKey": "" + /** + * Overrides the message that normally prompts: + * "What is your Artifactory user name?" + */ + // "userNamePrompt": "" + /** + * Overrides the message that normally prompts: + * "What is your Artifactory API key?" + */ + // "apiKeyPrompt": "" + } + } +} diff --git a/common/config/rush/browser-approved-packages.json b/common/config/rush/browser-approved-packages.json index 34c3a91cc03..23c585145b8 100644 --- a/common/config/rush/browser-approved-packages.json +++ b/common/config/rush/browser-approved-packages.json @@ -1,5 +1,110 @@ // DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json", - "packages": [] + "packages": [ + { + "name": "@fluentui/react", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@fluentui/react-components", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "@lifaon/path", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@radix-ui/colors", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@radix-ui/react-checkbox", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@radix-ui/react-icons", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@radix-ui/react-scroll-area", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@radix-ui/react-tabs", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@reduxjs/toolkit", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@rushstack/problem-matcher", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-themed-ui", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-vscode-command-webview", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "@ungap/structured-clone", + "allowedCategories": [ "libraries" ] + }, + { + "name": "axios", + "allowedCategories": [ "libraries" ] + }, + { + "name": "dependency-path", + "allowedCategories": [ "libraries" ] + }, + { + "name": "office-ui-fabric-core", + "allowedCategories": [ "libraries" ] + }, + { + "name": "prism-react-renderer", + "allowedCategories": [ "libraries" ] + }, + { + "name": "react", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "react-dom", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "react-hook-form", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "react-redux", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "redux", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "rxjs", + "allowedCategories": [ "libraries" ] + }, + { + "name": "scheduler", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "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 new file mode 100644 index 00000000000..59bc58ccb99 --- /dev/null +++ b/common/config/rush/build-cache.json @@ -0,0 +1,145 @@ +/** + * This configuration file manages Rush's build cache feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. + * + * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. + */ + "buildCacheEnabled": true, + + /** + * (Required) Choose where project build outputs will be cached. + * + * Possible values: "local-only", "azure-blob-storage", "amazon-s3" + */ + "cacheProvider": "local-only", + + /** + * Setting this property overrides the cache entry ID. If this property is set, it must contain + * a [hash] token. + * + * Other available tokens: + * - [projectName] Example: "@my-scope/my-project" + * - [projectName:normalize] Example: "my-scope+my-project" + * - [phaseName] Example: "_phase:test/api" + * - [phaseName:normalize] Example: "_phase:test+api" + * - [phaseName:trimPrefix] Example: "test/api" + * - [os] Example: "win32" + * - [arch] Example: "x64" + */ + "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" + */ + "azureBlobStorageConfiguration": { + /** + * (Required) The name of the the Azure storage account to use for build cache. + */ + // "storageAccountName": "example", + /** + * (Required) The name of the container in the Azure storage account to use for build cache. + */ + // "storageContainerName": "my-container", + /** + * The Azure environment the storage account exists in. Defaults to AzurePublicCloud. + * + * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" + */ + // "azureEnvironment": "AzurePublicCloud", + /** + * An optional prefix for cache item blob names. + */ + // "blobPrefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "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 + }, + + /** + * Use this configuration with "cacheProvider"="amazon-s3" + */ + "amazonS3Configuration": { + /** + * (Required unless s3Endpoint is specified) The name of the bucket to use for build cache. + * Example: "my-bucket" + */ + // "s3Bucket": "my-bucket", + /** + * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. + * This should not include any path; use the s3Prefix to set the path. + * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" + */ + // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", + /** + * (Required) The Amazon S3 region of the bucket to use for build cache. + * Example: "us-east-1" + */ + // "s3Region": "us-east-1", + /** + * An optional prefix ("folder") for cache items. It should not start with "/". + */ + // "s3Prefix": "my-prefix", + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + }, + + /** + * Use this configuration with "cacheProvider"="http" + */ + "httpConfiguration": { + /** + * (Required) The URL of the server that stores the caches. + * Example: "https://build-cacches.example.com/" + */ + // "url": "https://build-cacches.example.com/", + /** + * (Optional) The HTTP method to use when writing to the cache (defaults to PUT). + * Should be one of PUT, POST, or PATCH. + * Example: "PUT" + */ + // "uploadMethod": "PUT", + /** + * (Optional) HTTP headers to pass to the cache server. + * Example: { "X-HTTP-Company-Id": "109283" } + */ + // "headers": {}, + /** + * (Optional) Shell command that prints the authorization token needed to communicate with the + * cache server, and exits with exit code 0. This command will be executed from the root of + * the monorepo. + * Example: { "exec": "node", "args": ["common/scripts/auth.js"] } + */ + // "tokenHandler": { "exec": "node", "args": ["common/scripts/auth.js"] }, + /** + * (Optional) Prefix for cache keys. + * Example: "my-company-" + */ + // "cacheKeyPrefix": "", + /** + * (Optional) If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + } +} diff --git a/common/config/rush/cobuild.json b/common/config/rush/cobuild.json new file mode 100644 index 00000000000..dbac6a071cc --- /dev/null +++ b/common/config/rush/cobuild.json @@ -0,0 +1,22 @@ +/** + * This configuration file manages Rush's cobuild feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. + * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, + * otherwise the cobuild feature will be disabled. + */ + "cobuildFeatureEnabled": false, + + /** + * (Required) Choose where cobuild lock will be acquired. + * + * The lock provider is registered by the rush plugins. + * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. + */ + "cobuildLockProvider": "redis" +} diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json index 2f7a27d89d4..42a4467c79e 100644 --- a/common/config/rush/command-line.json +++ b/common/config/rush/command-line.json @@ -1,6 +1,6 @@ /** * This configuration file defines custom commands for the "rush" command-line. - * For full documentation, please see https://rushjs.io + * More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", @@ -11,32 +11,76 @@ * "rush my-global-command --help". */ "commands": [ + { + "commandKind": "phased", + "name": "build", + "phases": ["_phase:lite-build", "_phase:build"] + }, + + { + "commandKind": "phased", + "name": "test", + "summary": "Builds all projects and runs their tests.", + "phases": ["_phase:lite-build", "_phase:build", "_phase:test"], + "enableParallelism": true, + "incremental": true + }, + + { + "commandKind": "phased", + "name": "retest", + "summary": "Rebuilds all projects and reruns their tests.", + "phases": ["_phase:lite-build", "_phase:build", "_phase:test"], + "enableParallelism": true, + "incremental": false + }, + + { + "commandKind": "phased", + "name": "start", + "summary": "Build all projects, then watch for changes, build and test.", + "description": "Build all projects, then watches for changes and builds and runs tests for affected projects.", + "safeForSimultaneousRushProcesses": false, + + "enableParallelism": true, + "incremental": true, + // Initial execution only uses the build phase so that all dependencies of watch phases have been built + "phases": ["_phase:lite-build", "_phase:build"], + "watchOptions": { + // Act as though `--watch` is always passed. If false, adds support for passing `--watch`. + "alwaysWatch": true, + // During watch recompilation run both build and test for affected projects + "watchPhases": ["_phase:lite-build", "_phase:build", "_phase:test"] + } + }, // { // /** // * (Required) Determines the type of custom command. - // * Rush's "bulk" commands are invoked separately for each project. Rush will look in - // * each project's package.json file for a "scripts" entry whose name matches the - // * command name. By default, the command will run for every project in the repo, - // * according to the dependency graph (similar to how "rush build" works). + // * Rush's "bulk" commands are invoked separately for each project. By default, the command will run for + // * every project in the repo, according to the dependency graph (similar to how "rush build" works). // * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. // */ // "commandKind": "bulk", - // + // // /** // * (Required) The name that will be typed as part of the command line. This is also the name - // * of the "scripts" hook in the project's package.json file. + // * of the "scripts" hook in the project's package.json file (if "shellCommand" is not specified). + // * // * The name should be comprised of lower case words separated by hyphens or colons. The name should include an // * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands // * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). + // * + // * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command + // * and will call the "rebuild" script instead of the "build" script. // */ // "name": "my-bulk-command", - // + // // /** // * (Required) A short summary of the custom command to be shown when printing command line // * help, e.g. "rush --help". // */ // "summary": "Example bulk custom command", - // + // // /** // * A detailed description of the command to be shown when printing command line // * help (e.g. "rush --help my-command"). @@ -46,7 +90,7 @@ // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "This is an example custom command that runs separately for each project", - // + // // /** // * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously // * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the @@ -56,14 +100,24 @@ // * In particular, this is needed for custom scripts that invoke other Rush commands. // */ // "safeForSimultaneousRushProcesses": false, - // + // + // /** + // * (Optional) If the `shellCommand` field is set for a bulk command, Rush will invoke it for each + // * selected project; otherwise, Rush will invoke the package.json `"scripts"` entry matching Rush command name. + // * + // * The string is the path to a script that will be invoked using the OS shell. The working directory will be + // * the folder that contains rush.json. If custom parameters are associated with this command, their + // * values will be appended to the end of this string. + // */ + // // "shellCommand": "node common/scripts/my-bulk-command.js", + // // /** // * (Required) If true, then this command is safe to be run in parallel, i.e. executed // * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism // * projects will not start processing until their dependencies have completed processing. // */ // "enableParallelism": 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 @@ -71,14 +125,14 @@ // * you can set "ignoreDependencyOrder" to true to increase parallelism. // */ // "ignoreDependencyOrder": false, - // + // // /** // * Normally Rush requires that each project's package.json has a "scripts" entry matching // * the custom command name. To disable this check, set "ignoreMissingScript" to true; // * projects with a missing definition will be skipped. // */ // "ignoreMissingScript": false, - // + // // /** // * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: // * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". @@ -89,7 +143,7 @@ // * // * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because // * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. - // * In an active monorepo, we've found that if you allow any warnings in your master branch, it inadvertently + // * In an active monorepo, we've found that if you allow any warnings in your main branch, it inadvertently // * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings // * have accumulated that warnings no longer serve any useful purpose. // * @@ -99,29 +153,112 @@ // * // * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. // */ - // "allowWarningsInSuccessfulBuild": false + // "allowWarningsInSuccessfulBuild": false, + // + // /** + // * If true then this command will be incremental like the built-in "build" command + // */ + // "incremental": false, + // + // /** + // * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush + // * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a + // * change is detected, the command will be invoked again for the changed project and any selected projects that + // * directly or indirectly depend on it. + // * + // * For details, refer to the website article "Using watch mode". + // */ + // "watchForChanges": false, + // + // /** + // * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of + // * projects' own folders. + // */ + // "disableBuildCache": false // }, - // + // // { // /** // * (Required) Determines the type of custom command. // * Rush's "global" commands are invoked once for the entire repo. // */ // "commandKind": "global", - // + // // "name": "my-global-command", // "summary": "Example global custom command", // "description": "This is an example custom command that runs once for the entire repo", - // + // // "safeForSimultaneousRushProcesses": false, - // + // // /** - // * A script that will be invoked using the OS shell. The working directory will be the folder - // * that contains rush.json. If custom parameters are associated with this command, their + // * (Required) A script that will be invoked using the OS shell. The working directory will be + // * the folder that contains rush.json. If custom parameters are associated with this command, their // * values will be appended to the end of this string. // */ - // "shellCommand": "node common/scripts/my-global-command.js" + // "shellCommand": "node common/scripts/my-global-command.js", + // + // /** + // * If your "shellCommand" script depends on NPM packages, the recommended best practice is + // * to make it into a regular Rush project that builds using your normal toolchain. In cases where + // * the command needs to work without first having to run "rush build", the recommended practice + // * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. + // * + // * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with + // * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to + // * install these dependencies before an associated command is invoked. Autoinstallers have the + // * advantage that they work even in a branch where "rush install" is broken, which makes them a + // * good solution for Git hook scripts. But they have the disadvantages of not being buildable + // * projects, and of increasing the overall installation footprint for your monorepo. + // * + // * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. + // * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and + // * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when + // * invoking the "shellCommand". + // */ + // // "autoinstallerName": "my-task" // } + + { + "name": "prettier", + "commandKind": "global", + "summary": "Used by the pre-commit Git hook. This command invokes Prettier to reformat staged changes.", + + "autoinstallerName": "rush-prettier", + + // This will invoke common/autoinstall/rush-prettier/node_modules/.bin/pretty-quick + "shellCommand": "pretty-quick --staged", + + "safeForSimultaneousRushProcesses": true + } + ], + + "phases": [ + { + // Used for very simple builds that don't support CLI arguments like `--production` or `--fix` + "name": "_phase:lite-build", + "dependencies": { + "upstream": ["_phase:lite-build", "_phase:build"] + }, + "missingScriptBehavior": "silent", + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:build", + "dependencies": { + "self": ["_phase:lite-build"], + "upstream": ["_phase:build"] + }, + "missingScriptBehavior": "log", + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:test", + "dependencies": { + "self": ["_phase:lite-build", "_phase:build"] + }, + "missingScriptBehavior": "silent", + "allowWarningsOnSuccess": false + } ], /** @@ -135,12 +272,12 @@ // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. // */ // "parameterKind": "flag", - // + // // /** // * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. // */ // "longName": "--my-flag", - // + // // /** // * An optional alternative short name for the parameter. It must be a dash followed by a single // * lower-case or upper-case letter, which is case-sensitive. @@ -151,7 +288,7 @@ // * a short name if you expect the parameter to be needed very often in everyday operations. // */ // "shortName": "-m", - // + // // /** // * (Required) A long description to be shown in the command-line help. // * @@ -159,33 +296,158 @@ // * documentation can make a big difference for the developer experience in your repo. // */ // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", - // + // // /** // * (Required) A list of custom commands and/or built-in Rush commands that this parameter may // * be used with. The parameter will be appended to the shell command that Rush invokes. // */ - // "associatedCommands": [ "build", "rebuild" ] + // "associatedCommands": ["build", "rebuild"] // }, - // + // // { // /** // * (Required) Determines the type of custom parameter. - // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. + // * A "string" is a custom command-line parameter whose argument is a single text string. + // */ + // "parameterKind": "string", + // "longName": "--my-string", + // "description": "A custom string parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // "argumentName": "SOME_TEXT", + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + // * allowable alternatives (similar to an enum). // */ // "parameterKind": "choice", // "longName": "--my-choice", // "description": "A custom choice parameter for the \"my-global-command\" custom command", - // - // "associatedCommands": [ "my-global-command" ], - // + // + // "associatedCommands": ["my-global-command"], + // "required": false, + // // /** - // * Normally if a parameter is omitted from the command line, it will not be passed - // * to the shell command. this value will be inserted by default. Whereas if a "defaultValue" - // * is defined, the parameter will always be passed to the shell command, and will use the - // * default value if unspecified. The value must be one of the defined alternatives. + // * If a "defaultValue" is specified, then if the Rush command line is invoked without + // * this parameter, it will be automatically added with the "defaultValue" as the argument. + // * The value must be one of the defined alternatives. // */ // "defaultValue": "vanilla", - // + // + // /** + // * (Required) A list of alternative argument values that can be chosen for this parameter. + // */ + // "alternatives": [ + // { + // /** + // * A token that is one of the alternatives that can be used with the choice parameter, + // * e.g. "vanilla" in "--flavor vanilla". + // */ + // "name": "vanilla", + // + // /** + // * A detailed description for the alternative that can be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "Use the vanilla flavor" + // }, + // + // { + // "name": "chocolate", + // "description": "Use the chocolate flavor" + // }, + // + // { + // "name": "strawberry", + // "description": "Use the strawberry flavor" + // } + // ] + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * An "integer" is a custom command-line parameter whose value is an integer number. + // */ + // "parameterKind": "integer", + // "longName": "--my-integer", + // "description": "A custom integer parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // "argumentName": "SOME_NUMBER", + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * An "integerList" is a custom command-line parameter whose argument is an integer. + // * The parameter can be specified multiple times to build a list. + // * + // * For example, if the parameter name is "--my-integer-list", then the custom command + // * might be invoked as + // * `rush my-global-command --my-integer-list 1 --my-integer-list 2 --my-integer-list 3` + // * and the parsed array would be [1,2,3]. + // */ + // "parameterKind": "integerList", + // "longName": "--my-integer-list", + // "description": "A custom integer list parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // "argumentName": "SOME_NUMBER", + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * An "stringList" is a custom command-line parameter whose argument is a text string. + // * The parameter can be specified multiple times to build a list. + // * + // * For example, if the parameter name is "--my-string-list", then the custom command + // * might be invoked as + // * `rush my-global-command --my-string-list A --my-string-list B --my-string-list C` + // * and the parsed array would be [A,B,C]. + // */ + // "parameterKind": "stringList", + // "longName": "--my-string-list", + // "description": "A custom string list parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // "argumentName": "SOME_TEXT", + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + // * allowable alternatives (similar to an enum). + // * The parameter can be specified multiple times to build a list. + // * + // * For example, if the parameter name is "--my-choice-list", then the custom command + // * might be invoked as + // * `rush my-global-command --my-string-list vanilla --my-string-list chocolate` + // * and the parsed array would be [vanilla,chocolate]. + // */ + // "parameterKind": "choiceList", + // "longName": "--my-choice-list", + // "description": "A custom choice list parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // "required": false, + // // /** // * (Required) A list of alternative argument values that can be chosen for this parameter. // */ @@ -196,21 +458,21 @@ // * e.g. "vanilla" in "--flavor vanilla". // */ // "name": "vanilla", - // + // // /** // * A detailed description for the alternative that can be shown in the command-line help. // * // * Whenever you introduce commands/parameters, taking a little time to write meaningful // * documentation can make a big difference for the developer experience in your repo. // */ - // "description": "Use the vanilla flavor (the default)" + // "description": "Use the vanilla flavor" // }, - // + // // { // "name": "chocolate", // "description": "Use the chocolate flavor" // }, - // + // // { // "name": "strawberry", // "description": "Use the strawberry flavor" @@ -221,13 +483,29 @@ "longName": "--no-color", "parameterKind": "flag", "description": "disable colors in the build log, defaults to 'true'", - "associatedCommands": [ "build", "rebuild" ] + "associatedPhases": ["_phase:build", "_phase:test"], + "associatedCommands": ["build", "rebuild", "test", "retest"] + }, + { + "longName": "--update-snapshots", + "parameterKind": "flag", + "description": "Update Jest snapshots", + "associatedPhases": ["_phase:test"], + "associatedCommands": ["test", "retest"] }, { "longName": "--production", "parameterKind": "flag", "description": "Perform a production build, including minification and localization steps", - "associatedCommands": [ "build", "rebuild" ] + "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/common-versions.json b/common/config/rush/common-versions.json deleted file mode 100644 index a878f272ca6..00000000000 --- a/common/config/rush/common-versions.json +++ /dev/null @@ -1,85 +0,0 @@ -/** - * This configuration file specifies NPM dependency version selections that affect all projects - * in a Rush repo. For full documentation, please see https://rushjs.io - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", - - /** - * A table that specifies a "preferred version" for a given NPM package. This feature is typically used - * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. - * - * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into - * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager - * will calculate versions. The specific effect depends on your package manager. Generally it will have no - * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be - * achieved using the pnpmfile.js hook. See the Rush documentation for more details. - * - * After modifying this field, it's recommended to run "rush update --full" so that the package manager - * will recalculate all version selections. - */ - "preferredVersions": { - - /** - * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, - * instead of the latest version. - */ - // "some-library": "1.2.3" - - // From the allowedAlternativeVersions list below, this should be the TypeScript version that's used to - // build most of the projects in the repo. Preferring it avoids errors for indirect dependencies - // that request it as a peer dependency. - "typescript": "~3.5.3", - - // Workaround for https://github.com/microsoft/rushstack/issues/1466 - "eslint": "~6.5.1", - - "@types/webpack": "4.39.8", - "webpack": "~4.31.0" - }, - - /** - * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, - * except in cases where different projects specify different version ranges for a given dependency. For older - * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause - * trouble for indirect dependencies with incompatible peerDependencies ranges. - * - * The default value is true. If you're encountering installation errors related to peer dependencies, - * it's recommended to set this to false. - * - * After modifying this field, it's recommended to run "rush update --full" so that the package manager - * will recalculate all version selections. - */ - // "implicitlyPreferredVersions": false, - - /** - * The "rush check" command can be used to enforce that every project in the repo must specify - * the same SemVer range for a given dependency. However, sometimes exceptions are needed. - * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be - * accepted by "rush check" for a given dependency. - * - * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE - * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). - * This design avoids unnecessary churn in this file. - */ - "allowedAlternativeVersions": { - - /** - * 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): - */ - "typescript": [ - "~2.4.2", - "~2.7.2", - "~2.8.4", - "~2.9.2", - "~3.0.3", - "~3.1.6", - "~3.2.4", - "~3.4.3", - "~3.5.3", - "~3.6.4", - "~3.7.2" - ] - } -} diff --git a/common/config/rush/custom-tips.json b/common/config/rush/custom-tips.json new file mode 100644 index 00000000000..5f9ce32bfb8 --- /dev/null +++ b/common/config/rush/custom-tips.json @@ -0,0 +1,29 @@ +/** + * This configuration file allows repo maintainers to configure extra details to be + * printed alongside certain Rush messages. More documentation is available on the + * Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", + + /** + * Custom tips allow you to annotate Rush's console messages with advice tailored for + * your specific monorepo. + */ + "customTips": [ + // { + // /** + // * (REQUIRED) An identifier indicating a message that may be printed by Rush. + // * If that message is printed, then this custom tip will be shown. + // * The list of available tip identifiers can be found on this page: + // * https://rushjs.io/pages/maintainer/custom_tips/ + // */ + // "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + // + // /** + // * (REQUIRED) The message text to be displayed for this tip. + // */ + // "message": "For additional troubleshooting information, refer this wiki article:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" + // } + ] +} diff --git a/common/config/rush/experiments.json b/common/config/rush/experiments.json index b233e6a6a99..f8071d80056 100644 --- a/common/config/rush/experiments.json +++ b/common/config/rush/experiments.json @@ -1,16 +1,120 @@ /** * This configuration file allows repo maintainers to enable and disable experimental - * Rush features. For full documentation, please see https://rushjs.io + * Rush features. More documentation is available on the Rush website: https://rushjs.io */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", /** - * Rush 5.14.0 improved incremental builds to ignore spurious changes in the pnpm-lock.json file. - * This optimization is enabled by default. If you encounter a problem where "rush build" is neglecting - * to build some projects, please open a GitHub issue. As a workaround you can uncomment this line - * to temporarily restore the old behavior where everything must be rebuilt whenever pnpm-lock.json - * is modified. - */ - // "legacyIncrementalBuildDependencyDetection": true + * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead for faster installs. + */ + "usePnpmFrozenLockfileForRushInstall": true, + + /** + * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. + */ + "usePnpmPreferFrozenLockfileForRushUpdate": true, + + /** + * By default, 'rush update' runs as a single operation. + * Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. + * Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs. + */ + // "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate": true, + + /** + * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. + * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not + * cause hash changes. + */ + "omitImportersFromPreventManualShrinkwrapChanges": true, + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + // "noChmodFieldInTarHeaderNormalization": true, + + /** + * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. + * This will not replay warnings from the cached build. + */ + // "buildCacheWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. + * This will not replay warnings from the skipped build. + */ + // "buildSkipWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, perform a clean install after when running `rush install` or `rush update` if the + * `.npmrc` file has changed since the last install. + */ + // "cleanInstallAfterNpmrcChanges": true, + + /** + * If true, print the outputs of shell commands defined in event hooks to the console. + */ + // "printEventHooksOutputToConsole": true, + + /** + * If true, Rush will not allow node_modules in the repo folder or in parent folders. + */ + // "forbidPhantomResolvableNodeModulesFolders": true, + + /** + * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot + * correctly satisfy versioning requirements without installing duplicate copies of a package inside the + * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally + * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" + * feature provides a model for copying the local project folder into node_modules, however copying + * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. + * The "pnpm-sync" tool manages this operation; see its documentation for details. + * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies + * by invoking "pnpm-sync" during the build. + */ + "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, + + /** + * (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 } diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index 5ec41fcbb50..161327d854d 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -2,6 +2,50 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json", "packages": [ + { + "name": "@aws-sdk/client-sso-oidc", + "allowedCategories": [ "tests" ] + }, + { + "name": "@aws-sdk/client-sts", + "allowedCategories": [ "tests" ] + }, + { + "name": "@azure/identity", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@azure/storage-blob", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@babel/core", + "allowedCategories": [ "tests" ] + }, + { + "name": "@eslint/eslintrc", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@jest/core", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@jest/create-cache-key-function", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@jest/reporters", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "@jest/transform", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@jest/types", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "@microsoft/api-documenter", "allowedCategories": [ "libraries", "tests" ] @@ -15,185 +59,441 @@ "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/decorators", + "name": "@microsoft/load-themed-styles", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build", + "name": "@microsoft/rush-lib", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@microsoft/teams-js", + "allowedCategories": [ "tests" ] + }, + { + "name": "@microsoft/tsdoc", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build-mocha", + "name": "@microsoft/tsdoc-config", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build-sass", + "name": "@modelcontextprotocol/sdk", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build-serve", + "name": "@nodelib/fs.scandir", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build-typescript", + "name": "@nodelib/fs.stat", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/gulp-core-build-webpack", + "name": "@pnpm/dependency-path", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/load-themed-styles", - "allowedCategories": [ "libraries", "tests" ] + "name": "@pnpm/dependency-path-lockfile-pre-v10", + "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/node-core-library", - "allowedCategories": [ "libraries", "tests" ] + "name": "@pnpm/link-bins", + "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/node-library-build", - "allowedCategories": [ "libraries", "tests" ] + "name": "@pnpm/lockfile-types", + "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/package-deps-hash", + "name": "@pnpm/lockfile.types", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/rush-lib", + "name": "@pnpm/logger", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/rush-stack", + "name": "@pnpm/types", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@redis/client", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rspack/core", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-2.4", + "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" ] }, { - "name": "@microsoft/rush-stack-compiler-2.7", + "name": "@rushstack/eslint-config", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/eslint-patch", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-2.8", - "allowedCategories": [ "tests" ] + "name": "@rushstack/eslint-plugin", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/eslint-plugin-packlets", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/eslint-plugin-security", + "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/rush-stack-compiler-2.9", + "name": "@rushstack/hashed-folder-copy-plugin", "allowedCategories": [ "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.0", + "name": "@rushstack/heft", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/heft-api-extractor-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.1", + "name": "@rushstack/heft-config-file", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/heft-dev-cert-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.2", + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/heft-jest-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.3", + "name": "@rushstack/heft-json-schema-typings-plugin", "allowedCategories": [ "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.4", + "name": "@rushstack/heft-lint-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.5", + "name": "@rushstack/heft-localization-typings-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/heft-node-rig", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/heft-rspack-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/heft-sass-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.6", + "name": "@rushstack/heft-serverless-stack-plugin", "allowedCategories": [ "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-3.7", + "name": "@rushstack/heft-storybook-plugin", "allowedCategories": [ "tests" ] }, { - "name": "@microsoft/rush-stack-compiler-shared", + "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" ] + }, + { + "name": "@rushstack/heft-webpack4-plugin", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "@rushstack/heft-webpack5-plugin", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/localization-utilities", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/set-webpack-public-path-plugin", + "name": "@rushstack/lockfile-explorer-web", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/lookup-by-path", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/mcp-server", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@microsoft/sp-tslint-rules", + "name": "@rushstack/module-minifier", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "@rushstack/node-core-library", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/npm-check-fork", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/stream-collator", + "name": "@rushstack/operation-graph", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/teams-js", - "allowedCategories": [ "tests" ] + "name": "@rushstack/package-deps-hash", + "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/ts-command-line", + "name": "@rushstack/package-extractor", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@rushstack/real-node-module-path", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/tsdoc", + "name": "@rushstack/rig-package", "allowedCategories": [ "libraries" ] }, { - "name": "@microsoft/web-library-build", + "name": "@rushstack/rush-amazon-s3-build-cache-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@pnpm/link-bins", + "name": "@rushstack/rush-azure-storage-build-cache-plugin", "allowedCategories": [ "libraries" ] }, { - "name": "@pnpm/logger", + "name": "@rushstack/rush-bridge-cache-plugin", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/debug-certificate-manager", + "name": "@rushstack/rush-http-build-cache-plugin", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/eslint-config", + "name": "@rushstack/rush-redis-cobuild-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/rush-resolver-cache-plugin", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-sdk", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/set-webpack-public-path-plugin", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "@rushstack/eslint-plugin", + "name": "@rushstack/stream-collator", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/localization-plugin", - "allowedCategories": [ "tests" ] + "name": "@rushstack/terminal", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@rushstack/tls-sync-vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "@rushstack/tree-pattern", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/ts-command-line", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { "name": "@rushstack/typings-generator", "allowedCategories": [ "libraries" ] }, { - "name": "@typescript-eslint/eslint-plugin", + "name": "@rushstack/vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "@rushstack/webpack-deep-imports-plugin", "allowedCategories": [ "libraries" ] }, { - "name": "@typescript-eslint/experimental-utils", + "name": "@rushstack/webpack-plugin-utilities", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/webpack-preserve-dynamic-require-plugin", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@rushstack/webpack-workspace-resolve-plugin", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/webpack4-localization-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/webpack4-module-minifier-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/webpack5-module-minifier-plugin", + "allowedCategories": [ "tests" ] + }, + { + "name": "@rushstack/worker-pool", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/zipsync", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@serverless-stack/aws-lambda-ric", + "allowedCategories": [ "tests" ] + }, + { + "name": "@serverless-stack/cli", + "allowedCategories": [ "tests" ] + }, + { + "name": "@serverless-stack/resources", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/addon-actions", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/addon-essentials", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/addon-links", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/cli", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/components", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/core-events", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/react", + "allowedCategories": [ "tests" ] + }, + { + "name": "@storybook/theming", + "allowedCategories": [ "tests" ] + }, + { + "name": "@swc/core", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@tsconfig/node14", + "allowedCategories": [ "tests" ] + }, + { + "name": "@typescript-eslint/eslint-plugin", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, { "name": "@typescript-eslint/parser", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "@typescript-eslint/rule-tester", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@typescript-eslint/types", "allowedCategories": [ "libraries" ] }, { "name": "@typescript-eslint/typescript-estree", "allowedCategories": [ "libraries" ] }, + { + "name": "@typescript-eslint/utils", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@vscode/test-electron", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "@vscode/vsce", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, { "name": "@yarnpkg/lockfile", "allowedCategories": [ "libraries" ] }, + { + "name": "ajv", + "allowedCategories": [ "libraries" ] + }, + { + "name": "ajv-draft-04", + "allowedCategories": [ "libraries" ] + }, + { + "name": "ajv-formats", + "allowedCategories": [ "libraries" ] + }, { "name": "api-extractor-lib1-test", "allowedCategories": [ "tests" ] @@ -206,6 +506,14 @@ "name": "api-extractor-lib3-test", "allowedCategories": [ "tests" ] }, + { + "name": "api-extractor-lib4-test", + "allowedCategories": [ "tests" ] + }, + { + "name": "api-extractor-lib5-test", + "allowedCategories": [ "tests" ] + }, { "name": "api-extractor-test-01", "allowedCategories": [ "tests" ] @@ -220,38 +528,50 @@ }, { "name": "autoprefixer", - "allowedCategories": [ "libraries" ] + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "aws-cdk-lib", + "allowedCategories": [ "tests" ] + }, + { + "name": "babel-loader", + "allowedCategories": [ "tests" ] }, { "name": "builtin-modules", "allowedCategories": [ "libraries" ] }, { - "name": "chai", - "allowedCategories": [ "libraries", "tests" ] + "name": "buttono", + "allowedCategories": [ "tests" ] }, { - "name": "chalk", + "name": "chokidar", "allowedCategories": [ "libraries" ] }, { - "name": "chokidar", + "name": "cli-table", "allowedCategories": [ "libraries" ] }, { - "name": "clean-css", + "name": "compression", "allowedCategories": [ "libraries" ] }, { - "name": "cli-table", + "name": "constructs", + "allowedCategories": [ "tests" ] + }, + { + "name": "cors", "allowedCategories": [ "libraries" ] }, { - "name": "colors", + "name": "css-loader", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "deasync", + "name": "css-minimizer-webpack-plugin", "allowedCategories": [ "libraries" ] }, { @@ -259,11 +579,11 @@ "allowedCategories": [ "libraries" ] }, { - "name": "decomment", + "name": "decoupled-local-node-rig", "allowedCategories": [ "libraries" ] }, { - "name": "del", + "name": "diff", "allowedCategories": [ "libraries" ] }, { @@ -271,151 +591,163 @@ "allowedCategories": [ "libraries" ] }, { - "name": "end-of-stream", + "name": "dotenv", "allowedCategories": [ "libraries" ] }, { "name": "eslint", - "allowedCategories": [ "libraries" ] + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { - "name": "eslint-plugin-promise", + "name": "eslint-import-resolver-node", "allowedCategories": [ "libraries" ] }, { - "name": "eslint-plugin-react", + "name": "eslint-plugin-deprecation", "allowedCategories": [ "libraries" ] }, { - "name": "eslint-plugin-security", + "name": "eslint-plugin-header", "allowedCategories": [ "libraries" ] }, { - "name": "eslint-plugin-tsdoc", + "name": "eslint-plugin-headers", "allowedCategories": [ "libraries" ] }, { - "name": "express", + "name": "eslint-plugin-import", "allowedCategories": [ "libraries" ] }, { - "name": "fs-extra", - "allowedCategories": [ "libraries", "tests" ] + "name": "eslint-plugin-jsdoc", + "allowedCategories": [ "libraries" ] }, { - "name": "fsevents", + "name": "eslint-plugin-promise", "allowedCategories": [ "libraries" ] }, { - "name": "git-repo-info", + "name": "eslint-plugin-react", "allowedCategories": [ "libraries" ] }, { - "name": "glob", + "name": "eslint-plugin-react-hooks", "allowedCategories": [ "libraries" ] }, { - "name": "glob-escape", + "name": "eslint-plugin-tsdoc", "allowedCategories": [ "libraries" ] }, { - "name": "globby", + "name": "express", "allowedCategories": [ "libraries" ] }, { - "name": "gulp", - "allowedCategories": [ "libraries", "tests" ] + "name": "fast-glob", + "allowedCategories": [ "libraries" ] }, { - "name": "gulp-cache", - "allowedCategories": [ "libraries" ] + "name": "fastify", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-changed", + "name": "figures", "allowedCategories": [ "libraries" ] }, { - "name": "gulp-clean-css", - "allowedCategories": [ "libraries" ] + "name": "file-loader", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-clip-empty-files", - "allowedCategories": [ "libraries" ] + "name": "fs-extra", + "allowedCategories": [ "libraries", "tests" ] }, { - "name": "gulp-clone", + "name": "git-repo-info", "allowedCategories": [ "libraries" ] }, { - "name": "gulp-connect", + "name": "giturl", "allowedCategories": [ "libraries" ] }, { - "name": "gulp-decomment", - "allowedCategories": [ "libraries" ] + "name": "glob", + "allowedCategories": [ "libraries", "vscode-extensions" ] }, { - "name": "gulp-flatten", + "name": "glob-escape", "allowedCategories": [ "libraries" ] }, { - "name": "gulp-if", - "allowedCategories": [ "libraries" ] + "name": "heft-action-plugin", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-istanbul", - "allowedCategories": [ "libraries" ] + "name": "heft-example-lifecycle-plugin", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-mocha", - "allowedCategories": [ "libraries" ] + "name": "heft-example-plugin-01", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-open", - "allowedCategories": [ "libraries" ] + "name": "heft-example-plugin-02", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-plumber", - "allowedCategories": [ "libraries" ] + "name": "heft-minimal-rig-test", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-postcss", - "allowedCategories": [ "libraries" ] + "name": "heft-parameter-plugin", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-replace", - "allowedCategories": [ "libraries" ] + "name": "heft-storybook-react-tutorial", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-sass", - "allowedCategories": [ "libraries" ] + "name": "heft-storybook-react-tutorial-storybook", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-sourcemaps", - "allowedCategories": [ "libraries" ] + "name": "heft-storybook-react-tutorial-storykit", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-texttojs", - "allowedCategories": [ "libraries" ] + "name": "heft-web-rig-library-tutorial", + "allowedCategories": [ "tests" ] }, { - "name": "gulp-typescript", - "allowedCategories": [ "libraries" ] + "name": "heft-webpack5-plugin", + "allowedCategories": [] }, { "name": "html-webpack-plugin", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "http-proxy", "allowedCategories": [ "tests" ] }, + { + "name": "http2-express-bridge", + "allowedCategories": [ "libraries" ] + }, { "name": "https-proxy-agent", "allowedCategories": [ "libraries" ] }, { - "name": "inquirer", + "name": "ignore", "allowedCategories": [ "libraries" ] }, { - "name": "istanbul-instrumenter-loader", + "name": "import-lazy", + "allowedCategories": [ "libraries" ] + }, + { + "name": "inquirer", "allowedCategories": [ "libraries" ] }, { @@ -423,7 +755,7 @@ "allowedCategories": [ "libraries", "tests" ] }, { - "name": "jest-cli", + "name": "jest-config", "allowedCategories": [ "libraries" ] }, { @@ -431,13 +763,25 @@ "allowedCategories": [ "libraries" ] }, { - "name": "jest-nunit-reporter", + "name": "jest-environment-node", + "allowedCategories": [ "libraries" ] + }, + { + "name": "jest-junit", "allowedCategories": [ "libraries" ] }, { "name": "jest-resolve", "allowedCategories": [ "libraries" ] }, + { + "name": "jest-snapshot", + "allowedCategories": [ "libraries" ] + }, + { + "name": "jest-watch-select-projects", + "allowedCategories": [ "libraries" ] + }, { "name": "jju", "allowedCategories": [ "libraries" ] @@ -447,35 +791,51 @@ "allowedCategories": [ "libraries" ] }, { - "name": "jsdom", + "name": "json-schema-to-typescript", "allowedCategories": [ "libraries" ] }, { - "name": "loader-utils", + "name": "json-stable-stringify-without-jsonify", "allowedCategories": [ "libraries" ] }, { - "name": "lodash", - "allowedCategories": [ "libraries", "tests" ] + "name": "jsonpath-plus", + "allowedCategories": [ "libraries" ] }, { - "name": "lodash.merge", + "name": "jszip", "allowedCategories": [ "libraries" ] }, { - "name": "lolex", + "name": "loader-utils", "allowedCategories": [ "libraries" ] }, + { + "name": "local-eslint-config", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "local-node-rig", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "local-web-rig", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "lodash", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "long", "allowedCategories": [ "tests" ] }, { - "name": "md5", + "name": "memfs", "allowedCategories": [ "libraries" ] }, { - "name": "merge2", + "name": "mini-css-extract-plugin", "allowedCategories": [ "libraries" ] }, { @@ -484,7 +844,7 @@ }, { "name": "mocha", - "allowedCategories": [ "libraries" ] + "allowedCategories": [ "vscode-extensions" ] }, { "name": "node-fetch", @@ -495,11 +855,11 @@ "allowedCategories": [ "libraries" ] }, { - "name": "node-notifier", - "allowedCategories": [ "libraries" ] + "name": "node-sass", + "allowedCategories": [ "libraries", "tests" ] }, { - "name": "node-sass", + "name": "npm-check", "allowedCategories": [ "libraries" ] }, { @@ -507,29 +867,57 @@ "allowedCategories": [ "libraries" ] }, { - "name": "object-assign", + "name": "npm-packlist", "allowedCategories": [ "libraries" ] }, { - "name": "orchestrator", + "name": "object-hash", "allowedCategories": [ "libraries" ] }, { - "name": "postcss", + "name": "open", "allowedCategories": [ "libraries" ] }, + { + "name": "package-extractor-test-02", + "allowedCategories": [ "tests" ] + }, + { + "name": "package-extractor-test-03", + "allowedCategories": [ "tests" ] + }, + { + "name": "package-json", + "allowedCategories": [ "libraries" ] + }, + { + "name": "pnpm-sync-lib", + "allowedCategories": [ "libraries" ] + }, + { + "name": "postcss", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "postcss-loader", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "postcss-modules", "allowedCategories": [ "libraries" ] }, { - "name": "pretty-hrtime", + "name": "prettier", "allowedCategories": [ "libraries" ] }, { "name": "pseudolocale", "allowedCategories": [ "libraries" ] }, + { + "name": "punycode", + "allowedCategories": [ "libraries" ] + }, { "name": "read-package-tree", "allowedCategories": [ "libraries" ] @@ -539,35 +927,83 @@ "allowedCategories": [ "libraries" ] }, { - "name": "semver", + "name": "run-scenarios-helpers", + "allowedCategories": [ "tests" ] + }, + { + "name": "sass", "allowedCategories": [ "libraries", "tests" ] }, { - "name": "sinon", + "name": "sass-embedded", "allowedCategories": [ "libraries" ] }, { - "name": "sinon-chai", + "name": "sass-loader", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "semver", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "serialize-javascript", "allowedCategories": [ "libraries" ] }, { "name": "source-map", "allowedCategories": [ "libraries" ] }, + { + "name": "source-map-loader", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "ssri", + "allowedCategories": [ "libraries" ] + }, { "name": "strict-uri-encode", "allowedCategories": [ "libraries" ] }, + { + "name": "string-argv", + "allowedCategories": [ "libraries" ] + }, + { + "name": "strip-json-comments", + "allowedCategories": [ "libraries" ] + }, + { + "name": "style-loader", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "sudo", "allowedCategories": [ "libraries" ] }, + { + "name": "supports-color", + "allowedCategories": [ "libraries" ] + }, + { + "name": "tapable", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "tar", "allowedCategories": [ "libraries" ] }, { - "name": "through2", + "name": "terser", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "terser-webpack-plugin", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "throat", "allowedCategories": [ "libraries" ] }, { @@ -575,12 +1011,16 @@ "allowedCategories": [ "libraries" ] }, { - "name": "true-case-path", - "allowedCategories": [ "libraries" ] + "name": "tls-sync-vscode-ui-extension", + "allowedCategories": [ "vscode-extensions" ] }, { - "name": "ts-jest", - "allowedCategories": [ "libraries", "tests" ] + "name": "tls-sync-vscode-workspace-extension", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "true-case-path", + "allowedCategories": [ "libraries" ] }, { "name": "ts-loader", @@ -588,31 +1028,35 @@ }, { "name": "tslint", - "allowedCategories": [ "libraries" ] + "allowedCategories": [ "libraries", "tests" ] }, { - "name": "tslint-microsoft-contrib", + "name": "typescript", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "update-notifier", "allowedCategories": [ "libraries" ] }, { - "name": "typescript", - "allowedCategories": [ "libraries", "tests" ] + "name": "url-loader", + "allowedCategories": [ "libraries" ] }, { - "name": "uglify-js", + "name": "uuid", "allowedCategories": [ "libraries" ] }, { - "name": "vinyl", + "name": "watchpack", "allowedCategories": [ "libraries" ] }, { "name": "webpack", - "allowedCategories": [ "libraries", "tests" ] + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { "name": "webpack-bundle-analyzer", - "allowedCategories": [ "tests" ] + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { "name": "webpack-cli", @@ -620,26 +1064,30 @@ }, { "name": "webpack-dev-server", - "allowedCategories": [ "tests" ] + "allowedCategories": [ "libraries", "tests" ] }, { - "name": "wordwrap", + "name": "webpack-merge", "allowedCategories": [ "libraries" ] }, { - "name": "xml", + "name": "webpack-sources", "allowedCategories": [ "libraries" ] }, { - "name": "xmldoc", + "name": "wordwrap", + "allowedCategories": [ "libraries" ] + }, + { + "name": "ws", "allowedCategories": [ "libraries" ] }, { - "name": "yargs", + "name": "xmldoc", "allowedCategories": [ "libraries" ] }, { - "name": "z-schema", + "name": "zod", "allowedCategories": [ "libraries" ] } ] diff --git a/common/config/rush/pnpm-config.json b/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..02f9faa2a00 --- /dev/null +++ b/common/config/rush/pnpm-config.json @@ -0,0 +1,500 @@ +/** + * 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", + + /** + * If true, then `rush install` and `rush update` will use the PNPM workspaces feature + * to perform the install, instead of the old model where Rush generated the symlinks + * for each projects's node_modules folder. + * + * When using workspaces, Rush will generate a `common/temp/pnpm-workspace.yaml` file referencing + * all local projects to install. Rush will also generate a `.pnpmfile.cjs` shim which implements + * Rush-specific features such as preferred versions. The user's `common/config/rush/.pnpmfile.cjs` + * is invoked by the shim. + * + * This option is strongly recommended. The default value is false. + */ + "useWorkspaces": true, + + /** + * This setting determines how PNPM chooses version numbers during `rush update`. + * For example, suppose `lib-x@3.0.0` depends on `"lib-y": "^1.2.3"` whose latest major + * releases are `1.8.9` and `2.3.4`. The resolution mode `lowest-direct` might choose + * `lib-y@1.2.3`, wheres `highest` will choose 1.8.9, and `time-based` will pick the + * highest compatible version at the time when `lib-x@3.0.0` itself was published (ensuring + * that the version could have been tested by the maintainer of "lib-x"). For local workspace + * projects, `time-based` instead works like `lowest-direct`, avoiding upgrades unless + * they are explicitly requested. Although `time-based` is the most robust option, it may be + * slightly slower with registries such as npmjs.com that have not implemented an optimization. + * + * IMPORTANT: Be aware that PNPM 8.0.0 initially defaulted to `lowest-direct` instead of + * `highest`, but PNPM reverted this decision in 8.6.12 because it caused confusion for users. + * Rush version 5.106.0 and newer avoids this confusion by consistently defaulting to + * `highest` when `resolutionMode` is not explicitly set in pnpm-config.json or .npmrc, + * regardless of your PNPM version. + * + * PNPM documentation: https://pnpm.io/npmrc#resolution-mode + * + * Possible values are: `highest`, `time-based`, and `lowest-direct`. + * The default is `highest`. + */ + // "resolutionMode": "time-based", + + /** + * This setting determines whether PNPM will automatically install (non-optional) + * missing peer dependencies instead of reporting an error. Doing so conveniently + * avoids the need to specify peer versions in package.json, but in a large monorepo + * this often creates worse problems. The reason is that peer dependency behavior + * is inherently complicated, and it is easier to troubleshoot consequences of an explicit + * version than an invisible heuristic. The original NPM RFC discussion pointed out + * some other problems with this feature: https://github.com/npm/rfcs/pull/43 + + * IMPORTANT: Without Rush, the setting defaults to true for PNPM 8 and newer; however, + * as of Rush version 5.109.0 the default is always false unless `autoInstallPeers` + * is specified in pnpm-config.json or .npmrc, regardless of your PNPM version. + + * PNPM documentation: https://pnpm.io/npmrc#auto-install-peers + + * The default value is false. + */ + // "autoInstallPeers": false, + + /** + * 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, + * which is an invalid state that can cause build failures or incompatible dependency versions. + * (For historical reasons, JavaScript package managers generally do not treat this invalid + * state as an error.) + * + * PNPM documentation: https://pnpm.io/npmrc#strict-peer-dependencies + * + * The default value is false to avoid legacy compatibility issues. + * It is strongly recommended to set `strictPeerDependencies=true`. + */ + "strictPeerDependencies": true, + + /** + * Environment variables that will be provided to PNPM. + */ + // "environmentVariables": { + // "NODE_OPTIONS": { + // "value": "--max-old-space-size=4096", + // "override": false + // } + // }, + + /** + * Specifies the location of the PNPM store. There are two possible values: + * + * - `local` - use the `pnpm-store` folder in the current configured temp folder: + * `common/temp/pnpm-store` by default. + * - `global` - use PNPM's global store, which has the benefit of being shared + * across multiple repo folders, but the disadvantage of less isolation for builds + * (for example, bugs or incompatibilities when two repos use different releases of PNPM) + * + * In both cases, the store path can be overridden by the environment variable `RUSH_PNPM_STORE_PATH`. + * + * The default value is `local`. + */ + // "pnpmStore": "global", + + /** + * If true, then `rush install` will report an error if manual modifications + * were made to the PNPM shrinkwrap file without running `rush update` afterwards. + * + * This feature protects against accidental inconsistencies that may be introduced + * if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this + * feature is enabled, `rush update` will append a hash to the file as a YAML comment, + * and then `rush update` and `rush install` will validate the hash. Note that this + * does not prohibit manual modifications, but merely requires `rush update` be run + * afterwards, ensuring that PNPM can report or repair any potential inconsistencies. + * + * To temporarily disable this validation when invoking `rush install`, use the + * `--bypass-policy` command-line parameter. + * + * The default value is false. + */ + "preventManualShrinkwrapChanges": true, + + /** + * When a project uses `workspace:` to depend on another Rush project, PNPM normally installs + * it by creating a symlink under `node_modules`. This generally works well, but in certain + * cases such as differing `peerDependencies` versions, symlinking may cause trouble + * such as incorrectly satisfied versions. For such cases, the dependency can be declared + * as "injected", causing PNPM to copy its built output into `node_modules` like a real + * install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/ + * + * When using Rush subspaces, these sorts of versioning problems are much more likely if + * `workspace:` refers to a project from a different subspace. This is because the symlink + * would point to a separate `node_modules` tree installed by a different PNPM lockfile. + * A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`, + * which automatically treats all projects from other subspaces as injected dependencies + * without having to manually configure them. + * + * NOTE: Use carefully -- excessive file copying can slow down the `rush install` and + * `pnpm-sync` operations if too many dependencies become injected. + * + * The default value is false. + */ + // "alwaysInjectDependenciesFromOtherSubspaces": false, + + /** + * Defines the policies to be checked for the `pnpm-lock.yaml` file. + */ + "pnpmLockfilePolicies": { + /** + * This policy will cause "rush update" to report an error if `pnpm-lock.yaml` contains + * any SHA1 integrity hashes. + * + * For each NPM dependency, `pnpm-lock.yaml` normally stores an `integrity` hash. Although + * its main purpose is to detect corrupted or truncated network requests, this hash can also + * serve as a security fingerprint to protect against attacks that would substitute a + * malicious tarball, for example if a misconfigured .npmrc caused a machine to accidentally + * download a matching package name+version from npmjs.com instead of the private NPM registry. + * NPM originally used a SHA1 hash; this was insecure because an attacker can too easily craft + * a tarball with a matching fingerprint. For this reason, NPM later deprecated SHA1 and + * instead adopted a cryptographically strong SHA512 hash. Nonetheless, SHA1 hashes can + * occasionally reappear during "rush update", for example due to missing metadata fallbacks + * (https://github.com/orgs/pnpm/discussions/6194) or an incompletely migrated private registry. + * The `disallowInsecureSha1` policy prevents this, avoiding potential security/compliance alerts. + */ + // "disallowInsecureSha1": { + // /** + // * Enables the "disallowInsecureSha1" policy. The default value is false. + // */ + // "enabled": true, + // + // /** + // * In rare cases, a private NPM registry may continue to serve SHA1 hashes for very old + // * package versions, perhaps due to a caching issue or database migration glitch. To avoid + // * having to disable the "disallowInsecureSha1" policy for the entire monorepo, the problematic + // * package versions can be individually ignored. The "exemptPackageVersions" key is the + // * package name, and the array value lists exact version numbers to be ignored. + // */ + // "exemptPackageVersions": { + // "example1": ["1.0.0"], + // "example2": ["2.0.0", "2.0.1"] + // } + // } + }, + + /** + * The "globalOverrides" setting provides a simple mechanism for overriding version selections + * for all dependencies of all projects in the monorepo workspace. The settings are copied + * into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides + */ + "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", + + // Remove these when decoupled dependencies are bumped + "@rushstack/eslint-config@4.4.1>@typescript-eslint/eslint-plugin": "~8.46.0", + "@rushstack/eslint-config@4.4.1>@typescript-eslint/utils": "~8.46.0", + "@rushstack/eslint-config@4.4.1>@typescript-eslint/parser": "~8.46.0", + "@rushstack/eslint-config@4.4.1>@typescript-eslint/typescript-estree": "~8.46.0", + "@rushstack/eslint-plugin@0.20.0>@typescript-eslint/utils": "~8.46.0", + "@rushstack/heft-node-rig@2.10.1>eslint": "~9.37.0" + }, + + /** + * The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors + * that are reported during installation with `strictPeerDependencies=true`. The settings are copied + * into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * https://pnpm.io/package_json#pnpmpeerdependencyrules + */ + "globalPeerDependencyRules": { + // "ignoreMissing": ["@eslint/*"], + // "allowedVersions": { "react": "17" }, + // "allowAny": ["@babel/*"] + // TODO: Remove once Heft is 1.0.0 + "allowAny": ["@rushstack/heft"], + "allowedVersions": { + "webpack": "^4 || ^5" + } + }, + + /** + * The `globalPackageExtension` setting provides a way to patch arbitrary package.json fields + * for any PNPM dependency of the monorepo. The settings are copied into the `pnpm.packageExtensions` + * field of the `common/temp/package.json` file that is generated by Rush during installation. + * The `globalPackageExtension` setting has similar capabilities as `.pnpmfile.cjs` but without + * the downsides of an executable script (nondeterminism, unreliable caching, performance concerns). + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions + */ + "globalPackageExtensions": { + "@emotion/core": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@emotion/styled": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@emotion/styled-base": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@emotion/theming": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@jest/reporters": { + "dependencies": { + "@types/istanbul-lib-coverage": "2.0.4" + } + }, + + "@serverless-stack/resources": { + "dependencies": { + "esbuild": "*" + } + }, + + "@storybook/addons": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@storybook/api": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@storybook/react": { + "peerDependencies": { + "@types/node": ">=12", + "@types/react": ">=16" + } + }, + + "@storybook/router": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "@storybook/theming": { + "dependencies": { + "@emotion/serialize": "*", + "@emotion/utils": "*" + } + }, + + "@types/compression": { + "peerDependencies": { + "@types/express": "*" + } + }, + + "@types/webpack": { + "dependencies": { + "anymatch": "^3" + } + }, + + // Temporary workaround for https://github.com/typescript-eslint/typescript-eslint/issues/8259 + "@typescript-eslint/rule-tester": { + "dependencies": { + "@types/semver": "*" + } + }, + + "@typescript-eslint/types": { + "peerDependencies": { + "typescript": "*" + } + }, + + "collect-v8-coverage": { + "peerDependencies": { + "@types/node": ">=12" + } + }, + + "emotion-theming": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "http-proxy-middleware": { + "dependencies": { + "@types/express": "*" + } + }, + + "http2-express-bridge": { + "peerDependencies": { + "@types/express": "*" + } + }, + + "query-ast": { + "dependencies": { + "lodash": "~4.17.15" + } + }, + + "react-router": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "react-router-dom": { + "peerDependencies": { + "@types/react": ">=16" + } + }, + + "scss-parser": { + "dependencies": { + "lodash": "~4.17.15" + } + }, + + "webpack-dev-middleware": { + "peerDependencies": { + "@types/webpack": "^4" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + } + } + }, + + "webpack-dev-server": { + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/serve-static": "*", + "anymatch": "^3" + }, + "peerDependencies": { + "@types/webpack": "^4" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + } + } + } + }, + + /** + * The `globalNeverBuiltDependencies` setting suppresses the `preinstall`, `install`, and `postinstall` + * lifecycle events for the specified NPM dependencies. This is useful for scripts with poor practices + * such as downloading large binaries without retries or attempting to invoke OS tools such as + * a C++ compiler. (PNPM's terminology refers to these lifecycle events as "building" a package; + * it has nothing to do with build system operations such as `rush build` or `rushx build`.) + * The settings are copied into the `pnpm.neverBuiltDependencies` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies + */ + "globalNeverBuiltDependencies": [ + // "fsevents" + ], + + /** + * 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" + ], + + /** + * The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package + * versions that the NPM registry reports as being deprecated. This is useful if the + * deprecated package is an indirect dependency of an external package that has not released a fix. + * The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions + * + * If you are working to eliminate a deprecated version, it's better to specify `allowedDeprecatedVersions` + * in the package.json file for individual Rush projects. + */ + "globalAllowedDeprecatedVersions": { + // "request": "*" + }, + + /** + * (THIS FIELD IS MACHINE GENERATED) The "globalPatchedDependencies" field is updated automatically + * by the `rush-pnpm patch-commit` command. It is a dictionary, where the key is an NPM package name + * and exact version, and the value is a relative path to the associated patch file. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies + */ + "globalPatchedDependencies": {}, + + /** + * (USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into + * the `common/temp/package.json` file that is generated by Rush during installation. + * This provides a way to experiment with new PNPM features. These settings will override + * any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`. + * + * USAGE OF THIS SETTING IS NOT SUPPORTED BY THE RUSH MAINTAINERS AND MAY CAUSE RUSH + * TO MALFUNCTION. If you encounter a missing PNPM setting that you believe should + * be supported, please create a GitHub issue or PR. Note that Rush does not aim to + * support every possible PNPM setting, but rather to promote a battle-tested installation + * strategy that is known to provide a good experience for large teams with lots of projects. + */ + "unsupportedPackageJsonSettings": { + // "dependencies": { + // "not-a-good-practice": "*" + // }, + // "scripts": { + // "do-something": "echo Also not a good practice" + // }, + // "pnpm": { "futurePnpmFeature": true } + } +} diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml deleted file mode 100644 index 9d95999c79f..00000000000 --- a/common/config/rush/pnpm-lock.yaml +++ /dev/null @@ -1,13103 +0,0 @@ -dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@microsoft/teams-js': 1.3.0-beta.4 - '@microsoft/tsdoc': 0.12.14 - '@pnpm/link-bins': 5.1.7 - '@rush-temp/api-documenter': 'file:projects/api-documenter.tgz' - '@rush-temp/api-documenter-test': 'file:projects/api-documenter-test.tgz' - '@rush-temp/api-extractor': 'file:projects/api-extractor.tgz' - '@rush-temp/api-extractor-lib1-test': 'file:projects/api-extractor-lib1-test.tgz' - '@rush-temp/api-extractor-lib2-test': 'file:projects/api-extractor-lib2-test.tgz' - '@rush-temp/api-extractor-lib3-test': 'file:projects/api-extractor-lib3-test.tgz' - '@rush-temp/api-extractor-model': 'file:projects/api-extractor-model.tgz' - '@rush-temp/api-extractor-scenarios': 'file:projects/api-extractor-scenarios.tgz' - '@rush-temp/api-extractor-test-01': 'file:projects/api-extractor-test-01.tgz' - '@rush-temp/api-extractor-test-02': 'file:projects/api-extractor-test-02.tgz' - '@rush-temp/api-extractor-test-03': 'file:projects/api-extractor-test-03.tgz' - '@rush-temp/api-extractor-test-04': 'file:projects/api-extractor-test-04.tgz' - '@rush-temp/debug-certificate-manager': 'file:projects/debug-certificate-manager.tgz' - '@rush-temp/doc-plugin-rush-stack': 'file:projects/doc-plugin-rush-stack.tgz' - '@rush-temp/eslint-config': 'file:projects/eslint-config.tgz' - '@rush-temp/eslint-plugin': 'file:projects/eslint-plugin.tgz' - '@rush-temp/generate-api-docs': 'file:projects/generate-api-docs.tgz' - '@rush-temp/gulp-core-build': 'file:projects/gulp-core-build.tgz' - '@rush-temp/gulp-core-build-mocha': 'file:projects/gulp-core-build-mocha.tgz' - '@rush-temp/gulp-core-build-sass': 'file:projects/gulp-core-build-sass.tgz' - '@rush-temp/gulp-core-build-serve': 'file:projects/gulp-core-build-serve.tgz' - '@rush-temp/gulp-core-build-typescript': 'file:projects/gulp-core-build-typescript.tgz' - '@rush-temp/gulp-core-build-webpack': 'file:projects/gulp-core-build-webpack.tgz' - '@rush-temp/load-themed-styles': 'file:projects/load-themed-styles.tgz' - '@rush-temp/loader-load-themed-styles': 'file:projects/loader-load-themed-styles.tgz' - '@rush-temp/loader-raw-script': 'file:projects/loader-raw-script.tgz' - '@rush-temp/localization-plugin': 'file:projects/localization-plugin.tgz' - '@rush-temp/localization-plugin-test-01': 'file:projects/localization-plugin-test-01.tgz' - '@rush-temp/localization-plugin-test-02': 'file:projects/localization-plugin-test-02.tgz' - '@rush-temp/localization-plugin-test-03': 'file:projects/localization-plugin-test-03.tgz' - '@rush-temp/node-core-library': 'file:projects/node-core-library.tgz' - '@rush-temp/node-library-build': 'file:projects/node-library-build.tgz' - '@rush-temp/node-library-build-eslint-test': 'file:projects/node-library-build-eslint-test.tgz' - '@rush-temp/node-library-build-tslint-test': 'file:projects/node-library-build-tslint-test.tgz' - '@rush-temp/package-deps-hash': 'file:projects/package-deps-hash.tgz' - '@rush-temp/repo-toolbox': 'file:projects/repo-toolbox.tgz' - '@rush-temp/rush': 'file:projects/rush.tgz' - '@rush-temp/rush-buildxl': 'file:projects/rush-buildxl.tgz' - '@rush-temp/rush-lib': 'file:projects/rush-lib.tgz' - '@rush-temp/rush-stack-compiler-2.4': 'file:projects/rush-stack-compiler-2.4.tgz' - '@rush-temp/rush-stack-compiler-2.4-library-test': 'file:projects/rush-stack-compiler-2.4-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.7': 'file:projects/rush-stack-compiler-2.7.tgz' - '@rush-temp/rush-stack-compiler-2.7-library-test': 'file:projects/rush-stack-compiler-2.7-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.8': 'file:projects/rush-stack-compiler-2.8.tgz' - '@rush-temp/rush-stack-compiler-2.8-library-test': 'file:projects/rush-stack-compiler-2.8-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.9': 'file:projects/rush-stack-compiler-2.9.tgz' - '@rush-temp/rush-stack-compiler-2.9-library-test': 'file:projects/rush-stack-compiler-2.9-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.0': 'file:projects/rush-stack-compiler-3.0.tgz' - '@rush-temp/rush-stack-compiler-3.0-library-test': 'file:projects/rush-stack-compiler-3.0-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.1': 'file:projects/rush-stack-compiler-3.1.tgz' - '@rush-temp/rush-stack-compiler-3.1-library-test': 'file:projects/rush-stack-compiler-3.1-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.2': 'file:projects/rush-stack-compiler-3.2.tgz' - '@rush-temp/rush-stack-compiler-3.2-library-test': 'file:projects/rush-stack-compiler-3.2-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.3': 'file:projects/rush-stack-compiler-3.3.tgz' - '@rush-temp/rush-stack-compiler-3.3-library-test': 'file:projects/rush-stack-compiler-3.3-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.4': 'file:projects/rush-stack-compiler-3.4.tgz' - '@rush-temp/rush-stack-compiler-3.4-library-test': 'file:projects/rush-stack-compiler-3.4-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.5': 'file:projects/rush-stack-compiler-3.5.tgz' - '@rush-temp/rush-stack-compiler-3.5-library-test': 'file:projects/rush-stack-compiler-3.5-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.6': 'file:projects/rush-stack-compiler-3.6.tgz' - '@rush-temp/rush-stack-compiler-3.6-library-test': 'file:projects/rush-stack-compiler-3.6-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.7': 'file:projects/rush-stack-compiler-3.7.tgz' - '@rush-temp/rush-stack-compiler-3.7-library-test': 'file:projects/rush-stack-compiler-3.7-library-test.tgz' - '@rush-temp/rush-stack-compiler-shared': 'file:projects/rush-stack-compiler-shared.tgz' - '@rush-temp/rushell': 'file:projects/rushell.tgz' - '@rush-temp/set-webpack-public-path-plugin': 'file:projects/set-webpack-public-path-plugin.tgz' - '@rush-temp/stream-collator': 'file:projects/stream-collator.tgz' - '@rush-temp/ts-command-line': 'file:projects/ts-command-line.tgz' - '@rush-temp/typings-generator': 'file:projects/typings-generator.tgz' - '@rush-temp/web-library-build': 'file:projects/web-library-build.tgz' - '@rush-temp/web-library-build-test': 'file:projects/web-library-build-test.tgz' - '@types/argparse': 1.0.33 - '@types/chai': 3.4.34 - '@types/chalk': 0.4.31 - '@types/clean-css': 4.2.1 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 - '@types/express': 4.11.0 - '@types/express-serve-static-core': 4.11.0 - '@types/fs-extra': 5.0.4 - '@types/glob': 7.1.1 - '@types/gulp': 4.0.6 - '@types/gulp-istanbul': 0.9.30 - '@types/gulp-mocha': 0.0.32 - '@types/inquirer': 0.0.43 - '@types/jest': 23.3.11 - '@types/jju': 1.4.1 - '@types/js-yaml': 3.12.1 - '@types/loader-utils': 1.1.3 - '@types/lodash': 4.14.116 - '@types/long': 4.0.0 - '@types/mime': 0.0.29 - '@types/minimatch': 2.0.29 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/node-fetch': 1.6.9 - '@types/node-forge': 0.9.1 - '@types/node-notifier': 0.0.28 - '@types/node-sass': 4.11.0 - '@types/npm-package-arg': 6.1.0 - '@types/orchestrator': 0.0.30 - '@types/read-package-tree': 5.1.0 - '@types/resolve': 0.0.8 - '@types/semver': 5.3.33 - '@types/serve-static': 1.13.1 - '@types/sinon': 1.16.34 - '@types/source-map': 0.5.0 - '@types/strict-uri-encode': 2.0.0 - '@types/tapable': 1.0.4 - '@types/tar': 4.0.0 - '@types/through2': 2.0.32 - '@types/timsort': 0.3.0 - '@types/uglify-js': 2.6.29 - '@types/vinyl': 2.0.3 - '@types/webpack': 4.39.8 - '@types/webpack-dev-server': 3.1.7 - '@types/webpack-env': 1.13.0 - '@types/wordwrap': 1.0.0 - '@types/xmldoc': 1.1.4 - '@types/yargs': 0.0.34 - '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 2.3.3_5b3b7d3a75edb27abc53579646941536 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - '@yarnpkg/lockfile': 1.0.2 - argparse: 1.0.10 - autoprefixer: 9.7.4 - builtin-modules: 3.1.0 - chai: 3.5.0 - chokidar: 3.3.1 - clean-css: 4.2.1 - cli-table: 0.3.1 - colors: 1.2.5 - deasync: 0.1.19 - decache: 4.5.1 - decomment: 0.9.2 - del: 2.2.2 - end-of-stream: 1.1.0 - eslint: 6.5.1 - eslint-plugin-promise: 4.2.1 - eslint-plugin-react: 7.16.0_eslint@6.5.1 - eslint-plugin-security: 1.4.0 - eslint-plugin-tsdoc: 0.2.3 - express: 4.16.4 - fs-extra: 7.0.1 - git-repo-info: 2.1.1 - glob: 7.0.6 - glob-escape: 0.0.2 - globby: 5.0.0 - gulp: 4.0.2 - gulp-connect: 5.5.0 - gulp-flatten: 0.2.0 - gulp-if: 2.0.2 - gulp-istanbul: 0.10.4 - gulp-mocha: 6.0.0 - gulp-open: 3.0.1 - gulp-replace: 0.5.4 - html-webpack-plugin: 3.2.0_webpack@4.31.0 - https-proxy-agent: 2.2.4 - inquirer: 6.2.2 - jest: 23.6.0 - jest-cli: 22.4.4 - jest-environment-jsdom: 22.4.3 - jest-nunit-reporter: 1.3.1 - jest-resolve: 22.4.3 - jju: 1.4.0 - js-yaml: 3.13.1 - jsdom: 11.11.0 - loader-utils: 1.1.0 - lodash: 4.17.15 - lodash.merge: 4.6.2 - long: 4.0.0 - merge2: 1.0.3 - minimatch: 3.0.4 - mocha: 5.2.0 - node-fetch: 2.1.2 - node-forge: 0.7.6 - node-notifier: 5.0.2 - node-sass: 4.12.0 - npm-package-arg: 6.1.1 - object-assign: 4.1.1 - orchestrator: 0.3.8 - postcss: 7.0.5 - postcss-modules: 1.3.2 - pretty-hrtime: 1.0.3 - pseudolocale: 1.1.0 - read-package-tree: 5.1.6 - resolve: 1.8.1 - semver: 5.3.0 - sinon: 1.17.7 - source-map: 0.6.1 - strict-uri-encode: 2.0.0 - sudo: 1.0.3 - tar: 4.4.13 - through2: 2.0.5 - timsort: 0.3.0 - true-case-path: 2.2.1 - ts-jest: 22.4.6_jest@23.6.0 - ts-loader: 6.0.0 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.5.3 - uglify-js: 3.0.28 - vinyl: 2.2.0 - webpack: 4.31.0_webpack@4.31.0 - webpack-bundle-analyzer: 3.6.1 - webpack-cli: 3.3.11_webpack@4.31.0 - webpack-dev-server: 3.9.0_webpack@4.31.0 - wordwrap: 1.0.0 - xml: 1.0.1 - xmldoc: 1.1.2 - yargs: 4.6.0 - z-schema: 3.18.4 -lockfileVersion: 5.1 -packages: - /@babel/code-frame/7.8.3: - dependencies: - '@babel/highlight': 7.8.3 - dev: false - resolution: - integrity: sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - /@babel/highlight/7.8.3: - dependencies: - chalk: 2.4.2 - esutils: 2.0.3 - js-tokens: 4.0.0 - dev: false - resolution: - integrity: sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== - /@microsoft/api-extractor-model/7.7.8: - dependencies: - '@microsoft/tsdoc': 0.12.14 - '@rushstack/node-core-library': 3.19.4 - dev: false - resolution: - integrity: sha512-OWiIC3+Rnv6WzmwuOZkbpHGw9kSKTlzFZBrBwDVEkXp0SP1LsWOy7BALIR1RdTmaM9tRMzKZsjRWz4MWqXJdCQ== - /@microsoft/api-extractor/7.7.9: - dependencies: - '@microsoft/api-extractor-model': 7.7.8 - '@microsoft/tsdoc': 0.12.14 - '@rushstack/node-core-library': 3.19.4 - '@rushstack/ts-command-line': 4.3.11 - colors: 1.2.5 - lodash: 4.17.15 - resolve: 1.8.1 - source-map: 0.6.1 - typescript: 3.7.5 - dev: false - hasBin: true - resolution: - integrity: sha512-sXobUDKsKx2apisLFhk5gxBPBfnCbM31hpmQwqHAbwZ7ak4Sj7I+OcN41hSwbIQksZnk2OSbu+WElEehHiS+xA== - /@microsoft/gulp-core-build-mocha/3.8.5: - dependencies: - '@microsoft/gulp-core-build': 3.15.2 - '@types/node': 10.17.13 - glob: 7.0.6 - gulp: 4.0.2 - gulp-istanbul: 0.10.4 - gulp-mocha: 6.0.0 - dev: false - resolution: - integrity: sha512-d8B83x4pPTnDGjwno8D30Iier4Vn/tNTyV3kL3FxvwWF9ro6cP5nz0LythFCdxnkGivupIQa1ShmtI2WToQ7Cg== - /@microsoft/gulp-core-build-typescript/8.4.5: - dependencies: - '@microsoft/gulp-core-build': 3.15.2 - '@rushstack/node-core-library': 3.19.4 - '@types/node': 10.17.13 - decomment: 0.9.2 - glob: 7.0.6 - glob-escape: 0.0.2 - resolve: 1.8.1 - dev: false - resolution: - integrity: sha512-s3HOpXfX2byc49kTgs9kOqmgvjxkcJcyvUWV5vZkwRJ6nlWVbAu3lL+5rjr35dmNTL1Is8FusR3YXaLdRHZ+Rw== - /@microsoft/gulp-core-build/3.15.2: - dependencies: - '@rushstack/node-core-library': 3.19.4 - '@types/chalk': 0.4.31 - '@types/gulp': 4.0.6 - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - '@types/node-notifier': 0.0.28 - '@types/orchestrator': 0.0.30 - '@types/semver': 5.3.33 - '@types/through2': 2.0.32 - '@types/vinyl': 2.0.3 - '@types/yargs': 0.0.34 - colors: 1.2.5 - del: 2.2.2 - end-of-stream: 1.1.0 - glob: 7.0.6 - glob-escape: 0.0.2 - globby: 5.0.0 - gulp: 4.0.2 - gulp-flatten: 0.2.0 - gulp-if: 2.0.2 - jest: 23.6.0 - jest-cli: 22.4.4 - jest-environment-jsdom: 22.4.3 - jest-nunit-reporter: 1.3.1 - jest-resolve: 22.4.3 - jsdom: 11.11.0 - lodash.merge: 4.6.2 - merge2: 1.0.3 - node-notifier: 5.0.2 - object-assign: 4.1.1 - orchestrator: 0.3.8 - pretty-hrtime: 1.0.3 - semver: 5.3.0 - through2: 2.0.5 - vinyl: 2.2.0 - xml: 1.0.1 - yargs: 4.6.0 - z-schema: 3.18.4 - dev: false - resolution: - integrity: sha512-jvnno3o/RttWXsZyQ25kdu1ubGH52SJ8HtnViRHh6BTd0gT85YF2TwQh1OAig9WgkNB9UVn0T1VbEPJ9yrWCIg== - /@microsoft/node-library-build/6.4.5: - dependencies: - '@microsoft/gulp-core-build': 3.15.2 - '@microsoft/gulp-core-build-mocha': 3.8.5 - '@microsoft/gulp-core-build-typescript': 8.4.5 - '@types/gulp': 4.0.6 - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - resolution: - integrity: sha512-rGNg9HwvL+p7bDbczSvDYcSn4a3x9XmOsD4vPJhIqay+gyylwzZ3R6hbFci5ffytx5yj+DcktbVOXK8/P+xBOw== - /@microsoft/rush-stack-compiler-3.5/0.4.4: - dependencies: - '@microsoft/api-extractor': 7.7.9 - '@rushstack/eslint-config': 0.5.4_eslint@6.5.1+typescript@3.5.3 - '@rushstack/node-core-library': 3.19.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.5.3 - dev: false - hasBin: true - resolution: - integrity: sha512-gGqzxa4yVPXJJXUDddc/iHDSxs9Iv9Bmsh7PC+8KKgxtBOunW0HFojhF/N4XlhHheXYx0gNjRXHjJgom3KVXMA== - /@microsoft/teams-js/1.3.0-beta.4: - dev: false - resolution: - integrity: sha512-AxDfMpiVqh3hsqTxMEYtQoz866WB/sw/Jl0pgTLh6sMHHmIBNMd+E0pVcP9WNk8zTkr9LCphJ5SziU1C8BgZMA== - /@microsoft/tsdoc-config/0.13.2: - dependencies: - '@microsoft/tsdoc': 0.12.18 - ajv: 6.10.2 - jju: 1.4.0 - resolve: 1.12.3 - dev: false - resolution: - integrity: sha512-XSwH2Gs+oPDom9BDFfH8Y+x440m1aKE9dvRmjJyNgakOBevLeEg+ELcrhC93gyf+bH9Ah8vGtC0CmpH9EvWdhQ== - /@microsoft/tsdoc/0.12.14: - dev: false - resolution: - integrity: sha512-518yewjSga1jLdiLrcmpMFlaba5P+50b0TWNFUpC+SL9Yzf0kMi57qw+bMl+rQ08cGqH1vLx4eg9YFUbZXgZ0Q== - /@microsoft/tsdoc/0.12.18: - dev: false - resolution: - integrity: sha512-3rypGnknRaPGlU4HFx2MorC4zmhoGJx773cVbDfcUgc6zI/PFfFaiWmeRR6JiVyKRrLnU/ZH0pc/6jePzy/QyQ== - /@pnpm/error/1.1.0: - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-KK3lZlg79cAMEz4cWKwfUWIU+AegHaPIISnWQsCuGplKzD5Zy2yC0DK2w0Mug265Xj4FD51OLjNynAiOsP4Fww== - /@pnpm/link-bins/5.1.7: - dependencies: - '@pnpm/error': 1.1.0 - '@pnpm/package-bins': 4.0.3 - '@pnpm/read-modules-dir': 2.0.1 - '@pnpm/read-package-json': 3.0.2 - '@pnpm/read-project-manifest': 1.0.1 - '@pnpm/types': 5.0.0 - '@zkochan/cmd-shim': 4.2.1 - is-subdir: 1.1.1 - is-windows: 1.0.2 - make-dir: 3.0.2 - mz: 2.7.0 - normalize-path: 3.0.0 - p-settle: 4.0.0 - ramda: 0.27.0 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-BJNU3KrGS6gyeVNaIA0cwXw3RaAIRQd8GuJjnO7htoqzOnhk0tO+jGbiaO04SpDXDLNEaVLtFOOn8QaWFTc3iw== - /@pnpm/package-bins/4.0.3: - dependencies: - '@pnpm/types': 5.0.0 - graceful-fs: 4.2.3 - is-subdir: 1.1.1 - p-filter: 2.1.0 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-02xQqR+AjGZhWdJxTFgrRfME9bBRtVwZNRvAh5v3SrVxSTaB2Rw9FcoDAaE2SieK9Lmyi78/bHxVfa/ZISX0kw== - /@pnpm/read-modules-dir/2.0.1: - dependencies: - mz: 2.7.0 - dev: false - engines: - node: '>=8.15' - resolution: - integrity: sha512-ki1Hw9YtvnyO+X0NA2l6NV2rD+bnkgNSqZ2lnBa0nbFL/uqylePcEq4C0jkMrE4vS99Z0/ktoVyzVjBPFtKMkA== - /@pnpm/read-package-json/3.0.2: - dependencies: - '@pnpm/types': 5.0.0 - read-package-json: 2.1.1 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-FxUuHEkwkdAjstO0ioqrTnzTyAKwcZQQ0PKImIoehO3SlNNqjV9PLIjwfLdMqdxl4ll9C0qh83RxYWpak/XdqA== - /@pnpm/read-project-manifest/1.0.1: - dependencies: - '@pnpm/error': 1.1.0 - '@pnpm/types': 5.0.0 - '@pnpm/write-project-manifest': 1.0.0 - detect-indent: 6.0.0 - fast-deep-equal: 3.1.1 - graceful-fs: 4.2.1 - is-windows: 1.0.2 - json5: 2.1.1 - parse-json: 5.0.0 - read-yaml-file: 1.1.0 - sort-keys: 4.0.0 - strip-bom: 4.0.0 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-7UYv21bm0pP/1kTnQ39jr8BUhT6M8zVIA6PsRUC/i/dSbV5Bj8sOr9JneQwNnu2ROOAg89r7C5x2IZ8LjgwksA== - /@pnpm/types/5.0.0: - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-atnG7xWrtf22WNXFHQCqK+/LJnCuUNsWxUTg2uhvSq6OlcdviPe67AveqDv/q9KGkpBrEcqg7ChlhJyRjNE9zg== - /@pnpm/write-project-manifest/1.0.0: - dependencies: - '@pnpm/types': 5.0.0 - write-json-file: 4.0.0 - write-json5-file: 2.1.2 - write-yaml-file: 3.0.1 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-XNg0udEoe81rq1jTe3J9itbg8a4GwR/d1I7vSBdYdNU7qmmTilEy+2E+pu/VAL8PMIDRldplV3VkGDoiuN07Vw== - /@rushstack/eslint-config/0.5.4_eslint@6.5.1+typescript@3.5.3: - dependencies: - '@rushstack/eslint-plugin': 0.3.1_eslint@6.5.1 - '@typescript-eslint/eslint-plugin': 2.3.3_5b3b7d3a75edb27abc53579646941536 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 - eslint-plugin-promise: 4.2.1 - eslint-plugin-react: 7.16.0_eslint@6.5.1 - eslint-plugin-security: 1.4.0 - eslint-plugin-tsdoc: 0.2.3 - typescript: 3.5.3 - dev: false - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 - typescript: '>=3.0.0' - resolution: - integrity: sha512-AB7wAXYTuF0z1x9BpFM6Nm0hyk9v94k55w0bZHDJJoptopEOsoEEFf4QVnNRCnYi6JAABzOtvq2vW4g4mAx+Xw== - /@rushstack/eslint-plugin/0.3.1_eslint@6.5.1: - dependencies: - eslint: 6.5.1 - dev: false - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 - resolution: - integrity: sha512-7C1tEdlNTxd8YP852jZnA1RAFEtKTEM112nPQWqyYp5IFHvNEnIaOSvHzutmTItjUCk/S7OygqK6oJyd4xQltQ== - /@rushstack/node-core-library/3.19.4: - dependencies: - '@types/node': 10.17.13 - colors: 1.2.5 - fs-extra: 7.0.1 - jju: 1.4.0 - semver: 5.3.0 - timsort: 0.3.0 - z-schema: 3.18.4 - dev: false - resolution: - integrity: sha512-xH/eXMZycx9t69lHXZifnzuXADOqLp23lOkP6K4avgvdPoZcVIQHeL80/jdzARp5cm+HaHsNxNycqkvH7b7mxQ== - /@rushstack/ts-command-line/4.3.11: - dependencies: - '@types/argparse': 1.0.33 - argparse: 1.0.10 - colors: 1.2.5 - dev: false - resolution: - integrity: sha512-Jzu52EzzHmIuc4dCrK+jLKwFCrrCtVBPCxeMFtHlODXkZ61IlVW+a+rRATkNNlSykv3G0dmedOFxQsVpVgoUpA== - /@types/anymatch/1.3.1: - dev: false - resolution: - integrity: sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== - /@types/argparse/1.0.33: - dev: false - resolution: - integrity: sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== - /@types/body-parser/1.19.0: - dependencies: - '@types/connect': 3.4.33 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== - /@types/chai/3.4.34: - dev: false - resolution: - integrity: sha1-1TNXkoI7sJzd1eOMPSEbcJGDhU0= - /@types/chalk/0.4.31: - dev: false - resolution: - integrity: sha1-ox10JBprHtu5c8822XooloNKUfk= - /@types/clean-css/4.2.1: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ== - /@types/connect-history-api-fallback/1.3.3: - dependencies: - '@types/express-serve-static-core': 4.11.0 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-7SxFCd+FLlxCfwVwbyPxbR4khL9aNikJhrorw8nUIOqeuooc9gifBuDQOJw5kzN7i6i3vLn9G8Wde/4QDihpYw== - /@types/connect/3.4.33: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== - /@types/eslint-visitor-keys/1.0.0: - dev: false - resolution: - integrity: sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - /@types/eslint/6.1.3: - dependencies: - '@types/estree': 0.0.39 - '@types/json-schema': 7.0.4 - dev: false - resolution: - integrity: sha512-llYf1QNZaDweXtA7uY6JczcwHmFwJL9TpK3E6sY0B18l6ulDT6VWNMAdEjYccFHiDfxLPxffd8QmSDV4QUUspA== - /@types/estree/0.0.39: - dev: false - resolution: - integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - /@types/events/3.0.0: - dev: false - resolution: - integrity: sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - /@types/express-serve-static-core/4.11.0: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-hOi1QNb+4G+UjDt6CEJ6MjXHy+XceY7AxIa28U9HgJ80C+3gIbj7h5dJNxOI7PU3DO1LIhGP5Bs47Dbf5l8+MA== - /@types/express/4.11.0: - dependencies: - '@types/body-parser': 1.19.0 - '@types/express-serve-static-core': 4.11.0 - '@types/serve-static': 1.13.1 - dev: false - resolution: - integrity: sha512-N1Wdp3v4KmdO3W/CM7KXrDwM4xcVZjlHF2dAOs7sNrTUX8PY3G4n9NkaHlfjGFEfgFeHmRRjywoBd4VkujDs9w== - /@types/fs-extra/5.0.4: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g== - /@types/glob-stream/6.1.0: - dependencies: - '@types/glob': 7.1.1 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg== - /@types/glob/7.1.1: - dependencies: - '@types/events': 3.0.0 - '@types/minimatch': 2.0.29 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== - /@types/gulp-istanbul/0.9.30: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha1-RAh5rEB1frbwiO+CjRaedfkV7gs= - /@types/gulp-mocha/0.0.32: - dependencies: - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-30OJubm6wl7oVFR7ibaaTl0h52sRQDJwB0h7SXm8KbPG7TN3Bb8QqNI7ObfGFjCoBCk9tr55R4278ckLMFzNcw== - /@types/gulp/4.0.6: - dependencies: - '@types/undertaker': 1.2.2 - '@types/vinyl-fs': 2.4.11 - chokidar: 2.1.8 - dev: false - resolution: - integrity: sha512-0E8/iV/7FKWyQWSmi7jnUvgXXgaw+pfAzEB06Xu+l0iXVJppLbpOye5z7E2klw5akXd+8kPtYuk65YBcZPM4ow== - /@types/http-proxy-middleware/0.19.3: - dependencies: - '@types/connect': 3.4.33 - '@types/http-proxy': 1.17.3 - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA== - /@types/http-proxy/1.17.3: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-wIPqXANye5BbORbuh74exbwNzj+UWCwWyeEFJzUQ7Fq3W2NSAy+7x7nX1fgbEypr2/TdKqpeuxLnXWgzN533/Q== - /@types/inquirer/0.0.43: - dependencies: - '@types/rx': 4.1.1 - '@types/through': 0.0.30 - dev: false - resolution: - integrity: sha512-xgyfKZVMFqE8aIKy1xfFVsX2MxyXUNgjgmbF6dRbR3sL+ZM5K4ka/9L4mmTwX8eTeVYtduyXu0gUVwVJa1HbNw== - /@types/jest/23.3.11: - dev: false - resolution: - integrity: sha512-eroF85PoG87XjCwzxey7yBsQNkIY/TV5myKKSG/022A0FW25afdu/uub6JDMS5eT68zBBt82S+w/MFOTjeLM3Q== - /@types/jju/1.4.1: - dev: false - resolution: - integrity: sha512-LFt+YA7Lv2IZROMwokZKiPNORAV5N3huMs3IKnzlE430HWhWYZ8b+78HiwJXJJP1V2IEjinyJURuRJfGoaFSIA== - /@types/js-yaml/3.12.1: - dev: false - resolution: - integrity: sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA== - /@types/json-schema/7.0.4: - dev: false - resolution: - integrity: sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== - /@types/loader-utils/1.1.3: - dependencies: - '@types/node': 10.17.13 - '@types/webpack': 4.39.8 - dev: false - resolution: - integrity: sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg== - /@types/lodash/4.14.116: - dev: false - resolution: - integrity: sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg== - /@types/long/4.0.0: - dev: false - resolution: - integrity: sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q== - /@types/mime/0.0.29: - dev: false - resolution: - integrity: sha1-+8/TMFc7kS71nu7hRgK/rOYwdUs= - /@types/minimatch/2.0.29: - dev: false - resolution: - integrity: sha1-UALhT3Xi1x5WQoHfBDHIwbSio2o= - /@types/mocha/5.2.5: - dev: false - resolution: - integrity: sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww== - /@types/node-fetch/1.6.9: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-n2r6WLoY7+uuPT7pnEtKJCmPUGyJ+cbyBR8Avnu4+m1nzz7DwBVuyIvvlBzCZ/nrpC7rIgb3D6pNavL7rFEa9g== - /@types/node-forge/0.9.1: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-xNO6BfB4Du8DSChdbqyTf488gQwCEUjkxVQq8CeigoG6N7INc8TTRHJK+88IcrnJ0Q8HWPLK4X8pwC8Rcx+sYg== - /@types/node-notifier/0.0.28: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha1-hro9OqjZGDUswxkdiN4yiyDck8E= - /@types/node-sass/4.11.0: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-uNpVWhwVmbB5luE7b8vxcJwu5np75YkVTBJS0O3ar+hrxqLfyhOKXg9NYBwJ6mMQX/V6/8d6mMZTB7x2r5x9Bw== - /@types/node/10.17.13: - dev: false - resolution: - integrity: sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== - /@types/npm-package-arg/6.1.0: - dev: false - resolution: - integrity: sha512-vbt5fb0y1svMhu++1lwtKmZL76d0uPChFlw7kEzyUmTwfmpHRcFb8i0R8ElT69q/L+QLgK2hgECivIAvaEDwag== - /@types/orchestrator/0.0.30: - dependencies: - '@types/q': 1.5.2 - dev: false - resolution: - integrity: sha1-3N2o1ke1aLex40F4yx8LRKyamOU= - /@types/q/1.5.2: - dev: false - resolution: - integrity: sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== - /@types/read-package-tree/5.1.0: - dev: false - resolution: - integrity: sha512-QEaGDX5COe5Usog79fca6PEycs59075O/W0QcOJjVNv+ZQ26xjqxg8sWu63Lwdt4KAI08gb4Muho1EbEKs3YFw== - /@types/resolve/0.0.8: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== - /@types/rx-core-binding/4.0.4: - dependencies: - '@types/rx-core': 4.0.3 - dev: false - resolution: - integrity: sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ== - /@types/rx-core/4.0.3: - dev: false - resolution: - integrity: sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA= - /@types/rx-lite-aggregates/4.0.3: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg== - /@types/rx-lite-async/4.0.2: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw== - /@types/rx-lite-backpressure/4.0.3: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA== - /@types/rx-lite-coincidence/4.0.3: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ== - /@types/rx-lite-experimental/4.0.1: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0= - /@types/rx-lite-joinpatterns/4.0.1: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha1-9w/jcFGKhDLykVjMkv+1a05K/D4= - /@types/rx-lite-testing/4.0.1: - dependencies: - '@types/rx-lite-virtualtime': 4.0.3 - dev: false - resolution: - integrity: sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek= - /@types/rx-lite-time/4.0.3: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw== - /@types/rx-lite-virtualtime/4.0.3: - dependencies: - '@types/rx-lite': 4.0.6 - dev: false - resolution: - integrity: sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg== - /@types/rx-lite/4.0.6: - dependencies: - '@types/rx-core': 4.0.3 - '@types/rx-core-binding': 4.0.4 - dev: false - resolution: - integrity: sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w== - /@types/rx/4.1.1: - dependencies: - '@types/rx-core': 4.0.3 - '@types/rx-core-binding': 4.0.4 - '@types/rx-lite': 4.0.6 - '@types/rx-lite-aggregates': 4.0.3 - '@types/rx-lite-async': 4.0.2 - '@types/rx-lite-backpressure': 4.0.3 - '@types/rx-lite-coincidence': 4.0.3 - '@types/rx-lite-experimental': 4.0.1 - '@types/rx-lite-joinpatterns': 4.0.1 - '@types/rx-lite-testing': 4.0.1 - '@types/rx-lite-time': 4.0.3 - '@types/rx-lite-virtualtime': 4.0.3 - dev: false - resolution: - integrity: sha1-WY/JSla67ZdfGUV04PVy/Y5iekg= - /@types/semver/5.3.33: - dev: false - resolution: - integrity: sha512-UwrBgjsRS8BSsckIEdrAhIAmdh0MJidtKTvD3S6tpMq6qHLY3uGaNYcRDUjPxpF4hOAOEbMNSXhhfxmNHB1QNQ== - /@types/serve-static/1.13.1: - dependencies: - '@types/express-serve-static-core': 4.11.0 - '@types/mime': 0.0.29 - dev: false - resolution: - integrity: sha512-jDMH+3BQPtvqZVIcsH700Dfi8Q3MIcEx16g/VdxjoqiGR/NntekB10xdBpirMKnPe9z2C5cBmL0vte0YttOr3Q== - /@types/sinon/1.16.34: - dev: false - resolution: - integrity: sha1-qXYf/zPQ97P+YYdbV3d4oldqmgM= - /@types/source-list-map/0.1.2: - dev: false - resolution: - integrity: sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== - /@types/source-map/0.5.0: - dev: false - resolution: - integrity: sha1-3TS72OMv5OdPLj2KwH+KpbRaR6w= - /@types/strict-uri-encode/2.0.0: - dev: false - resolution: - integrity: sha512-R6vDd7CHxcWMzv5wfVhR3qyCRVQoZKwVd6kit0rkozTThRZSXZKEW2Kz3AxfVqq9+UyJAz1g8Q+bJ3CL6NzztQ== - /@types/tapable/1.0.4: - dev: false - resolution: - integrity: sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== - /@types/tar/4.0.0: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-YybbEHNngcHlIWVCYsoj7Oo1JU9JqONuAlt1LlTH/lmL8BMhbzdFUgReY87a05rY1j8mfK47Del+TCkaLAXwLw== - /@types/through/0.0.30: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== - /@types/through2/2.0.32: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha1-RwAkRQ8at2QPGfnr9C09pXTCYSk= - /@types/timsort/0.3.0: - dev: false - resolution: - integrity: sha512-SFjNmiiq4uCs9eXvxbaJMa8pnmlepV8dT2p0nCfdRL1h/UU7ZQFsnCLvtXRHTb3rnyILpQz4Kh8JoTqvDdgxYw== - /@types/uglify-js/2.6.29: - dependencies: - '@types/source-map': 0.5.0 - dev: false - resolution: - integrity: sha512-BdFLCZW0GTl31AbqXSak8ss/MqEZ3DN2MH9rkAyGoTuzK7ifGUlX+u0nfbWeTsa7IPcZhtn8BlpYBXSV+vqGhQ== - /@types/undertaker-registry/1.0.1: - dev: false - resolution: - integrity: sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ== - /@types/undertaker/1.2.2: - dependencies: - '@types/undertaker-registry': 1.0.1 - dev: false - resolution: - integrity: sha512-j4iepCSuY2JGW/hShVtUBagic0klYNFIXP7VweavnYnNC2EjiKxJFeaS9uaJmAT0ty9sQSqTS1aagWMZMV0HyA== - /@types/vinyl-fs/2.4.11: - dependencies: - '@types/glob-stream': 6.1.0 - '@types/node': 10.17.13 - '@types/vinyl': 2.0.3 - dev: false - resolution: - integrity: sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA== - /@types/vinyl/2.0.3: - dependencies: - '@types/node': 10.17.13 - dev: false - resolution: - integrity: sha512-hrT6xg16CWSmndZqOTJ6BGIn2abKyTw0B58bI+7ioUoj3Sma6u8ftZ1DTI2yCaJamOVGLOnQWiPH3a74+EaqTA== - /@types/webpack-dev-server/3.1.7: - dependencies: - '@types/connect-history-api-fallback': 1.3.3 - '@types/express': 4.11.0 - '@types/http-proxy-middleware': 0.19.3 - '@types/serve-static': 1.13.1 - '@types/webpack': 4.39.8 - dev: false - resolution: - integrity: sha512-VIRkDkBDuOkYRXQ1EG/etisQ3odo6pcjSmA1Si4VYANuNhSBsLxfuPGeGERwCx1nDKxK3aaXnicPzi0gUvxUaw== - /@types/webpack-env/1.13.0: - dev: false - resolution: - integrity: sha1-MEQ4FkfhHulzxa8uklMjkw9pHYA= - /@types/webpack-sources/0.1.6: - dependencies: - '@types/node': 10.17.13 - '@types/source-list-map': 0.1.2 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha512-FtAWR7wR5ocJ9+nP137DV81tveD/ZgB1sadnJ/axUGM3BUVfRPx8oQNMtv3JNfTeHx3VP7cXiyfR/jmtEsVHsQ== - /@types/webpack/4.39.8: - dependencies: - '@types/anymatch': 1.3.1 - '@types/node': 10.17.13 - '@types/tapable': 1.0.4 - '@types/uglify-js': 2.6.29 - '@types/webpack-sources': 0.1.6 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha512-lkJvwNJQUPW2SbVwAZW9s9whJp02nzLf2yTNwMULa4LloED9MYS1aNnGeoBCifpAI1pEBkTpLhuyRmBnLEOZAA== - /@types/wordwrap/1.0.0: - dev: false - resolution: - integrity: sha512-XknqsI3sxtVduA/zP475wjMPH/qaZB6teY+AGvZkNUPhwxAac/QuKt6fpJCY9iO6ZpDhBmu9iOHgLXK78hoEDA== - /@types/xmldoc/1.1.4: - dev: false - resolution: - integrity: sha512-a/ONNCf9itbmzEz1ohx0Fv5TLJzXIPQTapxFu+DlYlDtn9UcAa1OhnrOOMwbU8125hFjrkJKL3qllD7vO5Bivw== - /@types/yargs/0.0.34: - dev: false - resolution: - integrity: sha1-FWBCn8VQxDvEGnt9PfoK+8yRSjU= - /@types/z-schema/3.16.31: - dev: false - resolution: - integrity: sha1-LrHQCl5Ow/pYx2r94S4YK2bcXBw= - /@typescript-eslint/eslint-plugin/2.3.3_5b3b7d3a75edb27abc53579646941536: - dependencies: - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - eslint: 6.5.1 - eslint-utils: 1.4.3 - functional-red-black-tree: 1.0.1 - regexpp: 2.0.1 - tsutils: 3.17.1_typescript@3.5.3 - typescript: 3.5.3 - dev: false - engines: - node: ^8.10.0 || ^10.13.0 || >=11.10.1 - peerDependencies: - '@typescript-eslint/parser': ^2.0.0 - eslint: ^5.0.0 || ^6.0.0 - typescript: '*' - resolution: - integrity: sha512-12cCbwu5PbQudkq2xCIS/QhB7hCMrsNPXK+vJtqy/zFqtzVkPRGy12O5Yy0gUK086f3VHV/P4a4R4CjMW853pA== - /@typescript-eslint/experimental-utils/2.3.3_eslint@6.5.1: - dependencies: - '@types/json-schema': 7.0.4 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 - eslint-scope: 5.0.0 - dev: false - engines: - node: ^8.10.0 || ^10.13.0 || >=11.10.1 - peerDependencies: - eslint: '*' - resolution: - integrity: sha512-MQ4jKPMTU1ty4TigJCRKFPye2qyQdH8jzIIkceaHgecKFmkNS1hXPqKiZ+mOehkz6+HcN5Nuvwm+frmWZR9tdg== - /@typescript-eslint/parser/2.3.3_eslint@6.5.1: - dependencies: - '@types/eslint-visitor-keys': 1.0.0 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 - eslint-visitor-keys: 1.1.0 - dev: false - engines: - node: ^8.10.0 || ^10.13.0 || >=11.10.1 - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 - resolution: - integrity: sha512-+cV53HuYFeeyrNW8x/rgPmbVrzzp/rpRmwbJnNtwn4K8mroL1BdjxwQh7X9cUHp9rm4BBiEWmD3cSBjKG7d5mw== - /@typescript-eslint/typescript-estree/2.3.3: - dependencies: - glob: 7.1.6 - is-glob: 4.0.1 - lodash.unescape: 4.0.1 - semver: 6.3.0 - dev: false - engines: - node: ^8.10.0 || ^10.13.0 || >=11.10.1 - resolution: - integrity: sha512-GkACs12Xp8d/STunNv/iSMYJFQrkrax9vuPZySlgSzoJJtw1cp6tbEw4qsLskQv6vloLrkFJHcTJ0a/yCB5cIA== - /@webassemblyjs/ast/1.8.5: - dependencies: - '@webassemblyjs/helper-module-context': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/wast-parser': 1.8.5 - dev: false - resolution: - integrity: sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== - /@webassemblyjs/floating-point-hex-parser/1.8.5: - dev: false - resolution: - integrity: sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== - /@webassemblyjs/helper-api-error/1.8.5: - dev: false - resolution: - integrity: sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== - /@webassemblyjs/helper-buffer/1.8.5: - dev: false - resolution: - integrity: sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== - /@webassemblyjs/helper-code-frame/1.8.5: - dependencies: - '@webassemblyjs/wast-printer': 1.8.5 - dev: false - resolution: - integrity: sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== - /@webassemblyjs/helper-fsm/1.8.5: - dev: false - resolution: - integrity: sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== - /@webassemblyjs/helper-module-context/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - mamacro: 0.0.3 - dev: false - resolution: - integrity: sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== - /@webassemblyjs/helper-wasm-bytecode/1.8.5: - dev: false - resolution: - integrity: sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== - /@webassemblyjs/helper-wasm-section/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - dev: false - resolution: - integrity: sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== - /@webassemblyjs/ieee754/1.8.5: - dependencies: - '@xtuc/ieee754': 1.2.0 - dev: false - resolution: - integrity: sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== - /@webassemblyjs/leb128/1.8.5: - dependencies: - '@xtuc/long': 4.2.2 - dev: false - resolution: - integrity: sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== - /@webassemblyjs/utf8/1.8.5: - dev: false - resolution: - integrity: sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== - /@webassemblyjs/wasm-edit/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/helper-wasm-section': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - '@webassemblyjs/wasm-opt': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - '@webassemblyjs/wast-printer': 1.8.5 - dev: false - resolution: - integrity: sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== - /@webassemblyjs/wasm-gen/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/ieee754': 1.8.5 - '@webassemblyjs/leb128': 1.8.5 - '@webassemblyjs/utf8': 1.8.5 - dev: false - resolution: - integrity: sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== - /@webassemblyjs/wasm-opt/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-buffer': 1.8.5 - '@webassemblyjs/wasm-gen': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - dev: false - resolution: - integrity: sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== - /@webassemblyjs/wasm-parser/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-api-error': 1.8.5 - '@webassemblyjs/helper-wasm-bytecode': 1.8.5 - '@webassemblyjs/ieee754': 1.8.5 - '@webassemblyjs/leb128': 1.8.5 - '@webassemblyjs/utf8': 1.8.5 - dev: false - resolution: - integrity: sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== - /@webassemblyjs/wast-parser/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/floating-point-hex-parser': 1.8.5 - '@webassemblyjs/helper-api-error': 1.8.5 - '@webassemblyjs/helper-code-frame': 1.8.5 - '@webassemblyjs/helper-fsm': 1.8.5 - '@xtuc/long': 4.2.2 - dev: false - resolution: - integrity: sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== - /@webassemblyjs/wast-printer/1.8.5: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/wast-parser': 1.8.5 - '@xtuc/long': 4.2.2 - dev: false - resolution: - integrity: sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== - /@xtuc/ieee754/1.2.0: - dev: false - resolution: - integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - /@xtuc/long/4.2.2: - dev: false - resolution: - integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - /@yarnpkg/lockfile/1.0.2: - dev: false - resolution: - integrity: sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw== - /@zkochan/cmd-shim/4.2.1: - dependencies: - is-windows: 1.0.2 - make-dir: 3.0.2 - dev: false - engines: - node: '>=8.15' - resolution: - integrity: sha512-nlAQt6YjG1VwmxhNwvXOcgxPFJR6yF6u9kbAU2uWjfeDDkBavzUC6F210+Xfb44Ui7eY3vFK6CvSr3MNKedjOw== - /abab/1.0.4: - dev: false - resolution: - integrity: sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4= - /abab/2.0.3: - dev: false - resolution: - integrity: sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== - /abbrev/1.0.9: - dev: false - resolution: - integrity: sha1-kbR5JYinc4wl813W9jdSovh3YTU= - /accepts/1.3.7: - dependencies: - mime-types: 2.1.26 - negotiator: 0.6.2 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - /acorn-dynamic-import/4.0.0_acorn@6.4.1: - dependencies: - acorn: 6.4.1 - dev: false - peerDependencies: - acorn: ^6.0.0 - resolution: - integrity: sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== - /acorn-globals/4.3.4: - dependencies: - acorn: 6.4.1 - acorn-walk: 6.2.0 - dev: false - resolution: - integrity: sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - /acorn-jsx/5.2.0_acorn@7.1.1: - dependencies: - acorn: 7.1.1 - dev: false - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 - resolution: - integrity: sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - /acorn-walk/6.2.0: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - /acorn-walk/7.1.1: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== - /acorn/5.7.4: - dev: false - engines: - node: '>=0.4.0' - hasBin: true - resolution: - integrity: sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - /acorn/6.4.1: - dev: false - engines: - node: '>=0.4.0' - hasBin: true - resolution: - integrity: sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== - /acorn/7.1.1: - dev: false - engines: - node: '>=0.4.0' - hasBin: true - resolution: - integrity: sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== - /agent-base/4.3.0: - dependencies: - es6-promisify: 5.0.0 - dev: false - engines: - node: '>= 4.0.0' - resolution: - integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - /ajv-errors/1.0.1_ajv@6.12.0: - dependencies: - ajv: 6.12.0 - dev: false - peerDependencies: - ajv: '>=5.0.0' - resolution: - integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - /ajv-keywords/3.4.1_ajv@6.12.0: - dependencies: - ajv: 6.12.0 - dev: false - peerDependencies: - ajv: ^6.9.1 - resolution: - integrity: sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - /ajv/6.10.2: - dependencies: - fast-deep-equal: 2.0.1 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.2.2 - dev: false - resolution: - integrity: sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - /ajv/6.12.0: - dependencies: - fast-deep-equal: 3.1.1 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.2.2 - dev: false - resolution: - integrity: sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== - /amdefine/1.0.1: - dev: false - engines: - node: '>=0.4.2' - resolution: - integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - /ansi-colors/1.1.0: - dependencies: - ansi-wrap: 0.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== - /ansi-colors/3.2.4: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - /ansi-escapes/3.2.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - /ansi-gray/0.1.1: - dependencies: - ansi-wrap: 0.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-KWLPVOyXksSFEKPetSRDaGHvclE= - /ansi-html/0.0.7: - dev: false - engines: - '0': node >= 0.8.0 - hasBin: true - resolution: - integrity: sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - /ansi-regex/2.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - /ansi-regex/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - /ansi-regex/4.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - /ansi-styles/2.2.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - /ansi-styles/3.2.1: - dependencies: - color-convert: 1.9.3 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - /ansi-wrap/0.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-qCJQ3bABXponyoLoLqYDu/pF768= - /any-promise/1.3.0: - dev: false - resolution: - integrity: sha1-q8av7tzqUugJzcA3au0845Y10X8= - /anymatch/1.3.2: - dependencies: - micromatch: 2.3.11 - normalize-path: 2.1.1 - dev: false - resolution: - integrity: sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== - /anymatch/2.0.0: - dependencies: - micromatch: 3.1.10 - normalize-path: 2.1.1 - dev: false - resolution: - integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - /anymatch/3.1.1: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.2.1 - dev: false - engines: - node: '>= 8' - resolution: - integrity: sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== - /append-buffer/1.0.2: - dependencies: - buffer-equal: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE= - /append-transform/0.4.0: - dependencies: - default-require-extensions: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-126/jKlNJ24keja61EpLdKthGZE= - /aproba/1.2.0: - dev: false - resolution: - integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - /archy/1.0.0: - dev: false - resolution: - integrity: sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - /are-we-there-yet/1.1.5: - dependencies: - delegates: 1.0.0 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - /argparse/1.0.10: - dependencies: - sprintf-js: 1.0.3 - dev: false - resolution: - integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - /arr-diff/2.0.0: - dependencies: - arr-flatten: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - /arr-diff/4.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - /arr-filter/1.1.2: - dependencies: - make-iterator: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4= - /arr-flatten/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - /arr-map/2.0.2: - dependencies: - make-iterator: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Onc0X/wc814qkYJWAfnljy4kysQ= - /arr-union/3.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - /array-differ/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= - /array-each/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-p5SvDAWrF1KEbudTofIRoFugxE8= - /array-equal/1.0.0: - dev: false - resolution: - integrity: sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - /array-find-index/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - /array-flatten/1.1.1: - dev: false - resolution: - integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - /array-flatten/2.1.2: - dev: false - resolution: - integrity: sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - /array-includes/3.1.1: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - is-string: 1.0.5 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== - /array-initial/1.1.0: - dependencies: - array-slice: 1.1.0 - is-number: 4.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-L6dLJnOTccOUe9enrcc74zSz15U= - /array-last/1.3.0: - dependencies: - is-number: 4.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== - /array-slice/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== - /array-sort/1.0.0: - dependencies: - default-compare: 1.0.0 - get-value: 2.0.6 - kind-of: 5.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== - /array-union/1.0.2: - dependencies: - array-uniq: 1.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - /array-uniq/1.0.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - /array-unique/0.2.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - /array-unique/0.3.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - /arrify/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - /asap/2.0.6: - dev: false - resolution: - integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - /asn1.js/4.10.1: - dependencies: - bn.js: 4.11.8 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: false - resolution: - integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - /asn1/0.2.4: - dependencies: - safer-buffer: 2.1.2 - dev: false - resolution: - integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - /assert-plus/1.0.0: - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - /assert/1.5.0: - dependencies: - object-assign: 4.1.1 - util: 0.10.3 - dev: false - resolution: - integrity: sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - /assertion-error/1.1.0: - dev: false - resolution: - integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - /assign-symbols/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - /astral-regex/1.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - /async-done/1.3.2: - dependencies: - end-of-stream: 1.1.0 - once: 1.4.0 - process-nextick-args: 2.0.1 - stream-exhaust: 1.0.2 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw== - /async-each/1.0.3: - dev: false - resolution: - integrity: sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - /async-foreach/0.1.3: - dev: false - resolution: - integrity: sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= - /async-limiter/1.0.1: - dev: false - resolution: - integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - /async-settle/1.0.0: - dependencies: - async-done: 1.3.2 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs= - /async/1.5.2: - dev: false - resolution: - integrity: sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - /async/2.6.3: - dependencies: - lodash: 4.17.15 - dev: false - resolution: - integrity: sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - /asynckit/0.4.0: - dev: false - resolution: - integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k= - /atob/2.1.2: - dev: false - engines: - node: '>= 4.5.0' - hasBin: true - resolution: - integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - /autoprefixer/9.7.4: - dependencies: - browserslist: 4.9.1 - caniuse-lite: 1.0.30001035 - chalk: 2.4.2 - normalize-range: 0.1.2 - num2fraction: 1.2.2 - postcss: 7.0.27 - postcss-value-parser: 4.0.3 - dev: false - engines: - node: '>=6.0.0' - hasBin: true - resolution: - integrity: sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== - /aws-sign2/0.7.0: - dev: false - resolution: - integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - /aws4/1.9.1: - dev: false - resolution: - integrity: sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== - /babel-code-frame/6.26.0: - dependencies: - chalk: 1.1.3 - esutils: 2.0.3 - js-tokens: 3.0.2 - dev: false - resolution: - integrity: sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - /babel-core/6.26.3: - dependencies: - babel-code-frame: 6.26.0 - babel-generator: 6.26.1 - babel-helpers: 6.24.1 - babel-messages: 6.23.0 - babel-register: 6.26.0 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - convert-source-map: 1.7.0 - debug: 2.6.9 - json5: 0.5.1 - lodash: 4.17.15 - minimatch: 3.0.4 - path-is-absolute: 1.0.1 - private: 0.1.8 - slash: 1.0.0 - source-map: 0.5.7 - dev: false - resolution: - integrity: sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== - /babel-generator/6.26.1: - dependencies: - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - detect-indent: 4.0.0 - jsesc: 1.3.0 - lodash: 4.17.15 - source-map: 0.5.7 - trim-right: 1.0.1 - dev: false - resolution: - integrity: sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - /babel-helpers/6.24.1: - dependencies: - babel-runtime: 6.26.0 - babel-template: 6.26.0 - dev: false - resolution: - integrity: sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= - /babel-jest/22.4.4_babel-core@6.26.3: - dependencies: - babel-core: 6.26.3 - babel-plugin-istanbul: 4.1.6 - babel-preset-jest: 22.4.4 - dev: false - peerDependencies: - babel-core: ^6.0.0 || ^7.0.0-0 - resolution: - integrity: sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ== - /babel-jest/23.6.0_babel-core@6.26.3: - dependencies: - babel-core: 6.26.3 - babel-plugin-istanbul: 4.1.6 - babel-preset-jest: 23.2.0 - dev: false - peerDependencies: - babel-core: ^6.0.0 || ^7.0.0-0 - resolution: - integrity: sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew== - /babel-messages/6.23.0: - dependencies: - babel-runtime: 6.26.0 - dev: false - resolution: - integrity: sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= - /babel-plugin-istanbul/4.1.6: - dependencies: - babel-plugin-syntax-object-rest-spread: 6.13.0 - find-up: 2.1.0 - istanbul-lib-instrument: 1.10.2 - test-exclude: 4.2.3 - dev: false - resolution: - integrity: sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ== - /babel-plugin-jest-hoist/22.4.4: - dev: false - resolution: - integrity: sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ== - /babel-plugin-jest-hoist/23.2.0: - dev: false - resolution: - integrity: sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc= - /babel-plugin-syntax-object-rest-spread/6.13.0: - dev: false - resolution: - integrity: sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= - /babel-plugin-transform-es2015-modules-commonjs/6.26.2: - dependencies: - babel-plugin-transform-strict-mode: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-types: 6.26.0 - dev: false - resolution: - integrity: sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== - /babel-plugin-transform-strict-mode/6.24.1: - dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 - dev: false - resolution: - integrity: sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= - /babel-preset-jest/22.4.4: - dependencies: - babel-plugin-jest-hoist: 22.4.4 - babel-plugin-syntax-object-rest-spread: 6.13.0 - dev: false - resolution: - integrity: sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA== - /babel-preset-jest/23.2.0: - dependencies: - babel-plugin-jest-hoist: 23.2.0 - babel-plugin-syntax-object-rest-spread: 6.13.0 - dev: false - resolution: - integrity: sha1-jsegOhOPABoaj7HoETZSvxpV2kY= - /babel-register/6.26.0: - dependencies: - babel-core: 6.26.3 - babel-runtime: 6.26.0 - core-js: 2.6.11 - home-or-tmp: 2.0.0 - lodash: 4.17.15 - mkdirp: 0.5.3 - source-map-support: 0.4.18 - dev: false - resolution: - integrity: sha1-btAhFz4vy0htestFxgCahW9kcHE= - /babel-runtime/6.26.0: - dependencies: - core-js: 2.6.11 - regenerator-runtime: 0.11.1 - dev: false - resolution: - integrity: sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - /babel-template/6.26.0: - dependencies: - babel-runtime: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - lodash: 4.17.15 - dev: false - resolution: - integrity: sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= - /babel-traverse/6.26.0: - dependencies: - babel-code-frame: 6.26.0 - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - debug: 2.6.9 - globals: 9.18.0 - invariant: 2.2.4 - lodash: 4.17.15 - dev: false - resolution: - integrity: sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= - /babel-types/6.26.0: - dependencies: - babel-runtime: 6.26.0 - esutils: 2.0.3 - lodash: 4.17.15 - to-fast-properties: 1.0.3 - dev: false - resolution: - integrity: sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - /babylon/6.18.0: - dev: false - hasBin: true - resolution: - integrity: sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - /bach/1.2.0: - dependencies: - arr-filter: 1.1.2 - arr-flatten: 1.1.0 - arr-map: 2.0.2 - array-each: 1.0.1 - array-initial: 1.1.0 - array-last: 1.3.0 - async-done: 1.3.2 - async-settle: 1.0.0 - now-and-later: 2.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA= - /balanced-match/1.0.0: - dev: false - resolution: - integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - /base/0.11.2: - dependencies: - cache-base: 1.0.1 - class-utils: 0.3.6 - component-emitter: 1.3.0 - define-property: 1.0.0 - isobject: 3.0.1 - mixin-deep: 1.3.2 - pascalcase: 0.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - /base64-js/1.3.1: - dev: false - resolution: - integrity: sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - /batch/0.6.1: - dev: false - resolution: - integrity: sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= - /bcrypt-pbkdf/1.0.2: - dependencies: - tweetnacl: 0.14.5 - dev: false - resolution: - integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - /beeper/1.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= - /better-path-resolve/1.0.0: - dependencies: - is-windows: 1.0.2 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g== - /bfj/6.1.2: - dependencies: - bluebird: 3.7.2 - check-types: 8.0.3 - hoopy: 0.1.4 - tryer: 1.0.1 - dev: false - engines: - node: '>= 6.0.0' - resolution: - integrity: sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw== - /big.js/3.2.0: - dev: false - resolution: - integrity: sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - /big.js/5.2.2: - dev: false - resolution: - integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - /binary-extensions/1.13.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - /binary-extensions/2.0.0: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== - /binaryextensions/1.0.1: - dev: false - resolution: - integrity: sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U= - /bindings/1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - dev: false - resolution: - integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - /block-stream/0.0.9: - dependencies: - inherits: 2.0.4 - dev: false - engines: - node: 0.4 || >=0.5.8 - resolution: - integrity: sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - /bluebird/3.7.2: - dev: false - resolution: - integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - /bn.js/4.11.8: - dev: false - resolution: - integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - /body-parser/1.14.2: - dependencies: - bytes: 2.2.0 - content-type: 1.0.4 - debug: 2.2.0 - depd: 1.1.2 - http-errors: 1.3.1 - iconv-lite: 0.4.13 - on-finished: 2.3.0 - qs: 5.2.0 - raw-body: 2.1.7 - type-is: 1.6.18 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk= - /body-parser/1.18.3: - dependencies: - bytes: 3.0.0 - content-type: 1.0.4 - debug: 2.6.9 - depd: 1.1.2 - http-errors: 1.6.3 - iconv-lite: 0.4.23 - on-finished: 2.3.0 - qs: 6.5.2 - raw-body: 2.3.3 - type-is: 1.6.18 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= - /body-parser/1.19.0: - dependencies: - bytes: 3.1.0 - content-type: 1.0.4 - debug: 2.6.9 - depd: 1.1.2 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - on-finished: 2.3.0 - qs: 6.7.0 - raw-body: 2.4.0 - type-is: 1.6.18 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - /bonjour/3.5.0: - dependencies: - array-flatten: 2.1.2 - deep-equal: 1.1.1 - dns-equal: 1.0.0 - dns-txt: 2.0.2 - multicast-dns: 6.2.3 - multicast-dns-service-types: 1.1.0 - dev: false - resolution: - integrity: sha1-jokKGD2O6aI5OzhExpGkK897yfU= - /boolbase/1.0.0: - dev: false - resolution: - integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24= - /brace-expansion/1.1.11: - dependencies: - balanced-match: 1.0.0 - concat-map: 0.0.1 - dev: false - resolution: - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - /braces/1.8.5: - dependencies: - expand-range: 1.8.2 - preserve: 0.2.0 - repeat-element: 1.1.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - /braces/2.3.2: - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.3 - snapdragon: 0.8.2 - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - /braces/3.0.2: - dependencies: - fill-range: 7.0.1 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - /brorand/1.1.0: - dev: false - resolution: - integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - /browser-process-hrtime/1.0.0: - dev: false - resolution: - integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - /browser-resolve/1.11.3: - dependencies: - resolve: 1.1.7 - dev: false - resolution: - integrity: sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - /browser-stdout/1.3.1: - dev: false - resolution: - integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - /browserify-aes/1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.4 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - /browserify-cipher/1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - dev: false - resolution: - integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - /browserify-des/1.0.2: - dependencies: - cipher-base: 1.0.4 - des.js: 1.0.1 - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - /browserify-rsa/4.0.1: - dependencies: - bn.js: 4.11.8 - randombytes: 2.1.0 - dev: false - resolution: - integrity: sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - /browserify-sign/4.0.4: - dependencies: - bn.js: 4.11.8 - browserify-rsa: 4.0.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.5.2 - inherits: 2.0.4 - parse-asn1: 5.1.5 - dev: false - resolution: - integrity: sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= - /browserify-zlib/0.2.0: - dependencies: - pako: 1.0.11 - dev: false - resolution: - integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - /browserslist/4.9.1: - dependencies: - caniuse-lite: 1.0.30001035 - electron-to-chromium: 1.3.377 - node-releases: 1.1.52 - dev: false - hasBin: true - resolution: - integrity: sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw== - /bser/2.1.1: - dependencies: - node-int64: 0.4.0 - dev: false - resolution: - integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - /buffer-equal/1.0.0: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha1-WWFrSYME1Var1GaWayLu2j7KX74= - /buffer-from/1.1.1: - dev: false - resolution: - integrity: sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - /buffer-indexof/1.1.1: - dev: false - resolution: - integrity: sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== - /buffer-xor/1.0.3: - dev: false - resolution: - integrity: sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - /buffer/4.9.2: - dependencies: - base64-js: 1.3.1 - ieee754: 1.1.13 - isarray: 1.0.0 - dev: false - resolution: - integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - /builtin-modules/1.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - /builtin-modules/3.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== - /builtin-status-codes/3.0.0: - dev: false - resolution: - integrity: sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - /builtins/1.0.3: - dev: false - resolution: - integrity: sha1-y5T662HIaWRR2zZTThQi+U8K7og= - /bytes/2.2.0: - dev: false - resolution: - integrity: sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg= - /bytes/2.4.0: - dev: false - resolution: - integrity: sha1-fZcZb51br39pNeJZhVSe3SpsIzk= - /bytes/3.0.0: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - /bytes/3.1.0: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - /cacache/12.0.3: - dependencies: - bluebird: 3.7.2 - chownr: 1.1.4 - figgy-pudding: 3.5.1 - glob: 7.1.6 - graceful-fs: 4.2.3 - infer-owner: 1.0.4 - lru-cache: 5.1.1 - mississippi: 3.0.0 - mkdirp: 0.5.3 - move-concurrently: 1.0.1 - promise-inflight: 1.0.1 - rimraf: 2.7.1 - ssri: 6.0.1 - unique-filename: 1.1.1 - y18n: 4.0.0 - dev: false - resolution: - integrity: sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== - /cache-base/1.0.1: - dependencies: - collection-visit: 1.0.0 - component-emitter: 1.3.0 - get-value: 2.0.6 - has-value: 1.0.0 - isobject: 3.0.1 - set-value: 2.0.1 - to-object-path: 0.3.0 - union-value: 1.0.1 - unset-value: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - /callsite/1.0.0: - dev: false - resolution: - integrity: sha1-KAOY5dZkvXQDi28JBRU+borxvCA= - /callsites/2.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - /callsites/3.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - /camel-case/3.0.0: - dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: false - resolution: - integrity: sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= - /camelcase-keys/2.1.0: - dependencies: - camelcase: 2.1.1 - map-obj: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - /camelcase/2.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - /camelcase/3.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - /camelcase/4.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - /camelcase/5.3.1: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - /caniuse-lite/1.0.30001035: - dev: false - resolution: - integrity: sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ== - /capture-exit/1.2.0: - dependencies: - rsvp: 3.6.2 - dev: false - resolution: - integrity: sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= - /caseless/0.12.0: - dev: false - resolution: - integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - /chai/3.5.0: - dependencies: - assertion-error: 1.1.0 - deep-eql: 0.1.3 - type-detect: 1.0.0 - dev: false - engines: - node: '>= 0.4.0' - resolution: - integrity: sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc= - /chalk/1.1.3: - dependencies: - ansi-styles: 2.2.1 - escape-string-regexp: 1.0.5 - has-ansi: 2.0.0 - strip-ansi: 3.0.1 - supports-color: 2.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - /chalk/2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - /chardet/0.7.0: - dev: false - resolution: - integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - /check-types/8.0.3: - dev: false - resolution: - integrity: sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== - /chokidar/1.7.0: - dependencies: - anymatch: 1.3.2 - async-each: 1.0.3 - glob-parent: 2.0.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 2.0.1 - path-is-absolute: 1.0.1 - readdirp: 2.2.1 - dev: false - optionalDependencies: - fsevents: 1.2.11 - resolution: - integrity: sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= - /chokidar/2.1.8: - dependencies: - anymatch: 2.0.0 - async-each: 1.0.3 - braces: 2.3.2 - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.1 - normalize-path: 3.0.0 - path-is-absolute: 1.0.1 - readdirp: 2.2.1 - upath: 1.2.0 - dev: false - optionalDependencies: - fsevents: 1.2.11 - resolution: - integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - /chokidar/3.3.1: - dependencies: - anymatch: 3.1.1 - braces: 3.0.2 - glob-parent: 5.1.0 - is-binary-path: 2.1.0 - is-glob: 4.0.1 - normalize-path: 3.0.0 - readdirp: 3.3.0 - dev: false - engines: - node: '>= 8.10.0' - optionalDependencies: - fsevents: 2.1.2 - resolution: - integrity: sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== - /chownr/1.1.4: - dev: false - resolution: - integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - /chrome-trace-event/1.0.2: - dependencies: - tslib: 1.11.1 - dev: false - engines: - node: '>=6.0' - resolution: - integrity: sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - /ci-info/1.6.0: - dev: false - resolution: - integrity: sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - /cipher-base/1.0.4: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - /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 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - /clean-css/4.2.1: - dependencies: - source-map: 0.6.1 - dev: false - engines: - node: '>= 4.0' - resolution: - integrity: sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== - /cli-cursor/2.1.0: - dependencies: - restore-cursor: 2.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - /cli-table/0.3.1: - dependencies: - colors: 1.0.3 - dev: false - engines: - node: '>= 0.2.0' - resolution: - integrity: sha1-9TsFJmqLGguTSz0IIebi3FkUriM= - /cli-width/2.2.0: - dev: false - resolution: - integrity: sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - /cliui/3.2.0: - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - wrap-ansi: 2.1.0 - dev: false - resolution: - integrity: sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - /cliui/4.1.0: - dependencies: - string-width: 2.1.1 - strip-ansi: 4.0.0 - wrap-ansi: 2.1.0 - dev: false - resolution: - integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - /cliui/5.0.0: - dependencies: - string-width: 3.1.0 - strip-ansi: 5.2.0 - wrap-ansi: 5.1.0 - dev: false - resolution: - integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - /clone-buffer/1.0.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-4+JbIHrE5wGvch4staFnksrD3Fg= - /clone-stats/0.0.1: - dev: false - resolution: - integrity: sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= - /clone-stats/1.0.0: - dev: false - resolution: - integrity: sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= - /clone/1.0.4: - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - /clone/2.1.2: - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - /cloneable-readable/1.1.3: - dependencies: - inherits: 2.0.4 - process-nextick-args: 2.0.1 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== - /co/4.6.0: - dev: false - engines: - iojs: '>= 1.0.0' - node: '>= 0.12.0' - resolution: - integrity: sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - /code-point-at/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - /collection-map/1.0.0: - dependencies: - arr-map: 2.0.2 - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw= - /collection-visit/1.0.0: - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - /color-convert/1.9.3: - dependencies: - color-name: 1.1.3 - dev: false - resolution: - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - /color-name/1.1.3: - dev: false - resolution: - integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - /color-support/1.1.3: - dev: false - hasBin: true - resolution: - integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - /colors/1.0.3: - dev: false - engines: - node: '>=0.1.90' - resolution: - integrity: sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - /colors/1.2.5: - dev: false - engines: - node: '>=0.1.90' - resolution: - integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== - /combined-stream/1.0.8: - dependencies: - delayed-stream: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - /commander/2.11.0: - dev: false - resolution: - integrity: sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - /commander/2.15.1: - dev: false - resolution: - integrity: sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== - /commander/2.17.1: - dev: false - resolution: - integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - /commander/2.19.0: - dev: false - resolution: - integrity: sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - /commander/2.20.3: - dev: false - resolution: - integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - /commander/5.0.0: - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ== - /commondir/1.0.1: - dev: false - resolution: - integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - /component-emitter/1.3.0: - dev: false - resolution: - integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - /compressible/2.0.18: - dependencies: - mime-db: 1.43.0 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - /compression/1.7.4: - dependencies: - accepts: 1.3.7 - bytes: 3.0.0 - compressible: 2.0.18 - debug: 2.6.9 - on-headers: 1.0.2 - safe-buffer: 5.1.2 - vary: 1.1.2 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - /concat-map/0.0.1: - dev: false - resolution: - integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - /concat-stream/1.6.2: - dependencies: - buffer-from: 1.1.1 - inherits: 2.0.4 - readable-stream: 2.3.7 - typedarray: 0.0.6 - dev: false - engines: - '0': node >= 0.8 - resolution: - integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - /connect-history-api-fallback/1.6.0: - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== - /connect-livereload/0.5.4: - dev: false - resolution: - integrity: sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w= - /connect/3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - /console-browserify/1.2.0: - dev: false - resolution: - integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - /console-control-strings/1.1.0: - dev: false - resolution: - integrity: sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - /constants-browserify/1.0.0: - dev: false - resolution: - integrity: sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - /content-disposition/0.5.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-DPaLud318r55YcOoUXjLhdunjLQ= - /content-disposition/0.5.3: - dependencies: - safe-buffer: 5.1.2 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - /content-type/1.0.4: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - /convert-source-map/1.7.0: - dependencies: - safe-buffer: 5.1.2 - dev: false - resolution: - integrity: sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - /cookie-signature/1.0.6: - dev: false - resolution: - integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - /cookie/0.3.1: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= - /cookie/0.4.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - /copy-concurrently/1.0.5: - dependencies: - aproba: 1.2.0 - fs-write-stream-atomic: 1.0.10 - iferr: 0.1.5 - mkdirp: 0.5.3 - rimraf: 2.7.1 - run-queue: 1.0.3 - dev: false - resolution: - integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - /copy-descriptor/0.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - /copy-props/2.0.4: - dependencies: - each-props: 1.3.2 - is-plain-object: 2.0.4 - dev: false - resolution: - integrity: sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== - /core-js/2.6.11: - deprecated: 'core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.' - dev: false - requiresBuild: true - resolution: - integrity: sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - /core-util-is/1.0.2: - dev: false - resolution: - integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - /cpx/1.5.0: - dependencies: - babel-runtime: 6.26.0 - chokidar: 1.7.0 - duplexer: 0.1.1 - glob: 7.1.6 - glob2base: 0.0.12 - minimatch: 3.0.4 - mkdirp: 0.5.3 - resolve: 1.15.1 - safe-buffer: 5.2.0 - shell-quote: 1.7.2 - subarg: 1.0.0 - dev: false - hasBin: true - resolution: - integrity: sha1-GFvgGFEdhycN7czCkxceN2VauI8= - /create-ecdh/4.0.3: - dependencies: - bn.js: 4.11.8 - elliptic: 6.5.2 - dev: false - resolution: - integrity: sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== - /create-hash/1.2.0: - dependencies: - cipher-base: 1.0.4 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - dev: false - resolution: - integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - /create-hmac/1.1.7: - dependencies: - cipher-base: 1.0.4 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.0 - sha.js: 2.4.11 - dev: false - resolution: - integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - /cross-spawn/3.0.1: - dependencies: - lru-cache: 4.1.5 - which: 1.3.1 - dev: false - resolution: - integrity: sha1-ElYDfsufDF9549bvE14wdwGEuYI= - /cross-spawn/5.1.0: - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - dev: false - resolution: - integrity: sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - /cross-spawn/6.0.5: - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.1 - shebang-command: 1.2.0 - which: 1.3.1 - dev: false - engines: - node: '>=4.8' - resolution: - integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - /crypto-browserify/3.12.0: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.0.4 - create-ecdh: 4.0.3 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - inherits: 2.0.4 - pbkdf2: 3.0.17 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - dev: false - resolution: - integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - /css-modules-loader-core/1.1.0: - dependencies: - icss-replace-symbols: 1.1.0 - postcss: 6.0.1 - postcss-modules-extract-imports: 1.1.0 - postcss-modules-local-by-default: 1.2.0 - postcss-modules-scope: 1.1.0 - postcss-modules-values: 1.3.0 - dev: false - resolution: - integrity: sha1-WQhmgpShvs0mGuCkziGwtVHyHRY= - /css-select/1.2.0: - dependencies: - boolbase: 1.0.0 - css-what: 2.1.3 - domutils: 1.5.1 - nth-check: 1.0.2 - dev: false - resolution: - integrity: sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= - /css-selector-tokenizer/0.7.2: - dependencies: - cssesc: 3.0.0 - fastparse: 1.1.2 - regexpu-core: 4.7.0 - dev: false - resolution: - integrity: sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw== - /css-what/2.1.3: - dev: false - resolution: - integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - /cssesc/3.0.0: - dev: false - engines: - node: '>=4' - hasBin: true - resolution: - integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - /cssom/0.3.8: - dev: false - resolution: - integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - /cssstyle/0.3.1: - dependencies: - cssom: 0.3.8 - dev: false - resolution: - integrity: sha512-tNvaxM5blOnxanyxI6panOsnfiyLRj3HV4qjqqS45WPNS1usdYWRUQjqTEEELK73lpeP/1KoIGYUwrBn/VcECA== - /currently-unhandled/0.4.1: - dependencies: - array-find-index: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-mI3zP+qxke95mmE2nddsF635V+o= - /cyclist/1.0.1: - dev: false - resolution: - integrity: sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - /d/1.0.1: - dependencies: - es5-ext: 0.10.53 - type: 1.2.0 - dev: false - resolution: - integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - /dargs/5.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk= - /dashdash/1.14.1: - dependencies: - assert-plus: 1.0.0 - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - /data-urls/1.1.0: - dependencies: - abab: 2.0.3 - whatwg-mimetype: 2.3.0 - whatwg-url: 7.1.0 - dev: false - resolution: - integrity: sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - /dateformat/1.0.12: - dependencies: - get-stdin: 4.0.1 - meow: 3.7.0 - dev: false - hasBin: true - resolution: - integrity: sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk= - /dateformat/2.2.0: - dev: false - resolution: - integrity: sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= - /deasync/0.1.19: - dependencies: - bindings: 1.5.0 - node-addon-api: 1.7.1 - dev: false - engines: - node: '>=0.11.0' - requiresBuild: true - resolution: - integrity: sha512-oh3MRktfnPlLysCPpBpKZZzb4cUC/p0aA3SyRGp15lN30juJBTo/CiD0d4fR+f1kBtUQoJj1NE9RPNWQ7BQ9Mg== - /debug/2.2.0: - dependencies: - ms: 0.7.1 - dev: false - resolution: - integrity: sha1-+HBX6ZWxofauaklgZkE3vFbwOdo= - /debug/2.6.9: - dependencies: - ms: 2.0.0 - dev: false - resolution: - integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - /debug/3.1.0: - dependencies: - ms: 2.0.0 - dev: false - resolution: - integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - /debug/3.2.6: - dependencies: - ms: 2.1.2 - dev: false - resolution: - integrity: sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - /debug/4.1.1: - dependencies: - ms: 2.1.2 - dev: false - resolution: - integrity: sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - /debuglog/1.0.1: - dev: false - resolution: - integrity: sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= - /decache/4.5.1: - dependencies: - callsite: 1.0.0 - dev: false - resolution: - integrity: sha512-5J37nATc6FmOTLbcsr9qx7Nm28qQyg1SK4xyEHqM0IBkNhWFp0Sm+vKoWYHD8wq+OUEb9jLyaKFfzzd1A9hcoA== - /decamelize/1.2.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - /decode-uri-component/0.2.0: - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - /decomment/0.9.2: - dependencies: - esprima: 4.0.1 - dev: false - engines: - node: '>=6.4' - npm: '>=2.15' - resolution: - integrity: sha512-sblyUmOJZxiL7oJ2ogJS6jtl/67+CTOW87SrYE/96u3PhDYikYoLCdLzcnceToiQejOLlqNnLCkaxx/+nE/ehg== - /deep-eql/0.1.3: - dependencies: - type-detect: 0.1.1 - dev: false - resolution: - integrity: sha1-71WKyrjeJSBs1xOQbXTlaTDrafI= - /deep-equal/1.1.1: - dependencies: - is-arguments: 1.0.4 - is-date-object: 1.0.2 - is-regex: 1.0.5 - object-is: 1.0.2 - object-keys: 1.1.1 - regexp.prototype.flags: 1.3.0 - dev: false - resolution: - integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - /deep-is/0.1.3: - dev: false - resolution: - integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - /default-compare/1.0.0: - dependencies: - kind-of: 5.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== - /default-gateway/4.2.0: - dependencies: - execa: 1.0.0 - ip-regex: 2.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== - /default-require-extensions/1.0.0: - dependencies: - strip-bom: 2.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= - /default-resolution/2.0.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= - /define-properties/1.1.3: - dependencies: - object-keys: 1.1.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - /define-property/0.2.5: - dependencies: - is-descriptor: 0.1.6 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - /define-property/1.0.0: - dependencies: - is-descriptor: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - /define-property/2.0.2: - dependencies: - is-descriptor: 1.0.2 - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - /del/2.2.2: - dependencies: - globby: 5.0.0 - is-path-cwd: 1.0.0 - is-path-in-cwd: 1.0.1 - object-assign: 4.1.1 - pify: 2.3.0 - pinkie-promise: 2.0.1 - rimraf: 2.7.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= - /del/4.1.1: - dependencies: - '@types/glob': 7.1.1 - globby: 6.1.0 - is-path-cwd: 2.2.0 - is-path-in-cwd: 2.1.0 - p-map: 2.1.0 - pify: 4.0.1 - rimraf: 2.7.1 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== - /delayed-stream/1.0.0: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - /delegates/1.0.0: - dev: false - resolution: - integrity: sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - /depd/1.1.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - /des.js/1.0.1: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: false - resolution: - integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - /destroy/1.0.4: - dev: false - resolution: - integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - /detect-file/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= - /detect-indent/4.0.0: - dependencies: - repeating: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-920GQ1LN9Docts5hnE7jqUdd4gg= - /detect-indent/6.0.0: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== - /detect-newline/2.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - /detect-node/2.0.4: - dev: false - resolution: - integrity: sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== - /dezalgo/1.0.3: - dependencies: - asap: 2.0.6 - wrappy: 1.0.2 - dev: false - resolution: - integrity: sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - /diff/3.5.0: - dev: false - engines: - node: '>=0.3.1' - resolution: - integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - /diffie-hellman/5.0.3: - dependencies: - bn.js: 4.11.8 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - dev: false - resolution: - integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - /dns-equal/1.0.0: - dev: false - resolution: - integrity: sha1-s55/HabrCnW6nBcySzR1PEfgZU0= - /dns-packet/1.3.1: - dependencies: - ip: 1.1.5 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== - /dns-txt/2.0.2: - dependencies: - buffer-indexof: 1.1.1 - dev: false - resolution: - integrity: sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= - /doctrine/2.1.0: - dependencies: - esutils: 2.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - /doctrine/3.0.0: - dependencies: - esutils: 2.0.3 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - /dom-converter/0.2.0: - dependencies: - utila: 0.4.0 - dev: false - resolution: - integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - /dom-serializer/0.2.2: - dependencies: - domelementtype: 2.0.1 - entities: 2.0.0 - dev: false - resolution: - integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - /domain-browser/1.2.0: - dev: false - engines: - node: '>=0.4' - npm: '>=1.2' - resolution: - integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - /domelementtype/1.3.1: - dev: false - resolution: - integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - /domelementtype/2.0.1: - dev: false - resolution: - integrity: sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== - /domexception/1.0.1: - dependencies: - webidl-conversions: 4.0.2 - dev: false - resolution: - integrity: sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - /domhandler/2.4.2: - dependencies: - domelementtype: 1.3.1 - dev: false - resolution: - integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - /domutils/1.5.1: - dependencies: - dom-serializer: 0.2.2 - domelementtype: 1.3.1 - dev: false - resolution: - integrity: sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= - /domutils/1.7.0: - dependencies: - dom-serializer: 0.2.2 - domelementtype: 1.3.1 - dev: false - resolution: - integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - /duplexer/0.1.1: - dev: false - resolution: - integrity: sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= - /duplexer2/0.0.2: - dependencies: - readable-stream: 1.1.14 - dev: false - resolution: - integrity: sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= - /duplexify/3.7.1: - dependencies: - end-of-stream: 1.1.0 - inherits: 2.0.4 - readable-stream: 2.3.7 - stream-shift: 1.0.1 - dev: false - resolution: - integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - /each-props/1.3.2: - dependencies: - is-plain-object: 2.0.4 - object.defaults: 1.1.0 - dev: false - resolution: - integrity: sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== - /ecc-jsbn/0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - dev: false - resolution: - integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - /ee-first/1.1.1: - dev: false - resolution: - integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - /ejs/2.7.4: - dev: false - engines: - node: '>=0.10.0' - requiresBuild: true - resolution: - integrity: sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== - /electron-to-chromium/1.3.377: - dev: false - resolution: - integrity: sha512-cm2WzMKf/3dW5+hNANKm8GAW6SwIWOqLTJ6GPCD0Bbw1qJ9Wzm9nmx9M+byzSsgw8CdCv5fb/wzLFqVS5h6QrA== - /elliptic/6.5.2: - dependencies: - bn.js: 4.11.8 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - dev: false - resolution: - integrity: sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== - /emoji-regex/7.0.3: - dev: false - resolution: - integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - /emojis-list/2.1.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - /encodeurl/1.0.2: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - /end-of-stream/0.1.5: - dependencies: - once: 1.3.3 - dev: false - resolution: - integrity: sha1-jhdyBsPICDfYVjLouTWd/osvbq8= - /end-of-stream/1.1.0: - dependencies: - once: 1.3.3 - dev: false - resolution: - integrity: sha1-6TUyWLqpEIll78QcsO+K3i88+wc= - /enhanced-resolve/4.1.0: - dependencies: - graceful-fs: 4.2.3 - memory-fs: 0.4.1 - tapable: 1.1.3 - dev: false - engines: - node: '>=6.9.0' - resolution: - integrity: sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== - /enhanced-resolve/4.1.1: - dependencies: - graceful-fs: 4.2.3 - memory-fs: 0.5.0 - tapable: 1.1.3 - dev: false - engines: - node: '>=6.9.0' - resolution: - integrity: sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== - /entities/1.1.2: - dev: false - resolution: - integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - /entities/2.0.0: - dev: false - resolution: - integrity: sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== - /errno/0.1.7: - dependencies: - prr: 1.0.1 - dev: false - hasBin: true - resolution: - integrity: sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== - /error-ex/1.3.2: - dependencies: - is-arrayish: 0.2.1 - dev: false - resolution: - integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - /es-abstract/1.17.4: - dependencies: - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.1 - is-callable: 1.1.5 - is-regex: 1.0.5 - object-inspect: 1.7.0 - object-keys: 1.1.1 - object.assign: 4.1.0 - string.prototype.trimleft: 2.1.1 - string.prototype.trimright: 2.1.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== - /es-to-primitive/1.2.1: - dependencies: - is-callable: 1.1.5 - is-date-object: 1.0.2 - is-symbol: 1.0.3 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - /es5-ext/0.10.53: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - next-tick: 1.0.0 - dev: false - resolution: - integrity: sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - /es6-iterator/2.0.3: - dependencies: - d: 1.0.1 - es5-ext: 0.10.53 - es6-symbol: 3.1.3 - dev: false - resolution: - integrity: sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - /es6-promise/4.2.8: - dev: false - resolution: - integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - /es6-promisify/5.0.0: - dependencies: - es6-promise: 4.2.8 - dev: false - resolution: - integrity: sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - /es6-symbol/3.1.3: - dependencies: - d: 1.0.1 - ext: 1.4.0 - dev: false - resolution: - integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - /es6-weak-map/2.0.3: - dependencies: - d: 1.0.1 - es5-ext: 0.10.53 - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - dev: false - resolution: - integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== - /escape-html/1.0.3: - dev: false - resolution: - integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - /escape-string-regexp/1.0.5: - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - /escodegen/1.14.1: - dependencies: - esprima: 4.0.1 - estraverse: 4.3.0 - esutils: 2.0.3 - optionator: 0.8.3 - dev: false - engines: - node: '>=4.0' - hasBin: true - optionalDependencies: - source-map: 0.6.1 - resolution: - integrity: sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== - /escodegen/1.7.1: - dependencies: - esprima: 1.2.5 - estraverse: 1.9.3 - esutils: 2.0.3 - optionator: 0.5.0 - dev: false - engines: - node: '>=0.12.0' - hasBin: true - optionalDependencies: - source-map: 0.2.0 - resolution: - integrity: sha1-MOz89mypjcZ80v0WKr626vqM5vw= - /escodegen/1.8.1: - dependencies: - esprima: 2.7.3 - estraverse: 1.9.3 - esutils: 2.0.3 - optionator: 0.8.3 - dev: false - engines: - node: '>=0.12.0' - hasBin: true - optionalDependencies: - source-map: 0.2.0 - resolution: - integrity: sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= - /eslint-plugin-promise/4.2.1: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== - /eslint-plugin-react/7.16.0_eslint@6.5.1: - dependencies: - array-includes: 3.1.1 - doctrine: 2.1.0 - eslint: 6.5.1 - has: 1.0.3 - jsx-ast-utils: 2.2.3 - object.entries: 1.1.1 - object.fromentries: 2.0.2 - object.values: 1.1.1 - prop-types: 15.7.2 - resolve: 1.15.1 - dev: false - engines: - node: '>=4' - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 - resolution: - integrity: sha512-GacBAATewhhptbK3/vTP09CbFrgUJmBSaaRcWdbQLFvUZy9yVcQxigBNHGPU/KE2AyHpzj3AWXpxoMTsIDiHug== - /eslint-plugin-security/1.4.0: - dependencies: - safe-regex: 1.1.0 - dev: false - resolution: - integrity: sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA== - /eslint-plugin-tsdoc/0.2.3: - dependencies: - '@microsoft/tsdoc': 0.12.18 - '@microsoft/tsdoc-config': 0.13.2 - dev: false - resolution: - integrity: sha512-pYvYK94ISH9jKHgLjKlHZ9iFvXUsy4jQ944q5Cmp3kr7tAXH4MqJFfefGc47y6K7aOaGnKowGzeeoe1T4oQ1Mg== - /eslint-scope/4.0.3: - dependencies: - esrecurse: 4.2.1 - estraverse: 4.3.0 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - /eslint-scope/5.0.0: - dependencies: - esrecurse: 4.2.1 - estraverse: 4.3.0 - dev: false - engines: - node: '>=8.0.0' - resolution: - integrity: sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== - /eslint-utils/1.4.3: - dependencies: - eslint-visitor-keys: 1.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - /eslint-visitor-keys/1.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== - /eslint/6.5.1: - dependencies: - '@babel/code-frame': 7.8.3 - ajv: 6.12.0 - chalk: 2.4.2 - cross-spawn: 6.0.5 - debug: 4.1.1 - doctrine: 3.0.0 - eslint-scope: 5.0.0 - eslint-utils: 1.4.3 - eslint-visitor-keys: 1.1.0 - espree: 6.2.1 - esquery: 1.1.0 - esutils: 2.0.3 - file-entry-cache: 5.0.1 - functional-red-black-tree: 1.0.1 - glob-parent: 5.1.0 - globals: 11.12.0 - ignore: 4.0.6 - import-fresh: 3.2.1 - imurmurhash: 0.1.4 - inquirer: 6.5.2 - is-glob: 4.0.1 - js-yaml: 3.13.1 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.3.0 - lodash: 4.17.15 - minimatch: 3.0.4 - mkdirp: 0.5.3 - natural-compare: 1.4.0 - optionator: 0.8.3 - progress: 2.0.3 - regexpp: 2.0.1 - semver: 6.3.0 - strip-ansi: 5.2.0 - strip-json-comments: 3.0.1 - table: 5.4.6 - text-table: 0.2.0 - v8-compile-cache: 2.1.0 - dev: false - engines: - node: ^8.10.0 || ^10.13.0 || >=11.10.1 - hasBin: true - resolution: - integrity: sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A== - /espree/6.2.1: - dependencies: - acorn: 7.1.1 - acorn-jsx: 5.2.0_acorn@7.1.1 - eslint-visitor-keys: 1.1.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - /esprima/1.2.5: - dev: false - engines: - node: '>=0.4.0' - hasBin: true - resolution: - integrity: sha1-CZNQL+r2aBODJXVvMPmlH+7sEek= - /esprima/2.5.0: - dev: false - engines: - node: '>=0.10.0' - hasBin: true - resolution: - integrity: sha1-84ekb9NEwbGjm6+MIL+0O20AWMw= - /esprima/2.7.3: - dev: false - engines: - node: '>=0.10.0' - hasBin: true - resolution: - integrity: sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= - /esprima/4.0.1: - dev: false - engines: - node: '>=4' - hasBin: true - resolution: - integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - /esquery/1.1.0: - dependencies: - estraverse: 4.3.0 - dev: false - engines: - node: '>=0.6' - resolution: - integrity: sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q== - /esrecurse/4.2.1: - dependencies: - estraverse: 4.3.0 - dev: false - engines: - node: '>=4.0' - resolution: - integrity: sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - /estraverse/1.9.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - /estraverse/4.3.0: - dev: false - engines: - node: '>=4.0' - resolution: - integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - /esutils/2.0.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - /etag/1.7.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-A9MLX2fdbmMtKUXTDWZScxo01dg= - /etag/1.8.1: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - /event-stream/3.3.5: - dependencies: - duplexer: 0.1.1 - from: 0.1.7 - map-stream: 0.0.7 - pause-stream: 0.0.11 - split: 1.0.1 - stream-combiner: 0.2.2 - through: 2.3.8 - dev: false - resolution: - integrity: sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g== - /eventemitter3/4.0.0: - dev: false - resolution: - integrity: sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== - /events/3.1.0: - dev: false - engines: - node: '>=0.8.x' - resolution: - integrity: sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== - /eventsource/1.0.7: - dependencies: - original: 1.0.2 - dev: false - engines: - node: '>=0.12.0' - resolution: - integrity: sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== - /evp_bytestokey/1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - /exec-sh/0.2.2: - dependencies: - merge: 1.2.1 - dev: false - resolution: - integrity: sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - /execa/0.10.0: - dependencies: - cross-spawn: 6.0.5 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.2 - strip-eof: 1.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== - /execa/0.7.0: - dependencies: - cross-spawn: 5.1.0 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.2 - strip-eof: 1.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - /execa/1.0.0: - dependencies: - cross-spawn: 6.0.5 - 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.2 - strip-eof: 1.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - /exit/0.1.2: - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - /expand-brackets/0.1.5: - dependencies: - is-posix-bracket: 0.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - /expand-brackets/2.1.4: - dependencies: - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - /expand-range/1.8.2: - dependencies: - fill-range: 2.2.4 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - /expand-tilde/2.0.2: - dependencies: - homedir-polyfill: 1.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= - /expect/22.4.3: - dependencies: - ansi-styles: 3.2.1 - jest-diff: 22.4.3 - jest-get-type: 22.4.3 - jest-matcher-utils: 22.4.3 - jest-message-util: 22.4.3 - jest-regex-util: 22.4.3 - dev: false - resolution: - integrity: sha512-XcNXEPehqn8b/jm8FYotdX0YrXn36qp4HWlrVT4ktwQas1l1LPxiVWncYnnL2eyMtKAmVIaG0XAp0QlrqJaxaA== - /expect/23.6.0: - dependencies: - ansi-styles: 3.2.1 - jest-diff: 23.6.0 - jest-get-type: 22.4.3 - jest-matcher-utils: 23.6.0 - jest-message-util: 23.4.0 - jest-regex-util: 23.3.0 - dev: false - resolution: - integrity: sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w== - /express/4.16.4: - dependencies: - accepts: 1.3.7 - array-flatten: 1.1.1 - body-parser: 1.18.3 - content-disposition: 0.5.2 - content-type: 1.0.4 - cookie: 0.3.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 1.1.2 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.1.1 - fresh: 0.5.2 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.3.0 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.6 - qs: 6.5.2 - range-parser: 1.2.1 - safe-buffer: 5.1.2 - send: 0.16.2 - serve-static: 1.13.2 - setprototypeof: 1.1.0 - statuses: 1.4.0 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== - /express/4.17.1: - dependencies: - accepts: 1.3.7 - array-flatten: 1.1.1 - body-parser: 1.19.0 - content-disposition: 0.5.3 - content-type: 1.0.4 - cookie: 0.4.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 1.1.2 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.1.2 - fresh: 0.5.2 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.3.0 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.6 - qs: 6.7.0 - range-parser: 1.2.1 - safe-buffer: 5.1.2 - send: 0.17.1 - serve-static: 1.14.1 - setprototypeof: 1.1.1 - statuses: 1.5.0 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - /ext/1.4.0: - dependencies: - type: 2.0.0 - dev: false - resolution: - integrity: sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - /extend-shallow/2.0.1: - dependencies: - is-extendable: 0.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - /extend-shallow/3.0.2: - dependencies: - assign-symbols: 1.0.0 - is-extendable: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - /extend/3.0.2: - dev: false - resolution: - integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - /external-editor/3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - /extglob/0.3.2: - dependencies: - is-extglob: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - /extglob/2.0.4: - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4 - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - /extsprintf/1.3.0: - dev: false - engines: - '0': node >=0.6.0 - resolution: - integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - /fancy-log/1.3.3: - dependencies: - ansi-gray: 0.1.1 - color-support: 1.1.3 - parse-node-version: 1.0.1 - time-stamp: 1.1.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== - /fast-deep-equal/2.0.1: - dev: false - resolution: - integrity: sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - /fast-deep-equal/3.1.1: - dev: false - resolution: - integrity: sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== - /fast-json-stable-stringify/2.1.0: - dev: false - resolution: - integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - /fast-levenshtein/1.0.7: - dev: false - resolution: - integrity: sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk= - /fast-levenshtein/2.0.6: - dev: false - resolution: - integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - /fastparse/1.1.2: - dev: false - resolution: - integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - /faye-websocket/0.10.0: - dependencies: - websocket-driver: 0.7.3 - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= - /faye-websocket/0.11.3: - dependencies: - websocket-driver: 0.7.3 - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== - /fb-watchman/2.0.1: - dependencies: - bser: 2.1.1 - dev: false - resolution: - integrity: sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - /figgy-pudding/3.5.1: - dev: false - resolution: - integrity: sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== - /figures/2.0.0: - dependencies: - escape-string-regexp: 1.0.5 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - /file-entry-cache/5.0.1: - dependencies: - flat-cache: 2.0.1 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - /file-uri-to-path/1.0.0: - dev: false - resolution: - integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - /filename-regex/2.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - /fileset/0.2.1: - dependencies: - glob: 5.0.15 - minimatch: 2.0.10 - dev: false - resolution: - integrity: sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc= - /fileset/2.0.3: - dependencies: - glob: 7.1.6 - minimatch: 3.0.4 - dev: false - resolution: - integrity: sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= - /filesize/3.6.1: - dev: false - engines: - node: '>= 0.4.0' - resolution: - integrity: sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== - /fill-range/2.2.4: - dependencies: - is-number: 2.1.0 - isobject: 2.1.0 - randomatic: 3.1.1 - repeat-element: 1.1.3 - repeat-string: 1.6.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - /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 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - /fill-range/7.0.1: - dependencies: - to-regex-range: 5.0.1 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - /finalhandler/1.1.1: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.4.0 - unpipe: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== - /finalhandler/1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - /find-cache-dir/2.1.0: - dependencies: - commondir: 1.0.1 - make-dir: 2.1.0 - pkg-dir: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - /find-index/0.1.1: - dev: false - resolution: - integrity: sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= - /find-up/1.1.2: - dependencies: - path-exists: 2.1.0 - pinkie-promise: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - /find-up/2.1.0: - dependencies: - locate-path: 2.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - /find-up/3.0.0: - dependencies: - locate-path: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - /findup-sync/2.0.0: - dependencies: - detect-file: 1.0.0 - is-glob: 3.1.0 - micromatch: 3.1.10 - resolve-dir: 1.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= - /findup-sync/3.0.0: - dependencies: - detect-file: 1.0.0 - is-glob: 4.0.1 - micromatch: 3.1.10 - resolve-dir: 1.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== - /fined/1.2.0: - dependencies: - expand-tilde: 2.0.2 - is-plain-object: 2.0.4 - object.defaults: 1.1.0 - object.pick: 1.3.0 - parse-filepath: 1.0.2 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== - /flagged-respawn/1.0.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== - /flat-cache/2.0.1: - dependencies: - flatted: 2.0.1 - rimraf: 2.6.3 - write: 1.0.3 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - /flatted/2.0.1: - dev: false - resolution: - integrity: sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== - /flush-write-stream/1.1.1: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - /follow-redirects/1.10.0: - dependencies: - debug: 3.2.6 - dev: false - engines: - node: '>=4.0' - resolution: - integrity: sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ== - /for-in/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - /for-own/0.1.5: - dependencies: - for-in: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - /for-own/1.0.0: - dependencies: - for-in: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - /forever-agent/0.6.1: - dev: false - resolution: - integrity: sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - /fork-stream/0.0.4: - dev: false - resolution: - integrity: sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA= - /form-data/2.3.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.26 - dev: false - engines: - node: '>= 0.12' - resolution: - integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - /formatio/1.1.1: - dependencies: - samsam: 1.1.2 - deprecated: This package is unmaintained. Use @sinonjs/formatio instead - dev: false - resolution: - integrity: sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek= - /forwarded/0.1.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - /fragment-cache/0.2.1: - dependencies: - map-cache: 0.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - /fresh/0.3.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8= - /fresh/0.5.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - /from/0.1.7: - dev: false - resolution: - integrity: sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - /from2/2.3.0: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - /fs-extra/6.0.0: - dependencies: - graceful-fs: 4.2.3 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: false - resolution: - integrity: sha512-lk2cUCo8QzbiEWEbt7Cw3m27WMiRG321xsssbcIpfMhpRjrlC08WBOVQqj1/nQYYNnPtyIhP1oqLO3QwT2tPCw== - /fs-extra/7.0.1: - dependencies: - graceful-fs: 4.2.3 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: false - engines: - node: '>=6 <7 || >=8' - resolution: - integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - /fs-minipass/1.2.7: - dependencies: - minipass: 2.9.0 - dev: false - resolution: - integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - /fs-mkdirp-stream/1.0.0: - dependencies: - graceful-fs: 4.2.3 - through2: 2.0.5 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes= - /fs-write-stream-atomic/1.0.10: - dependencies: - graceful-fs: 4.2.3 - iferr: 0.1.5 - imurmurhash: 0.1.4 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - /fs.realpath/1.0.0: - dev: false - resolution: - integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - /fsevents/1.2.11: - bundledDependencies: - - node-pre-gyp - dependencies: - bindings: 1.5.0 - nan: 2.14.0 - dev: false - engines: - node: '>=4.0' - optional: true - os: - - darwin - requiresBuild: true - resolution: - integrity: sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== - /fsevents/2.1.2: - dev: false - engines: - node: ^8.16.0 || ^10.6.0 || >=11.0.0 - optional: true - os: - - darwin - resolution: - integrity: sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== - /fstream/1.0.12: - dependencies: - graceful-fs: 4.2.3 - inherits: 2.0.4 - mkdirp: 0.5.3 - rimraf: 2.7.1 - dev: false - engines: - node: '>=0.6' - resolution: - integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== - /function-bind/1.1.1: - dev: false - resolution: - integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - /functional-red-black-tree/1.0.1: - dev: false - resolution: - integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - /gauge/2.7.4: - dependencies: - aproba: 1.2.0 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - object-assign: 4.1.1 - signal-exit: 3.0.2 - string-width: 1.0.2 - strip-ansi: 3.0.1 - wide-align: 1.1.3 - dev: false - resolution: - integrity: sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - /gaze/1.1.3: - dependencies: - globule: 1.3.1 - dev: false - engines: - node: '>= 4.0.0' - resolution: - integrity: sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== - /generic-names/1.0.3: - dependencies: - loader-utils: 0.2.17 - dev: false - resolution: - integrity: sha1-LXhqEhruUIh2eWk56OO/+DbCCRc= - /get-caller-file/1.0.3: - dev: false - resolution: - integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - /get-caller-file/2.0.5: - dev: false - engines: - node: 6.* || 8.* || >= 10.* - resolution: - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - /get-stdin/4.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - /get-stream/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - /get-stream/4.1.0: - dependencies: - pump: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - /get-value/2.0.6: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - /getpass/0.1.7: - dependencies: - assert-plus: 1.0.0 - dev: false - resolution: - integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - /git-repo-info/2.1.1: - dev: false - engines: - node: '>= 4.0' - resolution: - integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg== - /glob-base/0.3.0: - dependencies: - glob-parent: 2.0.0 - is-glob: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - /glob-escape/0.0.2: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-nCf3gh7RwTd1gvPv2VWOP2dWKO0= - /glob-parent/2.0.0: - dependencies: - is-glob: 2.0.1 - dev: false - resolution: - integrity: sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - /glob-parent/3.1.0: - dependencies: - is-glob: 3.1.0 - path-dirname: 1.0.2 - dev: false - resolution: - integrity: sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - /glob-parent/5.1.0: - dependencies: - is-glob: 4.0.1 - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== - /glob-stream/6.1.0: - dependencies: - extend: 3.0.2 - glob: 7.1.6 - glob-parent: 3.1.0 - is-negated-glob: 1.0.0 - ordered-read-streams: 1.0.1 - pumpify: 1.5.1 - readable-stream: 2.3.7 - remove-trailing-separator: 1.1.0 - to-absolute-glob: 2.0.2 - unique-stream: 2.3.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ= - /glob-watcher/5.0.3: - dependencies: - anymatch: 2.0.0 - async-done: 1.3.2 - chokidar: 2.1.8 - is-negated-glob: 1.0.0 - just-debounce: 1.0.0 - object.defaults: 1.1.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg== - /glob/5.0.15: - dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.0.4 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - resolution: - integrity: sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= - /glob/7.0.6: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.0.4 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - resolution: - integrity: sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= - /glob/7.1.2: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.0.4 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - resolution: - integrity: sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== - /glob/7.1.6: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.0.4 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - resolution: - integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - /glob2base/0.0.12: - dependencies: - find-index: 0.1.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY= - /global-modules/1.0.0: - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== - /global-modules/2.0.0: - dependencies: - global-prefix: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - /global-prefix/1.0.2: - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.5 - is-windows: 1.0.2 - which: 1.3.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= - /global-prefix/3.0.0: - dependencies: - ini: 1.3.5 - kind-of: 6.0.3 - which: 1.3.1 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - /globals/11.12.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - /globals/9.18.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - /globby/5.0.0: - dependencies: - array-union: 1.0.2 - arrify: 1.0.1 - glob: 7.1.6 - object-assign: 4.1.1 - pify: 2.3.0 - pinkie-promise: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= - /globby/6.1.0: - dependencies: - array-union: 1.0.2 - glob: 7.1.6 - object-assign: 4.1.1 - pify: 2.3.0 - pinkie-promise: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - /globule/1.3.1: - dependencies: - glob: 7.1.6 - lodash: 4.17.15 - minimatch: 3.0.4 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g== - /glogg/1.0.2: - dependencies: - sparkles: 1.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== - /graceful-fs/4.2.1: - dev: false - resolution: - integrity: sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw== - /graceful-fs/4.2.3: - dev: false - resolution: - integrity: sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - /growl/1.10.5: - dev: false - engines: - node: '>=4.x' - resolution: - integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - /growly/1.3.0: - dev: false - resolution: - integrity: sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - /gulp-cli/2.2.0: - dependencies: - ansi-colors: 1.1.0 - archy: 1.0.0 - array-sort: 1.0.0 - color-support: 1.1.3 - concat-stream: 1.6.2 - copy-props: 2.0.4 - fancy-log: 1.3.3 - gulplog: 1.0.0 - interpret: 1.2.0 - isobject: 3.0.1 - liftoff: 3.1.0 - matchdep: 2.0.0 - mute-stdout: 1.0.1 - pretty-hrtime: 1.0.3 - replace-homedir: 1.0.0 - semver-greatest-satisfied-range: 1.1.0 - v8flags: 3.1.3 - yargs: 7.1.0 - dev: false - engines: - node: '>= 0.10' - hasBin: true - resolution: - integrity: sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA== - /gulp-connect/5.5.0: - dependencies: - ansi-colors: 1.1.0 - connect: 3.7.0 - connect-livereload: 0.5.4 - event-stream: 3.3.5 - fancy-log: 1.3.3 - send: 0.13.2 - serve-index: 1.9.1 - serve-static: 1.14.1 - tiny-lr: 0.2.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-oRBLjw/4EVaZb8g8OcxOVdGD8ZXYrRiWKcNxlrGjxb/6Cp0GDdqw7ieX7D8xJrQS7sbXT+G94u63pMJF3MMjQA== - /gulp-flatten/0.2.0: - dependencies: - gulp-util: 3.0.8 - through2: 2.0.5 - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-iS1RfjjXkA/UVM+aHgIQMA6S6wY= - /gulp-if/2.0.2: - dependencies: - gulp-match: 1.1.0 - ternary-stream: 2.1.1 - through2: 2.0.5 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha1-pJe351cwBQQcqivIt92jyARE1ik= - /gulp-istanbul/0.10.4: - dependencies: - gulp-util: 3.0.8 - istanbul: 0.4.5 - istanbul-threshold-checker: 0.1.0 - lodash: 4.17.15 - through2: 2.0.5 - dev: false - resolution: - integrity: sha1-Kyoby+uWpix45pgh0QTW/KMu+wk= - /gulp-match/1.1.0: - dependencies: - minimatch: 3.0.4 - dev: false - resolution: - integrity: sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ== - /gulp-mocha/6.0.0: - dependencies: - dargs: 5.1.0 - execa: 0.10.0 - mocha: 5.2.0 - npm-run-path: 2.0.2 - plugin-error: 1.0.1 - supports-color: 5.5.0 - through2: 2.0.5 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-FfBldW5ttnDpKf4Sg6/BLOOKCCbr5mbixDGK1t02/8oSrTCwNhgN/mdszG3cuQuYNzuouUdw4EH/mlYtgUscPg== - /gulp-open/3.0.1: - dependencies: - colors: 1.2.5 - opn: 5.2.0 - plugin-log: 0.1.0 - through2: 2.0.5 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-dohokw+npnt48AsD0hhvCLEHLnDMqM35F+amvIfJlX1H2nNHYUClR0Oy1rI0TvbL1/pHiHGNLmohhk+kvwIKjA== - /gulp-replace/0.5.4: - dependencies: - istextorbinary: 1.0.2 - readable-stream: 2.3.7 - replacestream: 4.0.3 - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-aaZ5FLvRPFYr/xT1BKQDeWqg2qk= - /gulp-util/3.0.8: - dependencies: - array-differ: 1.0.0 - array-uniq: 1.0.3 - beeper: 1.1.1 - chalk: 1.1.3 - dateformat: 2.2.0 - fancy-log: 1.3.3 - gulplog: 1.0.0 - has-gulplog: 0.1.0 - lodash._reescape: 3.0.0 - lodash._reevaluate: 3.0.0 - lodash._reinterpolate: 3.0.0 - lodash.template: 3.6.2 - minimist: 1.2.5 - multipipe: 0.1.2 - object-assign: 3.0.0 - replace-ext: 0.0.1 - through2: 2.0.5 - vinyl: 0.5.3 - deprecated: 'gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5' - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-AFTh50RQLifATBh8PsxQXdVLu08= - /gulp/4.0.2: - dependencies: - glob-watcher: 5.0.3 - gulp-cli: 2.2.0 - undertaker: 1.2.1 - vinyl-fs: 3.0.3 - dev: false - engines: - node: '>= 0.10' - hasBin: true - resolution: - integrity: sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA== - /gulplog/1.0.0: - dependencies: - glogg: 1.0.2 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-4oxNRdBey77YGDY86PnFkmIp/+U= - /gzip-size/5.1.1: - dependencies: - duplexer: 0.1.1 - pify: 4.0.1 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== - /handle-thing/2.0.0: - dev: false - resolution: - integrity: sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== - /handlebars/4.7.3: - dependencies: - neo-async: 2.6.1 - optimist: 0.6.1 - source-map: 0.6.1 - dev: false - engines: - node: '>=0.4.7' - hasBin: true - optionalDependencies: - uglify-js: 3.8.0 - resolution: - integrity: sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg== - /har-schema/2.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - /har-validator/5.1.3: - dependencies: - ajv: 6.12.0 - har-schema: 2.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - /has-ansi/2.0.0: - dependencies: - ansi-regex: 2.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - /has-flag/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - /has-flag/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - /has-gulplog/0.1.0: - dependencies: - sparkles: 1.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= - /has-symbols/1.0.1: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - /has-unicode/2.0.1: - dev: false - resolution: - integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - /has-value/0.3.1: - dependencies: - get-value: 2.0.6 - has-values: 0.1.4 - isobject: 2.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - /has-value/1.0.0: - dependencies: - get-value: 2.0.6 - has-values: 1.0.0 - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - /has-values/0.1.4: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-bWHeldkd/Km5oCCJrThL/49it3E= - /has-values/1.0.0: - dependencies: - is-number: 3.0.0 - kind-of: 4.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - /has/1.0.3: - dependencies: - function-bind: 1.1.1 - dev: false - engines: - node: '>= 0.4.0' - resolution: - integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - /hash-base/3.0.4: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= - /hash.js/1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: false - resolution: - integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - /he/1.1.1: - dev: false - hasBin: true - resolution: - integrity: sha1-k0EP0hsAlzUVH4howvJx80J+I/0= - /he/1.2.0: - dev: false - hasBin: true - resolution: - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - /hmac-drbg/1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - dev: false - resolution: - integrity: sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - /home-or-tmp/2.0.0: - dependencies: - os-homedir: 1.0.2 - os-tmpdir: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-42w/LSyufXRqhX440Y1fMqeILbg= - /homedir-polyfill/1.0.3: - dependencies: - parse-passwd: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== - /hoopy/0.1.4: - dev: false - engines: - node: '>= 6.0.0' - resolution: - integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== - /hosted-git-info/2.8.8: - dev: false - resolution: - integrity: sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - /hpack.js/2.1.6: - dependencies: - inherits: 2.0.4 - obuf: 1.1.2 - readable-stream: 2.3.7 - wbuf: 1.7.3 - dev: false - resolution: - integrity: sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= - /html-encoding-sniffer/1.0.2: - dependencies: - whatwg-encoding: 1.0.5 - dev: false - resolution: - integrity: sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - /html-entities/1.2.1: - dev: false - engines: - '0': node >= 0.4.0 - resolution: - integrity: sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= - /html-minifier/3.5.21: - dependencies: - camel-case: 3.0.0 - clean-css: 4.2.1 - commander: 2.17.1 - he: 1.2.0 - param-case: 2.1.1 - relateurl: 0.2.7 - uglify-js: 3.4.10 - dev: false - engines: - node: '>=4' - hasBin: true - resolution: - integrity: sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== - /html-webpack-plugin/3.2.0_webpack@4.31.0: - dependencies: - html-minifier: 3.5.21 - loader-utils: 0.2.17 - lodash: 4.17.15 - pretty-error: 2.1.1 - tapable: 1.1.3 - toposort: 1.0.7 - util.promisify: 1.0.0 - webpack: 4.31.0_webpack@4.31.0 - dev: false - engines: - node: '>=6.9' - peerDependencies: - webpack: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - resolution: - integrity: sha1-sBq71yOsqqeze2r0SS69oD2d03s= - /htmlparser2/3.10.1: - dependencies: - domelementtype: 1.3.1 - domhandler: 2.4.2 - domutils: 1.7.0 - entities: 1.1.2 - inherits: 2.0.4 - readable-stream: 3.6.0 - dev: false - resolution: - integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - /http-deceiver/1.2.7: - dev: false - resolution: - integrity: sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= - /http-errors/1.3.1: - dependencies: - inherits: 2.0.4 - statuses: 1.2.1 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-GX4izevUGYWF6GlO9nhhl7ke2UI= - /http-errors/1.6.3: - dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 - statuses: 1.5.0 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - /http-errors/1.7.2: - dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - /http-errors/1.7.3: - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - /http-parser-js/0.4.10: - dev: false - resolution: - integrity: sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= - /http-proxy-middleware/0.19.1: - dependencies: - http-proxy: 1.18.0 - is-glob: 4.0.1 - lodash: 4.17.15 - micromatch: 3.1.10 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== - /http-proxy/1.18.0: - dependencies: - eventemitter3: 4.0.0 - follow-redirects: 1.10.0 - requires-port: 1.0.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== - /http-signature/1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.1 - sshpk: 1.16.1 - dev: false - engines: - node: '>=0.8' - npm: '>=1.3.7' - resolution: - integrity: sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - /https-browserify/1.0.0: - dev: false - resolution: - integrity: sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - /https-proxy-agent/2.2.4: - dependencies: - agent-base: 4.3.0 - debug: 3.2.6 - dev: false - engines: - node: '>= 4.5.0' - resolution: - integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - /iconv-lite/0.4.13: - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha1-H4irpKsLFQjoMSrMOTRfNumS4vI= - /iconv-lite/0.4.23: - dependencies: - safer-buffer: 2.1.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== - /iconv-lite/0.4.24: - dependencies: - safer-buffer: 2.1.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - /icss-replace-symbols/1.1.0: - dev: false - resolution: - integrity: sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - /ieee754/1.1.13: - dev: false - resolution: - integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - /iferr/0.1.5: - dev: false - resolution: - integrity: sha1-xg7taebY/bazEEofy8ocGS3FtQE= - /ignore/4.0.6: - dev: false - engines: - node: '>= 4' - resolution: - integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - /import-fresh/3.2.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - /import-local/1.0.0: - dependencies: - pkg-dir: 2.0.0 - resolve-cwd: 2.0.0 - dev: false - engines: - node: '>=4' - hasBin: true - resolution: - integrity: sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ== - /import-local/2.0.0: - dependencies: - pkg-dir: 3.0.0 - resolve-cwd: 2.0.0 - dev: false - engines: - node: '>=6' - hasBin: true - resolution: - integrity: sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - /imurmurhash/0.1.4: - dev: false - engines: - node: '>=0.8.19' - resolution: - integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o= - /in-publish/2.0.1: - dev: false - hasBin: true - resolution: - integrity: sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ== - /indent-string/2.1.0: - dependencies: - repeating: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - /infer-owner/1.0.4: - dev: false - resolution: - integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - /inflight/1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: false - resolution: - integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - /inherits/2.0.1: - dev: false - resolution: - integrity: sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - /inherits/2.0.3: - dev: false - resolution: - integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - /inherits/2.0.4: - dev: false - resolution: - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - /ini/1.3.5: - dev: false - resolution: - integrity: sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - /inpath/1.0.2: - dev: false - resolution: - integrity: sha1-SsIZcQ7Hpy9GD/lL9CTdPvDlKBc= - /inquirer/6.2.2: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-width: 2.2.0 - external-editor: 3.1.0 - figures: 2.0.0 - lodash: 4.17.15 - mute-stream: 0.0.7 - run-async: 2.4.0 - rxjs: 6.5.4 - string-width: 2.1.1 - strip-ansi: 5.2.0 - through: 2.3.8 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA== - /inquirer/6.5.2: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-width: 2.2.0 - external-editor: 3.1.0 - figures: 2.0.0 - lodash: 4.17.15 - mute-stream: 0.0.7 - run-async: 2.4.0 - rxjs: 6.5.4 - string-width: 2.1.1 - strip-ansi: 5.2.0 - through: 2.3.8 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - /internal-ip/4.3.0: - dependencies: - default-gateway: 4.2.0 - ipaddr.js: 1.9.1 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== - /interpret/1.2.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== - /invariant/2.2.4: - dependencies: - loose-envify: 1.4.0 - dev: false - resolution: - integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - /invert-kv/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - /invert-kv/2.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - /ip-regex/2.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - /ip/1.1.5: - dev: false - resolution: - integrity: sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - /ipaddr.js/1.9.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - /is-absolute-url/3.0.3: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - /is-absolute/1.0.0: - dependencies: - is-relative: 1.0.0 - is-windows: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== - /is-accessor-descriptor/0.1.6: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - /is-accessor-descriptor/1.0.0: - dependencies: - kind-of: 6.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - /is-arguments/1.0.4: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== - /is-arrayish/0.2.1: - dev: false - resolution: - integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - /is-binary-path/1.0.1: - dependencies: - binary-extensions: 1.13.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - /is-binary-path/2.1.0: - dependencies: - binary-extensions: 2.0.0 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - /is-buffer/1.1.6: - dev: false - resolution: - integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - /is-callable/1.1.5: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== - /is-ci/1.2.1: - dependencies: - ci-info: 1.6.0 - dev: false - hasBin: true - resolution: - integrity: sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - /is-data-descriptor/0.1.4: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - /is-data-descriptor/1.0.0: - dependencies: - kind-of: 6.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - /is-date-object/1.0.2: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - /is-descriptor/0.1.6: - dependencies: - is-accessor-descriptor: 0.1.6 - is-data-descriptor: 0.1.4 - kind-of: 5.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - /is-descriptor/1.0.2: - dependencies: - is-accessor-descriptor: 1.0.0 - is-data-descriptor: 1.0.0 - kind-of: 6.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - /is-dotfile/1.0.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - /is-equal-shallow/0.1.3: - dependencies: - is-primitive: 2.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - /is-extendable/0.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - /is-extendable/1.0.1: - dependencies: - is-plain-object: 2.0.4 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - /is-extglob/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - /is-extglob/2.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - /is-finite/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - /is-fullwidth-code-point/1.0.0: - dependencies: - number-is-nan: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - /is-fullwidth-code-point/2.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - /is-generator-fn/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-lp1J4bszKfa7fwkIm+JleLLd1Go= - /is-generator-function/1.0.7: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== - /is-glob/2.0.1: - dependencies: - is-extglob: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - /is-glob/3.1.0: - dependencies: - is-extglob: 2.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - /is-glob/4.0.1: - dependencies: - is-extglob: 2.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - /is-negated-glob/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= - /is-number/2.1.0: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - /is-number/3.0.0: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - /is-number/4.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - /is-number/7.0.0: - dev: false - engines: - node: '>=0.12.0' - resolution: - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - /is-path-cwd/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= - /is-path-cwd/2.2.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - /is-path-in-cwd/1.0.1: - dependencies: - is-path-inside: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== - /is-path-in-cwd/2.1.0: - dependencies: - is-path-inside: 2.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - /is-path-inside/1.0.1: - dependencies: - path-is-inside: 1.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-jvW33lBDej/cprToZe96pVy0gDY= - /is-path-inside/2.1.0: - dependencies: - path-is-inside: 1.0.2 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - /is-plain-obj/2.1.0: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - /is-plain-object/2.0.4: - dependencies: - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - /is-posix-bracket/0.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - /is-primitive/2.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - /is-promise/2.1.0: - dev: false - resolution: - integrity: sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - /is-regex/1.0.5: - dependencies: - has: 1.0.3 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== - /is-relative/1.0.0: - dependencies: - is-unc-path: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== - /is-stream/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - /is-string/1.0.5: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - /is-subdir/1.1.1: - dependencies: - better-path-resolve: 1.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-VYpq0S7gPBVkkmfwkvGnx1EL9UVIo87NQyNcgMiNUdQCws3CJm5wj2nB+XPL7zigvjxhuZgp3bl2yBcKkSIj1w== - /is-symbol/1.0.3: - dependencies: - has-symbols: 1.0.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - /is-typedarray/1.0.0: - dev: false - resolution: - integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - /is-unc-path/1.0.0: - dependencies: - unc-path-regex: 0.1.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== - /is-utf8/0.2.1: - dev: false - resolution: - integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - /is-valid-glob/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= - /is-windows/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - /is-wsl/1.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - /isarray/0.0.1: - dev: false - resolution: - integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - /isarray/1.0.0: - dev: false - resolution: - integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - /isexe/2.0.0: - dev: false - resolution: - integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - /isobject/2.1.0: - dependencies: - isarray: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - /isobject/3.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - /isstream/0.1.2: - dev: false - resolution: - integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - /istanbul-api/1.3.7: - dependencies: - async: 2.6.3 - fileset: 2.0.3 - istanbul-lib-coverage: 1.2.1 - istanbul-lib-hook: 1.2.2 - istanbul-lib-instrument: 1.10.2 - istanbul-lib-report: 1.1.5 - istanbul-lib-source-maps: 1.2.6 - istanbul-reports: 1.5.1 - js-yaml: 3.13.1 - mkdirp: 0.5.3 - once: 1.4.0 - dev: false - resolution: - integrity: sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA== - /istanbul-lib-coverage/1.2.1: - dev: false - resolution: - integrity: sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== - /istanbul-lib-hook/1.2.2: - dependencies: - append-transform: 0.4.0 - dev: false - resolution: - integrity: sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== - /istanbul-lib-instrument/1.10.2: - dependencies: - babel-generator: 6.26.1 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - istanbul-lib-coverage: 1.2.1 - semver: 5.7.1 - dev: false - resolution: - integrity: sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== - /istanbul-lib-report/1.1.5: - dependencies: - istanbul-lib-coverage: 1.2.1 - mkdirp: 0.5.3 - path-parse: 1.0.6 - supports-color: 3.2.3 - dev: false - resolution: - integrity: sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== - /istanbul-lib-source-maps/1.2.6: - dependencies: - debug: 3.2.6 - istanbul-lib-coverage: 1.2.1 - mkdirp: 0.5.3 - rimraf: 2.7.1 - source-map: 0.5.7 - dev: false - resolution: - integrity: sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== - /istanbul-reports/1.5.1: - dependencies: - handlebars: 4.7.3 - dev: false - resolution: - integrity: sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== - /istanbul-threshold-checker/0.1.0: - dependencies: - istanbul: 0.3.22 - lodash: 3.6.0 - dev: false - resolution: - integrity: sha1-DhRCwBfLJ6hfeBc0/v0hJkBco5w= - /istanbul/0.3.22: - dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.7.1 - esprima: 2.5.0 - fileset: 0.2.1 - handlebars: 4.7.3 - js-yaml: 3.13.1 - mkdirp: 0.5.3 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - deprecated: |- - This module is no longer maintained, try this instead: - npm i nyc - Visit https://istanbul.js.org/integrations for other alternatives. - dev: false - hasBin: true - resolution: - integrity: sha1-PhZNhQIf4ZyYXR8OfvDD4i0BLrY= - /istanbul/0.4.5: - dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.3 - js-yaml: 3.13.1 - mkdirp: 0.5.3 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - deprecated: |- - This module is no longer maintained, try this instead: - npm i nyc - Visit https://istanbul.js.org/integrations for other alternatives. - dev: false - hasBin: true - resolution: - integrity: sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= - /istextorbinary/1.0.2: - dependencies: - binaryextensions: 1.0.1 - textextensions: 1.0.2 - dev: false - engines: - node: '>=0.4' - resolution: - integrity: sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8= - /jest-changed-files/22.4.3: - dependencies: - throat: 4.1.0 - dev: false - resolution: - integrity: sha512-83Dh0w1aSkUNFhy5d2dvqWxi/y6weDwVVLU6vmK0cV9VpRxPzhTeGimbsbRDSnEoszhF937M4sDLLeS7Cu/Tmw== - /jest-changed-files/23.4.2: - dependencies: - throat: 4.1.0 - dev: false - resolution: - integrity: sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA== - /jest-cli/22.4.4: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - exit: 0.1.2 - glob: 7.1.6 - graceful-fs: 4.2.3 - import-local: 1.0.0 - is-ci: 1.2.1 - istanbul-api: 1.3.7 - istanbul-lib-coverage: 1.2.1 - istanbul-lib-instrument: 1.10.2 - istanbul-lib-source-maps: 1.2.6 - jest-changed-files: 22.4.3 - jest-config: 22.4.4 - jest-environment-jsdom: 22.4.3 - jest-get-type: 22.4.3 - jest-haste-map: 22.4.3 - jest-message-util: 22.4.3 - jest-regex-util: 22.4.3 - jest-resolve-dependencies: 22.4.3 - jest-runner: 22.4.4 - jest-runtime: 22.4.4 - jest-snapshot: 22.4.3 - jest-util: 22.4.3 - jest-validate: 22.4.4 - jest-worker: 22.4.3 - micromatch: 2.3.11 - node-notifier: 5.4.3 - realpath-native: 1.1.0 - rimraf: 2.7.1 - slash: 1.0.0 - string-length: 2.0.0 - strip-ansi: 4.0.0 - which: 1.3.1 - yargs: 10.1.2 - dev: false - engines: - node: '>= 6' - hasBin: true - resolution: - integrity: sha512-I9dsgkeyjVEEZj9wrGrqlH+8OlNob9Iptyl+6L5+ToOLJmHm4JwOPatin1b2Bzp5R5YRQJ+oiedx7o1H7wJzhA== - /jest-cli/23.6.0: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - exit: 0.1.2 - glob: 7.1.6 - graceful-fs: 4.2.3 - import-local: 1.0.0 - is-ci: 1.2.1 - istanbul-api: 1.3.7 - istanbul-lib-coverage: 1.2.1 - istanbul-lib-instrument: 1.10.2 - istanbul-lib-source-maps: 1.2.6 - jest-changed-files: 23.4.2 - jest-config: 23.6.0 - jest-environment-jsdom: 23.4.0 - jest-get-type: 22.4.3 - jest-haste-map: 23.6.0 - jest-message-util: 23.4.0 - jest-regex-util: 23.3.0 - jest-resolve-dependencies: 23.6.0 - jest-runner: 23.6.0 - jest-runtime: 23.6.0 - jest-snapshot: 23.6.0 - jest-util: 23.4.0 - jest-validate: 23.6.0 - jest-watcher: 23.4.0 - jest-worker: 23.2.0 - micromatch: 2.3.11 - node-notifier: 5.4.3 - prompts: 0.1.14 - realpath-native: 1.1.0 - rimraf: 2.7.1 - slash: 1.0.0 - string-length: 2.0.0 - strip-ansi: 4.0.0 - which: 1.3.1 - yargs: 11.1.1 - dev: false - engines: - node: '>= 6' - hasBin: true - resolution: - integrity: sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ== - /jest-config/22.4.4: - dependencies: - chalk: 2.4.2 - glob: 7.1.6 - jest-environment-jsdom: 22.4.3 - jest-environment-node: 22.4.3 - jest-get-type: 22.4.3 - jest-jasmine2: 22.4.4 - jest-regex-util: 22.4.3 - jest-resolve: 22.4.3 - jest-util: 22.4.3 - jest-validate: 22.4.4 - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-9CKfo1GC4zrXSoMLcNeDvQBfgtqGTB1uP8iDIZ97oB26RCUb886KkKWhVcpyxVDOUxbhN+uzcBCeFe7w+Iem4A== - /jest-config/23.6.0: - dependencies: - babel-core: 6.26.3 - babel-jest: 23.6.0_babel-core@6.26.3 - chalk: 2.4.2 - glob: 7.1.6 - jest-environment-jsdom: 23.4.0 - jest-environment-node: 23.4.0 - jest-get-type: 22.4.3 - jest-jasmine2: 23.6.0 - jest-regex-util: 23.3.0 - jest-resolve: 23.6.0 - jest-util: 23.4.0 - jest-validate: 23.6.0 - micromatch: 2.3.11 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ== - /jest-diff/22.4.3: - dependencies: - chalk: 2.4.2 - diff: 3.5.0 - jest-get-type: 22.4.3 - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-/QqGvCDP5oZOF6PebDuLwrB2BMD8ffJv6TAGAdEVuDx1+uEgrHpSFrfrOiMRx2eJ1hgNjlQrOQEHetVwij90KA== - /jest-diff/23.6.0: - dependencies: - chalk: 2.4.2 - diff: 3.5.0 - jest-get-type: 22.4.3 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g== - /jest-docblock/22.4.3: - dependencies: - detect-newline: 2.1.0 - dev: false - resolution: - integrity: sha512-uPKBEAw7YrEMcXueMKZXn/rbMxBiSv48fSqy3uEnmgOlQhSX+lthBqHb1fKWNVmFqAp9E/RsSdBfiV31LbzaOg== - /jest-docblock/23.2.0: - dependencies: - detect-newline: 2.1.0 - dev: false - resolution: - integrity: sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c= - /jest-each/23.6.0: - dependencies: - chalk: 2.4.2 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg== - /jest-environment-jsdom/22.4.3: - dependencies: - jest-mock: 22.4.3 - jest-util: 22.4.3 - jsdom: 11.11.0 - dev: false - resolution: - integrity: sha512-FviwfR+VyT3Datf13+ULjIMO5CSeajlayhhYQwpzgunswoaLIPutdbrnfUHEMyJCwvqQFaVtTmn9+Y8WCt6n1w== - /jest-environment-jsdom/23.4.0: - dependencies: - jest-mock: 23.2.0 - jest-util: 23.4.0 - jsdom: 11.11.0 - dev: false - resolution: - integrity: sha1-BWp5UrP+pROsYqFAosNox52eYCM= - /jest-environment-node/22.4.3: - dependencies: - jest-mock: 22.4.3 - jest-util: 22.4.3 - dev: false - resolution: - integrity: sha512-reZl8XF6t/lMEuPWwo9OLfttyC26A5AMgDyEQ6DBgZuyfyeNUzYT8BFo6uxCCP/Av/b7eb9fTi3sIHFPBzmlRA== - /jest-environment-node/23.4.0: - dependencies: - jest-mock: 23.2.0 - jest-util: 23.4.0 - dev: false - resolution: - integrity: sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA= - /jest-get-type/22.4.3: - dev: false - resolution: - integrity: sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== - /jest-haste-map/22.4.3: - dependencies: - fb-watchman: 2.0.1 - graceful-fs: 4.2.3 - jest-docblock: 22.4.3 - jest-serializer: 22.4.3 - jest-worker: 22.4.3 - micromatch: 2.3.11 - sane: 2.5.2 - dev: false - resolution: - integrity: sha512-4Q9fjzuPVwnaqGKDpIsCSoTSnG3cteyk2oNVjBX12HHOaF1oxql+uUiqZb5Ndu7g/vTZfdNwwy4WwYogLh29DQ== - /jest-haste-map/23.6.0: - dependencies: - fb-watchman: 2.0.1 - graceful-fs: 4.2.3 - invariant: 2.2.4 - jest-docblock: 23.2.0 - jest-serializer: 23.0.1 - jest-worker: 23.2.0 - micromatch: 2.3.11 - sane: 2.5.2 - dev: false - resolution: - integrity: sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg== - /jest-jasmine2/22.4.4: - dependencies: - chalk: 2.4.2 - co: 4.6.0 - expect: 22.4.3 - graceful-fs: 4.2.3 - is-generator-fn: 1.0.0 - jest-diff: 22.4.3 - jest-matcher-utils: 22.4.3 - jest-message-util: 22.4.3 - jest-snapshot: 22.4.3 - jest-util: 22.4.3 - source-map-support: 0.5.16 - dev: false - resolution: - integrity: sha512-nK3vdUl50MuH7vj/8at7EQVjPGWCi3d5+6aCi7Gxy/XMWdOdbH1qtO/LjKbqD8+8dUAEH+BVVh7HkjpCWC1CSw== - /jest-jasmine2/23.6.0: - dependencies: - babel-traverse: 6.26.0 - chalk: 2.4.2 - co: 4.6.0 - expect: 23.6.0 - is-generator-fn: 1.0.0 - jest-diff: 23.6.0 - jest-each: 23.6.0 - jest-matcher-utils: 23.6.0 - jest-message-util: 23.4.0 - jest-snapshot: 23.6.0 - jest-util: 23.4.0 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ== - /jest-leak-detector/22.4.3: - dependencies: - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-NZpR/Ls7+ndO57LuXROdgCGz2RmUdC541tTImL9bdUtU3WadgFGm0yV+Ok4Fuia/1rLAn5KaJ+i76L6e3zGJYQ== - /jest-leak-detector/23.6.0: - dependencies: - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg== - /jest-matcher-utils/22.4.3: - dependencies: - chalk: 2.4.2 - jest-get-type: 22.4.3 - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA== - /jest-matcher-utils/23.6.0: - dependencies: - chalk: 2.4.2 - jest-get-type: 22.4.3 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog== - /jest-message-util/22.4.3: - dependencies: - '@babel/code-frame': 7.8.3 - chalk: 2.4.2 - micromatch: 2.3.11 - slash: 1.0.0 - stack-utils: 1.0.2 - dev: false - resolution: - integrity: sha512-iAMeKxhB3Se5xkSjU0NndLLCHtP4n+GtCqV0bISKA5dmOXQfEbdEmYiu2qpnWBDCQdEafNDDU6Q+l6oBMd/+BA== - /jest-message-util/23.4.0: - dependencies: - '@babel/code-frame': 7.8.3 - chalk: 2.4.2 - micromatch: 2.3.11 - slash: 1.0.0 - stack-utils: 1.0.2 - dev: false - resolution: - integrity: sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8= - /jest-mock/22.4.3: - dev: false - resolution: - integrity: sha512-+4R6mH5M1G4NK16CKg9N1DtCaFmuxhcIqF4lQK/Q1CIotqMs/XBemfpDPeVZBFow6iyUNu6EBT9ugdNOTT5o5Q== - /jest-mock/23.2.0: - dev: false - resolution: - integrity: sha1-rRxg8p6HGdR8JuETgJi20YsmETQ= - /jest-nunit-reporter/1.3.1: - dependencies: - mkdirp: 0.5.3 - read-pkg: 3.0.0 - xml: 1.0.1 - dev: false - resolution: - integrity: sha1-2xmVprP68SkftT+wNyJJcKpLVJc= - /jest-regex-util/22.4.3: - dev: false - resolution: - integrity: sha512-LFg1gWr3QinIjb8j833bq7jtQopiwdAs67OGfkPrvy7uNUbVMfTXXcOKXJaeY5GgjobELkKvKENqq1xrUectWg== - /jest-regex-util/23.3.0: - dev: false - resolution: - integrity: sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U= - /jest-resolve-dependencies/22.4.3: - dependencies: - jest-regex-util: 22.4.3 - dev: false - resolution: - integrity: sha512-06czCMVToSN8F2U4EvgSB1Bv/56gc7MpCftZ9z9fBgUQM7dzHGCMBsyfVA6dZTx8v0FDcnALf7hupeQxaBCvpA== - /jest-resolve-dependencies/23.6.0: - dependencies: - jest-regex-util: 23.3.0 - jest-snapshot: 23.6.0 - dev: false - resolution: - integrity: sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA== - /jest-resolve/22.4.3: - dependencies: - browser-resolve: 1.11.3 - chalk: 2.4.2 - dev: false - resolution: - integrity: sha512-u3BkD/MQBmwrOJDzDIaxpyqTxYH+XqAXzVJP51gt29H8jpj3QgKof5GGO2uPGKGeA1yTMlpbMs1gIQ6U4vcRhw== - /jest-resolve/23.6.0: - dependencies: - browser-resolve: 1.11.3 - chalk: 2.4.2 - realpath-native: 1.1.0 - dev: false - resolution: - integrity: sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA== - /jest-runner/22.4.4: - dependencies: - exit: 0.1.2 - jest-config: 22.4.4 - jest-docblock: 22.4.3 - jest-haste-map: 22.4.3 - jest-jasmine2: 22.4.4 - jest-leak-detector: 22.4.3 - jest-message-util: 22.4.3 - jest-runtime: 22.4.4 - jest-util: 22.4.3 - jest-worker: 22.4.3 - throat: 4.1.0 - dev: false - resolution: - integrity: sha512-5S/OpB51igQW9xnkM5Tgd/7ZjiAuIoiJAVtvVTBcEBiXBIFzWM3BAMPBM19FX68gRV0KWyFuGKj0EY3M3aceeQ== - /jest-runner/23.6.0: - dependencies: - exit: 0.1.2 - graceful-fs: 4.2.3 - jest-config: 23.6.0 - jest-docblock: 23.2.0 - jest-haste-map: 23.6.0 - jest-jasmine2: 23.6.0 - jest-leak-detector: 23.6.0 - jest-message-util: 23.4.0 - jest-runtime: 23.6.0 - jest-util: 23.4.0 - jest-worker: 23.2.0 - source-map-support: 0.5.16 - throat: 4.1.0 - dev: false - resolution: - integrity: sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA== - /jest-runtime/22.4.4: - dependencies: - babel-core: 6.26.3 - babel-jest: 22.4.4_babel-core@6.26.3 - babel-plugin-istanbul: 4.1.6 - chalk: 2.4.2 - convert-source-map: 1.7.0 - exit: 0.1.2 - graceful-fs: 4.2.3 - jest-config: 22.4.4 - jest-haste-map: 22.4.3 - jest-regex-util: 22.4.3 - jest-resolve: 22.4.3 - jest-util: 22.4.3 - jest-validate: 22.4.4 - json-stable-stringify: 1.0.1 - micromatch: 2.3.11 - realpath-native: 1.1.0 - slash: 1.0.0 - strip-bom: 3.0.0 - write-file-atomic: 2.4.3 - yargs: 10.1.2 - dev: false - hasBin: true - resolution: - integrity: sha512-WRTj9m///npte1YjuphCYX7GRY/c2YvJImU9t7qOwFcqHr4YMzmX6evP/3Sehz5DKW2Vi8ONYPCFWe36JVXxfw== - /jest-runtime/23.6.0: - dependencies: - babel-core: 6.26.3 - babel-plugin-istanbul: 4.1.6 - chalk: 2.4.2 - convert-source-map: 1.7.0 - exit: 0.1.2 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.3 - jest-config: 23.6.0 - jest-haste-map: 23.6.0 - jest-message-util: 23.4.0 - jest-regex-util: 23.3.0 - jest-resolve: 23.6.0 - jest-snapshot: 23.6.0 - jest-util: 23.4.0 - jest-validate: 23.6.0 - micromatch: 2.3.11 - realpath-native: 1.1.0 - slash: 1.0.0 - strip-bom: 3.0.0 - write-file-atomic: 2.4.3 - yargs: 11.1.1 - dev: false - hasBin: true - resolution: - integrity: sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw== - /jest-serializer/22.4.3: - dev: false - resolution: - integrity: sha512-uPaUAppx4VUfJ0QDerpNdF43F68eqKWCzzhUlKNDsUPhjOon7ZehR4C809GCqh765FoMRtTVUVnGvIoskkYHiw== - /jest-serializer/23.0.1: - dev: false - resolution: - integrity: sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= - /jest-snapshot/22.4.3: - dependencies: - chalk: 2.4.2 - jest-diff: 22.4.3 - jest-matcher-utils: 22.4.3 - mkdirp: 0.5.3 - natural-compare: 1.4.0 - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-JXA0gVs5YL0HtLDCGa9YxcmmV2LZbwJ+0MfyXBBc5qpgkEYITQFJP7XNhcHFbUvRiniRpRbGVfJrOoYhhGE0RQ== - /jest-snapshot/23.6.0: - dependencies: - babel-types: 6.26.0 - chalk: 2.4.2 - jest-diff: 23.6.0 - jest-matcher-utils: 23.6.0 - jest-message-util: 23.4.0 - jest-resolve: 23.6.0 - mkdirp: 0.5.3 - natural-compare: 1.4.0 - pretty-format: 23.6.0 - semver: 5.7.1 - dev: false - resolution: - integrity: sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg== - /jest-util/22.4.3: - dependencies: - callsites: 2.0.0 - chalk: 2.4.2 - graceful-fs: 4.2.3 - is-ci: 1.2.1 - jest-message-util: 22.4.3 - mkdirp: 0.5.3 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha512-rfDfG8wyC5pDPNdcnAlZgwKnzHvZDu8Td2NJI/jAGKEGxJPYiE4F0ss/gSAkG4778Y23Hvbz+0GMrDJTeo7RjQ== - /jest-util/23.4.0: - dependencies: - callsites: 2.0.0 - chalk: 2.4.2 - graceful-fs: 4.2.3 - is-ci: 1.2.1 - jest-message-util: 23.4.0 - mkdirp: 0.5.3 - slash: 1.0.0 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE= - /jest-validate/22.4.4: - dependencies: - chalk: 2.4.2 - jest-config: 22.4.4 - jest-get-type: 22.4.3 - leven: 2.1.0 - pretty-format: 22.4.3 - dev: false - resolution: - integrity: sha512-dmlf4CIZRGvkaVg3fa0uetepcua44DHtktHm6rcoNVtYlpwe6fEJRkMFsaUVcFHLzbuBJ2cPw9Gl9TKfnzMVwg== - /jest-validate/23.6.0: - dependencies: - chalk: 2.4.2 - jest-get-type: 22.4.3 - leven: 2.1.0 - pretty-format: 23.6.0 - dev: false - resolution: - integrity: sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A== - /jest-watcher/23.4.0: - dependencies: - ansi-escapes: 3.2.0 - chalk: 2.4.2 - string-length: 2.0.0 - dev: false - resolution: - integrity: sha1-0uKM50+NrWxq/JIrksq+9u0FyRw= - /jest-worker/22.4.3: - dependencies: - merge-stream: 1.0.1 - dev: false - resolution: - integrity: sha512-B1ucW4fI8qVAuZmicFxI1R3kr2fNeYJyvIQ1rKcuLYnenFV5K5aMbxFj6J0i00Ju83S8jP2d7Dz14+AvbIHRYQ== - /jest-worker/23.2.0: - dependencies: - merge-stream: 1.0.1 - dev: false - resolution: - integrity: sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= - /jest/23.6.0: - dependencies: - import-local: 1.0.0 - jest-cli: 23.6.0 - dev: false - engines: - node: '>= 6' - hasBin: true - resolution: - integrity: sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw== - /jju/1.4.0: - dev: false - resolution: - integrity: sha1-o6vicYryQaKykE+EpiWXDzia4yo= - /js-base64/2.5.2: - dev: false - resolution: - integrity: sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ== - /js-tokens/3.0.2: - dev: false - resolution: - integrity: sha1-mGbfOVECEw449/mWvOtlRDIJwls= - /js-tokens/4.0.0: - dev: false - resolution: - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - /js-yaml/3.13.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: false - hasBin: true - resolution: - integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - /jsbn/0.1.1: - dev: false - resolution: - integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - /jsdom/11.11.0: - dependencies: - abab: 1.0.4 - acorn: 5.7.4 - acorn-globals: 4.3.4 - array-equal: 1.0.0 - cssom: 0.3.8 - cssstyle: 0.3.1 - data-urls: 1.1.0 - domexception: 1.0.1 - escodegen: 1.14.1 - html-encoding-sniffer: 1.0.2 - left-pad: 1.3.0 - nwsapi: 2.2.0 - parse5: 4.0.0 - pn: 1.1.0 - request: 2.88.2 - request-promise-native: 1.0.8_request@2.88.2 - sax: 1.2.4 - symbol-tree: 3.2.4 - tough-cookie: 2.5.0 - w3c-hr-time: 1.0.2 - webidl-conversions: 4.0.2 - whatwg-encoding: 1.0.5 - whatwg-mimetype: 2.3.0 - whatwg-url: 6.5.0 - ws: 4.1.0 - xml-name-validator: 3.0.0 - dev: false - resolution: - integrity: sha512-ou1VyfjwsSuWkudGxb03FotDajxAto6USAlmMZjE2lc0jCznt7sBWkhfRBRaWwbnmDqdMSTKTLT5d9sBFkkM7A== - /jsesc/0.5.0: - dev: false - hasBin: true - resolution: - integrity: sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - /jsesc/1.3.0: - dev: false - hasBin: true - resolution: - integrity: sha1-RsP+yMGJKxKwgz25vHYiF226s0s= - /json-parse-better-errors/1.0.2: - dev: false - resolution: - integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - /json-schema-traverse/0.4.1: - dev: false - resolution: - integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - /json-schema/0.2.3: - dev: false - resolution: - integrity: sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - /json-stable-stringify-without-jsonify/1.0.1: - dev: false - resolution: - integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - /json-stable-stringify/1.0.1: - dependencies: - jsonify: 0.0.0 - dev: false - resolution: - integrity: sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - /json-stringify-safe/5.0.1: - dev: false - resolution: - integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - /json3/3.3.3: - dev: false - resolution: - integrity: sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== - /json5/0.5.1: - dev: false - hasBin: true - resolution: - integrity: sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - /json5/1.0.1: - dependencies: - minimist: 1.2.5 - dev: false - hasBin: true - resolution: - integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - /json5/2.1.1: - dependencies: - minimist: 1.2.5 - dev: false - engines: - node: '>=6' - hasBin: true - resolution: - integrity: sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== - /json5/2.1.2: - dependencies: - minimist: 1.2.5 - dev: false - engines: - node: '>=6' - hasBin: true - resolution: - integrity: sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== - /jsonfile/4.0.0: - dev: false - optionalDependencies: - graceful-fs: 4.2.3 - resolution: - integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - /jsonify/0.0.0: - dev: false - resolution: - integrity: sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - /jsprim/1.4.1: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.2.3 - verror: 1.10.0 - dev: false - engines: - '0': node >=0.6.0 - resolution: - integrity: sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - /jsx-ast-utils/2.2.3: - dependencies: - array-includes: 3.1.1 - object.assign: 4.1.0 - dev: false - engines: - node: '>=4.0' - resolution: - integrity: sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA== - /just-debounce/1.0.0: - dev: false - resolution: - integrity: sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= - /killable/1.0.1: - dev: false - resolution: - integrity: sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== - /kind-of/3.2.2: - dependencies: - is-buffer: 1.1.6 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - /kind-of/4.0.0: - dependencies: - is-buffer: 1.1.6 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - /kind-of/5.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - /kind-of/6.0.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - /kleur/2.0.2: - deprecated: 'Please upgrade to kleur@3 or migrate to ''ansi-colors'' if you prefer the old syntax. Visit for migration path(s).' - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ== - /last-run/1.1.1: - dependencies: - default-resolution: 2.0.0 - es6-weak-map: 2.0.3 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-RblpQsF7HHnHchmCWbqUO+v4yls= - /lazystream/1.0.0: - dependencies: - readable-stream: 2.3.7 - dev: false - engines: - node: '>= 0.6.3' - resolution: - integrity: sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= - /lcid/1.0.0: - dependencies: - invert-kv: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - /lcid/2.0.0: - dependencies: - invert-kv: 2.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - /lead/1.0.0: - dependencies: - flush-write-stream: 1.1.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI= - /left-pad/1.3.0: - deprecated: use String.prototype.padStart() - dev: false - resolution: - integrity: sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - /leven/2.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-wuep93IJTe6dNCAq6KzORoeHVYA= - /levn/0.2.5: - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-uo0znQykphDjo/FFucr0iAcVUFQ= - /levn/0.3.0: - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - /liftoff/3.1.0: - dependencies: - extend: 3.0.2 - findup-sync: 3.0.0 - fined: 1.2.0 - flagged-respawn: 1.0.1 - is-plain-object: 2.0.4 - object.map: 1.0.1 - rechoir: 0.6.2 - resolve: 1.15.1 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== - /lines-and-columns/1.1.6: - dev: false - resolution: - integrity: sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - /livereload-js/2.4.0: - dev: false - resolution: - integrity: sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== - /load-json-file/1.1.0: - dependencies: - graceful-fs: 4.2.3 - parse-json: 2.2.0 - pify: 2.3.0 - pinkie-promise: 2.0.1 - strip-bom: 2.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - /load-json-file/4.0.0: - dependencies: - graceful-fs: 4.2.3 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - /loader-runner/2.4.0: - dev: false - engines: - node: '>=4.3.0 <5.0.0 || >=5.10' - resolution: - integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - /loader-utils/0.2.17: - dependencies: - big.js: 3.2.0 - emojis-list: 2.1.0 - json5: 0.5.1 - object-assign: 4.1.1 - dev: false - resolution: - integrity: sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - /loader-utils/1.1.0: - dependencies: - big.js: 3.2.0 - emojis-list: 2.1.0 - json5: 0.5.1 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= - /loader-utils/1.2.3: - dependencies: - big.js: 5.2.2 - emojis-list: 2.1.0 - json5: 1.0.1 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - /locate-path/2.0.0: - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - /locate-path/3.0.0: - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - /lodash._basecopy/3.0.1: - dev: false - resolution: - integrity: sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= - /lodash._basetostring/3.0.1: - dev: false - resolution: - integrity: sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= - /lodash._basevalues/3.0.0: - dev: false - resolution: - integrity: sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= - /lodash._getnative/3.9.1: - dev: false - resolution: - integrity: sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= - /lodash._isiterateecall/3.0.9: - dev: false - resolution: - integrity: sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= - /lodash._reescape/3.0.0: - dev: false - resolution: - integrity: sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= - /lodash._reevaluate/3.0.0: - dev: false - resolution: - integrity: sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= - /lodash._reinterpolate/3.0.0: - dev: false - resolution: - integrity: sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - /lodash._root/3.0.1: - dev: false - resolution: - integrity: sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= - /lodash.assign/4.2.0: - dev: false - resolution: - integrity: sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= - /lodash.camelcase/4.3.0: - dev: false - resolution: - integrity: sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - /lodash.escape/3.2.0: - dependencies: - lodash._root: 3.0.1 - dev: false - resolution: - integrity: sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= - /lodash.get/4.4.2: - dev: false - resolution: - integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= - /lodash.isarguments/3.1.0: - dev: false - resolution: - integrity: sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - /lodash.isarray/3.0.4: - dev: false - resolution: - integrity: sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= - /lodash.isequal/4.5.0: - dev: false - resolution: - integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA= - /lodash.keys/3.1.2: - dependencies: - lodash._getnative: 3.9.1 - lodash.isarguments: 3.1.0 - lodash.isarray: 3.0.4 - dev: false - resolution: - integrity: sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= - /lodash.merge/4.6.2: - dev: false - resolution: - integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - /lodash.restparam/3.6.1: - dev: false - resolution: - integrity: sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - /lodash.sortby/4.7.0: - dev: false - resolution: - integrity: sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - /lodash.template/3.6.2: - dependencies: - lodash._basecopy: 3.0.1 - lodash._basetostring: 3.0.1 - lodash._basevalues: 3.0.0 - lodash._isiterateecall: 3.0.9 - lodash._reinterpolate: 3.0.0 - lodash.escape: 3.2.0 - lodash.keys: 3.1.2 - lodash.restparam: 3.6.1 - lodash.templatesettings: 3.1.1 - dev: false - resolution: - integrity: sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= - /lodash.templatesettings/3.1.1: - dependencies: - lodash._reinterpolate: 3.0.0 - lodash.escape: 3.2.0 - dev: false - resolution: - integrity: sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= - /lodash.unescape/4.0.1: - dev: false - resolution: - integrity: sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= - /lodash/3.6.0: - dev: false - resolution: - integrity: sha1-Umao9J3Zib5Pn2gbbyoMVShdDZo= - /lodash/4.17.15: - dev: false - resolution: - integrity: sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - /loglevel/1.6.7: - dev: false - engines: - node: '>= 0.6.0' - resolution: - integrity: sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A== - /lolex/1.3.2: - dev: false - resolution: - integrity: sha1-fD2mL/yzDw9agKJWbKJORdigHzE= - /long/4.0.0: - dev: false - resolution: - integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - /loose-envify/1.4.0: - dependencies: - js-tokens: 4.0.0 - dev: false - hasBin: true - resolution: - integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - /loud-rejection/1.6.0: - dependencies: - currently-unhandled: 0.4.1 - signal-exit: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - /lower-case/1.1.4: - dev: false - resolution: - integrity: sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - /lru-cache/4.1.5: - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - dev: false - resolution: - integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - /lru-cache/5.1.1: - dependencies: - yallist: 3.1.1 - dev: false - resolution: - integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - /make-dir/2.1.0: - dependencies: - pify: 4.0.1 - semver: 5.7.1 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - /make-dir/3.0.2: - dependencies: - semver: 6.3.0 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== - /make-iterator/1.0.1: - dependencies: - kind-of: 6.0.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw== - /makeerror/1.0.11: - dependencies: - tmpl: 1.0.4 - dev: false - resolution: - integrity: sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - /mamacro/0.0.3: - dev: false - resolution: - integrity: sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== - /map-age-cleaner/0.1.3: - dependencies: - p-defer: 1.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - /map-cache/0.2.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - /map-obj/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - /map-stream/0.0.7: - dev: false - resolution: - integrity: sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= - /map-visit/1.0.0: - dependencies: - object-visit: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - /matchdep/2.0.0: - dependencies: - findup-sync: 2.0.0 - micromatch: 3.1.10 - resolve: 1.15.1 - stack-trace: 0.0.10 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha1-xvNINKDY28OzfCfui7yyfHd1WC4= - /math-random/1.0.4: - dev: false - resolution: - integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - /md5.js/1.3.5: - dependencies: - hash-base: 3.0.4 - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - /media-typer/0.3.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - /mem/1.1.0: - dependencies: - mimic-fn: 1.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - /mem/4.3.0: - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 2.1.0 - p-is-promise: 2.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - /memory-fs/0.4.1: - dependencies: - errno: 0.1.7 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - /memory-fs/0.5.0: - dependencies: - errno: 0.1.7 - readable-stream: 2.3.7 - dev: false - engines: - node: '>=4.3.0 <5.0.0 || >=5.10' - resolution: - integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - /meow/3.7.0: - dependencies: - camelcase-keys: 2.1.0 - decamelize: 1.2.0 - loud-rejection: 1.6.0 - map-obj: 1.0.1 - minimist: 1.2.5 - normalize-package-data: 2.5.0 - object-assign: 4.1.1 - read-pkg-up: 1.0.1 - redent: 1.0.0 - trim-newlines: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - /merge-descriptors/1.0.1: - dev: false - resolution: - integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - /merge-stream/1.0.1: - dependencies: - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - /merge/1.2.1: - dev: false - resolution: - integrity: sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - /merge2/1.0.3: - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-+kT4siYmFaty8ICKQB1HinDjlNs= - /methods/1.1.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - /micromatch/2.3.11: - dependencies: - arr-diff: 2.0.0 - array-unique: 0.2.1 - braces: 1.8.5 - expand-brackets: 0.1.5 - extglob: 0.3.2 - filename-regex: 2.0.1 - is-extglob: 1.0.0 - is-glob: 2.0.1 - kind-of: 3.2.2 - normalize-path: 2.1.1 - object.omit: 2.0.1 - parse-glob: 3.0.4 - regex-cache: 0.4.4 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - /micromatch/3.1.10: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4 - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - /micromatch/4.0.2: - dependencies: - braces: 3.0.2 - picomatch: 2.2.1 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - /miller-rabin/4.0.1: - dependencies: - bn.js: 4.11.8 - brorand: 1.1.0 - dev: false - hasBin: true - resolution: - integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - /mime-db/1.43.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== - /mime-types/2.1.26: - dependencies: - mime-db: 1.43.0 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== - /mime/1.3.4: - dev: false - hasBin: true - resolution: - integrity: sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= - /mime/1.4.1: - dev: false - hasBin: true - resolution: - integrity: sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== - /mime/1.6.0: - dev: false - engines: - node: '>=4' - hasBin: true - resolution: - integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - /mime/2.4.4: - dev: false - engines: - node: '>=4.0.0' - hasBin: true - resolution: - integrity: sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== - /mimic-fn/1.2.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - /mimic-fn/2.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - /minimalistic-assert/1.0.1: - dev: false - resolution: - integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - /minimalistic-crypto-utils/1.0.1: - dev: false - resolution: - integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - /minimatch/2.0.10: - dependencies: - brace-expansion: 1.1.11 - deprecated: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue - dev: false - resolution: - integrity: sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - /minimatch/3.0.4: - dependencies: - brace-expansion: 1.1.11 - dev: false - resolution: - integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - /minimist/0.0.10: - dev: false - resolution: - integrity: sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - /minimist/0.0.8: - dev: false - resolution: - integrity: sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - /minimist/1.2.5: - dev: false - resolution: - integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - /minipass/2.9.0: - dependencies: - safe-buffer: 5.2.0 - yallist: 3.1.1 - dev: false - resolution: - integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - /minizlib/1.3.3: - dependencies: - minipass: 2.9.0 - dev: false - resolution: - integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - /mississippi/3.0.0: - dependencies: - concat-stream: 1.6.2 - duplexify: 3.7.1 - end-of-stream: 1.1.0 - flush-write-stream: 1.1.1 - from2: 2.3.0 - parallel-transform: 1.2.0 - pump: 3.0.0 - pumpify: 1.5.1 - stream-each: 1.2.3 - through2: 2.0.5 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - /mixin-deep/1.3.2: - dependencies: - for-in: 1.0.2 - is-extendable: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - /mkdirp/0.5.1: - dependencies: - minimist: 0.0.8 - deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) - dev: false - hasBin: true - resolution: - integrity: sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - /mkdirp/0.5.3: - dependencies: - minimist: 1.2.5 - deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) - dev: false - hasBin: true - resolution: - integrity: sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg== - /mocha/5.2.0: - dependencies: - browser-stdout: 1.3.1 - commander: 2.15.1 - debug: 3.1.0 - diff: 3.5.0 - escape-string-regexp: 1.0.5 - glob: 7.1.2 - growl: 1.10.5 - he: 1.1.1 - minimatch: 3.0.4 - mkdirp: 0.5.1 - supports-color: 5.4.0 - dev: false - engines: - node: '>= 4.0.0' - hasBin: true - resolution: - integrity: sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== - /move-concurrently/1.0.1: - dependencies: - aproba: 1.2.0 - copy-concurrently: 1.0.5 - fs-write-stream-atomic: 1.0.10 - mkdirp: 0.5.3 - rimraf: 2.7.1 - run-queue: 1.0.3 - dev: false - resolution: - integrity: sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - /ms/0.7.1: - dev: false - resolution: - integrity: sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= - /ms/2.0.0: - dev: false - resolution: - integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - /ms/2.1.1: - dev: false - resolution: - integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - /ms/2.1.2: - dev: false - resolution: - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - /multicast-dns-service-types/1.1.0: - dev: false - resolution: - integrity: sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= - /multicast-dns/6.2.3: - dependencies: - dns-packet: 1.3.1 - thunky: 1.1.0 - dev: false - hasBin: true - resolution: - integrity: sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== - /multipipe/0.1.2: - dependencies: - duplexer2: 0.0.2 - dev: false - resolution: - integrity: sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= - /mute-stdout/1.0.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== - /mute-stream/0.0.7: - dev: false - resolution: - integrity: sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - /mute-stream/0.0.8: - dev: false - resolution: - integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - /mz/2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - dev: false - resolution: - integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - /nan/2.14.0: - dev: false - resolution: - integrity: sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - /nanomatch/1.2.13: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - /natural-compare/1.4.0: - dev: false - resolution: - integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - /negotiator/0.6.2: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - /neo-async/2.6.1: - dev: false - resolution: - integrity: sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - /next-tick/1.0.0: - dev: false - resolution: - integrity: sha1-yobR/ogoFpsBICCOPchCS524NCw= - /nice-try/1.0.5: - dev: false - resolution: - integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - /no-case/2.3.2: - dependencies: - lower-case: 1.1.4 - dev: false - resolution: - integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - /node-addon-api/1.7.1: - dev: false - resolution: - integrity: sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ== - /node-fetch/2.1.2: - dev: false - engines: - node: 4.x || >=6.0.0 - resolution: - integrity: sha1-q4hOjn5X44qUR1POxwb3iNF2i7U= - /node-forge/0.7.6: - dev: false - resolution: - integrity: sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== - /node-forge/0.9.0: - dev: false - engines: - node: '>= 4.5.0' - resolution: - integrity: sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== - /node-gyp/3.8.0: - dependencies: - fstream: 1.0.12 - glob: 7.1.6 - graceful-fs: 4.2.3 - mkdirp: 0.5.3 - nopt: 3.0.6 - npmlog: 4.1.2 - osenv: 0.1.5 - request: 2.88.2 - rimraf: 2.7.1 - semver: 5.3.0 - tar: 2.2.2 - which: 1.3.1 - dev: false - engines: - node: '>= 0.8.0' - hasBin: true - resolution: - integrity: sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== - /node-int64/0.4.0: - dev: false - resolution: - integrity: sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - /node-libs-browser/2.2.1: - dependencies: - assert: 1.5.0 - browserify-zlib: 0.2.0 - buffer: 4.9.2 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - crypto-browserify: 3.12.0 - domain-browser: 1.2.0 - events: 3.1.0 - https-browserify: 1.0.0 - os-browserify: 0.3.0 - path-browserify: 0.0.1 - process: 0.11.10 - punycode: 1.4.1 - querystring-es3: 0.2.1 - readable-stream: 2.3.7 - stream-browserify: 2.0.2 - stream-http: 2.8.3 - string_decoder: 1.3.0 - timers-browserify: 2.0.11 - tty-browserify: 0.0.0 - url: 0.11.0 - util: 0.11.1 - vm-browserify: 1.1.2 - dev: false - resolution: - integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - /node-notifier/5.0.2: - dependencies: - growly: 1.3.0 - semver: 5.7.1 - shellwords: 0.1.1 - which: 1.3.1 - dev: false - resolution: - integrity: sha1-RDhEn+aeMh+UHO+UOYaweXAycBs= - /node-notifier/5.4.3: - dependencies: - growly: 1.3.0 - is-wsl: 1.1.0 - semver: 5.7.1 - shellwords: 0.1.1 - which: 1.3.1 - dev: false - resolution: - integrity: sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== - /node-releases/1.1.52: - dependencies: - semver: 6.3.0 - dev: false - resolution: - integrity: sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== - /node-sass/4.12.0: - dependencies: - async-foreach: 0.1.3 - chalk: 1.1.3 - cross-spawn: 3.0.1 - gaze: 1.1.3 - get-stdin: 4.0.1 - glob: 7.1.6 - in-publish: 2.0.1 - lodash: 4.17.15 - meow: 3.7.0 - mkdirp: 0.5.3 - nan: 2.14.0 - node-gyp: 3.8.0 - npmlog: 4.1.2 - request: 2.88.2 - sass-graph: 2.2.4 - stdout-stream: 1.4.1 - true-case-path: 1.0.3 - dev: false - engines: - node: '>=0.10.0' - hasBin: true - requiresBuild: true - resolution: - integrity: sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ== - /nopt/3.0.6: - dependencies: - abbrev: 1.0.9 - dev: false - hasBin: true - resolution: - integrity: sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - /normalize-package-data/2.5.0: - dependencies: - hosted-git-info: 2.8.8 - resolve: 1.15.1 - semver: 5.7.1 - validate-npm-package-license: 3.0.4 - dev: false - resolution: - integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - /normalize-path/2.1.1: - dependencies: - remove-trailing-separator: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - /normalize-path/3.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - /normalize-range/0.1.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - /now-and-later/2.0.1: - dependencies: - once: 1.4.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ== - /npm-normalize-package-bin/1.0.1: - dev: false - resolution: - integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - /npm-package-arg/6.1.1: - dependencies: - hosted-git-info: 2.8.8 - osenv: 0.1.5 - semver: 5.7.1 - validate-npm-package-name: 3.0.0 - dev: false - resolution: - integrity: sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== - /npm-run-path/2.0.2: - dependencies: - path-key: 2.0.1 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - /npmlog/4.1.2: - dependencies: - are-we-there-yet: 1.1.5 - console-control-strings: 1.1.0 - gauge: 2.7.4 - set-blocking: 2.0.0 - dev: false - resolution: - integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - /nth-check/1.0.2: - dependencies: - boolbase: 1.0.0 - dev: false - resolution: - integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - /num2fraction/1.2.2: - dev: false - resolution: - integrity: sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - /number-is-nan/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - /nwsapi/2.2.0: - dev: false - resolution: - integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - /oauth-sign/0.9.0: - dev: false - resolution: - integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - /object-assign/3.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= - /object-assign/4.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - /object-copy/0.1.0: - dependencies: - copy-descriptor: 0.1.1 - define-property: 0.2.5 - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - /object-inspect/1.7.0: - dev: false - resolution: - integrity: sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== - /object-is/1.0.2: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== - /object-keys/1.1.1: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - /object-visit/1.0.1: - dependencies: - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - /object.assign/4.1.0: - dependencies: - define-properties: 1.1.3 - function-bind: 1.1.1 - has-symbols: 1.0.1 - object-keys: 1.1.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - /object.defaults/1.1.0: - dependencies: - array-each: 1.0.1 - array-slice: 1.1.0 - for-own: 1.0.0 - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= - /object.entries/1.1.1: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - function-bind: 1.1.1 - has: 1.0.3 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== - /object.fromentries/2.0.2: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - function-bind: 1.1.1 - has: 1.0.3 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== - /object.getownpropertydescriptors/2.1.0: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== - /object.map/1.0.1: - dependencies: - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-z4Plncj8wK1fQlDh94s7gb2AHTc= - /object.omit/2.0.1: - dependencies: - for-own: 0.1.5 - is-extendable: 0.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - /object.pick/1.3.0: - dependencies: - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - /object.reduce/1.0.1: - dependencies: - for-own: 1.0.0 - make-iterator: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60= - /object.values/1.1.1: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - function-bind: 1.1.1 - has: 1.0.3 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - /obuf/1.1.2: - dev: false - resolution: - integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - /on-finished/2.3.0: - dependencies: - ee-first: 1.1.1 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - /on-headers/1.0.2: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - /once/1.3.3: - dependencies: - wrappy: 1.0.2 - dev: false - resolution: - integrity: sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA= - /once/1.4.0: - dependencies: - wrappy: 1.0.2 - dev: false - resolution: - integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - /onetime/2.0.1: - dependencies: - mimic-fn: 1.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - /opener/1.5.1: - dev: false - hasBin: true - resolution: - integrity: sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== - /opn/5.2.0: - dependencies: - is-wsl: 1.1.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ== - /opn/5.5.0: - dependencies: - is-wsl: 1.1.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - /optimist/0.6.1: - dependencies: - minimist: 0.0.10 - wordwrap: 0.0.3 - dev: false - resolution: - integrity: sha1-2j6nRob6IaGaERwybpDrFaAZZoY= - /optionator/0.5.0: - dependencies: - deep-is: 0.1.3 - fast-levenshtein: 1.0.7 - levn: 0.2.5 - prelude-ls: 1.1.2 - type-check: 0.3.2 - wordwrap: 0.0.3 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-t1qJlaLUF98ltuTjhi9QqohlE2g= - /optionator/0.8.3: - dependencies: - deep-is: 0.1.3 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.3 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - /orchestrator/0.3.8: - dependencies: - end-of-stream: 0.1.5 - sequencify: 0.0.7 - stream-consume: 0.1.1 - dev: false - resolution: - integrity: sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4= - /ordered-read-streams/1.0.1: - dependencies: - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4= - /original/1.0.2: - dependencies: - url-parse: 1.4.7 - dev: false - resolution: - integrity: sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - /os-browserify/0.3.0: - dev: false - resolution: - integrity: sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - /os-homedir/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - /os-locale/1.4.0: - dependencies: - lcid: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - /os-locale/2.1.0: - dependencies: - execa: 0.7.0 - lcid: 1.0.0 - mem: 1.1.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - /os-locale/3.1.0: - dependencies: - execa: 1.0.0 - lcid: 2.0.0 - mem: 4.3.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - /os-tmpdir/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - /osenv/0.1.5: - dependencies: - os-homedir: 1.0.2 - os-tmpdir: 1.0.2 - dev: false - resolution: - integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - /p-defer/1.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - /p-filter/2.1.0: - dependencies: - p-map: 2.1.0 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== - /p-finally/1.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - /p-is-promise/2.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - /p-limit/1.3.0: - dependencies: - p-try: 1.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - /p-limit/2.2.2: - dependencies: - p-try: 2.2.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== - /p-locate/2.0.0: - dependencies: - p-limit: 1.3.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - /p-locate/3.0.0: - dependencies: - p-limit: 2.2.2 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - /p-map/2.1.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - /p-reflect/2.1.0: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg== - /p-retry/3.0.1: - dependencies: - retry: 0.12.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== - /p-settle/4.0.0: - dependencies: - p-limit: 2.2.2 - p-reflect: 2.1.0 - dev: false - engines: - node: '>=10' - resolution: - integrity: sha512-MK1FEHO70HHo4uCjM2DP/2gOpLGjEes8czFH7bP9RzJS6mAEp7dFINcUUuuQXa+ZFztzKTdF3zl0IiBH1BCkrQ== - /p-try/1.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - /p-try/2.2.0: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - /pako/1.0.11: - dev: false - resolution: - integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - /parallel-transform/1.2.0: - dependencies: - cyclist: 1.0.1 - inherits: 2.0.4 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - /param-case/2.1.1: - dependencies: - no-case: 2.3.2 - dev: false - resolution: - integrity: sha1-35T9jPZTHs915r75oIWPvHK+Ikc= - /parent-module/1.0.1: - dependencies: - callsites: 3.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - /parse-asn1/5.1.5: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - pbkdf2: 3.0.17 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== - /parse-filepath/1.0.2: - dependencies: - is-absolute: 1.0.0 - map-cache: 0.2.2 - path-root: 0.1.1 - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= - /parse-glob/3.0.4: - dependencies: - glob-base: 0.3.0 - is-dotfile: 1.0.3 - is-extglob: 1.0.0 - is-glob: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - /parse-json/2.2.0: - dependencies: - error-ex: 1.3.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - /parse-json/4.0.0: - dependencies: - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - /parse-json/5.0.0: - dependencies: - '@babel/code-frame': 7.8.3 - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 - lines-and-columns: 1.1.6 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== - /parse-node-version/1.0.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - /parse-passwd/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= - /parse5/4.0.0: - dev: false - resolution: - integrity: sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== - /parseurl/1.3.3: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - /pascalcase/0.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - /path-browserify/0.0.1: - dev: false - resolution: - integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - /path-dirname/1.0.2: - dev: false - resolution: - integrity: sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - /path-exists/2.1.0: - dependencies: - pinkie-promise: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - /path-exists/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - /path-is-absolute/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - /path-is-inside/1.0.2: - dev: false - resolution: - integrity: sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - /path-key/2.0.1: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - /path-parse/1.0.6: - dev: false - resolution: - integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - /path-root-regex/0.1.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= - /path-root/0.1.1: - dependencies: - path-root-regex: 0.1.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= - /path-to-regexp/0.1.7: - dev: false - resolution: - integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - /path-type/1.1.0: - dependencies: - graceful-fs: 4.2.3 - pify: 2.3.0 - pinkie-promise: 2.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - /path-type/3.0.0: - dependencies: - pify: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - /pause-stream/0.0.11: - dependencies: - through: 2.3.8 - dev: false - resolution: - integrity: sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - /pbkdf2/3.0.17: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.0 - sha.js: 2.4.11 - dev: false - engines: - node: '>=0.12' - resolution: - integrity: sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== - /performance-now/2.1.0: - dev: false - resolution: - integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - /picomatch/2.2.1: - dev: false - engines: - node: '>=8.6' - resolution: - integrity: sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== - /pidof/1.0.2: - dev: false - resolution: - integrity: sha1-+6Dq4cgzWhHrgJn10PPvvEXLTpA= - /pify/2.3.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - /pify/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - /pify/4.0.1: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - /pinkie-promise/2.0.1: - dependencies: - pinkie: 2.0.4 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ITXW36ejWMBprJsXh3YogihFD/o= - /pinkie/2.0.4: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - /pkg-conf/1.1.3: - dependencies: - find-up: 1.1.2 - load-json-file: 1.1.0 - object-assign: 4.1.1 - symbol: 0.2.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-N45W1v0T6Iv7b0ol33qD+qvduls= - /pkg-dir/2.0.0: - dependencies: - find-up: 2.1.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - /pkg-dir/3.0.0: - dependencies: - find-up: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - /plugin-error/1.0.1: - dependencies: - ansi-colors: 1.1.0 - arr-diff: 4.0.0 - arr-union: 3.1.0 - extend-shallow: 3.0.2 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== - /plugin-log/0.1.0: - dependencies: - chalk: 1.1.3 - dateformat: 1.0.12 - dev: false - engines: - node: '>= 0.9.0' - resolution: - integrity: sha1-hgSc9qsQgzOYqTHzaJy67nteEzM= - /pn/1.1.0: - dev: false - resolution: - integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - /portfinder/1.0.25: - dependencies: - async: 2.6.3 - debug: 3.2.6 - mkdirp: 0.5.3 - dev: false - engines: - node: '>= 0.12.0' - resolution: - integrity: sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== - /posix-character-classes/0.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - /postcss-modules-extract-imports/1.1.0: - dependencies: - postcss: 6.0.23 - dev: false - resolution: - integrity: sha1-thTJcgvmgW6u41+zpfqh26agXds= - /postcss-modules-local-by-default/1.2.0: - dependencies: - css-selector-tokenizer: 0.7.2 - postcss: 6.0.23 - dev: false - resolution: - integrity: sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= - /postcss-modules-scope/1.1.0: - dependencies: - css-selector-tokenizer: 0.7.2 - postcss: 6.0.23 - dev: false - resolution: - integrity: sha1-1upkmUx5+XtipytCb75gVqGUu5A= - /postcss-modules-values/1.3.0: - dependencies: - icss-replace-symbols: 1.1.0 - postcss: 6.0.23 - dev: false - resolution: - integrity: sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= - /postcss-modules/1.3.2: - dependencies: - css-modules-loader-core: 1.1.0 - generic-names: 1.0.3 - lodash.camelcase: 4.3.0 - postcss: 7.0.27 - string-hash: 1.1.3 - dev: false - resolution: - integrity: sha512-QujH5ZpPtr1fBWTKDa43Hx45gm7p19aEtHaAtkMCBZZiB/D5za2wXSMtAf94tDUZHF3F5KZcTXISUNqgEQRiDw== - /postcss-value-parser/4.0.3: - dev: false - resolution: - integrity: sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg== - /postcss/6.0.1: - dependencies: - chalk: 1.1.3 - source-map: 0.5.7 - supports-color: 3.2.3 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha1-AA29H47vIXqjaLmiEsX8QLKo8/I= - /postcss/6.0.23: - dependencies: - chalk: 2.4.2 - source-map: 0.6.1 - supports-color: 5.5.0 - dev: false - engines: - node: '>=4.0.0' - resolution: - integrity: sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - /postcss/7.0.27: - dependencies: - chalk: 2.4.2 - source-map: 0.6.1 - supports-color: 6.1.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== - /postcss/7.0.5: - dependencies: - chalk: 2.4.2 - source-map: 0.6.1 - supports-color: 5.5.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ== - /prelude-ls/1.1.2: - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - /preserve/0.2.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - /pretty-error/2.1.1: - dependencies: - renderkid: 2.0.3 - utila: 0.4.0 - dev: false - resolution: - integrity: sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= - /pretty-format/22.4.3: - dependencies: - ansi-regex: 3.0.0 - ansi-styles: 3.2.1 - dev: false - resolution: - integrity: sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ== - /pretty-format/23.6.0: - dependencies: - ansi-regex: 3.0.0 - ansi-styles: 3.2.1 - dev: false - resolution: - integrity: sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== - /pretty-hrtime/1.0.3: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - /private/0.1.8: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - /process-nextick-args/2.0.1: - dev: false - resolution: - integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - /process/0.11.10: - dev: false - engines: - node: '>= 0.6.0' - resolution: - integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - /progress/2.0.3: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - /promise-inflight/1.0.1: - dev: false - resolution: - integrity: sha1-mEcocL8igTL8vdhoEputEsPAKeM= - /prompts/0.1.14: - dependencies: - kleur: 2.0.2 - sisteransi: 0.1.1 - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w== - /prop-types/15.7.2: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.0 - dev: false - resolution: - integrity: sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - /proxy-addr/2.0.6: - dependencies: - forwarded: 0.1.2 - ipaddr.js: 1.9.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== - /prr/1.0.1: - dev: false - resolution: - integrity: sha1-0/wRS6BplaRexok/SEzrHXj19HY= - /pseudolocale/1.1.0: - dependencies: - commander: 5.0.0 - dev: false - resolution: - integrity: sha512-OZ8I/hwYEJ3beN3IEcNnt8EpcqblH0/x23hulKBXjs+WhTTEle+ijCHCkh2bd+cIIeCuCwSCbBe93IthGG6hLw== - /pseudomap/1.0.2: - dev: false - resolution: - integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - /psl/1.7.0: - dev: false - resolution: - integrity: sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== - /public-encrypt/4.0.3: - dependencies: - bn.js: 4.11.8 - browserify-rsa: 4.0.1 - create-hash: 1.2.0 - parse-asn1: 5.1.5 - randombytes: 2.1.0 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - /pump/2.0.1: - dependencies: - end-of-stream: 1.1.0 - once: 1.4.0 - dev: false - resolution: - integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - /pump/3.0.0: - dependencies: - end-of-stream: 1.1.0 - once: 1.4.0 - dev: false - resolution: - integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - /pumpify/1.5.1: - dependencies: - duplexify: 3.7.1 - inherits: 2.0.4 - pump: 2.0.1 - dev: false - resolution: - integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - /punycode/1.3.2: - dev: false - resolution: - integrity: sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - /punycode/1.4.1: - dev: false - resolution: - integrity: sha1-wNWmOycYgArY4esPpSachN1BhF4= - /punycode/2.1.1: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - /qs/5.1.0: - dev: false - resolution: - integrity: sha1-TZMuXH6kEcynajEtOaYGIA/VDNk= - /qs/5.2.0: - dev: false - resolution: - integrity: sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4= - /qs/6.5.2: - dev: false - engines: - node: '>=0.6' - resolution: - integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - /qs/6.7.0: - dev: false - engines: - node: '>=0.6' - resolution: - integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - /querystring-es3/0.2.1: - dev: false - engines: - node: '>=0.4.x' - resolution: - integrity: sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - /querystring/0.2.0: - dev: false - engines: - node: '>=0.4.x' - resolution: - integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - /querystringify/2.1.1: - dev: false - resolution: - integrity: sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== - /ramda/0.27.0: - dev: false - resolution: - integrity: sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA== - /randomatic/3.1.1: - dependencies: - is-number: 4.0.0 - kind-of: 6.0.3 - math-random: 1.0.4 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - /randombytes/2.1.0: - dependencies: - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - /randomfill/1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - /range-parser/1.0.3: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU= - /range-parser/1.2.1: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - /raw-body/2.1.7: - dependencies: - bytes: 2.4.0 - iconv-lite: 0.4.13 - unpipe: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q= - /raw-body/2.3.3: - dependencies: - bytes: 3.0.0 - http-errors: 1.6.3 - iconv-lite: 0.4.23 - unpipe: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== - /raw-body/2.4.0: - dependencies: - bytes: 3.1.0 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - /react-is/16.13.0: - dev: false - resolution: - integrity: sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== - /read-package-json/2.1.1: - dependencies: - glob: 7.1.6 - json-parse-better-errors: 1.0.2 - normalize-package-data: 2.5.0 - npm-normalize-package-bin: 1.0.1 - dev: false - optionalDependencies: - graceful-fs: 4.2.3 - resolution: - integrity: sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== - /read-package-tree/5.1.6: - dependencies: - debuglog: 1.0.1 - dezalgo: 1.0.3 - once: 1.4.0 - read-package-json: 2.1.1 - readdir-scoped-modules: 1.1.0 - dev: false - resolution: - integrity: sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg== - /read-pkg-up/1.0.1: - dependencies: - find-up: 1.1.2 - read-pkg: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - /read-pkg/1.1.0: - dependencies: - load-json-file: 1.1.0 - normalize-package-data: 2.5.0 - path-type: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - /read-pkg/3.0.0: - dependencies: - load-json-file: 4.0.0 - normalize-package-data: 2.5.0 - path-type: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - /read-yaml-file/1.1.0: - dependencies: - graceful-fs: 4.2.1 - js-yaml: 3.13.1 - pify: 4.0.1 - strip-bom: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA== - /read/1.0.7: - dependencies: - mute-stream: 0.0.8 - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= - /readable-stream/1.1.14: - dependencies: - core-util-is: 1.0.2 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - dev: false - resolution: - integrity: sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - /readable-stream/2.3.7: - dependencies: - core-util-is: 1.0.2 - 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 - dev: false - resolution: - integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - /readable-stream/3.6.0: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - /readdir-scoped-modules/1.1.0: - dependencies: - debuglog: 1.0.1 - dezalgo: 1.0.3 - graceful-fs: 4.2.3 - once: 1.4.0 - dev: false - resolution: - integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - /readdirp/2.2.1: - dependencies: - graceful-fs: 4.2.3 - micromatch: 3.1.10 - readable-stream: 2.3.7 - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - /readdirp/3.3.0: - dependencies: - picomatch: 2.2.1 - dev: false - engines: - node: '>=8.10.0' - resolution: - integrity: sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== - /realpath-native/1.1.0: - dependencies: - util.promisify: 1.0.1 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - /rechoir/0.6.2: - dependencies: - resolve: 1.15.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - /redent/1.0.0: - dependencies: - indent-string: 2.1.0 - strip-indent: 1.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - /regenerate-unicode-properties/8.2.0: - dependencies: - regenerate: 1.4.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - /regenerate/1.4.0: - dev: false - resolution: - integrity: sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - /regenerator-runtime/0.11.1: - dev: false - resolution: - integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - /regex-cache/0.4.4: - dependencies: - is-equal-shallow: 0.1.3 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - /regex-not/1.0.2: - dependencies: - extend-shallow: 3.0.2 - safe-regex: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - /regexp.prototype.flags/1.3.0: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== - /regexpp/2.0.1: - dev: false - engines: - node: '>=6.5.0' - resolution: - integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - /regexpu-core/4.7.0: - dependencies: - regenerate: 1.4.0 - regenerate-unicode-properties: 8.2.0 - regjsgen: 0.5.1 - regjsparser: 0.6.4 - unicode-match-property-ecmascript: 1.0.4 - unicode-match-property-value-ecmascript: 1.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== - /regjsgen/0.5.1: - dev: false - resolution: - integrity: sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== - /regjsparser/0.6.4: - dependencies: - jsesc: 0.5.0 - dev: false - hasBin: true - resolution: - integrity: sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - /relateurl/0.2.7: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - /remove-bom-buffer/3.0.0: - dependencies: - is-buffer: 1.1.6 - is-utf8: 0.2.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ== - /remove-bom-stream/1.2.0: - dependencies: - remove-bom-buffer: 3.0.0 - safe-buffer: 5.2.0 - through2: 2.0.5 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-BfGlk/FuQuH7kOv1nejlaVJflSM= - /remove-trailing-separator/1.1.0: - dev: false - resolution: - integrity: sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - /renderkid/2.0.3: - dependencies: - css-select: 1.2.0 - dom-converter: 0.2.0 - htmlparser2: 3.10.1 - strip-ansi: 3.0.1 - utila: 0.4.0 - dev: false - resolution: - integrity: sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA== - /repeat-element/1.1.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - /repeat-string/1.6.1: - dev: false - engines: - node: '>=0.10' - resolution: - integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc= - /repeating/2.0.1: - dependencies: - is-finite: 1.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - /replace-ext/0.0.1: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= - /replace-ext/1.0.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= - /replace-homedir/1.0.0: - dependencies: - homedir-polyfill: 1.0.3 - is-absolute: 1.0.0 - remove-trailing-separator: 1.1.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw= - /replacestream/4.0.3: - dependencies: - escape-string-regexp: 1.0.5 - object-assign: 4.1.1 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA== - /request-promise-core/1.1.3_request@2.88.2: - dependencies: - lodash: 4.17.15 - request: 2.88.2 - dev: false - engines: - node: '>=0.10.0' - peerDependencies: - request: ^2.34 - resolution: - integrity: sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== - /request-promise-native/1.0.8_request@2.88.2: - dependencies: - request: 2.88.2 - request-promise-core: 1.1.3_request@2.88.2 - stealthy-require: 1.1.1 - tough-cookie: 2.5.0 - dev: false - engines: - node: '>=0.12.0' - peerDependencies: - request: ^2.34 - resolution: - integrity: sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== - /request/2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.9.1 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.3 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.26 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.2 - safe-buffer: 5.2.0 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - deprecated: 'request has been deprecated, see https://github.com/request/request/issues/3142' - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - /require-directory/2.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - /require-main-filename/1.0.1: - dev: false - resolution: - integrity: sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - /require-main-filename/2.0.0: - dev: false - resolution: - integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - /requires-port/1.0.0: - dev: false - resolution: - integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - /resolve-cwd/2.0.0: - dependencies: - resolve-from: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - /resolve-dir/1.0.1: - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= - /resolve-from/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-six699nWiBvItuZTM17rywoYh0g= - /resolve-from/4.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - /resolve-options/1.1.0: - dependencies: - value-or-function: 3.0.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-MrueOcBtZzONyTeMDW1gdFZq0TE= - /resolve-url/0.2.1: - dev: false - resolution: - integrity: sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - /resolve/1.1.7: - dev: false - resolution: - integrity: sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - /resolve/1.12.3: - dependencies: - path-parse: 1.0.6 - dev: false - resolution: - integrity: sha512-hF6+hAPlxjqHWrw4p1rF3Wztbgxd4AjA5VlUzY5zcTb4J8D3JK4/1RjU48pHz2PJWzGVsLB1VWZkvJzhK2CCOA== - /resolve/1.15.1: - dependencies: - path-parse: 1.0.6 - dev: false - resolution: - integrity: sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - /resolve/1.8.1: - dependencies: - path-parse: 1.0.6 - dev: false - resolution: - integrity: sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== - /restore-cursor/2.0.0: - dependencies: - onetime: 2.0.1 - signal-exit: 3.0.2 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - /ret/0.1.15: - dev: false - engines: - node: '>=0.12' - resolution: - integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - /retry/0.12.0: - dev: false - engines: - node: '>= 4' - resolution: - integrity: sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - /rimraf/2.6.3: - dependencies: - glob: 7.1.6 - dev: false - hasBin: true - resolution: - integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - /rimraf/2.7.1: - dependencies: - glob: 7.1.6 - dev: false - hasBin: true - resolution: - integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - /ripemd160/2.0.2: - dependencies: - hash-base: 3.0.4 - inherits: 2.0.4 - dev: false - resolution: - integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - /rsvp/3.6.2: - dev: false - engines: - node: 0.12.* || 4.* || 6.* || >= 7.* - resolution: - integrity: sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== - /run-async/2.4.0: - dependencies: - is-promise: 2.1.0 - dev: false - engines: - node: '>=0.12.0' - resolution: - integrity: sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== - /run-queue/1.0.3: - dependencies: - aproba: 1.2.0 - dev: false - resolution: - integrity: sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - /rxjs/6.5.4: - dependencies: - tslib: 1.11.1 - dev: false - engines: - npm: '>=2.0.0' - resolution: - integrity: sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== - /safe-buffer/5.1.2: - dev: false - resolution: - integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - /safe-buffer/5.2.0: - dev: false - resolution: - integrity: sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - /safe-regex/1.1.0: - dependencies: - ret: 0.1.15 - dev: false - resolution: - integrity: sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - /safer-buffer/2.1.2: - dev: false - resolution: - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - /samsam/1.1.2: - deprecated: This package has been deprecated in favour of @sinonjs/samsam - dev: false - resolution: - integrity: sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc= - /sane/2.5.2: - dependencies: - anymatch: 2.0.0 - capture-exit: 1.2.0 - exec-sh: 0.2.2 - fb-watchman: 2.0.1 - micromatch: 3.1.10 - minimist: 1.2.5 - walker: 1.0.7 - watch: 0.18.0 - dev: false - engines: - node: '>=0.6.0' - hasBin: true - optionalDependencies: - fsevents: 1.2.11 - resolution: - integrity: sha1-tNwYYcIbQn6SlQej51HiosuKs/o= - /sass-graph/2.2.4: - dependencies: - glob: 7.1.6 - lodash: 4.17.15 - scss-tokenizer: 0.2.3 - yargs: 7.1.0 - dev: false - hasBin: true - resolution: - integrity: sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= - /sax/1.2.4: - dev: false - resolution: - integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - /schema-utils/1.0.0: - dependencies: - ajv: 6.12.0 - ajv-errors: 1.0.1_ajv@6.12.0 - ajv-keywords: 3.4.1_ajv@6.12.0 - dev: false - engines: - node: '>= 4' - resolution: - integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - /scss-tokenizer/0.2.3: - dependencies: - js-base64: 2.5.2 - source-map: 0.4.4 - dev: false - resolution: - integrity: sha1-jrBtualyMzOCTT9VMGQRSYR85dE= - /select-hose/2.0.0: - dev: false - resolution: - integrity: sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= - /selfsigned/1.10.7: - dependencies: - node-forge: 0.9.0 - dev: false - resolution: - integrity: sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== - /semver-greatest-satisfied-range/1.1.0: - dependencies: - sver-compat: 1.5.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-E+jCZYq5aRywzXEJMkAoDTb3els= - /semver/5.3.0: - dev: false - hasBin: true - resolution: - integrity: sha1-myzl094C0XxgEq0yaqa00M9U+U8= - /semver/5.7.1: - dev: false - hasBin: true - resolution: - integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - /semver/6.3.0: - dev: false - hasBin: true - resolution: - integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - /send/0.13.2: - dependencies: - debug: 2.2.0 - depd: 1.1.2 - destroy: 1.0.4 - escape-html: 1.0.3 - etag: 1.7.0 - fresh: 0.3.0 - http-errors: 1.3.1 - mime: 1.3.4 - ms: 0.7.1 - on-finished: 2.3.0 - range-parser: 1.0.3 - statuses: 1.2.1 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-dl52B8gFVFK7pvCwUllTUJhgNt4= - /send/0.16.2: - dependencies: - debug: 2.6.9 - depd: 1.1.2 - destroy: 1.0.4 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 1.6.3 - mime: 1.4.1 - ms: 2.0.0 - on-finished: 2.3.0 - range-parser: 1.2.1 - statuses: 1.4.0 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== - /send/0.17.1: - dependencies: - debug: 2.6.9 - depd: 1.1.2 - destroy: 1.0.4 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 1.7.3 - mime: 1.6.0 - ms: 2.1.1 - on-finished: 2.3.0 - range-parser: 1.2.1 - statuses: 1.5.0 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - /sequencify/0.0.7: - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha1-kM/xnQLgcCf9dn9erT57ldHnOAw= - /serialize-javascript/2.1.2: - dev: false - resolution: - integrity: sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== - /serve-index/1.9.1: - dependencies: - accepts: 1.3.7 - batch: 0.6.1 - debug: 2.6.9 - escape-html: 1.0.3 - http-errors: 1.6.3 - mime-types: 2.1.26 - parseurl: 1.3.3 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= - /serve-static/1.13.2: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.16.2 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== - /serve-static/1.14.1: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.17.1 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - /set-blocking/2.0.0: - dev: false - resolution: - integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - /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 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - /setimmediate/1.0.5: - dev: false - resolution: - integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - /setprototypeof/1.1.0: - dev: false - resolution: - integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - /setprototypeof/1.1.1: - dev: false - resolution: - integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - /sha.js/2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.0 - dev: false - hasBin: true - resolution: - integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - /shebang-command/1.2.0: - dependencies: - shebang-regex: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - /shebang-regex/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - /shell-quote/1.7.2: - dev: false - resolution: - integrity: sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - /shellwords/0.1.1: - dev: false - resolution: - integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - /signal-exit/3.0.2: - dev: false - resolution: - integrity: sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - /sinon/1.17.7: - dependencies: - formatio: 1.1.1 - lolex: 1.3.2 - samsam: 1.1.2 - util: 0.12.2 - dev: false - engines: - node: '>=0.1.103' - resolution: - integrity: sha1-RUKk9JugxFwF6y6d2dID4rjv4L8= - /sisteransi/0.1.1: - dev: false - resolution: - integrity: sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g== - /slash/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - /slice-ansi/2.1.0: - dependencies: - ansi-styles: 3.2.1 - astral-regex: 1.0.0 - is-fullwidth-code-point: 2.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - /snapdragon-node/2.1.1: - dependencies: - define-property: 1.0.0 - isobject: 3.0.1 - snapdragon-util: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - /snapdragon-util/3.0.1: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - /snapdragon/0.8.2: - dependencies: - base: 0.11.2 - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - /sockjs-client/1.4.0: - dependencies: - debug: 3.2.6 - eventsource: 1.0.7 - faye-websocket: 0.11.3 - inherits: 2.0.4 - json3: 3.3.3 - url-parse: 1.4.7 - dev: false - resolution: - integrity: sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== - /sockjs/0.3.19: - dependencies: - faye-websocket: 0.10.0 - uuid: 3.4.0 - dev: false - resolution: - integrity: sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== - /sort-keys/3.0.0: - dependencies: - is-plain-obj: 2.1.0 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-77XUKMiZN5LvQXZ9sgWfJza19AvYIDwaDGwGiULM+B5XYru8Z90Oh06JvqDlJczvjjYvssrV0aK1GI6+YXvn5A== - /sort-keys/4.0.0: - dependencies: - is-plain-obj: 2.1.0 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-hlJLzrn/VN49uyNkZ8+9b+0q9DjmmYcYOnbMQtpkLrYpPwRApDPZfmqbUfJnAA3sb/nRib+nDot7Zi/1ER1fuA== - /source-list-map/2.0.1: - dev: false - resolution: - integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - /source-map-resolve/0.5.3: - dependencies: - atob: 2.1.2 - decode-uri-component: 0.2.0 - resolve-url: 0.2.1 - source-map-url: 0.4.0 - urix: 0.1.0 - dev: false - resolution: - integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - /source-map-support/0.4.18: - dependencies: - source-map: 0.5.7 - dev: false - resolution: - integrity: sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - /source-map-support/0.5.16: - dependencies: - buffer-from: 1.1.1 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - /source-map-url/0.4.0: - dev: false - resolution: - integrity: sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - /source-map/0.2.0: - dependencies: - amdefine: 1.0.1 - dev: false - engines: - node: '>=0.8.0' - optional: true - resolution: - integrity: sha1-2rc/vPwrqBm03gO9b26qSBZLP50= - /source-map/0.4.4: - dependencies: - amdefine: 1.0.1 - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha1-66T12pwNyZneaAMti092FzZSA2s= - /source-map/0.5.7: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - /source-map/0.6.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - /sparkles/1.0.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== - /spdx-correct/3.1.0: - dependencies: - spdx-expression-parse: 3.0.0 - spdx-license-ids: 3.0.5 - dev: false - resolution: - integrity: sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== - /spdx-exceptions/2.2.0: - dev: false - resolution: - integrity: sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== - /spdx-expression-parse/3.0.0: - dependencies: - spdx-exceptions: 2.2.0 - spdx-license-ids: 3.0.5 - dev: false - resolution: - integrity: sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - /spdx-license-ids/3.0.5: - dev: false - resolution: - integrity: sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== - /spdy-transport/3.0.0: - dependencies: - debug: 4.1.1 - detect-node: 2.0.4 - hpack.js: 2.1.6 - obuf: 1.1.2 - readable-stream: 3.6.0 - wbuf: 1.7.3 - dev: false - resolution: - integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - /spdy/4.0.1: - dependencies: - debug: 4.1.1 - handle-thing: 2.0.0 - http-deceiver: 1.2.7 - select-hose: 2.0.0 - spdy-transport: 3.0.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== - /split-string/3.1.0: - dependencies: - extend-shallow: 3.0.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - /split/1.0.1: - dependencies: - through: 2.3.8 - dev: false - resolution: - integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - /sprintf-js/1.0.3: - dev: false - resolution: - integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - /sshpk/1.16.1: - dependencies: - asn1: 0.2.4 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 - dev: false - engines: - node: '>=0.10.0' - hasBin: true - resolution: - integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - /ssri/6.0.1: - dependencies: - figgy-pudding: 3.5.1 - dev: false - resolution: - integrity: sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - /stack-trace/0.0.10: - dev: false - resolution: - integrity: sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= - /stack-utils/1.0.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== - /static-extend/0.1.2: - dependencies: - define-property: 0.2.5 - object-copy: 0.1.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - /statuses/1.2.1: - dev: false - resolution: - integrity: sha1-3e1FzBglbVHtQK7BQkidXGECbSg= - /statuses/1.4.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== - /statuses/1.5.0: - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - /stdout-stream/1.4.1: - dependencies: - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== - /stealthy-require/1.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - /stream-browserify/2.0.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - dev: false - resolution: - integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - /stream-combiner/0.2.2: - dependencies: - duplexer: 0.1.1 - through: 2.3.8 - dev: false - resolution: - integrity: sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= - /stream-consume/0.1.1: - dev: false - resolution: - integrity: sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg== - /stream-each/1.2.3: - dependencies: - end-of-stream: 1.1.0 - stream-shift: 1.0.1 - dev: false - resolution: - integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - /stream-exhaust/1.0.2: - dev: false - resolution: - integrity: sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== - /stream-http/2.8.3: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 2.3.7 - to-arraybuffer: 1.0.1 - xtend: 4.0.2 - dev: false - resolution: - integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - /stream-shift/1.0.1: - dev: false - resolution: - integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - /strict-uri-encode/2.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - /string-hash/1.1.3: - dev: false - resolution: - integrity: sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= - /string-length/2.0.0: - dependencies: - astral-regex: 1.0.0 - strip-ansi: 4.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-1A27aGo6zpYMHP/KVivyxF+DY+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: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - /string-width/2.1.1: - dependencies: - is-fullwidth-code-point: 2.0.0 - strip-ansi: 4.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - /string-width/3.1.0: - dependencies: - emoji-regex: 7.0.3 - is-fullwidth-code-point: 2.0.0 - strip-ansi: 5.2.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - /string.prototype.trimleft/2.1.1: - dependencies: - define-properties: 1.1.3 - function-bind: 1.1.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== - /string.prototype.trimright/2.1.1: - dependencies: - define-properties: 1.1.3 - function-bind: 1.1.1 - dev: false - engines: - node: '>= 0.4' - resolution: - integrity: sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== - /string_decoder/0.10.31: - dev: false - resolution: - integrity: sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - /string_decoder/1.1.1: - dependencies: - safe-buffer: 5.1.2 - dev: false - resolution: - integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - /string_decoder/1.3.0: - dependencies: - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - /strip-ansi/3.0.1: - dependencies: - ansi-regex: 2.1.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - /strip-ansi/4.0.0: - dependencies: - ansi-regex: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8= - /strip-ansi/5.2.0: - dependencies: - ansi-regex: 4.1.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - /strip-bom/2.0.0: - dependencies: - is-utf8: 0.2.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - /strip-bom/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - /strip-bom/4.0.0: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - /strip-eof/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - /strip-indent/1.0.1: - dependencies: - get-stdin: 4.0.1 - dev: false - engines: - node: '>=0.10.0' - hasBin: true - resolution: - integrity: sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - /strip-json-comments/3.0.1: - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - /subarg/1.0.0: - dependencies: - minimist: 1.2.5 - dev: false - resolution: - integrity: sha1-9izxdYHplrSPyWVpn1TAauJouNI= - /sudo/1.0.3: - dependencies: - inpath: 1.0.2 - pidof: 1.0.2 - read: 1.0.7 - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-zPKGaRIPi3T4K4Rt/38clRIO/yA= - /supports-color/2.0.0: - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - /supports-color/3.2.3: - dependencies: - has-flag: 1.0.0 - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= - /supports-color/5.4.0: - dependencies: - has-flag: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== - /supports-color/5.5.0: - dependencies: - has-flag: 3.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - /supports-color/6.1.0: - dependencies: - has-flag: 3.0.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - /sver-compat/1.5.0: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - dev: false - resolution: - integrity: sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg= - /symbol-tree/3.2.4: - dev: false - resolution: - integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - /symbol/0.2.3: - dev: false - resolution: - integrity: sha1-O5hzuKkB5Hxu/iFSajrDcu8ou8c= - /table/5.4.6: - dependencies: - ajv: 6.12.0 - lodash: 4.17.15 - slice-ansi: 2.1.0 - string-width: 3.1.0 - dev: false - engines: - node: '>=6.0.0' - resolution: - integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - /tapable/1.1.3: - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - /tar/2.2.2: - dependencies: - block-stream: 0.0.9 - fstream: 1.0.12 - inherits: 2.0.4 - dev: false - resolution: - integrity: sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== - /tar/4.4.13: - dependencies: - chownr: 1.1.4 - fs-minipass: 1.2.7 - minipass: 2.9.0 - minizlib: 1.3.3 - mkdirp: 0.5.3 - safe-buffer: 5.2.0 - yallist: 3.1.1 - dev: false - engines: - node: '>=4.5' - resolution: - integrity: sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - /ternary-stream/2.1.1: - dependencies: - duplexify: 3.7.1 - fork-stream: 0.0.4 - merge-stream: 1.0.1 - through2: 2.0.5 - dev: false - engines: - node: '>= 0.10.0' - resolution: - integrity: sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw== - /terser-webpack-plugin/1.4.3_webpack@4.31.0: - dependencies: - cacache: 12.0.3 - find-cache-dir: 2.1.0 - is-wsl: 1.1.0 - schema-utils: 1.0.0 - serialize-javascript: 2.1.2 - source-map: 0.6.1 - terser: 4.6.7 - webpack: 4.31.0_webpack@4.31.0 - webpack-sources: 1.4.3 - worker-farm: 1.7.0 - dev: false - engines: - node: '>= 6.9.0' - peerDependencies: - webpack: ^4.0.0 - resolution: - integrity: sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== - /terser/4.6.7: - dependencies: - commander: 2.20.3 - source-map: 0.6.1 - source-map-support: 0.5.16 - dev: false - engines: - node: '>=6.0.0' - hasBin: true - resolution: - integrity: sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g== - /test-exclude/4.2.3: - dependencies: - arrify: 1.0.1 - micromatch: 2.3.11 - object-assign: 4.1.1 - read-pkg-up: 1.0.1 - require-main-filename: 1.0.1 - dev: false - resolution: - integrity: sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA== - /text-table/0.2.0: - dev: false - resolution: - integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - /textextensions/1.0.2: - dev: false - resolution: - integrity: sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI= - /thenify-all/1.6.0: - dependencies: - thenify: 3.3.0 - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - /thenify/3.3.0: - dependencies: - any-promise: 1.3.0 - dev: false - resolution: - integrity: sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= - /throat/4.1.0: - dev: false - resolution: - integrity: sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= - /through/2.3.8: - dev: false - resolution: - integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - /through2-filter/3.0.0: - dependencies: - through2: 2.0.5 - xtend: 4.0.2 - dev: false - resolution: - integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA== - /through2/2.0.5: - dependencies: - readable-stream: 2.3.7 - xtend: 4.0.2 - dev: false - resolution: - integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - /thunky/1.1.0: - dev: false - resolution: - integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - /time-stamp/1.1.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= - /timers-browserify/2.0.11: - dependencies: - setimmediate: 1.0.5 - dev: false - engines: - node: '>=0.6.0' - resolution: - integrity: sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== - /timsort/0.3.0: - dev: false - resolution: - integrity: sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - /tiny-lr/0.2.1: - dependencies: - body-parser: 1.14.2 - debug: 2.2.0 - faye-websocket: 0.10.0 - livereload-js: 2.4.0 - parseurl: 1.3.3 - qs: 5.1.0 - dev: false - resolution: - integrity: sha1-s/26gC5dVqM8L28QeUsy5Hescp0= - /tmp/0.0.33: - dependencies: - os-tmpdir: 1.0.2 - dev: false - engines: - node: '>=0.6.0' - resolution: - integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - /tmpl/1.0.4: - dev: false - resolution: - integrity: sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= - /to-absolute-glob/2.0.2: - dependencies: - is-absolute: 1.0.0 - is-negated-glob: 1.0.0 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-GGX0PZ50sIItufFFt4z/fQ98hJs= - /to-arraybuffer/1.0.1: - dev: false - resolution: - integrity: sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - /to-fast-properties/1.0.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - /to-object-path/0.3.0: - dependencies: - kind-of: 3.2.2 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - /to-regex-range/2.1.1: - dependencies: - is-number: 3.0.0 - repeat-string: 1.6.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - /to-regex-range/5.0.1: - dependencies: - is-number: 7.0.0 - dev: false - engines: - node: '>=8.0' - resolution: - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - /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 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - /to-through/2.0.0: - dependencies: - through2: 2.0.5 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY= - /toidentifier/1.0.0: - dev: false - engines: - node: '>=0.6' - resolution: - integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - /toposort/1.0.7: - dev: false - resolution: - integrity: sha1-LmhELZ9k7HILjMieZEOsbKqVACk= - /tough-cookie/2.5.0: - dependencies: - psl: 1.7.0 - punycode: 2.1.1 - dev: false - engines: - node: '>=0.8' - resolution: - integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - /tr46/1.0.1: - dependencies: - punycode: 2.1.1 - dev: false - resolution: - integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - /trim-newlines/1.0.0: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-WIeWa7WCpFA6QetST301ARgVphM= - /trim-right/1.0.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - /true-case-path/1.0.3: - dependencies: - glob: 7.1.6 - dev: false - resolution: - integrity: sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== - /true-case-path/2.2.1: - dev: false - resolution: - integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== - /tryer/1.0.1: - dev: false - resolution: - integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== - /ts-jest/22.4.6_jest@23.6.0: - dependencies: - babel-core: 6.26.3 - babel-plugin-istanbul: 4.1.6 - babel-plugin-transform-es2015-modules-commonjs: 6.26.2 - babel-preset-jest: 22.4.4 - cpx: 1.5.0 - fs-extra: 6.0.0 - jest: 23.6.0 - jest-config: 22.4.4 - lodash: 4.17.15 - pkg-dir: 2.0.0 - source-map-support: 0.5.16 - typescript: 3.0.3 - yargs: 11.1.1 - dev: false - peerDependencies: - jest: ^22.4.0 || ^22.5.0-alpha.1 || ^23.0.0-alpha.1 - resolution: - integrity: sha512-kYQ6g1G1AU+bOO9rv+SSQXg4WTcni6Wx3AM48iHni0nP1vIuhdNRjKTE9Cxx36Ix/IOV7L85iKu07dgXJzH2pQ== - /ts-loader/6.0.0: - dependencies: - chalk: 2.4.2 - enhanced-resolve: 4.1.1 - loader-utils: 1.2.3 - micromatch: 4.0.2 - semver: 6.3.0 - typescript: 3.0.3 - dev: false - engines: - node: '>=8.6' - resolution: - integrity: sha512-lszy+D41R0Te2+loZxADWS+E1+Z55A+i3dFfFie1AZHL++65JRKVDBPQgeWgRrlv5tbxdU3zOtXp8b7AFR6KEg== - /tslib/1.11.1: - dev: false - resolution: - integrity: sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - /tslint-microsoft-contrib/5.2.1_tslint@5.12.1: - dependencies: - tslint: 5.12.1 - tsutils: 2.28.0_typescript@3.0.3 - typescript: 3.0.3 - dev: false - peerDependencies: - tslint: ^5.1.0 - resolution: - integrity: sha512-PDYjvpo0gN9IfMULwKk0KpVOPMhU6cNoT9VwCOLeDl/QS8v8W2yspRpFFuUS7/c5EIH/n8ApMi8TxJAz1tfFUA== - /tslint/5.12.1: - dependencies: - babel-code-frame: 6.26.0 - builtin-modules: 1.1.1 - chalk: 2.4.2 - commander: 2.20.3 - diff: 3.5.0 - glob: 7.1.6 - js-yaml: 3.13.1 - minimatch: 3.0.4 - resolve: 1.15.1 - semver: 5.7.1 - tslib: 1.11.1 - tsutils: 2.29.0_typescript@3.0.3 - typescript: 3.0.3 - dev: false - engines: - node: '>=4.8.0' - hasBin: true - resolution: - integrity: sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw== - /tsutils/2.28.0_typescript@3.0.3: - dependencies: - tslib: 1.11.1 - typescript: 3.0.3 - dev: false - 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' - resolution: - integrity: sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA== - /tsutils/2.29.0_typescript@3.0.3: - dependencies: - tslib: 1.11.1 - typescript: 3.0.3 - dev: false - 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' - resolution: - integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - /tsutils/3.17.1_typescript@3.5.3: - dependencies: - tslib: 1.11.1 - typescript: 3.5.3 - dev: false - 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' - resolution: - integrity: sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - /tty-browserify/0.0.0: - dev: false - resolution: - integrity: sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - /tunnel-agent/0.6.0: - dependencies: - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - /tweetnacl/0.14.5: - dev: false - resolution: - integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - /type-check/0.3.2: - dependencies: - prelude-ls: 1.1.2 - dev: false - engines: - node: '>= 0.8.0' - resolution: - integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - /type-detect/0.1.1: - dev: false - resolution: - integrity: sha1-C6XsKohWQORw6k6FBZcZANrFiCI= - /type-detect/1.0.0: - dev: false - resolution: - integrity: sha1-diIXzAbbJY7EiQihKY6LlRIejqI= - /type-is/1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.26 - dev: false - engines: - node: '>= 0.6' - resolution: - integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - /type/1.2.0: - dev: false - resolution: - integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - /type/2.0.0: - dev: false - resolution: - integrity: sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== - /typedarray/0.0.6: - dev: false - resolution: - integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - /typescript/2.4.2: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ= - /typescript/2.7.2: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw== - /typescript/2.8.4: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-IIU5cN1mR5J3z9jjdESJbnxikTrEz3lzAw/D0Tf45jHpBp55nY31UkUvmVHoffCfKHTqJs3fCLPDxknQTTFegQ== - /typescript/2.9.2: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== - /typescript/3.0.3: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg== - /typescript/3.1.6: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== - /typescript/3.2.4: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== - /typescript/3.3.4000: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA== - /typescript/3.4.5: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== - /typescript/3.5.3: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== - /typescript/3.6.5: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ== - /typescript/3.7.5: - dev: false - engines: - node: '>=4.2.0' - hasBin: true - resolution: - integrity: sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== - /uglify-js/3.0.28: - dependencies: - commander: 2.11.0 - source-map: 0.5.7 - dev: false - engines: - node: '>=0.8.0' - hasBin: true - resolution: - integrity: sha512-0h/qGay016GG2lVav3Kz174F3T2Vjlz2v6HCt+WDQpoXfco0hWwF5gHK9yh88mUYvIC+N7Z8NT8WpjSp1yoqGA== - /uglify-js/3.4.10: - dependencies: - commander: 2.19.0 - source-map: 0.6.1 - dev: false - engines: - node: '>=0.8.0' - hasBin: true - resolution: - integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== - /uglify-js/3.8.0: - dependencies: - commander: 2.20.3 - source-map: 0.6.1 - dev: false - engines: - node: '>=0.8.0' - hasBin: true - optional: true - resolution: - integrity: sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ== - /unc-path-regex/0.1.2: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-5z3T17DXxe2G+6xrCufYxqadUPo= - /undertaker-registry/1.0.1: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-XkvaMI5KiirlhPm5pDWaSZglzFA= - /undertaker/1.2.1: - dependencies: - arr-flatten: 1.1.0 - arr-map: 2.0.2 - bach: 1.2.0 - collection-map: 1.0.0 - es6-weak-map: 2.0.3 - last-run: 1.1.1 - object.defaults: 1.1.0 - object.reduce: 1.0.1 - undertaker-registry: 1.0.1 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA== - /unicode-canonical-property-names-ecmascript/1.0.4: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - /unicode-match-property-ecmascript/1.0.4: - dependencies: - unicode-canonical-property-names-ecmascript: 1.0.4 - unicode-property-aliases-ecmascript: 1.1.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - /unicode-match-property-value-ecmascript/1.2.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - /unicode-property-aliases-ecmascript/1.1.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - /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 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - /unique-filename/1.1.1: - dependencies: - unique-slug: 2.0.2 - dev: false - resolution: - integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - /unique-slug/2.0.2: - dependencies: - imurmurhash: 0.1.4 - dev: false - resolution: - integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - /unique-stream/2.3.1: - dependencies: - json-stable-stringify-without-jsonify: 1.0.1 - through2-filter: 3.0.0 - dev: false - resolution: - integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A== - /universalify/0.1.2: - dev: false - engines: - node: '>= 4.0.0' - resolution: - integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - /unpipe/1.0.0: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - /unset-value/1.0.0: - dependencies: - has-value: 0.3.1 - isobject: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - /upath/1.2.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - /upper-case/1.1.3: - dev: false - resolution: - integrity: sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= - /uri-js/4.2.2: - dependencies: - punycode: 2.1.1 - dev: false - resolution: - integrity: sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - /urix/0.1.0: - dev: false - resolution: - integrity: sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - /url-parse/1.4.7: - dependencies: - querystringify: 2.1.1 - requires-port: 1.0.0 - dev: false - resolution: - integrity: sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== - /url/0.11.0: - dependencies: - punycode: 1.3.2 - querystring: 0.2.0 - dev: false - resolution: - integrity: sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - /use/3.1.1: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - /util-deprecate/1.0.2: - dev: false - resolution: - integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - /util.promisify/1.0.0: - dependencies: - define-properties: 1.1.3 - object.getownpropertydescriptors: 2.1.0 - dev: false - resolution: - integrity: sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - /util.promisify/1.0.1: - dependencies: - define-properties: 1.1.3 - es-abstract: 1.17.4 - has-symbols: 1.0.1 - object.getownpropertydescriptors: 2.1.0 - dev: false - resolution: - integrity: sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - /util/0.10.3: - dependencies: - inherits: 2.0.1 - dev: false - resolution: - integrity: sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - /util/0.11.1: - dependencies: - inherits: 2.0.3 - dev: false - resolution: - integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - /util/0.12.2: - dependencies: - inherits: 2.0.4 - is-arguments: 1.0.4 - is-generator-function: 1.0.7 - safe-buffer: 5.2.0 - dev: false - resolution: - integrity: sha512-XE+MkWQvglYa+IOfBt5UFG93EmncEMP23UqpgDvVZVFBPxwmkK10QRp6pgU4xICPnWRf/t0zPv4noYSUq9gqUQ== - /utila/0.4.0: - dev: false - resolution: - integrity: sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - /utils-merge/1.0.1: - dev: false - engines: - node: '>= 0.4.0' - resolution: - integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - /uuid/3.4.0: - dev: false - hasBin: true - resolution: - integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - /v8-compile-cache/2.0.3: - dev: false - resolution: - integrity: sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== - /v8-compile-cache/2.1.0: - dev: false - resolution: - integrity: sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== - /v8flags/3.1.3: - dependencies: - homedir-polyfill: 1.0.3 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w== - /validate-npm-package-license/3.0.4: - dependencies: - spdx-correct: 3.1.0 - spdx-expression-parse: 3.0.0 - dev: false - resolution: - integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - /validate-npm-package-name/3.0.0: - dependencies: - builtins: 1.0.3 - dev: false - resolution: - integrity: sha1-X6kS2B630MdK/BQN5zF/DKffQ34= - /validator/8.2.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== - /value-or-function/3.0.0: - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= - /vary/1.1.2: - dev: false - engines: - node: '>= 0.8' - resolution: - integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - /verror/1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 - dev: false - engines: - '0': node >=0.6.0 - resolution: - integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - /vinyl-fs/3.0.3: - dependencies: - fs-mkdirp-stream: 1.0.0 - glob-stream: 6.1.0 - graceful-fs: 4.2.3 - is-valid-glob: 1.0.0 - lazystream: 1.0.0 - lead: 1.0.0 - object.assign: 4.1.0 - pumpify: 1.5.1 - readable-stream: 2.3.7 - remove-bom-buffer: 3.0.0 - remove-bom-stream: 1.2.0 - resolve-options: 1.1.0 - through2: 2.0.5 - to-through: 2.0.0 - value-or-function: 3.0.0 - vinyl: 2.2.0 - vinyl-sourcemap: 1.1.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== - /vinyl-sourcemap/1.1.0: - dependencies: - append-buffer: 1.0.2 - convert-source-map: 1.7.0 - graceful-fs: 4.2.3 - normalize-path: 2.1.1 - now-and-later: 2.0.1 - remove-bom-buffer: 3.0.0 - vinyl: 2.2.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY= - /vinyl/0.5.3: - dependencies: - clone: 1.0.4 - clone-stats: 0.0.1 - replace-ext: 0.0.1 - dev: false - engines: - node: '>= 0.9' - resolution: - integrity: sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= - /vinyl/2.2.0: - dependencies: - clone: 2.1.2 - clone-buffer: 1.0.0 - clone-stats: 1.0.0 - cloneable-readable: 1.1.3 - remove-trailing-separator: 1.1.0 - replace-ext: 1.0.0 - dev: false - engines: - node: '>= 0.10' - resolution: - integrity: sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg== - /vm-browserify/1.1.2: - dev: false - resolution: - integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - /w3c-hr-time/1.0.2: - dependencies: - browser-process-hrtime: 1.0.0 - dev: false - resolution: - integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - /walker/1.0.7: - dependencies: - makeerror: 1.0.11 - dev: false - resolution: - integrity: sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - /watch/0.18.0: - dependencies: - exec-sh: 0.2.2 - minimist: 1.2.5 - dev: false - engines: - node: '>=0.1.95' - hasBin: true - resolution: - integrity: sha1-KAlUdsbffJDJYxOJkMClQj60uYY= - /watchpack/1.6.0: - dependencies: - chokidar: 2.1.8 - graceful-fs: 4.2.3 - neo-async: 2.6.1 - dev: false - resolution: - integrity: sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== - /wbuf/1.7.3: - dependencies: - minimalistic-assert: 1.0.1 - dev: false - resolution: - integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - /webidl-conversions/4.0.2: - dev: false - resolution: - integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - /webpack-bundle-analyzer/3.6.1: - dependencies: - acorn: 7.1.1 - acorn-walk: 7.1.1 - bfj: 6.1.2 - chalk: 2.4.2 - commander: 2.20.3 - ejs: 2.7.4 - express: 4.17.1 - filesize: 3.6.1 - gzip-size: 5.1.1 - lodash: 4.17.15 - mkdirp: 0.5.3 - opener: 1.5.1 - ws: 6.2.1 - dev: false - engines: - node: '>= 6.14.4' - hasBin: true - resolution: - integrity: sha512-Nfd8HDwfSx1xBwC+P8QMGvHAOITxNBSvu/J/mCJvOwv+G4VWkU7zir9SSenTtyCi0LnVtmsc7G5SZo1uV+bxRw== - /webpack-cli/3.3.11_webpack@4.31.0: - dependencies: - chalk: 2.4.2 - cross-spawn: 6.0.5 - enhanced-resolve: 4.1.0 - findup-sync: 3.0.0 - global-modules: 2.0.0 - import-local: 2.0.0 - interpret: 1.2.0 - loader-utils: 1.2.3 - supports-color: 6.1.0 - v8-compile-cache: 2.0.3 - webpack: 4.31.0_webpack@4.31.0 - yargs: 13.2.4 - dev: false - engines: - node: '>=6.11.5' - hasBin: true - peerDependencies: - webpack: 4.x.x - resolution: - integrity: sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g== - /webpack-dev-middleware/3.7.2_webpack@4.31.0: - dependencies: - memory-fs: 0.4.1 - mime: 2.4.4 - mkdirp: 0.5.3 - range-parser: 1.2.1 - webpack: 4.31.0_webpack@4.31.0 - webpack-log: 2.0.0 - dev: false - engines: - node: '>= 6' - peerDependencies: - webpack: ^4.0.0 - resolution: - integrity: sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== - /webpack-dev-server/3.9.0_webpack@4.31.0: - dependencies: - ansi-html: 0.0.7 - bonjour: 3.5.0 - chokidar: 2.1.8 - compression: 1.7.4 - connect-history-api-fallback: 1.6.0 - debug: 4.1.1 - del: 4.1.1 - express: 4.17.1 - html-entities: 1.2.1 - http-proxy-middleware: 0.19.1 - import-local: 2.0.0 - internal-ip: 4.3.0 - ip: 1.1.5 - is-absolute-url: 3.0.3 - killable: 1.0.1 - loglevel: 1.6.7 - opn: 5.5.0 - p-retry: 3.0.1 - portfinder: 1.0.25 - schema-utils: 1.0.0 - selfsigned: 1.10.7 - semver: 6.3.0 - serve-index: 1.9.1 - sockjs: 0.3.19 - sockjs-client: 1.4.0 - spdy: 4.0.1 - strip-ansi: 3.0.1 - supports-color: 6.1.0 - url: 0.11.0 - webpack: 4.31.0_webpack@4.31.0 - webpack-dev-middleware: 3.7.2_webpack@4.31.0 - webpack-log: 2.0.0 - ws: 6.2.1 - yargs: 12.0.5 - dev: false - engines: - node: '>= 6.11.5' - hasBin: true - peerDependencies: - webpack: ^4.0.0 - resolution: - integrity: sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw== - /webpack-log/2.0.0: - dependencies: - ansi-colors: 3.2.4 - uuid: 3.4.0 - dev: false - engines: - node: '>= 6' - resolution: - integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - /webpack-sources/1.4.3: - dependencies: - source-list-map: 2.0.1 - source-map: 0.6.1 - dev: false - resolution: - integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - /webpack/4.31.0_webpack@4.31.0: - dependencies: - '@webassemblyjs/ast': 1.8.5 - '@webassemblyjs/helper-module-context': 1.8.5 - '@webassemblyjs/wasm-edit': 1.8.5 - '@webassemblyjs/wasm-parser': 1.8.5 - acorn: 6.4.1 - acorn-dynamic-import: 4.0.0_acorn@6.4.1 - ajv: 6.12.0 - ajv-keywords: 3.4.1_ajv@6.12.0 - chrome-trace-event: 1.0.2 - enhanced-resolve: 4.1.1 - eslint-scope: 4.0.3 - json-parse-better-errors: 1.0.2 - loader-runner: 2.4.0 - loader-utils: 1.2.3 - memory-fs: 0.4.1 - micromatch: 3.1.10 - mkdirp: 0.5.3 - neo-async: 2.6.1 - node-libs-browser: 2.2.1 - schema-utils: 1.0.0 - tapable: 1.1.3 - terser-webpack-plugin: 1.4.3_webpack@4.31.0 - watchpack: 1.6.0 - webpack-sources: 1.4.3 - dev: false - engines: - node: '>=6.11.5' - hasBin: true - peerDependencies: - webpack: '*' - resolution: - integrity: sha512-n6RVO3X0LbbipoE62akME9K/JI7qYrwwufs20VvgNNpqUoH4860KkaxJTbGq5bgkVZF9FqyyTG/0WPLH3PVNJA== - /websocket-driver/0.7.3: - dependencies: - http-parser-js: 0.4.10 - safe-buffer: 5.2.0 - websocket-extensions: 0.1.3 - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== - /websocket-extensions/0.1.3: - dev: false - engines: - node: '>=0.8.0' - resolution: - integrity: sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== - /whatwg-encoding/1.0.5: - dependencies: - iconv-lite: 0.4.24 - dev: false - resolution: - integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - /whatwg-mimetype/2.3.0: - dev: false - resolution: - integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - /whatwg-url/6.5.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - dev: false - resolution: - integrity: sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== - /whatwg-url/7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - dev: false - resolution: - integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - /which-module/1.0.0: - dev: false - resolution: - integrity: sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= - /which-module/2.0.0: - dev: false - resolution: - integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - /which/1.3.1: - dependencies: - isexe: 2.0.0 - dev: false - hasBin: true - resolution: - integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - /wide-align/1.1.3: - dependencies: - string-width: 1.0.2 - dev: false - resolution: - integrity: sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - /window-size/0.2.0: - dev: false - engines: - node: '>= 0.10.0' - hasBin: true - resolution: - integrity: sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= - /word-wrap/1.2.3: - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - /wordwrap/0.0.3: - dev: false - engines: - node: '>=0.4.0' - resolution: - integrity: sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - /wordwrap/1.0.0: - dev: false - resolution: - integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - /worker-farm/1.7.0: - dependencies: - errno: 0.1.7 - dev: false - resolution: - integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - /wrap-ansi/2.1.0: - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - dev: false - engines: - node: '>=0.10.0' - resolution: - integrity: sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - /wrap-ansi/5.1.0: - dependencies: - ansi-styles: 3.2.1 - string-width: 3.1.0 - strip-ansi: 5.2.0 - dev: false - engines: - node: '>=6' - resolution: - integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - /wrappy/1.0.2: - dev: false - resolution: - integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - /write-file-atomic/2.4.3: - dependencies: - graceful-fs: 4.2.3 - imurmurhash: 0.1.4 - signal-exit: 3.0.2 - dev: false - resolution: - integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - /write-json-file/4.0.0: - dependencies: - detect-indent: 6.0.0 - graceful-fs: 4.2.3 - make-dir: 3.0.2 - sort-keys: 3.0.0 - write-file-atomic: 2.4.3 - dev: false - engines: - node: '>=8' - resolution: - integrity: sha512-ak8Ww3Me8G9jD1XcFyXV4HTX0HGISBrJu09JYx/v+WINBOdJAge7wVH1BGhOnJxaFM1ufUevjlrrgiZz8Vwj7w== - /write-json5-file/2.1.2: - dependencies: - graceful-fs: 4.2.3 - json5: 2.1.2 - make-dir: 3.0.2 - sort-keys: 4.0.0 - write-file-atomic: 2.4.3 - dev: false - engines: - node: '>=8.15' - resolution: - integrity: sha512-4LUqyx4CwxVDLEbp83IF6s+3VHduw3PvDYowgbjPLJeD3bVt+vtnLfR4FbbPu7lCs9LSoqwDwGfnzhe/fJyACQ== - /write-yaml-file/3.0.1: - dependencies: - graceful-fs: 4.2.3 - js-yaml: 3.13.1 - make-dir: 3.0.2 - pify: 4.0.1 - write-file-atomic: 2.4.3 - dev: false - engines: - node: '>=8.15' - resolution: - integrity: sha512-OHzbrlgjw/K/BAH6LdEOcSQFz5nkk0I/25CjKLIVFvcg2Ej7+QE/GTnitgqWnhlsdghor7OV5gfttQPGogQ1XA== - /write/1.0.3: - dependencies: - mkdirp: 0.5.3 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - /ws/4.1.0: - dependencies: - async-limiter: 1.0.1 - safe-buffer: 5.1.2 - dev: false - resolution: - integrity: sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA== - /ws/6.2.1: - dependencies: - async-limiter: 1.0.1 - dev: false - resolution: - integrity: sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - /xml-name-validator/3.0.0: - dev: false - resolution: - integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - /xml/1.0.1: - dev: false - resolution: - integrity: sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= - /xmldoc/1.1.2: - dependencies: - sax: 1.2.4 - dev: false - resolution: - integrity: sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ== - /xtend/4.0.2: - dev: false - engines: - node: '>=0.4' - resolution: - integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - /y18n/3.2.1: - dev: false - resolution: - integrity: sha1-bRX7qITAhnnA136I53WegR4H+kE= - /y18n/4.0.0: - dev: false - resolution: - integrity: sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - /yallist/2.1.2: - dev: false - resolution: - integrity: sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - /yallist/3.1.1: - dev: false - resolution: - integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - /yargs-parser/11.1.1: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - dev: false - resolution: - integrity: sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - /yargs-parser/13.1.2: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - dev: false - resolution: - integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - /yargs-parser/2.4.1: - dependencies: - camelcase: 3.0.0 - lodash.assign: 4.2.0 - dev: false - resolution: - integrity: sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= - /yargs-parser/5.0.0: - dependencies: - camelcase: 3.0.0 - dev: false - resolution: - integrity: sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= - /yargs-parser/8.1.0: - dependencies: - camelcase: 4.1.0 - dev: false - resolution: - integrity: sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== - /yargs-parser/9.0.2: - dependencies: - camelcase: 4.1.0 - dev: false - resolution: - integrity: sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= - /yargs/10.1.2: - dependencies: - cliui: 4.1.0 - decamelize: 1.2.0 - find-up: 2.1.0 - get-caller-file: 1.0.3 - os-locale: 2.1.0 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 2.1.1 - which-module: 2.0.0 - y18n: 3.2.1 - yargs-parser: 8.1.0 - dev: false - resolution: - integrity: sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== - /yargs/11.1.1: - dependencies: - cliui: 4.1.0 - decamelize: 1.2.0 - find-up: 2.1.0 - get-caller-file: 1.0.3 - os-locale: 3.1.0 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 2.1.1 - which-module: 2.0.0 - y18n: 3.2.1 - yargs-parser: 9.0.2 - dev: false - resolution: - integrity: sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw== - /yargs/12.0.5: - dependencies: - cliui: 4.1.0 - decamelize: 1.2.0 - find-up: 3.0.0 - get-caller-file: 1.0.3 - os-locale: 3.1.0 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 2.1.1 - which-module: 2.0.0 - y18n: 4.0.0 - yargs-parser: 11.1.1 - dev: false - resolution: - integrity: sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - /yargs/13.2.4: - dependencies: - cliui: 5.0.0 - find-up: 3.0.0 - get-caller-file: 2.0.5 - os-locale: 3.1.0 - 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.0 - y18n: 4.0.0 - yargs-parser: 13.1.2 - dev: false - resolution: - integrity: sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== - /yargs/4.6.0: - dependencies: - camelcase: 2.1.1 - cliui: 3.2.0 - decamelize: 1.2.0 - lodash.assign: 4.2.0 - os-locale: 1.4.0 - pkg-conf: 1.1.3 - read-pkg-up: 1.0.1 - require-main-filename: 1.0.1 - string-width: 1.0.2 - window-size: 0.2.0 - y18n: 3.2.1 - yargs-parser: 2.4.1 - dev: false - resolution: - integrity: sha1-y0BQwBWb+2u2ScD0r1UFJqhGGdw= - /yargs/7.1.0: - dependencies: - camelcase: 3.0.0 - cliui: 3.2.0 - decamelize: 1.2.0 - get-caller-file: 1.0.3 - os-locale: 1.4.0 - read-pkg-up: 1.0.1 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 1.0.2 - which-module: 1.0.0 - y18n: 3.2.1 - yargs-parser: 5.0.0 - dev: false - resolution: - integrity: sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= - /z-schema/3.18.4: - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 8.2.0 - dev: false - hasBin: true - optionalDependencies: - commander: 2.20.3 - resolution: - integrity: sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw== - 'file:projects/api-documenter-test.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-documenter-test' - resolution: - integrity: sha512-IxYzaUsjim00TpAsKyonGc2LzvFG66s/P/ouKHeYeyegl6Na/UkglOG6sq0rai+P7wlxDkCXzdlhH1VApSP5jg== - tarball: 'file:projects/api-documenter-test.tgz' - version: 0.0.0 - 'file:projects/api-documenter.tgz': - dependencies: - '@microsoft/tsdoc': 0.12.14 - '@types/jest': 23.3.11 - '@types/js-yaml': 3.12.1 - '@types/node': 10.17.13 - '@types/resolve': 0.0.8 - colors: 1.2.5 - gulp: 4.0.2 - jest: 23.6.0 - js-yaml: 3.13.1 - resolve: 1.8.1 - dev: false - name: '@rush-temp/api-documenter' - resolution: - integrity: sha512-6fmG46uYHM4SGmlM+RIRc9iuaKpEzblcY1nO6GY84+45Ylv7FzV4f9gjdckksD1s3/A5pav8MxmgRRC8ZyHmdg== - tarball: 'file:projects/api-documenter.tgz' - version: 0.0.0 - 'file:projects/api-extractor-lib1-test.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - typescript: 2.4.2 - dev: false - name: '@rush-temp/api-extractor-lib1-test' - resolution: - integrity: sha512-RpxJbIdjnT5NGC/QbRhvXMlNKZrkXCjrb4QMYC4bOfl7It2bHUhFVC7ia/MVfiSfy3j/WOfLWlWEvfV+aUb3kg== - tarball: 'file:projects/api-extractor-lib1-test.tgz' - version: 0.0.0 - 'file:projects/api-extractor-lib2-test.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-lib2-test' - resolution: - integrity: sha512-Y8EjDqx8kh5POt2ahj5xHukdlDu7OwlYu48hQ20vwzCe7clrZGGITVzohSh5KCQpLj6lC0ViJ6bhnUC8Zn9itA== - tarball: 'file:projects/api-extractor-lib2-test.tgz' - version: 0.0.0 - 'file:projects/api-extractor-lib3-test.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-lib3-test' - resolution: - integrity: sha512-YZUv3cpx/vGYl4LRHh88mJgIUdu3x9csIkg/ex4VSrOOENIxY2508y8zaQbOLN7wQnGtdFh3e2naPZ8+PaZUGQ== - tarball: 'file:projects/api-extractor-lib3-test.tgz' - version: 0.0.0 - 'file:projects/api-extractor-model.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@microsoft/tsdoc': 0.12.14 - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/api-extractor-model' - resolution: - integrity: sha512-el+CZgEsaP2zfKtaVgq5In7pGTCokGxXSXRN1Umn15rx7mj24jsm6a0YCUh2Oy68aLrzfzaWuusrbDsvkTObFQ== - tarball: 'file:projects/api-extractor-model.tgz' - version: 0.0.0 - 'file:projects/api-extractor-scenarios.tgz': - dependencies: - '@microsoft/teams-js': 1.3.0-beta.4 - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - colors: 1.2.5 - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-scenarios' - resolution: - integrity: sha512-EWlVSacl5IXdOzG100I5ThL24K7a92PjJ9xyeFUwsvKKVMrnyTer2VxEObYwIsDeeivGSmtOj10+ZSONNKHrlA== - tarball: 'file:projects/api-extractor-scenarios.tgz' - version: 0.0.0 - 'file:projects/api-extractor-test-01.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/long': 4.0.0 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - long: 4.0.0 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-test-01' - resolution: - integrity: sha512-pe7+dQ87T/Xx2XnUdqxl3NYKP3AUlBre/sE4PYyMxR3ReD5fEVwZC50/po4Q+YKtH+z2lcDDftx/2qo6MOsXtw== - tarball: 'file:projects/api-extractor-test-01.tgz' - version: 0.0.0 - 'file:projects/api-extractor-test-02.tgz': - dependencies: - '@types/node': 10.17.13 - '@types/semver': 5.3.33 - fs-extra: 7.0.1 - semver: 5.3.0 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-test-02' - resolution: - integrity: sha512-snzcy5ZBrY7jG3JpZSQHJa5CJh6mLu0Sn0+w+k3EnRH9dpb/aY+Ty7G1cTEv7KE8vBsdbtXVC5XHFHU/8vnjBw== - tarball: 'file:projects/api-extractor-test-02.tgz' - version: 0.0.0 - 'file:projects/api-extractor-test-03.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-test-03' - resolution: - integrity: sha512-u3+vi0EJBQ0lENBb57W3IyIbmxGPaSO6D7IgCXZsoZUjr41Vl5+4QiNsEoePJuRk5yzo20r8nsLfXKCL1PspMQ== - tarball: 'file:projects/api-extractor-test-03.tgz' - version: 0.0.0 - 'file:projects/api-extractor-test-04.tgz': - dependencies: - fs-extra: 7.0.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor-test-04' - resolution: - integrity: sha512-2BItXxUajGahw84OndJ7wTPIDshJpZV4r+XXOYurJKaswoxrez6VGKBDUpD+ar7tkPLyPoTW435yxFRCTDgHIg== - tarball: 'file:projects/api-extractor-test-04.tgz' - version: 0.0.0 - 'file:projects/api-extractor.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@microsoft/tsdoc': 0.12.14 - '@types/jest': 23.3.11 - '@types/lodash': 4.14.116 - '@types/node': 10.17.13 - colors: 1.2.5 - gulp: 4.0.2 - lodash: 4.17.15 - resolve: 1.8.1 - source-map: 0.6.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/api-extractor' - resolution: - integrity: sha512-Z13gp+jB7xAMgpL19acjqLs6LJSmSltXGfYvC0ylJmA7OGlhuwqceO9SmXivupiDlxcXcTmDF7uX1ZHqj2xcNw== - tarball: 'file:projects/api-extractor.tgz' - version: 0.0.0 - 'file:projects/debug-certificate-manager.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - '@types/node-forge': 0.9.1 - deasync: 0.1.19 - gulp: 4.0.2 - node-forge: 0.7.6 - sudo: 1.0.3 - dev: false - name: '@rush-temp/debug-certificate-manager' - resolution: - integrity: sha512-7bMbqGDJ8PilmabfpXZ5vbubQzWcoUlYSWkbly0IgeHzc8Dpk9AXfD+2BT/JIk/ZMN6JkxkjA41b1BMeNTlgFg== - tarball: 'file:projects/debug-certificate-manager.tgz' - version: 0.0.0 - 'file:projects/doc-plugin-rush-stack.tgz': - dependencies: - '@microsoft/tsdoc': 0.12.14 - '@types/js-yaml': 3.12.1 - '@types/node': 10.17.13 - gulp: 4.0.2 - js-yaml: 3.13.1 - dev: false - name: '@rush-temp/doc-plugin-rush-stack' - resolution: - integrity: sha512-0MR4gl0OuC63vn+Hkc8ejeFJlwCNjwE697M6g+dK/e9ctNr813RPDbwSHPzwu2R77olcxIay4kvK+i3pPHfPeg== - tarball: 'file:projects/doc-plugin-rush-stack.tgz' - version: 0.0.0 - 'file:projects/eslint-config.tgz': - dependencies: - '@typescript-eslint/eslint-plugin': 2.3.3_5b3b7d3a75edb27abc53579646941536 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 - eslint-plugin-promise: 4.2.1 - eslint-plugin-react: 7.16.0_eslint@6.5.1 - eslint-plugin-security: 1.4.0 - eslint-plugin-tsdoc: 0.2.3 - typescript: 3.5.3 - dev: false - name: '@rush-temp/eslint-config' - resolution: - integrity: sha512-h6SLC+GZuBXl0iAiUzX9QQ72ZtQCAOxi6Cc+JvAMgROh491oiVRotKtGY7RDAOO76t3yZ08ryVdu/WH0xSVLRw== - tarball: 'file:projects/eslint-config.tgz' - version: 0.0.0 - 'file:projects/eslint-plugin.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 - '@types/node': 10.17.13 - '@typescript-eslint/experimental-utils': 2.3.3_eslint@6.5.1 - '@typescript-eslint/parser': 2.3.3_eslint@6.5.1 - '@typescript-eslint/typescript-estree': 2.3.3 - eslint: 6.5.1 - gulp: 4.0.2 - typescript: 3.5.3 - dev: false - name: '@rush-temp/eslint-plugin' - resolution: - integrity: sha512-r2NnXz0aAKrLDgBXx29fRUaPnnK2DqQGVUHv55x2r3TzrioMIPzGjw80+CGNvfluCmZ/B6NMJ3CSHBz7W2d8Uw== - tarball: 'file:projects/eslint-plugin.tgz' - version: 0.0.0 - 'file:projects/generate-api-docs.tgz': - dev: false - name: '@rush-temp/generate-api-docs' - resolution: - integrity: sha512-0StXpRcO30Y6eXubYyMtaS5BVse0ZLIFv2Gy8rXB+rcVyMiGgtz2lnzvFPDprfn/sjrwWaV2Plj7ZzYUJ+rg0g== - tarball: 'file:projects/generate-api-docs.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build-mocha.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/glob': 7.1.1 - '@types/gulp': 4.0.6 - '@types/gulp-istanbul': 0.9.30 - '@types/gulp-mocha': 0.0.32 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/orchestrator': 0.0.30 - glob: 7.0.6 - gulp: 4.0.2 - gulp-istanbul: 0.10.4 - gulp-mocha: 6.0.0 - dev: false - name: '@rush-temp/gulp-core-build-mocha' - resolution: - integrity: sha512-iCjRPZQkgnuN0x6HlxXAnK6/w53Bolq8tpLob3m3Sfea4EwLILx4CX9xLNLiIHu2qXSn7B/NH2LTCe+sKLPehw== - tarball: 'file:projects/gulp-core-build-mocha.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build-sass.tgz': - dependencies: - '@types/clean-css': 4.2.1 - '@types/glob': 7.1.1 - '@types/gulp': 4.0.6 - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - '@types/node-sass': 4.11.0 - autoprefixer: 9.7.4 - clean-css: 4.2.1 - glob: 7.0.6 - gulp: 4.0.2 - jest: 23.6.0 - node-sass: 4.12.0 - postcss: 7.0.5 - postcss-modules: 1.3.2 - dev: false - name: '@rush-temp/gulp-core-build-sass' - resolution: - integrity: sha512-QwZeLsLphU25Yj80vX1xnI9F5+odHgGR6AqHYwj7OaBsBuvPH1/wclRc1eTFdWl15Fbq96FNfDXa6EAbKGZsjQ== - tarball: 'file:projects/gulp-core-build-sass.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build-serve.tgz': - dependencies: - '@types/express': 4.11.0 - '@types/express-serve-static-core': 4.11.0 - '@types/gulp': 4.0.6 - '@types/mime': 0.0.29 - '@types/node': 10.17.13 - '@types/orchestrator': 0.0.30 - '@types/serve-static': 1.13.1 - '@types/through2': 2.0.32 - '@types/vinyl': 2.0.3 - colors: 1.2.5 - express: 4.16.4 - gulp: 4.0.2 - gulp-connect: 5.5.0 - gulp-open: 3.0.1 - sudo: 1.0.3 - dev: false - name: '@rush-temp/gulp-core-build-serve' - resolution: - integrity: sha512-kOe08Xlz9hCXlu0ZmUkKHmVrCUymJHaRtF9WrLOkfcR3JqYdbGhW/vawTcomwIusxqtG+anY3aZlSaCVZGXrUg== - tarball: 'file:projects/gulp-core-build-serve.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build-typescript.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/glob': 7.1.1 - '@types/node': 10.17.13 - '@types/resolve': 0.0.8 - decomment: 0.9.2 - glob: 7.0.6 - glob-escape: 0.0.2 - gulp: 4.0.2 - resolve: 1.8.1 - typescript: 3.2.4 - dev: false - name: '@rush-temp/gulp-core-build-typescript' - resolution: - integrity: sha512-RWfs2T5bymwsKeVFcjNwQKpJRsV34M8kZILiXibai0WgAeaTuKclL1iWvVXpNp8z3mE+3uIZz/ozr5CmJ9VErQ== - tarball: 'file:projects/gulp-core-build-typescript.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build-webpack.tgz': - dependencies: - '@types/gulp': 4.0.6 - '@types/node': 10.17.13 - '@types/orchestrator': 0.0.30 - '@types/source-map': 0.5.0 - '@types/uglify-js': 2.6.29 - '@types/webpack': 4.39.8 - '@types/webpack-dev-server': 3.1.7 - colors: 1.2.5 - gulp: 4.0.2 - webpack: 4.31.0_webpack@4.31.0 - dev: false - name: '@rush-temp/gulp-core-build-webpack' - resolution: - integrity: sha512-bAYuyYu7KrRxgpN8CKcZQjO9cSgpTq1zA9bS5+mc1m4gEUOKzcXggYerDQOOwAtHAgwLNTc4l/1DFMwU2cpcbg== - tarball: 'file:projects/gulp-core-build-webpack.tgz' - version: 0.0.0 - 'file:projects/gulp-core-build.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/chai': 3.4.34 - '@types/chalk': 0.4.31 - '@types/glob': 7.1.1 - '@types/gulp': 4.0.6 - '@types/jest': 23.3.11 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/node-notifier': 0.0.28 - '@types/orchestrator': 0.0.30 - '@types/semver': 5.3.33 - '@types/through2': 2.0.32 - '@types/vinyl': 2.0.3 - '@types/yargs': 0.0.34 - '@types/z-schema': 3.16.31 - chai: 3.5.0 - colors: 1.2.5 - del: 2.2.2 - end-of-stream: 1.1.0 - glob: 7.0.6 - glob-escape: 0.0.2 - globby: 5.0.0 - gulp: 4.0.2 - gulp-flatten: 0.2.0 - gulp-if: 2.0.2 - jest: 23.6.0 - jest-cli: 22.4.4 - jest-environment-jsdom: 22.4.3 - jest-nunit-reporter: 1.3.1 - jest-resolve: 22.4.3 - jsdom: 11.11.0 - lodash.merge: 4.6.2 - merge2: 1.0.3 - node-notifier: 5.0.2 - object-assign: 4.1.1 - orchestrator: 0.3.8 - pretty-hrtime: 1.0.3 - semver: 5.3.0 - through2: 2.0.5 - vinyl: 2.2.0 - xml: 1.0.1 - yargs: 4.6.0 - z-schema: 3.18.4 - dev: false - name: '@rush-temp/gulp-core-build' - resolution: - integrity: sha512-KY/rDdu8MtDPhtRmMBjr2t+mHIbRUUeAsaLuwJrY4u3CqeNHSWiReblaPQQ1MMsBmiYacTKdqv6/e23LTTrILQ== - tarball: 'file:projects/gulp-core-build.tgz' - version: 0.0.0 - 'file:projects/load-themed-styles.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/webpack-env': 1.13.0 - chai: 3.5.0 - gulp: 4.0.2 - dev: false - name: '@rush-temp/load-themed-styles' - resolution: - integrity: sha512-eZ/uPtBcR8i4G4NhO6WOek1/GW4pj7Ji7anhJLdHHpnYEhTuM7sc/ccFsxhO2wzLqJiFT7URd4N3aj1arUDx4w== - tarball: 'file:projects/load-themed-styles.tgz' - version: 0.0.0 - 'file:projects/loader-load-themed-styles.tgz': - dependencies: - '@types/loader-utils': 1.1.3 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/webpack': 4.39.8 - chai: 3.5.0 - gulp: 4.0.2 - loader-utils: 1.1.0 - dev: false - name: '@rush-temp/loader-load-themed-styles' - resolution: - integrity: sha512-aeoLRx7pZVrNwLQXu6h0bwvQfeCvVVFKAQ2iSQtqfXipNj/sA6AKH/TCtjfqPjVOqtTjXTh2iC0uwfsRfSOpGA== - tarball: 'file:projects/loader-load-themed-styles.tgz' - version: 0.0.0 - 'file:projects/loader-raw-script.tgz': - dependencies: - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - chai: 3.5.0 - gulp: 4.0.2 - loader-utils: 1.1.0 - mocha: 5.2.0 - dev: false - name: '@rush-temp/loader-raw-script' - resolution: - integrity: sha512-ZpToFNpTp6p2EQiT68voxDXd9reTZ2a+UUDdmntmJ1HIlWASYtUOZ9NvceephLav339QWfCPwuIkv6X1c4vQmw== - tarball: 'file:projects/loader-raw-script.tgz' - version: 0.0.0 - 'file:projects/localization-plugin-test-01.tgz': - dependencies: - '@types/webpack-env': 1.13.0 - html-webpack-plugin: 3.2.0_webpack@4.31.0 - ts-loader: 6.0.0 - webpack: 4.31.0_webpack@4.31.0 - webpack-bundle-analyzer: 3.6.1 - webpack-cli: 3.3.11_webpack@4.31.0 - webpack-dev-server: 3.9.0_webpack@4.31.0 - dev: false - name: '@rush-temp/localization-plugin-test-01' - resolution: - integrity: sha512-CPM8VgA662a5JXyszLuTJ+TgLe0ff/qkH0KkkrwHwrh3UOH7ST7zKtAcrKCtVKySV94GlVT5JGgD0rFcNj7Gbg== - tarball: 'file:projects/localization-plugin-test-01.tgz' - version: 0.0.0 - 'file:projects/localization-plugin-test-02.tgz': - dependencies: - '@types/lodash': 4.14.116 - '@types/webpack-env': 1.13.0 - html-webpack-plugin: 3.2.0_webpack@4.31.0 - lodash: 4.17.15 - ts-loader: 6.0.0 - webpack: 4.31.0_webpack@4.31.0 - webpack-bundle-analyzer: 3.6.1 - webpack-cli: 3.3.11_webpack@4.31.0 - webpack-dev-server: 3.9.0_webpack@4.31.0 - dev: false - name: '@rush-temp/localization-plugin-test-02' - resolution: - integrity: sha512-rZhAPTjsiuv1gkEODxe7qwWKzp0a0+ugO7oRhHULBkQFf2Uxcm9Vc3GCa8PDqQ9jLUFpqAXvxUyuCmB8YMBicA== - tarball: 'file:projects/localization-plugin-test-02.tgz' - version: 0.0.0 - 'file:projects/localization-plugin-test-03.tgz': - dependencies: - '@types/webpack-env': 1.13.0 - html-webpack-plugin: 3.2.0_webpack@4.31.0 - ts-loader: 6.0.0 - webpack: 4.31.0_webpack@4.31.0 - webpack-bundle-analyzer: 3.6.1 - webpack-cli: 3.3.11_webpack@4.31.0 - webpack-dev-server: 3.9.0_webpack@4.31.0 - dev: false - name: '@rush-temp/localization-plugin-test-03' - resolution: - integrity: sha512-Fiyizz/cRAZ3dct6uDburgjEM0r1PKcDmBRsWPPFtq+CbDZ/KVsUdmLrUqUiaJIgUsX7cx3L534QFJMt89PEDg== - tarball: 'file:projects/localization-plugin-test-03.tgz' - version: 0.0.0 - 'file:projects/localization-plugin.tgz': - dependencies: - '@types/jju': 1.4.1 - '@types/loader-utils': 1.1.3 - '@types/lodash': 4.14.116 - '@types/node': 10.17.13 - '@types/tapable': 1.0.4 - '@types/webpack': 4.39.8 - '@types/xmldoc': 1.1.4 - decache: 4.5.1 - gulp: 4.0.2 - jju: 1.4.0 - loader-utils: 1.1.0 - lodash: 4.17.15 - pseudolocale: 1.1.0 - webpack: 4.31.0_webpack@4.31.0 - xmldoc: 1.1.2 - dev: false - name: '@rush-temp/localization-plugin' - resolution: - integrity: sha512-C3kNhJQw5WnzAdtFxJ4R9dN7mFDkN7JguaJrz962quVAzHqfnvcJG6g8m0jKgoLnmIhSlIbpweDmwRF0eYMnhg== - tarball: 'file:projects/localization-plugin.tgz' - version: 0.0.0 - 'file:projects/node-core-library.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/fs-extra': 5.0.4 - '@types/jest': 23.3.11 - '@types/jju': 1.4.1 - '@types/node': 10.17.13 - '@types/semver': 5.3.33 - '@types/timsort': 0.3.0 - '@types/z-schema': 3.16.31 - colors: 1.2.5 - fs-extra: 7.0.1 - gulp: 4.0.2 - jju: 1.4.0 - semver: 5.3.0 - timsort: 0.3.0 - z-schema: 3.18.4 - dev: false - name: '@rush-temp/node-core-library' - resolution: - integrity: sha512-VBJmtX4C94d3dRP/R4JrtWf/kjJfN6h1lR6mu7noenJXhShuGurdOCdiHIBO5TAzPWG8ESklKJWV7O7dlJs4Kg== - tarball: 'file:projects/node-core-library.tgz' - version: 0.0.0 - 'file:projects/node-library-build-eslint-test.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - chai: 3.5.0 - gulp: 4.0.2 - dev: false - name: '@rush-temp/node-library-build-eslint-test' - resolution: - integrity: sha512-qmkHvn+IPfP04YSjVPBPrtxQgdIsk8asL4Iik8O7ewL0bliV9N3EF2aFZ5CdM6jp4I97DLbXJ464duErJdCazw== - tarball: 'file:projects/node-library-build-eslint-test.tgz' - version: 0.0.0 - 'file:projects/node-library-build-tslint-test.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - chai: 3.5.0 - gulp: 4.0.2 - dev: false - name: '@rush-temp/node-library-build-tslint-test' - resolution: - integrity: sha512-Q1LEO/baVdHPY5q3ZOob535X5xX+x9YvKVXlstySiQpuW8tCeWFHp/I/5R6fjCpbGlpPAF+LQIMtV5he56IMfQ== - tarball: 'file:projects/node-library-build-tslint-test.tgz' - version: 0.0.0 - 'file:projects/node-library-build.tgz': - dependencies: - '@types/gulp': 4.0.6 - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/node-library-build' - resolution: - integrity: sha512-CmYLuKAdg4uXDwivFZ0aYhlnuOl0GKib5XcaCeR8WufNMO8CCq7W/lVKYjprSNQQah+JZ/7uIzgMn8sq8z4g8g== - tarball: 'file:projects/node-library-build.tgz' - version: 0.0.0 - 'file:projects/package-deps-hash.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - chai: 3.5.0 - gulp: 4.0.2 - dev: false - name: '@rush-temp/package-deps-hash' - resolution: - integrity: sha512-fdcsFoUbDnpPmXJUlp5UQndUtZEM0Oz37LjmVUW2ixCY4YcSOHKxXN2LOAv8XjBYHIaCBvUcO0t+mTpe5NMkvQ== - tarball: 'file:projects/package-deps-hash.tgz' - version: 0.0.0 - 'file:projects/repo-toolbox.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/repo-toolbox' - resolution: - integrity: sha512-/eYU/rWThcXqbxpmxJDCsn2pP4jaakDN8zY1b9rpzh+GbuJsBaMoJ8ClS/m6OqUwnfDoYcRxt2SkGU6s1dPQmg== - tarball: 'file:projects/repo-toolbox.tgz' - version: 0.0.0 - 'file:projects/rush-buildxl.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-buildxl' - resolution: - integrity: sha512-27S1WLqqbx3f9A9TlTza9GSRfzmehT4rr1t25w2AedvBxd3/5/UoIRaAMxIR2kFMaJQSqCURJZ9bqVGwpJDr5g== - tarball: 'file:projects/rush-buildxl.tgz' - version: 0.0.0 - 'file:projects/rush-lib.tgz': - dependencies: - '@pnpm/link-bins': 5.1.7 - '@types/glob': 7.1.1 - '@types/inquirer': 0.0.43 - '@types/jest': 23.3.11 - '@types/js-yaml': 3.12.1 - '@types/lodash': 4.14.116 - '@types/minimatch': 2.0.29 - '@types/node': 10.17.13 - '@types/node-fetch': 1.6.9 - '@types/npm-package-arg': 6.1.0 - '@types/read-package-tree': 5.1.0 - '@types/semver': 5.3.33 - '@types/strict-uri-encode': 2.0.0 - '@types/tar': 4.0.0 - '@types/wordwrap': 1.0.0 - '@types/z-schema': 3.16.31 - '@yarnpkg/lockfile': 1.0.2 - builtin-modules: 3.1.0 - cli-table: 0.3.1 - colors: 1.2.5 - git-repo-info: 2.1.1 - glob: 7.0.6 - glob-escape: 0.0.2 - gulp: 4.0.2 - https-proxy-agent: 2.2.4 - inquirer: 6.2.2 - jest: 23.6.0 - js-yaml: 3.13.1 - lodash: 4.17.15 - minimatch: 3.0.4 - node-fetch: 2.1.2 - npm-package-arg: 6.1.1 - read-package-tree: 5.1.6 - semver: 5.3.0 - strict-uri-encode: 2.0.0 - tar: 4.4.13 - true-case-path: 2.2.1 - wordwrap: 1.0.0 - z-schema: 3.18.4 - dev: false - name: '@rush-temp/rush-lib' - resolution: - integrity: sha512-MDjsPBNWxfYSrSmf097WE5XB81WNxmWIgqZYFz7LkEteY227GKZosebIvMHx/G5xfButfzUXY/eyxA5OTd4Fbg== - tarball: 'file:projects/rush-lib.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.4-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.4-library-test' - resolution: - integrity: sha512-7ZNxj1iqqVXwPbwtLdOReCe0exBMkdAnTemNmHQacbykf4wAZVHndONQP1gOoF0ucqbpdUDQz0UjiX7ewSyvFQ== - tarball: 'file:projects/rush-stack-compiler-2.4-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.4.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 2.4.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.4' - resolution: - integrity: sha512-i9CHdMK8a6sC8cVV3q2BKvaEf/z22X839BiTekinVB6YlfKG5cowo2Km68Vg/BMQSfKjwBPwZOFsWJhYJFLMGQ== - tarball: 'file:projects/rush-stack-compiler-2.4.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.7-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.7-library-test' - resolution: - integrity: sha512-D+IQjPyadH3IFm2mC2vPulgsR7gKgHzx6Lb32SjvU5HHJb1vNFwiO6/KJ6P5lUN7x8s/amWYO/NAOFiTiEkpDA== - tarball: 'file:projects/rush-stack-compiler-2.7-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.7.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 2.7.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.7' - resolution: - integrity: sha512-i4s1pk8uaZN4UkHaK17S36jl4a9iQfNns5qtk2w/bNpfmB2qWsEJrRPG4SpJMqFFvNxCwLa2p+jxClD4mCujaw== - tarball: 'file:projects/rush-stack-compiler-2.7.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.8-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.8-library-test' - resolution: - integrity: sha512-/Va365kd2m2+bkAocpmaU9KdGUbTYVE/PUCVRjHRaC1dDExeU6MjCzDM7yP1Rul1MgMzhI7NOLqr3HxXW2qGCA== - tarball: 'file:projects/rush-stack-compiler-2.8-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.8.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 2.8.4 - dev: false - name: '@rush-temp/rush-stack-compiler-2.8' - resolution: - integrity: sha512-Pd2ZgQ8gZ20slCfO4//M2B5sCj9R0cKURWf8G/HwnxeTAJdnKdScW0IsU1TjNbPayQ7FpIGrZulPe2iWJt7D3Q== - tarball: 'file:projects/rush-stack-compiler-2.8.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.9-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.9-library-test' - resolution: - integrity: sha512-IMW41OF+UdMyjG3H+7KomOuyYdsc0RWOwdFPrZ5wbRHs8RauAmc4vjwlTuA9JL1UPMnFfVJyIgm2M//xqoqNpQ== - tarball: 'file:projects/rush-stack-compiler-2.9-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-2.9.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 2.9.2 - dev: false - name: '@rush-temp/rush-stack-compiler-2.9' - resolution: - integrity: sha512-wIpzf1RV5DLumxI61U+dVXj7K/wQ6VtQAuiG0BSA7GZOf50NWlIiA4AmnpLDpp6HkPVM8q5NK4PLsNfT2KJdUA== - tarball: 'file:projects/rush-stack-compiler-2.9.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.0-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.0-library-test' - resolution: - integrity: sha512-TchuH9wEKUC/IPTSfsBNGHdMBcFsA3MZIx8CzH+UTp6mLG8Xjef7iXz65Fhmq0NEAHsnx2kllvRfzbGYQ8ZIeQ== - tarball: 'file:projects/rush-stack-compiler-3.0-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.0.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.0.3 - dev: false - name: '@rush-temp/rush-stack-compiler-3.0' - resolution: - integrity: sha512-Zg0TDAbTq1L05fhOZtN6dYIpuidtrij/dTh5J+LEkqRIU+pA7CQeELynaViTFBuo/w+nr/54FPpGXMleTccukg== - tarball: 'file:projects/rush-stack-compiler-3.0.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.1-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.1-library-test' - resolution: - integrity: sha512-Uwy2U52LzHIdfrL+VIUAILbcjpeN5YItGHzwKqpzpIMWaunrEcfTXlaGm8yV4arVuwCGN7bX65kCR3Lh46JvBg== - tarball: 'file:projects/rush-stack-compiler-3.1-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.1.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.1.6 - dev: false - name: '@rush-temp/rush-stack-compiler-3.1' - resolution: - integrity: sha512-1TzClDXZW4wzfJ8n3h0R+v/iTuVOkm4BKyjvsOOKYaERIsAlOtL4RekqPUcvuKXxvZ0r0+jhoWR9w6COVcq5jg== - tarball: 'file:projects/rush-stack-compiler-3.1.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.2-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.2-library-test' - resolution: - integrity: sha512-55IVFkfBXuP0F/vnoep1IgHyNyKaQmhyizwzsJOD0HimOcQgdGFJjTM78JwIAJ0sSjE/VFtLrzgMfdXaZcHpSQ== - tarball: 'file:projects/rush-stack-compiler-3.2-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.2.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.2.4 - dev: false - name: '@rush-temp/rush-stack-compiler-3.2' - resolution: - integrity: sha512-2pnyX4ztXcsGi1MU+qQSYkAixvbuPE8m++f/swfzx6NmCpeUDW04xGvmhJd0zEGAmz/m4OJNUNL0cnRCI0PaNQ== - tarball: 'file:projects/rush-stack-compiler-3.2.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.3-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.3-library-test' - resolution: - integrity: sha512-wI6xA92vRBYzwLf6XPjhCBG3GHgm5d9cLfcXbTGBPjUPf2OvO2UIoThTjpzj0M6e4Togzq/92LNvVU9BKOfHgQ== - tarball: 'file:projects/rush-stack-compiler-3.3-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.3.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.3.4000 - dev: false - name: '@rush-temp/rush-stack-compiler-3.3' - resolution: - integrity: sha512-aKQ68jmk8I9dsgZgsPjkrrcMcwnnqsldV4hbfOC5sS/bU+SnQDnWf/yB2exPVOOQNcREm/k7loQNr1Rtq6Od2A== - tarball: 'file:projects/rush-stack-compiler-3.3.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.4-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.4-library-test' - resolution: - integrity: sha512-jB9yt5V9KGMBKZOxM/m5ToRx05iru7Lyl+R35H91eXZeaxAh9+AJQqkLr4DRpjBlUr7E65rdU/PX1ipviuC1Bg== - tarball: 'file:projects/rush-stack-compiler-3.4-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.4.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.4.5 - dev: false - name: '@rush-temp/rush-stack-compiler-3.4' - resolution: - integrity: sha512-uKE+rdbci95UTkFYes6/in4uqHw+KgDQVKyduQsQaHjo4QjLtqsSfoZdqiCHB2hOiUSnEX//DUP8B/hYPqW1Dg== - tarball: 'file:projects/rush-stack-compiler-3.4.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.5-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.5-library-test' - resolution: - integrity: sha512-aS/KD27qxwtqf3DoxL8FOGYL4n0M60SqqwcTnIbcKsQSrqPkJgvLM6H25b2cZFetrqJ0G7+UbAfLGRz3yxU77w== - tarball: 'file:projects/rush-stack-compiler-3.5-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.5.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.5.3 - dev: false - name: '@rush-temp/rush-stack-compiler-3.5' - resolution: - integrity: sha512-f+9GjlB9iS9mlK9irqXrPnOHUoW0F4yJ8ELKddDMgIl4t+6ghbFZWZd/nEThPrpXg+jlthiNEzCAbA1p4AIZeg== - tarball: 'file:projects/rush-stack-compiler-3.5.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.6-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.6-library-test' - resolution: - integrity: sha512-C7AppePylD6ra5gVLzNn8PlPqr8N1WYoVs063Al6OYyM3X6Y3LHayx5Nwo7PtTAuMlLMcSnyA0ehCqacOVxPmw== - tarball: 'file:projects/rush-stack-compiler-3.6-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.6.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.6.5 - dev: false - name: '@rush-temp/rush-stack-compiler-3.6' - resolution: - integrity: sha512-sD9mh0bxNR59NYAqJFfGuxygXylJExWU7fweb9W18EA2oPFvXtp0xxhlEmc2E5D7Cb09wDZ01DeWuW1Y4oPgWA== - tarball: 'file:projects/rush-stack-compiler-3.6.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.7-library-test.tgz': - dependencies: - '@types/node': 10.17.13 - gulp: 4.0.2 - dev: false - name: '@rush-temp/rush-stack-compiler-3.7-library-test' - resolution: - integrity: sha512-eF6EZ7mJKXEppJxHwozf4Wd+5dBQOXt2OTE49+1dmZQ3EOfaMsvZMGVZsts2cR0qBpxRxtoCIdCS4Yvp8t6yKA== - tarball: 'file:projects/rush-stack-compiler-3.7-library-test.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-3.7.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/node': 10.17.13 - eslint: 6.5.1 - gulp: 4.0.2 - tslint: 5.12.1 - tslint-microsoft-contrib: 5.2.1_tslint@5.12.1 - typescript: 3.7.5 - dev: false - name: '@rush-temp/rush-stack-compiler-3.7' - resolution: - integrity: sha512-iz62BYFkSDWqd/pGoiqu/yZ0o3FPIrjmP8jjDdIry0C5niJmcRvXxu7yBwl5vkOkAdxRzVzIjG5Jaz3A7RnSVw== - tarball: 'file:projects/rush-stack-compiler-3.7.tgz' - version: 0.0.0 - 'file:projects/rush-stack-compiler-shared.tgz': - dev: false - name: '@rush-temp/rush-stack-compiler-shared' - resolution: - integrity: sha512-3DA+ZdhWSjTNrAVaC6G9AizudJaiO82PoNgCTQ/3PQ4g4J9xx6BrNv+sVPv/4h5ST2WQhdHiY9OW0/2xWDWY/A== - tarball: 'file:projects/rush-stack-compiler-shared.tgz' - version: 0.0.0 - 'file:projects/rush.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/semver': 5.3.33 - '@types/sinon': 1.16.34 - chai: 3.5.0 - colors: 1.2.5 - gulp: 4.0.2 - semver: 5.3.0 - sinon: 1.17.7 - dev: false - name: '@rush-temp/rush' - resolution: - integrity: sha512-vFJN0QE+9/f8jEmZ860EJwJ1dIlIRacHSWsS9tyWvvPMXdVDaCY2LscEY/Or/j4ykaBuSq8jLYch3dwgw2b00w== - tarball: 'file:projects/rush.tgz' - version: 0.0.0 - 'file:projects/rushell.tgz': - dependencies: - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - gulp: 4.0.2 - jest: 23.6.0 - ts-jest: 22.4.6_jest@23.6.0 - dev: false - name: '@rush-temp/rushell' - resolution: - integrity: sha512-wnglr+80les1iH99ovZyyWYraleLtgfnlmariJDjO3pXMA8OIsZeDUB1bw3OgWO5iwyHIELlMeyylYm5wsHhYg== - tarball: 'file:projects/rushell.tgz' - version: 0.0.0 - 'file:projects/set-webpack-public-path-plugin.tgz': - dependencies: - '@types/lodash': 4.14.116 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/tapable': 1.0.4 - '@types/uglify-js': 2.6.29 - '@types/webpack': 4.39.8 - chai: 3.5.0 - gulp: 4.0.2 - lodash: 4.17.15 - mocha: 5.2.0 - uglify-js: 3.0.28 - dev: false - name: '@rush-temp/set-webpack-public-path-plugin' - resolution: - integrity: sha512-X9EEFU4KfZ/gWj414QGJetKB27Ymoy2Vh6eljj++18FiqSIbm47GCyYoG2Si/z50NE24NeLZPGlUg7V9qA0RHQ== - tarball: 'file:projects/set-webpack-public-path-plugin.tgz' - version: 0.0.0 - 'file:projects/stream-collator.tgz': - dependencies: - '@types/chai': 3.4.34 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - chai: 3.5.0 - colors: 1.2.5 - gulp: 4.0.2 - mocha: 5.2.0 - dev: false - name: '@rush-temp/stream-collator' - resolution: - integrity: sha512-MOiVvKeiunyw6QF7x5Ti1XSDVNcDz6WI9ZtDPjqVCuPPGuhlC3RdShj+uRKCM/eGIulQ3Z4nLDIjPg6QXvYVww== - tarball: 'file:projects/stream-collator.tgz' - version: 0.0.0 - 'file:projects/ts-command-line.tgz': - dependencies: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@types/argparse': 1.0.33 - '@types/jest': 23.3.11 - '@types/node': 10.17.13 - argparse: 1.0.10 - colors: 1.2.5 - gulp: 4.0.2 - dev: false - name: '@rush-temp/ts-command-line' - resolution: - integrity: sha512-swS3RsDJWBig5w1dsxSOh25SmLrUmiCDocjn5+v0dJRyYYWapciSDZAbHKvBZt8qvOOp2LIxdmG+uLscPdWsRA== - tarball: 'file:projects/ts-command-line.tgz' - version: 0.0.0 - 'file:projects/typings-generator.tgz': - dependencies: - '@types/glob': 7.1.1 - '@types/node': 10.17.13 - chokidar: 3.3.1 - glob: 7.0.6 - gulp: 4.0.2 - dev: false - name: '@rush-temp/typings-generator' - resolution: - integrity: sha512-xEsjhfmkSJN2/noguMF6JjLLNEFeAq11m2Z4rudZCQ2ci3fuFyPu4pjXQdlcV2fj8OblhcNG+5Zppe2vuXCx1A== - tarball: 'file:projects/typings-generator.tgz' - version: 0.0.0 - 'file:projects/web-library-build-test.tgz': - dependencies: - '@types/jest': 23.3.11 - gulp: 4.0.2 - jest: 23.6.0 - ts-jest: 22.4.6_jest@23.6.0 - dev: false - name: '@rush-temp/web-library-build-test' - resolution: - integrity: sha512-riChd+XLc6SgkTa3F/JnlGPpotEg5G8HUD5emTnut/TES/8ZfPv9JCUs0Alj9+9zff9dzKQzoyUOtzr7nnFZNg== - tarball: 'file:projects/web-library-build-test.tgz' - version: 0.0.0 - 'file:projects/web-library-build.tgz': - dependencies: - '@types/gulp': 4.0.6 - '@types/node': 10.17.13 - gulp: 4.0.2 - gulp-replace: 0.5.4 - dev: false - name: '@rush-temp/web-library-build' - resolution: - integrity: sha512-Wj4BXEHuZYUpgfJv6FndgcsYmAPEIJlfXMk43djaBK6iAPWJQGyo6MM9aJ24P126slwBtDrPiXWZMooYFDvm3g== - tarball: 'file:projects/web-library-build.tgz' - version: 0.0.0 -specifiers: - '@microsoft/node-library-build': 6.4.5 - '@microsoft/rush-stack-compiler-3.5': 0.4.4 - '@microsoft/teams-js': 1.3.0-beta.4 - '@microsoft/tsdoc': 0.12.14 - '@pnpm/link-bins': ~5.1.0 - '@rush-temp/api-documenter': 'file:./projects/api-documenter.tgz' - '@rush-temp/api-documenter-test': 'file:./projects/api-documenter-test.tgz' - '@rush-temp/api-extractor': 'file:./projects/api-extractor.tgz' - '@rush-temp/api-extractor-lib1-test': 'file:./projects/api-extractor-lib1-test.tgz' - '@rush-temp/api-extractor-lib2-test': 'file:./projects/api-extractor-lib2-test.tgz' - '@rush-temp/api-extractor-lib3-test': 'file:./projects/api-extractor-lib3-test.tgz' - '@rush-temp/api-extractor-model': 'file:./projects/api-extractor-model.tgz' - '@rush-temp/api-extractor-scenarios': 'file:./projects/api-extractor-scenarios.tgz' - '@rush-temp/api-extractor-test-01': 'file:./projects/api-extractor-test-01.tgz' - '@rush-temp/api-extractor-test-02': 'file:./projects/api-extractor-test-02.tgz' - '@rush-temp/api-extractor-test-03': 'file:./projects/api-extractor-test-03.tgz' - '@rush-temp/api-extractor-test-04': 'file:./projects/api-extractor-test-04.tgz' - '@rush-temp/debug-certificate-manager': 'file:./projects/debug-certificate-manager.tgz' - '@rush-temp/doc-plugin-rush-stack': 'file:./projects/doc-plugin-rush-stack.tgz' - '@rush-temp/eslint-config': 'file:./projects/eslint-config.tgz' - '@rush-temp/eslint-plugin': 'file:./projects/eslint-plugin.tgz' - '@rush-temp/generate-api-docs': 'file:./projects/generate-api-docs.tgz' - '@rush-temp/gulp-core-build': 'file:./projects/gulp-core-build.tgz' - '@rush-temp/gulp-core-build-mocha': 'file:./projects/gulp-core-build-mocha.tgz' - '@rush-temp/gulp-core-build-sass': 'file:./projects/gulp-core-build-sass.tgz' - '@rush-temp/gulp-core-build-serve': 'file:./projects/gulp-core-build-serve.tgz' - '@rush-temp/gulp-core-build-typescript': 'file:./projects/gulp-core-build-typescript.tgz' - '@rush-temp/gulp-core-build-webpack': 'file:./projects/gulp-core-build-webpack.tgz' - '@rush-temp/load-themed-styles': 'file:./projects/load-themed-styles.tgz' - '@rush-temp/loader-load-themed-styles': 'file:./projects/loader-load-themed-styles.tgz' - '@rush-temp/loader-raw-script': 'file:./projects/loader-raw-script.tgz' - '@rush-temp/localization-plugin': 'file:./projects/localization-plugin.tgz' - '@rush-temp/localization-plugin-test-01': 'file:./projects/localization-plugin-test-01.tgz' - '@rush-temp/localization-plugin-test-02': 'file:./projects/localization-plugin-test-02.tgz' - '@rush-temp/localization-plugin-test-03': 'file:./projects/localization-plugin-test-03.tgz' - '@rush-temp/node-core-library': 'file:./projects/node-core-library.tgz' - '@rush-temp/node-library-build': 'file:./projects/node-library-build.tgz' - '@rush-temp/node-library-build-eslint-test': 'file:./projects/node-library-build-eslint-test.tgz' - '@rush-temp/node-library-build-tslint-test': 'file:./projects/node-library-build-tslint-test.tgz' - '@rush-temp/package-deps-hash': 'file:./projects/package-deps-hash.tgz' - '@rush-temp/repo-toolbox': 'file:./projects/repo-toolbox.tgz' - '@rush-temp/rush': 'file:./projects/rush.tgz' - '@rush-temp/rush-buildxl': 'file:./projects/rush-buildxl.tgz' - '@rush-temp/rush-lib': 'file:./projects/rush-lib.tgz' - '@rush-temp/rush-stack-compiler-2.4': 'file:./projects/rush-stack-compiler-2.4.tgz' - '@rush-temp/rush-stack-compiler-2.4-library-test': 'file:./projects/rush-stack-compiler-2.4-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.7': 'file:./projects/rush-stack-compiler-2.7.tgz' - '@rush-temp/rush-stack-compiler-2.7-library-test': 'file:./projects/rush-stack-compiler-2.7-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.8': 'file:./projects/rush-stack-compiler-2.8.tgz' - '@rush-temp/rush-stack-compiler-2.8-library-test': 'file:./projects/rush-stack-compiler-2.8-library-test.tgz' - '@rush-temp/rush-stack-compiler-2.9': 'file:./projects/rush-stack-compiler-2.9.tgz' - '@rush-temp/rush-stack-compiler-2.9-library-test': 'file:./projects/rush-stack-compiler-2.9-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.0': 'file:./projects/rush-stack-compiler-3.0.tgz' - '@rush-temp/rush-stack-compiler-3.0-library-test': 'file:./projects/rush-stack-compiler-3.0-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.1': 'file:./projects/rush-stack-compiler-3.1.tgz' - '@rush-temp/rush-stack-compiler-3.1-library-test': 'file:./projects/rush-stack-compiler-3.1-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.2': 'file:./projects/rush-stack-compiler-3.2.tgz' - '@rush-temp/rush-stack-compiler-3.2-library-test': 'file:./projects/rush-stack-compiler-3.2-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.3': 'file:./projects/rush-stack-compiler-3.3.tgz' - '@rush-temp/rush-stack-compiler-3.3-library-test': 'file:./projects/rush-stack-compiler-3.3-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.4': 'file:./projects/rush-stack-compiler-3.4.tgz' - '@rush-temp/rush-stack-compiler-3.4-library-test': 'file:./projects/rush-stack-compiler-3.4-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.5': 'file:./projects/rush-stack-compiler-3.5.tgz' - '@rush-temp/rush-stack-compiler-3.5-library-test': 'file:./projects/rush-stack-compiler-3.5-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.6': 'file:./projects/rush-stack-compiler-3.6.tgz' - '@rush-temp/rush-stack-compiler-3.6-library-test': 'file:./projects/rush-stack-compiler-3.6-library-test.tgz' - '@rush-temp/rush-stack-compiler-3.7': 'file:./projects/rush-stack-compiler-3.7.tgz' - '@rush-temp/rush-stack-compiler-3.7-library-test': 'file:./projects/rush-stack-compiler-3.7-library-test.tgz' - '@rush-temp/rush-stack-compiler-shared': 'file:./projects/rush-stack-compiler-shared.tgz' - '@rush-temp/rushell': 'file:./projects/rushell.tgz' - '@rush-temp/set-webpack-public-path-plugin': 'file:./projects/set-webpack-public-path-plugin.tgz' - '@rush-temp/stream-collator': 'file:./projects/stream-collator.tgz' - '@rush-temp/ts-command-line': 'file:./projects/ts-command-line.tgz' - '@rush-temp/typings-generator': 'file:./projects/typings-generator.tgz' - '@rush-temp/web-library-build': 'file:./projects/web-library-build.tgz' - '@rush-temp/web-library-build-test': 'file:./projects/web-library-build-test.tgz' - '@types/argparse': 1.0.33 - '@types/chai': 3.4.34 - '@types/chalk': 0.4.31 - '@types/clean-css': 4.2.1 - '@types/eslint': 6.1.3 - '@types/estree': 0.0.39 - '@types/express': 4.11.0 - '@types/express-serve-static-core': 4.11.0 - '@types/fs-extra': 5.0.4 - '@types/glob': 7.1.1 - '@types/gulp': 4.0.6 - '@types/gulp-istanbul': 0.9.30 - '@types/gulp-mocha': 0.0.32 - '@types/inquirer': 0.0.43 - '@types/jest': 23.3.11 - '@types/jju': 1.4.1 - '@types/js-yaml': 3.12.1 - '@types/loader-utils': 1.1.3 - '@types/lodash': 4.14.116 - '@types/long': 4.0.0 - '@types/mime': 0.0.29 - '@types/minimatch': 2.0.29 - '@types/mocha': 5.2.5 - '@types/node': 10.17.13 - '@types/node-fetch': 1.6.9 - '@types/node-forge': 0.9.1 - '@types/node-notifier': 0.0.28 - '@types/node-sass': 4.11.0 - '@types/npm-package-arg': 6.1.0 - '@types/orchestrator': 0.0.30 - '@types/read-package-tree': 5.1.0 - '@types/resolve': 0.0.8 - '@types/semver': 5.3.33 - '@types/serve-static': 1.13.1 - '@types/sinon': 1.16.34 - '@types/source-map': 0.5.0 - '@types/strict-uri-encode': 2.0.0 - '@types/tapable': 1.0.4 - '@types/tar': 4.0.0 - '@types/through2': 2.0.32 - '@types/timsort': 0.3.0 - '@types/uglify-js': 2.6.29 - '@types/vinyl': 2.0.3 - '@types/webpack': 4.39.8 - '@types/webpack-dev-server': 3.1.7 - '@types/webpack-env': 1.13.0 - '@types/wordwrap': 1.0.0 - '@types/xmldoc': 1.1.4 - '@types/yargs': 0.0.34 - '@types/z-schema': 3.16.31 - '@typescript-eslint/eslint-plugin': 2.3.3 - '@typescript-eslint/experimental-utils': 2.3.3 - '@typescript-eslint/parser': 2.3.3 - '@typescript-eslint/typescript-estree': 2.3.3 - '@yarnpkg/lockfile': ~1.0.2 - argparse: ~1.0.9 - autoprefixer: ~9.7.4 - builtin-modules: ~3.1.0 - chai: ~3.5.0 - chokidar: ~3.3.1 - clean-css: 4.2.1 - cli-table: ~0.3.1 - colors: ~1.2.1 - deasync: ~0.1.19 - decache: ~4.5.1 - decomment: ~0.9.1 - del: ^2.2.2 - end-of-stream: ~1.1.0 - eslint: ~6.5.1 - eslint-plugin-promise: ~4.2.1 - eslint-plugin-react: ~7.16.0 - eslint-plugin-security: ~1.4.0 - eslint-plugin-tsdoc: ~0.2.1 - express: ~4.16.2 - fs-extra: ~7.0.1 - git-repo-info: ~2.1.0 - glob: ~7.0.5 - glob-escape: ~0.0.1 - globby: ~5.0.0 - gulp: ~4.0.2 - gulp-connect: ~5.5.0 - gulp-flatten: ~0.2.0 - gulp-if: ^2.0.1 - gulp-istanbul: ~0.10.3 - gulp-mocha: ~6.0.0 - gulp-open: ~3.0.1 - gulp-replace: ^0.5.4 - html-webpack-plugin: ~3.2.0 - https-proxy-agent: ~2.2.1 - inquirer: ~6.2.0 - jest: ~23.6.0 - jest-cli: ~22.4.3 - jest-environment-jsdom: ~22.4.3 - jest-nunit-reporter: ~1.3.1 - jest-resolve: ~22.4.3 - jju: ~1.4.0 - js-yaml: ~3.13.1 - jsdom: ~11.11.0 - loader-utils: ~1.1.0 - lodash: ~4.17.15 - lodash.merge: ~4.6.2 - long: ^4.0.0 - merge2: ~1.0.2 - minimatch: ~3.0.2 - mocha: ^5.2.0 - node-fetch: ~2.1.2 - node-forge: ~0.7.1 - node-notifier: ~5.0.2 - node-sass: 4.12.0 - npm-package-arg: ~6.1.0 - object-assign: ~4.1.0 - orchestrator: ~0.3.8 - postcss: 7.0.5 - postcss-modules: ~1.3.1 - pretty-hrtime: ~1.0.2 - pseudolocale: ~1.1.0 - read-package-tree: ~5.1.5 - resolve: 1.8.1 - semver: ~5.3.0 - sinon: ~1.17.3 - source-map: ~0.6.1 - strict-uri-encode: ~2.0.0 - sudo: ~1.0.3 - tar: ~4.4.1 - through2: ~2.0.1 - timsort: ~0.3.0 - true-case-path: ~2.2.1 - ts-jest: ~22.4.6 - ts-loader: 6.0.0 - tslint: ~5.12.1 - tslint-microsoft-contrib: ~5.2.1 - typescript: ~3.5.3 - uglify-js: ~3.0.28 - vinyl: ~2.2.0 - webpack: ~4.31.0 - webpack-bundle-analyzer: ~3.6.0 - webpack-cli: ~3.3.2 - webpack-dev-server: ~3.9.0 - wordwrap: ~1.0.0 - xml: ~1.0.1 - xmldoc: ~1.1.2 - yargs: ~4.6.0 - z-schema: ~3.18.3 diff --git a/common/config/rush/pnpmfile.js b/common/config/rush/pnpmfile.js deleted file mode 100644 index 435c2b0a4b5..00000000000 --- a/common/config/rush/pnpmfile.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; - -/** - * When using the PNPM package manager, you can use pnpmfile.js to workaround - * dependencies that have mistakes in their package.json file. (This feature is - * functionally similar to Yarn's "resolutions".) - * - * For details, see the PNPM documentation: - * https://pnpm.js.org/docs/en/hooks.html - * - * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE - * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run - * "rush update --full" so that PNPM will recalculate all version selections. - */ -module.exports = { - hooks: { - readPackage - } -}; - -/** - * This hook is invoked during installation before a package's dependencies - * are selected. - * The `packageJson` parameter is the deserialized package.json - * contents for the package that is about to be installed. - * The `context` parameter provides a log() function. - * The return value is the updated object. - */ -function readPackage(packageJson, context) { - // these packages have peerDependencies on typescript, but now we have multiple copies - // in the repo so it doesn't know which one to pick - // See this issue: https://github.com/pnpm/pnpm/issues/1187 - if (packageJson.name === 'tslint-microsoft-contrib' || packageJson.name === 'tslint' || packageJson.name === 'ts-jest' || packageJson.name === 'ts-loader') { - packageJson.dependencies['typescript'] = '~3.0.0'; - delete packageJson.peerDependencies['typescript']; - } - - return packageJson; -} diff --git a/common/config/rush/rush-plugins.json b/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..bee0e46c491 --- /dev/null +++ b/common/config/rush/rush-plugins.json @@ -0,0 +1,29 @@ +/** + * This configuration file manages Rush's plugin feature. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", + "plugins": [ + /** + * Each item configures a plugin to be loaded by Rush. + */ + // { + // /** + // * The name of the NPM package that provides the plugin. + // */ + // "packageName": "@scope/my-rush-plugin", + // /** + // * The name of the plugin. This can be found in the "pluginName" + // * field of the "rush-plugin-manifest.json" file in the NPM package folder. + // */ + // "pluginName": "my-plugin-name", + // /** + // * The name of a Rush autoinstaller that will be used for installation, which + // * can be created using "rush init-autoinstaller". Add the plugin's NPM package + // * to the package.json "dependencies" of your autoinstaller, then run + // * "rush update-autoinstaller". + // */ + // "autoinstallerName": "rush-plugins" + // } + ] +} diff --git a/common/config/rush/subspaces.json b/common/config/rush/subspaces.json new file mode 100644 index 00000000000..0f6f76b6f7b --- /dev/null +++ b/common/config/rush/subspaces.json @@ -0,0 +1,35 @@ +/** + * This configuration file manages the experimental "subspaces" feature for Rush, + * which allows multiple PNPM lockfiles to be used in a single Rush workspace. + * For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + + /** + * Set this flag to "true" to enable usage of subspaces. + */ + "subspacesEnabled": true, + + /** + * (DEPRECATED) This is a temporary workaround for migrating from an earlier prototype + * of this feature: https://github.com/microsoft/rushstack/pull/3481 + * It allows subspaces with only one project to store their config files in the project folder. + */ + "splitWorkspaceCompatibility": false, + + /** + * When a command such as "rush update" is invoked without the "--subspace" or "--to" + * parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces, + * this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this + * mistake by always requiring selection parameters for commands such as "rush update". + */ + "preventSelectingAllSubspaces": false, + + /** + * The list of subspace names, which should be lowercase alphanumeric words separated by + * hyphens, for example "my-subspace". The corresponding config files will have paths + * such as "common/config/subspaces/my-subspace/package-lock.yaml". + */ + "subspaceNames": ["build-tests-subspace"] +} diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index f6b3a6803ab..80628db04dd 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -1,13 +1,13 @@ /** * This is configuration file is used for advanced publishing configurations with Rush. - * For full documentation, please see https://rushjs.io + * More documentation is available on the Rush website: https://rushjs.io */ - /** - * A list of version policy definitions. A "version policy" is a custom package versioning - * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies - * to a set of projects that are specified using the "versionPolicyName" field in rush.json. - */ +/** + * A list of version policy definitions. A "version policy" is a custom package versioning + * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies + * to a set of projects that are specified using the "versionPolicyName" field in rush.json. + */ [ // { // /** @@ -20,30 +20,30 @@ // * SemVer range is usually restricted to a single version. // */ // "definitionName": "lockStepVersion", - // + // // /** // * (Required) The name that will be used for the "versionPolicyName" field in rush.json. // * This name is also used command-line parameters such as "--version-policy" // * and "--to-version-policy". // */ // "policyName": "MyBigFramework", - // + // // /** // * (Required) The current version. All packages belonging to the set should have this version // * in the current branch. When bumping versions, Rush uses this to determine the next version. // * (The "version" field in package.json is NOT considered.) // */ // "version": "1.0.0", - // + // // /** // * (Required) The type of bump that will be performed when publishing the next release. // * When creating a release branch in Git, this field should be updated according to the // * type of release. // * - // * Valid values are: "prerelease", "release", "minor", "patch", "major" + // * Valid values are: "prerelease", "preminor", "minor", "patch", "major" // */ // "nextBump": "prerelease", - // + // // /** // * (Optional) If specified, all packages in the set share a common CHANGELOG.md file. // * This file is stored with the specified "main" project, which must be a member of the set. @@ -51,9 +51,19 @@ // * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each // * package in the set. // */ - // "mainProject": "my-app" + // "mainProject": "my-app", + // + // /** + // * (Optional) If enabled, the "rush change" command will prompt the user for their email address + // * and include it in the JSON change files. If an organization maintains multiple repos, tracking + // * this contact information may be useful for a service that automatically upgrades packages and + // * needs to notify engineers whose change may be responsible for a downstream build break. It might + // * also be useful for crediting contributors. Rush itself does not do anything with the collected + // * email addresses. The default value is "false". + // */ + // // "includeEmailInChangeFile": true // }, - // + // // { // /** // * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). @@ -66,9 +76,9 @@ // * is changed. // */ // "definitionName": "individualVersion", - // + // // "policyName": "MyRandomLibraries", - // + // // /** // * (Optional) This can be used to enforce that all packages in the set must share a common // * major version number, e.g. because they are from the same major release branch. @@ -77,7 +87,7 @@ // * to the types of changes made to each project, according to the "rush change" command. // */ // "lockedMajor": 3, - // + // // /** // * (Optional) When publishing is managed by Rush, by default the "rush change" command will // * request changes for any projects that are modified by a pull request. These change entries @@ -85,12 +95,14 @@ // * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects // * belonging to this version policy. // */ - // "exemptFromRushChange": false + // "exemptFromRushChange": false, + // + // // "includeEmailInChangeFile": true // } { "policyName": "rush", "definitionName": "lockStepVersion", - "version": "5.22.0", + "version": "5.163.0", "nextBump": "minor", "mainProject": "@microsoft/rush" } diff --git a/common/config/subspaces/build-tests-subspace/.npmrc b/common/config/subspaces/build-tests-subspace/.npmrc new file mode 100644 index 00000000000..9ececc1f20b --- /dev/null +++ b/common/config/subspaces/build-tests-subspace/.npmrc @@ -0,0 +1,32 @@ +# Rush uses this file to configure the NPM package registry during installation. It is applicable +# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install", +# "rush update", and the "install-run.js" scripts. +# +# NOTE: The "rush publish" command uses .npmrc-publish instead. +# +# Before invoking the package manager, Rush will generate an .npmrc in the folder where installation +# is performed. This generated file will omit any config lines that reference environment variables +# that are undefined in that session; this avoids problems that would otherwise result due to +# a missing variable being replaced by an empty string. +# +# If "subspacesEnabled" is true in subspaces.json, the generated file will merge settings from +# "common/config/rush/.npmrc" and "common/config/subspaces//.npmrc", with the latter taking +# precedence. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read that file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# +registry=https://registry.npmjs.org/ +always-auth=false +# No phantom dependencies allowed in this repository +# Don't hoist in common/temp/node_modules +public-hoist-pattern= +# Don't hoist in common/temp/node_modules/.pnpm/node_modules +hoist=false +hoist-pattern= diff --git a/common/config/subspaces/build-tests-subspace/.pnpmfile.cjs b/common/config/subspaces/build-tests-subspace/.pnpmfile.cjs new file mode 100644 index 00000000000..b7821599ca7 --- /dev/null +++ b/common/config/subspaces/build-tests-subspace/.pnpmfile.cjs @@ -0,0 +1,68 @@ +'use strict'; + +/** + * When using the PNPM package manager, you can use pnpmfile.js to workaround + * dependencies that have mistakes in their package.json file. (This feature is + * functionally similar to Yarn's "resolutions".) + * + * For details, see the PNPM documentation: + * https://pnpm.io/pnpmfile#hooks + * + * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE + * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run + * "rush update --full" so that PNPM will recalculate all version selections. + */ +module.exports = { + hooks: { + readPackage + } +}; + +function fixUndeclaredDependency(packageJson, dependencyName) { + packageJson.dependencies[dependencyName] = + packageJson.dependencies[dependencyName] || + packageJson.devDependencies?.[dependencyName] || + packageJson.version; +} + +/** + * This hook is invoked during installation before a package's dependencies + * are selected. + * The `packageJson` parameter is the deserialized package.json + * contents for the package that is about to be installed. + * The `context` parameter provides a log() function. + * The return value is the updated object. + */ +function readPackage(packageJson, context) { + if (packageJson.name.startsWith('@radix-ui/')) { + if (packageJson.peerDependencies && packageJson.peerDependencies['react']) { + packageJson.peerDependencies['@types/react'] = '*'; + packageJson.peerDependencies['@types/react-dom'] = '*'; + } + } + + switch (packageJson.name) { + case '@jest/test-result': { + // The `@jest/test-result` package takes undeclared dependencies on `jest-haste-map` + // and `jest-resolve` + fixUndeclaredDependency(packageJson, 'jest-haste-map'); + fixUndeclaredDependency(packageJson, 'jest-resolve'); + } + + case '@serverless-stack/core': { + delete packageJson.dependencies['@typescript-eslint/eslint-plugin']; + delete packageJson.dependencies['eslint-config-serverless-stack']; + delete packageJson.dependencies['lerna']; + break; + } + + case '@typescript-eslint/rule-tester': { + // The `@typescript-eslint/rule-tester` package takes an undeclared dependency + // on `@typescript-eslint/parser` + fixUndeclaredDependency(packageJson, '@typescript-eslint/parser'); + break; + } + } + + return packageJson; +} diff --git a/common/config/subspaces/build-tests-subspace/common-versions.json b/common/config/subspaces/build-tests-subspace/common-versions.json new file mode 100644 index 00000000000..0d5cf26de52 --- /dev/null +++ b/common/config/subspaces/build-tests-subspace/common-versions.json @@ -0,0 +1,123 @@ +/** + * 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", + + /** + * A table that specifies a "preferred version" for a given NPM package. This feature is typically used + * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. + * + * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into + * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager + * will calculate versions. The specific effect depends on your package manager. Generally it will have no + * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be + * achieved using the pnpmfile.js hook. See the Rush documentation for more details. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + "preferredVersions": { + /** + * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, + * instead of the latest version. + */ + // "some-library": "1.2.3" + + // This should be the TypeScript version that's used to build most of the projects in the repo. + // 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.8.2", + + // Workaround for https://github.com/microsoft/rushstack/issues/1466 + "eslint": "~9.25.1" + }, + + /** + * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, + * except in cases where different projects specify different version ranges for a given dependency. For older + * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause + * trouble for indirect dependencies with incompatible peerDependencies ranges. + * + * The default value is true. If you're encountering installation errors related to peer dependencies, + * it's recommended to set this to false. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + // "implicitlyPreferredVersions": false, + + /** + * If you would like the version specifiers for your dependencies to be consistent, then + * uncomment this line. This is effectively similar to running "rush check" before any + * of the following commands: + * + * rush install, rush update, rush link, rush version, rush publish + * + * In some cases you may want this turned on, but need to allow certain packages to use a different + * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" + * section of the common-versions.json. + * + * In the case that subspaces is enabled, this setting will take effect at a subspace level. + */ + "ensureConsistentVersions": true, + + /** + * The "rush check" command can be used to enforce that every project in the repo must specify + * the same SemVer range for a given dependency. However, sometimes exceptions are needed. + * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be + * accepted by "rush check" for a given dependency. + * + * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE + * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). + * This design avoids unnecessary churn in this file. + */ + "allowedAlternativeVersions": { + /** + * 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): + */ + "typescript": [ + // "~5.0.4" is the (inferred, not alternative) range used by most projects in this repo + + // The oldest supported compiler, used by build-tests/api-extractor-lib1-test + "~2.9.2", + // For testing Heft with TS V3 + "~3.9.10", + // For testing Heft with TS V4 + "~4.9.5" + ], + "source-map": [ + "~0.6.1" // API Extractor is using an older version of source-map because newer versions are async + ], + "tapable": [ + "2.2.1", + "1.1.3" // heft plugin is using an older version of tapable + ], + // --- For Webpack 4 projects ---- + "css-loader": ["~5.2.7"], + "html-webpack-plugin": ["~4.5.2"], + "postcss-loader": ["~4.1.0"], + "sass-loader": ["~10.0.0"], + "sass": ["~1.3.0"], + "source-map-loader": ["~1.1.3"], + "style-loader": ["~2.0.0"], + "terser-webpack-plugin": ["~3.0.8"], + "terser": ["~4.8.0"], + "webpack": ["~4.47.0"], + "@types/node": [ + // These versions are used by testing projects + "ts2.9", + "ts3.9", + "ts4.9" + ], + "@types/jest": [ + // These versions are used by testing projects + "ts2.9", + "ts3.9", + "ts4.9" + ] + } +} diff --git a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml new file mode 100644 index 00000000000..9f1474f6bff --- /dev/null +++ b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml @@ -0,0 +1,8223 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +overrides: + package-json: ^7 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/eslint-plugin': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/utils': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/parser': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/typescript-estree': ~8.46.0 + '@rushstack/eslint-plugin@0.20.0>@typescript-eslint/utils': ~8.46.0 + '@rushstack/heft-node-rig@2.10.1>eslint': ~9.37.0 + +packageExtensionsChecksum: e59cfa9a35183eeeb6f2ac48c9ddd4b2 + +importers: + + .: {} + + ../../../build-tests-subspace/rush-lib-test: + dependencies: + '@microsoft/rush-lib': + specifier: file:../../libraries/rush-lib + version: file:../../../libraries/rush-lib(@types/node@20.17.19) + '@rushstack/terminal': + specifier: file:../../libraries/terminal + version: file:../../../libraries/terminal(@types/node@20.17.19) + devDependencies: + '@rushstack/heft': + specifier: file:../../apps/heft + version: file:../../../apps/heft(@types/node@20.17.19) + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.25.1 + version: 9.25.1 + local-node-rig: + specifier: file:../../rigs/local-node-rig + version: file:../../../rigs/local-node-rig + dependenciesMeta: + '@microsoft/rush-lib': + injected: true + '@rushstack/heft': + injected: true + '@rushstack/terminal': + 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@20.17.19) + devDependencies: + '@microsoft/rush-lib': + specifier: file:../../libraries/rush-lib + version: file:../../../libraries/rush-lib(@types/node@20.17.19) + '@rushstack/heft': + specifier: file:../../apps/heft + version: file:../../../apps/heft(@types/node@20.17.19) + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.25.1 + version: 9.25.1 + local-node-rig: + specifier: file:../../rigs/local-node-rig + version: file:../../../rigs/local-node-rig + dependenciesMeta: + '@microsoft/rush-lib': + injected: true + '@rushstack/heft': + injected: true + '@rushstack/rush-sdk': + injected: true + local-node-rig: + injected: true + + ../../../build-tests-subspace/typescript-newest-test: + devDependencies: + '@rushstack/heft': + specifier: file:../../apps/heft + version: file:../../../apps/heft(@types/node@20.17.19) + eslint: + 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.8.2 + version: 5.8.2 + dependenciesMeta: + '@rushstack/heft': + injected: true + local-node-rig: + injected: true + + ../../../build-tests-subspace/typescript-v4-test: + devDependencies: + '@rushstack/eslint-config': + specifier: file:../../eslint/eslint-config + 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@20.17.19) + '@rushstack/heft-lint-plugin': + specifier: file:../../heft-plugins/heft-lint-plugin + version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@1.1.5)(@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@1.1.5)(@types/node@20.17.19) + eslint: + 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 + '@rushstack/heft': + injected: true + '@rushstack/heft-lint-plugin': + injected: true + '@rushstack/heft-typescript-plugin': + injected: true + + ../../../build-tests/webpack-local-version-test: + devDependencies: + '@rushstack/heft': + specifier: link:../../apps/heft + version: link:../../apps/heft + '@rushstack/heft-lint-plugin': + specifier: link:../../heft-plugins/heft-lint-plugin + version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-typescript-plugin': + 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.98.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + +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.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + 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==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.26.0: + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + 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==} + 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==} + 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==} + 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==} + 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==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-string-parser@7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.25.9: + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.26.0: + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + 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==} + 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): + 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): + 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): + 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): + 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==} + 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): + 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): + 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==} + 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): + 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): + 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): + 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): + 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): + 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): + 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): + 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): + 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==} + 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==} + 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==} + 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==} + 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: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@devexpress/error-stack-parser@2.0.6: + resolution: {integrity: sha512-fneVypElGUH6Be39mlRZeAu00pccTlf4oVuzf9xPJD1cdEqI8NyAiQua/EW7lZdrbMUbgyXcJmfKPefhYius3A==} + dependencies: + stackframe: 1.3.4 + + /@es-joy/jsdoccomment@0.49.0: + resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} + engines: {node: '>=16'} + dependencies: + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 4.1.0 + dev: true + + /@eslint-community/eslint-utils@4.4.1(eslint@9.25.1): + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.25.1 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.4.1(eslint@9.37.0): + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.9.0(eslint@9.25.1): + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.25.1 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.9.0(eslint@9.37.0): + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/config-array@0.20.0: + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/config-array@0.21.0: + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/config-helpers@0.2.1: + resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/config-helpers@0.4.0: + resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + dev: true + + /@eslint/core@0.13.0: + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true + + /@eslint/core@0.16.0: + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true + + /@eslint/eslintrc@3.3.1: + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.3.0 + globals: 14.0.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/js@9.25.1: + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/js@9.37.0: + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/object-schema@2.1.6: + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/plugin-kit@0.2.8: + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + dev: true + + /@eslint/plugin-kit@0.4.0: + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + dev: true + + /@humanfs/core@0.19.1: + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + dev: true + + /@humanfs/node@0.16.6: + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/retry@0.3.1: + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + dev: true + + /@humanwhocodes/retry@0.4.2: + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + dev: true + + /@inquirer/external-editor@1.0.1(@types/node@20.17.19): + resolution: {integrity: sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.17.19 + chardet: 2.1.0 + iconv-lite: 0.6.3 + + /@isaacs/balanced-match@4.0.1: + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + /@isaacs/brace-expansion@5.0.0: + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/balanced-match': 4.0.1 + + /@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: + 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': 20.17.19 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@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 + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.5.0 + '@jest/test-result': 29.7.0(@types/node@20.17.19) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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.17.19) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.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': 20.17.19 + jest-mock: 29.7.0 + dev: true + + /@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/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': 20.17.19 + 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/reporters@29.5.0: + 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 + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0(@types/node@20.17.19) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/node': 20.17.19 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2(@types/node@20.17.19) + 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/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/test-result@29.7.0(@types/node@20.17.19): + 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@20.17.19) + jest-haste-map: 29.7.0 + jest-resolve: 29.7.0 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@jest/test-sequencer@29.7.0(@types/node@20.17.19): + 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@20.17.19) + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@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/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/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': 20.17.19 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + dev: true + + /@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/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==} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + /@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 + + /@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 + 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 + dependencies: + jsep: 1.4.0 + + /@microsoft/tsdoc-config@0.18.0: + resolution: {integrity: sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==} + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + dev: true + + /@microsoft/tsdoc@0.16.0: + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + /@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: + resolution: {integrity: sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==} + engines: {node: '>=16.14'} + dependencies: + rfc4648: 1.5.3 + + /@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.hash@1000.1.1: + resolution: {integrity: sha512-lb5kwXaOXdIW/4bkLLmtM9HEVRvp2eIvp+TrdawcPoaptgA/5f0/sRG0P52BF8dFqeNDj+1tGdqH89WQEqJnxA==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.0.0 + ssri: 10.0.5 + + /@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'} + dependencies: + '@pnpm/crypto.hash': 1000.1.1 + '@pnpm/types': 1000.6.0 + semver: 7.7.2 + + /@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.7.2 + + /@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.7.2 + + /@pnpm/error@1.4.0: + resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} + engines: {node: '>=10.16'} + + /@pnpm/graceful-fs@1000.0.0: + resolution: {integrity: sha512-RvMEliAmcfd/4UoaYQ93DLQcFeqit78jhYmeJJVPxqFGmj0jEcb9Tu0eAOXr7tGP3eJHpgvPbTU4o6pZ1bJhxg==} + engines: {node: '>=18.12'} + dependencies: + graceful-fs: 4.2.11 + + /@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==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + dev: false + + /@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==} + engines: {node: '>=18.12'} + dev: false + + /@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: + 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: + 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@1000.6.0: + resolution: {integrity: sha512-6PsMNe98VKPGcg6LnXSW/LE3YfJ77nj+bPKiRjYRWAQLZ+xXjEQRaR0dAuyjCmchlv4wR/hpnMVRS21/fCod5w==} + 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/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 + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sindresorhus/is@4.6.0: + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + + /@szmarczak/http-timer@4.0.6: + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + dependencies: + defer-to-connect: 2.0.1 + + /@types/argparse@1.0.38: + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + /@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 + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@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 + + /@types/babel__traverse@7.20.6: + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@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': 20.17.19 + '@types/responselike': 1.0.3 + + /@types/eslint-scope@3.7.7: + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.7 + dev: true + + /@types/eslint@9.6.1: + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + dependencies: + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + dev: true + + /@types/estree@1.0.7: + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 20.17.19 + dev: true + + /@types/heft-jest@1.0.1: + resolution: {integrity: sha512-cF2iEUpvGh2WgLowHVAdjI05xuDo+GwCA8hGV3Q5PBl8apjd6BTcpPFQ2uPlfUM7BLpgur2xpYo8VeBXopMI4A==} + dependencies: + '@types/jest': 29.5.14 + dev: true + + /@types/html-minifier-terser@6.1.0: + resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} + dev: true + + /@types/http-cache-semantics@4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + /@types/istanbul-lib-coverage@2.0.4: + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: true + + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@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 + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + dev: true + + /@types/jest@29.5.14: + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/keyv@3.1.4: + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + dependencies: + '@types/node': 20.17.19 + + /@types/lodash@4.17.13: + resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + + /@types/minimatch@3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + + /@types/minimist@1.2.5: + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + + /@types/node@20.17.19: + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} + dependencies: + undici-types: 6.19.8 + + /@types/normalize-package-data@2.4.4: + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + /@types/prettier@2.7.3: + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + dev: true + + /@types/responselike@1.0.3: + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + dependencies: + '@types/node': 20.17.19 + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + dev: true + + /@types/tapable@1.0.6: + resolution: {integrity: sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==} + dev: true + + /@types/webpack-env@1.18.8: + resolution: {integrity: sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==} + dev: true + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.33: + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.25.1)(typescript@4.9.5): + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/type-utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + eslint: 9.25.1 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + eslint: 9.37.0 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.46.0(eslint@9.25.1)(typescript@4.9.5): + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + debug: 4.3.7 + eslint: 9.25.1 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + debug: 4.3.7 + eslint: 9.37.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/project-service@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + debug: 4.3.7 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/project-service@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + debug: 4.3.7 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/scope-manager@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/tsconfig-utils@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 4.9.5 + dev: true + + /@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 5.8.2 + dev: true + + /@typescript-eslint/type-utils@8.46.0(eslint@9.25.1)(typescript@4.9.5): + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + debug: 4.3.7 + eslint: 9.25.1 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + debug: 4.3.7 + eslint: 9.37.0 + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + dependencies: + typescript: 4.9.5 + dev: true + + /@typescript-eslint/types@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + dependencies: + typescript: 5.8.2 + dev: true + + /@typescript-eslint/typescript-estree@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@4.9.5) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.8.2) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@8.46.0(eslint@9.25.1)(typescript@4.9.5): + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.25.1) + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + eslint: 9.25.1 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + eslint: 9.37.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/visitor-keys@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + eslint-visitor-keys: 4.2.1 + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/visitor-keys@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + eslint-visitor-keys: 4.2.1 + transitivePeerDependencies: + - typescript + dev: true + + /@ungap/structured-clone@1.3.0: + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + /@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 + + /@vue/compiler-dom@3.5.13: + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + /@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 + + /@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 + + /@vue/shared@3.5.13: + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + /@webassemblyjs/ast@1.14.1: + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + dev: true + + /@webassemblyjs/floating-point-hex-parser@1.13.2: + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + dev: true + + /@webassemblyjs/helper-api-error@1.13.2: + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + dev: true + + /@webassemblyjs/helper-buffer@1.14.1: + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + dev: true + + /@webassemblyjs/helper-numbers@1.13.2: + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/helper-wasm-bytecode@1.13.2: + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + dev: true + + /@webassemblyjs/helper-wasm-section@1.14.1: + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + 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 + dev: true + + /@webassemblyjs/ieee754@1.13.2: + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + dependencies: + '@xtuc/ieee754': 1.2.0 + dev: true + + /@webassemblyjs/leb128@1.13.2: + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + dependencies: + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/utf8@1.13.2: + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + dev: true + + /@webassemblyjs/wasm-edit@1.14.1: + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + 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 + dev: true + + /@webassemblyjs/wasm-gen@1.14.1: + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + 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 + dev: true + + /@webassemblyjs/wasm-opt@1.14.1: + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + dev: true + + /@webassemblyjs/wasm-parser@1.14.1: + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + 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 + dev: true + + /@webassemblyjs/wast-printer@1.14.1: + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + dev: true + + /@xtuc/ieee754@1.2.0: + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + dev: true + + /@xtuc/long@4.2.2: + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + dev: true + + /@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'} + 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): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + dev: true + + /acorn-jsx@5.3.2(acorn@8.15.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.15.0 + dev: true + + /acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /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): + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.13.0 + + /ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + dependencies: + ajv: 8.13.0 + dev: true + + /ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + dependencies: + ajv: 8.13.0 + + /ajv-keywords@5.1.0(ajv@8.13.0): + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + dependencies: + ajv: 8.13.0 + fast-deep-equal: 3.1.3 + dev: true + + /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@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@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 + + /ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + dependencies: + string-width: 4.2.3 + + /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: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + /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 + + /are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + is-array-buffer: 3.0.4 + dev: true + + /array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + 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==} + 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-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + 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.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + dev: true + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.5 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + dev: true + + /arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + dev: true + + /arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + + /arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + /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} + 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-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-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-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + 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} + 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 + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /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 + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /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 + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /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==} + 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: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /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: + 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: + 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-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + dev: true + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + 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 + + /call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.0 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: true + + /call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + 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 + + /callsite@1.0.0: + resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + dependencies: + pascal-case: 3.1.2 + tslib: 2.8.1 + 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 + + /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-lite@1.0.30001686: + resolution: {integrity: sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + /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==} + + /chardet@2.1.0: + resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + /chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + dev: true + + /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 + + /clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} + dependencies: + source-map: 0.6.1 + dev: true + + /cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + 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 + + /clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + dependencies: + mimic-response: 1.0.1 + + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + /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'} + + /collect-v8-coverage@1.0.2(@types/node@20.17.19): + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + peerDependencies: + '@types/node': '>=12' + dependencies: + '@types/node': 20.17.19 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /colors@1.0.3: + resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} + engines: {node: '>=0.1.90'} + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true + + /commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + dev: true + + /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==} + + /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 + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /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: + 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==} + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + dev: true + + /css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + dev: true + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /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==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + + /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==} + 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: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /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: + 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: + 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 + + /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.7.2 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + + /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.6.3 + + /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: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /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==} + engines: {node: '>=0.3.1'} + dev: true + + /diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + 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 + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-converter@0.2.0: + resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} + dependencies: + utila: 0.4.0 + dev: true + + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: true + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: true + + /dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dev: true + + /dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + + /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'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: true + + /electron-to-chromium@1.5.68: + resolution: {integrity: sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==} + dev: true + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + /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.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: true + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + + /es-abstract@1.23.5: + resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} + 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-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + 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.0.0 + 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-regex: 1.2.1 + 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.3 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + dev: true + + /es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + dev: true + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + 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 + safe-array-concat: 1.1.3 + dev: true + + /es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + dev: true + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + 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'} + dependencies: + hasown: 2.0.2 + dev: true + + /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: + 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: + 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'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /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.1(eslint@9.37.0): + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + eslint: '*' + peerDependenciesMeta: + eslint: + optional: true + dependencies: + debug: 3.2.7 + eslint: 9.37.0 + dev: true + + /eslint-plugin-header@3.1.1(eslint@9.37.0): + resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} + peerDependencies: + eslint: '>=7.7.0' + dependencies: + eslint: 9.37.0 + dev: true + + /eslint-plugin-headers@1.2.1(eslint@9.37.0): + resolution: {integrity: sha512-1L41t3DPrXFP6YLK+sAj0xDMGVHpQwI+uGefDwc1bKP91q65AIZoXzQgI7MjZJxB6sK8/vYhXMD8x0V8xLNxJA==} + engines: {node: ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 9.37.0 + dev: true + + /eslint-plugin-import@2.32.0(eslint@9.37.0): + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + 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.2 + 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: true + + /eslint-plugin-jsdoc@50.6.11(eslint@9.37.0): + resolution: {integrity: sha512-k4+MnBCGR8cuIB5MZ++FGd4gbXxjob2rX1Nq0q3nWFF4xSGZENTgTLZSjb+u9B8SAnP6lpGV2FJrBjllV3pVSg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@es-joy/jsdoccomment': 0.49.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint: 9.37.0 + espree: 10.3.0 + esquery: 1.6.0 + parse-imports-exports: 0.2.4 + semver: 7.7.2 + spdx-expression-parse: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-promise@7.2.1(eslint@9.25.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 + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.25.1) + eslint: 9.25.1 + dev: true + + /eslint-plugin-promise@7.2.1(eslint@9.37.0): + 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 + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.37.0) + eslint: 9.37.0 + dev: true + + /eslint-plugin-react-hooks@5.2.0(eslint@9.37.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 + dependencies: + eslint: 9.37.0 + dev: true + + /eslint-plugin-react@7.37.5(eslint@9.25.1): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.8 + 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.2.1 + eslint: 9.25.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + 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.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + dev: true + + /eslint-plugin-react@7.37.5(eslint@9.37.0): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.8 + 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.2.1 + eslint: 9.37.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + 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.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + dev: true + + /eslint-plugin-tsdoc@0.5.0(eslint@9.25.1)(typescript@4.9.5): + resolution: {integrity: sha512-ush8ehCwub2rgE16OIgQPFyj/o0k3T8kL++9IrAI4knsmupNo8gvfO2ERgDHWWgTC5MglbwLVRswU93HyXqNpw==} + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + dev: true + + /eslint-plugin-tsdoc@0.5.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-ush8ehCwub2rgE16OIgQPFyj/o0k3T8kL++9IrAI4knsmupNo8gvfO2ERgDHWWgTC5MglbwLVRswU93HyXqNpw==} + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /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-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /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} + dev: 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 + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.25.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.1 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.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.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + 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 + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.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.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + dev: true + + /espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + dev: true + + /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==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /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@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /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==} + 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 + + /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: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /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 + + /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 + + /file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + dependencies: + flat-cache: 4.0.1 + dev: true + + /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: + 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: + 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@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + dev: true + + /flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + dev: true + + /fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.5 + functions-have-names: 1.2.3 + dev: true + + /function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + 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 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /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==} + 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-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + 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 + dev: true + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + dev: true + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.2 + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + dev: true + + /get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + dev: true + + /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'} + + /giturl@2.0.0: + resolution: {integrity: sha512-FB0MmghWLcqsyrBZyqsLCNeS2kIzYymT34t/6BxM5R0/9Pxvj0K1eK25SBbwRHMjKMLgQ7nYqBSduF6XyfkgFg==} + engines: {node: '>= 14.17.0'} + + /glob-escape@0.0.2: + resolution: {integrity: sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==} + engines: {node: '>= 0.10'} + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /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 + + /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 + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + /globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + dev: true + + /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.2.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==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.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: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /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-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + dev: true + + /has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + dev: true + + /has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + dev: true + + /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'} + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: 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 + + /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@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + 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.44.0 + dev: true + + /html-webpack-plugin@5.5.4(webpack@5.98.0): + resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} + engines: {node: '>=10.13.0'} + peerDependencies: + webpack: ^5.20.0 || ^4 || ^5 + dependencies: + '@types/html-minifier-terser': 6.1.0 + html-minifier-terser: 6.1.0 + lodash: 4.17.21 + pretty-error: 4.0.0 + tapable: 2.2.1 + webpack: 5.98.0 + dev: true + + /htmlparser2@6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 2.2.0 + dev: true + + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + /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 + + /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: + 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 + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + 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.1.2 + + /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'} + dev: true + + /immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /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'} + + /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'} + + /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: + 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 + + /inquirer@8.2.7(@types/node@20.17.19): + resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} + engines: {node: '>=12.0.0'} + dependencies: + '@inquirer/external-editor': 1.0.1(@types/node@20.17.19) + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + figures: 3.0.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 6.2.0 + transitivePeerDependencies: + - '@types/node' + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + dev: true + + /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.1.0 + dev: true + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.2.4 + dev: true + + /is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + has-tostringtag: 1.0.2 + dev: true + + /is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + + /is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: true + + /is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /is-es2016-keyword@1.0.0: + resolution: {integrity: sha512-JtZWPUwjdbQ1LIo9OSZ8MdkWEve198ors27vH+RzUUvZXXZkzXCxFnlUhzWYxy5IexQSRiXVw9j2q/tHMmkVYQ==} + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + /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==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /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: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + has-tostringtag: 1.0.2 + dev: true + + /is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /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: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + /is-regex@1.2.0: + resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + gopd: 1.1.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + dev: true + + /is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: true + + /is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + dev: true + + /is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + dev: true + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.16 + dev: true + + /is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.19 + dev: true + + /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'} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.8 + dev: true + + /is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + dev: true + + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + dev: true + + /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: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /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-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==} + 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==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + 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 + 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 + + /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@20.17.19) + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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-config@29.5.0(@types/node@20.17.19): + 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 + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.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-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-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': 20.17.19 + 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': 20.17.19 + 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': 20.17.19 + 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-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-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-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-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': 20.17.19 + jest-util: 29.7.0 + dev: true + + /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 + 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@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@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@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-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@20.17.19) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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@20.17.19) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2(@types/node@20.17.19) + 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.7.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.7.2 + 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.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /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': 20.17.19 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /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-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@20.17.19) + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 20.17.19 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /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': 20.17.19 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + /js-tokens@3.0.2: + resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + + /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: + 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==} + engines: {node: '>=6'} + hasBin: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /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: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /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: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.7 + object.values: 1.2.1 + dev: true + + /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: + 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: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + + /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: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + dependencies: + immediate: 3.0.6 + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + /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.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + + /loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.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: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + /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: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: true + + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.8.1 + dev: true + + /lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /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: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.7.2 + dev: true + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /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'} + dev: true + + /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: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 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: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: 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-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + /minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + 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: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + /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.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + 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 + + /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: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + /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@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + + /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} + hasBin: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + dev: true + + /node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + dependencies: + lodash: 4.17.21 + + /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 + + /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: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.15.1 + semver: 7.7.2 + validate-npm-package-license: 3.0.4 + + /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.6.3 + 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-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + + /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'} + 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: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + /object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + dev: true + + /object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + dev: true + + /object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + 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 + dev: true + + /object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /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.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: true + + /object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + + /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: + 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. + dependencies: + os-homedir: 1.0.2 + os-tmpdir: 1.0.2 + + /own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + dev: true + + /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-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.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: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.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: + resolution: {integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==} + engines: {node: '>=8'} + + /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: + 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.7.2 + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + /param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + dependencies: + parse-statements: 1.0.11 + dev: true + + /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==} + dev: true + + /pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + 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'} + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + 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.3.2: + resolution: {integrity: sha512-XlHyNAHlBqIMGTBD0HfgyRyj1UpSJvVyP20ihPek00YKmMb7RJ16AxlQkjT1jQ/D6s6OAT0ety/tSxcJTrvQ4w==} + dependencies: + '@pnpm/dependency-path-2': /@pnpm/dependency-path@2.1.8 + '@pnpm/dependency-path-5': /@pnpm/dependency-path@5.1.7 + yaml: 2.4.1 + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + 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: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /pretty-error@4.0.0: + resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + dependencies: + lodash: 4.17.21 + renderkid: 3.0.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 + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + /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: + 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 + + /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: + resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /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: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + + /react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + dev: true + + /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: + 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: + 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: + 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: + 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: + 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.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + dev: true + + /reflect.getprototypeof@1.0.7: + resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + which-builtin-type: 1.2.0 + dev: true + + /regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + dev: true + + /regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.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 + 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'} + dev: true + + /renderkid@3.0.0: + resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + dependencies: + css-select: 4.3.0 + dom-converter: 0.2.0 + htmlparser2: 6.1.0 + lodash: 4.17.21 + strip-ansi: 6.0.1 + dev: true + + /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-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: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + /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==} + 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==} + 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==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + + /run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + dependencies: + tslib: 1.14.1 + + /rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + dependencies: + tslib: 2.8.1 + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.2.4 + has-symbols: 1.1.0 + isarray: 2.0.5 + dev: true + + /safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + 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 + dev: true + + /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-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-regex: 1.2.0 + dev: true + + /safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + /schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.13.0 + ajv-formats: 2.1.1 + ajv-keywords: 5.1.0(ajv@8.13.0) + dev: true + + /semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + /semver-diff@3.1.1: + resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + + /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 + dependencies: + lru-cache: 6.0.0 + + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + /semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + dev: true + + /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: + 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: + 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'} + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + dev: true + + /side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.3 + dev: true + + /side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + dev: true + + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.3 + dev: true + + /side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + /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: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /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: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + /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-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 + dev: true + + /spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + + /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} + dependencies: + minipass: 7.1.2 + + /ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.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'} + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + dev: true + + /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-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: + 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.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + 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.3 + set-function-name: 2.0.2 + side-channel: 1.1.0 + dev: true + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: true + + /string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + 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.23.9 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + dev: true + + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.5 + es-object-atoms: 1.1.1 + 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'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + + /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: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + dependencies: + ansi-regex: 4.1.1 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /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-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: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-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: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /tapable@1.1.3: + resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} + engines: {node: '>=6'} + dev: true + + /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==} + 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 + + /terser-webpack-plugin@5.3.14(webpack@5.98.0): + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + 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 + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.44.0 + webpack: 5.98.0 + dev: true + + /terser@5.44.0: + resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + + /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: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + 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==} + + /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 + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + + /true-case-path@2.2.1: + resolution: {integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==} + + /ts-api-utils@2.1.0(typescript@4.9.5): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 4.9.5 + dev: true + + /ts-api-utils@2.1.0(typescript@5.8.2): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 5.8.2 + dev: true + + /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: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + /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' + 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): + 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 + + /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: + 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: + 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'} + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + dev: true + + /typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + dev: true + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + 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-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + dev: true + + /typed-array-byte-offset@1.0.3: + resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + 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-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.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + dev: true + + /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.8 + for-each: 0.3.3 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.7 + dev: true + + /typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.8 + 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'} + dependencies: + call-bound: 1.0.4 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + dev: true + + /undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + /unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + dependencies: + crypto-random-string: 2.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==} + 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.7.2 + semver-diff: 3.1.1 + xdg-basedir: 4.0.0 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /utila@0.4.0: + resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + /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.6 + convert-source-map: 2.0.0 + dev: true + + /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: + resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} + dependencies: + builtins: 1.0.3 + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /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 + + /watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + 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 + + /webpack-sources@3.3.3: + resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + engines: {node: '>=10.13.0'} + dev: true + + /webpack@5.98.0: + resolution: {integrity: sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.7 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + browserslist: 4.24.2 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.3 + es-module-lexer: 1.7.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 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.14(webpack@5.98.0) + watchpack: 2.4.4 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + dev: true + + /which-boxed-primitive@1.1.0: + resolution: {integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==} + 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-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.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + dev: true + + /which-builtin-type@1.2.0: + resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + 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.1.0 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.0 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + dev: true + + /which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + dependencies: + 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.1.0 + is-finalizationregistry: 1.1.0 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.0 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + dev: true + + /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==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.1.0 + has-tostringtag: 1.0.2 + dev: true + + /which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + 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 + dev: true + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + + /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: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /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: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /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-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: + 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: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + /yaml@2.4.1: + resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + engines: {node: '>= 14'} + hasBin: true + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + 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 + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + file:../../../apps/api-extractor(@types/node@20.17.19): + resolution: {directory: ../../../apps/api-extractor, type: directory} + id: file:../../../apps/api-extractor + name: '@microsoft/api-extractor' + hasBin: true + dependencies: + '@microsoft/api-extractor-model': file:../../../libraries/api-extractor-model(@types/node@20.17.19) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@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.2 + lodash: 4.17.21 + minimatch: 10.0.3 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../apps/heft(@types/node@20.17.19): + resolution: {directory: ../../../apps/heft, type: directory} + id: file:../../../apps/heft + name: '@rushstack/heft' + engines: {node: '>=10.13.0'} + hasBin: true + 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.2 + git-repo-info: 2.1.1 + ignore: 5.1.9 + tapable: 1.1.3 + watchpack: 2.4.0 + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../apps/zipsync(@types/node@20.17.19): + resolution: {directory: ../../../apps/zipsync, type: directory} + id: file:../../../apps/zipsync + name: '@rushstack/zipsync' + hasBin: true + dependencies: + '@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/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@20.17.19) + semver: 7.5.4 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + + file:../../../eslint/eslint-config(eslint@9.25.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 || ^9.25.1 + typescript: '>=4.7.0' + 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.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/parser': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(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.0(eslint@9.25.1)(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.2): + resolution: {directory: ../../../eslint/eslint-config, type: directory} + id: file:../../../eslint/eslint-config + name: '@rushstack/eslint-config' + peerDependencies: + eslint: ^8.57.0 || ^9.25.1 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': file:../../../eslint/eslint-plugin-packlets(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': file:../../../eslint/eslint-plugin-security(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(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.0(eslint@9.37.0)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + file:../../../eslint/eslint-patch: + resolution: {directory: ../../../eslint/eslint-patch, type: directory} + name: '@rushstack/eslint-patch' + dev: true + + file:../../../eslint/eslint-plugin(eslint@9.25.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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.2): + 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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/eslint-plugin-packlets(eslint@9.25.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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/eslint-plugin-packlets(eslint@9.37.0)(typescript@5.8.2): + 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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/eslint-plugin-security(eslint@9.25.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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/eslint-plugin-security(eslint@9.37.0)(typescript@5.8.2): + 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 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + file:../../../eslint/local-eslint-config(eslint@9.37.0)(typescript@5.8.2): + resolution: {directory: ../../../eslint/local-eslint-config, type: directory} + id: file:../../../eslint/local-eslint-config + name: local-eslint-config + peerDependencies: + eslint: ^9.25.1 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + 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.2 + transitivePeerDependencies: + - supports-color + dev: true + + file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19): + 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': '*' + 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.5.4 + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19)(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 + dependencies: + '@jest/core': 29.5.0 + '@jest/reporters': 29.5.0 + '@jest/transform': 29.5.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: 29.5.0(@types/node@20.17.19) + 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 + + file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19): + resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} + id: file:../../../heft-plugins/heft-lint-plugin + name: '@rushstack/heft-lint-plugin' + peerDependencies: + '@rushstack/heft': '*' + 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.5.4 + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19): + resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} + id: file:../../../heft-plugins/heft-typescript-plugin + name: '@rushstack/heft-typescript-plugin' + peerDependencies: + '@rushstack/heft': '*' + 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.5.4 + tapable: 1.1.3 + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../libraries/api-extractor-model(@types/node@20.17.19): + resolution: {directory: ../../../libraries/api-extractor-model, type: directory} + id: file:../../../libraries/api-extractor-model + name: '@microsoft/api-extractor-model' + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + dev: true + + file:../../../libraries/credential-cache(@types/node@20.17.19): + resolution: {directory: ../../../libraries/credential-cache, type: directory} + id: file:../../../libraries/credential-cache + name: '@rushstack/credential-cache' + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + file:../../../libraries/heft-config-file(@types/node@20.17.19): + resolution: {directory: ../../../libraries/heft-config-file, type: directory} + id: file:../../../libraries/heft-config-file + name: '@rushstack/heft-config-file' + engines: {node: '>=10.13.0'} + 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) + '@ungap/structured-clone': 1.3.0 + jsonpath-plus: 10.3.0 + transitivePeerDependencies: + - '@types/node' + + file:../../../libraries/lookup-by-path(@types/node@20.17.19): + 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 + dependencies: + '@types/node': 20.17.19 + + file:../../../libraries/node-core-library(@types/node@20.17.19): + 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 + dependencies: + '@rushstack/problem-matcher': file:../../../libraries/problem-matcher(@types/node@20.17.19) + '@types/node': 20.17.19 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1 + fs-extra: 11.3.0 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + + file:../../../libraries/npm-check-fork: + resolution: {directory: ../../../libraries/npm-check-fork, type: directory} + name: '@rushstack/npm-check-fork' + dependencies: + giturl: 2.0.0 + lodash: 4.17.21 + package-json: 7.0.0 + semver: 7.5.4 + throat: 6.0.2 + + file:../../../libraries/operation-graph(@types/node@20.17.19): + resolution: {directory: ../../../libraries/operation-graph, type: directory} + id: file:../../../libraries/operation-graph + name: '@rushstack/operation-graph' + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + 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) + '@types/node': 20.17.19 + dev: true + + file:../../../libraries/package-deps-hash(@types/node@20.17.19): + resolution: {directory: ../../../libraries/package-deps-hash, type: directory} + id: file:../../../libraries/package-deps-hash + name: '@rushstack/package-deps-hash' + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + file:../../../libraries/package-extractor(@types/node@20.17.19): + resolution: {directory: ../../../libraries/package-extractor, type: directory} + id: file:../../../libraries/package-extractor + name: '@rushstack/package-extractor' + 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.0.3 + npm-packlist: 2.1.5 + semver: 7.5.4 + transitivePeerDependencies: + - '@types/node' + + file:../../../libraries/problem-matcher(@types/node@20.17.19): + resolution: {directory: ../../../libraries/problem-matcher, type: directory} + id: file:../../../libraries/problem-matcher + name: '@rushstack/problem-matcher' + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.17.19 + + file:../../../libraries/rig-package: + resolution: {directory: ../../../libraries/rig-package, type: directory} + name: '@rushstack/rig-package' + dependencies: + resolve: 1.22.8 + strip-json-comments: 3.1.1 + + file:../../../libraries/rush-lib(@types/node@20.17.19): + resolution: {directory: ../../../libraries/rush-lib, type: directory} + id: file:../../../libraries/rush-lib + name: '@microsoft/rush-lib' + engines: {node: '>=5.6.0'} + dependencies: + '@pnpm/dependency-path': 1000.0.9 + '@pnpm/dependency-path-lockfile-pre-v10': /@pnpm/dependency-path@5.1.7 + '@pnpm/dependency-path-lockfile-pre-v9': /@pnpm/dependency-path@2.1.8 + '@pnpm/link-bins': 5.3.25 + '@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 + '@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@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) + '@rushstack/zipsync': file:../../../apps/zipsync(@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 + dotenv: 16.4.7 + fast-glob: 3.3.2 + figures: 3.0.0 + git-repo-info: 2.1.1 + glob-escape: 0.0.2 + https-proxy-agent: 5.0.1 + ignore: 5.1.9 + inquirer: 8.2.7(@types/node@20.17.19) + js-yaml: 4.1.0 + npm-check: 6.0.1 + npm-package-arg: 6.1.1 + object-hash: 3.0.0 + pnpm-sync-lib: 0.3.2 + read-package-tree: 5.1.6 + rxjs: 6.6.7 + semver: 7.5.4 + ssri: 8.0.1 + strict-uri-encode: 2.0.0 + tapable: 2.2.1 + tar: 6.2.1 + true-case-path: 2.2.1 + uuid: 8.3.2 + transitivePeerDependencies: + - '@types/node' + - supports-color + + file:../../../libraries/rush-sdk(@types/node@20.17.19): + resolution: {directory: ../../../libraries/rush-sdk, type: directory} + id: file:../../../libraries/rush-sdk + name: '@rushstack/rush-sdk' + dependencies: + '@pnpm/lockfile.types': 1.0.3 + '@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' + dev: false + + file:../../../libraries/stream-collator(@types/node@20.17.19): + resolution: {directory: ../../../libraries/stream-collator, type: directory} + id: file:../../../libraries/stream-collator + name: '@rushstack/stream-collator' + 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' + + file:../../../libraries/terminal(@types/node@20.17.19): + resolution: {directory: ../../../libraries/terminal, type: directory} + id: file:../../../libraries/terminal + name: '@rushstack/terminal' + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + 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) + '@types/node': 20.17.19 + supports-color: 8.1.1 + + file:../../../libraries/tree-pattern: + resolution: {directory: ../../../libraries/tree-pattern, type: directory} + name: '@rushstack/tree-pattern' + dev: true + + file:../../../libraries/ts-command-line(@types/node@20.17.19): + resolution: {directory: ../../../libraries/ts-command-line, type: directory} + id: file:../../../libraries/ts-command-line + name: '@rushstack/ts-command-line' + 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' + + file:../../../rigs/heft-node-rig(@rushstack/heft@1.1.5)(@types/node@20.17.19): + 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@20.17.19) + '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19) + '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19)(jest-environment-node@29.5.0) + '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19) + '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@1.1.5)(@types/node@20.17.19) + '@types/heft-jest': 1.0.1 + eslint: 9.37.0 + jest-environment-node: 29.5.0 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - jest-environment-jsdom + - jiti + - 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@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@1.1.5)(@types/node@20.17.19) + '@types/heft-jest': 1.0.1 + '@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.2) + typescript: 5.8.2 + transitivePeerDependencies: + - babel-plugin-macros + - jest-environment-jsdom + - jiti + - node-notifier + - supports-color + - ts-node + dev: true diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json new file mode 100644 index 00000000000..7399cc047db --- /dev/null +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -0,0 +1,6 @@ +// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. +{ + "pnpmShrinkwrapHash": "e12ac931528bca6b851ff4e4bbe8df7c7463449c", + "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9", + "packageJsonInjectedDependenciesHash": "10959d629cddc9df960467f98e5cf3982e69f38d" +} diff --git a/common/config/subspaces/default/.npmrc b/common/config/subspaces/default/.npmrc new file mode 100644 index 00000000000..9ececc1f20b --- /dev/null +++ b/common/config/subspaces/default/.npmrc @@ -0,0 +1,32 @@ +# Rush uses this file to configure the NPM package registry during installation. It is applicable +# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install", +# "rush update", and the "install-run.js" scripts. +# +# NOTE: The "rush publish" command uses .npmrc-publish instead. +# +# Before invoking the package manager, Rush will generate an .npmrc in the folder where installation +# is performed. This generated file will omit any config lines that reference environment variables +# that are undefined in that session; this avoids problems that would otherwise result due to +# a missing variable being replaced by an empty string. +# +# If "subspacesEnabled" is true in subspaces.json, the generated file will merge settings from +# "common/config/rush/.npmrc" and "common/config/subspaces//.npmrc", with the latter taking +# precedence. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read that file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# +registry=https://registry.npmjs.org/ +always-auth=false +# No phantom dependencies allowed in this repository +# Don't hoist in common/temp/node_modules +public-hoist-pattern= +# Don't hoist in common/temp/node_modules/.pnpm/node_modules +hoist=false +hoist-pattern= diff --git a/common/config/subspaces/default/.pnpmfile.cjs b/common/config/subspaces/default/.pnpmfile.cjs new file mode 100644 index 00000000000..b7821599ca7 --- /dev/null +++ b/common/config/subspaces/default/.pnpmfile.cjs @@ -0,0 +1,68 @@ +'use strict'; + +/** + * When using the PNPM package manager, you can use pnpmfile.js to workaround + * dependencies that have mistakes in their package.json file. (This feature is + * functionally similar to Yarn's "resolutions".) + * + * For details, see the PNPM documentation: + * https://pnpm.io/pnpmfile#hooks + * + * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE + * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run + * "rush update --full" so that PNPM will recalculate all version selections. + */ +module.exports = { + hooks: { + readPackage + } +}; + +function fixUndeclaredDependency(packageJson, dependencyName) { + packageJson.dependencies[dependencyName] = + packageJson.dependencies[dependencyName] || + packageJson.devDependencies?.[dependencyName] || + packageJson.version; +} + +/** + * This hook is invoked during installation before a package's dependencies + * are selected. + * The `packageJson` parameter is the deserialized package.json + * contents for the package that is about to be installed. + * The `context` parameter provides a log() function. + * The return value is the updated object. + */ +function readPackage(packageJson, context) { + if (packageJson.name.startsWith('@radix-ui/')) { + if (packageJson.peerDependencies && packageJson.peerDependencies['react']) { + packageJson.peerDependencies['@types/react'] = '*'; + packageJson.peerDependencies['@types/react-dom'] = '*'; + } + } + + switch (packageJson.name) { + case '@jest/test-result': { + // The `@jest/test-result` package takes undeclared dependencies on `jest-haste-map` + // and `jest-resolve` + fixUndeclaredDependency(packageJson, 'jest-haste-map'); + fixUndeclaredDependency(packageJson, 'jest-resolve'); + } + + case '@serverless-stack/core': { + delete packageJson.dependencies['@typescript-eslint/eslint-plugin']; + delete packageJson.dependencies['eslint-config-serverless-stack']; + delete packageJson.dependencies['lerna']; + break; + } + + case '@typescript-eslint/rule-tester': { + // The `@typescript-eslint/rule-tester` package takes an undeclared dependency + // on `@typescript-eslint/parser` + fixUndeclaredDependency(packageJson, '@typescript-eslint/parser'); + break; + } + } + + return packageJson; +} diff --git a/common/config/subspaces/default/common-versions.json b/common/config/subspaces/default/common-versions.json new file mode 100644 index 00000000000..bcaa4198eb5 --- /dev/null +++ b/common/config/subspaces/default/common-versions.json @@ -0,0 +1,152 @@ +/** + * 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", + + /** + * A table that specifies a "preferred version" for a given NPM package. This feature is typically used + * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. + * + * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into + * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager + * will calculate versions. The specific effect depends on your package manager. Generally it will have no + * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be + * achieved using the pnpmfile.js hook. See the Rush documentation for more details. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + "preferredVersions": { + /** + * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, + * instead of the latest version. + */ + // "some-library": "1.2.3" + + // This should be the TypeScript version that's used to build most of the projects in the repo. + // 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.8.2", + + // 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.0.3" + }, + + /** + * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, + * except in cases where different projects specify different version ranges for a given dependency. For older + * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause + * trouble for indirect dependencies with incompatible peerDependencies ranges. + * + * The default value is true. If you're encountering installation errors related to peer dependencies, + * it's recommended to set this to false. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + // "implicitlyPreferredVersions": false, + + /** + * If you would like the version specifiers for your dependencies to be consistent, then + * uncomment this line. This is effectively similar to running "rush check" before any + * of the following commands: + * + * rush install, rush update, rush link, rush version, rush publish + * + * In some cases you may want this turned on, but need to allow certain packages to use a different + * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" + * section of the common-versions.json. + * + * In the case that subspaces is enabled, this setting will take effect at a subspace level. + */ + "ensureConsistentVersions": true, + + /** + * The "rush check" command can be used to enforce that every project in the repo must specify + * the same SemVer range for a given dependency. However, sometimes exceptions are needed. + * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be + * accepted by "rush check" for a given dependency. + * + * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE + * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). + * 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 + ], + "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-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 + * (in addition to whatever "usual" version is being used by other projects in the repo): + */ + "typescript": [ + // "~5.0.4" is the (inferred, not alternative) range used by most projects in this repo + + // The oldest supported compiler, used by build-tests/api-extractor-lib1-test + "~2.9.2", + // 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.8.2" + ], + "source-map": [ + "~0.6.1" // API Extractor is using an older version of source-map because newer versions are async + ], + "tapable": [ + "2.2.1", + "1.1.3" // heft plugin is using an older version of tapable + ], + // --- For Webpack 4 projects ---- + "css-loader": ["~5.2.7"], + "html-webpack-plugin": ["~4.5.2"], + "postcss-loader": ["~4.1.0"], + "sass-loader": ["~10.0.0"], + "sass": ["~1.3.0"], + "source-map-loader": ["~1.1.3"], + "style-loader": ["~2.0.0"], + "terser-webpack-plugin": ["~3.0.8"], + "terser": ["~4.8.0"], + "webpack": ["~4.47.0"], + "webpack-dev-server": ["~4.9.3"], + "@types/node": [ + // These versions are used by testing projects + "ts2.9", + "ts3.9", + "ts4.9" + ], + "@types/jest": [ + // These versions are used by testing projects + "ts2.9", + "ts3.9", + "ts4.9" + ], + "@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" + ] + } +} diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml new file mode 100644 index 00000000000..9b3644ccffe --- /dev/null +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -0,0 +1,31290 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +overrides: + package-json: ^7 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/eslint-plugin': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/utils': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/parser': ~8.46.0 + '@rushstack/eslint-config@4.4.1>@typescript-eslint/typescript-estree': ~8.46.0 + '@rushstack/eslint-plugin@0.20.0>@typescript-eslint/utils': ~8.46.0 + '@rushstack/heft-node-rig@2.10.1>eslint': ~9.37.0 + +packageExtensionsChecksum: e59cfa9a35183eeeb6f2ac48c9ddd4b2 + +importers: + + .: {} + + ../../../apps/api-documenter: + dependencies: + '@microsoft/api-extractor-model': + specifier: workspace:* + version: link:../../libraries/api-extractor-model + '@microsoft/tsdoc': + specifier: ~0.16.0 + version: 0.16.0 + '@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 + js-yaml: + specifier: ~4.1.0 + version: 4.1.0 + resolve: + specifier: ~1.22.1 + version: 1.22.8 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + '@types/js-yaml': + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/api-extractor: + dependencies: + '@microsoft/api-extractor-model': + specifier: workspace:* + version: link:../../libraries/api-extractor-model + '@microsoft/tsdoc': + specifier: ~0.16.0 + version: 0.16.0 + '@microsoft/tsdoc-config': + specifier: ~0.18.0 + version: 0.18.0 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rig-package': + specifier: workspace:* + version: link:../../libraries/rig-package + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + diff: + specifier: ~8.0.2 + version: 8.0.2 + lodash: + specifier: ~4.17.15 + version: 4.17.21 + minimatch: + specifier: 10.0.3 + version: 10.0.3 + resolve: + specifier: ~1.22.1 + version: 1.22.8 + semver: + specifier: ~7.5.4 + version: 7.5.4 + source-map: + specifier: ~0.6.1 + version: 0.6.1 + typescript: + specifier: 5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@types/lodash': + specifier: 4.14.116 + version: 4.14.116 + '@types/resolve': + specifier: 1.20.2 + version: 1.20.2 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/heft: + 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/operation-graph': + specifier: workspace:* + version: link:../../libraries/operation-graph + '@rushstack/rig-package': + specifier: workspace:* + version: link:../../libraries/rig-package + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + fast-glob: + specifier: ~3.3.1 + version: 3.3.2 + git-repo-info: + specifier: ~2.1.0 + version: 2.1.1 + ignore: + specifier: ~5.1.6 + version: 5.1.9 + tapable: + specifier: 1.1.3 + version: 1.1.3 + watchpack: + specifier: 2.4.0 + version: 2.4.0 + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../api-extractor + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@types/watchpack': + specifier: 2.4.0 + version: 2.4.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../apps/lockfile-explorer: + dependencies: + '@microsoft/rush-lib': + specifier: workspace:* + 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 + '@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 + cors: + specifier: ~2.8.5 + version: 2.8.5 + express: + specifier: 4.21.1 + version: 4.21.1 + js-yaml: + specifier: ~4.1.0 + version: 4.1.0 + open: + specifier: ~8.4.0 + version: 8.4.2 + semver: + specifier: ~7.5.4 + version: 7.5.4 + tslib: + specifier: ~2.8.1 + version: 2.8.1 + update-notifier: + specifier: ~5.1.0 + version: 5.1.0 + devDependencies: + '@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 + '@rushstack/lockfile-explorer-web': + specifier: workspace:* + version: link:../lockfile-explorer-web + '@types/cors': + specifier: ~2.8.12 + version: 2.8.17 + '@types/express': + specifier: 4.17.21 + version: 4.17.21 + '@types/js-yaml': + 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 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/lockfile-explorer-web: + dependencies: + '@reduxjs/toolkit': + specifier: ~1.8.6 + version: 1.8.6(react-redux@8.0.7)(react@17.0.2) + '@rushstack/rush-themed-ui': + specifier: workspace:* + version: link:../../libraries/rush-themed-ui + prism-react-renderer: + specifier: ~2.4.1 + version: 2.4.1(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-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 + 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 + '@types/react-dom': + specifier: 17.0.25 + version: 17.0.25 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + typescript: + specifier: 5.8.2 + version: 5.8.2 + + ../../../apps/rundown: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + string-argv: + specifier: ~0.3.1 + version: 0.3.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/rush: + dependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + semver: + specifier: ~7.5.4 + version: 7.5.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + '@rushstack/rush-amazon-s3-build-cache-plugin': + specifier: workspace:* + version: link:../../rush-plugins/rush-amazon-s3-build-cache-plugin + '@rushstack/rush-azure-storage-build-cache-plugin': + specifier: workspace:* + version: link:../../rush-plugins/rush-azure-storage-build-cache-plugin + '@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 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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.24.3 + version: 3.24.3 + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../apps/trace-import: + 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 + resolve: + specifier: ~1.22.1 + version: 1.22.8 + semver: + specifier: ~7.5.4 + version: 7.5.4 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + '@types/resolve': + specifier: 1.20.2 + version: 1.20.2 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests-samples/heft-node-basic-tutorial: + 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 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests-samples/heft-node-jest-tutorial: + 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 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests-samples/heft-node-rig-tutorial: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + + ../../../build-tests-samples/heft-serverless-stack-tutorial: + devDependencies: + '@aws-sdk/client-sso-oidc': + specifier: ^3.567.0 + version: 3.567.0(@aws-sdk/client-sts@3.567.0) + '@aws-sdk/client-sts': + specifier: ^3.567.0 + version: 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) + '@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-serverless-stack-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-serverless-stack-plugin + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@serverless-stack/aws-lambda-ric': + specifier: ^2.0.12 + 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) + '@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) + '@types/aws-lambda': + specifier: 8.10.93 + version: 8.10.93 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + aws-cdk-lib: + specifier: 2.189.1 + version: 2.189.1(constructs@10.0.130) + constructs: + specifier: ~10.0.98 + version: 10.0.130 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests-samples/heft-storybook-react-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.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 + '@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-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-webpack4-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack4-plugin + '@rushstack/webpack4-module-minifier-plugin': + specifier: workspace:* + version: link:../../webpack/webpack4-module-minifier-plugin + '@storybook/react': + specifier: ~6.4.18 + version: 6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.2) + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@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.8 + version: 1.18.8 + css-loader: + specifier: ~5.2.7 + version: 5.2.7(webpack@4.47.0) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + heft-storybook-react-tutorial-storykit: + specifier: workspace:* + version: link:../heft-storybook-react-tutorial-storykit + html-webpack-plugin: + specifier: ~4.5.2 + version: 4.5.2(webpack@4.47.0) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + source-map-loader: + specifier: ~1.1.3 + version: 1.1.3(webpack@4.47.0) + style-loader: + specifier: ~2.0.0 + version: 2.0.0(webpack@4.47.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + + ../../../build-tests-samples/heft-storybook-react-tutorial-app: + dependencies: + heft-storybook-react-tutorial: + specifier: 'workspace: *' + version: link:../heft-storybook-react-tutorial + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-storybook-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-storybook-plugin + heft-storybook-react-tutorial-storykit: + specifier: workspace:* + version: link:../heft-storybook-react-tutorial-storykit + + ../../../build-tests-samples/heft-storybook-react-tutorial-storykit: + devDependencies: + '@babel/core': + specifier: ~7.20.0 + 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) + '@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.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) + '@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.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) + '@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@20.17.19)(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.2) + '@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 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@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.8 + version: 1.18.8 + babel-loader: + specifier: ~8.2.3 + version: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) + css-loader: + specifier: ~5.2.7 + version: 5.2.7(webpack@4.47.0) + jest: + specifier: ~29.3.1 + version: 29.3.1(@types/node@20.17.19) + react: + specifier: ~17.0.2 + version: 17.0.2 + react-dom: + specifier: ~17.0.2 + version: 17.0.2(react@17.0.2) + style-loader: + specifier: ~2.0.0 + version: 2.0.0(webpack@4.47.0) + terser-webpack-plugin: + specifier: ~3.0.8 + version: 3.0.8(webpack@4.47.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + + ../../../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.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: 17.0.74 + version: 17.0.74 + '@types/react-dom': + specifier: 17.0.25 + version: 17.0.25 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + + ../../../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.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: 17.0.74 + version: 17.0.74 + '@types/react-dom': + specifier: 17.0.25 + version: 17.0.25 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + + ../../../build-tests-samples/heft-webpack-basic-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.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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@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.8 + version: 1.18.8 + css-loader: + specifier: ~6.6.0 + version: 6.6.0(webpack@5.98.0) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + source-map-loader: + specifier: ~3.0.1 + version: 3.0.2(webpack@5.98.0) + style-loader: + specifier: ~3.3.1 + version: 3.3.4(webpack@5.98.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../build-tests-samples/packlets-tutorial: + devDependencies: + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../../eslint/eslint-config + '@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: ~8.57.0 + version: 8.57.0 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/api-documenter-scenarios: + devDependencies: + '@microsoft/api-documenter': + specifier: workspace:* + version: link:../../apps/api-documenter + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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: + '@microsoft/api-documenter': + specifier: workspace:* + version: link:../../apps/api-documenter + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-d-cts-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-d-mts-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-lib1-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + 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: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-lib3-test: + dependencies: + api-extractor-lib1-test: + specifier: workspace:* + version: link:../api-extractor-lib1-test + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@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: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-lib5-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-scenarios: + dependencies: + api-extractor-lib1-test: + specifier: workspace:* + version: link:../api-extractor-lib1-test + devDependencies: + '@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 + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + api-extractor-lib2-test: + specifier: workspace:* + version: link:../api-extractor-lib2-test + api-extractor-lib3-test: + specifier: workspace:* + version: link:../api-extractor-lib3-test + api-extractor-lib4-test: + specifier: workspace:* + version: link:../api-extractor-lib4-test + api-extractor-lib5-test: + specifier: workspace:* + version: link:../api-extractor-lib5-test + 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 + '@types/long': + specifier: 4.0.0 + version: 4.0.0 + long: + specifier: ^4.0.0 + version: 4.0.0 + 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-02: + dependencies: + '@types/long': + specifier: 4.0.0 + version: 4.0.0 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + api-extractor-test-01: + specifier: workspace:* + version: link:../api-extractor-test-01 + semver: + specifier: ~7.5.4 + version: 7.5.4 + 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-03: + dependencies: + api-extractor-test-02: + specifier: workspace:* + version: link:../api-extractor-test-02 + 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 + 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.8.2) + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/node': + 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.8.2) + eslint: + specifier: 7.11.0 + version: 7.11.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + 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.8.2) + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/node': + 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.8.2) + eslint: + specifier: 7.7.0 + version: 7.7.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + 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.8.2) + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/node': + 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.8.2) + eslint: + specifier: ~7.30.0 + version: 7.30.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + 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: 20.17.19 + version: 20.17.19 + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@8.57.0)(typescript@5.8.2) + eslint: + specifier: ~8.57.0 + version: 8.57.0 + 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.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.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: + 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 + '@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.46.0 + version: 8.46.0(eslint@8.57.0)(typescript@5.8.2) + eslint: + specifier: ~8.57.0 + version: 8.57.0 + 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.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.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-legacy: + devDependencies: + '@rushstack/eslint-bulk': + specifier: workspace:* + version: link:../../eslint/eslint-bulk + '@rushstack/eslint-config': + specifier: 3.7.1 + version: 3.7.1(eslint@8.57.0)(typescript@5.8.2) + '@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.46.0 + version: 8.46.0(eslint@8.57.0)(typescript@5.8.2) + eslint: + specifier: ~8.57.0 + version: 8.57.0 + eslint-8.23: + specifier: npm:eslint@8.23.1 + version: /eslint@8.23.1 + eslint-oldest: + specifier: npm:eslint@8.6.0 + version: /eslint@8.6.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/hashed-folder-copy-plugin-webpack5-test: + devDependencies: + '@rushstack/hashed-folder-copy-plugin': + specifier: workspace:* + version: link:../../webpack/hashed-folder-copy-plugin + '@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 + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + + ../../../build-tests/heft-copy-files-test: + devDependencies: + '@rushstack/heft': + 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(supports-color@8.1.1) + 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: + specifier: 1.1.3 + version: 1.1.3 + 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 + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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-02: + 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(supports-color@8.1.1) + heft-example-plugin-01: + specifier: workspace:* + version: link:../heft-example-plugin-01 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-fastify-test: + dependencies: + fastify: + specifier: ~3.16.1 + version: 3.16.2 + 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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + 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 + '@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 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + 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 + '@jest/types': + specifier: 29.5.0 + version: 29.5.0 + '@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 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/heft-minimal-rig-test: + dependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-minimal-rig-usage-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@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/node': + specifier: 20.17.19 + version: 20.17.19 + heft-minimal-rig-test: + specifier: workspace:* + version: link:../heft-minimal-rig-test + + ../../../build-tests/heft-node-everything-esm-module-test: + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + heft-example-plugin-01: + specifier: workspace:* + version: link:../heft-example-plugin-01 + heft-example-plugin-02: + specifier: workspace:* + version: link:../heft-example-plugin-02 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-node-everything-test: + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + heft-example-lifecycle-plugin: + specifier: workspace:* + version: link:../heft-example-lifecycle-plugin + heft-example-plugin-01: + specifier: workspace:* + version: link:../heft-example-plugin-01 + heft-example-plugin-02: + specifier: workspace:* + version: link:../heft-example-plugin-02 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-parameter-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-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(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-parameter-plugin-test: + 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/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + heft-parameter-plugin: + specifier: workspace:* + version: link:../heft-parameter-plugin + typescript: + 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.0-beta.0 + '@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-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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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: + buttono: + specifier: ~1.0.2 + version: 1.0.4 + 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-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 + '@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/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/node': + specifier: 20.17.19 + version: 20.17.19 + '@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.8 + version: 1.18.8 + autoprefixer: + specifier: ~10.4.2 + version: 10.4.18(postcss@8.4.36) + css-loader: + specifier: ~5.2.7 + version: 5.2.7(webpack@4.47.0) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + html-webpack-plugin: + specifier: ~4.5.2 + version: 4.5.2(webpack@4.47.0) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + postcss: + specifier: ~8.4.6 + version: 8.4.36 + postcss-loader: + specifier: ~4.1.0 + version: 4.1.0(postcss@8.4.36)(webpack@4.47.0) + react: + specifier: ~17.0.2 + version: 17.0.2 + react-dom: + specifier: ~17.0.2 + version: 17.0.2(react@17.0.2) + style-loader: + specifier: ~2.0.0 + version: 2.0.0(webpack@4.47.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~4.47.0 + 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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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: + '@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 + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/jest': + specifier: 29.2.5 + version: 29.2.5 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-typescript-v2-test: + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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: ts2.9 + version: 23.3.13 + '@types/node': + specifier: ts2.9 + version: 14.0.1 + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@2.9.2) + typescript: + specifier: ~2.9.2 + version: 2.9.2 + + ../../../build-tests/heft-typescript-v3-test: + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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: ts3.9 + version: 28.1.1 + '@types/node': + specifier: ts3.9 + version: 17.0.41 + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@3.9.10) + typescript: + specifier: ~3.9.10 + version: 3.9.10 + + ../../../build-tests/heft-typescript-v4-test: + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/eslint-config': + specifier: 4.5.3 + version: 4.5.3(eslint@8.57.0)(typescript@4.9.5) + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../../eslint/eslint-patch + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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: ts4.9 + version: 29.5.12 + '@types/node': + specifier: ts4.9 + version: 20.12.12 + eslint: + specifier: ~8.57.0 + version: 8.57.0 + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@4.9.5) + typescript: + specifier: ~4.9.5 + version: 4.9.5 + + ../../../build-tests/heft-web-rig-library-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-web-rig': + specifier: workspace:* + version: link:../../rigs/heft-web-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../build-tests/heft-webpack4-everything-test: + devDependencies: + '@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-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/module-minifier': + specifier: workspace:* + version: link:../../libraries/module-minifier + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@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/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + file-loader: + specifier: ~6.0.0 + version: 6.0.0(webpack@4.47.0) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + source-map-loader: + specifier: ~1.1.3 + version: 1.1.3(webpack@4.47.0) + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + + ../../../build-tests/heft-webpack5-everything-test: + devDependencies: + '@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-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/module-minifier': + specifier: workspace:* + version: link:../../libraries/module-minifier + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@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/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + source-map-loader: + specifier: ~3.0.1 + version: 3.0.2(webpack@5.98.0) + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../build-tests/localization-plugin-test-01: + dependencies: + '@rushstack/heft': + specifier: workspace:* + 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@20.17.19)(@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/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + webpack-dev-server: + specifier: ~4.9.3 + 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-localization-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-localization-typings-plugin + '@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@20.17.19)(@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.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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 + lodash: + specifier: ~4.17.15 + version: 4.17.21 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + webpack-dev-server: + specifier: ~4.9.3 + 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@20.17.19)(@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/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~4.47.0 + version: 4.47.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + webpack-dev-server: + specifier: ~4.9.3 + version: 4.9.3(@types/webpack@4.41.32)(webpack@4.47.0) + + ../../../build-tests/package-extractor-test-01: + dependencies: + package-extractor-test-02: + specifier: workspace:* + version: link:../package-extractor-test-02 + devDependencies: + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + package-extractor-test-03: + specifier: workspace:* + version: link:../package-extractor-test-03 + + ../../../build-tests/package-extractor-test-02: + dependencies: + package-extractor-test-03: + specifier: workspace:* + version: link:../package-extractor-test-03 + + ../../../build-tests/package-extractor-test-03: + devDependencies: + '@types/node': + specifier: ts3.9 + version: 17.0.41 + + ../../../build-tests/package-extractor-test-04: + 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(supports-color@8.1.1) + 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': + 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/rush-amazon-s3-build-cache-plugin': + specifier: workspace:* + version: link:../../rush-plugins/rush-amazon-s3-build-cache-plugin + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/http-proxy': + specifier: ~1.17.8 + version: 1.17.14 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + http-proxy: + specifier: ~1.18.1 + version: 1.18.1 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/rush-lib-declaration-paths-test: + dependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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-project-change-analyzer-test: + dependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/rush-redis-cobuild-plugin-integration-test: + devDependencies: + '@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/rush-redis-cobuild-plugin': + specifier: workspace:* + version: link:../../rush-plugins/rush-redis-cobuild-plugin + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/http-proxy': + specifier: ~1.17.8 + version: 1.17.14 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + http-proxy: + specifier: ~1.18.1 + version: 1.18.1 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/set-webpack-public-path-plugin-test: + 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 + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/module-minifier': + specifier: workspace:* + version: link:../../libraries/module-minifier + '@rushstack/set-webpack-public-path-plugin': + specifier: workspace:* + version: link:../../webpack/set-webpack-public-path-plugin + '@rushstack/webpack5-module-minifier-plugin': + specifier: workspace:* + version: link:../../webpack/webpack5-module-minifier-plugin + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~8.57.0 + version: 8.57.0 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../eslint/eslint-bulk: + devDependencies: + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../eslint-patch + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../eslint/eslint-config: + dependencies: + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../eslint-patch + '@rushstack/eslint-plugin': + specifier: workspace:* + version: link:../eslint-plugin + '@rushstack/eslint-plugin-packlets': + specifier: workspace:* + version: link:../eslint-plugin-packlets + '@rushstack/eslint-plugin-security': + specifier: workspace:* + version: link:../eslint-plugin-security + '@typescript-eslint/eslint-plugin': + specifier: ~8.46.0 + version: 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': + specifier: ~8.46.0 + version: 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint-plugin-promise: + specifier: ~7.2.1 + version: 7.2.1(eslint@9.37.0) + eslint-plugin-react: + specifier: ~7.37.5 + version: 7.37.5(eslint@9.37.0) + eslint-plugin-tsdoc: + specifier: ~0.5.0 + version: 0.5.0(eslint@9.37.0)(typescript@5.8.2) + devDependencies: + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../eslint/eslint-patch: + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@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: ~8.46.0 + version: 8.46.0(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + eslint-8: + specifier: npm:eslint@~8.57.0 + version: /eslint@8.57.0 + eslint-9: + specifier: npm:eslint@~9.25.1 + version: /eslint@9.25.1 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../eslint/eslint-plugin: + dependencies: + '@rushstack/tree-pattern': + specifier: workspace:* + version: link:../../libraries/tree-pattern + '@typescript-eslint/utils': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/rule-tester': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/types': + specifier: ~8.46.0 + version: 8.46.0(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../eslint/eslint-plugin-packlets: + dependencies: + '@rushstack/tree-pattern': + specifier: workspace:* + version: link:../../libraries/tree-pattern + '@typescript-eslint/utils': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../eslint/eslint-plugin-security: + dependencies: + '@rushstack/tree-pattern': + specifier: workspace:* + version: link:../../libraries/tree-pattern + '@typescript-eslint/utils': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/rule-tester': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': + specifier: ~8.46.0 + version: 8.46.0(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../eslint/local-eslint-config: + dependencies: + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../eslint-config + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../eslint-patch + '@rushstack/eslint-plugin': + specifier: workspace:* + version: link:../eslint-plugin + '@typescript-eslint/eslint-plugin': + specifier: ~8.46.0 + version: 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(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@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) + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../heft-plugins/heft-api-extractor-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + semver: + specifier: ~7.5.4 + version: 7.5.4 + 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 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../heft-plugins/heft-dev-cert-plugin: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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 + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-jest-plugin: + dependencies: + '@jest/core': + specifier: ~29.5.0 + version: 29.5.0 + '@jest/reporters': + specifier: ~29.5.0 + version: 29.5.0 + '@jest/transform': + specifier: ~29.5.0 + version: 29.5.0 + '@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 + jest-config: + specifier: ~29.5.0 + version: 29.5.0(@types/node@20.17.19) + jest-resolve: + specifier: ~29.5.0 + version: 29.5.0 + jest-snapshot: + specifier: ~29.5.0 + version: 29.5.0 + lodash: + specifier: ~4.17.15 + version: 4.17.21 + punycode: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + '@jest/types': + specifier: 29.5.0 + version: 29.5.0 + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/lodash': + specifier: 4.14.116 + version: 4.14.116 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + jest-environment-jsdom: + specifier: ~29.5.0 + version: 29.5.0 + jest-environment-node: + specifier: ~29.5.0 + version: 29.5.0 + jest-watch-select-projects: + specifier: 2.0.0 + version: 2.0.0 + + ../../../heft-plugins/heft-json-schema-typings-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + 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(supports-color@8.1.1) + 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 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../heft-typescript-plugin + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/eslint': + 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 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + eslint-8: + specifier: npm:eslint@~8.57.0 + version: /eslint@8.57.0 + tslint: + specifier: ~5.20.1 + version: 5.20.1(typescript@5.8.2) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../heft-plugins/heft-localization-typings-plugin: + dependencies: + '@rushstack/localization-utilities': + specifier: workspace:* + version: link:../../libraries/localization-utilities + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-rspack-plugin: + dependencies: + '@rspack/dev-server': + specifier: ^1.1.4 + version: 1.1.4(@rspack/core@1.6.0-beta.0)(webpack@5.98.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 + tapable: + specifier: 2.3.0 + version: 2.3.0 + watchpack: + specifier: 2.4.0 + version: 2.4.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + devDependencies: + '@rspack/core': + specifier: ~1.6.0-beta.0 + version: 1.6.0-beta.0 + '@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: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-sass-load-themed-styles-plugin: + dependencies: + '@microsoft/load-themed-styles': + specifier: workspace:* + version: link:../../libraries/load-themed-styles + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-sass-plugin': + specifier: workspace:* + version: link:../heft-sass-plugin + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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.4.6 + version: 8.4.36 + postcss-modules: + specifier: ~6.0.0 + version: 6.0.0(postcss@8.4.36) + 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 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-storybook-plugin: + 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-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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-typescript-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 + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + semver: + specifier: ~7.5.4 + version: 7.5.4 + tapable: + specifier: 1.1.3 + version: 1.1.3 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + typescript: + 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 + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../heft-plugins/heft-webpack4-plugin: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + tapable: + specifier: 1.1.3 + version: 1.1.3 + watchpack: + specifier: 2.4.0 + version: 2.4.0 + webpack-dev-server: + specifier: ~4.9.3 + version: 4.9.3(@types/webpack@4.41.32)(webpack@4.47.0) + devDependencies: + '@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 + '@types/webpack': + specifier: 4.41.32 + version: 4.41.32 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~4.47.0 + version: 4.47.0 + + ../../../heft-plugins/heft-webpack5-plugin: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + tapable: + specifier: 1.1.3 + version: 1.1.3 + watchpack: + specifier: 2.4.0 + version: 2.4.0 + webpack-dev-server: + specifier: ^5.1.0 + version: 5.1.0(webpack@5.98.0) + devDependencies: + '@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: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../libraries/api-extractor-model: + dependencies: + '@microsoft/tsdoc': + specifier: ~0.16.0 + version: 0.16.0 + '@microsoft/tsdoc-config': + specifier: ~0.18.0 + version: 0.18.0 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/debug-certificate-manager: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + node-forge: + specifier: ~1.3.1 + version: 1.3.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/node-forge': + specifier: 1.0.4 + version: 1.0.4 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/heft-config-file: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/rig-package': + specifier: workspace:* + version: link:../rig-package + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + '@ungap/structured-clone': + specifier: ~1.3.0 + version: 1.3.0 + jsonpath-plus: + specifier: ~10.3.0 + version: 10.3.0 + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@types/ungap__structured-clone': + specifier: ~1.2.0 + version: 1.2.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/load-themed-styles: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + + ../../../libraries/localization-utilities: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + '@rushstack/typings-generator': + specifier: workspace:* + version: link:../typings-generator + pseudolocale: + specifier: ~1.1.0 + version: 1.1.0 + xmldoc: + specifier: ~1.1.2 + version: 1.1.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/xmldoc': + specifier: 1.1.4 + version: 1.1.4 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/lookup-by-path: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/module-minifier: + dependencies: + '@rushstack/worker-pool': + specifier: workspace:* + version: link:../worker-pool + serialize-javascript: + specifier: 6.0.2 + version: 6.0.2 + source-map: + specifier: ~0.7.3 + version: 0.7.4 + terser: + specifier: ^5.9.0 + version: 5.29.2 + 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 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/node-core-library: + dependencies: + ajv: + specifier: ~8.13.0 + version: 8.13.0 + ajv-draft-04: + specifier: ~1.0.0 + version: 1.0.0(ajv@8.13.0) + ajv-formats: + specifier: ~3.0.1 + version: 3.0.1(ajv@8.13.0) + fs-extra: + specifier: ~11.3.0 + version: 11.3.0 + import-lazy: + specifier: ~4.0.0 + version: 4.0.0 + jju: + specifier: ~1.4.0 + version: 1.4.0 + resolve: + specifier: ~1.22.1 + version: 1.22.8 + semver: + specifier: ~7.5.4 + version: 7.5.4 + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@rushstack/problem-matcher': + specifier: workspace:* + version: link:../problem-matcher + '@types/fs-extra': + specifier: 7.0.0 + version: 7.0.0 + '@types/jju': + specifier: 1.4.1 + version: 1.4.1 + '@types/resolve': + specifier: 1.20.2 + version: 1.20.2 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/npm-check-fork: + dependencies: + giturl: + specifier: ^2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.15 + version: 4.17.21 + package-json: + specifier: ^7 + version: 7.0.0 + semver: + specifier: ~7.5.4 + version: 7.5.4 + throat: + specifier: ^6.0.2 + version: 6.0.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/lodash': + specifier: 4.14.116 + version: 4.14.116 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/operation-graph: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/package-deps-hash: + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/package-extractor: + dependencies: + '@pnpm/link-bins': + specifier: ~5.3.7 + version: 5.3.25 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../ts-command-line + ignore: + specifier: ~5.1.6 + version: 5.1.9 + jszip: + specifier: ~3.8.0 + version: 3.8.0 + minimatch: + specifier: 10.0.3 + version: 10.0.3 + npm-packlist: + specifier: ~2.1.2 + version: 2.1.5 + semver: + specifier: ~7.5.4 + version: 7.5.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@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/glob': + specifier: 7.1.1 + version: 7.1.1 + '@types/npm-packlist': + specifier: ~1.1.1 + version: 1.1.2 + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../libraries/problem-matcher: + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/rig-package: + dependencies: + resolve: + specifier: ~1.22.1 + version: 1.22.8 + strip-json-comments: + specifier: ~3.1.1 + version: 3.1.1 + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@types/resolve': + specifier: 1.20.2 + version: 1.20.2 + ajv: + specifier: ~8.13.0 + version: 8.13.0 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/rush-lib: + dependencies: + '@pnpm/dependency-path': + specifier: ~1000.0.9 + version: 1000.0.9 + '@pnpm/dependency-path-lockfile-pre-v10': + specifier: npm:@pnpm/dependency-path@~5.1.7 + version: /@pnpm/dependency-path@5.1.7 + '@pnpm/dependency-path-lockfile-pre-v9': + specifier: npm:@pnpm/dependency-path@~2.1.2 + version: /@pnpm/dependency-path@2.1.8 + '@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 + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../lookup-by-path + '@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 + '@rushstack/package-extractor': + specifier: workspace:* + version: link:../package-extractor + '@rushstack/rig-package': + specifier: workspace:* + version: link:../rig-package + '@rushstack/stream-collator': + specifier: workspace:* + version: link:../stream-collator + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../ts-command-line + '@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 + 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: ~8.2.7 + version: 8.2.7 + js-yaml: + specifier: ~4.1.0 + version: 4.1.0 + 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.3.2 + version: 0.3.2 + read-package-tree: + specifier: ~5.1.5 + version: 5.1.6 + rxjs: + specifier: ~6.6.7 + version: 6.6.7 + semver: + specifier: ~7.5.4 + version: 7.5.4 + ssri: + specifier: ~8.0.0 + version: 8.0.1 + strict-uri-encode: + specifier: ~2.0.0 + version: 2.0.0 + tapable: + specifier: 2.2.1 + version: 2.2.1 + tar: + specifier: ~6.2.1 + version: 6.2.1 + true-case-path: + specifier: ~2.2.1 + version: 2.2.1 + devDependencies: + '@pnpm/lockfile.types': + specifier: ~1.0.3 + version: 1.0.3 + '@pnpm/logger': + specifier: 4.0.0 + version: 4.0.0 + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/operation-graph': + specifier: workspace:* + version: link:../operation-graph + '@rushstack/webpack-deep-imports-plugin': + specifier: workspace:* + version: link:../../webpack/webpack-deep-imports-plugin + '@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: 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 + '@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/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../libraries/rush-sdk: + dependencies: + '@pnpm/lockfile.types': + specifier: ~1.0.3 + version: 1.0.3 + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../credential-cache + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../lookup-by-path + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/package-deps-hash': + specifier: workspace:* + version: link:../package-deps-hash + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + tapable: + specifier: 2.2.1 + version: 2.2.1 + devDependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../rush-lib + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/stream-collator': + specifier: workspace:* + version: link:../stream-collator + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../ts-command-line + '@rushstack/webpack-preserve-dynamic-require-plugin': + specifier: workspace:* + version: link:../../webpack/preserve-dynamic-require-plugin + '@types/semver': + specifier: 7.5.0 + version: 7.5.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../libraries/rush-themed-ui: + dependencies: + react: + specifier: ~17.0.2 + version: 17.0.2 + react-dom: + specifier: ~17.0.2 + version: 17.0.2(react@17.0.2) + devDependencies: + '@radix-ui/colors': + specifier: ~0.1.8 + version: 0.1.9 + '@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) + '@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) + '@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) + '@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) + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/react': + specifier: 17.0.74 + version: 17.0.74 + '@types/react-dom': + specifier: 17.0.25 + version: 17.0.25 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + + ../../../libraries/rushell: + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/stream-collator: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/terminal: + dependencies: + '@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: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@types/supports-color': + specifier: 8.1.3 + version: 8.1.3 + decoupled-local-node-rig: + specifier: workspace:* + 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/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + + ../../../libraries/ts-command-line: + dependencies: + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + '@types/argparse': + specifier: 1.0.38 + version: 1.0.38 + argparse: + specifier: ~1.0.9 + version: 1.0.10 + string-argv: + specifier: ~0.3.1 + version: 0.3.2 + devDependencies: + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@rushstack/node-core-library': + specifier: workspace:* + 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(supports-color@8.1.1) + + ../../../libraries/typings-generator: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../terminal + chokidar: + specifier: ~3.6.0 + version: 3.6.0 + fast-glob: + specifier: ~3.3.1 + version: 3.3.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/worker-pool: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../repo-scripts/doc-plugin-rush-stack: + dependencies: + '@microsoft/api-documenter': + specifier: workspace:* + version: link:../../apps/api-documenter + '@microsoft/api-extractor-model': + specifier: workspace:* + version: link:../../libraries/api-extractor-model + '@microsoft/tsdoc': + specifier: ~0.16.0 + version: 0.16.0 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + js-yaml: + specifier: ~4.1.0 + version: 4.1.0 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/js-yaml': + specifier: 4.0.9 + version: 4.0.9 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../repo-scripts/generate-api-docs: + devDependencies: + '@microsoft/api-documenter': + specifier: workspace:* + version: link:../../apps/api-documenter + doc-plugin-rush-stack: + specifier: workspace:* + version: link:../doc-plugin-rush-stack + + ../../../repo-scripts/repo-toolbox: + dependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@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 + diff: + specifier: ~8.0.2 + version: 8.0.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rigs/decoupled-local-node-rig: + dependencies: + '@microsoft/api-extractor': + specifier: 7.54.0 + version: 7.54.0(@types/node@20.17.19) + '@rushstack/eslint-config': + specifier: 4.5.3 + version: 4.5.3(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-patch': + specifier: 1.14.1 + version: 1.14.1 + '@rushstack/eslint-plugin': + specifier: 0.22.0 + version: 0.22.0(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/heft': + specifier: 1.1.4 + version: 1.1.4(@types/node@20.17.19) + '@rushstack/heft-node-rig': + specifier: 2.11.6 + version: 2.11.6(@rushstack/heft@1.1.4)(@types/node@20.17.19) + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@typescript-eslint/eslint-plugin': + specifier: ~8.46.0 + version: 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../../eslint/eslint-config + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + jest-environment-node: + specifier: ~29.5.0 + version: 29.5.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/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + jest-environment-node: + specifier: ~29.5.0 + version: 29.5.0 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + + ../../../rigs/heft-web-rig: + dependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../../eslint/eslint-config + '@rushstack/heft-api-extractor-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-api-extractor-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-sass-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-sass-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 + autoprefixer: + specifier: ~10.4.2 + version: 10.4.18(postcss@8.4.36) + css-loader: + specifier: ~6.6.0 + version: 6.6.0(webpack@5.98.0) + css-minimizer-webpack-plugin: + specifier: ~3.4.1 + version: 3.4.1(webpack@5.98.0) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + jest-environment-jsdom: + specifier: ~29.5.0 + version: 29.5.0 + mini-css-extract-plugin: + specifier: ~2.5.3 + version: 2.5.3(webpack@5.98.0) + postcss: + specifier: ~8.4.6 + version: 8.4.36 + postcss-loader: + specifier: ~6.2.1 + version: 6.2.1(postcss@8.4.36)(webpack@5.98.0) + 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.98.0) + source-map-loader: + specifier: ~3.0.1 + version: 3.0.2(webpack@5.98.0) + style-loader: + specifier: ~3.3.1 + version: 3.3.4(webpack@5.98.0) + terser-webpack-plugin: + specifier: ~5.3.1 + version: 5.3.10(webpack@5.98.0) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + url-loader: + specifier: ~4.1.1 + version: 4.1.1(webpack@5.98.0) + webpack: + specifier: ~5.98.0 + version: 5.98.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + webpack-merge: + specifier: ~5.8.0 + version: 5.8.0 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + + ../../../rigs/local-node-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-node-rig': + specifier: workspace:* + version: link:../heft-node-rig + '@types/heft-jest': + specifier: 1.0.1 + version: 1.0.1 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + jest-junit: + specifier: 12.3.0 + version: 12.3.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + 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/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + jest-junit: + specifier: 12.3.0 + version: 12.3.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + 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 + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + https-proxy-agent: + specifier: ~5.0.0 + version: 5.0.1 + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-azure-storage-build-cache-plugin: + dependencies: + '@azure/identity': + specifier: ~4.5.0 + version: 4.5.0 + '@azure/storage-blob': + specifier: ~12.26.0 + version: 12.26.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(supports-color@8.1.1) + 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(supports-color@8.1.1) + 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 + '@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: + '@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(supports-color@8.1.1) + 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 + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + https-proxy-agent: + specifier: ~5.0.0 + version: 5.0.1 + devDependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-litewatch-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 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + 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(supports-color@8.1.1) + 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-redis-cobuild-plugin: + dependencies: + '@redis/client': + specifier: ~5.8.2 + version: 5.8.2 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + devDependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-resolver-cache-plugin: + dependencies: + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../../libraries/lookup-by-path + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/webpack-workspace-resolve-plugin': + specifier: workspace:* + version: link:../../webpack/webpack-workspace-resolve-plugin + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-serve-plugin: + dependencies: + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@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/rig-package': + specifier: workspace:* + version: link:../../libraries/rig-package + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + compression: + specifier: ~1.7.4 + version: 1.7.4 + cors: + specifier: ~2.8.5 + version: 2.8.5 + express: + 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 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@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 + '@types/express': + specifier: 4.17.21 + version: 4.17.21 + '@types/ws': + specifier: 8.5.5 + version: 8.5.5 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../vscode-extensions/debug-certificate-manager-vscode-extension: + dependencies: + '@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.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@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.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 + 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: 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 + '@types/vscode': + specifier: 1.103.0 + version: 1.103.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.98.0) + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + webpack-bundle-analyzer: + specifier: ~4.5.0 + version: 4.5.0 + + ../../../vscode-extensions/rush-vscode-extension: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/rush-vscode-command-webview': + specifier: workspace:* + version: link:../rush-vscode-command-webview + '@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:* + version: link:../../libraries/rush-lib + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-vscode-extension-rig': + specifier: workspace:* + version: link:../../rigs/heft-vscode-extension-rig + '@types/glob': + specifier: 7.1.1 + version: 7.1.1 + '@types/mocha': + specifier: 10.0.6 + version: 10.0.6 + '@types/vscode': + specifier: 1.103.0 + version: 1.103.0 + '@types/webpack-env': + 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(supports-color@8.1.1) + glob: + specifier: ~7.0.5 + version: 7.0.6 + mocha: + specifier: ^10.1.0 + version: 10.4.0 + + ../../../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 + fast-glob: + specifier: ~3.3.1 + version: 3.3.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/estree': + specifier: 1.0.6 + version: 1.0.6 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/loader-load-themed-styles: + dependencies: + loader-utils: + specifier: 1.4.2 + version: 1.4.2 + devDependencies: + '@microsoft/load-themed-styles': + specifier: workspace:* + version: link:../../libraries/load-themed-styles + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/loader-utils': + specifier: 1.1.3 + version: 1.1.3 + '@types/webpack': + specifier: 4.41.32 + version: 4.41.32 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../webpack/loader-raw-script: + dependencies: + loader-utils: + specifier: 1.4.2 + version: 1.4.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../webpack/preserve-dynamic-require-plugin: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/set-webpack-public-path-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 + devDependencies: + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack-deep-imports-plugin: + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack-embedded-dependencies-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/webpack-plugin-utilities': + specifier: workspace:* + version: link:../webpack-plugin-utilities + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack-plugin-utilities: + dependencies: + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack-merge: + specifier: ~5.8.0 + version: 5.8.0 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack-workspace-resolve-plugin: + dependencies: + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../../libraries/lookup-by-path + devDependencies: + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack4-localization-plugin: + dependencies: + '@rushstack/localization-utilities': + specifier: workspace:* + version: link:../../libraries/localization-utilities + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + loader-utils: + specifier: 1.4.2 + version: 1.4.2 + minimatch: + specifier: 10.0.3 + version: 10.0.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@20.17.19)(@types/webpack@4.41.32)(webpack@4.47.0) + '@types/loader-utils': + specifier: 1.1.3 + version: 1.1.3 + '@types/node': + 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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~4.47.0 + version: 4.47.0 + + ../../../webpack/webpack4-module-minifier-plugin: + dependencies: + '@rushstack/module-minifier': + specifier: workspace:* + version: link:../../libraries/module-minifier + '@rushstack/worker-pool': + specifier: workspace:* + version: link:../../libraries/worker-pool + '@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 + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~4.47.0 + version: 4.47.0 + webpack-sources: + specifier: ~1.4.3 + version: 1.4.3 + + ../../../webpack/webpack5-load-themed-styles-loader: + devDependencies: + '@microsoft/load-themed-styles': + specifier: workspace:* + version: link:../../libraries/load-themed-styles + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + css-loader: + specifier: ~6.6.0 + version: 6.6.0(webpack@5.98.0) + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack5-localization-plugin: + dependencies: + '@rushstack/localization-utilities': + specifier: workspace:* + version: link:../../libraries/localization-utilities + '@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 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + + ../../../webpack/webpack5-module-minifier-plugin: + dependencies: + '@rushstack/worker-pool': + specifier: workspace:* + version: link:../../libraries/worker-pool + '@types/estree': + specifier: 1.0.6 + version: 1.0.6 + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + tapable: + specifier: 2.2.1 + version: 2.2.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@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(supports-color@8.1.1) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + memfs: + specifier: 4.12.0 + version: 4.12.0 + webpack: + specifier: ~5.98.0 + version: 5.98.0 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.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 + + /@apidevtools/json-schema-ref-parser@11.9.3: + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + dev: false + + /@aws-cdk/asset-awscli-v1@2.2.230: + resolution: {integrity: sha512-kUnhKIYu42hqBa6a8x2/7o29ObpJgjYGQy28lZDq9awXyvpR62I2bRxrNKNR3uFUQz3ySuT9JXhGHhuZPdbnFw==} + dev: true + + /@aws-cdk/asset-node-proxy-agent-v6@2.1.0: + resolution: {integrity: sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==} + dev: true + + /@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130): + 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): + resolution: {integrity: sha512-lMXnSpUSOYtCxoAxauNkGJZLsKMonHgd9rzlFUK2zxE7aC1lVwb4qYX4X9WJdvIExkFOHSZQzOTKM6SZqusssw==} + engines: {node: '>= 14.15.0'} + deprecated: This package has been stabilized and moved to aws-cdk-lib + peerDependencies: + '@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): + resolution: {integrity: sha512-XEhz4HsU0HtQJnbs9XSb/yPN/1EEYAOZthWRKyniS9IWeGruVjEhWndoXpu0S7w+M5Bni7D9wrCTkqTgmTEvlw==} + engines: {node: '>= 14.15.0'} + deprecated: This package has been stabilized and moved to aws-cdk-lib + peerDependencies: + '@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): + 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-cdk/cloud-assembly-schema@41.2.0: + resolution: {integrity: sha512-JaulVS6z9y5+u4jNmoWbHZRs9uGOnmn/ktXygNWKNu1k6lF3ad4so3s18eRu15XCbUIomxN9WPYT6Ehh7hzONw==} + engines: {node: '>= 14.15.0'} + dev: true + bundledDependencies: + - jsonschema + - semver + + /@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-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/supports-web-crypto@3.0.0: + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + dependencies: + tslib: 1.14.1 + dev: true + + /@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-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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + dev: true + + /@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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: true + + /@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.8.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: true + + /@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.8.1 + 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.8.1 + dev: true + + /@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.8.1 + 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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: true + + /@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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@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.8.1 + dev: true + + /@aws-sdk/util-locate-window@3.567.0: + resolution: {integrity: sha512-o05vqq2+IdIHVqu2L28D1aVzZRkjheyQQE0kAIB+aS0fr4hYidsO2XqkXRRnhkaOxW3VN5/K/p2gxCaKt6A1XA==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@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.8.1 + dev: true + + /@aws-sdk/util-user-agent-node@3.567.0: + resolution: {integrity: sha512-Fph602FBhLssed0x2GsRZyqJB8thcrKzbS53v57rQ6XHSQ6T8t2BUyrlXcBfDpoZQjnqobr0Uu2DG5UI3cgR6g==} + engines: {node: '>=16.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.8.1 + dev: true + + /@aws-sdk/util-utf8-browser@3.259.0: + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + dependencies: + tslib: 2.8.1 + dev: true + + /@azure/abort-controller@2.1.0: + resolution: {integrity: sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.8.1 + dev: false + + /@azure/abort-controller@2.1.2: + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.8.1 + 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.8.1 + dev: false + + /@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.8.1 + dev: false + + /@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.8.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-client@1.9.2: + resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + 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.8.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-http-compat@2.1.2: + resolution: {integrity: sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==} + 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.8.1 + dev: false + + /@azure/core-paging@1.6.0: + resolution: {integrity: sha512-W8eRv7MVFx/jbbYfcRT5+pGnZ9St/P1UvOi+63vxPwuQ3y+xj+wqWTGxpkXUETv3szsqGu0msdxVtjszCeB4zA==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.8.1 + dev: false + + /@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.8.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@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.8.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-tracing@1.1.0: + resolution: {integrity: sha512-MVeJvGHB4jmF7PeHhyr72vYJsBJ3ff1piHikMgRaabPAC4P3rxhf9fm42I+DixLysBunskJWhsDQD2A+O+plkQ==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.8.1 + dev: false + + /@azure/core-tracing@1.2.0: + resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.8.1 + dev: false + + /@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.8.1 + dev: false + + /@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.8.1 + dev: false + + /@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.8.1 + dev: false + + /@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.8.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.8.1 + 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/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.8.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@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==} + 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==} + engines: {node: '>=6.9.0'} + + /@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 + '@babel/parser': 7.24.0 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 + convert-source-map: 1.9.0 + debug: 4.4.0(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: + 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 + '@babel/parser': 7.24.0 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@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 + '@babel/parser': 7.24.0 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.4.0(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==} + 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==} + 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==} + 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==} + 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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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): + resolution: {integrity: sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==} + peerDependencies: + '@babel/core': ^7.4.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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 + debug: 4.4.0(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==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + debug: 4.4.0(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 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + debug: 4.4.0(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==} + 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==} + 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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + 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==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@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==} + 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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-wrap-function@7.22.20: + resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + 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: + resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 + transitivePeerDependencies: + - supports-color + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.24.0: + resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} + engines: {node: '>=6.0.0'} + hasBin: true + + /@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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): + 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 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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): + 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 + '@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): + 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): + 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 + '@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): + 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 + '@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): + 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 + '@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): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.20.12): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.20.12): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@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): + 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 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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 + '@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 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.20.12): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-jsx@7.12.1(@babel/core@7.12.9): + 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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.20.12): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.20.12): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@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): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.20.12): + 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 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + 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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.24.0 + regenerator-transform: 0.15.2 + dev: true + + /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.20.12): + resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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): + 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 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@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==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + 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.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==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + 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: + resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} + 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.4.0(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + 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 + + /@base2/pretty-print-object@1.0.1: + resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} + dev: true + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + /@bufbuild/protobuf@2.2.5: + resolution: {integrity: sha512-/g5EzJifw5GF8aren8wZ/G5oMuPoGeS6MQD3ca8ddcvdXR5UELUfdTZITCGNhNXynY/AYl3Z4plmxdj/tRl/hQ==} + dev: false + + /@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: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@discoveryjs/json-ext@0.5.7: + resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} + engines: {node: '>=10.0.0'} + dev: true + + /@emnapi/core@1.5.0: + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + requiresBuild: true + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + /@emnapi/runtime@1.5.0: + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + optional: true + + /@emnapi/wasi-threads@1.1.0: + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + optional: true + + /@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): + 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: + 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: + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + dev: true + + /@emotion/hash@0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + + /@emotion/is-prop-valid@0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} + dependencies: + '@emotion/memoize': 0.7.4 + dev: true + + /@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/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/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): + 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): + 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: + resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} + dev: true + + /@emotion/unitless@0.7.5: + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + dev: true + + /@emotion/unitless@0.8.1: + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + dev: true + + /@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/weak-memoize@0.2.5: + resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==} + dev: true + + /@es-joy/jsdoccomment@0.49.0: + resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} + engines: {node: '>=16'} + dependencies: + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 4.1.0 + dev: false + + /@esbuild/aix-ppc64@0.20.2: + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + 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'} + 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'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.20.2: + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + 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'} + 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'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.20.2: + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + 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'} + 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'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.20.2: + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.20.2: + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@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'} + 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'} + 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'} + 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'} + 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'} + 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'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.20.2: + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.20.2: + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.20.2: + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.20.2: + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@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/win32-x64@0.20.2: + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@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: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.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 + 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 + 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 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@9.37.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.37.0(supports-color@8.1.1) + eslint-visitor-keys: 3.4.3 + + /@eslint-community/eslint-utils@4.9.0(eslint@8.57.0): + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + 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.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.9.0(eslint@9.37.0): + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.37.0(supports-color@8.1.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} + dev: true + + /@eslint-community/regexpp@4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + /@eslint/config-array@0.20.0: + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/config-array@0.21.0(supports-color@8.1.1): + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + /@eslint/config-helpers@0.2.1: + resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/config-helpers@0.4.0: + resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + + /@eslint/core@0.13.0: + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true + + /@eslint/core@0.16.0: + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + + /@eslint/eslintrc@0.1.3: + resolution: {integrity: sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.4.0(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.14.1 + lodash: 4.17.21 + minimatch: 3.1.2 + 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} + dependencies: + ajv: 6.12.6 + debug: 4.4.0(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.14.1 + minimatch: 3.1.2 + 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} + dependencies: + ajv: 6.12.6 + debug: 4.4.0(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 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + 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.4.0(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 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/eslintrc@3.3.1(supports-color@8.1.1): + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + ajv: 6.12.6 + debug: 4.4.0(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 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@eslint/js@9.25.1: + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@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.6: + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + 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} + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + dev: true + + /@eslint/plugin-kit@0.4.0: + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + + /@fastify/ajv-compiler@1.1.0: + resolution: {integrity: sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==} + dependencies: + ajv: 6.12.6 + dev: false + + /@fastify/forwarded@1.0.0: + resolution: {integrity: sha512-VoO+6WD0aRz8bwgJZ8pkkxjq7o/782cQ1j945HWg0obZMgIadYW3Pew0+an+k1QL7IPZHM3db5WF6OP6x4ymMA==} + engines: {node: '>= 10'} + dev: false + + /@fastify/proxy-addr@3.0.0: + resolution: {integrity: sha512-ty7wnUd/GeSqKTC2Jozsl5xGbnxUnEFC0On2/zPv/8ixywipQmVZwuWvNGnBoitJ2wixwVqofwXNua8j6Y62lQ==} + dependencies: + '@fastify/forwarded': 1.0.0 + ipaddr.js: 2.1.0 + dev: false + + /@floating-ui/core@1.6.0: + resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + dependencies: + '@floating-ui/utils': 0.2.1 + dev: false + + /@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' + dependencies: + '@floating-ui/dom': 1.6.3 + dev: false + + /@floating-ui/dom@1.6.3: + resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + dependencies: + '@floating-ui/core': 1.6.0 + '@floating-ui/utils': 0.2.1 + dev: false + + /@floating-ui/utils@0.2.1: + resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + dev: false + + /@fluentui/date-time-utilities@8.5.16: + resolution: {integrity: sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==} + dependencies: + '@fluentui/set-version': 8.2.14 + tslib: 2.8.1 + dev: false + + /@fluentui/dom-utilities@2.2.14: + resolution: {integrity: sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==} + dependencies: + '@fluentui/set-version': 8.2.14 + tslib: 2.8.1 + dev: false + + /@fluentui/font-icons-mdl2@8.5.33(@types/react@17.0.74)(react@17.0.2): + resolution: {integrity: sha512-SsHPRtE1COeW23RLy7yX/y+zqzbnhm5CVIrA4msG8ZWPFEtQ7sHyVM0Rt9iQs6vMPs1DWdGSQDozTE1LlKvR+Q==} + 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.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' + 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.8.1 + dev: false + + /@fluentui/keyboard-key@0.4.14: + resolution: {integrity: sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==} + dependencies: + tslib: 2.8.1 + dev: false + + /@fluentui/keyboard-keys@9.0.7: + resolution: {integrity: sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==} + dependencies: + '@swc/helpers': 0.5.7 + dev: false + + /@fluentui/merge-styles@8.6.0: + resolution: {integrity: sha512-Si54VVK/XZQMTPT6aKE/RmqsY7uy9hERreU143Fbqtg9cf+Hr4iJ7FOGC4dXCfrFIXs0KvIHXCh5mtfrEW2aRQ==} + dependencies: + '@fluentui/set-version': 8.2.14 + tslib: 2.8.1 + dev: false + + /@fluentui/priority-overflow@9.1.11: + resolution: {integrity: sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==} + dependencies: + '@swc/helpers': 0.5.7 + dev: false + + /@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' + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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.8.1 + dev: false + + /@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.8.1 + dev: false + + /@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.8.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) + 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) + 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' + 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-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' + 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) + 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) + 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) + 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) + 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' + dependencies: + '@swc/helpers': 0.5.7 + '@types/react': 17.0.74 + react: 17.0.2 + dev: false + + /@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' + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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-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.8.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) + '@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.8.1 + dev: false + + /@fluentui/set-version@8.2.14: + resolution: {integrity: sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==} + dependencies: + tslib: 2.8.1 + dev: false + + /@fluentui/style-utilities@8.10.4(@types/react@17.0.74)(react@17.0.2): + resolution: {integrity: sha512-EwQydL1tyZnhxuiW4r1IMeKTQCK7qh3acekNhdfJwPTCV5JLAU5GvHC3PqqUFjxEct9Ywn2gBWVcj54a2EMuPA==} + 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) + '@microsoft/load-themed-styles': 1.10.295 + 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' + 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.8.1 + dev: false + + /@fluentui/tokens@1.0.0-alpha.16: + resolution: {integrity: sha512-Gr9G8LIlUhZYX5j6CfDQrofQqsWAz/q54KabWn1tWV/1083WwyoTZXiG1k6b37NnK7Feye7D7Nz+4MNqoKpXGw==} + dependencies: + '@swc/helpers': 0.5.7 + dev: false + + /@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' + 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.8.1 + dev: false + + /@gar/promisify@1.1.3: + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + dev: true + + /@griffel/core@1.15.2: + resolution: {integrity: sha512-RlsIXoSS3gaYykUgxFpwKAs/DV9cRUKp3CW1kt3iPAtsDTWn/o+8bT1jvBws/tMM2GBu/Uc0EkaIzUPqD7uA+Q==} + dependencies: + '@emotion/hash': 0.9.1 + '@griffel/style-types': 1.0.3 + csstype: 3.1.3 + rtl-css-js: 1.16.1 + stylis: 4.3.1 + tslib: 2.8.1 + dev: false + + /@griffel/react@1.5.20(react@17.0.2): + resolution: {integrity: sha512-1P2yaPctENFSCwyPIYXBmgpNH68c0lc/jwSzPij1QATHDK1AASKuSeq6hW108I67RKjhRyHCcALshdZ3GcQXSg==} + peerDependencies: + react: '>=16.8.0 <19.0.0' + dependencies: + '@griffel/core': 1.15.2 + react: 17.0.2 + tslib: 2.8.1 + dev: false + + /@griffel/style-types@1.0.3: + resolution: {integrity: sha512-AzbbYV/EobNIBtfMtyu2edFin895gjVxtu1nsRhTETUAIb0/LCZoue3Jd/kFLuPwe95rv5WRUBiQpVwJsrrFcw==} + dependencies: + csstype: 3.1.3 + dev: false + + /@humanfs/core@0.19.1: + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + /@humanfs/node@0.16.6: + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + /@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 + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array@0.5.0: + resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + 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 + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/gitignore-to-minimatch@1.0.2: + resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} + dev: true + + /@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 + dev: true + + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + deprecated: Use @eslint/object-schema instead + dev: true + + /@humanwhocodes/retry@0.3.1: + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + /@humanwhocodes/retry@0.4.2: + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + + /@inquirer/external-editor@1.0.1: + resolution: {integrity: sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + chardet: 2.1.0 + iconv-lite: 0.6.3 + dev: false + + /@isaacs/balanced-match@4.0.1: + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + /@isaacs/brace-expansion@5.0.0: + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/balanced-match': 4.0.1 + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false + + /@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 + + /@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} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.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 + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.5.0 + '@jest/test-result': 29.7.0(@types/node@17.0.41) + '@jest/transform': 29.5.0 + '@jest/types': 29.5.0 + '@types/node': 17.0.41 + 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@17.0.41) + 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.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - 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 + 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 + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + 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-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + 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': 17.0.41 + 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} + dependencies: + jest-get-type: 29.6.3 + + /@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 + + /@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': 17.0.41 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + /@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 + + /@jest/reporters@29.5.0: + 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 + 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.5.0 + '@jest/types': 29.5.0 + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/node': 17.0.41 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2(@types/node@17.0.41) + 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.2.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 + 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 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/node': 17.0.41 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2(@types/node@17.0.41) + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + 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.2.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 + + /@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 + + /@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} + 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) + jest-haste-map: 29.7.0 + jest-resolve: 29.7.0 + transitivePeerDependencies: + - '@types/node' + + /@jest/test-result@29.7.0(@types/node@20.17.19): + 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@20.17.19) + jest-haste-map: 29.7.0 + jest-resolve: 29.7.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} + dependencies: + '@jest/test-result': 29.7.0(@types/node@17.0.41) + 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.17.19): + 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@20.17.19) + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + transitivePeerDependencies: + - '@types/node' + + /@jest/transform@26.6.2: + resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==} + engines: {node: '>= 10.14.2'} + dependencies: + '@babel/core': 7.20.12 + '@jest/types': 26.6.2 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.9.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + 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 + 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: + resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.20.12 + '@jest/types': 29.5.0 + '@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.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + /@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.20.12 + '@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.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + /@jest/types@26.6.2: + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.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 + 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} + 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 + 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} + 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 + chalk: 4.1.2 + + /@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.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + /@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.6: + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + /@jsdevtools/ono@7.1.3: + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + dev: false + + /@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 + 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 + dependencies: + jsep: 1.4.0 + + /@jsonjoy.com/base64@1.1.2(tslib@2.8.1): + resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + dependencies: + tslib: 2.8.1 + + /@jsonjoy.com/json-pack@1.1.0(tslib@2.8.1): + resolution: {integrity: sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + dependencies: + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.3.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 1.21.0(tslib@2.8.1) + tslib: 2.8.1 + + /@jsonjoy.com/util@1.3.0(tslib@2.8.1): + resolution: {integrity: sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + dependencies: + tslib: 2.8.1 + + /@leichtgewicht/ip-codec@2.0.4: + resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} + dev: false + + /@mdx-js/loader@1.6.22(react@17.0.2): + resolution: {integrity: sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==} + dependencies: + '@mdx-js/mdx': 1.6.22 + '@mdx-js/react': 1.6.22(react@17.0.2) + loader-utils: 2.0.0 + transitivePeerDependencies: + - react + - supports-color + dev: true + + /@mdx-js/mdx@1.6.22: + resolution: {integrity: sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==} + dependencies: + '@babel/core': 7.12.9 + '@babel/plugin-syntax-jsx': 7.12.1(@babel/core@7.12.9) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9) + '@mdx-js/util': 1.6.22 + babel-plugin-apply-mdx-type-prop: 1.6.22(@babel/core@7.12.9) + babel-plugin-extract-import-names: 1.6.22 + camelcase-css: 2.0.1 + detab: 2.0.4 + hast-util-raw: 6.0.1 + lodash.uniq: 4.5.0 + mdast-util-to-hast: 10.0.1 + remark-footnotes: 2.0.0 + remark-mdx: 1.6.22 + remark-parse: 8.0.3 + remark-squeeze-paragraphs: 4.0.0 + style-to-object: 0.3.0 + unified: 9.2.0 + unist-builder: 2.0.3 + 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 + dependencies: + react: 17.0.2 + dev: true + + /@mdx-js/util@1.6.22: + resolution: {integrity: sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==} + dev: true + + /@microsoft/api-extractor-model@7.31.3(@types/node@20.17.19): + resolution: {integrity: sha512-dv4quQI46p0U03TCEpasUf6JrJL3qjMN7JUAobsPElxBv4xayYYvWW9aPpfYV+Jx6hqUcVaLVOeV7+5hxsyoFQ==} + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + dev: false + + /@microsoft/api-extractor@7.54.0(@types/node@20.17.19): + resolution: {integrity: sha512-t0SEcbVUPy4yAVykPafTNWktBg728X6p9t8qCuGDsYr1/lz2VQFihYDP2CnBFSArP5vwJPcvxktoKVSqH326cA==} + hasBin: true + dependencies: + '@microsoft/api-extractor-model': 7.31.3(@types/node@20.17.19) + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/rig-package': 0.6.0 + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + '@rushstack/ts-command-line': 5.1.3(@types/node@20.17.19) + diff: 8.0.2 + lodash: 4.17.21 + minimatch: 10.0.3 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + dev: false + + /@microsoft/load-themed-styles@1.10.295: + resolution: {integrity: sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==} + dev: false + + /@microsoft/teams-js@1.3.0-beta.4: + resolution: {integrity: sha512-AxDfMpiVqh3hsqTxMEYtQoz866WB/sw/Jl0pgTLh6sMHHmIBNMd+E0pVcP9WNk8zTkr9LCphJ5SziU1C8BgZMA==} + dev: true + + /@microsoft/tsdoc-config@0.17.0: + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} + dependencies: + '@microsoft/tsdoc': 0.15.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + dev: true + + /@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 + + /@microsoft/tsdoc-config@0.18.0: + resolution: {integrity: sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==} + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + dev: false + + /@microsoft/tsdoc@0.15.0: + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + dev: true + + /@microsoft/tsdoc@0.15.1: + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + + /@microsoft/tsdoc@0.16.0: + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + dev: false + + /@modelcontextprotocol/sdk@1.10.2: + resolution: {integrity: sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==} + engines: {node: '>=18'} + dependencies: + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.3 + eventsource: 3.0.6 + express: 5.1.0 + express-rate-limit: 7.5.0(express@5.1.0) + pkce-challenge: 5.0.0 + raw-body: 3.0.0 + zod: 3.24.3 + zod-to-json-schema: 3.24.5(zod@3.24.3) + transitivePeerDependencies: + - supports-color + dev: false + + /@module-federation/error-codes@0.20.0: + resolution: {integrity: sha512-pwKqIFXHG72AaXjtptZb+l5VOO3O7JQMVZ4txFhBH4H/BMu7o1LRBONllTisVmojLHOC/RQpBrxXSGrC64LC4w==} + + /@module-federation/runtime-core@0.20.0: + resolution: {integrity: sha512-M/0F/Ed6o1eCC5gKW3V3QtbxeNZ1w0Y7r6NKNacnwKKC12Nn7Ty9Rg1Kjw2B13EUqP8Qs2Y2IwmBEApy7cFLMw==} + dependencies: + '@module-federation/error-codes': 0.20.0 + '@module-federation/sdk': 0.20.0 + + /@module-federation/runtime-tools@0.20.0: + resolution: {integrity: sha512-5NimrYQyYr8hBl48YVU+w6bzl9uWDKNq3IEqYDgYljTYlupbVqsH2MJTf2A+c95nuCycjHS0vp5B3rnJ3Kdotg==} + dependencies: + '@module-federation/runtime': 0.20.0 + '@module-federation/webpack-bundler-runtime': 0.20.0 + + /@module-federation/runtime@0.20.0: + resolution: {integrity: sha512-9vHE27aLCWbvzUfYWCTCsNbx4IQ5MtK3f340s4swQofTKj0Qv5dJ6gRIwmHk3DqvH5/1FZoQi3FYMCmrThiGrg==} + dependencies: + '@module-federation/error-codes': 0.20.0 + '@module-federation/runtime-core': 0.20.0 + '@module-federation/sdk': 0.20.0 + + /@module-federation/sdk@0.20.0: + resolution: {integrity: sha512-bBFGA07PpfioJLY0DITVe+szGwLtFad+8R4rb5bPFKCZPZsKqLKwMB9tSsdHeieFPSc+1v20s6wq+R1DiWe56Q==} + + /@module-federation/webpack-bundler-runtime@0.20.0: + resolution: {integrity: sha512-TB0v5FRjfpL5fR8O5L4L3FTKJsb4EsflK8aNkdrJ46Tm/MR+PvL4SEx/AXpnsY+g/zkGRkiz10vwF0/RgMh6fQ==} + dependencies: + '@module-federation/runtime': 0.20.0 + '@module-federation/sdk': 0.20.0 + + /@mrmlnc/readdir-enhanced@2.2.1: + resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} + engines: {node: '>=4'} + dependencies: + call-me-maybe: 1.0.2 + glob-to-regexp: 0.3.0 + dev: true + + /@napi-rs/wasm-runtime@1.0.7: + resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + requiresBuild: true + dependencies: + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 + '@tybys/wasm-util': 0.10.1 + optional: true + + /@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@1.1.3: + resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} + engines: {node: '>= 6'} + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + /@npmcli/fs@1.1.1: + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.5.4 + dev: true + + /@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 + 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 + dependencies: + ansi-html-community: 0.0.8 + common-path-prefix: 3.0.0 + core-js-pure: 3.36.0 + error-stack-parser: 2.1.4 + find-up: 5.0.0 + html-entities: 2.5.2 + loader-utils: 2.0.4 + react-refresh: 0.11.0 + schema-utils: 3.3.0 + source-map: 0.7.4 + webpack: 4.47.0 + dev: true + + /@pnpm/crypto.base32-hash@1.0.1: + resolution: {integrity: sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==} + engines: {node: '>=14.6'} + dependencies: + rfc4648: 1.5.3 + dev: false + + /@pnpm/crypto.base32-hash@2.0.0: + resolution: {integrity: sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==} + engines: {node: '>=16.14'} + dependencies: + rfc4648: 1.5.3 + dev: false + + /@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 + dev: false + + /@pnpm/crypto.hash@1000.1.1: + resolution: {integrity: sha512-lb5kwXaOXdIW/4bkLLmtM9HEVRvp2eIvp+TrdawcPoaptgA/5f0/sRG0P52BF8dFqeNDj+1tGdqH89WQEqJnxA==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.0.0 + ssri: 10.0.5 + dev: false + + /@pnpm/crypto.polyfill@1.0.0: + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + dev: false + + /@pnpm/crypto.polyfill@1000.1.0: + resolution: {integrity: sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==} + engines: {node: '>=18.12'} + dev: false + + /@pnpm/dependency-path@1000.0.9: + resolution: {integrity: sha512-0AhabApfiq3EEYeed5HKQEU3ftkrfyKTNgkMH9esGdp2yc+62Zu7eWFf8WW6IGyitDQPLWGYjSEWDC9Bvv8nPg==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/crypto.hash': 1000.1.1 + '@pnpm/types': 1000.6.0 + semver: 7.7.2 + dev: false + + /@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.5.4 + dev: false + + /@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.7.2 + dev: false + + /@pnpm/error@1.4.0: + resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} + engines: {node: '>=10.16'} + dev: false + + /@pnpm/graceful-fs@1000.0.0: + resolution: {integrity: sha512-RvMEliAmcfd/4UoaYQ93DLQcFeqit78jhYmeJJVPxqFGmj0jEcb9Tu0eAOXr7tGP3eJHpgvPbTU4o6pZ1bJhxg==} + engines: {node: '>=18.12'} + dependencies: + graceful-fs: 4.2.11 + dev: false + + /@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 + dev: false + + /@pnpm/lockfile.types@1.0.3: + resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + + /@pnpm/lockfile.types@1002.0.1: + resolution: {integrity: sha512-anzBtzb78rf2KRExS8R38v4nyiU7b9ZMUsyzRdWpo+rfCmLUupjIxvasVlDgsf5pV7tbcBPASOamQ2G5V8IGAQ==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/resolver-base': 1005.0.1 + '@pnpm/types': 1000.8.0 + dev: true + + /@pnpm/logger@4.0.0: + resolution: {integrity: sha512-SIShw+k556e7S7tLZFVSIHjCdiVog1qWzcKW2RbLEHPItdisAFVNIe34kYd9fMSswTlSRLS/qRjw3ZblzWmJ9Q==} + engines: {node: '>=12.17'} + dependencies: + bole: 4.0.1 + 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'} + dependencies: + '@pnpm/types': 6.4.0 + fast-glob: 3.3.2 + 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: + resolution: {integrity: sha512-Zib2ysLctRnWM4KXXlljR44qSKwyEqYmLk+8VPBDBEK3l5Gp5mT3N4ix9E4qjYynvFqahumsxzOfxOYQhUGMGw==} + engines: {node: '>=18.12'} + dev: true + + /@pnpm/read-modules-dir@2.0.3: + resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} + engines: {node: '>=10.13'} + dependencies: + mz: 2.7.0 + dev: false + + /@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 + dev: false + + /@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 + dev: false + + /@pnpm/resolver-base@1005.0.1: + resolution: {integrity: sha512-NBha12KjFMKwaG1BWTCtgr/RprNQhXItCBkzc8jZuVU0itAHRQhEykexna9K8XjAtYxZ9rhvir0T5a7fTB23yQ==} + engines: {node: '>=18.12'} + dependencies: + '@pnpm/types': 1000.8.0 + dev: true + + /@pnpm/types@1000.6.0: + resolution: {integrity: sha512-6PsMNe98VKPGcg6LnXSW/LE3YfJ77nj+bPKiRjYRWAQLZ+xXjEQRaR0dAuyjCmchlv4wR/hpnMVRS21/fCod5w==} + engines: {node: '>=18.12'} + dev: false + + /@pnpm/types@1000.8.0: + resolution: {integrity: sha512-yx86CGHHquWAI0GgKIuV/RnYewcf5fVFZemC45C/K2cX0uV8GB8TUP541ZrokWola2fZx5sn1vL7xzbceRZfoQ==} + engines: {node: '>=18.12'} + dev: true + + /@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'} + dev: false + + /@pnpm/types@8.9.0: + resolution: {integrity: sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==} + engines: {node: '>=14.6'} + dev: false + + /@pnpm/types@9.4.2: + resolution: {integrity: sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==} + engines: {node: '>=16.14'} + dev: false + + /@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 + dev: false + + /@polka/url@1.0.0-next.25: + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + dev: true + + /@pothos/core@3.41.1(graphql@16.8.1): + resolution: {integrity: sha512-K+TGTK2Q7rmLU9WaC1cSDiGZaU9M+gHNbCYBom2W1vHuEYDUAiihVHz9tXYsrYjFMJSK+wLJ7Xp2374bQa9x/w==} + requiresBuild: true + peerDependencies: + graphql: '>=15.1.0' + dependencies: + graphql: 16.8.1 + dev: true + 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/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/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/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 + 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-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 + 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-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 + 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-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 + dependencies: + '@types/react': 17.0.74 + '@types/react-dom': 17.0.25 + react: 17.0.2 + dev: true + + /@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 + 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-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 + 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 + + /@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 + 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-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 + 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-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 + 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.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 + 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-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 + 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 + + /@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 + 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-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 + 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.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 + 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-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 + 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-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 + 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 + + /@redis/client@5.8.2: + resolution: {integrity: sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==} + engines: {node: '>= 18'} + dependencies: + cluster-key-slot: 1.1.2 + 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 + 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 + + /@remix-run/router@1.15.3: + resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} + engines: {node: '>=14.0.0'} + dev: true + + /@rspack/binding-darwin-arm64@1.6.0-beta.0: + resolution: {integrity: sha512-iRza6XmLT0obDwlaFvZ/LUJ3FqbcZnwA48C1bwCUlDnM+9uVFInCrcHkOjKuXnNcWBBJvNmLDWA5XYWzjtbXsw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@rspack/binding-darwin-x64@1.6.0-beta.0: + resolution: {integrity: sha512-4rHw6IHpWO04C22lEQK34vk6H+CtBkVQK9pEoA4gr+zMX8H+Bfl8liVQgeaAgwRqD7ipDo3jXGLaakVGktDexw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@rspack/binding-linux-arm64-gnu@1.6.0-beta.0: + resolution: {integrity: sha512-ww45NhAOreOYRFpjf1TYRvNQYLOMr/LodFZA1yI5MLRCSYMgvWuv6B1WIY7o3pLaGWeY/H+zf89JTpR2rNn25g==} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@rspack/binding-linux-arm64-musl@1.6.0-beta.0: + resolution: {integrity: sha512-nxkqLF8vz62NR65wxxMpdRDXce6q36R3BHvibyXlElSbSPSPL0n7gsOW2yMeCB5q812DRkzm2c9RNkpQ8nfXwQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@rspack/binding-linux-x64-gnu@1.6.0-beta.0: + resolution: {integrity: sha512-xfOzI6+TeLZFJ8I1siOguIlyf5m0ABWPAStPY2Wm4EIEhJz+dr5PTWa5V6DlXZkUfV/6E5ZAQGZmgcgOR+DPHw==} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@rspack/binding-linux-x64-musl@1.6.0-beta.0: + resolution: {integrity: sha512-OauuEH2P4ZXQ6vCnNZZocmxUJCTdmyUyZYHBzd+cK62uGzXcGGBp+R74grfmwThL+b4rFI2IupxMCLcDOop0zg==} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@rspack/binding-wasm32-wasi@1.6.0-beta.0: + resolution: {integrity: sha512-0sSaIM39lSNthIvZsDA7WDnwdP4/4rRH4QyN4/DLUOCdci5xUSUSz/MsRXA+smI41qu4sh9yU/jRT8pq9bSWAQ==} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@napi-rs/wasm-runtime': 1.0.7 + optional: true + + /@rspack/binding-win32-arm64-msvc@1.6.0-beta.0: + resolution: {integrity: sha512-QqtnwHhpst37I3eQtx1FqpWCQCkigg2M73QUDvjhCE+opb1X46XK+kZOyt5qO0fKRdOgtxTcTVLLzRUWuT4t4A==} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@rspack/binding-win32-ia32-msvc@1.6.0-beta.0: + resolution: {integrity: sha512-Bi8fcihGY8QEgo+u8S3JeD41OLIs1/b4lYYAKOUVmpwJeN0lTlT7oMVikD2bLLpPs+gUkinTeeoUjwx0YWlGlA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@rspack/binding-win32-x64-msvc@1.6.0-beta.0: + resolution: {integrity: sha512-h7EltjtoAI2ohKxurD09uoXoe94nHiqcozca4Z7sB+f1RaBnc9U3RmddCVkENGZ2YFDx77fC6bayu2WkdY2YIw==} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /@rspack/binding@1.6.0-beta.0: + resolution: {integrity: sha512-8CoJCSkWhhgAcmymvkvXb6fHV1zfRnx68mW/tFD/pN2BzwLrAqzvq9PUhJw0MLq4Dg+RIYG6xjzDDp3fkt574Q==} + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.6.0-beta.0 + '@rspack/binding-darwin-x64': 1.6.0-beta.0 + '@rspack/binding-linux-arm64-gnu': 1.6.0-beta.0 + '@rspack/binding-linux-arm64-musl': 1.6.0-beta.0 + '@rspack/binding-linux-x64-gnu': 1.6.0-beta.0 + '@rspack/binding-linux-x64-musl': 1.6.0-beta.0 + '@rspack/binding-wasm32-wasi': 1.6.0-beta.0 + '@rspack/binding-win32-arm64-msvc': 1.6.0-beta.0 + '@rspack/binding-win32-ia32-msvc': 1.6.0-beta.0 + '@rspack/binding-win32-x64-msvc': 1.6.0-beta.0 + + /@rspack/core@1.6.0-beta.0: + resolution: {integrity: sha512-wrGg90zjX5/cf2hKh2La0q3++twOBnk6z2WkWWcd1Jz5F9OcbHWyn+9yGHJI921A0AziC0pv7P1MmucmG3e7fA==} + engines: {node: '>=18.12.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@module-federation/runtime-tools': 0.20.0 + '@rspack/binding': 1.6.0-beta.0 + '@rspack/lite-tapable': 1.0.1 + + /@rspack/dev-server@1.1.4(@rspack/core@1.6.0-beta.0)(webpack@5.98.0): + resolution: {integrity: sha512-kGHYX2jYf3ZiHwVl0aUEPBOBEIG1aWleCDCAi+Jg32KUu3qr/zDUpCEd0wPuHfLEgk0X0xAEYCS6JMO7nBStNQ==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@rspack/core': '*' + dependencies: + '@rspack/core': 1.6.0-beta.0 + chokidar: 3.6.0 + http-proxy-middleware: 2.0.9 + p-retry: 6.2.0 + webpack-dev-server: 5.2.2(webpack@5.98.0) + ws: 8.18.0 + transitivePeerDependencies: + - '@types/webpack' + - bufferutil + - debug + - supports-color + - utf-8-validate + - webpack + - webpack-cli + dev: false + + /@rspack/lite-tapable@1.0.1: + resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} + engines: {node: '>=16.0.0'} + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: false + + /@rushstack/eslint-config@3.7.1(eslint@7.11.0)(typescript@5.8.2): + resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.10.4 + '@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) + '@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.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@rushstack/eslint-config@3.7.1(eslint@7.30.0)(typescript@5.8.2): + resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.10.4 + '@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) + '@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.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@rushstack/eslint-config@3.7.1(eslint@7.7.0)(typescript@5.8.2): + resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.10.4 + '@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) + '@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.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@rushstack/eslint-config@3.7.1(eslint@8.57.0)(typescript@5.8.2): + resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.10.4 + '@rushstack/eslint-plugin': 0.15.2(eslint@8.57.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@8.57.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.8.2(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/parser': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + eslint: 8.57.0 + eslint-plugin-promise: 6.1.1(eslint@8.57.0) + eslint-plugin-react: 7.33.2(eslint@8.57.0) + eslint-plugin-tsdoc: 0.3.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@rushstack/eslint-config@4.5.3(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-pKcN99fZLhOgjYS6LAwUGlsUauUeaPS/4GHpkagvXO+iogz+ATL2CvfOt25hpI93YIxpU80YggmI1OFVd2iTiw==} + peerDependencies: + eslint: ^8.57.0 || ^9.25.1 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.14.1 + '@rushstack/eslint-plugin': 0.22.0(eslint@8.57.0)(typescript@4.9.5) + '@rushstack/eslint-plugin-packlets': 0.14.0(eslint@8.57.0)(typescript@4.9.5) + '@rushstack/eslint-plugin-security': 0.13.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/parser': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + eslint: 8.57.0 + eslint-plugin-promise: 7.2.1(eslint@8.57.0) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-tsdoc: 0.4.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@rushstack/eslint-config@4.5.3(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-pKcN99fZLhOgjYS6LAwUGlsUauUeaPS/4GHpkagvXO+iogz+ATL2CvfOt25hpI93YIxpU80YggmI1OFVd2iTiw==} + peerDependencies: + eslint: ^8.57.0 || ^9.25.1 + typescript: '>=4.7.0' + dependencies: + '@rushstack/eslint-patch': 1.14.1 + '@rushstack/eslint-plugin': 0.22.0(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.14.0(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.13.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + eslint-plugin-promise: 7.2.1(eslint@9.37.0) + eslint-plugin-react: 7.37.5(eslint@9.37.0) + eslint-plugin-tsdoc: 0.4.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@rushstack/eslint-patch@1.10.4: + resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + dev: true + + /@rushstack/eslint-patch@1.14.1: + resolution: {integrity: sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ==} + + /@rushstack/eslint-plugin-packlets@0.14.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-o1udsL8lPAVmNEfjUOAoBcOATVs9RpFY6D/Lv2jfQ3ZqpmuDiNb4mNdB9AkI8I/01viyrIWz/iq08p31q/EIZg==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin-packlets@0.14.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-o1udsL8lPAVmNEfjUOAoBcOATVs9RpFY6D/Lv2jfQ3ZqpmuDiNb4mNdB9AkI8I/01viyrIWz/iq08p31q/EIZg==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.11.0)(typescript@5.8.2): + resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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@7.30.0)(typescript@5.8.2): + resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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@7.7.0)(typescript@5.8.2): + resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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-packlets@0.9.2(eslint@8.57.0)(typescript@5.8.2): + resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin-security@0.13.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-0ixotA+4NSvmTN4dq8mEKInj6kYE5q6SvySbggvDPUtJWBjmTbt4bdh9thxvAqNZWoflAMdX4FV+ixJ3CEx/cQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin-security@0.13.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-0ixotA+4NSvmTN4dq8mEKInj6kYE5q6SvySbggvDPUtJWBjmTbt4bdh9thxvAqNZWoflAMdX4FV+ixJ3CEx/cQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@rushstack/eslint-plugin-security@0.8.2(eslint@7.11.0)(typescript@5.8.2): + resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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.2(eslint@7.30.0)(typescript@5.8.2): + resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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.2(eslint@7.7.0)(typescript@5.8.2): + resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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@8.57.0)(typescript@5.8.2): + resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin@0.15.2(eslint@7.11.0)(typescript@5.8.2): + resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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.30.0)(typescript@5.8.2): + resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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@7.7.0)(typescript@5.8.2): + resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@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@8.57.0)(typescript@5.8.2): + resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin@0.22.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-2x1fJQnV6H0O2kZho0/+miOQaYwGIG3yk+vS2EeUqii0OE4ZbEk9ad9ec6duDuxgx77V/nPHkrd4ftB4Twubmg==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@rushstack/eslint-plugin@0.22.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-2x1fJQnV6H0O2kZho0/+miOQaYwGIG3yk+vS2EeUqii0OE4ZbEk9ad9ec6duDuxgx77V/nPHkrd4ftB4Twubmg==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@rushstack/tree-pattern': 0.3.4 + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@rushstack/heft-api-extractor-plugin@1.2.0(@rushstack/heft@1.1.4)(@types/node@20.17.19): + resolution: {integrity: sha512-YqsWciAVb0XiliWWV1V9gQG6SQ/vpCqGRRmGyuuN9Rtf1To+WUxUaoHdZcDKQgAnBOKTYzm8WaUt/D9Cp9G0HA==} + peerDependencies: + '@rushstack/heft': '*' + dependencies: + '@rushstack/heft': 1.1.4(@types/node@20.17.19) + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + semver: 7.5.4 + transitivePeerDependencies: + - '@types/node' + dev: false + + /@rushstack/heft-config-file@0.19.3(@types/node@20.17.19): + resolution: {integrity: sha512-jct1Y2JEvNlSYdxkjWQU5J3mbDIFUiMZabgJ4/2J7qA02ACz1Eozif8I1SosRXOKc7WRVs/2tCbI3eMwfPHIBA==} + engines: {node: '>=10.13.0'} + dependencies: + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/rig-package': 0.6.0 + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + '@ungap/structured-clone': 1.3.0 + jsonpath-plus: 10.3.0 + transitivePeerDependencies: + - '@types/node' + + /@rushstack/heft-jest-plugin@1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19)(jest-environment-node@29.5.0): + resolution: {integrity: sha512-dhzobYz2OhvNZuJDHFyqaKEuh2+dGyH2Z5Hy79qg7JPN/+1J3zepmbDLrbYNCWIv7o0qZPYHtfCYyOI9uHFHow==} + 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 + '@jest/reporters': 29.5.0 + '@jest/transform': 29.5.0 + '@rushstack/heft': 1.1.4(@types/node@20.17.19) + '@rushstack/heft-config-file': 0.19.3(@types/node@20.17.19) + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + jest-config: 29.5.0(@types/node@20.17.19) + 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: false + + /@rushstack/heft-lint-plugin@1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19): + resolution: {integrity: sha512-Cg3gaXWMYYhpSAnvxArOi4ozZJhoGK0ftVxKKg3BL0XUKCEOddOhtWtddvmc6sYOkMxkowZpHKVyEfQnp1uoFA==} + peerDependencies: + '@rushstack/heft': '*' + dependencies: + '@rushstack/heft': 1.1.4(@types/node@20.17.19) + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + json-stable-stringify-without-jsonify: 1.0.1 + semver: 7.5.4 + transitivePeerDependencies: + - '@types/node' + dev: false + + /@rushstack/heft-node-rig@2.11.6(@rushstack/heft@1.1.4)(@types/node@20.17.19): + resolution: {integrity: sha512-QdJvXJ3MAOgN6qzhWy+SJPlgYFISyht+etyErQfJ7mUvsZo5Gf3DWLl57rVC7UZO8ugXu2wwNemexFwY2PR+ng==} + peerDependencies: + '@rushstack/heft': '*' + dependencies: + '@microsoft/api-extractor': 7.54.0(@types/node@20.17.19) + '@rushstack/eslint-config': 4.5.3(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/heft': 1.1.4(@types/node@20.17.19) + '@rushstack/heft-api-extractor-plugin': 1.2.0(@rushstack/heft@1.1.4)(@types/node@20.17.19) + '@rushstack/heft-jest-plugin': 1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19)(jest-environment-node@29.5.0) + '@rushstack/heft-lint-plugin': 1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19) + '@rushstack/heft-typescript-plugin': 1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19) + '@types/heft-jest': 1.0.1 + eslint: 9.37.0(supports-color@8.1.1) + jest-environment-node: 29.5.0 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - jest-environment-jsdom + - jiti + - node-notifier + - supports-color + - ts-node + dev: false + + /@rushstack/heft-typescript-plugin@1.1.4(@rushstack/heft@1.1.4)(@types/node@20.17.19): + resolution: {integrity: sha512-nl/OyZRb3Y4lemdpWkYuDjlHv4PSGn75JIM794B8NxPGk5rYdocmc88cuChLtp1l/rwsZqUYJtXOpR77MHJ0EA==} + peerDependencies: + '@rushstack/heft': '*' + dependencies: + '@rushstack/heft': 1.1.4(@types/node@20.17.19) + '@rushstack/heft-config-file': 0.19.3(@types/node@20.17.19) + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@types/tapable': 1.0.6 + semver: 7.5.4 + tapable: 1.1.3 + transitivePeerDependencies: + - '@types/node' + dev: false + + /@rushstack/heft@1.1.4(@types/node@20.17.19): + resolution: {integrity: sha512-W5p8tlwxVrcHi/hoiN/qabJOcV6xZFuheJUIbEXFS4N2m/WDxS2u6GZuyuDaDaa8Ch3kFW/MsnYbRrlh4C4FXw==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + '@rushstack/heft-config-file': 0.19.3(@types/node@20.17.19) + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/operation-graph': 0.5.3(@types/node@20.17.19) + '@rushstack/rig-package': 0.6.0 + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + '@rushstack/ts-command-line': 5.1.3(@types/node@20.17.19) + '@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' + + /@rushstack/node-core-library@3.63.0(@types/node@20.17.19): + resolution: {integrity: sha512-Q7B3dVpBQF1v+mUfxNcNZh5uHVR8ntcnkN5GYjbBLrxUYHBGKbnCM+OdcN+hzCpFlLBH6Ob0dEHhZ0spQwf24A==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.17.19 + colors: 1.2.5 + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + z-schema: 5.0.6 + + /@rushstack/node-core-library@5.18.0(@types/node@20.17.19): + resolution: {integrity: sha512-XDebtBdw5S3SuZIt+Ra2NieT8kQ3D2Ow1HxhDQ/2soinswnOu9e7S69VSwTOLlQnx5mpWbONu+5JJjDxMAb6Fw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.17.19 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.0 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + + /@rushstack/operation-graph@0.5.3(@types/node@20.17.19): + resolution: {integrity: sha512-SET7T/lHo8DVmE7hqvgKq0pYxNU/lmAu24huIjAPkdH8dv8yy5NQYSBIXOeMxMZebRFMYiRJ6TniXWMan69lJw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + '@types/node': 20.17.19 + + /@rushstack/problem-matcher@0.1.1(@types/node@20.17.19): + resolution: {integrity: sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.17.19 + + /@rushstack/rig-package@0.6.0: + resolution: {integrity: sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==} + dependencies: + resolve: 1.22.8 + strip-json-comments: 3.1.1 + + /@rushstack/set-webpack-public-path-plugin@4.1.16(@types/node@20.17.19)(@types/webpack@4.41.32)(webpack@4.47.0): + resolution: {integrity: sha512-9YD76OHSYr3pqJwc3wcxIFL1kSxPUyw3xThaZrJDBumMRdAEx7Wj3J0xkPtri5BS06yi49fIC1Di75CxeworzA==} + peerDependencies: + '@types/webpack': ^4.39.8 + peerDependenciesMeta: + '@types/webpack': + optional: true + dependencies: + '@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) + '@types/webpack': 4.41.32 + transitivePeerDependencies: + - '@types/node' + - webpack + + /@rushstack/terminal@0.19.3(@types/node@20.17.19): + resolution: {integrity: sha512-0P8G18gK9STyO+CNBvkKPnWGMxESxecTYqOcikHOVIHXa9uAuTK+Fw8TJq2Gng1w7W6wTC9uPX6hGNvrMll2wA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.18.0(@types/node@20.17.19) + '@rushstack/problem-matcher': 0.1.1(@types/node@20.17.19) + '@types/node': 20.17.19 + supports-color: 8.1.1 + + /@rushstack/tree-pattern@0.3.4: + resolution: {integrity: sha512-9uROnkiHWsQqxW6HirXABfTRlgzhYp6tevbYIGkwKQ09VaayUBkvFvt/urDKMwlo+tGU0iQQLuVige6c48wTgw==} + + /@rushstack/ts-command-line@5.1.3(@types/node@20.17.19): + resolution: {integrity: sha512-Kdv0k/BnnxIYFlMVC1IxrIS0oGQd4T4b7vKfx52Y2+wk2WZSDFIvedr7JrhenzSlm3ou5KwtoTGTGd5nbODRug==} + dependencies: + '@rushstack/terminal': 0.19.3(@types/node@20.17.19) + '@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): + 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 + dependencies: + '@types/webpack': 4.41.32 + memfs: 3.4.3 + webpack: 4.47.0 + webpack-merge: 5.8.0 + + /@serverless-stack/aws-lambda-ric@2.0.13: + resolution: {integrity: sha512-Aj4X2wMW6O5/PQoKoBdQGC3LwQyGTgW1XZtF0rs07WE9s6Q+46zWaVgURQjoNmTNQKpHSGJYo6B+ycp9u7/CSA==} + hasBin: true + 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 + dependencies: + '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(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) + 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 + chalk: 4.1.2 + chokidar: 3.4.3 + cross-spawn: 7.0.3 + detect-port-alt: 1.1.6 + esbuild: 0.14.54 + esbuild-runner: 2.2.2(esbuild@0.14.54) + express: 4.21.1 + fs-extra: 9.1.0 + remeda: 0.0.32 + source-map-support: 0.5.21 + ws: 8.14.2 + yargs: 15.4.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + - better-sqlite3 + - bufferutil + - constructs + - mysql2 + - pg + - supports-color + - utf-8-validate + dev: true + + /@serverless-stack/core@1.18.4: + resolution: {integrity: sha512-j6eoGoZbADbLsc95ZJZQ3nWkXqdlfayx1xEWE0UpFjxthKUi8qZUONd7NOEyTHiR0yYV1NrANcWur2alvn+vlA==} + dependencies: + '@serverless-stack/aws-lambda-ric': 2.0.13 + '@trpc/server': 9.27.4 + acorn: 8.14.0 + acorn-walk: 8.3.2 + 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 + 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.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.21.1 + fs-extra: 9.1.0 + immer: 9.0.21 + js-yaml: 4.1.0 + 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) + log4js: 6.9.1 + picomatch: 2.3.1 + remeda: 0.0.32 + semver: 7.5.4 + typescript: 4.9.5 + uuid: 8.3.2 + ws: 8.14.2 + xstate: 4.26.1 + zip-local: 0.3.5 + optionalDependencies: + '@pothos/core': 3.41.1(graphql@16.8.1) + graphql: 16.8.1 + transitivePeerDependencies: + - better-sqlite3 + - bufferutil + - mysql2 + - 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==} + 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) + '@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 + fs-extra: 9.1.0 + glob: 7.2.3 + indent-string: 5.0.0 + zip-local: 0.3.5 + optionalDependencies: + graphql: 16.8.1 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + - better-sqlite3 + - bufferutil + - mysql2 + - pg + - supports-color + - utf-8-validate + dev: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + /@sindresorhus/is@4.6.0: + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + + /@smithy/abort-controller@2.2.0: + resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/config-resolver@2.2.0: + resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/core@1.4.2: + resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/credential-provider-imds@2.3.0: + resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} + engines: {node: '>=14.0.0'} + 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.8.1 + 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.8.1 + dev: true + + /@smithy/hash-node@2.2.0: + resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + dev: true + + /@smithy/invalid-dependency@2.2.0: + resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/is-array-buffer@2.2.0: + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/middleware-content-length@2.2.0: + resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/middleware-endpoint@2.5.1: + resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/middleware-retry@2.3.1: + resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} + engines: {node: '>=14.0.0'} + 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.8.1 + uuid: 9.0.1 + dev: true + + /@smithy/middleware-serde@2.3.0: + resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/middleware-stack@2.2.0: + resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/node-config-provider@2.3.0: + resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/node-http-handler@2.5.0: + resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/property-provider@2.2.0: + resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/protocol-http@3.3.0: + resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/querystring-builder@2.2.0: + resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + '@smithy/util-uri-escape': 2.2.0 + tslib: 2.8.1 + dev: true + + /@smithy/querystring-parser@2.2.0: + resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/service-error-classification@2.1.5: + resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + dev: true + + /@smithy/shared-ini-file-loader@2.4.0: + resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/signature-v4@2.3.0: + resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/smithy-client@2.5.1: + resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/types@2.12.0: + resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/url-parser@2.2.0: + resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} + dependencies: + '@smithy/querystring-parser': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-base64@2.3.0: + resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-body-length-browser@2.2.0: + resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/util-body-length-node@2.3.0: + resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/util-buffer-from@2.2.0: + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-config-provider@2.3.0: + resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/util-defaults-mode-browser@2.2.1: + resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} + engines: {node: '>= 10.0.0'} + dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + bowser: 2.11.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-defaults-mode-node@2.3.1: + resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} + engines: {node: '>= 10.0.0'} + 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.8.1 + dev: true + + /@smithy/util-endpoints@1.2.0: + resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} + engines: {node: '>= 14.0.0'} + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-hex-encoding@2.2.0: + resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/util-middleware@2.2.0: + resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-retry@2.2.0: + resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} + engines: {node: '>= 14.0.0'} + dependencies: + '@smithy/service-error-classification': 2.1.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + dev: true + + /@smithy/util-stream@2.2.0: + resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} + engines: {node: '>=14.0.0'} + 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.8.1 + dev: true + + /@smithy/util-uri-escape@2.2.0: + resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.8.1 + dev: true + + /@smithy/util-utf8@2.3.0: + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + dev: true + + /@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 + 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/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 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + 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 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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/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-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 + 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 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@storybook/addon-controls@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + 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/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@9.37.0)(react-dom@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 + 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.8.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 + dependencies: + '@babel/core': 7.20.12 + '@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) + '@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@9.37.0)(react-dom@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@9.37.0)(react-dom@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@20.17.19)(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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) + acorn: 7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) + acorn-walk: 7.2.0 + core-js: 3.36.0 + doctrine: 3.0.0 + escodegen: 2.1.0 + fast-deep-equal: 3.1.3 + global: 4.4.0 + html-tags: 3.3.1 + js-string-escape: 1.0.1 + loader-utils: 2.0.4 + lodash: 4.17.21 + nanoid: 3.3.7 + 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) + 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 + transitivePeerDependencies: + - '@storybook/builder-webpack5' + - '@storybook/manager-webpack5' + - '@types/react' + - bufferutil + - encoding + - eslint + - supports-color + - typescript + - utf-8-validate + - 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.8.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 + '@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.8.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.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) + '@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/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) + regenerator-runtime: 0.13.11 + ts-dedent: 2.2.0 + webpack: 4.47.0 + transitivePeerDependencies: + - '@storybook/angular' + - '@storybook/builder-webpack5' + - '@storybook/html' + - '@storybook/manager-webpack5' + - '@storybook/react' + - '@storybook/vue3' + - '@types/react' + - bufferutil + - encoding + - eslint + - lit + - supports-color + - svelte + - sveltedoc-parser + - typescript + - utf-8-validate + - vue + - 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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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 + 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) + regenerator-runtime: 0.13.11 + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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/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-events': 6.4.22 + '@storybook/csf': 0.0.2--canary.87bc651.0 + core-js: 3.36.0 + global: 4.4.0 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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/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-events': 6.4.22 + '@storybook/csf': 0.0.2--canary.87bc651.0 + core-js: 3.36.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 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + regenerator-runtime: 0.13.11 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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/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-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 + global: 4.4.0 + memoizerific: 1.11.3 + prop-types: 15.8.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + regenerator-runtime: 0.13.11 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + dependencies: + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@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) + '@types/react': 17.0.74 + '@types/webpack-env': 1.18.8 + core-js: 3.36.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 + + /@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 + 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/semver': 7.3.2 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@types/react': 17.0.74 + core-js: 3.36.0 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + 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 + telejson: 5.3.3 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + dev: 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)(typescript@5.8.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 + dependencies: + '@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-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) + '@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-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@9.37.0)(react-dom@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/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) + '@types/node': 14.18.63 + '@types/webpack': 4.41.32 + autoprefixer: 9.8.8 + babel-loader: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) + 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 + css-loader: 3.6.0(webpack@4.47.0) + file-loader: 6.2.0(webpack@4.47.0) + find-up: 5.0.0 + fork-ts-checker-webpack-plugin: 4.1.6 + glob: 7.2.3 + 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.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) + raw-loader: 4.0.2(webpack@4.47.0) + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + stable: 0.1.8 + 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.8.2 + url-loader: 4.1.1(file-loader@6.2.0)(webpack@4.47.0) + util-deprecate: 1.0.2 + 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 + transitivePeerDependencies: + - '@types/react' + - eslint + - supports-color + - vue-template-compiler + - webpack-cli + - webpack-command + dev: true + + /@storybook/channel-postmessage@6.4.22: + resolution: {integrity: sha512-gt+0VZLszt2XZyQMh8E94TqjHZ8ZFXZ+Lv/Mmzl0Yogsc2H+6VzTTQO4sv0IIx6xLbpgG72g5cr8VHsxW5kuDQ==} + dependencies: + '@storybook/channels': 6.4.22 + '@storybook/client-logger': 6.4.22 + '@storybook/core-events': 6.4.22 + core-js: 3.36.0 + global: 4.4.0 + qs: 6.14.0 + telejson: 5.3.3 + dev: true + + /@storybook/channel-websocket@6.4.22: + resolution: {integrity: sha512-Bm/FcZ4Su4SAK5DmhyKKfHkr7HiHBui6PNutmFkASJInrL9wBduBfN8YQYaV7ztr8ezoHqnYRx8sj28jpwa6NA==} + dependencies: + '@storybook/channels': 6.4.22 + '@storybook/client-logger': 6.4.22 + core-js: 3.36.0 + global: 4.4.0 + telejson: 5.3.3 + dev: true + + /@storybook/channels@6.4.22: + resolution: {integrity: sha512-cfR74tu7MLah1A8Rru5sak71I+kH2e/sY6gkpVmlvBj4hEmdZp4Puj9PTeaKcMXh9DgIDPNA5mb8yvQH6VcyxQ==} + dependencies: + core-js: 3.36.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.8.2): + resolution: {integrity: sha512-Paj5JtiYG6HjYYEiLm0SGg6GJ+ebJSvfbbYx5W+MNiojyMwrzkof+G2VEGk5AbE2JSkXvDQJ/9B8/SuS94yqvA==} + hasBin: true + peerDependencies: + jest: '*' + dependencies: + '@babel/core': 7.20.12 + '@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@9.37.0)(react-dom@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.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@20.17.19) + jscodeshift: 0.13.1(@babel/preset-env@7.24.0) + json5: 2.2.3 + leven: 3.1.0 + prompts: 2.4.2 + puppeteer-core: 2.1.1 + read-pkg-up: 7.0.1 + shelljs: 0.8.5 + strip-json-comments: 3.1.1 + ts-dedent: 2.2.0 + update-notifier: 5.1.0 + transitivePeerDependencies: + - eslint + - react + - react-dom + - supports-color + - typescript + - 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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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.8 + core-js: 3.36.0 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + qs: 6.14.0 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + regenerator-runtime: 0.13.11 + store2: 2.14.3 + synchronous-promise: 2.0.17 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@storybook/client-logger@6.4.22: + resolution: {integrity: sha512-LXhxh/lcDsdGnK8kimqfhu3C0+D2ylCSPPQNbU0IsLRmTfbpQYMdyl0XBjPdHiRVwlL7Gkw5OMjYemQgJ02zlw==} + dependencies: + core-js: 3.36.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==} + dependencies: + '@babel/types': 7.24.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.6 + globby: 11.1.0 + jscodeshift: 0.13.1(@babel/preset-env@7.24.0) + lodash: 4.17.21 + 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 + 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 + '@types/overlayscrollbars': 1.12.5 + '@types/react-syntax-highlighter': 11.0.5 + color-convert: 2.0.1 + core-js: 3.36.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) + 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-dom: 17.0.2(react@17.0.2) + react-popper-tooltip: 3.1.1(react-dom@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) + regenerator-runtime: 0.13.11 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@storybook/core-client@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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-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) + airbnb-js-shims: 2.2.1 + ansi-to-html: 0.6.15 + core-js: 3.36.0 + global: 4.4.0 + lodash: 4.17.21 + qs: 6.14.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.8.2 + unfetch: 4.2.0 + util-deprecate: 1.0.2 + webpack: 4.47.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@storybook/core-common@6.4.22(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@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-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) + '@storybook/node-logger': 6.4.22 + '@storybook/semver': 7.3.2 + '@types/node': 14.18.63 + '@types/pretty-hrtime': 1.0.3 + babel-loader: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) + 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.21.1 + file-system-cache: 1.1.0 + find-up: 5.0.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 + interpret: 2.2.0 + json5: 2.2.3 + lazy-universal-dotenv: 3.0.1 + picomatch: 2.3.1 + pkg-dir: 5.0.0 + pretty-hrtime: 1.0.3 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + resolve-from: 5.0.0 + slash: 3.0.0 + telejson: 5.3.3 + ts-dedent: 2.2.0 + typescript: 5.8.2 + util-deprecate: 1.0.2 + webpack: 4.47.0 + 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==} + dependencies: + core-js: 3.36.0 + dev: true + + /@storybook/core-server@6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@discoveryjs/json-ext': 0.5.7 + '@storybook/builder-webpack4': 6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@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)(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)(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@9.37.0)(react-dom@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) + '@types/node': 14.18.63 + '@types/node-fetch': 2.6.2 + '@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 + commander: 6.2.1 + compression: 1.7.4 + core-js: 3.36.0 + cpy: 8.1.2 + detect-port: 1.5.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 + 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 + slash: 3.0.0 + telejson: 5.3.3 + ts-dedent: 2.2.0 + typescript: 5.8.2 + util-deprecate: 1.0.2 + watchpack: 2.4.0 + webpack: 4.47.0 + ws: 8.14.2 + transitivePeerDependencies: + - '@types/react' + - bufferutil + - encoding + - eslint + - supports-color + - utf-8-validate + - vue-template-compiler + - webpack-cli + - webpack-command + dev: true + + /@storybook/core@6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@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)(eslint@9.37.0)(react-dom@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.8.2 + webpack: 4.47.0 + transitivePeerDependencies: + - '@storybook/manager-webpack5' + - '@types/react' + - bufferutil + - encoding + - eslint + - supports-color + - utf-8-validate + - vue-template-compiler + - webpack-cli + - webpack-command + dev: true + + /@storybook/csf-tools@6.4.22: + resolution: {integrity: sha512-LMu8MZAiQspJAtMBLU2zitsIkqQv7jOwX7ih5JrXlyaDticH7l2j6Q+1mCZNWUOiMTizj0ivulmUsSaYbpToSw==} + dependencies: + '@babel/core': 7.20.12 + '@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 + '@babel/types': 7.24.0 + '@mdx-js/mdx': 1.6.22 + '@storybook/csf': 0.0.2--canary.87bc651.0 + core-js: 3.36.0 + fs-extra: 9.1.0 + global: 4.4.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + 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==} + dependencies: + lodash: 4.17.21 + dev: true + + /@storybook/manager-webpack4@6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@babel/core': 7.20.12 + '@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.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)(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) + '@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 + css-loader: 3.6.0(webpack@4.47.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.8.2) + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + read-pkg-up: 7.0.1 + regenerator-runtime: 0.13.11 + resolve-from: 5.0.0 + style-loader: 1.3.0(webpack@4.47.0) + telejson: 5.3.3 + terser-webpack-plugin: 4.2.3(webpack@4.47.0) + ts-dedent: 2.2.0 + typescript: 5.8.2 + url-loader: 4.1.1(file-loader@6.2.0)(webpack@4.47.0) + util-deprecate: 1.0.2 + 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 + transitivePeerDependencies: + - '@types/react' + - encoding + - eslint + - supports-color + - vue-template-compiler + - webpack-cli + - webpack-command + dev: true + + /@storybook/node-logger@6.4.22: + resolution: {integrity: sha512-sUXYFqPxiqM7gGH7gBXvO89YEO42nA4gBicJKZjj9e+W4QQLrftjF9l+mAw2K0mVE10Bn7r4pfs5oEZ0aruyyA==} + dependencies: + '@types/npmlog': 4.1.6 + chalk: 4.1.2 + core-js: 3.36.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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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) + ansi-to-html: 0.6.15 + core-js: 3.36.0 + global: 4.4.0 + lodash: 4.17.21 + qs: 6.14.0 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + regenerator-runtime: 0.13.11 + synchronous-promise: 2.0.17 + ts-dedent: 2.2.0 + unfetch: 4.2.0 + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@storybook/react-docgen-typescript-plugin@1.0.2-canary.253f8c1.0(typescript@5.8.2)(webpack@4.47.0): + resolution: {integrity: sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==} + peerDependencies: + typescript: '>= 3.x' + webpack: '>= 4 || ^4 || ^5' + dependencies: + debug: 4.4.0(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.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@20.17.19)(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.8.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 + dependencies: + '@babel/core': 7.20.12 + '@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@9.37.0)(react-dom@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)(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.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': 20.17.19 + '@types/react': 17.0.74 + '@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 + global: 4.4.0 + lodash: 4.17.21 + prop-types: 15.8.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + react-refresh: 0.11.0 + read-pkg-up: 7.0.1 + regenerator-runtime: 0.13.11 + ts-dedent: 2.2.0 + typescript: 5.8.2 + webpack: 4.47.0 + transitivePeerDependencies: + - '@storybook/builder-webpack5' + - '@storybook/manager-webpack5' + - '@types/webpack' + - bufferutil + - encoding + - eslint + - sockjs-client + - supports-color + - type-fest + - utf-8-validate + - vue-template-compiler + - webpack-cli + - webpack-command + - 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 + dependencies: + '@storybook/client-logger': 6.4.22 + '@types/react': 17.0.74 + core-js: 3.36.0 + fast-deep-equal: 3.1.3 + global: 4.4.0 + history: 5.0.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + qs: 6.13.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) + ts-dedent: 2.2.0 + dev: true + + /@storybook/semver@7.3.2: + resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + core-js: 3.36.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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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 + estraverse: 5.3.0 + global: 4.4.0 + loader-utils: 2.0.4 + lodash: 4.17.21 + 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 + + /@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 + dependencies: + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@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 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + regenerator-runtime: 0.13.11 + slash: 3.0.0 + stable: 0.1.8 + synchronous-promise: 2.0.17 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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 + '@storybook/client-logger': 6.4.22 + core-js: 3.36.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) + global: 4.4.0 + memoizerific: 1.11.3 + polished: 4.3.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + resolve-from: 5.0.0 + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@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 + 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/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/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/semver': 7.3.2 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + copy-to-clipboard: 3.3.3 + core-js: 3.36.0 + core-js-pure: 3.36.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) + fuse.js: 3.6.1 + global: 4.4.0 + lodash: 4.17.21 + markdown-to-jsx: 7.4.3(react@17.0.2) + memoizerific: 1.11.3 + polished: 4.3.1 + qs: 6.14.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-sizeme: 3.0.2 + regenerator-runtime: 0.13.11 + resolve-from: 5.0.0 + store2: 2.14.3 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@swc/core-darwin-arm64@1.7.10: + resolution: {integrity: sha512-TYp4x/9w/C/yMU1olK5hTKq/Hi7BjG71UJ4V1U1WxI1JA3uokjQ/GoktDfmH5V5pX4dgGSOJwUe2RjoN8Z/XnA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-darwin-x64@1.7.10: + resolution: {integrity: sha512-P3LJjAWh5yLc6p5IUwV5LgRfA3R1oDCZDMabYyb2BVQuJTD4MfegW9DhBcUUF5dhBLwq3191KpLVzE+dLTbiXw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm-gnueabihf@1.7.10: + resolution: {integrity: sha512-yGOFjE7w/akRTmqGY3FvWYrqbxO7OB2N2FHj2LO5HtzXflfoABb5RyRvdEquX+17J6mEpu4EwjYNraTD/WHIEQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-gnu@1.7.10: + resolution: {integrity: sha512-SPWsgWHfdWKKjLrYlvhxcdBJ7Ruy6crJbPoE9NfD95eJEjMnS2yZTqj2ChFsY737WeyhWYlHzgYhYOVCp83YwQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-musl@1.7.10: + resolution: {integrity: sha512-PUi50bkNqnBL3Z/Zq6jSfwgN9A/taA6u2Zou0tjDJi7oVdpjdr7SxNgCGzMJ/nNg5D/IQn1opM1jktMvpsPAuQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-gnu@1.7.10: + resolution: {integrity: sha512-Sc+pY55gknCAmBQBR6DhlA7jZSxHaLSDb5Sevzi6DOFMXR79NpA6zWTNKwp1GK2AnRIkbAfvYLgOxS5uWTFVpg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-musl@1.7.10: + resolution: {integrity: sha512-g5NKx2LXaGd0K26hmEts1Cvb7ptIvq3MHSgr6/D1tRPcDZw1Sp0dYsmyOv0ho4F5GOJyiCooG3oE9FXdb7jIpQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-arm64-msvc@1.7.10: + resolution: {integrity: sha512-plRIsOcfy9t9Q/ivm5DA7I0HaIvfAWPbI+bvVRrr3C/1K2CSqnqZJjEWOAmx2LiyipijNnEaFYuLBp0IkGuJpg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-ia32-msvc@1.7.10: + resolution: {integrity: sha512-GntrVNT23viHtbfzmlK8lfBiKeajH24GzbDT7qXhnoO20suUPcyYZxyvCb4gWM2zu8ZBTPHNlqfrNsriQCZ+lQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-x64-msvc@1.7.10: + resolution: {integrity: sha512-uXIF8GuSappe1imm6Lf7pHGepfCBjDQlS+qTqvEGE0wZAsL1IVATK9P/cH/OCLfJXeQDTLeSYmrpwjtXNt46tQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core@1.7.10: + resolution: {integrity: sha512-l0xrFwBQ9atizhmV94yC2nwcecTk/oftofwMNPiFMGe56dqdmi2ArHaTV3PCtMlgaUH6rGCehoRMt5OrCI1ktg==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.19 + 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 + dev: false + + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: false + + /@swc/helpers@0.4.14: + resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} + dependencies: + tslib: 2.8.1 + dev: false + + /@swc/helpers@0.4.36: + resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} + dependencies: + legacy-swc-helpers: /@swc/helpers@0.4.14 + tslib: 2.8.1 + dev: false + + /@swc/helpers@0.5.7: + resolution: {integrity: sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==} + dependencies: + tslib: 2.8.1 + dev: false + + /@swc/types@0.1.19: + resolution: {integrity: sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==} + dependencies: + '@swc/counter': 0.1.3 + dev: false + + /@szmarczak/http-timer@4.0.6: + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + dependencies: + defer-to-connect: 2.0.1 + + /@tootallnate/once@1.1.2: + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + dev: true + + /@tootallnate/once@2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + /@trpc/server@9.27.4: + resolution: {integrity: sha512-yw0omUrxGp8+gEAuieZFeXB4bCqFvmyCDL3GOBv+Q6+cK0m5824ViHZKPgK5DYG1ijN/lbi1hP3UVKywPN7rbQ==} + dev: true + + /@trysound/sax@0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: false + + /@tybys/wasm-util@0.10.1: + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + optional: true + + /@types/argparse@1.0.38: + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + /@types/aws-lambda@8.10.93: + resolution: {integrity: sha512-Vsyi9ogDAY3REZDjYnXMRJJa62SDvxHXxJI5nGDQdZW058dDE+av/anynN2rLKbCKXDRNw3D/sQmqxVflZFi4A==} + dev: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.24.0 + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 + + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + dependencies: + '@babel/types': 7.24.0 + + /@types/body-parser@1.19.5: + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + dependencies: + '@types/connect': 3.4.38 + '@types/node': 17.0.41 + + /@types/bonjour@3.5.13: + resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} + dependencies: + '@types/node': 17.0.41 + dev: false + + /@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': 17.0.41 + '@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/color-convert@2.0.3: + resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==} + dependencies: + '@types/color-name': 1.1.3 + dev: true + + /@types/color-name@1.1.3: + resolution: {integrity: sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw==} + dev: true + + /@types/compression@1.7.5(@types/express@4.17.21): + resolution: {integrity: sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==} + peerDependencies: + '@types/express': '*' + 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: + resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} + dependencies: + '@types/express-serve-static-core': 4.17.43 + '@types/node': 17.0.41 + dev: false + + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 17.0.41 + + /@types/cors@2.8.17: + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@types/eslint-scope@3.7.7: + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.6 + + /@types/eslint@8.56.10: + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + dependencies: + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + dev: true + + /@types/eslint@9.6.1: + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + dependencies: + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + /@types/events@3.0.3: + resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} + dev: true + + /@types/express-serve-static-core@4.17.43: + resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==} + dependencies: + '@types/node': 17.0.41 + '@types/qs': 6.9.13 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + /@types/express@4.17.21: + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + 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/fs-extra@7.0.0: + resolution: {integrity: sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@types/glob@7.1.1: + resolution: {integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==} + dependencies: + '@types/events': 3.0.3 + '@types/minimatch': 6.0.0 + '@types/node': 17.0.41 + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 17.0.41 + + /@types/hast@2.3.10: + resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + dependencies: + '@types/unist': 2.0.10 + dev: true + + /@types/heft-jest@1.0.1: + resolution: {integrity: sha512-cF2iEUpvGh2WgLowHVAdjI05xuDo+GwCA8hGV3Q5PBl8apjd6BTcpPFQ2uPlfUM7BLpgur2xpYo8VeBXopMI4A==} + dependencies: + '@types/jest': 28.1.1 + + /@types/hoist-non-react-statics@3.3.5: + resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} + dependencies: + '@types/react': 17.0.74 + hoist-non-react-statics: 3.3.2 + + /@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.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + /@types/http-errors@2.0.4: + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + + /@types/http-proxy@1.17.14: + resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==} + dependencies: + '@types/node': 17.0.41 + + /@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: + resolution: {integrity: sha512-/CLhCW79JUeLKznI6mbVieGbl4QU5Hfn+6udw1YHZoofASjbQ5zaP5LzAUZYDpRYEjS4/P+DhEgyJ/PQmGGTWw==} + dev: true + + /@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==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + /@types/jest@23.3.13: + resolution: {integrity: sha512-ePl4l+7dLLmCucIwgQHAgjiepY++qcI6nb8eAwGNkB6OxmTe3Z9rQU3rSpomqu42PCCnlThZbOoxsf+qylJsLA==} + dev: true + + /@types/jest@28.1.1: + resolution: {integrity: sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA==} + dependencies: + jest-matcher-utils: 27.5.1 + pretty-format: 27.5.1 + + /@types/jest@29.2.5: + resolution: {integrity: sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + /@types/jest@29.5.12: + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /@types/jju@1.4.1: + resolution: {integrity: sha512-LFt+YA7Lv2IZROMwokZKiPNORAV5N3huMs3IKnzlE430HWhWYZ8b+78HiwJXJJP1V2IEjinyJURuRJfGoaFSIA==} + dev: true + + /@types/js-yaml@4.0.9: + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + dev: true + + /@types/jsdom@20.0.1: + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + dependencies: + '@types/node': 17.0.41 + '@types/tough-cookie': 4.0.5 + parse5: 7.1.2 + + /@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==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: false + + /@types/keyv@3.1.4: + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + dependencies: + '@types/node': 17.0.41 + + /@types/loader-utils@1.1.3: + resolution: {integrity: sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg==} + dependencies: + '@types/node': 17.0.41 + '@types/webpack': 4.41.32 + dev: true + + /@types/lodash@4.14.116: + resolution: {integrity: sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg==} + + /@types/lodash@4.17.20: + resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} + dev: false + + /@types/long@4.0.0: + resolution: {integrity: sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==} + dev: false + + /@types/mdast@3.0.15: + resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} + 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/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. + dependencies: + minimatch: 10.0.3 + dev: true + + /@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==} + dependencies: + '@types/node': 17.0.41 + form-data: 3.0.1 + dev: true + + /@types/node-forge@1.0.4: + resolution: {integrity: sha512-UpX8LTRrarEZPQvQqF5/6KQAqZolOVckH7txWdlsWIJrhBFFtwEUTcqeDouhrJl6t0F7Wg5cyUOAqqF8a6hheg==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@types/node-forge@1.3.11: + resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + dependencies: + '@types/node': 17.0.41 + dev: false + + /@types/node@14.0.1: + resolution: {integrity: sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==} + dev: true + + /@types/node@14.18.63: + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + dev: true + + /@types/node@17.0.41: + resolution: {integrity: sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==} + + /@types/node@20.12.12: + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/node@20.17.19: + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} + dependencies: + undici-types: 6.19.8 + + /@types/normalize-package-data@2.4.4: + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + dev: true + + /@types/npm-package-arg@6.1.0: + resolution: {integrity: sha512-vbt5fb0y1svMhu++1lwtKmZL76d0uPChFlw7kEzyUmTwfmpHRcFb8i0R8ElT69q/L+QLgK2hgECivIAvaEDwag==} + dev: true + + /@types/npm-packlist@1.1.2: + resolution: {integrity: sha512-9NYoEH87t90e6dkaQOuUTY/R1xUE0a67sXzJBuAB+b+/z4FysHFD19g/O154ToGjyWqKYkezVUtuBdtfd4hyfw==} + dev: true + + /@types/npmlog@4.1.6: + resolution: {integrity: sha512-0l3z16vnlJGl2Mi/rgJFrdwfLZ4jfNYgE6ZShEpjqhHuGTqdEzNles03NpYHwUMVYZa+Tj46UxKIEpE78lQ3DQ==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@types/object-hash@3.0.6: + resolution: {integrity: sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w==} + dev: true + + /@types/overlayscrollbars@1.12.5: + resolution: {integrity: sha512-1yMmgFrq1DQ3sCHyb3DNfXnE0dB463MjG47ugX3cyade3sOt3U8Fjxk/Com0JJguTLPtw766TSDaO4NC65Wgkw==} + dev: true + + /@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==} + dev: true + + /@types/prettier@2.7.3: + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + + /@types/pretty-hrtime@1.0.3: + resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} + dev: true + + /@types/prismjs@1.26.5: + resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + dev: false + + /@types/prop-types@15.7.11: + resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + + /@types/qs@6.9.13: + resolution: {integrity: sha512-iLR+1vTTJ3p0QaOUq6ACbY1mzKTODFDT/XedZI8BksOotFmL4ForwDfRQ/DZeuTHR7/2i4lI1D203gdfxuqTlA==} + + /@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==} + dependencies: + '@types/react': 17.0.74 + + /@types/react-redux@7.1.33: + resolution: {integrity: sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==} + dependencies: + '@types/hoist-non-react-statics': 3.3.5 + '@types/react': 17.0.74 + 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==} + dependencies: + '@types/react': 17.0.74 + dev: true + + /@types/react@17.0.74: + resolution: {integrity: sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==} + dependencies: + '@types/prop-types': 15.7.11 + '@types/scheduler': 0.16.8 + csstype: 3.1.3 + + /@types/read-package-tree@5.1.0: + resolution: {integrity: sha512-QEaGDX5COe5Usog79fca6PEycs59075O/W0QcOJjVNv+ZQ26xjqxg8sWu63Lwdt4KAI08gb4Muho1EbEKs3YFw==} + dev: true + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: true + + /@types/responselike@1.0.3: + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + dependencies: + '@types/node': 17.0.41 + + /@types/retry@0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: false + + /@types/retry@0.12.2: + resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} + dev: false + + /@types/scheduler@0.16.8: + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + + /@types/semver@7.5.0: + resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} + + /@types/send@0.17.4: + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + dependencies: + '@types/mime': 1.3.5 + '@types/node': 17.0.41 + + /@types/serialize-javascript@5.0.2: + resolution: {integrity: sha512-BRLlwZzRoZukGaBtcUxkLsZsQfWZpvog6MZk3PWQO9Q6pXmXFzjU5iGzZ+943evp6tkkbN98N1Z31KT0UG1yRw==} + dev: true + + /@types/serve-index@1.9.4: + resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} + dependencies: + '@types/express': 4.17.21 + dev: false + + /@types/serve-static@1.15.5: + resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} + dependencies: + '@types/http-errors': 2.0.4 + '@types/mime': 3.0.4 + '@types/node': 17.0.41 + + /@types/sockjs@0.3.36: + resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + dependencies: + '@types/node': 17.0.41 + dev: false + + /@types/source-list-map@0.1.6: + resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==} + + /@types/ssri@7.1.5: + resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + /@types/strict-uri-encode@2.0.0: + resolution: {integrity: sha512-R6vDd7CHxcWMzv5wfVhR3qyCRVQoZKwVd6kit0rkozTThRZSXZKEW2Kz3AxfVqq9+UyJAz1g8Q+bJ3CL6NzztQ==} + dev: true + + /@types/supports-color@8.1.3: + resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} + dev: true + + /@types/tapable@1.0.6: + resolution: {integrity: sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==} + + /@types/tar@6.1.6: + resolution: {integrity: sha512-HQ06kiiDXz9uqtmE9ksQUn1ovcPr1gGV9EgaCWo6FGYKD0onNBCetBzL0kfcS8Kbj1EFxJWY9jL2W4ZvvtGI8Q==} + dependencies: + '@types/node': 17.0.41 + minipass: 4.2.8 + dev: true + + /@types/through@0.0.33: + resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} + dependencies: + '@types/node': 17.0.41 + dev: true + + /@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==} + dependencies: + source-map: 0.6.1 + + /@types/ungap__structured-clone@1.2.0: + resolution: {integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==} + dev: true + + /@types/unist@2.0.10: + resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} + dev: true + + /@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/vscode@1.103.0: + resolution: {integrity: sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q==} + dev: true + + /@types/watchpack@2.4.0: + resolution: {integrity: sha512-PSAD+o9hezvfUFFzrYB/PO6Je7kwiZ2BSnB3/EZ9le+jTDKB6x5NJ96WWzQz1h/AyGJ/de3/1KpuBTkUFZm77A==} + dependencies: + '@types/graceful-fs': 4.1.9 + '@types/node': 17.0.41 + dev: true + + /@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==} + dependencies: + '@types/node': 17.0.41 + '@types/source-list-map': 0.1.6 + source-map: 0.7.4 + + /@types/webpack@4.41.32: + resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==} + dependencies: + '@types/node': 17.0.41 + '@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==} + dependencies: + '@types/node': 17.0.41 + + /@types/xmldoc@1.1.4: + resolution: {integrity: sha512-a/ONNCf9itbmzEz1ohx0Fv5TLJzXIPQTapxFu+DlYlDtn9UcAa1OhnrOOMwbU8125hFjrkJKL3qllD7vO5Bivw==} + dev: true + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + /@types/yargs@15.0.19: + resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /@types/yargs@17.0.32: + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + 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.8.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.12.1 + '@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.0(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.8.2) + typescript: 5.8.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.8.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.12.1 + '@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.0(supports-color@8.1.1) + eslint: 7.30.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.8.2) + 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.8.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.12.1 + '@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.0(supports-color@8.1.1) + eslint: 7.7.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.8.2) + 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.8.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.12.1 + '@typescript-eslint/parser': 6.19.1(eslint@8.57.0)(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.0)(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.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.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/type-utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/parser@6.19.1(eslint@7.11.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 7.11.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.19.1(eslint@7.30.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 7.30.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.19.1(eslint@7.7.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 7.7.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.19.1(eslint@8.57.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 8.57.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.46.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.46.0(eslint@8.57.0)(typescript@5.8.2): + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 9.37.0(supports-color@8.1.1) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/project-service@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + debug: 4.4.0(supports-color@8.1.1) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/project-service@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/rule-tester@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-cIz9Z9BeL8YHKPVAHaFoSX4H359UPtbl93kRVS+Kx94HtFP48JXKmmUOBGRT/WdRQtpliu7U9pKGbCXYjv2byg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@types/semver': 7.5.0 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + ajv: 6.12.6 + eslint: 9.37.0(supports-color@8.1.1) + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/scope-manager@6.19.1(typescript@5.8.2): + resolution: {integrity: sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@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@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/scope-manager@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + transitivePeerDependencies: + - typescript + + /@typescript-eslint/tsconfig-utils@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 4.9.5 + dev: true + + /@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 5.8.2 + + /@typescript-eslint/type-utils@6.19.1(eslint@7.11.0)(typescript@5.8.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 + 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.0(supports-color@8.1.1) + eslint: 7.11.0 + ts-api-utils: 1.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@6.19.1(eslint@7.30.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 7.30.0 + ts-api-utils: 1.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@6.19.1(eslint@7.7.0)(typescript@5.8.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 + dependencies: + '@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.0(supports-color@8.1.1) + eslint: 7.7.0 + ts-api-utils: 1.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@6.19.1(eslint@8.57.0)(typescript@5.8.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 + dependencies: + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@8.46.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + '@typescript-eslint/utils': 8.46.0(eslint@8.57.0)(typescript@4.9.5) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.0 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 9.37.0(supports-color@8.1.1) + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/types@6.19.1(typescript@5.8.2): + resolution: {integrity: sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + dependencies: + typescript: 5.8.2 + dev: true + + /@typescript-eslint/types@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + dependencies: + typescript: 4.9.5 + dev: true + + /@typescript-eslint/types@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + dependencies: + typescript: 5.8.2 + + /@typescript-eslint/typescript-estree@6.19.1(typescript@5.8.2): + resolution: {integrity: sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.0(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.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@4.9.5) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@4.9.5) + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.8.2) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.46.0(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/utils@6.19.1(eslint@7.11.0)(typescript@5.8.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 + 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.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.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@6.19.1(eslint@7.30.0)(typescript@5.8.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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@7.30.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.0 + '@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.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@6.19.1(eslint@7.7.0)(typescript@5.8.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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@7.7.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.0 + '@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.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@6.19.1(eslint@8.57.0)(typescript@5.8.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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.0 + '@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.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@8.46.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.46.0(typescript@4.9.5) + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@4.9.5) + eslint: 8.57.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.46.0(typescript@5.8.2) + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.8.2) + eslint: 9.37.0(supports-color@8.1.1) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/visitor-keys@6.19.1(typescript@5.8.2): + resolution: {integrity: sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + eslint-visitor-keys: 3.4.3 + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/visitor-keys@8.46.0(typescript@4.9.5): + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@4.9.5) + eslint-visitor-keys: 4.2.1 + transitivePeerDependencies: + - typescript + dev: true + + /@typescript-eslint/visitor-keys@8.46.0(typescript@5.8.2): + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0(typescript@5.8.2) + eslint-visitor-keys: 4.2.1 + transitivePeerDependencies: + - typescript + + /@ungap/structured-clone@1.3.0: + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + /@vscode/test-electron@1.6.2: + resolution: {integrity: sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==} + engines: {node: '>=8.9.3'} + dependencies: + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + rimraf: 3.0.2 + unzipper: 0.10.14 + transitivePeerDependencies: + - supports-color + dev: true + + /@vscode/vsce-sign-alpine-arm64@2.0.5: + resolution: {integrity: sha512-XVmnF40APwRPXSLYA28Ye+qWxB25KhSVpF2eZVtVOs6g7fkpOxsVnpRU1Bz2xG4ySI79IRuapDJoAQFkoOgfdQ==} + cpu: [arm64] + os: [alpine] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-alpine-x64@2.0.5: + resolution: {integrity: sha512-JuxY3xcquRsOezKq6PEHwCgd1rh1GnhyH6urVEWUzWn1c1PC4EOoyffMD+zLZtFuZF5qR1I0+cqDRNKyPvpK7Q==} + cpu: [x64] + os: [alpine] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-darwin-arm64@2.0.5: + resolution: {integrity: sha512-z2Q62bk0ptADFz8a0vtPvnm6vxpyP3hIEYMU+i1AWz263Pj8Mc38cm/4sjzxu+LIsAfhe9HzvYNS49lV+KsatQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-darwin-x64@2.0.5: + resolution: {integrity: sha512-ma9JDC7FJ16SuPXlLKkvOD2qLsmW/cKfqK4zzM2iJE1PbckF3BlR08lYqHV89gmuoTpYB55+z8Y5Fz4wEJBVDA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-arm64@2.0.5: + resolution: {integrity: sha512-Hr1o0veBymg9SmkCqYnfaiUnes5YK6k/lKFA5MhNmiEN5fNqxyPUCdRZMFs3Ajtx2OFW4q3KuYVRwGA7jdLo7Q==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-arm@2.0.5: + resolution: {integrity: sha512-cdCwtLGmvC1QVrkIsyzv01+o9eR+wodMJUZ9Ak3owhcGxPRB53/WvrDHAFYA6i8Oy232nuen1YqWeEohqBuSzA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-linux-x64@2.0.5: + resolution: {integrity: sha512-XLT0gfGMcxk6CMRLDkgqEPTyG8Oa0OFe1tPv2RVbphSOjFWJwZgK3TYWx39i/7gqpDHlax0AP6cgMygNJrA6zg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-win32-arm64@2.0.5: + resolution: {integrity: sha512-hco8eaoTcvtmuPhavyCZhrk5QIcLiyAUhEso87ApAWDllG7djIrWiOCtqn48k4pHz+L8oCQlE0nwNHfcYcxOPw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign-win32-x64@2.0.5: + resolution: {integrity: sha512-1ixKFGM2FwM+6kQS2ojfY3aAelICxjiCzeg4nTHpkeU1Tfs4RC+lVLrgq5NwcBC7ZLr6UfY3Ct3D6suPeOf7BQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@vscode/vsce-sign@2.0.6: + resolution: {integrity: sha512-j9Ashk+uOWCDHYDxgGsqzKq5FXW9b9MW7QqOIYZ8IYpneJclWTBeHZz2DJCSKQgo+JAqNcaRRE1hzIx0dswqAw==} + requiresBuild: true + optionalDependencies: + '@vscode/vsce-sign-alpine-arm64': 2.0.5 + '@vscode/vsce-sign-alpine-x64': 2.0.5 + '@vscode/vsce-sign-darwin-arm64': 2.0.5 + '@vscode/vsce-sign-darwin-x64': 2.0.5 + '@vscode/vsce-sign-linux-arm': 2.0.5 + '@vscode/vsce-sign-linux-arm64': 2.0.5 + '@vscode/vsce-sign-linux-x64': 2.0.5 + '@vscode/vsce-sign-win32-arm64': 2.0.5 + '@vscode/vsce-sign-win32-x64': 2.0.5 + dev: false + + /@vscode/vsce@3.2.1: + resolution: {integrity: sha512-AY9vBjwExakK1c0cI/3NN2Ey0EgiKLBye/fxl/ue+o4q6RZ7N+xzd1jAD6eI6eBeMVANi617+V2rxIAkDPco2Q==} + engines: {node: '>= 20'} + hasBin: true + dependencies: + '@azure/identity': 4.5.0 + '@vscode/vsce-sign': 2.0.6 + 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.0 + glob: 11.0.3 + hosted-git-info: 4.1.0 + jsonc-parser: 3.3.1 + leven: 3.1.0 + markdown-it: 14.1.0 + mime: 1.6.0 + minimatch: 3.1.2 + parse-semver: 1.1.1 + read: 1.0.7 + semver: 7.5.4 + tmp: 0.2.3 + 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 + dev: false + + /@webassemblyjs/ast@1.14.1: + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + dependencies: + '@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==} + 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.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==} + dependencies: + '@webassemblyjs/wast-printer': 1.9.0 + + /@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==} + dependencies: + '@webassemblyjs/ast': 1.9.0 + + /@webassemblyjs/helper-numbers@1.13.2: + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + 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: + 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==} + 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/helper-wasm-section@1.9.0: + resolution: {integrity: sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==} + 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.13.2: + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + dependencies: + '@xtuc/ieee754': 1.2.0 + + /@webassemblyjs/ieee754@1.9.0: + resolution: {integrity: sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==} + dependencies: + '@xtuc/ieee754': 1.2.0 + + /@webassemblyjs/leb128@1.13.2: + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + dependencies: + '@xtuc/long': 4.2.2 + + /@webassemblyjs/leb128@1.9.0: + resolution: {integrity: sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==} + dependencies: + '@xtuc/long': 4.2.2 + + /@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==} + 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-edit@1.9.0: + resolution: {integrity: sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==} + dependencies: + '@webassemblyjs/ast': 1.9.0 + '@webassemblyjs/helper-buffer': 1.9.0 + '@webassemblyjs/helper-wasm-bytecode': 1.9.0 + '@webassemblyjs/helper-wasm-section': 1.9.0 + '@webassemblyjs/wasm-gen': 1.9.0 + '@webassemblyjs/wasm-opt': 1.9.0 + '@webassemblyjs/wasm-parser': 1.9.0 + '@webassemblyjs/wast-printer': 1.9.0 + + /@webassemblyjs/wasm-gen@1.14.1: + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + 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-gen@1.9.0: + resolution: {integrity: sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==} + dependencies: + '@webassemblyjs/ast': 1.9.0 + '@webassemblyjs/helper-wasm-bytecode': 1.9.0 + '@webassemblyjs/ieee754': 1.9.0 + '@webassemblyjs/leb128': 1.9.0 + '@webassemblyjs/utf8': 1.9.0 + + /@webassemblyjs/wasm-opt@1.14.1: + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + 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-opt@1.9.0: + resolution: {integrity: sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==} + 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.14.1: + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + 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/wasm-parser@1.9.0: + resolution: {integrity: sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==} + dependencies: + '@webassemblyjs/ast': 1.9.0 + '@webassemblyjs/helper-api-error': 1.9.0 + '@webassemblyjs/helper-wasm-bytecode': 1.9.0 + '@webassemblyjs/ieee754': 1.9.0 + '@webassemblyjs/leb128': 1.9.0 + '@webassemblyjs/utf8': 1.9.0 + + /@webassemblyjs/wast-parser@1.9.0: + resolution: {integrity: sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==} + dependencies: + '@webassemblyjs/ast': 1.9.0 + '@webassemblyjs/floating-point-hex-parser': 1.9.0 + '@webassemblyjs/helper-api-error': 1.9.0 + '@webassemblyjs/helper-code-frame': 1.9.0 + '@webassemblyjs/helper-fsm': 1.9.0 + '@xtuc/long': 4.2.2 + + /@webassemblyjs/wast-printer@1.14.1: + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + /@webassemblyjs/wast-printer@1.9.0: + resolution: {integrity: sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==} + 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/long@4.2.2: + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + /@yarnpkg/lockfile@1.0.2: + resolution: {integrity: sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw==} + dev: false + + /@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 + dev: false + + /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==} + dev: true + + /abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + /accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + dev: false + + /acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + dependencies: + acorn: 8.14.0 + acorn-walk: 8.3.2 + + /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 + dependencies: + acorn: 7.4.1 + dev: true + + /acorn-jsx@5.3.2(acorn@8.14.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + + /acorn-jsx@5.3.2(acorn@8.15.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.15.0 + + /acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + 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 + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + /acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + /acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + /address@1.2.2: + resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} + engines: {node: '>= 10.0.0'} + dev: true + + /agent-base@5.1.1: + resolution: {integrity: sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==} + engines: {node: '>= 6.0.0'} + dev: true + + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.4.0(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.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + dev: false + + /agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + dependencies: + humanize-ms: 1.2.1 + dev: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /airbnb-js-shims@2.2.1: + resolution: {integrity: sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==} + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + 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.9 + object.fromentries: 2.0.8 + object.getownpropertydescriptors: 2.1.7 + object.values: 1.2.1 + promise.allsettled: 1.0.7 + promise.prototype.finally: 3.1.8 + string.prototype.matchall: 4.0.12 + string.prototype.padend: 3.1.5 + string.prototype.padstart: 3.1.6 + symbol.prototype.description: 1.0.6 + dev: true + + /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-errors@1.0.1(ajv@6.12.6): + resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} + peerDependencies: + ajv: '>=5.0.0' + dependencies: + ajv: 6.12.6 + + /ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + dependencies: + ajv: 8.13.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-keywords@3.5.2(ajv@6.12.6): + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + dependencies: + ajv: 6.12.6 + + /ajv-keywords@5.1.0(ajv@8.13.0): + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + dependencies: + ajv: 8.13.0 + fast-deep-equal: 3.1.3 + + /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 + + /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 + + /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 + + /ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + dependencies: + string-width: 4.2.3 + + /ansi-colors@3.2.4: + resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} + engines: {node: '>=6'} + dev: true + + /ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + 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-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.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + 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: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + /ansi-to-html@0.6.15: + resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==} + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + entities: 2.2.0 + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: false + + /anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + 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'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /app-root-dir@1.0.2: + resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} + dev: true + + /aproba@1.2.0: + resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true + + /archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + 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'} + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + 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'} + dependencies: + archiver-utils: 2.1.0 + async: 3.2.5 + 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 + + /are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + dev: false + + /are-we-there-yet@1.1.7: + resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} + 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'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + /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.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + is-array-buffer: 3.0.4 + + /array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.2 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + /array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + dev: false + + /array-union@1.0.2: + resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} + engines: {node: '>=0.10.0'} + dependencies: + array-uniq: 1.0.3 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + dev: true + + /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'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.2 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + /array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: false + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + /array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + dev: false + + /array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + /array.prototype.map@1.0.7: + resolution: {integrity: sha512-XpcFfLoBEAhezrrNw1V+yLXkE7M6uR7xJEsxbG6c/V9v043qurwVJB9r9UTnoSioFDoz1i1VOydpWGmJpfVZbg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-array-method-boxes-properly: 1.0.0 + es-object-atoms: 1.1.1 + is-string: 1.1.1 + dev: true + + /array.prototype.reduce@1.0.6: + resolution: {integrity: sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-array-method-boxes-properly: 1.0.0 + is-string: 1.1.1 + + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + /arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + 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'} + dev: true + + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: false + + /asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + /assert@1.5.1: + resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} + dependencies: + object.assign: 4.1.5 + util: 0.10.4 + + /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'} + dev: true + + /ast-types@0.14.2: + resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} + engines: {node: '>=4'} + dependencies: + tslib: 2.8.1 + dev: true + + /astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + dev: true + + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + requiresBuild: true + optional: true + + /async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + dev: true + + /async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + dependencies: + retry: 0.13.1 + dev: true + + /async@1.5.2: + resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} + dev: true + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /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'} + dev: true + + /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'} + dev: false + + /atomically@1.7.0: + resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} + engines: {node: '>=10.12.0'} + dev: true + + /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 + 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 + postcss-value-parser: 4.2.0 + + /autoprefixer@9.8.8: + resolution: {integrity: sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==} + hasBin: true + dependencies: + browserslist: 4.23.0 + caniuse-lite: 1.0.30001599 + 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'} + dependencies: + possible-typed-array-names: 1.0.0 + + /avvio@7.2.5: + resolution: {integrity: sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA==} + dependencies: + archy: 1.0.0 + debug: 4.4.0(supports-color@8.1.1) + fastq: 1.17.1 + queue-microtask: 1.2.3 + transitivePeerDependencies: + - supports-color + dev: false + + /aws-cdk-lib@2.189.1(constructs@10.0.130): + resolution: {integrity: sha512-9JU0yUr2iRTJ1oCPrHyx7hOtBDWyUfyOcdb6arlumJnMcQr2cyAMASY8HuAXHc8Y10ipVp8dRTW+J4/132IIYA==} + engines: {node: '>= 14.15.0'} + peerDependencies: + constructs: ^10.0.0 + dependencies: + '@aws-cdk/asset-awscli-v1': 2.2.230 + '@aws-cdk/asset-node-proxy-agent-v6': 2.1.0 + '@aws-cdk/cloud-assembly-schema': 41.2.0 + constructs: 10.0.130 + dev: true + bundledDependencies: + - '@balena/dockerignore' + - case + - fs-extra + - ignore + - jsonschema + - minimatch + - punycode + - semver + - table + - yaml + - mime-types + + /aws-cdk-lib@2.50.0(constructs@10.0.130): + resolution: {integrity: sha512-deDbZTI7oyu3rqUyqjwhP6tnUO8MD70lE98yR65xiYty4yXBpsWKbeH3s1wNLpLAWS3hWJYyMtjZ4ZfC35NtVg==} + engines: {node: '>= 14.15.0'} + peerDependencies: + constructs: ^10.0.0 + dependencies: + '@balena/dockerignore': 1.0.2 + case: 1.6.3 + 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@2.50.0: + resolution: {integrity: sha512-55vmKTf2DZRqioumVfXn+S0H9oAbpRK3HFHY8EjZ5ykR5tq2+XiMWEZkYduX2HJhVAeHJJIS6h+Okk3smZjeqw==} + engines: {node: '>= 14.15.0'} + hasBin: true + 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 + dependencies: + buffer: 4.9.2 + events: 1.1.1 + ieee754: 1.1.13 + jmespath: 0.16.0 + querystring: 0.2.0 + sax: 1.2.1 + url: 0.10.3 + util: 0.12.5 + uuid: 8.0.0 + xml2js: 0.6.2 + dev: true + + /azure-devops-node-api@12.5.0: + resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} + dependencies: + tunnel: 0.0.6 + typed-rest-client: 1.8.11 + dev: false + + /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 + dependencies: + '@babel/core': 7.20.12 + dev: true + + /babel-jest@29.7.0(@babel/core@7.20.12): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.20.12 + '@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.20.12) + 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): + resolution: {integrity: sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==} + engines: {node: '>= 8.9'} + peerDependencies: + '@babel/core': ^7.0.0 + webpack: '>=2 || ^4 || ^5' + 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: 4.47.0 + dev: true + + /babel-plugin-add-react-displayname@0.0.5: + resolution: {integrity: sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==} + dev: true + + /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 + 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==} + dependencies: + '@babel/helper-module-imports': 7.22.15 + '@emotion/hash': 0.8.0 + '@emotion/memoize': 0.7.4 + '@emotion/serialize': 0.11.16 + babel-plugin-macros: 2.8.0 + babel-plugin-syntax-jsx: 6.18.0 + convert-source-map: 1.9.0 + escape-string-regexp: 1.0.5 + find-root: 1.1.0 + source-map: 0.5.7 + dev: true + + /babel-plugin-extract-import-names@1.6.22: + resolution: {integrity: sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==} + dependencies: + '@babel/helper-plugin-utils': 7.10.4 + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.24.0 + '@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 + + /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.24.0 + '@babel/types': 7.24.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.5 + + /babel-plugin-macros@2.8.0: + resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} + dependencies: + '@babel/runtime': 7.24.0 + cosmiconfig: 6.0.0 + resolve: 1.22.8 + dev: true + + /babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + dependencies: + '@babel/runtime': 7.24.0 + cosmiconfig: 7.1.0 + resolve: 1.22.8 + dev: true + + /babel-plugin-named-asset-import@0.3.8(@babel/core@7.20.12): + resolution: {integrity: sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==} + peerDependencies: + '@babel/core': ^7.1.0 + dependencies: + '@babel/core': 7.20.12 + dev: true + + /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 + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.6.1(@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 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.1.5(@babel/core@7.20.12) + core-js-compat: 3.36.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 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.20.12) + core-js-compat: 3.36.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 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-react-docgen@4.2.1: + resolution: {integrity: sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==} + dependencies: + ast-types: 0.14.2 + lodash: 4.17.21 + 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-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 + dependencies: + '@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-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-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 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.20.12) + + /bail@1.0.5: + resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /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'} + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + /batch-processor@1.0.0: + resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==} + dev: true + + /batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + dev: false + + /better-opn@2.1.1: + resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==} + engines: {node: '>8.0.0'} + dependencies: + open: 7.4.2 + dev: true + + /better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + 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.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + /binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + requiresBuild: true + optional: true + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + /binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + 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 + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + /bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + dev: true + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + /body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + 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 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.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} + 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 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + + /body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0(supports-color@8.1.1) + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /bole@4.0.1: + resolution: {integrity: sha512-42r0aSOJFJti2l6LasBHq2BuWJzohGs349olQnH/ETlJo87XnoWw7UT8pGE6UstjxzOKkwz7tjoFcmSr6L16vg==} + dependencies: + fast-safe-stringify: 2.1.1 + individual: 3.0.0 + dev: true + + /bonjour-service@1.2.1: + resolution: {integrity: sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==} + 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==} + + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: true + + /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 + + /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==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + /browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + dev: true + + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + + /browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /browserify-rsa@4.1.0: + resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + + /browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.5.5 + hash-base: 3.0.4 + inherits: 2.0.4 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + /browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + 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 + 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) + + /browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001699 + electron-to-chromium: 1.5.99 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + + /buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + dev: false + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + /buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + dev: false + + /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'} + dev: true + + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + /buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + requiresBuild: true + 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 + + /builtin-modules@3.1.0: + resolution: {integrity: sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==} + engines: {node: '>=6'} + dev: false + + /builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + + /builtins@1.0.3: + resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} + dev: false + + /bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + dependencies: + run-applescript: 7.0.0 + dev: false + + /buttono@1.0.4: + resolution: {integrity: sha512-aLOeyK3zrhZnqvH6LzwIbjur8mkKhW8Xl3/jolX+RCJnGG354+L48q1SJWdky89uhQ/mBlTxY/d0x8+ciE0ZWw==} + dev: false + + /bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + /c8@7.14.0: + resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} + engines: {node: '>=10.12.0'} + hasBin: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.1.7 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 9.2.0 + yargs: 16.2.0 + yargs-parser: 20.2.9 + dev: true + + /cacache@12.0.4: + resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==} + dependencies: + bluebird: 3.7.2 + chownr: 1.1.4 + figgy-pudding: 3.5.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + infer-owner: 1.0.4 + lru-cache: 5.1.1 + mississippi: 3.0.0 + mkdirp: 0.5.6 + move-concurrently: 1.0.1 + promise-inflight: 1.0.1 + rimraf: 2.7.1 + ssri: 6.0.2 + unique-filename: 1.1.1 + y18n: 4.0.3 + + /cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + dependencies: + '@npmcli/fs': 1.1.1 + '@npmcli/move-file': 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + 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'} + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + 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-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-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + /call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + /call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + dependencies: + pascal-case: 3.1.2 + tslib: 2.8.1 + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + /camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + + /caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + dependencies: + browserslist: 4.23.0 + caniuse-lite: 1.0.30001599 + 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.30001699: + resolution: {integrity: sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==} + + /capture-exit@2.0.0: + resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} + engines: {node: 6.* || 8.* || >= 10.*} + 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@1.6.3: + resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /ccount@1.1.0: + resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} + dev: true + + /chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + dependencies: + traverse: 0.3.9 + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + 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'} + 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: + 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@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + dev: true + + /character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + dev: true + + /chardet@2.1.0: + resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + dev: false + + /cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + dev: false + + /cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} + engines: {node: '>= 6'} + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.1.0 + htmlparser2: 8.0.2 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + dev: false + + /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 + dependencies: + anymatch: 2.0.0 + async-each: 1.0.6 + braces: 2.3.2 + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1 + upath: 1.2.0 + optionalDependencies: + 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 + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /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: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + /chrome-trace-event@1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + 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'} + + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + + /class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + 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'} + dependencies: + source-map: 0.6.1 + + /clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} + 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 + + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + dev: false + + /cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + 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@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + 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==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + 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'} + 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==} + 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 + + /clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + dev: false + + /cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + dev: false + + /cmd-extension@1.0.2: + resolution: {integrity: sha512-iWDjmP8kvsMdBmLTHxFaqXikO8EdFRDfim7k6vUHglY/2xJ5jLrPsnQGijdfp4U+sr/BeecG0wKm02dSIAeQ1g==} + engines: {node: '>=10'} + dev: false + + /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'} + dev: false + + /code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + dev: true + + /collapse-white-space@1.0.6: + resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==} + dev: true + + /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 + + /collect-v8-coverage@1.0.2(@types/node@20.17.19): + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + peerDependencies: + '@types/node': '>=12' + dependencies: + '@types/node': 20.17.19 + + /collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.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==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: true + + /colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + dev: false + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: false + + /colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + dev: false + + /colors@1.0.3: + resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} + engines: {node: '>=0.1.90'} + dev: false + + /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'} + dependencies: + delayed-stream: 1.0.0 + + /comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} + dev: true + + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + requiresBuild: true + optional: true + + /commander@12.0.0: + resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} + engines: {node: '>=18'} + dev: false + + /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'} + + /comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + dev: false + + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + + /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'} + 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'} + dependencies: + mime-db: 1.52.0 + + /compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + + /compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + dev: true + + /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} + 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'} + dependencies: + ajv: 8.13.0 + ajv-formats: 2.1.1 + atomically: 1.7.0 + debounce-fn: 4.0.0 + dot-prop: 6.0.1 + env-paths: 2.2.1 + json-schema-typed: 7.0.3 + onetime: 5.1.2 + pkg-up: 3.1.0 + semver: 7.5.4 + dev: true + + /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 + + /connect-history-api-fallback@2.0.0: + resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} + engines: {node: '>=0.8'} + dev: false + + /console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: true + + /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'} + dev: true + + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + + /content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /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.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + dev: false + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: false + + /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'} + dev: false + + /copy-concurrently@1.0.5: + resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} + dependencies: + aproba: 1.2.0 + fs-write-stream-atomic: 1.0.10 + iferr: 0.1.5 + mkdirp: 0.5.6 + 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-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + dependencies: + toggle-selection: 1.0.6 + dev: true + + /core-js-compat@3.36.0: + resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} + dependencies: + browserslist: 4.23.0 + dev: true + + /core-js-pure@3.36.0: + resolution: {integrity: sha512-cN28qmhRNgbMZZMc/RFu5w8pK9VJzpb2rJVR/lHuZJKwmXnoWOpXmMkxqBB514igkp1Hu8WGROsiOAzUcKdHOQ==} + requiresBuild: true + dev: true + + /core-js@3.36.0: + resolution: {integrity: sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==} + requiresBuild: true + dev: true + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + 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'} + 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 + dev: true + + /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 + + /cp-file@7.0.0: + resolution: {integrity: sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==} + engines: {node: '>=8'} + 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'} + dependencies: + arrify: 2.0.1 + cp-file: 7.0.0 + globby: 9.2.0 + has-glob: 1.0.0 + junk: 3.1.0 + nested-error-stacks: 2.1.1 + 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 + + /crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + 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==} + dependencies: + bn.js: 4.12.0 + elliptic: 6.5.5 + + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + /create-jest@29.7.0(@types/node@20.17.19): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + 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@20.17.19) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /cross-spawn@6.0.5: + resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + engines: {node: '>=4.8'} + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /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-browserify@3.12.0: + resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.3 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + + /crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + + /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 + dependencies: + postcss: 8.4.36 + dev: false + + /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 + dependencies: + camelcase: 5.3.1 + cssesc: 3.0.0 + icss-utils: 4.1.1 + loader-utils: 1.4.2 + normalize-path: 3.0.0 + postcss: 7.0.39 + postcss-modules-extract-imports: 2.0.0 + postcss-modules-local-by-default: 3.0.3 + postcss-modules-scope: 2.2.0 + postcss-modules-values: 3.0.0 + postcss-value-parser: 4.2.0 + schema-utils: 2.7.1 + semver: 6.3.1 + webpack: 4.47.0 + dev: true + + /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 + dependencies: + icss-utils: 5.1.0(postcss@8.4.36) + 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-value-parser: 4.2.0 + schema-utils: 3.3.0 + semver: 7.5.4 + webpack: 4.47.0 + dev: true + + /css-loader@6.6.0(webpack@5.98.0): + resolution: {integrity: sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 || ^4 || ^5 + 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) + postcss-value-parser: 4.2.0 + semver: 7.5.4 + webpack: 5.98.0 + + /css-minimizer-webpack-plugin@3.4.1(webpack@5.98.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 + dependencies: + cssnano: 5.1.15(postcss@8.4.36) + jest-worker: 27.5.1 + postcss: 8.4.36 + schema-utils: 4.2.0 + serialize-javascript: 6.0.2 + source-map: 0.6.1 + webpack: 5.98.0 + dev: false + + /css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + 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==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + dev: false + + /css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + 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) + lilconfig: 2.1.0 + postcss: 8.4.36 + yaml: 1.10.2 + dev: false + + /csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.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'} + dependencies: + cssom: 0.3.8 + + /csstype@2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + dev: true + + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + /cyclist@1.0.2: + resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} + + /data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + /data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + 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'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + /data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + 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'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + /data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + 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 + + /debounce-fn@4.0.0: + resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} + engines: {node: '>=10'} + dependencies: + mimic-fn: 3.1.0 + dev: true + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + dependencies: + ms: 2.0.0 + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + 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 + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /debug@4.4.0(supports-color@8.1.1): + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + 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@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: true + + /decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + dev: true + + /decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + /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'} + dependencies: + mimic-response: 3.1.0 + + /dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + dev: true + + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + requiresBuild: true + + /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==} + dev: true + + /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.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + dev: false + + /default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.0 + dev: false + + /default-gateway@6.0.3: + resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} + engines: {node: '>= 10'} + 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'} + + /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.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: false + + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: false + + /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 + + /define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 0.1.7 + + /define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.3 + + /define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + + /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==} + dev: true + + /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 + + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: false + + /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'} + dependencies: + '@pnpm/crypto.base32-hash': 1.0.1 + '@pnpm/types': 8.9.0 + encode-registry: 3.0.1 + semver: 7.5.4 + dev: false + + /des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + /destroy@1.0.4: + resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} + dev: false + + /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==} + dependencies: + repeat-string: 1.6.1 + dev: true + + /detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + dev: false + + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + optional: true + + /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==} + dev: false + + /detect-port-alt@1.1.6: + resolution: {integrity: sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==} + engines: {node: '>= 4.2.1'} + hasBin: true + 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 + dependencies: + address: 1.2.2 + debug: 4.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + dev: true + + /dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + 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} + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + dev: true + + /diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + dev: false + + /diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + + /dir-glob@2.2.2: + resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} + engines: {node: '>=4'} + dependencies: + path-type: 3.0.0 + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /dns-packet@5.6.1: + resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} + engines: {node: '>=6'} + dependencies: + '@leichtgewicht/ip-codec': 2.0.4 + dev: false + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + + /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==} + dependencies: + utila: 0.4.0 + + /dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dependencies: + '@babel/runtime': 7.24.0 + csstype: 3.1.3 + dev: false + + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + 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==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /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'} + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + /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 + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + 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==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + + /dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + /dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + + /dot-prop@6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + dependencies: + is-obj: 2.0.0 + dev: true + + /dotenv-expand@5.1.0: + resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + dev: true + + /dotenv@10.0.0: + resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} + engines: {node: '>=10'} + dev: true + + /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'} + dev: true + + /downshift@6.1.12(react@17.0.2): + resolution: {integrity: sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==} + peerDependencies: + react: '>=16.12.0' + dependencies: + '@babel/runtime': 7.24.0 + compute-scroll-into-view: 1.0.20 + prop-types: 15.8.1 + react: 17.0.2 + react-is: 17.0.2 + tslib: 2.8.1 + dev: true + + /dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + /duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + dependencies: + readable-stream: 2.3.8 + dev: true + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + /duplexify@3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.8 + stream-shift: 1.0.3 + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + /electron-to-chromium@1.4.709: + resolution: {integrity: sha512-ixj1cyHrKqmdXF5CeHDSLbO0KRuOE1BHdCYKbcRA04dPLaKu8Vi7JDK5KLnGrfD6WxKcSEGm9gtHR4MqBq8gmg==} + + /electron-to-chromium@1.5.99: + resolution: {integrity: sha512-77c/+fCyL2U+aOyqfIFi89wYLBeSTCs55xCZL0oFH0KjqsvSvyh6AdQ+UIl1vgpnQQE6g+/KK8hOIupH6VwPtg==} + + /element-resize-detector@1.2.4: + resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==} + dependencies: + batch-processor: 1.0.0 + dev: true + + /elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + /emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + dev: true + + /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(@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' + dependencies: + '@babel/runtime': 7.24.0 + '@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'} + dependencies: + mem: 8.1.1 + dev: false + + /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==} + requiresBuild: true + 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==} + dependencies: + once: 1.4.0 + + /endent@2.1.0: + resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} + 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'} + 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'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true + + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: true + + /envinfo@7.11.1: + resolution: {integrity: sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + dev: true + + /errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + dependencies: + prr: 1.0.1 + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + + /error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + dependencies: + stackframe: 1.3.4 + dev: true + + /es-abstract@1.23.2: + resolution: {integrity: sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==} + 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.8 + 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.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.3.0 + get-symbol-description: 1.0.2 + globalthis: 1.0.3 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + 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.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.1.1 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + 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.9 + 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-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + 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-regex: 1.2.1 + 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 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + /es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + /es-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==} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + is-arguments: 1.1.1 + is-map: 2.0.3 + is-set: 2.0.3 + is-string: 1.1.1 + isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 + dev: true + + /es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + 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 + safe-array-concat: 1.1.3 + + /es-module-lexer@1.4.1: + resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + + /es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + /es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + dependencies: + 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==} + dependencies: + hasown: 2.0.2 + + /es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + /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.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 + + /es6-shim@0.35.8: + resolution: {integrity: sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==} + dev: true + + /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 + 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 + optional: true + + /esbuild-darwin-64@0.14.54: + resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64@0.14.54: + resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + 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 + optional: true + + /esbuild-freebsd-arm64@0.14.54: + resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + 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 + optional: true + + /esbuild-linux-64@0.14.54: + resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + 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 + 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 + 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 + optional: true + + /esbuild-linux-ppc64le@0.14.54: + resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + 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 + 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 + 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 + optional: true + + /esbuild-openbsd-64@0.14.54: + resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-runner@2.2.2(esbuild@0.14.54): + resolution: {integrity: sha512-fRFVXcmYVmSmtYm2mL8RlUASt2TDkGh3uRcvHFOKNr/T58VrfVeKD9uT9nlgxk96u0LS0ehS/GY7Da/bXWKkhw==} + hasBin: true + peerDependencies: + esbuild: '*' + 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 + 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 + optional: true + + /esbuild-windows-64@0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + 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 + optional: true + + /esbuild@0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/linux-loong64': 0.14.54 + esbuild-android-64: 0.14.54 + esbuild-android-arm64: 0.14.54 + esbuild-darwin-64: 0.14.54 + esbuild-darwin-arm64: 0.14.54 + esbuild-freebsd-64: 0.14.54 + esbuild-freebsd-arm64: 0.14.54 + esbuild-linux-32: 0.14.54 + esbuild-linux-64: 0.14.54 + esbuild-linux-arm: 0.14.54 + esbuild-linux-arm64: 0.14.54 + esbuild-linux-mips64le: 0.14.54 + esbuild-linux-ppc64le: 0.14.54 + esbuild-linux-riscv64: 0.14.54 + esbuild-linux-s390x: 0.14.54 + esbuild-netbsd-64: 0.14.54 + esbuild-openbsd-64: 0.14.54 + esbuild-sunos-64: 0.14.54 + 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 + 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'} + + /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 + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.8 + dev: false + + /eslint-module-utils@2.12.1(eslint@9.37.0): + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + eslint: '*' + peerDependenciesMeta: + eslint: + optional: true + dependencies: + debug: 3.2.7 + eslint: 9.37.0(supports-color@8.1.1) + dev: false + + /eslint-plugin-header@3.1.1(eslint@9.37.0): + resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} + peerDependencies: + eslint: '>=7.7.0' + dependencies: + eslint: 9.37.0(supports-color@8.1.1) + dev: false + + /eslint-plugin-headers@1.2.1(eslint@9.37.0): + resolution: {integrity: sha512-1L41t3DPrXFP6YLK+sAj0xDMGVHpQwI+uGefDwc1bKP91q65AIZoXzQgI7MjZJxB6sK8/vYhXMD8x0V8xLNxJA==} + engines: {node: ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 9.37.0(supports-color@8.1.1) + dev: false + + /eslint-plugin-import@2.32.0(eslint@9.37.0): + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + 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(supports-color@8.1.1) + 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.2 + 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@50.6.11(eslint@9.37.0): + resolution: {integrity: sha512-k4+MnBCGR8cuIB5MZ++FGd4gbXxjob2rX1Nq0q3nWFF4xSGZENTgTLZSjb+u9B8SAnP6lpGV2FJrBjllV3pVSg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + dependencies: + '@es-joy/jsdoccomment': 0.49.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.0(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint: 9.37.0(supports-color@8.1.1) + espree: 10.3.0 + esquery: 1.6.0 + parse-imports-exports: 0.2.4 + semver: 7.7.2 + 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 + 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 + 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 + 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 + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-promise@7.2.1(eslint@8.57.0): + 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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + eslint: 8.57.0 + dev: true + + /eslint-plugin-promise@7.2.1(eslint@9.37.0): + 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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.37.0) + eslint: 9.37.0(supports-color@8.1.1) + dev: false + + /eslint-plugin-react-hooks@5.2.0(eslint@9.37.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 + dependencies: + eslint: 9.37.0(supports-color@8.1.1) + dev: false + + /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 + dependencies: + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 7.11.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.3 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + dev: true + + /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 + dependencies: + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 7.30.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.3 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + dev: true + + /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 + dependencies: + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 7.7.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.3 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + dev: true + + /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 + dependencies: + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 8.57.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.3 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + dev: true + + /eslint-plugin-react@7.37.5(eslint@8.57.0): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.8 + 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.2.1 + eslint: 8.57.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + 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.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + dev: true + + /eslint-plugin-react@7.37.5(eslint@9.37.0): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.8 + 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.2.1 + eslint: 9.37.0(supports-color@8.1.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + 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.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + dev: false + + /eslint-plugin-tsdoc@0.3.0: + resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==} + 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==} + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + + /eslint-plugin-tsdoc@0.5.0(eslint@9.37.0)(typescript@5.8.2): + resolution: {integrity: sha512-ush8ehCwub2rgE16OIgQPFyj/o0k3T8kL++9IrAI4knsmupNo8gvfO2ERgDHWWgTC5MglbwLVRswU93HyXqNpw==} + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.8.2) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + dev: false + + /eslint-scope@4.0.3: + resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==} + engines: {node: '>=4.0.0'} + 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'} + 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} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + /eslint-utils@2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + 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' + dependencies: + eslint: 8.57.0 + 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@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /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.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.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@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 + dependencies: + '@babel/code-frame': 7.23.5 + '@eslint/eslintrc': 0.1.3 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(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.6.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 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 3.14.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash: 4.17.21 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.5.4 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + table: 5.4.6 + text-table: 0.2.0 + 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} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + dependencies: + '@babel/code-frame': 7.12.11 + '@eslint/eslintrc': 0.4.3 + '@humanwhocodes/config-array': 0.5.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + doctrine: 3.0.0 + enquirer: 2.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 5.1.1 + eslint-utils: 2.1.0 + eslint-visitor-keys: 2.1.0 + espree: 7.3.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 5.1.2 + globals: 13.24.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 3.14.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.5.4 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.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} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + dependencies: + '@babel/code-frame': 7.23.5 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(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.6.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 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 3.14.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash: 4.17.21 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.5.4 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + table: 5.4.6 + text-table: 0.2.0 + 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 + 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 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(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-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + globby: 11.1.0 + grapheme-splitter: 1.0.4 + ignore: 5.3.1 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-sdsl: 4.4.2 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + 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: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + 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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.4.0(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 + 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.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint@8.6.0: + resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.9.5 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(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-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.24.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.5.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 + + /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 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.1 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.1(supports-color@8.1.1) + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.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.1 + 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.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint@9.37.0(supports-color@8.1.1): + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0(supports-color@8.1.1) + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1(supports-color@8.1.1) + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(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.6.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.1 + 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.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + transitivePeerDependencies: + - supports-color + + /espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + + /espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.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} + 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} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + + /estraverse@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'} + dependencies: + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 + c8: 7.14.0 + transitivePeerDependencies: + - supports-color + dev: true + + /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'} + dev: true + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + /eventsource-parser@3.0.1: + resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} + engines: {node: '>=18.0.0'} + dev: false + + /eventsource@3.0.6: + resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} + engines: {node: '>=18.0.0'} + dependencies: + eventsource-parser: 3.0.1 + dev: false + + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + 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 + + /execa@1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + dependencies: + cross-spawn: 6.0.5 + 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'} + 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==} + 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'} + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + 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'} + requiresBuild: true + dev: false + optional: true + + /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 + + /express-rate-limit@7.5.0(express@5.1.0): + resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} + engines: {node: '>= 16'} + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + dependencies: + express: 5.1.0 + dev: false + + /express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + engines: {node: '>= 0.10.0'} + 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.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.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.10 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.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 + + /express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + 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.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.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.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 + dev: false + + /express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + + /extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + 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 + 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-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'} + dependencies: + '@mrmlnc/readdir-enhanced': 2.2.1 + '@nodelib/fs.stat': 1.1.3 + glob-parent: 3.1.0 + 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'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + /fast-json-parse@1.0.3: + resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} + dev: true + + /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'} + dependencies: + ajv: 6.12.6 + deepmerge: 4.3.1 + rfdc: 1.3.1 + string-similarity: 4.0.4 + dev: false + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + /fast-redact@3.4.0: + resolution: {integrity: sha512-2gwPvyna0zwBdxKnng1suu/dTL5s8XEy2ZqH8mwDUwJdDkV8w5kp+JV26mupdK68HmPMbm6yjW9m7/Ys/BHEHg==} + engines: {node: '>=6'} + dev: false + + /fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + /fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: true + + /fast-xml-parser@4.5.0: + resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + + /fastify-error@0.3.1: + resolution: {integrity: sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==} + dev: false + + /fastify-warning@0.2.0: + resolution: {integrity: sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==} + deprecated: This module renamed to process-warning + dev: false + + /fastify@3.16.2: + resolution: {integrity: sha512-tdu0fz6wk9AbtD91AbzZGjKgEQLcIy7rT2vEzTUL/zifAMS/L7ViKY9p9k3g3yCRnIQzYzxH2RAbvYZaTbKasw==} + engines: {node: '>=10.16.0'} + dependencies: + '@fastify/ajv-compiler': 1.1.0 + '@fastify/proxy-addr': 3.0.0 + abstract-logging: 2.0.1 + avvio: 7.2.5 + fast-json-stringify: 2.7.13 + fastify-error: 0.3.1 + fastify-warning: 0.2.0 + find-my-way: 4.5.1 + flatstr: 1.0.12 + light-my-request: 4.12.0 + pino: 6.14.0 + readable-stream: 3.6.2 + rfdc: 1.3.1 + secure-json-parse: 2.7.0 + semver: 7.5.4 + tiny-lru: 7.0.6 + transitivePeerDependencies: + - supports-color + dev: false + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + + /fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + dependencies: + format: 0.2.2 + dev: true + + /faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + dependencies: + websocket-driver: 0.7.4 + dev: false + + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + + /fdir@6.4.6(picomatch@4.0.2): + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.2 + dev: false + + /figgy-pudding@3.5.2: + resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} + deprecated: This module is no longer supported. + + /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 + + /file-entry-cache@5.0.1: + resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} + engines: {node: '>=4'} + 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} + 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'} + dependencies: + flat-cache: 4.0.1 + + /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 + dependencies: + loader-utils: 2.0.4 + schema-utils: 2.7.1 + webpack: 4.47.0 + dev: true + + /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 + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 4.47.0 + dev: true + + /file-system-cache@1.1.0: + resolution: {integrity: sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==} + 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 + optional: true + + /fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.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'} + dependencies: + to-regex-range: 5.0.1 + + /finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + 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.1 + unpipe: 1.0.0 + + /finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + dependencies: + debug: 4.4.0(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.1 + transitivePeerDependencies: + - supports-color + dev: false + + /find-cache-dir@2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + 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'} + 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'} + 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-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + dependencies: + locate-path: 3.0.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: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + /flat-cache@2.0.1: + resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} + engines: {node: '>=4'} + 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} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: true + + /flatstr@1.0.12: + resolution: {integrity: sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==} + dev: false + + /flatted@2.0.2: + resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} + dev: true + + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + /flow-parser@0.231.0: + resolution: {integrity: sha512-WVzuqwq7ZnvBceCG0DGeTQebZE+iIU0mlk5PmJgYj9DDrt+0isGC2m1ezW9vxL4V+HERJJo9ExppOnwKH2op6Q==} + engines: {node: '>=0.4.0'} + dev: true + + /flush-write-stream@1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + 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 + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + + /for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + + /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'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 3.0.7 + dev: true + + /foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + dev: false + + /fork-ts-checker-webpack-plugin@4.1.6: + resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} + engines: {node: '>=6.11.5', yarn: '>=1.0.0'} + dependencies: + '@babel/code-frame': 7.23.5 + chalk: 2.4.2 + micromatch: 3.1.10 + minimatch: 3.1.2 + semver: 5.7.2 + tapable: 1.1.3 + worker-rpc: 0.1.1 + dev: true + + /fork-ts-checker-webpack-plugin@6.5.3(eslint@9.37.0)(typescript@5.8.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 + dependencies: + '@babel/code-frame': 7.23.5 + '@types/json-schema': 7.0.15 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 6.0.0 + deepmerge: 4.3.1 + eslint: 9.37.0(supports-color@8.1.1) + fs-extra: 9.1.0 + glob: 7.2.3 + memfs: 3.4.3 + minimatch: 3.1.2 + schema-utils: 2.7.0 + semver: 7.5.4 + tapable: 1.1.3 + typescript: 5.8.2 + webpack: 4.47.0 + dev: true + + /form-data@3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + /format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + dev: true + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + /fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + /fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + dependencies: + map-cache: 0.2.2 + + /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'} + dev: false + + /from2@2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + 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==} + requiresBuild: true + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + /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 + + /fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + 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'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + + /fs-monkey@1.0.3: + resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} + + /fs-write-stream-atomic@1.0.10: + resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} + 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==} + + /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 + dependencies: + bindings: 1.5.0 + nan: 2.19.0 + 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 + dev: 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 + 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 + optional: true + + /fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + 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.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + functions-have-names: 1.2.3 + + /function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + 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 + + /functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + dev: true + + /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'} + dev: true + + /gauge@2.7.4: + resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} + dependencies: + aproba: 1.2.0 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + 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'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + 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 + + /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.*} + dev: true + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.1.0 + hasown: 2.0.2 + + /get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + /get-package-type@0.1.0: + 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'} + dev: true + + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + /get-stream@4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + dependencies: + pump: 3.0.0 + dev: true + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + + /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==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + /get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + /get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + /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==} + requiresBuild: true + dev: false + optional: true + + /github-slugger@1.5.0: + resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} + dev: true + + /giturl@2.0.0: + resolution: {integrity: sha512-FB0MmghWLcqsyrBZyqsLCNeS2kIzYymT34t/6BxM5R0/9Pxvj0K1eK25SBbwRHMjKMLgQ7nYqBSduF6XyfkgFg==} + engines: {node: '>= 14.17.0'} + dev: false + + /glob-escape@0.0.2: + resolution: {integrity: sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==} + engines: {node: '>= 0.10'} + dev: false + + /glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + 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'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob-promise@3.4.0(glob@7.2.3): + resolution: {integrity: sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==} + engines: {node: '>=4'} + peerDependencies: + glob: '*' + 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-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + /glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + dev: false + + /glob@7.0.6: + resolution: {integrity: sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + + /global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + + /global@4.4.0: + resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} + dependencies: + min-document: 2.19.0 + 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'} + dependencies: + type-fest: 0.8.1 + dev: true + + /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.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + + /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.2.0 + + /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.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /globby@9.2.0: + resolution: {integrity: sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==} + engines: {node: '>=6'} + dependencies: + '@types/glob': 7.1.1 + array-union: 1.0.2 + dir-glob: 2.2.2 + fast-glob: 2.2.7 + glob: 7.2.3 + ignore: 4.0.6 + pify: 4.0.1 + slash: 2.0.0 + dev: true + + /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'} + 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: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graceful-fs@4.2.4: + resolution: {integrity: sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==} + dev: false + + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + /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 + optional: true + + /gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + dependencies: + duplexer: 0.1.2 + + /handle-thing@2.0.1: + resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} + dev: false + + /handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + 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 + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + /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'} + dependencies: + is-glob: 3.1.0 + dev: true + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + 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: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.1.0 + + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: true + + /has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + 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'} + 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@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.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'} + + /hash-base@3.0.4: + resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} + engines: {node: '>=4'} + 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'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /hast-to-hyperscript@9.0.1: + resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==} + dependencies: + '@types/unist': 2.0.10 + 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==} + dependencies: + '@types/parse5': 5.0.3 + hastscript: 6.0.0 + property-information: 5.6.0 + 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-raw@6.0.1: + resolution: {integrity: sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==} + dependencies: + '@types/hast': 2.3.10 + hast-util-from-parse5: 6.0.1 + hast-util-to-parse5: 6.0.0 + html-void-elements: 1.0.5 + parse5: 6.0.1 + unist-util-position: 3.1.0 + vfile: 4.2.1 + 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==} + 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==} + 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.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + dev: true + + /history@5.0.0: + resolution: {integrity: sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==} + dependencies: + '@babel/runtime': 7.24.0 + dev: true + + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + + /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'} + dependencies: + lru-cache: 6.0.0 + dev: false + + /hpack.js@2.1.6: + resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} + 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'} + dependencies: + whatwg-encoding: 2.0.0 + + /html-entities@2.5.2: + resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + + /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 + dependencies: + camel-case: 4.1.2 + clean-css: 4.2.4 + commander: 4.1.1 + he: 1.2.0 + param-case: 3.0.4 + relateurl: 0.2.7 + terser: 4.8.1 + + /html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + 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.29.2 + + /html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + dev: true + + /html-void-elements@1.0.5: + resolution: {integrity: sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==} + dev: true + + /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 + 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 + pretty-error: 2.1.2 + tapable: 1.1.3 + util.promisify: 1.0.0 + webpack: 4.47.0 + + /html-webpack-plugin@5.5.4(webpack@5.98.0): + resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} + engines: {node: '>=10.13.0'} + peerDependencies: + webpack: ^5.20.0 || ^4 || ^5 + dependencies: + '@types/html-minifier-terser': 6.1.0 + html-minifier-terser: 6.1.0 + lodash: 4.17.21 + pretty-error: 4.0.0 + tapable: 2.2.1 + webpack: 5.98.0 + + /htmlparser2@6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + 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==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + dev: false + + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + /http-deceiver@1.2.7: + resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} + dev: false + + /http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + dev: false + + /http-errors@1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + dev: false + + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + /http-parser-js@0.5.8: + resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} + dev: false + + /http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.4.0(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.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.4.0(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'} + dependencies: + '@types/express': 4.17.21 + '@types/http-proxy': 1.17.14 + http-proxy: 1.18.1 + is-glob: 4.0.3 + is-plain-obj: 3.0.0 + micromatch: 4.0.5 + transitivePeerDependencies: + - debug + dev: false + + /http-proxy-middleware@2.0.9: + resolution: {integrity: sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==} + engines: {node: '>=12.0.0'} + dependencies: + '@types/express': 4.17.21 + '@types/http-proxy': 1.17.14 + http-proxy: 1.18.1 + is-glob: 4.0.3 + is-plain-obj: 3.0.0 + micromatch: 4.0.5 + transitivePeerDependencies: + - debug + dev: false + + /http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.6 + 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': '*' + 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'} + 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-proxy-agent@4.0.0: + resolution: {integrity: sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==} + engines: {node: '>= 6.0.0'} + dependencies: + agent-base: 5.1.1 + debug: 4.4.0(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'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + /https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.4.0(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'} + + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + dev: true + + /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'} + dependencies: + safer-buffer: 2.1.2 + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + + /icss-utils@4.1.1: + resolution: {integrity: sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==} + engines: {node: '>= 6'} + 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 + dependencies: + postcss: 8.4.36 + + /ieee754@1.1.13: + resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /iferr@0.1.5: + resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} + + /ignore-walk@3.0.4: + resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} + dependencies: + minimatch: 3.1.2 + dev: false + + /ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + dev: true + + /ignore@5.1.9: + resolution: {integrity: sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==} + engines: {node: '>= 4'} + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + /ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + /immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + dev: false + + /immer@9.0.21: + resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + + /immutable@4.3.5: + resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} + dev: false + + /immutable@5.1.1: + resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==} + dev: false + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /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.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + 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'} + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /individual@3.0.0: + resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==} + dev: true + + /infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + 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 + + /inquirer@8.2.7: + resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} + engines: {node: '>=12.0.0'} + dependencies: + '@inquirer/external-editor': 1.0.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + figures: 3.0.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.1 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 6.2.0 + transitivePeerDependencies: + - '@types/node' + dev: false + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + /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.1.0 + + /interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: true + + /interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + dev: true + + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + 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@1.1.9: + resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==} + dev: true + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + /ipaddr.js@2.1.0: + resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==} + engines: {node: '>= 10'} + dev: false + + /is-absolute-url@3.0.3: + resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} + engines: {node: '>=8'} + dev: true + + /is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + dependencies: + hasown: 2.0.2 + + /is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + dev: true + + /is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + 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'} + dependencies: + call-bind: 1.0.8 + has-tostringtag: 1.0.2 + dev: true + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + + /is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + dependencies: + 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-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + dependencies: + has-bigints: 1.0.2 + + /is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + requiresBuild: true + dependencies: + binary-extensions: 1.13.1 + optional: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + + /is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + /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'} + dev: true + + /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 + dependencies: + ci-info: 2.0.0 + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + + /is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + + /is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + 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==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + + /is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + dependencies: + 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'} + dependencies: + has-tostringtag: 1.0.2 + + /is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + /is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + dev: true + + /is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + 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'} + 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@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-dom@1.1.0: + resolution: {integrity: sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==} + dependencies: + is-object: 1.0.2 + is-window: 1.0.2 + dev: true + + /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'} + dependencies: + is-plain-object: 2.0.4 + + /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'} + dependencies: + call-bound: 1.0.4 + + /is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.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'} + dev: true + + /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==} + dev: true + + /is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + dev: true + + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: false + + /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'} + dev: false + + /is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + dev: true + + /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.1.0: + resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} + engines: {node: '>=16'} + dev: false + + /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'} + 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'} + 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-object@1.0.2: + resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==} + dev: true + + /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'} + dev: false + + /is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: false + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + /is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + dependencies: + 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-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + + /is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + + /is-stream@1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + 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'} + dependencies: + better-path-resolve: 1.0.0 + dev: false + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.1.0 + + /is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + dependencies: + 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'} + dependencies: + which-typed-array: 1.1.15 + + /is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.19 + + /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.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.8 + + /is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + + /is-whitespace-character@1.0.4: + resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} + dev: true + + /is-window@1.0.2: + resolution: {integrity: sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg==} + dev: true + + /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==} + dev: true + + /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'} + dependencies: + is-docker: 2.2.1 + + /is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + dependencies: + is-inside-container: 1.0.0 + dev: false + + /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'} + dependencies: + isarray: 1.0.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'} + dev: true + + /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'} + dependencies: + '@babel/core': 7.20.12 + '@babel/parser': 7.24.0 + '@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'} + dependencies: + '@babel/core': 7.24.0 + '@babel/parser': 7.24.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /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 + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.4.0(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'} + 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-value@1.0.2: + resolution: {integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==} + dependencies: + es-get-iterator: 1.1.3 + iterate-iterator: 1.0.2 + dev: true + + /iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + 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@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + dev: false + + /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 + + /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@17.0.41) + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + 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.0.4 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + /jest-cli@29.7.0(@types/node@20.17.19): + 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 + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.17.19) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.17.19) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-config@29.5.0(@types/node@17.0.41): + 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 + dependencies: + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@17.0.41) + '@jest/types': 29.5.0 + '@types/node': 17.0.41 + 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 + 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.5 + 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 + + /jest-config@29.5.0(@types/node@20.17.19): + 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 + dependencies: + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.5.0 + '@types/node': 20.17.19 + 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 + 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.5 + 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: false + + /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 + dependencies: + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@17.0.41) + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + 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 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + 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-config@29.7.0(@types/node@20.17.19): + 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 + dependencies: + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.6.3 + '@types/node': 20.17.19 + 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 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + 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@27.5.1: + resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 + + /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 + + /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 + + /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 + + /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 + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.5.0 + '@types/jsdom': 20.0.1 + '@types/node': 17.0.41 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jsdom: 20.0.3 + 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} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.5.0 + '@types/node': 17.0.41 + 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} + 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-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'} + dependencies: + '@jest/types': 26.6.2 + '@types/graceful-fs': 4.1.9 + '@types/node': 17.0.41 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 26.0.0 + jest-serializer: 26.6.2 + jest-util: 26.6.2 + jest-worker: 26.6.2 + micromatch: 4.0.5 + 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} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 17.0.41 + 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 + 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'} + 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} + 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} + dependencies: + chalk: 4.1.2 + jest-diff: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 + + /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 + + /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.23.5 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + 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} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + 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 + dependencies: + jest-resolve: 29.5.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-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-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.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 + + /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.2 + 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} + 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 + slash: 3.0.0 + + /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@17.0.41) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + 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 + + /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@17.0.41) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2(@types/node@17.0.41) + 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 + + /jest-serializer@26.6.2: + resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} + engines: {node: '>= 10.14.2'} + dependencies: + '@types/node': 17.0.41 + graceful-fs: 4.2.11 + 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.20.12 + '@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 + '@babel/types': 7.24.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.5.0 + '@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) + 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.5.4 + transitivePeerDependencies: + - supports-color + + /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.20.12 + '@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 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.20.12) + 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.5.4 + transitivePeerDependencies: + - supports-color + + /jest-util@26.6.2: + resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==} + engines: {node: '>= 10.14.2'} + dependencies: + '@jest/types': 26.6.2 + '@types/node': 17.0.41 + chalk: 4.1.2 + graceful-fs: 4.2.11 + is-ci: 2.0.0 + micromatch: 4.0.5 + dev: true + + /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': 17.0.41 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + /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 + + /jest-watch-select-projects@2.0.0: + resolution: {integrity: sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==} + 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} + dependencies: + '@jest/test-result': 29.7.0(@types/node@17.0.41) + '@jest/types': 29.6.3 + '@types/node': 17.0.41 + 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'} + dependencies: + '@types/node': 17.0.41 + 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'} + dependencies: + '@types/node': 17.0.41 + 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} + dependencies: + '@types/node': 17.0.41 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + /jest@29.3.1(@types/node@20.17.19): + 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 + dependencies: + '@jest/core': 29.5.0 + '@jest/types': 29.5.0 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.17.19) + 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 + + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + 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 + dependencies: + '@babel/core': 7.20.12 + '@babel/parser': 7.24.0 + '@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-core: 7.0.0-bridge.0(@babel/core@7.20.12) + chalk: 4.1.2 + flow-parser: 0.231.0 + 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 + dev: true + + /jsdoc-type-pratt-parser@4.1.0: + resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} + engines: {node: '>=12.0.0'} + dev: false + + /jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.14.0 + 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 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.7 + parse5: 7.1.2 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.3 + w3c-xmlserializer: 4.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 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + /jsep@1.4.0: + resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} + engines: {node: '>= 10.16.0'} + + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + /json-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 + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.20 + is-glob: 4.0.3 + js-yaml: 4.1.0 + lodash: 4.17.21 + minimist: 1.2.8 + prettier: 3.6.2 + tinyglobby: 0.2.14 + dev: false + + /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==} + dev: true + + /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==} + dev: true + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + + /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==} + dev: false + + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /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 + + /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'} + dependencies: + jws: 3.2.2 + 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.1.1 + ms: 2.1.3 + semver: 7.5.4 + dev: false + + /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.1 + + /jszip@2.7.0: + resolution: {integrity: sha512-JIsRKRVC3gTRo2vM4Wy9WBC3TRcfnIZU8k65Phi3izkvPH975FowRYtKGT6PxevA0XnJ/yO8b0QwV0ydVyQwfw==} + dependencies: + pako: 1.0.11 + dev: true + + /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 + 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 + + /jwa@2.0.0: + resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + 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==} + dependencies: + jwa: 2.0.0 + safe-buffer: 5.2.1 + dev: false + + /keyborg@2.5.0: + resolution: {integrity: sha512-nb4Ji1suqWqj6VXb61Jrs4ab/UWgtGph4wDch2NIZDfLBUObmLcZE0aiDjZY49ghtu03fvwxDNvS9ZB0XMz6/g==} + dev: false + + /keytar@7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + requiresBuild: true + dependencies: + node-addon-api: 4.3.0 + prebuild-install: 7.1.2 + dev: false + optional: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + + /kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + + /kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.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'} + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + /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 + dependencies: + chalk: 4.1.2 + dotenv: 16.4.7 + kysely: 0.21.6 + micromatch: 4.0.5 + 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 + dependencies: + aws-sdk: 2.1580.0 + kysely: 0.21.6 + dev: true + + /kysely@0.21.6: + resolution: {integrity: sha512-DNecGKzzYtx2OumPJ8inrVFsSfq1lNHLFZDJvXMQxqbrTFElqq70VLR3DiK0P9fw4pB+xXTYvLiLurWiYqgk3w==} + engines: {node: '>=14.0.0'} + dev: true + + /latest-version@5.1.0: + resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} + engines: {node: '>=8'} + dependencies: + package-json: 7.0.0 + + /launch-editor@2.9.1: + resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==} + dependencies: + picocolors: 1.0.0 + shell-quote: 1.8.1 + dev: false + + /lazy-universal-dotenv@3.0.1: + resolution: {integrity: sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==} + engines: {node: '>=6.0.0', npm: '>=6.0.0', yarn: '>=1.0.0'} + dependencies: + '@babel/runtime': 7.24.0 + app-root-dir: 1.0.2 + core-js: 3.36.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'} + 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'} + + /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 + + /lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + dependencies: + immediate: 3.0.6 + dev: false + + /light-my-request@4.12.0: + resolution: {integrity: sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==} + dependencies: + ajv: 8.13.0 + cookie: 0.5.0 + process-warning: 1.0.0 + set-cookie-parser: 2.6.0 + dev: false + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: false + + /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==} + dependencies: + uc.micro: 2.1.0 + dev: false + + /listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + dev: true + + /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 + 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@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + /loader-utils@1.4.2: + resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} + engines: {node: '>=4.0.0'} + 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'} + 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 + + /locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + dependencies: + p-locate: 3.0.0 + path-exists: 3.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: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + + /lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + dev: false + + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: true + + /lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + dev: true + + /lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: true + + /lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + + /lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + dev: false + + /lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + dev: false + + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + /lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + dev: false + + /lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + dev: false + + /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==} + dev: false + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: false + + /lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + dev: true + + /lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + dev: true + + /lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + /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 + + /log4js@6.9.1: + resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} + engines: {node: '>=8.0'} + dependencies: + date-format: 4.0.14 + debug: 4.4.0(supports-color@8.1.1) + flatted: 3.3.1 + rfdc: 1.3.1 + streamroller: 3.1.5 + transitivePeerDependencies: + - supports-color + dev: true + + /long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.8.1 + + /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==} + dependencies: + fault: 1.0.4 + highlight.js: 10.7.3 + dev: true + + /lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + dev: false + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + + /make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + 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'} + dependencies: + semver: 6.3.1 + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + + /make-fetch-happen@8.0.14: + resolution: {integrity: sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==} + engines: {node: '>= 10'} + dependencies: + agentkeepalive: 4.5.0 + cacache: 15.3.0 + http-cache-semantics: 4.1.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + 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==} + dependencies: + tmpl: 1.0.5 + + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + 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-or-similar@1.5.0: + resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} + dev: true + + /map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + dependencies: + object-visit: 1.0.1 + + /markdown-escapes@1.0.4: + resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} + dev: true + + /markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + dev: false + + /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: + react: 17.0.2 + dev: 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==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /mdast-squeeze-paragraphs@4.0.0: + resolution: {integrity: sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==} + dependencies: + unist-util-remove: 2.1.0 + dev: true + + /mdast-util-definitions@4.0.0: + resolution: {integrity: sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==} + dependencies: + unist-util-visit: 2.0.3 + dev: true + + /mdast-util-to-hast@10.0.1: + resolution: {integrity: sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==} + dependencies: + '@types/mdast': 3.0.15 + '@types/unist': 2.0.10 + 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 + + /mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + dev: false + + /mdurl@1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + dev: true + + /mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + dev: false + + /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'} + dev: false + + /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 + dev: false + + /memfs@3.4.3: + resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} + engines: {node: '>= 4.0.0'} + dependencies: + fs-monkey: 1.0.3 + + /memfs@4.12.0: + resolution: {integrity: sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==} + engines: {node: '>= 4.0.0'} + dependencies: + '@jsonjoy.com/json-pack': 1.1.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.3.0(tslib@2.8.1) + tree-dump: 1.0.2(tslib@2.8.1) + tslib: 2.8.1 + + /memoizerific@1.11.3: + resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} + dependencies: + map-or-similar: 1.5.0 + dev: true + + /memory-fs@0.4.1: + resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} + 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'} + dependencies: + errno: 0.1.8 + readable-stream: 2.3.8 + + /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'} + dev: false + + /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==} + dev: true + + /micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + /miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + + /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'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.54.0 + dev: false + + /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 + + /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'} + requiresBuild: true + + /min-document@2.19.0: + resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} + dependencies: + dom-walk: 0.1.2 + dev: true + + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + + /mini-css-extract-plugin@2.5.3(webpack@5.98.0): + resolution: {integrity: sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 || ^4 || ^5 + dependencies: + schema-utils: 4.2.0 + webpack: 5.98.0 + dev: false + + /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.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch@5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /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==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + + /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'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + 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'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + 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: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: false + + /minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + 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'} + dependencies: + concat-stream: 1.6.2 + duplexify: 3.7.1 + end-of-stream: 1.4.4 + flush-write-stream: 1.1.1 + from2: 2.3.0 + parallel-transform: 1.2.0 + pump: 3.0.0 + 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'} + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + requiresBuild: true + dev: false + optional: true + + /mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + dependencies: + minimist: 1.2.8 + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + /mocha@10.4.0: + resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} + engines: {node: '>= 14.0.0'} + hasBin: true + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: true + + /move-concurrently@1.0.1: + resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==} + dependencies: + aproba: 1.2.0 + copy-concurrently: 1.0.5 + fs-write-stream-atomic: 1.0.10 + mkdirp: 0.5.6 + 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 + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /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 + dependencies: + dns-packet: 5.6.1 + thunky: 1.1.0 + dev: false + + /mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + dev: false + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: false + + /nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} + requiresBuild: true + optional: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + 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'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + requiresBuild: true + dev: false + optional: 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 + 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@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + dev: false + + /neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + /nested-error-stacks@2.1.1: + resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} + dev: true + + /nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + dev: true + + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + /node-abi@3.56.0: + resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} + engines: {node: '>=10'} + requiresBuild: true + dependencies: + semver: 7.5.4 + dev: false + optional: true + + /node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + dev: true + + /node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + requiresBuild: true + dev: false + optional: true + + /node-dir@0.1.17: + resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} + engines: {node: '>= 0.10.5'} + dependencies: + minimatch: 3.1.2 + dev: 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 + dev: true + + /node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: false + + /node-gyp@8.1.0: + resolution: {integrity: sha512-o2elh1qt7YUp3lkMwY3/l4KF3j/A3fI/Qt4NH+CQQgPJdqGE9y7qnP84cjIWN27Q0jJkrSAhCVDg+wBVNBYdBg==} + engines: {node: '>= 10.12.0'} + hasBin: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 8.0.14 + nopt: 5.0.0 + npmlog: 4.1.2 + rimraf: 3.0.2 + semver: 7.5.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-libs-browser@2.2.1: + resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} + 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 + domain-browser: 1.2.0 + events: 3.3.0 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 0.0.1 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + readable-stream: 2.3.8 + stream-browserify: 2.0.2 + stream-http: 2.8.3 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.0 + url: 0.11.3 + util: 0.11.1 + vm-browserify: 1.1.2 + + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + /node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + /nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + + /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: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.16.1 + semver: 7.5.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 + dependencies: + remove-trailing-separator: 1.1.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@1.1.2: + resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} + dependencies: + npm-normalize-package-bin: 1.0.1 + dev: false + + /npm-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + dev: false + + /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 + dev: false + + /npm-packlist@2.1.5: + resolution: {integrity: sha512-KCfK3Vi2F+PH1klYauoQzg81GQ8/GGjQRKYY6tRnpQUPKTs/1gBZSRWtTEd7jGdSn1LZL7gpAmJT+BcS55k2XQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + glob: 7.2.3 + ignore-walk: 3.0.4 + npm-bundled: 1.1.2 + npm-normalize-package-bin: 1.0.1 + dev: false + + /npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + dependencies: + path-key: 2.0.1 + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + + /npmlog@4.1.2: + resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} + 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==} + 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==} + 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 + + /number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + dev: true + + /nwsapi@2.2.7: + resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + + /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'} + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: false + + /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'} + dependencies: + isobject: 3.0.1 + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + /object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + + /object.getownpropertydescriptors@2.1.7: + resolution: {integrity: sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==} + engines: {node: '>= 0.8'} + dependencies: + array.prototype.reduce: 1.0.6 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.2 + safe-array-concat: 1.1.2 + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: false + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: true + + /object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + + /object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + /objectorarray@1.0.5: + resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==} + dev: true + + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: false + + /on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + 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'} + 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'} + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + + /open@10.1.0: + resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} + engines: {node: '>=18'} + dependencies: + default-browser: 5.2.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 3.1.0 + dev: false + + /open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + 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'} + 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 + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + + /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-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + dev: false + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + dev: false + + /osenv@0.1.5: + resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} + 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 + + /own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + /p-all@2.1.0: + resolution: {integrity: sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==} + engines: {node: '>=6'} + dependencies: + p-map: 2.1.0 + dev: true + + /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'} + dev: false + + /p-event@4.2.0: + resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==} + engines: {node: '>=8'} + dependencies: + p-timeout: 3.2.0 + dev: true + + /p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + 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-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + + /p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + dependencies: + p-limit: 2.3.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: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + + /p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + dev: true + + /p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + 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-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + 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'} + dependencies: + '@types/retry': 0.12.2 + is-network-error: 1.1.0 + retry: 0.13.1 + dev: false + + /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 + dev: false + + /p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + dependencies: + p-finally: 1.0.0 + dev: true + + /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==} + dev: false + + /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.5.4 + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + /parallel-transform@1.2.0: + resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} + dependencies: + cyclist: 1.0.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + + /param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} + 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 + safe-buffer: 5.2.1 + + /parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + dev: true + + /parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + dependencies: + parse-statements: 1.0.11 + dev: false + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.23.5 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + /parse-semver@1.1.1: + resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + dependencies: + semver: 5.7.2 + dev: false + + /parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + dev: false + + /parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + dev: false + + /parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: true + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + + /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==} + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + /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==} + requiresBuild: true + + /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-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'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + dev: false + + /path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + + /path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + dev: false + + /path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + dev: false + + /path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + dependencies: + pify: 3.0.0 + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + /picocolors@0.2.1: + resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: false + + /pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + dev: true + + /pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + /pino-std-serializers@3.2.0: + resolution: {integrity: sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==} + dev: false + + /pino@6.14.0: + resolution: {integrity: sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==} + hasBin: true + dependencies: + fast-redact: 3.4.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'} + + /pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + dev: false + + /pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + dependencies: + find-up: 3.0.0 + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + dependencies: + find-up: 5.0.0 + dev: true + + /pkg-up@3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} + dependencies: + find-up: 3.0.0 + dev: true + + /pnp-webpack-plugin@1.6.4(typescript@5.8.2): + resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} + engines: {node: '>=6'} + dependencies: + ts-pnp: 1.2.0(typescript@5.8.2) + transitivePeerDependencies: + - typescript + dev: true + + /pnpm-sync-lib@0.3.2: + resolution: {integrity: sha512-XlHyNAHlBqIMGTBD0HfgyRyj1UpSJvVyP20ihPek00YKmMb7RJ16AxlQkjT1jQ/D6s6OAT0ety/tSxcJTrvQ4w==} + dependencies: + '@pnpm/dependency-path-2': /@pnpm/dependency-path@2.1.8 + '@pnpm/dependency-path-5': /@pnpm/dependency-path@5.1.7 + yaml: 2.4.1 + dev: false + + /polished@4.3.1: + resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} + engines: {node: '>=10'} + dependencies: + '@babel/runtime': 7.24.0 + dev: true + + /posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + /postcss-calc@8.2.4(postcss@8.4.36): + resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} + peerDependencies: + postcss: ^8.2.2 + dependencies: + postcss: 8.4.36 + postcss-selector-parser: 6.0.16 + 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 + dependencies: + browserslist: 4.23.0 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.4.36 + 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 + dependencies: + browserslist: 4.23.0 + postcss: 8.4.36 + 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 + dependencies: + postcss: 8.4.36 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + dev: false + + /postcss-flexbugs-fixes@4.2.1: + resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==} + 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 + dependencies: + cosmiconfig: 7.1.0 + klona: 2.0.6 + loader-utils: 2.0.4 + postcss: 8.4.36 + schema-utils: 3.3.0 + semver: 7.5.4 + webpack: 4.47.0 + dev: true + + /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 + 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 + dev: true + + /postcss-loader@6.2.1(postcss@8.4.36)(webpack@5.98.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 + dependencies: + cosmiconfig: 7.1.0 + klona: 2.0.6 + postcss: 8.4.36 + semver: 7.5.4 + webpack: 5.98.0 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + postcss-value-parser: 4.2.0 + stylehacks: 5.1.1(postcss@8.4.36) + dev: false + + /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 + dependencies: + browserslist: 4.23.0 + 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 + + /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 + dependencies: + postcss: 8.4.36 + 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 + dependencies: + colord: 2.9.3 + cssnano-utils: 3.1.0(postcss@8.4.36) + postcss: 8.4.36 + 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 + dependencies: + browserslist: 4.23.0 + cssnano-utils: 3.1.0(postcss@8.4.36) + postcss: 8.4.36 + 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 + dependencies: + postcss: 8.4.36 + postcss-selector-parser: 6.0.16 + dev: false + + /postcss-modules-extract-imports@2.0.0: + resolution: {integrity: sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==} + engines: {node: '>= 6'} + 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 + dependencies: + postcss: 8.4.36 + + /postcss-modules-local-by-default@3.0.3: + resolution: {integrity: sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==} + engines: {node: '>= 6'} + dependencies: + icss-utils: 4.1.1 + postcss: 7.0.39 + postcss-selector-parser: 6.0.16 + 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 + dependencies: + icss-utils: 5.1.0(postcss@8.4.36) + postcss: 8.4.36 + postcss-selector-parser: 6.0.16 + postcss-value-parser: 4.2.0 + + /postcss-modules-scope@2.2.0: + resolution: {integrity: sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==} + engines: {node: '>= 6'} + dependencies: + postcss: 7.0.39 + postcss-selector-parser: 6.0.16 + dev: true + + /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 + dependencies: + postcss: 8.4.36 + postcss-selector-parser: 6.0.16 + + /postcss-modules-values@3.0.0: + resolution: {integrity: sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==} + 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 + dependencies: + icss-utils: 5.1.0(postcss@8.4.36) + postcss: 8.4.36 + + /postcss-modules@6.0.0(postcss@8.4.36): + resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==} + peerDependencies: + postcss: ^8.0.0 + dependencies: + generic-names: 4.0.0 + icss-utils: 5.1.0(postcss@8.4.36) + 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) + 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 + dependencies: + postcss: 8.4.36 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + 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 + dependencies: + postcss: 8.4.36 + 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 + dependencies: + postcss: 8.4.36 + 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 + 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 + dependencies: + postcss: 8.4.36 + 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 + dependencies: + browserslist: 4.23.0 + postcss: 8.4.36 + 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 + dependencies: + normalize-url: 6.1.0 + postcss: 8.4.36 + 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 + dependencies: + postcss: 8.4.36 + 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 + dependencies: + cssnano-utils: 3.1.0(postcss@8.4.36) + postcss: 8.4.36 + 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 + dependencies: + browserslist: 4.23.0 + caniuse-api: 3.0.0 + postcss: 8.4.36 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + 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'} + 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 + dependencies: + postcss: 8.4.36 + postcss-value-parser: 4.2.0 + svgo: 2.8.0 + dev: false + + /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 + dependencies: + postcss: 8.4.36 + postcss-selector-parser: 6.0.16 + dev: false + + /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'} + 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} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.1.0 + + /prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + requiresBuild: true + dependencies: + detect-libc: 2.0.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.56.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + optional: 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 + dev: true + + /prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + dev: false + + /pretty-error@2.1.2: + resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==} + dependencies: + lodash: 4.17.21 + renderkid: 2.0.7 + + /pretty-error@4.0.0: + resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + dependencies: + lodash: 4.17.21 + 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} + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + + /pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + dev: true + + /prism-react-renderer@2.4.1(react@17.0.2): + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + peerDependencies: + react: '>=16.0.0' + dependencies: + '@types/prismjs': 1.26.5 + clsx: 2.1.1 + react: 17.0.2 + dev: false + + /prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + dev: true + + /prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + dev: true + + /private@0.1.8: + resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} + engines: {node: '>= 0.6'} + dev: true + + /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==} + dev: false + + /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'} + dev: true + + /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'} + 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'} + dependencies: + array.prototype.map: 1.0.7 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + 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'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + 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'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /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 + + /property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + 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'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true + + /prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + /pseudolocale@1.1.0: + resolution: {integrity: sha512-OZ8I/hwYEJ3beN3IEcNnt8EpcqblH0/x23hulKBXjs+WhTTEle+ijCHCkh2bd+cIIeCuCwSCbBe93IthGG6hLw==} + dependencies: + commander: 12.0.0 + dev: false + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + + /public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + parse-asn1: 5.1.7 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + /pump@2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + /pumpify@1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + + /punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + dev: false + + /punycode@1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + dev: true + + /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'} + dependencies: + escape-goat: 2.1.1 + + /puppeteer-core@2.1.1: + resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==} + engines: {node: '>=8.16.0'} + dependencies: + '@types/mime-types': 2.1.4 + debug: 4.4.0(supports-color@8.1.1) + extract-zip: 1.7.0 + https-proxy-agent: 4.0.0 + mime: 2.6.0 + mime-types: 2.1.35 + progress: 2.0.3 + proxy-from-env: 1.1.0 + rimraf: 2.7.1 + ws: 6.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /pure-rand@6.0.4: + resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + + /q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: true + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.1.0 + dev: true + + /qs@6.12.0: + resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.6 + dev: true + + /qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.1.0 + + /qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.1.0 + + /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. + dev: true + + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + + /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==} + dev: false + + /ramda@0.28.0: + resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==} + dev: true + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + + /randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + 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'} + + /raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + /raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + dev: false + + /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 + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 4.47.0 + dev: true + + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + /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' + dependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + dev: true + + /react-docgen-typescript@2.2.2(typescript@5.8.2): + resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} + peerDependencies: + typescript: '>= 4.3.x' + dependencies: + typescript: 5.8.2 + dev: true + + /react-docgen@5.4.3: + resolution: {integrity: sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==} + engines: {node: '>=8.10.0'} + hasBin: true + dependencies: + '@babel/core': 7.20.12 + '@babel/generator': 7.23.6 + '@babel/runtime': 7.24.0 + ast-types: 0.14.2 + commander: 2.20.3 + doctrine: 3.0.0 + estree-to-babel: 3.2.1 + neo-async: 2.6.2 + node-dir: 0.1.17 + 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 + 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' + dependencies: + clsx: 1.2.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 + 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-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 + dependencies: + '@babel/runtime': 7.24.0 + 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 + dependencies: + react: 17.0.2 + dev: false + + /react-inspector@5.1.1(react@17.0.2): + resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==} + peerDependencies: + react: ^16.8.4 || ^17.0.0 + dependencies: + '@babel/runtime': 7.24.0 + 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@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + + /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 + dependencies: + '@babel/runtime': 7.24.0 + '@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): + resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} + peerDependencies: + '@popperjs/core': ^2.0.0 + react: ^16.8.0 || ^17 || ^18 + react-dom: ^16.8.0 || ^17 || ^18 + 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 + 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 + + /react-refresh@0.11.0: + resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==} + engines: {node: '>=0.10.0'} + dev: true + + /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' + dependencies: + '@remix-run/router': 1.15.3 + '@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.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' + dependencies: + '@remix-run/router': 1.15.3 + '@types/react': 17.0.74 + react: 17.0.2 + dev: true + + /react-sizeme@3.0.2: + resolution: {integrity: sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==} + 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' + dependencies: + '@babel/runtime': 7.24.0 + highlight.js: 10.7.3 + lowlight: 1.20.0 + prismjs: 1.29.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 + dependencies: + '@babel/runtime': 7.24.0 + 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) + 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 + + /react@17.0.2: + resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + + /read-package-json@2.1.2: + resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} + 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 + 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'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /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 + dev: true + + /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 + dev: false + + /read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + dependencies: + mute-stream: 0.0.8 + dev: false + + /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: + 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-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + dependencies: + minimatch: 5.1.6 + dev: true + + /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 + dev: false + + /readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + requiresBuild: true + 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 + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /recast@0.19.1: + resolution: {integrity: sha512-8FCjrBxjeEU2O6I+2hyHyBFH1siJbMBLwIRvVr1T3FD2cL754sOaJDsJ/8h3xYltasbJ8jqWRIhMuDGBSiSbjw==} + engines: {node: '>= 4'} + 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'} + dependencies: + ast-types: 0.14.2 + esprima: 4.0.1 + source-map: 0.6.1 + tslib: 2.8.1 + dev: true + + /rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.8 + dev: true + + /redux-thunk@2.4.2(redux@4.2.1): + resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} + peerDependencies: + redux: ^4 + dependencies: + redux: 4.2.1 + dev: false + + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.24.0 + + /reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + 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 + + /refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + 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'} + 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==} + + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + dependencies: + '@babel/runtime': 7.24.0 + dev: true + + /regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + 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'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + /regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.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 + + /regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 + 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 + + /regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: 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==} + 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-mdx@1.6.22: + resolution: {integrity: sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==} + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-plugin-utils': 7.10.4 + '@babel/plugin-proposal-object-rest-spread': 7.12.1(@babel/core@7.12.9) + '@babel/plugin-syntax-jsx': 7.12.1(@babel/core@7.12.9) + '@mdx-js/util': 1.6.22 + is-alphabetical: 1.0.4 + remark-parse: 8.0.3 + unified: 9.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /remark-parse@8.0.3: + resolution: {integrity: sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==} + dependencies: + ccount: 1.1.0 + collapse-white-space: 1.0.6 + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + is-whitespace-character: 1.0.4 + is-word-character: 1.0.4 + markdown-escapes: 1.0.4 + parse-entities: 2.0.0 + repeat-string: 1.6.1 + state-toggle: 1.0.3 + trim: 0.0.1 + trim-trailing-lines: 1.1.4 + unherit: 1.1.3 + 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==} + 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==} + dependencies: + mdast-squeeze-paragraphs: 4.0.0 + dev: true + + /remeda@0.0.32: + resolution: {integrity: sha512-FEdl8ONpqY7AvvMHG5WYdomc0mGf2khHPUDu6QvNkOq4Wjkw5BvzWM4QyksAQ/US1sFIIRG8TVBn6iJx6HbRrA==} + dev: true + + /remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + requiresBuild: true + + /renderkid@2.0.7: + resolution: {integrity: sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==} + dependencies: + css-select: 4.3.0 + dom-converter: 0.2.0 + htmlparser2: 6.1.0 + lodash: 4.17.21 + strip-ansi: 3.0.1 + + /renderkid@3.0.0: + resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + dependencies: + css-select: 4.3.0 + dom-converter: 0.2.0 + htmlparser2: 6.1.0 + lodash: 4.17.21 + 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'} + dev: true + + /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==} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + /reselect@4.1.8: + resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} + dev: false + + /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'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /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.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /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 + dev: false + + /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 + + /retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + dev: true + + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + dev: false + + /rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + + /rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + 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 + 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 + dependencies: + glob: 7.2.3 + + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + + /router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + dependencies: + debug: 4.4.0(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + dev: false + + /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==} + dependencies: + '@babel/runtime': 7.24.0 + dev: false + + /run-applescript@7.0.0: + resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} + engines: {node: '>=18'} + dev: false + + /run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + dev: false + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /run-queue@1.0.3: + resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} + dependencies: + aproba: 1.2.0 + + /rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + dependencies: + tslib: 1.14.1 + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.8.1 + dev: false + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + /safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + 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.1: + resolution: {integrity: sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==} + dev: true + + /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-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-regex: 1.1.4 + + /safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + /safe-regex2@2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + dependencies: + ret: 0.2.2 + dev: false + + /safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + dependencies: + ret: 0.1.15 + + /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 + dependencies: + '@cnakazawa/watch': 1.0.4 + anymatch: 2.0.0 + capture-exit: 2.0.0 + exec-sh: 0.3.6 + execa: 1.0.0 + fb-watchman: 2.0.2 + micromatch: 3.1.10 + minimist: 1.2.8 + walker: 1.0.8 + dev: true + + /sass-embedded-android-arm64@1.85.1: + resolution: {integrity: sha512-27oRheqNA3SJM2hAxpVbs7mCKUwKPWmEEhyiNFpBINb5ELVLg+Ck5RsGg+SJmo130ul5YX0vinmVB5uPWc8X5w==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-android-arm@1.85.1: + resolution: {integrity: sha512-GkcgUGMZtEF9gheuE1dxCU0ZSAifuaFXi/aX7ZXvjtdwmTl9Zc/OHR9oiUJkc8IW9UI7H8TuwlTAA8+SwgwIeQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-android-ia32@1.85.1: + resolution: {integrity: sha512-f3x16NyRgtXFksIaO/xXKrUhttUBv8V0XsAR2Dhdb/yz4yrDrhzw9Wh8fmw7PlQqECcQvFaoDr3XIIM6lKzasw==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-android-riscv64@1.85.1: + resolution: {integrity: sha512-IP6OijpJ8Mqo7XqCe0LsuZVbAxEFVboa0kXqqR5K55LebEplsTIA2GnmRyMay3Yr/2FVGsZbCb6Wlgkw23eCiA==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-android-x64@1.85.1: + resolution: {integrity: sha512-Mh7CA53wR3ADvXAYipFc/R3vV4PVOzoKwWzPxmq+7i8UZrtsVjKONxGtqWe9JG1mna0C9CRZAx0sv/BzbOJxWg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-darwin-arm64@1.85.1: + resolution: {integrity: sha512-msWxzhvcP9hqGVegxVePVEfv9mVNTlUgGr6k7O7Ihji702mbtrH/lKwF4aRkkt4g1j7tv10+JtQXmTNi/pi9kA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-darwin-x64@1.85.1: + resolution: {integrity: sha512-J4UFHUiyI9Z+mwYMwz11Ky9TYr3hY1fCxeQddjNGL/+ovldtb0yAIHvoVM0BGprQDm5JqhtUk8KyJ3RMJqpaAA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-arm64@1.85.1: + resolution: {integrity: sha512-jGadetB03BMFG2rq3OXub/uvC/lGpbQOiLGEz3NLb2nRZWyauRhzDtvZqkr6BEhxgIWtMtz2020yD8ZJSw/r2w==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-arm@1.85.1: + resolution: {integrity: sha512-X0fDh95nNSw1wfRlnkE4oscoEA5Au4nnk785s9jghPFkTBg+A+5uB6trCjf0fM22+Iw6kiP4YYmDdw3BqxAKLQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-ia32@1.85.1: + resolution: {integrity: sha512-7HlYY90d9mitDtNi5s+S+5wYZrTVbkBH2/kf7ixrzh2BFfT0YM81UHLJRnGX93y9aOMBL6DSZAIfkt1RsV9bkQ==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-musl-arm64@1.85.1: + resolution: {integrity: sha512-FLkIT0p18XOkR6wryJ13LqGBDsrYev2dRk9dtiU18NCpNXruKsdBQ1ZnWHVKB3h1dA9lFyEEisC0sooKdNfeOQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-musl-arm@1.85.1: + resolution: {integrity: sha512-5vcdEqE8QZnu6i6shZo7x2N36V7YUoFotWj2rGekII5ty7Nkaj+VtZhUEOp9tAzEOlaFuDp5CyO1kUCvweT64A==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-musl-ia32@1.85.1: + resolution: {integrity: sha512-N1093T84zQJor1yyIAdYScB5eAuQarGK1tKgZ4uTnxVlgA7Xi1lXV8Eh7ox9sDqKCaWkVQ3MjqU26vYRBeRWyw==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-musl-riscv64@1.85.1: + resolution: {integrity: sha512-WRsZS/7qlfYXsa93FBpSruieuURIu7ySfFhzYfF1IbKrNAGwmbduutkHZh2ddm5/vQMvQ0Rdosgv+CslaQHMcw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-musl-x64@1.85.1: + resolution: {integrity: sha512-+OlLIilA5TnP0YEqTQ8yZtkW+bJIQYvzoGoNLUEskeyeGuOiIyn2CwL6G4JQB4xZQFaxPHb7JD3EueFkQbH0Pw==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-riscv64@1.85.1: + resolution: {integrity: sha512-mKKlOwMGLN7yP1p0gB5yG/HX4fYLnpWaqstNuOOXH+fOzTaNg0+1hALg0H0CDIqypPO74M5MS9T6FAJZGdT6dQ==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-linux-x64@1.85.1: + resolution: {integrity: sha512-uKRTv0z8NgtHV7xSren78+yoWB79sNi7TMqI7Bxd8fcRNIgHQSA8QBdF8led2ETC004hr8h71BrY60RPO+SSvA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-win32-arm64@1.85.1: + resolution: {integrity: sha512-/GMiZXBOc6AEMBC3g25Rp+x8fq9Z6Ql7037l5rajBPhZ+DdFwtdHY0Ou3oIU6XuWUwD06U3ii4XufXVFhsP6PA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-win32-ia32@1.85.1: + resolution: {integrity: sha512-L+4BWkKKBGFOKVQ2PQ5HwFfkM5FvTf1Xx2VSRvEWt9HxPXp6SPDho6zC8fqNQ3hSjoaoASEIJcSvgfdQYO0gdg==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /sass-embedded-win32-x64@1.85.1: + resolution: {integrity: sha512-/FO0AGKWxVfCk4GKsC0yXWBpUZdySe3YAAbQQL0lL6xUd1OiUY8Kow6g4Kc1TB/+z0iuQKKTqI/acJMEYl4iTQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /sass-embedded@1.85.1: + resolution: {integrity: sha512-0i+3h2Df/c71afluxC1SXqyyMmJlnKWfu9ZGdzwuKRM1OftEa2XM2myt5tR36CF3PanYrMjFKtRIj8PfSf838w==} + engines: {node: '>=16.0.0'} + hasBin: true + dependencies: + '@bufbuild/protobuf': 2.2.5 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.1 + rxjs: 7.8.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 + dev: false + + /sass-loader@12.4.0(sass@1.49.11)(webpack@5.98.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 + dependencies: + klona: 2.0.6 + neo-async: 2.6.2 + sass: 1.49.11 + webpack: 5.98.0 + dev: false + + /sass@1.49.11: + resolution: {integrity: sha512-wvS/geXgHUGs6A/4ud5BFIWKO1nKd7wYIGimDk4q4GFkJicILActpv9ueMT4eRGSsp1BdKHuw1WwAHXbhsJELQ==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + chokidar: 3.6.0 + immutable: 4.3.5 + source-map-js: 1.1.0 + dev: false + + /sax@1.2.1: + resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} + dev: true + + /sax@1.3.0: + resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + + /saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + + /scheduler@0.19.0: + resolution: {integrity: sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA==} + 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 + + /schema-utils@1.0.0: + resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} + engines: {node: '>= 4'} + dependencies: + ajv: 6.12.6 + ajv-errors: 1.0.1(ajv@6.12.6) + ajv-keywords: 3.5.2(ajv@6.12.6) + + /schema-utils@2.7.0: + resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} + engines: {node: '>= 8.9.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + dev: true + + /schema-utils@2.7.1: + resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} + engines: {node: '>= 8.9.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + dev: true + + /schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + /schema-utils@4.2.0: + resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} + engines: {node: '>= 12.13.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.13.0 + ajv-formats: 2.1.1 + ajv-keywords: 5.1.0(ajv@8.13.0) + dev: false + + /schema-utils@4.3.0: + resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.13.0 + ajv-formats: 2.1.1 + ajv-keywords: 5.1.0(ajv@8.13.0) + + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + + /select-hose@2.0.0: + resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} + dev: false + + /selfsigned@2.4.1: + resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} + engines: {node: '>=10'} + dependencies: + '@types/node-forge': 1.3.11 + node-forge: 1.3.1 + dev: false + + /semver-diff@3.1.1: + resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + + /semver-store@0.3.0: + resolution: {integrity: sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==} + dev: false + + /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 + dependencies: + lru-cache: 6.0.0 + + /semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + /send@0.17.2: + resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 1.1.2 + destroy: 1.0.4 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 1.8.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.3.0 + range-parser: 1.2.1 + statuses: 1.5.0 + dev: false + + /send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + + /send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + dependencies: + debug: 4.4.0(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.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /serialize-javascript@4.0.0: + resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + dependencies: + randombytes: 2.1.0 + + /serialize-javascript@5.0.1: + resolution: {integrity: sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==} + dependencies: + randombytes: 2.1.0 + dev: true + + /serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + dependencies: + randombytes: 2.1.0 + dev: true + + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + + /serve-favicon@2.5.0: + resolution: {integrity: sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==} + engines: {node: '>= 0.8.0'} + dependencies: + etag: 1.8.1 + fresh: 0.5.2 + ms: 2.1.1 + parseurl: 1.3.3 + safe-buffer: 5.1.1 + dev: true + + /serve-index@1.9.1: + resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9 + escape-html: 1.0.3 + http-errors: 1.6.3 + mime-types: 2.1.35 + parseurl: 1.3.3 + dev: false + + /serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + + /serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + dev: false + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true + + /set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + dev: false + + /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.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'} + 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-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + /set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + 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 + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + dependencies: + kind-of: 6.0.3 + + /shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + dev: true + + /shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + dependencies: + shebang-regex: 1.0.0 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: false + + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.0.6 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: true + + /side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + /side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + 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.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.4 + dev: true + + /side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + 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: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: false + + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + requiresBuild: true + dev: false + optional: true + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + requiresBuild: true + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + optional: true + + /sirv@1.0.19: + resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.25 + mrmime: 1.0.1 + totalist: 1.1.0 + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash@2.0.0: + resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} + engines: {node: '>=6'} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + /slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + 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'} + 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 + + /snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + 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'} + dependencies: + kind-of: 3.2.2 + + /snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + + /sockjs@0.3.24: + resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} + 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'} + dependencies: + agent-base: 6.0.2 + debug: 4.4.0(supports-color@8.1.1) + socks: 2.8.1 + transitivePeerDependencies: + - supports-color + dev: true + + /socks@2.8.1: + resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + dev: true + + /sonic-boom@1.4.1: + resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==} + 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'} + dependencies: + is-plain-obj: 2.1.0 + dev: false + + /source-list-map@2.0.1: + resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} + + /source-map-js@1.1.0: + resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==} + engines: {node: '>=0.10.0'} + + /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 + 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 + whatwg-mimetype: 2.3.0 + dev: true + + /source-map-loader@3.0.2(webpack@5.98.0): + resolution: {integrity: sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 || ^4 || ^5 + dependencies: + abab: 2.0.6 + iconv-lite: 0.6.3 + source-map-js: 1.1.0 + webpack: 5.98.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 + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + 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@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.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + /space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + dev: true + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.17 + + /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==} + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 + + /spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 + dev: false + + /spdx-license-ids@3.0.17: + resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + + /spdy-transport@3.0.0: + resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + dependencies: + debug: 4.4.0(supports-color@8.1.1) + detect-node: 2.1.0 + hpack.js: 2.1.6 + obuf: 1.1.2 + readable-stream: 3.6.2 + 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'} + dependencies: + debug: 4.4.0(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'} + dependencies: + extend-shallow: 3.0.2 + + /split2@3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.2 + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + /sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + dev: true + + /ssri@10.0.5: + resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 7.1.2 + dev: false + + /ssri@6.0.2: + resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==} + dependencies: + figgy-pudding: 3.5.2 + + /ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + 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' + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + + /stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + dev: true + + /state-toggle@1.0.3: + resolution: {integrity: sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==} + dev: true + + /static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + 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'} + + /stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + dependencies: + internal-slot: 1.1.0 + dev: true + + /stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + /stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + dev: false + + /store2@2.14.3: + resolution: {integrity: sha512-4QcZ+yx7nzEFiV4BMLnr/pRa5HYzNITX2ri0Zh6sT9EyQHbBHacC6YigllUPU9X3D0f/22QCgfokpKs52YRrUg==} + dev: true + + /stream-browserify@2.0.2: + resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + /stream-each@1.2.3: + resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==} + dependencies: + end-of-stream: 1.4.4 + stream-shift: 1.0.3 + + /stream-http@2.8.3: + resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 2.3.8 + to-arraybuffer: 1.0.1 + xtend: 4.0.2 + + /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'} + dependencies: + date-format: 4.0.14 + debug: 4.4.0(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 + + /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==} + dev: false + + /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 + + /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-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + 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'} + dependencies: + emoji-regex: 7.0.3 + is-fullwidth-code-point: 2.0.0 + strip-ansi: 5.2.0 + dev: true + + /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-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + /string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + 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.padend@3.1.5: + resolution: {integrity: sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: true + + /string.prototype.padstart@3.1.6: + resolution: {integrity: sha512-1y15lz7otgfRTAVK5qbp3eHIga+w8j7+jIH+7HpUrOfnLVl6n0hbspi4EXf4tR+PNOpBjPstltemkx0SvViOCg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + dev: true + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.2 + + /string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + 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.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + + /string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + 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.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 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: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + + /strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + + /strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + dependencies: + ansi-regex: 4.1.1 + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: false + + /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'} + dev: true + + /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 + dev: true + + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + requiresBuild: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + + /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 + dependencies: + loader-utils: 2.0.4 + schema-utils: 2.7.1 + webpack: 4.47.0 + dev: true + + /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 + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 4.47.0 + dev: true + + /style-loader@3.3.4(webpack@5.98.0): + resolution: {integrity: sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 || ^4 || ^5 + dependencies: + webpack: 5.98.0 + + /style-to-object@0.3.0: + resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} + dependencies: + inline-style-parser: 0.1.1 + dev: true + + /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 + 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 + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-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: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /svgo@2.8.0: + resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} + engines: {node: '>=10.13.0'} + hasBin: true + 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 + stable: 0.1.8 + dev: false + + /symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + /symbol.prototype.description@1.0.6: + resolution: {integrity: sha512-VgVgtEabORsQtmuindtO7v8fF+bsKxUkvEMFj+ecBK6bomrwv5JUSWdMoC3ypa9+Jaqp/wOzkWk4f6I+p5GzyA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + get-symbol-description: 1.1.0 + has-symbols: 1.1.0 + object.getownpropertydescriptors: 2.1.7 + dev: true + + /sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + dependencies: + sync-message-port: 1.1.3 + dev: false + + /sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + dev: false + + /synchronous-promise@2.0.17: + resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} + dev: true + + /table@5.4.6: + resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} + engines: {node: '>=6.0.0'} + dependencies: + ajv: 6.12.6 + lodash: 4.17.21 + slice-ansi: 2.1.0 + string-width: 3.1.0 + dev: true + + /table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + dependencies: + ajv: 8.13.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==} + dependencies: + keyborg: 2.5.0 + tslib: 2.8.1 + dev: false + + /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.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + requiresBuild: true + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + optional: true + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + /tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + 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 + + /telejson@5.3.3: + resolution: {integrity: sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==} + 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 + isobject: 4.0.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + dev: true + + /temp@0.8.4: + resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} + engines: {node: '>=6.0.0'} + 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 + dependencies: + cacache: 12.0.4 + find-cache-dir: 2.1.0 + is-wsl: 1.1.0 + schema-utils: 1.0.0 + serialize-javascript: 4.0.0 + source-map: 0.6.1 + terser: 4.8.1 + 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 + 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: 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 + dependencies: + cacache: 15.3.0 + find-cache-dir: 3.3.2 + jest-worker: 26.6.2 + p-limit: 3.1.0 + schema-utils: 3.3.0 + serialize-javascript: 5.0.1 + source-map: 0.6.1 + terser: 5.29.2 + webpack: 4.47.0 + webpack-sources: 1.4.3 + dev: true + + /terser-webpack-plugin@5.3.10(webpack@5.98.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 + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.29.2 + webpack: 5.98.0 + dev: false + + /terser-webpack-plugin@5.3.11(webpack@5.98.0): + resolution: {integrity: sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==} + 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 + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 4.3.0 + serialize-javascript: 6.0.2 + terser: 5.39.0 + webpack: 5.98.0 + + /terser@4.8.1: + resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} + engines: {node: '>=6.0.0'} + hasBin: true + 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 + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 + + /terser@5.39.0: + resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.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'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: false + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: false + + /thingies@1.21.0(tslib@2.8.1): + resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + dependencies: + tslib: 2.8.1 + + /throat@6.0.2: + resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} + dev: false + + /throttle-debounce@3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + dev: true + + /through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + /through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.2 + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: false + + /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'} + dependencies: + setimmediate: 1.0.5 + + /tiny-lru@7.0.6: + resolution: {integrity: sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==} + engines: {node: '>=6'} + dev: false + + /tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 + dev: false + + /tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + dev: false + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + /to-arraybuffer@1.0.1: + resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + + /to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + 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'} + dependencies: + is-number: 7.0.0 + + /to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + 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 + + /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@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + + /tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + dependencies: + punycode: 2.3.1 + + /traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + dev: true + + /tree-dump@1.0.2(tslib@2.8.1): + resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + dependencies: + tslib: 2.8.1 + + /trim-trailing-lines@1.1.4: + resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==} + dev: true + + /trim@0.0.1: + resolution: {integrity: sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==} + deprecated: Use String.prototype.trim() instead + dev: true + + /trough@1.0.5: + resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} + dev: true + + /true-case-path@2.2.1: + resolution: {integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==} + dev: false + + /ts-api-utils@1.3.0(typescript@5.8.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.8.2 + dev: true + + /ts-api-utils@2.1.0(typescript@4.9.5): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 4.9.5 + dev: true + + /ts-api-utils@2.1.0(typescript@5.8.2): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 5.8.2 + + /ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + dev: true + + /ts-loader@6.0.0(typescript@5.8.2): + resolution: {integrity: sha512-lszy+D41R0Te2+loZxADWS+E1+Z55A+i3dFfFie1AZHL++65JRKVDBPQgeWgRrlv5tbxdU3zOtXp8b7AFR6KEg==} + engines: {node: '>=8.6'} + peerDependencies: + typescript: '*' + dependencies: + chalk: 2.4.2 + enhanced-resolve: 4.5.0 + loader-utils: 1.4.2 + micromatch: 4.0.5 + semver: 6.3.1 + typescript: 5.8.2 + dev: false + + /ts-pnp@1.2.0(typescript@5.8.2): + resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} + engines: {node: '>=6'} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.8.2 + dev: true + + /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: false + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + /tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + dev: true + + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + /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' + dependencies: + '@babel/code-frame': 7.23.5 + 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@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' + dependencies: + '@babel/code-frame': 7.23.5 + 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@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' + dependencies: + '@babel/code-frame': 7.23.5 + 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 + + /tslint@5.20.1(typescript@5.8.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' + dependencies: + '@babel/code-frame': 7.23.5 + 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@5.8.2) + typescript: 5.8.2 + dev: true + + /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' + 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' + 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' + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + dev: true + + /tsutils@2.29.0(typescript@5.8.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' + dependencies: + tslib: 1.14.1 + typescript: 5.8.2 + dev: true + + /tty-browserify@0.0.0: + resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + requiresBuild: true + dependencies: + safe-buffer: 5.2.1 + dev: false + optional: true + + /tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + dev: false + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + /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'} + dev: true + + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + /type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + dev: false + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + /typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + /typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + 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.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + /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.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.5: + resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + /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.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.10 + + /typed-rest-client@1.8.11: + resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + dependencies: + qs: 6.14.0 + tunnel: 0.0.6 + underscore: 1.13.6 + dev: false + + /typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + + /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 + dev: true + + /typescript@3.9.10: + resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + + /uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + dev: false + + /uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.8 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.0.2 + + /unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + /underscore@1.13.6: + resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} + dev: false + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + /unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + dev: true + + /unherit@1.1.3: + resolution: {integrity: sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==} + 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-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-property-aliases-ecmascript: 2.1.0 + dev: true + + /unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + engines: {node: '>=4'} + dev: true + + /unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + dev: true + + /unified@9.2.0: + resolution: {integrity: sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==} + dependencies: + bail: 1.0.5 + extend: 3.0.2 + is-buffer: 2.0.5 + 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'} + 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==} + dependencies: + unique-slug: 2.0.2 + + /unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + dependencies: + imurmurhash: 0.1.4 + + /unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + dependencies: + crypto-random-string: 2.0.0 + + /unist-builder@2.0.3: + resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==} + dev: true + + /unist-util-generated@1.1.6: + resolution: {integrity: sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==} + dev: true + + /unist-util-is@4.1.0: + resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} + dev: true + + /unist-util-position@3.1.0: + resolution: {integrity: sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==} + dev: true + + /unist-util-remove-position@2.0.1: + resolution: {integrity: sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==} + dependencies: + unist-util-visit: 2.0.3 + dev: true + + /unist-util-remove@2.1.0: + resolution: {integrity: sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==} + 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==} + dependencies: + '@types/unist': 2.0.10 + dev: true + + /unist-util-visit-parents@3.1.1: + resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + dependencies: + '@types/unist': 2.0.10 + unist-util-is: 4.1.0 + dev: true + + /unist-util-visit@2.0.3: + resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + dependencies: + '@types/unist': 2.0.10 + 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@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'} + + /unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + /unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + dependencies: + big-integer: 1.6.52 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + 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 + 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' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.0 + + /update-browserslist-db@1.1.2(browserslist@4.24.4): + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + /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.5.4 + semver-diff: 3.1.1 + xdg-basedir: 4.0.0 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /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==} + dev: false + + /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 + 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 + dev: true + + /url-loader@4.1.1(webpack@5.98.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 + dependencies: + loader-utils: 2.0.4 + mime-types: 2.1.35 + schema-utils: 3.3.0 + webpack: 5.98.0 + dev: false + + /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==} + dependencies: + punycode: 1.3.2 + querystring: 0.2.0 + dev: true + + /url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + dependencies: + punycode: 1.4.1 + qs: 6.14.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 + 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: + '@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 + dependencies: + '@types/react': 17.0.74 + react: 17.0.2 + dev: true + + /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 + 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-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 + dependencies: + react: 17.0.2 + dev: false + + /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==} + dependencies: + define-properties: 1.2.1 + object.getownpropertydescriptors: 2.1.7 + + /util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + dependencies: + inherits: 2.0.3 + + /util@0.11.1: + resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} + dependencies: + inherits: 2.0.3 + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 + dev: true + + /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 + dev: true + + /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@8.0.0: + resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} + hasBin: true + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: true + + /v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + dev: true + + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@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==} + 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==} + dependencies: + builtins: 1.0.3 + dev: false + + /validator@13.11.0: + resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} + engines: {node: '>= 0.10'} + + /varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + dev: false + + /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==} + dev: true + + /vfile-message@2.0.4: + resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + dependencies: + '@types/unist': 2.0.10 + unist-util-stringify-position: 2.0.3 + dev: true + + /vfile@4.2.1: + resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==} + dependencies: + '@types/unist': 2.0.10 + 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==} + + /w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + dependencies: + xml-name-validator: 4.0.0 + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + + /warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + dependencies: + loose-envify: 1.4.0 + dev: true + + /watchpack-chokidar2@2.0.1: + resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} + requiresBuild: true + dependencies: + chokidar: 2.1.8 + optional: true + + /watchpack@1.7.5: + resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} + dependencies: + graceful-fs: 4.2.11 + neo-async: 2.6.2 + optionalDependencies: + 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'} + 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'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + /wbuf@1.7.3: + resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + 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 + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /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 + dependencies: + acorn: 8.11.3 + acorn-walk: 8.3.2 + chalk: 4.1.2 + commander: 7.2.0 + gzip-size: 6.0.0 + lodash: 4.17.21 + opener: 1.5.2 + sirv: 1.0.19 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + /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 + 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-log: 2.0.0 + dev: 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 + dependencies: + '@types/webpack': 4.41.32 + colorette: 2.0.20 + memfs: 3.4.3 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.2.0 + webpack: 4.47.0 + dev: false + + /webpack-dev-middleware@7.4.2(webpack@5.98.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 + dependencies: + colorette: 2.0.20 + memfs: 4.12.0 + mime-types: 2.1.35 + on-finished: 2.4.1 + range-parser: 1.2.1 + schema-utils: 4.2.0 + webpack: 5.98.0 + dev: false + + /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 + 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/serve-index': 1.9.4 + '@types/serve-static': 1.15.5 + '@types/sockjs': 0.3.36 + '@types/webpack': 4.41.32 + '@types/ws': 8.5.5 + ansi-html-community: 0.0.8 + anymatch: 3.1.3 + bonjour-service: 1.2.1 + chokidar: 3.6.0 + colorette: 2.0.20 + compression: 1.7.4 + connect-history-api-fallback: 2.0.0 + default-gateway: 6.0.3 + 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 + 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 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack: 4.47.0 + webpack-dev-middleware: 5.3.3(@types/webpack@4.41.32)(webpack@4.47.0) + ws: 8.14.2 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: false + + /webpack-dev-server@5.1.0(webpack@5.98.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 + 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/serve-index': 1.9.4 + '@types/serve-static': 1.15.5 + '@types/sockjs': 0.3.36 + '@types/ws': 8.5.12 + ansi-html-community: 0.0.8 + anymatch: 3.1.3 + bonjour-service: 1.2.1 + chokidar: 3.6.0 + colorette: 2.0.20 + compression: 1.7.4 + connect-history-api-fallback: 2.0.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 + 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 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack: 5.98.0 + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: false + + /webpack-dev-server@5.2.2(webpack@5.98.0): + resolution: {integrity: sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==} + 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 + 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/serve-index': 1.9.4 + '@types/serve-static': 1.15.5 + '@types/sockjs': 0.3.36 + '@types/ws': 8.5.12 + ansi-html-community: 0.0.8 + anymatch: 3.1.3 + bonjour-service: 1.2.1 + chokidar: 3.6.0 + colorette: 2.0.20 + compression: 1.7.4 + connect-history-api-fallback: 2.0.0 + express: 4.21.2 + graceful-fs: 4.2.11 + http-proxy-middleware: 2.0.9 + ipaddr.js: 2.1.0 + launch-editor: 2.9.1 + open: 10.1.0 + p-retry: 6.2.0 + schema-utils: 4.3.0 + selfsigned: 2.4.1 + serve-index: 1.9.1 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack: 5.98.0 + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + ws: 8.18.0 + 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 + dependencies: + webpack: 4.47.0 + dev: true + + /webpack-hot-middleware@2.26.1: + resolution: {integrity: sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==} + dependencies: + ansi-html-community: 0.0.8 + html-entities: 2.5.2 + strip-ansi: 6.0.1 + dev: true + + /webpack-log@2.0.0: + resolution: {integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==} + engines: {node: '>= 6'} + 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'} + dependencies: + clone-deep: 4.0.1 + wildcard: 2.0.1 + + /webpack-sources@1.4.3: + resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} + 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-virtual-modules@0.2.2: + resolution: {integrity: sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==} + dependencies: + debug: 3.2.7 + dev: true + + /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 + 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 + enhanced-resolve: 4.5.0 + eslint-scope: 4.0.3 + json-parse-better-errors: 1.0.2 + loader-runner: 2.4.0 + loader-utils: 1.4.2 + memory-fs: 0.4.1 + micromatch: 3.1.10 + mkdirp: 0.5.6 + neo-async: 2.6.2 + 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) + watchpack: 1.7.5 + webpack-sources: 1.4.3 + + /webpack@5.98.0: + resolution: {integrity: sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.0 + browserslist: 4.24.4 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.4.1 + 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 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.11(webpack@5.98.0) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + /websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + dependencies: + http-parser-js: 0.5.8 + 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 + + /whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + dependencies: + iconv-lite: 0.6.3 + + /whatwg-mimetype@2.3.0: + resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} + dev: true + + /whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + /whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + 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-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.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + /which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + dependencies: + 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.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.0.10 + 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.19 + + /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 + + /which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: true + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + /which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: true + + /widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + 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: + resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + + /wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: true + + /worker-farm@1.7.0: + resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==} + dependencies: + errno: 0.1.8 + + /worker-rpc@0.1.1: + resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==} + dependencies: + microevent.ts: 0.1.1 + dev: true + + /workerpool@6.2.1: + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /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 + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + /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==} + 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==} + 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 + + /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 + dev: false + + /write@1.0.3: + resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} + engines: {node: '>=4'} + dependencies: + mkdirp: 0.5.6 + dev: true + + /ws@6.2.2: + resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + 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@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.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 + + /xdg-basedir@4.0.0: + resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} + engines: {node: '>=8'} + + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + /xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.3.0 + xmlbuilder: 11.0.1 + dev: false + + /xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.3.0 + xmlbuilder: 11.0.1 + dev: true + + /xml@1.0.1: + resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} + dev: false + + /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==} + dependencies: + sax: 1.3.0 + dev: false + + /xstate@4.26.1: + resolution: {integrity: sha512-JLofAEnN26l/1vbODgsDa+Phqa61PwDlxWu8+2pK+YbXf+y9pQSDLRvcYH2H1kkeUBA5fGp+xFL/zfE8jNMw4g==} + dev: true + + /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'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + /yaml@2.4.1: + resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + engines: {node: '>= 14'} + hasBin: true + dev: false + + /yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + 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'} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: true + + /yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.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: 4.2.3 + 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'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + 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 + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + 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==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + /yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + dependencies: + buffer-crc32: 0.2.13 + dev: false + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + /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 + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.11.0 + optionalDependencies: + commander: 10.0.1 + + /zip-local@0.3.5: + resolution: {integrity: sha512-GRV3D5TJY+/PqyeRm5CYBs7xVrKTKzljBoEXvocZu0HJ7tPEcgpSOYa2zFIsCZWgKWMuc4U3yMFgFkERGFIB9w==} + 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'} + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 + dev: true + + /zod-to-json-schema@3.24.5(zod@3.24.3): + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + peerDependencies: + zod: ^3.24.1 + dependencies: + zod: 3.24.3 + dev: false + + /zod@3.24.3: + resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + dev: false + + /zwitch@1.0.5: + resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} + dev: true diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json new file mode 100644 index 00000000000..4dc7a555200 --- /dev/null +++ b/common/config/subspaces/default/repo-state.json @@ -0,0 +1,5 @@ +// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. +{ + "pnpmShrinkwrapHash": "5bb8825107066ff50f554daed7bc20aae550e573", + "preferredVersionsHash": "a9b67c38568259823f9cfb8270b31bf6d8470b27" +} diff --git a/common/docs/rfcs/images/4230/subspaces-figure-1.excalidraw.png b/common/docs/rfcs/images/4230/subspaces-figure-1.excalidraw.png new file mode 100644 index 00000000000..4ebcfd7c656 Binary files /dev/null and b/common/docs/rfcs/images/4230/subspaces-figure-1.excalidraw.png differ diff --git a/common/docs/rfcs/rfc-4230-rush-subspaces.md b/common/docs/rfcs/rfc-4230-rush-subspaces.md new file mode 100644 index 00000000000..8bb28775129 --- /dev/null +++ b/common/docs/rfcs/rfc-4230-rush-subspaces.md @@ -0,0 +1,242 @@ +# [RFC #4320](https://github.com/microsoft/rushstack/issues/4230): Rush Subspaces + +RFC maintainers: [@chengcyber](https://github.com/chengcyber), [@octogonz](https://github.com/octogonz) + +## Motivation + +The PNPM package manager provides a **workspace** feature that allows multiple projects to be managed as a group. The workspace is defined by `pnpm-workspace.yaml`, which in a Rush monorepo is generated from `rush.json`. That workspace has a **package lockfile** `pnpm-lock.yaml` that is essentially an installation plan, tracking the installed version of every dependency for your projects. + +## More than one lockfile + +When projects share a lockfile, the versions of NPM dependencies are centrally coordinated, which mostly involves choosing the right version numbers to avoid problems such as side-by-side versions, doppelgangers, and unsatisfied peer dependencies. For a crash course in these topics, see the [Lockfile Explorer docs](https://lfx.rushstack.io/). + +Centrally coordinating lockfiles brings some challenges: + +- **Consistency assumption:** In a healthy monorepo, most projects will use a consistent set of toolchains and versions, or at least a small number of such sets (perhaps one set of versions for experimental projects, one for stable projects, etc.). The `.pnpmfile.cjs` override rules can then mostly involve forcing projects to conform to one of those established sets. This assumption does not apply very well for projects whose dependencies wildly different from the rest of the monorepo, such as a project that was developed externally and then moved into the monorepo. + (This RFC was originally proposed by TikTok, whose monorepo has an abundance of such projects.) + +- **Collateral effects:** When someone updates a version and regenerates `pnpm-lock.yaml`, this may affect the version choices for shared dependencies being used by other unrelated projects. Those projects must then be tested, and fixed if a break occurs. (TikTok has many projects that rely primarily on manual testing, which is costly.) + +- **Git merge conflicts:** Git pull requests will encounter merge conflicts if multiple PRs have modified the same NPM dependencies in `pnpm-lock.yaml`. If the file is frequently churned, it can become a "mutex" that requires each PR to be built and merged one at a time, greatly reducing parallelization. + +- **Unrealistic library tests:** When publishing NPM packages for external consumption, it can be beneficial for a test project to use a real installation of the library project rather than relying on `workspace:*` linking. Using a real installation can reveal bugs such as incorrect `.npmignore` globs, that otherwise would not be discovered until after the release is published. (A prototype of this idea was implemented by the [install-test-workspace project](https://github.com/microsoft/rushstack/tree/main/build-tests/install-test-workspace) in the Rush Stack monorepo, discussed in [pnpm#3510](https://github.com/pnpm/pnpm/issues/3510).) + +All of the above problems can be reduced by breaking apart the single centrally coordinated file into multiple decoupled lockfiles; however, doing so creates new problems whose trouble increases according to the number of lockfiles. In the subsequent sections, we'll be contrasting 3 different models: + +1. **1 lockfile:** the established convention for PNPM workspaces +2. **700+ lockfiles:** our current "split workspace" fork of Rush, roughly one lockfile per project +3. **20 lockfiles:** this new "subspaces" proposal, roughly one lockfile per team + +## Current situation: A split workspace + +PNPM supports a feature called **split workspace** enabled via the `.npmrc` setting [shared-workspace-lockfile=false](https://pnpm.io/npmrc#shared-workspace-lockfile). With this model, every project gets its own `pnpm-lock.yaml` file, and `workspace:*` dependencies are installed as symlinks pointing to the corresponding library project folder. Such links are equivalent to what `npm link` would create, and therefore do not correctly satisfy `package.json` dependencies. For that reason PNPM has deprecated this feature. Nonetheless, TikTok has been using it privately via a forked version of Rush tracked by [Rush Stack PR #3481 (split workspace)](https://github.com/microsoft/rushstack/pull/3481). Our fork adapts Rush to support multiple lockfiles while also preserving the usual "common" lockfile, with the goal that over time split lockfiles would be eliminated by eventually migrating all projects into the common lockfile. + +> Note that with the "split workspace" feature there is still only one `pnpm-workspace.yaml` file, so this terminology is a bit misleading -- the lockfile is being split, not the workspace file. + +The split workspace feature has two major drawbacks: + +1. **Not scalable:** We currently have over 700 split lockfiles. Because each lockfile gets installed separately, our total install time is approximately 700x slower than a conventional single-lockfile monorepo. This cost is somewhat hidden in our setup because each CI pipeline only installs a small subset of lockfiles, distributed across hundreds of VMs, one for each pipeline. But even if the runtime cost is acceptable, consuming so many VM resources is not financially acceptable. + +2. **Incorrect installation model:** As mentioned, this installation does not correctly satisfy `package.json` version requirements. For example, if `my-app` depends on `react@16.0.0` and `my-library` also depends on `react@16.0.0`, two distinct copies of `react` will be installed in the `node_modules` folder, which we call a **split workspace doppelganger.** This happens because each `pnpm-lock.yaml` is processed essentially as an independent installation. Attempts to fix this problem are equivalent to reverting to a centralized lockfile. + +For these reasons, the Rush maintainers have been reluctant to accept **PR #3481** as an official feature. + +## Subspaces (formerly "injected workspaces") + +Let's propose a new feature called **subspaces** that divides the workspace into named groups of projects. (In earlier discussions, we called this same feature "injected workspaces.") Each project belongs to exactly one subspace, and each subspace has one lockfile and associated configuration such as `.pnpmfile.cjs`, `common-versions.json`, etc. This can solve both of the problems identified above: + +1. **Scalable:** Whereas the split workspace feature introduced one lockfile for every project, subspaces allow splitting conservatively, according to meaningful purposes. For example, we might define one subspace for "bleeding edge projects," one for "testing libraries," and one for "everything else." Or perhaps one subspace per team. A large monrepo could have 20 subspaces but not 700+. + +2. **Correct installation model:** When projects belong to separate lockfiles, instead of treating `workspace:*` as a blind `npm link` into a separate universe of versions, subspaces will instead perform an "injected" install. This terminology comes from PNPM's [injected: true](https://pnpm.io/package_json#dependenciesmetainjected) feature. It simulates what would happen if the library project was first published to an NPM registry (for example [Verdaccio](https://verdaccio.org/) on `localhost`) and then installed normally by the dependent project. Rush's `install-test-workspace` project achieves the same result by running `pnpm pack` in the library folder to produce a tarball, then using `.pnpmfile.cjs` to replace `workspace:*` with a `file:` reference to that tarball. + +### Observation #1: We need a postbuild event + +Whichever way that injected installs are implemented, an important consequence is that the library project gets copied instead of symlinked into the consumer's `node_modules` folder. This fundamentally changes the developer workflow: + +A conventional workflow only needs to perform `rush install` once: + +```bash +# 1. this will link my-app/node_modules/my-lib --> libraries/my-lib +rush install + +# 2. Make some changes to my-lib, which is a dependency of my-app + +# 3. Rebuild my-lib and my-app +rush build --to my-app + +# 4. everything is now good, repeat from step 2 +``` + +Whenever `my-lib` is modified and rebuilt, `my-app` automatically reflects those changes, because `my-app/node_modules/my-lib` is a symlink pointing to the build outputs. By contrast, with an injected install, step #1 makes a copy of `libraries/my-lib`, which does not update automatically. In step #3 we must redo this copy, and copying must occur AFTER `my-lib` is built, but BEFORE `my-app` is built. + +How to accomplish that? It implies a new project lifecycle event such as **postbuild** (for `my-lib`) or **prebuild** (for `my-app`). + +- **prebuild challenges:** If each project syncs its injected folders before building, then the main problem is change detection. "Building" could mean any operation in that folder, for example any `npm run do-something` command, and such commands can be chained together. Efficient filesystem change detection is very difficult without a live process such as [chokidar](https://www.npmjs.com/package/chokidar) or [watchman](https://facebook.github.io/watchman/), and every such project needs this logic. With PNPM symlinking, two different projects may have an injected `node_modules` subfolder that ends up symlinking to the same final target; in this case, a mutex may be required to prevent two concurrent **prebuild** actions from overwriting each other's outputs. + +- **postbuild challenges:** On the other hand, if the library itself updates all of its injected copies after building, then watching is not necessary; it's relatively easy to know when the library has finished building. The mutex problem is also simpler, or avoided entirely if we don't allow concurrent builds in the same folder. The main challenge is registering/unregistering the folders to be updated, since in theory any PNPM workspace could introduce a new injected install relationship, or the project folder might get moved, or abandoned but left on disk. + +Our proposal chooses the "postbuild" approach because it seems to be easier to implement and more efficient for Rush's use case, but perhaps ultimately both approaches can be supported. + +This is a nontrivial change: PNPM's "injected" feature is not widely used today, for the exact reason that it provides no event for updating the injected copies, and thus is only practical for non-built projects such as plain .js source files without any transformations. The PNPM maintainers perhaps hesitated to introduce such an event as it is unconventional and may break assumptions of existing tools. Rush monorepos are in a better position to adopt such a model, given to our focus on centrally managed monorepos with a more formalized structure. + +### Observation #2: Subspace topology is surprisingly flexible + +Consider the following diagram: + + + +NPM package dependencies must form a directed graph without cycles, and this determines build order. This suggests that our lockfiles should also avoid cycles: for example, if `S1` depends on `S2` via `A->B` then perhaps we should not allow `S2` to depend on `S1` via `C->D`. Surprisingly, it turns out that this constraint is unnecessary. Injected dependencies are installed as if the tarball was fetched from an NPM registry, and recall that NPM registries store `package.json` files but not lockfiles. In this way each subspace lockfile is essentially a self-contained installation plan that gets generated based on the `package.json` file of the library project, but without ever consulting the other lockfile. Thus, the above diagram poses no problems. The project build order must of course still follow the directed acyclic graph, with the "postbuild" event copying the package contents. + +### Observation #3: Which dependencies to inject? + +In PNPM's implementation, there is only one lockfile, and `injected: true` is manually configured in `package.json` for specific dependency package names. How should an engineer know when to enable this setting? In other words, when should a `workspace:*` dependency get installed via injecting instead of folder symlinking? + +As a clue to this problem, recall that PNPM's installation model has a longstanding limitation that `workspace:*` dependencies do not correctly satisfy peer dependencies, because peer dependencies are satisfied by making copies of the package folder (**peer doppelgangers**). In practice this can usually be mitigated for example by enforcing consistent versions across the monorepo, or by using Webpack aliases to override module resolution, but these mitigations are hacks. The `injected: true` feature originally arose as a correct solution. + +Here is the complete list of cases where injected copying is required (assuming we are unwilling to mitigate the problem in some other way): + +1. If a local project depends on another local project via `workspace:*` and needs to satisfy a peer dependency (including implicit peer dependencies resulting from transitive dependencies) +2. In our new subspaces proposal, injecting is required wherever a `workspace:*` dependency refers to a project in a separate subspace +3. Even if it is not theoretically required, injecting can be enabled manually for more accurate testing of published libraries (the `install-test-workspace` scenario mentioned earlier) + +Note that cases #1 and #2 could be automatically inferred -- we don't really need to require engineers to manually configure an `injected: true` setting. In fact it would not be theoretically incorrect to always inject every dependency, except that in practice copying is significantly more expensive than symlinking, and of course it also requires our unconventional "postbuild" lifecycle event. + +### Observation #4: Two entirely independent features + +Thinking more deeply about that last point, we are proposing two entirely separate features: + +1. Multiple lockfiles which are defined using subspaces +2. Injected installation with a "postbuild" lifecycle event to that updates the folder copies under `node_modules` + +Each feature could be used by itself: + +- **#1 without #2:** Subspaces could be used without injected installation, instead handling `workspace:*` by creating simple symlinks as was done with the split workspace feature. This is undesirable because it produces an incorrect solution. But we should implement it, since it will help with migrating from a split workspace, by allowing split lockfiles to be replaced by equivalent subspaces. +- **#2 without #1:** Injected installation could be used without subspaces, as exemplified by PNPM's `injected: true` feature. We should support this in the final design, however doing so probably requires designing config files and policies to manage such settings in a large scale problem domain. In order to postpone that work, for our initial implementation we will make a simplifying assumption: + +_**Initial implementation:** A dependency will be injected if-and-only-if it is a `workspace:*` reference that refers to a project external to the lockfile/subspace that is being installed._ + +## Design Details + +### Configuring subspaces + +Subspaces will be enabled using a new config file `common/config/rush/subspaces.json`, whose format will be: + +**common/config/rush/subspaces.json** + +```js +{ + "useSubspaces": true, + + // Names must be lowercase and separated by dashes. + // To avoid mistakes, common/config/subspaces/ subfolder + // cannot be used unless its name appears in this array. + "subspaceNames": [ "default", "react19", "install-test" ] +} +``` + +The lockfile and associated config files for each subspace will be `common/config/subspaces` folder: + +``` +common/config/subspaces//pnpm-lock.yaml +common/config/subspaces//.pnpmfile.cjs +common/config/subspaces//.npmrc +common/config/subspaces//common-versions.json +``` + +Subspaces will also allow for a global configuration file for npmrc settings to apply for all subspaces. This global configuration file will be located in the common rush directory: `common/config/rush/.npmrc-global` + +As noted in the [PR #3481 discussion](https://github.com/microsoft/rushstack/pull/3481#discussion_r901277915), Rush's current strategy of installing directly into `common/temp` makes it difficult to introduce additional PNPM installations without phantom dependency folders. To address this problem, when `useSubspaces=true`, the top-level `common/temp/node_modules` folder will not be created at all. Instead, lockfiles will get installed to subfolders with the naming pattern `common/temp/subspaces//`. + +Rush projects will be mapped to a subspace using a new project-specific field in rush.json: + +**rush.json** + +```js +"projects": [ + "my-project": { + "packageName": "@acme/my-project", + "projectFolder": "apps/my-project", + "subspace": "react18" + } +] +``` + +If the `"subspaceNames"` array in **subspaces.json** includes the name `"default"`, then the `"subspace"` field can be omitted for **rush.json** projects; in that case the project will be mapped to the default subspace. + +### The pnpm-sync command + +We propose to introduce a new command line tool called `pnpm-sync` that should be invoked for any library projects that have been installed as an injected dependency. Doing so updates the installed copies of this library's outputs. This command should be invoked whenever the library project has been rebuilt in any way, at the end of that operation, and before building any dependent projects. The command is so-named because we eventually hope to contribute it back to the PNPM project as a package manager feature, rather than making it a Rush-specific tool. + +In a vanilla PNPM workspace, we could introduce `"postbuild"` as an actual [NPM lifecycle event](https://docs.npmjs.com/cli/v6/using-npm/scripts) to invoke `pnpm-sync`: + +**package.json** + +```js +{ + "name": "my-library", + "version": "1.0.0", + "scripts": { + "build": "heft build --clean", + "postbuild": "pnpm-sync" + } + . . . +``` + +In a Rush monorepo, it is probably better invoked via a dedicated [Rush phase](https://rushjs.io/pages/maintainer/phased_builds/). + +The `pnpm-sync` command will perform the following operations: + +1. Look for a machine-generated file `/node_modules/.pnpm-sync.json` which contains an inventory of injected folders to be updated. In our initial implementation, this file will get generated by `rush install` or `rush update`. Later, `pnpm install` will manage it natively. +2. Calculate the list of files to be copied, using the same logic as `pnpm pack` which consults the [.npmignore](https://docs.npmjs.com/cli/v7/using-npm/developers#keeping-files-out-of-your-package) file and/or `files` field of **package.json**. +3. Copy those files into each target folder. + +Here's a suggested format for `.pnpm-sync.json`: + +**<project-folder>/node_modules/.pnpm-sync.json** + +```js +{ + "postbuildInjectedCopy": { + /** + * The project folder to be copied, relative to the folder containing ".pnpm-sync.json". + * The "pnpm-sync" command will look for package.json and .npmignore in this folder + * and apply the same filtering as "pnpm pack". + */ + "sourceFolder": "../..", + + "targetFolders": [ + { + /** + * The target path containing an injected copy that "pnpm-sync" should update. + * This path is relative to the folder containing pnpm-sync.json, and typically + * should point into the physical ".pnpm" subfolder for a given PNPM lockfile. + */ + "folderPath": "../../node_modules/.pnpm/file+..+shared+my-library/node_modules/my-library" + }, + { + // Here's an example for a hypothetical peer doppelganger of our "my-library" + "folderPath": "../../node_modules/.pnpm/file+..+shared+my-library_react@16.14.0/node_modules/my-library" + } + ] + } +} +``` + +### rush-inject-workspace-prototype repository + +[@chengcyber](https://github.com/chengcyber) has created this repository to help with studying `pnpm-sync` folder structures: + +https://github.com/chengcyber/rush-inject-workspace-prototype + +It illustrates how two PNPM workspaces could be configured to automatically perform injection for cross-space dependencies, by using `.pnpmfile.cjs` to automatically rewrite `workspace:*` to links to `file:` links, similar to the approach of his **PR #3481**. It also illustrates how this might be adapted to a Rush feature. He found that PNPM 6 has different handling of `file:` from later versions of PNPM. + +## Interaction with other Rush features + +Our experience with [Rush Stack PR #3481 (split workspace)](https://github.com/microsoft/rushstack/pull/3481) found that operational changes to `pnpm install` have relatively little impact on other Rush features. For example: + +- The `rush build` cache works with **PR #3481** and correctly calculates cache keys based on `node_modules` dependencies. +- `rush publish` does some rewriting of `workspace:*` dependencies, but he heuristic that it uses does not seem to assume that the referenced project is really in the same **pnpm-workspace.yaml** file. +- `rush deploy` should work essentially the with injected installations for subspaces, since the underlying [@rushstack/package-extractor](https://github.com/microsoft/rushstack/tree/main/libraries/package-extractor) engine is driven by Node.js module resolution, and is largely independent of how those `node_modules` folders or symlinks were created. +- **PR #3481** integrated with Rush [project selectors](https://rushjs.io/pages/developer/selecting_subsets/), for example `rush list --only split:true`. For subspaces, we can implement something similar, for example `rush list --only space:my-subspace-name`. + +**PR #3481** did not attempt to apply Rush policies to projects with split lockfile; policies only applied to the so-called "common" lockfile. Generalizing these policies across subspaces will be nontrivial work, so we've proposed to implement that as a secondary stage of work. diff --git a/common/git-hooks/commit-msg.sample b/common/git-hooks/commit-msg.sample new file mode 100644 index 00000000000..59cacb80ca1 --- /dev/null +++ b/common/git-hooks/commit-msg.sample @@ -0,0 +1,25 @@ +#!/bin/sh +# +# This is an example Git hook for use with Rush. To enable this hook, rename this file +# to "commit-msg" and then run "rush install", which will copy it from common/git-hooks +# to the .git/hooks folder. +# +# TO LEARN MORE ABOUT GIT HOOKS +# +# The Git documentation is here: https://git-scm.com/docs/githooks +# Some helpful resources: https://githooks.com +# +# ABOUT THIS EXAMPLE +# +# The commit-msg hook is called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero status after issuing +# an appropriate message if it wants to stop the commit. The hook is allowed to edit +# the commit message file. + +# This example enforces that commit message should contain a minimum amount of +# description text. +if [ `cat $1 | wc -w` -lt 3 ]; then + echo "" + echo "Invalid commit message: The message must contain at least 3 words." + exit 1 +fi diff --git a/common/git-hooks/pre-commit b/common/git-hooks/pre-commit new file mode 100755 index 00000000000..ecda2ba7104 --- /dev/null +++ b/common/git-hooks/pre-commit @@ -0,0 +1,9 @@ +#!/bin/sh +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. + +# Invoke the "rush prettier" custom command to reformat files whenever they +# are committed. The command is defined in common/config/rush/command-line.json +# and uses the "rush-prettier" autoinstaller. +node common/scripts/install-run-rush.js prettier || exit $? diff --git a/common/reviews/api/api-documenter.api.md b/common/reviews/api/api-documenter.api.md index 959e460bf32..83a4d498dae 100644 --- a/common/reviews/api/api-documenter.api.md +++ b/common/reviews/api/api-documenter.api.md @@ -4,8 +4,8 @@ ```ts -import { ApiItem } from '@microsoft/api-extractor-model'; -import { ApiModel } from '@microsoft/api-extractor-model'; +import type { ApiItem } from '@microsoft/api-extractor-model'; +import type { ApiModel } from '@microsoft/api-extractor-model'; // @public export interface IApiDocumenterPluginManifest { @@ -36,14 +36,16 @@ export interface IMarkdownDocumenterFeatureOnFinishedArgs { // @public export class MarkdownDocumenterAccessor { // Warning: (ae-forgotten-export) The symbol "IMarkdownDocumenterAccessorImplementation" needs to be exported by the entry point index.d.ts - // + // // @internal constructor(implementation: IMarkdownDocumenterAccessorImplementation); getLinkForApiItem(apiItem: ApiItem): string | undefined; - } +} // @public export class MarkdownDocumenterFeature extends PluginFeature { + // (undocumented) + static [Symbol.hasInstance](instance: object): boolean; context: MarkdownDocumenterFeatureContext; // @virtual onBeforeWritePage(eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs): void; @@ -62,6 +64,8 @@ export class MarkdownDocumenterFeatureContext { // @public export abstract class PluginFeature { + // (undocumented) + static [Symbol.hasInstance](instance: object): boolean; // @internal constructor(initialization: PluginFeatureInitialization); context: PluginFeatureContext; @@ -81,5 +85,4 @@ export class PluginFeatureInitialization { _context: PluginFeatureContext; } - ``` diff --git a/common/reviews/api/api-extractor-model.api.md b/common/reviews/api/api-extractor-model.api.md index 8461e54ee25..dd3f5dab530 100644 --- a/common/reviews/api/api-extractor-model.api.md +++ b/common/reviews/api/api-extractor-model.api.md @@ -4,16 +4,17 @@ ```ts -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; +import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { DocDeclarationReference } from '@microsoft/tsdoc'; import { IJsonFileSaveOptions } from '@rushstack/node-core-library'; +import { JsonObject } from '@rushstack/node-core-library'; import * as tsdoc from '@microsoft/tsdoc'; import { TSDocConfiguration } from '@microsoft/tsdoc'; import { TSDocTagDefinition } from '@microsoft/tsdoc'; // Warning: (ae-internal-missing-underscore) The name "AedocDefinitions" should be prefixed with an underscore because the declaration is marked as @internal // -// @internal (undocumented) +// @internal @deprecated (undocumented) export class AedocDefinitions { // (undocumented) static readonly betaDocumentation: TSDocTagDefinition; @@ -22,8 +23,25 @@ export class AedocDefinitions { // (undocumented) static readonly preapprovedTag: TSDocTagDefinition; // (undocumented) - static readonly tsdocConfiguration: TSDocConfiguration; - } + static get tsdocConfiguration(): TSDocConfiguration; +} + +// @public +export function ApiAbstractMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiAbstractMixin); + +// @public +export interface ApiAbstractMixin extends ApiItem { + readonly isAbstract: boolean; + // Warning: (ae-forgotten-export) The symbol "IApiItemJson" needs to be exported by the entry point index.d.ts + // + // (undocumented) + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiAbstractMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiAbstractMixin; +} // Warning: (ae-forgotten-export) The symbol "ApiCallSignature_base" needs to be exported by the entry point index.d.ts // @@ -33,11 +51,11 @@ export class ApiCallSignature extends ApiCallSignature_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiClass_base" needs to be exported by the entry point index.d.ts @@ -48,13 +66,13 @@ export class ApiClass extends ApiClass_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; readonly extendsType: HeritageType | undefined; // (undocumented) static getContainerKey(name: string): string; - readonly implementsTypes: ReadonlyArray; + get implementsTypes(): ReadonlyArray; // @override (undocumented) - readonly kind: ApiItemKind; + 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 // @@ -72,11 +90,11 @@ export class ApiConstructor extends ApiConstructor_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiConstructSignature_base" needs to be exported by the entry point index.d.ts @@ -87,19 +105,20 @@ export class ApiConstructSignature extends ApiConstructSignature_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // @public export class ApiDeclaredItem extends ApiDocumentedItem { constructor(options: IApiDeclaredItemOptions); buildExcerpt(tokenRange: IExcerptTokenRange): Excerpt; - readonly excerpt: Excerpt; - readonly excerptTokens: ReadonlyArray; + get excerpt(): Excerpt; + get excerptTokens(): ReadonlyArray; + get fileUrlPath(): string | undefined; getExcerptWithModifiers(): string; // Warning: (ae-forgotten-export) The symbol "IApiDeclaredItemJson" needs to be exported by the entry point index.d.ts // @@ -107,13 +126,12 @@ export class ApiDeclaredItem extends ApiDocumentedItem { static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiDeclaredItemJson): void; // @override (undocumented) serializeInto(jsonObject: Partial): void; + get sourceLocation(): SourceLocation; } // @public export class ApiDocumentedItem extends ApiItem { constructor(options: IApiDocumentedItemOptions); - // Warning: (ae-forgotten-export) The symbol "IApiItemJson" needs to be exported by the entry point index.d.ts - // // @override (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 @@ -121,8 +139,8 @@ export class ApiDocumentedItem extends ApiItem { // @override (undocumented) serializeInto(jsonObject: Partial): void; // (undocumented) - readonly tsdocComment: tsdoc.DocComment | undefined; - } + get tsdocComment(): tsdoc.DocComment | undefined; +} // Warning: (ae-forgotten-export) The symbol "ApiEntryPoint_base" needs to be exported by the entry point index.d.ts // @@ -132,10 +150,10 @@ export class ApiEntryPoint extends ApiEntryPoint_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; - readonly importPath: string; + get containerKey(): string; + get importPath(): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiEnum_base" needs to be exported by the entry point index.d.ts @@ -148,13 +166,13 @@ export class ApiEnum extends ApiEnum_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // @override (undocumented) - readonly members: ReadonlyArray; + get members(): ReadonlyArray; } // Warning: (ae-forgotten-export) The symbol "ApiEnumMember_base" needs to be exported by the entry point index.d.ts @@ -165,18 +183,26 @@ export class ApiEnumMember extends ApiEnumMember_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - readonly initializerExcerpt: Excerpt; // @override (undocumented) - readonly kind: ApiItemKind; - // Warning: (ae-forgotten-export) The symbol "IApiEnumMemberJson" needs to be exported by the entry point index.d.ts - // - // @override (undocumented) - static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiEnumMemberJson): void; + get kind(): ApiItemKind; +} + +// @public +export function ApiExportedMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiExportedMixin); + +// @public +export interface ApiExportedMixin extends ApiItem { + readonly isExported: boolean; // @override (undocumented) - serializeInto(jsonObject: Partial): void; + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiExportedMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiExportedMixin; } // Warning: (ae-forgotten-export) The symbol "ApiFunction_base" needs to be exported by the entry point index.d.ts @@ -187,11 +213,11 @@ export class ApiFunction extends ApiFunction_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string, overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiIndexSignature_base" needs to be exported by the entry point index.d.ts @@ -202,11 +228,28 @@ export class ApiIndexSignature extends ApiIndexSignature_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; +} + +// @public +export function ApiInitializerMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiInitializerMixin); + +// @public +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) + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiInitializerMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiInitializerMixin; } // Warning: (ae-forgotten-export) The symbol "ApiInterface_base" needs to be exported by the entry point index.d.ts @@ -217,12 +260,12 @@ export class ApiInterface extends ApiInterface_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; - readonly extendsTypes: ReadonlyArray; + get containerKey(): string; + get extendsTypes(): ReadonlyArray; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiInterfaceJson" needs to be exported by the entry point index.d.ts // // @override (undocumented) @@ -239,27 +282,28 @@ export class ApiItem { // @virtual protected buildCanonicalReference(): DeclarationReference; // @beta - readonly canonicalReference: DeclarationReference; + get canonicalReference(): DeclarationReference; // @virtual - readonly containerKey: string; + get containerKey(): string; // (undocumented) static deserialize(jsonObject: IApiItemJson, context: DeserializerContext): ApiItem; // @virtual - readonly displayName: string; + get displayName(): string; + getAssociatedModel(): ApiModel | undefined; getAssociatedPackage(): ApiPackage | undefined; getHierarchy(): ReadonlyArray; getMergedSiblings(): ReadonlyArray; getScopedNameWithinPackage(): string; - // @virtual (undocumented) + // @virtual getSortKey(): string; // @virtual - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // @virtual - readonly members: ReadonlyArray; + get members(): ReadonlyArray; // @virtual (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiItemJson): void; // @virtual - readonly parent: ApiItem | undefined; + get parent(): ApiItem | undefined; // @virtual (undocumented) serializeInto(jsonObject: Partial): void; } @@ -271,9 +315,10 @@ export function ApiItemContainerMixin(ba export interface ApiItemContainerMixin extends ApiItem { addMember(member: ApiItem): void; findMembersByName(name: string): ReadonlyArray; + findMembersWithInheritance(): IFindApiItemsResult; // @internal _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray; - readonly members: ReadonlyArray; + readonly preserveMemberOrder: boolean; // @override (undocumented) serializeInto(jsonObject: Partial): void; tryGetMemberByKey(containerKey: string): ApiItem | undefined; @@ -285,7 +330,7 @@ export namespace ApiItemContainerMixin { } // @public -export const enum ApiItemKind { +export enum ApiItemKind { // (undocumented) CallSignature = "CallSignature", // (undocumented) @@ -336,11 +381,11 @@ export class ApiMethod extends ApiMethod_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string, isStatic: boolean, overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiMethodSignature_base" needs to be exported by the entry point index.d.ts @@ -351,11 +396,11 @@ export class ApiMethodSignature extends ApiMethodSignature_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string, overloadIndex: number): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiModel_base" needs to be exported by the entry point index.d.ts @@ -368,15 +413,15 @@ export class ApiModel extends ApiModel_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // (undocumented) loadPackage(apiJsonFilename: string): ApiPackage; // (undocumented) - readonly packages: ReadonlyArray; + get packages(): ReadonlyArray; // (undocumented) - resolveDeclarationReference(declarationReference: DocDeclarationReference, contextApiItem: ApiItem | undefined): IResolveDeclarationReferenceResult; + resolveDeclarationReference(declarationReference: DocDeclarationReference | DeclarationReference, contextApiItem: ApiItem | undefined): IResolveDeclarationReferenceResult; tryGetPackageByName(packageName: string): ApiPackage | undefined; } @@ -403,11 +448,26 @@ export class ApiNamespace extends ApiNamespace_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; +} + +// @public +export function ApiOptionalMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiOptionalMixin); + +// @public +export interface ApiOptionalMixin extends ApiItem { + readonly isOptional: boolean; + // @override (undocumented) + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiOptionalMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiOptionalMixin; } // Warning: (ae-forgotten-export) The symbol "ApiPackage_base" needs to be exported by the entry point index.d.ts @@ -420,17 +480,24 @@ export class ApiPackage extends ApiPackage_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) - readonly entryPoints: ReadonlyArray; + get entryPoints(): ReadonlyArray; // (undocumented) findEntryPointsByPath(importPath: string): ReadonlyArray; // @override (undocumented) - readonly kind: ApiItemKind; + 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) + static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiPackageJson): void; + // (undocumented) + get projectFolderUrl(): string | undefined; // (undocumented) saveToJsonFile(apiJsonFilename: string, options?: IApiPackageSaveOptions): void; + get tsdocConfiguration(): TSDocConfiguration; } // @public @@ -457,11 +524,11 @@ export class ApiProperty extends ApiProperty_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string, isStatic: boolean): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; } // Warning: (ae-forgotten-export) The symbol "ApiPropertyItem_base" needs to be exported by the entry point index.d.ts @@ -469,7 +536,7 @@ export class ApiProperty extends ApiProperty_base { // @public export class ApiPropertyItem extends ApiPropertyItem_base { constructor(options: IApiPropertyItemOptions); - readonly isEventProperty: boolean; + get isEventProperty(): boolean; // Warning: (ae-forgotten-export) The symbol "IApiPropertyItemJson" needs to be exported by the entry point index.d.ts // // @override (undocumented) @@ -485,11 +552,41 @@ export class ApiPropertySignature extends ApiPropertyItem { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; +} + +// @public +export function ApiProtectedMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiProtectedMixin); + +// @public +export interface ApiProtectedMixin extends ApiItem { + readonly isProtected: boolean; + // @override (undocumented) + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiProtectedMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiProtectedMixin; +} + +// @public +export function ApiReadonlyMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiReadonlyMixin); + +// @public +export interface ApiReadonlyMixin extends ApiItem { + readonly isReadonly: boolean; + // (undocumented) + serializeInto(jsonObject: Partial): void; +} + +// @public +export namespace ApiReadonlyMixin { + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReadonlyMixin; } // @public @@ -547,11 +644,11 @@ export class ApiTypeAlias extends ApiTypeAlias_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiTypeAliasJson" needs to be exported by the entry point index.d.ts // // @override (undocumented) @@ -584,11 +681,11 @@ export class ApiVariable extends ApiVariable_base { // @beta @override (undocumented) buildCanonicalReference(): DeclarationReference; // @override (undocumented) - readonly containerKey: string; + get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; // @override (undocumented) - readonly kind: ApiItemKind; + get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiVariableJson" needs to be exported by the entry point index.d.ts // // @override (undocumented) @@ -601,48 +698,62 @@ export class ApiVariable extends ApiVariable_base { // @public export type Constructor = new (...args: any[]) => T; +// @public +export enum EnumMemberOrder { + ByName = "by-name", + Preserve = "preserve" +} + // @public export class Excerpt { constructor(tokens: ReadonlyArray, tokenRange: IExcerptTokenRange); - // (undocumented) - readonly isEmpty: boolean; - // (undocumented) - readonly text: string; - // (undocumented) + get isEmpty(): boolean; + readonly spannedTokens: ReadonlyArray; + get text(): string; readonly tokenRange: Readonly; - // (undocumented) readonly tokens: ReadonlyArray; } -// @public (undocumented) +// @public export class ExcerptToken { constructor(kind: ExcerptTokenKind, text: string, canonicalReference?: DeclarationReference); - // (undocumented) - readonly canonicalReference: DeclarationReference | undefined; - // (undocumented) - readonly kind: ExcerptTokenKind; - // (undocumented) - readonly text: string; - } + get canonicalReference(): DeclarationReference | undefined; + get kind(): ExcerptTokenKind; + get text(): string; +} // @public (undocumented) -export const enum ExcerptTokenKind { +export enum ExcerptTokenKind { Content = "Content", Reference = "Reference" } +// @public +export enum FindApiItemsMessageId { + DeclarationResolutionFailed = "declaration-resolution-failed", + ExtendsClauseMissingReference = "extends-clause-missing-reference", + NoAssociatedApiModel = "no-associated-api-model", + UnsupportedKind = "unsupported-kind" +} + // @public export class HeritageType { constructor(excerpt: Excerpt); readonly excerpt: Excerpt; } +// @public +export interface IApiAbstractMixinOptions extends IApiItemOptions { + // (undocumented) + isAbstract: boolean; +} + // @public export interface IApiCallSignatureOptions extends IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiDeclaredItemOptions { } // @public -export interface IApiClassOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiTypeParameterListMixinOptions { +export interface IApiClassOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiAbstractMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiTypeParameterListMixinOptions, IApiExportedMixinOptions { // (undocumented) extendsTokenRange: IExcerptTokenRange | undefined; // (undocumented) @@ -650,7 +761,7 @@ export interface IApiClassOptions extends IApiItemContainerMixinOptions, IApiNam } // @public -export interface IApiConstructorOptions extends IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiConstructorOptions extends IApiParameterListMixinOptions, IApiProtectedMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { } // @public @@ -661,6 +772,8 @@ export interface IApiConstructSignatureOptions extends IApiTypeParameterListMixi export interface IApiDeclaredItemOptions extends IApiDocumentedItemOptions { // (undocumented) excerptTokens: IExcerptToken[]; + // (undocumented) + fileUrlPath?: string; } // @public @@ -674,25 +787,35 @@ export interface IApiEntryPointOptions extends IApiItemContainerMixinOptions, IA } // @public -export interface IApiEnumMemberOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiEnumMemberOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiInitializerMixinOptions { +} + +// @public +export interface IApiEnumOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiExportedMixinOptions { +} + +// @public +export interface IApiExportedMixinOptions extends IApiItemOptions { // (undocumented) - initializerTokenRange: IExcerptTokenRange; + isExported: boolean; } // @public -export interface IApiEnumOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiFunctionOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiDeclaredItemOptions, IApiExportedMixinOptions { } // @public -export interface IApiFunctionOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiDeclaredItemOptions { +export interface IApiIndexSignatureOptions extends IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiReadonlyMixinOptions, IApiDeclaredItemOptions { } // @public -export interface IApiIndexSignatureOptions extends IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiDeclaredItemOptions { +export interface IApiInitializerMixinOptions extends IApiItemOptions { + // (undocumented) + initializerTokenRange?: IExcerptTokenRange; } // @public -export interface IApiInterfaceOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiInterfaceOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiExportedMixinOptions { // (undocumented) extendsTokenRanges: IExcerptTokenRange[]; } @@ -705,6 +828,8 @@ export interface IApiItemConstructor extends Constructor, PropertiesOf< export interface IApiItemContainerMixinOptions extends IApiItemOptions { // (undocumented) members?: ApiItem[]; + // (undocumented) + preserveMemberOrder?: boolean; } // @public @@ -712,11 +837,11 @@ export interface IApiItemOptions { } // @public -export interface IApiMethodOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiStaticMixinOptions, IApiDeclaredItemOptions { +export interface IApiMethodOptions extends IApiNameMixinOptions, IApiAbstractMixinOptions, IApiOptionalMixinOptions, IApiParameterListMixinOptions, IApiProtectedMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiStaticMixinOptions, IApiTypeParameterListMixinOptions, IApiDeclaredItemOptions { } // @public (undocumented) -export interface IApiMethodSignatureOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiDeclaredItemOptions { +export interface IApiMethodSignatureOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiOptionalMixinOptions, IApiDeclaredItemOptions { } // @public @@ -726,11 +851,21 @@ export interface IApiNameMixinOptions extends IApiItemOptions { } // @public -export interface IApiNamespaceOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiNamespaceOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiExportedMixinOptions { +} + +// @public +export interface IApiOptionalMixinOptions extends IApiItemOptions { + // (undocumented) + isOptional: boolean; } // @public export interface IApiPackageOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiDocumentedItemOptions { + // (undocumented) + projectFolderUrl?: string; + // (undocumented) + tsdocConfiguration: TSDocConfiguration; } // @public @@ -750,6 +885,8 @@ export interface IApiParameterListMixinOptions extends IApiItemOptions { // @public export interface IApiParameterOptions { + // (undocumented) + isOptional: boolean; // (undocumented) parameterName: string; // (undocumented) @@ -757,19 +894,31 @@ export interface IApiParameterOptions { } // @public -export interface IApiPropertyItemOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiPropertyItemOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiOptionalMixinOptions, IApiReadonlyMixinOptions, IApiDeclaredItemOptions { // (undocumented) propertyTypeTokenRange: IExcerptTokenRange; } // @public -export interface IApiPropertyOptions extends IApiPropertyItemOptions, IApiStaticMixinOptions { +export interface IApiPropertyOptions extends IApiPropertyItemOptions, IApiAbstractMixinOptions, IApiProtectedMixinOptions, IApiStaticMixinOptions, IApiInitializerMixinOptions { } // @public export interface IApiPropertySignatureOptions extends IApiPropertyItemOptions { } +// @public +export interface IApiProtectedMixinOptions extends IApiItemOptions { + // (undocumented) + isProtected: boolean; +} + +// @public +export interface IApiReadonlyMixinOptions extends IApiItemOptions { + // (undocumented) + isReadonly: boolean; +} + // @public export interface IApiReleaseTagMixinOptions extends IApiItemOptions { // (undocumented) @@ -789,7 +938,7 @@ export interface IApiStaticMixinOptions extends IApiItemOptions { } // @public -export interface IApiTypeAliasOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiTypeParameterListMixinOptions { +export interface IApiTypeAliasOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiTypeParameterListMixinOptions, IApiExportedMixinOptions { // (undocumented) typeTokenRange: IExcerptTokenRange; } @@ -811,7 +960,7 @@ export interface IApiTypeParameterOptions { } // @public -export interface IApiVariableOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions { +export interface IApiVariableOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiReadonlyMixinOptions, IApiDeclaredItemOptions, IApiInitializerMixinOptions, IApiExportedMixinOptions { // (undocumented) variableTypeTokenRange: IExcerptTokenRange; } @@ -826,16 +975,30 @@ export interface IExcerptToken { text: string; } -// @public (undocumented) +// @public export interface IExcerptTokenRange { - // (undocumented) endIndex: number; - // (undocumented) startIndex: number; } +// @public +export interface IFindApiItemsMessage { + // @beta + messageId: FindApiItemsMessageId; + text: string; +} + +// @public +export interface IFindApiItemsResult { + items: ApiItem[]; + maybeIncompleteResult: boolean; + messages: IFindApiItemsMessage[]; +} + // @public export interface IParameterOptions { + // (undocumented) + isOptional: boolean; // (undocumented) name: string; // (undocumented) @@ -850,6 +1013,12 @@ export interface IResolveDeclarationReferenceResult { resolvedApiItem: ApiItem | undefined; } +// @public +export interface ISourceLocationOptions { + fileUrlPath?: string; + projectFolderUrl?: string; +} + // @public export interface ITypeParameterOptions { // (undocumented) @@ -857,6 +1026,8 @@ export interface ITypeParameterOptions { // (undocumented) defaultTypeExcerpt: Excerpt; // (undocumented) + isOptional: boolean; + // (undocumented) name: string; // (undocumented) parent: ApiTypeParameterListMixin; @@ -865,9 +1036,10 @@ export interface ITypeParameterOptions { // @public export class Parameter { constructor(options: IParameterOptions); + isOptional: boolean; name: string; readonly parameterTypeExcerpt: Excerpt; - readonly tsdocParamBlock: tsdoc.DocParamBlock | undefined; + get tsdocParamBlock(): tsdoc.DocParamBlock | undefined; } // @public @@ -890,14 +1062,20 @@ export namespace ReleaseTag { export function getTagName(releaseTag: ReleaseTag): string; } +// @public +export class SourceLocation { + constructor(options: ISourceLocationOptions); + get fileUrl(): string | undefined; +} + // @public export class TypeParameter { constructor(options: ITypeParameterOptions); readonly constraintExcerpt: Excerpt; readonly defaultTypeExcerpt: Excerpt; + isOptional: boolean; name: string; - readonly tsdocTypeParamBlock: tsdoc.DocParamBlock | undefined; + get tsdocTypeParamBlock(): tsdoc.DocParamBlock | undefined; } - ``` diff --git a/common/reviews/api/api-extractor.api.md b/common/reviews/api/api-extractor.api.md index f74c763215c..f44ecd8e92b 100644 --- a/common/reviews/api/api-extractor.api.md +++ b/common/reviews/api/api-extractor.api.md @@ -4,10 +4,19 @@ ```ts +import { EnumMemberOrder } from '@microsoft/api-extractor-model'; import { INodePackageJson } from '@rushstack/node-core-library'; +import { IRigConfig } from '@rushstack/rig-package'; import { JsonSchema } from '@rushstack/node-core-library'; import { NewlineKind } from '@rushstack/node-core-library'; -import * as tsdoc from '@microsoft/tsdoc'; +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'; + +// @public +export type ApiReportVariant = 'public' | 'beta' | 'alpha' | 'complete'; // @public export class CompilerState { @@ -16,14 +25,19 @@ export class CompilerState { } // @public -export const enum ConsoleMessageId { +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", + CompilerVersionNotice = "console-compiler-version-notice", Diagnostics = "console-diagnostics", FoundTSDocMetadata = "console-found-tsdoc-metadata", + Preamble = "console-preamble", + UsingCustomTSDocConfig = "console-using-custom-tsdoc-config", + WritingApiReport = "console-writing-api-report", WritingDocModelFile = "console-writing-doc-model-file", WritingDtsRollup = "console-writing-dts-rollup" } @@ -32,18 +46,23 @@ export const enum ConsoleMessageId { export class Extractor { static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult; static loadConfigAndInvoke(configFilePath: string, options?: IExtractorInvokeOptions): ExtractorResult; - static readonly packageName: string; - static readonly version: string; + static get packageName(): string; + static get version(): string; } -// @public +// @public @sealed export class ExtractorConfig { + readonly alphaTrimmedFilePath: string; readonly apiJsonFilePath: string; readonly apiReportEnabled: boolean; + readonly apiReportIncludeForgottenExports: boolean; readonly betaTrimmedFilePath: string; readonly bundledPackages: string[]; - readonly docModelEnabled: boolean; - static readonly FILENAME: string; + // @beta + readonly docModelGenerationOptions: IApiModelGenerationOptions | undefined; + readonly docModelIncludeForgottenExports: boolean; + readonly enumMemberOrder: EnumMemberOrder; + static readonly FILENAME: 'api-extractor.json'; getDiagnosticDump(): string; // @internal _getShortFilePath(absolutePath: string): string; @@ -60,20 +79,32 @@ export class ExtractorConfig { readonly packageJson: INodePackageJson | undefined; static prepare(options: IExtractorConfigPrepareOptions): ExtractorConfig; readonly projectFolder: string; + readonly projectFolderUrl: string | undefined; readonly publicTrimmedFilePath: string; - readonly reportFilePath: string; - readonly reportTempFilePath: string; + readonly reportConfigs: readonly IExtractorConfigApiReport[]; + // @deprecated + get reportFilePath(): string; + readonly reportFolder: string; + // @deprecated + get reportTempFilePath(): string; + readonly reportTempFolder: string; readonly rollupEnabled: boolean; readonly skipLibCheck: boolean; + readonly tagsToReport: Readonly>; readonly testMode: boolean; + static tryLoadForFolder(options: IExtractorConfigLoadForFolderOptions): IExtractorConfigPrepareOptions | undefined; readonly tsconfigFilePath: string; + // @internal + static readonly _tsdocBaseFilePath: string; + readonly tsdocConfigFile: TSDocConfigFile; + readonly tsdocConfiguration: TSDocConfiguration; readonly tsdocMetadataEnabled: boolean; readonly tsdocMetadataFilePath: string; readonly untrimmedFilePath: string; } // @public -export const enum ExtractorLogLevel { +export enum ExtractorLogLevel { Error = "error", Info = "info", None = "none", @@ -91,8 +122,10 @@ export class ExtractorMessage { formatMessageWithLocation(workingPackageFolderPath: string | undefined): string; // (undocumented) formatMessageWithoutLocation(): string; - handled: boolean; - logLevel: ExtractorLogLevel; + get handled(): boolean; + set handled(value: boolean); + get logLevel(): ExtractorLogLevel; + set logLevel(value: ExtractorLogLevel); readonly messageId: tsdoc.TSDocMessageId | ExtractorMessageId | ConsoleMessageId | string; readonly properties: IExtractorMessageProperties; readonly sourceFileColumn: number | undefined; @@ -102,7 +135,7 @@ export class ExtractorMessage { } // @public -export const enum ExtractorMessageCategory { +export enum ExtractorMessageCategory { Compiler = "Compiler", Console = "console", Extractor = "Extractor", @@ -110,7 +143,7 @@ export const enum ExtractorMessageCategory { } // @public -export const enum ExtractorMessageId { +export enum ExtractorMessageId { CyclicInheritDoc = "ae-cyclic-inherit-doc", DifferentReleaseTags = "ae-different-release-tags", ExtraReleaseTag = "ae-extra-release-tag", @@ -124,9 +157,11 @@ export const enum ExtractorMessageId { PreapprovedBadReleaseTag = "ae-preapproved-bad-release-tag", PreapprovedUnsupportedType = "ae-preapproved-unsupported-type", SetterWithDocs = "ae-setter-with-docs", + Undocumented = "ae-undocumented", UnresolvedInheritDocBase = "ae-unresolved-inheritdoc-base", UnresolvedInheritDocReference = "ae-unresolved-inheritdoc-reference", - UnresolvedLink = "ae-unresolved-link" + UnresolvedLink = "ae-unresolved-link", + WrongInputFileType = "ae-wrong-input-file-type" } // @public @@ -141,6 +176,11 @@ export class ExtractorResult { readonly warningCount: number; } +// @beta (undocumented) +export interface IApiModelGenerationOptions { + releaseTagsToTrim: Set; +} + // @public export interface ICompilerStateCreateOptions { additionalEntryPoints?: string[]; @@ -150,9 +190,12 @@ export interface ICompilerStateCreateOptions { // @public export interface IConfigApiReport { enabled: boolean; + includeForgottenExports?: boolean; reportFileName?: string; reportFolder?: string; reportTempFolder?: string; + reportVariants?: ApiReportVariant[]; + tagsToReport?: Readonly>; } // @public @@ -166,10 +209,14 @@ export interface IConfigCompiler { export interface IConfigDocModel { apiJsonFilePath?: string; enabled: boolean; + includeForgottenExports?: boolean; + projectFolderUrl?: string; + releaseTagsToTrim?: ReleaseTagForTrim[]; } // @public export interface IConfigDtsRollup { + alphaTrimmedFilePath?: string; betaTrimmedFilePath?: string; enabled: boolean; omitTrimmingComments?: boolean; @@ -185,6 +232,7 @@ export interface IConfigFile { docModel?: IConfigDocModel; // @beta dtsRollup?: IConfigDtsRollup; + enumMemberOrder?: EnumMemberOrder; extends?: string; mainEntryPointFilePath: string; messages?: IExtractorMessagesConfig; @@ -212,12 +260,28 @@ export interface IConfigTsdocMetadata { tsdocMetadataFilePath?: string; } +// @public +export interface IExtractorConfigApiReport { + fileName: string; + variant: ApiReportVariant; +} + +// @public +export interface IExtractorConfigLoadForFolderOptions { + packageJsonLookup?: PackageJsonLookup; + rigConfig?: IRigConfig; + startingFolder: string; +} + // @public export interface IExtractorConfigPrepareOptions { configObject: IConfigFile; configObjectFullPath: string | undefined; + ignoreMissingEntryPoint?: boolean; packageJson?: INodePackageJson | undefined; packageJsonFullPath: string | undefined; + projectFolderLookupToken?: string; + tsdocConfigFile?: TSDocConfigFile; } // @public @@ -225,6 +289,7 @@ export interface IExtractorInvokeOptions { compilerState?: CompilerState; localBuild?: boolean; messageCallback?: (message: ExtractorMessage) => void; + printApiReportDiff?: boolean; showDiagnostics?: boolean; showVerboseMessages?: boolean; typescriptCompilerFolder?: string; @@ -242,5 +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 0fa887fc061..536abe8b1f3 100644 --- a/common/reviews/api/debug-certificate-manager.api.md +++ b/common/reviews/api/debug-certificate-manager.api.md @@ -4,28 +4,68 @@ ```ts -import { Terminal } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; // @public export class CertificateManager { - constructor(); - ensureCertificate(canGenerateNewCertificate: boolean, terminal: Terminal): ICertificate; - untrustCertificate(terminal: Terminal): boolean; + 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(); - certificateData: string | undefined; - readonly certificatePath: string; - keyData: string | undefined; - } + constructor(options?: ICertificateStoreOptions); + get caCertificateData(): string | undefined; + set caCertificateData(certificate: string | undefined); + get caCertificatePath(): string; + get certificateData(): string | undefined; + set certificateData(certificate: string | undefined); + get certificatePath(): string; + get keyData(): string | undefined; + set keyData(key: string | undefined); + get keyPath(): string; + get storePath(): string; +} + +// @public +export const DEFAULT_CERTIFICATE_SUBJECT_NAMES: ReadonlyArray; // @public export interface ICertificate { + pemCaCertificate: string | undefined; pemCertificate: string | undefined; pemKey: string | undefined; + subjectAltNames: readonly string[] | undefined; +} + +// @public +export interface ICertificateGenerationOptions { + skipCertificateTrust?: boolean; + subjectAltNames?: ReadonlyArray; + subjectIPAddresses?: ReadonlyArray; + 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/gulp-core-build-karma.api.md b/common/reviews/api/gulp-core-build-karma.api.md deleted file mode 100644 index ce130fe8bcc..00000000000 --- a/common/reviews/api/gulp-core-build-karma.api.md +++ /dev/null @@ -1,3 +0,0 @@ -// WARNING: Unsupported export: karma -// WARNING: Unsupported export: default -// (No @packagedocumentation comment for this package) diff --git a/common/reviews/api/gulp-core-build-mocha.api.md b/common/reviews/api/gulp-core-build-mocha.api.md deleted file mode 100644 index b7800f360ec..00000000000 --- a/common/reviews/api/gulp-core-build-mocha.api.md +++ /dev/null @@ -1,30 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build-mocha" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as Gulp from 'gulp'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import { IBuildConfig } from '@microsoft/gulp-core-build'; -import { IExecutable } from '@microsoft/gulp-core-build'; - -// @public (undocumented) -const _default: IExecutable; - -export default _default; - -// Warning: (ae-forgotten-export) The symbol "InstrumentTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const instrument: InstrumentTask; - -// Warning: (ae-forgotten-export) The symbol "MochaTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const mocha: MochaTask; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/gulp-core-build-sass.api.md b/common/reviews/api/gulp-core-build-sass.api.md deleted file mode 100644 index c7dc14c3a69..00000000000 --- a/common/reviews/api/gulp-core-build-sass.api.md +++ /dev/null @@ -1,24 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build-sass" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as CleanCss from 'clean-css'; -import * as Gulp from 'gulp'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import { JsonObject } from '@rushstack/node-core-library'; - -// Warning: (ae-forgotten-export) The symbol "SassTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -const sass: SassTask; - -export default sass; - -export { sass } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/gulp-core-build-serve.api.md b/common/reviews/api/gulp-core-build-serve.api.md deleted file mode 100644 index d8b5766ffb8..00000000000 --- a/common/reviews/api/gulp-core-build-serve.api.md +++ /dev/null @@ -1,40 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build-serve" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { GCBTerminalProvider } from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import { JsonObject } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; - -// Warning: (ae-forgotten-export) The symbol "ReloadTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const reload: ReloadTask; - -// Warning: (ae-forgotten-export) The symbol "ServeTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -const serve: ServeTask; - -export default serve; - -export { serve } - -// Warning: (ae-forgotten-export) The symbol "TrustCertTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const trustDevCert: TrustCertTask; - -// Warning: (ae-forgotten-export) The symbol "UntrustCertTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const untrustDevCert: UntrustCertTask; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/gulp-core-build-typescript.api.md b/common/reviews/api/gulp-core-build-typescript.api.md deleted file mode 100644 index 2921d9ab62d..00000000000 --- a/common/reviews/api/gulp-core-build-typescript.api.md +++ /dev/null @@ -1,81 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build-typescript" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { GCBTerminalProvider } from '@microsoft/gulp-core-build'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import { IBuildConfig } from '@microsoft/gulp-core-build'; -import { JsonObject } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as TRushStackCompiler from '@microsoft/rush-stack-compiler-3.1'; - -// Warning: (ae-forgotten-export) The symbol "ApiExtractorTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const apiExtractor: ApiExtractorTask; - -// Warning: (ae-forgotten-export) The symbol "IRSCTaskConfig" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export interface ILintCmdTaskConfig extends IRSCTaskConfig { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface ITscCmdTaskConfig extends IRSCTaskConfig { - customArgs?: string[]; - removeCommentsFromJavaScript?: boolean; - staticMatch?: string[]; -} - -// @public (undocumented) -export interface ITslintCmdTaskConfig extends IRSCTaskConfig { - displayAsError?: boolean; -} - -// @public (undocumented) -export const lintCmd: LintCmdTask; - -// Warning: (ae-forgotten-export) The symbol "RSCTask" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export class LintCmdTask extends RSCTask { - constructor(); - // (undocumented) - executeTask(): Promise; - // (undocumented) - loadSchema(): JsonObject; -} - -// @public (undocumented) -export const tscCmd: TscCmdTask; - -// @public (undocumented) -export class TscCmdTask extends RSCTask { - constructor(); - // (undocumented) - executeTask(): Promise; - // (undocumented) - loadSchema(): JsonObject; - // (undocumented) - protected _onData(data: Buffer): void; - } - -// @public (undocumented) -export const tslintCmd: TslintCmdTask; - -// @public (undocumented) -export class TslintCmdTask extends RSCTask { - constructor(); - // (undocumented) - executeTask(): Promise; - // (undocumented) - loadSchema(): JsonObject; -} - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/gulp-core-build-webpack.api.md b/common/reviews/api/gulp-core-build-webpack.api.md deleted file mode 100644 index 0e464fe275b..00000000000 --- a/common/reviews/api/gulp-core-build-webpack.api.md +++ /dev/null @@ -1,50 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build-webpack" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as Gulp from 'gulp'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import { IBuildConfig } from '@microsoft/gulp-core-build'; -import * as Webpack from 'webpack'; - -// @public (undocumented) -export interface IWebpackResources { - // (undocumented) - webpack: typeof Webpack; -} - -// @public (undocumented) -export interface IWebpackTaskConfig { - config?: Webpack.Configuration | Webpack.Configuration[]; - configPath: string; - printStats?: boolean; - suppressWarnings?: (string | RegExp)[]; - webpack?: typeof Webpack; -} - -// @public (undocumented) -const webpack: WebpackTask; - -export default webpack; - -export { webpack } - -// @public (undocumented) -export class WebpackTask extends GulpTask { - constructor(extendedName?: string, extendedConfig?: TExtendedConfig); - // (undocumented) - executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): void; - // (undocumented) - isEnabled(buildConfig: IBuildConfig): boolean; - // (undocumented) - loadSchema(): any; - // (undocumented) - readonly resources: IWebpackResources; - } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/gulp-core-build.api.md b/common/reviews/api/gulp-core-build.api.md deleted file mode 100644 index 02b20d2e8a4..00000000000 --- a/common/reviews/api/gulp-core-build.api.md +++ /dev/null @@ -1,294 +0,0 @@ -## API Report File for "@microsoft/gulp-core-build" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { ConsoleTerminalProvider } from '@rushstack/node-core-library'; -import gulp = require('gulp'); -import * as gulp_2 from 'gulp'; -import { JsonObject } from '@rushstack/node-core-library'; -import Orchestrator = require('orchestrator'); -import { TerminalProviderSeverity } from '@rushstack/node-core-library'; - -// @public -export function addSuppression(suppression: string | RegExp): void; - -// @public (undocumented) -export const clean: IExecutable; - -// @public (undocumented) -export const cleanFlag: IExecutable; - -// @public -export class CleanFlagTask extends CleanTask { - constructor(); - // (undocumented) - executeTask(gulp: typeof gulp_2, completeCallback: (error?: string | Error) => void): void; - // (undocumented) - isEnabled(buildConfig: IBuildConfig): boolean; -} - -// @public -export class CleanTask extends GulpTask { - constructor(); - executeTask(gulp: typeof gulp_2, completeCallback: (error?: string | Error) => void): void; -} - -// @public (undocumented) -export const copyStaticAssets: CopyStaticAssetsTask; - -// @public -export class CopyStaticAssetsTask extends GulpTask { - constructor(); - // (undocumented) - executeTask(gulp: typeof gulp_2, completeCallback: (error?: string) => void): NodeJS.ReadWriteStream; - // (undocumented) - loadSchema(): JsonObject; -} - -// @public -export class CopyTask extends GulpTask { - constructor(); - executeTask(gulp: typeof gulp_2, completeCallback: (error?: string | Error) => void): Promise | NodeJS.ReadWriteStream | void; - loadSchema(): JsonObject; -} - -// @public -export function coverageData(coverage: number, threshold: number, filePath: string): void; - -// @public -export function error(...args: string[]): void; - -// @public -export function fileError(taskName: string, filePath: string, line: number, column: number, errorCode: string, message: string): void; - -// @public -export function fileLog(write: (text: string) => void, taskName: string, filePath: string, line: number, column: number, errorCode: string, message: string): void; - -// @public -export function fileWarning(taskName: string, filePath: string, line: number, column: number, errorCode: string, message: string): void; - -// @public -export function functionalTestRun(name: string, result: TestResultState, duration: number): void; - -// @public (undocumented) -export class GCBTerminalProvider extends ConsoleTerminalProvider { - constructor(gcbTask: GulpTask); - // (undocumented) - write(data: string, severity: TerminalProviderSeverity): void; -} - -// @public -export class GenerateShrinkwrapTask extends GulpTask { - constructor(); - executeTask(gulp: gulp.Gulp, completeCallback: (error?: string | Error) => void): NodeJS.ReadWriteStream | void; -} - -// @public -export function getConfig(): IBuildConfig; - -// @public -export function getErrors(): string[]; - -// @public -export function getWarnings(): string[]; - -// @public -export abstract class GulpTask implements IExecutable { - constructor(name: string, initialTaskConfig?: Partial); - buildConfig: IBuildConfig; - cleanMatch: string[]; - copyFile(localSourcePath: string, localDestPath?: string): void; - enabled: boolean; - execute(config: IBuildConfig): Promise; - // Warning: (ae-forgotten-export) The symbol "GulpProxy" needs to be exported by the entry point index.d.ts - abstract executeTask(gulp: gulp.Gulp | GulpProxy, completeCallback?: (error?: string | Error) => void): Promise | NodeJS.ReadWriteStream | void; - fileError(filePath: string, line: number, column: number, errorCode: string, message: string): void; - fileExists(localPath: string): boolean; - fileWarning(filePath: string, line: number, column: number, warningCode: string, message: string): void; - getCleanMatch(buildConfig: IBuildConfig, taskConfig?: TTaskConfig): string[]; - protected _getConfigFilePath(): string; - isEnabled(buildConfig: IBuildConfig): boolean; - protected loadSchema(): JsonObject | undefined; - log(message: string): void; - logError(message: string): void; - logVerbose(message: string): void; - logWarning(message: string): void; - mergeConfig(taskConfig: Partial): void; - name: string; - onRegister(): void; - readJSONSync(localPath: string): JsonObject | undefined; - replaceConfig(taskConfig: TTaskConfig): void; - resolvePath(localPath: string): string; - readonly schema: JsonObject | undefined; - setConfig(taskConfig: Partial): void; - taskConfig: TTaskConfig; -} - -// @public (undocumented) -export interface IBuildConfig { - args: { - [name: string]: string | boolean; - }; - buildErrorIconPath?: string; - buildSuccessIconPath?: string; - distFolder: string; - gulp: GulpProxy | gulp_2.Gulp; - isRedundantBuild?: boolean; - jestEnabled?: boolean; - libAMDFolder?: string; - libES6Folder?: string; - libESNextFolder?: string; - libFolder: string; - maxBuildTimeMs: number; - onTaskEnd?: (taskName: string, duration: number[], error?: any) => void; - onTaskStart?: (taskName: string) => void; - packageFolder: string; - production: boolean; - properties?: { - [key: string]: any; - }; - relogIssues?: boolean; - rootPath: string; - shouldWarningsFailBuild: boolean; - showToast?: boolean; - srcFolder: string; - tempFolder: string; - uniqueTasks?: IExecutable[]; - verbose: boolean; -} - -// @public -export interface ICopyConfig { - copyTo: { - [destPath: string]: string[]; - }; - shouldFlatten?: boolean; -} - -// @public -export interface ICopyStaticAssetsTaskConfig { - // (undocumented) - excludeExtensions?: string[]; - // (undocumented) - excludeFiles?: string[]; - // (undocumented) - includeExtensions?: string[]; - // (undocumented) - includeFiles?: string[]; -} - -// @public -export interface ICustomGulpTask { - // (undocumented) - (gulp: typeof gulp_2 | GulpProxy, buildConfig: IBuildConfig, done?: (failure?: any) => void): Promise | NodeJS.ReadWriteStream | void; -} - -// @public (undocumented) -export interface IExecutable { - execute: (config: IBuildConfig) => Promise; - getCleanMatch?: (config: IBuildConfig, taskConfig?: any) => string[]; - isEnabled?: (buildConfig: IBuildConfig) => boolean; - maxBuildTimeMs?: number; - name?: string; - onRegister?: () => void; -} - -// @alpha -export interface IJestConfig { - cache?: boolean; - collectCoverageFrom?: string[]; - coverage?: boolean; - coverageReporters?: string[]; - isEnabled?: boolean; - maxWorkers?: number; - moduleDirectories?: string[]; - modulePathIgnorePatterns?: string[]; - testMatch?: string[]; - testPathIgnorePatterns?: string[]; - writeNUnitResults?: boolean; -} - -// @public -export function initialize(gulp: typeof gulp_2): void; - -// @internal -export function _isJestEnabled(rootFolder: string): boolean; - -// Warning: (ae-incompatible-release-tags) The symbol "jest" is marked as @public, but its signature references "JestTask" which is marked as @alpha -// -// @public (undocumented) -export const jest: JestTask; - -// @alpha -export class JestTask extends GulpTask { - constructor(); - // (undocumented) - executeTask(gulp: typeof gulp_2, completeCallback: (error?: string | Error) => void): void; - // (undocumented) - isEnabled(buildConfig: IBuildConfig): boolean; - loadSchema(): JsonObject; -} - -// @public -export function log(...args: string[]): void; - -// @public -export function logSummary(value: string): void; - -// @public -export function mergeConfig(config: Partial): void; - -// @public -export function parallel(...tasks: (IExecutable[] | IExecutable)[]): IExecutable; - -// @public -export function replaceConfig(config: IBuildConfig): void; - -// @public -export function reset(): void; - -// @public -export function serial(...tasks: (IExecutable[] | IExecutable)[]): IExecutable; - -// @public -export function setConfig(config: Partial): void; - -// @public -export function subTask(taskName: string, fn: ICustomGulpTask): IExecutable; - -// @public -export function task(taskName: string, taskExecutable: IExecutable): IExecutable; - -// @public -export enum TestResultState { - // (undocumented) - Failed = 1, - // (undocumented) - FlakyFailed = 2, - // (undocumented) - Passed = 0, - // (undocumented) - Skipped = 3 -} - -// @public -export class ValidateShrinkwrapTask extends GulpTask { - constructor(); - executeTask(gulp: gulp.Gulp, completeCallback: (error: string) => void): NodeJS.ReadWriteStream | void; - } - -// @public -export function verbose(...args: string[]): void; - -// @public -export function warn(...args: string[]): void; - -// @public -export function watch(watchMatch: string | string[], taskExecutable: IExecutable): IExecutable; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/hashed-folder-copy-plugin.api.md b/common/reviews/api/hashed-folder-copy-plugin.api.md new file mode 100644 index 00000000000..a2bee927a2f --- /dev/null +++ b/common/reviews/api/hashed-folder-copy-plugin.api.md @@ -0,0 +1,17 @@ +## API Report File for "@rushstack/hashed-folder-copy-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type webpack from 'webpack'; + +// @public (undocumented) +export class HashedFolderCopyPlugin implements webpack.WebpackPluginInstance { + // (undocumented) + apply(compiler: webpack.Compiler): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/heft-config-file.api.md b/common/reviews/api/heft-config-file.api.md new file mode 100644 index 00000000000..f432abc2fca --- /dev/null +++ b/common/reviews/api/heft-config-file.api.md @@ -0,0 +1,199 @@ +## API Report File for "@rushstack/heft-config-file" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IRigConfig } from '@rushstack/rig-package'; +import type { ITerminal } from '@rushstack/terminal'; + +// @beta @deprecated (undocumented) +export const ConfigurationFile: typeof ProjectConfigurationFile; + +// @beta @deprecated (undocumented) +export type ConfigurationFile = ProjectConfigurationFile; + +// @beta (undocumented) +export abstract class ConfigurationFileBase { + constructor(options: IConfigurationFileOptions); + // @internal (undocumented) + static _formatPathForLogging: (path: string) => string; + getObjectSourceFilePath(obj: TObject): string | undefined; + getPropertyOriginalValue(options: IOriginalValueOptions): TValue | undefined; + getSchemaPropertyOriginalValue(obj: TObject): string | undefined; + // (undocumented) + protected _loadConfigurationFileInnerWithCache(terminal: ITerminal, resolvedConfigurationFilePath: string, projectFolderPath: string | undefined, onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback): TConfigurationFile; + // (undocumented) + 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; +} + +// @beta (undocumented) +export type IConfigurationFileOptionsWithJsonSchemaFilePath = IConfigurationFileOptionsBase & TExtraOptions & { + jsonSchemaPath: string; + jsonSchemaObject?: never; +}; + +// @beta (undocumented) +export type IConfigurationFileOptionsWithJsonSchemaObject = IConfigurationFileOptionsBase & TExtraOptions & { + jsonSchemaObject: object; + jsonSchemaPath?: never; +}; + +// @beta +export interface ICustomJsonPathMetadata { + customResolver?: (resolverOptions: IJsonPathMetadataResolverOptions) => string; + pathResolutionMethod?: PathResolutionMethod.custom; +} + +// @beta (undocumented) +export interface ICustomPropertyInheritance extends IPropertyInheritance { + inheritanceFunction: PropertyInheritanceCustomFunction; +} + +// @beta (undocumented) +export type IJsonPathMetadata = ICustomJsonPathMetadata | INonCustomJsonPathMetadata; + +// @beta +export interface IJsonPathMetadataResolverOptions { + configurationFile: Partial; + configurationFilePath: string; + projectFolderPath?: string; + propertyName: string; + propertyValue: string; +} + +// @beta +export interface IJsonPathsMetadata { + // (undocumented) + [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 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 +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) + parentObject: Partial; + // (undocumented) + propertyName: keyof TParentProperty; +} + +// @beta (undocumented) +export interface IProjectConfigurationFileOptions { + projectRelativeFilePath: string; +} + +// @beta +export type IProjectConfigurationFileSpecification = IConfigurationFileOptions; + +// @beta (undocumented) +export type IPropertiesInheritance = { + [propertyName in keyof TConfigurationFile]?: IPropertyInheritance | ICustomPropertyInheritance; +}; + +// @beta (undocumented) +export interface IPropertyInheritance { + // (undocumented) + inheritanceType: TInheritanceType; +} + +// @beta (undocumented) +export interface IPropertyInheritanceDefaults { + // (undocumented) + array?: IPropertyInheritance; + // (undocumented) + object?: IPropertyInheritance; +} + +// @beta (undocumented) +export class NonProjectConfigurationFile extends ConfigurationFileBase { + loadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile; + loadConfigurationFileAsync(terminal: ITerminal, filePath: string): Promise; + tryLoadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile | undefined; + tryLoadConfigurationFileAsync(terminal: ITerminal, filePath: string): 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 namespace PathResolutionMethod { + export type custom = typeof PathResolutionMethod.custom; + // @deprecated + 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: 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; +} + +// @beta (undocumented) +export type PropertyInheritanceCustomFunction = (currentObject: TObject, parentObject: TObject) => TObject; + +// @beta +function stripAnnotations(obj: TObject): TObject; + +declare namespace TestUtilities { + export { + stripAnnotations + } +} + +``` diff --git a/common/reviews/api/heft-dev-cert-plugin.api.md b/common/reviews/api/heft-dev-cert-plugin.api.md new file mode 100644 index 00000000000..177367902af --- /dev/null +++ b/common/reviews/api/heft-dev-cert-plugin.api.md @@ -0,0 +1,13 @@ +## API Report File for "@rushstack/heft-dev-cert-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IHeftPlugin } from '@rushstack/heft'; + +// @public (undocumented) +const _default: IHeftPlugin; +export default _default; + +``` 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-jest-plugin.api.md b/common/reviews/api/heft-jest-plugin.api.md new file mode 100644 index 00000000000..1fd42799ee9 --- /dev/null +++ b/common/reviews/api/heft-jest-plugin.api.md @@ -0,0 +1,13 @@ +## API Report File for "@rushstack/heft-jest-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IHeftPlugin } from '@rushstack/heft'; + +// @public (undocumented) +const _default: IHeftPlugin; +export default _default; + +``` 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-sass-plugin.api.md b/common/reviews/api/heft-sass-plugin.api.md new file mode 100644 index 00000000000..b00a09a3568 --- /dev/null +++ b/common/reviews/api/heft-sass-plugin.api.md @@ -0,0 +1,13 @@ +## API Report File for "@rushstack/heft-sass-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IHeftPlugin } from '@rushstack/heft'; + +// @public (undocumented) +const _default: IHeftPlugin; +export default _default; + +``` diff --git a/common/reviews/api/heft-storybook-plugin.api.md b/common/reviews/api/heft-storybook-plugin.api.md new file mode 100644 index 00000000000..01834ab9ec2 --- /dev/null +++ b/common/reviews/api/heft-storybook-plugin.api.md @@ -0,0 +1,21 @@ +## API Report File for "@rushstack/heft-storybook-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IHeftPlugin } from '@rushstack/heft'; + +// @public (undocumented) +const _default: IHeftPlugin; +export default _default; + +// @public +export interface IStorybookPluginOptions { + startupModulePath?: string; + staticBuildModulePath?: string; + staticBuildOutputFolder?: string; + storykitPackageName: string; +} + +``` diff --git a/common/reviews/api/heft-typescript-plugin.api.md b/common/reviews/api/heft-typescript-plugin.api.md new file mode 100644 index 00000000000..2e42af718cc --- /dev/null +++ b/common/reviews/api/heft-typescript-plugin.api.md @@ -0,0 +1,144 @@ +## API Report File for "@rushstack/heft-typescript-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +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'; + +// @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<_TTypeScript.SourceFile>; + // (undocumented) + program: _TTypeScript.Program; +} + +// @internal (undocumented) +export interface _ICompilerCapabilities { + incrementalProgram: boolean; + solutionBuilder: boolean; +} + +// @beta (undocumented) +export interface IEmitModuleKind { + // (undocumented) + jsExtensionOverride?: string; + // (undocumented) + moduleKind: 'commonjs' | 'amd' | 'umd' | 'system' | 'es2015' | 'esnext'; + // (undocumented) + 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) + compilerOptions?: IPartialTsconfigCompilerOptions; +} + +// @beta (undocumented) +export interface IPartialTsconfigCompilerOptions { + // (undocumented) + outDir?: string; +} + +// @beta (undocumented) +export interface IStaticAssetsCopyConfiguration { + // (undocumented) + excludeGlobs: string[]; + // (undocumented) + fileExtensions: string[]; + // (undocumented) + includeGlobs: string[]; +} + +// @beta (undocumented) +export interface ITypeScriptConfigurationJson { + additionalModuleKindsToEmit?: IEmitModuleKind[] | undefined; + buildProjectReferences?: boolean; + emitCjsExtensionForCommonJS?: boolean | undefined; + emitMjsExtensionForESModule?: boolean | undefined; + onlyResolveSymlinksInNodeModules?: boolean; + // (undocumented) + project?: string; + staticAssetsToCopy?: IStaticAssetsCopyConfiguration; + useTranspilerWorker?: boolean; +} + +// @beta (undocumented) +export interface ITypeScriptPluginAccessor { + // (undocumented) + readonly onChangedFilesHook: SyncHook; +} + +// @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-webpack4-plugin.api.md b/common/reviews/api/heft-webpack4-plugin.api.md new file mode 100644 index 00000000000..65305cc3dbe --- /dev/null +++ b/common/reviews/api/heft-webpack4-plugin.api.md @@ -0,0 +1,60 @@ +## API Report File for "@rushstack/heft-webpack4-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 { Configuration } from 'webpack-dev-server'; +import type { HeftConfiguration } from '@rushstack/heft'; +import type { IHeftTaskSession } from '@rushstack/heft'; +import type * as TWebpack from 'webpack'; + +// @public (undocumented) +export type IWebpackConfiguration = IWebpackConfigurationWithDevServer | IWebpackConfigurationWithDevServer[]; + +// @public +export interface IWebpackConfigurationFnEnvironment { + heftConfiguration: HeftConfiguration; + prod: boolean; + production: boolean; + taskSession: IHeftTaskSession; + webpack: typeof TWebpack; +} + +// @public (undocumented) +export interface IWebpackConfigurationWithDevServer extends TWebpack.Configuration { + // (undocumented) + devServer?: Configuration; +} + +// @public (undocumented) +export interface IWebpackPluginAccessor { + readonly hooks: IWebpackPluginAccessorHooks; + readonly parameters: IWebpackPluginAccessorParameters; +} + +// @public (undocumented) +export interface IWebpackPluginAccessorHooks { + readonly onAfterConfigure: AsyncParallelHook; + readonly onConfigure: AsyncSeriesHook; + readonly onEmitStats: AsyncParallelHook; + readonly onLoadConfiguration: AsyncSeriesBailHook; +} + +// @public (undocumented) +export interface IWebpackPluginAccessorParameters { + readonly isServeMode: boolean; +} + +// @public (undocumented) +export const PluginName: 'webpack4-plugin'; + +// @public +export const STAGE_LOAD_LOCAL_CONFIG: 1000; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/heft-webpack5-plugin.api.md b/common/reviews/api/heft-webpack5-plugin.api.md new file mode 100644 index 00000000000..e7212e5014b --- /dev/null +++ b/common/reviews/api/heft-webpack5-plugin.api.md @@ -0,0 +1,62 @@ +## API Report File for "@rushstack/heft-webpack5-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 { Configuration } from 'webpack-dev-server'; +import type { HeftConfiguration } from '@rushstack/heft'; +import type { IHeftTaskSession } from '@rushstack/heft'; +import type * as TWebpack from 'webpack'; + +// @public (undocumented) +export type IWebpackConfiguration = IWebpackConfigurationWithDevServer | IWebpackConfigurationWithDevServer[]; + +// @public +export interface IWebpackConfigurationFnEnvironment { + heftConfiguration: HeftConfiguration; + prod: boolean; + production: boolean; + taskSession: IHeftTaskSession; + webpack: typeof TWebpack; +} + +// @public (undocumented) +export interface IWebpackConfigurationWithDevServer extends TWebpack.Configuration { + // (undocumented) + devServer?: Configuration; +} + +// @public (undocumented) +export interface IWebpackPluginAccessor { + readonly hooks: IWebpackPluginAccessorHooks; + readonly parameters: IWebpackPluginAccessorParameters; +} + +// @public (undocumented) +export interface IWebpackPluginAccessorHooks { + readonly onAfterConfigure: AsyncParallelHook; + readonly onConfigure: AsyncSeriesHook; + readonly onEmitStats: AsyncParallelHook; + readonly onGetWatchOptions: AsyncSeriesWaterfallHook[0], Readonly, never>; + readonly onLoadConfiguration: AsyncSeriesBailHook; +} + +// @public (undocumented) +export interface IWebpackPluginAccessorParameters { + readonly isServeMode: boolean; +} + +// @public (undocumented) +export const PluginName: 'webpack5-plugin'; + +// @public +export const STAGE_LOAD_LOCAL_CONFIG: 1000; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/heft.api.md b/common/reviews/api/heft.api.md new file mode 100644 index 00000000000..96f4281126f --- /dev/null +++ b/common/reviews/api/heft.api.md @@ -0,0 +1,434 @@ +## API Report File for "@rushstack/heft" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import { AsyncParallelHook } from 'tapable'; +import { AsyncSeriesWaterfallHook } from 'tapable'; +import { CommandLineChoiceListParameter } from '@rushstack/ts-command-line'; +import { CommandLineChoiceParameter } from '@rushstack/ts-command-line'; +import { CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { CommandLineIntegerListParameter } from '@rushstack/ts-command-line'; +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 } + +export { CommandLineChoiceParameter } + +export { CommandLineFlagParameter } + +export { CommandLineIntegerListParameter } + +export { CommandLineIntegerParameter } + +export { CommandLineParameter } + +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 { + readonly buildFolderPath: string; + // @internal + _checkForRigAsync(): Promise; + 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; + readonly terminalProvider: ITerminalProvider; + tryLoadProjectConfigurationFile(options: IProjectConfigurationFileSpecification, terminal: ITerminal): TConfigFile | undefined; + tryLoadProjectConfigurationFileAsync(options: IProjectConfigurationFileSpecification, terminal: ITerminal): Promise; +} + +// @public +export interface ICopyOperation extends IFileSelectionSpecifier { + destinationFolders: string[]; + flatten?: boolean; + hardlink?: boolean; +} + +// @public +export interface IDeleteOperation extends IFileSelectionSpecifier { +} + +// @public +export interface IFileSelectionSpecifier { + excludeGlobs?: string[]; + fileExtensions?: string[]; + includeGlobs?: string[]; + sourcePath?: string; +} + +// @public +export interface IGlobOptions { + absolute?: boolean; + cwd?: string; + dot?: boolean; + ignore?: string[]; +} + +// @internal (undocumented) +export interface _IHeftConfigurationInitializationOptions { + cwd: string; + numberOfCores: number; + terminalProvider: ITerminalProvider; +} + +// @public +export interface IHeftDefaultParameters { + readonly clean: boolean; + readonly debug: boolean; + readonly locales: Iterable; + readonly production: boolean; + readonly verbose: boolean; + readonly watch: boolean; +} + +// @public +export interface IHeftLifecycleCleanHookOptions { + addDeleteOperations: (...deleteOperations: IDeleteOperation[]) => void; +} + +// @public +export interface IHeftLifecycleHooks { + clean: AsyncParallelHook; + phaseFinish: SyncHook; + phaseStart: SyncHook; + recordMetrics: AsyncParallelHook; + taskFinish: SyncHook; + taskStart: SyncHook; + toolFinish: AsyncParallelHook; + toolStart: AsyncParallelHook; +} + +// @public +export interface IHeftLifecyclePlugin extends IHeftPlugin { +} + +// @public +export interface IHeftLifecycleSession { + readonly hooks: IHeftLifecycleHooks; + readonly logger: IScopedLogger; + readonly parameters: IHeftParameters; + requestAccessToPluginByName(pluginToAccessPackage: string, pluginToAccessName: string, pluginApply: (pluginAccessor: T) => void): void; + readonly tempFolderPath: string; +} + +// @public +export interface IHeftLifecycleToolFinishHookOptions { +} + +// @public +export interface IHeftLifecycleToolStartHookOptions { +} + +// @public +export interface IHeftParameters extends IHeftDefaultParameters { + getChoiceListParameter(parameterLongName: string): CommandLineChoiceListParameter; + getChoiceParameter(parameterLongName: string): CommandLineChoiceParameter; + getFlagParameter(parameterLongName: string): CommandLineFlagParameter; + getIntegerListParameter(parameterLongName: string): CommandLineIntegerListParameter; + getIntegerParameter(parameterLongName: string): CommandLineIntegerParameter; + getStringListParameter(parameterLongName: string): CommandLineStringListParameter; + getStringParameter(parameterLongName: string): CommandLineStringParameter; +} + +// @public +export interface IHeftParsedCommandLine { + readonly commandName: string; + 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; + apply(session: TSession, heftConfiguration: HeftConfiguration, pluginOptions?: TOptions): void; +} + +// @public (undocumented) +export interface IHeftRecordMetricsHookOptions { + // (undocumented) + metricData: IMetricsData; + // (undocumented) + 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; + readonly run: AsyncParallelHook; + readonly runIncremental: AsyncParallelHook; +} + +// @public +export interface IHeftTaskOperationMetadata { + // (undocumented) + phase: IHeftPhase; + // (undocumented) + task: IHeftTask; +} + +// @public +export interface IHeftTaskPlugin extends IHeftPlugin { +} + +// @public +export interface IHeftTaskRunHookOptions { + // @beta + readonly abortSignal: AbortSignal; + readonly globAsync: GlobFn; +} + +// @public +export interface IHeftTaskRunIncrementalHookOptions extends IHeftTaskRunHookOptions { + readonly requestRun: () => void; + readonly watchFs: IWatchFileSystem; + readonly watchGlobAsync: WatchGlobFn; +} + +// @public +export interface IHeftTaskSession { + readonly hooks: IHeftTaskHooks; + readonly logger: IScopedLogger; + readonly parameters: IHeftParameters; + readonly parsedCommandLine: IHeftParsedCommandLine; + requestAccessToPluginByName(pluginToAccessPackage: string, pluginToAccessName: string, pluginApply: (pluginAccessor: T) => void): void; + readonly taskName: string; + readonly tempFolderPath: string; +} + +// @public (undocumented) +export interface IHeftTaskStartHookOptions { + // (undocumented) + operation: Operation; +} + +// @public +export interface IIncrementalCopyOperation extends ICopyOperation { + onlyIfChanged?: boolean; +} + +// @public (undocumented) +export interface IMetricsData { + bootDurationMs: number; + command: string; + commandParameters: Record; + encounteredError?: boolean; + machineArch: string; + machineCores: number; + machineOs: string; + machineProcessor: string; + machineTotalMemoryMB: number; + taskTotalExecutionMs: number; + totalUptimeMs: number; +} + +// @internal (undocumented) +export interface _IPerformanceData { + // (undocumented) + encounteredError?: boolean; + // (undocumented) + taskTotalExecutionMs: number; +} + +// @public +export interface IReaddirOptions { + withFileTypes: true; +} + +// @public +export interface IRigPackageResolver { + // (undocumented) + resolvePackageAsync(packageName: string, terminal: ITerminal): Promise; +} + +// @beta +export interface IRunScript { + runAsync: (options: IRunScriptOptions) => Promise; +} + +// @beta +export interface IRunScriptOptions { + // (undocumented) + heftConfiguration: HeftConfiguration; + // (undocumented) + heftTaskSession: IHeftTaskSession; + // (undocumented) + runOptions: IHeftTaskRunHookOptions; + // (undocumented) + scriptOptions: Record; +} + +// @public +export interface IScopedLogger { + emitError(error: Error): void; + emitWarning(warning: Error): void; + readonly hasErrors: boolean; + readonly loggerName: string; + resetErrorsAndWarnings(): void; + readonly terminal: ITerminal; +} + +// @public +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; + // (undocumented) + readonly recordMetricsHook: AsyncParallelHook; + 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/loader-load-themed-styles.api.md b/common/reviews/api/loader-load-themed-styles.api.md index 5125d92c88a..4d2c7c3bd02 100644 --- a/common/reviews/api/loader-load-themed-styles.api.md +++ b/common/reviews/api/loader-load-themed-styles.api.md @@ -4,7 +4,6 @@ ```ts - // (No @packageDocumentation comment for this package) ``` diff --git a/common/reviews/api/localization-plugin.api.md b/common/reviews/api/localization-plugin.api.md deleted file mode 100644 index 3a9e353e4a0..00000000000 --- a/common/reviews/api/localization-plugin.api.md +++ /dev/null @@ -1,219 +0,0 @@ -## API Report File for "@rushstack/localization-plugin" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { loader } from 'webpack'; -import { StringValuesTypingsGenerator } from '@rushstack/typings-generator'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Webpack from 'webpack'; - -// @public (undocumented) -export interface IDefaultLocaleOptions { - fillMissingTranslationStrings?: boolean; - localeName: string; -} - -// @public (undocumented) -export interface ILocaleData { - // (undocumented) - [locFilePath: string]: ILocaleFileData; -} - -// @public (undocumented) -export interface ILocaleElementMap { - // (undocumented) - [locale: string]: string; -} - -// @public (undocumented) -export interface ILocaleFileData { - // (undocumented) - [stringName: string]: string; -} - -// @public -export interface ILocalizationPluginOptions { - filesToIgnore?: string[]; - localizationStats?: ILocalizationStatsOptions; - localizedData: ILocalizedData; - noStringsLocaleName?: string; - typingsOptions?: ITypingsGenerationOptions; -} - -// @public (undocumented) -export interface ILocalizationStats { - // (undocumented) - entrypoints: { - [name: string]: ILocalizationStatsEntrypoint; - }; - // (undocumented) - namedChunkGroups: { - [name: string]: ILocalizationStatsChunkGroup; - }; -} - -// @public (undocumented) -export interface ILocalizationStatsChunkGroup { - // (undocumented) - localizedAssets: ILocaleElementMap; -} - -// @public (undocumented) -export interface ILocalizationStatsEntrypoint { - // (undocumented) - localizedAssets: ILocaleElementMap; -} - -// @public -export interface ILocalizationStatsOptions { - callback?: (stats: ILocalizationStats) => void; - dropPath?: string; -} - -// @public (undocumented) -export interface ILocalizedData { - defaultLocale: IDefaultLocaleOptions; - passthroughLocale?: IPassthroughLocaleOptions; - pseudolocales?: IPseudolocalesOptions; - translatedStrings: ILocalizedStrings; -} - -// @internal (undocumented) -export interface _ILocalizedString { - // (undocumented) - comment?: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export interface ILocalizedStrings { - // (undocumented) - [locale: string]: ILocaleData; -} - -// @public (undocumented) -export interface ILocalizedWebpackChunk extends Webpack.compilation.Chunk { - // (undocumented) - localizedFiles?: { - [locale: string]: string; - }; -} - -// @internal (undocumented) -export interface _ILocFile { - // (undocumented) - [stringName: string]: _ILocalizedString; -} - -// @internal (undocumented) -export interface _ILoggerOptions { - // (undocumented) - writeError: (message: string) => void; - // (undocumented) - writeWarning: (message: string) => void; -} - -// @internal (undocumented) -export interface _IParseLocFileOptions { - // (undocumented) - content: string; - // (undocumented) - filePath: string; - // (undocumented) - loggerOptions: _ILoggerOptions; -} - -// @public -export interface IPassthroughLocaleOptions { - passthroughLocaleName?: string; - usePassthroughLocale?: boolean; -} - -// @public -export interface IPseudolocaleOptions { - // (undocumented) - append?: string; - // (undocumented) - delimiter?: string; - // (undocumented) - endDelimiter?: string; - // (undocumented) - extend?: number; - // (undocumented) - override?: string; - // (undocumented) - prepend?: string; - // (undocumented) - startDelimiter?: string; -} - -// @public -export interface IPseudolocalesOptions { - // (undocumented) - [pseudoLocaleName: string]: IPseudolocaleOptions; -} - -// @internal (undocumented) -export interface _IStringPlaceholder { - // (undocumented) - suffix: string; - // (undocumented) - value: string; -} - -// @public -export interface ITypingsGenerationOptions { - exportAsDefault?: boolean; - generatedTsFolder: string; - sourceRoot?: string; -} - -// @public (undocumented) -export interface ITypingsGeneratorOptions { - // (undocumented) - exportAsDefault?: boolean; - // (undocumented) - filesToIgnore?: string[]; - // (undocumented) - generatedTsFolder: string; - // (undocumented) - srcFolder: string; - // (undocumented) - terminal?: Terminal; -} - -// @public -export class LocalizationPlugin implements Webpack.Plugin { - constructor(options: ILocalizationPluginOptions); - // @internal (undocumented) - addDefaultLocFile(locFilePath: string, locFile: _ILocFile): void; - // (undocumented) - apply(compiler: Webpack.Compiler): void; - // Warning: (ae-forgotten-export) The symbol "IStringSerialNumberData" needs to be exported by the entry point index.d.ts - // - // @internal (undocumented) - getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined; - // @internal (undocumented) - stringKeys: Map; - } - -// @internal (undocumented) -export class _LocFileParser { - // (undocumented) - static parseLocFile(options: _IParseLocFileOptions): _ILocFile; - // (undocumented) - static parseLocFileFromLoader(content: string, loaderContext: loader.LoaderContext): _ILocFile; -} - -// @public -export class TypingsGenerator extends StringValuesTypingsGenerator { - constructor(options: ITypingsGeneratorOptions); - } - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/localization-utilities.api.md b/common/reviews/api/localization-utilities.api.md new file mode 100644 index 00000000000..d42a0efbf98 --- /dev/null +++ b/common/reviews/api/localization-utilities.api.md @@ -0,0 +1,115 @@ +## API Report File for "@rushstack/localization-utilities" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { IExportAsDefaultOptions } from '@rushstack/typings-generator'; +import type { ITerminal } from '@rushstack/terminal'; +import { ITypingsGeneratorBaseOptions } from '@rushstack/typings-generator'; +import { NewlineKind } from '@rushstack/node-core-library'; +import { StringValuesTypingsGenerator } from '@rushstack/typings-generator'; + +// @public +export function getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string; + +// @public (undocumented) +export type IgnoreStringFunction = (filePath: string, stringName: string) => boolean; + +// @public (undocumented) +export interface IInferInterfaceNameExportAsDefaultOptions extends Omit { + inferInterfaceNameFromFilename?: boolean; +} + +// @public (undocumented) +export interface ILocalizationFile { + // (undocumented) + [stringName: string]: ILocalizedString; +} + +// @public (undocumented) +export interface ILocalizedString { + // (undocumented) + comment?: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export interface IParseFileOptions { + // (undocumented) + content: string; + // (undocumented) + filePath: string; + ignoreString?: IgnoreStringFunction; +} + +// @public (undocumented) +export interface IParseLocFileOptions extends IParseFileOptions, IParseResxOptionsBase { + // (undocumented) + parser?: ParserKind; +} + +// @public (undocumented) +export interface IParseResxOptions extends IParseFileOptions, IParseResxOptionsBase { +} + +// @public (undocumented) +export interface IParseResxOptionsBase { + // (undocumented) + ignoreMissingResxComments: boolean | undefined; + // (undocumented) + resxNewlineNormalization: NewlineKind | undefined; + // (undocumented) + terminal: ITerminal; +} + +// @public +export interface IPseudolocaleOptions { + // (undocumented) + append?: string; + // (undocumented) + delimiter?: string; + // (undocumented) + endDelimiter?: string; + // (undocumented) + extend?: number; + // (undocumented) + override?: string; + // (undocumented) + prepend?: string; + // (undocumented) + startDelimiter?: string; +} + +// @public (undocumented) +export interface ITypingsGeneratorOptions extends ITypingsGeneratorBaseOptions { + exportAsDefault?: boolean | IExportAsDefaultOptions | IInferInterfaceNameExportAsDefaultOptions; + ignoreMissingResxComments?: boolean | undefined; + ignoreString?: IgnoreStringFunction; + processComment?: (comment: string | undefined, relativeFilePath: string, stringName: string) => string | undefined; + resxNewlineNormalization?: NewlineKind | undefined; + trimmedJsonOutputFolders?: string[] | undefined; +} + +// @public (undocumented) +export function parseLocFile(options: IParseLocFileOptions): ILocalizationFile; + +// @public (undocumented) +export function parseLocJson({ content, filePath, ignoreString }: IParseFileOptions): ILocalizationFile; + +// @public (undocumented) +export function parseResJson({ content, ignoreString, filePath }: IParseFileOptions): ILocalizationFile; + +// @public (undocumented) +export function parseResx(options: IParseResxOptions): ILocalizationFile; + +// @public (undocumented) +export type ParserKind = 'resx' | 'loc.json' | 'resjson'; + +// @public +export class TypingsGenerator extends StringValuesTypingsGenerator { + constructor(options: ITypingsGeneratorOptions); +} + +``` diff --git a/common/reviews/api/lookup-by-path.api.md b/common/reviews/api/lookup-by-path.api.md new file mode 100644 index 00000000000..66336af9e63 --- /dev/null +++ b/common/reviews/api/lookup-by-path.api.md @@ -0,0 +1,72 @@ +## API Report File for "@rushstack/lookup-by-path" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @beta +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 IPrefixMatch { + index: number; + lastMatch?: IPrefixMatch; + value: TItem; +} + +// @beta +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, 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; + // (undocumented) + get tree(): IReadonlyPathTrieNode; +} + +// @beta +export interface IReadonlyPathTrieNode { + readonly children: ReadonlyMap> | undefined; + readonly value: TItem | undefined; +} + +// @beta +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; + entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + findChildPath(childPath: string, delimiter?: string): TItem | undefined; + findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined; + findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch | undefined; + 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, delimiter?: string): this; + setItemFromSegments(pathSegments: Iterable, value: TItem): this; + get size(): number; + // (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 new file mode 100644 index 00000000000..e4aa1c13a60 --- /dev/null +++ b/common/reviews/api/module-minifier.api.md @@ -0,0 +1,131 @@ +## API Report File for "@rushstack/module-minifier" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import { MinifyOptions } from 'terser'; +import type { RawSourceMap } from 'source-map'; +import type { ResourceLimits } from 'node:worker_threads'; +import type * as WorkerThreads from 'node:worker_threads'; + +// @public +export function getIdentifier(ordinal: number): string; + +// @public +export interface ILocalMinifierOptions { + // (undocumented) + terserOptions?: MinifyOptions; +} + +// @public +export interface IMinifierConnection { + configHash: string; + // @deprecated (undocumented) + disconnect(): Promise; + disconnectAsync(): Promise; +} + +// @public +export interface IModuleMinificationCallback { + // (undocumented) + (result: IModuleMinificationResult): void; +} + +// @public +export interface IModuleMinificationErrorResult { + code?: undefined; + error: Error; + hash: string; + map?: undefined; +} + +// @public +export interface IModuleMinificationRequest { + code: string; + externals: string[] | undefined; + hash: string; + nameForMap: string | undefined; +} + +// @public +export type IModuleMinificationResult = IModuleMinificationErrorResult | IModuleMinificationSuccessResult; + +// @public +export interface IModuleMinificationSuccessResult { + code: string; + error: undefined; + hash: string; + map?: RawSourceMap; +} + +// @public +export interface IModuleMinifier { + // @deprecated (undocumented) + connect(): Promise; + connectAsync(): Promise; + minify: IModuleMinifierFunction; +} + +// @public +export interface IModuleMinifierFunction { + // (undocumented) + (request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; +} + +// @public +export interface IWorkerPoolMinifierOptions { + maxThreads?: number; + terserOptions?: MinifyOptions; + verbose?: boolean; + workerResourceLimits?: ResourceLimits; +} + +// @public +export class LocalMinifier implements IModuleMinifier { + constructor(options: ILocalMinifierOptions); + // @deprecated (undocumented) + connect(): Promise; + connectAsync(): Promise; + minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; +} + +// @public +export class MessagePortMinifier implements IModuleMinifier { + constructor(port: WorkerThreads.MessagePort); + // @deprecated (undocumented) + connect(): Promise; + connectAsync(): Promise; + minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; + // (undocumented) + readonly port: WorkerThreads.MessagePort; +} + +export { MinifyOptions } + +// @internal +export function _minifySingleFileAsync(request: IModuleMinificationRequest, terserOptions: MinifyOptions): Promise; + +// @public +export class NoopMinifier implements IModuleMinifier { + // @deprecated (undocumented) + connect(): Promise; + connectAsync(): Promise; + minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; +} + +// @public +export class WorkerPoolMinifier implements IModuleMinifier { + constructor(options: IWorkerPoolMinifierOptions); + // @deprecated (undocumented) + connect(): Promise; + connectAsync(): Promise; + // (undocumented) + get maxThreads(): number; + set maxThreads(threads: number); + minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; +} + +``` diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index ccbf76b9de9..cc01c92c873 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -4,105 +4,122 @@ ```ts -import * as child_process from 'child_process'; -import * as fs from 'fs'; +/// -// @beta -export class Colors { - // (undocumented) - static black(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static blackBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static blink(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static blue(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static blueBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static bold(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static cyan(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static cyanBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static dim(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static gray(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static grayBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static green(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static greenBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static hidden(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static invertColor(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static magenta(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static magentaBackground(text: string | IColorableSequence): IColorableSequence; - // @internal - static _normalizeStringOrColorableSequence(value: string | IColorableSequence): IColorableSequence; - // (undocumented) - static red(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static redBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static underline(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static white(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static whiteBackground(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static yellow(text: string | IColorableSequence): IColorableSequence; - // (undocumented) - static yellowBackground(text: string | IColorableSequence): IColorableSequence; +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as nodePath from 'node:path'; + +// @public +export enum AlreadyExistsBehavior { + Error = "error", + Ignore = "ignore", + Overwrite = "overwrite" } -// @beta -export enum ColorValue { - // (undocumented) - Black = 0, - // (undocumented) - Blue = 4, - // (undocumented) - Cyan = 6, - // (undocumented) - Gray = 8, - // (undocumented) - Green = 2, - // (undocumented) - Magenta = 5, - // (undocumented) - Red = 1, +// @public +export class AlreadyReportedError extends Error { // (undocumented) - White = 7, + static [Symbol.hasInstance](instance: object): boolean; + 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 & { + weighted?: false; + }) | undefined): Promise; + static forEachAsync(iterable: Iterable | AsyncIterable, callback: (entry: TEntry, arrayIndex: number) => Promise, options: IAsyncParallelismOptions & { + weighted: true; + }): Promise; + static getSignal(): [Promise, () => void, (err: Error) => void]; + static mapAsync(iterable: Iterable | AsyncIterable, callback: (entry: TEntry, arrayIndex: number) => Promise, options?: (IAsyncParallelismOptions & { + weighted?: false; + }) | undefined): Promise; + static mapAsync(iterable: Iterable | AsyncIterable, callback: (entry: TEntry, arrayIndex: number) => Promise, options: IAsyncParallelismOptions & { + weighted: true; + }): Promise; + static runWithRetriesAsync({ action, maxRetries, retryDelayMs }: IRunWithRetriesOptions): Promise; + static runWithTimeoutAsync({ action, timeoutMs, timeoutMessage }: IRunWithTimeoutOptions): Promise; + static sleepAsync(ms: number): Promise; + static validateWeightedIterable(operation: IWeighted): void; +} + +// @public +export class AsyncQueue implements AsyncIterable<[T, () => void]> { // (undocumented) - Yellow = 3 + [Symbol.asyncIterator](): AsyncIterableIterator<[T, () => void]>; + constructor(iterable?: Iterable); + push(item: T): void; } -// @beta -export class ConsoleTerminalProvider implements ITerminalProvider { - constructor(options?: Partial); - readonly eolCharacter: string; - readonly supportsColor: boolean; - verboseEnabled: boolean; - write(data: string, severity: TerminalProviderSeverity): void; +// @public +export type Brand = T & { + __brand: BrandTag; +}; + +declare namespace Disposables { + export { + polyfillDisposeSymbols + } } +export { Disposables } // @public -export const enum Encoding { +export enum Encoding { // (undocumented) Utf8 = "utf8" } +// @public +export class Enum { + static getKeyByNumber(enumObject: TEnumObject, value: number): keyof typeof enumObject; + static getValueByKey(enumObject: { + [key: string]: TEnumValue | string; + [key: number]: TEnumValue | string; + }, key: string): TEnumValue; + static tryGetKeyByNumber(enumObject: TEnumObject, value: number): keyof typeof enumObject | undefined; + static tryGetValueByKey(enumObject: { + [key: string]: TEnumValue | string; + [key: number]: TEnumValue | string; + }, key: string): TEnumValue | undefined; +} + +// @public +export class EnvironmentMap { + constructor(environmentObject?: Record); + readonly caseSensitive: boolean; + clear(): void; + entries(): IterableIterator; + get(name: string): string | undefined; + mergeFrom(environmentMap: EnvironmentMap): void; + mergeFromObject(environmentObject?: Record): void; + names(): IterableIterator; + set(name: string, value: string): void; + toObject(): Record; + unset(name: string): void; +} + // @public export class Executable { + static getProcessInfoById(): Map; + static getProcessInfoByIdAsync(): Promise>; + static getProcessInfoByName(): Map; + static getProcessInfoByNameAsync(): Promise>; + static spawn(filename: string, args: string[], options?: IExecutableSpawnOptions): child_process.ChildProcess; static spawnSync(filename: string, args: string[], options?: IExecutableSpawnSyncOptions): child_process.SpawnSyncReturns; 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; +} // @public export type ExecutableStdioMapping = 'pipe' | 'ignore' | 'inherit' | ExecutableStdioStreamMapping[]; @@ -111,73 +128,158 @@ export type ExecutableStdioMapping = 'pipe' | 'ignore' | 'inherit' | ExecutableS export type ExecutableStdioStreamMapping = 'pipe' | 'ignore' | 'inherit' | NodeJS.WritableStream | NodeJS.ReadableStream | number | undefined; // @public -export const enum FileConstants { - PackageJson = "package.json" +export const FileConstants: { + readonly PackageJson: "package.json"; +}; + +// @public +export class FileError extends Error { + // (undocumented) + static [Symbol.hasInstance](instance: object): boolean; + constructor(message: string, options: IFileErrorOptions); + readonly absolutePath: string; + readonly column: number | undefined; + // @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; } +// @public +export type FileLocationStyle = 'Unix' | 'VisualStudio'; + // @public export class FileSystem { static appendToFile(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): void; - static changePosixModeBits(path: string, mode: PosixModeBits): void; + static appendToFileAsync(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): Promise; + static changePosixModeBits(path: string, modeBits: PosixModeBits): void; + static changePosixModeBitsAsync(path: string, mode: PosixModeBits): Promise; static copyFile(options: IFileSystemCopyFileOptions): void; + static copyFileAsync(options: IFileSystemCopyFileOptions): Promise; + static copyFiles(options: IFileSystemCopyFilesOptions): void; + static copyFilesAsync(options: IFileSystemCopyFilesAsyncOptions): Promise; static createHardLink(options: IFileSystemCreateLinkOptions): void; + static createHardLinkAsync(options: IFileSystemCreateLinkOptions): Promise; 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 deleteFile(filePath: string, options?: IFileSystemDeleteFileOptions): void; + static deleteFileAsync(filePath: string, options?: IFileSystemDeleteFileOptions): Promise; static deleteFolder(folderPath: string): void; + static deleteFolderAsync(folderPath: string): Promise; static ensureEmptyFolder(folderPath: string): void; + static ensureEmptyFolderAsync(folderPath: string): Promise; static ensureFolder(folderPath: string): void; + static ensureFolderAsync(folderPath: string): Promise; static exists(path: string): boolean; + static existsAsync(path: string): Promise; static formatPosixModeBits(modeBits: PosixModeBits): string; - static getLinkStatistics(path: string): fs.Stats; + static getLinkStatistics(path: string): FileSystemStats; + static getLinkStatisticsAsync(path: string): Promise; static getPosixModeBits(path: string): PosixModeBits; + static getPosixModeBitsAsync(path: string): Promise; static getRealPath(linkPath: string): string; - static getStatistics(path: string): fs.Stats; + static getRealPathAsync(linkPath: string): Promise; + static getStatistics(path: string): FileSystemStats; + static getStatisticsAsync(path: string): Promise; + static isDirectoryError(error: Error): boolean; + static isErrnoException(error: Error): error is NodeJS.ErrnoException; + static isExistError(error: Error): boolean; + static isFileDoesNotExistError(error: Error): boolean; + static isFolderDoesNotExistError(error: Error): boolean; + static isNotDirectoryError(error: Error): boolean; + static isNotExistError(error: Error): boolean; + static isUnlinkNotPermittedError(error: Error): boolean; static move(options: IFileSystemMoveOptions): void; + static moveAsync(options: IFileSystemMoveOptions): Promise; static readFile(filePath: string, options?: IFileSystemReadFileOptions): string; + static readFileAsync(filePath: string, options?: IFileSystemReadFileOptions): Promise; static readFileToBuffer(filePath: string): Buffer; - static readFolder(folderPath: string, options?: IFileSystemReadFolderOptions): string[]; + static readFileToBufferAsync(filePath: string): Promise; + static readFolderItemNames(folderPath: string, options?: IFileSystemReadFolderOptions): string[]; + static readFolderItemNamesAsync(folderPath: string, options?: IFileSystemReadFolderOptions): Promise; + static readFolderItems(folderPath: string, options?: IFileSystemReadFolderOptions): FolderItem[]; + static readFolderItemsAsync(folderPath: string, options?: IFileSystemReadFolderOptions): Promise; + static readLink(path: string): string; + 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 writeFile(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): void; + static writeFileAsync(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): Promise; } +// @public +export type FileSystemCopyFilesAsyncFilter = (sourcePath: string, destinationPath: string) => Promise; + +// @public +export type FileSystemCopyFilesFilter = (sourcePath: string, destinationPath: string) => boolean; + +// @public +export type FileSystemStats = fs.Stats; + // @public export class FileWriter { close(): void; - static open(path: string, flags?: IFileWriterFlags): FileWriter; + readonly filePath: string; + getStatistics(): FileSystemStats; + static open(filePath: string, flags?: IFileWriterFlags): FileWriter; write(text: string): void; } // @public -export const enum FolderConstants { - Git = ".git", - NodeModules = "node_modules" +export const FolderConstants: { + readonly Git: ".git"; + readonly NodeModules: "node_modules"; +}; + +// @public +export type FolderItem = fs.Dirent; + +// @public +function getHomeFolder(): string; + +// @public +export interface IAsyncParallelismOptions { + allowOversubscription?: boolean; + concurrency?: number; + weighted?: boolean; } -// @beta (undocumented) -export interface IColorableSequence { - // (undocumented) - backgroundColor?: ColorValue; - // (undocumented) - foregroundColor?: ColorValue; - // (undocumented) - isEol?: boolean; - // (undocumented) - text: string; +// @public +export interface IDependenciesMetaTable { // (undocumented) - textAttributes?: TextAttribute[]; + [dependencyName: string]: { + injected?: boolean; + }; } -// @beta -export interface IConsoleTerminalProviderOptions { - verboseEnabled: boolean; +// @public +export interface IEnvironmentEntry { + name: string; + value: string; } // @public export interface IExecutableResolveOptions { currentWorkingDirectory?: string; environment?: NodeJS.ProcessEnv; + environmentMap?: EnvironmentMap; +} + +// @public +export interface IExecutableSpawnOptions extends IExecutableResolveOptions { + stdio?: ExecutableStdioMapping; } // @public @@ -189,13 +291,47 @@ export interface IExecutableSpawnSyncOptions extends IExecutableResolveOptions { } // @public -export interface IFileSystemCopyFileOptions { +export interface IFileErrorFormattingOptions { + format?: FileLocationStyle; +} + +// @public +export interface IFileErrorOptions { + absolutePath: string; + column?: number; + line?: number; + projectFolder: string; +} + +// @public (undocumented) +export interface IFileSystemCopyFileBaseOptions { + alreadyExistsBehavior?: AlreadyExistsBehavior; + sourcePath: string; +} + +// @public +export interface IFileSystemCopyFileOptions extends IFileSystemCopyFileBaseOptions { + destinationPath: string; +} + +// @public +export interface IFileSystemCopyFilesAsyncOptions { + alreadyExistsBehavior?: AlreadyExistsBehavior; + dereferenceSymlinks?: boolean; destinationPath: string; + filter?: FileSystemCopyFilesAsyncFilter | FileSystemCopyFilesFilter; + preserveTimestamps?: boolean; sourcePath: string; } +// @public +export interface IFileSystemCopyFilesOptions extends IFileSystemCopyFilesAsyncOptions { + filter?: FileSystemCopyFilesFilter; +} + // @public export interface IFileSystemCreateLinkOptions { + alreadyExistsBehavior?: AlreadyExistsBehavior; linkTargetPath: string; newLinkPath: string; } @@ -231,10 +367,14 @@ export interface IFileSystemUpdateTimeParameters { } // @public -export interface IFileSystemWriteFileOptions { +export interface IFileSystemWriteBinaryFileOptions { + ensureFolderExists?: boolean; +} + +// @public +export interface IFileSystemWriteFileOptions extends IFileSystemWriteBinaryFileOptions { convertLineEndings?: NewlineKind; encoding?: Encoding; - ensureFolderExists?: boolean; } // @public @@ -243,6 +383,49 @@ export interface IFileWriterFlags { exclusive?: boolean; } +// @public +export interface IImportResolveAsyncOptions extends IImportResolveOptions { + getRealPathAsync?: (filePath: string) => Promise; +} + +// @public +export interface IImportResolveModuleAsyncOptions extends IImportResolveAsyncOptions { + modulePath: string; +} + +// @public +export interface IImportResolveModuleOptions extends IImportResolveOptions { + modulePath: string; +} + +// @public +export interface IImportResolveOptions { + allowSelfReference?: boolean; + baseFolderPath: string; + getRealPath?: (filePath: string) => string; + includeSystemModules?: boolean; +} + +// @public +export interface IImportResolvePackageAsyncOptions extends IImportResolveAsyncOptions { + packageName: string; +} + +// @public +export interface IImportResolvePackageOptions extends IImportResolveOptions { + packageName: string; + useNodeJSResolver?: boolean; +} + +// @public +export interface IJsonFileLoadAndValidateOptions extends IJsonFileParseOptions, IJsonSchemaValidateOptions { +} + +// @public +export interface IJsonFileParseOptions { + jsonSyntax?: JsonSyntax; +} + // @public export interface IJsonFileSaveOptions extends IJsonFileStringifyOptions { ensureFolderExists?: boolean; @@ -251,44 +434,80 @@ export interface IJsonFileSaveOptions extends IJsonFileStringifyOptions { } // @public -export interface IJsonFileStringifyOptions { +export interface IJsonFileStringifyOptions extends IJsonFileParseOptions { + headerComment?: string; + ignoreUndefinedValues?: boolean; newlineConversion?: NewlineKind; prettyFormatting?: boolean; } +// @public +export interface IJsonSchemaCustomFormat { + type: T extends string ? 'string' : T extends number ? 'number' : never; + validate: (data: T) => boolean; +} + // @public export interface IJsonSchemaErrorInfo { details: string; } // @public -export interface IJsonSchemaFromFileOptions { +export type IJsonSchemaFromFileOptions = IJsonSchemaLoadOptions; + +// @public +export type IJsonSchemaFromObjectOptions = IJsonSchemaLoadOptions; + +// @public +export interface IJsonSchemaLoadOptions { + customFormats?: Record | IJsonSchemaCustomFormat>; dependentSchemas?: JsonSchema[]; + schemaVersion?: JsonSchemaVersion; +} + +// @public +export interface IJsonSchemaValidateObjectWithOptions { + ignoreSchemaField?: boolean; } // @public -export interface IJsonSchemaValidateOptions { +export interface IJsonSchemaValidateOptions extends IJsonSchemaValidateObjectWithOptions { customErrorHeader?: string; } +// @public +export class Import { + static lazy(moduleName: string, require: (id: string) => unknown): any; + static resolveModule(options: IImportResolveModuleOptions): string; + static resolveModuleAsync(options: IImportResolveModuleAsyncOptions): Promise; + static resolvePackage(options: IImportResolvePackageOptions): string; + static resolvePackageAsync(options: IImportResolvePackageAsyncOptions): Promise; +} + // @public export interface INodePackageJson { - bin?: string; + bin?: string | Record; dependencies?: IPackageJsonDependencyTable; + dependenciesMeta?: IDependenciesMetaTable; description?: string; devDependencies?: IPackageJsonDependencyTable; + exports?: string | string[] | Record; + files?: string[]; homepage?: string; license?: string; main?: string; name: string; optionalDependencies?: IPackageJsonDependencyTable; peerDependencies?: IPackageJsonDependencyTable; + peerDependenciesMeta?: IPeerDependenciesMetaTable; private?: boolean; - repository?: string; + repository?: string | IPackageJsonRepository; + resolutions?: Record; scripts?: IPackageJsonScriptTable; // @beta tsdocMetadata?: string; types?: string; + typesVersions?: Record>; typings?: string; version?: string; } @@ -312,16 +531,41 @@ export interface IPackageJsonDependencyTable { [dependencyName: string]: string; } +// @public +export interface IPackageJsonExports { + 'node-addons'?: string | IPackageJsonExports; + browser?: string | IPackageJsonExports; + default?: string | IPackageJsonExports; + development?: string | IPackageJsonExports; + import?: string | IPackageJsonExports; + node?: string | IPackageJsonExports; + production?: string | IPackageJsonExports; + require?: string | IPackageJsonExports; + types?: string | IPackageJsonExports; +} + // @public export interface IPackageJsonLookupParameters { loadExtraFields?: boolean; } +// @public +export interface IPackageJsonRepository { + directory?: string; + type: string; + url: string; +} + // @public export interface IPackageJsonScriptTable { [scriptName: string]: string; } +// @public +export interface IPackageNameParserOptions { + allowUpperCase?: boolean; +} + // @public export interface IParsedPackageName { scope: string; @@ -333,6 +577,54 @@ export interface IParsedPackageNameOrError extends IParsedPackageName { error: string; } +// @public +export interface IPathFormatConciselyOptions { + baseFolder: string; + pathToConvert: string; + trimLeadingDotSlash?: boolean; +} + +// @public +export interface IPathFormatFileLocationOptions { + baseFolder?: string; + column?: number; + format: FileLocationStyle; + line?: number; + message: string; + pathToFormat: string; +} + +// @public +export interface IPeerDependenciesMetaTable { + // (undocumented) + [dependencyName: string]: { + optional?: boolean; + }; +} + +// @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[]; + parentProcessInfo: IProcessInfo | undefined; + processId: number; + processName: string; +} + // @public export interface IProtectableMapParameters { onClear?: (source: ProtectableMap) => void; @@ -340,6 +632,35 @@ export interface IProtectableMapParameters { onSet?: (source: ProtectableMap, key: K, value: V) => V; } +// @public +export interface IReadLinesFromIterableOptions { + encoding?: Encoding; + ignoreEmptyLines?: boolean; +} + +// @public +export interface IRealNodeModulePathResolverOptions { + // (undocumented) + fs?: Partial>; + ignoreMissingPaths?: boolean; + // (undocumented) + path?: Partial>; +} + +// @public (undocumented) +export interface IRunWithRetriesOptions { + action: (retryCount: number) => Promise | TResult; + maxRetries: number; + retryDelayMs?: number; +} + +// @public (undocumented) +export interface IRunWithTimeoutOptions { + action: () => Promise | TResult; + timeoutMessage?: string; + timeoutMs: number; +} + // @public export interface IStringBuilder { append(text: string): void; @@ -347,22 +668,64 @@ export interface IStringBuilder { } // @beta -export interface ITerminalProvider { - eolCharacter: string; - supportsColor: boolean; - write(data: string, severity: TerminalProviderSeverity): void; +export interface ISubprocessOptions { + detached: boolean; +} + +// @public +export interface IWaitForExitOptions { + encoding?: BufferEncoding | 'buffer'; + throwOnNonZeroExitCode?: boolean; + throwOnSignal?: boolean; +} + +// @public +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'; +} + +// @public +export interface IWaitForExitWithStringOptions extends IWaitForExitOptions { + encoding: BufferEncoding; +} + +// @public (undocumented) +export interface IWeighted { + weight: number; } // @public export class JsonFile { - static load(jsonFilename: string): JsonObject; - static loadAndValidate(jsonFilename: string, jsonSchema: JsonSchema, options?: IJsonSchemaValidateOptions): JsonObject; - static loadAndValidateWithCallback(jsonFilename: string, jsonSchema: JsonSchema, errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void): JsonObject; + // @internal (undocumented) + static _formatPathForError: (path: string) => string; + static load(jsonFilename: string, options?: IJsonFileParseOptions): JsonObject; + static loadAndValidate(jsonFilename: string, jsonSchema: JsonSchema, options?: IJsonFileLoadAndValidateOptions): JsonObject; + static loadAndValidateAsync(jsonFilename: string, jsonSchema: JsonSchema, options?: IJsonFileLoadAndValidateOptions): Promise; + static loadAndValidateWithCallback(jsonFilename: string, jsonSchema: JsonSchema, errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, options?: IJsonFileLoadAndValidateOptions): JsonObject; + static loadAndValidateWithCallbackAsync(jsonFilename: string, jsonSchema: JsonSchema, errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, options?: IJsonFileLoadAndValidateOptions): Promise; + static loadAsync(jsonFilename: string, options?: IJsonFileParseOptions): Promise; + static parseString(jsonContents: string, options?: IJsonFileParseOptions): JsonObject; static save(jsonObject: JsonObject, jsonFilename: string, options?: IJsonFileSaveOptions): boolean; + static saveAsync(jsonObject: JsonObject, jsonFilename: string, options?: IJsonFileSaveOptions): Promise; static stringify(jsonObject: JsonObject, options?: IJsonFileStringifyOptions): string; static updateString(previousJson: string, newJsonObject: JsonObject, options?: IJsonFileStringifyOptions): string; static validateNoUndefinedMembers(jsonObject: JsonObject): void; - } +} + +// @public +export type JsonNull = null; // @public export type JsonObject = any; @@ -371,11 +734,21 @@ export type JsonObject = any; export class JsonSchema { ensureCompiled(): void; static fromFile(filename: string, options?: IJsonSchemaFromFileOptions): JsonSchema; - static fromLoadedObject(schemaObject: JsonObject): JsonSchema; - readonly shortName: string; + static fromLoadedObject(schemaObject: JsonObject, options?: IJsonSchemaFromObjectOptions): JsonSchema; + get shortName(): string; validateObject(jsonObject: JsonObject, filenameForErrors: string, options?: IJsonSchemaValidateOptions): void; - validateObjectWithCallback(jsonObject: JsonObject, errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void): void; - } + validateObjectWithCallback(jsonObject: JsonObject, errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, options?: IJsonSchemaValidateObjectWithOptions): void; +} + +// @public +export type JsonSchemaVersion = 'draft-04' | 'draft-07'; + +// @public +export enum JsonSyntax { + Json5 = "json5", + JsonWithComments = "jsonWithComments", + Strict = "strict" +} // @public export class LegacyAdapters { @@ -389,39 +762,60 @@ export class LegacyAdapters { // (undocumented) static convertCallbackToPromise(fn: (arg1: TArg1, arg2: TArg2, arg3: TArg3, arg4: TArg4, cb: LegacyCallback) => void, arg1: TArg1, arg2: TArg2, arg3: TArg3, arg4: TArg4): Promise; static scrubError(error: Error | string | any): Error; - static sortStable(array: T[], compare?: (a: T, b: T) => number): void; - } +} // @public export type LegacyCallback = (error: TError | null | undefined, result: TResult) => void; // @public export class LockFile { - static acquire(resourceDir: string, resourceName: string, maxWaitMs?: number): Promise; - readonly dirtyWhenAcquired: boolean; - readonly filePath: string; - static getLockFilePath(resourceDir: string, resourceName: string, pid?: number): string; - readonly isReleased: boolean; - release(): void; - static tryAcquire(resourceDir: string, resourceName: string): LockFile | undefined; - } + // @deprecated (undocumented) + static acquire(resourceFolder: string, resourceName: string, maxWaitMs?: number): Promise; + static acquireAsync(resourceFolder: string, resourceName: string, maxWaitMs?: number): Promise; + get dirtyWhenAcquired(): boolean; + get filePath(): string; + static getLockFilePath(resourceFolder: string, resourceName: string, pid?: number): string; + get isReleased(): boolean; + release(deleteFile?: boolean): void; + static tryAcquire(resourceFolder: string, resourceName: string): LockFile | undefined; +} // @public export class MapExtensions { static mergeFromMap(targetMap: Map, sourceMap: ReadonlyMap): void; + static toObject(map: Map): { + [key: string]: TValue; + }; +} + +// @public +export class MinimumHeap { + constructor(comparator: (a: T, b: T) => number); + peek(): T | undefined; + poll(): T | undefined; + push(item: T): void; + get size(): number; } // @public -export const enum NewlineKind { +export enum NewlineKind { CrLf = "\r\n", Lf = "\n", OsDefault = "os" } +declare namespace Objects { + export { + areDeepEqual + } +} +export { Objects } + // @public export class PackageJsonLookup { constructor(parameters?: IPackageJsonLookupParameters); clearCache(): void; + static get instance(): PackageJsonLookup; loadNodePackageJson(jsonFilename: string): INodePackageJson; static loadOwnPackageJson(dirnameOfCaller: string): IPackageJson; loadPackageJson(jsonFilename: string): IPackageJson; @@ -442,14 +836,36 @@ export class PackageName { static validate(packageName: string): void; } +// @public +export class PackageNameParser { + constructor(options?: IPackageNameParserOptions); + combineParts(scope: string, unscopedName: string): string; + getScope(packageName: string): string; + getUnscopedName(packageName: string): string; + isValidName(packageName: string): boolean; + parse(packageName: string): IParsedPackageName; + tryParse(packageName: string): IParsedPackageNameOrError; + validate(packageName: string): void; +} + // @public export class Path { + static convertToBackslashes(inputPath: string): string; + static convertToPlatformDefault(inputPath: string): string; + static convertToSlashes(inputPath: string): string; + static formatConcisely(options: IPathFormatConciselyOptions): string; + static formatFileLocation(options: IPathFormatFileLocationOptions): string; + static isDownwardRelative(inputPath: string): boolean; + static isEqual(path1: string, path2: string): boolean; static isUnder(childPath: string, parentFolderPath: string): boolean; static isUnderOrEqual(childPath: string, parentFolderPath: string): boolean; - } +} + +// @public +function polyfillDisposeSymbols(): void; // @public -export const enum PosixModeBits { +export enum PosixModeBits { AllExecute = 73, AllRead = 292, AllWrite = 146, @@ -473,34 +889,30 @@ export class ProtectableMap { forEach(callbackfn: (value: V, key: K, map: Map) => void, thisArg?: any): void; get(key: K): V | undefined; has(key: K): boolean; - readonly protectedView: Map; + get protectedView(): Map; set(key: K, value: V): this; - readonly size: number; + get size(): number; +} + +// @public +export class RealNodeModulePathResolver { + constructor(options?: IRealNodeModulePathResolverOptions); + clearCache(): void; + readonly realNodeModulePath: (input: string) => string; } // @public export class Sort { static compareByValue(x: any, y: any): number; - static isSorted(array: T[], comparer?: (x: any, y: any) => number): boolean; - static isSortedBy(array: T[], keySelector: (element: T) => any, comparer?: (x: any, y: any) => number): boolean; + static isSorted(collection: Iterable, comparer?: (x: any, y: any) => number): boolean; + static isSortedBy(collection: Iterable, keySelector: (element: T) => any, comparer?: (x: any, y: any) => number): boolean; static sortBy(array: T[], keySelector: (element: T) => any, comparer?: (x: any, y: any) => number): void; + static sortKeys> | unknown[]>(object: T): T; static sortMapKeys(map: Map, keyComparer?: (x: K, y: K) => number): void; static sortSet(set: Set, comparer?: (x: T, y: T) => number): void; static sortSetBy(set: Set, keySelector: (element: T) => any, keyComparer?: (x: T, y: T) => number): void; } -// @beta -export class StringBufferTerminalProvider implements ITerminalProvider { - constructor(supportsColor?: boolean); - readonly eolCharacter: string; - getErrorOutput(): string; - getOutput(): string; - getVerbose(): string; - getWarningOutput(): string; - readonly supportsColor: boolean; - write(data: string, severity: TerminalProviderSeverity): void; -} - // @public export class StringBuilder implements IStringBuilder { constructor(); @@ -509,30 +921,10 @@ export class StringBuilder implements IStringBuilder { } // @beta -export class Terminal { - constructor(provider: ITerminalProvider); - registerProvider(provider: ITerminalProvider): void; - unregisterProvider(provider: ITerminalProvider): void; - write(...messageParts: (string | IColorableSequence)[]): void; - writeError(...messageParts: (string | IColorableSequence)[]): void; - writeErrorLine(...messageParts: (string | IColorableSequence)[]): void; - writeLine(...messageParts: (string | IColorableSequence)[]): void; - writeVerbose(...messageParts: (string | IColorableSequence)[]): void; - writeVerboseLine(...messageParts: (string | IColorableSequence)[]): void; - writeWarning(...messageParts: (string | IColorableSequence)[]): void; - writeWarningLine(...messageParts: (string | IColorableSequence)[]): void; -} - -// @beta (undocumented) -export enum TerminalProviderSeverity { - // (undocumented) - error = 2, - // (undocumented) - log = 0, - // (undocumented) - verbose = 3, - // (undocumented) - warning = 1 +export class SubprocessTerminator { + static killProcessTree(subprocess: child_process.ChildProcess, subprocessOptions: ISubprocessOptions): void; + static killProcessTreeOnExit(subprocess: child_process.ChildProcess, subprocessOptions: ISubprocessOptions): void; + static readonly RECOMMENDED_OPTIONS: ISubprocessOptions; } // @public @@ -541,27 +933,33 @@ export class Text { static convertToCrLf(input: string): string; static convertToLf(input: string): string; static ensureTrailingNewline(s: string, newlineKind?: NewlineKind): string; + static escapeRegExp(literal: string): string; + static getNewline(newlineKind: NewlineKind): string; static padEnd(s: string, minimumLength: number, paddingCharacter?: string): string; static padStart(s: string, minimumLength: number, paddingCharacter?: string): string; + static readLinesFromIterable(iterable: Iterable, options?: IReadLinesFromIterableOptions): Generator; + static readLinesFromIterableAsync(iterable: AsyncIterable, options?: IReadLinesFromIterableOptions): AsyncGenerator; static replaceAll(input: string, searchValue: string, replaceValue: string): string; + static reverse(s: string): string; + static splitByNewLines(s: undefined): undefined; + // (undocumented) + static splitByNewLines(s: string): string[]; + // (undocumented) + static splitByNewLines(s: string | undefined): string[] | undefined; static truncateWithEllipsis(s: string, maximumLength: number): string; } -// @beta -export enum TextAttribute { - // (undocumented) - Blink = 3, - // (undocumented) - Bold = 0, - // (undocumented) - Dim = 1, - // (undocumented) - Hidden = 5, - // (undocumented) - InvertColor = 4, - // (undocumented) - Underline = 2 +// @public +export class TypeUuid { + static isInstanceOf(targetObject: unknown, typeUuid: string): boolean; + static registerClass(targetClass: any, typeUuid: string): void; } +declare namespace User { + export { + getHomeFolder + } +} +export { User } ``` diff --git a/common/reviews/api/node-library-build.api.md b/common/reviews/api/node-library-build.api.md deleted file mode 100644 index 3e5437231de..00000000000 --- a/common/reviews/api/node-library-build.api.md +++ /dev/null @@ -1,32 +0,0 @@ -## API Report File for "@microsoft/node-library-build" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { CopyTask } from '@microsoft/gulp-core-build'; -import { IExecutable } from '@microsoft/gulp-core-build'; - -// @public (undocumented) -export const buildTasks: IExecutable; - -// @public (undocumented) -export const defaultTasks: IExecutable; - -// @public (undocumented) -export const postCopy: CopyTask; - -// @public (undocumented) -export const preCopy: CopyTask; - -// @public (undocumented) -export const testTasks: IExecutable; - - -export * from "@microsoft/gulp-core-build"; -export * from "@microsoft/gulp-core-build-mocha"; -export * from "@microsoft/gulp-core-build-typescript"; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/operation-graph.api.md b/common/reviews/api/operation-graph.api.md new file mode 100644 index 00000000000..261057fb62a --- /dev/null +++ b/common/reviews/api/operation-graph.api.md @@ -0,0 +1,258 @@ +## API Report File for "@rushstack/operation-graph" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import type { ITerminal } from '@rushstack/terminal'; + +// @beta +export type CommandMessageFromHost = ICancelCommandMessage | IExitCommandMessage | IRunCommandMessage | ISyncCommandMessage; + +// @beta +export type EventMessageFromClient = IRequestRunEventMessage | IAfterExecuteEventMessage | ISyncEventMessage; + +// @beta +export interface IAfterExecuteEventMessage { + // (undocumented) + event: 'after-execute'; + // (undocumented) + status: OperationStatus; +} + +// @beta +export interface ICancelCommandMessage { + // (undocumented) + command: 'cancel'; +} + +// @beta +export interface IExecuteOperationContext extends Omit { + afterExecute(operation: Operation, state: IOperationState): void; + beforeExecute(operation: Operation, state: IOperationState): void; + queueWork(workFn: () => Promise, priority: number): Promise; + requestRun?: OperationRequestRunCallback; + terminal: ITerminal; +} + +// @beta +export interface IExitCommandMessage { + // (undocumented) + command: 'exit'; +} + +// @beta +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?: OperationRequestRunCallback; + // (undocumented) + terminal: ITerminal; +} + +// @beta +export interface IOperationOptions { + group?: OperationGroupRecord | undefined; + metadata?: TMetadata | undefined; + name: string; + runner?: IOperationRunner | undefined; + weight?: number | undefined; +} + +// @beta +export interface IOperationRunner { + executeAsync(context: IOperationRunnerContext): Promise; + readonly name: string; + silent: boolean; +} + +// @beta +export interface IOperationRunnerContext { + abortSignal: AbortSignal; + isFirstRun: boolean; + requestRun?: (detail?: string) => void; +} + +// @beta +export interface IOperationState { + error: OperationError | undefined; + hasBeenRun: boolean; + status: OperationStatus; + stopwatch: Stopwatch; +} + +// @beta +export interface IOperationStates { + readonly lastState: Readonly | undefined; + readonly state: Readonly | undefined; +} + +// @beta +export type IPCHost = Pick; + +// @beta +export interface IRequestRunEventMessage { + detail?: string; + // (undocumented) + event: 'requestRun'; + requestor: string; +} + +// @beta +export interface IRunCommandMessage { + // (undocumented) + command: 'run'; +} + +// @beta +export interface ISyncCommandMessage { + // (undocumented) + command: 'sync'; +} + +// @beta +export interface ISyncEventMessage { + // (undocumented) + event: 'sync'; + // (undocumented) + status: OperationStatus; +} + +// @beta +export interface IWatchLoopOptions { + executeAsync: (state: IWatchLoopState) => Promise; + onAbort: () => void; + onBeforeExecute: () => void; + onRequestRun: OperationRequestRunCallback; +} + +// @beta +export interface IWatchLoopState { + // (undocumented) + get abortSignal(): AbortSignal; + // (undocumented) + requestRun: OperationRequestRunCallback; +} + +// @beta +export class Operation implements IOperationStates { + constructor(options: IOperationOptions); + // (undocumented) + addDependency(dependency: Operation): void; + readonly consumers: Set>; + criticalPathLength: number | undefined; + // (undocumented) + deleteDependency(dependency: Operation): void; + readonly dependencies: Set>; + // @internal (undocumented) + _executeAsync(context: IExecuteOperationContext): Promise; + readonly group: OperationGroupRecord | undefined; + lastState: IOperationState | undefined; + // (undocumented) + readonly metadata: TMetadata; + readonly name: string; + // (undocumented) + reset(): void; + runner: IOperationRunner | undefined; + state: IOperationState | undefined; + weight: number; +} + +// @beta +export class OperationError extends Error { + constructor(type: string, message: string); + // (undocumented) + get message(): string; + // (undocumented) + toString(): string; + // (undocumented) + protected _type: string; +} + +// @beta +export class OperationExecutionManager { + constructor(operations: ReadonlySet>); + executeAsync(executionOptions: IOperationExecutionOptions): Promise; +} + +// @beta +export class OperationGroupRecord { + constructor(name: string, metadata?: TMetadata); + // (undocumented) + addOperation(operation: Operation): void; + // (undocumented) + get duration(): number; + // (undocumented) + get finished(): boolean; + // (undocumented) + get hasCancellations(): boolean; + // (undocumented) + get hasFailures(): boolean; + // (undocumented) + readonly metadata: TMetadata; + // (undocumented) + readonly name: string; + // (undocumented) + reset(): void; + // (undocumented) + setOperationAsComplete(operation: Operation, state: IOperationState): void; + // (undocumented) + startTimer(): void; +} + +// @beta +export type OperationRequestRunCallback = (requestor: string, detail?: string) => void; + +// @beta +export enum OperationStatus { + Aborted = "ABORTED", + Blocked = "BLOCKED", + Executing = "EXECUTING", + Failure = "FAILURE", + NoOp = "NO OP", + Ready = "READY", + Success = "SUCCESS", + Waiting = "WAITING" +} + +// @public +export class Stopwatch { + constructor(); + get duration(): number; + get endTime(): number | undefined; + // (undocumented) + get isRunning(): boolean; + reset(): Stopwatch; + static start(): Stopwatch; + start(): Stopwatch; + get startTime(): number | undefined; + stop(): Stopwatch; + toString(): string; +} + +// @beta +export class WatchLoop implements IWatchLoopState { + constructor(options: IWatchLoopOptions); + get abortSignal(): AbortSignal; + requestRun: OperationRequestRunCallback; + runIPCAsync(host?: IPCHost): Promise; + runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise; + runUntilStableAsync(abortSignal: AbortSignal): Promise; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/package-deps-hash.api.md b/common/reviews/api/package-deps-hash.api.md index 57bfa231984..6a18a450903 100644 --- a/common/reviews/api/package-deps-hash.api.md +++ b/common/reviews/api/package-deps-hash.api.md @@ -5,18 +5,46 @@ ```ts // @public -export function getGitHashForFiles(filesToHash: string[], packagePath: string): Map; +export function ensureGitMinimumVersion(gitPath?: string): void; + +// @beta +export function getDetailedRepoStateAsync(rootDirectory: string, additionalRelativePathsToHash?: string[], gitPath?: string, filterPath?: string[]): Promise; // @public -export function getPackageDeps(packagePath?: string, excludedPaths?: string[]): IPackageDeps; +export function getGitHashForFiles(filesToHash: string[], packagePath: string, gitPath?: string): Map; // @public -export interface IPackageDeps { - arguments?: string; - files: { - [key: string]: string; - }; +export function getPackageDeps(packagePath?: string, excludedPaths?: string[], gitPath?: string): Map; + +// @beta +export function getRepoChanges(currentWorkingDirectory: string, revision?: string, gitPath?: string): Map; + +// @beta +export function getRepoRoot(currentWorkingDirectory: string, gitPath?: string): string; + +// @beta +export function getRepoStateAsync(rootDirectory: string, additionalRelativePathsToHash?: string[], gitPath?: string, filterPath?: string[]): Promise>; + +// @beta +export function hashFilesAsync(rootDirectory: string, filesToHash: Iterable | AsyncIterable, gitPath?: string): Promise>; + +// @beta +export interface IDetailedRepoState { + files: Map; + hasSubmodules: boolean; + hasUncommittedChanges: boolean; } +// @beta +export interface IFileDiffStatus { + // (undocumented) + mode: string; + // (undocumented) + newhash: string; + // (undocumented) + oldhash: string; + // (undocumented) + status: 'A' | 'D' | 'M'; +} ``` diff --git a/common/reviews/api/package-extractor.api.md b/common/reviews/api/package-extractor.api.md new file mode 100644 index 00000000000..f0503a30d4f --- /dev/null +++ b/common/reviews/api/package-extractor.api.md @@ -0,0 +1,90 @@ +## API Report File for "@rushstack/package-extractor" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { IPackageJson } from '@rushstack/node-core-library'; +import { ITerminal } from '@rushstack/terminal'; + +// @public +export interface IExtractorDependencyConfiguration { + dependencyName: string; + dependencyVersionRange: string; + patternsToExclude?: string[]; + patternsToInclude?: string[]; +} + +// @public +export interface IExtractorMetadataJson { + files: string[]; + links: ILinkInfo[]; + mainProjectName: string; + projects: IProjectInfoJson[]; +} + +// @public +export interface IExtractorOptions { + createArchiveFilePath?: string; + createArchiveOnly?: boolean; + dependencyConfigurations?: IExtractorDependencyConfiguration[]; + folderToCopy?: string; + includeDevDependencies?: boolean; + includeNpmIgnoreFiles?: boolean; + linkCreation?: LinkCreationMode; + linkCreationScriptPath?: string; + mainProjectName: string; + overwriteExisting: boolean; + pnpmInstallFolder?: string; + projectConfigurations: IExtractorProjectConfiguration[]; + sourceRootFolder: string; + subspaces?: IExtractorSubspace[]; + targetRootFolder: string; + terminal: ITerminal; + transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; +} + +// @public +export interface IExtractorProjectConfiguration { + additionalDependenciesToInclude?: string[]; + additionalProjectsToInclude?: string[]; + dependenciesToExclude?: string[]; + patternsToExclude?: string[]; + patternsToInclude?: string[]; + projectFolder: string; + projectName: string; +} + +// @public +export interface IExtractorSubspace { + pnpmInstallFolder?: string; + subspaceName: string; + transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; +} + +// @public +export interface ILinkInfo { + kind: 'fileLink' | 'folderLink'; + linkPath: string; + targetPath: string; +} + +// @public +export interface IProjectInfoJson { + path: string; + projectName: string; +} + +// @public +export type LinkCreationMode = 'default' | 'script' | 'none'; + +// @public +export class PackageExtractor { + extractAsync(options: IExtractorOptions): Promise; + // @beta + static getPackageIncludedFilesAsync(packageRootPath: string): Promise; +} + +// (No @packageDocumentation comment for this package) + +``` 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/real-node-module-path.api.md b/common/reviews/api/real-node-module-path.api.md new file mode 100644 index 00000000000..751844943b5 --- /dev/null +++ b/common/reviews/api/real-node-module-path.api.md @@ -0,0 +1,17 @@ +## API Report File for "@rushstack/real-node-module-path" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +// @public +export function clearCache(): void; + +// @public +export const realNodeModulePath: (input: string) => string; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/resolve-chunk-plugin.api.md b/common/reviews/api/resolve-chunk-plugin.api.md deleted file mode 100644 index b2c755df6f6..00000000000 --- a/common/reviews/api/resolve-chunk-plugin.api.md +++ /dev/null @@ -1,15 +0,0 @@ -## API Report File for "@microsoft/resolve-chunk-plugin" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as Webpack from 'webpack'; - -// @public -export class ResolveChunkPlugin implements Webpack.Plugin { - apply(compiler: Webpack.Compiler): void; - } - - -``` diff --git a/common/reviews/api/rig-package.api.md b/common/reviews/api/rig-package.api.md new file mode 100644 index 00000000000..d79f609abb6 --- /dev/null +++ b/common/reviews/api/rig-package.api.md @@ -0,0 +1,54 @@ +## API Report File for "@rushstack/rig-package" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export interface ILoadForProjectFolderOptions { + bypassCache?: boolean; + overrideRigJsonObject?: IRigConfigJson; + projectFolderPath: string; +} + +// @public +export interface IRigConfig { + readonly filePath: string; + getResolvedProfileFolder(): string; + getResolvedProfileFolderAsync(): Promise; + readonly projectFolderOriginalPath: string; + readonly projectFolderPath: string; + readonly relativeProfileFolderPath: string; + readonly rigFound: boolean; + readonly rigPackageName: string; + readonly rigProfile: string; + tryResolveConfigFilePath(configFileRelativePath: string): string | undefined; + tryResolveConfigFilePathAsync(configFileRelativePath: string): Promise; +} + +// @public +export interface IRigConfigJson { + rigPackageName: string; + rigProfile?: string; +} + +// @public +export class RigConfig implements IRigConfig { + readonly filePath: string; + getResolvedProfileFolder(): string; + getResolvedProfileFolderAsync(): Promise; + static get jsonSchemaObject(): object; + static jsonSchemaPath: string; + static loadForProjectFolder(options: ILoadForProjectFolderOptions): RigConfig; + static loadForProjectFolderAsync(options: ILoadForProjectFolderOptions): Promise; + readonly projectFolderOriginalPath: string; + readonly projectFolderPath: string; + readonly relativeProfileFolderPath: string; + readonly rigFound: boolean; + readonly rigPackageName: string; + readonly rigProfile: string; + tryResolveConfigFilePath(configFileRelativePath: string): string | undefined; + tryResolveConfigFilePathAsync(configFileRelativePath: string): Promise; +} + +``` 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 new file mode 100644 index 00000000000..e0d5fe032ad --- /dev/null +++ b/common/reviews/api/rush-amazon-s3-build-cache-plugin.api.md @@ -0,0 +1,75 @@ +## API Report File for "@rushstack/rush-amazon-s3-build-cache-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import type { IRushPlugin } from '@rushstack/rush-sdk'; +import { ITerminal } from '@rushstack/terminal'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { RushSession } from '@rushstack/rush-sdk'; +import { WebClient } from '@rushstack/rush-sdk/lib/utilities/WebClient'; + +// @public +export class AmazonS3Client { + constructor(credentials: IAmazonS3Credentials | undefined, options: IAmazonS3BuildCacheProviderOptionsAdvanced, webClient: WebClient, terminal: ITerminal); + // (undocumented) + getObjectAsync(objectName: string): Promise; + // (undocumented) + _getSha256Hmac(key: string | Buffer, data: string): Buffer; + // (undocumented) + _getSha256Hmac(key: string | Buffer, data: string, encoding: 'hex'): string; + // (undocumented) + static tryDeserializeCredentials(credentialString: string | undefined): IAmazonS3Credentials | undefined; + // (undocumented) + uploadObjectAsync(objectName: string, objectBuffer: Buffer): Promise; + // (undocumented) + static UriEncode(input: string): string; +} + +// @public +export interface IAmazonS3BuildCacheProviderOptionsAdvanced extends IAmazonS3BuildCacheProviderOptionsBase { + // (undocumented) + s3Endpoint: string; +} + +// @public (undocumented) +export interface IAmazonS3BuildCacheProviderOptionsBase { + // (undocumented) + isCacheWriteAllowed: boolean; + // (undocumented) + s3Prefix: string | undefined; + // (undocumented) + s3Region: string; +} + +// @public +export interface IAmazonS3BuildCacheProviderOptionsSimple extends IAmazonS3BuildCacheProviderOptionsBase { + // (undocumented) + s3Bucket: string; +} + +// @public +export interface IAmazonS3Credentials { + // (undocumented) + accessKeyId: string; + // (undocumented) + secretAccessKey: string; + // (undocumented) + sessionToken: string | undefined; +} + +// @public (undocumented) +class RushAmazonS3BuildCachePlugin implements IRushPlugin { + // (undocumented) + apply(rushSession: RushSession, rushConfig: RushConfiguration): void; + // (undocumented) + pluginName: string; +} +export default RushAmazonS3BuildCachePlugin; + +// (No @packageDocumentation comment for this package) + +``` 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 new file mode 100644 index 00000000000..26f39c4993a --- /dev/null +++ b/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md @@ -0,0 +1,156 @@ +## API Report File for "@rushstack/rush-azure-storage-build-cache-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { AzureAuthorityHosts } from '@azure/identity'; +import { CredentialCache } from '@rushstack/credential-cache'; +import { DeviceCodeCredentialOptions } from '@azure/identity'; +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'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { RushSession } from '@rushstack/rush-sdk'; +import { TokenCredential } from '@azure/identity'; + +// @public (undocumented) +export abstract class AzureAuthenticationBase { + constructor(options: IAzureAuthenticationBaseOptions); + // (undocumented) + protected readonly _additionalDeviceCodeCredentialOptions: DeviceCodeCredentialOptions | undefined; + // (undocumented) + protected readonly _additionalInteractiveCredentialOptions: InteractiveBrowserCredentialNodeOptions | undefined; + // (undocumented) + protected readonly _azureEnvironment: AzureEnvironmentName; + // (undocumented) + protected get _credentialCacheId(): string; + // (undocumented) + protected abstract readonly _credentialKindForLogging: string; + // (undocumented) + protected abstract readonly _credentialNameForCache: string; + // (undocumented) + protected readonly _credentialUpdateCommandForLogging: string | undefined; + // (undocumented) + deleteCachedCredentialsAsync(terminal: ITerminal): Promise; + // (undocumented) + protected readonly _failoverOrder: { + [key in LoginFlowType]?: LoginFlowType; + } | undefined; + protected abstract _getCacheIdParts(): string[]; + // (undocumented) + protected abstract _getCredentialFromTokenAsync(terminal: ITerminal, tokenCredential: TokenCredential, credentialsCache: CredentialCache): Promise; + // (undocumented) + protected readonly _loginFlow: LoginFlowType; + // (undocumented) + tryGetCachedCredentialAsync(options?: ITryGetCachedCredentialOptionsThrow | ITryGetCachedCredentialOptionsIgnore): Promise; + // (undocumented) + tryGetCachedCredentialAsync(options: ITryGetCachedCredentialOptionsLogWarning): Promise; + // (undocumented) + updateCachedCredentialAsync(terminal: ITerminal, credential: string): Promise; + updateCachedCredentialInteractiveAsync(terminal: ITerminal, onlyIfExistingCredentialExpiresBefore?: Date): Promise; +} + +// @public (undocumented) +export type AzureEnvironmentName = keyof typeof AzureAuthorityHosts; + +// @public (undocumented) +export class AzureStorageAuthentication extends AzureAuthenticationBase { + constructor(options: IAzureStorageAuthenticationOptions); + // (undocumented) + protected readonly _credentialKindForLogging: string; + // (undocumented) + protected readonly _credentialNameForCache: string; + // (undocumented) + protected _getCacheIdParts(): string[]; + // (undocumented) + protected _getCredentialFromTokenAsync(terminal: ITerminal, tokenCredential: TokenCredential): Promise; + // (undocumented) + protected readonly _isCacheWriteAllowedByConfiguration: boolean; + // (undocumented) + protected readonly _storageAccountName: string; + // (undocumented) + protected readonly _storageAccountUrl: string; + // (undocumented) + protected readonly _storageContainerName: string; +} + +// @public (undocumented) +export type ExpiredCredentialBehavior = 'logWarning' | 'throwError' | 'ignore'; + +// @public (undocumented) +export interface IAzureAuthenticationBaseOptions { + // (undocumented) + azureEnvironment?: AzureEnvironmentName; + // (undocumented) + credentialUpdateCommandForLogging?: string | undefined; + // (undocumented) + loginFlow?: LoginFlowType; + loginFlowFailover?: LoginFlowFailoverMap; +} + +// @public (undocumented) +export interface IAzureStorageAuthenticationOptions extends IAzureAuthenticationBaseOptions { + // (undocumented) + isCacheWriteAllowed: boolean; + // (undocumented) + storageAccountName: string; + // (undocumented) + storageContainerName: string; +} + +// @public (undocumented) +export interface ICredentialResult { + // (undocumented) + credentialMetadata?: object; + // (undocumented) + credentialString: string; + // (undocumented) + expiresOn?: Date; +} + +// @public (undocumented) +export interface ITryGetCachedCredentialOptionsBase { + expiredCredentialBehavior?: ExpiredCredentialBehavior; + // (undocumented) + terminal?: ITerminal; +} + +// @public (undocumented) +export interface ITryGetCachedCredentialOptionsIgnore extends ITryGetCachedCredentialOptionsBase { + expiredCredentialBehavior: 'ignore'; +} + +// @public (undocumented) +export interface ITryGetCachedCredentialOptionsLogWarning extends ITryGetCachedCredentialOptionsBase { + expiredCredentialBehavior: 'logWarning'; + // (undocumented) + terminal: ITerminal; +} + +// @public (undocumented) +export interface ITryGetCachedCredentialOptionsThrow extends ITryGetCachedCredentialOptionsBase { + expiredCredentialBehavior: 'throwError'; +} + +// @public (undocumented) +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 { + // (undocumented) + apply(rushSession: RushSession, rushConfig: RushConfiguration): void; + // (undocumented) + pluginName: string; +} +export default RushAzureStorageBuildCachePlugin; + +// (No @packageDocumentation comment for this package) + +``` 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 258bc359295..da3c87d6bd4 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -4,8 +4,34 @@ ```ts +/// + +import { AsyncParallelHook } from 'tapable'; +import { AsyncSeriesBailHook } from 'tapable'; +import { AsyncSeriesHook } from 'tapable'; +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'; // @public export class ApprovedPackagesConfiguration { @@ -24,6 +50,8 @@ export class ApprovedPackagesConfiguration { // @public export class ApprovedPackagesItem { + // @internal + constructor(packageName: string); allowedCategories: Set; packageName: string; } @@ -36,12 +64,25 @@ export class ApprovedPackagesPolicy { constructor(rushConfiguration: RushConfiguration, rushConfigurationJson: IRushConfigurationJson); readonly browserApprovedPackages: ApprovedPackagesConfiguration; readonly enabled: boolean; - readonly ignoredNpmScopes: Set; + readonly ignoredNpmScopes: ReadonlySet; readonly nonbrowserApprovedPackages: ApprovedPackagesConfiguration; - readonly reviewCategories: Set; - } + readonly reviewCategories: ReadonlySet; +} // @beta +export class BuildCacheConfiguration { + readonly buildCacheEnabled: boolean; + readonly cacheHashSalt: string | undefined; + cacheWriteEnabled: boolean; + readonly cloudCacheProvider: ICloudBuildCacheProvider | undefined; + static getBuildCacheConfigFilePath(rushConfiguration: RushConfiguration): string; + readonly getCacheEntryId: GetCacheEntryIdFunction; + static loadAndRequireEnabledAsync(terminal: ITerminal, rushConfiguration: RushConfiguration, rushSession: RushSession): Promise; + readonly localCacheProvider: FileSystemBuildCacheProvider; + static tryLoadAsync(terminal: ITerminal, rushConfiguration: RushConfiguration, rushSession: RushSession): Promise; +} + +// @public export enum BumpType { // (undocumented) 'major' = 5, @@ -62,20 +103,107 @@ export class ChangeManager { static createEmptyChangeFiles(rushConfiguration: RushConfiguration, projectName: string, emailAddress: string): string | undefined; } +// Warning: (ae-forgotten-export) The symbol "IBuildCacheJson" needs to be exported by the entry point index.d.ts +// +// @beta (undocumented) +export type CloudBuildCacheProviderFactory = (buildCacheJson: IBuildCacheJson) => ICloudBuildCacheProvider | Promise; + +// @beta +export class CobuildConfiguration { + readonly cobuildContextId: string | undefined; + readonly cobuildFeatureEnabled: boolean; + readonly cobuildLeafProjectLogOnlyAllowed: boolean; + readonly cobuildRunnerId: string; + readonly cobuildWithoutCacheAllowed: boolean; + // (undocumented) + createLockProviderAsync(terminal: ITerminal): Promise; + // (undocumented) + destroyLockProviderAsync(): Promise; + // (undocumented) + static getCobuildConfigFilePath(rushConfiguration: RushConfiguration): string; + // (undocumented) + getCobuildLockProvider(): ICobuildLockProvider; + static tryLoadAsync(terminal: ITerminal, rushConfiguration: RushConfiguration, rushSession: RushSession): Promise; +} + +// @beta (undocumented) +export type CobuildLockProviderFactory = (cobuildJson: ICobuildJson) => ICobuildLockProvider | Promise; + // @public export class CommonVersionsConfiguration { readonly allowedAlternativeVersions: Map>; + readonly ensureConsistentVersions: boolean; readonly filePath: string; getAllPreferredVersions(): Map; + getPreferredVersionsHash(): string; readonly implicitlyPreferredVersions: boolean | undefined; - static loadFromFile(jsonFilename: string): CommonVersionsConfiguration; + static loadFromFile(jsonFilePath: string, rushConfiguration?: RushConfiguration): CommonVersionsConfiguration; readonly preferredVersions: Map; save(): boolean; - readonly xstitchPreferredVersions: Map; - } +} -// @beta (undocumented) -export const enum DependencyType { +export { CredentialCache } + +// @beta +export enum CustomTipId { + // (undocumented) + TIP_PNPM_INVALID_NODE_VERSION = "TIP_PNPM_INVALID_NODE_VERSION", + // (undocumented) + TIP_PNPM_MISMATCHED_RELEASE_CHANNEL = "TIP_PNPM_MISMATCHED_RELEASE_CHANNEL", + // (undocumented) + TIP_PNPM_NO_MATCHING_VERSION = "TIP_PNPM_NO_MATCHING_VERSION", + // (undocumented) + TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE = "TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE", + // (undocumented) + TIP_PNPM_OUTDATED_LOCKFILE = "TIP_PNPM_OUTDATED_LOCKFILE", + // (undocumented) + TIP_PNPM_PEER_DEP_ISSUES = "TIP_PNPM_PEER_DEP_ISSUES", + // (undocumented) + TIP_PNPM_TARBALL_INTEGRITY = "TIP_PNPM_TARBALL_INTEGRITY", + // (undocumented) + TIP_PNPM_UNEXPECTED_STORE = "TIP_PNPM_UNEXPECTED_STORE", + // (undocumented) + TIP_RUSH_DISALLOW_INSECURE_SHA1 = "TIP_RUSH_DISALLOW_INSECURE_SHA1", + // (undocumented) + TIP_RUSH_INCONSISTENT_VERSIONS = "TIP_RUSH_INCONSISTENT_VERSIONS" +} + +// @beta +export class CustomTipsConfiguration { + constructor(configFilePath: string); + static customTipRegistry: Readonly>; + // (undocumented) + readonly providedCustomTipsByTipId: ReadonlyMap; + // @internal + _showErrorTip(terminal: ITerminal, tipId: CustomTipId): void; + // @internal + _showInfoTip(terminal: ITerminal, tipId: CustomTipId): void; + // @internal + _showTip(terminal: ITerminal, tipId: CustomTipId): void; + // @internal + _showWarningTip(terminal: ITerminal, tipId: CustomTipId): void; +} + +// @beta +export enum CustomTipSeverity { + // (undocumented) + Error = "Error", + // (undocumented) + Info = "Info", + // (undocumented) + Warning = "Warning" +} + +// @beta +export enum CustomTipType { + // (undocumented) + pnpm = "pnpm", + // (undocumented) + rush = "rush" +} + +// @public (undocumented) +export enum DependencyType { // (undocumented) Dev = "devDependencies", // (undocumented) @@ -83,26 +211,80 @@ export const enum DependencyType { // (undocumented) Peer = "peerDependencies", // (undocumented) - Regular = "dependencies" + Regular = "dependencies", + // (undocumented) + YarnResolutions = "resolutions" } -// @public -export const enum EnvironmentVariableNames { - RUSH_ABSOLUTE_SYMLINKS = "RUSH_ABSOLUTE_SYMLINKS", - RUSH_ALLOW_UNSUPPORTED_NODEJS = "RUSH_ALLOW_UNSUPPORTED_NODEJS", - RUSH_PNPM_STORE_PATH = "RUSH_PNPM_STORE_PATH", - RUSH_PREVIEW_VERSION = "RUSH_PREVIEW_VERSION", - RUSH_TEMP_FOLDER = "RUSH_TEMP_FOLDER", - RUSH_VARIANT = "RUSH_VARIANT" +// @beta +export class EnvironmentConfiguration { + static get absoluteSymlinks(): boolean; + static get allowUnsupportedNodeVersion(): boolean; + 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; + static get cobuildRunnerId(): string | undefined; + // Warning: (ae-forgotten-export) The symbol "IEnvironment" needs to be exported by the entry point index.d.ts + // + // @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 reset(): void; + static get rushGlobalFolderOverride(): string | undefined; + static get rushTempFolderOverride(): string | undefined; + static get tarBinaryPath(): string | undefined; + static validate(options?: IEnvironmentConfigurationInitializeOptions): void; } // @beta -export enum Event { +export const EnvironmentVariableNames: { + readonly RUSH_TEMP_FOLDER: "RUSH_TEMP_FOLDER"; + readonly RUSH_PREVIEW_VERSION: "RUSH_PREVIEW_VERSION"; + readonly RUSH_ALLOW_UNSUPPORTED_NODEJS: "RUSH_ALLOW_UNSUPPORTED_NODEJS"; + readonly RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD: "RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD"; + readonly RUSH_VARIANT: "RUSH_VARIANT"; + readonly RUSH_PARALLELISM: "RUSH_PARALLELISM"; + readonly RUSH_ABSOLUTE_SYMLINKS: "RUSH_ABSOLUTE_SYMLINKS"; + readonly RUSH_PNPM_STORE_PATH: "RUSH_PNPM_STORE_PATH"; + readonly RUSH_PNPM_VERIFY_STORE_INTEGRITY: "RUSH_PNPM_VERIFY_STORE_INTEGRITY"; + readonly RUSH_DEPLOY_TARGET_FOLDER: "RUSH_DEPLOY_TARGET_FOLDER"; + readonly RUSH_GLOBAL_FOLDER: "RUSH_GLOBAL_FOLDER"; + 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"; + readonly RUSH_GIT_BINARY_PATH: "RUSH_GIT_BINARY_PATH"; + readonly RUSH_TAR_BINARY_PATH: "RUSH_TAR_BINARY_PATH"; + readonly _RUSH_RECURSIVE_RUSHX_CALL: "_RUSH_RECURSIVE_RUSHX_CALL"; + readonly _RUSH_LIB_PATH: "_RUSH_LIB_PATH"; + readonly RUSH_INVOKED_FOLDER: "RUSH_INVOKED_FOLDER"; + readonly RUSH_INVOKED_ARGS: "RUSH_INVOKED_ARGS"; +}; + +// @beta +enum Event_2 { postRushBuild = 4, postRushInstall = 2, + postRushx = 6, preRushBuild = 3, - preRushInstall = 1 + preRushInstall = 1, + preRushx = 5 } +export { Event_2 as Event } // @beta export class EventHooks { @@ -110,15 +292,100 @@ export class EventHooks { // // @internal constructor(eventHooksJson: IEventHooksJson); - get(event: Event): string[]; - } + get(event: Event_2): string[]; +} -// @beta +// @public export class ExperimentsConfiguration { // @internal - constructor(jsonFileName: string); + constructor(jsonFilePath: string); + // @beta readonly configuration: Readonly; - } +} + +// @beta +export class FileSystemBuildCacheProvider { + constructor(options: IFileSystemBuildCacheProviderOptions); + getCacheEntryPath(cacheId: string): string; + tryGetCacheEntryPathByIdAsync(terminal: ITerminal, cacheId: string): Promise; + trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): Promise; +} + +// @internal +export class _FlagFile { + constructor(folderPath: string, flagName: string, initialState: TState); + clearAsync(): Promise; + createAsync(): Promise; + isValidAsync(): Promise; + readonly path: string; + protected _state: TState; +} + +// @beta +export type GetCacheEntryIdFunction = (options: IGenerateCacheEntryIdOptions) => string; + +// @beta +export type GetInputsSnapshotAsyncFn = () => Promise; + +// @internal (undocumented) +export interface _IBuiltInPluginConfiguration extends _IRushPluginConfigurationBase { + // (undocumented) + pluginPackageFolder: string; +} + +// @beta (undocumented) +export interface ICloudBuildCacheProvider { + // (undocumented) + deleteCachedCredentialsAsync(terminal: ITerminal): Promise; + // (undocumented) + readonly isCacheWriteAllowed: boolean; + // (undocumented) + tryGetCacheEntryBufferByIdAsync(terminal: ITerminal, cacheId: string): Promise; + // (undocumented) + trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): Promise; + // (undocumented) + updateCachedCredentialAsync(terminal: ITerminal, credential: string): Promise; + // (undocumented) + updateCachedCredentialInteractiveAsync(terminal: ITerminal): Promise; +} + +// @beta (undocumented) +export interface ICobuildCompletedState { + cacheId: string; + // (undocumented) + status: OperationStatus.Success | OperationStatus.SuccessWithWarning | OperationStatus.Failure; +} + +// @beta (undocumented) +export interface ICobuildContext { + cacheId: string; + clusterId: string; + completedStateKey: string; + contextId: string; + lockExpireTimeInSeconds: number; + lockKey: string; + packageName: string; + phaseName: string; + runnerId: string; +} + +// @beta (undocumented) +export interface ICobuildJson { + // (undocumented) + cobuildFeatureEnabled: boolean; + // (undocumented) + cobuildLockProvider: string; +} + +// @beta (undocumented) +export interface ICobuildLockProvider { + acquireLockAsync(context: Readonly): Promise; + connectAsync(): Promise; + disconnectAsync(): Promise; + getCompletedStateAsync(context: Readonly): Promise; + renewLockAsync(context: Readonly): Promise; + setCompletedStateAsync(context: Readonly, state: ICobuildCompletedState): Promise; +} // @public export interface IConfigurationEnvironment { @@ -131,28 +398,180 @@ export interface IConfigurationEnvironmentVariable { value: string; } +// @alpha +export interface ICreateOperationsContext { + readonly buildCacheConfiguration: BuildCacheConfiguration | undefined; + readonly changedProjectsOnly: boolean; + readonly cobuildConfiguration: CobuildConfiguration | undefined; + readonly customParameters: ReadonlyMap; + readonly includePhaseDeps: boolean; + readonly invalidateOperation?: ((operation: Operation, reason: string) => void) | undefined; + readonly isIncrementalBuildAllowed: boolean; + readonly isInitial: boolean; + readonly isWatch: boolean; + readonly parallelism: number; + readonly phaseOriginal: ReadonlySet; + readonly phaseSelection: ReadonlySet; + readonly projectConfigurations: ReadonlyMap; + readonly projectSelection: ReadonlySet; + readonly projectsInUnknownState: ReadonlySet; + readonly rushConfiguration: RushConfiguration; +} + +export { ICredentialCacheEntry } + +export { ICredentialCacheOptions } + +// @beta +export interface ICustomTipInfo { + isMatch?: (str: string) => boolean; + severity: CustomTipSeverity; + // (undocumented) + tipId: CustomTipId; + type: CustomTipType; +} + +// @beta +export interface ICustomTipItemJson { + message: string; + tipId: CustomTipId; +} + +// @beta +export interface ICustomTipsJson { + customTips?: ICustomTipItemJson[]; +} + +// @beta (undocumented) +export interface IEnvironmentConfigurationInitializeOptions { + // (undocumented) + doNotNormalizePaths?: boolean; +} + +// @alpha +export interface IExecuteOperationsContext extends ICreateOperationsContext { + readonly abortController: AbortController; + readonly inputsSnapshot?: IInputsSnapshot; +} + +// @alpha +export interface IExecutionResult { + readonly operationResults: ReadonlyMap; + readonly status: OperationStatus; +} + // @beta export interface IExperimentsJson { - legacyIncrementalBuildDependencyDetection?: boolean; + allowCobuildWithoutCache?: boolean; + buildCacheWithAllowWarningsInSuccessfulBuild?: boolean; + buildSkipWithAllowWarningsInSuccessfulBuild?: boolean; + cleanInstallAfterNpmrcChanges?: boolean; + enableSubpathScan?: boolean; + exemptDecoupledDependenciesBetweenSubspaces?: boolean; + forbidPhantomResolvableNodeModulesFolders?: boolean; + generateProjectImpactGraphDuringRushUpdate?: boolean; + noChmodFieldInTarHeaderNormalization?: boolean; + omitImportersFromPreventManualShrinkwrapChanges?: boolean; + printEventHooksOutputToConsole?: boolean; + rushAlerts?: boolean; + useIPCScriptsInWatchMode?: boolean; + usePnpmFrozenLockfileForRushInstall?: boolean; + usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate?: boolean; + usePnpmPreferFrozenLockfileForRushUpdate?: boolean; + usePnpmSyncForInjectedDependencies?: boolean; +} + +// @beta +export interface IFileSystemBuildCacheProviderOptions { + rushConfiguration: RushConfiguration; + rushUserConfiguration: RushUserConfiguration; +} + +// @beta +export interface IGenerateCacheEntryIdOptions { + phaseName: string; + projectName: string; + projectStateHash: string; +} + +// @beta (undocumented) +export interface IGetChangedProjectsOptions { + enableFiltering: boolean; + includeExternalDependencies: boolean; + // (undocumented) + shouldFetch?: boolean; + // (undocumented) + targetBranchName: string; + // (undocumented) + terminal: ITerminal; + // (undocumented) + variant?: string; +} + +// @beta +export interface IGlobalCommand extends IRushCommand { +} + +// @public +export interface IIndividualVersionJson extends IVersionPolicyJson { + // (undocumented) + lockedMajor?: number; +} + +// @beta +export interface IInputsSnapshot { + getOperationOwnStateHash(project: IRushConfigurationProjectForSnapshot, operationName?: string): string; + getTrackedFileHashesForOperation(project: IRushConfigurationProjectForSnapshot, operationName?: string): ReadonlyMap; + readonly hashes: ReadonlyMap; + readonly hasUncommittedChanges: boolean; + readonly rootDirectory: string; } // @public export interface ILaunchOptions { alreadyReportedNodeTooNewError?: boolean; + // @internal + builtInPluginConfigurations?: _IBuiltInPluginConfiguration[]; isManaged: boolean; + terminalProvider?: ITerminalProvider; } -// @beta +// @public +export interface ILockStepVersionJson extends IVersionPolicyJson { + // (undocumented) + mainProject?: string; + // (undocumented) + nextBump?: string; + // (undocumented) + version: string; +} + +// @alpha +export interface ILogFilePaths { + error: string; + jsonl: string; + jsonlFolder: string; + text: string; + textFolder: string; +} + +// @beta (undocumented) +export interface ILogger { + emitError(error: Error): void; + emitWarning(warning: Error): void; + // (undocumented) + readonly terminal: Terminal; +} + +// @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 + // @internal (undocumented) readonly _json: IIndividualVersionJson; - readonly lockedMajor: number | undefined; + get lockedMajor(): number | undefined; validate(versionString: string, packageName: string): void; } @@ -160,16 +579,338 @@ export class IndividualVersionPolicy extends VersionPolicy { export interface _INpmOptionsJson extends IPackageManagerOptionsJsonBase { } +// @internal (undocumented) +export interface _IOperationBuildCacheOptions { + buildCacheConfiguration: BuildCacheConfiguration; + terminal: ITerminal; +} + +// @alpha +export interface IOperationExecutionResult { + readonly error: Error | undefined; + getStateHash(): string; + getStateHashComponents(): ReadonlyArray; + 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; +} + +// @internal (undocumented) +export interface _IOperationMetadata { + // (undocumented) + cobuildContextId: string | undefined; + // (undocumented) + cobuildRunnerId: string | undefined; + // (undocumented) + durationInSeconds: number; + // (undocumented) + errorLogPath: string; + // (undocumented) + logChunksPath: string; + // (undocumented) + logPath: string; +} + +// @internal (undocumented) +export interface _IOperationMetadataManagerOptions { + // (undocumented) + operation: Operation; +} + +// @alpha +export interface IOperationOptions { + logFilenameIdentifier: string; + phase: IPhase; + project: RushConfigurationProject; + runner?: IOperationRunner | undefined; + settings?: IOperationSettings | undefined; +} + +// @beta +export interface IOperationRunner { + cacheable: boolean; + executeAsync(context: IOperationRunnerContext): Promise; + getConfigHash(): string; + readonly isNoOp?: boolean; + readonly name: string; + reportTiming: boolean; + silent: boolean; + warningsAreAllowed: boolean; +} + +// @beta +export interface IOperationRunnerContext { + collatedWriter: CollatedWriter; + debugMode: boolean; + environment: IEnvironment | undefined; + error?: Error; + // @internal + _operationMetadataManager: _OperationMetadataManager; + quietMode: boolean; + runWithTerminalAsync(callback: (terminal: ITerminal, terminalProvider: ITerminalProvider) => Promise, options: { + createLogFile: boolean; + logFileSuffix?: string; + }): Promise; + status: OperationStatus; + stopwatch: IStopwatchResult; +} + +// @alpha (undocumented) +export interface IOperationSettings { + allowCobuildWithoutCache?: boolean; + dependsOnAdditionalFiles?: string[]; + dependsOnEnvVars?: string[]; + disableBuildCacheForOperation?: boolean; + ignoreChangedProjectsOnlyFlag?: boolean; + operationName: string; + outputFolderNames?: string[]; + parameterNamesToIgnore?: string[]; + sharding?: IRushPhaseSharding; + weight?: number; +} + +// @internal (undocumented) +export interface _IOperationStateFileOptions { + // (undocumented) + metadataFolder: string; + // (undocumented) + projectFolder: string; +} + +// @internal (undocumented) +export interface _IOperationStateJson { + // (undocumented) + cobuildContextId: string | undefined; + // (undocumented) + cobuildRunnerId: string | undefined; + // (undocumented) + nonCachedDurationMs: number; +} + // @public export interface IPackageManagerOptionsJsonBase { environmentVariables?: IConfigurationEnvironment; } +// @alpha +export interface IPhase { + allowWarningsOnSuccess: boolean; + associatedParameters: Set; + dependencies: { + self: Set; + upstream: Set; + }; + isSynthetic: boolean; + logFilenameIdentifier: string; + missingScriptBehavior: IPhaseBehaviorForMissingScript; + name: string; + shellCommand?: string; +} + +// @alpha +export type IPhaseBehaviorForMissingScript = 'silent' | 'log' | 'error'; + +// @beta +export interface IPhasedCommand extends IRushCommand { + // @alpha + readonly hooks: PhasedCommandHooks; + // @alpha + readonly sessionAbortController: AbortController; +} + +// @public +export interface IPnpmLockfilePolicies { + disallowInsecureSha1?: { + enabled: boolean; + exemptPackageVersions: Record; + }; +} + // @internal export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { - pnpmStore?: PnpmStoreOptions; - resolutionStrategy?: ResolutionStrategy; + // (undocumented) + $schema?: string; + alwaysFullInstall?: boolean; + alwaysInjectDependenciesFromOtherSubspaces?: boolean; + autoInstallPeers?: boolean; + globalAllowedDeprecatedVersions?: Record; + globalCatalogs?: Record>; + globalIgnoredOptionalDependencies?: string[]; + globalNeverBuiltDependencies?: string[]; + globalOverrides?: Record; + globalPackageExtensions?: Record; + globalPatchedDependencies?: Record; + globalPeerDependencyRules?: IPnpmPeerDependencyRules; + minimumReleaseAge?: number; + minimumReleaseAgeExclude?: string[]; + pnpmLockfilePolicies?: IPnpmLockfilePolicies; + pnpmStore?: PnpmStoreLocation; + preventManualShrinkwrapChanges?: boolean; + resolutionMode?: PnpmResolutionMode; strictPeerDependencies?: boolean; + unsupportedPackageJsonSettings?: unknown; + useWorkspaces?: boolean; +} + +// @public (undocumented) +export interface IPnpmPackageExtension { + // (undocumented) + dependencies?: Record; + // (undocumented) + optionalDependencies?: Record; + // (undocumented) + peerDependencies?: Record; + // (undocumented) + peerDependenciesMeta?: IPnpmPeerDependenciesMeta; +} + +// @public (undocumented) +export interface IPnpmPeerDependenciesMeta { + // (undocumented) + [packageName: string]: { + optional?: boolean; + }; +} + +// @public (undocumented) +export interface IPnpmPeerDependencyRules { + // (undocumented) + allowAny?: string[]; + // (undocumented) + allowedVersions?: Record; + // (undocumented) + ignoreMissing?: string[]; +} + +export { IPrefixMatch } + +// @internal (undocumented) +export type _IProjectBuildCacheOptions = _IOperationBuildCacheOptions & { + projectOutputFolderNames: ReadonlyArray; + project: RushConfigurationProject; + operationStateHash: string; + phaseName: string; +}; + +// @beta +export interface IRushCommand { + readonly actionName: string; +} + +// @beta +export interface IRushCommandLineAction { + // (undocumented) + actionName: string; + // (undocumented) + parameters: IRushCommandLineParameter[]; +} + +// @beta +export interface IRushCommandLineParameter { + readonly description: string; + readonly environmentVariable?: string; + readonly kind: keyof typeof CommandLineParameterKind; + readonly longName: string; + readonly required?: boolean; + readonly shortName?: string; +} + +// @beta +export interface IRushCommandLineSpec { + // (undocumented) + actions: IRushCommandLineAction[]; +} + +// @beta (undocumented) +export type IRushConfigurationProjectForSnapshot = Pick; + +// @alpha (undocumented) +export interface IRushPhaseSharding { + count: number; + outputFolderArgumentFormat?: string; + shardArgumentFormat?: string; + // @deprecated (undocumented) + shardOperationSettings?: unknown; +} + +// @beta (undocumented) +export interface IRushPlugin { + // (undocumented) + apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void; +} + +// @internal (undocumented) +export interface _IRushPluginConfigurationBase { + // (undocumented) + packageName: string; + // (undocumented) + pluginName: string; +} + +// @internal +export interface _IRushProjectJson { + disableBuildCacheForProject?: boolean; + incrementalBuildIgnoredGlobs?: string[]; + // (undocumented) + operationSettings?: IOperationSettings[]; +} + +// @beta (undocumented) +export interface IRushSessionOptions { + // (undocumented) + getIsDebugMode: () => boolean; + // (undocumented) + terminalProvider: ITerminalProvider; +} + +// @beta +export interface IStopwatchResult { + get duration(): number; + get endTime(): number | undefined; + get startTime(): number | undefined; + toString(): string; +} + +// @beta (undocumented) +export interface ITelemetryData { + readonly durationInSeconds: number; + // (undocumented) + readonly extraData?: { + [key: string]: string | number | boolean; + }; + readonly machineInfo?: ITelemetryMachineInfo; + readonly name: string; + readonly operationResults?: Record; + readonly performanceEntries?: readonly PerformanceEntry_2[]; + readonly platform?: string; + readonly result: 'Succeeded' | 'Failed'; + readonly rushVersion?: string; + readonly timestampMs?: number; +} + +// @beta (undocumented) +export interface ITelemetryMachineInfo { + machineArchitecture: string; + machineCores: number; + machineCpu: string; + machineFreeMemoryMiB: number; + machineTotalMemoryMiB: number; +} + +// @beta (undocumented) +export interface ITelemetryOperationResult { + dependencies: string[]; + endTimestampMs?: number; + nonCachedDurationMs?: number; + result: string; + startTimestampMs?: number; + wasExecutedOnThisMachine?: boolean; } // @public @@ -178,37 +919,43 @@ 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; } -// @internal -export class _LastInstallFlag { - constructor(folderPath: string, state?: JsonObject); - checkValidAndReportStoreIssues(): boolean; - clear(): void; - create(): void; - isValid(): boolean; - readonly path: string; - } - -// @beta +// @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 + // @internal (undocumented) readonly _json: ILockStepVersionJson; - readonly mainProject: string | undefined; - readonly nextBump: BumpType; + get mainProject(): string | undefined; + get nextBump(): BumpType | undefined; update(newVersionString: string): boolean; validate(versionString: string, packageName: string): void; - readonly version: string; - } + get version(): string; +} + +export { LookupByPath } // @public export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { @@ -216,7 +963,94 @@ export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationB constructor(json: _INpmOptionsJson); } -// @beta (undocumented) +// @alpha +export class Operation { + constructor(options: IOperationOptions); + addDependency(dependency: Operation): void; + readonly associatedPhase: IPhase; + readonly associatedProject: RushConfigurationProject; + readonly consumers: ReadonlySet; + deleteDependency(dependency: Operation): void; + readonly dependencies: ReadonlySet; + enabled: boolean; + get isNoOp(): boolean; + logFilenameIdentifier: string; + get name(): string; + runner: IOperationRunner | undefined; + settings: IOperationSettings | undefined; + weight: number; +} + +// @internal (undocumented) +export class _OperationBuildCache { + // (undocumented) + get cacheId(): string | undefined; + // (undocumented) + static forOperation(executionResult: IOperationExecutionResult, options: _IOperationBuildCacheOptions): _OperationBuildCache; + // (undocumented) + static getOperationBuildCache(options: _IProjectBuildCacheOptions): _OperationBuildCache; + // (undocumented) + tryRestoreFromCacheAsync(terminal: ITerminal, specifiedCacheId?: string): Promise; + // (undocumented) + trySetCacheEntryAsync(terminal: ITerminal, specifiedCacheId?: string): Promise; +} + +// @internal +export class _OperationMetadataManager { + constructor(options: _IOperationMetadataManagerOptions); + // (undocumented) + readonly logFilenameIdentifier: string; + get metadataFolderPath(): string; + // (undocumented) + saveAsync({ durationInSeconds, cobuildContextId, cobuildRunnerId, logPath, errorLogPath, logChunksPath }: _IOperationMetadata): Promise; + // (undocumented) + readonly stateFile: _OperationStateFile; + // (undocumented) + tryRestoreAsync({ terminal, terminalProvider, errorLogPath, cobuildContextId, cobuildRunnerId }: { + terminalProvider: ITerminalProvider; + terminal: ITerminal; + errorLogPath: string; + cobuildContextId?: string; + cobuildRunnerId?: string; + }): Promise; + // (undocumented) + tryRestoreStopwatch(originalStopwatch: IStopwatchResult): IStopwatchResult; + // (undocumented) + wasCobuilt: boolean; +} + +// @internal +export class _OperationStateFile { + constructor(options: _IOperationStateFileOptions); + // (undocumented) + static filename: string; + readonly filepath: string; + readonly relativeFilepath: string; + // (undocumented) + get state(): _IOperationStateJson | undefined; + // (undocumented) + tryRestoreAsync(): Promise<_IOperationStateJson | undefined>; + // (undocumented) + writeAsync(json: _IOperationStateJson): Promise; +} + +// @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" +} + +// @public (undocumented) export class PackageJsonDependency { constructor(name: string, version: string, type: DependencyType, onChange: () => void); // (undocumented) @@ -226,15 +1060,27 @@ export class PackageJsonDependency { // (undocumented) setVersion(newVersion: string): void; // (undocumented) - readonly version: string; - } + get version(): string; +} -// @beta (undocumented) +// @public (undocumented) +export class PackageJsonDependencyMeta { + constructor(name: string, injected: boolean, onChange: () => void); + // (undocumented) + get injected(): boolean; + // (undocumented) + readonly name: string; +} + +// @public (undocumented) export class PackageJsonEditor { + // @internal + protected constructor(filepath: string, data: IPackageJson); // (undocumented) addOrUpdateDependency(packageName: string, newVersion: string, dependencyType: DependencyType): void; - readonly dependencyList: ReadonlyArray; - readonly devDependencyList: ReadonlyArray; + get dependencyList(): ReadonlyArray; + get dependencyMetaList(): ReadonlyArray; + get devDependencyList(): ReadonlyArray; // (undocumented) readonly filePath: string; // (undocumented) @@ -242,25 +1088,27 @@ export class PackageJsonEditor { // (undocumented) static load(filePath: string): PackageJsonEditor; // (undocumented) - readonly name: string; + get name(): string; + // (undocumented) + removeDependency(packageName: string, dependencyType: DependencyType): void; + get resolutionsList(): ReadonlyArray; // (undocumented) saveIfModified(): boolean; + saveToObject(): IPackageJson; // (undocumented) tryGetDependency(packageName: string): PackageJsonDependency | undefined; // (undocumented) tryGetDevDependency(packageName: string): PackageJsonDependency | undefined; // (undocumented) - readonly version: string; + get version(): string; } -// @beta +// @public export abstract class PackageManager { // @internal - protected constructor(version: string, packageManager: PackageManagerName); + protected constructor(version: string, packageManager: PackageManagerName, shrinkwrapFilename: string); readonly packageManager: PackageManagerName; readonly shrinkwrapFilename: string; - // (undocumented) - protected _shrinkwrapFilename: string; readonly version: string; } @@ -274,59 +1122,175 @@ export abstract class PackageManagerOptionsConfigurationBase implements IPackage readonly environmentVariables?: IConfigurationEnvironment; } +// @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 beforeLog: SyncHook; + readonly createEnvironmentForOperation: SyncWaterfallHook<[ + IEnvironment, + IOperationRunnerContext & IOperationExecutionResult + ]>; + readonly createOperations: AsyncSeriesWaterfallHook<[Set, ICreateOperationsContext]>; + readonly onOperationStatusChanged: SyncHook<[IOperationExecutionResult]>; + readonly shutdownAsync: AsyncParallelHook; + readonly waitingForChanges: SyncHook; +} + // @public export class PnpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { - // @internal - constructor(json: _IPnpmOptionsJson, commonTempFolder: string); - readonly pnpmStore: PnpmStoreOptions; + readonly alwaysFullInstall: boolean | undefined; + readonly alwaysInjectDependenciesFromOtherSubspaces: boolean | undefined; + readonly autoInstallPeers: boolean | undefined; + readonly globalAllowedDeprecatedVersions: Record | undefined; + readonly globalCatalogs: Record> | undefined; + readonly globalIgnoredOptionalDependencies: string[] | undefined; + readonly globalNeverBuiltDependencies: string[] | undefined; + readonly globalOverrides: Record | undefined; + readonly globalPackageExtensions: Record | undefined; + get globalPatchedDependencies(): Record | undefined; + readonly globalPeerDependencyRules: IPnpmPeerDependencyRules | undefined; + // (undocumented) + readonly jsonFilename: string | undefined; + // @internal (undocumented) + static loadFromJsonFileOrThrow(jsonFilePath: string, commonTempFolder: string): PnpmOptionsConfiguration; + // @internal (undocumented) + static loadFromJsonObject(json: _IPnpmOptionsJson, commonTempFolder: string): PnpmOptionsConfiguration; + readonly minimumReleaseAge: number | undefined; + readonly minimumReleaseAgeExclude: string[] | undefined; + readonly pnpmLockfilePolicies: IPnpmLockfilePolicies | undefined; + readonly pnpmStore: PnpmStoreLocation; readonly pnpmStorePath: string; - readonly resolutionStrategy: ResolutionStrategy; + readonly preventManualShrinkwrapChanges: boolean; + readonly resolutionMode: PnpmResolutionMode | undefined; readonly strictPeerDependencies: boolean; + readonly unsupportedPackageJsonSettings: unknown | undefined; + updateGlobalPatchedDependencies(patchedDependencies: Record | undefined): void; + readonly useWorkspaces: boolean; } // @public -export type PnpmStoreOptions = 'local' | 'global'; +export type PnpmResolutionMode = 'highest' | 'time-based' | 'lowest-direct'; // @public -export type ResolutionStrategy = 'fewer-dependencies' | 'fast'; +export type PnpmStoreLocation = 'local' | 'global'; + +// @public @deprecated (undocumented) +export type PnpmStoreOptions = PnpmStoreLocation; + +// @beta (undocumented) +export class ProjectChangeAnalyzer { + constructor(rushConfiguration: RushConfiguration); + // @internal (undocumented) + _filterProjectDataAsync(project: RushConfigurationProject, unfilteredProjectData: Map, rootDir: string, terminal: ITerminal): Promise>; + getChangedProjectsAsync(options: IGetChangedProjectsOptions): Promise>; + // (undocumented) + protected getChangesByProject(lookup: LookupByPath, changedFiles: Map): Map>; + // @internal + _tryGetSnapshotProviderAsync(projectConfigurations: ReadonlyMap, terminal: ITerminal, projectSelection?: ReadonlySet): Promise; +} + +// @public +export class RepoStateFile { + readonly filePath: string; + 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; +} // @public export class Rush { - static launch(launcherVersion: string, arg: ILaunchOptions): void; + static launch(launcherVersion: string, options: ILaunchOptions): void; + static launchRushPnpm(launcherVersion: string, options: ILaunchOptions): void; static launchRushX(launcherVersion: string, options: ILaunchOptions): void; - static readonly version: string; + // (undocumented) + static get _rushLibPackageFolder(): string; + // @internal (undocumented) + static get _rushLibPackageJson(): IPackageJson; + static get version(): string; +} + +// @beta +export class RushCommandLine { + // (undocumented) + static getCliSpec(rushJsonFolder: string): IRushCommandLineSpec; } // @public export class RushConfiguration { + readonly allowMostlyStandardPackageNames: boolean; readonly approvedPackagesPolicy: ApprovedPackagesPolicy; readonly changesFolder: string; - // @deprecated - readonly committedShrinkwrapFilename: string; + get commonAutoinstallersFolder(): string; readonly commonFolder: string; readonly commonRushConfigFolder: string; readonly commonScriptsFolder: string; readonly commonTempFolder: string; // @deprecated - readonly commonVersions: CommonVersionsConfiguration; - readonly currentInstalledVariant: string | undefined; - readonly currentVariantJsonFilename: string; + get commonVersions(): CommonVersionsConfiguration; + readonly currentVariantJsonFilePath: string; + // Warning: (ae-forgotten-export) The symbol "ICurrentVariantJson" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + _currentVariantJsonLoadingPromise: Promise | undefined; + // @beta + readonly customTipsConfiguration: CustomTipsConfiguration; + // @beta + readonly customTipsConfigurationFilePath: string; + // @beta (undocumented) + get defaultSubspace(): Subspace; + // @deprecated readonly ensureConsistentVersions: boolean; + // @internal + readonly _ensureConsistentVersionsJsonValue: boolean | undefined; // @beta readonly eventHooks: EventHooks; // @beta readonly experimentsConfiguration: ExperimentsConfiguration; findProjectByShorthandName(shorthandProjectName: string): RushConfigurationProject | undefined; findProjectByTempName(tempProjectName: string): RushConfigurationProject | undefined; - getCommittedShrinkwrapFilename(variant?: string | undefined): string; - getCommonVersions(variant?: string | undefined): CommonVersionsConfiguration; - getCommonVersionsFilePath(variant?: string | undefined): string; - getPnpmfilePath(variant?: string | undefined): string; + // @deprecated (undocumented) + getCommittedShrinkwrapFilename(subspace?: Subspace, variant?: string): string; + // @deprecated (undocumented) + getCommonVersions(subspace?: Subspace, variant?: string): CommonVersionsConfiguration; + // @deprecated (undocumented) + getCommonVersionsFilePath(subspace?: Subspace, variant?: string): string; + getCurrentlyInstalledVariantAsync(): Promise; + getImplicitlyPreferredVersions(subspace?: Subspace, variant?: string): Map; + // @deprecated (undocumented) + getPnpmfilePath(subspace?: Subspace, variant?: string): string; getProjectByName(projectName: string): RushConfigurationProject | undefined; + // @beta (undocumented) + getProjectLookupForRoot(rootPath: string): LookupByPath; + // @deprecated (undocumented) + getRepoState(subspace?: Subspace): RepoStateFile; + // @deprecated (undocumented) + getRepoStateFilePath(subspace?: Subspace): string; + // @beta (undocumented) + getSubspace(subspaceName: string): Subspace; + // @beta + getSubspacesForProjects(projects: Iterable): ReadonlySet; readonly gitAllowedEmailRegExps: string[]; + readonly gitChangefilesCommitMessage: string | undefined; + readonly gitChangeLogUpdateCommitMessage: string | undefined; readonly gitSampleEmail: string; + readonly gitTagSeparator: string | undefined; readonly gitVersionBumpCommitMessage: string | undefined; readonly hotfixChangeEnabled: boolean; + readonly isPnpm: boolean; static loadFromConfigurationFile(rushJsonFilename: string): RushConfiguration; // (undocumented) static loadFromDefaultLocation(options?: ITryFindRushJsonLocationOptions): RushConfiguration; @@ -334,109 +1298,358 @@ export class RushConfiguration { readonly npmOptions: NpmOptionsConfiguration; readonly npmTmpFolder: string; readonly packageManager: PackageManagerName; + readonly packageManagerOptions: PackageManagerOptionsConfigurationBase; readonly packageManagerToolFilename: string; readonly packageManagerToolVersion: string; // @beta readonly packageManagerWrapper: PackageManager; + readonly packageNameParser: PackageNameParser; readonly pnpmOptions: PnpmOptionsConfiguration; readonly projectFolderMaxDepth: number; readonly projectFolderMinDepth: number; // (undocumented) - readonly projects: RushConfigurationProject[]; - // (undocumented) - readonly projectsByName: Map; + get projects(): RushConfigurationProject[]; + // @beta (undocumented) + get projectsByName(): ReadonlyMap; + // @beta + get projectsByTag(): ReadonlyMap>; readonly repositoryDefaultBranch: string; - readonly repositoryDefaultFullyQualifiedRemoteBranch: string; + get repositoryDefaultFullyQualifiedRemoteBranch(): string; readonly repositoryDefaultRemote: string; - readonly repositoryUrl: string | undefined; + readonly repositoryUrls: string[]; + // @internal + readonly rushConfigurationJson: IRushConfigurationJson; readonly rushJsonFile: string; readonly rushJsonFolder: string; - readonly rushLinkJsonFilename: string; + // @deprecated + get rushLinkJsonFilename(): string; + get rushPluginOptionsFolder(): string; + // Warning: (ae-forgotten-export) The symbol "RushPluginsConfiguration" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + readonly _rushPluginsConfiguration: RushPluginsConfiguration; readonly shrinkwrapFilename: string; - readonly shrinkwrapFilePhrase: string; + get shrinkwrapFilePhrase(): string; + // @beta + get subspaces(): readonly Subspace[]; + // @beta + readonly subspacesConfiguration: SubspacesConfiguration | undefined; + readonly subspacesFeatureEnabled: boolean; readonly suppressNodeLtsWarning: boolean; // @beta readonly telemetryEnabled: boolean; - readonly tempShrinkwrapFilename: string; - readonly tempShrinkwrapPreinstallFilename: string; + // @deprecated + get tempShrinkwrapFilename(): string; + // @deprecated + get tempShrinkwrapPreinstallFilename(): string; static tryFindRushJsonLocation(options?: ITryFindRushJsonLocationOptions): string | undefined; tryGetProjectForPath(currentFolderPath: string): RushConfigurationProject | undefined; // @beta (undocumented) + tryGetSubspace(subspaceName: string): Subspace | undefined; + // (undocumented) + static tryLoadFromDefaultLocation(options?: ITryFindRushJsonLocationOptions): RushConfiguration | undefined; + // @beta + readonly variants: ReadonlySet; + // @beta (undocumented) readonly versionPolicyConfiguration: VersionPolicyConfiguration; + // @beta (undocumented) + readonly versionPolicyConfigurationFilePath: string; readonly yarnCacheFolder: string; readonly yarnOptions: YarnOptionsConfiguration; - } +} // @public export class RushConfigurationProject { - // Warning: (ae-forgotten-export) The symbol "IRushConfigurationProjectJson" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "IRushConfigurationProjectOptions" needs to be exported by the entry point index.d.ts // // @internal - constructor(projectJson: IRushConfigurationProjectJson, rushConfiguration: RushConfiguration, tempProjectName: string); - readonly cyclicDependencyProjects: Set; - readonly downstreamDependencyProjects: string[]; + constructor(options: IRushConfigurationProjectOptions); // @beta - readonly isMainProject: boolean; + readonly configuredSubspaceName: string | undefined; + get consumingProjects(): ReadonlySet; + // @deprecated + get cyclicDependencyProjects(): Set; + readonly decoupledLocalDependencies: Set; + get dependencyProjects(): ReadonlySet; // @deprecated - readonly packageJson: IPackageJson; + get downstreamDependencyProjects(): string[]; + // @beta + get isMainProject(): boolean; + // @deprecated + get localDependencyProjects(): ReadonlyArray; + get packageJson(): IPackageJson; // @beta readonly packageJsonEditor: PackageJsonEditor; readonly packageName: string; readonly projectFolder: string; readonly projectRelativeFolder: string; + readonly projectRushConfigFolder: string; readonly projectRushTempFolder: string; - readonly reviewCategory: string; + readonly publishFolder: string; + readonly reviewCategory: string | undefined; readonly rushConfiguration: RushConfiguration; - readonly shouldPublish: boolean; + get shouldPublish(): boolean; readonly skipRushCheck: boolean; + readonly subspace: Subspace; + // @beta + readonly tags: ReadonlySet; readonly tempProjectName: string; readonly unscopedTempProjectName: string; // @beta - readonly versionPolicy: VersionPolicy | undefined; + get versionPolicy(): VersionPolicy | undefined; // @beta readonly versionPolicyName: string | undefined; - } +} + +// @beta +export class RushConstants { + static readonly artifactoryFilename: 'artifactory.json'; + static readonly browserApprovedPackagesFilename: 'browser-approved-packages.json'; + static readonly buildCacheFilename: 'build-cache.json'; + static readonly buildCacheVersion: 1; + static readonly buildCommandName: 'build'; + static readonly bulkCommandKind: 'bulk'; + static readonly bypassPolicyFlagLongName: '--bypass-policy'; + static readonly changeFilesFolderName: 'changes'; + static readonly cobuildFilename: 'cobuild.json'; + static readonly commandLineFilename: 'command-line.json'; + static readonly commonFolderName: 'common'; + static readonly commonVersionsFilename: 'common-versions.json'; + static readonly currentVariantsFilename: 'current-variants.json'; + static readonly customTipsFilename: 'custom-tips.json'; + static readonly defaultMaxInstallAttempts: 1; + static readonly defaultSubspaceName: 'default'; + static readonly defaultWatchDebounceMs: 1000; + static readonly experimentsFilename: 'experiments.json'; + static readonly globalCommandKind: 'global'; + static readonly hashDelimiter: '|'; + static readonly lastLinkFlagFilename: 'last-link'; + static readonly mergeQueueIgnoreFileName: '.mergequeueignore'; + static readonly nodeModulesFolderName: 'node_modules'; + static readonly nonbrowserApprovedPackagesFilename: 'nonbrowser-approved-packages.json'; + static readonly npmShrinkwrapFilename: 'npm-shrinkwrap.json'; + static readonly phasedCommandKind: 'phased'; + static readonly phaseNamePrefix: '_phase:'; + // @deprecated + static readonly pinnedVersionsFilename: 'pinned-versions.json'; + static readonly pnpmConfigFilename: 'pnpm-config.json'; + static readonly pnpmfileGlobalFilename: 'global-pnpmfile.cjs'; + static readonly pnpmfileV1Filename: 'pnpmfile.js'; + static readonly pnpmfileV6Filename: '.pnpmfile.cjs'; + 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 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 rushHotlinkStateFilename: 'rush-hotlink-state.json'; + static readonly rushJsonFilename: 'rush.json'; + static readonly rushLogsFolderName: 'rush-logs'; + static readonly rushPackageName: '@microsoft/rush'; + static readonly rushPluginManifestFilename: 'rush-plugin-manifest.json'; + static readonly rushPluginsConfigFilename: 'rush-plugins.json'; + static readonly rushProjectConfigFilename: 'rush-project.json'; + static readonly rushRecyclerFolderName: 'rush-recycler'; + static readonly rushTempFolderName: 'temp'; + static readonly rushTempNpmScope: '@rush-temp'; + static readonly rushTempProjectsFolderName: 'projects'; + static readonly rushUserConfigurationFolderName: '.rush-user'; + static readonly rushVariantsFolderName: 'variants'; + static readonly rushWebSiteUrl: 'https://rushjs.io'; + static readonly subspacesConfigFilename: 'subspaces.json'; + // (undocumented) + static readonly updateCloudCredentialsCommandName: 'update-cloud-credentials'; + // (undocumented) + static readonly versionPoliciesFilename: 'version-policies.json'; + static readonly yarnShrinkwrapFilename: 'yarn.lock'; +} // @internal export class _RushGlobalFolder { constructor(); readonly nodeSpecificPath: string; readonly path: string; - } +} + +// @internal +export class _RushInternals { + static loadModule(srcImportPath: string): unknown; +} // @beta +export class RushLifecycleHooks { + readonly afterInstall: AsyncSeriesHook<[ + command: IRushCommand, + subspace: Subspace, + variant: string | undefined + ]>; + readonly beforeInstall: AsyncSeriesHook<[ + command: IGlobalCommand, + subspace: Subspace, + variant: string | undefined + ]>; + readonly flushTelemetry: AsyncParallelHook<[ReadonlyArray]>; + readonly initialize: AsyncSeriesHook; + readonly runAnyGlobalCustomCommand: AsyncSeriesHook; + readonly runAnyPhasedCommand: AsyncSeriesHook; + readonly runGlobalCustomCommand: HookMap>; + readonly runPhasedCommand: HookMap>; +} + +// @alpha +export class RushProjectConfiguration { + readonly disableBuildCacheForProject: boolean; + getCacheDisabledReason(trackedFileNames: Iterable, phaseName: string, isNoOp: boolean): string | undefined; + static getCacheDisabledReasonForProject(options: { + projectConfiguration: RushProjectConfiguration | undefined; + trackedFileNames: Iterable; + phaseName: string; + isNoOp: boolean; + }): string | undefined; + readonly incrementalBuildIgnoredGlobs: ReadonlyArray; + // (undocumented) + readonly operationSettingsByOperationName: ReadonlyMap>; + // (undocumented) + readonly project: RushConfigurationProject; + static tryLoadForProjectAsync(project: RushConfigurationProject, terminal: ITerminal): Promise; + static tryLoadForProjectsAsync(projects: Iterable, terminal: ITerminal): Promise>; + static tryLoadIgnoreGlobsForProjectAsync(project: RushConfigurationProject, terminal: ITerminal): Promise | undefined>; + validatePhaseConfiguration(phases: Iterable, terminal: ITerminal): void; +} + +// @beta (undocumented) +export class RushSession { + constructor(options: IRushSessionOptions); + // (undocumented) + getCloudBuildCacheProviderFactory(cacheProviderName: string): CloudBuildCacheProviderFactory | undefined; + // (undocumented) + getCobuildLockProviderFactory(cobuildLockProviderName: string): CobuildLockProviderFactory | undefined; + // (undocumented) + getLogger(name: string): ILogger; + // (undocumented) + readonly hooks: RushLifecycleHooks; + // (undocumented) + registerCloudBuildCacheProviderFactory(cacheProviderName: string, factory: CloudBuildCacheProviderFactory): void; + // (undocumented) + registerCobuildLockProviderFactory(cobuildLockProviderName: string, factory: CobuildLockProviderFactory): void; + // (undocumented) + get terminalProvider(): ITerminalProvider; +} + +// @beta +export class RushUserConfiguration { + readonly buildCacheFolder: string | undefined; + // (undocumented) + static getRushUserFolderPath(): string; + // (undocumented) + static initializeAsync(): Promise; +} + +// @public +export class Subspace { + // Warning: (ae-forgotten-export) The symbol "ISubspaceOptions" needs to be exported by the entry point index.d.ts + constructor(options: ISubspaceOptions); + // @internal (undocumented) + _addProject(project: RushConfigurationProject): void; + // @beta + contains(project: RushConfigurationProject): boolean; + // @deprecated (undocumented) + getCommittedShrinkwrapFilename(): string; + // @beta + getCommittedShrinkwrapFilePath(variant?: string): string; + // @beta + getCommonVersions(variant?: string): CommonVersionsConfiguration; + // @beta + getCommonVersionsFilePath(variant?: string): string; + // @beta + getPackageJsonInjectedDependenciesHash(variant?: string): string | undefined; + getPnpmCatalogsHash(): string | undefined; + // @beta + getPnpmConfigFilePath(): string; + // @beta + getPnpmfilePath(variant?: string): string; + // @beta + getPnpmOptions(): PnpmOptionsConfiguration | undefined; + // @beta + getProjects(): RushConfigurationProject[]; + // @beta + getRepoState(): RepoStateFile; + // @beta + getRepoStateFilePath(): string; + // @beta + getSubspaceConfigFolderPath(): string; + // @beta + getSubspacePnpmPatchesFolderPath(): string; + // @beta + getSubspaceTempFolderPath(): string; + // @beta + getTempShrinkwrapFilename(): string; + // @deprecated (undocumented) + getTempShrinkwrapPreinstallFilename(subspaceName?: string | undefined): string; + // @beta + getTempShrinkwrapPreinstallFilePath(): string; + // @beta + getVariantDependentSubspaceConfigFolderPath(variant: string | undefined): string; + // @beta + shouldEnsureConsistentVersions(variant?: string): boolean; + // (undocumented) + readonly subspaceName: string; +} + +// @beta +export class SubspacesConfiguration { + static explainIfInvalidSubspaceName(subspaceName: string, splitWorkspaceCompatibility?: boolean): string | undefined; + readonly preventSelectingAllSubspaces: boolean; + static requireValidSubspaceName(subspaceName: string, splitWorkspaceCompatibility?: boolean): void; + readonly splitWorkspaceCompatibility: boolean; + readonly subspaceJsonFilePath: string; + readonly subspaceNames: ReadonlySet; + // (undocumented) + readonly subspacesEnabled: boolean; + // (undocumented) + static tryLoadFromConfigurationFile(subspaceJsonFilePath: string): SubspacesConfiguration | undefined; + // (undocumented) + static tryLoadFromDefaultLocation(rushConfiguration: RushConfiguration): SubspacesConfiguration | undefined; +} + +// @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 isLockstepped: boolean; + get exemptFromRushChange(): boolean; + get includeEmailInChangeFile(): boolean; + get isLockstepped(): boolean; // @internal - abstract readonly _json: IVersionPolicyJson; + readonly _json: IVersionPolicyJson; // @internal static load(versionPolicyJson: IVersionPolicyJson): VersionPolicy | undefined; - readonly policyName: string; + get policyName(): string; setDependenciesBeforeCommit(packageName: string, configuration: RushConfiguration): void; setDependenciesBeforePublish(packageName: string, configuration: RushConfiguration): void; abstract validate(versionString: string, packageName: string): void; - } +} -// @beta +// @public export class VersionPolicyConfiguration { // @internal constructor(jsonFileName: string); bump(versionPolicyName?: string, bumpType?: BumpType, identifier?: string, shouldCommit?: boolean): void; getVersionPolicy(policyName: string): VersionPolicy; - update(versionPolicyName: string, newVersion: string): void; - validate(projectsByName: Map): void; + update(versionPolicyName: string, newVersion: string, shouldCommit?: boolean): void; + validate(projectsByName: ReadonlyMap): void; readonly versionPolicies: Map; - } +} -// @beta +// @public export enum VersionPolicyDefinitionName { // (undocumented) 'individualVersion' = 1, @@ -451,5 +1664,4 @@ export class YarnOptionsConfiguration extends PackageManagerOptionsConfiguration readonly ignoreEngines: boolean; } - ``` diff --git a/common/reviews/api/rush-redis-cobuild-plugin.api.md b/common/reviews/api/rush-redis-cobuild-plugin.api.md new file mode 100644 index 00000000000..a28011c7be2 --- /dev/null +++ b/common/reviews/api/rush-redis-cobuild-plugin.api.md @@ -0,0 +1,57 @@ +## API Report File for "@rushstack/rush-redis-cobuild-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import type { ICobuildCompletedState } from '@rushstack/rush-sdk'; +import type { ICobuildContext } from '@rushstack/rush-sdk'; +import type { ICobuildLockProvider } from '@rushstack/rush-sdk'; +import type { IRushPlugin } from '@rushstack/rush-sdk'; +import type { RedisClientOptions } from '@redis/client'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { RushSession } from '@rushstack/rush-sdk'; + +// @beta +export interface IRedisCobuildLockProviderOptions extends RedisClientOptions { + passwordEnvironmentVariable?: string; +} + +// Warning: (ae-incompatible-release-tags) The symbol "IRushRedisCobuildPluginOptions" is marked as @public, but its signature references "IRedisCobuildLockProviderOptions" which is marked as @beta +// +// @public (undocumented) +export type IRushRedisCobuildPluginOptions = IRedisCobuildLockProviderOptions; + +// @beta (undocumented) +export class RedisCobuildLockProvider implements ICobuildLockProvider { + constructor(options: IRedisCobuildLockProviderOptions, rushSession: RushSession); + acquireLockAsync(context: ICobuildContext): Promise; + // (undocumented) + connectAsync(): Promise; + // (undocumented) + disconnectAsync(): Promise; + // (undocumented) + static expandOptionsWithEnvironmentVariables(options: IRedisCobuildLockProviderOptions, environment?: NodeJS.ProcessEnv): IRedisCobuildLockProviderOptions; + // (undocumented) + getCompletedStateAsync(context: ICobuildContext): Promise; + // (undocumented) + renewLockAsync(context: ICobuildContext): Promise; + // (undocumented) + setCompletedStateAsync(context: ICobuildContext, state: ICobuildCompletedState): Promise; +} + +// @public (undocumented) +class RushRedisCobuildPlugin implements IRushPlugin { + constructor(options: IRushRedisCobuildPluginOptions); + // (undocumented) + apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void; + // (undocumented) + pluginName: string; +} +export default RushRedisCobuildPlugin; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-resolver-cache-plugin.api.md b/common/reviews/api/rush-resolver-cache-plugin.api.md new file mode 100644 index 00000000000..2ea472f1340 --- /dev/null +++ b/common/reviews/api/rush-resolver-cache-plugin.api.md @@ -0,0 +1,22 @@ +## API Report File for "@rushstack/rush-resolver-cache-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IRushPlugin } from '@rushstack/rush-sdk'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { RushSession } from '@rushstack/rush-sdk'; + +// @beta +class RushResolverCachePlugin implements IRushPlugin { + // (undocumented) + apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void; + // (undocumented) + readonly pluginName: 'RushResolverCachePlugin'; +} +export default RushResolverCachePlugin; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-sdk.api.md b/common/reviews/api/rush-sdk.api.md new file mode 100644 index 00000000000..8816b7c1edd --- /dev/null +++ b/common/reviews/api/rush-sdk.api.md @@ -0,0 +1,39 @@ +## API Report File for "@rushstack/rush-sdk" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +// @public +export interface ILoadSdkAsyncOptions { + abortSignal?: AbortSignal; + onNotifyEvent?: SdkNotifyEventCallback; + rushJsonSearchFolder?: string; +} + +// @public +export interface IProgressBarCallbackLogMessage { + kind: 'info' | 'debug'; + text: string; +} + +// @public +export interface ISdkCallbackEvent { + logMessage: IProgressBarCallbackLogMessage | undefined; + progressPercent: number | undefined; +} + +// @public +export class RushSdkLoader { + static get isLoaded(): boolean; + static loadAsync(options?: ILoadSdkAsyncOptions): Promise; +} + +// @public +export type SdkNotifyEventCallback = (sdkEvent: ISdkCallbackEvent) => void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-serve-plugin.api.md b/common/reviews/api/rush-serve-plugin.api.md new file mode 100644 index 00000000000..2cbb7e96f08 --- /dev/null +++ b/common/reviews/api/rush-serve-plugin.api.md @@ -0,0 +1,25 @@ +## API Report File for "@rushstack/rush-serve-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IRushPlugin } from '@rushstack/rush-sdk'; +import type { RushConfiguration } from '@rushstack/rush-sdk'; +import type { RushSession } from '@rushstack/rush-sdk'; + +// @public (undocumented) +class RushServePlugin implements IRushPlugin { + // Warning: (ae-forgotten-export) The symbol "IRushServePluginOptions" needs to be exported by the entry point index.d.ts + constructor(options: IRushServePluginOptions); + // (undocumented) + apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void; + // (undocumented) + readonly pluginName: 'RushServePlugin'; +} +export { RushServePlugin } +export default RushServePlugin; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-stack-compiler-2.4.api.md b/common/reviews/api/rush-stack-compiler-2.4.api.md deleted file mode 100644 index 984ccdbab7f..00000000000 --- a/common/reviews/api/rush-stack-compiler-2.4.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-2.4" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-2.7.api.md b/common/reviews/api/rush-stack-compiler-2.7.api.md deleted file mode 100644 index 9cb7197f846..00000000000 --- a/common/reviews/api/rush-stack-compiler-2.7.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-2.7" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-2.8.api.md b/common/reviews/api/rush-stack-compiler-2.8.api.md deleted file mode 100644 index 06a18b8aa16..00000000000 --- a/common/reviews/api/rush-stack-compiler-2.8.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-2.8" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-2.9.api.md b/common/reviews/api/rush-stack-compiler-2.9.api.md deleted file mode 100644 index 552f16c6104..00000000000 --- a/common/reviews/api/rush-stack-compiler-2.9.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-2.9" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.0.api.md b/common/reviews/api/rush-stack-compiler-3.0.api.md deleted file mode 100644 index 37597a050b7..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.0.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.0" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.1.api.md b/common/reviews/api/rush-stack-compiler-3.1.api.md deleted file mode 100644 index 3618969d601..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.1.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.1" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.2.api.md b/common/reviews/api/rush-stack-compiler-3.2.api.md deleted file mode 100644 index 2b3a948deba..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.2.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.2" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.3.api.md b/common/reviews/api/rush-stack-compiler-3.3.api.md deleted file mode 100644 index 617bf2153cf..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.3.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.3" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.4.api.md b/common/reviews/api/rush-stack-compiler-3.4.api.md deleted file mode 100644 index ebbf2ba322e..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.4.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.4" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.5.api.md b/common/reviews/api/rush-stack-compiler-3.5.api.md deleted file mode 100644 index 75ddc110f88..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.5.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.5" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.6.api.md b/common/reviews/api/rush-stack-compiler-3.6.api.md deleted file mode 100644 index 528383dbf84..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.6.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.6" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-stack-compiler-3.7.api.md b/common/reviews/api/rush-stack-compiler-3.7.api.md deleted file mode 100644 index dfe1f493135..00000000000 --- a/common/reviews/api/rush-stack-compiler-3.7.api.md +++ /dev/null @@ -1,130 +0,0 @@ -## API Report File for "@microsoft/rush-stack-compiler-3.7" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as ApiExtractor from '@microsoft/api-extractor'; -import { ExtractorConfig } from '@microsoft/api-extractor'; -import { IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { IPackageJson } from '@rushstack/node-core-library'; -import { ITerminalProvider } from '@rushstack/node-core-library'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Tslint from 'tslint'; -import * as Typescript from 'typescript'; - -// @beta -export class ApiExtractorRunner extends RushStackCompilerBase { - constructor(extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - constructor(options: IRushStackCompilerBaseOptions, extractorConfig: ExtractorConfig, extractorOptions: IExtractorInvokeOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export interface ILintRunnerConfig extends IRushStackCompilerBaseOptions { - displayAsError?: boolean; -} - -// @public (undocumented) -export interface IRushStackCompilerBaseOptions { - // (undocumented) - fileError: WriteFileIssueFunction; - // (undocumented) - fileWarning: WriteFileIssueFunction; -} - -// @public (undocumented) -export interface ITslintRunnerConfig extends ILintRunnerConfig { -} - -// @beta (undocumented) -export interface ITypescriptCompilerOptions extends IRushStackCompilerBaseOptions { - customArgs?: string[]; -} - -// @beta (undocumented) -export class LintRunner extends RushStackCompilerBase { - constructor(taskOptions: ILintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; - } - -// @beta (undocumented) -export abstract class RushStackCompilerBase { - constructor(taskOptions: TOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - protected _fileError: WriteFileIssueFunction; - // (undocumented) - protected _fileWarning: WriteFileIssueFunction; - // (undocumented) - protected _standardBuildFolders: StandardBuildFolders; - // (undocumented) - protected _taskOptions: TOptions; - // (undocumented) - protected _terminal: Terminal; -} - -// @beta (undocumented) -export class StandardBuildFolders { - constructor(projectFolderPath: string); - // (undocumented) - readonly distFolderPath: string; - // (undocumented) - readonly libFolderPath: string; - // (undocumented) - readonly projectFolderPath: string; - // (undocumented) - readonly srcFolderPath: string; - // (undocumented) - readonly tempFolderPath: string; - } - -// @alpha (undocumented) -export class ToolPackages { - // (undocumented) - static apiExtractor: typeof ApiExtractor; - // (undocumented) - static tslint: typeof Tslint; - // (undocumented) - static typescript: typeof Typescript; -} - -// @beta (undocumented) -export class ToolPaths { - // (undocumented) - static readonly eslintPackageJson: IPackageJson; - // (undocumented) - static readonly eslintPackagePath: string; - // (undocumented) - static readonly tslintPackageJson: IPackageJson; - // (undocumented) - static readonly tslintPackagePath: string; - // (undocumented) - static readonly typescriptPackageJson: IPackageJson; - // (undocumented) - static readonly typescriptPackagePath: string; - } - -// @beta (undocumented) -export class TslintRunner extends RushStackCompilerBase { - constructor(taskOptions: ITslintRunnerConfig, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @beta (undocumented) -export class TypescriptCompiler extends RushStackCompilerBase { - constructor(rootPath: string, terminalProvider: ITerminalProvider); - constructor(taskOptions: ITypescriptCompilerOptions, rootPath: string, terminalProvider: ITerminalProvider); - // (undocumented) - invoke(): Promise; -} - -// @public (undocumented) -export type WriteFileIssueFunction = (filePath: string, line: number, column: number, errorCode: string, message: string) => void; - - -``` diff --git a/common/reviews/api/rush-themed-ui.api.md b/common/reviews/api/rush-themed-ui.api.md new file mode 100644 index 00000000000..69176682dd2 --- /dev/null +++ b/common/reviews/api/rush-themed-ui.api.md @@ -0,0 +1,107 @@ +## API Report File for "@rushstack/rush-themed-ui" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { default as React_2 } from 'react'; + +// @public +export const Button: ({ children, disabled, onClick }: IButtonProps) => JSX.Element; + +// @public +export const Checkbox: ({ label, isChecked, onChecked }: ICheckboxProps) => JSX.Element; + +// @public +export interface IButtonProps { + // (undocumented) + children: JSX.Element | string; + // (undocumented) + disabled?: boolean; + // (undocumented) + onClick: () => void; +} + +// @public +export interface ICheckboxProps { + // (undocumented) + isChecked: boolean; + // (undocumented) + label: string; + // (undocumented) + onChecked: (checked: boolean) => void; +} + +// @public +export interface IInputProps { + // (undocumented) + onChange: (e: React_2.ChangeEvent) => void; + // (undocumented) + placeholder?: string; + // (undocumented) + type?: string; + // (undocumented) + value: string; +} + +// @public +export const Input: ({ value, placeholder, onChange, type }: IInputProps) => JSX.Element; + +// @public +export interface IScrollAreaProps { + // (undocumented) + children: React_2.ReactNode; +} + +// @public +export interface ITabsItem { + // (undocumented) + body?: React_2.ReactNode; + // (undocumented) + header: string; + // (undocumented) + value?: string; +} + +// @public +export interface ITabsProps { + // (undocumented) + def?: string; + // (undocumented) + items: ITabsItem[]; + // (undocumented) + onChange?: (value: any) => void; + // (undocumented) + renderChildren?: () => JSX.Element; + // (undocumented) + value: string; +} + +// @public +export interface ITextProps { + // (undocumented) + bold?: boolean; + // (undocumented) + children: React_2.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + size?: number; + // (undocumented) + type: TextType; +} + +// @public +export const ScrollArea: ({ children }: IScrollAreaProps) => JSX.Element; + +// @public +export const Tabs: ({ items, def, value, onChange, renderChildren }: ITabsProps) => JSX.Element; + +// @public +const Text_2: ({ type, bold, children, className, size }: ITextProps) => JSX.Element; +export { Text_2 as Text } + +// @public +export type TextType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span'; + +``` diff --git a/common/reviews/api/rushell.api.md b/common/reviews/api/rushell.api.md index 861c8627111..86ee13f9aef 100644 --- a/common/reviews/api/rushell.api.md +++ b/common/reviews/api/rushell.api.md @@ -15,5 +15,4 @@ export class Rushell { execute(script: string): IRushellExecuteResult; } - ``` diff --git a/common/reviews/api/set-webpack-public-path-plugin.api.md b/common/reviews/api/set-webpack-public-path-plugin.api.md index c2c35c6b8e1..a56b1fd1fd8 100644 --- a/common/reviews/api/set-webpack-public-path-plugin.api.md +++ b/common/reviews/api/set-webpack-public-path-plugin.api.md @@ -4,42 +4,59 @@ ```ts -import * as Webpack from 'webpack'; +import type webpack from 'webpack'; -// @public -export function getGlobalRegisterCode(debug?: boolean): string; +// @public (undocumented) +export interface IScriptNameAssetNameOptions { + useAssetName: true; +} + +// @public (undocumented) +export type IScriptNameOptions = IScriptNameAssetNameOptions | IScriptNameRegexOptions; + +// @public (undocumented) +export interface IScriptNameRegexOptions { + isTokenized?: boolean; + name: string; +} // @public export interface ISetWebpackPublicPathOptions { getPostProcessScript?: (varName: string) => string; preferLastFoundScript?: boolean; - publicPath?: string; regexVariable?: string; - skipDetection?: boolean; - systemJs?: boolean; - urlPrefix?: string; } // @public export interface ISetWebpackPublicPathPluginOptions extends ISetWebpackPublicPathOptions { - scriptName?: { - useAssetName?: boolean; - name?: string; - isTokenized?: boolean; - }; + scriptName: IScriptNameOptions; } -// @public (undocumented) -export const registryVariableName: string; +// @public +export class SetPublicPathCurrentScriptPlugin extends SetPublicPathPluginBase { + constructor(); + // (undocumented) + protected _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void; +} // @public -export class SetPublicPathPlugin implements Webpack.Plugin { +export class SetPublicPathPlugin extends SetPublicPathPluginBase { constructor(options: ISetWebpackPublicPathPluginOptions); // (undocumented) - apply(compiler: Webpack.Compiler): void; + protected _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void; + // (undocumented) + readonly options: ISetWebpackPublicPathPluginOptions; +} + +// @public (undocumented) +export abstract class SetPublicPathPluginBase implements webpack.WebpackPluginInstance { + constructor(pluginName: string); + // (undocumented) + apply(compiler: webpack.Compiler): void; // (undocumented) - options: ISetWebpackPublicPathPluginOptions; + protected abstract _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void; } +// (No @packageDocumentation comment for this package) ``` diff --git a/common/reviews/api/stream-collator.api.md b/common/reviews/api/stream-collator.api.md index 4c85f57b1b3..6c209cdd5b4 100644 --- a/common/reviews/api/stream-collator.api.md +++ b/common/reviews/api/stream-collator.api.md @@ -4,30 +4,56 @@ ```ts -// @public -export class Interleaver { - static registerTask(taskName: string, quietMode?: boolean): ITaskWriter; - static reset(): void; - static setStdOut(stdout: { - write: (text: string) => void; - }): void; - } - -// @public -export interface ITaskWriter { - // (undocumented) - close(): void; +import { ITerminalChunk } from '@rushstack/terminal'; +import { TerminalWritable } from '@rushstack/terminal'; + +// @beta @deprecated +export class CollatedTerminal { + constructor(destination: TerminalWritable); // (undocumented) - getStdError(): string; + writeChunk(chunk: ITerminalChunk): void; // (undocumented) - getStdOutput(): string; + writeStderrLine(message: string): void; // (undocumented) - write(data: string): void; + writeStdoutLine(message: string): void; +} + +// @beta +export class CollatedWriter extends TerminalWritable { + constructor(taskName: string, collator: StreamCollator); + get bufferedChunks(): ReadonlyArray; + // @internal (undocumented) + _flushBufferedChunks(): void; + get isActive(): boolean; + onClose(): void; + onWriteChunk(chunk: ITerminalChunk): void; // (undocumented) - writeError(data: string): void; + readonly taskName: string; // (undocumented) - writeLine(data: string): void; + readonly terminal: CollatedTerminal; } +// @beta +export interface IStreamCollatorOptions { + destination: TerminalWritable; + onWriterActive?: (writer: CollatedWriter) => void; +} + +// @beta +export class StreamCollator { + constructor(options: IStreamCollatorOptions); + get activeTaskName(): string; + get activeWriter(): CollatedWriter | undefined; + // (undocumented) + readonly destination: TerminalWritable; + registerTask(taskName: string): CollatedWriter; + // (undocumented) + readonly terminal: CollatedTerminal; + // @internal (undocumented) + _writerClose(writer: CollatedWriter, bufferedChunks: ITerminalChunk[]): void; + get writers(): ReadonlySet; + // @internal (undocumented) + _writerWriteChunk(writer: CollatedWriter, chunk: ITerminalChunk, bufferedChunks: ITerminalChunk[]): void; +} ``` diff --git a/common/reviews/api/terminal.api.md b/common/reviews/api/terminal.api.md new file mode 100644 index 00000000000..cd5edfb7e06 --- /dev/null +++ b/common/reviews/api/terminal.api.md @@ -0,0 +1,473 @@ +## API Report File for "@rushstack/terminal" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +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 'node:stream'; +import { WritableOptions } from 'node:stream'; + +// @public +export class AnsiEscape { + static formatForTests(text: string, options?: IAnsiEscapeConvertForTestsOptions): string; + // (undocumented) + static getEscapeSequenceForAnsiCode(code: number): string; + static removeCodes(text: string): string; +} + +// @public +export class CallbackWritable extends TerminalWritable { + constructor(options: ICallbackWritableOptions); + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; +} + +// @public +export class Colorize { + // (undocumented) + static black(text: string): string; + // (undocumented) + static blackBackground(text: string): string; + // (undocumented) + static blink(text: string): string; + // (undocumented) + static blue(text: string): string; + // (undocumented) + static blueBackground(text: string): string; + // (undocumented) + static bold(text: string): string; + // (undocumented) + static cyan(text: string): string; + // (undocumented) + static cyanBackground(text: string): string; + // (undocumented) + static dim(text: string): string; + // (undocumented) + static gray(text: string): string; + // (undocumented) + static grayBackground(text: string): string; + // (undocumented) + static green(text: string): string; + // (undocumented) + static greenBackground(text: string): string; + // (undocumented) + static hidden(text: string): string; + // (undocumented) + static invertColor(text: string): string; + // (undocumented) + static magenta(text: string): string; + // (undocumented) + static magentaBackground(text: string): string; + // (undocumented) + static rainbow(text: string): string; + // (undocumented) + static red(text: string): string; + // (undocumented) + static redBackground(text: string): string; + // (undocumented) + static underline(text: string): string; + // (undocumented) + static white(text: string): string; + // (undocumented) + static whiteBackground(text: string): string; + // (undocumented) + static yellow(text: string): string; + // (undocumented) + static yellowBackground(text: string): string; +} + +// @beta +export class ConsoleTerminalProvider implements ITerminalProvider { + constructor(options?: Partial); + debugEnabled: boolean; + get eolCharacter(): string; + // (undocumented) + static readonly supportsColor: boolean; + readonly supportsColor: boolean; + verboseEnabled: boolean; + write(data: string, severity: TerminalProviderSeverity): void; +} + +// @public +export const DEFAULT_CONSOLE_WIDTH: number; + +// @beta +export class DiscardStdoutTransform extends TerminalTransform { + constructor(options: IDiscardStdoutTransformOptions); + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; +} + +// @public +export interface IAnsiEscapeConvertForTestsOptions { + encodeNewlines?: boolean; +} + +// @public +export interface ICallbackWritableOptions { + // (undocumented) + onWriteChunk: (chunk: ITerminalChunk) => void; +} + +// @beta +export interface IConsoleTerminalProviderOptions { + debugEnabled: boolean; + verboseEnabled: boolean; +} + +// @beta +export interface IDiscardStdoutTransformOptions extends ITerminalTransformOptions { +} + +// @beta +export interface IDynamicPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase { + getPrefix: () => string; +} + +// @public +export interface INormalizeNewlinesTextRewriterOptions { + ensureNewlineAtEnd?: boolean; + newlineKind: NewlineKind; +} + +// @beta (undocumented) +export type IPrefixProxyTerminalProviderOptions = IStaticPrefixProxyTerminalProviderOptions | IDynamicPrefixProxyTerminalProviderOptions; + +// @beta (undocumented) +export interface IPrefixProxyTerminalProviderOptionsBase { + terminalProvider: ITerminalProvider; +} + +// @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: Iterable; +} + +// @beta +export interface IStaticPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase { + prefix: string; +} + +// @beta +export interface IStdioLineTransformOptions extends ITerminalTransformOptions { + newlineKind?: NewlineKind; +} + +// @beta +export interface IStdioSummarizerOptions extends ITerminalWritableOptions { + leadingLines?: number; + trailingLines?: number; +} + +// @beta (undocumented) +export interface IStringBufferOutputOptions { + normalizeSpecialCharacters: boolean; +} + +// @beta (undocumented) +export interface ITerminal { + registerProvider(provider: ITerminalProvider): void; + unregisterProvider(provider: ITerminalProvider): void; + write(...messageParts: TerminalWriteParameters): void; + writeDebug(...messageParts: TerminalWriteParameters): void; + writeDebugLine(...messageParts: TerminalWriteParameters): void; + writeError(...messageParts: TerminalWriteParameters): void; + writeErrorLine(...messageParts: TerminalWriteParameters): void; + writeLine(...messageParts: TerminalWriteParameters): void; + writeVerbose(...messageParts: TerminalWriteParameters): void; + writeVerboseLine(...messageParts: TerminalWriteParameters): void; + writeWarning(...messageParts: TerminalWriteParameters): void; + writeWarningLine(...messageParts: TerminalWriteParameters): void; +} + +// @public +export interface ITerminalChunk { + kind: TerminalChunkKind; + text: string; +} + +// @beta +export interface ITerminalProvider { + eolCharacter: string; + supportsColor: boolean; + write(data: string, severity: TerminalProviderSeverity): void; +} + +// @beta +export interface ITerminalStreamWritableOptions { + severity: TerminalProviderSeverity; + terminal: ITerminal; + writableOptions?: WritableOptions; +} + +// @public +export interface ITerminalTransformOptions extends ITerminalWritableOptions { + destination: TerminalWritable; + preventDestinationAutoclose?: boolean; +} + +// @public +export interface ITerminalWritableOptions { + preventAutoclose?: boolean; +} + +// @beta (undocumented) +export interface ITerminalWriteOptions { + doNotOverrideSgrCodes?: boolean; +} + +// @public +export interface ITextRewriterTransformOptions extends ITerminalTransformOptions { + ensureNewlineAtEnd?: boolean; + normalizeNewlines?: NewlineKind; + removeColors?: boolean; + textRewriters?: TextRewriter[]; +} + +// @beta +export class MockWritable extends TerminalWritable { + // (undocumented) + readonly chunks: ITerminalChunk[]; + // (undocumented) + getAllOutput(): string; + // (undocumented) + getFormattedChunks(): ITerminalChunk[]; + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; + // (undocumented) + 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); + // (undocumented) + close(unknownState: TextRewriterState): string; + readonly ensureNewlineAtEnd: boolean; + // (undocumented) + initialize(): TextRewriterState; + readonly newline: string; + readonly newlineKind: NewlineKind; + // (undocumented) + process(unknownState: TextRewriterState, text: string): string; +} + +// @beta +export class PrefixProxyTerminalProvider implements ITerminalProvider { + constructor(options: IPrefixProxyTerminalProviderOptions); + // @override (undocumented) + get eolCharacter(): string; + // @override (undocumented) + get supportsColor(): boolean; + // @override (undocumented) + write(data: string, severity: TerminalProviderSeverity): void; +} + +// @public +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, boxWidth?: number): void; + static wrapWords(text: string, maxLineLength?: number, indent?: number): string; + static wrapWords(text: string, maxLineLength?: number, linePrefix?: string): string; + static wrapWords(text: string, maxLineLength?: number, indentOrLinePrefix?: number | string): string; + static wrapWordsToLines(text: string, maxLineLength?: number, indent?: number): string[]; + static wrapWordsToLines(text: string, maxLineLength?: number, linePrefix?: string): string[]; + 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) + close(unknownState: TextRewriterState): string; + // (undocumented) + initialize(): TextRewriterState; + // (undocumented) + process(unknownState: TextRewriterState, text: string): string; +} + +// @public +export class SplitterTransform extends TerminalWritable { + constructor(options: ISplitterTransformOptions); + addDestination(destination: TerminalWritable): void; + // (undocumented) + get destinations(): ReadonlySet; + // (undocumented) + protected onClose(): void; + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; + removeDestination(destination: TerminalWritable, close?: boolean): boolean; +} + +// @beta +export class StderrLineTransform extends TerminalTransform { + constructor(options: IStdioLineTransformOptions); + // (undocumented) + readonly newline: string; + // (undocumented) + protected onClose(): void; + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; +} + +// @beta +export class StdioSummarizer extends TerminalWritable { + constructor(options?: IStdioSummarizerOptions); + getReport(): string; + // (undocumented) + onWriteChunk(chunk: ITerminalChunk): void; +} + +// @public +export class StdioWritable extends TerminalWritable { + // (undocumented) + static instance: StdioWritable; + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; +} + +// @beta +export class StringBufferTerminalProvider implements ITerminalProvider { + constructor(supportsColor?: boolean); + get eolCharacter(): string; + getDebugOutput(options?: IStringBufferOutputOptions): string; + getErrorOutput(options?: IStringBufferOutputOptions): string; + getOutput(options?: IStringBufferOutputOptions): string; + // @deprecated (undocumented) + getVerbose(options?: IStringBufferOutputOptions): string; + getVerboseOutput(options?: IStringBufferOutputOptions): string; + getWarningOutput(options?: IStringBufferOutputOptions): string; + get supportsColor(): boolean; + write(data: string, severity: TerminalProviderSeverity): void; +} + +// @beta +export class Terminal implements ITerminal { + constructor(provider: ITerminalProvider); + registerProvider(provider: ITerminalProvider): void; + unregisterProvider(provider: ITerminalProvider): void; + write(...messageParts: TerminalWriteParameters): void; + writeDebug(...messageParts: TerminalWriteParameters): void; + writeDebugLine(...messageParts: TerminalWriteParameters): void; + writeError(...messageParts: TerminalWriteParameters): void; + writeErrorLine(...messageParts: TerminalWriteParameters): void; + writeLine(...messageParts: TerminalWriteParameters): void; + writeVerbose(...messageParts: TerminalWriteParameters): void; + writeVerboseLine(...messageParts: TerminalWriteParameters): void; + writeWarning(...messageParts: TerminalWriteParameters): void; + writeWarningLine(...messageParts: TerminalWriteParameters): void; +} + +// @public +export enum TerminalChunkKind { + Stderr = "E", + Stdout = "O" +} + +// @beta +export enum TerminalProviderSeverity { + // (undocumented) + debug = 4, + // (undocumented) + error = 2, + // (undocumented) + log = 0, + // (undocumented) + verbose = 3, + // (undocumented) + warning = 1 +} + +// @beta +export class TerminalStreamWritable extends Writable { + constructor(options: ITerminalStreamWritableOptions); + // (undocumented) + _write(chunk: string | Buffer | Uint8Array, encoding: string, callback: (error?: Error | null) => void): void; +} + +// @public +export abstract class TerminalTransform extends TerminalWritable { + constructor(options: ITerminalTransformOptions); + // @sealed + protected autocloseDestination(): void; + readonly destination: TerminalWritable; + // @override (undocumented) + protected onClose(): void; + readonly preventDestinationAutoclose: boolean; +} + +// @public +export abstract class TerminalWritable { + constructor(options?: ITerminalWritableOptions); + // @sealed + close(): void; + // @sealed + get isOpen(): boolean; + // @virtual + protected onClose(): void; + protected abstract onWriteChunk(chunk: ITerminalChunk): void; + // (undocumented) + readonly preventAutoclose: boolean; + // @sealed + writeChunk(chunk: ITerminalChunk): void; +} + +// @beta (undocumented) +export type TerminalWriteParameters = string[] | [...string[], ITerminalWriteOptions]; + +// @public +export abstract class TextRewriter { + abstract close(state: TextRewriterState): string; + abstract initialize(): TextRewriterState; + abstract process(state: TextRewriterState, input: string): string; +} + +// @public +export type TextRewriterState = Brand; + +// @public +export class TextRewriterTransform extends TerminalTransform { + constructor(options: ITextRewriterTransformOptions); + // (undocumented) + protected onClose(): void; + // (undocumented) + protected onWriteChunk(chunk: ITerminalChunk): void; + // (undocumented) + readonly textRewriters: ReadonlyArray; +} + +``` diff --git a/common/reviews/api/tree-pattern.api.md b/common/reviews/api/tree-pattern.api.md new file mode 100644 index 00000000000..e8b299c28d9 --- /dev/null +++ b/common/reviews/api/tree-pattern.api.md @@ -0,0 +1,26 @@ +## API Report File for "@rushstack/tree-pattern" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export type ITreePatternCaptureSet = { + [tagName: string]: TreeNode; +} | { + failPath: string; +}; + +// @public +export type TreeNode = any; + +// @public +export class TreePattern { + constructor(pattern: TreeNode); + match(root: TreeNode, captures?: ITreePatternCaptureSet): boolean; + static oneOf(possibleSubtrees: TreeNode[]): TreeNode; + static tag(tagName: string, subtree?: TreeNode): TreeNode; +} + + +``` diff --git a/common/reviews/api/ts-command-line.api.md b/common/reviews/api/ts-command-line.api.md index 090c711c465..3541c82bb73 100644 --- a/common/reviews/api/ts-command-line.api.md +++ b/common/reviews/api/ts-command-line.api.md @@ -6,6 +6,18 @@ import * as argparse from 'argparse'; +// @public +export class AliasCommandLineAction extends CommandLineAction { + constructor(options: IAliasCommandLineActionOptions); + readonly defaultParameters: ReadonlyArray; + protected onExecuteAsync(): Promise; + // @internal + _processParsedData(parserOptions: ICommandLineParserOptions, data: _ICommandLineParserData): void; + // @internal (undocumented) + _registerDefinedParameters(state: _IRegisterDefinedParametersState): void; + readonly targetAction: CommandLineAction; +} + // @public export abstract class CommandLineAction extends CommandLineParameterProvider { constructor(options: ICommandLineActionOptions); @@ -14,43 +26,77 @@ export abstract class CommandLineAction extends CommandLineParameterProvider { _buildParser(actionsSubParser: argparse.SubParser): void; readonly documentation: string; // @internal - _execute(): Promise; - // @internal - protected _getArgumentParser(): argparse.ArgumentParser; - protected abstract onDefineParameters(): void; - protected abstract onExecute(): Promise; + _executeAsync(): Promise; // @internal - _processParsedData(data: _ICommandLineParserData): void; + _getArgumentParser(): argparse.ArgumentParser; + protected abstract onExecuteAsync(): Promise; readonly summary: string; } // @public -export class CommandLineChoiceParameter extends CommandLineParameter { +export class CommandLineChoiceListParameter extends CommandLineParameterBase { // @internal - constructor(definition: ICommandLineChoiceDefinition); - readonly alternatives: ReadonlyArray; + constructor(definition: ICommandLineChoiceListDefinition); + readonly alternatives: ReadonlySet; // @override appendToArgList(argList: string[]): void; - readonly defaultValue: string | undefined; + readonly completions: (() => Promise | ReadonlySet>) | undefined; + readonly kind: CommandLineParameterKind.ChoiceList; + // @internal + _setValue(data: unknown): void; + get values(): ReadonlyArray; +} + +// @public +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; // @internal _getSupplementaryNotes(supplementaryNotes: string[]): void; - readonly kind: CommandLineParameterKind; + readonly kind: CommandLineParameterKind.Choice; // @internal - _setValue(data: any): void; - readonly value: string | undefined; - } + _setValue(data: unknown): void; + get value(): TChoice | undefined; +} // @public -export class CommandLineFlagParameter extends CommandLineParameter { +export enum CommandLineConstants { + TabCompletionActionName = "tab-complete" +} + +// @public +export class CommandLineFlagParameter extends CommandLineParameterBase { // @internal constructor(definition: ICommandLineFlagDefinition); // @override appendToArgList(argList: string[]): void; - readonly kind: CommandLineParameterKind; + readonly kind: CommandLineParameterKind.Flag; // @internal - _setValue(data: any): void; - readonly value: boolean; - } + _setValue(data: unknown): void; + get value(): boolean; +} + +// @public +export class CommandLineHelper { + static isTabCompletionActionRequest(argv: string[]): boolean; +} + +// @public +export class CommandLineIntegerListParameter extends CommandLineParameterWithArgument { + // @internal + constructor(definition: ICommandLineIntegerListDefinition); + // @override + appendToArgList(argList: string[]): void; + readonly kind: CommandLineParameterKind.IntegerList; + // @internal + _setValue(data: unknown): void; + get values(): ReadonlyArray; +} // @public export class CommandLineIntegerParameter extends CommandLineParameterWithArgument { @@ -61,39 +107,55 @@ export class CommandLineIntegerParameter extends CommandLineParameterWithArgumen readonly defaultValue: number | undefined; // @internal _getSupplementaryNotes(supplementaryNotes: string[]): void; - readonly kind: CommandLineParameterKind; + readonly kind: CommandLineParameterKind.Integer; // @internal - _setValue(data: any): void; - readonly value: number | undefined; - } + _setValue(data: unknown): void; + 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; abstract appendToArgList(argList: string[]): void; readonly description: string; readonly environmentVariable: string | undefined; // @internal _getSupplementaryNotes(supplementaryNotes: string[]): void; - abstract readonly kind: CommandLineParameterKind; + abstract get kind(): CommandLineParameterKind; readonly longName: string; + readonly parameterGroup: string | typeof SCOPING_PARAMETER_GROUP | undefined; + readonly parameterScope: string | undefined; // @internal - _parserKey: string; - protected reportInvalidData(data: any): never; + _parserKey: string | undefined; + // @internal (undocumented) + _postParse?: () => void; + // @internal (undocumented) + _preParse?: () => void; + protected reportInvalidData(data: unknown): never; readonly required: boolean; + readonly scopedLongName: string | undefined; // @internal - abstract _setValue(data: any): void; - readonly shortName: string | undefined; + abstract _setValue(data: unknown): void; + get shortName(): string | undefined; + readonly undocumentedSynonyms: string[] | undefined; // (undocumented) protected validateDefaultValue(hasDefaultValue: boolean): void; + // @internal (undocumented) + _validateValue?: () => void; } // @public export enum CommandLineParameterKind { Choice = 0, + ChoiceList = 5, Flag = 1, Integer = 2, + IntegerList = 6, String = 3, StringList = 4 } @@ -102,60 +164,130 @@ export enum CommandLineParameterKind { export abstract class CommandLineParameterProvider { // @internal constructor(); - defineChoiceParameter(definition: ICommandLineChoiceDefinition): CommandLineChoiceParameter; + // @internal (undocumented) + readonly _ambiguousParameterParserKeysByName: Map; + // @internal (undocumented) + protected _defineAmbiguousParameter(name: string): string; + defineChoiceListParameter(definition: ICommandLineChoiceListDefinition): CommandLineChoiceListParameter; + defineChoiceParameter(definition: ICommandLineChoiceDefinition & { + required: false | undefined; + defaultValue: undefined; + }): CommandLineChoiceParameter; + defineChoiceParameter(definition: ICommandLineChoiceDefinition & { + required: true; + }): IRequiredCommandLineChoiceParameter; + defineChoiceParameter(definition: ICommandLineChoiceDefinition & { + defaultValue: TChoice; + }): IRequiredCommandLineChoiceParameter; + defineChoiceParameter(definition: ICommandLineChoiceDefinition): CommandLineChoiceParameter; + defineCommandLineRemainder(definition: ICommandLineRemainderDefinition): CommandLineRemainder; defineFlagParameter(definition: ICommandLineFlagDefinition): CommandLineFlagParameter; + defineIntegerListParameter(definition: ICommandLineIntegerListDefinition): CommandLineIntegerListParameter; + defineIntegerParameter(definition: ICommandLineIntegerDefinition & { + required: false | undefined; + defaultValue: undefined; + }): CommandLineIntegerParameter; + defineIntegerParameter(definition: ICommandLineIntegerDefinition & { + required: true; + }): IRequiredCommandLineIntegerParameter; + defineIntegerParameter(definition: ICommandLineIntegerDefinition & { + defaultValue: number; + }): IRequiredCommandLineIntegerParameter; defineIntegerParameter(definition: ICommandLineIntegerDefinition): CommandLineIntegerParameter; + // @internal (undocumented) + protected _defineParameter(parameter: CommandLineParameter): void; defineStringListParameter(definition: ICommandLineStringListDefinition): CommandLineStringListParameter; + defineStringParameter(definition: ICommandLineStringDefinition & { + required: false | undefined; + defaultValue: undefined; + }): CommandLineStringParameter; + defineStringParameter(definition: ICommandLineStringDefinition & { + required: true; + }): IRequiredCommandLineStringParameter; + defineStringParameter(definition: ICommandLineStringDefinition & { + defaultValue: string; + }): IRequiredCommandLineStringParameter; defineStringParameter(definition: ICommandLineStringDefinition): CommandLineStringParameter; // @internal protected abstract _getArgumentParser(): argparse.ArgumentParser; - getChoiceParameter(parameterLongName: string): CommandLineChoiceParameter; - getFlagParameter(parameterLongName: string): CommandLineFlagParameter; - getIntegerParameter(parameterLongName: string): CommandLineIntegerParameter; - getStringListParameter(parameterLongName: string): CommandLineStringListParameter; - getStringParameter(parameterLongName: string): CommandLineStringParameter; - protected abstract onDefineParameters(): void; - readonly parameters: ReadonlyArray; + getChoiceListParameter(parameterLongName: string, parameterScope?: string): CommandLineChoiceListParameter; + getChoiceParameter(parameterLongName: string, parameterScope?: string): CommandLineChoiceParameter; + getFlagParameter(parameterLongName: string, parameterScope?: string): CommandLineFlagParameter; + getIntegerListParameter(parameterLongName: string, parameterScope?: string): CommandLineIntegerListParameter; + getIntegerParameter(parameterLongName: string, parameterScope?: string): CommandLineIntegerParameter; + getParameterStringMap(): Record; + getStringListParameter(parameterLongName: string, parameterScope?: string): CommandLineStringListParameter; + getStringParameter(parameterLongName: string, parameterScope?: string): CommandLineStringParameter; + get parameters(): ReadonlyArray; + get parametersProcessed(): boolean; + parseScopedLongName(scopedLongName: string): IScopedLongNameParseResult; + // @internal + _postParse(): void; + // @internal + _preParse(): void; + // @internal + _processParsedData(parserOptions: ICommandLineParserOptions, data: _ICommandLineParserData): void; + // (undocumented) + protected _registerAmbiguousParameter(name: string, parserKey: string): void; + // @internal (undocumented) + _registerDefinedParameters(state: _IRegisterDefinedParametersState): void; + // @internal (undocumented) + protected readonly _registeredParameterParserKeysByName: Map; // @internal (undocumented) - protected _processParsedData(data: _ICommandLineParserData): 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 getCompletionsAsync: (() => Promise | ReadonlySet>) | undefined; +} // @public export abstract class CommandLineParser extends CommandLineParameterProvider { constructor(options: ICommandLineParserOptions); - readonly actions: ReadonlyArray; + get actions(): ReadonlyArray; addAction(action: CommandLineAction): void; - execute(args?: string[]): Promise; - executeWithoutErrorHandling(args?: string[]): Promise; + executeAsync(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; - readonly toolDescription: string; - readonly toolFilename: string; tryGetAction(actionName: string): CommandLineAction | undefined; } +// @public +export class CommandLineRemainder { + // @internal + constructor(definition: ICommandLineRemainderDefinition); + // @override + appendToArgList(argList: string[]): void; + readonly description: string; + // @internal + _setValue(data: unknown): void; + get values(): ReadonlyArray; +} + // @public export class CommandLineStringListParameter extends CommandLineParameterWithArgument { // @internal constructor(definition: ICommandLineStringListDefinition); // @override appendToArgList(argList: string[]): void; - readonly kind: CommandLineParameterKind; + readonly kind: CommandLineParameterKind.StringList; // @internal - _setValue(data: any): void; - readonly values: ReadonlyArray; - } + _setValue(data: unknown): void; + get values(): ReadonlyArray; +} // @public export class CommandLineStringParameter extends CommandLineParameterWithArgument { @@ -166,38 +298,47 @@ export class CommandLineStringParameter extends CommandLineParameterWithArgument readonly defaultValue: string | undefined; // @internal _getSupplementaryNotes(supplementaryNotes: string[]): void; - readonly kind: CommandLineParameterKind; + readonly kind: CommandLineParameterKind.String; // @internal - _setValue(data: any): void; - readonly value: string | undefined; - } + _setValue(data: unknown): void; + get value(): string | undefined; +} // @public (undocumented) export class DynamicCommandLineAction extends CommandLineAction { // (undocumented) - protected onDefineParameters(): void; - // (undocumented) - protected onExecute(): Promise; + protected onExecuteAsync(): Promise; } // @public (undocumented) export class DynamicCommandLineParser extends CommandLineParser { - // (undocumented) - protected onDefineParameters(): void; +} + +// @public +export interface IAliasCommandLineActionOptions { + aliasName: string; + defaultParameters?: string[]; + targetAction: CommandLineAction; + toolFilename: string; } // @public export interface IBaseCommandLineDefinition { + allowNonStandardEnvironmentVariableNames?: boolean; description: string; environmentVariable?: string; + parameterGroup?: string | typeof SCOPING_PARAMETER_GROUP; parameterLongName: string; + parameterScope?: string; parameterShortName?: string; required?: boolean; + undocumentedSynonyms?: string[]; } // @public export interface IBaseCommandLineDefinitionWithArgument extends IBaseCommandLineDefinition { argumentName: string; + getCompletionsAsync?: () => Promise | ReadonlySet>; } // @public @@ -208,9 +349,16 @@ export interface ICommandLineActionOptions { } // @public -export interface ICommandLineChoiceDefinition extends IBaseCommandLineDefinition { - alternatives: string[]; - defaultValue?: string; +export interface ICommandLineChoiceDefinition extends IBaseCommandLineDefinition { + alternatives: ReadonlyArray | ReadonlySet; + completions?: () => Promise | ReadonlySet>; + defaultValue?: TChoice; +} + +// @public +export interface ICommandLineChoiceListDefinition extends IBaseCommandLineDefinition { + alternatives: ReadonlyArray | ReadonlySet; + completions?: () => Promise | ReadonlySet>; } // @public @@ -222,20 +370,35 @@ export interface ICommandLineIntegerDefinition extends IBaseCommandLineDefinitio defaultValue?: number; } +// @public +export interface ICommandLineIntegerListDefinition extends IBaseCommandLineDefinitionWithArgument { +} + // @internal export interface _ICommandLineParserData { // (undocumented) [key: string]: any; // (undocumented) action: string; + // (undocumented) + aliasAction?: string; + // (undocumented) + aliasDocumentation?: string; } // @public export interface ICommandLineParserOptions { + enableTabCompletionAction?: boolean; toolDescription: string; + toolEpilog?: string; toolFilename: string; } +// @public +export interface ICommandLineRemainderDefinition { + description: string; +} + // @public export interface ICommandLineStringDefinition extends IBaseCommandLineDefinitionWithArgument { defaultValue?: string; @@ -245,5 +408,52 @@ export interface ICommandLineStringDefinition extends IBaseCommandLineDefinition export interface ICommandLineStringListDefinition extends IBaseCommandLineDefinitionWithArgument { } +// @internal +export interface _IRegisterDefinedParametersState { + parentParameterNames: Set; +} + +// @public +export interface IRequiredCommandLineChoiceParameter extends CommandLineChoiceParameter { + // (undocumented) + readonly value: TChoice; +} + +// @public +export interface IRequiredCommandLineIntegerParameter extends CommandLineIntegerParameter { + // (undocumented) + readonly value: number; +} + +// @public +export interface IRequiredCommandLineStringParameter extends CommandLineStringParameter { + // (undocumented) + readonly value: string; +} + +// @public +export interface IScopedLongNameParseResult { + longName: string; + scope: string | undefined; +} + +// @public +export abstract class ScopedCommandLineAction extends CommandLineAction { + constructor(options: ICommandLineActionOptions); + // @internal (undocumented) + protected _defineParameter(parameter: CommandLineParameter): void; + // @internal + _executeAsync(): Promise; + // @internal + protected _getScopedCommandLineParser(): CommandLineParser; + protected abstract onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void; + protected abstract onExecuteAsync(): Promise; + get parameters(): ReadonlyArray; + // @internal + _processParsedData(parserOptions: ICommandLineParserOptions, data: _ICommandLineParserData): void; + // @internal (undocumented) + _registerDefinedParameters(state: _IRegisterDefinedParametersState): void; + static readonly ScopingParameterGroup: typeof SCOPING_PARAMETER_GROUP; +} ``` diff --git a/common/reviews/api/typings-generator.api.md b/common/reviews/api/typings-generator.api.md index a8a75f30ee0..a942f38b474 100644 --- a/common/reviews/api/typings-generator.api.md +++ b/common/reviews/api/typings-generator.api.md @@ -4,12 +4,30 @@ ```ts -import { Terminal } from '@rushstack/node-core-library'; +import { ITerminal } from '@rushstack/terminal'; // @public (undocumented) -export interface IStringValuesTypingsGeneratorOptions extends ITypingsGeneratorOptions { - // (undocumented) - exportAsDefault?: boolean; +export interface IExportAsDefaultOptions { + // @deprecated (undocumented) + documentationComment?: string; + interfaceDocumentationComment?: string; + interfaceName?: string; + valueDocumentationComment?: string; +} + +// @public (undocumented) +export interface IStringValuesTypingsGeneratorBaseOptions { + exportAsDefault?: boolean | IExportAsDefaultOptions; + // @deprecated (undocumented) + exportAsDefaultInterfaceName?: string; +} + +// @public (undocumented) +export interface IStringValuesTypingsGeneratorOptions extends ITypingsGeneratorOptions, IStringValuesTypingsGeneratorBaseOptions { +} + +// @public (undocumented) +export interface IStringValuesTypingsGeneratorOptionsWithCustomReadFile extends ITypingsGeneratorOptionsWithCustomReadFile, IStringValuesTypingsGeneratorBaseOptions { } // @public (undocumented) @@ -22,43 +40,73 @@ export interface IStringValueTyping { // @public (undocumented) export interface IStringValueTypings { + exportAsDefault?: boolean | IExportAsDefaultOptions; // (undocumented) typings: IStringValueTyping[]; } // @public (undocumented) -export interface ITypingsGeneratorOptions { - // (undocumented) - fileExtensions: string[]; - // (undocumented) - filesToIgnore?: string[]; +export interface ITypingsGeneratorBaseOptions { // (undocumented) generatedTsFolder: string; // (undocumented) - parseAndGenerateTypings: (fileContents: string, filePath: string) => TTypingsResult; + globsToIgnore?: string[]; + // (undocumented) + secondaryGeneratedTsFolders?: string[]; // (undocumented) srcFolder: string; // (undocumented) - terminal?: Terminal; + terminal?: ITerminal; } -// @public -export class StringValuesTypingsGenerator extends TypingsGenerator { - constructor(options: IStringValuesTypingsGeneratorOptions); +// @public (undocumented) +export interface ITypingsGeneratorOptions extends ITypingsGeneratorOptionsWithoutReadFile { + // (undocumented) + readFile?: ReadFile; } // @public -export class TypingsGenerator { - constructor(options: ITypingsGeneratorOptions); +export interface ITypingsGeneratorOptionsWithCustomReadFile extends ITypingsGeneratorOptionsWithoutReadFile { + // (undocumented) + readFile: ReadFile; +} + +// @public (undocumented) +export interface ITypingsGeneratorOptionsWithoutReadFile extends ITypingsGeneratorBaseOptions { // (undocumented) - generateTypings(): void; + fileExtensions: string[]; // (undocumented) - protected _options: ITypingsGeneratorOptions; + getAdditionalOutputFiles?: (relativePath: string) => string[]; // (undocumented) - runWatcher(): void; + parseAndGenerateTypings: (fileContents: TFileContents, filePath: string, relativePath: string) => TTypingsResult | Promise; } +// @public (undocumented) +export type ReadFile = (filePath: string, relativePath: string) => Promise | TFileContents; + +// @public +export class StringValuesTypingsGenerator extends TypingsGenerator { + constructor(options: TFileContents extends string ? IStringValuesTypingsGeneratorOptions : never); + constructor(options: IStringValuesTypingsGeneratorOptionsWithCustomReadFile); +} -// (No @packageDocumentation comment for this package) +// @public +export class TypingsGenerator { + 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; + registerDependency(consumer: string, rawDependency: string): void; + // (undocumented) + runWatcherAsync(): Promise; + readonly sourceFolderPath: string; + // (undocumented) + protected readonly terminal: ITerminal; +} ``` diff --git a/common/reviews/api/web-library-build-test.api.md b/common/reviews/api/web-library-build-test.api.md deleted file mode 100644 index 5ea92df22d0..00000000000 --- a/common/reviews/api/web-library-build-test.api.md +++ /dev/null @@ -1,19 +0,0 @@ -## API Report File for "web-library-build-test" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -// @public (undocumented) -export function add(num1: number, num2: number): number; - -// @public (undocumented) -export function log(message: string): void; - -// @public (undocumented) -export function logClass(): void; - - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/web-library-build.api.md b/common/reviews/api/web-library-build.api.md deleted file mode 100644 index 4bd50e35185..00000000000 --- a/common/reviews/api/web-library-build.api.md +++ /dev/null @@ -1,52 +0,0 @@ -## API Report File for "@microsoft/web-library-build" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { CopyTask } from '@microsoft/gulp-core-build'; -import { GenerateShrinkwrapTask } from '@microsoft/gulp-core-build'; -import { GulpTask } from '@microsoft/gulp-core-build'; -import gulpType = require('gulp'); -import { IExecutable } from '@microsoft/gulp-core-build'; -import { ValidateShrinkwrapTask } from '@microsoft/gulp-core-build'; - -// @public (undocumented) -export const buildTasks: IExecutable; - -// @public (undocumented) -export const bundleTasks: IExecutable; - -// @public (undocumented) -export const defaultTasks: IExecutable; - -// @public (undocumented) -export const generateShrinkwrapTask: GenerateShrinkwrapTask; - -// @public (undocumented) -export const postCopy: CopyTask; - -// Warning: (ae-forgotten-export) The symbol "PostProcessSourceMaps" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export const postProcessSourceMapsTask: PostProcessSourceMaps; - -// @public (undocumented) -export const preCopy: CopyTask; - -// @public (undocumented) -export const testTasks: IExecutable; - -// @public (undocumented) -export const validateShrinkwrapTask: ValidateShrinkwrapTask; - - -export * from "@microsoft/gulp-core-build"; -export * from "@microsoft/gulp-core-build-sass"; -export * from "@microsoft/gulp-core-build-serve"; -export * from "@microsoft/gulp-core-build-typescript"; -export * from "@microsoft/gulp-core-build-webpack"; - -// (No @packageDocumentation comment for this package) - -``` diff --git a/common/reviews/api/webpack-deep-imports-plugin.api.md b/common/reviews/api/webpack-deep-imports-plugin.api.md new file mode 100644 index 00000000000..6090d7ba889 --- /dev/null +++ b/common/reviews/api/webpack-deep-imports-plugin.api.md @@ -0,0 +1,29 @@ +## API Report File for "@rushstack/webpack-deep-imports-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Compiler } from 'webpack'; +import { DllPlugin } from 'webpack'; + +// @public +export class DeepImportsPlugin extends DllPlugin { + constructor(options: IDeepImportsPluginOptions); + // (undocumented) + apply(compiler: Compiler): void; +} + +// Warning: (ae-forgotten-export) The symbol "DllPluginOptions" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export interface IDeepImportsPluginOptions extends DllPluginOptions { + dTsFilesInputFolderName?: string; + inFolderName: string; + outFolderName: string; + pathsToIgnore?: string[]; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/webpack-embedded-dependencies-plugin.api.md b/common/reviews/api/webpack-embedded-dependencies-plugin.api.md new file mode 100644 index 00000000000..1fa9db5337d --- /dev/null +++ b/common/reviews/api/webpack-embedded-dependencies-plugin.api.md @@ -0,0 +1,46 @@ +## API Report File for "@rushstack/webpack-embedded-dependencies-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Compiler } from 'webpack'; +import type { IPackageJson } from '@rushstack/node-core-library'; +import type { WebpackPluginInstance } from 'webpack'; + +// @beta +class EmbeddedDependenciesWebpackPlugin implements WebpackPluginInstance { + constructor(options?: IEmbeddedDependenciesWebpackPluginOptions); + apply(compiler: Compiler): void; +} +export default EmbeddedDependenciesWebpackPlugin; + +// @beta +export interface IEmbeddedDependenciesWebpackPluginOptions { + generatedLicenseFilename?: LicenseFileName; + generateLicenseFile?: boolean; + generateLicenseFileFunction?: LicenseFileGeneratorFunction; + outputFileName?: string; + packageFilterPredicate?: (packageJson: IPackageData, filePath: string) => boolean; +} + +// @beta +export interface IPackageData extends IPackageJson { + author?: string | { + name?: string; + }; + copyright: string | undefined; + licenses?: { + type: string; + url: string; + }[]; + licenseSource?: string; +} + +// @beta +export type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string; + +// @beta +export type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`; + +``` diff --git a/common/reviews/api/webpack-plugin-utilities.api.md b/common/reviews/api/webpack-plugin-utilities.api.md new file mode 100644 index 00000000000..3b2bf0ac56f --- /dev/null +++ b/common/reviews/api/webpack-plugin-utilities.api.md @@ -0,0 +1,41 @@ +## API Report File for "@rushstack/webpack-plugin-utilities" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Configuration } from 'webpack'; +import { IFs } from 'memfs'; +import type { MultiStats } from 'webpack'; +import type { Stats } from 'webpack'; +import type * as Webpack from 'webpack'; + +// @public +function getTestingWebpackCompilerAsync(entry: string, additionalConfig?: Configuration, memFs?: IFs): Promise<(Stats | MultiStats) | undefined>; + +// @public +function isWebpack3OrEarlier(compiler: Webpack.Compiler): boolean; + +// @public +function isWebpack4(compiler: Webpack.Compiler): boolean; + +// @public +function isWebpack5(compiler: Webpack.Compiler): boolean; + +declare namespace Testing { + export { + getTestingWebpackCompilerAsync + } +} +export { Testing } + +declare namespace VersionDetection { + export { + isWebpack3OrEarlier, + isWebpack4, + isWebpack5 + } +} +export { VersionDetection } + +``` diff --git a/common/reviews/api/webpack-preserve-dynamic-require-plugin.api.md b/common/reviews/api/webpack-preserve-dynamic-require-plugin.api.md new file mode 100644 index 00000000000..02c64fe5655 --- /dev/null +++ b/common/reviews/api/webpack-preserve-dynamic-require-plugin.api.md @@ -0,0 +1,17 @@ +## API Report File for "@rushstack/webpack-preserve-dynamic-require-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type * as webpack from 'webpack'; + +// @public (undocumented) +export class PreserveDynamicRequireWebpackPlugin { + // (undocumented) + apply(compiler: webpack.Compiler): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/webpack-workspace-resolve-plugin.api.md b/common/reviews/api/webpack-workspace-resolve-plugin.api.md new file mode 100644 index 00000000000..ef0216174c9 --- /dev/null +++ b/common/reviews/api/webpack-workspace-resolve-plugin.api.md @@ -0,0 +1,69 @@ +## API Report File for "@rushstack/webpack-workspace-resolve-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Compiler } from 'webpack'; +import { IPrefixMatch } from '@rushstack/lookup-by-path'; +import { LookupByPath } from '@rushstack/lookup-by-path'; +import type { WebpackPluginInstance } from 'webpack'; + +// @beta +export type IPathNormalizationFunction = ((input: string) => string) | undefined; + +// @beta +export interface IResolveContext { + descriptionFileRoot: string; + findDependency(request: string): IPrefixMatch | undefined; +} + +// @beta +export interface IResolverCacheFile { + basePath: string; + contexts: ISerializedResolveContext[]; +} + +// @beta +export interface ISerializedResolveContext { + deps?: Record; + dirInfoFiles?: string[]; + name: string; + root: string; +} + +// @beta +export interface IWorkspaceLayoutCacheOptions { + cacheData: IResolverCacheFile; + resolverPathSeparator?: '/' | '\\'; +} + +// @beta +export interface IWorkspaceResolvePluginOptions { + cache: WorkspaceLayoutCache; + resolverNames?: Iterable; +} + +// @beta +export class WorkspaceLayoutCache { + constructor(options: IWorkspaceLayoutCacheOptions); + readonly contextForPackage: WeakMap>; + readonly contextLookup: LookupByPath; + // (undocumented) + readonly normalizeToPlatform: IPathNormalizationFunction; + // (undocumented) + readonly normalizeToSlash: IPathNormalizationFunction; + // (undocumented) + readonly resolverPathSeparator: string; +} + +// @beta +export class WorkspaceResolvePlugin implements WebpackPluginInstance { + constructor(options: IWorkspaceResolvePluginOptions); + // (undocumented) + apply(compiler: Compiler): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/webpack4-localization-plugin.api.md b/common/reviews/api/webpack4-localization-plugin.api.md new file mode 100644 index 00000000000..9c8f51cc3ec --- /dev/null +++ b/common/reviews/api/webpack4-localization-plugin.api.md @@ -0,0 +1,160 @@ +## API Report File for "@rushstack/webpack4-localization-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { IgnoreStringFunction } from '@rushstack/localization-utilities'; +import { ILocalizationFile } from '@rushstack/localization-utilities'; +import type { IPseudolocaleOptions } from '@rushstack/localization-utilities'; +import type { ITerminal } from '@rushstack/terminal'; +import * as Webpack from 'webpack'; + +// @public (undocumented) +export interface IDefaultLocaleOptions { + fillMissingTranslationStrings?: boolean; + localeName: string; +} + +// @public (undocumented) +export interface ILocaleData { + // (undocumented) + [locFilePath: string]: string | ILocaleFileData; +} + +// @public (undocumented) +export interface ILocaleElementMap { + // (undocumented) + [locale: string]: string; +} + +// @public (undocumented) +export interface ILocaleFileData { + // (undocumented) + [stringName: string]: string; +} + +// @public +export interface ILocalizationPluginOptions { + // @deprecated (undocumented) + filesToIgnore?: string[]; + globsToIgnore?: string[]; + ignoreString?: IgnoreStringFunction; + localizationStats?: ILocalizationStatsOptions; + localizedData: ILocalizedData; + noStringsLocaleName?: string; + typingsOptions?: ITypingsGenerationOptions; +} + +// @public (undocumented) +export interface ILocalizationStats { + // (undocumented) + entrypoints: { + [name: string]: ILocalizationStatsEntrypoint; + }; + // (undocumented) + namedChunkGroups: { + [name: string]: ILocalizationStatsChunkGroup; + }; +} + +// @public (undocumented) +export interface ILocalizationStatsChunkGroup { + // (undocumented) + localizedAssets: ILocaleElementMap; +} + +// @public (undocumented) +export interface ILocalizationStatsEntrypoint { + // (undocumented) + localizedAssets: ILocaleElementMap; +} + +// @public +export interface ILocalizationStatsOptions { + callback?: (stats: ILocalizationStats) => void; + dropPath?: string; +} + +// @public (undocumented) +export interface ILocalizedData { + defaultLocale: IDefaultLocaleOptions; + ignoreMissingResxComments?: boolean; + normalizeResxNewlines?: 'lf' | 'crlf'; + passthroughLocale?: IPassthroughLocaleOptions; + pseudolocales?: IPseudolocalesOptions; + resolveMissingTranslatedStrings?: (locales: string[], filePath: string) => IResolvedMissingTranslations; + translatedStrings: ILocalizedStrings; +} + +// @public (undocumented) +export interface ILocalizedStrings { + // (undocumented) + [locale: string]: ILocaleData; +} + +// @public (undocumented) +export interface ILocalizedWebpackChunk extends Webpack.compilation.Chunk { + // (undocumented) + localizedFiles?: { + [locale: string]: string; + }; +} + +// @public +export interface IPassthroughLocaleOptions { + passthroughLocaleName?: string; + usePassthroughLocale?: boolean; +} + +// @public +export interface IPseudolocalesOptions { + // (undocumented) + [pseudoLocaleName: string]: IPseudolocaleOptions; +} + +// @public (undocumented) +export interface IResolvedMissingTranslations { + // (undocumented) + [localeName: string]: string | ILocaleFileData; +} + +// @internal (undocumented) +export interface _IStringPlaceholder { + // (undocumented) + suffix: string; + // (undocumented) + value: string; +} + +// @public +export interface ITypingsGenerationOptions { + exportAsDefault?: boolean; + generatedTsFolder: string; + // @deprecated (undocumented) + ignoreString?: (resxFilePath: string, stringName: string) => boolean; + processComment?: (comment: string | undefined, resxFilePath: string, stringName: string) => string | undefined; + secondaryGeneratedTsFolders?: string[]; + sourceRoot?: string; +} + +// @public +export class LocalizationPlugin implements Webpack.Plugin { + constructor(options: ILocalizationPluginOptions); + // Warning: (ae-forgotten-export) The symbol "IAddDefaultLocFileResult" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + addDefaultLocFile(terminal: ITerminal, localizedResourcePath: string, localizedResourceData: ILocalizationFile): IAddDefaultLocFileResult; + // (undocumented) + apply(compiler: Webpack.Compiler): void; + // Warning: (ae-forgotten-export) The symbol "IStringSerialNumberData" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined; + // @internal (undocumented) + stringKeys: Map; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/webpack4-module-minifier-plugin.api.md b/common/reviews/api/webpack4-module-minifier-plugin.api.md new file mode 100644 index 00000000000..a664bae677f --- /dev/null +++ b/common/reviews/api/webpack4-module-minifier-plugin.api.md @@ -0,0 +1,213 @@ +## API Report File for "@rushstack/webpack4-module-minifier-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { AsyncSeriesWaterfallHook } from 'tapable'; +import type { Compiler } from 'webpack'; +import { getIdentifier } from '@rushstack/module-minifier'; +import { ILocalMinifierOptions } from '@rushstack/module-minifier'; +import { IMinifierConnection } from '@rushstack/module-minifier'; +import { IModuleMinificationCallback } from '@rushstack/module-minifier'; +import { IModuleMinificationErrorResult } from '@rushstack/module-minifier'; +import { IModuleMinificationRequest } from '@rushstack/module-minifier'; +import { IModuleMinificationResult } from '@rushstack/module-minifier'; +import { IModuleMinificationSuccessResult } from '@rushstack/module-minifier'; +import { IModuleMinifier } from '@rushstack/module-minifier'; +import { IModuleMinifierFunction } from '@rushstack/module-minifier'; +import { IWorkerPoolMinifierOptions } from '@rushstack/module-minifier'; +import { LocalMinifier } from '@rushstack/module-minifier'; +import { MessagePortMinifier } from '@rushstack/module-minifier'; +import { NoopMinifier } from '@rushstack/module-minifier'; +import type { Plugin } from 'webpack'; +import type { ReplaceSource } from 'webpack-sources'; +import { Source } from 'webpack-sources'; +import type { SyncWaterfallHook } from 'tapable'; +import * as webpack from 'webpack'; +import { WorkerPoolMinifier } from '@rushstack/module-minifier'; + +// @public +export const CHUNK_MODULES_TOKEN: '__WEBPACK_CHUNK_MODULES__'; + +// @public +export function generateLicenseFileForAsset(compilation: webpack.compilation.Compilation, asset: IAssetInfo, minifiedModules: IModuleMap): string; + +export { getIdentifier } + +// @internal +export interface _IAcornComment { + // (undocumented) + end: number; + // (undocumented) + start: number; + // (undocumented) + type: 'Line' | 'Block'; + // (undocumented) + value: string; +} + +// @public +export interface IAssetInfo { + chunk: webpack.compilation.Chunk; + externalNames: Map; + fileName: string; + modules: (string | number)[]; + renderInfo: Map; + source: Source; +} + +// @public +export type IAssetMap = Map; + +// @public +export interface IAssetStats { + // (undocumented) + positionByModuleId: Map; +} + +// @public +export interface IDehydratedAssets { + assets: IAssetMap; + modules: IModuleMap; +} + +// @public +export interface IExtendedModule extends webpack.compilation.Module { + external?: boolean; + hasDependencies(callback: (dep: webpack.compilation.Dependency) => boolean | void): boolean; + id: string | number | null; + identifier(): string; + modules?: IExtendedModule[]; + readableIdentifier(requestShortener: unknown): string; + resource?: string; +} + +export { ILocalMinifierOptions } + +export { IMinifierConnection } + +// @public +export interface IModuleInfo { + module: IExtendedModule; + source: Source; +} + +// @public +export type IModuleMap = Map; + +export { IModuleMinificationCallback } + +export { IModuleMinificationErrorResult } + +export { IModuleMinificationRequest } + +export { IModuleMinificationResult } + +export { IModuleMinificationSuccessResult } + +export { IModuleMinifier } + +export { IModuleMinifierFunction } + +// @public +export interface IModuleMinifierPluginHooks { + finalModuleId: SyncWaterfallHook; + postProcessCodeFragment: SyncWaterfallHook; + rehydrateAssets: AsyncSeriesWaterfallHook; +} + +// @public +export interface IModuleMinifierPluginOptions { + compressAsyncImports?: boolean; + minifier: IModuleMinifier; + sourceMap?: boolean; + usePortableModules?: boolean; +} + +// @public +export interface IModuleMinifierPluginStats { + // (undocumented) + metadataByAssetFileName: Map; +} + +// @internal +export interface _INormalModuleFactoryModuleData { + // (undocumented) + resourceResolveData?: { + descriptionFileData?: { + name: string; + }; + descriptionFilePath?: string; + descriptionFileRoot?: string; + relativePath?: string; + }; +} + +// @public +export interface IPostProcessFragmentContext { + compilation: webpack.compilation.Compilation; + loggingName: string; + module: webpack.compilation.Module | undefined; +} + +// @public +export interface IRenderedModulePosition { + charLength: number; + charOffset: number; +} + +// @internal +export interface _IWebpackCompilationData { + // (undocumented) + normalModuleFactory: webpack.compilation.NormalModuleFactory; +} + +export { IWorkerPoolMinifierOptions } + +export { LocalMinifier } + +export { MessagePortMinifier } + +// @public +export const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__('; + +// @public +export const MODULE_WRAPPER_SUFFIX: ');'; + +// @public +export class ModuleMinifierPlugin implements webpack.Plugin { + constructor(options: IModuleMinifierPluginOptions); + // (undocumented) + apply(compiler: webpack.Compiler): void; + // (undocumented) + static getCompilationStatistics(compilation: webpack.compilation.Compilation): IModuleMinifierPluginStats | undefined; + // (undocumented) + readonly hooks: IModuleMinifierPluginHooks; + // (undocumented) + minifier: IModuleMinifier; +} + +export { NoopMinifier } + +// @public +export class PortableMinifierModuleIdsPlugin implements Plugin { + constructor(minifierHooks: IModuleMinifierPluginHooks); + // (undocumented) + apply(compiler: Compiler): void; +} + +// @public +export function rehydrateAsset(asset: IAssetInfo, moduleMap: IModuleMap, banner: string, emitRenderInfo?: boolean): Source; + +// @public +export const STAGE_AFTER: 100; + +// @public +export const STAGE_BEFORE: -100; + +export { WorkerPoolMinifier } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/webpack5-load-themed-styles-loader.api.md b/common/reviews/api/webpack5-load-themed-styles-loader.api.md new file mode 100644 index 00000000000..84f5dbb129c --- /dev/null +++ b/common/reviews/api/webpack5-load-themed-styles-loader.api.md @@ -0,0 +1,21 @@ +## API Report File for "@microsoft/webpack5-load-themed-styles-loader" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { PitchLoaderDefinitionFunction } from 'webpack'; + +// @public +export interface ILoadThemedStylesLoaderOptions { + async?: boolean; + // (undocumented) + esModule?: boolean; + // (undocumented) + loadThemedStylesPath?: string; +} + +// @public +export const pitch: PitchLoaderDefinitionFunction; + +``` diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md new file mode 100644 index 00000000000..b985e49c966 --- /dev/null +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -0,0 +1,179 @@ +## API Report File for "@rushstack/webpack5-localization-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import type { Chunk } from 'webpack'; +import type { Compilation } from 'webpack'; +import type { Compiler } from 'webpack'; +import { ILocalizationFile } from '@rushstack/localization-utilities'; +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; + localeName: string; +} + +// @public (undocumented) +export interface ILocaleData { + // (undocumented) + [locFilePath: string]: ILocaleFileData; +} + +// @public (undocumented) +export interface ILocaleElementMap { + // (undocumented) + [locale: string]: string; +} + +// @public +export type ILocaleFileData = string | ILocaleFileObject | ReadonlyMap; + +// @public (undocumented) +export interface ILocaleFileObject { + // (undocumented) + [stringName: string]: string; +} + +// @public +export interface ILocalizationPluginOptions { + formatLocaleForFilename?: (locale: string) => string; + globsToIgnore?: string[]; + localizationStats?: ILocalizationStatsOptions; + localizedData: ILocalizedData; + noStringsLocaleName?: string; + realContentHash?: boolean; + runtimeLocaleExpression?: string; +} + +// @public (undocumented) +export interface ILocalizationStats { + // (undocumented) + entrypoints: { + [name: string]: ILocalizationStatsEntrypoint; + }; + // (undocumented) + namedChunkGroups: { + [name: string]: ILocalizationStatsChunkGroup; + }; +} + +// @public (undocumented) +export interface ILocalizationStatsChunkGroup { + // (undocumented) + localizedAssets: ILocaleElementMap; +} + +// @public (undocumented) +export interface ILocalizationStatsEntrypoint { + // (undocumented) + localizedAssets: ILocaleElementMap; +} + +// @public +export interface ILocalizationStatsOptions { + callback?: (stats: ILocalizationStats, compilation: Compilation) => void; + dropPath?: string; +} + +// @public (undocumented) +export interface ILocalizedData { + defaultLocale: IDefaultLocaleOptions; + passthroughLocale?: IPassthroughLocaleOptions; + pseudolocales?: IPseudolocalesOptions; + resolveMissingTranslatedStrings?: (locales: string[], localizedFileKey: string, loaderContext: LoaderContext<{}>) => Promise | IResolvedMissingTranslations; + translatedStrings: ILocalizedStrings; +} + +// @public (undocumented) +export interface ILocalizedStrings { + // (undocumented) + [locale: string]: ILocaleData; +} + +// @public (undocumented) +export interface ILocalizedWebpackChunk extends Chunk { + // (undocumented) + localizedFiles?: { + [locale: string]: string; + }; +} + +// @public +export interface IPassthroughLocaleOptions { + passthroughLocaleName?: string; + usePassthroughLocale?: boolean; +} + +// @public +export interface IPseudolocalesOptions { + // (undocumented) + [pseudoLocaleName: string]: IPseudolocaleOptions; +} + +// @public (undocumented) +export type IResolvedMissingTranslations = ReadonlyMap; + +// @public (undocumented) +interface IStringPlaceholder extends IValuePlaceholderBase { + locFilePath: string; + stringName: string; + translations: ReadonlyMap>; +} +export { IStringPlaceholder } +export { IStringPlaceholder as _IStringPlaceholder } + +// @public (undocumented) +export interface ITrueHashPluginOptions { + hashFunction?: (contents: string | Buffer) => string; + stageOverride?: number; +} + +// @public (undocumented) +export interface IValuePlaceholderBase { + suffix: string; + value: string; +} + +// @public +export class LocalizationPlugin implements WebpackPluginInstance { + constructor(options: ILocalizationPluginOptions); + // (undocumented) + addDefaultLocFileAsync(context: LoaderContext<{}>, localizedFileKey: string, localizedResourceData: ILocalizationFile): Promise>; + apply(compiler: Compiler): void; + // @internal (undocumented) + _getCustomDataForSerialNumber(suffix: string): _ICustomDataPlaceholder | undefined; + // @beta (undocumented) + getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn, placeholderUniqueId: string): string; + // (undocumented) + getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined; + // @internal (undocumented) + _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined; + // @internal (undocumented) + readonly _options: ILocalizationPluginOptions; +} + +// @public (undocumented) +export class TrueHashPlugin implements WebpackPluginInstance { + constructor(options?: ITrueHashPluginOptions); + // (undocumented) + 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 new file mode 100644 index 00000000000..825f134b3b6 --- /dev/null +++ b/common/reviews/api/webpack5-module-minifier-plugin.api.md @@ -0,0 +1,137 @@ +## API Report File for "@rushstack/webpack5-module-minifier-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { AsyncSeriesWaterfallHook } from 'tapable'; +import type { Chunk } from 'webpack'; +import type { Comment } from 'estree'; +import type { Compilation } from 'webpack'; +import type { Compiler } from 'webpack'; +import type { IModuleMinifier } from '@rushstack/module-minifier'; +import type { Module } from 'webpack'; +import type { sources } from 'webpack'; +import type { SyncWaterfallHook } from 'tapable'; +import type { WebpackPluginInstance } from 'webpack'; + +// @public +export const CHUNK_MODULE_REGEX: RegExp; + +// @public +export const CHUNK_MODULE_TOKEN: '__WEBPACK_CHUNK_MODULE__'; + +// @public +export function generateLicenseFileForAsset(compilation: Compilation, asset: IAssetInfo): string; + +// @public +export interface IAssetInfo { + chunk: Chunk; + fileName: string; + renderInfo: Map; + source: sources.Source; + type: string; +} + +// @public +export type IAssetMap = Map; + +// @public +export interface IAssetStats { + // (undocumented) + positionByModuleId: Map; +} + +// @public +export interface IDehydratedAssets { + assets: IAssetMap; + modules: IModuleMap; +} + +// @public +export interface IFactoryMeta { + // (undocumented) + comments?: Comment[]; + // (undocumented) + skipMinification?: boolean; +} + +// @public +export interface IModuleInfo { + id: string | number; + module: Module; + source: sources.Source; +} + +// @public +export type IModuleMap = Map; + +// @public +export interface IModuleMinifierPluginHooks { + postProcessCodeFragment: SyncWaterfallHook<[sources.ReplaceSource, IPostProcessFragmentContext]>; + rehydrateAssets: AsyncSeriesWaterfallHook<[IDehydratedAssets, Compilation]>; +} + +// @public +export interface IModuleMinifierPluginOptions { + minifier: IModuleMinifier; + sourceMap?: boolean; +} + +// @public +export interface IModuleMinifierPluginStats { + // (undocumented) + metadataByAssetFileName: Map; + // (undocumented) + metadataByModule: WeakMap; +} + +// @public +export interface IModuleStats { + // (undocumented) + hashByChunk: Map; + // (undocumented) + sizeByHash: Map; +} + +// @public +export interface IPostProcessFragmentContext { + compilation: Compilation; + loggingName: string; + module: Module | undefined; +} + +// @public +export interface IRenderedModulePosition { + charLength: number; + charOffset: number; +} + +// @public +export const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__('; + +// @public +export const MODULE_WRAPPER_SUFFIX: ');'; + +// @public +export class ModuleMinifierPlugin implements WebpackPluginInstance { + constructor(options: IModuleMinifierPluginOptions); + // (undocumented) + apply(compiler: Compiler): void; + // (undocumented) + static getCompilationStatistics(compilation: Compilation): IModuleMinifierPluginStats | undefined; + // (undocumented) + readonly hooks: IModuleMinifierPluginHooks; + // (undocumented) + minifier: IModuleMinifier; +} + +// @public +export const STAGE_AFTER: 100; + +// @public +export const STAGE_BEFORE: -10000; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/worker-pool.api.md b/common/reviews/api/worker-pool.api.md new file mode 100644 index 00000000000..5761d9d92ce --- /dev/null +++ b/common/reviews/api/worker-pool.api.md @@ -0,0 +1,48 @@ +## API Report File for "@rushstack/worker-pool" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +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 +// +// @internal (undocumented) +export interface IWorkerPoolOptions { + id: string; + maxWorkers: number; + onWorkerDestroyed?: () => void; + prepareWorker?: (worker: Worker) => void; + workerData?: unknown; + workerResourceLimits?: ResourceLimits; + workerScriptPath: string; +} + +// Warning: (ae-internal-missing-underscore) The name "WORKER_ID_SYMBOL" should be prefixed with an underscore because the declaration is marked as @internal +// +// @internal +export const WORKER_ID_SYMBOL: unique symbol; + +// Warning: (ae-internal-missing-underscore) The name "WorkerPool" should be prefixed with an underscore because the declaration is marked as @internal +// +// @internal +export class WorkerPool { + constructor(options: IWorkerPoolOptions); + checkinWorker(worker: Worker): void; + checkoutWorkerAsync(allowCreate: boolean): Promise; + finishAsync(): Promise; + getActiveCount(): number; + getIdleCount(): number; + getLiveCount(): number; + // (undocumented) + id: string; + // (undocumented) + maxWorkers: number; + reset(): void; +} + +``` diff --git a/common/scripts/install-run-rush-pnpm.js b/common/scripts/install-run-rush-pnpm.js new file mode 100644 index 00000000000..2356649f4e7 --- /dev/null +++ b/common/scripts/install-run-rush-pnpm.js @@ -0,0 +1,31 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rush-pnpm command. +// +// An example usage would be: +// +// node common/scripts/install-run-rush-pnpm.js pnpm-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// 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__ = {}; +/*!*****************************************************!*\ + !*** ./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'); +//# 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/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js index 7fc381d5640..dc8980d1a27 100644 --- a/common/scripts/install-run-rush.js +++ b/common/scripts/install-run-rush.js @@ -1,7 +1,3 @@ -"use strict"; -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. -Object.defineProperty(exports, "__esModule", { value: true }); // THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. // // This script is intended for usage in an automated build environment where the Rush command may not have @@ -12,44 +8,189 @@ Object.defineProperty(exports, "__esModule", { value: true }); // node common/scripts/install-run-rush.js install // // For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ -const path = require("path"); -const fs = require("fs"); -const install_run_1 = require("./install-run"); +// +// 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__ = ({ + +/***/ 176760: +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +/***/ ((module) => { + +module.exports = require("node:path"); + +/***/ }), + +/***/ 973024: +/*!**************************!*\ + !*** external "node:fs" ***! + \**************************/ +/***/ ((module) => { + +module.exports = require("node:fs"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // 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 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 ***! + \************************************************/ +__webpack_require__.r(__webpack_exports__); +/* 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 */ + + +const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run'); const PACKAGE_NAME = '@microsoft/rush'; const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; -function _getRushVersion() { +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) { - console.log(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); + logger.info(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); return rushPreviewVersion; } - const rushJsonFolder = install_run_1.findRushJsonFolder(); - const rushJsonPath = path.join(rushJsonFolder, install_run_1.RUSH_JSON_FILENAME); + const rushJsonFolder = findRushJsonFolder(); + const rushJsonPath = node_path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); try { - const rushJsonContents = fs.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.+\-]+)\"/); return rushJsonMatches[1]; } catch (e) { - throw new Error(`Unable to determine the required version of Rush from rush.json (${rushJsonFolder}). ` + - 'The \'rushVersion\' field is either not assigned in rush.json or was specified ' + + 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.'); } } +function _getBin(scriptName) { + switch (scriptName.toLowerCase()) { + case 'install-run-rush-pnpm.js': + return 'rush-pnpm'; + case 'install-run-rushx.js': + return 'rushx'; + default: + return 'rush'; + } +} function _run() { - const [nodePath, /* Ex: /bin/node */ scriptPath, /* /repo/common/scripts/install-run-rush.js */ ...packageBinArgs /* [build, --to, myproject] */] = process.argv; + 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.basename(scriptPath); - const bin = scriptName.toLowerCase() === 'install-run-rushx.js' ? 'rushx' : 'rush'; + 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'); } - if (process.argv.length < 3) { + 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 + }; + } + 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) { console.log(`Usage: ${scriptName} [args...]`); - if (scriptName === 'install-run-rush.js') { + 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 { @@ -57,11 +198,21 @@ function _run() { } process.exit(1); } - install_run_1.runWithErrorAndStatusCode(() => { - const version = _getRushVersion(); - console.log(`The rush.json configuration requests Rush version ${version}`); - return install_run_1.installAndRun(PACKAGE_NAME, version, bin, packageBinArgs); + 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.`); + } + return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); }); } _run(); +//# sourceMappingURL=install-run-rush.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; //# sourceMappingURL=install-run-rush.js.map \ No newline at end of file diff --git a/common/scripts/install-run-rushx.js b/common/scripts/install-run-rushx.js index bf26eb5e50a..6581521f3c7 100644 --- a/common/scripts/install-run-rushx.js +++ b/common/scripts/install-run-rushx.js @@ -1,7 +1,3 @@ -"use strict"; -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. -Object.defineProperty(exports, "__esModule", { value: true }); // THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. // // This script is intended for usage in an automated build environment where the Rush command may not have @@ -14,5 +10,22 @@ Object.defineProperty(exports, "__esModule", { value: true }); // node common/scripts/install-run-rushx.js custom-command // // For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ -require("./install-run-rush"); +// +// 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__ = {}; +/*!*************************************************!*\ + !*** ./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'); +//# 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/common/scripts/install-run.js b/common/scripts/install-run.js index e12534c87cf..c5949f5a411 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -1,7 +1,3 @@ -"use strict"; -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. -Object.defineProperty(exports, "__esModule", { value: true }); // THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. // // This script is intended for usage in an automated build environment where a Node tool may not have @@ -12,71 +8,147 @@ Object.defineProperty(exports, "__esModule", { value: true }); // node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io // // For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ -const childProcess = require("child_process"); -const fs = require("fs"); -const os = require("os"); -const path = require("path"); -exports.RUSH_JSON_FILENAME = 'rush.json'; -const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER'; -const INSTALLED_FLAG_FILENAME = 'installed.flag'; -const NODE_MODULES_FOLDER_NAME = 'node_modules'; -const PACKAGE_JSON_FILENAME = 'package.json'; +// +// 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__ = ({ + +/***/ 176760: +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +/***/ ((module) => { + +module.exports = require("node:path"); + +/***/ }), + +/***/ 731421: +/*!*************************************!*\ + !*** external "node:child_process" ***! + \*************************************/ +/***/ ((module) => { + +module.exports = require("node:child_process"); + +/***/ }), + +/***/ 832286: +/*!************************************************!*\ + !*** ./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 */ trimNpmrcFileLines: () => (/* binding */ trimNpmrcFileLines) +/* harmony export */ }); +/* 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 + + /** - * Parse a package specifier (in the form of name\@version) into name and version parts. + * 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. */ -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; +// create a global _combinedNpmrc for cache purpose +const _combinedNpmrcMap = new Map(); +function _trimNpmrcFile(options) { + const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax } = options; + const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); + if (combinedNpmrcFromCache !== undefined) { + return combinedNpmrcFromCache; } - else if (separatorIndex === -1) { - // The specifier doesn't have a version - name = rawPackageSpecifier; + let npmrcFileLines = []; + if (linesToPrepend) { + npmrcFileLines.push(...linesToPrepend); } - else { - name = rawPackageSpecifier.substring(0, separatorIndex); - version = rawPackageSpecifier.substring(separatorIndex + 1); + if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + npmrcFileLines.push(...node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n')); } - if (!name) { - throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); + if (linesToAppend) { + npmrcFileLines.push(...linesToAppend); } - return { name, version }; + npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + const resultLines = trimNpmrcFileLines(npmrcFileLines, process.env, supportEnvVarFallbackSyntax); + const combinedNpmrc = resultLines.join('\n'); + //save the cache + _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); + return combinedNpmrc; } /** - * As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims - * unusable lines from the .npmrc file. * - * Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in - * the .npmrc file to provide different authentication tokens for different registry. - * However, if the environment variable is undefined, it expands to an empty string, which - * produces a valid-looking mapping with an invalid URL that causes an error. Instead, - * we'd prefer to skip that line and continue looking in other places such as the user's - * home directory. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._copyNpmrcFile() + * @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 */ -function _copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath) { - console.log(`Copying ${sourceNpmrcPath} --> ${targetNpmrcPath}`); // Verbose - let npmrcFileLines = fs.readFileSync(sourceNpmrcPath).toString().split('\n'); - npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); +function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax) { + var _a; 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 (const line of npmrcFileLines) { - // This finds environment variable tokens that look like "${VAR_NAME}" - const regex = /\$\{([^\}]+)\}/g; - const environmentVariables = line.match(regex); + for (let line of npmrcFileLines) { let lineShouldBeTrimmed = false; - if (environmentVariables) { - for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName = token.substring(2, token.length - 1); - if (!process.env[environmentVariableName]) { - lineShouldBeTrimmed = true; - break; + //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 + * + * ${nameString} -> nameString + * ${nameString-fallbackString} -> name-fallbackString + * ${nameString:-fallbackString} -> name:-fallbackString + */ + const nameWithFallback = token.substring(2, token.length - 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(/^([^:-]+)(?:\:?-(.+))?$/); + // matched: [originStr, variableName, fallback] + environmentVariableName = (_a = matched === null || matched === void 0 ? void 0 : matched[1]) !== null && _a !== void 0 ? _a : nameWithFallback; + fallback = matched === null || matched === void 0 ? void 0 : matched[2]; + } + else { + environmentVariableName = nameWithFallback; + } + // Is the environment variable and fallback value defined. + if (!env[environmentVariableName] && !fallback) { + // No, so trim this line + lineShouldBeTrimmed = true; + break; + } } } } @@ -89,31 +161,212 @@ function _copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath) { resultLines.push(line); } } - fs.writeFileSync(targetNpmrcPath, resultLines.join(os.EOL)); + return resultLines; } -/** - * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. - * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. - * - * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc() - */ -function _syncNpmrc(sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish) { - const sourceNpmrcPath = path.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); - const targetNpmrcPath = path.join(targetNpmrcFolder, '.npmrc'); +function _copyAndTrimNpmrcFile(options) { + const { logger, sourceNpmrcPath, targetNpmrcPath } = options; + logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose + logger.info(` --> "${targetNpmrcPath}"`); + const combinedNpmrc = _trimNpmrcFile(options); + node_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 } = 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.existsSync(sourceNpmrcPath)) { - _copyAndTrimNpmrcFile(sourceNpmrcPath, targetNpmrcPath); + if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { + // Ensure the target folder exists + if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + return _copyAndTrimNpmrcFile({ + sourceNpmrcPath, + targetNpmrcPath, + logger, + ...options + }); } - else if (fs.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 - console.log(`Deleting ${targetNpmrcPath}`); // Verbose - fs.unlinkSync(targetNpmrcPath); + logger.info(`Deleting ${targetNpmrcPath}`); // Verbose + node_fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); } } catch (e) { throw new Error(`Error syncing .npmrc file: ${e}`); } } +function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarFallbackSyntax) { + const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; + //if .npmrc file does not exist, return false directly + if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + return false; + } + const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath, supportEnvVarFallbackSyntax }); + const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); + return trimmedNpmrcFile.match(variableKeyRegExp) !== null; +} +//# sourceMappingURL=npmrcUtilities.js.map + +/***/ }), + +/***/ 848161: +/*!**************************!*\ + !*** external "node:os" ***! + \**************************/ +/***/ ((module) => { + +module.exports = require("node:os"); + +/***/ }), + +/***/ 973024: +/*!**************************!*\ + !*** external "node:fs" ***! + \**************************/ +/***/ ((module) => { + +module.exports = require("node:fs"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // 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 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 ***! + \*******************************************/ +__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 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 */ 832286); +// 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) { + // The specifier starts with a scope and doesn't have a version specified + name = rawPackageSpecifier; + } + else if (separatorIndex === -1) { + // The specifier doesn't have a version + name = rawPackageSpecifier; + } + else { + name = rawPackageSpecifier.substring(0, separatorIndex); + version = rawPackageSpecifier.substring(separatorIndex + 1); + } + if (!name) { + throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); + } + return { name, version }; +} let _npmPath = undefined; /** * Get the absolute path to the npm executable @@ -121,35 +374,34 @@ let _npmPath = undefined; function getNpmPath() { if (!_npmPath) { try { - if (os.platform() === 'win32') { + if (_isWindows()) { // We're on Windows - const whereOutput = childProcess.execSync('where npm', { stdio: [] }).toString(); - const lines = whereOutput.split(os.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 = childProcess.execSync('which 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.existsSync(_npmPath)) { + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) { throw new Error('The NPM executable does not exist'); } } return _npmPath; } -exports.getNpmPath = getNpmPath; function _ensureFolder(folderPath) { - if (!fs.existsSync(folderPath)) { - const parentDir = path.dirname(folderPath); + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { + const parentDir = node_path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath); _ensureFolder(parentDir); - fs.mkdirSync(folderPath); + node_fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath); } } /** @@ -163,14 +415,14 @@ function _ensureAndJoinPath(baseFolder, ...pathSegments) { try { for (let pathSegment of pathSegments) { pathSegment = pathSegment.replace(/[\\\/]/g, '+'); - joinedPath = path.join(joinedPath, pathSegment); - if (!fs.existsSync(joinedPath)) { - fs.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.join(baseFolder, ...pathSegments)}): ${e}`); + throw new Error(`Error building local installation folder (${node_path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`); } return joinedPath; } @@ -184,10 +436,27 @@ function _getRushTempFolder(rushCommonFolder) { 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++) { + if (aParts[i] !== bParts[i]) { + return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0); + } + } + return 0; +} /** * Resolve a package specifier to a static version */ -function _resolvePackageVersion(rushCommonFolder, { name, version }) { +function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { if (!version) { version = '*'; // If no version is specified, use the latest version } @@ -200,33 +469,57 @@ function _resolvePackageVersion(rushCommonFolder, { name, version }) { // version resolves to try { const rushTempFolder = _getRushTempFolder(rushCommonFolder); - const sourceNpmrcFolder = path.join(rushCommonFolder, 'config', 'rush'); - _syncNpmrc(sourceNpmrcFolder, rushTempFolder); + const sourceNpmrcFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: rushTempFolder, + logger, + supportEnvVarFallbackSyntax: false + }); const npmPath = getNpmPath(); // This returns something that looks like: - // @microsoft/rush@3.0.0 '3.0.0' - // @microsoft/rush@3.0.1 '3.0.1' - // ... - // @microsoft/rush@3.0.20 '3.0.20' - // - const npmVersionSpawnResult = childProcess.spawnSync(npmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier'], { + // ``` + // [ + // "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: [] - }); + stdio: [], + shell: _isWindows() + }; + const platformNpmPath = _getPlatformPath(npmPath); + const npmVersionSpawnResult = node_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 versionLines = npmViewVersionOutput.split('\n').filter((line) => !!line); - const latestVersion = versionLines[versionLines.length - 1]; + 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 versionMatches = latestVersion.match(/^.+\s\'(.+)\'$/); - if (!versionMatches) { - throw new Error(`Invalid npm output ${latestVersion}`); - } - return versionMatches[1]; + return latestVersion; } catch (e) { throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`); @@ -242,58 +535,72 @@ function findRushJsonFolder() { let basePath = __dirname; let tempPath = __dirname; do { - const testRushJsonPath = path.join(basePath, exports.RUSH_JSON_FILENAME); - if (fs.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.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.'); + throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); } } return _rushJsonFolder; } -exports.findRushJsonFolder = findRushJsonFolder; /** * Detects if the package in the specified directory is installed */ function _isPackageAlreadyInstalled(packageInstallFolder) { try { - const flagFilePath = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - if (!fs.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.readFileSync(flagFilePath).toString(); + const fileContents = node_fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); return fileContents.trim() === process.version; } catch (e) { return false; } } +/** + * Delete a file. Fail silently if it does not exist. + */ +function _deleteFile(file) { + try { + node_fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); + } + catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} /** * Removes the following files and directories under the specified folder path: * - installed.flag * - * - node_modules */ -function _cleanInstallFolder(rushTempFolder, packageInstallFolder) { +function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) { try { - const flagFile = path.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); - if (fs.existsSync(flagFile)) { - fs.unlinkSync(flagFile); + const flagFile = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); + _deleteFile(flagFile); + const packageLockFile = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json'); + if (lockFilePath) { + node_fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); } - const packageLockFile = path.resolve(packageInstallFolder, 'package-lock.json'); - if (fs.existsSync(packageLockFile)) { - fs.unlinkSync(packageLockFile); - } - const nodeModulesFolder = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); - if (fs.existsSync(nodeModulesFolder)) { - const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler', `install-run-${Date.now().toString()}`); - fs.renameSync(nodeModulesFolder, rushRecyclerFolder); + else { + // Not running `npm ci`, so need to cleanup + _deleteFile(packageLockFile); + 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'); + node_fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)); + } } } catch (e) { @@ -303,17 +610,17 @@ function _cleanInstallFolder(rushTempFolder, packageInstallFolder) { function _createPackageJson(packageInstallFolder, name, version) { try { const packageJsonContents = { - 'name': 'ci-rush', - 'version': '0.0.0', - 'dependencies': { + name: 'ci-rush', + version: '0.0.0', + dependencies: { [name]: version }, - 'description': 'DON\'T WARN', - 'repository': 'DON\'T WARN', - 'license': 'MIT' + description: "DON'T WARN", + repository: "DON'T WARN", + license: 'MIT' }; - const packageJsonPath = path.join(packageInstallFolder, PACKAGE_JSON_FILENAME); - fs.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}`); @@ -322,19 +629,21 @@ function _createPackageJson(packageInstallFolder, name, version) { /** * Run "npm install" in the package install folder. */ -function _installPackage(packageInstallFolder, name, version) { +function _installPackage(logger, packageInstallFolder, name, version, command) { try { - console.log(`Installing ${name}...`); + logger.info(`Installing ${name}...`); const npmPath = getNpmPath(); - const result = childProcess.spawnSync(npmPath, ['install'], { + const platformNpmPath = _getPlatformPath(npmPath); + const result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, [command], { stdio: 'inherit', cwd: packageInstallFolder, - env: process.env + env: process.env, + shell: _isWindows() }); if (result.status !== 0) { - throw new Error('"npm install" encountered an error'); + throw new Error(`"npm ${command}" encountered an error`); } - console.log(`Successfully installed ${name}@${version}`); + logger.info(`Successfully installed ${name}@${version}`); } catch (e) { throw new Error(`Unable to install package: ${e}`); @@ -344,45 +653,76 @@ function _installPackage(packageInstallFolder, name, version) { * Get the ".bin" path for the package. */ function _getBinPath(packageInstallFolder, binName) { - const binFolderPath = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - const resolvedBinName = (os.platform() === 'win32') ? `${binName}.cmd` : binName; - return path.resolve(binFolderPath, resolvedBinName); + const binFolderPath = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); + const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName; + return node_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 node_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.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - fs.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}`); } } -function installAndRun(packageName, packageVersion, packageBinName, packageBinArgs) { +function installAndRun(logger, packageName, packageVersion, packageBinName, packageBinArgs, lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]) { const rushJsonFolder = findRushJsonFolder(); - const rushCommonFolder = path.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); - const sourceNpmrcFolder = path.join(rushCommonFolder, 'config', 'rush'); - _syncNpmrc(sourceNpmrcFolder, packageInstallFolder); + _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath); + const sourceNpmrcFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: packageInstallFolder, + logger, + supportEnvVarFallbackSyntax: false + }); _createPackageJson(packageInstallFolder, packageName, packageVersion); - _installPackage(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('-'); - console.log(os.EOL + statusMessage + os.EOL + statusMessageLine + os.EOL); + logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); const binPath = _getBinPath(packageInstallFolder, packageBinName); - const result = childProcess.spawnSync(binPath, packageBinArgs, { - stdio: 'inherit', - cwd: process.cwd(), - env: process.env - }); + 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(node_path__WEBPACK_IMPORTED_MODULE_3__.delimiter); + result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformBinPath, packageBinArgs, { + stdio: 'inherit', + windowsVerbatimArguments: false, + shell: _isWindows(), + cwd: process.cwd(), + env: process.env + }); + } + finally { + process.env.PATH = originalEnvPath; + } if (result.status !== null) { return result.status; } @@ -390,24 +730,22 @@ function installAndRun(packageName, packageVersion, packageBinName, packageBinAr throw result.error || new Error('An unknown error occurred.'); } } -exports.installAndRun = installAndRun; -function runWithErrorAndStatusCode(fn) { +function runWithErrorAndStatusCode(logger, fn) { process.exitCode = 1; try { const exitCode = fn(); process.exitCode = exitCode; } catch (e) { - console.error(os.EOL + os.EOL + e.toString() + os.EOL + os.EOL); + logger.error('\n\n' + e.toString() + '\n\n'); } } -exports.runWithErrorAndStatusCode = runWithErrorAndStatusCode; 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; + 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.basename(scriptPath).toLowerCase() !== 'install-run.js') { + if (node_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; @@ -417,17 +755,24 @@ function _run() { console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io'); process.exit(1); } - runWithErrorAndStatusCode(() => { + 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(rushCommonFolder, packageSpecifier); + const version = _resolvePackageVersion(logger, rushCommonFolder, packageSpecifier); if (packageSpecifier.version !== version) { console.log(`Resolved to ${name}@${version}`); } - return installAndRun(name, version, packageBinName, packageBinArgs); + return installAndRun(logger, name, version, packageBinName, packageBinArgs); }); } _run(); +//# sourceMappingURL=install-run.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; //# sourceMappingURL=install-run.js.map \ No newline at end of file diff --git a/common/wiki-images/heft-300x120.png b/common/wiki-images/heft-300x120.png new file mode 100644 index 00000000000..9ff80b73f4b Binary files /dev/null and b/common/wiki-images/heft-300x120.png differ diff --git a/core-build/gulp-core-build-mocha/.eslintrc.js b/core-build/gulp-core-build-mocha/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/gulp-core-build-mocha/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/gulp-core-build-mocha/.npmignore b/core-build/gulp-core-build-mocha/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build-mocha/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build-mocha/CHANGELOG.json b/core-build/gulp-core-build-mocha/CHANGELOG.json deleted file mode 100644 index 0c696423e80..00000000000 --- a/core-build/gulp-core-build-mocha/CHANGELOG.json +++ /dev/null @@ -1,2615 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-mocha", - "entries": [ - { - "version": "3.8.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.6", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "3.8.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.5", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - } - ] - } - }, - { - "version": "3.8.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.4", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - } - ] - } - }, - { - "version": "3.8.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - } - ] - } - }, - { - "version": "3.8.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - } - ] - } - }, - { - "version": "3.8.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.1", - "date": "Tue, 21 Jan 2020 21:56:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "3.8.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.8.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "3.7.10", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.10", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.7.9", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.9", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - } - ] - } - }, - { - "version": "3.7.8", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.8", - "date": "Thu, 09 Jan 2020 06:44:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.7.7", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.7", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "3.7.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.6", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - } - ] - } - }, - { - "version": "3.7.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.5", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - } - ] - } - }, - { - "version": "3.7.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.4", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.7.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.3", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - } - ] - } - }, - { - "version": "3.7.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.2", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.7.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.1", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - } - ] - } - }, - { - "version": "3.7.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.7.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - } - ] - } - }, - { - "version": "3.6.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.6.4", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - } - ] - } - }, - { - "version": "3.6.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.6.3", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - } - ] - } - }, - { - "version": "3.6.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.6.2", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - } - ] - } - }, - { - "version": "3.6.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.6.1", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - } - ] - } - }, - { - "version": "3.6.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.6.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - } - ] - } - }, - { - "version": "3.5.76", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.76", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "3.5.75", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.75", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - } - ] - } - }, - { - "version": "3.5.74", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.74", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - } - ] - } - }, - { - "version": "3.5.73", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.73", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - } - ] - } - }, - { - "version": "3.5.72", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.72", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - } - ] - } - }, - { - "version": "3.5.71", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.71", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - } - ] - } - }, - { - "version": "3.5.70", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.70", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - } - ] - } - }, - { - "version": "3.5.69", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.69", - "date": "Thu, 21 Mar 2019 01:15:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - } - ] - } - }, - { - "version": "3.5.68", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.68", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - } - ] - } - }, - { - "version": "3.5.67", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.67", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - } - ] - } - }, - { - "version": "3.5.66", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.66", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - } - ] - } - }, - { - "version": "3.5.65", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.65", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - } - ] - } - }, - { - "version": "3.5.64", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.64", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - } - ] - } - }, - { - "version": "3.5.63", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.63", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - } - ] - } - }, - { - "version": "3.5.62", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.62", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - } - ] - } - }, - { - "version": "3.5.61", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.61", - "date": "Mon, 04 Mar 2019 17:13:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - } - ] - } - }, - { - "version": "3.5.60", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.60", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "3.5.59", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.59", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "3.5.58", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.58", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "3.5.57", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.57", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "3.5.56", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.56", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.5.55", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.55", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.5.54", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.54", - "date": "Wed, 30 Jan 2019 20:49:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - } - ] - } - }, - { - "version": "3.5.53", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.53", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - } - ] - } - }, - { - "version": "3.5.52", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.52", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - } - ] - } - }, - { - "version": "3.5.51", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.51", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "3.5.50", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.50", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - } - ] - } - }, - { - "version": "3.5.49", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.49", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "3.5.48", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.48", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "3.5.47", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.47", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "3.5.46", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.46", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - } - ] - } - }, - { - "version": "3.5.45", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.45", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "3.5.44", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.44", - "date": "Fri, 30 Nov 2018 23:34:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - } - ] - } - }, - { - "version": "3.5.43", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.43", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "3.5.42", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.42", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - } - ] - } - }, - { - "version": "3.5.41", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.41", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - } - ] - } - }, - { - "version": "3.5.40", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.40", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "3.5.39", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.39", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "3.5.38", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.38", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "3.5.37", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.37", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.5.36", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.36", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.5.35", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.35", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - } - ] - } - }, - { - "version": "3.5.34", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.34", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "3.5.33", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.33", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "3.5.32", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.32", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.5.31", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.31", - "date": "Wed, 31 Oct 2018 17:00:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.5.30", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.30", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - } - ] - } - }, - { - "version": "3.5.29", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.29", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - } - ] - } - }, - { - "version": "3.5.28", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.28", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - } - ] - } - }, - { - "version": "3.5.27", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.27", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "3.5.26", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.26", - "date": "Thu, 25 Oct 2018 08:56:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "3.5.25", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.25", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "3.5.24", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.24", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - } - ] - } - }, - { - "version": "3.5.23", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.23", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "3.5.22", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.22", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "3.5.21", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.21", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "3.5.20", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.20", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "3.5.19", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.19", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "3.5.18", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.18", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "3.5.17", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.17", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - } - ] - } - }, - { - "version": "3.5.16", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.16", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - } - ] - } - }, - { - "version": "3.5.15", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.15", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - } - ] - } - }, - { - "version": "3.5.14", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.14", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - } - ] - } - }, - { - "version": "3.5.13", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.13", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - } - ] - } - }, - { - "version": "3.5.12", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.12", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - } - ] - } - }, - { - "version": "3.5.11", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.11", - "date": "Tue, 18 Sep 2018 21:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - } - ] - } - }, - { - "version": "3.5.10", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.10", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "3.5.9", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.9", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "3.5.8", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.8", - "date": "Mon, 03 Sep 2018 16:04:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "3.5.7", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.7", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "3.5.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.6", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - } - ] - } - }, - { - "version": "3.5.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.5", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "3.5.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.4", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - } - ] - } - }, - { - "version": "3.5.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.3", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - } - ] - } - }, - { - "version": "3.5.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.2", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - } - ] - } - }, - { - "version": "3.5.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.1", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - } - ] - } - }, - { - "version": "3.5.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.5.0", - "date": "Thu, 09 Aug 2018 21:58:02 GMT", - "comments": { - "minor": [ - { - "comment": "Fix an issue where the mocha task was breaking the build for projects that don't have any unit tests yet" - } - ] - } - }, - { - "version": "3.4.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.4.3", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - } - ] - } - }, - { - "version": "3.4.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.4.2", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.4.1", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.4.0", - "date": "Fri, 20 Jul 2018 16:04:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrading mocha-related pack ages to remove dependency on a version of \"growl\" with NSP warnings." - } - ] - } - }, - { - "version": "3.3.31", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.31", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - } - ] - } - }, - { - "version": "3.3.30", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.30", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - } - ] - } - }, - { - "version": "3.3.29", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.29", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - } - ] - } - }, - { - "version": "3.3.28", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.28", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - } - ] - } - }, - { - "version": "3.3.27", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.27", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - } - ] - } - }, - { - "version": "3.3.26", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.26", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - } - ] - } - }, - { - "version": "3.3.25", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.25", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - } - ] - } - }, - { - "version": "3.3.24", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.24", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - } - ] - } - }, - { - "version": "3.3.23", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.23", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - } - ] - } - }, - { - "version": "3.3.22", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.22", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - } - ] - } - }, - { - "version": "3.3.21", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.21", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - } - ] - } - }, - { - "version": "3.3.20", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.20", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - } - ] - } - }, - { - "version": "3.3.19", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.19", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - } - ] - } - }, - { - "version": "3.3.18", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.18", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - } - ] - } - }, - { - "version": "3.3.17", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.17", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - } - ] - } - }, - { - "version": "3.3.16", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.16", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - } - ] - } - }, - { - "version": "3.3.15", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.15", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - } - ] - } - }, - { - "version": "3.3.14", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.14", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - } - ] - } - }, - { - "version": "3.3.13", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.13", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - } - ] - } - }, - { - "version": "3.3.12", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.12", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - } - ] - } - }, - { - "version": "3.3.11", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.11", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - } - ] - } - }, - { - "version": "3.3.10", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.10", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - } - ] - } - }, - { - "version": "3.3.9", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.9", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - } - ] - } - }, - { - "version": "3.3.8", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.8", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - } - ] - } - }, - { - "version": "3.3.7", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.7", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "patch": [ - { - "comment": "Increase Mocha test timeout to 15 seconds" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - } - ] - } - }, - { - "version": "3.3.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.6", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - } - ] - } - }, - { - "version": "3.3.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.5", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - } - ] - } - }, - { - "version": "3.3.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.4", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - } - ] - } - }, - { - "version": "3.3.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.3.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - } - ] - } - }, - { - "version": "3.2.17", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.17", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.6` to `3.3.7`" - } - ] - } - }, - { - "version": "3.2.16", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.16", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - } - ] - } - }, - { - "version": "3.2.15", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.15", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - } - ] - } - }, - { - "version": "3.2.14", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.14", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - } - ] - } - }, - { - "version": "3.2.13", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.13", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - } - ] - } - }, - { - "version": "3.2.12", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.12", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - } - ] - } - }, - { - "version": "3.2.11", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.11", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - } - ] - } - }, - { - "version": "3.2.10", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.10", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.9", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.8", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.7", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.6", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.5", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.4", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.3", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.2", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.1", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.2.0", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "minor": [ - { - "author": "QZ ", - "commit": "5fe47765dbb3567bebc30cf5d7ac2205f6e655b0", - "comment": "Turn off Mocha task when Jest task is enabled" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - } - ] - } - }, - { - "version": "3.1.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - } - ] - } - }, - { - "version": "3.1.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - } - ] - } - }, - { - "version": "3.1.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - } - ] - } - }, - { - "version": "3.1.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - } - ] - } - }, - { - "version": "3.1.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - } - ] - } - }, - { - "version": "3.1.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - } - ] - } - }, - { - "version": "3.0.8", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - } - ] - } - }, - { - "version": "3.0.7", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - } - ] - } - }, - { - "version": "3.0.6", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - } - ] - } - }, - { - "version": "3.0.5", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - } - ] - } - }, - { - "version": "3.0.4", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.4", - "date": "Thu, 07 Sep 2017 00:11:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build-mocha_v3.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - } - ] - } - }, - { - "version": "2.1.13", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.13", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - } - ] - } - }, - { - "version": "2.1.12", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.12", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - } - ] - } - }, - { - "version": "2.1.11", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.11", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - } - ] - } - }, - { - "version": "2.1.10", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.10", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - } - ] - } - }, - { - "version": "2.1.9", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.9", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - } - ] - } - }, - { - "version": "2.1.8", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.8", - "date": "Tue, 15 Aug 2017 19:04:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.2` to `2.9.3`" - } - ] - } - }, - { - "version": "2.1.7", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.7", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - } - ] - } - }, - { - "version": "2.1.6", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.6", - "date": "Sat, 12 Aug 2017 01:03:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.0` to `2.9.1`" - } - ] - } - }, - { - "version": "2.1.5", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.5", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.8.0` to `2.9.0`" - } - ] - } - }, - { - "version": "2.1.4", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.4", - "date": "Sat, 05 Aug 2017 01:04:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.3` to `2.8.0`" - } - ] - } - }, - { - "version": "2.1.3", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.3", - "date": "Mon, 31 Jul 2017 21:18:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.2` to `2.7.3`" - } - ] - } - }, - { - "version": "2.1.2", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.2", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - } - ] - } - }, - { - "version": "2.1.1", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.1", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/gulp-core-build-mocha_v2.1.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.3", - "tag": "@microsoft/gulp-core-build-mocha_v2.0.3", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.2", - "tag": "@microsoft/gulp-core-build-mocha_v2.0.2", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build-mocha_v2.0.1", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build-mocha/CHANGELOG.md b/core-build/gulp-core-build-mocha/CHANGELOG.md deleted file mode 100644 index 96842ba791d..00000000000 --- a/core-build/gulp-core-build-mocha/CHANGELOG.md +++ /dev/null @@ -1,989 +0,0 @@ -# Change Log - @microsoft/gulp-core-build-mocha - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 3.8.6 -Wed, 18 Mar 2020 15:07:47 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.8.5 -Tue, 17 Mar 2020 23:55:58 GMT - -*Version update only* - -## 3.8.4 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 3.8.3 -Fri, 24 Jan 2020 00:27:39 GMT - -*Version update only* - -## 3.8.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 3.8.1 -Tue, 21 Jan 2020 21:56:14 GMT - -*Version update only* - -## 3.8.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 3.7.10 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 3.7.9 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 3.7.8 -Thu, 09 Jan 2020 06:44:13 GMT - -*Version update only* - -## 3.7.7 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 3.7.6 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 3.7.5 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 3.7.4 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 3.7.3 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 3.7.2 -Tue, 22 Oct 2019 06:24:44 GMT - -*Version update only* - -## 3.7.1 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 3.7.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 3.6.4 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 3.6.3 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 3.6.2 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 3.6.1 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 3.6.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2 - -## 3.5.76 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 3.5.75 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 3.5.74 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 3.5.73 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 3.5.72 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 3.5.71 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 3.5.70 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 3.5.69 -Thu, 21 Mar 2019 01:15:33 GMT - -*Version update only* - -## 3.5.68 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 3.5.67 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 3.5.66 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 3.5.65 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 3.5.64 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 3.5.63 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 3.5.62 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 3.5.61 -Mon, 04 Mar 2019 17:13:20 GMT - -*Version update only* - -## 3.5.60 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 3.5.59 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 3.5.58 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 3.5.57 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 3.5.56 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 3.5.55 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 3.5.54 -Wed, 30 Jan 2019 20:49:12 GMT - -*Version update only* - -## 3.5.53 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 3.5.52 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 3.5.51 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 3.5.50 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 3.5.49 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 3.5.48 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 3.5.47 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 3.5.46 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 3.5.45 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 3.5.44 -Fri, 30 Nov 2018 23:34:58 GMT - -*Version update only* - -## 3.5.43 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 3.5.42 -Thu, 29 Nov 2018 00:35:38 GMT - -*Version update only* - -## 3.5.41 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 3.5.40 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 3.5.39 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 3.5.38 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 3.5.37 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 3.5.36 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 3.5.35 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 3.5.34 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 3.5.33 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 3.5.32 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 3.5.31 -Wed, 31 Oct 2018 17:00:54 GMT - -*Version update only* - -## 3.5.30 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 3.5.29 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 3.5.28 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 3.5.27 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 3.5.26 -Thu, 25 Oct 2018 08:56:03 GMT - -*Version update only* - -## 3.5.25 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 3.5.24 -Thu, 18 Oct 2018 05:30:14 GMT - -*Version update only* - -## 3.5.23 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 3.5.22 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 3.5.21 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 3.5.20 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 3.5.19 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 3.5.18 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 3.5.17 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 3.5.16 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 3.5.15 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 3.5.14 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 3.5.13 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 3.5.12 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 3.5.11 -Tue, 18 Sep 2018 21:04:56 GMT - -*Version update only* - -## 3.5.10 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 3.5.9 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 3.5.8 -Mon, 03 Sep 2018 16:04:45 GMT - -*Version update only* - -## 3.5.7 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 3.5.6 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 3.5.5 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 3.5.4 -Wed, 29 Aug 2018 06:36:50 GMT - -*Version update only* - -## 3.5.3 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 3.5.2 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 3.5.1 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 3.5.0 -Thu, 09 Aug 2018 21:58:02 GMT - -### Minor changes - -- Fix an issue where the mocha task was breaking the build for projects that don't have any unit tests yet - -## 3.4.3 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 3.4.2 -Tue, 07 Aug 2018 22:27:31 GMT - -*Version update only* - -## 3.4.1 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 3.4.0 -Fri, 20 Jul 2018 16:04:52 GMT - -### Minor changes - -- Upgrading mocha-related pack ages to remove dependency on a version of "growl" with NSP warnings. - -## 3.3.31 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 3.3.30 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 3.3.29 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 3.3.28 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 3.3.27 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 3.3.26 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 3.3.25 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 3.3.24 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 3.3.23 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 3.3.22 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 3.3.21 -Fri, 23 Mar 2018 00:34:53 GMT - -*Version update only* - -## 3.3.20 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 3.3.19 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 3.3.18 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 3.3.17 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 3.3.16 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 3.3.15 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 3.3.14 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 3.3.13 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 3.3.12 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 3.3.11 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.3.10 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.3.9 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 3.3.8 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 3.3.7 -Fri, 26 Jan 2018 00:36:51 GMT - -### Patches - -- Increase Mocha test timeout to 15 seconds - -## 3.3.6 -Tue, 23 Jan 2018 17:05:28 GMT - -*Version update only* - -## 3.3.5 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 3.3.4 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 3.3.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 3.3.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 3.3.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 3.3.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 3.2.17 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 3.2.16 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 3.2.15 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 3.2.14 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 3.2.13 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 3.2.12 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 3.2.11 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 3.2.10 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 3.2.9 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 3.2.8 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 3.2.7 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 3.2.6 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 3.2.5 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 3.2.4 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.2.3 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 3.2.2 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 3.2.1 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 3.2.0 -Tue, 24 Oct 2017 18:17:12 GMT - -### Minor changes - -- Turn off Mocha task when Jest task is enabled - -## 3.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 3.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 3.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 3.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 3.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 3.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 3.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 3.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 3.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 3.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -*Version update only* - -## 3.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 3.0.4 -Thu, 07 Sep 2017 00:11:12 GMT - -*Version update only* - -## 3.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 3.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 3.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 3.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 2.1.13 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 2.1.12 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 2.1.11 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 2.1.10 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 2.1.9 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 2.1.8 -Tue, 15 Aug 2017 19:04:14 GMT - -*Version update only* - -## 2.1.7 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 2.1.6 -Sat, 12 Aug 2017 01:03:30 GMT - -*Version update only* - -## 2.1.5 -Fri, 11 Aug 2017 21:44:05 GMT - -*Version update only* - -## 2.1.4 -Sat, 05 Aug 2017 01:04:41 GMT - -*Version update only* - -## 2.1.3 -Mon, 31 Jul 2017 21:18:26 GMT - -*Version update only* - -## 2.1.2 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 2.1.1 -Tue, 25 Jul 2017 20:03:31 GMT - -### Patches - -- Upgrade to TypeScript 2.4 - -## 2.1.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 2.0.3 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 2.0.2 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.0.1 -Fri, 13 Jan 2017 06:46:05 GMT - -*Initial release* - diff --git a/core-build/gulp-core-build-mocha/LICENSE b/core-build/gulp-core-build-mocha/LICENSE deleted file mode 100644 index e5f6473ae74..00000000000 --- a/core-build/gulp-core-build-mocha/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build-mocha - -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/core-build/gulp-core-build-mocha/README.md b/core-build/gulp-core-build-mocha/README.md deleted file mode 100644 index f36b177d6c5..00000000000 --- a/core-build/gulp-core-build-mocha/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# gulp-core-build-mocha - -`gulp-core-build-mocha` is a `gulp-core-build` subtask for running unit tests and creating coverage reports using mocha/chai. -This setup is useful for unit testing build tools, as it runs in the node process rather than in a browser. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-mocha.svg)](https://badge.fury.io/js/gulp-core-build-mocha) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build-mocha.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build-mocha) [![Dependencies](https://david-dm.org/Microsoft/gulp-core-build-mocha.svg)](https://david-dm.org/Microsoft/gulp-core-build-mocha) - -# Description - -**gulp-core-build-mocha** is a gulp-core-build plugin which will automatically execute a set of -unit test files using the mocha test suite. - -# MochaTask -## Usage - -Simply create a file which ends in `.test.js`. Next, register the Mocha task to gulp-core-build. - -A coverage report is both written to the console and to a folder on disk. - -## Configuration - -### testMatch - -Sets the glob pattern which is used to locate the files to run tests on. - -**Default:** 'lib/\*\*/\*.test.js' - -### reportDir - -The folder in which to store the coverage reports. - -**Default:** 'coverage' - -# InstrumentTask -## Usage - -This task selects which files should be covered by the code coverage tool. - -## Configuration -### coverageMatch -An array of globs which define which files should be included in code coverage reports. - -**Default:** `['lib/**/*.js', '!lib/**/*.test.js']` - -# License - -MIT \ No newline at end of file diff --git a/core-build/gulp-core-build-mocha/gulpfile.js b/core-build/gulp-core-build-mocha/gulpfile.js deleted file mode 100644 index 5ef0defb6ca..00000000000 --- a/core-build/gulp-core-build-mocha/gulpfile.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); - -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/core-build/gulp-core-build-mocha/package.json b/core-build/gulp-core-build-mocha/package.json deleted file mode 100644 index 9b7c07d7c4b..00000000000 --- a/core-build/gulp-core-build-mocha/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-mocha", - "version": "3.8.6", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build-mocha" - }, - "scripts": { - "build": "gulp --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@types/node": "10.17.13", - "glob": "~7.0.5", - "gulp": "~4.0.2", - "gulp-istanbul": "~0.10.3", - "gulp-mocha": "~6.0.0" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/glob": "7.1.1", - "@types/gulp": "4.0.6", - "@types/gulp-istanbul": "0.9.30", - "@types/gulp-mocha": "0.0.32", - "@types/mocha": "5.2.5", - "@types/orchestrator": "0.0.30" - } -} diff --git a/core-build/gulp-core-build-mocha/src/InstrumentTask.ts b/core-build/gulp-core-build-mocha/src/InstrumentTask.ts deleted file mode 100644 index 2a3b8ac50be..00000000000 --- a/core-build/gulp-core-build-mocha/src/InstrumentTask.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask, IBuildConfig } from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; -import * as gulpIstanbul from 'gulp-istanbul'; - -export interface IInstrumentTaskConfig { - coverageMatch: string[]; -} - -export class InstrumentTask extends GulpTask { - public constructor() { - super( - 'instrument', - { - coverageMatch: ['lib/**/*.js', '!lib/**/*.test.js'] - } - ); - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - return ( - super.isEnabled(buildConfig) && - !buildConfig.jestEnabled - ); - } - - public executeTask(gulp: typeof Gulp, completeCallback?: (error?: string) => void): NodeJS.ReadWriteStream { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const istanbul: typeof gulpIstanbul = require('gulp-istanbul'); - - return gulp.src(this.taskConfig.coverageMatch) - // Covering files - .pipe(istanbul()) - // Force `require` to return covered files - .pipe(istanbul.hookRequire()) - // Write the covered files to a temporary directory - .pipe(gulp.dest(this.buildConfig.tempFolder)); - } -} diff --git a/core-build/gulp-core-build-mocha/src/MochaTask.ts b/core-build/gulp-core-build-mocha/src/MochaTask.ts deleted file mode 100644 index 07511809e7e..00000000000 --- a/core-build/gulp-core-build-mocha/src/MochaTask.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask, IBuildConfig } from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; -import * as gulpMocha from 'gulp-mocha'; -import * as gulpIstanbul from 'gulp-istanbul'; -import * as glob from 'glob'; - -export interface IMochaTaskConfig { - testMatch: string[]; - reportDir: string; -} - -export class MochaTask extends GulpTask { - public constructor() { - super( - 'mocha', - { - testMatch: ['lib/**/*.test.js'], - reportDir: 'coverage' - } - ); - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - return ( - super.isEnabled(buildConfig) && - !buildConfig.jestEnabled - ); - } - - public executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): NodeJS.ReadWriteStream - | Promise { - - // eslint-disable-next-line @typescript-eslint/no-var-requires - const istanbul: typeof gulpIstanbul = require('gulp-istanbul'); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const mocha: typeof gulpMocha = require('gulp-mocha'); - - const globPattern: string = this.taskConfig.testMatch.join('|'); - - if (glob.sync(globPattern).length === 0) { - this.log('Skipping unit tests because no files were found matching: ' + globPattern); - return Promise.resolve(); - } - - // eslint-disable-next-line dot-notation - const matchString: string = this.buildConfig.args['match'] as string; - - return gulp.src(this.taskConfig.testMatch, { read: false }) - .pipe( - mocha({ - grep: matchString, - timeout: 15000 - }).on('error', (error: Error) => { - completeCallback(error.toString()); - }) - ) - .pipe(istanbul.writeReports({ - dir: this.taskConfig.reportDir - })); - } -} diff --git a/core-build/gulp-core-build-mocha/src/index.ts b/core-build/gulp-core-build-mocha/src/index.ts deleted file mode 100644 index e7909f58c88..00000000000 --- a/core-build/gulp-core-build-mocha/src/index.ts +++ /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. - -import { serial, IExecutable } from '@microsoft/gulp-core-build'; -import { MochaTask } from './MochaTask'; -import { InstrumentTask } from './InstrumentTask'; - -/** @public */ -export const instrument: InstrumentTask = new InstrumentTask(); -/** @public */ -export const mocha: MochaTask = new MochaTask(); - -export default serial(instrument, mocha) as IExecutable; diff --git a/core-build/gulp-core-build-mocha/tsconfig.json b/core-build/gulp-core-build-mocha/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/core-build/gulp-core-build-mocha/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/core-build/gulp-core-build-sass/.eslintrc.js b/core-build/gulp-core-build-sass/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/gulp-core-build-sass/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/gulp-core-build-sass/.npmignore b/core-build/gulp-core-build-sass/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build-sass/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build-sass/CHANGELOG.json b/core-build/gulp-core-build-sass/CHANGELOG.json deleted file mode 100644 index e8311633b38..00000000000 --- a/core-build/gulp-core-build-sass/CHANGELOG.json +++ /dev/null @@ -1,4974 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-sass", - "entries": [ - { - "version": "4.10.6", - "tag": "@microsoft/gulp-core-build-sass_v4.10.6", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.38` to `1.10.39`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "4.10.5", - "tag": "@microsoft/gulp-core-build-sass_v4.10.5", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.37` to `1.10.38`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" - } - ] - } - }, - { - "version": "4.10.4", - "tag": "@microsoft/gulp-core-build-sass_v4.10.4", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.36` to `1.10.37`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.2` to `0.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.3` to `6.4.4`" - } - ] - } - }, - { - "version": "4.10.3", - "tag": "@microsoft/gulp-core-build-sass_v4.10.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.35` to `1.10.36`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.2` to `6.4.3`" - } - ] - } - }, - { - "version": "4.10.2", - "tag": "@microsoft/gulp-core-build-sass_v4.10.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.34` to `1.10.35`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.1` to `0.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.1` to `6.4.2`" - } - ] - } - }, - { - "version": "4.10.1", - "tag": "@microsoft/gulp-core-build-sass_v4.10.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.33` to `1.10.34`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.0` to `6.4.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "4.10.0", - "tag": "@microsoft/gulp-core-build-sass_v4.10.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.32` to `1.10.33`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.15` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.16` to `6.4.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "4.9.0", - "tag": "@microsoft/gulp-core-build-sass_v4.9.0", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "minor": [ - { - "comment": "Update autoprefixer to ~9.7.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.31` to `1.10.32`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.15` to `6.3.16`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "4.8.24", - "tag": "@microsoft/gulp-core-build-sass_v4.8.24", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.30` to `1.10.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.13` to `0.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.14` to `6.3.15`" - } - ] - } - }, - { - "version": "4.8.23", - "tag": "@microsoft/gulp-core-build-sass_v4.8.23", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.29` to `1.10.30`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.13` to `6.3.14`" - } - ] - } - }, - { - "version": "4.8.22", - "tag": "@microsoft/gulp-core-build-sass_v4.8.22", - "date": "Fri, 10 Jan 2020 03:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.28` to `1.10.29`" - } - ] - } - }, - { - "version": "4.8.21", - "tag": "@microsoft/gulp-core-build-sass_v4.8.21", - "date": "Thu, 09 Jan 2020 06:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.27` to `1.10.28`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.12` to `6.3.13`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "4.8.20", - "tag": "@microsoft/gulp-core-build-sass_v4.8.20", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.26` to `1.10.27`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.11` to `6.3.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "4.8.19", - "tag": "@microsoft/gulp-core-build-sass_v4.8.19", - "date": "Mon, 23 Dec 2019 16:08:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.25` to `1.10.26`" - } - ] - } - }, - { - "version": "4.8.18", - "tag": "@microsoft/gulp-core-build-sass_v4.8.18", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.24` to `1.10.25`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.10` to `6.3.11`" - } - ] - } - }, - { - "version": "4.8.17", - "tag": "@microsoft/gulp-core-build-sass_v4.8.17", - "date": "Tue, 03 Dec 2019 03:17:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.23` to `1.10.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.9` to `0.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.9` to `6.3.10`" - } - ] - } - }, - { - "version": "4.8.16", - "tag": "@microsoft/gulp-core-build-sass_v4.8.16", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.22` to `1.10.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.8` to `0.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.8` to `6.3.9`" - } - ] - } - }, - { - "version": "4.8.15", - "tag": "@microsoft/gulp-core-build-sass_v4.8.15", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.21` to `1.10.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.7` to `0.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.7` to `6.3.8`" - } - ] - } - }, - { - "version": "4.8.14", - "tag": "@microsoft/gulp-core-build-sass_v4.8.14", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.20` to `1.10.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.6` to `0.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.6` to `6.3.7`" - } - ] - } - }, - { - "version": "4.8.13", - "tag": "@microsoft/gulp-core-build-sass_v4.8.13", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.19` to `1.10.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.5` to `6.3.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "4.8.12", - "tag": "@microsoft/gulp-core-build-sass_v4.8.12", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.18` to `1.10.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.4` to `0.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.4` to `6.3.5`" - } - ] - } - }, - { - "version": "4.8.11", - "tag": "@microsoft/gulp-core-build-sass_v4.8.11", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.17` to `1.10.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.3` to `6.3.4`" - } - ] - } - }, - { - "version": "4.8.10", - "tag": "@microsoft/gulp-core-build-sass_v4.8.10", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.16` to `1.10.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.2` to `6.3.3`" - } - ] - } - }, - { - "version": "4.8.9", - "tag": "@microsoft/gulp-core-build-sass_v4.8.9", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.15` to `1.10.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.1` to `6.3.2`" - } - ] - } - }, - { - "version": "4.8.8", - "tag": "@microsoft/gulp-core-build-sass_v4.8.8", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.14` to `1.10.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.0` to `6.3.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "4.8.7", - "tag": "@microsoft/gulp-core-build-sass_v4.8.7", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.13` to `1.10.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.6` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.6` to `6.3.0`" - } - ] - } - }, - { - "version": "4.8.6", - "tag": "@microsoft/gulp-core-build-sass_v4.8.6", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.12` to `1.10.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.5` to `6.2.6`" - } - ] - } - }, - { - "version": "4.8.5", - "tag": "@microsoft/gulp-core-build-sass_v4.8.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.11` to `1.10.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.4` to `6.2.5`" - } - ] - } - }, - { - "version": "4.8.4", - "tag": "@microsoft/gulp-core-build-sass_v4.8.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.10` to `1.10.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.3` to `6.2.4`" - } - ] - } - }, - { - "version": "4.8.3", - "tag": "@microsoft/gulp-core-build-sass_v4.8.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.9` to `1.10.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.2` to `6.2.3`" - } - ] - } - }, - { - "version": "4.8.2", - "tag": "@microsoft/gulp-core-build-sass_v4.8.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.8` to `1.10.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.1` to `0.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.1` to `6.2.2`" - } - ] - } - }, - { - "version": "4.8.1", - "tag": "@microsoft/gulp-core-build-sass_v4.8.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.7` to `1.10.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.0` to `6.2.1`" - } - ] - } - }, - { - "version": "4.8.0", - "tag": "@microsoft/gulp-core-build-sass_v4.8.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.6` to `1.10.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.24` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.11` to `6.2.0`" - } - ] - } - }, - { - "version": "4.7.25", - "tag": "@microsoft/gulp-core-build-sass_v4.7.25", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.5` to `1.10.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.23` to `0.1.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.10` to `6.1.11`" - } - ] - } - }, - { - "version": "4.7.24", - "tag": "@microsoft/gulp-core-build-sass_v4.7.24", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.4` to `1.10.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.22` to `0.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.9` to `6.1.10`" - } - ] - } - }, - { - "version": "4.7.23", - "tag": "@microsoft/gulp-core-build-sass_v4.7.23", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.3` to `1.10.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.21` to `0.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.8` to `6.1.9`" - } - ] - } - }, - { - "version": "4.7.22", - "tag": "@microsoft/gulp-core-build-sass_v4.7.22", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.2` to `1.10.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.20` to `0.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.7` to `6.1.8`" - } - ] - } - }, - { - "version": "4.7.21", - "tag": "@microsoft/gulp-core-build-sass_v4.7.21", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.1` to `1.10.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.19` to `0.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.6` to `6.1.7`" - } - ] - } - }, - { - "version": "4.7.20", - "tag": "@microsoft/gulp-core-build-sass_v4.7.20", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.0` to `1.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.18` to `0.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.5` to `6.1.6`" - } - ] - } - }, - { - "version": "4.7.19", - "tag": "@microsoft/gulp-core-build-sass_v4.7.19", - "date": "Wed, 04 Sep 2019 01:43:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.20` to `1.10.0`" - } - ] - } - }, - { - "version": "4.7.18", - "tag": "@microsoft/gulp-core-build-sass_v4.7.18", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.19` to `1.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.4` to `6.1.5`" - } - ] - } - }, - { - "version": "4.7.17", - "tag": "@microsoft/gulp-core-build-sass_v4.7.17", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.18` to `1.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.3` to `6.1.4`" - } - ] - } - }, - { - "version": "4.7.16", - "tag": "@microsoft/gulp-core-build-sass_v4.7.16", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.17` to `1.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.2` to `6.1.3`" - } - ] - } - }, - { - "version": "4.7.15", - "tag": "@microsoft/gulp-core-build-sass_v4.7.15", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.16` to `1.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.1` to `6.1.2`" - } - ] - } - }, - { - "version": "4.7.14", - "tag": "@microsoft/gulp-core-build-sass_v4.7.14", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.15` to `1.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.0` to `6.1.1`" - } - ] - } - }, - { - "version": "4.7.13", - "tag": "@microsoft/gulp-core-build-sass_v4.7.13", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "patch": [ - { - "comment": "Update node-sass to latest. Required for compatibility with Node 12." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.14` to `1.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.74` to `6.1.0`" - } - ] - } - }, - { - "version": "4.7.12", - "tag": "@microsoft/gulp-core-build-sass_v4.7.12", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.13` to `1.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.73` to `6.0.74`" - } - ] - } - }, - { - "version": "4.7.11", - "tag": "@microsoft/gulp-core-build-sass_v4.7.11", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.12` to `1.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.72` to `6.0.73`" - } - ] - } - }, - { - "version": "4.7.10", - "tag": "@microsoft/gulp-core-build-sass_v4.7.10", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.11` to `1.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.23` to `0.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.71` to `6.0.72`" - } - ] - } - }, - { - "version": "4.7.9", - "tag": "@microsoft/gulp-core-build-sass_v4.7.9", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.10` to `1.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.22` to `0.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.70` to `6.0.71`" - } - ] - } - }, - { - "version": "4.7.8", - "tag": "@microsoft/gulp-core-build-sass_v4.7.8", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.9` to `1.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.21` to `0.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.69` to `6.0.70`" - } - ] - } - }, - { - "version": "4.7.7", - "tag": "@microsoft/gulp-core-build-sass_v4.7.7", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.8` to `1.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.20` to `0.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.68` to `6.0.69`" - } - ] - } - }, - { - "version": "4.7.6", - "tag": "@microsoft/gulp-core-build-sass_v4.7.6", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.7` to `1.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.19` to `0.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.67` to `6.0.68`" - } - ] - } - }, - { - "version": "4.7.5", - "tag": "@microsoft/gulp-core-build-sass_v4.7.5", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.6` to `1.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.18` to `0.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.66` to `6.0.67`" - } - ] - } - }, - { - "version": "4.7.4", - "tag": "@microsoft/gulp-core-build-sass_v4.7.4", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.5` to `1.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.17` to `0.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.65` to `6.0.66`" - } - ] - } - }, - { - "version": "4.7.3", - "tag": "@microsoft/gulp-core-build-sass_v4.7.3", - "date": "Thu, 06 Jun 2019 22:33:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.4` to `1.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.16` to `0.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.64` to `6.0.65`" - } - ] - } - }, - { - "version": "4.7.2", - "tag": "@microsoft/gulp-core-build-sass_v4.7.2", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.3` to `1.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.15` to `0.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.63` to `6.0.64`" - } - ] - } - }, - { - "version": "4.7.1", - "tag": "@microsoft/gulp-core-build-sass_v4.7.1", - "date": "Tue, 04 Jun 2019 05:51:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.2` to `1.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.62` to `6.0.63`" - } - ] - } - }, - { - "version": "4.7.0", - "tag": "@microsoft/gulp-core-build-sass_v4.7.0", - "date": "Fri, 31 May 2019 01:13:07 GMT", - "comments": { - "minor": [ - { - "comment": "Make css modules class hash names consistent relative to root path." - } - ] - } - }, - { - "version": "4.6.35", - "tag": "@microsoft/gulp-core-build-sass_v4.6.35", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.1` to `1.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.13` to `0.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.61` to `6.0.62`" - } - ] - } - }, - { - "version": "4.6.34", - "tag": "@microsoft/gulp-core-build-sass_v4.6.34", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.9.0` to `1.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.60` to `6.0.61`" - } - ] - } - }, - { - "version": "4.6.33", - "tag": "@microsoft/gulp-core-build-sass_v4.6.33", - "date": "Thu, 09 May 2019 19:12:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.89` to `1.9.0`" - } - ] - } - }, - { - "version": "4.6.32", - "tag": "@microsoft/gulp-core-build-sass_v4.6.32", - "date": "Mon, 06 May 2019 20:46:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.88` to `1.8.89`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.59` to `6.0.60`" - } - ] - } - }, - { - "version": "4.6.31", - "tag": "@microsoft/gulp-core-build-sass_v4.6.31", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.87` to `1.8.88`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.10` to `0.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.58` to `6.0.59`" - } - ] - } - }, - { - "version": "4.6.30", - "tag": "@microsoft/gulp-core-build-sass_v4.6.30", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.86` to `1.8.87`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.9` to `0.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.57` to `6.0.58`" - } - ] - } - }, - { - "version": "4.6.29", - "tag": "@microsoft/gulp-core-build-sass_v4.6.29", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.85` to `1.8.86`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.8` to `0.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.56` to `6.0.57`" - } - ] - } - }, - { - "version": "4.6.28", - "tag": "@microsoft/gulp-core-build-sass_v4.6.28", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.84` to `1.8.85`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.7` to `0.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.55` to `6.0.56`" - } - ] - } - }, - { - "version": "4.6.27", - "tag": "@microsoft/gulp-core-build-sass_v4.6.27", - "date": "Fri, 12 Apr 2019 06:13:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.83` to `1.8.84`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.6` to `0.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.54` to `6.0.55`" - } - ] - } - }, - { - "version": "4.6.26", - "tag": "@microsoft/gulp-core-build-sass_v4.6.26", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.82` to `1.8.83`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.53` to `6.0.54`" - } - ] - } - }, - { - "version": "4.6.25", - "tag": "@microsoft/gulp-core-build-sass_v4.6.25", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.81` to `1.8.82`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.4` to `0.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.52` to `6.0.53`" - } - ] - } - }, - { - "version": "4.6.24", - "tag": "@microsoft/gulp-core-build-sass_v4.6.24", - "date": "Mon, 08 Apr 2019 19:12:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.80` to `1.8.81`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.51` to `6.0.52`" - } - ] - } - }, - { - "version": "4.6.23", - "tag": "@microsoft/gulp-core-build-sass_v4.6.23", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.79` to `1.8.80`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.50` to `6.0.51`" - } - ] - } - }, - { - "version": "4.6.22", - "tag": "@microsoft/gulp-core-build-sass_v4.6.22", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.78` to `1.8.79`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.49` to `6.0.50`" - } - ] - } - }, - { - "version": "4.6.21", - "tag": "@microsoft/gulp-core-build-sass_v4.6.21", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.77` to `1.8.78`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.48` to `6.0.49`" - } - ] - } - }, - { - "version": "4.6.20", - "tag": "@microsoft/gulp-core-build-sass_v4.6.20", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.76` to `1.8.77`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.47` to `6.0.48`" - } - ] - } - }, - { - "version": "4.6.19", - "tag": "@microsoft/gulp-core-build-sass_v4.6.19", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.75` to `1.8.76`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.46` to `6.0.47`" - } - ] - } - }, - { - "version": "4.6.18", - "tag": "@microsoft/gulp-core-build-sass_v4.6.18", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.74` to `1.8.75`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.45` to `6.0.46`" - } - ] - } - }, - { - "version": "4.6.17", - "tag": "@microsoft/gulp-core-build-sass_v4.6.17", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.73` to `1.8.74`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.44` to `6.0.45`" - } - ] - } - }, - { - "version": "4.6.16", - "tag": "@microsoft/gulp-core-build-sass_v4.6.16", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.72` to `1.8.73`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.43` to `6.0.44`" - } - ] - } - }, - { - "version": "4.6.15", - "tag": "@microsoft/gulp-core-build-sass_v4.6.15", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.71` to `1.8.72`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.42` to `6.0.43`" - } - ] - } - }, - { - "version": "4.6.14", - "tag": "@microsoft/gulp-core-build-sass_v4.6.14", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.70` to `1.8.71`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.41` to `6.0.42`" - } - ] - } - }, - { - "version": "4.6.13", - "tag": "@microsoft/gulp-core-build-sass_v4.6.13", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.69` to `1.8.70`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.40` to `6.0.41`" - } - ] - } - }, - { - "version": "4.6.12", - "tag": "@microsoft/gulp-core-build-sass_v4.6.12", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.68` to `1.8.69`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.39` to `6.0.40`" - } - ] - } - }, - { - "version": "4.6.11", - "tag": "@microsoft/gulp-core-build-sass_v4.6.11", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.67` to `1.8.68`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.38` to `6.0.39`" - } - ] - } - }, - { - "version": "4.6.10", - "tag": "@microsoft/gulp-core-build-sass_v4.6.10", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.66` to `1.8.67`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.37` to `6.0.38`" - } - ] - } - }, - { - "version": "4.6.9", - "tag": "@microsoft/gulp-core-build-sass_v4.6.9", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.65` to `1.8.66`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.36` to `6.0.37`" - } - ] - } - }, - { - "version": "4.6.8", - "tag": "@microsoft/gulp-core-build-sass_v4.6.8", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.64` to `1.8.65`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.35` to `6.0.36`" - } - ] - } - }, - { - "version": "4.6.7", - "tag": "@microsoft/gulp-core-build-sass_v4.6.7", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.63` to `1.8.64`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.34` to `6.0.35`" - } - ] - } - }, - { - "version": "4.6.6", - "tag": "@microsoft/gulp-core-build-sass_v4.6.6", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.62` to `1.8.63`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.33` to `6.0.34`" - } - ] - } - }, - { - "version": "4.6.5", - "tag": "@microsoft/gulp-core-build-sass_v4.6.5", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.61` to `1.8.62`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.1` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.32` to `6.0.33`" - } - ] - } - }, - { - "version": "4.6.4", - "tag": "@microsoft/gulp-core-build-sass_v4.6.4", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.60` to `1.8.61`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.31` to `6.0.32`" - } - ] - } - }, - { - "version": "4.6.3", - "tag": "@microsoft/gulp-core-build-sass_v4.6.3", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.59` to `1.8.60`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.30` to `6.0.31`" - } - ] - } - }, - { - "version": "4.6.2", - "tag": "@microsoft/gulp-core-build-sass_v4.6.2", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.58` to `1.8.59`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.29` to `6.0.30`" - } - ] - } - }, - { - "version": "4.6.1", - "tag": "@microsoft/gulp-core-build-sass_v4.6.1", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.57` to `1.8.58`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.28` to `6.0.29`" - } - ] - } - }, - { - "version": "4.6.0", - "tag": "@microsoft/gulp-core-build-sass_v4.6.0", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "minor": [ - { - "comment": "Updated support for clean-css 4.2.1 and typings. Added override task configuration for clean-css options." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.56` to `1.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.9.0` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.27` to `6.0.28`" - } - ] - } - }, - { - "version": "4.5.40", - "tag": "@microsoft/gulp-core-build-sass_v4.5.40", - "date": "Wed, 30 Jan 2019 20:49:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.55` to `1.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.26` to `6.0.27`" - } - ] - } - }, - { - "version": "4.5.39", - "tag": "@microsoft/gulp-core-build-sass_v4.5.39", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.54` to `1.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.25` to `6.0.26`" - } - ] - } - }, - { - "version": "4.5.38", - "tag": "@microsoft/gulp-core-build-sass_v4.5.38", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.53` to `1.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.24` to `6.0.25`" - } - ] - } - }, - { - "version": "4.5.37", - "tag": "@microsoft/gulp-core-build-sass_v4.5.37", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.52` to `1.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.3` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.23` to `6.0.24`" - } - ] - } - }, - { - "version": "4.5.36", - "tag": "@microsoft/gulp-core-build-sass_v4.5.36", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.51` to `1.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.22` to `6.0.23`" - } - ] - } - }, - { - "version": "4.5.35", - "tag": "@microsoft/gulp-core-build-sass_v4.5.35", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.50` to `1.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.21` to `6.0.22`" - } - ] - } - }, - { - "version": "4.5.34", - "tag": "@microsoft/gulp-core-build-sass_v4.5.34", - "date": "Fri, 14 Dec 2018 20:51:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.49` to `1.8.50`" - } - ] - } - }, - { - "version": "4.5.33", - "tag": "@microsoft/gulp-core-build-sass_v4.5.33", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.48` to `1.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.20` to `6.0.21`" - } - ] - } - }, - { - "version": "4.5.32", - "tag": "@microsoft/gulp-core-build-sass_v4.5.32", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.47` to `1.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.19` to `6.0.20`" - } - ] - } - }, - { - "version": "4.5.31", - "tag": "@microsoft/gulp-core-build-sass_v4.5.31", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.46` to `1.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.18` to `6.0.19`" - } - ] - } - }, - { - "version": "4.5.30", - "tag": "@microsoft/gulp-core-build-sass_v4.5.30", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.45` to `1.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.1` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.17` to `6.0.18`" - } - ] - } - }, - { - "version": "4.5.29", - "tag": "@microsoft/gulp-core-build-sass_v4.5.29", - "date": "Mon, 03 Dec 2018 17:04:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.44` to `1.8.45`" - } - ] - } - }, - { - "version": "4.5.28", - "tag": "@microsoft/gulp-core-build-sass_v4.5.28", - "date": "Fri, 30 Nov 2018 23:34:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.43` to `1.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.16` to `6.0.17`" - } - ] - } - }, - { - "version": "4.5.27", - "tag": "@microsoft/gulp-core-build-sass_v4.5.27", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.42` to `1.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.15` to `6.0.16`" - } - ] - } - }, - { - "version": "4.5.26", - "tag": "@microsoft/gulp-core-build-sass_v4.5.26", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.41` to `1.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.14` to `6.0.15`" - } - ] - } - }, - { - "version": "4.5.25", - "tag": "@microsoft/gulp-core-build-sass_v4.5.25", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.40` to `1.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.13` to `6.0.14`" - } - ] - } - }, - { - "version": "4.5.24", - "tag": "@microsoft/gulp-core-build-sass_v4.5.24", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.39` to `1.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.6.0` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.12` to `6.0.13`" - } - ] - } - }, - { - "version": "4.5.23", - "tag": "@microsoft/gulp-core-build-sass_v4.5.23", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.38` to `1.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.2` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.11` to `6.0.12`" - } - ] - } - }, - { - "version": "4.5.22", - "tag": "@microsoft/gulp-core-build-sass_v4.5.22", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.37` to `1.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.10` to `6.0.11`" - } - ] - } - }, - { - "version": "4.5.21", - "tag": "@microsoft/gulp-core-build-sass_v4.5.21", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.36` to `1.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.9` to `6.0.10`" - } - ] - } - }, - { - "version": "4.5.20", - "tag": "@microsoft/gulp-core-build-sass_v4.5.20", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.35` to `1.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.8` to `6.0.9`" - } - ] - } - }, - { - "version": "4.5.19", - "tag": "@microsoft/gulp-core-build-sass_v4.5.19", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.34` to `1.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.7` to `6.0.8`" - } - ] - } - }, - { - "version": "4.5.18", - "tag": "@microsoft/gulp-core-build-sass_v4.5.18", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.33` to `1.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.6` to `6.0.7`" - } - ] - } - }, - { - "version": "4.5.17", - "tag": "@microsoft/gulp-core-build-sass_v4.5.17", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.32` to `1.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.5` to `6.0.6`" - } - ] - } - }, - { - "version": "4.5.16", - "tag": "@microsoft/gulp-core-build-sass_v4.5.16", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.31` to `1.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.4` to `6.0.5`" - } - ] - } - }, - { - "version": "4.5.15", - "tag": "@microsoft/gulp-core-build-sass_v4.5.15", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.30` to `1.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.3` to `6.0.4`" - } - ] - } - }, - { - "version": "4.5.14", - "tag": "@microsoft/gulp-core-build-sass_v4.5.14", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.29` to `1.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.2` to `6.0.3`" - } - ] - } - }, - { - "version": "4.5.13", - "tag": "@microsoft/gulp-core-build-sass_v4.5.13", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.28` to `1.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.1` to `6.0.2`" - } - ] - } - }, - { - "version": "4.5.12", - "tag": "@microsoft/gulp-core-build-sass_v4.5.12", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.27` to `1.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.0` to `6.0.1`" - } - ] - } - }, - { - "version": "4.5.11", - "tag": "@microsoft/gulp-core-build-sass_v4.5.11", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.26` to `1.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.26` to `6.0.0`" - } - ] - } - }, - { - "version": "4.5.10", - "tag": "@microsoft/gulp-core-build-sass_v4.5.10", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.25` to `1.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.4.0` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.25` to `5.0.26`" - } - ] - } - }, - { - "version": "4.5.9", - "tag": "@microsoft/gulp-core-build-sass_v4.5.9", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.24` to `1.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.24` to `5.0.25`" - } - ] - } - }, - { - "version": "4.5.8", - "tag": "@microsoft/gulp-core-build-sass_v4.5.8", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.23` to `1.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.1` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.23` to `5.0.24`" - } - ] - } - }, - { - "version": "4.5.7", - "tag": "@microsoft/gulp-core-build-sass_v4.5.7", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.22` to `1.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.22` to `5.0.23`" - } - ] - } - }, - { - "version": "4.5.6", - "tag": "@microsoft/gulp-core-build-sass_v4.5.6", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.21` to `1.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.21` to `5.0.22`" - } - ] - } - }, - { - "version": "4.5.5", - "tag": "@microsoft/gulp-core-build-sass_v4.5.5", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.20` to `1.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.20` to `5.0.21`" - } - ] - } - }, - { - "version": "4.5.4", - "tag": "@microsoft/gulp-core-build-sass_v4.5.4", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.19` to `1.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.19` to `5.0.20`" - } - ] - } - }, - { - "version": "4.5.3", - "tag": "@microsoft/gulp-core-build-sass_v4.5.3", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.18` to `1.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.18` to `5.0.19`" - } - ] - } - }, - { - "version": "4.5.2", - "tag": "@microsoft/gulp-core-build-sass_v4.5.2", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.17` to `1.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.17` to `5.0.18`" - } - ] - } - }, - { - "version": "4.5.1", - "tag": "@microsoft/gulp-core-build-sass_v4.5.1", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.16` to `1.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.2.0` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.16` to `5.0.17`" - } - ] - } - }, - { - "version": "4.5.0", - "tag": "@microsoft/gulp-core-build-sass_v4.5.0", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "minor": [ - { - "comment": "Refactor task to no longer use Gulp." - } - ], - "patch": [ - { - "comment": "Better support for indented syntax and, likewise, `.sass` extension." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.15` to `1.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.1.0` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.15` to `5.0.16`" - } - ] - } - }, - { - "version": "4.4.8", - "tag": "@microsoft/gulp-core-build-sass_v4.4.8", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.14` to `1.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.14` to `5.0.15`" - } - ] - } - }, - { - "version": "4.4.7", - "tag": "@microsoft/gulp-core-build-sass_v4.4.7", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.13` to `1.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.13` to `5.0.14`" - } - ] - } - }, - { - "version": "4.4.6", - "tag": "@microsoft/gulp-core-build-sass_v4.4.6", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.12` to `1.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.12` to `5.0.13`" - } - ] - } - }, - { - "version": "4.4.5", - "tag": "@microsoft/gulp-core-build-sass_v4.4.5", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.11` to `1.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.11` to `5.0.12`" - } - ] - } - }, - { - "version": "4.4.4", - "tag": "@microsoft/gulp-core-build-sass_v4.4.4", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.10` to `1.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.10` to `5.0.11`" - } - ] - } - }, - { - "version": "4.4.3", - "tag": "@microsoft/gulp-core-build-sass_v4.4.3", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.9` to `1.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.9` to `5.0.10`" - } - ] - } - }, - { - "version": "4.4.2", - "tag": "@microsoft/gulp-core-build-sass_v4.4.2", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.8` to `1.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.8` to `5.0.9`" - } - ] - } - }, - { - "version": "4.4.1", - "tag": "@microsoft/gulp-core-build-sass_v4.4.1", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.7` to `1.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.7` to `5.0.8`" - } - ] - } - }, - { - "version": "4.4.0", - "tag": "@microsoft/gulp-core-build-sass_v4.4.0", - "date": "Thu, 06 Sep 2018 21:04:43 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade PostCSS related packages to newest versions." - } - ] - } - }, - { - "version": "4.3.54", - "tag": "@microsoft/gulp-core-build-sass_v4.3.54", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.6` to `1.8.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.6` to `5.0.7`" - } - ] - } - }, - { - "version": "4.3.53", - "tag": "@microsoft/gulp-core-build-sass_v4.3.53", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.5` to `1.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.5` to `5.0.6`" - } - ] - } - }, - { - "version": "4.3.52", - "tag": "@microsoft/gulp-core-build-sass_v4.3.52", - "date": "Mon, 03 Sep 2018 16:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.4` to `1.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.4` to `5.0.5`" - } - ] - } - }, - { - "version": "4.3.51", - "tag": "@microsoft/gulp-core-build-sass_v4.3.51", - "date": "Fri, 31 Aug 2018 00:11:01 GMT", - "comments": { - "patch": [ - { - "comment": "Include @types/gulp as a non-dev dependency." - } - ] - } - }, - { - "version": "4.3.50", - "tag": "@microsoft/gulp-core-build-sass_v4.3.50", - "date": "Thu, 30 Aug 2018 22:47:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.3` to `1.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.3` to `5.0.4`" - } - ] - } - }, - { - "version": "4.3.49", - "tag": "@microsoft/gulp-core-build-sass_v4.3.49", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.2` to `1.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.2` to `5.0.3`" - } - ] - } - }, - { - "version": "4.3.48", - "tag": "@microsoft/gulp-core-build-sass_v4.3.48", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.1` to `1.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.1` to `5.0.2`" - } - ] - } - }, - { - "version": "4.3.47", - "tag": "@microsoft/gulp-core-build-sass_v4.3.47", - "date": "Thu, 30 Aug 2018 04:42:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.8.0` to `1.8.1`" - } - ] - } - }, - { - "version": "4.3.46", - "tag": "@microsoft/gulp-core-build-sass_v4.3.46", - "date": "Thu, 30 Aug 2018 04:24:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.84` to `1.8.0`" - } - ] - } - }, - { - "version": "4.3.45", - "tag": "@microsoft/gulp-core-build-sass_v4.3.45", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.83` to `1.7.84`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.0` to `5.0.1`" - } - ] - } - }, - { - "version": "4.3.44", - "tag": "@microsoft/gulp-core-build-sass_v4.3.44", - "date": "Wed, 29 Aug 2018 20:34:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.82` to `1.7.83`" - } - ] - } - }, - { - "version": "4.3.43", - "tag": "@microsoft/gulp-core-build-sass_v4.3.43", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.81` to `1.7.82`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `4.4.11` to `5.0.0`" - } - ] - } - }, - { - "version": "4.3.42", - "tag": "@microsoft/gulp-core-build-sass_v4.3.42", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.80` to `1.7.81`" - } - ] - } - }, - { - "version": "4.3.41", - "tag": "@microsoft/gulp-core-build-sass_v4.3.41", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.79` to `1.7.80`" - } - ] - } - }, - { - "version": "4.3.40", - "tag": "@microsoft/gulp-core-build-sass_v4.3.40", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.78` to `1.7.79`" - } - ] - } - }, - { - "version": "4.3.39", - "tag": "@microsoft/gulp-core-build-sass_v4.3.39", - "date": "Tue, 21 Aug 2018 16:04:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.77` to `1.7.78`" - } - ] - } - }, - { - "version": "4.3.38", - "tag": "@microsoft/gulp-core-build-sass_v4.3.38", - "date": "Thu, 09 Aug 2018 21:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.76` to `1.7.77`" - } - ] - } - }, - { - "version": "4.3.37", - "tag": "@microsoft/gulp-core-build-sass_v4.3.37", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.75` to `1.7.76`" - } - ] - } - }, - { - "version": "4.3.36", - "tag": "@microsoft/gulp-core-build-sass_v4.3.36", - "date": "Thu, 09 Aug 2018 16:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.74` to `1.7.75`" - } - ] - } - }, - { - "version": "4.3.35", - "tag": "@microsoft/gulp-core-build-sass_v4.3.35", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.73` to `1.7.74`" - } - ] - } - }, - { - "version": "4.3.34", - "tag": "@microsoft/gulp-core-build-sass_v4.3.34", - "date": "Thu, 26 Jul 2018 23:53:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.72` to `1.7.73`" - } - ] - } - }, - { - "version": "4.3.33", - "tag": "@microsoft/gulp-core-build-sass_v4.3.33", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.71` to `1.7.72`" - } - ] - } - }, - { - "version": "4.3.32", - "tag": "@microsoft/gulp-core-build-sass_v4.3.32", - "date": "Wed, 25 Jul 2018 21:02:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.70` to `1.7.71`" - } - ] - } - }, - { - "version": "4.3.31", - "tag": "@microsoft/gulp-core-build-sass_v4.3.31", - "date": "Fri, 20 Jul 2018 16:04:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.69` to `1.7.70`" - } - ] - } - }, - { - "version": "4.3.30", - "tag": "@microsoft/gulp-core-build-sass_v4.3.30", - "date": "Tue, 17 Jul 2018 16:02:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.68` to `1.7.69`" - } - ] - } - }, - { - "version": "4.3.29", - "tag": "@microsoft/gulp-core-build-sass_v4.3.29", - "date": "Fri, 13 Jul 2018 19:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.67` to `1.7.68`" - } - ] - } - }, - { - "version": "4.3.28", - "tag": "@microsoft/gulp-core-build-sass_v4.3.28", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.66` to `1.7.67`" - } - ] - } - }, - { - "version": "4.3.27", - "tag": "@microsoft/gulp-core-build-sass_v4.3.27", - "date": "Fri, 29 Jun 2018 02:56:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.65` to `1.7.66`" - } - ] - } - }, - { - "version": "4.3.26", - "tag": "@microsoft/gulp-core-build-sass_v4.3.26", - "date": "Sat, 23 Jun 2018 02:21:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.64` to `1.7.65`" - } - ] - } - }, - { - "version": "4.3.25", - "tag": "@microsoft/gulp-core-build-sass_v4.3.25", - "date": "Fri, 22 Jun 2018 16:05:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.63` to `1.7.64`" - } - ] - } - }, - { - "version": "4.3.24", - "tag": "@microsoft/gulp-core-build-sass_v4.3.24", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.62` to `1.7.63`" - } - ] - } - }, - { - "version": "4.3.23", - "tag": "@microsoft/gulp-core-build-sass_v4.3.23", - "date": "Tue, 19 Jun 2018 19:35:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.61` to `1.7.62`" - } - ] - } - }, - { - "version": "4.3.22", - "tag": "@microsoft/gulp-core-build-sass_v4.3.22", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.60` to `1.7.61`" - } - ] - } - }, - { - "version": "4.3.21", - "tag": "@microsoft/gulp-core-build-sass_v4.3.21", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.59` to `1.7.60`" - } - ] - } - }, - { - "version": "4.3.20", - "tag": "@microsoft/gulp-core-build-sass_v4.3.20", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.58` to `1.7.59`" - } - ] - } - }, - { - "version": "4.3.19", - "tag": "@microsoft/gulp-core-build-sass_v4.3.19", - "date": "Tue, 15 May 2018 00:18:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.57` to `1.7.58`" - } - ] - } - }, - { - "version": "4.3.18", - "tag": "@microsoft/gulp-core-build-sass_v4.3.18", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.56` to `1.7.57`" - } - ] - } - }, - { - "version": "4.3.17", - "tag": "@microsoft/gulp-core-build-sass_v4.3.17", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.55` to `1.7.56`" - } - ] - } - }, - { - "version": "4.3.16", - "tag": "@microsoft/gulp-core-build-sass_v4.3.16", - "date": "Tue, 01 May 2018 22:03:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.54` to `1.7.55`" - } - ] - } - }, - { - "version": "4.3.15", - "tag": "@microsoft/gulp-core-build-sass_v4.3.15", - "date": "Fri, 27 Apr 2018 03:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.53` to `1.7.54`" - } - ] - } - }, - { - "version": "4.3.14", - "tag": "@microsoft/gulp-core-build-sass_v4.3.14", - "date": "Fri, 20 Apr 2018 16:06:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.52` to `1.7.53`" - } - ] - } - }, - { - "version": "4.3.13", - "tag": "@microsoft/gulp-core-build-sass_v4.3.13", - "date": "Thu, 19 Apr 2018 21:25:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.51` to `1.7.52`" - } - ] - } - }, - { - "version": "4.3.12", - "tag": "@microsoft/gulp-core-build-sass_v4.3.12", - "date": "Thu, 19 Apr 2018 17:02:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.50` to `1.7.51`" - } - ] - } - }, - { - "version": "4.3.11", - "tag": "@microsoft/gulp-core-build-sass_v4.3.11", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.49` to `1.7.50`" - } - ] - } - }, - { - "version": "4.3.10", - "tag": "@microsoft/gulp-core-build-sass_v4.3.10", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.48` to `1.7.49`" - } - ] - } - }, - { - "version": "4.3.9", - "tag": "@microsoft/gulp-core-build-sass_v4.3.9", - "date": "Tue, 27 Mar 2018 01:34:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.47` to `1.7.48`" - } - ] - } - }, - { - "version": "4.3.8", - "tag": "@microsoft/gulp-core-build-sass_v4.3.8", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.46` to `1.7.47`" - } - ] - } - }, - { - "version": "4.3.7", - "tag": "@microsoft/gulp-core-build-sass_v4.3.7", - "date": "Sun, 25 Mar 2018 01:26:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.45` to `1.7.46`" - } - ] - } - }, - { - "version": "4.3.6", - "tag": "@microsoft/gulp-core-build-sass_v4.3.6", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.44` to `1.7.45`" - } - ] - } - }, - { - "version": "4.3.5", - "tag": "@microsoft/gulp-core-build-sass_v4.3.5", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.43` to `1.7.44`" - } - ] - } - }, - { - "version": "4.3.4", - "tag": "@microsoft/gulp-core-build-sass_v4.3.4", - "date": "Tue, 20 Mar 2018 02:44:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.42` to `1.7.43`" - } - ] - } - }, - { - "version": "4.3.3", - "tag": "@microsoft/gulp-core-build-sass_v4.3.3", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.41` to `1.7.42`" - } - ] - } - }, - { - "version": "4.3.2", - "tag": "@microsoft/gulp-core-build-sass_v4.3.2", - "date": "Thu, 15 Mar 2018 20:00:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.40` to `1.7.41`" - } - ] - } - }, - { - "version": "4.3.1", - "tag": "@microsoft/gulp-core-build-sass_v4.3.1", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.39` to `1.7.40`" - } - ] - } - }, - { - "version": "4.3.0", - "tag": "@microsoft/gulp-core-build-sass_v4.3.0", - "date": "Tue, 13 Mar 2018 23:11:32 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for sourcemaps." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.38` to `1.7.39`" - } - ] - } - }, - { - "version": "4.2.21", - "tag": "@microsoft/gulp-core-build-sass_v4.2.21", - "date": "Mon, 12 Mar 2018 20:36:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.37` to `1.7.38`" - } - ] - } - }, - { - "version": "4.2.20", - "tag": "@microsoft/gulp-core-build-sass_v4.2.20", - "date": "Tue, 06 Mar 2018 17:04:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.36` to `1.7.37`" - } - ] - } - }, - { - "version": "4.2.19", - "tag": "@microsoft/gulp-core-build-sass_v4.2.19", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.35` to `1.7.36`" - } - ] - } - }, - { - "version": "4.2.18", - "tag": "@microsoft/gulp-core-build-sass_v4.2.18", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.34` to `1.7.35`" - } - ] - } - }, - { - "version": "4.2.17", - "tag": "@microsoft/gulp-core-build-sass_v4.2.17", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.33` to `1.7.34`" - } - ] - } - }, - { - "version": "4.2.16", - "tag": "@microsoft/gulp-core-build-sass_v4.2.16", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.32` to `1.7.33`" - } - ] - } - }, - { - "version": "4.2.15", - "tag": "@microsoft/gulp-core-build-sass_v4.2.15", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.31` to `1.7.32`" - } - ] - } - }, - { - "version": "4.2.14", - "tag": "@microsoft/gulp-core-build-sass_v4.2.14", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.30` to `1.7.31`" - } - ] - } - }, - { - "version": "4.2.13", - "tag": "@microsoft/gulp-core-build-sass_v4.2.13", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.29` to `1.7.30`" - } - ] - } - }, - { - "version": "4.2.12", - "tag": "@microsoft/gulp-core-build-sass_v4.2.12", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.28` to `1.7.29`" - } - ] - } - }, - { - "version": "4.2.11", - "tag": "@microsoft/gulp-core-build-sass_v4.2.11", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.27` to `1.7.28`" - } - ] - } - }, - { - "version": "4.2.10", - "tag": "@microsoft/gulp-core-build-sass_v4.2.10", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.26` to `1.7.27`" - } - ] - } - }, - { - "version": "4.2.9", - "tag": "@microsoft/gulp-core-build-sass_v4.2.9", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.25` to `1.7.26`" - } - ] - } - }, - { - "version": "4.2.8", - "tag": "@microsoft/gulp-core-build-sass_v4.2.8", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.24` to `1.7.25`" - } - ] - } - }, - { - "version": "4.2.7", - "tag": "@microsoft/gulp-core-build-sass_v4.2.7", - "date": "Sat, 20 Jan 2018 02:39:16 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unused dependencies" - } - ] - } - }, - { - "version": "4.2.6", - "tag": "@microsoft/gulp-core-build-sass_v4.2.6", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.23` to `1.7.24`" - } - ] - } - }, - { - "version": "4.2.5", - "tag": "@microsoft/gulp-core-build-sass_v4.2.5", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.22` to `1.7.23`" - } - ] - } - }, - { - "version": "4.2.4", - "tag": "@microsoft/gulp-core-build-sass_v4.2.4", - "date": "Thu, 18 Jan 2018 00:27:23 GMT", - "comments": { - "patch": [ - { - "comment": "Remove deprecated tslint rule \"typeof-compare\"" - } - ] - } - }, - { - "version": "4.2.3", - "tag": "@microsoft/gulp-core-build-sass_v4.2.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.21` to `1.7.22`" - } - ] - } - }, - { - "version": "4.2.2", - "tag": "@microsoft/gulp-core-build-sass_v4.2.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.20` to `1.7.21`" - } - ] - } - }, - { - "version": "4.2.1", - "tag": "@microsoft/gulp-core-build-sass_v4.2.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.19` to `1.7.20`" - } - ] - } - }, - { - "version": "4.2.0", - "tag": "@microsoft/gulp-core-build-sass_v4.2.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.18` to `1.7.19`" - } - ] - } - }, - { - "version": "4.1.24", - "tag": "@microsoft/gulp-core-build-sass_v4.1.24", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.6` to `3.3.7`" - } - ] - } - }, - { - "version": "4.1.23", - "tag": "@microsoft/gulp-core-build-sass_v4.1.23", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.17` to `1.7.18`" - } - ] - } - }, - { - "version": "4.1.22", - "tag": "@microsoft/gulp-core-build-sass_v4.1.22", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.16` to `1.7.17`" - } - ] - } - }, - { - "version": "4.1.21", - "tag": "@microsoft/gulp-core-build-sass_v4.1.21", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.15` to `1.7.16`" - } - ] - } - }, - { - "version": "4.1.20", - "tag": "@microsoft/gulp-core-build-sass_v4.1.20", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.14` to `1.7.15`" - } - ] - } - }, - { - "version": "4.1.19", - "tag": "@microsoft/gulp-core-build-sass_v4.1.19", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.13` to `1.7.14`" - } - ] - } - }, - { - "version": "4.1.18", - "tag": "@microsoft/gulp-core-build-sass_v4.1.18", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.12` to `1.7.13`" - } - ] - } - }, - { - "version": "4.1.17", - "tag": "@microsoft/gulp-core-build-sass_v4.1.17", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.11` to `1.7.12`" - } - ] - } - }, - { - "version": "4.1.16", - "tag": "@microsoft/gulp-core-build-sass_v4.1.16", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.10` to `1.7.11`" - } - ] - } - }, - { - "version": "4.1.15", - "tag": "@microsoft/gulp-core-build-sass_v4.1.15", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.9` to `1.7.10`" - } - ] - } - }, - { - "version": "4.1.14", - "tag": "@microsoft/gulp-core-build-sass_v4.1.14", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.8` to `1.7.9`" - } - ] - } - }, - { - "version": "4.1.13", - "tag": "@microsoft/gulp-core-build-sass_v4.1.13", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.7` to `1.7.8`" - } - ] - } - }, - { - "version": "4.1.12", - "tag": "@microsoft/gulp-core-build-sass_v4.1.12", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.7.6` to `1.7.7`" - } - ] - } - }, - { - "version": "4.1.11", - "tag": "@microsoft/gulp-core-build-sass_v4.1.11", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "4.1.10", - "tag": "@microsoft/gulp-core-build-sass_v4.1.10", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - } - ] - } - }, - { - "version": "4.1.9", - "tag": "@microsoft/gulp-core-build-sass_v4.1.9", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - } - ] - } - }, - { - "version": "4.1.8", - "tag": "@microsoft/gulp-core-build-sass_v4.1.8", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - } - ] - } - }, - { - "version": "4.1.7", - "tag": "@microsoft/gulp-core-build-sass_v4.1.7", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.7.5` to `~1.7.6`" - } - ] - } - }, - { - "version": "4.1.6", - "tag": "@microsoft/gulp-core-build-sass_v4.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - } - ] - } - }, - { - "version": "4.1.5", - "tag": "@microsoft/gulp-core-build-sass_v4.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - } - ] - } - }, - { - "version": "4.1.4", - "tag": "@microsoft/gulp-core-build-sass_v4.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - } - ] - } - }, - { - "version": "4.1.3", - "tag": "@microsoft/gulp-core-build-sass_v4.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - } - ] - } - }, - { - "version": "4.1.2", - "tag": "@microsoft/gulp-core-build-sass_v4.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - } - ] - } - }, - { - "version": "4.1.1", - "tag": "@microsoft/gulp-core-build-sass_v4.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - } - ] - } - }, - { - "version": "4.1.0", - "tag": "@microsoft/gulp-core-build-sass_v4.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.7.4` to `~1.7.5`" - } - ] - } - }, - { - "version": "4.0.8", - "tag": "@microsoft/gulp-core-build-sass_v4.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - } - ] - } - }, - { - "version": "4.0.7", - "tag": "@microsoft/gulp-core-build-sass_v4.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - } - ] - } - }, - { - "version": "4.0.6", - "tag": "@microsoft/gulp-core-build-sass_v4.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - } - ] - } - }, - { - "version": "4.0.5", - "tag": "@microsoft/gulp-core-build-sass_v4.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - } - ] - } - }, - { - "version": "4.0.4", - "tag": "@microsoft/gulp-core-build-sass_v4.0.4", - "date": "Thu, 07 Sep 2017 00:11:11 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "4b7451b442c2078a96430f7a05caed37101aed52", - "comment": " Add $schema field to all schemas" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - } - ] - } - }, - { - "version": "4.0.3", - "tag": "@microsoft/gulp-core-build-sass_v4.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - } - ] - } - }, - { - "version": "4.0.2", - "tag": "@microsoft/gulp-core-build-sass_v4.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - } - ] - } - }, - { - "version": "4.0.1", - "tag": "@microsoft/gulp-core-build-sass_v4.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - } - ] - } - }, - { - "version": "4.0.0", - "tag": "@microsoft/gulp-core-build-sass_v4.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.7.3` to `~1.7.4`" - } - ] - } - }, - { - "version": "3.2.11", - "tag": "@microsoft/gulp-core-build-sass_v3.2.11", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - } - ] - } - }, - { - "version": "3.2.10", - "tag": "@microsoft/gulp-core-build-sass_v3.2.10", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.7.2` to `~1.7.3`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/gulp-core-build-sass_v3.2.9", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/gulp-core-build-sass_v3.2.8", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/gulp-core-build-sass_v3.2.7", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.7.1` to `~1.7.2`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/gulp-core-build-sass_v3.2.6", - "date": "Wed, 16 Aug 2017 23:16:55 GMT", - "comments": { - "patch": [ - { - "comment": "Publish" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/gulp-core-build-sass_v3.2.5", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.6.0` to `~1.7.0`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/gulp-core-build-sass_v3.2.4", - "date": "Tue, 08 Aug 2017 23:10:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.5.2` to `~1.6.0`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/gulp-core-build-sass_v3.2.3", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/gulp-core-build-sass_v3.2.2", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.5.0` to `~1.5.1`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/gulp-core-build-sass_v3.2.1", - "date": "Fri, 21 Jul 2017 01:02:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `~1.4.0` to `~1.5.0`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build-sass_v3.2.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - } - ] - } - }, - { - "version": "3.1.2", - "tag": "@microsoft/gulp-core-build-sass_v3.1.2", - "date": "Mon, 15 May 2017 21:59:43 GMT", - "comments": { - "patch": [ - { - "comment": "Remove incremental builds, which cause incorrect behavior when dealing with imports." - } - ] - } - }, - { - "version": "3.1.1", - "tag": "@microsoft/gulp-core-build-sass_v3.1.1", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build-sass_v3.1.0", - "date": "Tue, 11 Apr 2017 01:33:59 GMT", - "comments": { - "minor": [ - { - "comment": "Add task config property: warnOnCssInvalidPropertyName to gulp-core-build-sass. if set to false, CSS module compile warning message will changed to verbose message" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build-sass_v3.0.0", - "date": "Mon, 20 Mar 2017 21:52:20 GMT", - "comments": { - "minor": [ - { - "comment": "Adding moduleExportName option to sass task, so that we can optionally export to something other than \"default\"." - } - ], - "major": [ - { - "comment": "Updating gulp-sass and related package version dependencies." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.2 <3.0.0` to `>=2.4.3 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.8", - "tag": "@microsoft/gulp-core-build-sass_v2.0.8", - "date": "Mon, 20 Mar 2017 03:50:55 GMT", - "comments": { - "patch": [ - { - "comment": "Reverting previous change, which causes a regression in SPFx yeoman scenario." - } - ] - } - }, - { - "version": "2.0.7", - "tag": "@microsoft/gulp-core-build-sass_v2.0.7", - "date": "Mon, 20 Mar 2017 00:54:03 GMT", - "comments": { - "patch": [ - { - "comment": "Updating gulp-sass and related package version dependencies." - } - ] - } - }, - { - "version": "2.0.6", - "tag": "@microsoft/gulp-core-build-sass_v2.0.6", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.5", - "tag": "@microsoft/gulp-core-build-sass_v2.0.5", - "date": "Tue, 14 Feb 2017 20:03:00 GMT", - "comments": { - "patch": [ - { - "comment": "Updating SASS hash generation for css modules to consider css content in addition to filename." - } - ] - } - }, - { - "version": "2.0.4", - "tag": "@microsoft/gulp-core-build-sass_v2.0.4", - "date": "Wed, 08 Feb 2017 00:23:01 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing the paths generated by GCB-sass to be compatible with Webpack 2.X" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.2.1 <3.0.0` to `>=2.2.2 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.3", - "tag": "@microsoft/gulp-core-build-sass_v2.0.3", - "date": "Tue, 31 Jan 2017 20:32:37 GMT", - "comments": { - "patch": [ - { - "comment": "Make loadSchema public instead of protected." - } - ] - } - }, - { - "version": "2.0.2", - "tag": "@microsoft/gulp-core-build-sass_v2.0.2", - "date": "Tue, 31 Jan 2017 01:55:09 GMT", - "comments": { - "patch": [ - { - "comment": "Introduce schema for SassTask" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build-sass_v2.0.1", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build-sass/CHANGELOG.md b/core-build/gulp-core-build-sass/CHANGELOG.md deleted file mode 100644 index eae8494d03e..00000000000 --- a/core-build/gulp-core-build-sass/CHANGELOG.md +++ /dev/null @@ -1,1496 +0,0 @@ -# Change Log - @microsoft/gulp-core-build-sass - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 4.10.6 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 4.10.5 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 4.10.4 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 4.10.3 -Fri, 24 Jan 2020 00:27:39 GMT - -*Version update only* - -## 4.10.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 4.10.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 4.10.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 4.9.0 -Fri, 17 Jan 2020 01:08:23 GMT - -### Minor changes - -- Update autoprefixer to ~9.7.4 - -## 4.8.24 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 4.8.23 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 4.8.22 -Fri, 10 Jan 2020 03:07:47 GMT - -*Version update only* - -## 4.8.21 -Thu, 09 Jan 2020 06:44:12 GMT - -*Version update only* - -## 4.8.20 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 4.8.19 -Mon, 23 Dec 2019 16:08:05 GMT - -*Version update only* - -## 4.8.18 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 4.8.17 -Tue, 03 Dec 2019 03:17:43 GMT - -*Version update only* - -## 4.8.16 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 4.8.15 -Wed, 20 Nov 2019 06:14:28 GMT - -*Version update only* - -## 4.8.14 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 4.8.13 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 4.8.12 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 4.8.11 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 4.8.10 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 4.8.9 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 4.8.8 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 4.8.7 -Mon, 21 Oct 2019 05:22:43 GMT - -*Version update only* - -## 4.8.6 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 4.8.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 4.8.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 4.8.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 4.8.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 4.8.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 4.8.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 4.7.25 -Fri, 20 Sep 2019 21:27:22 GMT - -*Version update only* - -## 4.7.24 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 4.7.23 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 4.7.22 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 4.7.21 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 4.7.20 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 4.7.19 -Wed, 04 Sep 2019 01:43:31 GMT - -*Version update only* - -## 4.7.18 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 4.7.17 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 4.7.16 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 4.7.15 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 4.7.14 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 4.7.13 -Tue, 23 Jul 2019 19:14:38 GMT - -### Patches - -- Update node-sass to latest. Required for compatibility with Node 12. - -## 4.7.12 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 4.7.11 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 4.7.10 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 4.7.9 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 4.7.8 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 4.7.7 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 4.7.6 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 4.7.5 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 4.7.4 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 4.7.3 -Thu, 06 Jun 2019 22:33:36 GMT - -*Version update only* - -## 4.7.2 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 4.7.1 -Tue, 04 Jun 2019 05:51:53 GMT - -*Version update only* - -## 4.7.0 -Fri, 31 May 2019 01:13:07 GMT - -### Minor changes - -- Make css modules class hash names consistent relative to root path. - -## 4.6.35 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 4.6.34 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 4.6.33 -Thu, 09 May 2019 19:12:31 GMT - -*Version update only* - -## 4.6.32 -Mon, 06 May 2019 20:46:21 GMT - -*Version update only* - -## 4.6.31 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 4.6.30 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 4.6.29 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 4.6.28 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 4.6.27 -Fri, 12 Apr 2019 06:13:16 GMT - -*Version update only* - -## 4.6.26 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 4.6.25 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 4.6.24 -Mon, 08 Apr 2019 19:12:52 GMT - -*Version update only* - -## 4.6.23 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 4.6.22 -Fri, 05 Apr 2019 04:16:17 GMT - -*Version update only* - -## 4.6.21 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 4.6.20 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 4.6.19 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 4.6.18 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 4.6.17 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 4.6.16 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 4.6.15 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 4.6.14 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 4.6.13 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 4.6.12 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 4.6.11 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 4.6.10 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 4.6.9 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 4.6.8 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 4.6.7 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 4.6.6 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 4.6.5 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 4.6.4 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 4.6.3 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 4.6.2 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 4.6.1 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 4.6.0 -Mon, 11 Feb 2019 03:31:55 GMT - -### Minor changes - -- Updated support for clean-css 4.2.1 and typings. Added override task configuration for clean-css options. - -## 4.5.40 -Wed, 30 Jan 2019 20:49:11 GMT - -*Version update only* - -## 4.5.39 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 4.5.38 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 4.5.37 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 4.5.36 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 4.5.35 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 4.5.34 -Fri, 14 Dec 2018 20:51:51 GMT - -*Version update only* - -## 4.5.33 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 4.5.32 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 4.5.31 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 4.5.30 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 4.5.29 -Mon, 03 Dec 2018 17:04:06 GMT - -*Version update only* - -## 4.5.28 -Fri, 30 Nov 2018 23:34:58 GMT - -*Version update only* - -## 4.5.27 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 4.5.26 -Thu, 29 Nov 2018 00:35:38 GMT - -*Version update only* - -## 4.5.25 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 4.5.24 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 4.5.23 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 4.5.22 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 4.5.21 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 4.5.20 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 4.5.19 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 4.5.18 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 4.5.17 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 4.5.16 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 4.5.15 -Wed, 31 Oct 2018 21:17:50 GMT - -*Version update only* - -## 4.5.14 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 4.5.13 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 4.5.12 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 4.5.11 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 4.5.10 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 4.5.9 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 4.5.8 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 4.5.7 -Thu, 18 Oct 2018 05:30:14 GMT - -*Version update only* - -## 4.5.6 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 4.5.5 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 4.5.4 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 4.5.3 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 4.5.2 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 4.5.1 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 4.5.0 -Sun, 07 Oct 2018 06:15:56 GMT - -### Minor changes - -- Refactor task to no longer use Gulp. - -### Patches - -- Better support for indented syntax and, likewise, `.sass` extension. - -## 4.4.8 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 4.4.7 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 4.4.6 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 4.4.5 -Mon, 24 Sep 2018 16:04:28 GMT - -*Version update only* - -## 4.4.4 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 4.4.3 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 4.4.2 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 4.4.1 -Mon, 10 Sep 2018 23:23:01 GMT - -*Version update only* - -## 4.4.0 -Thu, 06 Sep 2018 21:04:43 GMT - -### Minor changes - -- Upgrade PostCSS related packages to newest versions. - -## 4.3.54 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 4.3.53 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 4.3.52 -Mon, 03 Sep 2018 16:04:46 GMT - -*Version update only* - -## 4.3.51 -Fri, 31 Aug 2018 00:11:01 GMT - -### Patches - -- Include @types/gulp as a non-dev dependency. - -## 4.3.50 -Thu, 30 Aug 2018 22:47:34 GMT - -*Version update only* - -## 4.3.49 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 4.3.48 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 4.3.47 -Thu, 30 Aug 2018 04:42:01 GMT - -*Version update only* - -## 4.3.46 -Thu, 30 Aug 2018 04:24:41 GMT - -*Version update only* - -## 4.3.45 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 4.3.44 -Wed, 29 Aug 2018 20:34:33 GMT - -*Version update only* - -## 4.3.43 -Wed, 29 Aug 2018 06:36:50 GMT - -*Version update only* - -## 4.3.42 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 4.3.41 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 4.3.40 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 4.3.39 -Tue, 21 Aug 2018 16:04:38 GMT - -*Version update only* - -## 4.3.38 -Thu, 09 Aug 2018 21:58:02 GMT - -*Version update only* - -## 4.3.37 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 4.3.36 -Thu, 09 Aug 2018 16:04:24 GMT - -*Version update only* - -## 4.3.35 -Tue, 07 Aug 2018 22:27:31 GMT - -*Version update only* - -## 4.3.34 -Thu, 26 Jul 2018 23:53:43 GMT - -*Version update only* - -## 4.3.33 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 4.3.32 -Wed, 25 Jul 2018 21:02:57 GMT - -*Version update only* - -## 4.3.31 -Fri, 20 Jul 2018 16:04:52 GMT - -*Version update only* - -## 4.3.30 -Tue, 17 Jul 2018 16:02:52 GMT - -*Version update only* - -## 4.3.29 -Fri, 13 Jul 2018 19:04:50 GMT - -*Version update only* - -## 4.3.28 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 4.3.27 -Fri, 29 Jun 2018 02:56:51 GMT - -*Version update only* - -## 4.3.26 -Sat, 23 Jun 2018 02:21:20 GMT - -*Version update only* - -## 4.3.25 -Fri, 22 Jun 2018 16:05:15 GMT - -*Version update only* - -## 4.3.24 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 4.3.23 -Tue, 19 Jun 2018 19:35:11 GMT - -*Version update only* - -## 4.3.22 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 4.3.21 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 4.3.20 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 4.3.19 -Tue, 15 May 2018 00:18:10 GMT - -*Version update only* - -## 4.3.18 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 4.3.17 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 4.3.16 -Tue, 01 May 2018 22:03:20 GMT - -*Version update only* - -## 4.3.15 -Fri, 27 Apr 2018 03:04:32 GMT - -*Version update only* - -## 4.3.14 -Fri, 20 Apr 2018 16:06:11 GMT - -*Version update only* - -## 4.3.13 -Thu, 19 Apr 2018 21:25:56 GMT - -*Version update only* - -## 4.3.12 -Thu, 19 Apr 2018 17:02:06 GMT - -*Version update only* - -## 4.3.11 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 4.3.10 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 4.3.9 -Tue, 27 Mar 2018 01:34:25 GMT - -*Version update only* - -## 4.3.8 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 4.3.7 -Sun, 25 Mar 2018 01:26:19 GMT - -*Version update only* - -## 4.3.6 -Fri, 23 Mar 2018 00:34:53 GMT - -*Version update only* - -## 4.3.5 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 4.3.4 -Tue, 20 Mar 2018 02:44:45 GMT - -*Version update only* - -## 4.3.3 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 4.3.2 -Thu, 15 Mar 2018 20:00:50 GMT - -*Version update only* - -## 4.3.1 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 4.3.0 -Tue, 13 Mar 2018 23:11:32 GMT - -### Minor changes - -- Add support for sourcemaps. - -## 4.2.21 -Mon, 12 Mar 2018 20:36:19 GMT - -*Version update only* - -## 4.2.20 -Tue, 06 Mar 2018 17:04:51 GMT - -*Version update only* - -## 4.2.19 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 4.2.18 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 4.2.17 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 4.2.16 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 4.2.15 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 4.2.14 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 4.2.13 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.2.12 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.2.11 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 4.2.10 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 4.2.9 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 4.2.8 -Tue, 23 Jan 2018 17:05:28 GMT - -*Version update only* - -## 4.2.7 -Sat, 20 Jan 2018 02:39:16 GMT - -### Patches - -- Remove unused dependencies - -## 4.2.6 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 4.2.5 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 4.2.4 -Thu, 18 Jan 2018 00:27:23 GMT - -### Patches - -- Remove deprecated tslint rule "typeof-compare" - -## 4.2.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 4.2.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 4.2.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 4.2.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 4.1.24 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 4.1.23 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 4.1.22 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 4.1.21 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 4.1.20 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 4.1.19 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 4.1.18 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 4.1.17 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 4.1.16 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 4.1.15 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 4.1.14 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 4.1.13 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 4.1.12 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 4.1.11 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 4.1.10 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 4.1.9 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 4.1.8 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 4.1.7 -Tue, 24 Oct 2017 18:17:12 GMT - -*Version update only* - -## 4.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 4.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 4.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 4.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 4.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 4.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 4.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 4.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 4.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 4.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -*Version update only* - -## 4.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 4.0.4 -Thu, 07 Sep 2017 00:11:11 GMT - -### Patches - -- Add $schema field to all schemas - -## 4.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 4.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 4.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 4.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 3.2.11 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 3.2.10 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 3.2.9 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 3.2.8 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 3.2.7 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 3.2.6 -Wed, 16 Aug 2017 23:16:55 GMT - -### Patches - -- Publish - -## 3.2.5 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 3.2.4 -Tue, 08 Aug 2017 23:10:36 GMT - -*Version update only* - -## 3.2.3 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 3.2.2 -Tue, 25 Jul 2017 20:03:31 GMT - -### Patches - -- Upgrade to TypeScript 2.4 - -## 3.2.1 -Fri, 21 Jul 2017 01:02:30 GMT - -*Version update only* - -## 3.2.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 3.1.2 -Mon, 15 May 2017 21:59:43 GMT - -### Patches - -- Remove incremental builds, which cause incorrect behavior when dealing with imports. - -## 3.1.1 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 3.1.0 -Tue, 11 Apr 2017 01:33:59 GMT - -### Minor changes - -- Add task config property: warnOnCssInvalidPropertyName to gulp-core-build-sass. if set to false, CSS module compile warning message will changed to verbose message - -## 3.0.0 -Mon, 20 Mar 2017 21:52:20 GMT - -### Breaking changes - -- Updating gulp-sass and related package version dependencies. - -### Minor changes - -- Adding moduleExportName option to sass task, so that we can optionally export to something other than "default". - -## 2.0.8 -Mon, 20 Mar 2017 03:50:55 GMT - -### Patches - -- Reverting previous change, which causes a regression in SPFx yeoman scenario. - -## 2.0.7 -Mon, 20 Mar 2017 00:54:03 GMT - -### Patches - -- Updating gulp-sass and related package version dependencies. - -## 2.0.6 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.0.5 -Tue, 14 Feb 2017 20:03:00 GMT - -### Patches - -- Updating SASS hash generation for css modules to consider css content in addition to filename. - -## 2.0.4 -Wed, 08 Feb 2017 00:23:01 GMT - -### Patches - -- Fixing the paths generated by GCB-sass to be compatible with Webpack 2.X - -## 2.0.3 -Tue, 31 Jan 2017 20:32:37 GMT - -### Patches - -- Make loadSchema public instead of protected. - -## 2.0.2 -Tue, 31 Jan 2017 01:55:09 GMT - -### Patches - -- Introduce schema for SassTask - -## 2.0.1 -Fri, 13 Jan 2017 06:46:05 GMT - -*Initial release* - diff --git a/core-build/gulp-core-build-sass/LICENSE b/core-build/gulp-core-build-sass/LICENSE deleted file mode 100644 index d1df86eea40..00000000000 --- a/core-build/gulp-core-build-sass/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build-sass - -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/core-build/gulp-core-build-sass/README.md b/core-build/gulp-core-build-sass/README.md deleted file mode 100644 index cc46e0e83fc..00000000000 --- a/core-build/gulp-core-build-sass/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# @microsoft/gulp-core-build-sass - -`gulp-core-build-sass` is a `gulp-core-build` subtask which processes sass and scss files using SASS, runs them through postcss, and produces commonjs/amd modules which are injected using the `@microsoft/load-themed-styles` package. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-sass.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-sass) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build-sass.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build-sass) [![Dependencies](https://david-dm.org/Microsoft/gulp-core-build-sass.svg)](https://david-dm.org/Microsoft/gulp-core-build-sass) - -# SassTask - -## Usage -This task invokes `gulp-sass` to compile source SASS files into a CommonJS module which uses `load-themed-styles` to load styles onto the page. If the `libAmdFolder` is specified globally, this task will also output an AMD module. Various templates may be specified. - -## Config -### preamble -An optional parameter for text to include in the generated typescript file. - -**Default:** `'/* tslint:disable */'` - -### postamble -An optional parameter for text to include at the end of the generated typescript file. - -**Default:** `'/* tslint:enable */'` - -### sassMatch -An array of glob patterns for locating SASS files. - -**Default:** `['src/**/*.scss']` - -### useCSSModules -If this option is specified, ALL files will be treated as `module.sass` or `module.scss` and will -automatically generate a corresponding TypeScript file. All classes will be -appended with a hash to help ensure uniqueness on a page. This file can be -imported directly, and will contain an object describing the mangled class names. - -**Default:** `false` - -### dropCssFiles -If this is false, then we do not create `.css` files in the `lib` directory. - -**Default:** `false` - -### warnOnNonCSSModules -If files are matched by sassMatch which do not end in `.module.sass` or `.module.scss`, log a warning. - -**Default:** `false` - -# License - -MIT diff --git a/core-build/gulp-core-build-sass/config/api-extractor.json b/core-build/gulp-core-build-sass/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/gulp-core-build-sass/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/gulp-core-build-sass/config/jest.json b/core-build/gulp-core-build-sass/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/core-build/gulp-core-build-sass/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/core-build/gulp-core-build-sass/gulpfile.js b/core-build/gulp-core-build-sass/gulpfile.js deleted file mode 100644 index 296eccbf8a6..00000000000 --- a/core-build/gulp-core-build-sass/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/core-build/gulp-core-build-sass/package.json b/core-build/gulp-core-build-sass/package.json deleted file mode 100644 index 70a2dd77145..00000000000 --- a/core-build/gulp-core-build-sass/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-sass", - "version": "4.10.6", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build-sass" - }, - "scripts": { - "build": "gulp test --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@microsoft/load-themed-styles": "1.10.39", - "@rushstack/node-core-library": "3.19.5", - "@types/gulp": "4.0.6", - "@types/node": "10.17.13", - "autoprefixer": "~9.7.4", - "clean-css": "4.2.1", - "glob": "~7.0.5", - "node-sass": "4.12.0", - "postcss": "7.0.5", - "postcss-modules": "~1.3.1" - }, - "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/clean-css": "4.2.1", - "@types/glob": "7.1.1", - "@types/jest": "23.3.11", - "@types/node-sass": "4.11.0", - "gulp": "~4.0.2", - "jest": "~23.6.0" - } -} diff --git a/core-build/gulp-core-build-sass/src/CSSModules.ts b/core-build/gulp-core-build-sass/src/CSSModules.ts deleted file mode 100644 index c0b13895835..00000000000 --- a/core-build/gulp-core-build-sass/src/CSSModules.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as path from 'path'; - -import * as postcss from 'postcss'; -import * as cssModules from 'postcss-modules'; -import * as crypto from 'crypto'; - -export interface IClassMap { - [className: string]: string; -} - -export interface ICSSModules { - /** - * Return a configured postcss plugin that will map class names to a - * consistently generated scoped name. - */ - getPlugin(): postcss.AcceptedPlugin; - - /** - * Return the CSS class map that is stored after postcss-modules runs. - */ - getClassMap(): IClassMap; -} - -export default class CSSModules implements ICSSModules { - private _classMap: IClassMap; - private _rootPath: string; - - /** - * CSSModules includes the source file's path relative to the project root - * as part of the class name hashing algorithm. - * This should be configured with the setting: - * {@link @microsoft/gulp-core-build#IBuildConfig.rootPath} - * That is used in {@link ./SassTask#SassTask} - * But will default the process' current working dir. - */ - public constructor(rootPath?: string) { - this._classMap = {}; - if (rootPath) { - this._rootPath = rootPath; - } else { - this._rootPath = process.cwd(); - } - } - - public getPlugin(): postcss.AcceptedPlugin { - return cssModules({ - getJSON: this.saveJson.bind(this), - generateScopedName: this.generateScopedName.bind(this) - }); - } - - public getClassMap(): IClassMap { - return this._classMap; - } - - protected saveJson(cssFileName: string, json: IClassMap): void { - this._classMap = json; - } - - protected generateScopedName(name: string, fileName: string, css: string) - : string { - const fileBaseName: string = path.relative(this._rootPath, fileName); - const safeFileBaseName: string = fileBaseName.replace(/\\/g, '/'); - const hash: string = crypto.createHmac('sha1', safeFileBaseName) - .update(css) - .digest('hex') - .substring(0, 8); - return `${name}_${hash}`; - } -} diff --git a/core-build/gulp-core-build-sass/src/SassTask.ts b/core-build/gulp-core-build-sass/src/SassTask.ts deleted file mode 100644 index 57ae3efe245..00000000000 --- a/core-build/gulp-core-build-sass/src/SassTask.ts +++ /dev/null @@ -1,311 +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 Gulp from 'gulp'; -import { EOL } from 'os'; - -import { GulpTask } from '@microsoft/gulp-core-build'; -import { splitStyles } from '@microsoft/load-themed-styles'; -import { - FileSystem, - JsonFile, - LegacyAdapters, - JsonObject -} from '@rushstack/node-core-library'; -import * as glob from 'glob'; -import * as nodeSass from 'node-sass'; -import * as postcss from 'postcss'; -import * as CleanCss from 'clean-css'; -import * as autoprefixer from 'autoprefixer'; -import CSSModules, { ICSSModules, IClassMap } from './CSSModules'; - -export interface ISassTaskConfig { - /** - * An optional parameter for text to include in the generated TypeScript file. - */ - preamble?: string; - - /** - * An optional parameter for text to include at the end of the generated - * TypeScript file. - */ - postamble?: string; - - /** - * An array of glob patterns for locating files. - */ - sassMatch?: string[]; - - /** - * If this option is specified, ALL files will be treated as module.sass or - * module.scss and will automatically generate a corresponding TypeScript - * file. All classes will be appended with a hash to help ensure uniqueness - * on a page. This file can be imported directly, and will contain an object - * describing the mangled class names. - */ - useCSSModules?: boolean; - - /** - * If false, we will set the CSS property naming warning to verbose message - * while the module generates to prevent task exit with exitcode: 1. - * Default value is true. - */ - warnOnCssInvalidPropertyName?: boolean; - - /** - * If true, we will generate CSS in the lib folder. If false, the CSS is - * directly embedded into the TypeScript file. - */ - dropCssFiles?: boolean; - - /** - * If files are matched by sassMatch which do not end in .module.sass or - * .module.scss, log a warning. - */ - warnOnNonCSSModules?: boolean; - - /** - * If this option is specified, module CSS will be exported using the name - * provided. If an empty value is specified, the styles will be exported - * using 'export =', rather than a named export. By default, we use the - * 'default' export name. - */ - moduleExportName?: string; - - /** - * Allows the override of the options passed to clean-css. Options such a - * returnPromise and sourceMap will be ignored. - */ - cleanCssOptions?: CleanCss.Options; -} - -export class SassTask extends GulpTask { - public cleanMatch: string[] = [ - 'src/**/*.sass.ts', - 'src/**/*.scss.ts' - ]; - - private _postCSSPlugins: postcss.AcceptedPlugin[] = [ - autoprefixer({ overrideBrowserslist: ['> 1%', 'last 2 versions', 'ie >= 10'] }) - ]; - - public constructor() { - super( - 'sass', - { - preamble: '/* tslint:disable */', - postamble: '/* tslint:enable */', - sassMatch: [ - 'src/**/*.scss', - 'src/**/*.sass' - ], - useCSSModules: false, - warnOnCssInvalidPropertyName: true, - dropCssFiles: false, - warnOnNonCSSModules: false - } - ); - } - - public loadSchema(): JsonObject { - return JsonFile.load(path.join(__dirname, 'sass.schema.json')); - } - - public executeTask(gulp: typeof Gulp): Promise | undefined { - if (!this.taskConfig.sassMatch) { - return Promise.reject(new Error('taskConfig.sassMatch must be defined')); - } - - return this._globAll(...this.taskConfig.sassMatch).then((matches: string[]) => { - return Promise.all(matches.map((match) => this._processFile(match))); - }).then(() => { /* collapse void[] to void */ }); - } - - private _processFile(filePath: string): Promise { - // Ignore files that start with underscores - if (path.basename(filePath).match(/^\_/)) { - return Promise.resolve(); - } - - const isFileModuleCss: boolean = !!filePath.match(/\.module\.s(a|c)ss/); - const processAsModuleCss: boolean = isFileModuleCss || !!this.taskConfig.useCSSModules; - const cssModules: ICSSModules = new CSSModules(this.buildConfig.rootPath); - - if (!processAsModuleCss && this.taskConfig.warnOnNonCSSModules) { - const relativeFilePath: string = path.relative( - this.buildConfig.rootPath, filePath - ); - this.logWarning( - `${relativeFilePath}: filename should end with module.sass or module.scss` - ); - } - - let cssOutputPath: string | undefined = undefined; - let cssOutputPathAbsolute: string | undefined = undefined; - if (this.taskConfig.dropCssFiles) { - const srcRelativePath: string = path.relative( - path.join(this.buildConfig.rootPath, this.buildConfig.srcFolder), - filePath - ); - cssOutputPath = path.join(this.buildConfig.libFolder, srcRelativePath); - cssOutputPath = cssOutputPath.replace(/\.s(c|a)ss$/, '.css'); - cssOutputPathAbsolute = path.join(this.buildConfig.rootPath, cssOutputPath); - } - - return LegacyAdapters.convertCallbackToPromise( - nodeSass.render, - { - file: filePath, - importer: (url: string) => ({ file: this._patchSassUrl(url) }), - sourceMap: this.taskConfig.dropCssFiles, - sourceMapContents: true, - omitSourceMapUrl: true, - outFile: cssOutputPath - } - ).catch((error: nodeSass.SassError) => { - this.fileError(filePath, error.line, error.column, error.name, error.message); - throw new Error(error.message); - }).then((result: nodeSass.Result) => { - const options: postcss.ProcessOptions = { - from: filePath - }; - if (result.map && !this.buildConfig.production) { - options.map = { - prev: result.map.toString() // Pass the source map through to postcss - }; - } - - const plugins: postcss.AcceptedPlugin[] = [...this._postCSSPlugins]; - if (processAsModuleCss) { - plugins.push(cssModules.getPlugin()); - } - return postcss(plugins).process(result.css.toString(), options) as PromiseLike; - }).then((result: postcss.Result) => { - let cleanCssOptions: CleanCss.Options = { level: 1, returnPromise: true }; - if (this.taskConfig.cleanCssOptions) { - cleanCssOptions = { ...this.taskConfig.cleanCssOptions, returnPromise: true }; - } - cleanCssOptions.sourceMap = !!result.map; - - const cleanCss: CleanCss.MinifierPromise = new CleanCss(cleanCssOptions); - return cleanCss.minify(result.css.toString(), result.map ? result.map.toString() : undefined); - }).then((result: CleanCss.Output) => { - if (cssOutputPathAbsolute) { - const generatedFileLines: string[] = [ - result.styles.toString() - ]; - if (result.sourceMap && !this.buildConfig.production) { - const encodedSourceMap: string = Buffer.from(result.sourceMap.toString()).toString('base64'); - generatedFileLines.push( - `/*# sourceMappingURL=data:application/json;base64,${encodedSourceMap} */` - ); - } - - FileSystem.writeFile( - cssOutputPathAbsolute, - generatedFileLines.join(EOL), - { ensureFolderExists: true } - ); - } - - const scssTsOutputPath: string = `${filePath}.ts`; - const classMap: IClassMap = cssModules.getClassMap(); - const stylesExportString: string = this._getStylesExportString(classMap); - const content: string | undefined = result.styles; - - let lines: string[] = []; - lines.push(this.taskConfig.preamble || ''); - - if (cssOutputPathAbsolute) { - lines = lines.concat([ - `require(${JSON.stringify(`./${path.basename(cssOutputPathAbsolute)}`)});`, - stylesExportString - ]); - } else if (content) { - lines = lines.concat([ - 'import { loadStyles } from \'@microsoft/load-themed-styles\';', - '', - stylesExportString, - '', - `loadStyles(${JSON.stringify(splitStyles(content))});` - ]); - } - - lines.push(this.taskConfig.postamble || ''); - - const generatedTsFile: string = ( - lines - .join(EOL) - .replace(new RegExp(`(${EOL}){3,}`, 'g'), `${EOL}${EOL}`) - .replace(new RegExp(`(${EOL})+$`, 'm'), EOL) - ); - - FileSystem.writeFile(scssTsOutputPath, generatedTsFile); - }); - } - - private _globAll(...patterns: string[]): Promise { - return Promise.all(patterns.map((pattern) => - LegacyAdapters.convertCallbackToPromise( - glob, - path.isAbsolute(pattern) ? pattern : path.join(this.buildConfig.rootPath, pattern) - ) - )).then((matchSets: string[][]) => { - const result: { [path: string]: boolean } = {}; - for (const matchSet of matchSets) { - for (const match of matchSet) { - const normalizedMatch: string = path.resolve(match); - result[normalizedMatch] = true; - } - } - - return Object.keys(result); - }); - } - - private _patchSassUrl(url: string): string { - if (url[0] === '~') { - url = 'node_modules/' + url.substr(1); - } else if (url === 'stdin') { - url = ''; - } - - return url; - } - - private _getStylesExportString(classMap: IClassMap): string { - const classKeys: string[] = Object.keys(classMap); - const styleLines: string[] = []; - classKeys.forEach((key: string) => { - const value: string = classMap[key]; - if (key.indexOf('-') !== -1) { - const message: string = `The local CSS class '${key}' is not ` + - `camelCase and will not be type-safe.`; - if (this.taskConfig.warnOnCssInvalidPropertyName) { - this.logWarning(message); - } else { - this.logVerbose(message); - } - key = `'${key}'`; - } - styleLines.push(` ${key}: '${value}'`); - }); - - let exportString: string = 'export default styles;'; - - if (this.taskConfig.moduleExportName === '') { - exportString = 'export = styles;'; - } else if (this.taskConfig.moduleExportName) { - // exportString = `export const ${this.taskConfig.moduleExportName} = styles;`; - } - - return [ - 'const styles = {', - styleLines.join(`,${EOL}`), - '};', - '', - exportString - ].join(EOL); - } -} diff --git a/core-build/gulp-core-build-sass/src/index.ts b/core-build/gulp-core-build-sass/src/index.ts deleted file mode 100644 index fd764656820..00000000000 --- a/core-build/gulp-core-build-sass/src/index.ts +++ /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 { SassTask } from './SassTask'; - -/** - * @public - */ -export const sass: SassTask = new SassTask(); - -export default sass; diff --git a/core-build/gulp-core-build-sass/src/sass.schema.json b/core-build/gulp-core-build-sass/src/sass.schema.json deleted file mode 100644 index 4755e7ff225..00000000000 --- a/core-build/gulp-core-build-sass/src/sass.schema.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "title": "Sass Task Configuration", - "description": "Defines configuration for the SASS compilation task", - - "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" - }, - - "preamble": { - "title": "Preamble Text", - "description": "An optional parameter for text to include in the generated typescript file.", - "type": "string" - }, - - "postamble": { - "title": "Postamble Text", - "description": "An optional parameter for text to include at the end of the generated typescript file.", - "type": "string" - }, - - "sassMatch": { - "title": "Sass File Glob Pattern", - "description": "An array of glob patterns for locating SASS files.", - "type": "array" - }, - - "useCSSModules": { - "title": "Use CSS Modules", - "description": "If this option is specified, files ending with .module.sass or .module.scss extension will automatically generate a corresponding TypeScript file. All classes will be appended with a hash to help ensure uniqueness on a page. This file can be imported directly, and will contain an object describing the mangled class names.", - "type": "boolean" - }, - - "warnOnCssInvalidPropertyName ": { - "title": "Safety delver the CSS module compile warning", - "description": "If false, CSS module compile warning will be change verbose type to avoid build task exit with exitcode:1", - "type": "boolean" - }, - - "moduleExportName": { - "title": "Defines the export name for the styles", - "description": "If this option is specified, module css will be exported using the name provided. If an empty value is specified, the styles will be exported using 'export =', rather than a named export. By default we use the 'default' export name.", - "type": "string", - "pattern": "^[a-zA-Z][a-zA-Z0-9]*$" - }, - - "dropCssFiles": { - "title": "Create CSS Files", - "description": "If true, we will generate a CSS in the lib folder. If false, the CSS is directly embedded into the TypeScript file", - "type": "boolean" - } - } -} diff --git a/core-build/gulp-core-build-sass/src/test/CSSModules.test.ts b/core-build/gulp-core-build-sass/src/test/CSSModules.test.ts deleted file mode 100644 index 8b16897a927..00000000000 --- a/core-build/gulp-core-build-sass/src/test/CSSModules.test.ts +++ /dev/null @@ -1,90 +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 CSSModules from '../CSSModules'; - -interface IScopedNameArgs { - name: string; - fileName: string; - css: string; -} - -interface ITestCSSModules { - testGenerateScopedName(name: string, fileName: string, css: string): string; -} - -class TestCSSModules extends CSSModules { - public testGenerateScopedName(name: string, fileName: string, css: string) - : string { - return this.generateScopedName(name, fileName, css); - } -} - -test('will generate different hashes for different content', () => { - const version1: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Sally', 'src', 'main.sass'), - css: 'color: blue;' - }; - const version2: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Sally', 'src', 'main.sass'), - css: 'color: pink;' - }; - const cssModules: ITestCSSModules = new TestCSSModules(); - const output1: string = cssModules.testGenerateScopedName( - version1.name, version1.fileName, version1.css - ); - const output2: string = cssModules.testGenerateScopedName( - version2.name, version2.fileName, version2.css - ); - expect(output1).not.toBe(output2); -}); - -test('will generate the same hash in a different root path', () => { - const version1: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Sally', 'src', 'main.sass'), - css: 'color: blue;' - }; - const version2: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Suzan', 'workspace', 'src', 'main.sass'), - css: 'color: blue;' - }; - const cssModules: ITestCSSModules = new TestCSSModules( - path.join(__dirname, 'Sally') - ); - const output1: string = cssModules.testGenerateScopedName( - version1.name, version1.fileName, version1.css - ); - const cssModules2: ITestCSSModules = new TestCSSModules( - path.join(__dirname, 'Suzan', 'workspace') - ); - const output2: string = cssModules2.testGenerateScopedName( - version2.name, version2.fileName, version2.css - ); - expect(output1).toBe(output2); -}); - -test('will generate a different hash in a different src path', () => { - const version1: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Sally', 'src', 'main.sass'), - css: 'color: blue;' - }; - const version2: IScopedNameArgs = { - name: 'Button', - fileName: path.join(__dirname, 'Sally', 'src', 'lib', 'main.sass'), - css: 'color: blue;' - }; - const cssModules: ITestCSSModules = new TestCSSModules(); - const output1: string = cssModules.testGenerateScopedName( - version1.name, version1.fileName, version1.css - ); - const output2: string = cssModules.testGenerateScopedName( - version2.name, version2.fileName, version2.css - ); - expect(output1).not.toBe(output2); -}); diff --git a/core-build/gulp-core-build-sass/tsconfig.json b/core-build/gulp-core-build-sass/tsconfig.json deleted file mode 100644 index 47e75f9f181..00000000000 --- a/core-build/gulp-core-build-sass/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "jest" - ] - } -} diff --git a/core-build/gulp-core-build-serve/.eslintrc.js b/core-build/gulp-core-build-serve/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/gulp-core-build-serve/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/gulp-core-build-serve/.npmignore b/core-build/gulp-core-build-serve/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build-serve/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build-serve/CHANGELOG.json b/core-build/gulp-core-build-serve/CHANGELOG.json deleted file mode 100644 index 2b59a41e303..00000000000 --- a/core-build/gulp-core-build-serve/CHANGELOG.json +++ /dev/null @@ -1,3879 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-serve", - "entries": [ - { - "version": "3.7.3", - "tag": "@microsoft/gulp-core-build-serve_v3.7.3", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "3.7.2", - "tag": "@microsoft/gulp-core-build-serve_v3.7.2", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - }, - { - "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" from `0.2.1` to `0.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" - } - ] - } - }, - { - "version": "3.7.1", - "tag": "@microsoft/gulp-core-build-serve_v3.7.1", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" - }, - { - "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.2` to `0.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.3` to `6.4.4`" - } - ] - } - }, - { - "version": "3.7.0", - "tag": "@microsoft/gulp-core-build-serve_v3.7.0", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "minor": [ - { - "comment": "Extract debug certificate logic into separate package." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" from `0.1.0` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.2` to `6.4.3`" - } - ] - } - }, - { - "version": "3.6.2", - "tag": "@microsoft/gulp-core-build-serve_v3.6.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.1` to `0.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.1` to `6.4.2`" - } - ] - } - }, - { - "version": "3.6.1", - "tag": "@microsoft/gulp-core-build-serve_v3.6.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.0` to `6.4.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "3.6.0", - "tag": "@microsoft/gulp-core-build-serve_v3.6.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.15` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.16` to `6.4.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "3.5.23", - "tag": "@microsoft/gulp-core-build-serve_v3.5.23", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.15` to `6.3.16`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.5.22", - "tag": "@microsoft/gulp-core-build-serve_v3.5.22", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.13` to `0.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.14` to `6.3.15`" - } - ] - } - }, - { - "version": "3.5.21", - "tag": "@microsoft/gulp-core-build-serve_v3.5.21", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.13` to `6.3.14`" - } - ] - } - }, - { - "version": "3.5.20", - "tag": "@microsoft/gulp-core-build-serve_v3.5.20", - "date": "Thu, 09 Jan 2020 06:44:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.12` to `6.3.13`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.5.19", - "tag": "@microsoft/gulp-core-build-serve_v3.5.19", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.11` to `6.3.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "3.5.18", - "tag": "@microsoft/gulp-core-build-serve_v3.5.18", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.10` to `6.3.11`" - } - ] - } - }, - { - "version": "3.5.17", - "tag": "@microsoft/gulp-core-build-serve_v3.5.17", - "date": "Tue, 03 Dec 2019 03:17:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.9` to `0.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.9` to `6.3.10`" - } - ] - } - }, - { - "version": "3.5.16", - "tag": "@microsoft/gulp-core-build-serve_v3.5.16", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.8` to `0.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.8` to `6.3.9`" - } - ] - } - }, - { - "version": "3.5.15", - "tag": "@microsoft/gulp-core-build-serve_v3.5.15", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.7` to `0.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.7` to `6.3.8`" - } - ] - } - }, - { - "version": "3.5.14", - "tag": "@microsoft/gulp-core-build-serve_v3.5.14", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.6` to `0.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.6` to `6.3.7`" - } - ] - } - }, - { - "version": "3.5.13", - "tag": "@microsoft/gulp-core-build-serve_v3.5.13", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.5` to `6.3.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.5.12", - "tag": "@microsoft/gulp-core-build-serve_v3.5.12", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.4` to `0.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.4` to `6.3.5`" - } - ] - } - }, - { - "version": "3.5.11", - "tag": "@microsoft/gulp-core-build-serve_v3.5.11", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.3` to `6.3.4`" - } - ] - } - }, - { - "version": "3.5.10", - "tag": "@microsoft/gulp-core-build-serve_v3.5.10", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.2` to `6.3.3`" - } - ] - } - }, - { - "version": "3.5.9", - "tag": "@microsoft/gulp-core-build-serve_v3.5.9", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.1` to `6.3.2`" - } - ] - } - }, - { - "version": "3.5.8", - "tag": "@microsoft/gulp-core-build-serve_v3.5.8", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.0` to `6.3.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.5.7", - "tag": "@microsoft/gulp-core-build-serve_v3.5.7", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.6` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.6` to `6.3.0`" - } - ] - } - }, - { - "version": "3.5.6", - "tag": "@microsoft/gulp-core-build-serve_v3.5.6", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.5` to `6.2.6`" - } - ] - } - }, - { - "version": "3.5.5", - "tag": "@microsoft/gulp-core-build-serve_v3.5.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.4` to `6.2.5`" - } - ] - } - }, - { - "version": "3.5.4", - "tag": "@microsoft/gulp-core-build-serve_v3.5.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.3` to `6.2.4`" - } - ] - } - }, - { - "version": "3.5.3", - "tag": "@microsoft/gulp-core-build-serve_v3.5.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.2` to `6.2.3`" - } - ] - } - }, - { - "version": "3.5.2", - "tag": "@microsoft/gulp-core-build-serve_v3.5.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.1` to `0.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.1` to `6.2.2`" - } - ] - } - }, - { - "version": "3.5.1", - "tag": "@microsoft/gulp-core-build-serve_v3.5.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.0` to `6.2.1`" - } - ] - } - }, - { - "version": "3.5.0", - "tag": "@microsoft/gulp-core-build-serve_v3.5.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.24` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.11` to `6.2.0`" - } - ] - } - }, - { - "version": "3.4.11", - "tag": "@microsoft/gulp-core-build-serve_v3.4.11", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.23` to `0.1.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.10` to `6.1.11`" - } - ] - } - }, - { - "version": "3.4.10", - "tag": "@microsoft/gulp-core-build-serve_v3.4.10", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.22` to `0.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.9` to `6.1.10`" - } - ] - } - }, - { - "version": "3.4.9", - "tag": "@microsoft/gulp-core-build-serve_v3.4.9", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.21` to `0.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.8` to `6.1.9`" - } - ] - } - }, - { - "version": "3.4.8", - "tag": "@microsoft/gulp-core-build-serve_v3.4.8", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.20` to `0.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.7` to `6.1.8`" - } - ] - } - }, - { - "version": "3.4.7", - "tag": "@microsoft/gulp-core-build-serve_v3.4.7", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.19` to `0.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.6` to `6.1.7`" - } - ] - } - }, - { - "version": "3.4.6", - "tag": "@microsoft/gulp-core-build-serve_v3.4.6", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.18` to `0.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.5` to `6.1.6`" - } - ] - } - }, - { - "version": "3.4.5", - "tag": "@microsoft/gulp-core-build-serve_v3.4.5", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.4` to `6.1.5`" - } - ] - } - }, - { - "version": "3.4.4", - "tag": "@microsoft/gulp-core-build-serve_v3.4.4", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.3` to `6.1.4`" - } - ] - } - }, - { - "version": "3.4.3", - "tag": "@microsoft/gulp-core-build-serve_v3.4.3", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.2` to `6.1.3`" - } - ] - } - }, - { - "version": "3.4.2", - "tag": "@microsoft/gulp-core-build-serve_v3.4.2", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.1` to `6.1.2`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/gulp-core-build-serve_v3.4.1", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.0` to `6.1.1`" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/gulp-core-build-serve_v3.4.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.74` to `6.1.0`" - } - ] - } - }, - { - "version": "3.3.48", - "tag": "@microsoft/gulp-core-build-serve_v3.3.48", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.73` to `6.0.74`" - } - ] - } - }, - { - "version": "3.3.47", - "tag": "@microsoft/gulp-core-build-serve_v3.3.47", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.72` to `6.0.73`" - } - ] - } - }, - { - "version": "3.3.46", - "tag": "@microsoft/gulp-core-build-serve_v3.3.46", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.23` to `0.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.71` to `6.0.72`" - } - ] - } - }, - { - "version": "3.3.45", - "tag": "@microsoft/gulp-core-build-serve_v3.3.45", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.22` to `0.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.70` to `6.0.71`" - } - ] - } - }, - { - "version": "3.3.44", - "tag": "@microsoft/gulp-core-build-serve_v3.3.44", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.21` to `0.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.69` to `6.0.70`" - } - ] - } - }, - { - "version": "3.3.43", - "tag": "@microsoft/gulp-core-build-serve_v3.3.43", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.20` to `0.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.68` to `6.0.69`" - } - ] - } - }, - { - "version": "3.3.42", - "tag": "@microsoft/gulp-core-build-serve_v3.3.42", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.19` to `0.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.67` to `6.0.68`" - } - ] - } - }, - { - "version": "3.3.41", - "tag": "@microsoft/gulp-core-build-serve_v3.3.41", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.18` to `0.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.66` to `6.0.67`" - } - ] - } - }, - { - "version": "3.3.40", - "tag": "@microsoft/gulp-core-build-serve_v3.3.40", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.17` to `0.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.65` to `6.0.66`" - } - ] - } - }, - { - "version": "3.3.39", - "tag": "@microsoft/gulp-core-build-serve_v3.3.39", - "date": "Thu, 06 Jun 2019 22:33:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.16` to `0.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.64` to `6.0.65`" - } - ] - } - }, - { - "version": "3.3.38", - "tag": "@microsoft/gulp-core-build-serve_v3.3.38", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.15` to `0.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.63` to `6.0.64`" - } - ] - } - }, - { - "version": "3.3.37", - "tag": "@microsoft/gulp-core-build-serve_v3.3.37", - "date": "Tue, 04 Jun 2019 05:51:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.62` to `6.0.63`" - } - ] - } - }, - { - "version": "3.3.36", - "tag": "@microsoft/gulp-core-build-serve_v3.3.36", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.13` to `0.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.61` to `6.0.62`" - } - ] - } - }, - { - "version": "3.3.35", - "tag": "@microsoft/gulp-core-build-serve_v3.3.35", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.60` to `6.0.61`" - } - ] - } - }, - { - "version": "3.3.34", - "tag": "@microsoft/gulp-core-build-serve_v3.3.34", - "date": "Mon, 06 May 2019 20:46:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.59` to `6.0.60`" - } - ] - } - }, - { - "version": "3.3.33", - "tag": "@microsoft/gulp-core-build-serve_v3.3.33", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.10` to `0.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.58` to `6.0.59`" - } - ] - } - }, - { - "version": "3.3.32", - "tag": "@microsoft/gulp-core-build-serve_v3.3.32", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.9` to `0.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.57` to `6.0.58`" - } - ] - } - }, - { - "version": "3.3.31", - "tag": "@microsoft/gulp-core-build-serve_v3.3.31", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.8` to `0.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.56` to `6.0.57`" - } - ] - } - }, - { - "version": "3.3.30", - "tag": "@microsoft/gulp-core-build-serve_v3.3.30", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.7` to `0.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.55` to `6.0.56`" - } - ] - } - }, - { - "version": "3.3.29", - "tag": "@microsoft/gulp-core-build-serve_v3.3.29", - "date": "Fri, 12 Apr 2019 06:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.6` to `0.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.54` to `6.0.55`" - } - ] - } - }, - { - "version": "3.3.28", - "tag": "@microsoft/gulp-core-build-serve_v3.3.28", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.53` to `6.0.54`" - } - ] - } - }, - { - "version": "3.3.27", - "tag": "@microsoft/gulp-core-build-serve_v3.3.27", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.4` to `0.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.52` to `6.0.53`" - } - ] - } - }, - { - "version": "3.3.26", - "tag": "@microsoft/gulp-core-build-serve_v3.3.26", - "date": "Mon, 08 Apr 2019 19:12:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.51` to `6.0.52`" - } - ] - } - }, - { - "version": "3.3.25", - "tag": "@microsoft/gulp-core-build-serve_v3.3.25", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.50` to `6.0.51`" - } - ] - } - }, - { - "version": "3.3.24", - "tag": "@microsoft/gulp-core-build-serve_v3.3.24", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.49` to `6.0.50`" - } - ] - } - }, - { - "version": "3.3.23", - "tag": "@microsoft/gulp-core-build-serve_v3.3.23", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.48` to `6.0.49`" - } - ] - } - }, - { - "version": "3.3.22", - "tag": "@microsoft/gulp-core-build-serve_v3.3.22", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.47` to `6.0.48`" - } - ] - } - }, - { - "version": "3.3.21", - "tag": "@microsoft/gulp-core-build-serve_v3.3.21", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.46` to `6.0.47`" - } - ] - } - }, - { - "version": "3.3.20", - "tag": "@microsoft/gulp-core-build-serve_v3.3.20", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.45` to `6.0.46`" - } - ] - } - }, - { - "version": "3.3.19", - "tag": "@microsoft/gulp-core-build-serve_v3.3.19", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.44` to `6.0.45`" - } - ] - } - }, - { - "version": "3.3.18", - "tag": "@microsoft/gulp-core-build-serve_v3.3.18", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.43` to `6.0.44`" - } - ] - } - }, - { - "version": "3.3.17", - "tag": "@microsoft/gulp-core-build-serve_v3.3.17", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.42` to `6.0.43`" - } - ] - } - }, - { - "version": "3.3.16", - "tag": "@microsoft/gulp-core-build-serve_v3.3.16", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.41` to `6.0.42`" - } - ] - } - }, - { - "version": "3.3.15", - "tag": "@microsoft/gulp-core-build-serve_v3.3.15", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.40` to `6.0.41`" - } - ] - } - }, - { - "version": "3.3.14", - "tag": "@microsoft/gulp-core-build-serve_v3.3.14", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.39` to `6.0.40`" - } - ] - } - }, - { - "version": "3.3.13", - "tag": "@microsoft/gulp-core-build-serve_v3.3.13", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.38` to `6.0.39`" - } - ] - } - }, - { - "version": "3.3.12", - "tag": "@microsoft/gulp-core-build-serve_v3.3.12", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.37` to `6.0.38`" - } - ] - } - }, - { - "version": "3.3.11", - "tag": "@microsoft/gulp-core-build-serve_v3.3.11", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.36` to `6.0.37`" - } - ] - } - }, - { - "version": "3.3.10", - "tag": "@microsoft/gulp-core-build-serve_v3.3.10", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.35` to `6.0.36`" - } - ] - } - }, - { - "version": "3.3.9", - "tag": "@microsoft/gulp-core-build-serve_v3.3.9", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "patch": [ - { - "comment": "Fix UntrustCertTask imports" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.34` to `6.0.35`" - } - ] - } - }, - { - "version": "3.3.8", - "tag": "@microsoft/gulp-core-build-serve_v3.3.8", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.33` to `6.0.34`" - } - ] - } - }, - { - "version": "3.3.7", - "tag": "@microsoft/gulp-core-build-serve_v3.3.7", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.1` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.32` to `6.0.33`" - } - ] - } - }, - { - "version": "3.3.6", - "tag": "@microsoft/gulp-core-build-serve_v3.3.6", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.31` to `6.0.32`" - } - ] - } - }, - { - "version": "3.3.5", - "tag": "@microsoft/gulp-core-build-serve_v3.3.5", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.30` to `6.0.31`" - } - ] - } - }, - { - "version": "3.3.4", - "tag": "@microsoft/gulp-core-build-serve_v3.3.4", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.29` to `6.0.30`" - } - ] - } - }, - { - "version": "3.3.3", - "tag": "@microsoft/gulp-core-build-serve_v3.3.3", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.28` to `6.0.29`" - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/gulp-core-build-serve_v3.3.2", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.9.0` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.27` to `6.0.28`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/gulp-core-build-serve_v3.3.1", - "date": "Wed, 30 Jan 2019 20:49:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.26` to `6.0.27`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/gulp-core-build-serve_v3.3.0", - "date": "Mon, 21 Jan 2019 17:04:11 GMT", - "comments": { - "minor": [ - { - "comment": "Added rootFolder option to adjust base folder for gulp serve" - } - ] - } - }, - { - "version": "3.2.94", - "tag": "@microsoft/gulp-core-build-serve_v3.2.94", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.25` to `6.0.26`" - } - ] - } - }, - { - "version": "3.2.93", - "tag": "@microsoft/gulp-core-build-serve_v3.2.93", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.24` to `6.0.25`" - } - ] - } - }, - { - "version": "3.2.92", - "tag": "@microsoft/gulp-core-build-serve_v3.2.92", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.3` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.23` to `6.0.24`" - } - ] - } - }, - { - "version": "3.2.91", - "tag": "@microsoft/gulp-core-build-serve_v3.2.91", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.22` to `6.0.23`" - } - ] - } - }, - { - "version": "3.2.90", - "tag": "@microsoft/gulp-core-build-serve_v3.2.90", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.21` to `6.0.22`" - } - ] - } - }, - { - "version": "3.2.89", - "tag": "@microsoft/gulp-core-build-serve_v3.2.89", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.20` to `6.0.21`" - } - ] - } - }, - { - "version": "3.2.88", - "tag": "@microsoft/gulp-core-build-serve_v3.2.88", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.19` to `6.0.20`" - } - ] - } - }, - { - "version": "3.2.87", - "tag": "@microsoft/gulp-core-build-serve_v3.2.87", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.18` to `6.0.19`" - } - ] - } - }, - { - "version": "3.2.86", - "tag": "@microsoft/gulp-core-build-serve_v3.2.86", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.1` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.17` to `6.0.18`" - } - ] - } - }, - { - "version": "3.2.85", - "tag": "@microsoft/gulp-core-build-serve_v3.2.85", - "date": "Fri, 30 Nov 2018 23:34:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.16` to `6.0.17`" - } - ] - } - }, - { - "version": "3.2.84", - "tag": "@microsoft/gulp-core-build-serve_v3.2.84", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.15` to `6.0.16`" - } - ] - } - }, - { - "version": "3.2.83", - "tag": "@microsoft/gulp-core-build-serve_v3.2.83", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.14` to `6.0.15`" - } - ] - } - }, - { - "version": "3.2.82", - "tag": "@microsoft/gulp-core-build-serve_v3.2.82", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.13` to `6.0.14`" - } - ] - } - }, - { - "version": "3.2.81", - "tag": "@microsoft/gulp-core-build-serve_v3.2.81", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.6.0` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.12` to `6.0.13`" - } - ] - } - }, - { - "version": "3.2.80", - "tag": "@microsoft/gulp-core-build-serve_v3.2.80", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.2` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.11` to `6.0.12`" - } - ] - } - }, - { - "version": "3.2.79", - "tag": "@microsoft/gulp-core-build-serve_v3.2.79", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.10` to `6.0.11`" - } - ] - } - }, - { - "version": "3.2.78", - "tag": "@microsoft/gulp-core-build-serve_v3.2.78", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.9` to `6.0.10`" - } - ] - } - }, - { - "version": "3.2.77", - "tag": "@microsoft/gulp-core-build-serve_v3.2.77", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.8` to `6.0.9`" - } - ] - } - }, - { - "version": "3.2.76", - "tag": "@microsoft/gulp-core-build-serve_v3.2.76", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.7` to `6.0.8`" - } - ] - } - }, - { - "version": "3.2.75", - "tag": "@microsoft/gulp-core-build-serve_v3.2.75", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.6` to `6.0.7`" - } - ] - } - }, - { - "version": "3.2.74", - "tag": "@microsoft/gulp-core-build-serve_v3.2.74", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.5` to `6.0.6`" - } - ] - } - }, - { - "version": "3.2.73", - "tag": "@microsoft/gulp-core-build-serve_v3.2.73", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.4` to `6.0.5`" - } - ] - } - }, - { - "version": "3.2.72", - "tag": "@microsoft/gulp-core-build-serve_v3.2.72", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.3` to `6.0.4`" - } - ] - } - }, - { - "version": "3.2.71", - "tag": "@microsoft/gulp-core-build-serve_v3.2.71", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.2` to `6.0.3`" - } - ] - } - }, - { - "version": "3.2.70", - "tag": "@microsoft/gulp-core-build-serve_v3.2.70", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.1` to `6.0.2`" - } - ] - } - }, - { - "version": "3.2.69", - "tag": "@microsoft/gulp-core-build-serve_v3.2.69", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.0` to `6.0.1`" - } - ] - } - }, - { - "version": "3.2.68", - "tag": "@microsoft/gulp-core-build-serve_v3.2.68", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.26` to `6.0.0`" - } - ] - } - }, - { - "version": "3.2.67", - "tag": "@microsoft/gulp-core-build-serve_v3.2.67", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.4.0` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.25` to `5.0.26`" - } - ] - } - }, - { - "version": "3.2.66", - "tag": "@microsoft/gulp-core-build-serve_v3.2.66", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.24` to `5.0.25`" - } - ] - } - }, - { - "version": "3.2.65", - "tag": "@microsoft/gulp-core-build-serve_v3.2.65", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.1` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.23` to `5.0.24`" - } - ] - } - }, - { - "version": "3.2.64", - "tag": "@microsoft/gulp-core-build-serve_v3.2.64", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.22` to `5.0.23`" - } - ] - } - }, - { - "version": "3.2.63", - "tag": "@microsoft/gulp-core-build-serve_v3.2.63", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.21` to `5.0.22`" - } - ] - } - }, - { - "version": "3.2.62", - "tag": "@microsoft/gulp-core-build-serve_v3.2.62", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.20` to `5.0.21`" - } - ] - } - }, - { - "version": "3.2.61", - "tag": "@microsoft/gulp-core-build-serve_v3.2.61", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.19` to `5.0.20`" - } - ] - } - }, - { - "version": "3.2.60", - "tag": "@microsoft/gulp-core-build-serve_v3.2.60", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.18` to `5.0.19`" - } - ] - } - }, - { - "version": "3.2.59", - "tag": "@microsoft/gulp-core-build-serve_v3.2.59", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.17` to `5.0.18`" - } - ] - } - }, - { - "version": "3.2.58", - "tag": "@microsoft/gulp-core-build-serve_v3.2.58", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.2.0` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.16` to `5.0.17`" - } - ] - } - }, - { - "version": "3.2.57", - "tag": "@microsoft/gulp-core-build-serve_v3.2.57", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.1.0` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.15` to `5.0.16`" - } - ] - } - }, - { - "version": "3.2.56", - "tag": "@microsoft/gulp-core-build-serve_v3.2.56", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.1` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.14` to `5.0.15`" - } - ] - } - }, - { - "version": "3.2.55", - "tag": "@microsoft/gulp-core-build-serve_v3.2.55", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.13` to `5.0.14`" - } - ] - } - }, - { - "version": "3.2.54", - "tag": "@microsoft/gulp-core-build-serve_v3.2.54", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.12` to `5.0.13`" - } - ] - } - }, - { - "version": "3.2.53", - "tag": "@microsoft/gulp-core-build-serve_v3.2.53", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.11` to `5.0.12`" - } - ] - } - }, - { - "version": "3.2.52", - "tag": "@microsoft/gulp-core-build-serve_v3.2.52", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.10` to `5.0.11`" - } - ] - } - }, - { - "version": "3.2.51", - "tag": "@microsoft/gulp-core-build-serve_v3.2.51", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.9` to `5.0.10`" - } - ] - } - }, - { - "version": "3.2.50", - "tag": "@microsoft/gulp-core-build-serve_v3.2.50", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.8` to `5.0.9`" - } - ] - } - }, - { - "version": "3.2.49", - "tag": "@microsoft/gulp-core-build-serve_v3.2.49", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.7` to `5.0.8`" - } - ] - } - }, - { - "version": "3.2.48", - "tag": "@microsoft/gulp-core-build-serve_v3.2.48", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "3.2.47", - "tag": "@microsoft/gulp-core-build-serve_v3.2.47", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "3.2.46", - "tag": "@microsoft/gulp-core-build-serve_v3.2.46", - "date": "Mon, 03 Sep 2018 16:04:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "3.2.45", - "tag": "@microsoft/gulp-core-build-serve_v3.2.45", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "3.2.44", - "tag": "@microsoft/gulp-core-build-serve_v3.2.44", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - } - ] - } - }, - { - "version": "3.2.43", - "tag": "@microsoft/gulp-core-build-serve_v3.2.43", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "3.2.42", - "tag": "@microsoft/gulp-core-build-serve_v3.2.42", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.1` to `3.0.0`" - } - ] - } - }, - { - "version": "3.2.41", - "tag": "@microsoft/gulp-core-build-serve_v3.2.41", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.0` to `2.2.1`" - } - ] - } - }, - { - "version": "3.2.40", - "tag": "@microsoft/gulp-core-build-serve_v3.2.40", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.1` to `2.2.0`" - } - ] - } - }, - { - "version": "3.2.39", - "tag": "@microsoft/gulp-core-build-serve_v3.2.39", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.0` to `2.1.1`" - } - ] - } - }, - { - "version": "3.2.38", - "tag": "@microsoft/gulp-core-build-serve_v3.2.38", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.0.0` to `2.1.0`" - } - ] - } - }, - { - "version": "3.2.37", - "tag": "@microsoft/gulp-core-build-serve_v3.2.37", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade gulp-open to elimiante security warning" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - } - ] - } - }, - { - "version": "3.2.36", - "tag": "@microsoft/gulp-core-build-serve_v3.2.36", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.5.0` to `2.0.0`" - } - ] - } - }, - { - "version": "3.2.35", - "tag": "@microsoft/gulp-core-build-serve_v3.2.35", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.4.1` to `1.5.0`" - } - ] - } - }, - { - "version": "3.2.34", - "tag": "@microsoft/gulp-core-build-serve_v3.2.34", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - } - ] - } - }, - { - "version": "3.2.33", - "tag": "@microsoft/gulp-core-build-serve_v3.2.33", - "date": "Wed, 13 Jun 2018 16:05:21 GMT", - "comments": { - "patch": [ - { - "comment": "Pass the hostname from serve.json to gulpConnect.server()" - } - ] - } - }, - { - "version": "3.2.32", - "tag": "@microsoft/gulp-core-build-serve_v3.2.32", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - } - ] - } - }, - { - "version": "3.2.31", - "tag": "@microsoft/gulp-core-build-serve_v3.2.31", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - } - ] - } - }, - { - "version": "3.2.30", - "tag": "@microsoft/gulp-core-build-serve_v3.2.30", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - } - ] - } - }, - { - "version": "3.2.29", - "tag": "@microsoft/gulp-core-build-serve_v3.2.29", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - } - ] - } - }, - { - "version": "3.2.28", - "tag": "@microsoft/gulp-core-build-serve_v3.2.28", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - } - ] - } - }, - { - "version": "3.2.27", - "tag": "@microsoft/gulp-core-build-serve_v3.2.27", - "date": "Mon, 30 Apr 2018 21:04:44 GMT", - "comments": { - "patch": [ - { - "comment": "Internal refactoring to eliminate default exports" - } - ] - } - }, - { - "version": "3.2.26", - "tag": "@microsoft/gulp-core-build-serve_v3.2.26", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - } - ] - } - }, - { - "version": "3.2.25", - "tag": "@microsoft/gulp-core-build-serve_v3.2.25", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - } - ] - } - }, - { - "version": "3.2.24", - "tag": "@microsoft/gulp-core-build-serve_v3.2.24", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - } - ] - } - }, - { - "version": "3.2.23", - "tag": "@microsoft/gulp-core-build-serve_v3.2.23", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade colors to version ~1.2.1" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - } - ] - } - }, - { - "version": "3.2.22", - "tag": "@microsoft/gulp-core-build-serve_v3.2.22", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - } - ] - } - }, - { - "version": "3.2.21", - "tag": "@microsoft/gulp-core-build-serve_v3.2.21", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - } - ] - } - }, - { - "version": "3.2.20", - "tag": "@microsoft/gulp-core-build-serve_v3.2.20", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - } - ] - } - }, - { - "version": "3.2.19", - "tag": "@microsoft/gulp-core-build-serve_v3.2.19", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - } - ] - } - }, - { - "version": "3.2.18", - "tag": "@microsoft/gulp-core-build-serve_v3.2.18", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - } - ] - } - }, - { - "version": "3.2.17", - "tag": "@microsoft/gulp-core-build-serve_v3.2.17", - "date": "Fri, 23 Feb 2018 17:04:33 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade gulp-connect in order to remove the HTTP2/HTTPS workaround ." - } - ] - } - }, - { - "version": "3.2.16", - "tag": "@microsoft/gulp-core-build-serve_v3.2.16", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - } - ] - } - }, - { - "version": "3.2.15", - "tag": "@microsoft/gulp-core-build-serve_v3.2.15", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - } - ] - } - }, - { - "version": "3.2.14", - "tag": "@microsoft/gulp-core-build-serve_v3.2.14", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - } - ] - } - }, - { - "version": "3.2.13", - "tag": "@microsoft/gulp-core-build-serve_v3.2.13", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - } - ] - } - }, - { - "version": "3.2.12", - "tag": "@microsoft/gulp-core-build-serve_v3.2.12", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - } - ] - } - }, - { - "version": "3.2.11", - "tag": "@microsoft/gulp-core-build-serve_v3.2.11", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - } - ] - } - }, - { - "version": "3.2.10", - "tag": "@microsoft/gulp-core-build-serve_v3.2.10", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/gulp-core-build-serve_v3.2.9", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/gulp-core-build-serve_v3.2.8", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/gulp-core-build-serve_v3.2.7", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "patch": [ - { - "comment": "Replace gulp-util.colors with colors package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/gulp-core-build-serve_v3.2.6", - "date": "Sat, 20 Jan 2018 02:39:16 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue with gulp serve when serving via https on Node8" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/gulp-core-build-serve_v3.2.5", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/gulp-core-build-serve_v3.2.4", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/gulp-core-build-serve_v3.2.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/gulp-core-build-serve_v3.2.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/gulp-core-build-serve_v3.2.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build-serve_v3.2.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - } - ] - } - }, - { - "version": "3.1.24", - "tag": "@microsoft/gulp-core-build-serve_v3.1.24", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.6` to `3.3.7`" - } - ] - } - }, - { - "version": "3.1.23", - "tag": "@microsoft/gulp-core-build-serve_v3.1.23", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - } - ] - } - }, - { - "version": "3.1.22", - "tag": "@microsoft/gulp-core-build-serve_v3.1.22", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - } - ] - } - }, - { - "version": "3.1.21", - "tag": "@microsoft/gulp-core-build-serve_v3.1.21", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - } - ] - } - }, - { - "version": "3.1.20", - "tag": "@microsoft/gulp-core-build-serve_v3.1.20", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - } - ] - } - }, - { - "version": "3.1.19", - "tag": "@microsoft/gulp-core-build-serve_v3.1.19", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - } - ] - } - }, - { - "version": "3.1.18", - "tag": "@microsoft/gulp-core-build-serve_v3.1.18", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - } - ] - } - }, - { - "version": "3.1.17", - "tag": "@microsoft/gulp-core-build-serve_v3.1.17", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - } - ] - } - }, - { - "version": "3.1.16", - "tag": "@microsoft/gulp-core-build-serve_v3.1.16", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - } - ] - } - }, - { - "version": "3.1.15", - "tag": "@microsoft/gulp-core-build-serve_v3.1.15", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - } - ] - } - }, - { - "version": "3.1.14", - "tag": "@microsoft/gulp-core-build-serve_v3.1.14", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - } - ] - } - }, - { - "version": "3.1.13", - "tag": "@microsoft/gulp-core-build-serve_v3.1.13", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - } - ] - } - }, - { - "version": "3.1.12", - "tag": "@microsoft/gulp-core-build-serve_v3.1.12", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - } - ] - } - }, - { - "version": "3.1.11", - "tag": "@microsoft/gulp-core-build-serve_v3.1.11", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "3.1.10", - "tag": "@microsoft/gulp-core-build-serve_v3.1.10", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - } - ] - } - }, - { - "version": "3.1.9", - "tag": "@microsoft/gulp-core-build-serve_v3.1.9", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - } - ] - } - }, - { - "version": "3.1.8", - "tag": "@microsoft/gulp-core-build-serve_v3.1.8", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - } - ] - } - }, - { - "version": "3.1.7", - "tag": "@microsoft/gulp-core-build-serve_v3.1.7", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - } - ] - } - }, - { - "version": "3.1.6", - "tag": "@microsoft/gulp-core-build-serve_v3.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - } - ] - } - }, - { - "version": "3.1.5", - "tag": "@microsoft/gulp-core-build-serve_v3.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - } - ] - } - }, - { - "version": "3.1.4", - "tag": "@microsoft/gulp-core-build-serve_v3.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - } - ] - } - }, - { - "version": "3.1.3", - "tag": "@microsoft/gulp-core-build-serve_v3.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - } - ] - } - }, - { - "version": "3.1.2", - "tag": "@microsoft/gulp-core-build-serve_v3.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - } - ] - } - }, - { - "version": "3.1.1", - "tag": "@microsoft/gulp-core-build-serve_v3.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build-serve_v3.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - } - ] - } - }, - { - "version": "3.0.8", - "tag": "@microsoft/gulp-core-build-serve_v3.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - } - ] - } - }, - { - "version": "3.0.7", - "tag": "@microsoft/gulp-core-build-serve_v3.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - } - ] - } - }, - { - "version": "3.0.6", - "tag": "@microsoft/gulp-core-build-serve_v3.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - } - ] - } - }, - { - "version": "3.0.5", - "tag": "@microsoft/gulp-core-build-serve_v3.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - } - ] - } - }, - { - "version": "3.0.4", - "tag": "@microsoft/gulp-core-build-serve_v3.0.4", - "date": "Thu, 07 Sep 2017 00:11:11 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "4b7451b442c2078a96430f7a05caed37101aed52", - "comment": " Add $schema field to all schemas" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/gulp-core-build-serve_v3.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/gulp-core-build-serve_v3.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/gulp-core-build-serve_v3.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build-serve_v3.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - } - ] - } - }, - { - "version": "2.1.13", - "tag": "@microsoft/gulp-core-build-serve_v2.1.13", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - } - ] - } - }, - { - "version": "2.1.12", - "tag": "@microsoft/gulp-core-build-serve_v2.1.12", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - } - ] - } - }, - { - "version": "2.1.11", - "tag": "@microsoft/gulp-core-build-serve_v2.1.11", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - } - ] - } - }, - { - "version": "2.1.10", - "tag": "@microsoft/gulp-core-build-serve_v2.1.10", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - } - ] - } - }, - { - "version": "2.1.9", - "tag": "@microsoft/gulp-core-build-serve_v2.1.9", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - } - ] - } - }, - { - "version": "2.1.8", - "tag": "@microsoft/gulp-core-build-serve_v2.1.8", - "date": "Wed, 16 Aug 2017 23:16:55 GMT", - "comments": { - "patch": [ - { - "comment": "Publish" - } - ] - } - }, - { - "version": "2.1.7", - "tag": "@microsoft/gulp-core-build-serve_v2.1.7", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - } - ] - } - }, - { - "version": "2.1.6", - "tag": "@microsoft/gulp-core-build-serve_v2.1.6", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "patch": [ - { - "comment": "Allow the serve task to be extended with new configuration args." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.8.0` to `2.9.0`" - } - ] - } - }, - { - "version": "2.1.5", - "tag": "@microsoft/gulp-core-build-serve_v2.1.5", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - } - ] - } - }, - { - "version": "2.1.4", - "tag": "@microsoft/gulp-core-build-serve_v2.1.4", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.3", - "tag": "@microsoft/gulp-core-build-serve_v2.1.3", - "date": "Tue, 16 May 2017 00:01:03 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing an issue where the cert utility would fail if two certutils were on the PATH." - } - ] - } - }, - { - "version": "2.1.2", - "tag": "@microsoft/gulp-core-build-serve_v2.1.2", - "date": "Thu, 27 Apr 2017 13:03:03 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing the development certificate to have the subjectAltName property to work with new versions of browsers." - } - ] - } - }, - { - "version": "2.1.1", - "tag": "@microsoft/gulp-core-build-serve_v2.1.1", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/gulp-core-build-serve_v2.1.0", - "date": "Sat, 15 Apr 2017 01:03:33 GMT", - "comments": { - "minor": [ - { - "comment": "Allowing the hostname to be configured in gulp-core-build-serve." - } - ] - } - }, - { - "version": "2.0.4", - "tag": "@microsoft/gulp-core-build-serve_v2.0.4", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.3", - "tag": "@microsoft/gulp-core-build-serve_v2.0.3", - "date": "Tue, 31 Jan 2017 20:32:37 GMT", - "comments": { - "patch": [ - { - "comment": "Make loadSchema public instead of protected." - } - ] - } - }, - { - "version": "2.0.2", - "tag": "@microsoft/gulp-core-build-serve_v2.0.2", - "date": "Tue, 31 Jan 2017 01:55:09 GMT", - "comments": { - "patch": [ - { - "comment": "Introduce schema for ServeTask" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build-serve_v2.0.1", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build-serve/CHANGELOG.md b/core-build/gulp-core-build-serve/CHANGELOG.md deleted file mode 100644 index 2ae30508bc1..00000000000 --- a/core-build/gulp-core-build-serve/CHANGELOG.md +++ /dev/null @@ -1,1277 +0,0 @@ -# Change Log - @microsoft/gulp-core-build-serve - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 3.7.3 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 3.7.2 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 3.7.1 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 3.7.0 -Fri, 24 Jan 2020 00:27:39 GMT - -### Minor changes - -- Extract debug certificate logic into separate package. - -## 3.6.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 3.6.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 3.6.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 3.5.23 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 3.5.22 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 3.5.21 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 3.5.20 -Thu, 09 Jan 2020 06:44:13 GMT - -*Version update only* - -## 3.5.19 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 3.5.18 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 3.5.17 -Tue, 03 Dec 2019 03:17:44 GMT - -*Version update only* - -## 3.5.16 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 3.5.15 -Wed, 20 Nov 2019 06:14:28 GMT - -*Version update only* - -## 3.5.14 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 3.5.13 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 3.5.12 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 3.5.11 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 3.5.10 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 3.5.9 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 3.5.8 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 3.5.7 -Mon, 21 Oct 2019 05:22:43 GMT - -*Version update only* - -## 3.5.6 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 3.5.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 3.5.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 3.5.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 3.5.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 3.5.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 3.5.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 3.4.11 -Fri, 20 Sep 2019 21:27:22 GMT - -*Version update only* - -## 3.4.10 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 3.4.9 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 3.4.8 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 3.4.7 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 3.4.6 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 3.4.5 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 3.4.4 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 3.4.3 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 3.4.2 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 3.4.1 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 3.4.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2 - -## 3.3.48 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 3.3.47 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 3.3.46 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 3.3.45 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 3.3.44 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 3.3.43 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 3.3.42 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 3.3.41 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 3.3.40 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 3.3.39 -Thu, 06 Jun 2019 22:33:36 GMT - -*Version update only* - -## 3.3.38 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 3.3.37 -Tue, 04 Jun 2019 05:51:54 GMT - -*Version update only* - -## 3.3.36 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 3.3.35 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 3.3.34 -Mon, 06 May 2019 20:46:22 GMT - -*Version update only* - -## 3.3.33 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 3.3.32 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 3.3.31 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 3.3.30 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 3.3.29 -Fri, 12 Apr 2019 06:13:17 GMT - -*Version update only* - -## 3.3.28 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 3.3.27 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 3.3.26 -Mon, 08 Apr 2019 19:12:52 GMT - -*Version update only* - -## 3.3.25 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 3.3.24 -Fri, 05 Apr 2019 04:16:17 GMT - -*Version update only* - -## 3.3.23 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 3.3.22 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 3.3.21 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 3.3.20 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 3.3.19 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 3.3.18 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 3.3.17 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 3.3.16 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 3.3.15 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 3.3.14 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 3.3.13 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 3.3.12 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 3.3.11 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 3.3.10 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 3.3.9 -Tue, 05 Mar 2019 17:13:11 GMT - -### Patches - -- Fix UntrustCertTask imports - -## 3.3.8 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 3.3.7 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 3.3.6 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 3.3.5 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 3.3.4 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 3.3.3 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 3.3.2 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 3.3.1 -Wed, 30 Jan 2019 20:49:12 GMT - -*Version update only* - -## 3.3.0 -Mon, 21 Jan 2019 17:04:11 GMT - -### Minor changes - -- Added rootFolder option to adjust base folder for gulp serve - -## 3.2.94 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 3.2.93 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 3.2.92 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 3.2.91 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 3.2.90 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 3.2.89 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 3.2.88 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 3.2.87 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 3.2.86 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 3.2.85 -Fri, 30 Nov 2018 23:34:58 GMT - -*Version update only* - -## 3.2.84 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 3.2.83 -Thu, 29 Nov 2018 00:35:38 GMT - -*Version update only* - -## 3.2.82 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 3.2.81 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 3.2.80 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 3.2.79 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 3.2.78 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 3.2.77 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 3.2.76 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 3.2.75 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 3.2.74 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 3.2.73 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 3.2.72 -Wed, 31 Oct 2018 21:17:50 GMT - -*Version update only* - -## 3.2.71 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 3.2.70 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 3.2.69 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 3.2.68 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 3.2.67 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 3.2.66 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 3.2.65 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 3.2.64 -Thu, 18 Oct 2018 05:30:14 GMT - -*Version update only* - -## 3.2.63 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 3.2.62 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 3.2.61 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 3.2.60 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 3.2.59 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 3.2.58 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 3.2.57 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 3.2.56 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 3.2.55 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 3.2.54 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 3.2.53 -Mon, 24 Sep 2018 16:04:28 GMT - -*Version update only* - -## 3.2.52 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 3.2.51 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 3.2.50 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 3.2.49 -Mon, 10 Sep 2018 23:23:01 GMT - -*Version update only* - -## 3.2.48 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 3.2.47 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 3.2.46 -Mon, 03 Sep 2018 16:04:45 GMT - -*Version update only* - -## 3.2.45 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 3.2.44 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 3.2.43 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 3.2.42 -Wed, 29 Aug 2018 06:36:50 GMT - -*Version update only* - -## 3.2.41 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 3.2.40 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 3.2.39 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 3.2.38 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 3.2.37 -Tue, 07 Aug 2018 22:27:31 GMT - -### Patches - -- Upgrade gulp-open to elimiante security warning - -## 3.2.36 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 3.2.35 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 3.2.34 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 3.2.33 -Wed, 13 Jun 2018 16:05:21 GMT - -### Patches - -- Pass the hostname from serve.json to gulpConnect.server() - -## 3.2.32 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 3.2.31 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 3.2.30 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 3.2.29 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 3.2.28 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 3.2.27 -Mon, 30 Apr 2018 21:04:44 GMT - -### Patches - -- Internal refactoring to eliminate default exports - -## 3.2.26 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 3.2.25 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 3.2.24 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 3.2.23 -Fri, 23 Mar 2018 00:34:53 GMT - -### Patches - -- Upgrade colors to version ~1.2.1 - -## 3.2.22 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 3.2.21 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 3.2.20 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 3.2.19 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 3.2.18 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 3.2.17 -Fri, 23 Feb 2018 17:04:33 GMT - -### Patches - -- Upgrade gulp-connect in order to remove the HTTP2/HTTPS workaround . - -## 3.2.16 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 3.2.15 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 3.2.14 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 3.2.13 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 3.2.12 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.2.11 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.2.10 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 3.2.9 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 3.2.8 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 3.2.7 -Tue, 23 Jan 2018 17:05:28 GMT - -### Patches - -- Replace gulp-util.colors with colors package - -## 3.2.6 -Sat, 20 Jan 2018 02:39:16 GMT - -### Patches - -- Fix an issue with gulp serve when serving via https on Node8 - -## 3.2.5 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 3.2.4 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 3.2.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 3.2.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 3.2.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 3.2.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 3.1.24 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 3.1.23 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 3.1.22 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 3.1.21 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 3.1.20 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 3.1.19 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 3.1.18 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 3.1.17 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 3.1.16 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 3.1.15 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 3.1.14 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 3.1.13 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 3.1.12 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 3.1.11 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.1.10 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 3.1.9 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 3.1.8 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 3.1.7 -Tue, 24 Oct 2017 18:17:12 GMT - -*Version update only* - -## 3.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 3.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 3.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 3.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 3.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 3.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 3.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 3.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 3.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 3.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -*Version update only* - -## 3.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 3.0.4 -Thu, 07 Sep 2017 00:11:11 GMT - -### Patches - -- Add $schema field to all schemas - -## 3.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 3.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 3.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 3.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 2.1.13 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 2.1.12 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 2.1.11 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 2.1.10 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 2.1.9 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 2.1.8 -Wed, 16 Aug 2017 23:16:55 GMT - -### Patches - -- Publish - -## 2.1.7 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 2.1.6 -Fri, 11 Aug 2017 21:44:05 GMT - -### Patches - -- Allow the serve task to be extended with new configuration args. - -## 2.1.5 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 2.1.4 -Tue, 25 Jul 2017 20:03:31 GMT - -### Patches - -- Upgrade to TypeScript 2.4 - -## 2.1.3 -Tue, 16 May 2017 00:01:03 GMT - -### Patches - -- Fixing an issue where the cert utility would fail if two certutils were on the PATH. - -## 2.1.2 -Thu, 27 Apr 2017 13:03:03 GMT - -### Patches - -- Fixing the development certificate to have the subjectAltName property to work with new versions of browsers. - -## 2.1.1 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 2.1.0 -Sat, 15 Apr 2017 01:03:33 GMT - -### Minor changes - -- Allowing the hostname to be configured in gulp-core-build-serve. - -## 2.0.4 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.0.3 -Tue, 31 Jan 2017 20:32:37 GMT - -### Patches - -- Make loadSchema public instead of protected. - -## 2.0.2 -Tue, 31 Jan 2017 01:55:09 GMT - -### Patches - -- Introduce schema for ServeTask - -## 2.0.1 -Fri, 13 Jan 2017 06:46:05 GMT - -*Initial release* - diff --git a/core-build/gulp-core-build-serve/LICENSE b/core-build/gulp-core-build-serve/LICENSE deleted file mode 100644 index b3f0c9c646a..00000000000 --- a/core-build/gulp-core-build-serve/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build-serve - -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/core-build/gulp-core-build-serve/README.md b/core-build/gulp-core-build-serve/README.md deleted file mode 100644 index 5ff70e85a82..00000000000 --- a/core-build/gulp-core-build-serve/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# @microsoft/gulp-core-build-serve - - -`gulp-core-build-serve` is a `gulp-core-build` subtask for testing/serving web content on the localhost, and live reloading it when things change. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-serve.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-serve) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build-serve.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build-serve) [![Dependencies](https://david-dm.org/Microsoft/gulp-core-build-serve.svg)](https://david-dm.org/Microsoft/gulp-core-build-serve) - -# ServeTask -A task which spins up two servers, one for serving files in the project, and another for -mocking out an API server to run on a different port. - -## Usage -`--nobrowser` will stop the browser from automatically launching. - -`--port X` will use X as the currently active port. - -## Config -### api -This configuration has two options. If it is undefined, no API endpoint is created. - -Default: `undefined` - -### port -The port to run the API server on. - -### entryPath -The path to the API file. This file should export an object of the following interface: - -```typescript -interface IApiMap { - [ route: string ]: Function; -} -``` - -### initialPage -The initial URL to load. This is ignored if the `--nobrowser` option is specified. - -Default: `'/index.html'` - -### port -The port to serve on. - -Default: `4321` - -### https -A boolean determining whether HTTPS mode should be turned on. - -Default: `false` - -### keyPath -When the `https` option is `true`, this is the path to the HTTPS key - -Default: `undefined` - -### certPath -Path to the HTTPS cert - -Default: `undefined` - -### pfxPath -Path to the HTTPS PFX cert - -Default: `undefined` - -### tryCreateDevCertificate -If true, when gulp-core-build-serve is initialized and a dev certificate doesn't already exist and hasn't been -specified, attempt to generate one and trust it automatically. - -Default: `false` - -# ReloadTask -## Usage -If this task is configured, whenever it is triggered it will tell `gulp-connect` to reload the page. - -## Config -*This task doesn't have any configuration options.* - -# TrustCertTask -## Usage -This task generates and trusts a development certificate. The certificate is self-signed -and stored, along with its private key, in the user's home directory. On Windows, it's -trusted as a root certification authority in the user certificate store. On macOS, it's -trusted as a root cert in the keychain. On other platforms, the certificate is generated -and signed, but the user must trust it manually. See ***Development Certificate*** below for -more information. - -## Config -*This task doesn't have any configuration options.* - -# UntrustCertTask -## Usage -On Windows, this task removes the certificate with the expected serial number from the user's -root certification authorities list. On macOS, it finds the SHA signature of the certificate -with the expected serial number and then removes that certificate from the keychain. On -other platforms, the user must untrust the certificate manually. On all platforms, -the certificate and private key are deleted from the user's home directory. See -***Development Certificate*** below for more information. - -## Config -*This task doesn't have any configuration options.* - -# Development Certificate - -`gulp-core-build-serve` provides functionality to run a development server in HTTPS. Because -HTTPS-hosted server responses are signed, hosting a server using HTTPS requires a trusted certificate -signed by a root certification authority or modern browsers will show security warnings and block -unsigned responses unless they are explicitly excepted. - -Because of this issue `gulp-core-build-serve` also provides functionality to generate and trust -(and un-trust) a development certificate. There are two ways to generate the development certificate: - -1. By setting the `ServeTask`'s `tryCreateDevCertificate` configuration option to `true`. This option -will make the serve task attempt to generate and trust a development certificate before starting the -server if a certificate wasn't specified using the `keyPath` and `certPath` paramters or the `pfxPath` -parameter. - -2. By invoking the `TrustCertTask` build task. - -The certificate is generated and self-signed with a unique private key and an attempt is made to trust -it (Windows and macOS only). If the user does not agree to trust the certificate, provides invalid root -credentials, or something else goes wrong, the `TrustCertTask` will fail and the `ServeTask` will serve -with the default, non-trusted certificate. If trust succeeds, the certificate and the private key are -dropped in the `.rushstack` directory in the user's home folder in `PEM` format. On platforms -other than Windows and macOS, the certificate and key are always dropped in that directory, and the user -must trust the certificate manually. - -After the certificate has been generated, trusted, and dropped in the home folder, any instance of -`gulp-core-build-serve` running in any project will use it when running in HTTPS mode. - -To untrust the certificate, invoke the `UntrustCertTask`. On Windows, this task deletes the certificate -by its serial number from the user root certification authorities store, and on macOS the certificate's -signature is found by its serial number and then the certificate is deleted from the keychain by its -signature. Regardless of whether the untrust succeeds or not, the certificate and key are deleted -from the user's home directory. - -To manually untrust the certificate, delete the files in the `.rushstack` directory under your -home directory and untrust the certificate with the -`73 1c 32 17 44 e3 46 50 a2 02 e3 ef 91 c3 c1 b0` serial number. diff --git a/core-build/gulp-core-build-serve/config/api-extractor.json b/core-build/gulp-core-build-serve/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/gulp-core-build-serve/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/gulp-core-build-serve/gulpfile.js b/core-build/gulp-core-build-serve/gulpfile.js deleted file mode 100644 index 37aa39ec67b..00000000000 --- a/core-build/gulp-core-build-serve/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/core-build/gulp-core-build-serve/package.json b/core-build/gulp-core-build-serve/package.json deleted file mode 100644 index 8022043e875..00000000000 --- a/core-build/gulp-core-build-serve/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-serve", - "version": "3.7.3", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build-serve" - }, - "scripts": { - "build": "gulp --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/debug-certificate-manager": "0.2.3", - "@types/node": "10.17.13", - "colors": "~1.2.1", - "express": "~4.16.2", - "gulp": "~4.0.2", - "gulp-connect": "~5.5.0", - "gulp-open": "~3.0.1", - "sudo": "~1.0.3" - }, - "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/express": "4.11.0", - "@types/express-serve-static-core": "4.11.0", - "@types/gulp": "4.0.6", - "@types/mime": "0.0.29", - "@types/orchestrator": "0.0.30", - "@types/serve-static": "1.13.1", - "@types/through2": "2.0.32", - "@types/vinyl": "2.0.3" - } -} diff --git a/core-build/gulp-core-build-serve/src/ReloadTask.ts b/core-build/gulp-core-build-serve/src/ReloadTask.ts deleted file mode 100644 index 0d45507c1c7..00000000000 --- a/core-build/gulp-core-build-serve/src/ReloadTask.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask } from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; - -export class ReloadTask extends GulpTask { - public constructor() { - super('reload'); - } - - public executeTask(gulp: typeof Gulp, completeCallback?: (error?: string) => void): void { - // eslint-disable-next-line - const gulpConnect = require('gulp-connect'); - - gulp.src('') - .pipe(gulpConnect.reload()); - - completeCallback(); - } -} diff --git a/core-build/gulp-core-build-serve/src/ServeTask.ts b/core-build/gulp-core-build-serve/src/ServeTask.ts deleted file mode 100644 index 7a6705d8583..00000000000 --- a/core-build/gulp-core-build-serve/src/ServeTask.ts +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask, GCBTerminalProvider } from '@microsoft/gulp-core-build'; -import { IBuildConfig } from '@microsoft/gulp-core-build/lib/IBuildConfig'; -import { FileSystem, JsonObject, Terminal } from '@rushstack/node-core-library'; -import * as Gulp from 'gulp'; -import * as colors from 'colors'; -import * as HttpType from 'http'; -import * as HttpsType from 'https'; -import * as pathType from 'path'; -import * as ExpressType from 'express'; - -/* eslint-disable @typescript-eslint/no-var-requires */ - -import { - ICertificate, - CertificateManager -} from '@rushstack/debug-certificate-manager'; - -/** - * @remarks - * If this schema is updated, dependant schemas MUST also be updated, including the spfx-serve.schema.json. - * The spfx-serve.schema.json is the serve.schema.json file with the spfx-specific properties included. The - * merge is simple, but must be done manually whenever the serve.schema.json file is changed. - */ -export interface IServeTaskConfig { - /** - * API server configuration - */ - api?: { - /** - * The port on which to run the API server - */ - port: number, - - /** - * The path to the script to run as the API server - */ - entryPath: string - }; - - /** - * The path to the page which should open automatically after this task completes. If you prefer no page to be - * launched, run the build with the "--nobrowser" flag - */ - initialPage?: string; - - /** - * The port on which to host the file server. - */ - port?: number; - - /** - * The name of the host on which serve is running. Defaults to 'localhost' - */ - hostname?: string; - - /** - * If true, the server should run on HTTPS - */ - https?: boolean; - - /** - * Path to the HTTPS key - */ - keyPath?: string; - - /** - * Path to the HTTPS cert - */ - certPath?: string; - - /** - * Path to the HTTPS PFX cert - */ - pfxPath?: string; - - /** - * Path relative to the server root to base the server in. - */ - rootFolder?: string; - - /** - * If true, when gulp-core-build-serve is initialized and a dev certificate doesn't already exist and hasn't been - * specified, attempt to generate one and trust it automatically. - * - * @default false - */ - tryCreateDevCertificate?: boolean; -} - -interface IApiMap { - [ route: string ]: Function; -} - -export class ServeTask extends GulpTask { - protected _terminalProvider: GCBTerminalProvider; - protected _terminal: Terminal; - - public constructor(extendedName?: string, extendedConfig?: TExtendedConfig) { - super( - extendedName || 'serve', - { - api: undefined, - https: false, - initialPage: '/index.html', - port: 4321, - hostname: 'localhost', - tryCreateDevCertificate: false, - ...(extendedConfig as any) // eslint-disable-line @typescript-eslint/no-explicit-any - } as IServeTaskConfig & TExtendedConfig - ); - this._terminalProvider = new GCBTerminalProvider(this); - this._terminal = new Terminal(this._terminalProvider); - } - - public loadSchema(): JsonObject { - return require('./serve.schema.json'); - } - - public executeTask(gulp: typeof Gulp, completeCallback?: (error?: string) => void): void { - - /* eslint-disable @typescript-eslint/typedef */ - const gulpConnect = require('gulp-connect'); - const open = require('gulp-open'); - const http = require('http'); - const https = require('https'); - /* eslint-enable @typescript-eslint/typedef */ - - const path: typeof pathType = require('path'); - - const openBrowser: boolean = (process.argv.indexOf('--nobrowser') === -1); - const portArgumentIndex: number = process.argv.indexOf('--port'); - let { port, initialPage }: IServeTaskConfig = this.taskConfig; - const { api, hostname }: IServeTaskConfig = this.taskConfig; - const { rootPath }: IBuildConfig = this.buildConfig; - const httpsServerOptions: HttpsType.ServerOptions = this._loadHttpsServerOptions(); - - if (portArgumentIndex >= 0 && process.argv.length > (portArgumentIndex + 1)) { - port = Number(process.argv[portArgumentIndex + 1]); - } - - // Spin up the connect server - gulpConnect.server({ - https: httpsServerOptions, - livereload: true, - middleware: (): Function[] => [this._logRequestsMiddleware, this._enableCorsMiddleware], - port: port, - root: path.join(rootPath, this.taskConfig.rootFolder || ''), - preferHttp1: true, - host: hostname - }); - - // If an api is provided, spin it up. - if (api) { - let apiMap: IApiMap | { default: IApiMap }; - - try { - apiMap = require(path.join(rootPath, api.entryPath)); - - if (apiMap && (apiMap as { default: IApiMap }).default) { - apiMap = (apiMap as { default: IApiMap }).default; - } - } catch (e) { - this.logError(`The api entry could not be loaded: ${api.entryPath}`); - } - - if (apiMap) { - console.log(`Starting api server on port ${api.port}.`); - - const express: typeof ExpressType = require('express'); - const app: ExpressType.Express = express(); - - app.use(this._logRequestsMiddleware); - app.use(this._enableCorsMiddleware); - app.use(this._setJSONResponseContentTypeMiddleware); - - // Load the apis. - for (const apiMapEntry in apiMap) { - if (apiMap.hasOwnProperty(apiMapEntry)) { - console.log(`Registring api: ${ colors.green(apiMapEntry) }`); - app.get(apiMapEntry, apiMap[apiMapEntry]); - } - } - - const apiPort: number = api.port || 5432; - if (this.taskConfig.https) { - https.createServer(httpsServerOptions, app).listen(apiPort); - } else { - http.createServer(app).listen(apiPort); - } - } - } - - // Spin up the browser. - if (openBrowser) { - let uri: string = initialPage; - if (!initialPage.match(/^https?:\/\//)) { - if (!initialPage.match(/^\//)) { - initialPage = `/${initialPage}`; - } - - uri = `${this.taskConfig.https ? 'https' : 'http'}://${this.taskConfig.hostname}:${port}${initialPage}`; - } - - gulp.src('') - .pipe(open({ - uri: uri - })); - } - - completeCallback(); - } - - private _logRequestsMiddleware( - req: HttpType.IncomingMessage, - res: HttpType.ServerResponse, - next?: () => void - ): void { - const ipAddress: string = (req as any).ip; // eslint-disable-line @typescript-eslint/no-explicit-any - let resourceColor: (text: string) => string = colors.cyan; - - if (req && req.url) { - if (req.url.indexOf('.bundle.js') >= 0) { - resourceColor = colors.green; - } else if (req.url.indexOf('.js') >= 0) { - resourceColor = colors.magenta; - } - - console.log( - [ - ` Request: `, - `${ ipAddress ? `[${ colors.cyan(ipAddress) }] ` : `` }`, - `'${ resourceColor(req.url) }'` - ].join('')); - } - - next(); - } - - private _enableCorsMiddleware( - req: HttpType.IncomingMessage, - res: HttpType.ServerResponse, - next?: () => void - ): void { - res.setHeader('Access-Control-Allow-Origin', '*'); - next(); - } - - private _setJSONResponseContentTypeMiddleware( - req: HttpType.IncomingMessage, - res: HttpType.ServerResponse, - next?: () => void - ): void { - res.setHeader('content-type', 'application/json'); - next(); - } - - private _loadHttpsServerOptions(): HttpsType.ServerOptions { - if (this.taskConfig.https) { - const result: HttpsType.ServerOptions = {}; - - // We're configuring an HTTPS server, so we need a certificate - if (this.taskConfig.pfxPath) { - // There's a PFX path in the config, so try that - this.logVerbose(`Trying PFX path: ${this.taskConfig.pfxPath}`); - if (FileSystem.exists(this.taskConfig.pfxPath)) { - try { - result.pfx = FileSystem.readFile(this.taskConfig.pfxPath); - this.logVerbose(`Loaded PFX certificate.`); - } catch (e) { - this.logError(`Error loading PFX file: ${e}`); - } - } else { - this.logError(`PFX file not found at path "${this.taskConfig.pfxPath}"`); - } - } else if (this.taskConfig.keyPath && this.taskConfig.certPath) { - this.logVerbose(`Trying key path "${this.taskConfig.keyPath}" and cert path "${this.taskConfig.certPath}".`); - const certExists: boolean = FileSystem.exists(this.taskConfig.certPath); - const keyExists: boolean = FileSystem.exists(this.taskConfig.keyPath); - - if (keyExists && certExists) { - try { - result.cert = FileSystem.readFile(this.taskConfig.certPath); - result.key = FileSystem.readFile(this.taskConfig.keyPath); - } catch (e) { - this.logError(`Error loading key or cert file: ${e}`); - } - } else { - if (!keyExists) { - this.logError(`Key file not found at path "${this.taskConfig.keyPath}`); - } - - if (!certExists) { - this.logError(`Cert file not found at path "${this.taskConfig.certPath}`); - } - } - } else { - const certificateManager: CertificateManager = new CertificateManager(); - const devCertificate: ICertificate = certificateManager.ensureCertificate( - this.taskConfig.tryCreateDevCertificate, - this._terminal - ); - if (devCertificate.pemCertificate && devCertificate.pemKey) { - result.cert = devCertificate.pemCertificate; - result.key = devCertificate.pemKey; - } else { - this.logWarning( - 'When serving in HTTPS mode, a PFX cert path or a cert path and a key path must be ' + - 'provided, or a dev certificate must be generated and trusted. If a SSL certificate isn\'t ' + - 'provided, a default, self-signed certificate will be used. Expect browser security ' + - 'warnings.' - ); - } - } - - return result; - } else { - return undefined; - } - } -} diff --git a/core-build/gulp-core-build-serve/src/TrustCertTask.ts b/core-build/gulp-core-build-serve/src/TrustCertTask.ts deleted file mode 100644 index ef5d52d6ea7..00000000000 --- a/core-build/gulp-core-build-serve/src/TrustCertTask.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - GulpTask, - GCBTerminalProvider -} from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; -import { - ICertificate, - CertificateManager -} from '@rushstack/debug-certificate-manager'; -import { Terminal } from '@rushstack/node-core-library'; - -/** - * This task generates and trusts a development certificate. The certificate is self-signed - * and stored, along with its private key, in the user's home directory. On Windows, it's - * trusted as a root certification authority in the user certificate store. On macOS, it's - * trusted as a root cert in the keychain. On other platforms, the certificate is generated - * and signed, but the user must trust it manually. - */ -export class TrustCertTask extends GulpTask { - private _terminalProvider: GCBTerminalProvider; - private _terminal: Terminal; - - public constructor() { - super('trust-cert'); - this._terminalProvider = new GCBTerminalProvider(this); - this._terminal = new Terminal(this._terminalProvider); - } - - public executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): void { - const certificateManager: CertificateManager = new CertificateManager(); - const certificate: ICertificate = certificateManager.ensureCertificate(true, this._terminal); - - if (certificate.pemCertificate && certificate.pemKey) { - completeCallback(); - } else { - completeCallback('Error trusting development certificate.'); - } - } -} diff --git a/core-build/gulp-core-build-serve/src/UntrustCertTask.ts b/core-build/gulp-core-build-serve/src/UntrustCertTask.ts deleted file mode 100644 index 23d3e0717eb..00000000000 --- a/core-build/gulp-core-build-serve/src/UntrustCertTask.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - GulpTask, - GCBTerminalProvider -} from '@microsoft/gulp-core-build'; -import { Terminal } from '@rushstack/node-core-library'; -import * as Gulp from 'gulp'; -import { - CertificateStore, - CertificateManager -} from '@rushstack/debug-certificate-manager'; - -/** - * On Windows, this task removes the certificate with the expected serial number from the user's - * root certification authorities list. On macOS, it finds the SHA signature of the certificate - * with the expected serial number and then removes that certificate from the keychain. On - * other platforms, the user must untrust the certificate manually. On all platforms, - * the certificate and private key are deleted from the user's home directory. - */ -export class UntrustCertTask extends GulpTask { - private _terminalProvider: GCBTerminalProvider; - private _terminal: Terminal; - - public constructor() { - super('untrust-cert'); - - this._terminalProvider = new GCBTerminalProvider(this); - this._terminal = new Terminal(this._terminalProvider); - } - - public executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): void { - const certificateManager: CertificateManager = new CertificateManager(); - const untrustCertResult: boolean = certificateManager.untrustCertificate(this._terminal); - const certificateStore: CertificateStore = new CertificateStore(); - - // Clear out the certificate store - certificateStore.certificateData = undefined; - certificateStore.keyData = undefined; - - if (untrustCertResult) { - completeCallback(); - } else { - completeCallback('Error untrusting certificate.'); - } - } -} diff --git a/core-build/gulp-core-build-serve/src/index.ts b/core-build/gulp-core-build-serve/src/index.ts deleted file mode 100644 index e9472673415..00000000000 --- a/core-build/gulp-core-build-serve/src/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { ServeTask } from './ServeTask'; -import { ReloadTask } from './ReloadTask'; -import { TrustCertTask } from './TrustCertTask'; -import { UntrustCertTask } from './UntrustCertTask'; - -/** - * @public - */ -export const serve: ServeTask = new ServeTask(); - -/** - * @public - */ -export const reload: ReloadTask = new ReloadTask(); - -/** - * @public - */ -export const trustDevCert: TrustCertTask = new TrustCertTask(); - -/** - * @public - */ -export const untrustDevCert: UntrustCertTask = new UntrustCertTask(); - -export default serve; diff --git a/core-build/gulp-core-build-serve/src/serve.schema.json b/core-build/gulp-core-build-serve/src/serve.schema.json deleted file mode 100644 index 540fef50a5c..00000000000 --- a/core-build/gulp-core-build-serve/src/serve.schema.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "title": "Serve Task Configuration", - "description": "Defines parameters for the webserver which is spun up by the Serve Task", - - "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" - }, - - "api": { - "title": "API server configuration", - "description": "Parameters which configure the API server, which runs simultaneously and allows for mock testing", - - "type": "object", - "additionalProperties": false, - "required": [ "port", "entryPath" ], - "properties": { - "port": { - "title": "API Port", - "description": "The port which the API server listens on", - "type": "number" - }, - "entryPath": { - "title": "API Entry Point Path", - "description": "The path to the script to run as the API server", - "type": "string" - } - } - }, - - "initialPage": { - "title": "Initial Page", - "description": "The path to the page which should open automatically after this task completes", - "type": "string" - }, - - "port": { - "title": "Port", - "description": "The port on which to host the file server.", - "type": "number" - }, - - "hostname": { - "title": "Hostname", - "description": "The name of the host on which serve is running. Defaults to 'localhost'", - "type": "string" - }, - - "https": { - "title": "HTTPS Mode", - "description": "If true, the server should run on HTTPS", - "type": "boolean" - }, - - "keyPath": { - "title": "HTTPS Key Path", - "description": "Path to the HTTPS key", - "type": "string" - }, - - "certPath": { - "title": "HTTPS Cert Path", - "description": "Path to the HTTPS cert", - "type": "string" - }, - - "pfxPath": { - "title": "HTTPS PFX Path", - "description": "Path to the HTTPS PFX cert", - "type": "string" - }, - - "tryCreateDevCertificate": { - "title": "Should Create Dev Certificate", - "description": "If true, when gulp-core-build-serve is initialized and a dev certificate doesn't already exist and hasn't been specified, attempt to generate one and trust it automatically.", - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build-serve/tsconfig.json b/core-build/gulp-core-build-serve/tsconfig.json deleted file mode 100644 index f69e315c014..00000000000 --- a/core-build/gulp-core-build-serve/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "strictNullChecks": false - } -} diff --git a/core-build/gulp-core-build-typescript/.eslintrc.js b/core-build/gulp-core-build-typescript/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/gulp-core-build-typescript/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/gulp-core-build-typescript/.npmignore b/core-build/gulp-core-build-typescript/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build-typescript/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build-typescript/CHANGELOG.json b/core-build/gulp-core-build-typescript/CHANGELOG.json deleted file mode 100644 index 589254143b9..00000000000 --- a/core-build/gulp-core-build-typescript/CHANGELOG.json +++ /dev/null @@ -1,4823 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-typescript", - "entries": [ - { - "version": "8.4.6", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.6", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.9` to `7.7.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.9.4` to `0.9.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "8.4.5", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.5", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.8` to `7.7.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.9.3` to `0.9.4`" - } - ] - } - }, - { - "version": "8.4.4", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.4", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.7` to `7.7.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.9.2` to `0.9.3`" - } - ] - } - }, - { - "version": "8.4.3", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "patch": [ - { - "comment": "Extract GCBTerminalProvider to gulp-core-build." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - } - ] - } - }, - { - "version": "8.4.2", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.6` to `7.7.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.9.1` to `0.9.2`" - } - ] - } - }, - { - "version": "8.4.1", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.5` to `7.7.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.9.0` to `0.9.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "8.4.0", - "tag": "@microsoft/gulp-core-build-typescript_v8.4.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.4` to `7.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.14` to `0.9.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "8.3.16", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.16", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.3` to `7.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.13` to `0.8.14`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "8.3.15", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.15", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.2` to `7.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.12` to `0.8.13`" - } - ] - } - }, - { - "version": "8.3.14", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.14", - "date": "Sat, 11 Jan 2020 05:18:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - } - ] - } - }, - { - "version": "8.3.13", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.13", - "date": "Thu, 09 Jan 2020 06:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.1` to `7.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.11` to `0.8.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "8.3.12", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.12", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.7.0` to `7.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.10` to `0.8.11`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "8.3.11", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.11", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - } - ] - } - }, - { - "version": "8.3.10", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.10", - "date": "Tue, 03 Dec 2019 03:17:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.6.2` to `7.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.9` to `0.8.10`" - } - ] - } - }, - { - "version": "8.3.9", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.9", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.6.1` to `7.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.8` to `0.8.9`" - } - ] - } - }, - { - "version": "8.3.8", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.8", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.6.0` to `7.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.7` to `0.8.8`" - } - ] - } - }, - { - "version": "8.3.7", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.7", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.6` to `7.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.6` to `0.8.7`" - } - ] - } - }, - { - "version": "8.3.6", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.6", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.5` to `7.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.5` to `0.8.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "8.3.5", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.5", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.4` to `7.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.4` to `0.8.5`" - } - ] - } - }, - { - "version": "8.3.4", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.4", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.3` to `7.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.3` to `0.8.4`" - } - ] - } - }, - { - "version": "8.3.3", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.3", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.2` to `7.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.2` to `0.8.3`" - } - ] - } - }, - { - "version": "8.3.2", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.2", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.1` to `0.8.2`" - } - ] - } - }, - { - "version": "8.3.1", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.1", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.1` to `7.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.8.0` to `0.8.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "8.3.0", - "tag": "@microsoft/gulp-core-build-typescript_v8.3.0", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for ESLint+TypeScript" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.6` to `0.8.0`" - } - ] - } - }, - { - "version": "8.2.6", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.6", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.5.0` to `7.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.5` to `0.7.6`" - } - ] - } - }, - { - "version": "8.2.5", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.7` to `7.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.4` to `0.7.5`" - } - ] - } - }, - { - "version": "8.2.4", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.6` to `7.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.3` to `0.7.4`" - } - ] - } - }, - { - "version": "8.2.3", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.5` to `7.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.2` to `0.7.3`" - } - ] - } - }, - { - "version": "8.2.2", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.4` to `7.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.1` to `0.7.2`" - } - ] - } - }, - { - "version": "8.2.1", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.3` to `7.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.7.0` to `0.7.1`" - } - ] - } - }, - { - "version": "8.2.0", - "tag": "@microsoft/gulp-core-build-typescript_v8.2.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.2` to `7.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.36` to `0.7.0`" - } - ] - } - }, - { - "version": "8.1.35", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.35", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where api-extractor warnings weren't being reported." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.35` to `0.6.36`" - } - ] - } - }, - { - "version": "8.1.34", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.34", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.1` to `7.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.34` to `0.6.35`" - } - ] - } - }, - { - "version": "8.1.33", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.33", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.4.0` to `7.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.33` to `0.6.34`" - } - ] - } - }, - { - "version": "8.1.32", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.32", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.11` to `7.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.32` to `0.6.33`" - } - ] - } - }, - { - "version": "8.1.31", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.31", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.10` to `7.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.31` to `0.6.32`" - } - ] - } - }, - { - "version": "8.1.30", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.30", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.9` to `7.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.30` to `0.6.31`" - } - ] - } - }, - { - "version": "8.1.29", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.29", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.8` to `7.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.29` to `0.6.30`" - } - ] - } - }, - { - "version": "8.1.28", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.28", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.7` to `7.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.28` to `0.6.29`" - } - ] - } - }, - { - "version": "8.1.27", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.27", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.6` to `7.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.27` to `0.6.28`" - } - ] - } - }, - { - "version": "8.1.26", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.26", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.5` to `7.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.26` to `0.6.27`" - } - ] - } - }, - { - "version": "8.1.25", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.25", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.4` to `7.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.25` to `0.6.26`" - } - ] - } - }, - { - "version": "8.1.24", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.24", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - } - ] - } - }, - { - "version": "8.1.23", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.23", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.3` to `7.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.24` to `0.6.25`" - } - ] - } - }, - { - "version": "8.1.22", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.22", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.2` to `7.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.23` to `0.6.24`" - } - ] - } - }, - { - "version": "8.1.21", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.21", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.1` to `7.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.22` to `0.6.23`" - } - ] - } - }, - { - "version": "8.1.20", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.20", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.3.0` to `7.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.21` to `0.6.22`" - } - ] - } - }, - { - "version": "8.1.19", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.19", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.2.3` to `7.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.20` to `0.6.21`" - } - ] - } - }, - { - "version": "8.1.18", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.18", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.2.2` to `7.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.19` to `0.6.20`" - } - ] - } - }, - { - "version": "8.1.17", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.17", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.2.1` to `7.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.18` to `0.6.19`" - } - ] - } - }, - { - "version": "8.1.16", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.16", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.2.0` to `7.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.17` to `0.6.18`" - } - ] - } - }, - { - "version": "8.1.15", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.15", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.8` to `7.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.16` to `0.6.17`" - } - ] - } - }, - { - "version": "8.1.14", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.14", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.7` to `7.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.15` to `0.6.16`" - } - ] - } - }, - { - "version": "8.1.13", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.13", - "date": "Tue, 04 Jun 2019 05:51:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.6` to `7.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.14` to `0.6.15`" - } - ] - } - }, - { - "version": "8.1.12", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.12", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.5` to `7.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.13` to `0.6.14`" - } - ] - } - }, - { - "version": "8.1.11", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.11", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.4` to `7.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.12` to `0.6.13`" - } - ] - } - }, - { - "version": "8.1.10", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.10", - "date": "Mon, 06 May 2019 20:46:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.3` to `7.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.11` to `0.6.12`" - } - ] - } - }, - { - "version": "8.1.9", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.9", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.2` to `7.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.10` to `0.6.11`" - } - ] - } - }, - { - "version": "8.1.8", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.8", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.1` to `7.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.9` to `0.6.10`" - } - ] - } - }, - { - "version": "8.1.7", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.7", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.1.0` to `7.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.8` to `0.6.9`" - } - ] - } - }, - { - "version": "8.1.6", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.6", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.42` to `7.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.7` to `0.6.8`" - } - ] - } - }, - { - "version": "8.1.5", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.5", - "date": "Fri, 12 Apr 2019 06:13:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.41` to `7.0.42`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.6` to `0.6.7`" - } - ] - } - }, - { - "version": "8.1.4", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.4", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.40` to `7.0.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.5` to `0.6.6`" - } - ] - } - }, - { - "version": "8.1.3", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.3", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.39` to `7.0.40`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.4` to `0.6.5`" - } - ] - } - }, - { - "version": "8.1.2", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.2", - "date": "Mon, 08 Apr 2019 19:12:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.38` to `7.0.39`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.3` to `0.6.4`" - } - ] - } - }, - { - "version": "8.1.1", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.1", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.37` to `7.0.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.2` to `0.6.3`" - } - ] - } - }, - { - "version": "8.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v8.1.0", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "minor": [ - { - "comment": "Update to use the new rush-stack-compiler contract for API Extractor 7" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.36` to `7.0.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.1\" from `0.6.1` to `0.6.2`" - } - ] - } - }, - { - "version": "8.0.23", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.23", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.35` to `7.0.36`" - } - ] - } - }, - { - "version": "8.0.22", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.22", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - } - ] - } - }, - { - "version": "8.0.21", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.21", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.34` to `7.0.35`" - } - ] - } - }, - { - "version": "8.0.20", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.20", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.33` to `7.0.34`" - } - ] - } - }, - { - "version": "8.0.19", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.19", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.32` to `7.0.33`" - } - ] - } - }, - { - "version": "8.0.18", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.18", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.31` to `7.0.32`" - } - ] - } - }, - { - "version": "8.0.17", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.17", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.30` to `7.0.31`" - } - ] - } - }, - { - "version": "8.0.16", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.16", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.29` to `7.0.30`" - } - ] - } - }, - { - "version": "8.0.15", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.15", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.28` to `7.0.29`" - } - ] - } - }, - { - "version": "8.0.14", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.14", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.27` to `7.0.28`" - } - ] - } - }, - { - "version": "8.0.13", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.13", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.26` to `7.0.27`" - } - ] - } - }, - { - "version": "8.0.12", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.12", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.25` to `7.0.26`" - } - ] - } - }, - { - "version": "8.0.11", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.11", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.24` to `7.0.25`" - } - ] - } - }, - { - "version": "8.0.10", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.10", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.23` to `7.0.24`" - } - ] - } - }, - { - "version": "8.0.9", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.9", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.22` to `7.0.23`" - } - ] - } - }, - { - "version": "8.0.8", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.8", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.21` to `7.0.22`" - } - ] - } - }, - { - "version": "8.0.7", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.7", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.1` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.20` to `7.0.21`" - } - ] - } - }, - { - "version": "8.0.6", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.6", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.19` to `7.0.20`" - } - ] - } - }, - { - "version": "8.0.5", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.5", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.18` to `7.0.19`" - } - ] - } - }, - { - "version": "8.0.4", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.4", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.17` to `7.0.18`" - } - ] - } - }, - { - "version": "8.0.3", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.3", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `7.0.16` to `7.0.17`" - } - ] - } - }, - { - "version": "8.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.2", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.9.0` to `3.10.0`" - } - ] - } - }, - { - "version": "8.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.1", - "date": "Wed, 30 Jan 2019 20:49:11 GMT", - "comments": { - "patch": [ - { - "comment": "Update dependency on changed API in RSC" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.4.0` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - } - ] - } - }, - { - "version": "8.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v8.0.0", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "major": [ - { - "comment": "Update api extractor task to use api extractor's config file." - } - ], - "minor": [ - { - "comment": "Upgrade to use API Extractor 7 beta" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.3.4` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - } - ] - } - }, - { - "version": "7.4.8", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.8", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - } - ] - } - }, - { - "version": "7.4.7", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.7", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.3` to `3.9.0`" - } - ] - } - }, - { - "version": "7.4.6", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.6", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - } - ] - } - }, - { - "version": "7.4.5", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.5", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.2` to `3.8.3`" - } - ] - } - }, - { - "version": "7.4.4", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.4", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.1` to `3.8.2`" - } - ] - } - }, - { - "version": "7.4.3", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.3", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.0` to `3.8.1`" - } - ] - } - }, - { - "version": "7.4.2", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.2", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.2.1` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - } - ] - } - }, - { - "version": "7.4.1", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.1", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.1` to `3.8.0`" - } - ] - } - }, - { - "version": "7.4.0", - "tag": "@microsoft/gulp-core-build-typescript_v7.4.0", - "date": "Fri, 30 Nov 2018 23:34:57 GMT", - "comments": { - "minor": [ - { - "comment": "Allow custom arguments to be passed to the tsc command." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.1.1` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - } - ] - } - }, - { - "version": "7.3.1", - "tag": "@microsoft/gulp-core-build-typescript_v7.3.1", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.0` to `3.7.1`" - } - ] - } - }, - { - "version": "7.3.0", - "tag": "@microsoft/gulp-core-build-typescript_v7.3.0", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update rush-stack-compiler resolution to find a package following the \"rush-stack-compiler-\" naming convention." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-2.7\" from `0.0.0` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - } - ] - } - }, - { - "version": "7.2.7", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.7", - "date": "Wed, 28 Nov 2018 19:29:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - } - ] - } - }, - { - "version": "7.2.6", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.6", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.6.0` to `3.7.0`" - } - ] - } - }, - { - "version": "7.2.5", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.5", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.2` to `3.6.0`" - } - ] - } - }, - { - "version": "7.2.4", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.4", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - } - ] - } - }, - { - "version": "7.2.3", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.3", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - } - ] - } - }, - { - "version": "7.2.2", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.2", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.1` to `3.5.2`" - } - ] - } - }, - { - "version": "7.2.1", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.1", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - } - ] - } - }, - { - "version": "7.2.0", - "tag": "@microsoft/gulp-core-build-typescript_v7.2.0", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "minor": [ - { - "comment": "Update GCB-TS to ship with a default rush-stack-compiler with TS 2.4." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.0` to `3.5.1`" - } - ] - } - }, - { - "version": "7.1.2", - "tag": "@microsoft/gulp-core-build-typescript_v7.1.2", - "date": "Thu, 01 Nov 2018 21:33:51 GMT", - "comments": { - "patch": [ - { - "comment": "Fix a regression where @microsoft/rush-stack-compiler could not compile itself" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "7.1.1", - "tag": "@microsoft/gulp-core-build-typescript_v7.1.1", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.1.0` to `6.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "7.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v7.1.0", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "minor": [ - { - "comment": "Update the way rush-stack-compiler is resolved. Now it's resolved by looking at the \"extends\" properties of tsconfig.json" - } - ] - } - }, - { - "version": "7.0.3", - "tag": "@microsoft/gulp-core-build-typescript_v7.0.3", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.9` to `6.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "7.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v7.0.2", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - } - ] - } - }, - { - "version": "7.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v7.0.1", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - } - ] - } - }, - { - "version": "7.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v7.0.0", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "major": [ - { - "comment": "Moving logic into rush-stack-compiler." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - } - ] - } - }, - { - "version": "6.1.12", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.12", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.8` to `6.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.4.0` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "6.1.11", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.11", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.7` to `6.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "6.1.10", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.10", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.6` to `6.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.1` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "6.1.9", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.9", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "patch": [ - { - "comment": "Replace deprecated dependency gulp-util" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - } - ] - } - }, - { - "version": "6.1.8", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.8", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.5` to `6.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "6.1.7", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.7", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.4` to `6.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "6.1.6", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.6", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.3` to `6.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "6.1.5", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.5", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.2` to `6.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "6.1.4", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.4", - "date": "Tue, 09 Oct 2018 06:58:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.1` to `6.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "6.1.3", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.3", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `6.0.0` to `6.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.2.0` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "6.1.2", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.2", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.13.1` to `6.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.1.0` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - } - ] - } - }, - { - "version": "6.1.1", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.1", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.13.0` to `5.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.1` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - } - ] - } - }, - { - "version": "6.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v6.1.0", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "minor": [ - { - "comment": "Expose new api-extractor skipLibCheck option." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.12.2` to `5.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - } - ] - } - }, - { - "version": "6.0.5", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.5", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.12.1` to `5.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - } - ] - } - }, - { - "version": "6.0.4", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.4", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "patch": [ - { - "comment": "Fixed overridePackagePath not loading correct version of package." - } - ] - } - }, - { - "version": "6.0.3", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.3", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.12.0` to `5.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - } - ] - } - }, - { - "version": "6.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.2", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "patch": [ - { - "comment": "Include support for the typescriptCompilerFolder api-extractor option." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.11.2` to `5.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - } - ] - } - }, - { - "version": "6.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.1", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.11.1` to `5.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - } - ] - } - }, - { - "version": "6.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v6.0.0", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "major": [ - { - "comment": "Remove the old TypeScript, TSLint, Text, and RemoveTripleSlash tasks." - } - ] - } - }, - { - "version": "5.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v5.0.2", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.11.0` to `5.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "5.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v5.0.1", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "5.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v5.0.0", - "date": "Mon, 03 Sep 2018 16:04:45 GMT", - "comments": { - "major": [ - { - "comment": "Replace the old api-extractor task with the new one that uses tsconfig.json instead of a runtime configuration." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.8` to `5.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "4.11.12", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.12", - "date": "Thu, 30 Aug 2018 22:47:34 GMT", - "comments": { - "patch": [ - { - "comment": "Include defaultTslint in npm package." - } - ] - } - }, - { - "version": "4.11.11", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.11", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "4.11.10", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.10", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - } - ] - } - }, - { - "version": "4.11.9", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.9", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "4.11.8", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.8", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing minor path issue." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.7` to `5.10.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.1` to `3.0.0`" - } - ] - } - }, - { - "version": "4.11.7", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.7", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.6` to `5.10.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.0` to `2.2.1`" - } - ] - } - }, - { - "version": "4.11.6", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.6", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.5` to `5.10.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.1` to `2.2.0`" - } - ] - } - }, - { - "version": "4.11.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.5", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.4` to `5.10.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.0` to `2.1.1`" - } - ] - } - }, - { - "version": "4.11.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.4", - "date": "Tue, 21 Aug 2018 16:04:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.3` to `5.10.4`" - } - ] - } - }, - { - "version": "4.11.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.3", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.2` to `5.10.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.0.0` to `2.1.0`" - } - ] - } - }, - { - "version": "4.11.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.2", - "date": "Thu, 09 Aug 2018 16:04:24 GMT", - "comments": { - "patch": [ - { - "comment": "Update lodash." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.1` to `5.10.2`" - } - ] - } - }, - { - "version": "4.11.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.1", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - } - ] - } - }, - { - "version": "4.11.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.11.0", - "date": "Thu, 26 Jul 2018 23:53:43 GMT", - "comments": { - "minor": [ - { - "comment": "Include an option to strip comments from produced JS files in the TSC task." - } - ] - } - }, - { - "version": "4.10.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.5", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.10.0` to `5.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.5.0` to `2.0.0`" - } - ] - } - }, - { - "version": "4.10.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.4", - "date": "Wed, 25 Jul 2018 21:02:57 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where the TscTask and TslintTasks where invoking the wrong version of Node.js" - } - ] - } - }, - { - "version": "4.10.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.3", - "date": "Tue, 17 Jul 2018 16:02:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.9.1` to `5.10.0`" - } - ] - } - }, - { - "version": "4.10.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.2", - "date": "Fri, 13 Jul 2018 19:04:50 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where \"spawnSync\" may not be able to resolve node." - } - ] - } - }, - { - "version": "4.10.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.1", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.9.0` to `5.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.4.1` to `1.5.0`" - } - ] - } - }, - { - "version": "4.10.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.10.0", - "date": "Fri, 29 Jun 2018 02:56:51 GMT", - "comments": { - "minor": [ - { - "comment": "Inclusion of three new tasks designed to use as minimal behavior as possible to run tsc, tslint, and api-extractor." - } - ] - } - }, - { - "version": "4.9.19", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.19", - "date": "Sat, 23 Jun 2018 02:21:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.8.1` to `5.9.0`" - } - ] - } - }, - { - "version": "4.9.18", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.18", - "date": "Fri, 22 Jun 2018 16:05:15 GMT", - "comments": { - "patch": [ - { - "comment": "Fixed mutation on tsConfigFile resulting in tslint error" - } - ] - } - }, - { - "version": "4.9.17", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.17", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.8.0` to `5.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.4.0` to `1.4.1`" - } - ] - } - }, - { - "version": "4.9.16", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.16", - "date": "Tue, 19 Jun 2018 19:35:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.7.3` to `5.8.0`" - } - ] - } - }, - { - "version": "4.9.15", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.15", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.7.2` to `5.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.2` to `1.4.0`" - } - ] - } - }, - { - "version": "4.9.14", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.14", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.7.1` to `5.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.1` to `1.3.2`" - } - ] - } - }, - { - "version": "4.9.13", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.13", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.7.0` to `5.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.0` to `1.3.1`" - } - ] - } - }, - { - "version": "4.9.12", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.12", - "date": "Tue, 15 May 2018 00:18:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.8` to `5.7.0`" - } - ] - } - }, - { - "version": "4.9.11", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.11", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - } - ] - } - }, - { - "version": "4.9.10", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.10", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.7` to `5.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.2.0` to `1.3.0`" - } - ] - } - }, - { - "version": "4.9.9", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.9", - "date": "Tue, 01 May 2018 22:03:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.6` to `5.6.7`" - } - ] - } - }, - { - "version": "4.9.8", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.8", - "date": "Fri, 27 Apr 2018 03:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.5` to `5.6.6`" - } - ] - } - }, - { - "version": "4.9.7", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.7", - "date": "Fri, 20 Apr 2018 16:06:11 GMT", - "comments": { - "patch": [ - { - "comment": "Fix logging warnings in TypeScript config" - } - ] - } - }, - { - "version": "4.9.6", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.6", - "date": "Thu, 19 Apr 2018 21:25:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.4` to `5.6.5`" - } - ] - } - }, - { - "version": "4.9.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.5", - "date": "Thu, 19 Apr 2018 17:02:06 GMT", - "comments": { - "patch": [ - { - "comment": "Expose three more api-extractor config parameters in gulp-core-build-typescript" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.3` to `5.6.4`" - } - ] - } - }, - { - "version": "4.9.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.4", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.2` to `5.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.1.0` to `1.2.0`" - } - ] - } - }, - { - "version": "4.9.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.3", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.1` to `5.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.0.0` to `1.1.0`" - } - ] - } - }, - { - "version": "4.9.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.2", - "date": "Tue, 27 Mar 2018 01:34:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.6.0` to `5.6.1`" - } - ] - } - }, - { - "version": "4.9.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.1", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - } - ] - } - }, - { - "version": "4.9.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.9.0", - "date": "Sun, 25 Mar 2018 01:26:19 GMT", - "comments": { - "minor": [ - { - "comment": "For the API Extractor task config file, the \"generatePackageTypings\" setting was renamed to \"generateDtsRollup\"" - }, - { - "comment": "Add a new GCB option dtsRollupTrimming which corresponds to the new \"trimming\" flag for API Extractor" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.5.2` to `5.6.0`" - } - ] - } - }, - { - "version": "4.8.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.8.1", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.5.1` to `5.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - } - ] - } - }, - { - "version": "4.8.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.8.0", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "minor": [ - { - "comment": "Add a `libESNextFolder` option" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - } - ] - } - }, - { - "version": "4.7.22", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.22", - "date": "Tue, 20 Mar 2018 02:44:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.5.0` to `5.5.1`" - } - ] - } - }, - { - "version": "4.7.21", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.21", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.4.0` to `5.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.8.0` to `1.0.0`" - } - ] - } - }, - { - "version": "4.7.20", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.20", - "date": "Thu, 15 Mar 2018 20:00:50 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where the column number for typescript errors was off by one" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.9` to `5.4.0`" - } - ] - } - }, - { - "version": "4.7.19", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.19", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.8` to `5.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.3` to `0.8.0`" - } - ] - } - }, - { - "version": "4.7.18", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.18", - "date": "Tue, 13 Mar 2018 23:11:32 GMT", - "comments": { - "patch": [ - { - "comment": "Update gulp-sourcemaps." - } - ] - } - }, - { - "version": "4.7.17", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.17", - "date": "Mon, 12 Mar 2018 20:36:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.7` to `5.3.8`" - } - ] - } - }, - { - "version": "4.7.16", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.16", - "date": "Tue, 06 Mar 2018 17:04:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.6` to `5.3.7`" - } - ] - } - }, - { - "version": "4.7.15", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.15", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.5` to `5.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.2` to `0.7.3`" - } - ] - } - }, - { - "version": "4.7.14", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.14", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.4` to `5.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.1` to `0.7.2`" - } - ] - } - }, - { - "version": "4.7.13", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.13", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where the line number for typescript errors were off by one." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.3` to `5.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.0` to `0.7.1`" - } - ] - } - }, - { - "version": "4.7.12", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.12", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.2` to `5.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.6.1` to `0.7.0`" - } - ] - } - }, - { - "version": "4.7.11", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.11", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.1` to `5.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.6.0` to `0.6.1`" - } - ] - } - }, - { - "version": "4.7.10", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.10", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.3.0` to `5.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.5.1` to `0.6.0`" - } - ] - } - }, - { - "version": "4.7.9", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.9", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.7` to `5.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "4.7.8", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.8", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.6` to `5.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.10` to `0.5.0`" - } - ] - } - }, - { - "version": "4.7.7", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.7", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.5` to `5.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.9` to `0.4.10`" - } - ] - } - }, - { - "version": "4.7.6", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.6", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.4` to `5.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.8` to `0.4.9`" - } - ] - } - }, - { - "version": "4.7.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.5", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "patch": [ - { - "comment": "Add some missing @types dependencies to the package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.3` to `5.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.7` to `0.4.8`" - } - ] - } - }, - { - "version": "4.7.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.4", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.2` to `5.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.6` to `0.4.7`" - } - ] - } - }, - { - "version": "4.7.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.3", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade api-extractor library" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.1` to `5.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.5` to `0.4.6`" - } - ] - } - }, - { - "version": "4.7.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.2", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.2.0` to `5.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.4` to `0.4.5`" - } - ] - } - }, - { - "version": "4.7.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.1", - "date": "Thu, 18 Jan 2018 00:27:23 GMT", - "comments": { - "patch": [ - { - "comment": "Remove deprecated tslint rule \"typeof-compare\"" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.1.3` to `5.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "4.7.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.7.0", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "minor": [ - { - "author": "Ian Clanton-Thuon ", - "commit": "edab484323d9eb4d12cd5c77f0757595105bb7cb", - "comment": "Upgrade TSLint and tslint-microsoft-contrib." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.1.2` to `5.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "4.6.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.6.0", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "minor": [ - { - "author": "pgonzal ", - "commit": "4589070d63c8c1d5d77bfa5e52b4f9fd2734e19f", - "comment": "Add a new setting \"generatePackageTypings\" for the API Extractor task" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.1.1` to `5.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "4.5.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.5.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.1.0` to `5.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "4.5.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.5.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.0.1` to `5.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.26` to `0.4.0`" - } - ] - } - }, - { - "version": "4.4.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.4.1", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `5.0.0` to `5.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.6` to `3.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.25` to `0.3.26`" - } - ] - } - }, - { - "version": "4.4.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.4.0", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "minor": [ - { - "author": "pgonzal ", - "commit": "aa0c67382d4dee0cde40ee84a581dbdcdabe77ef", - "comment": "The ApiExtractor task now expects *.d.ts files instead of *.ts, but includes a compatibility workaround for the common case of src/index.ts" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.7` to `5.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.24` to `0.3.25`" - } - ] - } - }, - { - "version": "4.3.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.3.3", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.6` to `4.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.23` to `0.3.24`" - } - ] - } - }, - { - "version": "4.3.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.3.2", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.5` to `4.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.22` to `0.3.23`" - } - ] - } - }, - { - "version": "4.3.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.3.1", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.4` to `4.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.21` to `0.3.22`" - } - ] - } - }, - { - "version": "4.3.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.3.0", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "minor": [ - { - "author": "Ian Clanton-Thuon ", - "commit": "12a4e112bf218033f4422e95b1107f913abf70c1", - "comment": "Allow the TS task's configuration to be extended on an instance-by-instance basis." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.3` to `4.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.20` to `0.3.21`" - } - ] - } - }, - { - "version": "4.2.18", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.18", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.2` to `4.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.19` to `0.3.20`" - } - ] - } - }, - { - "version": "4.2.17", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.17", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.1` to `4.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.18` to `0.3.19`" - } - ] - } - }, - { - "version": "4.2.16", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.16", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.3.0` to `4.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.17` to `0.3.18`" - } - ] - } - }, - { - "version": "4.2.15", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.15", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.6` to `4.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.16` to `0.3.17`" - } - ] - } - }, - { - "version": "4.2.14", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.14", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.5` to `4.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.15` to `0.3.16`" - } - ] - } - }, - { - "version": "4.2.13", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.13", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.4` to `4.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.14` to `0.3.15`" - } - ] - } - }, - { - "version": "4.2.12", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.12", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.3` to `4.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "4.2.11", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.11", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.2` to `4.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.12` to `~0.3.13`" - } - ] - } - }, - { - "version": "4.2.10", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.10", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.1` to `4.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.11` to `~0.3.12`" - } - ] - } - }, - { - "version": "4.2.9", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.9", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.2.0` to `4.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.10` to `~0.3.11`" - } - ] - } - }, - { - "version": "4.2.8", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.8", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.1.2` to `4.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.9` to `~0.3.10`" - } - ] - } - }, - { - "version": "4.2.7", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.7", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.1.1` to `4.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.8` to `~0.3.9`" - } - ] - } - }, - { - "version": "4.2.6", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.1.0` to `4.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.7` to `~0.3.8`" - } - ] - } - }, - { - "version": "4.2.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.0.1` to `4.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.6` to `~0.3.7`" - } - ] - } - }, - { - "version": "4.2.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `4.0.0` to `4.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.5` to `~0.3.6`" - } - ] - } - }, - { - "version": "4.2.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "3ff332dc81aafca27952120afc1be0788239b741", - "comment": "Updated to use simplified api-extractor interface" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.4.2` to `4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.4` to `~0.3.5`" - } - ] - } - }, - { - "version": "4.2.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "patch": [ - { - "author": "Ian Clanton-Thuon ", - "commit": "abc659beb2646af4be529a064031ae9aa1f9afd9", - "comment": "Fix an error message when the \"module\" property is set to esnext." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.2` to `~0.3.3`" - } - ] - } - }, - { - "version": "4.2.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.3.0` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.0` to `~0.3.1`" - } - ] - } - }, - { - "version": "4.2.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.2.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.6` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.11` to `~0.3.0`" - } - ] - } - }, - { - "version": "4.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.1.0", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "minor": [ - { - "author": "Ian Clanton-Thuon ", - "commit": "45ad3b5af2e7f315995d1b36579dc1e35b012831", - "comment": "Support ESNext module output format and allow a base TypeScript configuration to be set by a build rig." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.10` to `~0.2.11`" - } - ] - } - }, - { - "version": "4.0.7", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.9` to `~0.2.10`" - } - ] - } - }, - { - "version": "4.0.6", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "bb96549aa8508ff627a0cae5ee41ae0251f2777d", - "comment": "Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable'" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.7` to `~0.2.8`" - } - ] - } - }, - { - "version": "4.0.5", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.6` to `~0.2.7`" - } - ] - } - }, - { - "version": "4.0.4", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.4", - "date": "Thu, 07 Sep 2017 00:11:11 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "4b7451b442c2078a96430f7a05caed37101aed52", - "comment": " Add $schema field to all schemas" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.5` to `~0.2.6`" - } - ] - } - }, - { - "version": "4.0.3", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.4` to `~0.2.5`" - } - ] - } - }, - { - "version": "4.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.1.0` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.3` to `~0.2.4`" - } - ] - } - }, - { - "version": "4.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `3.0.0` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.2` to `~0.2.3`" - } - ] - } - }, - { - "version": "4.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v4.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.7` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.1` to `~0.2.2`" - } - ] - } - }, - { - "version": "3.5.3", - "tag": "@microsoft/gulp-core-build-typescript_v3.5.3", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.6` to `2.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.0` to `~0.2.1`" - } - ] - } - }, - { - "version": "3.5.2", - "tag": "@microsoft/gulp-core-build-typescript_v3.5.2", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.5` to `2.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.1.3` to `~0.2.0`" - } - ] - } - }, - { - "version": "3.5.1", - "tag": "@microsoft/gulp-core-build-typescript_v3.5.1", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.4` to `2.3.5`" - } - ] - } - }, - { - "version": "3.5.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.5.0", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade to tslint 5.6.0" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.3` to `2.3.4`" - } - ] - } - }, - { - "version": "3.4.2", - "tag": "@microsoft/gulp-core-build-typescript_v3.4.2", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.2` to `2.3.3`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/gulp-core-build-typescript_v3.4.1", - "date": "Wed, 16 Aug 2017 23:16:55 GMT", - "comments": { - "patch": [ - { - "comment": "Publish" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.4.0", - "date": "Wed, 16 Aug 2017 13:04:08 GMT", - "comments": { - "minor": [ - { - "comment": "Include the no-unused-variable TSLint rule to bring back the \"no-unused-import\" functionality. Remove no-unused-parameters default TSConfig option to be consistent with the TSLint no-unused-variable behavior." - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/gulp-core-build-typescript_v3.3.2", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.1` to `2.3.2`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/gulp-core-build-typescript_v3.3.1", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `2.3.0` to `2.3.1`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.3.0", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=2.2.0 <3.0.0` to `>=2.2.0 <3.0.0`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.2.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - } - ] - } - }, - { - "version": "3.1.5", - "tag": "@microsoft/gulp-core-build-typescript_v3.1.5", - "date": "Wed, 21 Jun 2017 04:19:35 GMT", - "comments": { - "patch": [ - { - "comment": "Add missing API Extractor release tags" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.3 <3.0.0` to `>=2.5.5 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=2.0.10 <3.0.0` to `>=2.2.0 <3.0.0`" - } - ] - } - }, - { - "version": "3.1.3", - "tag": "@microsoft/gulp-core-build-typescript_v3.1.3", - "date": "Fri, 16 Jun 2017 01:21:40 GMT", - "comments": { - "patch": [ - { - "comment": "Upgraded api-extractor dependency" - } - ] - } - }, - { - "version": "3.1.2", - "tag": "@microsoft/gulp-core-build-typescript_v3.1.2", - "date": "Fri, 16 Jun 2017 01:04:08 GMT", - "comments": { - "patch": [ - { - "comment": "Fix issue where TypeScriptTask did not allow you to set a target other than \"commonjs\"" - } - ] - } - }, - { - "version": "3.1.1", - "tag": "@microsoft/gulp-core-build-typescript_v3.1.1", - "date": "Fri, 28 Apr 2017 01:03:54 GMT", - "comments": { - "patch": [ - { - "comment": "Bugfix: Update TypeScriptConfiguration to allow setting a custom version of typescript compiler." - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.1.0", - "date": "Mon, 24 Apr 2017 22:01:17 GMT", - "comments": { - "minor": [ - { - "comment": "Adding `libES6Dir` setting to taskConfig to optionally output es6 modules." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.5.0 <3.0.0`" - } - ] - } - }, - { - "version": "3.0.4", - "tag": "@microsoft/gulp-core-build-typescript_v3.0.4", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=2.0.3 <3.0.0` to `>=2.0.3 <3.0.0`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/gulp-core-build-typescript_v3.0.3", - "date": "Tue, 18 Apr 2017 23:41:42 GMT", - "comments": { - "patch": [ - { - "comment": "API Extractor now uses Gulp-Typescript to generate compiler options." - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/gulp-core-build-typescript_v3.0.2", - "date": "Fri, 07 Apr 2017 21:43:16 GMT", - "comments": { - "patch": [ - { - "comment": "Adjusted the version specifier for typescript to ~2.2.2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=2.0.1 <3.0.0` to `>=2.0.2 <3.0.0`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v3.0.1", - "date": "Wed, 05 Apr 2017 13:01:40 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing the way the TSLint task is configured to allow removal of existing rules." - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build-typescript_v3.0.0", - "date": "Mon, 20 Mar 2017 21:52:20 GMT", - "comments": { - "major": [ - { - "comment": "Updating typescript, gulp-typescript, and tslint." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.2 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.19 <2.0.0` to `>=2.0.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.4.1", - "tag": "@microsoft/gulp-core-build-typescript_v2.4.1", - "date": "Mon, 20 Mar 2017 04:20:13 GMT", - "comments": { - "patch": [ - { - "comment": "Reverting change." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.18 <2.0.0` to `>=1.1.19 <2.0.0`" - } - ] - } - }, - { - "version": "2.4.0", - "tag": "@microsoft/gulp-core-build-typescript_v2.4.0", - "date": "Sun, 19 Mar 2017 19:10:30 GMT", - "comments": { - "minor": [ - { - "comment": "Updating typescript, gulp-typescript, and tslint." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.14 <2.0.0` to `>=1.1.16 <2.0.0`" - } - ] - } - }, - { - "version": "2.3.0", - "tag": "@microsoft/gulp-core-build-typescript_v2.3.0", - "date": "Thu, 16 Mar 2017 19:02:22 GMT", - "comments": { - "minor": [ - { - "comment": "Write the TSLint configuration file after executing the task." - } - ] - } - }, - { - "version": "2.2.6", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.6", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.14 <2.0.0` to `>=1.1.14 <2.0.0`" - } - ] - } - }, - { - "version": "2.2.5", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.5", - "date": "Tue, 31 Jan 2017 20:32:37 GMT", - "comments": { - "patch": [ - { - "comment": "Make loadSchema public instead of protected." - } - ] - } - }, - { - "version": "2.2.4", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.4", - "date": "Tue, 31 Jan 2017 01:55:09 GMT", - "comments": { - "patch": [ - { - "comment": "Introduce schema for TsLintTask, TypeScriptTask" - } - ] - } - }, - { - "version": "2.2.3", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.3", - "date": "Fri, 27 Jan 2017 20:04:15 GMT", - "comments": { - "patch": [ - { - "comment": "Added external json docs loading before analyzing API" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.4 <2.0.0` to `>=1.1.4 <2.0.0`" - } - ] - } - }, - { - "version": "2.2.2", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.2", - "date": "Fri, 27 Jan 2017 02:35:10 GMT", - "comments": { - "patch": [ - { - "comment": "Added external-api-json folder with external types definitions. Added gulp task to run ApiExtractor on external types defintions." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.1.3 <2.0.0` to `>=1.1.4 <2.0.0`" - } - ] - } - }, - { - "version": "2.2.1", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.1", - "date": "Thu, 19 Jan 2017 02:37:34 GMT", - "comments": { - "patch": [ - { - "comment": "Updating the tsconfig to give compiler options as enums." - } - ] - } - }, - { - "version": "2.2.0", - "tag": "@microsoft/gulp-core-build-typescript_v2.2.0", - "date": "Wed, 18 Jan 2017 21:40:58 GMT", - "comments": { - "minor": [ - { - "comment": "Refactor the API-Extractor to use the same config as the TypeScriptTask" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.1 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.1", - "tag": "@microsoft/gulp-core-build-typescript_v2.1.1", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "patch": [ - { - "comment": "Add a schema for the api-extractor task and change the name." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=1.0.0 <2.0.0` to `>=1.0.1 <2.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/gulp-core-build-typescript_v2.1.0", - "date": "Wed, 11 Jan 2017 14:11:26 GMT", - "comments": { - "minor": [ - { - "comment": "Adding an API Extractor task." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/api-extractor\" from `>=0.0.1 <1.0.0` to `>=1.0.0 <2.0.0`" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build-typescript_v2.0.1", - "date": "Wed, 04 Jan 2017 03:02:12 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing TSLint task by removing some deprecated rules (\"label-undefined”, \"no-duplicate-key\", and \"no-unreachable\") and setting the \"noUnusedParameters\" and \"noUnusedLocals\" TS compiler options to cover the deprecated \"no-unused-variable\"." - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build-typescript/CHANGELOG.md b/core-build/gulp-core-build-typescript/CHANGELOG.md deleted file mode 100644 index 5e957a3ea7f..00000000000 --- a/core-build/gulp-core-build-typescript/CHANGELOG.md +++ /dev/null @@ -1,1561 +0,0 @@ -# Change Log - @microsoft/gulp-core-build-typescript - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 8.4.6 -Wed, 18 Mar 2020 15:07:47 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 8.4.5 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 8.4.4 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 8.4.3 -Fri, 24 Jan 2020 00:27:39 GMT - -### Patches - -- Extract GCBTerminalProvider to gulp-core-build. - -## 8.4.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 8.4.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 8.4.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 8.3.16 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 8.3.15 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 8.3.14 -Sat, 11 Jan 2020 05:18:24 GMT - -*Version update only* - -## 8.3.13 -Thu, 09 Jan 2020 06:44:12 GMT - -*Version update only* - -## 8.3.12 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 8.3.11 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 8.3.10 -Tue, 03 Dec 2019 03:17:43 GMT - -*Version update only* - -## 8.3.9 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 8.3.8 -Wed, 20 Nov 2019 06:14:28 GMT - -*Version update only* - -## 8.3.7 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 8.3.6 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 8.3.5 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 8.3.4 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 8.3.3 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 8.3.2 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 8.3.1 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 8.3.0 -Mon, 21 Oct 2019 05:22:43 GMT - -### Minor changes - -- Add support for ESLint+TypeScript - -## 8.2.6 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 8.2.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 8.2.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 8.2.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 8.2.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 8.2.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 8.2.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 8.1.35 -Fri, 20 Sep 2019 21:27:22 GMT - -### Patches - -- Fix an issue where api-extractor warnings weren't being reported. - -## 8.1.34 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 8.1.33 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 8.1.32 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 8.1.31 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 8.1.30 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 8.1.29 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 8.1.28 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 8.1.27 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 8.1.26 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 8.1.25 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 8.1.24 -Tue, 23 Jul 2019 19:14:38 GMT - -*Version update only* - -## 8.1.23 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 8.1.22 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 8.1.21 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 8.1.20 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 8.1.19 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 8.1.18 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 8.1.17 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 8.1.16 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 8.1.15 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 8.1.14 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 8.1.13 -Tue, 04 Jun 2019 05:51:53 GMT - -*Version update only* - -## 8.1.12 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 8.1.11 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 8.1.10 -Mon, 06 May 2019 20:46:21 GMT - -*Version update only* - -## 8.1.9 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 8.1.8 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 8.1.7 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 8.1.6 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 8.1.5 -Fri, 12 Apr 2019 06:13:16 GMT - -*Version update only* - -## 8.1.4 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 8.1.3 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 8.1.2 -Mon, 08 Apr 2019 19:12:52 GMT - -*Version update only* - -## 8.1.1 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 8.1.0 -Fri, 05 Apr 2019 04:16:17 GMT - -### Minor changes - -- Update to use the new rush-stack-compiler contract for API Extractor 7 - -## 8.0.23 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 8.0.22 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 8.0.21 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 8.0.20 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 8.0.19 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 8.0.18 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 8.0.17 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 8.0.16 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 8.0.15 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 8.0.14 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 8.0.13 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 8.0.12 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 8.0.11 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 8.0.10 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 8.0.9 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 8.0.8 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 8.0.7 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 8.0.6 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 8.0.5 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 8.0.4 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 8.0.3 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 8.0.2 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 8.0.1 -Wed, 30 Jan 2019 20:49:11 GMT - -### Patches - -- Update dependency on changed API in RSC - -## 8.0.0 -Sat, 19 Jan 2019 03:47:47 GMT - -### Breaking changes - -- Update api extractor task to use api extractor's config file. - -### Minor changes - -- Upgrade to use API Extractor 7 beta - -## 7.4.8 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 7.4.7 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 7.4.6 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 7.4.5 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 7.4.4 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 7.4.3 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 7.4.2 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 7.4.1 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 7.4.0 -Fri, 30 Nov 2018 23:34:57 GMT - -### Minor changes - -- Allow custom arguments to be passed to the tsc command. - -## 7.3.1 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 7.3.0 -Thu, 29 Nov 2018 00:35:38 GMT - -### Minor changes - -- Update rush-stack-compiler resolution to find a package following the "rush-stack-compiler-" naming convention. - -## 7.2.7 -Wed, 28 Nov 2018 19:29:54 GMT - -*Version update only* - -## 7.2.6 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 7.2.5 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 7.2.4 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 7.2.3 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 7.2.2 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 7.2.1 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 7.2.0 -Mon, 05 Nov 2018 17:04:24 GMT - -### Minor changes - -- Update GCB-TS to ship with a default rush-stack-compiler with TS 2.4. - -## 7.1.2 -Thu, 01 Nov 2018 21:33:51 GMT - -### Patches - -- Fix a regression where @microsoft/rush-stack-compiler could not compile itself - -## 7.1.1 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 7.1.0 -Wed, 31 Oct 2018 21:17:50 GMT - -### Minor changes - -- Update the way rush-stack-compiler is resolved. Now it's resolved by looking at the "extends" properties of tsconfig.json - -## 7.0.3 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 7.0.2 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 7.0.1 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 7.0.0 -Sat, 27 Oct 2018 00:26:56 GMT - -### Breaking changes - -- Moving logic into rush-stack-compiler. - -## 6.1.12 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 6.1.11 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 6.1.10 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 6.1.9 -Thu, 18 Oct 2018 05:30:14 GMT - -### Patches - -- Replace deprecated dependency gulp-util - -## 6.1.8 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 6.1.7 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 6.1.6 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 6.1.5 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 6.1.4 -Tue, 09 Oct 2018 06:58:01 GMT - -*Version update only* - -## 6.1.3 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 6.1.2 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 6.1.1 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 6.1.0 -Wed, 26 Sep 2018 21:39:40 GMT - -### Minor changes - -- Expose new api-extractor skipLibCheck option. - -## 6.0.5 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 6.0.4 -Mon, 24 Sep 2018 16:04:28 GMT - -### Patches - -- Fixed overridePackagePath not loading correct version of package. - -## 6.0.3 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 6.0.2 -Thu, 20 Sep 2018 23:57:21 GMT - -### Patches - -- Include support for the typescriptCompilerFolder api-extractor option. - -## 6.0.1 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 6.0.0 -Mon, 10 Sep 2018 23:23:01 GMT - -### Breaking changes - -- Remove the old TypeScript, TSLint, Text, and RemoveTripleSlash tasks. - -## 5.0.2 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 5.0.1 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 5.0.0 -Mon, 03 Sep 2018 16:04:45 GMT - -### Breaking changes - -- Replace the old api-extractor task with the new one that uses tsconfig.json instead of a runtime configuration. - -## 4.11.12 -Thu, 30 Aug 2018 22:47:34 GMT - -### Patches - -- Include defaultTslint in npm package. - -## 4.11.11 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 4.11.10 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 4.11.9 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 4.11.8 -Wed, 29 Aug 2018 06:36:50 GMT - -### Patches - -- Fixing minor path issue. - -## 4.11.7 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 4.11.6 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 4.11.5 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 4.11.4 -Tue, 21 Aug 2018 16:04:38 GMT - -*Version update only* - -## 4.11.3 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 4.11.2 -Thu, 09 Aug 2018 16:04:24 GMT - -### Patches - -- Update lodash. - -## 4.11.1 -Tue, 07 Aug 2018 22:27:31 GMT - -*Version update only* - -## 4.11.0 -Thu, 26 Jul 2018 23:53:43 GMT - -### Minor changes - -- Include an option to strip comments from produced JS files in the TSC task. - -## 4.10.5 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 4.10.4 -Wed, 25 Jul 2018 21:02:57 GMT - -### Patches - -- Fix an issue where the TscTask and TslintTasks where invoking the wrong version of Node.js - -## 4.10.3 -Tue, 17 Jul 2018 16:02:52 GMT - -*Version update only* - -## 4.10.2 -Fri, 13 Jul 2018 19:04:50 GMT - -### Patches - -- Fix an issue where "spawnSync" may not be able to resolve node. - -## 4.10.1 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 4.10.0 -Fri, 29 Jun 2018 02:56:51 GMT - -### Minor changes - -- Inclusion of three new tasks designed to use as minimal behavior as possible to run tsc, tslint, and api-extractor. - -## 4.9.19 -Sat, 23 Jun 2018 02:21:20 GMT - -*Version update only* - -## 4.9.18 -Fri, 22 Jun 2018 16:05:15 GMT - -### Patches - -- Fixed mutation on tsConfigFile resulting in tslint error - -## 4.9.17 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 4.9.16 -Tue, 19 Jun 2018 19:35:11 GMT - -*Version update only* - -## 4.9.15 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 4.9.14 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 4.9.13 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 4.9.12 -Tue, 15 May 2018 00:18:10 GMT - -*Version update only* - -## 4.9.11 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 4.9.10 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 4.9.9 -Tue, 01 May 2018 22:03:20 GMT - -*Version update only* - -## 4.9.8 -Fri, 27 Apr 2018 03:04:32 GMT - -*Version update only* - -## 4.9.7 -Fri, 20 Apr 2018 16:06:11 GMT - -### Patches - -- Fix logging warnings in TypeScript config - -## 4.9.6 -Thu, 19 Apr 2018 21:25:56 GMT - -*Version update only* - -## 4.9.5 -Thu, 19 Apr 2018 17:02:06 GMT - -### Patches - -- Expose three more api-extractor config parameters in gulp-core-build-typescript - -## 4.9.4 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 4.9.3 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 4.9.2 -Tue, 27 Mar 2018 01:34:25 GMT - -*Version update only* - -## 4.9.1 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 4.9.0 -Sun, 25 Mar 2018 01:26:19 GMT - -### Minor changes - -- For the API Extractor task config file, the "generatePackageTypings" setting was renamed to "generateDtsRollup" -- Add a new GCB option dtsRollupTrimming which corresponds to the new "trimming" flag for API Extractor - -## 4.8.1 -Fri, 23 Mar 2018 00:34:53 GMT - -*Version update only* - -## 4.8.0 -Thu, 22 Mar 2018 18:34:13 GMT - -### Minor changes - -- Add a `libESNextFolder` option - -## 4.7.22 -Tue, 20 Mar 2018 02:44:45 GMT - -*Version update only* - -## 4.7.21 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 4.7.20 -Thu, 15 Mar 2018 20:00:50 GMT - -### Patches - -- Fix an issue where the column number for typescript errors was off by one - -## 4.7.19 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 4.7.18 -Tue, 13 Mar 2018 23:11:32 GMT - -### Patches - -- Update gulp-sourcemaps. - -## 4.7.17 -Mon, 12 Mar 2018 20:36:19 GMT - -*Version update only* - -## 4.7.16 -Tue, 06 Mar 2018 17:04:51 GMT - -*Version update only* - -## 4.7.15 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 4.7.14 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 4.7.13 -Wed, 21 Feb 2018 22:04:19 GMT - -### Patches - -- Fix an issue where the line number for typescript errors were off by one. - -## 4.7.12 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 4.7.11 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 4.7.10 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 4.7.9 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.7.8 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.7.7 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 4.7.6 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 4.7.5 -Fri, 26 Jan 2018 00:36:51 GMT - -### Patches - -- Add some missing @types dependencies to the package.json - -## 4.7.4 -Tue, 23 Jan 2018 17:05:28 GMT - -*Version update only* - -## 4.7.3 -Thu, 18 Jan 2018 03:23:46 GMT - -### Patches - -- Upgrade api-extractor library - -## 4.7.2 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 4.7.1 -Thu, 18 Jan 2018 00:27:23 GMT - -### Patches - -- Remove deprecated tslint rule "typeof-compare" - -## 4.7.0 -Wed, 17 Jan 2018 10:49:31 GMT - -### Minor changes - -- Upgrade TSLint and tslint-microsoft-contrib. - -## 4.6.0 -Fri, 12 Jan 2018 03:35:22 GMT - -### Minor changes - -- Add a new setting "generatePackageTypings" for the API Extractor task - -## 4.5.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 4.5.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 4.4.1 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 4.4.0 -Sun, 07 Jan 2018 05:12:08 GMT - -### Minor changes - -- The ApiExtractor task now expects *.d.ts files instead of *.ts, but includes a compatibility workaround for the common case of src/index.ts - -## 4.3.3 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 4.3.2 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 4.3.1 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 4.3.0 -Tue, 12 Dec 2017 03:33:26 GMT - -### Minor changes - -- Allow the TS task's configuration to be extended on an instance-by-instance basis. - -## 4.2.18 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 4.2.17 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 4.2.16 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 4.2.15 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 4.2.14 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 4.2.13 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 4.2.12 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 4.2.11 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 4.2.10 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 4.2.9 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 4.2.8 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 4.2.7 -Tue, 24 Oct 2017 18:17:12 GMT - -*Version update only* - -## 4.2.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 4.2.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 4.2.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 4.2.3 -Fri, 20 Oct 2017 01:04:44 GMT - -### Patches - -- Updated to use simplified api-extractor interface - -## 4.2.2 -Thu, 05 Oct 2017 01:05:02 GMT - -### Patches - -- Fix an error message when the "module" property is set to esnext. - -## 4.2.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 4.2.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 4.1.0 -Wed, 20 Sep 2017 22:10:17 GMT - -### Minor changes - -- Support ESNext module output format and allow a base TypeScript configuration to be set by a build rig. - -## 4.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 4.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -### Patches - -- Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable' - -## 4.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 4.0.4 -Thu, 07 Sep 2017 00:11:11 GMT - -### Patches - -- Add $schema field to all schemas - -## 4.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 4.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 4.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 4.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 3.5.3 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 3.5.2 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 3.5.1 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 3.5.0 -Thu, 24 Aug 2017 01:04:33 GMT - -### Minor changes - -- Upgrade to tslint 5.6.0 - -## 3.4.2 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 3.4.1 -Wed, 16 Aug 2017 23:16:55 GMT - -### Patches - -- Publish - -## 3.4.0 -Wed, 16 Aug 2017 13:04:08 GMT - -### Minor changes - -- Include the no-unused-variable TSLint rule to bring back the "no-unused-import" functionality. Remove no-unused-parameters default TSConfig option to be consistent with the TSLint no-unused-variable behavior. - -## 3.3.2 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 3.3.1 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 3.3.0 -Tue, 25 Jul 2017 20:03:31 GMT - -### Minor changes - -- Upgrade to TypeScript 2.4 - -## 3.2.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 3.1.5 -Wed, 21 Jun 2017 04:19:35 GMT - -### Patches - -- Add missing API Extractor release tags - -## 3.1.3 -Fri, 16 Jun 2017 01:21:40 GMT - -### Patches - -- Upgraded api-extractor dependency - -## 3.1.2 -Fri, 16 Jun 2017 01:04:08 GMT - -### Patches - -- Fix issue where TypeScriptTask did not allow you to set a target other than "commonjs" - -## 3.1.1 -Fri, 28 Apr 2017 01:03:54 GMT - -### Patches - -- Bugfix: Update TypeScriptConfiguration to allow setting a custom version of typescript compiler. - -## 3.1.0 -Mon, 24 Apr 2017 22:01:17 GMT - -### Minor changes - -- Adding `libES6Dir` setting to taskConfig to optionally output es6 modules. - -## 3.0.4 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 3.0.3 -Tue, 18 Apr 2017 23:41:42 GMT - -### Patches - -- API Extractor now uses Gulp-Typescript to generate compiler options. - -## 3.0.2 -Fri, 07 Apr 2017 21:43:16 GMT - -### Patches - -- Adjusted the version specifier for typescript to ~2.2.2 - -## 3.0.1 -Wed, 05 Apr 2017 13:01:40 GMT - -### Patches - -- Fixing the way the TSLint task is configured to allow removal of existing rules. - -## 3.0.0 -Mon, 20 Mar 2017 21:52:20 GMT - -### Breaking changes - -- Updating typescript, gulp-typescript, and tslint. - -## 2.4.1 -Mon, 20 Mar 2017 04:20:13 GMT - -### Patches - -- Reverting change. - -## 2.4.0 -Sun, 19 Mar 2017 19:10:30 GMT - -### Minor changes - -- Updating typescript, gulp-typescript, and tslint. - -## 2.3.0 -Thu, 16 Mar 2017 19:02:22 GMT - -### Minor changes - -- Write the TSLint configuration file after executing the task. - -## 2.2.6 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.2.5 -Tue, 31 Jan 2017 20:32:37 GMT - -### Patches - -- Make loadSchema public instead of protected. - -## 2.2.4 -Tue, 31 Jan 2017 01:55:09 GMT - -### Patches - -- Introduce schema for TsLintTask, TypeScriptTask - -## 2.2.3 -Fri, 27 Jan 2017 20:04:15 GMT - -### Patches - -- Added external json docs loading before analyzing API - -## 2.2.2 -Fri, 27 Jan 2017 02:35:10 GMT - -### Patches - -- Added external-api-json folder with external types definitions. Added gulp task to run ApiExtractor on external types defintions. - -## 2.2.1 -Thu, 19 Jan 2017 02:37:34 GMT - -### Patches - -- Updating the tsconfig to give compiler options as enums. - -## 2.2.0 -Wed, 18 Jan 2017 21:40:58 GMT - -### Minor changes - -- Refactor the API-Extractor to use the same config as the TypeScriptTask - -## 2.1.1 -Fri, 13 Jan 2017 06:46:05 GMT - -### Patches - -- Add a schema for the api-extractor task and change the name. - -## 2.1.0 -Wed, 11 Jan 2017 14:11:26 GMT - -### Minor changes - -- Adding an API Extractor task. - -## 2.0.1 -Wed, 04 Jan 2017 03:02:12 GMT - -### Patches - -- Fixing TSLint task by removing some deprecated rules ("label-undefined”, "no-duplicate-key", and "no-unreachable") and setting the "noUnusedParameters" and "noUnusedLocals" TS compiler options to cover the deprecated "no-unused-variable". - diff --git a/core-build/gulp-core-build-typescript/LICENSE b/core-build/gulp-core-build-typescript/LICENSE deleted file mode 100644 index 9dbf4d9fc5a..00000000000 --- a/core-build/gulp-core-build-typescript/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build-typescript - -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/core-build/gulp-core-build-typescript/README.md b/core-build/gulp-core-build-typescript/README.md deleted file mode 100644 index 086a4f2e28e..00000000000 --- a/core-build/gulp-core-build-typescript/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# @microsoft/gulp-core-build-typescript - -`gulp-core-build-typescript` contains `gulp-core-build` subtasks for compiling and linting TypeScript code. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-typescript.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-typescript) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build-typescript.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build-typescript) -[![Dependencies](https://david-dm.org/Microsoft/gulp-core-build-typescript.svg)](https://david-dm.org/Microsoft/gulp-core-build-typescript) - -# TypescriptTask -## Usage -The task for building TypeScript into JavaScript. - -## Config -See the `ITypeScriptTaskConfig` interface for the definition. - -### failBuildOnErrors -Fails the build when errors occur. - -Default: `true` - -### sourceMatch -An array of glob matches for files to be included in the build. - -Default: -```javascript -[ - 'src/**/*.ts', - 'src/**/*.tsx', - 'typings/main/**/*.ts', - 'typings/main.d.ts', - 'typings/tsd.d.ts', - 'typings/index.d.ts' -] -``` - -### staticMatch -Array of glob matches for files that should by passed through (copied) to the build output. - -Default: -```javascript -[ - 'src/**/*.js', - 'src/**/*.json', - 'src/**/*.jsx' -] -``` - -### reporter -Custom TypeScript reporter. - -Should be an interface conforming to: -```typescript -interface IErrorReporter { - error: (error: ITypeScriptErrorObject) => void -} -``` - -Default: a custom function which writes errors to the console. - -### typescript -Optional override of the typescript compiler. Set this to the result of require('typescript'). - -Default: `undefined` - -### removeCommentsFromJavaScript -Removes comments from all generated `.js` files. Will **not** remove comments from generated `.d.ts` files. - -Default: `false` - -### emitSourceMaps -If true, creates sourcemap files which are useful for debugging. - -Default: `true` - -# TSLintTask -## Usage -The task for linting the TypeScript code. - -By default, it includes a cache, such that files which have not been updated since the last linting -are not checked again, unless the config or tslint version has changed. - -## Config -See the `ITSLintTaskConfig` interface for the definition. - -### lintConfig -The tslint configuration object. - -Default: `{}` - -### rulesDirectory -Directories to search for custom linter rules. An array of glob expressions. - -Default: the tslint-microsoft-contrib directory - -### sourceMatch -Provides the glob matches for files to be analyzed. - -Default: `['src/**/*.ts', 'src/**/*.tsx']` - -### reporter -A function which reports errors to the proper location. It should conform to the following interface: - -`((result: lintTypes.LintResult, file: Vinyl, options: ITSLintTaskConfig) => void;)` - -Defaults to using the base GulpTask's this.fileError() function. - -### displayAsWarning -If true, displays warnings as errors. If the reporter function is overwritten, it should reference -this flag. - -Default: `false` - -### removeExistingRules -If true, the lintConfig rules which were previously set will be removed. This flag is useful -for ensuring that there are no rules activated from previous calls to setConfig(). - -Default: `false` - -### useDefaultConfigAsBase -If false, does not use a default tslint configuration as the basis for creating the list of active rules. - -Default: `true` - -# RemoveTripleSlashReferencesTask -## Usage -Removes any `/// ` entries from compiled D.TS files. -This helps mitigate an issue with duplicated typings in TS 1.8. - -## Config -*This task has no configuration options.* - -# TextTask -Converts text files into JavaScript. - -## Usage -## Config -See the `ITextTaskConfig` interface for the definition. - -### textMatch -Glob matches for files that should be converted into modules. - -Default: `['src/**/*.txt']` - -# Usage -To use these tasks in your build setup, simply import the package and add the task to a build task group. - -# Examples -Some examples of build packages that use this task: - -* [@microsoft/web-library-build](../web-library-build) -* [@microsoft/node-library-build](../node-library-build) - -# Configuring task options - -Use the standard "setConfig" method on task instances to set their configuration options. Example: - -```typescript -import { typescript } from '@microsoft/gulp-core-build-typescript'; - -typescript.setConfig({ - typescript: require('typescript') -}); -``` - -# Related projects - -[@microsoft/gulp-core-build](https://github.com/microsoft/gulp-core-build) - An abstraction around gulp that adds simplified serial/parallel task execution and a formal base task interface. - -[typescript](https://github.com/microsoft/typescript) - The TypeScript compiler. - -# License - -[MIT](https://github.com/microsoft/gulp-core-build-typescript/blob/master/LICENSE) diff --git a/core-build/gulp-core-build-typescript/config/api-extractor.json b/core-build/gulp-core-build-typescript/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/gulp-core-build-typescript/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/gulp-core-build-typescript/gulpfile.js b/core-build/gulp-core-build-typescript/gulpfile.js deleted file mode 100644 index 363f0d45904..00000000000 --- a/core-build/gulp-core-build-typescript/gulpfile.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/core-build/gulp-core-build-typescript/package.json b/core-build/gulp-core-build-typescript/package.json deleted file mode 100644 index f6063f8d7d1..00000000000 --- a/core-build/gulp-core-build-typescript/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-typescript", - "version": "8.4.6", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build-typescript" - }, - "scripts": { - "build": "gulp --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@rushstack/node-core-library": "3.19.5", - "@types/node": "10.17.13", - "decomment": "~0.9.1", - "glob": "~7.0.5", - "glob-escape": "~0.0.1", - "resolve": "1.8.1" - }, - "devDependencies": { - "@microsoft/api-extractor": "7.7.10", - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.1": "0.9.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/glob": "7.1.1", - "@types/resolve": "0.0.8", - "gulp": "~4.0.2", - "typescript": "~3.2.4" - } -} diff --git a/core-build/gulp-core-build-typescript/src/ApiExtractorTask.ts b/core-build/gulp-core-build-typescript/src/ApiExtractorTask.ts deleted file mode 100644 index 2fc9f745372..00000000000 --- a/core-build/gulp-core-build-typescript/src/ApiExtractorTask.ts +++ /dev/null @@ -1,75 +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 { IBuildConfig } from '@microsoft/gulp-core-build'; -import { - JsonFile, - FileSystem, - JsonObject -} from '@rushstack/node-core-library'; -import { ExtractorConfig, IExtractorInvokeOptions } from '@microsoft/api-extractor'; -import { ApiExtractorRunner as TApiExtractorRunner } from '@microsoft/rush-stack-compiler-3.1'; - -import { RSCTask, IRSCTaskConfig } from './RSCTask'; - -/** @public */ -export interface IApiExtractorTaskConfig extends IRSCTaskConfig { -} - -/** - * The ApiExtractorTask uses the api-extractor tool to analyze a project for public APIs. api-extractor will detect - * common problems and generate a report of the exported public API. The task uses the entry point of a project to - * find the aliased exports of the project. An api-extractor.ts file is generated for the project in the temp folder. - * @public - */ -export class ApiExtractorTask extends RSCTask { - public constructor() { - super( - 'api-extractor', - {} - ); - } - - public loadSchema(): JsonObject { - return JsonFile.load(path.resolve(__dirname, 'schemas', 'api-extractor.schema.json')); - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - return FileSystem.exists(this._getApiExtractorConfigFilePath(buildConfig.rootPath)); - } - - public executeTask(): Promise { - this.initializeRushStackCompiler(); - - const extractorOptions: IExtractorInvokeOptions = { - localBuild: !this.buildConfig.production - }; - - const ApiExtractorRunner: typeof TApiExtractorRunner = this._rushStackCompiler.ApiExtractorRunner; - const extractorConfig: ExtractorConfig = ApiExtractorRunner.apiExtractor.ExtractorConfig.loadFileAndPrepare( - this._getApiExtractorConfigFilePath(this.buildConfig.rootPath) - ); - - const apiExtractorRunner: TApiExtractorRunner = new ApiExtractorRunner( - { - fileError: this.fileError.bind(this), - fileWarning: this.fileWarning.bind(this) - }, - extractorConfig, - extractorOptions, - this.buildFolder, - this._terminalProvider - ); - - return apiExtractorRunner.invoke(); - } - - protected _getConfigFilePath(): string { - return path.join('.', 'config', 'gcb-api-extractor.json'); // There aren't config options specific to this task - } - - private _getApiExtractorConfigFilePath(rootPath: string): string { - return path.resolve(rootPath, 'config', 'api-extractor.json'); - } -} diff --git a/core-build/gulp-core-build-typescript/src/LintCmdTask.ts b/core-build/gulp-core-build-typescript/src/LintCmdTask.ts deleted file mode 100644 index cbcc31c6d1a..00000000000 --- a/core-build/gulp-core-build-typescript/src/LintCmdTask.ts +++ /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. - -import * as path from 'path'; -import { JsonFile, JsonObject } from '@rushstack/node-core-library'; -import { LintRunner as TLintRunner } from '@microsoft/rush-stack-compiler-3.1'; - -import { - RSCTask, - IRSCTaskConfig -} from './RSCTask'; - -/** - * @public - */ -export interface ILintCmdTaskConfig extends IRSCTaskConfig { - /** - * If true, displays warnings as errors. Defaults to false. - */ - displayAsError?: boolean; -} - -/** - * @public - */ -export class LintCmdTask extends RSCTask { - public constructor() { - super( - 'lint', - { - displayAsError: false - } - ); - } - - public loadSchema(): JsonObject { - return JsonFile.load(path.resolve(__dirname, 'schemas', 'lint-cmd.schema.json')); - } - - public executeTask(): Promise { - this.initializeRushStackCompiler(); - - const lintRunner: TLintRunner = new this._rushStackCompiler.LintRunner( - { - displayAsError: this.taskConfig.displayAsError, - - fileError: this.fileError.bind(this), - fileWarning: this.fileWarning.bind(this) - }, - this.buildFolder, - this._terminalProvider - ); - - return lintRunner.invoke(); - } -} diff --git a/core-build/gulp-core-build-typescript/src/RSCTask.ts b/core-build/gulp-core-build-typescript/src/RSCTask.ts deleted file mode 100644 index cda27c50588..00000000000 --- a/core-build/gulp-core-build-typescript/src/RSCTask.ts +++ /dev/null @@ -1,202 +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 resolve from 'resolve'; - -import { - JsonFile, - IPackageJson, - FileSystem, - PackageJsonLookup, - Terminal -} from '@rushstack/node-core-library'; -import { - GulpTask, - GCBTerminalProvider -} from '@microsoft/gulp-core-build'; -import * as TRushStackCompiler from '@microsoft/rush-stack-compiler-3.1'; - -export interface IRSCTaskConfig extends Object { - buildDirectory: string; - - allowBuiltinCompiler: boolean; -} - -interface ITsconfig { - extends?: string; -} - -export abstract class RSCTask extends GulpTask { - - // For a given folder that contains a tsconfig.json file, return the absolute path of the folder - // containing "@microsoft/rush-stack-compiler-*" - private static _rushStackCompilerPackagePathCache: Map = new Map(); - - private static __packageJsonLookup: PackageJsonLookup | undefined; - - private static get _packageJsonLookup(): PackageJsonLookup { - if (!RSCTask.__packageJsonLookup) { - RSCTask.__packageJsonLookup = new PackageJsonLookup(); - } - - return RSCTask.__packageJsonLookup; - } - - protected _terminalProvider: GCBTerminalProvider = new GCBTerminalProvider(this); - protected _terminal: Terminal = new Terminal(this._terminalProvider); - - /** - * @internal - */ - protected _rushStackCompiler: typeof TRushStackCompiler; - - private get _rushStackCompilerPackagePath(): string { - if (!RSCTask._rushStackCompilerPackagePathCache.has(this.buildFolder)) { - const projectTsconfigPath: string = path.join(this.buildFolder, 'tsconfig.json'); - - const visitedTsconfigPaths: Set = new Set(); - let compilerPath: string; - try { - compilerPath = this._resolveRushStackCompilerFromTsconfig(projectTsconfigPath, visitedTsconfigPaths); - } catch (e) { - if (this.taskConfig.allowBuiltinCompiler) { - this._terminal.writeVerboseLine( - 'Unable to resolve rush-stack-compiler from tsconfig.json. Using built-in compiler' - ); - const builtInCompilerPath: string | undefined = RSCTask._packageJsonLookup.tryGetPackageFolderFor( - require.resolve('@microsoft/rush-stack-compiler-3.2') - ); - if (!builtInCompilerPath) { - throw new Error( - 'Unable to resolve built-in compiler. Ensure @microsoft/gulp-core-build-typescript is correctly installed' - ); - } - - compilerPath = builtInCompilerPath; - } else { - throw e; - } - } - - RSCTask._rushStackCompilerPackagePathCache.set( - this.buildFolder, - compilerPath - ); - } - - return RSCTask._rushStackCompilerPackagePathCache.get(this.buildFolder)!; - } - - protected get buildFolder(): string { - return this.taskConfig.buildDirectory || this.buildConfig.rootPath; - } - - public constructor(taskName: string, defaultConfig: Partial) { - super( - taskName, - { - allowBuiltinCompiler: false, - ...defaultConfig - } as TTaskConfig - ); - } - - protected initializeRushStackCompiler(): void { - const compilerPackageJson: IPackageJson = JsonFile.load( - path.join(this._rushStackCompilerPackagePath, 'package.json') - ); - const main: string | undefined = compilerPackageJson.main; - if (!main) { - throw new Error('Compiler package does not have a "main" entry.'); - } - - this._rushStackCompiler = require(path.join(this._rushStackCompilerPackagePath, main)); - } - - /** - * Determine which compiler should be used to compile a given project. - * - * @remarks - * We load the tsconfig.json file, and follow its "extends" field until we reach the end of the chain. - * We expect the last extended file to be under an installed @microsoft/rush-stack-compiler-* package, - * which determines which typescript/tslint/api-extractor versions should be invoked. - * - * @param tsconfigPath - The path of a tsconfig.json file to analyze - * @returns The absolute path of the folder containing "@microsoft/rush-stack-compiler-*" which should be used - * to compile this tsconfig.json project - */ - private _resolveRushStackCompilerFromTsconfig(tsconfigPath: string, visitedTsconfigPaths: Set): string { - this._terminal.writeVerboseLine(`Examining ${tsconfigPath}`); - visitedTsconfigPaths.add(tsconfigPath); - - if (!FileSystem.exists(tsconfigPath)) { - throw new Error(`tsconfig.json file (${tsconfigPath}) does not exist.`); - } - - let tsconfig: ITsconfig; - try { - tsconfig = JsonFile.load(tsconfigPath); - } catch (e) { - throw new Error(`Error parsing tsconfig.json ${tsconfigPath}: ${e}`); - } - - if (!tsconfig.extends) { - // Does the chain end with a file in the rush-stack-compiler package? - const packageJsonPath: string | undefined = RSCTask._packageJsonLookup.tryGetPackageJsonFilePathFor(tsconfigPath); - if (packageJsonPath) { - const packageJson: IPackageJson = JsonFile.load(packageJsonPath); - if (packageJson.name.match(/^@microsoft\/rush-stack-compiler-[0-9\.]+$/)) { - const packagePath: string = path.dirname(packageJsonPath); - this._terminal.writeVerboseLine(`Found rush-stack compiler at ${packagePath}/`); - return packagePath; - } - } - - throw new Error( - 'Rush Stack determines your TypeScript compiler by following the "extends" field in your tsconfig.json ' + - 'file, until it reaches a package folder that depends on a variant of @microsoft/rush-stack-compiler-*. ' + - `This lookup failed when it reached this file: ${tsconfigPath}` - ); - } - - // Follow the tsconfig.extends field: - let baseTsconfigPath: string; - let extendsPathKind: string; - if (path.isAbsolute(tsconfig.extends)) { - // Absolute path - baseTsconfigPath = tsconfig.extends; - extendsPathKind = 'an absolute path'; - } else if (tsconfig.extends.match(/^\./)) { - // Relative path - baseTsconfigPath = path.resolve(path.dirname(tsconfigPath), tsconfig.extends); - extendsPathKind = 'a relative path'; - } else { - // Package path - baseTsconfigPath = resolve.sync( - tsconfig.extends, - { - basedir: this.buildConfig.rootPath, - packageFilter: (pkg: IPackageJson) => { - return { - ...pkg, - main: 'package.json' - }; - } - } - ); - extendsPathKind = 'a package path'; - } - - this._terminal.writeVerboseLine( - `Found tsconfig.extends property ${tsconfig.extends}. It appears ` + - `to be ${extendsPathKind}. Resolved to ${baseTsconfigPath}` - ); - - if (visitedTsconfigPaths.has(baseTsconfigPath)) { - throw new Error(`The file "${baseTsconfigPath}" has an "extends" field that creates a circular reference`); - } - - return this._resolveRushStackCompilerFromTsconfig(baseTsconfigPath, visitedTsconfigPaths); - } -} diff --git a/core-build/gulp-core-build-typescript/src/TsParseConfigHost.ts b/core-build/gulp-core-build-typescript/src/TsParseConfigHost.ts deleted file mode 100644 index d2fe3f133b9..00000000000 --- a/core-build/gulp-core-build-typescript/src/TsParseConfigHost.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. - -import * as TTypescript from 'typescript'; -import { FileSystem } from '@rushstack/node-core-library'; - -/** - * Used as a helper to parse tsconfig.json files. - */ -export class TsParseConfigHost implements TTypescript.ParseConfigHost { - public useCaseSensitiveFileNames: boolean = false; - - public readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[]): string[] { - return FileSystem.readFolder(rootDir); - } - - public fileExists(path: string): boolean { - return FileSystem.exists(path); - } - - public readFile(path: string): string { - return FileSystem.readFile(path); - } -} diff --git a/core-build/gulp-core-build-typescript/src/TscCmdTask.ts b/core-build/gulp-core-build-typescript/src/TscCmdTask.ts deleted file mode 100644 index 357e391c7a0..00000000000 --- a/core-build/gulp-core-build-typescript/src/TscCmdTask.ts +++ /dev/null @@ -1,176 +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 { - JsonFile, - FileSystem, - LegacyAdapters, - JsonObject -} from '@rushstack/node-core-library'; -import * as glob from 'glob'; -import * as globEscape from 'glob-escape'; -import * as decomment from 'decomment'; -import { TypescriptCompiler as TTypescriptCompiler, ToolPackages } from '@microsoft/rush-stack-compiler-3.1'; - -type TTypescript = typeof ToolPackages.typescript; - -import { - RSCTask, - IRSCTaskConfig -} from './RSCTask'; -import { TsParseConfigHost } from './TsParseConfigHost'; - -/** - * @public - */ -export interface ITscCmdTaskConfig extends IRSCTaskConfig { - /** - * Option to pass custom arguments to the tsc command. - */ - customArgs?: string[]; - - /** - * Glob matches for files to be passed through the build. - */ - staticMatch?: string[]; - - /** - * Removes comments from all generated `.js` files in the TSConfig outDir. Will **not** remove comments from - * generated `.d.ts` files. Defaults to false. - */ - removeCommentsFromJavaScript?: boolean; -} - -/** - * @public - */ -export class TscCmdTask extends RSCTask { - public constructor() { - super( - 'tsc', - { - staticMatch: [ - 'src/**/*.js', - 'src/**/*.json', - 'src/**/*.jsx' - ], - removeCommentsFromJavaScript: false - } - ); - } - - public loadSchema(): JsonObject { - return JsonFile.load(path.resolve(__dirname, 'schemas', 'tsc-cmd.schema.json')); - } - - public executeTask(): Promise { - this.initializeRushStackCompiler(); - - // Static passthrough files. - const srcPath: string = path.join(this.buildConfig.rootPath, this.buildConfig.srcFolder); - const libFolders: string[] = [this.buildConfig.libFolder]; - if (this.buildConfig.libAMDFolder) { - libFolders.push(this.buildConfig.libAMDFolder); - } - - if (this.buildConfig.libES6Folder) { - libFolders.push(this.buildConfig.libES6Folder); - } - - if (this.buildConfig.libESNextFolder) { - libFolders.push(this.buildConfig.libESNextFolder); - } - - const resolvedLibFolders: string[] = libFolders.map((libFolder) => path.join(this.buildConfig.rootPath, libFolder)); - const promises: Promise[] = (this.taskConfig.staticMatch || []).map((pattern) => - LegacyAdapters.convertCallbackToPromise(glob, path.join(globEscape(this.buildConfig.rootPath), pattern)).then( - (matchPaths: string[]) => { - for (const matchPath of matchPaths) { - const fileContents: string = FileSystem.readFile(matchPath); - const relativePath: string = path.relative(srcPath, matchPath); - for (const resolvedLibFolder of resolvedLibFolders) { - const destPath: string = path.join(resolvedLibFolder, relativePath); - FileSystem.writeFile(destPath, fileContents, { ensureFolderExists: true }); - } - } - } - ) - ); - - const typescriptCompiler: TTypescriptCompiler = new this._rushStackCompiler.TypescriptCompiler( - { - customArgs: this.taskConfig.customArgs, - fileError: this.fileError.bind(this), - fileWarning: this.fileWarning.bind(this) - }, - this.buildFolder, - this._terminalProvider - ); - const basePromise: Promise | undefined = typescriptCompiler.invoke(); - - if (basePromise) { - promises.push(basePromise); - } - - let buildPromise: Promise = Promise.all(promises).then(() => { /* collapse void[] to void */ }); - - if (this.taskConfig.removeCommentsFromJavaScript === true) { - buildPromise = buildPromise.then( - () => this._removeComments(this._rushStackCompiler.ToolPackages.typescript) - ); - } - - return buildPromise; - } - - protected _onData(data: Buffer): void { - // Log lines separately - const dataLines: (string | undefined)[] = data.toString().split('\n'); - for (const dataLine of dataLines) { - const trimmedLine: string = (dataLine || '').trim(); - if (trimmedLine) { - if (trimmedLine.match(/\serror\s/i)) { - // If the line looks like an error, log it as an error - this.logError(trimmedLine); - } else { - this.log(trimmedLine); - } - } - } - } - - private _removeComments(typescript: TTypescript): Promise { - const configFilePath: string | undefined = typescript.findConfigFile(this.buildConfig.rootPath, FileSystem.exists); - if (!configFilePath) { - return Promise.reject(new Error('Unable to resolve tsconfig file to determine outDir.')); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const tsConfig: any = typescript.parseJsonConfigFileContent( - JsonFile.load(configFilePath), - new TsParseConfigHost(), - path.dirname(configFilePath) - ); - if (!tsConfig || !tsConfig.options.outDir) { - return Promise.reject('Unable to determine outDir from TypesScript configuration.'); - } - - return LegacyAdapters.convertCallbackToPromise( - glob, - path.join(globEscape(tsConfig.options.outDir), '**', '*.js') - ).then((matches: string[]) => { - for (const match of matches) { - const sourceText: string = FileSystem.readFile(match); - const decommentedText: string = decomment( - sourceText, - { - // This option preserves comments that start with /*!, /**! or //! - typically copyright comments - safe: true - } - ); - FileSystem.writeFile(match, decommentedText); - } - }); - } -} diff --git a/core-build/gulp-core-build-typescript/src/TslintCmdTask.ts b/core-build/gulp-core-build-typescript/src/TslintCmdTask.ts deleted file mode 100644 index 99fd9f5bae0..00000000000 --- a/core-build/gulp-core-build-typescript/src/TslintCmdTask.ts +++ /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. - -import * as path from 'path'; -import { JsonFile, JsonObject } from '@rushstack/node-core-library'; -import { TslintRunner as TTslintRunner } from '@microsoft/rush-stack-compiler-3.1'; - -import { - RSCTask, - IRSCTaskConfig -} from './RSCTask'; - -/** - * @public - */ -export interface ITslintCmdTaskConfig extends IRSCTaskConfig { - /** - * If true, displays warnings as errors. Defaults to false. - */ - displayAsError?: boolean; -} - -/** - * @public - */ -export class TslintCmdTask extends RSCTask { - public constructor() { - super( - 'tslint', - { - displayAsError: false - } - ); - } - - public loadSchema(): JsonObject { - return JsonFile.load(path.resolve(__dirname, 'schemas', 'tslint-cmd.schema.json')); - } - - public executeTask(): Promise { - this.initializeRushStackCompiler(); - - const tslintRunner: TTslintRunner = new this._rushStackCompiler.TslintRunner( - { - displayAsError: this.taskConfig.displayAsError, - - fileError: this.fileError.bind(this), - fileWarning: this.fileWarning.bind(this) - }, - this.buildFolder, - this._terminalProvider - ); - - return tslintRunner.invoke(); - } -} diff --git a/core-build/gulp-core-build-typescript/src/index.ts b/core-build/gulp-core-build-typescript/src/index.ts deleted file mode 100644 index 9759879bc77..00000000000 --- a/core-build/gulp-core-build-typescript/src/index.ts +++ /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 { - TscCmdTask, - ITscCmdTaskConfig -} from './TscCmdTask'; -import { - LintCmdTask, - ILintCmdTaskConfig -} from './LintCmdTask'; -import { - TslintCmdTask, - ITslintCmdTaskConfig -} from './TslintCmdTask'; -import { ApiExtractorTask } from './ApiExtractorTask'; - -export { - TscCmdTask, - ITscCmdTaskConfig, - TslintCmdTask, - ITslintCmdTaskConfig, - LintCmdTask, - ILintCmdTaskConfig -}; - -/** @public */ -export const tscCmd: TscCmdTask = new TscCmdTask(); - -/** @public */ -export const tslintCmd: TslintCmdTask = new TslintCmdTask(); - -/** @public */ -export const lintCmd: LintCmdTask = new LintCmdTask(); - -/** @public */ -export const apiExtractor: ApiExtractorTask = new ApiExtractorTask(); diff --git a/core-build/gulp-core-build-typescript/src/schemas/api-extractor.schema.json b/core-build/gulp-core-build-typescript/src/schemas/api-extractor.schema.json deleted file mode 100644 index 2497b4b1046..00000000000 --- a/core-build/gulp-core-build-typescript/src/schemas/api-extractor.schema.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - - "title": "api-extractor Configuration", - "description": "Generates a report of the Public API exports for a project, and detects changes that impact the SemVer contract", - - "type": "object", - "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" - } - }, - "required": [ "enabled" ], - "additionalProperties": false -} diff --git a/core-build/gulp-core-build-typescript/src/schemas/lint-cmd.schema.json b/core-build/gulp-core-build-typescript/src/schemas/lint-cmd.schema.json deleted file mode 100644 index cd2bd48a205..00000000000 --- a/core-build/gulp-core-build-typescript/src/schemas/lint-cmd.schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - - "title": "Lint Task configuration", - "description": "Defines configuration options for the lint task which supports both ESLint or TSLint", - - "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" - }, - "buildDirectory": { - "description": "The directory in which TSLint or ESLint should be invoked.", - "type": "string" - }, - "displayAsError": { - "description": "If true, displays warnings as errors. Defaults to false.", - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build-typescript/src/schemas/tsc-cmd.schema.json b/core-build/gulp-core-build-typescript/src/schemas/tsc-cmd.schema.json deleted file mode 100644 index ebfbafcdfae..00000000000 --- a/core-build/gulp-core-build-typescript/src/schemas/tsc-cmd.schema.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - - "title": "Typescript Task configuration", - "description": "Defines configuration options for the typescript compilation task", - - "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" - }, - "staticMatch": { - "description": "Glob matches for files to be passed through the build", - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1 - }, - "buildDirectory": { - "description": "The directory in which the typescript compiler should be invoked.", - "type": "string" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build-typescript/src/schemas/tslint-cmd.schema.json b/core-build/gulp-core-build-typescript/src/schemas/tslint-cmd.schema.json deleted file mode 100644 index 9944b45a3ed..00000000000 --- a/core-build/gulp-core-build-typescript/src/schemas/tslint-cmd.schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - - "title": "Tslint Task configuration", - "description": "Defines configuration options for the tslint task", - - "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" - }, - "buildDirectory": { - "description": "The directory in which tslint should be invoked.", - "type": "string" - }, - "displayAsError": { - "description": "If true, displays warnings as errors. Defaults to false.", - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build-typescript/tsconfig.json b/core-build/gulp-core-build-typescript/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/core-build/gulp-core-build-typescript/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/core-build/gulp-core-build-webpack/.eslintrc.js b/core-build/gulp-core-build-webpack/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/gulp-core-build-webpack/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/gulp-core-build-webpack/.npmignore b/core-build/gulp-core-build-webpack/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build-webpack/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build-webpack/CHANGELOG.json b/core-build/gulp-core-build-webpack/CHANGELOG.json deleted file mode 100644 index eff16577f1d..00000000000 --- a/core-build/gulp-core-build-webpack/CHANGELOG.json +++ /dev/null @@ -1,3833 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-webpack", - "entries": [ - { - "version": "5.0.2", - "tag": "@microsoft/gulp-core-build-webpack_v5.0.2", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "5.0.1", - "tag": "@microsoft/gulp-core-build-webpack_v5.0.1", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "5.0.0", - "tag": "@microsoft/gulp-core-build-webpack_v5.0.0", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "major": [ - { - "comment": "Upgrade to Webpack 4." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.3` to `6.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "4.1.3", - "tag": "@microsoft/gulp-core-build-webpack_v4.1.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.2` to `6.4.3`" - } - ] - } - }, - { - "version": "4.1.2", - "tag": "@microsoft/gulp-core-build-webpack_v4.1.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.1` to `6.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "4.1.1", - "tag": "@microsoft/gulp-core-build-webpack_v4.1.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.0` to `6.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "4.1.0", - "tag": "@microsoft/gulp-core-build-webpack_v4.1.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.16` to `6.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.15` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "4.0.8", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.8", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.15` to `6.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "4.0.7", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.7", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.14` to `6.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "4.0.6", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.6", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.13` to `6.3.14`" - } - ] - } - }, - { - "version": "4.0.5", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.5", - "date": "Thu, 09 Jan 2020 06:44:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.12` to `6.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "4.0.4", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.4", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.11` to `6.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "4.0.3", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.3", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.10` to `6.3.11`" - } - ] - } - }, - { - "version": "4.0.2", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.2", - "date": "Tue, 03 Dec 2019 03:17:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.9` to `6.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "4.0.1", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.1", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.8` to `6.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "4.0.0", - "tag": "@microsoft/gulp-core-build-webpack_v4.0.0", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "major": [ - { - "comment": "Upgrade to Webpack 4." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.7` to `6.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "3.7.9", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.9", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.6` to `6.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "3.7.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.8", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.5` to `6.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.7.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.7", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.4` to `6.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "3.7.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.6", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.3` to `6.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "3.7.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.5", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.2` to `6.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "3.7.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.4", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.1` to `6.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "3.7.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.3", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.0` to `6.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.7.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.2", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.6` to `6.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.6` to `0.3.0`" - } - ] - } - }, - { - "version": "3.7.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.1", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.5` to `6.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "3.7.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.7.0", - "date": "Mon, 07 Oct 2019 20:15:00 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for multi-compiler webpack config setting." - } - ] - } - }, - { - "version": "3.6.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.4` to `6.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "3.6.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.3` to `6.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "3.6.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.2` to `6.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "3.6.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.1` to `6.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.1` to `0.2.2`" - } - ] - } - }, - { - "version": "3.6.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.0` to `6.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "3.6.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.6.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.11` to `6.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.24` to `0.2.0`" - } - ] - } - }, - { - "version": "3.5.12", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.12", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.10` to `6.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.23` to `0.1.24`" - } - ] - } - }, - { - "version": "3.5.11", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.11", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.9` to `6.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.22` to `0.1.23`" - } - ] - } - }, - { - "version": "3.5.10", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.10", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.8` to `6.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.21` to `0.1.22`" - } - ] - } - }, - { - "version": "3.5.9", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.9", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.7` to `6.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.20` to `0.1.21`" - } - ] - } - }, - { - "version": "3.5.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.8", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.6` to `6.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "3.5.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.7", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.5` to `6.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "3.5.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.6", - "date": "Wed, 04 Sep 2019 01:43:31 GMT", - "comments": { - "patch": [ - { - "comment": "Make @types/webpack dependency more loose, add @types/webpack-dev-server." - } - ] - } - }, - { - "version": "3.5.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.5", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.4` to `6.1.5`" - } - ] - } - }, - { - "version": "3.5.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.4", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.3` to `6.1.4`" - } - ] - } - }, - { - "version": "3.5.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.3", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.2` to `6.1.3`" - } - ] - } - }, - { - "version": "3.5.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.2", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.1` to `6.1.2`" - } - ] - } - }, - { - "version": "3.5.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.1", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.0` to `6.1.1`" - } - ] - } - }, - { - "version": "3.5.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.5.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.74` to `6.1.0`" - } - ] - } - }, - { - "version": "3.4.115", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.115", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.73` to `6.0.74`" - } - ] - } - }, - { - "version": "3.4.114", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.114", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.72` to `6.0.73`" - } - ] - } - }, - { - "version": "3.4.113", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.113", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.23` to `0.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.71` to `6.0.72`" - } - ] - } - }, - { - "version": "3.4.112", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.112", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.22` to `0.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.70` to `6.0.71`" - } - ] - } - }, - { - "version": "3.4.111", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.111", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.21` to `0.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.69` to `6.0.70`" - } - ] - } - }, - { - "version": "3.4.110", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.110", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.20` to `0.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.68` to `6.0.69`" - } - ] - } - }, - { - "version": "3.4.109", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.109", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.19` to `0.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.67` to `6.0.68`" - } - ] - } - }, - { - "version": "3.4.108", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.108", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.18` to `0.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.66` to `6.0.67`" - } - ] - } - }, - { - "version": "3.4.107", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.107", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.17` to `0.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.65` to `6.0.66`" - } - ] - } - }, - { - "version": "3.4.106", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.106", - "date": "Thu, 06 Jun 2019 22:33:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.16` to `0.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.64` to `6.0.65`" - } - ] - } - }, - { - "version": "3.4.105", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.105", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.15` to `0.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.63` to `6.0.64`" - } - ] - } - }, - { - "version": "3.4.104", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.104", - "date": "Tue, 04 Jun 2019 05:51:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.62` to `6.0.63`" - } - ] - } - }, - { - "version": "3.4.103", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.103", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.13` to `0.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.61` to `6.0.62`" - } - ] - } - }, - { - "version": "3.4.102", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.102", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.60` to `6.0.61`" - } - ] - } - }, - { - "version": "3.4.101", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.101", - "date": "Mon, 06 May 2019 20:46:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.59` to `6.0.60`" - } - ] - } - }, - { - "version": "3.4.100", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.100", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.10` to `0.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.58` to `6.0.59`" - } - ] - } - }, - { - "version": "3.4.99", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.99", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.9` to `0.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.57` to `6.0.58`" - } - ] - } - }, - { - "version": "3.4.98", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.98", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.8` to `0.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.56` to `6.0.57`" - } - ] - } - }, - { - "version": "3.4.97", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.97", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.7` to `0.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.55` to `6.0.56`" - } - ] - } - }, - { - "version": "3.4.96", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.96", - "date": "Fri, 12 Apr 2019 06:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.6` to `0.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.54` to `6.0.55`" - } - ] - } - }, - { - "version": "3.4.95", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.95", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.53` to `6.0.54`" - } - ] - } - }, - { - "version": "3.4.94", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.94", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.4` to `0.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.52` to `6.0.53`" - } - ] - } - }, - { - "version": "3.4.93", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.93", - "date": "Mon, 08 Apr 2019 19:12:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.51` to `6.0.52`" - } - ] - } - }, - { - "version": "3.4.92", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.92", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.50` to `6.0.51`" - } - ] - } - }, - { - "version": "3.4.91", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.91", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.49` to `6.0.50`" - } - ] - } - }, - { - "version": "3.4.90", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.90", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.48` to `6.0.49`" - } - ] - } - }, - { - "version": "3.4.89", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.89", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.47` to `6.0.48`" - } - ] - } - }, - { - "version": "3.4.88", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.88", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.46` to `6.0.47`" - } - ] - } - }, - { - "version": "3.4.87", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.87", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.45` to `6.0.46`" - } - ] - } - }, - { - "version": "3.4.86", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.86", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.44` to `6.0.45`" - } - ] - } - }, - { - "version": "3.4.85", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.85", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.43` to `6.0.44`" - } - ] - } - }, - { - "version": "3.4.84", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.84", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.42` to `6.0.43`" - } - ] - } - }, - { - "version": "3.4.83", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.83", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.41` to `6.0.42`" - } - ] - } - }, - { - "version": "3.4.82", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.82", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.40` to `6.0.41`" - } - ] - } - }, - { - "version": "3.4.81", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.81", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.39` to `6.0.40`" - } - ] - } - }, - { - "version": "3.4.80", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.80", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.38` to `6.0.39`" - } - ] - } - }, - { - "version": "3.4.79", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.79", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.37` to `6.0.38`" - } - ] - } - }, - { - "version": "3.4.78", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.78", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.36` to `6.0.37`" - } - ] - } - }, - { - "version": "3.4.77", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.77", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.35` to `6.0.36`" - } - ] - } - }, - { - "version": "3.4.76", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.76", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.34` to `6.0.35`" - } - ] - } - }, - { - "version": "3.4.75", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.75", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.33` to `6.0.34`" - } - ] - } - }, - { - "version": "3.4.74", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.74", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.32` to `6.0.33`" - } - ] - } - }, - { - "version": "3.4.73", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.73", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.31` to `6.0.32`" - } - ] - } - }, - { - "version": "3.4.72", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.72", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.30` to `6.0.31`" - } - ] - } - }, - { - "version": "3.4.71", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.71", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.29` to `6.0.30`" - } - ] - } - }, - { - "version": "3.4.70", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.70", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.28` to `6.0.29`" - } - ] - } - }, - { - "version": "3.4.69", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.69", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.27` to `6.0.28`" - } - ] - } - }, - { - "version": "3.4.68", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.68", - "date": "Wed, 30 Jan 2019 20:49:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.26` to `6.0.27`" - } - ] - } - }, - { - "version": "3.4.67", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.67", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.25` to `6.0.26`" - } - ] - } - }, - { - "version": "3.4.66", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.66", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.24` to `6.0.25`" - } - ] - } - }, - { - "version": "3.4.65", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.65", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.23` to `6.0.24`" - } - ] - } - }, - { - "version": "3.4.64", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.64", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.22` to `6.0.23`" - } - ] - } - }, - { - "version": "3.4.63", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.63", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.21` to `6.0.22`" - } - ] - } - }, - { - "version": "3.4.62", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.62", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.20` to `6.0.21`" - } - ] - } - }, - { - "version": "3.4.61", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.61", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.19` to `6.0.20`" - } - ] - } - }, - { - "version": "3.4.60", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.60", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.18` to `6.0.19`" - } - ] - } - }, - { - "version": "3.4.59", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.59", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.17` to `6.0.18`" - } - ] - } - }, - { - "version": "3.4.58", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.58", - "date": "Fri, 30 Nov 2018 23:34:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.16` to `6.0.17`" - } - ] - } - }, - { - "version": "3.4.57", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.57", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.15` to `6.0.16`" - } - ] - } - }, - { - "version": "3.4.56", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.56", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.14` to `6.0.15`" - } - ] - } - }, - { - "version": "3.4.55", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.55", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.13` to `6.0.14`" - } - ] - } - }, - { - "version": "3.4.54", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.54", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.12` to `6.0.13`" - } - ] - } - }, - { - "version": "3.4.53", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.53", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.11` to `6.0.12`" - } - ] - } - }, - { - "version": "3.4.52", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.52", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.10` to `6.0.11`" - } - ] - } - }, - { - "version": "3.4.51", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.51", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.9` to `6.0.10`" - } - ] - } - }, - { - "version": "3.4.50", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.50", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.8` to `6.0.9`" - } - ] - } - }, - { - "version": "3.4.49", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.49", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.7` to `6.0.8`" - } - ] - } - }, - { - "version": "3.4.48", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.48", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.6` to `6.0.7`" - } - ] - } - }, - { - "version": "3.4.47", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.47", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.5` to `6.0.6`" - } - ] - } - }, - { - "version": "3.4.46", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.46", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.4` to `6.0.5`" - } - ] - } - }, - { - "version": "3.4.45", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.45", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.3` to `6.0.4`" - } - ] - } - }, - { - "version": "3.4.44", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.44", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.2` to `6.0.3`" - } - ] - } - }, - { - "version": "3.4.43", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.43", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.1` to `6.0.2`" - } - ] - } - }, - { - "version": "3.4.42", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.42", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.0` to `6.0.1`" - } - ] - } - }, - { - "version": "3.4.41", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.41", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.26` to `6.0.0`" - } - ] - } - }, - { - "version": "3.4.40", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.40", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.25` to `5.0.26`" - } - ] - } - }, - { - "version": "3.4.39", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.39", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.24` to `5.0.25`" - } - ] - } - }, - { - "version": "3.4.38", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.38", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.23` to `5.0.24`" - } - ] - } - }, - { - "version": "3.4.37", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.37", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "patch": [ - { - "comment": "Replace deprecated dependency gulp-util" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.22` to `5.0.23`" - } - ] - } - }, - { - "version": "3.4.36", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.36", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.21` to `5.0.22`" - } - ] - } - }, - { - "version": "3.4.35", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.35", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.20` to `5.0.21`" - } - ] - } - }, - { - "version": "3.4.34", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.34", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.19` to `5.0.20`" - } - ] - } - }, - { - "version": "3.4.33", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.33", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.18` to `5.0.19`" - } - ] - } - }, - { - "version": "3.4.32", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.32", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.17` to `5.0.18`" - } - ] - } - }, - { - "version": "3.4.31", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.31", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.16` to `5.0.17`" - } - ] - } - }, - { - "version": "3.4.30", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.30", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.15` to `5.0.16`" - } - ] - } - }, - { - "version": "3.4.29", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.29", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.14` to `5.0.15`" - } - ] - } - }, - { - "version": "3.4.28", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.28", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.13` to `5.0.14`" - } - ] - } - }, - { - "version": "3.4.27", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.27", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.12` to `5.0.13`" - } - ] - } - }, - { - "version": "3.4.26", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.26", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.11` to `5.0.12`" - } - ] - } - }, - { - "version": "3.4.25", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.25", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.10` to `5.0.11`" - } - ] - } - }, - { - "version": "3.4.24", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.24", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.9` to `5.0.10`" - } - ] - } - }, - { - "version": "3.4.23", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.23", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.8` to `5.0.9`" - } - ] - } - }, - { - "version": "3.4.22", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.22", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.7` to `5.0.8`" - } - ] - } - }, - { - "version": "3.4.21", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.21", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.6` to `5.0.7`" - } - ] - } - }, - { - "version": "3.4.20", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.20", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.5` to `5.0.6`" - } - ] - } - }, - { - "version": "3.4.19", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.19", - "date": "Mon, 03 Sep 2018 16:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.4` to `5.0.5`" - } - ] - } - }, - { - "version": "3.4.18", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.18", - "date": "Thu, 30 Aug 2018 22:47:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.3` to `5.0.4`" - } - ] - } - }, - { - "version": "3.4.17", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.17", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.2` to `5.0.3`" - } - ] - } - }, - { - "version": "3.4.16", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.16", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.1` to `5.0.2`" - } - ] - } - }, - { - "version": "3.4.15", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.15", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.0` to `5.0.1`" - } - ] - } - }, - { - "version": "3.4.14", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.14", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `4.4.11` to `5.0.0`" - } - ] - } - }, - { - "version": "3.4.13", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.13", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - } - ] - } - }, - { - "version": "3.4.12", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.12", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - } - ] - } - }, - { - "version": "3.4.11", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.11", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - } - ] - } - }, - { - "version": "3.4.10", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.10", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - } - ] - } - }, - { - "version": "3.4.9", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.9", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "patch": [ - { - "comment": "Update typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - } - ] - } - }, - { - "version": "3.4.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.8", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - } - ] - } - }, - { - "version": "3.4.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.7", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - } - ] - } - }, - { - "version": "3.4.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.6", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - } - ] - } - }, - { - "version": "3.4.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.5", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - } - ] - } - }, - { - "version": "3.4.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.4", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - } - ] - } - }, - { - "version": "3.4.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.3", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - } - ] - } - }, - { - "version": "3.4.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.2", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.1", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.4.0", - "date": "Fri, 06 Apr 2018 16:03:14 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade webpack to ~3.11.0" - } - ] - } - }, - { - "version": "3.3.25", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.25", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - } - ] - } - }, - { - "version": "3.3.24", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.24", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - } - ] - } - }, - { - "version": "3.3.23", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.23", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - } - ] - } - }, - { - "version": "3.3.22", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.22", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade colors to version ~1.2.1" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - } - ] - } - }, - { - "version": "3.3.21", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.21", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - } - ] - } - }, - { - "version": "3.3.20", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.20", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - } - ] - } - }, - { - "version": "3.3.19", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.19", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - } - ] - } - }, - { - "version": "3.3.18", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.18", - "date": "Mon, 12 Mar 2018 20:36:19 GMT", - "comments": { - "patch": [ - { - "comment": "Locked down some \"@types/\" dependency versions to avoid upgrade conflicts" - } - ] - } - }, - { - "version": "3.3.17", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.17", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - } - ] - } - }, - { - "version": "3.3.16", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.16", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - } - ] - } - }, - { - "version": "3.3.15", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.15", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - } - ] - } - }, - { - "version": "3.3.14", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.14", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - } - ] - } - }, - { - "version": "3.3.13", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.13", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - } - ] - } - }, - { - "version": "3.3.12", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.12", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - } - ] - } - }, - { - "version": "3.3.11", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.11", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - } - ] - } - }, - { - "version": "3.3.10", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.10", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - } - ] - } - }, - { - "version": "3.3.9", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.9", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - } - ] - } - }, - { - "version": "3.3.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.8", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - } - ] - } - }, - { - "version": "3.3.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.7", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - } - ] - } - }, - { - "version": "3.3.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.6", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "patch": [ - { - "comment": "Replace gulp-util.colors with colors package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - } - ] - } - }, - { - "version": "3.3.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.5", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - } - ] - } - }, - { - "version": "3.3.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.4", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - } - ] - } - }, - { - "version": "3.3.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.3.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - } - ] - } - }, - { - "version": "3.2.24", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.24", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.6` to `3.3.7`" - } - ] - } - }, - { - "version": "3.2.23", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.23", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - } - ] - } - }, - { - "version": "3.2.22", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.22", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - } - ] - } - }, - { - "version": "3.2.21", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.21", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - } - ] - } - }, - { - "version": "3.2.20", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.20", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - } - ] - } - }, - { - "version": "3.2.19", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.19", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - } - ] - } - }, - { - "version": "3.2.18", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.18", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - } - ] - } - }, - { - "version": "3.2.17", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.17", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - } - ] - } - }, - { - "version": "3.2.16", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.16", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - } - ] - } - }, - { - "version": "3.2.15", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.15", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - } - ] - } - }, - { - "version": "3.2.14", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.14", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - } - ] - } - }, - { - "version": "3.2.13", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.13", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - } - ] - } - }, - { - "version": "3.2.12", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.12", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - } - ] - } - }, - { - "version": "3.2.11", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.11", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "3.2.10", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.10", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.9", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.8", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.7", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.2.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.1.0", - "date": "Thu, 21 Sep 2017 20:34:26 GMT", - "comments": { - "minor": [ - { - "author": "Ian Clanton-Thuon ", - "commit": "3e9fdf5918d62327ef1b88ac75c8fa001306f2cb", - "comment": "Upgrade webpack to 3.6.0." - } - ] - } - }, - { - "version": "3.0.8", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - } - ] - } - }, - { - "version": "3.0.7", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - } - ] - } - }, - { - "version": "3.0.6", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - } - ] - } - }, - { - "version": "3.0.5", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - } - ] - } - }, - { - "version": "3.0.4", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.4", - "date": "Thu, 07 Sep 2017 00:11:11 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "4b7451b442c2078a96430f7a05caed37101aed52", - "comment": "Add $schema field to all schemas" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build-webpack_v3.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - } - ] - } - }, - { - "version": "2.0.2", - "tag": "@microsoft/gulp-core-build-webpack_v2.0.2", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build-webpack_v2.0.1", - "date": "Thu, 31 Aug 2017 13:04:19 GMT", - "comments": { - "patch": [ - { - "comment": "Removing an unneccessary dependency." - } - ] - } - }, - { - "version": "2.0.0", - "tag": "@microsoft/gulp-core-build-webpack_v2.0.0", - "date": "Wed, 30 Aug 2017 22:08:21 GMT", - "comments": { - "major": [ - { - "comment": "Upgrade to webpack 3.X." - } - ] - } - }, - { - "version": "1.2.9", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.9", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - } - ] - } - }, - { - "version": "1.2.8", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.8", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - } - ] - } - }, - { - "version": "1.2.7", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.7", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - } - ] - } - }, - { - "version": "1.2.6", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.6", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - } - ] - } - }, - { - "version": "1.2.5", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.5", - "date": "Wed, 16 Aug 2017 23:16:55 GMT", - "comments": { - "patch": [ - { - "comment": "Publish" - } - ] - } - }, - { - "version": "1.2.4", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.4", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - } - ] - } - }, - { - "version": "1.2.3", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.3", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "patch": [ - { - "comment": "Allow the webpack task to be extended with new configuration args." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.8.0` to `2.9.0`" - } - ] - } - }, - { - "version": "1.2.2", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.2", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - } - ] - } - }, - { - "version": "1.2.1", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.1", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - } - ] - } - }, - { - "version": "1.2.0", - "tag": "@microsoft/gulp-core-build-webpack_v1.2.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - } - ] - } - }, - { - "version": "1.1.8", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.8", - "date": "Wed, 21 Jun 2017 04:19:35 GMT", - "comments": { - "patch": [ - { - "comment": "Add missing API Extractor release tags" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.3 <3.0.0` to `>=2.5.5 <3.0.0`" - } - ] - } - }, - { - "version": "1.1.6", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.6", - "date": "Mon, 15 May 2017 21:59:43 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unnecessary fsevents optional dependency" - } - ] - } - }, - { - "version": "1.1.5", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.5", - "date": "Mon, 24 Apr 2017 22:01:17 GMT", - "comments": { - "patch": [ - { - "comment": "Updating --initwebpack to contain the proper namespace." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.5.0 <3.0.0`" - } - ] - } - }, - { - "version": "1.1.4", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.4", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - } - ] - } - }, - { - "version": "1.1.3", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.3", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - } - ] - } - }, - { - "version": "1.1.2", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.2", - "date": "Tue, 31 Jan 2017 20:32:37 GMT", - "comments": { - "patch": [ - { - "comment": "Make loadSchema public instead of protected." - } - ] - } - }, - { - "version": "1.1.1", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.1", - "date": "Tue, 31 Jan 2017 01:55:09 GMT", - "comments": { - "patch": [ - { - "comment": "Introduce schema for WebpackTask" - } - ] - } - }, - { - "version": "1.1.0", - "tag": "@microsoft/gulp-core-build-webpack_v1.1.0", - "date": "Thu, 19 Jan 2017 02:37:34 GMT", - "comments": { - "minor": [ - { - "comment": "Including an option to pass in the webpack compiler object to the GCB-webpack task." - } - ] - } - }, - { - "version": "1.0.4", - "tag": "@microsoft/gulp-core-build-webpack_v1.0.4", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "1.0.3", - "tag": "@microsoft/gulp-core-build-webpack_v1.0.3", - "date": "Fri, 16 Dec 2016 07:47:32 GMT", - "comments": { - "patch": [ - { - "comment": "Patching webpack due to a publishing issue not publishing it in the last batch." - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build-webpack/CHANGELOG.md b/core-build/gulp-core-build-webpack/CHANGELOG.md deleted file mode 100644 index a0d374434c7..00000000000 --- a/core-build/gulp-core-build-webpack/CHANGELOG.md +++ /dev/null @@ -1,1317 +0,0 @@ -# Change Log - @microsoft/gulp-core-build-webpack - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 5.0.2 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 5.0.1 -Tue, 17 Mar 2020 23:55:58 GMT - -*Version update only* - -## 5.0.0 -Tue, 28 Jan 2020 02:23:44 GMT - -### Breaking changes - -- Upgrade to Webpack 4. - -## 4.1.3 -Fri, 24 Jan 2020 00:27:39 GMT - -*Version update only* - -## 4.1.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 4.1.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 4.1.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 4.0.8 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 4.0.7 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 4.0.6 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 4.0.5 -Thu, 09 Jan 2020 06:44:13 GMT - -*Version update only* - -## 4.0.4 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 4.0.3 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 4.0.2 -Tue, 03 Dec 2019 03:17:44 GMT - -*Version update only* - -## 4.0.1 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 4.0.0 -Wed, 20 Nov 2019 06:14:28 GMT - -### Breaking changes - -- Upgrade to Webpack 4. - -## 3.7.9 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 3.7.8 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 3.7.7 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 3.7.6 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 3.7.5 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 3.7.4 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 3.7.3 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 3.7.2 -Mon, 21 Oct 2019 05:22:43 GMT - -*Version update only* - -## 3.7.1 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 3.7.0 -Mon, 07 Oct 2019 20:15:00 GMT - -### Minor changes - -- Add support for multi-compiler webpack config setting. - -## 3.6.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 3.6.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 3.6.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 3.6.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 3.6.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 3.6.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 3.5.12 -Fri, 20 Sep 2019 21:27:22 GMT - -*Version update only* - -## 3.5.11 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 3.5.10 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 3.5.9 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 3.5.8 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 3.5.7 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 3.5.6 -Wed, 04 Sep 2019 01:43:31 GMT - -### Patches - -- Make @types/webpack dependency more loose, add @types/webpack-dev-server. - -## 3.5.5 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 3.5.4 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 3.5.3 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 3.5.2 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 3.5.1 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 3.5.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2 - -## 3.4.115 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 3.4.114 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 3.4.113 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 3.4.112 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 3.4.111 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 3.4.110 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 3.4.109 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 3.4.108 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 3.4.107 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 3.4.106 -Thu, 06 Jun 2019 22:33:36 GMT - -*Version update only* - -## 3.4.105 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 3.4.104 -Tue, 04 Jun 2019 05:51:54 GMT - -*Version update only* - -## 3.4.103 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 3.4.102 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 3.4.101 -Mon, 06 May 2019 20:46:22 GMT - -*Version update only* - -## 3.4.100 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 3.4.99 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 3.4.98 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 3.4.97 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 3.4.96 -Fri, 12 Apr 2019 06:13:17 GMT - -*Version update only* - -## 3.4.95 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 3.4.94 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 3.4.93 -Mon, 08 Apr 2019 19:12:53 GMT - -*Version update only* - -## 3.4.92 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 3.4.91 -Fri, 05 Apr 2019 04:16:17 GMT - -*Version update only* - -## 3.4.90 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 3.4.89 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 3.4.88 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 3.4.87 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 3.4.86 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 3.4.85 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 3.4.84 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 3.4.83 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 3.4.82 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 3.4.81 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 3.4.80 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 3.4.79 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 3.4.78 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 3.4.77 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 3.4.76 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 3.4.75 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 3.4.74 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 3.4.73 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 3.4.72 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 3.4.71 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 3.4.70 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 3.4.69 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 3.4.68 -Wed, 30 Jan 2019 20:49:12 GMT - -*Version update only* - -## 3.4.67 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 3.4.66 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 3.4.65 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 3.4.64 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 3.4.63 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 3.4.62 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 3.4.61 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 3.4.60 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 3.4.59 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 3.4.58 -Fri, 30 Nov 2018 23:34:58 GMT - -*Version update only* - -## 3.4.57 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 3.4.56 -Thu, 29 Nov 2018 00:35:38 GMT - -*Version update only* - -## 3.4.55 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 3.4.54 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 3.4.53 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 3.4.52 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 3.4.51 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 3.4.50 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 3.4.49 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 3.4.48 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 3.4.47 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 3.4.46 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 3.4.45 -Wed, 31 Oct 2018 21:17:50 GMT - -*Version update only* - -## 3.4.44 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 3.4.43 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 3.4.42 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 3.4.41 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 3.4.40 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 3.4.39 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 3.4.38 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 3.4.37 -Thu, 18 Oct 2018 05:30:14 GMT - -### Patches - -- Replace deprecated dependency gulp-util - -## 3.4.36 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 3.4.35 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 3.4.34 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 3.4.33 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 3.4.32 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 3.4.31 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 3.4.30 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 3.4.29 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 3.4.28 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 3.4.27 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 3.4.26 -Mon, 24 Sep 2018 16:04:28 GMT - -*Version update only* - -## 3.4.25 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 3.4.24 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 3.4.23 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 3.4.22 -Mon, 10 Sep 2018 23:23:01 GMT - -*Version update only* - -## 3.4.21 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 3.4.20 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 3.4.19 -Mon, 03 Sep 2018 16:04:46 GMT - -*Version update only* - -## 3.4.18 -Thu, 30 Aug 2018 22:47:34 GMT - -*Version update only* - -## 3.4.17 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 3.4.16 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 3.4.15 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 3.4.14 -Wed, 29 Aug 2018 06:36:50 GMT - -*Version update only* - -## 3.4.13 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 3.4.12 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 3.4.11 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 3.4.10 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 3.4.9 -Tue, 07 Aug 2018 22:27:31 GMT - -### Patches - -- Update typings - -## 3.4.8 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 3.4.7 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 3.4.6 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 3.4.5 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 3.4.4 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 3.4.3 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 3.4.2 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 3.4.1 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 3.4.0 -Fri, 06 Apr 2018 16:03:14 GMT - -### Minor changes - -- Upgrade webpack to ~3.11.0 - -## 3.3.25 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 3.3.24 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 3.3.23 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 3.3.22 -Fri, 23 Mar 2018 00:34:53 GMT - -### Patches - -- Upgrade colors to version ~1.2.1 - -## 3.3.21 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 3.3.20 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 3.3.19 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 3.3.18 -Mon, 12 Mar 2018 20:36:19 GMT - -### Patches - -- Locked down some "@types/" dependency versions to avoid upgrade conflicts - -## 3.3.17 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 3.3.16 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 3.3.15 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 3.3.14 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 3.3.13 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 3.3.12 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 3.3.11 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.3.10 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.3.9 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 3.3.8 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 3.3.7 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 3.3.6 -Tue, 23 Jan 2018 17:05:28 GMT - -### Patches - -- Replace gulp-util.colors with colors package - -## 3.3.5 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 3.3.4 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 3.3.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 3.3.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 3.3.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 3.3.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 3.2.24 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 3.2.23 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 3.2.22 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 3.2.21 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 3.2.20 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 3.2.19 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 3.2.18 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 3.2.17 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 3.2.16 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 3.2.15 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 3.2.14 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 3.2.13 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 3.2.12 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 3.2.11 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.2.10 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 3.2.9 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 3.2.8 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 3.2.7 -Tue, 24 Oct 2017 18:17:12 GMT - -*Version update only* - -## 3.2.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 3.2.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 3.2.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 3.2.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 3.2.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 3.2.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 3.2.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 3.1.0 -Thu, 21 Sep 2017 20:34:26 GMT - -### Minor changes - -- Upgrade webpack to 3.6.0. - -## 3.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 3.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 3.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -*Version update only* - -## 3.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 3.0.4 -Thu, 07 Sep 2017 00:11:11 GMT - -### Patches - -- Add $schema field to all schemas - -## 3.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 3.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 3.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 3.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 2.0.2 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 2.0.1 -Thu, 31 Aug 2017 13:04:19 GMT - -### Patches - -- Removing an unneccessary dependency. - -## 2.0.0 -Wed, 30 Aug 2017 22:08:21 GMT - -### Breaking changes - -- Upgrade to webpack 3.X. - -## 1.2.9 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 1.2.8 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 1.2.7 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 1.2.6 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 1.2.5 -Wed, 16 Aug 2017 23:16:55 GMT - -### Patches - -- Publish - -## 1.2.4 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 1.2.3 -Fri, 11 Aug 2017 21:44:05 GMT - -### Patches - -- Allow the webpack task to be extended with new configuration args. - -## 1.2.2 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 1.2.1 -Tue, 25 Jul 2017 20:03:31 GMT - -### Patches - -- Upgrade to TypeScript 2.4 - -## 1.2.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 1.1.8 -Wed, 21 Jun 2017 04:19:35 GMT - -### Patches - -- Add missing API Extractor release tags - -## 1.1.6 -Mon, 15 May 2017 21:59:43 GMT - -### Patches - -- Remove unnecessary fsevents optional dependency - -## 1.1.5 -Mon, 24 Apr 2017 22:01:17 GMT - -### Patches - -- Updating --initwebpack to contain the proper namespace. - -## 1.1.4 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 1.1.3 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 1.1.2 -Tue, 31 Jan 2017 20:32:37 GMT - -### Patches - -- Make loadSchema public instead of protected. - -## 1.1.1 -Tue, 31 Jan 2017 01:55:09 GMT - -### Patches - -- Introduce schema for WebpackTask - -## 1.1.0 -Thu, 19 Jan 2017 02:37:34 GMT - -### Minor changes - -- Including an option to pass in the webpack compiler object to the GCB-webpack task. - -## 1.0.4 -Fri, 13 Jan 2017 06:46:05 GMT - -*Version update only* - -## 1.0.3 -Fri, 16 Dec 2016 07:47:32 GMT - -### Patches - -- Patching webpack due to a publishing issue not publishing it in the last batch. - diff --git a/core-build/gulp-core-build-webpack/LICENSE b/core-build/gulp-core-build-webpack/LICENSE deleted file mode 100644 index e1cfd57af48..00000000000 --- a/core-build/gulp-core-build-webpack/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build-webpack - -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/core-build/gulp-core-build-webpack/README.md b/core-build/gulp-core-build-webpack/README.md deleted file mode 100644 index 8ad8204e800..00000000000 --- a/core-build/gulp-core-build-webpack/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# @microsoft/gulp-core-build-webpack - -`gulp-core-build-webpack` is a `gulp-core-build` subtask which introduces the ability to bundle various source files into a set of bundles, using webpack. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-webpack.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build-webpack) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build-webpack.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build-webpack) -[![Dependencies](https://david-dm.org/Microsoft/gulp-core-build-webpack.svg)](https://david-dm.org/Microsoft/gulp-core-build-webpack) - -# Tasks -## WebpackTask - -### Description -This task invokes webpack using a consumer-specified `webpack.config.js` on a package. - -### Command Line Options -If the `--initwebpack` flag is passed to the command line, this task will initialize a `webpack.config.js` which bundles `lib/index.js` into `dist/{packagename}.js as a UMD module. - -### Config -```typescript -interface IWebpackConfig { - configPath: string; - config: Webpack.Configuration; - suppressWarnings: string[]; -} -``` -* **configPath** used to specify the local package relative path to a `webpack.config.js` -* **config** used to specify a webpack config object. **configPath** takes precidence over this option if it is set and the file it refefences exists. -* **suppressWarnings** used to specify regular expressions or regular expression strings that will prevent logging of a warning if that warning matches. - -Usage: -```typescript -build.webpack.setConfig({ - configPath: "./webpack.config.js" -}) -``` diff --git a/core-build/gulp-core-build-webpack/config/api-extractor.json b/core-build/gulp-core-build-webpack/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/gulp-core-build-webpack/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/gulp-core-build-webpack/gulpfile.js b/core-build/gulp-core-build-webpack/gulpfile.js deleted file mode 100644 index 37aa39ec67b..00000000000 --- a/core-build/gulp-core-build-webpack/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/core-build/gulp-core-build-webpack/package.json b/core-build/gulp-core-build-webpack/package.json deleted file mode 100644 index eb42641a37d..00000000000 --- a/core-build/gulp-core-build-webpack/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build-webpack", - "version": "5.0.2", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build-webpack" - }, - "scripts": { - "build": "gulp --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@types/gulp": "4.0.6", - "@types/node": "10.17.13", - "colors": "~1.2.1", - "gulp": "~4.0.2", - "webpack": "~4.31.0" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/orchestrator": "0.0.30", - "@types/source-map": "0.5.0", - "@types/uglify-js": "2.6.29", - "@types/webpack": "4.39.8", - "@types/webpack-dev-server": "3.1.7" - } -} diff --git a/core-build/gulp-core-build-webpack/src/WebpackTask.ts b/core-build/gulp-core-build-webpack/src/WebpackTask.ts deleted file mode 100644 index 73cb44b5625..00000000000 --- a/core-build/gulp-core-build-webpack/src/WebpackTask.ts +++ /dev/null @@ -1,198 +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 colors from 'colors'; -import * as Webpack from 'webpack'; -import { GulpTask, IBuildConfig } from '@microsoft/gulp-core-build'; -import * as Gulp from 'gulp'; -import { EOL } from 'os'; - -/** - * @public - */ -export interface IWebpackTaskConfig { - /** - * Path to a webpack config. A path to a config takes precedence over the "config" option. - */ - configPath: string; - - /** - * Webpack config object, or array of config objects for multi-compiler. - * If a path is specified by "configPath," and it is valid, this option is ignored. - */ - config?: Webpack.Configuration | Webpack.Configuration[]; - - /** - * An array of regular expressions or regular expression strings. If a warning matches any of them, it - * will not be logged. - */ - suppressWarnings?: (string | RegExp)[]; - - /** - * An instance of the webpack compiler object, useful for building with Webpack 2.X while GCB is still on 1.X. - */ - webpack?: typeof Webpack; - - /** - * If true, a summary of the compilation will be printed after it completes. Defaults to true. - */ - printStats?: boolean; -} - -/** - * @public - */ -export interface IWebpackResources { - webpack: typeof Webpack; -} - -/** - * @public - */ -export class WebpackTask extends GulpTask { - private _resources: IWebpackResources; - - public constructor(extendedName?: string, extendedConfig?: TExtendedConfig) { - super( - extendedName || 'webpack', - { - configPath: './webpack.config.js', - suppressWarnings: [], - printStats: true, - ...extendedConfig - } as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - } - - public get resources(): IWebpackResources { - if (!this._resources) { - this._resources = { - webpack: this.taskConfig.webpack || require('webpack') - }; - } - - return this._resources; - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - return ( - super.isEnabled(buildConfig) && - this.taskConfig.configPath !== null // eslint-disable-line @rushstack/no-null - ); - } - - public loadSchema(): any { // eslint-disable-line @typescript-eslint/no-explicit-any - return require('./webpack.schema.json'); - } - - public executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): void { - const shouldInitWebpack: boolean = (process.argv.indexOf('--initwebpack') > -1); - - // eslint-disable-next-line - const path = require('path'); - - if (shouldInitWebpack) { - this.log( - 'Initializing a webpack.config.js, which bundles lib/index.js ' + - 'into dist/packagename.js into a UMD module.'); - - this.copyFile(path.resolve(__dirname, 'webpack.config.js')); - completeCallback(); - } else { - let webpackConfig: any; // eslint-disable-line @typescript-eslint/no-explicit-any - - if (this.taskConfig.configPath && this.fileExists(this.taskConfig.configPath)) { - try { - webpackConfig = require(this.resolvePath(this.taskConfig.configPath)); - } catch (err) { - completeCallback(`Error parsing webpack config: ${this.taskConfig.configPath}: ${err}`); - return; - } - } else if (this.taskConfig.config) { - webpackConfig = this.taskConfig.config; - } else { - this._logMissingConfigWarning(); - completeCallback(); - return; - } - - if (webpackConfig) { - const webpack: typeof Webpack = this.taskConfig.webpack || require('webpack'); - const startTime: number = new Date().getTime(); - const outputDir: string = this.buildConfig.distFolder; - - webpack( - webpackConfig, - (error, stats) => { - if (!this.buildConfig.properties) { - this.buildConfig.properties = {}; - } - - // eslint-disable-next-line dot-notation - this.buildConfig.properties['webpackStats'] = stats; - - const statsResult: Webpack.Stats.ToJsonOutput = stats.toJson({ - hash: false, - source: false - }); - - if (statsResult.errors && statsResult.errors.length) { - this.logError(`'${outputDir}':` + EOL + statsResult.errors.join(EOL) + EOL); - } - - if (statsResult.warnings && statsResult.warnings.length) { - const unsuppressedWarnings: string[] = []; - const warningSuppressionRegexes: RegExp[] = (this.taskConfig.suppressWarnings || []).map((regex: string) => { - return new RegExp(regex); - }); - - statsResult.warnings.forEach((warning: string) => { - let suppressed: boolean = false; - for (let i: number = 0; i < warningSuppressionRegexes.length; i++) { - const suppressionRegex: RegExp = warningSuppressionRegexes[i]; - if (warning.match(suppressionRegex)) { - suppressed = true; - break; - } - } - - if (!suppressed) { - unsuppressedWarnings.push(warning); - } - }); - - if (unsuppressedWarnings.length > 0) { - this.logWarning(`'${outputDir}':` + EOL + unsuppressedWarnings.join(EOL) + EOL); - } - } - - const duration: number = (new Date().getTime() - startTime); - const statsResultChildren: Webpack.Stats.ToJsonOutput[] = statsResult.children ? statsResult.children : [statsResult]; - - statsResultChildren.forEach(child => { - if (child.chunks) { - child.chunks.forEach(chunk => { - if (chunk.files && this.taskConfig.printStats) { - chunk.files.forEach(file => ( - this.log(`Bundled: '${colors.cyan(path.basename(file))}', ` + - `size: ${colors.magenta(chunk.size.toString())} bytes, ` + - `took ${colors.magenta(duration.toString(10))} ms.`) - )); // end file - } - }); // end chunk - } - }); // end child - - completeCallback(); - }); // endwebpack callback - } - } - } - - private _logMissingConfigWarning(): void { - this.logWarning( - 'No webpack config has been provided. ' + - 'Run again using --initwebpack to create a default config, ' + - `or call webpack.setConfig({ configPath: null }) in your gulpfile.`); - } -} diff --git a/core-build/gulp-core-build-webpack/src/index.ts b/core-build/gulp-core-build-webpack/src/index.ts deleted file mode 100644 index 2705807b085..00000000000 --- a/core-build/gulp-core-build-webpack/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { WebpackTask } from './WebpackTask'; - -export { - IWebpackTaskConfig, - IWebpackResources, - WebpackTask -} from './WebpackTask'; - -/** - * @public - */ -export const webpack: WebpackTask = new WebpackTask(); -export default webpack; diff --git a/core-build/gulp-core-build-webpack/src/webpack.config.ts b/core-build/gulp-core-build-webpack/src/webpack.config.ts deleted file mode 100644 index e03949d428d..00000000000 --- a/core-build/gulp-core-build-webpack/src/webpack.config.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as Webpack from 'webpack'; -// @ts-ignore -import * as WebpackDevServer from 'webpack-dev-server'; // eslint-disable-line -import { WebpackTask } from './WebpackTask'; -import * as path from 'path'; - -// Note: this require may need to be fixed to point to the build that exports the gulp-core-build-webpack instance. -const webpackTask: WebpackTask = require('@microsoft/web-library-build').webpack; -const webpack: typeof Webpack = webpackTask.resources.webpack; - -const isProduction: boolean = webpackTask.buildConfig.production; - -// eslint-disable-next-line -const packageJSON: { name: string } = require('./package.json'); - -const webpackConfiguration: Webpack.Configuration = { - context: __dirname, - devtool: (isProduction) ? undefined : 'source-map', - - entry: { - [packageJSON.name]: path.join(__dirname, webpackTask.buildConfig.libFolder, 'index.js') - }, - - output: { - libraryTarget: 'umd', - path: path.join(__dirname, webpackTask.buildConfig.distFolder), - filename: `[name]${isProduction ? '.min' : ''}.js` - }, - - // The typings are missing the "object" option here (https://webpack.js.org/configuration/externals/#object) - externals: { - 'react': { - amd: 'react', - commonjs: 'react' - }, - 'react-dom': { - amd: 'react-dom', - commonjs: 'react-dom' - } - } as any, // eslint-disable-line @typescript-eslint/no-explicit-any - - plugins: [ - // new WebpackNotifierPlugin() - ] -}; - -if (isProduction && webpackConfiguration.plugins) { - webpackConfiguration.plugins.push(new webpack.optimize.UglifyJsPlugin({ - mangle: true, - compress: { - dead_code: true, - warnings: false - } - })); -} - -exports = webpackConfiguration; diff --git a/core-build/gulp-core-build-webpack/src/webpack.schema.json b/core-build/gulp-core-build-webpack/src/webpack.schema.json deleted file mode 100644 index 19852b5bfd8..00000000000 --- a/core-build/gulp-core-build-webpack/src/webpack.schema.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "Webpack Task Configuration", - "description": "Defines parameters for the webpack bundler", - - "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" - }, - "config": { - "title": "WebPack configuration object.", - "description": "If a path is specified by `configPath,` and it is valid, this option is ignored.", - - "type": "object", - "additionalProperties": true - }, - - "configPath": { - "title": "Path to a webpack config", - "description": "A path to a config takes precedence over the `config` option.", - "type": "string" - }, - - "suppressWarnings": { - "title": "Warnings To Suppress", - "description": "If a warning matches any of these, it will not be logged.", - "type": "array", - "items": { - "type": "string" - } - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build-webpack/tsconfig.json b/core-build/gulp-core-build-webpack/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/core-build/gulp-core-build-webpack/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/core-build/gulp-core-build/.eslintrc.js b/core-build/gulp-core-build/.eslintrc.js deleted file mode 100644 index e2dba14d883..00000000000 --- a/core-build/gulp-core-build/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require("@rushstack/eslint-config/patch-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, - rules: { - // This predates the new ESLint ruleset; not worth fixing - "@typescript-eslint/no-use-before-define": "off" - } -}; diff --git a/core-build/gulp-core-build/.npmignore b/core-build/gulp-core-build/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/gulp-core-build/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/gulp-core-build/CHANGELOG.json b/core-build/gulp-core-build/CHANGELOG.json deleted file mode 100644 index 607e0088b49..00000000000 --- a/core-build/gulp-core-build/CHANGELOG.json +++ /dev/null @@ -1,2766 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build", - "entries": [ - { - "version": "3.15.3", - "tag": "@microsoft/gulp-core-build_v3.15.3", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "3.15.2", - "tag": "@microsoft/gulp-core-build_v3.15.2", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - } - ] - } - }, - { - "version": "3.15.1", - "tag": "@microsoft/gulp-core-build_v3.15.1", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" - } - ] - } - }, - { - "version": "3.15.0", - "tag": "@microsoft/gulp-core-build_v3.15.0", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "minor": [ - { - "comment": "Add GCBTerminalProvider for use in GulpTasks." - } - ] - } - }, - { - "version": "3.14.2", - "tag": "@microsoft/gulp-core-build_v3.14.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" - } - ] - } - }, - { - "version": "3.14.1", - "tag": "@microsoft/gulp-core-build_v3.14.1", - "date": "Tue, 21 Jan 2020 21:56:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "3.14.0", - "tag": "@microsoft/gulp-core-build_v3.14.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "3.13.4", - "tag": "@microsoft/gulp-core-build_v3.13.4", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.13.3", - "tag": "@microsoft/gulp-core-build_v3.13.3", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "patch": [ - { - "comment": "Temporarily disable the HTML Jest reporter in the default config because of an issue with Handlebars." - } - ] - } - }, - { - "version": "3.13.2", - "tag": "@microsoft/gulp-core-build_v3.13.2", - "date": "Thu, 09 Jan 2020 06:44:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.13.1", - "tag": "@microsoft/gulp-core-build_v3.13.1", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "3.13.0", - "tag": "@microsoft/gulp-core-build_v3.13.0", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "minor": [ - { - "comment": "Add ability to write Jest results as an NUnit compatible file" - } - ] - } - }, - { - "version": "3.12.5", - "tag": "@microsoft/gulp-core-build_v3.12.5", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" - } - ] - } - }, - { - "version": "3.12.4", - "tag": "@microsoft/gulp-core-build_v3.12.4", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.12.3", - "tag": "@microsoft/gulp-core-build_v3.12.3", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" - } - ] - } - }, - { - "version": "3.12.2", - "tag": "@microsoft/gulp-core-build_v3.12.2", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor some code as part of migration from TSLint to ESLint" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.12.1", - "tag": "@microsoft/gulp-core-build_v3.12.1", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" - } - ] - } - }, - { - "version": "3.12.0", - "tag": "@microsoft/gulp-core-build_v3.12.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" - } - ] - } - }, - { - "version": "3.11.3", - "tag": "@microsoft/gulp-core-build_v3.11.3", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" - } - ] - } - }, - { - "version": "3.11.2", - "tag": "@microsoft/gulp-core-build_v3.11.2", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" - } - ] - } - }, - { - "version": "3.11.1", - "tag": "@microsoft/gulp-core-build_v3.11.1", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" - } - ] - } - }, - { - "version": "3.11.0", - "tag": "@microsoft/gulp-core-build_v3.11.0", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "minor": [ - { - "comment": "Introduce an optional build timeout." - } - ], - "patch": [ - { - "comment": "Security updates." - } - ] - } - }, - { - "version": "3.10.0", - "tag": "@microsoft/gulp-core-build_v3.10.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2" - } - ] - } - }, - { - "version": "3.9.26", - "tag": "@microsoft/gulp-core-build_v3.9.26", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "3.9.25", - "tag": "@microsoft/gulp-core-build_v3.9.25", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - } - ] - } - }, - { - "version": "3.9.24", - "tag": "@microsoft/gulp-core-build_v3.9.24", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - } - ] - } - }, - { - "version": "3.9.23", - "tag": "@microsoft/gulp-core-build_v3.9.23", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - } - ] - } - }, - { - "version": "3.9.22", - "tag": "@microsoft/gulp-core-build_v3.9.22", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - } - ] - } - }, - { - "version": "3.9.21", - "tag": "@microsoft/gulp-core-build_v3.9.21", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - } - ] - } - }, - { - "version": "3.9.20", - "tag": "@microsoft/gulp-core-build_v3.9.20", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - } - ] - } - }, - { - "version": "3.9.19", - "tag": "@microsoft/gulp-core-build_v3.9.19", - "date": "Thu, 21 Mar 2019 01:15:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - } - ] - } - }, - { - "version": "3.9.18", - "tag": "@microsoft/gulp-core-build_v3.9.18", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - } - ] - } - }, - { - "version": "3.9.17", - "tag": "@microsoft/gulp-core-build_v3.9.17", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - } - ] - } - }, - { - "version": "3.9.16", - "tag": "@microsoft/gulp-core-build_v3.9.16", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - } - ] - } - }, - { - "version": "3.9.15", - "tag": "@microsoft/gulp-core-build_v3.9.15", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - } - ] - } - }, - { - "version": "3.9.14", - "tag": "@microsoft/gulp-core-build_v3.9.14", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - } - ] - } - }, - { - "version": "3.9.13", - "tag": "@microsoft/gulp-core-build_v3.9.13", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - } - ] - } - }, - { - "version": "3.9.12", - "tag": "@microsoft/gulp-core-build_v3.9.12", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - } - ] - } - }, - { - "version": "3.9.11", - "tag": "@microsoft/gulp-core-build_v3.9.11", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - } - ] - } - }, - { - "version": "3.9.10", - "tag": "@microsoft/gulp-core-build_v3.9.10", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.1` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "3.9.9", - "tag": "@microsoft/gulp-core-build_v3.9.9", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "3.9.8", - "tag": "@microsoft/gulp-core-build_v3.9.8", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "3.9.7", - "tag": "@microsoft/gulp-core-build_v3.9.7", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "3.9.6", - "tag": "@microsoft/gulp-core-build_v3.9.6", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.9.5", - "tag": "@microsoft/gulp-core-build_v3.9.5", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.9.0` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.9.4", - "tag": "@microsoft/gulp-core-build_v3.9.4", - "date": "Wed, 30 Jan 2019 20:49:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - } - ] - } - }, - { - "version": "3.9.3", - "tag": "@microsoft/gulp-core-build_v3.9.3", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - } - ] - } - }, - { - "version": "3.9.2", - "tag": "@microsoft/gulp-core-build_v3.9.2", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "patch": [ - { - "comment": "Remove karma task." - } - ] - } - }, - { - "version": "3.9.1", - "tag": "@microsoft/gulp-core-build_v3.9.1", - "date": "Thu, 10 Jan 2019 01:57:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.3` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "3.9.0", - "tag": "@microsoft/gulp-core-build_v3.9.0", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Jest to version 23." - } - ] - } - }, - { - "version": "3.8.57", - "tag": "@microsoft/gulp-core-build_v3.8.57", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "3.8.56", - "tag": "@microsoft/gulp-core-build_v3.8.56", - "date": "Thu, 13 Dec 2018 02:58:10 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unused jju dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "3.8.55", - "tag": "@microsoft/gulp-core-build_v3.8.55", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "3.8.54", - "tag": "@microsoft/gulp-core-build_v3.8.54", - "date": "Sat, 08 Dec 2018 06:35:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - } - ] - } - }, - { - "version": "3.8.53", - "tag": "@microsoft/gulp-core-build_v3.8.53", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.1` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "3.8.52", - "tag": "@microsoft/gulp-core-build_v3.8.52", - "date": "Fri, 30 Nov 2018 23:34:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - } - ] - } - }, - { - "version": "3.8.51", - "tag": "@microsoft/gulp-core-build_v3.8.51", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "3.8.50", - "tag": "@microsoft/gulp-core-build_v3.8.50", - "date": "Thu, 29 Nov 2018 00:35:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - } - ] - } - }, - { - "version": "3.8.49", - "tag": "@microsoft/gulp-core-build_v3.8.49", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - } - ] - } - }, - { - "version": "3.8.48", - "tag": "@microsoft/gulp-core-build_v3.8.48", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.6.0` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "3.8.47", - "tag": "@microsoft/gulp-core-build_v3.8.47", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.2` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "3.8.46", - "tag": "@microsoft/gulp-core-build_v3.8.46", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "3.8.45", - "tag": "@microsoft/gulp-core-build_v3.8.45", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "3.8.44", - "tag": "@microsoft/gulp-core-build_v3.8.44", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.8.43", - "tag": "@microsoft/gulp-core-build_v3.8.43", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - } - ] - } - }, - { - "version": "3.8.42", - "tag": "@microsoft/gulp-core-build_v3.8.42", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "patch": [ - { - "comment": "Remove all dependencies on the \"rimraf\" library" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "3.8.41", - "tag": "@microsoft/gulp-core-build_v3.8.41", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "3.8.40", - "tag": "@microsoft/gulp-core-build_v3.8.40", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.8.39", - "tag": "@microsoft/gulp-core-build_v3.8.39", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.8.38", - "tag": "@microsoft/gulp-core-build_v3.8.38", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - } - ] - } - }, - { - "version": "3.8.37", - "tag": "@microsoft/gulp-core-build_v3.8.37", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - } - ] - } - }, - { - "version": "3.8.36", - "tag": "@microsoft/gulp-core-build_v3.8.36", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - } - ] - } - }, - { - "version": "3.8.35", - "tag": "@microsoft/gulp-core-build_v3.8.35", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.4.0` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "3.8.34", - "tag": "@microsoft/gulp-core-build_v3.8.34", - "date": "Thu, 25 Oct 2018 08:56:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "3.8.33", - "tag": "@microsoft/gulp-core-build_v3.8.33", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.1` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "3.8.32", - "tag": "@microsoft/gulp-core-build_v3.8.32", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "patch": [ - { - "comment": "Replace deprecated dependency gulp-util" - } - ] - } - }, - { - "version": "3.8.31", - "tag": "@microsoft/gulp-core-build_v3.8.31", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "3.8.30", - "tag": "@microsoft/gulp-core-build_v3.8.30", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "patch": [ - { - "comment": "Remove use of a deprecated Buffer API." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "3.8.29", - "tag": "@microsoft/gulp-core-build_v3.8.29", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "3.8.28", - "tag": "@microsoft/gulp-core-build_v3.8.28", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "3.8.27", - "tag": "@microsoft/gulp-core-build_v3.8.27", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "3.8.26", - "tag": "@microsoft/gulp-core-build_v3.8.26", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.2.0` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "3.8.25", - "tag": "@microsoft/gulp-core-build_v3.8.25", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "patch": [ - { - "comment": "Update documentation" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.1.0` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - } - ] - } - }, - { - "version": "3.8.24", - "tag": "@microsoft/gulp-core-build_v3.8.24", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.1` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - } - ] - } - }, - { - "version": "3.8.23", - "tag": "@microsoft/gulp-core-build_v3.8.23", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - } - ] - } - }, - { - "version": "3.8.22", - "tag": "@microsoft/gulp-core-build_v3.8.22", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - } - ] - } - }, - { - "version": "3.8.21", - "tag": "@microsoft/gulp-core-build_v3.8.21", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - } - ] - } - }, - { - "version": "3.8.20", - "tag": "@microsoft/gulp-core-build_v3.8.20", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - } - ] - } - }, - { - "version": "3.8.19", - "tag": "@microsoft/gulp-core-build_v3.8.19", - "date": "Tue, 18 Sep 2018 21:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - } - ] - } - }, - { - "version": "3.8.18", - "tag": "@microsoft/gulp-core-build_v3.8.18", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "3.8.17", - "tag": "@microsoft/gulp-core-build_v3.8.17", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "3.8.16", - "tag": "@microsoft/gulp-core-build_v3.8.16", - "date": "Mon, 03 Sep 2018 16:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "3.8.15", - "tag": "@microsoft/gulp-core-build_v3.8.15", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "3.8.14", - "tag": "@microsoft/gulp-core-build_v3.8.14", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where the Jest task uses the global temp directory." - } - ] - } - }, - { - "version": "3.8.13", - "tag": "@microsoft/gulp-core-build_v3.8.13", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "3.8.12", - "tag": "@microsoft/gulp-core-build_v3.8.12", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "patch": [ - { - "comment": "Update to use new node-core-library API" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.1` to `3.0.0`" - } - ] - } - }, - { - "version": "3.8.11", - "tag": "@microsoft/gulp-core-build_v3.8.11", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.2.0` to `2.2.1`" - } - ] - } - }, - { - "version": "3.8.10", - "tag": "@microsoft/gulp-core-build_v3.8.10", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.1` to `2.2.0`" - } - ] - } - }, - { - "version": "3.8.9", - "tag": "@microsoft/gulp-core-build_v3.8.9", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.1.0` to `2.1.1`" - } - ] - } - }, - { - "version": "3.8.8", - "tag": "@microsoft/gulp-core-build_v3.8.8", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `2.0.0` to `2.1.0`" - } - ] - } - }, - { - "version": "3.8.7", - "tag": "@microsoft/gulp-core-build_v3.8.7", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "patch": [ - { - "comment": "Add explicit dependency on jsdom to workaround Jest regression #6766" - } - ] - } - }, - { - "version": "3.8.6", - "tag": "@microsoft/gulp-core-build_v3.8.6", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.5.0` to `2.0.0`" - } - ] - } - }, - { - "version": "3.8.5", - "tag": "@microsoft/gulp-core-build_v3.8.5", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.4.1` to `1.5.0`" - } - ] - } - }, - { - "version": "3.8.4", - "tag": "@microsoft/gulp-core-build_v3.8.4", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.4.0` to `1.4.1`" - } - ] - } - }, - { - "version": "3.8.3", - "tag": "@microsoft/gulp-core-build_v3.8.3", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.2` to `1.4.0`" - } - ] - } - }, - { - "version": "3.8.2", - "tag": "@microsoft/gulp-core-build_v3.8.2", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.1` to `1.3.2`" - } - ] - } - }, - { - "version": "3.8.1", - "tag": "@microsoft/gulp-core-build_v3.8.1", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.3.0` to `1.3.1`" - } - ] - } - }, - { - "version": "3.8.0", - "tag": "@microsoft/gulp-core-build_v3.8.0", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for modulePathIgnorePatterns for the Jest task" - } - ], - "patch": [ - { - "comment": "Upgrade to Jest 22.4.3 and remove the workaround for the symlink bug" - } - ] - } - }, - { - "version": "3.7.5", - "tag": "@microsoft/gulp-core-build_v3.7.5", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.2.0` to `1.3.0`" - } - ] - } - }, - { - "version": "3.7.4", - "tag": "@microsoft/gulp-core-build_v3.7.4", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.1.0` to `1.2.0`" - } - ] - } - }, - { - "version": "3.7.3", - "tag": "@microsoft/gulp-core-build_v3.7.3", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `1.0.0` to `1.1.0`" - } - ] - } - }, - { - "version": "3.7.2", - "tag": "@microsoft/gulp-core-build_v3.7.2", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue where snapshot filenames did not follow Jest's naming convention." - } - ] - } - }, - { - "version": "3.7.1", - "tag": "@microsoft/gulp-core-build_v3.7.1", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade colors to version ~1.2.1" - } - ] - } - }, - { - "version": "3.7.0", - "tag": "@microsoft/gulp-core-build_v3.7.0", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "minor": [ - { - "comment": "Add a `libESNextFolder` option" - } - ] - } - }, - { - "version": "3.6.10", - "tag": "@microsoft/gulp-core-build_v3.6.10", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.8.0` to `1.0.0`" - } - ] - } - }, - { - "version": "3.6.9", - "tag": "@microsoft/gulp-core-build_v3.6.9", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.3` to `0.8.0`" - } - ] - } - }, - { - "version": "3.6.8", - "tag": "@microsoft/gulp-core-build_v3.6.8", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "patch": [ - { - "comment": "Fix the \"relogIssues\" buld config option." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.2` to `0.7.3`" - } - ] - } - }, - { - "version": "3.6.7", - "tag": "@microsoft/gulp-core-build_v3.6.7", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.1` to `0.7.2`" - } - ] - } - }, - { - "version": "3.6.6", - "tag": "@microsoft/gulp-core-build_v3.6.6", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.7.0` to `0.7.1`" - } - ] - } - }, - { - "version": "3.6.5", - "tag": "@microsoft/gulp-core-build_v3.6.5", - "date": "Wed, 21 Feb 2018 03:13:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.6.1` to `0.7.0`" - } - ] - } - }, - { - "version": "3.6.4", - "tag": "@microsoft/gulp-core-build_v3.6.4", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.6.0` to `0.6.1`" - } - ] - } - }, - { - "version": "3.6.3", - "tag": "@microsoft/gulp-core-build_v3.6.3", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.5.1` to `0.6.0`" - } - ] - } - }, - { - "version": "3.6.2", - "tag": "@microsoft/gulp-core-build_v3.6.2", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "3.6.1", - "tag": "@microsoft/gulp-core-build_v3.6.1", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.10` to `0.5.0`" - } - ] - } - }, - { - "version": "3.6.0", - "tag": "@microsoft/gulp-core-build_v3.6.0", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "minor": [ - { - "comment": "made default testMatch and maxWorkers arguments in Jest task overridable" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.9` to `0.4.10`" - } - ] - } - }, - { - "version": "3.5.3", - "tag": "@microsoft/gulp-core-build_v3.5.3", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.8` to `0.4.9`" - } - ] - } - }, - { - "version": "3.5.2", - "tag": "@microsoft/gulp-core-build_v3.5.2", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.7` to `0.4.8`" - } - ] - } - }, - { - "version": "3.5.1", - "tag": "@microsoft/gulp-core-build_v3.5.1", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "patch": [ - { - "comment": "Replace gulp-util.colors with colors package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.6` to `0.4.7`" - } - ] - } - }, - { - "version": "3.5.0", - "tag": "@microsoft/gulp-core-build_v3.5.0", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "minor": [ - { - "comment": "Add a feature where when shouldWarningsFailBuild is true, then we will hook stderr and fail the build if anything consequential is written there" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.5` to `0.4.6`" - } - ] - } - }, - { - "version": "3.4.4", - "tag": "@microsoft/gulp-core-build_v3.4.4", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.4` to `0.4.5`" - } - ] - } - }, - { - "version": "3.4.3", - "tag": "@microsoft/gulp-core-build_v3.4.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "3.4.2", - "tag": "@microsoft/gulp-core-build_v3.4.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/gulp-core-build_v3.4.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "f1ba3c91dcdb8eb661fb303583f4476bce2c099f", - "comment": "Fix Jest error handling" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/gulp-core-build_v3.4.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.26` to `0.4.0`" - } - ] - } - }, - { - "version": "3.3.7", - "tag": "@microsoft/gulp-core-build_v3.3.7", - "date": "Tue, 09 Jan 2018 17:05:51 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "d00b6549d13610fbb6f84be3478b532be9da0747", - "comment": "Get web-build-tools building with pnpm" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.25` to `0.3.26`" - } - ] - } - }, - { - "version": "3.3.6", - "tag": "@microsoft/gulp-core-build_v3.3.6", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.24` to `0.3.25`" - } - ] - } - }, - { - "version": "3.3.5", - "tag": "@microsoft/gulp-core-build_v3.3.5", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "4626d69e54f05aaabf87479626e8c1b6fcdc7eff", - "comment": "Specify package version for chalk. It was used without version specified." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.23` to `0.3.24`" - } - ] - } - }, - { - "version": "3.3.4", - "tag": "@microsoft/gulp-core-build_v3.3.4", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "patch": [ - { - "author": "Nicholas Pape ", - "commit": "b942f54445bf01dbdb98aaa5f0007f5b95315b58", - "comment": "Update Jest to ~21.2.1" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.22` to `0.3.23`" - } - ] - } - }, - { - "version": "3.3.3", - "tag": "@microsoft/gulp-core-build_v3.3.3", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.21` to `0.3.22`" - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/gulp-core-build_v3.3.2", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.20` to `0.3.21`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/gulp-core-build_v3.3.1", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "patch": [ - { - "author": "Oleg F <1832418+olfilato@users.noreply.github.com>", - "commit": "68ba0ac17fb415cbc5ae9ec7508e9b426e50d46b", - "comment": "reverted addition of rootDir as a parameter for jest task" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.19` to `0.3.20`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/gulp-core-build_v3.3.0", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "minor": [ - { - "author": "Oleg F <1832418+olfilato@users.noreply.github.com>", - "commit": "23b9679ff4b4adbd4fd56253e7283a92091443ee", - "comment": "Added optional args moduleDirectories and rootDir to JestTask" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.18` to `0.3.19`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/gulp-core-build_v3.2.9", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "a3b528954bebb0e683a2a860e36a568b3f778643", - "comment": "Add cache configuration to Jest task" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.17` to `0.3.18`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/gulp-core-build_v3.2.8", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.16` to `0.3.17`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/gulp-core-build_v3.2.7", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "872d10d28296059de4e844a5ece2aa95e28ac1d3", - "comment": "Allow settings in jest.json to override Jest task's default options" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.15` to `0.3.16`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/gulp-core-build_v3.2.6", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "f5ce31ad32c1102790b4fe1d5264b7691400cb57", - "comment": "Automatically use --colors unless --no-colors is specified." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.14` to `0.3.15`" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/gulp-core-build_v3.2.5", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "patch": [ - { - "author": "QZ ", - "commit": "2c58095f2f13492887cc1278c9a0cff49af9735b", - "comment": "lock the reference version between web build tools projects" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/gulp-core-build_v3.2.4", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "e449bd6cdc3c179461be68e59590c25021cd1286", - "comment": "Upgrade cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.12` to `~0.3.13`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/gulp-core-build_v3.2.3", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.11` to `~0.3.12`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/gulp-core-build_v3.2.2", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "e204dd49b5af75511cf0dd8e50eb6c6c40a694a1", - "comment": "Fix an issue where an exception was being thrown when displaying toasts for build failures." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.10` to `~0.3.11`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/gulp-core-build_v3.2.1", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.9` to `~0.3.10`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/gulp-core-build_v3.2.0", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "minor": [ - { - "author": "QZ ", - "commit": "5fe47765dbb3567bebc30cf5d7ac2205f6e655b0", - "comment": "Add a Jest task to support running tests on Jest" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.8` to `~0.3.9`" - } - ] - } - }, - { - "version": "3.1.6", - "tag": "@microsoft/gulp-core-build_v3.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "patch": [ - { - "author": "pgonzal ", - "commit": "5de032b254b632b8af0d0dd98913acef589f88d5", - "comment": "Updated cyclic dependencies" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.7` to `~0.3.8`" - } - ] - } - }, - { - "version": "3.1.5", - "tag": "@microsoft/gulp-core-build_v3.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.6` to `~0.3.7`" - } - ] - } - }, - { - "version": "3.1.4", - "tag": "@microsoft/gulp-core-build_v3.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.5` to `~0.3.6`" - } - ] - } - }, - { - "version": "3.1.3", - "tag": "@microsoft/gulp-core-build_v3.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.4` to `~0.3.5`" - } - ] - } - }, - { - "version": "3.1.2", - "tag": "@microsoft/gulp-core-build_v3.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.2` to `~0.3.3`" - } - ] - } - }, - { - "version": "3.1.1", - "tag": "@microsoft/gulp-core-build_v3.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.0` to `~0.3.1`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/gulp-core-build_v3.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.11` to `~0.3.0`" - } - ] - } - }, - { - "version": "3.0.8", - "tag": "@microsoft/gulp-core-build_v3.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.10` to `~0.2.11`" - } - ] - } - }, - { - "version": "3.0.7", - "tag": "@microsoft/gulp-core-build_v3.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.9` to `~0.2.10`" - } - ] - } - }, - { - "version": "3.0.6", - "tag": "@microsoft/gulp-core-build_v3.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.7` to `~0.2.8`" - } - ] - } - }, - { - "version": "3.0.5", - "tag": "@microsoft/gulp-core-build_v3.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.6` to `~0.2.7`" - } - ] - } - }, - { - "version": "3.0.4", - "tag": "@microsoft/gulp-core-build_v3.0.4", - "date": "Thu, 07 Sep 2017 00:11:12 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "4b7451b442c2078a96430f7a05caed37101aed52", - "comment": " Add $schema field to all schemas" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.5` to `~0.2.6`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/gulp-core-build_v3.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.4` to `~0.2.5`" - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/gulp-core-build_v3.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.3` to `~0.2.4`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/gulp-core-build_v3.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.2` to `~0.2.3`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/gulp-core-build_v3.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.1` to `~0.2.2`" - } - ] - } - }, - { - "version": "2.10.1", - "tag": "@microsoft/gulp-core-build_v2.10.1", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.2.0` to `~0.2.1`" - } - ] - } - }, - { - "version": "2.10.0", - "tag": "@microsoft/gulp-core-build_v2.10.0", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "minor": [ - { - "comment": "added CopyStaticAssetsTask" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.1.3` to `~0.2.0`" - } - ] - } - }, - { - "version": "2.9.6", - "tag": "@microsoft/gulp-core-build_v2.9.6", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "patch": [ - { - "comment": "Update the schema validator." - } - ] - } - }, - { - "version": "2.9.5", - "tag": "@microsoft/gulp-core-build_v2.9.5", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": {} - }, - { - "version": "2.9.4", - "tag": "@microsoft/gulp-core-build_v2.9.4", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": {} - }, - { - "version": "2.9.3", - "tag": "@microsoft/gulp-core-build_v2.9.3", - "date": "Tue, 15 Aug 2017 19:04:14 GMT", - "comments": { - "patch": [ - { - "comment": "Allow a partial config to be passed to GulpTask.mergeConfig." - } - ] - } - }, - { - "version": "2.9.2", - "tag": "@microsoft/gulp-core-build_v2.9.2", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump to ensure everything is published" - } - ] - } - }, - { - "version": "2.9.1", - "tag": "@microsoft/gulp-core-build_v2.9.1", - "date": "Sat, 12 Aug 2017 01:03:30 GMT", - "comments": { - "patch": [ - { - "comment": "Add missing orchestrator dependency." - } - ] - } - }, - { - "version": "2.9.0", - "tag": "@microsoft/gulp-core-build_v2.9.0", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "minor": [ - { - "comment": "Refactor GulpTask to support taking the name and initial task configuration through the constructor." - } - ] - } - }, - { - "version": "2.8.0", - "tag": "@microsoft/gulp-core-build_v2.8.0", - "date": "Sat, 05 Aug 2017 01:04:41 GMT", - "comments": { - "minor": [ - { - "comment": "Add a --clean or -c command line flag which runs the clean task." - } - ] - } - }, - { - "version": "2.7.3", - "tag": "@microsoft/gulp-core-build_v2.7.3", - "date": "Mon, 31 Jul 2017 21:18:26 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade @types/semver to 5.3.33" - } - ] - } - }, - { - "version": "2.7.2", - "tag": "@microsoft/gulp-core-build_v2.7.2", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools." - } - ] - } - }, - { - "version": "2.7.1", - "tag": "@microsoft/gulp-core-build_v2.7.1", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ] - } - }, - { - "version": "2.7.0", - "tag": "@microsoft/gulp-core-build_v2.7.0", - "date": "Wed, 12 Jul 2017 01:04:36 GMT", - "comments": { - "minor": [ - { - "comment": "Add the ability to suppress warnings and errors via a regular expression" - } - ] - } - }, - { - "version": "2.6.0", - "tag": "@microsoft/gulp-core-build_v2.6.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ] - } - }, - { - "version": "2.5.6", - "tag": "@microsoft/gulp-core-build_v2.5.6", - "date": "Thu, 29 Jun 2017 01:05:37 GMT", - "comments": { - "patch": [ - { - "comment": "Improve watch() so that it will automatically begin excecuting and it will not exit if there is a failure on the initial build" - } - ] - } - }, - { - "version": "2.5.5", - "tag": "@microsoft/gulp-core-build_v2.5.5", - "date": "Wed, 21 Jun 2017 04:19:35 GMT", - "comments": { - "patch": [ - { - "comment": "Add missing API Extractor release tags" - } - ] - } - }, - { - "version": "2.5.3", - "tag": "@microsoft/gulp-core-build_v2.5.3", - "date": "Wed, 31 May 2017 01:08:33 GMT", - "comments": { - "patch": [ - { - "comment": "Normalizing slashes in warnings suppressions to suppress warnings across windows and 'nix." - } - ] - } - }, - { - "version": "2.5.2", - "tag": "@microsoft/gulp-core-build_v2.5.2", - "date": "Wed, 24 May 2017 01:27:16 GMT", - "comments": { - "patch": [ - { - "comment": "Only show overriden errors and warnings when we are in verbose mode." - } - ] - } - }, - { - "version": "2.5.1", - "tag": "@microsoft/gulp-core-build_v2.5.1", - "date": "Tue, 16 May 2017 21:17:17 GMT", - "comments": { - "patch": [ - { - "comment": "Fixing an issue with how the GCB schema validator handles errors." - } - ] - } - }, - { - "version": "2.5.0", - "tag": "@microsoft/gulp-core-build_v2.5.0", - "date": "Mon, 24 Apr 2017 22:01:17 GMT", - "comments": { - "minor": [ - { - "comment": "Adding `libES6Folder` setting to build config to optionally instruct tasks to output es6 modules." - } - ] - } - }, - { - "version": "2.4.4", - "tag": "@microsoft/gulp-core-build_v2.4.4", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ] - } - }, - { - "version": "2.4.3", - "tag": "@microsoft/gulp-core-build_v2.4.3", - "date": "Mon, 20 Mar 2017 21:52:20 GMT", - "comments": {} - }, - { - "version": "2.4.2", - "tag": "@microsoft/gulp-core-build_v2.4.2", - "date": "Sat, 18 Mar 2017 01:31:49 GMT", - "comments": { - "patch": [ - { - "comment": "Fixes an issue with the clean command, which causes builds to spuriously fail." - } - ] - } - }, - { - "version": "2.4.1", - "tag": "@microsoft/gulp-core-build_v2.4.1", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ] - } - }, - { - "version": "2.4.0", - "tag": "@microsoft/gulp-core-build_v2.4.0", - "date": "Sat, 18 Feb 2017 02:32:06 GMT", - "comments": { - "minor": [ - { - "comment": "Add an enabled toggle to IExecutable and GulpTask. Using this toggle is now preferred to overriding the isEnabled function." - } - ] - } - }, - { - "version": "2.3.1", - "tag": "@microsoft/gulp-core-build_v2.3.1", - "date": "Thu, 09 Feb 2017 02:35:45 GMT", - "comments": { - "patch": [ - { - "comment": "Don't watch process exit if user passed in the -h flag." - } - ] - } - }, - { - "version": "2.3.0", - "tag": "@microsoft/gulp-core-build_v2.3.0", - "date": "Wed, 08 Feb 2017 01:41:58 GMT", - "comments": { - "minor": [ - { - "comment": "Remove a function which was exposing z-schema and causing issues." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=2.2.0 <3.0.0` to `>=2.2.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.2.3", - "tag": "@microsoft/gulp-core-build_v2.2.3", - "date": "Wed, 08 Feb 2017 01:05:47 GMT", - "comments": { - "patch": [ - { - "comment": "Ensure the log function is exported" - } - ] - } - }, - { - "version": "2.2.2", - "tag": "@microsoft/gulp-core-build_v2.2.2", - "date": "Wed, 08 Feb 2017 00:23:01 GMT", - "comments": { - "patch": [ - { - "comment": "Fix _flatten and make serial/parallel more robust" - } - ] - } - }, - { - "version": "2.2.1", - "tag": "@microsoft/gulp-core-build_v2.2.1", - "date": "Tue, 07 Feb 2017 02:33:34 GMT", - "comments": { - "patch": [ - { - "comment": "Update node-notifier to remove SNYK warning about marked package having a vulnerability (although this vulnerability should not affect us)" - } - ] - } - }, - { - "version": "2.2.0", - "tag": "@microsoft/gulp-core-build_v2.2.0", - "date": "Mon, 23 Jan 2017 20:07:59 GMT", - "comments": { - "minor": [ - { - "comment": "Remove several logging utilities from the public API and improve documentation in other places." - } - ] - } - }, - { - "version": "2.1.1", - "tag": "@microsoft/gulp-core-build_v2.1.1", - "date": "Fri, 20 Jan 2017 01:46:41 GMT", - "comments": { - "patch": [ - { - "comment": "Update documentation." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=2.1.0 <3.0.0` to `>=2.2.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/gulp-core-build_v2.1.0", - "date": "Wed, 18 Jan 2017 21:40:58 GMT", - "comments": { - "minor": [ - { - "comment": "Export the SchemaValidator" - } - ] - } - }, - { - "version": "2.0.1", - "tag": "@microsoft/gulp-core-build_v2.0.1", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "patch": [ - { - "comment": "Enable the schema for CopyTask." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `>=1.0.0 <2.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/gulp-core-build/CHANGELOG.md b/core-build/gulp-core-build/CHANGELOG.md deleted file mode 100644 index e5852f1681b..00000000000 --- a/core-build/gulp-core-build/CHANGELOG.md +++ /dev/null @@ -1,1189 +0,0 @@ -# Change Log - @microsoft/gulp-core-build - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 3.15.3 -Wed, 18 Mar 2020 15:07:47 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.15.2 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 3.15.1 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 3.15.0 -Fri, 24 Jan 2020 00:27:39 GMT - -### Minor changes - -- Add GCBTerminalProvider for use in GulpTasks. - -## 3.14.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 3.14.1 -Tue, 21 Jan 2020 21:56:14 GMT - -*Version update only* - -## 3.14.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 3.13.4 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 3.13.3 -Sat, 11 Jan 2020 05:18:23 GMT - -### Patches - -- Temporarily disable the HTML Jest reporter in the default config because of an issue with Handlebars. - -## 3.13.2 -Thu, 09 Jan 2020 06:44:13 GMT - -*Version update only* - -## 3.13.1 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 3.13.0 -Wed, 04 Dec 2019 23:17:55 GMT - -### Minor changes - -- Add ability to write Jest results as an NUnit compatible file - -## 3.12.5 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 3.12.4 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 3.12.3 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 3.12.2 -Tue, 22 Oct 2019 06:24:44 GMT - -### Patches - -- Refactor some code as part of migration from TSLint to ESLint - -## 3.12.1 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 3.12.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 3.11.3 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 3.11.2 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 3.11.1 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 3.11.0 -Mon, 05 Aug 2019 22:04:32 GMT - -### Minor changes - -- Introduce an optional build timeout. - -### Patches - -- Security updates. - -## 3.10.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2 - -## 3.9.26 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 3.9.25 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 3.9.24 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 3.9.23 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 3.9.22 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 3.9.21 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 3.9.20 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 3.9.19 -Thu, 21 Mar 2019 01:15:33 GMT - -*Version update only* - -## 3.9.18 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 3.9.17 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 3.9.16 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 3.9.15 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 3.9.14 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 3.9.13 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 3.9.12 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 3.9.11 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 3.9.10 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 3.9.9 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 3.9.8 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 3.9.7 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 3.9.6 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 3.9.5 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 3.9.4 -Wed, 30 Jan 2019 20:49:12 GMT - -*Version update only* - -## 3.9.3 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 3.9.2 -Tue, 15 Jan 2019 17:04:09 GMT - -### Patches - -- Remove karma task. - -## 3.9.1 -Thu, 10 Jan 2019 01:57:52 GMT - -*Version update only* - -## 3.9.0 -Mon, 07 Jan 2019 17:04:07 GMT - -### Minor changes - -- Upgrade Jest to version 23. - -## 3.8.57 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 3.8.56 -Thu, 13 Dec 2018 02:58:10 GMT - -### Patches - -- Remove unused jju dependency - -## 3.8.55 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 3.8.54 -Sat, 08 Dec 2018 06:35:35 GMT - -*Version update only* - -## 3.8.53 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 3.8.52 -Fri, 30 Nov 2018 23:34:58 GMT - -*Version update only* - -## 3.8.51 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 3.8.50 -Thu, 29 Nov 2018 00:35:38 GMT - -*Version update only* - -## 3.8.49 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 3.8.48 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 3.8.47 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 3.8.46 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 3.8.45 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 3.8.44 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 3.8.43 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 3.8.42 -Mon, 05 Nov 2018 17:04:24 GMT - -### Patches - -- Remove all dependencies on the "rimraf" library - -## 3.8.41 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 3.8.40 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 3.8.39 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 3.8.38 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 3.8.37 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 3.8.36 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 3.8.35 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 3.8.34 -Thu, 25 Oct 2018 08:56:03 GMT - -*Version update only* - -## 3.8.33 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 3.8.32 -Thu, 18 Oct 2018 05:30:14 GMT - -### Patches - -- Replace deprecated dependency gulp-util - -## 3.8.31 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 3.8.30 -Wed, 17 Oct 2018 21:04:49 GMT - -### Patches - -- Remove use of a deprecated Buffer API. - -## 3.8.29 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 3.8.28 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 3.8.27 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 3.8.26 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 3.8.25 -Sun, 07 Oct 2018 06:15:56 GMT - -### Patches - -- Update documentation - -## 3.8.24 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 3.8.23 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 3.8.22 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 3.8.21 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 3.8.20 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 3.8.19 -Tue, 18 Sep 2018 21:04:56 GMT - -*Version update only* - -## 3.8.18 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 3.8.17 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 3.8.16 -Mon, 03 Sep 2018 16:04:46 GMT - -*Version update only* - -## 3.8.15 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 3.8.14 -Thu, 30 Aug 2018 18:45:12 GMT - -### Patches - -- Fix an issue where the Jest task uses the global temp directory. - -## 3.8.13 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 3.8.12 -Wed, 29 Aug 2018 06:36:50 GMT - -### Patches - -- Update to use new node-core-library API - -## 3.8.11 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 3.8.10 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 3.8.9 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 3.8.8 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 3.8.7 -Tue, 07 Aug 2018 22:27:31 GMT - -### Patches - -- Add explicit dependency on jsdom to workaround Jest regression #6766 - -## 3.8.6 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 3.8.5 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 3.8.4 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 3.8.3 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 3.8.2 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 3.8.1 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 3.8.0 -Fri, 11 May 2018 22:43:14 GMT - -### Minor changes - -- Add support for modulePathIgnorePatterns for the Jest task - -### Patches - -- Upgrade to Jest 22.4.3 and remove the workaround for the symlink bug - -## 3.7.5 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 3.7.4 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 3.7.3 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 3.7.2 -Mon, 26 Mar 2018 19:12:42 GMT - -### Patches - -- Fix an issue where snapshot filenames did not follow Jest's naming convention. - -## 3.7.1 -Fri, 23 Mar 2018 00:34:53 GMT - -### Patches - -- Upgrade colors to version ~1.2.1 - -## 3.7.0 -Thu, 22 Mar 2018 18:34:13 GMT - -### Minor changes - -- Add a `libESNextFolder` option - -## 3.6.10 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 3.6.9 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 3.6.8 -Fri, 02 Mar 2018 01:13:59 GMT - -### Patches - -- Fix the "relogIssues" buld config option. - -## 3.6.7 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 3.6.6 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 3.6.5 -Wed, 21 Feb 2018 03:13:28 GMT - -*Version update only* - -## 3.6.4 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 3.6.3 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 3.6.2 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.6.1 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 3.6.0 -Fri, 26 Jan 2018 22:05:30 GMT - -### Minor changes - -- made default testMatch and maxWorkers arguments in Jest task overridable - -## 3.5.3 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 3.5.2 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 3.5.1 -Tue, 23 Jan 2018 17:05:28 GMT - -### Patches - -- Replace gulp-util.colors with colors package - -## 3.5.0 -Thu, 18 Jan 2018 03:23:46 GMT - -### Minor changes - -- Add a feature where when shouldWarningsFailBuild is true, then we will hook stderr and fail the build if anything consequential is written there - -## 3.4.4 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 3.4.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 3.4.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 3.4.1 -Thu, 11 Jan 2018 22:31:51 GMT - -### Patches - -- Fix Jest error handling - -## 3.4.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 3.3.7 -Tue, 09 Jan 2018 17:05:51 GMT - -### Patches - -- Get web-build-tools building with pnpm - -## 3.3.6 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 3.3.5 -Fri, 05 Jan 2018 20:26:45 GMT - -### Patches - -- Specify package version for chalk. It was used without version specified. - -## 3.3.4 -Fri, 05 Jan 2018 00:48:41 GMT - -### Patches - -- Update Jest to ~21.2.1 - -## 3.3.3 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 3.3.2 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 3.3.1 -Thu, 30 Nov 2017 23:59:09 GMT - -### Patches - -- reverted addition of rootDir as a parameter for jest task - -## 3.3.0 -Thu, 30 Nov 2017 23:12:21 GMT - -### Minor changes - -- Added optional args moduleDirectories and rootDir to JestTask - -## 3.2.9 -Wed, 29 Nov 2017 17:05:37 GMT - -### Patches - -- Add cache configuration to Jest task - -## 3.2.8 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 3.2.7 -Mon, 13 Nov 2017 17:04:50 GMT - -### Patches - -- Allow settings in jest.json to override Jest task's default options - -## 3.2.6 -Mon, 06 Nov 2017 17:04:18 GMT - -### Patches - -- Automatically use --colors unless --no-colors is specified. - -## 3.2.5 -Thu, 02 Nov 2017 16:05:24 GMT - -### Patches - -- lock the reference version between web build tools projects - -## 3.2.4 -Wed, 01 Nov 2017 21:06:08 GMT - -### Patches - -- Upgrade cyclic dependencies - -## 3.2.3 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 3.2.2 -Tue, 31 Oct 2017 16:04:55 GMT - -### Patches - -- Fix an issue where an exception was being thrown when displaying toasts for build failures. - -## 3.2.1 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 3.2.0 -Tue, 24 Oct 2017 18:17:12 GMT - -### Minor changes - -- Add a Jest task to support running tests on Jest - -## 3.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -### Patches - -- Updated cyclic dependencies - -## 3.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 3.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 3.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 3.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 3.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 3.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 3.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 3.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 3.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -*Version update only* - -## 3.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 3.0.4 -Thu, 07 Sep 2017 00:11:12 GMT - -### Patches - -- Add $schema field to all schemas - -## 3.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 3.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 3.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 3.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 2.10.1 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 2.10.0 -Wed, 30 Aug 2017 01:04:34 GMT - -### Minor changes - -- added CopyStaticAssetsTask - -## 2.9.6 -Thu, 24 Aug 2017 22:44:12 GMT - -### Patches - -- Update the schema validator. - -## 2.9.5 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 2.9.4 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 2.9.3 -Tue, 15 Aug 2017 19:04:14 GMT - -### Patches - -- Allow a partial config to be passed to GulpTask.mergeConfig. - -## 2.9.2 -Tue, 15 Aug 2017 01:29:31 GMT - -### Patches - -- Force a patch bump to ensure everything is published - -## 2.9.1 -Sat, 12 Aug 2017 01:03:30 GMT - -### Patches - -- Add missing orchestrator dependency. - -## 2.9.0 -Fri, 11 Aug 2017 21:44:05 GMT - -### Minor changes - -- Refactor GulpTask to support taking the name and initial task configuration through the constructor. - -## 2.8.0 -Sat, 05 Aug 2017 01:04:41 GMT - -### Minor changes - -- Add a --clean or -c command line flag which runs the clean task. - -## 2.7.3 -Mon, 31 Jul 2017 21:18:26 GMT - -### Patches - -- Upgrade @types/semver to 5.3.33 - -## 2.7.2 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools. - -## 2.7.1 -Tue, 25 Jul 2017 20:03:31 GMT - -### Patches - -- Upgrade to TypeScript 2.4 - -## 2.7.0 -Wed, 12 Jul 2017 01:04:36 GMT - -### Minor changes - -- Add the ability to suppress warnings and errors via a regular expression - -## 2.6.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 2.5.6 -Thu, 29 Jun 2017 01:05:37 GMT - -### Patches - -- Improve watch() so that it will automatically begin excecuting and it will not exit if there is a failure on the initial build - -## 2.5.5 -Wed, 21 Jun 2017 04:19:35 GMT - -### Patches - -- Add missing API Extractor release tags - -## 2.5.3 -Wed, 31 May 2017 01:08:33 GMT - -### Patches - -- Normalizing slashes in warnings suppressions to suppress warnings across windows and 'nix. - -## 2.5.2 -Wed, 24 May 2017 01:27:16 GMT - -### Patches - -- Only show overriden errors and warnings when we are in verbose mode. - -## 2.5.1 -Tue, 16 May 2017 21:17:17 GMT - -### Patches - -- Fixing an issue with how the GCB schema validator handles errors. - -## 2.5.0 -Mon, 24 Apr 2017 22:01:17 GMT - -### Minor changes - -- Adding `libES6Folder` setting to build config to optionally instruct tasks to output es6 modules. - -## 2.4.4 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 2.4.3 -Mon, 20 Mar 2017 21:52:20 GMT - -*Version update only* - -## 2.4.2 -Sat, 18 Mar 2017 01:31:49 GMT - -### Patches - -- Fixes an issue with the clean command, which causes builds to spuriously fail. - -## 2.4.1 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.4.0 -Sat, 18 Feb 2017 02:32:06 GMT - -### Minor changes - -- Add an enabled toggle to IExecutable and GulpTask. Using this toggle is now preferred to overriding the isEnabled function. - -## 2.3.1 -Thu, 09 Feb 2017 02:35:45 GMT - -### Patches - -- Don't watch process exit if user passed in the -h flag. - -## 2.3.0 -Wed, 08 Feb 2017 01:41:58 GMT - -### Minor changes - -- Remove a function which was exposing z-schema and causing issues. - -## 2.2.3 -Wed, 08 Feb 2017 01:05:47 GMT - -### Patches - -- Ensure the log function is exported - -## 2.2.2 -Wed, 08 Feb 2017 00:23:01 GMT - -### Patches - -- Fix _flatten and make serial/parallel more robust - -## 2.2.1 -Tue, 07 Feb 2017 02:33:34 GMT - -### Patches - -- Update node-notifier to remove SNYK warning about marked package having a vulnerability (although this vulnerability should not affect us) - -## 2.2.0 -Mon, 23 Jan 2017 20:07:59 GMT - -### Minor changes - -- Remove several logging utilities from the public API and improve documentation in other places. - -## 2.1.1 -Fri, 20 Jan 2017 01:46:41 GMT - -### Patches - -- Update documentation. - -## 2.1.0 -Wed, 18 Jan 2017 21:40:58 GMT - -### Minor changes - -- Export the SchemaValidator - -## 2.0.1 -Fri, 13 Jan 2017 06:46:05 GMT - -### Patches - -- Enable the schema for CopyTask. - diff --git a/core-build/gulp-core-build/LICENSE b/core-build/gulp-core-build/LICENSE deleted file mode 100644 index 0f521ba7e9e..00000000000 --- a/core-build/gulp-core-build/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/gulp-core-build - -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/core-build/gulp-core-build/README.md b/core-build/gulp-core-build/README.md deleted file mode 100644 index 55f171a2c21..00000000000 --- a/core-build/gulp-core-build/README.md +++ /dev/null @@ -1,187 +0,0 @@ -# @microsoft/gulp-core-build - -`gulp-core-build` is a set of utility functions that makes it easy to create gulp-based build rigs. Instead of having unweildy unmaintainable gulpfiles in every project, we want the build setup to be as reusable and centralized as possible. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build.svg)](https://badge.fury.io/js/%40microsoft%2Fgulp-core-build) -[![Build Status](https://travis-ci.org/Microsoft/gulp-core-build.svg?branch=master)](https://travis-ci.org/Microsoft/gulp-core-build) [![Dependencies](https://david-dm.org/Microsoft/gulp-core-build.svg)](https://david-dm.org/Microsoft/gulp-core-build) - -The gulp build system, along with its rich plugin ecosystem, is a very powerful tool for web development projects. -However project gulp build setups become difficult to manage over time, as gulpfiles grow in complexity. This project -simplifies a number of aspects of getting a build setup going for a majority of scenarios. - -Core build defines a contract for tasks to implement, such that they can share opinions about where things end up. Tasks are modular but they are designed to work well together. - -With gulp core build, your gulpfile translates into a list of task definitions, each which define what to run: - -```typescript -'use strict'; - -// Import core build and the tasks the project needs. -let build = require('gulp-core-build'); -let lint = require('gulp-core-build-typescript').tslint; -let typescript = require('gulp-core-build-typescript').typescript; -let sass = require('gulp-core-build-sass').default; -let webpack = require('gulp-core-build-webpack').default; -let serve = require('gulp-core-build-serve').default; - -// Define gulp tasks. -let buildTasks = build.task('build', build.parallel(lint, typescript, sass)); -let testTasks = build.task('test', build.serial(buildTasks, build.jest)); -let bundleTasks = build.task('bundle', build.serial(buildTasks, webpack)); -let serveTasks = build.task('serve', build.serial(bundleTasks, serve)); -let defaultTasks = build.task('default', testTasks); - -// Initialize! -build.initialize(require('gulp')); -``` - -# Usage - -Within your project, install gulp, gulp-core-build, and the tasks you need: - -``` -npm install --save-dev gulp gulp-core-build -``` - -Then install the tasks you need: - -``` -npm install --save-dev gulp-core-build-typescript gulp-core-build-webpack gulp-core-build-serve - -``` - -Create a gulpfile.js that sets up the tasks in the way you want them to run: - -```javascript -'use strict'; - -// Import core build. -let build = require('gulp-core-build'); - -// Import the tasks. -let lint = require('gulp-core-build-typescript').tslint; -let typescript = require('gulp-core-build-typescript').typescript; -let sass = require('gulp-core-build-sass').default; -let webpack = require('gulp-core-build-webpack').default; -let serve = require('gulp-core-build-serve').default; - -// Shorthand for defining custom subtasks -// The proper method for this is to introduce a new package which exports a class that extends GulpTask -// However, this shorthand allows an easy way to introduce one-off subtasks directly in the gulpfile -let helloWorldSubtask = build.subTask('do-hello-world-subtask', function(gulp, buildOptions, done) { - this.log('Hello, World!'); // use functions from GulpTask -}); - -// Define gulp tasks. -let buildTasks = build.task('build', build.parallel(helloWorldSubtask, lint, typescript, sass)); -let testTasks = build.task('test', build.serial(buildTasks, build.jest)); -let bundleTasks = build.task('bundle', build.serial(buildTasks, webpack)); -let serveTasks = build.task('serve', build.serial(bundleTasks, serve)); -let helloWorldTasks = build.task('hello-world', helloWorldSubtask); -let defaultTasks = build.task('default', testTasks); - -// Tell the build to set up gulp tasks with the given gulp instance. -build.initialize(require('gulp')); -``` - -Once this is set up, you should be able to execute the gulp tasks and they should run in the order you defined. - -# Available tasks - -| Task name | Description | -| --------- | ----------- | -| [gulp-core-build-typescript](https://www.npmjs.com/package/@microsoft/gulp-core-build-typescript) | Builds and lints typescript. | -| [gulp-core-build-sass](https://www.npmjs.com/package/@microsoft/gulp-core-build) | Compiles sass into css, into js modules, that are theme friendly. | -| [gulp-core-build-webpack](https://www.npmjs.com/package/@microsoft/gulp-core-build-webpack) | Runs webpack given a config, and outputs libraries plus the stats and logging. | -| [gulp-core-build-serve](https://www.npmjs.com/package/@microsoft/gulp-core-build-serve) | Sets up a server and live reload for a quick dev loop. | -| [gulp-core-build-mocha](https://www.npmjs.com/package/@microsoft/gulp-core-build-mocha) | Runs unit tests in a NodeJS environment with [Mocha](https://www.npmjs.com/package/mocha) | - -# API - -## task(name, task) - -Defines a named task to be registered with gulp as a primary gulp task, which will run the provided task when execution. - -## parallel(tasks) - -Runs a given list of tasks in parallel execution order. - -## serial(tasks) - -Runs a given list of tasks in serial execution order. - -## subtask(name: string, fn: ICustomGulpTask) - -Creates a subtask (which is not registered directly with gulp, use `task()` for that) which can be -used with `parallel()` and `serial()`. The `this` variable in the callback function will be an instance of a `GulpTask`. - -`fn` should be a function of type `ICustomGulpTask` - -```typescript -/** - * The callback interface for a custom task definition. - * The task should either return a Promise, a stream, or call the - * callback function (passing in an object value if there was an error). - */ -export interface ICustomGulpTask { - (gulp: gulp.Gulp | GulpProxy, buildConfig: IBuildConfig, done: (failure?: Object) => void): - Promise | NodeJS.ReadWriteStream | void; -} -``` - -## initialize(gulpInstance, [buildOtions]) - -Registers the gulp tasks. - -The options are broken down into task-specific sections, and all are optional, so only provide the ones -that require deviating from defaults: - -```typescript -build.initializeTasks( - require('gulp'), - { - build: { /* build options */ }, - bundle: { /* bundle options */ }, - test: { /* test options */ }, - serve: { /* serve options */ }, - clean: { /* clean options */ } - }); -``` - -## addSuppression(suppression: string | RegExp) - -Suppresses a warning or an error message. It will no longer be displayed in the build logs, nor will the warning or error cause the build to fail. - -```typescript -// Suppresses this exact warning -build.addSuppression("Warning - tslint /foo/bar/test.tsx no-any") - -// Suppresses anything with "tslint" -build.addSuppression(/tslint/) -``` - -# Building gulp-core-build -1. ```npm install --force``` -2. ```gulp``` - -# Defining a custom task - -The `subtask()` function is used to define a custom task. For example, -you could create the following subtask, which is registered to the command -`gulp hello-world`: - -```javascript -let helloWorldSubtask = build.subTask('do-hello-world-subtask', function(gulp, buildOptions, done) { - this.log('Hello, World!'); // use functions from GulpTask -}); - -// Register the task with gulp command line -let helloWorldTask = build.task('hello-world', helloWorldSubtask); -``` - -Note that the command `gulp do-hello-world-subtask` would error. - - -# License - -MIT diff --git a/core-build/gulp-core-build/config/api-extractor.json b/core-build/gulp-core-build/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/gulp-core-build/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/gulp-core-build/gulpfile.js b/core-build/gulp-core-build/gulpfile.js deleted file mode 100644 index 340fd4df3a4..00000000000 --- a/core-build/gulp-core-build/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); \ No newline at end of file diff --git a/core-build/gulp-core-build/jsconfig.json b/core-build/gulp-core-build/jsconfig.json deleted file mode 100644 index c25b2cc60e6..00000000000 --- a/core-build/gulp-core-build/jsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "target": "ES6", - "module": "commonjs" - } -} diff --git a/core-build/gulp-core-build/package.json b/core-build/gulp-core-build/package.json deleted file mode 100644 index c479809f60a..00000000000 --- a/core-build/gulp-core-build/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@microsoft/gulp-core-build", - "version": "3.15.3", - "description": "Core gulp build tasks for building typescript, html, less, etc.", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/gulp-core-build" - }, - "scripts": { - "build": "gulp --clean" - }, - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@types/chalk": "0.4.31", - "@types/gulp": "4.0.6", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "@types/node-notifier": "0.0.28", - "@types/orchestrator": "0.0.30", - "@types/semver": "5.3.33", - "@types/through2": "2.0.32", - "@types/vinyl": "2.0.3", - "@types/yargs": "0.0.34", - "colors": "~1.2.1", - "del": "^2.2.2", - "end-of-stream": "~1.1.0", - "glob-escape": "~0.0.1", - "globby": "~5.0.0", - "glob": "~7.0.5", - "gulp": "~4.0.2", - "gulp-flatten": "~0.2.0", - "gulp-if": "^2.0.1", - "jest": "~23.6.0", - "jest-cli": "~22.4.3", - "jest-environment-jsdom": "~22.4.3", - "jest-nunit-reporter": "~1.3.1", - "jest-resolve": "~22.4.3", - "jsdom": "~11.11.0", - "lodash.merge": "~4.6.2", - "merge2": "~1.0.2", - "node-notifier": "~5.0.2", - "object-assign": "~4.1.0", - "orchestrator": "~0.3.8", - "pretty-hrtime": "~1.0.2", - "semver": "~5.3.0", - "through2": "~2.0.1", - "vinyl": "~2.2.0", - "xml": "~1.0.1", - "yargs": "~4.6.0", - "z-schema": "~3.18.3" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/chai": "3.4.34", - "@types/glob": "7.1.1", - "@types/mocha": "5.2.5", - "@types/z-schema": "3.16.31", - "chai": "~3.5.0" - } -} diff --git a/core-build/gulp-core-build/src/GulpProxy.ts b/core-build/gulp-core-build/src/GulpProxy.ts deleted file mode 100644 index d813d24a36e..00000000000 --- a/core-build/gulp-core-build/src/GulpProxy.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import gulp = require('gulp'); -import Orchestrator = require('orchestrator'); - -/** - * A helper utility for gulp which can be extended to provide additional features to gulp vinyl streams - */ -export class GulpProxy extends Orchestrator { - public src: gulp.SrcMethod; - public dest: gulp.DestMethod; - public watch: gulp.WatchMethod; - - public constructor(gulpInstance: gulp.Gulp) { - super(); - this.src = gulpInstance.src; - this.dest = gulpInstance.dest; - this.watch = gulpInstance.watch; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public task(): any { - throw new Error( - 'You should not define gulp tasks directly, but instead subclass the GulpTask or call subTask(), and register it to gulp-core-build.' - ); - } -} diff --git a/core-build/gulp-core-build/src/IBuildConfig.ts b/core-build/gulp-core-build/src/IBuildConfig.ts deleted file mode 100644 index 14bb3790e37..00000000000 --- a/core-build/gulp-core-build/src/IBuildConfig.ts +++ /dev/null @@ -1,144 +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 gulp from 'gulp'; -import { GulpProxy } from './GulpProxy'; -import { IExecutable } from './IExecutable'; - -/** - * @public - */ -export interface IBuildConfig { - /** - * The maximum amount of time the build can run before being terminated. - * Specified in milliseconds. By default, there is no timeout. - * - * If set to zero (0), the build will never time out. - */ - maxBuildTimeMs: number; - - /** - * Proxy gulp instance. - */ - gulp: GulpProxy | gulp.Gulp; - - /** - * Array of all unique tasks. - */ - uniqueTasks?: IExecutable[]; - - /** - * Full physical path to the root path directory. - */ - rootPath: string; - - /** - * Package output folder in which publishable output should be dropped. - * Defaults to package.json directories/packagePath value. - */ - packageFolder: string; - - /** - * Source folder name where source is included. - */ - srcFolder: string; - - /** - * Unbundled commonjs modules folder, which will be referenced by other node projects. - */ - libFolder: string; - - /** - * Unbundled amd modules folder, which can be optionally set to cause build tasks to - * output AMD modules if required for legacy reasons. - */ - libAMDFolder?: string; - - /** - * Unbundled es6 modules folder, which can be optionally set to cause build tasks to output es6 modules. - */ - libES6Folder?: string; - - /** - * Unbundled esnext modules folder, which can be optionally set to cause build tasks to output esnext modules. - */ - libESNextFolder?: string; - - /** - * Dist folder, which includes all bundled resources which would be copied to a CDN for the project. - */ - distFolder: string; - - /** - * Temp folder for storing temporary files. - */ - tempFolder: string; - - /** - * Re-log known issues after the build is complete. - */ - relogIssues?: boolean; - - /** - * Show toast on build failures and recoveries. - */ - showToast?: boolean; - - /** - * Path to icon shown in toast on a successful build recovery. - */ - buildSuccessIconPath?: string; - - /** - * Path to icon shown in toast on a build error. - */ - buildErrorIconPath?: string; - - /** - * Use verbose logging. - */ - verbose: boolean; - - /** - * Build a full production build. - */ - production: boolean; - - /** - * Should warnings be written to STDERR and cause build to return non-zero exit code - */ - shouldWarningsFailBuild: boolean; - - /** - * Arguments passed in. - */ - args: { [name: string]: string | boolean }; - - /** - * Arbitrary property bag for a task to store environment values in. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - properties?: { [key: string]: any }; - - /** - * Optional callback to be executed when a task starts. - */ - onTaskStart?: (taskName: string) => void; - - /** - * Optional callback to be executed when a task ends. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onTaskEnd?: (taskName: string, duration: number[], error?: any) => void; - - /** - * Flag used to indicate if the build is redundant and should be exited prematurely. - */ - isRedundantBuild?: boolean; - - /** - * Flag to indicate whether Jest is enabled. - * If Jest is enabled, mocha and Karma are disabled. - */ - jestEnabled?: boolean; -} diff --git a/core-build/gulp-core-build/src/IExecutable.ts b/core-build/gulp-core-build/src/IExecutable.ts deleted file mode 100644 index 7af4533a16f..00000000000 --- a/core-build/gulp-core-build/src/IExecutable.ts +++ /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. - -import { IBuildConfig } from './IBuildConfig'; - -/** - * @public - */ -export interface IExecutable { - /** - * The maximum amount of time the build can run before being terminated. - * Specified in milliseconds. By default, there is no timeout. - * - * If set to zero (0), the build will never time out. - * - * This option overrides the maxBuildTime property on the global build config. - */ - maxBuildTimeMs?: number; - - /** - * Helper function which is called one time when the task is registered - */ - onRegister?: () => void; - - /** - * Execution method. - */ - execute: (config: IBuildConfig) => Promise; - - /** - * Optional name to give the task. If no name is provided, the "Running subtask" logging will be silent. - */ - name?: string; - - /** - * Optional callback to indicate if the task is enabled or not. - */ - isEnabled?: (buildConfig: IBuildConfig) => boolean; - - /** - * Optional method to indicate directory matches to clean up when the clean task is run. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getCleanMatch?: (config: IBuildConfig, taskConfig?: any) => string[]; -} diff --git a/core-build/gulp-core-build/src/State.ts b/core-build/gulp-core-build/src/State.ts deleted file mode 100644 index 5227976501e..00000000000 --- a/core-build/gulp-core-build/src/State.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 { argv as clArgs } from 'yargs'; -import * as path from 'path'; -import { FileConstants } from '@rushstack/node-core-library'; - -export const root: string = process.cwd(); -export const args: { [flat: string]: boolean | string } = clArgs; - -export interface IPackageJSON { - name?: string; - version?: string; - directories: { - packagePath: string | undefined; - } | undefined; -} - -// There appears to be a TypeScript compiler bug that isn't allowing us to say -// IPackageJSON | undefined here, so let's create a stub package.json here instead. -// @todo: remove this when the compiler is fixed. -let packageJson: IPackageJSON = { - directories: { - packagePath: undefined - } -}; -try { - packageJson = require(path.join(root, FileConstants.PackageJson)); -} catch (e) { - // Package.json probably doesn't exit -} - -export const builtPackage: IPackageJSON = packageJson; -// eslint-disable-next-line @typescript-eslint/no-var-requires -export const coreBuildPackage: IPackageJSON = require('../package.json'); -export const nodeVersion: string = process.version; diff --git a/core-build/gulp-core-build/src/config.ts b/core-build/gulp-core-build/src/config.ts deleted file mode 100644 index 37c98e2260a..00000000000 --- a/core-build/gulp-core-build/src/config.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { args } from './State'; -import { getConfig } from './index'; - -const ENVIRONMENT_VARIABLE_PREFIX: string = 'GCB_'; - -export function getConfigValue(name: string, defaultValue?: string | boolean): string | boolean { - - // Try to get config value from environment variable. - const envVariable: string = ENVIRONMENT_VARIABLE_PREFIX + name.toUpperCase(); - const envValue: string | undefined = process.env[envVariable]; - const argsValue: string | boolean = args[name.toLowerCase()]; - - // getConfig can be undefined during the first few calls to this function because the build config is initialized - // before the getConfig function is defined. In those cases, a defaultValue is provided. - const configValue: string | boolean = ((getConfig ? getConfig() : {}) || {})[name]; - - return _firstDefinedValue(argsValue, envValue, defaultValue, configValue); -} - -export function getFlagValue(name: string, defaultValue?: boolean): boolean { - const configValue: string | boolean = getConfigValue(name, defaultValue); - - return configValue === 'true' || configValue === true; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function _firstDefinedValue(...values: (string | boolean | undefined)[]): any { - for (const value of values) { - if (value !== undefined) { - return value; - } - } - - return undefined; -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/fail.png b/core-build/gulp-core-build/src/fail.png deleted file mode 100644 index 0b3f5e3a962..00000000000 Binary files a/core-build/gulp-core-build/src/fail.png and /dev/null differ diff --git a/core-build/gulp-core-build/src/index.ts b/core-build/gulp-core-build/src/index.ts deleted file mode 100644 index 416a6009d12..00000000000 --- a/core-build/gulp-core-build/src/index.ts +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -if (process.argv.indexOf('--no-color') === -1) { - process.argv.push('--color'); -} - -import * as path from 'path'; - -import { GulpTask } from './tasks/GulpTask'; -import { GulpProxy } from './GulpProxy'; -import { IExecutable } from './IExecutable'; -import { IBuildConfig } from './IBuildConfig'; -import { CleanTask } from './tasks/CleanTask'; -import { CleanFlagTask } from './tasks/CleanFlagTask'; -import { CopyStaticAssetsTask } from './tasks/copyStaticAssets/CopyStaticAssetsTask'; -import { args, builtPackage } from './State'; -export { IExecutable } from './IExecutable'; -import { log, error as logError } from './logging'; -import { initialize as initializeLogging, markTaskCreationTime, generateGulpError, setWatchMode } from './logging'; -import { getFlagValue } from './config'; -import * as Gulp from 'gulp'; -import * as notifier from 'node-notifier'; -import { JestTask, _isJestEnabled } from './tasks/JestTask'; - -export * from './IBuildConfig'; -export { - addSuppression, - coverageData, - functionalTestRun, - getErrors, - getWarnings, - TestResultState, - warn, - verbose, - error, - fileError, - fileLog, - fileWarning, - reset, - log, - logSummary -} from './logging'; -export { GCBTerminalProvider } from './utilities/GCBTerminalProvider'; -export * from './tasks/CopyTask'; -export * from './tasks/GenerateShrinkwrapTask'; -export * from './tasks/GulpTask'; -export * from './tasks/CleanTask'; -export * from './tasks/CleanFlagTask'; -export * from './tasks/ValidateShrinkwrapTask'; -export * from './tasks/copyStaticAssets/CopyStaticAssetsTask'; -export * from './tasks/JestTask'; - -const _taskMap: { [key: string]: IExecutable } = {}; -const _uniqueTasks: IExecutable[] = []; - -const packageFolder: string = (builtPackage.directories && builtPackage.directories.packagePath) - ? builtPackage.directories.packagePath - : ''; - -let _buildConfig: IBuildConfig = { - maxBuildTimeMs: 0, // Defaults to no timeout - // gulp and rootPath are set to undefined here because they'll be defined in the initialize function below, - // but we don't want their types to be nullable because a task that uses StrictNullChecks should expect them - // to be defined without checking their values. - gulp: undefined as any, // eslint-disable-line @typescript-eslint/no-explicit-any - rootPath: undefined as any, // eslint-disable-line @typescript-eslint/no-explicit-any - packageFolder, - srcFolder: 'src', - distFolder: path.join(packageFolder, 'dist'), - libAMDFolder: undefined, - libESNextFolder: undefined, - libFolder: path.join(packageFolder, 'lib'), - tempFolder: 'temp', - properties: {}, - relogIssues: getFlagValue('relogIssues', true), - showToast: getFlagValue('showToast', true), - buildSuccessIconPath: path.resolve(__dirname, 'pass.png'), - buildErrorIconPath: path.resolve(__dirname, 'fail.png'), - verbose: getFlagValue('verbose', false), - production: getFlagValue('production', false), - args: args, - shouldWarningsFailBuild: false -}; - -/** - * Merges the given build config settings into existing settings. - * - * @param config - The build config settings. - * @public - */ -export function setConfig(config: Partial): void { - // eslint-disable-next-line - const objectAssign = require('object-assign'); - - _buildConfig = objectAssign({}, _buildConfig, config); -} - -/** - * Merges the given build config settings into existing settings. - * - * @param config - The build config settings. - * @public - */ -export function mergeConfig(config: Partial): void { - // eslint-disable-next-line - const merge = require('lodash.merge'); - - _buildConfig = merge({}, _buildConfig, config); -} - -/** - * Replaces the build config. - * - * @param config - The build config settings. - * @public - */ -export function replaceConfig(config: IBuildConfig): void { - _buildConfig = config; -} - -/** - * Gets the current config. - * @returns the current build configuration - * @public - */ -export function getConfig(): IBuildConfig { - return _buildConfig; -} - -/** @public */ -export const cleanFlag: IExecutable = new CleanFlagTask(); - -/** - * Registers an IExecutable to gulp so that it can be called from the command line - * @param taskName - the name of the task, can be called from the command line (e.g. "gulp ") - * @param taskExecutable - the executable to execute when the task is invoked - * @returns the task parameter - * @public - */ -export function task(taskName: string, taskExecutable: IExecutable): IExecutable { - taskExecutable = serial(cleanFlag, taskExecutable); - - _taskMap[taskName] = taskExecutable; - - _trackTask(taskExecutable); - - return taskExecutable; -} - -/** - * The callback interface for a custom task definition. - * The task should either return a Promise, a stream, or call the - * callback function (passing in an object value if there was an error). - * @public - */ -export interface ICustomGulpTask { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (gulp: typeof Gulp | GulpProxy, buildConfig: IBuildConfig, done?: (failure?: any) => void): - Promise | NodeJS.ReadWriteStream | void; -} - -/** @public */ -class CustomTask extends GulpTask { - private _fn: ICustomGulpTask; - public constructor(name: string, fn: ICustomGulpTask) { - super(name); - this._fn = fn.bind(this); - } - - public executeTask(gulp: typeof Gulp | GulpProxy, completeCallback?: (error?: string | Error) => void): - Promise | NodeJS.ReadWriteStream | void { - return this._fn(gulp, getConfig(), completeCallback); - } -} - -/** - * Creates a new subtask from a function callback. Useful as a shorthand way - * of defining tasks directly in a gulpfile. - * - * @param taskName - the name of the task, appearing in build logs - * @param fn - the callback function to execute when this task runs - * @returns an IExecutable which can be registered to the command line with task() - * @public - */ -export function subTask(taskName: string, fn: ICustomGulpTask): IExecutable { - const customTask: CustomTask = new CustomTask(taskName, fn); - return customTask; -} - -/** - * Defines a gulp watch and maps it to a given IExecutable. - * - * @param watchMatch - the list of files patterns to watch - * @param taskExecutable - the task to execute when a file changes - * @returns IExecutable - * @public - */ -export function watch(watchMatch: string | string[], taskExecutable: IExecutable): IExecutable { - _trackTask(taskExecutable); - - let isWatchRunning: boolean = false; - let shouldRerunWatch: boolean = false; - let lastError: Error | undefined = undefined; - - const successMessage: string = 'Build succeeded'; - const failureMessage: string = 'Build failed'; - - return { - execute: (buildConfig: IBuildConfig): Promise => { - return new Promise(() => { - - function _runWatch(): Promise { - if (isWatchRunning) { - shouldRerunWatch = true; - return Promise.resolve(); - } else { - isWatchRunning = true; - - return _executeTask(taskExecutable, buildConfig) - .then(() => { - if (lastError) { - lastError = undefined; - - if (buildConfig.showToast) { - notifier.notify({ - title: successMessage, - message: (builtPackage ? builtPackage.name : ''), - icon: buildConfig.buildSuccessIconPath - }); - } else { - log(successMessage); - } - } - return _finalizeWatch(); - }) - .catch((error: Error) => { - if (!lastError || lastError !== error) { - lastError = error; - - if (buildConfig.showToast) { - notifier.notify({ - title: failureMessage, - message: error.toString(), - icon: buildConfig.buildErrorIconPath - }); - } else { - log(failureMessage); - } - } - - return _finalizeWatch(); - }); - } - } - - function _finalizeWatch(): Promise { - isWatchRunning = false; - - if (shouldRerunWatch) { - shouldRerunWatch = false; - return _runWatch(); - } - return Promise.resolve(); - } - - setWatchMode(); - buildConfig.gulp.watch(watchMatch, _runWatch); - - _runWatch().catch(console.error); - }); - } - }; -} - -/** - * Takes in IExecutables as arguments and returns an IExecutable that will execute them in serial. - * @public - */ -export function serial(...tasks: (IExecutable[] | IExecutable)[]): IExecutable { - const flatTasks: IExecutable[] = _flatten(tasks).filter(taskExecutable => { - // eslint-disable-next-line @rushstack/no-null - return taskExecutable !== null && taskExecutable !== undefined; - }); - - for (const flatTask of flatTasks) { - _trackTask(flatTask); - } - - return { - execute: (buildConfig: IBuildConfig): Promise => { - let output: Promise = Promise.resolve(); - - for (const taskExecutable of flatTasks) { - output = output.then(() => _executeTask(taskExecutable, buildConfig)); - } - - return output; - } - }; -} - -/** - * Takes in IExecutables as arguments and returns an IExecutable that will execute them in parallel. - * @public - */ -export function parallel(...tasks: (IExecutable[] | IExecutable)[]): IExecutable { - const flatTasks: IExecutable[] = _flatten(tasks).filter(taskExecutable => { - // eslint-disable-next-line @rushstack/no-null - return taskExecutable !== null && taskExecutable !== undefined; - }); - - for (const flatTask of flatTasks) { - _trackTask(flatTask); - } - - return { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - execute: (buildConfig: IBuildConfig): Promise => { - return new Promise((resolve, reject) => { - const promises: Promise[] = []; - for (const taskExecutable of flatTasks) { - promises.push(_executeTask(taskExecutable, buildConfig)); - } - - // Use promise all to make sure errors are propagated correctly - Promise.all(promises).then(resolve, reject); - }); - } - }; -} - -/** - * Initializes the gulp tasks. - * @public - */ -export function initialize(gulp: typeof Gulp): void { - _buildConfig.rootPath = process.cwd(); - _buildConfig.gulp = new GulpProxy(gulp); - _buildConfig.uniqueTasks = _uniqueTasks; - _buildConfig.jestEnabled = _isJestEnabled(_buildConfig.rootPath); - - _handleCommandLineArguments(); - - for (const uniqueTask of _buildConfig.uniqueTasks) { - if (uniqueTask.onRegister) { - uniqueTask.onRegister(); - } - } - - initializeLogging(gulp, getConfig(), undefined, undefined); - - Object.keys(_taskMap).forEach(taskName => _registerTask(gulp, taskName, _taskMap[taskName])); - - markTaskCreationTime(); -} - -/** - * Registers a given gulp task given a name and an IExecutable. - */ -function _registerTask(gulp: typeof Gulp, taskName: string, taskExecutable: IExecutable): void { - gulp.task(taskName, (cb) => { - const maxBuildTimeMs: number = taskExecutable.maxBuildTimeMs === undefined - ? _buildConfig.maxBuildTimeMs - : taskExecutable.maxBuildTimeMs; - const timer: NodeJS.Timer | undefined = maxBuildTimeMs === 0 - ? undefined - : setTimeout( - () => { - logError( - `Build ran for ${maxBuildTimeMs} milliseconds without completing. Cancelling build with error.` - ); - cb(new Error('Timeout')); - }, - maxBuildTimeMs - ); - _executeTask(taskExecutable, _buildConfig).then( - () => { - if (timer) { - clearTimeout(timer); - } - - cb(); - }, - (error: Error) => { - if (timer) { - clearTimeout(timer); - } - - cb(generateGulpError(error)); - } - ); - }); -} - -/** - * Executes a given IExecutable. - */ -function _executeTask(taskExecutable: IExecutable, buildConfig: IBuildConfig): Promise { - // Try to fallback to the default task if provided. - if (taskExecutable && !taskExecutable.execute) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if ((taskExecutable as any).default) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - taskExecutable = (taskExecutable as any).default; - } - } - - // If the task is missing, throw a meaningful error. - if (!taskExecutable || !taskExecutable.execute) { - return Promise.reject(new Error(`A task was scheduled, but the task was null. This probably means the task wasn't imported correctly.`)); - } - - if (taskExecutable.isEnabled === undefined || taskExecutable.isEnabled(buildConfig)) { - const startTime: [number, number] = process.hrtime(); - - if (buildConfig.onTaskStart && taskExecutable.name) { - buildConfig.onTaskStart(taskExecutable.name); - } - - const taskPromise: Promise = taskExecutable.execute(buildConfig) - .then(() => { - if (buildConfig.onTaskEnd && taskExecutable.name) { - buildConfig.onTaskEnd(taskExecutable.name, process.hrtime(startTime)); - } - }, - (error: Error) => { - if (buildConfig.onTaskEnd && taskExecutable.name) { - buildConfig.onTaskEnd(taskExecutable.name, process.hrtime(startTime), error); - } - - return Promise.reject(error); - }); - - return taskPromise; - } - - // No-op otherwise. - return Promise.resolve(); -} - -function _trackTask(taskExecutable: IExecutable): void { - if (_uniqueTasks.indexOf(taskExecutable) < 0) { - _uniqueTasks.push(taskExecutable); - } -} - -/** - * Flattens a set of arrays into a single array. - */ -function _flatten(oArr: (T | T[])[]): T[] { - const output: T[] = []; - - function traverse(arr: (T | T[])[]): void { - for (let i: number = 0; i < arr.length; ++i) { - if (Array.isArray(arr[i])) { - traverse(arr[i] as T[]); - } else { - output.push(arr[i] as T); - } - } - } - - traverse(oArr); - - return output; -} - -function _handleCommandLineArguments(): void { - _handleTasksListArguments(); -} - -function _handleTasksListArguments(): void { - /* eslint-disable dot-notation */ - if (args['tasks'] || args['tasks-simple'] || args['T']) { - global['dontWatchExit'] = true; - } - if (args['h']) { - // we are showing a help command prompt via yargs or ts-command-line - global['dontWatchExit'] = true; - } - /* eslint-enable dot-notation */ -} - -/** @public */ -export const clean: IExecutable = new CleanTask(); - -/** @public */ -export const copyStaticAssets: CopyStaticAssetsTask = new CopyStaticAssetsTask(); - -/** @public */ -export const jest: JestTask = new JestTask(); - -// Register default clean task. -task('clean', clean); diff --git a/core-build/gulp-core-build/src/logging.ts b/core-build/gulp-core-build/src/logging.ts deleted file mode 100644 index d592fe57a1e..00000000000 --- a/core-build/gulp-core-build/src/logging.ts +++ /dev/null @@ -1,888 +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 colors from 'colors'; -import * as Gulp from 'gulp'; -import * as path from 'path'; -// eslint-disable-next-line -const prettyTime = require('pretty-hrtime'); - -import { IBuildConfig } from './IBuildConfig'; -import * as state from './State'; -import { getFlagValue } from './config'; -import { getConfig } from './index'; - -const WROTE_ERROR_KEY: string = '__gulpCoreBuildWroteError'; - -interface ILocalCache { - warnings: string[]; - errors: string[]; - taskRun: number; - subTasksRun: number; - testsRun: number; - testsPassed: number; - testsFailed: number; - testsFlakyFailed: number; - testsSkipped: number; - taskErrors: number; - coverageResults: number; - coveragePass: number; - coverageTotal: number; - totalTaskHrTime: [number, number] | undefined; - start?: [number, number]; - taskCreationTime?: [number, number]; - totalTaskSrc: number; - wroteSummary: boolean; - writingSummary: boolean; - writeSummaryCallbacks: (() => void)[]; - watchMode?: boolean; - fromRunGulp?: boolean; - exitCode: number; - writeSummaryLogs: string[]; - gulp: typeof Gulp | undefined; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulpErrorCallback: undefined | ((err: any) => void); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulpStopCallback: undefined | ((err: any) => void); - errorAndWarningSuppressions: (string | RegExp)[]; - shouldLogWarningsDuringSummary: boolean; - shouldLogErrorsDuringSummary: boolean; -} - -let wiredUpErrorHandling: boolean = false; -let duringFastExit: boolean = false; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const globalInstance: any = global as any; - -const localCache: ILocalCache = globalInstance.__loggingCache = globalInstance.__loggingCache || { - warnings: [], - errors: [], - testsRun: 0, - subTasksRun: 0, - testsPassed: 0, - testsFailed: 0, - testsFlakyFailed: 0, - testsSkipped: 0, - taskRun: 0, - taskErrors: 0, - coverageResults: 0, - coveragePass: 0, - coverageTotal: 0, - totalTaskHrTime: undefined, - totalTaskSrc: 0, - wroteSummary: false, - writingSummary: false, - writeSummaryCallbacks: [], - exitCode: 0, - writeSummaryLogs: [], - errorAndWarningSuppressions: [], - gulp: undefined, - gulpErrorCallback: undefined, - gulpStopCallback: undefined, - shouldLogErrorsDuringSummary: false, - shouldLogWarningsDuringSummary: false -}; - -if (!localCache.start) { - localCache.start = process.hrtime(); -} - -function isVerbose(): boolean { - return getFlagValue('verbose'); -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function formatError(e: any): string | undefined { - - if (!e.err) { - if (isVerbose()) { - return e.message + '\r\n' + e.stack; - } else { - return e.message; - } - } - - // PluginError - if (typeof e.err.showStack === 'boolean') { - return e.err.toString() + (e.err.stack && isVerbose() ? '\r\n' + e.err.stack : ''); - } - - // normal error - if (e.err.stack) { - if (isVerbose()) { - return e.err.stack; - } else { - return e.err.message; - } - } - - // unknown (string, number, etc.) - if (typeof (Error) === 'undefined') { - if (isVerbose()) { - return e.message + '\r\n' + e.stack; - } else { - return e.message; - } - } else { - let output: string = String(e.err); - - try { - output = JSON.stringify(e.err); - } catch (e) { - // Do nothing - } - - if (isVerbose()) { - return new Error(output).stack; - } else { - return new Error(output).message; - } - } -} - -function afterStreamFlushed(streamName: string, callback: () => void): void { - if (duringFastExit) { - callback(); - } else { - const stream: NodeJS.WritableStream = process[streamName]; - const outputWritten: boolean = stream.write(''); - if (outputWritten) { - setTimeout(() => { - callback(); - }, 250); - } else { - stream.once('drain', () => { - setTimeout(() => { - callback(); - }, 250); - }); - } - } -} - -function afterStreamsFlushed(callback: () => void): void { - afterStreamFlushed('stdout', () => { - afterStreamFlushed('stderr', () => { - callback(); - }); - }); -} - -function writeSummary(callback: () => void): void { - - localCache.writeSummaryCallbacks.push(callback); - - if (!localCache.writingSummary) { - localCache.writingSummary = true; - - // flush the log - afterStreamsFlushed(() => { - const shouldRelogIssues: boolean = getFlagValue('relogIssues'); - log(colors.magenta('==================[ Finished ]==================')); - - const warnings: string[] = getWarnings(); - if (shouldRelogIssues) { - for (let x: number = 0; x < warnings.length; x++) { - console.error(colors.yellow(warnings[x])); - } - } - - if (shouldRelogIssues && (localCache.taskErrors > 0 || getErrors().length)) { - const errors: string[] = getErrors(); - for (let x: number = 0; x < errors.length; x++) { - console.error(colors.red(errors[x])); - } - } - - afterStreamsFlushed(() => { - for (const writeSummaryString of localCache.writeSummaryLogs) { - log(writeSummaryString); - } - const totalDuration: [number, number] = process.hrtime(getStart()); - - const name: string = state.builtPackage.name || 'with unknown name'; - const version: string = state.builtPackage.version || 'unknown'; - log(`Project ${name} version:`, colors.yellow(version)); - log('Build tools version:', colors.yellow(state.coreBuildPackage.version || '')); - log('Node version:', colors.yellow(process.version)); - // log('Create tasks duration:', colors.yellow(prettyTime(localCache.taskCreationTime))); - // log('Read src tasks duration:', colors.yellow(prettyTime(localCache.totalTaskHrTime))); - log('Total duration:', colors.yellow(prettyTime(totalDuration))); - // log(`Tasks run: ${colors.yellow(localCache.taskRun + '')} ` + - // `Subtasks run: ${colors.yellow(localCache.subTasksRun + '')}`); - - if (localCache.testsRun > 0) { - log('Tests results -', - 'Passed:', colors.green(localCache.testsPassed + ''), - 'Failed:', colors.red(localCache.testsFailed + ''), - // 'Flaky:', colors.yellow(localCache.testsFlakyFailed + ''), - 'Skipped:', colors.yellow(localCache.testsSkipped + '')); - } - - if (localCache.coverageResults > 0) { - log( - 'Coverage results -', - 'Passed:', colors.green(localCache.coveragePass + ''), - 'Failed:', colors.red((localCache.coverageResults - localCache.coveragePass) + ''), - 'Avg. Cov.:', colors.yellow(Math.floor(localCache.coverageTotal / localCache.coverageResults) + '%')); - } - - if (getWarnings().length) { - log('Task warnings:', colors.yellow(getWarnings().length.toString())); - } - - let totalErrors: number = 0; - - if (localCache.taskErrors > 0 || getErrors().length) { - totalErrors = (localCache.taskErrors + getErrors().length); - log('Task errors:', colors.red(totalErrors + '')); - } - - localCache.wroteSummary = true; - const callbacks: (() => void)[] = localCache.writeSummaryCallbacks; - localCache.writeSummaryCallbacks = []; - for (const writeSummaryCallback of callbacks) { - writeSummaryCallback(); - } - }); - }); - } else if (localCache.wroteSummary) { - const callbacks: (() => void)[] = localCache.writeSummaryCallbacks; - localCache.writeSummaryCallbacks = []; - for (const writeSummaryCallback of callbacks) { - writeSummaryCallback(); - } - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function _writeTaskError(e: any): void { - if (!e || !(e.err && e.err[WROTE_ERROR_KEY])) { - writeError(e); - localCache.taskErrors++; - } -} - -function exitProcess(errorCode: number): void { - if (!localCache.watchMode) { - process.stdout.write('', () => { - process.exit(errorCode); - }); - } -} - -function wireUpProcessErrorHandling(shouldWarningsFailBuild: boolean): void { - if (!wiredUpErrorHandling) { - wiredUpErrorHandling = true; - - let wroteToStdErr: boolean = false; - - if (shouldWarningsFailBuild) { - const oldStdErr: Function = process.stderr.write; - process.stderr.write = function (text: string | Buffer): boolean { - if (text.toString()) { - wroteToStdErr = true; - return oldStdErr.apply(process.stderr, arguments); - } - return true; - }; - } - - process.on('exit', (code: number) => { - duringFastExit = true; - if (!global['dontWatchExit']) { // eslint-disable-line dot-notation - if (!localCache.wroteSummary) { - localCache.wroteSummary = true; - console.log('About to exit with code:', code); - console.error('Process terminated before summary could be written, possible error in async code not ' + - 'continuing!'); - console.log('Trying to exit with exit code 1'); - exitProcess(1); - } else { - if (localCache.exitCode !== 0) { - console.log(`Exiting with exit code: ${localCache.exitCode}`); - exitProcess(localCache.exitCode); - } else if (wroteToStdErr) { - console.error(`The build failed because a task wrote output to stderr.`); - console.log(`Exiting with exit code: 1`); - exitProcess(1); - } - } - } - }); - - process.on('uncaughtException', - (err: Error) => { - console.error(err); - - _writeTaskError(err); - writeSummary(() => { - exitProcess(1); - - if (localCache.gulpErrorCallback) { - localCache.gulpErrorCallback(err); - } - }); - }); - } -} - -function markErrorAsWritten(err: Error): void { - try { - err[WROTE_ERROR_KEY] = true; - } catch (e) { - // Do Nothing - } -} - -/** - * Adds a message to be displayed in the summary after execution is complete. - * @param value - the message to display - * @public - */ -export function logSummary(value: string): void { - localCache.writeSummaryLogs.push(value); -} - -/** - * Log a message to the console - * @param args - the messages to log to the console - * @public - */ -export function log(...args: string[]): void { - const currentTime: Date = new Date(); - const timestamp: string = colors.gray( - [padTimePart(currentTime.getHours()), - padTimePart(currentTime.getMinutes()), - padTimePart(currentTime.getSeconds())] - .join(':')); - console.log(`[${timestamp}] ${args.join('')}`); -} - -function padTimePart(timepart: number): string { - return timepart >= 10 ? timepart.toString(10) : `0${timepart.toString(10)}`; -} - -/** - * Resets the state of the logging cache - * @public - */ -export function reset(): void { - localCache.start = process.hrtime(); - localCache.warnings = []; - localCache.errors = []; - localCache.coverageResults = 0; - localCache.coveragePass = 0; - localCache.coverageTotal = 0; - localCache.taskRun = 0; - localCache.subTasksRun = 0; - localCache.taskErrors = 0; - localCache.totalTaskHrTime = undefined; - localCache.totalTaskSrc = 0; - localCache.wroteSummary = false; - localCache.writingSummary = false; - localCache.writeSummaryCallbacks = []; - localCache.testsRun = 0; - localCache.testsPassed = 0; - localCache.testsFailed = 0; - localCache.testsFlakyFailed = 0; - localCache.testsSkipped = 0; - localCache.writeSummaryLogs = []; -} - -/** - * The result of a functional test run - * @public - */ -export enum TestResultState { - Passed, - Failed, - FlakyFailed, - Skipped -} - -/** - * Store a single functional test run's information - * @param name - the name of the test - * @param result - the result of the test - * @param duration - the length of time it took for the test to execute - * @public - */ -export function functionalTestRun(name: string, result: TestResultState, duration: number): void { - localCache.testsRun++; - - switch (result) { - case TestResultState.Failed: - localCache.testsFailed++; - break; - case TestResultState.Passed: - localCache.testsPassed++; - break; - case TestResultState.FlakyFailed: - localCache.testsFlakyFailed++; - break; - case TestResultState.Skipped: - localCache.testsSkipped++; - break; - } -} - -/** @public */ -export function endTaskSrc(taskName: string, startHrtime: [number, number], fileCount: number): void { - localCache.totalTaskSrc++; - const taskDuration: [number, number] = process.hrtime(startHrtime); - if (!localCache.totalTaskHrTime) { - localCache.totalTaskHrTime = taskDuration; - } else { - localCache.totalTaskHrTime[0] += taskDuration[0]; - const nanoSecTotal: number = taskDuration[1] + localCache.totalTaskHrTime[1]; - if (nanoSecTotal > 1e9) { - localCache.totalTaskHrTime[0]++; - localCache.totalTaskHrTime[1] = nanoSecTotal - 1e9; - } else { - localCache.totalTaskHrTime[1] = nanoSecTotal; - } - } - - log(taskName, 'read src task duration:', colors.yellow(prettyTime(taskDuration)), `- ${fileCount} files`); -} - -/** - * Store coverage information, potentially logging an error if the coverage is below the threshold - * @param coverage - the coverage of the file as a percentage - * @param threshold - the minimum coverage for the file as a percentage, an error will be logged if coverage is below - * the threshold - * @param filePath - the path to the file whose coverage is being measured - * @public - */ -export function coverageData(coverage: number, threshold: number, filePath: string): void { - localCache.coverageResults++; - - if (coverage < threshold) { - error('Coverage:', Math.floor(coverage) + '% (<' + threshold + '%) -', filePath); - } else { - localCache.coveragePass++; - } - - localCache.coverageTotal += coverage; -} - -// eslint-disable-next-line no-control-regex -const colorCodeRegex: RegExp = /\x1B[[(?);]{0,2}(;?\d)*./g; - -/** - * Adds a suppression for an error or warning - * @param suppression - the error or warning as a string or Regular Expression - * @public - */ -export function addSuppression(suppression: string | RegExp): void { - - if (typeof suppression === 'string') { - suppression = normalizeMessage(suppression); - } - - localCache.errorAndWarningSuppressions.push(suppression); - - if (getConfig().verbose) { - logSummary(`${colors.yellow('Suppressing')} - ${suppression.toString()}`); - } -} - -/** - * Logs a warning. It will be logged to standard error and cause the build to fail - * if buildConfig.shouldWarningsFailBuild is true, otherwise it will be logged to standard output. - * @param message - the warning description - * @public - */ -export function warn(...args: string[]): void { - args.splice(0, 0, 'Warning -'); - - const stringMessage: string = normalizeMessage(args.join(' ')); - - if (!messageIsSuppressed(stringMessage)) { - localCache.warnings.push(stringMessage); - log(colors.yellow.apply(undefined, args)); - } -} - -/** - * Logs an error to standard error and causes the build to fail. - * @param message - the error description - * @public - */ -export function error(...args: string[]): void { - args.splice(0, 0, 'Error -'); - - const stringMessage: string = normalizeMessage(args.join(' ')); - - if (!messageIsSuppressed(stringMessage)) { - localCache.errors.push(stringMessage); - log(colors.red.apply(undefined, args)); - } -} - -/** - * Logs a message about a particular file - * @param write - the function which will write message - * @param taskName - the name of the task which is doing the logging - * @param filePath - the path to the file which encountered an issue - * @param line - the line in the file which had an issue - * @param column - the column in the file which had an issue - * @param errorCode - the custom error code representing this error - * @param message - a description of the error - * @public - */ -export function fileLog( - write: (text: string) => void, - taskName: string, - filePath: string, - line: number, - column: number, - errorCode: string, - message: string -): void { - - if (!filePath) { - filePath = ''; - } else if (path.isAbsolute(filePath)) { - filePath = path.relative(process.cwd(), filePath); - } - - write(`${colors.cyan(taskName)} - ${filePath}(${line},${column}): error ${errorCode}: ${message}`); -} - -/** - * Logs a warning regarding a specific file. - * @param filePath - the path to the file which encountered an issue - * @param line - the line in the file which had an issue - * @param column - the column in the file which had an issue - * @param warningCode - the custom warning code representing this warning - * @param message - a description of the warning - * @public - */ -export function fileWarning( - taskName: string, - filePath: string, - line: number, - column: number, - errorCode: string, - message: string -): void { - fileLog(warn, taskName, filePath, line, column, errorCode, message); -} - -/** - * Logs an error regarding a specific file to standard error and causes the build to fail. - * @param filePath - the path to the file which encountered an issue - * @param line - the line in the file which had an issue - * @param column - the column in the file which had an issue - * @param errorCode - the custom error code representing this error - * @param message - a description of the error - * @public - */ -export function fileError( - taskName: string, - filePath: string, - line: number, - column: number, - errorCode: string, - message: string -): void { - fileLog(error, taskName, filePath, line, column, errorCode, message); -} - -/** - * Logs a message to standard output if the verbose flag is specified. - * @param args - the messages to log when in verbose mode - * @public - */ -export function verbose(...args: string[]): void { - - if (getFlagValue('verbose')) { - log.apply(undefined, args); - } -} - -/** @public */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function generateGulpError(err: any): any { - if (isVerbose()) { - return err; - } else { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const output: any = { - showStack: false, - toString: (): string => { - return ''; - } - }; - - markErrorAsWritten(output); - - return output; - } -} - -/** - * Logs an error to standard error and causes the build to fail. - * @param e - the error (can be a string or Error object) - * @public - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function writeError(e: any): void { - if (e) { - if (!e[WROTE_ERROR_KEY]) { - if (e.err) { - if (!e.err[WROTE_ERROR_KEY]) { - const msg: string | undefined = formatError(e); - const time: string = prettyTime(e.hrDuration); - - error( - '\'' + colors.cyan(e.task) + '\'', - colors.red(e.subTask ? 'sub task errored after' : 'errored after'), - colors.magenta(time), - '\r\n', - msg || '' - ); - markErrorAsWritten(e.err[WROTE_ERROR_KEY]); - } - } else if (e.fileName) { - // This is probably a plugin error - if (isVerbose()) { - error( - e.message, - '\r\n', - e.plugin + ': \'' + colors.yellow(e.fileName) + '\':' + e.lineNumber, - '\r\n', - e.stack - ); - } else { - error( - e.message, - '\r\n', - e.plugin + ': \'' + colors.yellow(e.fileName) + '\':' + e.lineNumber - ); - } - } else { - if (isVerbose()) { - error( - 'Unknown', - '\r\n', - colors.red(e.message), - '\r\n', - e.stack); - } else { - error( - 'Unknown', - '\r\n', - colors.red(e.message)); - } - } - markErrorAsWritten(e); - } - } else { - error('Unknown Error Object'); - } -} - -/** - * Returns the list of warnings which have been logged - * @public - */ -export function getWarnings(): string[] { - return localCache.warnings; -} - -/** - * Returns the list of errors which have been logged - * @public - */ -export function getErrors(): string[] { - return localCache.errors; -} - -/** @public */ -export function getStart(): [number, number] | undefined { - return localCache.start; -} - -/** - * @public - */ -export function setWatchMode(): void { - localCache.watchMode = true; -} - -/** - * @public - */ -export function getWatchMode(): boolean | undefined { - return localCache.watchMode; -} - -/** - * @public - */ -export function setExitCode(exitCode: number): void { - localCache.exitCode = exitCode; -} - -/** - * @public - */ -export function logStartSubtask(name: string): void { - log(`Starting subtask '${colors.cyan(name)}'...`); - localCache.subTasksRun++; -} - -/** - * @public - */ -export function logEndSubtask(name: string, startTime: [number, number], errorObject?: Error): void { - const duration: [number, number] = process.hrtime(startTime); - - if (name) { - if (!errorObject) { - const durationString: string = prettyTime(duration); - log(`Finished subtask '${colors.cyan(name)}' after ${colors.magenta(durationString)}`); - } else { - writeError({ - err: errorObject, - task: name, - subTask: true, - hrDuration: duration - }); - } - } -} - -/** - * @public - */ -export function initialize( - gulp: typeof Gulp, - config: IBuildConfig, - gulpErrorCallback?: (err: Error) => void, - gulpStopCallback?: (err: Error) => void -): void { - // This will add logging to the gulp execution - - localCache.gulp = gulp; - - wireUpProcessErrorHandling(config.shouldWarningsFailBuild); - - localCache.gulpErrorCallback = gulpErrorCallback || (() => { - - // Do Nothing - }); - - localCache.gulpStopCallback = gulpStopCallback || (() => { - - // Do Nothing - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('start', (err: any) => { - - log('Starting gulp'); - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('stop', (err: any) => { - - writeSummary(() => { - // error if we have any errors - if (localCache.taskErrors > 0 || - (getWarnings().length && config.shouldWarningsFailBuild) || - getErrors().length || - localCache.testsFailed > 0) { - exitProcess(1); - } - - if (localCache.gulpStopCallback) { - localCache.gulpStopCallback(err); - } - exitProcess(0); - }); - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('err', (err: any) => { - - _writeTaskError(err); - writeSummary(() => { - exitProcess(1); - if (localCache.gulpErrorCallback) { - localCache.gulpErrorCallback(err); - } - }); - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('task_start', (e: any) => { - - if (localCache.fromRunGulp) { - log('Starting', '\'' + colors.cyan(e.task) + '\'...'); - } - - localCache.taskRun++; - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('task_stop', (e: any) => { - - const time: string = prettyTime(e.hrDuration); - - if (localCache.fromRunGulp) { - log( - 'Finished', '\'' + colors.cyan(e.task) + '\'', - 'after', colors.magenta(time) - ); - } - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('task_err', (err: any) => { - - _writeTaskError(err); - writeSummary(() => { - exitProcess(1); - }); - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - gulp.on('task_not_found', (err: any) => { - - log( - colors.red('Task \'' + err.task + '\' is not in your gulpfile') - ); - log('Please check the documentation for proper gulpfile formatting'); - exitProcess(1); - }); -} - -/** - * @public - */ -export function markTaskCreationTime(): void { - localCache.taskCreationTime = process.hrtime(getStart()); -} - -function messageIsSuppressed(message: string): boolean { - for (const suppression of localCache.errorAndWarningSuppressions) { - if (typeof suppression === 'string' && message === suppression) { - return true; - } else if (suppression instanceof RegExp && message.match(suppression)) { - return true; - } - } - return false; -} - -function normalizeMessage(message: string): string { - return message - .replace(colorCodeRegex, '') // remove colors - .replace(/\r\n/g, '\n') // normalize newline - .replace(/\\/g, '/'); // normalize slashes -} diff --git a/core-build/gulp-core-build/src/pass.png b/core-build/gulp-core-build/src/pass.png deleted file mode 100644 index 60b4d3042e6..00000000000 Binary files a/core-build/gulp-core-build/src/pass.png and /dev/null differ diff --git a/core-build/gulp-core-build/src/tasks/CleanFlagTask.ts b/core-build/gulp-core-build/src/tasks/CleanFlagTask.ts deleted file mode 100644 index 7a54f79f062..00000000000 --- a/core-build/gulp-core-build/src/tasks/CleanFlagTask.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 { CleanTask } from './CleanTask'; -import * as Gulp from 'gulp'; -import { IBuildConfig } from './../IBuildConfig'; - -/** - * This task runs at the start of any command if the --clean or -c parameter is specified - * @public - */ -export class CleanFlagTask extends CleanTask { - /** Instantiates a new CleanTask with the name 'clean' */ - private _hasRun: boolean = false; - - public constructor() { - super(); - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - // eslint-disable-next-line dot-notation - const shouldRun: boolean = (!!buildConfig.args['clean'] || !!buildConfig.args['c']) - && this._hasRun === false; - return shouldRun; -} - - public executeTask( - gulp: typeof Gulp, - completeCallback: (error?: string | Error) => void - ): void { - super.executeTask(gulp, () => { - this._hasRun = true; - completeCallback(); - }); - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/CleanTask.ts b/core-build/gulp-core-build/src/tasks/CleanTask.ts deleted file mode 100644 index c68063bceac..00000000000 --- a/core-build/gulp-core-build/src/tasks/CleanTask.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask } from './GulpTask'; -import * as Gulp from 'gulp'; - -import { FileDeletionUtility } from '../utilities/FileDeletionUtility'; -import { IBuildConfig } from './../IBuildConfig'; - -/** - * The clean task is a special task which iterates through all registered - * tasks and subtasks, collecting a list of patterns which should be deleted. - * An instance of this task is automatically registered to the 'clean' command. - * @public - */ -export class CleanTask extends GulpTask { - /** - * Instantiates a new CleanTask with the name 'clean' - */ - public constructor() { - super('clean'); - } - - /** - * The main function, which iterates through all uniqueTasks registered - * to the build, and by calling the getCleanMatch() function, collects a list of - * glob patterns which are then passed to the `del` plugin to delete them from disk. - */ - public executeTask( - gulp: typeof Gulp, - completeCallback: (error?: string | Error) => void - ): void { - const { distFolder, libFolder, libAMDFolder, tempFolder }: IBuildConfig = this.buildConfig; - let cleanPaths: string[] = [ - distFolder, - libFolder, - tempFolder - ]; - - if (libAMDFolder) { - cleanPaths.push(libAMDFolder); - } - - // Give each registered task an opportunity to add their own clean paths. - for (const executable of this.buildConfig.uniqueTasks || []) { - if (executable.getCleanMatch) { - // Set the build config, as tasks need this to build up paths - cleanPaths = cleanPaths.concat(executable.getCleanMatch(this.buildConfig)); - } - } - - const uniquePaths: { [key: string]: string } = {}; - - // Create dictionary of unique paths. (Could be replaced with ES6 set.) - cleanPaths.forEach(cleanPath => { - if (cleanPath) { - uniquePaths[cleanPath] = cleanPath; - } - }); - - // Reset cleanPaths to only unique non-empty paths. - cleanPaths = []; - for (const uniquePath in uniquePaths) { - if (uniquePaths.hasOwnProperty(uniquePath)) { - cleanPaths.push(uniquePath); - } - } - - try { - FileDeletionUtility.deletePatterns(cleanPaths); - completeCallback(); - } catch (e) { - completeCallback(e); - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/CopyTask.ts b/core-build/gulp-core-build/src/tasks/CopyTask.ts deleted file mode 100644 index e3536924a3b..00000000000 --- a/core-build/gulp-core-build/src/tasks/CopyTask.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask } from './GulpTask'; -import * as Gulp from 'gulp'; -import { JsonObject } from '@rushstack/node-core-library'; - -/** - * Configuration for CopyTask - * @public - */ -export interface ICopyConfig { - /** - * The list of patterns and the destination which where they should be copied - */ - copyTo: { - /** - * A mapping of destination paths (absolute or relative) to a list of glob pattern matches - */ - [destPath: string]: string[]; - }; - - /** - * If true, the files will be copied into a flattened folder. If false, they will retain the original - * folder structure. True by default. - */ - shouldFlatten?: boolean; -} - -/** - * This task takes in a map of dest: [sources], and copies items from one place to another. - * @public - */ -export class CopyTask extends GulpTask { - /** - * Instantiates a CopyTask with an empty configuration - */ - public constructor() { - super( - 'copy', - { - copyTo: {}, - shouldFlatten: true - } - ); - } - - /** - * Loads the z-schema object for this task - */ - public loadSchema(): JsonObject { - return require('./copy.schema.json'); - } - - /** - * Executes the copy task, which copy files based on the task's Configuration - */ - public executeTask( - gulp: typeof Gulp, - completeCallback: (error?: string | Error) => void - ): Promise | NodeJS.ReadWriteStream | void { // eslint-disable-line @typescript-eslint/no-explicit-any - /* eslint-disable */ - const flatten = require('gulp-flatten'); - const gulpif = require('gulp-if'); - const merge = require('merge2'); - /* eslint-enable */ - - const { copyTo, shouldFlatten } = this.taskConfig; - - const allStreams: NodeJS.ReadWriteStream[] = []; - - for (const copyDest in copyTo) { - if (copyTo.hasOwnProperty(copyDest)) { - const sources: string[] = copyTo[copyDest]; - - sources.forEach(sourceMatch => allStreams.push( - gulp.src(sourceMatch, { allowEmpty: true }) - .pipe(gulpif(shouldFlatten, flatten())) - .pipe(gulp.dest(copyDest)) - )); - } - } - - if (allStreams.length === 0) { - completeCallback(); - } else { - return merge(allStreams); - } - } -} diff --git a/core-build/gulp-core-build/src/tasks/GenerateShrinkwrapTask.ts b/core-build/gulp-core-build/src/tasks/GenerateShrinkwrapTask.ts deleted file mode 100644 index 7fdf60295f4..00000000000 --- a/core-build/gulp-core-build/src/tasks/GenerateShrinkwrapTask.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import gulpType = require('gulp'); -import * as child_process from 'child_process'; -import * as os from 'os'; -import * as path from 'path'; -import { FileSystem } from '@rushstack/node-core-library'; - -import { GulpTask } from './GulpTask'; - -/** - * This provides a convenient way to more consistently generate a shrinkwrap file in - * a desired manner as a gulp task, as there are many consistency issues with just - * running npm-shrinkwrap directly. - * @public - */ -export class GenerateShrinkwrapTask extends GulpTask { - /** - * Instantiates a GenerateShrinkwrap task which will regenerate the shrinkwrap for a particular project - */ - public constructor() { - super('generate-shrinkwrap'); - } - - /** - * Runs npm `prune` and `update` on a package before running `shrinkwrap --dev` - */ - public executeTask( - gulp: gulpType.Gulp, - completeCallback: (error?: string | Error) => void - ): NodeJS.ReadWriteStream | void { - const pathToShrinkwrap: string = path.join(this.buildConfig.rootPath, 'npm-shrinkwrap.json'); - - if (this.fileExists(pathToShrinkwrap)) { - this.log(`Remove existing shrinkwrap file.`); - this._dangerouslyDeletePath(pathToShrinkwrap); - } - - this.log(`Running npm prune`); - child_process.execSync('npm prune'); - - this.log(`Running npm update`); - child_process.execSync('npm update'); - - this.log(`Running npm shrinkwrap --dev`); - child_process.execSync('npm shrinkwrap --dev'); - - completeCallback(); - return; - } - - private _dangerouslyDeletePath(folderPath: string): void { - try { - FileSystem.deleteFolder(folderPath); - } catch (e) { - throw new Error(`${e.message}${os.EOL}Often this is caused by a file lock from a process - such as your text editor, command prompt, or "gulp serve"`); - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/GulpTask.ts b/core-build/gulp-core-build/src/tasks/GulpTask.ts deleted file mode 100644 index 0263fe7f32f..00000000000 --- a/core-build/gulp-core-build/src/tasks/GulpTask.ts +++ /dev/null @@ -1,410 +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 colors from 'colors'; -import * as path from 'path'; -import { JsonFile, JsonSchema, FileSystem, JsonObject } from '@rushstack/node-core-library'; - -import { GulpProxy } from '../GulpProxy'; -import { IExecutable } from '../IExecutable'; -import { IBuildConfig } from '../IBuildConfig'; -import { - log, - verbose, - error, - fileError, - fileWarning, - warn, - logEndSubtask, - logStartSubtask -} from '../logging'; -import Vinyl = require('vinyl'); -import gulp = require('gulp'); -import through2 = require('through2'); - -// eslint-disable-next-line -const eos = require('end-of-stream'); - -import { args } from '../State'; - -/** - * The base GulpTask class, should be extended by any classes which represent build tasks. - * It provides convenient mechanisms for reading configuration files, validating their schema, - * etc. It also provides convenient utility and logging functions. - * @public - */ -export abstract class GulpTask implements IExecutable { - /** - * The name of the task. The configuration file with this name will be loaded and applied to the task. - */ - public name: string; - - /** - * The global build configuration object. Will be the same for all task instances. - */ - public buildConfig: IBuildConfig; - - /** - * The configuration for this task instance. - */ - public taskConfig: TTaskConfig; - - /** - * An overridable array of file patterns which will be utilized by the CleanTask to - * determine which files to delete. Unless overridden, the getCleanMatch() function - * will return this value. - */ - public cleanMatch: string[]; - - /** - * Indicates whether this task should be executed or not. This toggle is used by isEnabled() to determine - * if the task should run. Since some tasks have more complex logic to determine if they should run or - * not, the isEnabled() function can be overridden. - */ - public enabled: boolean = true; - - /** - * The memoized schema for this task. Should not be utilized by child classes, use schema property instead. - */ - private _schema: JsonObject | undefined; - - /** - * Initializes a new instance of the task with the specified initial task config - */ - public constructor(name: string, initialTaskConfig: Partial = {}) { - this.name = name; - this.setConfig(initialTaskConfig); - } - - /** - * Overridable function which returns true if this task should be executed, or false if it should be skipped. - * @param buildConfig - the build configuration which should be used when determining if the task is enabled - * @returns true if the build is not redundant and the enabled toggle is true - */ - public isEnabled(buildConfig: IBuildConfig): boolean { - return (!buildConfig || !buildConfig.isRedundantBuild) && this.enabled; - } - - /** - * A JSON Schema object which will be used to validate this task's configuration file. - * @returns a z-schema schema definition - */ - public get schema(): JsonObject | undefined { - if (!this._schema) { - this._schema = this.loadSchema(); - } - return this._schema; - } - - /** - * Shallow merges config settings into the task config. - * Note this will override configuration options for those which are objects. - * @param taskConfig - configuration settings which should be applied - */ - public setConfig(taskConfig: Partial): void { - // eslint-disable-next-line - const objectAssign = require('object-assign'); - - this.taskConfig = objectAssign({}, this.taskConfig, taskConfig); - } - - /** - * Deep merges config settings into task config. - * Do not use this function if the configuration contains complex objects that cannot be merged. - * @param taskConfig - configuration settings which should be applied - */ - public mergeConfig(taskConfig: Partial): void { - // eslint-disable-next-line - const merge = require('lodash.merge'); - - this.taskConfig = merge({}, this.taskConfig, taskConfig); - } - - /** - * Replaces all of the task config settings with new settings. - * @param taskConfig - the new task configuration - */ - public replaceConfig(taskConfig: TTaskConfig): void { - this.taskConfig = taskConfig; - } - - /** - * This function is called when the task is initially registered into gulp-core-build as a task or subtask. It reads - * the configuration file, validates it against the schema, then applies it to the task instance's configuration. - */ - public onRegister(): void { - const configFilename: string = this._getConfigFilePath(); - const schema: JsonObject | undefined = this.schema; - - const rawConfig: TTaskConfig | undefined = this._readConfigFile(configFilename, schema); - - if (rawConfig) { - this.mergeConfig(rawConfig); - } - } - - /** - * When the task is executed by the build system, this function is called once. Note that this function - * must either return a Promise, a Stream, or call the completeCallback() parameter. - * @param gulp - an instance of the gulp library - * @param completeCallback - a callback which should be called if the function is non-value returning - * @returns a Promise, a Stream or undefined if completeCallback() is called - */ - public abstract executeTask( - gulp: gulp.Gulp | GulpProxy, - completeCallback?: (error?: string | Error) => void - ): Promise | NodeJS.ReadWriteStream | void; // eslint-disable-line @typescript-eslint/no-explicit-any - - /** - * Logs a message to standard output. - * @param message - the message to log to standard output. - */ - public log(message: string): void { - log(`[${colors.cyan(this.name)}] ${message}`); - } - - /** - * Logs a message to standard output if the verbose flag is specified. - * @param message - the message to log when in verbose mode - */ - public logVerbose(message: string): void { - verbose(`[${colors.cyan(this.name)}] ${message}`); - } - - /** - * Logs a warning. It will be logged to standard error and cause the build to fail - * if buildConfig.shouldWarningsFailBuild is true, otherwise it will be logged to standard output. - * @param message - the warning description - */ - public logWarning(message: string): void { - warn(`[${colors.cyan(this.name)}] ${message}`); - } - - /** - * Logs an error to standard error and causes the build to fail. - * @param message - the error description - */ - public logError(message: string): void { - error(`[${colors.cyan(this.name)}] ${message}`); - } - - /** - * Logs an error regarding a specific file to standard error and causes the build to fail. - * @param filePath - the path to the file which encountered an issue - * @param line - the line in the file which had an issue - * @param column - the column in the file which had an issue - * @param errorCode - the custom error code representing this error - * @param message - a description of the error - */ - public fileError(filePath: string, line: number, column: number, errorCode: string, message: string): void { - fileError(this.name, filePath, line, column, errorCode, message); - } - - /** - * Logs a warning regarding a specific file. - * @param filePath - the path to the file which encountered an issue - * @param line - the line in the file which had an issue - * @param column - the column in the file which had an issue - * @param warningCode - the custom warning code representing this warning - * @param message - a description of the warning - */ - public fileWarning(filePath: string, line: number, column: number, warningCode: string, message: string): void { - fileWarning(this.name, filePath, line, column, warningCode, message); - } - - /** - * An overridable function which returns a list of glob patterns representing files that should be deleted - * by the CleanTask. - * @param buildConfig - the current build configuration - * @param taskConfig - a task instance's configuration - */ - public getCleanMatch(buildConfig: IBuildConfig, taskConfig: TTaskConfig = this.taskConfig): string[] { - return this.cleanMatch; - } - - /** - * This function is called once to execute the task. It calls executeTask() and handles the return - * value from that function. It also provides some utilities such as logging how long each - * task takes to execute. - * @param config - the buildConfig which is applied to the task instance before execution - * @returns a Promise which is completed when the task is finished executing - */ - public execute(config: IBuildConfig): Promise { - this.buildConfig = config; - - const startTime: [number, number] = process.hrtime(); - - logStartSubtask(this.name); - - return new Promise((resolve, reject) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let stream: any = undefined; - - try { - if (!this.executeTask) { - throw new Error('The task subclass is missing the "executeTask" method.'); - } - - stream = this.executeTask(this.buildConfig.gulp, (err?: string | Error) => { - if (!err) { - resolve(); - } else if (typeof err === 'string') { - reject(new Error(err)); - } else { - reject(err); - } - }); - } catch (e) { - this.logError(e); - reject(e); - } - - if (stream) { - if (stream.then) { - stream.then(resolve, reject); - } else if (stream.pipe) { - // wait for stream to end - - eos(stream, { - error: true, - readable: stream.readable, - writable: stream.writable && !stream.readable - }, (err: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any - if (err) { - reject(err); - } else { - resolve(); - } - }); - - // Make sure the stream is completely read - stream.pipe(through2.obj( - (file: Vinyl, - encoding: string, - callback: (p?: any) => void) => { // eslint-disable-line @typescript-eslint/no-explicit-any - callback(); - }, - (callback: () => void) => { - callback(); - })); - - } else if (this.executeTask.length === 1) { - resolve(stream); - } - } else if (this.executeTask.length === 1) { - resolve(stream); - } - }) - .then(() => { - logEndSubtask(this.name, startTime); - }, - (ex) => { - logEndSubtask(this.name, startTime, ex); - throw ex; - }); - } - - /** - * Resolves a path relative to the buildConfig.rootPath. - * @param localPath - a relative or absolute path - * @returns If localPath is relative, returns an absolute path relative to the rootPath. Otherwise, returns localPath. - */ - public resolvePath(localPath: string): string { - if (path.isAbsolute(localPath)) { - return path.resolve(localPath); - } - - return path.resolve(path.join(this.buildConfig.rootPath, localPath)); - } - - /** - * Synchronously detect if a file exists. - * @param localPath - the path to the file [resolved using resolvePath()] - * @returns true if the file exists, false otherwise - */ - public fileExists(localPath: string): boolean { - let doesExist: boolean = false; - const fullPath: string = this.resolvePath(localPath); - - try { - doesExist = FileSystem.getStatistics(fullPath).isFile(); - } catch (e) { /* no-op */ } - - return doesExist; - } - - /** - * Copy a file from one location to another. - * @param localSourcePath - path to the source file - * @param localDestPath - path to the destination file - */ - public copyFile(localSourcePath: string, localDestPath?: string): void { - const fullSourcePath: string = path.resolve(__dirname, localSourcePath); - const fullDestPath: string = path.resolve( - this.buildConfig.rootPath, - (localDestPath || path.basename(localSourcePath))); - - FileSystem.copyFile({ - sourcePath: fullSourcePath, - destinationPath: fullDestPath - }); - } - - /** - * Read a JSON file into an object - * @param localPath - the path to the JSON file - */ - public readJSONSync(localPath: string): JsonObject | undefined { - const fullPath: string = this.resolvePath(localPath); - let result: JsonObject | undefined = undefined; - - try { - const content: string = FileSystem.readFile(fullPath); - result = JSON.parse(content); - } catch (e) { /* no-op */ } - - return result; - } - - /** - * Override this function to provide a schema which will be used to validate - * the task's configuration file. This function is called once per task instance. - * @returns a z-schema schema definition - */ - protected loadSchema(): JsonObject | undefined { - return undefined; - } - - /** - * Returns the path to the config file used to configure this task - */ - protected _getConfigFilePath(): string { - return path.join(process.cwd(), 'config', `${this.name}.json`); - } - - /** - * Helper function which loads a custom configuration file from disk and validates it against the schema - * @param filePath - the path to the custom configuration file - * @param schema - the z-schema schema object used to validate the configuration file - * @returns If the configuration file is valid, returns the configuration as an object. - */ - private _readConfigFile(filePath: string, schema?: JsonObject): TTaskConfig | undefined { - if (!FileSystem.exists(filePath)) { - return undefined; - } else { - if (args['verbose']) { // eslint-disable-line dot-notation - console.log(`Found config file: ${path.basename(filePath)}`); - } - - const rawData: TTaskConfig = JsonFile.load(filePath); - - if (schema) { - // TODO: Convert GulpTask.schema to be a JsonSchema instead of a bare object - const jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schema); - jsonSchema.validateObject(rawData, filePath); - } - - return rawData; - } - } -} diff --git a/core-build/gulp-core-build/src/tasks/JestReporter.ts b/core-build/gulp-core-build/src/tasks/JestReporter.ts deleted file mode 100644 index f9b51792b9c..00000000000 --- a/core-build/gulp-core-build/src/tasks/JestReporter.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { FileSystem } from '@rushstack/node-core-library'; -import * as xml from 'xml'; -import * as Jest from 'jest-cli'; -import * as TestResults from 'jest-nunit-reporter/src/Testresults'; -import { default as DEFAULT_REPORTER } from 'jest-cli/build/reporters/default_reporter'; - -/** - * Jest logs message to stderr. This class is to override that behavior so that - * rush does not get confused. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -class JestReporter extends (DEFAULT_REPORTER as { new (globalConfig: Jest.GlobalConfig): any }) { - private _options: IReporterOptions | undefined; - - public constructor(globalConfig: Jest.GlobalConfig, options?: IReporterOptions) { - super(globalConfig); - this._options = options; - } - - public log(message: string): void { - process.stdout.write(message + '\n'); - } - - public onRunComplete(contexts: Set, results: Jest.AggregatedResult): void { - super.onRunComplete(contexts, results); - if (!this._options || !this._options.writeNUnitResults) { - return; - } - - const outputFilePath: string | undefined = this._options.outputFilePath; - if (!outputFilePath) { - throw new Error('Jest NUnit output was enabled but no outputFilePath was provided'); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const testResults: TestResults = new TestResults(results); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const data: string = xml(testResults, { declaration: true, indent: ' ' }); - FileSystem.writeFile(outputFilePath, data, { ensureFolderExists: true }); - } -} - -interface IReporterOptions { - outputFilePath?: string, - writeNUnitResults?: boolean -} - -module.exports = JestReporter; \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/JestTask.ts b/core-build/gulp-core-build/src/tasks/JestTask.ts deleted file mode 100644 index f6fa0cfa282..00000000000 --- a/core-build/gulp-core-build/src/tasks/JestTask.ts +++ /dev/null @@ -1,221 +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 { GulpTask} from './GulpTask'; -import { IBuildConfig } from '../IBuildConfig'; -import * as Gulp from 'gulp'; -import * as Jest from 'jest-cli'; -import * as glob from 'glob'; -import { FileSystem, JsonObject } from '@rushstack/node-core-library'; - -/** - * Configuration for JestTask - * @alpha - */ -export interface IJestConfig { - /** - * Indicate whether this task is enabled. The default value is false. - */ - isEnabled?: boolean; - - /** - * Indicate whether Jest cache is enabled or not. - */ - cache?: boolean; - - /** - * Same as Jest CLI option collectCoverageFrom - */ - collectCoverageFrom?: string[]; - - /** - * Same as Jest CLI option coverage - */ - coverage?: boolean; - - /** - * Same as Jest CLI option coverageReporters - */ - coverageReporters?: string[]; - - /** - * Same as Jest CLI option testPathIgnorePatterns - */ - testPathIgnorePatterns?: string[]; - - /** - * Same as Jest CLI option modulePathIgnorePatterns - */ - modulePathIgnorePatterns?: string[]; - - /** - * Same as Jest CLI option moduleDirectories - */ - moduleDirectories?: string[]; - - /** - * Same as Jest CLI option maxWorkers - */ - maxWorkers?: number; - - /** - * Same as Jest CLI option testMatch - */ - testMatch?: string[]; - - /** - * Indicate whether writing NUnit results is enabled when using the default reporter - */ - writeNUnitResults?: boolean; -} - -const DEFAULT_JEST_CONFIG_FILE_NAME: string = 'jest.config.json'; - -/** - * Indicates if jest is enabled - * @internal - * @param rootFolder - package root folder - */ -export function _isJestEnabled(rootFolder: string): boolean { - const taskConfigFile: string = path.join(rootFolder, 'config', 'jest.json'); - if (!FileSystem.exists(taskConfigFile)) { - return false; - } - // eslint-disable-next-line @typescript-eslint/no-var-requires - const taskConfig: {} = require(taskConfigFile); - // eslint-disable-next-line dot-notation - return !!taskConfig['isEnabled']; -} - -/** - * This task takes in a map of dest: [sources], and copies items from one place to another. - * @alpha - */ -export class JestTask extends GulpTask { - - public constructor() { - super('jest', - { - cache: true, - collectCoverageFrom: ['lib/**/*.js?(x)', '!lib/**/test/**'], - coverage: true, - coverageReporters: ['json' /*, 'html' */], // Remove HTML reporter temporarily until the Handlebars issue is fixed - testPathIgnorePatterns: ['/(src|lib-amd|lib-es6|coverage|build|docs|node_modules)/'], - // Some unit tests rely on data folders that look like packages. This confuses jest-hast-map - // when it tries to scan for package.json files. - modulePathIgnorePatterns: ['/(src|lib)/.*/package.json'] - }); - } - - public isEnabled(buildConfig: IBuildConfig): boolean { - return super.isEnabled(buildConfig) && !!this.taskConfig.isEnabled; - } - - /** - * Loads the z-schema object for this task - */ - public loadSchema(): JsonObject { - return require('./jest.schema.json'); - } - - public executeTask( - gulp: typeof Gulp, - completeCallback: (error?: string | Error) => void - ): void { - const configFileFullPath: string = path.join(this.buildConfig.rootPath, - 'config', 'jest', DEFAULT_JEST_CONFIG_FILE_NAME); - - this._copySnapshots(this.buildConfig.srcFolder, this.buildConfig.libFolder); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const jestConfig: any = { - ci: this.buildConfig.production, - cache: !!this.taskConfig.cache, - config: FileSystem.exists(configFileFullPath) ? configFileFullPath : undefined, - collectCoverageFrom: this.taskConfig.collectCoverageFrom, - coverage: this.taskConfig.coverage, - coverageReporters: this.taskConfig.coverageReporters, - coverageDirectory: path.join(this.buildConfig.tempFolder, 'coverage'), - maxWorkers: this.taskConfig.maxWorkers ? - this.taskConfig.maxWorkers : 1, - moduleDirectories: this.taskConfig.moduleDirectories ? - this.taskConfig.moduleDirectories : - ['node_modules', this.buildConfig.libFolder], - reporters: [ - [ - path.join(__dirname, 'JestReporter.js'), - { - outputFilePath: path.join(this.buildConfig.tempFolder, 'jest-results', 'test-results.xml'), - writeNUnitResults: this.taskConfig.writeNUnitResults - } - ] - ], - rootDir: this.buildConfig.rootPath, - testMatch: this.taskConfig.testMatch ? - this.taskConfig.testMatch : ['**/*.test.js?(x)'], - testPathIgnorePatterns: this.taskConfig.testPathIgnorePatterns, - modulePathIgnorePatterns: this.taskConfig.modulePathIgnorePatterns, - updateSnapshot: !this.buildConfig.production, - - // Jest's module resolution for finding jest-environment-jsdom is broken. See this issue: - // https://github.com/facebook/jest/issues/5913 - // As a workaround, resolve it for Jest: - testEnvironment: require.resolve('jest-environment-jsdom'), - cacheDirectory: path.join(this.buildConfig.rootPath, this.buildConfig.tempFolder, 'jest-cache') - }; - - // suppress 'Running coverage on untested files...' warning - const oldTTY: true | undefined = process.stdout.isTTY; - process.stdout.isTTY = undefined; - - Jest.runCLI(jestConfig, - [this.buildConfig.rootPath]).then( - (result: { results: Jest.AggregatedResult, globalConfig: Jest.GlobalConfig }) => { - process.stdout.isTTY = oldTTY; - if (result.results.numFailedTests || result.results.numFailedTestSuites) { - completeCallback(new Error('Jest tests failed')); - } else { - if (!this.buildConfig.production) { - this._copySnapshots(this.buildConfig.libFolder, this.buildConfig.srcFolder); - } - completeCallback(); - } - }).catch((err) => { - process.stdout.isTTY = oldTTY; - completeCallback(err); - }); - } - - private _copySnapshots(srcRoot: string, destRoot: string): void { - const pattern: string = path.join(srcRoot, '**', '__snapshots__', '*.snap'); - glob.sync(pattern).forEach(snapFile => { - const destination: string = snapFile.replace(srcRoot, destRoot); - if (this._copyIfMatchExtension(snapFile, destination, '.test.tsx.snap')) { - this.logVerbose(`Snapshot file ${snapFile} is copied to match extension ".test.tsx.snap".`); - } else if (this._copyIfMatchExtension(snapFile, destination, '.test.ts.snap')) { - this.logVerbose(`Snapshot file ${snapFile} is copied to match extension ".test.ts.snap".`); - } else if (this._copyIfMatchExtension(snapFile, destination, '.test.jsx.snap')) { - this.logVerbose(`Snapshot file ${snapFile} is copied to match extension ".test.jsx.snap".`); - } else if (this._copyIfMatchExtension(snapFile, destination, '.test.js.snap')) { - this.logVerbose(`Snapshot file ${snapFile} is copied to match extension ".test.js.snap".`); - } else { - this.logWarning(`Snapshot file ${snapFile} is not copied because don't find that matching test file.`); - } - }); - } - - private _copyIfMatchExtension(snapSourceFile: string, destinationFile: string, extension: string): boolean { - const snapDestFile: string = destinationFile.replace(/\.test\..+\.snap$/, extension); - const testFileName: string = path.basename(snapDestFile, '.snap'); - const testFile: string = path.resolve(path.dirname(snapDestFile), '..', testFileName); // Up from `__snapshots__`. - if (FileSystem.exists(testFile)) { - FileSystem.copyFile({ - sourcePath: snapSourceFile, - destinationPath: snapDestFile - }); - return true; - } else { - return false; - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/ValidateShrinkwrapTask.ts b/core-build/gulp-core-build/src/tasks/ValidateShrinkwrapTask.ts deleted file mode 100644 index b1db8538323..00000000000 --- a/core-build/gulp-core-build/src/tasks/ValidateShrinkwrapTask.ts +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask } from './GulpTask'; -import gulpType = require('gulp'); -import * as path from 'path'; -import * as semver from 'semver'; -import { FileConstants } from '@rushstack/node-core-library'; - -interface IShrinkwrapDep { - [name: string]: { version: string } -}; - -interface IPackageDep { - [name: string]: string -}; - -/** - * Partial representation of the contents of a `package.json` file - */ -interface INpmPackage { - dependencies: IPackageDep; - devDependencies: IPackageDep; -} - -/** - * Partial representation of the contents of an `npm-shrinkwrap.json` file - */ -interface INpmShrinkwrap { - dependencies: IShrinkwrapDep; -} - -/** - * This task attempts to detect if package.json file has been updated without the - * shrinkwrap file being regenerated. - * - * It does this by checking that every dependency and dev dependency exists in the - * shrinkwrap file and that the version in the shrinkwrap file satisfies what is - * defined in the package.json file. - * @public - */ -export class ValidateShrinkwrapTask extends GulpTask { - /** - * Instantiates an instance of the ValidateShrinkwrap task - */ - public constructor() { - super('validate-shrinkwrap'); - } - - /** - * Iterates through dependencies listed in a project's package.json and ensures that they are all - * resolvable in the npm-shrinkwrap file. - */ - public executeTask(gulp: gulpType.Gulp, completeCallback: (error: string) => void): NodeJS.ReadWriteStream | void { - const pathToPackageJson: string = path.join(this.buildConfig.rootPath, FileConstants.PackageJson); - const pathToShrinkwrap: string = path.join(this.buildConfig.rootPath, 'npm-shrinkwrap.json'); - - if (!this.fileExists(pathToPackageJson)) { - this.logError('Failed to find package.json at ' + pathToPackageJson); - return; - } else if (!this.fileExists(pathToShrinkwrap)) { - this.logError('Failed to find package.json at ' + pathToShrinkwrap); - return; - } - - // eslint-disable-next-line - const packageJson: INpmPackage = require(pathToPackageJson); - // eslint-disable-next-line - const shrinkwrapJson: INpmShrinkwrap = require(pathToShrinkwrap); - - this._validate(packageJson.dependencies, shrinkwrapJson.dependencies); - this._validate(packageJson.devDependencies, shrinkwrapJson.dependencies); - - return; - } - - private _validate(packageDep: IPackageDep, shrinkwrapDep: IShrinkwrapDep): void { - for (const pkg in packageDep) { - if (!shrinkwrapDep.hasOwnProperty(pkg)) { - this.logError(`Failed to find package ${pkg} in shrinkwrap file`); - } else if (!semver.satisfies(shrinkwrapDep[pkg].version, packageDep[pkg])) { - this.logError(`Shrinkwrap version for ${pkg} (${shrinkwrapDep[pkg].version}) does not - satisfy package.json version of ${packageDep[pkg]}.`); - } - } - } -} diff --git a/core-build/gulp-core-build/src/tasks/copy.schema.json b/core-build/gulp-core-build/src/tasks/copy.schema.json deleted file mode 100644 index 54046d01381..00000000000 --- a/core-build/gulp-core-build/src/tasks/copy.schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "title": "Copy Task configuration", - "description": "Defines the static assets which should be copied as a build step", - - "type": "object", - "required": ["copyTo"], - "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" - }, - "copyTo": { - "description": "A mapping of destination folders to a list of files to get copied", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9_@/-]+$": { - "type": "array", - "description": "A list of paths to the source files which get copied", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": "string" - } - } - } - }, - "shouldFlatten": { - "description": "An optional property that indicates whether to keep the directory structure intact. By default it copies all files to the same directory level", - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/copyStaticAssets/CopyStaticAssetsTask.ts b/core-build/gulp-core-build/src/tasks/copyStaticAssets/CopyStaticAssetsTask.ts deleted file mode 100644 index 8e889ea4bd0..00000000000 --- a/core-build/gulp-core-build/src/tasks/copyStaticAssets/CopyStaticAssetsTask.ts +++ /dev/null @@ -1,105 +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 Gulp from 'gulp'; -import * as path from 'path'; -import globEscape = require('glob-escape'); -import { GulpTask } from '../GulpTask'; -import { JsonObject } from '@rushstack/node-core-library'; - -/** - * Configuration for CopyStaticAssetsTask - * @public - */ -export interface ICopyStaticAssetsTaskConfig { - includeExtensions?: string[]; - excludeExtensions?: string[]; - includeFiles?: string[]; - excludeFiles?: string[]; -} - -/** - * Copies files from the /src folder into the /lib folder, if they have certain file extensions - * or file paths. - * - * @privateRemarks - * - * Example: - * ``` - * IN: - * setConfig({ - * includeExtensions: ['template.html'], - * excludeExtensions: ['png'], - * includeFiles: ['/assets/goodAsset.png'], - * excludeFiles: ['/assets/badAsset.gif'] - * }) - * - * OUT: - * copies all files that match our standard webpack file-loader extensions - * ('jpg', 'png', 'woff', 'eot', 'ttf', 'svg', 'gif'), with the following extensions, in the following order of - * precedence (from lowest to highest): - * 1. including additional extensions (i.e. 'template.html') - * 2. excluding specific extensions (i.e. 'png') - * 3. including specific globs (i.e. '/assets/goodAsset.png') - * 4. excluding specific globs (i.e. '/assets/badAsset.gif') - * ``` - * @public - */ -export class CopyStaticAssetsTask extends GulpTask { - public constructor() { - super( - 'copy-static-assets', - { - includeExtensions: [], - excludeExtensions: [], - includeFiles: [], - excludeFiles: [] - } - ); - } - - public loadSchema(): JsonObject { - return require('./copy-static-assets.schema.json'); - } - - public executeTask(gulp: typeof Gulp, completeCallback: (error?: string) => void): NodeJS.ReadWriteStream { - const rootPath: string = path.join(this.buildConfig.rootPath, this.buildConfig.srcFolder || 'src'); - const libPath: string = path.join(this.buildConfig.rootPath, this.buildConfig.libFolder || 'lib'); - - const globPatterns: string[] = []; - - const allExtensions: string[] = (this.taskConfig.includeExtensions || []).concat(['json', 'html', 'css', 'md']); - - for (let ext of allExtensions) { - if (this.taskConfig.excludeExtensions) { - if (this.taskConfig.excludeExtensions.indexOf(ext) !== -1) { - break; // Skipping this extension. It's been excluded - } - } - - if (!ext.match(/^\./)) { - ext = `.${ext}`; - } - - globPatterns.push(path.join(rootPath, '**', `*${globEscape(ext)}`)); - } - - for (const file of this.taskConfig.includeFiles || []) { - if (this.taskConfig.excludeFiles) { - if (this.taskConfig.excludeFiles.indexOf(file) !== -1) { - break; // Skipping this file. It's been excluded - } - } - - globPatterns.push(path.join(rootPath, file)); - } - - for (const file of this.taskConfig.excludeFiles || []) { - globPatterns.push(`!${path.join(rootPath, file)}`); - } - - return gulp.src(globPatterns, { base: rootPath }) - .pipe(gulp.dest(libPath)) - .on('finish', () => completeCallback()); - } -} diff --git a/core-build/gulp-core-build/src/tasks/copyStaticAssets/copy-static-assets.schema.json b/core-build/gulp-core-build/src/tasks/copyStaticAssets/copy-static-assets.schema.json deleted file mode 100644 index 011546271fe..00000000000 --- a/core-build/gulp-core-build/src/tasks/copyStaticAssets/copy-static-assets.schema.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "title": "copy-static-assets Configuration", - "description": "Defines which static assets should be copied from the src directory to the lib directory", - - "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" - }, - - "includeExtensions": { - "title": "Include Extensions", - "description": "list of extensions to be copied", - - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - } - }, - - "excludeExtensions": { - "title": "Exclude Extensions", - "description": "list of extensions not to be copied. Takes prescedence over includeExtensions", - - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - } - }, - - "includeFiles": { - "title": "Include Files", - "description": "list of globs to be copied. Takes prescedence over extensions", - - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - } - }, - - "excludeFiles": { - "title": "Exclude Files", - "description": "list of globs not to be copied. Takes precedence over includeFiles", - - "type": "array", - "uniqueItems": true, - "items": { - "type": "string" - } - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/tasks/jest.schema.json b/core-build/gulp-core-build/src/tasks/jest.schema.json deleted file mode 100644 index 895d15791bb..00000000000 --- a/core-build/gulp-core-build/src/tasks/jest.schema.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "title": "Jest Task configuration", - "description": "Defines Jest task configuration. Same definitions as Jest CLI has.", - - "type": "object", - "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" - }, - "isEnabled": { - "description": "Indicate whether the test is enabled", - "type": "boolean", - "default": false - }, - "cache": { - "description": "Indicate whether Jest cache is enabled or not", - "type": "boolean" - }, - "cacheDirectory": { - "description": "The directory where Jest should store its cached information", - "type": "string" - }, - "collectCoverageFrom": { - "description": "Same as Jest CLI option collectCoverageFrom", - "type": "array", - "items": { - "type": "string" - } - }, - "coverage": { - "description": "Same as Jest CLI option coverage", - "type": "boolean", - "default": true - }, - "coverageReporters": { - "description": "Same as Jest CLI option coverageReporters", - "type": "array", - "items": { - "type": "string" - } - }, - "testPathIgnorePatterns": { - "description": "Same as Jest CLI option testPathIgnorePatterns", - "type": "array", - "items": { - "type": "string" - } - }, - "moduleDirectories": { - "description": "Same as Jest CLI option moduleDirectories", - "type": "array", - "items": { - "type": "string" - } - }, - "maxWorkers": { - "description": "Same as Jest CLI option maxWorkers", - "type": "number" - }, - "testMatch": { - "description": "Same as Jest CLI option testMatch", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/test/GulpTask.test.ts b/core-build/gulp-core-build/src/test/GulpTask.test.ts deleted file mode 100644 index 71198fbad7a..00000000000 --- a/core-build/gulp-core-build/src/test/GulpTask.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { assert, expect } from 'chai'; -import Vinyl = require('vinyl'); -import * as Gulp from 'gulp'; -import { Readable } from 'stream'; -import * as path from 'path'; - -import { - serial, - parallel, - GulpTask -} from '../index'; -import { mockBuildConfig } from './mockBuildConfig'; - -interface IConfig { -} - -let testArray: string[] = []; - -class PromiseTask extends GulpTask { - public constructor() { - super('promise', {}); - } - - public executeTask(gulp: typeof Gulp): Promise { - return new Promise((resolve: () => void) => { - testArray.push(this.name); - resolve(); - }); - } -} - -class StreamTask extends GulpTask { - public constructor() { - super('stream', {}); - } - - public executeTask(gulp: typeof Gulp): any { // eslint-disable-line @typescript-eslint/no-explicit-any - const stream: Readable = new Readable({ objectMode: true }); - - // Add no opt function to make it compat with through - stream['_read'] = () => { // eslint-disable-line dot-notation - // Do Nothing - }; - - setTimeout(() => { - - const file: Vinyl = new Vinyl({ - path: 'test.js', - contents: Buffer.from('test') - }); - - stream.push(file); - - testArray.push(this.name); - - stream.emit('end'); - }, 100); - - return stream; - } -} - -class SyncTask extends GulpTask { - public constructor() { - super('sync', {}); - } - - public executeTask(gulp: typeof Gulp): void { - testArray.push(this.name); - } -} - -class SyncWithReturnTask extends GulpTask { - public constructor() { - super('sync-with-return', {}); - } - - public executeTask(gulp: typeof Gulp): void { - testArray.push(this.name); - } -} - -class CallbackTask extends GulpTask { - public constructor() { - super('schema-task', {}); - } - - public executeTask(gulp: typeof Gulp, callback: (error?: string | Error) => void): void { - testArray.push(this.name); - callback(); - } -} - -interface ISimpleConfig { - shouldDoThings: boolean; -} - -class SchemaTask extends GulpTask { - public name: string = ''; - - public constructor() { - super( - 'schema-task', - { - shouldDoThings: false - } - ); - } - - public executeTask(gulp: typeof Gulp, callback: (error?: string | Error) => void): void { - callback(); - } - - protected _getConfigFilePath(): string { - return path.join(__dirname, 'schema-task.config.json'); - } -} - -const tasks: GulpTask[] = [ -]; - -tasks.push(new PromiseTask()); -tasks.push(new StreamTask()); -tasks.push(new SyncTask()); -tasks.push(new SyncWithReturnTask()); -tasks.push(new CallbackTask()); - -describe('GulpTask', () => { - for (const task of tasks) { - it(`${task.name} serial`, (done) => { - testArray = []; - task.setConfig({ addToMe: testArray }); - serial(task).execute(mockBuildConfig).then(() => { - expect(testArray).to.deep.equal([task.name]); - done(); - }).catch(done); - }); - - it(`${task.name} parallel`, (done) => { - testArray = []; - task.setConfig({ addToMe: testArray }); - parallel(task).execute(mockBuildConfig).then(() => { - expect(testArray).to.deep.equal([task.name]); - done(); - }).catch(done); - }); - } - - it(`all tasks serial`, (done) => { - testArray = []; - for (const task of tasks) { - task.setConfig({ addToMe: testArray }); - } - serial(tasks).execute(mockBuildConfig).then(() => { - for (const task of tasks) { - expect(testArray.indexOf(task.name)).to.be.greaterThan(-1); - } - done(); - }).catch(done); - }); - - it(`all tasks parallel`, (done) => { - testArray = []; - for (const task of tasks) { - task.setConfig({ addToMe: testArray }); - } - parallel(tasks).execute(mockBuildConfig).then(() => { - for (const task of tasks) { - expect(testArray.indexOf(task.name)).to.be.greaterThan(-1); - } - done(); - }).catch(done); - }); - - it(`reads schema file if loadSchema is implemented`, (done) => { - const schemaTask: SchemaTask = new SchemaTask(); - assert.isFalse(schemaTask.taskConfig.shouldDoThings); - schemaTask.onRegister(); - assert.isTrue(schemaTask.taskConfig.shouldDoThings); - done(); - }); - - it(`throws validation error is config does not conform to schema file`, (done) => { - const schemaTask: SchemaTask = new SchemaTask(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (schemaTask as any)._getConfigFilePath = (): string => { - return path.join(__dirname, 'other-schema-task.config.json'); - }; - - assert.isFalse(schemaTask.taskConfig.shouldDoThings); - assert.throws(schemaTask.onRegister); - done(); - }); -}); diff --git a/core-build/gulp-core-build/src/test/index.test.ts b/core-build/gulp-core-build/src/test/index.test.ts deleted file mode 100644 index 1730f57933d..00000000000 --- a/core-build/gulp-core-build/src/test/index.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { expect } from 'chai'; - -import { - serial, - parallel, - getConfig, - setConfig, - IExecutable, - IBuildConfig -} from '../index'; -import { mockBuildConfig } from './mockBuildConfig'; - -// disable the exit watching -global['dontWatchExit'] = true; // eslint-disable-line dot-notation - -describe('serial', () => { - it('can run a set of tasks in serial', (done) => { - const execution: string[] = []; - const tasks: IExecutable[] = createTasks('task', 3, command => execution.push(command)); - - serial(tasks).execute(mockBuildConfig).then(() => { - expect(execution).to.deep.equal([ - 'executing task 0', - 'complete task 0', - 'executing task 1', - 'complete task 1', - 'executing task 2', - 'complete task 2' - ]); - done(); - }).catch(error => done(error)); - }); - -}); - -describe('parallel', () => { - it('can run a set of tasks in parallel', (done) => { - const execution: string[] = []; - const tasks: IExecutable[] = createTasks('task', 3, command => execution.push(command)); - - parallel(tasks).execute(mockBuildConfig).then(() => { - expect(execution).to.deep.equal([ - 'executing task 0', - 'executing task 1', - 'executing task 2', - 'complete task 0', - 'complete task 1', - 'complete task 2' - ]); - done(); - }).catch(error => done(error)); - }); - - it('can mix in serial sets of tasks', (done) => { - const execution: string[] = []; - const serial1Tasks: IExecutable = serial(createTasks('serial set 1 -', 2, command => execution.push(command))); - const parallelTasks: IExecutable = parallel(createTasks('parallel', 2, command => execution.push(command))); - const serial2Tasks: IExecutable = serial(createTasks('serial set 2 -', 2, command => execution.push(command))); - - serial([ - serial1Tasks, - parallelTasks, - serial2Tasks - ]).execute(mockBuildConfig) - .then(() => { - expect(execution).to.deep.equal([ - 'executing serial set 1 - 0', - 'complete serial set 1 - 0', - 'executing serial set 1 - 1', - 'complete serial set 1 - 1', - 'executing parallel 0', - 'executing parallel 1', - 'complete parallel 0', - 'complete parallel 1', - 'executing serial set 2 - 0', - 'complete serial set 2 - 0', - 'executing serial set 2 - 1', - 'complete serial set 2 - 1' - ]); - done(); - }) - .catch(error => done(error)); - }); - - it('stops running serial tasks on failure', (done) => { - const execution: string[] = []; - const tasks: IExecutable[] = createTasks('task', 1, command => execution.push(command)); - - tasks.push(createTask('fail task', command => execution.push(command), true)); - tasks.push(createTask('should not run task', command => execution.push(command), false)); - - serial(tasks).execute(mockBuildConfig).then( - () => { - done('The task returned success unexpectedly.'); - }).catch((error) => { - expect(error).to.equal('Failure', 'Make sure the proper error is propagate'); - expect(execution).to.deep.equal([ - 'executing task 0', - 'complete task 0', - 'executing fail task', - 'complete fail task' - ]); - done(); - }); - - }); - - it('can read the current config', (done) => { - const config: IBuildConfig = getConfig(); - // eslint-disable-next-line - expect(config).not.to.be.null; - done(); - }); - - it('can set the config', (done) => { - const distFolder: string = 'testFolder'; - const newConfig: Partial = { - distFolder: distFolder - }; - - setConfig(newConfig); - expect(getConfig().distFolder).to.eq(distFolder); - done(); - }); -}); - -function createTasks( - name: string, - count: number, - executionCallback: (message: string) => void): IExecutable[] { - return Array.apply(undefined, Array(count)) - .map((item, index) => createTask(name + ' ' + index, executionCallback)); -} - -function createTask( - name: string, - executionCallback: (message: string) => void, - shouldFail?: boolean): IExecutable { - return { - execute: (buildConfig): Promise => new Promise((resolve, reject) => { - executionCallback(`executing ${name}`); - - setTimeout(() => { - executionCallback(`complete ${name}`); - - if (shouldFail) { - reject('Failure'); - } else { - resolve(); - } - }, 10); - }) - }; -} diff --git a/core-build/gulp-core-build/src/test/mockBuildConfig.ts b/core-build/gulp-core-build/src/test/mockBuildConfig.ts deleted file mode 100644 index 71563f935da..00000000000 --- a/core-build/gulp-core-build/src/test/mockBuildConfig.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as gulp from 'gulp'; - -import { IBuildConfig } from './../IBuildConfig'; - -export const mockBuildConfig: IBuildConfig = { - maxBuildTimeMs: 5 * 1000, - gulp, - rootPath: '', - packageFolder: '', - srcFolder: 'src', - libFolder: 'lib', - distFolder: 'dist', - tempFolder: 'temp', - verbose: false, - production: false, - args: {}, - shouldWarningsFailBuild: false -}; diff --git a/core-build/gulp-core-build/src/test/other-schema-task.config.json b/core-build/gulp-core-build/src/test/other-schema-task.config.json deleted file mode 100644 index b5dbcabaaf8..00000000000 --- a/core-build/gulp-core-build/src/test/other-schema-task.config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "A simple sample schema", - - "type": "object", - "required": ["shouldDoOtherThings"], - "additionalProperties": false, - "properties": { - "shouldDoOtherThings": { - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/test/schema-task.config.json b/core-build/gulp-core-build/src/test/schema-task.config.json deleted file mode 100644 index ba382d6def6..00000000000 --- a/core-build/gulp-core-build/src/test/schema-task.config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "shouldDoThings": true -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/test/schema-task.schema.json b/core-build/gulp-core-build/src/test/schema-task.schema.json deleted file mode 100644 index 449441f1f72..00000000000 --- a/core-build/gulp-core-build/src/test/schema-task.schema.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "A simple sample schema", - - "type": "object", - "required": ["shouldDoThings"], - "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" - }, - "shouldDoThings": { - "type": "boolean" - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/utilities/FileDeletionUtility.ts b/core-build/gulp-core-build/src/utilities/FileDeletionUtility.ts deleted file mode 100644 index d65f67d5bdf..00000000000 --- a/core-build/gulp-core-build/src/utilities/FileDeletionUtility.ts +++ /dev/null @@ -1,82 +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 globEscape = require('glob-escape'); -import globby = require('globby'); - -// eslint-disable-next-line -const del = require('del'); - -export class FileDeletionUtility { - public static deletePatterns(patterns: string[]): void { - const files: string[] = globby.sync(patterns); - this.deleteFiles(files); - } - - public static deleteFiles(files: string[]): void { - del.sync(this.escapeFilePaths(this.removeChildren(files))); - } - - public static escapeFilePaths(files: string[]): string[] { - return files.map((file: string) => { - return globEscape(file); - }); - } - - public static removeChildren(filenames: string[]): string[] { - // Appears to be a known issue with `del` whereby - // if you ask to delete both a folder, and something in the folder, - // it randomly chooses which one to delete first, which can cause - // the function to fail sporadically. The fix for this is simple: - // we need to remove any cleanPaths which exist under a folder we - // are attempting to delete - - // First we sort the list of files. We know that if something is a file, - // if matched, the parent folder should appear earlier in the list - filenames.sort(); - - // We need to determine which paths exist under other paths, and remove them from the - // list of files to delete - const filesToDelete: string[] = []; - - // current working directory - let currentParent: string | undefined = undefined; - - for (let i: number = 0; i < filenames.length; i++) { - const curFile: string = filenames[i]; - if (this.isParentDirectory(currentParent, curFile)) { - continue; - } else { - filesToDelete.push(curFile); - currentParent = curFile; - } - } - return filesToDelete; - } - - public static isParentDirectory(directory: string | undefined, filePath: string | undefined): boolean { - if (!directory || !filePath) { - return false; - } - - const directoryParts: string[] = path.resolve(directory).split(path.sep); - const fileParts: string[] = path.resolve(filePath).split(path.sep); - - if (directoryParts[directoryParts.length - 1] === '') { - // this is to fix an issue with windows roots - directoryParts.pop(); - } - - if (directoryParts.length >= fileParts.length) { - return false; - } - - for (let i: number = 0; i < directoryParts.length; i++) { - if (directoryParts[i] !== fileParts[i]) { - return false; - } - } - return true; - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/utilities/GCBTerminalProvider.ts b/core-build/gulp-core-build/src/utilities/GCBTerminalProvider.ts deleted file mode 100644 index da69b36c586..00000000000 --- a/core-build/gulp-core-build/src/utilities/GCBTerminalProvider.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - TerminalProviderSeverity, - ConsoleTerminalProvider -} from '@rushstack/node-core-library'; - -import { GulpTask } from '../tasks/GulpTask'; - -/** - * @public - */ -export class GCBTerminalProvider extends ConsoleTerminalProvider { - private _gcbTask: GulpTask; - - public constructor(gcbTask: GulpTask) { - super({ verboseEnabled: true }); - - this._gcbTask = gcbTask; - } - - public write(data: string, severity: TerminalProviderSeverity): void { - data = data.replace(/\r?\n$/, ''); // Trim trailing newlines because the GCB log functions include a newline - - switch (severity) { - case TerminalProviderSeverity.warning: { - this._gcbTask.logWarning(data); - break; - } - - case TerminalProviderSeverity.error: { - this._gcbTask.logError(data); - break; - } - - case TerminalProviderSeverity.verbose: { - this._gcbTask.logVerbose(data); - break; - } - - case TerminalProviderSeverity.log: - default: { - this._gcbTask.log(data); - break; - } - } - } -} \ No newline at end of file diff --git a/core-build/gulp-core-build/src/utilities/test/FileDeletionUtility.test.ts b/core-build/gulp-core-build/src/utilities/test/FileDeletionUtility.test.ts deleted file mode 100644 index 1a600614a42..00000000000 --- a/core-build/gulp-core-build/src/utilities/test/FileDeletionUtility.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { assert } from 'chai'; -import { FileDeletionUtility } from './../FileDeletionUtility'; - -describe('FileDeletionUtility', () => { - describe('constructor', () => { - it('can be constructed', () => { - const test: FileDeletionUtility = new FileDeletionUtility(); - assert.isNotNull(test); - }); - }); - describe('isParentDirectory', () => { - it('can detect an immediate child', () => { - assert.isTrue( - FileDeletionUtility.isParentDirectory('/a', '/a/b.txt') - ); - }); - it('can detect a deep child', () => { - assert.isTrue( - FileDeletionUtility.isParentDirectory('/a', '/a/b/c/d.txt') - ); - }); - it('can detect if base path is longer', () => { - assert.isTrue( - FileDeletionUtility.isParentDirectory('/a/b/c/d', '/a/b/c/d/g.txt') - ); - }); - it('can detect siblings', () => { - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b', '/a/c') - ); - }); - it('can detect siblings with file extensions', () => { - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b/c.txt', '/a/b/d.txt') - ); - }); - it('can detect when not a parent', () => { - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b/c', '/a') - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b/c', '/a/b.txt') - ); - }); - it('accepts anything under the root', () => { - assert.isTrue( - FileDeletionUtility.isParentDirectory('/', '/a.txt') - ); - assert.isTrue( - FileDeletionUtility.isParentDirectory('/', '/a/b/c/d.txt') - ); - }); - it('it is case sensitive', () => { - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a', '/A/b.txt') - ); - assert.isTrue( - FileDeletionUtility.isParentDirectory('/a', '/a/b.txt') - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/B/c', '/a/b/c/d.txt') - ); - }); - it('it does not accept null or undefined', () => { - /* eslint-disable @rushstack/no-null */ - assert.isFalse( - FileDeletionUtility.isParentDirectory('', '/A/b.txt') - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory(undefined, '/a/b.txt') - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory(null as any, '/a/b/c/d.txt') // eslint-disable-line @typescript-eslint/no-explicit-any - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory('/A/b.txt', '') - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b.txt', undefined) - ); - assert.isFalse( - FileDeletionUtility.isParentDirectory('/a/b/c/d.txt', null as any) // eslint-disable-line @typescript-eslint/no-explicit-any - ); - /* eslint-enable @rushstack/no-null */ - }); - }); - describe('removeChildren', () => { - it('removes children of a parent', () => { - const files: string[] = [ - '/a', - '/a/b', - '/a/b/c.txt', - '/a/b/d.txt', - '/a/z', - '/b/f/g', - '/b/f/ggg', - '/b/f/ggg/foo.txt', - '/c', - '/c/a.txt', - '/c/f/g/h/j/k/l/q', - '/d' - ]; - const expected: string[] = [ - '/a', - '/b/f/g', - '/b/f/ggg', - '/c', - '/d' - ]; - const actual: string[] = FileDeletionUtility.removeChildren(files); - - assert.equal(actual.length, expected.length); - assert.includeMembers(expected, actual); - }); - it('removes everything under the root', () => { - const files: string[] = [ - '/', - '/a/b', - '/a/b/c.txt', - '/a/b/d.txt', - '/a/z', - '/b/f/g', - '/b/f/ggg', - '/b/f/ggg/foo.txt', - '/c', - '/c/a.txt', - '/c/f/g/h/j/k/l/q', - '/d' - ]; - const expected: string[] = [ - '/' - ]; - const actual: string[] = FileDeletionUtility.removeChildren(files); - - assert.equal(actual.length, expected.length); - assert.includeMembers(expected, actual); - }); - }); -}); \ No newline at end of file diff --git a/core-build/gulp-core-build/tsconfig.json b/core-build/gulp-core-build/tsconfig.json deleted file mode 100644 index 66a4556945e..00000000000 --- a/core-build/gulp-core-build/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "mocha" - ] - } -} diff --git a/core-build/gulp-core-build/typings-custom/glob-escape/index.d.ts b/core-build/gulp-core-build/typings-custom/glob-escape/index.d.ts deleted file mode 100644 index a1c89033510..00000000000 --- a/core-build/gulp-core-build/typings-custom/glob-escape/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Type definitions for glob-escape 0.0.1 -// Definitions by: pgonzal - -declare module "glob-escape" { - - function escapeGlob(glob: string): string; - function escapeGlob(glob: string[]): string[]; - - export = escapeGlob; -} diff --git a/core-build/node-library-build/.eslintrc.js b/core-build/node-library-build/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/node-library-build/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/node-library-build/.npmignore b/core-build/node-library-build/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/node-library-build/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/node-library-build/CHANGELOG.json b/core-build/node-library-build/CHANGELOG.json deleted file mode 100644 index 9411b174c25..00000000000 --- a/core-build/node-library-build/CHANGELOG.json +++ /dev/null @@ -1,4824 +0,0 @@ -{ - "name": "@microsoft/node-library-build", - "entries": [ - { - "version": "6.4.6", - "tag": "@microsoft/node-library-build_v6.4.6", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.5` to `8.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "6.4.5", - "tag": "@microsoft/node-library-build_v6.4.5", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.4` to `8.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "6.4.4", - "tag": "@microsoft/node-library-build_v6.4.4", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.3` to `3.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.3` to `8.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "6.4.3", - "tag": "@microsoft/node-library-build_v6.4.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.2` to `8.4.3`" - } - ] - } - }, - { - "version": "6.4.2", - "tag": "@microsoft/node-library-build_v6.4.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.1` to `8.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "6.4.1", - "tag": "@microsoft/node-library-build_v6.4.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.0` to `8.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "6.4.0", - "tag": "@microsoft/node-library-build_v6.4.0", - "date": "Sun, 19 Jan 2020 02:26:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.10` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.16` to `8.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.15` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "6.3.16", - "tag": "@microsoft/node-library-build_v6.3.16", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.9` to `3.7.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.15` to `8.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "6.3.15", - "tag": "@microsoft/node-library-build_v6.3.15", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.14` to `8.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "6.3.14", - "tag": "@microsoft/node-library-build_v6.3.14", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.8` to `3.7.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.13` to `8.3.14`" - } - ] - } - }, - { - "version": "6.3.13", - "tag": "@microsoft/node-library-build_v6.3.13", - "date": "Thu, 09 Jan 2020 06:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.7` to `3.7.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.12` to `8.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "6.3.12", - "tag": "@microsoft/node-library-build_v6.3.12", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.6` to `3.7.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.11` to `8.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "6.3.11", - "tag": "@microsoft/node-library-build_v6.3.11", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.5` to `3.7.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.10` to `8.3.11`" - } - ] - } - }, - { - "version": "6.3.10", - "tag": "@microsoft/node-library-build_v6.3.10", - "date": "Tue, 03 Dec 2019 03:17:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.9` to `8.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "6.3.9", - "tag": "@microsoft/node-library-build_v6.3.9", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.8` to `8.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "6.3.8", - "tag": "@microsoft/node-library-build_v6.3.8", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.7` to `8.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "6.3.7", - "tag": "@microsoft/node-library-build_v6.3.7", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.6` to `8.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "6.3.6", - "tag": "@microsoft/node-library-build_v6.3.6", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.5` to `8.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "6.3.5", - "tag": "@microsoft/node-library-build_v6.3.5", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.4` to `8.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "6.3.4", - "tag": "@microsoft/node-library-build_v6.3.4", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.3` to `8.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "6.3.3", - "tag": "@microsoft/node-library-build_v6.3.3", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.2` to `8.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "6.3.2", - "tag": "@microsoft/node-library-build_v6.3.2", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.1` to `8.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "6.3.1", - "tag": "@microsoft/node-library-build_v6.3.1", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.0` to `8.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "6.3.0", - "tag": "@microsoft/node-library-build_v6.3.0", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for ESLint+TypeScript" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.6` to `8.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.6` to `0.3.0`" - } - ] - } - }, - { - "version": "6.2.6", - "tag": "@microsoft/node-library-build_v6.2.6", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.5` to `8.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "6.2.5", - "tag": "@microsoft/node-library-build_v6.2.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.4` to `8.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "6.2.4", - "tag": "@microsoft/node-library-build_v6.2.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.3` to `8.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "6.2.3", - "tag": "@microsoft/node-library-build_v6.2.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.2` to `8.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "6.2.2", - "tag": "@microsoft/node-library-build_v6.2.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.1` to `8.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.1` to `0.2.2`" - } - ] - } - }, - { - "version": "6.2.1", - "tag": "@microsoft/node-library-build_v6.2.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.0` to `8.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "6.2.0", - "tag": "@microsoft/node-library-build_v6.2.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.6.4` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.35` to `8.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.24` to `0.2.0`" - } - ] - } - }, - { - "version": "6.1.11", - "tag": "@microsoft/node-library-build_v6.1.11", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.34` to `8.1.35`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.23` to `0.1.24`" - } - ] - } - }, - { - "version": "6.1.10", - "tag": "@microsoft/node-library-build_v6.1.10", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.33` to `8.1.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.22` to `0.1.23`" - } - ] - } - }, - { - "version": "6.1.9", - "tag": "@microsoft/node-library-build_v6.1.9", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.32` to `8.1.33`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.21` to `0.1.22`" - } - ] - } - }, - { - "version": "6.1.8", - "tag": "@microsoft/node-library-build_v6.1.8", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.31` to `8.1.32`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.20` to `0.1.21`" - } - ] - } - }, - { - "version": "6.1.7", - "tag": "@microsoft/node-library-build_v6.1.7", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.30` to `8.1.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "6.1.6", - "tag": "@microsoft/node-library-build_v6.1.6", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.29` to `8.1.30`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "6.1.5", - "tag": "@microsoft/node-library-build_v6.1.5", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.28` to `8.1.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "6.1.4", - "tag": "@microsoft/node-library-build_v6.1.4", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.27` to `8.1.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "6.1.3", - "tag": "@microsoft/node-library-build_v6.1.3", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.26` to `8.1.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "6.1.2", - "tag": "@microsoft/node-library-build_v6.1.2", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.25` to `8.1.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "6.1.1", - "tag": "@microsoft/node-library-build_v6.1.1", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.24` to `8.1.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "6.1.0", - "tag": "@microsoft/node-library-build_v6.1.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.76` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.23` to `8.1.24`" - } - ] - } - }, - { - "version": "6.0.74", - "tag": "@microsoft/node-library-build_v6.0.74", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.22` to `8.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "6.0.73", - "tag": "@microsoft/node-library-build_v6.0.73", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.21` to `8.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "6.0.72", - "tag": "@microsoft/node-library-build_v6.0.72", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.20` to `8.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.23` to `0.3.24`" - } - ] - } - }, - { - "version": "6.0.71", - "tag": "@microsoft/node-library-build_v6.0.71", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.19` to `8.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.22` to `0.3.23`" - } - ] - } - }, - { - "version": "6.0.70", - "tag": "@microsoft/node-library-build_v6.0.70", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.18` to `8.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.21` to `0.3.22`" - } - ] - } - }, - { - "version": "6.0.69", - "tag": "@microsoft/node-library-build_v6.0.69", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.17` to `8.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.20` to `0.3.21`" - } - ] - } - }, - { - "version": "6.0.68", - "tag": "@microsoft/node-library-build_v6.0.68", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.16` to `8.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.19` to `0.3.20`" - } - ] - } - }, - { - "version": "6.0.67", - "tag": "@microsoft/node-library-build_v6.0.67", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.15` to `8.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.18` to `0.3.19`" - } - ] - } - }, - { - "version": "6.0.66", - "tag": "@microsoft/node-library-build_v6.0.66", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.14` to `8.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.17` to `0.3.18`" - } - ] - } - }, - { - "version": "6.0.65", - "tag": "@microsoft/node-library-build_v6.0.65", - "date": "Thu, 06 Jun 2019 22:33:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.16` to `0.3.17`" - } - ] - } - }, - { - "version": "6.0.64", - "tag": "@microsoft/node-library-build_v6.0.64", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.13` to `8.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.15` to `0.3.16`" - } - ] - } - }, - { - "version": "6.0.63", - "tag": "@microsoft/node-library-build_v6.0.63", - "date": "Tue, 04 Jun 2019 05:51:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.12` to `8.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.14` to `0.3.15`" - } - ] - } - }, - { - "version": "6.0.62", - "tag": "@microsoft/node-library-build_v6.0.62", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.11` to `8.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "6.0.61", - "tag": "@microsoft/node-library-build_v6.0.61", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.10` to `8.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.12` to `0.3.13`" - } - ] - } - }, - { - "version": "6.0.60", - "tag": "@microsoft/node-library-build_v6.0.60", - "date": "Mon, 06 May 2019 20:46:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.9` to `8.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.11` to `0.3.12`" - } - ] - } - }, - { - "version": "6.0.59", - "tag": "@microsoft/node-library-build_v6.0.59", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.8` to `8.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.10` to `0.3.11`" - } - ] - } - }, - { - "version": "6.0.58", - "tag": "@microsoft/node-library-build_v6.0.58", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.7` to `8.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "6.0.57", - "tag": "@microsoft/node-library-build_v6.0.57", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.6` to `8.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "6.0.56", - "tag": "@microsoft/node-library-build_v6.0.56", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.5` to `8.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "6.0.55", - "tag": "@microsoft/node-library-build_v6.0.55", - "date": "Fri, 12 Apr 2019 06:13:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.4` to `8.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "6.0.54", - "tag": "@microsoft/node-library-build_v6.0.54", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.3` to `8.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.5` to `0.3.6`" - } - ] - } - }, - { - "version": "6.0.53", - "tag": "@microsoft/node-library-build_v6.0.53", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.2` to `8.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "6.0.52", - "tag": "@microsoft/node-library-build_v6.0.52", - "date": "Mon, 08 Apr 2019 19:12:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.1` to `8.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "6.0.51", - "tag": "@microsoft/node-library-build_v6.0.51", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.0` to `8.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "6.0.50", - "tag": "@microsoft/node-library-build_v6.0.50", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.23` to `8.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "6.0.49", - "tag": "@microsoft/node-library-build_v6.0.49", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.75` to `3.5.76`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.22` to `8.0.23`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "6.0.48", - "tag": "@microsoft/node-library-build_v6.0.48", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.74` to `3.5.75`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.21` to `8.0.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - } - ] - } - }, - { - "version": "6.0.47", - "tag": "@microsoft/node-library-build_v6.0.47", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.73` to `3.5.74`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.20` to `8.0.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - } - ] - } - }, - { - "version": "6.0.46", - "tag": "@microsoft/node-library-build_v6.0.46", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.72` to `3.5.73`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.19` to `8.0.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - } - ] - } - }, - { - "version": "6.0.45", - "tag": "@microsoft/node-library-build_v6.0.45", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.71` to `3.5.72`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.18` to `8.0.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - } - ] - } - }, - { - "version": "6.0.44", - "tag": "@microsoft/node-library-build_v6.0.44", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.70` to `3.5.71`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.17` to `8.0.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - } - ] - } - }, - { - "version": "6.0.43", - "tag": "@microsoft/node-library-build_v6.0.43", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.69` to `3.5.70`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.16` to `8.0.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - } - ] - } - }, - { - "version": "6.0.42", - "tag": "@microsoft/node-library-build_v6.0.42", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.68` to `3.5.69`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.15` to `8.0.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - } - ] - } - }, - { - "version": "6.0.41", - "tag": "@microsoft/node-library-build_v6.0.41", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.67` to `3.5.68`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.14` to `8.0.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - } - ] - } - }, - { - "version": "6.0.40", - "tag": "@microsoft/node-library-build_v6.0.40", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.66` to `3.5.67`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.13` to `8.0.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - } - ] - } - }, - { - "version": "6.0.39", - "tag": "@microsoft/node-library-build_v6.0.39", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.65` to `3.5.66`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.12` to `8.0.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - } - ] - } - }, - { - "version": "6.0.38", - "tag": "@microsoft/node-library-build_v6.0.38", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.64` to `3.5.65`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.11` to `8.0.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - } - ] - } - }, - { - "version": "6.0.37", - "tag": "@microsoft/node-library-build_v6.0.37", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.63` to `3.5.64`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.10` to `8.0.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - } - ] - } - }, - { - "version": "6.0.36", - "tag": "@microsoft/node-library-build_v6.0.36", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.62` to `3.5.63`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.9` to `8.0.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - } - ] - } - }, - { - "version": "6.0.35", - "tag": "@microsoft/node-library-build_v6.0.35", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.61` to `3.5.62`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.8` to `8.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - } - ] - } - }, - { - "version": "6.0.34", - "tag": "@microsoft/node-library-build_v6.0.34", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.60` to `3.5.61`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.7` to `8.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - } - ] - } - }, - { - "version": "6.0.33", - "tag": "@microsoft/node-library-build_v6.0.33", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.59` to `3.5.60`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.6` to `8.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "6.0.32", - "tag": "@microsoft/node-library-build_v6.0.32", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.58` to `3.5.59`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.5` to `8.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "6.0.31", - "tag": "@microsoft/node-library-build_v6.0.31", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.57` to `3.5.58`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.4` to `8.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "6.0.30", - "tag": "@microsoft/node-library-build_v6.0.30", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.56` to `3.5.57`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.3` to `8.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "6.0.29", - "tag": "@microsoft/node-library-build_v6.0.29", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.55` to `3.5.56`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.2` to `8.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "6.0.28", - "tag": "@microsoft/node-library-build_v6.0.28", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.54` to `3.5.55`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.1` to `8.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "6.0.27", - "tag": "@microsoft/node-library-build_v6.0.27", - "date": "Wed, 30 Jan 2019 20:49:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.53` to `3.5.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.0` to `8.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - } - ] - } - }, - { - "version": "6.0.26", - "tag": "@microsoft/node-library-build_v6.0.26", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.52` to `3.5.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.8` to `8.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - } - ] - } - }, - { - "version": "6.0.25", - "tag": "@microsoft/node-library-build_v6.0.25", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.51` to `3.5.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.7` to `7.4.8`" - } - ] - } - }, - { - "version": "6.0.24", - "tag": "@microsoft/node-library-build_v6.0.24", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.50` to `3.5.51`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.6` to `7.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "6.0.23", - "tag": "@microsoft/node-library-build_v6.0.23", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.49` to `3.5.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.5` to `7.4.6`" - } - ] - } - }, - { - "version": "6.0.22", - "tag": "@microsoft/node-library-build_v6.0.22", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.48` to `3.5.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.4` to `7.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "6.0.21", - "tag": "@microsoft/node-library-build_v6.0.21", - "date": "Thu, 13 Dec 2018 02:58:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.47` to `3.5.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.3` to `7.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "6.0.20", - "tag": "@microsoft/node-library-build_v6.0.20", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.46` to `3.5.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.2` to `7.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "6.0.19", - "tag": "@microsoft/node-library-build_v6.0.19", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.45` to `3.5.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.1` to `7.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - } - ] - } - }, - { - "version": "6.0.18", - "tag": "@microsoft/node-library-build_v6.0.18", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.44` to `3.5.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.0` to `7.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "6.0.17", - "tag": "@microsoft/node-library-build_v6.0.17", - "date": "Fri, 30 Nov 2018 23:34:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.43` to `3.5.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.3.1` to `7.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - } - ] - } - }, - { - "version": "6.0.16", - "tag": "@microsoft/node-library-build_v6.0.16", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.42` to `3.5.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.3.0` to `7.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "6.0.15", - "tag": "@microsoft/node-library-build_v6.0.15", - "date": "Thu, 29 Nov 2018 00:35:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.41` to `3.5.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.7` to `7.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - } - ] - } - }, - { - "version": "6.0.14", - "tag": "@microsoft/node-library-build_v6.0.14", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.40` to `3.5.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.6` to `7.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - } - ] - } - }, - { - "version": "6.0.13", - "tag": "@microsoft/node-library-build_v6.0.13", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.39` to `3.5.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.5` to `7.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "6.0.12", - "tag": "@microsoft/node-library-build_v6.0.12", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.38` to `3.5.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.4` to `7.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "6.0.11", - "tag": "@microsoft/node-library-build_v6.0.11", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.37` to `3.5.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.3` to `7.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "6.0.10", - "tag": "@microsoft/node-library-build_v6.0.10", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.36` to `3.5.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.2` to `7.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "6.0.9", - "tag": "@microsoft/node-library-build_v6.0.9", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.35` to `3.5.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.1` to `7.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "6.0.8", - "tag": "@microsoft/node-library-build_v6.0.8", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.34` to `3.5.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.0` to `7.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - } - ] - } - }, - { - "version": "6.0.7", - "tag": "@microsoft/node-library-build_v6.0.7", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.33` to `3.5.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.2` to `7.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "6.0.6", - "tag": "@microsoft/node-library-build_v6.0.6", - "date": "Thu, 01 Nov 2018 21:33:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.32` to `3.5.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.1` to `7.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "6.0.5", - "tag": "@microsoft/node-library-build_v6.0.5", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.31` to `3.5.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.0` to `7.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "6.0.4", - "tag": "@microsoft/node-library-build_v6.0.4", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.3` to `7.1.0`" - } - ] - } - }, - { - "version": "6.0.3", - "tag": "@microsoft/node-library-build_v6.0.3", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.30` to `3.5.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.2` to `7.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "6.0.2", - "tag": "@microsoft/node-library-build_v6.0.2", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.29` to `3.5.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.1` to `7.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - } - ] - } - }, - { - "version": "6.0.1", - "tag": "@microsoft/node-library-build_v6.0.1", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.28` to `3.5.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.0` to `7.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - } - ] - } - }, - { - "version": "6.0.0", - "tag": "@microsoft/node-library-build_v6.0.0", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "major": [ - { - "comment": "Upgrading tasks to use rush-stack-compiler." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.27` to `3.5.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.12` to `7.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - } - ] - } - }, - { - "version": "5.0.26", - "tag": "@microsoft/node-library-build_v5.0.26", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.26` to `3.5.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.11` to `6.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "5.0.25", - "tag": "@microsoft/node-library-build_v5.0.25", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.25` to `3.5.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.10` to `6.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "5.0.24", - "tag": "@microsoft/node-library-build_v5.0.24", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.24` to `3.5.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.9` to `6.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "5.0.23", - "tag": "@microsoft/node-library-build_v5.0.23", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.23` to `3.5.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.8` to `6.1.9`" - } - ] - } - }, - { - "version": "5.0.22", - "tag": "@microsoft/node-library-build_v5.0.22", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.22` to `3.5.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.7` to `6.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "5.0.21", - "tag": "@microsoft/node-library-build_v5.0.21", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.21` to `3.5.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.6` to `6.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "5.0.20", - "tag": "@microsoft/node-library-build_v5.0.20", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.20` to `3.5.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.5` to `6.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "5.0.19", - "tag": "@microsoft/node-library-build_v5.0.19", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.19` to `3.5.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.4` to `6.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "5.0.18", - "tag": "@microsoft/node-library-build_v5.0.18", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.18` to `3.5.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.3` to `6.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "5.0.17", - "tag": "@microsoft/node-library-build_v5.0.17", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.17` to `3.5.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.2` to `6.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "5.0.16", - "tag": "@microsoft/node-library-build_v5.0.16", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.16` to `3.5.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.1` to `6.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - } - ] - } - }, - { - "version": "5.0.15", - "tag": "@microsoft/node-library-build_v5.0.15", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.15` to `3.5.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.0` to `6.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - } - ] - } - }, - { - "version": "5.0.14", - "tag": "@microsoft/node-library-build_v5.0.14", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.14` to `3.5.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.5` to `6.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - } - ] - } - }, - { - "version": "5.0.13", - "tag": "@microsoft/node-library-build_v5.0.13", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.13` to `3.5.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.4` to `6.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - } - ] - } - }, - { - "version": "5.0.12", - "tag": "@microsoft/node-library-build_v5.0.12", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.3` to `6.0.4`" - } - ] - } - }, - { - "version": "5.0.11", - "tag": "@microsoft/node-library-build_v5.0.11", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.12` to `3.5.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.2` to `6.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - } - ] - } - }, - { - "version": "5.0.10", - "tag": "@microsoft/node-library-build_v5.0.10", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.11` to `3.5.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.1` to `6.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - } - ] - } - }, - { - "version": "5.0.9", - "tag": "@microsoft/node-library-build_v5.0.9", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.10` to `3.5.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.0` to `6.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - } - ] - } - }, - { - "version": "5.0.8", - "tag": "@microsoft/node-library-build_v5.0.8", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.2` to `6.0.0`" - } - ] - } - }, - { - "version": "5.0.7", - "tag": "@microsoft/node-library-build_v5.0.7", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.9` to `3.5.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.1` to `5.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "5.0.6", - "tag": "@microsoft/node-library-build_v5.0.6", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.8` to `3.5.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.0` to `5.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "5.0.5", - "tag": "@microsoft/node-library-build_v5.0.5", - "date": "Mon, 03 Sep 2018 16:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.7` to `3.5.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.12` to `5.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "5.0.4", - "tag": "@microsoft/node-library-build_v5.0.4", - "date": "Thu, 30 Aug 2018 22:47:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.11` to `4.11.12`" - } - ] - } - }, - { - "version": "5.0.3", - "tag": "@microsoft/node-library-build_v5.0.3", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.6` to `3.5.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.10` to `4.11.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "5.0.2", - "tag": "@microsoft/node-library-build_v5.0.2", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.5` to `3.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.9` to `4.11.10`" - } - ] - } - }, - { - "version": "5.0.1", - "tag": "@microsoft/node-library-build_v5.0.1", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.4` to `3.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.8` to `4.11.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "5.0.0", - "tag": "@microsoft/node-library-build_v5.0.0", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "major": [ - { - "comment": "Updating the way typescript and tslint are invoked." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.3` to `3.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.7` to `4.11.8`" - } - ] - } - }, - { - "version": "4.4.11", - "tag": "@microsoft/node-library-build_v4.4.11", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.6` to `4.11.7`" - } - ] - } - }, - { - "version": "4.4.10", - "tag": "@microsoft/node-library-build_v4.4.10", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.5` to `4.11.6`" - } - ] - } - }, - { - "version": "4.4.9", - "tag": "@microsoft/node-library-build_v4.4.9", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.4` to `4.11.5`" - } - ] - } - }, - { - "version": "4.4.8", - "tag": "@microsoft/node-library-build_v4.4.8", - "date": "Tue, 21 Aug 2018 16:04:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.3` to `4.11.4`" - } - ] - } - }, - { - "version": "4.4.7", - "tag": "@microsoft/node-library-build_v4.4.7", - "date": "Thu, 09 Aug 2018 21:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.4.3` to `3.5.0`" - } - ] - } - }, - { - "version": "4.4.6", - "tag": "@microsoft/node-library-build_v4.4.6", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.2` to `4.11.3`" - } - ] - } - }, - { - "version": "4.4.5", - "tag": "@microsoft/node-library-build_v4.4.5", - "date": "Thu, 09 Aug 2018 16:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.1` to `4.11.2`" - } - ] - } - }, - { - "version": "4.4.4", - "tag": "@microsoft/node-library-build_v4.4.4", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.0` to `4.11.1`" - } - ] - } - }, - { - "version": "4.4.3", - "tag": "@microsoft/node-library-build_v4.4.3", - "date": "Thu, 26 Jul 2018 23:53:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.5` to `4.11.0`" - } - ] - } - }, - { - "version": "4.4.2", - "tag": "@microsoft/node-library-build_v4.4.2", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.4` to `4.10.5`" - } - ] - } - }, - { - "version": "4.4.1", - "tag": "@microsoft/node-library-build_v4.4.1", - "date": "Wed, 25 Jul 2018 21:02:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.3` to `4.10.4`" - } - ] - } - }, - { - "version": "4.4.0", - "tag": "@microsoft/node-library-build_v4.4.0", - "date": "Fri, 20 Jul 2018 16:04:52 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrading mocha-related pack ages to remove dependency on a version of \"growl\" with NSP warnings." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.31` to `3.4.0`" - } - ] - } - }, - { - "version": "4.3.50", - "tag": "@microsoft/node-library-build_v4.3.50", - "date": "Tue, 17 Jul 2018 16:02:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.2` to `4.10.3`" - } - ] - } - }, - { - "version": "4.3.49", - "tag": "@microsoft/node-library-build_v4.3.49", - "date": "Fri, 13 Jul 2018 19:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.1` to `4.10.2`" - } - ] - } - }, - { - "version": "4.3.48", - "tag": "@microsoft/node-library-build_v4.3.48", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.30` to `3.3.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.0` to `4.10.1`" - } - ] - } - }, - { - "version": "4.3.47", - "tag": "@microsoft/node-library-build_v4.3.47", - "date": "Fri, 29 Jun 2018 02:56:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.19` to `4.10.0`" - } - ] - } - }, - { - "version": "4.3.46", - "tag": "@microsoft/node-library-build_v4.3.46", - "date": "Sat, 23 Jun 2018 02:21:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.18` to `4.9.19`" - } - ] - } - }, - { - "version": "4.3.45", - "tag": "@microsoft/node-library-build_v4.3.45", - "date": "Fri, 22 Jun 2018 16:05:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.17` to `4.9.18`" - } - ] - } - }, - { - "version": "4.3.44", - "tag": "@microsoft/node-library-build_v4.3.44", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.29` to `3.3.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.16` to `4.9.17`" - } - ] - } - }, - { - "version": "4.3.43", - "tag": "@microsoft/node-library-build_v4.3.43", - "date": "Tue, 19 Jun 2018 19:35:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.15` to `4.9.16`" - } - ] - } - }, - { - "version": "4.3.42", - "tag": "@microsoft/node-library-build_v4.3.42", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.28` to `3.3.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.14` to `4.9.15`" - } - ] - } - }, - { - "version": "4.3.41", - "tag": "@microsoft/node-library-build_v4.3.41", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.27` to `3.3.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.13` to `4.9.14`" - } - ] - } - }, - { - "version": "4.3.40", - "tag": "@microsoft/node-library-build_v4.3.40", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.26` to `3.3.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.12` to `4.9.13`" - } - ] - } - }, - { - "version": "4.3.39", - "tag": "@microsoft/node-library-build_v4.3.39", - "date": "Tue, 15 May 2018 00:18:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.11` to `4.9.12`" - } - ] - } - }, - { - "version": "4.3.38", - "tag": "@microsoft/node-library-build_v4.3.38", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.25` to `3.3.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.10` to `4.9.11`" - } - ] - } - }, - { - "version": "4.3.37", - "tag": "@microsoft/node-library-build_v4.3.37", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.24` to `3.3.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.9` to `4.9.10`" - } - ] - } - }, - { - "version": "4.3.36", - "tag": "@microsoft/node-library-build_v4.3.36", - "date": "Tue, 01 May 2018 22:03:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.8` to `4.9.9`" - } - ] - } - }, - { - "version": "4.3.35", - "tag": "@microsoft/node-library-build_v4.3.35", - "date": "Fri, 27 Apr 2018 03:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.7` to `4.9.8`" - } - ] - } - }, - { - "version": "4.3.34", - "tag": "@microsoft/node-library-build_v4.3.34", - "date": "Fri, 20 Apr 2018 16:06:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.6` to `4.9.7`" - } - ] - } - }, - { - "version": "4.3.33", - "tag": "@microsoft/node-library-build_v4.3.33", - "date": "Thu, 19 Apr 2018 21:25:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.5` to `4.9.6`" - } - ] - } - }, - { - "version": "4.3.32", - "tag": "@microsoft/node-library-build_v4.3.32", - "date": "Thu, 19 Apr 2018 17:02:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.4` to `4.9.5`" - } - ] - } - }, - { - "version": "4.3.31", - "tag": "@microsoft/node-library-build_v4.3.31", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.23` to `3.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.3` to `4.9.4`" - } - ] - } - }, - { - "version": "4.3.30", - "tag": "@microsoft/node-library-build_v4.3.30", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.22` to `3.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.2` to `4.9.3`" - } - ] - } - }, - { - "version": "4.3.29", - "tag": "@microsoft/node-library-build_v4.3.29", - "date": "Tue, 27 Mar 2018 01:34:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.1` to `4.9.2`" - } - ] - } - }, - { - "version": "4.3.28", - "tag": "@microsoft/node-library-build_v4.3.28", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.21` to `3.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.0` to `4.9.1`" - } - ] - } - }, - { - "version": "4.3.27", - "tag": "@microsoft/node-library-build_v4.3.27", - "date": "Sun, 25 Mar 2018 01:26:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.8.1` to `4.9.0`" - } - ] - } - }, - { - "version": "4.3.26", - "tag": "@microsoft/node-library-build_v4.3.26", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.20` to `3.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.8.0` to `4.8.1`" - } - ] - } - }, - { - "version": "4.3.25", - "tag": "@microsoft/node-library-build_v4.3.25", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.19` to `3.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.22` to `4.8.0`" - } - ] - } - }, - { - "version": "4.3.24", - "tag": "@microsoft/node-library-build_v4.3.24", - "date": "Tue, 20 Mar 2018 02:44:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.21` to `4.7.22`" - } - ] - } - }, - { - "version": "4.3.23", - "tag": "@microsoft/node-library-build_v4.3.23", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.18` to `3.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.20` to `4.7.21`" - } - ] - } - }, - { - "version": "4.3.22", - "tag": "@microsoft/node-library-build_v4.3.22", - "date": "Thu, 15 Mar 2018 20:00:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.19` to `4.7.20`" - } - ] - } - }, - { - "version": "4.3.21", - "tag": "@microsoft/node-library-build_v4.3.21", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.17` to `3.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.18` to `4.7.19`" - } - ] - } - }, - { - "version": "4.3.20", - "tag": "@microsoft/node-library-build_v4.3.20", - "date": "Tue, 13 Mar 2018 23:11:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.17` to `4.7.18`" - } - ] - } - }, - { - "version": "4.3.19", - "tag": "@microsoft/node-library-build_v4.3.19", - "date": "Mon, 12 Mar 2018 20:36:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.16` to `4.7.17`" - } - ] - } - }, - { - "version": "4.3.18", - "tag": "@microsoft/node-library-build_v4.3.18", - "date": "Tue, 06 Mar 2018 17:04:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.15` to `4.7.16`" - } - ] - } - }, - { - "version": "4.3.17", - "tag": "@microsoft/node-library-build_v4.3.17", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.16` to `3.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.14` to `4.7.15`" - } - ] - } - }, - { - "version": "4.3.16", - "tag": "@microsoft/node-library-build_v4.3.16", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.15` to `3.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.13` to `4.7.14`" - } - ] - } - }, - { - "version": "4.3.15", - "tag": "@microsoft/node-library-build_v4.3.15", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.14` to `3.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.12` to `4.7.13`" - } - ] - } - }, - { - "version": "4.3.14", - "tag": "@microsoft/node-library-build_v4.3.14", - "date": "Wed, 21 Feb 2018 03:13:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.13` to `3.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.11` to `4.7.12`" - } - ] - } - }, - { - "version": "4.3.13", - "tag": "@microsoft/node-library-build_v4.3.13", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.12` to `3.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.10` to `4.7.11`" - } - ] - } - }, - { - "version": "4.3.12", - "tag": "@microsoft/node-library-build_v4.3.12", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.11` to `3.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.9` to `4.7.10`" - } - ] - } - }, - { - "version": "4.3.11", - "tag": "@microsoft/node-library-build_v4.3.11", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.10` to `3.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.8` to `4.7.9`" - } - ] - } - }, - { - "version": "4.3.10", - "tag": "@microsoft/node-library-build_v4.3.10", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.9` to `3.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.7` to `4.7.8`" - } - ] - } - }, - { - "version": "4.3.9", - "tag": "@microsoft/node-library-build_v4.3.9", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.8` to `3.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.6` to `4.7.7`" - } - ] - } - }, - { - "version": "4.3.8", - "tag": "@microsoft/node-library-build_v4.3.8", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.7` to `3.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.5` to `4.7.6`" - } - ] - } - }, - { - "version": "4.3.7", - "tag": "@microsoft/node-library-build_v4.3.7", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.6` to `3.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.4` to `4.7.5`" - } - ] - } - }, - { - "version": "4.3.6", - "tag": "@microsoft/node-library-build_v4.3.6", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.3` to `4.7.4`" - } - ] - } - }, - { - "version": "4.3.5", - "tag": "@microsoft/node-library-build_v4.3.5", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.2` to `4.7.3`" - } - ] - } - }, - { - "version": "4.3.4", - "tag": "@microsoft/node-library-build_v4.3.4", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "patch": [ - { - "comment": "Update dependency of node-library-build" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.1` to `4.7.2`" - } - ] - } - }, - { - "version": "4.3.3", - "tag": "@microsoft/node-library-build_v4.3.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.6.0` to `4.7.0`" - } - ] - } - }, - { - "version": "4.3.2", - "tag": "@microsoft/node-library-build_v4.3.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.5.1` to `4.6.0`" - } - ] - } - }, - { - "version": "4.3.1", - "tag": "@microsoft/node-library-build_v4.3.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.5.0` to `4.5.1`" - } - ] - } - }, - { - "version": "4.3.0", - "tag": "@microsoft/node-library-build_v4.3.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.17` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.4.1` to `4.5.0`" - } - ] - } - }, - { - "version": "4.2.16", - "tag": "@microsoft/node-library-build_v4.2.16", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.15` to `3.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.3` to `4.4.0`" - } - ] - } - }, - { - "version": "4.2.15", - "tag": "@microsoft/node-library-build_v4.2.15", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.14` to `3.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.2` to `4.3.3`" - } - ] - } - }, - { - "version": "4.2.14", - "tag": "@microsoft/node-library-build_v4.2.14", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.13` to `3.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.1` to `4.3.2`" - } - ] - } - }, - { - "version": "4.2.13", - "tag": "@microsoft/node-library-build_v4.2.13", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.12` to `3.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.0` to `4.3.1`" - } - ] - } - }, - { - "version": "4.2.12", - "tag": "@microsoft/node-library-build_v4.2.12", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.11` to `3.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.18` to `4.3.0`" - } - ] - } - }, - { - "version": "4.2.11", - "tag": "@microsoft/node-library-build_v4.2.11", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.10` to `3.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.17` to `4.2.18`" - } - ] - } - }, - { - "version": "4.2.10", - "tag": "@microsoft/node-library-build_v4.2.10", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.9` to `3.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.16` to `4.2.17`" - } - ] - } - }, - { - "version": "4.2.9", - "tag": "@microsoft/node-library-build_v4.2.9", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.15` to `4.2.16`" - } - ] - } - }, - { - "version": "4.2.8", - "tag": "@microsoft/node-library-build_v4.2.8", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.14` to `4.2.15`" - } - ] - } - }, - { - "version": "4.2.7", - "tag": "@microsoft/node-library-build_v4.2.7", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.13` to `4.2.14`" - } - ] - } - }, - { - "version": "4.2.6", - "tag": "@microsoft/node-library-build_v4.2.6", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.12` to `4.2.13`" - } - ] - } - }, - { - "version": "4.2.5", - "tag": "@microsoft/node-library-build_v4.2.5", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.11` to `4.2.12`" - } - ] - } - }, - { - "version": "4.2.4", - "tag": "@microsoft/node-library-build_v4.2.4", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.10` to `4.2.11`" - } - ] - } - }, - { - "version": "4.2.3", - "tag": "@microsoft/node-library-build_v4.2.3", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.9` to `4.2.10`" - } - ] - } - }, - { - "version": "4.2.2", - "tag": "@microsoft/node-library-build_v4.2.2", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.8` to `4.2.9`" - } - ] - } - }, - { - "version": "4.2.1", - "tag": "@microsoft/node-library-build_v4.2.1", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.7` to `4.2.8`" - } - ] - } - }, - { - "version": "4.2.0", - "tag": "@microsoft/node-library-build_v4.2.0", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "minor": [ - { - "author": "QZ ", - "commit": "5fe47765dbb3567bebc30cf5d7ac2205f6e655b0", - "comment": "Support Jest task" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.6` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.6` to `4.2.7`" - } - ] - } - }, - { - "version": "4.1.6", - "tag": "@microsoft/node-library-build_v4.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.5` to `3.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.5` to `4.2.6`" - } - ] - } - }, - { - "version": "4.1.5", - "tag": "@microsoft/node-library-build_v4.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.4` to `3.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.4` to `4.2.5`" - } - ] - } - }, - { - "version": "4.1.4", - "tag": "@microsoft/node-library-build_v4.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.3` to `3.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.3` to `4.2.4`" - } - ] - } - }, - { - "version": "4.1.3", - "tag": "@microsoft/node-library-build_v4.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.2` to `3.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.2` to `4.2.3`" - } - ] - } - }, - { - "version": "4.1.2", - "tag": "@microsoft/node-library-build_v4.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.1` to `3.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.1` to `4.2.2`" - } - ] - } - }, - { - "version": "4.1.1", - "tag": "@microsoft/node-library-build_v4.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.1.0` to `3.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.0` to `4.2.1`" - } - ] - } - }, - { - "version": "4.1.0", - "tag": "@microsoft/node-library-build_v4.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.1.0` to `4.2.0`" - } - ] - } - }, - { - "version": "4.0.8", - "tag": "@microsoft/node-library-build_v4.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.7` to `3.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.7` to `4.1.0`" - } - ] - } - }, - { - "version": "4.0.7", - "tag": "@microsoft/node-library-build_v4.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.6` to `3.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.6` to `4.0.7`" - } - ] - } - }, - { - "version": "4.0.6", - "tag": "@microsoft/node-library-build_v4.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "bb96549aa8508ff627a0cae5ee41ae0251f2777d", - "comment": "Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable'" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.5` to `3.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.5` to `4.0.6`" - } - ] - } - }, - { - "version": "4.0.5", - "tag": "@microsoft/node-library-build_v4.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.4` to `3.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.4` to `4.0.5`" - } - ] - } - }, - { - "version": "4.0.4", - "tag": "@microsoft/node-library-build_v4.0.4", - "date": "Thu, 07 Sep 2017 00:11:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.3` to `3.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.3` to `4.0.4`" - } - ] - } - }, - { - "version": "4.0.3", - "tag": "@microsoft/node-library-build_v4.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.2` to `3.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.2` to `4.0.3`" - } - ] - } - }, - { - "version": "4.0.2", - "tag": "@microsoft/node-library-build_v4.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.1` to `3.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.1` to `4.0.2`" - } - ] - } - }, - { - "version": "4.0.1", - "tag": "@microsoft/node-library-build_v4.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.0` to `4.0.1`" - } - ] - } - }, - { - "version": "4.0.0", - "tag": "@microsoft/node-library-build_v4.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.13` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.3` to `4.0.0`" - } - ] - } - }, - { - "version": "3.4.1", - "tag": "@microsoft/node-library-build_v3.4.1", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.12` to `2.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.2` to `3.5.3`" - } - ] - } - }, - { - "version": "3.4.0", - "tag": "@microsoft/node-library-build_v3.4.0", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "minor": [ - { - "comment": "node-library-build now supports the CopyStaticAssetsTask" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.11` to `2.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.1` to `3.5.2`" - } - ] - } - }, - { - "version": "3.3.2", - "tag": "@microsoft/node-library-build_v3.3.2", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.10` to `2.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.0` to `3.5.1`" - } - ] - } - }, - { - "version": "3.3.1", - "tag": "@microsoft/node-library-build_v3.3.1", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.9` to `2.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.4.2` to `3.5.0`" - } - ] - } - }, - { - "version": "3.3.0", - "tag": "@microsoft/node-library-build_v3.3.0", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "minor": [ - { - "comment": "node-library-build now supports pre-copy.json and post-copy.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.8` to `2.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.4.1` to `3.4.2`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/node-library-build_v3.2.8", - "date": "Wed, 16 Aug 2017 13:04:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.3.2` to `3.4.0`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/node-library-build_v3.2.7", - "date": "Tue, 15 Aug 2017 19:04:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.2` to `2.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.7` to `2.1.8`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/node-library-build_v3.2.6", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.6` to `2.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.3.1` to `3.3.2`" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/node-library-build_v3.2.5", - "date": "Sat, 12 Aug 2017 01:03:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.0` to `2.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.5` to `2.1.6`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/node-library-build_v3.2.4", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.8.0` to `2.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.4` to `2.1.5`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/node-library-build_v3.2.3", - "date": "Sat, 05 Aug 2017 01:04:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.3` to `2.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.3` to `2.1.4`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/node-library-build_v3.2.2", - "date": "Mon, 31 Jul 2017 21:18:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.2` to `2.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.2` to `2.1.3`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/node-library-build_v3.2.1", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools and restrict the dependency version requirements." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `2.1.1` to `2.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.3.0` to `3.3.1`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/node-library-build_v3.2.0", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `>=2.1.0 <3.0.0` to `>=2.1.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.2.0 <4.0.0` to `>=3.3.0 <4.0.0`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/node-library-build_v3.1.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `>=2.0.2 <3.0.0` to `>=2.1.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.1.5 <4.0.0` to `>=3.2.0 <4.0.0`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/node-library-build_v3.0.1", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `>=2.0.1 <3.0.0` to `>=2.0.2 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.0.3 <4.0.0` to `>=3.0.3 <4.0.0`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/node-library-build_v3.0.0", - "date": "Mon, 20 Mar 2017 21:52:20 GMT", - "comments": { - "major": [ - { - "comment": "Updating build task dependencies." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.2 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.4.1 <3.0.0` to `>=3.0.0 <4.0.0`" - } - ] - } - }, - { - "version": "2.3.1", - "tag": "@microsoft/node-library-build_v2.3.1", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.2.5 <3.0.0` to `>=2.2.5 <3.0.0`" - } - ] - } - }, - { - "version": "2.3.0", - "tag": "@microsoft/node-library-build_v2.3.0", - "date": "Wed, 08 Feb 2017 01:41:58 GMT", - "comments": { - "minor": [ - { - "comment": "Treat warnings as errors in production. Treat tsli nt errors as warnings." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.2.3 <3.0.0` to `>=2.3.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.2.0", - "tag": "@microsoft/node-library-build_v2.2.0", - "date": "Fri, 20 Jan 2017 01:46:41 GMT", - "comments": { - "minor": [ - { - "comment": "Run the api-extractor task during the default build." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.1.0 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/node-library-build_v2.1.0", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "minor": [ - { - "comment": "Enable the ApiExtractor task from gulp-core-build-typescript." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-mocha\" from `>=2.0.0 <3.0.0` to `>=2.0.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.1.0 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.0.0", - "tag": "@microsoft/node-library-build_v2.0.0", - "date": "Wed, 11 Jan 2017 14:11:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.0.1 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/node-library-build/CHANGELOG.md b/core-build/node-library-build/CHANGELOG.md deleted file mode 100644 index aab37b71fb4..00000000000 --- a/core-build/node-library-build/CHANGELOG.md +++ /dev/null @@ -1,1375 +0,0 @@ -# Change Log - @microsoft/node-library-build - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 6.4.6 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 6.4.5 -Tue, 17 Mar 2020 23:55:58 GMT - -*Version update only* - -## 6.4.4 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 6.4.3 -Fri, 24 Jan 2020 00:27:39 GMT - -*Version update only* - -## 6.4.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 6.4.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 6.4.0 -Sun, 19 Jan 2020 02:26:52 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 6.3.16 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 6.3.15 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 6.3.14 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 6.3.13 -Thu, 09 Jan 2020 06:44:12 GMT - -*Version update only* - -## 6.3.12 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 6.3.11 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 6.3.10 -Tue, 03 Dec 2019 03:17:43 GMT - -*Version update only* - -## 6.3.9 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 6.3.8 -Wed, 20 Nov 2019 06:14:28 GMT - -*Version update only* - -## 6.3.7 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 6.3.6 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 6.3.5 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 6.3.4 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 6.3.3 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 6.3.2 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 6.3.1 -Tue, 22 Oct 2019 06:24:44 GMT - -*Version update only* - -## 6.3.0 -Mon, 21 Oct 2019 05:22:43 GMT - -### Minor changes - -- Add support for ESLint+TypeScript - -## 6.2.6 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 6.2.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 6.2.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 6.2.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 6.2.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 6.2.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 6.2.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 6.1.11 -Fri, 20 Sep 2019 21:27:22 GMT - -*Version update only* - -## 6.1.10 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 6.1.9 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 6.1.8 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 6.1.7 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 6.1.6 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 6.1.5 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 6.1.4 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 6.1.3 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 6.1.2 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 6.1.1 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 6.1.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2 - -## 6.0.74 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 6.0.73 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 6.0.72 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 6.0.71 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 6.0.70 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 6.0.69 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 6.0.68 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 6.0.67 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 6.0.66 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 6.0.65 -Thu, 06 Jun 2019 22:33:36 GMT - -*Version update only* - -## 6.0.64 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 6.0.63 -Tue, 04 Jun 2019 05:51:53 GMT - -*Version update only* - -## 6.0.62 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 6.0.61 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 6.0.60 -Mon, 06 May 2019 20:46:21 GMT - -*Version update only* - -## 6.0.59 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 6.0.58 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 6.0.57 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 6.0.56 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 6.0.55 -Fri, 12 Apr 2019 06:13:16 GMT - -*Version update only* - -## 6.0.54 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 6.0.53 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 6.0.52 -Mon, 08 Apr 2019 19:12:52 GMT - -*Version update only* - -## 6.0.51 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 6.0.50 -Fri, 05 Apr 2019 04:16:17 GMT - -*Version update only* - -## 6.0.49 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 6.0.48 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 6.0.47 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 6.0.46 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 6.0.45 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 6.0.44 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 6.0.43 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 6.0.42 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 6.0.41 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 6.0.40 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 6.0.39 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 6.0.38 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 6.0.37 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 6.0.36 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 6.0.35 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 6.0.34 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 6.0.33 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 6.0.32 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 6.0.31 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 6.0.30 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 6.0.29 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 6.0.28 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 6.0.27 -Wed, 30 Jan 2019 20:49:11 GMT - -*Version update only* - -## 6.0.26 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 6.0.25 -Tue, 15 Jan 2019 17:04:09 GMT - -*Version update only* - -## 6.0.24 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 6.0.23 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 6.0.22 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 6.0.21 -Thu, 13 Dec 2018 02:58:11 GMT - -*Version update only* - -## 6.0.20 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 6.0.19 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 6.0.18 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 6.0.17 -Fri, 30 Nov 2018 23:34:57 GMT - -*Version update only* - -## 6.0.16 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 6.0.15 -Thu, 29 Nov 2018 00:35:39 GMT - -*Version update only* - -## 6.0.14 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 6.0.13 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 6.0.12 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 6.0.11 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 6.0.10 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 6.0.9 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 6.0.8 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 6.0.7 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 6.0.6 -Thu, 01 Nov 2018 21:33:51 GMT - -*Version update only* - -## 6.0.5 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 6.0.4 -Wed, 31 Oct 2018 21:17:50 GMT - -*Version update only* - -## 6.0.3 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 6.0.2 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 6.0.1 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 6.0.0 -Sat, 27 Oct 2018 00:26:56 GMT - -### Breaking changes - -- Upgrading tasks to use rush-stack-compiler. - -## 5.0.26 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 5.0.25 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 5.0.24 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 5.0.23 -Thu, 18 Oct 2018 05:30:14 GMT - -*Version update only* - -## 5.0.22 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 5.0.21 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 5.0.20 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 5.0.19 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 5.0.18 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 5.0.17 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 5.0.16 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 5.0.15 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 5.0.14 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 5.0.13 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 5.0.12 -Mon, 24 Sep 2018 16:04:28 GMT - -*Version update only* - -## 5.0.11 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 5.0.10 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 5.0.9 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 5.0.8 -Mon, 10 Sep 2018 23:23:01 GMT - -*Version update only* - -## 5.0.7 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 5.0.6 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 5.0.5 -Mon, 03 Sep 2018 16:04:46 GMT - -*Version update only* - -## 5.0.4 -Thu, 30 Aug 2018 22:47:34 GMT - -*Version update only* - -## 5.0.3 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 5.0.2 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 5.0.1 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 5.0.0 -Wed, 29 Aug 2018 06:36:50 GMT - -### Breaking changes - -- Updating the way typescript and tslint are invoked. - -## 4.4.11 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 4.4.10 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 4.4.9 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 4.4.8 -Tue, 21 Aug 2018 16:04:38 GMT - -*Version update only* - -## 4.4.7 -Thu, 09 Aug 2018 21:58:02 GMT - -*Version update only* - -## 4.4.6 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 4.4.5 -Thu, 09 Aug 2018 16:04:24 GMT - -*Version update only* - -## 4.4.4 -Tue, 07 Aug 2018 22:27:31 GMT - -*Version update only* - -## 4.4.3 -Thu, 26 Jul 2018 23:53:43 GMT - -*Version update only* - -## 4.4.2 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 4.4.1 -Wed, 25 Jul 2018 21:02:57 GMT - -*Version update only* - -## 4.4.0 -Fri, 20 Jul 2018 16:04:52 GMT - -### Minor changes - -- Upgrading mocha-related pack ages to remove dependency on a version of "growl" with NSP warnings. - -## 4.3.50 -Tue, 17 Jul 2018 16:02:52 GMT - -*Version update only* - -## 4.3.49 -Fri, 13 Jul 2018 19:04:50 GMT - -*Version update only* - -## 4.3.48 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 4.3.47 -Fri, 29 Jun 2018 02:56:51 GMT - -*Version update only* - -## 4.3.46 -Sat, 23 Jun 2018 02:21:20 GMT - -*Version update only* - -## 4.3.45 -Fri, 22 Jun 2018 16:05:15 GMT - -*Version update only* - -## 4.3.44 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 4.3.43 -Tue, 19 Jun 2018 19:35:11 GMT - -*Version update only* - -## 4.3.42 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 4.3.41 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 4.3.40 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 4.3.39 -Tue, 15 May 2018 00:18:10 GMT - -*Version update only* - -## 4.3.38 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 4.3.37 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 4.3.36 -Tue, 01 May 2018 22:03:20 GMT - -*Version update only* - -## 4.3.35 -Fri, 27 Apr 2018 03:04:32 GMT - -*Version update only* - -## 4.3.34 -Fri, 20 Apr 2018 16:06:11 GMT - -*Version update only* - -## 4.3.33 -Thu, 19 Apr 2018 21:25:56 GMT - -*Version update only* - -## 4.3.32 -Thu, 19 Apr 2018 17:02:06 GMT - -*Version update only* - -## 4.3.31 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 4.3.30 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 4.3.29 -Tue, 27 Mar 2018 01:34:25 GMT - -*Version update only* - -## 4.3.28 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 4.3.27 -Sun, 25 Mar 2018 01:26:19 GMT - -*Version update only* - -## 4.3.26 -Fri, 23 Mar 2018 00:34:53 GMT - -*Version update only* - -## 4.3.25 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 4.3.24 -Tue, 20 Mar 2018 02:44:45 GMT - -*Version update only* - -## 4.3.23 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 4.3.22 -Thu, 15 Mar 2018 20:00:50 GMT - -*Version update only* - -## 4.3.21 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 4.3.20 -Tue, 13 Mar 2018 23:11:32 GMT - -*Version update only* - -## 4.3.19 -Mon, 12 Mar 2018 20:36:19 GMT - -*Version update only* - -## 4.3.18 -Tue, 06 Mar 2018 17:04:51 GMT - -*Version update only* - -## 4.3.17 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 4.3.16 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 4.3.15 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 4.3.14 -Wed, 21 Feb 2018 03:13:29 GMT - -*Version update only* - -## 4.3.13 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 4.3.12 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 4.3.11 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.3.10 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.3.9 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 4.3.8 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 4.3.7 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 4.3.6 -Tue, 23 Jan 2018 17:05:28 GMT - -*Version update only* - -## 4.3.5 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 4.3.4 -Thu, 18 Jan 2018 00:48:06 GMT - -### Patches - -- Update dependency of node-library-build - -## 4.3.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 4.3.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 4.3.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 4.3.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 4.2.16 -Sun, 07 Jan 2018 05:12:08 GMT - -*Version update only* - -## 4.2.15 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 4.2.14 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 4.2.13 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 4.2.12 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 4.2.11 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 4.2.10 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 4.2.9 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 4.2.8 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 4.2.7 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 4.2.6 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 4.2.5 -Thu, 02 Nov 2017 16:05:24 GMT - -*Version update only* - -## 4.2.4 -Wed, 01 Nov 2017 21:06:08 GMT - -*Version update only* - -## 4.2.3 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 4.2.2 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 4.2.1 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 4.2.0 -Tue, 24 Oct 2017 18:17:12 GMT - -### Minor changes - -- Support Jest task - -## 4.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -*Version update only* - -## 4.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 4.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 4.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 4.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 4.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 4.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 4.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 4.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 4.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -### Patches - -- Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable' - -## 4.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 4.0.4 -Thu, 07 Sep 2017 00:11:12 GMT - -*Version update only* - -## 4.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 4.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 4.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 4.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 3.4.1 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 3.4.0 -Wed, 30 Aug 2017 01:04:34 GMT - -### Minor changes - -- node-library-build now supports the CopyStaticAssetsTask - -## 3.3.2 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 3.3.1 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 3.3.0 -Tue, 22 Aug 2017 13:04:22 GMT - -### Minor changes - -- node-library-build now supports pre-copy.json and post-copy.json - -## 3.2.8 -Wed, 16 Aug 2017 13:04:08 GMT - -*Version update only* - -## 3.2.7 -Tue, 15 Aug 2017 19:04:14 GMT - -*Version update only* - -## 3.2.6 -Tue, 15 Aug 2017 01:29:31 GMT - -*Version update only* - -## 3.2.5 -Sat, 12 Aug 2017 01:03:30 GMT - -*Version update only* - -## 3.2.4 -Fri, 11 Aug 2017 21:44:05 GMT - -*Version update only* - -## 3.2.3 -Sat, 05 Aug 2017 01:04:41 GMT - -*Version update only* - -## 3.2.2 -Mon, 31 Jul 2017 21:18:26 GMT - -*Version update only* - -## 3.2.1 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools and restrict the dependency version requirements. - -## 3.2.0 -Tue, 25 Jul 2017 20:03:31 GMT - -### Minor changes - -- Upgrade to TypeScript 2.4 - -## 3.1.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 3.0.1 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 3.0.0 -Mon, 20 Mar 2017 21:52:20 GMT - -### Breaking changes - -- Updating build task dependencies. - -## 2.3.1 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.3.0 -Wed, 08 Feb 2017 01:41:58 GMT - -### Minor changes - -- Treat warnings as errors in production. Treat tsli nt errors as warnings. - -## 2.2.0 -Fri, 20 Jan 2017 01:46:41 GMT - -### Minor changes - -- Run the api-extractor task during the default build. - -## 2.1.0 -Fri, 13 Jan 2017 06:46:05 GMT - -### Minor changes - -- Enable the ApiExtractor task from gulp-core-build-typescript. - -## 2.0.0 -Wed, 11 Jan 2017 14:11:26 GMT - -*Initial release* - diff --git a/core-build/node-library-build/LICENSE b/core-build/node-library-build/LICENSE deleted file mode 100644 index 12aae643b3f..00000000000 --- a/core-build/node-library-build/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/node-library-build - -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/core-build/node-library-build/README.md b/core-build/node-library-build/README.md deleted file mode 100644 index 551b4f9d3fc..00000000000 --- a/core-build/node-library-build/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# @microsoft/node-library-build - -`node-library-build` is a `gulp-core-build` based build rig which provides basic functionality for building and unit testing TypeScript projects. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fnode-library-build.svg)](https://badge.fury.io/js/%40microsoft%2Fnode-library-build) -[![Build Status](https://travis-ci.org/Microsoft/node-library-build.svg?branch=master)](https://travis-ci.org/Microsoft/node-library-build) -[![Dependencies](https://david-dm.org/Microsoft/node-library-build.svg)](https://david-dm.org/Microsoft/node-library-build) diff --git a/core-build/node-library-build/config/api-extractor.json b/core-build/node-library-build/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/node-library-build/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/node-library-build/gulpfile.js b/core-build/node-library-build/gulpfile.js deleted file mode 100644 index e5dbce33a56..00000000000 --- a/core-build/node-library-build/gulpfile.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -let build = require('@microsoft/gulp-core-build'); -let { tscCmd, lintCmd, apiExtractor } = require('@microsoft/gulp-core-build-typescript') -let mocha = require('@microsoft/gulp-core-build-mocha'); - -build.setConfig({ - shouldWarningsFailBuild: build.getConfig().production -}); - -build.task('default', build.serial(build.parallel(tscCmd, lintCmd), apiExtractor, mocha)); - -build.initialize(require('gulp')); - diff --git a/core-build/node-library-build/package.json b/core-build/node-library-build/package.json deleted file mode 100644 index 7d23f7976a3..00000000000 --- a/core-build/node-library-build/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@microsoft/node-library-build", - "version": "6.4.6", - "description": "", - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/node-library-build" - }, - "scripts": { - "build": "gulp --clean" - }, - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@microsoft/gulp-core-build-mocha": "3.8.6", - "@microsoft/gulp-core-build-typescript": "8.4.6", - "@types/gulp": "4.0.6", - "@types/node": "10.17.13", - "gulp": "~4.0.2" - }, - "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5" - } -} diff --git a/core-build/node-library-build/src/index.ts b/core-build/node-library-build/src/index.ts deleted file mode 100644 index 5bda754d5b7..00000000000 --- a/core-build/node-library-build/src/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - CopyTask, - copyStaticAssets, - jest, - task, - watch, - serial, - parallel, - IExecutable, - setConfig -} from '@microsoft/gulp-core-build'; -import { tscCmd, lintCmd, apiExtractor } from '@microsoft/gulp-core-build-typescript'; -import { instrument, mocha } from '@microsoft/gulp-core-build-mocha'; - -export * from '@microsoft/gulp-core-build'; -export * from '@microsoft/gulp-core-build-typescript'; -export * from '@microsoft/gulp-core-build-mocha'; - -// pre copy and post copy allows you to specify a map of dest: [sources] to copy from one place to another. -/** - * @public - */ -export const preCopy: CopyTask = new CopyTask(); -preCopy.name = 'pre-copy'; - -/** - * @public - */ -export const postCopy: CopyTask = new CopyTask(); -postCopy.name = 'post-copy'; - -const PRODUCTION: boolean = process.argv.indexOf('--production') !== -1 || process.argv.indexOf('--ship') !== -1; -setConfig({ - production: PRODUCTION, - shouldWarningsFailBuild: PRODUCTION -}); - -const buildSubtask: IExecutable = serial( - preCopy, - parallel(lintCmd, tscCmd, copyStaticAssets), - apiExtractor, - postCopy -); - -/** - * @public - */ -export const buildTasks: IExecutable = task('build', buildSubtask); - -/** - * @public - */ -export const testTasks: IExecutable = task('test', serial(buildSubtask, mocha, jest)); - -/** - * @public - */ -export const defaultTasks: IExecutable = task('default', serial(buildSubtask, instrument, mocha, jest)); - -task('watch', watch('src/**.ts', testTasks)); diff --git a/core-build/node-library-build/tsconfig.json b/core-build/node-library-build/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/core-build/node-library-build/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/core-build/web-library-build/.eslintrc.js b/core-build/web-library-build/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/core-build/web-library-build/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/core-build/web-library-build/.npmignore b/core-build/web-library-build/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/core-build/web-library-build/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/core-build/web-library-build/CHANGELOG.json b/core-build/web-library-build/CHANGELOG.json deleted file mode 100644 index 17e2ead5baa..00000000000 --- a/core-build/web-library-build/CHANGELOG.json +++ /dev/null @@ -1,7664 +0,0 @@ -{ - "name": "@microsoft/web-library-build", - "entries": [ - { - "version": "7.4.6", - "tag": "@microsoft/web-library-build_v7.4.6", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.2` to `3.15.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.5` to `4.10.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.5` to `8.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `5.0.1` to `5.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "7.4.5", - "tag": "@microsoft/web-library-build_v7.4.5", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.1` to `3.15.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.4` to `4.10.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.4` to `8.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `5.0.0` to `5.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "7.4.4", - "tag": "@microsoft/web-library-build_v7.4.4", - "date": "Tue, 28 Jan 2020 02:23:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.15.0` to `3.15.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.3` to `4.10.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.3` to `8.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.1.3` to `5.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.3` to `6.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "7.4.3", - "tag": "@microsoft/web-library-build_v7.4.3", - "date": "Fri, 24 Jan 2020 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.2` to `3.15.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.2` to `4.10.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.6.2` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.2` to `8.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.1.2` to `4.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.2` to `6.4.3`" - } - ] - } - }, - { - "version": "7.4.2", - "tag": "@microsoft/web-library-build_v7.4.2", - "date": "Thu, 23 Jan 2020 01:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.1` to `3.14.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.1` to `4.10.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.1` to `8.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.1.1` to `4.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.1` to `6.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "7.4.1", - "tag": "@microsoft/web-library-build_v7.4.1", - "date": "Tue, 21 Jan 2020 21:56:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.14.0` to `3.14.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.10.0` to `4.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.4.0` to `8.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.1.0` to `4.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.0` to `6.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.0` to `0.4.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "7.4.0", - "tag": "@microsoft/web-library-build_v7.4.0", - "date": "Sun, 19 Jan 2020 02:26:53 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade Node typings to Node 10" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.4` to `3.14.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.9.0` to `4.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.23` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.16` to `8.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.8` to `4.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.16` to `6.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.15` to `0.4.0`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "7.3.18", - "tag": "@microsoft/web-library-build_v7.3.18", - "date": "Fri, 17 Jan 2020 01:08:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.3` to `3.13.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.24` to `4.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.22` to `3.5.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.15` to `8.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.7` to `4.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.15` to `6.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.14` to `0.3.15`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "7.3.17", - "tag": "@microsoft/web-library-build_v7.3.17", - "date": "Tue, 14 Jan 2020 01:34:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.23` to `4.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.21` to `3.5.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.14` to `8.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.6` to `4.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.14` to `6.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "7.3.16", - "tag": "@microsoft/web-library-build_v7.3.16", - "date": "Sat, 11 Jan 2020 05:18:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.2` to `3.13.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.22` to `4.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.20` to `3.5.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.13` to `8.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.5` to `4.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.13` to `6.3.14`" - } - ] - } - }, - { - "version": "7.3.15", - "tag": "@microsoft/web-library-build_v7.3.15", - "date": "Fri, 10 Jan 2020 03:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.21` to `4.8.22`" - } - ] - } - }, - { - "version": "7.3.14", - "tag": "@microsoft/web-library-build_v7.3.14", - "date": "Thu, 09 Jan 2020 06:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.1` to `3.13.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.20` to `4.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.19` to `3.5.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.12` to `8.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.4` to `4.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.12` to `6.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.12` to `0.3.13`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "7.3.13", - "tag": "@microsoft/web-library-build_v7.3.13", - "date": "Wed, 08 Jan 2020 00:11:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.13.0` to `3.13.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.19` to `4.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.18` to `3.5.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.11` to `8.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.3` to `4.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.11` to `6.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.3.11` to `0.3.12`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" - } - ] - } - }, - { - "version": "7.3.12", - "tag": "@microsoft/web-library-build_v7.3.12", - "date": "Mon, 23 Dec 2019 16:08:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.18` to `4.8.19`" - } - ] - } - }, - { - "version": "7.3.11", - "tag": "@microsoft/web-library-build_v7.3.11", - "date": "Wed, 04 Dec 2019 23:17:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.5` to `3.13.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.17` to `4.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.17` to `3.5.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.10` to `8.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.2` to `4.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.10` to `6.3.11`" - } - ] - } - }, - { - "version": "7.3.10", - "tag": "@microsoft/web-library-build_v7.3.10", - "date": "Tue, 03 Dec 2019 03:17:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.16` to `4.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.16` to `3.5.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.9` to `8.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.1` to `4.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.9` to `6.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "7.3.9", - "tag": "@microsoft/web-library-build_v7.3.9", - "date": "Sun, 24 Nov 2019 00:54:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.15` to `4.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.15` to `3.5.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.8` to `8.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `4.0.0` to `4.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.8` to `6.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "7.3.8", - "tag": "@microsoft/web-library-build_v7.3.8", - "date": "Wed, 20 Nov 2019 06:14:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.14` to `4.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.14` to `3.5.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.7` to `8.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.9` to `4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.7` to `6.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "7.3.7", - "tag": "@microsoft/web-library-build_v7.3.7", - "date": "Fri, 15 Nov 2019 04:50:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.4` to `3.12.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.13` to `4.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.13` to `3.5.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.6` to `8.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.8` to `3.7.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.6` to `6.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "7.3.6", - "tag": "@microsoft/web-library-build_v7.3.6", - "date": "Mon, 11 Nov 2019 16:07:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.3` to `3.12.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.12` to `4.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.12` to `3.5.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.5` to `8.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.7` to `3.7.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.5` to `6.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.5` to `0.3.6`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "7.3.5", - "tag": "@microsoft/web-library-build_v7.3.5", - "date": "Wed, 06 Nov 2019 22:44:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.11` to `4.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.11` to `3.5.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.4` to `8.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.6` to `3.7.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.4` to `6.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "7.3.4", - "tag": "@microsoft/web-library-build_v7.3.4", - "date": "Tue, 05 Nov 2019 06:49:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.2` to `3.12.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.10` to `4.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.10` to `3.5.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.3` to `8.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.5` to `3.7.6`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.3` to `6.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "7.3.3", - "tag": "@microsoft/web-library-build_v7.3.3", - "date": "Tue, 05 Nov 2019 01:08:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.9` to `4.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.9` to `3.5.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.2` to `8.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.2` to `6.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "7.3.2", - "tag": "@microsoft/web-library-build_v7.3.2", - "date": "Fri, 25 Oct 2019 15:08:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.8` to `4.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.8` to `3.5.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.1` to `8.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.1` to `6.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "7.3.1", - "tag": "@microsoft/web-library-build_v7.3.1", - "date": "Tue, 22 Oct 2019 06:24:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.1` to `3.12.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.7` to `4.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.7` to `3.5.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.3.0` to `8.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.3.0` to `6.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.3.0` to `0.3.1`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "7.3.0", - "tag": "@microsoft/web-library-build_v7.3.0", - "date": "Mon, 21 Oct 2019 05:22:43 GMT", - "comments": { - "minor": [ - { - "comment": "Add support for ESLint+TypeScript" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.6` to `4.8.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.6` to `3.5.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.6` to `8.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.6` to `6.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.6` to `0.3.0`" - } - ] - } - }, - { - "version": "7.2.7", - "tag": "@microsoft/web-library-build_v7.2.7", - "date": "Fri, 18 Oct 2019 15:15:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.5` to `4.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.5` to `3.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.5` to `8.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.5` to `6.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "7.2.6", - "tag": "@microsoft/web-library-build_v7.2.6", - "date": "Mon, 07 Oct 2019 20:15:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.5` to `3.7.0`" - } - ] - } - }, - { - "version": "7.2.5", - "tag": "@microsoft/web-library-build_v7.2.5", - "date": "Sun, 06 Oct 2019 00:27:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.4` to `4.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.4` to `3.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.4` to `8.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.4` to `3.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.4` to `6.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "7.2.4", - "tag": "@microsoft/web-library-build_v7.2.4", - "date": "Fri, 04 Oct 2019 00:15:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.3` to `4.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.3` to `3.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.3` to `8.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.3` to `6.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "7.2.3", - "tag": "@microsoft/web-library-build_v7.2.3", - "date": "Sun, 29 Sep 2019 23:56:29 GMT", - "comments": { - "patch": [ - { - "comment": "Update repository URL" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.12.0` to `3.12.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.2` to `4.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.2` to `8.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.2` to `6.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "7.2.2", - "tag": "@microsoft/web-library-build_v7.2.2", - "date": "Wed, 25 Sep 2019 15:15:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.1` to `4.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.1` to `8.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.1` to `6.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.1` to `0.2.2`" - } - ] - } - }, - { - "version": "7.2.1", - "tag": "@microsoft/web-library-build_v7.2.1", - "date": "Tue, 24 Sep 2019 02:58:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.8.0` to `4.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.2.0` to `8.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.2.0` to `6.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "7.2.0", - "tag": "@microsoft/web-library-build_v7.2.0", - "date": "Mon, 23 Sep 2019 15:14:55 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade @types/node dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.3` to `3.12.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.25` to `4.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.11` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.35` to `8.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.12` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.11` to `6.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.24` to `0.2.0`" - } - ] - } - }, - { - "version": "7.1.12", - "tag": "@microsoft/web-library-build_v7.1.12", - "date": "Fri, 20 Sep 2019 21:27:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.24` to `4.7.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.10` to `3.4.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.34` to `8.1.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.11` to `3.5.12`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.10` to `6.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.23` to `0.1.24`" - } - ] - } - }, - { - "version": "7.1.11", - "tag": "@microsoft/web-library-build_v7.1.11", - "date": "Wed, 11 Sep 2019 19:56:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.23` to `4.7.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.9` to `3.4.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.33` to `8.1.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.10` to `3.5.11`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.9` to `6.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.22` to `0.1.23`" - } - ] - } - }, - { - "version": "7.1.10", - "tag": "@microsoft/web-library-build_v7.1.10", - "date": "Tue, 10 Sep 2019 22:32:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.2` to `3.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.22` to `4.7.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.8` to `3.4.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.32` to `8.1.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.9` to `3.5.10`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.8` to `6.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.21` to `0.1.22`" - } - ] - } - }, - { - "version": "7.1.9", - "tag": "@microsoft/web-library-build_v7.1.9", - "date": "Tue, 10 Sep 2019 20:38:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.21` to `4.7.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.7` to `3.4.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.31` to `8.1.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.8` to `3.5.9`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.7` to `6.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.20` to `0.1.21`" - } - ] - } - }, - { - "version": "7.1.8", - "tag": "@microsoft/web-library-build_v7.1.8", - "date": "Wed, 04 Sep 2019 18:28:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.1` to `3.11.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.20` to `4.7.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.6` to `3.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.30` to `8.1.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.7` to `3.5.8`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.6` to `6.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "7.1.7", - "tag": "@microsoft/web-library-build_v7.1.7", - "date": "Wed, 04 Sep 2019 15:15:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.19` to `4.7.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.5` to `3.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.29` to `8.1.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.6` to `3.5.7`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.5` to `6.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "7.1.6", - "tag": "@microsoft/web-library-build_v7.1.6", - "date": "Wed, 04 Sep 2019 01:43:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.18` to `4.7.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.5` to `3.5.6`" - } - ] - } - }, - { - "version": "7.1.5", - "tag": "@microsoft/web-library-build_v7.1.5", - "date": "Fri, 30 Aug 2019 00:14:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.17` to `4.7.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.4` to `3.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.28` to `8.1.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.4` to `3.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.4` to `6.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "7.1.4", - "tag": "@microsoft/web-library-build_v7.1.4", - "date": "Mon, 12 Aug 2019 15:15:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.16` to `4.7.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.3` to `3.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.27` to `8.1.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.3` to `3.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.3` to `6.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "7.1.3", - "tag": "@microsoft/web-library-build_v7.1.3", - "date": "Thu, 08 Aug 2019 15:14:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.11.0` to `3.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.15` to `4.7.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.26` to `8.1.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.2` to `6.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "7.1.2", - "tag": "@microsoft/web-library-build_v7.1.2", - "date": "Thu, 08 Aug 2019 00:49:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.14` to `4.7.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.25` to `8.1.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.1` to `6.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "7.1.1", - "tag": "@microsoft/web-library-build_v7.1.1", - "date": "Mon, 05 Aug 2019 22:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.10.0` to `3.11.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.13` to `4.7.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.24` to `8.1.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.1.0` to `6.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "7.1.0", - "tag": "@microsoft/web-library-build_v7.1.0", - "date": "Tue, 23 Jul 2019 19:14:38 GMT", - "comments": { - "minor": [ - { - "comment": "Update gulp to 4.0.2." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.26` to `3.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.12` to `4.7.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.48` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.23` to `8.1.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.115` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.74` to `6.1.0`" - } - ] - } - }, - { - "version": "7.0.52", - "tag": "@microsoft/web-library-build_v7.0.52", - "date": "Tue, 23 Jul 2019 01:13:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.11` to `4.7.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.47` to `3.3.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.22` to `8.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.114` to `3.4.115`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.73` to `6.0.74`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "7.0.51", - "tag": "@microsoft/web-library-build_v7.0.51", - "date": "Mon, 22 Jul 2019 19:13:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.10` to `4.7.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.46` to `3.3.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.21` to `8.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.113` to `3.4.114`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.72` to `6.0.73`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.4\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "7.0.50", - "tag": "@microsoft/web-library-build_v7.0.50", - "date": "Fri, 12 Jul 2019 19:12:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.9` to `4.7.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.45` to `3.3.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.20` to `8.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.112` to `3.4.113`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.71` to `6.0.72`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.23` to `0.3.24`" - } - ] - } - }, - { - "version": "7.0.49", - "tag": "@microsoft/web-library-build_v7.0.49", - "date": "Thu, 11 Jul 2019 19:13:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.8` to `4.7.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.44` to `3.3.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.19` to `8.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.111` to `3.4.112`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.70` to `6.0.71`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.22` to `0.3.23`" - } - ] - } - }, - { - "version": "7.0.48", - "tag": "@microsoft/web-library-build_v7.0.48", - "date": "Tue, 09 Jul 2019 19:13:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.7` to `4.7.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.43` to `3.3.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.18` to `8.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.110` to `3.4.111`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.69` to `6.0.70`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.21` to `0.3.22`" - } - ] - } - }, - { - "version": "7.0.47", - "tag": "@microsoft/web-library-build_v7.0.47", - "date": "Mon, 08 Jul 2019 19:12:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.6` to `4.7.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.42` to `3.3.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.17` to `8.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.109` to `3.4.110`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.68` to `6.0.69`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.20` to `0.3.21`" - } - ] - } - }, - { - "version": "7.0.46", - "tag": "@microsoft/web-library-build_v7.0.46", - "date": "Sat, 29 Jun 2019 02:30:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.5` to `4.7.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.41` to `3.3.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.16` to `8.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.108` to `3.4.109`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.67` to `6.0.68`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.19` to `0.3.20`" - } - ] - } - }, - { - "version": "7.0.45", - "tag": "@microsoft/web-library-build_v7.0.45", - "date": "Wed, 12 Jun 2019 19:12:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.4` to `4.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.40` to `3.3.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.15` to `8.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.107` to `3.4.108`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.66` to `6.0.67`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.18` to `0.3.19`" - } - ] - } - }, - { - "version": "7.0.44", - "tag": "@microsoft/web-library-build_v7.0.44", - "date": "Tue, 11 Jun 2019 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.3` to `4.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.39` to `3.3.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.14` to `8.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.106` to `3.4.107`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.65` to `6.0.66`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.17` to `0.3.18`" - } - ] - } - }, - { - "version": "7.0.43", - "tag": "@microsoft/web-library-build_v7.0.43", - "date": "Thu, 06 Jun 2019 22:33:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.2` to `4.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.38` to `3.3.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.105` to `3.4.106`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.64` to `6.0.65`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.16` to `0.3.17`" - } - ] - } - }, - { - "version": "7.0.42", - "tag": "@microsoft/web-library-build_v7.0.42", - "date": "Wed, 05 Jun 2019 19:12:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.1` to `4.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.37` to `3.3.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.13` to `8.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.104` to `3.4.105`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.63` to `6.0.64`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.15` to `0.3.16`" - } - ] - } - }, - { - "version": "7.0.41", - "tag": "@microsoft/web-library-build_v7.0.41", - "date": "Tue, 04 Jun 2019 05:51:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.7.0` to `4.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.36` to `3.3.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.12` to `8.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.103` to `3.4.104`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.62` to `6.0.63`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.14` to `0.3.15`" - } - ] - } - }, - { - "version": "7.0.40", - "tag": "@microsoft/web-library-build_v7.0.40", - "date": "Fri, 31 May 2019 01:13:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.35` to `4.7.0`" - } - ] - } - }, - { - "version": "7.0.39", - "tag": "@microsoft/web-library-build_v7.0.39", - "date": "Mon, 27 May 2019 04:13:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.34` to `4.6.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.35` to `3.3.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.11` to `8.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.102` to `3.4.103`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.61` to `6.0.62`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.13` to `0.3.14`" - } - ] - } - }, - { - "version": "7.0.38", - "tag": "@microsoft/web-library-build_v7.0.38", - "date": "Mon, 13 May 2019 02:08:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.33` to `4.6.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.34` to `3.3.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.10` to `8.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.101` to `3.4.102`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.60` to `6.0.61`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.12` to `0.3.13`" - } - ] - } - }, - { - "version": "7.0.37", - "tag": "@microsoft/web-library-build_v7.0.37", - "date": "Thu, 09 May 2019 19:12:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.32` to `4.6.33`" - } - ] - } - }, - { - "version": "7.0.36", - "tag": "@microsoft/web-library-build_v7.0.36", - "date": "Mon, 06 May 2019 20:46:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.31` to `4.6.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.33` to `3.3.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.9` to `8.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.100` to `3.4.101`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.59` to `6.0.60`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.11` to `0.3.12`" - } - ] - } - }, - { - "version": "7.0.35", - "tag": "@microsoft/web-library-build_v7.0.35", - "date": "Mon, 06 May 2019 19:34:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.30` to `4.6.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.32` to `3.3.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.8` to `8.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.99` to `3.4.100`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.58` to `6.0.59`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.10` to `0.3.11`" - } - ] - } - }, - { - "version": "7.0.34", - "tag": "@microsoft/web-library-build_v7.0.34", - "date": "Mon, 06 May 2019 19:11:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.29` to `4.6.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.31` to `3.3.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.7` to `8.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.98` to `3.4.99`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.57` to `6.0.58`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.9` to `0.3.10`" - } - ] - } - }, - { - "version": "7.0.33", - "tag": "@microsoft/web-library-build_v7.0.33", - "date": "Tue, 30 Apr 2019 23:08:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.28` to `4.6.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.30` to `3.3.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.6` to `8.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.97` to `3.4.98`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.56` to `6.0.57`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.8` to `0.3.9`" - } - ] - } - }, - { - "version": "7.0.32", - "tag": "@microsoft/web-library-build_v7.0.32", - "date": "Tue, 16 Apr 2019 11:01:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.27` to `4.6.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.29` to `3.3.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.5` to `8.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.96` to `3.4.97`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.55` to `6.0.56`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.7` to `0.3.8`" - } - ] - } - }, - { - "version": "7.0.31", - "tag": "@microsoft/web-library-build_v7.0.31", - "date": "Fri, 12 Apr 2019 06:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.26` to `4.6.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.28` to `3.3.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.4` to `8.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.95` to `3.4.96`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.54` to `6.0.55`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.6` to `0.3.7`" - } - ] - } - }, - { - "version": "7.0.30", - "tag": "@microsoft/web-library-build_v7.0.30", - "date": "Thu, 11 Apr 2019 07:14:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.25` to `4.6.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.27` to `3.3.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.3` to `8.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.94` to `3.4.95`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.53` to `6.0.54`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.5` to `0.3.6`" - } - ] - } - }, - { - "version": "7.0.29", - "tag": "@microsoft/web-library-build_v7.0.29", - "date": "Tue, 09 Apr 2019 05:31:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.24` to `4.6.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.26` to `3.3.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.2` to `8.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.93` to `3.4.94`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.52` to `6.0.53`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.4` to `0.3.5`" - } - ] - } - }, - { - "version": "7.0.28", - "tag": "@microsoft/web-library-build_v7.0.28", - "date": "Mon, 08 Apr 2019 19:12:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.23` to `4.6.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.25` to `3.3.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.1` to `8.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.92` to `3.4.93`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.51` to `6.0.52`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "7.0.27", - "tag": "@microsoft/web-library-build_v7.0.27", - "date": "Sat, 06 Apr 2019 02:05:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.22` to `4.6.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.24` to `3.3.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.1.0` to `8.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.91` to `3.4.92`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.50` to `6.0.51`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "7.0.26", - "tag": "@microsoft/web-library-build_v7.0.26", - "date": "Fri, 05 Apr 2019 04:16:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.21` to `4.6.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.23` to `3.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.23` to `8.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.90` to `3.4.91`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.49` to `6.0.50`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "7.0.25", - "tag": "@microsoft/web-library-build_v7.0.25", - "date": "Wed, 03 Apr 2019 02:58:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.25` to `3.9.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.20` to `4.6.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.22` to `3.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.22` to `8.0.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.89` to `3.4.90`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.48` to `6.0.49`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "7.0.24", - "tag": "@microsoft/web-library-build_v7.0.24", - "date": "Tue, 02 Apr 2019 01:12:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.24` to `3.9.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.19` to `4.6.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.21` to `3.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.21` to `8.0.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.88` to `3.4.89`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.47` to `6.0.48`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.20` to `0.3.0`" - } - ] - } - }, - { - "version": "7.0.23", - "tag": "@microsoft/web-library-build_v7.0.23", - "date": "Sat, 30 Mar 2019 22:27:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.23` to `3.9.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.18` to `4.6.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.20` to `3.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.20` to `8.0.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.87` to `3.4.88`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.46` to `6.0.47`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.19` to `0.2.20`" - } - ] - } - }, - { - "version": "7.0.22", - "tag": "@microsoft/web-library-build_v7.0.22", - "date": "Thu, 28 Mar 2019 19:14:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.22` to `3.9.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.17` to `4.6.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.19` to `3.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.19` to `8.0.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.86` to `3.4.87`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.45` to `6.0.46`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.18` to `0.2.19`" - } - ] - } - }, - { - "version": "7.0.21", - "tag": "@microsoft/web-library-build_v7.0.21", - "date": "Tue, 26 Mar 2019 20:54:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.21` to `3.9.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.16` to `4.6.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.18` to `3.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.18` to `8.0.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.85` to `3.4.86`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.44` to `6.0.45`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.17` to `0.2.18`" - } - ] - } - }, - { - "version": "7.0.20", - "tag": "@microsoft/web-library-build_v7.0.20", - "date": "Sat, 23 Mar 2019 03:48:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.20` to `3.9.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.15` to `4.6.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.17` to `3.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.17` to `8.0.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.84` to `3.4.85`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.43` to `6.0.44`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.16` to `0.2.17`" - } - ] - } - }, - { - "version": "7.0.19", - "tag": "@microsoft/web-library-build_v7.0.19", - "date": "Thu, 21 Mar 2019 04:59:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.19` to `3.9.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.14` to `4.6.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.16` to `3.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.16` to `8.0.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.83` to `3.4.84`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.42` to `6.0.43`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.15` to `0.2.16`" - } - ] - } - }, - { - "version": "7.0.18", - "tag": "@microsoft/web-library-build_v7.0.18", - "date": "Thu, 21 Mar 2019 01:15:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.18` to `3.9.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.13` to `4.6.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.15` to `3.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.15` to `8.0.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.82` to `3.4.83`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.41` to `6.0.42`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.14` to `0.2.15`" - } - ] - } - }, - { - "version": "7.0.17", - "tag": "@microsoft/web-library-build_v7.0.17", - "date": "Wed, 20 Mar 2019 19:14:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.17` to `3.9.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.12` to `4.6.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.14` to `3.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.14` to `8.0.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.81` to `3.4.82`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.40` to `6.0.41`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.13` to `0.2.14`" - } - ] - } - }, - { - "version": "7.0.16", - "tag": "@microsoft/web-library-build_v7.0.16", - "date": "Mon, 18 Mar 2019 04:28:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.16` to `3.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.11` to `4.6.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.13` to `3.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.13` to `8.0.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.80` to `3.4.81`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.39` to `6.0.40`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.12` to `0.2.13`" - } - ] - } - }, - { - "version": "7.0.15", - "tag": "@microsoft/web-library-build_v7.0.15", - "date": "Fri, 15 Mar 2019 19:13:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.15` to `3.9.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.10` to `4.6.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.12` to `3.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.12` to `8.0.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.79` to `3.4.80`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.38` to `6.0.39`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.11` to `0.2.12`" - } - ] - } - }, - { - "version": "7.0.14", - "tag": "@microsoft/web-library-build_v7.0.14", - "date": "Wed, 13 Mar 2019 19:13:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.14` to `3.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.9` to `4.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.11` to `3.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.11` to `8.0.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.78` to `3.4.79`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.37` to `6.0.38`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.10` to `0.2.11`" - } - ] - } - }, - { - "version": "7.0.13", - "tag": "@microsoft/web-library-build_v7.0.13", - "date": "Wed, 13 Mar 2019 01:14:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.13` to `3.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.8` to `4.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.10` to `3.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.10` to `8.0.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.77` to `3.4.78`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.36` to `6.0.37`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.9` to `0.2.10`" - } - ] - } - }, - { - "version": "7.0.12", - "tag": "@microsoft/web-library-build_v7.0.12", - "date": "Mon, 11 Mar 2019 16:13:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.12` to `3.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.7` to `4.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.9` to `3.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.9` to `8.0.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.76` to `3.4.77`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.35` to `6.0.36`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.8` to `0.2.9`" - } - ] - } - }, - { - "version": "7.0.11", - "tag": "@microsoft/web-library-build_v7.0.11", - "date": "Tue, 05 Mar 2019 17:13:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.11` to `3.9.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.6` to `4.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.8` to `3.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.8` to `8.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.75` to `3.4.76`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.34` to `6.0.35`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.7` to `0.2.8`" - } - ] - } - }, - { - "version": "7.0.10", - "tag": "@microsoft/web-library-build_v7.0.10", - "date": "Mon, 04 Mar 2019 17:13:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.10` to `3.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.5` to `4.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.7` to `3.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.7` to `8.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.74` to `3.4.75`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.33` to `6.0.34`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.6` to `0.2.7`" - } - ] - } - }, - { - "version": "7.0.9", - "tag": "@microsoft/web-library-build_v7.0.9", - "date": "Wed, 27 Feb 2019 22:13:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.9` to `3.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.4` to `4.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.6` to `3.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.6` to `8.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.73` to `3.4.74`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.32` to `6.0.33`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.5` to `0.2.6`" - } - ] - } - }, - { - "version": "7.0.8", - "tag": "@microsoft/web-library-build_v7.0.8", - "date": "Wed, 27 Feb 2019 17:13:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.8` to `3.9.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.3` to `4.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.5` to `8.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.72` to `3.4.73`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.31` to `6.0.32`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.4` to `0.2.5`" - } - ] - } - }, - { - "version": "7.0.7", - "tag": "@microsoft/web-library-build_v7.0.7", - "date": "Mon, 18 Feb 2019 17:13:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.7` to `3.9.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.2` to `4.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.4` to `8.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.71` to `3.4.72`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.30` to `6.0.31`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.3` to `0.2.4`" - } - ] - } - }, - { - "version": "7.0.6", - "tag": "@microsoft/web-library-build_v7.0.6", - "date": "Tue, 12 Feb 2019 17:13:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.6` to `3.9.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.1` to `4.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.3` to `8.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.70` to `3.4.71`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.29` to `6.0.30`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.2\" from `0.2.2` to `0.2.3`" - } - ] - } - }, - { - "version": "7.0.5", - "tag": "@microsoft/web-library-build_v7.0.5", - "date": "Mon, 11 Feb 2019 10:32:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.5` to `3.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.6.0` to `4.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.2` to `8.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.69` to `3.4.70`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.28` to `6.0.29`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "7.0.4", - "tag": "@microsoft/web-library-build_v7.0.4", - "date": "Mon, 11 Feb 2019 03:31:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.4` to `3.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.40` to `4.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.1` to `8.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.68` to `3.4.69`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.27` to `6.0.28`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "7.0.3", - "tag": "@microsoft/web-library-build_v7.0.3", - "date": "Wed, 30 Jan 2019 20:49:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.3` to `3.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.39` to `4.5.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `8.0.0` to `8.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.67` to `3.4.68`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.26` to `6.0.27`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.4.0` to `0.5.0`" - } - ] - } - }, - { - "version": "7.0.2", - "tag": "@microsoft/web-library-build_v7.0.2", - "date": "Mon, 21 Jan 2019 17:04:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.94` to `3.3.0`" - } - ] - } - }, - { - "version": "7.0.1", - "tag": "@microsoft/web-library-build_v7.0.1", - "date": "Sat, 19 Jan 2019 03:47:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.2` to `3.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.38` to `4.5.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.93` to `3.2.94`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.8` to `8.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.66` to `3.4.67`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.25` to `6.0.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.4` to `0.4.0`" - } - ] - } - }, - { - "version": "7.0.0", - "tag": "@microsoft/web-library-build_v7.0.0", - "date": "Tue, 15 Jan 2019 17:04:09 GMT", - "comments": { - "major": [ - { - "comment": "Remove karma task." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.1` to `3.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.37` to `4.5.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.92` to `3.2.93`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.7` to `7.4.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.65` to `3.4.66`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.24` to `6.0.25`" - } - ] - } - }, - { - "version": "6.0.45", - "tag": "@microsoft/web-library-build_v6.0.45", - "date": "Thu, 10 Jan 2019 01:57:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.9.0` to `3.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.56` to `4.6.57`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.36` to `4.5.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.91` to `3.2.92`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.6` to `7.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.64` to `3.4.65`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.23` to `6.0.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.3` to `0.3.4`" - } - ] - } - }, - { - "version": "6.0.44", - "tag": "@microsoft/web-library-build_v6.0.44", - "date": "Mon, 07 Jan 2019 17:04:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.57` to `3.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.55` to `4.6.56`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.35` to `4.5.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.90` to `3.2.91`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.5` to `7.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.63` to `3.4.64`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.22` to `6.0.23`" - } - ] - } - }, - { - "version": "6.0.43", - "tag": "@microsoft/web-library-build_v6.0.43", - "date": "Wed, 19 Dec 2018 05:57:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.56` to `3.8.57`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.54` to `4.6.55`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.34` to `4.5.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.89` to `3.2.90`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.4` to `7.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.62` to `3.4.63`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.21` to `6.0.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.2` to `0.3.3`" - } - ] - } - }, - { - "version": "6.0.42", - "tag": "@microsoft/web-library-build_v6.0.42", - "date": "Fri, 14 Dec 2018 20:51:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.33` to `4.5.34`" - } - ] - } - }, - { - "version": "6.0.41", - "tag": "@microsoft/web-library-build_v6.0.41", - "date": "Thu, 13 Dec 2018 02:58:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.55` to `3.8.56`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.53` to `4.6.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.32` to `4.5.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.88` to `3.2.89`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.3` to `7.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.61` to `3.4.62`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.20` to `6.0.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.1` to `0.3.2`" - } - ] - } - }, - { - "version": "6.0.40", - "tag": "@microsoft/web-library-build_v6.0.40", - "date": "Wed, 12 Dec 2018 17:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.54` to `3.8.55`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.52` to `4.6.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.31` to `4.5.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.87` to `3.2.88`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.2` to `7.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.60` to `3.4.61`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.19` to `6.0.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.3.0` to `0.3.1`" - } - ] - } - }, - { - "version": "6.0.39", - "tag": "@microsoft/web-library-build_v6.0.39", - "date": "Sat, 08 Dec 2018 06:35:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.53` to `3.8.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.51` to `4.6.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.30` to `4.5.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.86` to `3.2.87`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.1` to `7.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.59` to `3.4.60`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.18` to `6.0.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.1` to `0.3.0`" - } - ] - } - }, - { - "version": "6.0.38", - "tag": "@microsoft/web-library-build_v6.0.38", - "date": "Fri, 07 Dec 2018 17:04:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.52` to `3.8.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.50` to `4.6.51`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.29` to `4.5.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.85` to `3.2.86`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.4.0` to `7.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.58` to `3.4.59`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.17` to `6.0.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.2.0` to `0.2.1`" - } - ] - } - }, - { - "version": "6.0.37", - "tag": "@microsoft/web-library-build_v6.0.37", - "date": "Mon, 03 Dec 2018 17:04:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.28` to `4.5.29`" - } - ] - } - }, - { - "version": "6.0.36", - "tag": "@microsoft/web-library-build_v6.0.36", - "date": "Fri, 30 Nov 2018 23:34:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.51` to `3.8.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.49` to `4.6.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.27` to `4.5.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.84` to `3.2.85`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.3.1` to `7.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.57` to `3.4.58`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.16` to `6.0.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.1` to `0.2.0`" - } - ] - } - }, - { - "version": "6.0.35", - "tag": "@microsoft/web-library-build_v6.0.35", - "date": "Thu, 29 Nov 2018 07:02:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.50` to `3.8.51`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.48` to `4.6.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.26` to `4.5.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.83` to `3.2.84`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.3.0` to `7.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.56` to `3.4.57`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.15` to `6.0.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "6.0.34", - "tag": "@microsoft/web-library-build_v6.0.34", - "date": "Thu, 29 Nov 2018 00:35:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.49` to `3.8.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.47` to `4.6.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.25` to `4.5.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.82` to `3.2.83`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.7` to `7.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.55` to `3.4.56`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.14` to `6.0.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.0\" from `0.0.0` to `0.1.0`" - } - ] - } - }, - { - "version": "6.0.33", - "tag": "@microsoft/web-library-build_v6.0.33", - "date": "Wed, 28 Nov 2018 19:29:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.48` to `3.8.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.46` to `4.6.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.24` to `4.5.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.81` to `3.2.82`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.6` to `7.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.54` to `3.4.55`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.13` to `6.0.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.5` to `0.5.6`" - } - ] - } - }, - { - "version": "6.0.32", - "tag": "@microsoft/web-library-build_v6.0.32", - "date": "Wed, 28 Nov 2018 02:17:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.47` to `3.8.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.45` to `4.6.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.23` to `4.5.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.80` to `3.2.81`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.5` to `7.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.53` to `3.4.54`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.12` to `6.0.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "6.0.31", - "tag": "@microsoft/web-library-build_v6.0.31", - "date": "Fri, 16 Nov 2018 21:37:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.46` to `3.8.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.44` to `4.6.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.22` to `4.5.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.79` to `3.2.80`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.4` to `7.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.52` to `3.4.53`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.11` to `6.0.12`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.3` to `0.5.4`" - } - ] - } - }, - { - "version": "6.0.30", - "tag": "@microsoft/web-library-build_v6.0.30", - "date": "Fri, 16 Nov 2018 00:59:00 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.45` to `3.8.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.43` to `4.6.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.21` to `4.5.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.78` to `3.2.79`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.3` to `7.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.51` to `3.4.52`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.10` to `6.0.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.2` to `0.5.3`" - } - ] - } - }, - { - "version": "6.0.29", - "tag": "@microsoft/web-library-build_v6.0.29", - "date": "Fri, 09 Nov 2018 23:07:39 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.44` to `3.8.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.42` to `4.6.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.20` to `4.5.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.77` to `3.2.78`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.2` to `7.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.50` to `3.4.51`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.9` to `6.0.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.1` to `0.5.2`" - } - ] - } - }, - { - "version": "6.0.28", - "tag": "@microsoft/web-library-build_v6.0.28", - "date": "Wed, 07 Nov 2018 21:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.43` to `3.8.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.41` to `4.6.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.19` to `4.5.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.76` to `3.2.77`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.1` to `7.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.49` to `3.4.50`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.8` to `6.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.5.0` to `0.5.1`" - } - ] - } - }, - { - "version": "6.0.27", - "tag": "@microsoft/web-library-build_v6.0.27", - "date": "Wed, 07 Nov 2018 17:03:03 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.42` to `3.8.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.40` to `4.6.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.18` to `4.5.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.75` to `3.2.76`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.2.0` to `7.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.48` to `3.4.49`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.7` to `6.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.4` to `0.5.0`" - } - ] - } - }, - { - "version": "6.0.26", - "tag": "@microsoft/web-library-build_v6.0.26", - "date": "Mon, 05 Nov 2018 17:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.41` to `3.8.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.39` to `4.6.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.17` to `4.5.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.74` to `3.2.75`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.2` to `7.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.47` to `3.4.48`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.6` to `6.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.3` to `0.4.4`" - } - ] - } - }, - { - "version": "6.0.25", - "tag": "@microsoft/web-library-build_v6.0.25", - "date": "Thu, 01 Nov 2018 21:33:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.40` to `3.8.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.38` to `4.6.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.16` to `4.5.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.73` to `3.2.74`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.1` to `7.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.46` to `3.4.47`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.5` to `6.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.2` to `0.4.3`" - } - ] - } - }, - { - "version": "6.0.24", - "tag": "@microsoft/web-library-build_v6.0.24", - "date": "Thu, 01 Nov 2018 19:32:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.39` to `3.8.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.37` to `4.6.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.15` to `4.5.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.72` to `3.2.73`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.1.0` to `7.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.45` to `3.4.46`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.4` to `6.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.1` to `0.4.2`" - } - ] - } - }, - { - "version": "6.0.23", - "tag": "@microsoft/web-library-build_v6.0.23", - "date": "Wed, 31 Oct 2018 21:17:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.36` to `4.6.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.14` to `4.5.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.71` to `3.2.72`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.3` to `7.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.44` to `3.4.45`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.3` to `6.0.4`" - } - ] - } - }, - { - "version": "6.0.22", - "tag": "@microsoft/web-library-build_v6.0.22", - "date": "Wed, 31 Oct 2018 17:00:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.38` to `3.8.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.35` to `4.6.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.13` to `4.5.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.70` to `3.2.71`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.2` to `7.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.43` to `3.4.44`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.2` to `6.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.4.0` to `0.4.1`" - } - ] - } - }, - { - "version": "6.0.21", - "tag": "@microsoft/web-library-build_v6.0.21", - "date": "Sat, 27 Oct 2018 03:45:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.37` to `3.8.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.34` to `4.6.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.12` to `4.5.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.69` to `3.2.70`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.1` to `7.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.42` to `3.4.43`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.1` to `6.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.3.0` to `0.4.0`" - } - ] - } - }, - { - "version": "6.0.20", - "tag": "@microsoft/web-library-build_v6.0.20", - "date": "Sat, 27 Oct 2018 02:17:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.36` to `3.8.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.33` to `4.6.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.11` to `4.5.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.68` to `3.2.69`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `7.0.0` to `7.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.41` to `3.4.42`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.0.0` to `6.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.2.0` to `0.3.0`" - } - ] - } - }, - { - "version": "6.0.19", - "tag": "@microsoft/web-library-build_v6.0.19", - "date": "Sat, 27 Oct 2018 00:26:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.35` to `3.8.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.32` to `4.6.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.10` to `4.5.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.67` to `3.2.68`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.12` to `7.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.40` to `3.4.41`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.26` to `6.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.20` to `0.2.0`" - } - ] - } - }, - { - "version": "6.0.18", - "tag": "@microsoft/web-library-build_v6.0.18", - "date": "Thu, 25 Oct 2018 23:20:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.34` to `3.8.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.31` to `4.6.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.9` to `4.5.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.66` to `3.2.67`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.11` to `6.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.39` to `3.4.40`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.25` to `5.0.26`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.19` to `0.1.20`" - } - ] - } - }, - { - "version": "6.0.17", - "tag": "@microsoft/web-library-build_v6.0.17", - "date": "Thu, 25 Oct 2018 08:56:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.33` to `3.8.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.30` to `4.6.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.8` to `4.5.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.65` to `3.2.66`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.10` to `6.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.38` to `3.4.39`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.24` to `5.0.25`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.18` to `0.1.19`" - } - ] - } - }, - { - "version": "6.0.16", - "tag": "@microsoft/web-library-build_v6.0.16", - "date": "Wed, 24 Oct 2018 16:03:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.32` to `3.8.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.29` to `4.6.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.7` to `4.5.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.64` to `3.2.65`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.9` to `6.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.37` to `3.4.38`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.23` to `5.0.24`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.17` to `0.1.18`" - } - ] - } - }, - { - "version": "6.0.15", - "tag": "@microsoft/web-library-build_v6.0.15", - "date": "Thu, 18 Oct 2018 05:30:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.31` to `3.8.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.28` to `4.6.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.6` to `4.5.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.63` to `3.2.64`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.8` to `6.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.36` to `3.4.37`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.22` to `5.0.23`" - } - ] - } - }, - { - "version": "6.0.14", - "tag": "@microsoft/web-library-build_v6.0.14", - "date": "Thu, 18 Oct 2018 01:32:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.30` to `3.8.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.27` to `4.6.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.5` to `4.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.62` to `3.2.63`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.7` to `6.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.35` to `3.4.36`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.21` to `5.0.22`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.16` to `0.1.17`" - } - ] - } - }, - { - "version": "6.0.13", - "tag": "@microsoft/web-library-build_v6.0.13", - "date": "Wed, 17 Oct 2018 21:04:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.29` to `3.8.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.26` to `4.6.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.4` to `4.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.61` to `3.2.62`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.6` to `6.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.34` to `3.4.35`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.20` to `5.0.21`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.15` to `0.1.16`" - } - ] - } - }, - { - "version": "6.0.12", - "tag": "@microsoft/web-library-build_v6.0.12", - "date": "Wed, 17 Oct 2018 14:43:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.28` to `3.8.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.25` to `4.6.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.3` to `4.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.60` to `3.2.61`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.5` to `6.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.33` to `3.4.34`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.19` to `5.0.20`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.14` to `0.1.15`" - } - ] - } - }, - { - "version": "6.0.11", - "tag": "@microsoft/web-library-build_v6.0.11", - "date": "Thu, 11 Oct 2018 23:26:07 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.27` to `3.8.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.24` to `4.6.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.2` to `4.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.59` to `3.2.60`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.4` to `6.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.32` to `3.4.33`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.18` to `5.0.19`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.13` to `0.1.14`" - } - ] - } - }, - { - "version": "6.0.10", - "tag": "@microsoft/web-library-build_v6.0.10", - "date": "Tue, 09 Oct 2018 06:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.26` to `3.8.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.23` to `4.6.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.1` to `4.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.58` to `3.2.59`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.3` to `6.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.31` to `3.4.32`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.17` to `5.0.18`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.12` to `0.1.13`" - } - ] - } - }, - { - "version": "6.0.9", - "tag": "@microsoft/web-library-build_v6.0.9", - "date": "Mon, 08 Oct 2018 16:04:27 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.25` to `3.8.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.22` to `4.6.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.5.0` to `4.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.57` to `3.2.58`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.2` to `6.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.30` to `3.4.31`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.16` to `5.0.17`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.11` to `0.1.12`" - } - ] - } - }, - { - "version": "6.0.8", - "tag": "@microsoft/web-library-build_v6.0.8", - "date": "Sun, 07 Oct 2018 06:15:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.24` to `3.8.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.21` to `4.6.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.8` to `4.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.56` to `3.2.57`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.1` to `6.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.29` to `3.4.30`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.15` to `5.0.16`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.10` to `0.1.11`" - } - ] - } - }, - { - "version": "6.0.7", - "tag": "@microsoft/web-library-build_v6.0.7", - "date": "Fri, 28 Sep 2018 16:05:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.23` to `3.8.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.20` to `4.6.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.7` to `4.4.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.55` to `3.2.56`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.1.0` to `6.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.28` to `3.4.29`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.14` to `5.0.15`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.9` to `0.1.10`" - } - ] - } - }, - { - "version": "6.0.6", - "tag": "@microsoft/web-library-build_v6.0.6", - "date": "Wed, 26 Sep 2018 21:39:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.22` to `3.8.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.19` to `4.6.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.6` to `4.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.54` to `3.2.55`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.5` to `6.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.27` to `3.4.28`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.13` to `5.0.14`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.8` to `0.1.9`" - } - ] - } - }, - { - "version": "6.0.5", - "tag": "@microsoft/web-library-build_v6.0.5", - "date": "Mon, 24 Sep 2018 23:06:40 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.21` to `3.8.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.18` to `4.6.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.5` to `4.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.53` to `3.2.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.4` to `6.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.26` to `3.4.27`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.12` to `5.0.13`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.7` to `0.1.8`" - } - ] - } - }, - { - "version": "6.0.4", - "tag": "@microsoft/web-library-build_v6.0.4", - "date": "Mon, 24 Sep 2018 16:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.17` to `4.6.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.4` to `4.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.52` to `3.2.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.3` to `6.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.25` to `3.4.26`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.11` to `5.0.12`" - } - ] - } - }, - { - "version": "6.0.3", - "tag": "@microsoft/web-library-build_v6.0.3", - "date": "Fri, 21 Sep 2018 16:04:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.20` to `3.8.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.16` to `4.6.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.3` to `4.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.51` to `3.2.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.2` to `6.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.24` to `3.4.25`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.10` to `5.0.11`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.6` to `0.1.7`" - } - ] - } - }, - { - "version": "6.0.2", - "tag": "@microsoft/web-library-build_v6.0.2", - "date": "Thu, 20 Sep 2018 23:57:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.19` to `3.8.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.15` to `4.6.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.2` to `4.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.50` to `3.2.51`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.1` to `6.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.23` to `3.4.24`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.9` to `5.0.10`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.5` to `0.1.6`" - } - ] - } - }, - { - "version": "6.0.1", - "tag": "@microsoft/web-library-build_v6.0.1", - "date": "Tue, 18 Sep 2018 21:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.18` to `3.8.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.14` to `4.6.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.1` to `4.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.49` to `3.2.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `6.0.0` to `6.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.22` to `3.4.23`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.8` to `5.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.4` to `0.1.5`" - } - ] - } - }, - { - "version": "6.0.0", - "tag": "@microsoft/web-library-build_v6.0.0", - "date": "Mon, 10 Sep 2018 23:23:01 GMT", - "comments": { - "major": [ - { - "comment": "Removing the text task from the rig." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.13` to `4.6.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.4.0` to `4.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.48` to `3.2.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.2` to `6.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.21` to `3.4.22`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.7` to `5.0.8`" - } - ] - } - }, - { - "version": "5.1.3", - "tag": "@microsoft/web-library-build_v5.1.3", - "date": "Thu, 06 Sep 2018 21:04:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.54` to `4.4.0`" - } - ] - } - }, - { - "version": "5.1.2", - "tag": "@microsoft/web-library-build_v5.1.2", - "date": "Thu, 06 Sep 2018 01:25:26 GMT", - "comments": { - "patch": [ - { - "comment": "Update \"repository\" field in package.json" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.17` to `3.8.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.12` to `4.6.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.53` to `4.3.54`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.47` to `3.2.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.1` to `5.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.20` to `3.4.21`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.6` to `5.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.3` to `0.1.4`" - } - ] - } - }, - { - "version": "5.1.1", - "tag": "@microsoft/web-library-build_v5.1.1", - "date": "Tue, 04 Sep 2018 21:34:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.16` to `3.8.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.11` to `4.6.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.52` to `4.3.53`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.46` to `3.2.47`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `5.0.0` to `5.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.19` to `3.4.20`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.5` to `5.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.2` to `0.1.3`" - } - ] - } - }, - { - "version": "5.1.0", - "tag": "@microsoft/web-library-build_v5.1.0", - "date": "Mon, 03 Sep 2018 16:04:46 GMT", - "comments": { - "minor": [ - { - "comment": "Update the way api-extractor is invoked." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.15` to `3.8.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.10` to `4.6.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.51` to `4.3.52`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.45` to `3.2.46`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.12` to `5.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.18` to `3.4.19`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.4` to `5.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.1` to `0.1.2`" - } - ] - } - }, - { - "version": "5.0.8", - "tag": "@microsoft/web-library-build_v5.0.8", - "date": "Fri, 31 Aug 2018 00:11:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.50` to `4.3.51`" - } - ] - } - }, - { - "version": "5.0.7", - "tag": "@microsoft/web-library-build_v5.0.7", - "date": "Thu, 30 Aug 2018 22:47:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.49` to `4.3.50`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.11` to `4.11.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.17` to `3.4.18`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.3` to `5.0.4`" - } - ] - } - }, - { - "version": "5.0.6", - "tag": "@microsoft/web-library-build_v5.0.6", - "date": "Thu, 30 Aug 2018 19:23:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.14` to `3.8.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.9` to `4.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.48` to `4.3.49`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.44` to `3.2.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.10` to `4.11.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.16` to `3.4.17`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.2` to `5.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.1.0` to `0.1.1`" - } - ] - } - }, - { - "version": "5.0.5", - "tag": "@microsoft/web-library-build_v5.0.5", - "date": "Thu, 30 Aug 2018 18:45:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.13` to `3.8.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.8` to `4.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.47` to `4.3.48`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.43` to `3.2.44`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.9` to `4.11.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.15` to `3.4.16`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.1` to `5.0.2`" - } - ] - } - }, - { - "version": "5.0.4", - "tag": "@microsoft/web-library-build_v5.0.4", - "date": "Thu, 30 Aug 2018 04:42:01 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.46` to `4.3.47`" - } - ] - } - }, - { - "version": "5.0.3", - "tag": "@microsoft/web-library-build_v5.0.3", - "date": "Thu, 30 Aug 2018 04:24:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.45` to `4.3.46`" - } - ] - } - }, - { - "version": "5.0.2", - "tag": "@microsoft/web-library-build_v5.0.2", - "date": "Wed, 29 Aug 2018 21:43:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.12` to `3.8.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.7` to `4.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.44` to `4.3.45`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.42` to `3.2.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.8` to `4.11.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.14` to `3.4.15`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `5.0.0` to `5.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack\" from `0.0.1` to `0.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler\" from `0.0.1` to `0.1.0`" - } - ] - } - }, - { - "version": "5.0.1", - "tag": "@microsoft/web-library-build_v5.0.1", - "date": "Wed, 29 Aug 2018 20:34:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.43` to `4.3.44`" - } - ] - } - }, - { - "version": "5.0.0", - "tag": "@microsoft/web-library-build_v5.0.0", - "date": "Wed, 29 Aug 2018 06:36:50 GMT", - "comments": { - "major": [ - { - "comment": "Updating the way typescript and tslint are invoked." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.11` to `3.8.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.6` to `4.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.42` to `4.3.43`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.41` to `3.2.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.7` to `4.11.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.13` to `3.4.14`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `4.4.11` to `5.0.0`" - } - ] - } - }, - { - "version": "4.4.68", - "tag": "@microsoft/web-library-build_v4.4.68", - "date": "Thu, 23 Aug 2018 18:18:53 GMT", - "comments": { - "patch": [ - { - "comment": "Republish all packages in web-build-tools to resolve GitHub issue #782" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.10` to `3.8.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.5` to `4.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.41` to `4.3.42`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.40` to `3.2.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.6` to `4.11.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.12` to `3.4.13`" - } - ] - } - }, - { - "version": "4.4.67", - "tag": "@microsoft/web-library-build_v4.4.67", - "date": "Wed, 22 Aug 2018 20:58:58 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.9` to `3.8.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.4` to `4.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.40` to `4.3.41`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.39` to `3.2.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.5` to `4.11.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.11` to `3.4.12`" - } - ] - } - }, - { - "version": "4.4.66", - "tag": "@microsoft/web-library-build_v4.4.66", - "date": "Wed, 22 Aug 2018 16:03:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.8` to `3.8.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.3` to `4.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.39` to `4.3.40`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.38` to `3.2.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.4` to `4.11.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.10` to `3.4.11`" - } - ] - } - }, - { - "version": "4.4.65", - "tag": "@microsoft/web-library-build_v4.4.65", - "date": "Tue, 21 Aug 2018 16:04:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.38` to `4.3.39`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.3` to `4.11.4`" - } - ] - } - }, - { - "version": "4.4.64", - "tag": "@microsoft/web-library-build_v4.4.64", - "date": "Thu, 09 Aug 2018 21:58:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.37` to `4.3.38`" - } - ] - } - }, - { - "version": "4.4.63", - "tag": "@microsoft/web-library-build_v4.4.63", - "date": "Thu, 09 Aug 2018 21:03:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.7` to `3.8.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.2` to `4.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.36` to `4.3.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.37` to `3.2.38`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.2` to `4.11.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.9` to `3.4.10`" - } - ] - } - }, - { - "version": "4.4.62", - "tag": "@microsoft/web-library-build_v4.4.62", - "date": "Thu, 09 Aug 2018 16:04:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.35` to `4.3.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.1` to `4.11.2`" - } - ] - } - }, - { - "version": "4.4.61", - "tag": "@microsoft/web-library-build_v4.4.61", - "date": "Tue, 07 Aug 2018 22:27:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.6` to `3.8.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.1` to `4.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.34` to `4.3.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.36` to `3.2.37`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.11.0` to `4.11.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.8` to `3.4.9`" - } - ] - } - }, - { - "version": "4.4.60", - "tag": "@microsoft/web-library-build_v4.4.60", - "date": "Thu, 26 Jul 2018 23:53:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.33` to `4.3.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.5` to `4.11.0`" - } - ] - } - }, - { - "version": "4.4.59", - "tag": "@microsoft/web-library-build_v4.4.59", - "date": "Thu, 26 Jul 2018 16:04:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.5` to `3.8.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.6.0` to `4.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.32` to `4.3.33`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.35` to `3.2.36`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.4` to `4.10.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.7` to `3.4.8`" - } - ] - } - }, - { - "version": "4.4.58", - "tag": "@microsoft/web-library-build_v4.4.58", - "date": "Wed, 25 Jul 2018 21:02:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.31` to `4.3.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.3` to `4.10.4`" - } - ] - } - }, - { - "version": "4.4.57", - "tag": "@microsoft/web-library-build_v4.4.57", - "date": "Fri, 20 Jul 2018 16:04:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.7` to `4.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.30` to `4.3.31`" - } - ] - } - }, - { - "version": "4.4.56", - "tag": "@microsoft/web-library-build_v4.4.56", - "date": "Tue, 17 Jul 2018 16:02:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.29` to `4.3.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.2` to `4.10.3`" - } - ] - } - }, - { - "version": "4.4.55", - "tag": "@microsoft/web-library-build_v4.4.55", - "date": "Fri, 13 Jul 2018 19:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.28` to `4.3.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.1` to `4.10.2`" - } - ] - } - }, - { - "version": "4.4.54", - "tag": "@microsoft/web-library-build_v4.4.54", - "date": "Tue, 03 Jul 2018 21:03:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.4` to `3.8.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.6` to `4.5.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.27` to `4.3.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.34` to `3.2.35`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.10.0` to `4.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.6` to `3.4.7`" - } - ] - } - }, - { - "version": "4.4.53", - "tag": "@microsoft/web-library-build_v4.4.53", - "date": "Fri, 29 Jun 2018 02:56:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.26` to `4.3.27`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.19` to `4.10.0`" - } - ] - } - }, - { - "version": "4.4.52", - "tag": "@microsoft/web-library-build_v4.4.52", - "date": "Sat, 23 Jun 2018 02:21:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.25` to `4.3.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.18` to `4.9.19`" - } - ] - } - }, - { - "version": "4.4.51", - "tag": "@microsoft/web-library-build_v4.4.51", - "date": "Fri, 22 Jun 2018 16:05:15 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.24` to `4.3.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.17` to `4.9.18`" - } - ] - } - }, - { - "version": "4.4.50", - "tag": "@microsoft/web-library-build_v4.4.50", - "date": "Thu, 21 Jun 2018 08:27:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.3` to `3.8.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.5` to `4.5.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.23` to `4.3.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.33` to `3.2.34`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.16` to `4.9.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.5` to `3.4.6`" - } - ] - } - }, - { - "version": "4.4.49", - "tag": "@microsoft/web-library-build_v4.4.49", - "date": "Tue, 19 Jun 2018 19:35:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.22` to `4.3.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.15` to `4.9.16`" - } - ] - } - }, - { - "version": "4.4.48", - "tag": "@microsoft/web-library-build_v4.4.48", - "date": "Wed, 13 Jun 2018 16:05:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.32` to `3.2.33`" - } - ] - } - }, - { - "version": "4.4.47", - "tag": "@microsoft/web-library-build_v4.4.47", - "date": "Fri, 08 Jun 2018 08:43:52 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.2` to `3.8.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.4` to `4.5.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.21` to `4.3.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.31` to `3.2.32`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.14` to `4.9.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.4` to `3.4.5`" - } - ] - } - }, - { - "version": "4.4.46", - "tag": "@microsoft/web-library-build_v4.4.46", - "date": "Thu, 31 May 2018 01:39:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.1` to `3.8.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.3` to `4.5.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.20` to `4.3.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.30` to `3.2.31`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.13` to `4.9.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.3` to `3.4.4`" - } - ] - } - }, - { - "version": "4.4.45", - "tag": "@microsoft/web-library-build_v4.4.45", - "date": "Tue, 15 May 2018 02:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.8.0` to `3.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.2` to `4.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.19` to `4.3.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.29` to `3.2.30`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.12` to `4.9.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.2` to `3.4.3`" - } - ] - } - }, - { - "version": "4.4.44", - "tag": "@microsoft/web-library-build_v4.4.44", - "date": "Tue, 15 May 2018 00:18:10 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.18` to `4.3.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.11` to `4.9.12`" - } - ] - } - }, - { - "version": "4.4.43", - "tag": "@microsoft/web-library-build_v4.4.43", - "date": "Fri, 11 May 2018 22:43:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.5` to `3.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.1` to `4.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.17` to `4.3.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.28` to `3.2.29`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.10` to `4.9.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.1` to `3.4.2`" - } - ] - } - }, - { - "version": "4.4.42", - "tag": "@microsoft/web-library-build_v4.4.42", - "date": "Fri, 04 May 2018 00:42:38 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.4` to `3.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.5.0` to `4.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.16` to `4.3.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.27` to `3.2.28`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.9` to `4.9.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.4.0` to `3.4.1`" - } - ] - } - }, - { - "version": "4.4.41", - "tag": "@microsoft/web-library-build_v4.4.41", - "date": "Tue, 01 May 2018 22:03:20 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.15` to `4.3.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.8` to `4.9.9`" - } - ] - } - }, - { - "version": "4.4.40", - "tag": "@microsoft/web-library-build_v4.4.40", - "date": "Mon, 30 Apr 2018 21:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.26` to `3.2.27`" - } - ] - } - }, - { - "version": "4.4.39", - "tag": "@microsoft/web-library-build_v4.4.39", - "date": "Fri, 27 Apr 2018 03:04:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.14` to `4.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.7` to `4.9.8`" - } - ] - } - }, - { - "version": "4.4.38", - "tag": "@microsoft/web-library-build_v4.4.38", - "date": "Fri, 20 Apr 2018 16:06:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.13` to `4.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.6` to `4.9.7`" - } - ] - } - }, - { - "version": "4.4.37", - "tag": "@microsoft/web-library-build_v4.4.37", - "date": "Thu, 19 Apr 2018 21:25:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.12` to `4.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.5` to `4.9.6`" - } - ] - } - }, - { - "version": "4.4.36", - "tag": "@microsoft/web-library-build_v4.4.36", - "date": "Thu, 19 Apr 2018 17:02:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.11` to `4.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.4` to `4.9.5`" - } - ] - } - }, - { - "version": "4.4.35", - "tag": "@microsoft/web-library-build_v4.4.35", - "date": "Fri, 06 Apr 2018 16:03:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.24` to `4.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.25` to `3.4.0`" - } - ] - } - }, - { - "version": "4.4.34", - "tag": "@microsoft/web-library-build_v4.4.34", - "date": "Tue, 03 Apr 2018 16:05:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.3` to `3.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.23` to `4.4.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.10` to `4.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.25` to `3.2.26`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.3` to `4.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.24` to `3.3.25`" - } - ] - } - }, - { - "version": "4.4.33", - "tag": "@microsoft/web-library-build_v4.4.33", - "date": "Mon, 02 Apr 2018 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.2` to `3.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.22` to `4.4.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.9` to `4.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.24` to `3.2.25`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.2` to `4.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.23` to `3.3.24`" - } - ] - } - }, - { - "version": "4.4.32", - "tag": "@microsoft/web-library-build_v4.4.32", - "date": "Tue, 27 Mar 2018 01:34:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.8` to `4.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.1` to `4.9.2`" - } - ] - } - }, - { - "version": "4.4.31", - "tag": "@microsoft/web-library-build_v4.4.31", - "date": "Mon, 26 Mar 2018 19:12:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.1` to `3.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.21` to `4.4.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.7` to `4.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.23` to `3.2.24`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.9.0` to `4.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.22` to `3.3.23`" - } - ] - } - }, - { - "version": "4.4.30", - "tag": "@microsoft/web-library-build_v4.4.30", - "date": "Sun, 25 Mar 2018 01:26:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.6` to `4.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.8.1` to `4.9.0`" - } - ] - } - }, - { - "version": "4.4.29", - "tag": "@microsoft/web-library-build_v4.4.29", - "date": "Fri, 23 Mar 2018 00:34:53 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.7.0` to `3.7.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.20` to `4.4.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.5` to `4.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.22` to `3.2.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.8.0` to `4.8.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.21` to `3.3.22`" - } - ] - } - }, - { - "version": "4.4.28", - "tag": "@microsoft/web-library-build_v4.4.28", - "date": "Thu, 22 Mar 2018 18:34:13 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.10` to `3.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.19` to `4.4.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.4` to `4.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.21` to `3.2.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.22` to `4.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.20` to `3.3.21`" - } - ] - } - }, - { - "version": "4.4.27", - "tag": "@microsoft/web-library-build_v4.4.27", - "date": "Tue, 20 Mar 2018 02:44:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.3` to `4.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.21` to `4.7.22`" - } - ] - } - }, - { - "version": "4.4.26", - "tag": "@microsoft/web-library-build_v4.4.26", - "date": "Sat, 17 Mar 2018 02:54:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.9` to `3.6.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.18` to `4.4.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.2` to `4.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.20` to `3.2.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.20` to `4.7.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.19` to `3.3.20`" - } - ] - } - }, - { - "version": "4.4.25", - "tag": "@microsoft/web-library-build_v4.4.25", - "date": "Thu, 15 Mar 2018 20:00:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.1` to `4.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.19` to `4.7.20`" - } - ] - } - }, - { - "version": "4.4.24", - "tag": "@microsoft/web-library-build_v4.4.24", - "date": "Thu, 15 Mar 2018 16:05:43 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.8` to `3.6.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.17` to `4.4.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.3.0` to `4.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.19` to `3.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.18` to `4.7.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.18` to `3.3.19`" - } - ] - } - }, - { - "version": "4.4.23", - "tag": "@microsoft/web-library-build_v4.4.23", - "date": "Tue, 13 Mar 2018 23:11:32 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.21` to `4.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.17` to `4.7.18`" - } - ] - } - }, - { - "version": "4.4.22", - "tag": "@microsoft/web-library-build_v4.4.22", - "date": "Mon, 12 Mar 2018 20:36:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.20` to `4.2.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.16` to `4.7.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.17` to `3.3.18`" - } - ] - } - }, - { - "version": "4.4.21", - "tag": "@microsoft/web-library-build_v4.4.21", - "date": "Tue, 06 Mar 2018 17:04:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.19` to `4.2.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.15` to `4.7.16`" - } - ] - } - }, - { - "version": "4.4.20", - "tag": "@microsoft/web-library-build_v4.4.20", - "date": "Fri, 02 Mar 2018 01:13:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.7` to `3.6.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.16` to `4.4.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.18` to `4.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.18` to `3.2.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.14` to `4.7.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.16` to `3.3.17`" - } - ] - } - }, - { - "version": "4.4.19", - "tag": "@microsoft/web-library-build_v4.4.19", - "date": "Tue, 27 Feb 2018 22:05:57 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.6` to `3.6.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.15` to `4.4.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.17` to `4.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.17` to `3.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.13` to `4.7.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.15` to `3.3.16`" - } - ] - } - }, - { - "version": "4.4.18", - "tag": "@microsoft/web-library-build_v4.4.18", - "date": "Fri, 23 Feb 2018 17:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.16` to `3.2.17`" - } - ] - } - }, - { - "version": "4.4.17", - "tag": "@microsoft/web-library-build_v4.4.17", - "date": "Wed, 21 Feb 2018 22:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.5` to `3.6.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.14` to `4.4.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.16` to `4.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.15` to `3.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.12` to `4.7.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.14` to `3.3.15`" - } - ] - } - }, - { - "version": "4.4.16", - "tag": "@microsoft/web-library-build_v4.4.16", - "date": "Wed, 21 Feb 2018 03:13:29 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.4` to `3.6.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.13` to `4.4.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.15` to `4.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.14` to `3.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.11` to `4.7.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.13` to `3.3.14`" - } - ] - } - }, - { - "version": "4.4.15", - "tag": "@microsoft/web-library-build_v4.4.15", - "date": "Sat, 17 Feb 2018 02:53:49 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.3` to `3.6.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.12` to `4.4.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.14` to `4.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.13` to `3.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.10` to `4.7.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.12` to `3.3.13`" - } - ] - } - }, - { - "version": "4.4.14", - "tag": "@microsoft/web-library-build_v4.4.14", - "date": "Fri, 16 Feb 2018 22:05:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.2` to `3.6.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.11` to `4.4.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.13` to `4.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.12` to `3.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.9` to `4.7.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.11` to `3.3.12`" - } - ] - } - }, - { - "version": "4.4.13", - "tag": "@microsoft/web-library-build_v4.4.13", - "date": "Fri, 16 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.1` to `3.6.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.10` to `4.4.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.12` to `4.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.11` to `3.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.8` to `4.7.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.10` to `3.3.11`" - } - ] - } - }, - { - "version": "4.4.12", - "tag": "@microsoft/web-library-build_v4.4.12", - "date": "Wed, 07 Feb 2018 17:05:11 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.6.0` to `3.6.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.9` to `4.4.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.11` to `4.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.10` to `3.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.7` to `4.7.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.9` to `3.3.10`" - } - ] - } - }, - { - "version": "4.4.11", - "tag": "@microsoft/web-library-build_v4.4.11", - "date": "Fri, 26 Jan 2018 22:05:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.3` to `3.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.8` to `4.4.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.10` to `4.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.9` to `3.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.6` to `4.7.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.8` to `3.3.9`" - } - ] - } - }, - { - "version": "4.4.10", - "tag": "@microsoft/web-library-build_v4.4.10", - "date": "Fri, 26 Jan 2018 17:53:38 GMT", - "comments": { - "patch": [ - { - "comment": "Force a patch bump in case the previous version was an empty package" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.7` to `4.4.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.9` to `4.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.5` to `4.7.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.7` to `3.3.8`" - } - ] - } - }, - { - "version": "4.4.9", - "tag": "@microsoft/web-library-build_v4.4.9", - "date": "Fri, 26 Jan 2018 00:36:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.6` to `4.4.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.8` to `4.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.4` to `4.7.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.6` to `3.3.7`" - } - ] - } - }, - { - "version": "4.4.8", - "tag": "@microsoft/web-library-build_v4.4.8", - "date": "Tue, 23 Jan 2018 17:05:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.5` to `4.4.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.7` to `4.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.3` to `4.7.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.5` to `3.3.6`" - } - ] - } - }, - { - "version": "4.4.7", - "tag": "@microsoft/web-library-build_v4.4.7", - "date": "Sat, 20 Jan 2018 02:39:16 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.6` to `4.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.5` to `3.2.6`" - } - ] - } - }, - { - "version": "4.4.6", - "tag": "@microsoft/web-library-build_v4.4.6", - "date": "Thu, 18 Jan 2018 03:23:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.4` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.4` to `4.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.5` to `4.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.2` to `4.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.4` to `3.3.5`" - } - ] - } - }, - { - "version": "4.4.5", - "tag": "@microsoft/web-library-build_v4.4.5", - "date": "Thu, 18 Jan 2018 00:48:06 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.3` to `3.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.3` to `4.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.4` to `4.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.1` to `4.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.3` to `3.3.4`" - } - ] - } - }, - { - "version": "4.4.4", - "tag": "@microsoft/web-library-build_v4.4.4", - "date": "Thu, 18 Jan 2018 00:27:23 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.3` to `4.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.7.0` to `4.7.1`" - } - ] - } - }, - { - "version": "4.4.3", - "tag": "@microsoft/web-library-build_v4.4.3", - "date": "Wed, 17 Jan 2018 10:49:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.2` to `3.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.2` to `4.4.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.2` to `4.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.6.0` to `4.7.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.2` to `3.3.3`" - } - ] - } - }, - { - "version": "4.4.2", - "tag": "@microsoft/web-library-build_v4.4.2", - "date": "Fri, 12 Jan 2018 03:35:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.1` to `4.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.1` to `4.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.5.1` to `4.6.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.1` to `3.3.2`" - } - ] - } - }, - { - "version": "4.4.1", - "tag": "@microsoft/web-library-build_v4.4.1", - "date": "Thu, 11 Jan 2018 22:31:51 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.4.0` to `4.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.2.0` to `4.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.5.0` to `4.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.3.0` to `3.3.1`" - } - ] - } - }, - { - "version": "4.4.0", - "tag": "@microsoft/web-library-build_v4.4.0", - "date": "Wed, 10 Jan 2018 20:40:01 GMT", - "comments": { - "minor": [ - { - "author": "Nicholas Pape ", - "commit": "1271a0dc21fedb882e7953f491771724f80323a1", - "comment": "Upgrade to Node 8" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.7` to `3.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.16` to `4.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.24` to `4.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.24` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.4.1` to `4.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.24` to `3.3.0`" - } - ] - } - }, - { - "version": "4.3.0", - "tag": "@microsoft/web-library-build_v4.3.0", - "date": "Sun, 07 Jan 2018 05:12:08 GMT", - "comments": { - "minor": [ - { - "author": "pgonzal ", - "commit": "aa0c67382d4dee0cde40ee84a581dbdcdabe77ef", - "comment": "api-extractor now runs after tsc rather than in parallel, and is excluded from \"gulp serve\"" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.5` to `3.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.14` to `4.3.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.22` to `4.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.22` to `3.1.23`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.3` to `4.4.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.22` to `3.2.23`" - } - ] - } - }, - { - "version": "4.2.16", - "tag": "@microsoft/web-library-build_v4.2.16", - "date": "Fri, 05 Jan 2018 20:26:45 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.4` to `3.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.13` to `4.3.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.21` to `4.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.21` to `3.1.22`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.2` to `4.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.21` to `3.2.22`" - } - ] - } - }, - { - "version": "4.2.15", - "tag": "@microsoft/web-library-build_v4.2.15", - "date": "Fri, 05 Jan 2018 00:48:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.3` to `3.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.12` to `4.3.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.20` to `4.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.20` to `3.1.21`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.1` to `4.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.20` to `3.2.21`" - } - ] - } - }, - { - "version": "4.2.14", - "tag": "@microsoft/web-library-build_v4.2.14", - "date": "Fri, 22 Dec 2017 17:04:46 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.2` to `3.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.11` to `4.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.19` to `4.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.19` to `3.1.20`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.3.0` to `4.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.19` to `3.2.20`" - } - ] - } - }, - { - "version": "4.2.13", - "tag": "@microsoft/web-library-build_v4.2.13", - "date": "Tue, 12 Dec 2017 03:33:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.10` to `4.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.18` to `4.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.18` to `3.1.19`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.18` to `4.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.18` to `3.2.19`" - } - ] - } - }, - { - "version": "4.2.12", - "tag": "@microsoft/web-library-build_v4.2.12", - "date": "Thu, 30 Nov 2017 23:59:09 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.9` to `4.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.17` to `4.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.17` to `3.1.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.17` to `4.2.18`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.17` to `3.2.18`" - } - ] - } - }, - { - "version": "4.2.11", - "tag": "@microsoft/web-library-build_v4.2.11", - "date": "Thu, 30 Nov 2017 23:12:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.9` to `3.3.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.8` to `4.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.16` to `4.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.16` to `3.1.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.16` to `4.2.17`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.16` to `3.2.17`" - } - ] - } - }, - { - "version": "4.2.10", - "tag": "@microsoft/web-library-build_v4.2.10", - "date": "Wed, 29 Nov 2017 17:05:37 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.7` to `4.3.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.15` to `4.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.15` to `3.1.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.15` to `4.2.16`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.15` to `3.2.16`" - } - ] - } - }, - { - "version": "4.2.9", - "tag": "@microsoft/web-library-build_v4.2.9", - "date": "Tue, 28 Nov 2017 23:43:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.6` to `4.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.14` to `4.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.14` to `3.1.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.14` to `4.2.15`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.14` to `3.2.15`" - } - ] - } - }, - { - "version": "4.2.8", - "tag": "@microsoft/web-library-build_v4.2.8", - "date": "Mon, 13 Nov 2017 17:04:50 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.5` to `4.3.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.13` to `4.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.13` to `3.1.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.13` to `4.2.14`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.13` to `3.2.14`" - } - ] - } - }, - { - "version": "4.2.7", - "tag": "@microsoft/web-library-build_v4.2.7", - "date": "Mon, 06 Nov 2017 17:04:18 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.4` to `4.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.12` to `4.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.12` to `3.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.12` to `4.2.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.12` to `3.2.13`" - } - ] - } - }, - { - "version": "4.2.6", - "tag": "@microsoft/web-library-build_v4.2.6", - "date": "Thu, 02 Nov 2017 16:05:24 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.3` to `4.3.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.11` to `4.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.11` to `3.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.11` to `4.2.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.11` to `3.2.12`" - } - ] - } - }, - { - "version": "4.2.5", - "tag": "@microsoft/web-library-build_v4.2.5", - "date": "Wed, 01 Nov 2017 21:06:08 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.3` to `3.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.2` to `4.3.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.10` to `4.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.10` to `3.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.10` to `4.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.10` to `3.2.11`" - } - ] - } - }, - { - "version": "4.2.4", - "tag": "@microsoft/web-library-build_v4.2.4", - "date": "Tue, 31 Oct 2017 21:04:04 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.1` to `4.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.9` to `4.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.9` to `3.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.9` to `4.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.9` to `3.2.10`" - } - ] - } - }, - { - "version": "4.2.3", - "tag": "@microsoft/web-library-build_v4.2.3", - "date": "Tue, 31 Oct 2017 16:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.1` to `3.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.3.0` to `4.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.8` to `4.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.8` to `3.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.8` to `4.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.8` to `3.2.9`" - } - ] - } - }, - { - "version": "4.2.2", - "tag": "@microsoft/web-library-build_v4.2.2", - "date": "Thu, 26 Oct 2017 00:00:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.2.1` to `4.3.0`" - } - ] - } - }, - { - "version": "4.2.1", - "tag": "@microsoft/web-library-build_v4.2.1", - "date": "Wed, 25 Oct 2017 20:03:59 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.2.0` to `3.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.2.0` to `4.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.7` to `4.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.7` to `3.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.7` to `4.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.7` to `3.2.8`" - } - ] - } - }, - { - "version": "4.2.0", - "tag": "@microsoft/web-library-build_v4.2.0", - "date": "Tue, 24 Oct 2017 18:17:12 GMT", - "comments": { - "minor": [ - { - "author": "QZ ", - "commit": "5fe47765dbb3567bebc30cf5d7ac2205f6e655b0", - "comment": "Support Jest task" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.6` to `3.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.6` to `4.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.6` to `4.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.6` to `3.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.6` to `4.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.6` to `3.2.7`" - } - ] - } - }, - { - "version": "4.1.6", - "tag": "@microsoft/web-library-build_v4.1.6", - "date": "Mon, 23 Oct 2017 21:53:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.5` to `3.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.5` to `4.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.5` to `4.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.5` to `3.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.5` to `4.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.5` to `3.2.6`" - } - ] - } - }, - { - "version": "4.1.5", - "tag": "@microsoft/web-library-build_v4.1.5", - "date": "Fri, 20 Oct 2017 19:57:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.4` to `3.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.4` to `4.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.4` to `4.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.4` to `3.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.4` to `4.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.4` to `3.2.5`" - } - ] - } - }, - { - "version": "4.1.4", - "tag": "@microsoft/web-library-build_v4.1.4", - "date": "Fri, 20 Oct 2017 01:52:54 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.3` to `3.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.3` to `4.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.3` to `4.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.3` to `3.1.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.3` to `4.2.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "4.1.3", - "tag": "@microsoft/web-library-build_v4.1.3", - "date": "Fri, 20 Oct 2017 01:04:44 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.2` to `3.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.2` to `4.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.2` to `4.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.2` to `3.1.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.2` to `4.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.2` to `3.2.3`" - } - ] - } - }, - { - "version": "4.1.2", - "tag": "@microsoft/web-library-build_v4.1.2", - "date": "Thu, 05 Oct 2017 01:05:02 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.1` to `3.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.1` to `4.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.1` to `4.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.1` to `3.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.1` to `4.2.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.1` to `3.2.2`" - } - ] - } - }, - { - "version": "4.1.1", - "tag": "@microsoft/web-library-build_v4.1.1", - "date": "Thu, 28 Sep 2017 01:04:28 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.1.0` to `3.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.1.0` to `4.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.1.0` to `4.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.1.0` to `3.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.2.0` to `4.2.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.2.0` to `3.2.1`" - } - ] - } - }, - { - "version": "4.1.0", - "tag": "@microsoft/web-library-build_v4.1.0", - "date": "Fri, 22 Sep 2017 01:04:02 GMT", - "comments": { - "minor": [ - { - "author": "Nick Pape ", - "commit": "481a10f460a454fb5a3e336e3cf25a1c3f710645", - "comment": "Upgrade to es6" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.9` to `4.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.8` to `4.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.8` to `3.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.1.0` to `4.2.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.1.0` to `3.2.0`" - } - ] - } - }, - { - "version": "4.0.9", - "tag": "@microsoft/web-library-build_v4.0.9", - "date": "Thu, 21 Sep 2017 20:34:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.8` to `4.0.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.8` to `3.1.0`" - } - ] - } - }, - { - "version": "4.0.8", - "tag": "@microsoft/web-library-build_v4.0.8", - "date": "Wed, 20 Sep 2017 22:10:17 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.7` to `3.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.7` to `4.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.7` to `4.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.7` to `3.0.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.7` to `4.1.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.7` to `3.0.8`" - } - ] - } - }, - { - "version": "4.0.7", - "tag": "@microsoft/web-library-build_v4.0.7", - "date": "Mon, 11 Sep 2017 13:04:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.6` to `3.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.6` to `4.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.6` to `4.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.6` to `3.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.6` to `4.0.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.6` to `3.0.7`" - } - ] - } - }, - { - "version": "4.0.6", - "tag": "@microsoft/web-library-build_v4.0.6", - "date": "Fri, 08 Sep 2017 01:28:04 GMT", - "comments": { - "patch": [ - { - "author": "Nick Pape ", - "commit": "bb96549aa8508ff627a0cae5ee41ae0251f2777d", - "comment": "Deprecate @types/es6-collections in favor of built-in typescript typings 'es2015.collection' and 'es2015.iterable'" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.5` to `3.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.5` to `4.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.5` to `4.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.5` to `3.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.5` to `4.0.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.5` to `3.0.6`" - } - ] - } - }, - { - "version": "4.0.5", - "tag": "@microsoft/web-library-build_v4.0.5", - "date": "Thu, 07 Sep 2017 13:04:35 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.4` to `3.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.4` to `4.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.4` to `4.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.4` to `3.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.4` to `4.0.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.4` to `3.0.5`" - } - ] - } - }, - { - "version": "4.0.4", - "tag": "@microsoft/web-library-build_v4.0.4", - "date": "Thu, 07 Sep 2017 00:11:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.3` to `3.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.3` to `4.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.3` to `4.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.3` to `3.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.3` to `4.0.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.3` to `3.0.4`" - } - ] - } - }, - { - "version": "4.0.3", - "tag": "@microsoft/web-library-build_v4.0.3", - "date": "Wed, 06 Sep 2017 13:03:42 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.2` to `3.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.2` to `4.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.2` to `4.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.2` to `3.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.2` to `4.0.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.2` to `3.0.3`" - } - ] - } - }, - { - "version": "4.0.2", - "tag": "@microsoft/web-library-build_v4.0.2", - "date": "Tue, 05 Sep 2017 19:03:56 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.1` to `3.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.1` to `4.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.1` to `4.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.1` to `3.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.1` to `4.0.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.1` to `3.0.2`" - } - ] - } - }, - { - "version": "4.0.1", - "tag": "@microsoft/web-library-build_v4.0.1", - "date": "Sat, 02 Sep 2017 01:04:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `4.0.0` to `4.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `4.0.0` to `4.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `4.0.0` to `4.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `3.0.0` to `3.0.1`" - } - ] - } - }, - { - "version": "4.0.0", - "tag": "@microsoft/web-library-build_v4.0.0", - "date": "Thu, 31 Aug 2017 18:41:18 GMT", - "comments": { - "major": [ - { - "comment": "Fix compatibility issues with old releases, by incrementing the major version number" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.1` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `3.0.1` to `4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.11` to `4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.13` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.3` to `4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `2.0.2` to `3.0.0`" - } - ] - } - }, - { - "version": "3.2.16", - "tag": "@microsoft/web-library-build_v3.2.16", - "date": "Thu, 31 Aug 2017 17:46:25 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.10.0` to `2.10.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `3.0.0` to `3.0.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.10` to `3.2.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.12` to `2.1.13`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.2` to `3.5.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `2.0.1` to `2.0.2`" - } - ] - } - }, - { - "version": "3.2.15", - "tag": "@microsoft/web-library-build_v3.2.15", - "date": "Thu, 31 Aug 2017 13:04:19 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `2.0.0` to `2.0.1`" - } - ] - } - }, - { - "version": "3.2.14", - "tag": "@microsoft/web-library-build_v3.2.14", - "date": "Wed, 30 Aug 2017 22:08:21 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.12` to `3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.9` to `2.0.0`" - } - ] - } - }, - { - "version": "3.2.13", - "tag": "@microsoft/web-library-build_v3.2.13", - "date": "Wed, 30 Aug 2017 01:04:34 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.6` to `2.10.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.11` to `2.3.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.9` to `3.2.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.11` to `2.1.12`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.1` to `3.5.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.8` to `1.2.9`" - } - ] - } - }, - { - "version": "3.2.12", - "tag": "@microsoft/web-library-build_v3.2.12", - "date": "Thu, 24 Aug 2017 22:44:12 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.5` to `2.9.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.10` to `2.3.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.8` to `3.2.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.10` to `2.1.11`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.5.0` to `3.5.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.7` to `1.2.8`" - } - ] - } - }, - { - "version": "3.2.11", - "tag": "@microsoft/web-library-build_v3.2.11", - "date": "Thu, 24 Aug 2017 01:04:33 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.4` to `2.9.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.9` to `2.3.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.7` to `3.2.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.9` to `2.1.10`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.4.2` to `3.5.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.6` to `1.2.7`" - } - ] - } - }, - { - "version": "3.2.10", - "tag": "@microsoft/web-library-build_v3.2.10", - "date": "Tue, 22 Aug 2017 13:04:22 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.3` to `2.9.4`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.8` to `2.3.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.6` to `3.2.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.8` to `2.1.9`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.4.1` to `3.4.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.5` to `1.2.6`" - } - ] - } - }, - { - "version": "3.2.9", - "tag": "@microsoft/web-library-build_v3.2.9", - "date": "Wed, 16 Aug 2017 23:16:55 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.5` to `3.2.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.7` to `2.1.8`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.4.0` to `3.4.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.4` to `1.2.5`" - } - ] - } - }, - { - "version": "3.2.8", - "tag": "@microsoft/web-library-build_v3.2.8", - "date": "Tue, 15 Aug 2017 19:04:14 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.2` to `2.9.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.7` to `2.3.8`" - } - ] - } - }, - { - "version": "3.2.7", - "tag": "@microsoft/web-library-build_v3.2.7", - "date": "Tue, 15 Aug 2017 01:29:31 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.1` to `2.9.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.6` to `2.3.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.4` to `3.2.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.6` to `2.1.7`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.3.1` to `3.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.3` to `1.2.4`" - } - ] - } - }, - { - "version": "3.2.6", - "tag": "@microsoft/web-library-build_v3.2.6", - "date": "Sat, 12 Aug 2017 01:03:30 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.9.0` to `2.9.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.5` to `2.3.6`" - } - ] - } - }, - { - "version": "3.2.5", - "tag": "@microsoft/web-library-build_v3.2.5", - "date": "Fri, 11 Aug 2017 21:44:05 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.8.0` to `2.9.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.4` to `2.3.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.5` to `2.1.6`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.2` to `1.2.3`" - } - ] - } - }, - { - "version": "3.2.4", - "tag": "@microsoft/web-library-build_v3.2.4", - "date": "Tue, 08 Aug 2017 23:10:36 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.3` to `3.2.4`" - } - ] - } - }, - { - "version": "3.2.3", - "tag": "@microsoft/web-library-build_v3.2.3", - "date": "Sat, 05 Aug 2017 01:04:41 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.3` to `2.8.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.3` to `2.3.4`" - } - ] - } - }, - { - "version": "3.2.2", - "tag": "@microsoft/web-library-build_v3.2.2", - "date": "Mon, 31 Jul 2017 21:18:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.2` to `2.7.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.2` to `2.3.3`" - } - ] - } - }, - { - "version": "3.2.1", - "tag": "@microsoft/web-library-build_v3.2.1", - "date": "Thu, 27 Jul 2017 01:04:48 GMT", - "comments": { - "patch": [ - { - "comment": "Upgrade to the TS2.4 version of the build tools and restrict the dependency version requirements." - }, - { - "comment": "Fix an issue with 'gulp serve' where the server was not being launched." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `2.7.1` to `2.7.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `2.3.1` to `2.3.2`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `3.2.2` to `3.2.3`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `2.1.4` to `2.1.5`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `3.3.0` to `3.3.1`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `1.2.1` to `1.2.2`" - } - ] - } - }, - { - "version": "3.2.0", - "tag": "@microsoft/web-library-build_v3.2.0", - "date": "Tue, 25 Jul 2017 20:03:31 GMT", - "comments": { - "minor": [ - { - "comment": "Upgrade to TypeScript 2.4" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.7.0 <3.0.0` to `>=2.7.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.3.0 <3.0.0` to `>=2.3.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=3.2.1 <4.0.0` to `>=3.2.2 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `>=2.1.3 <3.0.0` to `>=2.1.4 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.2.0 <4.0.0` to `>=3.3.0 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `>=1.2.0 <2.0.0` to `>=1.2.1 <2.0.0`" - } - ] - } - }, - { - "version": "3.1.0", - "tag": "@microsoft/web-library-build_v3.1.0", - "date": "Fri, 07 Jul 2017 01:02:28 GMT", - "comments": { - "minor": [ - { - "comment": "Enable StrictNullChecks." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.6 <3.0.0` to `>=2.5.6 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.2.3 <3.0.0` to `>=2.3.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=3.1.0 <4.0.0` to `>=3.2.0 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.1.5 <4.0.0` to `>=3.2.0 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `>=1.1.8 <2.0.0` to `>=1.2.0 <2.0.0`" - } - ] - } - }, - { - "version": "3.0.3", - "tag": "@microsoft/web-library-build_v3.0.3", - "date": "Thu, 29 Jun 2017 01:05:37 GMT", - "comments": { - "patch": [ - { - "comment": "Fix an issue with 'gulp serve' where an initial build error would stop watch from continuing" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.5.5 <3.0.0` to `>=2.5.6 <3.0.0`" - } - ] - } - }, - { - "version": "3.0.2", - "tag": "@microsoft/web-library-build_v3.0.2", - "date": "Tue, 16 May 2017 00:01:03 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unnecessary fsevents optional dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `>=2.1.2 <3.0.0` to `>=2.1.3 <3.0.0`" - } - ] - } - }, - { - "version": "3.0.1", - "tag": "@microsoft/web-library-build_v3.0.1", - "date": "Wed, 19 Apr 2017 20:18:06 GMT", - "comments": { - "patch": [ - { - "comment": "Remove ES6 Promise & @types/es6-promise typings" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.3 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.2.0 <3.0.0` to `>=2.2.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=3.1.0 <4.0.0` to `>=3.1.0 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `>=2.1.0 <3.0.0` to `>=2.1.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=3.0.3 <4.0.0` to `>=3.0.3 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `>=1.1.2 <2.0.0` to `>=1.1.3 <2.0.0`" - } - ] - } - }, - { - "version": "3.0.0", - "tag": "@microsoft/web-library-build_v3.0.0", - "date": "Mon, 20 Mar 2017 21:52:20 GMT", - "comments": { - "major": [ - { - "comment": "Updating build task dependencies." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.2 <3.0.0` to `>=2.4.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=2.0.8 <3.0.0` to `>=3.0.0 <4.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.4.1 <3.0.0` to `>=3.0.0 <4.0.0`" - } - ] - } - }, - { - "version": "2.3.2", - "tag": "@microsoft/web-library-build_v2.3.2", - "date": "Wed, 15 Mar 2017 01:32:09 GMT", - "comments": { - "patch": [ - { - "comment": "Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.4.0 <3.0.0` to `>=2.4.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.2.0 <3.0.0` to `>=2.2.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=2.0.5 <3.0.0` to `>=2.0.5 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `>=2.0.3 <3.0.0` to `>=2.0.3 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.2.5 <3.0.0` to `>=2.2.5 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `>=1.1.2 <2.0.0` to `>=1.1.2 <2.0.0`" - } - ] - } - }, - { - "version": "2.3.1", - "tag": "@microsoft/web-library-build_v2.3.1", - "date": "Fri, 03 Mar 2017 02:31:24 GMT", - "comments": { - "patch": [ - { - "comment": "Restore TS Lint task in gulp build" - } - ] - } - }, - { - "version": "2.3.0", - "tag": "@microsoft/web-library-build_v2.3.0", - "date": "Wed, 08 Feb 2017 01:41:58 GMT", - "comments": { - "minor": [ - { - "comment": "Treat warnings as errors in production. Treat tslint errors as warnings." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.2.3 <3.0.0` to `>=2.3.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.2.2", - "tag": "@microsoft/web-library-build_v2.2.2", - "date": "Tue, 07 Feb 2017 02:33:34 GMT", - "comments": { - "patch": [ - { - "comment": "Remove unused dependency" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.1.1 <3.0.0` to `>=2.2.1 <3.0.0`" - } - ] - } - }, - { - "version": "2.2.1", - "tag": "@microsoft/web-library-build_v2.2.1", - "date": "Fri, 27 Jan 2017 23:27:42 GMT", - "comments": { - "patch": [ - { - "comment": "Refactor the build task to not run \"text\" subtask twice." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.0.2 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - }, - { - "version": "2.2.0", - "tag": "@microsoft/web-library-build_v2.2.0", - "date": "Fri, 20 Jan 2017 01:46:41 GMT", - "comments": { - "minor": [ - { - "comment": "Run the api-extractor task during the default build." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.1.0 <3.0.0` to `>=2.1.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.0.0 <3.0.0` to `>=2.0.2 <3.0.0`" - } - ] - } - }, - { - "version": "2.1.0", - "tag": "@microsoft/web-library-build_v2.1.0", - "date": "Fri, 13 Jan 2017 06:46:05 GMT", - "comments": { - "minor": [ - { - "comment": "Enable the ApiExtractor task from gulp-core-build-typescript." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build\" from `>=2.0.0 <3.0.0` to `>=2.0.1 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-karma\" from `>=2.0.0 <3.0.0` to `>=2.0.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-sass\" from `>=2.0.0 <3.0.0` to `>=2.0.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-serve\" from `>=2.0.0 <3.0.0` to `>=2.0.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.1.0 <3.0.0` to `>=2.1.0 <3.0.0`" - }, - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-webpack\" from `>=1.0.3 <2.0.0` to `>=1.0.3 <2.0.0`" - } - ] - } - }, - { - "version": "2.0.0", - "tag": "@microsoft/web-library-build_v2.0.0", - "date": "Wed, 11 Jan 2017 14:11:26 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@microsoft/gulp-core-build-typescript\" from `>=2.0.1 <3.0.0` to `>=2.1.0 <3.0.0`" - } - ] - } - } - ] -} diff --git a/core-build/web-library-build/CHANGELOG.md b/core-build/web-library-build/CHANGELOG.md deleted file mode 100644 index 74bddde6408..00000000000 --- a/core-build/web-library-build/CHANGELOG.md +++ /dev/null @@ -1,1534 +0,0 @@ -# Change Log - @microsoft/web-library-build - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 7.4.6 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 7.4.5 -Tue, 17 Mar 2020 23:55:58 GMT - -*Version update only* - -## 7.4.4 -Tue, 28 Jan 2020 02:23:44 GMT - -*Version update only* - -## 7.4.3 -Fri, 24 Jan 2020 00:27:39 GMT - -*Version update only* - -## 7.4.2 -Thu, 23 Jan 2020 01:07:56 GMT - -*Version update only* - -## 7.4.1 -Tue, 21 Jan 2020 21:56:13 GMT - -*Version update only* - -## 7.4.0 -Sun, 19 Jan 2020 02:26:53 GMT - -### Minor changes - -- Upgrade Node typings to Node 10 - -## 7.3.18 -Fri, 17 Jan 2020 01:08:23 GMT - -*Version update only* - -## 7.3.17 -Tue, 14 Jan 2020 01:34:15 GMT - -*Version update only* - -## 7.3.16 -Sat, 11 Jan 2020 05:18:23 GMT - -*Version update only* - -## 7.3.15 -Fri, 10 Jan 2020 03:07:47 GMT - -*Version update only* - -## 7.3.14 -Thu, 09 Jan 2020 06:44:12 GMT - -*Version update only* - -## 7.3.13 -Wed, 08 Jan 2020 00:11:31 GMT - -*Version update only* - -## 7.3.12 -Mon, 23 Dec 2019 16:08:05 GMT - -*Version update only* - -## 7.3.11 -Wed, 04 Dec 2019 23:17:55 GMT - -*Version update only* - -## 7.3.10 -Tue, 03 Dec 2019 03:17:44 GMT - -*Version update only* - -## 7.3.9 -Sun, 24 Nov 2019 00:54:04 GMT - -*Version update only* - -## 7.3.8 -Wed, 20 Nov 2019 06:14:28 GMT - -*Version update only* - -## 7.3.7 -Fri, 15 Nov 2019 04:50:50 GMT - -*Version update only* - -## 7.3.6 -Mon, 11 Nov 2019 16:07:56 GMT - -*Version update only* - -## 7.3.5 -Wed, 06 Nov 2019 22:44:18 GMT - -*Version update only* - -## 7.3.4 -Tue, 05 Nov 2019 06:49:28 GMT - -*Version update only* - -## 7.3.3 -Tue, 05 Nov 2019 01:08:39 GMT - -*Version update only* - -## 7.3.2 -Fri, 25 Oct 2019 15:08:54 GMT - -*Version update only* - -## 7.3.1 -Tue, 22 Oct 2019 06:24:44 GMT - -*Version update only* - -## 7.3.0 -Mon, 21 Oct 2019 05:22:43 GMT - -### Minor changes - -- Add support for ESLint+TypeScript - -## 7.2.7 -Fri, 18 Oct 2019 15:15:01 GMT - -*Version update only* - -## 7.2.6 -Mon, 07 Oct 2019 20:15:00 GMT - -*Version update only* - -## 7.2.5 -Sun, 06 Oct 2019 00:27:39 GMT - -*Version update only* - -## 7.2.4 -Fri, 04 Oct 2019 00:15:22 GMT - -*Version update only* - -## 7.2.3 -Sun, 29 Sep 2019 23:56:29 GMT - -### Patches - -- Update repository URL - -## 7.2.2 -Wed, 25 Sep 2019 15:15:31 GMT - -*Version update only* - -## 7.2.1 -Tue, 24 Sep 2019 02:58:49 GMT - -*Version update only* - -## 7.2.0 -Mon, 23 Sep 2019 15:14:55 GMT - -### Minor changes - -- Upgrade @types/node dependency - -## 7.1.12 -Fri, 20 Sep 2019 21:27:22 GMT - -*Version update only* - -## 7.1.11 -Wed, 11 Sep 2019 19:56:23 GMT - -*Version update only* - -## 7.1.10 -Tue, 10 Sep 2019 22:32:23 GMT - -*Version update only* - -## 7.1.9 -Tue, 10 Sep 2019 20:38:33 GMT - -*Version update only* - -## 7.1.8 -Wed, 04 Sep 2019 18:28:06 GMT - -*Version update only* - -## 7.1.7 -Wed, 04 Sep 2019 15:15:37 GMT - -*Version update only* - -## 7.1.6 -Wed, 04 Sep 2019 01:43:31 GMT - -*Version update only* - -## 7.1.5 -Fri, 30 Aug 2019 00:14:32 GMT - -*Version update only* - -## 7.1.4 -Mon, 12 Aug 2019 15:15:14 GMT - -*Version update only* - -## 7.1.3 -Thu, 08 Aug 2019 15:14:17 GMT - -*Version update only* - -## 7.1.2 -Thu, 08 Aug 2019 00:49:05 GMT - -*Version update only* - -## 7.1.1 -Mon, 05 Aug 2019 22:04:32 GMT - -*Version update only* - -## 7.1.0 -Tue, 23 Jul 2019 19:14:38 GMT - -### Minor changes - -- Update gulp to 4.0.2. - -## 7.0.52 -Tue, 23 Jul 2019 01:13:01 GMT - -*Version update only* - -## 7.0.51 -Mon, 22 Jul 2019 19:13:10 GMT - -*Version update only* - -## 7.0.50 -Fri, 12 Jul 2019 19:12:46 GMT - -*Version update only* - -## 7.0.49 -Thu, 11 Jul 2019 19:13:08 GMT - -*Version update only* - -## 7.0.48 -Tue, 09 Jul 2019 19:13:24 GMT - -*Version update only* - -## 7.0.47 -Mon, 08 Jul 2019 19:12:18 GMT - -*Version update only* - -## 7.0.46 -Sat, 29 Jun 2019 02:30:10 GMT - -*Version update only* - -## 7.0.45 -Wed, 12 Jun 2019 19:12:33 GMT - -*Version update only* - -## 7.0.44 -Tue, 11 Jun 2019 00:48:06 GMT - -*Version update only* - -## 7.0.43 -Thu, 06 Jun 2019 22:33:36 GMT - -*Version update only* - -## 7.0.42 -Wed, 05 Jun 2019 19:12:34 GMT - -*Version update only* - -## 7.0.41 -Tue, 04 Jun 2019 05:51:54 GMT - -*Version update only* - -## 7.0.40 -Fri, 31 May 2019 01:13:07 GMT - -*Version update only* - -## 7.0.39 -Mon, 27 May 2019 04:13:44 GMT - -*Version update only* - -## 7.0.38 -Mon, 13 May 2019 02:08:35 GMT - -*Version update only* - -## 7.0.37 -Thu, 09 May 2019 19:12:31 GMT - -*Version update only* - -## 7.0.36 -Mon, 06 May 2019 20:46:21 GMT - -*Version update only* - -## 7.0.35 -Mon, 06 May 2019 19:34:54 GMT - -*Version update only* - -## 7.0.34 -Mon, 06 May 2019 19:11:16 GMT - -*Version update only* - -## 7.0.33 -Tue, 30 Apr 2019 23:08:02 GMT - -*Version update only* - -## 7.0.32 -Tue, 16 Apr 2019 11:01:37 GMT - -*Version update only* - -## 7.0.31 -Fri, 12 Apr 2019 06:13:17 GMT - -*Version update only* - -## 7.0.30 -Thu, 11 Apr 2019 07:14:01 GMT - -*Version update only* - -## 7.0.29 -Tue, 09 Apr 2019 05:31:01 GMT - -*Version update only* - -## 7.0.28 -Mon, 08 Apr 2019 19:12:52 GMT - -*Version update only* - -## 7.0.27 -Sat, 06 Apr 2019 02:05:51 GMT - -*Version update only* - -## 7.0.26 -Fri, 05 Apr 2019 04:16:17 GMT - -*Version update only* - -## 7.0.25 -Wed, 03 Apr 2019 02:58:33 GMT - -*Version update only* - -## 7.0.24 -Tue, 02 Apr 2019 01:12:02 GMT - -*Version update only* - -## 7.0.23 -Sat, 30 Mar 2019 22:27:16 GMT - -*Version update only* - -## 7.0.22 -Thu, 28 Mar 2019 19:14:27 GMT - -*Version update only* - -## 7.0.21 -Tue, 26 Mar 2019 20:54:18 GMT - -*Version update only* - -## 7.0.20 -Sat, 23 Mar 2019 03:48:31 GMT - -*Version update only* - -## 7.0.19 -Thu, 21 Mar 2019 04:59:11 GMT - -*Version update only* - -## 7.0.18 -Thu, 21 Mar 2019 01:15:32 GMT - -*Version update only* - -## 7.0.17 -Wed, 20 Mar 2019 19:14:49 GMT - -*Version update only* - -## 7.0.16 -Mon, 18 Mar 2019 04:28:43 GMT - -*Version update only* - -## 7.0.15 -Fri, 15 Mar 2019 19:13:25 GMT - -*Version update only* - -## 7.0.14 -Wed, 13 Mar 2019 19:13:14 GMT - -*Version update only* - -## 7.0.13 -Wed, 13 Mar 2019 01:14:05 GMT - -*Version update only* - -## 7.0.12 -Mon, 11 Mar 2019 16:13:36 GMT - -*Version update only* - -## 7.0.11 -Tue, 05 Mar 2019 17:13:11 GMT - -*Version update only* - -## 7.0.10 -Mon, 04 Mar 2019 17:13:19 GMT - -*Version update only* - -## 7.0.9 -Wed, 27 Feb 2019 22:13:58 GMT - -*Version update only* - -## 7.0.8 -Wed, 27 Feb 2019 17:13:17 GMT - -*Version update only* - -## 7.0.7 -Mon, 18 Feb 2019 17:13:23 GMT - -*Version update only* - -## 7.0.6 -Tue, 12 Feb 2019 17:13:12 GMT - -*Version update only* - -## 7.0.5 -Mon, 11 Feb 2019 10:32:37 GMT - -*Version update only* - -## 7.0.4 -Mon, 11 Feb 2019 03:31:55 GMT - -*Version update only* - -## 7.0.3 -Wed, 30 Jan 2019 20:49:12 GMT - -*Version update only* - -## 7.0.2 -Mon, 21 Jan 2019 17:04:11 GMT - -*Version update only* - -## 7.0.1 -Sat, 19 Jan 2019 03:47:47 GMT - -*Version update only* - -## 7.0.0 -Tue, 15 Jan 2019 17:04:09 GMT - -### Breaking changes - -- Remove karma task. - -## 6.0.45 -Thu, 10 Jan 2019 01:57:53 GMT - -*Version update only* - -## 6.0.44 -Mon, 07 Jan 2019 17:04:07 GMT - -*Version update only* - -## 6.0.43 -Wed, 19 Dec 2018 05:57:33 GMT - -*Version update only* - -## 6.0.42 -Fri, 14 Dec 2018 20:51:51 GMT - -*Version update only* - -## 6.0.41 -Thu, 13 Dec 2018 02:58:10 GMT - -*Version update only* - -## 6.0.40 -Wed, 12 Dec 2018 17:04:19 GMT - -*Version update only* - -## 6.0.39 -Sat, 08 Dec 2018 06:35:36 GMT - -*Version update only* - -## 6.0.38 -Fri, 07 Dec 2018 17:04:56 GMT - -*Version update only* - -## 6.0.37 -Mon, 03 Dec 2018 17:04:06 GMT - -*Version update only* - -## 6.0.36 -Fri, 30 Nov 2018 23:34:57 GMT - -*Version update only* - -## 6.0.35 -Thu, 29 Nov 2018 07:02:09 GMT - -*Version update only* - -## 6.0.34 -Thu, 29 Nov 2018 00:35:39 GMT - -*Version update only* - -## 6.0.33 -Wed, 28 Nov 2018 19:29:53 GMT - -*Version update only* - -## 6.0.32 -Wed, 28 Nov 2018 02:17:11 GMT - -*Version update only* - -## 6.0.31 -Fri, 16 Nov 2018 21:37:10 GMT - -*Version update only* - -## 6.0.30 -Fri, 16 Nov 2018 00:59:00 GMT - -*Version update only* - -## 6.0.29 -Fri, 09 Nov 2018 23:07:39 GMT - -*Version update only* - -## 6.0.28 -Wed, 07 Nov 2018 21:04:35 GMT - -*Version update only* - -## 6.0.27 -Wed, 07 Nov 2018 17:03:03 GMT - -*Version update only* - -## 6.0.26 -Mon, 05 Nov 2018 17:04:24 GMT - -*Version update only* - -## 6.0.25 -Thu, 01 Nov 2018 21:33:52 GMT - -*Version update only* - -## 6.0.24 -Thu, 01 Nov 2018 19:32:52 GMT - -*Version update only* - -## 6.0.23 -Wed, 31 Oct 2018 21:17:50 GMT - -*Version update only* - -## 6.0.22 -Wed, 31 Oct 2018 17:00:55 GMT - -*Version update only* - -## 6.0.21 -Sat, 27 Oct 2018 03:45:51 GMT - -*Version update only* - -## 6.0.20 -Sat, 27 Oct 2018 02:17:18 GMT - -*Version update only* - -## 6.0.19 -Sat, 27 Oct 2018 00:26:56 GMT - -*Version update only* - -## 6.0.18 -Thu, 25 Oct 2018 23:20:40 GMT - -*Version update only* - -## 6.0.17 -Thu, 25 Oct 2018 08:56:02 GMT - -*Version update only* - -## 6.0.16 -Wed, 24 Oct 2018 16:03:10 GMT - -*Version update only* - -## 6.0.15 -Thu, 18 Oct 2018 05:30:14 GMT - -*Version update only* - -## 6.0.14 -Thu, 18 Oct 2018 01:32:21 GMT - -*Version update only* - -## 6.0.13 -Wed, 17 Oct 2018 21:04:49 GMT - -*Version update only* - -## 6.0.12 -Wed, 17 Oct 2018 14:43:24 GMT - -*Version update only* - -## 6.0.11 -Thu, 11 Oct 2018 23:26:07 GMT - -*Version update only* - -## 6.0.10 -Tue, 09 Oct 2018 06:58:02 GMT - -*Version update only* - -## 6.0.9 -Mon, 08 Oct 2018 16:04:27 GMT - -*Version update only* - -## 6.0.8 -Sun, 07 Oct 2018 06:15:56 GMT - -*Version update only* - -## 6.0.7 -Fri, 28 Sep 2018 16:05:35 GMT - -*Version update only* - -## 6.0.6 -Wed, 26 Sep 2018 21:39:40 GMT - -*Version update only* - -## 6.0.5 -Mon, 24 Sep 2018 23:06:40 GMT - -*Version update only* - -## 6.0.4 -Mon, 24 Sep 2018 16:04:28 GMT - -*Version update only* - -## 6.0.3 -Fri, 21 Sep 2018 16:04:42 GMT - -*Version update only* - -## 6.0.2 -Thu, 20 Sep 2018 23:57:21 GMT - -*Version update only* - -## 6.0.1 -Tue, 18 Sep 2018 21:04:55 GMT - -*Version update only* - -## 6.0.0 -Mon, 10 Sep 2018 23:23:01 GMT - -### Breaking changes - -- Removing the text task from the rig. - -## 5.1.3 -Thu, 06 Sep 2018 21:04:43 GMT - -*Version update only* - -## 5.1.2 -Thu, 06 Sep 2018 01:25:26 GMT - -### Patches - -- Update "repository" field in package.json - -## 5.1.1 -Tue, 04 Sep 2018 21:34:10 GMT - -*Version update only* - -## 5.1.0 -Mon, 03 Sep 2018 16:04:46 GMT - -### Minor changes - -- Update the way api-extractor is invoked. - -## 5.0.8 -Fri, 31 Aug 2018 00:11:01 GMT - -*Version update only* - -## 5.0.7 -Thu, 30 Aug 2018 22:47:34 GMT - -*Version update only* - -## 5.0.6 -Thu, 30 Aug 2018 19:23:16 GMT - -*Version update only* - -## 5.0.5 -Thu, 30 Aug 2018 18:45:12 GMT - -*Version update only* - -## 5.0.4 -Thu, 30 Aug 2018 04:42:01 GMT - -*Version update only* - -## 5.0.3 -Thu, 30 Aug 2018 04:24:41 GMT - -*Version update only* - -## 5.0.2 -Wed, 29 Aug 2018 21:43:23 GMT - -*Version update only* - -## 5.0.1 -Wed, 29 Aug 2018 20:34:33 GMT - -*Version update only* - -## 5.0.0 -Wed, 29 Aug 2018 06:36:50 GMT - -### Breaking changes - -- Updating the way typescript and tslint are invoked. - -## 4.4.68 -Thu, 23 Aug 2018 18:18:53 GMT - -### Patches - -- Republish all packages in web-build-tools to resolve GitHub issue #782 - -## 4.4.67 -Wed, 22 Aug 2018 20:58:58 GMT - -*Version update only* - -## 4.4.66 -Wed, 22 Aug 2018 16:03:25 GMT - -*Version update only* - -## 4.4.65 -Tue, 21 Aug 2018 16:04:38 GMT - -*Version update only* - -## 4.4.64 -Thu, 09 Aug 2018 21:58:02 GMT - -*Version update only* - -## 4.4.63 -Thu, 09 Aug 2018 21:03:22 GMT - -*Version update only* - -## 4.4.62 -Thu, 09 Aug 2018 16:04:24 GMT - -*Version update only* - -## 4.4.61 -Tue, 07 Aug 2018 22:27:31 GMT - -*Version update only* - -## 4.4.60 -Thu, 26 Jul 2018 23:53:43 GMT - -*Version update only* - -## 4.4.59 -Thu, 26 Jul 2018 16:04:17 GMT - -*Version update only* - -## 4.4.58 -Wed, 25 Jul 2018 21:02:57 GMT - -*Version update only* - -## 4.4.57 -Fri, 20 Jul 2018 16:04:52 GMT - -*Version update only* - -## 4.4.56 -Tue, 17 Jul 2018 16:02:52 GMT - -*Version update only* - -## 4.4.55 -Fri, 13 Jul 2018 19:04:50 GMT - -*Version update only* - -## 4.4.54 -Tue, 03 Jul 2018 21:03:31 GMT - -*Version update only* - -## 4.4.53 -Fri, 29 Jun 2018 02:56:51 GMT - -*Version update only* - -## 4.4.52 -Sat, 23 Jun 2018 02:21:20 GMT - -*Version update only* - -## 4.4.51 -Fri, 22 Jun 2018 16:05:15 GMT - -*Version update only* - -## 4.4.50 -Thu, 21 Jun 2018 08:27:29 GMT - -*Version update only* - -## 4.4.49 -Tue, 19 Jun 2018 19:35:11 GMT - -*Version update only* - -## 4.4.48 -Wed, 13 Jun 2018 16:05:21 GMT - -*Version update only* - -## 4.4.47 -Fri, 08 Jun 2018 08:43:52 GMT - -*Version update only* - -## 4.4.46 -Thu, 31 May 2018 01:39:33 GMT - -*Version update only* - -## 4.4.45 -Tue, 15 May 2018 02:26:45 GMT - -*Version update only* - -## 4.4.44 -Tue, 15 May 2018 00:18:10 GMT - -*Version update only* - -## 4.4.43 -Fri, 11 May 2018 22:43:14 GMT - -*Version update only* - -## 4.4.42 -Fri, 04 May 2018 00:42:38 GMT - -*Version update only* - -## 4.4.41 -Tue, 01 May 2018 22:03:20 GMT - -*Version update only* - -## 4.4.40 -Mon, 30 Apr 2018 21:04:44 GMT - -*Version update only* - -## 4.4.39 -Fri, 27 Apr 2018 03:04:32 GMT - -*Version update only* - -## 4.4.38 -Fri, 20 Apr 2018 16:06:11 GMT - -*Version update only* - -## 4.4.37 -Thu, 19 Apr 2018 21:25:56 GMT - -*Version update only* - -## 4.4.36 -Thu, 19 Apr 2018 17:02:06 GMT - -*Version update only* - -## 4.4.35 -Fri, 06 Apr 2018 16:03:14 GMT - -*Version update only* - -## 4.4.34 -Tue, 03 Apr 2018 16:05:29 GMT - -*Version update only* - -## 4.4.33 -Mon, 02 Apr 2018 16:05:24 GMT - -*Version update only* - -## 4.4.32 -Tue, 27 Mar 2018 01:34:25 GMT - -*Version update only* - -## 4.4.31 -Mon, 26 Mar 2018 19:12:42 GMT - -*Version update only* - -## 4.4.30 -Sun, 25 Mar 2018 01:26:19 GMT - -*Version update only* - -## 4.4.29 -Fri, 23 Mar 2018 00:34:53 GMT - -*Version update only* - -## 4.4.28 -Thu, 22 Mar 2018 18:34:13 GMT - -*Version update only* - -## 4.4.27 -Tue, 20 Mar 2018 02:44:45 GMT - -*Version update only* - -## 4.4.26 -Sat, 17 Mar 2018 02:54:22 GMT - -*Version update only* - -## 4.4.25 -Thu, 15 Mar 2018 20:00:50 GMT - -*Version update only* - -## 4.4.24 -Thu, 15 Mar 2018 16:05:43 GMT - -*Version update only* - -## 4.4.23 -Tue, 13 Mar 2018 23:11:32 GMT - -*Version update only* - -## 4.4.22 -Mon, 12 Mar 2018 20:36:19 GMT - -*Version update only* - -## 4.4.21 -Tue, 06 Mar 2018 17:04:51 GMT - -*Version update only* - -## 4.4.20 -Fri, 02 Mar 2018 01:13:59 GMT - -*Version update only* - -## 4.4.19 -Tue, 27 Feb 2018 22:05:57 GMT - -*Version update only* - -## 4.4.18 -Fri, 23 Feb 2018 17:04:33 GMT - -*Version update only* - -## 4.4.17 -Wed, 21 Feb 2018 22:04:19 GMT - -*Version update only* - -## 4.4.16 -Wed, 21 Feb 2018 03:13:29 GMT - -*Version update only* - -## 4.4.15 -Sat, 17 Feb 2018 02:53:49 GMT - -*Version update only* - -## 4.4.14 -Fri, 16 Feb 2018 22:05:23 GMT - -*Version update only* - -## 4.4.13 -Fri, 16 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.4.12 -Wed, 07 Feb 2018 17:05:11 GMT - -*Version update only* - -## 4.4.11 -Fri, 26 Jan 2018 22:05:30 GMT - -*Version update only* - -## 4.4.10 -Fri, 26 Jan 2018 17:53:38 GMT - -### Patches - -- Force a patch bump in case the previous version was an empty package - -## 4.4.9 -Fri, 26 Jan 2018 00:36:51 GMT - -*Version update only* - -## 4.4.8 -Tue, 23 Jan 2018 17:05:28 GMT - -*Version update only* - -## 4.4.7 -Sat, 20 Jan 2018 02:39:16 GMT - -*Version update only* - -## 4.4.6 -Thu, 18 Jan 2018 03:23:46 GMT - -*Version update only* - -## 4.4.5 -Thu, 18 Jan 2018 00:48:06 GMT - -*Version update only* - -## 4.4.4 -Thu, 18 Jan 2018 00:27:23 GMT - -*Version update only* - -## 4.4.3 -Wed, 17 Jan 2018 10:49:31 GMT - -*Version update only* - -## 4.4.2 -Fri, 12 Jan 2018 03:35:22 GMT - -*Version update only* - -## 4.4.1 -Thu, 11 Jan 2018 22:31:51 GMT - -*Version update only* - -## 4.4.0 -Wed, 10 Jan 2018 20:40:01 GMT - -### Minor changes - -- Upgrade to Node 8 - -## 4.3.0 -Sun, 07 Jan 2018 05:12:08 GMT - -### Minor changes - -- api-extractor now runs after tsc rather than in parallel, and is excluded from "gulp serve" - -## 4.2.16 -Fri, 05 Jan 2018 20:26:45 GMT - -*Version update only* - -## 4.2.15 -Fri, 05 Jan 2018 00:48:41 GMT - -*Version update only* - -## 4.2.14 -Fri, 22 Dec 2017 17:04:46 GMT - -*Version update only* - -## 4.2.13 -Tue, 12 Dec 2017 03:33:26 GMT - -*Version update only* - -## 4.2.12 -Thu, 30 Nov 2017 23:59:09 GMT - -*Version update only* - -## 4.2.11 -Thu, 30 Nov 2017 23:12:21 GMT - -*Version update only* - -## 4.2.10 -Wed, 29 Nov 2017 17:05:37 GMT - -*Version update only* - -## 4.2.9 -Tue, 28 Nov 2017 23:43:55 GMT - -*Version update only* - -## 4.2.8 -Mon, 13 Nov 2017 17:04:50 GMT - -*Version update only* - -## 4.2.7 -Mon, 06 Nov 2017 17:04:18 GMT - -*Version update only* - -## 4.2.6 -Thu, 02 Nov 2017 16:05:24 GMT - -*Version update only* - -## 4.2.5 -Wed, 01 Nov 2017 21:06:08 GMT - -*Version update only* - -## 4.2.4 -Tue, 31 Oct 2017 21:04:04 GMT - -*Version update only* - -## 4.2.3 -Tue, 31 Oct 2017 16:04:55 GMT - -*Version update only* - -## 4.2.2 -Thu, 26 Oct 2017 00:00:12 GMT - -*Version update only* - -## 4.2.1 -Wed, 25 Oct 2017 20:03:59 GMT - -*Version update only* - -## 4.2.0 -Tue, 24 Oct 2017 18:17:12 GMT - -### Minor changes - -- Support Jest task - -## 4.1.6 -Mon, 23 Oct 2017 21:53:12 GMT - -*Version update only* - -## 4.1.5 -Fri, 20 Oct 2017 19:57:12 GMT - -*Version update only* - -## 4.1.4 -Fri, 20 Oct 2017 01:52:54 GMT - -*Version update only* - -## 4.1.3 -Fri, 20 Oct 2017 01:04:44 GMT - -*Version update only* - -## 4.1.2 -Thu, 05 Oct 2017 01:05:02 GMT - -*Version update only* - -## 4.1.1 -Thu, 28 Sep 2017 01:04:28 GMT - -*Version update only* - -## 4.1.0 -Fri, 22 Sep 2017 01:04:02 GMT - -### Minor changes - -- Upgrade to es6 - -## 4.0.9 -Thu, 21 Sep 2017 20:34:26 GMT - -*Version update only* - -## 4.0.8 -Wed, 20 Sep 2017 22:10:17 GMT - -*Version update only* - -## 4.0.7 -Mon, 11 Sep 2017 13:04:55 GMT - -*Version update only* - -## 4.0.6 -Fri, 08 Sep 2017 01:28:04 GMT - -### Patches - -- Deprecate @types/es6-collections in favor of built-in typescript typings 'es2015.collection' and 'es2015.iterable' - -## 4.0.5 -Thu, 07 Sep 2017 13:04:35 GMT - -*Version update only* - -## 4.0.4 -Thu, 07 Sep 2017 00:11:12 GMT - -*Version update only* - -## 4.0.3 -Wed, 06 Sep 2017 13:03:42 GMT - -*Version update only* - -## 4.0.2 -Tue, 05 Sep 2017 19:03:56 GMT - -*Version update only* - -## 4.0.1 -Sat, 02 Sep 2017 01:04:26 GMT - -*Version update only* - -## 4.0.0 -Thu, 31 Aug 2017 18:41:18 GMT - -### Breaking changes - -- Fix compatibility issues with old releases, by incrementing the major version number - -## 3.2.16 -Thu, 31 Aug 2017 17:46:25 GMT - -*Version update only* - -## 3.2.15 -Thu, 31 Aug 2017 13:04:19 GMT - -*Version update only* - -## 3.2.14 -Wed, 30 Aug 2017 22:08:21 GMT - -*Version update only* - -## 3.2.13 -Wed, 30 Aug 2017 01:04:34 GMT - -*Version update only* - -## 3.2.12 -Thu, 24 Aug 2017 22:44:12 GMT - -*Version update only* - -## 3.2.11 -Thu, 24 Aug 2017 01:04:33 GMT - -*Version update only* - -## 3.2.10 -Tue, 22 Aug 2017 13:04:22 GMT - -*Version update only* - -## 3.2.9 -Wed, 16 Aug 2017 23:16:55 GMT - -*Version update only* - -## 3.2.8 -Tue, 15 Aug 2017 19:04:14 GMT - -*Version update only* - -## 3.2.7 -Tue, 15 Aug 2017 01:29:31 GMT - -*Version update only* - -## 3.2.6 -Sat, 12 Aug 2017 01:03:30 GMT - -*Version update only* - -## 3.2.5 -Fri, 11 Aug 2017 21:44:05 GMT - -*Version update only* - -## 3.2.4 -Tue, 08 Aug 2017 23:10:36 GMT - -*Version update only* - -## 3.2.3 -Sat, 05 Aug 2017 01:04:41 GMT - -*Version update only* - -## 3.2.2 -Mon, 31 Jul 2017 21:18:26 GMT - -*Version update only* - -## 3.2.1 -Thu, 27 Jul 2017 01:04:48 GMT - -### Patches - -- Upgrade to the TS2.4 version of the build tools and restrict the dependency version requirements. -- Fix an issue with 'gulp serve' where the server was not being launched. - -## 3.2.0 -Tue, 25 Jul 2017 20:03:31 GMT - -### Minor changes - -- Upgrade to TypeScript 2.4 - -## 3.1.0 -Fri, 07 Jul 2017 01:02:28 GMT - -### Minor changes - -- Enable StrictNullChecks. - -## 3.0.3 -Thu, 29 Jun 2017 01:05:37 GMT - -### Patches - -- Fix an issue with 'gulp serve' where an initial build error would stop watch from continuing - -## 3.0.2 -Tue, 16 May 2017 00:01:03 GMT - -### Patches - -- Remove unnecessary fsevents optional dependency - -## 3.0.1 -Wed, 19 Apr 2017 20:18:06 GMT - -### Patches - -- Remove ES6 Promise & @types/es6-promise typings - -## 3.0.0 -Mon, 20 Mar 2017 21:52:20 GMT - -### Breaking changes - -- Updating build task dependencies. - -## 2.3.2 -Wed, 15 Mar 2017 01:32:09 GMT - -### Patches - -- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects. - -## 2.3.1 -Fri, 03 Mar 2017 02:31:24 GMT - -### Patches - -- Restore TS Lint task in gulp build - -## 2.3.0 -Wed, 08 Feb 2017 01:41:58 GMT - -### Minor changes - -- Treat warnings as errors in production. Treat tslint errors as warnings. - -## 2.2.2 -Tue, 07 Feb 2017 02:33:34 GMT - -### Patches - -- Remove unused dependency - -## 2.2.1 -Fri, 27 Jan 2017 23:27:42 GMT - -### Patches - -- Refactor the build task to not run "text" subtask twice. - -## 2.2.0 -Fri, 20 Jan 2017 01:46:41 GMT - -### Minor changes - -- Run the api-extractor task during the default build. - -## 2.1.0 -Fri, 13 Jan 2017 06:46:05 GMT - -### Minor changes - -- Enable the ApiExtractor task from gulp-core-build-typescript. - -## 2.0.0 -Wed, 11 Jan 2017 14:11:26 GMT - -*Initial release* - diff --git a/core-build/web-library-build/LICENSE b/core-build/web-library-build/LICENSE deleted file mode 100644 index 50f47a414b9..00000000000 --- a/core-build/web-library-build/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@microsoft/web-library-build - -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/core-build/web-library-build/README.md b/core-build/web-library-build/README.md deleted file mode 100644 index 6f79b343ba3..00000000000 --- a/core-build/web-library-build/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# @microsoft/web-library-build - -`web-library-build` is a `gulp-core-build` build rig for building web libraries. It includes build subtasks for processing css, typescript, serving, and running browser tests using karma. - -[![npm version](https://badge.fury.io/js/%40microsoft%2Fweb-library-build.svg)](https://badge.fury.io/js/%40microsoft%2Fweb-library-build) -[![Build Status](https://travis-ci.org/Microsoft/web-library-build.svg?branch=master)](https://travis-ci.org/Microsoft/web-library-build) -[![Dependencies](https://david-dm.org/Microsoft/web-library-build.svg)](https://david-dm.org/Microsoft/web-library-build) diff --git a/core-build/web-library-build/config/api-extractor.json b/core-build/web-library-build/config/api-extractor.json deleted file mode 100644 index dcfa9cfc5b7..00000000000 --- a/core-build/web-library-build/config/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 - }, - - "dtsRollup": { - "enabled": false - } -} diff --git a/core-build/web-library-build/gulpfile.js b/core-build/web-library-build/gulpfile.js deleted file mode 100644 index 37aa39ec67b..00000000000 --- a/core-build/web-library-build/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/core-build/web-library-build/package.json b/core-build/web-library-build/package.json deleted file mode 100644 index 90a82d99541..00000000000 --- a/core-build/web-library-build/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@microsoft/web-library-build", - "version": "7.4.6", - "description": "", - "engines": { - "npm": "3.10.8" - }, - "repository": { - "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/core-build/web-library-build" - }, - "scripts": { - "build": "gulp --clean" - }, - "main": "lib/index.js", - "typings": "lib/index.d.ts", - "dependencies": { - "@microsoft/gulp-core-build": "3.15.3", - "@microsoft/gulp-core-build-sass": "4.10.6", - "@microsoft/gulp-core-build-serve": "3.7.3", - "@microsoft/gulp-core-build-typescript": "8.4.6", - "@microsoft/gulp-core-build-webpack": "5.0.2", - "@types/gulp": "4.0.6", - "@types/node": "10.17.13", - "gulp": "~4.0.2", - "gulp-replace": "^0.5.4" - }, - "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5" - } -} diff --git a/core-build/web-library-build/src/PostProcessSourceMaps.ts b/core-build/web-library-build/src/PostProcessSourceMaps.ts deleted file mode 100644 index 2c1ccc53f23..00000000000 --- a/core-build/web-library-build/src/PostProcessSourceMaps.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { GulpTask } from '@microsoft/gulp-core-build'; -import gulpType = require('gulp'); - -export class PostProcessSourceMaps extends GulpTask { - public constructor() { - super('post-process'); - } - - public executeTask(gulp: gulpType.Gulp): NodeJS.ReadWriteStream | void { - if (this.buildConfig.args.hasOwnProperty('vscode')) { - - // eslint-disable-next-line - const replace = require('gulp-replace'); - - return gulp.src(['dist/*!(.min).js.map']) - .pipe(replace('webpack:///./', '')) - .pipe(replace('webpack:////source/', '')) - .pipe(replace('webpack:////src/', '')) - .pipe(replace('webpack:///../~/', '../node_modules/')) - .pipe(replace('"sourceRoot":""', '"sourceRoot":"/"')) - .pipe(gulp.dest('dist/')); - - } else { - return; - } - } -} \ No newline at end of file diff --git a/core-build/web-library-build/src/index.ts b/core-build/web-library-build/src/index.ts deleted file mode 100644 index 4143630358b..00000000000 --- a/core-build/web-library-build/src/index.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - CopyTask, - GenerateShrinkwrapTask, - IExecutable, - jest, - ValidateShrinkwrapTask, - parallel, - serial, - task, - watch, - setConfig, - getConfig -} from '@microsoft/gulp-core-build'; -import { apiExtractor, tscCmd, lintCmd } from '@microsoft/gulp-core-build-typescript'; -import { sass } from '@microsoft/gulp-core-build-sass'; -import { webpack } from '@microsoft/gulp-core-build-webpack'; -import { serve, reload } from '@microsoft/gulp-core-build-serve'; -import { PostProcessSourceMaps } from './PostProcessSourceMaps'; - -export * from '@microsoft/gulp-core-build'; -export * from '@microsoft/gulp-core-build-typescript'; -export * from '@microsoft/gulp-core-build-sass'; -export * from '@microsoft/gulp-core-build-webpack'; -export * from '@microsoft/gulp-core-build-serve'; - -// Pre copy and post copy allows you to specify a map of dest: [sources] to copy from one place to another. -/** - * @public - */ -export const preCopy: CopyTask = new CopyTask(); -preCopy.name = 'pre-copy'; - -/** - * @public - */ -export const postCopy: CopyTask = new CopyTask(); -postCopy.name = 'post-copy'; - -const sourceMatch: string[] = [ - 'src/**/*.{ts,tsx,scss,js,txt,html}', - '!src/**/*.scss.ts' -]; - -// eslint-disable-next-line dot-notation -const PRODUCTION: boolean = !!getConfig().args['production'] || !!getConfig().args['ship']; -setConfig({ - production: PRODUCTION, - shouldWarningsFailBuild: PRODUCTION -}); - -// Define default task groups. -/** - * @public - */ -export const buildTasks: IExecutable = task( - 'build', - serial(preCopy, sass, parallel(lintCmd, tscCmd), apiExtractor, postCopy) -); - -/** - * @public - */ -export const bundleTasks: IExecutable = task('bundle', serial(buildTasks, webpack)); - -/** - * @public - */ -export const testTasks: IExecutable = task('test', serial(buildTasks, jest)); - -/** - * @public - */ -export const defaultTasks: IExecutable = serial(bundleTasks, jest); - -/** - * @public - */ -export const postProcessSourceMapsTask: PostProcessSourceMaps = new PostProcessSourceMaps(); - -/** - * @public - */ -export const validateShrinkwrapTask: ValidateShrinkwrapTask = new ValidateShrinkwrapTask(); - -/** - * @public - */ -export const generateShrinkwrapTask: GenerateShrinkwrapTask = new GenerateShrinkwrapTask(); - -task('validate-shrinkwrap', validateShrinkwrapTask); -task('generate', generateShrinkwrapTask); -task('test-watch', watch(sourceMatch, testTasks)); - -// For watch scenarios like serve, make sure to exclude generated files from src (like *.scss.ts.) -task('serve', - serial( - serve, - watch( - sourceMatch, - serial(preCopy, sass, tscCmd, postCopy, webpack, postProcessSourceMapsTask, reload) - ) - ) -); - -task('default', defaultTasks); diff --git a/core-build/web-library-build/tsconfig.json b/core-build/web-library-build/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/core-build/web-library-build/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/eslint/eslint-bulk/.npmignore b/eslint/eslint-bulk/.npmignore new file mode 100755 index 00000000000..e15a94aeb84 --- /dev/null +++ b/eslint/eslint-bulk/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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/eslint/eslint-bulk/CHANGELOG.json b/eslint/eslint-bulk/CHANGELOG.json new file mode 100644 index 00000000000..90175a1e62c --- /dev/null +++ b/eslint/eslint-bulk/CHANGELOG.json @@ -0,0 +1,1400 @@ +{ + "name": "@rushstack/eslint-bulk", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.1.69", + "tag": "@rushstack/eslint-bulk_v0.1.69", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.1.68", + "tag": "@rushstack/eslint-bulk_v0.1.68", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.1.67", + "tag": "@rushstack/eslint-bulk_v0.1.67", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.1.66", + "tag": "@rushstack/eslint-bulk_v0.1.66", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.1.65", + "tag": "@rushstack/eslint-bulk_v0.1.65", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.1.64", + "tag": "@rushstack/eslint-bulk_v0.1.64", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.1.63", + "tag": "@rushstack/eslint-bulk_v0.1.63", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.1.62", + "tag": "@rushstack/eslint-bulk_v0.1.62", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.1.61", + "tag": "@rushstack/eslint-bulk_v0.1.61", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.1.60", + "tag": "@rushstack/eslint-bulk_v0.1.60", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.1.59", + "tag": "@rushstack/eslint-bulk_v0.1.59", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/eslint-bulk_v0.1.58", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/eslint-bulk_v0.1.57", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/eslint-bulk_v0.1.56", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/eslint-bulk_v0.1.55", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/eslint-bulk_v0.1.54", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/eslint-bulk_v0.1.53", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/eslint-bulk_v0.1.52", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/eslint-bulk_v0.1.51", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/eslint-bulk_v0.1.50", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/eslint-bulk_v0.1.49", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/eslint-bulk_v0.1.48", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/eslint-bulk_v0.1.47", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/eslint-bulk_v0.1.46", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/eslint-bulk_v0.1.45", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/eslint-bulk_v0.1.44", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/eslint-bulk_v0.1.43", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/eslint-bulk_v0.1.42", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/eslint-bulk_v0.1.41", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/eslint-bulk_v0.1.40", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/eslint-bulk_v0.1.39", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/eslint-bulk_v0.1.38", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/eslint-bulk_v0.1.37", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/eslint-bulk_v0.1.36", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/eslint-bulk_v0.1.35", + "date": "Sat, 11 May 2024 00:12:09 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the tool will not correctly execute if the installed eslint path contains a space." + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/eslint-bulk_v0.1.34", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/eslint-bulk_v0.1.33", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/eslint-bulk_v0.1.32", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/eslint-bulk_v0.1.31", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/eslint-bulk_v0.1.30", + "date": "Tue, 09 Apr 2024 18:08:23 GMT", + "comments": { + "patch": [ + { + "comment": "Attempt to resolve eslint as a dependency of the current project before falling back to a globally-installed copy." + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/eslint-bulk_v0.1.29", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/eslint-bulk_v0.1.28", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/eslint-bulk_v0.1.27", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/eslint-bulk_v0.1.26", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/eslint-bulk_v0.1.25", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/eslint-bulk_v0.1.24", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/eslint-bulk_v0.1.23", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/eslint-bulk_v0.1.22", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/eslint-bulk_v0.1.21", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/eslint-bulk_v0.1.20", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/eslint-bulk_v0.1.19", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/eslint-bulk_v0.1.18", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/eslint-bulk_v0.1.17", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/eslint-bulk_v0.1.16", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/eslint-bulk_v0.1.15", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/eslint-bulk_v0.1.14", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/eslint-bulk_v0.1.13", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/eslint-bulk_v0.1.12", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/eslint-bulk_v0.1.11", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/eslint-bulk_v0.1.10", + "date": "Thu, 25 Jan 2024 23:03:57 GMT", + "comments": { + "patch": [ + { + "comment": "Some minor documentation updates" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/eslint-bulk_v0.1.9", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/eslint-bulk_v0.1.8", + "date": "Wed, 24 Jan 2024 07:38:34 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/eslint-bulk_v0.1.7", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/eslint-bulk_v0.1.6", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/eslint-bulk_v0.1.5", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/eslint-bulk_v0.1.4", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/eslint-bulk_v0.1.3", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/eslint-bulk_v0.1.2", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/eslint-bulk_v0.1.1", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/eslint-bulk_v0.1.0", + "date": "Wed, 22 Nov 2023 01:45:18 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release of `@rushstack/eslint-bulk` package" + } + ] + } + } + ] +} diff --git a/eslint/eslint-bulk/CHANGELOG.md b/eslint/eslint-bulk/CHANGELOG.md new file mode 100644 index 00000000000..11c4cbf4ab0 --- /dev/null +++ b/eslint/eslint-bulk/CHANGELOG.md @@ -0,0 +1,597 @@ +# Change Log - @rushstack/eslint-bulk + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.1.69 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.1.68 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.1.67 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.1.66 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.1.65 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.1.64 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.1.63 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.1.62 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.1.61 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.1.60 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.1.59 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.1.58 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.1.57 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.1.56 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.1.55 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.1.54 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.1.53 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.1.52 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.1.51 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.1.50 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.1.49 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.1.48 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.1.47 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.1.46 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.1.45 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.1.44 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.1.43 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.1.42 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.1.41 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.1.40 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.1.39 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.1.38 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.1.37 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.1.36 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.1.35 +Sat, 11 May 2024 00:12:09 GMT + +### Patches + +- Fix an issue where the tool will not correctly execute if the installed eslint path contains a space. + +## 0.1.34 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.1.33 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.1.32 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.1.31 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.1.30 +Tue, 09 Apr 2024 18:08:23 GMT + +### Patches + +- Attempt to resolve eslint as a dependency of the current project before falling back to a globally-installed copy. + +## 0.1.29 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.1.28 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.1.27 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.1.26 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.1.25 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.1.24 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.1.23 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.1.22 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.1.21 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.1.20 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.1.19 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.1.18 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.1.17 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.1.16 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.1.15 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.1.14 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.1.13 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.1.12 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.1.11 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.1.10 +Thu, 25 Jan 2024 23:03:57 GMT + +### Patches + +- Some minor documentation updates + +## 0.1.9 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.1.8 +Wed, 24 Jan 2024 07:38:34 GMT + +### Patches + +- Update documentation + +## 0.1.7 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.1.6 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.1.5 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.1.4 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.1.3 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.1.2 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.1.1 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.1.0 +Wed, 22 Nov 2023 01:45:18 GMT + +### Minor changes + +- Initial release of `@rushstack/eslint-bulk` package + diff --git a/eslint/eslint-bulk/LICENSE b/eslint/eslint-bulk/LICENSE new file mode 100644 index 00000000000..bd913f236dd --- /dev/null +++ b/eslint/eslint-bulk/LICENSE @@ -0,0 +1,24 @@ +@rushstack/eslint-bulk + +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/eslint/eslint-bulk/README.md b/eslint/eslint-bulk/README.md new file mode 100755 index 00000000000..4f17d9a855d --- /dev/null +++ b/eslint/eslint-bulk/README.md @@ -0,0 +1,52 @@ +# @rushstack/eslint-bulk + +This package provides the command-line interface (CLI) for the **ESLint bulk suppressions** +feature from `@rushstack/eslint-patch`. + +### Setting it up + +👉 Before using this tool, you will first need to install and configure the +[@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch) package. + +See the [eslint-bulk-suppressions documentation](https://www.npmjs.com/package/@rushstack/eslint-patch#eslint-bulk-suppressions-feature) +for details. + +### Typical workflow + +1. Checkout your `main` branch, which is in a clean state where ESLint reports no violations. +2. Update your configuration to enable the latest lint rules; ESLint now reports thousands of legacy violations. +3. Run `eslint-bulk suppress --all ./src` to update **.eslint-bulk-suppressions.json.** +4. ESLint now no longer reports violations, so commit the results to Git and merge your pull request. +5. Over time, engineers may improve some of the suppressed code, in which case the associated suppressions are no longer needed. +6. Run `eslint-bulk prune` periodically to find and remove unnecessary suppressions from **.eslint-bulk-suppressions.json**, ensuring that new violations will now get caught in those scopes. + +### "eslint-bulk suppress" command + +```bash +eslint-bulk suppress --rule NAME1 [--rule NAME2...] PATH1 [PATH2...] +eslint-bulk suppress --all PATH1 [PATH2...] +``` + +Use this command to automatically generate bulk suppressions for the specified lint rules and file paths. +The path argument is a [glob pattern](https://en.wikipedia.org/wiki/Glob_(programming)) with the same syntax +as path arguments for the `eslint` command. + + +### "eslint-bulk prune" command + +Use this command to automatically delete all unnecessary suppression entries in all +**.eslint-bulk-suppressions.json** files under the current working directory. + +```bash +eslint-bulk prune +``` + +# Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/eslint/eslint-bulk/CHANGELOG.md) - Find + out what's new in the latest version + +- [`@rushstack/eslint-patch`](https://www.npmjs.com/package/@rushstack/eslint-patch) required companion package + + +`@rushstack/eslint-bulk` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/eslint/eslint-bulk/bin/eslint-bulk b/eslint/eslint-bulk/bin/eslint-bulk new file mode 100755 index 00000000000..aee68e80224 --- /dev/null +++ b/eslint/eslint-bulk/bin/eslint-bulk @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/start.js'); diff --git a/eslint/eslint-bulk/config/rig.json b/eslint/eslint-bulk/config/rig.json new file mode 100755 index 00000000000..165ffb001f5 --- /dev/null +++ b/eslint/eslint-bulk/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/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 new file mode 100755 index 00000000000..15866877497 --- /dev/null +++ b/eslint/eslint-bulk/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/eslint-bulk", + "version": "0.4.8", + "description": "Roll out new ESLint rules in a large monorepo without cluttering up your code with \"eslint-ignore-next-line\"", + "main": "index.js", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-bulk" + }, + "homepage": "https://rushstack.io", + "bin": { + "eslint-bulk": "./bin/eslint-bulk" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "start": "node ./lib/start.js" + }, + "keywords": [ + "eslintrc", + "eslint", + "bulk", + "legacy", + "retroactive", + "disable", + "ignore", + "suppression", + "monkey", + "patch" + ], + "devDependencies": { + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/eslint/eslint-bulk/src/start.ts b/eslint/eslint-bulk/src/start.ts new file mode 100644 index 00000000000..e2ea84ba852 --- /dev/null +++ b/eslint/eslint-bulk/src/start.ts @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + type ExecSyncOptionsWithBufferEncoding, + type SpawnSyncOptionsWithBufferEncoding, + execSync, + spawnSync +} 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 { + /** + * `@rushtack/eslint`-bulk should report an error if its package.json is older than this number + */ + minCliVersion: string; + /** + * `@rushtack/eslint-bulk` will invoke this entry point + */ + cliEntryPoint: string; +} + +function findPatchPath(): string { + const candidatePaths: string[] = ESLINT_CONFIG_FILES.map((fileName) => `${process.cwd()}/${fileName}`); + let eslintConfigPath: string | undefined; + for (const candidatePath of candidatePaths) { + if (fs.existsSync(candidatePath)) { + eslintConfigPath = candidatePath; + break; + } + } + + if (!eslintConfigPath) { + console.error( + '@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); + } + + const env: NodeJS.ProcessEnv = { ...process.env, _RUSHSTACK_ESLINT_BULK_DETECT: 'true' }; + + let eslintPackageJsonPath: string | undefined; + try { + eslintPackageJsonPath = require.resolve(`${BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME}/package.json`, { + paths: [process.cwd()] + }); + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') { + throw e; + } + } + + let eslintBinPath: string | undefined; + if (eslintPackageJsonPath) { + eslintPackageJsonPath = eslintPackageJsonPath.replace(/\\/g, '/'); + const packagePath: string = eslintPackageJsonPath.substring(0, eslintPackageJsonPath.lastIndexOf('/')); + const { bin: { eslint: relativeEslintBinPath } = {} }: { bin?: Record } = require( + eslintPackageJsonPath + ); + if (relativeEslintBinPath) { + eslintBinPath = `${packagePath}/${relativeEslintBinPath}`; + } else { + console.warn( + `@rushstack/eslint-bulk: The eslint package resolved at "${packagePath}" does not contain an eslint bin path. ` + + 'Attempting to use a globally-installed eslint instead.' + ); + } + } else { + console.log( + '@rushstack/eslint-bulk: Unable to resolve the eslint package as a dependency of the current project. ' + + 'Attempting to use a globally-installed eslint instead.' + ); + } + + const eslintArgs: string[] = ['--stdin', '--config']; + const spawnOrExecOptions: SpawnSyncOptionsWithBufferEncoding & ExecSyncOptionsWithBufferEncoding = { + env, + input: '', + stdio: 'pipe' + }; + let runEslintFn: () => Buffer; + if (eslintBinPath) { + runEslintFn = () => + 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(' ')} "${eslintConfigPath}"`, spawnOrExecOptions); + } + + let stdout: Buffer; + try { + stdout = runEslintFn(); + } catch (e) { + console.error('@rushstack/eslint-bulk: Error finding patch path: ' + e.message); + process.exit(1); + } + + 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) { + // The configuration data will look something like this: + // + // RUSHSTACK_ESLINT_BULK_START{"minCliVersion":"0.0.0","cliEntryPoint":"path/to/eslint-bulk.js"}RUSHSTACK_ESLINT_BULK_END + const configurationJson: string = match[1].trim(); + let configuration: IEslintBulkConfigurationJson; + try { + configuration = JSON.parse(configurationJson); + if (!configuration.minCliVersion || !configuration.cliEntryPoint) { + throw new Error('Required field is missing'); + } + } catch (e) { + console.error('@rushstack/eslint-bulk: Error parsing patch configuration object:' + e.message); + process.exit(1); + } + + const myVersion: string = require('../package.json').version; + const myVersionParts: number[] = myVersion.split('.').map((x) => parseInt(x, 10)); + const minVersion: string = configuration.minCliVersion; + const minVersionParts: number[] = minVersion.split('.').map((x) => parseInt(x, 10)); + if ( + myVersionParts.length !== 3 || + minVersionParts.length !== 3 || + myVersionParts.some((x) => isNaN(x)) || + minVersionParts.some((x) => isNaN(x)) + ) { + console.error(`@rushstack/eslint-bulk: Unable to compare versions "${myVersion}" and "${minVersion}"`); + process.exit(1); + } + + for (let i: number = 0; i < 3; ++i) { + if (myVersionParts[i] > minVersionParts[i]) { + break; + } + if (myVersionParts[i] < minVersionParts[i]) { + console.error( + `@rushstack/eslint-bulk: The @rushstack/eslint-bulk version ${myVersion} is too old;` + + ` please upgrade to ${minVersion} or newer.` + ); + process.exit(1); + } + } + + return configuration.cliEntryPoint; + } + + console.error( + '@rushstack/eslint-bulk: Error finding patch path. Are you sure the package you are in has @rushstack/eslint-patch as a direct or indirect dependency?' + ); + process.exit(1); +} + +const patchPath: string = findPatchPath(); +try { + require(patchPath); +} catch (e) { + console.error(`@rushstack/eslint-bulk: Error running patch at ${patchPath}:\n` + e.message); + process.exit(1); +} diff --git a/eslint/eslint-bulk/tsconfig.json b/eslint/eslint-bulk/tsconfig.json new file mode 100644 index 00000000000..b2e15527599 --- /dev/null +++ b/eslint/eslint-bulk/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "types": ["node"] + } +} diff --git a/eslint/eslint-config/.npmignore b/eslint/eslint-config/.npmignore new file mode 100644 index 00000000000..4babcddc16d --- /dev/null +++ b/eslint/eslint-config/.npmignore @@ -0,0 +1,38 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!*.js +!flat/**/*.js +!mixins/*.js +!patch/*.js +!profile/*.js diff --git a/eslint/eslint-config/CHANGELOG.json b/eslint/eslint-config/CHANGELOG.json new file mode 100644 index 00000000000..6180321b70a --- /dev/null +++ b/eslint/eslint-config/CHANGELOG.json @@ -0,0 +1,1634 @@ +{ + "name": "@rushstack/eslint-config", + "entries": [ + { + "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", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "minor": [ + { + "comment": "Update TSDoc dependencies." + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@rushstack/eslint-config_v4.0.2", + "date": "Thu, 19 Sep 2024 00:11:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix ESLint broken links" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.8.3`" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@rushstack/eslint-config_v4.0.1", + "date": "Wed, 14 Aug 2024 22:37:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.16.0`" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@rushstack/eslint-config_v4.0.0", + "date": "Tue, 13 Aug 2024 18:17:05 GMT", + "comments": { + "major": [ + { + "comment": "[BREAKING CHANGE] Bump \"@typescript-eslint/eslint-plugin\" to \"~8.1.0\" and \"@typescript-eslint/eslint-parser\" to \"~8.1.0\". Due to these changes, node@>=17.0.0 and eslint@^8.57.0 are now required due to breaking changes in the newer rules set." + } + ] + } + }, + { + "version": "3.7.1", + "tag": "@rushstack/eslint-config_v3.7.1", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.8.2`" + } + ] + } + }, + { + "version": "3.7.0", + "tag": "@rushstack/eslint-config_v3.7.0", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `eslint-plugin-tsdoc` plugin." + } + ] + } + }, + { + "version": "3.6.10", + "tag": "@rushstack/eslint-config_v3.6.10", + "date": "Fri, 17 May 2024 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.3`" + } + ] + } + }, + { + "version": "3.6.9", + "tag": "@rushstack/eslint-config_v3.6.9", + "date": "Wed, 10 Apr 2024 21:59:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.2`" + } + ] + } + }, + { + "version": "3.6.8", + "tag": "@rushstack/eslint-config_v3.6.8", + "date": "Fri, 29 Mar 2024 05:46:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.1`" + } + ] + } + }, + { + "version": "3.6.7", + "tag": "@rushstack/eslint-config_v3.6.7", + "date": "Thu, 28 Mar 2024 18:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.0`" + } + ] + } + }, + { + "version": "3.6.6", + "tag": "@rushstack/eslint-config_v3.6.6", + "date": "Wed, 27 Mar 2024 19:47:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.9.0`" + } + ] + } + }, + { + "version": "3.6.5", + "tag": "@rushstack/eslint-config_v3.6.5", + "date": "Wed, 20 Mar 2024 02:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.8.0`" + } + ] + } + }, + { + "version": "3.6.4", + "tag": "@rushstack/eslint-config_v3.6.4", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.8.1`" + } + ] + } + }, + { + "version": "3.6.3", + "tag": "@rushstack/eslint-config_v3.6.3", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.15.0`" + } + ] + } + }, + { + "version": "3.6.2", + "tag": "@rushstack/eslint-config_v3.6.2", + "date": "Thu, 25 Jan 2024 23:03:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.7.2`" + } + ] + } + }, + { + "version": "3.6.1", + "tag": "@rushstack/eslint-config_v3.6.1", + "date": "Wed, 24 Jan 2024 07:38:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.7.1`" + } + ] + } + }, + { + "version": "3.6.0", + "tag": "@rushstack/eslint-config_v3.6.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3 with @typescript-eslint 6.19.x" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.8.0`" + } + ] + } + }, + { + "version": "3.5.1", + "tag": "@rushstack/eslint-config_v3.5.1", + "date": "Fri, 15 Dec 2023 01:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.6.1`" + } + ] + } + }, + { + "version": "3.5.0", + "tag": "@rushstack/eslint-config_v3.5.0", + "date": "Wed, 22 Nov 2023 01:45:18 GMT", + "comments": { + "minor": [ + { + "comment": "Added eslint-bulk-suppressions to @rushstack/eslint-config dependencies, allowing it to be used in all projects that use rushstack's eslint-config" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.6.0`" + } + ] + } + }, + { + "version": "3.4.1", + "tag": "@rushstack/eslint-config_v3.4.1", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.5.1`" + } + ] + } + }, + { + "version": "3.4.0", + "tag": "@rushstack/eslint-config_v3.4.0", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the \"eslint-config-\" prefix" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.7.1`" + } + ] + } + }, + { + "version": "3.3.4", + "tag": "@rushstack/eslint-config_v3.3.4", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.7.0`" + } + ] + } + }, + { + "version": "3.3.3", + "tag": "@rushstack/eslint-config_v3.3.3", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.3.3`" + } + ] + } + }, + { + "version": "3.3.2", + "tag": "@rushstack/eslint-config_v3.3.2", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.3.2`" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@rushstack/eslint-config_v3.3.1", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.3.1`" + } + ] + } + }, + { + "version": "3.3.0", + "tag": "@rushstack/eslint-config_v3.3.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the @typescript-eslint/* dependencies to ~5.59.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.6.0`" + } + ] + } + }, + { + "version": "3.2.0", + "tag": "@rushstack/eslint-config_v3.2.0", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "minor": [ + { + "comment": "Replace the @typescript-eslint/no-parameter-properties rule with the replacement rule (@typescript-eslint/parameter-properties)." + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@rushstack/eslint-config_v3.1.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.6.1`" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@rushstack/eslint-config_v3.1.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.5.0`" + } + ] + } + }, + { + "version": "3.0.1", + "tag": "@rushstack/eslint-config_v3.0.1", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.2.0`" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@rushstack/eslint-config_v3.0.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "major": [ + { + "comment": "Upgrade TypeScript dependency to 4.7. This package now requires a peerDependency on TypeScript >=4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.4.0`" + } + ] + } + }, + { + "version": "2.6.2", + "tag": "@rushstack/eslint-config_v2.6.2", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.1.4`" + } + ] + } + }, + { + "version": "2.6.1", + "tag": "@rushstack/eslint-config_v2.6.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.3.1`" + } + ] + } + }, + { + "version": "2.6.0", + "tag": "@rushstack/eslint-config_v2.6.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.3.0`" + } + ] + } + }, + { + "version": "2.5.4", + "tag": "@rushstack/eslint-config_v2.5.4", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.1.3`" + } + ] + } + }, + { + "version": "2.5.3", + "tag": "@rushstack/eslint-config_v2.5.3", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.6`" + } + ] + } + }, + { + "version": "2.5.2", + "tag": "@rushstack/eslint-config_v2.5.2", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the path in the package.json \"directory\" field." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.5`" + } + ] + } + }, + { + "version": "2.5.1", + "tag": "@rushstack/eslint-config_v2.5.1", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Re-enable eslint-plugin-promise rules which now support ESLint v8" + } + ] + } + }, + { + "version": "2.5.0", + "tag": "@rushstack/eslint-config_v2.5.0", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "minor": [ + { + "comment": "Temporarily disable eslint-plugin-promise until ESLint v8 support is added (https://github.com/xjamundx/eslint-plugin-promise/issues/218)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.4`" + } + ] + } + }, + { + "version": "2.4.5", + "tag": "@rushstack/eslint-config_v2.4.5", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.1.0`" + } + ] + } + }, + { + "version": "2.4.4", + "tag": "@rushstack/eslint-config_v2.4.4", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.3`" + } + ] + } + }, + { + "version": "2.4.3", + "tag": "@rushstack/eslint-config_v2.4.3", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.8`" + } + ] + } + }, + { + "version": "2.4.2", + "tag": "@rushstack/eslint-config_v2.4.2", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "patch": [ + { + "comment": "Update typescript-eslint to add support for TypeScript 4.4." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.2`" + } + ] + } + }, + { + "version": "2.4.1", + "tag": "@rushstack/eslint-config_v2.4.1", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.1`" + } + ] + } + }, + { + "version": "2.4.0", + "tag": "@rushstack/eslint-config_v2.4.0", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.2.0`" + } + ] + } + }, + { + "version": "2.3.4", + "tag": "@rushstack/eslint-config_v2.3.4", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.2.2`" + } + ] + } + }, + { + "version": "2.3.3", + "tag": "@rushstack/eslint-config_v2.3.3", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "patch": [ + { + "comment": "Switch to range version specifier for Typescript experimental utils" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.1.4`" + } + ] + } + }, + { + "version": "2.3.2", + "tag": "@rushstack/eslint-config_v2.3.2", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to TSDoc 0.12.24" + } + ] + } + }, + { + "version": "2.3.1", + "tag": "@rushstack/eslint-config_v2.3.1", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.2.0`" + } + ] + } + }, + { + "version": "2.3.0", + "tag": "@rushstack/eslint-config_v2.3.0", + "date": "Fri, 30 Oct 2020 06:38:38 GMT", + "comments": { + "minor": [ + { + "comment": "Exclude *.d.ts from linting" + }, + { + "comment": "Set \"root\"=true to prevent unintended loading of other ESLint config files found in parent folders (which may be outside the Git working directory)" + } + ] + } + }, + { + "version": "2.2.3", + "tag": "@rushstack/eslint-config_v2.2.3", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "patch": [ + { + "comment": "Update the \"modern-module-resolution\" patch to support ESLint 7.8.0 and newer" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.6`" + } + ] + } + }, + { + "version": "2.2.2", + "tag": "@rushstack/eslint-config_v2.2.2", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.1.2`" + } + ] + } + }, + { + "version": "2.2.1", + "tag": "@rushstack/eslint-config_v2.2.1", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.1.1`" + } + ] + } + }, + { + "version": "2.2.0", + "tag": "@rushstack/eslint-config_v2.2.0", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add a mixin to support @rushstack/eslint-plugin-packlets" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.1.0`" + } + ] + } + }, + { + "version": "2.1.3", + "tag": "@rushstack/eslint-config_v2.1.3", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.1.3`" + } + ] + } + }, + { + "version": "2.1.2", + "tag": "@rushstack/eslint-config_v2.1.2", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.1.2`" + } + ] + } + }, + { + "version": "2.1.1", + "tag": "@rushstack/eslint-config_v2.1.1", + "date": "Tue, 22 Sep 2020 05:45:56 GMT", + "comments": { + "patch": [ + { + "comment": "Fix some missing files that were incorrectly excluded due to .npmignore" + } + ] + } + }, + { + "version": "2.1.0", + "tag": "@rushstack/eslint-config_v2.1.0", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "minor": [ + { + "comment": "Relax the \"typedef\" rule so that type inference is now allowed for local variables, while still requiring explicit type declarations in other scopes" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@rushstack/eslint-config_v2.0.0", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "major": [ + { + "comment": "(BREAKING CHANGE) The \"@rushstack/eslint-config\" entry point has been separated into 3 choices: \"@rushstack/eslint-config/profile/node\", \"@rushstack/eslint-config/profile/node-trusted-tool\", or \"@rushstack/eslint-config/profile/web-app\". See the documentation for details." + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/eslint-config_v1.4.2", + "date": "Sat, 19 Sep 2020 04:37:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.1.1`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/eslint-config_v1.4.1", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "patch": [ + { + "comment": "Add a dependency on the new @rushstack/eslint-plugin-security" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.1.0`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/eslint-config_v1.4.0", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "minor": [ + { + "comment": "Remove the @typescript-eslint/array-type rule" + }, + { + "comment": "Add *.spec.ts file extension for tests, since this is also a commonly used convention" + } + ], + "patch": [ + { + "comment": "Relax @typescript-eslint/no-use-before-define slightly" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/eslint-config_v1.3.0", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "minor": [ + { + "comment": "Enable the \"@rushstack/hoist-jest-mock\" lint rule to catch a common mistake when using Jest with Heft" + } + ], + "patch": [ + { + "comment": "Add an override to relax some lint rules for *.test.ts files, making unit tests easier to write" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.6.1`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/eslint-config_v1.2.1", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/eslint-config_v1.2.0", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "minor": [ + { + "comment": "Replace the \"@rushstack/no-null\" rule with a more flexible rule \"@rushstack/no-new-null\" (GitHub #2017)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/eslint-config_v1.1.0", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "minor": [ + { + "comment": "Reclassify many lint rules to report ESLint warnings rather than errors" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/eslint-config_v1.0.4", + "date": "Wed, 12 Aug 2020 00:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.4.2`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/eslint-config_v1.0.3", + "date": "Sat, 25 Jul 2020 01:38:03 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md to add the missing file extension for .eslintrc.js" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/eslint-config_v1.0.2", + "date": "Thu, 25 Jun 2020 06:43:34 GMT", + "comments": { + "patch": [ + { + "comment": "Enable variableDeclarationIgnoreFunction for the \"@typescript-eslint/typedef\" rule" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/eslint-config_v1.0.1", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the published file set" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" from `1.0.1` to `1.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.4.0` to `0.4.1`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/eslint-config_v1.0.0", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "major": [ + { + "comment": "Upgrade to ESLint 7. Breaking change: patch-eslint6.js has been renamed to patch-eslint-resolver.js" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" from `1.0.0` to `1.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.3.2` to `0.4.0`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/eslint-config_v0.5.8", + "date": "Wed, 27 May 2020 05:15:10 GMT", + "comments": { + "patch": [ + { + "comment": "Relax \"max-lines\" lint rule to 2,000 lines instead of 1,000 lines" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/eslint-config_v0.5.7", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the error message text for the \"ban-types\" rule" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/eslint-config_v0.5.6", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to eslint-plugin-tsdoc version 0.2.4" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/eslint-config_v0.5.5", + "date": "Wed, 18 Mar 2020 15:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.3.1` to `0.3.2`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/eslint-config_v0.5.4", + "date": "Tue, 21 Jan 2020 21:56:13 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade eslint-plugin-tsdoc to enable comments in tsdoc.json and more efficient loading" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/eslint-config_v0.5.3", + "date": "Sun, 19 Jan 2020 02:26:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.3.0` to `0.3.1`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/eslint-config_v0.5.2", + "date": "Fri, 17 Jan 2020 01:08:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.2.0` to `0.3.0`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/eslint-config_v0.5.1", + "date": "Thu, 09 Jan 2020 06:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.1.0` to `0.2.0`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/eslint-config_v0.5.0", + "date": "Wed, 08 Jan 2020 00:11:31 GMT", + "comments": { + "minor": [ + { + "comment": "Replace \"no-restricted-syntax\" rule with an equivalent rule \"@rushstack/no-null\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" from `0.0.0` to `0.1.0`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/eslint-config_v0.4.2", + "date": "Mon, 11 Nov 2019 16:07:56 GMT", + "comments": { + "patch": [ + { + "comment": "Add eslint-plugin-tsdoc; update plugin versions" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/eslint-config_v0.4.1", + "date": "Tue, 22 Oct 2019 06:24:44 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/eslint-config_v0.4.0", + "date": "Tue, 15 Oct 2019 01:22:16 GMT", + "comments": { + "minor": [ + { + "comment": "Rename `@microsoft/eslint-config-scalable-ts` to `@rushstack/eslint-config`" + } + ], + "patch": [ + { + "comment": "Upgraded ESLint plugin dependencies" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@microsoft/eslint-config-scalable-ts_v0.3.1", + "date": "Sun, 29 Sep 2019 23:56:29 GMT", + "comments": { + "patch": [ + { + "comment": "Update repository URL" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@microsoft/eslint-config-scalable-ts_v0.3.0", + "date": "Wed, 04 Sep 2019 01:43:31 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where the @typescript-eslint/array-type rule required a syntax that broke compatibility with TypeScript versions prior to 3.4" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@microsoft/eslint-config-scalable-ts_v0.2.3", + "date": "Tue, 03 Sep 2019 23:13:45 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to @typescript-eslint/eslint-plugin 2.1.0" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@microsoft/eslint-config-scalable-ts_v0.2.2", + "date": "Tue, 27 Aug 2019 01:48:45 GMT", + "comments": { + "patch": [ + { + "comment": "Remove unused plugin reference" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@microsoft/eslint-config-scalable-ts_v0.2.1", + "date": "Tue, 27 Aug 2019 01:24:54 GMT", + "comments": { + "patch": [ + { + "comment": "Replace \"eslint-plugin-no-null\" with a more lenient implementation that allows equality comparisons with \"null\"" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@microsoft/eslint-config-scalable-ts_v0.2.0", + "date": "Wed, 21 Aug 2019 21:56:59 GMT", + "comments": { + "minor": [ + { + "comment": "Enable react/no-deprecated, react/no-unescaped-entities, and react/self-closing-comp" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@microsoft/eslint-config-scalable-ts_v0.1.2", + "date": "Fri, 16 Aug 2019 21:58:15 GMT", + "comments": { + "patch": [ + { + "comment": "Relax peer dependency to allow usage with ESLint 5" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@microsoft/eslint-config-scalable-ts_v0.1.1", + "date": "Fri, 16 Aug 2019 01:15:03 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where @typescript-eslint/no-unused-vars didn't work properly with React source files" + }, + { + "comment": "Relax @typescript-eslint/camelcase to allow \"_checkBox1_onChanged\"" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@microsoft/eslint-config-scalable-ts_v0.1.0", + "date": "Thu, 15 Aug 2019 02:56:10 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/eslint/eslint-config/CHANGELOG.md b/eslint/eslint-config/CHANGELOG.md new file mode 100644 index 00000000000..fcf1aa50d58 --- /dev/null +++ b/eslint/eslint-config/CHANGELOG.md @@ -0,0 +1,659 @@ +# Change Log - @rushstack/eslint-config + +This log was last generated on Wed, 12 Nov 2025 01:57:54 GMT and should not be manually modified. + +## 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 + +### Minor changes + +- Update TSDoc dependencies. + +## 4.0.2 +Thu, 19 Sep 2024 00:11:08 GMT + +### Patches + +- Fix ESLint broken links + +## 4.0.1 +Wed, 14 Aug 2024 22:37:32 GMT + +_Version update only_ + +## 4.0.0 +Tue, 13 Aug 2024 18:17:05 GMT + +### Breaking changes + +- [BREAKING CHANGE] Bump "@typescript-eslint/eslint-plugin" to "~8.1.0" and "@typescript-eslint/eslint-parser" to "~8.1.0". Due to these changes, node@>=17.0.0 and eslint@^8.57.0 are now required due to breaking changes in the newer rules set. + +## 3.7.1 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 3.7.0 +Wed, 29 May 2024 00:10:52 GMT + +### Minor changes + +- Bump the `eslint-plugin-tsdoc` plugin. + +## 3.6.10 +Fri, 17 May 2024 00:10:40 GMT + +_Version update only_ + +## 3.6.9 +Wed, 10 Apr 2024 21:59:39 GMT + +_Version update only_ + +## 3.6.8 +Fri, 29 Mar 2024 05:46:41 GMT + +_Version update only_ + +## 3.6.7 +Thu, 28 Mar 2024 18:11:12 GMT + +_Version update only_ + +## 3.6.6 +Wed, 27 Mar 2024 19:47:21 GMT + +_Version update only_ + +## 3.6.5 +Wed, 20 Mar 2024 02:09:14 GMT + +_Version update only_ + +## 3.6.4 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 3.6.3 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 3.6.2 +Thu, 25 Jan 2024 23:03:57 GMT + +_Version update only_ + +## 3.6.1 +Wed, 24 Jan 2024 07:38:34 GMT + +_Version update only_ + +## 3.6.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 with @typescript-eslint 6.19.x + +## 3.5.1 +Fri, 15 Dec 2023 01:10:06 GMT + +_Version update only_ + +## 3.5.0 +Wed, 22 Nov 2023 01:45:18 GMT + +### Minor changes + +- Added eslint-bulk-suppressions to @rushstack/eslint-config dependencies, allowing it to be used in all projects that use rushstack's eslint-config + +## 3.4.1 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 3.4.0 +Tue, 26 Sep 2023 09:30:33 GMT + +### Minor changes + +- Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the "eslint-config-" prefix + +## 3.3.4 +Fri, 15 Sep 2023 00:36:58 GMT + +_Version update only_ + +## 3.3.3 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 3.3.2 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 3.3.1 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 3.3.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the @typescript-eslint/* dependencies to ~5.59.2 + +## 3.2.0 +Fri, 10 Feb 2023 01:18:50 GMT + +### Minor changes + +- Replace the @typescript-eslint/no-parameter-properties rule with the replacement rule (@typescript-eslint/parameter-properties). + +## 3.1.1 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 3.1.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8 + +## 3.0.1 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 3.0.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Breaking changes + +- Upgrade TypeScript dependency to 4.7. This package now requires a peerDependency on TypeScript >=4.7 + +## 2.6.2 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 2.6.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 2.6.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.6 + +## 2.5.4 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 2.5.3 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 2.5.2 +Tue, 15 Mar 2022 19:15:53 GMT + +### Patches + +- Fix the path in the package.json "directory" field. + +## 2.5.1 +Mon, 27 Dec 2021 16:10:40 GMT + +### Patches + +- Re-enable eslint-plugin-promise rules which now support ESLint v8 + +## 2.5.0 +Mon, 06 Dec 2021 16:08:32 GMT + +### Minor changes + +- Temporarily disable eslint-plugin-promise until ESLint v8 support is added (https://github.com/xjamundx/eslint-plugin-promise/issues/218) + +## 2.4.5 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 2.4.4 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 2.4.3 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 2.4.2 +Thu, 07 Oct 2021 07:13:35 GMT + +### Patches + +- Update typescript-eslint to add support for TypeScript 4.4. + +## 2.4.1 +Thu, 23 Sep 2021 00:10:40 GMT + +_Version update only_ + +## 2.4.0 +Mon, 12 Jul 2021 23:08:26 GMT + +### Minor changes + +- Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389) + +## 2.3.4 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 2.3.3 +Tue, 06 Apr 2021 15:14:22 GMT + +### Patches + +- Switch to range version specifier for Typescript experimental utils + +## 2.3.2 +Thu, 10 Dec 2020 23:25:49 GMT + +### Patches + +- Upgrade to TSDoc 0.12.24 + +## 2.3.1 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 2.3.0 +Fri, 30 Oct 2020 06:38:38 GMT + +### Minor changes + +- Exclude *.d.ts from linting +- Set "root"=true to prevent unintended loading of other ESLint config files found in parent folders (which may be outside the Git working directory) + +## 2.2.3 +Fri, 30 Oct 2020 00:10:14 GMT + +### Patches + +- Update the "modern-module-resolution" patch to support ESLint 7.8.0 and newer + +## 2.2.2 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 2.2.1 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 2.2.0 +Mon, 05 Oct 2020 22:36:57 GMT + +### Minor changes + +- Add a mixin to support @rushstack/eslint-plugin-packlets + +## 2.1.3 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 2.1.2 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 2.1.1 +Tue, 22 Sep 2020 05:45:56 GMT + +### Patches + +- Fix some missing files that were incorrectly excluded due to .npmignore + +## 2.1.0 +Tue, 22 Sep 2020 01:45:31 GMT + +### Minor changes + +- Relax the "typedef" rule so that type inference is now allowed for local variables, while still requiring explicit type declarations in other scopes + +## 2.0.0 +Tue, 22 Sep 2020 00:08:53 GMT + +### Breaking changes + +- (BREAKING CHANGE) The "@rushstack/eslint-config" entry point has been separated into 3 choices: "@rushstack/eslint-config/profile/node", "@rushstack/eslint-config/profile/node-trusted-tool", or "@rushstack/eslint-config/profile/web-app". See the documentation for details. + +## 1.4.2 +Sat, 19 Sep 2020 04:37:26 GMT + +_Version update only_ + +## 1.4.1 +Sat, 19 Sep 2020 03:33:06 GMT + +### Patches + +- Add a dependency on the new @rushstack/eslint-plugin-security + +## 1.4.0 +Fri, 18 Sep 2020 22:57:24 GMT + +### Minor changes + +- Remove the @typescript-eslint/array-type rule +- Add *.spec.ts file extension for tests, since this is also a commonly used convention + +### Patches + +- Relax @typescript-eslint/no-use-before-define slightly + +## 1.3.0 +Thu, 27 Aug 2020 11:27:06 GMT + +### Minor changes + +- Enable the "@rushstack/hoist-jest-mock" lint rule to catch a common mistake when using Jest with Heft + +### Patches + +- Add an override to relax some lint rules for *.test.ts files, making unit tests easier to write + +## 1.2.1 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 1.2.0 +Sat, 22 Aug 2020 05:55:42 GMT + +### Minor changes + +- Replace the "@rushstack/no-null" rule with a more flexible rule "@rushstack/no-new-null" (GitHub #2017) + +## 1.1.0 +Mon, 17 Aug 2020 04:53:23 GMT + +### Minor changes + +- Reclassify many lint rules to report ESLint warnings rather than errors + +## 1.0.4 +Wed, 12 Aug 2020 00:10:06 GMT + +_Version update only_ + +## 1.0.3 +Sat, 25 Jul 2020 01:38:03 GMT + +### Patches + +- Update README.md to add the missing file extension for .eslintrc.js + +## 1.0.2 +Thu, 25 Jun 2020 06:43:34 GMT + +### Patches + +- Enable variableDeclarationIgnoreFunction for the "@typescript-eslint/typedef" rule + +## 1.0.1 +Wed, 24 Jun 2020 09:50:48 GMT + +### Patches + +- Fix an issue with the published file set + +## 1.0.0 +Wed, 24 Jun 2020 09:04:28 GMT + +### Breaking changes + +- Upgrade to ESLint 7. Breaking change: patch-eslint6.js has been renamed to patch-eslint-resolver.js + +## 0.5.8 +Wed, 27 May 2020 05:15:10 GMT + +### Patches + +- Relax "max-lines" lint rule to 2,000 lines instead of 1,000 lines + +## 0.5.7 +Wed, 08 Apr 2020 04:07:33 GMT + +### Patches + +- Improve the error message text for the "ban-types" rule + +## 0.5.6 +Sat, 28 Mar 2020 00:37:16 GMT + +### Patches + +- Upgrade to eslint-plugin-tsdoc version 0.2.4 + +## 0.5.5 +Wed, 18 Mar 2020 15:07:47 GMT + +_Version update only_ + +## 0.5.4 +Tue, 21 Jan 2020 21:56:13 GMT + +### Patches + +- Upgrade eslint-plugin-tsdoc to enable comments in tsdoc.json and more efficient loading + +## 0.5.3 +Sun, 19 Jan 2020 02:26:53 GMT + +_Version update only_ + +## 0.5.2 +Fri, 17 Jan 2020 01:08:23 GMT + +_Version update only_ + +## 0.5.1 +Thu, 09 Jan 2020 06:44:13 GMT + +_Version update only_ + +## 0.5.0 +Wed, 08 Jan 2020 00:11:31 GMT + +### Minor changes + +- Replace "no-restricted-syntax" rule with an equivalent rule "@rushstack/no-null" + +## 0.4.2 +Mon, 11 Nov 2019 16:07:56 GMT + +### Patches + +- Add eslint-plugin-tsdoc; update plugin versions + +## 0.4.1 +Tue, 22 Oct 2019 06:24:44 GMT + +### Patches + +- Update documentation + +## 0.4.0 +Tue, 15 Oct 2019 01:22:16 GMT + +### Minor changes + +- Rename `@microsoft/eslint-config-scalable-ts` to `@rushstack/eslint-config` + +### Patches + +- Upgraded ESLint plugin dependencies + +## 0.3.1 +Sun, 29 Sep 2019 23:56:29 GMT + +### Patches + +- Update repository URL + +## 0.3.0 +Wed, 04 Sep 2019 01:43:31 GMT + +### Minor changes + +- Fix an issue where the @typescript-eslint/array-type rule required a syntax that broke compatibility with TypeScript versions prior to 3.4 + +## 0.2.3 +Tue, 03 Sep 2019 23:13:45 GMT + +### Patches + +- Upgrade to @typescript-eslint/eslint-plugin 2.1.0 + +## 0.2.2 +Tue, 27 Aug 2019 01:48:45 GMT + +### Patches + +- Remove unused plugin reference + +## 0.2.1 +Tue, 27 Aug 2019 01:24:54 GMT + +### Patches + +- Replace "eslint-plugin-no-null" with a more lenient implementation that allows equality comparisons with "null" + +## 0.2.0 +Wed, 21 Aug 2019 21:56:59 GMT + +### Minor changes + +- Enable react/no-deprecated, react/no-unescaped-entities, and react/self-closing-comp + +## 0.1.2 +Fri, 16 Aug 2019 21:58:15 GMT + +### Patches + +- Relax peer dependency to allow usage with ESLint 5 + +## 0.1.1 +Fri, 16 Aug 2019 01:15:03 GMT + +### Patches + +- Fix an issue where @typescript-eslint/no-unused-vars didn't work properly with React source files +- Relax @typescript-eslint/camelcase to allow "_checkBox1_onChanged" + +## 0.1.0 +Thu, 15 Aug 2019 02:56:10 GMT + +### Minor changes + +- Initial release + diff --git a/stack/eslint-config/LICENSE b/eslint/eslint-config/LICENSE similarity index 100% rename from stack/eslint-config/LICENSE rename to eslint/eslint-config/LICENSE diff --git a/eslint/eslint-config/README.md b/eslint/eslint-config/README.md new file mode 100644 index 00000000000..cff35291a57 --- /dev/null +++ b/eslint/eslint-config/README.md @@ -0,0 +1,274 @@ +# @rushstack/eslint-config + +A TypeScript ESLint ruleset designed for large teams and projects. + +## Philosophy + +When you work in a small repo, you spend most of your time writing code. You know what each file does. You want lint +rules that keep things concise and won't slow you down. That's the situation for the 99% of open source projects +that shape popular coding conventions. + +But as your organization scales up, things may change. People come and go. Projects frequently get handed off between +teams. Every day, you find yourself working with files that you've never seen before, created by strangers whom +you may never meet. It's annoying to constantly come across inconsistent styles. It can be frustrating to decipher +expressions that seem to require a TypeScript Ph.D. -- especially for newcomers and junior contributors. When +refactoring in bulk, you may edit lots of files without reading them very carefully. In short, the linting needs +reflect different priorities: + +**Small scale:** We can assume developers are _familiar_ with the project. We want code to be _easy to write_. + +**Large scale:** Developers are generally _unfamiliar_ with projects. Code must be _easy to read_. If not, +there's a risk of fragmentation, duplication of efforts, and costly rewrites. (Enabling people to churn out +lots of code really fast is still a goal of course; just not the #1 priority.) + +Welcome to the world of [Rush Stack](https://rushstack.io/)! The `@rushstack/eslint-config` package was specifically +designed around the the requirements of large teams and projects. + + +## Implementation + +- **Monorepo friendly:** The `@rushstack/eslint-config` package has direct dependencies on all the ESLint plugins + that it needs. This avoids encumbering each consuming project with the obligation to satisfy a peer dependencies. + It also ensures that the installed plugin versions were tested for compatibility together. + +- **Battle tested:** The `@rushstack/eslint-config` rules have been vetted on large production monorepos, across + a broad set of projects, teams, and requirements. These rules embody a way of working that scales. Quite + a lot of discussion and evolution went into them. + +- **Designed for Prettier:** The `@rushstack/eslint-config` ruleset is designed to be used together with + the [Prettier](https://prettier.io/) code formatter. This separation of workflows avoids hassling developers with + lint "errors" for frivolous issues like spaces and commas. Instead, those issues get fixed automatically whenever + you save or commit a file. Prettier also avoids frivolous debates: its defaults have already been debated + at length and adopted by a sizeable community. No need to reinvent the wheel! + +- **Explicit:** The ruleset does not import any "recommended" templates from other ESLint packages. This avoids + worrying about precedence issues due to import order. It also eliminates confusion caused by files + overriding/undoing settings from another file. Each rule is configured once, in one + [easy-to-read file](https://github.com/microsoft/rushstack/blob/main/eslint/eslint-config/profile/_common.js). + +- **Minimal configuration:** To use this ruleset, your **.eslintrc.js** will need to choose one **"profile"** + and possibly one or two **"mixins"** that cover special cases. Beyond that, our goal is to reduce monorepo + maintenance by providing a small set of **.eslintrc.js** recipes that can be reused across many different projects. + (This sometimes means that rules will be included which have no effect for a particular project, however in practice + the installation/execution cost for unused rules turns out to be negligible.) + + +## Getting started in 3 steps + +Applying the ruleset to your project is quick and easy. You install the package, then create an **.eslintrc.js** file +and select an appropriate project profile. Optionally you can also add some "mixins" to enable additional rules. +Let's walk through those three steps in more detail. + +### 1. Install the package + +To install the package, do this: + +```sh +$ cd your-project-folder +$ npm install --save-dev eslint +$ npm install --save-dev typescript +$ npm install --save-dev @rushstack/eslint-config +``` + +### 2. Choose one profile + +The ruleset currently supports three different "profile" strings, which select lint rules applicable for +your project: + +- `@rushstack/eslint-config/profile/node` - 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. + +- `@rushstack/eslint-config/profile/node-trusted-tool` - 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 exclusively on 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.** + +- `@rushstack/eslint-config/profile/web-app` - This profile enables lint rules intended for a web application, for + example 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._ + +After choosing a profile, create an **.eslintrc.js** config file that provides the NodeJS `__dirname` context +for TypeScript. Add your profile string in the `extends` field, as shown below: + +**.eslintrc.js** +```ts +// 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" ], // <---- put your profile string here + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + +The `@rushstack/eslint-config` ruleset is intended to be used with the Prettier code formatter. For general +instructions on setting that up, please refer to the [Prettier docs](https://prettier.io/docs/en/index.html). +For Rush-specific settings, see the article +[Rush: Enabling Prettier](https://rushjs.io/pages/maintainer/enabling_prettier/). + + +### 3. Add any relevant mixins + +Optionally, you can add some "mixins" to your `extends` array to opt-in to some extra behaviors. + +Important: Your **.eslintrc.js** `"extends"` field must load mixins after the profile entry. + + +#### `@rushstack/eslint-config/mixins/friendly-locals` + +Requires explicit type declarations for local variables. + +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 [GitHub #2206](https://github.com/microsoft/rushstack/issues/2206) for background. + +If you are onboarding a large existing code base, this new default will make adoption easier: + +Example source file without `mixins/friendly-locals`: +```ts +export class MyDataService { + . . . + public queryResult(provider: IProvider): IResult { + // Type inference is concise, but what are "item", "index", and "data"? + const item = provider.getItem(provider.title); + const index = item.fetchIndex(); + const data = index.get(provider.state); + return data.results.filter(x => x.title === provider.title); + } +} +``` + +On the other hand, if your priority is make source files more friendly for other people to read, you can enable +the `"@rushstack/eslint-config/mixins/friendly-locals"` mixin. This restores the requirement that local variables +should have explicit type declarations. + +Example source file with `mixins/friendly-locals`: +```ts +export class MyDataService { + . . . + public queryResult(provider: IProvider): IResult { + // This is more work for the person writing the code... but definitely easier to understand + // for a code reviewer if they are unfamiliar with your project + const item: ISalesReport = provider.getItem(provider.title); + const index: Map = item.fetchIndex(); + const data: IGeographicData | undefined = index.get(provider.state); + return data.results.filter(x => x.title === provider.title); + } +} +``` + +Add the mixin to your `"extends"` field like this: + +**.eslintrc.js** +```ts +// 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", + "@rushstack/eslint-config/mixins/friendly-locals" // <---- + ], + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + + +#### `@rushstack/eslint-config/mixins/packlets` + +Packlets provide a lightweight alternative to NPM packages for organizing source files within a single project. +This system is described in the [@rushstack/eslint-plugin-packlets](https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets) +documentation. + +To use packlets, add the mixin to your `"extends"` field like this: + +**.eslintrc.js** +```ts +// 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", + "@rushstack/eslint-config/mixins/packlets" // <---- + ], + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + + +#### `@rushstack/eslint-config/mixins/tsdoc` + +If your project is using [API Extractor](https://api-extractor.com/) or another tool that uses +the [TSDoc](https://github.com/Microsoft/tsdoc) standard for doc comments, it's recommended to use the +`"@rushstack/eslint-config/mixins/tsdoc"` mixin. It will enable +[eslint-plugin-tsdoc](https://www.npmjs.com/package/eslint-plugin-tsdoc) validation for TypeScript doc comments. + +Add the mixin to your `"extends"` field like this: + +**.eslintrc.js** +```ts +// 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", + "@rushstack/eslint-config/mixins/tsdoc" // <---- + ], + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + + +#### `@rushstack/eslint-config/mixins/react` + +For projects using the [React](https://reactjs.org/) library, the `"@rushstack/eslint-config/mixins/react"` mixin +enables some recommended additional rules. These rules are selected via a mixin because they require you to: + +- Add `"jsx": "react"` to your **tsconfig.json** +- Configure your `settings.react.version` as shown below. This determines which React APIs will be considered + to be deprecated. (If you omit this, the React version will be detected automatically by + [loading the entire React library](https://github.com/yannickcr/eslint-plugin-react/blob/4da74518bd78f11c9c6875a159ffbae7d26be693/lib/util/version.js#L23) + into the linter's process, which is costly.) + +Add the mixin to your `"extends"` field like this: + +**.eslintrc.js** +```ts +// 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/web-app", + "@rushstack/eslint-config/mixins/react" // <---- + ], + parserOptions: { tsconfigRootDir: __dirname }, + + settings: { + react: { + "version": "16.9" // <---- + } + } +}; +``` + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/eslint/eslint-config/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/eslint-config` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/eslint/eslint-config/config/rush-project.json b/eslint/eslint-config/config/rush-project.json new file mode 100644 index 00000000000..514e557d5eb --- /dev/null +++ b/eslint/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: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/eslint-config/flat/patch/eslint-bulk-suppressions.js b/eslint/eslint-config/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..12c37b253da --- /dev/null +++ b/eslint/eslint-config/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-patch/eslint-bulk-suppressions'); diff --git a/eslint/eslint-config/flat/profile/_common.js b/eslint/eslint-config/flat/profile/_common.js new file mode 100644 index 00000000000..cb35456c9db --- /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): JSX.Element { + // . . . + // } + // } + 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/index.js b/eslint/eslint-config/index.js new file mode 100644 index 00000000000..b8eedd9c41f --- /dev/null +++ b/eslint/eslint-config/index.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. + +throw new Error( + 'The index.js entry point has been removed. Please update your ESLint configuration to import one of the' + + ' profile paths such as "@rushstack/eslint-config/profile/web-app" or "@rushstack/eslint-config/profile/node.' + + '\n\nSee the documentation for details: https://www.npmjs.com/package/@rushstack/eslint-config' +); diff --git a/eslint/eslint-config/mixins/friendly-locals.js b/eslint/eslint-config/mixins/friendly-locals.js new file mode 100644 index 00000000000..35b1dcd686f --- /dev/null +++ b/eslint/eslint-config/mixins/friendly-locals.js @@ -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. + +// 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: Your .eslintrc.js "extends" field must load mixins AFTER the profile. +module.exports = { + overrides: [ + { + files: ['*.ts', '*.tsx'], + 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 + } + ] + } + }, + // Note that the above block also applies to *.test.ts, so we need to + // reapply those overrides. + { + 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: { + '@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/mixins/packlets.js b/eslint/eslint-config/mixins/packlets.js new file mode 100644 index 00000000000..9c6b791e546 --- /dev/null +++ b/eslint/eslint-config/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 +module.exports = { + plugins: ['@rushstack/eslint-plugin-packlets'], + + overrides: [ + { + // Declare an override that applies to TypeScript files only + files: ['*.ts', '*.tsx'], + + rules: { + '@rushstack/packlets/mechanics': 'warn', + '@rushstack/packlets/circular-deps': 'warn' + } + } + ] +}; diff --git a/eslint/eslint-config/mixins/react.js b/eslint/eslint-config/mixins/react.js new file mode 100644 index 00000000000..00e06aa0074 --- /dev/null +++ b/eslint/eslint-config/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". +module.exports = { + // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-react + plugins: ['eslint-plugin-react'], + + 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' + } + }, + + overrides: [ + { + // Declare an override that applies to TypeScript files only + files: ['*.ts', '*.tsx'], + + 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/mixins/tsdoc.js b/eslint/eslint-config/mixins/tsdoc.js new file mode 100644 index 00000000000..5e07fc79e28 --- /dev/null +++ b/eslint/eslint-config/mixins/tsdoc.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. + +// 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. +module.exports = { + // The plugin documentation is here: https://www.npmjs.com/package/eslint-plugin-tsdoc + plugins: ['eslint-plugin-tsdoc'], + + overrides: [ + { + // Declare an override that applies to TypeScript files only + files: ['*.ts', '*.tsx'], + + rules: { + 'tsdoc/syntax': 'warn' + } + } + ] +}; diff --git a/eslint/eslint-config/package.json b/eslint/eslint-config/package.json new file mode 100644 index 00000000000..1b07e3584eb --- /dev/null +++ b/eslint/eslint-config/package.json @@ -0,0 +1,46 @@ +{ + "name": "@rushstack/eslint-config", + "version": "4.6.1", + "description": "A TypeScript ESLint ruleset designed for large teams and projects", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-config" + }, + "homepage": "https://rushstack.io", + "scripts": { + "build": "", + "_phase:build": "" + }, + "keywords": [ + "eslint", + "eslint-config", + "monorepo", + "rush", + "scalable", + "scale", + "typescript" + ], + "peerDependencies": { + "eslint": "^8.57.0 || ^9.25.1", + "typescript": ">=4.7.0" + }, + "dependencies": { + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/eslint-plugin": "workspace:*", + "@rushstack/eslint-plugin-packlets": "workspace:*", + "@rushstack/eslint-plugin-security": "workspace:*", + "@typescript-eslint/eslint-plugin": "~8.46.0", + "@typescript-eslint/utils": "~8.46.0", + "@typescript-eslint/parser": "~8.46.0", + "@typescript-eslint/typescript-estree": "~8.46.0", + "eslint-plugin-promise": "~7.2.1", + "eslint-plugin-react": "~7.37.5", + "eslint-plugin-tsdoc": "~0.5.0" + }, + "devDependencies": { + "eslint": "~9.37.0", + "typescript": "~5.8.2" + } +} diff --git a/eslint/eslint-config/patch-eslint6.js b/eslint/eslint-config/patch-eslint6.js new file mode 100644 index 00000000000..336494cb3b9 --- /dev/null +++ b/eslint/eslint-config/patch-eslint6.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. + +throw new Error( + 'The patch-eslint6.js script has been rewritten to support both ESLint 6.x and 7.x.' + + ' Please update your ESLint configuration to use this path instead:\n\n' + + ' require("@rushstack/eslint-config/patch/modern-module-resolution");' +); diff --git a/eslint/eslint-config/patch/custom-config-package-names.js b/eslint/eslint-config/patch/custom-config-package-names.js new file mode 100644 index 00000000000..20341195020 --- /dev/null +++ b/eslint/eslint-config/patch/custom-config-package-names.js @@ -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. + +require('@rushstack/eslint-patch/custom-config-package-names'); diff --git a/eslint/eslint-config/patch/eslint-bulk-suppressions.js b/eslint/eslint-config/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..12c37b253da --- /dev/null +++ b/eslint/eslint-config/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-patch/eslint-bulk-suppressions'); diff --git a/eslint/eslint-config/patch/modern-module-resolution.js b/eslint/eslint-config/patch/modern-module-resolution.js new file mode 100644 index 00000000000..d4ba8827123 --- /dev/null +++ b/eslint/eslint-config/patch/modern-module-resolution.js @@ -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. + +require('@rushstack/eslint-patch/modern-module-resolution'); diff --git a/eslint/eslint-config/profile/_common.js b/eslint/eslint-config/profile/_common.js new file mode 100644 index 00000000000..2ceda351b0c --- /dev/null +++ b/eslint/eslint-config/profile/_common.js @@ -0,0 +1,804 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const macros = require('./_macros'); + +const namingConventionRuleOptions = [ + { + // 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): JSX.Element { + // . . . + // } + // } + 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 + } + } +]; + +// 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 + +function buildRules(profile) { + return { + // After an .eslintrc.js file is loaded, ESLint will normally continue visiting all parent folders + // to look for other .eslintrc.js files, and also consult a personal file ~/.eslintrc.js. If any files + // are found, their options will be merged. This is difficult for humans to understand, and it will cause + // nondeterministic behavior if files are loaded from outside the Git working folder. + // + // Setting root=true causes ESLint to stop looking for other config files after the first .eslintrc.js + // is loaded. + root: true, + + // Disable the parser by default + parser: '', + + plugins: [ + // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin + '@rushstack/eslint-plugin', + // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin-security + '@rushstack/eslint-plugin-security', + // Plugin documentation: https://www.npmjs.com/package/@typescript-eslint/eslint-plugin + '@typescript-eslint/eslint-plugin', + // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-promise + 'eslint-plugin-promise' + ], + + // 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. + ignorePatterns: ['*.d.ts'], + + overrides: [ + { + // Declare an override that applies to TypeScript files only + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser', + 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' + }, + + rules: { + // ==================================================================== + // CUSTOM RULES + // ==================================================================== + + // The @rushstack rules are documented in the package README: + // https://www.npmjs.com/package/@rushstack/eslint-plugin + + // 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 + // ==================================================================== + + // This is disabled for tools because, for example, it is a common and safe practice for a tool + // to read a RegExp from a config file and use it to filter files paths. + '@rushstack/security/no-unsafe-regexp': profile === 'node-trusted-tool' ? 'off' : 'warn', + + // ==================================================================== + // GENERAL 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', + ...macros.expandNamingConventionSelectors(namingConventionRuleOptions) + ], + + // 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 + } + ], + + // 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": [ + // ], + } + }, + { + // 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' + ], + 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', + '@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 + } + ] + } + } + ] + }; +} + +exports.buildRules = buildRules; +exports.namingConventionRuleOptions = namingConventionRuleOptions; diff --git a/eslint/eslint-config/profile/_macros.js b/eslint/eslint-config/profile/_macros.js new file mode 100644 index 00000000000..87c8487b314 --- /dev/null +++ b/eslint/eslint-config/profile/_macros.js @@ -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. + +// 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; +} + +exports.expandNamingConventionSelectors = expandNamingConventionSelectors; diff --git a/eslint/eslint-config/profile/node-trusted-tool.js b/eslint/eslint-config/profile/node-trusted-tool.js new file mode 100644 index 00000000000..f185f532b70 --- /dev/null +++ b/eslint/eslint-config/profile/node-trusted-tool.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. + +// 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 { buildRules } = require('./_common'); + +const rules = buildRules('node-trusted-tool'); +module.exports = rules; diff --git a/eslint/eslint-config/profile/node.js b/eslint/eslint-config/profile/node.js new file mode 100644 index 00000000000..df3b0dc79fa --- /dev/null +++ b/eslint/eslint-config/profile/node.js @@ -0,0 +1,11 @@ +// 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/eslint-config/profile/web-app.js b/eslint/eslint-config/profile/web-app.js new file mode 100644 index 00000000000..916b888ec6e --- /dev/null +++ b/eslint/eslint-config/profile/web-app.js @@ -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. + +// 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/eslint/eslint-config/react.js b/eslint/eslint-config/react.js new file mode 100644 index 00000000000..14516d2ff32 --- /dev/null +++ b/eslint/eslint-config/react.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. + +throw new Error( + 'The react.js entry point has moved. Please update your ESLint configuration to reference' + + ' "@rushstack/eslint-config/mixins/react" instead.' + + '\n\nSee the documentation for details: https://www.npmjs.com/package/@rushstack/eslint-config' +); diff --git a/eslint/eslint-patch/.npmignore b/eslint/eslint-patch/.npmignore new file mode 100644 index 00000000000..285cde9e713 --- /dev/null +++ b/eslint/eslint-patch/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!*.js +gulpfile.js diff --git a/eslint/eslint-patch/CHANGELOG.json b/eslint/eslint-patch/CHANGELOG.json new file mode 100644 index 00000000000..2ecb40a74d5 --- /dev/null +++ b/eslint/eslint-patch/CHANGELOG.json @@ -0,0 +1,513 @@ +{ + "name": "@rushstack/eslint-patch", + "entries": [ + { + "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", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ] + } + }, + { + "version": "1.10.3", + "tag": "@rushstack/eslint-patch_v1.10.3", + "date": "Fri, 17 May 2024 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "[eslint-patch] Allow use of ESLint v9" + } + ] + } + }, + { + "version": "1.10.2", + "tag": "@rushstack/eslint-patch_v1.10.2", + "date": "Wed, 10 Apr 2024 21:59:39 GMT", + "comments": { + "patch": [ + { + "comment": "Bump maximum supported ESLint version for the bulk-suppressions tool to `8.57.0`." + } + ] + } + }, + { + "version": "1.10.1", + "tag": "@rushstack/eslint-patch_v1.10.1", + "date": "Fri, 29 Mar 2024 05:46:41 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `eslint-bulk prune` command would crash if a bulk suppressions file exists that speicifies no suppressions." + }, + { + "comment": "Exit with success under normal conditions." + } + ] + } + }, + { + "version": "1.10.0", + "tag": "@rushstack/eslint-patch_v1.10.0", + "date": "Thu, 28 Mar 2024 18:11:12 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with running `eslint-bulk prune` in a project with suppressions that refer to deleted files." + } + ], + "minor": [ + { + "comment": "Delete the `.eslint-bulk-suppressions.json` file during pruning if all suppressions have been eliminated." + } + ] + } + }, + { + "version": "1.9.0", + "tag": "@rushstack/eslint-patch_v1.9.0", + "date": "Wed, 27 Mar 2024 19:47:21 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where `eslint-bulk prune` does not work if there are no files to lint in the project root." + } + ] + } + }, + { + "version": "1.8.0", + "tag": "@rushstack/eslint-patch_v1.8.0", + "date": "Wed, 20 Mar 2024 02:09:14 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor the bulk-suppressions feature to fix some performance issues." + } + ], + "patch": [ + { + "comment": "Fix an issue where linting issues that were already suppressed via suppression comments were recorded in the bulk suppressions list." + } + ] + } + }, + { + "version": "1.7.2", + "tag": "@rushstack/eslint-patch_v1.7.2", + "date": "Thu, 25 Jan 2024 23:03:57 GMT", + "comments": { + "patch": [ + { + "comment": "Some minor documentation updates" + } + ] + } + }, + { + "version": "1.7.1", + "tag": "@rushstack/eslint-patch_v1.7.1", + "date": "Wed, 24 Jan 2024 07:38:34 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation" + } + ] + } + }, + { + "version": "1.7.0", + "tag": "@rushstack/eslint-patch_v1.7.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3 with @typescript-eslint 6.19.x" + } + ] + } + }, + { + "version": "1.6.1", + "tag": "@rushstack/eslint-patch_v1.6.1", + "date": "Fri, 15 Dec 2023 01:10:06 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bulk suppression patch's eslintrc detection in polyrepos" + } + ] + } + }, + { + "version": "1.6.0", + "tag": "@rushstack/eslint-patch_v1.6.0", + "date": "Wed, 22 Nov 2023 01:45:18 GMT", + "comments": { + "minor": [ + { + "comment": "Add an experimental new feature for ESLint bulk suppressions; for details see GitHub #4303" + } + ] + } + }, + { + "version": "1.5.1", + "tag": "@rushstack/eslint-patch_v1.5.1", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "patch": [ + { + "comment": "Fix patch compatibility with ESLint 7 for versions matching <7.12.0" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/eslint-patch_v1.5.0", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the \"eslint-config-\" prefix" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/eslint-patch_v1.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/eslint-patch_v1.3.3", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "patch": [ + { + "comment": "Fix patching for running eslint via eslint/use-at-your-own-risk, which VS Code's eslint extension does when enabling flat config support" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/eslint-patch_v1.3.2", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "patch": [ + { + "comment": "[eslint-patch] add invalid importer path test to ESLint 7.x || 8.x block" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/eslint-patch_v1.3.1", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "patch": [ + { + "comment": "Add test for invalid importer path to fallback to relative path when loading eslint 6 plugins" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/eslint-patch_v1.3.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the @typescript-eslint/* dependencies to ~5.59.2" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/eslint-patch_v1.2.0", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "minor": [ + { + "comment": "Use original resolver if patched resolver fails." + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/eslint-patch_v1.1.4", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "patch": [ + { + "comment": "Update the README to mention support for ESLint 8." + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/eslint-patch_v1.1.3", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where tools could not determine the module type as CommonJS" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/eslint-patch_v1.1.2", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/eslint-patch_v1.1.1", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the path in the package.json \"directory\" field." + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/eslint-patch_v1.1.0", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "minor": [ + { + "comment": "feat(eslint-patch): Find patch targets independently of disk layout" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/eslint-patch_v1.0.9", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/eslint-patch_v1.0.8", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for ESLint 8.0.0" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/eslint-patch_v1.0.7", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/eslint-patch_v1.0.6", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "patch": [ + { + "comment": "Update the \"modern-module-resolution\" patch to support ESLint 7.8.0 and newer" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/eslint-patch_v1.0.5", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/eslint-patch_v1.0.4", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/eslint-patch_v1.0.3", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/eslint-patch_v1.0.2", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the published file set" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/eslint-patch_v1.0.1", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "patch": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/eslint/eslint-patch/CHANGELOG.md b/eslint/eslint-patch/CHANGELOG.md new file mode 100644 index 00000000000..212bc897402 --- /dev/null +++ b/eslint/eslint-patch/CHANGELOG.md @@ -0,0 +1,301 @@ +# Change Log - @rushstack/eslint-patch + +This log was last generated on Wed, 12 Nov 2025 01:57:54 GMT and should not be manually modified. + +## 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 + +### Patches + +- Include CHANGELOG.md in published releases again + +## 1.10.3 +Fri, 17 May 2024 00:10:40 GMT + +### Patches + +- [eslint-patch] Allow use of ESLint v9 + +## 1.10.2 +Wed, 10 Apr 2024 21:59:39 GMT + +### Patches + +- Bump maximum supported ESLint version for the bulk-suppressions tool to `8.57.0`. + +## 1.10.1 +Fri, 29 Mar 2024 05:46:41 GMT + +### Patches + +- Fix an issue where the `eslint-bulk prune` command would crash if a bulk suppressions file exists that speicifies no suppressions. +- Exit with success under normal conditions. + +## 1.10.0 +Thu, 28 Mar 2024 18:11:12 GMT + +### Minor changes + +- Delete the `.eslint-bulk-suppressions.json` file during pruning if all suppressions have been eliminated. + +### Patches + +- Fix an issue with running `eslint-bulk prune` in a project with suppressions that refer to deleted files. + +## 1.9.0 +Wed, 27 Mar 2024 19:47:21 GMT + +### Minor changes + +- Fix an issue where `eslint-bulk prune` does not work if there are no files to lint in the project root. + +## 1.8.0 +Wed, 20 Mar 2024 02:09:14 GMT + +### Minor changes + +- Refactor the bulk-suppressions feature to fix some performance issues. + +### Patches + +- Fix an issue where linting issues that were already suppressed via suppression comments were recorded in the bulk suppressions list. + +## 1.7.2 +Thu, 25 Jan 2024 23:03:57 GMT + +### Patches + +- Some minor documentation updates + +## 1.7.1 +Wed, 24 Jan 2024 07:38:34 GMT + +### Patches + +- Update documentation + +## 1.7.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 with @typescript-eslint 6.19.x + +## 1.6.1 +Fri, 15 Dec 2023 01:10:06 GMT + +### Patches + +- Fix bulk suppression patch's eslintrc detection in polyrepos + +## 1.6.0 +Wed, 22 Nov 2023 01:45:18 GMT + +### Minor changes + +- Add an experimental new feature for ESLint bulk suppressions; for details see GitHub #4303 + +## 1.5.1 +Sun, 01 Oct 2023 02:56:29 GMT + +### Patches + +- Fix patch compatibility with ESLint 7 for versions matching <7.12.0 + +## 1.5.0 +Tue, 26 Sep 2023 09:30:33 GMT + +### Minor changes + +- Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the "eslint-config-" prefix + +## 1.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 1.3.3 +Tue, 08 Aug 2023 07:10:39 GMT + +### Patches + +- Fix patching for running eslint via eslint/use-at-your-own-risk, which VS Code's eslint extension does when enabling flat config support + +## 1.3.2 +Thu, 15 Jun 2023 00:21:01 GMT + +### Patches + +- [eslint-patch] add invalid importer path test to ESLint 7.x || 8.x block + +## 1.3.1 +Wed, 07 Jun 2023 22:45:16 GMT + +### Patches + +- Add test for invalid importer path to fallback to relative path when loading eslint 6 plugins + +## 1.3.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the @typescript-eslint/* dependencies to ~5.59.2 + +## 1.2.0 +Thu, 15 Sep 2022 00:18:51 GMT + +### Minor changes + +- Use original resolver if patched resolver fails. + +## 1.1.4 +Tue, 28 Jun 2022 00:23:32 GMT + +### Patches + +- Update the README to mention support for ESLint 8. + +## 1.1.3 +Fri, 15 Apr 2022 00:12:36 GMT + +### Patches + +- Fix an issue where tools could not determine the module type as CommonJS + +## 1.1.2 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.1.1 +Tue, 15 Mar 2022 19:15:53 GMT + +### Patches + +- Fix the path in the package.json "directory" field. + +## 1.1.0 +Fri, 05 Nov 2021 15:09:18 GMT + +### Minor changes + +- feat(eslint-patch): Find patch targets independently of disk layout + +## 1.0.9 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.0.8 +Wed, 13 Oct 2021 15:09:54 GMT + +### Patches + +- Add support for ESLint 8.0.0 + +## 1.0.7 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 1.0.6 +Fri, 30 Oct 2020 00:10:14 GMT + +### Patches + +- Update the "modern-module-resolution" patch to support ESLint 7.8.0 and newer + +## 1.0.5 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 1.0.4 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 1.0.3 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 1.0.2 +Wed, 24 Jun 2020 09:50:48 GMT + +### Patches + +- Fix an issue with the published file set + +## 1.0.1 +Wed, 24 Jun 2020 09:04:28 GMT + +### Patches + +- Initial release + diff --git a/eslint/eslint-patch/LICENSE b/eslint/eslint-patch/LICENSE new file mode 100644 index 00000000000..838114d971b --- /dev/null +++ b/eslint/eslint-patch/LICENSE @@ -0,0 +1,24 @@ +@rushstack/eslint-patch + +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/eslint/eslint-patch/README.md b/eslint/eslint-patch/README.md new file mode 100644 index 00000000000..36fa4922816 --- /dev/null +++ b/eslint/eslint-patch/README.md @@ -0,0 +1,252 @@ +# @rushstack/eslint-patch + +Enhance [ESLint](https://eslint.org/) with better support for large scale monorepos! + +This is a runtime patch that enables new/experimental features for ESLint. It operates as a "monkey patch" +that gets loaded with **.eslintrc.js** and modifies the ESLint engine in memory. This approach works +with your existing ESLint version (no need to install a forked ESLint), and is fully interoperable with +companion tools such as the ESLint extensions for VS Code and WebStorm. + +This package provides several independently loadable features: + +- **eslint-bulk-suppressions**: enables you to roll out new lint rules in your monorepo without having to + clutter up source files with thousands of machine-generated `// eslint-ignore-next-line` directives. + Instead, the "bulk suppressions" for legacy violations are managed in a separate file called + **.eslint-bulk-suppressions.json**. + +- **modern-module-resolution**: allows an ESLint config package to provide plugin dependencies, avoiding the + problem where hundreds of projects in a monorepo need to copy+paste the same `"devDependencies"` in + every **package.json** file. + + > **NOTE:** ESLint 8.21.0 has now introduced a new `ESLINT_USE_FLAT_CONFIG` mode that may reduce the need + for the `modern-module-resolution` patch. + +- **custom-config-package-names**: enables [rig packages](https://heft.rushstack.io/pages/intro/rig_packages/) + to provide shareable configs for ESLint, by removing the requirement that `eslint-config` must appear in + the NPM package name. + +Contributions welcome! If you have more ideas for experimental ESLint enhancements that might benefit +large scale monorepos, consider adding them to this patch. + + +# eslint-bulk-suppressions feature + + + +### What it does + +As your monorepo evolves and grows, there's an ongoing need to expand and improve lint rules. But whenever a +new rule is enabled, there may be hundreds or thousands of "legacy violations" in existing source files. +How to handle that? We could fix the old code, but that's often prohibitively expensive and may even cause +regressions. We could disable the rule for those projects or files, but we want new code to follow the rule. +An effective solution is to inject thousands of `// eslint-ignore-next-line` lines, but these "bulk suppressions" +have an unintended side effect: It normalizes the practice of suppressing lint rules. If people get used to +seeing `// eslint-ignore-next-line` everywhere, nobody will notice when humans suppress the rules for new code. +That would undermine the mission of establishing better code standards. + +The `eslint-bulk-suppressions` feature introduces a way to store machine-generated suppressions in a separate +file **.eslint-bulk-suppressions.json** which can even be protected using `CODEOWNERS` policies, since that file +will generally only change when new lint rules are introduced, or in occasional circumstances when existing files +are being moved or renamed. In this way `// eslint-ignore-next-line` remains a directive written by humans +and hopefully rarely needed. + + +### Why it's a patch + +As with `modern-module-resolution`, our hope is for this feature to eventually be incorporated as an official +feature of ESLint. Starting out as an unofficial patch allows faster iteration and community feedback. + + +### How to use it + +1. Add `@rushstack/eslint-patch` as a dependency of your project: + + ```bash + cd your-project + npm install --save-dev @rushstack/eslint-patch + ``` + +2. Globally install the [`@rushstack/eslint-bulk`](https://www.npmjs.com/package/@rushstack/eslint-bulk) + command line interface (CLI) package. For example: + + ```bash + npm install --global @rushstack/eslint-bulk + ``` + + This installs the `eslint-bulk` shell command for managing the **.eslint-bulk-suppressions.json** files. + With it you can generate new suppressions as well as "prune" old suppressions that are no longer needed. + +3. Load the patch by adding the following `require()` statement as the first line of + your **.eslintrc.js** file. For example: + + **.eslintrc.js** + ```js + require("@rushstack/eslint-patch/eslint-bulk-suppressions"); // 👈 add this line + + module.exports = { + rules: { + rule1: 'error', + rule2: 'warning' + }, + parserOptions: { tsconfigRootDir: __dirname } + }; + ``` + +Typical workflow: + +1. Checkout your `main` branch, which is in a clean state where ESLint reports no violations. +2. Update your configuration to enable the latest lint rules; ESLint now reports thousands of legacy violations. +3. Run `eslint-bulk suppress --all ./src` to update **.eslint-bulk-suppressions.json.** +4. ESLint now no longer reports violations, so commit the results to Git and merge your pull request. +5. Over time, engineers may improve some of the suppressed code, in which case the associated suppressions are no longer needed. +6. Run `eslint-bulk prune` periodically to find and remove unnecessary suppressions from **.eslint-bulk-suppressions.json**, ensuring that new violations will now get caught in those scopes. + +### "eslint-bulk suppress" command + +```bash +eslint-bulk suppress --rule NAME1 [--rule NAME2...] PATH1 [PATH2...] +eslint-bulk suppress --all PATH1 [PATH2...] +``` + +Use this command to automatically generate bulk suppressions for the specified lint rules and file paths. +The path argument is a [glob pattern](https://en.wikipedia.org/wiki/Glob_(programming)) with the same syntax +as path arguments for the `eslint` command. + + +### "eslint-bulk prune" command + +Use this command to automatically delete all unnecessary suppression entries in all +**.eslint-bulk-suppressions.json** files under the current working directory. + +```bash +eslint-bulk prune +``` + +### Implementation notes + +The `eslint-bulk` command is a thin wrapper whose behavior is actually provided by the patch itself. +In this way, if your monorepo contains projects using different versions of this package, the same globally +installed `eslint-bulk` command can be used under any project folder, and it will always invoke the correct +version of the engine compatible with that project. Because the patch is loaded by ESLint, the `eslint-bulk` +command must be invoked in a project folder that contains an **.eslintrc.js** configuration with correctly +installed **package.json** dependencies. + +Here's an example of the bulk suppressions file content: + +**.eslint-bulk-suppressions.json** +```js +{ + "suppressions": [ + { + "rule": "no-var", + "file": "./src/your-file.ts", + "scopeId": ".ExampleClass.exampleMethod" + } + ] +} +``` +The `rule` field is the ESLint rule name. The `file` field is the source file path, relative to the **eslintrc.js** file. The `scopeId` is a special string built from the names of containing structures. (For implementation details, take a look at the [calculateScopeId()](https://github.com/microsoft/rushstack/blob/e95c51088341f01516ee5a7639d57c3f6dce8772/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts#L52) function.) The `scopeId` identifies a region of code where the rule should be suppressed, while being reasonably stable across edits of the source file. + +# modern-module-resolution feature + +### What it does + +This patch is a workaround for a longstanding [ESLint feature request](https://github.com/eslint/eslint/issues/3458) +that would allow a shareable ESLint config to bring along its own plugins, rather than imposing peer dependencies +on every consumer of the config. In a monorepo scenario, this enables your lint setup to be consolidated in a +single NPM package. Doing so greatly reduces the copy+pasting and version management for all the other projects +that use your standard lint rule set, but don't want to be bothered with the details. + +> **NOTE:** ESLint 8.21.0 has now introduced a new `ESLINT_USE_FLAT_CONFIG` mode that may reduce the need +> for this patch. + + +### Why it's a patch + +We initially proposed this feature in a pull request for the official ESLint back in 2019, however the +maintainers preferred to implement a more comprehensive overhaul of the ESLint config engine. It ultimately +shipped with the experimental new `ESLINT_USE_FLAT_CONFIG` mode (still opt-in as of ESLint 8). +While waiting for that, Rush Stack's `modern-module-resolution` patch provided a reliable interim solution. +We will continue to maintain this patch as long as it is being widely used, but we encourage you to check out +`ESLINT_USE_FLAT_CONFIG` and see if it meets your needs. + + +### How to use it + +1. Add `@rushstack/eslint-patch` as a dependency of your project: + + ```bash + cd your-project + npm install --save-dev @rushstack/eslint-patch + ``` + +2. Add a `require()` call to the to top of the **.eslintrc.js** file for each project that depends + on your shareable ESLint config, for example: + + **.eslintrc.js** + ```ts + require("@rushstack/eslint-patch/modern-module-resolution"); // 👈 add this line + + // Add your "extends" boilerplate here, for example: + module.exports = { + extends: ['@your-company/eslint-config'], + parserOptions: { tsconfigRootDir: __dirname } + }; + ``` + +With this change, the local project no longer needs any ESLint plugins in its **package.json** file. +Instead, the hypothetical `@your-company/eslint-config` NPM package would declare the plugins as its +own dependencies. + +This patch works by modifying the ESLint engine so that its module resolver will load relative to the folder of +the referencing config file, rather than the project folder. The patch is compatible with ESLint 6, 7, and 8. +It also works with any editor extensions that load ESLint as a library. + +For an even leaner setup, `@your-company/eslint-config` can provide the patches as its own dependency. +See [@rushstack/eslint-config](https://github.com/microsoft/rushstack/blob/main/eslint/eslint-config/patch/modern-module-resolution.js) for a real world example. + + +# custom-config-package-names feature + +### What it does + +Load the `custom-config-package-names` patch to remove ESLint's +[naming requirement](https://eslint.org/docs/latest/extend/shareable-configs) +that `eslint-config` must be part of the NPM package name for shareable configs. + +This is useful because Rush Stack's [rig package](https://heft.rushstack.io/pages/intro/rig_packages/) +specification defines a way for many different tooling configurations and dependencies to be shared +via a single NPM package, for example +[`@rushstack/heft-web-rig`](https://www.npmjs.com/package/@rushstack/heft-web-rig). +Rigs avoid a lot of copy+pasting of dependencies in a large scale monorepo. +Rig packages always include the `-rig` suffix in their name. It doesn't make sense to enforce +that `eslint-config` should also appear in the name of a package that includes shareable configs +for many other tools besides ESLint. + +### How to use it + +Continuing the example above, to load this patch you would add a second line to your config file: + +**.eslintrc.js** +```ts +require("@rushstack/eslint-patch/modern-module-resolution"); +require("@rushstack/eslint-patch/custom-config-package-names"); // 👈 add this line + +// Add your "extends" boilerplate here, for example: +module.exports = { + extends: [ + '@your-company/build-rig/profile/default/includes/eslint/node' // Notice the package name does not start with "eslint-config-" + ], + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + + +# Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/eslint/eslint-patch/CHANGELOG.md) - Find + out what's new in the latest version + +- [`@rushstack/eslint-bulk`](https://www.npmjs.com/package/@rushstack/eslint-bulk) CLI package + +`@rushstack/eslint-patch` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/eslint/eslint-patch/config/rig.json b/eslint/eslint-patch/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/eslint/eslint-patch/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/eslint/eslint-patch/custom-config-package-names.js b/eslint/eslint-patch/custom-config-package-names.js new file mode 100644 index 00000000000..8897e869792 --- /dev/null +++ b/eslint/eslint-patch/custom-config-package-names.js @@ -0,0 +1 @@ +require('./lib/custom-config-package-names'); diff --git a/eslint/eslint-patch/eslint-bulk-suppressions.js b/eslint/eslint-patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..b1236d4e449 --- /dev/null +++ b/eslint/eslint-patch/eslint-bulk-suppressions.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..921317824f4 --- /dev/null +++ b/eslint/eslint-patch/modern-module-resolution.js @@ -0,0 +1 @@ +require('./lib/modern-module-resolution'); diff --git a/eslint/eslint-patch/package.json b/eslint/eslint-patch/package.json new file mode 100644 index 00000000000..9b3c0343a96 --- /dev/null +++ b/eslint/eslint-patch/package.json @@ -0,0 +1,43 @@ +{ + "name": "@rushstack/eslint-patch", + "version": "1.15.0", + "description": "Enhance ESLint with better support for large scale monorepos", + "main": "lib/usage.js", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-patch" + }, + "homepage": "https://rushstack.io", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "keywords": [ + "eslintrc", + "config", + "module", + "resolve", + "resolver", + "plugin", + "relative", + "package", + "bulk", + "suppressions", + "monorepo", + "monkey", + "patch" + ], + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@types/eslint-8": "npm:@types/eslint@8.56.10", + "@types/eslint-9": "npm:@types/eslint@9.6.1", + "@typescript-eslint/types": "~8.46.0", + "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" + } +} diff --git a/eslint/eslint-patch/src/_patch-base.ts b/eslint/eslint-patch/src/_patch-base.ts new file mode 100644 index 00000000000..d4fa0056538 --- /dev/null +++ b/eslint/eslint-patch/src/_patch-base.ts @@ -0,0 +1,342 @@ +// 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 +// +// To correct how ESLint searches for plugin packages, add this line to the top of your project's .eslintrc.js file: +// +// require("@rushstack/eslint-patch/modern-module-resolution"); +// + +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; + +// Module path for config-array-factory.js +// Example: ".../@eslint/eslintrc/lib/config-array-factory" +let configArrayFactoryPath: string | undefined = undefined; + +// Module path for relative-module-resolver.js +// Example: ".../@eslint/eslintrc/lib/shared/relative-module-resolver" +let moduleResolverPath: string | undefined = undefined; + +// Module path for naming.js +// Example: ".../@eslint/eslintrc/lib/shared/naming" +let namingPath: string | undefined = undefined; + +// Folder path where ESLint's package.json can be found +// Example: ".../node_modules/eslint" +let eslintFolder: string | undefined = undefined; + +// Probe for the ESLint >=9.0.0 flat config layout: +for (let currentModule: NodeModule = module; ; ) { + 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 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 (!eslintFolder) { + // Probe for the ESLint >=7.12.0 layout: + for (let currentModule: NodeModule = module; ; ) { + if (!configArrayFactoryPath) { + // For ESLint >=7.12.0, config-array-factory.js is at this path: + // .../@eslint/eslintrc/lib/config-array-factory.js + try { + const eslintrcFolder: string = path.dirname( + require.resolve('@eslint/eslintrc/package.json', { + paths: [currentModule.path] + }) + ); + + const resolvedConfigArrayFactoryPath: string = path.join( + eslintrcFolder, + '/lib/config-array-factory.js' + ); + if (resolvedConfigArrayFactoryPath === currentModule.filename) { + configArrayFactoryPath = resolvedConfigArrayFactoryPath; + moduleResolverPath = `${eslintrcFolder}/lib/shared/relative-module-resolver`; + namingPath = `${eslintrcFolder}/lib/shared/naming`; + } + } 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 if (currentModule.filename.endsWith('cli-engine.js')) { + // 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] + }) + ); + + if (path.join(eslintCandidateFolder, 'lib/cli-engine/cli-engine.js') === currentModule.filename) { + 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 rethrown. + if (!isModuleResolutionError(ex)) { + throw ex; + } + } + } + + if (!currentModule.parent) { + break; + } + currentModule = currentModule.parent; + } +} + +if (!eslintFolder) { + // Probe for the <7.12.0 layout: + for (let currentModule: NodeModule = module; ; ) { + // For ESLint <7.12.0, config-array-factory.js was at this path: + // .../eslint/lib/cli-engine/config-array-factory.js + if (/[\\/]eslint[\\/]lib[\\/]cli-engine[\\/]config-array-factory\.js$/i.test(currentModule.filename)) { + eslintFolder = path.join(path.dirname(currentModule.filename), '../..'); + configArrayFactoryPath = `${eslintFolder}/lib/cli-engine/config-array-factory`; + moduleResolverPath = `${eslintFolder}/lib/shared/relative-module-resolver`; + + // The naming module was moved to @eslint/eslintrc in ESLint 7.8.0, which is also when the @eslint/eslintrc + // package was created and added to ESLint, so we need to probe for whether it's in the old or new location. + let eslintrcFolder: string | undefined; + try { + eslintrcFolder = path.dirname( + require.resolve('@eslint/eslintrc/package.json', { + paths: [currentModule.path] + }) + ); + } catch (ex: unknown) { + if (!isModuleResolutionError(ex)) { + throw ex; + } + } + + namingPath = `${eslintrcFolder ?? eslintFolder}/lib/shared/naming`; + break; + } + + if (!currentModule.parent) { + // This was tested with ESLint 6.1.0 .. 7.12.1. + throw new Error( + 'Failed to patch ESLint because the calling module was not recognized.\n' + + 'If you are using a newer ESLint version that may be unsupported, please create a GitHub issue:\n' + + 'https://github.com/microsoft/rushstack/issues' + ); + } + currentModule = currentModule.parent; + } +} + +// Detect the ESLint package version +const eslintPackageJsonPath: string = `${eslintFolder}/package.json`; +const eslintPackageObject: { version: string } = require(eslintPackageJsonPath); +export const eslintPackageVersion: string = eslintPackageObject.version; +const ESLINT_MAJOR_VERSION: number = parseInt(eslintPackageVersion, 10); +if (isNaN(ESLINT_MAJOR_VERSION)) { + throw new Error( + `Unable to parse ESLint version "${eslintPackageVersion}" in file "${eslintPackageJsonPath}"` + ); +} + +if (!(ESLINT_MAJOR_VERSION >= 6 && ESLINT_MAJOR_VERSION <= 9)) { + throw new Error( + 'The ESLint patch script has only been tested with ESLint version 6.x, 7.x, 8.x, and 9.x.' + + ` (Your version: ${eslintPackageVersion})\n` + + 'Consider reporting a GitHub issue:\n' + + 'https://github.com/microsoft/rushstack/issues' + ); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let configArrayFactory: any; +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 && eslintrcBundlePath) { + ModuleResolver = require(eslintrcBundlePath).Legacy.ModuleResolver; + Naming = require(eslintrcBundlePath).Legacy.naming; +} else if (moduleResolverPath && namingPath) { + ModuleResolver = require(moduleResolverPath); + Naming = require(namingPath); +} + +export { + eslintFolder, + configArrayFactory, + ModuleResolver, + Naming, + ESLINT_MAJOR_VERSION, + isModuleResolutionError +}; diff --git a/eslint/eslint-patch/src/custom-config-package-names.ts b/eslint/eslint-patch/src/custom-config-package-names.ts new file mode 100644 index 00000000000..6184b774b88 --- /dev/null +++ b/eslint/eslint-patch/src/custom-config-package-names.ts @@ -0,0 +1,46 @@ +// 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 ESLint's requirement to consume shareable configurations from package names prefixed +// with "eslint-config". +// +// To remove this requirement, add this line to the top of your project's .eslintrc.js file: +// +// require("@rushstack/eslint-patch/custom-config-package-names"); +// +import { configArrayFactory, ModuleResolver, Naming } from './_patch-base'; + +if (!configArrayFactory.__loadExtendedShareableConfigPatched) { + configArrayFactory.__loadExtendedShareableConfigPatched = true; + // eslint-disable-next-line @typescript-eslint/typedef + const originalLoadExtendedShareableConfig = configArrayFactory.prototype._loadExtendedShareableConfig; + + // Common between ESLint versions + // https://github.com/eslint/eslintrc/blob/242d569020dfe4f561e4503787b99ec016337457/lib/config-array-factory.js#L910 + configArrayFactory.prototype._loadExtendedShareableConfig = function (extendName: string): unknown { + const originalResolve: (moduleName: string, relativeToPath: string) => string = ModuleResolver.resolve; + try { + ModuleResolver.resolve = function (moduleName: string, relativeToPath: string): string { + try { + return originalResolve.call(this, moduleName, relativeToPath); + } catch (e) { + // Only change the name we resolve if we cannot find the normalized module, since it is + // valid to rely on the normalized package name. Use the originally provided module path + // instead of the normalized module path. + if ( + (e as NodeJS.ErrnoException)?.code === 'MODULE_NOT_FOUND' && + moduleName !== extendName && + moduleName === Naming.normalizePackageName(extendName, 'eslint-config') + ) { + return originalResolve.call(this, extendName, relativeToPath); + } else { + throw e; + } + } + }; + return originalLoadExtendedShareableConfig.apply(this, arguments); + } finally { + ModuleResolver.resolve = originalResolve; + } + }; +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts new file mode 100644 index 00000000000..a308b49f7fb --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts @@ -0,0 +1,272 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESTree } from '@typescript-eslint/types'; + +export function isArrayExpression(node: TSESTree.Node): node is TSESTree.ArrayExpression { + return node.type === 'ArrayExpression'; +} + +export function isArrowFunctionExpression(node: TSESTree.Node): node is TSESTree.ArrowFunctionExpression { + return node.type === 'ArrowFunctionExpression'; +} + +/** default parameters */ +export function isAssignmentPattern(node: TSESTree.Node): node is TSESTree.AssignmentPattern { + return node.type === 'AssignmentPattern'; +} + +export function isClassDeclaration(node: TSESTree.Node): node is TSESTree.ClassDeclaration { + return node.type === 'ClassDeclaration'; +} + +export function isClassExpression(node: TSESTree.Node): node is TSESTree.ClassExpression { + return node.type === 'ClassExpression'; +} + +export function isExportDefaultDeclaration(node: TSESTree.Node): node is TSESTree.ExportDefaultDeclaration { + return node.type === 'ExportDefaultDeclaration'; +} + +export function isExpression(node: TSESTree.Node): node is TSESTree.Expression { + return node.type.includes('Expression'); +} + +export function isFunctionDeclaration(node: TSESTree.Node): node is TSESTree.FunctionDeclaration { + return node.type === 'FunctionDeclaration'; +} + +export function isFunctionExpression(node: TSESTree.Node): node is TSESTree.FunctionExpression { + return node.type === 'FunctionExpression'; +} + +export function isIdentifier(node: TSESTree.Node): node is TSESTree.Identifier { + return node.type === 'Identifier'; +} + +export function isLiteral(node: TSESTree.Node): node is TSESTree.Literal { + return node.type === 'Literal'; +} + +export function isMethodDefinition(node: TSESTree.Node): node is TSESTree.MethodDefinition { + return node.type === 'MethodDefinition'; +} + +export function isObjectExpression(node: TSESTree.Node): node is TSESTree.ObjectExpression { + return node.type === 'ObjectExpression'; +} + +export function isPrivateIdentifier(node: TSESTree.Node): node is TSESTree.PrivateIdentifier { + return node.type === 'PrivateIdentifier'; +} + +export function isProperty(node: TSESTree.Node): node is TSESTree.Property { + return node.type === 'Property'; +} + +export function isPropertyDefinition(node: TSESTree.Node): node is TSESTree.PropertyDefinition { + return node.type === 'PropertyDefinition'; +} + +export function isTSEnumDeclaration(node: TSESTree.Node): node is TSESTree.TSEnumDeclaration { + return node.type === 'TSEnumDeclaration'; +} + +export function isTSInterfaceDeclaration(node: TSESTree.Node): node is TSESTree.TSInterfaceDeclaration { + return node.type === 'TSInterfaceDeclaration'; +} + +export function isTSModuleDeclaration(node: TSESTree.Node): node is TSESTree.TSModuleDeclaration { + return node.type === 'TSModuleDeclaration'; +} + +export function isTSQualifiedName(node: TSESTree.Node): node is TSESTree.TSQualifiedName { + return node.type === 'TSQualifiedName'; +} + +export function isTSTypeAliasDeclaration(node: TSESTree.Node): node is TSESTree.TSTypeAliasDeclaration { + return node.type === 'TSTypeAliasDeclaration'; +} + +export function isVariableDeclarator(node: TSESTree.Node): node is TSESTree.VariableDeclarator { + return node.type === 'VariableDeclarator'; +} + +// Compound Type Guards for @typescript-eslint/types ast-spec compound types +export function isClassDeclarationWithName(node: TSESTree.Node): node is TSESTree.ClassDeclarationWithName { + return isClassDeclaration(node) && node.id !== null; +} + +export function isClassPropertyNameNonComputed( + node: TSESTree.Node +): node is TSESTree.ClassPropertyNameNonComputed { + return isPrivateIdentifier(node) || isPropertyNameNonComputed(node); +} + +export function isFunctionDeclarationWithName( + node: TSESTree.Node +): node is TSESTree.FunctionDeclarationWithName { + return isFunctionDeclaration(node) && node.id !== null; +} + +export function isNumberLiteral(node: TSESTree.Node): node is TSESTree.NumberLiteral { + return isLiteral(node) && typeof node.value === 'number'; +} + +export function isPropertyNameNonComputed(node: TSESTree.Node): node is TSESTree.PropertyNameNonComputed { + return isIdentifier(node) || isNumberLiteral(node) || isStringLiteral(node); +} + +export function isStringLiteral(node: TSESTree.Node): node is TSESTree.StringLiteral { + return isLiteral(node) && typeof node.value === 'string'; +} + +// Custom compound types +export interface IClassExpressionWithName extends TSESTree.ClassExpression { + id: TSESTree.Identifier; +} + +export function isClassExpressionWithName(node: TSESTree.Node): node is IClassExpressionWithName { + return isClassExpression(node) && node.id !== null; +} +export interface IFunctionExpressionWithName extends TSESTree.FunctionExpression { + id: TSESTree.Identifier; +} + +export function isFunctionExpressionWithName(node: TSESTree.Node): node is IFunctionExpressionWithName { + return isFunctionExpression(node) && node.id !== null; +} + +export type NormalAnonymousExpression = + | TSESTree.ArrowFunctionExpression + | TSESTree.ClassExpression + | TSESTree.FunctionExpression + | TSESTree.ObjectExpression; + +export function isNormalAnonymousExpression(node: TSESTree.Node): node is NormalAnonymousExpression { + const ANONYMOUS_EXPRESSION_GUARDS: ((node: TSESTree.Node) => boolean)[] = [ + isArrowFunctionExpression, + isClassExpression, + isFunctionExpression, + isObjectExpression + ]; + return ANONYMOUS_EXPRESSION_GUARDS.some((guard) => guard(node)); +} + +export interface INormalAssignmentPattern extends TSESTree.AssignmentPattern { + left: TSESTree.Identifier; +} + +export function isNormalAssignmentPattern(node: TSESTree.Node): node is INormalAssignmentPattern { + return isAssignmentPattern(node) && isIdentifier(node.left); +} + +export interface INormalClassPropertyDefinition extends TSESTree.PropertyDefinitionNonComputedName { + key: TSESTree.PrivateIdentifier | TSESTree.Identifier; + value: TSESTree.Expression; +} + +export function isNormalClassPropertyDefinition(node: TSESTree.Node): node is INormalClassPropertyDefinition { + return ( + isPropertyDefinition(node) && + (isIdentifier(node.key) || isPrivateIdentifier(node.key)) && + node.value !== null + ); +} + +export interface INormalMethodDefinition extends TSESTree.MethodDefinitionNonComputedName { + key: TSESTree.PrivateIdentifier | TSESTree.Identifier; +} + +export function isNormalMethodDefinition(node: TSESTree.Node): node is INormalMethodDefinition { + return isMethodDefinition(node) && (isIdentifier(node.key) || isPrivateIdentifier(node.key)); +} + +export interface INormalObjectProperty extends TSESTree.PropertyNonComputedName { + key: TSESTree.Identifier; +} + +export function isNormalObjectProperty(node: TSESTree.Node): node is INormalObjectProperty { + return isProperty(node) && (isIdentifier(node.key) || isPrivateIdentifier(node.key)); +} + +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; +} + +export interface INormalAssignmentPatternWithAnonymousExpressionAssigned extends INormalAssignmentPattern { + right: NormalAnonymousExpression; +} + +export function isNormalAssignmentPatternWithAnonymousExpressionAssigned( + node: TSESTree.Node +): node is INormalAssignmentPatternWithAnonymousExpressionAssigned { + return isNormalAssignmentPattern(node) && isNormalAnonymousExpression(node.right); +} + +export type INormalVariableDeclaratorWithAnonymousExpressionAssigned = INormalVariableDeclarator & { + init: NormalAnonymousExpression; +}; + +export function isNormalVariableDeclaratorWithAnonymousExpressionAssigned( + node: TSESTree.Node +): node is INormalVariableDeclaratorWithAnonymousExpressionAssigned { + return isNormalVariableDeclarator(node) && isNormalAnonymousExpression(node.init); +} + +export interface INormalObjectPropertyWithAnonymousExpressionAssigned extends INormalObjectProperty { + value: NormalAnonymousExpression; +} + +export function isNormalObjectPropertyWithAnonymousExpressionAssigned( + node: TSESTree.Node +): node is INormalObjectPropertyWithAnonymousExpressionAssigned { + return isNormalObjectProperty(node) && isNormalAnonymousExpression(node.value); +} + +export interface INormalClassPropertyDefinitionWithAnonymousExpressionAssigned + extends INormalClassPropertyDefinition { + value: NormalAnonymousExpression; +} + +export function isNormalClassPropertyDefinitionWithAnonymousExpressionAssigned( + node: TSESTree.Node +): node is INormalClassPropertyDefinitionWithAnonymousExpressionAssigned { + return isNormalClassPropertyDefinition(node) && isNormalAnonymousExpression(node.value); +} + +export type NodeWithName = + | TSESTree.ClassDeclarationWithName + | TSESTree.FunctionDeclarationWithName + | IClassExpressionWithName + | IFunctionExpressionWithName + | INormalVariableDeclaratorWithAnonymousExpressionAssigned + | INormalObjectPropertyWithAnonymousExpressionAssigned + | INormalClassPropertyDefinitionWithAnonymousExpressionAssigned + | INormalAssignmentPatternWithAnonymousExpressionAssigned + | INormalMethodDefinition + | TSESTree.TSEnumDeclaration + | TSESTree.TSInterfaceDeclaration + | TSESTree.TSTypeAliasDeclaration; + +export function isNodeWithName(node: TSESTree.Node): node is NodeWithName { + return ( + isClassDeclarationWithName(node) || + isFunctionDeclarationWithName(node) || + isClassExpressionWithName(node) || + isFunctionExpressionWithName(node) || + isNormalVariableDeclaratorWithAnonymousExpressionAssigned(node) || + isNormalObjectPropertyWithAnonymousExpressionAssigned(node) || + isNormalClassPropertyDefinitionWithAnonymousExpressionAssigned(node) || + isNormalAssignmentPatternWithAnonymousExpressionAssigned(node) || + isNormalMethodDefinition(node) || + isTSEnumDeclaration(node) || + isTSInterfaceDeclaration(node) || + isTSTypeAliasDeclaration(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 new file mode 100644 index 00000000000..2526196eca7 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-file.ts @@ -0,0 +1,209 @@ +// 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 { VSCODE_PID_ENV_VAR_NAME } from './constants'; + +export interface ISuppression { + file: string; + scopeId: string; + rule: string; +} + +export interface IBulkSuppressionsConfig { + serializedSuppressions: Set; + jsonObject: IBulkSuppressionsJson; + newSerializedSuppressions: Set; + newJsonObject: IBulkSuppressionsJson; +} + +export interface IBulkSuppressionsJson { + suppressions: ISuppression[]; +} + +const IS_RUNNING_IN_VSCODE: boolean = process.env[VSCODE_PID_ENV_VAR_NAME] !== undefined; +const TEN_SECONDS_MS: number = 10 * 1000; +const SUPPRESSIONS_JSON_FILENAME: string = '.eslint-bulk-suppressions.json'; + +function throwIfAnythingOtherThanNotExistError(e: NodeJS.ErrnoException): void | never { + if (e?.code !== 'ENOENT') { + // Throw an error if any other error than file not found + throw e; + } +} + +interface ICachedBulkSuppressionsConfig { + readTime: number; + suppressionsConfig: IBulkSuppressionsConfig; +} +const suppressionsJsonByFolderPath: Map = new Map(); +export function getSuppressionsConfigForEslintConfigFolderPath( + eslintConfigFolderPath: string +): IBulkSuppressionsConfig { + const cachedSuppressionsConfig: ICachedBulkSuppressionsConfig | undefined = + suppressionsJsonByFolderPath.get(eslintConfigFolderPath); + + let shouldLoad: boolean; + let suppressionsConfig: IBulkSuppressionsConfig; + if (cachedSuppressionsConfig) { + shouldLoad = IS_RUNNING_IN_VSCODE && cachedSuppressionsConfig.readTime < Date.now() - TEN_SECONDS_MS; + suppressionsConfig = cachedSuppressionsConfig.suppressionsConfig; + } else { + shouldLoad = true; + } + + if (shouldLoad) { + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; + let rawJsonFile: string | undefined; + try { + rawJsonFile = fs.readFileSync(suppressionsPath).toString(); + } catch (e) { + throwIfAnythingOtherThanNotExistError(e); + } + + if (!rawJsonFile) { + suppressionsConfig = { + serializedSuppressions: new Set(), + jsonObject: { suppressions: [] }, + newSerializedSuppressions: new Set(), + newJsonObject: { suppressions: [] } + }; + } else { + const jsonObject: IBulkSuppressionsJson = JSON.parse(rawJsonFile); + validateSuppressionsJson(jsonObject); + + const serializedSuppressions: Set = new Set(); + for (const suppression of jsonObject.suppressions) { + serializedSuppressions.add(serializeSuppression(suppression)); + } + + suppressionsConfig = { + serializedSuppressions, + jsonObject, + newSerializedSuppressions: new Set(), + newJsonObject: { suppressions: [] } + }; + } + + suppressionsJsonByFolderPath.set(eslintConfigFolderPath, { readTime: Date.now(), suppressionsConfig }); + } + + return suppressionsConfig!; +} + +export function getAllBulkSuppressionsConfigsByEslintConfigFolderPath(): [string, IBulkSuppressionsConfig][] { + const result: [string, IBulkSuppressionsConfig][] = []; + for (const [eslintConfigFolderPath, { suppressionsConfig }] of suppressionsJsonByFolderPath) { + result.push([eslintConfigFolderPath, suppressionsConfig]); + } + + return result; +} + +export function writeSuppressionsJsonToFile( + eslintConfigFolderPath: string, + suppressionsConfig: IBulkSuppressionsConfig +): void { + suppressionsJsonByFolderPath.set(eslintConfigFolderPath, { readTime: Date.now(), suppressionsConfig }); + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; + if (suppressionsConfig.jsonObject.suppressions.length === 0) { + deleteFile(suppressionsPath); + } else { + suppressionsConfig.jsonObject.suppressions.sort(compareSuppressions); + fs.writeFileSync(suppressionsPath, JSON.stringify(suppressionsConfig.jsonObject, undefined, 2)); + } +} + +export function deleteBulkSuppressionsFileInEslintConfigFolder(eslintConfigFolderPath: string): void { + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; + deleteFile(suppressionsPath); +} + +function deleteFile(filePath: string): void { + try { + fs.unlinkSync(filePath); + } catch (e) { + throwIfAnythingOtherThanNotExistError(e); + } +} + +export function serializeSuppression({ file, scopeId, rule }: ISuppression): string { + return `${file}|${scopeId}|${rule}`; +} + +function compareSuppressions(a: ISuppression, b: ISuppression): -1 | 0 | 1 { + if (a.file < b.file) { + return -1; + } else if (a.file > b.file) { + return 1; + } else if (a.scopeId < b.scopeId) { + return -1; + } else if (a.scopeId > b.scopeId) { + return 1; + } else if (a.rule < b.rule) { + return -1; + } else if (a.rule > b.rule) { + return 1; + } else { + return 0; + } +} + +function validateSuppressionsJson(json: IBulkSuppressionsJson): json is IBulkSuppressionsJson { + if (typeof json !== 'object') { + throw new Error(`Invalid JSON object: ${JSON.stringify(json, null, 2)}`); + } + + if (!json) { + throw new Error('JSON object is null.'); + } + + const EXPECTED_ROOT_PROPERTY_NAMES: Set = new Set(['suppressions']); + + for (const propertyName of Object.getOwnPropertyNames(json)) { + if (!EXPECTED_ROOT_PROPERTY_NAMES.has(propertyName as keyof IBulkSuppressionsJson)) { + throw new Error(`Unexpected property name: ${propertyName}`); + } + } + + const { suppressions } = json; + if (!suppressions) { + throw new Error('Missing "suppressions" property.'); + } + + if (!Array.isArray(suppressions)) { + throw new Error('"suppressions" property is not an array.'); + } + + const EXPECTED_SUPPRESSION_PROPERTY_NAMES: Set = new Set(['file', 'scopeId', 'rule']); + for (const suppression of suppressions) { + if (typeof suppression !== 'object') { + throw new Error(`Invalid suppression: ${JSON.stringify(suppression, null, 2)}`); + } + + if (!suppression) { + throw new Error(`Suppression is null: ${JSON.stringify(suppression, null, 2)}`); + } + + for (const propertyName of Object.getOwnPropertyNames(suppression)) { + if (!EXPECTED_SUPPRESSION_PROPERTY_NAMES.has(propertyName as keyof ISuppression)) { + throw new Error(`Unexpected property name: ${propertyName}`); + } + } + + for (const propertyName of EXPECTED_SUPPRESSION_PROPERTY_NAMES) { + if (!suppression.hasOwnProperty(propertyName)) { + throw new Error( + `Missing "${propertyName}" property in suppression: ${JSON.stringify(suppression, null, 2)}` + ); + } else if (typeof suppression[propertyName] !== 'string') { + throw new Error( + `"${propertyName}" property in suppression is not a string: ${JSON.stringify(suppression, null, 2)}` + ); + } + } + } + + return true; +} 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 new file mode 100644 index 00000000000..549ad21b2bf --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts @@ -0,0 +1,273 @@ +// 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 * as Guards from './ast-guards'; +import { eslintFolder } from '../_patch-base'; +import { + ESLINT_BULK_ENABLE_ENV_VAR_NAME, + ESLINT_BULK_PRUNE_ENV_VAR_NAME, + ESLINT_BULK_SUPPRESS_ENV_VAR_NAME +} from './constants'; +import { + getSuppressionsConfigForEslintConfigFolderPath, + serializeSuppression, + type IBulkSuppressionsConfig, + type ISuppression, + writeSuppressionsJsonToFile, + getAllBulkSuppressionsConfigsByEslintConfigFolderPath +} from './bulk-suppressions-file'; + +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, + // so we only need to check for the JS-based filenames +]; +const SUPPRESSION_SYMBOL: unique symbol = Symbol('suppression'); +const ESLINT_BULK_SUPPRESS_ENV_VAR_VALUE: string | undefined = process.env[ESLINT_BULK_SUPPRESS_ENV_VAR_NAME]; +const SUPPRESS_ALL_RULES: boolean = ESLINT_BULK_SUPPRESS_ENV_VAR_VALUE === '*'; +const RULES_TO_SUPPRESS: Set | undefined = ESLINT_BULK_SUPPRESS_ENV_VAR_VALUE + ? new Set(ESLINT_BULK_SUPPRESS_ENV_VAR_VALUE.split(',')) + : undefined; + +interface IProblem { + [SUPPRESSION_SYMBOL]?: { + config: IBulkSuppressionsConfig; + suppression: ISuppression; + serializedSuppression: string; + }; +} + +function getNodeName(node: TSESTree.Node): string | undefined { + if (Guards.isClassDeclarationWithName(node)) { + return node.id.name; + } else if (Guards.isFunctionDeclarationWithName(node)) { + return node.id.name; + } else if (Guards.isClassExpressionWithName(node)) { + return node.id.name; + } else if (Guards.isFunctionExpressionWithName(node)) { + return node.id.name; + } else if (Guards.isNormalVariableDeclaratorWithAnonymousExpressionAssigned(node)) { + return node.id.name; + } else if (Guards.isNormalObjectPropertyWithAnonymousExpressionAssigned(node)) { + return node.key.name; + } else if (Guards.isNormalClassPropertyDefinitionWithAnonymousExpressionAssigned(node)) { + return node.key.name; + } else if (Guards.isNormalAssignmentPatternWithAnonymousExpressionAssigned(node)) { + return node.left.name; + } else if (Guards.isNormalMethodDefinition(node)) { + return node.key.name; + } else if (Guards.isTSEnumDeclaration(node)) { + return node.id.name; + } else if (Guards.isTSInterfaceDeclaration(node)) { + return node.id.name; + } else if (Guards.isTSTypeAliasDeclaration(node)) { + return node.id.name; + } +} + +type NodeWithParent = TSESTree.Node & { parent?: TSESTree.Node }; + +function calculateScopeId(node: NodeWithParent | undefined): string { + const scopeIds: string[] = []; + for (let current: NodeWithParent | undefined = node; current; current = current.parent) { + const scopeIdForASTNode: string | undefined = getNodeName(current); + if (scopeIdForASTNode !== undefined) { + scopeIds.unshift(scopeIdForASTNode); + } + } + + if (scopeIds.length === 0) { + return '.'; + } else { + return '.' + scopeIds.join('.'); + } +} + +const eslintConfigPathByFileOrFolderPath: Map = new Map(); + +function findEslintConfigFolderPathForNormalizedFileAbsolutePath(normalizedFilePath: string): string { + const cachedFolderPathForFilePath: string | undefined = + eslintConfigPathByFileOrFolderPath.get(normalizedFilePath); + if (cachedFolderPathForFilePath) { + return cachedFolderPathForFilePath; + } + const normalizedFileFolderPath: string = normalizedFilePath.substring( + 0, + normalizedFilePath.lastIndexOf('/') + ); + + const pathsToCache: string[] = [normalizedFilePath]; + 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 = + eslintConfigPathByFileOrFolderPath.get(currentFolder); + if (cachedEslintrcFolderPath) { + // Need to cache this result into the intermediate paths + eslintConfigFolderPath = cachedEslintrcFolderPath; + break; + } + + pathsToCache.push(currentFolder); + for (const eslintConfigFilename of ESLINT_CONFIG_FILENAMES) { + if (fs.existsSync(`${currentFolder}/${eslintConfigFilename}`)) { + eslintConfigFolderPath = currentFolder; + break findEslintConfigFileLoop; + } + } + } + + if (eslintConfigFolderPath) { + for (const checkedFolder of pathsToCache) { + eslintConfigPathByFileOrFolderPath.set(checkedFolder, eslintConfigFolderPath); + } + + return eslintConfigFolderPath; + } else { + throw new Error(`Cannot locate an ESLint configuration file for ${normalizedFilePath}`); + } +} + +// One-line insert into the ruleContext report method to prematurely exit if the ESLint problem has been suppressed +export function shouldBulkSuppress(params: { + filename: string; + currentNode: TSESTree.Node; + ruleId: string; + problem: IProblem; +}): boolean { + // Use this ENV variable to turn off eslint-bulk-suppressions functionality, default behavior is on + if (process.env[ESLINT_BULK_ENABLE_ENV_VAR_NAME] === 'false') { + return false; + } + + const { filename: fileAbsolutePath, currentNode, ruleId: rule, problem } = params; + const normalizedFileAbsolutePath: string = fileAbsolutePath.replace(/\\/g, '/'); + 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 = + getSuppressionsConfigForEslintConfigFolderPath(eslintConfigDirectory); + const serializedSuppression: string = serializeSuppression(suppression); + const currentNodeIsSuppressed: boolean = config.serializedSuppressions.has(serializedSuppression); + + if (currentNodeIsSuppressed || SUPPRESS_ALL_RULES || RULES_TO_SUPPRESS?.has(suppression.rule)) { + problem[SUPPRESSION_SYMBOL] = { + suppression, + serializedSuppression, + config + }; + } + + return process.env[ESLINT_BULK_PRUNE_ENV_VAR_NAME] !== '1' && currentNodeIsSuppressed; +} + +export function prune(): void { + for (const [ + eslintConfigFolderPath, + suppressionsConfig + ] of getAllBulkSuppressionsConfigsByEslintConfigFolderPath()) { + if (suppressionsConfig) { + const { newSerializedSuppressions, newJsonObject } = suppressionsConfig; + const newSuppressionsConfig: IBulkSuppressionsConfig = { + serializedSuppressions: newSerializedSuppressions, + jsonObject: newJsonObject, + newSerializedSuppressions: new Set(), + newJsonObject: { suppressions: [] } + }; + + writeSuppressionsJsonToFile(eslintConfigFolderPath, newSuppressionsConfig); + } + } +} + +export function write(): void { + for (const [ + eslintrcFolderPath, + suppressionsConfig + ] of getAllBulkSuppressionsConfigsByEslintConfigFolderPath()) { + if (suppressionsConfig) { + writeSuppressionsJsonToFile(eslintrcFolderPath, suppressionsConfig); + } + } +} + +// 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-9').Linter | import('eslint-8').Linter { + if (!eslintFolder) { + return require(importPath); + } + + const pathToLinterFolder: string = `${eslintFolder}/lib/linter`; + const moduleAbsolutePath: string = require.resolve(importPath, { paths: [pathToLinterFolder] }); + return require(moduleAbsolutePath); +} + +export function patchClass(originalClass: new () => T, patchedClass: new () => U): void { + // Get all the property names of the patched class prototype + const patchedProperties: string[] = Object.getOwnPropertyNames(patchedClass.prototype); + + // Loop through all the properties + for (const prop of patchedProperties) { + // Override the property in the original class + originalClass.prototype[prop] = patchedClass.prototype[prop]; + } + + // Handle getters and setters + for (const [prop, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(patchedClass.prototype))) { + if (descriptor.get || descriptor.set) { + Object.defineProperty(originalClass.prototype, prop, descriptor); + } + } +} + +/** + * This returns a wrapped version of the "verify" function from ESLint's Linter class + * that postprocesses rule violations that weren't suppressed by comments. This postprocessing + * records suppressions that weren't otherwise suppressed by comments to be used + * by the "suppress" and "prune" commands. + */ +export function extendVerifyFunction( + originalFn: (this: unknown, ...args: unknown[]) => IProblem[] | undefined +): (this: unknown, ...args: unknown[]) => IProblem[] | undefined { + return function (this: unknown, ...args: unknown[]): IProblem[] | undefined { + const problems: IProblem[] | undefined = originalFn.apply(this, args); + if (problems) { + for (const problem of problems) { + if (problem[SUPPRESSION_SYMBOL]) { + const { + serializedSuppression, + suppression, + config: { + newSerializedSuppressions, + jsonObject: { suppressions }, + newJsonObject: { suppressions: newSuppressions } + } + } = problem[SUPPRESSION_SYMBOL]; + if (!newSerializedSuppressions.has(serializedSuppression)) { + newSerializedSuppressions.add(serializedSuppression); + newSuppressions.push(suppression); + suppressions.push(suppression); + } + } + } + } + + return problems; + }; +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts new file mode 100755 index 00000000000..ecbc702a63b --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts @@ -0,0 +1,68 @@ +// 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 { printPruneHelp } from './utils/print-help'; +import { runEslintAsync } from './runEslint'; +import { ESLINT_BULK_PRUNE_ENV_VAR_NAME } from '../constants'; +import { + deleteBulkSuppressionsFileInEslintConfigFolder, + getSuppressionsConfigForEslintConfigFolderPath +} from '../bulk-suppressions-file'; + +export async function pruneAsync(): Promise { + const args: string[] = process.argv.slice(3); + + if (args.includes('--help') || args.includes('-h')) { + printPruneHelp(); + process.exit(0); + } + + if (args.length > 0) { + throw new Error(`@rushstack/eslint-bulk: Unknown arguments: ${args.join(' ')}`); + } + + const normalizedCwd: string = process.cwd().replace(/\\/g, '/'); + const allFiles: string[] = await getAllFilesWithExistingSuppressionsForCwdAsync(normalizedCwd); + if (allFiles.length > 0) { + process.env[ESLINT_BULK_PRUNE_ENV_VAR_NAME] = '1'; + console.log(`Pruning suppressions for ${allFiles.length} files...`); + await runEslintAsync(allFiles, 'prune'); + } else { + console.log('No files with existing suppressions found.'); + deleteBulkSuppressionsFileInEslintConfigFolder(normalizedCwd); + } +} + +async function getAllFilesWithExistingSuppressionsForCwdAsync(normalizedCwd: string): Promise { + const { jsonObject: bulkSuppressionsConfigJson } = + getSuppressionsConfigForEslintConfigFolderPath(normalizedCwd); + const allFiles: Set = new Set(); + for (const { file: filePath } of bulkSuppressionsConfigJson.suppressions) { + allFiles.add(filePath); + } + + const allFilesArray: string[] = Array.from(allFiles); + + const allExistingFiles: string[] = []; + // TODO: limit parallelism here with something similar to `Async.forEachAsync` from `node-core-library`. + await Promise.all( + allFilesArray.map(async (filePath: string) => { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + allExistingFiles.push(filePath); + } catch { + // Doesn't exist - ignore + } + }) + ); + + console.log(`Found ${allExistingFiles.length} files with existing suppressions.`); + const deletedCount: number = allFilesArray.length - allExistingFiles.length; + if (deletedCount > 0) { + console.log(`${deletedCount} files with suppressions were deleted.`); + } + + return allExistingFiles; +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts new file mode 100644 index 00000000000..8d73302aa8a --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.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 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, 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) { + throw new Error(`@rushstack/eslint-bulk execution error: ${e.message}`); + } + + const { write, prune } = await import('../bulk-suppressions-patch'); + switch (mode) { + case 'suppress': { + await write(); + break; + } + + case 'prune': { + await prune(); + break; + } + } + + if (results.length > 0) { + 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); + } + + console.log( + '@rushstack/eslint-bulk: Successfully pruned unused suppressions in all .eslint-bulk-suppressions.json ' + + `files under directory ${cwd}` + ); +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/start.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/start.ts new file mode 100644 index 00000000000..b871a6149f3 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/start.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 { pruneAsync } from './prune'; +import { suppressAsync } from './suppress'; +import { isCorrectCwd } from './utils/is-correct-cwd'; +import { printHelp } from './utils/print-help'; + +if (process.argv.includes('-h') || process.argv.includes('-H') || process.argv.includes('--help')) { + printHelp(); + process.exit(0); +} + +if (process.argv.length < 3) { + printHelp(); + process.exit(1); +} + +if (!isCorrectCwd(process.cwd())) { + console.error( + '@rushstack/eslint-bulk: Please call this command from the directory that contains .eslintrc.js or .eslintrc.cjs' + ); + process.exit(1); +} + +const subcommand: string = process.argv[2]; +let processPromise: Promise; +switch (subcommand) { + case 'suppress': { + processPromise = suppressAsync(); + break; + } + + case 'prune': { + processPromise = pruneAsync(); + break; + } + + default: { + console.error('@rushstack/eslint-bulk: Unknown subcommand: ' + subcommand); + process.exit(1); + } +} + +processPromise.catch((e) => { + if (e instanceof Error) { + console.error(e.message); + process.exit(1); + } + + throw e; +}); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/suppress.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/suppress.ts new file mode 100755 index 00000000000..c8ba1eafa43 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/suppress.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 { printSuppressHelp } from './utils/print-help'; +import { runEslintAsync } from './runEslint'; +import { ESLINT_BULK_SUPPRESS_ENV_VAR_NAME } from '../constants'; + +interface IParsedArgs { + rules: string[]; + all: boolean; + files: string[]; +} + +export async function suppressAsync(): Promise { + const args: string[] = process.argv.slice(3); + + if (args.includes('--help') || args.includes('-h')) { + printSuppressHelp(); + process.exit(0); + } + + // Use reduce to create an object with all the parsed arguments + const parsedArgs: IParsedArgs = args.reduce<{ + rules: string[]; + all: boolean; + files: string[]; + }>( + (acc, arg, index, arr) => { + if (arg === '--rule') { + // continue because next arg should be the rule + } else if (index > 0 && arr[index - 1] === '--rule' && arr[index + 1]) { + acc.rules.push(arg); + } else if (arg === '--all') { + acc.all = true; + } else if (arg.startsWith('--')) { + throw new Error(`@rushstack/eslint-bulk: Unknown option: ${arg}`); + } else { + acc.files.push(arg); + } + return acc; + }, + { rules: [], all: false, files: [] } + ); + + if (parsedArgs.files.length === 0) { + throw new Error( + '@rushstack/eslint-bulk: Files argument is required. Use glob patterns to specify files or use ' + + '`.` to suppress all files for the specified rules.' + ); + } + + if (parsedArgs.rules.length === 0 && !parsedArgs.all) { + throw new Error( + '@rushstack/eslint-bulk: Please specify at least one rule to suppress. Use --all to suppress all rules.' + ); + } + + // Find the index of the last argument that starts with '--' + const lastOptionIndex: number = args + .map((arg, i) => (arg.startsWith('--') ? i : -1)) + .reduce((lastIndex, currentIndex) => Math.max(lastIndex, currentIndex), -1); + + // Check if options come before files + if (parsedArgs.files.some((file) => args.indexOf(file) < lastOptionIndex)) { + throw new Error( + '@rushstack/eslint-bulk: Unable to parse command line arguments. All options should come before files argument.' + ); + } + + if (parsedArgs.all) { + process.env[ESLINT_BULK_SUPPRESS_ENV_VAR_NAME] = '*'; + } else if (parsedArgs.rules.length > 0) { + process.env[ESLINT_BULK_SUPPRESS_ENV_VAR_NAME] = parsedArgs.rules.join(','); + } + + await runEslintAsync(parsedArgs.files, 'suppress'); + + if (parsedArgs.all) { + console.log(`@rushstack/eslint-bulk: Successfully suppressed all rules for file(s) ${parsedArgs.files}`); + } else if (parsedArgs.rules.length > 0) { + console.log( + `@rushstack/eslint-bulk: Successfully suppressed rules ${parsedArgs.rules} for file(s) ${parsedArgs.files}` + ); + } +} 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 new file mode 100755 index 00000000000..be55dea24c9 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts @@ -0,0 +1,68 @@ +// 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 { BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME } from '../../constants'; + +// When this list is updated, update the `eslint-bulk-suppressions-newest-test` +// and/or the `eslint-bulk-suppressions-newest-test` projects' eslint dependencies. +const TESTED_VERSIONS: Set = new Set([ + '8.6.0', + '8.7.0', + '8.21.0', + '8.22.0', + '8.23.0', + '8.23.1', + '8.57.0', + '9.25.1', + '9.37.0' +]); + +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 { + const localEslintApiPath: string = require.resolve(BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME, { + paths: [packagePath] + }); + const localEslintPath: string = path.dirname(path.dirname(localEslintApiPath)); + const { version: localEslintVersion } = require(`${localEslintPath}/package.json`); + + if (!TESTED_VERSIONS.has(localEslintVersion)) { + console.warn( + '@rushstack/eslint-bulk: Be careful, the installed ESLint version has not been tested with eslint-bulk.' + ); + } + + return [localEslintApiPath, localEslintVersion]; + } catch (e1) { + try { + const { + dependencies, + devDependencies + }: { + dependencies: Record | undefined; + devDependencies: Record | undefined; + } = require(`${packagePath}/package.json`); + + if (devDependencies?.eslint) { + throw new Error( + '@rushstack/eslint-bulk: eslint is specified as a dev dependency in package.json, ' + + 'but eslint-bulk cannot find it in node_modules.' + ); + } else if (dependencies?.eslint) { + throw new Error( + '@rushstack/eslint-bulk: eslint is specified as a dependency in package.json, ' + + 'but eslint-bulk cannot find it in node_modules.' + ); + } else { + throw new Error('@rushstack/eslint-bulk: eslint is not specified as a dependency in package.json.'); + } + } 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 new file mode 100755 index 00000000000..eff0c18cb68 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/is-correct-cwd.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 fs from 'node:fs'; + +export function isCorrectCwd(cwd: string): boolean { + 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/cli/utils/print-help.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/print-help.ts new file mode 100644 index 00000000000..a0a8212dead --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/print-help.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 { wrapWordsToLines } from './wrap-words-to-lines'; + +export function printPruneHelp(): void { + const help: string = `eslint-bulk prune + +Usage: + +eslint-bulk prune + +This command is a thin wrapper around ESLint that communicates with @rushstack/eslint-patch to delete all unused suppression entries in all .eslint-bulk-suppressions.json files under the current working directory.`; + + const wrapped: string[] = wrapWordsToLines(help); + for (const line of wrapped) { + console.log(line); + } +} + +export function printHelp(): void { + const help: string = `eslint-bulk + +Usage: + +eslint-bulk suppress --rule RULENAME1 [--rule RULENAME2...] PATH1 [PATH2...] +eslint-bulk suppress --all PATH1 [PATH2...] +eslint-bulk suppress --help + +eslint-bulk prune +eslint-bulk prune --help + +eslint-bulk --help + +This command line tool is a thin wrapper around ESLint that communicates with @rushstack/eslint-patch to suppress or prune unused suppressions in the local .eslint-bulk-suppressions.json file. + +Commands: + eslint-bulk suppress [options] + Use this command to generate a new .eslint-bulk-suppressions.json file or add suppression entries to the existing file. Specify the files and rules you want to suppress. + Please run "eslint-bulk suppress --help" to learn more. + + eslint-bulk prune + Use this command to delete all unused suppression entries in all .eslint-bulk-suppressions.json files under the current working directory. + Please run "eslint-bulk prune --help" to learn more. +`; + + const wrapped: string[] = wrapWordsToLines(help); + for (const line of wrapped) { + console.log(line); + } +} + +export function printSuppressHelp(): void { + const help: string = `eslint-bulk suppress [options] + +Usage: + +eslint-bulk suppress --rule RULENAME1 [--rule RULENAME2...] PATH1 [PATH2...] +eslint-bulk suppress --all PATH1 [PATH2...] +eslint-bulk suppress --help + +This command is a thin wrapper around ESLint that communicates with @rushstack/eslint-patch to either generate a new .eslint-bulk-suppressions.json file or add suppression entries to the existing file. Specify the files and rules you want to suppress. + +Argument: + + Glob patterns for paths to suppress, same as eslint files argument. Should be relative to the project root. + +Options: + -h, -H, --help + Display this help message. + + -R, --rule + The full name of the ESLint rule you want to bulk-suppress. Specify multiple rules with --rule NAME1 --rule RULENAME2. + + -A, --all + Bulk-suppress all rules in the specified file patterns.`; + + const wrapped: string[] = wrapWordsToLines(help); + for (const line of wrapped) { + console.log(line); + } +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/wrap-words-to-lines.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/wrap-words-to-lines.ts new file mode 100755 index 00000000000..b38de3bd20a --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/wrap-words-to-lines.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// ---------------------------------------------------------------------------------------------------------- +// TO AVOID EXTRA DEPENDENCIES, THE CODE IN THIS FILE WAS BORROWED FROM: +// +// rushstack/libraries/terminal/src/PrintUtilities.ts +// +// KEEP IT IN SYNC WITH THAT FILE. +// ---------------------------------------------------------------------------------------------------------- + +/** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indent - The number of spaces to indent the wrapped lines, defaults to 0 + */ +export function wrapWordsToLines(text: string, maxLineLength?: number, indent?: number): string[]; +/** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param linePrefix - The string to prefix each line with, defaults to '' + */ +export function wrapWordsToLines(text: string, maxLineLength?: number, linePrefix?: string): string[]; +/** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indentOrLinePrefix - The number of spaces to indent the wrapped lines or the string to prefix + * each line with, defaults to no prefix + */ +export function wrapWordsToLines( + text: string, + maxLineLength?: number, + indentOrLinePrefix?: number | string +): string[]; +export function wrapWordsToLines( + text: string, + maxLineLength?: number, + indentOrLinePrefix?: number | string +): string[] { + let linePrefix: string; + switch (typeof indentOrLinePrefix) { + case 'number': + linePrefix = ' '.repeat(indentOrLinePrefix); + break; + case 'string': + linePrefix = indentOrLinePrefix; + break; + default: + linePrefix = ''; + break; + } + + const linePrefixLength: number = linePrefix.length; + + if (!maxLineLength) { + maxLineLength = process.stdout.getWindowSize()[0]; + } + + // Apply word wrapping and the provided line prefix, while also respecting existing newlines + // and prefix spaces that may exist in the text string already. + const lines: string[] = text.split(/\r?\n/); + + const wrappedLines: string[] = []; + for (const line of lines) { + if (line.length + linePrefixLength <= maxLineLength) { + wrappedLines.push(linePrefix + line); + } else { + const lineAdditionalPrefix: string = line.match(/^\s*/)?.[0] || ''; + const whitespaceRegexp: RegExp = /\s+/g; + let currentWhitespaceMatch: RegExpExecArray | null = null; + let previousWhitespaceMatch: RegExpExecArray | undefined; + let currentLineStartIndex: number = lineAdditionalPrefix.length; + let previousBreakRanOver: boolean = false; + while ((currentWhitespaceMatch = whitespaceRegexp.exec(line)) !== null) { + if (currentWhitespaceMatch.index + linePrefixLength - currentLineStartIndex > maxLineLength) { + let whitespaceToSplitAt: RegExpExecArray | undefined; + if ( + !previousWhitespaceMatch || + // Handle the case where there are two words longer than the maxLineLength in a row + previousBreakRanOver + ) { + whitespaceToSplitAt = currentWhitespaceMatch; + } else { + whitespaceToSplitAt = previousWhitespaceMatch; + } + + wrappedLines.push( + linePrefix + + lineAdditionalPrefix + + line.substring(currentLineStartIndex, whitespaceToSplitAt.index) + ); + previousBreakRanOver = whitespaceToSplitAt.index - currentLineStartIndex > maxLineLength; + currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length; + } else { + previousBreakRanOver = false; + } + + previousWhitespaceMatch = currentWhitespaceMatch; + } + + if (currentLineStartIndex < line.length) { + wrappedLines.push(linePrefix + lineAdditionalPrefix + line.substring(currentLineStartIndex)); + } + } + } + + return wrappedLines; +} diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts new file mode 100644 index 00000000000..69be3edb8e5 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME: 'RUSHSTACK_ESLINT_BULK_PATCH_PATH' = + 'RUSHSTACK_ESLINT_BULK_PATCH_PATH'; +export const ESLINT_BULK_SUPPRESS_ENV_VAR_NAME: 'RUSHSTACK_ESLINT_BULK_SUPPRESS' = + 'RUSHSTACK_ESLINT_BULK_SUPPRESS'; +export const ESLINT_BULK_ENABLE_ENV_VAR_NAME: 'ESLINT_BULK_ENABLE' = 'ESLINT_BULK_ENABLE'; +export const ESLINT_BULK_PRUNE_ENV_VAR_NAME: 'ESLINT_BULK_PRUNE' = 'ESLINT_BULK_PRUNE'; +export const ESLINT_BULK_DETECT_ENV_VAR_NAME: '_RUSHSTACK_ESLINT_BULK_DETECT' = + '_RUSHSTACK_ESLINT_BULK_DETECT'; +export const ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME: 'RUSHSTACK_ESLINT_BULK_FORCE_REGENERATE_PATCH' = + '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'; + +export const BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME: string = + process.env[ESLINT_PACKAGE_NAME_ENV_VAR_NAME] ?? 'eslint'; 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 new file mode 100644 index 00000000000..5a0107537a3 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/generate-patched-file.ts @@ -0,0 +1,399 @@ +// 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 { + ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME, + ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME +} from './constants'; + +/** + * Dynamically generate file to properly patch many versions of ESLint + * @param inputFilePath - Must be an iteration of https://github.com/eslint/eslint/blob/main/lib/linter/linter.js + * @param outputFilePath - Some small changes to linter.js + */ +export function generatePatchedLinterJsFileIfDoesNotExist( + inputFilePath: string, + outputFilePath: string, + eslintPackageVersion: string +): void { + const generateEnvVarValue: string | undefined = + process.env[ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME]; + if (generateEnvVarValue !== 'true' && generateEnvVarValue !== '1' && fs.existsSync(outputFilePath)) { + 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; + + /** + * Extract from the stream until marker is reached. When matching marker, + * ignore whitespace in the stream and in the marker. Return the extracted text. + */ + function scanUntilMarker(marker: string): string { + const trimmedMarker: string = marker.replace(/\s/g, ''); + + let output: string = ''; + let trimmed: string = ''; + + while (inputIndex < inputFile.length) { + const char: string = inputFile[inputIndex++]; + output += char; + if (!/^\s$/.test(char)) { + trimmed += char; + } + if (trimmed.endsWith(trimmedMarker)) { + return output; + } + } + + throw new Error('Unexpected end of input while looking for ' + JSON.stringify(marker)); + } + + function scanUntilNewline(): string { + let output: string = ''; + + while (inputIndex < inputFile.length) { + const char: string = inputFile[inputIndex++]; + output += char; + if (char === '\n') { + return output; + } + } + + throw new Error('Unexpected end of input while looking for new line'); + } + + function scanUntilEnd(): string { + const output: string = inputFile.substring(inputIndex); + inputIndex = inputFile.length; + 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 getIndexOfNextMethod(fromIndex: number): { index: number; isPublic?: boolean } { + const rest: string = inputFile.substring(fromIndex); + + const endOfClassIndex: number = rest.indexOf('\n}'); + + const { index: startOfClassMethodIndex, marker: startOfClassMethodMarker } = + indexOfStartOfClassMethod(rest); + + if ( + startOfClassMethodIndex === -1 || + !startOfClassMethodMarker || + startOfClassMethodIndex > endOfClassIndex + ) { + return { index: -1 }; + } + + const afterMarkerIndex: number = startOfClassMethodIndex + startOfClassMethodMarker.length; + + const isPublicMethod: boolean = + rest[afterMarkerIndex] !== '_' && + rest[afterMarkerIndex] !== '#' && + !rest.substring(afterMarkerIndex, rest.indexOf('\n', afterMarkerIndex)).includes('static') && + !rest.substring(afterMarkerIndex, rest.indexOf('\n', afterMarkerIndex)).includes('constructor'); + + return { index: fromIndex + afterMarkerIndex, isPublic: isPublicMethod }; + } + + function scanUntilIndex(indexToScanTo: number): string { + const output: string = inputFile.substring(inputIndex, indexToScanTo); + inputIndex = indexToScanTo; + return output; + } + + let outputFile: string = ''; + + // Match this: + // //------------------------------------------------------------------------------ + // // Requirements + // //------------------------------------------------------------------------------ + outputFile += scanUntilMarker('// Requirements'); + outputFile += scanUntilMarker('//--'); + outputFile += scanUntilNewline(); + + outputFile += ` +// --- BEGIN MONKEY PATCH --- +const bulkSuppressionsPatch = require(process.env.${ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME}); +const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJS; +`; + + // Match this: + // //------------------------------------------------------------------------------ + // // Typedefs + // //------------------------------------------------------------------------------ + const requireSection: string = scanUntilMarker('// Typedefs'); + + // Match something like this: + // + // const path = require('path'), + // eslintScope = require('eslint-scope'), + // evk = require('eslint-visitor-keys'), + // + // Convert to something like this: + // + // const path = require('path'), + // eslintScope = requireFromPathToLinterJS('eslint-scope'), + // evk = requireFromPathToLinterJS('eslint-visitor-keys'), + // + outputFile += requireSection.replace(/require\s*\((?:'([^']+)'|"([^"]+)")\)/g, (match, p1, p2) => { + const importPath: string = p1 ?? p2 ?? ''; + + if (importPath !== 'path') { + if (p1) { + return `requireFromPathToLinterJS('${p1}')`; + } + if (p2) { + return `requireFromPathToLinterJS("${p2}")`; + } + } + + // Keep as-is + return match; + }); + outputFile += `--- END MONKEY PATCH --- +`; + + 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({ + // ruleId, + // severity, + // sourceCode, + // messageIds, + // disableFixes + // }); + // } + // const problem = reportTranslator(...args); + // + // if (problem.fix && !(rule.meta && rule.meta.fixable)) { + // 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, + // ); + // + // 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({ + // ruleId, + // severity, + // sourceCode, + // messageIds, + // disableFixes + // }); + // } + // const problem = reportTranslator(...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\"."); + // } + // ``` + // 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 (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('class Linter {'); + outputFile += scanUntilNewline(); + outputFile += ` + // --- BEGIN MONKEY PATCH --- + /** + * We intercept ESLint execution at the .eslintrc.js file, but unfortunately the Linter class is + * initialized before the .eslintrc.js file is executed. This means the internalSlotsMap that all + * the patched methods refer to is not initialized. This method checks if the internalSlotsMap is + * initialized, and if not, initializes it. + */ + _conditionallyReinitialize({ cwd, configType } = {}) { + if (internalSlotsMap.get(this) === undefined) { + internalSlotsMap.set(this, { + cwd: normalizeCwd(cwd), + flags: [], + lastConfigArray: null, + lastSourceCode: null, + lastSuppressedMessages: [], + configType, // TODO: Remove after flat config conversion + parserMap: new Map([['espree', espree]]), + ruleMap: new Rules() + }); + + this.version = pkg.version; + } + } + // --- END 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 --- +`; + } 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 new file mode 100644 index 00000000000..c11870137a9 --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/index.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 { 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'; +import { ESLINT_BULK_DETECT_ENV_VAR_NAME, ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME } from './constants'; + +if (!eslintFolder) { + console.error( + '@rushstack/eslint-patch/eslint-bulk-suppressions: Could not find ESLint installation to patch.' + ); + + process.exit(1); +} + +const eslintBulkDetectEnvVarValue: string | undefined = process.env[ESLINT_BULK_DETECT_ENV_VAR_NAME]; +if (eslintBulkDetectEnvVarValue === 'true' || eslintBulkDetectEnvVarValue === '1') { + findAndConsoleLogPatchPathCli(); + process.exit(0); +} + +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, eslintPackageVersion); +const { Linter: LinterPatch } = require(pathToGeneratedPatch); +LinterPatch.prototype.verify = extendVerifyFunction(LinterPatch.prototype.verify); + +const { Linter } = require(pathToLinterJS); + +patchClass(Linter, LinterPatch); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts new file mode 100644 index 00000000000..62e54bcd31b --- /dev/null +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.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 fs from 'node:fs'; +import os from 'node:os'; + +import { eslintFolder, eslintPackageVersion } from '../_patch-base'; +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 { + minCliVersion: string; + cliEntryPoint: string; +} + +const CURRENT_PACKAGE_VERSION: string = currentPackageJson.version; + +export function findAndConsoleLogPatchPathCli(): void { + const eslintBulkDetectEnvVarValue: string | undefined = process.env[ESLINT_BULK_DETECT_ENV_VAR_NAME]; + if (eslintBulkDetectEnvVarValue !== 'true' && eslintBulkDetectEnvVarValue !== '1') { + return; + } + + const configuration: IConfiguration = { + /** + * `@rushstack/eslint-bulk` should report an error if its package.json is older than this number + */ + minCliVersion: '0.0.0', + /** + * `@rushstack/eslint-bulk` will invoke this entry point + */ + cliEntryPoint: require.resolve('../exports/eslint-bulk') + }; + + console.log( + ESLINT_BULK_STDOUT_START_DELIMETER + JSON.stringify(configuration) + ESLINT_BULK_STDOUT_END_DELIMETER + ); +} + +export function getPathToLinterJS(): string { + if (!eslintFolder) { + throw new Error('Cannot find ESLint installation to patch.'); + } + + return `${eslintFolder}/lib/linter/linter.js`; +} + +export function ensurePathToGeneratedPatch(): string { + const patchesFolderPath: string = `${os.tmpdir()}/rushstack-eslint-bulk-${CURRENT_PACKAGE_VERSION}/patches`; + fs.mkdirSync(patchesFolderPath, { recursive: true }); + const pathToGeneratedPatch: string = `${patchesFolderPath}/linter-patch-v${eslintPackageVersion}.js`; + return pathToGeneratedPatch; +} diff --git a/eslint/eslint-patch/src/exports/eslint-bulk.ts b/eslint/eslint-patch/src/exports/eslint-bulk.ts new file mode 100644 index 00000000000..b096074c206 --- /dev/null +++ b/eslint/eslint-patch/src/exports/eslint-bulk.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. + +// "lib/exports/eslint-bulk" is the entry point for the @rushstack/eslint-bulk command line front end. + +import '../eslint-bulk-suppressions/cli/start'; diff --git a/eslint/eslint-patch/src/modern-module-resolution.ts b/eslint/eslint-patch/src/modern-module-resolution.ts new file mode 100644 index 00000000000..3b0e0003dd5 --- /dev/null +++ b/eslint/eslint-patch/src/modern-module-resolution.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. + +// This is a workaround for https://github.com/eslint/eslint/issues/3458 +// +// To correct how ESLint searches for plugin packages, add this line to the top of your project's .eslintrc.js file: +// +// require("@rushstack/eslint-patch/modern-module-resolution"); +// + +import { + configArrayFactory, + ModuleResolver, + isModuleResolutionError, + ESLINT_MAJOR_VERSION +} from './_patch-base'; + +// error: "The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ''" +const isInvalidImporterPath: (ex: unknown) => boolean = (ex) => + (ex as { code: unknown } | undefined)?.code === 'ERR_INVALID_ARG_VALUE'; + +if (!configArrayFactory.__loadPluginPatched) { + configArrayFactory.__loadPluginPatched = true; + // eslint-disable-next-line @typescript-eslint/typedef + const originalLoadPlugin = configArrayFactory.prototype._loadPlugin; + + if (ESLINT_MAJOR_VERSION === 6) { + // ESLint 6.x + // https://github.com/eslint/eslint/blob/9738f8cc864d769988ccf42bb70f524444df1349/lib/cli-engine/config-array-factory.js#L915 + configArrayFactory.prototype._loadPlugin = function ( + name: string, + importerPath: string, + importerName: string + ) { + const originalResolve: (moduleName: string, relativeToPath: string) => string = ModuleResolver.resolve; + try { + ModuleResolver.resolve = function (moduleName: string, relativeToPath: string) { + try { + // resolve using importerPath instead of relativeToPath + return originalResolve.call(this, moduleName, importerPath); + } catch (e) { + if (isModuleResolutionError(e) || isInvalidImporterPath(e)) { + return originalResolve.call(this, moduleName, relativeToPath); + } + throw e; + } + }; + return originalLoadPlugin.apply(this, arguments); + } finally { + ModuleResolver.resolve = originalResolve; + } + }; + } else { + // ESLint 7.x || 8.x + // https://github.com/eslint/eslintrc/blob/242d569020dfe4f561e4503787b99ec016337457/lib/config-array-factory.js#L1023 + configArrayFactory.prototype._loadPlugin = function (name: string, ctx: Record) { + const originalResolve: (moduleName: string, relativeToPath: string | unknown) => string = + ModuleResolver.resolve; + try { + ModuleResolver.resolve = function (moduleName: string, relativeToPath: string) { + try { + // resolve using ctx.filePath instead of relativeToPath + return originalResolve.call(this, moduleName, ctx.filePath); + } catch (e) { + if (isModuleResolutionError(e) || isInvalidImporterPath(e)) { + return originalResolve.call(this, moduleName, relativeToPath); + } + throw e; + } + }; + return originalLoadPlugin.apply(this, arguments); + } finally { + ModuleResolver.resolve = originalResolve; + } + }; + } +} diff --git a/eslint/eslint-patch/src/usage.ts b/eslint/eslint-patch/src/usage.ts new file mode 100644 index 00000000000..6fab9af4b00 --- /dev/null +++ b/eslint/eslint-patch/src/usage.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. + +throw new Error( + 'The @rushstack/eslint-patch package does not have a default entry point.' + + ' See README.md for usage instructions.' +); + +export {}; diff --git a/eslint/eslint-patch/tsconfig.json b/eslint/eslint-patch/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/eslint/eslint-patch/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/eslint/eslint-plugin-packlets/.npmignore b/eslint/eslint-plugin-packlets/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/eslint/eslint-plugin-packlets/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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/eslint/eslint-plugin-packlets/.vscode/launch.json b/eslint/eslint-plugin-packlets/.vscode/launch.json new file mode 100644 index 00000000000..3fa732c0a0e --- /dev/null +++ b/eslint/eslint-plugin-packlets/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // 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": "packlets-tutorial", + "cwd": "${workspaceFolder}/../../tutorials/packlets-tutorial", + "program": "${workspaceFolder}/node_modules/eslint/bin/eslint.js", + "args": ["-f", "unix", "src/**/*.ts"] + }, + { + "type": "node", + "request": "launch", + "name": "packlets-tutorial file", + "cwd": "${workspaceFolder}/../../tutorials/packlets-tutorial/src", + "program": "${workspaceFolder}/node_modules/eslint/bin/eslint.js", + "args": [ + "-f", + "unix", + "${workspaceFolder}/../../tutorials/packlets-tutorial/src/packlets/reports/index.ts" + ] + } + ] +} diff --git a/eslint/eslint-plugin-packlets/CHANGELOG.json b/eslint/eslint-plugin-packlets/CHANGELOG.json new file mode 100644 index 00000000000..836dd17d4e4 --- /dev/null +++ b/eslint/eslint-plugin-packlets/CHANGELOG.json @@ -0,0 +1,384 @@ +{ + "name": "@rushstack/eslint-plugin-packlets", + "entries": [ + { + "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", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.4`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.9.1", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.3`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.9.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3 with @typescript-eslint 6.19.x" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.2`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.8.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.1`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.8.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.7.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the @typescript-eslint/* dependencies to ~5.59.2" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.6.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a link in the README." + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.6.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.5.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript dependency to 4.7" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.4.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.4.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.6" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.5", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the path in the package.json \"directory\" field." + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.4", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for ESLint v8" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.3", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.2", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "patch": [ + { + "comment": "Update typescript-eslint to add support for TypeScript 4.4." + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.1", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.3.0", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/eslint-plugin-packlets_v0.2.2", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the @rushstack/packlets/circular-deps rule did not work correctly with TypeScript 4.2" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.2.1", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix unlisted dependency on @typescript-eslint/experimental-utils" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.2.0", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "minor": [ + { + "comment": "Add an optional \"@rushstack/packlets/readme\" rule that requires a README.md in each packlet folder" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/eslint-plugin-packlets_v0.1.2", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an exception that occured if a source file was added to the \"src/packlets\" folder, not belonging to any packlet" + }, + { + "comment": "Fix an issue where linting was sometimes not performed on MacOS, because Node.js \"path.relative()\" incorrectly assumes that every POSIX file system is case-sensitive" + }, + { + "comment": "Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.1.1", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to tutorial project in README.md" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.1.0", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/eslint/eslint-plugin-packlets/CHANGELOG.md b/eslint/eslint-plugin-packlets/CHANGELOG.md new file mode 100644 index 00000000000..594093c59ba --- /dev/null +++ b/eslint/eslint-plugin-packlets/CHANGELOG.md @@ -0,0 +1,203 @@ +# Change Log - @rushstack/eslint-plugin-packlets + +This log was last generated on Mon, 13 Oct 2025 15:13:02 GMT and should not be manually modified. + +## 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 + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.9.1 +Sat, 17 Feb 2024 06:24:34 GMT + +_Version update only_ + +## 0.9.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 with @typescript-eslint 6.19.x + +## 0.8.1 +Tue, 26 Sep 2023 09:30:33 GMT + +_Version update only_ + +## 0.8.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.7.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the @typescript-eslint/* dependencies to ~5.59.2 + +## 0.6.1 +Mon, 10 Oct 2022 15:23:44 GMT + +### Patches + +- Fix a link in the README. + +## 0.6.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8 + +## 0.5.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript dependency to 4.7 + +## 0.4.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.4.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.6 + +## 0.3.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.3.5 +Tue, 15 Mar 2022 19:15:53 GMT + +### Patches + +- Fix the path in the package.json "directory" field. + +## 0.3.4 +Mon, 06 Dec 2021 16:08:32 GMT + +### Patches + +- Add support for ESLint v8 + +## 0.3.3 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.3.2 +Thu, 07 Oct 2021 07:13:35 GMT + +### Patches + +- Update typescript-eslint to add support for TypeScript 4.4. + +## 0.3.1 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.3.0 +Mon, 12 Jul 2021 23:08:26 GMT + +### Minor changes + +- Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389) + +## 0.2.2 +Mon, 12 Apr 2021 15:10:28 GMT + +### Patches + +- Fix an issue where the @rushstack/packlets/circular-deps rule did not work correctly with TypeScript 4.2 + +## 0.2.1 +Tue, 06 Apr 2021 15:14:22 GMT + +### Patches + +- Fix unlisted dependency on @typescript-eslint/experimental-utils + +## 0.2.0 +Wed, 11 Nov 2020 01:08:58 GMT + +### Minor changes + +- Add an optional "@rushstack/packlets/readme" rule that requires a README.md in each packlet folder + +## 0.1.2 +Wed, 28 Oct 2020 01:18:03 GMT + +### Patches + +- Fix an exception that occured if a source file was added to the "src/packlets" folder, not belonging to any packlet +- Fix an issue where linting was sometimes not performed on MacOS, because Node.js "path.relative()" incorrectly assumes that every POSIX file system is case-sensitive +- Fix an issue where @rushstack/packlets/circular-deps did not detect certain types of circular dependencies + +## 0.1.1 +Tue, 06 Oct 2020 00:24:06 GMT + +### Patches + +- Fix broken link to tutorial project in README.md + +## 0.1.0 +Mon, 05 Oct 2020 22:36:57 GMT + +### Minor changes + +- Initial release + diff --git a/eslint/eslint-plugin-packlets/LICENSE b/eslint/eslint-plugin-packlets/LICENSE new file mode 100644 index 00000000000..579e79aa4f4 --- /dev/null +++ b/eslint/eslint-plugin-packlets/LICENSE @@ -0,0 +1,24 @@ +@rushstack/eslint-plugin-packlets + +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/eslint/eslint-plugin-packlets/README.md b/eslint/eslint-plugin-packlets/README.md new file mode 100644 index 00000000000..2227b456fa5 --- /dev/null +++ b/eslint/eslint-plugin-packlets/README.md @@ -0,0 +1,201 @@ +# @rushstack/eslint-plugin-packlets + +Packlets provide a lightweight alternative to NPM packages for organizing source files within a single project. The formalism is validated using ESLint rules. + +## Motivation + +When building a large application, it's a good idea to organize source files into modules, so that their dependencies can be managed. For example, suppose an application's source files can be grouped as follows: + +- `src/logging/*.ts` - the logging system +- `src/data-model/*.ts` - the data model +- `src/reports/*.ts` - the report engine +- `src/*.ts` - other arbitrary files such as startup code and the main application + +Using file folders is helpful, but it's not very strict. Files under `src/logging` can easily import files from `/src/reports`, creating a confusing circular import. They can also import arbitrary application files. Also, there is no clear distinction between which files are the "public API" for `src/logging` versus its private implementation details. + +All these problems can be solved by reorganizing the project into NPM packages (or [Rush projects](https://rushjs.io/)). Something like this: + +- `@my-app/logging` - the logging system +- `@my-app/data-model` - the data model +- `@my-app/reports` - the report engine +- `@my-app/application` - other arbitrary files such as startup code and the main application + +However, separating code in this way has some downsides. The projects need to build separately, which has some tooling costs (for example, "watch mode" now needs to consider multiple projects). In a large monorepo, the library may attract other consumers, before the API has been fully worked out. + +Packlets provide a lightweight alternative that offers many of the same benefits of packages, but without the `package.json` file. It's a great way to prototype your project organization before later graduating your packlets into proper NPM packages. + +## 5 rules for packlets + +With packlets, our folders would be reorganized as follows: + +- `src/packlets/logging/*.ts` - the logging system +- `src/packlets/data-model/*.ts` - the data model +- `src/packlets/reports/*.ts` - the report engine +- `src/*.ts` - other arbitrary files such as startup code and the main application + +The [packlets-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/other/packlets-tutorial) sample project illustrates this layout in full detail. + +The basic design can be summarized in 5 rules: + +1. A "packlet" is defined to be a folder path `./src/packlets//index.ts`. The **index.ts** file will have the exported APIs. The `` name must consist of lower case words separated by hyphens, similar to an NPM package name. + + Example file paths: + ``` + src/packlets/controls + src/packlets/logger + src/packlets/my-long-name + ``` + + > **NOTE:** The `packlets` cannot be nested deeper in the tree. Like with NPM packages, `src/packlets` is a flat namespace. + +2. Files outside the packlet folder can only import the packlet root **index.ts**: + + **src/app/App.ts** + ```ts + // Okay + import { MainReport } from '../packlets/reports'; + + // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics) + import { MainReport } from '../packlets/reports/index'; + + // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics) + import { MainReport } from '../packlets/reports/MainReport'; + ``` + +3. Files inside a packlet folder should import their siblings directly, not via their own **index.ts** (which might create a circular reference): + + **src/packlets/logging/Logger.ts** + ```ts + // Okay + import { MessageType } from "./MessageType"; + + // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics) + import { MessageType } from "."; + + // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics) + import { MessageType } from "./index"; + ``` + + +4. Packlets may reference other packlets, but not in a way that would introduce a circular dependency: + + **src/packlets/data-model/DataModel.ts** + ```ts + // Okay + import { Logger } from '../../packlets/logging'; + ``` + + **src/packlets/logging/Logger.ts** + ```ts + // Error: Packlet imports create a circular reference: (@rushstack/packlets/circular-deps) + // "logging" is referenced by src/packlets/data-model/DataModel.ts + // "data-model" is referenced by src/packlets/logging/Logger.ts + import { DataModel } from '../../packlets/data-model'; + ``` + +5. Other source files are allowed outside the **src/packlets** folder. They may import a packlet, but packlets must only import from other packlets or NPM packages. + + **src/app/App.ts** + + ```ts + // Okay + import { MainReport } from '../packlets/reports'; + ``` + + **src/packlets/data-model/ExampleModel.ts** + ```ts + // Error: A local project file cannot be imported. A packlet's dependencies must be + // NPM packages and/or other packlets. (@rushstack/packlets/mechanics) + import { App } from '../../app/App'; + ``` + + +## Getting Started + +To enable packlet validation for a simple `typescript-eslint` setup, reference the `@rushstack/eslint-plugin-packlets` project like this: + +**\/.eslintrc.js** +```js +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@rushstack/eslint-plugin-packlets/recommended' // <--- ADD THIS + ], + parserOptions: { + project: './tsconfig.json', + sourceType: 'module', + tsconfigRootDir: __dirname + } +}; +``` + +Or, if you are using the [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) ruleset, add the `"packlets"` mixin like this: + +**\/.eslintrc.js** +```ts +// 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", + "@rushstack/eslint-config/mixins/packlets" // <--- ADD THIS + ], + parserOptions: { tsconfigRootDir: __dirname } +}; +``` + +The `@rushstack/eslint-plugin-packlets` plugin implements three separate rules: + +- `@rushstack/packlets/mechanics` - validates most of the import path rules outlined above. +- `@rushstack/packlets/circular-deps` - detects circular dependencies between packlets. This rule requires an ESLint configuration that enables full type information from the TypeScript compiler. +- `@rushstack/packlets/readme` - requires each packlet to have a README.md file. This rule is disabled by default. + +## Requiring a README.md file + +If you'd like to require a README.md file in each packlet folder, enable the optional `@rushstack/packlets/readme` rule. + +The `minimumReadmeWords` option allows you to specify a minimum number of words of documentation in the README.md file. The default value is `10` words. + +Example configuration with the `@rushstack/packlets/readme` rule enabled: + +**\/.eslintrc.js** +```ts +// 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", + "@rushstack/eslint-config/mixins/packlets" + ], + parserOptions: { tsconfigRootDir: __dirname }, + overrides: [ + { + files: ['*.ts', '*.tsx'], + + rules: { + '@rushstack/packlets/readme': [ // <--- ADD THIS + 'warn', + { minimumReadmeWords: 10 } + ] + } + } + ] +}; +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/eslint/eslint-plugin-packlets/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) documentation + +`@rushstack/eslint-plugin-packlets` is part of the [Rush Stack](https://rushstack.io/) family of projects. +The idea for packlets was originally proposed by [@bartvandenende-wm](https://github.com/bartvandenende-wm) +and [@victor-wm](https://github.com/victor-wm). diff --git a/eslint/eslint-plugin-packlets/config/jest.config.json b/eslint/eslint-plugin-packlets/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/eslint/eslint-plugin-packlets/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/eslint/eslint-plugin-packlets/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/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 new file mode 100644 index 00000000000..efe79cc5703 --- /dev/null +++ b/eslint/eslint-plugin-packlets/package.json @@ -0,0 +1,39 @@ +{ + "name": "@rushstack/eslint-plugin-packlets", + "version": "0.14.0", + "description": "A lightweight alternative to NPM packages for organizing source files within a single project", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-plugin-packlets" + }, + "homepage": "https://rushstack.io", + "keywords": [ + "eslint", + "eslint-config", + "packlets", + "rules" + ], + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/tree-pattern": "workspace:*", + "@typescript-eslint/utils": "~8.46.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@typescript-eslint/parser": "~8.46.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + } +} diff --git a/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts b/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts new file mode 100644 index 00000000000..02f7d33b210 --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts @@ -0,0 +1,282 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as ts from 'typescript'; + +import { Path } from './Path'; +import type { PackletAnalyzer } from './PackletAnalyzer'; + +enum RefFileKind { + Import, + ReferenceFile, + TypeReferenceDirective +} + +// TypeScript compiler internal: +// Version range: >= 3.6.0, <= 4.2.0 +// https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/program.ts#L541 +interface IRefFile { + // The absolute path of the module that was imported. + // (Normalized to an all lowercase ts.Path string.) + referencedFileName: string; + // The kind of reference. + kind: RefFileKind; + // An index indicating the order in which items occur in a compound expression + index: number; + + // The absolute path of the source file containing the import statement. + // (Normalized to an all lowercase ts.Path string.) + file: string; +} + +// TypeScript compiler internal: +// Version range: > 4.2.0 +// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3693 +enum FileIncludeKind { + RootFile, + SourceFromProjectReference, + OutputFromProjectReference, + Import, + ReferenceFile, + TypeReferenceDirective, + LibFile, + LibReferenceDirective, + AutomaticTypeDirectiveFile +} + +// TypeScript compiler internal: +// Version range: > 4.2.0 +// https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3748 +interface IFileIncludeReason { + kind: FileIncludeKind; + file: string | undefined; +} + +interface ITsProgramInternals extends ts.Program { + // TypeScript compiler internal: + // Version range: >= 3.6.0, <= 4.2.0 + // https://github.com/microsoft/TypeScript/blob/5ecdcef4cecfcdc86bd681b377636422447507d7/src/compiler/types.ts#L3723 + getRefFileMap?: () => Map | undefined; + + // TypeScript compiler internal: + // Version range: > 4.2.0 + // https://github.com/microsoft/TypeScript/blob/2eca17d7c1a3fb2b077f3a910d5019d74b6f07a0/src/compiler/types.ts#L3871 + getFileIncludeReasons?: () => Map; +} + +/** + * Represents a packlet that imports another packlet. + */ +export interface IPackletImport { + /** + * The name of the packlet being imported. + */ + packletName: string; + + /** + * The absolute path of the file that imports the packlet. + */ + fromFilePath: string; +} + +/** + * Used to build a linked list of imports that represent a circular dependency. + */ +interface IImportListNode extends IPackletImport { + /** + * The previous link in the linked list. + */ + 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); + + 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 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); + } + } + } + } 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; + } + } + + // 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 = DependencyAnalyzer._walkImports( + referencingPackletName, + startingPackletName, + refFileMap, + fileIncludeReasonsMap, + program, + packletsFolderPath, + visitedPacklets, + importListNode + ); + if (result) { + return result; + } + } + } + } + + return undefined; + } + + /** + * 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 + * the problem. + * + * @remarks + * For example, suppose we have files like this: + * + * ``` + * src/packlets/logging/index.ts + * src/packlets/logging/Logger.ts --> imports "../data-model" + * src/packlets/data-model/index.ts + * src/packlets/data-model/DataModel.ts --> imports "../logging" + * ``` + * + * The returned array would be: + * ```ts + * [ + * { packletName: "logging", fromFilePath: "/path/to/src/packlets/data-model/DataModel.ts" }, + * { packletName: "data-model", fromFilePath: "/path/to/src/packlets/logging/Logger.ts" }, + * ] + * ``` + * + * If there is more than one circular dependency chain, only the first one that is encountered + * will be returned. + */ + public static checkEntryPointForCircularImport( + packletName: string, + packletAnalyzer: PackletAnalyzer, + program: ts.Program + ): IPackletImport[] | undefined { + const programInternals: ITsProgramInternals = program; + + let refFileMap: Map | undefined; + let fileIncludeReasonsMap: Map | undefined; + + if (programInternals.getRefFileMap) { + // TypeScript version range: >= 3.6.0, <= 4.2.0 + refFileMap = programInternals.getRefFileMap(); + } else if (programInternals.getFileIncludeReasons) { + // Typescript version range: > 4.2.0 + fileIncludeReasonsMap = programInternals.getFileIncludeReasons(); + } else { + // If you encounter this error, please report a bug + throw new Error( + 'Your TypeScript compiler version is not supported; please upgrade @rushstack/eslint-plugin-packlets' + + ' or report a GitHub issue' + ); + } + + const visitedPacklets: Set = new Set(); + + const listNode: IImportListNode | undefined = DependencyAnalyzer._walkImports( + packletName, + packletName, + refFileMap, + fileIncludeReasonsMap, + program, + packletAnalyzer.packletsFolderPath!, + visitedPacklets, + undefined // previousNode + ); + + if (listNode) { + // Convert the linked list to an array + const packletImports: IPackletImport[] = []; + for (let current: IImportListNode | undefined = listNode; current; current = current.previousNode) { + packletImports.push({ fromFilePath: current.fromFilePath, packletName: current.packletName }); + } + return packletImports; + } + + return undefined; + } +} diff --git a/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts b/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts new file mode 100644 index 00000000000..b0149b24519 --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts @@ -0,0 +1,257 @@ +// 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 { Path } from './Path'; + +export type InputFileMessageIds = + | 'file-in-packets-folder' + | 'invalid-packlet-name' + | 'misplaced-packlets-folder' + | 'missing-src-folder' + | 'missing-tsconfig' + | 'packlet-folder-case'; + +export type ImportMessageIds = + | 'bypassed-entry-point' + | 'circular-entry-point' + | 'packlet-importing-project-file'; + +export interface IAnalyzerError { + messageId: InputFileMessageIds | ImportMessageIds; + data?: Readonly>; +} + +export class PackletAnalyzer { + private static _validPackletName: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; + + /** + * The input file being linted. + * + * Example: "/path/to/my-project/src/file.ts" + */ + public readonly inputFilePath: string; + + /** + * An error that occurred while analyzing the inputFilePath. + */ + public readonly error: IAnalyzerError | undefined; + + /** + * Returned to indicate that the linter can ignore this file. Possible reasons: + * - It's outside the "src" folder + * - The project doesn't define any packlets + */ + public readonly nothingToDo: boolean; + + /** + * If true, then the "src/packlets" folder exists. + */ + public readonly projectUsesPacklets: boolean; + + /** + * The absolute path of the "src/packlets" folder. + */ + public readonly packletsFolderPath: string | undefined; + + /** + * The packlet that the inputFilePath is under, if any. + */ + public readonly inputFilePackletName: string | undefined; + + /** + * Returns true if inputFilePath belongs to a packlet and is the entry point index.ts. + */ + public readonly isEntryPoint: boolean; + + private constructor(inputFilePath: string, tsconfigFilePath: string | undefined) { + this.inputFilePath = inputFilePath; + this.error = undefined; + this.nothingToDo = false; + this.projectUsesPacklets = false; + this.packletsFolderPath = undefined; + this.inputFilePackletName = undefined; + this.isEntryPoint = false; + + // Example: /path/to/my-project/src + + if (!tsconfigFilePath) { + this.error = { messageId: 'missing-tsconfig' }; + return; + } + + const srcFolderPath: string = Path.join(Path.dirname(tsconfigFilePath), 'src'); + + if (!fs.existsSync(srcFolderPath)) { + this.error = { messageId: 'missing-src-folder', data: { srcFolderPath } }; + return; + } + + if (!Path.isUnder(inputFilePath, srcFolderPath)) { + // Ignore files outside the "src" folder + this.nothingToDo = true; + return; + } + + // Example: packlets/my-packlet/index.ts + const inputFilePathRelativeToSrc: string = Path.relative(srcFolderPath, inputFilePath); + + // Example: [ 'packlets', 'my-packlet', 'index.ts' ] + const pathParts: string[] = inputFilePathRelativeToSrc.split(/[\/\\]+/); + + let underPackletsFolder: boolean = false; + + const expectedPackletsFolder: string = Path.join(srcFolderPath, 'packlets'); + + for (let i: number = 0; i < pathParts.length; ++i) { + const pathPart: string = pathParts[i]; + if (pathPart.toUpperCase() === 'PACKLETS') { + if (pathPart !== 'packlets') { + // Example: /path/to/my-project/src/PACKLETS + const packletsFolderPath: string = Path.join(srcFolderPath, ...pathParts.slice(0, i + 1)); + this.error = { messageId: 'packlet-folder-case', data: { packletsFolderPath } }; + return; + } + + if (i !== 0) { + this.error = { messageId: 'misplaced-packlets-folder', data: { expectedPackletsFolder } }; + return; + } + + underPackletsFolder = true; + } + } + + if (underPackletsFolder || fs.existsSync(expectedPackletsFolder)) { + // packletsAbsolutePath + this.projectUsesPacklets = true; + this.packletsFolderPath = expectedPackletsFolder; + } + + if (underPackletsFolder) { + if (pathParts.length === 2) { + // Example: src/packlets/SomeFile.ts + this.error = { messageId: 'file-in-packets-folder' }; + return; + } + if (pathParts.length >= 2) { + // Example: 'my-packlet' + const packletName: string = pathParts[1]; + this.inputFilePackletName = packletName; + + if (pathParts.length === 3) { + // Example: 'index.ts' or 'index.tsx' + const thirdPart: string = pathParts[2]; + + // Example: 'index' + const thirdPartWithoutExtension: string = Path.parse(thirdPart).name; + + if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') { + if (!PackletAnalyzer._validPackletName.test(packletName)) { + this.error = { messageId: 'invalid-packlet-name', data: { packletName } }; + return; + } + + this.isEntryPoint = true; + } + } + } + } + + if (this.error === undefined && !this.projectUsesPacklets) { + this.nothingToDo = true; + } + } + + public static analyzeInputFile( + inputFilePath: string, + tsconfigFilePath: string | undefined + ): PackletAnalyzer { + return new PackletAnalyzer(inputFilePath, tsconfigFilePath); + } + + public analyzeImport(modulePath: string): IAnalyzerError | undefined { + if (!this.packletsFolderPath) { + // The caller should ensure this can never happen + throw new Error('Internal error: packletsFolderPath is not defined'); + } + + // Example: /path/to/my-project/src/packlets/my-packlet + const inputFileFolder: string = Path.dirname(this.inputFilePath); + + // Example: /path/to/my-project/src/other-packlet/index + const importedPath: string = Path.resolve(inputFileFolder, modulePath); + + // Is the imported path referring to a file under the src/packlets folder? + if (Path.isUnder(importedPath, this.packletsFolderPath)) { + // Example: other-packlet/index + const importedPathRelativeToPackletsFolder: string = Path.relative( + this.packletsFolderPath, + importedPath + ); + // Example: [ 'other-packlet', 'index' ] + const importedPathParts: string[] = importedPathRelativeToPackletsFolder.split(/[\/\\]+/); + if (importedPathParts.length > 0) { + // Example: 'other-packlet' + const importedPackletName: string = importedPathParts[0]; + + // We are importing from a packlet. Is the input file part of the same packlet? + if (this.inputFilePackletName && importedPackletName === this.inputFilePackletName) { + // Yes. Then our import must NOT use the packlet entry point. + + // Example: 'index' + // + // We discard the file extension to handle a degenerate case like: + // import { X } from "../index.js"; + const lastPart: string = Path.parse(importedPathParts[importedPathParts.length - 1]).name; + let pathToCompare: string; + if (lastPart.toUpperCase() === 'INDEX') { + // Example: + // importedPath = /path/to/my-project/src/other-packlet/index + // pathToCompare = /path/to/my-project/src/other-packlet + pathToCompare = Path.dirname(importedPath); + } else { + pathToCompare = importedPath; + } + + // Example: /path/to/my-project/src/other-packlet + const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName); + + if (Path.isEqual(pathToCompare, entryPointPath)) { + return { + messageId: 'circular-entry-point' + }; + } + } else { + // No. If we are not part of the same packlet, then the module path must refer + // to the index.ts entry point. + + // Example: /path/to/my-project/src/other-packlet + const entryPointPath: string = Path.join(this.packletsFolderPath, importedPackletName); + + if (!Path.isEqual(importedPath, entryPointPath)) { + // Example: "../packlets/other-packlet" + const entryPointModulePath: string = Path.convertToSlashes( + Path.relative(inputFileFolder, entryPointPath) + ); + + return { + messageId: 'bypassed-entry-point', + data: { entryPointModulePath } + }; + } + } + } + } else { + // The imported path does NOT refer to a file under the src/packlets folder + if (this.inputFilePackletName) { + return { + messageId: 'packlet-importing-project-file' + }; + } + } + + return undefined; + } +} diff --git a/eslint/eslint-plugin-packlets/src/Path.ts b/eslint/eslint-plugin-packlets/src/Path.ts new file mode 100644 index 00000000000..b49def2434d --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/Path.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 * as path from 'node:path'; +import * as fs from 'node:fs'; + +export type ParsedPath = path.ParsedPath; + +const RELATIVE_PATH_REGEXP: RegExp = /^[.\/\\]+$/; + +export class Path { + /** + * Whether the filesystem is assumed to be case sensitive for Path operations. + * + * @remarks + * Regardless of operating system, a given file system's paths may be case-sensitive or case-insensitive. + * If a volume is mounted under a subfolder, then different parts of a path can even have different + * case-sensitivity. The Node.js "path" API naively assumes that all Windows paths are case-insensitive, + * and that all other OS's are case-sensitive. This is way off, for example a modern MacBook has a + * case-insensitive filesystem by default. There isn't an easy workaround because Node.js does not expose + * the native OS APIs that would give accurate answers. + * + * The TypeScript compiler does somewhat better: it performs an empirical test of its own bundle path to see + * whether it can be read using different case. If so, it normalizes all paths to lowercase (sometimes with + * no API for retrieving the real path). This caused our Path.isUnder() to return incorrect answers because + * it relies on Node.js path.relative(). + * + * To solve that problem, Path.ts performs an empirical test similar to what the TypeScript compiler does, + * and then we adjust path.relative() to be case insensitive if appropriate. + * + * @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 relative(from: string, to: string): string { + if (!Path.usingCaseSensitive) { + return Path._relativeCaseInsensitive(from, to); + } + return path.relative(from, to); + } + + // -------------------------------------------------------------------------------------------------------- + // The operations below don't care about case sensitivity + + public static dirname(p: string): string { + return path.dirname(p); + } + + public static join(...paths: string[]): string { + return path.join(...paths); + } + + public static resolve(...pathSegments: string[]): string { + return path.resolve(...pathSegments); + } + + public static parse(pathString: string): ParsedPath { + return path.parse(pathString); + } + + // -------------------------------------------------------------------------------------------------------- + // The operations below are borrowed from @rushstack/node-core-library + + /** + * Returns true if "childPath" is located inside the "parentFolderPath" folder + * or one of its child folders. Note that "parentFolderPath" is not considered to be + * under itself. The "childPath" can refer to any type of file system object. + * + * @remarks + * The indicated file/folder objects are not required to actually exist on disk. + * For example, "parentFolderPath" is interpreted as a folder name even if it refers to a file. + * If the paths are relative, they will first be resolved using path.resolve(). + */ + public static isUnder(childPath: string, parentFolderPath: string): boolean { + const relativePath: string = Path.relative(childPath, parentFolderPath); + return RELATIVE_PATH_REGEXP.test(relativePath); + } + + /** + * Returns true if `path1` and `path2` refer to the same underlying path. + * + * @remarks + * + * The comparison is performed using `path.relative()`. + */ + public static isEqual(path1: string, path2: string): boolean { + return Path.relative(path1, path2) === ''; + } + + /** + * Replaces Windows-style backslashes with POSIX-style slashes. + * + * @remarks + * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. + */ + public static convertToSlashes(inputPath: string): string { + return inputPath.split('\\').join('/'); + } +} diff --git a/eslint/eslint-plugin-packlets/src/circular-deps.ts b/eslint/eslint-plugin-packlets/src/circular-deps.ts new file mode 100644 index 00000000000..e36b0546e2c --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/circular-deps.ts @@ -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. + +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, type IPackletImport } from './DependencyAnalyzer'; +import { Path } from './Path'; + +export type MessageIds = 'circular-import'; +type Options = []; + +const circularDeps: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { 'circular-import': 'Packlet imports create a circular reference:\n{{report}}' }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: 'Check for circular dependencies between packlets', + recommended: 'recommended', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + // Example: /path/to/my-project/src/packlets/my-packlet/index.ts + const inputFilePath: string = context.getFilename(); + + // Example: /path/to/my-project/tsconfig.json + const program: ts.Program = ESLintUtils.getParserServices(context).program; + const tsconfigFilePath: string | undefined = program.getCompilerOptions().configFilePath as string; + + const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile( + inputFilePath, + tsconfigFilePath + ); + if (packletAnalyzer.nothingToDo) { + return {}; + } + + return { + // Match the first node in the source file. Ideally we should be matching "Program > :first-child" + // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector: + // https://github.com/estools/esquery/issues/114 + Program: (node: TSESTree.Node): void => { + if (packletAnalyzer.isEntryPoint && !packletAnalyzer.error) { + const packletImports: IPackletImport[] | undefined = + DependencyAnalyzer.checkEntryPointForCircularImport( + packletAnalyzer.inputFilePackletName!, + packletAnalyzer, + program + ); + + if (packletImports) { + const tsconfigFileFolder: string = Path.dirname(tsconfigFilePath); + + const affectedPackletNames: string[] = packletImports.map((x) => x.packletName); + + // If 3 different packlets form a circular dependency, we don't need to report the same warning 3 times. + // Instead, only report the warning for the alphabetically smallest packlet. + affectedPackletNames.sort(); + if (affectedPackletNames[0] === packletAnalyzer.inputFilePackletName) { + let report: string = ''; + for (const packletImport of packletImports) { + const filePath: string = Path.relative(tsconfigFileFolder, packletImport.fromFilePath); + report += `"${packletImport.packletName}" is referenced by ${filePath}\n`; + } + + context.report({ + node: node, + messageId: 'circular-import', + data: { report: report } + }); + } + } + } + } + }; + } +}; + +export { circularDeps }; diff --git a/eslint/eslint-plugin-packlets/src/index.ts b/eslint/eslint-plugin-packlets/src/index.ts new file mode 100644 index 00000000000..7958fa842df --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/index.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 type { TSESLint } from '@typescript-eslint/utils'; + +import { mechanics } from './mechanics'; +import { circularDeps } from './circular-deps'; +import { readme } from './readme'; + +interface IPlugin { + rules: { [ruleName: string]: TSESLint.RuleModule }; + configs: { [ruleName: string]: unknown }; +} + +const plugin: IPlugin = { + rules: { + // Full name: "@rushstack/packlets/mechanics" + mechanics: mechanics, + // Full name: "@rushstack/packlets/circular-deps" + 'circular-deps': circularDeps, + readme: readme + }, + configs: { + recommended: { + plugins: ['@rushstack/eslint-plugin-packlets'], + rules: { + '@rushstack/packlets/mechanics': 'warn', + '@rushstack/packlets/circular-deps': 'warn', + '@rushstack/packlets/readme': 'off' + } + } + } +}; + +export = plugin; diff --git a/eslint/eslint-plugin-packlets/src/mechanics.ts b/eslint/eslint-plugin-packlets/src/mechanics.ts new file mode 100644 index 00000000000..1c299d88117 --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/mechanics.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'; + +import { + PackletAnalyzer, + type IAnalyzerError, + type InputFileMessageIds, + type ImportMessageIds +} from './PackletAnalyzer'; + +export type MessageIds = InputFileMessageIds | ImportMessageIds; +type Options = []; + +const mechanics: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + // InputFileMessageIds + 'file-in-packets-folder': 'The "packlets" folder must not contain regular source files', + 'invalid-packlet-name': + 'Invalid packlet name "{{packletName}}".' + + ' The name must be lowercase alphanumeric words separated by hyphens. Example: "my-packlet"', + 'misplaced-packlets-folder': 'The packlets folder must be located at "{{expectedPackletsFolder}}"', + 'missing-src-folder': 'Expecting to find a "src" folder at: {{srcFolderPath}}', + 'missing-tsconfig': + 'In order to use @rushstack/eslint-plugin-packlets, your ESLint config file' + + ' must configure the TypeScript parser', + 'packlet-folder-case': 'The packlets folder must be all lower case: {{packletsFolderPath}}', + + // ImportMessageIds + 'bypassed-entry-point': + 'The import statement does not use the packlet\'s entry point "{{entryPointModulePath}}"', + 'circular-entry-point': 'Files under a packlet folder must not import from their own index.ts file', + 'packlet-importing-project-file': + 'A local project file cannot be imported.' + + " A packlet's dependencies must be NPM packages and/or other packlets." + }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: 'Check that file paths and imports follow the basic mechanics for the packlet formalism', + recommended: 'recommended', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + // Example: /path/to/my-project/src/packlets/my-packlet/index.ts + const inputFilePath: string = context.getFilename(); + + // Example: /path/to/my-project/tsconfig.json + const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices( + context + ).program.getCompilerOptions().configFilePath as string; + + const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile( + inputFilePath, + tsconfigFilePath + ); + if (packletAnalyzer.nothingToDo) { + return {}; + } + + return { + // Match the first node in the source file. Ideally we should be matching "Program > :first-child" + // so a warning doesn't highlight the whole file. But that's blocked behind a bug in the query selector: + // https://github.com/estools/esquery/issues/114 + Program: (node: TSESTree.Node): void => { + if (packletAnalyzer.error) { + context.report({ + node: node, + messageId: packletAnalyzer.error.messageId, + data: packletAnalyzer.error.data + }); + } + }, + + // ImportDeclaration matches these forms: + // import { X } from '../../packlets/other-packlet'; + // import X from '../../packlets/other-packlet'; + // import type { X, Y } from '../../packlets/other-packlet'; + // import * as X from '../../packlets/other-packlet'; + // + // ExportNamedDeclaration matches these forms: + // export { X } from '../../packlets/other-packlet'; + // + // ExportAllDeclaration matches these forms: + // export * from '../../packlets/other-packlet'; + // export * as X from '../../packlets/other-packlet'; + // eslint-disable-next-line @typescript-eslint/naming-convention + 'ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration': ( + node: TSESTree.ImportDeclaration | TSESTree.ExportNamedDeclaration | TSESTree.ExportAllDeclaration + ): void => { + if (node.source?.type === AST_NODE_TYPES.Literal) { + if (packletAnalyzer.projectUsesPacklets) { + // Extract the import/export module path + // Example: "../../packlets/other-packlet" + const modulePath: string = node.source.value; + if (typeof modulePath !== 'string') { + return; + } + + if (!(modulePath.startsWith('.') || modulePath.startsWith('..'))) { + // It's not a local import. + + // Examples: + // import { X } from "npm-package"; + // import { X } from "raw-loader!./webpack-file.ts"; + return; + } + + const lint: IAnalyzerError | undefined = packletAnalyzer.analyzeImport(modulePath); + if (lint) { + context.report({ + node: node, + messageId: lint.messageId, + data: lint.data + }); + } + } + } + } + }; + } +}; + +export { mechanics }; diff --git a/eslint/eslint-plugin-packlets/src/readme.ts b/eslint/eslint-plugin-packlets/src/readme.ts new file mode 100644 index 00000000000..20ceb014c09 --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/readme.ts @@ -0,0 +1,113 @@ +// 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 type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { ESLintUtils } from '@typescript-eslint/utils'; + +import { PackletAnalyzer } from './PackletAnalyzer'; + +export type MessageIds = 'missing-readme' | 'error-reading-file' | 'readme-too-short'; +type Options = [ + { + minimumReadmeWords?: number; + } +]; + +const readme: TSESLint.RuleModule = { + defaultOptions: [{}], + meta: { + type: 'problem', + messages: { + 'missing-readme': + 'The ESLint configuration requires each packlet to provide a README.md file summarizing' + + ' its purpose and usage: {{readmePath}}', + 'readme-too-short': + 'The ESLint configuration requires at least {{minimumReadmeWords}} words of documentation in the' + + ' README.md file: {{readmePath}}', + 'error-reading-file': 'Error reading input file {{readmePath}}:\n{{errorMessage}}' + }, + schema: [ + { + type: 'object', + properties: { + minimumReadmeWords: { + type: 'number' + } + }, + additionalProperties: false + } + ], + + docs: { + description: 'Require each packlet folder to have a README.md file summarizing its purpose and usage', + // Too strict to be recommended in the default configuration + recommended: 'strict', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + const minimumReadmeWords: number = context.options[0]?.minimumReadmeWords || 10; + + // Example: /path/to/my-project/src/packlets/my-packlet/index.ts + const inputFilePath: string = context.getFilename(); + + // Example: /path/to/my-project/tsconfig.json + const tsconfigFilePath: string | undefined = ESLintUtils.getParserServices( + context + ).program.getCompilerOptions().configFilePath as string; + + const packletAnalyzer: PackletAnalyzer = PackletAnalyzer.analyzeInputFile( + inputFilePath, + tsconfigFilePath + ); + + if (!packletAnalyzer.nothingToDo && !packletAnalyzer.error) { + if (packletAnalyzer.isEntryPoint) { + return { + Program: (node: TSESTree.Node): void => { + const readmePath: string = path.join( + packletAnalyzer.packletsFolderPath!, + packletAnalyzer.inputFilePackletName!, + 'README.md' + ); + try { + if (!fs.existsSync(readmePath)) { + context.report({ + node: node, + messageId: 'missing-readme', + data: { readmePath } + }); + } else { + if (minimumReadmeWords > 0) { + const readmeContent: string = fs.readFileSync(readmePath).toString(); + const words: string[] = readmeContent.split(/[^a-z'"]+/i).filter((x) => x.length > 0); + if (words.length < minimumReadmeWords) { + context.report({ + node: node, + messageId: 'readme-too-short', + data: { readmePath, minimumReadmeWords } + }); + } + } + } + } catch (error) { + context.report({ + node: node, + messageId: 'error-reading-file', + data: { readmePath, errorMessage: (error as Error).toString() } + }); + } + } + }; + } + } + + return {}; + } +}; + +export { readme }; diff --git a/eslint/eslint-plugin-packlets/src/test/Path.test.ts b/eslint/eslint-plugin-packlets/src/test/Path.test.ts new file mode 100644 index 00000000000..57d75b1be1b --- /dev/null +++ b/eslint/eslint-plugin-packlets/src/test/Path.test.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 { Path } from '../Path'; + +function toPosixPath(value: string): string { + return value.replace(/[\\\/]/g, '/'); +} +function toNativePath(value: string): string { + return value.replace(/[\\\/]/g, path.sep); +} + +function relativeCaseInsensitive(from: string, to: string): string { + return toPosixPath(Path['_relativeCaseInsensitive'](toNativePath(from), toNativePath(to))); +} + +describe(Path.name, () => { + test('_detectCaseSensitive()', () => { + // NOTE: To ensure these tests are deterministic, only use absolute paths + expect(relativeCaseInsensitive('/', '/')).toEqual(''); + expect(relativeCaseInsensitive('/', '/a')).toEqual('a'); + expect(relativeCaseInsensitive('/', '/a/')).toEqual('a'); + expect(relativeCaseInsensitive('/', '/a//')).toEqual('a'); + expect(relativeCaseInsensitive('/', '/a/b')).toEqual('a/b'); + expect(relativeCaseInsensitive('/', '/a/b/c')).toEqual('a/b/c'); + expect(relativeCaseInsensitive('/A', '/a/b/c')).toEqual('b/c'); + expect(relativeCaseInsensitive('/A/', '/a/b/c')).toEqual('b/c'); + expect(relativeCaseInsensitive('/A/B', '/a/b/c')).toEqual('c'); + expect(relativeCaseInsensitive('/A/b/C', '/a/b/c')).toEqual(''); + expect(relativeCaseInsensitive('/a/B/c', '/a/b/c')).toEqual(''); + expect(relativeCaseInsensitive('/a/B/c/D', '/a/b/c')).toEqual('..'); + expect(relativeCaseInsensitive('/a/B/c/D', '/a/b/c/e')).toEqual('../e'); + }); +}); diff --git a/eslint/eslint-plugin-packlets/tsconfig.json b/eslint/eslint-plugin-packlets/tsconfig.json new file mode 100644 index 00000000000..e98df1ad324 --- /dev/null +++ b/eslint/eslint-plugin-packlets/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "module": "Node16" + } +} diff --git a/eslint/eslint-plugin-security/.npmignore b/eslint/eslint-plugin-security/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/eslint/eslint-plugin-security/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/eslint/eslint-plugin-security/CHANGELOG.json b/eslint/eslint-plugin-security/CHANGELOG.json new file mode 100644 index 00000000000..747f9361574 --- /dev/null +++ b/eslint/eslint-plugin-security/CHANGELOG.json @@ -0,0 +1,389 @@ +{ + "name": "@rushstack/eslint-plugin-security", + "entries": [ + { + "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", + "date": "Thu, 19 Sep 2024 00:11:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix ESLint broken links" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/eslint-plugin-security_v0.8.2", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.4`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/eslint-plugin-security_v0.8.1", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.3`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/eslint-plugin-security_v0.8.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3 with @typescript-eslint 6.19.x" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.2`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/eslint-plugin-security_v0.7.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.1`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/eslint-plugin-security_v0.7.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/eslint-plugin-security_v0.6.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the @typescript-eslint/* dependencies to ~5.59.2" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/eslint-plugin-security_v0.5.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "none": [ + { + "comment": "Update resolution for typescript-eslint/parser" + } + ], + "minor": [ + { + "comment": "Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/eslint-plugin-security_v0.4.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript dependency to 4.7" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/eslint-plugin-security_v0.3.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/eslint-plugin-security_v0.3.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.6" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/eslint-plugin-security_v0.2.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/eslint-plugin-security_v0.2.5", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the path in the package.json \"directory\" field." + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/eslint-plugin-security_v0.2.4", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for ESLint v8" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/eslint-plugin-security_v0.2.3", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/eslint-plugin-security_v0.2.2", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "patch": [ + { + "comment": "Update typescript-eslint to add support for TypeScript 4.4." + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/eslint-plugin-security_v0.2.1", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/eslint-plugin-security_v0.2.0", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/eslint-plugin-security_v0.1.4", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix unlisted dependency on @typescript-eslint/experimental-utils" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/eslint-plugin-security_v0.1.3", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/eslint-plugin-security_v0.1.2", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing \"License\" field." + }, + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/eslint-plugin-security_v0.1.1", + "date": "Sat, 19 Sep 2020 04:37:26 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing dependency" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/eslint-plugin-security_v0.1.0", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.1.0`" + } + ] + } + } + ] +} diff --git a/eslint/eslint-plugin-security/CHANGELOG.md b/eslint/eslint-plugin-security/CHANGELOG.md new file mode 100644 index 00000000000..89df9268f08 --- /dev/null +++ b/eslint/eslint-plugin-security/CHANGELOG.md @@ -0,0 +1,195 @@ +# Change Log - @rushstack/eslint-plugin-security + +This log was last generated on Mon, 13 Oct 2025 15:13:02 GMT and should not be manually modified. + +## 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 + +### Patches + +- Fix ESLint broken links + +## 0.8.2 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.8.1 +Sat, 17 Feb 2024 06:24:34 GMT + +_Version update only_ + +## 0.8.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 with @typescript-eslint 6.19.x + +## 0.7.1 +Tue, 26 Sep 2023 09:30:33 GMT + +_Version update only_ + +## 0.7.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.6.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the @typescript-eslint/* dependencies to ~5.59.2 + +## 0.5.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8 + +## 0.4.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript dependency to 4.7 + +## 0.3.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.3.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.6 + +## 0.2.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.2.5 +Tue, 15 Mar 2022 19:15:53 GMT + +### Patches + +- Fix the path in the package.json "directory" field. + +## 0.2.4 +Mon, 06 Dec 2021 16:08:32 GMT + +### Patches + +- Add support for ESLint v8 + +## 0.2.3 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.2.2 +Thu, 07 Oct 2021 07:13:35 GMT + +### Patches + +- Update typescript-eslint to add support for TypeScript 4.4. + +## 0.2.1 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.2.0 +Mon, 12 Jul 2021 23:08:26 GMT + +### Minor changes + +- Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389) + +## 0.1.4 +Tue, 06 Apr 2021 15:14:22 GMT + +### Patches + +- Fix unlisted dependency on @typescript-eslint/experimental-utils + +## 0.1.3 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 0.1.2 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Include missing "License" field. +- Update README.md + +## 0.1.1 +Sat, 19 Sep 2020 04:37:26 GMT + +### Patches + +- Add missing dependency + +## 0.1.0 +Sat, 19 Sep 2020 03:33:06 GMT + +### Minor changes + +- Initial release + diff --git a/eslint/eslint-plugin-security/LICENSE b/eslint/eslint-plugin-security/LICENSE new file mode 100644 index 00000000000..e6f863662cc --- /dev/null +++ b/eslint/eslint-plugin-security/LICENSE @@ -0,0 +1,24 @@ +@rushstack/eslint-plugin-security + +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/eslint/eslint-plugin-security/README.md b/eslint/eslint-plugin-security/README.md new file mode 100644 index 00000000000..861aafa4320 --- /dev/null +++ b/eslint/eslint-plugin-security/README.md @@ -0,0 +1,72 @@ +# @rushstack/eslint-plugin-security + +This plugin implements a collection of security rules for ESLint. + +Our ambition is to eventually provide a comprehensive set of recommended security rules for: +- web browser applications +- Node.js tools +- Node.js services + +If you would like to request or contribute a new security rule, you are encouraged to +[create a GitHub issue](https://github.com/microsoft/rushstack/issues) in the +[Rush Stack](https://rushstack.io/) monorepo where this project is developed. +Thanks! + +## `@rushstack/security/no-unsafe-regexp` + +Require regular expressions to be constructed from string constants rather than dynamically +building strings at runtime. + +#### Rule Details + +Regular expressions should be constructed from string constants. Dynamically building strings at runtime may +introduce security vulnerabilities, performance concerns, and bugs involving incorrect escaping of special characters. + +#### Examples + +The following patterns are considered problems when `@rushstack/security/no-unsafe-regexp` is enabled: + +```ts +function parseRestResponse(request: ICatalogRequest, + items: ICatalogItem[]): ICatalogItem[] { + + // Security vulnerability: A malicious user could invoke the REST service using a + // "searchPattern" with a complex RegExp that causes a denial of service. + const regexp: RegExp = new RegExp(request.searchPattern); + return items.filter(item => regexp.test(item.title)); +} +``` + +```ts +function hasExtension(filePath: string, extension: string): boolean { + // Escaping mistake: If the "extension" string contains a special character such as ".", + // it will be interpreted as a regular expression operator. Correctly escaping an arbitrary + // string is a nontrivial problem due to RegExp implementation differences, as well as contextual + // issues (since which characters are special changes inside RegExp nesting constructs). + // In most cases, this problem is better solved without regular expressions. + const regexp: RegExp = new RegExp(`\.${extension}$`); + return regexp.test(filePath); +} +``` + +The following patterns are NOT considered problems: + +```ts +function isInteger(s: string): boolean { + return /[0-9]+/.test(s); +} +``` + +```ts +function isInteger(s: string): boolean { + return new RegExp('[0-9]+').test(s); +} +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/eslint/eslint-plugin-security/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/eslint-plugin-security` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/eslint/eslint-plugin-security/config/jest.config.json b/eslint/eslint-plugin-security/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/eslint/eslint-plugin-security/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/eslint/eslint-plugin-security/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/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 new file mode 100644 index 00000000000..f3baef08e9e --- /dev/null +++ b/eslint/eslint-plugin-security/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/eslint-plugin-security", + "version": "0.13.0", + "description": "An ESLint plugin providing rules that identify common security vulnerabilities for browser applications, Node.js tools, and Node.js services", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-plugin-security" + }, + "homepage": "https://rushstack.io", + "keywords": [ + "eslint", + "eslint-config", + "security" + ], + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/tree-pattern": "workspace:*", + "@typescript-eslint/utils": "~8.46.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@typescript-eslint/parser": "~8.46.0", + "@typescript-eslint/rule-tester": "~8.46.0", + "@typescript-eslint/typescript-estree": "~8.46.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + } +} diff --git a/eslint/eslint-plugin-security/src/index.ts b/eslint/eslint-plugin-security/src/index.ts new file mode 100644 index 00000000000..8e2d433001c --- /dev/null +++ b/eslint/eslint-plugin-security/src/index.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint } from '@typescript-eslint/utils'; + +import { noUnsafeRegExp } from './no-unsafe-regexp'; + +interface IPlugin { + rules: { [ruleName: string]: TSESLint.RuleModule }; +} + +const plugin: IPlugin = { + rules: { + // Full name: "@rushstack/security/no-unsafe-regexp" + 'no-unsafe-regexp': noUnsafeRegExp + } +}; + +export = plugin; diff --git a/eslint/eslint-plugin-security/src/no-unsafe-regexp.ts b/eslint/eslint-plugin-security/src/no-unsafe-regexp.ts new file mode 100644 index 00000000000..999d04c636b --- /dev/null +++ b/eslint/eslint-plugin-security/src/no-unsafe-regexp.ts @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +import { TreePattern } from '@rushstack/tree-pattern'; + +// Matches an expression like this: +// new RegExp('hello'); +// +// Tree: +// { +// "type": "NewExpression", +// "callee": { +// "type": "Identifier", +// "name": "RegExp" +// }, +// "arguments": [ +// { +// "type": "Literal", +// "raw": "'\"hello\"'", +// "value": "\"hello\"" +// } +// ] +// } +const newRegExpPattern: TreePattern = new TreePattern({ + type: 'NewExpression', + callee: { + type: 'Identifier', + name: 'RegExp' + }, + arguments: TreePattern.tag('constructorArgs') +}); + +interface INewRegExpPatternCaptures { + constructorArgs?: TSESTree.Expression[]; +} + +type MessageIds = 'error-unsafe-regexp'; +type Options = []; + +const noUnsafeRegExp: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + 'error-unsafe-regexp': + 'Regular expressions should be constructed from string constants. Dynamically building strings' + + ' at runtime may introduce security vulnerabilities, performance concerns, and bugs involving' + + ' incorrect escaping of special characters.' + }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: + 'Requires regular expressions to be constructed from string constants rather than dynamically' + + ' building strings at runtime.', + recommended: 'strict', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin-security' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + return { + NewExpression: (node: TSESTree.NewExpression): void => { + const captures: INewRegExpPatternCaptures = {}; + if (newRegExpPattern.match(node, captures) && captures.constructorArgs) { + if ( + captures.constructorArgs.length > 0 && + captures.constructorArgs[0].type !== AST_NODE_TYPES.Literal + ) { + context.report({ + node, + messageId: 'error-unsafe-regexp' + }); + } + } + } + }; + } +}; + +export { noUnsafeRegExp }; diff --git a/eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts b/eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts new file mode 100644 index 00000000000..d321eb03619 --- /dev/null +++ b/eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts @@ -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 parser from '@typescript-eslint/parser'; +import { RuleTester } from '@typescript-eslint/rule-tester'; +import { noUnsafeRegExp } from '../no-unsafe-regexp'; + +const ruleTester = new RuleTester({ languageOptions: { parser } }); +ruleTester.run('no-unsafe-regexp', noUnsafeRegExp, { + invalid: [ + { + // prettier-ignore + code: [ + 'function f(s: string) {', + ' const r1 = new RegExp(s);', + '}' + ].join('\n'), + errors: [{ messageId: 'error-unsafe-regexp' }] + } + ], + valid: [ + { + code: 'const r1 = new RegExp(".*");' + } + ] +}); diff --git a/eslint/eslint-plugin-security/tsconfig.json b/eslint/eslint-plugin-security/tsconfig.json new file mode 100644 index 00000000000..e98df1ad324 --- /dev/null +++ b/eslint/eslint-plugin-security/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "module": "Node16" + } +} diff --git a/eslint/eslint-plugin/.npmignore b/eslint/eslint-plugin/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/eslint/eslint-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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/eslint/eslint-plugin/CHANGELOG.json b/eslint/eslint-plugin/CHANGELOG.json new file mode 100644 index 00000000000..a83857f584e --- /dev/null +++ b/eslint/eslint-plugin/CHANGELOG.json @@ -0,0 +1,606 @@ +{ + "name": "@rushstack/eslint-plugin", + "entries": [ + { + "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", + "date": "Thu, 19 Sep 2024 00:11:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix ESLint broken links" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/eslint-plugin_v0.16.0", + "date": "Wed, 14 Aug 2024 22:37:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add 4 new ESLint rules: \"@rushstack/no-backslash-imports\", used to prevent backslashes in import and require statements; \"@rushstack/no-external-local-imports\", used to prevent referencing external depedencies in import and require statements; \"@rushstack/no-transitive-dependency-imports\", used to prevent referencing transitive dependencies (ie. dependencies of dependencies) in import and require statements; and \"@rushstack/normalized-imports\", used to ensure that the most direct path to a dependency is provided in import and require statements" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/eslint-plugin_v0.15.2", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.4`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/eslint-plugin_v0.15.1", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.3`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/eslint-plugin_v0.15.0", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "minor": [ + { + "comment": "Allow using `as const` in `typedef-var`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/eslint-plugin_v0.14.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3 with @typescript-eslint 6.19.x" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.2`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/eslint-plugin_v0.13.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.1`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/eslint-plugin_v0.13.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/eslint-plugin_v0.12.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the @typescript-eslint/* dependencies to ~5.59.2" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/eslint-plugin_v0.11.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "none": [ + { + "comment": "Update resolution for typescript-eslint/parser" + } + ], + "minor": [ + { + "comment": "Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/eslint-plugin_v0.10.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript dependency to 4.7" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/eslint-plugin_v0.9.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/eslint-plugin_v0.9.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 4.6" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/eslint-plugin_v0.8.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/eslint-plugin_v0.8.5", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the path in the package.json \"directory\" field." + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/eslint-plugin_v0.8.4", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for ESLint v8" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/eslint-plugin_v0.8.3", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/eslint-plugin_v0.8.2", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "patch": [ + { + "comment": "Update typescript-eslint to add support for TypeScript 4.4." + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/eslint-plugin_v0.8.1", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/eslint-plugin_v0.8.0", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389)" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/eslint-plugin_v0.7.3", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix unlisted dependency on @typescript-eslint/experimental-utils" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/eslint-plugin_v0.7.2", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/eslint-plugin_v0.7.1", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing \"License\" field." + }, + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/eslint-plugin_v0.7.0", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new rule \"@rushstack/typedef-var\" which supplements \"@typescript-eslint/typedef\" by enabling a special policy for local variables" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/eslint-plugin_v0.6.3", + "date": "Sat, 19 Sep 2020 04:37:26 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing dependency" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/eslint-plugin_v0.6.2", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "patch": [ + { + "comment": "Extract the pattern matcher into the new \"@rushstack/tree-pattern\" package" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/eslint-plugin_v0.6.1", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "patch": [ + { + "comment": "Revise the \"@rushstack/hoist-jest-mock\" rule to allow some common Jest coding practices that are not problematic" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/eslint-plugin_v0.6.0", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "minor": [ + { + "comment": "Add new rule @rushstack/hoist-jest-mock" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/eslint-plugin_v0.5.0", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new rule \"@rushstack/no-new-null\" that will replace \"@rushstack/no-null\"" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/eslint-plugin_v0.4.2", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/eslint-plugin_v0.4.1", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the published file set" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/eslint-plugin_v0.4.0", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to ESLint 7" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/eslint-plugin_v0.3.2", + "date": "Wed, 18 Mar 2020 15:07:47 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade cyclic dependencies" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/eslint-plugin_v0.3.1", + "date": "Sun, 19 Jan 2020 02:26:53 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade Node typings to Node 10" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/eslint-plugin_v0.3.0", + "date": "Fri, 17 Jan 2020 01:08:23 GMT", + "comments": { + "minor": [ + { + "comment": "Allow null in == and != conditionals for no-null eslint rule" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/eslint-plugin_v0.2.0", + "date": "Thu, 09 Jan 2020 06:44:12 GMT", + "comments": { + "minor": [ + { + "comment": "Add new rule `@rushstack/no-untyped-underscore`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/eslint-plugin_v0.1.0", + "date": "Wed, 08 Jan 2020 00:11:31 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/eslint/eslint-plugin/CHANGELOG.md b/eslint/eslint-plugin/CHANGELOG.md new file mode 100644 index 00000000000..80611aa8eaf --- /dev/null +++ b/eslint/eslint-plugin/CHANGELOG.md @@ -0,0 +1,321 @@ +# Change Log - @rushstack/eslint-plugin + +This log was last generated on Tue, 11 Nov 2025 16:13:26 GMT and should not be manually modified. + +## 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 + +### Patches + +- Fix ESLint broken links + +## 0.16.0 +Wed, 14 Aug 2024 22:37:32 GMT + +### Minor changes + +- Add 4 new ESLint rules: "@rushstack/no-backslash-imports", used to prevent backslashes in import and require statements; "@rushstack/no-external-local-imports", used to prevent referencing external depedencies in import and require statements; "@rushstack/no-transitive-dependency-imports", used to prevent referencing transitive dependencies (ie. dependencies of dependencies) in import and require statements; and "@rushstack/normalized-imports", used to ensure that the most direct path to a dependency is provided in import and require statements + +## 0.15.2 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.15.1 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.15.0 +Wed, 07 Feb 2024 01:11:18 GMT + +### Minor changes + +- Allow using `as const` in `typedef-var` + +## 0.14.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 with @typescript-eslint 6.19.x + +## 0.13.1 +Tue, 26 Sep 2023 09:30:33 GMT + +_Version update only_ + +## 0.13.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.12.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the @typescript-eslint/* dependencies to ~5.59.2 + +## 0.11.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgraded @typescript-eslint dependencies to 5.30.x to enable support for TypeScript 4.8 + +## 0.10.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript dependency to 4.7 + +## 0.9.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.9.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Add support for TypeScript 4.6 + +## 0.8.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.8.5 +Tue, 15 Mar 2022 19:15:53 GMT + +### Patches + +- Fix the path in the package.json "directory" field. + +## 0.8.4 +Mon, 06 Dec 2021 16:08:32 GMT + +### Patches + +- Add support for ESLint v8 + +## 0.8.3 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.8.2 +Thu, 07 Oct 2021 07:13:35 GMT + +### Patches + +- Update typescript-eslint to add support for TypeScript 4.4. + +## 0.8.1 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.8.0 +Mon, 12 Jul 2021 23:08:26 GMT + +### Minor changes + +- Upgrade @typescript-eslint/* packages to 4.28.0 (GitHub #2389) + +## 0.7.3 +Tue, 06 Apr 2021 15:14:22 GMT + +### Patches + +- Fix unlisted dependency on @typescript-eslint/experimental-utils + +## 0.7.2 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 0.7.1 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Include missing "License" field. +- Update README.md + +## 0.7.0 +Tue, 22 Sep 2020 01:45:31 GMT + +### Minor changes + +- Add a new rule "@rushstack/typedef-var" which supplements "@typescript-eslint/typedef" by enabling a special policy for local variables + +## 0.6.3 +Sat, 19 Sep 2020 04:37:26 GMT + +### Patches + +- Add missing dependency + +## 0.6.2 +Sat, 19 Sep 2020 03:33:06 GMT + +### Patches + +- Extract the pattern matcher into the new "@rushstack/tree-pattern" package + +## 0.6.1 +Thu, 27 Aug 2020 11:27:06 GMT + +### Patches + +- Revise the "@rushstack/hoist-jest-mock" rule to allow some common Jest coding practices that are not problematic + +## 0.6.0 +Mon, 24 Aug 2020 07:35:20 GMT + +### Minor changes + +- Add new rule @rushstack/hoist-jest-mock + +## 0.5.0 +Sat, 22 Aug 2020 05:55:42 GMT + +### Minor changes + +- Add a new rule "@rushstack/no-new-null" that will replace "@rushstack/no-null" + +## 0.4.2 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 0.4.1 +Wed, 24 Jun 2020 09:50:48 GMT + +### Patches + +- Fix an issue with the published file set + +## 0.4.0 +Wed, 24 Jun 2020 09:04:28 GMT + +### Minor changes + +- Upgrade to ESLint 7 + +## 0.3.2 +Wed, 18 Mar 2020 15:07:47 GMT + +### Patches + +- Upgrade cyclic dependencies + +## 0.3.1 +Sun, 19 Jan 2020 02:26:53 GMT + +### Patches + +- Upgrade Node typings to Node 10 + +## 0.3.0 +Fri, 17 Jan 2020 01:08:23 GMT + +### Minor changes + +- Allow null in == and != conditionals for no-null eslint rule + +## 0.2.0 +Thu, 09 Jan 2020 06:44:12 GMT + +### Minor changes + +- Add new rule `@rushstack/no-untyped-underscore` + +## 0.1.0 +Wed, 08 Jan 2020 00:11:31 GMT + +### Minor changes + +- Initial release + diff --git a/stack/eslint-plugin/LICENSE b/eslint/eslint-plugin/LICENSE similarity index 100% rename from stack/eslint-plugin/LICENSE rename to eslint/eslint-plugin/LICENSE diff --git a/eslint/eslint-plugin/README.md b/eslint/eslint-plugin/README.md new file mode 100644 index 00000000000..037045492d7 --- /dev/null +++ b/eslint/eslint-plugin/README.md @@ -0,0 +1,625 @@ +# @rushstack/eslint-plugin + +This plugin implements supplementary rules for use with the `@rushstack/eslint-config` package, +which provides a TypeScript ESLint ruleset tailored for large teams and projects. +Please see [that project's documentation](https://www.npmjs.com/package/@rushstack/eslint-config) +for details. To learn about Rush Stack, please visit: [https://rushstack.io/](https://rushstack.io/) + +## `@rushstack/hoist-jest-mock` + +Require Jest module mocking APIs to be called before any other statements in their code block. + +#### Rule Details + +Jest module mocking APIs such as "jest.mock()" must be called before the associated module is imported, otherwise +they will have no effect. Transpilers such as `ts-jest` and `babel-jest` automatically "hoist" these calls, however +this can produce counterintuitive behavior. Instead, the `hoist-jest-mocks` lint rule simply requires developers +to write the statements in the correct order. + +The following APIs are affected: 'jest.mock()', 'jest.unmock()', 'jest.enableAutomock()', 'jest.disableAutomock()', +'jest.deepUnmock()'. + +For technical background, please read the Jest documentation here: https://jestjs.io/docs/en/es6-class-mocks + +#### Examples + +The following patterns are considered problems when `@rushstack/hoist-jest-mock` is enabled: + +```ts +import * as file from './file'; // import statement +jest.mock('./file'); // error + +test("example", () => { + jest.mock('./file2'); // error +}); +``` + +```ts +require('./file'); // import statement +jest.mock('./file'); // error +``` + +The following patterns are NOT considered problems: + +```ts +jest.mock('./file'); // okay, because mock() precedes the import below +import * as file from './file'; // import statement +``` + +```ts +// These statements are not real "imports" because they import compile-time types +// without any runtime effects +import type { X } from './file'; +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 +may require `null`. + +#### Rule Details + +Most programming languages have a "null" or "nil" value that serves several purposes: + +1. the initial value for an uninitialized variable +2. the value of `x.y` or `x["y"]` when `x` has no such key, and +3. a special token that developers can assign to indicate an unknown or empty state. + +In JavaScript, the `undefined` value fulfills all three roles. JavaScript's `null` value is a redundant secondary +token that only fulfills (3), even though its name confusingly implies otherwise. The `null` value was arguably +a mistake in the original JavaScript language design, but it cannot be banned entirely because it is returned +by some entrenched system APIs such as `JSON.parse()`, and also some popular NPM packages. Thus, this rule aims +to tolerate preexisting `null` values while preventing new ones from being introduced. + +The `@rushstack/no-new-null` rule flags type definitions with `null` that can be exported or used by others. +The rule ignores declarations that are local variables, private members, or types that are not exported. + +If you are designing a new JSON file format, it's a good idea to avoid `null` entirely. In most cases +there are better representations that convey more information about an item that is unknown, omitted, +or disabled. If you do need to declare types for JSON structures containing `null`, rather than +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: + +```ts +// interface declaration with null field +interface IHello { hello: null; } // error + +// type declaration with null field +type Hello = { hello: null; } // error + +// type function alias +type T = (args: string | null) => void; // error + +// type alias +type N = null; // error + +// type constructor +type C = {new (args: string | null)} // error + +// function declaration with null args +function hello(world: string | null): void {}; // error +function legacy(callback: (err: Error| null) => void): void { }; // error + +// function with null return type +function hello(): (err: Error | null) => void {}; // error + +// const with null type +const nullType: 'hello' | null = 'hello'; // error + +// classes with publicly visible properties and methods +class PublicNulls { + property: string | null; // error + propertyFunc: (val: string | null) => void; // error + legacyImplicitPublic(hello: string | null): void {} // error + public legacyExplicitPublic(hello: string | null): void {} // error +} +``` + +The following patterns are NOT considered problems: + +```ts +// wrapping an null-API +export function ok(hello: string): void { + const innerCallback: (err: Error | null) => void = (e) => {}; // passes + return innerCallback(null); +} + +// classes where null APIs are used, but are private-only +class PrivateNulls { + private pField: string | null; // passes + private pFunc: (val: string | null) => void; // passes + private legacyPrivate(hello: string | null): void { // passes + this.pField = hello; + this.pFunc(this.pField) + this.pFunc('hello') + } +} +``` + +## `@rushstack/no-null` + +(Deprecated) Prevent usage of JavaScript's `null` keyword. + +#### Rule Details + +This rule has been superseded by `@rushstack/no-new-null`, and is maintained to support code that has not +migrated to the new rule yet. The `@rushstack/no-null` rule prohibits `null` as a literal value, but allows +it in type annotations. Comparisons with `null` are also allowed. + +#### Examples + +The following patterns are considered problems when `@rushstack/no-null` is enabled: + +```ts +let x = null; // error + +f(null); // error + +function g() { + return null; // error +} +``` + +The following patterns are NOT considered problems: + +```ts +let x: number | null = f(); // declaring types as possibly "null" is okay + +if (x === null) { // comparisons are okay + x = 0; +} +``` + +## `@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. + +#### Rule Details + +JavaScript does not provide a straightforward way to restrict access to object members, so API names commonly +indicate a private member by using an underscore prefix (e.g. `exampleObject._privateMember`). For inexperienced +developers who may be unfamiliar with this convention, in TypeScript we can mark the APIs as `private` or omit them +from the typings. However, when migrating a large code base to TypeScript, it may be difficult to declare types +for every legacy API. In this situation, the `@rushstack/no-untyped-underscore` rule can help. + +This rule detects expressions that access a member with an underscore prefix, EXCEPT in cases where: + +- The object is typed: specifically, `exampleObject` has a TypeScript type that declares `_privateMember`; OR +- The object expression uses: the `this` or `super` keywords; OR +- The object expression is a variable named `that`. (In older ES5 code, `that` was commonly used as an alias + for `this` in unbound contexts.) + +#### Examples + +The following patterns are considered problems when `@rushstack/no-untyped-underscore` is enabled: + +```ts +let x: any; +x._privateMember = 123; // error, because x is untyped + +let x: { [key: string]: number }; +x._privateMember = 123; // error, because _privateMember is not a declared member of x's type +``` + +The following patterns are NOT considered problems: + +```ts +let x: { _privateMember: any }; +x._privateMember = 123; // okay, because _privateMember is declared by x's type + +let x = { _privateMember: 0 }; +x._privateMember = 123; // okay, because _privateMember is part of the inferred type + +enum E { + _PrivateMember +} +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 + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/eslint/eslint-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/eslint-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/eslint/eslint-plugin/config/jest.config.json b/eslint/eslint-plugin/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/eslint/eslint-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/eslint/eslint-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": "decoupled-local-node-rig" +} 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 new file mode 100644 index 00000000000..9d05d451743 --- /dev/null +++ b/eslint/eslint-plugin/package.json @@ -0,0 +1,44 @@ +{ + "name": "@rushstack/eslint-plugin", + "version": "0.22.1", + "description": "An ESLint plugin providing supplementary rules for use with the @rushstack/eslint-config package", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "eslint/eslint-plugin" + }, + "homepage": "https://rushstack.io", + "keywords": [ + "eslint", + "eslint-config", + "monorepo", + "rush", + "scalable", + "scale", + "typescript" + ], + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/tree-pattern": "workspace:*", + "@typescript-eslint/utils": "~8.46.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@typescript-eslint/parser": "~8.46.0", + "@typescript-eslint/rule-tester": "~8.46.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2", + "@typescript-eslint/types": "~8.46.0" + } +} diff --git a/eslint/eslint-plugin/src/LintUtilities.ts b/eslint/eslint-plugin/src/LintUtilities.ts new file mode 100644 index 00000000000..fb610ba7a99 --- /dev/null +++ b/eslint/eslint-plugin/src/LintUtilities.ts @@ -0,0 +1,137 @@ +// 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 { ESLintUtils, TSESTree, type TSESLint } from '@typescript-eslint/utils'; +import type { CompilerOptions, Program } from 'typescript'; + +export interface IParsedImportSpecifier { + loader?: string; + importTarget: string; + loaderOptions?: string; +} + +// Regex to parse out the import target from the specifier. Expected formats are: +// - '' +// - '!' +// - '?' +// - '!?' +const LOADER_CAPTURE_GROUP: 'loader' = 'loader'; +const IMPORT_TARGET_CAPTURE_GROUP: 'importTarget' = 'importTarget'; +const LOADER_OPTIONS_CAPTURE_GROUP: 'loaderOptions' = 'loaderOptions'; +const SPECIFIER_REGEX: RegExp = new RegExp( + `^((?<${LOADER_CAPTURE_GROUP}>(!|-!|!!).+)!)?` + + `(?<${IMPORT_TARGET_CAPTURE_GROUP}>[^!?]+)` + + `(\\?(?<${LOADER_OPTIONS_CAPTURE_GROUP}>.*))?$` +); + +export function getFilePathFromContext(context: TSESLint.RuleContext): string { + return context.physicalFilename || context.filename; +} + +export function getRootDirectoryFromContext( + context: TSESLint.RuleContext +): 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 { + const program: Program | null | undefined = ( + context.sourceCode?.parserServices ?? ESLintUtils.getParserServices(context) + ).program; + 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 + } + + // Last resort: use ESLint's current working directory + return context.getCwd?.(); +} + +export function parseImportSpecifierFromExpression( + importExpression: TSESTree.Expression +): IParsedImportSpecifier | undefined { + if ( + !importExpression || + importExpression.type !== TSESTree.AST_NODE_TYPES.Literal || + typeof importExpression.value !== 'string' + ) { + // Can't determine the path of the import target, return + return undefined; + } + + // Extract the target of the import, stripping out webpack loaders and query strings. The regex will + // also ensure that the import target is a relative path. + const specifierMatch: RegExpMatchArray | null = importExpression.value.match(SPECIFIER_REGEX); + if (!specifierMatch?.groups) { + // Can't determine the path of the import target, return + return undefined; + } + + const loader: string | undefined = specifierMatch.groups[LOADER_CAPTURE_GROUP]; + const importTarget: string = specifierMatch.groups[IMPORT_TARGET_CAPTURE_GROUP]; + const loaderOptions: string | undefined = specifierMatch.groups[LOADER_OPTIONS_CAPTURE_GROUP]; + return { loader, importTarget, loaderOptions }; +} + +export function serializeImportSpecifier(parsedImportPath: IParsedImportSpecifier): string { + const { loader, importTarget, loaderOptions } = parsedImportPath; + return `${loader ? `${loader}!` : ''}${importTarget}${loaderOptions ? `?${loaderOptions}` : ''}`; +} + +export function getImportPathFromExpression( + importExpression: TSESTree.Expression, + relativeImportsOnly: boolean = true +): string | undefined { + const parsedImportSpecifier: IParsedImportSpecifier | undefined = + parseImportSpecifierFromExpression(importExpression); + if ( + !parsedImportSpecifier || + (relativeImportsOnly && !parsedImportSpecifier.importTarget.startsWith('.')) + ) { + // The import target isn't a path, return + return undefined; + } + return parsedImportSpecifier?.importTarget; +} + +export function getImportAbsolutePathFromExpression( + context: TSESLint.RuleContext, + importExpression: TSESTree.Expression, + relativeImportsOnly: boolean = true +): string | undefined { + const importPath: string | undefined = getImportPathFromExpression(importExpression, relativeImportsOnly); + if (importPath === undefined) { + // Can't determine the absolute path of the import target, return + return undefined; + } + + const filePath: string = getFilePathFromContext(context); + const fileDirectory: string = path.dirname(filePath); + + // Combine the import path with the absolute path of the file parent directory to get the + // absolute path of the import target + return path.resolve(fileDirectory, importPath); +} diff --git a/eslint/eslint-plugin/src/hoist-jest-mock.ts b/eslint/eslint-plugin/src/hoist-jest-mock.ts new file mode 100644 index 00000000000..4178cab0d13 --- /dev/null +++ b/eslint/eslint-plugin/src/hoist-jest-mock.ts @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +import * as hoistJestMockPatterns from './hoistJestMockPatterns'; + +type MessageIds = 'error-unhoisted-jest-mock'; +type Options = []; + +// Jest APIs that need to be hoisted +// Based on HOIST_METHODS from ts-jest +const HOIST_METHODS: string[] = ['mock', 'unmock', 'enableAutomock', 'disableAutomock', 'deepUnmock']; + +const hoistJestMock: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + 'error-unhoisted-jest-mock': + "Jest's module mocking APIs must be called before regular imports. Move this call so that it precedes" + + ' the import found on line {{importLine}}.' + }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: + 'Require Jest module mocking APIs to be called before other modules are imported.' + + ' Jest module mocking APIs such as "jest.mock(\'./example\')" must be called before the associated module' + + ' is imported, otherwise they will have no effect. Transpilers such as ts-jest and babel-jest automatically' + + ' "hoist" these calls, however this can produce counterintuitive results. Instead, the hoist-jest-mocks' + + ' lint rule requires developers to manually hoist these calls. For technical background, please read the' + + ' Jest documentation here: https://jestjs.io/docs/en/es6-class-mocks', + recommended: 'recommended', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + // Returns true for a statement such as "jest.mock()" that needs to precede + // module imports (i.e. be "hoisted"). + function isHoistableJestCall(node: TSESTree.Node | undefined): boolean { + if (node === undefined) { + return false; + } + + const captures: hoistJestMockPatterns.IJestCallExpression = {}; + + if (hoistJestMockPatterns.jestCallExpression.match(node, captures)) { + if (captures.methodName && HOIST_METHODS.indexOf(captures.methodName) >= 0) { + return true; + } + } + + // Recurse into some common expression-combining syntaxes + switch (node.type) { + case AST_NODE_TYPES.CallExpression: + return isHoistableJestCall(node.callee); + case AST_NODE_TYPES.MemberExpression: + return isHoistableJestCall(node.object); + case AST_NODE_TYPES.LogicalExpression: + return isHoistableJestCall(node.left) || isHoistableJestCall(node.right); + } + + return false; + } + + // Given part of an expression, walk upwards in the tree and find the containing statement + function findOuterStatement(node: TSESTree.Node): TSESTree.Node { + let current: TSESTree.Node | undefined = node; + while (current.parent) { + switch (current.parent.type) { + // Statements are always found inside a block: + case AST_NODE_TYPES.Program: + case AST_NODE_TYPES.BlockStatement: + case AST_NODE_TYPES.TSModuleBlock: + return current; + } + current = current.parent; + } + return node; + } + + // This tracks the first require() or import expression that we found in the file. + let firstImportNode: TSESTree.Node | undefined = undefined; + + // Avoid reporting more than one error for a given statement. + // Example: jest.mock('a').mock('b'); + const reportedStatements: Set = new Set(); + + return { + CallExpression: (node: TSESTree.CallExpression): void => { + if (firstImportNode === undefined) { + // EXAMPLE: const x = require('x') + if (hoistJestMockPatterns.requireCallExpression.match(node)) { + firstImportNode = node; + } + } + + if (firstImportNode) { + // EXAMPLE: jest.mock() + if (isHoistableJestCall(node)) { + const outerStatement: TSESTree.Node = findOuterStatement(node); + if (!reportedStatements.has(outerStatement)) { + reportedStatements.add(outerStatement); + context.report({ + node, + messageId: 'error-unhoisted-jest-mock', + data: { importLine: firstImportNode.loc.start.line } + }); + } + } + } + }, + + ImportExpression: (node: TSESTree.ImportExpression): void => { + if (firstImportNode === undefined) { + // EXAMPLE: const x = import('x'); + if (hoistJestMockPatterns.importExpression.match(node)) { + firstImportNode = node; + } + } + }, + + ImportDeclaration: (node: TSESTree.ImportDeclaration): void => { + if (firstImportNode === undefined) { + // EXAMPLE: import { X } from "Y"; + // IGNORE: import type { X } from "Y"; + if (node.importKind !== 'type') { + firstImportNode = node; + } + } + }, + + ExportDeclaration: (node: TSESTree.ExportDeclaration): void => { + if (firstImportNode === undefined) { + // EXAMPLE: export * from "Y"; + // IGNORE: export type { Y } from "Y"; + if ((node as unknown as TSESTree.ExportNamedDeclaration).exportKind !== 'type') { + firstImportNode = node; + } + } + }, + + TSImportEqualsDeclaration: (node: TSESTree.TSImportEqualsDeclaration): void => { + if (firstImportNode === undefined) { + // EXAMPLE: import x = require("x"); + firstImportNode = node; + } + } + }; + } +}; + +export { hoistJestMock }; diff --git a/eslint/eslint-plugin/src/hoistJestMockPatterns.ts b/eslint/eslint-plugin/src/hoistJestMockPatterns.ts new file mode 100644 index 00000000000..41b41f03335 --- /dev/null +++ b/eslint/eslint-plugin/src/hoistJestMockPatterns.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 { TreePattern } from '@rushstack/tree-pattern'; + +export interface IJestCallExpression { + // Example: "mock" from "jest.mock('./thing')" + methodName?: string; +} + +// Matches a statement expression like this: +// jest.mock('./thing') +// +// Tree: +// { +// type: 'CallExpression', +// callee: { +// type: 'MemberExpression', +// object: { +// type: 'Identifier', +// name: 'jest' +// }, +// property: { +// type: 'Identifier', +// name: 'mock' +// } +// }, +// arguments: [ +// { +// type: 'Literal', +// value: './thing' +// } +// ] +// }; +export const jestCallExpression: TreePattern = new TreePattern({ + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'jest' + }, + property: { + type: 'Identifier', + name: TreePattern.tag('methodName') + } + } +}); + +// Matches require() in a statement expression like this: +// const x = require("package-name"); +export const requireCallExpression: TreePattern = new TreePattern({ + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'require' + } +}); + +// Matches import in a statement expression like this: +// const x = import("package-name"); +export const importExpression: TreePattern = new TreePattern({ + type: 'ImportExpression', + source: { + type: 'Literal' + } +}); 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 new file mode 100644 index 00000000000..61f0c64f23e --- /dev/null +++ b/eslint/eslint-plugin/src/index.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint } from '@typescript-eslint/utils'; + +import { hoistJestMock } from './hoist-jest-mock'; +import { noBackslashImportsRule } from './no-backslash-imports'; +import { noExternalLocalImportsRule } from './no-external-local-imports'; +import { noNewNullRule } from './no-new-null'; +import { noNullRule } from './no-null'; +import { noTransitiveDependencyImportsRule } from './no-transitive-dependency-imports'; +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 }; +} + +const plugin: IPlugin = { + rules: { + // Full name: "@rushstack/hoist-jest-mock" + 'hoist-jest-mock': hoistJestMock, + + // Full name: "@rushstack/no-backslash-imports" + 'no-backslash-imports': noBackslashImportsRule, + + // Full name: "@rushstack/no-external-local-imports" + 'no-external-local-imports': noExternalLocalImportsRule, + + // Full name: "@rushstack/no-new-null" + 'no-new-null': noNewNullRule, + + // Full name: "@rushstack/no-null" + 'no-null': noNullRule, + + // Full name: "@rushstack/no-transitive-dependency-imports" + 'no-transitive-dependency-imports': noTransitiveDependencyImportsRule, + + // Full name: "@rushstack/no-untyped-underscore" + 'no-untyped-underscore': noUntypedUnderscoreRule, + + // Full name: "@rushstack/normalized-imports" + 'normalized-imports': normalizedImportsRule, + + // Full name: "@rushstack/typedef-var" + '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 + } +}; + +export = plugin; diff --git a/eslint/eslint-plugin/src/no-backslash-imports.ts b/eslint/eslint-plugin/src/no-backslash-imports.ts new file mode 100644 index 00000000000..82fbb1bb791 --- /dev/null +++ b/eslint/eslint-plugin/src/no-backslash-imports.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 type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + +import { + parseImportSpecifierFromExpression, + serializeImportSpecifier, + type IParsedImportSpecifier +} from './LintUtilities'; + +export const MESSAGE_ID: 'no-backslash-imports' = 'no-backslash-imports'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext; + +export const noBackslashImportsRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + [MESSAGE_ID]: 'The specified import target path contains backslashes.' + }, + schema: [], + docs: { + description: 'Prevents imports using paths that use backslashes', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + }, + fixable: 'code' + }, + create: (context: RuleContext) => { + const checkImportExpression: (importExpression: TSESTree.Expression | null) => void = ( + importExpression: TSESTree.Expression | null + ) => { + if (!importExpression) { + // Can't validate, return + return; + } + + // Determine the target file path and find the most direct relative path from the source file + const importSpecifier: IParsedImportSpecifier | undefined = + parseImportSpecifierFromExpression(importExpression); + if (importSpecifier === undefined) { + // Can't validate, return + return; + } + + // Check if the import path contains backslashes. If it does, suggest a fix to replace them with forward + // slashes. + const { importTarget } = importSpecifier; + if (importTarget.includes('\\')) { + context.report({ + node: importExpression, + messageId: MESSAGE_ID, + fix: (fixer: TSESLint.RuleFixer) => { + const normalizedSpecifier: IParsedImportSpecifier = { + ...importSpecifier, + importTarget: importTarget.replace(/\\/g, '/') + }; + return fixer.replaceText(importExpression, `'${serializeImportSpecifier(normalizedSpecifier)}'`); + } + }); + } + }; + + return { + ImportDeclaration: (node: TSESTree.ImportDeclaration) => checkImportExpression(node.source), + ImportExpression: (node: TSESTree.ImportExpression) => checkImportExpression(node.source), + ExportAllDeclaration: (node: TSESTree.ExportAllDeclaration) => checkImportExpression(node.source), + ExportNamedDeclaration: (node: TSESTree.ExportNamedDeclaration) => checkImportExpression(node.source) + }; + } +}; diff --git a/eslint/eslint-plugin/src/no-external-local-imports.ts b/eslint/eslint-plugin/src/no-external-local-imports.ts new file mode 100644 index 00000000000..e4ae7bae204 --- /dev/null +++ b/eslint/eslint-plugin/src/no-external-local-imports.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 * 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'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext; + +const _relativePathRegex: RegExp = /^[.\/\\]+$/; + +export const noExternalLocalImportsRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + [MESSAGE_ID]: + '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 "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' + } + }, + create: (context: RuleContext) => { + const rootDirectory: string | undefined = getRootDirectoryFromContext(context); + const checkImportExpression: (importExpression: TSESTree.Expression | null) => void = ( + importExpression: TSESTree.Expression | null + ) => { + if (!importExpression || !rootDirectory) { + // Can't validate, return + return; + } + + // Get the relative path between the target and the root. If the target is under the root, then the resulting + // relative path should be a series of "../" segments. + const importAbsolutePath: string | undefined = getImportAbsolutePathFromExpression( + context, + importExpression + ); + if (!importAbsolutePath) { + // Can't validate, return + return; + } + + const relativePathToRoot: string = path.relative(importAbsolutePath, rootDirectory); + if (!_relativePathRegex.test(relativePathToRoot)) { + context.report({ + node: importExpression, + messageId: MESSAGE_ID, + data: { importAbsolutePath, rootDirectory } + }); + } + }; + + return { + ImportDeclaration: (node: TSESTree.ImportDeclaration) => checkImportExpression(node.source), + ImportExpression: (node: TSESTree.ImportExpression) => checkImportExpression(node.source), + ExportAllDeclaration: (node: TSESTree.ExportAllDeclaration) => checkImportExpression(node.source), + ExportNamedDeclaration: (node: TSESTree.ExportNamedDeclaration) => checkImportExpression(node.source) + }; + } +}; diff --git a/eslint/eslint-plugin/src/no-new-null.ts b/eslint/eslint-plugin/src/no-new-null.ts new file mode 100644 index 00000000000..36d3e82db74 --- /dev/null +++ b/eslint/eslint-plugin/src/no-new-null.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 type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +type MessageIds = 'error-new-usage-of-null'; +type Options = []; + +interface IAccessible { + accessibility?: TSESTree.Accessibility; +} + +const noNewNullRule: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + 'error-new-usage-of-null': + 'Usage of "null" is deprecated except when describing legacy APIs; use "undefined" instead' + }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: + 'Prevent usage of JavaScript\'s "null" keyword in new type declarations. To avoid hampering usage' + + ' of preexisting APIs that require "null", the rule ignores declarations that are local variables,' + + ' private members, or types that are not exported.', + recommended: 'recommended', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + /** + * Returns true if the accessibility is not explicitly set to private or protected, e.g. class properties, methods. + */ + function isPubliclyAccessible(node?: IAccessible): boolean { + const accessibility: TSESTree.Accessibility | undefined = node?.accessibility; + return !(accessibility === 'private' || accessibility === 'protected'); + } + + /** + * Let's us check the accessibility field of certain types of nodes + */ + function isAccessible(node?: unknown): node is IAccessible { + if (!node) { + return false; + } + switch ((node as TSESTree.Node).type) { + case AST_NODE_TYPES.MethodDefinition: + return true; + case AST_NODE_TYPES.PropertyDefinition: + return true; + case AST_NODE_TYPES.TSIndexSignature: + return true; + case AST_NODE_TYPES.TSParameterProperty: + return true; + default: + return false; + } + } + + /** + * Checks if the type declaration is lifted to be exportable to others + */ + function isDefinitionExportable(node?: TSESTree.Node): boolean { + switch (node?.type) { + case undefined: // base case + return false; + case AST_NODE_TYPES.BlockStatement: // we are an inline function, scope is not exportable + return false; + case AST_NODE_TYPES.ExportNamedDeclaration: // our definition is being exported + return true; + case AST_NODE_TYPES.Program: // our definition can be exported + return true; + default: + if (isAccessible(node)) { + // only fail when class method/constructor is accessible publicly + return isPubliclyAccessible(node); + } + return isDefinitionExportable(node?.parent); + } + } + + /** + * Returns true if this type definition exposes a null type + */ + function isNewNull(node?: TSESTree.Node): boolean { + switch (node?.type) { + case undefined: + return false; + case AST_NODE_TYPES.TSTypeAnnotation: + return isDefinitionExportable(node.parent); + case AST_NODE_TYPES.TSTypeAliasDeclaration: + return isDefinitionExportable(node.parent); + default: + return isNewNull(node?.parent); + } + } + + return { + TSNullKeyword(node: TSESTree.TSNullKeyword): void { + if (isNewNull(node.parent)) { + context.report({ node, messageId: 'error-new-usage-of-null' }); + } + } + }; + } +}; + +export { noNewNullRule }; diff --git a/stack/eslint-plugin/src/no-null.ts b/eslint/eslint-plugin/src/no-null.ts similarity index 80% rename from stack/eslint-plugin/src/no-null.ts rename to eslint/eslint-plugin/src/no-null.ts index 076c282b2ed..3525d0128a4 100644 --- a/stack/eslint-plugin/src/no-null.ts +++ b/eslint/eslint-plugin/src/no-null.ts @@ -1,35 +1,31 @@ // 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/experimental-utils'; +import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; type MessageIds = 'error-usage-of-null'; -type Options = [ ]; +type Options = []; -const noNullRule: TSESLint.RuleModule = { +const noNullRule: TSESLint.RuleModule = { + defaultOptions: [], meta: { type: 'problem', messages: { 'error-usage-of-null': 'Usage of "null" is deprecated except when received from legacy APIs; use "undefined" instead' }, - schema: [ ], + schema: [], docs: { description: 'Prevent usage of JavaScript\'s "null" keyword', - category: 'Stylistic Issues', - recommended: "error", + recommended: 'recommended', url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' - } + } as TSESLint.RuleMetaDataDocs }, create: (context: TSESLint.RuleContext) => { return { - Literal: function(node: TSESTree.Literal) { + Literal: function (node: TSESTree.Literal) { // Is it a "null" literal? if (node.value === null) { - // Does the "null" appear in a comparison such as "if (x === null)"? let isComparison: boolean = false; if (node.parent && node.parent.type === 'BinaryExpression') { diff --git a/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts b/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts new file mode 100644 index 00000000000..e7677826f14 --- /dev/null +++ b/eslint/eslint-plugin/src/no-transitive-dependency-imports.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 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'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext; + +const NODE_MODULES_PATH_SEGMENT: '/node_modules/' = '/node_modules/'; + +export const noTransitiveDependencyImportsRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + [MESSAGE_ID]: 'The specified import targets a transitive dependency.' + }, + schema: [], + docs: { + description: + 'Prevents referencing imports that are transitive dependencies, ie. imports that are not ' + + 'direct dependencies of the package.', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } + }, + create: (context: RuleContext) => { + const checkImportExpression: (importExpression: TSESTree.Expression | null) => void = ( + importExpression: TSESTree.Expression | null + ) => { + if (!importExpression) { + // Can't validate, return + return; + } + + const importSpecifier: IParsedImportSpecifier | undefined = + parseImportSpecifierFromExpression(importExpression); + if (importSpecifier === undefined) { + // Can't validate, return + return; + } + + // Check to see if node_modules is mentioned in the normalized import path more than once if + // the path is relative, or if it is mentioned at all if the path is to a package. + const { importTarget } = importSpecifier; + const isRelative: boolean = importTarget.startsWith('.'); + let nodeModulesIndex: number = importTarget.indexOf(NODE_MODULES_PATH_SEGMENT); + if (nodeModulesIndex >= 0 && isRelative) { + // We allow relative paths to node_modules one layer deep to deal with bypassing exports + nodeModulesIndex = importTarget.indexOf( + NODE_MODULES_PATH_SEGMENT, + nodeModulesIndex + NODE_MODULES_PATH_SEGMENT.length - 1 + ); + } + if (nodeModulesIndex >= 0) { + context.report({ node: importExpression, messageId: MESSAGE_ID }); + } + }; + + return { + ImportDeclaration: (node: TSESTree.ImportDeclaration) => checkImportExpression(node.source), + ImportExpression: (node: TSESTree.ImportExpression) => checkImportExpression(node.source), + ExportAllDeclaration: (node: TSESTree.ExportAllDeclaration) => checkImportExpression(node.source), + ExportNamedDeclaration: (node: TSESTree.ExportNamedDeclaration) => checkImportExpression(node.source) + }; + } +}; diff --git a/eslint/eslint-plugin/src/no-untyped-underscore.ts b/eslint/eslint-plugin/src/no-untyped-underscore.ts new file mode 100644 index 00000000000..01f948f2873 --- /dev/null +++ b/eslint/eslint-plugin/src/no-untyped-underscore.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 type { TSESTree, TSESLint, ParserServices } from '@typescript-eslint/utils'; +import type * as ts from 'typescript'; + +type MessageIds = 'error-untyped-underscore'; +type Options = []; + +const noUntypedUnderscoreRule: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + 'error-untyped-underscore': + 'This expression appears to access a private member "{{memberName}}"; ' + + 'either remove the underscore prefix or else declare a type for the containing object' + }, + schema: [], + docs: { + description: + 'Prevent TypeScript code from accessing legacy JavaScript members' + + ' whose names have an underscore prefix', + recommended: 'strict', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } as TSESLint.RuleMetaDataDocs + }, + create: (context: TSESLint.RuleContext) => { + 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"' + + ' property for "@typescript-eslint/parser".' + ); + } + + const typeChecker: ts.TypeChecker = parserServices.program.getTypeChecker(); + + return { + MemberExpression: function (node: TSESTree.MemberExpression) { + // Is it an expression like "x.y"? + + // Ignore expressions such as "super.y", "this.y", and "that.y" + const memberObject: TSESTree.Expression = node.object; + if (memberObject) { + if (memberObject.type === 'Super' || memberObject.type === 'ThisExpression') { + return; // no match + } + if (memberObject.type === 'Identifier') { + if (memberObject.name === 'this' || memberObject.name === 'that') { + return; // no match + } + } + } + + // Does the member name start with an underscore? (e.g. "x._y") + if (node.property && node.property.type === 'Identifier') { + const memberName: string = node.property.name; + if (memberName && memberName[0] === '_') { + // Do we have type information for the property (e.g. "_y")? + // + // Examples where propertyType is defined: + // + // let x: { _y: any }; + // let x: { + // _y: boolean; + // [key: string]: number; + // }; + // + // Examples with propertyType=undefined: + // let x: any; + // let x: { [key: string]: number }; + // + let propertyType: ts.Symbol | undefined = undefined; + + const memberObjectNode: ts.Node | undefined = parserServices.esTreeNodeToTSNodeMap!.get( + node.object + ); + if (memberObjectNode) { + const memberObjectType: ts.Type | undefined = typeChecker.getTypeAtLocation(memberObjectNode); + if (memberObjectType) { + propertyType = memberObjectType.getProperty(memberName); + } + } + + // TypeScript's type system already sufficiently restricts access to private members. + // Thus, this ESLint rule only considers untyped code such as a legacy JavaScript API. + if (!propertyType) { + context.report({ + node, + messageId: 'error-untyped-underscore', + data: { memberName: memberName } + }); + } + } + } + } + }; + } +}; + +export { noUntypedUnderscoreRule }; diff --git a/eslint/eslint-plugin/src/normalized-imports.ts b/eslint/eslint-plugin/src/normalized-imports.ts new file mode 100644 index 00000000000..1534642a20c --- /dev/null +++ b/eslint/eslint-plugin/src/normalized-imports.ts @@ -0,0 +1,87 @@ +// 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 { TSESTree, TSESLint } from '@typescript-eslint/utils'; + +import { + getFilePathFromContext, + parseImportSpecifierFromExpression, + serializeImportSpecifier, + type IParsedImportSpecifier +} from './LintUtilities'; + +export const MESSAGE_ID: 'error-normalized-imports' = 'error-normalized-imports'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext; + +export const normalizedImportsRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'suggestion', + messages: { + [MESSAGE_ID]: 'The specified import target path was not provided in a normalized form.' + }, + schema: [], + docs: { + description: + 'Prevents and normalizes references to relative imports using paths that make unnecessary ' + + 'traversals (ex. "../blah/module" in directory "blah" -> "./module")', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + }, + fixable: 'code' + }, + create: (context: RuleContext) => { + const checkImportExpression: (importExpression: TSESTree.Expression | null) => void = ( + importExpression: TSESTree.Expression | null + ) => { + if (!importExpression) { + // Can't validate, return + return; + } + + // Determine the target file path and find the most direct relative path from the source file + const importSpecifier: IParsedImportSpecifier | undefined = + parseImportSpecifierFromExpression(importExpression); + if (!importSpecifier || !importSpecifier.importTarget.startsWith('.')) { + // Can't validate, return + return; + } + const { importTarget } = importSpecifier; + const parentDirectory: string = path.dirname(getFilePathFromContext(context)); + const absoluteImportPath: string = path.resolve(parentDirectory, importTarget); + const relativeImportPath: string = path.relative(parentDirectory, absoluteImportPath); + + // Reconstruct the import target using posix separators and manually re-add the leading './' if needed + let normalizedImportPath: string = + path.sep !== '/' ? relativeImportPath.replace(/\\/g, '/') : relativeImportPath; + if (!normalizedImportPath.startsWith('.')) { + normalizedImportPath = `.${normalizedImportPath ? '/' : ''}${normalizedImportPath}`; + } + + // If they don't match, suggest the normalized path as a fix + if (importTarget !== normalizedImportPath) { + context.report({ + node: importExpression, + messageId: MESSAGE_ID, + fix: (fixer: TSESLint.RuleFixer) => { + // Re-include stripped loader and query strings, if provided + const normalizedSpecifier: string = serializeImportSpecifier({ + ...importSpecifier, + importTarget: normalizedImportPath + }); + return fixer.replaceText(importExpression, `'${normalizedSpecifier}'`); + } + }); + } + }; + + return { + ImportDeclaration: (node: TSESTree.ImportDeclaration) => checkImportExpression(node.source), + ImportExpression: (node: TSESTree.ImportExpression) => checkImportExpression(node.source), + ExportAllDeclaration: (node: TSESTree.ExportAllDeclaration) => checkImportExpression(node.source), + ExportNamedDeclaration: (node: TSESTree.ExportNamedDeclaration) => checkImportExpression(node.source) + }; + } +}; 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/fixtures/file.ts b/eslint/eslint-plugin/src/test/fixtures/file.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/eslint/eslint-plugin/src/test/fixtures/file.ts @@ -0,0 +1,2 @@ +// 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/src/test/fixtures/tsconfig.json b/eslint/eslint-plugin/src/test/fixtures/tsconfig.json new file mode 100644 index 00000000000..7e9126b848c --- /dev/null +++ b/eslint/eslint-plugin/src/test/fixtures/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "target": "es5", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "lib": ["es2015", "es2017", "esnext"], + "experimentalDecorators": true + }, + "include": ["file.ts"] +} diff --git a/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts b/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts new file mode 100644 index 00000000000..49e4af553cc --- /dev/null +++ b/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts @@ -0,0 +1,142 @@ +// 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 { hoistJestMock } from '../hoist-jest-mock'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +// These are the CODE_WITH_HOISTING cases from ts-jest's hoist-jest.spec.ts +const INVALID_EXAMPLE_CODE = [ + /* 001 */ "require('foo')", + /* 002 */ 'console.log(foo)', + /* 003 */ 'jest.enableAutomock()', + /* 004 */ 'jest.disableAutomock()', + /* 005 */ "jest.mock('./foo')", + /* 006 */ "jest.mock('./foo/bar', () => 'bar')", + /* 007 */ "jest.unmock('./bar/foo').dontMock('./bar/bar')", + /* 008 */ "jest.deepUnmock('./foo')", + /* 009 */ "jest.mock('./foo').mock('./bar')", + /* 010 */ 'const func = () => {', + /* 011 */ " const bar = 'bar'", + /* 012 */ ' console.log(bar)', + /* 013 */ " jest.unmock('./foo')", + /* 014 */ " jest.mock('./bar')", + /* 015 */ " jest.mock('./bar/foo', () => 'foo')", + /* 016 */ " jest.unmock('./foo/bar')", + /* 017 */ " jest.unmock('./bar/foo').dontMock('./bar/bar')", + /* 018 */ " jest.deepUnmock('./bar')", + /* 019 */ " jest.mock('./foo').mock('./bar')", + /* 020 */ '}', + /* 021 */ 'const func2 = () => {', + /* 022 */ " const bar = 'bar'", + /* 023 */ ' console.log(bar)', + /* 024 */ " jest.mock('./bar')", + /* 025 */ " jest.unmock('./foo/bar')", + /* 026 */ " jest.mock('./bar/foo', () => 'foo')", + /* 027 */ " jest.unmock('./foo')", + /* 028 */ " jest.unmock('./bar/foo').dontMock('./bar/bar')", + /* 029 */ " jest.deepUnmock('./bar')", + /* 030 */ " jest.mock('./foo').mock('./bar')", + /* 031 */ '}' +].join('\n'); + +ruleTester.run('hoist-jest-mock', hoistJestMock, { + invalid: [ + { + // Detect all the Jest APIs detected by ts-jest + code: INVALID_EXAMPLE_CODE, + errors: [ + { messageId: 'error-unhoisted-jest-mock', line: 3 }, + { messageId: 'error-unhoisted-jest-mock', line: 4 }, + { messageId: 'error-unhoisted-jest-mock', line: 5 }, + { messageId: 'error-unhoisted-jest-mock', line: 6 }, + { messageId: 'error-unhoisted-jest-mock', line: 7 }, + { messageId: 'error-unhoisted-jest-mock', line: 8 }, + { messageId: 'error-unhoisted-jest-mock', line: 9 }, + + { messageId: 'error-unhoisted-jest-mock', line: 13 }, + { messageId: 'error-unhoisted-jest-mock', line: 14 }, + { messageId: 'error-unhoisted-jest-mock', line: 15 }, + { messageId: 'error-unhoisted-jest-mock', line: 16 }, + { messageId: 'error-unhoisted-jest-mock', line: 17 }, + { messageId: 'error-unhoisted-jest-mock', line: 18 }, + { messageId: 'error-unhoisted-jest-mock', line: 19 }, + + { messageId: 'error-unhoisted-jest-mock', line: 24 }, + { messageId: 'error-unhoisted-jest-mock', line: 25 }, + { messageId: 'error-unhoisted-jest-mock', line: 26 }, + { messageId: 'error-unhoisted-jest-mock', line: 27 }, + { messageId: 'error-unhoisted-jest-mock', line: 28 }, + { messageId: 'error-unhoisted-jest-mock', line: 29 }, + { messageId: 'error-unhoisted-jest-mock', line: 30 } + ] + }, + { + // A simple failure using realistic code + // prettier-ignore + code: [ + "const soundPlayer = require('./SoundPlayer');", + "jest.mock('./SoundPlayer');" + ].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + { + // Import syntaxes that should fail + code: ["import x from 'y';", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + // { + // // Import syntaxes that should fail + // code: ["export { x } from 'y';", 'jest.mock();'].join('\n'), + // errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + // }, + { + // Import syntaxes that should fail + code: ["import * as x from 'y';", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + // { + // // Import syntaxes that should fail + // code: ["export * from 'y';", 'jest.mock();'].join('\n'), + // errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + // }, + { + // Import syntaxes that should fail + code: ["import 'y';", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + { + // Import syntaxes that should fail + code: ["const x = require('package-name');", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + { + // Import syntaxes that should fail + code: ["const x = import('package-name');", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + }, + { + // Import syntaxes that should fail + code: ["import x = require('package-name');", 'jest.mock();'].join('\n'), + errors: [{ messageId: 'error-unhoisted-jest-mock', line: 2 }] + } + ], + valid: [ + { + // A simple success using realistic code + code: [ + 'const mockPlaySoundFile = jest.fn();', + "jest.mock('./SoundPlayer', () => {", + ' return {', + ' SoundPlayer: jest.fn().mockImplementation(() => {', + ' return { playSoundFile: mockPlaySoundFile };', + ' })', + ' };', + '});' + ].join('\n') + } + ] +}); 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 new file mode 100644 index 00000000000..a508ff60138 --- /dev/null +++ b/eslint/eslint-plugin/src/test/no-backslash-imports.test.ts @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { noBackslashImportsRule, MESSAGE_ID } from '../no-backslash-imports'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); +const expectedErrors: TestCaseError[] = [{ messageId: MESSAGE_ID }]; + +ruleTester.run('no-backslash-imports', noBackslashImportsRule, { + invalid: [ + // Test variants + { + code: "import blah from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import blah from './foo/bar'" + }, + { + code: "import * as blah from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import * as blah from './foo/bar'" + }, + { + code: "import { blah } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import { blah } from './foo/bar'" + }, + { + code: "import { _blah as Blah } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, { _blah as Blah } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import blah, { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, * as Blah from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import blah, * as Blah from './foo/bar'" + }, + { + code: "import '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import './foo/bar'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar'" + }, + { + code: "import blah from '.\\\\foo\\\\bar?source'", + errors: expectedErrors, + output: "import blah from './foo/bar?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!.\\\\foo\\\\bar?source'", + errors: expectedErrors, + output: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar?source'" + }, + { + code: "export * from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "export * from './foo/bar'" + }, + // { + // code: "export * as blah from './foo/../foo/bar'", + // errors: expectedErrors, + // output: "export * as blah from './foo/bar'" + // }, + { + code: "export { blah } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "export { blah } from './foo/bar'" + }, + { + code: "export { _blah as Blah } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "export { _blah as Blah } from './foo/bar'" + }, + { + code: "export { default } from '.\\\\foo\\\\bar'", + errors: expectedErrors, + output: "export { default } from './foo/bar'" + }, + // Test async imports + { + code: "const blah = await import('.\\\\foo\\\\bar')", + errors: expectedErrors, + output: "const blah = await import('./foo/bar')" + } + ], + valid: [ + // Test variants + { + code: "import blah from './foo/bar'" + }, + { + code: "import * as blah from './foo/bar'" + }, + { + code: "import { blah } from './foo/bar'" + }, + { + code: "import { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, * as Blah from './foo/bar'" + }, + { + code: "import './foo/bar'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar'" + }, + { + code: "import blah from './foo/bar?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar?source'" + }, + { + code: "export * from './foo/bar'" + }, + // { + // code: "export * as blah from './foo/bar'" + // }, + { + code: "export { blah } from './foo/bar'" + }, + { + code: "export { _blah as Blah } from './foo/bar'" + }, + { + code: "export { default } from './foo/bar'" + }, + // Test async imports + { + code: "const blah = await import('./foo/bar')" + } + ] +}); 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 new file mode 100644 index 00000000000..c18b995dac9 --- /dev/null +++ b/eslint/eslint-plugin/src/test/no-external-local-imports.test.ts @@ -0,0 +1,171 @@ +// 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 { getRuleTesterWithoutProject } from './ruleTester'; +import { noExternalLocalImportsRule } from '../no-external-local-imports'; + +const ruleTester: RuleTester = getRuleTesterWithoutProject(); + +// The root in the test cases is the immediate directory +ruleTester.run('no-external-local-imports', noExternalLocalImportsRule, { + invalid: [ + // Test variants + { + code: "import blah from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import * as blah from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import { blah } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import { _blah as Blah } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import blah, { _blah as Blah } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import blah, * as Blah from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import blah from '../foo?source'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!../foo?source'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "export * from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + // { + // code: "export * as blah from '../foo'", + // errors: [{ messageId: 'error-external-local-imports' }] + // }, + { + code: "export { blah } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "export { _blah as Blah } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "export { default } from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }] + }, + // Test importing from outside of tsconfigRootDir + { + code: "import blah from '../foo'", + errors: [{ messageId: 'error-external-local-imports' }], + filename: `${__dirname}/blah/test.ts`, + languageOptions: { + parserOptions: { + tsconfigRootDir: `${__dirname}/blah` + } + } + }, + // Test async imports + { + code: "const blah = await import('../foo')", + errors: [{ messageId: 'error-external-local-imports' }] + }, + { + code: "const blah = await import('../foo')", + errors: [{ messageId: 'error-external-local-imports' }], + filename: `${__dirname}/blah/test.ts`, + languageOptions: { + parserOptions: { + tsconfigRootDir: `${__dirname}/blah` + } + } + } + ], + valid: [ + // Test variants + { + code: "import blah from './foo'" + }, + { + code: "import * as blah from './foo'" + }, + { + code: "import { blah } from './foo'" + }, + { + code: "import { _blah as Blah } from './foo'" + }, + { + code: "import blah, { _blah as Blah } from './foo'" + }, + { + code: "import blah, * as Blah from './foo'" + }, + { + code: "import './foo'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo'" + }, + { + code: "import blah from './foo?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo?source'" + }, + { + code: "export * from './foo'" + }, + // { + // code: "export * as blah from './foo'" + // }, + { + code: "export { blah } from './foo'" + }, + { + code: "export { _blah as Blah } from './foo'" + }, + { + code: "export { default } from './foo'" + }, + // Test that importing vertically within the project is valid + { + code: "import blah from '../foo/bar'", + filename: 'blah2/test.ts' + }, + { + code: "import blah from '../../foo/bar'", + filename: 'blah2/foo3/test.ts' + }, + // Test async imports + { + code: "const blah = await import('./foo')" + }, + { + code: "const blah = await import('../foo/bar')", + filename: 'blah2/test.ts' + }, + { + code: "const blah = await import('../../foo/bar')", + filename: 'blah2/foo3/test.ts' + } + ] +}); diff --git a/eslint/eslint-plugin/src/test/no-new-null.test.ts b/eslint/eslint-plugin/src/test/no-new-null.test.ts new file mode 100644 index 00000000000..7ae2fdf8045 --- /dev/null +++ b/eslint/eslint-plugin/src/test/no-new-null.test.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 type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { noNewNullRule } from '../no-new-null'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +ruleTester.run('no-new-null', noNewNullRule, { + invalid: [ + { + code: 'type FuncAlias = (args: string | null) => void', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'type Alias = null', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'type ObjAlias = { field: string | null; }', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'type Constructor = {new (args: string | null)}', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'function nullTypeArgs(args: string | null): void {}', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'function nullReturn(args: string): (err: Error | null) => void {}', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'const functionExpression = function (arg: null): void {}', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'const arrow = (args: null) => {}', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'interface I { field: null; }', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: 'const v: string | null = "hello"', + errors: [{ messageId: 'error-new-usage-of-null' }] + }, + { + code: [ + 'class PublicNulls {', + ' property: string | null;', + ' propertyFunc: (val: string | null) => void;', + ' legacyImplicitPublic(hello: string | null): void {}', + ' public legacyExplicitPublic(hello: string | null): void {}', + '}' + ].join('\n'), + errors: [ + { + messageId: 'error-new-usage-of-null' + }, + { + messageId: 'error-new-usage-of-null' + }, + { + messageId: 'error-new-usage-of-null' + }, + { + messageId: 'error-new-usage-of-null' + } + ] + } + ], + valid: [ + { + code: [ + 'export function wrapLegacy(hello: string): void {', + ' const innerCallback: (err: NodeJS.ErrnoException | null) => void = (e) => {};', + ' return innerCallback(null);', + '}' + ].join('\n') + }, + { + code: [ + 'function functionWithLocalVariableTypes(): void {', + ' const match: RegExpExecArray | null = null;', + '}' + ].join('\n') + }, + { + code: [ + 'class PrivateNulls {', + ' // private pField: string | null;', + ' private pFunc: (val: string | null) => void;', + ' l = this.legacyPrivate(null);', + " // field = this.legacyPrivate('null');", + ' private legacyPrivate(hello: string | null): void {', + ' // this.pFunc(this.pField)', + " this.pFunc('hello')", + ' }', + '}' + ].join('\n') + } + ] +}); 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 new file mode 100644 index 00000000000..9d61892ce34 --- /dev/null +++ b/eslint/eslint-plugin/src/test/no-transitive-dependency-imports.test.ts @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { noTransitiveDependencyImportsRule, MESSAGE_ID } from '../no-transitive-dependency-imports'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); +const expectedErrors: TestCaseError[] = [{ messageId: MESSAGE_ID }]; + +ruleTester.run('no-transitive-dependency-imports', noTransitiveDependencyImportsRule, { + invalid: [ + // Test variants + { + code: "import blah from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import * as blah from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import { blah } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import { _blah as Blah } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import blah, { _blah as Blah } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import blah, * as Blah from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "import blah from './node_modules/foo/node_modules/bar?source'", + errors: expectedErrors + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./node_modules/foo/node_modules/bar?source'", + errors: expectedErrors + }, + { + code: "export * from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + // { + // code: "export * as blah from './node_modules/foo/node_modules/bar'", + // errors: expectedErrors + // }, + { + code: "export { blah } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "export { _blah as Blah } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + { + code: "export { default } from './node_modules/foo/node_modules/bar'", + errors: expectedErrors + }, + // Test async imports + { + code: "const blah = await import('./node_modules/foo/node_modules/bar')", + errors: expectedErrors + } + ], + valid: [ + // Test variants + { + code: "import blah from './node_modules/foo'" + }, + { + code: "import * as blah from './node_modules/foo'" + }, + { + code: "import { blah } from './node_modules/foo'" + }, + { + code: "import { _blah as Blah } from './node_modules/foo'" + }, + { + code: "import blah, { _blah as Blah } from './node_modules/foo'" + }, + { + code: "import blah, * as Blah from './node_modules/foo'" + }, + { + code: "import './node_modules/foo'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./node_modules/foo'" + }, + { + code: "import blah from './node_modules/foo?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./node_modules/foo?source'" + }, + { + code: "export * from './node_modules/foo'" + }, + // { + // code: "export * as blah from './node_modules/foo'" + // }, + { + code: "export { blah } from './node_modules/foo'" + }, + { + code: "export { _blah as Blah } from './node_modules/foo'" + }, + { + code: "export { default } from './node_modules/foo'" + }, + // Test async imports + { + code: "const blah = await import('./node_modules/foo')" + } + ] +}); diff --git a/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts b/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts new file mode 100644 index 00000000000..388646d7ecd --- /dev/null +++ b/eslint/eslint-plugin/src/test/no-untyped-underscore.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 type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { noUntypedUnderscoreRule } from '../no-untyped-underscore'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +ruleTester.run('no-untyped-underscore', noUntypedUnderscoreRule, { + invalid: [ + { + // prettier-ignore + code: [ + 'let x: any;', + 'x._privateMember = 123;' + ].join('\n'), + errors: [{ messageId: 'error-untyped-underscore' }] + }, + { + // prettier-ignore + code: [ + 'let x: { [key: string]: number };', + 'x._privateMember = 123;' + ].join('\n'), + errors: [{ messageId: 'error-untyped-underscore' }] + } + ], + valid: [ + { + // prettier-ignore + code: [ + 'let x: { _privateMember: any };', + 'x._privateMember = 123;' + ].join('\n') + }, + { + // prettier-ignore + code: [ + 'let x = { _privateMember: 0 };', + 'x._privateMember = 123;' + ].join('\n') + }, + { + // prettier-ignore + code: [ + 'enum E {', + ' _PrivateMember', + '}', + 'let e: E._PrivateMember = E._PrivateMember;' + ].join('\n') + } + ] +}); diff --git a/eslint/eslint-plugin/src/test/normalized-imports.test.ts b/eslint/eslint-plugin/src/test/normalized-imports.test.ts new file mode 100644 index 00000000000..b65a88565c2 --- /dev/null +++ b/eslint/eslint-plugin/src/test/normalized-imports.test.ts @@ -0,0 +1,215 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithoutProject } from './ruleTester'; +import { normalizedImportsRule, MESSAGE_ID } from '../normalized-imports'; + +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, { + invalid: [ + // Test variants + { + code: "import blah from './foo/../foo/bar'", + errors: expectedErrors, + output: "import blah from './foo/bar'" + }, + { + code: "import * as blah from './foo/../foo/bar'", + errors: expectedErrors, + output: "import * as blah from './foo/bar'" + }, + { + code: "import { blah } from './foo/../foo/bar'", + errors: expectedErrors, + output: "import { blah } from './foo/bar'" + }, + { + code: "import { _blah as Blah } from './foo/../foo/bar'", + errors: expectedErrors, + output: "import { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, { _blah as Blah } from './foo/../foo/bar'", + errors: expectedErrors, + output: "import blah, { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, * as Blah from './foo/../foo/bar'", + errors: expectedErrors, + output: "import blah, * as Blah from './foo/bar'" + }, + { + code: "import './foo/../foo/bar'", + errors: expectedErrors, + output: "import './foo/bar'" + }, + // While directory imports aren't ideal, especially from the immediate directory, the path is normalized + { + code: "import blah from './'", + errors: expectedErrors, + output: "import blah from '.'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/../foo/bar'", + errors: expectedErrors, + output: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar'" + }, + { + code: "import blah from './foo/../foo/bar?source'", + errors: expectedErrors, + output: "import blah from './foo/bar?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/../foo/bar?source'", + errors: expectedErrors, + output: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar?source'" + }, + { + code: "export * from './foo/../foo/bar'", + errors: expectedErrors, + output: "export * from './foo/bar'" + }, + // { + // code: "export * as blah from './foo/../foo/bar'", + // errors: expectedErrors, + // output: "export * as blah from './foo/bar'" + // }, + { + code: "export { blah } from './foo/../foo/bar'", + errors: expectedErrors, + output: "export { blah } from './foo/bar'" + }, + { + code: "export { _blah as Blah } from './foo/../foo/bar'", + errors: expectedErrors, + output: "export { _blah as Blah } from './foo/bar'" + }, + { + code: "export { default } from './foo/../foo/bar'", + errors: expectedErrors, + output: "export { default } from './foo/bar'" + }, + // Test leaving and re-entering the current directory + { + code: "import blah from '../foo/bar'", + errors: expectedErrors, + output: "import blah from './bar'", + filename: 'foo/test.ts' + }, + { + code: "import blah from '../../foo/foo2/bar'", + errors: expectedErrors, + output: "import blah from './bar'", + filename: 'foo/foo2/test.ts' + }, + { + code: "import blah from '../../foo/bar'", + errors: expectedErrors, + output: "import blah from '../bar'", + filename: 'foo/foo2/test.ts' + }, + // Test async imports + { + code: "const blah = await import('./foo/../foo/bar')", + errors: expectedErrors, + output: "const blah = await import('./foo/bar')" + }, + { + code: "const blah = await import('../foo/bar')", + errors: expectedErrors, + output: "const blah = await import('./bar')", + filename: 'foo/test.ts' + }, + { + code: "const blah = await import('../../foo/foo2/bar')", + errors: expectedErrors, + output: "const blah = await import('./bar')", + filename: 'foo/foo2/test.ts' + }, + { + code: "const blah = await import('../../foo/bar')", + errors: expectedErrors, + output: "const blah = await import('../bar')", + filename: 'foo/foo2/test.ts' + } + ], + valid: [ + // Test variants + { + code: "import blah from './foo/bar'" + }, + { + code: "import * as blah from './foo/bar'" + }, + { + code: "import { blah } from './foo/bar'" + }, + { + code: "import { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, { _blah as Blah } from './foo/bar'" + }, + { + code: "import blah, * as Blah from './foo/bar'" + }, + { + code: "import './foo/bar'" + }, + // While directory imports aren't ideal, especially from the immediate directory, the path is normalized + { + code: "import blah from '.'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar'" + }, + { + code: "import blah from './foo/bar?source'" + }, + { + code: "import blah from '!!file-loader?name=image_[name]_[hash:8][ext]!./foo/bar?source'" + }, + { + code: "export * from './foo/bar'" + }, + // { + // code: "export * as blah from './foo/bar'" + // }, + { + code: "export { blah } from './foo/bar'" + }, + { + code: "export { _blah as Blah } from './foo/bar'" + }, + { + code: "export { default } from './foo/bar'" + }, + // Test that importing vertically is valid + { + code: "import blah from '../foo/bar'", + filename: 'foo2/test.ts' + }, + { + code: "import blah from '../../foo/bar'", + filename: 'foo2/foo3/test.ts' + }, + // Test async imports + { + code: "const blah = await import('./foo/bar')" + }, + { + code: "const blah = await import('../foo/bar')", + filename: 'foo2/test.ts' + }, + { + code: "const blah = import('../../foo/bar')", + filename: 'foo2/foo3/test.ts' + } + ] +}); 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 new file mode 100644 index 00000000000..7f7b9b69bf7 --- /dev/null +++ b/eslint/eslint-plugin/src/test/typedef-var.test.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 type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { typedefVar } from '../typedef-var'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +ruleTester.run('typedef-var', typedefVar, { + invalid: [ + { + code: 'const x = 123;', + errors: [{ messageId: 'expected-typedef-named' }] + }, + { + code: 'let x = 123;', + errors: [{ messageId: 'expected-typedef-named' }] + }, + { + code: 'var x = 123;', + errors: [{ messageId: 'expected-typedef-named' }] + }, + { + code: '{ const x = 123; }', + errors: [{ messageId: 'expected-typedef-named' }] + } + ], + valid: [ + { + code: 'function f() { const x = 123; }' + }, + { + code: 'const f = () => { const x = 123; };' + }, + { + code: 'const f = function() { const x = 123; }' + }, + { + code: 'for (const x of []) { }' + }, + { + code: 'const x = 1 as const;' + }, + { + code: 'const x: 1 = 1;' + }, + { + code: 'const x: number = 1;' + }, + { + // prettier-ignore + code: [ + 'let { a , b } = {', + ' a: 123,', + ' b: 234', + '}', + ].join('\n') + }, + { + // prettier-ignore + code: [ + 'class C {', + ' public m(): void {', + ' const x = 123;', + ' }', + '}', + ].join('\n') + }, + { + // prettier-ignore + code: [ + 'class C {', + ' public m = (): void => {', + ' const x = 123;', + ' }', + '}', + ].join('\n') + } + ] +}); diff --git a/eslint/eslint-plugin/src/typedef-var.ts b/eslint/eslint-plugin/src/typedef-var.ts new file mode 100644 index 00000000000..cd74234a0c2 --- /dev/null +++ b/eslint/eslint-plugin/src/typedef-var.ts @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; + +type MessageIds = 'expected-typedef' | 'expected-typedef-named'; +type Options = []; + +const typedefVar: TSESLint.RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + 'expected-typedef-named': 'Expected a type annotation.', + 'expected-typedef': 'Expected {{name}} to have a type annotation.' + }, + schema: [ + { + type: 'object', + additionalProperties: false + } + ], + docs: { + description: + 'Supplements the "@typescript-eslint/typedef" rule by relaxing the requirements for local variables', + recommended: 'recommended', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } as TSESLint.RuleMetaDataDocs + }, + + create: (context: TSESLint.RuleContext) => { + // This rule implements the variableDeclarationIgnoreFunction=true behavior from + // @typescript-eslint/typedef + function isVariableDeclarationIgnoreFunction(node: TSESTree.Node): boolean { + return ( + node.type === AST_NODE_TYPES.FunctionExpression || + node.type === AST_NODE_TYPES.ArrowFunctionExpression + ); + } + + function getNodeName(node: TSESTree.Parameter | TSESTree.PropertyName): string | undefined { + return node.type === AST_NODE_TYPES.Identifier ? node.name : undefined; + } + + return { + VariableDeclarator(node: TSESTree.VariableDeclarator): void { + if (node.id.typeAnnotation) { + // An explicit type declaration was provided + return; + } + + if ( + node.init?.type === AST_NODE_TYPES.TSAsExpression && + node.init.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference && + node.init.typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier && + node.init.typeAnnotation.typeName.name === 'const' + ) { + // An `as const` type declaration was provided + return; + } + + // These are @typescript-eslint/typedef exemptions + if ( + node.id.type === AST_NODE_TYPES.ArrayPattern /* ArrayDestructuring */ || + node.id.type === AST_NODE_TYPES.ObjectPattern /* ObjectDestructuring */ || + (node.init && isVariableDeclarationIgnoreFunction(node.init)) + ) { + return; + } + + // Ignore this case: + // + // for (const NODE of thing) { } + let current: TSESTree.Node | undefined = node.parent; + while (current) { + switch (current.type) { + case AST_NODE_TYPES.VariableDeclaration: + // Keep looking upwards + current = current.parent; + break; + case AST_NODE_TYPES.ForOfStatement: + case AST_NODE_TYPES.ForInStatement: + // Stop traversing and don't report an error + return; + default: + // Stop traversing + current = undefined; + break; + } + } + + // Is it a local variable? + current = node.parent; + while (current) { + switch (current.type) { + // function f() { + // const NODE = 123; + // } + case AST_NODE_TYPES.FunctionDeclaration: + + // class C { + // public m(): void { + // const NODE = 123; + // } + // } + // eslint-disable-next-line no-fallthrough + case AST_NODE_TYPES.MethodDefinition: + + // let f = function() { + // const NODE = 123; + // } + // eslint-disable-next-line no-fallthrough + case AST_NODE_TYPES.FunctionExpression: + + // let f = () => { + // const NODE = 123; + // } + // eslint-disable-next-line no-fallthrough + case AST_NODE_TYPES.ArrowFunctionExpression: + // Stop traversing and don't report an error + return; + } + + current = current.parent; + } + + const nodeName: string | undefined = getNodeName(node.id); + if (nodeName) { + context.report({ + node, + messageId: 'expected-typedef-named', + data: { name: nodeName } + }); + } else { + context.report({ + node, + messageId: 'expected-typedef' + }); + } + } + }; + } +}; + +export { typedefVar }; diff --git a/eslint/eslint-plugin/tsconfig.json b/eslint/eslint-plugin/tsconfig.json new file mode 100644 index 00000000000..09aacf59d98 --- /dev/null +++ b/eslint/eslint-plugin/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "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 new file mode 100644 index 00000000000..25141726512 --- /dev/null +++ b/eslint/local-eslint-config/.npmignore @@ -0,0 +1,27 @@ +# Ignore everything by default +** + +# Use negative patterns to bring back the specific things we want to publish +!/bin/** +!/lib/** +!/dist/** +!ThirdPartyNotice.txt +!/EULA/** + +# Ignore certain files in the above folder +/dist/*.stats.* +/lib/**/test/** +/lib/**/*.js.map +/dist/**/*.js.map + +# 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 + +## Project specific definitions +# ----------------------------- + +!/flat/** \ No newline at end of file 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/package.json b/eslint/local-eslint-config/package.json new file mode 100644 index 00000000000..4d908d71a63 --- /dev/null +++ b/eslint/local-eslint-config/package.json @@ -0,0 +1,33 @@ +{ + "name": "local-eslint-config", + "version": "1.0.0", + "private": true, + "description": "An ESLint configuration consumed projects inside the rushstack repo.", + "scripts": { + "build": "heft build --clean", + "_phase:lite-build": "heft build --clean" + }, + "peerDependencies": { + "eslint": "^9.25.1", + "typescript": ">=4.7.0" + }, + "devDependencies": { + "eslint": "~9.37.0", + "typescript": "~5.8.2", + "@rushstack/heft": "1.1.4", + "decoupled-local-node-rig": "workspace:*" + }, + "dependencies": { + "@rushstack/eslint-config": "workspace:*", + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/eslint-plugin": "workspace:*", + "@typescript-eslint/eslint-plugin": "~8.46.0", + "@typescript-eslint/parser": "~8.46.0", + "eslint-import-resolver-node": "0.3.9", + "eslint-plugin-header": "~3.1.1", + "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/heft-plugins/heft-api-extractor-plugin/.npmignore b/heft-plugins/heft-api-extractor-plugin/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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-api-extractor-plugin/CHANGELOG.json b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json new file mode 100644 index 00000000000..68d5ac49249 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json @@ -0,0 +1,2873 @@ +{ + "name": "@rushstack/heft-api-extractor-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.60", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.59", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.58", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.57", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.56", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.55", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.54", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.53", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.52", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.51", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.50", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.49", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.48", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.47", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.46", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.45", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.44", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.43", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.42", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.41", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.40", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.39", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.38", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.37", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.36", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.35", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.34", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.33", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.32", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.31", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.30", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.29", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.28", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.27", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.26", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.25", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.24", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.23", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.22", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.21", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.20", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.19", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.18", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.17", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.16", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.15", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.14", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.4` to `0.65.5`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.13", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.3` to `0.65.4`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.12", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.2` to `0.65.3`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.11", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.1` to `0.65.2`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.10", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.0` to `0.65.1`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.9", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.8` to `0.65.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.8", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.7` to `0.64.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.7", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.6` to `0.64.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.6", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.5` to `0.64.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.5", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.4` to `0.64.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.4", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.3` to `0.64.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.3", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.2` to `0.64.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.1` to `0.64.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.1", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.0` to `0.64.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.6` to `0.64.0`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.5` to `0.63.6`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.4` to `0.63.5`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.3` to `0.63.4`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.2` to `0.63.3`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.1` to `0.63.2`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.0` to `0.63.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.3` to `0.63.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.2` to `0.62.3`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.1` to `0.62.2`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.0` to `0.62.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.3` to `0.62.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.2` to `0.61.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.1` to `0.61.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.0` to `0.61.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.60.0` to `0.61.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.59.0` to `0.60.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-api-extractor-plugin_v0.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + }, + { + "comment": "Add \"runInWatchMode\" task configuration flag to support invocation when Heft is in watch mode. Does not currently offer any performance benefit." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.2` to `0.59.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.18", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.1` to `0.58.2`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.17", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.0` to `0.58.1`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.16", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.1` to `0.58.0`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.15", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.0` to `0.57.1`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.14", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.3` to `0.57.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.13", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.2` to `0.56.3`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.12", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.1` to `0.56.2`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.11", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.0` to `0.56.1`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.10", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.2` to `0.56.0`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.9", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.1` to `0.55.2`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.8", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.0` to `0.55.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.7", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.54.0` to `0.55.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.6", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.1` to `0.54.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.5", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.0` to `0.53.1`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.4", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.2` to `0.53.0`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.3", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.1` to `0.52.2`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.2", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.0` to `0.52.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.1", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.51.0` to `0.52.0`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-api-extractor-plugin_v0.1.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Prepare for official release." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.50.0` to `0.51.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md new file mode 100644 index 00000000000..7732d458cef --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md @@ -0,0 +1,719 @@ +# Change Log - @rushstack/heft-api-extractor-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.3.60 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.3.59 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.3.58 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.3.57 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.3.56 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.3.55 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.3.54 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.3.53 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.3.52 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.51 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.3.50 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.3.49 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.3.48 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.3.47 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.3.46 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.3.45 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.3.44 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.3.43 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.3.42 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.3.41 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.40 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.3.39 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.3.38 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.3.37 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.3.36 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.3.35 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.3.34 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.33 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.3.32 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.3.31 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.3.30 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.3.29 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.3.28 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.3.27 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.3.26 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.3.25 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.3.24 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.3.23 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.22 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.3.21 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.3.20 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.3.19 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.3.18 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.3.17 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.3.16 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.3.15 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.3.14 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.3.13 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.3.12 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.3.11 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.3.10 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.3.9 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.3.8 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.3.7 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.3.6 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.3.5 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.3.4 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.3.3 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.3.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.3.1 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.3.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 + +## 0.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.2.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.2.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.2.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.2.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.2.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.2.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.2.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.2.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 +- Add "runInWatchMode" task configuration flag to support invocation when Heft is in watch mode. Does not currently offer any performance benefit. + +## 0.1.18 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.1.17 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.1.16 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.1.15 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 0.1.14 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.13 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.1.12 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.1.11 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.1.10 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.1.9 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.1.8 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.1.7 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.1.6 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 0.1.5 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.1.4 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.1.2 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.1.1 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 0.1.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Prepare for official release. + diff --git a/heft-plugins/heft-api-extractor-plugin/LICENSE b/heft-plugins/heft-api-extractor-plugin/LICENSE new file mode 100644 index 00000000000..3df59e864a4 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-api-extractor-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-api-extractor-plugin/README.md b/heft-plugins/heft-api-extractor-plugin/README.md new file mode 100644 index 00000000000..960f1e0afaa --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-api-extractor-plugin + +This is a Heft plugin for running API Extractor. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-api-extractor-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-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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/heft-plugins/heft-api-extractor-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": "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 new file mode 100644 index 00000000000..6ee3f11034f --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "api-extractor-plugin", + "entryPoint": "./lib/ApiExtractorPlugin" + } + ] +} diff --git a/heft-plugins/heft-api-extractor-plugin/package.json b/heft-plugins/heft-api-extractor-plugin/package.json new file mode 100644 index 00000000000..ca233d7ba51 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rushstack/heft-api-extractor-plugin", + "version": "1.2.3", + "description": "A Heft plugin for API Extractor", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-api-extractor-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" + }, + "peerDependencies": { + "@rushstack/heft": "1.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "semver": "~7.5.4" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/semver": "7.5.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts new file mode 100644 index 00000000000..8ab77d46808 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as TApiExtractor from '@microsoft/api-extractor'; +import type { + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IHeftTaskSession, + HeftConfiguration, + IHeftTaskRunIncrementalHookOptions, + ConfigurationFile +} from '@rushstack/heft'; + +import { invokeApiExtractorAsync } from './ApiExtractorRunner'; +import apiExtractorConfigSchema from './schemas/api-extractor-task.schema.json'; + +// eslint-disable-next-line @rushstack/no-new-null +const UNINITIALIZED: null = null; + +const PLUGIN_NAME: string = 'api-extractor-plugin'; +const TASK_CONFIG_RELATIVE_PATH: string = './config/api-extractor-task.json'; +const EXTRACTOR_CONFIG_FILENAME: typeof TApiExtractor.ExtractorConfig.FILENAME = 'api-extractor.json'; +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; +} + +export interface IApiExtractorTaskConfiguration { + /** + * If set to true, use the project's TypeScript compiler version for API Extractor's + * analysis. API Extractor's included TypeScript compiler can generally correctly + * analyze typings generated by older compilers, and referencing the project's compiler + * can cause issues. If issues are encountered with API Extractor's included compiler, + * set this option to true. + * + * This corresponds to API Extractor's `--typescript-compiler-folder` CLI option and + * `IExtractorInvokeOptions.typescriptCompilerFolder` API option. This option defaults to false. + */ + useProjectTypescriptVersion?: boolean; + + /** + * 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 _printedWatchWarning: boolean = false; + + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + const runAsync = async ( + runOptions: IHeftTaskRunHookOptions & Partial + ): Promise => { + const result: IApiExtractorConfigurationResult | undefined = + await this._getApiExtractorConfigurationAsync(taskSession, heftConfiguration); + if (result) { + await this._runApiExtractorAsync( + taskSession, + heftConfiguration, + runOptions, + result.apiExtractorPackage, + result.apiExtractorConfiguration + ); + } + }; + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, runAsync); + taskSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, runAsync); + } + + private async _getApiExtractorConfigurationFilePathAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + if (this._apiExtractorConfigurationFilePath === UNINITIALIZED) { + this._apiExtractorConfigurationFilePath = + await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync(EXTRACTOR_CONFIG_RELATIVE_PATH); + if (this._apiExtractorConfigurationFilePath === undefined) { + this._apiExtractorConfigurationFilePath = + await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync( + LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH + ); + if (this._apiExtractorConfigurationFilePath !== undefined) { + taskSession.logger.emitWarning( + new Error( + `The "${LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH}" configuration file path is not supported ` + + `in Heft. Please move it to "${EXTRACTOR_CONFIG_RELATIVE_PATH}".` + ) + ); + } + } + } + return this._apiExtractorConfigurationFilePath; + } + + private async _getApiExtractorConfigurationAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + ignoreMissingEntryPoint?: boolean + ): Promise { + // API Extractor provides an ExtractorConfig.tryLoadForFolder() API that will probe for api-extractor.json + // including support for rig.json. However, Heft does not load the @microsoft/api-extractor package at all + // unless it sees a config/api-extractor.json file. Thus we need to do our own lookup here. + const apiExtractorConfigurationFilePath: string | undefined = + await this._getApiExtractorConfigurationFilePathAsync(taskSession, heftConfiguration); + if (!apiExtractorConfigurationFilePath) { + return undefined; + } + + // Since the config file exists, we can assume that API Extractor is available. Attempt to resolve + // and import the package. If the resolution fails, a helpful error is thrown. + const apiExtractorPackage: typeof TApiExtractor = await this._getApiExtractorPackageAsync( + taskSession, + heftConfiguration + ); + const apiExtractorConfigurationObject: TApiExtractor.IConfigFile = + apiExtractorPackage.ExtractorConfig.loadFile(apiExtractorConfigurationFilePath); + + // Load the configuration file. Always load from scratch. + const apiExtractorConfiguration: TApiExtractor.ExtractorConfig = + apiExtractorPackage.ExtractorConfig.prepare({ + ignoreMissingEntryPoint, + configObject: apiExtractorConfigurationObject, + configObjectFullPath: apiExtractorConfigurationFilePath, + packageJsonFullPath: `${heftConfiguration.buildFolderPath}/package.json`, + projectFolderLookupToken: heftConfiguration.buildFolderPath + }); + + return { apiExtractorPackage, apiExtractorConfiguration }; + } + + private async _getApiExtractorPackageAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + if (!this._apiExtractor) { + const apiExtractorPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + '@microsoft/api-extractor', + taskSession.logger.terminal + ); + this._apiExtractor = (await import(apiExtractorPackagePath)) as typeof TApiExtractor; + } + return this._apiExtractor; + } + + private async _runApiExtractorAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + runOptions: IHeftTaskRunHookOptions & Partial, + apiExtractor: typeof TApiExtractor, + apiExtractorConfiguration: TApiExtractor.ExtractorConfig + ): Promise { + const { + runInWatchMode, + useProjectTypescriptVersion, + printApiReportDiff: printApiReportDiffOption + } = (await heftConfiguration.tryLoadProjectConfigurationFileAsync( + API_EXTRACTOR_CONFIG_SPECIFICATION, + taskSession.logger.terminal + )) ?? {}; + + if (runOptions.requestRun) { + if (!runInWatchMode) { + if (!this._printedWatchWarning) { + this._printedWatchWarning = true; + taskSession.logger.terminal.writeWarningLine( + "API Extractor isn't currently enabled in watch mode." + ); + } + return; + } + } + + let typescriptPackagePath: string | undefined; + if (useProjectTypescriptVersion) { + typescriptPackagePath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + 'typescript', + taskSession.logger.terminal + ); + } + + 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, + scopedLogger: taskSession.logger, + printApiReportDiff + }); + } +} diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts new file mode 100644 index 00000000000..ae5fa860b2d --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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 * as TApiExtractor from '@microsoft/api-extractor'; + +export interface IApiExtractorRunnerConfiguration { + /** + * The root folder of the build. + */ + buildFolder: string; + + /** + * The loaded and prepared Extractor config file ("api-extractor.json") + */ + apiExtractorConfiguration: TApiExtractor.ExtractorConfig; + + /** + * The imported \@microsoft/api-extractor package + */ + apiExtractor: typeof TApiExtractor; + + /** + * The path to the typescript package + * + * For example, /home/username/code/repo/project/node_modules/typescript + */ + typescriptPackagePath: string | undefined; + + /** + * If set to true, run API Extractor in production mode + */ + production: boolean; + + /** + * 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 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`)); + } + + 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 (sourceFilePath) { + errorToEmit = new FileError(`(${messageId}) ${text}`, { + absolutePath: sourceFilePath, + projectFolder: buildFolder, + line: sourceFileLine, + column: sourceFileColumn + }); + } else { + errorToEmit = new Error(text); + } + + 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: ${logLevel}`); + } + } + + break; + } + + case apiExtractor.ExtractorLogLevel.Verbose: { + terminal.writeVerboseLine(text); + break; + } + + case apiExtractor.ExtractorLogLevel.Info: { + terminal.writeLine(text); + break; + } + + case apiExtractor.ExtractorLogLevel.None: { + // Ignore messages with ExtractorLogLevel.None + break; + } + + default: + scopedLogger.emitError(new Error(`Unexpected API Extractor log level: ${logLevel}`)); + } + + 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 new file mode 100644 index 00000000000..84e0fe3f689 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/src/schemas/api-extractor-task.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "API Extractor Task Configuration", + "description": "Defines additional Heft-specific configuration for the API Extractor task.", + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "useProjectTypescriptVersion": { + "type": "boolean", + "description": "If set to true, use the project's TypeScript compiler version for API Extractor's analysis. API Extractor's included TypeScript compiler can generally correctly analyze typings generated by older compilers, and referencing the project's compiler can cause issues. If issues are encountered with API Extractor's included compiler, set this option to true. This corresponds to API Extractor's --typescript-compiler-folder CLI option and IExtractorInvokeOptions.typescriptCompilerFolder API option. This option defaults to false." + }, + + "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 new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-dev-cert-plugin/.npmignore b/heft-plugins/heft-dev-cert-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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-dev-cert-plugin/CHANGELOG.json b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json new file mode 100644 index 00000000000..6767e165381 --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json @@ -0,0 +1,5518 @@ +{ + "name": "@rushstack/heft-dev-cert-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.4.78", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.78", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.4.77", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.77", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.4.76", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.76", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.4.75", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.75", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.4.74", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.74", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.4.73", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.73", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.4.72", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.72", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.4.71", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.71", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.4.70", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.70", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.4.69", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.69", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.4.68", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.68", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.4.67", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.67", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.4.66", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.66", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.66`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.4.65", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.65`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.4.64", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.64`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.4.63", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.63`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.4.62", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.62`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.4.61", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.61`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.4.60", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.60`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.4.59", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.59`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.4.58", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.4.57", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.57", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.57`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.4.56", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.4.55", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.55`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.4.54", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.54`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.4.53", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.53`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.4.52", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.52`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.4.51", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.51`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.4.50", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.50`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.4.49", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.49`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.4.48", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.48`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.4.47", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.47`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.4.46", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.46`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.4.45", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.45`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.4.44", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.44`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.4.43", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.43`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.4.42", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.42`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.4.41", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.41`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.4.40", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.40`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.4.39", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.39`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.4.38", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.4.37", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.36`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.35`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.34`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.33`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.32`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.31`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.29`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.28`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.26", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.56`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.25", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.55`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.24", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.23", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.22", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.21", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.51`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.20", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.19", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.18", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.48`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.17", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.16", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.15", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.45`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.14", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.13", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.43`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.12", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.42`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.11", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.10", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.9", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.39`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.8", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.7", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.6", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.5", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.4", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.3", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.2", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-dev-cert-plugin_v0.3.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.32", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.31", + "date": "Wed, 24 May 2023 00:19:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.28`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.30", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.29", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.28", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.27", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.26", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.25", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.24", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.23", + "date": "Mon, 17 Apr 2023 15:21:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.22", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.21", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.20", + "date": "Mon, 20 Mar 2023 20:14:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.19", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.18", + "date": "Fri, 03 Mar 2023 04:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.17", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.16", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.15", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.14", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.13", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.12", + "date": "Thu, 26 Jan 2023 02:55:09 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.11", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.10", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.9", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.8", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.7", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.6", + "date": "Fri, 18 Nov 2022 00:55:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.5", + "date": "Tue, 15 Nov 2022 23:31:49 GMT", + "comments": { + "patch": [ + { + "comment": "Fix Webpack auto-refresh issues caused by mismatched hostname" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.4", + "date": "Sat, 12 Nov 2022 00:16:31 GMT", + "comments": { + "patch": [ + { + "comment": "Serve the CA certificate alongside the TLS certificate." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.3", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.2", + "date": "Fri, 04 Nov 2022 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.1", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-dev-cert-plugin_v0.2.0", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "minor": [ + { + "comment": "Set allowedHosts from the subjectAltNames of the TLS certificate." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.73", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.73", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.84`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.1.72", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.72", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.83`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.1.71", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.71", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.82`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.1.70", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.70", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.81`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.1.69", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.69", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.80`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.1.68", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.68", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.79`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.1.67", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.67", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.78`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.1.66", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.66", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.1.65", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.65", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.76`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.1.64", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.64", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.75`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.1.63", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.63", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.74`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.1.62", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.62", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.73`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.1.61", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.61", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.72`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.1.60", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.60", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.59", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.59", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.58", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.69`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.57", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.68`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.56", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.67`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.55", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.66`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.54", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.65`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.53", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.64`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.52", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.63`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.51", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.62`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.50", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.61`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.49", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade webpack-dev-server" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.48", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.59`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.47", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.58`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.46", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.57`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.45", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.56`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.44", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.55`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.43", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.42", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.53`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.41", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.40", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.51`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.39", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.50`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.38", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.37", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.36", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.47`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.35", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.46`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.34", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.45`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.33", + "date": "Wed, 18 May 2022 15:10:55 GMT", + "comments": { + "patch": [ + { + "comment": "fix issue where webpack-dev-server v4 users recieved deprecation warnings" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.32", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.44`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.31", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.30", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.42`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.29", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.28", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.27", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.26", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.38`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.25", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.37`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.24", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.36`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.23", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.35`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.22", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.21", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.33`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.20", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.32`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.19", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.31`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.18", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.17", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.16", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.15", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.14", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.13", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.12", + "date": "Thu, 06 Jan 2022 08:49:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.24`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.11", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.10", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.9", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.8", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.7", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.6", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.5", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.4", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.3", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.2", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.1", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-dev-cert-plugin_v0.1.0", + "date": "Tue, 09 Nov 2021 16:08:07 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce the heft-dev-cert-plugin for https with webpack-dev-server." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.1.12`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md new file mode 100644 index 00000000000..977be8eadff --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md @@ -0,0 +1,1323 @@ +# Change Log - @rushstack/heft-dev-cert-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.4.78 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.4.77 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.4.76 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.4.75 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.4.74 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 0.4.73 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.4.72 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.4.71 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.4.70 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.69 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.4.68 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.4.67 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.4.66 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 0.4.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.4.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.4.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.4.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.4.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.4.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.4.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.4.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.57 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.4.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.4.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.4.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.4.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.4.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.4.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.4.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.4.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.4.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.4.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.4.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.4.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.4.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.4.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.4.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.4.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.4.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.4.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.4.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.4.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.4.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.4.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.4.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.4.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.4.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.4.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.4.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.4.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.4.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 0.4.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.4.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.4.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.4.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.4.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.4.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.4.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.4.18 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.4.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.4.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.4.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.4.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.4.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.4.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.4.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.4.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.4.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 0.4.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.4.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.4.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.4.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.4.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.4.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.4.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.4.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.3.26 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.3.25 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 0.3.24 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.3.23 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 0.3.22 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.3.21 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.3.20 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.3.19 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.3.18 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.3.17 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.3.16 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.3.15 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.3.14 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.3.13 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.3.12 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 0.3.11 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.3.10 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.3.9 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.3.8 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.3.7 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.3.6 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.3.5 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.3.4 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.3.3 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.3.2 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.3.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.3.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.2.32 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.31 +Wed, 24 May 2023 00:19:12 GMT + +_Version update only_ + +## 0.2.30 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.2.29 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.2.28 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.2.27 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.2.26 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 0.2.25 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.2.24 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.2.23 +Mon, 17 Apr 2023 15:21:31 GMT + +_Version update only_ + +## 0.2.22 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.2.21 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.2.20 +Mon, 20 Mar 2023 20:14:20 GMT + +_Version update only_ + +## 0.2.19 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.2.18 +Fri, 03 Mar 2023 04:11:20 GMT + +_Version update only_ + +## 0.2.17 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.2.16 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.2.15 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.2.14 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.2.13 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.2.12 +Thu, 26 Jan 2023 02:55:09 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.2.11 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.2.10 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.2.9 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.2.8 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.2.7 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.2.6 +Fri, 18 Nov 2022 00:55:17 GMT + +_Version update only_ + +## 0.2.5 +Tue, 15 Nov 2022 23:31:49 GMT + +### Patches + +- Fix Webpack auto-refresh issues caused by mismatched hostname + +## 0.2.4 +Sat, 12 Nov 2022 00:16:31 GMT + +### Patches + +- Serve the CA certificate alongside the TLS certificate. + +## 0.2.3 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.2.2 +Fri, 04 Nov 2022 00:15:59 GMT + +_Version update only_ + +## 0.2.1 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.2.0 +Tue, 25 Oct 2022 00:20:44 GMT + +### Minor changes + +- Set allowedHosts from the subjectAltNames of the TLS certificate. + +## 0.1.73 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.72 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.71 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.70 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.69 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.68 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.67 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.66 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.65 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.64 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.1.63 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.62 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.61 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.60 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.59 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.58 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.57 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.56 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.1.55 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.54 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.53 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.52 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.51 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.50 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.49 +Wed, 13 Jul 2022 21:31:13 GMT + +### Patches + +- Upgrade webpack-dev-server + +## 0.1.48 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 0.1.47 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.46 +Thu, 30 Jun 2022 04:48:53 GMT + +_Version update only_ + +## 0.1.45 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 0.1.44 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.43 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.42 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.41 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.40 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.39 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.1.38 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.37 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.36 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 0.1.35 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.1.34 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.1.33 +Wed, 18 May 2022 15:10:55 GMT + +### Patches + +- fix issue where webpack-dev-server v4 users recieved deprecation warnings + +## 0.1.32 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.1.31 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.1.30 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.1.29 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.1.28 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 0.1.27 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.1.26 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.1.25 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.1.24 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.1.23 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.1.22 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.1.21 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.1.20 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.1.19 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.1.18 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.1.17 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.1.16 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 0.1.15 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.1.14 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.1.13 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.1.12 +Thu, 06 Jan 2022 08:49:34 GMT + +_Version update only_ + +## 0.1.11 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.1.10 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.1.9 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.1.8 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.1.7 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.1.6 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.1.5 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.1.4 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 0.1.3 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.1.2 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.1.1 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.1.0 +Tue, 09 Nov 2021 16:08:07 GMT + +### Minor changes + +- Introduce the heft-dev-cert-plugin for https with webpack-dev-server. + diff --git a/heft-plugins/heft-dev-cert-plugin/LICENSE b/heft-plugins/heft-dev-cert-plugin/LICENSE new file mode 100644 index 00000000000..506de1faf1f --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-dev-cert-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-dev-cert-plugin/README.md b/heft-plugins/heft-dev-cert-plugin/README.md new file mode 100644 index 00000000000..9e874b9965b --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-dev-cert-plugin + +This is a Heft plugin to manage development certificates for local serve. +Automatically configures webpack-dev-server to use https in serve mode. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-dev-cert-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-dev-cert-plugin/config/rig.json b/heft-plugins/heft-dev-cert-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-dev-cert-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-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 new file mode 100644 index 00000000000..41e46022fcb --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/heft-plugin.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "lifecyclePlugins": [], + + "taskPlugins": [ + { + "pluginName": "trust-dev-certificate-plugin", + "entryPoint": "./lib/TrustDevCertificatePlugin" + }, + { + "pluginName": "untrust-dev-certificate-plugin", + "entryPoint": "./lib/UntrustDevCertificatePlugin" + } + ] +} diff --git a/heft-plugins/heft-dev-cert-plugin/package.json b/heft-plugins/heft-dev-cert-plugin/package.json new file mode 100644 index 00000000000..89b8077516b --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/package.json @@ -0,0 +1,30 @@ +{ + "name": "@rushstack/heft-dev-cert-plugin", + "version": "1.0.8", + "description": "A Heft plugin for generating and using local development certificates", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-dev-cert-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.1.7" + }, + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/heft-plugins/heft-dev-cert-plugin/src/TrustDevCertificatePlugin.ts b/heft-plugins/heft-dev-cert-plugin/src/TrustDevCertificatePlugin.ts new file mode 100644 index 00000000000..28adb9b010a --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/src/TrustDevCertificatePlugin.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 { CertificateManager } from '@rushstack/debug-certificate-manager'; +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; + +const PLUGIN_NAME: 'trust-dev-certificate-plugin' = 'trust-dev-certificate-plugin'; + +export default class TrustDevCertificatePlugin implements IHeftTaskPlugin { + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { logger } = taskSession; + const certificateManager: CertificateManager = new CertificateManager(); + + try { + await certificateManager.ensureCertificateAsync( + /* canGenerateNewCertificate: */ true, + logger.terminal + ); + logger.terminal.writeLine('Certificate successfully trusted.'); + } catch (err) { + logger.emitError(new Error(`Unable to generate or trust development certificate. Error: ${err}`)); + } + }); + } +} diff --git a/heft-plugins/heft-dev-cert-plugin/src/UntrustDevCertificatePlugin.ts b/heft-plugins/heft-dev-cert-plugin/src/UntrustDevCertificatePlugin.ts new file mode 100644 index 00000000000..706d162a82e --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/src/UntrustDevCertificatePlugin.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 { CertificateManager } from '@rushstack/debug-certificate-manager'; +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; + +const PLUGIN_NAME: 'untrust-dev-certificate-plugin' = 'untrust-dev-certificate-plugin'; + +export default class UntrustDevCertificatePlugin implements IHeftTaskPlugin { + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { logger } = taskSession; + const certificateManager: CertificateManager = new CertificateManager(); + + try { + await certificateManager.untrustCertificateAsync(logger.terminal); + logger.terminal.writeLine('Certificate successfully untrusted.'); + } catch (err) { + logger.emitError(new Error(`Unable to untrust development certificate. Error: ${err}`)); + } + }); + } +} diff --git a/heft-plugins/heft-dev-cert-plugin/tsconfig.json b/heft-plugins/heft-dev-cert-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} 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..bc349f9a4be --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..056cf802e9b --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.json @@ -0,0 +1,766 @@ +{ + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "entries": [ + { + "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..bd1ee213097 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md @@ -0,0 +1,181 @@ +# Change Log - @rushstack/heft-isolated-typescript-transpile-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..74590d3c4f8 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$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": 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..87563eea79e --- /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/SwcIsolatedTranspilePlugin", + "optionsSchema": "./lib/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..0e839be76d8 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/package.json @@ -0,0 +1,37 @@ +{ + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "version": "1.1.7", + "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/index.js", + "types": "dist/heft-isolated-typescript-transpile-plugin.d.ts", + "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.1.7", + "@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" + } +} 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/.npmignore b/heft-plugins/heft-jest-plugin/.npmignore new file mode 100644 index 00000000000..c672d8fde22 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/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 new file mode 100644 index 00000000000..fe469ebf94b --- /dev/null +++ b/heft-plugins/heft-jest-plugin/CHANGELOG.json @@ -0,0 +1,5430 @@ +{ + "name": "@rushstack/heft-jest-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/heft-jest-plugin_v0.14.0", + "date": "Tue, 10 Dec 2024 07:32:19 GMT", + "comments": { + "minor": [ + { + "comment": "Inject `punycode` into the NodeJS module cache in Node versions 22 and above to work around a deprecation warning." + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/heft-jest-plugin_v0.13.3", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/heft-jest-plugin_v0.13.2", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/heft-jest-plugin_v0.13.1", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug in `jest-node-modules-symlink-resolver` with respect to evaluating paths that don't exist. Expected behavior in that situation is to return the input path." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/heft-jest-plugin_v0.13.0", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "minor": [ + { + "comment": "Add a custom resolver that only resolves symlinks that are within node_modules." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.12.18", + "tag": "@rushstack/heft-jest-plugin_v0.12.18", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.12.17", + "tag": "@rushstack/heft-jest-plugin_v0.12.17", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.12.16", + "tag": "@rushstack/heft-jest-plugin_v0.12.16", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.12.15", + "tag": "@rushstack/heft-jest-plugin_v0.12.15", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/heft-jest-plugin_v0.12.14", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/heft-jest-plugin_v0.12.13", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/heft-jest-plugin_v0.12.12", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/heft-jest-plugin_v0.12.11", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/heft-jest-plugin_v0.12.10", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/heft-jest-plugin_v0.12.9", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/heft-jest-plugin_v0.12.8", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/heft-jest-plugin_v0.12.7", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/heft-jest-plugin_v0.12.6", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/heft-jest-plugin_v0.12.5", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/heft-jest-plugin_v0.12.4", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/heft-jest-plugin_v0.12.3", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/heft-jest-plugin_v0.12.2", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/heft-jest-plugin_v0.12.1", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/heft-jest-plugin_v0.12.0", + "date": "Tue, 11 Jun 2024 00:21:28 GMT", + "comments": { + "minor": [ + { + "comment": "Update the test reporter to report unchecked snapshots." + } + ] + } + }, + { + "version": "0.11.39", + "tag": "@rushstack/heft-jest-plugin_v0.11.39", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.11.38", + "tag": "@rushstack/heft-jest-plugin_v0.11.38", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.11.37", + "tag": "@rushstack/heft-jest-plugin_v0.11.37", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.11.36", + "tag": "@rushstack/heft-jest-plugin_v0.11.36", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.11.35", + "tag": "@rushstack/heft-jest-plugin_v0.11.35", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.11.34", + "tag": "@rushstack/heft-jest-plugin_v0.11.34", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.11.33", + "tag": "@rushstack/heft-jest-plugin_v0.11.33", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.11.32", + "tag": "@rushstack/heft-jest-plugin_v0.11.32", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.11.31", + "tag": "@rushstack/heft-jest-plugin_v0.11.31", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.11.30", + "tag": "@rushstack/heft-jest-plugin_v0.11.30", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.11.29", + "tag": "@rushstack/heft-jest-plugin_v0.11.29", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.11.28", + "tag": "@rushstack/heft-jest-plugin_v0.11.28", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.11.27", + "tag": "@rushstack/heft-jest-plugin_v0.11.27", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.11.26", + "tag": "@rushstack/heft-jest-plugin_v0.11.26", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.11.25", + "tag": "@rushstack/heft-jest-plugin_v0.11.25", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.11.24", + "tag": "@rushstack/heft-jest-plugin_v0.11.24", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.11.23", + "tag": "@rushstack/heft-jest-plugin_v0.11.23", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.11.22", + "tag": "@rushstack/heft-jest-plugin_v0.11.22", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.11.21", + "tag": "@rushstack/heft-jest-plugin_v0.11.21", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.11.20", + "tag": "@rushstack/heft-jest-plugin_v0.11.20", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.11.19", + "tag": "@rushstack/heft-jest-plugin_v0.11.19", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.11.18", + "tag": "@rushstack/heft-jest-plugin_v0.11.18", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.11.17", + "tag": "@rushstack/heft-jest-plugin_v0.11.17", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/heft-jest-plugin_v0.11.16", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/heft-jest-plugin_v0.11.15", + "date": "Mon, 26 Feb 2024 16:10:56 GMT", + "comments": { + "patch": [ + { + "comment": "Make `@rushstack/terminal` a dependency because the reporter has a runtime dependency on that package." + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/heft-jest-plugin_v0.11.14", + "date": "Thu, 22 Feb 2024 05:54:17 GMT", + "comments": { + "patch": [ + { + "comment": "Add a missing dependency on `@rushstack/terminal`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/heft-jest-plugin_v0.11.13", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/heft-jest-plugin_v0.11.12", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/heft-jest-plugin_v0.11.11", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/heft-jest-plugin_v0.11.10", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/heft-jest-plugin_v0.11.9", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/heft-jest-plugin_v0.11.8", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/heft-jest-plugin_v0.11.7", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/heft-jest-plugin_v0.11.6", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/heft-jest-plugin_v0.11.5", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/heft-jest-plugin_v0.11.4", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/heft-jest-plugin_v0.11.3", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/heft-jest-plugin_v0.11.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft-jest-plugin_v0.11.1", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft-jest-plugin_v0.11.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/heft-jest-plugin_v0.10.8", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/heft-jest-plugin_v0.10.7", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/heft-jest-plugin_v0.10.6", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/heft-jest-plugin_v0.10.5", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/heft-jest-plugin_v0.10.4", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/heft-jest-plugin_v0.10.3", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/heft-jest-plugin_v0.10.2", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/heft-jest-plugin_v0.10.1", + "date": "Thu, 26 Oct 2023 00:27:48 GMT", + "comments": { + "patch": [ + { + "comment": "Add an option (`enableNodeEnvManagement`) to ensure that the NODE_ENV environment variable is set to `\"test\"` during test execution." + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-jest-plugin_v0.10.0", + "date": "Mon, 23 Oct 2023 15:18:38 GMT", + "comments": { + "minor": [ + { + "comment": "Use Jest verbose logging when `heft --debug test` or `heft test --verbose` is specified" + }, + { + "comment": "Fix an issue where `silent: true` was ignored when specified in `jest.config.json`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/heft-jest-plugin_v0.9.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/heft-jest-plugin_v0.9.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/heft-jest-plugin_v0.9.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/heft-jest-plugin_v0.9.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/heft-jest-plugin_v0.9.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/heft-jest-plugin_v0.9.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-jest-plugin_v0.9.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-jest-plugin_v0.9.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-jest-plugin_v0.9.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-jest-plugin_v0.9.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `--log-heap-usage` flag that includes memory usage analysis in each test run." + }, + { + "comment": "Update @types/node from 14 to 18" + } + ], + "patch": [ + { + "comment": "Wait for first test run to be scheduled in initial invocation in watch mode." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-jest-plugin_v0.8.1", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-jest-plugin_v0.8.0", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "minor": [ + { + "comment": "Make `jest-environment-jsdom` and `jest-environment-node` optional peerDependencies." + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/heft-jest-plugin_v0.7.18", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/heft-jest-plugin_v0.7.17", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/heft-jest-plugin_v0.7.16", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/heft-jest-plugin_v0.7.15", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/heft-jest-plugin_v0.7.14", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/heft-jest-plugin_v0.7.13", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/heft-jest-plugin_v0.7.12", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/heft-jest-plugin_v0.7.11", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/heft-jest-plugin_v0.7.10", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/heft-jest-plugin_v0.7.9", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/heft-jest-plugin_v0.7.8", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-jest-plugin_v0.7.7", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for using '-u' for the '--update-snapshots' parameter and '-t' for the '--test-name-pattern' parameter" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-jest-plugin_v0.7.6", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/heft-jest-plugin_v0.7.5", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "patch": [ + { + "comment": "Added --test-path-ignore-patterns support for subtractive test selection to complement existing additive support." + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-jest-plugin_v0.7.4", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-jest-plugin_v0.7.3", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-jest-plugin_v0.7.2", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-jest-plugin_v0.7.1", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-jest-plugin_v0.7.0", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "minor": [ + { + "comment": "Adds a new base config for web projects, jest-web.config.json. Adds the \"customExportConditions\" field to both base configs with sensible defaults." + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-jest-plugin_v0.6.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/heft-jest-plugin_v0.5.13", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/heft-jest-plugin_v0.5.12", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/heft-jest-plugin_v0.5.11", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/heft-jest-plugin_v0.5.10", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/heft-jest-plugin_v0.5.9", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "patch": [ + { + "comment": "Allow \"preset\" configuration value to be used when extending Jest configuration files" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/heft-jest-plugin_v0.5.8", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/heft-jest-plugin_v0.5.7", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/heft-jest-plugin_v0.5.6", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade Jest to 29.5.0." + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/heft-jest-plugin_v0.5.5", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/heft-jest-plugin_v0.5.4", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-jest-plugin_v0.5.3", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-jest-plugin_v0.5.2", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-jest-plugin_v0.5.1", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-jest-plugin_v0.5.0", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest from `~27.4.2` to `~29.3.1`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-jest-plugin_v0.4.5", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-jest-plugin_v0.4.4", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-jest-plugin_v0.4.3", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-jest-plugin_v0.4.2", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-jest-plugin_v0.4.1", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-jest-plugin_v0.4.0", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "minor": [ + { + "comment": "Remove a postinstall step that patches Jest in-place. This is better achieved with a PNPM patch. See https://github.com/microsoft/rushstack/pull/3790 for more information." + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/heft-jest-plugin_v0.3.45", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/heft-jest-plugin_v0.3.44", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/heft-jest-plugin_v0.3.43", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/heft-jest-plugin_v0.3.42", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/heft-jest-plugin_v0.3.41", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/heft-jest-plugin_v0.3.40", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/heft-jest-plugin_v0.3.39", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/heft-jest-plugin_v0.3.38", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/heft-jest-plugin_v0.3.37", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/heft-jest-plugin_v0.3.36", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/heft-jest-plugin_v0.3.35", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/heft-jest-plugin_v0.3.34", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/heft-jest-plugin_v0.3.33", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/heft-jest-plugin_v0.3.32", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/heft-jest-plugin_v0.3.31", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/heft-jest-plugin_v0.3.30", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "patch": [ + { + "comment": "Hide disabling Jest cache behind environment variable \"HEFT_JEST_DISABLE_CACHE\"" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-jest-plugin_v0.3.29", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "patch": [ + { + "comment": "Disable reading and writing of Jest cache due to unexpected caching behavior" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-jest-plugin_v0.3.28", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-jest-plugin_v0.3.27", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-jest-plugin_v0.3.26", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-jest-plugin_v0.3.25", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-jest-plugin_v0.3.24", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-jest-plugin_v0.3.23", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-jest-plugin_v0.3.22", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-jest-plugin_v0.3.21", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-jest-plugin_v0.3.20", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-jest-plugin_v0.3.19", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-jest-plugin_v0.3.18", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-jest-plugin_v0.3.17", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-jest-plugin_v0.3.16", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-jest-plugin_v0.3.15", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-jest-plugin_v0.3.14", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-jest-plugin_v0.3.13", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-jest-plugin_v0.3.12", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-jest-plugin_v0.3.11", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-jest-plugin_v0.3.10", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-jest-plugin_v0.3.9", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-jest-plugin_v0.3.8", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-jest-plugin_v0.3.7", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Fix resolution of \"jest-environment-node\" and \"jest-environment-jsdom\" with strict dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-jest-plugin_v0.3.6", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-jest-plugin_v0.3.5", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-jest-plugin_v0.3.4", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-jest-plugin_v0.3.3", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-jest-plugin_v0.3.2", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-jest-plugin_v0.3.1", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-jest-plugin_v0.3.0", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Enable clearMocks: true by default" + } + ], + "patch": [ + { + "comment": "Add command-line flag for disabling code coverage." + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-jest-plugin_v0.2.15", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-jest-plugin_v0.2.14", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-jest-plugin_v0.2.13", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-jest-plugin_v0.2.12", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-jest-plugin_v0.2.11", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-jest-plugin_v0.2.10", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-jest-plugin_v0.2.9", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-jest-plugin_v0.2.8", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-jest-plugin_v0.2.7", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-jest-plugin_v0.2.6", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-jest-plugin_v0.2.5", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-jest-plugin_v0.2.4", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-jest-plugin_v0.2.3", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "patch": [ + { + "comment": "Update JSON schema documentation" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-jest-plugin_v0.2.2", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-jest-plugin_v0.2.1", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-jest-plugin_v0.2.0", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest to v27" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/heft-jest-plugin_v0.1.53", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/heft-jest-plugin_v0.1.52", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/heft-jest-plugin_v0.1.51", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/heft-jest-plugin_v0.1.50", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/heft-jest-plugin_v0.1.49", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/heft-jest-plugin_v0.1.48", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/heft-jest-plugin_v0.1.47", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/heft-jest-plugin_v0.1.46", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/heft-jest-plugin_v0.1.45", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/heft-jest-plugin_v0.1.44", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/heft-jest-plugin_v0.1.43", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/heft-jest-plugin_v0.1.42", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/heft-jest-plugin_v0.1.41", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/heft-jest-plugin_v0.1.40", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/heft-jest-plugin_v0.1.39", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/heft-jest-plugin_v0.1.38", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/heft-jest-plugin_v0.1.37", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/heft-jest-plugin_v0.1.36", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/heft-jest-plugin_v0.1.35", + "date": "Tue, 05 Oct 2021 15:08:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-jest-plugin_v0.1.34", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-jest-plugin_v0.1.33", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-jest-plugin_v0.1.32", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-jest-plugin_v0.1.31", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-jest-plugin_v0.1.30", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-jest-plugin_v0.1.29", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-jest-plugin_v0.1.28", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.4` to `^0.38.0`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-jest-plugin_v0.1.27", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.3` to `^0.37.4`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-jest-plugin_v0.1.26", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.2` to `^0.37.3`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-jest-plugin_v0.1.25", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.1` to `^0.37.2`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-jest-plugin_v0.1.24", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.0` to `^0.37.1`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-jest-plugin_v0.1.23", + "date": "Fri, 03 Sep 2021 00:09:09 GMT", + "comments": { + "patch": [ + { + "comment": "Use package name as Jest 'displayName' by default and always log a test duration." + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-jest-plugin_v0.1.22", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.4` to `^0.37.0`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-jest-plugin_v0.1.21", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.3` to `^0.36.4`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-jest-plugin_v0.1.20", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.36.3`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-jest-plugin_v0.1.19", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.1` to `^0.36.2`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-jest-plugin_v0.1.18", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.0` to `^0.36.1`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-jest-plugin_v0.1.17", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.1` to `^0.36.0`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-jest-plugin_v0.1.16", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.0` to `^0.35.1`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-jest-plugin_v0.1.15", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.8` to `^0.35.0`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-jest-plugin_v0.1.14", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.7` to `^0.34.8`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-jest-plugin_v0.1.13", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.6` to `^0.34.7`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-jest-plugin_v0.1.12", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.5` to `^0.34.6`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-jest-plugin_v0.1.11", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.4` to `^0.34.5`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-jest-plugin_v0.1.10", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.3` to `^0.34.4`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-jest-plugin_v0.1.9", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.2` to `^0.34.3`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-jest-plugin_v0.1.8", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "patch": [ + { + "comment": "Fix Jest configuration merging of \"transform\" and \"moduleNameMapper\" fields" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-jest-plugin_v0.1.7", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.1` to `^0.34.2`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-jest-plugin_v0.1.6", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "patch": [ + { + "comment": "Improve resolution logic to match closer to default Jest functionality and add \"\" and \"\" tokens to improve flexibility when using extended configuration files" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.0` to `^0.34.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-jest-plugin_v0.1.5", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.1` to `^0.34.0`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-jest-plugin_v0.1.4", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where \"testEnvironment\" did not resolve correctly (GitHub #2745)" + }, + { + "comment": "Enable \"@rushstack/heft-jest-plugin/lib/exports/jest-global-setup.js\" to resolve for rigged projects that don't have a direct dependency on that package" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-jest-plugin_v0.1.3", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an incorrect \"peerDependencies\" entry that caused installation failures (GitHub #2754)" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-jest-plugin_v0.1.2", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "patch": [ + { + "comment": "Resolve the \"testEnvironment\" Jest configuration property in jest.config.json" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-jest-plugin_v0.1.1", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "patch": [ + { + "comment": "Initial implementation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.5.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-jest-plugin/CHANGELOG.md b/heft-plugins/heft-jest-plugin/CHANGELOG.md new file mode 100644 index 00000000000..d9a51e259a7 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/CHANGELOG.md @@ -0,0 +1,1511 @@ +# Change Log - @rushstack/heft-jest-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.14.0 +Tue, 10 Dec 2024 07:32:19 GMT + +### Minor changes + +- Inject `punycode` into the NodeJS module cache in Node versions 22 and above to work around a deprecation warning. + +## 0.13.3 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.13.2 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.13.1 +Sat, 23 Nov 2024 01:18:55 GMT + +### Patches + +- Fix a bug in `jest-node-modules-symlink-resolver` with respect to evaluating paths that don't exist. Expected behavior in that situation is to return the input path. + +## 0.13.0 +Fri, 22 Nov 2024 01:10:43 GMT + +### Minor changes + +- Add a custom resolver that only resolves symlinks that are within node_modules. + +## 0.12.18 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.12.17 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.12.16 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.12.15 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.12.14 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.12.13 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.12.12 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.12.11 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.12.10 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.12.9 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.12.8 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.12.7 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.12.6 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.12.5 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.12.4 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.12.3 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.12.2 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.12.1 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.12.0 +Tue, 11 Jun 2024 00:21:28 GMT + +### Minor changes + +- Update the test reporter to report unchecked snapshots. + +## 0.11.39 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.11.38 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.11.37 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.11.36 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.11.35 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.11.34 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.11.33 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.11.32 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.11.31 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.11.30 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.11.29 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.11.28 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.11.27 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.11.26 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.11.25 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.11.24 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.11.23 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.11.22 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.11.21 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.11.20 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.11.19 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.11.18 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.11.17 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.11.16 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.11.15 +Mon, 26 Feb 2024 16:10:56 GMT + +### Patches + +- Make `@rushstack/terminal` a dependency because the reporter has a runtime dependency on that package. + +## 0.11.14 +Thu, 22 Feb 2024 05:54:17 GMT + +### Patches + +- Add a missing dependency on `@rushstack/terminal` + +## 0.11.13 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.11.12 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.11.11 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.11.10 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.11.9 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.11.8 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.11.7 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.11.6 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.11.5 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.11.4 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.11.3 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.11.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.11.1 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.11.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 + +## 0.10.8 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.10.7 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.10.6 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.10.5 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.10.4 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.10.3 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.10.2 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.10.1 +Thu, 26 Oct 2023 00:27:48 GMT + +### Patches + +- Add an option (`enableNodeEnvManagement`) to ensure that the NODE_ENV environment variable is set to `"test"` during test execution. + +## 0.10.0 +Mon, 23 Oct 2023 15:18:38 GMT + +### Minor changes + +- Use Jest verbose logging when `heft --debug test` or `heft test --verbose` is specified +- Fix an issue where `silent: true` was ignored when specified in `jest.config.json` + +## 0.9.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.9.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.9.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.9.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.9.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.9.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.9.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.9.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.9.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.9.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Add a `--log-heap-usage` flag that includes memory usage analysis in each test run. +- Update @types/node from 14 to 18 + +### Patches + +- Wait for first test run to be scheduled in initial invocation in watch mode. + +## 0.8.1 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.8.0 +Mon, 31 Jul 2023 15:19:05 GMT + +### Minor changes + +- Make `jest-environment-jsdom` and `jest-environment-node` optional peerDependencies. + +## 0.7.18 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.7.17 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.7.16 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.7.15 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.7.14 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.7.13 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.7.12 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.7.11 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.7.10 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.7.9 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.7.8 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.7.7 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Add support for using '-u' for the '--update-snapshots' parameter and '-t' for the '--test-name-pattern' parameter + +## 0.7.6 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.7.5 +Fri, 09 Jun 2023 15:23:15 GMT + +### Patches + +- Added --test-path-ignore-patterns support for subtractive test selection to complement existing additive support. + +## 0.7.4 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.7.3 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.7.2 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.7.1 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.7.0 +Tue, 06 Jun 2023 02:52:51 GMT + +### Minor changes + +- Adds a new base config for web projects, jest-web.config.json. Adds the "customExportConditions" field to both base configs with sensible defaults. + +## 0.6.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.5.13 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.5.12 +Mon, 22 May 2023 06:34:32 GMT + +_Version update only_ + +## 0.5.11 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.5.10 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.5.9 +Mon, 01 May 2023 15:23:19 GMT + +### Patches + +- Allow "preset" configuration value to be used when extending Jest configuration files + +## 0.5.8 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 0.5.7 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.5.6 +Tue, 04 Apr 2023 22:36:28 GMT + +### Patches + +- Upgrade Jest to 29.5.0. + +## 0.5.5 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.5.4 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.5.3 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.5.2 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.5.1 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.5.0 +Mon, 30 Jan 2023 00:55:44 GMT + +### Minor changes + +- Upgrade Jest from `~27.4.2` to `~29.3.1` + +## 0.4.5 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.4.4 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.4.3 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.4.2 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.4.1 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.4.0 +Tue, 29 Nov 2022 01:16:49 GMT + +### Minor changes + +- Remove a postinstall step that patches Jest in-place. This is better achieved with a PNPM patch. See https://github.com/microsoft/rushstack/pull/3790 for more information. + +## 0.3.45 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 0.3.44 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.3.43 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.3.42 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.3.41 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.3.40 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.3.39 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.3.38 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.3.37 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.3.36 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.3.35 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.3.34 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.3.33 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.3.32 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.3.31 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.3.30 +Wed, 31 Aug 2022 01:45:06 GMT + +### Patches + +- Hide disabling Jest cache behind environment variable "HEFT_JEST_DISABLE_CACHE" + +## 0.3.29 +Wed, 31 Aug 2022 00:42:46 GMT + +### Patches + +- Disable reading and writing of Jest cache due to unexpected caching behavior + +## 0.3.28 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.3.27 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.3.26 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.3.25 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.3.24 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.3.23 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.3.22 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.3.21 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.3.20 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.3.19 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.3.18 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.3.17 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.3.16 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.3.15 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 0.3.14 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.3.13 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.3.12 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.3.11 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.3.10 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.3.9 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.3.8 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.3.7 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Fix resolution of "jest-environment-node" and "jest-environment-jsdom" with strict dependencies. + +## 0.3.6 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.3.5 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.3.4 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.3.3 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.3.2 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.3.1 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.3.0 +Tue, 26 Apr 2022 00:10:15 GMT + +### Minor changes + +- (BREAKING CHANGE) Enable clearMocks: true by default + +### Patches + +- Add command-line flag for disabling code coverage. + +## 0.2.15 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 0.2.14 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.2.13 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.2.12 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.2.11 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.2.10 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.2.9 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.2.8 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.2.7 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.2.6 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.2.5 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.2.4 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.2.3 +Fri, 11 Feb 2022 10:30:25 GMT + +### Patches + +- Update JSON schema documentation + +## 0.2.2 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.2.1 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.2.0 +Tue, 14 Dec 2021 19:27:51 GMT + +### Minor changes + +- Upgrade Jest to v27 + +## 0.1.53 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.1.52 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.1.51 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.1.50 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.1.49 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 0.1.48 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.1.47 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.1.46 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.1.45 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.1.44 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.1.43 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.1.42 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.1.41 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.1.40 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.1.39 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.1.38 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.1.37 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.1.36 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.1.35 +Tue, 05 Oct 2021 15:08:37 GMT + +_Version update only_ + +## 0.1.34 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.1.33 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.1.32 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.1.31 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.1.30 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.1.29 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.1.28 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.1.27 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.1.26 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.1.25 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.1.24 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.1.23 +Fri, 03 Sep 2021 00:09:09 GMT + +### Patches + +- Use package name as Jest 'displayName' by default and always log a test duration. + +## 0.1.22 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.1.21 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.1.20 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.1.19 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.1.18 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.1.17 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.1.16 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.1.15 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 0.1.14 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.1.13 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.1.12 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.1.11 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.1.10 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.1.9 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.1.8 +Wed, 30 Jun 2021 19:16:19 GMT + +### Patches + +- Fix Jest configuration merging of "transform" and "moduleNameMapper" fields + +## 0.1.7 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.1.6 +Wed, 30 Jun 2021 01:37:17 GMT + +### Patches + +- Improve resolution logic to match closer to default Jest functionality and add "" and "" tokens to improve flexibility when using extended configuration files + +## 0.1.5 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.1.4 +Fri, 18 Jun 2021 06:23:05 GMT + +### Patches + +- Fix a regression where "testEnvironment" did not resolve correctly (GitHub #2745) +- Enable "@rushstack/heft-jest-plugin/lib/exports/jest-global-setup.js" to resolve for rigged projects that don't have a direct dependency on that package + +## 0.1.3 +Wed, 16 Jun 2021 18:53:52 GMT + +### Patches + +- Fix an incorrect "peerDependencies" entry that caused installation failures (GitHub #2754) + +## 0.1.2 +Fri, 11 Jun 2021 23:26:16 GMT + +### Patches + +- Resolve the "testEnvironment" Jest configuration property in jest.config.json + +## 0.1.1 +Fri, 11 Jun 2021 00:34:02 GMT + +### Patches + +- Initial implementation + diff --git a/heft-plugins/heft-jest-plugin/LICENSE b/heft-plugins/heft-jest-plugin/LICENSE new file mode 100644 index 00000000000..01c459d5139 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-jest-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-jest-plugin/README.md b/heft-plugins/heft-jest-plugin/README.md new file mode 100644 index 00000000000..25f82e5ef62 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-jest-plugin + +This is a Heft plugin for running Jest. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-jest-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-jest-plugin/UPGRADING.md b/heft-plugins/heft-jest-plugin/UPGRADING.md new file mode 100644 index 00000000000..db10be2aabc --- /dev/null +++ b/heft-plugins/heft-jest-plugin/UPGRADING.md @@ -0,0 +1,29 @@ +# Upgrade notes for @rushstack/heft-jest-plugin + +### 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. + +This release of `heft-jest-plugin` switched from using Jest's transformer infrastructure and pointing at TypeScript source files to instead directly point Jest at the compiled output files, relying on source maps to redirect snapshot files back to the committed source folder. If no source maps are present, the plugin will assume that the project is authored in raw ECMAScript and expect to find snapshots in a `__snapshots__` folder directly alongside the test files. + +### Version 0.3.0 + +This release of `heft-jest-plugin` enabled Jest's `clearMocks` option by default. +If your project didn't already have this option turned on, it is possible that +previously passing unit tests will fail after the upgrade. + +If you do have failing unit tests, then most likely the assertions in the test +were incorrect, because the number of calls and call parameters were not being +cleared between tests. The ideal solution is to correct these assertions. + +If you can't immediately address the failing unit tests, you can turn `clearMocks` +back off in your `config/jest.config.json` file: + +```json +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + + "clearMocks": false +} +``` + +For more information on the `clearMocks` option, see [Jest's clearMocks documentation](https://jestjs.io/docs/configuration#clearmocks-boolean). 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 new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/heft-plugins/heft-jest-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": "decoupled-local-node-rig" +} 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 new file mode 100644 index 00000000000..c43c7a81092 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/heft-plugin.json @@ -0,0 +1,89 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "jest-plugin", + "entryPoint": "./lib/JestPlugin", + "optionsSchema": "./lib/schemas/heft-jest-plugin.schema.json", + + "parameterScope": "jest", + "parameters": [ + { + "longName": "--config", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which Jest configuration file will be used to run Jest tests. If not specified, it will default to \"config/jest.config.json\". This corresponds to the \"--config\" parameter in Jest's documentation." + }, + { + "longName": "--debug-heft-reporter", + "parameterKind": "flag", + "description": "Normally Heft installs a custom Jest reporter so that test results are presented consistently with other task logging. If you suspect a problem with the HeftJestReporter, specify \"--debug-heft-reporter\" to temporarily disable it so that you can compare with how Jest's default reporter would have presented it. Include this output in your bug report. Do not use \"--debug-heft-reporter\" in production." + }, + { + "longName": "--detect-open-handles", + "parameterKind": "flag", + "description": "Attempt to collect and print open handles preventing Jest from exiting cleanly. This option has a significant performance penalty and should only be used for debugging. This corresponds to the \"--detectOpenHandles\" parameter in Jest's documentation." + }, + { + "longName": "--disable-code-coverage", + "parameterKind": "flag", + "description": "Disable any configured code coverage. If code coverage is not configured, this parameter has no effect." + }, + { + "longName": "--find-related-tests", + "parameterKind": "stringList", + "argumentName": "SOURCE_FILE", + "description": "Find and run the tests that cover a source file that was passed in as an argument. This corresponds to the \"--findRelatedTests\" parameter in Jest's documentation. This parameter is not compatible with watch mode." + }, + { + "longName": "--log-heap-usage", + "parameterKind": "flag", + "description": "Logs the heap usage after every test. Useful to debug memory leaks. Use together with --expose-gc in node." + }, + { + "longName": "--max-workers", + "parameterKind": "string", + "argumentName": "COUNT_OR_PERCENTAGE", + "description": "Use this parameter to control maximum number of worker processes tests are allowed to use. This parameter is similar to the parameter noted in the Jest documentation, and can either be an integer representing the number of workers to spawn when running tests, or can be a string representing a percentage of the available CPUs on the machine to utilize. Example values: \"3\", \"25%%\"" + }, + { + "longName": "--silent", + "parameterKind": "flag", + "description": "Prevent tests from printing messages through the console. This corresponds to the \"--silent\" parameter in Jest's documentation." + }, + { + "longName": "--test-name-pattern", + "shortName": "-t", + "parameterKind": "string", + "argumentName": "REGEXP", + "description": "Run only tests with a name that matches a regular expression. The REGEXP is matched against the full name, which is a combination of the test name and all its surrounding describe blocks. This corresponds to the \"--testNamePattern\" parameter in Jest's documentation." + }, + { + "longName": "--test-path-ignore-patterns", + "parameterKind": "string", + "argumentName": "REGEXP", + "description": "Avoid running tests with a source file path that matches one ore more regular expressions. On Windows you will need to use \"/\" instead of \"\\\". This corresponds to the \"--testPathIgnorePatterns\" parameter in Jest's documentation." + }, + { + "longName": "--test-path-pattern", + "parameterKind": "string", + "argumentName": "REGEXP", + "description": "Run only tests with a source file path that matches a regular expression. On Windows you will need to use \"/\" instead of \"\\\". This corresponds to the \"--testPathPattern\" parameter in Jest's documentation." + }, + { + "longName": "--test-timeout-ms", + "parameterKind": "integer", + "argumentName": "TIMEOUT", + "description": "Change the default timeout for tests; if a test doesn't complete within this many milliseconds, it will fail. Individual tests can override the default. If unspecified, the default is normally 5000 ms. This corresponds to the \"--testTimeout\" parameter in Jest's documentation." + }, + { + "longName": "--update-snapshots", + "shortName": "-u", + "parameterKind": "flag", + "description": "Update Jest snapshots while running the tests. This corresponds to the \"--updateSnapshots\" parameter in Jest." + } + ] + } + ] +} diff --git a/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json b/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json new file mode 100644 index 00000000000..766c8c5608e --- /dev/null +++ b/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json @@ -0,0 +1,85 @@ +{ + // THIS SHARED JEST CONFIGURATION FILE IS INTENDED TO BE REFERENCED BY THE JEST CONFIGURATION IN + // CONSUMING PACKAGE AND REQUIRES PRESET-RELATIVE MODULE RESOLUTION TO BE ENABLED. IF YOU HAVE + // DISABLED THIS FEATURE YOU MUST CREATE YOUR OWN JEST CONFIGURATION + + // By default, don't hide console output + "silent": false, + + // In order for HeftJestReporter to receive console.log() events, we must set verbose=false + "verbose": false, + + // If mocks are not cleared between tests, it opens the door to accidental reliance on + // ordering of tests or describe blocks, eventually resulting in intermittent failures. + // + // We suggest this setting for any heft project (in a monorepo or not). + "clearMocks": true, + + // "Adding '/lib' here enables lib/__mocks__ to be used for mocking Node.js system modules + "roots": ["/lib"], + + "testMatch": ["/lib/**/*.test.{cjs,js}"], + "testPathIgnorePatterns": ["/node_modules/"], + + // Code coverage tracking is disabled by default; set this to true to enable it + "collectCoverage": false, + + "coverageDirectory": "/temp/coverage", + + // Use V8 instead of Babel to avoid the overhead of instrumenting code + "coverageProvider": "v8", + + "collectCoverageFrom": [ + "lib/**/*.{cjs,js}", + "!lib/**/*.d.ts", + "!lib/**/*.test.{cjs,js}", + "!lib/**/test/**", + "!lib/**/__tests__/**", + "!lib/**/__fixtures__/**", + "!lib/**/__mocks__/**" + ], + "coveragePathIgnorePatterns": ["/node_modules/"], + + "testEnvironment": "jest-environment-node", + + "testEnvironmentOptions": { + "url": "http://localhost/", + "customExportConditions": ["require", "node"] + }, + + // Retain pre-Jest 29 snapshot behavior + "snapshotFormat": { + "escapeString": true, + "printBasicPrototype": true + }, + + "snapshotResolver": "../lib/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, 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", + + "\\.(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" + }, + + // The modulePathIgnorePatterns below accepts these sorts of paths: + // - /lib + // - /lib/file.js + // ...and ignores anything else under + "modulePathIgnorePatterns": [], + + // Prefer .cjs to .js to catch explicit commonjs output. Optimize for local files, which will be .js + "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" +} diff --git a/heft-plugins/heft-jest-plugin/includes/jest-web.config.json b/heft-plugins/heft-jest-plugin/includes/jest-web.config.json new file mode 100644 index 00000000000..0780a8d2d2f --- /dev/null +++ b/heft-plugins/heft-jest-plugin/includes/jest-web.config.json @@ -0,0 +1,37 @@ +{ + "extends": "./jest-shared.config.json", + + "testEnvironment": "jest-environment-jsdom", + + "testEnvironmentOptions": { + "url": "http://localhost/", + + // For web projects, we write ESM output (with "import" statements") into the "lib" folder + // to be processed by Webpack or other tree-shaking bundlers. + // We also write CommonJS output (with "require()" calls") into the "lib-commonjs" folder + // to be processed by Jest. We do this because the Jest requires the --experimental-vm-modules flag + // in order to load ESM, and also because the interop story between CommonJS and ESM in NodeJs is + // very finicky. + // + // The jest-environment-jsdom package now sets "customExportConditions" to ["browser"], + // which often selects an ESM entry point when resolving packages. This is incorrect for + // our setup. The setting below fixes that. For details, refer to these docs: + // https://nodejs.org/api/packages.html#conditional-exports + "customExportConditions": ["require", "node", "umd"] + }, + + // For web projects, `lib/` is normally ESM, so we route to the CommonJS output in `lib-commonjs/` instead. + "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__/**" + ] +} diff --git a/heft-plugins/heft-jest-plugin/package.json b/heft-plugins/heft-jest-plugin/package.json new file mode 100644 index 00000000000..cd72ee46fe1 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/package.json @@ -0,0 +1,55 @@ +{ + "name": "@rushstack/heft-jest-plugin", + "version": "1.1.7", + "description": "Heft plugin for Jest", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-jest-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.1.7", + "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", + "@jest/reporters": "~29.5.0", + "@jest/transform": "~29.5.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" + }, + "devDependencies": { + "@jest/types": "29.5.0", + "@rushstack/heft": "workspace:*", + "@types/lodash": "4.14.116", + "@types/node": "20.17.19", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "jest-environment-jsdom": "~29.5.0", + "jest-environment-node": "~29.5.0", + "jest-watch-select-projects": "2.0.0" + } +} diff --git a/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts new file mode 100644 index 00000000000..3f4e7089c3c --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts @@ -0,0 +1,248 @@ +// 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 { + Reporter, + Test, + TestResult, + AggregatedResult, + TestContext, + ReporterOnStartOptions, + 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 { + heftConfiguration: HeftConfiguration; + logger: IScopedLogger; + debugMode: boolean; +} + +/** + * This custom reporter presents Jest test results using Heft's logging system. + * + * @privateRemarks + * After making changes to this code, it's recommended to use `--debug-heft-reporter` to compare + * with the output from Jest's default reporter, to check our output is consistent with typical + * Jest behavior. + * + * For reference, Jest's default implementation is here: + * https://github.com/facebook/jest/blob/main/packages/jest-reporters/src/default_reporter.ts + */ +export default class HeftJestReporter implements Reporter { + private _terminal: ITerminal; + private _buildFolderPath: string; + private _debugMode: boolean; + + public constructor(jestConfig: Config.GlobalConfig, options: IHeftJestReporterOptions) { + this._terminal = options.logger.terminal; + this._buildFolderPath = options.heftConfiguration.buildFolderPath; + this._debugMode = options.debugMode; + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + public async onTestStart(test: Test): Promise { + this._terminal.writeLine( + Colorize.whiteBackground(Colorize.black('START')), + ` ${this._getTestPath(test.path)}` + ); + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + public async onTestResult( + test: Test, + testResult: TestResult, + aggregatedResult: AggregatedResult + ): Promise { + this._writeConsoleOutput(testResult); + const { + numPassingTests, + numFailingTests, + failureMessage, + testExecError, + perfStats, + memoryUsage, + snapshot: { updated: updatedSnapshots, added: addedSnapshots, unchecked: uncheckedSnapshots } + } = testResult; + + // Calculate the suite duration time from the test result. This is necessary because Jest doesn't + // provide the duration on the 'test' object (at least not as of Jest 25), and other reporters + // (ex. jest-junit) only use perfStats: + // https://github.com/jest-community/jest-junit/blob/12da1a20217a9b6f30858013175319c1256f5b15/utils/buildJsonResults.js#L112 + const duration: string = perfStats ? `${((perfStats.end - perfStats.start) / 1000).toFixed(3)}s` : '?'; + + // calculate memoryUsage to MB reference -> https://jestjs.io/docs/cli#--logheapusage + const memUsage: string = memoryUsage ? `, ${Math.floor(memoryUsage / 1000000)}MB heap size` : ''; + + const message: string = + ` ${this._getTestPath(test.path)} ` + + `(duration: ${duration}, ${numPassingTests} passed, ${numFailingTests} failed${memUsage})`; + + if (numFailingTests > 0) { + this._terminal.writeLine(Colorize.redBackground(Colorize.black('FAIL')), message); + } else if (testExecError) { + this._terminal.writeLine( + Colorize.redBackground(Colorize.black(`FAIL (${testExecError.type})`)), + message + ); + } else { + this._terminal.writeLine(Colorize.greenBackground(Colorize.black('PASS')), message); + } + + if (failureMessage) { + this._terminal.writeErrorLine(failureMessage); + } + + if (updatedSnapshots) { + this._terminal.writeErrorLine( + `Updated ${this._formatWithPlural(updatedSnapshots, 'snapshot', 'snapshots')}` + ); + } + + if (addedSnapshots) { + this._terminal.writeErrorLine( + `Added ${this._formatWithPlural(addedSnapshots, 'snapshot', 'snapshots')}` + ); + } + + if (uncheckedSnapshots) { + this._terminal.writeWarningLine( + `${this._formatWithPlural(uncheckedSnapshots, 'snapshot was', 'snapshots were')} not checked` + ); + } + } + + // Tests often write messy console output. For example, it may contain messages such as + // "ERROR: Test successfully threw an exception!", which may confuse someone who is investigating + // a build failure and searching its log output for errors. To reduce confusion, we add a prefix + // like "|console.error|" to each output line, to clearly distinguish test logging from regular + // task output. You can suppress test logging entirely using the "--silent" CLI parameter. + private _writeConsoleOutput(testResult: TestResult): void { + if (testResult.console) { + for (const logEntry of testResult.console) { + switch (logEntry.type) { + case 'debug': + this._writeConsoleOutputWithLabel('console.debug', logEntry.message); + break; + case 'log': + this._writeConsoleOutputWithLabel('console.log', logEntry.message); + break; + case 'warn': + this._writeConsoleOutputWithLabel('console.warn', logEntry.message); + break; + case 'error': + this._writeConsoleOutputWithLabel('console.error', logEntry.message); + break; + case 'info': + this._writeConsoleOutputWithLabel('console.info', logEntry.message); + break; + + case 'groupCollapsed': + if (this._debugMode) { + // The "groupCollapsed" name is too long + this._writeConsoleOutputWithLabel('collapsed', logEntry.message); + } + break; + + case 'assert': + case 'count': + case 'dir': + case 'dirxml': + case 'group': + case 'time': + if (this._debugMode) { + this._writeConsoleOutputWithLabel( + logEntry.type, + `(${logEntry.type}) ${logEntry.message}`, + true + ); + } + break; + default: + // Let's trap any new log types that get introduced in the future to make sure we handle + // them correctly. + throw new InternalError('Unimplemented Jest console log entry type: ' + logEntry.type); + } + } + } + } + + private _writeConsoleOutputWithLabel(label: string, message: string, debug?: boolean): void { + if (message === '') { + return; + } + const scrubbedMessage: string = Text.ensureTrailingNewline(Text.convertToLf(message)); + const lines: string[] = scrubbedMessage.split('\n').slice(0, -1); + + const PAD_LENGTH: number = 13; // "console.error" is the longest label + + const paddedLabel: string = '|' + label.padStart(PAD_LENGTH) + '|'; + const prefix: string = debug ? Colorize.yellow(paddedLabel) : Colorize.cyan(paddedLabel); + + for (const line of lines) { + this._terminal.writeLine(prefix, ' ' + line); + } + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + public async onRunStart( + aggregatedResult: AggregatedResult, + options: ReporterOnStartOptions + ): Promise { + // Jest prints some text that changes the console's color without a newline, so we reset the console's color here + // and print a newline. + this._terminal.writeLine('\u001b[0m'); + this._terminal.writeLine( + `Run start. ${this._formatWithPlural(aggregatedResult.numTotalTestSuites, 'test suite', 'test suites')}` + ); + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + public async onRunComplete(contexts: Set, results: AggregatedResult): Promise { + const { + numPassedTests, + numFailedTests, + numTotalTests, + numRuntimeErrorTestSuites, + snapshot: { uncheckedKeysByFile: uncheckedSnapshotsByFile } + } = results; + + this._terminal.writeLine(); + this._terminal.writeLine('Tests finished:'); + + const successesText: string = ` Successes: ${numPassedTests}`; + this._terminal.writeLine(numPassedTests > 0 ? Colorize.green(successesText) : successesText); + + const failText: string = ` Failures: ${numFailedTests}`; + this._terminal.writeLine(numFailedTests > 0 ? Colorize.red(failText) : failText); + + if (numRuntimeErrorTestSuites) { + this._terminal.writeLine(Colorize.red(` Failed test suites: ${numRuntimeErrorTestSuites}`)); + } + + if (uncheckedSnapshotsByFile.length > 0) { + this._terminal.writeWarningLine( + ` Test suites with unchecked snapshots: ${uncheckedSnapshotsByFile.length}` + ); + } + + this._terminal.writeLine(` Total: ${numTotalTests}`); + } + + public getLastError(): void { + // This reporter doesn't have any errors to throw + } + + private _getTestPath(fullTestPath: string): string { + return path.relative(this._buildFolderPath, fullTestPath); + } + + private _formatWithPlural(num: number, singular: string, plural: string): string { + return `${num} ${num === 1 ? singular : plural}`; + } +} diff --git a/heft-plugins/heft-jest-plugin/src/HeftJestResolver.ts b/heft-plugins/heft-jest-plugin/src/HeftJestResolver.ts new file mode 100644 index 00000000000..6168a667f40 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/HeftJestResolver.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. + +// This signature is declared here: +// https://github.com/facebook/jest/blob/c76f9a7c8eb2fab1a15dfe8952d125a8607d1bbe/packages/jest-resolve/src/defaultResolver.ts#L26 +interface IResolverOptions { + basedir: string; + browser?: boolean; + conditions?: Array; + defaultResolver: (path: string, options: IResolverOptions) => string; + extensions?: Array; + moduleDirectory?: Array; + paths?: Array; + rootDir?: string; + packageFilter?: unknown; // (pkg: PkgJson, dir: string) => PkgJson + pathFilter?: unknown; // (pkg: PkgJson, path: string, relativePath: string) => string +} + +// Match Jest's magic convention for specifying a mock: +// +// YES: ../__mocks__/Thing +// YES: ./__mocks__/Thing.js +// +// Do not match other objects deeper in the tree +// NO: ./__mocks__/folder/Thing.js +// +// Do not match paths belong to an external package: +// NO: some-package/__mocks__/Thing +const mockPathRegExp: RegExp = /^(\..*[\/])__mocks__\/([^\/]+)$/; + +function resolve(request: string, options: IResolverOptions): string { + let newRequest: string = request; + + // Jest's manual mock feature works by looking for a matching filename in a "__mocks__" subfolder, + // like this: + // + // file exports + // ------------------------------ ------------------------ + // path/to/MyClass.ts MyClass + // path/to/__mocks__/MyClass.ts MyClass, mockedMember + // + // At runtime, the Jest will substitute "__mocks__/MyClass.ts" for the real "MyClass.ts". Often the mock + // needs to export additional test helpers like mockedMember. Because Jest was not designed for type safety, + // the Jest documentation shows examples like this: + // + // jest.mock("./path/to/MyClass"); + // import { MyClass, mockedMember } from "./path/to/MyClass"; + // + // But that won't work with TypeScript, because "mockedMember" is not declared by the real MyClass.ts. + // For proper type safety, we need write it like this: + // + // jest.mock("./path/to/MyClass"); + // import { MyClass } from "./path/to/MyClass"; + // import { mockedMember } from "./path/to/__mocks__/MyClass"; + // + // ...or equivalently: + // + // jest.mock("./path/to/MyClass"); + // import { MyClass, mockedMember } from "./path/to/__mocks__/MyClass"; + // + // Unfortunately when Jest substitutes path/to/__mocks__/MyClass.ts for path/to/MyClass.ts, it doesn't tell + // the module resolver about this, so "./path/to/__mocks__/MyClass" produces a duplicate object and the test fails. + // The code below fixes that problem, ensuring that the two import paths resolve to the same module object. + // + // Documentation: + // https://jestjs.io/docs/en/manual-mocks + // https://jestjs.io/docs/en/es6-class-mocks#manual-mock + const match: RegExpExecArray | null = mockPathRegExp.exec(request); + if (match) { + // Example: + // request = "../__mocks__/Thing" + // match[1] = "../" + // match[2] = "Thing" + // newRequest = "../Thing" + newRequest = match[1] + match[2]; + } + + return options.defaultResolver(newRequest, options); +} + +export = resolve; diff --git a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts new file mode 100644 index 00000000000..5bf31ed257e --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts @@ -0,0 +1,1097 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Load the Jest patches before anything else loads +import './patches/jestWorkerPatch'; + +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, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions, + CommandLineFlagParameter, + CommandLineIntegerParameter, + CommandLineStringParameter, + CommandLineStringListParameter +} from '@rushstack/heft'; +import { + ProjectConfigurationFile, + type ICustomJsonPathMetadata, + type IJsonPathMetadataResolverOptions, + InheritanceType, + PathResolutionMethod +} from '@rushstack/heft-config-file'; +import { FileSystem, Path, Import, JsonFile, PackageName } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { IHeftJestReporterOptions } from './HeftJestReporter'; +import { jestResolve } from './JestUtils'; +import { TerminalWritableStream } from './TerminalWritableStream'; +import anythingSchema from './schemas/anything.schema.json'; + +const jestPluginSymbol: unique symbol = Symbol('heft-jest-plugin'); +interface IWithJestPlugin { + [jestPluginSymbol]?: JestPlugin; +} + +interface IReadConfigsResult { + globalConfig: Config.GlobalConfig; +} + +interface IReadConfigs { + (argv: Config.Argv, projectPaths: string[]): Promise; +} + +interface IRunJestParams { + globalConfig: Config.GlobalConfig; + onComplete: (result: AggregatedResult) => void; +} + +interface IJestWatch { + ( + initialGlobalConfig: Config.GlobalConfig, + contexts: unknown, + outputStream: NodeJS.WriteStream, + hasteMapInstances: EventEmitter[], + stdin: NodeJS.ReadStream | undefined, + hooks: unknown, + filter: unknown + ): Promise; +} + +type JestReporterConfig = string | Config.ReporterConfig; + +/** + * Options to use when performing resolution for paths and modules specified in the Jest + * configuration. + */ +interface IJestResolutionOptions { + /** + * The value that will be substituted for tokens. + */ + rootDir: string; + /** + * Whether the value should be resolved as a module relative to the configuration file after + * substituting special tokens. + */ + resolveAsModule?: boolean; +} + +/** + * Options that can be provided to the plugin. + */ +export interface IJestPluginOptions { + configurationPath?: string; + debugHeftReporter?: boolean; + detectOpenHandles?: boolean; + disableCodeCoverage?: boolean; + disableConfigurationModuleResolution?: boolean; + enableNodeEnvManagement?: boolean; + findRelatedTests?: string[]; + maxWorkers?: string; + passWithNoTests?: boolean; + silent?: boolean; + testNamePattern?: string; + testPathIgnorePatterns?: string; + testPathPattern?: string; + testTimeout?: number; + updateSnapshots?: boolean; + logHeapUsage?: boolean; +} + +export interface IHeftJestConfiguration extends Config.InitialOptions {} + +interface IHeftJestConfigurationWithExtends extends IHeftJestConfiguration { + extends?: string; +} + +interface IExtendedHeftJestConfiguration extends IHeftJestConfiguration { + extends: string | undefined; +} + +const PLUGIN_NAME: 'jest-plugin' = 'jest-plugin'; +const PLUGIN_PACKAGE_NAME: '@rushstack/heft-jest-plugin' = '@rushstack/heft-jest-plugin'; +const PLUGIN_PACKAGE_FOLDER: string = path.resolve(__dirname, '..'); +const JEST_CONFIGURATION_LOCATION: 'config/jest.config.json' = `config/jest.config.json`; +export const JEST_CONFIG_JSDOM_PACKAGE_NAME: 'jest-environment-jsdom' = 'jest-environment-jsdom'; + +const ROOTDIR_TOKEN: '' = ''; +const CONFIGDIR_TOKEN: '' = ''; +const PACKAGE_CAPTUREGROUP: 'package' = 'package'; +const PACKAGEDIR_REGEX: RegExp = /^[^\s>]+)\s*>/; +const JSONPATHPROPERTY_REGEX: RegExp = /^\$\['([^']+)'\]/; + +const JEST_CONFIG_PACKAGE_FOLDER: string = path.dirname(require.resolve('jest-config')); + +interface IPendingTestRun { + (): Promise; +} + +/** + * @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; + + private _jestOutputStream: TerminalWritableStream | undefined; + private _changedFiles: Set = new Set(); + private _requestRun!: () => void; + private _nodeEnvSet: boolean | undefined; + + private _resolveFirstRunQueued!: () => void; + private _firstRunQueuedPromise: Promise; + + public constructor() { + this._firstRunQueuedPromise = new Promise((resolve) => { + this._resolveFirstRunQueued = resolve; + }); + } + + public static getJestPlugin(object: object): JestPlugin | undefined { + return (object as IWithJestPlugin)[jestPluginSymbol]; + } + + /** + * Setup the hooks and custom CLI options for the Jest plugin. + * + * @override + */ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions?: IJestPluginOptions + ): void { + const { parameters } = taskSession; + + // Flags + const detectOpenHandlesParameter: CommandLineFlagParameter = + parameters.getFlagParameter('--detect-open-handles'); + const debugHeftReporterParameter: CommandLineFlagParameter = + parameters.getFlagParameter('--debug-heft-reporter'); + const disableCodeCoverageParameter: CommandLineFlagParameter = + parameters.getFlagParameter('--disable-code-coverage'); + const silentParameter: CommandLineFlagParameter = parameters.getFlagParameter('--silent'); + const updateSnapshotsParameter: CommandLineFlagParameter = + parameters.getFlagParameter('--update-snapshots'); + const logHeapUsageParameter: CommandLineFlagParameter = parameters.getFlagParameter('--log-heap-usage'); + + // Strings + const configParameter: CommandLineStringParameter = parameters.getStringParameter('--config'); + const maxWorkersParameter: CommandLineStringParameter = parameters.getStringParameter('--max-workers'); + const testNamePatternParameter: CommandLineStringParameter = + parameters.getStringParameter('--test-name-pattern'); + const testPathIgnorePatternsParameter: CommandLineStringParameter = parameters.getStringParameter( + '--test-path-ignore-patterns' + ); + const testPathPatternParameter: CommandLineStringParameter = + parameters.getStringParameter('--test-path-pattern'); + + // String lists + const findRelatedTestsParameter: CommandLineStringListParameter = + parameters.getStringListParameter('--find-related-tests'); + + // Integers + const testTimeoutParameter: CommandLineIntegerParameter = + parameters.getIntegerParameter('--test-timeout-ms'); + + const options: IJestPluginOptions = { + ...pluginOptions, + configurationPath: configParameter.value || pluginOptions?.configurationPath, + debugHeftReporter: debugHeftReporterParameter.value || pluginOptions?.debugHeftReporter, + detectOpenHandles: detectOpenHandlesParameter.value || pluginOptions?.detectOpenHandles, + disableCodeCoverage: disableCodeCoverageParameter.value || pluginOptions?.disableCodeCoverage, + logHeapUsage: logHeapUsageParameter.value || pluginOptions?.logHeapUsage, + findRelatedTests: findRelatedTestsParameter.values.length + ? Array.from(findRelatedTestsParameter.values) + : pluginOptions?.findRelatedTests, + maxWorkers: maxWorkersParameter.value || pluginOptions?.maxWorkers, + // Default to true and always pass with no tests + passWithNoTests: true, + silent: silentParameter.value || pluginOptions?.silent, + testNamePattern: testNamePatternParameter.value || pluginOptions?.testNamePattern, + testPathIgnorePatterns: testPathIgnorePatternsParameter.value || pluginOptions?.testPathIgnorePatterns, + testPathPattern: testPathPatternParameter.value || pluginOptions?.testPathPattern, + testTimeout: testTimeoutParameter.value ?? pluginOptions?.testTimeout, + updateSnapshots: updateSnapshotsParameter.value || pluginOptions?.updateSnapshots, + enableNodeEnvManagement: pluginOptions?.enableNodeEnvManagement ?? true + }; + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + await this._runJestAsync(taskSession, heftConfiguration, options); + }); + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runJestWatchAsync( + taskSession, + heftConfiguration, + options, + runIncrementalOptions.requestRun + ); + } + ); + } + + /** + * Runs Jest using the provided options. + */ + private async _runJestAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IJestPluginOptions + ): Promise { + const logger: IScopedLogger = taskSession.logger; + const terminal: ITerminal = logger.terminal; + + this._setNodeEnvIfRequested(options, logger); + + const { getVersion, runCLI } = await import(`@jest/core`); + terminal.writeLine(`Using Jest version ${getVersion()}`); + + const buildFolderPath: string = heftConfiguration.buildFolderPath; + const jestArgv: Config.Argv | undefined = await this._createJestArgvAsync( + taskSession, + heftConfiguration, + options, + false + ); + if (!jestArgv) { + return; + } + + const { + // Config.Argv is weakly typed. After updating the jestArgv object, it's a good idea to inspect "globalConfig" + // in the debugger to validate that your changes are being applied as expected. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + globalConfig, + results: jestResults + } = await runCLI(jestArgv, [buildFolderPath]); + + this._resetNodeEnv(); + + if (jestResults.numFailedTests > 0) { + logger.emitError( + new Error( + `${jestResults.numFailedTests} Jest test${jestResults.numFailedTests > 1 ? 's' : ''} failed` + ) + ); + } else if (jestResults.numFailedTestSuites > 0) { + logger.emitError( + new Error( + `${jestResults.numFailedTestSuites} Jest test suite${ + jestResults.numFailedTestSuites > 1 ? 's' : '' + } failed` + ) + ); + } + } + + /** + * Runs Jest using the provided options. + */ + private async _runJestWatchAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IJestPluginOptions, + requestRun: () => void + ): Promise { + const logger: IScopedLogger = taskSession.logger; + const terminal: ITerminal = logger.terminal; + + const pendingTestRuns: Set = this._pendingTestRuns; + this._requestRun = requestRun; + + if (!this._jestPromise) { + // Monkey-patch Jest's watch mode so that we can orchestrate it. + const jestCoreDir: string = path.dirname(require.resolve('@jest/core')); + + const jestConfigPath: string = require.resolve('jest-config', { + paths: [jestCoreDir] + }); + const jestConfigModule: { + readConfigs: IReadConfigs; + } = require(jestConfigPath); + const { readConfigs: originalReadConfigs } = jestConfigModule; + // eslint-disable-next-line func-style + const readConfigs: typeof originalReadConfigs = async function wrappedReadConfigs( + this: void, + argv: Config.Argv, + projectPaths: string[] + ): Promise { + const host: JestPlugin | undefined = JestPlugin.getJestPlugin(argv); + const result: IReadConfigsResult = await originalReadConfigs(argv, projectPaths); + // Forward the JestPlugin instance from argv. + const extendedGlobalConfig: Config.GlobalConfig & IWithJestPlugin = Object.freeze({ + ...result.globalConfig, + [jestPluginSymbol]: host + }); + + return { + // There are other properties on this object + ...result, + globalConfig: extendedGlobalConfig + }; + }; + Object.defineProperty(jestConfigModule, 'readConfigs', { + get: () => readConfigs + }); + + const wrappedStdOut: TerminalWritableStream = new TerminalWritableStream(terminal); + this._jestOutputStream = wrappedStdOut; + + // Shim watch so that we can intercept the output stream + const watchModulePath: string = path.resolve(jestCoreDir, 'watch.js'); + const watchModule: { + default: IJestWatch; + } = require(watchModulePath); + const { default: originalWatch } = watchModule; + + // eslint-disable-next-line func-style + const watch: IJestWatch = function patchedWatch( + this: void, + initialGlobalConfig: Config.GlobalConfig, + contexts: unknown, + outputStream: NodeJS.WriteStream, + hasteMapInstances: EventEmitter[], + stdin: NodeJS.ReadStream | undefined, + hooks: unknown, + filter: unknown + ): Promise { + // Extract the host JestPlugin. This is plumbed through on the config rather than captured + // in a closure to avoid binding global state to the current plugin instance. + const host: JestPlugin | undefined = JestPlugin.getJestPlugin(initialGlobalConfig); + if (!host || !(host instanceof JestPlugin)) { + throw new Error(`Patched Jest expected JestPlugin on globalConfig`); + } + + // Listen to the haste maps directly to get the list of touched files + hasteMapInstances.forEach((hasteMap: EventEmitter, index: number) => { + hasteMap.on('change', ({ eventsQueue }: { eventsQueue: { filePath: string }[] }) => { + for (const file of eventsQueue) { + // Record all changed files for the next test run + host._changedFiles.add(file.filePath); + } + }); + }); + + return originalWatch( + initialGlobalConfig, + contexts, + host._jestOutputStream as unknown as NodeJS.WriteStream, + hasteMapInstances, + stdin, + hooks, + filter + ); + }; + Object.defineProperty(watchModule, 'default', { + get(): typeof originalWatch { + return watch; + } + }); + + // Shim runJest so that we can defer test execution + const runJestModulePath: string = path.resolve(jestCoreDir, 'runJest.js'); + const runJestModule: { + default: (params: IRunJestParams) => Promise; + } = require(runJestModulePath); + const { default: originalRunJest } = runJestModule; + // eslint-disable-next-line func-style + const runJest: typeof originalRunJest = function patchedRunJest( + this: void, + params: IRunJestParams + ): Promise { + const host: JestPlugin | undefined = JestPlugin.getJestPlugin(params.globalConfig); + if (!host || !(host instanceof JestPlugin)) { + throw new Error(`Patched Jest expected JestPlugin on globalConfig`); + } + + if (!host._executing) { + host._requestRun(); + } + + return new Promise((resolve: () => void, reject: (err: Error) => void) => { + host._pendingTestRuns.add(async (): Promise => { + let result: AggregatedResult | undefined; + const { onComplete } = params; + + const findRelatedTests: boolean = params.globalConfig.onlyChanged && host._changedFiles.size > 0; + + const globalConfig: IRunJestParams['globalConfig'] = Object.freeze({ + ...params.globalConfig, + // Use the knowledge of changed files to implement the "onlyChanged" behavior via + // findRelatedTests and the list of changed files + findRelatedTests, + nonFlagArgs: findRelatedTests ? Array.from(host._changedFiles) : [], + // This property can only be true when the files are tracked directly by Git + // Since we run tests on compiled files, this is not the case. + onlyChanged: false + }); + + try { + await originalRunJest({ + ...params, + globalConfig, + onComplete: (testResults: AggregatedResult) => { + result = testResults; + onComplete(testResults); + } + }); + resolve(); + } catch (err) { + reject(err); + throw err; + } + + return result; + }); + host._resolveFirstRunQueued(); + }); + }; + + Object.defineProperty(runJestModule, 'default', { + get(): typeof originalRunJest { + return runJest; + } + }); + + const { getVersion, runCLI } = await import(`@jest/core`); + terminal.writeLine(`Using Jest version ${getVersion()}`); + + const buildFolderPath: string = heftConfiguration.buildFolderPath; + const jestArgv: Config.Argv | undefined = await this._createJestArgvAsync( + taskSession, + heftConfiguration, + options, + true + ); + if (!jestArgv) { + this._jestPromise = Promise.resolve(); + return; + } + + this._jestPromise = runCLI(jestArgv, [buildFolderPath]); + } + + // Wait for the initial run to be queued. + await this._firstRunQueuedPromise; + // Explicitly wait an async tick for any file watchers + await Promise.resolve(); + + if (pendingTestRuns.size > 0) { + this._setNodeEnvIfRequested(options, logger); + + this._executing = true; + for (const pendingTestRun of pendingTestRuns) { + pendingTestRuns.delete(pendingTestRun); + const jestResults: AggregatedResult | undefined = await pendingTestRun(); + if (jestResults) { + if (jestResults.numFailedTests > 0) { + logger.emitError( + new Error( + `${jestResults.numFailedTests} Jest test${jestResults.numFailedTests > 1 ? 's' : ''} failed` + ) + ); + } else if (jestResults.numFailedTestSuites > 0) { + logger.emitError( + new Error( + `${jestResults.numFailedTestSuites} Jest test suite${ + jestResults.numFailedTestSuites > 1 ? 's' : '' + } failed` + ) + ); + } + } else { + terminal.writeLine(`No tests were executed.`); + } + } + + this._resetNodeEnv(); + + if (!logger.hasErrors) { + // If we ran tests and they succeeded, consider the files to no longer be changed. + // This might be overly-permissive, but there isn't a great way to identify if the changes + // are no longer relevant, unfortunately. + this._changedFiles.clear(); + } + this._executing = false; + } else { + terminal.writeLine(`No pending test runs.`); + } + } + + private async _createJestArgvAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IJestPluginOptions, + watch: boolean + ): Promise { + const logger: IScopedLogger = taskSession.logger; + const { terminal } = logger; + + const buildFolderPath: string = heftConfiguration.buildFolderPath; + const projectRelativeFilePath: string = options?.configurationPath ?? JEST_CONFIGURATION_LOCATION; + let jestConfig: IHeftJestConfiguration; + if (options?.disableConfigurationModuleResolution) { + // Module resolution explicitly disabled, use the config as-is + const jestConfigPath: string = path.join(buildFolderPath, projectRelativeFilePath); + if (!(await FileSystem.existsAsync(jestConfigPath))) { + logger.emitError(new Error(`Expected to find jest config file at "${jestConfigPath}".`)); + return; + } + jestConfig = await JsonFile.loadAsync(jestConfigPath); + const extendedJestConfig: IExtendedHeftJestConfiguration = jestConfig as IExtendedHeftJestConfiguration; + if (extendedJestConfig.extends) { + throw new Error( + 'The provided jest.config.json specifies an "extends" property while resolved modules are disabled. ' + + 'You must either remove the "extends" property from your Jest configuration, use the "preset" ' + + 'property, or set the "disableConfigurationModuleResolution" option to "false" on the Jest ' + + 'plugin in heft.json.' + ); + } + } else { + // Load in and resolve the config file using the "extends" field + jestConfig = await JestPlugin._getJestConfigurationLoader( + buildFolderPath, + projectRelativeFilePath + ).loadConfigurationFileForProjectAsync( + terminal, + heftConfiguration.buildFolderPath, + heftConfiguration.rigConfig + ); + } + + // If no displayName is provided, use the package name. This field is used by Jest to + // differentiate in multi-project repositories, and since we have the context, we may + // as well provide it. + if (!jestConfig.displayName) { + jestConfig.displayName = heftConfiguration.projectPackageJson.name; + } + + let silent: boolean | undefined; + if (taskSession.parameters.verbose || taskSession.parameters.debug) { + // If Heft's "--verbose" or "--debug" parameters were used, then we're debugging Jest problems, + // so we always want to see "console.log()" even if jest.config.json asked to suppress it. + // If someone really dislikes that, we could expose "--silent" in the Heft CLI, + // but it is a confusing combination. + silent = false; + } else { + // If "silent" is specified via IJestPluginOptions, that takes precedence over jest.config.json + silent = options.silent ?? jestConfig.silent ?? false; + } + + const jestArgv: Config.Argv = { + // In debug mode, avoid forking separate processes that are difficult to debug + runInBand: taskSession.parameters.debug, + debug: taskSession.parameters.debug, + detectOpenHandles: options.detectOpenHandles || false, + logHeapUsage: options.logHeapUsage || false, + + // Use the temp folder. Cache is unreliable, so we want it cleared on every --clean run + cacheDirectory: taskSession.tempFolderPath, + updateSnapshot: options.updateSnapshots, + + listTests: false, + rootDir: buildFolderPath, + + // What these fields mean for Jest: + // + // If "silent" is true: + // - Jest discards all console.log() output and there is no way to retrieve it + // + // If "silent" is false and "verbose" is false: + // - Jest uses BufferedConsole which doesn't show console.log() until after the test run completes, + // which is annoying in the debugger. The output is formatted nicely using HeftJestReporter. + // + // If "silent" is false and "verbose" is true: + // - Jest uses CustomConsole which logs immediately, but shows ugly call stacks with each log. + // + // If "verbose" is true (regardless of "silent"): + // - Jest reports include detailed results for every test, even if all tests passed within a test suite. + silent, + verbose: taskSession.parameters.verbose || taskSession.parameters.debug, + + testNamePattern: options.testNamePattern, + testPathIgnorePatterns: options.testPathIgnorePatterns ? [options.testPathIgnorePatterns] : undefined, + testPathPattern: options.testPathPattern ? [options.testPathPattern] : undefined, + testTimeout: options.testTimeout, + maxWorkers: options.maxWorkers, + + passWithNoTests: options.passWithNoTests, + + [jestPluginSymbol]: this, + + $0: process.argv0, + _: [], + + watchAll: watch + }; + + 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 + ); + } else { + logger.emitWarning( + new Error('The "--debug-heft-reporter" parameter was specified; disabling HeftJestReporter') + ); + } + + if (options.findRelatedTests?.length) { + // Pass test names as the command line remainder + jestArgv.findRelatedTests = true; + jestArgv._ = [...options.findRelatedTests]; + } + + if (options.disableCodeCoverage) { + jestConfig.collectCoverage = false; + } + + // Stringify the config and pass it into Jest directly + jestArgv.config = JSON.stringify(jestConfig); + + return jestArgv; + } + + /** + * Returns the loader for the `config/api-extractor-task.json` config file. + */ + public static _getJestConfigurationLoader( + buildFolder: string, + projectRelativeFilePath: string + ): ProjectConfigurationFile { + if (!JestPlugin._jestConfigurationFileLoader) { + // By default, ConfigurationFile will replace all objects, so we need to provide merge functions for these + const shallowObjectInheritanceFunc: | undefined>( + currentObject: T, + parentObject: T + ) => 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 + // "\\.(css|sass|scss)$" transform but the extending Jest configuration contains a "\\.(css)$" transform, + // merging like this will ensure that the returned transforms are executed in the correct order, stopping + // after hitting the first pattern that applies: + // { + // "\\.(css)$": "...", + // "\\.(css|sass|scss)$": "..." + // } + // https://github.com/facebook/jest/blob/0a902e10e0a5550b114340b87bd31764a7638729/packages/jest-config/src/normalize.ts#L102 + return { ...(currentObject || {}), ...(parentObject || {}), ...(currentObject || {}) } as T; + }; + const deepObjectInheritanceFunc: | undefined>( + currentObject: T, + parentObject: T + ) => T = (currentObject: T, parentObject: T): T => { + return mergeWith(parentObject || {}, currentObject || {}, (value: T, source: T) => { + // 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)) { + return source; + } + return Array.isArray(value) ? [...value, ...(source as Array)] : { ...value, ...source }; + }) as T; + }; + + const tokenResolveMetadata: ICustomJsonPathMetadata = + JestPlugin._getJsonPathMetadata({ + rootDir: buildFolder + }); + const jestResolveMetadata: ICustomJsonPathMetadata = + JestPlugin._getJsonPathMetadata({ + rootDir: buildFolder, + resolveAsModule: true + }); + + JestPlugin._jestConfigurationFileLoader = new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + // Bypass Jest configuration validation + jsonSchemaObject: anythingSchema, + propertyInheritance: { + moduleNameMapper: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: shallowObjectInheritanceFunc + }, + transform: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: shallowObjectInheritanceFunc + }, + globals: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: deepObjectInheritanceFunc + }, + roots: { + inheritanceType: InheritanceType.replace + }, + testMatch: { + inheritanceType: InheritanceType.replace + }, + transformIgnorePatterns: { + inheritanceType: InheritanceType.replace + }, + collectCoverageFrom: { + inheritanceType: InheritanceType.replace + } + }, + jsonPathMetadata: { + // string + '$.cacheDirectory': tokenResolveMetadata, + '$.coverageDirectory': tokenResolveMetadata, + '$.dependencyExtractor': jestResolveMetadata, + '$.filter': jestResolveMetadata, + '$.globalSetup': jestResolveMetadata, + '$.globalTeardown': jestResolveMetadata, + '$.moduleLoader': jestResolveMetadata, + '$.preset': jestResolveMetadata, + '$.prettierPath': jestResolveMetadata, + '$.resolver': jestResolveMetadata, + '$.runner': jestResolveMetadata, + '$.snapshotResolver': jestResolveMetadata, + '$.testEnvironment': jestResolveMetadata, + '$.testResultsProcessor': jestResolveMetadata, + '$.testRunner': jestResolveMetadata, + '$.testSequencer': jestResolveMetadata, + // string[] + '$.modulePaths.*': tokenResolveMetadata, + '$.roots.*': tokenResolveMetadata, + '$.setupFiles.*': jestResolveMetadata, + '$.setupFilesAfterEnv.*': jestResolveMetadata, + '$.snapshotSerializers.*': jestResolveMetadata, + // moduleNameMapper: { [regex]: path | [ ...paths ] } + '$.moduleNameMapper.*@string()': tokenResolveMetadata, // string path + '$.moduleNameMapper.*.*': tokenResolveMetadata, // array of paths + // reporters: (path | [ path, options ])[] + '$.reporters[?(@ !== "default")]*@string()': jestResolveMetadata, // string path, excluding "default" + '$.reporters.*[?(@property == 0 && @ !== "default")]': jestResolveMetadata, // First entry in [ path, options ], excluding "default" + // transform: { [regex]: path | [ path, options ] } + '$.transform.*@string()': jestResolveMetadata, // string path + '$.transform.*[?(@property == 0)]': jestResolveMetadata, // First entry in [ path, options ] + // watchPlugins: (path | [ path, options ])[] + '$.watchPlugins.*@string()': jestResolveMetadata, // string path + '$.watchPlugins.*[?(@property == 0)]': jestResolveMetadata // First entry in [ path, options ] + } + }); + } + + return JestPlugin._jestConfigurationFileLoader; + } + + private _setNodeEnvIfRequested(options: IJestPluginOptions, logger: IScopedLogger): void { + if (options.enableNodeEnvManagement) { + if (process.env.NODE_ENV) { + if (process.env.NODE_ENV !== 'test') { + // In the future, we may consider just setting this and not warning + logger.emitWarning( + new Error(`NODE_ENV variable is set and it's not "test". NODE_ENV=${process.env.NODE_ENV}`) + ); + } + } else { + process.env.NODE_ENV = 'test'; + this._nodeEnvSet = true; + } + } + } + + private _resetNodeEnv(): void { + // unset the NODE_ENV only if we have set it + if (this._nodeEnvSet) { + 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; + } + } 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; + } + + /** + * 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 + ]; + } + + /** + * 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] + }); + } + + // 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}".` + ); + } + + 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 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); + } + } + + // 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; + } + + // 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); + } + + // Use the Jest-provided resolvers to resolve the module paths + switch (parsedPropertyName) { + case 'testRunner': + return resolveRunner(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + requireResolveFunction + }); + + case 'testSequencer': + return resolveSequencer(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + requireResolveFunction + }); + + case 'testEnvironment': + const testEnvironment: string = resolveTestEnvironment({ + rootDir: configDir, + testEnvironment: propertyValue, + requireResolveFunction + }); + + 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`; + } + } + + return testEnvironment; + + case 'watchPlugins': + return resolveWatchPlugin(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: 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.` + ); + } + + // 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 + }); + } 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; + } + + 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 + }; + } + + /** + * Finds the indices of jest reporters with a given name + */ + private static _findIndexes(items: JestReporterConfig[], search: string): number[] { + const result: number[] = []; + + for (let index: number = 0; index < items.length; index++) { + const item: JestReporterConfig = items[index]; + + // 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 new file mode 100644 index 00000000000..71440b051b6 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/JestRealPathPatch.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 * as path from 'node:path'; + +import { RealNodeModulePathResolver } from '@rushstack/node-core-library/lib/RealNodeModulePath'; + +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 => { + try { + return realNodeModulePath(input); + } catch (error) { + // Not using the helper from FileSystem here because this code loads in every Jest worker process + // and FileSystem has a lot of extra dependencies + // These error codes cloned from the logic in jest-util's tryRealpath.js + if (error.code !== 'ENOENT' && error.code !== 'EISDIR') { + throw error; + } + } + return input; +}; diff --git a/heft-plugins/heft-jest-plugin/src/JestUtils.ts b/heft-plugins/heft-jest-plugin/src/JestUtils.ts new file mode 100644 index 00000000000..89e6b5069c8 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/JestUtils.ts @@ -0,0 +1,149 @@ +// 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 { createHash } from 'node:crypto'; + +import { default as JestResolver } from 'jest-resolve'; +import type { TransformOptions } from '@jest/transform'; + +import { FileSystem } from '@rushstack/node-core-library'; + +// See: https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L21 +export type CacheKeyOptions = Pick; + +// See: https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L35 +export type GetCacheKeyFunction = ( + sourceText: string, + sourcePath: string, + options: CacheKeyOptions +) => string; + +// See: https://github.com/facebook/jest/blob/3093c18c428d962eb959437b322c6a5b0ae0e7a2/packages/jest-config/src/utils.ts#L14 +export interface IResolveOptions { + rootDir: string; + key: string; + filePath: string; + optional?: boolean; +} + +// Adapted from Jest to expose non-exported resolve function +// See: https://github.com/facebook/jest/blob/3093c18c428d962eb959437b322c6a5b0ae0e7a2/packages/jest-config/src/utils.ts#L58 +export const replaceRootDirInPath = (rootDir: string, filePath: string): string => { + if (!/^/.test(filePath)) { + return filePath; + } + + return path.resolve(rootDir, `./${filePath.substring(''.length)}`); +}; + +// Adapted from Jest to expose non-exported resolve function. +// See: https://github.com/facebook/jest/blob/3093c18c428d962eb959437b322c6a5b0ae0e7a2/packages/jest-config/src/utils.ts#L31 +export const jestResolve = ( + // eslint-disable-next-line @rushstack/no-new-null + resolver: string | null | undefined, + options: IResolveOptions + // eslint-disable-next-line @rushstack/no-new-null +): string | null => { + const { key, filePath, rootDir, optional } = options; + const module: string | null = JestResolver.findNodeModule(replaceRootDirInPath(rootDir, filePath), { + basedir: rootDir, + resolver: resolver || undefined + }); + + if (!module && !optional) { + throw new Error(`The ${key} option was not found. ' is: ${rootDir}`); + } + return module; +}; + +// -> +// NOTE: Assumes that the content of these serialized inputs are constant. +const globalCacheKeyStore: Map = new Map(); + +// Adapted from @jest/create-cache-key-function to add memoization and support for async I/O. +// See: https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L43 +const getGlobalCacheKey = (files: string[], values: string[]): string => { + const components: (string | undefined)[] = [ + process.env.NODE_ENV, + process.env.BABEL_ENV, + ...values, + ...files + ]; + const serializedComponents: string = JSON.stringify(components); + const existingGlobalCacheKey: string | undefined = globalCacheKeyStore.get(serializedComponents); + if (existingGlobalCacheKey) { + return existingGlobalCacheKey; + } + + const generatedGlobalCacheKey: string = [ + process.env.NODE_ENV, + process.env.BABEL_ENV, + ...values, + ...files.map((file: string) => FileSystem.readFile(file)) + ] + .reduce((hash, chunk) => hash.update('\0', 'utf8').update(chunk || ''), createHash('md5')) + .digest('hex'); + globalCacheKeyStore.set(serializedComponents, generatedGlobalCacheKey); + return generatedGlobalCacheKey; +}; + +// Adapted from @jest/create-cache-key-function to add memoization and support for async I/O. +// See: https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L43 +const getGlobalCacheKeyAsync = async (files: string[], values: string[]): Promise => { + const components: (string | undefined)[] = [ + process.env.NODE_ENV, + process.env.BABEL_ENV, + ...values, + ...files + ]; + const serializedComponents: string = JSON.stringify(components); + const existingGlobalCacheKey: string | undefined = globalCacheKeyStore.get(serializedComponents); + if (existingGlobalCacheKey) { + return existingGlobalCacheKey; + } + + const generatedGlobalCacheKey: string = [ + process.env.NODE_ENV, + process.env.BABEL_ENV, + ...values, + ...(await Promise.all(files.map((file: string) => FileSystem.readFileAsync(file)))) + ] + .reduce((hash, chunk) => hash.update('\0', 'utf8').update(chunk || ''), createHash('md5')) + .digest('hex'); + globalCacheKeyStore.set(serializedComponents, generatedGlobalCacheKey); + return generatedGlobalCacheKey; +}; + +// See: https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L57 +const createCacheKeyFunctionInternal = (globalCacheKey: string): GetCacheKeyFunction => { + return (sourceText: string, sourcePath: string, options: CacheKeyOptions): string => { + const { config, instrument } = options; + return createHash('md5') + .update(globalCacheKey) + .update('\0', 'utf8') + .update(sourceText) + .update('\0', 'utf8') + .update(config.rootDir ? path.relative(config.rootDir, sourcePath) : '') + .update('\0', 'utf8') + .update(instrument ? 'instrument' : '') + .digest('hex'); + }; +}; + +// Adapted from @jest/create-cache-key-function to add memoization and support for async I/O. +// https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L57 +export const createCacheKeyFunction = (files: string[], values: string[]): GetCacheKeyFunction => { + const globalCacheKey: string = getGlobalCacheKey(files, values); + return createCacheKeyFunctionInternal(globalCacheKey); +}; + +// Adapted from @jest/create-cache-key-function to add memoization and support for async I/O. +// https://github.com/facebook/jest/blob/86e64611c98dd3a6656be27dc5c342d53f8e7c30/packages/jest-create-cache-key-function/src/index.ts#L57 +export const createCacheKeyFunctionAsync = async ( + files: string[], + values: string[] +): Promise => { + const globalCacheKey: string = await getGlobalCacheKeyAsync(files, values); + return createCacheKeyFunctionInternal(globalCacheKey); +}; diff --git a/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts b/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts new file mode 100644 index 00000000000..6dd1791ff19 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts @@ -0,0 +1,62 @@ +// 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'; + +function findSourcePath(testPath: string, snapshotExtension: string): string { + const sourceMapFilePath: string = `${testPath}.map`; + let sourceFilePath: string = testPath; + try { + const sourceMapContent: string = fs.readFileSync(sourceMapFilePath, 'utf-8'); + const { + sources: [sourcePath] + } = JSON.parse(sourceMapContent); + sourceFilePath = path.resolve(path.dirname(testPath), sourcePath); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } + + const { dir, base } = path.parse(sourceFilePath); + return path.resolve(dir, '__snapshots__', base + snapshotExtension); +} + +const testToSnapshotCache: Map = new Map(); +const snapshotToTestCache: Map = new Map(); + +interface IJestSnapshotResolver { + resolveSnapshotPath(testPath: string, snapshotExtension: string): string; + resolveTestPath(snapshotFilePath: string, snapshotExtension: string): string; + + testPathForConsistencyCheck: string; +} + +const testPathForConsistencyCheck: string = path.normalize('/home/rushstack/heft/lib/jest/test.js'); + +const snapshotResolver: IJestSnapshotResolver = { + resolveSnapshotPath(testPath: string, snapshotExtension: string): string { + testPath = path.normalize(testPath); + let cachedPath: string | undefined = testToSnapshotCache.get(testPath); + if (!cachedPath) { + cachedPath = findSourcePath(testPath, snapshotExtension); + testToSnapshotCache.set(testPath, cachedPath); + snapshotToTestCache.set(cachedPath, testPath); + } + return cachedPath; + }, + + resolveTestPath(snapshotFilePath: string, snapshotExtension: string): string { + snapshotFilePath = path.normalize(snapshotFilePath); + const fromCache: string | undefined = snapshotToTestCache.get(snapshotFilePath); + if (!fromCache) { + throw new Error(`Expected snapshot lookup to happen first for ${snapshotFilePath}`); + } + return fromCache; + }, + + testPathForConsistencyCheck +}; + +export default snapshotResolver; diff --git a/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts new file mode 100644 index 00000000000..285bd520478 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.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. + +import { Writable } from 'node:stream'; + +import type { ITerminal } from '@rushstack/terminal'; + +// Regex to filter out screen clearing directives +// Can't use the AnsiEscape.removeCodes() function from node-core-library because we are only +// removing the clear screen directives, but want to preserve coloring. +// eslint-disable-next-line no-control-regex +const FILTER_REGEX: RegExp = /\x1B\[2J\x1B\[0f|\x1B\[2J\x1B\[3J\x1B\[H/g; + +export class TerminalWritableStream extends Writable { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + objectMode: false, + decodeStrings: false, + defaultEncoding: 'utf-8' + }); + + this._terminal = terminal; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public _write(chunk: any, encoding: string, callback: (error?: Error | undefined) => void): void { + const stringified: string = typeof chunk === 'string' ? chunk : chunk.toString(encoding); + const filtered: string = stringified.replace(FILTER_REGEX, ''); + this._terminal.write(filtered); + callback(); + } +} 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 new file mode 100644 index 00000000000..c046bfefa4a --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-global-setup.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. + +/** + * 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/jest-identity-mock-transform.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-identity-mock-transform.ts new file mode 100644 index 00000000000..3f2aff47b9b --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-identity-mock-transform.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. + +import { IdentityMockTransformer } from '../transformers/IdentityMockTransformer'; +export = new IdentityMockTransformer(); diff --git a/heft-plugins/heft-jest-plugin/src/exports/jest-improved-resolver.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-improved-resolver.ts new file mode 100644 index 00000000000..d16ddfc0116 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-improved-resolver.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. + +import resolver = require('../HeftJestResolver'); +export = resolver; diff --git a/heft-plugins/heft-jest-plugin/src/exports/jest-node-modules-symlink-resolver.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-node-modules-symlink-resolver.ts new file mode 100644 index 00000000000..5c4f9fb6e70 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-node-modules-symlink-resolver.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 '../JestRealPathPatch'; +// Using this syntax because HeftJestResolver uses `export =` syntax. +import resolver = require('../HeftJestResolver'); +export = resolver; diff --git a/heft-plugins/heft-jest-plugin/src/exports/jest-source-map-snapshot-resolver.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-source-map-snapshot-resolver.ts new file mode 100644 index 00000000000..a91c56443d6 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-source-map-snapshot-resolver.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. + +import resolver from '../SourceMapSnapshotResolver'; +export = resolver; diff --git a/heft-plugins/heft-jest-plugin/src/exports/jest-string-mock-transform.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-string-mock-transform.ts new file mode 100644 index 00000000000..9a4da921af6 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/jest-string-mock-transform.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. + +import { StringMockTransformer } from '../transformers/StringMockTransformer'; +export = new StringMockTransformer(); 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 new file mode 100644 index 00000000000..9292372bdaa --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/exports/patched-jest-environment-jsdom.ts @@ -0,0 +1,24 @@ +// 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/identityMock.ts b/heft-plugins/heft-jest-plugin/src/identityMock.ts new file mode 100644 index 00000000000..d8acdeb5988 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/identityMock.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. + +// This proxy is injected by Heft's jest-identity-mock-transform. See Heft documentation for details. +const identityMock: unknown = new Proxy( + {}, + { + get: (target: {}, key: PropertyKey, receiver: unknown): unknown => { + if (key === '__esModule') { + return false; + } + // When accessing a key like "identityMock.xyz", simply return "xyz" as a text string. + return key; + } + } +); + +export = identityMock; diff --git a/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts b/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts new file mode 100644 index 00000000000..ba3ae8ff04e --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts @@ -0,0 +1,151 @@ +// 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 * as path from 'node:path'; + +import { Import, FileSystem } 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: +// +// "A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests +// leaking due to improper teardown. Try running with --runInBand --detectOpenHandles to find leaks." +// +// The upstream issue is here: https://github.com/facebook/jest/issues/11354 +// +// The relevant code is in jest-worker/src/base/BaseWorkerPool.ts: +// https://github.com/facebook/jest/blob/64d5983d20a628d68644a3a4cd0f510dc304805a/packages/jest-worker/src/base/BaseWorkerPool.ts#L110 +// +// // Schedule a force exit in case worker fails to exit gracefully so +// // await worker.waitForExit() never takes longer than FORCE_EXIT_DELAY +// let forceExited = false; +// const forceExitTimeout = setTimeout(() => { +// worker.forceExit(); +// forceExited = true; +// }, FORCE_EXIT_DELAY); +// +// The problem is that Jest hardwires FORCE_EXIT_DELAY to be 500 ms. On a machine that is under heavy load, +// the IPC message is not received from the child process before the timeout elapses. The mitigation is to +// increase the delay. (Jest itself seems to be a significant contributor to machine load, so perhaps reducing +// Jest's parallelism could also help.) + +interface IBaseWorkerPoolModule { + default: unknown; +} + +// Follow the NPM dependency chain to find the module path for BaseWorkerPool.js +// heft --> @jest/core --> @jest/reporters --> jest-worker + +const PATCHED_FORCE_EXIT_DELAY: number = 7000; // 7 seconds +const patchName: string = path.basename(__filename); + +function applyPatch(): void { + try { + let contextFolder: string = __dirname; + // Resolve the "@jest/core" package relative to Heft + 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, + useNodeJSResolver: true + }); + // Resolve the "jest-worker" package relative to "@jest/reporters" + const jestWorkerFolder: string = Import.resolvePackage({ + packageName: 'jest-worker', + baseFolderPath: contextFolder, + useNodeJSResolver: true + }); + + const baseWorkerPoolPath: string = path.join(jestWorkerFolder, 'build/base/BaseWorkerPool.js'); + const baseWorkerPoolFilename: string = path.basename(baseWorkerPoolPath); // BaseWorkerPool.js + + if (!FileSystem.exists(baseWorkerPoolPath)) { + throw new Error( + 'The BaseWorkerPool.js file was not found in the expected location:\n' + baseWorkerPoolPath + ); + } + + // 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; + } + } + + if (!baseWorkerPoolModuleMetadata) { + throw new Error('Failed to detect the Node.js module metadata for BaseWorkerPool.js'); + } + + // 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; + // + // with this: + // + // const FORCE_EXIT_DELAY = 7000; + let matched: boolean = false; + patchedCode = patchedCode.replace( + /(const\s+FORCE_EXIT_DELAY\s*=\s*)(\d+)(\s*\;)/, + (matchedString: string, leftPart: string, middlePart: string, rightPart: string): string => { + matched = true; + return leftPart + PATCHED_FORCE_EXIT_DELAY.toString() + rightPart; + } + ); + + if (!matched) { + throw new Error('The expected pattern was not found in the file:\n' + baseWorkerPoolPath); + } + + function evalInContext(): IBaseWorkerPoolModule { + // Remap the require() function for the eval() context + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function require(modulePath: string): void { + return baseWorkerPoolModuleMetadata!.require(modulePath); + } + + // eslint-disable-next-line no-eval + return eval(patchedCode); + } + + const patchedModule: IBaseWorkerPoolModule = evalInContext(); + + baseWorkerPoolModule.default = patchedModule.default; + } catch (e) { + console.error(); + console.error(`ERROR: ${patchName} failed to patch the "jest-worker" package:`); + console.error((e as Error).toString()); + console.error(); + + throw e; + } +} + +if (typeof jest !== 'undefined' || process.env.JEST_WORKER_ID) { + // This patch is incompatible with Jest's proprietary require() implementation + console.log(`\nJEST ENVIRONMENT DETECTED - Skipping Heft's ${patchName}\n`); +} else { + applyPatch(); +} diff --git a/heft-plugins/heft-jest-plugin/src/schemas/anything.schema.json b/heft-plugins/heft-jest-plugin/src/schemas/anything.schema.json new file mode 100644 index 00000000000..15e4861463a --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/schemas/anything.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Schema that matches anything", + + "oneOf": [ + { + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "integer" + }, + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ] +} 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 new file mode 100644 index 00000000000..af5a94ddccd --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Jest Plugin Options Configuration", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-jest-plugin\".", + "type": "object", + + "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.", + "type": "boolean" + }, + "enableNodeEnvManagement": { + "title": "Enable management of the NODE_ENV variable", + "description": "If set to false, heft-jest-plugin will not set or unset the NODE_ENV variable. Otherwise, NODE_ENV will be set to `test` before execution and cleared after. If the NODE_ENV value is already set to a value that is not `test`, warning message appears.", + "type": "boolean" + } + } +} diff --git a/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts b/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts new file mode 100644 index 00000000000..1ef210d665e --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts @@ -0,0 +1,206 @@ +// 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 { 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 { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { + JEST_CONFIG_JSDOM_PACKAGE_NAME, + default as JestPlugin, + type IHeftJestConfiguration +} from '../JestPlugin'; + +interface IPartialHeftPluginJson { + taskPlugins?: { + parameters?: { + longName: string; + }[]; + }[]; +} + +describe('JestPlugin', () => { + it('loads and requests all specified plugin parameters', async () => { + const requestedParameters: Set = new Set(); + function mockGetParameter(parameterLongName: string): T { + requestedParameters.add(parameterLongName); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return { value: undefined, values: [] } as any as T; + } + const mockTaskSession: IHeftTaskSession = { + hooks: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + run: { tapPromise: () => {} } as any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + runIncremental: { tapPromise: () => {} } as any + }, + parameters: { + getChoiceParameter: mockGetParameter, + getChoiceListParameter: mockGetParameter, + getFlagParameter: mockGetParameter, + getIntegerParameter: mockGetParameter, + getIntegerListParameter: mockGetParameter, + getStringParameter: mockGetParameter, + getStringListParameter: mockGetParameter + } + } as IHeftTaskSession; + const mockHeftConfiguration: HeftConfiguration = {} as HeftConfiguration; + + const plugin = new JestPlugin(); + plugin.apply(mockTaskSession, mockHeftConfiguration, undefined); + + // Load up all the allowed parameters + const heftPluginJson: IPartialHeftPluginJson = await JsonFile.loadAsync( + `${__dirname}/../../heft-plugin.json` + ); + + // Verify that all parameters were requested + expect(requestedParameters.size).toBe(heftPluginJson.taskPlugins![0].parameters!.length); + for (const parameter of heftPluginJson.taskPlugins![0].parameters!) { + expect(requestedParameters.has(parameter.longName)).toBe(true); + } + }); +}); + +describe('JestConfigLoader', () => { + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(false); + terminal = new Terminal(terminalProvider); + }); + + 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 + // means that we don't run on the built test assets directly + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project1'); + const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( + rootDir, + 'config/jest.config.json' + ); + const loadedConfig: IHeftJestConfiguration = await loader.loadConfigurationFileForProjectAsync( + terminal, + rootDir + ); + + expect(loadedConfig.preset).toBe(undefined); + expect(loadedConfig.globalSetup).toBe(path.join(rootDir, 'a', 'b', 'globalSetupFile1.js')); + + // Validate string[] + expect(loadedConfig.setupFiles?.length).toBe(2); + expect(loadedConfig.setupFiles![0]).toBe(path.join(rootDir, 'a', 'b', 'setupFile2.js')); + expect(loadedConfig.setupFiles![1]).toBe(path.join(rootDir, 'a', 'b', 'setupFile1.js')); + + // Validate testEnvironment + expect(loadedConfig.testEnvironment).toBe(require.resolve('jest-environment-node')); + + // Validate watchPlugins + expect(loadedConfig.watchPlugins?.length).toBe(2); + expect(loadedConfig.watchPlugins?.[0]).toBe(require.resolve('jest-watch-select-projects')); + expect(loadedConfig.watchPlugins?.[1]).toBe(path.join(rootDir, 'a', 'b', 'mockWatchPlugin.js')); + + // Validate reporters + expect(loadedConfig.reporters?.length).toBe(3); + expect(loadedConfig.reporters![0]).toBe('default'); + expect(loadedConfig.reporters![1]).toBe(path.join(rootDir, 'a', 'c', 'mockReporter1.js')); + expect((loadedConfig.reporters![2] as Config.ReporterConfig)[0]).toBe( + path.join(rootDir, 'a', 'c', 'd', 'mockReporter2.js') + ); + + // Validate transformers + expect(Object.keys(loadedConfig.transform || {}).length).toBe(2); + expect(loadedConfig.transform!['\\.(xxx)$']).toBe( + path.join(rootDir, 'a', 'b', 'mockTransformModule2.js') + ); + expect((loadedConfig.transform!['\\.(yyy)$'] as Config.TransformerConfig)[0]).toBe( + path.join(rootDir, 'a', 'c', 'mockTransformModule3.js') + ); + + // Validate moduleNameMapper + expect(Object.keys(loadedConfig.moduleNameMapper || {}).length).toBe(4); + expect(loadedConfig.moduleNameMapper!['\\.resx$']).toBe( + // Test overrides + path.join(rootDir, 'a', 'some', 'path', 'to', 'overridden', 'module.js') + ); + expect(loadedConfig.moduleNameMapper!['\\.jpg$']).toBe( + // Test + path.join(rootDir, 'a', 'c', 'some', 'path', 'to', 'module.js') + ); + expect(loadedConfig.moduleNameMapper!['^!!file-loader']).toBe( + // Test + path.join( + Import.resolvePackage({ packageName: '@rushstack/heft', baseFolderPath: __dirname }), + 'some', + 'path', + 'to', + 'module.js' + ) + ); + expect(loadedConfig.moduleNameMapper!['^@1js/search-dispatcher/lib/(.+)']).toBe( + // Test unmodified + '@1js/search-dispatcher/lib-commonjs/$1' + ); + + // Validate globals + expect(Object.keys(loadedConfig.globals || {}).length).toBe(4); + expect(loadedConfig.globals!.key1).toBe('value5'); + expect((loadedConfig.globals!.key2 as string[]).length).toBe(4); + expect((loadedConfig.globals!.key2 as string[])[0]).toBe('value2'); + expect((loadedConfig.globals!.key2 as string[])[1]).toContain('value3'); + expect((loadedConfig.globals!.key2 as string[])[2]).toContain('value2'); + expect((loadedConfig.globals!.key2 as string[])[3]).toContain('value6'); + const key3Obj: any = (loadedConfig.globals as any).key3; // eslint-disable-line @typescript-eslint/no-explicit-any + expect(Object.keys(key3Obj).length).toBe(3); + expect(key3Obj.key4).toBe('value7'); + expect(key3Obj.key5).toBe('value5'); + expect(key3Obj.key6).toBe('value8'); + expect(loadedConfig.globals!.key7).toBe('value9'); + }); + + 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 + // means that we don't run on the built test assets directly + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project2'); + const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( + rootDir, + 'config/jest.config.json' + ); + const loadedConfig: IHeftJestConfiguration = await loader.loadConfigurationFileForProjectAsync( + terminal, + rootDir + ); + + expect(loadedConfig.setupFiles?.length).toBe(1); + expect(loadedConfig.setupFiles![0]).toBe(require.resolve('@jest/core')); + + // Also validate that a test environment that we specified as 'jsdom' (but have not added as a dependency) + // is resolved, implying it came from Jest directly + expect(loadedConfig.testEnvironment).toContain('jest-environment-jsdom'); + expect(loadedConfig.testEnvironment).toMatch(/index.js$/); + }); + + it('the default web config const matches the name in the config JSON file', async () => { + const { testEnvironment } = await JsonFile.loadAsync(`${__dirname}/../../includes/jest-web.config.json`); + 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 + // means that we don't run on the built test assets directly + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project3'); + const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( + rootDir, + 'config/jest.config.json' + ); + const loadedConfig: IHeftJestConfiguration = await loader.loadConfigurationFileForProjectAsync( + terminal, + rootDir + ); + const testEnvironment: string = Path.convertToPlatformDefault(loadedConfig.testEnvironment!); + expect(testEnvironment).toEqual(require.resolve('../exports/patched-jest-environment-jsdom')); + }); +}); diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/globalSetupFile1.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/globalSetupFile1.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/globalSetupFile1.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule1.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule1.ts new file mode 100644 index 00000000000..4cc179f0780 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule1.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. + +module.exports = { + moduleValue: 'zzz' +}; diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule2.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule2.ts new file mode 100644 index 00000000000..4cc179f0780 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockTransformModule2.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. + +module.exports = { + moduleValue: 'zzz' +}; diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockWatchPlugin.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockWatchPlugin.ts new file mode 100644 index 00000000000..4cc179f0780 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/mockWatchPlugin.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. + +module.exports = { + moduleValue: 'zzz' +}; diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile1.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile1.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile1.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile2.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile2.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/b/setupFile2.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/globalSetupFile2.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/globalSetupFile2.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/globalSetupFile2.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/mockReporter2.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/mockReporter2.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/d/mockReporter2.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/c/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/jest.config.json new file mode 100644 index 00000000000..8b53a16d098 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/jest.config.json @@ -0,0 +1,29 @@ +{ + "globalSetup": "./d/globalSetupFile2.js", + + "setupFiles": ["../b/setupFile2.js"], + + "reporters": ["default", "./mockReporter1.js", ["./d/mockReporter2.js", { "key": "value" }]], + + "testEnvironment": "node", + + "transform": { + "\\.(xxx)$": ["../b/mockTransformModule1.js", { "key": "value" }], + "\\.(yyy)$": ["./mockTransformModule3.js", { "key": "value" }] + }, + + "moduleNameMapper": { + "\\.resx$": "/some/path/to/module.js", + "\\.jpg$": "/some/path/to/module.js", + "^!!file-loader": "/some/path/to/module.js" + }, + + "globals": { + "key1": "value1", + "key2": ["value2", "value3"], + "key3": { + "key4": "value4", + "key5": "value5" + } + } +} diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockReporter1.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockReporter1.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockReporter1.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockTransformModule3.ts b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockTransformModule3.ts new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/c/mockTransformModule3.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/a/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project1/a/jest.config.json new file mode 100644 index 00000000000..b9d4e4f8ce8 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/a/jest.config.json @@ -0,0 +1,16 @@ +{ + "extends": "./c/jest.config.json", + + "setupFiles": ["./b/setupFile1.js"], + + "transform": { + "\\.(xxx)$": "./b/mockTransformModule2.js" + }, + + "moduleNameMapper": { + "\\.resx$": "/some/path/to/overridden/module.js", + "^@1js/search-dispatcher/lib/(.+)": "@1js/search-dispatcher/lib-commonjs/$1" + }, + + "watchPlugins": ["select-projects", "./b/mockWatchPlugin.js"] +} diff --git a/heft-plugins/heft-jest-plugin/src/test/project1/config/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project1/config/jest.config.json new file mode 100644 index 00000000000..b54d6102ded --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project1/config/jest.config.json @@ -0,0 +1,15 @@ +{ + "extends": "../a/jest.config.json", + + "globalSetup": "/a/b/globalSetupFile1.js", + + "globals": { + "key1": "value5", + "key2": ["value2", "value6"], + "key3": { + "key4": "value7", + "key6": "value8" + }, + "key7": "value9" + } +} diff --git a/heft-plugins/heft-jest-plugin/src/test/project2/a/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project2/a/jest.config.json new file mode 100644 index 00000000000..e9dfbde4f07 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project2/a/jest.config.json @@ -0,0 +1,5 @@ +{ + "setupFiles": ["@jest/core"], + + "testEnvironment": "jsdom" +} diff --git a/heft-plugins/heft-jest-plugin/src/test/project2/config/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project2/config/jest.config.json new file mode 100644 index 00000000000..c57fc64febe --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project2/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "../a/jest.config.json" +} diff --git a/heft-plugins/heft-jest-plugin/src/test/project3/config/jest.config.json b/heft-plugins/heft-jest-plugin/src/test/project3/config/jest.config.json new file mode 100644 index 00000000000..d052e597d38 --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/test/project3/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "../../../../includes/jest-web.config.json" +} diff --git a/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts b/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts new file mode 100644 index 00000000000..c6423bcad8f --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.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 * 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(); + +/** + * This Jest transform handles imports of files like CSS that would normally be + * processed by a Webpack loader. Instead of actually loading the resource, we return a mock object. + * The mock simply returns the imported name as a text string. For example, `mock.xyz` would evaluate to `"xyz"`. + * This technique is based on "identity-obj-proxy": + * + * https://www.npmjs.com/package/identity-obj-proxy + * + * @privateRemarks + * (We don't import the actual "identity-obj-proxy" package because transform output gets resolved with respect + * to the target project folder, not Heft's folder.) + */ +export class IdentityMockTransformer implements SyncTransformer { + public process(sourceText: string, sourcePath: string, options: TransformOptions): TransformedSource { + return { + code: proxyCode + }; + } +} diff --git a/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts b/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts new file mode 100644 index 00000000000..23766ffc9de --- /dev/null +++ b/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.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 { 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. + * Webpack's file-loader normally returns the resource's URL, and the filename is an equivalent for a Node + * environment. + */ +export class StringMockTransformer implements SyncTransformer { + public process(sourceText: string, sourcePath: string, options: TransformOptions): TransformedSource { + // 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(normalizedRelativePath)};` + }; + } +} diff --git a/heft-plugins/heft-jest-plugin/tsconfig.json b/heft-plugins/heft-jest-plugin/tsconfig.json new file mode 100644 index 00000000000..7b03eaec26f --- /dev/null +++ b/heft-plugins/heft-jest-plugin/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + // 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..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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..614f59a3251 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.json @@ -0,0 +1,354 @@ +{ + "name": "@rushstack/heft-json-schema-typings-plugin", + "entries": [ + { + "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..37b1bb13128 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md @@ -0,0 +1,90 @@ +# Change Log - @rushstack/heft-json-schema-typings-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..e6fc6cd0be1 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-json-schema-typings-plugin + +This is a Heft plugin for generating TypeScript typings from JSON schema files. + +## 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/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..f9db17a5dbd --- /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/JsonSchemaTypingsPlugin", + "optionsSchema": "./lib/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..b3152700713 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/heft-json-schema-typings-plugin", + "version": "1.1.7", + "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" + }, + "peerDependencies": { + "@rushstack/heft": "1.1.7" + }, + "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:*" + } +} 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..8b0cadc7e23 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.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 path from 'node:path'; + +import { compileFromFile } from 'json-schema-to-typescript'; + +import { type ITypingsGeneratorBaseOptions, TypingsGenerator } from '@rushstack/typings-generator'; + +interface IJsonSchemaTypingsGeneratorBaseOptions extends ITypingsGeneratorBaseOptions {} + +export class JsonSchemaTypingsGenerator extends TypingsGenerator { + public constructor(options: IJsonSchemaTypingsGeneratorBaseOptions) { + super({ + ...options, + fileExtensions: ['.schema.json'], + // Don't bother reading the file contents, compileFromFile will read the file + readFile: () => '', + // eslint-disable-next-line @typescript-eslint/naming-convention + parseAndGenerateTypings: async (fileContents: string, filePath: string): Promise => + await compileFromFile(filePath, { + // The typings generator adds its own banner comment + bannerComment: '', + cwd: path.dirname(filePath) + }) + }); + } +} 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..573e8cf5ce9 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.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 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[]; +} + +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'] } = 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 + }); + + 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/schemas/heft-json-schema-typings-plugin.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin.schema.json new file mode 100644 index 00000000000..27716523997 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/schemas/heft-json-schema-typings-plugin.schema.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + + "type": "object", + "additionalProperties": false, + + "properties": { + "srcFolder": { + "type": "string", + "description": "Source code root directory. Defaults to \"src/\".", + "pattern": "[^\\\\]" + }, + + "generatedTsFolders": { + "type": "array", + "description": "Output directories for generated typings. Defaults to [\"temp/schemas-ts\"].", + "minItems": 1, + "items": { + "type": "string" + } + } + } +} 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/.npmignore b/heft-plugins/heft-lint-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/heft-plugins/heft-lint-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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-lint-plugin/CHANGELOG.json b/heft-plugins/heft-lint-plugin/CHANGELOG.json new file mode 100644 index 00000000000..6f9237163f1 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/CHANGELOG.json @@ -0,0 +1,3072 @@ +{ + "name": "@rushstack/heft-lint-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/heft-lint-plugin_v0.5.9", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/heft-lint-plugin_v0.5.8", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/heft-lint-plugin_v0.5.7", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/heft-lint-plugin_v0.5.6", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/heft-lint-plugin_v0.5.5", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/heft-lint-plugin_v0.5.4", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-lint-plugin_v0.5.3", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-lint-plugin_v0.5.2", + "date": "Wed, 16 Oct 2024 00:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.32`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-lint-plugin_v0.5.1", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-lint-plugin_v0.5.0", + "date": "Thu, 10 Oct 2024 00:11:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option `sarifLogPath` that, when specified, will emit logs in the SARIF format: https://sarifweb.azurewebsites.net/. Note that this is only supported by ESLint." + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-lint-plugin_v0.4.6", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-lint-plugin_v0.4.5", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-lint-plugin_v0.4.4", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-lint-plugin_v0.4.3", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-lint-plugin_v0.4.2", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-lint-plugin_v0.4.1", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-lint-plugin_v0.4.0", + "date": "Wed, 14 Aug 2024 22:37:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add autofix functionality for ESLint and TSLint. Fixes can now be applied by providing the \"--fix\" command-line argument, or setting the \"alwaysFix\" plugin option to \"true\"" + } + ], + "patch": [ + { + "comment": "Unintrusively disable \"--fix\" mode when running in \"--production\" mode" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/heft-lint-plugin_v0.3.48", + "date": "Tue, 13 Aug 2024 18:17:05 GMT", + "comments": { + "patch": [ + { + "comment": "Supported linters (ESLint, TSLint) are now loaded asynchronously" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/heft-lint-plugin_v0.3.47", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/heft-lint-plugin_v0.3.46", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/heft-lint-plugin_v0.3.45", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/heft-lint-plugin_v0.3.44", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/heft-lint-plugin_v0.3.43", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/heft-lint-plugin_v0.3.42", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/heft-lint-plugin_v0.3.41", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/heft-lint-plugin_v0.3.40", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/heft-lint-plugin_v0.3.39", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/heft-lint-plugin_v0.3.38", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/heft-lint-plugin_v0.3.37", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/heft-lint-plugin_v0.3.36", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/heft-lint-plugin_v0.3.35", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/heft-lint-plugin_v0.3.34", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/heft-lint-plugin_v0.3.33", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/heft-lint-plugin_v0.3.32", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/heft-lint-plugin_v0.3.31", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/heft-lint-plugin_v0.3.30", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-lint-plugin_v0.3.29", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-lint-plugin_v0.3.28", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-lint-plugin_v0.3.27", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-lint-plugin_v0.3.26", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-lint-plugin_v0.3.25", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-lint-plugin_v0.3.24", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-lint-plugin_v0.3.23", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-lint-plugin_v0.3.22", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-lint-plugin_v0.3.21", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-lint-plugin_v0.3.20", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-lint-plugin_v0.3.19", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-lint-plugin_v0.3.18", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-lint-plugin_v0.3.17", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-lint-plugin_v0.3.16", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-lint-plugin_v0.3.15", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-lint-plugin_v0.3.14", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.4` to `0.65.5`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-lint-plugin_v0.3.13", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.3` to `0.65.4`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-lint-plugin_v0.3.12", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.2` to `0.65.3`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-lint-plugin_v0.3.11", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.1` to `0.65.2`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-lint-plugin_v0.3.10", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.0` to `0.65.1`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-lint-plugin_v0.3.9", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.8` to `0.65.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-lint-plugin_v0.3.8", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.7` to `0.64.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-lint-plugin_v0.3.7", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.6` to `0.64.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-lint-plugin_v0.3.6", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.5` to `0.64.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-lint-plugin_v0.3.5", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.4` to `0.64.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-lint-plugin_v0.3.4", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.3` to `0.64.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-lint-plugin_v0.3.3", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.2` to `0.64.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-lint-plugin_v0.3.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.1` to `0.64.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-lint-plugin_v0.3.1", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.0` to `0.64.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-lint-plugin_v0.3.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.6` to `0.64.0`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-lint-plugin_v0.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.5` to `0.63.6`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-lint-plugin_v0.2.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.4` to `0.63.5`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-lint-plugin_v0.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.3` to `0.63.4`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-lint-plugin_v0.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.2` to `0.63.3`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-lint-plugin_v0.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.1` to `0.63.2`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-lint-plugin_v0.2.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.0` to `0.63.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-lint-plugin_v0.2.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.3` to `0.63.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-lint-plugin_v0.2.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.2` to `0.62.3`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-lint-plugin_v0.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.1` to `0.62.2`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-lint-plugin_v0.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.0` to `0.62.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-lint-plugin_v0.2.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.3` to `0.62.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-lint-plugin_v0.2.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.2` to `0.61.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-lint-plugin_v0.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.1` to `0.61.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-lint-plugin_v0.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.0` to `0.61.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-lint-plugin_v0.2.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.60.0` to `0.61.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-lint-plugin_v0.2.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.59.0` to `0.60.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-lint-plugin_v0.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "patch": [ + { + "comment": "Reduce verbosity by only printing the \"not supported in watch mode\" warning during the initial build." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.2` to `0.59.0`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-lint-plugin_v0.1.22", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.1` to `0.58.2`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-lint-plugin_v0.1.21", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.0` to `0.58.1`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-lint-plugin_v0.1.20", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.1` to `0.58.0`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-lint-plugin_v0.1.19", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.0` to `0.57.1`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-lint-plugin_v0.1.18", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "patch": [ + { + "comment": "Treat a malformed cache file the same as no cache file (i.e. recheck everything) instead of throwing an error.." + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-lint-plugin_v0.1.17", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.3` to `0.57.0`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-lint-plugin_v0.1.16", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.2` to `0.56.3`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-lint-plugin_v0.1.15", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.15`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-lint-plugin_v0.1.14", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.1` to `0.56.2`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-lint-plugin_v0.1.13", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.0` to `0.56.1`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-lint-plugin_v0.1.12", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.12`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-lint-plugin_v0.1.11", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.2` to `0.56.0`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-lint-plugin_v0.1.10", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.1` to `0.55.2`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-lint-plugin_v0.1.9", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.0` to `0.55.1`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-lint-plugin_v0.1.8", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.54.0` to `0.55.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-lint-plugin_v0.1.7", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.1` to `0.54.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-lint-plugin_v0.1.6", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.0` to `0.53.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-lint-plugin_v0.1.5", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.2` to `0.53.0`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-lint-plugin_v0.1.4", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.1` to `0.52.2`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-lint-plugin_v0.1.3", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "patch": [ + { + "comment": "Use the temp folder instead of the cache folder." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.0` to `0.52.1`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-lint-plugin_v0.1.2", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.51.0` to `0.52.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-lint-plugin_v0.1.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression that caused this error: \"[build:lint] The create() function for rule ___ did not return an object.\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-lint-plugin_v0.1.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Prepare for official release." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.50.0` to `0.51.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-lint-plugin/CHANGELOG.md b/heft-plugins/heft-lint-plugin/CHANGELOG.md new file mode 100644 index 00000000000..aac67ba8937 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/CHANGELOG.md @@ -0,0 +1,845 @@ +# Change Log - @rushstack/heft-lint-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.5.9 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.5.8 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.5.7 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.5.6 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.5.5 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.5.4 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.5.3 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.5.2 +Wed, 16 Oct 2024 00:11:20 GMT + +_Version update only_ + +## 0.5.1 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.5.0 +Thu, 10 Oct 2024 00:11:51 GMT + +### Minor changes + +- Add an option `sarifLogPath` that, when specified, will emit logs in the SARIF format: https://sarifweb.azurewebsites.net/. Note that this is only supported by ESLint. + +## 0.4.6 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.5 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.4.4 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.4.3 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.4.2 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.4.1 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.4.0 +Wed, 14 Aug 2024 22:37:32 GMT + +### Minor changes + +- Add autofix functionality for ESLint and TSLint. Fixes can now be applied by providing the "--fix" command-line argument, or setting the "alwaysFix" plugin option to "true" + +### Patches + +- Unintrusively disable "--fix" mode when running in "--production" mode + +## 0.3.48 +Tue, 13 Aug 2024 18:17:05 GMT + +### Patches + +- Supported linters (ESLint, TSLint) are now loaded asynchronously + +## 0.3.47 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.3.46 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.3.45 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.3.44 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.3.43 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.3.42 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.41 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.3.40 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.3.39 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.3.38 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.3.37 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.3.36 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.3.35 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.34 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.3.33 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.3.32 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.3.31 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.3.30 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.3.29 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.3.28 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.3.27 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.3.26 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.3.25 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.3.24 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.23 +Thu, 28 Mar 2024 22:42:23 GMT + +_Version update only_ + +## 0.3.22 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.3.21 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.3.20 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.3.19 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.3.18 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.3.17 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.3.16 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.3.15 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.3.14 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.3.13 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.3.12 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.3.11 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.3.10 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.3.9 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.3.8 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.3.7 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.3.6 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.3.5 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.3.4 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.3.3 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.3.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.3.1 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.3.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 + +## 0.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.2.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.2.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.2.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.2.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.2.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.2.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.2.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.2.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +### Patches + +- Reduce verbosity by only printing the "not supported in watch mode" warning during the initial build. + +## 0.1.22 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.1.21 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.1.20 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.1.19 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 0.1.18 +Fri, 14 Jul 2023 15:20:45 GMT + +### Patches + +- Treat a malformed cache file the same as no cache file (i.e. recheck everything) instead of throwing an error.. + +## 0.1.17 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.16 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.1.15 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.1.14 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.1.13 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.1.12 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.1.11 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.1.10 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.1.9 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.1.8 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.1.7 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 0.1.6 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.1.5 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.1.4 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jun 2023 00:20:02 GMT + +### Patches + +- Use the temp folder instead of the cache folder. + +## 0.1.2 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 0.1.1 +Mon, 05 Jun 2023 21:45:21 GMT + +### Patches + +- Fix a regression that caused this error: "[build:lint] The create() function for rule ___ did not return an object." + +## 0.1.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Prepare for official release. + diff --git a/heft-plugins/heft-lint-plugin/LICENSE b/heft-plugins/heft-lint-plugin/LICENSE new file mode 100644 index 00000000000..14ff3db4c61 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-lint-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-lint-plugin/README.md b/heft-plugins/heft-lint-plugin/README.md new file mode 100644 index 00000000000..35171dec35a --- /dev/null +++ b/heft-plugins/heft-lint-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-lint-plugin + +This is a Heft plugin to run ESLint or TSLint. Intended for use with @rushstack/heft-typescript-plugin. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-lint-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-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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/heft-plugins/heft-lint-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": "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 new file mode 100644 index 00000000000..1de6fef351a --- /dev/null +++ b/heft-plugins/heft-lint-plugin/heft-plugin.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "lint-plugin", + "entryPoint": "./lib/LintPlugin", + "optionsSchema": "./lib/schemas/heft-lint-plugin.schema.json", + + "parameterScope": "lint", + "parameters": [ + { + "longName": "--fix", + "parameterKind": "flag", + "description": "Fix all encountered rule violations where the violated rule provides a fixer. When running in production mode, fixes will be disabled regardless of this parameter." + } + ] + } + ] +} diff --git a/heft-plugins/heft-lint-plugin/package.json b/heft-plugins/heft-lint-plugin/package.json new file mode 100644 index 00000000000..257141cf804 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/heft-lint-plugin", + "version": "1.1.10", + "description": "A Heft plugin for using ESLint or TSLint. Intended for use with @rushstack/heft-typescript-plugin", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-lint-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "1.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "json-stable-stringify-without-jsonify": "1.0.1", + "semver": "~7.5.4" + }, + "devDependencies": { + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@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.5.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "eslint-8": "npm:eslint@~8.57.0", + "typescript": "~5.8.2", + "tslint": "~5.20.1" + } +} diff --git a/heft-plugins/heft-lint-plugin/src/Eslint.ts b/heft-plugins/heft-lint-plugin/src/Eslint.ts new file mode 100644 index 00000000000..aea83cbee8d --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/Eslint.ts @@ -0,0 +1,399 @@ +// 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 { 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 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 | typeof TEslintLegacy; + eslintTimings: Map; +} + +interface IEslintTiming { + enabled: boolean; + time: (key: string, fn: (...args: unknown[]) => void) => (...args: unknown[]) => void; +} + +enum EslintMessageSeverity { + warning = 1, + error = 2 +} + +// Patch the timer used to track rule execution time. This allows us to get access to the detailed information +// about how long each rule took to execute, which we provide on the CLI when running in verbose mode. +async function patchTimerAsync(eslintPackagePath: string, timingsMap: Map): Promise { + const timingModulePath: string = `${eslintPackagePath}/lib/linter/timing`; + const timing: IEslintTiming = (await import(timingModulePath)).default; + timing.enabled = true; + const patchedTime: (key: string, fn: (...args: unknown[]) => unknown) => (...args: unknown[]) => unknown = ( + key: string, + fn: (...args: unknown[]) => unknown + ) => { + return (...args: unknown[]) => { + const startTime: number = performance.now(); + const result: unknown = fn(...args); + const endTime: number = performance.now(); + const existingTiming: number = timingsMap.get(key) || 0; + timingsMap.set(key, existingTiming + endTime - startTime); + return result; + }; + }; + timing.time = patchedTime; +} + +function getFormattedErrorMessage( + lintMessage: TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage +): string { + // https://eslint.org/docs/developer-guide/nodejs-api#◆-lintmessage-type + return lintMessage.ruleId ? `(${lintMessage.ruleId}) ${lintMessage.message}` : lintMessage.message; +} + +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 | 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); + + const { + buildFolderPath, + eslintPackage, + linterConfigFilePath, + tsProgram, + eslintTimings, + fix, + 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 | 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 | TEslintLegacy.Linter.LintMessage) => { + this._currentFixMessages.push(message); + return true; + }; + } 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. + const legacyEslintOverrideConfig: TEslintLegacy.Linter.Config = { + parserOptions: { + 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 + // 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(); + // This must happen before the rest of the linter package is loaded + await patchTimerAsync(linterToolPath, eslintTimings); + + const eslintPackage: typeof TEslint = await import(linterToolPath); + return new Eslint({ + ...options, + eslintPackage, + eslintTimings + }); + } + + public override printVersionHeader(): void { + const { version, major } = this._eslintPackageVersion; + this._terminal.writeLine(`Using ESLint version ${version}`); + + if (major < 7) { + throw new Error('Heft requires ESLint 7 or newer. Your ESLint version is too old'); + } 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( + 'The ESLint version is newer than the latest version that was tested with Heft, so it may not work correctly.' + ); + } + } + + 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 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 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 | TEslintLegacy.Linter.LintMessage)[] = + this._currentFixMessages.splice(0); + if (lintResults.length === 1) { + this._fixMessagesByResult.set(lintResults[0], fixMessages); + } + + this._fixesPossible ||= + !this._fix && + lintResults.some((lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult) => { + return lintResult.fixableErrorCount + lintResult.fixableWarningCount > 0; + }); + + return lintResults; + } + + 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]) => { + return y[1] - x[1]; + } + ); + for (const [ruleName, duration] of timings) { + if (duration > 0) { + this._terminal.writeVerboseLine(`Rule "${ruleName}" duration: ${duration.toFixed(3)} ms`); + } else { + omittedRuleCount++; + } + } + + if (omittedRuleCount > 0) { + this._terminal.writeVerboseLine(`${omittedRuleCount} rules took 0ms`); + } + + if (this._fix && this._fixMessagesByResult.size > 0) { + await this._eslintPackage.ESLint.outputFixes(lintResults); + } + + 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[] | TEslintLegacy.Linter.LintMessage[] | undefined = + this._fixMessagesByResult.get(lintResult); + if (fixMessages) { + for (const fixMessage of fixMessages) { + const formattedMessage: string = `[FIXED] ${getFormattedErrorMessage(fixMessage)}`; + const errorObject: FileError = this._getLintFileError(lintResult, fixMessage, formattedMessage); + this._scopedLogger.emitWarning(errorObject); + } + } + + // Report linter errors and warnings to the logger + for (const lintMessage of lintResult.messages) { + const errorObject: FileError = this._getLintFileError(lintResult, lintMessage); + switch (lintMessage.severity) { + case EslintMessageSeverity.error: { + this._scopedLogger.emitError(errorObject); + break; + } + + case EslintMessageSeverity.warning: { + this._scopedLogger.emitWarning(errorObject); + break; + } + } + } + } + + const sarifLogPath: string | undefined = this._sarifLogPath; + if (sarifLogPath) { + const rulesMeta: TEslint.ESLint.LintResultData['rulesMeta'] = + this._linter.getRulesMetaForResults(lintResults); + const { formatEslintResultsAsSARIF } = await import('./SarifFormatter'); + const sarifString: string = JSON.stringify( + formatEslintResultsAsSARIF(lintResults, rulesMeta, { + ignoreSuppressed: false, + eslintVersion: this._eslintPackage.ESLint.version, + buildFolderPath: this._buildFolderPath + }), + undefined, + 2 + ); + + await FileSystem.writeFileAsync(sarifLogPath, sarifString, { ensureFolderExists: true }); + } + } + + 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 | TEslintLegacy.ESLint.LintResult, + lintMessage: TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage, + message?: string + ): FileError { + if (!message) { + message = getFormattedErrorMessage(lintMessage); + } + + return new FileError(message, { + absolutePath: lintResult.filePath, + projectFolder: this._buildFolderPath, + line: lintMessage.line, + column: lintMessage.column + }); + } +} diff --git a/heft-plugins/heft-lint-plugin/src/LintPlugin.ts b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts new file mode 100644 index 00000000000..74a4e384d97 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts @@ -0,0 +1,277 @@ +// 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 type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IScopedLogger +} from '@rushstack/heft'; +import type { + TypeScriptPluginName, + IChangedFilesHookOptions, + ITypeScriptPluginAccessor +} from '@rushstack/heft-typescript-plugin'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; + +import type { LinterBase } from './LinterBase'; +import { Eslint } from './Eslint'; +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'; + +interface ILintPluginOptions { + alwaysFix?: boolean; + sarifLogPath?: string; +} + +interface ILintOptions { + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + tsProgram: IExtendedProgram; + fix?: boolean; + sarifLogPath?: string; + changedFiles?: ReadonlySet; +} + +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; + private _eslintConfigFilePath: string | undefined; + private _tslintToolPath: string | undefined; + private _tslintConfigFilePath: string | undefined; + + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions?: ILintPluginOptions + ): 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 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; + } + + 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. + 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); + } + } + } + + // 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 + ): Promise { + // Make sure that we only ever init once by memoizing the init promise + if (!this._initPromise) { + this._initPromise = this._initInnerAsync(heftConfiguration, taskSession.logger); + } + await this._initPromise; + } + + private async _initInnerAsync(heftConfiguration: HeftConfiguration, logger: IScopedLogger): Promise { + // Locate the tslint linter if enabled + this._tslintConfigFilePath = await Tslint.resolveTslintConfigFilePathAsync(heftConfiguration); + if (this._tslintConfigFilePath) { + this._tslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + 'tslint', + logger.terminal + ); + } + + // Locate the eslint linter if enabled + 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'); + } + } + + private async _lintAsync(options: ILintOptions): Promise { + const { taskSession, heftConfiguration, tsProgram, changedFiles, fix, sarifLogPath } = options; + + // Ensure that we have initialized. This promise is cached, so calling init + // multiple times will only init once. + await this._ensureInitializedAsync(taskSession, heftConfiguration); + + const linters: LinterBase[] = []; + if (this._eslintConfigFilePath && this._eslintToolPath) { + const eslintLinter: Eslint = await Eslint.initializeAsync({ + tsProgram, + fix, + sarifLogPath, + scopedLogger: taskSession.logger, + linterToolPath: this._eslintToolPath, + linterConfigFilePath: this._eslintConfigFilePath, + buildFolderPath: heftConfiguration.buildFolderPath, + buildMetadataFolderPath: taskSession.tempFolderPath + }); + linters.push(eslintLinter); + } + + if (this._tslintConfigFilePath && this._tslintToolPath) { + const tslintLinter: Tslint = await Tslint.initializeAsync({ + tsProgram, + fix, + scopedLogger: taskSession.logger, + linterToolPath: this._tslintToolPath, + linterConfigFilePath: this._tslintConfigFilePath, + buildFolderPath: heftConfiguration.buildFolderPath, + buildMetadataFolderPath: taskSession.tempFolderPath + }); + linters.push(tslintLinter); + } + + // Now that we know we have initialized properly, run the linter(s) + await Promise.all(linters.map((linter) => this._runLinterAsync(linter, tsProgram, changedFiles))); + } + + private async _runLinterAsync( + linter: LinterBase, + tsProgram: IExtendedProgram, + changedFiles?: ReadonlySet | undefined + ): Promise { + linter.printVersionHeader(); + + const typeScriptFilenames: Set = new Set(tsProgram.getRootFileNames()); + await linter.performLintingAsync({ + tsProgram, + typeScriptFilenames, + changedFiles: changedFiles || new Set(tsProgram.getSourceFiles()) + }); + } +} diff --git a/heft-plugins/heft-lint-plugin/src/LinterBase.ts b/heft-plugins/heft-lint-plugin/src/LinterBase.ts new file mode 100644 index 00000000000..f6c473754c7 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/LinterBase.ts @@ -0,0 +1,244 @@ +// 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 { 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'; + +import type { IExtendedProgram, IExtendedSourceFile } from './internalTypings/TypeScriptInternals'; + +export interface ILinterBaseOptions { + scopedLogger: IScopedLogger; + buildFolderPath: string; + /** + * The path where the linter state will be written to. + */ + buildMetadataFolderPath: string; + linterToolPath: string; + linterConfigFilePath: string; + tsProgram: IExtendedProgram; + fix?: boolean; + sarifLogPath?: string; +} + +export interface IRunLinterOptions { + tsProgram: IExtendedProgram; + + /** + * All of the files that the TypeScript compiler processed. + */ + typeScriptFilenames: Set; + + /** + * The set of files that TypeScript has compiled since the last compilation. + */ + changedFiles: ReadonlySet; +} + +interface ILinterCacheData { + /** + * The TSLint version and a hash of the TSLint config files. If either changes, + * the cache is invalidated. + */ + cacheVersion: string; + + /** + * This is the result of `Array.from(Map)`. The first element of + * 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 { + protected readonly _scopedLogger: IScopedLogger; + protected readonly _terminal: ITerminal; + protected readonly _buildFolderPath: string; + protected readonly _buildMetadataFolderPath: string; + protected readonly _linterConfigFilePath: string; + protected readonly _fix: boolean; + + protected _fixesPossible: boolean = false; + + private readonly _linterName: string; + + protected constructor(linterName: string, options: ILinterBaseOptions) { + this._scopedLogger = options.scopedLogger; + this._terminal = this._scopedLogger.terminal; + this._buildFolderPath = options.buildFolderPath; + this._buildMetadataFolderPath = options.buildMetadataFolderPath; + this._linterConfigFilePath = options.linterConfigFilePath; + this._linterName = linterName; + this._fix = options.fix || false; + } + + public abstract printVersionHeader(): void; + + public async performLintingAsync(options: IRunLinterOptions): Promise { + const startTime: number = performance.now(); + let fileCount: number = 0; + + const commonDirectory: string = options.tsProgram.getCommonSourceDirectory(); + + const relativePaths: Map = new Map(); + + // 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); + 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 linterCacheVersion: string = await this.getCacheVersionAsync(); + const linterCacheFilePath: string = path.resolve( + this._buildMetadataFolderPath, + `_${this._linterName}-${hashSuffix}.json` + ); + + let linterCacheData: ILinterCacheData | undefined; + try { + const cacheFileContent: string = await FileSystem.readFileAsync(linterCacheFilePath); + if (cacheFileContent) { + // Using JSON.parse instead of JsonFile because it is faster for plain JSON + // This is safe because it is a machine-generated file that will not be edited by a human. + // Also so that we can check for empty file first. + linterCacheData = JSON.parse(cacheFileContent); + } + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + linterCacheData = undefined; + } else if (e instanceof SyntaxError) { + this._terminal.writeVerboseLine(`Error parsing ${linterCacheFilePath}: ${e}; ignoring cached data.`); + linterCacheData = undefined; + } else { + throw e; + } + } + + const cachedNoFailureFileVersions: Map = new Map( + linterCacheData?.cacheVersion === linterCacheVersion && linterCacheData?.filesHash === filesHashString + ? linterCacheData.fileVersions + : [] + ); + + const newNoFailureFileVersions: Map = new Map(); + + //#region Code from TSLint + // Some of this code comes from here: + // https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L161-L179 + // Modified to only lint files that have changed and that we care about + const lintResults: TLintResult[] = []; + for (const sourceFile of options.tsProgram.getSourceFiles()) { + const filePath: string = sourceFile.fileName; + const relative: string | undefined = relativePaths.get(filePath); + + if (relative === undefined || (await this.isFileExcludedAsync(filePath))) { + continue; + } + + const version: string = await this.getSourceFileHashAsync(sourceFile); + const cachedVersion: string = cachedNoFailureFileVersions.get(relative) || ''; + if ( + cachedVersion === '' || + version === '' || + cachedVersion !== version || + options.changedFiles.has(sourceFile) + ) { + fileCount++; + const results: TLintResult[] = await this.lintFileAsync(sourceFile); + // 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 { + newNoFailureFileVersions.set(relative, version); + } + } + //#endregion + + await this.lintingFinishedAsync(lintResults); + + if (!this._fix && this._fixesPossible) { + this._terminal.writeWarningLine( + 'The linter reported that fixes are possible. To apply fixes, run Heft with the "--fix" option.' + ); + } + + const updatedTslintCacheData: ILinterCacheData = { + cacheVersion: linterCacheVersion, + fileVersions: Array.from(newNoFailureFileVersions), + filesHash: filesHashString + }; + await JsonFile.saveAsync(updatedTslintCacheData, linterCacheFilePath, { ensureFolderExists: true }); + + const duration: number = performance.now() - startTime; + + 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(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 new file mode 100644 index 00000000000..1a55bfa2cc8 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/SarifFormatter.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 path from 'node:path'; + +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; + eslintVersion?: string; + buildFolderPath: string; +} + +export interface ISarifRun { + tool: { + driver: { + name: string; + informationUri: string; + version?: string; + rules: IStaticAnalysisRules[]; + }; + }; + artifacts?: ISarifFile[]; + results?: ISarifRepresentation[]; + invocations?: { + toolConfigurationNotifications: ISarifRepresentation[]; + executionSuccessful: boolean; + }[]; +} + +export interface ISarifRepresentation { + level: string; + message: { + text: string; + }; + locations: ISarifLocation[]; + ruleId?: string; + ruleIndex?: number; + descriptor?: { + id: string; + }; + suppressions?: ISuppressedAnalysis[]; +} + +// Interface for the SARIF log structure +export interface ISarifLog { + version: string; + $schema: string; + runs: ISarifRun[]; +} + +export interface IRegion { + startLine?: number; + startColumn?: number; + endLine?: number; + endColumn?: number; + snippet?: { + text: string; + }; +} + +export interface IStaticAnalysisRules { + id: string; + name?: string; + shortDescription?: { + text: string; + }; + fullDescription?: { + text: string; + }; + defaultConfiguration?: { + level: 'note' | 'warning' | 'error'; + }; + helpUri?: string; + properties?: { + category?: string; + precision?: 'very-high' | 'high' | 'medium' | 'low'; + tags?: string[]; + problem?: { + severity?: 'recommendation' | 'warning' | 'error'; + securitySeverity?: number; + }; + }; +} + +export interface ISarifFile { + location: { + uri: string; + }; +} + +export interface ISuppressedAnalysis { + kind: string; + justification: string; +} + +export interface ISarifLocation { + physicalLocation: ISarifPhysicalLocation; +} + +export interface ISarifArtifactLocation { + uri: string; + index?: number; +} + +export interface ISarifPhysicalLocation { + artifactLocation: ISarifArtifactLocation; + region?: IRegion; +} + +export interface ISarifRule { + id: string; + helpUri?: string; + shortDescription?: { + text: string; + }; + properties?: { + category?: string; + }; +} + +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'; +const SARIF_INFORMATION_URI: 'http://json.schemastore.org/sarif-2.1.0-rtm.5' = + 'http://json.schemastore.org/sarif-2.1.0-rtm.5'; +/** + * Converts ESLint results into a SARIF (Static Analysis Results Interchange Format) log. + * + * This function takes in a list of ESLint lint results, processes them to extract + * relevant information such as errors, warnings, and suppressed messages, and + * outputs a SARIF log which conforms to the SARIF v2.1.0 specification. + * + * @param results - An array of lint results from ESLint that contains linting information, + * such as file paths, messages, and suppression details. + * @param rulesMeta - An object containing metadata about the ESLint rules that were applied during the linting session. + * The keys are the rule names, and the values are rule metadata objects + * that describe each rule. This metadata typically includes: + * - `docs`: Documentation about the rule. + * - `fixable`: Indicates whether the rule is fixable. + * - `messages`: Custom messages that the rule might output when triggered. + * - `schema`: The configuration schema for the rule. + * This metadata helps in providing more context about the rules when generating the SARIF log. + * @param options - An object containing options for formatting: + * - `ignoreSuppressed`: Boolean flag to decide whether to ignore suppressed messages. + * - `eslintVersion`: Optional string to include the version of ESLint in the SARIF log. + * @returns The SARIF log containing information about the linting results in SARIF format. + */ + +export function formatEslintResultsAsSARIF( + results: (TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult)[], + rulesMeta: (TEslint.ESLint.LintResultData | TEslintLegacy.ESLint.LintResultData)['rulesMeta'], + options: ISerifFormatterOptions +): ISarifLog { + const { ignoreSuppressed, eslintVersion, buildFolderPath } = options; + const toolConfigurationNotifications: ISarifRepresentation[] = []; + const sarifFiles: ISarifFile[] = []; + const sarifResults: ISarifRepresentation[] = []; + const sarifArtifactIndices: Map = new Map(); + const sarifRules: ISarifRule[] = []; + const sarifRuleIndices: Map = new Map(); + + const sarifRun: ISarifRun = { + tool: { + driver: { + name: 'ESLint', + informationUri: 'https://eslint.org', + version: eslintVersion, + rules: [] + } + } + }; + + const sarifLog: ISarifLog = { + version: SARIF_VERSION, + $schema: SARIF_INFORMATION_URI, + runs: [sarifRun] + }; + + let executionSuccessful: boolean = true; + let currentArtifactIndex: number = 0; + let currentRuleIndex: number = 0; + + for (const result of results) { + const { filePath, source } = result; + const fileUrl: string = Path.convertToSlashes(path.relative(buildFolderPath, filePath)); + let sarifFileIndex: number | undefined = sarifArtifactIndices.get(fileUrl); + + if (sarifFileIndex === undefined) { + sarifFileIndex = currentArtifactIndex++; + sarifArtifactIndices.set(fileUrl, sarifFileIndex); + sarifFiles.push({ + location: { + uri: fileUrl + } + }); + } + + const artifactLocation: ISarifArtifactLocation = { + uri: fileUrl, + index: sarifFileIndex + }; + + const containsSuppressedMessages: boolean = + result.suppressedMessages && result.suppressedMessages.length > 0; + 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 = { + artifactLocation + }; + + const sarifRepresentation: ISarifRepresentation = { + level, + message: { + text: message.message + }, + locations: [ + { + physicalLocation + } + ] + }; + + if (message.ruleId) { + sarifRepresentation.ruleId = message.ruleId; + + if (rulesMeta && sarifRuleIndices.get(message.ruleId) === undefined) { + 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) { + sarifRuleIndices.set(message.ruleId, currentRuleIndex++); + + if (meta.docs) { + // Create a new entry in the rules dictionary. + const shortDescription: string = meta.docs.description ?? ''; + + const sarifRule: ISarifRule = { + id: message.ruleId, + helpUri: meta.docs.url, + properties: { + category: meta.docs.category + }, + shortDescription: { + text: shortDescription + } + }; + sarifRules.push(sarifRule); + // Some rulesMetas do not have docs property + } else { + sarifRules.push({ + id: message.ruleId, + properties: { + category: 'No category provided' + }, + shortDescription: { + text: 'Please see details in message' + } + }); + } + } + } + + if (sarifRuleIndices.has(message.ruleId)) { + sarifRepresentation.ruleIndex = sarifRuleIndices.get(message.ruleId); + } + + if (containsSuppressedMessages && !ignoreSuppressed) { + sarifRepresentation.suppressions = message.suppressions + ? message.suppressions.map((suppression: ISuppressedAnalysis) => { + return { + kind: suppression.kind === 'directive' ? 'inSource' : 'external', + justification: suppression.justification + }; + }) + : []; + } + } else { + sarifRepresentation.descriptor = { + id: INTERNAL_ERROR_ID + }; + + if (sarifRepresentation.level === 'error') { + executionSuccessful = false; + } + } + + if (message.line !== undefined || message.column !== undefined) { + const { line: startLine, column: startColumn, endLine, endColumn } = message; + const region: IRegion = { + startLine, + startColumn, + endLine, + endColumn + }; + physicalLocation.region = region; + } + + 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: snippetText + }; + } + + if (message.ruleId) { + sarifResults.push(sarifRepresentation); + } else { + toolConfigurationNotifications.push(sarifRepresentation); + } + } + } + + if (sarifRules.length > 0) { + sarifRun.tool.driver.rules = sarifRules; + } + + if (sarifFiles.length > 0) { + sarifRun.artifacts = sarifFiles; + } + + sarifRun.results = sarifResults; + + if (toolConfigurationNotifications.length > 0) { + sarifRun.invocations = [ + { + toolConfigurationNotifications, + executionSuccessful + } + ]; + } + + return sarifLog; +} diff --git a/heft-plugins/heft-lint-plugin/src/Tslint.ts b/heft-plugins/heft-lint-plugin/src/Tslint.ts new file mode 100644 index 00000000000..52a15677ad7 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/Tslint.ts @@ -0,0 +1,226 @@ +// 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 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'; + +interface ITslintOptions extends ILinterBaseOptions { + tslintPackage: typeof TTslint; + tslintConfiguration: TTslint.Configuration.IConfigurationFile; +} + +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; + private readonly _linter: IExtendedLinter; + private readonly _enabledRules: TTslint.IRule[]; + private readonly _ruleSeverityMap: Map; + + public constructor(options: ITslintOptions) { + super('tslint', options); + + const { tslintPackage, tsProgram } = options; + this._tslintPackage = tslintPackage; + this._tslintConfiguration = options.tslintConfiguration; + this._linter = new tslintPackage.Linter( + { + // This is not handled by the linter in the way that we use it, so we will manually apply + // fixes later + fix: false, + rulesDirectory: this._tslintConfiguration.rulesDirectory + }, + tsProgram + ) as unknown as IExtendedLinter; + + this._enabledRules = this._linter.getEnabledRules(this._tslintConfiguration, false); + + this._ruleSeverityMap = new Map( + this._enabledRules.map((rule): [string, TTslint.RuleSeverity] => [ + rule.getOptions().ruleName, + rule.getOptions().ruleSeverity + ]) + ); + } + + public static async initializeAsync(options: ILinterBaseOptions): Promise { + const { linterToolPath, linterConfigFilePath } = options; + const tslintPackage: typeof TTslint = await import(linterToolPath); + const tslintConfiguration: TTslint.Configuration.IConfigurationFile = + tslintPackage.Configuration.loadConfigurationFromPath(linterConfigFilePath); + return new Tslint({ + ...options, + tslintPackage, + tslintConfiguration + }); + } + + 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. + * + * @param previousHash - If supplied, the hash is updated with the contents of the + * file's extended configs and itself before being returned. Passing a digested hash to + * this parameter will result in an error. + */ + public static async getConfigHashAsync( + configFilePath: string, + terminal: ITerminal, + previousHash?: crypto.Hash + ): Promise { + interface IMinimalConfig { + extends?: string | string[]; + } + + terminal.writeVerboseLine(`Examining config file "${configFilePath}"`); + // if configFilePath is not a json file, assume that it is a package whose package.json + // specifies a "main" file which is a config file, per the "extends" spec of tslint.json, found at + // https://palantir.github.io/tslint/usage/configuration/ + if (!configFilePath.endsWith('.json')) { + configFilePath = Import.resolveModule({ + modulePath: configFilePath, + baseFolderPath: path.dirname(configFilePath) + }); + } + const rawConfig: string = await FileSystem.readFileAsync(configFilePath); + const parsedConfig: IMinimalConfig = JsonFile.parseString(rawConfig); + const extendsProperty: string | string[] | undefined = parsedConfig.extends; + let hash: crypto.Hash = previousHash || crypto.createHash('sha1'); + + if (extendsProperty instanceof Array) { + for (const extendFile of extendsProperty) { + const extendFilePath: string = Import.resolveModule({ + modulePath: extendFile, + baseFolderPath: path.dirname(configFilePath) + }); + hash = await Tslint.getConfigHashAsync(extendFilePath, terminal, hash); + } + } else if (extendsProperty) { + // note that if we get here, extendsProperty is a string + const extendsFullPath: string = Import.resolveModule({ + modulePath: extendsProperty, + baseFolderPath: path.dirname(configFilePath) + }); + hash = await Tslint.getConfigHashAsync(extendsFullPath, terminal, hash); + } + + return hash.update(rawConfig); + } + + public printVersionHeader(): void { + this._terminal.writeLine(`Using TSLint version ${this._tslintPackage.Linter.VERSION}`); + } + + protected async getCacheVersionAsync(): Promise { + const tslintConfigHash: crypto.Hash = await Tslint.getConfigHashAsync( + this._linterConfigFilePath, + this._terminal + ); + const tslintConfigVersion: string = `${this._tslintPackage.Linter.VERSION}_${tslintConfigHash.digest( + 'hex' + )}`; + + return tslintConfigVersion; + } + + protected async lintFileAsync(sourceFile: TTypescript.SourceFile): Promise { + // Some of this code comes from here: + // https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L161-L179 + // Modified to only lint files that have changed and that we care about + let failures: TTslint.RuleFailure[] = this._linter.getAllFailures(sourceFile, this._enabledRules); + const hasFixableIssue: boolean = failures.some((f) => f.hasFix()); + if (hasFixableIssue) { + if (this._fix) { + failures = this._linter.applyAllFixes(this._enabledRules, failures, sourceFile, sourceFile.fileName); + } else { + this._fixesPossible = true; + } + } + + for (const failure of failures) { + const severity: TTslint.RuleSeverity | undefined = this._ruleSeverityMap.get(failure.getRuleName()); + if (severity === undefined) { + throw new Error(`Severity for rule '${failure.getRuleName()}' not found`); + } + + failure.setRuleSeverity(severity); + } + + return failures; + } + + protected async lintingFinishedAsync(failures: TTslint.RuleFailure[]): Promise { + this._linter.failures = failures; + const lintResult: TTslint.LintResult = this._linter.getResult(); + + // Report linter fixes to the logger. These will only be returned when the underlying failure was fixed + if (lintResult.fixes?.length) { + for (const fixedTslintFailure of lintResult.fixes) { + const formattedMessage: string = `[FIXED] ${getFormattedErrorMessage(fixedTslintFailure)}`; + const errorObject: FileError = this._getLintFileError(fixedTslintFailure, formattedMessage); + this._scopedLogger.emitWarning(errorObject); + } + } + + // Report linter errors and warnings to the logger + for (const tslintFailure of lintResult.failures) { + const errorObject: FileError = this._getLintFileError(tslintFailure); + switch (tslintFailure.getRuleSeverity()) { + case 'error': { + this._scopedLogger.emitError(errorObject); + break; + } + + case 'warning': { + this._scopedLogger.emitWarning(errorObject); + break; + } + } + } + } + + protected async isFileExcludedAsync(filePath: string): Promise { + 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); + } + + const { line, character } = tslintFailure.getStartPosition().getLineAndCharacter(); + return new FileError(message, { + absolutePath: tslintFailure.getFileName(), + projectFolder: this._buildFolderPath, + line: line + 1, + column: character + 1 + }); + } +} diff --git a/heft-plugins/heft-lint-plugin/src/internalTypings/TslintInternals.ts b/heft-plugins/heft-lint-plugin/src/internalTypings/TslintInternals.ts new file mode 100644 index 00000000000..a886be74f73 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/internalTypings/TslintInternals.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 type * as TTslint from 'tslint'; +import type * as TTypescript from 'typescript'; + +type TrimmedLinter = Omit< + TTslint.Linter, + 'getAllFailures' | 'applyAllFixes' | 'getEnabledRules' | 'failures' +>; +export interface IExtendedLinter extends TrimmedLinter { + /** + * https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L117 + */ + failures: TTslint.RuleFailure[]; + + /** + * https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L207-L210 + */ + getAllFailures(sourceFile: TTypescript.SourceFile, enabledRules: TTslint.IRule[]): TTslint.RuleFailure[]; + + /** + * https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L303-L306 + */ + getEnabledRules(configuration: TTslint.Configuration.IConfigurationFile, isJs: boolean): TTslint.IRule[]; + + /** + * https://github.com/palantir/tslint/blob/24d29e421828348f616bf761adb3892bcdf51662/src/linter.ts#L212-L241 + */ + applyAllFixes( + enabledRules: TTslint.IRule[], + fileFailures: TTslint.RuleFailure[], + sourceFile: TTypescript.SourceFile, + sourceFileName: string + ): TTslint.RuleFailure[]; +} diff --git a/heft-plugins/heft-lint-plugin/src/internalTypings/TypeScriptInternals.ts b/heft-plugins/heft-lint-plugin/src/internalTypings/TypeScriptInternals.ts new file mode 100644 index 00000000000..ffe2b42773d --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/internalTypings/TypeScriptInternals.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 * as TTypescript from 'typescript'; + +/** + * @beta + */ +export interface IExtendedProgram extends TTypescript.Program { + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3205 + */ + getSourceFiles(): ReadonlyArray; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/program.ts#L1024-L1048 + */ + getCommonSourceDirectory(): string; +} + +/** + * @beta + */ +export interface IExtendedSourceFile extends TTypescript.SourceFile { + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3011 + */ + version: string; +} diff --git a/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin.schema.json b/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin.schema.json new file mode 100644 index 00000000000..072d2c70df6 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/schemas/heft-lint-plugin.schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Lint Plugin Options Configuration", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-lint-plugin\".", + "type": "object", + + "additionalProperties": false, + + "properties": { + "alwaysFix": { + "title": "Always Fix", + "description": "If set to true, fix all encountered rule violations where the violated rule provides a fixer, regardless of if the \"--fix\" command-line argument is provided. When running in production mode, fixes will be disabled regardless of this setting.", + "type": "boolean" + }, + + "sarifLogPath": { + "title": "SARIF Log Path", + "description": "If specified and using ESLint, a log describing the lint configuration and all messages (suppressed or not) will be emitted in the Static Analysis Results Interchange Format (https://sarifweb.azurewebsites.net/) at the provided path, relative to the project root.", + "type": "string" + } + } +} diff --git a/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts b/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts new file mode 100644 index 00000000000..abae66cd8cd --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts @@ -0,0 +1,649 @@ +// 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'; + +describe('formatEslintResultsAsSARIF', () => { + test('should correctly format ESLint results into SARIF log', () => { + 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: 1, + column: 7, + nodeType: 'Identifier', + endLine: 1, + endColumn: 8 + } + ], + suppressedMessages: [], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-unused-vars': { + type: 'suggestion', + docs: { + description: "'x' is defined but never used.", + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-unused-vars' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "'x' is defined but never used." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('case with no files', () => { + const mockLintResults: ESLint.LintResult[] = []; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = {}; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('case with single issues in the same file', () => { + 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: 1, + column: 7, + nodeType: 'Identifier', + endLine: 1, + endColumn: 8 + } + ], + suppressedMessages: [], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-unused-vars': { + type: 'suggestion', + docs: { + description: "'x' is defined but never used.", + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-unused-vars' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "'x' is defined but never used." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('should handle multiple issues in the same file', async () => { + 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: 1, + column: 5, + nodeType: 'Identifier', + endLine: 1, + endColumn: 6 + }, + { + ruleId: 'no-console', + severity: 1, + message: 'Unexpected console statement.', + line: 2, + column: 1, + nodeType: 'MemberExpression', + endLine: 2, + endColumn: 12 + } + ], + suppressedMessages: [], + errorCount: 1, + warningCount: 1, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-console': { + type: 'suggestion', + docs: { + description: 'Disallow the use of `console`', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-console' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: 'Unexpected console statement.', + removeConsole: 'Remove the console.{{ propertyName }}().' + } + }, + 'no-unused-vars': { + type: 'suggestion', + docs: { + description: "'x' is defined but never used.", + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-unused-vars' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "'x' is defined but never used." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = await formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('should handle a file with no messages', async () => { + const mockLintResults: ESLint.LintResult[] = [ + { + filePath: '/src/file3.ts', + messages: [], + suppressedMessages: [], + errorCount: 0, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = {}; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = await formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('should handle multiple files', async () => { + 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: 1, + column: 7, + nodeType: 'Identifier', + endLine: 1, + endColumn: 8 + } + ], + suppressedMessages: [], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + }, + { + filePath: '/src/file2.ts', + source: 'let y = z == 2;', + messages: [ + { + ruleId: 'eqeqeq', + severity: 2, + message: "Expected '===' and instead saw '=='.", + line: 1, + column: 9, + nodeType: 'BinaryExpression', + endLine: 1, + endColumn: 15 + } + ], + suppressedMessages: [], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-console': { + type: 'suggestion', + docs: { + description: 'Disallow the use of `console`', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-console' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: 'Unexpected console statement.', + removeConsole: 'Remove the console.{{ propertyName }}().' + } + }, + eqeqeq: { + type: 'problem', + docs: { + description: 'Require the use of === and !==', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/eqeqeq' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "Expected '===' and instead saw '=='." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = await formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('should handle ignoreSuppressed: true with suppressed messages', async () => { + const mockLintResults: ESLint.LintResult[] = [ + { + filePath: '/src/file4.ts', + source: 'debugger;\nconsole.log("test");', + messages: [ + { + ruleId: 'no-debugger', + severity: 2, + message: "Unexpected 'debugger' statement.", + line: 1, + column: 1, + nodeType: 'DebuggerStatement', + endLine: 1, + endColumn: 10 + } + ], + suppressedMessages: [ + { + ruleId: 'no-console', + severity: 1, + message: 'Unexpected console statement.', + line: 2, + column: 1, + nodeType: 'MemberExpression', + endLine: 2, + endColumn: 12, + suppressions: [ + { + kind: 'inSource', + justification: 'rejected' + } + ] + } + ], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-console': { + type: 'suggestion', + docs: { + description: 'Disallow the use of `console`', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-console' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: 'Unexpected console statement.', + removeConsole: 'Remove the console.{{ propertyName }}().' + } + }, + 'no-debugger': { + type: 'suggestion', + docs: { + description: 'Disallow the use of debugger', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-debugger' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "Unexpected 'debugger' statement." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: true, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = await formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); + + test('should handle ignoreSuppressed: false with suppressed messages', async () => { + const mockLintResults: ESLint.LintResult[] = [ + { + filePath: '/src/file4.ts', + source: 'debugger;\nconsole.log("test");', + messages: [ + { + ruleId: 'no-debugger', + severity: 2, + message: "Unexpected 'debugger' statement.", + line: 1, + column: 1, + nodeType: 'DebuggerStatement', + endLine: 1, + endColumn: 10 + } + ], + suppressedMessages: [ + { + ruleId: 'no-console', + severity: 1, + message: 'Unexpected console statement.', + line: 2, + column: 1, + nodeType: 'MemberExpression', + endLine: 2, + endColumn: 12, + suppressions: [ + { + kind: 'inSource', + justification: 'rejected' + } + ] + } + ], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + usedDeprecatedRules: [], + fatalErrorCount: 0 + } + ]; + + const mockRulesMeta: ESLint.LintResultData['rulesMeta'] = { + 'no-console': { + type: 'suggestion', + docs: { + description: 'Disallow the use of `console`', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-console' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: 'Unexpected console statement.', + removeConsole: 'Remove the console.{{ propertyName }}().' + } + }, + 'no-debugger': { + type: 'suggestion', + docs: { + description: 'Disallow the use of debugger', + recommended: false, + url: 'https://eslint.org/docs/latest/rules/no-debugger' + }, + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1, + uniqueItems: true + } + }, + additionalProperties: false + } + ], + hasSuggestions: true, + messages: { + unexpected: "Unexpected 'debugger' statement." + } + } + }; + + const options: ISerifFormatterOptions = { + ignoreSuppressed: false, + eslintVersion: '7.32.0', + buildFolderPath: '/' + }; + + const sarifLog = await formatEslintResultsAsSARIF(mockLintResults, mockRulesMeta, options); + + expect(sarifLog).toMatchSnapshot(); + }); +}); 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 new file mode 100644 index 00000000000..e702399283f --- /dev/null +++ b/heft-plugins/heft-lint-plugin/src/test/__snapshots__/SarifFormatter.test.ts.snap @@ -0,0 +1,556 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`formatEslintResultsAsSARIF case with no files 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "results": Array [], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [], + "version": "7.32.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`formatEslintResultsAsSARIF case with single issues in the same file 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file1.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file1.ts", + }, + "region": Object { + "endColumn": 8, + "endLine": 1, + "snippet": Object { + "text": "x", + }, + "startColumn": 7, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "'x' is defined but never used.", + }, + "ruleId": "no-unused-vars", + "ruleIndex": 0, + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/no-unused-vars", + "id": "no-unused-vars", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "'x' is defined but never used.", + }, + }, + ], + "version": "7.32.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`formatEslintResultsAsSARIF should correctly format ESLint results into SARIF log 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file1.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file1.ts", + }, + "region": Object { + "endColumn": 8, + "endLine": 1, + "snippet": Object { + "text": "x", + }, + "startColumn": 7, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "'x' is defined but never used.", + }, + "ruleId": "no-unused-vars", + "ruleIndex": 0, + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/no-unused-vars", + "id": "no-unused-vars", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "'x' is defined but never used.", + }, + }, + ], + "version": "7.32.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`formatEslintResultsAsSARIF should handle a file with no messages 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file3.ts", + }, + }, + ], + "results": Array [], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [], + "version": "7.32.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`formatEslintResultsAsSARIF should handle ignoreSuppressed: false with suppressed messages 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file4.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file4.ts", + }, + "region": Object { + "endColumn": 10, + "endLine": 1, + "snippet": Object { + "text": "debugger;", + }, + "startColumn": 1, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "Unexpected 'debugger' statement.", + }, + "ruleId": "no-debugger", + "ruleIndex": 0, + "suppressions": Array [], + }, + Object { + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file4.ts", + }, + "region": Object { + "endColumn": 12, + "endLine": 2, + "snippet": Object { + "text": "console.log", + }, + "startColumn": 1, + "startLine": 2, + }, + }, + }, + ], + "message": Object { + "text": "Unexpected console statement.", + }, + "ruleId": "no-console", + "ruleIndex": 1, + "suppressions": Array [ + Object { + "justification": "rejected", + "kind": "external", + }, + ], + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/no-debugger", + "id": "no-debugger", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "Disallow the use of debugger", + }, + }, + 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 ignoreSuppressed: true with suppressed messages 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file4.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file4.ts", + }, + "region": Object { + "endColumn": 10, + "endLine": 1, + "snippet": Object { + "text": "debugger;", + }, + "startColumn": 1, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "Unexpected 'debugger' statement.", + }, + "ruleId": "no-debugger", + "ruleIndex": 0, + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/no-debugger", + "id": "no-debugger", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "Disallow the use of debugger", + }, + }, + ], + "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", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file1.ts", + }, + }, + Object { + "location": Object { + "uri": "src/file2.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file1.ts", + }, + "region": Object { + "endColumn": 8, + "endLine": 1, + "snippet": Object { + "text": "x", + }, + "startColumn": 7, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "'x' is defined but never used.", + }, + "ruleId": "no-unused-vars", + }, + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 1, + "uri": "src/file2.ts", + }, + "region": Object { + "endColumn": 15, + "endLine": 1, + "snippet": Object { + "text": "z == 2", + }, + "startColumn": 9, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "Expected '===' and instead saw '=='.", + }, + "ruleId": "eqeqeq", + "ruleIndex": 0, + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/eqeqeq", + "id": "eqeqeq", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "Require the use of === and !==", + }, + }, + ], + "version": "7.32.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`formatEslintResultsAsSARIF should handle multiple issues in the same file 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/file2.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file2.ts", + }, + "region": Object { + "endColumn": 6, + "endLine": 1, + "snippet": Object { + "text": "x", + }, + "startColumn": 5, + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "'x' is defined but never used.", + }, + "ruleId": "no-unused-vars", + "ruleIndex": 0, + }, + Object { + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/file2.ts", + }, + "region": Object { + "endColumn": 12, + "endLine": 2, + "snippet": Object { + "text": "console.log", + }, + "startColumn": 1, + "startLine": 2, + }, + }, + }, + ], + "message": Object { + "text": "Unexpected console statement.", + }, + "ruleId": "no-console", + "ruleIndex": 1, + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://eslint.org/docs/latest/rules/no-unused-vars", + "id": "no-unused-vars", + "properties": Object { + "category": undefined, + }, + "shortDescription": Object { + "text": "'x' is defined but never used.", + }, + }, + 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", +} +`; diff --git a/heft-plugins/heft-lint-plugin/tsconfig.json b/heft-plugins/heft-lint-plugin/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/heft-plugins/heft-lint-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-localization-typings-plugin/.npmignore b/heft-plugins/heft-localization-typings-plugin/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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-localization-typings-plugin/CHANGELOG.json b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json new file mode 100644 index 00000000000..6fdde118e04 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json @@ -0,0 +1,1086 @@ +{ + "name": "@rushstack/heft-localization-typings-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.14", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.13", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.12", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.11", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.10", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.9", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.8", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.7", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.6", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.5", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.4", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.3", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.2", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.0", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value." + }, + { + "comment": "Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-localization-typings-plugin_v0.1.2", + "date": "Wed, 21 Aug 2024 16:24:51 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `stringNamesToIgnore` option was ignored." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-localization-typings-plugin_v0.1.1", + "date": "Wed, 21 Aug 2024 06:52:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a misnamed property in the options schema." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-localization-typings-plugin_v0.1.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md new file mode 100644 index 00000000000..8d62552a2ea --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md @@ -0,0 +1,317 @@ +# Change Log - @rushstack/heft-localization-typings-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.2.14 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.2.13 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.2.12 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.2.11 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.2.10 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.2.9 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.2.8 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.2.7 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.2.6 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.2.5 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.2.4 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.2.3 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.2.2 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.2.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.2.0 +Mon, 26 Aug 2024 02:00:11 GMT + +### Minor changes + +- Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value. +- Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`. + +## 0.1.2 +Wed, 21 Aug 2024 16:24:51 GMT + +### Patches + +- Fix an issue where the `stringNamesToIgnore` option was ignored. + +## 0.1.1 +Wed, 21 Aug 2024 06:52:07 GMT + +### Patches + +- Fix a misnamed property in the options schema. + +## 0.1.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Initial release. + 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/config/rig.json b/heft-plugins/heft-localization-typings-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-localization-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-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 new file mode 100644 index 00000000000..3d1d82ac7f3 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/heft-plugin.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "localization-typings-plugin", + "entryPoint": "./lib/LocalizationTypingsPlugin", + "optionsSchema": "./lib/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 new file mode 100644 index 00000000000..a072e2c49d1 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/package.json @@ -0,0 +1,29 @@ +{ + "name": "@rushstack/heft-localization-typings-plugin", + "version": "1.0.8", + "description": "Heft plugin for generating types for localization files.", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-localization-typings-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.1.7" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "dependencies": { + "@rushstack/localization-utilities": "workspace:*" + } +} diff --git a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts new file mode 100644 index 00000000000..5d71f8da9a7 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.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 { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskRunIncrementalHookOptions, + IHeftTaskSession, + IScopedLogger, + IWatchedFileState +} from '@rushstack/heft'; +import { type ITypingsGeneratorOptions, TypingsGenerator } from '@rushstack/localization-utilities'; + +export interface ILocalizationTypingsPluginOptions { + /** + * Source code root directory. + * Defaults to "src/". + */ + srcFolder?: string; + + /** + * Output directory for generated typings. + * Defaults to "temp/loc-ts/". + */ + 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. + */ + secondaryGeneratedTsFolders?: string[]; + + exportAsDefault?: ITypingsGeneratorOptions['exportAsDefault']; + + /** + * An array of string names to ignore when generating typings. + */ + stringNamesToIgnore?: string[]; +} + +const PLUGIN_NAME: 'localization-typings-plugin' = 'localization-typings-plugin'; + +export default class LocalizationTypingsPlugin implements IHeftTaskPlugin { + public apply( + taskSession: IHeftTaskSession, + { slashNormalizedBuildFolderPath }: HeftConfiguration, + options?: ILocalizationTypingsPluginOptions + ): void { + const { + srcFolder, + generatedTsFolder, + stringNamesToIgnore, + secondaryGeneratedTsFolders: secondaryGeneratedTsFoldersFromOptions, + trimmedJsonOutputFolders: trimmedJsonOutputFoldersFromOptions + } = options ?? {}; + + let secondaryGeneratedTsFolders: string[] | undefined; + if (secondaryGeneratedTsFoldersFromOptions) { + secondaryGeneratedTsFolders = []; + for (const secondaryGeneratedTsFolder of secondaryGeneratedTsFoldersFromOptions) { + secondaryGeneratedTsFolders.push(`${slashNormalizedBuildFolderPath}/${secondaryGeneratedTsFolder}`); + } + } + + let trimmedJsonOutputFolders: string[] | undefined; + if (trimmedJsonOutputFoldersFromOptions) { + trimmedJsonOutputFolders = []; + for (const trimmedJsonOutputFolder of trimmedJsonOutputFoldersFromOptions) { + trimmedJsonOutputFolders.push(`${slashNormalizedBuildFolderPath}/${trimmedJsonOutputFolder}`); + } + } + + const logger: IScopedLogger = taskSession.logger; + const stringNamesToIgnoreSet: Set | undefined = stringNamesToIgnore + ? new Set(stringNamesToIgnore) + : undefined; + + const typingsGenerator: TypingsGenerator = new TypingsGenerator({ + ...options, + srcFolder: `${slashNormalizedBuildFolderPath}/${srcFolder ?? 'src'}`, + generatedTsFolder: `${slashNormalizedBuildFolderPath}/${generatedTsFolder ?? 'temp/loc-ts'}`, + terminal: logger.terminal, + ignoreString: stringNamesToIgnoreSet + ? (filePath: string, stringName: string) => stringNamesToIgnoreSet.has(stringName) + : undefined, + secondaryGeneratedTsFolders + }); + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async () => { + await this._runLocalizationTypingsGeneratorAsync(typingsGenerator, logger, undefined); + }); + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runLocalizationTypingsGeneratorAsync(typingsGenerator, logger, runIncrementalOptions); + } + ); + } + + private async _runLocalizationTypingsGeneratorAsync( + typingsGenerator: TypingsGenerator, + { terminal }: IScopedLogger, + 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 localization typings...'); + await typingsGenerator.generateTypingsAsync(changedRelativeFilePaths); + } +} 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..ae9cf8f52c3 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json @@ -0,0 +1,85 @@ +{ + "$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" + } + } + } +} diff --git a/heft-plugins/heft-localization-typings-plugin/tsconfig.json b/heft-plugins/heft-localization-typings-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-localization-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-rspack-plugin/.npmignore b/heft-plugins/heft-rspack-plugin/.npmignore new file mode 100644 index 00000000000..ffb155d74e6 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** diff --git a/heft-plugins/heft-rspack-plugin/CHANGELOG.json b/heft-plugins/heft-rspack-plugin/CHANGELOG.json new file mode 100644 index 00000000000..c7ecdb04be7 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/CHANGELOG.json @@ -0,0 +1,70 @@ +{ + "name": "@rushstack/heft-rspack-plugin", + "entries": [ + { + "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..a26528ececc --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/CHANGELOG.md @@ -0,0 +1,23 @@ +# Change Log - @rushstack/heft-rspack-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..74590d3c4f8 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$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": 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..a8ce14984a6 --- /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/RspackPlugin", + "optionsSchema": "./lib/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..4b34b709381 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/heft-rspack-plugin", + "version": "0.1.2", + "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/index.js", + "types": "dist/heft-rspack-plugin.d.ts", + "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.1.7", + "@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.98.0" + }, + "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" + } +} 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..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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..eeb7eddcf78 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.json @@ -0,0 +1,527 @@ +{ + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "entries": [ + { + "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..2f8164f034e --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md @@ -0,0 +1,135 @@ +# Change Log - @rushstack/heft-sass-load-themed-styles-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..ef11936b177 --- /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/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..5d21ba99bef --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/package.json @@ -0,0 +1,30 @@ +{ + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "version": "1.1.7", + "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.1.7" + }, + "dependencies": { + "@microsoft/load-themed-styles": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-sass-plugin": "workspace:*", + "local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} 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/.npmignore b/heft-plugins/heft-sass-plugin/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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-plugin/CHANGELOG.json b/heft-plugins/heft-sass-plugin/CHANGELOG.json new file mode 100644 index 00000000000..3d01e897cf8 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/CHANGELOG.json @@ -0,0 +1,6656 @@ +{ + "name": "@rushstack/heft-sass-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.15.8", + "tag": "@rushstack/heft-sass-plugin_v0.15.8", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.15.7", + "tag": "@rushstack/heft-sass-plugin_v0.15.7", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/heft-sass-plugin_v0.15.6", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.15.5", + "tag": "@rushstack/heft-sass-plugin_v0.15.5", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/heft-sass-plugin_v0.15.4", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/heft-sass-plugin_v0.15.3", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/heft-sass-plugin_v0.15.2", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/heft-sass-plugin_v0.15.1", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/heft-sass-plugin_v0.15.0", + "date": "Thu, 03 Oct 2024 19:46:23 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"suppressDeprecations\" option to suppress specific SASS deprecation IDs. Add \"ignoreDeprecationsInDependencies\" option to ignore deprecation warnings from external SASS." + } + ] + } + }, + { + "version": "0.14.24", + "tag": "@rushstack/heft-sass-plugin_v0.14.24", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.14.23", + "tag": "@rushstack/heft-sass-plugin_v0.14.23", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.14.22", + "tag": "@rushstack/heft-sass-plugin_v0.14.22", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.14.21", + "tag": "@rushstack/heft-sass-plugin_v0.14.21", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.3`" + } + ] + } + }, + { + "version": "0.14.20", + "tag": "@rushstack/heft-sass-plugin_v0.14.20", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.14.19", + "tag": "@rushstack/heft-sass-plugin_v0.14.19", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.14.18", + "tag": "@rushstack/heft-sass-plugin_v0.14.18", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.0`" + } + ] + } + }, + { + "version": "0.14.17", + "tag": "@rushstack/heft-sass-plugin_v0.14.17", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.14.16", + "tag": "@rushstack/heft-sass-plugin_v0.14.16", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.63`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.14.15", + "tag": "@rushstack/heft-sass-plugin_v0.14.15", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.62`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.14.14", + "tag": "@rushstack/heft-sass-plugin_v0.14.14", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.61`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/heft-sass-plugin_v0.14.13", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.60`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/heft-sass-plugin_v0.14.12", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.59`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/heft-sass-plugin_v0.14.11", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/heft-sass-plugin_v0.14.10", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.57`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/heft-sass-plugin_v0.14.9", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/heft-sass-plugin_v0.14.8", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.55`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/heft-sass-plugin_v0.14.7", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.54`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/heft-sass-plugin_v0.14.6", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.53`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/heft-sass-plugin_v0.14.5", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.52`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/heft-sass-plugin_v0.14.4", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.51`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/heft-sass-plugin_v0.14.3", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.50`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/heft-sass-plugin_v0.14.2", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.49`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/heft-sass-plugin_v0.14.1", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.48`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/heft-sass-plugin_v0.14.0", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `sass-embedded` to 1.77." + }, + { + "comment": "Fix an issue where `@import` and `@use` rules that referenced dependency packages that are not direct dependencies of the project being built were not correctly resolved." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.47`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.13.32", + "tag": "@rushstack/heft-sass-plugin_v0.13.32", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.46`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.13.31", + "tag": "@rushstack/heft-sass-plugin_v0.13.31", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.45`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.13.30", + "tag": "@rushstack/heft-sass-plugin_v0.13.30", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.44`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.13.29", + "tag": "@rushstack/heft-sass-plugin_v0.13.29", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.43`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.13.28", + "tag": "@rushstack/heft-sass-plugin_v0.13.28", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.42`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.13.27", + "tag": "@rushstack/heft-sass-plugin_v0.13.27", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.41`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.13.26", + "tag": "@rushstack/heft-sass-plugin_v0.13.26", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.40`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.13.25", + "tag": "@rushstack/heft-sass-plugin_v0.13.25", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.39`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.13.24", + "tag": "@rushstack/heft-sass-plugin_v0.13.24", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.13.23", + "tag": "@rushstack/heft-sass-plugin_v0.13.23", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.13.22", + "tag": "@rushstack/heft-sass-plugin_v0.13.22", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.36`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.13.21", + "tag": "@rushstack/heft-sass-plugin_v0.13.21", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.35`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.13.20", + "tag": "@rushstack/heft-sass-plugin_v0.13.20", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.34`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.13.19", + "tag": "@rushstack/heft-sass-plugin_v0.13.19", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.33`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.13.18", + "tag": "@rushstack/heft-sass-plugin_v0.13.18", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.32`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.13.17", + "tag": "@rushstack/heft-sass-plugin_v0.13.17", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.31`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.13.16", + "tag": "@rushstack/heft-sass-plugin_v0.13.16", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.13.15", + "tag": "@rushstack/heft-sass-plugin_v0.13.15", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.29`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.13.14", + "tag": "@rushstack/heft-sass-plugin_v0.13.14", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.28`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.13.13", + "tag": "@rushstack/heft-sass-plugin_v0.13.13", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.13.12", + "tag": "@rushstack/heft-sass-plugin_v0.13.12", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.13.11", + "tag": "@rushstack/heft-sass-plugin_v0.13.11", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.13.10", + "tag": "@rushstack/heft-sass-plugin_v0.13.10", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/heft-sass-plugin_v0.13.9", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/heft-sass-plugin_v0.13.8", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/heft-sass-plugin_v0.13.7", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/heft-sass-plugin_v0.13.6", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.13.5", + "tag": "@rushstack/heft-sass-plugin_v0.13.5", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/heft-sass-plugin_v0.13.4", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.18`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/heft-sass-plugin_v0.13.3", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/heft-sass-plugin_v0.13.2", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/heft-sass-plugin_v0.13.1", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/heft-sass-plugin_v0.13.0", + "date": "Fri, 08 Dec 2023 20:48:44 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade postcss-modules from v1.5.0 to v6.0.0" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/heft-sass-plugin_v0.12.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/heft-sass-plugin_v0.12.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/heft-sass-plugin_v0.12.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/heft-sass-plugin_v0.12.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/heft-sass-plugin_v0.12.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/heft-sass-plugin_v0.12.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/heft-sass-plugin_v0.12.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/heft-sass-plugin_v0.12.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/heft-sass-plugin_v0.12.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/heft-sass-plugin_v0.12.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/heft-sass-plugin_v0.12.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/heft-sass-plugin_v0.12.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/heft-sass-plugin_v0.12.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/heft-sass-plugin_v0.12.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/heft-sass-plugin_v0.12.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.11.28", + "tag": "@rushstack/heft-sass-plugin_v0.11.28", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.11.27", + "tag": "@rushstack/heft-sass-plugin_v0.11.27", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.11.26", + "tag": "@rushstack/heft-sass-plugin_v0.11.26", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.37`" + } + ] + } + }, + { + "version": "0.11.25", + "tag": "@rushstack/heft-sass-plugin_v0.11.25", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.11.24", + "tag": "@rushstack/heft-sass-plugin_v0.11.24", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.11.23", + "tag": "@rushstack/heft-sass-plugin_v0.11.23", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.11.22", + "tag": "@rushstack/heft-sass-plugin_v0.11.22", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.33`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.11.21", + "tag": "@rushstack/heft-sass-plugin_v0.11.21", + "date": "Mon, 17 Jul 2023 15:20:25 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the \"excludeFiles\" configuration option." + } + ] + } + }, + { + "version": "0.11.20", + "tag": "@rushstack/heft-sass-plugin_v0.11.20", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.11.19", + "tag": "@rushstack/heft-sass-plugin_v0.11.19", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.11.18", + "tag": "@rushstack/heft-sass-plugin_v0.11.18", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.30`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.11.17", + "tag": "@rushstack/heft-sass-plugin_v0.11.17", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/heft-sass-plugin_v0.11.16", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/heft-sass-plugin_v0.11.15", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/heft-sass-plugin_v0.11.14", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/heft-sass-plugin_v0.11.13", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/heft-sass-plugin_v0.11.12", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/heft-sass-plugin_v0.11.11", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/heft-sass-plugin_v0.11.10", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/heft-sass-plugin_v0.11.9", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/heft-sass-plugin_v0.11.8", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/heft-sass-plugin_v0.11.7", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/heft-sass-plugin_v0.11.6", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/heft-sass-plugin_v0.11.5", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/heft-sass-plugin_v0.11.4", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/heft-sass-plugin_v0.11.3", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/heft-sass-plugin_v0.11.2", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft-sass-plugin_v0.11.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft-sass-plugin_v0.11.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-sass-plugin_v0.10.0", + "date": "Fri, 02 Jun 2023 00:24:45 GMT", + "comments": { + "minor": [ + { + "comment": "Update to sass-embedded ~1.62.0" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-sass-plugin_v0.9.3", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-sass-plugin_v0.9.2", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-sass-plugin_v0.9.1", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-sass-plugin_v0.9.0", + "date": "Thu, 11 May 2023 00:17:21 GMT", + "comments": { + "minor": [ + { + "comment": "Switch from sass to sass-embedded for better performance." + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/heft-sass-plugin_v0.8.9", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/heft-sass-plugin_v0.8.8", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/heft-sass-plugin_v0.8.7", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/heft-sass-plugin_v0.8.6", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/heft-sass-plugin_v0.8.5", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/heft-sass-plugin_v0.8.4", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/heft-sass-plugin_v0.8.3", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/heft-sass-plugin_v0.8.2", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-sass-plugin_v0.8.1", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-sass-plugin_v0.8.0", + "date": "Tue, 31 Jan 2023 01:23:23 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"preserveSCSSExtension\" flag for backwards compatibility with build flows that cannot be expected to alter import resolution." + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/heft-sass-plugin_v0.7.10", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/heft-sass-plugin_v0.7.9", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/heft-sass-plugin_v0.7.8", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-sass-plugin_v0.7.7", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-sass-plugin_v0.7.6", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/heft-sass-plugin_v0.7.5", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-sass-plugin_v0.7.4", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-sass-plugin_v0.7.3", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.12`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-sass-plugin_v0.7.2", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-sass-plugin_v0.7.1", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-sass-plugin_v0.7.0", + "date": "Wed, 26 Oct 2022 15:16:29 GMT", + "comments": { + "minor": [ + { + "comment": "Update sass transpiler to dart-sass" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft-sass-plugin_v0.6.4", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-sass-plugin_v0.6.3", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-sass-plugin_v0.6.2", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-sass-plugin_v0.6.1", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-sass-plugin_v0.6.0", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "minor": [ + { + "comment": "Add `nonModuleFileExtensions` property to support generating typings for non-module CSS files." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/heft-sass-plugin_v0.5.21", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/heft-sass-plugin_v0.5.20", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/heft-sass-plugin_v0.5.19", + "date": "Sat, 08 Oct 2022 02:30:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with identifying partial sass files on Windows." + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/heft-sass-plugin_v0.5.18", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/heft-sass-plugin_v0.5.17", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/heft-sass-plugin_v0.5.16", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/heft-sass-plugin_v0.5.15", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/heft-sass-plugin_v0.5.14", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/heft-sass-plugin_v0.5.13", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/heft-sass-plugin_v0.5.12", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/heft-sass-plugin_v0.5.11", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/heft-sass-plugin_v0.5.10", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/heft-sass-plugin_v0.5.9", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/heft-sass-plugin_v0.5.8", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/heft-sass-plugin_v0.5.7", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/heft-sass-plugin_v0.5.6", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/heft-sass-plugin_v0.5.5", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/heft-sass-plugin_v0.5.4", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-sass-plugin_v0.5.3", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-sass-plugin_v0.5.2", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-sass-plugin_v0.5.1", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-sass-plugin_v0.5.0", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where cssOutputFolders specified in sass.json in a rig did not correctly resolve relative to the root of the project being built." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-sass-plugin_v0.4.7", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-sass-plugin_v0.4.6", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-sass-plugin_v0.4.5", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-sass-plugin_v0.4.4", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-sass-plugin_v0.4.3", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-sass-plugin_v0.4.2", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-sass-plugin_v0.4.1", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-sass-plugin_v0.4.0", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to output typings to additional output folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/heft-sass-plugin_v0.3.30", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.30`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-sass-plugin_v0.3.29", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.29`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-sass-plugin_v0.3.28", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.28`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-sass-plugin_v0.3.27", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-sass-plugin_v0.3.26", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.26`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-sass-plugin_v0.3.25", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-sass-plugin_v0.3.24", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-sass-plugin_v0.3.23", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-sass-plugin_v0.3.22", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-sass-plugin_v0.3.21", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-sass-plugin_v0.3.20", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-sass-plugin_v0.3.19", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-sass-plugin_v0.3.18", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-sass-plugin_v0.3.17", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-sass-plugin_v0.3.16", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-sass-plugin_v0.3.15", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-sass-plugin_v0.3.14", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-sass-plugin_v0.3.13", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-sass-plugin_v0.3.12", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-sass-plugin_v0.3.11", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-sass-plugin_v0.3.10", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-sass-plugin_v0.3.9", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-sass-plugin_v0.3.8", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-sass-plugin_v0.3.7", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade postcss" + }, + { + "comment": "Update JSON schema documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-sass-plugin_v0.3.6", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-sass-plugin_v0.3.5", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-sass-plugin_v0.3.4", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-sass-plugin_v0.3.3", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-sass-plugin_v0.3.2", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-sass-plugin_v0.3.1", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-sass-plugin_v0.3.0", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add a \"cssOuputFolders\" option to \"config/sass.json\" to emit compiled CSS." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-sass-plugin_v0.2.10", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-sass-plugin_v0.2.9", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-sass-plugin_v0.2.8", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-sass-plugin_v0.2.7", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-sass-plugin_v0.2.6", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-sass-plugin_v0.2.5", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-sass-plugin_v0.2.4", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-sass-plugin_v0.2.3", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-sass-plugin_v0.2.2", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-sass-plugin_v0.2.1", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-sass-plugin_v0.2.0", + "date": "Thu, 28 Oct 2021 23:48:23 GMT", + "comments": { + "minor": [ + { + "comment": "Update node-sass to version 6 to support Node 16." + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-sass-plugin_v0.1.30", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-sass-plugin_v0.1.29", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-sass-plugin_v0.1.28", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-sass-plugin_v0.1.27", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-sass-plugin_v0.1.26", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-sass-plugin_v0.1.25", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-sass-plugin_v0.1.24", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-sass-plugin_v0.1.23", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-sass-plugin_v0.1.22", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-sass-plugin_v0.1.21", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-sass-plugin_v0.1.20", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-sass-plugin_v0.1.19", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-sass-plugin_v0.1.18", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-sass-plugin_v0.1.17", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-sass-plugin_v0.1.16", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-sass-plugin_v0.1.15", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-sass-plugin_v0.1.14", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.4` to `^0.38.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-sass-plugin_v0.1.13", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.3` to `^0.37.4`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-sass-plugin_v0.1.12", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.2` to `^0.37.3`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-sass-plugin_v0.1.11", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.1` to `^0.37.2`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-sass-plugin_v0.1.10", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.0` to `^0.37.1`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-sass-plugin_v0.1.9", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-sass-plugin_v0.1.8", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.4` to `^0.37.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-sass-plugin_v0.1.7", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.3` to `^0.36.4`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-sass-plugin_v0.1.6", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.36.3`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-sass-plugin_v0.1.5", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-sass-plugin_v0.1.4", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.1` to `^0.36.2`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-sass-plugin_v0.1.3", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.0` to `^0.36.1`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-sass-plugin_v0.1.2", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.1` to `^0.36.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-sass-plugin_v0.1.1", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.0` to `^0.35.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-sass-plugin_v0.1.0", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "minor": [ + { + "comment": "Extract default Sass plugin to separate package" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.8` to `^0.35.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-sass-plugin/CHANGELOG.md b/heft-plugins/heft-sass-plugin/CHANGELOG.md new file mode 100644 index 00000000000..4f9b80eac2e --- /dev/null +++ b/heft-plugins/heft-sass-plugin/CHANGELOG.md @@ -0,0 +1,1510 @@ +# Change Log - @rushstack/heft-sass-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.15.8 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.15.7 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.15.6 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.15.5 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.15.4 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.15.3 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.15.2 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.15.1 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.15.0 +Thu, 03 Oct 2024 19:46:23 GMT + +### Minor changes + +- Add "suppressDeprecations" option to suppress specific SASS deprecation IDs. Add "ignoreDeprecationsInDependencies" option to ignore deprecation warnings from external SASS. + +## 0.14.24 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.14.23 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.14.22 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.14.21 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.14.20 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.14.19 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.14.18 +Mon, 26 Aug 2024 02:00:11 GMT + +_Version update only_ + +## 0.14.17 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.14.16 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.14.15 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.14.14 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.14.13 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.14.12 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.14.11 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.14.10 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.14.9 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.14.8 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.14.7 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.14.6 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.14.5 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.14.4 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.14.3 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.14.2 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.14.1 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.14.0 +Thu, 23 May 2024 02:26:56 GMT + +### Minor changes + +- Bump `sass-embedded` to 1.77. +- Fix an issue where `@import` and `@use` rules that referenced dependency packages that are not direct dependencies of the project being built were not correctly resolved. + +## 0.13.32 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.13.31 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.13.30 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.13.29 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.13.28 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.13.27 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.13.26 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.13.25 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.13.24 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.13.23 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.13.22 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.13.21 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.13.20 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.13.19 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.13.18 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.13.17 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.13.16 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.13.15 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.13.14 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.13.13 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.13.12 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.13.11 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.13.10 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.13.9 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.13.8 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.13.7 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.13.6 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.13.5 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.13.4 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.13.3 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.13.2 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.13.1 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.13.0 +Fri, 08 Dec 2023 20:48:44 GMT + +### Minor changes + +- Upgrade postcss-modules from v1.5.0 to v6.0.0 + +## 0.12.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.12.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.12.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.12.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.12.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.12.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.12.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.12.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.12.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.12.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.12.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.12.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.12.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.12.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.12.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.11.28 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.11.27 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.11.26 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.11.25 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.11.24 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.11.23 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.11.22 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.11.21 +Mon, 17 Jul 2023 15:20:25 GMT + +### Patches + +- Fix the "excludeFiles" configuration option. + +## 0.11.20 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.11.19 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.11.18 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.11.17 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.11.16 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.11.15 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.11.14 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.11.13 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.11.12 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.11.11 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.11.10 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.11.9 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.11.8 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.11.7 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.11.6 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.11.5 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.11.4 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.11.3 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.11.2 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.11.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.11.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.10.0 +Fri, 02 Jun 2023 00:24:45 GMT + +### Minor changes + +- Update to sass-embedded ~1.62.0 + +## 0.9.3 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.9.2 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.9.1 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.9.0 +Thu, 11 May 2023 00:17:21 GMT + +### Minor changes + +- Switch from sass to sass-embedded for better performance. + +## 0.8.9 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.8.8 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.8.7 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.8.6 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.8.5 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.8.4 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.8.3 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.8.2 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.8.1 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.8.0 +Tue, 31 Jan 2023 01:23:23 GMT + +### Minor changes + +- Add "preserveSCSSExtension" flag for backwards compatibility with build flows that cannot be expected to alter import resolution. + +## 0.7.10 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.7.9 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.7.8 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.7.7 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.7.6 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.7.5 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.7.4 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.7.3 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 0.7.2 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.7.1 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.7.0 +Wed, 26 Oct 2022 15:16:29 GMT + +### Minor changes + +- Update sass transpiler to dart-sass + +## 0.6.4 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.6.3 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.6.2 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.6.1 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.6.0 +Thu, 13 Oct 2022 00:20:15 GMT + +### Minor changes + +- Add `nonModuleFileExtensions` property to support generating typings for non-module CSS files. + +## 0.5.21 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.5.20 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.5.19 +Sat, 08 Oct 2022 02:30:08 GMT + +### Patches + +- Fix an issue with identifying partial sass files on Windows. + +## 0.5.18 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.5.17 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.5.16 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.5.15 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.5.14 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.5.13 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.5.12 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.5.11 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.5.10 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.5.9 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.5.8 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.5.7 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.5.6 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.5.5 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.5.4 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.5.3 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.5.2 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.5.1 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.5.0 +Wed, 13 Jul 2022 21:31:13 GMT + +### Minor changes + +- Fix an issue where cssOutputFolders specified in sass.json in a rig did not correctly resolve relative to the root of the project being built. + +## 0.4.7 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.4.6 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.4.5 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.4.4 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.4.3 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.4.2 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.4.1 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.4.0 +Sat, 25 Jun 2022 01:54:29 GMT + +### Minor changes + +- Add an option to output typings to additional output folders. + +## 0.3.30 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.3.29 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.3.28 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.3.27 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.3.26 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.3.25 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.3.24 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.3.23 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.3.22 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.3.21 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.3.20 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.3.19 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.3.18 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.3.17 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.3.16 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.3.15 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.3.14 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.3.13 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.3.12 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.3.11 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.3.10 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.3.9 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.3.8 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.3.7 +Fri, 11 Feb 2022 10:30:25 GMT + +### Patches + +- Upgrade postcss +- Update JSON schema documentation + +## 0.3.6 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.3.5 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.3.4 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.3.3 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.3.2 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.3.1 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.3.0 +Fri, 10 Dec 2021 01:09:33 GMT + +### Minor changes + +- Add a "cssOuputFolders" option to "config/sass.json" to emit compiled CSS. + +## 0.2.10 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.2.9 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.2.8 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.2.7 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.2.6 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 0.2.5 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.2.4 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.2.3 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.2.2 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.2.1 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.2.0 +Thu, 28 Oct 2021 23:48:23 GMT + +### Minor changes + +- Update node-sass to version 6 to support Node 16. + +## 0.1.30 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.1.29 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.1.28 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.1.27 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.1.26 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.1.25 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.1.24 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.1.23 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.1.22 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.1.21 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 0.1.20 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.1.19 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.1.18 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.1.17 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.1.16 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.1.15 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.1.14 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.1.13 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.1.12 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.1.11 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.1.10 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.1.9 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.1.8 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.1.7 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.1.6 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.1.5 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 0.1.4 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.1.3 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.1.2 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.1.1 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.1.0 +Sat, 31 Jul 2021 00:52:11 GMT + +### Minor changes + +- Extract default Sass plugin to separate package + diff --git a/heft-plugins/heft-sass-plugin/LICENSE b/heft-plugins/heft-sass-plugin/LICENSE new file mode 100644 index 00000000000..40e2a06dc72 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-sass-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-plugin/README.md b/heft-plugins/heft-sass-plugin/README.md new file mode 100644 index 00000000000..1d6602caf7e --- /dev/null +++ b/heft-plugins/heft-sass-plugin/README.md @@ -0,0 +1,12 @@ +# @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. + +## 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 + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. 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/rig.json b/heft-plugins/heft-sass-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-sass-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-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 new file mode 100644 index 00000000000..ab4d21de8f6 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "sass-plugin", + "entryPoint": "./lib/SassPlugin.js" + } + ] +} diff --git a/heft-plugins/heft-sass-plugin/package.json b/heft-plugins/heft-sass-plugin/package.json new file mode 100644 index 00000000000..0765dc8b1a0 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/package.json @@ -0,0 +1,37 @@ +{ + "name": "@rushstack/heft-sass-plugin", + "version": "1.1.7", + "description": "Heft plugin for SASS", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-sass-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" + }, + "main": "lib/index.js", + "types": "lib/index.d.ts", + "peerDependencies": { + "@rushstack/heft": "^1.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@types/tapable": "1.0.6", + "postcss": "~8.4.6", + "postcss-modules": "~6.0.0", + "sass-embedded": "~1.85.1", + "tapable": "1.1.3" + }, + "devDependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/heft-plugins/heft-sass-plugin/src/SassPlugin.ts b/heft-plugins/heft-sass-plugin/src/SassPlugin.ts new file mode 100644 index 00000000000..3525cbfa817 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/SassPlugin.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. + +import path from 'node:path'; + +import { AsyncSeriesWaterfallHook } from 'tapable'; + +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftPlugin, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions, + IWatchedFileState, + ConfigurationFile +} from '@rushstack/heft'; + +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 { + srcFolder?: string; + generatedTsFolder?: string; + cssOutputFolders?: (string | ICssOutputFolder)[]; + secondaryGeneratedTsFolders?: string[]; + exportAsDefault?: boolean; + fileExtensions?: string[]; + nonModuleFileExtensions?: string[]; + silenceDeprecations?: string[]; + excludeFiles?: string[]; +} + +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 { + public accessor: ISassPluginAccessor = { + hooks: { + postProcessCss: new AsyncSeriesWaterfallHook(['cssText']) + } + }; + + /** + * Generate typings for Sass files before TypeScript compilation. + */ + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + 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; + } + + 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 + } = sassConfigurationJson || {}; + + function resolveFolder(folder: string): string { + return path.resolve(slashNormalizedBuildFolderPath, folder); + } + + 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, + postProcessCssAsync: hooks.postProcessCss.isUsed() + ? async (cssText: string) => hooks.postProcessCss.promise(cssText) + : undefined + }; + + const sassProcessor: SassProcessor = new SassProcessor(sassProcessorOptions); + await sassProcessor.loadCacheAsync(tempFolderPath); + + return sassProcessor; + })()); + } + + const compileFilesAsync = async ( + sassProcessor: SassProcessor, + files: Set, + changed: boolean + ): Promise => { + if (files.size === 0) { + terminal.writeLine(`No SCSS files to process.`); + return; + } + + await sassProcessor.compileFilesAsync(files); + terminal.writeLine(`Finished compiling.`); + }; + + 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 + }); + + const fileSet: Set = new Set(); + for (const file of files) { + // Using path.resolve to normalize slashes + fileSet.add(path.resolve(file)); + } + + await compileFilesAsync(sassProcessor, fileSet, false); + }); + + 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 + } + ); + + const modifiedFiles: Set = new Set(); + for (const [file, { changed }] of changedFiles) { + if (changed) { + modifiedFiles.add(file); + } + } + + await compileFilesAsync(sassProcessor, modifiedFiles, true); + } + ); + } +} diff --git a/heft-plugins/heft-sass-plugin/src/SassProcessor.ts b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts new file mode 100644 index 00000000000..d3a7da77acc --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts @@ -0,0 +1,995 @@ +// 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 { + type CompileResult, + type Syntax, + type Exception, + type CanonicalizeContext, + deprecations, + type Deprecations, + type DeprecationOrId, + type ImporterResult, + type AsyncCompiler, + type Options, + initAsyncCompiler +} from 'sass-embedded'; +import * as postcss from 'postcss'; +import cssModules from 'postcss-modules'; + +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 ICssOutputFolder { + folder: string; + shimModuleFormat: 'commonjs' | 'esnext' | undefined; +} + +/** + * @public + */ +export interface ISassProcessorOptions { + /** + * The logger for this processor. + */ + logger: IScopedLogger; + + /** + * The project root folder. + */ + buildFolder: string; + + /** + * How many SASS compiler processes to run in parallel. + */ + concurrency: number; + + /** + * Source code root directory. + * Defaults to "src/". + */ + srcFolder: string; + + /** + * Output directory for generated Sass typings. + * Defaults to "temp/sass-ts/". + */ + dtsOutputFolders: string[]; + + /** + * Output kinds for generated JS stubs and CSS files. + */ + cssOutputFolders?: ICssOutputFolder[]; + + /** + * Determines whether export values are wrapped in a default property, or not. + */ + exportAsDefault: boolean; + + /** + * Files with these extensions will pass through the Sass transpiler for typings generation. + * They will be treated as SCSS modules. + * Defaults to [".sass", ".scss", ".css"] + */ + fileExtensions?: string[]; + + /** + * Files with these extensions will pass through the Sass transpiler for typings generation. + * They will be treated as non-module SCSS. + * Defaults to [".global.sass", ".global.scss", ".global.css"] + */ + nonModuleFileExtensions?: string[]; + + /** + * A list of file paths relative to the "src" folder that should be excluded from typings generation. + */ + excludeFiles?: string[]; + + /** + * If set, deprecation warnings from dependencies will be suppressed. + */ + ignoreDeprecationsInDependencies?: boolean; + + /** + * 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[]; + + /** + * A callback to further modify the raw CSS text after it has been generated. Only relevant if emitting CSS files. + */ + postProcessCssAsync?: (cssText: string) => Promise; +} + +/** + * @public + */ +export interface ISassTypingsGeneratorOptions { + buildFolder: string; + 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[]; +} + +/** + * 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 and .scss.js redirector files. + * + * @public + */ +export class SassProcessor { + public readonly ignoredFileGlobs: string[] | undefined; + public readonly inputFileGlob: string; + public readonly sourceFolderPath: string; + + // Map of input file path -> record + private readonly _fileInfo: Map; + private readonly _resolutions: Map; + + 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 deprecation as keyof Deprecations; + }) + : undefined; + + 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) + }; + }; + + 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 + }; + } + + 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 { + 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); + } + } + + // 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 + } + ); + + 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); + } + } + + 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())); + } + } + + // 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 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 (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); + } + + // Check the cache first, and exit early if previously resolved + if (url.startsWith('heft:')) { + return await this._canonicalizeHeftUrlAsync(url, context); + } + + const { containingUrl } = context; + if (!containingUrl) { + throw new Error(`Cannot resolve ${url} without a containing URL`); + } + + 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')) { + // 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 + for (const candidate of [`${url}.scss`, `${url}.sass`, `${url}/index.scss`, `${url}/index.sass`]) { + 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); + } + + /** + * Configures the state of this processor using the specified cache file content. + * @param cacheFileContent - The contents of the cache file + */ + 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); + } + } + } + + /** + * 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; + try { + result = await compiler.compileStringAsync(content, { + ...scssOptions, + url: record.url, + syntax: determineSyntaxFromFilePath(sourceFilePath) + }); + } catch (err) { + const typedError: Exception = err; + const { span } = typedError; + + 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 files as dependencies. + record.dependencies.clear(); + for (const dependency of result.loadedUrls) { + 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; + } + + record.cssVersion = contentHash; + const { cssOutputFolders, dtsOutputFolders, srcFolder, exportAsDefault, postProcessCssAsync } = + 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 }); + css = postCssResult.css; + } + + if (postProcessCssAsync) { + css = await postProcessCssAsync(css); + } + + const relativeFilePath: string = path.relative(srcFolder, sourceFilePath); + + const dtsContent: string = this._createDTS(moduleMap); + + const writeFileOptions: IFileSystemWriteFileOptions = { + ensureFolderExists: true + }; + + for (const dtsOutputFolder of dtsOutputFolders) { + await FileSystem.writeFileAsync( + path.resolve(dtsOutputFolder, `${relativeFilePath}.d.ts`), + dtsContent, + writeFileOptions + ); + } + + const filename: string = path.basename(relativeFilePath); + const extensionStart: number = filename.lastIndexOf('.'); + const cssPathFromJs: string = `./${filename.slice(0, extensionStart)}.css`; + const relativeCssPath: string = `${relativeFilePath.slice(0, relativeFilePath.lastIndexOf('.'))}.css`; + + if (cssOutputFolders && cssOutputFolders.length > 0) { + if (!exportAsDefault) { + throw new Error(`The "cssOutputFolders" option is not supported when "exportAsDefault" is false.`); + } + + for (const cssOutputFolder of cssOutputFolders) { + const { folder, shimModuleFormat } = cssOutputFolder; + + const cssFilePath: string = path.resolve(folder, relativeCssPath); + await FileSystem.writeFileAsync(cssFilePath, css, writeFileOptions); + + if (shimModuleFormat && !filename.endsWith('.css')) { + const jsFilePath: string = path.resolve(folder, `${relativeFilePath}.js`); + const jsShimContent: string = generateJsShimContent( + shimModuleFormat, + cssPathFromJs, + record.isModule + ); + await FileSystem.writeFileAsync(jsFilePath, jsShimContent, writeFileOptions); + } + } + } + } + + private _createDTS(moduleMap: JsonObject | undefined): string { + // Create a source file. + const source: string[] = []; + + if (moduleMap) { + if (this._options.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;`); + } + } + } + + if (source.length === 0 || !moduleMap) { + return `export {};`; + } + + return source.join('\n'); + } +} + +interface IExtensionClassifier { + allFileExtensions: string[]; + isFileModule: (relativePath: string) => boolean; +} + +function buildExtensionClassifier(sassConfiguration: ISassProcessorOptions): IExtensionClassifier { + const { + fileExtensions: moduleFileExtensions = ['.sass', '.scss', '.css'], + nonModuleFileExtensions = ['.global.sass', '.global.scss', '.global.css'] + } = sassConfiguration; + + const hasModules: boolean = moduleFileExtensions.length > 0; + const hasNonModules: boolean = nonModuleFileExtensions.length > 0; + + if (!hasModules) { + return { + allFileExtensions: nonModuleFileExtensions, + isFileModule: (relativePath: string) => false + }; + } + + if (!hasNonModules) { + return { + allFileExtensions: moduleFileExtensions, + isFileModule: (relativePath: string) => true + }; + } + + const extensionClassifier: Map = new Map(); + for (const extension of moduleFileExtensions) { + const normalizedExtension: string = extension.startsWith('.') ? extension : `.${extension}`; + extensionClassifier.set(normalizedExtension, true); + } + + for (const extension of nonModuleFileExtensions) { + const normalizedExtension: string = extension.startsWith('.') ? extension : `.${extension}`; + const existingClassification: boolean | undefined = extensionClassifier.get(normalizedExtension); + if (existingClassification === true) { + throw new Error( + `File extension "${normalizedExtension}" is declared as both a SCSS module and not an SCSS module.` + ); + } + extensionClassifier.set(normalizedExtension, false); + } + + Sort.sortMapKeys(extensionClassifier, (key1, key2) => { + // Order by length, descending, so the longest gets tested first. + return key2.length - key1.length; + }); + + const isFileModule: (relativePath: string) => boolean = (relativePath: string) => { + // Naive comparison algorithm. O(E), where E is the number of extensions + // If performance becomes an issue, switch to using LookupByPath with a reverse iteration order using `.` as the delimiter + for (const [extension, isExtensionModule] of extensionClassifier) { + if (relativePath.endsWith(extension)) { + return isExtensionModule; + } + } + throw new Error(`Could not classify ${relativePath} as a SCSS module / not an SCSS module`); + }; + + return { + allFileExtensions: [...extensionClassifier.keys()], + isFileModule + }; +} + +/** + * 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.slice(filePath.lastIndexOf('.'))) { + case '.sass': + return 'indented'; + case '.scss': + return 'scss'; + default: + return 'css'; + } +} + +function generateJsShimContent( + format: 'commonjs' | 'esnext', + relativePathToCss: string, + isModule: boolean +): 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/README-ModifyingSchemas.md b/heft-plugins/heft-sass-plugin/src/schemas/README-ModifyingSchemas.md new file mode 100644 index 00000000000..b745eb707e7 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/schemas/README-ModifyingSchemas.md @@ -0,0 +1,4 @@ +## Important + +If you change the Heft schemas, be sure to update the example files under **`src/templates`**. +The templates are used as a reference when updating the website documentation. 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 new file mode 100644 index 00000000000..0ff5b533c91 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json @@ -0,0 +1,111 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Sass Configuration", + "description": "This schema describes the \"config/sass.json\" config file used to configure \"@rushstack/heft-jest-plugin\", and also the \"options\" field that can be specified in heft.json when loading the plugin.", + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "srcFolder": { + "type": "string", + "description": "Source code root directory." + }, + + "generatedTsFolder": { + "type": "string", + "description": "Output directory for generated Sass typings." + }, + + "secondaryGeneratedTsFolders": { + "type": "array", + "description": "Optional additional folders to which Sass typings should be output.", + "items": { + "type": "string" + } + }, + + "exportAsDefault": { + "type": "boolean", + "description": "Determines whether export values are wrapped in a default property, or not." + }, + + "cssOutputFolders": { + "type": "array", + "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": { + "oneOf": [ + { + "type": "string", + "pattern": "[^\\\\]" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "folder": { + "type": "string", + "pattern": "[^\\\\]" + }, + "shimModuleFormat": { + "type": "string", + "enum": ["commonjs", "esnext"] + } + }, + "required": ["folder"] + } + ] + } + }, + + "fileExtensions": { + "type": "array", + "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-_]+$" + } + }, + + "nonModuleFileExtensions": { + "type": "array", + "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-_]+$" + } + }, + + "excludeFiles": { + "type": "array", + "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": "[^\\\\]" + } + }, + + "ignoreDeprecationsInDependencies": { + "type": "boolean", + "description": "If set, deprecation warnings from dependencies will be suppressed." + }, + + "silenceDeprecations": { + "type": "array", + "description": "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.", + "items": { + "type": "string" + } + } + } +} diff --git a/heft-plugins/heft-sass-plugin/src/templates/sass.json b/heft-plugins/heft-sass-plugin/src/templates/sass.json new file mode 100644 index 00000000000..88b2b1a7120 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/templates/sass.json @@ -0,0 +1,91 @@ +/** + * Configuration for @rushstack/heft-sass-plugin + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.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": "base-project/config/serve-command.json", + + /** + * The root directory for project source code. + * + * Default value: "src/" + */ + // "srcFolder": "src/", + + /** + * Output directory for generated Sass typings. + * + * Default value: "temp/sass-ts/" + */ + // "generatedTsFolder": "temp/sass-ts/", + + /** + * Optional additional folders to which Sass typings should be output. + */ + // "secondaryGeneratedTsFolders": [], + + /** + * Determines whether export values are wrapped in a default property, or not. + * + * 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. + * + * Default value: undefined + */ + // "cssOutputFolders": [], + + /** + * 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". + * + * Default value: false + */ + // "preserveSCSSExtension": true, + + /** + * Files with these extensions will pass through the Sass transpiler for typings generation. + * + * Default value: [".sass", ".scss", ".css"] + */ + // "fileExtensions": [".sass", ".scss"], + + /** + * A list of paths used when resolving Sass imports. The paths should be relative to the project root. + * + * Default value: ["node_modules", "src"] + */ + // "importIncludePaths": ["node_modules", "src"], + + /** + * A list of file paths relative to the "src" folder that should be excluded from typings generation. + * + * Default value: undefined + */ + // "excludeFiles": [], + + /** + * If set, deprecation warnings from dependencies will be suppressed. + * + * Default value: false + */ + // "ignoreDeprecationsInDependencies": true, + + /** + * If set, the specified deprecation warnings will be suppressed. + * + * Default value: [] + */ + // "silenceDeprecations": ["mixed-decls"] +} diff --git a/heft-plugins/heft-sass-plugin/tsconfig.json b/heft-plugins/heft-sass-plugin/tsconfig.json new file mode 100644 index 00000000000..fbf5b4d1ea6 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "include": ["src/**/*.ts", "./custom-typings/**/*.ts"] +} diff --git a/heft-plugins/heft-serverless-stack-plugin/.npmignore b/heft-plugins/heft-serverless-stack-plugin/.npmignore new file mode 100644 index 00000000000..e15a94aeb84 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/.npmignore @@ -0,0 +1,33 @@ +# 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/** + +!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 + +# 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-serverless-stack-plugin/CHANGELOG.json b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json new file mode 100644 index 00000000000..64a7a3aa68d --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json @@ -0,0 +1,4902 @@ +{ + "name": "@rushstack/heft-serverless-stack-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.3.79", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.79", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.3.78", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.78", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.3.77", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.77", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.3.76", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.76", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.75", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.74", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.73", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.72", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.71", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.70", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.69", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.68", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.12`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.67", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.66", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.65", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.64", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.63", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.62", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.3.61", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.61", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.60", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.59", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.58", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.57", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.56", + "date": "Fri, 07 Jun 2024 15:10:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.28", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.27", + "date": "Thu, 07 Sep 2023 03:35:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.26", + "date": "Sat, 12 Aug 2023 00:21:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.25", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.24", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.23", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.22", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.21", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.20", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.19", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.18", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.17", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.16", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.15", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.14", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.13", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.12", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.11", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.10", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.9", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.8", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.7", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.6", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.5", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.4", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.3", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.2", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.2.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.1.77", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.77", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.1.76", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.76", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.1.75", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.75", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.1.74", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.74", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.1.73", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.73", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.1.72", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.72", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.1.71", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.71", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.1.70", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.70", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.1.69", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.69", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.1.68", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.68", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.1.67", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.67", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.1.66", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.66", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.1.65", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.65", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.1.64", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.64", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.63", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.63", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.1.62", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.62", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.1.61", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.61", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.1.60", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.60", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.1.59", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.59", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.58", + "date": "Wed, 30 Nov 2022 01:23:44 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for Serverless-Stack 1.2.0 and later versions" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.57", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.56", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.55", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.54", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.53", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.52", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.51", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.50", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.49", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.48", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.47", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.46", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.45", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.44", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.43", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.42", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.41", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.40", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.39", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.38", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.37", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.36", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.35", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.34", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.33", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.32", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.31", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.30", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.29", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.28", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.27", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.26", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.25", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.24", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.23", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.22", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.21", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.20", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.19", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.18", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.17", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.16", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.15", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.14", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.13", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.12", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.11", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.10", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.9", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.8", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.7", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.6", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.5", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.4", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.3", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.2", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.1", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.1.0", + "date": "Tue, 29 Mar 2022 20:30:23 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md new file mode 100644 index 00000000000..97590b478cc --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md @@ -0,0 +1,1184 @@ +# Change Log - @rushstack/heft-serverless-stack-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.3.79 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.3.78 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.3.77 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.3.76 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.3.75 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.3.74 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.3.73 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.3.72 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.3.71 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.70 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.3.69 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.3.68 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.3.67 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 0.3.66 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.3.65 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.3.64 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.3.63 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.3.62 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.3.61 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.3.60 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.3.59 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.3.58 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.3.57 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.3.56 +Fri, 07 Jun 2024 15:10:25 GMT + +_Version update only_ + +## 0.3.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.3.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.3.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.3.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.3.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.3.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.3.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.3.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.3.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.3.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.3.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.3.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.3.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.3.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.3.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.3.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.3.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.3.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.3.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.3.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.3.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.3.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.3.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.3.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.3.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.3.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.3.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.3.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.3.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 0.3.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.3.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.3.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.3.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.3.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.3.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.3.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.3.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.3.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.3.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.3.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.3.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.3.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.3.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.3.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.3.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.3.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 0.3.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.3.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.3.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.3.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.3.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.3.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.3.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.3.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.2.28 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.2.27 +Thu, 07 Sep 2023 03:35:43 GMT + +_Version update only_ + +## 0.2.26 +Sat, 12 Aug 2023 00:21:48 GMT + +_Version update only_ + +## 0.2.25 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.2.24 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.2.23 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.2.22 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.2.21 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.2.20 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.2.19 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.2.18 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.2.17 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.2.16 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.2.15 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.2.14 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.2.13 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.2.12 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.2.11 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.2.10 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.2.9 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.2.8 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.2.7 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.2.6 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.2.5 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.2.4 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.2.3 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.2.2 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.2.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.2.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.1.77 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.1.76 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.1.75 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.1.74 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.1.73 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.1.72 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.1.71 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.1.70 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.1.69 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.1.68 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.1.67 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.1.66 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.1.65 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.64 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.63 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.62 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.1.61 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.60 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.59 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.58 +Wed, 30 Nov 2022 01:23:44 GMT + +### Patches + +- Add support for Serverless-Stack 1.2.0 and later versions + +## 0.1.57 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.56 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.55 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.54 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.53 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.52 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.51 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.50 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.49 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.48 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.47 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.46 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.45 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.1.44 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.43 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.42 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.41 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.40 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.39 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.38 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.37 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.1.36 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.35 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.34 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.33 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.32 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.31 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.30 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.29 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.28 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.27 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.26 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 0.1.25 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.24 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.23 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.22 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.21 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.20 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.1.19 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.18 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.17 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.16 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.1.15 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.1.14 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.1.13 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.1.12 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.1.11 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.1.10 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.1.9 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.1.8 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.1.7 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.1.6 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.1.5 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.1.4 +Sat, 09 Apr 2022 02:24:27 GMT + +_Version update only_ + +## 0.1.3 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.1.2 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.1.1 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.1.0 +Tue, 29 Mar 2022 20:30:23 GMT + +### Minor changes + +- Initial release + diff --git a/heft-plugins/heft-serverless-stack-plugin/README.md b/heft-plugins/heft-serverless-stack-plugin/README.md new file mode 100644 index 00000000000..e29f6a26e0e --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/README.md @@ -0,0 +1,32 @@ +# @rushstack/heft-serverless-stack-plugin + +This is a Heft plugin for building apps using the [Serverless Stack (SST)](https://serverless-stack.com/) framework. +With this approach, the [SST toolchain](https://docs.serverless-stack.com/packages/cli) is only used for +synthesizing CloudFormation stacks and deploying the app, and Heft takes over the role of compiling, linting, +testing your TypeScript project. + +The plugin accepts two command-line parameters: + +- `--sst` can be appended to `heft build` or `heft start`, causing the corresponding SST operation to be invoked + +- `--sst-stage STAGE_NAME` allows you to customize the stage. It is equivalent to the `--stage` parameter + for the SST command-line tool. + + +The plugin has no effect without the `--sst` parameter. When the parameter is provided: + +- `heft build --sst` will behave similar to `sst build`, which synthesizes CloudFormation stacks + in the `build/cdk.out/` directory. See [this documentation](https://docs.serverless-stack.com/packages/cli#build) + for details. Heft's `--watch` mode is also supported. + +- `heft start --sst` will behave similar to `sst start`, which deploys a + [stub lambda](https://docs.serverless-stack.com/live-lambda-development#sst-start) to AWS + and then launches the WebSocket client locally for debugging. See + [this documentation](https://docs.serverless-stack.com/packages/cli#start) for details. + + +> Note that `heft build --sst` currently requires AWS credentials, which limits the ability to perform this +> validation in a monorepo environment where we can't assume that every developer works on AWS. +> Issue [serverless-stack#1537](https://github.com/serverless-stack/serverless-stack/issues/1537) +> is tracking a possible improvement. + diff --git a/heft-plugins/heft-serverless-stack-plugin/config/rig.json b/heft-plugins/heft-serverless-stack-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-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-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 new file mode 100644 index 00000000000..7b3beee1a00 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/heft-plugin.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "serverless-stack-plugin", + "entryPoint": "./lib/ServerlessStackPlugin", + + "parameterScope": "serverless-stack", + "parameters": [ + { + "longName": "--sst", + "description": "(EXPERIMENTAL) Invokes the SST postprocessing. Requires AWS credentials.", + "parameterKind": "flag" + }, + { + "longName": "--sst-stage", + "argumentName": "STAGE_NAME", + "description": "Specifies the Serverless Stack stage; equivalent to to the \"--stage\" parameter from the \"sst\" CLI", + "parameterKind": "string" + } + ] + } + ] +} diff --git a/heft-plugins/heft-serverless-stack-plugin/package.json b/heft-plugins/heft-serverless-stack-plugin/package.json new file mode 100644 index 00000000000..277f28fced4 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/package.json @@ -0,0 +1,30 @@ +{ + "name": "@rushstack/heft-serverless-stack-plugin", + "version": "1.1.8", + "description": "Heft plugin for building apps using the Serverless Stack (SST) framework", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-serverless-stack-plugin" + }, + "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.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-webpack4-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts new file mode 100644 index 00000000000..3dd5368e47a --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts @@ -0,0 +1,230 @@ +// 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 child_process from 'node:child_process'; + +import type { + CommandLineFlagParameter, + CommandLineStringParameter, + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IScopedLogger +} from '@rushstack/heft'; +import { FileSystem, Import, SubprocessTerminator } from '@rushstack/node-core-library'; +import type { + PluginName as Webpack4PluginName, + IWebpackPluginAccessor as IWebpack4PluginAccessor +} from '@rushstack/heft-webpack4-plugin'; +import type { + PluginName as Webpack5PluginName, + IWebpackPluginAccessor as IWebpack5PluginAccessor +} from '@rushstack/heft-webpack5-plugin'; + +const PLUGIN_NAME: 'serverless-stack-plugin' = 'serverless-stack-plugin'; +const WEBPACK4_PLUGIN_NAME: typeof Webpack4PluginName = 'webpack4-plugin'; +const WEBPACK5_PLUGIN_NAME: typeof Webpack5PluginName = 'webpack5-plugin'; +const SST_CLI_PACKAGE_NAME: string = '@serverless-stack/cli'; + +export default class ServerlessStackPlugin implements IHeftTaskPlugin { + private _logger!: IScopedLogger; + + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + this._logger = taskSession.logger; + + // Once https://github.com/serverless-stack/serverless-stack/issues/1537 is fixed, we may be + // eliminate the need for this parameter. + const sstParameter: CommandLineFlagParameter = taskSession.parameters.getFlagParameter('--sst'); + const sstStageParameter: CommandLineStringParameter = + taskSession.parameters.getStringParameter('--sst-stage'); + + // Only tap if the --sst flag is set. + if (sstParameter.value) { + const configureWebpackTap: () => Promise = async () => { + this._logger.terminal.writeLine( + 'The command line includes "--sst", redirecting Webpack to Serverless Stack' + ); + return false; + }; + + taskSession.requestAccessToPluginByName( + '@rushstack/heft-webpack4-plugin', + WEBPACK4_PLUGIN_NAME, + async (accessor: IWebpack4PluginAccessor) => + accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configureWebpackTap) + ); + + taskSession.requestAccessToPluginByName( + '@rushstack/heft-webpack5-plugin', + WEBPACK5_PLUGIN_NAME, + async (accessor: IWebpack5PluginAccessor) => + accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configureWebpackTap) + ); + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + // TODO: Handle watch / serve mode + await this._runServerlessStackAsync({ + taskSession, + heftConfiguration, + sstStage: sstStageParameter.value + }); + }); + } + } + + private async _runServerlessStackAsync(options: { + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + sstStage?: string; + serveMode?: boolean; + }): Promise { + let sstCliPackagePath: string; + try { + sstCliPackagePath = Import.resolvePackage({ + packageName: SST_CLI_PACKAGE_NAME, + baseFolderPath: options.heftConfiguration.buildFolderPath, + useNodeJSResolver: true + }); + } catch (e) { + this._logger.emitError( + new Error( + `The ${options.taskSession.taskName} task cannot start because your project does not seem to have ` + + `a dependency on the "${SST_CLI_PACKAGE_NAME}" package: ` + + e.message + ) + ); + return; + } + + const sstCliEntryPoint: string = this._getSstCliEntryPoint(sstCliPackagePath); + + this._logger.terminal.writeVerboseLine('Found SST package in' + sstCliPackagePath); + + const sstCommandArgs: string[] = []; + sstCommandArgs.push(sstCliEntryPoint); + + if (options.serveMode) { + sstCommandArgs.push('start'); + } else { + sstCommandArgs.push('build'); + } + if (options.taskSession.parameters.debug || options.taskSession.parameters.verbose) { + sstCommandArgs.push('--verbose'); + } + if (options.sstStage) { + sstCommandArgs.push('--stage'); + sstCommandArgs.push(options.sstStage); + } + + this._logger.terminal.writeVerboseLine('Launching child process: ' + JSON.stringify(sstCommandArgs)); + + const sstCommandEnv: NodeJS.ProcessEnv = this._getWorkaroundEnvironment(sstCliPackagePath); + + const sstCommandResult: child_process.ChildProcess = child_process.spawn( + process.execPath, + sstCommandArgs, + { + cwd: options.heftConfiguration.buildFolderPath, + stdio: ['inherit', 'pipe', 'pipe'], + env: sstCommandEnv, + ...SubprocessTerminator.RECOMMENDED_OPTIONS + } + ); + + SubprocessTerminator.killProcessTreeOnExit(sstCommandResult, SubprocessTerminator.RECOMMENDED_OPTIONS); + + let completionResolve: () => void; + let completionReject: (reason: Error) => void; + + const completionPromise: Promise = new Promise((resolve, reject) => { + completionResolve = resolve; + completionReject = reject; + }); + + sstCommandResult.stdout?.on('data', (chunk: Buffer) => { + this._writeOutput(chunk.toString(), (x) => this._logger.terminal.write(x)); + }); + sstCommandResult.stderr?.on('data', (chunk: Buffer) => { + this._writeOutput(chunk.toString(), (x) => this._logger.terminal.writeError(x)); + }); + + sstCommandResult.on('exit', (code: number | null) => { + if (options.serveMode) { + // The child process is not supposed to terminate in watch mode + this._logger.terminal.writeErrorLine(`SST process terminated with exit code ${code}`); + // TODO: Provide a Heft facility for this + process.exit(1); + } else { + this._logger.terminal.writeVerboseLine(`SST process terminated with exit code ${code}`); + if (!code) { + completionResolve(); + } else { + completionReject(new Error(`SST process terminated with exit code ${code}`)); + } + } + }); + + return completionPromise; + } + + private _writeOutput(chunk: string, write: (message: string) => void): void { + const lines: string[] = chunk.split('\n'); + const lastLine: string = lines.pop() || ''; + + lines.map((x) => write(x + '\n')); + if (lastLine !== '') { + write(lastLine); + } + } + + private _getSstCliEntryPoint(sstCliPackagePath: string): string { + // Entry point for SST prior to v1.2.0 + let sstCliEntryPoint: string = path.join(sstCliPackagePath, 'bin/scripts.js'); + if (FileSystem.exists(sstCliEntryPoint)) { + return sstCliEntryPoint; + } + + // Entry point for SST v1.2.0 and later + sstCliEntryPoint = path.join(sstCliPackagePath, 'bin/scripts.mjs'); + if (FileSystem.exists(sstCliEntryPoint)) { + return sstCliEntryPoint; + } + + throw new Error( + `${PLUGIN_NAME} task cannot start because the entry point was not found: ${sstCliEntryPoint}` + ); + } + + // The SST CLI emits a script "/.build/run.js" with a bunch of phantom dependencies + // on packages that NPM would shamefully hoist into the project's node_modules folder when + // "@serverless-stack/cli" is being installed. The only reason this works with PNPM is that + // (to improve compatibility) its bin script sets up NODE_PATH to include "common/temp/node_modules/.pnpm/" + // where those dependencies can be found, and this environment variable gets passed along to the run.js + // child process. SST is not following best practices -- regardless of which package manager you're using, there + // is no guarantee that the versions found in this way will correspond to @serverless-stack/cli/package.json. + // + // Since we're invoking the "@serverless-stack/cli/bin/scripts.js" entry point directly, we need to + // reproduce this workaround. + private _getWorkaroundEnvironment(sstCliPackagePath: string): NodeJS.ProcessEnv { + const sstCommandEnv: NodeJS.ProcessEnv = { + ...process.env + }; + + const phantomPaths: string[] = []; + let current: string = path.join(sstCliPackagePath); + while (current) { + phantomPaths.push(path.join(current, 'node_modules')); + const parent: string = path.dirname(current); + if (parent === current) { + break; + } + current = parent; + } + + sstCommandEnv.NODE_PATH = phantomPaths.join(path.delimiter); + return sstCommandEnv; + } +} diff --git a/heft-plugins/heft-serverless-stack-plugin/tsconfig.json b/heft-plugins/heft-serverless-stack-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-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/.npmignore b/heft-plugins/heft-storybook-plugin/.npmignore new file mode 100644 index 00000000000..ffb155d74e6 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.json b/heft-plugins/heft-storybook-plugin/CHANGELOG.json new file mode 100644 index 00000000000..f41e27eb720 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.json @@ -0,0 +1,5786 @@ +{ + "name": "@rushstack/heft-storybook-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-storybook-plugin_v0.7.4", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-storybook-plugin_v0.7.3", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-storybook-plugin_v0.7.2", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-storybook-plugin_v0.7.1", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-storybook-plugin_v0.7.0", + "date": "Fri, 25 Oct 2024 00:10:38 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for Storybook v8" + } + ] + } + }, + { + "version": "0.6.52", + "tag": "@rushstack/heft-storybook-plugin_v0.6.52", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.6.51", + "tag": "@rushstack/heft-storybook-plugin_v0.6.51", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.6.50", + "tag": "@rushstack/heft-storybook-plugin_v0.6.50", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.6.49", + "tag": "@rushstack/heft-storybook-plugin_v0.6.49", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.6.48", + "tag": "@rushstack/heft-storybook-plugin_v0.6.48", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.6.47", + "tag": "@rushstack/heft-storybook-plugin_v0.6.47", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.6.46", + "tag": "@rushstack/heft-storybook-plugin_v0.6.46", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.6.45", + "tag": "@rushstack/heft-storybook-plugin_v0.6.45", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.12`" + } + ] + } + }, + { + "version": "0.6.44", + "tag": "@rushstack/heft-storybook-plugin_v0.6.44", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.6.43", + "tag": "@rushstack/heft-storybook-plugin_v0.6.43", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.6.42", + "tag": "@rushstack/heft-storybook-plugin_v0.6.42", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.6.41", + "tag": "@rushstack/heft-storybook-plugin_v0.6.41", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.6.40", + "tag": "@rushstack/heft-storybook-plugin_v0.6.40", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.6.39", + "tag": "@rushstack/heft-storybook-plugin_v0.6.39", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.6.38", + "tag": "@rushstack/heft-storybook-plugin_v0.6.38", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.6.37", + "tag": "@rushstack/heft-storybook-plugin_v0.6.37", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.6.36", + "tag": "@rushstack/heft-storybook-plugin_v0.6.36", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.6.35", + "tag": "@rushstack/heft-storybook-plugin_v0.6.35", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.6.34", + "tag": "@rushstack/heft-storybook-plugin_v0.6.34", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.6.33", + "tag": "@rushstack/heft-storybook-plugin_v0.6.33", + "date": "Fri, 07 Jun 2024 15:10:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.6.32", + "tag": "@rushstack/heft-storybook-plugin_v0.6.32", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.6.31", + "tag": "@rushstack/heft-storybook-plugin_v0.6.31", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.6.30", + "tag": "@rushstack/heft-storybook-plugin_v0.6.30", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.6.29", + "tag": "@rushstack/heft-storybook-plugin_v0.6.29", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.6.28", + "tag": "@rushstack/heft-storybook-plugin_v0.6.28", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.6.27", + "tag": "@rushstack/heft-storybook-plugin_v0.6.27", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.6.26", + "tag": "@rushstack/heft-storybook-plugin_v0.6.26", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.6.25", + "tag": "@rushstack/heft-storybook-plugin_v0.6.25", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.6.24", + "tag": "@rushstack/heft-storybook-plugin_v0.6.24", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an edge case where the Storybook STDOUT might not be flushed completely when an error occurs" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.6.23", + "tag": "@rushstack/heft-storybook-plugin_v0.6.23", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.6.22", + "tag": "@rushstack/heft-storybook-plugin_v0.6.22", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.6.21", + "tag": "@rushstack/heft-storybook-plugin_v0.6.21", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.6.20", + "tag": "@rushstack/heft-storybook-plugin_v0.6.20", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.6.19", + "tag": "@rushstack/heft-storybook-plugin_v0.6.19", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.6.18", + "tag": "@rushstack/heft-storybook-plugin_v0.6.18", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.6.17", + "tag": "@rushstack/heft-storybook-plugin_v0.6.17", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.6.16", + "tag": "@rushstack/heft-storybook-plugin_v0.6.16", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.6.15", + "tag": "@rushstack/heft-storybook-plugin_v0.6.15", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/heft-storybook-plugin_v0.6.14", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/heft-storybook-plugin_v0.6.13", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/heft-storybook-plugin_v0.6.12", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/heft-storybook-plugin_v0.6.11", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/heft-storybook-plugin_v0.6.10", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/heft-storybook-plugin_v0.6.9", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/heft-storybook-plugin_v0.6.8", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/heft-storybook-plugin_v0.6.7", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/heft-storybook-plugin_v0.6.6", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/heft-storybook-plugin_v0.6.5", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft-storybook-plugin_v0.6.4", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-storybook-plugin_v0.6.3", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-storybook-plugin_v0.6.2", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-storybook-plugin_v0.6.1", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-storybook-plugin_v0.6.0", + "date": "Mon, 12 Feb 2024 16:09:54 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where Webpack would run twice during static storybook builds." + }, + { + "comment": "Introduce a `captureWebpackStats` configuration option that, when enabled, will pass the `--webpack-stats-json` parameter to Storybook." + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-storybook-plugin_v0.5.3", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-storybook-plugin_v0.5.2", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-storybook-plugin_v0.5.1", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-storybook-plugin_v0.5.0", + "date": "Thu, 25 Jan 2024 01:09:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for storybook 7, HMR, and breaking chages in the plugin configuration option. The \"startupModulePath\" and \"staticBuildModulePath\" have been removed in favour of \"cliCallingConvention\" and \"cliPackageName\". A new 'cwdPackageName' option provides the ability to set an alternative dependency name as (cwd) target for the storybook commands." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/heft-storybook-plugin_v0.4.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/heft-storybook-plugin_v0.4.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/heft-storybook-plugin_v0.4.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/heft-storybook-plugin_v0.4.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/heft-storybook-plugin_v0.4.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-storybook-plugin_v0.4.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-storybook-plugin_v0.4.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-storybook-plugin_v0.4.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-storybook-plugin_v0.4.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-storybook-plugin_v0.4.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-storybook-plugin_v0.4.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-storybook-plugin_v0.4.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-storybook-plugin_v0.4.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-storybook-plugin_v0.4.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-storybook-plugin_v0.4.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-storybook-plugin_v0.4.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-storybook-plugin_v0.4.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-storybook-plugin_v0.4.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-storybook-plugin_v0.4.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-storybook-plugin_v0.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/heft-storybook-plugin_v0.3.29", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/heft-storybook-plugin_v0.3.28", + "date": "Thu, 07 Sep 2023 03:35:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/heft-storybook-plugin_v0.3.27", + "date": "Sat, 12 Aug 2023 00:21:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/heft-storybook-plugin_v0.3.26", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/heft-storybook-plugin_v0.3.25", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/heft-storybook-plugin_v0.3.24", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/heft-storybook-plugin_v0.3.23", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-storybook-plugin_v0.3.22", + "date": "Wed, 19 Jul 2023 18:46:59 GMT", + "comments": { + "patch": [ + { + "comment": "Run Storybook in a forked Node process, providing various advantages including isolation of the process and encapsulation of all console logging" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-storybook-plugin_v0.3.21", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-storybook-plugin_v0.3.20", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-storybook-plugin_v0.3.19", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-storybook-plugin_v0.3.18", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-storybook-plugin_v0.3.17", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-storybook-plugin_v0.3.16", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-storybook-plugin_v0.3.15", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-storybook-plugin_v0.3.14", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-storybook-plugin_v0.3.13", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-storybook-plugin_v0.3.12", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-storybook-plugin_v0.3.11", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-storybook-plugin_v0.3.10", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-storybook-plugin_v0.3.9", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-storybook-plugin_v0.3.8", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-storybook-plugin_v0.3.7", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-storybook-plugin_v0.3.6", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-storybook-plugin_v0.3.5", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-storybook-plugin_v0.3.4", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-storybook-plugin_v0.3.3", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-storybook-plugin_v0.3.2", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-storybook-plugin_v0.3.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-storybook-plugin_v0.3.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-storybook-plugin_v0.2.12", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-storybook-plugin_v0.2.11", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-storybook-plugin_v0.2.10", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-storybook-plugin_v0.2.9", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-storybook-plugin_v0.2.8", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-storybook-plugin_v0.2.7", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-storybook-plugin_v0.2.6", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-storybook-plugin_v0.2.5", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-storybook-plugin_v0.2.4", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-storybook-plugin_v0.2.3", + "date": "Wed, 22 Feb 2023 16:26:55 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where static build output ends up in the wrong folder." + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-storybook-plugin_v0.2.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-storybook-plugin_v0.2.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-storybook-plugin_v0.2.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for storybook static build" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.1.99", + "tag": "@rushstack/heft-storybook-plugin_v0.1.99", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.1.98", + "tag": "@rushstack/heft-storybook-plugin_v0.1.98", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.97", + "tag": "@rushstack/heft-storybook-plugin_v0.1.97", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.1.96", + "tag": "@rushstack/heft-storybook-plugin_v0.1.96", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.1.95", + "tag": "@rushstack/heft-storybook-plugin_v0.1.95", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.1.94", + "tag": "@rushstack/heft-storybook-plugin_v0.1.94", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.1.93", + "tag": "@rushstack/heft-storybook-plugin_v0.1.93", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.1.92", + "tag": "@rushstack/heft-storybook-plugin_v0.1.92", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.91", + "tag": "@rushstack/heft-storybook-plugin_v0.1.91", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.1.90", + "tag": "@rushstack/heft-storybook-plugin_v0.1.90", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.1.89", + "tag": "@rushstack/heft-storybook-plugin_v0.1.89", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.1.88", + "tag": "@rushstack/heft-storybook-plugin_v0.1.88", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.1.87", + "tag": "@rushstack/heft-storybook-plugin_v0.1.87", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.1.86", + "tag": "@rushstack/heft-storybook-plugin_v0.1.86", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.1.85", + "tag": "@rushstack/heft-storybook-plugin_v0.1.85", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.1.84", + "tag": "@rushstack/heft-storybook-plugin_v0.1.84", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.1.83", + "tag": "@rushstack/heft-storybook-plugin_v0.1.83", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.1.82", + "tag": "@rushstack/heft-storybook-plugin_v0.1.82", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.1.81", + "tag": "@rushstack/heft-storybook-plugin_v0.1.81", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.1.80", + "tag": "@rushstack/heft-storybook-plugin_v0.1.80", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.1.79", + "tag": "@rushstack/heft-storybook-plugin_v0.1.79", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.1.78", + "tag": "@rushstack/heft-storybook-plugin_v0.1.78", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.1.77", + "tag": "@rushstack/heft-storybook-plugin_v0.1.77", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.1.76", + "tag": "@rushstack/heft-storybook-plugin_v0.1.76", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.75", + "tag": "@rushstack/heft-storybook-plugin_v0.1.75", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.74", + "tag": "@rushstack/heft-storybook-plugin_v0.1.74", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.1.73", + "tag": "@rushstack/heft-storybook-plugin_v0.1.73", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.1.72", + "tag": "@rushstack/heft-storybook-plugin_v0.1.72", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.1.71", + "tag": "@rushstack/heft-storybook-plugin_v0.1.71", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.1.70", + "tag": "@rushstack/heft-storybook-plugin_v0.1.70", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.1.69", + "tag": "@rushstack/heft-storybook-plugin_v0.1.69", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.1.68", + "tag": "@rushstack/heft-storybook-plugin_v0.1.68", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.1.67", + "tag": "@rushstack/heft-storybook-plugin_v0.1.67", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.1.66", + "tag": "@rushstack/heft-storybook-plugin_v0.1.66", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.1.65", + "tag": "@rushstack/heft-storybook-plugin_v0.1.65", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.1.64", + "tag": "@rushstack/heft-storybook-plugin_v0.1.64", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.1.63", + "tag": "@rushstack/heft-storybook-plugin_v0.1.63", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.1.62", + "tag": "@rushstack/heft-storybook-plugin_v0.1.62", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.1.61", + "tag": "@rushstack/heft-storybook-plugin_v0.1.61", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.1.60", + "tag": "@rushstack/heft-storybook-plugin_v0.1.60", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.1.59", + "tag": "@rushstack/heft-storybook-plugin_v0.1.59", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/heft-storybook-plugin_v0.1.58", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/heft-storybook-plugin_v0.1.57", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/heft-storybook-plugin_v0.1.56", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/heft-storybook-plugin_v0.1.55", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/heft-storybook-plugin_v0.1.54", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/heft-storybook-plugin_v0.1.53", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/heft-storybook-plugin_v0.1.52", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/heft-storybook-plugin_v0.1.51", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/heft-storybook-plugin_v0.1.50", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/heft-storybook-plugin_v0.1.49", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/heft-storybook-plugin_v0.1.48", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/heft-storybook-plugin_v0.1.47", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/heft-storybook-plugin_v0.1.46", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/heft-storybook-plugin_v0.1.45", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/heft-storybook-plugin_v0.1.44", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/heft-storybook-plugin_v0.1.43", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/heft-storybook-plugin_v0.1.42", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/heft-storybook-plugin_v0.1.41", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/heft-storybook-plugin_v0.1.40", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/heft-storybook-plugin_v0.1.39", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/heft-storybook-plugin_v0.1.38", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/heft-storybook-plugin_v0.1.37", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/heft-storybook-plugin_v0.1.36", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/heft-storybook-plugin_v0.1.35", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-storybook-plugin_v0.1.34", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-storybook-plugin_v0.1.33", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-storybook-plugin_v0.1.32", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-storybook-plugin_v0.1.31", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-storybook-plugin_v0.1.30", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-storybook-plugin_v0.1.29", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-storybook-plugin_v0.1.28", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-storybook-plugin_v0.1.27", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-storybook-plugin_v0.1.26", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-storybook-plugin_v0.1.25", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-storybook-plugin_v0.1.24", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-storybook-plugin_v0.1.23", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-storybook-plugin_v0.1.22", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-storybook-plugin_v0.1.21", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-storybook-plugin_v0.1.20", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-storybook-plugin_v0.1.19", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-storybook-plugin_v0.1.18", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-storybook-plugin_v0.1.17", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-storybook-plugin_v0.1.16", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-storybook-plugin_v0.1.15", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-storybook-plugin_v0.1.14", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-storybook-plugin_v0.1.13", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-storybook-plugin_v0.1.12", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-storybook-plugin_v0.1.11", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-storybook-plugin_v0.1.10", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-storybook-plugin_v0.1.9", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-storybook-plugin_v0.1.8", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-storybook-plugin_v0.1.7", + "date": "Tue, 05 Oct 2021 15:08:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-storybook-plugin_v0.1.6", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "patch": [ + { + "comment": "Adopt new Heft RegisterParameter feature." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-storybook-plugin_v0.1.5", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-storybook-plugin_v0.1.4", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-storybook-plugin_v0.1.3", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-storybook-plugin_v0.1.2", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-storybook-plugin_v0.1.1", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-storybook-plugin_v0.1.0", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.38.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.md b/heft-plugins/heft-storybook-plugin/CHANGELOG.md new file mode 100644 index 00000000000..78b3934ccb5 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.md @@ -0,0 +1,1400 @@ +# Change Log - @rushstack/heft-storybook-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.7.4 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.7.3 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.7.2 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.7.1 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.7.0 +Fri, 25 Oct 2024 00:10:38 GMT + +### Minor changes + +- Add support for Storybook v8 + +## 0.6.52 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.6.51 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.6.50 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.6.49 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.6.48 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.6.47 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.6.46 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.6.45 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.6.44 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.6.43 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.6.42 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.6.41 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.6.40 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.6.39 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.6.38 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.6.37 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.6.36 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.6.35 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.6.34 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.6.33 +Fri, 07 Jun 2024 15:10:25 GMT + +_Version update only_ + +## 0.6.32 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.6.31 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.6.30 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.6.29 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.6.28 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.6.27 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.6.26 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.6.25 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.6.24 +Thu, 23 May 2024 02:26:56 GMT + +### Patches + +- Fix an edge case where the Storybook STDOUT might not be flushed completely when an error occurs + +## 0.6.23 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.6.22 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.6.21 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.6.20 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.6.19 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.6.18 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.6.17 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.6.16 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.6.15 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.6.14 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.6.13 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.6.12 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.6.11 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.6.10 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.6.9 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.6.8 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.6.7 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.6.6 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.6.5 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.6.4 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.6.3 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.6.2 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.6.1 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.6.0 +Mon, 12 Feb 2024 16:09:54 GMT + +### Minor changes + +- Fix an issue where Webpack would run twice during static storybook builds. +- Introduce a `captureWebpackStats` configuration option that, when enabled, will pass the `--webpack-stats-json` parameter to Storybook. + +## 0.5.3 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.5.2 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.5.1 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.5.0 +Thu, 25 Jan 2024 01:09:29 GMT + +### Minor changes + +- Add support for storybook 7, HMR, and breaking chages in the plugin configuration option. The "startupModulePath" and "staticBuildModulePath" have been removed in favour of "cliCallingConvention" and "cliPackageName". A new 'cwdPackageName' option provides the ability to set an alternative dependency name as (cwd) target for the storybook commands. + +## 0.4.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.4.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.4.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.4.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.4.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.4.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.4.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.4.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.4.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.4.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.4.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 0.4.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.4.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.4.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.4.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.4.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.4.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.4.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.4.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.3.29 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.3.28 +Thu, 07 Sep 2023 03:35:43 GMT + +_Version update only_ + +## 0.3.27 +Sat, 12 Aug 2023 00:21:48 GMT + +_Version update only_ + +## 0.3.26 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.3.25 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.3.24 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.3.23 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.3.22 +Wed, 19 Jul 2023 18:46:59 GMT + +### Patches + +- Run Storybook in a forked Node process, providing various advantages including isolation of the process and encapsulation of all console logging + +## 0.3.21 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.3.20 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.3.19 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.3.18 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.3.17 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.3.16 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.3.15 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.3.14 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.3.13 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.3.12 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.3.11 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.3.10 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.3.9 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.3.8 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.3.7 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.3.6 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.3.5 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.3.4 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.3.3 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.3.2 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.3.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.3.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.2.12 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.11 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.2.10 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.2.9 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.2.8 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.2.7 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.2.6 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.2.5 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.2.4 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.2.3 +Wed, 22 Feb 2023 16:26:55 GMT + +### Patches + +- Fix an issue where static build output ends up in the wrong folder. + +## 0.2.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.2.1 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.2.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Add support for storybook static build + +## 0.1.99 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.98 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.97 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.96 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.1.95 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.94 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.93 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.92 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.91 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.90 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.89 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.88 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.87 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.86 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.85 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.84 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.83 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.82 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.81 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.80 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.1.79 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.78 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.77 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.76 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.75 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.74 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.73 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.72 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.1.71 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.70 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.69 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.68 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.67 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.66 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.65 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.64 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.63 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.62 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.61 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.1.60 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.59 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.58 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.57 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.56 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.55 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.1.54 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.53 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.52 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.51 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.1.50 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.1.49 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.1.48 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.1.47 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.1.46 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.1.45 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.1.44 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.1.43 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.1.42 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.1.41 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.1.40 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.1.39 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.1.38 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.1.37 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.1.36 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.1.35 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.1.34 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.1.33 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 0.1.32 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.1.31 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.1.30 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.1.29 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.1.28 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.1.27 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.1.26 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.1.25 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.1.24 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.1.23 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.1.22 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.1.21 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.1.20 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.1.19 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.1.18 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.1.17 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.1.16 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.1.15 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.1.14 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.1.13 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.1.12 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.1.11 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.1.10 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.1.9 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.1.8 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.1.7 +Tue, 05 Oct 2021 15:08:37 GMT + +_Version update only_ + +## 0.1.6 +Mon, 04 Oct 2021 15:10:18 GMT + +### Patches + +- Adopt new Heft RegisterParameter feature. + +## 0.1.5 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.1.4 +Thu, 23 Sep 2021 00:10:40 GMT + +_Version update only_ + +## 0.1.3 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.1.2 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.1.1 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.1.0 +Tue, 14 Sep 2021 01:17:04 GMT + +### Minor changes + +- Initial release + diff --git a/heft-plugins/heft-storybook-plugin/LICENSE b/heft-plugins/heft-storybook-plugin/LICENSE new file mode 100644 index 00000000000..034b50a5aae --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-storybook-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-storybook-plugin/README.md b/heft-plugins/heft-storybook-plugin/README.md new file mode 100644 index 00000000000..4654c7bb305 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/README.md @@ -0,0 +1,13 @@ +# @rushstack/heft-storybook-plugin + +This is a Heft plugin for using the [Storybook](https://storybook.js.org/) tool for developing and testing +UI components. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-storybook-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-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/config/jest.config.json b/heft-plugins/heft-storybook-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-storybook-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-storybook-plugin/config/rig.json b/heft-plugins/heft-storybook-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-storybook-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-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 new file mode 100644 index 00000000000..c961ec466f9 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/heft-plugin.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "storybook-plugin", + "entryPoint": "./lib/StorybookPlugin", + "optionsSchema": "./lib/schemas/storybook.schema.json", + + "parameterScope": "storybook", + "parameters": [ + { + "longName": "--storybook", + "description": "(EXPERIMENTAL) Used by the \"@rushstack/heft-storybook-plugin\" package to launch Storybook.", + "parameterKind": "flag" + }, + { + "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" + } + ] + } + ] +} diff --git a/heft-plugins/heft-storybook-plugin/package.json b/heft-plugins/heft-storybook-plugin/package.json new file mode 100644 index 00000000000..db1ce985a63 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rushstack/heft-storybook-plugin", + "version": "1.1.8", + "description": "Heft plugin for supporting UI development using Storybook", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-storybook-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.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-webpack4-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts new file mode 100644 index 00000000000..d5182c5c2a9 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts @@ -0,0 +1,588 @@ +// 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 'node:child_process'; +import * as path from 'node:path'; + +import { + AlreadyExistsBehavior, + FileSystem, + Import, + type IParsedPackageNameOrError, + PackageName, + SubprocessTerminator, + FileConstants, + type IPackageJson, + InternalError, + JsonFile +} from '@rushstack/node-core-library'; +import { TerminalStreamWritable, type ITerminal, TerminalProviderSeverity } from '@rushstack/terminal'; +import type { + HeftConfiguration, + IHeftTaskSession, + IScopedLogger, + IHeftTaskPlugin, + CommandLineFlagParameter, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; +import type { + PluginName as Webpack4PluginName, + IWebpackPluginAccessor as IWebpack4PluginAccessor +} from '@rushstack/heft-webpack4-plugin'; +import type { + PluginName as Webpack5PluginName, + IWebpackPluginAccessor as IWebpack5PluginAccessor +} from '@rushstack/heft-webpack5-plugin'; + +const PLUGIN_NAME: 'storybook-plugin' = 'storybook-plugin'; +const WEBPACK4_PLUGIN_NAME: typeof Webpack4PluginName = 'webpack4-plugin'; +const WEBPACK5_PLUGIN_NAME: typeof Webpack5PluginName = 'webpack5-plugin'; + +/** + * Storybook CLI build type targets + */ +enum StorybookBuildMode { + /** + * Invoke storybook in watch mode + */ + WATCH = 'watch', + /** + * Invoke storybook in build mode + */ + BUILD = 'build' +} + +/** + * Storybook CLI versions + */ +enum StorybookCliVersion { + STORYBOOK6 = 'storybook6', + STORYBOOK7 = 'storybook7', + STORYBOOK8 = 'storybook8' +} + +/** + * Configuration object holding default storybook cli package and command + */ +interface IStorybookCliCallingConfig { + command: Record; + packageName: string; +} + +/** + * Options for `StorybookPlugin`. + * + * @public + */ +export interface IStorybookPluginOptions { + /** + * Specifies an NPM package that will provide the Storybook dependencies for the project. + * + * @example + * `"storykitPackageName": "my-react-storykit"` + * + * @remarks + * + * Storybook's conventional approach is for your app project to have direct dependencies + * on NPM packages such as `@storybook/react` and `@storybook/addon-essentials`. These packages have + * heavyweight dependencies such as Babel, Webpack, and the associated loaders and plugins needed to + * build the Storybook app (which is bundled completely independently from Heft). Naively adding these + * dependencies to your app's package.json muddies the waters of two radically different toolchains, + * and is likely to lead to dependency conflicts, for example if Heft installs Webpack 5 but + * `@storybook/react` installs Webpack 4. + * + * To solve this problem, `heft-storybook-plugin` introduces the concept of a separate + * "storykit package". All of your Storybook NPM packages are moved to be dependencies of the + * storykit. Storybook's browser API unfortunately isn't separated into dedicated NPM packages, + * but instead is exported by the Node.js toolchain packages such as `@storybook/react`. For + * an even cleaner separation the storykit package can simply reexport such APIs. + */ + storykitPackageName: string; + + /** + * Specify how the Storybook CLI should be invoked. Possible values: + * + * - "storybook6": For a static build, Heft will expect the cliPackageName package + * to define a binary command named "build-storybook". For the dev server mode, + * Heft will expect to find a binary command named "start-storybook". These commands + * must be declared in the "bin" section of package.json since Heft invokes the script directly. + * The output folder will be specified using the "--output-dir" CLI parameter. + * + * - "storybook7": Heft looks for a single binary command named "sb". It will be invoked as + * "sb build" for static builds, or "sb dev" for dev server mode. + * The output folder will be specified using the "--output-dir" CLI parameter. + * + * @defaultValue `storybook7` + */ + cliCallingConvention?: `${StorybookCliVersion}`; + + /** + * Specify the NPM package that provides the CLI binary to run. + * It will be resolved from the folder of your storykit package. + * + * @defaultValue + * The default is `@storybook/cli` when `cliCallingConvention` is `storybook7` + * and `@storybook/react` when `cliCallingConvention` is `storybook6` + */ + cliPackageName?: string; + + /** + * The customized output dir for storybook static build. + * If this is empty, then it will use the storybook default output dir. + * + * @example + * If you want to change the static build output dir to staticBuildDir, then the static build output dir would be: + * + * `"staticBuildOutputFolder": "newStaticBuildDir"` + */ + staticBuildOutputFolder?: string; + + /** + * Specifies an NPM dependency name that is used as the (cwd) target for the storybook commands + * By default the plugin executes the storybook commands in the local package context, + * but for distribution purposes it can be useful to split the TS library and storybook exports into two packages. + * + * @example + * If you create a storybook app project "my-ui-storybook-library-app" for the storybook preview distribution, + * and your main UI component library is my-ui-storybook-library. + * + * Your 'app' project is able to compile the 'library' storybook preview using the CWD target: + * + * `"cwdPackageName": "my-storybook-ui-library"` + */ + cwdPackageName?: string; + /** + * Specifies whether to capture the webpack stats for the storybook build by adding the `--webpack-stats-json` CLI flag. + */ + captureWebpackStats?: boolean; +} + +interface IRunStorybookOptions extends IPrepareStorybookOptions { + logger: IScopedLogger; + isServeMode: boolean; + workingDirectory: string; + resolvedModulePath: string; + outputFolder: string | undefined; + moduleDefaultArgs: string[]; + verbose: boolean; +} + +interface IPrepareStorybookOptions extends IStorybookPluginOptions { + logger: IScopedLogger; + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + isServeMode: boolean; + isTestMode: boolean; + isDocsMode: boolean; +} + +const DEFAULT_STORYBOOK_VERSION: StorybookCliVersion = StorybookCliVersion.STORYBOOK7; +const DEFAULT_STORYBOOK_CLI_CONFIG: Record = { + [StorybookCliVersion.STORYBOOK6]: { + packageName: '@storybook/react', + command: { + watch: ['start-storybook'], + build: ['build-storybook'] + } + }, + [StorybookCliVersion.STORYBOOK7]: { + packageName: '@storybook/cli', + command: { + watch: ['sb', 'dev'], + build: ['sb', 'build'] + } + }, + [StorybookCliVersion.STORYBOOK8]: { + packageName: 'storybook', + command: { + watch: ['sb', 'dev'], + build: ['sb', 'build'] + } + } +}; + +const STORYBOOK_FLAG_NAME: '--storybook' = '--storybook'; +const STORYBOOK_TEST_FLAG_NAME: '--storybook-test' = '--storybook-test'; +const DOCS_FLAG_NAME: '--docs' = '--docs'; + +/** @public */ +export default class StorybookPlugin implements IHeftTaskPlugin { + /** + * Generate typings for Sass files before TypeScript compilation. + */ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IStorybookPluginOptions + ): void { + const logger: IScopedLogger = taskSession.logger; + const storybookParameter: CommandLineFlagParameter = + taskSession.parameters.getFlagParameter(STORYBOOK_FLAG_NAME); + const storybookTestParameter: CommandLineFlagParameter = + taskSession.parameters.getFlagParameter(STORYBOOK_TEST_FLAG_NAME); + const docsParameter: CommandLineFlagParameter = taskSession.parameters.getFlagParameter(DOCS_FLAG_NAME); + + const parseResult: IParsedPackageNameOrError = PackageName.tryParse(options.storykitPackageName); + if (parseResult.error) { + throw new Error( + `The ${taskSession.taskName} task cannot start because the "storykitPackageName"` + + ` plugin option is not a valid package name: ` + + parseResult.error + ); + } + + // Only tap if the --storybook flag is present. + if (storybookParameter.value) { + const configureWebpackTap: () => Promise = async () => { + // Discard Webpack's configuration to prevent Webpack from running + logger.terminal.writeLine( + 'The command line includes "--storybook", redirecting Webpack to Storybook' + ); + return false; + }; + + let isServeMode: boolean = false; + taskSession.requestAccessToPluginByName( + '@rushstack/heft-webpack4-plugin', + WEBPACK4_PLUGIN_NAME, + (accessor: IWebpack4PluginAccessor) => { + 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); + } + ); + + taskSession.requestAccessToPluginByName( + '@rushstack/heft-webpack5-plugin', + WEBPACK5_PLUGIN_NAME, + (accessor: IWebpack5PluginAccessor) => { + 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); + } + ); + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const runStorybookOptions: IRunStorybookOptions = await this._prepareStorybookAsync({ + logger, + taskSession, + heftConfiguration, + isServeMode, + isTestMode: storybookTestParameter.value, + isDocsMode: docsParameter.value, + ...options + }); + await this._runStorybookAsync(runStorybookOptions, 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; + const buildMode: StorybookBuildMode = taskSession.parameters.watch + ? StorybookBuildMode.WATCH + : StorybookBuildMode.BUILD; + + if (buildMode === StorybookBuildMode.WATCH && isTestMode) { + throw new Error(`The ${STORYBOOK_TEST_FLAG_NAME} flag is not supported in watch mode`); + } + if ( + isTestMode && + (storybookCliVersion === StorybookCliVersion.STORYBOOK6 || + storybookCliVersion === StorybookCliVersion.STORYBOOK7) + ) { + throw new Error( + `The ${STORYBOOK_TEST_FLAG_NAME} flag is only supported in Storybook version 8 and above.` + ); + } + + logger.terminal.writeVerboseLine(`Probing for "${storykitPackageName}"`); + // Example: "/path/to/my-project/node_modules/my-storykit" + let storykitFolderPath: string; + try { + storykitFolderPath = Import.resolvePackage({ + packageName: storykitPackageName, + baseFolderPath: heftConfiguration.buildFolderPath, + useNodeJSResolver: true + }); + } catch (ex) { + throw new Error(`The ${taskSession.taskName} task cannot start: ` + (ex as Error).message); + } + + logger.terminal.writeVerboseLine(`Found "${storykitPackageName}" in ` + storykitFolderPath); + + logger.terminal.writeVerboseLine(`Probing for "${cliPackageName}" in "${storykitPackageName}"`); + // Example: "/path/to/my-project/node_modules/my-storykit/node_modules/@storybook/cli" + let storyBookCliPackage: string; + try { + storyBookCliPackage = Import.resolvePackage({ + packageName: cliPackageName, + baseFolderPath: storykitFolderPath, + useNodeJSResolver: true + }); + } catch (ex) { + throw new Error(`The ${taskSession.taskName} task cannot start: ` + (ex as Error).message); + } + + logger.terminal.writeVerboseLine(`Found "${cliPackageName}" in ` + storyBookCliPackage); + + const storyBookPackagePackageJsonFile: string = path.join(storyBookCliPackage, FileConstants.PackageJson); + const packageJson: IPackageJson = await JsonFile.loadAsync(storyBookPackagePackageJsonFile); + if (!packageJson.bin || typeof packageJson.bin === 'string') { + throw new Error( + `The cli package "${cliPackageName}" does not provide a 'bin' executables in the 'package.json'` + ); + } + const [moduleExecutableName, ...moduleDefaultArgs] = storyBookCliConfig.command[buildMode]; + const modulePath: string | undefined = packageJson.bin[moduleExecutableName]; + logger.terminal.writeVerboseLine( + `Found storybook "${modulePath}" for "${buildMode}" mode in "${cliPackageName}"` + ); + + // Example: "/path/to/my-project/node_modules/my-storykit/node_modules" + const storykitModuleFolderPath: string = `${storykitFolderPath}/node_modules`; + const storykitModuleFolderExists: boolean = await FileSystem.existsAsync(storykitModuleFolderPath); + if (!storykitModuleFolderExists) { + throw new Error( + `The ${taskSession.taskName} task cannot start because the storykit module folder does not exist:\n` + + storykitModuleFolderPath + + '\nDid you forget to install it?' + ); + } + + // We only want to specify a different output dir when operating in build mode + const outputFolder: string | undefined = + buildMode === StorybookBuildMode.WATCH ? undefined : staticBuildOutputFolder; + + if (!modulePath) { + logger.terminal.writeVerboseLine( + 'No matching module path option specified in heft.json, so bundling will proceed without Storybook' + ); + } + + logger.terminal.writeVerboseLine(`Resolving modulePath "${modulePath}"`); + let resolvedModulePath: string; + try { + resolvedModulePath = Import.resolveModule({ + modulePath: modulePath, + baseFolderPath: storyBookCliPackage + }); + } catch (ex) { + throw new Error(`The ${taskSession.taskName} task cannot start: ` + (ex as Error).message); + } + logger.terminal.writeVerboseLine(`Resolved modulePath is "${resolvedModulePath}"`); + + // Example: "/path/to/my-project/.storybook" + const dotStorybookFolderPath: string = `${heftConfiguration.buildFolderPath}/.storybook`; + await FileSystem.ensureFolderAsync(dotStorybookFolderPath); + + // Example: "/path/to/my-project/.storybook/node_modules" + const dotStorybookModuleFolderPath: string = `${dotStorybookFolderPath}/node_modules`; + + // Example: + // LINK FROM: "/path/to/my-project/.storybook/node_modules" + // TARGET: "/path/to/my-project/node_modules/my-storykit/node_modules" + // + // For node_modules links it's standard to use createSymbolicLinkJunction(), which avoids + // administrator elevation on Windows; on other operating systems it will create a symbolic link. + await FileSystem.createSymbolicLinkJunctionAsync({ + newLinkPath: dotStorybookModuleFolderPath, + linkTargetPath: storykitModuleFolderPath, + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite + }); + + return { + ...options, + workingDirectory: heftConfiguration.buildFolderPath, + resolvedModulePath, + moduleDefaultArgs, + outputFolder, + verbose: taskSession.parameters.verbose + }; + } + + private async _runStorybookAsync( + runStorybookOptions: IRunStorybookOptions, + options: IStorybookPluginOptions + ): Promise { + const { logger, resolvedModulePath, verbose, isServeMode, isTestMode, isDocsMode } = runStorybookOptions; + let { workingDirectory, outputFolder } = runStorybookOptions; + logger.terminal.writeLine('Running Storybook compilation'); + logger.terminal.writeVerboseLine(`Loading Storybook module "${resolvedModulePath}"`); + const storybookCliVersion: `${StorybookCliVersion}` = this._getStorybookVersion(options); + + /** + * Support \'cwdPackageName\' option + * by changing the working directory of the storybook command + */ + if (options.cwdPackageName) { + // Map outputFolder to local context. + if (outputFolder) { + outputFolder = path.resolve(workingDirectory, outputFolder); + } + + // Update workingDirectory to target context. + workingDirectory = await Import.resolvePackageAsync({ + packageName: options.cwdPackageName, + baseFolderPath: workingDirectory + }); + + logger.terminal.writeVerboseLine(`Changing Storybook working directory to "${workingDirectory}"`); + } + + const storybookArgs: string[] = runStorybookOptions.moduleDefaultArgs ?? []; + + if (outputFolder) { + storybookArgs.push('--output-dir', outputFolder); + } + + if (options.captureWebpackStats) { + storybookArgs.push('--webpack-stats-json'); + } + + if (!verbose) { + storybookArgs.push('--quiet'); + } + + if (isTestMode) { + storybookArgs.push('--test'); + } + + if (isDocsMode) { + storybookArgs.push('--docs'); + } + + if (isServeMode) { + // Instantiate storybook runner synchronously for incremental builds + // this ensure that the process is not killed when heft watcher detects file changes + this._invokeSync( + logger, + resolvedModulePath, + storybookArgs, + storybookCliVersion === StorybookCliVersion.STORYBOOK8 + ); + } else { + await this._invokeAsSubprocessAsync(logger, resolvedModulePath, storybookArgs, workingDirectory); + } + } + + /** + * Invoke storybook cli in a forked subprocess + * @param command - storybook command + * @param args - storybook args + * @param cwd - working directory + * @returns + */ + private async _invokeAsSubprocessAsync( + logger: IScopedLogger, + command: string, + args: string[], + cwd: string + ): 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, + ...SubprocessTerminator.RECOMMENDED_OPTIONS + }); + + SubprocessTerminator.killProcessTreeOnExit(forkedProcess, SubprocessTerminator.RECOMMENDED_OPTIONS); + + const childPid: number | undefined = forkedProcess.pid; + if (childPid === undefined) { + throw new InternalError(`Failed to spawn child process`); + } + logger.terminal.writeVerboseLine(`Started storybook process #${childPid}`); + + // Apply the pipe here instead of doing it in the forked process args due to a bug in Node + // We will output stderr to the normal stdout stream since all output is piped through + // stdout. We have to rely on the exit code to determine if there was an error. + const terminal: ITerminal = logger.terminal; + const terminalOutStream: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.log + }); + forkedProcess.stdout!.pipe(terminalOutStream); + forkedProcess.stderr!.pipe(terminalOutStream); + + let processFinished: boolean = false; + forkedProcess.on('error', (error: Error) => { + processFinished = true; + reject(new Error(`Storybook returned error: ${error}`)); + }); + + forkedProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { + if (processFinished) { + return; + } + processFinished = true; + if (exitCode) { + reject(new Error(`Storybook exited with code ${exitCode}`)); + } else if (signal) { + reject(new Error(`Storybook terminated by signal ${signal}`)); + } else { + resolve(); + } + }); + }); + } + + /** + * Invoke storybook cli synchronously within the current process + * @param command - storybook command + * @param args - storybook args + * @param cwd - working directory + */ + private _invokeSync( + logger: IScopedLogger, + command: string, + args: string[], + patchNpmConfigUserAgent: boolean + ): void { + logger.terminal.writeLine('Launching ' + command); + + // simulate storybook cli command + const originalArgv: string[] = process.argv; + const node: string = originalArgv[0]; + process.argv = [node, command, ...args]; + // npm_config_user_agent is used by Storybook to determine the package manager + // in a Rush monorepo it can't determine it automatically so it raises a benign error + // Storybook failed to check addon compatibility Error: Unable to find a usable package manager within NPM, PNPM, Yarn and Yarn 2 + // hardcode it to NPM to suppress the error + // + // This only happens for dev server mode, not for build mode, so does not need to be in _invokeAsSubprocessAsync + // + // Storing the original env and restoring it like happens with argv does not seem to work + // At the time when storybook checks env.npm_config_user_agent it has been reset to undefined + if (patchNpmConfigUserAgent) { + process.env.npm_config_user_agent = 'npm'; + } + + // invoke command synchronously + require(command); + + // restore original heft process argv + process.argv = originalArgv; + + logger.terminal.writeVerboseLine('Completed synchronous portion of launching startupModulePath'); + } + + private _getStorybookVersion(options: IStorybookPluginOptions): `${StorybookCliVersion}` { + return options.cliCallingConvention ?? DEFAULT_STORYBOOK_VERSION; + } +} diff --git a/heft-plugins/heft-storybook-plugin/src/schemas/storybook.schema.json b/heft-plugins/heft-storybook-plugin/src/schemas/storybook.schema.json new file mode 100644 index 00000000000..b0eb7ebf506 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/src/schemas/storybook.schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Storybook Plugin Options Configuration", + "description": "This schema describes the \"options\" field that can be specified in heft.json when loading \"@rushstack/heft-storybook-plugin\".", + "type": "object", + "additionalProperties": false, + "required": ["storykitPackageName"], + + "properties": { + "storykitPackageName": { + "title": "Specifies an NPM package that will provide the Storybook dependencies for the project.", + "description": "Storybook's conventional approach is for your app project to have direct dependencies on NPM packages such as `@storybook/react` and `@storybook/addon-essentials`. These packages have heavyweight dependencies such as Babel, Webpack, and the associated loaders and plugins needed to build the Storybook app (which is bundled completely independently from Heft). Naively adding these dependencies to your app's package.json muddies the waters of two radically different toolchains, and is likely to lead to dependency conflicts, for example if Heft installs Webpack 5 but `@storybook/react` installs Webpack 4. To solve this problem, `heft-storybook-plugin` introduces the concept of a separate \"storykit package\". All of your Storybook NPM packages are moved to be dependencies of the storykit. Storybook's browser API unfortunately isn't separated into dedicated NPM packages, but instead is exported by the Node.js toolchain packages such as `@storybook/react`. For an even cleaner separation the storykit package can simply reexport such APIs.", + "type": "string" + }, + "cliCallingConvention": { + "title": "Specifies the calling convention of the storybook CLI based on the storybook version.", + "description": "Specify how the Storybook CLI should be invoked. Possible values: \"storybook6\" or \"storybook7\", defaults to \"storybook7\".", + "enum": ["storybook6", "storybook7", "storybook8"] + }, + "cliPackageName": { + "title": "The NPM package that Heft should use to launch the Storybook toolchain.", + "description": "Specify the NPM package that provides the CLI binary to run. Defaults to `@storybook/cli` for storybook 7 and `@storybook/react` for storybook 6.", + "type": "string" + }, + "staticBuildOutputFolder": { + "title": "The customized output dir for storybook static build.", + "description": "If this is empty, then it will use the storybook default output dir. If you want to change the static build output dir to staticBuildDir, then the static build output dir would be: `\"staticBuildOutputFolder\": \"staticBuildDir\"`", + "type": "string", + "pattern": "[^\\\\]" + }, + "cwdPackageName": { + "title": "Specifies an NPM dependency name that is used as the CWD target for the storybook commands", + "description": "By default the plugin executes the storybook commands in the local package context, but for distribution purposes it can be useful to split the TS library and storybook exports into two packages. For example, If you create a storybook 'app' project \"my-ui-storybook-library-app\" for the storybook preview distribution, and your main UI component `library` is my-ui-storybook-library. Your 'app' project is able to compile the 'library' storybook app using the CWD target: `\"cwdPackageName\": \"my-ui-storybook-library\"`", + "type": "string" + }, + "captureWebpackStats": { + "title": "Specifies whether to capture the webpack stats for storybook build.", + "description": "If this is true, then it will capture the webpack stats for storybook build. Defaults to false.", + "type": "boolean" + } + } +} diff --git a/heft-plugins/heft-storybook-plugin/tsconfig.json b/heft-plugins/heft-storybook-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-typescript-plugin/.npmignore b/heft-plugins/heft-typescript-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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-typescript-plugin/CHANGELOG.json b/heft-plugins/heft-typescript-plugin/CHANGELOG.json new file mode 100644 index 00000000000..2e305d2816f --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/CHANGELOG.json @@ -0,0 +1,2739 @@ +{ + "name": "@rushstack/heft-typescript-plugin", + "entries": [ + { + "version": "1.1.7", + "tag": "@rushstack/heft-typescript-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/heft-config-file\" to `0.19.5`" + }, + { + "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-typescript-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/heft-config-file\" to `0.19.4`" + }, + { + "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-typescript-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "patch": [ + { + "comment": "Support \"${configDir}\" token in tsconfig when using file copier." + } + ], + "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-typescript-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-typescript-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-config-file\" to `0.19.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-typescript-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-config-file\" to `0.19.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-typescript-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-config-file\" to `0.19.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-typescript-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-config-file\" to `0.19.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-typescript-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-config-file\" to `0.18.6`" + }, + { + "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.9.15", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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 \"@rushstack/heft-config-file\" to `0.18.5`" + }, + { + "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.9.14", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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.9.13", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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/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.9.12", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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.9.11", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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.9.10", + "tag": "@rushstack/heft-typescript-plugin_v0.9.10", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "patch": [ + { + "comment": "Update internal typings." + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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 \"@rushstack/heft-config-file\" to `0.18.3`" + }, + { + "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.9.8", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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.9.7", + "tag": "@rushstack/heft-typescript-plugin_v0.9.7", + "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.9.6", + "tag": "@rushstack/heft-typescript-plugin_v0.9.6", + "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.9.5", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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 \"@rushstack/heft-config-file\" to `0.18.2`" + }, + { + "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.9.4", + "tag": "@rushstack/heft-typescript-plugin_v0.9.4", + "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.9.3", + "tag": "@rushstack/heft-typescript-plugin_v0.9.3", + "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.9.2", + "tag": "@rushstack/heft-typescript-plugin_v0.9.2", + "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 \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-typescript-plugin_v0.9.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.9.0", + "tag": "@rushstack/heft-typescript-plugin_v0.9.0", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "minor": [ + { + "comment": "Leverage Heft's new `tryLoadProjectConfigurationFileAsync` method." + } + ], + "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.8.2", + "tag": "@rushstack/heft-typescript-plugin_v0.8.2", + "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\" from `0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-typescript-plugin_v0.8.1", + "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-config-file\" to `0.16.8`" + }, + { + "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.8.0", + "tag": "@rushstack/heft-typescript-plugin_v0.8.0", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "minor": [ + { + "comment": "Expose some internal APIs to be used by `@rushstack/heft-isolated-typescript-transpile-plugin`." + } + ], + "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.7.1", + "tag": "@rushstack/heft-typescript-plugin_v0.7.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.7.0", + "tag": "@rushstack/heft-typescript-plugin_v0.7.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.7`" + }, + { + "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.6.16", + "tag": "@rushstack/heft-typescript-plugin_v0.6.16", + "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.6.15", + "tag": "@rushstack/heft-typescript-plugin_v0.6.15", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for TypeScript 5.7." + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/heft-typescript-plugin_v0.6.14", + "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.6.13", + "tag": "@rushstack/heft-typescript-plugin_v0.6.13", + "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.6.12", + "tag": "@rushstack/heft-typescript-plugin_v0.6.12", + "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.6.11", + "tag": "@rushstack/heft-typescript-plugin_v0.6.11", + "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.6.10", + "tag": "@rushstack/heft-typescript-plugin_v0.6.10", + "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.6.9", + "tag": "@rushstack/heft-typescript-plugin_v0.6.9", + "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/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.6.8", + "tag": "@rushstack/heft-typescript-plugin_v0.6.8", + "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.6.7", + "tag": "@rushstack/heft-typescript-plugin_v0.6.7", + "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-config-file\" to `0.16.4`" + }, + { + "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.6.6", + "tag": "@rushstack/heft-typescript-plugin_v0.6.6", + "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-config-file\" to `0.16.3`" + }, + { + "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.6.5", + "tag": "@rushstack/heft-typescript-plugin_v0.6.5", + "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.6.4", + "tag": "@rushstack/heft-typescript-plugin_v0.6.4", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-typescript-plugin_v0.6.3", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-typescript-plugin_v0.6.2", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-typescript-plugin_v0.6.1", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-typescript-plugin_v0.6.0", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"onlyResolveSymlinksInNodeModules\" option to improve performance for typical repository layouts." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.5.35", + "tag": "@rushstack/heft-typescript-plugin_v0.5.35", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.5.34", + "tag": "@rushstack/heft-typescript-plugin_v0.5.34", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.5.33", + "tag": "@rushstack/heft-typescript-plugin_v0.5.33", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.5.32", + "tag": "@rushstack/heft-typescript-plugin_v0.5.32", + "date": "Wed, 16 Oct 2024 00:11:20 GMT", + "comments": { + "patch": [ + { + "comment": "Support typescript v5.6" + } + ] + } + }, + { + "version": "0.5.31", + "tag": "@rushstack/heft-typescript-plugin_v0.5.31", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/heft-typescript-plugin_v0.5.30", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/heft-typescript-plugin_v0.5.29", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/heft-typescript-plugin_v0.5.28", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/heft-typescript-plugin_v0.5.27", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/heft-typescript-plugin_v0.5.26", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/heft-typescript-plugin_v0.5.25", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/heft-typescript-plugin_v0.5.24", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/heft-typescript-plugin_v0.5.23", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/heft-typescript-plugin_v0.5.22", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/heft-typescript-plugin_v0.5.21", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/heft-typescript-plugin_v0.5.20", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/heft-typescript-plugin_v0.5.19", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/heft-typescript-plugin_v0.5.18", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/heft-typescript-plugin_v0.5.17", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/heft-typescript-plugin_v0.5.16", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/heft-typescript-plugin_v0.5.15", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/heft-typescript-plugin_v0.5.14", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/heft-typescript-plugin_v0.5.13", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/heft-typescript-plugin_v0.5.12", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/heft-typescript-plugin_v0.5.11", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/heft-typescript-plugin_v0.5.10", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/heft-typescript-plugin_v0.5.9", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/heft-typescript-plugin_v0.5.8", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/heft-typescript-plugin_v0.5.7", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/heft-typescript-plugin_v0.5.6", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/heft-typescript-plugin_v0.5.5", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/heft-typescript-plugin_v0.5.4", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-typescript-plugin_v0.5.3", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-typescript-plugin_v0.5.2", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-typescript-plugin_v0.5.1", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-typescript-plugin_v0.5.0", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "minor": [ + { + "comment": "Gracefully exit transpile worker instead of using `process.exit(0)`." + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-typescript-plugin_v0.4.0", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Bump latest supported version of TypeScript to 5.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-typescript-plugin_v0.3.21", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-typescript-plugin_v0.3.20", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-typescript-plugin_v0.3.19", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-typescript-plugin_v0.3.18", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-typescript-plugin_v0.3.17", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-typescript-plugin_v0.3.16", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-typescript-plugin_v0.3.15", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-typescript-plugin_v0.3.14", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.4` to `0.65.5`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-typescript-plugin_v0.3.13", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.3` to `0.65.4`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-typescript-plugin_v0.3.12", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.2` to `0.65.3`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-typescript-plugin_v0.3.11", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.1` to `0.65.2`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-typescript-plugin_v0.3.10", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.65.0` to `0.65.1`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-typescript-plugin_v0.3.9", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.8` to `0.65.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-typescript-plugin_v0.3.8", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.7` to `0.64.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-typescript-plugin_v0.3.7", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.6` to `0.64.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-typescript-plugin_v0.3.6", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.5` to `0.64.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-typescript-plugin_v0.3.5", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.4` to `0.64.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-typescript-plugin_v0.3.4", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.3` to `0.64.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-typescript-plugin_v0.3.3", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.2` to `0.64.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-typescript-plugin_v0.3.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.1` to `0.64.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-typescript-plugin_v0.3.1", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.64.0` to `0.64.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-typescript-plugin_v0.3.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.6` to `0.64.0`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-typescript-plugin_v0.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "patch": [ + { + "comment": "Fix break in watch mode during updateShapeSignature call." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.5` to `0.63.6`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-typescript-plugin_v0.2.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.4` to `0.63.5`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-typescript-plugin_v0.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.3` to `0.63.4`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-typescript-plugin_v0.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.2` to `0.63.3`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-typescript-plugin_v0.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.1` to `0.63.2`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-typescript-plugin_v0.2.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.63.0` to `0.63.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-typescript-plugin_v0.2.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.3` to `0.63.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-typescript-plugin_v0.2.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.2` to `0.62.3`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-typescript-plugin_v0.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.1` to `0.62.2`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-typescript-plugin_v0.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.62.0` to `0.62.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-typescript-plugin_v0.2.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.3` to `0.62.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-typescript-plugin_v0.2.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.2` to `0.61.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-typescript-plugin_v0.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.1` to `0.61.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-typescript-plugin_v0.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.61.0` to `0.61.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-typescript-plugin_v0.2.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.60.0` to `0.61.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-typescript-plugin_v0.2.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.59.0` to `0.60.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-typescript-plugin_v0.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "patch": [ + { + "comment": "Fix bugs related to tracking of the current working directory if the value changes." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.2` to `0.59.0`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-typescript-plugin_v0.1.21", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.1` to `0.58.2`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-typescript-plugin_v0.1.20", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.58.0` to `0.58.1`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-typescript-plugin_v0.1.19", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.1` to `0.58.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-typescript-plugin_v0.1.18", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.57.0` to `0.57.1`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-typescript-plugin_v0.1.17", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.3` to `0.57.0`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-typescript-plugin_v0.1.16", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.2` to `0.56.3`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-typescript-plugin_v0.1.15", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "patch": [ + { + "comment": "Only make warnings terminal if \"buildProjectReferences\" is true." + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-typescript-plugin_v0.1.14", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.1` to `0.56.2`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-typescript-plugin_v0.1.13", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.56.0` to `0.56.1`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-typescript-plugin_v0.1.12", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "patch": [ + { + "comment": "Fix evaluation of the \"project\" configuration option." + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-typescript-plugin_v0.1.11", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.2` to `0.56.0`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-typescript-plugin_v0.1.10", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.1` to `0.55.2`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-typescript-plugin_v0.1.9", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.55.0` to `0.55.1`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-typescript-plugin_v0.1.8", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.54.0` to `0.55.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-typescript-plugin_v0.1.7", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.1` to `0.54.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-typescript-plugin_v0.1.6", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.53.0` to `0.53.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-typescript-plugin_v0.1.5", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "patch": [ + { + "comment": "Emit error if warnings are encountered when building in solution mode. This avoids confusion because the TypeScript compiler implicitly sets `noEmitOnError: true` when building in solution mode." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.2` to `0.53.0`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-typescript-plugin_v0.1.4", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.1` to `0.52.2`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-typescript-plugin_v0.1.3", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "patch": [ + { + "comment": "Use the temp folder instead of the cache folder." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.52.0` to `0.52.1`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-typescript-plugin_v0.1.2", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.51.0` to `0.52.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-typescript-plugin_v0.1.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "patch": [ + { + "comment": "Fix resolution of relative tsconfig paths that start with './' or '../'." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-typescript-plugin_v0.1.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Prepare for official release." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.50.0` to `0.51.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-typescript-plugin/CHANGELOG.md b/heft-plugins/heft-typescript-plugin/CHANGELOG.md new file mode 100644 index 00000000000..695a85439c9 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/CHANGELOG.md @@ -0,0 +1,785 @@ +# Change Log - @rushstack/heft-typescript-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +### Patches + +- Support "${configDir}" token in tsconfig when using file copier. + +## 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.9.15 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.9.14 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.9.13 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.9.12 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.9.11 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.9.10 +Mon, 28 Jul 2025 15:11:56 GMT + +### Patches + +- Update internal typings. + +## 0.9.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.9.8 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.9.7 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.9.6 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.9.5 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.9.4 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.9.3 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.9.2 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 0.9.1 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.9.0 +Wed, 09 Apr 2025 00:11:02 GMT + +### Minor changes + +- Leverage Heft's new `tryLoadProjectConfigurationFileAsync` method. + +## 0.8.2 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.8.1 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.8.0 +Wed, 12 Mar 2025 22:41:36 GMT + +### Minor changes + +- Expose some internal APIs to be used by `@rushstack/heft-isolated-typescript-transpile-plugin`. + +## 0.7.1 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.7.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Add support for TypeScript 5.8. + +## 0.6.16 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.6.15 +Sat, 01 Mar 2025 07:23:16 GMT + +### Patches + +- Add support for TypeScript 5.7. + +## 0.6.14 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.6.13 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.6.12 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.6.11 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.6.10 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.6.9 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.6.8 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.6.7 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.6.6 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.6.5 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.6.4 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.6.3 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.6.2 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.6.1 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.6.0 +Fri, 22 Nov 2024 01:10:43 GMT + +### Minor changes + +- Add "onlyResolveSymlinksInNodeModules" option to improve performance for typical repository layouts. + +## 0.5.35 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.5.34 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.5.33 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.5.32 +Wed, 16 Oct 2024 00:11:20 GMT + +### Patches + +- Support typescript v5.6 + +## 0.5.31 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.5.30 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.5.29 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.5.28 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.5.27 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.5.26 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.5.25 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.5.24 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.5.23 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.5.22 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.5.21 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.5.20 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.5.19 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.5.18 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.5.17 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.5.16 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.5.15 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.5.14 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.5.13 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.5.12 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.5.11 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.5.10 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.5.9 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.5.8 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.5.7 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.5.6 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.5.5 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.5.4 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.5.3 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.5.2 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.5.1 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.5.0 +Thu, 28 Mar 2024 22:42:23 GMT + +### Minor changes + +- Gracefully exit transpile worker instead of using `process.exit(0)`. + +## 0.4.0 +Tue, 19 Mar 2024 15:10:18 GMT + +### Minor changes + +- Bump latest supported version of TypeScript to 5.4 + +## 0.3.21 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.3.20 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.3.19 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.3.18 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.3.17 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.3.16 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.3.15 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.3.14 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.3.13 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.3.12 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.3.11 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.3.10 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.3.9 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.3.8 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.3.7 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.3.6 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.3.5 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.3.4 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.3.3 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.3.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.3.1 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.3.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Add support for TypeScript 5.3 + +## 0.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +### Patches + +- Fix break in watch mode during updateShapeSignature call. + +## 0.2.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.2.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.2.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.2.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.2.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.2.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.2.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.2.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +### Patches + +- Fix bugs related to tracking of the current working directory if the value changes. + +## 0.1.21 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.1.20 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.1.19 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.1.18 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 0.1.17 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.16 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.1.15 +Wed, 12 Jul 2023 00:23:29 GMT + +### Patches + +- Only make warnings terminal if "buildProjectReferences" is true. + +## 0.1.14 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.1.13 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.1.12 +Tue, 04 Jul 2023 00:18:47 GMT + +### Patches + +- Fix evaluation of the "project" configuration option. + +## 0.1.11 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.1.10 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.1.9 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.1.8 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.1.7 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 0.1.6 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.1.5 +Fri, 09 Jun 2023 00:19:49 GMT + +### Patches + +- Emit error if warnings are encountered when building in solution mode. This avoids confusion because the TypeScript compiler implicitly sets `noEmitOnError: true` when building in solution mode. + +## 0.1.4 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jun 2023 00:20:02 GMT + +### Patches + +- Use the temp folder instead of the cache folder. + +## 0.1.2 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 0.1.1 +Mon, 05 Jun 2023 21:45:21 GMT + +### Patches + +- Fix resolution of relative tsconfig paths that start with './' or '../'. + +## 0.1.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Prepare for official release. + diff --git a/heft-plugins/heft-typescript-plugin/LICENSE b/heft-plugins/heft-typescript-plugin/LICENSE new file mode 100644 index 00000000000..0c5c67a4896 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-typescript-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-typescript-plugin/README.md b/heft-plugins/heft-typescript-plugin/README.md new file mode 100644 index 00000000000..ce8b8ec809d --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-typescript-plugin + +This is a Heft plugin for compiling TypeScript. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-typescript-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-typescript-plugin/config/api-extractor.json b/heft-plugins/heft-typescript-plugin/config/api-extractor.json new file mode 100644 index 00000000000..74590d3c4f8 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$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": 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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/heft-plugins/heft-typescript-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": "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 new file mode 100644 index 00000000000..8b0bdcbe4a6 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "typescript-plugin", + "entryPoint": "./lib/TypeScriptPlugin" + } + ] +} diff --git a/heft-plugins/heft-typescript-plugin/package.json b/heft-plugins/heft-typescript-plugin/package.json new file mode 100644 index 00000000000..333da43d36e --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/package.json @@ -0,0 +1,37 @@ +{ + "name": "@rushstack/heft-typescript-plugin", + "version": "1.1.7", + "description": "Heft plugin for TypeScript", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-typescript-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "lib/index.js", + "types": "dist/heft-typescript-plugin.d.ts", + "license": "MIT", + "scripts": { + "build": "heft test --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "1.1.7" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/heft-config-file": "workspace:*", + "@types/tapable": "1.0.6", + "semver": "~7.5.4", + "tapable": "1.1.3" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/semver": "7.5.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + } +} diff --git a/heft-plugins/heft-typescript-plugin/src/Performance.ts b/heft-plugins/heft-typescript-plugin/src/Performance.ts new file mode 100644 index 00000000000..9115aa638c5 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/Performance.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. + +export type PerformanceMeasurer = ( + measurementName: string, + fn: () => TResult +) => TResult & { duration: number }; + +export type PerformanceMeasurerAsync = ( + measurementName: string, + fn: () => Promise +) => Promise; diff --git a/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts b/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts new file mode 100644 index 00000000000..9021218e3c5 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts @@ -0,0 +1,127 @@ +// 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 * as TTypescript from 'typescript'; + +import type { + ITranspilationErrorMessage, + ITranspilationRequestMessage, + ITranspilationSuccessMessage, + ITypescriptWorkerData +} from './types'; +import type { ExtendedTypeScript } from './internalTypings/TypeScriptInternals'; +import { configureProgramForMultiEmit } from './configureProgramForMultiEmit'; + +const typedWorkerData: ITypescriptWorkerData = workerData; + +const ts: ExtendedTypeScript = require(typedWorkerData.typeScriptToolPath); + +process.exitCode = 1; + +function handleMessage(message: ITranspilationRequestMessage | false): void { + if (!message) { + parentPort!.off('message', handleMessage); + parentPort!.close(); + return; + } + + try { + const response: ITranspilationSuccessMessage = runTranspiler(message); + parentPort!.postMessage(response); + } catch (err) { + const errorResponse: ITranspilationErrorMessage = { + requestId: message.requestId, + type: 'error', + result: { + message: err.message, + ...Object.fromEntries(Object.entries(err)) + } + }; + parentPort!.postMessage(errorResponse); + } +} + +function runTranspiler(message: ITranspilationRequestMessage): ITranspilationSuccessMessage { + const { requestId, compilerOptions, moduleKindsToEmit, filesToTranspile } = message; + + const fullySkipTypeCheck: boolean = + /* TypeScript 5+ */ compilerOptions.verbatimModuleSyntax || + /* TypeScript 4 */ compilerOptions.importsNotUsedAsValues === ts.ImportsNotUsedAsValues.Error; + + for (const [option, value] of Object.entries(ts.getDefaultCompilerOptions())) { + if (compilerOptions[option] === undefined) { + compilerOptions[option] = value; + } + } + + const { target: rawTarget } = compilerOptions; + + for (const option of ts.transpileOptionValueCompilerOptions) { + compilerOptions[option.name] = option.transpileOptionValue; + } + + compilerOptions.suppressOutputPathCheck = true; + compilerOptions.skipDefaultLibCheck = true; + // To fully disable the type checker, we have to set `hasNoDefaultLib: true` on every source file. + // However, doing so loses the information about which imports are used. + // To retain the imports, we use `preserveValueImports`. However, if some imports are only used for types, + // this will produce invalid runtime output unless said imports are marked with `type `. + // Thus we can only enable this optimization if `verbatimModuleSyntax` is enabled (or equivalent). + compilerOptions.preserveValueImports = fullySkipTypeCheck; + + const sourceFileByPath: Map = new Map(); + + const includedFiles: string[] = []; + for (const [fileName, sourceText] of filesToTranspile) { + if (sourceText) { + const sourceFile: TTypescript.SourceFile = ts.createSourceFile(fileName, sourceText, rawTarget!); + sourceFile.hasNoDefaultLib = fullySkipTypeCheck; + sourceFileByPath.set(fileName, sourceFile); + includedFiles.push(fileName); + } + } + + const newLine: string = ts.getNewLineCharacter(compilerOptions); + + const compilerHost: TTypescript.CompilerHost = { + getSourceFile: (fileName: string) => sourceFileByPath.get(fileName), + writeFile: ts.sys.writeFile, + getDefaultLibFileName: () => 'lib.d.ts', + useCaseSensitiveFileNames: () => true, + getCanonicalFileName: (fileName: string) => fileName, + getCurrentDirectory: () => '', + getNewLine: () => newLine, + fileExists: (fileName: string) => sourceFileByPath.has(fileName), + readFile: () => '', + directoryExists: () => true, + getDirectories: () => [] + }; + + const program: TTypescript.Program = ts.createProgram(includedFiles, compilerOptions, compilerHost); + + configureProgramForMultiEmit(program, ts, moduleKindsToEmit, 'transpile'); + + const result: TTypescript.EmitResult = program.emit( + undefined, + // The writeFile callback must be provided for the multi-emit redirector + ts.sys.writeFile, + undefined, + undefined, + undefined + ); + + const response: ITranspilationSuccessMessage = { + requestId, + type: 'success', + result + }; + + return response; +} + +parentPort!.once('close', () => { + process.exitCode = 0; +}); +parentPort!.on('message', handleMessage); diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts new file mode 100644 index 00000000000..a398242aafa --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts @@ -0,0 +1,1271 @@ +// 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 { Worker } from 'node:worker_threads'; + +import type * as TTypescript from 'typescript'; + +import { Path, FileError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import type { HeftConfiguration, IScopedLogger } from '@rushstack/heft'; + +import type { + ExtendedBuilderProgram, + ExtendedTypeScript, + IExtendedSolutionBuilder, + ITypeScriptNodeSystem +} from './internalTypings/TypeScriptInternals'; +import type { ITypeScriptConfigurationJson } from './TypeScriptPlugin'; +import type { PerformanceMeasurer } from './Performance'; +import type { + ICachedEmitModuleKind, + ITranspilationRequestMessage, + ITranspilationResponseMessage, + ITypescriptWorkerData +} from './types'; +import { configureProgramForMultiEmit } from './configureProgramForMultiEmit'; +import { loadTsconfig } from './tsconfigLoader'; +import { loadTypeScriptToolAsync } from './loadTypeScriptTool'; + +export interface ITypeScriptBuilderConfiguration extends ITypeScriptConfigurationJson { + /** + * The root folder of the build. + */ + buildFolderPath: string; + + /** + * The folder to write build metadata. + */ + buildMetadataFolderPath: string; + + /** + * The path to the TypeScript tool. + */ + heftConfiguration: HeftConfiguration; + + // watchMode: boolean; + + /** + * The path to the tsconfig file being built. + */ + tsconfigPath: string; + + /** + * The scoped logger that the builder will log to. + */ + scopedLogger: IScopedLogger; + + /** + * The callback used to emit the typescript program (or programs) from the builder. + */ + emitChangedFilesCallback: ( + program: TTypescript.Program, + changedFiles?: Set + ) => void; +} + +type TSolutionHost = TTypescript.SolutionBuilderHost; +type TWatchCompilerHost = + TTypescript.WatchCompilerHostOfFilesAndCompilerOptions; +type TWatchSolutionHost = + TTypescript.SolutionBuilderWithWatchHost; +type TWatchProgram = + TTypescript.WatchOfFilesAndCompilerOptions; + +interface IFileToWrite { + filePath: string; + data: string; +} + +interface IModuleKindReason { + kind: keyof typeof TTypescript.ModuleKind; + outDir: string; + extension: '.js' | '.cjs' | '.mjs'; + reason: string; +} + +interface IExtendedEmitResult extends TTypescript.EmitResult { + changedSourceFiles: Set; + filesToWrite: IFileToWrite[]; +} + +interface IPendingWork { + (): void; +} + +interface ITranspileSignal { + resolve: (result: TTypescript.EmitResult) => void; + reject: (error: Error) => void; +} + +/** + * @internal + */ +export interface IBaseTypeScriptTool { + typeScriptToolPath: string; + ts: ExtendedTypeScript; + system: TSystem; +} + +interface ITypeScriptTool extends IBaseTypeScriptTool { + measureSync: PerformanceMeasurer; + + sourceFileCache: Map; + + watchProgram: TWatchProgram | undefined; + + solutionBuilder: IExtendedSolutionBuilder | undefined; + + rawDiagnostics: TTypescript.Diagnostic[]; + pendingOperations: Set; + + executing: boolean; + + worker: Worker | undefined; + pendingTranspilePromises: Map>; + pendingTranspileSignals: Map; + + reportDiagnostic: TTypescript.DiagnosticReporter; +} + +export class TypeScriptBuilder { + private readonly _configuration: ITypeScriptBuilderConfiguration; + private readonly _typescriptLogger: IScopedLogger; + private readonly _typescriptTerminal: ITerminal; + + private _useSolutionBuilder!: boolean; + + private _moduleKindsToEmit!: ICachedEmitModuleKind[]; + private readonly _suppressedDiagnosticCodes: Set = new Set(); + + private __tsCacheFilePath: string | undefined; + + private _tool: ITypeScriptTool | undefined = undefined; + + private _nextRequestId: number = 0; + + private get _tsCacheFilePath(): string { + if (!this.__tsCacheFilePath) { + // TypeScript internally handles if the tsconfig options have changed from when the tsbuildinfo file was created. + // 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, '_'); + + // 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. + // TypeScript will normalize to '/' when serializing, but not on the direct input, and uses exact string equality. + const normalizedCacheFolderPath: string = Path.convertToSlashes( + this._configuration.buildMetadataFolderPath + ); + this.__tsCacheFilePath = `${normalizedCacheFolderPath}/ts_${serializedConfigHash}.json`; + } + + return this.__tsCacheFilePath; + } + + public constructor(configuration: ITypeScriptBuilderConfiguration) { + this._configuration = configuration; + this._typescriptLogger = configuration.scopedLogger; + this._typescriptTerminal = configuration.scopedLogger.terminal; + } + + public async invokeAsync(onChangeDetected?: () => void): Promise { + if (!this._tool) { + 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; + + ts.performance.enable(); + + const suppressedCodes: (number | undefined)[] = [ + ts.Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor?.code, + // This diagnostic code is not present in old versions of TypeScript + ts.Diagnostics + .Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1?.code + ]; + for (const code of suppressedCodes) { + if (code !== undefined) { + this._suppressedDiagnosticCodes.add(code); + } + } + + const measureTsPerformance: PerformanceMeasurer = ( + measurementName: string, + fn: () => TResult + ) => { + const beforeName: string = `before${measurementName}`; + ts.performance.mark(beforeName); + const result: TResult = fn(); + const afterName: string = `after${measurementName}`; + ts.performance.mark(afterName); + ts.performance.measure(measurementName, beforeName, afterName); + return { + ...result, + duration: ts.performance.getDuration(measurementName), + count: ts.performance.getCount(beforeName) + }; + }; + + this._typescriptTerminal.writeLine(`Using TypeScript version ${ts.version}`); + + const rawDiagnostics: TTypescript.Diagnostic[] = []; + + const pendingOperations: Set = new Set(); + + const clearTimeout = (timeout: IPendingWork): void => { + pendingOperations.delete(timeout); + }; + + const setTimeout = ( + fn: (...args: T) => void, + ms: number, + ...args: T + ): IPendingWork => { + const timeout: IPendingWork = () => { + fn(...args); + }; + pendingOperations.add(timeout); + if (!this._tool?.executing && onChangeDetected) { + onChangeDetected(); + } + return timeout; + }; + + const getCurrentDirectory: () => string = () => this._configuration.buildFolderPath; + + // Need to also update watchFile and watchDirectory + const system: ITypeScriptNodeSystem = { + ...baseSystem, + getCurrentDirectory, + clearTimeout, + setTimeout + }; + const { realpath } = system; + + if (realpath && system.getAccessibleFileSystemEntries) { + const { getAccessibleFileSystemEntries } = system; + system.readDirectory = (folderPath, extensions, exclude, include, depth): string[] => { + return ts.matchFiles( + folderPath, + extensions, + exclude, + include, + ts.sys.useCaseSensitiveFileNames, + getCurrentDirectory(), + depth, + getAccessibleFileSystemEntries, + realpath, + ts.sys.directoryExists + ); + }; + } + + this._tool = { + typeScriptToolPath, + ts, + system, + + measureSync: measureTsPerformance, + + sourceFileCache: new Map(), + + watchProgram: undefined, + solutionBuilder: undefined, + + rawDiagnostics, + + pendingOperations, + + executing: false, + + reportDiagnostic: (diagnostic: TTypescript.Diagnostic) => { + rawDiagnostics.push(diagnostic); + }, + + worker: undefined, + + pendingTranspilePromises: new Map(), + pendingTranspileSignals: new Map() + }; + } + + const { performance } = this._tool.ts; + // Reset the performance counters to 0 to avoid contamination from previous runs + performance.disable(); + performance.enable(); + + if (onChangeDetected !== undefined) { + await this._runWatchAsync(this._tool); + } else if (this._useSolutionBuilder) { + await this._runSolutionBuildAsync(this._tool); + } else { + await this._runBuildAsync(this._tool); + } + } + + public async _runWatchAsync(tool: ITypeScriptTool): Promise { + const { + ts, + measureSync: measureTsPerformance, + pendingOperations, + rawDiagnostics, + pendingTranspilePromises + } = tool; + + if (!tool.solutionBuilder && !tool.watchProgram) { + //#region CONFIGURE + const { duration: configureDurationMs, tsconfig } = measureTsPerformance('Configure', () => { + const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ + tool, + tsconfigPath: this._configuration.tsconfigPath, + tsCacheFilePath: this._tsCacheFilePath + }); + this._validateTsconfig(ts, _tsconfig); + + return { + tsconfig: _tsconfig + }; + }); + this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + //#endregion + + if (this._useSolutionBuilder) { + const solutionHost: TWatchSolutionHost = this._buildWatchSolutionBuilderHost(tool); + const builder: TTypescript.SolutionBuilder = + ts.createSolutionBuilderWithWatch(solutionHost, [this._configuration.tsconfigPath], {}); + + tool.solutionBuilder = builder as IExtendedSolutionBuilder; + + builder.build(); + } else { + const compilerHost: TWatchCompilerHost = this._buildWatchCompilerHost(tool, tsconfig); + tool.watchProgram = ts.createWatchProgram(compilerHost); + } + } + + if (pendingOperations.size > 0) { + rawDiagnostics.length = 0; + tool.executing = true; + for (const operation of pendingOperations) { + pendingOperations.delete(operation); + operation(); + } + if (pendingTranspilePromises.size) { + const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); + for (const { diagnostics } of emitResults) { + for (const diagnostic of diagnostics) { + rawDiagnostics.push(diagnostic); + } + } + } + // eslint-disable-next-line require-atomic-updates + tool.executing = false; + } + this._logDiagnostics(ts, rawDiagnostics, this._useSolutionBuilder); + } + + public async _runBuildAsync(tool: ITypeScriptTool): Promise { + const { ts, measureSync: measureTsPerformance, pendingTranspilePromises } = tool; + + //#region CONFIGURE + const { + duration: configureDurationMs, + tsconfig, + compilerHost + } = measureTsPerformance('Configure', () => { + 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); + + return { + tsconfig: _tsconfig, + compilerHost: _compilerHost + }; + }); + this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + //#endregion + + //#region PROGRAM + // There will be only one program here; emit will get a bit abused if we produce multiple outputs + let builderProgram: TTypescript.BuilderProgram | undefined = undefined; + let innerProgram: TTypescript.Program; + + const isolatedModules: boolean = + !!this._configuration.useTranspilerWorker && !!tsconfig.options.isolatedModules; + const mode: 'both' | 'declaration' = isolatedModules ? 'declaration' : 'both'; + + let filesToTranspile: Map | undefined; + + if (tsconfig.options.incremental) { + // Use ts.createEmitAndSemanticDiagnositcsBuilderProgram directly because the customizations performed by + // _getCreateBuilderProgram duplicate those performed in this function for non-incremental build. + const oldProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram | undefined = + ts.readBuilderProgram(tsconfig.options, compilerHost); + builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram( + tsconfig.fileNames, + tsconfig.options, + compilerHost, + oldProgram, + ts.getConfigFileParsingDiagnostics(tsconfig), + tsconfig.projectReferences + ); + filesToTranspile = getFilesToTranspileFromBuilderProgram(builderProgram); + innerProgram = builderProgram.getProgram(); + } else { + innerProgram = ts.createProgram({ + rootNames: tsconfig.fileNames, + options: tsconfig.options, + projectReferences: tsconfig.projectReferences, + host: compilerHost, + oldProgram: undefined, + configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(tsconfig) + }); + filesToTranspile = getFilesToTranspileFromProgram(innerProgram); + } + + // Prefer the builder program, since it is what gives us incremental builds + const genericProgram: TTypescript.BuilderProgram | TTypescript.Program = builderProgram || innerProgram; + + this._logReadPerformance(ts); + //#endregion + + if (isolatedModules) { + // Kick the transpilation worker. + this._queueTranspileInWorker(tool, genericProgram.getCompilerOptions(), filesToTranspile); + } + + //#region ANALYSIS + const { duration: diagnosticsDurationMs, diagnostics: preDiagnostics } = measureTsPerformance( + 'Analyze', + () => { + const rawDiagnostics: TTypescript.Diagnostic[] = [ + ...genericProgram.getConfigFileParsingDiagnostics(), + ...genericProgram.getOptionsDiagnostics(), + ...genericProgram.getSyntacticDiagnostics(), + ...genericProgram.getGlobalDiagnostics(), + ...genericProgram.getSemanticDiagnostics() + ]; + return { diagnostics: rawDiagnostics }; + } + ); + this._typescriptTerminal.writeVerboseLine(`Analyze: ${diagnosticsDurationMs}ms`); + //#endregion + + //#region EMIT + const { changedFiles } = configureProgramForMultiEmit(innerProgram, ts, this._moduleKindsToEmit, mode); + + const emitResult: TTypescript.EmitResult = genericProgram.emit( + undefined, + // The writeFile callback must be provided for the multi-emit redirector + ts.sys.writeFile, + undefined, + undefined, + undefined + ); + + this._cleanupWorker(); + //#endregion + + this._logEmitPerformance(ts); + + //#region FINAL_ANALYSIS + // Need to ensure that we include emit diagnostics, since they might not be part of the other sets + const rawDiagnostics: TTypescript.Diagnostic[] = [...preDiagnostics, ...emitResult.diagnostics]; + //#endregion + + this._configuration.emitChangedFilesCallback(innerProgram, changedFiles); + + if (pendingTranspilePromises.size) { + const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); + for (const { diagnostics } of emitResults) { + for (const diagnostic of diagnostics) { + rawDiagnostics.push(diagnostic); + } + } + } + + this._logDiagnostics(ts, rawDiagnostics); + // Reset performance counters in case any are used in the callback + ts.performance.disable(); + ts.performance.enable(); + } + + public async _runSolutionBuildAsync(tool: ITypeScriptTool): Promise { + this._typescriptTerminal.writeVerboseLine(`Using solution mode`); + + const { ts, measureSync, rawDiagnostics, pendingTranspilePromises } = tool; + rawDiagnostics.length = 0; + + if (!tool.solutionBuilder) { + //#region CONFIGURE + const { duration: configureDurationMs, solutionBuilderHost } = measureSync('Configure', () => { + const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ + tool, + tsconfigPath: this._configuration.tsconfigPath, + tsCacheFilePath: this._tsCacheFilePath + }); + this._validateTsconfig(ts, _tsconfig); + + const _solutionBuilderHost: TSolutionHost = this._buildSolutionBuilderHost(tool); + + return { + solutionBuilderHost: _solutionBuilderHost + }; + }); + this._typescriptTerminal.writeVerboseLine(`Configure: ${configureDurationMs}ms`); + //#endregion + + tool.solutionBuilder = ts.createSolutionBuilder( + solutionBuilderHost, + [this._configuration.tsconfigPath], + {} + ) as IExtendedSolutionBuilder; + } else { + // Force reload everything from disk + for (const project of tool.solutionBuilder.getBuildOrder()) { + tool.solutionBuilder.invalidateProject(project, 1); + } + } + + //#region EMIT + // Ignoring the exit status because we only care about presence of diagnostics + tool.solutionBuilder.build(); + this._cleanupWorker(); + //#endregion + + if (pendingTranspilePromises.size) { + const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); + for (const { diagnostics } of emitResults) { + for (const diagnostic of diagnostics) { + rawDiagnostics.push(diagnostic); + } + } + } + + this._logDiagnostics(ts, rawDiagnostics, true); + } + + private _logDiagnostics( + ts: ExtendedTypeScript, + rawDiagnostics: TTypescript.Diagnostic[], + isSolutionMode?: boolean + ): void { + const diagnostics: readonly TTypescript.Diagnostic[] = ts.sortAndDeduplicateDiagnostics(rawDiagnostics); + + if (diagnostics.length > 0) { + let warningCount: number = 0; + let hasError: boolean = false; + + this._typescriptTerminal.writeLine( + `Encountered ${diagnostics.length} TypeScript issue${diagnostics.length > 1 ? 's' : ''}:` + ); + for (const diagnostic of diagnostics) { + const diagnosticCategory: TTypescript.DiagnosticCategory = this._getAdjustedDiagnosticCategory( + diagnostic, + ts + ); + + if (diagnosticCategory === ts.DiagnosticCategory.Warning) { + warningCount++; + } else if (diagnosticCategory === ts.DiagnosticCategory.Error) { + hasError = true; + } + + this._printDiagnosticMessage(ts, diagnostic, diagnosticCategory); + } + + if (isSolutionMode && warningCount > 0 && !hasError) { + this._typescriptLogger.emitError( + new Error( + `TypeScript encountered ${warningCount} warning${warningCount === 1 ? '' : 's'} ` + + `and is configured to build project references. As a result, no files were emitted. Please fix the reported warnings to proceed.` + ) + ); + } + } + } + + private _logEmitPerformance(ts: ExtendedTypeScript): void { + this._typescriptTerminal.writeVerboseLine(`Bind: ${ts.performance.getDuration('Bind')}ms`); + this._typescriptTerminal.writeVerboseLine(`Check: ${ts.performance.getDuration('Check')}ms`); + this._typescriptTerminal.writeVerboseLine( + `Transform: ${ts.performance.getDuration('transformTime')}ms ` + + `(${ts.performance.getCount('beforeTransform')} files)` + ); + this._typescriptTerminal.writeVerboseLine( + `Print: ${ts.performance.getDuration('printTime')}ms ` + + `(${ts.performance.getCount('beforePrint')} files) (Includes Transform)` + ); + this._typescriptTerminal.writeVerboseLine( + `Emit: ${ts.performance.getDuration('Emit')}ms (Includes Print)` + ); + this._typescriptTerminal.writeVerboseLine( + `I/O Write: ${ts.performance.getDuration('I/O Write')}ms (${ts.performance.getCount( + 'beforeIOWrite' + )} files)` + ); + } + + private _logReadPerformance(ts: ExtendedTypeScript): void { + this._typescriptTerminal.writeVerboseLine( + `I/O Read: ${ts.performance.getDuration('I/O Read')}ms (${ts.performance.getCount( + 'beforeIORead' + )} files)` + ); + this._typescriptTerminal.writeVerboseLine( + `Parse: ${ts.performance.getDuration('Parse')}ms (${ts.performance.getCount('beforeParse')} files)` + ); + this._typescriptTerminal.writeVerboseLine( + `Program (includes Read + Parse): ${ts.performance.getDuration('Program')}ms` + ); + } + + private _printDiagnosticMessage( + ts: ExtendedTypeScript, + diagnostic: TTypescript.Diagnostic, + diagnosticCategory: TTypescript.DiagnosticCategory = this._getAdjustedDiagnosticCategory(diagnostic, ts) + ): void { + // Code taken from reference example + let diagnosticMessage: string; + let errorObject: Error; + if (diagnostic.file) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); + const message: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + const formattedMessage: string = `(TS${diagnostic.code}) ${message}`; + errorObject = new FileError(formattedMessage, { + absolutePath: diagnostic.file.fileName, + projectFolder: this._configuration.buildFolderPath, + line: line + 1, + column: character + 1 + }); + diagnosticMessage = errorObject.toString(); + } else { + diagnosticMessage = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + errorObject = new Error(diagnosticMessage); + } + + switch (diagnosticCategory) { + case ts.DiagnosticCategory.Error: { + this._typescriptLogger.emitError(errorObject); + break; + } + + case ts.DiagnosticCategory.Warning: { + this._typescriptLogger.emitWarning(errorObject); + break; + } + + default: { + this._typescriptTerminal.writeLine(...diagnosticMessage); + break; + } + } + } + + private _getAdjustedDiagnosticCategory( + diagnostic: TTypescript.Diagnostic, + ts: ExtendedTypeScript + ): TTypescript.DiagnosticCategory { + // Workaround for https://github.com/microsoft/TypeScript/issues/40058 + // The compiler reports a hard error for issues such as this: + // + // error TS6133: 'x' is declared but its value is never read. + // + // These should properly be treated as warnings, because they are purely cosmetic issues. + // TODO: Maybe heft should provide a config file for managing DiagnosticCategory mappings. + if (diagnostic.reportsUnnecessary && diagnostic.category === ts.DiagnosticCategory.Error) { + return ts.DiagnosticCategory.Warning; + } + + // These pedantic checks also should not be treated as hard errors + if (this._suppressedDiagnosticCodes.has(diagnostic.code)) { + return ts.DiagnosticCategory.Warning; + } + + return diagnostic.category; + } + + private _validateTsconfig(ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine): void { + if ( + (tsconfig.options.module && !tsconfig.options.outDir) || + (!tsconfig.options.module && tsconfig.options.outDir) + ) { + throw new Error( + 'If either the module or the outDir option is provided in the tsconfig compilerOptions, both must be provided' + ); + } + + this._moduleKindsToEmit = []; + const specifiedKinds: Map = new Map(); + const specifiedOutDirs: Map = new Map(); + + if (!tsconfig.options.module) { + throw new Error( + 'If the module tsconfig compilerOption is not provided, the builder must be provided with the ' + + 'additionalModuleKindsToEmit configuration option.' + ); + } + + if (this._configuration.emitCjsExtensionForCommonJS) { + this._addModuleKindToEmit( + ts.ModuleKind.CommonJS, + tsconfig.options.outDir!, + /* isPrimary */ tsconfig.options.module === ts.ModuleKind.CommonJS, + '.cjs' + ); + + const cjsReason: IModuleKindReason = { + outDir: tsconfig.options.outDir!, + kind: 'CommonJS', + extension: '.cjs', + reason: 'emitCjsExtensionForCommonJS' + }; + + specifiedKinds.set(ts.ModuleKind.CommonJS, cjsReason); + specifiedOutDirs.set(`${tsconfig.options.outDir!}:.cjs`, cjsReason); + } + + if (this._configuration.emitMjsExtensionForESModule) { + this._addModuleKindToEmit( + ts.ModuleKind.ESNext, + tsconfig.options.outDir!, + /* isPrimary */ tsconfig.options.module === ts.ModuleKind.ESNext, + '.mjs' + ); + + const mjsReason: IModuleKindReason = { + outDir: tsconfig.options.outDir!, + kind: 'ESNext', + extension: '.mjs', + reason: 'emitMjsExtensionForESModule' + }; + + specifiedKinds.set(ts.ModuleKind.ESNext, mjsReason); + specifiedOutDirs.set(`${tsconfig.options.outDir!}:.mjs`, mjsReason); + } + + if (!specifiedKinds.has(tsconfig.options.module)) { + this._addModuleKindToEmit( + tsconfig.options.module, + tsconfig.options.outDir!, + /* isPrimary */ true, + /* jsExtensionOverride */ undefined + ); + + const tsConfigReason: IModuleKindReason = { + outDir: tsconfig.options.outDir!, + kind: ts.ModuleKind[tsconfig.options.module] as keyof typeof TTypescript.ModuleKind, + extension: '.js', + reason: 'tsconfig.json' + }; + + specifiedKinds.set(tsconfig.options.module, tsConfigReason); + specifiedOutDirs.set(`${tsconfig.options.outDir!}:.js`, tsConfigReason); + } + + if (this._configuration.additionalModuleKindsToEmit) { + for (const additionalModuleKindToEmit of this._configuration.additionalModuleKindsToEmit) { + const moduleKind: TTypescript.ModuleKind = this._parseModuleKind( + ts, + additionalModuleKindToEmit.moduleKind + ); + + const outDirKey: string = `${additionalModuleKindToEmit.outFolderName}:.js`; + const moduleKindReason: IModuleKindReason = { + kind: ts.ModuleKind[moduleKind] as keyof typeof TTypescript.ModuleKind, + outDir: additionalModuleKindToEmit.outFolderName, + extension: '.js', + reason: `additionalModuleKindsToEmit` + }; + + const existingKind: IModuleKindReason | undefined = specifiedKinds.get(moduleKind); + const existingDir: IModuleKindReason | undefined = specifiedOutDirs.get(outDirKey); + + if (existingKind) { + throw new Error( + `Module kind "${additionalModuleKindToEmit.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}.` + ); + } else { + const outFolderKey: string | undefined = this._addModuleKindToEmit( + moduleKind, + additionalModuleKindToEmit.outFolderName, + /* isPrimary */ false, + undefined + ); + + if (outFolderKey) { + specifiedKinds.set(moduleKind, moduleKindReason); + specifiedOutDirs.set(outFolderKey, moduleKindReason); + } + } + } + } + } + + private _addModuleKindToEmit( + moduleKind: TTypescript.ModuleKind, + outFolderPath: string, + isPrimary: boolean, + jsExtensionOverride: string | undefined + ): string | undefined { + let outFolderName: string; + if (path.isAbsolute(outFolderPath)) { + outFolderName = path.relative(this._configuration.buildFolderPath, outFolderPath); + } else { + outFolderName = outFolderPath; + outFolderPath = path.resolve(this._configuration.buildFolderPath, outFolderPath); + } + + outFolderPath = Path.convertToSlashes(outFolderPath); + outFolderPath = outFolderPath.replace(/\/*$/, '/'); // Ensure the outFolderPath ends with a slash + + for (const existingModuleKindToEmit of this._moduleKindsToEmit) { + let errorText: string | undefined; + + if (existingModuleKindToEmit.outFolderPath === outFolderPath) { + if (existingModuleKindToEmit.jsExtensionOverride === jsExtensionOverride) { + errorText = + 'Unable to output two different module kinds with the same ' + + `module extension (${jsExtensionOverride || '.js'}) to the same ` + + `folder ("${outFolderPath}").`; + } + } else { + let parentFolder: string | undefined; + let childFolder: string | undefined; + if (outFolderPath.startsWith(existingModuleKindToEmit.outFolderPath)) { + parentFolder = outFolderPath; + childFolder = existingModuleKindToEmit.outFolderPath; + } else if (existingModuleKindToEmit.outFolderPath.startsWith(outFolderPath)) { + parentFolder = existingModuleKindToEmit.outFolderPath; + childFolder = outFolderPath; + } + + if (parentFolder) { + errorText = + 'Unable to output two different module kinds to nested folders ' + + `("${parentFolder}" and "${childFolder}").`; + } + } + + if (errorText) { + this._typescriptLogger.emitError(new Error(errorText)); + return undefined; + } + } + + this._moduleKindsToEmit.push({ + outFolderPath, + moduleKind, + jsExtensionOverride, + + isPrimary + }); + + return `${outFolderName}:${jsExtensionOverride || '.js'}`; + } + + private _getCreateBuilderProgram( + ts: ExtendedTypeScript + ): TTypescript.CreateProgram { + const { + _configuration: { emitChangedFilesCallback } + } = this; + + const createMultiEmitBuilderProgram: TTypescript.CreateProgram< + TTypescript.EmitAndSemanticDiagnosticsBuilderProgram + > = ( + fileNames: readonly string[] | undefined, + compilerOptions: TTypescript.CompilerOptions | undefined, + host: TTypescript.CompilerHost | undefined, + oldProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram | undefined, + configFileParsingDiagnostics: readonly TTypescript.Diagnostic[] | undefined, + projectReferences: readonly TTypescript.ProjectReference[] | undefined + ): TTypescript.EmitAndSemanticDiagnosticsBuilderProgram => { + // Reset performance counters + ts.performance.disable(); + ts.performance.enable(); + + this._typescriptTerminal.writeVerboseLine(`Reading program "${compilerOptions!.configFilePath}"`); + + const newProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram = + ts.createEmitAndSemanticDiagnosticsBuilderProgram( + fileNames, + compilerOptions, + host, + oldProgram, + configFileParsingDiagnostics, + projectReferences + ); + + this._logReadPerformance(ts); + + const isolatedModules: boolean = + !!this._configuration.useTranspilerWorker && !!compilerOptions!.isolatedModules; + const mode: 'both' | 'declaration' = isolatedModules ? 'declaration' : 'both'; + + if (isolatedModules) { + // Kick the transpilation worker. + const filesToTranspile: Map = getFilesToTranspileFromBuilderProgram(newProgram); + this._queueTranspileInWorker(this._tool!, compilerOptions!, filesToTranspile); + } + + const { emit: originalEmit } = newProgram; + + const emit: TTypescript.Program['emit'] = ( + outerTargetSourceFile?: TTypescript.SourceFile, + outerWriteFile?: TTypescript.WriteFileCallback, + outerCancellationToken?: TTypescript.CancellationToken, + outerEmitOnlyDtsFiles?: boolean, + outerCustomTransformers?: TTypescript.CustomTransformers + ) => { + const innerProgram: TTypescript.Program = newProgram.getProgram(); + + const innerCompilerOptions: TTypescript.CompilerOptions = innerProgram.getCompilerOptions(); + + const { changedFiles } = configureProgramForMultiEmit( + innerProgram, + ts, + this._moduleKindsToEmit, + mode + ); + + const result: TTypescript.EmitResult = originalEmit.call( + newProgram, + outerTargetSourceFile, + outerWriteFile, + outerCancellationToken, + outerEmitOnlyDtsFiles, + outerCustomTransformers + ); + + (result as IExtendedEmitResult).changedSourceFiles = changedFiles; + + this._typescriptTerminal.writeVerboseLine( + `Emitting program "${innerCompilerOptions!.configFilePath}"` + ); + + this._logEmitPerformance(ts); + + // Reset performance counters + ts.performance.disable(); + ts.performance.enable(); + + emitChangedFilesCallback(innerProgram, changedFiles); + + return result; + }; + + newProgram.emit = emit; + + return newProgram; + }; + + return createMultiEmitBuilderProgram; + } + + private _buildSolutionBuilderHost(tool: ITypeScriptTool): TSolutionHost { + const reportSolutionBuilderStatus: TTypescript.DiagnosticReporter = tool.reportDiagnostic; + const reportEmitErrorSummary: TTypescript.ReportEmitErrorSummary = (errorCount: number): void => { + // Do nothing + }; + + const { ts, system } = tool; + + const solutionBuilderHost: TTypescript.SolutionBuilderHost = + ts.createSolutionBuilderHost( + system, + this._getCreateBuilderProgram(ts), + tool.reportDiagnostic, + reportSolutionBuilderStatus, + reportEmitErrorSummary + ); + + solutionBuilderHost.afterProgramEmitAndDiagnostics = ( + program: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram + ) => { + // Use the native metric since we aren't overwriting the writer + this._typescriptTerminal.writeVerboseLine( + `I/O Write: ${ts.performance.getDuration('I/O Write')}ms (${ts.performance.getCount( + 'beforeIOWrite' + )} files)` + ); + }; + + return solutionBuilderHost; + } + + private _buildIncrementalCompilerHost( + tool: ITypeScriptTool, + tsconfig: TTypescript.ParsedCommandLine + ): TTypescript.CompilerHost { + const { ts, system } = tool; + + let compilerHost: TTypescript.CompilerHost | undefined; + + if (tsconfig.options.incremental) { + compilerHost = ts.createIncrementalCompilerHost(tsconfig.options, system); + } else { + compilerHost = (ts.createCompilerHostWorker ?? ts.createCompilerHost)( + tsconfig.options, + undefined, + system + ); + } + + this._changeCompilerHostToUseCache(compilerHost, tool); + + return compilerHost; + } + + private _buildWatchCompilerHost( + tool: ITypeScriptTool, + tsconfig: TTypescript.ParsedCommandLine + ): TWatchCompilerHost { + const { ts, system } = tool; + + const reportWatchStatus: TTypescript.DiagnosticReporter = (diagnostic: TTypescript.Diagnostic): void => { + this._printDiagnosticMessage(ts, diagnostic); + }; + + const compilerHost: TWatchCompilerHost = ts.createWatchCompilerHost( + tsconfig.fileNames, + tsconfig.options, + system, + this._getCreateBuilderProgram(ts), + tool.reportDiagnostic, + reportWatchStatus, + tsconfig.projectReferences, + tsconfig.watchOptions + ); + + return compilerHost; + } + + private _changeCompilerHostToUseCache(compilerHost: TTypescript.CompilerHost, tool: ITypeScriptTool): void { + const { sourceFileCache } = tool; + + const { getSourceFile: innerGetSourceFile } = compilerHost; + if ((innerGetSourceFile as { cache?: typeof sourceFileCache }).cache === sourceFileCache) { + return; + } + + compilerHost.getCurrentDirectory = () => this._configuration.buildFolderPath; + + // Enable source file persistence + const getSourceFile: typeof innerGetSourceFile & { + cache?: typeof sourceFileCache; + } = ( + fileName: string, + languageVersionOrOptions: TTypescript.ScriptTarget | TTypescript.CreateSourceFileOptions, + onError?: ((message: string) => void) | undefined, + shouldCreateNewSourceFile?: boolean | undefined + ): TTypescript.SourceFile | undefined => { + if (!shouldCreateNewSourceFile) { + const cachedSourceFile: TTypescript.SourceFile | undefined = sourceFileCache.get(fileName); + if (cachedSourceFile) { + return cachedSourceFile; + } + } + + const result: TTypescript.SourceFile | undefined = innerGetSourceFile( + fileName, + languageVersionOrOptions, + onError, + shouldCreateNewSourceFile + ); + if (result) { + sourceFileCache.set(fileName, result); + } else { + sourceFileCache.delete(fileName); + } + return result; + }; + + getSourceFile.cache = sourceFileCache; + + compilerHost.getSourceFile = getSourceFile; + } + + private _buildWatchSolutionBuilderHost(tool: ITypeScriptTool): TWatchSolutionHost { + const { reportDiagnostic, ts, system } = tool; + + const host: TWatchSolutionHost = ts.createSolutionBuilderWithWatchHost( + system, + this._getCreateBuilderProgram(ts), + reportDiagnostic, + reportDiagnostic, + reportDiagnostic + ); + + return host; + } + + private _parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind { + switch (moduleKindName.toLowerCase()) { + case 'commonjs': + return ts.ModuleKind.CommonJS; + + case 'amd': + return ts.ModuleKind.AMD; + + case 'umd': + return ts.ModuleKind.UMD; + + case 'system': + return ts.ModuleKind.System; + + case 'es2015': + return ts.ModuleKind.ES2015; + + case 'esnext': + return ts.ModuleKind.ESNext; + + default: + throw new Error(`"${moduleKindName}" is not a valid module kind name.`); + } + } + + private _queueTranspileInWorker( + tool: ITypeScriptTool, + compilerOptions: TTypescript.CompilerOptions, + filesToTranspile: Map + ): void { + const { typeScriptToolPath, pendingTranspilePromises, pendingTranspileSignals } = tool; + let maybeWorker: Worker | undefined = tool.worker; + if (!maybeWorker) { + const workerData: ITypescriptWorkerData = { + typeScriptToolPath + }; + tool.worker = maybeWorker = new Worker(require.resolve('./TranspilerWorker.js'), { + workerData: workerData + }); + + maybeWorker.on('message', (response: ITranspilationResponseMessage) => { + const { requestId: resolvingRequestId, type, result } = response; + const signal: ITranspileSignal | undefined = pendingTranspileSignals.get(resolvingRequestId); + + if (type === 'error') { + const error: Error = Object.assign(new Error(result.message), result); + if (signal) { + signal.reject(error); + } else { + this._typescriptTerminal.writeErrorLine( + `Unexpected worker rejection for request with id ${resolvingRequestId}: ${error}` + ); + } + } else if (signal) { + signal.resolve(result); + } else { + this._typescriptTerminal.writeErrorLine( + `Unexpected worker resolution for request with id ${resolvingRequestId}` + ); + } + + pendingTranspileSignals.delete(resolvingRequestId); + pendingTranspilePromises.delete(resolvingRequestId); + }); + + maybeWorker.once('exit', (exitCode: number) => { + if (pendingTranspileSignals.size) { + const error: Error = new Error(`Worker exited unexpectedly with code ${exitCode}.`); + for (const { reject: rejectTranspile } of pendingTranspileSignals.values()) { + rejectTranspile(error); + } + pendingTranspileSignals.clear(); + } + }); + + maybeWorker.once('error', (err: Error) => { + for (const { reject: rejectTranspile } of pendingTranspileSignals.values()) { + rejectTranspile(err); + } + pendingTranspileSignals.clear(); + }); + } + + // make linter happy + const worker: Worker = maybeWorker; + + const requestId: number = ++this._nextRequestId; + const transpilePromise: Promise = new Promise( + (resolve: (result: TTypescript.EmitResult) => void, reject: (err: Error) => void) => { + pendingTranspileSignals.set(requestId, { resolve, reject }); + + this._typescriptTerminal.writeLine(`Asynchronously transpiling ${compilerOptions.configFilePath}`); + const request: ITranspilationRequestMessage = { + compilerOptions, + filesToTranspile, + moduleKindsToEmit: this._moduleKindsToEmit, + requestId + }; + + worker.postMessage(request); + } + ); + + pendingTranspilePromises.set(requestId, transpilePromise); + } + + private _cleanupWorker(): void { + const tool: ITypeScriptTool | undefined = this._tool; + if (!tool) { + return; + } + + const { worker } = tool; + if (worker) { + worker.postMessage(false); + tool.worker = undefined; + } + } +} + +function getFilesToTranspileFromBuilderProgram( + builderProgram: TTypescript.BuilderProgram +): Map { + const program: ExtendedBuilderProgram = builderProgram as unknown as ExtendedBuilderProgram; + // getState was removed in Typescript 5.6, replaced with state + const changedFilesSet: Set = (program.state ?? program.getState()).changedFilesSet; + + const filesToTranspile: Map = new Map(); + for (const fileName of changedFilesSet) { + const sourceFile: TTypescript.SourceFile | undefined = builderProgram.getSourceFile(fileName); + if (sourceFile && !sourceFile.isDeclarationFile) { + filesToTranspile.set(sourceFile.fileName, sourceFile.text); + } + } + return filesToTranspile; +} + +function getFilesToTranspileFromProgram(program: TTypescript.Program): Map { + const filesToTranspile: Map = new Map(); + for (const sourceFile of program.getSourceFiles()) { + if (!sourceFile.isDeclarationFile) { + filesToTranspile.set(sourceFile.fileName, sourceFile.text); + } + } + return filesToTranspile; +} diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts new file mode 100644 index 00000000000..cd47dfc1b89 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts @@ -0,0 +1,413 @@ +// 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 TTypescript from 'typescript'; +import { SyncHook } from 'tapable'; + +import { FileSystem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { ProjectConfigurationFile, InheritanceType, PathResolutionMethod } from '@rushstack/heft-config-file'; +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions, + ICopyOperation, + 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 + * + * @public + */ +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 + */ +export interface IEmitModuleKind { + moduleKind: 'commonjs' | 'amd' | 'umd' | 'system' | 'es2015' | 'esnext'; + outFolderName: string; + jsExtensionOverride?: string; +} + +/** + * @beta + */ +export interface IStaticAssetsCopyConfiguration { + fileExtensions: string[]; + excludeGlobs: string[]; + includeGlobs: string[]; +} + +/** + * @beta + */ +export interface ITypeScriptConfigurationJson { + /** + * 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?: IEmitModuleKind[] | undefined; + + /** + * If 'true', emit CommonJS output into the TSConfig outDir with the file extension '.cjs' + */ + emitCjsExtensionForCommonJS?: boolean | undefined; + + /** + * If 'true', emit ESModule output into the TSConfig outDir with the file extension '.mjs' + */ + emitMjsExtensionForESModule?: boolean | undefined; + + /** + * If true, enable behavior analogous to the "tsc --build" command. Will build projects referenced by the main project in dependency order. + * Note that this will effectively enable \"noEmitOnError\". + */ + buildProjectReferences?: boolean; + + /** + * If true, and the tsconfig has \"isolatedModules\": true, then transpilation will happen in parallel in a worker thread. + */ + useTranspilerWorker?: boolean; + + /** + * If true, the TypeScript compiler will only resolve symlinks to their targets if the links are in a node_modules folder. + * This significantly reduces file system operations in typical usage. + */ + onlyResolveSymlinksInNodeModules?: boolean; + + /* + * Specifies the tsconfig.json file that will be used for compilation. Equivalent to the "project" argument for the 'tsc' and 'tslint' command line tools. + * + * The default value is "./tsconfig.json" + */ + project?: string; + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + staticAssetsToCopy?: IStaticAssetsCopyConfiguration; +} + +/** + * @beta + */ +export interface IPartialTsconfigCompilerOptions { + outDir?: string; +} + +/** + * @beta + */ +export interface IPartialTsconfig { + compilerOptions?: IPartialTsconfigCompilerOptions; +} + +/** + * @beta + */ +export interface IChangedFilesHookOptions { + program: TTypescript.Program; + changedFiles?: ReadonlySet; +} + +/** + * @beta + */ +export interface ITypeScriptPluginAccessor { + readonly onChangedFilesHook: SyncHook; +} + +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 + */ +export async function loadTypeScriptConfigurationFileAsync( + heftConfiguration: HeftConfiguration, + terminal: ITerminal +): Promise { + return await heftConfiguration.tryLoadProjectConfigurationFileAsync( + TYPESCRIPT_LOADER_CONFIG, + terminal + ); +} + +let _partialTsconfigFileLoader: ProjectConfigurationFile | undefined; +const _partialTsconfigFilePromiseCache: Map> = new Map(); + +/** + * @beta + */ +export async function loadPartialTsconfigFileAsync( + heftConfiguration: HeftConfiguration, + terminal: ITerminal, + typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined +): Promise { + const buildFolderPath: string = heftConfiguration.buildFolderPath; + + // Check the cache first + let partialTsconfigFilePromise: Promise | undefined = + _partialTsconfigFilePromiseCache.get(buildFolderPath); + + if (!partialTsconfigFilePromise) { + // We don't want to load the tsconfig.json file through the rig, but we do want to take + // 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?.project + ); + terminal.writeVerboseLine(`Looking for tsconfig at ${tsconfigFilePath}`); + const tsconfigExists: boolean = await FileSystem.existsAsync(tsconfigFilePath); + if (!tsconfigExists) { + partialTsconfigFilePromise = Promise.resolve(undefined); + } else { + // Ensure that the file loader has been initialized. + if (!_partialTsconfigFileLoader) { + _partialTsconfigFileLoader = new ProjectConfigurationFile({ + projectRelativeFilePath: typeScriptConfigurationJson?.project || 'tsconfig.json', + jsonSchemaObject: anythingSchema, + propertyInheritance: { + compilerOptions: { + inheritanceType: InheritanceType.merge + } + }, + jsonPathMetadata: { + '$.compilerOptions.outDir': { + 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); + } + } + } + } + }); + } + + partialTsconfigFilePromise = _partialTsconfigFileLoader.loadConfigurationFileForProjectAsync( + terminal, + buildFolderPath, + heftConfiguration.rigConfig + ); + } + _partialTsconfigFilePromiseCache.set(buildFolderPath, partialTsconfigFilePromise); + } + + return await partialTsconfigFilePromise; +} + +interface ITypeScriptConfigurationJsonAndPartialTsconfigFile { + typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined; + partialTsconfigFile: IPartialTsconfig | undefined; +} + +export default class TypeScriptPlugin implements IHeftTaskPlugin { + public accessor: ITypeScriptPluginAccessor = { + onChangedFilesHook: new SyncHook(['changedFilesHookOptions']) + }; + + public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + taskSession.hooks.registerFileOperations.tapPromise( + PLUGIN_NAME, + async (fileOperations: IHeftTaskFileOperations): Promise => { + // TODO: We should consider maybe only doing one copy of static assets and pointing + // all source files to this set of static assets. This would allow us to avoid + // having to copy the static assets multiple times, increasing build times and + // package size. + for (const copyOperation of await this._getStaticAssetCopyOperationsAsync( + taskSession, + heftConfiguration + )) { + fileOperations.copyOperations.add(copyOperation); + } + + return fileOperations; + } + ); + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const builder: TypeScriptBuilder | false = await this._getTypeScriptBuilderAsync( + taskSession, + heftConfiguration + ); + if (builder) { + await builder.invokeAsync(); + } + }); + + let incrementalBuilder: TypeScriptBuilder | undefined | false; + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { + if (incrementalBuilder === undefined) { + // eslint-disable-next-line require-atomic-updates + incrementalBuilder = await this._getTypeScriptBuilderAsync(taskSession, heftConfiguration); + } + + if (incrementalBuilder) { + await incrementalBuilder.invokeAsync(runIncrementalOptions.requestRun); + } + } + ); + } + + private async _getStaticAssetCopyOperationsAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + 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 ( + 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 = partialTsconfigFile?.compilerOptions?.outDir; + if (tsconfigOutDir) { + destinationFolderPaths.add(tsconfigOutDir); + } + + for (const emitModule of typeScriptConfigurationJson?.additionalModuleKindsToEmit || []) { + destinationFolderPaths.add(emitModule.outFolderName); + } + + copyOperations.push({ + ...staticAssetsConfig, + + // For now - these may need to be revised later + sourcePath: path.resolve(heftConfiguration.buildFolderPath, 'src'), + destinationFolders: Array.from(destinationFolderPaths), + flatten: false, + hardlink: false + }); + } + + return copyOperations; + } + + private async _getTypeScriptBuilderAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + const { typeScriptConfigurationJson, partialTsconfigFile } = await this._loadConfigAsync( + taskSession, + heftConfiguration + ); + + if (!partialTsconfigFile) { + // There is no tsconfig file, we can exit early + // This check may need watch mode to break on tsconfig addition/deletion + return false; + } + + // 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, + heftConfiguration, + + buildProjectReferences: typeScriptConfigurationJson?.buildProjectReferences, + + useTranspilerWorker: typeScriptConfigurationJson?.useTranspilerWorker, + + onlyResolveSymlinksInNodeModules: typeScriptConfigurationJson?.onlyResolveSymlinksInNodeModules, + + tsconfigPath: getTsconfigFilePath(heftConfiguration, typeScriptConfigurationJson?.project), + additionalModuleKindsToEmit: typeScriptConfigurationJson?.additionalModuleKindsToEmit, + emitCjsExtensionForCommonJS: !!typeScriptConfigurationJson?.emitCjsExtensionForCommonJS, + emitMjsExtensionForESModule: !!typeScriptConfigurationJson?.emitMjsExtensionForESModule, + scopedLogger: taskSession.logger, + emitChangedFilesCallback: ( + program: TTypescript.Program, + changedFiles?: Set + ) => { + // Provide the typescript program dependent plugins + if (this.accessor.onChangedFilesHook.isUsed()) { + this.accessor.onChangedFilesHook.call({ program, changedFiles }); + } + } + }; + + // Run the builder + const typeScriptBuilder: TypeScriptBuilder = new TypeScriptBuilder(typeScriptBuilderConfiguration); + return typeScriptBuilder; + } + + private async _loadConfigAsync( + 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 + ); + + return { + typeScriptConfigurationJson, + partialTsconfigFile + }; + } +} diff --git a/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts b/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts new file mode 100644 index 00000000000..a9fe703e7ec --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; +import type { ICachedEmitModuleKind } from './types'; + +// symbols for attaching hidden metadata to ts.Program instances. +const INNER_GET_COMPILER_OPTIONS_SYMBOL: unique symbol = Symbol('getCompilerOptions'); +const INNER_EMIT_SYMBOL: unique symbol = Symbol('emit'); + +const JS_EXTENSION_REGEX: RegExp = /\.js(\.map)?$/; + +function wrapWriteFile( + this: void, + baseWriteFile: TTypescript.WriteFileCallback, + jsExtensionOverride: string | undefined +): TTypescript.WriteFileCallback { + if (!jsExtensionOverride) { + return baseWriteFile; + } + + const replacementExtension: string = `${jsExtensionOverride}$1`; + return ( + fileName: string, + data: string, + writeBOM: boolean, + onError?: ((message: string) => void) | undefined, + sourceFiles?: readonly TTypescript.SourceFile[] | undefined + ) => { + return baseWriteFile( + fileName.replace(JS_EXTENSION_REGEX, replacementExtension), + data, + writeBOM, + onError, + sourceFiles + ); + }; +} + +export function configureProgramForMultiEmit( + this: void, + innerProgram: TTypescript.Program, + ts: ExtendedTypeScript, + moduleKindsToEmit: ICachedEmitModuleKind[], + mode: 'transpile' | 'declaration' | 'both' +): { changedFiles: Set } { + interface IProgramWithMultiEmit extends TTypescript.Program { + // Attach the originals to the Program instance to avoid modifying the same Program twice. + // Don't use WeakMap because this Program could theoretically get a { ... } applied to it. + [INNER_GET_COMPILER_OPTIONS_SYMBOL]?: TTypescript.Program['getCompilerOptions']; + [INNER_EMIT_SYMBOL]?: // https://github.com/microsoft/TypeScript/blob/88cb76d314a93937ce8d9543114ccbad993be6d1/src/compiler/program.ts#L2697-L2698 + // There is a "forceDtsEmit" parameter that is not on the published types. + (...args: [...Parameters, boolean | undefined]) => TTypescript.EmitResult; + } + + const program: IProgramWithMultiEmit = innerProgram; + + // Check to see if this Program has already been modified. + let { [INNER_EMIT_SYMBOL]: innerEmit, [INNER_GET_COMPILER_OPTIONS_SYMBOL]: innerGetCompilerOptions } = + program; + + if (!innerGetCompilerOptions) { + program[INNER_GET_COMPILER_OPTIONS_SYMBOL] = innerGetCompilerOptions = program.getCompilerOptions; + } + + if (!innerEmit) { + program[INNER_EMIT_SYMBOL] = innerEmit = program.emit; + } + + let foundPrimary: boolean = false; + let defaultModuleKind: TTypescript.ModuleKind; + + const multiEmitMap: Map = new Map(); + for (const moduleKindToEmit of moduleKindsToEmit) { + const kindCompilerOptions: TTypescript.CompilerOptions = moduleKindToEmit.isPrimary + ? { + ...innerGetCompilerOptions() + } + : { + ...innerGetCompilerOptions(), + module: moduleKindToEmit.moduleKind, + outDir: moduleKindToEmit.outFolderPath, + + // Don't emit declarations for secondary module kinds + declaration: false, + declarationMap: false + }; + if (!kindCompilerOptions.outDir) { + throw new InternalError('Expected compilerOptions.outDir to be assigned'); + } + if (mode === 'transpile') { + kindCompilerOptions.declaration = false; + kindCompilerOptions.declarationMap = false; + } else if (mode === 'declaration') { + kindCompilerOptions.emitDeclarationOnly = true; + } + + if (moduleKindToEmit.isPrimary || mode !== 'declaration') { + multiEmitMap.set(moduleKindToEmit, kindCompilerOptions); + } + + if (moduleKindToEmit.isPrimary) { + if (foundPrimary) { + throw new Error('Multiple primary module emit kinds encountered.'); + } else { + foundPrimary = true; + } + + defaultModuleKind = moduleKindToEmit.moduleKind; + } + } + + const changedFiles: Set = new Set(); + + program.emit = ( + targetSourceFile?: TTypescript.SourceFile, + writeFile?: TTypescript.WriteFileCallback, + cancellationToken?: TTypescript.CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: TTypescript.CustomTransformers, + forceDtsEmit?: boolean + ) => { + if (emitOnlyDtsFiles) { + return program[INNER_EMIT_SYMBOL]!( + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + forceDtsEmit + ); + } + + if (targetSourceFile && changedFiles) { + changedFiles.add(targetSourceFile); + } + + const originalCompilerOptions: TTypescript.CompilerOptions = + program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!(); + + let defaultModuleKindResult: TTypescript.EmitResult; + const diagnostics: TTypescript.Diagnostic[] = []; + let emitSkipped: boolean = false; + try { + for (const [moduleKindToEmit, kindCompilerOptions] of multiEmitMap) { + program.getCompilerOptions = () => kindCompilerOptions; + // Need to mutate the compiler options for the `module` field specifically, because emitWorker() captures + // options in the closure and passes it to `ts.getTransformers()` + originalCompilerOptions.module = moduleKindToEmit.moduleKind; + const flavorResult: TTypescript.EmitResult = program[INNER_EMIT_SYMBOL]!( + targetSourceFile, + writeFile && wrapWriteFile(writeFile, moduleKindToEmit.jsExtensionOverride), + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + forceDtsEmit + ); + + emitSkipped = emitSkipped || flavorResult.emitSkipped; + // Need to aggregate diagnostics because some are impacted by the target module type + for (const diagnostic of flavorResult.diagnostics) { + diagnostics.push(diagnostic); + } + + if (moduleKindToEmit.moduleKind === defaultModuleKind) { + defaultModuleKindResult = flavorResult; + } + } + + const mergedDiagnostics: readonly TTypescript.Diagnostic[] = + ts.sortAndDeduplicateDiagnostics(diagnostics); + + return { + ...defaultModuleKindResult!, + changedSourceFiles: changedFiles, + diagnostics: mergedDiagnostics, + emitSkipped + }; + } finally { + // Restore the original compiler options and module kind for future calls + program.getCompilerOptions = program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!; + originalCompilerOptions.module = defaultModuleKind; + } + }; + return { changedFiles }; +} diff --git a/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts b/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts new file mode 100644 index 00000000000..ca76573d285 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/fileSystem/TypeScriptCachedFileSystem.ts @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + Encoding, + Text, + type IFileSystemWriteFileOptions, + type IFileSystemReadFileOptions, + type IFileSystemCopyFileOptions, + type IFileSystemDeleteFileOptions, + type IFileSystemCreateLinkOptions, + FileSystem, + type FileSystemStats, + Sort, + type FolderItem +} from '@rushstack/node-core-library'; + +export interface IReadFolderFilesAndDirectoriesResult { + files: string[]; + directories: string[]; +} + +interface ICacheEntry { + entry: TEntry | undefined; + error?: NodeJS.ErrnoException; +} + +/** + * This is a FileSystem API (largely unrelated to the @rushstack/node-core-library FileSystem API) + * that provides caching to the Heft TypeScriptBuilder. + * It uses an in-memory cache to avoid requests against the disk. It assumes that the disk stays + * static after construction, except for writes performed through the TypeScriptCachedFileSystem + * instance. + */ +export class TypeScriptCachedFileSystem { + private _statsCache: Map> = new Map(); + private _readFolderCache: Map> = new Map(); + private _readFileCache: Map> = new Map(); + private _realPathCache: Map> = new Map(); + + public exists: (path: string) => boolean = (path: string) => { + try { + this.getStatistics(path); + return true; + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return false; + } else { + throw e; + } + } + }; + + public directoryExists: (path: string) => boolean = (path: string) => { + try { + const stats: FileSystemStats = this.getStatistics(path); + return stats.isDirectory(); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return false; + } else { + throw e; + } + } + }; + + public getStatistics: (path: string) => FileSystemStats = (path: string) => { + return this._withCaching(path, FileSystem.getStatistics, this._statsCache); + }; + + public ensureFolder: (folderPath: string) => void = (folderPath: string) => { + if (!this._readFolderCache.get(folderPath)?.entry && !this._statsCache.get(folderPath)?.entry) { + FileSystem.ensureFolder(folderPath); + this._invalidateCacheEntry(folderPath); + } + }; + + public ensureFolderAsync: (folderPath: string) => Promise = async (folderPath: string) => { + if (!this._readFolderCache.get(folderPath)?.entry && !this._statsCache.get(folderPath)?.entry) { + await FileSystem.ensureFolderAsync(folderPath); + this._invalidateCacheEntry(folderPath); + } + }; + + public writeFile: ( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions | undefined + ) => void = ( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions | undefined + ) => { + FileSystem.writeFile(filePath, contents, options); + this._invalidateCacheEntry(filePath); + }; + + public readFile: (filePath: string, options?: IFileSystemReadFileOptions | undefined) => string = ( + filePath: string, + options?: IFileSystemReadFileOptions | undefined + ) => { + let contents: string = this.readFileToBuffer(filePath).toString(options?.encoding || Encoding.Utf8); + if (options?.convertLineEndings) { + contents = Text.convertTo(contents, options.convertLineEndings); + } + + return contents; + }; + + public readFileToBuffer: (filePath: string) => Buffer = (filePath: string) => { + return this._withCaching(filePath, FileSystem.readFileToBuffer, this._readFileCache); + }; + + public copyFileAsync: (options: IFileSystemCopyFileOptions) => Promise = async ( + options: IFileSystemCopyFileOptions + ) => { + await FileSystem.copyFileAsync(options); + this._invalidateCacheEntry(options.destinationPath); + }; + + public deleteFile: (filePath: string, options?: IFileSystemDeleteFileOptions | undefined) => void = ( + filePath: string, + options?: IFileSystemDeleteFileOptions | undefined + ) => { + const cachedError: Error | undefined = this._statsCache.get(filePath)?.error; + if (!cachedError || !FileSystem.isFileDoesNotExistError(cachedError)) { + FileSystem.deleteFile(filePath); + this._invalidateCacheEntry(filePath); + } else if (options?.throwIfNotExists) { + throw cachedError; + } + }; + + public createHardLinkAsync: (options: IFileSystemCreateLinkOptions) => Promise = async ( + options: IFileSystemCreateLinkOptions + ) => { + await FileSystem.createHardLinkAsync(options); + this._invalidateCacheEntry(options.newLinkPath); + }; + + public getRealPath: (linkPath: string) => string = (linkPath: string) => { + return this._withCaching( + linkPath, + (path: string) => { + try { + return FileSystem.getRealPath(path); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + // TypeScript's ts.sys.realpath returns the path it's provided if that path doesn't exist + return path; + } else { + throw e; + } + } + }, + this._realPathCache + ); + }; + + public readFolderFilesAndDirectories: (folderPath: string) => IReadFolderFilesAndDirectoriesResult = ( + folderPath: string + ) => { + return this._withCaching( + folderPath, + (path: string) => { + const folderEntries: FolderItem[] = FileSystem.readFolderItems(path); + return this._sortFolderEntries(folderEntries); + }, + this._readFolderCache + ); + }; + + private _sortFolderEntries(folderEntries: FolderItem[]): IReadFolderFilesAndDirectoriesResult { + // TypeScript expects entries sorted ordinally by name + // In practice this might not matter + folderEntries.sort((a, b) => Sort.compareByValue(a, b)); + + const files: string[] = []; + const directories: string[] = []; + for (const folderEntry of folderEntries) { + if (folderEntry.isFile()) { + files.push(folderEntry.name); + } else if (folderEntry.isDirectory()) { + directories.push(folderEntry.name); + } + } + + return { files, directories }; + } + + private _withCaching( + path: string, + fn: (path: string) => TResult, + cache: Map> + ): TResult { + let cacheEntry: ICacheEntry | undefined = cache.get(path); + if (!cacheEntry) { + try { + cacheEntry = { entry: fn(path) }; + } catch (e) { + cacheEntry = { error: e as Error, entry: undefined }; + } + + cache.set(path, cacheEntry); + } + + if (cacheEntry.entry) { + return cacheEntry.entry; + } else { + throw cacheEntry.error; + } + } + + private _invalidateCacheEntry(path: string): void { + this._statsCache.delete(path); + this._readFolderCache.delete(path); + this._readFileCache.delete(path); + this._realPathCache.delete(path); + } +} diff --git a/heft-plugins/heft-typescript-plugin/src/index.ts b/heft-plugins/heft-typescript-plugin/src/index.ts new file mode 100644 index 00000000000..4b727d4baa1 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/index.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. + +/** + * A Heft plugin for using TypeScript. + * + * @packageDocumentation + */ + +export type { + IEmitModuleKind, + IStaticAssetsCopyConfiguration, + ITypeScriptConfigurationJson, + IPartialTsconfigCompilerOptions, + IPartialTsconfig, + IChangedFilesHookOptions, + ITypeScriptPluginAccessor +} from './TypeScriptPlugin'; + +export { + PLUGIN_NAME as TypeScriptPluginName, + 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 new file mode 100644 index 00000000000..40be5463261 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/internalTypings/TypeScriptInternals.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as TTypescript from 'typescript'; + +export interface IExtendedSolutionBuilder + extends TTypescript.SolutionBuilder { + getBuildOrder(): readonly string[]; + 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 + */ + getAccessibleFileSystemEntries?: (folderPath: string) => { + files: string[]; + directories: string[]; + }; +} + +/** + * @internal + */ +export interface IExtendedTypeScript { + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L3 + */ + performance: { + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L119-L121 + */ + disable(): void; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L110-L116 + */ + enable(): void; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L55-L61 + */ + mark(performanceMaker: string): void; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L72-L78 + */ + measure(measureName: string, startMarkName?: string, endMarkName?: string): void; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L94-L96 + */ + getDuration(measureName: string): number; + + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L85-L87 + */ + getCount(measureName: string): number; + }; + + transpileOptionValueCompilerOptions: { + name: keyof TTypescript.CompilerOptions; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transpileOptionValue: any; + }[]; + + getNewLineCharacter(compilerOptions: TTypescript.CompilerOptions): string; + + createCompilerHost( + options: TTypescript.CompilerOptions, + setParentNodes?: boolean, + system?: TTypescript.System + ): TTypescript.CompilerHost; + + createCompilerHostWorker( + options: TTypescript.CompilerOptions, + setParentNodes?: boolean, + system?: TTypescript.System + ): TTypescript.CompilerHost; + + combinePaths(path1: string, path2: string): string; + + /** + * https://github.com/microsoft/TypeScript/blob/782c09d783e006a697b4ba6d1e7ec2f718ce8393/src/compiler/utilities.ts#L6540 + */ + matchFiles( + path: string, + extensions: ReadonlyArray | undefined, + excludes: ReadonlyArray | undefined, + includes: ReadonlyArray | undefined, + useCaseSensitiveFileNames: boolean, + currentDirectory: string, + depth: number | undefined, + getFileSystemEntries: (path: string) => { + readonly files: ReadonlyArray; + readonly directories: ReadonlyArray; + }, + realpath: (path: string) => string, + directoryExists: (path: string) => boolean + ): string[]; + + Diagnostics: { + // https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/diagnosticMessages.json#L4252-L4255 + // eslint-disable-next-line @typescript-eslint/naming-convention + Found_1_error_Watching_for_file_changes: TTypescript.DiagnosticMessage; + + // https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/diagnosticMessages.json#L4256-L4259 + // eslint-disable-next-line @typescript-eslint/naming-convention + Found_0_errors_Watching_for_file_changes: TTypescript.DiagnosticMessage; + + // https://github.com/microsoft/TypeScript/blob/2428ade1a91248e847f3e1561e31a9426650efee/src/compiler/diagnosticMessages.json#L2252 + // eslint-disable-next-line @typescript-eslint/naming-convention + Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor: TTypescript.DiagnosticMessage; + + // https://github.com/microsoft/TypeScript/blob/2428ade1a91248e847f3e1561e31a9426650efee/src/compiler/diagnosticMessages.json#L4920 + // eslint-disable-next-line @typescript-eslint/naming-convention + Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1: TTypescript.DiagnosticMessage; + }; +} + +export type ExtendedTypeScript = typeof TTypescript & IExtendedTypeScript; + +export type ExtendedBuilderProgram = TTypescript.BuilderProgram & { + /** + * Typescript 5.6+ + */ + state?: { changedFilesSet: Set }; + /** + * Typescript < 5.6 + */ + getState(): { changedFilesSet: Set }; +}; 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/anything.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/anything.schema.json new file mode 100644 index 00000000000..15e4861463a --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/schemas/anything.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Schema that matches anything", + + "oneOf": [ + { + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "integer" + }, + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ] +} diff --git a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json new file mode 100644 index 00000000000..d42ff1f0476 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json @@ -0,0 +1,106 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TypeScript Build Configuration", + "description": "Defines optional options for TypeScript build.", + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "additionalModuleKindsToEmit": { + "type": "array", + "description": "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.", + "items": { + "type": "object", + "properties": { + "moduleKind": { + "type": "string", + "enum": ["commonjs", "amd", "umd", "system", "es2015", "esnext"] + }, + + "outFolderName": { + "type": "string", + "pattern": "[^\\\\\\/]" + } + }, + "required": ["moduleKind", "outFolderName"] + } + }, + + "onlyResolveSymlinksInNodeModules": { + "description": "If true, the TypeScript compiler will only resolve symlinks to their targets if the links are in a node_modules folder. This significantly reduces file system operations in typical usage.", + "type": "boolean" + }, + + "emitCjsExtensionForCommonJS": { + "description": "If true, emit CommonJS module output to the folder specified in the tsconfig \"outDir\" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies CommonJS) the default compilation output.", + "type": "boolean" + }, + + "emitMjsExtensionForESModule": { + "description": "If true, emit ESNext module output to the folder specified in the tsconfig \"outDir\" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output.", + "type": "boolean" + }, + + "buildProjectReferences": { + "description": "If true, enable behavior analogous to the \"tsc --build\" command. Will build projects referenced by the main project. Note that this will effectively enable \"noEmitOnError\".", + "type": "boolean" + }, + + "useTranspilerWorker": { + "description": "If true, and the tsconfig has \"isolatedModules\": true, then transpilation will happen in parallel in a worker thread.", + "type": "boolean" + }, + + "project": { + "description": "Specifies the tsconfig.json file that will be used for compilation. Equivalent to the \"project\" argument for the 'tsc' and 'tslint' command line tools. The default value is \"./tsconfig.json\".", + "type": "string" + }, + + "staticAssetsToCopy": { + "description": "Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example so that these files can be resolved by import statements.", + "type": "object", + + "additionalProperties": false, + + "properties": { + "fileExtensions": { + "type": "array", + "description": "File extensions that should be copied from the source folder to the destination folder(s)", + "items": { + "type": "string", + "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" + } + }, + + "excludeGlobs": { + "type": "array", + "description": "Globs that should be explicitly excluded. This takes precedence over globs listed in \"includeGlobs\" and files that match the file extensions provided in \"fileExtensions\".", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + }, + + "includeGlobs": { + "type": "array", + "description": "Globs that should be explicitly included.", + "items": { + "type": "string", + "pattern": "[^\\\\]" + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..c7855b9ab55 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/types.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 type * as TTypescript from 'typescript'; + +export interface ITypescriptWorkerData { + /** + * Path to the version of TypeScript to use. + */ + typeScriptToolPath: string; +} + +export interface ITranspilationRequestMessage { + /** + * Unique identifier for this request. + */ + requestId: number; + /** + * The tsconfig compiler options to use for the request. + */ + compilerOptions: TTypescript.CompilerOptions; + /** + * The variants to emit. + */ + moduleKindsToEmit: ICachedEmitModuleKind[]; + /** + * The set of files to build. + */ + filesToTranspile: Map; +} + +export interface ITranspilationSuccessMessage { + requestId: number; + type: 'success'; + result: TTypescript.EmitResult; +} + +export interface ITranspilationErrorMessage { + requestId: number; + type: 'error'; + result: { + message: string; + [key: string]: unknown; + }; +} + +export type ITranspilationResponseMessage = ITranspilationSuccessMessage | ITranspilationErrorMessage; + +export interface ICachedEmitModuleKind { + moduleKind: TTypescript.ModuleKind; + + outFolderPath: string; + + /** + * File extension to use instead of '.js' for emitted ECMAScript files. + * For example, '.cjs' to indicate commonjs content, or '.mjs' to indicate ECMAScript modules. + */ + jsExtensionOverride: string | undefined; + + /** + * Set to true if this is the emit kind that is specified in the tsconfig.json. + * Declarations are only emitted for the primary module kind. + */ + isPrimary: boolean; +} diff --git a/heft-plugins/heft-typescript-plugin/tsconfig.json b/heft-plugins/heft-typescript-plugin/tsconfig.json new file mode 100644 index 00000000000..c3c96cb3fb7 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + // 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..65edae3d51a --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/.npmignore @@ -0,0 +1,28 @@ +# Ignore everything by default +** + +# Use negative patterns to bring back the specific things we want to publish +!/bin/** +!/lib/** +!/dist/** +!ThirdPartyNotice.txt +!/EULA/** + +# Ignore certain files in the above folder +/dist/*.stats.* +/lib/**/test/** +/lib/**/*.js.map +/dist/**/*.js.map + +# 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 + +## Project specific definitions +# ----------------------------- + +# (Add your exceptions here) +!heft-plugin.json 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..c8a6c9b7ebe --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.json @@ -0,0 +1,477 @@ +{ + "name": "@rushstack/heft-vscode-extension-plugin", + "entries": [ + { + "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..66f57cb9766 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md @@ -0,0 +1,145 @@ +# Change Log - @rushstack/heft-vscode-extension-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..6ac88a96368 --- /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": "@rushstack/heft-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..006cb82d1c0 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/eslint.config.js @@ -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. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; 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..24bef905318 --- /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/VSCodeExtensionPackagePlugin.js", + "parameterScope": "package" + }, + { + "pluginName": "vscode-extension-verify-signature-plugin", + "entryPoint": "./lib/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/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..76e6ef79af7 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/package.json @@ -0,0 +1,35 @@ +{ + "name": "@rushstack/heft-vscode-extension-plugin", + "version": "1.0.15", + "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" + }, + "main": "lib/index.js", + "types": "lib/index.d.ts", + "peerDependencies": { + "@rushstack/heft": "^1.1.7" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-node-rig": "workspace:*", + "eslint": "~9.37.0", + "@types/node": "20.17.19" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@vscode/vsce": "3.2.1", + "@rushstack/terminal": "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..ada8af53bdc --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts @@ -0,0 +1,101 @@ +// 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, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +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..9440e1f53fd --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPublishPlugin.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 type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions, + CommandLineStringParameter, + CommandLineFlagParameter +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +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..fda739f015b --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionVerifySignaturePlugin.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 type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions, + CommandLineStringParameter +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +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..0772a2698a0 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/util.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 { Executable, IExecutableSpawnOptions, IWaitForExitResult } from '@rushstack/node-core-library'; +import type { ChildProcess } from 'node:child_process'; +import * as path from 'node:path'; +import { TerminalStreamWritable, TerminalProviderSeverity, 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..7f8cf47e02b --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/tsconfig.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-webpack4-plugin/.npmignore b/heft-plugins/heft-webpack4-plugin/.npmignore new file mode 100644 index 00000000000..ffb155d74e6 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** diff --git a/heft-plugins/heft-webpack4-plugin/CHANGELOG.json b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json new file mode 100644 index 00000000000..1328a1b63b0 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json @@ -0,0 +1,6264 @@ +{ + "name": "@rushstack/heft-webpack4-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.10.78", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.78", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.10.77", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.77", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.10.76", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.76", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.10.75", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.75", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.10.74", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.74", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.10.73", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.73", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.10.72", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.72", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.10.71", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.71", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.10.70", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.70", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.10.69", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.69", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.10.68", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.68", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.10.67", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.67", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.10.66", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.66", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.10.65", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.10.64", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.10.63", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.10.62", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.10.61", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.10.60", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.10.59", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.10.58", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.10.57", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.57", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.10.56", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.10.55", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.10.54", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.10.53", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.10.52", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.10.51", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.10.50", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.10.49", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.10.48", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.10.47", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.10.46", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.10.45", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.10.44", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.10.43", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.10.42", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.10.41", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.10.40", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.10.39", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.10.38", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.10.37", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.10.36", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.10.35", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.10.34", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.10.33", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.10.32", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.10.31", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.10.30", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.10.29", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.10.28", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.10.27", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.10.26", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.10.25", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.25", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.10.24", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.10.23", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.10.22", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-webpack4-plugin_v0.9.1", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.56`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-webpack4-plugin_v0.9.0", + "date": "Thu, 07 Sep 2023 03:35:42 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack peerDependency to ~4.47.0 and removes the warning about Node /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/config/jest.config.json b/heft-plugins/heft-webpack4-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-webpack4-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-webpack4-plugin/config/rig.json b/heft-plugins/heft-webpack4-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-webpack4-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-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 new file mode 100644 index 00000000000..34b6f65442d --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/heft-plugin.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "webpack4-plugin", + "entryPoint": "./lib/Webpack4Plugin", + "optionsSchema": "./lib/schemas/heft-webpack4-plugin.schema.json", + + "parameterScope": "webpack4", + "parameters": [ + { + "longName": "--serve", + "parameterKind": "flag", + "description": "Start a local web server for testing purposes using webpack-dev-server. This parameter is only available when running in watch mode." + } + ] + } + ] +} diff --git a/heft-plugins/heft-webpack4-plugin/package.json b/heft-plugins/heft-webpack4-plugin/package.json new file mode 100644 index 00000000000..a8135a61721 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/heft-webpack4-plugin", + "version": "1.1.7", + "description": "Heft plugin for Webpack 4", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-webpack4-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "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" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + } + }, + "peerDependencies": { + "@rushstack/heft": "^1.1.7", + "@types/webpack": "^4", + "webpack": "~4.47.0" + }, + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@types/tapable": "1.0.6", + "tapable": "1.1.3", + "watchpack": "2.4.0", + "webpack-dev-server": "~4.9.3" + }, + "devDependencies": { + "@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" + } +} diff --git a/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts b/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts new file mode 100644 index 00000000000..e3032c9a541 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/DeferredWatchFileSystem.ts @@ -0,0 +1,215 @@ +// 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, Plugin } from 'webpack'; + +export interface IPurgeable { + purge?: (changes: string[]) => void; +} + +export interface IWatchCallback { + ( + err: Error | undefined, + files: string[], + dirs: string[], + missing: string[], + fileTimes: Map, + dirTimes: Map, + removals: Set + ): void; +} + +export interface IWatchUndelayedCallback { + (path: string, mtime: number): void; +} + +export interface IWatch { + close(): void; + pause(): void; + getFileTimestamps(): Map; + getContextTimestamps(): Map; +} + +function* contains(source: Iterable, collection: ReadonlySet): IterableIterator { + for (const item of source) { + if (collection.has(item)) { + yield item; + } + } +} + +interface IWatchState { + files: Set; + dirs: Set; + missing: Set; + + changes: Set; + removals: Set; + + callback: IWatchCallback; +} + +export interface IWatchFileSystem { + watch( + files: string[], + directories: string[], + missing: string[], + startTime: number, + options: WatchOptions, + callback: IWatchCallback, + callbackUndelayed: IWatchUndelayedCallback + ): IWatch; +} + +export class DeferredWatchFileSystem implements IWatchFileSystem { + public readonly inputFileSystem: IPurgeable; + public readonly watcherOptions: WatchOptions; + public watcher: Watchpack | undefined; + + private readonly _onChange: () => void; + private _state: IWatchState | undefined; + + public constructor(inputFileSystem: IPurgeable, 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 { files, dirs, missing, changes, removals, callback } = state; + + const { changes: aggregatedChanges, removals: aggregatedRemovals } = this.watcher!.getAggregated(); + + // Webpack 4 treats changes as a superset of removals + for (const removal of aggregatedRemovals) { + changes.add(removal); + removals.add(removal); + } + for (const change of aggregatedChanges) { + removals.delete(change); + changes.add(change); + } + + if (changes.size > 0) { + this.inputFileSystem.purge?.(Array.from(changes)); + + const filteredRemovals: Set = new Set(contains(removals, files)); + const changedFiles: string[] = Array.from(contains(changes, files)).sort(); + const changedDirs: string[] = Array.from(contains(changes, dirs)).sort(); + const changedMissing: string[] = Array.from(contains(changes, missing)).sort(); + + const times: Map = new Map(Object.entries(this.watcher!.getTimes())); + + callback(undefined, changedFiles, changedDirs, changedMissing, times, times, filteredRemovals); + + changes.clear(); + removals.clear(); + + return true; + } + + return false; + } + + public watch( + files: string[], + directories: string[], + missing: string[], + startTime: number, + options: WatchOptions, + callback: IWatchCallback, + callbackUndelayed: IWatchUndelayedCallback + ): IWatch { + const oldWatcher: Watchpack | undefined = this.watcher; + const watcher: Watchpack = (this.watcher = new Watchpack(options)); + + const changes: Set = new Set(); + const removals: Set = new Set(); + + this._state = { + files: new Set(files), + dirs: new Set(directories), + missing: new Set(missing), + + changes, + removals, + + callback + }; + + watcher.once('aggregated', (newChanges: Set, newRemovals: Set) => { + watcher.pause(); + + for (const change of newChanges) { + changes.add(change); + } + for (const removal of newRemovals) { + changes.add(removal); + removals.add(removal); + } + + this._onChange(); + }); + + 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(); + } + }, + getFileTimestamps: () => { + const timestamps: Record | undefined = this.watcher?.getTimes(); + return timestamps ? new Map(Object.entries(timestamps)) : new Map(); + }, + getContextTimestamps: () => { + const timestamps: Record | undefined = this.watcher?.getTimes(); + return timestamps ? new Map(Object.entries(timestamps)) : new Map(); + } + }; + } +} + +export class OverrideNodeWatchFSPlugin implements Plugin { + public readonly fileSystems: Set = new Set(); + private readonly _onChange: () => void; + + public constructor(onChange: () => void) { + this._onChange = onChange; + } + + public apply(compiler: Compiler): void { + const watchFileSystem: DeferredWatchFileSystem = new DeferredWatchFileSystem( + compiler.inputFileSystem, + this._onChange + ); + this.fileSystems.add(watchFileSystem); + (compiler as { watchFileSystem?: IWatchFileSystem }).watchFileSystem = watchFileSystem; + } +} diff --git a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts new file mode 100644 index 00000000000..644f585c8e8 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts @@ -0,0 +1,478 @@ +// 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 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 { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IScopedLogger, + IHeftTaskRunIncrementalHookOptions +} from '@rushstack/heft'; + +import { + PLUGIN_NAME, + type IWebpackConfiguration, + type IWebpackPluginAccessor, + type IWebpackPluginAccessorHooks +} from './shared'; +import { tryLoadWebpackConfigurationAsync } from './WebpackConfigurationLoader'; +import { + type DeferredWatchFileSystem, + type IWatchFileSystem, + OverrideNodeWatchFSPlugin +} from './DeferredWatchFileSystem'; + +type ExtendedWatching = TWebpack.Watching & { + resume: () => void; + suspend: () => void; +}; + +type ExtendedMultiWatching = TWebpack.MultiWatching & { + resume: () => void; + suspend: () => void; +}; + +type ExtendedCompiler = TWebpack.Compiler & { + hooks: TWebpack.Compiler['hooks'] & { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + infrastructureLog: SyncBailHook; + }; + watching: ExtendedWatching; + watchFileSystem: IWatchFileSystem; +}; + +type ExtendedMultiCompiler = TWebpack.MultiCompiler & { + compilers: ExtendedCompiler[]; + hooks: TWebpack.MultiCompiler['hooks'] & { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + infrastructureLog: SyncBailHook; + }; + watching: ExtendedMultiWatching; +}; + +export interface IWebpackPluginOptions { + devConfigurationPath?: string | undefined; + configurationPath?: string | undefined; +} + +const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; +const WEBPACK_PACKAGE_NAME: 'webpack' = 'webpack'; +const WEBPACK_DEV_SERVER_PACKAGE_NAME: 'webpack-dev-server' = 'webpack-dev-server'; +const WEBPACK_DEV_SERVER_ENV_VAR_NAME: 'WEBPACK_DEV_SERVER' = 'WEBPACK_DEV_SERVER'; +const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-dev-middleware'; + +/** + * @internal + */ +export default class Webpack4Plugin implements IHeftTaskPlugin { + private _accessor: IWebpackPluginAccessor | undefined; + private _isServeMode: boolean = false; + private _webpack: typeof TWebpack | undefined; + private _webpackCompiler: ExtendedCompiler | ExtendedMultiCompiler | undefined; + private _webpackConfiguration: IWebpackConfiguration | undefined | false = false; + private _webpackCompilationDonePromise: Promise | undefined; + private _webpackCompilationDonePromiseResolveFn: (() => void) | undefined; + private _watchFileSystems: Set | undefined; + + private _warnings: Error[] = []; + private _errors: Error[] = []; + + public get accessor(): IWebpackPluginAccessor { + if (!this._accessor) { + this._accessor = { + hooks: _createAccessorHooks(), + parameters: { + isServeMode: this._isServeMode + } + }; + } + return this._accessor; + } + + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions = {} + ): void { + this._isServeMode = taskSession.parameters.getFlagParameter(SERVE_PARAMETER_LONG_NAME).value; + if (!taskSession.parameters.watch && this._isServeMode) { + throw new Error( + `The ${JSON.stringify( + SERVE_PARAMETER_LONG_NAME + )} parameter is only available when running in watch mode.` + ); + } + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + await this._runWebpackAsync(taskSession, heftConfiguration, options); + }); + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + } + ); + } + + private async _getWebpackConfigurationAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions, + requestRun?: () => void + ): Promise { + if (this._webpackConfiguration === false) { + const webpackConfiguration: IWebpackConfiguration | undefined = await tryLoadWebpackConfigurationAsync( + { + taskSession, + heftConfiguration, + hooks: this.accessor.hooks, + serveMode: this._isServeMode, + loadWebpackAsyncFn: this._loadWebpackAsync.bind(this) + }, + options + ); + + if (webpackConfiguration && requestRun) { + const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); + this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + for (const config of Array.isArray(webpackConfiguration) + ? webpackConfiguration + : [webpackConfiguration]) { + if (!config.plugins) { + config.plugins = [overrideWatchFSPlugin]; + } else { + config.plugins.unshift(overrideWatchFSPlugin); + } + } + } + + this._webpackConfiguration = webpackConfiguration; + } + + return this._webpackConfiguration; + } + + private async _loadWebpackAsync(): Promise { + if (!this._webpack) { + // Allow this to fail if webpack is not installed + this._webpack = await import(WEBPACK_PACKAGE_NAME); + } + return this._webpack!; + } + + private async _getWebpackCompilerAsync( + taskSession: IHeftTaskSession, + webpackConfiguration: IWebpackConfiguration + ): Promise { + if (!this._webpackCompiler) { + const webpack: typeof TWebpack = await this._loadWebpackAsync(); + taskSession.logger.terminal.writeLine(`Using Webpack version ${webpack.version}`); + this._webpackCompiler = Array.isArray(webpackConfiguration) + ? (webpack.default( + webpackConfiguration + ) as ExtendedMultiCompiler) /* (webpack.Compilation[]) => MultiCompiler */ + : (webpack.default(webpackConfiguration) as ExtendedCompiler); /* (webpack.Compilation) => Compiler */ + } + return this._webpackCompiler; + } + + private async _runWebpackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions + ): Promise { + this._validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this._isServeMode) { + // Should never happen, but just in case + throw new InternalError('Cannot run Webpack in compilation mode when watch mode is enabled'); + } + + // Load the config and compiler, and return if there is no config found + const webpackConfiguration: IWebpackConfiguration | undefined = await this._getWebpackConfigurationAsync( + taskSession, + heftConfiguration, + options + ); + if (!webpackConfiguration) { + return; + } + const compiler: ExtendedCompiler | ExtendedMultiCompiler = await this._getWebpackCompilerAsync( + taskSession, + webpackConfiguration + ); + taskSession.logger.terminal.writeLine('Running Webpack compilation'); + + // Run the webpack compiler + let stats: TWebpack.Stats | TWebpack.MultiStats | undefined; + try { + stats = await LegacyAdapters.convertCallbackToPromise( + (compiler as TWebpack.Compiler).run.bind(compiler) + ); + } catch (e) { + taskSession.logger.emitError(e as Error); + } + + // Emit the errors from the stats object, if present + if (stats) { + this._recordErrors(stats); + if (this.accessor.hooks.onEmitStats.isUsed()) { + await this.accessor.hooks.onEmitStats.promise(stats); + } + this._emitErrors(taskSession.logger); + } + } + + private async _runWebpackWatchAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions, + requestRun: () => void + ): Promise { + // Save a handle to the original promise, since the this-scoped promise will be replaced whenever + // the compilation completes. + let webpackCompilationDonePromise: Promise | undefined = this._webpackCompilationDonePromise; + + let isInitial: boolean = false; + + if (!this._webpackCompiler) { + isInitial = true; + this._validateEnvironmentVariable(taskSession); + if (!taskSession.parameters.watch) { + // Should never happen, but just in case + throw new InternalError('Cannot run Webpack in watch mode when compilation mode is enabled'); + } + + // Load the config and compiler, and return if there is no config found + const webpackConfiguration: IWebpackConfiguration | undefined = + await this._getWebpackConfigurationAsync(taskSession, heftConfiguration, options, requestRun); + if (!webpackConfiguration) { + return; + } + + // Get the compiler which will be used for both serve and watch mode + const compiler: ExtendedCompiler | ExtendedMultiCompiler = await this._getWebpackCompilerAsync( + taskSession, + webpackConfiguration + ); + + // 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._webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this._webpackCompilationDonePromiseResolveFn = resolve; + }); + webpackCompilationDonePromise = this._webpackCompilationDonePromise; + compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TWebpack.Stats | TWebpack.MultiStats) => { + this._webpackCompilationDonePromiseResolveFn!(); + this._webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this._webpackCompilationDonePromiseResolveFn = resolve; + }); + if (stats) { + this._recordErrors(stats); + } + }); + + // Determine how we will run the compiler. When serving, we will run the compiler + // via the webpack-dev-server. Otherwise, we will run the compiler directly. + if (this._isServeMode) { + const defaultDevServerOptions: TWebpackDevServer.Configuration = { + host: 'localhost', + devMiddleware: { + publicPath: '/', + stats: { + cached: false, + cachedAssets: false, + colors: heftConfiguration.terminalProvider.supportsColor + } + }, + client: { + logging: 'info', + webSocketURL: { + port: 8080 + } + }, + port: 8080, + onListening: (server: TWebpackDevServer) => { + 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}`); + } + } + }; + + // Obtain the devServerOptions from the webpack configuration, and combine with the default options + let devServerOptions: TWebpackDevServer.Configuration; + if (Array.isArray(webpackConfiguration)) { + const filteredDevServerOptions: TWebpackDevServer.Configuration[] = webpackConfiguration + .map((configuration) => configuration.devServer) + .filter((devServer): devServer is TWebpackDevServer.Configuration => !!devServer); + if (filteredDevServerOptions.length > 1) { + taskSession.logger.emitWarning( + new Error(`Detected multiple webpack devServer configurations, using the first one.`) + ); + } + devServerOptions = { ...defaultDevServerOptions, ...filteredDevServerOptions[0] }; + } else { + devServerOptions = { ...defaultDevServerOptions, ...webpackConfiguration.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: TWebpackDevServer.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. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + compiler.hooks.infrastructureLog.tap(PLUGIN_NAME, (name: string, type: string, args: any[]) => { + if (name === WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME && type === 'error') { + const error: Error | undefined = args[0]; + if (error) { + taskSession.logger.emitError(error); + } + } + return true; + }); + + // 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. + taskSession.logger.terminal.writeLine('Starting webpack-dev-server'); + const WebpackDevServer: typeof TWebpackDevServer = (await import(WEBPACK_DEV_SERVER_PACKAGE_NAME)) + .default; + const webpackDevServer: TWebpackDevServer = new WebpackDevServer(devServerOptions, compiler); + await webpackDevServer.start(); + } else { + // Create the watcher. Compilation will start immediately after invoking watch(). + taskSession.logger.terminal.writeLine('Starting Webpack watcher'); + compiler.watch({}, (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 Webpack compilation'); + await webpackCompilationDonePromise; + } else { + taskSession.logger.terminal.writeLine( + 'Webpack has not detected changes. Listing previous diagnostics.' + ); + } + + this._emitErrors(taskSession.logger); + } + + private _validateEnvironmentVariable(taskSession: IHeftTaskSession): void { + if (!this._isServeMode && process.env[WEBPACK_DEV_SERVER_ENV_VAR_NAME]) { + taskSession.logger.emitWarning( + new Error( + `The "${WEBPACK_DEV_SERVER_ENV_VAR_NAME}" environment variable is set, ` + + 'which will cause problems when webpack is not running in serve mode. ' + + `(Did a dependency inadvertently load the "${WEBPACK_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: TWebpack.Stats | TWebpack.compilation.MultiStats): void { + this._errors.length = 0; + this._warnings.length = 0; + + if (stats.hasErrors() || stats.hasWarnings()) { + const serializedStats: TWebpack.Stats.ToJsonOutput[] = [stats.toJson('errors-warnings')]; + + for (const compilationStats of serializedStats) { + for (const warning of compilationStats.warnings as (string | Error)[]) { + this._warnings.push(warning instanceof Error ? warning : new Error(warning)); + } + + for (const error of compilationStats.errors as (string | Error)[]) { + this._errors.push(error instanceof Error ? error : new Error(error)); + } + + if (compilationStats.children) { + for (const child of compilationStats.children) { + serializedStats.push(child); + } + } + } + } + } +} + +/** + * @internal + */ +export function _createAccessorHooks(): IWebpackPluginAccessorHooks { + return { + onLoadConfiguration: new AsyncSeriesBailHook(), + onConfigure: new AsyncSeriesHook(['webpackConfiguration']), + onAfterConfigure: new AsyncParallelHook(['webpackConfiguration']), + onEmitStats: new AsyncParallelHook(['webpackStats']) + }; +} diff --git a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.test.ts b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.test.ts new file mode 100644 index 00000000000..26b9e1ce52d --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.test.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { HeftConfiguration, IHeftParameters, IHeftTaskSession, IScopedLogger } from '@rushstack/heft'; +import { MockScopedLogger } from '@rushstack/heft/lib/pluginFramework/logging/MockScopedLogger'; +import { type ITerminal, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import * as WebpackConfigurationLoader from './WebpackConfigurationLoader'; +import { _createAccessorHooks } from './Webpack4Plugin'; +import { type IWebpackConfiguration, STAGE_LOAD_LOCAL_CONFIG } from './shared'; + +interface IMockLoadWebpackConfigurationOptions + extends WebpackConfigurationLoader.ILoadWebpackConfigurationOptions { + loadWebpackAsyncFn: jest.Mock; + _terminalProvider: StringBufferTerminalProvider; + _tryLoadConfigFileAsync: jest.Mock; +} + +describe(WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync.name, () => { + function createOptions(production: boolean, serveMode: boolean): IMockLoadWebpackConfigurationOptions { + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + const logger: IScopedLogger = new MockScopedLogger(terminal); + const buildFolderPath: string = __dirname; + + const parameters: Partial = { + production + }; + + const taskSession: IHeftTaskSession = { + logger, + parameters: parameters as unknown as IHeftParameters, + // Other values unused during these tests + hooks: undefined!, + parsedCommandLine: undefined!, + requestAccessToPluginByName: undefined!, + taskName: 'webpack', + tempFolderPath: `${__dirname}/temp` + }; + + const heftConfiguration: Partial = { + buildFolderPath + }; + + return { + taskSession, + heftConfiguration: heftConfiguration as unknown as HeftConfiguration, + hooks: _createAccessorHooks(), + loadWebpackAsyncFn: jest.fn(), + serveMode, + + _terminalProvider: terminalProvider, + _tryLoadConfigFileAsync: jest.fn() + }; + } + + it(`onLoadConfiguration can return false`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onLoadConfiguration: jest.Mock = jest.fn(); + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onLoadConfiguration.tap('test', onLoadConfiguration); + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + onLoadConfiguration.mockReturnValue(false); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBeUndefined(); + expect(onLoadConfiguration).toHaveBeenCalledTimes(1); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(0); + expect(onConfigure).toHaveBeenCalledTimes(0); + expect(onAfterConfigure).toHaveBeenCalledTimes(0); + }); + + it(`calls tryLoadWebpackConfigurationFileAsync`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(undefined)); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBeUndefined(); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(0); + expect(onAfterConfigure).toHaveBeenCalledTimes(0); + }); + + it(`can fall back`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onLoadConfiguration: jest.Mock = jest.fn(); + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onLoadConfiguration.tap( + { name: 'test', stage: STAGE_LOAD_LOCAL_CONFIG + 1 }, + onLoadConfiguration + ); + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(undefined)); + + const mockConfig: IWebpackConfiguration = {}; + onLoadConfiguration.mockReturnValue(mockConfig); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBe(mockConfig); + + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onLoadConfiguration).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(1); + expect(onAfterConfigure).toHaveBeenCalledTimes(1); + + expect(onConfigure).toHaveBeenCalledWith(mockConfig); + expect(onAfterConfigure).toHaveBeenCalledWith(mockConfig); + }); + + it(`respects hook order`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + const mockConfig: IWebpackConfiguration = {}; + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(mockConfig)); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBe(mockConfig); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledWith(mockConfig); + expect(onAfterConfigure).toHaveBeenCalledTimes(1); + expect(onAfterConfigure).toHaveBeenCalledWith(mockConfig); + }); +}); diff --git a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts new file mode 100644 index 00000000000..cd1b0c36052 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts @@ -0,0 +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 path from 'node:path'; + +import type * as TWebpack from 'webpack'; + +import { FileSystem } from '@rushstack/node-core-library'; +import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; + +import type { IWebpackPluginOptions } from './Webpack4Plugin'; +import { + PLUGIN_NAME, + STAGE_LOAD_LOCAL_CONFIG, + type IWebpackConfiguration, + type IWebpackConfigurationFnEnvironment, + type IWebpackPluginAccessorHooks +} from './shared'; + +type IWebpackConfigJsExport = + | TWebpack.Configuration + | TWebpack.Configuration[] + | Promise + | Promise + | ((env: IWebpackConfigurationFnEnvironment) => TWebpack.Configuration | TWebpack.Configuration[]) + | ((env: IWebpackConfigurationFnEnvironment) => Promise); +type IWebpackConfigJs = IWebpackConfigJsExport | { default: IWebpackConfigJsExport }; + +/** + * @internal + */ +export interface ILoadWebpackConfigurationOptions { + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + serveMode: boolean; + loadWebpackAsyncFn: () => Promise; + hooks: Pick; + + _tryLoadConfigFileAsync?: typeof tryLoadWebpackConfigurationFileAsync; +} + +const DEFAULT_WEBPACK_CONFIG_PATH: './webpack.config.js' = './webpack.config.js'; +const DEFAULT_WEBPACK_DEV_CONFIG_PATH: './webpack.dev.config.js' = './webpack.dev.config.js'; + +/** + * @internal + */ +export async function tryLoadWebpackConfigurationAsync( + options: ILoadWebpackConfigurationOptions, + pluginOptions: IWebpackPluginOptions +): Promise { + const { taskSession, hooks, _tryLoadConfigFileAsync = tryLoadWebpackConfigurationFileAsync } = options; + const { logger } = taskSession; + const { terminal } = logger; + + // Apply default behavior. Due to the state of `this._webpackConfiguration`, this code + // will execute exactly once. + hooks.onLoadConfiguration.tapPromise( + { + name: PLUGIN_NAME, + stage: STAGE_LOAD_LOCAL_CONFIG + }, + async () => { + terminal.writeVerboseLine(`Attempting to load Webpack configuration from local file`); + const webpackConfiguration: IWebpackConfiguration | undefined = await _tryLoadConfigFileAsync( + options, + pluginOptions + ); + + if (webpackConfiguration) { + terminal.writeVerboseLine(`Loaded Webpack configuration from local file.`); + } + + return webpackConfiguration; + } + ); + + // Obtain the webpack configuration by calling into the hook. + // The local configuration is loaded at STAGE_LOAD_LOCAL_CONFIG + terminal.writeVerboseLine('Attempting to load Webpack configuration'); + let webpackConfiguration: IWebpackConfiguration | false | undefined = + await hooks.onLoadConfiguration.promise(); + + if (webpackConfiguration === false) { + terminal.writeLine('Webpack disabled by external plugin'); + webpackConfiguration = undefined; + } else if ( + webpackConfiguration === undefined || + (Array.isArray(webpackConfiguration) && webpackConfiguration.length === 0) + ) { + terminal.writeLine('No Webpack configuration found'); + webpackConfiguration = undefined; + } else { + if (hooks.onConfigure.isUsed()) { + // Allow for plugins to customise the configuration + await hooks.onConfigure.promise(webpackConfiguration); + } + if (hooks.onAfterConfigure.isUsed()) { + // Provide the finalized configuration + await hooks.onAfterConfigure.promise(webpackConfiguration); + } + } + return webpackConfiguration; +} + +/** + * @internal + */ +export async function tryLoadWebpackConfigurationFileAsync( + options: ILoadWebpackConfigurationOptions, + pluginOptions: IWebpackPluginOptions +): Promise { + // TODO: Eventually replace this custom logic with a call to this utility in in webpack-cli: + // https://github.com/webpack/webpack-cli/blob/next/packages/webpack-cli/lib/groups/ConfigGroup.js + + const { taskSession, heftConfiguration, loadWebpackAsyncFn, serveMode } = options; + const { + logger, + parameters: { production } + } = taskSession; + const { terminal } = logger; + const { configurationPath, devConfigurationPath } = pluginOptions; + let webpackConfigJs: IWebpackConfigJs | undefined; + + try { + const buildFolderPath: string = heftConfiguration.buildFolderPath; + if (serveMode) { + const devConfigPath: string = path.resolve( + buildFolderPath, + devConfigurationPath || DEFAULT_WEBPACK_DEV_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load webpack configuration from "${devConfigPath}".`); + webpackConfigJs = await _tryLoadWebpackConfigurationFileInnerAsync(devConfigPath); + } + + if (!webpackConfigJs) { + const configPath: string = path.resolve( + buildFolderPath, + configurationPath || DEFAULT_WEBPACK_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load webpack configuration from "${configPath}".`); + webpackConfigJs = await _tryLoadWebpackConfigurationFileInnerAsync(configPath); + } + } catch (error) { + logger.emitError(error as Error); + } + + if (webpackConfigJs) { + const webpackConfig: IWebpackConfigJsExport = + (webpackConfigJs as { default: IWebpackConfigJsExport }).default || webpackConfigJs; + + if (typeof webpackConfig === 'function') { + // Defer loading of webpack until we know for sure that we will need it + return webpackConfig({ + prod: production, + production, + taskSession, + heftConfiguration, + webpack: await loadWebpackAsyncFn() + }); + } else { + return webpackConfig; + } + } else { + return undefined; + } +} + +/** + * @internal + */ +export async function _tryLoadWebpackConfigurationFileInnerAsync( + configurationPath: string +): Promise { + const configExists: boolean = await FileSystem.existsAsync(configurationPath); + if (configExists) { + try { + return await import(configurationPath); + } catch (e) { + const error: NodeJS.ErrnoException = e as NodeJS.ErrnoException; + if (error.code === 'ERR_MODULE_NOT_FOUND') { + // No configuration found, return undefined. + return undefined; + } + throw new Error(`Error loading webpack configuration at "${configurationPath}": ${e}`); + } + } else { + return undefined; + } +} diff --git a/heft-plugins/heft-webpack4-plugin/src/index.ts b/heft-plugins/heft-webpack4-plugin/src/index.ts new file mode 100644 index 00000000000..0ad82466ea3 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/index.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. + +export { PLUGIN_NAME as PluginName, STAGE_LOAD_LOCAL_CONFIG } from './shared'; + +export type { + IWebpackConfigurationWithDevServer, + IWebpackConfiguration, + IWebpackConfigurationFnEnvironment, + IWebpackPluginAccessor, + IWebpackPluginAccessorHooks, + IWebpackPluginAccessorParameters +} from './shared'; diff --git a/heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin.schema.json b/heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin.schema.json new file mode 100644 index 00000000000..d780b1ac1f5 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/schemas/heft-webpack4-plugin.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Webpack 4 Plugin Configuration", + "description": "Defines options for Webpack 4 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 Webpack dev configuration, which is used in \"serve\" mode. The default value is \"./webpack.dev.config.js\".", + "type": "string" + }, + + "configurationPath": { + "description": "Specifies a relative path to the Webpack configuration. The default value is \"./webpack.config.js\".", + "type": "string" + } + } +} diff --git a/heft-plugins/heft-webpack4-plugin/src/shared.ts b/heft-plugins/heft-webpack4-plugin/src/shared.ts new file mode 100644 index 00000000000..22589b3d54e --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/src/shared.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. + +// 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' { + export type MultiStats = TWebpack.compilation.MultiStats; + export type StatsOptions = unknown; + export type StatsCompilation = TWebpack.compilation.Compilation; + + // eslint-disable-next-line @typescript-eslint/naming-convention + export interface Compiler { + watching?: unknown; + } +} +import type { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server'; +import type { AsyncParallelHook, AsyncSeriesBailHook, AsyncSeriesHook } from 'tapable'; + +import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; + +/** + * The environment passed into the Webpack configuration function. Loosely based + * on the default Webpack environment options, specified here: + * https://webpack.js.org/api/cli/#environment-options + * + * @public + */ +export interface IWebpackConfigurationFnEnvironment { + /** + * Whether or not the run is in production mode. Synonym of + * IWebpackConfigurationFnEnvironment.production. + */ + prod: boolean; + /** + * Whether or not the run is in production mode. Synonym of + * IWebpackConfigurationFnEnvironment.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 Webpack package. + */ + webpack: typeof TWebpack; +} + +/** + * @public + */ +export interface IWebpackConfigurationWithDevServer extends TWebpack.Configuration { + devServer?: WebpackDevServerConfiguration; +} + +/** + * @public + */ +export type IWebpackConfiguration = IWebpackConfigurationWithDevServer | IWebpackConfigurationWithDevServer[]; + +/** + * @public + */ +export interface IWebpackPluginAccessorHooks { + /** + * A hook that allows for loading custom configurations used by the Webpack + * plugin. If a tap returns a value other than `undefined` before stage {@link STAGE_LOAD_LOCAL_CONFIG}, + * it will suppress loading from the webpack 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 webpack from running. + */ + readonly onLoadConfiguration: AsyncSeriesBailHook; + /** + * A hook that allows for modification of the loaded configuration used by the Webpack + * plugin. If no configuration was loaded, this hook will not be called. + */ + readonly onConfigure: AsyncSeriesHook; + /** + * A hook that provides the finalized configuration that will be used by Webpack. + * If no configuration was loaded, this hook will not be called. + */ + readonly onAfterConfigure: AsyncParallelHook; + /** + * A hook that provides the stats output from Webpack. If no configuration is loaded, + * this hook will not be called. + */ + readonly onEmitStats: AsyncParallelHook; +} + +/** + * @public + */ +export interface IWebpackPluginAccessorParameters { + /** + * Whether or not serve mode was enabled by passing the `--serve` flag. + */ + readonly isServeMode: boolean; +} + +/** + * @public + */ +export interface IWebpackPluginAccessor { + /** + * Hooks that are called at various points in the Webpack plugin lifecycle. + */ + readonly hooks: IWebpackPluginAccessorHooks; + /** + * Parameters that are provided by the Webpack plugin. + */ + readonly parameters: IWebpackPluginAccessorParameters; +} + +/** + * The stage in the `onLoadConfiguration` hook at which the config will be loaded from the local + * webpack config file. + * @public + */ +export const STAGE_LOAD_LOCAL_CONFIG: 1000 = 1000; + +/** + * @public + */ +export const PLUGIN_NAME: 'webpack4-plugin' = 'webpack4-plugin'; diff --git a/heft-plugins/heft-webpack4-plugin/tsconfig.json b/heft-plugins/heft-webpack4-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-webpack5-plugin/.npmignore b/heft-plugins/heft-webpack5-plugin/.npmignore new file mode 100644 index 00000000000..ffb155d74e6 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.json b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json new file mode 100644 index 00000000000..4ce93fc88b3 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json @@ -0,0 +1,6336 @@ +{ + "name": "@rushstack/heft-webpack5-plugin", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.8", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.7", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.6", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.5", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.4", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.3", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.2", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.1", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.0", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "minor": [ + { + "comment": "Update the `webpack` peer dependency to `^5.82.1` from `~5.82.1`. Also bump `webpack-dev-server` to `^5.1.0`. This drops support for Node 16 and includes some breaking configuration changes. See https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.14", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.13", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.12", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.11", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.10", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.9", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.8", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.7", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.6", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.5", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.4", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.3", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.2", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.1", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.10.0", + "date": "Fri, 07 Jun 2024 15:10:25 GMT", + "comments": { + "minor": [ + { + "comment": "Add `onGetWatchOptions` accessor hook to allow cooperating plugins to, for example, configure a list of globs for the file watcher to ignore." + } + ] + } + }, + { + "version": "0.9.55", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.9.54", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.9.53", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.9.52", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.9.51", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.9.50", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.9.49", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.9.48", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.9.47", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.9.46", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.9.45", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.9.44", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.9.43", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.9.42", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.9.41", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.9.40", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.9.39", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.9.38", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.9.37", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.9.36", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.9.35", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.9.34", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.9.33", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.9.32", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.9.31", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.9.30", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.9.29", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.9.28", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.9.27", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.9.26", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.9.25", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.25", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.9.24", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.9.23", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.9.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.8.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.15", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.56`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.14", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.55`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.13", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.12", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.11", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.10", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.9", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.8", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.7", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.6", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.5", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.4", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.45`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.3", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.2", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.1", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.42`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.8.0", + "date": "Wed, 14 Jun 2023 00:19:41 GMT", + "comments": { + "minor": [ + { + "comment": "Move loading of webpack config file into the `onLoadConfiguration` hook to allow other plugins to define fallback behavior, rather than only overriding the config file." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.10", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.9", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.8", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.7", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.6", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.5", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.4", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.3", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the error message when the \"--serve\" is incorrectly specified" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.2", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.7.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.12", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.11", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.10", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.9", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.8", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.7", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.6", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.5", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.4", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bug where peerDep of webpack was not properly updated with regular dependency version. " + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.3", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.2", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.1", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.6.0", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for `.cjs` and `.mjs` file extensions for webpack config files, in addition to the `.js` file extension." + } + ] + } + }, + { + "version": "0.5.73", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.73", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.5.72", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.72", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.5.71", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.71", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.5.70", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.70", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.5.69", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.69", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.5.68", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.68", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.5.67", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.67", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.5.66", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.66", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.5.65", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.65", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.5.64", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.64", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.5.63", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.63", + "date": "Fri, 02 Dec 2022 01:15:41 GMT", + "comments": { + "patch": [ + { + "comment": "Log errors and warnings from nested compilations." + } + ] + } + }, + { + "version": "0.5.62", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.62", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.5.61", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.61", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.5.60", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.60", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.5.59", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.59", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "patch": [ + { + "comment": "Set WebSocket port to match http port." + } + ] + } + }, + { + "version": "0.5.58", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.58", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.5.57", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.57", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.5.56", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.56", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.5.55", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.55", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.5.54", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.54", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.5.53", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.53", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.5.52", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.52", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.5.51", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.51", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.5.50", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.50", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.5.49", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.49", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.5.48", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.48", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.5.47", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.47", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.5.46", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.46", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.5.45", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.45", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.5.44", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.44", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.5.43", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.43", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.5.42", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.42", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.5.41", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.41", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.5.40", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.40", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.5.39", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.39", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.5.38", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.38", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.5.37", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.37", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.5.36", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.36", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.5.35", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.35", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.5.34", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.34", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade webpack-dev-server" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.5.33", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.33", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.5.32", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.32", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.5.31", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.31", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.30", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.29", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.28", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.27", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.26", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.25", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.24", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.23", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.22", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.21", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.20", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.19", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.18", + "date": "Wed, 18 May 2022 15:10:55 GMT", + "comments": { + "patch": [ + { + "comment": "fix: removed deprecation warning for webpack-dev-server" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.17", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.16", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.15", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where Heft will crash if the Webpack configuration is an empty array." + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.14", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.13", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.12", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.11", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.10", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.9", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.8", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.7", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.5", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.4", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.3", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.2", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.1", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.5.0", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to Webpack ~5.68.0" + }, + { + "comment": "Change \"webpack\" to be a peer dependency instead of a regular dependency; this avoids a situation where Heft might import a different version of Webpack from the consuming project or its rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.32", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.31", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.30", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.29", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.28", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.27", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.26", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.25", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.24", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.23", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.22", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.21", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.20", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.19", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.18", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.17", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.16", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.15", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.14", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.13", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.12", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.11", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.10", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.9", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.8", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.7", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.6", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.5", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.4", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.3", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.2", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.1", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.4.0", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "minor": [ + { + "comment": "Improve the type declaration for IWebpackBundleSubstageProperties.webpackConfiguration" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.4` to `^0.38.0`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.6", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.3` to `^0.37.4`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.5", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.2` to `^0.37.3`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.4", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.1` to `^0.37.2`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.3", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.0` to `^0.37.1`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.2", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.1", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.4` to `^0.37.0`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.3.0", + "date": "Mon, 30 Aug 2021 15:08:25 GMT", + "comments": { + "minor": [ + { + "comment": "Migrate to webpack-dev-server 4.x" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.8", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.3` to `^0.36.4`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.7", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.36.3`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.6", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.5", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.1` to `^0.36.2`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.4", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.0` to `^0.36.1`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.3", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.1` to `^0.36.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.2", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.0` to `^0.35.1`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.1", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.8` to `^0.35.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.2.0", + "date": "Tue, 27 Jul 2021 22:31:02 GMT", + "comments": { + "minor": [ + { + "comment": "Update webpack to be lazy-loaded." + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.38", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.7` to `^0.34.8`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.37", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.6` to `^0.34.7`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.36", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.5` to `^0.34.6`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.35", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.4` to `^0.34.5`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.34", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.3` to `^0.34.4`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.33", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.2` to `^0.34.3`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.32", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.31", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.1` to `^0.34.2`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.30", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.0` to `^0.34.1`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.29", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.1` to `^0.34.0`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.28", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.0` to `^0.33.1`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.27", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.26", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.32.0` to `^0.33.0`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.25", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.24", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.23", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.5` to `^0.32.0`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.22", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.4` to `^0.31.5`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.21", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.3` to `^0.31.4`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.20", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.2` to `^0.31.3`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.19", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.1` to `^0.31.2`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.18", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.0` to `^0.31.1`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.17", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.7` to `^0.31.0`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.16", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.6` to `^0.30.7`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.15", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.5` to `^0.30.6`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.14", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.4` to `^0.30.5`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.13", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.3` to `^0.30.4`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.12", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.2` to `^0.30.3`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.11", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.1` to `^0.30.2`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.10", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.0` to `^0.30.1`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.9", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.1` to `^0.30.0`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.8", + "date": "Tue, 27 Apr 2021 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrades webpack 5 to get a bug fix when resolving modules with a # in the path" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.7", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.0` to `^0.29.1`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.6", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.5` to `^0.29.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.5", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.4` to `^0.28.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.4", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.3` to `^0.28.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.3", + "date": "Thu, 15 Apr 2021 15:09:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix webpack5 persistent cache in production mode" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.2", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.2` to `^0.28.3`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.1", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.1` to `^0.28.2`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-webpack5-plugin_v0.1.0", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "minor": [ + { + "comment": "Initial project creation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.5` to `^0.28.1`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.md b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md new file mode 100644 index 00000000000..4c1548b098a --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md @@ -0,0 +1,1710 @@ +# Change Log - @rushstack/heft-webpack5-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.11.8 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.11.7 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.11.6 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.11.5 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.11.4 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.11.3 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.11.2 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.11.1 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.11.0 +Wed, 02 Oct 2024 00:11:19 GMT + +### Minor changes + +- Update the `webpack` peer dependency to `^5.82.1` from `~5.82.1`. Also bump `webpack-dev-server` to `^5.1.0`. This drops support for Node 16 and includes some breaking configuration changes. See https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md. + +## 0.10.14 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.10.13 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.10.12 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.10.11 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.10.10 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.10.9 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.10.8 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.10.7 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.10.6 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.10.5 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.10.4 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.10.3 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.10.2 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.10.1 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.10.0 +Fri, 07 Jun 2024 15:10:25 GMT + +### Minor changes + +- Add `onGetWatchOptions` accessor hook to allow cooperating plugins to, for example, configure a list of globs for the file watcher to ignore. + +## 0.9.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.9.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.9.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.9.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.9.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.9.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.9.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.9.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.9.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.9.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.9.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.9.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.9.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.9.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.9.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.9.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.9.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.9.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.9.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.9.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.9.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.9.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.9.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.9.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.9.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.9.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.9.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.9.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.9.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.9.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.9.25 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.9.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.9.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.9.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.9.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.9.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.9.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.9.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.9.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.9.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.9.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.9.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.9.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.9.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.9.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.9.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.9.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.9.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.9.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.9.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.9.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.9.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.9.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.9.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.9.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.9.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.8.15 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.8.14 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.8.13 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.8.12 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.8.11 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.8.10 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.8.9 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.8.8 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.8.7 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.8.6 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.8.5 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.8.4 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.8.3 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.8.2 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.8.1 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.8.0 +Wed, 14 Jun 2023 00:19:41 GMT + +### Minor changes + +- Move loading of webpack config file into the `onLoadConfiguration` hook to allow other plugins to define fallback behavior, rather than only overriding the config file. + +## 0.7.10 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.7.9 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.7.8 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.7.7 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.7.6 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.7.5 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.7.4 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.7.3 +Wed, 07 Jun 2023 22:45:16 GMT + +### Patches + +- Improve the error message when the "--serve" is incorrectly specified + +## 0.7.2 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.7.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.7.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.6.12 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.6.11 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.6.10 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.6.9 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.6.8 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.6.7 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.6.6 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.6.5 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.6.4 +Tue, 11 Apr 2023 00:23:22 GMT + +### Patches + +- Fix bug where peerDep of webpack was not properly updated with regular dependency version. + +## 0.6.3 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.6.2 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.6.1 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.6.0 +Sat, 11 Mar 2023 01:24:51 GMT + +### Minor changes + +- Add support for `.cjs` and `.mjs` file extensions for webpack config files, in addition to the `.js` file extension. + +## 0.5.73 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.5.72 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.5.71 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.5.70 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.5.69 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.5.68 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.5.67 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.5.66 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.5.65 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.5.64 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.5.63 +Fri, 02 Dec 2022 01:15:41 GMT + +### Patches + +- Log errors and warnings from nested compilations. + +## 0.5.62 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.5.61 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.5.60 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.5.59 +Tue, 25 Oct 2022 00:20:44 GMT + +### Patches + +- Set WebSocket port to match http port. + +## 0.5.58 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.5.57 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.5.56 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.5.55 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.5.54 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.5.53 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.5.52 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.5.51 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.5.50 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.5.49 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.5.48 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.5.47 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.5.46 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.5.45 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.5.44 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.5.43 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.5.42 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.5.41 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.5.40 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.5.39 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.5.38 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.5.37 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.5.36 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.5.35 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.5.34 +Wed, 13 Jul 2022 21:31:13 GMT + +### Patches + +- Upgrade webpack-dev-server + +## 0.5.33 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.5.32 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.5.31 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.5.30 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.5.29 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.5.28 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.5.27 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.5.26 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.5.25 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.5.24 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.5.23 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.5.22 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.5.21 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.5.20 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.5.19 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.5.18 +Wed, 18 May 2022 15:10:55 GMT + +### Patches + +- fix: removed deprecation warning for webpack-dev-server + +## 0.5.17 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.5.16 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.5.15 +Fri, 06 May 2022 18:54:42 GMT + +### Patches + +- Fix an issue where Heft will crash if the Webpack configuration is an empty array. + +## 0.5.14 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.5.13 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.5.12 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.5.11 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.5.10 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.5.9 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.5.8 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.5.7 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.5.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.5.5 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.5.4 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.5.3 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.5.2 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.5.1 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.5.0 +Fri, 11 Feb 2022 10:30:25 GMT + +### Minor changes + +- Upgrade to Webpack ~5.68.0 +- Change "webpack" to be a peer dependency instead of a regular dependency; this avoids a situation where Heft might import a different version of Webpack from the consuming project or its rig + +## 0.4.32 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.4.31 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.4.30 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.4.29 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.4.28 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.4.27 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.4.26 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.4.25 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.4.24 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.4.23 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.4.22 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.4.21 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.4.20 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.4.19 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.4.18 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.4.17 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.4.16 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.4.15 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.4.14 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.4.13 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.4.12 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.4.11 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.4.10 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.4.9 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.4.8 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.4.7 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 0.4.6 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.4.5 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.4.4 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.4.3 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.4.2 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.4.1 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.4.0 +Tue, 14 Sep 2021 01:17:04 GMT + +### Minor changes + +- Improve the type declaration for IWebpackBundleSubstageProperties.webpackConfiguration + +## 0.3.6 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.3.5 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.3.4 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.3.3 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.3.2 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.3.1 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.3.0 +Mon, 30 Aug 2021 15:08:25 GMT + +### Minor changes + +- Migrate to webpack-dev-server 4.x + +## 0.2.8 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.2.7 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.2.6 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 0.2.5 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.2.4 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.2.3 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.2.2 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.2.1 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 0.2.0 +Tue, 27 Jul 2021 22:31:02 GMT + +### Minor changes + +- Update webpack to be lazy-loaded. + +## 0.1.38 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.1.37 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.1.36 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.1.35 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.1.34 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.1.33 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.1.32 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 0.1.31 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.1.30 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.1.29 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.1.28 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 0.1.27 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 0.1.26 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 0.1.25 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 0.1.24 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 0.1.23 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 0.1.22 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 0.1.21 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.1.20 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 0.1.19 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.1.18 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 0.1.17 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 0.1.16 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 0.1.15 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 0.1.14 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.1.13 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 0.1.12 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 0.1.11 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 0.1.10 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.1.9 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 0.1.8 +Tue, 27 Apr 2021 00:11:19 GMT + +### Patches + +- Upgrades webpack 5 to get a bug fix when resolving modules with a # in the path + +## 0.1.7 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 0.1.6 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 0.1.5 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 0.1.4 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.1.3 +Thu, 15 Apr 2021 15:09:34 GMT + +### Patches + +- Fix webpack5 persistent cache in production mode + +## 0.1.2 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 0.1.1 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.1.0 +Thu, 08 Apr 2021 20:41:54 GMT + +### Minor changes + +- Initial project creation. + diff --git a/heft-plugins/heft-webpack5-plugin/LICENSE b/heft-plugins/heft-webpack5-plugin/LICENSE new file mode 100644 index 00000000000..3372a03b9b2 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-webpack5-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-webpack5-plugin/README.md b/heft-plugins/heft-webpack5-plugin/README.md new file mode 100644 index 00000000000..cfac2a70129 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-webpack5-plugin + +This is a Heft plugin for using Webpack 5. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-webpack5-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-webpack5-plugin/config/api-extractor.json b/heft-plugins/heft-webpack5-plugin/config/api-extractor.json new file mode 100644 index 00000000000..74590d3c4f8 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/config/api-extractor.json @@ -0,0 +1,16 @@ +{ + "$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": 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/config/jest.config.json b/heft-plugins/heft-webpack5-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-webpack5-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-webpack5-plugin/config/rig.json b/heft-plugins/heft-webpack5-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-webpack5-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-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 new file mode 100644 index 00000000000..191a30e7cc6 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/heft-plugin.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "webpack5-plugin", + "entryPoint": "./lib/Webpack5Plugin", + "optionsSchema": "./lib/schemas/heft-webpack5-plugin.schema.json", + + "parameterScope": "webpack5", + "parameters": [ + { + "longName": "--serve", + "parameterKind": "flag", + "description": "Start a local web server for testing purposes using webpack-dev-server. This parameter is only available when running in watch mode." + } + ] + } + ] +} diff --git a/heft-plugins/heft-webpack5-plugin/package.json b/heft-plugins/heft-webpack5-plugin/package.json new file mode 100644 index 00000000000..fc06080e7c2 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/heft-webpack5-plugin", + "version": "1.2.7", + "description": "Heft plugin for Webpack 5", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-webpack5-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "lib/index.js", + "types": "dist/heft-webpack5-plugin.d.ts", + "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.1.7", + "webpack": "^5.82.1" + }, + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@types/tapable": "1.0.6", + "tapable": "1.1.3", + "watchpack": "2.4.0", + "webpack-dev-server": "^5.1.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/watchpack": "2.4.0", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.98.0" + } +} diff --git a/heft-plugins/heft-webpack5-plugin/src/DeferredWatchFileSystem.ts b/heft-plugins/heft-webpack5-plugin/src/DeferredWatchFileSystem.ts new file mode 100644 index 00000000000..302e367ed9b --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/DeferredWatchFileSystem.ts @@ -0,0 +1,219 @@ +// 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, WebpackPluginInstance, InputFileSystem } from 'webpack'; + +export type { InputFileSystem }; +export type WatchFileSystem = NonNullable; +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(); + + // 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 WebpackPluginInstance { + 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-webpack5-plugin/src/Webpack5Plugin.ts b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts new file mode 100644 index 00000000000..59bf0c4b725 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts @@ -0,0 +1,523 @@ +// 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 TWebpack from 'webpack'; +import type TWebpackDevServer from 'webpack-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 IWebpackConfiguration, + type IWebpackPluginAccessor, + PLUGIN_NAME, + type IWebpackPluginAccessorHooks +} from './shared'; +import { tryLoadWebpackConfigurationAsync } from './WebpackConfigurationLoader'; +import { type DeferredWatchFileSystem, OverrideNodeWatchFSPlugin } from './DeferredWatchFileSystem'; + +export interface IWebpackPluginOptions { + devConfigurationPath?: string | undefined; + configurationPath?: string | undefined; +} +const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; +const WEBPACK_PACKAGE_NAME: 'webpack' = 'webpack'; +const WEBPACK_DEV_SERVER_PACKAGE_NAME: 'webpack-dev-server' = 'webpack-dev-server'; +const WEBPACK_DEV_SERVER_ENV_VAR_NAME: 'WEBPACK_DEV_SERVER' = 'WEBPACK_DEV_SERVER'; +const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-dev-middleware'; + +/** + * @internal + */ +export default class Webpack5Plugin implements IHeftTaskPlugin { + private _accessor: IWebpackPluginAccessor | undefined; + private _isServeMode: boolean = false; + private _webpack: typeof TWebpack | undefined; + private _webpackCompiler: TWebpack.Compiler | TWebpack.MultiCompiler | undefined; + private _webpackConfiguration: IWebpackConfiguration | undefined | false = false; + private _webpackCompilationDonePromise: Promise | undefined; + private _webpackCompilationDonePromiseResolveFn: (() => void) | undefined; + private _watchFileSystems: Set | undefined; + + private _warnings: Error[] = []; + private _errors: Error[] = []; + + public get accessor(): IWebpackPluginAccessor { + if (!this._accessor) { + this._accessor = { + hooks: _createAccessorHooks(), + parameters: { + isServeMode: this._isServeMode + } + }; + } + return this._accessor; + } + + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions = {} + ): 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._runWebpackAsync(taskSession, heftConfiguration, options); + }); + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runWebpackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + } + ); + } + + private async _getWebpackConfigurationAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions, + requestRun?: () => void + ): Promise { + if (this._webpackConfiguration === false) { + const webpackConfiguration: IWebpackConfiguration | undefined = await tryLoadWebpackConfigurationAsync( + { + taskSession, + heftConfiguration, + hooks: this.accessor.hooks, + serveMode: this._isServeMode, + loadWebpackAsyncFn: this._loadWebpackAsync.bind(this, taskSession, heftConfiguration) + }, + options + ); + + if (webpackConfiguration && requestRun) { + const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); + this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + for (const config of Array.isArray(webpackConfiguration) + ? webpackConfiguration + : [webpackConfiguration]) { + if (!config.plugins) { + config.plugins = [overrideWatchFSPlugin]; + } else { + config.plugins.unshift(overrideWatchFSPlugin); + } + } + } + + this._webpackConfiguration = webpackConfiguration; + } + + return this._webpackConfiguration; + } + + private async _loadWebpackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + if (!this._webpack) { + 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(taskSession, heftConfiguration); + taskSession.logger.terminal.writeLine(`Using Webpack version ${webpack.version}`); + this._webpackCompiler = Array.isArray(webpackConfiguration) + ? webpack.default(webpackConfiguration) /* (webpack.Compilation[]) => MultiCompiler */ + : webpack.default(webpackConfiguration); /* (webpack.Compilation) => Compiler */ + } + return this._webpackCompiler; + } + + private async _runWebpackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions + ): Promise { + this._validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this._isServeMode) { + // Should never happen, but just in case + throw new InternalError('Cannot run Webpack in compilation mode when watch mode is enabled'); + } + + // Load the config and compiler, and return if there is no config found + const webpackConfiguration: IWebpackConfiguration | undefined = await this._getWebpackConfigurationAsync( + taskSession, + heftConfiguration, + options + ); + if (!webpackConfiguration) { + return; + } + const compiler: TWebpack.Compiler | TWebpack.MultiCompiler = await this._getWebpackCompilerAsync( + taskSession, + heftConfiguration, + webpackConfiguration + ); + taskSession.logger.terminal.writeLine('Running Webpack compilation'); + + // Run the webpack compiler + let stats: TWebpack.Stats | TWebpack.MultiStats | undefined; + try { + stats = await LegacyAdapters.convertCallbackToPromise( + (compiler as TWebpack.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 _runWebpackWatchAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IWebpackPluginOptions, + requestRun: () => void + ): Promise { + // Save a handle to the original promise, since the this-scoped promise will be replaced whenever + // the compilation completes. + let webpackCompilationDonePromise: Promise | undefined = this._webpackCompilationDonePromise; + + let isInitial: boolean = false; + + if (!this._webpackCompiler) { + isInitial = true; + this._validateEnvironmentVariable(taskSession); + if (!taskSession.parameters.watch) { + // Should never happen, but just in case + throw new InternalError('Cannot run Webpack in watch mode when watch mode is not enabled'); + } + + // Load the config and compiler, and return if there is no config found + const webpackConfiguration: IWebpackConfiguration | undefined = + await this._getWebpackConfigurationAsync(taskSession, heftConfiguration, options, requestRun); + if (!webpackConfiguration) { + return; + } + + // Get the compiler which will be used for both serve and watch mode + const compiler: TWebpack.Compiler | TWebpack.MultiCompiler = await this._getWebpackCompilerAsync( + taskSession, + heftConfiguration, + webpackConfiguration + ); + + // 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._webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this._webpackCompilationDonePromiseResolveFn = resolve; + }); + webpackCompilationDonePromise = this._webpackCompilationDonePromise; + compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TWebpack.Stats | TWebpack.MultiStats) => { + this._webpackCompilationDonePromiseResolveFn!(); + this._webpackCompilationDonePromise = new Promise((resolve: () => void) => { + this._webpackCompilationDonePromiseResolveFn = resolve; + }); + + if (stats) { + this._recordErrors(stats, heftConfiguration.buildFolderPath); + } + }); + + // Determine how we will run the compiler. When serving, we will run the compiler + // via the webpack-dev-server. Otherwise, we will run the compiler directly. + if (this._isServeMode) { + const defaultDevServerOptions: TWebpackDevServer.Configuration = { + host: 'localhost', + devMiddleware: { + publicPath: '/', + stats: { + cached: false, + cachedAssets: false, + colors: heftConfiguration.terminalProvider.supportsColor + } + }, + client: { + logging: 'info', + webSocketURL: { + port: 8080 + } + }, + port: 8080, + onListening: (server: TWebpackDevServer) => { + 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 Webpack Dev Server at ${url}`); + } + } + }; + + // Obtain the devServerOptions from the webpack configuration, and combine with the default options + let devServerOptions: TWebpackDevServer.Configuration; + if (Array.isArray(webpackConfiguration)) { + const filteredDevServerOptions: TWebpackDevServer.Configuration[] = webpackConfiguration + .map((configuration) => configuration.devServer) + .filter((devServer): devServer is TWebpackDevServer.Configuration => !!devServer); + if (filteredDevServerOptions.length > 1) { + taskSession.logger.emitWarning( + new Error(`Detected multiple webpack devServer configurations, using the first one.`) + ); + } + devServerOptions = { ...defaultDevServerOptions, ...filteredDevServerOptions[0] }; + } else { + devServerOptions = { ...defaultDevServerOptions, ...webpackConfiguration.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: TWebpackDevServer.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. + 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. + taskSession.logger.terminal.writeLine('Starting webpack-dev-server'); + const WebpackDevServer: typeof TWebpackDevServer = (await import(WEBPACK_DEV_SERVER_PACKAGE_NAME)) + .default; + const webpackDevServer: TWebpackDevServer = new WebpackDevServer(devServerOptions, compiler); + await webpackDevServer.start(); + } else { + // Create the watcher. Compilation will start immediately after invoking watch(). + taskSession.logger.terminal.writeLine('Starting Webpack watcher'); + + const { onGetWatchOptions } = this.accessor.hooks; + + const watchOptions: Parameters[0] = onGetWatchOptions.isUsed() + ? await onGetWatchOptions.promise({}, webpackConfiguration) + : {}; + + 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 Webpack compilation'); + await webpackCompilationDonePromise; + } else { + taskSession.logger.terminal.writeLine( + 'Webpack has not detected changes. Listing previous diagnostics.' + ); + } + + this._emitErrors(taskSession.logger); + } + + private _validateEnvironmentVariable(taskSession: IHeftTaskSession): void { + if (!this._isServeMode && process.env[WEBPACK_DEV_SERVER_ENV_VAR_NAME]) { + taskSession.logger.emitWarning( + new Error( + `The "${WEBPACK_DEV_SERVER_ENV_VAR_NAME}" environment variable is set, ` + + 'which will cause problems when webpack is not running in serve mode. ' + + `(Did a dependency inadvertently load the "${WEBPACK_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: TWebpack.Stats | TWebpack.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: TWebpack.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: TWebpack.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(): IWebpackPluginAccessorHooks { + return { + onLoadConfiguration: new AsyncSeriesBailHook(), + onConfigure: new AsyncSeriesHook(['webpackConfiguration']), + onAfterConfigure: new AsyncParallelHook(['webpackConfiguration']), + onEmitStats: new AsyncParallelHook(['webpackStats']), + onGetWatchOptions: new AsyncSeriesWaterfallHook(['watchOptions', 'webpackConfiguration']) + }; +} diff --git a/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts new file mode 100644 index 00000000000..c8516cfbe1f --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/WebpackConfigurationLoader.ts @@ -0,0 +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 path from 'node:path'; + +import type * as TWebpack from 'webpack'; + +import { FileSystem } from '@rushstack/node-core-library'; +import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; + +import type { IWebpackPluginOptions } from './Webpack5Plugin'; +import { + PLUGIN_NAME, + STAGE_LOAD_LOCAL_CONFIG, + type IWebpackConfiguration, + type IWebpackConfigurationFnEnvironment, + type IWebpackPluginAccessorHooks +} from './shared'; + +type IWebpackConfigJsExport = + | TWebpack.Configuration + | TWebpack.Configuration[] + | Promise + | Promise + | ((env: IWebpackConfigurationFnEnvironment) => TWebpack.Configuration | TWebpack.Configuration[]) + | ((env: IWebpackConfigurationFnEnvironment) => Promise); +type IWebpackConfigJs = IWebpackConfigJsExport | { default: IWebpackConfigJsExport }; + +/** + * @internal + */ +export interface ILoadWebpackConfigurationOptions { + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + serveMode: boolean; + loadWebpackAsyncFn: () => Promise; + hooks: Pick; + + _tryLoadConfigFileAsync?: typeof tryLoadWebpackConfigurationFileAsync; +} + +const DEFAULT_WEBPACK_CONFIG_PATH: './webpack.config.js' = './webpack.config.js'; +const DEFAULT_WEBPACK_DEV_CONFIG_PATH: './webpack.dev.config.js' = './webpack.dev.config.js'; + +/** + * @internal + */ +export async function tryLoadWebpackConfigurationAsync( + options: ILoadWebpackConfigurationOptions, + pluginOptions: IWebpackPluginOptions +): Promise { + const { taskSession, hooks, _tryLoadConfigFileAsync = tryLoadWebpackConfigurationFileAsync } = options; + const { logger } = taskSession; + const { terminal } = logger; + + // Apply default behavior. Due to the state of `this._webpackConfiguration`, this code + // will execute exactly once. + hooks.onLoadConfiguration.tapPromise( + { + name: PLUGIN_NAME, + stage: STAGE_LOAD_LOCAL_CONFIG + }, + async () => { + terminal.writeVerboseLine(`Attempting to load Webpack configuration from local file`); + const webpackConfiguration: IWebpackConfiguration | undefined = await _tryLoadConfigFileAsync( + options, + pluginOptions + ); + + if (webpackConfiguration) { + terminal.writeVerboseLine(`Loaded Webpack configuration from local file.`); + } + + return webpackConfiguration; + } + ); + + // Obtain the webpack configuration by calling into the hook. + // The local configuration is loaded at STAGE_LOAD_LOCAL_CONFIG + terminal.writeVerboseLine('Attempting to load Webpack configuration'); + let webpackConfiguration: IWebpackConfiguration | false | undefined = + await hooks.onLoadConfiguration.promise(); + + if (webpackConfiguration === false) { + terminal.writeLine('Webpack disabled by external plugin'); + webpackConfiguration = undefined; + } else if ( + webpackConfiguration === undefined || + (Array.isArray(webpackConfiguration) && webpackConfiguration.length === 0) + ) { + terminal.writeLine('No Webpack configuration found'); + webpackConfiguration = undefined; + } else { + if (hooks.onConfigure.isUsed()) { + // Allow for plugins to customise the configuration + await hooks.onConfigure.promise(webpackConfiguration); + } + if (hooks.onAfterConfigure.isUsed()) { + // Provide the finalized configuration + await hooks.onAfterConfigure.promise(webpackConfiguration); + } + } + return webpackConfiguration; +} + +/** + * @internal + */ +export async function tryLoadWebpackConfigurationFileAsync( + options: ILoadWebpackConfigurationOptions, + pluginOptions: IWebpackPluginOptions +): Promise { + // TODO: Eventually replace this custom logic with a call to this utility in in webpack-cli: + // https://github.com/webpack/webpack-cli/blob/next/packages/webpack-cli/lib/groups/ConfigGroup.js + + const { taskSession, heftConfiguration, loadWebpackAsyncFn, serveMode } = options; + const { + logger, + parameters: { production } + } = taskSession; + const { terminal } = logger; + const { configurationPath, devConfigurationPath } = pluginOptions; + let webpackConfigJs: IWebpackConfigJs | undefined; + + try { + const buildFolderPath: string = heftConfiguration.buildFolderPath; + if (serveMode) { + const devConfigPath: string = path.resolve( + buildFolderPath, + devConfigurationPath || DEFAULT_WEBPACK_DEV_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load webpack configuration from "${devConfigPath}".`); + webpackConfigJs = await _tryLoadWebpackConfigurationFileInnerAsync(devConfigPath); + } + + if (!webpackConfigJs) { + const configPath: string = path.resolve( + buildFolderPath, + configurationPath || DEFAULT_WEBPACK_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load webpack configuration from "${configPath}".`); + webpackConfigJs = await _tryLoadWebpackConfigurationFileInnerAsync(configPath); + } + } catch (error) { + logger.emitError(error as Error); + } + + if (webpackConfigJs) { + const webpackConfig: IWebpackConfigJsExport = + (webpackConfigJs as { default: IWebpackConfigJsExport }).default || webpackConfigJs; + + if (typeof webpackConfig === 'function') { + // Defer loading of webpack until we know for sure that we will need it + return webpackConfig({ + prod: production, + production, + taskSession, + heftConfiguration, + webpack: await loadWebpackAsyncFn() + }); + } else { + return webpackConfig; + } + } else { + return undefined; + } +} + +/** + * @internal + */ +export async function _tryLoadWebpackConfigurationFileInnerAsync( + configurationPath: string +): Promise { + const configExists: boolean = await FileSystem.existsAsync(configurationPath); + if (configExists) { + try { + return await import(configurationPath); + } catch (e) { + const error: NodeJS.ErrnoException = e as NodeJS.ErrnoException; + if (error.code === 'ERR_MODULE_NOT_FOUND') { + // No configuration found, return undefined. + return undefined; + } + throw new Error(`Error loading webpack configuration at "${configurationPath}": ${e}`); + } + } else { + return undefined; + } +} diff --git a/heft-plugins/heft-webpack5-plugin/src/index.ts b/heft-plugins/heft-webpack5-plugin/src/index.ts new file mode 100644 index 00000000000..0ad82466ea3 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/index.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. + +export { PLUGIN_NAME as PluginName, STAGE_LOAD_LOCAL_CONFIG } from './shared'; + +export type { + IWebpackConfigurationWithDevServer, + IWebpackConfiguration, + IWebpackConfigurationFnEnvironment, + IWebpackPluginAccessor, + IWebpackPluginAccessorHooks, + IWebpackPluginAccessorParameters +} from './shared'; diff --git a/heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin.schema.json b/heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin.schema.json new file mode 100644 index 00000000000..8253d4b9761 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/schemas/heft-webpack5-plugin.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Webpack 5 Plugin Configuration", + "description": "Defines options for Webpack 5 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 Webpack dev configuration, which is used in \"serve\" mode. The default value is \"./webpack.dev.config.js\".", + "type": "string" + }, + + "configurationPath": { + "description": "Specifies a relative path to the Webpack configuration. The default value is \"./webpack.config.js\".", + "type": "string" + } + } +} diff --git a/heft-plugins/heft-webpack5-plugin/src/shared.ts b/heft-plugins/heft-webpack5-plugin/src/shared.ts new file mode 100644 index 00000000000..7975bcec0c0 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/shared.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as TWebpack from 'webpack'; +import type { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server'; +import type { + AsyncParallelHook, + AsyncSeriesBailHook, + AsyncSeriesHook, + AsyncSeriesWaterfallHook +} from 'tapable'; + +import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; + +/** + * The environment passed into the Webpack configuration function. Loosely based + * on the default Webpack environment options, specified here: + * https://webpack.js.org/api/cli/#environment-options + * + * @public + */ +export interface IWebpackConfigurationFnEnvironment { + /** + * Whether or not the run is in production mode. Synonym of + * {@link IWebpackConfigurationFnEnvironment.production}. + */ + prod: boolean; + /** + * Whether or not the run is in production mode. Synonym of + * {@link IWebpackConfigurationFnEnvironment.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 Webpack package. + */ + webpack: typeof TWebpack; +} + +/** + * @public + */ +export interface IWebpackConfigurationWithDevServer extends TWebpack.Configuration { + devServer?: WebpackDevServerConfiguration; +} + +/** + * @public + */ +export type IWebpackConfiguration = IWebpackConfigurationWithDevServer | IWebpackConfigurationWithDevServer[]; + +/** + * @public + */ +export interface IWebpackPluginAccessorHooks { + /** + * A hook that allows for loading custom configurations used by the Webpack + * plugin. If a tap returns a value other than `undefined` before stage {@link STAGE_LOAD_LOCAL_CONFIG}, + * it will suppress loading from the webpack 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 webpack from running. + */ + readonly onLoadConfiguration: AsyncSeriesBailHook; + /** + * A hook that allows for modification of the loaded configuration used by the Webpack + * plugin. If no configuration was loaded, this hook will not be called. + */ + readonly onConfigure: AsyncSeriesHook; + /** + * A hook that provides the finalized configuration that will be used by Webpack. + * If no configuration was loaded, this hook will not be called. + */ + readonly onAfterConfigure: AsyncParallelHook; + /** + * A hook that provides the stats output from Webpack. If no configuration is loaded, + * this hook will not be called. + */ + readonly onEmitStats: AsyncParallelHook; + /** + * 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 + >; +} + +/** + * @public + */ +export interface IWebpackPluginAccessorParameters { + /** + * Whether or not serve mode was enabled by passing the `--serve` flag. + */ + readonly isServeMode: boolean; +} + +/** + * @public + */ +export interface IWebpackPluginAccessor { + /** + * Hooks that are called at various points in the Webpack plugin lifecycle. + */ + readonly hooks: IWebpackPluginAccessorHooks; + /** + * Parameters that are provided by the Webpack plugin. + */ + readonly parameters: IWebpackPluginAccessorParameters; +} + +/** + * The stage in the `onLoadConfiguration` hook at which the config will be loaded from the local + * webpack config file. + * @public + */ +export const STAGE_LOAD_LOCAL_CONFIG: 1000 = 1000; + +/** + * @public + */ +export const PLUGIN_NAME: 'webpack5-plugin' = 'webpack5-plugin'; diff --git a/heft-plugins/heft-webpack5-plugin/src/test/WebpackConfigurationLoader.test.ts b/heft-plugins/heft-webpack5-plugin/src/test/WebpackConfigurationLoader.test.ts new file mode 100644 index 00000000000..855acc231cf --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/src/test/WebpackConfigurationLoader.test.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { HeftConfiguration, IHeftParameters, IHeftTaskSession, IScopedLogger } from '@rushstack/heft'; +import { MockScopedLogger } from '@rushstack/heft/lib/pluginFramework/logging/MockScopedLogger'; +import { type ITerminal, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import * as WebpackConfigurationLoader from '../WebpackConfigurationLoader'; +import { _createAccessorHooks } from '../Webpack5Plugin'; +import { type IWebpackConfiguration, STAGE_LOAD_LOCAL_CONFIG } from '../shared'; + +interface IMockLoadWebpackConfigurationOptions + extends WebpackConfigurationLoader.ILoadWebpackConfigurationOptions { + loadWebpackAsyncFn: jest.Mock; + _terminalProvider: StringBufferTerminalProvider; + _tryLoadConfigFileAsync: jest.Mock; +} + +describe(WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync.name, () => { + function createOptions(production: boolean, serveMode: boolean): IMockLoadWebpackConfigurationOptions { + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + const logger: IScopedLogger = new MockScopedLogger(terminal); + const buildFolderPath: string = __dirname; + + const parameters: Partial = { + production + }; + + const taskSession: IHeftTaskSession = { + logger, + parameters: parameters as unknown as IHeftParameters, + // Other values unused during these tests + hooks: undefined!, + parsedCommandLine: undefined!, + requestAccessToPluginByName: undefined!, + taskName: 'webpack', + tempFolderPath: `${__dirname}/temp` + }; + + const heftConfiguration: Partial = { + buildFolderPath + }; + + return { + taskSession, + heftConfiguration: heftConfiguration as unknown as HeftConfiguration, + hooks: _createAccessorHooks(), + loadWebpackAsyncFn: jest.fn(), + serveMode, + + _terminalProvider: terminalProvider, + _tryLoadConfigFileAsync: jest.fn() + }; + } + + it(`onLoadConfiguration can return false`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onLoadConfiguration: jest.Mock = jest.fn(); + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onLoadConfiguration.tap('test', onLoadConfiguration); + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + onLoadConfiguration.mockReturnValue(false); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBeUndefined(); + expect(onLoadConfiguration).toHaveBeenCalledTimes(1); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(0); + expect(onConfigure).toHaveBeenCalledTimes(0); + expect(onAfterConfigure).toHaveBeenCalledTimes(0); + }); + + it(`calls tryLoadWebpackConfigurationFileAsync`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(undefined)); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBeUndefined(); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(0); + expect(onAfterConfigure).toHaveBeenCalledTimes(0); + }); + + it(`can fall back`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onLoadConfiguration: jest.Mock = jest.fn(); + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onLoadConfiguration.tap( + { name: 'test', stage: STAGE_LOAD_LOCAL_CONFIG + 1 }, + onLoadConfiguration + ); + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(undefined)); + + const mockConfig: IWebpackConfiguration = {}; + onLoadConfiguration.mockReturnValue(mockConfig); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBe(mockConfig); + + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onLoadConfiguration).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(1); + expect(onAfterConfigure).toHaveBeenCalledTimes(1); + + expect(onConfigure).toHaveBeenCalledWith(mockConfig); + expect(onAfterConfigure).toHaveBeenCalledWith(mockConfig); + }); + + it(`respects hook order`, async () => { + const options: IMockLoadWebpackConfigurationOptions = createOptions(false, false); + + const onConfigure: jest.Mock = jest.fn(); + const onAfterConfigure: jest.Mock = jest.fn(); + + options.hooks.onConfigure.tap('test', onConfigure); + options.hooks.onAfterConfigure.tap('test', onAfterConfigure); + + const mockConfig: IWebpackConfiguration = {}; + + options._tryLoadConfigFileAsync.mockReturnValue(Promise.resolve(mockConfig)); + + const config: IWebpackConfiguration | undefined = + await WebpackConfigurationLoader.tryLoadWebpackConfigurationAsync(options, {}); + expect(config).toBe(mockConfig); + expect(options._tryLoadConfigFileAsync).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledTimes(1); + expect(onConfigure).toHaveBeenCalledWith(mockConfig); + expect(onAfterConfigure).toHaveBeenCalledTimes(1); + expect(onAfterConfigure).toHaveBeenCalledWith(mockConfig); + }); +}); diff --git a/heft-plugins/heft-webpack5-plugin/tsconfig.json b/heft-plugins/heft-webpack5-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/api-extractor-model/.npmignore b/libraries/api-extractor-model/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/api-extractor-model/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/api-extractor-model/CHANGELOG.json b/libraries/api-extractor-model/CHANGELOG.json new file mode 100644 index 00000000000..ba89baed45d --- /dev/null +++ b/libraries/api-extractor-model/CHANGELOG.json @@ -0,0 +1,2877 @@ +{ + "name": "@microsoft/api-extractor-model", + "entries": [ + { + "version": "7.32.2", + "tag": "@microsoft/api-extractor-model_v7.32.2", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + } + ] + } + }, + { + "version": "7.32.1", + "tag": "@microsoft/api-extractor-model_v7.32.1", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + } + ] + } + }, + { + "version": "7.32.0", + "tag": "@microsoft/api-extractor-model_v7.32.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`." + } + ] + } + }, + { + "version": "7.31.3", + "tag": "@microsoft/api-extractor-model_v7.31.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + } + ] + } + }, + { + "version": "7.31.2", + "tag": "@microsoft/api-extractor-model_v7.31.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + } + ] + } + }, + { + "version": "7.31.1", + "tag": "@microsoft/api-extractor-model_v7.31.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + } + ] + } + }, + { + "version": "7.31.0", + "tag": "@microsoft/api-extractor-model_v7.31.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`" + } + ] + } + }, + { + "version": "7.30.9", + "tag": "@microsoft/api-extractor-model_v7.30.9", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + } + ] + } + }, + { + "version": "7.30.8", + "tag": "@microsoft/api-extractor-model_v7.30.8", + "date": "Tue, 30 Sep 2025 20:33:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + } + ] + } + }, + { + "version": "7.30.7", + "tag": "@microsoft/api-extractor-model_v7.30.7", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + } + ] + } + }, + { + "version": "7.30.6", + "tag": "@microsoft/api-extractor-model_v7.30.6", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + } + ] + } + }, + { + "version": "7.30.5", + "tag": "@microsoft/api-extractor-model_v7.30.5", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + } + ] + } + }, + { + "version": "7.30.4", + "tag": "@microsoft/api-extractor-model_v7.30.4", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + } + ] + } + }, + { + "version": "7.30.3", + "tag": "@microsoft/api-extractor-model_v7.30.3", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + } + ] + } + }, + { + "version": "7.30.2", + "tag": "@microsoft/api-extractor-model_v7.30.2", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + } + ] + } + }, + { + "version": "7.30.1", + "tag": "@microsoft/api-extractor-model_v7.30.1", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + } + ] + } + }, + { + "version": "7.30.0", + "tag": "@microsoft/api-extractor-model_v7.30.0", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "minor": [ + { + "comment": "Update TSDoc dependencies." + } + ] + } + }, + { + "version": "7.29.9", + "tag": "@microsoft/api-extractor-model_v7.29.9", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + } + ] + } + }, + { + "version": "7.29.8", + "tag": "@microsoft/api-extractor-model_v7.29.8", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + } + ] + } + }, + { + "version": "7.29.7", + "tag": "@microsoft/api-extractor-model_v7.29.7", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + } + ] + } + }, + { + "version": "7.29.6", + "tag": "@microsoft/api-extractor-model_v7.29.6", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + } + ] + } + }, + { + "version": "7.29.5", + "tag": "@microsoft/api-extractor-model_v7.29.5", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + } + ] + } + }, + { + "version": "7.29.4", + "tag": "@microsoft/api-extractor-model_v7.29.4", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + } + ] + } + }, + { + "version": "7.29.3", + "tag": "@microsoft/api-extractor-model_v7.29.3", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + } + ] + } + }, + { + "version": "7.29.2", + "tag": "@microsoft/api-extractor-model_v7.29.2", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + } + ] + } + }, + { + "version": "7.29.1", + "tag": "@microsoft/api-extractor-model_v7.29.1", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + } + ] + } + }, + { + "version": "7.29.0", + "tag": "@microsoft/api-extractor-model_v7.29.0", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Bump TSDoc dependencies." + } + ] + } + }, + { + "version": "7.28.21", + "tag": "@microsoft/api-extractor-model_v7.28.21", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + } + ] + } + }, + { + "version": "7.28.20", + "tag": "@microsoft/api-extractor-model_v7.28.20", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + } + ] + } + }, + { + "version": "7.28.19", + "tag": "@microsoft/api-extractor-model_v7.28.19", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + } + ] + } + }, + { + "version": "7.28.18", + "tag": "@microsoft/api-extractor-model_v7.28.18", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + } + ] + } + }, + { + "version": "7.28.17", + "tag": "@microsoft/api-extractor-model_v7.28.17", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + } + ] + } + }, + { + "version": "7.28.16", + "tag": "@microsoft/api-extractor-model_v7.28.16", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + } + ] + } + }, + { + "version": "7.28.15", + "tag": "@microsoft/api-extractor-model_v7.28.15", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + } + ] + } + }, + { + "version": "7.28.14", + "tag": "@microsoft/api-extractor-model_v7.28.14", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + } + ] + } + }, + { + "version": "7.28.13", + "tag": "@microsoft/api-extractor-model_v7.28.13", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + } + ] + } + }, + { + "version": "7.28.12", + "tag": "@microsoft/api-extractor-model_v7.28.12", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + } + ] + } + }, + { + "version": "7.28.11", + "tag": "@microsoft/api-extractor-model_v7.28.11", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a formatting issue with the LICENSE." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + } + ] + } + }, + { + "version": "7.28.10", + "tag": "@microsoft/api-extractor-model_v7.28.10", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + } + ] + } + }, + { + "version": "7.28.9", + "tag": "@microsoft/api-extractor-model_v7.28.9", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + } + ] + } + }, + { + "version": "7.28.8", + "tag": "@microsoft/api-extractor-model_v7.28.8", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + } + ] + } + }, + { + "version": "7.28.7", + "tag": "@microsoft/api-extractor-model_v7.28.7", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + } + ] + } + }, + { + "version": "7.28.6", + "tag": "@microsoft/api-extractor-model_v7.28.6", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + } + ] + } + }, + { + "version": "7.28.5", + "tag": "@microsoft/api-extractor-model_v7.28.5", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + } + ] + } + }, + { + "version": "7.28.4", + "tag": "@microsoft/api-extractor-model_v7.28.4", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + } + ] + } + }, + { + "version": "7.28.3", + "tag": "@microsoft/api-extractor-model_v7.28.3", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + } + ] + } + }, + { + "version": "7.28.2", + "tag": "@microsoft/api-extractor-model_v7.28.2", + "date": "Thu, 28 Sep 2023 20:53:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + } + ] + } + }, + { + "version": "7.28.1", + "tag": "@microsoft/api-extractor-model_v7.28.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + } + ] + } + }, + { + "version": "7.28.0", + "tag": "@microsoft/api-extractor-model_v7.28.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "7.27.6", + "tag": "@microsoft/api-extractor-model_v7.27.6", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "7.27.5", + "tag": "@microsoft/api-extractor-model_v7.27.5", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + } + ] + } + }, + { + "version": "7.27.4", + "tag": "@microsoft/api-extractor-model_v7.27.4", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + } + ] + } + }, + { + "version": "7.27.3", + "tag": "@microsoft/api-extractor-model_v7.27.3", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "7.27.2", + "tag": "@microsoft/api-extractor-model_v7.27.2", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "7.27.1", + "tag": "@microsoft/api-extractor-model_v7.27.1", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + } + ] + } + }, + { + "version": "7.27.0", + "tag": "@microsoft/api-extractor-model_v7.27.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the TypeScript dependency to ~5.0.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "7.26.9", + "tag": "@microsoft/api-extractor-model_v7.26.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + } + ] + } + }, + { + "version": "7.26.8", + "tag": "@microsoft/api-extractor-model_v7.26.8", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a mistake in the documentation for ApiParameterListMixin.overloadIndex" + } + ] + } + }, + { + "version": "7.26.7", + "tag": "@microsoft/api-extractor-model_v7.26.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + } + ] + } + }, + { + "version": "7.26.6", + "tag": "@microsoft/api-extractor-model_v7.26.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + } + ] + } + }, + { + "version": "7.26.5", + "tag": "@microsoft/api-extractor-model_v7.26.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + } + ] + } + }, + { + "version": "7.26.4", + "tag": "@microsoft/api-extractor-model_v7.26.4", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "7.26.3", + "tag": "@microsoft/api-extractor-model_v7.26.3", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + } + ] + } + }, + { + "version": "7.26.2", + "tag": "@microsoft/api-extractor-model_v7.26.2", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + } + ] + } + }, + { + "version": "7.26.1", + "tag": "@microsoft/api-extractor-model_v7.26.1", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + } + ] + } + }, + { + "version": "7.26.0", + "tag": "@microsoft/api-extractor-model_v7.26.0", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "minor": [ + { + "comment": "Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)" + } + ] + } + }, + { + "version": "7.25.3", + "tag": "@microsoft/api-extractor-model_v7.25.3", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + } + ] + } + }, + { + "version": "7.25.2", + "tag": "@microsoft/api-extractor-model_v7.25.2", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "patch": [ + { + "comment": "Update the @microsoft/tsdoc dependency version to 0.14.2." + } + ] + } + }, + { + "version": "7.25.1", + "tag": "@microsoft/api-extractor-model_v7.25.1", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + } + ] + } + }, + { + "version": "7.25.0", + "tag": "@microsoft/api-extractor-model_v7.25.0", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new fileUrlPath property to relevant API items and serialize this to the .api.json. Additionally, add a SourceFile helper class for constructing file URLs from these paths and the projectFolderUrl." + } + ] + } + }, + { + "version": "7.24.4", + "tag": "@microsoft/api-extractor-model_v7.24.4", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "7.24.3", + "tag": "@microsoft/api-extractor-model_v7.24.3", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "7.24.2", + "tag": "@microsoft/api-extractor-model_v7.24.2", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + } + ] + } + }, + { + "version": "7.24.1", + "tag": "@microsoft/api-extractor-model_v7.24.1", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "7.24.0", + "tag": "@microsoft/api-extractor-model_v7.24.0", + "date": "Fri, 02 Sep 2022 17:48:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add new ApiExportedMixin mixin class for determining whether an API item is exported or not" + } + ] + } + }, + { + "version": "7.23.3", + "tag": "@microsoft/api-extractor-model_v7.23.3", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + } + ] + } + }, + { + "version": "7.23.2", + "tag": "@microsoft/api-extractor-model_v7.23.2", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "patch": [ + { + "comment": "Remove use of LegacyAdapters.sortStable" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + } + ] + } + }, + { + "version": "7.23.1", + "tag": "@microsoft/api-extractor-model_v7.23.1", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + } + ] + } + }, + { + "version": "7.23.0", + "tag": "@microsoft/api-extractor-model_v7.23.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript dependency to 4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "7.22.2", + "tag": "@microsoft/api-extractor-model_v7.22.2", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + } + ] + } + }, + { + "version": "7.22.1", + "tag": "@microsoft/api-extractor-model_v7.22.1", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "patch": [ + { + "comment": "Improve IFindApiItemMessage and fix two small bugs with ApiItemContainerMixin.findMembersWithInheritance()" + } + ] + } + }, + { + "version": "7.22.0", + "tag": "@microsoft/api-extractor-model_v7.22.0", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new ApiItemContainerMixin.findMembersWithInheritance() method for finding an item's inherited members" + } + ] + } + }, + { + "version": "7.21.0", + "tag": "@microsoft/api-extractor-model_v7.21.0", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "minor": [ + { + "comment": "Update model to reflect that index signatures can also be readonly" + } + ] + } + }, + { + "version": "7.20.3", + "tag": "@microsoft/api-extractor-model_v7.20.3", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + } + ] + } + }, + { + "version": "7.20.2", + "tag": "@microsoft/api-extractor-model_v7.20.2", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "7.20.1", + "tag": "@microsoft/api-extractor-model_v7.20.1", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + } + ] + } + }, + { + "version": "7.20.0", + "tag": "@microsoft/api-extractor-model_v7.20.0", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new initializerTokenRange field to ApiProperty and ApiVariable items." + } + ] + } + }, + { + "version": "7.19.1", + "tag": "@microsoft/api-extractor-model_v7.19.1", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + } + ] + } + }, + { + "version": "7.19.0", + "tag": "@microsoft/api-extractor-model_v7.19.0", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "minor": [ + { + "comment": "Added new configuration for ItemContainerMixin member ordering" + } + ] + } + }, + { + "version": "7.18.2", + "tag": "@microsoft/api-extractor-model_v7.18.2", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + } + ] + } + }, + { + "version": "7.18.1", + "tag": "@microsoft/api-extractor-model_v7.18.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "7.18.0", + "tag": "@microsoft/api-extractor-model_v7.18.0", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add an \"isReadonly\" field to ApiProperty, ApiPropertySignature, and ApiVariable" + }, + { + "comment": "Add an \"isProtected\" field to ApiConstructor, ApiMethod, and ApiProperty" + } + ] + } + }, + { + "version": "7.17.3", + "tag": "@microsoft/api-extractor-model_v7.17.3", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + } + ] + } + }, + { + "version": "7.17.2", + "tag": "@microsoft/api-extractor-model_v7.17.2", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "7.17.1", + "tag": "@microsoft/api-extractor-model_v7.17.1", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "7.17.0", + "tag": "@microsoft/api-extractor-model_v7.17.0", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new isOptional property to TypeParameters deserialized from the .api.json file with api-extractor-model." + } + ] + } + }, + { + "version": "7.16.2", + "tag": "@microsoft/api-extractor-model_v7.16.2", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "patch": [ + { + "comment": "Update TSDoc dependencies." + } + ] + } + }, + { + "version": "7.16.1", + "tag": "@microsoft/api-extractor-model_v7.16.1", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + }, + { + "comment": "Update a path in the README." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "7.16.0", + "tag": "@microsoft/api-extractor-model_v7.16.0", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "minor": [ + { + "comment": "Updated api-extractor-model to store whether a parameter is optional." + } + ] + } + }, + { + "version": "7.15.4", + "tag": "@microsoft/api-extractor-model_v7.15.4", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "7.15.3", + "tag": "@microsoft/api-extractor-model_v7.15.3", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + } + ] + } + }, + { + "version": "7.15.2", + "tag": "@microsoft/api-extractor-model_v7.15.2", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "7.15.1", + "tag": "@microsoft/api-extractor-model_v7.15.1", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + } + ] + } + }, + { + "version": "7.15.0", + "tag": "@microsoft/api-extractor-model_v7.15.0", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "minor": [ + { + "comment": "Replace const enums with conventional enums to allow for compatibility with JavaScript consumers." + } + ] + } + }, + { + "version": "7.14.0", + "tag": "@microsoft/api-extractor-model_v7.14.0", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.5" + } + ] + } + }, + { + "version": "7.13.18", + "tag": "@microsoft/api-extractor-model_v7.13.18", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "7.13.17", + "tag": "@microsoft/api-extractor-model_v7.13.17", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + } + ] + } + }, + { + "version": "7.13.16", + "tag": "@microsoft/api-extractor-model_v7.13.16", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + } + ] + } + }, + { + "version": "7.13.15", + "tag": "@microsoft/api-extractor-model_v7.13.15", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "7.13.14", + "tag": "@microsoft/api-extractor-model_v7.13.14", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "7.13.13", + "tag": "@microsoft/api-extractor-model_v7.13.13", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "7.13.12", + "tag": "@microsoft/api-extractor-model_v7.13.12", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + } + ] + } + }, + { + "version": "7.13.11", + "tag": "@microsoft/api-extractor-model_v7.13.11", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "7.13.10", + "tag": "@microsoft/api-extractor-model_v7.13.10", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + } + ] + } + }, + { + "version": "7.13.9", + "tag": "@microsoft/api-extractor-model_v7.13.9", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + } + ] + } + }, + { + "version": "7.13.8", + "tag": "@microsoft/api-extractor-model_v7.13.8", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "7.13.7", + "tag": "@microsoft/api-extractor-model_v7.13.7", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + } + ] + } + }, + { + "version": "7.13.6", + "tag": "@microsoft/api-extractor-model_v7.13.6", + "date": "Mon, 13 Sep 2021 15:07:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + } + ] + } + }, + { + "version": "7.13.5", + "tag": "@microsoft/api-extractor-model_v7.13.5", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + } + ] + } + }, + { + "version": "7.13.4", + "tag": "@microsoft/api-extractor-model_v7.13.4", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "7.13.3", + "tag": "@microsoft/api-extractor-model_v7.13.3", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + } + ] + } + }, + { + "version": "7.13.2", + "tag": "@microsoft/api-extractor-model_v7.13.2", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + } + ] + } + }, + { + "version": "7.13.1", + "tag": "@microsoft/api-extractor-model_v7.13.1", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + } + ] + } + }, + { + "version": "7.13.0", + "tag": "@microsoft/api-extractor-model_v7.13.0", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "minor": [ + { + "comment": "The .api.json file format now stores the TSDoc configuration used for parsing doc comments" + } + ] + } + }, + { + "version": "7.12.5", + "tag": "@microsoft/api-extractor-model_v7.12.5", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "7.12.4", + "tag": "@microsoft/api-extractor-model_v7.12.4", + "date": "Thu, 08 Apr 2021 06:05:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix minor typo in README.md" + } + ] + } + }, + { + "version": "7.12.3", + "tag": "@microsoft/api-extractor-model_v7.12.3", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "7.12.2", + "tag": "@microsoft/api-extractor-model_v7.12.2", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + } + ] + } + }, + { + "version": "7.12.1", + "tag": "@microsoft/api-extractor-model_v7.12.1", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "patch": [ + { + "comment": "Enable support for @decorator" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "7.12.0", + "tag": "@microsoft/api-extractor-model_v7.12.0", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce an ApiOptionalMixin base class for representing optional properties and methods" + } + ] + } + }, + { + "version": "7.11.0", + "tag": "@microsoft/api-extractor-model_v7.11.0", + "date": "Wed, 18 Nov 2020 06:21:57 GMT", + "comments": { + "minor": [ + { + "comment": "Update .api.json file format to store a new field \"isOptional\" for documenting optional properties" + } + ] + } + }, + { + "version": "7.10.10", + "tag": "@microsoft/api-extractor-model_v7.10.10", + "date": "Wed, 11 Nov 2020 01:08:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "7.10.9", + "tag": "@microsoft/api-extractor-model_v7.10.9", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + } + ] + } + }, + { + "version": "7.10.8", + "tag": "@microsoft/api-extractor-model_v7.10.8", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "7.10.7", + "tag": "@microsoft/api-extractor-model_v7.10.7", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "7.10.6", + "tag": "@microsoft/api-extractor-model_v7.10.6", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "patch": [ + { + "comment": "Fix .d.ts error when the library is imported by a project using TypeScript 4.0" + } + ] + } + }, + { + "version": "7.10.5", + "tag": "@microsoft/api-extractor-model_v7.10.5", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "7.10.4", + "tag": "@microsoft/api-extractor-model_v7.10.4", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + } + ] + } + }, + { + "version": "7.10.3", + "tag": "@microsoft/api-extractor-model_v7.10.3", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + } + ] + } + }, + { + "version": "7.10.2", + "tag": "@microsoft/api-extractor-model_v7.10.2", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + } + ] + } + }, + { + "version": "7.10.1", + "tag": "@microsoft/api-extractor-model_v7.10.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + } + ] + } + }, + { + "version": "7.10.0", + "tag": "@microsoft/api-extractor-model_v7.10.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "minor": [ + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "7.9.7", + "tag": "@microsoft/api-extractor-model_v7.9.7", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "7.9.6", + "tag": "@microsoft/api-extractor-model_v7.9.6", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "7.9.5", + "tag": "@microsoft/api-extractor-model_v7.9.5", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "7.9.4", + "tag": "@microsoft/api-extractor-model_v7.9.4", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "7.9.3", + "tag": "@microsoft/api-extractor-model_v7.9.3", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "7.9.2", + "tag": "@microsoft/api-extractor-model_v7.9.2", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "7.9.1", + "tag": "@microsoft/api-extractor-model_v7.9.1", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + } + ] + } + }, + { + "version": "7.9.0", + "tag": "@microsoft/api-extractor-model_v7.9.0", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for system selectors in declaration references" + } + ] + } + }, + { + "version": "7.8.22", + "tag": "@microsoft/api-extractor-model_v7.8.22", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + } + ] + } + }, + { + "version": "7.8.21", + "tag": "@microsoft/api-extractor-model_v7.8.21", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + } + ] + } + }, + { + "version": "7.8.20", + "tag": "@microsoft/api-extractor-model_v7.8.20", + "date": "Sat, 05 Sep 2020 18:56:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix \"Converting circular structure to JSON\" error (GitHub #2152)" + } + ] + } + }, + { + "version": "7.8.19", + "tag": "@microsoft/api-extractor-model_v7.8.19", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + }, + { + "version": "7.8.18", + "tag": "@microsoft/api-extractor-model_v7.8.18", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + } + ] + } + }, + { + "version": "7.8.17", + "tag": "@microsoft/api-extractor-model_v7.8.17", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + } + ] + } + }, + { + "version": "7.8.16", + "tag": "@microsoft/api-extractor-model_v7.8.16", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + } + ] + } + }, + { + "version": "7.8.15", + "tag": "@microsoft/api-extractor-model_v7.8.15", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + } + ] + } + }, + { + "version": "7.8.14", + "tag": "@microsoft/api-extractor-model_v7.8.14", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + } + ] + } + }, + { + "version": "7.8.13", + "tag": "@microsoft/api-extractor-model_v7.8.13", + "date": "Wed, 05 Aug 2020 18:27:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + } + ] + } + }, + { + "version": "7.8.12", + "tag": "@microsoft/api-extractor-model_v7.8.12", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + } + ] + } + }, + { + "version": "7.8.11", + "tag": "@microsoft/api-extractor-model_v7.8.11", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "7.8.10", + "tag": "@microsoft/api-extractor-model_v7.8.10", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "7.8.9", + "tag": "@microsoft/api-extractor-model_v7.8.9", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "7.8.8", + "tag": "@microsoft/api-extractor-model_v7.8.8", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + } + ] + } + }, + { + "version": "7.8.7", + "tag": "@microsoft/api-extractor-model_v7.8.7", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + } + ] + } + }, + { + "version": "7.8.6", + "tag": "@microsoft/api-extractor-model_v7.8.6", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + } + ] + } + }, + { + "version": "7.8.5", + "tag": "@microsoft/api-extractor-model_v7.8.5", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "7.8.4", + "tag": "@microsoft/api-extractor-model_v7.8.4", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + } + ] + } + }, + { + "version": "7.8.3", + "tag": "@microsoft/api-extractor-model_v7.8.3", + "date": "Fri, 22 May 2020 15:08:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + } + ] + } + }, + { + "version": "7.8.2", + "tag": "@microsoft/api-extractor-model_v7.8.2", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + } + ] + } + }, + { + "version": "7.8.1", + "tag": "@microsoft/api-extractor-model_v7.8.1", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + } + ] + } + }, + { + "version": "7.8.0", + "tag": "@microsoft/api-extractor-model_v7.8.0", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "minor": [ + { + "comment": "Enable canonicalReference to ApiItem lookup" + } + ] + } + }, + { + "version": "7.7.11", + "tag": "@microsoft/api-extractor-model_v7.7.11", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "7.7.10", + "tag": "@microsoft/api-extractor-model_v7.7.10", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to TSdoc 0.12.19" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, + { + "version": "7.7.9", + "tag": "@microsoft/api-extractor-model_v7.7.9", + "date": "Wed, 18 Mar 2020 15:07:47 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade cyclic dependencies" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" + } + ] + } + }, + { + "version": "7.7.8", + "tag": "@microsoft/api-extractor-model_v7.7.8", + "date": "Tue, 17 Mar 2020 23:55:58 GMT", + "comments": { + "patch": [ + { + "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" + } + ] + } + }, + { + "version": "7.7.7", + "tag": "@microsoft/api-extractor-model_v7.7.7", + "date": "Tue, 28 Jan 2020 02:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.2` to `3.19.3`" + } + ] + } + }, + { + "version": "7.7.6", + "tag": "@microsoft/api-extractor-model_v7.7.6", + "date": "Thu, 23 Jan 2020 01:07:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.1` to `3.19.2`" + } + ] + } + }, + { + "version": "7.7.5", + "tag": "@microsoft/api-extractor-model_v7.7.5", + "date": "Tue, 21 Jan 2020 21:56:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.19.0` to `3.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.3` to `0.5.4`" + } + ] + } + }, + { + "version": "7.7.4", + "tag": "@microsoft/api-extractor-model_v7.7.4", + "date": "Sun, 19 Jan 2020 02:26:52 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade Node typings to Node 10" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.3` to `3.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.2` to `0.5.3`" + } + ] + } + }, + { + "version": "7.7.3", + "tag": "@microsoft/api-extractor-model_v7.7.3", + "date": "Fri, 17 Jan 2020 01:08:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.2` to `3.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.1` to `0.5.2`" + } + ] + } + }, + { + "version": "7.7.2", + "tag": "@microsoft/api-extractor-model_v7.7.2", + "date": "Thu, 09 Jan 2020 06:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.1` to `3.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.0` to `0.5.1`" + } + ] + } + }, + { + "version": "7.7.1", + "tag": "@microsoft/api-extractor-model_v7.7.1", + "date": "Wed, 08 Jan 2020 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.18.0` to `3.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.2` to `0.5.0`" + } + ] + } + }, + { + "version": "7.7.0", + "tag": "@microsoft/api-extractor-model_v7.7.0", + "date": "Tue, 03 Dec 2019 03:17:43 GMT", + "comments": { + "minor": [ + { + "comment": "Improve declaration reference syntax to allow linking to overloaded functions/methods" + } + ] + } + }, + { + "version": "7.6.0", + "tag": "@microsoft/api-extractor-model_v7.6.0", + "date": "Sun, 24 Nov 2019 00:54:04 GMT", + "comments": { + "minor": [ + { + "comment": "Added support for `@throws`" + } + ] + } + }, + { + "version": "7.5.6", + "tag": "@microsoft/api-extractor-model_v7.5.6", + "date": "Fri, 15 Nov 2019 04:50:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.1` to `3.18.0`" + } + ] + } + }, + { + "version": "7.5.5", + "tag": "@microsoft/api-extractor-model_v7.5.5", + "date": "Mon, 11 Nov 2019 16:07:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.17.0` to `3.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.1` to `0.4.2`" + } + ] + } + }, + { + "version": "7.5.4", + "tag": "@microsoft/api-extractor-model_v7.5.4", + "date": "Tue, 05 Nov 2019 06:49:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.16.0` to `3.17.0`" + } + ] + } + }, + { + "version": "7.5.3", + "tag": "@microsoft/api-extractor-model_v7.5.3", + "date": "Tue, 05 Nov 2019 01:08:39 GMT", + "comments": { + "patch": [ + { + "comment": "Clarified an error message" + } + ] + } + }, + { + "version": "7.5.2", + "tag": "@microsoft/api-extractor-model_v7.5.2", + "date": "Tue, 22 Oct 2019 06:24:44 GMT", + "comments": { + "patch": [ + { + "comment": "Refactor some code as part of migration from TSLint to ESLint" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.1` to `3.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.4.0` to `0.4.1`" + } + ] + } + }, + { + "version": "7.5.1", + "tag": "@microsoft/api-extractor-model_v7.5.1", + "date": "Sun, 29 Sep 2019 23:56:29 GMT", + "comments": { + "patch": [ + { + "comment": "Update repository URL" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.15.0` to `3.15.1`" + } + ] + } + }, + { + "version": "7.5.0", + "tag": "@microsoft/api-extractor-model_v7.5.0", + "date": "Wed, 25 Sep 2019 15:15:31 GMT", + "comments": { + "minor": [ + { + "comment": "Add ApiItem.getMergedSiblings() API" + } + ] + } + }, + { + "version": "7.4.2", + "tag": "@microsoft/api-extractor-model_v7.4.2", + "date": "Mon, 23 Sep 2019 15:14:55 GMT", + "comments": { + "patch": [ + { + "comment": "Remove unnecessary dependency on @types/node" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.2` to `3.15.0`" + } + ] + } + }, + { + "version": "7.4.1", + "tag": "@microsoft/api-extractor-model_v7.4.1", + "date": "Tue, 10 Sep 2019 22:32:23 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.1` to `3.14.2`" + } + ] + } + }, + { + "version": "7.4.0", + "tag": "@microsoft/api-extractor-model_v7.4.0", + "date": "Tue, 10 Sep 2019 20:38:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add 'canonicalReference' to ExcerptToken" + } + ] + } + }, + { + "version": "7.3.4", + "tag": "@microsoft/api-extractor-model_v7.3.4", + "date": "Wed, 04 Sep 2019 18:28:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.14.0` to `3.14.1`" + } + ] + } + }, + { + "version": "7.3.3", + "tag": "@microsoft/api-extractor-model_v7.3.3", + "date": "Wed, 04 Sep 2019 15:15:37 GMT", + "comments": { + "patch": [ + { + "comment": "Update TSDoc dependency to 0.12.14" + } + ] + } + }, + { + "version": "7.3.2", + "tag": "@microsoft/api-extractor-model_v7.3.2", + "date": "Thu, 08 Aug 2019 15:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.13.0` to `3.14.0`" + } + ] + } + }, + { + "version": "7.3.1", + "tag": "@microsoft/api-extractor-model_v7.3.1", + "date": "Thu, 08 Aug 2019 00:49:05 GMT", + "comments": { + "patch": [ + { + "comment": "(Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation" + } + ] + } + }, + { + "version": "7.3.0", + "tag": "@microsoft/api-extractor-model_v7.3.0", + "date": "Mon, 22 Jul 2019 19:13:10 GMT", + "comments": { + "minor": [ + { + "comment": "Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()`" + } + ] + } + }, + { + "version": "7.2.0", + "tag": "@microsoft/api-extractor-model_v7.2.0", + "date": "Tue, 11 Jun 2019 00:48:06 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the .api.json deserializer to validate the schema version and support backwards compatibility" + } + ], + "minor": [ + { + "comment": "Add API support for type parameters and type alias types" + } + ] + } + }, + { + "version": "7.1.3", + "tag": "@microsoft/api-extractor-model_v7.1.3", + "date": "Wed, 05 Jun 2019 19:12:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number" + } + ] + } + }, + { + "version": "7.1.2", + "tag": "@microsoft/api-extractor-model_v7.1.2", + "date": "Tue, 04 Jun 2019 05:51:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static" + } + ] + } + }, + { + "version": "7.1.1", + "tag": "@microsoft/api-extractor-model_v7.1.1", + "date": "Mon, 27 May 2019 04:13:44 GMT", + "comments": { + "patch": [ + { + "comment": "Make the strings returned by ApiItem.displayName less verbose" + }, + { + "comment": "Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage()" + } + ] + } + }, + { + "version": "7.1.0", + "tag": "@microsoft/api-extractor-model_v7.1.0", + "date": "Tue, 16 Apr 2019 11:01:37 GMT", + "comments": { + "minor": [ + { + "comment": "Initial stable release of API Extractor 7" + } + ] + } + }, + { + "version": "7.0.28", + "tag": "@microsoft/api-extractor-model_v7.0.28", + "date": "Wed, 20 Mar 2019 19:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.1` to `3.13.0`" + } + ] + } + }, + { + "version": "7.0.27", + "tag": "@microsoft/api-extractor-model_v7.0.27", + "date": "Mon, 18 Mar 2019 04:28:43 GMT", + "comments": { + "patch": [ + { + "comment": "Add helper functions for ReleaseTag" + }, + { + "comment": "Export IApiItemConstructor to eliminate the ae-forgotten-export warning" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-core-library\" from `3.12.0` to `3.12.1`" + } + ] + } + }, + { + "version": "7.0.26", + "tag": "@microsoft/api-extractor-model_v7.0.26", + "date": "Wed, 13 Mar 2019 19:13:14 GMT", + "comments": { + "patch": [ + { + "comment": "Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter" + } + ] + } + }, + { + "version": "7.0.25", + "tag": "@microsoft/api-extractor-model_v7.0.25", + "date": "Wed, 13 Mar 2019 01:14:05 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade TSDoc" + } + ] + } + }, + { + "version": "7.0.24", + "tag": "@microsoft/api-extractor-model_v7.0.24", + "date": "Mon, 11 Mar 2019 16:13:36 GMT", + "comments": { + "patch": [ + { + "comment": "Initial setup of new package @microsoft/api-extractor-model" + } + ] + } + } + ] +} diff --git a/libraries/api-extractor-model/CHANGELOG.md b/libraries/api-extractor-model/CHANGELOG.md new file mode 100644 index 00000000000..3d2ae041cdb --- /dev/null +++ b/libraries/api-extractor-model/CHANGELOG.md @@ -0,0 +1,1212 @@ +# Change Log - @microsoft/api-extractor-model + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 7.32.2 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 7.32.1 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 7.32.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.31.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 7.31.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 7.31.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 7.31.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 7.30.9 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 7.30.8 +Tue, 30 Sep 2025 20:33:50 GMT + +_Version update only_ + +## 7.30.7 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 7.30.6 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 7.30.5 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 7.30.4 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 7.30.3 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 7.30.2 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 7.30.1 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 7.30.0 +Sat, 23 Nov 2024 01:18:55 GMT + +### Minor changes + +- Update TSDoc dependencies. + +## 7.29.9 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 7.29.8 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 7.29.7 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 7.29.6 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 7.29.5 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 7.29.4 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 7.29.3 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 7.29.2 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 7.29.1 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 7.29.0 +Wed, 29 May 2024 00:10:52 GMT + +### Minor changes + +- Bump TSDoc dependencies. + +## 7.28.21 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 7.28.20 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 7.28.19 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 7.28.18 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 7.28.17 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 7.28.16 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 7.28.15 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 7.28.14 +Wed, 10 Apr 2024 15:10:08 GMT + +_Version update only_ + +## 7.28.13 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 7.28.12 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 7.28.11 +Mon, 19 Feb 2024 21:54:26 GMT + +### Patches + +- Fix a formatting issue with the LICENSE. + +## 7.28.10 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 7.28.9 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 7.28.8 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 7.28.7 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 7.28.6 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 7.28.5 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 7.28.4 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 7.28.3 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 7.28.2 +Thu, 28 Sep 2023 20:53:16 GMT + +_Version update only_ + +## 7.28.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 7.28.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 7.27.6 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 7.27.5 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 7.27.4 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 7.27.3 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 7.27.2 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 7.27.1 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 7.27.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade the TypeScript dependency to ~5.0.4 + +## 7.26.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 7.26.8 +Thu, 04 May 2023 00:20:28 GMT + +### Patches + +- Fix a mistake in the documentation for ApiParameterListMixin.overloadIndex + +## 7.26.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 7.26.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 7.26.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 7.26.4 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 7.26.3 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 7.26.2 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 7.26.1 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 7.26.0 +Wed, 25 Jan 2023 07:26:55 GMT + +### Minor changes + +- Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661) + +## 7.25.3 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 7.25.2 +Wed, 26 Oct 2022 00:16:16 GMT + +### Patches + +- Update the @microsoft/tsdoc dependency version to 0.14.2. + +## 7.25.1 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 7.25.0 +Tue, 11 Oct 2022 23:49:12 GMT + +### Minor changes + +- Add a new fileUrlPath property to relevant API items and serialize this to the .api.json. Additionally, add a SourceFile helper class for constructing file URLs from these paths and the projectFolderUrl. + +## 7.24.4 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 7.24.3 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 7.24.2 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 7.24.1 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 7.24.0 +Fri, 02 Sep 2022 17:48:42 GMT + +### Minor changes + +- Add new ApiExportedMixin mixin class for determining whether an API item is exported or not + +## 7.23.3 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 7.23.2 +Wed, 24 Aug 2022 00:14:38 GMT + +### Patches + +- Remove use of LegacyAdapters.sortStable + +## 7.23.1 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 7.23.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript dependency to 4.7 + +## 7.22.2 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 7.22.1 +Thu, 21 Jul 2022 23:30:27 GMT + +### Patches + +- Improve IFindApiItemMessage and fix two small bugs with ApiItemContainerMixin.findMembersWithInheritance() + +## 7.22.0 +Thu, 21 Jul 2022 00:16:14 GMT + +### Minor changes + +- Add a new ApiItemContainerMixin.findMembersWithInheritance() method for finding an item's inherited members + +## 7.21.0 +Thu, 30 Jun 2022 04:48:53 GMT + +### Minor changes + +- Update model to reflect that index signatures can also be readonly + +## 7.20.3 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 7.20.2 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 7.20.1 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 7.20.0 +Sat, 25 Jun 2022 21:00:40 GMT + +### Minor changes + +- Add a new initializerTokenRange field to ApiProperty and ApiVariable items. + +## 7.19.1 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 7.19.0 +Fri, 24 Jun 2022 07:16:47 GMT + +### Minor changes + +- Added new configuration for ItemContainerMixin member ordering + +## 7.18.2 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 7.18.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 7.18.0 +Tue, 07 Jun 2022 09:37:04 GMT + +### Minor changes + +- Add an "isReadonly" field to ApiProperty, ApiPropertySignature, and ApiVariable +- Add an "isProtected" field to ApiConstructor, ApiMethod, and ApiProperty + +## 7.17.3 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 7.17.2 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 7.17.1 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 7.17.0 +Wed, 13 Apr 2022 15:12:40 GMT + +### Minor changes + +- Add a new isOptional property to TypeParameters deserialized from the .api.json file with api-extractor-model. + +## 7.16.2 +Tue, 12 Apr 2022 02:58:32 GMT + +### Patches + +- Update TSDoc dependencies. + +## 7.16.1 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". +- Update a path in the README. + +## 7.16.0 +Thu, 31 Mar 2022 02:06:05 GMT + +### Minor changes + +- Updated api-extractor-model to store whether a parameter is optional. + +## 7.15.4 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 7.15.3 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 7.15.2 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 7.15.1 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 7.15.0 +Thu, 09 Dec 2021 00:21:54 GMT + +### Minor changes + +- Replace const enums with conventional enums to allow for compatibility with JavaScript consumers. + +## 7.14.0 +Wed, 08 Dec 2021 16:14:05 GMT + +### Minor changes + +- Update to TypeScript 4.5 + +## 7.13.18 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 7.13.17 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 7.13.16 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 7.13.15 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 7.13.14 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 7.13.13 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 7.13.12 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 7.13.11 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 7.13.10 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 7.13.9 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 7.13.8 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 7.13.7 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 7.13.6 +Mon, 13 Sep 2021 15:07:06 GMT + +_Version update only_ + +## 7.13.5 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 7.13.4 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 7.13.3 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 7.13.2 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 7.13.1 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 7.13.0 +Tue, 20 Apr 2021 04:59:51 GMT + +### Minor changes + +- The .api.json file format now stores the TSDoc configuration used for parsing doc comments + +## 7.12.5 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 7.12.4 +Thu, 08 Apr 2021 06:05:31 GMT + +### Patches + +- Fix minor typo in README.md + +## 7.12.3 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 7.12.2 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 7.12.1 +Thu, 10 Dec 2020 23:25:49 GMT + +### Patches + +- Enable support for @decorator + +## 7.12.0 +Wed, 18 Nov 2020 08:19:54 GMT + +### Minor changes + +- Introduce an ApiOptionalMixin base class for representing optional properties and methods + +## 7.11.0 +Wed, 18 Nov 2020 06:21:57 GMT + +### Minor changes + +- Update .api.json file format to store a new field "isOptional" for documenting optional properties + +## 7.10.10 +Wed, 11 Nov 2020 01:08:59 GMT + +_Version update only_ + +## 7.10.9 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 7.10.8 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 7.10.7 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 7.10.6 +Thu, 29 Oct 2020 06:14:19 GMT + +### Patches + +- Fix .d.ts error when the library is imported by a project using TypeScript 4.0 + +## 7.10.5 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 7.10.4 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 7.10.3 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 7.10.2 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 7.10.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 7.10.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 7.9.7 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 7.9.6 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 7.9.5 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 7.9.4 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 7.9.3 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 7.9.2 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 7.9.1 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 7.9.0 +Sun, 13 Sep 2020 01:53:20 GMT + +### Minor changes + +- Add support for system selectors in declaration references + +## 7.8.22 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 7.8.21 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 7.8.20 +Sat, 05 Sep 2020 18:56:34 GMT + +### Patches + +- Fix "Converting circular structure to JSON" error (GitHub #2152) + +## 7.8.19 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 7.8.18 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 7.8.17 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 7.8.16 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 7.8.15 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 7.8.14 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 7.8.13 +Wed, 05 Aug 2020 18:27:33 GMT + +_Version update only_ + +## 7.8.12 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 7.8.11 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 7.8.10 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 7.8.9 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 7.8.8 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 7.8.7 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 7.8.6 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 7.8.5 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 7.8.4 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 7.8.3 +Fri, 22 May 2020 15:08:43 GMT + +_Version update only_ + +## 7.8.2 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 7.8.1 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 7.8.0 +Wed, 06 May 2020 08:23:45 GMT + +### Minor changes + +- Enable canonicalReference to ApiItem lookup + +## 7.7.11 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 7.7.10 +Sat, 28 Mar 2020 00:37:16 GMT + +### Patches + +- Upgrade to TSdoc 0.12.19 + +## 7.7.9 +Wed, 18 Mar 2020 15:07:47 GMT + +### Patches + +- Upgrade cyclic dependencies + +## 7.7.8 +Tue, 17 Mar 2020 23:55:58 GMT + +### Patches + +- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` + +## 7.7.7 +Tue, 28 Jan 2020 02:23:44 GMT + +_Version update only_ + +## 7.7.6 +Thu, 23 Jan 2020 01:07:56 GMT + +_Version update only_ + +## 7.7.5 +Tue, 21 Jan 2020 21:56:14 GMT + +_Version update only_ + +## 7.7.4 +Sun, 19 Jan 2020 02:26:52 GMT + +### Patches + +- Upgrade Node typings to Node 10 + +## 7.7.3 +Fri, 17 Jan 2020 01:08:23 GMT + +_Version update only_ + +## 7.7.2 +Thu, 09 Jan 2020 06:44:13 GMT + +_Version update only_ + +## 7.7.1 +Wed, 08 Jan 2020 00:11:31 GMT + +_Version update only_ + +## 7.7.0 +Tue, 03 Dec 2019 03:17:43 GMT + +### Minor changes + +- Improve declaration reference syntax to allow linking to overloaded functions/methods + +## 7.6.0 +Sun, 24 Nov 2019 00:54:04 GMT + +### Minor changes + +- Added support for `@throws` + +## 7.5.6 +Fri, 15 Nov 2019 04:50:50 GMT + +_Version update only_ + +## 7.5.5 +Mon, 11 Nov 2019 16:07:56 GMT + +_Version update only_ + +## 7.5.4 +Tue, 05 Nov 2019 06:49:28 GMT + +### Patches + +- Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552) + +## 7.5.3 +Tue, 05 Nov 2019 01:08:39 GMT + +### Patches + +- Clarified an error message + +## 7.5.2 +Tue, 22 Oct 2019 06:24:44 GMT + +### Patches + +- Refactor some code as part of migration from TSLint to ESLint + +## 7.5.1 +Sun, 29 Sep 2019 23:56:29 GMT + +### Patches + +- Update repository URL + +## 7.5.0 +Wed, 25 Sep 2019 15:15:31 GMT + +### Minor changes + +- Add ApiItem.getMergedSiblings() API + +## 7.4.2 +Mon, 23 Sep 2019 15:14:55 GMT + +### Patches + +- Remove unnecessary dependency on @types/node + +## 7.4.1 +Tue, 10 Sep 2019 22:32:23 GMT + +### Patches + +- Update documentation + +## 7.4.0 +Tue, 10 Sep 2019 20:38:33 GMT + +### Minor changes + +- Add 'canonicalReference' to ExcerptToken + +## 7.3.4 +Wed, 04 Sep 2019 18:28:06 GMT + +_Version update only_ + +## 7.3.3 +Wed, 04 Sep 2019 15:15:37 GMT + +### Patches + +- Update TSDoc dependency to 0.12.14 + +## 7.3.2 +Thu, 08 Aug 2019 15:14:17 GMT + +_Version update only_ + +## 7.3.1 +Thu, 08 Aug 2019 00:49:05 GMT + +### Patches + +- (Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation + +## 7.3.0 +Mon, 22 Jul 2019 19:13:10 GMT + +### Minor changes + +- Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()` + +## 7.2.0 +Tue, 11 Jun 2019 00:48:06 GMT + +### Minor changes + +- Add API support for type parameters and type alias types + +### Patches + +- Improve the .api.json deserializer to validate the schema version and support backwards compatibility + +## 7.1.3 +Wed, 05 Jun 2019 19:12:34 GMT + +### Patches + +- Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number + +## 7.1.2 +Tue, 04 Jun 2019 05:51:53 GMT + +### Patches + +- Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static + +## 7.1.1 +Mon, 27 May 2019 04:13:44 GMT + +### Patches + +- Make the strings returned by ApiItem.displayName less verbose +- Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage() + +## 7.1.0 +Tue, 16 Apr 2019 11:01:37 GMT + +### Minor changes + +- Initial stable release of API Extractor 7 + +## 7.0.28 +Wed, 20 Mar 2019 19:14:49 GMT + +_Version update only_ + +## 7.0.27 +Mon, 18 Mar 2019 04:28:43 GMT + +### Patches + +- Add helper functions for ReleaseTag +- Export IApiItemConstructor to eliminate the ae-forgotten-export warning + +## 7.0.26 +Wed, 13 Mar 2019 19:13:14 GMT + +### Patches + +- Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter + +## 7.0.25 +Wed, 13 Mar 2019 01:14:05 GMT + +### Patches + +- Upgrade TSDoc + +## 7.0.24 +Mon, 11 Mar 2019 16:13:36 GMT + +### Patches + +- Initial setup of new package @microsoft/api-extractor-model + diff --git a/libraries/api-extractor-model/LICENSE b/libraries/api-extractor-model/LICENSE new file mode 100644 index 00000000000..71a5411091a --- /dev/null +++ b/libraries/api-extractor-model/LICENSE @@ -0,0 +1,24 @@ +@microsoft/api-extractor-model + +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/libraries/api-extractor-model/README.md b/libraries/api-extractor-model/README.md new file mode 100644 index 00000000000..d00064af4cd --- /dev/null +++ b/libraries/api-extractor-model/README.md @@ -0,0 +1,68 @@ +# @microsoft/api-extractor-model + +Use this library to read and write *.api.json files as defined by the [API Extractor](https://api-extractor.com/) tool. +These files are used to generate a documentation website for your TypeScript package. The files store the +API signatures and doc comments that were extracted from your package. + +API documentation for this package: https://api.rushstack.io/pages/api-extractor-model/ + +## Example Usage + +The following code sample shows how to load `example.api.json`, which would be generated by API Extractor +when it analyzes a hypothetical NPM package called `example`: + +```ts +import { ApiModel, ApiPackage } from '@microsoft/api-extractor-model'; + +const apiModel: ApiModel = new ApiModel(); +const apiPackage: ApiPackage = apiModel.loadPackage('example.api.json'); + +for (const member of apiPackage.members) { + console.log(member.displayName); +} +``` + +The `ApiModel` is acts as a container for various packages that are loaded and operated on as a group. +For example, a documentation tool may need to resolve `@link` references across different packages. +In this case we would load the various packages into the `ApiModel`, and then use +the `ApiModel.resolveDeclarationReference()` to resolve the `@link` targets. + +The data structure forms a tree of various classes that start with the `Api` prefix. The nesting hierarchy +might look like this: + +``` +- ApiModel + - ApiPackage + - ApiEntryPoint + - ApiClass + - ApiMethod + - ApiProperty + - ApiEnum + - ApiEnumMember + - ApiInterface + - ApiMethodSignature + - ApiPropertySignature + - ApiNamespace + - (ApiClass, ApiEnum, ApiInterface, ...) +``` + +You can use the `ApiItem.members` property to traverse this tree. + +Note that the non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use +TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various +features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class +to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: +the function that generates a subclass, an interface that describes the members of the subclass, and +a namespace containing static members of the class. + +> For a complete project that uses these APIs to generate an API reference web site, +> see the [@microsoft/api-documenter](https://www.npmjs.com/package/@microsoft/api-documenter) source code. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/api-extractor-model/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/api-extractor-model/) + +API Extractor is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/api-extractor-model/config/api-extractor.json b/libraries/api-extractor-model/config/api-extractor.json new file mode 100644 index 00000000000..aa9d8f810fd --- /dev/null +++ b/libraries/api-extractor-model/config/api-extractor.json @@ -0,0 +1,20 @@ +{ + "$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, + "untrimmedFilePath": "/dist/rollup.d.ts" + } +} diff --git a/libraries/api-extractor-model/config/jest.config.json b/libraries/api-extractor-model/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/api-extractor-model/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/api-extractor-model/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/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 new file mode 100644 index 00000000000..341e740beb9 --- /dev/null +++ b/libraries/api-extractor-model/package.json @@ -0,0 +1,29 @@ +{ + "name": "@microsoft/api-extractor-model", + "version": "7.32.2", + "description": "A helper library for loading and saving the .api.json files created by API Extractor", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/api-extractor-model" + }, + "homepage": "https://api-extractor.com", + "main": "lib/index.js", + "typings": "dist/rollup.d.ts", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.0", + "@rushstack/node-core-library": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/apps/api-extractor-model/src/aedoc/AedocDefinitions.ts b/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts similarity index 79% rename from apps/api-extractor-model/src/aedoc/AedocDefinitions.ts rename to libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts index 539d6a95249..a639404d66a 100644 --- a/apps/api-extractor-model/src/aedoc/AedocDefinitions.ts +++ b/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts @@ -1,15 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - TSDocConfiguration, - TSDocTagDefinition, - TSDocTagSyntaxKind, - StandardTags -} from '@microsoft/tsdoc'; +import { TSDocConfiguration, TSDocTagDefinition, TSDocTagSyntaxKind, StandardTags } from '@microsoft/tsdoc'; /** * @internal + * @deprecated - tsdoc configuration is now constructed from tsdoc.json files associated with each package. */ export class AedocDefinitions { public static readonly betaDocumentation: TSDocTagDefinition = new TSDocTagDefinition({ @@ -30,16 +26,20 @@ export class AedocDefinitions { public static get tsdocConfiguration(): TSDocConfiguration { if (!AedocDefinitions._tsdocConfiguration) { const configuration: TSDocConfiguration = new TSDocConfiguration(); - configuration.addTagDefinitions([ - AedocDefinitions.betaDocumentation, - AedocDefinitions.internalRemarks, - AedocDefinitions.preapprovedTag - ], true); + configuration.addTagDefinitions( + [ + AedocDefinitions.betaDocumentation, + AedocDefinitions.internalRemarks, + AedocDefinitions.preapprovedTag + ], + true + ); configuration.setSupportForTags( [ StandardTags.alpha, StandardTags.beta, + StandardTags.decorator, StandardTags.defaultValue, StandardTags.deprecated, StandardTags.eventProperty, diff --git a/libraries/api-extractor-model/src/aedoc/ReleaseTag.ts b/libraries/api-extractor-model/src/aedoc/ReleaseTag.ts new file mode 100644 index 00000000000..6cad2224212 --- /dev/null +++ b/libraries/api-extractor-model/src/aedoc/ReleaseTag.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * A "release tag" is a custom TSDoc tag that is applied to an API to communicate the level of support + * provided for third-party developers. + * + * @remarks + * + * The four release tags are: `@internal`, `@alpha`, `@beta`, and `@public`. They are applied to API items such + * as classes, member functions, enums, etc. The release tag applies recursively to members of a container + * (e.g. class or interface). For example, if a class is marked as `@beta`, then all of its members automatically + * have this status; you DON'T need add the `@beta` tag to each member function. However, you could add + * `@internal` to a member function to give it a different release status. + * + * @public + */ +export enum ReleaseTag { + /** + * No release tag was specified in the AEDoc summary. + */ + None = 0, + /** + * Indicates that an API item is meant only for usage by other NPM packages from the same + * maintainer. Third parties should never use "internal" APIs. (To emphasize this, their + * names are prefixed by underscores.) + */ + Internal = 1, + /** + * Indicates that an API item is eventually intended to be public, but currently is in an + * early stage of development. Third parties should not use "alpha" APIs. + */ + Alpha = 2, + /** + * Indicates that an API item has been released in an experimental state. Third parties are + * encouraged to try it and provide feedback. However, a "beta" API should NOT be used + * in production. + */ + Beta = 3, + /** + * Indicates that an API item has been officially released. It is part of the supported + * contract (e.g. SemVer) for a package. + */ + Public = 4 +} + +/** + * Helper functions for working with the `ReleaseTag` enum. + * @public + */ +export namespace ReleaseTag { + /** + * Returns the TSDoc tag name for a `ReleaseTag` value. + * + * @remarks + * For example, `getTagName(ReleaseTag.Internal)` would return the string `@internal`. + */ + export function getTagName(releaseTag: ReleaseTag): string { + switch (releaseTag) { + case ReleaseTag.None: + return '(none)'; + case ReleaseTag.Internal: + return '@internal'; + case ReleaseTag.Alpha: + return '@alpha'; + case ReleaseTag.Beta: + return '@beta'; + case ReleaseTag.Public: + return '@public'; + default: + throw new Error('Unsupported release tag'); + } + } + + /** + * Compares two `ReleaseTag` values. Their values must not be `ReleaseTag.None`. + * @returns 0 if `a` and `b` are equal, a positive number if `a` is more public than `b`, + * and a negative number if `a` is less public than `b`. + * @remarks + * For example, `compareReleaseTag(ReleaseTag.Beta, ReleaseTag.Alpha)` will return a positive + * number because beta is more public than alpha. + */ + export function compare(a: ReleaseTag, b: ReleaseTag): number { + return a - b; + } +} diff --git a/libraries/api-extractor-model/src/index.ts b/libraries/api-extractor-model/src/index.ts new file mode 100644 index 00000000000..f902fa8dc91 --- /dev/null +++ b/libraries/api-extractor-model/src/index.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Use this library to read and write *.api.json files as defined by the + * {@link https://api-extractor.com/ | API Extractor} tool. These files are used to generate a documentation + * website for your TypeScript package. The files store the API signatures and doc comments that were extracted + * from your package. + * + * @packageDocumentation + */ + +export { AedocDefinitions } from './aedoc/AedocDefinitions'; +export { ReleaseTag } from './aedoc/ReleaseTag'; + +// items +export { type IApiDeclaredItemOptions, ApiDeclaredItem } from './items/ApiDeclaredItem'; +export { type IApiDocumentedItemOptions, ApiDocumentedItem } from './items/ApiDocumentedItem'; +export { ApiItemKind, type IApiItemOptions, ApiItem, type IApiItemConstructor } from './items/ApiItem'; +export { type IApiPropertyItemOptions, ApiPropertyItem } from './items/ApiPropertyItem'; + +// mixins +export { + type IApiParameterListMixinOptions, + type IApiParameterOptions, + ApiParameterListMixin +} from './mixins/ApiParameterListMixin'; +export { + type IApiTypeParameterOptions, + type IApiTypeParameterListMixinOptions, + ApiTypeParameterListMixin +} from './mixins/ApiTypeParameterListMixin'; +export { type IApiAbstractMixinOptions, ApiAbstractMixin } from './mixins/ApiAbstractMixin'; +export { type IApiItemContainerMixinOptions, ApiItemContainerMixin } from './mixins/ApiItemContainerMixin'; +export { type IApiProtectedMixinOptions, ApiProtectedMixin } from './mixins/ApiProtectedMixin'; +export { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from './mixins/ApiReleaseTagMixin'; +export { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from './mixins/ApiReturnTypeMixin'; +export { type IApiStaticMixinOptions, ApiStaticMixin } from './mixins/ApiStaticMixin'; +export { type IApiNameMixinOptions, ApiNameMixin } from './mixins/ApiNameMixin'; +export { type IApiOptionalMixinOptions, ApiOptionalMixin } from './mixins/ApiOptionalMixin'; +export { type IApiReadonlyMixinOptions, ApiReadonlyMixin } from './mixins/ApiReadonlyMixin'; +export { type IApiInitializerMixinOptions, ApiInitializerMixin } from './mixins/ApiInitializerMixin'; +export { type IApiExportedMixinOptions, ApiExportedMixin } from './mixins/ApiExportedMixin'; +export { + type IFindApiItemsResult, + type IFindApiItemsMessage, + FindApiItemsMessageId +} from './mixins/IFindApiItemsResult'; + +export { + ExcerptTokenKind, + type IExcerptTokenRange, + type IExcerptToken, + ExcerptToken, + Excerpt +} from './mixins/Excerpt'; +export type { Constructor, PropertiesOf } from './mixins/Mixin'; + +// model +export { type IApiCallSignatureOptions, ApiCallSignature } from './model/ApiCallSignature'; +export { type IApiClassOptions, ApiClass } from './model/ApiClass'; +export { type IApiConstructorOptions, ApiConstructor } from './model/ApiConstructor'; +export { type IApiConstructSignatureOptions, ApiConstructSignature } from './model/ApiConstructSignature'; +export { type IApiEntryPointOptions, ApiEntryPoint } from './model/ApiEntryPoint'; +export { type IApiEnumOptions, ApiEnum } from './model/ApiEnum'; +export { type IApiEnumMemberOptions, ApiEnumMember, EnumMemberOrder } from './model/ApiEnumMember'; +export { type IApiFunctionOptions, ApiFunction } from './model/ApiFunction'; +export { type IApiIndexSignatureOptions, ApiIndexSignature } from './model/ApiIndexSignature'; +export { type IApiInterfaceOptions, ApiInterface } from './model/ApiInterface'; +export { type IApiMethodOptions, ApiMethod } from './model/ApiMethod'; +export { type IApiMethodSignatureOptions, ApiMethodSignature } from './model/ApiMethodSignature'; +export { ApiModel } from './model/ApiModel'; +export { type IApiNamespaceOptions, ApiNamespace } from './model/ApiNamespace'; +export { type IApiPackageOptions, ApiPackage, type IApiPackageSaveOptions } from './model/ApiPackage'; +export { type IParameterOptions, Parameter } from './model/Parameter'; +export { type IApiPropertyOptions, ApiProperty } from './model/ApiProperty'; +export { type IApiPropertySignatureOptions, ApiPropertySignature } from './model/ApiPropertySignature'; +export { type IApiTypeAliasOptions, ApiTypeAlias } from './model/ApiTypeAlias'; +export { type ITypeParameterOptions, TypeParameter } from './model/TypeParameter'; +export { type IApiVariableOptions, ApiVariable } from './model/ApiVariable'; +export { type IResolveDeclarationReferenceResult } from './model/ModelReferenceResolver'; +export { HeritageType } from './model/HeritageType'; +export { type ISourceLocationOptions, SourceLocation } from './model/SourceLocation'; diff --git a/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts b/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts new file mode 100644 index 00000000000..75d4e279f62 --- /dev/null +++ b/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import { + ApiDocumentedItem, + type IApiDocumentedItemJson, + type IApiDocumentedItemOptions +} from './ApiDocumentedItem'; +import type { ApiItem } from './ApiItem'; +import { Excerpt, ExcerptToken, type IExcerptTokenRange, type IExcerptToken } from '../mixins/Excerpt'; +import type { DeserializerContext } from '../model/DeserializerContext'; +import { SourceLocation } from '../model/SourceLocation'; + +/** + * Constructor options for {@link ApiDeclaredItem}. + * @public + */ +export interface IApiDeclaredItemOptions extends IApiDocumentedItemOptions { + excerptTokens: IExcerptToken[]; + fileUrlPath?: string; +} + +export interface IApiDeclaredItemJson extends IApiDocumentedItemJson { + excerptTokens: IExcerptToken[]; + fileUrlPath?: string; +} + +/** + * The base class for API items that have an associated source code excerpt containing a TypeScript declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * Most `ApiItem` subclasses have declarations and thus extend `ApiDeclaredItem`. Counterexamples include + * `ApiModel` and `ApiPackage`, which do not have any corresponding TypeScript source code. + * + * @public + */ +export class ApiDeclaredItem extends ApiDocumentedItem { + private _excerptTokens: ExcerptToken[]; + private _excerpt: Excerpt; + private _fileUrlPath?: string; + private _sourceLocation?: SourceLocation; + + public constructor(options: IApiDeclaredItemOptions) { + super(options); + + this._excerptTokens = options.excerptTokens.map((token) => { + const canonicalReference: DeclarationReference | undefined = + token.canonicalReference === undefined + ? undefined + : DeclarationReference.parse(token.canonicalReference); + return new ExcerptToken(token.kind, token.text, canonicalReference); + }); + this._excerpt = new Excerpt(this.excerptTokens, { startIndex: 0, endIndex: this.excerptTokens.length }); + this._fileUrlPath = options.fileUrlPath; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiDeclaredItemJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.excerptTokens = jsonObject.excerptTokens; + options.fileUrlPath = jsonObject.fileUrlPath; + } + + /** + * The source code excerpt where the API item is declared. + */ + public get excerpt(): Excerpt { + return this._excerpt; + } + + /** + * The individual source code tokens that comprise the main excerpt. + */ + public get excerptTokens(): ReadonlyArray { + return this._excerptTokens; + } + + /** + * The file URL path relative to the `projectFolder` and `projectFolderURL` fields + * as defined in the `api-extractor.json` config. Is `undefined` if the path is + * the same as the parent API item's. + */ + public get fileUrlPath(): string | undefined { + return this._fileUrlPath; + } + + /** + * Returns the source location where the API item is declared. + */ + public get sourceLocation(): SourceLocation { + if (!this._sourceLocation) { + this._sourceLocation = this._buildSourceLocation(); + } + return this._sourceLocation; + } + + /** + * If the API item has certain important modifier tags such as `@sealed`, `@virtual`, or `@override`, + * this prepends them as a doc comment above the excerpt. + */ + public getExcerptWithModifiers(): string { + const excerpt: string = this.excerpt.text; + const modifierTags: string[] = []; + + if (excerpt.length > 0) { + if (this instanceof ApiDocumentedItem) { + if (this.tsdocComment) { + if (this.tsdocComment.modifierTagSet.isSealed()) { + modifierTags.push('@sealed'); + } + if (this.tsdocComment.modifierTagSet.isVirtual()) { + modifierTags.push('@virtual'); + } + if (this.tsdocComment.modifierTagSet.isOverride()) { + modifierTags.push('@override'); + } + } + if (modifierTags.length > 0) { + return '/** ' + modifierTags.join(' ') + ' */\n' + excerpt; + } + } + } + + return excerpt; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + jsonObject.excerptTokens = this.excerptTokens.map((x) => { + const excerptToken: IExcerptToken = { kind: x.kind, text: x.text }; + if (x.canonicalReference !== undefined) { + excerptToken.canonicalReference = x.canonicalReference.toString(); + } + return excerptToken; + }); + + // Only serialize this API item's file URL path if it exists and it's different from its parent's + // (a little optimization to keep the doc model succinct). + if (this.fileUrlPath) { + if (!(this.parent instanceof ApiDeclaredItem) || this.fileUrlPath !== this.parent.fileUrlPath) { + jsonObject.fileUrlPath = this.fileUrlPath; + } + } + } + + /** + * Constructs a new {@link Excerpt} corresponding to the provided token range. + */ + public buildExcerpt(tokenRange: IExcerptTokenRange): Excerpt { + return new Excerpt(this.excerptTokens, tokenRange); + } + + /** + * Builds the cached object used by the `sourceLocation` property. + */ + private _buildSourceLocation(): SourceLocation { + const projectFolderUrl: string | undefined = this.getAssociatedPackage()?.projectFolderUrl; + + let fileUrlPath: string | undefined; + for (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) { + if (current instanceof ApiDeclaredItem && current.fileUrlPath) { + fileUrlPath = current.fileUrlPath; + break; + } + } + + return new SourceLocation({ + projectFolderUrl: projectFolderUrl, + fileUrlPath: fileUrlPath + }); + } +} diff --git a/apps/api-extractor-model/src/items/ApiDocumentedItem.ts b/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts similarity index 82% rename from apps/api-extractor-model/src/items/ApiDocumentedItem.ts rename to libraries/api-extractor-model/src/items/ApiDocumentedItem.ts index 9316d479dc5..126c0983afe 100644 --- a/apps/api-extractor-model/src/items/ApiDocumentedItem.ts +++ b/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. import * as tsdoc from '@microsoft/tsdoc'; -import { ApiItem, IApiItemOptions, IApiItemJson } from './ApiItem'; -import { AedocDefinitions } from '../aedoc/AedocDefinitions'; -import { DeserializerContext } from '../model/DeserializerContext'; + +import { ApiItem, type IApiItemOptions, type IApiItemJson } from './ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Constructor options for {@link ApiDocumentedItem}. @@ -37,15 +37,17 @@ export class ApiDocumentedItem extends ApiItem { } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiItemJson): void { - - super.onDeserializeInto(options, context, jsonObject); + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiItemJson + ): void { + super.onDeserializeInto(options, context, jsonObject); const documentedJson: IApiDocumentedItemJson = jsonObject as IApiDocumentedItemJson; if (documentedJson.docComment) { - const tsdocParser: tsdoc.TSDocParser = new tsdoc.TSDocParser(AedocDefinitions.tsdocConfiguration); + const tsdocParser: tsdoc.TSDocParser = new tsdoc.TSDocParser(context.tsdocConfiguration); // NOTE: For now, we ignore TSDoc errors found in a serialized .api.json file. // Normally these errors would have already been reported by API Extractor during analysis. diff --git a/apps/api-extractor-model/src/items/ApiItem.ts b/libraries/api-extractor-model/src/items/ApiItem.ts similarity index 80% rename from apps/api-extractor-model/src/items/ApiItem.ts rename to libraries/api-extractor-model/src/items/ApiItem.ts index b38a1d2e154..1eb7fb014c6 100644 --- a/apps/api-extractor-model/src/items/ApiItem.ts +++ b/libraries/api-extractor-model/src/items/ApiItem.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 { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; -import { Constructor, PropertiesOf } from '../mixins/Mixin'; -import { ApiPackage } from '../model/ApiPackage'; -import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; -import { DeserializerContext } from '../model/DeserializerContext'; +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 { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; +import type { ApiModel } from '../model/ApiModel'; /** * The type returned by the {@link ApiItem.kind} property, which can be used to easily distinguish subclasses of @@ -15,7 +17,7 @@ import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; * * @public */ -export const enum ApiItemKind { +export enum ApiItemKind { CallSignature = 'CallSignature', Class = 'Class', Constructor = 'Constructor', @@ -42,8 +44,7 @@ export const enum ApiItemKind { * Constructor options for {@link ApiItem}. * @public */ -export interface IApiItemOptions { -} +export interface IApiItemOptions {} export interface IApiItemJson { kind: ApiItemKind; @@ -73,14 +74,16 @@ export class ApiItem { public static deserialize(jsonObject: IApiItemJson, context: DeserializerContext): ApiItem { // The Deserializer class is coupled with a ton of other classes, so we delay loading it // to avoid ES5 circular imports. - // eslint-disable-next-line @typescript-eslint/no-var-requires const deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer'); return deserializerModule.Deserializer.deserialize(context, jsonObject); } /** @virtual */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiItemJson): void { + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiItemJson + ): void { // (implemented by subclasses) } @@ -113,8 +116,7 @@ export class ApiItem { this._canonicalReference = this.buildCanonicalReference(); } catch (e) { const name: string = this.getScopedNameWithinPackage() || this.displayName; - throw new InternalError(`Error building canonical reference for ${name}:\n` - + e.message); + throw new InternalError(`Error building canonical reference for ${name}:\n` + (e as Error).message); } } return this._canonicalReference; @@ -145,13 +147,18 @@ export class ApiItem { */ public get displayName(): string { switch (this.kind) { - case ApiItemKind.CallSignature: return '(call)'; - case ApiItemKind.Constructor: return '(constructor)'; - case ApiItemKind.ConstructSignature: return '(new)'; - case ApiItemKind.IndexSignature: return '(indexer)'; - case ApiItemKind.Model: return '(model)'; + case ApiItemKind.CallSignature: + return '(call)'; + case ApiItemKind.Constructor: + return '(constructor)'; + case ApiItemKind.ConstructSignature: + return '(new)'; + case ApiItemKind.IndexSignature: + return '(indexer)'; + case ApiItemKind.Model: + return '(model)'; } - return '(???)'; // All other types should inherit ApiNameMixin which will override this property + return '(???)'; // All other types should inherit ApiNameMixin which will override this property } /** @@ -166,7 +173,7 @@ export class ApiItem { /** * This property supports a visitor pattern for walking the tree. - * For items with ApiItemContainerMixin, it returns the contained items. + * For items with ApiItemContainerMixin, it returns the contained items, sorted alphabetically. * Otherwise it returns an empty array. * @virtual */ @@ -215,9 +222,11 @@ export class ApiItem { const reversedParts: string[] = []; for (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) { - if (current.kind === ApiItemKind.Model - || current.kind === ApiItemKind.Package - || current.kind === ApiItemKind.EntryPoint) { + if ( + current.kind === ApiItemKind.Model || + current.kind === ApiItemKind.Package || + current.kind === ApiItemKind.EntryPoint + ) { break; } if (reversedParts.length !== 0) { @@ -255,7 +264,30 @@ export class ApiItem { return undefined; } - /** @virtual */ + /** + * If this item is an ApiModel or has an ApiModel as one of its parents, then that object is returned. + * Otherwise undefined is returned. + */ + public getAssociatedModel(): ApiModel | undefined { + for (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) { + if (current.kind === ApiItemKind.Model) { + return current as ApiModel; + } + } + return undefined; + } + + /** + * A text string whose value determines the sort order that is automatically applied by the + * {@link (ApiItemContainerMixin:interface)} class. + * + * @remarks + * The value of this string is undocumented and may change at any time. + * If {@link (ApiItemContainerMixin:interface).preserveMemberOrder} is enabled for the `ApiItem`'s parent, + * then no sorting is performed, and this key is not used. + * + * @virtual + */ public getSortKey(): string { return this.containerKey; } @@ -288,4 +320,4 @@ export class ApiItem { * * @public */ -export interface IApiItemConstructor extends Constructor, PropertiesOf { } +export interface IApiItemConstructor extends Constructor, PropertiesOf {} diff --git a/libraries/api-extractor-model/src/items/ApiPropertyItem.ts b/libraries/api-extractor-model/src/items/ApiPropertyItem.ts new file mode 100644 index 00000000000..fbe7d94aaea --- /dev/null +++ b/libraries/api-extractor-model/src/items/ApiPropertyItem.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 type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; +import { type IApiDeclaredItemOptions, ApiDeclaredItem, type IApiDeclaredItemJson } from './ApiDeclaredItem'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import type { DeserializerContext } from '../model/DeserializerContext'; +import { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin'; +import { ApiReadonlyMixin, type IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin'; + +/** + * Constructor options for {@link ApiPropertyItem}. + * @public + */ +export interface IApiPropertyItemOptions + extends IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiOptionalMixinOptions, + IApiReadonlyMixinOptions, + IApiDeclaredItemOptions { + propertyTypeTokenRange: IExcerptTokenRange; +} + +export interface IApiPropertyItemJson extends IApiDeclaredItemJson { + propertyTypeTokenRange: IExcerptTokenRange; +} + +/** + * The abstract base class for {@link ApiProperty} and {@link ApiPropertySignature}. + * + * @public + */ +export class ApiPropertyItem extends ApiNameMixin( + ApiReleaseTagMixin(ApiOptionalMixin(ApiReadonlyMixin(ApiDeclaredItem))) +) { + /** + * An {@link Excerpt} that describes the type of the property. + */ + public readonly propertyTypeExcerpt: Excerpt; + + public constructor(options: IApiPropertyItemOptions) { + super(options); + + this.propertyTypeExcerpt = this.buildExcerpt(options.propertyTypeTokenRange); + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiPropertyItemJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.propertyTypeTokenRange = jsonObject.propertyTypeTokenRange; + } + + /** + * Returns true if this property should be documented as an event. + * + * @remarks + * The `@eventProperty` TSDoc modifier can be added to readonly properties to indicate that they return an + * event object that event handlers can be attached to. The event-handling API is implementation-defined, but + * typically the return type would be a class with members such as `addHandler()` and `removeHandler()`. + * The documentation should display such properties under an "Events" heading instead of the + * usual "Properties" heading. + */ + public get isEventProperty(): boolean { + if (this.tsdocComment) { + return this.tsdocComment.modifierTagSet.isEventProperty(); + } + return false; + } + + /** @override */ + public 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 new file mode 100644 index 00000000000..6c6ef04191c --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiAbstractMixin.ts @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; + +/** + * Constructor options for {@link (ApiAbstractMixin:interface)}. + * @public + */ +export interface IApiAbstractMixinOptions extends IApiItemOptions { + isAbstract: boolean; +} + +export interface IApiAbstractMixinJson extends IApiItemJson { + isAbstract: boolean; +} + +const _isAbstract: unique symbol = Symbol('ApiAbstractMixin._isAbstract'); + +/** + * The mixin base class for API items that have an abstract modifier. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiAbstractMixin extends ApiItem { + /** + * Indicates that the API item's value has an 'abstract' modifier. + */ + readonly isAbstract: boolean; + + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiAbstractMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiAbstractMixin:interface)} + * functionality. + * + * @public + */ +export function ApiAbstractMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiAbstractMixin) { + class MixedClass extends baseClass implements ApiAbstractMixin { + public [_isAbstract]: boolean; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiAbstractMixinOptions = args[0]; + this[_isAbstract] = options.isAbstract; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiAbstractMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + options.isAbstract = jsonObject.isAbstract || false; + } + + public get isAbstract(): boolean { + return this[_isAbstract]; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.isAbstract = this.isAbstract; + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiAbstractMixin:interface)}. + * @public + */ +export namespace ApiAbstractMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiAbstractMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiAbstractMixin { + return apiItem.hasOwnProperty(_isAbstract); + } +} diff --git a/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts b/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts new file mode 100644 index 00000000000..13909545473 --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* 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'; + +/** + * Constructor options for {@link (IApiExportedMixinOptions:interface)}. + * @public + */ +export interface IApiExportedMixinOptions extends IApiItemOptions { + isExported: boolean; +} + +export interface IApiExportedMixinJson extends IApiItemJson { + isExported: boolean; +} + +const _isExported: unique symbol = Symbol('ApiExportedMixin._isExported'); + +/** + * The mixin base class for API items that can be exported. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiExportedMixin extends ApiItem { + /** + * Whether the declaration is exported from its parent item container (i.e. either an `ApiEntryPoint` or an + * `ApiNamespace`). + * + * @remarks + * Suppose `index.ts` is your entry point: + * + * ```ts + * // index.ts + * + * export class A {} + * class B {} + * + * namespace n { + * export class C {} + * class D {} + * } + * + * // file.ts + * export class E {} + * ``` + * + * Classes `A` and `C` are both exported, while classes `B`, `D`, and `E` are not. `E` is exported from its + * local file, but not from its parent item container (i.e. the entry point). + * + */ + readonly isExported: boolean; + + /** @override */ + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiExportedMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiExportedMixin:interface)} functionality. + * + * @public + */ +export function ApiExportedMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiExportedMixin) { + class MixedClass extends baseClass implements ApiExportedMixin { + public [_isExported]: boolean; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiExportedMixinOptions = args[0]; + this[_isExported] = options.isExported; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiExportedMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + const declarationReference: DeclarationReference = DeclarationReference.parse( + jsonObject.canonicalReference + ); + options.isExported = declarationReference.navigation === Navigation.Exports; + } + + public get isExported(): boolean { + return this[_isExported]; + } + + /** + * The `isExported` property is intentionally not serialized because the information is already present + * in the item's `canonicalReference`. + * @override + */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiExportedMixin:interface)}. + * @public + */ +export namespace ApiExportedMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiExportedMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiExportedMixin { + return apiItem.hasOwnProperty(_isExported); + } +} diff --git a/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts b/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts new file mode 100644 index 00000000000..ff25a29b020 --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.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. + +/* 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 type { DeserializerContext } from '../model/DeserializerContext'; + +/** + * Constructor options for {@link (IApiInitializerMixinOptions:interface)}. + * @public + */ +export interface IApiInitializerMixinOptions extends IApiItemOptions { + initializerTokenRange?: IExcerptTokenRange; +} + +export interface IApiInitializerMixinJson extends IApiItemJson { + initializerTokenRange?: IExcerptTokenRange; +} + +const _initializerExcerpt: unique symbol = Symbol('ApiInitializerMixin._initializerExcerpt'); + +/** + * The mixin base class for API items that can have an initializer. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiInitializerMixin extends ApiItem { + /** + * An {@link Excerpt} that describes the item's initializer. + */ + readonly initializerExcerpt?: Excerpt; + + /** @override */ + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiInitializerMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiInitializerMixin:interface)} functionality. + * + * @public + */ +export function ApiInitializerMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiInitializerMixin) { + class MixedClass extends baseClass implements ApiInitializerMixin { + public [_initializerExcerpt]?: Excerpt; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiInitializerMixinOptions = args[0]; + + if (this instanceof ApiDeclaredItem) { + if (options.initializerTokenRange) { + this[_initializerExcerpt] = this.buildExcerpt(options.initializerTokenRange); + } + } else { + throw new InternalError( + 'ApiInitializerMixin expects a base class that inherits from ApiDeclaredItem' + ); + } + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiInitializerMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + options.initializerTokenRange = jsonObject.initializerTokenRange; + } + + public get initializerExcerpt(): Excerpt | undefined { + return this[_initializerExcerpt]; + } + + /** @override */ + public 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 + if (this.initializerExcerpt) { + jsonObject.initializerTokenRange = this.initializerExcerpt.tokenRange; + } + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiInitializerMixin:interface)}. + * @public + */ +export namespace ApiInitializerMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiInitializerMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiInitializerMixin { + return apiItem.hasOwnProperty(_initializerExcerpt); + } +} diff --git a/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts b/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts new file mode 100644 index 00000000000..fa6adee67c8 --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts @@ -0,0 +1,549 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* 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, + type IApiItemJson, + type IApiItemOptions, + type IApiItemConstructor, + ApiItemKind +} from '../items/ApiItem'; +import { ApiNameMixin } from './ApiNameMixin'; +import type { DeserializerContext } from '../model/DeserializerContext'; +import type { ApiModel } from '../model/ApiModel'; +import type { ApiClass } from '../model/ApiClass'; +import type { ApiInterface } from '../model/ApiInterface'; +import { type ExcerptToken, ExcerptTokenKind } from './Excerpt'; +import { + type IFindApiItemsResult, + type IFindApiItemsMessage, + FindApiItemsMessageId +} from './IFindApiItemsResult'; +import type { HeritageType } from '../model/HeritageType'; +import type { IResolveDeclarationReferenceResult } from '../model/ModelReferenceResolver'; + +/** + * Constructor options for {@link (ApiItemContainerMixin:interface)}. + * @public + */ +export interface IApiItemContainerMixinOptions extends IApiItemOptions { + preserveMemberOrder?: boolean; + members?: ApiItem[]; +} + +export interface IApiItemContainerJson extends IApiItemJson { + preserveMemberOrder?: boolean; + members: IApiItemJson[]; +} + +const _members: unique symbol = Symbol('ApiItemContainerMixin._members'); +const _membersSorted: unique symbol = Symbol('ApiItemContainerMixin._membersSorted'); +const _membersByContainerKey: unique symbol = Symbol('ApiItemContainerMixin._membersByContainerKey'); +const _membersByName: unique symbol = Symbol('ApiItemContainerMixin._membersByName'); +const _membersByKind: unique symbol = Symbol('ApiItemContainerMixin._membersByKind'); +const _preserveMemberOrder: unique symbol = Symbol('ApiItemContainerMixin._preserveMemberOrder'); + +/** + * The mixin base class for API items that act as containers for other child items. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * Examples of `ApiItemContainerMixin` child classes include `ApiModel`, `ApiPackage`, `ApiEntryPoint`, + * and `ApiEnum`. But note that `Parameter` is not considered a "member" of an `ApiMethod`; this relationship + * is modeled using {@link (ApiParameterListMixin:interface).parameters} instead + * of {@link ApiItem.members}. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiItemContainerMixin extends ApiItem { + /** + * Disables automatic sorting of {@link ApiItem.members}. + * + * @remarks + * By default `ApiItemContainerMixin` will automatically sort its members according to their + * {@link ApiItem.getSortKey} string, which provides a standardized mostly alphabetical ordering + * that is appropriate for most API items. When loading older .api.json files the automatic sorting + * is reapplied and may update the ordering. + * + * Set `preserveMemberOrder` to true to disable automatic sorting for this container; instead, the + * members will retain whatever ordering appeared in the {@link IApiItemContainerMixinOptions.members} array. + * The `preserveMemberOrder` option is saved in the .api.json file. + */ + readonly preserveMemberOrder: boolean; + + /** + * Adds a new member to the container. + * + * @remarks + * An ApiItem cannot be added to more than one container. + */ + addMember(member: ApiItem): void; + + /** + * Attempts to retrieve a member using its containerKey, or returns `undefined` if no matching member was found. + * + * @remarks + * Use the `getContainerKey()` static member to construct the key. Each subclass has a different implementation + * of this function, according to the aspects that are important for identifying it. + * + * See {@link ApiItem.containerKey} for more information. + */ + tryGetMemberByKey(containerKey: string): ApiItem | undefined; + + /** + * Returns a list of members with the specified name. + */ + findMembersByName(name: string): ReadonlyArray; + + /** + * Finds all of the ApiItem's immediate and inherited members by walking up the inheritance tree. + * + * @remarks + * + * Given the following class heritage: + * + * ``` + * export class A { + * public a: number|boolean; + * } + * + * export class B extends A { + * public a: number; + * public b: string; + * } + * + * export class C extends B { + * public c: boolean; + * } + * ``` + * + * Calling `findMembersWithInheritance` on `C` will return `B.a`, `B.b`, and `C.c`. Calling the + * method on `B` will return `B.a` and `B.b`. And calling the method on `A` will return just + * `A.a`. + * + * The inherited members returned by this method may be incomplete. If so, there will be a flag + * on the result object indicating this as well as messages explaining the errors in more detail. + * Some scenarios include: + * + * - Interface extending from a type alias. + * + * - Class extending from a variable. + * + * - Extending from a declaration not present in the model (e.g. external package). + * + * - Extending from an unexported declaration (e.g. ae-forgotten-export). Common in mixin + * patterns. + * + * - Unexpected runtime errors... + * + * Lastly, be aware that the types of inherited members are returned with respect to their + * defining class as opposed to with respect to the inheriting class. For example, consider + * the following: + * + * ``` + * export class A { + * public a: T; + * } + * + * export class B extends A {} + * ``` + * + * When called on `B`, this method will return `B.a` with type `T` as opposed to type + * `number`, although the latter is more accurate. + */ + findMembersWithInheritance(): IFindApiItemsResult; + + /** + * For a given member of this container, return its `ApiItem.getMergedSiblings()` list. + * @internal + */ + _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray; + + /** @override */ + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link ApiDeclaredItem}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiItemContainerMixin:interface)} functionality. + * + * @public + */ +export function ApiItemContainerMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { + class MixedClass extends baseClass implements ApiItemContainerMixin { + public readonly [_members]: ApiItem[]; + public [_membersSorted]: boolean; + public [_membersByContainerKey]: Map; + public [_preserveMemberOrder]: boolean; + + // For members of this container that extend ApiNameMixin, this stores the list of members with a given name. + // Examples include merged declarations, overloaded functions, etc. + public [_membersByName]: Map | undefined; + + // For members of this container that do NOT extend ApiNameMixin, this stores the list of members + // that share a common ApiItemKind. Examples include overloaded constructors or index signatures. + public [_membersByKind]: Map | undefined; // key is ApiItemKind + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + const options: IApiItemContainerMixinOptions = args[0] as IApiItemContainerMixinOptions; + + this[_members] = []; + this[_membersSorted] = false; + this[_membersByContainerKey] = new Map(); + this[_preserveMemberOrder] = options.preserveMemberOrder ?? false; + + if (options.members) { + for (const member of options.members) { + this.addMember(member); + } + } + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiItemContainerJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + options.preserveMemberOrder = jsonObject.preserveMemberOrder; + options.members = []; + for (const memberObject of jsonObject.members) { + options.members.push(ApiItem.deserialize(memberObject, context)); + } + } + + /** @override */ + public get members(): ReadonlyArray { + if (!this[_membersSorted] && !this[_preserveMemberOrder]) { + this[_members].sort((x, y) => x.getSortKey().localeCompare(y.getSortKey())); + this[_membersSorted] = true; + } + + return this[_members]; + } + + public get preserveMemberOrder(): boolean { + return this[_preserveMemberOrder]; + } + + public addMember(member: ApiItem): void { + if (this[_membersByContainerKey].has(member.containerKey)) { + throw new Error( + `Another member has already been added with the same name (${member.displayName})` + + ` and containerKey (${member.containerKey})` + ); + } + + const existingParent: ApiItem | undefined = member.parent; + if (existingParent !== undefined) { + throw new Error( + `This item has already been added to another container: "${existingParent.displayName}"` + ); + } + + this[_members].push(member); + this[_membersByName] = undefined; // invalidate the lookup + this[_membersByKind] = undefined; // invalidate the lookup + this[_membersSorted] = false; + this[_membersByContainerKey].set(member.containerKey, member); + + member[apiItem_onParentChanged](this); + } + + public tryGetMemberByKey(containerKey: string): ApiItem | undefined { + return this[_membersByContainerKey].get(containerKey); + } + + public findMembersByName(name: string): ReadonlyArray { + this._ensureMemberMaps(); + return this[_membersByName]!.get(name) || []; + } + + public findMembersWithInheritance(): IFindApiItemsResult { + const messages: IFindApiItemsMessage[] = []; + let maybeIncompleteResult: boolean = false; + + // For API items that don't support inheritance, this method just returns the item's + // immediate members. + switch (this.kind) { + case ApiItemKind.Class: + case ApiItemKind.Interface: + break; + default: { + return { + items: this.members.concat(), + messages, + maybeIncompleteResult + }; + } + } + + const membersByName: Map = new Map(); + const membersByKind: Map = new Map(); + + const toVisit: ApiItem[] = []; + let next: ApiItem | undefined = this; + + while (next) { + const membersToAdd: ApiItem[] = []; + + // For each member, check to see if we've already seen a member with the same name + // previously in the inheritance tree. If so, we know we won't inherit it, and thus + // do not add it to our `membersToAdd` array. + for (const member of next.members) { + // We add the to-be-added members to an intermediate array instead of immediately + // to the maps themselves to support method overloads with the same name. + if (ApiNameMixin.isBaseClassOf(member)) { + if (!membersByName.has(member.name)) { + membersToAdd.push(member); + } + } else { + if (!membersByKind.has(member.kind)) { + membersToAdd.push(member); + } + } + } + + for (const member of membersToAdd) { + if (ApiNameMixin.isBaseClassOf(member)) { + const members: ApiItem[] = membersByName.get(member.name) || []; + members.push(member); + membersByName.set(member.name, members); + } else { + const members: ApiItem[] = membersByKind.get(member.kind) || []; + members.push(member); + membersByKind.set(member.kind, members); + } + } + + // Interfaces can extend multiple interfaces, so iterate through all of them. + const extendedItems: ApiItem[] = []; + let extendsTypes: readonly HeritageType[] | undefined; + + switch (next.kind) { + case ApiItemKind.Class: { + const apiClass: ApiClass = next as ApiClass; + extendsTypes = apiClass.extendsType ? [apiClass.extendsType] : []; + break; + } + case ApiItemKind.Interface: { + const apiInterface: ApiInterface = next as ApiInterface; + extendsTypes = apiInterface.extendsTypes; + break; + } + } + + if (extendsTypes === undefined) { + messages.push({ + messageId: FindApiItemsMessageId.UnsupportedKind, + text: `Unable to analyze references of API item ${next.displayName} because it is of unsupported kind ${next.kind}` + }); + maybeIncompleteResult = true; + next = toVisit.shift(); + continue; + } + + for (const extendsType of extendsTypes) { + // We want to find the reference token associated with the actual inherited declaration. + // In every case we support, this is the first reference token. For example: + // + // ``` + // export class A extends B {} + // ^ + // export class A extends B {} + // ^ + // export class A extends B.C {} + // ^^^ + // ``` + const firstReferenceToken: ExcerptToken | undefined = extendsType.excerpt.spannedTokens.find( + (token: ExcerptToken) => { + return token.kind === ExcerptTokenKind.Reference && token.canonicalReference; + } + ); + + if (!firstReferenceToken) { + messages.push({ + messageId: FindApiItemsMessageId.ExtendsClauseMissingReference, + text: `Unable to analyze extends clause ${extendsType.excerpt.text} of API item ${next.displayName} because no canonical reference was found` + }); + maybeIncompleteResult = true; + continue; + } + + const apiModel: ApiModel | undefined = this.getAssociatedModel(); + if (!apiModel) { + messages.push({ + messageId: FindApiItemsMessageId.NoAssociatedApiModel, + text: `Unable to analyze references of API item ${next.displayName} because it is not associated with an ApiModel` + }); + maybeIncompleteResult = true; + continue; + } + + const canonicalReference: DeclarationReference = firstReferenceToken.canonicalReference!; + const apiItemResult: IResolveDeclarationReferenceResult = apiModel.resolveDeclarationReference( + canonicalReference, + undefined + ); + + const apiItem: ApiItem | undefined = apiItemResult.resolvedApiItem; + if (!apiItem) { + messages.push({ + messageId: FindApiItemsMessageId.DeclarationResolutionFailed, + text: `Unable to resolve declaration reference within API item ${next.displayName}: ${apiItemResult.errorMessage}` + }); + maybeIncompleteResult = true; + continue; + } + + extendedItems.push(apiItem); + } + + // For classes, this array will only have one item. For interfaces, there may be multiple items. Sort the array + // into alphabetical order before adding to our list of API items to visit. This ensures that in the case + // of multiple interface inheritance, a member inherited from multiple interfaces is attributed to the interface + // earlier in alphabetical order (as opposed to source order). + // + // For example, in the code block below, `Bar.x` is reported as the inherited item, not `Foo.x`. + // + // ``` + // interface Foo { + // public x: string; + // } + // + // interface Bar { + // public x: string; + // } + // + // interface FooBar extends Foo, Bar {} + // ``` + extendedItems.sort((x: ApiItem, y: ApiItem) => x.getSortKey().localeCompare(y.getSortKey())); + + toVisit.push(...extendedItems); + next = toVisit.shift(); + } + + const items: ApiItem[] = []; + for (const members of membersByName.values()) { + items.push(...members); + } + for (const members of membersByKind.values()) { + items.push(...members); + } + items.sort((x: ApiItem, y: ApiItem) => x.getSortKey().localeCompare(y.getSortKey())); + + return { + items, + messages, + maybeIncompleteResult + }; + } + + /** @internal */ + public _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray { + this._ensureMemberMaps(); + let result: ApiItem[] | undefined; + if (ApiNameMixin.isBaseClassOf(memberApiItem)) { + result = this[_membersByName]!.get(memberApiItem.name); + } else { + result = this[_membersByKind]!.get(memberApiItem.kind); + } + if (!result) { + throw new InternalError('Item was not found in the _membersByName/_membersByKind lookup'); + } + return result; + } + + /** @internal */ + public _ensureMemberMaps(): void { + // Build the _membersByName and _membersByKind tables if they don't already exist + if (this[_membersByName] === undefined) { + const membersByName: Map = new Map(); + const membersByKind: Map = new Map(); + + for (const member of this[_members]) { + let map: Map | Map; + let key: string | ApiItemKind; + + if (ApiNameMixin.isBaseClassOf(member)) { + map = membersByName; + key = member.name; + } else { + map = membersByKind; + key = member.kind; + } + + let list: ApiItem[] | undefined = map.get(key); + if (list === undefined) { + list = []; + map.set(key, list); + } + list.push(member); + } + + this[_membersByName] = membersByName; + this[_membersByKind] = membersByKind; + } + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + const memberObjects: IApiItemJson[] = []; + + for (const member of this.members) { + const memberJsonObject: Partial = {}; + member.serializeInto(memberJsonObject); + memberObjects.push(memberJsonObject as IApiItemJson); + } + + jsonObject.preserveMemberOrder = this.preserveMemberOrder; + jsonObject.members = memberObjects; + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiItemContainerMixin:interface)}. + * @public + */ +export namespace ApiItemContainerMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiItemContainerMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiItemContainerMixin { + return apiItem.hasOwnProperty(_members); + } +} diff --git a/apps/api-extractor-model/src/mixins/ApiNameMixin.ts b/libraries/api-extractor-model/src/mixins/ApiNameMixin.ts similarity index 81% rename from apps/api-extractor-model/src/mixins/ApiNameMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiNameMixin.ts index 840bb43b7c8..6066839f111 100644 --- a/apps/api-extractor-model/src/mixins/ApiNameMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiNameMixin.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.s +// See LICENSE in the project root for license information. -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; -import { DeserializerContext } from '../model/DeserializerContext'; +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Constructor options for {@link (IApiNameMixinOptions:interface)}. @@ -34,7 +36,7 @@ const _name: unique symbol = Symbol('ApiNameMixin._name'); * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiNameMixin extends ApiItem { /** * The exported name of this API item. @@ -56,10 +58,11 @@ export interface ApiNameMixin extends ApiItem { * * @public */ -export function ApiNameMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiNameMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiNameMixin { +export function ApiNameMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiNameMixin) { + class MixedClass extends baseClass implements ApiNameMixin { public readonly [_name]: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -71,9 +74,11 @@ export function ApiNameMixin(baseClass: } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiNameMixinJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiNameMixinJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); options.name = jsonObject.name; diff --git a/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts b/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts new file mode 100644 index 00000000000..63e0bbd445d --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; + +/** + * Constructor options for {@link (IApiOptionalMixinOptions:interface)}. + * @public + */ +export interface IApiOptionalMixinOptions extends IApiItemOptions { + isOptional: boolean; +} + +export interface IApiOptionalMixinJson extends IApiItemJson { + isOptional: boolean; +} + +const _isOptional: unique symbol = Symbol('ApiOptionalMixin._isOptional'); + +/** + * The mixin base class for API items that can be marked as optional by appending a `?` to them. + * For example, a property of an interface can be optional. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiOptionalMixin extends ApiItem { + /** + * True if this is an optional property. + * @remarks + * For example: + * ```ts + * interface X { + * y: string; // not optional + * z?: string; // optional + * } + * ``` + */ + readonly isOptional: boolean; + + /** @override */ + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiOptionalMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiOptionalMixin:interface)} functionality. + * + * @public + */ +export function ApiOptionalMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiOptionalMixin) { + class MixedClass extends baseClass implements ApiOptionalMixin { + public [_isOptional]: boolean; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiOptionalMixinOptions = args[0]; + this[_isOptional] = !!options.isOptional; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiOptionalMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + options.isOptional = !!jsonObject.isOptional; + } + + public get isOptional(): boolean { + return this[_isOptional]; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.isOptional = this.isOptional; + } + } + + return MixedClass; +} + +/** + * Optional members for {@link (ApiOptionalMixin:interface)}. + * @public + */ +export namespace ApiOptionalMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiOptionalMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiOptionalMixin { + return apiItem.hasOwnProperty(_isOptional); + } +} diff --git a/apps/api-extractor-model/src/mixins/ApiParameterListMixin.ts b/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts similarity index 84% rename from apps/api-extractor-model/src/mixins/ApiParameterListMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts index b29c1f097f2..29d82f81bc1 100644 --- a/apps/api-extractor-model/src/mixins/ApiParameterListMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.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.s +// See LICENSE in the project root for license information. -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +/* 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 { IExcerptTokenRange } from './Excerpt'; -import { InternalError } from '@rushstack/node-core-library'; -import { DeserializerContext } from '../model/DeserializerContext'; +import type { IExcerptTokenRange } from './Excerpt'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Represents parameter information that is part of {@link IApiParameterListMixinOptions} @@ -15,6 +18,7 @@ import { DeserializerContext } from '../model/DeserializerContext'; export interface IApiParameterOptions { parameterName: string; parameterTypeTokenRange: IExcerptTokenRange; + isOptional: boolean; } /** @@ -49,10 +53,10 @@ const _parameters: unique symbol = Symbol('ApiParameterListMixin._parameters'); * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiParameterListMixin extends ApiItem { /** - * When a function has multiple overloaded declarations, this zero-based integer index can be used to unqiuely + * When a function has multiple overloaded declarations, this one-based integer index can be used to uniquely * identify them. * * @remarks @@ -96,10 +100,11 @@ export interface ApiParameterListMixin extends ApiItem { * * @public */ -export function ApiParameterListMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiParameterListMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiParameterListMixin { +export function ApiParameterListMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiParameterListMixin) { + class MixedClass extends baseClass implements ApiParameterListMixin { public readonly [_overloadIndex]: number; public readonly [_parameters]: Parameter[]; @@ -115,10 +120,11 @@ export function ApiParameterListMixin(ba if (this instanceof ApiDeclaredItem) { if (options.parameters) { for (const parameterOptions of options.parameters) { - const parameter: Parameter = new Parameter({ name: parameterOptions.parameterName, parameterTypeExcerpt: this.buildExcerpt(parameterOptions.parameterTypeTokenRange), + // Prior to ApiJsonSchemaVersion.V_1005 this input will be undefined + isOptional: !!parameterOptions.isOptional, parent: this }); @@ -131,9 +137,11 @@ export function ApiParameterListMixin(ba } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiParameterListJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiParameterListJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); options.overloadIndex = jsonObject.overloadIndex; @@ -158,7 +166,8 @@ export function ApiParameterListMixin(ba for (const parameter of this.parameters) { parameterObjects.push({ parameterName: parameter.name, - parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange + parameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange, + isOptional: parameter.isOptional }); } diff --git a/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts b/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts new file mode 100644 index 00000000000..c187a68acbe --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; + +/** + * Constructor options for {@link (IApiProtectedMixinOptions:interface)}. + * @public + */ +export interface IApiProtectedMixinOptions extends IApiItemOptions { + isProtected: boolean; +} + +export interface IApiProtectedMixinJson extends IApiItemJson { + isProtected: boolean; +} + +const _isProtected: unique symbol = Symbol('ApiProtectedMixin._isProtected'); + +/** + * The mixin base class for API items that can have the TypeScript `protected` keyword applied to them. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiProtectedMixin extends ApiItem { + /** + * Whether the declaration has the TypeScript `protected` keyword. + */ + readonly isProtected: boolean; + + /** @override */ + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiProtectedMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiProtectedMixin:interface)} functionality. + * + * @public + */ +export function ApiProtectedMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiProtectedMixin) { + class MixedClass extends baseClass implements ApiProtectedMixin { + public [_isProtected]: boolean; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiProtectedMixinOptions = args[0]; + this[_isProtected] = options.isProtected; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiProtectedMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + options.isProtected = jsonObject.isProtected; + } + + public get isProtected(): boolean { + return this[_isProtected]; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.isProtected = this.isProtected; + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiProtectedMixin:interface)}. + * @public + */ +export namespace ApiProtectedMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiProtectedMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiProtectedMixin { + return apiItem.hasOwnProperty(_isProtected); + } +} diff --git a/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts new file mode 100644 index 00000000000..90d8aeac2b1 --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; + +/** + * Constructor options for {@link (ApiReadonlyMixin:interface)}. + * @public + */ +export interface IApiReadonlyMixinOptions extends IApiItemOptions { + isReadonly: boolean; +} + +export interface IApiReadonlyMixinJson extends IApiItemJson { + isReadonly: boolean; +} + +const _isReadonly: unique symbol = Symbol('ApiReadonlyMixin._isReadonly'); + +/** + * The mixin base class for API items that cannot be modified after instantiation. + * Examples such as the readonly modifier and only having a getter but no setter. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use + * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various + * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class + * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components: + * the function that generates a subclass, an interface that describes the members of the subclass, and + * a namespace containing static members of the class. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface ApiReadonlyMixin extends ApiItem { + /** + * Indicates that the API item's value cannot be assigned by an external consumer. + * + * @remarks + * Examples of API items that would be considered "read only" by API Extractor: + * + * - A class or interface's property that has the `readonly` modifier. + * + * - A variable that has the `const` modifier. + * + * - A property or variable whose TSDoc comment includes the `@readonly` tag. + * + * - A property declaration with a getter but no setter. + * + * Note that if the `readonly` keyword appears in a type annotation, this does not + * guarantee that that the API item will be considered readonly. For example: + * + * ```ts + * declare class C { + * // isReadonly=false in this case, because C.x is assignable + * public x: readonly string[]; + * } + * ``` + */ + readonly isReadonly: boolean; + + serializeInto(jsonObject: Partial): void; +} + +/** + * Mixin function for {@link (ApiReadonlyMixin:interface)}. + * + * @param baseClass - The base class to be extended + * @returns A child class that extends baseClass, adding the {@link (ApiReadonlyMixin:interface)} + * functionality. + * + * @public + */ +export function ApiReadonlyMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiReadonlyMixin) { + class MixedClass extends baseClass implements ApiReadonlyMixin { + public [_isReadonly]: boolean; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(...args: any[]) { + super(...args); + + const options: IApiReadonlyMixinOptions = args[0]; + this[_isReadonly] = options.isReadonly; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiReadonlyMixinJson + ): void { + baseClass.onDeserializeInto(options, context, jsonObject); + + options.isReadonly = jsonObject.isReadonly || false; + } + + public get isReadonly(): boolean { + return this[_isReadonly]; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.isReadonly = this.isReadonly; + } + } + + return MixedClass; +} + +/** + * Static members for {@link (ApiReadonlyMixin:interface)}. + * @public + */ +export namespace ApiReadonlyMixin { + /** + * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiReadonlyMixin` mixin. + * + * @remarks + * + * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of + * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however + * the TypeScript type system cannot invoke a runtime test.) + */ + export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReadonlyMixin { + return apiItem.hasOwnProperty(_isReadonly); + } +} diff --git a/apps/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts similarity index 79% rename from apps/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts index 0326f061841..f00b92a1681 100644 --- a/apps/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts @@ -1,9 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information.s +// See LICENSE in the project root for license information. -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +/* eslint-disable @typescript-eslint/no-redeclare */ + +import { Enum } from '@rushstack/node-core-library'; + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import { ReleaseTag } from '../aedoc/ReleaseTag'; -import { DeserializerContext } from '../model/DeserializerContext'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Constructor options for {@link (ApiReleaseTagMixin:interface)}. @@ -35,7 +39,7 @@ const _releaseTag: unique symbol = Symbol('ApiReleaseTagMixin._releaseTag'); * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiReleaseTagMixin extends ApiItem { /** * The effective release tag for this declaration. If it is not explicitly specified, the value may be @@ -58,10 +62,11 @@ export interface ApiReleaseTagMixin extends ApiItem { * * @public */ -export function ApiReleaseTagMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiReleaseTagMixin { +export function ApiReleaseTagMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin) { + class MixedClass extends baseClass implements ApiReleaseTagMixin { public [_releaseTag]: ReleaseTag; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -73,12 +78,17 @@ export function ApiReleaseTagMixin(baseC } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiReleaseTagMixinJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiReleaseTagMixinJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); - const deserializedReleaseTag: ReleaseTag | undefined = ReleaseTag[jsonObject.releaseTag]; + const deserializedReleaseTag: ReleaseTag | undefined = Enum.tryGetValueByKey( + ReleaseTag as any, // eslint-disable-line + jsonObject.releaseTag + ); if (deserializedReleaseTag === undefined) { throw new Error(`Failed to deserialize release tag ${JSON.stringify(jsonObject.releaseTag)}`); } diff --git a/apps/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts similarity index 81% rename from apps/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts index 3c935f5616f..754305ad1e1 100644 --- a/apps/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.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.s +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; -import { IExcerptTokenRange, Excerpt } from './Excerpt'; -import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { InternalError } from '@rushstack/node-core-library'; -import { DeserializerContext } from '../model/DeserializerContext'; + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { IExcerptTokenRange, Excerpt } from './Excerpt'; +import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Constructor options for {@link (ApiReturnTypeMixin:interface)}. @@ -36,7 +39,7 @@ const _returnTypeExcerpt: unique symbol = Symbol('ApiReturnTypeMixin._returnType * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiReturnTypeMixin extends ApiItem { /** * An {@link Excerpt} that describes the type of the function's return value. @@ -55,10 +58,11 @@ export interface ApiReturnTypeMixin extends ApiItem { * * @public */ -export function ApiReturnTypeMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiReturnTypeMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiReturnTypeMixin { +export function ApiReturnTypeMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiReturnTypeMixin) { + class MixedClass extends baseClass implements ApiReturnTypeMixin { public [_returnTypeExcerpt]: Excerpt; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -75,9 +79,11 @@ export function ApiReturnTypeMixin(baseC } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiReturnTypeMixinJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiReturnTypeMixinJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); options.returnTypeTokenRange = jsonObject.returnTypeTokenRange; diff --git a/apps/api-extractor-model/src/mixins/ApiStaticMixin.ts b/libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts similarity index 81% rename from apps/api-extractor-model/src/mixins/ApiStaticMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts index 6f18b405631..05ad206d8b7 100644 --- a/apps/api-extractor-model/src/mixins/ApiStaticMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiStaticMixin.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.s +// See LICENSE in the project root for license information. -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; -import { DeserializerContext } from '../model/DeserializerContext'; +/* eslint-disable @typescript-eslint/no-redeclare */ + +import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Constructor options for {@link (IApiStaticMixinOptions:interface)}. @@ -33,7 +35,7 @@ const _isStatic: unique symbol = Symbol('ApiStaticMixin._isStatic'); * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiStaticMixin extends ApiItem { /** * Whether the declaration has the TypeScript `static` keyword. @@ -52,10 +54,11 @@ export interface ApiStaticMixin extends ApiItem { * * @public */ -export function ApiStaticMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiStaticMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiStaticMixin { +export function ApiStaticMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiStaticMixin) { + class MixedClass extends baseClass implements ApiStaticMixin { public [_isStatic]: boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -67,9 +70,11 @@ export function ApiStaticMixin(baseClass } /** @override */ - public static onDeserializeInto(options: Partial, context: DeserializerContext, - jsonObject: IApiStaticMixinJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiStaticMixinJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); options.isStatic = jsonObject.isStatic; diff --git a/apps/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts b/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts similarity index 76% rename from apps/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts rename to libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts index 5c0bd73c96b..9af4943bb6e 100644 --- a/apps/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.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.s +// See LICENSE in the project root for license information. + +/* eslint-disable @typescript-eslint/no-redeclare */ -import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; -import { IExcerptTokenRange } from './Excerpt'; -import { TypeParameter } from '../model/TypeParameter'; 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 { ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { DeserializerContext } from '../model/DeserializerContext'; +import type { DeserializerContext } from '../model/DeserializerContext'; /** * Represents parameter information that is part of {@link IApiTypeParameterListMixinOptions} @@ -47,7 +50,7 @@ const _typeParameters: unique symbol = Symbol('ApiTypeParameterListMixin._typePa * * @public */ -// eslint-disable-next-line @typescript-eslint/interface-name-prefix +// eslint-disable-next-line @typescript-eslint/naming-convention export interface ApiTypeParameterListMixin extends ApiItem { /** * The type parameters. @@ -66,10 +69,11 @@ export interface ApiTypeParameterListMixin extends ApiItem { * * @public */ -export function ApiTypeParameterListMixin(baseClass: TBaseClass): - TBaseClass & (new (...args: any[]) => ApiTypeParameterListMixin) { // eslint-disable-line @typescript-eslint/no-explicit-any - - abstract class MixedClass extends baseClass implements ApiTypeParameterListMixin { +export function ApiTypeParameterListMixin( + baseClass: TBaseClass + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): TBaseClass & (new (...args: any[]) => ApiTypeParameterListMixin) { + class MixedClass extends baseClass implements ApiTypeParameterListMixin { public readonly [_typeParameters]: TypeParameter[]; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -83,11 +87,12 @@ export function ApiTypeParameterListMixin, context: DeserializerContext, - jsonObject: IApiTypeParameterListMixinJson): void { - + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiTypeParameterListMixinJson + ): void { baseClass.onDeserializeInto(options, context, jsonObject); options.typeParameters = jsonObject.typeParameters || []; @@ -118,13 +127,11 @@ export function ApiTypeParameterListMixin 0) { diff --git a/libraries/api-extractor-model/src/mixins/Excerpt.ts b/libraries/api-extractor-model/src/mixins/Excerpt.ts new file mode 100644 index 00000000000..c6060a8448b --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/Excerpt.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 type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; +import { Text } from '@rushstack/node-core-library'; + +/** @public */ +export enum ExcerptTokenKind { + /** + * Generic text without any special properties + */ + Content = 'Content', + + /** + * A reference to an API declaration + */ + Reference = 'Reference' +} + +/** + * Used by {@link Excerpt} to indicate a range of indexes within an array of `ExcerptToken` objects. + * + * @public + */ +export interface IExcerptTokenRange { + /** + * The starting index of the span. + */ + startIndex: number; + + /** + * The index of the last member of the span, plus one. + * + * @remarks + * + * If `startIndex` and `endIndex` are the same number, then the span is empty. + */ + endIndex: number; +} + +/** @public */ +export interface IExcerptToken { + readonly kind: ExcerptTokenKind; + text: string; + canonicalReference?: string; +} + +/** + * Represents a fragment of text belonging to an {@link Excerpt} object. + * + * @public + */ +export class ExcerptToken { + private readonly _kind: ExcerptTokenKind; + private readonly _text: string; + private readonly _canonicalReference: DeclarationReference | undefined; + + public constructor(kind: ExcerptTokenKind, text: string, canonicalReference?: DeclarationReference) { + this._kind = kind; + + // Standardize the newlines across operating systems. Even though this may deviate from the actual + // input source file that was parsed, it's useful because the newline gets serialized inside + // a string literal in .api.json, which cannot be automatically normalized by Git. + this._text = Text.convertToLf(text); + this._canonicalReference = canonicalReference; + } + + /** + * Indicates the kind of token. + */ + public get kind(): ExcerptTokenKind { + return this._kind; + } + + /** + * The text fragment. + */ + public get text(): string { + return this._text; + } + + /** + * The hyperlink target for a token whose type is `ExcerptTokenKind.Reference`. For other token types, + * this property will be `undefined`. + */ + public get canonicalReference(): DeclarationReference | undefined { + return this._canonicalReference; + } +} + +/** + * The `Excerpt` class is used by {@link ApiDeclaredItem} to represent a TypeScript code fragment that may be + * annotated with hyperlinks to declared types (and in the future, source code locations). + * + * @remarks + * API Extractor's .api.json file format stores excerpts compactly as a start/end indexes into an array of tokens. + * Every `ApiDeclaredItem` has a "main excerpt" corresponding to the full list of tokens. The declaration may + * also have have "captured" excerpts that correspond to subranges of tokens. + * + * For example, if the main excerpt is: + * + * ``` + * function parse(s: string): Vector | undefined; + * ``` + * + * ...then this entire signature is the "main excerpt", whereas the function's return type `Vector | undefined` is a + * captured excerpt. The `Vector` token might be a hyperlink to that API item. + * + * An excerpt may be empty (i.e. a token range containing zero tokens). For example, if a function's return value + * is not explicitly declared, then the returnTypeExcerpt will be empty. By contrast, a class constructor cannot + * have a return value, so ApiConstructor has no returnTypeExcerpt property at all. + * + * @public + */ +export class Excerpt { + /** + * The complete list of tokens for the source code fragment that this excerpt is based upon. + * If this object is the main excerpt, then it will span all of the tokens; otherwise, it will correspond to + * a range within the array. + */ + public readonly tokens: ReadonlyArray; + + /** + * Specifies the excerpt's range within the `tokens` array. + */ + public readonly tokenRange: Readonly; + + /** + * The tokens spanned by this excerpt. It is the range of the `tokens` array as specified by the `tokenRange` + * property. + */ + public readonly spannedTokens: ReadonlyArray; + + private _text: string | undefined; + + public constructor(tokens: ReadonlyArray, tokenRange: IExcerptTokenRange) { + this.tokens = tokens; + this.tokenRange = tokenRange; + + if ( + this.tokenRange.startIndex < 0 || + this.tokenRange.endIndex > this.tokens.length || + this.tokenRange.startIndex > this.tokenRange.endIndex + ) { + throw new Error('Invalid token range'); + } + + this.spannedTokens = this.tokens.slice(this.tokenRange.startIndex, this.tokenRange.endIndex); + } + + /** + * The excerpted text, formed by concatenating the text of the `spannedTokens` strings. + */ + public get text(): string { + if (this._text === undefined) { + this._text = this.spannedTokens.map((x) => x.text).join(''); + } + return this._text; + } + + /** + * Returns true if the excerpt is an empty range. + */ + public get isEmpty(): boolean { + return this.tokenRange.startIndex === this.tokenRange.endIndex; + } +} diff --git a/libraries/api-extractor-model/src/mixins/IFindApiItemsResult.ts b/libraries/api-extractor-model/src/mixins/IFindApiItemsResult.ts new file mode 100644 index 00000000000..f5a6df5da2c --- /dev/null +++ b/libraries/api-extractor-model/src/mixins/IFindApiItemsResult.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 type { ApiItem } from '../items/ApiItem'; + +/** + * Generic result object for finding API items used by different kinds of find operations. + * @public + */ +export interface IFindApiItemsResult { + /** + * The API items that were found. Not guaranteed to be complete, see `maybeIncompleteResult`. + */ + items: ApiItem[]; + + /** + * Diagnostic messages regarding the find operation. + */ + messages: IFindApiItemsMessage[]; + + /** + * Indicates whether the result is potentially incomplete due to errors during the find operation. + * If true, the `messages` explain the errors in more detail. + */ + maybeIncompleteResult: boolean; +} + +/** + * This object is used for messages returned as part of `IFindApiItemsResult`. + * @public + */ +export interface IFindApiItemsMessage { + /** + * Unique identifier for the message. + * @beta + */ + messageId: FindApiItemsMessageId; + + /** + * Text description of the message. + */ + text: string; +} + +/** + * Unique identifiers for messages returned as part of `IFindApiItemsResult`. + * @public + */ +export enum FindApiItemsMessageId { + /** + * "Unable to resolve declaration reference within API item ___: ___" + */ + DeclarationResolutionFailed = 'declaration-resolution-failed', + + /** + * "Unable to analyze extends clause ___ of API item ___ because no canonical reference was found." + */ + ExtendsClauseMissingReference = 'extends-clause-missing-reference', + + /** + * "Unable to analyze references of API item ___ because it is not associated with an ApiModel" + */ + NoAssociatedApiModel = 'no-associated-api-model', + + /** + * "Unable to analyze references of API item ___ because it is of unsupported kind ___" + */ + UnsupportedKind = 'unsupported-kind' +} diff --git a/apps/api-extractor-model/src/mixins/Mixin.ts b/libraries/api-extractor-model/src/mixins/Mixin.ts similarity index 100% rename from apps/api-extractor-model/src/mixins/Mixin.ts rename to libraries/api-extractor-model/src/mixins/Mixin.ts diff --git a/libraries/api-extractor-model/src/model/ApiCallSignature.ts b/libraries/api-extractor-model/src/model/ApiCallSignature.ts new file mode 100644 index 00000000000..738fdec23fe --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiCallSignature.ts @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + 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'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; +import { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; +import { + type IApiTypeParameterListMixinOptions, + ApiTypeParameterListMixin +} from '../mixins/ApiTypeParameterListMixin'; + +/** + * Constructor options for {@link ApiCallSignature}. + * @public + */ +export interface IApiCallSignatureOptions + extends IApiTypeParameterListMixinOptions, + IApiParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript function call signature. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiCallSignature` represents a TypeScript declaration such as `(x: number, y: number): number` + * in this example: + * + * ```ts + * export interface IChooser { + * // A call signature: + * (x: number, y: number): number; + * + * // Another overload for this call signature: + * (x: string, y: string): string; + * } + * + * function chooseFirst(x: T, y: T): T { + * return x; + * } + * + * let chooser: IChooser = chooseFirst; + * ``` + * + * @public + */ +export class ApiCallSignature extends ApiTypeParameterListMixin( + ApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))) +) { + public constructor(options: IApiCallSignatureOptions) { + super(options); + } + + public static getContainerKey(overloadIndex: number): string { + return `|${ApiItemKind.CallSignature}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.CallSignature; + } + + /** @override */ + public get containerKey(): string { + return ApiCallSignature.getContainerKey(this.overloadIndex); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const parent: DeclarationReference = this.parent + ? this.parent.canonicalReference + : // .withMeaning() requires some kind of component + DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); + return parent.withMeaning(Meaning.CallSignature).withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiClass.ts b/libraries/api-extractor-model/src/model/ApiClass.ts new file mode 100644 index 00000000000..90ea079f0f4 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiClass.ts @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + Meaning, + Navigation, + type Component +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import { ApiItemKind } from '../items/ApiItem'; +import { + ApiDeclaredItem, + type IApiDeclaredItemOptions, + type IApiDeclaredItemJson +} from '../items/ApiDeclaredItem'; +import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import type { IExcerptTokenRange } from '../mixins/Excerpt'; +import { HeritageType } from './HeritageType'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { + ApiTypeParameterListMixin, + type IApiTypeParameterListMixinOptions, + type IApiTypeParameterListMixinJson +} from '../mixins/ApiTypeParameterListMixin'; +import type { DeserializerContext } from './DeserializerContext'; +import { + type IApiExportedMixinJson, + type IApiExportedMixinOptions, + ApiExportedMixin +} from '../mixins/ApiExportedMixin'; +import { + ApiAbstractMixin, + type IApiAbstractMixinJson, + type IApiAbstractMixinOptions +} from '../mixins/ApiAbstractMixin'; + +/** + * Constructor options for {@link ApiClass}. + * @public + */ +export interface IApiClassOptions + extends IApiItemContainerMixinOptions, + IApiNameMixinOptions, + IApiAbstractMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiTypeParameterListMixinOptions, + IApiExportedMixinOptions { + extendsTokenRange: IExcerptTokenRange | undefined; + implementsTokenRanges: IExcerptTokenRange[]; +} + +export interface IApiClassJson + extends IApiDeclaredItemJson, + IApiAbstractMixinJson, + IApiTypeParameterListMixinJson, + IApiExportedMixinJson { + extendsTokenRange?: IExcerptTokenRange; + implementsTokenRanges: IExcerptTokenRange[]; +} + +/** + * Represents a TypeScript class declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiClass` represents a TypeScript declaration such as this: + * + * ```ts + * export class X { } + * ``` + * + * @public + */ +export class ApiClass extends ApiItemContainerMixin( + ApiNameMixin( + ApiAbstractMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem)))) + ) +) { + /** + * The base class that this class inherits from (using the `extends` keyword), or undefined if there is no base class. + */ + public readonly extendsType: HeritageType | undefined; + + private readonly _implementsTypes: HeritageType[] = []; + + public constructor(options: IApiClassOptions) { + super(options); + + if (options.extendsTokenRange) { + this.extendsType = new HeritageType(this.buildExcerpt(options.extendsTokenRange)); + } else { + this.extendsType = undefined; + } + + for (const implementsTokenRange of options.implementsTokenRanges) { + this._implementsTypes.push(new HeritageType(this.buildExcerpt(implementsTokenRange))); + } + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.Class}`; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiClassJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.extendsTokenRange = jsonObject.extendsTokenRange; + options.implementsTokenRanges = jsonObject.implementsTokenRanges; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Class; + } + + /** @override */ + public get containerKey(): string { + return ApiClass.getContainerKey(this.name); + } + + /** + * The list of interfaces that this class implements using the `implements` keyword. + */ + public get implementsTypes(): ReadonlyArray { + return this._implementsTypes; + } + + /** @override */ + public 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 + if (this.extendsType) { + jsonObject.extendsTokenRange = this.extendsType.excerpt.tokenRange; + } + + jsonObject.implementsTokenRanges = this.implementsTypes.map((x) => x.excerpt.tokenRange); + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Class); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiConstructSignature.ts b/libraries/api-extractor-model/src/model/ApiConstructSignature.ts new file mode 100644 index 00000000000..707b155ef5f --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiConstructSignature.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 { + DeclarationReference, + 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'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; +import { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; +import { + ApiTypeParameterListMixin, + type IApiTypeParameterListMixinOptions +} from '../mixins/ApiTypeParameterListMixin'; + +/** + * Constructor options for {@link ApiConstructor}. + * @public + */ +export interface IApiConstructSignatureOptions + extends IApiTypeParameterListMixinOptions, + IApiParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript construct signature that belongs to an `ApiInterface`. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiConstructSignature` represents a construct signature using the `new` keyword such as in this example: + * + * ```ts + * export interface IVector { + * x: number; + * y: number; + * } + * + * export interface IVectorConstructor { + * // A construct signature: + * new(x: number, y: number): IVector; + * } + * + * export function createVector(vectorConstructor: IVectorConstructor, + * x: number, y: number): IVector { + * return new vectorConstructor(x, y); + * } + * + * class Vector implements IVector { + * public x: number; + * public y: number; + * public constructor(x: number, y: number) { + * this.x = x; + * this.y = y; + * } + * } + * + * let vector: Vector = createVector(Vector, 1, 2); + * ``` + * + * Compare with {@link ApiConstructor}, which describes the class constructor itself. + * + * @public + */ +export class ApiConstructSignature extends ApiTypeParameterListMixin( + ApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))) +) { + public constructor(options: IApiConstructSignatureOptions) { + super(options); + } + + public static getContainerKey(overloadIndex: number): string { + return `|${ApiItemKind.ConstructSignature}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.ConstructSignature; + } + + /** @override */ + public get containerKey(): string { + return ApiConstructSignature.getContainerKey(this.overloadIndex); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const parent: DeclarationReference = this.parent + ? this.parent.canonicalReference + : // .withMeaning() requires some kind of component + DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); + return parent.withMeaning(Meaning.ConstructSignature).withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiConstructor.ts b/libraries/api-extractor-model/src/model/ApiConstructor.ts new file mode 100644 index 00000000000..2ff037a9329 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiConstructor.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 { + DeclarationReference, + 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'; +import { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; + +/** + * Constructor options for {@link ApiConstructor}. + * @public + */ +export interface IApiConstructorOptions + extends IApiParameterListMixinOptions, + IApiProtectedMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript class constructor declaration that belongs to an `ApiClass`. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiConstructor` represents a declaration using the `constructor` keyword such as in this example: + * + * ```ts + * export class Vector { + * public x: number; + * public y: number; + * + * // A class constructor: + * public constructor(x: number, y: number) { + * this.x = x; + * this.y = y; + * } + * } + * ``` + * + * Compare with {@link ApiConstructSignature}, which describes the construct signature for a class constructor. + * + * @public + */ +export class ApiConstructor extends ApiParameterListMixin( + ApiProtectedMixin(ApiReleaseTagMixin(ApiDeclaredItem)) +) { + public constructor(options: IApiConstructorOptions) { + super(options); + } + + public static getContainerKey(overloadIndex: number): string { + return `|${ApiItemKind.Constructor}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Constructor; + } + + /** @override */ + public get containerKey(): string { + return ApiConstructor.getContainerKey(this.overloadIndex); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const parent: DeclarationReference = this.parent + ? this.parent.canonicalReference + : // .withMeaning() requires some kind of component + DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); + return parent.withMeaning(Meaning.Constructor).withOverloadIndex(this.overloadIndex); + } +} diff --git a/apps/api-extractor-model/src/model/ApiEntryPoint.ts b/libraries/api-extractor-model/src/model/ApiEntryPoint.ts similarity index 89% rename from apps/api-extractor-model/src/model/ApiEntryPoint.ts rename to libraries/api-extractor-model/src/model/ApiEntryPoint.ts index a95b84f47ac..4d03a35fdd5 100644 --- a/apps/api-extractor-model/src/model/ApiEntryPoint.ts +++ b/libraries/api-extractor-model/src/model/ApiEntryPoint.ts @@ -1,18 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { DeclarationReference } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; +import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItem, ApiItemKind } from '../items/ApiItem'; -import { ApiItemContainerMixin, IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; -import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; import { ApiPackage } from './ApiPackage'; /** * Constructor options for {@link ApiEntryPoint}. * @public */ -export interface IApiEntryPointOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions { -} +export interface IApiEntryPointOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions {} /** * Represents the entry point for an NPM package. @@ -75,7 +75,6 @@ export class ApiEntryPoint extends ApiItemContainerMixin(ApiNameMixin(ApiItem)) /** @beta @override */ public 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 new file mode 100644 index 00000000000..23528c219bd --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiEnum.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 { + DeclarationReference, + Meaning, + 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'; +import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; +import type { ApiEnumMember } from './ApiEnumMember'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiEnum}. + * @public + */ +export interface IApiEnumOptions + extends IApiItemContainerMixinOptions, + IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiExportedMixinOptions {} + +/** + * Represents a TypeScript enum declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiEnum` represents an enum declaration such as `FontSizes` in the example below: + * + * ```ts + * export enum FontSizes { + * Small = 100, + * Medium = 200, + * Large = 300 + * } + * ``` + * + * @public + */ +export class ApiEnum extends ApiItemContainerMixin( + ApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))) +) { + public constructor(options: IApiEnumOptions) { + super(options); + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.Enum}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Enum; + } + + /** @override */ + public get members(): ReadonlyArray { + return super.members as ReadonlyArray; + } + + /** @override */ + public get containerKey(): string { + return ApiEnum.getContainerKey(this.name); + } + + /** @override */ + public 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 { + const nameComponent: Component = DeclarationReference.parseComponent(this.name); + const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; + return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Enum); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiEnumMember.ts b/libraries/api-extractor-model/src/model/ApiEnumMember.ts new file mode 100644 index 00000000000..2c95578cf47 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiEnumMember.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 { + DeclarationReference, + Meaning, + 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'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin'; + +/** + * Constructor options for {@link ApiEnumMember}. + * @public + */ +export interface IApiEnumMemberOptions + extends IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiInitializerMixinOptions {} + +/** + * Options for customizing the sort order of {@link ApiEnum} members. + * + * @privateRemarks + * This enum is currently only used by the `@microsoft/api-extractor` package; it is declared here + * because we anticipate that if more options are added in the future, their sorting will be implemented + * by the `@microsoft/api-extractor-model` package. + * + * See https://github.com/microsoft/rushstack/issues/918 for details. + * + * @public + */ +export enum EnumMemberOrder { + /** + * `ApiEnumMember` items are sorted according to their {@link ApiItem.getSortKey}. The order is + * basically alphabetical by identifier name, but otherwise unspecified to allow for cosmetic improvements. + * + * This is the default behavior. + */ + ByName = 'by-name', + + /** + * `ApiEnumMember` items preserve the original order of the declarations in the source file. + * (This disables the automatic sorting that is normally applied based on {@link ApiItem.getSortKey}.) + */ + Preserve = 'preserve' +} + +/** + * Represents a member of a TypeScript enum declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiEnumMember` represents an enum member such as `Small = 100` in the example below: + * + * ```ts + * export enum FontSizes { + * Small = 100, + * Medium = 200, + * Large = 300 + * } + * ``` + * + * @public + */ +export class ApiEnumMember extends ApiNameMixin(ApiReleaseTagMixin(ApiInitializerMixin(ApiDeclaredItem))) { + public constructor(options: IApiEnumMemberOptions) { + super(options); + } + + public static getContainerKey(name: string): string { + // No prefix needed, because ApiEnumMember is the only possible member of an ApiEnum + return name; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.EnumMember; + } + + /** @override */ + public get containerKey(): string { + return ApiEnumMember.getContainerKey(this.name); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const nameComponent: Component = DeclarationReference.parseComponent(this.name); + return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) + .addNavigationStep(Navigation.Exports, nameComponent) + .withMeaning(Meaning.Member); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiFunction.ts b/libraries/api-extractor-model/src/model/ApiFunction.ts new file mode 100644 index 00000000000..39a10cacdab --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiFunction.ts @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + Meaning, + 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'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; +import { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { + type IApiTypeParameterListMixinOptions, + ApiTypeParameterListMixin +} from '../mixins/ApiTypeParameterListMixin'; +import { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiFunction}. + * @public + */ +export interface IApiFunctionOptions + extends IApiNameMixinOptions, + IApiTypeParameterListMixinOptions, + IApiParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiDeclaredItemOptions, + IApiExportedMixinOptions {} + +/** + * Represents a TypeScript function declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiFunction` represents a TypeScript declaration such as this example: + * + * ```ts + * export function getAverage(x: number, y: number): number { + * return (x + y) / 2.0; + * } + * ``` + * + * Functions are exported by an entry point module or by a namespace. Compare with {@link ApiMethod}, which + * represents a function that is a member of a class. + * + * @public + */ +export class ApiFunction extends ApiNameMixin( + ApiTypeParameterListMixin( + ApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiExportedMixin(ApiDeclaredItem)))) + ) +) { + public constructor(options: IApiFunctionOptions) { + super(options); + } + + public static getContainerKey(name: string, overloadIndex: number): string { + return `${name}|${ApiItemKind.Function}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Function; + } + + /** @override */ + public get containerKey(): string { + return ApiFunction.getContainerKey(this.name, this.overloadIndex); + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Function) + .withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiIndexSignature.ts b/libraries/api-extractor-model/src/model/ApiIndexSignature.ts new file mode 100644 index 00000000000..4a2d2f9092a --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiIndexSignature.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 { + DeclarationReference, + 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'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; +import { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; +import { type IApiReadonlyMixinOptions, ApiReadonlyMixin } from '../mixins/ApiReadonlyMixin'; + +/** + * Constructor options for {@link ApiIndexSignature}. + * @public + */ +export interface IApiIndexSignatureOptions + extends IApiParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiReadonlyMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript index signature. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiIndexSignature` represents a TypeScript declaration such as `[x: number]: number` in this example: + * + * ```ts + * export interface INumberTable { + * // An index signature + * [value: number]: number; + * + * // An overloaded index signature + * [name: string]: number; + * } + * ``` + * + * @public + */ +export class ApiIndexSignature extends ApiParameterListMixin( + ApiReleaseTagMixin(ApiReturnTypeMixin(ApiReadonlyMixin(ApiDeclaredItem))) +) { + public constructor(options: IApiIndexSignatureOptions) { + super(options); + } + + public static getContainerKey(overloadIndex: number): string { + return `|${ApiItemKind.IndexSignature}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.IndexSignature; + } + + /** @override */ + public get containerKey(): string { + return ApiIndexSignature.getContainerKey(this.overloadIndex); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const parent: DeclarationReference = this.parent + ? this.parent.canonicalReference + : // .withMeaning() requires some kind of component + DeclarationReference.empty().addNavigationStep(Navigation.Members, '(parent)'); + return parent.withMeaning(Meaning.IndexSignature).withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiInterface.ts b/libraries/api-extractor-model/src/model/ApiInterface.ts new file mode 100644 index 00000000000..aa8cdd7083d --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiInterface.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 { + DeclarationReference, + Meaning, + Navigation, + type Component +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import { ApiItemKind } from '../items/ApiItem'; +import { + ApiItemContainerMixin, + type IApiItemContainerMixinOptions, + type IApiItemContainerJson +} from '../mixins/ApiItemContainerMixin'; +import { + ApiDeclaredItem, + type IApiDeclaredItemOptions, + type IApiDeclaredItemJson +} from '../items/ApiDeclaredItem'; +import { + type IApiReleaseTagMixinOptions, + ApiReleaseTagMixin, + type IApiReleaseTagMixinJson +} from '../mixins/ApiReleaseTagMixin'; +import type { IExcerptTokenRange } from '../mixins/Excerpt'; +import { HeritageType } from './HeritageType'; +import { type IApiNameMixinOptions, ApiNameMixin, type IApiNameMixinJson } from '../mixins/ApiNameMixin'; +import { + type IApiTypeParameterListMixinOptions, + type IApiTypeParameterListMixinJson, + ApiTypeParameterListMixin +} from '../mixins/ApiTypeParameterListMixin'; +import type { DeserializerContext } from './DeserializerContext'; +import { + type IApiExportedMixinJson, + type IApiExportedMixinOptions, + ApiExportedMixin +} from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiInterface}. + * @public + */ +export interface IApiInterfaceOptions + extends IApiItemContainerMixinOptions, + IApiNameMixinOptions, + IApiTypeParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiExportedMixinOptions { + extendsTokenRanges: IExcerptTokenRange[]; +} + +export interface IApiInterfaceJson + extends IApiItemContainerJson, + IApiNameMixinJson, + IApiTypeParameterListMixinJson, + IApiReleaseTagMixinJson, + IApiDeclaredItemJson, + IApiExportedMixinJson { + extendsTokenRanges: IExcerptTokenRange[]; +} + +/** + * Represents a TypeScript class declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiInterface` represents a TypeScript declaration such as this: + * + * ```ts + * export interface X extends Y { + * } + * ``` + * + * @public + */ +export class ApiInterface extends ApiItemContainerMixin( + ApiNameMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem)))) +) { + private readonly _extendsTypes: HeritageType[] = []; + + public constructor(options: IApiInterfaceOptions) { + super(options); + + for (const extendsTokenRange of options.extendsTokenRanges) { + this._extendsTypes.push(new HeritageType(this.buildExcerpt(extendsTokenRange))); + } + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.Interface}`; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiInterfaceJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.extendsTokenRanges = jsonObject.extendsTokenRanges; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Interface; + } + + /** @override */ + public get containerKey(): string { + return ApiInterface.getContainerKey(this.name); + } + + /** + * The list of base interfaces that this interface inherits from using the `extends` keyword. + */ + public get extendsTypes(): ReadonlyArray { + return this._extendsTypes; + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.extendsTokenRanges = this.extendsTypes.map((x) => x.excerpt.tokenRange); + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Interface); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiMethod.ts b/libraries/api-extractor-model/src/model/ApiMethod.ts new file mode 100644 index 00000000000..88816d09389 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiMethod.ts @@ -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. + +import { + DeclarationReference, + Meaning, + 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'; +import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; +import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; +import { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin'; +import { ApiReturnTypeMixin, type IApiReturnTypeMixinOptions } from '../mixins/ApiReturnTypeMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { type IApiAbstractMixinOptions, ApiAbstractMixin } from '../mixins/ApiAbstractMixin'; +import { + ApiTypeParameterListMixin, + type IApiTypeParameterListMixinOptions +} from '../mixins/ApiTypeParameterListMixin'; +import { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin'; + +/** + * Constructor options for {@link ApiMethod}. + * @public + */ +export interface IApiMethodOptions + extends IApiNameMixinOptions, + IApiAbstractMixinOptions, + IApiOptionalMixinOptions, + IApiParameterListMixinOptions, + IApiProtectedMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiStaticMixinOptions, + IApiTypeParameterListMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript member function declaration that belongs to an `ApiClass`. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiMethod` represents a TypeScript declaration such as the `render` member function in this example: + * + * ```ts + * export class Widget { + * public render(): void { } + * } + * ``` + * + * Compare with {@link ApiMethodSignature}, which represents a method belonging to an interface. + * For example, a class method can be `static` but an interface method cannot. + * + * @public + */ +export class ApiMethod extends ApiNameMixin( + ApiAbstractMixin( + ApiOptionalMixin( + ApiParameterListMixin( + ApiProtectedMixin( + ApiReleaseTagMixin(ApiReturnTypeMixin(ApiStaticMixin(ApiTypeParameterListMixin(ApiDeclaredItem)))) + ) + ) + ) + ) +) { + public constructor(options: IApiMethodOptions) { + super(options); + } + + public static getContainerKey(name: string, isStatic: boolean, overloadIndex: number): string { + if (isStatic) { + return `${name}|${ApiItemKind.Method}|static|${overloadIndex}`; + } else { + return `${name}|${ApiItemKind.Method}|instance|${overloadIndex}`; + } + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Method; + } + + /** @override */ + public get containerKey(): string { + return ApiMethod.getContainerKey(this.name, this.isStatic, this.overloadIndex); + } + + /** @beta @override */ + public 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) + .withMeaning(Meaning.Member) + .withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiMethodSignature.ts b/libraries/api-extractor-model/src/model/ApiMethodSignature.ts new file mode 100644 index 00000000000..b69d9649a4e --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiMethodSignature.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 { + DeclarationReference, + Meaning, + 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'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { + type IApiTypeParameterListMixinOptions, + ApiTypeParameterListMixin +} from '../mixins/ApiTypeParameterListMixin'; +import { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin'; + +/** @public */ +export interface IApiMethodSignatureOptions + extends IApiNameMixinOptions, + IApiTypeParameterListMixinOptions, + IApiParameterListMixinOptions, + IApiReleaseTagMixinOptions, + IApiReturnTypeMixinOptions, + IApiOptionalMixinOptions, + IApiDeclaredItemOptions {} + +/** + * Represents a TypeScript member function declaration that belongs to an `ApiInterface`. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiMethodSignature` represents a TypeScript declaration such as the `render` member function in this example: + * + * ```ts + * export interface IWidget { + * render(): void; + * } + * ``` + * + * Compare with {@link ApiMethod}, which represents a method belonging to a class. + * For example, a class method can be `static` but an interface method cannot. + * + * @public + */ +export class ApiMethodSignature extends ApiNameMixin( + ApiTypeParameterListMixin( + ApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiOptionalMixin(ApiDeclaredItem)))) + ) +) { + public constructor(options: IApiMethodSignatureOptions) { + super(options); + } + + public static getContainerKey(name: string, overloadIndex: number): string { + return `${name}|${ApiItemKind.MethodSignature}|${overloadIndex}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.MethodSignature; + } + + /** @override */ + public get containerKey(): string { + return ApiMethodSignature.getContainerKey(this.name, this.overloadIndex); + } + + /** @beta @override */ + public buildCanonicalReference(): DeclarationReference { + const nameComponent: Component = DeclarationReference.parseComponent(this.name); + return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) + .addNavigationStep(Navigation.Members, nameComponent) + .withMeaning(Meaning.Member) + .withOverloadIndex(this.overloadIndex); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiModel.ts b/libraries/api-extractor-model/src/model/ApiModel.ts new file mode 100644 index 00000000000..ef60535ffb5 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiModel.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 { 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 { ModelReferenceResolver, type IResolveDeclarationReferenceResult } from './ModelReferenceResolver'; + +/** + * A serializable representation of a collection of API declarations. + * + * @remarks + * + * An `ApiModel` represents a collection of API declarations that can be serialized to disk. It captures all the + * important information needed to generate documentation, without any reliance on the TypeScript compiler engine. + * + * An `ApiModel` acts as the root of a tree of objects that all inherit from the `ApiItem` base class. + * The tree children are determined by the {@link (ApiItemContainerMixin:interface)} mixin base class. The model + * contains packages. Packages have an entry point (today, only one). And the entry point can contain various types + * of API declarations. The container relationships might look like this: + * + * ``` + * Things that can contain other things: + * + * - ApiModel + * - ApiPackage + * - ApiEntryPoint + * - ApiClass + * - ApiMethod + * - ApiProperty + * - ApiEnum + * - ApiEnumMember + * - ApiInterface + * - ApiMethodSignature + * - ApiPropertySignature + * - ApiNamespace + * - (ApiClass, ApiEnum, ApiInterace, ...) + * + * ``` + * + * Normally, API Extractor writes an .api.json file to disk for each project that it builds. Then, a tool like + * API Documenter can load the various `ApiPackage` objects into a single `ApiModel` and process them as a group. + * This is useful because compilation generally occurs separately (e.g. because projects may reside in different + * Git repos, or because they build with different TypeScript compiler configurations that may be incompatible), + * whereas API Documenter cannot detect broken hyperlinks without seeing the entire documentation set. + * + * @public + */ +export class ApiModel extends ApiItemContainerMixin(ApiItem) { + private readonly _resolver: ModelReferenceResolver; + + private _packagesByName: Map | undefined = undefined; + private _apiItemsByCanonicalReference: Map | undefined = undefined; + public constructor() { + super({}); + + this._resolver = new ModelReferenceResolver(this); + } + + public loadPackage(apiJsonFilename: string): ApiPackage { + const apiPackage: ApiPackage = ApiPackage.loadFromJsonFile(apiJsonFilename); + this.addMember(apiPackage); + return apiPackage; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Model; + } + + /** @override */ + public get containerKey(): string { + return ''; + } + + public get packages(): ReadonlyArray { + return this.members as ReadonlyArray; + } + + /** @override */ + public addMember(member: ApiPackage): void { + if (member.kind !== ApiItemKind.Package) { + throw new Error('Only items of type ApiPackage may be added to an ApiModel'); + } + super.addMember(member); + this._packagesByName = undefined; // invalidate the cache + this._apiItemsByCanonicalReference = undefined; // invalidate the cache + } + + /** + * Efficiently finds a package by the NPM package name. + * + * @remarks + * + * If the NPM scope is omitted in the package name, it will still be found provided that it is an unambiguous match. + * For example, it's often convenient to write `{@link node-core-library#JsonFile}` instead of + * `{@link @rushstack/node-core-library#JsonFile}`. + */ + public tryGetPackageByName(packageName: string): ApiPackage | undefined { + // Build the lookup on demand + if (this._packagesByName === undefined) { + this._packagesByName = new Map(); + + const unscopedMap: Map = new Map(); + + for (const apiPackage of this.packages) { + if (this._packagesByName.get(apiPackage.name)) { + // This should not happen + throw new Error(`The model contains multiple packages with the name ${apiPackage.name}`); + } + + this._packagesByName.set(apiPackage.name, apiPackage); + + const unscopedName: string = PackageName.parse(apiPackage.name).unscopedName; + + if (unscopedMap.has(unscopedName)) { + // If another package has the same unscoped name, then we won't register it + unscopedMap.set(unscopedName, undefined); + } else { + unscopedMap.set(unscopedName, apiPackage); + } + } + + for (const [unscopedName, apiPackage] of unscopedMap) { + if (apiPackage) { + if (!this._packagesByName.has(unscopedName)) { + // If the unscoped name is unambiguous, then we can also use it as a lookup + this._packagesByName.set(unscopedName, apiPackage); + } + } + } + } + + return this._packagesByName.get(packageName); + } + + public resolveDeclarationReference( + declarationReference: DocDeclarationReference | DeclarationReference, + contextApiItem: ApiItem | undefined + ): IResolveDeclarationReferenceResult { + if (declarationReference instanceof DocDeclarationReference) { + return this._resolver.resolve(declarationReference, contextApiItem); + } else if (declarationReference instanceof DeclarationReference) { + // use this._apiItemsByCanonicalReference to look up ApiItem + + // Build the lookup on demand + if (!this._apiItemsByCanonicalReference) { + this._apiItemsByCanonicalReference = new Map(); + + for (const apiPackage of this.packages) { + this._initApiItemsRecursive(apiPackage, this._apiItemsByCanonicalReference); + } + } + + const result: IResolveDeclarationReferenceResult = { + resolvedApiItem: undefined, + errorMessage: undefined + }; + + const apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get( + declarationReference.toString() + ); + + if (!apiItem) { + result.errorMessage = `${declarationReference.toString()} can not be located`; + } else { + result.resolvedApiItem = apiItem; + } + + return result; + } else { + // NOTE: The "instanceof DeclarationReference" test assumes a specific version of the @microsoft/tsdoc package. + throw new Error( + 'The "declarationReference" parameter must be an instance of' + + ' DocDeclarationReference or DeclarationReference' + ); + } + } + + private _initApiItemsRecursive(apiItem: ApiItem, apiItemsByCanonicalReference: Map): void { + if (apiItem.canonicalReference && !apiItem.canonicalReference.isEmpty) { + apiItemsByCanonicalReference.set(apiItem.canonicalReference.toString(), apiItem); + } + + // Recurse container members + if (ApiItemContainerMixin.isBaseClassOf(apiItem)) { + for (const apiMember of apiItem.members) { + this._initApiItemsRecursive(apiMember, apiItemsByCanonicalReference); + } + } + } + + /** @beta @override */ + public 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 new file mode 100644 index 00000000000..22cb9545cd1 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiNamespace.ts @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + Meaning, + 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'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiClass}. + * @public + */ +export interface IApiNamespaceOptions + extends IApiItemContainerMixinOptions, + IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiExportedMixinOptions {} + +/** + * Represents a TypeScript namespace declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiNamespace` represents a TypeScript declaration such `X` or `Y` in this example: + * + * ```ts + * export namespace X { + * export namespace Y { + * export interface IWidget { + * render(): void; + * } + * } + * } + * ``` + * + * @public + */ +export class ApiNamespace extends ApiItemContainerMixin( + ApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))) +) { + public constructor(options: IApiNamespaceOptions) { + super(options); + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.Namespace}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Namespace; + } + + /** @override */ + public get containerKey(): string { + return ApiNamespace.getContainerKey(this.name); + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Namespace); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiPackage.ts b/libraries/api-extractor-model/src/model/ApiPackage.ts new file mode 100644 index 00000000000..0a28b932933 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiPackage.ts @@ -0,0 +1,303 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; +import { + JsonFile, + type IJsonFileSaveOptions, + PackageJsonLookup, + 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'; + +/** + * Constructor options for {@link ApiPackage}. + * @public + */ +export interface IApiPackageOptions + extends IApiItemContainerMixinOptions, + IApiNameMixinOptions, + IApiDocumentedItemOptions { + tsdocConfiguration: TSDocConfiguration; + projectFolderUrl?: string; +} + +export interface IApiPackageMetadataJson { + /** + * The NPM package name for the tool that wrote the *.api.json file. + * For informational purposes only. + */ + toolPackage: string; + + /** + * The NPM package version for the tool that wrote the *.api.json file. + * For informational purposes only. + */ + toolVersion: string; + + /** + * The schema version for the .api.json file format. Used for determining whether the file format is + * supported, and for backwards compatibility. + */ + schemaVersion: ApiJsonSchemaVersion; + + /** + * To support forwards compatibility, the `oldestForwardsCompatibleVersion` field tracks the oldest schema version + * whose corresponding deserializer could safely load this file. + * + * @remarks + * Normally api-extractor-model should refuse to load a schema version that is newer than the latest version + * that its deserializer understands. However, sometimes a schema change may merely introduce some new fields + * without modifying or removing any existing fields. In this case, an older api-extractor-model library can + * safely deserialize the newer version (by ignoring the extra fields that it doesn't recognize). The newer + * serializer can use this field to communicate that. + * + * If present, the `oldestForwardsCompatibleVersion` must be less than or equal to + * `IApiPackageMetadataJson.schemaVersion`. + */ + oldestForwardsCompatibleVersion?: ApiJsonSchemaVersion; + + /** + * The TSDoc configuration that was used when analyzing the API for this package. + * + * @remarks + * + * The structure of this objet is defined by the `@microsoft/tsdoc-config` library. + * Normally this configuration is loaded from the project's tsdoc.json file. It is stored + * in the .api.json file so that doc comments can be parsed accurately when loading the file. + */ + tsdocConfig: JsonObject; +} + +export interface IApiPackageJson extends IApiItemJson { + /** + * A file header that stores metadata about the tool that wrote the *.api.json file. + */ + metadata: IApiPackageMetadataJson; + + /** + * 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. Provided via the + * `api-extractor.json` config. + */ + projectFolderUrl?: string; +} + +/** + * Options for {@link ApiPackage.saveToJsonFile}. + * @public + */ +export interface IApiPackageSaveOptions extends IJsonFileSaveOptions { + /** + * Optionally specifies a value for the "toolPackage" field in the output .api.json data file; + * otherwise, the value will be "api-extractor-model". + */ + toolPackage?: string; + + /** + * Optionally specifies a value for the "toolVersion" field in the output .api.json data file; + * otherwise, the value will be the current version of the api-extractor-model package. + */ + toolVersion?: string; + + /** + * Set to true only when invoking API Extractor's test harness. + * + * @remarks + * 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. + */ + testMode?: boolean; +} + +/** + * Represents an NPM package containing API declarations. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * @public + */ +export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumentedItem)) { + private readonly _tsdocConfiguration: TSDocConfiguration; + private readonly _projectFolderUrl?: string; + + public constructor(options: IApiPackageOptions) { + super(options); + + this._tsdocConfiguration = options.tsdocConfiguration; + this._projectFolderUrl = options.projectFolderUrl; + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiPackageJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.projectFolderUrl = jsonObject.projectFolderUrl; + } + + public static loadFromJsonFile(apiJsonFilename: string): ApiPackage { + const jsonObject: IApiPackageJson = JsonFile.load(apiJsonFilename); + + if (!jsonObject || !jsonObject.metadata || typeof jsonObject.metadata.schemaVersion !== 'number') { + throw new Error( + `Error loading ${apiJsonFilename}:` + + `\nThe file format is not recognized; the "metadata.schemaVersion" field is missing or invalid` + ); + } + + const schemaVersion: number = jsonObject.metadata.schemaVersion; + + if (schemaVersion < ApiJsonSchemaVersion.OLDEST_SUPPORTED) { + throw new Error( + `Error loading ${apiJsonFilename}:` + + `\nThe file format is version ${schemaVersion},` + + ` whereas ${ApiJsonSchemaVersion.OLDEST_SUPPORTED} is the oldest version supported by this tool` + ); + } + + let oldestForwardsCompatibleVersion: number = schemaVersion; + if (jsonObject.metadata.oldestForwardsCompatibleVersion) { + // Sanity check + if (jsonObject.metadata.oldestForwardsCompatibleVersion > schemaVersion) { + throw new Error( + `Error loading ${apiJsonFilename}:` + + `\nInvalid file format; "oldestForwardsCompatibleVersion" cannot be newer than "schemaVersion"` + ); + } + oldestForwardsCompatibleVersion = jsonObject.metadata.oldestForwardsCompatibleVersion; + } + + let versionToDeserialize: number = schemaVersion; + if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) { + // If the file format is too new, can we treat it as some earlier compatible version + // as indicated by oldestForwardsCompatibleVersion? + versionToDeserialize = Math.max(oldestForwardsCompatibleVersion, ApiJsonSchemaVersion.LATEST); + + if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) { + // Nope, still too new + throw new Error( + `Error loading ${apiJsonFilename}:` + + `\nThe file format version ${schemaVersion} was written by a newer release of` + + ` the api-extractor-model library; you may need to upgrade your software` + ); + } + } + + const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration(); + + if (versionToDeserialize >= ApiJsonSchemaVersion.V_1004) { + const tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromObject( + jsonObject.metadata.tsdocConfig + ); + if (tsdocConfigFile.hasErrors) { + throw new Error(`Error loading ${apiJsonFilename}:\n` + tsdocConfigFile.getErrorSummary()); + } + + tsdocConfigFile.configureParser(tsdocConfiguration); + } + + const context: DeserializerContext = new DeserializerContext({ + apiJsonFilename, + toolPackage: jsonObject.metadata.toolPackage, + toolVersion: jsonObject.metadata.toolVersion, + versionToDeserialize: versionToDeserialize, + tsdocConfiguration + }); + + return ApiItem.deserialize(jsonObject, context) as ApiPackage; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Package; + } + + /** @override */ + public get containerKey(): string { + // No prefix needed, because ApiPackage is the only possible member of an ApiModel + return this.name; + } + + public get entryPoints(): ReadonlyArray { + return this.members as ReadonlyArray; + } + + /** + * The TSDoc configuration that was used when analyzing the API for this package. + * + * @remarks + * + * Normally this configuration is loaded from the project's tsdoc.json file. It is stored + * in the .api.json file so that doc comments can be parsed accurately when loading the file. + */ + public get tsdocConfiguration(): TSDocConfiguration { + return this._tsdocConfiguration; + } + + public get projectFolderUrl(): string | undefined { + return this._projectFolderUrl; + } + + /** @override */ + public addMember(member: ApiEntryPoint): void { + if (member.kind !== ApiItemKind.EntryPoint) { + throw new Error('Only items of type ApiEntryPoint may be added to an ApiPackage'); + } + super.addMember(member); + } + + public findEntryPointsByPath(importPath: string): ReadonlyArray { + return this.findMembersByName(importPath) as ReadonlyArray; + } + + public saveToJsonFile(apiJsonFilename: string, options?: IApiPackageSaveOptions): void { + if (!options) { + options = {}; + } + + const packageJson: IPackageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); + + const tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(this.tsdocConfiguration); + const tsdocConfig: JsonObject = tsdocConfigFile.saveToObject(); + + const jsonObject: IApiPackageJson = { + metadata: { + toolPackage: options.toolPackage || packageJson.name, + // In test mode, we don't write the real version, since that would cause spurious diffs whenever + // the version is bumped. Instead we write a placeholder string. + toolVersion: options.testMode ? '[test mode]' : options.toolVersion || packageJson.version, + schemaVersion: ApiJsonSchemaVersion.LATEST, + oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE, + tsdocConfig + } + } as IApiPackageJson; + + if (this.projectFolderUrl) { + jsonObject.projectFolderUrl = this.projectFolderUrl; + } + + this.serializeInto(jsonObject); + JsonFile.save(jsonObject, apiJsonFilename, options); + } + + /** @beta @override */ + public 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 new file mode 100644 index 00000000000..e7a46f8ed4f --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiProperty.ts @@ -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. + +import { + DeclarationReference, + Meaning, + 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'; +import { ApiStaticMixin, type IApiStaticMixinOptions } from '../mixins/ApiStaticMixin'; +import { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin'; +import { ApiPropertyItem, type IApiPropertyItemOptions } from '../items/ApiPropertyItem'; + +/** + * Constructor options for {@link ApiProperty}. + * @public + */ +export interface IApiPropertyOptions + extends IApiPropertyItemOptions, + IApiAbstractMixinOptions, + IApiProtectedMixinOptions, + IApiStaticMixinOptions, + IApiInitializerMixinOptions {} + +/** + * Represents a TypeScript property declaration that belongs to an `ApiClass`. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiProperty` represents a TypeScript declaration such as the `width` and `height` members in this example: + * + * ```ts + * export class Widget { + * public width: number = 100; + * + * public get height(): number { + * if (this.isSquashed()) { + * return 0; + * } else { + * return this.clientArea.height; + * } + * } + * } + * ``` + * + * Note that member variables are also considered to be properties. + * + * If the property has both a getter function and setter function, they will be represented by a single `ApiProperty` + * and must have a single documentation comment. + * + * Compare with {@link ApiPropertySignature}, which represents a property belonging to an interface. + * For example, a class property can be `static` but an interface property cannot. + * + * @public + */ +export class ApiProperty extends ApiAbstractMixin( + ApiProtectedMixin(ApiStaticMixin(ApiInitializerMixin(ApiPropertyItem))) +) { + public constructor(options: IApiPropertyOptions) { + super(options); + } + + public static getContainerKey(name: string, isStatic: boolean): string { + if (isStatic) { + return `${name}|${ApiItemKind.Property}|static`; + } else { + return `${name}|${ApiItemKind.Property}|instance`; + } + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Property; + } + + /** @override */ + public get containerKey(): string { + return ApiProperty.getContainerKey(this.name, this.isStatic); + } + + /** @beta @override */ + public 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) + .withMeaning(Meaning.Member); + } +} diff --git a/apps/api-extractor-model/src/model/ApiPropertySignature.ts b/libraries/api-extractor-model/src/model/ApiPropertySignature.ts similarity index 88% rename from apps/api-extractor-model/src/model/ApiPropertySignature.ts rename to libraries/api-extractor-model/src/model/ApiPropertySignature.ts index b0f98f63cb0..490b19b2ae9 100644 --- a/apps/api-extractor-model/src/model/ApiPropertySignature.ts +++ b/libraries/api-extractor-model/src/model/ApiPropertySignature.ts @@ -1,16 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { DeclarationReference, Meaning, Navigation, Component } from '@microsoft/tsdoc/lib/beta/DeclarationReference'; +import { + DeclarationReference, + Meaning, + Navigation, + type Component +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; -import { ApiPropertyItem, IApiPropertyItemOptions } from '../items/ApiPropertyItem'; +import { ApiPropertyItem, type IApiPropertyItemOptions } from '../items/ApiPropertyItem'; /** * Constructor options for {@link ApiPropertySignature}. * @public */ -export interface IApiPropertySignatureOptions extends IApiPropertyItemOptions { -} +export interface IApiPropertySignatureOptions extends IApiPropertyItemOptions {} /** * Represents a TypeScript property declaration that belongs to an `ApiInterface`. @@ -35,7 +40,6 @@ export interface IApiPropertySignatureOptions extends IApiPropertyItemOptions { * @public */ export class ApiPropertySignature extends ApiPropertyItem { - public constructor(options: IApiPropertySignatureOptions) { super(options); } diff --git a/libraries/api-extractor-model/src/model/ApiTypeAlias.ts b/libraries/api-extractor-model/src/model/ApiTypeAlias.ts new file mode 100644 index 00000000000..db46b4e6740 --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiTypeAlias.ts @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + Meaning, + Navigation, + type Component +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; +import { ApiItemKind } from '../items/ApiItem'; +import { + ApiDeclaredItem, + type IApiDeclaredItemOptions, + type IApiDeclaredItemJson +} from '../items/ApiDeclaredItem'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { + ApiTypeParameterListMixin, + type IApiTypeParameterListMixinOptions, + type IApiTypeParameterListMixinJson +} from '../mixins/ApiTypeParameterListMixin'; +import type { DeserializerContext } from './DeserializerContext'; +import { + type IApiExportedMixinJson, + type IApiExportedMixinOptions, + ApiExportedMixin +} from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiTypeAlias}. + * @public + */ +export interface IApiTypeAliasOptions + extends IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiDeclaredItemOptions, + IApiTypeParameterListMixinOptions, + IApiExportedMixinOptions { + typeTokenRange: IExcerptTokenRange; +} + +export interface IApiTypeAliasJson + extends IApiDeclaredItemJson, + IApiTypeParameterListMixinJson, + IApiExportedMixinJson { + typeTokenRange: IExcerptTokenRange; +} + +/** + * Represents a TypeScript type alias declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiTypeAlias` represents a definition such as one of these examples: + * + * ```ts + * // A union type: + * export type Shape = Square | Triangle | Circle; + * + * // A generic type alias: + * export type BoxedValue = { value: T }; + * + * export type BoxedArray = { array: T[] }; + * + * // A conditional type alias: + * export type Boxed = T extends any[] ? BoxedArray : BoxedValue; + * + * ``` + * + * @public + */ +export class ApiTypeAlias extends ApiTypeParameterListMixin( + ApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))) +) { + /** + * An {@link Excerpt} that describes the type of the alias. + * + * @remarks + * In the example below, the `typeExcerpt` would correspond to the subexpression + * `T extends any[] ? BoxedArray : BoxedValue;`: + * + * ```ts + * export type Boxed = T extends any[] ? BoxedArray : BoxedValue; + * ``` + */ + public readonly typeExcerpt: Excerpt; + + public constructor(options: IApiTypeAliasOptions) { + super(options); + + this.typeExcerpt = this.buildExcerpt(options.typeTokenRange); + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiTypeAliasJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.typeTokenRange = jsonObject.typeTokenRange; + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.TypeAlias}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.TypeAlias; + } + + /** @override */ + public get containerKey(): string { + return ApiTypeAlias.getContainerKey(this.name); + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.typeTokenRange = this.typeExcerpt.tokenRange; + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.TypeAlias); + } +} diff --git a/libraries/api-extractor-model/src/model/ApiVariable.ts b/libraries/api-extractor-model/src/model/ApiVariable.ts new file mode 100644 index 00000000000..d49c3ea738f --- /dev/null +++ b/libraries/api-extractor-model/src/model/ApiVariable.ts @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + DeclarationReference, + Meaning, + Navigation, + type Component +} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + +import { ApiItemKind } from '../items/ApiItem'; +import { + ApiDeclaredItem, + type IApiDeclaredItemOptions, + type IApiDeclaredItemJson +} from '../items/ApiDeclaredItem'; +import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; +import { ApiReadonlyMixin, type IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin'; +import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; +import { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin'; +import type { IExcerptTokenRange, Excerpt } from '../mixins/Excerpt'; +import type { DeserializerContext } from './DeserializerContext'; +import { + type IApiExportedMixinJson, + type IApiExportedMixinOptions, + ApiExportedMixin +} from '../mixins/ApiExportedMixin'; + +/** + * Constructor options for {@link ApiVariable}. + * @public + */ +export interface IApiVariableOptions + extends IApiNameMixinOptions, + IApiReleaseTagMixinOptions, + IApiReadonlyMixinOptions, + IApiDeclaredItemOptions, + IApiInitializerMixinOptions, + IApiExportedMixinOptions { + variableTypeTokenRange: IExcerptTokenRange; +} + +export interface IApiVariableJson extends IApiDeclaredItemJson, IApiExportedMixinJson { + variableTypeTokenRange: IExcerptTokenRange; +} + +/** + * Represents a TypeScript variable declaration. + * + * @remarks + * + * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of + * API declarations. + * + * `ApiVariable` represents an exported `const` or `let` object such as these examples: + * + * ```ts + * // A variable declaration + * export let verboseLogging: boolean; + * + * // A constant variable declaration with an initializer + * export const canvas: IWidget = createCanvas(); + * ``` + * + * @public + */ +export class ApiVariable extends ApiNameMixin( + ApiReleaseTagMixin(ApiReadonlyMixin(ApiInitializerMixin(ApiExportedMixin(ApiDeclaredItem)))) +) { + /** + * An {@link Excerpt} that describes the type of the variable. + */ + public readonly variableTypeExcerpt: Excerpt; + + public constructor(options: IApiVariableOptions) { + super(options); + + this.variableTypeExcerpt = this.buildExcerpt(options.variableTypeTokenRange); + } + + /** @override */ + public static onDeserializeInto( + options: Partial, + context: DeserializerContext, + jsonObject: IApiVariableJson + ): void { + super.onDeserializeInto(options, context, jsonObject); + + options.variableTypeTokenRange = jsonObject.variableTypeTokenRange; + } + + public static getContainerKey(name: string): string { + return `${name}|${ApiItemKind.Variable}`; + } + + /** @override */ + public get kind(): ApiItemKind { + return ApiItemKind.Variable; + } + + /** @override */ + public get containerKey(): string { + return ApiVariable.getContainerKey(this.name); + } + + /** @override */ + public serializeInto(jsonObject: Partial): void { + super.serializeInto(jsonObject); + + jsonObject.variableTypeTokenRange = this.variableTypeExcerpt.tokenRange; + } + + /** @beta @override */ + public 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()) + .addNavigationStep(navigation, nameComponent) + .withMeaning(Meaning.Variable); + } +} diff --git a/libraries/api-extractor-model/src/model/Deserializer.ts b/libraries/api-extractor-model/src/model/Deserializer.ts new file mode 100644 index 00000000000..c82955286f8 --- /dev/null +++ b/libraries/api-extractor-model/src/model/Deserializer.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 { type IApiItemJson, type IApiItemOptions, type ApiItem, ApiItemKind } from '../items/ApiItem'; +import { ApiClass, type IApiClassOptions, type IApiClassJson } from './ApiClass'; +import { ApiEntryPoint, type IApiEntryPointOptions } from './ApiEntryPoint'; +import { ApiMethod, type IApiMethodOptions } from './ApiMethod'; +import { ApiModel } from './ApiModel'; +import { ApiNamespace, type IApiNamespaceOptions } from './ApiNamespace'; +import { ApiPackage, type IApiPackageOptions, type IApiPackageJson } from './ApiPackage'; +import { ApiInterface, type IApiInterfaceOptions, type IApiInterfaceJson } from './ApiInterface'; +import { ApiPropertySignature, type IApiPropertySignatureOptions } from './ApiPropertySignature'; +import { ApiMethodSignature, type IApiMethodSignatureOptions } from './ApiMethodSignature'; +import { ApiProperty, type IApiPropertyOptions } from './ApiProperty'; +import { ApiEnumMember, type IApiEnumMemberOptions } from './ApiEnumMember'; +import { ApiEnum, type IApiEnumOptions } from './ApiEnum'; +import type { IApiPropertyItemJson } from '../items/ApiPropertyItem'; +import { ApiConstructor, type IApiConstructorOptions } from './ApiConstructor'; +import { ApiConstructSignature, type IApiConstructSignatureOptions } from './ApiConstructSignature'; +import { ApiFunction, type IApiFunctionOptions } from './ApiFunction'; +import { ApiCallSignature, type IApiCallSignatureOptions } from './ApiCallSignature'; +import { ApiIndexSignature, type IApiIndexSignatureOptions } from './ApiIndexSignature'; +import { ApiTypeAlias, type IApiTypeAliasOptions, type IApiTypeAliasJson } from './ApiTypeAlias'; +import { ApiVariable, type IApiVariableOptions, type IApiVariableJson } from './ApiVariable'; +import type { IApiDeclaredItemJson } from '../items/ApiDeclaredItem'; +import type { DeserializerContext } from './DeserializerContext'; + +export class Deserializer { + public static deserialize(context: DeserializerContext, jsonObject: IApiItemJson): ApiItem { + const options: Partial = {}; + + switch (jsonObject.kind) { + case ApiItemKind.Class: + ApiClass.onDeserializeInto(options, context, jsonObject as IApiClassJson); + return new ApiClass(options as IApiClassOptions); + case ApiItemKind.CallSignature: + ApiCallSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiCallSignature(options as IApiCallSignatureOptions); + case ApiItemKind.Constructor: + ApiConstructor.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiConstructor(options as IApiConstructorOptions); + case ApiItemKind.ConstructSignature: + ApiConstructSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiConstructSignature(options as IApiConstructSignatureOptions); + case ApiItemKind.EntryPoint: + ApiEntryPoint.onDeserializeInto(options, context, jsonObject); + return new ApiEntryPoint(options as IApiEntryPointOptions); + case ApiItemKind.Enum: + ApiEnum.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiEnum(options as IApiEnumOptions); + case ApiItemKind.EnumMember: + ApiEnumMember.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiEnumMember(options as IApiEnumMemberOptions); + case ApiItemKind.Function: + ApiFunction.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiFunction(options as IApiFunctionOptions); + case ApiItemKind.IndexSignature: + ApiIndexSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiIndexSignature(options as IApiIndexSignatureOptions); + case ApiItemKind.Interface: + ApiInterface.onDeserializeInto(options, context, jsonObject as IApiInterfaceJson); + return new ApiInterface(options as IApiInterfaceOptions); + case ApiItemKind.Method: + ApiMethod.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiMethod(options as IApiMethodOptions); + case ApiItemKind.MethodSignature: + ApiMethodSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiMethodSignature(options as IApiMethodSignatureOptions); + case ApiItemKind.Model: + return new ApiModel(); + case ApiItemKind.Namespace: + ApiNamespace.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson); + return new ApiNamespace(options as IApiNamespaceOptions); + case ApiItemKind.Package: + ApiPackage.onDeserializeInto(options, context, jsonObject as IApiPackageJson); + return new ApiPackage(options as IApiPackageOptions); + case ApiItemKind.Property: + ApiProperty.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson); + return new ApiProperty(options as IApiPropertyOptions); + case ApiItemKind.PropertySignature: + ApiPropertySignature.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson); + return new ApiPropertySignature(options as IApiPropertySignatureOptions); + case ApiItemKind.TypeAlias: + ApiTypeAlias.onDeserializeInto(options, context, jsonObject as IApiTypeAliasJson); + return new ApiTypeAlias(options as IApiTypeAliasOptions); + case ApiItemKind.Variable: + ApiVariable.onDeserializeInto(options, context, jsonObject as IApiVariableJson); + return new ApiVariable(options as IApiVariableOptions); + default: + throw new Error(`Failed to deserialize unsupported API item type ${JSON.stringify(jsonObject.kind)}`); + } + } +} diff --git a/libraries/api-extractor-model/src/model/DeserializerContext.ts b/libraries/api-extractor-model/src/model/DeserializerContext.ts new file mode 100644 index 00000000000..2ad1be7b246 --- /dev/null +++ b/libraries/api-extractor-model/src/model/DeserializerContext.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSDocConfiguration } from '@microsoft/tsdoc'; + +export enum ApiJsonSchemaVersion { + /** + * The initial release. + */ + V_1000 = 1000, + + /** + * Add support for type parameters and type alias types. + */ + V_1001 = 1001, + + /** + * Remove `canonicalReference` field. This field was for diagnostic purposes only and was never deserialized. + */ + V_1002 = 1002, + + /** + * Reintroduce the `canonicalReference` field using the experimental new TSDoc declaration reference notation. + * + * This is not a breaking change because this field is never deserialized; it is provided for informational + * purposes only. + */ + V_1003 = 1003, + + /** + * Add a `tsdocConfig` field that tracks the TSDoc configuration for parsing doc comments. + * + * This is not a breaking change because an older implementation will still work correctly. The + * custom tags will be skipped over by the parser. + */ + V_1004 = 1004, + + /** + * Add an `isOptional` field to `Parameter` and `TypeParameter` to track whether a function parameter is optional. + * + * When loading older JSON files, the value defaults to `false`. + */ + V_1005 = 1005, + + /** + * Add an `isProtected` field to `ApiConstructor`, `ApiMethod`, and `ApiProperty` to + * track whether a class member has the `protected` modifier. + * + * Add an `isReadonly` field to `ApiProperty`, `ApiPropertySignature`, and `ApiVariable` to + * track whether the item is readonly. + * + * When loading older JSON files, the values default to `false`. + */ + V_1006 = 1006, + + /** + * Add `ApiItemContainerMixin.preserveMemberOrder` to support enums that preserve their original sort order. + * + * When loading older JSON files, the value default to `false`. + */ + V_1007 = 1007, + + /** + * Add an `initializerTokenRange` field to `ApiProperty` and `ApiVariable` to track the item's + * initializer. + * + * When loading older JSON files, this range is empty. + */ + V_1008 = 1008, + + /** + * Add an `isReadonly` field to `ApiIndexSignature` to track whether the item is readonly. + * + * When loading older JSON files, the values defaults to `false`. + */ + V_1009 = 1009, + + /** + * Add a `fileUrlPath` field to `ApiDeclaredItem` to track the URL to a declared item's source file. + * + * When loading older JSON files, the value defaults to `undefined`. + */ + V_1010 = 1010, + + /** + * Add an `isAbstract` field to `ApiClass`, `ApiMethod`, and `ApiProperty` to + * track whether the item is abstract. + * + * When loading older JSON files, the value defaults to `false`. + */ + V_1011 = 1011, + + /** + * The current latest .api.json schema version. + * + * IMPORTANT: When incrementing this number, consider whether `OLDEST_SUPPORTED` or `OLDEST_FORWARDS_COMPATIBLE` + * should be updated. + */ + LATEST = V_1011, + + /** + * The oldest .api.json schema version that is still supported for backwards compatibility. + * + * This must be updated if you change to the file format and do not implement compatibility logic for + * deserializing the older representation. + */ + OLDEST_SUPPORTED = V_1001, + + /** + * Used to assign `IApiPackageMetadataJson.oldestForwardsCompatibleVersion`. + * + * This value must be \<= `ApiJsonSchemaVersion.LATEST`. It must be reset to the `LATEST` value + * if the older library would not be able to deserialize your new file format. Adding a nonessential field + * is generally okay. Removing, modifying, or reinterpreting existing fields is NOT safe. + */ + OLDEST_FORWARDS_COMPATIBLE = V_1001 +} + +export class DeserializerContext { + /** + * The path of the file being deserialized, which may be useful for diagnostic purposes. + */ + public readonly apiJsonFilename: string; + + /** + * Metadata from `IApiPackageMetadataJson.toolPackage`. + */ + public readonly toolPackage: string; + + /** + * Metadata from `IApiPackageMetadataJson.toolVersion`. + */ + public readonly toolVersion: string; + + /** + * The version of the schema being deserialized, as obtained from `IApiPackageMetadataJson.schemaVersion`. + */ + public readonly versionToDeserialize: ApiJsonSchemaVersion; + + /** + * The TSDoc configuration for the context. + */ + 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; + } +} diff --git a/apps/api-extractor-model/src/model/HeritageType.ts b/libraries/api-extractor-model/src/model/HeritageType.ts similarity index 90% rename from apps/api-extractor-model/src/model/HeritageType.ts rename to libraries/api-extractor-model/src/model/HeritageType.ts index 18973d4cb4c..c07448c3d63 100644 --- a/apps/api-extractor-model/src/model/HeritageType.ts +++ b/libraries/api-extractor-model/src/model/HeritageType.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 { Excerpt } from '../mixins/Excerpt'; +import type { Excerpt } from '../mixins/Excerpt'; /** - * Represents a type referenced via an "extends" or "implements" heritage clause for a TypeScript class. + * Represents a type referenced via an "extends" or "implements" heritage clause for a TypeScript class + * or interface. + * * @remarks * * For example, consider this declaration: diff --git a/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts b/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts new file mode 100644 index 00000000000..e8282dedaab --- /dev/null +++ b/libraries/api-extractor-model/src/model/ModelReferenceResolver.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 { 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'; +import type { ApiEntryPoint } from './ApiEntryPoint'; +import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; +import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; + +/** + * Result object for {@link ApiModel.resolveDeclarationReference}. + * + * @public + */ +export interface IResolveDeclarationReferenceResult { + /** + * The referenced ApiItem, if the declaration reference could be resolved. + */ + resolvedApiItem: ApiItem | undefined; + + /** + * If resolvedApiItem is undefined, then this will always contain an error message explaining why the + * resolution failed. + */ + errorMessage: string | undefined; +} + +/** + * This resolves a TSDoc declaration reference by walking the `ApiModel` hierarchy. + * + * @remarks + * + * This class is analogous to `AstReferenceResolver` from the `@microsoft/api-extractor` project, + * which resolves declaration references by walking the compiler state. + */ +export class ModelReferenceResolver { + private readonly _apiModel: ApiModel; + + public constructor(apiModel: ApiModel) { + this._apiModel = apiModel; + } + + public resolve( + declarationReference: DocDeclarationReference, + contextApiItem: ApiItem | undefined + ): IResolveDeclarationReferenceResult { + const result: IResolveDeclarationReferenceResult = { + resolvedApiItem: undefined, + errorMessage: undefined + }; + + let apiPackage: ApiPackage | undefined = undefined; + + // Is this an absolute reference? + if (declarationReference.packageName !== undefined) { + apiPackage = this._apiModel.tryGetPackageByName(declarationReference.packageName); + if (apiPackage === undefined) { + result.errorMessage = `The package "${declarationReference.packageName}" could not be located`; + return result; + } + } else { + // If the package name is omitted, try to infer it from the context + if (contextApiItem !== undefined) { + apiPackage = contextApiItem.getAssociatedPackage(); + } + + if (apiPackage === undefined) { + result.errorMessage = + `The reference does not include a package name, and the package could not be inferred` + + ` from the context`; + return result; + } + } + + const importPath: string = declarationReference.importPath || ''; + + const foundEntryPoints: ReadonlyArray = apiPackage.findEntryPointsByPath(importPath); + if (foundEntryPoints.length !== 1) { + result.errorMessage = `The import path "${importPath}" could not be resolved`; + return result; + } + + let currentItem: ApiItem = foundEntryPoints[0]; + + // Now search for the member reference + for (const memberReference of declarationReference.memberReferences) { + if (memberReference.memberSymbol !== undefined) { + result.errorMessage = `Symbols are not yet supported in declaration references`; + return result; + } + + if (memberReference.memberIdentifier === undefined) { + result.errorMessage = `Missing member identifier`; + return result; + } + + const identifier: string = memberReference.memberIdentifier.identifier; + + if (!ApiItemContainerMixin.isBaseClassOf(currentItem)) { + // For example, {@link MyClass.myMethod.X} is invalid because methods cannot contain members + result.errorMessage = `Unable to resolve ${JSON.stringify( + identifier + )} because ${currentItem.getScopedNameWithinPackage()} cannot act as a container`; + return result; + } + + const foundMembers: ReadonlyArray = currentItem.findMembersByName(identifier); + if (foundMembers.length === 0) { + result.errorMessage = `The member reference ${JSON.stringify(identifier)} was not found`; + return result; + } + + const memberSelector: DocMemberSelector | undefined = memberReference.selector; + if (memberSelector === undefined) { + if (foundMembers.length > 1) { + result.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous`; + return result; + } + currentItem = foundMembers[0]; + } else { + let memberSelectorResult: IResolveDeclarationReferenceResult; + switch (memberSelector.selectorKind) { + case SelectorKind.System: + memberSelectorResult = this._selectUsingSystemSelector(foundMembers, memberSelector, identifier); + break; + case SelectorKind.Index: + memberSelectorResult = this._selectUsingIndexSelector(foundMembers, memberSelector, identifier); + break; + default: + result.errorMessage = `The selector "${memberSelector.selector}" is not a supported selector type`; + return result; + } + if (memberSelectorResult.resolvedApiItem === undefined) { + return memberSelectorResult; + } + currentItem = memberSelectorResult.resolvedApiItem; + } + } + result.resolvedApiItem = currentItem; + return result; + } + + private _selectUsingSystemSelector( + foundMembers: ReadonlyArray, + memberSelector: DocMemberSelector, + identifier: string + ): IResolveDeclarationReferenceResult { + const result: IResolveDeclarationReferenceResult = { + resolvedApiItem: undefined, + errorMessage: undefined + }; + + const selectorName: string = memberSelector.selector; + + let selectorItemKind: ApiItemKind; + switch (selectorName) { + case 'class': + selectorItemKind = ApiItemKind.Class; + break; + case 'enum': + selectorItemKind = ApiItemKind.Enum; + break; + case 'function': + selectorItemKind = ApiItemKind.Function; + break; + case 'interface': + selectorItemKind = ApiItemKind.Interface; + break; + case 'namespace': + selectorItemKind = ApiItemKind.Namespace; + break; + case 'type': + selectorItemKind = ApiItemKind.TypeAlias; + break; + case 'variable': + selectorItemKind = ApiItemKind.Variable; + break; + default: + result.errorMessage = `Unsupported system selector "${selectorName}"`; + return result; + } + + const matches: ApiItem[] = foundMembers.filter((x) => x.kind === selectorItemKind); + if (matches.length === 0) { + result.errorMessage = + `A declaration for "${identifier}" was not found that matches the` + + ` TSDoc selector "${selectorName}"`; + return result; + } + if (matches.length > 1) { + result.errorMessage = `More than one declaration "${identifier}" matches the TSDoc selector "${selectorName}"`; + } + result.resolvedApiItem = matches[0]; + return result; + } + + private _selectUsingIndexSelector( + foundMembers: ReadonlyArray, + memberSelector: DocMemberSelector, + identifier: string + ): IResolveDeclarationReferenceResult { + const result: IResolveDeclarationReferenceResult = { + resolvedApiItem: undefined, + errorMessage: undefined + }; + + const selectedMembers: ApiItem[] = []; + + const selectorOverloadIndex: number = parseInt(memberSelector.selector, 10); + for (const foundMember of foundMembers) { + if (ApiParameterListMixin.isBaseClassOf(foundMember)) { + if (foundMember.overloadIndex === selectorOverloadIndex) { + selectedMembers.push(foundMember); + } + } + } + + if (selectedMembers.length === 0) { + result.errorMessage = + `An overload for ${JSON.stringify(identifier)} was not found that matches` + + ` the TSDoc selector ":${selectorOverloadIndex}"`; + return result; + } + + if (selectedMembers.length === 1) { + result.resolvedApiItem = selectedMembers[0]; + return result; + } + + result.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous`; + return result; + } +} diff --git a/apps/api-extractor-model/src/model/Parameter.ts b/libraries/api-extractor-model/src/model/Parameter.ts similarity index 83% rename from apps/api-extractor-model/src/model/Parameter.ts rename to libraries/api-extractor-model/src/model/Parameter.ts index 383e895dd0f..d802380c443 100644 --- a/apps/api-extractor-model/src/model/Parameter.ts +++ b/libraries/api-extractor-model/src/model/Parameter.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 tsdoc from '@microsoft/tsdoc'; +import type * as tsdoc from '@microsoft/tsdoc'; import { ApiDocumentedItem } from '../items/ApiDocumentedItem'; -import { Excerpt } from '../mixins/Excerpt'; -import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; +import type { Excerpt } from '../mixins/Excerpt'; +import type { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; /** * Constructor options for {@link Parameter}. @@ -14,6 +14,7 @@ import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; export interface IParameterOptions { name: string; parameterTypeExcerpt: Excerpt; + isOptional: boolean; parent: ApiParameterListMixin; } @@ -45,11 +46,17 @@ export class Parameter { */ public name: string; + /** + * Whether the parameter is optional. + */ + public isOptional: boolean; + private _parent: ApiParameterListMixin; public constructor(options: IParameterOptions) { this.name = options.name; this.parameterTypeExcerpt = options.parameterTypeExcerpt; + this.isOptional = options.isOptional; this._parent = options.parent; } @@ -63,5 +70,4 @@ export class Parameter { } } } - } diff --git a/libraries/api-extractor-model/src/model/SourceLocation.ts b/libraries/api-extractor-model/src/model/SourceLocation.ts new file mode 100644 index 00000000000..4d92a07c66c --- /dev/null +++ b/libraries/api-extractor-model/src/model/SourceLocation.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 { URL } from 'node:url'; + +/** + * Constructor options for `SourceLocation`. + * @public + */ +export interface ISourceLocationOptions { + /** + * The project folder URL as defined by the `api-extractor.json` config `projectFolderUrl` + * setting. + */ + projectFolderUrl?: string; + + /** + * The file URL path relative to the `projectFolder` and `projectFolderURL` fields as + * defined in the `api-extractor.json` config. + */ + fileUrlPath?: string; +} + +/** + * The source location where a given API item is declared. + * + * @remarks + * The source location points to the `.ts` source file where the API item was originally + declared. However, in some cases, if source map resolution fails, it falls back to pointing + to the `.d.ts` file instead. + * + * @public + */ +export class SourceLocation { + private readonly _projectFolderUrl?: string; + private readonly _fileUrlPath?: string; + + public constructor(options: ISourceLocationOptions) { + this._projectFolderUrl = options.projectFolderUrl; + this._fileUrlPath = options.fileUrlPath; + } + + /** + * Returns the file URL to the given source location. Returns `undefined` if the file URL + * cannot be determined. + */ + public get fileUrl(): string | undefined { + if (this._projectFolderUrl === undefined || this._fileUrlPath === undefined) { + return undefined; + } + + let projectFolderUrl: string = this._projectFolderUrl; + if (!projectFolderUrl.endsWith('/')) { + projectFolderUrl += '/'; + } + + const url: URL = new URL(this._fileUrlPath, projectFolderUrl); + return url.href; + } +} diff --git a/apps/api-extractor-model/src/model/TypeParameter.ts b/libraries/api-extractor-model/src/model/TypeParameter.ts similarity index 87% rename from apps/api-extractor-model/src/model/TypeParameter.ts rename to libraries/api-extractor-model/src/model/TypeParameter.ts index 160caa014d8..37baa84ad92 100644 --- a/apps/api-extractor-model/src/model/TypeParameter.ts +++ b/libraries/api-extractor-model/src/model/TypeParameter.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 tsdoc from '@microsoft/tsdoc'; +import type * as tsdoc from '@microsoft/tsdoc'; import { ApiDocumentedItem } from '../items/ApiDocumentedItem'; -import { Excerpt } from '../mixins/Excerpt'; -import { ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin'; +import type { Excerpt } from '../mixins/Excerpt'; +import type { ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin'; /** * Constructor options for {@link TypeParameter}. @@ -15,6 +15,7 @@ export interface ITypeParameterOptions { name: string; constraintExcerpt: Excerpt; defaultTypeExcerpt: Excerpt; + isOptional: boolean; parent: ApiTypeParameterListMixin; } @@ -78,12 +79,18 @@ export class TypeParameter { */ public name: string; + /** + * Whether the type parameter is optional. True IFF there exists a `defaultTypeExcerpt`. + */ + public isOptional: boolean; + 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; } @@ -97,5 +104,4 @@ export class TypeParameter { } } } - } diff --git a/libraries/api-extractor-model/tsconfig.json b/libraries/api-extractor-model/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/api-extractor-model/tsconfig.json @@ -0,0 +1,3 @@ +{ + "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..bc349f9a4be --- /dev/null +++ b/libraries/credential-cache/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..d8ea9bfa5a4 --- /dev/null +++ b/libraries/credential-cache/CHANGELOG.json @@ -0,0 +1,79 @@ +{ + "name": "@rushstack/credential-cache", + "entries": [ + { + "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..b1bb0eb1272 --- /dev/null +++ b/libraries/credential-cache/CHANGELOG.md @@ -0,0 +1,31 @@ +# Change Log - @rushstack/credential-cache + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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/webpack/localization-plugin/config/api-extractor.json b/libraries/credential-cache/config/api-extractor.json similarity index 100% rename from webpack/localization-plugin/config/api-extractor.json rename to libraries/credential-cache/config/api-extractor.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..3ad64a31ae2 --- /dev/null +++ b/libraries/credential-cache/package.json @@ -0,0 +1,26 @@ +{ + "name": "@rushstack/credential-cache", + "version": "0.1.4", + "description": "Cross-platform functionality to manage cached credentials.", + "main": "lib/index.js", + "typings": "dist/credential-cache.d.ts", + "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:*" + } +} diff --git a/libraries/credential-cache/src/CredentialCache.ts b/libraries/credential-cache/src/CredentialCache.ts new file mode 100644 index 00000000000..bac9378e7a9 --- /dev/null +++ b/libraries/credential-cache/src/CredentialCache.ts @@ -0,0 +1,229 @@ +// 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 { + Disposables, + FileSystem, + JsonFile, + JsonSchema, + LockFile, + User, + Objects +} from '@rushstack/node-core-library'; + +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 { + version: string; + cacheEntries: { + [credentialCacheId: string]: ICacheEntryJson; + }; +} + +interface ICacheEntryJson { + expires: number; + credential: string; + credentialMetadata?: object; +} + +/** + * @public + */ +export interface ICredentialCacheEntry { + expires?: Date; + credential: string; + credentialMetadata?: object; +} + +/** + * @public + */ +export interface ICredentialCacheOptions { + supportEditing: boolean; + cacheFilePath?: string; +} + +/** + * @public + */ +export class CredentialCache implements Disposable { + private readonly _cacheFilePath: string; + private readonly _cacheEntries: Map; + private _modified: boolean = false; + private _disposed: boolean = false; + private readonly _supportsEditing: boolean; + private readonly _lockfile: LockFile | undefined; + + private constructor( + cacheFilePath: string, + loadedJson: ICredentialCacheJson | undefined, + lockfile: LockFile | undefined + ) { + if (loadedJson && loadedJson.version !== LATEST_CREDENTIALS_JSON_VERSION) { + throw new Error(`Unexpected ${cacheFilePath} file version: ${loadedJson.version}`); + } + + this._cacheFilePath = cacheFilePath; + this._cacheEntries = new Map(Object.entries(loadedJson?.cacheEntries || {})); + this._supportsEditing = !!lockfile; + this._lockfile = lockfile; + } + + public static async initializeAsync(options: ICredentialCacheOptions): Promise { + 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; + try { + loadedJson = await JsonFile.loadAndValidateAsync(cacheFilePath, jsonSchema); + } catch (e) { + if (!FileSystem.isErrnoException(e as Error)) { + throw e; + } + } + + let lockfile: LockFile | undefined; + if (options.supportEditing) { + lockfile = await LockFile.acquireAsync(cacheDirectory, `${cacheFileName}.lock`); + } + + const credentialCache: CredentialCache = new CredentialCache(cacheFilePath, loadedJson, lockfile); + return credentialCache; + } + + public static async usingAsync( + options: ICredentialCacheOptions, + doActionAsync: (credentialCache: CredentialCache) => Promise | void + ): Promise { + const cache: CredentialCache = await CredentialCache.initializeAsync(options); + try { + await doActionAsync(cache); + } finally { + cache.dispose(); + } + } + + public setCacheEntry(cacheId: string, entry: ICredentialCacheEntry): void { + this._validate(true); + + const { expires, credential, credentialMetadata } = entry; + const expiresMilliseconds: number = expires?.getTime() || 0; + const existingCacheEntry: ICacheEntryJson | undefined = this._cacheEntries.get(cacheId); + if ( + existingCacheEntry?.credential !== credential || + existingCacheEntry?.expires !== expiresMilliseconds || + !Objects.areDeepEqual(existingCacheEntry?.credentialMetadata, credentialMetadata) + ) { + this._modified = true; + this._cacheEntries.set(cacheId, { + expires: expiresMilliseconds, + credential, + credentialMetadata + }); + } + } + + public tryGetCacheEntry(cacheId: string): ICredentialCacheEntry | undefined { + this._validate(false); + + const cacheEntry: ICacheEntryJson | undefined = this._cacheEntries.get(cacheId); + if (cacheEntry) { + const result: ICredentialCacheEntry = { + expires: cacheEntry.expires ? new Date(cacheEntry.expires) : undefined, + credential: cacheEntry.credential, + credentialMetadata: cacheEntry.credentialMetadata + }; + + return result; + } else { + return undefined; + } + } + + public deleteCacheEntry(cacheId: string): void { + this._validate(true); + + if (this._cacheEntries.has(cacheId)) { + this._modified = true; + this._cacheEntries.delete(cacheId); + } + } + + public trimExpiredEntries(): void { + this._validate(true); + + const now: number = Date.now(); + for (const [cacheId, cacheEntry] of this._cacheEntries.entries()) { + if (cacheEntry.expires < now) { + this._cacheEntries.delete(cacheId); + this._modified = true; + } + } + } + + public async saveIfModifiedAsync(): Promise { + this._validate(true); + + if (this._modified) { + const cacheEntriesJson: { [cacheId: string]: ICacheEntryJson } = {}; + for (const [cacheId, cacheEntry] of this._cacheEntries.entries()) { + cacheEntriesJson[cacheId] = cacheEntry; + } + + const newJson: ICredentialCacheJson = { + version: LATEST_CREDENTIALS_JSON_VERSION, + cacheEntries: cacheEntriesJson + }; + await JsonFile.saveAsync(newJson, this._cacheFilePath, { + ensureFolderExists: true, + updateExistingFile: true, + ignoreUndefinedValues: true + }); + + this._modified = false; + } + } + + public [Symbol.dispose](): void { + this.dispose(); + } + + public dispose(): void { + this._lockfile?.release(); + this._disposed = true; + } + + private _validate(requiresEditing: boolean): void { + if (!this._supportsEditing && requiresEditing) { + throw new Error(`This instance of ${CredentialCache.name} does not support editing.`); + } + + if (this._disposed) { + throw new Error(`This instance of ${CredentialCache.name} has been disposed.`); + } + } +} 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/credential-cache/src/schemas/credentials.schema.json b/libraries/credential-cache/src/schemas/credentials.schema.json new file mode 100644 index 00000000000..9800b511877 --- /dev/null +++ b/libraries/credential-cache/src/schemas/credentials.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Cache for credentials used with the Rush tool.", + "description": "For use with the Rush tool, this file acts as a cache for the credentials. See http://rushjs.io for details.", + + "type": "object", + + "required": ["version", "cacheEntries"], + "properties": { + "version": { + "type": "string" + }, + + "cacheEntries": { + "type": "object", + "patternProperties": { + ".+": { + "type": "object", + "required": ["expires", "credential"], + + "properties": { + "expires": { + "type": "number" + }, + "credential": { + "type": "string" + }, + "credentialMetadata": { + "type": "object" + } + } + } + } + } + } +} 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..f0c2c1e488b --- /dev/null +++ b/libraries/credential-cache/src/test/__snapshots__/CredentialCache.test.ts.snap @@ -0,0 +1,244 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 d7953bb2a36..00000000000 --- a/libraries/debug-certificate-manager/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/debug-certificate-manager/.npmignore b/libraries/debug-certificate-manager/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/debug-certificate-manager/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/debug-certificate-manager/CHANGELOG.json b/libraries/debug-certificate-manager/CHANGELOG.json index 60e5f9c20a8..64174d9ccd3 100644 --- a/libraries/debug-certificate-manager/CHANGELOG.json +++ b/libraries/debug-certificate-manager/CHANGELOG.json @@ -1,6 +1,6969 @@ { "name": "@rushstack/debug-certificate-manager", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "1.4.11", + "tag": "@rushstack/debug-certificate-manager_v1.4.11", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "1.4.10", + "tag": "@rushstack/debug-certificate-manager_v1.4.10", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "1.4.9", + "tag": "@rushstack/debug-certificate-manager_v1.4.9", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "1.4.8", + "tag": "@rushstack/debug-certificate-manager_v1.4.8", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "1.4.7", + "tag": "@rushstack/debug-certificate-manager_v1.4.7", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "1.4.6", + "tag": "@rushstack/debug-certificate-manager_v1.4.6", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "1.4.5", + "tag": "@rushstack/debug-certificate-manager_v1.4.5", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "1.4.4", + "tag": "@rushstack/debug-certificate-manager_v1.4.4", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/debug-certificate-manager_v1.4.3", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/debug-certificate-manager_v1.4.2", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/debug-certificate-manager_v1.4.1", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/debug-certificate-manager_v1.4.0", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `skipCertificateTrust` option to `CertificateManager.ensureCertificateAsync` that skips automatically trusting the generated certificate and untrusting an existing certificate with issues." + } + ] + } + }, + { + "version": "1.3.66", + "tag": "@rushstack/debug-certificate-manager_v1.3.66", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "1.3.65", + "tag": "@rushstack/debug-certificate-manager_v1.3.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "1.3.64", + "tag": "@rushstack/debug-certificate-manager_v1.3.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "1.3.63", + "tag": "@rushstack/debug-certificate-manager_v1.3.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "1.3.62", + "tag": "@rushstack/debug-certificate-manager_v1.3.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "1.3.61", + "tag": "@rushstack/debug-certificate-manager_v1.3.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "1.3.60", + "tag": "@rushstack/debug-certificate-manager_v1.3.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "1.3.59", + "tag": "@rushstack/debug-certificate-manager_v1.3.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "1.3.58", + "tag": "@rushstack/debug-certificate-manager_v1.3.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "1.3.57", + "tag": "@rushstack/debug-certificate-manager_v1.3.57", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "1.3.56", + "tag": "@rushstack/debug-certificate-manager_v1.3.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "1.3.55", + "tag": "@rushstack/debug-certificate-manager_v1.3.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "1.3.54", + "tag": "@rushstack/debug-certificate-manager_v1.3.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "1.3.53", + "tag": "@rushstack/debug-certificate-manager_v1.3.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "1.3.52", + "tag": "@rushstack/debug-certificate-manager_v1.3.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "1.3.51", + "tag": "@rushstack/debug-certificate-manager_v1.3.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "1.3.50", + "tag": "@rushstack/debug-certificate-manager_v1.3.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "1.3.49", + "tag": "@rushstack/debug-certificate-manager_v1.3.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "1.3.48", + "tag": "@rushstack/debug-certificate-manager_v1.3.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "1.3.47", + "tag": "@rushstack/debug-certificate-manager_v1.3.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the task could report success if the subprocess was terminated by a signal" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "1.3.46", + "tag": "@rushstack/debug-certificate-manager_v1.3.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "1.3.45", + "tag": "@rushstack/debug-certificate-manager_v1.3.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "1.3.44", + "tag": "@rushstack/debug-certificate-manager_v1.3.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "1.3.43", + "tag": "@rushstack/debug-certificate-manager_v1.3.43", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "1.3.42", + "tag": "@rushstack/debug-certificate-manager_v1.3.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "1.3.41", + "tag": "@rushstack/debug-certificate-manager_v1.3.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "1.3.40", + "tag": "@rushstack/debug-certificate-manager_v1.3.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "1.3.39", + "tag": "@rushstack/debug-certificate-manager_v1.3.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "1.3.38", + "tag": "@rushstack/debug-certificate-manager_v1.3.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "1.3.37", + "tag": "@rushstack/debug-certificate-manager_v1.3.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "1.3.36", + "tag": "@rushstack/debug-certificate-manager_v1.3.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "1.3.35", + "tag": "@rushstack/debug-certificate-manager_v1.3.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "1.3.34", + "tag": "@rushstack/debug-certificate-manager_v1.3.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "1.3.33", + "tag": "@rushstack/debug-certificate-manager_v1.3.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "1.3.32", + "tag": "@rushstack/debug-certificate-manager_v1.3.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "1.3.31", + "tag": "@rushstack/debug-certificate-manager_v1.3.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "1.3.30", + "tag": "@rushstack/debug-certificate-manager_v1.3.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "1.3.29", + "tag": "@rushstack/debug-certificate-manager_v1.3.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "1.3.28", + "tag": "@rushstack/debug-certificate-manager_v1.3.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "1.3.27", + "tag": "@rushstack/debug-certificate-manager_v1.3.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "1.3.26", + "tag": "@rushstack/debug-certificate-manager_v1.3.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "1.3.25", + "tag": "@rushstack/debug-certificate-manager_v1.3.25", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "1.3.24", + "tag": "@rushstack/debug-certificate-manager_v1.3.24", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "1.3.23", + "tag": "@rushstack/debug-certificate-manager_v1.3.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "1.3.22", + "tag": "@rushstack/debug-certificate-manager_v1.3.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "1.3.21", + "tag": "@rushstack/debug-certificate-manager_v1.3.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "1.3.20", + "tag": "@rushstack/debug-certificate-manager_v1.3.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "1.3.19", + "tag": "@rushstack/debug-certificate-manager_v1.3.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "1.3.18", + "tag": "@rushstack/debug-certificate-manager_v1.3.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "1.3.17", + "tag": "@rushstack/debug-certificate-manager_v1.3.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "1.3.16", + "tag": "@rushstack/debug-certificate-manager_v1.3.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "1.3.15", + "tag": "@rushstack/debug-certificate-manager_v1.3.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "1.3.14", + "tag": "@rushstack/debug-certificate-manager_v1.3.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "1.3.13", + "tag": "@rushstack/debug-certificate-manager_v1.3.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "1.3.12", + "tag": "@rushstack/debug-certificate-manager_v1.3.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "1.3.11", + "tag": "@rushstack/debug-certificate-manager_v1.3.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "1.3.10", + "tag": "@rushstack/debug-certificate-manager_v1.3.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "1.3.9", + "tag": "@rushstack/debug-certificate-manager_v1.3.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "1.3.8", + "tag": "@rushstack/debug-certificate-manager_v1.3.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/debug-certificate-manager_v1.3.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "1.3.6", + "tag": "@rushstack/debug-certificate-manager_v1.3.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "1.3.5", + "tag": "@rushstack/debug-certificate-manager_v1.3.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "1.3.4", + "tag": "@rushstack/debug-certificate-manager_v1.3.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/debug-certificate-manager_v1.3.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/debug-certificate-manager_v1.3.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/debug-certificate-manager_v1.3.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/debug-certificate-manager_v1.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "1.2.56", + "tag": "@rushstack/debug-certificate-manager_v1.2.56", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes issues with CertificateManager when setting the certificate friendly name fails." + } + ] + } + }, + { + "version": "1.2.55", + "tag": "@rushstack/debug-certificate-manager_v1.2.55", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "1.2.54", + "tag": "@rushstack/debug-certificate-manager_v1.2.54", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "1.2.53", + "tag": "@rushstack/debug-certificate-manager_v1.2.53", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "1.2.52", + "tag": "@rushstack/debug-certificate-manager_v1.2.52", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "1.2.51", + "tag": "@rushstack/debug-certificate-manager_v1.2.51", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "1.2.50", + "tag": "@rushstack/debug-certificate-manager_v1.2.50", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "1.2.49", + "tag": "@rushstack/debug-certificate-manager_v1.2.49", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "1.2.48", + "tag": "@rushstack/debug-certificate-manager_v1.2.48", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "1.2.47", + "tag": "@rushstack/debug-certificate-manager_v1.2.47", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "1.2.46", + "tag": "@rushstack/debug-certificate-manager_v1.2.46", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "1.2.45", + "tag": "@rushstack/debug-certificate-manager_v1.2.45", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "1.2.44", + "tag": "@rushstack/debug-certificate-manager_v1.2.44", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "1.2.43", + "tag": "@rushstack/debug-certificate-manager_v1.2.43", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "1.2.42", + "tag": "@rushstack/debug-certificate-manager_v1.2.42", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "1.2.41", + "tag": "@rushstack/debug-certificate-manager_v1.2.41", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "1.2.40", + "tag": "@rushstack/debug-certificate-manager_v1.2.40", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "1.2.39", + "tag": "@rushstack/debug-certificate-manager_v1.2.39", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "1.2.38", + "tag": "@rushstack/debug-certificate-manager_v1.2.38", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "1.2.37", + "tag": "@rushstack/debug-certificate-manager_v1.2.37", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "1.2.36", + "tag": "@rushstack/debug-certificate-manager_v1.2.36", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "1.2.35", + "tag": "@rushstack/debug-certificate-manager_v1.2.35", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "1.2.34", + "tag": "@rushstack/debug-certificate-manager_v1.2.34", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "1.2.33", + "tag": "@rushstack/debug-certificate-manager_v1.2.33", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "1.2.32", + "tag": "@rushstack/debug-certificate-manager_v1.2.32", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "1.2.31", + "tag": "@rushstack/debug-certificate-manager_v1.2.31", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "1.2.30", + "tag": "@rushstack/debug-certificate-manager_v1.2.30", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "1.2.29", + "tag": "@rushstack/debug-certificate-manager_v1.2.29", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "1.2.28", + "tag": "@rushstack/debug-certificate-manager_v1.2.28", + "date": "Wed, 24 May 2023 00:19:12 GMT", + "comments": { + "patch": [ + { + "comment": "Add environment variable to force disable certificate generation. Correctly encode 127.0.0.1 as an IP Address in subjectAltNames field during certificate generation." + } + ] + } + }, + { + "version": "1.2.27", + "tag": "@rushstack/debug-certificate-manager_v1.2.27", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "1.2.26", + "tag": "@rushstack/debug-certificate-manager_v1.2.26", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "1.2.25", + "tag": "@rushstack/debug-certificate-manager_v1.2.25", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "1.2.24", + "tag": "@rushstack/debug-certificate-manager_v1.2.24", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "1.2.23", + "tag": "@rushstack/debug-certificate-manager_v1.2.23", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/debug-certificate-manager_v1.2.22", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/debug-certificate-manager_v1.2.21", + "date": "Mon, 17 Apr 2023 15:21:31 GMT", + "comments": { + "patch": [ + { + "comment": "Include \"rushstack.localhost\" and \"127.0.0.1\" in the default certificate subjects." + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/debug-certificate-manager_v1.2.20", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/debug-certificate-manager_v1.2.19", + "date": "Mon, 20 Mar 2023 20:14:20 GMT", + "comments": { + "patch": [ + { + "comment": "Force certificates with a validity period longer than the expected validity period to be refreshed." + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/debug-certificate-manager_v1.2.18", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/debug-certificate-manager_v1.2.17", + "date": "Fri, 03 Mar 2023 04:11:20 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where certificate expiration was calculated incorrectly and certificates were set to expire too late." + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/debug-certificate-manager_v1.2.16", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/debug-certificate-manager_v1.2.15", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/debug-certificate-manager_v1.2.14", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/debug-certificate-manager_v1.2.13", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/debug-certificate-manager_v1.2.12", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/debug-certificate-manager_v1.2.11", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/debug-certificate-manager_v1.2.10", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/debug-certificate-manager_v1.2.9", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/debug-certificate-manager_v1.2.8", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/debug-certificate-manager_v1.2.7", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/debug-certificate-manager_v1.2.6", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/debug-certificate-manager_v1.2.5", + "date": "Fri, 18 Nov 2022 00:55:17 GMT", + "comments": { + "patch": [ + { + "comment": "Reduce default certificate validity period to 365 days. Check certificate validity period as part of validating the existing certificate." + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/debug-certificate-manager_v1.2.4", + "date": "Sat, 12 Nov 2022 00:16:31 GMT", + "comments": { + "patch": [ + { + "comment": "Mark X.509 issuerAltName extension non-critical, since Firefox doesn't understand it." + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/debug-certificate-manager_v1.2.3", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/debug-certificate-manager_v1.2.2", + "date": "Fri, 04 Nov 2022 00:15:59 GMT", + "comments": { + "patch": [ + { + "comment": "Remove usage of Import.lazy so that the tool can be bundled." + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/debug-certificate-manager_v1.2.1", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/debug-certificate-manager_v1.2.0", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "minor": [ + { + "comment": "Support custom certificate subjects and validity period." + }, + { + "comment": "Generate and trust a separate CA certificate, use that to generate the TLS certificate, then destroy the private key for the CA certificate." + } + ] + } + }, + { + "version": "1.1.84", + "tag": "@rushstack/debug-certificate-manager_v1.1.84", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "1.1.83", + "tag": "@rushstack/debug-certificate-manager_v1.1.83", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "1.1.82", + "tag": "@rushstack/debug-certificate-manager_v1.1.82", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "1.1.81", + "tag": "@rushstack/debug-certificate-manager_v1.1.81", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "1.1.80", + "tag": "@rushstack/debug-certificate-manager_v1.1.80", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "1.1.79", + "tag": "@rushstack/debug-certificate-manager_v1.1.79", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "1.1.78", + "tag": "@rushstack/debug-certificate-manager_v1.1.78", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "1.1.77", + "tag": "@rushstack/debug-certificate-manager_v1.1.77", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "1.1.76", + "tag": "@rushstack/debug-certificate-manager_v1.1.76", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "1.1.75", + "tag": "@rushstack/debug-certificate-manager_v1.1.75", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "1.1.74", + "tag": "@rushstack/debug-certificate-manager_v1.1.74", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "1.1.73", + "tag": "@rushstack/debug-certificate-manager_v1.1.73", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "1.1.72", + "tag": "@rushstack/debug-certificate-manager_v1.1.72", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "1.1.71", + "tag": "@rushstack/debug-certificate-manager_v1.1.71", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "1.1.70", + "tag": "@rushstack/debug-certificate-manager_v1.1.70", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "1.1.69", + "tag": "@rushstack/debug-certificate-manager_v1.1.69", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "1.1.68", + "tag": "@rushstack/debug-certificate-manager_v1.1.68", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "1.1.67", + "tag": "@rushstack/debug-certificate-manager_v1.1.67", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "1.1.66", + "tag": "@rushstack/debug-certificate-manager_v1.1.66", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "1.1.65", + "tag": "@rushstack/debug-certificate-manager_v1.1.65", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "1.1.64", + "tag": "@rushstack/debug-certificate-manager_v1.1.64", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "1.1.63", + "tag": "@rushstack/debug-certificate-manager_v1.1.63", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "1.1.62", + "tag": "@rushstack/debug-certificate-manager_v1.1.62", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "1.1.61", + "tag": "@rushstack/debug-certificate-manager_v1.1.61", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "1.1.60", + "tag": "@rushstack/debug-certificate-manager_v1.1.60", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade node-forge to 1.3.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "1.1.59", + "tag": "@rushstack/debug-certificate-manager_v1.1.59", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "1.1.58", + "tag": "@rushstack/debug-certificate-manager_v1.1.58", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "1.1.57", + "tag": "@rushstack/debug-certificate-manager_v1.1.57", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "1.1.56", + "tag": "@rushstack/debug-certificate-manager_v1.1.56", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "1.1.55", + "tag": "@rushstack/debug-certificate-manager_v1.1.55", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "1.1.54", + "tag": "@rushstack/debug-certificate-manager_v1.1.54", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "1.1.53", + "tag": "@rushstack/debug-certificate-manager_v1.1.53", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "1.1.52", + "tag": "@rushstack/debug-certificate-manager_v1.1.52", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "1.1.51", + "tag": "@rushstack/debug-certificate-manager_v1.1.51", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "1.1.50", + "tag": "@rushstack/debug-certificate-manager_v1.1.50", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "1.1.49", + "tag": "@rushstack/debug-certificate-manager_v1.1.49", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "1.1.48", + "tag": "@rushstack/debug-certificate-manager_v1.1.48", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "1.1.47", + "tag": "@rushstack/debug-certificate-manager_v1.1.47", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "1.1.46", + "tag": "@rushstack/debug-certificate-manager_v1.1.46", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "1.1.45", + "tag": "@rushstack/debug-certificate-manager_v1.1.45", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "1.1.44", + "tag": "@rushstack/debug-certificate-manager_v1.1.44", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "1.1.43", + "tag": "@rushstack/debug-certificate-manager_v1.1.43", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "1.1.42", + "tag": "@rushstack/debug-certificate-manager_v1.1.42", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "1.1.41", + "tag": "@rushstack/debug-certificate-manager_v1.1.41", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "1.1.40", + "tag": "@rushstack/debug-certificate-manager_v1.1.40", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "1.1.39", + "tag": "@rushstack/debug-certificate-manager_v1.1.39", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "1.1.38", + "tag": "@rushstack/debug-certificate-manager_v1.1.38", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "1.1.37", + "tag": "@rushstack/debug-certificate-manager_v1.1.37", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "1.1.36", + "tag": "@rushstack/debug-certificate-manager_v1.1.36", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "1.1.35", + "tag": "@rushstack/debug-certificate-manager_v1.1.35", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "1.1.34", + "tag": "@rushstack/debug-certificate-manager_v1.1.34", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "1.1.33", + "tag": "@rushstack/debug-certificate-manager_v1.1.33", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "1.1.32", + "tag": "@rushstack/debug-certificate-manager_v1.1.32", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "1.1.31", + "tag": "@rushstack/debug-certificate-manager_v1.1.31", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "1.1.30", + "tag": "@rushstack/debug-certificate-manager_v1.1.30", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "1.1.29", + "tag": "@rushstack/debug-certificate-manager_v1.1.29", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "1.1.28", + "tag": "@rushstack/debug-certificate-manager_v1.1.28", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "1.1.27", + "tag": "@rushstack/debug-certificate-manager_v1.1.27", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "1.1.26", + "tag": "@rushstack/debug-certificate-manager_v1.1.26", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "1.1.25", + "tag": "@rushstack/debug-certificate-manager_v1.1.25", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "1.1.24", + "tag": "@rushstack/debug-certificate-manager_v1.1.24", + "date": "Thu, 06 Jan 2022 08:49:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an incorrect argument passed to the command to repair the certificate store on Windows." + } + ] + } + }, + { + "version": "1.1.23", + "tag": "@rushstack/debug-certificate-manager_v1.1.23", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "1.1.22", + "tag": "@rushstack/debug-certificate-manager_v1.1.22", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "1.1.21", + "tag": "@rushstack/debug-certificate-manager_v1.1.21", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "1.1.20", + "tag": "@rushstack/debug-certificate-manager_v1.1.20", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "1.1.19", + "tag": "@rushstack/debug-certificate-manager_v1.1.19", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/debug-certificate-manager_v1.1.18", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/debug-certificate-manager_v1.1.17", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/debug-certificate-manager_v1.1.16", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/debug-certificate-manager_v1.1.15", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/debug-certificate-manager_v1.1.14", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/debug-certificate-manager_v1.1.13", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/debug-certificate-manager_v1.1.12", + "date": "Tue, 09 Nov 2021 16:08:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug where ensureCertificateAsync would assume a previously generated certificate was trusted." + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/debug-certificate-manager_v1.1.11", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/debug-certificate-manager_v1.1.10", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/debug-certificate-manager_v1.1.9", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/debug-certificate-manager_v1.1.8", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/debug-certificate-manager_v1.1.7", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/debug-certificate-manager_v1.1.6", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/debug-certificate-manager_v1.1.5", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/debug-certificate-manager_v1.1.4", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/debug-certificate-manager_v1.1.3", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/debug-certificate-manager_v1.1.2", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/debug-certificate-manager_v1.1.1", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/debug-certificate-manager_v1.1.0", + "date": "Tue, 05 Oct 2021 15:08:37 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "1.0.71", + "tag": "@rushstack/debug-certificate-manager_v1.0.71", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "1.0.70", + "tag": "@rushstack/debug-certificate-manager_v1.0.70", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "1.0.69", + "tag": "@rushstack/debug-certificate-manager_v1.0.69", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "1.0.68", + "tag": "@rushstack/debug-certificate-manager_v1.0.68", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "1.0.67", + "tag": "@rushstack/debug-certificate-manager_v1.0.67", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "1.0.66", + "tag": "@rushstack/debug-certificate-manager_v1.0.66", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "1.0.65", + "tag": "@rushstack/debug-certificate-manager_v1.0.65", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "1.0.64", + "tag": "@rushstack/debug-certificate-manager_v1.0.64", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "1.0.63", + "tag": "@rushstack/debug-certificate-manager_v1.0.63", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "1.0.62", + "tag": "@rushstack/debug-certificate-manager_v1.0.62", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "1.0.61", + "tag": "@rushstack/debug-certificate-manager_v1.0.61", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "1.0.60", + "tag": "@rushstack/debug-certificate-manager_v1.0.60", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "1.0.59", + "tag": "@rushstack/debug-certificate-manager_v1.0.59", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "1.0.58", + "tag": "@rushstack/debug-certificate-manager_v1.0.58", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "1.0.57", + "tag": "@rushstack/debug-certificate-manager_v1.0.57", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "1.0.56", + "tag": "@rushstack/debug-certificate-manager_v1.0.56", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "1.0.55", + "tag": "@rushstack/debug-certificate-manager_v1.0.55", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "1.0.54", + "tag": "@rushstack/debug-certificate-manager_v1.0.54", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.0.53", + "tag": "@rushstack/debug-certificate-manager_v1.0.53", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "1.0.52", + "tag": "@rushstack/debug-certificate-manager_v1.0.52", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "1.0.51", + "tag": "@rushstack/debug-certificate-manager_v1.0.51", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "1.0.50", + "tag": "@rushstack/debug-certificate-manager_v1.0.50", + "date": "Tue, 27 Jul 2021 22:31:02 GMT", + "comments": { + "patch": [ + { + "comment": "Update node-forge to version ~0.10.0." + } + ] + } + }, + { + "version": "1.0.49", + "tag": "@rushstack/debug-certificate-manager_v1.0.49", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "1.0.48", + "tag": "@rushstack/debug-certificate-manager_v1.0.48", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "1.0.47", + "tag": "@rushstack/debug-certificate-manager_v1.0.47", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "1.0.46", + "tag": "@rushstack/debug-certificate-manager_v1.0.46", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "1.0.45", + "tag": "@rushstack/debug-certificate-manager_v1.0.45", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.0.44", + "tag": "@rushstack/debug-certificate-manager_v1.0.44", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "1.0.43", + "tag": "@rushstack/debug-certificate-manager_v1.0.43", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.0.42", + "tag": "@rushstack/debug-certificate-manager_v1.0.42", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.0.41", + "tag": "@rushstack/debug-certificate-manager_v1.0.41", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.0.40", + "tag": "@rushstack/debug-certificate-manager_v1.0.40", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.0.39", + "tag": "@rushstack/debug-certificate-manager_v1.0.39", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.0.38", + "tag": "@rushstack/debug-certificate-manager_v1.0.38", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.0.37", + "tag": "@rushstack/debug-certificate-manager_v1.0.37", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.36", + "tag": "@rushstack/debug-certificate-manager_v1.0.36", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.35", + "tag": "@rushstack/debug-certificate-manager_v1.0.35", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "1.0.34", + "tag": "@rushstack/debug-certificate-manager_v1.0.34", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "1.0.33", + "tag": "@rushstack/debug-certificate-manager_v1.0.33", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "1.0.32", + "tag": "@rushstack/debug-certificate-manager_v1.0.32", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "1.0.31", + "tag": "@rushstack/debug-certificate-manager_v1.0.31", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "1.0.30", + "tag": "@rushstack/debug-certificate-manager_v1.0.30", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "1.0.29", + "tag": "@rushstack/debug-certificate-manager_v1.0.29", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "1.0.28", + "tag": "@rushstack/debug-certificate-manager_v1.0.28", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "1.0.27", + "tag": "@rushstack/debug-certificate-manager_v1.0.27", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "1.0.26", + "tag": "@rushstack/debug-certificate-manager_v1.0.26", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "1.0.25", + "tag": "@rushstack/debug-certificate-manager_v1.0.25", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "1.0.24", + "tag": "@rushstack/debug-certificate-manager_v1.0.24", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "1.0.23", + "tag": "@rushstack/debug-certificate-manager_v1.0.23", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/debug-certificate-manager_v1.0.22", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/debug-certificate-manager_v1.0.21", + "date": "Fri, 30 Apr 2021 00:30:52 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where certmgr.exe sometimes could not be found on Windows." + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/debug-certificate-manager_v1.0.20", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/debug-certificate-manager_v1.0.19", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/debug-certificate-manager_v1.0.18", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/debug-certificate-manager_v1.0.17", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/debug-certificate-manager_v1.0.16", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/debug-certificate-manager_v1.0.15", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/debug-certificate-manager_v1.0.14", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/debug-certificate-manager_v1.0.13", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/debug-certificate-manager_v1.0.12", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/debug-certificate-manager_v1.0.11", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/debug-certificate-manager_v1.0.10", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/debug-certificate-manager_v1.0.9", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/debug-certificate-manager_v1.0.8", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/debug-certificate-manager_v1.0.7", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/debug-certificate-manager_v1.0.6", + "date": "Thu, 25 Mar 2021 04:57:54 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bug resolving the path of certutil.exe on Windows." + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/debug-certificate-manager_v1.0.5", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/debug-certificate-manager_v1.0.4", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/debug-certificate-manager_v1.0.3", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/debug-certificate-manager_v1.0.2", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/debug-certificate-manager_v1.0.1", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/debug-certificate-manager_v1.0.0", + "date": "Tue, 09 Mar 2021 23:31:46 GMT", + "comments": { + "major": [ + { + "comment": "Make the trust/untrust APIs async." + } + ] + } + }, + { + "version": "0.2.113", + "tag": "@rushstack/debug-certificate-manager_v0.2.113", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "0.2.112", + "tag": "@rushstack/debug-certificate-manager_v0.2.112", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "0.2.111", + "tag": "@rushstack/debug-certificate-manager_v0.2.111", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.2.110", + "tag": "@rushstack/debug-certificate-manager_v0.2.110", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.2.109", + "tag": "@rushstack/debug-certificate-manager_v0.2.109", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.2.108", + "tag": "@rushstack/debug-certificate-manager_v0.2.108", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.2.107", + "tag": "@rushstack/debug-certificate-manager_v0.2.107", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.2.106", + "tag": "@rushstack/debug-certificate-manager_v0.2.106", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "0.2.105", + "tag": "@rushstack/debug-certificate-manager_v0.2.105", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "0.2.104", + "tag": "@rushstack/debug-certificate-manager_v0.2.104", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "0.2.103", + "tag": "@rushstack/debug-certificate-manager_v0.2.103", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "0.2.102", + "tag": "@rushstack/debug-certificate-manager_v0.2.102", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "0.2.101", + "tag": "@rushstack/debug-certificate-manager_v0.2.101", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "0.2.100", + "tag": "@rushstack/debug-certificate-manager_v0.2.100", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "0.2.99", + "tag": "@rushstack/debug-certificate-manager_v0.2.99", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "0.2.98", + "tag": "@rushstack/debug-certificate-manager_v0.2.98", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "0.2.97", + "tag": "@rushstack/debug-certificate-manager_v0.2.97", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "0.2.96", + "tag": "@rushstack/debug-certificate-manager_v0.2.96", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "0.2.95", + "tag": "@rushstack/debug-certificate-manager_v0.2.95", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "0.2.94", + "tag": "@rushstack/debug-certificate-manager_v0.2.94", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "0.2.93", + "tag": "@rushstack/debug-certificate-manager_v0.2.93", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "0.2.92", + "tag": "@rushstack/debug-certificate-manager_v0.2.92", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "0.2.91", + "tag": "@rushstack/debug-certificate-manager_v0.2.91", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "0.2.90", + "tag": "@rushstack/debug-certificate-manager_v0.2.90", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "0.2.89", + "tag": "@rushstack/debug-certificate-manager_v0.2.89", + "date": "Tue, 03 Nov 2020 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "0.2.88", + "tag": "@rushstack/debug-certificate-manager_v0.2.88", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "0.2.87", + "tag": "@rushstack/debug-certificate-manager_v0.2.87", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "0.2.86", + "tag": "@rushstack/debug-certificate-manager_v0.2.86", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "0.2.85", + "tag": "@rushstack/debug-certificate-manager_v0.2.85", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "0.2.84", + "tag": "@rushstack/debug-certificate-manager_v0.2.84", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "0.2.83", + "tag": "@rushstack/debug-certificate-manager_v0.2.83", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "0.2.82", + "tag": "@rushstack/debug-certificate-manager_v0.2.82", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "0.2.81", + "tag": "@rushstack/debug-certificate-manager_v0.2.81", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "0.2.80", + "tag": "@rushstack/debug-certificate-manager_v0.2.80", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "0.2.79", + "tag": "@rushstack/debug-certificate-manager_v0.2.79", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "0.2.78", + "tag": "@rushstack/debug-certificate-manager_v0.2.78", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.2.77", + "tag": "@rushstack/debug-certificate-manager_v0.2.77", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.2.76", + "tag": "@rushstack/debug-certificate-manager_v0.2.76", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.2.75", + "tag": "@rushstack/debug-certificate-manager_v0.2.75", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "0.2.74", + "tag": "@rushstack/debug-certificate-manager_v0.2.74", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "0.2.73", + "tag": "@rushstack/debug-certificate-manager_v0.2.73", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "0.2.72", + "tag": "@rushstack/debug-certificate-manager_v0.2.72", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.2.71", + "tag": "@rushstack/debug-certificate-manager_v0.2.71", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.2.70", + "tag": "@rushstack/debug-certificate-manager_v0.2.70", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.2.69", + "tag": "@rushstack/debug-certificate-manager_v0.2.69", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "0.2.68", + "tag": "@rushstack/debug-certificate-manager_v0.2.68", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.2.67", + "tag": "@rushstack/debug-certificate-manager_v0.2.67", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.2.66", + "tag": "@rushstack/debug-certificate-manager_v0.2.66", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.2.65", + "tag": "@rushstack/debug-certificate-manager_v0.2.65", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.2.64", + "tag": "@rushstack/debug-certificate-manager_v0.2.64", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "0.2.63", + "tag": "@rushstack/debug-certificate-manager_v0.2.63", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "0.2.62", + "tag": "@rushstack/debug-certificate-manager_v0.2.62", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "0.2.61", + "tag": "@rushstack/debug-certificate-manager_v0.2.61", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "0.2.60", + "tag": "@rushstack/debug-certificate-manager_v0.2.60", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "0.2.59", + "tag": "@rushstack/debug-certificate-manager_v0.2.59", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "0.2.58", + "tag": "@rushstack/debug-certificate-manager_v0.2.58", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "0.2.57", + "tag": "@rushstack/debug-certificate-manager_v0.2.57", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.2.56", + "tag": "@rushstack/debug-certificate-manager_v0.2.56", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.2.55", + "tag": "@rushstack/debug-certificate-manager_v0.2.55", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.2.54", + "tag": "@rushstack/debug-certificate-manager_v0.2.54", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.2.53", + "tag": "@rushstack/debug-certificate-manager_v0.2.53", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.2.52", + "tag": "@rushstack/debug-certificate-manager_v0.2.52", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.2.51", + "tag": "@rushstack/debug-certificate-manager_v0.2.51", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "0.2.50", + "tag": "@rushstack/debug-certificate-manager_v0.2.50", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "0.2.49", + "tag": "@rushstack/debug-certificate-manager_v0.2.49", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "0.2.48", + "tag": "@rushstack/debug-certificate-manager_v0.2.48", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "0.2.47", + "tag": "@rushstack/debug-certificate-manager_v0.2.47", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.2.46", + "tag": "@rushstack/debug-certificate-manager_v0.2.46", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.2.45", + "tag": "@rushstack/debug-certificate-manager_v0.2.45", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.2.44", + "tag": "@rushstack/debug-certificate-manager_v0.2.44", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.2.43", + "tag": "@rushstack/debug-certificate-manager_v0.2.43", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.2.42", + "tag": "@rushstack/debug-certificate-manager_v0.2.42", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "0.2.41", + "tag": "@rushstack/debug-certificate-manager_v0.2.41", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.2.40", + "tag": "@rushstack/debug-certificate-manager_v0.2.40", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.2.39", + "tag": "@rushstack/debug-certificate-manager_v0.2.39", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@rushstack/debug-certificate-manager_v0.2.38", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/debug-certificate-manager_v0.2.37", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/debug-certificate-manager_v0.2.36", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@rushstack/debug-certificate-manager_v0.2.35", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/debug-certificate-manager_v0.2.34", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/debug-certificate-manager_v0.2.33", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/debug-certificate-manager_v0.2.32", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/debug-certificate-manager_v0.2.31", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/debug-certificate-manager_v0.2.30", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/debug-certificate-manager_v0.2.29", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/debug-certificate-manager_v0.2.28", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/debug-certificate-manager_v0.2.27", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/debug-certificate-manager_v0.2.26", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/debug-certificate-manager_v0.2.25", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/debug-certificate-manager_v0.2.24", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/debug-certificate-manager_v0.2.23", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/debug-certificate-manager_v0.2.22", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/debug-certificate-manager_v0.2.21", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/debug-certificate-manager_v0.2.20", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/debug-certificate-manager_v0.2.19", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/debug-certificate-manager_v0.2.18", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/debug-certificate-manager_v0.2.17", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/debug-certificate-manager_v0.2.16", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/debug-certificate-manager_v0.2.15", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/debug-certificate-manager_v0.2.14", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/debug-certificate-manager_v0.2.13", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/debug-certificate-manager_v0.2.12", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/debug-certificate-manager_v0.2.11", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/debug-certificate-manager_v0.2.10", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/debug-certificate-manager_v0.2.9", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/debug-certificate-manager_v0.2.8", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/debug-certificate-manager_v0.2.7", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/debug-certificate-manager_v0.2.6", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/debug-certificate-manager_v0.2.5", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/debug-certificate-manager_v0.2.4", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "0.2.3", "tag": "@rushstack/debug-certificate-manager_v0.2.3", diff --git a/libraries/debug-certificate-manager/CHANGELOG.md b/libraries/debug-certificate-manager/CHANGELOG.md index d47c138291d..d518f4248b0 100644 --- a/libraries/debug-certificate-manager/CHANGELOG.md +++ b/libraries/debug-certificate-manager/CHANGELOG.md @@ -1,11 +1,2322 @@ # Change Log - @rushstack/debug-certificate-manager -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 1.4.11 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 1.4.10 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 1.4.9 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 1.4.8 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 1.4.7 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 1.4.6 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 1.4.5 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 1.4.4 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 1.4.3 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 1.4.2 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 1.4.1 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 1.4.0 +Sat, 21 Sep 2024 00:10:27 GMT + +### Minor changes + +- Add a `skipCertificateTrust` option to `CertificateManager.ensureCertificateAsync` that skips automatically trusting the generated certificate and untrusting an existing certificate with issues. + +## 1.3.66 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 1.3.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 1.3.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 1.3.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 1.3.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 1.3.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 1.3.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 1.3.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 1.3.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 1.3.57 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 1.3.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 1.3.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 1.3.54 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 1.3.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 1.3.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 1.3.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 1.3.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 1.3.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 1.3.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 1.3.47 +Thu, 23 May 2024 02:26:56 GMT + +### Patches + +- Fix an issue where the task could report success if the subprocess was terminated by a signal + +## 1.3.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 1.3.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 1.3.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 1.3.43 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 1.3.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 1.3.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 1.3.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 1.3.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 1.3.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 1.3.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 1.3.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 1.3.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 1.3.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 1.3.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 1.3.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 1.3.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 1.3.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 1.3.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 1.3.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 1.3.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 1.3.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 1.3.25 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 1.3.24 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 1.3.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 1.3.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 1.3.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 1.3.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 1.3.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 1.3.18 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 1.3.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 1.3.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 1.3.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 1.3.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 1.3.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 1.3.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 1.3.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 1.3.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 1.3.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 1.3.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 1.3.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 1.3.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 1.3.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 1.3.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 1.3.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 1.3.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 1.3.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 1.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 1.2.56 +Wed, 13 Sep 2023 00:32:29 GMT + +### Patches + +- Fixes issues with CertificateManager when setting the certificate friendly name fails. + +## 1.2.55 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 1.2.54 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 1.2.53 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 1.2.52 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 1.2.51 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 1.2.50 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 1.2.49 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 1.2.48 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 1.2.47 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 1.2.46 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 1.2.45 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 1.2.44 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 1.2.43 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 1.2.42 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 1.2.41 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 1.2.40 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 1.2.39 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 1.2.38 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 1.2.37 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 1.2.36 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 1.2.35 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 1.2.34 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 1.2.33 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 1.2.32 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 1.2.31 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 1.2.30 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 1.2.29 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 1.2.28 +Wed, 24 May 2023 00:19:12 GMT + +### Patches + +- Add environment variable to force disable certificate generation. Correctly encode 127.0.0.1 as an IP Address in subjectAltNames field during certificate generation. + +## 1.2.27 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 1.2.26 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 1.2.25 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 1.2.24 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 1.2.23 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 1.2.22 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 1.2.21 +Mon, 17 Apr 2023 15:21:31 GMT + +### Patches + +- Include "rushstack.localhost" and "127.0.0.1" in the default certificate subjects. + +## 1.2.20 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 1.2.19 +Mon, 20 Mar 2023 20:14:20 GMT + +### Patches + +- Force certificates with a validity period longer than the expected validity period to be refreshed. + +## 1.2.18 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 1.2.17 +Fri, 03 Mar 2023 04:11:20 GMT + +### Patches + +- Fix an issue where certificate expiration was calculated incorrectly and certificates were set to expire too late. + +## 1.2.16 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 1.2.15 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 1.2.14 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 1.2.13 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 1.2.12 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 1.2.11 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 1.2.10 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 1.2.9 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 1.2.8 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 1.2.7 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 1.2.6 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 1.2.5 +Fri, 18 Nov 2022 00:55:17 GMT + +### Patches + +- Reduce default certificate validity period to 365 days. Check certificate validity period as part of validating the existing certificate. + +## 1.2.4 +Sat, 12 Nov 2022 00:16:31 GMT + +### Patches + +- Mark X.509 issuerAltName extension non-critical, since Firefox doesn't understand it. + +## 1.2.3 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 1.2.2 +Fri, 04 Nov 2022 00:15:59 GMT + +### Patches + +- Remove usage of Import.lazy so that the tool can be bundled. + +## 1.2.1 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 1.2.0 +Tue, 25 Oct 2022 00:20:44 GMT + +### Minor changes + +- Support custom certificate subjects and validity period. +- Generate and trust a separate CA certificate, use that to generate the TLS certificate, then destroy the private key for the CA certificate. + +## 1.1.84 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 1.1.83 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 1.1.82 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 1.1.81 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 1.1.80 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 1.1.79 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 1.1.78 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 1.1.77 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 1.1.76 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 1.1.75 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 1.1.74 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.1.73 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.1.72 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.1.71 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.1.70 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.1.69 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.1.68 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.1.67 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 1.1.66 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.1.65 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.1.64 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 1.1.63 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.1.62 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 1.1.61 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.1.60 +Wed, 13 Jul 2022 21:31:13 GMT + +### Patches + +- Upgrade node-forge to 1.3.1 + +## 1.1.59 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 1.1.58 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.1.57 +Thu, 30 Jun 2022 04:48:53 GMT + +_Version update only_ + +## 1.1.56 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 1.1.55 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.1.54 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.1.53 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.1.52 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.1.51 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.1.50 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 1.1.49 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.1.48 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 1.1.47 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 1.1.46 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 1.1.45 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 1.1.44 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.1.43 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.1.42 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.1.41 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.1.40 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 1.1.39 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.1.38 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 1.1.37 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.1.36 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.1.35 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.1.34 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.1.33 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.1.32 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.1.31 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.1.30 +Sat, 19 Mar 2022 08:05:37 GMT + +_Version update only_ + +## 1.1.29 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 1.1.28 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 1.1.27 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 1.1.26 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 1.1.25 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 1.1.24 +Thu, 06 Jan 2022 08:49:34 GMT + +### Patches + +- Fix an incorrect argument passed to the command to repair the certificate store on Windows. + +## 1.1.23 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.1.22 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.1.21 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 1.1.20 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.1.19 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.1.18 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.1.17 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 1.1.16 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 1.1.15 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.1.14 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 1.1.13 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.1.12 +Tue, 09 Nov 2021 16:08:07 GMT + +### Patches + +- Fix a bug where ensureCertificateAsync would assume a previously generated certificate was trusted. + +## 1.1.11 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.1.10 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.1.9 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.1.8 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.1.7 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 1.1.6 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.1.5 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.1.4 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.1.3 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.1.2 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 1.1.1 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.1.0 +Tue, 05 Oct 2021 15:08:37 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 1.0.71 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.0.70 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.0.69 +Thu, 23 Sep 2021 00:10:40 GMT + +_Version update only_ + +## 1.0.68 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.0.67 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.0.66 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.0.65 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.0.64 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.0.63 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.0.62 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.0.61 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.0.60 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 1.0.59 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.0.58 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.0.57 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.0.56 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 1.0.55 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.0.54 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 1.0.53 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 1.0.52 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.0.51 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.0.50 +Tue, 27 Jul 2021 22:31:02 GMT + +### Patches + +- Update node-forge to version ~0.10.0. + +## 1.0.49 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.0.48 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.0.47 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.0.46 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.0.45 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.0.44 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.0.43 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.0.42 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.0.41 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.0.40 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.0.39 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.0.38 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.0.37 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.0.36 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 1.0.35 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.0.34 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 1.0.33 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.0.32 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.0.31 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.0.30 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.0.29 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.0.28 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.0.27 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 1.0.26 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.0.25 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.0.24 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 1.0.23 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.0.22 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.0.21 +Fri, 30 Apr 2021 00:30:52 GMT + +### Patches + +- Fix an issue where certmgr.exe sometimes could not be found on Windows. + +## 1.0.20 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.0.19 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.0.18 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 1.0.17 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 1.0.16 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 1.0.15 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.0.14 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 1.0.13 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.0.12 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 1.0.11 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.0.10 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.0.9 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.0.8 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.0.7 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 1.0.6 +Thu, 25 Mar 2021 04:57:54 GMT + +### Patches + +- Fix bug resolving the path of certutil.exe on Windows. + +## 1.0.5 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 1.0.4 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.0.3 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.0.2 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 1.0.1 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 1.0.0 +Tue, 09 Mar 2021 23:31:46 GMT + +### Breaking changes + +- Make the trust/untrust APIs async. + +## 0.2.113 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.2.112 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.2.111 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.2.110 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.2.109 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 0.2.108 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.2.107 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 0.2.106 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.2.105 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.2.104 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.2.103 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.2.102 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.2.101 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.2.100 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.2.99 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.2.98 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.2.97 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.2.96 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.2.95 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.2.94 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.2.93 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 0.2.92 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.2.91 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.2.90 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.2.89 +Tue, 03 Nov 2020 01:11:18 GMT + +_Version update only_ + +## 0.2.88 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.2.87 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.2.86 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.2.85 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 0.2.84 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 0.2.83 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.2.82 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 0.2.81 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 0.2.80 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.2.79 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 0.2.78 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 0.2.77 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.2.76 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 0.2.75 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 0.2.74 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 0.2.73 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 0.2.72 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.2.71 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.2.70 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 0.2.69 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 0.2.68 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.2.67 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 0.2.66 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.2.65 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 0.2.64 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.2.63 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.2.62 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.2.61 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.2.60 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.2.59 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.2.58 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 0.2.57 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 0.2.56 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 0.2.55 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 0.2.54 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 0.2.53 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.2.52 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 0.2.51 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 0.2.50 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 0.2.49 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 0.2.48 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 0.2.47 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 0.2.46 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 0.2.45 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 0.2.44 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 0.2.43 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 0.2.42 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 0.2.41 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 0.2.40 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 0.2.39 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 0.2.38 +Thu, 20 Aug 2020 15:13:52 GMT + +_Version update only_ + +## 0.2.37 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 0.2.36 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 0.2.35 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 0.2.34 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 0.2.33 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 0.2.32 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 0.2.31 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 0.2.30 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 0.2.29 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 0.2.28 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 0.2.27 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 0.2.26 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 0.2.25 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 0.2.24 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 0.2.23 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 0.2.22 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 0.2.21 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 0.2.20 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 0.2.19 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 0.2.18 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 0.2.17 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 0.2.16 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 0.2.15 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 0.2.14 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 0.2.13 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 0.2.12 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 0.2.11 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 0.2.10 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 0.2.9 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 0.2.8 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 0.2.7 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 0.2.6 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 0.2.5 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 0.2.4 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 0.2.3 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 0.2.2 Tue, 17 Mar 2020 23:55:58 GMT @@ -17,7 +2328,7 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 0.2.1 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 0.2.0 Fri, 24 Jan 2020 00:27:39 GMT diff --git a/libraries/debug-certificate-manager/README.md b/libraries/debug-certificate-manager/README.md index f9af6ca77ae..59ecac4eb78 100644 --- a/libraries/debug-certificate-manager/README.md +++ b/libraries/debug-certificate-manager/README.md @@ -9,7 +9,6 @@ This library contains utilities for managing debug certificates in a development server environment. It provides functions to generate, self-sign, trust, and untrust .pem certificates for both Windows and Mac OS. It will also generate self-signed certificates on other OS's, but the user must manually trust and untrust them. [![npm version](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager.svg)](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager) -[![Build Status](https://travis-ci.org/Microsoft/debug-certificate-manager.svg?branch=master)](https://travis-ci.org/Microsoft/debug-certificate-manager) [![Dependencies](https://david-dm.org/Microsoft/debug-certificate-manager.svg)](https://david-dm.org/Microsoft/debug-certificate-manager) ## `CertificateStore` @@ -28,7 +27,7 @@ Set data using the same property names `certificateData: string | undefined` and ## `ensureCertificate` -Get a dev certificate from the store, or optionally, generate a new one and trust it if one does not exist in the store. Returns a certificate object following the `ICertificate` interface. +Get a development certificate from the store, or optionally, generate a new one and trust it if one does not exist in the store. Returns a certificate object following the `ICertificate` interface. ```typescript export interface ICertificate { @@ -41,10 +40,11 @@ export interface ICertificate { Attempts to locate a previously generated debug certificate and untrust it. Returns a `boolean` value to denote success. -## API Documentation +## Links -Complete API documentation for this package: https://rushstack.io/pages/api/debug-certificate-manager/ +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/debug-certificate-manager/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/debug-certificate-manager/) -# License - -MIT (http://www.opensource.org/licenses/mit-license.php) +**@rushstack/debug-certificate-manager** is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/debug-certificate-manager/config/jest.json b/libraries/debug-certificate-manager/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/libraries/debug-certificate-manager/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/libraries/debug-certificate-manager/config/rig.json b/libraries/debug-certificate-manager/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/debug-certificate-manager/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/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/gulpfile.js b/libraries/debug-certificate-manager/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/libraries/debug-certificate-manager/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/libraries/debug-certificate-manager/package.json b/libraries/debug-certificate-manager/package.json index 43d8633ed31..028c2eb004f 100644 --- a/libraries/debug-certificate-manager/package.json +++ b/libraries/debug-certificate-manager/package.json @@ -1,29 +1,28 @@ { "name": "@rushstack/debug-certificate-manager", - "version": "0.2.3", + "version": "1.6.7", "description": "Cross-platform functionality to create debug ssl certificates.", "main": "lib/index.js", "typings": "dist/debug-certificate-manager.d.ts", "license": "MIT", "repository": { - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/debug-certificate-manager" + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/debug-certificate-manager" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "deasync": "~0.1.19", - "node-forge": "~0.7.1", - "sudo": "~1.0.3" + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "node-forge": "~1.3.1" }, "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "@types/node-forge": "0.9.1", - "gulp": "~4.0.2" + "@rushstack/heft": "workspace:*", + "@types/node-forge": "1.0.4", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/libraries/debug-certificate-manager/src/CertificateManager.ts b/libraries/debug-certificate-manager/src/CertificateManager.ts index a5ac4b8f42f..f36143fd050 100644 --- a/libraries/debug-certificate-manager/src/CertificateManager.ts +++ b/libraries/debug-certificate-manager/src/CertificateManager.ts @@ -1,20 +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 forge from 'node-forge'; -import * as path from 'path'; -import * as child_process from 'child_process'; -import { EOL } from 'os'; -import { FileSystem, Terminal } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +import { EOL } from 'node:os'; -import { runSudoSync, ISudoSyncResult } from './sudoSync'; -import { CertificateStore } from './CertificateStore'; +import type { pki } from 'node-forge'; -const serialNumber: string = '731c321744e34650a202e3ef91c3c1b0'; -const friendlyName: string = 'debug-certificate-manager Development Certificate'; -const macKeychain: string = '/Library/Keychains/System.keychain'; +import { FileSystem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; -let _certutilExePath: string | undefined; +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'; +const FRIENDLY_NAME: string = 'debug-certificate-manager Development Certificate'; +const MAC_KEYCHAIN: string = '/Library/Keychains/System.keychain'; +const CERTUTIL_EXE_NAME: string = 'certutil'; +const CA_ALT_NAME: string = 'rushstack-certificate-manager.localhost'; +const ONE_DAY_IN_MILLISECONDS: number = 24 * 60 * 60 * 1000; + +/** + * The set of names the certificate should be generated for, by default. + * @public + */ +export const DEFAULT_CERTIFICATE_SUBJECT_NAMES: ReadonlyArray = ['localhost']; + +/** + * 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', '::1']; + +const DISABLE_CERT_GENERATION_VARIABLE_NAME: 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION' = + 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION'; /** * The interface for a debug certificate instance @@ -23,15 +42,114 @@ let _certutilExePath: string | undefined; */ export interface ICertificate { /** - * Generated pem certificate contents + * Generated pem Certificate Authority certificate contents + */ + pemCaCertificate: string | undefined; + + /** + * Generated pem TLS Server certificate contents */ pemCertificate: string | undefined; /** - * Private key used to sign the pem certificate + * Private key for the TLS server certificate, used to sign TLS communications */ pemKey: string | undefined; + + /** + * The subject names the TLS server certificate is valid for + */ + 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 + */ + certificate: pki.Certificate; + + /** + * Private key for the CA cert. Delete after signing the TLS cert. + */ + privateKey: pki.PrivateKey; +} + +interface ISubjectAltNameExtension { + altNames: readonly IAltName[]; +} + +/** + * Fields for a Subject Alternative Name of type DNS Name + */ +interface IDnsAltName { + type: 2; + value: string; +} +/** + * Fields for a Subject Alternative Name of type IP Address + * `node-forge` requires the field name to be "ip" instead of "value", likely due to subtle encoding differences. + */ +interface IIPAddressAltName { + type: 7; + ip: string; } +type IAltName = IDnsAltName | IIPAddressAltName; + +/** + * Options to use if needing to generate a new certificate + * @public + */ +export interface ICertificateGenerationOptions { + /** + * The DNS Subject names to issue the certificate for. Defaults to ['localhost']. + */ + subjectAltNames?: ReadonlyArray; + /** + * The IP Address Subject names to issue the certificate for. Defaults to ['127.0.0.1']. + */ + subjectIPAddresses?: ReadonlyArray; + /** + * How many days the certificate should be valid for. + */ + validityInDays?: number; + /** + * Skip trusting a certificate. Defaults to false. + */ + 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. @@ -39,51 +157,77 @@ export interface ICertificate { * @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); } /** - * Get a dev certificate from the store, or optionally, generate a new one + * Get a development certificate from the store, or optionally, generate a new one * and trust it if one doesn't exist in the store. * * @public */ - public ensureCertificate( + public async ensureCertificateAsync( canGenerateNewCertificate: boolean, - terminal: Terminal - ): ICertificate { - - if (this._certificateStore.certificateData && this._certificateStore.keyData) { - if (!this._certificateHasSubjectAltName()) { - let warningMessage: string = ( - 'The existing development certificate is missing the subjectAltName ' + - 'property and will not work with the latest versions of some browsers. ' - ); + terminal: ITerminal, + options?: ICertificateGenerationOptions + ): Promise { + const optionsWithDefaults: Required = applyDefaultOptions(options); + + 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. ` + + VS_CODE_EXTENSION_FIX_MESSAGE + ); + canGenerateNewCertificate = false; + } - if (canGenerateNewCertificate) { - warningMessage += ' Attempting to untrust the certificate and generate a new one.'; - } else { - warningMessage += ' Untrust the certificate and generate a new one.'; - } + // Validate existing certificates + const validationResult: ICertificateValidationResult = await this.validateCertificateAsync( + terminal, + options + ); - terminal.writeWarningLine(warningMessage); + if (validationResult.isValid && validationResult.certificate) { + // Existing certificate is valid, return it + return validationResult.certificate; + } - if (canGenerateNewCertificate) { - this.untrustCertificate(terminal); - this._ensureCertificateInternal(terminal); + // 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.' + ); + terminal.writeWarningLine(validationResult.validationMessages.join(' ')); + if (!options?.skipCertificateTrust) { + await this.untrustCertificateAsync(terminal); } + return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); + } else { + 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) { - this._ensureCertificateInternal(terminal); + 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`. ' + + VS_CODE_EXTENSION_FIX_MESSAGE + ); } - - return { - pemCertificate: this._certificateStore.certificateData, - pemKey: this._certificateStore.keyData - }; } /** @@ -91,20 +235,22 @@ export class CertificateManager { * * @public */ - public untrustCertificate(terminal: Terminal): boolean { + public async untrustCertificateAsync(terminal: ITerminal): Promise { + this.certificateStore.certificateData = undefined; + this.certificateStore.keyData = undefined; + this.certificateStore.caCertificateData = undefined; + switch (process.platform) { case 'win32': - const certutilExePath: string | undefined = this._ensureCertUtilExePath(terminal); - if (!certutilExePath) { - // Unable to find the cert utility - return false; - } - - const winUntrustResult: child_process.SpawnSyncReturns = - child_process.spawnSync(certutilExePath, ['-user', '-delstore', 'root', serialNumber]); - - if (winUntrustResult.status !== 0) { - terminal.writeErrorLine(`Error: ${winUntrustResult.stdout.toString()}`); + const winUntrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [ + '-user', + '-delstore', + 'root', + CA_SERIAL_NUMBER + ]); + + if (winUntrustResult.exitCode !== 0) { + terminal.writeErrorLine(`Error: ${winUntrustResult.stderr.join(' ')}`); return false; } else { terminal.writeVerboseLine('Successfully untrusted development certificate.'); @@ -112,44 +258,43 @@ export class CertificateManager { } case 'darwin': - terminal.writeVerboseLine('Trying to find the signature of the dev cert'); - - const macFindCertificateResult: child_process.SpawnSyncReturns = - child_process.spawnSync('security', ['find-certificate', '-c', 'localhost', '-a', '-Z', macKeychain]); - if (macFindCertificateResult.status !== 0) { - terminal.writeErrorLine(`Error finding the dev certificate: ${macFindCertificateResult.output.join(' ')}`); + terminal.writeVerboseLine('Trying to find the signature of the development certificate.'); + + const macFindCertificateResult: IRunResult = await runAsync('security', [ + 'find-certificate', + '-c', + CA_ALT_NAME, + '-a', + '-Z', + MAC_KEYCHAIN + ]); + if (macFindCertificateResult.exitCode !== 0) { + terminal.writeErrorLine( + `Error finding the development certificate: ${macFindCertificateResult.stderr.join(' ')}` + ); return false; } - const outputLines: string[] = macFindCertificateResult.stdout.toString().split(EOL); - let found: boolean = false; - let shaHash: string = ""; - for (let i: number = 0; i < outputLines.length; i++) { - const line: string = outputLines[i]; - const shaMatch: string[] | null = line.match(/^SHA-1 hash: (.+)$/); - if (shaMatch) { - shaHash = shaMatch[1]; - } - - const snbrMatch: string[] | null = line.match(/^\s*"snbr"=0x([^\s]+).+$/); - if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === serialNumber) { - found = true; - break; - } - } + const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash( + macFindCertificateResult.stdout.join(EOL) + ); - if (!found) { - terminal.writeErrorLine('Unable to find the dev certificate.'); + if (!shaHash) { + terminal.writeErrorLine('Unable to find the development certificate.'); return false; + } else { + terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`); } - terminal.writeVerboseLine(`Found the dev cert. SHA is ${shaHash}`); - - const macUntrustResult: ISudoSyncResult = - runSudoSync(['security', 'delete-certificate', '-Z', shaHash, macKeychain]); + const macUntrustResult: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ + 'delete-certificate', + '-Z', + shaHash, + MAC_KEYCHAIN + ]); - if (macUntrustResult.code === 0) { - terminal.writeVerboseLine('Successfully untrusted dev certificate.'); + if (macUntrustResult.exitCode === 0) { + terminal.writeVerboseLine('Successfully untrusted development certificate.'); return true; } else { terminal.writeErrorLine(macUntrustResult.stderr.join(' ')); @@ -160,117 +305,220 @@ export class CertificateManager { // Linux + others: Have the user manually untrust the cert 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 ` + - `certificate has serial number "${serialNumber}".` + 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' + + `root certification authorities: "${this.certificateStore.certificatePath}". The ` + + `certificate has serial number "${CA_SERIAL_NUMBER}".` ); return false; } } - - private _createDevelopmentCertificate(): ICertificate { - const keys: forge.pki.KeyPair = forge.pki.rsa.generateKeyPair(2048); - const certificate: forge.pki.Certificate = forge.pki.createCertificate(); + private async _createCACertificateAsync( + validityInDays: number, + forge: typeof import('node-forge') + ): Promise { + const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048); + const certificate: pki.Certificate = forge.pki.createCertificate(); certificate.publicKey = keys.publicKey; - certificate.serialNumber = serialNumber; + certificate.serialNumber = CA_SERIAL_NUMBER; - const now: Date = new Date(); - certificate.validity.notBefore = now; - // Valid for 3 years - certificate.validity.notAfter.setFullYear(certificate.validity.notBefore.getFullYear() + 3); + const notBefore: Date = new Date(); + const notAfter: Date = new Date(notBefore); + notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays); + certificate.validity.notBefore = notBefore; + certificate.validity.notAfter = notAfter; - const attrs: forge.pki.CertificateField[] = [{ - name: 'commonName', - value: 'localhost' - }]; + const attrs: pki.CertificateField[] = [ + { + name: 'commonName', + value: CA_ALT_NAME + } + ]; certificate.setSubject(attrs); certificate.setIssuer(attrs); + const altNames: readonly IAltName[] = [ + { + type: 2, // DNS + value: CA_ALT_NAME + } + ]; + certificate.setExtensions([ + { + name: 'basicConstraints', + cA: true, + pathLenConstraint: 0, + critical: true + }, { name: 'subjectAltName', - altNames: [{ - type: 2, // DNS - value: 'localhost' - }] + altNames, + critical: true + }, + { + name: 'issuerAltName', + altNames, + critical: false }, { name: 'keyUsage', - digitalSignature: true, - keyEncipherment: true, - dataEncipherment: true - }, { + keyCertSign: true, + critical: true + }, + { name: 'extKeyUsage', - serverAuth: true - }, { + serverAuth: true, + critical: true + }, + { name: 'friendlyName', - value: friendlyName - }]); + value: FRIENDLY_NAME + } + ]); // self-sign certificate certificate.sign(keys.privateKey, forge.md.sha256.create()); - // convert a Forge certificate to PEM - const pem: string = forge.pki.certificateToPem(certificate); - const pemKey: string = forge.pki.privateKeyToPem(keys.privateKey); - return { - pemCertificate: pem, - pemKey: pemKey + certificate, + privateKey: keys.privateKey }; } - private _ensureCertUtilExePath(terminal: Terminal): string | undefined { - if (!_certutilExePath) { - const where: child_process.SpawnSyncReturns = child_process.spawnSync( - 'where', - ['certutil'] - ); + private async _createDevelopmentCertificateAsync( + options: Required + ): Promise { + const forge: typeof import('node-forge') = await import('node-forge'); + const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048); + const certificate: pki.Certificate = forge.pki.createCertificate(); - const whereErr: string = where.stderr.toString(); - if (whereErr) { - terminal.writeErrorLine(`Error finding certUtil command: "${whereErr}"`); - _certutilExePath = undefined; - } else { - const lines: string[] = where.stdout.toString().trim().split(EOL); - _certutilExePath = lines[0].trim(); + certificate.publicKey = keys.publicKey; + certificate.serialNumber = TLS_SERIAL_NUMBER; + + const { subjectAltNames: subjectNames, subjectIPAddresses: subjectIpAddresses, validityInDays } = options; + + const { certificate: caCertificate, privateKey: caPrivateKey } = await this._createCACertificateAsync( + validityInDays, + forge + ); + + const notBefore: Date = new Date(); + const notAfter: Date = new Date(notBefore); + notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays); + certificate.validity.notBefore = notBefore; + certificate.validity.notAfter = notAfter; + + const subjectAttrs: pki.CertificateField[] = [ + { + name: 'commonName', + value: subjectNames[0] } - } + ]; + const issuerAttrs: pki.CertificateField[] = caCertificate.subject.attributes; + + certificate.setSubject(subjectAttrs); + certificate.setIssuer(issuerAttrs); + + const subjectAltNames: IAltName[] = [ + ...subjectNames.map((subjectName) => ({ + type: 2, // DNS + value: subjectName + })), + ...subjectIpAddresses.map((ip) => ({ + type: 7, // IP + ip + })) + ]; + + const issuerAltNames: readonly IAltName[] = [ + { + type: 2, // DNS + value: CA_ALT_NAME + } + ]; + + certificate.setExtensions([ + { + name: 'basicConstraints', + cA: false, + critical: true + }, + { + name: 'subjectAltName', + altNames: subjectAltNames, + critical: true + }, + { + name: 'issuerAltName', + altNames: issuerAltNames, + critical: false + }, + { + name: 'keyUsage', + digitalSignature: true, + keyEncipherment: true, + dataEncipherment: true, + critical: true + }, + { + name: 'extKeyUsage', + serverAuth: true, + critical: true + }, + { + name: 'friendlyName', + value: FRIENDLY_NAME + } + ]); + + // Sign certificate with CA + certificate.sign(caPrivateKey, forge.md.sha256.create()); + + // convert a Forge certificate to PEM + const caPem: string = forge.pki.certificateToPem(caCertificate); + const pem: string = forge.pki.certificateToPem(certificate); + const pemKey: string = forge.pki.privateKeyToPem(keys.privateKey); - return _certutilExePath; + return { + pemCaCertificate: caPem, + pemCertificate: pem, + pemKey: pemKey, + subjectAltNames: options.subjectAltNames + }; } - private _tryTrustCertificate(certificatePath: string, terminal: Terminal): boolean { + private async _tryTrustCertificateAsync(certificatePath: string, terminal: ITerminal): Promise { switch (process.platform) { case 'win32': - const certutilExePath: string | undefined = this._ensureCertUtilExePath(terminal); - if (!certutilExePath) { - // Unable to find the cert utility - return false; - } - terminal.writeLine( - 'Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' + - 'and will be stored in your local user profile to be used by other instances of ' + - 'debug-certificate-manager. If you do not consent to trust this certificate, click "NO" in the dialog.' + 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' + + 'and will be stored in your local user profile to be used by other instances of ' + + 'debug-certificate-manager. If you do not consent to trust this certificate, click "NO" in the dialog.' ); - const winTrustResult: child_process.SpawnSyncReturns = - child_process.spawnSync(certutilExePath, ['-user', '-addstore', 'root', certificatePath]); + const winTrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [ + '-user', + '-addstore', + 'root', + certificatePath + ]); - if (winTrustResult.status !== 0) { + if (winTrustResult.exitCode !== 0) { terminal.writeErrorLine(`Error: ${winTrustResult.stdout.toString()}`); - const errorLines: string[] = winTrustResult.stdout.toString().split(EOL).map( - (line: string) => line.trim() - ); + const errorLines: string[] = winTrustResult.stdout + .toString() + .split(EOL) + .map((line: string) => line.trim()); // Not sure if this is always the status code for "cancelled" - should confirm. - if (winTrustResult.status === 2147943623 || - errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0) { + if ( + winTrustResult.exitCode === 2147943623 || + errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0 + ) { terminal.writeLine('Certificate trust cancelled.'); } else { terminal.writeErrorLine('Certificate trust failed with an unknown error.'); @@ -285,35 +533,37 @@ export class CertificateManager { case 'darwin': terminal.writeLine( - 'Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' + - 'and will be stored in your local user profile to be used by other instances of ' + - 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' + - 'root password in the prompt.' + 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' + + 'and will be stored in your local user profile to be used by other instances of ' + + 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' + + 'root password in the prompt.' ); - const commands: string[] = [ - 'security', + const result: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ 'add-trusted-cert', '-d', '-r', 'trustRoot', '-k', - macKeychain, + MAC_KEYCHAIN, certificatePath - ]; - const result: ISudoSyncResult = runSudoSync(commands); + ]); - if (result.code === 0) { + if (result.exitCode === 0) { terminal.writeVerboseLine('Successfully trusted development certificate.'); return true; } else { - if (result.stderr.some((value: string) => !!value.match(/The authorization was cancelled by the user\./))) { + if ( + result.stderr.some( + (value: string) => !!value.match(/The authorization was cancelled by the user\./) + ) + ) { terminal.writeLine('Certificate trust cancelled.'); return false; } else { terminal.writeErrorLine( - `Certificate trust failed with an unknown error. Exit code: ${result.code}. ` + - `Error: ${result.stderr.join(' ')}` + `Certificate trust failed with an unknown error. Exit code: ${result.exitCode}. ` + + `Error: ${result.stderr.join(' ')}` ); return false; } @@ -323,21 +573,87 @@ export class CertificateManager { // Linux + others: Have the user manually trust the cert if they want to terminal.writeLine( 'Automatic certificate trust is only implemented for debug-certificate-manager on Windows ' + - 'and macOS. To trust the development certificate, add this certificate to your trusted root ' + - `certification authorities: "${certificatePath}".` + 'and macOS. To trust the development certificate, add this certificate to your trusted root ' + + `certification authorities: "${certificatePath}".` ); return true; } } - private _trySetFriendlyName(certificatePath: string, terminal: Terminal): boolean { - if (process.platform === 'win32') { - const certutilExePath: string | undefined = this._ensureCertUtilExePath(terminal); - if (!certutilExePath) { - // Unable to find the cert utility - return false; - } + private async _detectIfCertificateIsTrustedAsync(terminal: ITerminal): Promise { + switch (process.platform) { + case 'win32': + const winVerifyStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [ + '-user', + '-verifystore', + 'root', + CA_SERIAL_NUMBER + ]); + + if (winVerifyStoreResult.exitCode !== 0) { + terminal.writeVerboseLine( + 'The development certificate was not found in the store. CertUtil error: ', + winVerifyStoreResult.stderr.join(' ') + ); + return false; + } else { + terminal.writeVerboseLine( + 'The development certificate was found in the store. CertUtil output: ', + winVerifyStoreResult.stdout.join(' ') + ); + return true; + } + + case 'darwin': + terminal.writeVerboseLine('Trying to find the signature of the development certificate.'); + + const macFindCertificateResult: IRunResult = await runAsync('security', [ + 'find-certificate', + '-c', + CA_ALT_NAME, + '-a', + '-Z', + MAC_KEYCHAIN + ]); + + if (macFindCertificateResult.exitCode !== 0) { + terminal.writeVerboseLine( + 'The development certificate was not found in keychain. Find certificate error: ', + macFindCertificateResult.stderr.join(' ') + ); + return false; + } + const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash( + macFindCertificateResult.stdout.join(EOL) + ); + + if (!shaHash) { + terminal.writeVerboseLine( + 'The development certificate was not found in keychain. Find certificate output:\n', + macFindCertificateResult.stdout.join(' ') + ); + return false; + } + + terminal.writeVerboseLine(`The development certificate was found in keychain.`); + return true; + + default: + // Linux + others: Have the user manually verify the cert is trusted + 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}". ` + + `The certificate has serial number "${CA_SERIAL_NUMBER}".` + ); + // Always return true on Linux to prevent breaking flow. + return true; + } + } + + private async _trySetFriendlyNameAsync(certificatePath: string, terminal: ITerminal): Promise { + if (process.platform === 'win32') { const basePath: string = path.dirname(certificatePath); const fileName: string = path.basename(certificatePath, path.extname(certificatePath)); const friendlyNamePath: string = path.join(basePath, `${fileName}.inf`); @@ -346,29 +662,26 @@ export class CertificateManager { '[Version]', 'Signature = "$Windows NT$"', '[Properties]', - `11 = "{text}${friendlyName}"`, + `11 = "{text}${FRIENDLY_NAME}"`, '' ].join(EOL); - FileSystem.writeFile(friendlyNamePath, friendlyNameFile); + await FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile); - const commands: string[] = [ - '–repairstore', - '–user', + const repairStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [ + '-repairstore', + '-user', 'root', - serialNumber, + CA_SERIAL_NUMBER, friendlyNamePath - ]; - const repairStoreResult: child_process.SpawnSyncReturns = - child_process.spawnSync(certutilExePath, commands); - - if (repairStoreResult.status !== 0) { - terminal.writeErrorLine(`CertUtil Error: ${repairStoreResult.stdout.toString()}`); + ]); + if (repairStoreResult.exitCode !== 0) { + terminal.writeVerboseLine(`CertUtil Error: ${repairStoreResult.stderr.join('')}`); + terminal.writeVerboseLine(`CertUtil: ${repairStoreResult.stdout.join('')}`); return false; } else { terminal.writeVerboseLine('Successfully set certificate name.'); - return true; } } else { @@ -377,47 +690,203 @@ export class CertificateManager { } } - private _ensureCertificateInternal(terminal: Terminal): void { - const certificateStore: CertificateStore = this._certificateStore; - const generatedCertificate: ICertificate = this._createDevelopmentCertificate(); + private async _ensureCertificateInternalAsync( + options: Required, + terminal: ITerminal + ): Promise { + const certificateStore: CertificateStore = this.certificateStore; + const generatedCertificate: ICertificate = await this._createDevelopmentCertificateAsync(options); - const now: Date = new Date(); - const certificateName: string = now.getTime().toString(); - const tempDirName: string = path.join(__dirname, '..', 'temp'); + const certificateName: string = Date.now().toString(); + const tempDirName: string = randomTmpPath('rushstack', 'temp'); + await FileSystem.ensureFolderAsync(tempDirName); const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`); - const pemFileContents: string | undefined = generatedCertificate.pemCertificate; + const pemFileContents: string | undefined = generatedCertificate.pemCaCertificate; if (pemFileContents) { - FileSystem.writeFile(tempCertificatePath, pemFileContents, { + await FileSystem.writeFileAsync(tempCertificatePath, pemFileContents, { ensureFolderExists: true }); } - if (this._tryTrustCertificate(tempCertificatePath, terminal)) { + const trustCertificateResult: boolean = options.skipCertificateTrust + ? true + : await this._tryTrustCertificateAsync(tempCertificatePath, terminal); + + let subjectAltNames: readonly string[] | undefined; + if (trustCertificateResult) { + certificateStore.caCertificateData = generatedCertificate.pemCaCertificate; certificateStore.certificateData = generatedCertificate.pemCertificate; certificateStore.keyData = generatedCertificate.pemKey; + subjectAltNames = generatedCertificate.subjectAltNames; // Try to set the friendly name, and warn if we can't - if (!this._trySetFriendlyName(tempCertificatePath, terminal)) { - terminal.writeWarningLine('Unable to set the certificate\'s friendly name.'); + if (!(await this._trySetFriendlyNameAsync(tempCertificatePath, terminal))) { + terminal.writeWarningLine("Unable to set the certificate's friendly name."); } } else { // Clear out the existing store data, if any exists + certificateStore.caCertificateData = undefined; certificateStore.certificateData = undefined; certificateStore.keyData = undefined; } - FileSystem.deleteFile(tempCertificatePath); + await FileSystem.deleteFileAsync(tempCertificatePath); + + return { + pemCaCertificate: certificateStore.caCertificateData, + pemCertificate: certificateStore.certificateData, + pemKey: certificateStore.keyData, + subjectAltNames + }; } - private _certificateHasSubjectAltName(): boolean { - const certificateData: string | undefined = this._certificateStore.certificateData; - if (!certificateData) { - return false; + /** + * 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 certificate: forge.pki.Certificate = forge.pki.certificateFromPem(certificateData); - return !!certificate.getExtension('subjectAltName'); + + 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)) { + // Sets `shaHash` to the current certificate SHA-1 as we progress through the lines of certificate text. + const shaHashMatch: string[] | null = line.match(/^SHA-1 hash: (.+)$/); + if (shaHashMatch) { + shaHash = shaHashMatch[1]; + } -} \ No newline at end of file + const snbrMatch: string[] | null = line.match(/^\s*"snbr"=0x([^\s]+).+$/); + if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === CA_SERIAL_NUMBER) { + return shaHash; + } + } + } +} + +function applyDefaultOptions( + options: ICertificateGenerationOptions | undefined +): Required { + const subjectNames: ReadonlyArray | undefined = options?.subjectAltNames; + const subjectIpAddresses: ReadonlyArray | undefined = options?.subjectIPAddresses; + const skipCertificateTrust: boolean | undefined = options?.skipCertificateTrust || false; + return { + subjectAltNames: subjectNames?.length ? subjectNames : DEFAULT_CERTIFICATE_SUBJECT_NAMES, + subjectIPAddresses: subjectIpAddresses?.length + ? subjectIpAddresses + : DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES, + validityInDays: Math.min( + MAX_CERTIFICATE_VALIDITY_DAYS, + options?.validityInDays ?? MAX_CERTIFICATE_VALIDITY_DAYS + ), + skipCertificateTrust: skipCertificateTrust + }; +} + +function isIPAddress(altName: IAltName): altName is IIPAddressAltName { + return altName.type === 7; +} diff --git a/libraries/debug-certificate-manager/src/CertificateStore.ts b/libraries/debug-certificate-manager/src/CertificateStore.ts index 6133a4087be..4f3ff73d1fa 100644 --- a/libraries/debug-certificate-manager/src/CertificateStore.ts +++ b/libraries/debug-certificate-manager/src/CertificateStore.ts @@ -1,54 +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 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 */ export class CertificateStore { - private _userProfilePath: string; - private _serveDataPath: string; - private _certificatePath: string; - private _keyPath: string; + 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(); - this._userProfilePath = path.resolve(unresolvedUserFolder); - if (!FileSystem.exists(this._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; + } + + 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._serveDataPath = path.join(this._userProfilePath, '.rushstack'); - FileSystem.ensureFolder(this._serveDataPath); + /** + * Path to the directory where the debug certificates are stored. + */ + public get storePath(): string { + return this._storePath; + } - this._certificatePath = path.join(this._serveDataPath, 'rushstack-serve.pem'); - this._keyPath = path.join(this._serveDataPath, 'rushstack-serve.key'); + /** + * Path to the saved debug CA certificate + */ + public get caCertificatePath(): string { + return this._caCertificatePath; } /** - * Path to the saved debug certificate + * Path to the saved debug TLS certificate */ public get certificatePath(): string { return this._certificatePath; } /** - * Debug certificate pem file contents. + * Path to the saved debug TLS key + */ + public get keyPath(): string { + return this._keyPath; + } + + /** + * Debug Certificate Authority certificate pem file contents. + */ + public get caCertificateData(): string | undefined { + if (!this._caCertificateData) { + try { + this._caCertificateData = FileSystem.readFile(this._caCertificatePath); + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + throw err; + } + } + } + + return this._caCertificateData; + } + + public set caCertificateData(certificate: string | undefined) { + if (certificate) { + FileSystem.writeFile(this._caCertificatePath, certificate); + } else if (FileSystem.exists(this._caCertificatePath)) { + FileSystem.deleteFile(this._caCertificatePath); + } + + this._caCertificateData = certificate; + } + + /** + * Debug TLS Server certificate pem file contents. */ public get certificateData(): string | undefined { if (!this._certificateData) { - if (FileSystem.exists(this._certificatePath)) { + try { this._certificateData = FileSystem.readFile(this._certificatePath); - } else { - return undefined; + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + throw err; + } } } @@ -70,10 +206,12 @@ export class CertificateStore { */ public get keyData(): string | undefined { if (!this._keyData) { - if (FileSystem.exists(this._keyPath)) { + try { this._keyData = FileSystem.readFile(this._keyPath); - } else { - return undefined; + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + throw err; + } } } diff --git a/libraries/debug-certificate-manager/src/index.ts b/libraries/debug-certificate-manager/src/index.ts index 0d695fd51ef..02562f4baea 100644 --- a/libraries/debug-certificate-manager/src/index.ts +++ b/libraries/debug-certificate-manager/src/index.ts @@ -3,21 +3,26 @@ /** * This package is used to manage debug certificates for development servers. - * It is used by - * [\@microsoft/gulp-core-build-serve](https://www.npmjs.com/package/\@microsoft/gulp-core-build-serve) - * to generate and trust a certificate when HTTPS is turned on. * * This package provides the following utilities: + * * - `CertificateStore` to handle retrieving and saving a debug certificate. + * * - `CertificateManager` is a utility class containing the following public methods: - * | - `ensureCertificate` will find or optionally create a debug certificate and trust it. - * | - `untrustCertificate` will untrust a debug certificate. + * + * - `ensureCertificate` will find or optionally create a debug certificate and trust it. + * + * - `untrustCertificate` will untrust a debug certificate. * * @packageDocumentation */ export { - ICertificate, - CertificateManager + type ICertificate, + CertificateManager, + type ICertificateGenerationOptions, + type ICertificateManagerOptions, + type ICertificateValidationResult, + DEFAULT_CERTIFICATE_SUBJECT_NAMES } from './CertificateManager'; -export { CertificateStore } from './CertificateStore'; \ No newline at end of file +export { CertificateStore, type ICertificateStoreOptions } from './CertificateStore'; diff --git a/libraries/debug-certificate-manager/src/runCommand.ts b/libraries/debug-certificate-manager/src/runCommand.ts new file mode 100644 index 00000000000..e2febdb653a --- /dev/null +++ b/libraries/debug-certificate-manager/src/runCommand.ts @@ -0,0 +1,117 @@ +// 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 '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[]; + stderr: string[]; + /** + * The exit code, or -1 if the child process was terminated by a signal + */ + exitCode: number; +} + +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 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 { + const result: child_process.ChildProcess = Executable.spawn(command, params); + return await _handleChildProcess(result); +} + +async function _handleChildProcess(childProcess: child_process.ChildProcess): Promise { + return await new Promise((resolve: (result: IRunResult) => void) => { + const stderr: string[] = []; + childProcess.stderr?.on('data', (data: Buffer) => { + stderr.push(data.toString()); + }); + + const stdout: string[] = []; + childProcess.stdout?.on('data', (data: Buffer) => { + stdout.push(data.toString()); + }); + + childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { + const normalizedExitCode: number = typeof exitCode === 'number' ? exitCode : signal ? -1 : 0; + resolve({ exitCode: normalizedExitCode, stdout, stderr }); + }); + }); +} diff --git a/libraries/debug-certificate-manager/src/sudoSync.ts b/libraries/debug-certificate-manager/src/sudoSync.ts deleted file mode 100644 index 68c13ce444b..00000000000 --- a/libraries/debug-certificate-manager/src/sudoSync.ts +++ /dev/null @@ -1,48 +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 child_process from 'child_process'; -// eslint-disable-next-line -const sudo: (args: string[], options: any) => child_process.ChildProcess = require('sudo'); -// eslint-disable-next-line -const deasync: { sleep: (ms: number) => void } = require('deasync'); - -export interface ISudoSyncResult { - stdout: string[]; - stderr: string[]; - code: number; -} - -export function runSudoSync(params: string[]): ISudoSyncResult { - const sudoResult: child_process.ChildProcess = sudo( - params, - { - cachePassword: false, - prompt: 'Enter your password: ' - } - ); - - const stderr: string[] = []; - sudoResult.stderr.on('data', (data: Buffer) => { - stderr.push(data.toString()); - }); - - const stdout: string[] = []; - sudoResult.stdout.on('data', (data: Buffer) => { - stdout.push(data.toString()); - }); - - let code: number | undefined; - sudoResult.on('close', (exitCode: number) => { - code = exitCode; - }); - - // Because we're running with sudo, we can't run synchronously, so synchronize by polling. - - // eslint-disable-next-line no-unmodified-loop-condition - while (code === undefined) { - deasync.sleep(100); - } - - return { code, stdout, stderr }; -} \ No newline at end of file diff --git a/libraries/debug-certificate-manager/src/test/index.test.ts b/libraries/debug-certificate-manager/src/test/index.test.ts deleted file mode 100644 index 8b88f37ddbe..00000000000 --- a/libraries/debug-certificate-manager/src/test/index.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CertificateStore } from '../index'; -import { CertificateManager } from '../CertificateManager'; - -test('Verify CertificateStore store is created.', () => { - const certificateStore: CertificateStore = new CertificateStore(); - expect(certificateStore).toHaveProperty('certificateData'); - expect(certificateStore).toHaveProperty('keyData'); -}); - -test('Verify CertificateManger provides ensure and untrust methods', () => { - const certificateManger: CertificateManager = new CertificateManager; - expect(certificateManger).toHaveProperty('ensureCertificate'); - expect(certificateManger).toHaveProperty('untrustCertificate'); -}); \ No newline at end of file diff --git a/libraries/debug-certificate-manager/tsconfig.json b/libraries/debug-certificate-manager/tsconfig.json index 824a88b71e5..dac21d04081 100644 --- a/libraries/debug-certificate-manager/tsconfig.json +++ b/libraries/debug-certificate-manager/tsconfig.json @@ -1,10 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/heft-config-file/.npmignore b/libraries/heft-config-file/.npmignore new file mode 100644 index 00000000000..ffb155d74e6 --- /dev/null +++ b/libraries/heft-config-file/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/includes/** diff --git a/libraries/heft-config-file/CHANGELOG.json b/libraries/heft-config-file/CHANGELOG.json new file mode 100644 index 00000000000..0a526296afe --- /dev/null +++ b/libraries/heft-config-file/CHANGELOG.json @@ -0,0 +1,2456 @@ +{ + "name": "@rushstack/heft-config-file", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + } + ] + } + }, + { + "version": "0.16.1", + "tag": "@rushstack/heft-config-file_v0.16.1", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `jsonpath-plus` to `~10.2.0`." + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/heft-config-file_v0.16.0", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new `NonProjectConfigurationFile` class that is designed to load absolute-pathed configuration files without rig support." + }, + { + "comment": "Rename `ConfigurationFile` to `ProjectConfigurationFile` and mark `ConfigurationFile` as `@deprecated`." + } + ] + } + }, + { + "version": "0.15.9", + "tag": "@rushstack/heft-config-file_v0.15.9", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + } + ] + } + }, + { + "version": "0.15.8", + "tag": "@rushstack/heft-config-file_v0.15.8", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "patch": [ + { + "comment": "Update the `jsonpath-plus` dependency to mitigate CVE-2024-21534.\"" + } + ] + } + }, + { + "version": "0.15.7", + "tag": "@rushstack/heft-config-file_v0.15.7", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/heft-config-file_v0.15.6", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + } + ] + } + }, + { + "version": "0.15.5", + "tag": "@rushstack/heft-config-file_v0.15.5", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/heft-config-file_v0.15.4", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/heft-config-file_v0.15.3", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/heft-config-file_v0.15.2", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/heft-config-file_v0.15.1", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/heft-config-file_v0.15.0", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "minor": [ + { + "comment": "Add `ConfigurationFile.loadConfigurationFileForProject` and `ConfigurationFile.tryLoadConfigurationFileForProject` APIs to allow for synchronously loading Heft configuration files" + } + ] + } + }, + { + "version": "0.14.25", + "tag": "@rushstack/heft-config-file_v0.14.25", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.14.24", + "tag": "@rushstack/heft-config-file_v0.14.24", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.14.23", + "tag": "@rushstack/heft-config-file_v0.14.23", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + } + ] + } + }, + { + "version": "0.14.22", + "tag": "@rushstack/heft-config-file_v0.14.22", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + } + ] + } + }, + { + "version": "0.14.21", + "tag": "@rushstack/heft-config-file_v0.14.21", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.14.20", + "tag": "@rushstack/heft-config-file_v0.14.20", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.14.19", + "tag": "@rushstack/heft-config-file_v0.14.19", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.14.18", + "tag": "@rushstack/heft-config-file_v0.14.18", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + } + ] + } + }, + { + "version": "0.14.17", + "tag": "@rushstack/heft-config-file_v0.14.17", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + } + ] + } + }, + { + "version": "0.14.16", + "tag": "@rushstack/heft-config-file_v0.14.16", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + } + ] + } + }, + { + "version": "0.14.15", + "tag": "@rushstack/heft-config-file_v0.14.15", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.14.14", + "tag": "@rushstack/heft-config-file_v0.14.14", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/heft-config-file_v0.14.13", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/heft-config-file_v0.14.12", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/heft-config-file_v0.14.11", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/heft-config-file_v0.14.10", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.2`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/heft-config-file_v0.14.9", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/heft-config-file_v0.14.8", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/heft-config-file_v0.14.7", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/heft-config-file_v0.14.6", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/heft-config-file_v0.14.5", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/heft-config-file_v0.14.4", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/heft-config-file_v0.14.3", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/heft-config-file_v0.14.2", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/heft-config-file_v0.14.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/heft-config-file_v0.14.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/heft-config-file_v0.13.3", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/heft-config-file_v0.13.2", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/heft-config-file_v0.13.1", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/heft-config-file_v0.13.0", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "minor": [ + { + "comment": " Use the `IRigConfig` interface insteacd of the `RigConfig` class in the API." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/heft-config-file_v0.12.5", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/heft-config-file_v0.12.4", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/heft-config-file_v0.12.3", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/heft-config-file_v0.12.2", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/heft-config-file_v0.12.1", + "date": "Fri, 12 May 2023 00:23:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/heft-config-file_v0.12.0", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "minor": [ + { + "comment": "BREAKING CHANGE: The custom resolver method now accepts an options parameter. This parameter includes all previously provided information and now includes the partially-resolved configuration file." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/heft-config-file_v0.11.11", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/heft-config-file_v0.11.10", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/heft-config-file_v0.11.9", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/heft-config-file_v0.11.8", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/heft-config-file_v0.11.7", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/heft-config-file_v0.11.6", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/heft-config-file_v0.11.5", + "date": "Thu, 26 Jan 2023 02:55:09 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/heft-config-file_v0.11.4", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/heft-config-file_v0.11.3", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/heft-config-file_v0.11.2", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft-config-file_v0.11.1", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft-config-file_v0.11.0", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "minor": [ + { + "comment": "Allow a schema object to be passed to the ConfigurationFile constructor instead of the path to a schema file." + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-config-file_v0.10.0", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add a \"propertyInheritanceDefaults\" option that allows the default property inheritance type to be configured." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/heft-config-file_v0.9.6", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/heft-config-file_v0.9.5", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/heft-config-file_v0.9.4", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-config-file_v0.9.3", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-config-file_v0.9.2", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-config-file_v0.9.1", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-config-file_v0.9.0", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING API CHANGE) Deprecate `PathResolutionMethod.NodeResolve` in favor of `PathResolutionMethod.nodeResolve`." + } + ], + "patch": [ + { + "comment": "Improve types strictness of `IJsonPathsMetadata`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/heft-config-file_v0.8.10", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/heft-config-file_v0.8.9", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/heft-config-file_v0.8.8", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/heft-config-file_v0.8.7", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/heft-config-file_v0.8.6", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/heft-config-file_v0.8.5", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/heft-config-file_v0.8.4", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/heft-config-file_v0.8.3", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/heft-config-file_v0.8.2", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-config-file_v0.8.1", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-config-file_v0.8.0", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for an inline \"$.inheritanceType\" property. This feature allows for configuration files to specify how object and array properties are inherited, overriding the default inheritance behavior provided by the configuration file class." + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/heft-config-file_v0.7.12", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/heft-config-file_v0.7.11", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/heft-config-file_v0.7.10", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/heft-config-file_v0.7.9", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/heft-config-file_v0.7.8", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-config-file_v0.7.7", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-config-file_v0.7.6", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/heft-config-file_v0.7.5", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-config-file_v0.7.4", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-config-file_v0.7.3", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-config-file_v0.7.2", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-config-file_v0.7.1", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-config-file_v0.7.0", + "date": "Tue, 05 Oct 2021 15:08:37 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/heft-config-file_v0.6.8", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/heft-config-file_v0.6.7", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/heft-config-file_v0.6.6", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/heft-config-file_v0.6.5", + "date": "Mon, 13 Sep 2021 15:07:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft-config-file_v0.6.4", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix issue with overwriting configuration properties using falsey values" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-config-file_v0.6.3", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-config-file_v0.6.2", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "patch": [ + { + "comment": "Move detailed logging from verbose to debug severity." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-config-file_v0.6.1", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-config-file_v0.6.0", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "minor": [ + { + "comment": "Allow for specifying a custom resolver when resolving paths with heft-config-file. This change removes \"preresolve\" property for JsonPath module resolution options and replaces it with a more flexible \"customResolver\" property" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-config-file_v0.5.0", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"preresolve\" property to transform paths before resolution" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-config-file_v0.4.2", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-config-file_v0.4.1", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "patch": [ + { + "comment": "Reduce the number of extra file system calls made when loading many config files." + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-config-file_v0.4.0", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "minor": [ + { + "comment": "Expose the ConfigurationFile.projectRelativeFilePath property" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-config-file_v0.3.22", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-config-file_v0.3.21", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-config-file_v0.3.20", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-config-file_v0.3.19", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "patch": [ + { + "comment": "Remove an outdated note from the README." + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-config-file_v0.3.18", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-config-file_v0.3.17", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.10`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-config-file_v0.3.16", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-config-file_v0.3.15", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-config-file_v0.3.14", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where .map files were not being published" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-config-file_v0.3.13", + "date": "Wed, 11 Nov 2020 01:08:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-config-file_v0.3.12", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-config-file_v0.3.11", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an error would be thrown if a value was omitted in a parent configuration file." + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-config-file_v0.3.10", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-config-file_v0.3.9", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-config-file_v0.3.8", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-config-file_v0.3.7", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-config-file_v0.3.6", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-config-file_v0.3.5", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-config-file_v0.3.4", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-config-file_v0.3.3", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-config-file_v0.3.2", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-config-file_v0.3.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-config-file_v0.3.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove \"propertyInheritanceTypes\" option in favor of a more flexible \"propertyInheritance\" that allows for custom inheritance." + }, + { + "comment": "(BREAKING CHANGE) Change the ConfigurationFile API to take the project-relative configuration file in the constructor. Now the configuration file loading function takes the project root instead of the configuration file path." + }, + { + "comment": "Add an API to \"try\" to load a configuration file, and return undefined if it doesn't exist instead of throwing an exception." + }, + { + "comment": "Add support for config/rig.json." + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.9\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-config-file_v0.2.7", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-config-file_v0.2.6", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-config-file_v0.2.5", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-config-file_v0.2.4", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-config-file_v0.2.3", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-config-file_v0.2.2", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-config-file_v0.2.1", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "patch": [ + { + "comment": "Allow \"extends\" fields to refer to modules in addition to relative paths." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.15`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-config-file_v0.2.0", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Change the API to require the JSON schema path to be passed via the ConfigurationFile constructor options object." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.14`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-config-file_v0.1.3", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.13`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-config-file_v0.1.2", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.12`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-config-file_v0.1.1", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.11`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-config-file_v0.1.0", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "minor": [ + { + "comment": "Initial project creation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.7\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + } + ] +} diff --git a/libraries/heft-config-file/CHANGELOG.md b/libraries/heft-config-file/CHANGELOG.md new file mode 100644 index 00000000000..2db1a0f5745 --- /dev/null +++ b/libraries/heft-config-file/CHANGELOG.md @@ -0,0 +1,902 @@ +# Change Log - @rushstack/heft-config-file + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.16.1 +Mon, 09 Dec 2024 20:31:43 GMT + +### Patches + +- Bump `jsonpath-plus` to `~10.2.0`. + +## 0.16.0 +Tue, 03 Dec 2024 16:11:07 GMT + +### Minor changes + +- Add a new `NonProjectConfigurationFile` class that is designed to load absolute-pathed configuration files without rig support. +- Rename `ConfigurationFile` to `ProjectConfigurationFile` and mark `ConfigurationFile` as `@deprecated`. + +## 0.15.9 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.15.8 +Thu, 24 Oct 2024 00:15:47 GMT + +### Patches + +- Update the `jsonpath-plus` dependency to mitigate CVE-2024-21534." + +## 0.15.7 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.15.6 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.15.5 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.15.4 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.15.3 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.15.2 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.15.1 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.15.0 +Thu, 27 Jun 2024 21:01:36 GMT + +### Minor changes + +- Add `ConfigurationFile.loadConfigurationFileForProject` and `ConfigurationFile.tryLoadConfigurationFileForProject` APIs to allow for synchronously loading Heft configuration files + +## 0.14.25 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 0.14.24 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.14.23 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.14.22 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.14.21 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.14.20 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.14.19 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.14.18 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.14.17 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.14.16 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.14.15 +Wed, 10 Apr 2024 15:10:08 GMT + +_Version update only_ + +## 0.14.14 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.14.13 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.14.12 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.14.11 +Mon, 19 Feb 2024 21:54:26 GMT + +_Version update only_ + +## 0.14.10 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.14.9 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.14.8 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.14.7 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.14.6 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.14.5 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.14.4 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.14.3 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.14.2 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.14.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.14.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.13.3 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.13.2 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.13.1 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.13.0 +Mon, 19 Jun 2023 22:40:21 GMT + +### Minor changes + +- Use the `IRigConfig` interface insteacd of the `RigConfig` class in the API. + +## 0.12.5 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 0.12.4 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 0.12.3 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.12.2 +Mon, 22 May 2023 06:34:32 GMT + +_Version update only_ + +## 0.12.1 +Fri, 12 May 2023 00:23:06 GMT + +_Version update only_ + +## 0.12.0 +Mon, 01 May 2023 15:23:19 GMT + +### Minor changes + +- BREAKING CHANGE: The custom resolver method now accepts an options parameter. This parameter includes all previously provided information and now includes the partially-resolved configuration file. + +## 0.11.11 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.11.10 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.11.9 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.11.8 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.11.7 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.11.6 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 0.11.5 +Thu, 26 Jan 2023 02:55:09 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.11.4 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.11.3 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.11.2 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.11.1 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.11.0 +Tue, 27 Sep 2022 22:17:20 GMT + +### Minor changes + +- Allow a schema object to be passed to the ConfigurationFile constructor instead of the path to a schema file. + +## 0.10.0 +Wed, 21 Sep 2022 20:21:10 GMT + +### Minor changes + +- Add a "propertyInheritanceDefaults" option that allows the default property inheritance type to be configured. + +## 0.9.6 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.9.5 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.9.4 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.9.3 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.9.2 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.9.1 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.9.0 +Wed, 13 Jul 2022 21:31:13 GMT + +### Minor changes + +- (BREAKING API CHANGE) Deprecate `PathResolutionMethod.NodeResolve` in favor of `PathResolutionMethod.nodeResolve`. + +### Patches + +- Improve types strictness of `IJsonPathsMetadata` + +## 0.8.10 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 0.8.9 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.8.8 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.8.7 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.8.6 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.8.5 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.8.4 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.8.3 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.8.2 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.8.1 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.8.0 +Sat, 19 Mar 2022 08:05:37 GMT + +### Minor changes + +- Add support for an inline "$.inheritanceType" property. This feature allows for configuration files to specify how object and array properties are inherited, overriding the default inheritance behavior provided by the configuration file class. + +## 0.7.12 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.7.11 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.7.10 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.7.9 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.7.8 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.7.7 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.7.6 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.7.5 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.7.4 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.7.3 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.7.2 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.7.1 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.7.0 +Tue, 05 Oct 2021 15:08:37 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 0.6.8 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.6.7 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.6.6 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.6.5 +Mon, 13 Sep 2021 15:07:06 GMT + +_Version update only_ + +## 0.6.4 +Wed, 08 Sep 2021 19:06:22 GMT + +### Patches + +- Fix issue with overwriting configuration properties using falsey values + +## 0.6.3 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.6.2 +Wed, 11 Aug 2021 00:07:21 GMT + +### Patches + +- Move detailed logging from verbose to debug severity. + +## 0.6.1 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.6.0 +Wed, 30 Jun 2021 01:37:17 GMT + +### Minor changes + +- Allow for specifying a custom resolver when resolving paths with heft-config-file. This change removes "preresolve" property for JsonPath module resolution options and replaces it with a more flexible "customResolver" property + +## 0.5.0 +Fri, 11 Jun 2021 00:34:02 GMT + +### Minor changes + +- Add "preresolve" property to transform paths before resolution + +## 0.4.2 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.4.1 +Fri, 04 Jun 2021 00:08:34 GMT + +### Patches + +- Reduce the number of extra file system calls made when loading many config files. + +## 0.4.0 +Sat, 29 May 2021 01:05:06 GMT + +### Minor changes + +- Expose the ConfigurationFile.projectRelativeFilePath property + +## 0.3.22 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.3.21 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 0.3.20 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.3.19 +Thu, 08 Apr 2021 20:41:54 GMT + +### Patches + +- Remove an outdated note from the README. + +## 0.3.18 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.3.17 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.3.16 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.3.15 +Thu, 10 Dec 2020 23:25:49 GMT + +_Version update only_ + +## 0.3.14 +Tue, 17 Nov 2020 01:17:38 GMT + +### Patches + +- Fix an issue where .map files were not being published + +## 0.3.13 +Wed, 11 Nov 2020 01:08:59 GMT + +_Version update only_ + +## 0.3.12 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 0.3.11 +Fri, 06 Nov 2020 16:09:30 GMT + +### Patches + +- Fix an issue where an error would be thrown if a value was omitted in a parent configuration file. + +## 0.3.10 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.3.9 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.3.8 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.3.7 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 0.3.6 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.3.5 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.3.4 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.3.3 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 0.3.2 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.3.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 0.3.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove "propertyInheritanceTypes" option in favor of a more flexible "propertyInheritance" that allows for custom inheritance. +- (BREAKING CHANGE) Change the ConfigurationFile API to take the project-relative configuration file in the constructor. Now the configuration file loading function takes the project root instead of the configuration file path. +- Add an API to "try" to load a configuration file, and return undefined if it doesn't exist instead of throwing an exception. +- Add support for config/rig.json. +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 0.2.7 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.2.6 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.2.5 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.2.4 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.2.3 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.2.2 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.2.1 +Fri, 18 Sep 2020 21:49:53 GMT + +### Patches + +- Allow "extends" fields to refer to modules in addition to relative paths. + +## 0.2.0 +Sun, 13 Sep 2020 01:53:20 GMT + +### Minor changes + +- (BREAKING CHANGE) Change the API to require the JSON schema path to be passed via the ConfigurationFile constructor options object. + +## 0.1.3 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.1.2 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 0.1.1 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 0.1.0 +Thu, 27 Aug 2020 11:27:06 GMT + +### Minor changes + +- Initial project creation. + diff --git a/libraries/heft-config-file/LICENSE b/libraries/heft-config-file/LICENSE new file mode 100644 index 00000000000..7f0fa47d5c3 --- /dev/null +++ b/libraries/heft-config-file/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-config-file + +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/heft-config-file/README.md b/libraries/heft-config-file/README.md new file mode 100644 index 00000000000..a2f43d2d0ac --- /dev/null +++ b/libraries/heft-config-file/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-config-file + +A library for loading config files for use with the [Heft](https://rushstack.io/pages/heft/overview/) build system. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/heft-config-file/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/heft-config-file/) + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/heft-config-file/config/api-extractor.json b/libraries/heft-config-file/config/api-extractor.json new file mode 100644 index 00000000000..34fb7776c9d --- /dev/null +++ b/libraries/heft-config-file/config/api-extractor.json @@ -0,0 +1,17 @@ +{ + "$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, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/libraries/heft-config-file/config/jest.config.json b/libraries/heft-config-file/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/heft-config-file/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/heft-config-file/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/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 new file mode 100644 index 00000000000..295a685e2de --- /dev/null +++ b/libraries/heft-config-file/package.json @@ -0,0 +1,36 @@ +{ + "name": "@rushstack/heft-config-file", + "version": "0.19.5", + "description": "Configuration file loader for @rushstack/heft", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/heft-config-file" + }, + "engines": { + "node": ">=10.13.0" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "lib/index.js", + "types": "dist/heft-config-file.d.ts", + "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" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rig-package": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@ungap/structured-clone": "~1.3.0", + "jsonpath-plus": "~10.3.0" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@types/ungap__structured-clone": "~1.2.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/libraries/heft-config-file/src/ConfigurationFileBase.ts b/libraries/heft-config-file/src/ConfigurationFileBase.ts new file mode 100644 index 00000000000..a1524b566b6 --- /dev/null +++ b/libraries/heft-config-file/src/ConfigurationFileBase.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 * as nodeJsPath from 'node:path'; + +import { JSONPath } from 'jsonpath-plus'; +import structuredClone from '@ungap/structured-clone'; + +import { JsonSchema, JsonFile, Import, FileSystem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +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 + */ +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. + */ + 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. + */ + export type merge = typeof InheritanceType.merge; + + /** + * Discard elements from the parent file's property + */ + export type replace = typeof InheritanceType.replace; + + /** + * Custom inheritance functionality + */ + export type custom = typeof InheritanceType.custom; +} +export { InheritanceType }; + +/** + * @beta + * + * The set of possible resolution methods for fields that refer to paths. + */ +const PathResolutionMethod = { + /** + * Resolve a path relative to the configuration file + */ + resolvePathRelativeToConfigurationFile: 'resolvePathRelativeToConfigurationFile', + + /** + * Resolve a path relative to the root of the project containing the configuration file + */ + resolvePathRelativeToProjectRoot: 'resolvePathRelativeToProjectRoot', + + /** + * Treat the property as a NodeJS-style require/import reference and resolve using standard + * NodeJS filesystem resolution + * + * @deprecated + * Use {@link (PathResolutionMethod:variable).nodeResolve} instead + */ + NodeResolve: 'NodeResolve', + + /** + * Treat the property as a NodeJS-style require/import reference and resolve using standard + * NodeJS filesystem resolution + */ + nodeResolve: 'nodeResolve', + + /** + * Resolve the property using a custom resolver. + */ + 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< + 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}. + * + * @beta + */ +export interface IJsonPathMetadataResolverOptions { + /** + * The name of the property being resolved. + */ + propertyName: string; + /** + * The value of the path property being resolved. + */ + propertyValue: string; + /** + * The path to the configuration file the property was obtained from. + */ + configurationFilePath: string; + /** + * 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; +} + +/** + * Used to specify how node(s) in a JSON object should be processed after being loaded. + * + * @beta + */ +export interface ICustomJsonPathMetadata { + /** + * If `ICustomJsonPathMetadata.pathResolutionMethod` is set to `PathResolutionMethod.custom`, + * this property be used to resolve the path. + */ + customResolver?: (resolverOptions: IJsonPathMetadataResolverOptions) => string; + + /** + * If this property describes a filesystem path, use this property to describe + * how the path should be resolved. + */ + pathResolutionMethod?: PathResolutionMethod.custom; +} + +/** + * Used to specify how node(s) in a JSON object should be processed after being loaded. + * + * @beta + */ +export interface INonCustomJsonPathMetadata { + /** + * If this property describes a filesystem path, use this property to describe + * how the path should be resolved. + */ + pathResolutionMethod?: + | PathResolutionMethod.NodeResolve // TODO: Remove + | PathResolutionMethod.nodeResolve + | PathResolutionMethod.resolvePathRelativeToConfigurationFile + | PathResolutionMethod.resolvePathRelativeToProjectRoot; +} + +/** + * @beta + */ +export type PropertyInheritanceCustomFunction = ( + currentObject: TObject, + parentObject: TObject +) => TObject; + +/** + * @beta + */ +export interface IPropertyInheritance { + inheritanceType: TInheritanceType; +} + +/** + * @beta + */ +export interface ICustomPropertyInheritance extends IPropertyInheritance { + /** + * 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; +} + +/** + * @beta + */ +export type IPropertiesInheritance = { + [propertyName in keyof TConfigurationFile]?: + | IPropertyInheritance + | ICustomPropertyInheritance; +}; + +/** + * @beta + */ +export interface IPropertyInheritanceDefaults { + array?: IPropertyInheritance; + object?: IPropertyInheritance; +} + +/** + * @beta + */ +export type IJsonPathMetadata = ICustomJsonPathMetadata | INonCustomJsonPathMetadata; + +/** + * Keys in this object are JSONPaths {@link https://jsonpath.com/}, and values are objects + * that describe how node(s) selected by the JSONPath are processed after loading. + * + * @beta + */ +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 + */ +export interface IConfigurationFileOptionsBase { + /** + * Use this property to specify how JSON nodes are postprocessed. + */ + jsonPathMetadata?: IJsonPathsMetadata; + + /** + * Use this property to control how root-level properties are handled between parent and child + * configuration files. + */ + propertyInheritance?: IPropertiesInheritance; + + /** + * Use this property to control how specific property types are handled between parent and child + * 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; +} + +/** + * @beta + */ +export type IConfigurationFileOptionsWithJsonSchemaFilePath< + TConfigurationFile, + TExtraOptions extends {} +> = IConfigurationFileOptionsBase & + TExtraOptions & { + /** + * The path to the schema for the configuration file. + */ + jsonSchemaPath: string; + jsonSchemaObject?: never; + }; + +/** + * @beta + */ +export type IConfigurationFileOptionsWithJsonSchemaObject< + TConfigurationFile, + TExtraOptions extends {} +> = IConfigurationFileOptionsBase & + TExtraOptions & { + /** + * The schema for the configuration file. + */ + jsonSchemaObject: object; + jsonSchemaPath?: never; + }; + +/** + * @beta + */ +export type IConfigurationFileOptions = + | IConfigurationFileOptionsWithJsonSchemaFilePath + | IConfigurationFileOptionsWithJsonSchemaObject; + +interface IJsonPathCallbackObject { + path: string; + parent: object; + parentProperty: string; + value: string; +} + +/** + * @beta + */ +export interface IOriginalValueOptions { + parentObject: Partial; + 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: 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) { + this.__schema = this._getSchema(); + } + + return this.__schema; + } + + 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); + } else { + this._getSchema = () => JsonSchema.fromFile(options.jsonSchemaPath); + } + + this._jsonPathMetadata = Object.entries(options.jsonPathMetadata || {}); + this._propertyInheritanceTypes = options.propertyInheritance || {}; + this._defaultPropertyInheritance = options.propertyInheritanceDefaults || {}; + this._customValidationFunction = options.customValidationFunction; + } + + /** + * @internal + */ + public static _formatPathForLogging: (path: string) => string = (path: string) => path; + + /** + * Get the path to the source file that the referenced property was originally + * loaded from. + */ + public getObjectSourceFilePath(obj: TObject): string | undefined { + const { [CONFIGURATION_FILE_FIELD_ANNOTATION]: annotation }: IAnnotatedObject = obj; + return annotation?.configurationFilePath; + } + + /** + * Get the value of the specified property on the specified object that was originally + * loaded from a configuration file. + */ + public getPropertyOriginalValue( + options: IOriginalValueOptions + ): TValue | 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, + 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 + ); + throw new Error( + 'A loop has been detected in the "extends" properties of configuration file at ' + + `"${resolvedConfigurationFilePathForLogging}".` + ); + } + visitedConfigurationFilePaths.add(resolvedConfigurationFilePath); + + let cacheEntry: IConfigurationFileCacheEntry | undefined = this._configCache.get( + resolvedConfigurationFilePath + ); + if (!cacheEntry) { + cacheEntry = this._loadConfigurationFileEntry( + terminal, + resolvedConfigurationFilePath, + visitedConfigurationFilePaths, + onFileNotFound + ); + this._configCache.set(resolvedConfigurationFilePath, cacheEntry); + } + + return cacheEntry; + } + + private async _loadConfigurationFileEntryWithCacheAsync( + terminal: ITerminal, + resolvedConfigurationFilePath: string, + visitedConfigurationFilePaths: Set, + onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback + ): Promise> { + if (visitedConfigurationFilePaths.has(resolvedConfigurationFilePath)) { + const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( + resolvedConfigurationFilePath + ); + throw new Error( + 'A loop has been detected in the "extends" properties of configuration file at ' + + `"${resolvedConfigurationFilePathForLogging}".` + ); + } + visitedConfigurationFilePaths.add(resolvedConfigurationFilePath); + + let cacheEntryPromise: Promise> | undefined = + this._configPromiseCache.get(resolvedConfigurationFilePath); + if (!cacheEntryPromise) { + cacheEntryPromise = this._loadConfigurationFileEntryAsync( + terminal, + resolvedConfigurationFilePath, + visitedConfigurationFilePaths, + onConfigurationFileNotFound + ).then((value: IConfigurationFileCacheEntry) => { + this._configCache.set(resolvedConfigurationFilePath, value); + return value; + }); + this._configPromiseCache.set(resolvedConfigurationFilePath, cacheEntryPromise); + } + + return await cacheEntryPromise; + } + + /** + * 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, + resolvedConfigurationFilePathForLogging: string + ): IConfigurationJson & TConfigurationFile { + let configurationJson: IConfigurationJson & TConfigurationFile; + try { + configurationJson = JsonFile.parseString(fileText); + } catch (e) { + throw new Error(`In configuration file "${resolvedConfigurationFilePathForLogging}": ${e}`); + } + + 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. + // TODO: Replace this version of structuredClone with the built-in version once Node 16 support is dropped on the TikTok side + const result: IConfigurationJson & TConfigurationFile = structuredClone< + IConfigurationJson & TConfigurationFile + >(entry.configurationFile); + + const { resolvedConfigurationFilePath } = entry; + + this._annotateProperties(resolvedConfigurationFilePath, result); + + for (const [jsonPath, metadata] of this._jsonPathMetadata) { + JSONPath({ + path: jsonPath, + json: result, + callback: (payload: unknown, payloadType: string, fullPayload: IJsonPathCallbackObject) => { + const resolvedPath: string = this._resolvePathProperty( + { + propertyName: fullPayload.path, + propertyValue: fullPayload.value, + configurationFilePath: resolvedConfigurationFilePath, + configurationFile: result, + projectFolderPath + }, + metadata + ); + (fullPayload.parent as Record)[fullPayload.parentProperty] = resolvedPath; + }, + otherTypeCallback: () => { + throw new Error('@other() tags are not supported'); + } + }); + } + + return result; + } + + /** + * Resolves all path properties and merges parent properties. + * @param entry - The cache entry for the loaded configuration file + * @param projectFolderPath - The project folder path, if applicable + * @returns The flattened, unvalidated configuration file, with path properties resolved + */ + private _contextualizeAndFlattenConfigurationFile( + entry: IConfigurationFileCacheEntry, + 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 _loadConfigurationFileEntry( + terminal: ITerminal, + resolvedConfigurationFilePath: string, + visitedConfigurationFilePaths: Set, + fileNotFoundFallback?: IOnConfigurationFileNotFoundCallback + ): IConfigurationFileCacheEntry { + const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( + resolvedConfigurationFilePath + ); + + let fileText: string; + try { + fileText = FileSystem.readFile(resolvedConfigurationFilePath); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + const fallbackPath: string | undefined = fileNotFoundFallback?.( + resolvedConfigurationFilePathForLogging + ); + if (fallbackPath) { + try { + return this._loadConfigurationFileEntryWithCache( + terminal, + fallbackPath, + visitedConfigurationFilePaths + ); + } catch (fallbackError) { + if (!FileSystem.isNotExistError(fallbackError as Error)) { + throw fallbackError; + } + // Otherwise report the missing original file. + } + } + + terminal.writeDebugLine(`Configuration file "${resolvedConfigurationFilePathForLogging}" not found.`); + (e as Error).message = `File does not exist: ${resolvedConfigurationFilePathForLogging}`; + } + + throw e; + } + const configurationJson: IConfigurationJson & TConfigurationFile = this._parseConfigurationFile( + fileText, + resolvedConfigurationFilePathForLogging + ); + + let parentConfiguration: IConfigurationFileCacheEntry | undefined; + if (configurationJson.extends) { + try { + const resolvedParentConfigPath: string = Import.resolveModule({ + modulePath: configurationJson.extends, + baseFolderPath: nodeJsPath.dirname(resolvedConfigurationFilePath) + }); + parentConfiguration = this._loadConfigurationFileEntryWithCache( + terminal, + resolvedParentConfigPath, + visitedConfigurationFilePaths + ); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + throw new Error( + `In file "${resolvedConfigurationFilePathForLogging}", file referenced in "extends" property ` + + `("${configurationJson.extends}") cannot be resolved.` + ); + } else { + throw e; + } + } + } + + 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 _loadConfigurationFileEntryAsync( + terminal: ITerminal, + resolvedConfigurationFilePath: string, + visitedConfigurationFilePaths: Set, + fileNotFoundFallback?: IOnConfigurationFileNotFoundCallback + ): Promise> { + const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( + resolvedConfigurationFilePath + ); + + let fileText: string; + try { + fileText = await FileSystem.readFileAsync(resolvedConfigurationFilePath); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + const fallbackPath: string | undefined = fileNotFoundFallback?.( + resolvedConfigurationFilePathForLogging + ); + if (fallbackPath) { + try { + return await this._loadConfigurationFileEntryWithCacheAsync( + terminal, + fallbackPath, + visitedConfigurationFilePaths + ); + } catch (fallbackError) { + if (!FileSystem.isNotExistError(fallbackError as Error)) { + throw fallbackError; + } + // Otherwise report the missing original file. + } + } + + terminal.writeDebugLine(`Configuration file "${resolvedConfigurationFilePathForLogging}" not found.`); + (e as Error).message = `File does not exist: ${resolvedConfigurationFilePathForLogging}`; + } + + throw e; + } + const configurationJson: IConfigurationJson & TConfigurationFile = this._parseConfigurationFile( + fileText, + resolvedConfigurationFilePathForLogging + ); + + let parentConfiguration: IConfigurationFileCacheEntry | undefined; + if (configurationJson.extends) { + try { + const resolvedParentConfigPath: string = await Import.resolveModuleAsync({ + modulePath: configurationJson.extends, + baseFolderPath: nodeJsPath.dirname(resolvedConfigurationFilePath) + }); + parentConfiguration = await this._loadConfigurationFileEntryWithCacheAsync( + terminal, + resolvedParentConfigPath, + visitedConfigurationFilePaths + ); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + throw new Error( + `In file "${resolvedConfigurationFilePathForLogging}", file referenced in "extends" property ` + + `("${configurationJson.extends}") cannot be resolved.` + ); + } else { + throw e; + } + } + } + + const result: IConfigurationFileCacheEntry = { + configurationFile: configurationJson, + resolvedConfigurationFilePath, + resolvedConfigurationFilePathForLogging, + parent: parentConfiguration + }; + return result; + } + + private _annotateProperties(resolvedConfigurationFilePath: string, root: TObject): void { + if (!root) { + return; + } + + 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)) { + queue.add(objValue as TObject); + } + } + } + } + + private _resolvePathProperty( + resolverOptions: IJsonPathMetadataResolverOptions, + metadata: IJsonPathMetadata + ): string { + const { propertyValue, configurationFilePath, projectFolderPath } = resolverOptions; + const resolutionMethod: PathResolutionMethod | undefined = metadata.pathResolutionMethod; + if (resolutionMethod === undefined) { + return propertyValue; + } + + switch (metadata.pathResolutionMethod) { + case PathResolutionMethod.resolvePathRelativeToConfigurationFile: { + return nodeJsPath.resolve(nodeJsPath.dirname(configurationFilePath), propertyValue); + } + + case PathResolutionMethod.resolvePathRelativeToProjectRoot: { + const packageRoot: string | undefined = projectFolderPath; + if (!packageRoot) { + throw new Error( + `Project-relative resolution was requested in "${ConfigurationFileBase._formatPathForLogging( + configurationFilePath + )}" but no project root was provided to the configuration file loader.` + ); + } + + return nodeJsPath.resolve(packageRoot, propertyValue); + } + + case PathResolutionMethod.NodeResolve: // TODO: Remove + case PathResolutionMethod.nodeResolve: { + return Import.resolveModule({ + modulePath: propertyValue, + baseFolderPath: nodeJsPath.dirname(configurationFilePath) + }); + } + + case PathResolutionMethod.custom: { + if (!metadata.customResolver) { + throw new Error( + `The pathResolutionMethod was set to "${PathResolutionMethod[resolutionMethod]}", but a custom ` + + 'resolver was not provided.' + ); + } + + return metadata.customResolver(resolverOptions); + } + + default: { + throw new Error( + `Unsupported PathResolutionMethod: ${PathResolutionMethod[resolutionMethod]} (${resolutionMethod})` + ); + } + } + } + + private _mergeConfigurationFiles( + parentConfiguration: Partial, + configurationJson: Partial, + resolvedConfigurationFilePath: string + ): Partial { + const ignoreProperties: Set = new Set(['extends', '$schema']); + + // Need to do a dance with the casting here because while we know that JSON keys are always + // strings, TypeScript doesn't. + const result: Partial = this._mergeObjects( + parentConfiguration as { [key: string]: unknown }, + configurationJson as { [key: string]: unknown }, + resolvedConfigurationFilePath, + this._defaultPropertyInheritance, + this._propertyInheritanceTypes as IPropertiesInheritance<{ [key: string]: unknown }>, + 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( + parentObject: Partial, + currentObject: Partial, + resolvedConfigurationFilePath: string, + defaultPropertyInheritance: IPropertyInheritanceDefaults, + configuredPropertyInheritance?: IPropertiesInheritance, + ignoreProperties?: Set + ): Partial { + const resultAnnotation: IConfigurationFileFieldAnnotation> = { + configurationFilePath: resolvedConfigurationFilePath, + originalValues: {} as Partial + }; + const result: Partial = { + [CONFIGURATION_FILE_FIELD_ANNOTATION]: resultAnnotation + } as unknown as Partial; + + // An array of property names that are on the merging object. Typed as Set since it may + // contain inheritance type annotation keys, or other built-in properties that we ignore + // (eg. "extends", "$schema"). + const currentObjectPropertyNames: Set = new Set(Object.keys(currentObject)); + // 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)) { + continue; + } + + // Try to get the inheritance type annotation from the merging object using the regex. + // Note: since this regex matches a specific style of property name, we should not need to + // allow for any escaping of $-prefixed properties. If this ever changes (eg. to allow for + // `"$propertyName": { ... }` options), then we'll likely need to handle that error case, + // as well as allow escaping $-prefixed properties that developers want to be serialized, + // possibly by using the form `$$propertyName` to escape `$propertyName`. + const inheritanceTypeMatches: RegExpMatchArray | null = propertyName.match( + CONFIGURATION_FILE_MERGE_BEHAVIOR_FIELD_REGEX + ); + if (inheritanceTypeMatches) { + // Should always be of length 2, since the first match is the entire string and the second + // match is the capture group. + const mergeTargetPropertyName: string = inheritanceTypeMatches[1]; + const inheritanceTypeRaw: unknown | undefined = currentObject[propertyName]; + if (!currentObjectPropertyNames.has(mergeTargetPropertyName)) { + throw new Error( + `Issue in processing configuration file property "${propertyName}". ` + + `An inheritance type was provided but no matching property was found in the parent.` + ); + } else if (typeof inheritanceTypeRaw !== 'string') { + throw new Error( + `Issue in processing configuration file property "${propertyName}". ` + + `An unsupported inheritance type was provided: ${JSON.stringify(inheritanceTypeRaw)}` + ); + } else if (typeof currentObject[mergeTargetPropertyName] !== 'object') { + throw new Error( + `Issue in processing configuration file property "${propertyName}". ` + + `An inheritance type was provided for a property that is not a keyed object or array.` + ); + } + switch (inheritanceTypeRaw.toLowerCase()) { + case 'append': + inheritanceTypeMap.set(mergeTargetPropertyName, { inheritanceType: InheritanceType.append }); + break; + case 'merge': + inheritanceTypeMap.set(mergeTargetPropertyName, { inheritanceType: InheritanceType.merge }); + break; + case 'replace': + inheritanceTypeMap.set(mergeTargetPropertyName, { inheritanceType: InheritanceType.replace }); + break; + default: + throw new Error( + `Issue in processing configuration file property "${propertyName}". ` + + `An unsupported inheritance type was provided: "${inheritanceTypeRaw}"` + ); + } + } else { + mergedPropertyNames.add(propertyName); + } + } + + // Cycle through properties and merge them + for (const propertyName of mergedPropertyNames) { + const propertyValue: TField[keyof TField] | undefined = currentObject[propertyName]; + const parentPropertyValue: TField[keyof TField] | undefined = parentObject[propertyName]; + + let newValue: TField[keyof TField] | undefined; + const usePropertyValue: () => void = () => { + resultAnnotation.originalValues[propertyName] = this.getPropertyOriginalValue({ + parentObject: currentObject, + propertyName: propertyName + }); + newValue = propertyValue; + }; + const useParentPropertyValue: () => void = () => { + resultAnnotation.originalValues[propertyName] = this.getPropertyOriginalValue({ + parentObject: parentObject, + propertyName: propertyName + }); + newValue = parentPropertyValue; + }; + + if (propertyValue === null) { + if (parentPropertyValue !== undefined) { + resultAnnotation.originalValues[propertyName] = this.getPropertyOriginalValue({ + parentObject: parentObject, + propertyName: propertyName + }); + } + newValue = undefined; + } else if (propertyValue !== undefined && parentPropertyValue === undefined) { + usePropertyValue(); + } else if (parentPropertyValue !== undefined && propertyValue === undefined) { + useParentPropertyValue(); + } else if (propertyValue !== undefined && parentPropertyValue !== undefined) { + // If the property is an inheritance type annotation, use it, otherwise fallback to the configured + // top-level property inheritance, if one is specified. + let propertyInheritance: IPropertyInheritance | undefined = + inheritanceTypeMap.get(propertyName) ?? configuredPropertyInheritance?.[propertyName]; + if (!propertyInheritance) { + const bothAreArrays: boolean = Array.isArray(propertyValue) && Array.isArray(parentPropertyValue); + if (bothAreArrays) { + // If both are arrays, use the configured default array inheritance and fallback to appending + // if one is not specified + propertyInheritance = defaultPropertyInheritance.array ?? { + inheritanceType: InheritanceType.append + }; + } else { + const bothAreObjects: boolean = + propertyValue && + parentPropertyValue && + typeof propertyValue === 'object' && + typeof parentPropertyValue === 'object'; + if (bothAreObjects) { + // If both are objects, use the configured default object inheritance and fallback to replacing + // if one is not specified + propertyInheritance = defaultPropertyInheritance.object ?? { + inheritanceType: InheritanceType.replace + }; + } else { + // Fall back to replacing if they are of different types, since we don't know how to merge these + propertyInheritance = { inheritanceType: InheritanceType.replace }; + } + } + } + + switch (propertyInheritance.inheritanceType) { + case InheritanceType.replace: { + usePropertyValue(); + + break; + } + + case InheritanceType.append: { + if (!Array.isArray(propertyValue) || !Array.isArray(parentPropertyValue)) { + throw new Error( + `Issue in processing configuration file property "${propertyName.toString()}". ` + + `Property is not an array, but the inheritance type is set as "${InheritanceType.append}"` + ); + } + + newValue = [...parentPropertyValue, ...propertyValue] as TField[keyof TField]; + (newValue as unknown as IAnnotatedField)[CONFIGURATION_FILE_FIELD_ANNOTATION] = { + configurationFilePath: undefined, + originalValues: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...(parentPropertyValue as any)[CONFIGURATION_FILE_FIELD_ANNOTATION].originalValues, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...(propertyValue as any)[CONFIGURATION_FILE_FIELD_ANNOTATION].originalValues + } + }; + + break; + } + + case InheritanceType.merge: { + if (parentPropertyValue === null || propertyValue === null) { + throw new Error( + `Issue in processing configuration file property "${propertyName.toString()}". ` + + `Null values cannot be used when the inheritance type is set as "${InheritanceType.merge}"` + ); + } else if ( + (propertyValue && typeof propertyValue !== 'object') || + (parentPropertyValue && typeof parentPropertyValue !== 'object') + ) { + throw new Error( + `Issue in processing configuration file property "${propertyName.toString()}". ` + + `Primitive types cannot be provided when the inheritance type is set as "${InheritanceType.merge}"` + ); + } else if (Array.isArray(propertyValue) || Array.isArray(parentPropertyValue)) { + throw new Error( + `Issue in processing configuration file property "${propertyName.toString()}". ` + + `Property is not a keyed object, but the inheritance type is set as "${InheritanceType.merge}"` + ); + } + + // Recursively merge the parent and child objects. Don't pass the configuredPropertyInheritance or + // ignoreProperties because we are no longer at the top level of the configuration file. We also know + // that it must be a string-keyed object, since the JSON spec requires it. + newValue = this._mergeObjects( + parentPropertyValue as { [key: string]: unknown }, + propertyValue as { [key: string]: unknown }, + resolvedConfigurationFilePath, + defaultPropertyInheritance + ) as TField[keyof TField]; + + break; + } + + case InheritanceType.custom: { + const customInheritance: ICustomPropertyInheritance = + propertyInheritance as ICustomPropertyInheritance; + if ( + !customInheritance.inheritanceFunction || + typeof customInheritance.inheritanceFunction !== 'function' + ) { + throw new Error( + 'For property inheritance type "InheritanceType.custom", an inheritanceFunction must be provided.' + ); + } + + newValue = customInheritance.inheritanceFunction(propertyValue, parentPropertyValue); + + break; + } + + default: { + throw new Error(`Unknown inheritance type "${propertyInheritance}"`); + } + } + } + + if (newValue !== undefined) { + // Don't attach the key for undefined values so that they don't enumerate. + result[propertyName] = newValue; + } + } + + return result; + } +} diff --git a/libraries/heft-config-file/src/NonProjectConfigurationFile.ts b/libraries/heft-config-file/src/NonProjectConfigurationFile.ts new file mode 100644 index 00000000000..20929de4d07 --- /dev/null +++ b/libraries/heft-config-file/src/NonProjectConfigurationFile.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 { FileSystem, PackageJsonLookup } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { ConfigurationFileBase } from './ConfigurationFileBase'; + +/** + * @beta + */ +export class NonProjectConfigurationFile extends ConfigurationFileBase< + TConfigurationFile, + {} +> { + /** + * Load the configuration file at the specified absolute path, automatically resolving + * `extends` properties. Will throw an error if the file cannot be found. + */ + public loadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile { + return this._loadConfigurationFileInnerWithCache( + terminal, + filePath, + PackageJsonLookup.instance.tryGetPackageFolderFor(filePath) + ); + } + + /** + * Load the configuration file at the specified absolute path, automatically resolving + * `extends` properties. Will throw an error if the file cannot be found. + */ + public async loadConfigurationFileAsync( + terminal: ITerminal, + filePath: string + ): Promise { + return await this._loadConfigurationFileInnerWithCacheAsync( + terminal, + filePath, + PackageJsonLookup.instance.tryGetPackageFolderFor(filePath) + ); + } + + /** + * This function is identical to {@link NonProjectConfigurationFile.loadConfigurationFile}, except + * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. + */ + public tryLoadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile | undefined { + try { + return this.loadConfigurationFile(terminal, filePath); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return undefined; + } + throw e; + } + } + + /** + * This function is identical to {@link NonProjectConfigurationFile.loadConfigurationFileAsync}, except + * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. + */ + public async tryLoadConfigurationFileAsync( + terminal: ITerminal, + filePath: string + ): Promise { + try { + return await this.loadConfigurationFileAsync(terminal, filePath); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return undefined; + } + throw e; + } + } +} diff --git a/libraries/heft-config-file/src/ProjectConfigurationFile.ts b/libraries/heft-config-file/src/ProjectConfigurationFile.ts new file mode 100644 index 00000000000..4ccbb659db7 --- /dev/null +++ b/libraries/heft-config-file/src/ProjectConfigurationFile.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. + +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 IOnConfigurationFileNotFoundCallback, + type IConfigurationFileOptions +} from './ConfigurationFileBase'; + +/** + * @beta + */ +export interface IProjectConfigurationFileOptions { + /** + * A project root-relative path to the configuration file that should be loaded. + */ + projectRelativeFilePath: string; +} + +/** + * Alias for the constructor type for {@link ProjectConfigurationFile}. + * @beta + */ +export type IProjectConfigurationFileSpecification = IConfigurationFileOptions< + TConfigFile, + IProjectConfigurationFileOptions +>; + +/** + * @beta + */ +export class ProjectConfigurationFile extends ConfigurationFileBase< + TConfigurationFile, + IProjectConfigurationFileOptions +> { + /** {@inheritDoc IProjectConfigurationFileOptions.projectRelativeFilePath} */ + public readonly projectRelativeFilePath: string; + + public constructor(options: IProjectConfigurationFileSpecification) { + super(options); + this.projectRelativeFilePath = options.projectRelativeFilePath; + } + + /** + * Find and return a configuration file for the specified project, automatically resolving + * `extends` properties and handling rigged configuration files. Will throw an error if a configuration + * file cannot be found in the rig or project config folder. + */ + public loadConfigurationFileForProject( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig + ): TConfigurationFile { + const projectConfigurationFilePath: string = this._getConfigurationFilePathForProject(projectPath); + return this._loadConfigurationFileInnerWithCache( + terminal, + projectConfigurationFilePath, + PackageJsonLookup.instance.tryGetPackageFolderFor(projectPath), + this._getRigConfigFallback(terminal, rigConfig) + ); + } + + /** + * Find and return a configuration file for the specified project, automatically resolving + * `extends` properties and handling rigged configuration files. Will throw an error if a configuration + * file cannot be found in the rig or project config folder. + */ + public async loadConfigurationFileForProjectAsync( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig + ): Promise { + const projectConfigurationFilePath: string = this._getConfigurationFilePathForProject(projectPath); + return await this._loadConfigurationFileInnerWithCacheAsync( + terminal, + projectConfigurationFilePath, + PackageJsonLookup.instance.tryGetPackageFolderFor(projectPath), + this._getRigConfigFallback(terminal, rigConfig) + ); + } + + /** + * This function is identical to {@link ProjectConfigurationFile.loadConfigurationFileForProject}, except + * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. + */ + public tryLoadConfigurationFileForProject( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig + ): TConfigurationFile | undefined { + try { + return this.loadConfigurationFileForProject(terminal, projectPath, rigConfig); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return undefined; + } + throw e; + } + } + + /** + * This function is identical to {@link ProjectConfigurationFile.loadConfigurationFileForProjectAsync}, except + * that it returns `undefined` instead of throwing an error if the configuration file cannot be found. + */ + public async tryLoadConfigurationFileForProjectAsync( + terminal: ITerminal, + projectPath: string, + rigConfig?: IRigConfig + ): Promise { + try { + return await this.loadConfigurationFileForProjectAsync(terminal, projectPath, rigConfig); + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + return undefined; + } + throw e; + } + } + + private _getConfigurationFilePathForProject(projectPath: string): string { + return nodeJsPath.resolve(projectPath, this.projectRelativeFilePath); + } + + private _getRigConfigFallback( + terminal: ITerminal, + 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)}"` + ); + } + } + : undefined; + } +} diff --git a/libraries/heft-config-file/src/TestUtilities.ts b/libraries/heft-config-file/src/TestUtilities.ts new file mode 100644 index 00000000000..b51f3f455c0 --- /dev/null +++ b/libraries/heft-config-file/src/TestUtilities.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 { CONFIGURATION_FILE_FIELD_ANNOTATION, type IAnnotatedField } from './ConfigurationFileBase'; + +/** + * Returns an object with investigative annotations stripped, useful for snapshot testing. + * + * @beta + */ +export function stripAnnotations(obj: TObject): TObject { + if (typeof obj !== 'object' || obj === null) { + return obj; + } else if (Array.isArray(obj)) { + const result: unknown[] = []; + for (const value of obj) { + result.push(stripAnnotations(value)); + } + + return result as TObject; + } else { + const clonedObj: TObject = { ...obj } as TObject; + delete (clonedObj as Partial>)[CONFIGURATION_FILE_FIELD_ANNOTATION]; + for (const [name, value] of Object.entries(clonedObj as object)) { + clonedObj[name as keyof TObject] = stripAnnotations( + value as TObject[keyof TObject] + ); + } + + return clonedObj; + } +} diff --git a/libraries/heft-config-file/src/index.ts b/libraries/heft-config-file/src/index.ts new file mode 100644 index 00000000000..bd912a1ea15 --- /dev/null +++ b/libraries/heft-config-file/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. + +/** + * A library for loading config files for use with the + * {@link https://rushstack.io/pages/heft/overview/ | Heft} build system. + * + * @packageDocumentation + */ + +export { + ConfigurationFileBase, + type CustomValidationFunction, + type IConfigurationFileOptionsBase, + type IConfigurationFileOptionsWithJsonSchemaFilePath, + type IConfigurationFileOptionsWithJsonSchemaObject, + type IConfigurationFileOptions, + type ICustomJsonPathMetadata, + type ICustomPropertyInheritance, + type IJsonPathMetadataResolverOptions, + type IJsonPathMetadata, + type IJsonPathsMetadata, + InheritanceType, + type INonCustomJsonPathMetadata, + type IOnConfigurationFileNotFoundCallback, + type IOriginalValueOptions, + type IPropertiesInheritance, + type IPropertyInheritance, + type IPropertyInheritanceDefaults, + PathResolutionMethod, + type PropertyInheritanceCustomFunction +} from './ConfigurationFileBase'; + +import { ProjectConfigurationFile } from './ProjectConfigurationFile'; + +/** + * @deprecated Use {@link ProjectConfigurationFile} instead. + * @beta + */ +export const ConfigurationFile: typeof ProjectConfigurationFile = ProjectConfigurationFile; + +/** + * @deprecated Use {@link ProjectConfigurationFile} instead. + * @beta + */ +// eslint-disable-next-line @typescript-eslint/no-redeclare +export type ConfigurationFile = 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 new file mode 100644 index 00000000000..2afb977e9e7 --- /dev/null +++ b/libraries/heft-config-file/src/test/ConfigurationFile.test.ts @@ -0,0 +1,1925 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; + +import { ProjectConfigurationFile } from '../ProjectConfigurationFile'; +import { PathResolutionMethod, InheritanceType, ConfigurationFileBase } from '../ConfigurationFileBase'; +import { NonProjectConfigurationFile } from '../NonProjectConfigurationFile'; + +describe('ConfigurationFile', () => { + const projectRoot: string = nodeJsPath.resolve(__dirname, '../..'); + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + + beforeEach(() => { + const formatPathForLogging: (path: string) => string = (path: string) => + `/${Path.convertToSlashes(nodeJsPath.relative(projectRoot, path))}`; + jest.spyOn(ConfigurationFileBase, '_formatPathForLogging').mockImplementation(formatPathForLogging); + jest.spyOn(JsonFile, '_formatPathForError').mockImplementation(formatPathForLogging); + + terminalProvider = new StringBufferTerminalProvider(false); + terminal = new Terminal(terminalProvider); + }); + + afterEach(() => { + expect({ + log: terminalProvider.getOutput(), + warning: terminalProvider.getWarningOutput(), + error: terminalProvider.getErrorOutput(), + verbose: terminalProvider.getVerboseOutput(), + debug: terminalProvider.getDebugOutput() + }).toMatchSnapshot(); + }); + + describe('A simple config file', () => { + const configFileFolderName: string = 'simplestConfigFile'; + function runTests(partialOptions: { jsonSchemaPath: string } | { jsonSchemaObject: object }): void { + const projectRelativeFilePath: string = `${configFileFolderName}/simplestConfigFile.json`; + + interface ISimplestConfigFile { + thing: string; + } + + it('Correctly loads the config file', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions + }); + const loadedConfigFile: ISimplestConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('Correctly loads the config file async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions + }); + const loadedConfigFile: ISimplestConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('Correctly resolves paths relative to the config file', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions, + jsonPathMetadata: { + '$.thing': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimplestConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimplestConfigFile = { + thing: nodeJsPath.resolve(__dirname, configFileFolderName, 'A') + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('Correctly resolves paths relative to the config file async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions, + jsonPathMetadata: { + '$.thing': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimplestConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: ISimplestConfigFile = { + thing: nodeJsPath.resolve(__dirname, configFileFolderName, 'A') + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('Correctly resolves paths relative to the project root', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions, + jsonPathMetadata: { + '$.thing': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + } + } + }); + const loadedConfigFile: ISimplestConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimplestConfigFile = { + thing: nodeJsPath.resolve(projectRoot, 'A') + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('Correctly resolves paths relative to the project root async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + ...partialOptions, + jsonPathMetadata: { + '$.thing': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + } + } + }); + const loadedConfigFile: ISimplestConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: ISimplestConfigFile = { + thing: nodeJsPath.resolve(projectRoot, 'A') + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve(__dirname, projectRelativeFilePath) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it(`The ${NonProjectConfigurationFile.name} version works correctly`, () => { + const configFileLoader: NonProjectConfigurationFile = + new NonProjectConfigurationFile(partialOptions); + const loadedConfigFile: ISimplestConfigFile = configFileLoader.loadConfigurationFile( + terminal, + `${__dirname}/${projectRelativeFilePath}` + ); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + `${__dirname}/${projectRelativeFilePath}` + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it(`The ${NonProjectConfigurationFile.name} version works correctly async`, async () => { + const configFileLoader: NonProjectConfigurationFile = + new NonProjectConfigurationFile(partialOptions); + const loadedConfigFile: ISimplestConfigFile = await configFileLoader.loadConfigurationFileAsync( + terminal, + `${__dirname}/${projectRelativeFilePath}` + ); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + `${__dirname}/${projectRelativeFilePath}` + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + } + + describe('with a JSON schema path', () => { + runTests({ jsonSchemaPath: `${__dirname}/${configFileFolderName}/simplestConfigFile.schema.json` }); + }); + + describe('with a JSON schema object', () => { + runTests({ + jsonSchemaObject: JsonFile.load(`${__dirname}/${configFileFolderName}/simplestConfigFile.schema.json`) + }); + }); + }); + + describe('A simple config file containing an array and an object', () => { + const configFileFolderName: string = 'simpleConfigFile'; + const projectRelativeFilePath: string = `${configFileFolderName}/simpleConfigFile.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', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C'], + thingsObj: { A: { B: 'C' }, D: { E: 'F' } }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C'], + thingsObj: { A: { B: 'C' }, D: { E: 'F' } }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the config file', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(__dirname, configFileFolderName, 'A'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'B'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'C') + ], + thingsObj: { + A: { B: nodeJsPath.resolve(__dirname, configFileFolderName, 'C') }, + D: { E: nodeJsPath.resolve(__dirname, configFileFolderName, 'F') } + }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the config file async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(__dirname, configFileFolderName, 'A'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'B'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'C') + ], + thingsObj: { + A: { B: nodeJsPath.resolve(__dirname, configFileFolderName, 'C') }, + D: { E: nodeJsPath.resolve(__dirname, configFileFolderName, 'F') } + }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the project root', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(projectRoot, 'A'), + nodeJsPath.resolve(projectRoot, 'B'), + nodeJsPath.resolve(projectRoot, 'C') + ], + thingsObj: { + A: { B: nodeJsPath.resolve(projectRoot, 'C') }, + D: { E: nodeJsPath.resolve(projectRoot, 'F') } + }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the project root async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(projectRoot, 'A'), + nodeJsPath.resolve(projectRoot, 'B'), + nodeJsPath.resolve(projectRoot, 'C') + ], + thingsObj: { + A: { B: nodeJsPath.resolve(projectRoot, 'C') }, + D: { E: nodeJsPath.resolve(projectRoot, 'F') } + }, + booleanProp: true, + stringProp: 'someValue' + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + }); + + describe('A simple config file with "extends"', () => { + const configFileFolderName: string = 'simpleConfigFileWithExtends'; + const projectRelativeFilePath: string = `${configFileFolderName}/simpleConfigFileWithExtends.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', () => { + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C', 'D', 'E'], + thingsObj: { A: { D: 'E' }, F: { G: 'H' } }, + booleanProp: false + }; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + const nonProjectConfigFileLoader: NonProjectConfigurationFile = + new NonProjectConfigurationFile({ + jsonSchemaPath: schemaPath + }); + const nonProjectLoadedConfigFile: ISimpleConfigFile = nonProjectConfigFileLoader.loadConfigurationFile( + terminal, + `${__dirname}/${projectRelativeFilePath}` + ); + expect(JSON.stringify(nonProjectLoadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with default config meta async', async () => { + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C', 'D', 'E'], + thingsObj: { A: { D: 'E' }, F: { G: 'H' } }, + booleanProp: false + }; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + const nonProjectConfigFileLoader: NonProjectConfigurationFile = + new NonProjectConfigurationFile({ + jsonSchemaPath: schemaPath + }); + const nonProjectLoadedConfigFile: ISimpleConfigFile = + await nonProjectConfigFileLoader.loadConfigurationFileAsync( + terminal, + `${__dirname}/${projectRelativeFilePath}` + ); + expect(JSON.stringify(nonProjectLoadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "append" and "merge" in config meta', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.append + }, + thingsObj: { + inheritanceType: InheritanceType.merge + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C', 'D', 'E'], + thingsObj: { A: { D: 'E' }, D: { E: 'F' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "append" and "merge" in config meta async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.append + }, + thingsObj: { + inheritanceType: InheritanceType.merge + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['A', 'B', 'C', 'D', 'E'], + thingsObj: { A: { D: 'E' }, D: { E: 'F' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "replace" in config meta', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.replace + }, + thingsObj: { + inheritanceType: InheritanceType.replace + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['D', 'E'], + thingsObj: { A: { D: 'E' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "replace" in config meta async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.replace + }, + thingsObj: { + inheritanceType: InheritanceType.replace + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['D', 'E'], + thingsObj: { A: { D: 'E' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with modified merge behaviors for arrays and objects', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritanceDefaults: { + array: { inheritanceType: InheritanceType.replace }, + object: { inheritanceType: InheritanceType.merge } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['D', 'E'], + thingsObj: { A: { B: 'C', D: 'E' }, D: { E: 'F' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with modified merge behaviors for arrays and objects async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritanceDefaults: { + array: { inheritanceType: InheritanceType.replace }, + object: { inheritanceType: InheritanceType.merge } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['D', 'E'], + thingsObj: { A: { B: 'C', D: 'E' }, D: { E: 'F' }, F: { G: 'H' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "custom" in config meta', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: (current: string[], parent: string[]) => ['X', 'Y', 'Z'] + }, + thingsObj: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: ( + current: { A: { B?: string; D?: string }; D?: { E: string }; F?: { G: string } }, + parent: { A: { B?: string; D?: string }; D?: { E: string }; F?: { G: string } } + ) => { + return { + A: { B: 'Y', D: 'Z' } + }; + } + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['X', 'Y', 'Z'], + thingsObj: { A: { B: 'Y', D: 'Z' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly loads the config file with "custom" in config meta async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + propertyInheritance: { + things: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: (current: string[], parent: string[]) => ['X', 'Y', 'Z'] + }, + thingsObj: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: ( + current: { A: { B?: string; D?: string }; D?: { E: string }; F?: { G: string } }, + parent: { A: { B?: string; D?: string }; D?: { E: string }; F?: { G: string } } + ) => { + return { + A: { B: 'Y', D: 'Z' } + }; + } + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const expectedConfigFile: ISimpleConfigFile = { + things: ['X', 'Y', 'Z'], + thingsObj: { A: { B: 'Y', D: 'Z' } }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the config file', () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimpleConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const parentConfigFileFolder: string = nodeJsPath.resolve( + __dirname, + configFileFolderName, + '..', + 'simpleConfigFile' + ); + + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(parentConfigFileFolder, 'A'), + nodeJsPath.resolve(parentConfigFileFolder, 'B'), + nodeJsPath.resolve(parentConfigFileFolder, 'C'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'D'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'E') + ], + thingsObj: { + A: { D: nodeJsPath.resolve(__dirname, configFileFolderName, 'E') }, + F: { G: nodeJsPath.resolve(__dirname, configFileFolderName, 'H') } + }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + + it('Correctly resolves paths relative to the config file async', async () => { + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.things.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + '$.thingsObj.*.*': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } + }); + const loadedConfigFile: ISimpleConfigFile = await configFileLoader.loadConfigurationFileForProjectAsync( + terminal, + __dirname + ); + const parentConfigFileFolder: string = nodeJsPath.resolve( + __dirname, + configFileFolderName, + '..', + 'simpleConfigFile' + ); + + const expectedConfigFile: ISimpleConfigFile = { + things: [ + nodeJsPath.resolve(parentConfigFileFolder, 'A'), + nodeJsPath.resolve(parentConfigFileFolder, 'B'), + nodeJsPath.resolve(parentConfigFileFolder, 'C'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'D'), + nodeJsPath.resolve(__dirname, configFileFolderName, 'E') + ], + thingsObj: { + A: { D: nodeJsPath.resolve(__dirname, configFileFolderName, 'E') }, + F: { G: nodeJsPath.resolve(__dirname, configFileFolderName, 'H') } + }, + booleanProp: false + }; + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + }); + }); + + describe('A complex config file', () => { + interface IComplexConfigFile { + plugins: { plugin: string }[]; + } + + it('Correctly loads a complex config file (Deprecated PathResolutionMethod.NodeResolve)', () => { + const projectRelativeFilePath: string = 'complexConfigFile/pluginsD.json'; + const rootConfigFilePath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'pluginsA.json'); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'complexConfigFile', + 'pluginsB.json' + ); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.plugins.*.plugin': { + pathResolutionMethod: PathResolutionMethod.NodeResolve + } + } + }); + const loadedConfigFile: IComplexConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: IComplexConfigFile = { + plugins: [ + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'node-core-library', + 'lib', + 'index.js' + ) + ) + }, + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + ) + }, + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve(projectRoot, 'node_modules', 'jsonpath-plus', 'dist', 'index-node-cjs.cjs') + ) + } + ] + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[0], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/node-core-library'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[1], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/heft'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[2], + propertyName: 'plugin' + }) + ).toEqual('jsonpath-plus'); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[0])).toEqual( + rootConfigFilePath + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[1])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[2])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + }); + + it('Correctly loads a complex config file async (Deprecated PathResolutionMethod.NodeResolve)', async () => { + const projectRelativeFilePath: string = 'complexConfigFile/pluginsD.json'; + const rootConfigFilePath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'pluginsA.json'); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'complexConfigFile', + 'pluginsB.json' + ); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.plugins.*.plugin': { + pathResolutionMethod: PathResolutionMethod.NodeResolve + } + } + }); + const loadedConfigFile: IComplexConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: IComplexConfigFile = { + plugins: [ + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'node-core-library', + 'lib', + 'index.js' + ) + ) + }, + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + ) + }, + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve(projectRoot, 'node_modules', 'jsonpath-plus', 'dist', 'index-node-cjs.cjs') + ) + } + ] + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[0], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/node-core-library'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[1], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/heft'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[2], + propertyName: 'plugin' + }) + ).toEqual('jsonpath-plus'); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[0])).toEqual( + rootConfigFilePath + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[1])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[2])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + }); + + it('Correctly loads a complex config file', () => { + const projectRelativeFilePath: string = 'complexConfigFile/pluginsD.json'; + const rootConfigFilePath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'pluginsA.json'); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'complexConfigFile', + 'pluginsB.json' + ); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.plugins.*.plugin': { + pathResolutionMethod: PathResolutionMethod.nodeResolve + } + } + }); + const loadedConfigFile: IComplexConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: IComplexConfigFile = { + plugins: [ + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'node-core-library', + 'lib', + 'index.js' + ) + ) + }, + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + ) + }, + { + plugin: FileSystem.getRealPath( + nodeJsPath.resolve(projectRoot, 'node_modules', 'jsonpath-plus', 'dist', 'index-node-cjs.cjs') + ) + } + ] + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[0], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/node-core-library'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[1], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/heft'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[2], + propertyName: 'plugin' + }) + ).toEqual('jsonpath-plus'); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[0])).toEqual( + rootConfigFilePath + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[1])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[2])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + }); + + it('Correctly loads a complex config file async', async () => { + const projectRelativeFilePath: string = 'complexConfigFile/pluginsD.json'; + const rootConfigFilePath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'pluginsA.json'); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'complexConfigFile', + 'pluginsB.json' + ); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath, + jsonPathMetadata: { + '$.plugins.*.plugin': { + pathResolutionMethod: PathResolutionMethod.nodeResolve + } + } + }); + const loadedConfigFile: IComplexConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: IComplexConfigFile = { + plugins: [ + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'node-core-library', + 'lib', + 'index.js' + ) + ) + }, + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + ) + }, + { + plugin: await FileSystem.getRealPathAsync( + nodeJsPath.resolve(projectRoot, 'node_modules', 'jsonpath-plus', 'dist', 'index-node-cjs.cjs') + ) + } + ] + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[0], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/node-core-library'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[1], + propertyName: 'plugin' + }) + ).toEqual('@rushstack/heft'); + expect( + configFileLoader.getPropertyOriginalValue({ + parentObject: loadedConfigFile.plugins[2], + propertyName: 'plugin' + }) + ).toEqual('jsonpath-plus'); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[0])).toEqual( + rootConfigFilePath + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[1])).toEqual( + nodeJsPath.resolve(__dirname, secondConfigFilePath) + ); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.plugins[2])).toEqual( + 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', () => { + interface IInheritanceTypeConfigFile { + a: string; + b: { c: string }[]; + d: { + e: string; + f: string; + g: { h: string }[]; + i: { j: string }[]; + k: { + l: string; + m: { n: string }[]; + z?: string; + }; + o: { + p: { q: string }[]; + }; + r: { + s: string; + }; + y?: { + z: string; + }; + }; + y?: { + z: string; + }; + } + + interface ISimpleInheritanceTypeConfigFile { + a: { b: string }[]; + c: { + d: { e: string }[]; + }; + f: { + g: { h: string }[]; + i: { + j: { k: string }[]; + }; + }; + l: string; + } + + it('Correctly loads a complex config file with inheritance type annotations', () => { + const projectRelativeFilePath: string = 'inheritanceTypeConfigFile/inheritanceTypeConfigFileB.json'; + const rootConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'inheritanceTypeConfigFile', + 'inheritanceTypeConfigFileA.json' + ); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'inheritanceTypeConfigFile', + 'inheritanceTypeConfigFileB.json' + ); + const schemaPath: string = `${__dirname}/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: IInheritanceTypeConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + __dirname + ); + const expectedConfigFile: IInheritanceTypeConfigFile = { + a: 'A', + // "$b.inheritanceType": "append" + b: [{ c: 'A' }, { c: 'B' }], + // "$d.inheritanceType": "merge" + d: { + e: 'A', + f: 'B', + // "$g.inheritanceType": "append" + g: [{ h: 'A' }, { h: 'B' }], + // "$i.inheritanceType": "replace" + i: [{ j: 'B' }], + // "$k.inheritanceType": "merge" + k: { + l: 'A', + m: [{ n: 'A' }, { n: 'B' }], + z: 'B' + }, + // "$o.inheritanceType": "replace" + o: { + p: [{ q: 'B' }] + }, + r: { + s: 'A' + }, + y: { + z: 'B' + } + }, + y: { + z: 'B' + } + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.b[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.b[1])).toEqual(secondConfigFilePath); + + // loadedConfigFile.d source path is the second config file since it was merged into the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.g[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.g[1])).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.i[0])).toEqual(secondConfigFilePath); + + // loadedConfigFile.d.k source path is the second config file since it was merged into the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k.m[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k.m[1])).toEqual( + secondConfigFilePath + ); + + // loadedConfigFile.d.o source path is the second config file since it replaced the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.o)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.o.p[0])).toEqual( + secondConfigFilePath + ); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.r)).toEqual(rootConfigFilePath); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.y!)).toEqual(secondConfigFilePath); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.y!)).toEqual(secondConfigFilePath); + }); + + it('Correctly loads a complex config file with inheritance type annotations async', async () => { + const projectRelativeFilePath: string = 'inheritanceTypeConfigFile/inheritanceTypeConfigFileB.json'; + const rootConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'inheritanceTypeConfigFile', + 'inheritanceTypeConfigFileA.json' + ); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'inheritanceTypeConfigFile', + 'inheritanceTypeConfigFileB.json' + ); + const schemaPath: string = `${__dirname}/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: IInheritanceTypeConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: IInheritanceTypeConfigFile = { + a: 'A', + // "$b.inheritanceType": "append" + b: [{ c: 'A' }, { c: 'B' }], + // "$d.inheritanceType": "merge" + d: { + e: 'A', + f: 'B', + // "$g.inheritanceType": "append" + g: [{ h: 'A' }, { h: 'B' }], + // "$i.inheritanceType": "replace" + i: [{ j: 'B' }], + // "$k.inheritanceType": "merge" + k: { + l: 'A', + m: [{ n: 'A' }, { n: 'B' }], + z: 'B' + }, + // "$o.inheritanceType": "replace" + o: { + p: [{ q: 'B' }] + }, + r: { + s: 'A' + }, + y: { + z: 'B' + } + }, + y: { + z: 'B' + } + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.b[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.b[1])).toEqual(secondConfigFilePath); + + // loadedConfigFile.d source path is the second config file since it was merged into the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.g[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.g[1])).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.i[0])).toEqual(secondConfigFilePath); + + // loadedConfigFile.d.k source path is the second config file since it was merged into the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k.m[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.k.m[1])).toEqual( + secondConfigFilePath + ); + + // loadedConfigFile.d.o source path is the second config file since it replaced the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.o)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.o.p[0])).toEqual( + secondConfigFilePath + ); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.r)).toEqual(rootConfigFilePath); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.d.y!)).toEqual(secondConfigFilePath); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.y!)).toEqual(secondConfigFilePath); + }); + + it('Correctly loads a complex config file with a single inheritance type annotation', async () => { + const projectRelativeFilePath: string = + 'simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileB.json'; + const rootConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'simpleInheritanceTypeConfigFile', + 'simpleInheritanceTypeConfigFileA.json' + ); + const secondConfigFilePath: string = nodeJsPath.resolve( + __dirname, + 'simpleInheritanceTypeConfigFile', + 'simpleInheritanceTypeConfigFileB.json' + ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimpleInheritanceTypeConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + const expectedConfigFile: ISimpleInheritanceTypeConfigFile = { + a: [{ b: 'A' }, { b: 'B' }], + c: { + d: [{ e: 'B' }] + }, + // "$f.inheritanceType": "merge" + f: { + g: [{ h: 'A' }, { h: 'B' }], + i: { + j: [{ k: 'B' }] + } + }, + l: 'A' + }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.a[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.a[1])).toEqual(secondConfigFilePath); + + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.c)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.c.d[0])).toEqual(secondConfigFilePath); + + // loadedConfigFile.f source path is the second config file since it was merged into the first + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.f)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.f.g[0])).toEqual(rootConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.f.g[1])).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.f.i)).toEqual(secondConfigFilePath); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile.f.i.j[0])).toEqual( + secondConfigFilePath + ); + }); + + it("throws an error when an array uses the 'merge' inheritance type", () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("throws an error when an array uses the 'merge' inheritance type async", async () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it("throws an error when a keyed object uses the 'append' inheritance type", () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("throws an error when a keyed object uses the 'append' inheritance type async", async () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when a non-object property uses an inheritance type', () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when a non-object property uses an inheritance type async', async () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when an inheritance type is specified for an unspecified property', () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when an inheritance type is specified for an unspecified property async', async () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when an unsupported inheritance type is specified', () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it('throws an error when an unsupported inheritance type is specified async', async () => { + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + + describe('loading a rig', () => { + const projectFolder: string = `${__dirname}/project-referencing-rig`; + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ projectFolderPath: projectFolder }); + + const schemaPath: string = `${__dirname}/simplestConfigFile/simplestConfigFile.schema.json`; + + interface ISimplestConfigFile { + thing: string; + } + + it('correctly loads a config file inside a rig', () => { + const projectRelativeFilePath: string = 'config/simplestConfigFile.json'; + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimplestConfigFile = configFileLoader.loadConfigurationFileForProject( + terminal, + projectFolder, + rigConfig + ); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve( + projectFolder, + 'node_modules', + 'test-rig', + 'profiles', + 'default', + projectRelativeFilePath + ) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('correctly loads a config file inside a rig async', async () => { + const projectRelativeFilePath: string = 'config/simplestConfigFile.json'; + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimplestConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, projectFolder, rigConfig); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile)).toEqual( + nodeJsPath.resolve( + projectFolder, + 'node_modules', + 'test-rig', + 'profiles', + 'default', + projectRelativeFilePath + ) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('correctly loads a config file inside a rig via tryLoadConfigurationFileForProject', () => { + const projectRelativeFilePath: string = 'config/simplestConfigFile.json'; + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimplestConfigFile | undefined = + configFileLoader.tryLoadConfigurationFileForProject(terminal, projectFolder, rigConfig); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(loadedConfigFile).not.toBeUndefined(); + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile!)).toEqual( + nodeJsPath.resolve( + projectFolder, + 'node_modules', + 'test-rig', + 'profiles', + 'default', + projectRelativeFilePath + ) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile!, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it('correctly loads a config file inside a rig via tryLoadConfigurationFileForProjectAsync', async () => { + const projectRelativeFilePath: string = 'config/simplestConfigFile.json'; + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: projectRelativeFilePath, + jsonSchemaPath: schemaPath + }); + const loadedConfigFile: ISimplestConfigFile | undefined = + await configFileLoader.tryLoadConfigurationFileForProjectAsync(terminal, projectFolder, rigConfig); + const expectedConfigFile: ISimplestConfigFile = { thing: 'A' }; + + expect(loadedConfigFile).not.toBeUndefined(); + expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); + expect(configFileLoader.getObjectSourceFilePath(loadedConfigFile!)).toEqual( + nodeJsPath.resolve( + projectFolder, + 'node_modules', + 'test-rig', + 'profiles', + 'default', + projectRelativeFilePath + ) + ); + expect( + configFileLoader.getPropertyOriginalValue({ parentObject: loadedConfigFile!, propertyName: 'thing' }) + ).toEqual('A'); + }); + + it("throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file", () => { + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'config/notExist.json', + jsonSchemaPath: schemaPath + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, projectFolder, rigConfig) + ).toThrowErrorMatchingSnapshot(); + }); + + it("throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file async", async () => { + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: 'config/notExist.json', + jsonSchemaPath: schemaPath + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, projectFolder, rigConfig) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + + describe('error cases', () => { + const errorCasesFolderName: string = 'errorCases'; + + it("throws an error when the file doesn't exist", () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("throws an error when the file doesn't exist async", async () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it("returns undefined when the file doesn't exist for tryLoadConfigurationFileForProject", () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(configFileLoader.tryLoadConfigurationFileForProject(terminal, __dirname)).toBeUndefined(); + }); + + it("returns undefined when the file doesn't exist for tryLoadConfigurationFileForProjectAsync", async () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.tryLoadConfigurationFileForProjectAsync(terminal, __dirname) + ).resolves.toBeUndefined(); + }); + + it("Throws an error when the file isn't valid JSON", () => { + const errorCaseFolderName: string = 'invalidJson'; + const configFilePath: string = `${errorCasesFolderName}/${errorCaseFolderName}/config.json`; + const fullConfigFilePath: string = `${__dirname}/${configFilePath}`; + // Normalize newlines to make the error message consistent across platforms + const normalizedRawConfigFile: string = Text.convertToLf(FileSystem.readFile(fullConfigFilePath)); + jest + .spyOn(FileSystem, 'readFileAsync') + .mockImplementation((filePath: string) => + Path.convertToSlashes(filePath) === Path.convertToSlashes(fullConfigFilePath) + ? Promise.resolve(normalizedRawConfigFile) + : Promise.reject(new Error('File not found')) + ); + + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: configFilePath, + 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 configuration file "\/lib\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ + ); + + jest.restoreAllMocks(); + }); + + it("Throws an error when the file isn't valid JSON async", async () => { + const errorCaseFolderName: string = 'invalidJson'; + const configFilePath: string = `${errorCasesFolderName}/${errorCaseFolderName}/config.json`; + const fullConfigFilePath: string = `${__dirname}/${configFilePath}`; + // Normalize newlines to make the error message consistent across platforms + const normalizedRawConfigFile: string = Text.convertToLf( + await FileSystem.readFileAsync(fullConfigFilePath) + ); + jest + .spyOn(FileSystem, 'readFileAsync') + .mockImplementation((filePath: string) => + Path.convertToSlashes(filePath) === Path.convertToSlashes(fullConfigFilePath) + ? Promise.resolve(normalizedRawConfigFile) + : Promise.reject(new Error('File not found')) + ); + + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: configFilePath, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowError( + /In configuration file "\/lib\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ + ); + + jest.restoreAllMocks(); + }); + + it("Throws an error for a file that doesn't match its schema", () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("Throws an error for a file that doesn't match its schema async", async () => { + const errorCaseFolderName: string = 'invalidType'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Throws an error when there is a circular reference in "extends" properties', () => { + const errorCaseFolderName: string = 'circularReference'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it('Throws an error when there is a circular reference in "extends" properties async', async () => { + const errorCaseFolderName: string = 'circularReference'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Throws an error when an "extends" property points to a file that cannot be resolved', () => { + const errorCaseFolderName: string = 'extendsNotExist'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it('Throws an error when an "extends" property points to a file that cannot be resolved async', async () => { + const errorCaseFolderName: string = 'extendsNotExist'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it("Throws an error when a combined config file doesn't match the schema", () => { + const errorCaseFolderName: string = 'invalidCombinedFile'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("Throws an error when a combined config file doesn't match the schema async", async () => { + const errorCaseFolderName: string = 'invalidCombinedFile'; + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it("Throws an error when a requested file doesn't exist", () => { + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/folderThatDoesntExist/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/invalidCombinedFile/config.schema.json` + }); + + expect(() => + configFileLoader.loadConfigurationFileForProject(terminal, __dirname) + ).toThrowErrorMatchingSnapshot(); + }); + + it("Throws an error when a requested file doesn't exist async", async () => { + const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ + projectRelativeFilePath: `${errorCasesFolderName}/folderThatDoesntExist/config.json`, + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/invalidCombinedFile/config.schema.json` + }); + + await expect( + configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + }); +}); 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 new file mode 100644 index 00000000000..04cdb9dff85 --- /dev/null +++ b/libraries/heft-config-file/src/test/__snapshots__/ConfigurationFile.test.ts.snap @@ -0,0 +1,821 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConfigurationFile A complex config file Can get the original $schema property value 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`ConfigurationFile A complex config file Correctly loads a complex config file (Deprecated PathResolutionMethod.NodeResolve) 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 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 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 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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 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 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 modified merge behaviors for arrays and objects async 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 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 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`] = ` +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`] = ` +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`] = ` +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`] = ` +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`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 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 loads 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 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 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`] = ` +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`] = ` +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`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 The NonProjectConfigurationFile version works correctly 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`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 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 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 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 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 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 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 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 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 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 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 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 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 + +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 async 1`] = ` +"Resolved configuration object does not match schema: Error: JSON validation failed: +/lib/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 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 + +Error: # + must NOT have additional properties: folderPaths +Error: # + must NOT have additional properties: filePaths +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 async 1`] = ` +"Resolved configuration object does not match schema: Error: JSON validation failed: +/lib/test/errorCases/invalidCombinedFile/config1.json + +Error: # + must NOT have additional properties: folderPaths +Error: # + must NOT have additional properties: filePaths +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 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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 async 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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": "", +} +`; + +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": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig 1`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig async 1`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig via tryLoadConfigurationFileForProject 1`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig via tryLoadConfigurationFileForProjectAsync 1`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]Configuration file \\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]Configuration file \\"/lib/test/project-referencing-rig/config/notExist.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +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 2`] = ` +Object { + "debug": "Configuration file \\"/lib/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]Configuration file \\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]Configuration file \\"/lib/test/project-referencing-rig/config/notExist.json\\" not found.[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; diff --git a/libraries/heft-config-file/src/test/complexConfigFile/plugins.schema.json b/libraries/heft-config-file/src/test/complexConfigFile/plugins.schema.json new file mode 100644 index 00000000000..801855200bf --- /dev/null +++ b/libraries/heft-config-file/src/test/complexConfigFile/plugins.schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Heft Plugins Configuration", + "description": "Defines plugins that are used by a project.", + "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" + }, + + "extends": { + "type": "string" + }, + + "plugins": { + "type": "array", + "items": { + "type": "object", + "required": ["plugin"], + "properties": { + "plugin": { + "description": "Path to the plugin package, relative to the project root.", + "type": "string", + "pattern": "[^\\\\]" + }, + + "options": { + "type": "object" + } + } + } + } + } +} diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json new file mode 100644 index 00000000000..37a1be91f2e --- /dev/null +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://schema.net/A", + + "plugins": [ + { + "plugin": "@rushstack/node-core-library" + } + ] +} diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json new file mode 100644 index 00000000000..24cc40fa261 --- /dev/null +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://schema.net/B", + + "extends": "./pluginsA.json", + + "plugins": [ + { + "plugin": "@rushstack/heft" + }, + { + "plugin": "jsonpath-plus" + } + ] +} diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json new file mode 100644 index 00000000000..9d24ea71f15 --- /dev/null +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json @@ -0,0 +1,5 @@ +{ + "$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 new file mode 100644 index 00000000000..08840447fef --- /dev/null +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsD.json @@ -0,0 +1,5 @@ +{ + "$schema": "http://schema.net/D", + + "extends": "./pluginsC.json" +} diff --git a/libraries/heft-config-file/src/test/errorCases/circularReference/config.schema.json b/libraries/heft-config-file/src/test/errorCases/circularReference/config.schema.json new file mode 100644 index 00000000000..d13f6deb34d --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/circularReference/config.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "extends": { + "type": "string" + } + } +} diff --git a/libraries/heft-config-file/src/test/errorCases/circularReference/config1.json b/libraries/heft-config-file/src/test/errorCases/circularReference/config1.json new file mode 100644 index 00000000000..d78efb6d7f9 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/circularReference/config1.json @@ -0,0 +1,3 @@ +{ + "extends": "./config2.json" +} diff --git a/libraries/heft-config-file/src/test/errorCases/circularReference/config2.json b/libraries/heft-config-file/src/test/errorCases/circularReference/config2.json new file mode 100644 index 00000000000..1cb2c69c1b1 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/circularReference/config2.json @@ -0,0 +1,3 @@ +{ + "extends": "./config3.json" +} diff --git a/libraries/heft-config-file/src/test/errorCases/circularReference/config3.json b/libraries/heft-config-file/src/test/errorCases/circularReference/config3.json new file mode 100644 index 00000000000..01626e20b9a --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/circularReference/config3.json @@ -0,0 +1,3 @@ +{ + "extends": "./config1.json" +} diff --git a/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.json b/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.json new file mode 100644 index 00000000000..d78efb6d7f9 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.json @@ -0,0 +1,3 @@ +{ + "extends": "./config2.json" +} diff --git a/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.schema.json b/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.schema.json new file mode 100644 index 00000000000..d13f6deb34d --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/extendsNotExist/config.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "extends": { + "type": "string" + } + } +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config.schema.json b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config.schema.json new file mode 100644 index 00000000000..ae78375e2ef --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config.schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + + "oneOf": [ + { + "additionalProperties": false, + "type": "object", + "properties": { + "extends": { + "type": "string" + }, + "filePaths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + + { + "additionalProperties": false, + "type": "object", + "properties": { + "extends": { + "type": "string" + }, + "folderPaths": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config1.json b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config1.json new file mode 100644 index 00000000000..e894f59181f --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config1.json @@ -0,0 +1,4 @@ +{ + "extends": "./config2.json", + "folderPaths": ["./lib"] +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config2.json b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config2.json new file mode 100644 index 00000000000..1073d5fb0e5 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidCombinedFile/config2.json @@ -0,0 +1,3 @@ +{ + "filePaths": ["value"] +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidJson/.gitattributes b/libraries/heft-config-file/src/test/errorCases/invalidJson/.gitattributes new file mode 100644 index 00000000000..81473505643 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidJson/.gitattributes @@ -0,0 +1 @@ +*.json text eol=lf \ No newline at end of file diff --git a/libraries/heft-config-file/src/test/errorCases/invalidJson/config.json b/libraries/heft-config-file/src/test/errorCases/invalidJson/config.json new file mode 100644 index 00000000000..9d97f7f9e78 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidJson/config.json @@ -0,0 +1,3 @@ +{ + "filePaths": "A +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidJson/config.schema.json b/libraries/heft-config-file/src/test/errorCases/invalidJson/config.schema.json new file mode 100644 index 00000000000..1a601eee049 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidJson/config.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "filePaths": { + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidType/config.json b/libraries/heft-config-file/src/test/errorCases/invalidType/config.json new file mode 100644 index 00000000000..c889916b2e1 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidType/config.json @@ -0,0 +1,3 @@ +{ + "filePaths": "A" +} diff --git a/libraries/heft-config-file/src/test/errorCases/invalidType/config.schema.json b/libraries/heft-config-file/src/test/errorCases/invalidType/config.schema.json new file mode 100644 index 00000000000..1a601eee049 --- /dev/null +++ b/libraries/heft-config-file/src/test/errorCases/invalidType/config.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "filePaths": { + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json new file mode 100644 index 00000000000..cf761aa0ec6 --- /dev/null +++ b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json @@ -0,0 +1,152 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Inheritance Type Configuration", + "description": "Defines an arbitrary configration file used to test inheritance", + "type": "object", + + "additionalProperties": false, + + "required": ["a", "b", "d"], + + "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" + }, + + "extends": { + "type": "string" + }, + + "a": { + "type": "string" + }, + + "b": { + "type": "array", + "items": { + "type": "object", + "required": ["c"], + "properties": { + "c": { + "type": "string" + } + } + } + }, + + "d": { + "type": "object", + "required": ["e", "f", "g", "i", "k", "o", "r"], + "properties": { + "e": { + "type": "string" + }, + + "f": { + "type": "string" + }, + + "g": { + "type": "array", + "items": { + "type": "object", + "required": ["h"], + "properties": { + "h": { + "type": "string" + } + } + } + }, + + "i": { + "type": "array", + "items": { + "type": "object", + "required": ["j"], + "properties": { + "j": { + "type": "string" + } + } + } + }, + + "k": { + "type": "object", + "required": ["l", "m"], + "properties": { + "l": { + "type": "string" + }, + "m": { + "type": "array", + "items": { + "type": "object", + "required": ["n"], + "properties": { + "n": { + "type": "string" + } + } + } + }, + "z": { + "type": "string" + } + } + }, + + "o": { + "type": "object", + "required": ["p"], + "properties": { + "p": { + "type": "array", + "items": { + "type": "object", + "required": ["q"], + "properties": { + "q": { + "type": "string" + } + } + } + } + } + }, + + "r": { + "type": "object", + "required": ["s"], + "properties": { + "s": { + "type": "string" + } + } + }, + + "y": { + "type": "object", + "required": ["z"], + "properties": { + "z": { + "type": "string" + } + } + } + } + }, + + "y": { + "type": "object", + "required": ["z"], + "properties": { + "z": { + "type": "string" + } + } + } + } +} diff --git a/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileA.json b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileA.json new file mode 100644 index 00000000000..20c60fccf61 --- /dev/null +++ b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileA.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://schema.net/", + + "a": "A", + + "b": [ + { + "c": "A" + } + ], + + "d": { + "e": "A", + + "f": "A", + + "g": [{ "h": "A" }], + + "i": [{ "j": "A" }], + + "k": { + "l": "A", + "m": [{ "n": "A" }] + }, + + "o": { + "p": [{ "q": "A" }] + }, + + "r": { + "s": "A" + } + } +} diff --git a/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileB.json b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileB.json new file mode 100644 index 00000000000..d391959250f --- /dev/null +++ b/libraries/heft-config-file/src/test/inheritanceTypeConfigFile/inheritanceTypeConfigFileB.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./inheritanceTypeConfigFileA.json", + + "$b.inheritanceType": "append", + "b": [ + { + "c": "B" + } + ], + + "$d.inheritanceType": "merge", + "d": { + "f": "B", + + "$g.inheritanceType": "append", + "g": [{ "h": "B" }], + + "$i.inheritanceType": "replace", + "i": [{ "j": "B" }], + + "$k.inheritanceType": "merge", + "k": { + "$m.inheritanceType": "append", + "m": [{ "n": "B" }], + "z": "B" + }, + + "$o.inheritanceType": "replace", + "o": { + "p": [{ "q": "B" }] + }, + + "y": { + "z": "B" + } + }, + + "y": { + "z": "B" + } +} diff --git a/libraries/heft-config-file/src/test/project-referencing-rig/.gitignore b/libraries/heft-config-file/src/test/project-referencing-rig/.gitignore new file mode 100644 index 00000000000..cf4bab9ddde --- /dev/null +++ b/libraries/heft-config-file/src/test/project-referencing-rig/.gitignore @@ -0,0 +1 @@ +!node_modules diff --git a/libraries/heft-config-file/src/test/project-referencing-rig/config/rig.json b/libraries/heft-config-file/src/test/project-referencing-rig/config/rig.json new file mode 100644 index 00000000000..c10ba9b9c7c --- /dev/null +++ b/libraries/heft-config-file/src/test/project-referencing-rig/config/rig.json @@ -0,0 +1,3 @@ +{ + "rigPackageName": "test-rig" +} diff --git a/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/package.json b/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/package.json new file mode 100644 index 00000000000..a7be54f52a1 --- /dev/null +++ b/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/package.json @@ -0,0 +1,7 @@ +{ + "name": "test-rig", + "version": "1.0.0", + "description": "", + "author": "", + "license": "ISC" +} diff --git a/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/simplestConfigFile.json b/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/simplestConfigFile.json new file mode 100644 index 00000000000..0629f5f32c3 --- /dev/null +++ b/libraries/heft-config-file/src/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/simplestConfigFile.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://schema.net/", + "thing": "A" +} diff --git a/libraries/heft-config-file/src/test/project-referencing-rig/package.json b/libraries/heft-config-file/src/test/project-referencing-rig/package.json new file mode 100644 index 00000000000..17e8dc46ab9 --- /dev/null +++ b/libraries/heft-config-file/src/test/project-referencing-rig/package.json @@ -0,0 +1,11 @@ +{ + "name": "project-referencing-rig", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "test-rig": "1.0.0" + }, + "author": "", + "license": "ISC" +} diff --git a/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json new file mode 100644 index 00000000000..4db0a32d630 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://schema.net/", + "things": ["A", "B", "C"], + "thingsObj": { + "A": { + "B": "C" + }, + "D": { + "E": "F" + } + }, + "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 new file mode 100644 index 00000000000..0c2c53a91b8 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "things": { + "type": "array", + "items": { + "type": "string" + } + }, + + "thingsObj": { + "type": "object", + "additionalProperties": true + }, + + "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 new file mode 100644 index 00000000000..5a4b4c5ce9e --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://schema.net/", + "extends": "../simpleConfigFile/simpleConfigFile.json", + + "things": ["D", "E"], + + "thingsObj": { + "A": { + "D": "E" + }, + "F": { + "G": "H" + } + }, + + "booleanProp": false, + + "stringProp": null +} diff --git a/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.schema.json b/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.schema.json new file mode 100644 index 00000000000..9ad3ccdbefc --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "extends": { + "type": "string" + }, + + "things": { + "type": "array", + "items": { + "type": "string" + } + }, + + "thingsObj": { + "type": "object", + "additionalProperties": true + }, + + "booleanProp": { + "type": "boolean" + } + } +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json new file mode 100644 index 00000000000..b6288173090 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "$a.inheritanceType": "merge", + "a": [ + { + "b": "B" + } + ] +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json new file mode 100644 index 00000000000..49cd8097686 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "$c.inheritanceType": "append", + "c": { + "d": [{ "e": "B" }] + } +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json new file mode 100644 index 00000000000..42f31760e81 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json @@ -0,0 +1,8 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "$l.inheritanceType": "replace", + "l": "B" +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json new file mode 100644 index 00000000000..076557439d5 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "$c.inheritanceType": "merge" +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json new file mode 100644 index 00000000000..ec3f9fe2f9e --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "$a.inheritanceType": "custom", + "a": [ + { + "b": "B" + } + ] +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json new file mode 100644 index 00000000000..c96567e8d56 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json @@ -0,0 +1,85 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Inheritance Type Configuration", + "description": "Defines an arbitrary configration file used to test inheritance", + "type": "object", + + "additionalProperties": false, + + "required": ["a", "c", "f", "l"], + + "properties": { + "a": { + "type": "array", + "items": { + "type": "object", + "required": ["b"], + "properties": { + "b": { + "type": "string" + } + } + } + }, + + "c": { + "type": "object", + "required": ["d"], + "properties": { + "d": { + "type": "array", + "items": { + "type": "object", + "required": ["e"], + "properties": { + "e": { + "type": "string" + } + } + } + } + } + }, + + "f": { + "type": "object", + "required": ["g", "i"], + "properties": { + "g": { + "type": "array", + "items": { + "type": "object", + "required": ["h"], + "properties": { + "h": { + "type": "string" + } + } + } + }, + + "i": { + "type": "object", + "properties": { + "j": { + "type": "array", + "items": { + "type": "object", + "required": ["k"], + "properties": { + "k": { + "type": "string" + } + } + } + } + } + } + } + }, + + "l": { + "type": "string" + } + } +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileA.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileA.json new file mode 100644 index 00000000000..c005aabed78 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileA.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://schema.net/", + + "a": [ + { + "b": "A" + } + ], + + "c": { + "d": [{ "e": "A" }] + }, + + "f": { + "g": [{ "h": "A" }], + + "i": { + "j": [{ "k": "A" }] + } + }, + + "l": "A" +} diff --git a/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileB.json b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileB.json new file mode 100644 index 00000000000..2ccae63bd71 --- /dev/null +++ b/libraries/heft-config-file/src/test/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFileB.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://schema.net/", + + "extends": "./simpleInheritanceTypeConfigFileA.json", + + "a": [ + { + "b": "B" + } + ], + + "c": { + "d": [{ "e": "B" }] + }, + + "$f.inheritanceType": "merge", + "f": { + "g": [{ "h": "B" }], + + "i": { + "j": [{ "k": "B" }] + } + } +} diff --git a/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.json b/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.json new file mode 100644 index 00000000000..0629f5f32c3 --- /dev/null +++ b/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://schema.net/", + "thing": "A" +} diff --git a/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.schema.json b/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.schema.json new file mode 100644 index 00000000000..d1017503fe0 --- /dev/null +++ b/libraries/heft-config-file/src/test/simplestConfigFile/simplestConfigFile.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "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" + }, + + "thing": { + "type": "string" + } + } +} diff --git a/libraries/heft-config-file/tsconfig.json b/libraries/heft-config-file/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/heft-config-file/tsconfig.json @@ -0,0 +1,3 @@ +{ + "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 d7953bb2a36..00000000000 --- a/libraries/load-themed-styles/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/load-themed-styles/.npmignore b/libraries/load-themed-styles/.npmignore index 197e541c32e..3ab4fe6105c 100644 --- a/libraries/load-themed-styles/.npmignore +++ b/libraries/load-themed-styles/.npmignore @@ -1,28 +1,30 @@ -# 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-amd/** -!/lib-es6/** +!/lib*/** !/dist/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* -/lib-amd/**/test/* -/lib-es6/**/test/* +/lib*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/load-themed-styles/.vscode/tasks.json b/libraries/load-themed-styles/.vscode/tasks.json index 3567ff9ad0c..225802b60e0 100644 --- a/libraries/load-themed-styles/.vscode/tasks.json +++ b/libraries/load-themed-styles/.vscode/tasks.json @@ -1,23 +1,24 @@ { - "version": "0.1.0", + "version": "2.0.0", "command": "gulp", - "isShellCommand": true, "tasks": [ { - "taskName": "build", - - "echoCommand": true, - "args": [ - ], - "isBuildCommand": true, - "showOutput": "always", - "isWatching": true + "label": "build", + "type": "gulp", + "task": "build", + "isBackground": true, + "problemMatcher": [], + "group": { + "_id": "build", + "isDefault": false + } }, { - "taskName": "watch", - "isBuildCommand": false, - "showOutput": "always", - "isWatching": true + "label": "watch", + "type": "gulp", + "task": "watch", + "isBackground": true, + "problemMatcher": [] } ] } diff --git a/libraries/load-themed-styles/CHANGELOG.json b/libraries/load-themed-styles/CHANGELOG.json index 847696d1a9f..6c9395d4430 100644 --- a/libraries/load-themed-styles/CHANGELOG.json +++ b/libraries/load-themed-styles/CHANGELOG.json @@ -1,6 +1,6409 @@ { "name": "@microsoft/load-themed-styles", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "2.0.153", + "tag": "@microsoft/load-themed-styles_v2.0.153", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "2.0.152", + "tag": "@microsoft/load-themed-styles_v2.0.152", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "2.0.151", + "tag": "@microsoft/load-themed-styles_v2.0.151", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "2.0.150", + "tag": "@microsoft/load-themed-styles_v2.0.150", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "2.0.149", + "tag": "@microsoft/load-themed-styles_v2.0.149", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "2.0.148", + "tag": "@microsoft/load-themed-styles_v2.0.148", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "2.0.147", + "tag": "@microsoft/load-themed-styles_v2.0.147", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "2.0.146", + "tag": "@microsoft/load-themed-styles_v2.0.146", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "2.0.145", + "tag": "@microsoft/load-themed-styles_v2.0.145", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "2.0.144", + "tag": "@microsoft/load-themed-styles_v2.0.144", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "2.0.143", + "tag": "@microsoft/load-themed-styles_v2.0.143", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "2.0.142", + "tag": "@microsoft/load-themed-styles_v2.0.142", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "2.0.141", + "tag": "@microsoft/load-themed-styles_v2.0.141", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "2.0.140", + "tag": "@microsoft/load-themed-styles_v2.0.140", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "2.0.139", + "tag": "@microsoft/load-themed-styles_v2.0.139", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "2.0.138", + "tag": "@microsoft/load-themed-styles_v2.0.138", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "2.0.137", + "tag": "@microsoft/load-themed-styles_v2.0.137", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "2.0.136", + "tag": "@microsoft/load-themed-styles_v2.0.136", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "2.0.135", + "tag": "@microsoft/load-themed-styles_v2.0.135", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "2.0.134", + "tag": "@microsoft/load-themed-styles_v2.0.134", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "2.0.133", + "tag": "@microsoft/load-themed-styles_v2.0.133", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "2.0.132", + "tag": "@microsoft/load-themed-styles_v2.0.132", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "2.0.131", + "tag": "@microsoft/load-themed-styles_v2.0.131", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "2.0.130", + "tag": "@microsoft/load-themed-styles_v2.0.130", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "2.0.129", + "tag": "@microsoft/load-themed-styles_v2.0.129", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "2.0.128", + "tag": "@microsoft/load-themed-styles_v2.0.128", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "2.0.127", + "tag": "@microsoft/load-themed-styles_v2.0.127", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "2.0.126", + "tag": "@microsoft/load-themed-styles_v2.0.126", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "2.0.125", + "tag": "@microsoft/load-themed-styles_v2.0.125", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "2.0.124", + "tag": "@microsoft/load-themed-styles_v2.0.124", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "2.0.123", + "tag": "@microsoft/load-themed-styles_v2.0.123", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "2.0.122", + "tag": "@microsoft/load-themed-styles_v2.0.122", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "2.0.121", + "tag": "@microsoft/load-themed-styles_v2.0.121", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "2.0.120", + "tag": "@microsoft/load-themed-styles_v2.0.120", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "2.0.119", + "tag": "@microsoft/load-themed-styles_v2.0.119", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "2.0.118", + "tag": "@microsoft/load-themed-styles_v2.0.118", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "2.0.117", + "tag": "@microsoft/load-themed-styles_v2.0.117", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "2.0.116", + "tag": "@microsoft/load-themed-styles_v2.0.116", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "2.0.115", + "tag": "@microsoft/load-themed-styles_v2.0.115", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "2.0.114", + "tag": "@microsoft/load-themed-styles_v2.0.114", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "2.0.113", + "tag": "@microsoft/load-themed-styles_v2.0.113", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "2.0.112", + "tag": "@microsoft/load-themed-styles_v2.0.112", + "date": "Sun, 03 Mar 2024 20:58:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "2.0.111", + "tag": "@microsoft/load-themed-styles_v2.0.111", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "2.0.110", + "tag": "@microsoft/load-themed-styles_v2.0.110", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "2.0.109", + "tag": "@microsoft/load-themed-styles_v2.0.109", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "2.0.108", + "tag": "@microsoft/load-themed-styles_v2.0.108", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "2.0.107", + "tag": "@microsoft/load-themed-styles_v2.0.107", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "2.0.106", + "tag": "@microsoft/load-themed-styles_v2.0.106", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "2.0.105", + "tag": "@microsoft/load-themed-styles_v2.0.105", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "2.0.104", + "tag": "@microsoft/load-themed-styles_v2.0.104", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "2.0.103", + "tag": "@microsoft/load-themed-styles_v2.0.103", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "2.0.102", + "tag": "@microsoft/load-themed-styles_v2.0.102", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "2.0.101", + "tag": "@microsoft/load-themed-styles_v2.0.101", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "2.0.100", + "tag": "@microsoft/load-themed-styles_v2.0.100", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "2.0.99", + "tag": "@microsoft/load-themed-styles_v2.0.99", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "2.0.98", + "tag": "@microsoft/load-themed-styles_v2.0.98", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "2.0.97", + "tag": "@microsoft/load-themed-styles_v2.0.97", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "2.0.96", + "tag": "@microsoft/load-themed-styles_v2.0.96", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "2.0.95", + "tag": "@microsoft/load-themed-styles_v2.0.95", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "2.0.94", + "tag": "@microsoft/load-themed-styles_v2.0.94", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "2.0.93", + "tag": "@microsoft/load-themed-styles_v2.0.93", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "2.0.92", + "tag": "@microsoft/load-themed-styles_v2.0.92", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "2.0.91", + "tag": "@microsoft/load-themed-styles_v2.0.91", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "2.0.90", + "tag": "@microsoft/load-themed-styles_v2.0.90", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "2.0.89", + "tag": "@microsoft/load-themed-styles_v2.0.89", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "2.0.88", + "tag": "@microsoft/load-themed-styles_v2.0.88", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "2.0.87", + "tag": "@microsoft/load-themed-styles_v2.0.87", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "2.0.86", + "tag": "@microsoft/load-themed-styles_v2.0.86", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "2.0.85", + "tag": "@microsoft/load-themed-styles_v2.0.85", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "2.0.84", + "tag": "@microsoft/load-themed-styles_v2.0.84", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "2.0.83", + "tag": "@microsoft/load-themed-styles_v2.0.83", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "2.0.82", + "tag": "@microsoft/load-themed-styles_v2.0.82", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "2.0.81", + "tag": "@microsoft/load-themed-styles_v2.0.81", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "2.0.80", + "tag": "@microsoft/load-themed-styles_v2.0.80", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "2.0.79", + "tag": "@microsoft/load-themed-styles_v2.0.79", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "2.0.78", + "tag": "@microsoft/load-themed-styles_v2.0.78", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "2.0.77", + "tag": "@microsoft/load-themed-styles_v2.0.77", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.28`" + } + ] + } + }, + { + "version": "2.0.76", + "tag": "@microsoft/load-themed-styles_v2.0.76", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.27`" + } + ] + } + }, + { + "version": "2.0.75", + "tag": "@microsoft/load-themed-styles_v2.0.75", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.26`" + } + ] + } + }, + { + "version": "2.0.74", + "tag": "@microsoft/load-themed-styles_v2.0.74", + "date": "Fri, 01 Sep 2023 04:53:58 GMT", + "comments": { + "patch": [ + { + "comment": "Use self.setTimeout() instead of setTimeout() to work around a Jest regression" + } + ] + } + }, + { + "version": "2.0.73", + "tag": "@microsoft/load-themed-styles_v2.0.73", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.25`" + } + ] + } + }, + { + "version": "2.0.72", + "tag": "@microsoft/load-themed-styles_v2.0.72", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.24`" + } + ] + } + }, + { + "version": "2.0.71", + "tag": "@microsoft/load-themed-styles_v2.0.71", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.23`" + } + ] + } + }, + { + "version": "2.0.70", + "tag": "@microsoft/load-themed-styles_v2.0.70", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.22`" + } + ] + } + }, + { + "version": "2.0.69", + "tag": "@microsoft/load-themed-styles_v2.0.69", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.21`" + } + ] + } + }, + { + "version": "2.0.68", + "tag": "@microsoft/load-themed-styles_v2.0.68", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.20`" + } + ] + } + }, + { + "version": "2.0.67", + "tag": "@microsoft/load-themed-styles_v2.0.67", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.19`" + } + ] + } + }, + { + "version": "2.0.66", + "tag": "@microsoft/load-themed-styles_v2.0.66", + "date": "Mon, 17 Jul 2023 15:20:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.18`" + } + ] + } + }, + { + "version": "2.0.65", + "tag": "@microsoft/load-themed-styles_v2.0.65", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.17`" + } + ] + } + }, + { + "version": "2.0.64", + "tag": "@microsoft/load-themed-styles_v2.0.64", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.16`" + } + ] + } + }, + { + "version": "2.0.63", + "tag": "@microsoft/load-themed-styles_v2.0.63", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.15`" + } + ] + } + }, + { + "version": "2.0.62", + "tag": "@microsoft/load-themed-styles_v2.0.62", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.14`" + } + ] + } + }, + { + "version": "2.0.61", + "tag": "@microsoft/load-themed-styles_v2.0.61", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.13`" + } + ] + } + }, + { + "version": "2.0.60", + "tag": "@microsoft/load-themed-styles_v2.0.60", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.12`" + } + ] + } + }, + { + "version": "2.0.59", + "tag": "@microsoft/load-themed-styles_v2.0.59", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.11`" + } + ] + } + }, + { + "version": "2.0.58", + "tag": "@microsoft/load-themed-styles_v2.0.58", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.10`" + } + ] + } + }, + { + "version": "2.0.57", + "tag": "@microsoft/load-themed-styles_v2.0.57", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.9`" + } + ] + } + }, + { + "version": "2.0.56", + "tag": "@microsoft/load-themed-styles_v2.0.56", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.8`" + } + ] + } + }, + { + "version": "2.0.55", + "tag": "@microsoft/load-themed-styles_v2.0.55", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.7`" + } + ] + } + }, + { + "version": "2.0.54", + "tag": "@microsoft/load-themed-styles_v2.0.54", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.6`" + } + ] + } + }, + { + "version": "2.0.53", + "tag": "@microsoft/load-themed-styles_v2.0.53", + "date": "Fri, 09 Jun 2023 18:05:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.5`" + } + ] + } + }, + { + "version": "2.0.52", + "tag": "@microsoft/load-themed-styles_v2.0.52", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.4`" + } + ] + } + }, + { + "version": "2.0.51", + "tag": "@microsoft/load-themed-styles_v2.0.51", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.3`" + } + ] + } + }, + { + "version": "2.0.50", + "tag": "@microsoft/load-themed-styles_v2.0.50", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.2`" + } + ] + } + }, + { + "version": "2.0.49", + "tag": "@microsoft/load-themed-styles_v2.0.49", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.1`" + } + ] + } + }, + { + "version": "2.0.48", + "tag": "@microsoft/load-themed-styles_v2.0.48", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.18.0`" + } + ] + } + }, + { + "version": "2.0.47", + "tag": "@microsoft/load-themed-styles_v2.0.47", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.17.0`" + } + ] + } + }, + { + "version": "2.0.46", + "tag": "@microsoft/load-themed-styles_v2.0.46", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.16.1`" + } + ] + } + }, + { + "version": "2.0.45", + "tag": "@microsoft/load-themed-styles_v2.0.45", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.16.0`" + } + ] + } + }, + { + "version": "2.0.44", + "tag": "@microsoft/load-themed-styles_v2.0.44", + "date": "Fri, 02 Jun 2023 00:24:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.15.2`" + } + ] + } + }, + { + "version": "2.0.43", + "tag": "@microsoft/load-themed-styles_v2.0.43", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.15.1`" + } + ] + } + }, + { + "version": "2.0.42", + "tag": "@microsoft/load-themed-styles_v2.0.42", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.15.0`" + } + ] + } + }, + { + "version": "2.0.41", + "tag": "@microsoft/load-themed-styles_v2.0.41", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.17`" + } + ] + } + }, + { + "version": "2.0.40", + "tag": "@microsoft/load-themed-styles_v2.0.40", + "date": "Thu, 11 May 2023 00:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.16`" + } + ] + } + }, + { + "version": "2.0.39", + "tag": "@microsoft/load-themed-styles_v2.0.39", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.15`" + } + ] + } + }, + { + "version": "2.0.38", + "tag": "@microsoft/load-themed-styles_v2.0.38", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.14`" + } + ] + } + }, + { + "version": "2.0.37", + "tag": "@microsoft/load-themed-styles_v2.0.37", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.13`" + } + ] + } + }, + { + "version": "2.0.36", + "tag": "@microsoft/load-themed-styles_v2.0.36", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.12`" + } + ] + } + }, + { + "version": "2.0.35", + "tag": "@microsoft/load-themed-styles_v2.0.35", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.11`" + } + ] + } + }, + { + "version": "2.0.34", + "tag": "@microsoft/load-themed-styles_v2.0.34", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.10`" + } + ] + } + }, + { + "version": "2.0.33", + "tag": "@microsoft/load-themed-styles_v2.0.33", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.9`" + } + ] + } + }, + { + "version": "2.0.32", + "tag": "@microsoft/load-themed-styles_v2.0.32", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.8`" + } + ] + } + }, + { + "version": "2.0.31", + "tag": "@microsoft/load-themed-styles_v2.0.31", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.7`" + } + ] + } + }, + { + "version": "2.0.30", + "tag": "@microsoft/load-themed-styles_v2.0.30", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.6`" + } + ] + } + }, + { + "version": "2.0.29", + "tag": "@microsoft/load-themed-styles_v2.0.29", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.5`" + } + ] + } + }, + { + "version": "2.0.28", + "tag": "@microsoft/load-themed-styles_v2.0.28", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.4`" + } + ] + } + }, + { + "version": "2.0.27", + "tag": "@microsoft/load-themed-styles_v2.0.27", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.3`" + } + ] + } + }, + { + "version": "2.0.26", + "tag": "@microsoft/load-themed-styles_v2.0.26", + "date": "Tue, 31 Jan 2023 01:23:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.2`" + } + ] + } + }, + { + "version": "2.0.25", + "tag": "@microsoft/load-themed-styles_v2.0.25", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.1`" + } + ] + } + }, + { + "version": "2.0.24", + "tag": "@microsoft/load-themed-styles_v2.0.24", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.14.0`" + } + ] + } + }, + { + "version": "2.0.23", + "tag": "@microsoft/load-themed-styles_v2.0.23", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.13.2`" + } + ] + } + }, + { + "version": "2.0.22", + "tag": "@microsoft/load-themed-styles_v2.0.22", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.13.1`" + } + ] + } + }, + { + "version": "2.0.21", + "tag": "@microsoft/load-themed-styles_v2.0.21", + "date": "Sun, 22 Jan 2023 20:37:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.13.0`" + } + ] + } + }, + { + "version": "2.0.20", + "tag": "@microsoft/load-themed-styles_v2.0.20", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.17`" + } + ] + } + }, + { + "version": "2.0.19", + "tag": "@microsoft/load-themed-styles_v2.0.19", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.16`" + } + ] + } + }, + { + "version": "2.0.18", + "tag": "@microsoft/load-themed-styles_v2.0.18", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.15`" + } + ] + } + }, + { + "version": "2.0.17", + "tag": "@microsoft/load-themed-styles_v2.0.17", + "date": "Fri, 02 Dec 2022 01:15:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.14`" + } + ] + } + }, + { + "version": "2.0.16", + "tag": "@microsoft/load-themed-styles_v2.0.16", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.13`" + } + ] + } + }, + { + "version": "2.0.15", + "tag": "@microsoft/load-themed-styles_v2.0.15", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.12`" + } + ] + } + }, + { + "version": "2.0.14", + "tag": "@microsoft/load-themed-styles_v2.0.14", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.11`" + } + ] + } + }, + { + "version": "2.0.13", + "tag": "@microsoft/load-themed-styles_v2.0.13", + "date": "Wed, 26 Oct 2022 15:16:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.10`" + } + ] + } + }, + { + "version": "2.0.12", + "tag": "@microsoft/load-themed-styles_v2.0.12", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.9`" + } + ] + } + }, + { + "version": "2.0.11", + "tag": "@microsoft/load-themed-styles_v2.0.11", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.8`" + } + ] + } + }, + { + "version": "2.0.10", + "tag": "@microsoft/load-themed-styles_v2.0.10", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.7`" + } + ] + } + }, + { + "version": "2.0.9", + "tag": "@microsoft/load-themed-styles_v2.0.9", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.6`" + } + ] + } + }, + { + "version": "2.0.8", + "tag": "@microsoft/load-themed-styles_v2.0.8", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.5`" + } + ] + } + }, + { + "version": "2.0.7", + "tag": "@microsoft/load-themed-styles_v2.0.7", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.4`" + } + ] + } + }, + { + "version": "2.0.6", + "tag": "@microsoft/load-themed-styles_v2.0.6", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.3`" + } + ] + } + }, + { + "version": "2.0.5", + "tag": "@microsoft/load-themed-styles_v2.0.5", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.2`" + } + ] + } + }, + { + "version": "2.0.4", + "tag": "@microsoft/load-themed-styles_v2.0.4", + "date": "Sat, 08 Oct 2022 02:30:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.1`" + } + ] + } + }, + { + "version": "2.0.3", + "tag": "@microsoft/load-themed-styles_v2.0.3", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.12.0`" + } + ] + } + }, + { + "version": "2.0.2", + "tag": "@microsoft/load-themed-styles_v2.0.2", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.13`" + } + ] + } + }, + { + "version": "2.0.1", + "tag": "@microsoft/load-themed-styles_v2.0.1", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.12`" + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@microsoft/load-themed-styles_v2.0.0", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "major": [ + { + "comment": "Switch compilation target to ES2017" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.11`" + } + ] + } + }, + { + "version": "1.10.295", + "tag": "@microsoft/load-themed-styles_v1.10.295", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.10`" + } + ] + } + }, + { + "version": "1.10.294", + "tag": "@microsoft/load-themed-styles_v1.10.294", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.9`" + } + ] + } + }, + { + "version": "1.10.293", + "tag": "@microsoft/load-themed-styles_v1.10.293", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.8`" + } + ] + } + }, + { + "version": "1.10.292", + "tag": "@microsoft/load-themed-styles_v1.10.292", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.7`" + } + ] + } + }, + { + "version": "1.10.291", + "tag": "@microsoft/load-themed-styles_v1.10.291", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.6`" + } + ] + } + }, + { + "version": "1.10.290", + "tag": "@microsoft/load-themed-styles_v1.10.290", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.5`" + } + ] + } + }, + { + "version": "1.10.289", + "tag": "@microsoft/load-themed-styles_v1.10.289", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.4`" + } + ] + } + }, + { + "version": "1.10.288", + "tag": "@microsoft/load-themed-styles_v1.10.288", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.3`" + } + ] + } + }, + { + "version": "1.10.287", + "tag": "@microsoft/load-themed-styles_v1.10.287", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.2`" + } + ] + } + }, + { + "version": "1.10.286", + "tag": "@microsoft/load-themed-styles_v1.10.286", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.1`" + } + ] + } + }, + { + "version": "1.10.285", + "tag": "@microsoft/load-themed-styles_v1.10.285", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.11.0`" + } + ] + } + }, + { + "version": "1.10.284", + "tag": "@microsoft/load-themed-styles_v1.10.284", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.25`" + } + ] + } + }, + { + "version": "1.10.283", + "tag": "@microsoft/load-themed-styles_v1.10.283", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.24`" + } + ] + } + }, + { + "version": "1.10.282", + "tag": "@microsoft/load-themed-styles_v1.10.282", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.23`" + } + ] + } + }, + { + "version": "1.10.281", + "tag": "@microsoft/load-themed-styles_v1.10.281", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.22`" + } + ] + } + }, + { + "version": "1.10.280", + "tag": "@microsoft/load-themed-styles_v1.10.280", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.21`" + } + ] + } + }, + { + "version": "1.10.279", + "tag": "@microsoft/load-themed-styles_v1.10.279", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.20`" + } + ] + } + }, + { + "version": "1.10.278", + "tag": "@microsoft/load-themed-styles_v1.10.278", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.19`" + } + ] + } + }, + { + "version": "1.10.277", + "tag": "@microsoft/load-themed-styles_v1.10.277", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.18`" + } + ] + } + }, + { + "version": "1.10.276", + "tag": "@microsoft/load-themed-styles_v1.10.276", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.17`" + } + ] + } + }, + { + "version": "1.10.275", + "tag": "@microsoft/load-themed-styles_v1.10.275", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.16`" + } + ] + } + }, + { + "version": "1.10.274", + "tag": "@microsoft/load-themed-styles_v1.10.274", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.15`" + } + ] + } + }, + { + "version": "1.10.273", + "tag": "@microsoft/load-themed-styles_v1.10.273", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.14`" + } + ] + } + }, + { + "version": "1.10.272", + "tag": "@microsoft/load-themed-styles_v1.10.272", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.13`" + } + ] + } + }, + { + "version": "1.10.271", + "tag": "@microsoft/load-themed-styles_v1.10.271", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.12`" + } + ] + } + }, + { + "version": "1.10.270", + "tag": "@microsoft/load-themed-styles_v1.10.270", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.11`" + } + ] + } + }, + { + "version": "1.10.269", + "tag": "@microsoft/load-themed-styles_v1.10.269", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.10`" + } + ] + } + }, + { + "version": "1.10.268", + "tag": "@microsoft/load-themed-styles_v1.10.268", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.9`" + } + ] + } + }, + { + "version": "1.10.267", + "tag": "@microsoft/load-themed-styles_v1.10.267", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.8`" + } + ] + } + }, + { + "version": "1.10.266", + "tag": "@microsoft/load-themed-styles_v1.10.266", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.7`" + } + ] + } + }, + { + "version": "1.10.265", + "tag": "@microsoft/load-themed-styles_v1.10.265", + "date": "Wed, 18 May 2022 15:10:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.6`" + } + ] + } + }, + { + "version": "1.10.264", + "tag": "@microsoft/load-themed-styles_v1.10.264", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.5`" + } + ] + } + }, + { + "version": "1.10.263", + "tag": "@microsoft/load-themed-styles_v1.10.263", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.4`" + } + ] + } + }, + { + "version": "1.10.262", + "tag": "@microsoft/load-themed-styles_v1.10.262", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.3`" + } + ] + } + }, + { + "version": "1.10.261", + "tag": "@microsoft/load-themed-styles_v1.10.261", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.2`" + } + ] + } + }, + { + "version": "1.10.260", + "tag": "@microsoft/load-themed-styles_v1.10.260", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.1`" + } + ] + } + }, + { + "version": "1.10.259", + "tag": "@microsoft/load-themed-styles_v1.10.259", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.10.0`" + } + ] + } + }, + { + "version": "1.10.258", + "tag": "@microsoft/load-themed-styles_v1.10.258", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.11`" + } + ] + } + }, + { + "version": "1.10.257", + "tag": "@microsoft/load-themed-styles_v1.10.257", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.10`" + } + ] + } + }, + { + "version": "1.10.256", + "tag": "@microsoft/load-themed-styles_v1.10.256", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.9`" + } + ] + } + }, + { + "version": "1.10.255", + "tag": "@microsoft/load-themed-styles_v1.10.255", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.8`" + } + ] + } + }, + { + "version": "1.10.254", + "tag": "@microsoft/load-themed-styles_v1.10.254", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.7`" + } + ] + } + }, + { + "version": "1.10.253", + "tag": "@microsoft/load-themed-styles_v1.10.253", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.6`" + } + ] + } + }, + { + "version": "1.10.252", + "tag": "@microsoft/load-themed-styles_v1.10.252", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.5`" + } + ] + } + }, + { + "version": "1.10.251", + "tag": "@microsoft/load-themed-styles_v1.10.251", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.4`" + } + ] + } + }, + { + "version": "1.10.250", + "tag": "@microsoft/load-themed-styles_v1.10.250", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.3`" + } + ] + } + }, + { + "version": "1.10.249", + "tag": "@microsoft/load-themed-styles_v1.10.249", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.2`" + } + ] + } + }, + { + "version": "1.10.248", + "tag": "@microsoft/load-themed-styles_v1.10.248", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.1`" + } + ] + } + }, + { + "version": "1.10.247", + "tag": "@microsoft/load-themed-styles_v1.10.247", + "date": "Tue, 15 Feb 2022 01:39:45 GMT", + "comments": { + "patch": [ + { + "comment": "Do not import TS helpers." + } + ] + } + }, + { + "version": "1.10.246", + "tag": "@microsoft/load-themed-styles_v1.10.246", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "patch": [ + { + "comment": "Enable importHelpers=true" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.9.0`" + } + ] + } + }, + { + "version": "1.10.245", + "tag": "@microsoft/load-themed-styles_v1.10.245", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.8.2`" + } + ] + } + }, + { + "version": "1.10.244", + "tag": "@microsoft/load-themed-styles_v1.10.244", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.8.1`" + } + ] + } + }, + { + "version": "1.10.243", + "tag": "@microsoft/load-themed-styles_v1.10.243", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.8.0`" + } + ] + } + }, + { + "version": "1.10.242", + "tag": "@microsoft/load-themed-styles_v1.10.242", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.7.2`" + } + ] + } + }, + { + "version": "1.10.241", + "tag": "@microsoft/load-themed-styles_v1.10.241", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.7.1`" + } + ] + } + }, + { + "version": "1.10.240", + "tag": "@microsoft/load-themed-styles_v1.10.240", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.7.0`" + } + ] + } + }, + { + "version": "1.10.239", + "tag": "@microsoft/load-themed-styles_v1.10.239", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.6.4`" + } + ] + } + }, + { + "version": "1.10.238", + "tag": "@microsoft/load-themed-styles_v1.10.238", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.6.3`" + } + ] + } + }, + { + "version": "1.10.237", + "tag": "@microsoft/load-themed-styles_v1.10.237", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.6.2`" + } + ] + } + }, + { + "version": "1.10.236", + "tag": "@microsoft/load-themed-styles_v1.10.236", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.6.1`" + } + ] + } + }, + { + "version": "1.10.235", + "tag": "@microsoft/load-themed-styles_v1.10.235", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.6.0`" + } + ] + } + }, + { + "version": "1.10.234", + "tag": "@microsoft/load-themed-styles_v1.10.234", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.10.233", + "tag": "@microsoft/load-themed-styles_v1.10.233", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.34`" + } + ] + } + }, + { + "version": "1.10.232", + "tag": "@microsoft/load-themed-styles_v1.10.232", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.33`" + } + ] + } + }, + { + "version": "1.10.231", + "tag": "@microsoft/load-themed-styles_v1.10.231", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.32`" + } + ] + } + }, + { + "version": "1.10.230", + "tag": "@microsoft/load-themed-styles_v1.10.230", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.31`" + } + ] + } + }, + { + "version": "1.10.229", + "tag": "@microsoft/load-themed-styles_v1.10.229", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.30`" + } + ] + } + }, + { + "version": "1.10.228", + "tag": "@microsoft/load-themed-styles_v1.10.228", + "date": "Thu, 28 Oct 2021 23:48:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.29`" + } + ] + } + }, + { + "version": "1.10.227", + "tag": "@microsoft/load-themed-styles_v1.10.227", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.28`" + } + ] + } + }, + { + "version": "1.10.226", + "tag": "@microsoft/load-themed-styles_v1.10.226", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.27`" + } + ] + } + }, + { + "version": "1.10.225", + "tag": "@microsoft/load-themed-styles_v1.10.225", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.26`" + } + ] + } + }, + { + "version": "1.10.224", + "tag": "@microsoft/load-themed-styles_v1.10.224", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.25`" + } + ] + } + }, + { + "version": "1.10.223", + "tag": "@microsoft/load-themed-styles_v1.10.223", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.24`" + } + ] + } + }, + { + "version": "1.10.222", + "tag": "@microsoft/load-themed-styles_v1.10.222", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.23`" + } + ] + } + }, + { + "version": "1.10.221", + "tag": "@microsoft/load-themed-styles_v1.10.221", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.22`" + } + ] + } + }, + { + "version": "1.10.220", + "tag": "@microsoft/load-themed-styles_v1.10.220", + "date": "Wed, 06 Oct 2021 15:08:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.21`" + } + ] + } + }, + { + "version": "1.10.219", + "tag": "@microsoft/load-themed-styles_v1.10.219", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.20`" + } + ] + } + }, + { + "version": "1.10.218", + "tag": "@microsoft/load-themed-styles_v1.10.218", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.19`" + } + ] + } + }, + { + "version": "1.10.217", + "tag": "@microsoft/load-themed-styles_v1.10.217", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.18`" + } + ] + } + }, + { + "version": "1.10.216", + "tag": "@microsoft/load-themed-styles_v1.10.216", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.17`" + } + ] + } + }, + { + "version": "1.10.215", + "tag": "@microsoft/load-themed-styles_v1.10.215", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.16`" + } + ] + } + }, + { + "version": "1.10.214", + "tag": "@microsoft/load-themed-styles_v1.10.214", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.15`" + } + ] + } + }, + { + "version": "1.10.213", + "tag": "@microsoft/load-themed-styles_v1.10.213", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.14`" + } + ] + } + }, + { + "version": "1.10.212", + "tag": "@microsoft/load-themed-styles_v1.10.212", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.13`" + } + ] + } + }, + { + "version": "1.10.211", + "tag": "@microsoft/load-themed-styles_v1.10.211", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.12`" + } + ] + } + }, + { + "version": "1.10.210", + "tag": "@microsoft/load-themed-styles_v1.10.210", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.11`" + } + ] + } + }, + { + "version": "1.10.209", + "tag": "@microsoft/load-themed-styles_v1.10.209", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.10`" + } + ] + } + }, + { + "version": "1.10.208", + "tag": "@microsoft/load-themed-styles_v1.10.208", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.9`" + } + ] + } + }, + { + "version": "1.10.207", + "tag": "@microsoft/load-themed-styles_v1.10.207", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.8`" + } + ] + } + }, + { + "version": "1.10.206", + "tag": "@microsoft/load-themed-styles_v1.10.206", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.7`" + } + ] + } + }, + { + "version": "1.10.205", + "tag": "@microsoft/load-themed-styles_v1.10.205", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.6`" + } + ] + } + }, + { + "version": "1.10.204", + "tag": "@microsoft/load-themed-styles_v1.10.204", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.5`" + } + ] + } + }, + { + "version": "1.10.203", + "tag": "@microsoft/load-themed-styles_v1.10.203", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.4`" + } + ] + } + }, + { + "version": "1.10.202", + "tag": "@microsoft/load-themed-styles_v1.10.202", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.3`" + } + ] + } + }, + { + "version": "1.10.201", + "tag": "@microsoft/load-themed-styles_v1.10.201", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.2`" + } + ] + } + }, + { + "version": "1.10.200", + "tag": "@microsoft/load-themed-styles_v1.10.200", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.1`" + } + ] + } + }, + { + "version": "1.10.199", + "tag": "@microsoft/load-themed-styles_v1.10.199", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.4.0`" + } + ] + } + }, + { + "version": "1.10.198", + "tag": "@microsoft/load-themed-styles_v1.10.198", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.16`" + } + ] + } + }, + { + "version": "1.10.197", + "tag": "@microsoft/load-themed-styles_v1.10.197", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.15`" + } + ] + } + }, + { + "version": "1.10.196", + "tag": "@microsoft/load-themed-styles_v1.10.196", + "date": "Tue, 27 Jul 2021 22:31:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.14`" + } + ] + } + }, + { + "version": "1.10.195", + "tag": "@microsoft/load-themed-styles_v1.10.195", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.13`" + } + ] + } + }, + { + "version": "1.10.194", + "tag": "@microsoft/load-themed-styles_v1.10.194", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.12`" + } + ] + } + }, + { + "version": "1.10.193", + "tag": "@microsoft/load-themed-styles_v1.10.193", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.11`" + } + ] + } + }, + { + "version": "1.10.192", + "tag": "@microsoft/load-themed-styles_v1.10.192", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.10`" + } + ] + } + }, + { + "version": "1.10.191", + "tag": "@microsoft/load-themed-styles_v1.10.191", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.9`" + } + ] + } + }, + { + "version": "1.10.190", + "tag": "@microsoft/load-themed-styles_v1.10.190", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.8`" + } + ] + } + }, + { + "version": "1.10.189", + "tag": "@microsoft/load-themed-styles_v1.10.189", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.7`" + } + ] + } + }, + { + "version": "1.10.188", + "tag": "@microsoft/load-themed-styles_v1.10.188", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.6`" + } + ] + } + }, + { + "version": "1.10.187", + "tag": "@microsoft/load-themed-styles_v1.10.187", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.5`" + } + ] + } + }, + { + "version": "1.10.186", + "tag": "@microsoft/load-themed-styles_v1.10.186", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.4`" + } + ] + } + }, + { + "version": "1.10.185", + "tag": "@microsoft/load-themed-styles_v1.10.185", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.3`" + } + ] + } + }, + { + "version": "1.10.184", + "tag": "@microsoft/load-themed-styles_v1.10.184", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.2`" + } + ] + } + }, + { + "version": "1.10.183", + "tag": "@microsoft/load-themed-styles_v1.10.183", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.1`" + } + ] + } + }, + { + "version": "1.10.182", + "tag": "@microsoft/load-themed-styles_v1.10.182", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.3.0`" + } + ] + } + }, + { + "version": "1.10.181", + "tag": "@microsoft/load-themed-styles_v1.10.181", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.38`" + } + ] + } + }, + { + "version": "1.10.180", + "tag": "@microsoft/load-themed-styles_v1.10.180", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.37`" + } + ] + } + }, + { + "version": "1.10.179", + "tag": "@microsoft/load-themed-styles_v1.10.179", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.36`" + } + ] + } + }, + { + "version": "1.10.178", + "tag": "@microsoft/load-themed-styles_v1.10.178", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.35`" + } + ] + } + }, + { + "version": "1.10.177", + "tag": "@microsoft/load-themed-styles_v1.10.177", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.34`" + } + ] + } + }, + { + "version": "1.10.176", + "tag": "@microsoft/load-themed-styles_v1.10.176", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.33`" + } + ] + } + }, + { + "version": "1.10.175", + "tag": "@microsoft/load-themed-styles_v1.10.175", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.32`" + } + ] + } + }, + { + "version": "1.10.174", + "tag": "@microsoft/load-themed-styles_v1.10.174", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.31`" + } + ] + } + }, + { + "version": "1.10.173", + "tag": "@microsoft/load-themed-styles_v1.10.173", + "date": "Fri, 28 May 2021 06:19:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.30`" + } + ] + } + }, + { + "version": "1.10.172", + "tag": "@microsoft/load-themed-styles_v1.10.172", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.29`" + } + ] + } + }, + { + "version": "1.10.171", + "tag": "@microsoft/load-themed-styles_v1.10.171", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.28`" + } + ] + } + }, + { + "version": "1.10.170", + "tag": "@microsoft/load-themed-styles_v1.10.170", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.27`" + } + ] + } + }, + { + "version": "1.10.169", + "tag": "@microsoft/load-themed-styles_v1.10.169", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.26`" + } + ] + } + }, + { + "version": "1.10.168", + "tag": "@microsoft/load-themed-styles_v1.10.168", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.25`" + } + ] + } + }, + { + "version": "1.10.167", + "tag": "@microsoft/load-themed-styles_v1.10.167", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.24`" + } + ] + } + }, + { + "version": "1.10.166", + "tag": "@microsoft/load-themed-styles_v1.10.166", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.23`" + } + ] + } + }, + { + "version": "1.10.165", + "tag": "@microsoft/load-themed-styles_v1.10.165", + "date": "Fri, 23 Apr 2021 22:00:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.22`" + } + ] + } + }, + { + "version": "1.10.164", + "tag": "@microsoft/load-themed-styles_v1.10.164", + "date": "Fri, 23 Apr 2021 15:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.21`" + } + ] + } + }, + { + "version": "1.10.163", + "tag": "@microsoft/load-themed-styles_v1.10.163", + "date": "Wed, 21 Apr 2021 15:12:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.20`" + } + ] + } + }, + { + "version": "1.10.162", + "tag": "@microsoft/load-themed-styles_v1.10.162", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.19`" + } + ] + } + }, + { + "version": "1.10.161", + "tag": "@microsoft/load-themed-styles_v1.10.161", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.18`" + } + ] + } + }, + { + "version": "1.10.160", + "tag": "@microsoft/load-themed-styles_v1.10.160", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.17`" + } + ] + } + }, + { + "version": "1.10.159", + "tag": "@microsoft/load-themed-styles_v1.10.159", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.16`" + } + ] + } + }, + { + "version": "1.10.158", + "tag": "@microsoft/load-themed-styles_v1.10.158", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.15`" + } + ] + } + }, + { + "version": "1.10.157", + "tag": "@microsoft/load-themed-styles_v1.10.157", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.14`" + } + ] + } + }, + { + "version": "1.10.156", + "tag": "@microsoft/load-themed-styles_v1.10.156", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.13`" + } + ] + } + }, + { + "version": "1.10.155", + "tag": "@microsoft/load-themed-styles_v1.10.155", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.12`" + } + ] + } + }, + { + "version": "1.10.154", + "tag": "@microsoft/load-themed-styles_v1.10.154", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.11`" + } + ] + } + }, + { + "version": "1.10.153", + "tag": "@microsoft/load-themed-styles_v1.10.153", + "date": "Fri, 19 Mar 2021 22:31:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.10`" + } + ] + } + }, + { + "version": "1.10.152", + "tag": "@microsoft/load-themed-styles_v1.10.152", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.9`" + } + ] + } + }, + { + "version": "1.10.151", + "tag": "@microsoft/load-themed-styles_v1.10.151", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.8`" + } + ] + } + }, + { + "version": "1.10.150", + "tag": "@microsoft/load-themed-styles_v1.10.150", + "date": "Wed, 10 Mar 2021 05:10:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.10.149", + "tag": "@microsoft/load-themed-styles_v1.10.149", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "1.10.148", + "tag": "@microsoft/load-themed-styles_v1.10.148", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "1.10.147", + "tag": "@microsoft/load-themed-styles_v1.10.147", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "1.10.146", + "tag": "@microsoft/load-themed-styles_v1.10.146", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "1.10.145", + "tag": "@microsoft/load-themed-styles_v1.10.145", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "1.10.144", + "tag": "@microsoft/load-themed-styles_v1.10.144", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "1.10.143", + "tag": "@microsoft/load-themed-styles_v1.10.143", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "1.10.142", + "tag": "@microsoft/load-themed-styles_v1.10.142", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "1.10.141", + "tag": "@microsoft/load-themed-styles_v1.10.141", + "date": "Mon, 14 Dec 2020 16:12:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "1.10.140", + "tag": "@microsoft/load-themed-styles_v1.10.140", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "1.10.139", + "tag": "@microsoft/load-themed-styles_v1.10.139", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "1.10.138", + "tag": "@microsoft/load-themed-styles_v1.10.138", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "1.10.137", + "tag": "@microsoft/load-themed-styles_v1.10.137", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "1.10.136", + "tag": "@microsoft/load-themed-styles_v1.10.136", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "1.10.135", + "tag": "@microsoft/load-themed-styles_v1.10.135", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "1.10.134", + "tag": "@microsoft/load-themed-styles_v1.10.134", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "1.10.133", + "tag": "@microsoft/load-themed-styles_v1.10.133", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "1.10.132", + "tag": "@microsoft/load-themed-styles_v1.10.132", + "date": "Fri, 13 Nov 2020 01:11:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "1.10.131", + "tag": "@microsoft/load-themed-styles_v1.10.131", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "1.10.130", + "tag": "@microsoft/load-themed-styles_v1.10.130", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "1.10.129", + "tag": "@microsoft/load-themed-styles_v1.10.129", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "1.10.128", + "tag": "@microsoft/load-themed-styles_v1.10.128", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "1.10.127", + "tag": "@microsoft/load-themed-styles_v1.10.127", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "1.10.126", + "tag": "@microsoft/load-themed-styles_v1.10.126", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "1.10.125", + "tag": "@microsoft/load-themed-styles_v1.10.125", + "date": "Tue, 03 Nov 2020 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "1.10.124", + "tag": "@microsoft/load-themed-styles_v1.10.124", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "1.10.123", + "tag": "@microsoft/load-themed-styles_v1.10.123", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "1.10.122", + "tag": "@microsoft/load-themed-styles_v1.10.122", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "1.10.121", + "tag": "@microsoft/load-themed-styles_v1.10.121", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "1.10.120", + "tag": "@microsoft/load-themed-styles_v1.10.120", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "1.10.119", + "tag": "@microsoft/load-themed-styles_v1.10.119", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "1.10.118", + "tag": "@microsoft/load-themed-styles_v1.10.118", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "1.10.117", + "tag": "@microsoft/load-themed-styles_v1.10.117", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "1.10.116", + "tag": "@microsoft/load-themed-styles_v1.10.116", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "1.10.115", + "tag": "@microsoft/load-themed-styles_v1.10.115", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "1.10.114", + "tag": "@microsoft/load-themed-styles_v1.10.114", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "1.10.113", + "tag": "@microsoft/load-themed-styles_v1.10.113", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "1.10.112", + "tag": "@microsoft/load-themed-styles_v1.10.112", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "1.10.111", + "tag": "@microsoft/load-themed-styles_v1.10.111", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "1.10.110", + "tag": "@microsoft/load-themed-styles_v1.10.110", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "1.10.109", + "tag": "@microsoft/load-themed-styles_v1.10.109", + "date": "Fri, 09 Oct 2020 15:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "1.10.108", + "tag": "@microsoft/load-themed-styles_v1.10.108", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "1.10.107", + "tag": "@microsoft/load-themed-styles_v1.10.107", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "1.10.106", + "tag": "@microsoft/load-themed-styles_v1.10.106", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "1.10.105", + "tag": "@microsoft/load-themed-styles_v1.10.105", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "1.10.104", + "tag": "@microsoft/load-themed-styles_v1.10.104", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + } + ] + } + }, + { + "version": "1.10.103", + "tag": "@microsoft/load-themed-styles_v1.10.103", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "1.10.102", + "tag": "@microsoft/load-themed-styles_v1.10.102", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "1.10.101", + "tag": "@microsoft/load-themed-styles_v1.10.101", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-web-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "1.10.100", + "tag": "@microsoft/load-themed-styles_v1.10.100", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "1.10.99", + "tag": "@microsoft/load-themed-styles_v1.10.99", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "1.10.98", + "tag": "@microsoft/load-themed-styles_v1.10.98", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "1.10.97", + "tag": "@microsoft/load-themed-styles_v1.10.97", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "1.10.96", + "tag": "@microsoft/load-themed-styles_v1.10.96", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "1.10.95", + "tag": "@microsoft/load-themed-styles_v1.10.95", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "1.10.94", + "tag": "@microsoft/load-themed-styles_v1.10.94", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "1.10.93", + "tag": "@microsoft/load-themed-styles_v1.10.93", + "date": "Wed, 16 Sep 2020 05:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "1.10.92", + "tag": "@microsoft/load-themed-styles_v1.10.92", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "1.10.91", + "tag": "@microsoft/load-themed-styles_v1.10.91", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "1.10.90", + "tag": "@microsoft/load-themed-styles_v1.10.90", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "1.10.89", + "tag": "@microsoft/load-themed-styles_v1.10.89", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "1.10.88", + "tag": "@microsoft/load-themed-styles_v1.10.88", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "1.10.87", + "tag": "@microsoft/load-themed-styles_v1.10.87", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "1.10.86", + "tag": "@microsoft/load-themed-styles_v1.10.86", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "1.10.85", + "tag": "@microsoft/load-themed-styles_v1.10.85", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "1.10.84", + "tag": "@microsoft/load-themed-styles_v1.10.84", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "1.10.83", + "tag": "@microsoft/load-themed-styles_v1.10.83", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "1.10.82", + "tag": "@microsoft/load-themed-styles_v1.10.82", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "1.10.81", + "tag": "@microsoft/load-themed-styles_v1.10.81", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "1.10.80", + "tag": "@microsoft/load-themed-styles_v1.10.80", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "1.10.79", + "tag": "@microsoft/load-themed-styles_v1.10.79", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "1.10.78", + "tag": "@microsoft/load-themed-styles_v1.10.78", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "1.10.77", + "tag": "@microsoft/load-themed-styles_v1.10.77", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "1.10.76", + "tag": "@microsoft/load-themed-styles_v1.10.76", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "1.10.75", + "tag": "@microsoft/load-themed-styles_v1.10.75", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "1.10.74", + "tag": "@microsoft/load-themed-styles_v1.10.74", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "1.10.73", + "tag": "@microsoft/load-themed-styles_v1.10.73", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "1.10.72", + "tag": "@microsoft/load-themed-styles_v1.10.72", + "date": "Tue, 18 Aug 2020 03:03:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "1.10.71", + "tag": "@microsoft/load-themed-styles_v1.10.71", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "1.10.70", + "tag": "@microsoft/load-themed-styles_v1.10.70", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.10.69", + "tag": "@microsoft/load-themed-styles_v1.10.69", + "date": "Thu, 13 Aug 2020 09:26:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "1.10.68", + "tag": "@microsoft/load-themed-styles_v1.10.68", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "1.10.67", + "tag": "@microsoft/load-themed-styles_v1.10.67", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "1.10.66", + "tag": "@microsoft/load-themed-styles_v1.10.66", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "1.10.65", + "tag": "@microsoft/load-themed-styles_v1.10.65", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + } + ] + } + }, + { + "version": "1.10.64", + "tag": "@microsoft/load-themed-styles_v1.10.64", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "1.10.63", + "tag": "@microsoft/load-themed-styles_v1.10.63", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "1.10.62", + "tag": "@microsoft/load-themed-styles_v1.10.62", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "1.10.61", + "tag": "@microsoft/load-themed-styles_v1.10.61", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + } + ] + } + }, + { + "version": "1.10.60", + "tag": "@microsoft/load-themed-styles_v1.10.60", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + } + ] + } + }, + { + "version": "1.10.59", + "tag": "@microsoft/load-themed-styles_v1.10.59", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + } + ] + } + }, + { + "version": "1.10.58", + "tag": "@microsoft/load-themed-styles_v1.10.58", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "1.10.57", + "tag": "@microsoft/load-themed-styles_v1.10.57", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "1.10.56", + "tag": "@microsoft/load-themed-styles_v1.10.56", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + } + ] + } + }, + { + "version": "1.10.55", + "tag": "@microsoft/load-themed-styles_v1.10.55", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "1.10.54", + "tag": "@microsoft/load-themed-styles_v1.10.54", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + } + ] + } + }, + { + "version": "1.10.53", + "tag": "@microsoft/load-themed-styles_v1.10.53", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + } + ] + } + }, + { + "version": "1.10.52", + "tag": "@microsoft/load-themed-styles_v1.10.52", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + } + ] + } + }, + { + "version": "1.10.51", + "tag": "@microsoft/load-themed-styles_v1.10.51", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + } + ] + } + }, + { + "version": "1.10.50", + "tag": "@microsoft/load-themed-styles_v1.10.50", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + } + ] + } + }, + { + "version": "1.10.49", + "tag": "@microsoft/load-themed-styles_v1.10.49", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + } + ] + } + }, + { + "version": "1.10.48", + "tag": "@microsoft/load-themed-styles_v1.10.48", + "date": "Thu, 21 May 2020 15:41:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "1.10.47", + "tag": "@microsoft/load-themed-styles_v1.10.47", + "date": "Tue, 19 May 2020 15:08:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "1.10.46", + "tag": "@microsoft/load-themed-styles_v1.10.46", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "1.10.45", + "tag": "@microsoft/load-themed-styles_v1.10.45", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "1.10.44", + "tag": "@microsoft/load-themed-styles_v1.10.44", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "1.10.43", + "tag": "@microsoft/load-themed-styles_v1.10.43", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + } + ] + } + }, + { + "version": "1.10.42", + "tag": "@microsoft/load-themed-styles_v1.10.42", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "1.10.41", + "tag": "@microsoft/load-themed-styles_v1.10.41", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "1.10.40", + "tag": "@microsoft/load-themed-styles_v1.10.40", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + } + ] + } + }, { "version": "1.10.39", "tag": "@microsoft/load-themed-styles_v1.10.39", diff --git a/libraries/load-themed-styles/CHANGELOG.md b/libraries/load-themed-styles/CHANGELOG.md index 55e8e9afe60..44f2e6f2750 100644 --- a/libraries/load-themed-styles/CHANGELOG.md +++ b/libraries/load-themed-styles/CHANGELOG.md @@ -1,56 +1,2336 @@ # Change Log - @microsoft/load-themed-styles -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 2.0.153 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 2.0.152 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 2.0.151 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 2.0.150 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 2.0.149 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 2.0.148 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 2.0.147 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 2.0.146 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 2.0.145 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 2.0.144 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 2.0.143 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 2.0.142 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 2.0.141 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 2.0.140 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 2.0.139 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 2.0.138 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 2.0.137 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 2.0.136 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 2.0.135 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 2.0.134 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 2.0.133 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 2.0.132 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 2.0.131 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 2.0.130 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 2.0.129 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 2.0.128 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 2.0.127 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 2.0.126 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 2.0.125 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 2.0.124 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 2.0.123 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 2.0.122 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 2.0.121 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 2.0.120 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 2.0.119 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 2.0.118 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 2.0.117 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 2.0.116 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 2.0.115 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 2.0.114 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 2.0.113 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 2.0.112 +Sun, 03 Mar 2024 20:58:12 GMT + +_Version update only_ + +## 2.0.111 +Sat, 02 Mar 2024 02:22:23 GMT + +_Version update only_ + +## 2.0.110 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 2.0.109 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 2.0.108 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 2.0.107 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 2.0.106 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 2.0.105 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 2.0.104 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 2.0.103 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 2.0.102 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 2.0.101 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 2.0.100 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 2.0.99 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 2.0.98 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 2.0.97 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 2.0.96 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 2.0.95 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 2.0.94 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 2.0.93 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 2.0.92 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 2.0.91 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 2.0.90 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 2.0.89 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 2.0.88 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 2.0.87 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 2.0.86 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 2.0.85 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 2.0.84 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 2.0.83 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 2.0.82 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 2.0.81 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 2.0.80 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 2.0.79 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 2.0.78 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 2.0.77 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 2.0.76 +Fri, 15 Sep 2023 00:36:58 GMT + +_Version update only_ + +## 2.0.75 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 2.0.74 +Fri, 01 Sep 2023 04:53:58 GMT + +### Patches + +- Use self.setTimeout() instead of setTimeout() to work around a Jest regression + +## 2.0.73 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 2.0.72 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 2.0.71 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 2.0.70 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 2.0.69 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 2.0.68 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 2.0.67 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 2.0.66 +Mon, 17 Jul 2023 15:20:25 GMT + +_Version update only_ + +## 2.0.65 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 2.0.64 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 2.0.63 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 2.0.62 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 2.0.61 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 2.0.60 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 2.0.59 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 2.0.58 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 2.0.57 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 2.0.56 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 2.0.55 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 2.0.54 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 2.0.53 +Fri, 09 Jun 2023 18:05:34 GMT + +_Version update only_ + +## 2.0.52 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 2.0.51 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 2.0.50 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 2.0.49 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 2.0.48 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 2.0.47 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 2.0.46 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 2.0.45 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 2.0.44 +Fri, 02 Jun 2023 00:24:45 GMT + +_Version update only_ + +## 2.0.43 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 2.0.42 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 2.0.41 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 2.0.40 +Thu, 11 May 2023 00:17:21 GMT + +_Version update only_ + +## 2.0.39 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 2.0.38 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 2.0.37 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 2.0.36 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 2.0.35 +Thu, 20 Apr 2023 15:16:55 GMT + +_Version update only_ + +## 2.0.34 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 2.0.33 +Fri, 07 Apr 2023 22:19:21 GMT + +_Version update only_ + +## 2.0.32 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 2.0.31 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 2.0.30 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 2.0.29 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 2.0.28 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 2.0.27 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 2.0.26 +Tue, 31 Jan 2023 01:23:23 GMT + +_Version update only_ + +## 2.0.25 +Mon, 30 Jan 2023 16:22:30 GMT + +_Version update only_ + +## 2.0.24 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 2.0.23 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 2.0.22 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 2.0.21 +Sun, 22 Jan 2023 20:37:08 GMT + +_Version update only_ + +## 2.0.20 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 2.0.19 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 2.0.18 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 2.0.17 +Fri, 02 Dec 2022 01:15:41 GMT + +_Version update only_ + +## 2.0.16 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 2.0.15 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 2.0.14 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 2.0.13 +Wed, 26 Oct 2022 15:16:29 GMT + +_Version update only_ + +## 2.0.12 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 2.0.11 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 2.0.10 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 2.0.9 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 2.0.8 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 2.0.7 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 2.0.6 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 2.0.5 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 2.0.4 +Sat, 08 Oct 2022 02:30:08 GMT + +_Version update only_ + +## 2.0.3 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 2.0.2 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 2.0.1 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 2.0.0 +Thu, 15 Sep 2022 00:18:51 GMT + +### Breaking changes + +- Switch compilation target to ES2017 + +## 1.10.295 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.10.294 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.10.293 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.10.292 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.10.291 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.10.290 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.10.289 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.10.288 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 1.10.287 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.10.286 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.10.285 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 1.10.284 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.10.283 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 1.10.282 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.10.281 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 1.10.280 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 1.10.279 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.10.278 +Thu, 30 Jun 2022 04:48:53 GMT + +_Version update only_ + +## 1.10.277 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 1.10.276 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.10.275 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.10.274 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.10.273 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.10.272 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.10.271 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 1.10.270 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.10.269 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 1.10.268 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 1.10.267 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 1.10.266 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 1.10.265 +Wed, 18 May 2022 15:10:55 GMT + +_Version update only_ + +## 1.10.264 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.10.263 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.10.262 +Fri, 06 May 2022 18:54:42 GMT + +_Version update only_ + +## 1.10.261 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.10.260 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.10.259 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 1.10.258 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.10.257 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 1.10.256 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.10.255 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.10.254 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.10.253 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.10.252 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.10.251 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.10.250 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.10.249 +Sat, 19 Mar 2022 08:05:37 GMT + +_Version update only_ + +## 1.10.248 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 1.10.247 +Tue, 15 Feb 2022 01:39:45 GMT + +### Patches + +- Do not import TS helpers. + +## 1.10.246 +Fri, 11 Feb 2022 10:30:25 GMT + +### Patches + +- Enable importHelpers=true + +## 1.10.245 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 1.10.244 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 1.10.243 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 1.10.242 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.10.241 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.10.240 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 1.10.239 +Fri, 10 Dec 2021 01:09:33 GMT + +_Version update only_ + +## 1.10.238 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.10.237 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.10.236 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.10.235 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 1.10.234 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 1.10.233 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.10.232 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 1.10.231 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.10.230 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.10.229 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.10.228 +Thu, 28 Oct 2021 23:48:23 GMT + +_Version update only_ + +## 1.10.227 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.10.226 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.10.225 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 1.10.224 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.10.223 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.10.222 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.10.221 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.10.220 +Wed, 06 Oct 2021 15:08:25 GMT + +_Version update only_ + +## 1.10.219 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.10.218 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 1.10.217 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.10.216 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.10.215 +Thu, 23 Sep 2021 00:10:41 GMT + +_Version update only_ + +## 1.10.214 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.10.213 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.10.212 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.10.211 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.10.210 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.10.209 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.10.208 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.10.207 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.10.206 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 1.10.205 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.10.204 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.10.203 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.10.202 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 1.10.201 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.10.200 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 1.10.199 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 1.10.198 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.10.197 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.10.196 +Tue, 27 Jul 2021 22:31:02 GMT + +_Version update only_ + +## 1.10.195 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.10.194 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.10.193 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.10.192 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.10.191 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.10.190 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.10.189 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.10.188 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.10.187 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.10.186 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.10.185 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.10.184 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.10.183 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.10.182 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 1.10.181 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.10.180 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 1.10.179 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.10.178 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.10.177 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.10.176 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.10.175 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.10.174 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.10.173 +Fri, 28 May 2021 06:19:57 GMT + +_Version update only_ + +## 1.10.172 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.10.171 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.10.170 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 1.10.169 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.10.168 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.10.167 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.10.166 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.10.165 +Fri, 23 Apr 2021 22:00:06 GMT + +_Version update only_ + +## 1.10.164 +Fri, 23 Apr 2021 15:11:20 GMT + +_Version update only_ + +## 1.10.163 +Wed, 21 Apr 2021 15:12:27 GMT + +_Version update only_ + +## 1.10.162 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.10.161 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 1.10.160 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.10.159 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 1.10.158 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.10.157 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.10.156 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.10.155 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.10.154 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 1.10.153 +Fri, 19 Mar 2021 22:31:37 GMT + +_Version update only_ + +## 1.10.152 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.10.151 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.10.150 +Wed, 10 Mar 2021 05:10:05 GMT + +_Version update only_ + +## 1.10.149 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 1.10.148 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 1.10.147 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 1.10.146 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 1.10.145 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 1.10.144 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 1.10.143 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 1.10.142 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 1.10.141 +Mon, 14 Dec 2020 16:12:20 GMT + +_Version update only_ + +## 1.10.140 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 1.10.139 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 1.10.138 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 1.10.137 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 1.10.136 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 1.10.135 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 1.10.134 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 1.10.133 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 1.10.132 +Fri, 13 Nov 2020 01:11:00 GMT + +_Version update only_ + +## 1.10.131 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 1.10.130 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 1.10.129 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 1.10.128 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 1.10.127 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 1.10.126 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 1.10.125 +Tue, 03 Nov 2020 01:11:18 GMT + +_Version update only_ + +## 1.10.124 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 1.10.123 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 1.10.122 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 1.10.121 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 1.10.120 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 1.10.119 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 1.10.118 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 1.10.117 +Sat, 24 Oct 2020 00:11:18 GMT + +_Version update only_ + +## 1.10.116 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 1.10.115 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 1.10.114 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 1.10.113 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 1.10.112 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 1.10.111 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 1.10.110 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 1.10.109 +Fri, 09 Oct 2020 15:11:08 GMT + +_Version update only_ + +## 1.10.108 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 1.10.107 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 1.10.106 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 1.10.105 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 1.10.104 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 1.10.103 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 1.10.102 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 1.10.101 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 1.10.100 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 1.10.99 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 1.10.98 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 1.10.97 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 1.10.96 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 1.10.95 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 1.10.94 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 1.10.93 +Wed, 16 Sep 2020 05:30:25 GMT + +_Version update only_ + +## 1.10.92 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 1.10.91 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 1.10.90 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 1.10.89 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 1.10.88 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 1.10.87 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 1.10.86 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 1.10.85 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 1.10.84 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 1.10.83 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 1.10.82 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 1.10.81 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 1.10.80 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 1.10.79 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 1.10.78 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 1.10.77 +Sat, 22 Aug 2020 05:55:42 GMT + +_Version update only_ + +## 1.10.76 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 1.10.75 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 1.10.74 +Thu, 20 Aug 2020 15:13:52 GMT + +_Version update only_ + +## 1.10.73 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 1.10.72 +Tue, 18 Aug 2020 03:03:23 GMT + +_Version update only_ + +## 1.10.71 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 1.10.70 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 1.10.69 +Thu, 13 Aug 2020 09:26:39 GMT + +_Version update only_ + +## 1.10.68 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 1.10.67 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 1.10.66 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 1.10.65 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 1.10.64 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 1.10.63 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 1.10.62 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 1.10.61 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 1.10.60 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 1.10.59 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 1.10.58 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 1.10.57 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 1.10.56 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 1.10.55 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 1.10.54 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 1.10.53 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 1.10.52 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 1.10.51 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 1.10.50 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 1.10.49 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 1.10.48 +Thu, 21 May 2020 15:41:59 GMT + +_Version update only_ + +## 1.10.47 +Tue, 19 May 2020 15:08:19 GMT + +_Version update only_ + +## 1.10.46 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 1.10.45 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 1.10.44 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 1.10.43 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 1.10.42 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 1.10.41 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 1.10.40 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 1.10.39 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 1.10.38 Tue, 17 Mar 2020 23:55:58 GMT -*Version update only* +_Version update only_ ## 1.10.37 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 1.10.36 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 1.10.35 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 1.10.34 Tue, 21 Jan 2020 21:56:13 GMT -*Version update only* +_Version update only_ ## 1.10.33 Sun, 19 Jan 2020 02:26:53 GMT -*Version update only* +_Version update only_ ## 1.10.32 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 1.10.31 Tue, 14 Jan 2020 01:34:15 GMT -*Version update only* +_Version update only_ ## 1.10.30 Sat, 11 Jan 2020 05:18:23 GMT -*Version update only* +_Version update only_ ## 1.10.29 Fri, 10 Jan 2020 03:07:47 GMT @@ -62,12 +2342,12 @@ Fri, 10 Jan 2020 03:07:47 GMT ## 1.10.28 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 1.10.27 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 1.10.26 Mon, 23 Dec 2019 16:08:05 GMT @@ -79,67 +2359,67 @@ Mon, 23 Dec 2019 16:08:05 GMT ## 1.10.25 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 1.10.24 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 1.10.23 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 1.10.22 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 1.10.21 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 1.10.20 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 1.10.19 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 1.10.18 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 1.10.17 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 1.10.16 Fri, 25 Oct 2019 15:08:54 GMT -*Version update only* +_Version update only_ ## 1.10.15 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 1.10.14 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 1.10.13 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 1.10.12 Sun, 06 Oct 2019 00:27:39 GMT @@ -151,7 +2431,7 @@ Sun, 06 Oct 2019 00:27:39 GMT ## 1.10.11 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 1.10.10 Sun, 29 Sep 2019 23:56:29 GMT @@ -163,47 +2443,47 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 1.10.9 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 1.10.8 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 1.10.7 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 1.10.6 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 1.10.5 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 1.10.4 Tue, 10 Sep 2019 22:32:23 GMT -*Version update only* +_Version update only_ ## 1.10.3 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 1.10.2 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 1.10.1 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 1.10.0 Wed, 04 Sep 2019 01:43:31 GMT @@ -215,102 +2495,102 @@ Wed, 04 Sep 2019 01:43:31 GMT ## 1.9.20 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 1.9.19 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 1.9.18 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 1.9.17 Thu, 08 Aug 2019 00:49:05 GMT -*Version update only* +_Version update only_ ## 1.9.16 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 1.9.15 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 1.9.14 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 1.9.13 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 1.9.12 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 1.9.11 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 1.9.10 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 1.9.9 Mon, 08 Jul 2019 19:12:18 GMT -*Version update only* +_Version update only_ ## 1.9.8 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 1.9.7 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 1.9.6 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.9.5 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 1.9.4 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 1.9.3 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 1.9.2 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 1.9.1 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 1.9.0 Thu, 09 May 2019 19:12:31 GMT @@ -322,122 +2602,122 @@ Thu, 09 May 2019 19:12:31 GMT ## 1.8.89 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 1.8.88 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 1.8.87 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 1.8.86 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 1.8.85 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 1.8.84 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 1.8.83 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 1.8.82 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 1.8.81 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 1.8.80 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 1.8.79 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 1.8.78 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 1.8.77 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 1.8.76 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 1.8.75 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 1.8.74 Tue, 26 Mar 2019 20:54:18 GMT -*Version update only* +_Version update only_ ## 1.8.73 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 1.8.72 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 1.8.71 Thu, 21 Mar 2019 01:15:32 GMT -*Version update only* +_Version update only_ ## 1.8.70 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 1.8.69 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 1.8.68 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 1.8.67 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 1.8.66 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 1.8.65 Mon, 11 Mar 2019 16:13:36 GMT @@ -449,72 +2729,72 @@ Mon, 11 Mar 2019 16:13:36 GMT ## 1.8.64 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 1.8.63 Mon, 04 Mar 2019 17:13:19 GMT -*Version update only* +_Version update only_ ## 1.8.62 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 1.8.61 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 1.8.60 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 1.8.59 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 1.8.58 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 1.8.57 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 1.8.56 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 1.8.55 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 1.8.54 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 1.8.53 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 1.8.52 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 1.8.51 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 1.8.50 Fri, 14 Dec 2018 20:51:51 GMT @@ -526,22 +2806,22 @@ Fri, 14 Dec 2018 20:51:51 GMT ## 1.8.49 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 1.8.48 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 1.8.47 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 1.8.46 Fri, 07 Dec 2018 17:04:56 GMT -*Version update only* +_Version update only_ ## 1.8.45 Mon, 03 Dec 2018 17:04:06 GMT @@ -560,182 +2840,182 @@ Fri, 30 Nov 2018 23:34:57 GMT ## 1.8.43 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 1.8.42 Thu, 29 Nov 2018 00:35:38 GMT -*Version update only* +_Version update only_ ## 1.8.41 Wed, 28 Nov 2018 19:29:53 GMT -*Version update only* +_Version update only_ ## 1.8.40 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 1.8.39 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 1.8.38 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 1.8.37 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 1.8.36 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 1.8.35 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 1.8.34 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 1.8.33 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 1.8.32 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 1.8.31 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 1.8.30 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 1.8.29 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 1.8.28 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 1.8.27 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 1.8.26 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 1.8.25 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 1.8.24 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 1.8.23 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 1.8.22 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 1.8.21 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 1.8.20 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 1.8.19 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 1.8.18 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 1.8.17 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 1.8.16 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 1.8.15 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 1.8.14 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 1.8.13 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 1.8.12 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 1.8.11 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 1.8.10 Thu, 20 Sep 2018 23:57:21 GMT -*Version update only* +_Version update only_ ## 1.8.9 Tue, 18 Sep 2018 21:04:55 GMT -*Version update only* +_Version update only_ ## 1.8.8 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 1.8.7 Thu, 06 Sep 2018 01:25:26 GMT @@ -747,17 +3027,17 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 1.8.6 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 1.8.5 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 1.8.4 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 1.8.3 Thu, 30 Aug 2018 19:23:16 GMT @@ -769,7 +3049,7 @@ Thu, 30 Aug 2018 19:23:16 GMT ## 1.8.2 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 1.8.1 Thu, 30 Aug 2018 04:42:01 GMT @@ -788,7 +3068,7 @@ Thu, 30 Aug 2018 04:24:41 GMT ## 1.7.84 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 1.7.83 Wed, 29 Aug 2018 20:34:33 GMT @@ -800,7 +3080,7 @@ Wed, 29 Aug 2018 20:34:33 GMT ## 1.7.82 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 1.7.81 Thu, 23 Aug 2018 18:18:53 GMT @@ -812,267 +3092,267 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 1.7.80 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 1.7.79 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 1.7.78 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 1.7.77 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 1.7.76 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 1.7.75 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 1.7.74 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 1.7.73 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 1.7.72 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 1.7.71 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 1.7.70 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 1.7.69 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 1.7.68 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 1.7.67 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 1.7.66 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 1.7.65 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 1.7.64 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 1.7.63 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 1.7.62 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 1.7.61 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 1.7.60 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 1.7.59 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 1.7.58 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 1.7.57 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 1.7.56 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 1.7.55 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 1.7.54 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 1.7.53 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 1.7.52 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 1.7.51 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 1.7.50 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 1.7.49 Mon, 02 Apr 2018 16:05:24 GMT -*Version update only* +_Version update only_ ## 1.7.48 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 1.7.47 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 1.7.46 Sun, 25 Mar 2018 01:26:19 GMT -*Version update only* +_Version update only_ ## 1.7.45 Fri, 23 Mar 2018 00:34:53 GMT -*Version update only* +_Version update only_ ## 1.7.44 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 1.7.43 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 1.7.42 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 1.7.41 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 1.7.40 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 1.7.39 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 1.7.38 Mon, 12 Mar 2018 20:36:19 GMT -*Version update only* +_Version update only_ ## 1.7.37 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 1.7.36 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 1.7.35 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 1.7.34 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 1.7.33 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 1.7.32 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 1.7.31 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 1.7.30 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.7.29 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.7.28 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 1.7.27 Fri, 26 Jan 2018 17:53:38 GMT @@ -1084,97 +3364,97 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 1.7.26 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 1.7.25 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 1.7.24 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 1.7.23 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.7.22 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 1.7.21 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 1.7.20 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 1.7.19 Wed, 10 Jan 2018 20:40:01 GMT -*Version update only* +_Version update only_ ## 1.7.18 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 1.7.17 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 1.7.16 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 1.7.15 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 1.7.14 Tue, 12 Dec 2017 03:33:26 GMT -*Version update only* +_Version update only_ ## 1.7.13 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 1.7.12 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 1.7.11 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 1.7.10 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 1.7.9 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 1.7.8 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 1.7.7 Thu, 02 Nov 2017 16:05:24 GMT @@ -1186,27 +3466,27 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 1.7.6 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 1.7.5 Fri, 22 Sep 2017 01:04:02 GMT -*Version update only* +_Version update only_ ## 1.7.4 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 1.7.3 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 1.7.2 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 1.7.1 Tue, 15 Aug 2017 23:48:10 GMT @@ -1253,5 +3533,5 @@ Fri, 21 Jul 2017 01:02:30 GMT ## 1.4.0 Fri, 07 Jul 2017 01:02:28 GMT -*Initial release* +_Initial release_ diff --git a/libraries/load-themed-styles/README.md b/libraries/load-themed-styles/README.md index a93cf02d507..8de7a8ebcdb 100644 --- a/libraries/load-themed-styles/README.md +++ b/libraries/load-themed-styles/README.md @@ -1,8 +1,6 @@ # @microsoft/load-themed-styles [![npm version](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles.svg)](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles) -[![Build Status](https://travis-ci.org/Microsoft/load-themed-styles.svg?branch=master)](https://travis-ci.org/Microsoft/load-themed-styles) [![Dependencies](https://david-dm.org/Microsoft/load-themed-styles.svg)](https://david-dm.org/Microsoft/load-themed-styles) - > Loads a string of style rules, but supports detokenizing theme constants built within it. ## Install @@ -59,6 +57,10 @@ window.CSPSettings = { }; ``` -## License +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/load-themed-styles/CHANGELOG.md) - Find + out what's new in the latest version -MIT © [Microsoft](http://github.com/microsoft) +`@microsoft/load-themed-styles` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/load-themed-styles/config/heft.json b/libraries/load-themed-styles/config/heft.json new file mode 100644 index 00000000000..90163480937 --- /dev/null +++ b/libraries/load-themed-styles/config/heft.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-web-rig/profiles/library/config/heft.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["lib-dts", "lib-esm"] }] + } + } +} diff --git a/libraries/load-themed-styles/config/jest.config.json b/libraries/load-themed-styles/config/jest.config.json new file mode 100644 index 00000000000..a6a75a1a029 --- /dev/null +++ b/libraries/load-themed-styles/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-web-rig/profiles/library/config/jest.config.json" +} diff --git a/libraries/load-themed-styles/config/rig.json b/libraries/load-themed-styles/config/rig.json new file mode 100644 index 00000000000..659f339663a --- /dev/null +++ b/libraries/load-themed-styles/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/libraries/load-themed-styles/config/rush-project.json b/libraries/load-themed-styles/config/rush-project.json new file mode 100644 index 00000000000..de5c9b428a0 --- /dev/null +++ b/libraries/load-themed-styles/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "extends": "local-web-rig/profiles/library/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-dts", "lib-esm"] + } + ] +} diff --git a/libraries/load-themed-styles/config/typescript.json b/libraries/load-themed-styles/config/typescript.json new file mode 100644 index 00000000000..ece203c8107 --- /dev/null +++ b/libraries/load-themed-styles/config/typescript.json @@ -0,0 +1,33 @@ +/** + * 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": "amd", + "outFolderName": "lib-amd" + }, + + { + "moduleKind": "commonjs", + "outFolderName": "lib-commonjs" + } + ] +} 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/gulpfile.js b/libraries/load-themed-styles/gulpfile.js deleted file mode 100644 index efaca7428df..00000000000 --- a/libraries/load-themed-styles/gulpfile.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); -const path = require('path'); - -build.tscCmd = 'tsc-commonjs'; - -const tscAmdTask = new build.TscCmdTask(); -tscAmdTask.name = 'tsc-amd'; -tscAmdTask.cleanMatch = [path.join(__dirname, 'lib-amd')]; -tscAmdTask.setConfig({ - customArgs: [ - '--outDir', './lib-amd', - '--module', 'amd' - ] -}); - -const tscEsnextTask = new build.TscCmdTask(); -tscEsnextTask.name = 'tsc-es6'; -tscEsnextTask.cleanMatch = [path.join(__dirname, 'lib-es6')]; -tscEsnextTask.setConfig({ - customArgs: [ - '--outDir', './lib-es6', - '--module', 'esnext' - ] -}); - -build.defaultTasks = build.task( - 'default', - build.parallel( - build.defaultTasks, - tscAmdTask, - tscEsnextTask - ) -); - -build.setConfig({ - libAMDFolder: 'lib-amd', - libES6Folder: 'lib-es6' -}); - -build.initialize(require('gulp')); diff --git a/libraries/load-themed-styles/package.json b/libraries/load-themed-styles/package.json index 9e9608c0a6c..b48832df39f 100644 --- a/libraries/load-themed-styles/package.json +++ b/libraries/load-themed-styles/package.json @@ -1,26 +1,45 @@ { "name": "@microsoft/load-themed-styles", - "version": "1.10.39", + "version": "2.1.22", "description": "Loads themed styles.", "license": "MIT", "repository": { - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/load-themed-styles" + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/load-themed-styles" }, "scripts": { - "build": "gulp --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, - "main": "lib/index.js", - "module": "lib-es6/index.js", - "typings": "lib/index.d.ts", + "main": "lib-commonjs/index.js", + "module": "lib-esm/index.js", + "typings": "lib-dts/index.d.ts", "keywords": [], "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/webpack-env": "1.13.0", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "@microsoft/node-library-build": "6.4.6" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + }, + "exports": { + ".": { + "require": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts" + }, + "./lib/*": { + "require": "./lib-commonjs/*", + "import": "./lib-esm/*", + "types": "./lib-dts/*" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/libraries/load-themed-styles/src/index.ts b/libraries/load-themed-styles/src/index.ts index ef348edc102..ba6296d77b6 100644 --- a/libraries/load-themed-styles/src/index.ts +++ b/libraries/load-themed-styles/src/index.ts @@ -1,14 +1,16 @@ -/** - * 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 */ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. // 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; @@ -52,8 +54,8 @@ interface IRunState { interface IThemeState { theme: ITheme | undefined; lastStyleElement: IExtendedHtmlStyleElement; - registeredStyles: IStyleRecord[]; // records of already registered non-themable styles - registeredThemableStyles: IStyleRecord[]; // records of already registered themable styles + registeredStyles: IStyleRecord[]; // records of already registered non-themable styles + registeredThemableStyles: IStyleRecord[]; // records of already registered themable styles loadStyles: ((processedStyles: string, rawStyles?: string | ThemableArray) => void) | undefined; perf: IMeasurement; runState: IRunState; @@ -103,7 +105,7 @@ export const enum ClearStyleOptions { // Store the theming state in __themeState__ global scope for reuse in the case of duplicate // load-themed-styles hosted on the page. -const _root: any = (typeof window === 'undefined') ? global : window; // eslint-disable-line @typescript-eslint/no-explicit-any +const _root: any = typeof window === 'undefined' ? global : window; // eslint-disable-line @typescript-eslint/no-explicit-any // Nonce string to inject into script tag if one provided. This is used in CSP (Content Security Policy). const _styleNonce: string = _root && _root.CSPSettings && _root.CSPSettings.nonce; @@ -113,10 +115,11 @@ const _themeState: IThemeState = initializeThemeState(); /** * Matches theming tokens. For example, "[theme: themeSlotName, default: #FFF]" (including the quotes). */ -const _themeTokenRegex: RegExp = /[\'\"]\[theme:\s*(\w+)\s*(?:\,\s*default:\s*([\\"\']?[\.\,\(\)\#\-\s\w]*[\.\,\(\)\#\-\w][\"\']?))?\s*\][\'\"]/g; +const _themeTokenRegex: RegExp = + /[\'\"]\[theme:\s*(\w+)\s*(?:\,\s*default:\s*([\\"\']?[\.\,\(\)\#\-\s\w]*[\.\,\(\)\#\-\w][\"\']?))?\s*\][\'\"]/g; -const now: () => number = - () => (typeof performance !== 'undefined' && !!performance.now) ? performance.now() : Date.now(); +const now: () => number = () => + typeof performance !== 'undefined' && !!performance.now ? performance.now() : Date.now(); function measure(func: () => void): void { const start: number = now(); @@ -137,7 +140,7 @@ function initializeThemeState(): IThemeState { if (!state.runState) { state = { - ...(state), + ...state, perf: { count: 0, duration: 0 @@ -151,7 +154,7 @@ function initializeThemeState(): IThemeState { } if (!state.registeredThemableStyles) { state = { - ...(state), + ...state, registeredThemableStyles: [] }; } @@ -168,11 +171,7 @@ function initializeThemeState(): IThemeState { export function loadStyles(styles: string | ThemableArray, loadAsync: boolean = false): void { measure(() => { const styleParts: ThemableArray = Array.isArray(styles) ? styles : splitStyles(styles); - const { - mode, - buffer, - flushTimer - } = _themeState.runState; + const { mode, buffer, flushTimer } = _themeState.runState; if (loadAsync || mode === Mode.async) { buffer.push(styleParts); if (!flushTimer) { @@ -210,7 +209,7 @@ export function flush(): void { measure(() => { const styleArrays: ThemableArray[] = _themeState.runState.buffer.slice(); _themeState.runState.buffer = []; - const mergedStyleArray: ThemableArray = [].concat.apply([], styleArrays); + const mergedStyleArray: ThemableArray = ([] as ThemableArray).concat.apply([], styleArrays); if (mergedStyleArray.length > 0) { applyThemableStyles(mergedStyleArray); } @@ -221,7 +220,9 @@ export function flush(): void { * register async loadStyles */ function asyncLoadStyles(): number { - return setTimeout(() => { + // Use "self" to distinguish conflicting global typings for setTimeout() from lib.dom.d.ts vs Jest's @types/node + // https://github.com/jestjs/jest/issues/14418 + return self.setTimeout(() => { _themeState.runState.flushTimer = 0; flush(); }, 0); @@ -237,7 +238,7 @@ function applyThemableStyles(stylesArray: ThemableArray, styleRecord?: IStyleRec if (_themeState.loadStyles) { _themeState.loadStyles(resolveThemableArray(stylesArray).styleString, stylesArray); } else { - registerStyles(stylesArray); + registerStyles(stylesArray); } } @@ -249,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. @@ -271,7 +290,7 @@ export function clearStyles(option: ClearStyleOptions = ClearStyleOptions.all): function clearStylesInternal(records: IStyleRecord[]): void { records.forEach((styleRecord: IStyleRecord) => { - const styleElement: HTMLStyleElement = styleRecord && styleRecord.styleElement as HTMLStyleElement; + const styleElement: HTMLStyleElement = styleRecord && (styleRecord.styleElement as HTMLStyleElement); if (styleElement && styleElement.parentElement) { styleElement.parentElement.removeChild(styleElement); } @@ -289,7 +308,7 @@ function reloadStyles(): void { } if (themableStyles.length > 0) { clearStyles(ClearStyleOptions.onlyThemable); - applyThemableStyles([].concat.apply([], themableStyles)); + applyThemableStyles(([] as ThemableArray).concat.apply([], themableStyles)); } } } @@ -315,26 +334,36 @@ function resolveThemableArray(splitStyleArray: ThemableArray): IThemableArrayRes let themable: boolean = false; // Resolve the array of theming instructions to an array of strings. // Then join the array to produce the final CSS string. - const resolvedArray: (string | undefined)[] = (splitStyleArray || []).map((currentValue: IThemingInstruction) => { - const themeSlot: string | undefined = currentValue.theme; - if (themeSlot) { - themable = true; - // A theming annotation. Resolve it. - const themedValue: string | undefined = theme ? theme[themeSlot] : undefined; - const defaultValue: string = currentValue.defaultValue || 'inherit'; - - // Warn to console if we hit an unthemed value even when themes are provided, but only if "DEBUG" is true. - // Allow the themedValue to be undefined to explicitly request the default value. - if (theme && !themedValue && console && !(themeSlot in theme) && typeof DEBUG !== 'undefined' && DEBUG) { - console.warn(`Theming value not provided for "${themeSlot}". Falling back to "${defaultValue}".`); + const resolvedArray: (string | undefined)[] = (splitStyleArray || []).map( + (currentValue: IThemingInstruction) => { + const themeSlot: string | undefined = currentValue.theme; + if (themeSlot) { + themable = true; + // A theming annotation. Resolve it. + const themedValue: string | undefined = theme ? theme[themeSlot] : undefined; + const defaultValue: string = currentValue.defaultValue || 'inherit'; + + // Warn to console if we hit an unthemed value even when themes are provided, but only if "DEBUG" is true. + // Allow the themedValue to be undefined to explicitly request the default value. + if ( + theme && + !themedValue && + console && + !(themeSlot in theme) && + typeof DEBUG !== 'undefined' && + DEBUG + ) { + // eslint-disable-next-line no-console + console.warn(`Theming value not provided for "${themeSlot}". Falling back to "${defaultValue}".`); + } + + return themedValue || defaultValue; + } else { + // A non-themable string. Preserve it. + return currentValue.rawString; } - - return themedValue || defaultValue; - } else { - // A non-themable string. Preserve it. - return currentValue.rawString; } - }); + ); return { styleString: resolvedArray.join(''), @@ -350,7 +379,7 @@ export function splitStyles(styles: string): ThemableArray { const result: ThemableArray = []; if (styles) { let pos: number = 0; // Current position in styles. - let tokenMatch: RegExpExecArray | null; // eslint-disable-line @rushstack/no-null + let tokenMatch: RegExpExecArray | null; while ((tokenMatch = _themeTokenRegex.exec(styles))) { const matchIndex: number = tokenMatch.index; if (matchIndex > pos) { @@ -389,10 +418,7 @@ function registerStyles(styleArray: ThemableArray): void { } const head: HTMLHeadElement = document.getElementsByTagName('head')[0]; const styleElement: HTMLStyleElement = document.createElement('style'); - const { - styleString, - themable - } = resolveThemableArray(styleArray); + const { styleString, themable } = resolveThemableArray(styleArray); styleElement.setAttribute('data-load-themed-styles', 'true'); if (_styleNonce) { @@ -402,7 +428,7 @@ function registerStyles(styleArray: ThemableArray): void { _themeState.perf.count++; head.appendChild(styleElement); - const ev: ICustomEvent<{ newStyle: HTMLStyleElement}> = document.createEvent('HTMLEvents'); + const ev: ICustomEvent<{ newStyle: HTMLStyleElement }> = document.createEvent('HTMLEvents'); ev.initEvent('styleinsert', true /* bubbleEvent */, false /* cancelable */); ev.args = { newStyle: styleElement diff --git a/libraries/load-themed-styles/src/test/index.test.ts b/libraries/load-themed-styles/src/test/index.test.ts index e574538d6c6..df4aa339704 100644 --- a/libraries/load-themed-styles/src/test/index.test.ts +++ b/libraries/load-themed-styles/src/test/index.test.ts @@ -1,28 +1,29 @@ -/// +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. -import { expect } from 'chai'; import { detokenize, loadTheme, splitStyles, loadStyles, configureLoadStyles, - IThemingInstruction -} from './../index'; + replaceTokensWithVariables, + type IThemingInstruction +} from '../index'; -describe('detokenize', () => { +describe(detokenize.name, () => { it('handles colors', () => { - expect(detokenize('"[theme:name, default: #FFF]"')).to.equal('#FFF'); - expect(detokenize('"[theme: name, default: #FFF]"')).to.equal('#FFF'); - expect(detokenize('"[theme: name , default: #FFF ]"')).to.equal('#FFF'); + expect(detokenize('"[theme:name, default: #FFF]"')).toEqual('#FFF'); + expect(detokenize('"[theme: name, default: #FFF]"')).toEqual('#FFF'); + expect(detokenize('"[theme: name , default: #FFF ]"')).toEqual('#FFF'); }); it('handles rgba', () => { - expect(detokenize('"[theme:name, default: rgba(255,255,255,.5)]"')).to.equal('rgba(255,255,255,.5)'); + expect(detokenize('"[theme:name, default: rgba(255,255,255,.5)]"')).toEqual('rgba(255,255,255,.5)'); }); it('handles fonts', () => { - expect(detokenize('"[theme:name, default: "Segoe UI"]"')).to.equal('"Segoe UI"'); + expect(detokenize('"[theme:name, default: "Segoe UI"]"')).toEqual('"Segoe UI"'); }); it('respects theme', () => { @@ -31,42 +32,81 @@ describe('detokenize', () => { }); try { - expect(detokenize('"[theme:color, default: #FFF]"')).to.equal('red'); - expect(detokenize('"[theme: color , default: #FFF]"')).to.equal('red'); + expect(detokenize('"[theme:color, default: #FFF]"')).toEqual('red'); + expect(detokenize('"[theme: color , default: #FFF]"')).toEqual('red'); } finally { loadTheme(undefined); } }); it('ignores malformed themes', () => { - expect(detokenize('"[theme:name, default: "Segoe UI"]')).to.equal('"[theme:name, default: "Segoe UI"]'); - expect(detokenize('"[theme:]"')).to.equal('"[theme:]"'); + expect(detokenize('"[theme:name, default: "Segoe UI"]')).toEqual('"[theme:name, default: "Segoe UI"]'); + expect(detokenize('"[theme:]"')).toEqual('"[theme:]"'); }); it('translates missing themes', () => { - expect(detokenize('"[theme:name]"')).to.equal('inherit'); + 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); - expect(arr.length).to.equal(1); - expect(arr[0].rawString).to.equal(cssString); + const cssString: string = '.sampleClass\n{\n color: #FF0000;\n}\n'; + const arr: IThemingInstruction[] = splitStyles(cssString); + expect(arr).toHaveLength(1); + expect(arr[0].rawString).toEqual(cssString); }); it('splits themable CSS', () => { - const arr: IThemingInstruction[] = splitStyles('.firstClass { color: "[theme: firstColor ]";}\n' + - ' .secondClass { color: "[theme:secondColor, default: #AAA]";}\n .coach { color: #333; }'); - expect(arr.length).to.equal(5); - for (let i: number = 0; i < arr.length; i++) { - if (i % 2 === 0) { // even index should be a string component - expect(typeof arr[i].rawString).to.equal('string'); - } else { // odd index should be a theme instruction object - expect(typeof arr[i].theme).to.equal('string'); - } + const arr: IThemingInstruction[] = splitStyles( + '.firstClass { color: "[theme: firstColor ]";}\n' + + ' .secondClass { color: "[theme:secondColor, default: #AAA]";}\n .coach { color: #333; }' + ); + expect(arr).toHaveLength(5); + for (let i: number = 0; i < arr.length; i++) { + if (i % 2 === 0) { + // even index should be a string component + expect(typeof arr[i].rawString).toEqual('string'); + } else { + // odd index should be a theme instruction object + expect(typeof arr[i].theme).toEqual('string'); } + } }); +}); +describe(loadStyles.name, () => { it('passes the styles to loadStyles override callback', () => { const expected: string = 'xxx.foo { color: #FFF }xxx'; let subject: string | undefined = undefined; @@ -78,7 +118,7 @@ describe('detokenize', () => { configureLoadStyles(callback); loadStyles('.foo { color: "[theme:fooColor, default: #FFF]" }'); - expect(subject).to.equal(expected); + expect(subject).toEqual(expected); configureLoadStyles(undefined); }); diff --git a/libraries/load-themed-styles/tsconfig.json b/libraries/load-themed-styles/tsconfig.json index 0407e17dc62..d6a12420aa1 100644 --- a/libraries/load-themed-styles/tsconfig.json +++ b/libraries/load-themed-styles/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-web.json", + "extends": "./node_modules/local-web-rig/profiles/library/tsconfig-base.json", "compilerOptions": { - "module": "commonjs", - "types": [ - "webpack-env" - ] + "importHelpers": false, + "outDir": "lib-esm", + "declarationDir": "lib-dts", + "lib": ["ES2015"] } } diff --git a/libraries/localization-utilities/.npmignore b/libraries/localization-utilities/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/localization-utilities/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/localization-utilities/CHANGELOG.json b/libraries/localization-utilities/CHANGELOG.json new file mode 100644 index 00000000000..168a589fb91 --- /dev/null +++ b/libraries/localization-utilities/CHANGELOG.json @@ -0,0 +1,3925 @@ +{ + "name": "@rushstack/localization-utilities", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/localization-utilities_v0.12.14", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/localization-utilities_v0.12.13", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/localization-utilities_v0.12.12", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/localization-utilities_v0.12.11", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/localization-utilities_v0.12.10", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/localization-utilities_v0.12.9", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/localization-utilities_v0.12.8", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/localization-utilities_v0.12.7", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/localization-utilities_v0.12.6", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/localization-utilities_v0.12.5", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/localization-utilities_v0.12.4", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/localization-utilities_v0.12.3", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.3`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/localization-utilities_v0.12.2", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/localization-utilities_v0.12.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/localization-utilities_v0.12.0", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value." + }, + { + "comment": "Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.0`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/localization-utilities_v0.11.1", + "date": "Wed, 21 Aug 2024 16:24:51 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where `inferDefaultExportInterfaceNameFromFilename` did not apply." + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/localization-utilities_v0.11.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Expand the typings generator to take a richer set of options for default exports. See `exportAsDefault` in @rushstack/typings-generator's `StringValuesTypingsGenerator`. Also included is another property in `exportAsDefault`: `inferInterfaceNameFromFilename`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/localization-utilities_v0.10.0", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update the schema for `.loc.json` files to allow string names that include the `$` character." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.9.62", + "tag": "@rushstack/localization-utilities_v0.9.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.9.61", + "tag": "@rushstack/localization-utilities_v0.9.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.9.60", + "tag": "@rushstack/localization-utilities_v0.9.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.9.59", + "tag": "@rushstack/localization-utilities_v0.9.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.9.58", + "tag": "@rushstack/localization-utilities_v0.9.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.9.57", + "tag": "@rushstack/localization-utilities_v0.9.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.9.56", + "tag": "@rushstack/localization-utilities_v0.9.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.9.55", + "tag": "@rushstack/localization-utilities_v0.9.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.9.54", + "tag": "@rushstack/localization-utilities_v0.9.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.9.53", + "tag": "@rushstack/localization-utilities_v0.9.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.9.52", + "tag": "@rushstack/localization-utilities_v0.9.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.9.51", + "tag": "@rushstack/localization-utilities_v0.9.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.9.50", + "tag": "@rushstack/localization-utilities_v0.9.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.9.49", + "tag": "@rushstack/localization-utilities_v0.9.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.9.48", + "tag": "@rushstack/localization-utilities_v0.9.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.9.47", + "tag": "@rushstack/localization-utilities_v0.9.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.9.46", + "tag": "@rushstack/localization-utilities_v0.9.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.9.45", + "tag": "@rushstack/localization-utilities_v0.9.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.9.44", + "tag": "@rushstack/localization-utilities_v0.9.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.9.43", + "tag": "@rushstack/localization-utilities_v0.9.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.9.42", + "tag": "@rushstack/localization-utilities_v0.9.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.9.41", + "tag": "@rushstack/localization-utilities_v0.9.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.9.40", + "tag": "@rushstack/localization-utilities_v0.9.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.9.39", + "tag": "@rushstack/localization-utilities_v0.9.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.9.38", + "tag": "@rushstack/localization-utilities_v0.9.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.9.37", + "tag": "@rushstack/localization-utilities_v0.9.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.9.36", + "tag": "@rushstack/localization-utilities_v0.9.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.9.35", + "tag": "@rushstack/localization-utilities_v0.9.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.9.34", + "tag": "@rushstack/localization-utilities_v0.9.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.9.33", + "tag": "@rushstack/localization-utilities_v0.9.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.9.32", + "tag": "@rushstack/localization-utilities_v0.9.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.9.31", + "tag": "@rushstack/localization-utilities_v0.9.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.9.30", + "tag": "@rushstack/localization-utilities_v0.9.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.9.29", + "tag": "@rushstack/localization-utilities_v0.9.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.9.28", + "tag": "@rushstack/localization-utilities_v0.9.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.9.27", + "tag": "@rushstack/localization-utilities_v0.9.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.9.26", + "tag": "@rushstack/localization-utilities_v0.9.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.9.25", + "tag": "@rushstack/localization-utilities_v0.9.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.9.24", + "tag": "@rushstack/localization-utilities_v0.9.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.9.23", + "tag": "@rushstack/localization-utilities_v0.9.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/localization-utilities_v0.9.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/localization-utilities_v0.9.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/localization-utilities_v0.9.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/localization-utilities_v0.9.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/localization-utilities_v0.9.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/localization-utilities_v0.9.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/localization-utilities_v0.9.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/localization-utilities_v0.9.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/localization-utilities_v0.9.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/localization-utilities_v0.9.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/localization-utilities_v0.9.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/localization-utilities_v0.9.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/localization-utilities_v0.9.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/localization-utilities_v0.9.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/localization-utilities_v0.9.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/localization-utilities_v0.9.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/localization-utilities_v0.9.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/localization-utilities_v0.9.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/localization-utilities_v0.9.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/localization-utilities_v0.9.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/localization-utilities_v0.9.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/localization-utilities_v0.9.1", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/localization-utilities_v0.9.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.8.83", + "tag": "@rushstack/localization-utilities_v0.8.83", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.8.82", + "tag": "@rushstack/localization-utilities_v0.8.82", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.8.81", + "tag": "@rushstack/localization-utilities_v0.8.81", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.37`" + } + ] + } + }, + { + "version": "0.8.80", + "tag": "@rushstack/localization-utilities_v0.8.80", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.8.79", + "tag": "@rushstack/localization-utilities_v0.8.79", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.8.78", + "tag": "@rushstack/localization-utilities_v0.8.78", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.8.77", + "tag": "@rushstack/localization-utilities_v0.8.77", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.8.76", + "tag": "@rushstack/localization-utilities_v0.8.76", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.8.75", + "tag": "@rushstack/localization-utilities_v0.8.75", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.8.74", + "tag": "@rushstack/localization-utilities_v0.8.74", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.8.73", + "tag": "@rushstack/localization-utilities_v0.8.73", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.8.72", + "tag": "@rushstack/localization-utilities_v0.8.72", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.8.71", + "tag": "@rushstack/localization-utilities_v0.8.71", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.8.70", + "tag": "@rushstack/localization-utilities_v0.8.70", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.8.69", + "tag": "@rushstack/localization-utilities_v0.8.69", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.8.68", + "tag": "@rushstack/localization-utilities_v0.8.68", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.8.67", + "tag": "@rushstack/localization-utilities_v0.8.67", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.8.66", + "tag": "@rushstack/localization-utilities_v0.8.66", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.8.65", + "tag": "@rushstack/localization-utilities_v0.8.65", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.8.64", + "tag": "@rushstack/localization-utilities_v0.8.64", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.8.63", + "tag": "@rushstack/localization-utilities_v0.8.63", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.8.62", + "tag": "@rushstack/localization-utilities_v0.8.62", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.8.61", + "tag": "@rushstack/localization-utilities_v0.8.61", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.8.60", + "tag": "@rushstack/localization-utilities_v0.8.60", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.8.59", + "tag": "@rushstack/localization-utilities_v0.8.59", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.8.58", + "tag": "@rushstack/localization-utilities_v0.8.58", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.8.57", + "tag": "@rushstack/localization-utilities_v0.8.57", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.8.56", + "tag": "@rushstack/localization-utilities_v0.8.56", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.8.55", + "tag": "@rushstack/localization-utilities_v0.8.55", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.8.54", + "tag": "@rushstack/localization-utilities_v0.8.54", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.8.53", + "tag": "@rushstack/localization-utilities_v0.8.53", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.8.52", + "tag": "@rushstack/localization-utilities_v0.8.52", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.8.51", + "tag": "@rushstack/localization-utilities_v0.8.51", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.8.50", + "tag": "@rushstack/localization-utilities_v0.8.50", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.8.49", + "tag": "@rushstack/localization-utilities_v0.8.49", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.8.48", + "tag": "@rushstack/localization-utilities_v0.8.48", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.8.47", + "tag": "@rushstack/localization-utilities_v0.8.47", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.8.46", + "tag": "@rushstack/localization-utilities_v0.8.46", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.8.45", + "tag": "@rushstack/localization-utilities_v0.8.45", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.8.44", + "tag": "@rushstack/localization-utilities_v0.8.44", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.8.43", + "tag": "@rushstack/localization-utilities_v0.8.43", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.8.42", + "tag": "@rushstack/localization-utilities_v0.8.42", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.8.41", + "tag": "@rushstack/localization-utilities_v0.8.41", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.8.40", + "tag": "@rushstack/localization-utilities_v0.8.40", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.8.39", + "tag": "@rushstack/localization-utilities_v0.8.39", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.8.38", + "tag": "@rushstack/localization-utilities_v0.8.38", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.8.37", + "tag": "@rushstack/localization-utilities_v0.8.37", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.8.36", + "tag": "@rushstack/localization-utilities_v0.8.36", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.12`" + } + ] + } + }, + { + "version": "0.8.35", + "tag": "@rushstack/localization-utilities_v0.8.35", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.8.34", + "tag": "@rushstack/localization-utilities_v0.8.34", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.8.33", + "tag": "@rushstack/localization-utilities_v0.8.33", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.8.32", + "tag": "@rushstack/localization-utilities_v0.8.32", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.8.31", + "tag": "@rushstack/localization-utilities_v0.8.31", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.8.30", + "tag": "@rushstack/localization-utilities_v0.8.30", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.8.29", + "tag": "@rushstack/localization-utilities_v0.8.29", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.8.28", + "tag": "@rushstack/localization-utilities_v0.8.28", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.8.27", + "tag": "@rushstack/localization-utilities_v0.8.27", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.8.26", + "tag": "@rushstack/localization-utilities_v0.8.26", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.8.25", + "tag": "@rushstack/localization-utilities_v0.8.25", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.8.24", + "tag": "@rushstack/localization-utilities_v0.8.24", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.8.23", + "tag": "@rushstack/localization-utilities_v0.8.23", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.8.22", + "tag": "@rushstack/localization-utilities_v0.8.22", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.8.21", + "tag": "@rushstack/localization-utilities_v0.8.21", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.8.20", + "tag": "@rushstack/localization-utilities_v0.8.20", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.8.19", + "tag": "@rushstack/localization-utilities_v0.8.19", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.8.18", + "tag": "@rushstack/localization-utilities_v0.8.18", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.8.17", + "tag": "@rushstack/localization-utilities_v0.8.17", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.8.16", + "tag": "@rushstack/localization-utilities_v0.8.16", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.8.15", + "tag": "@rushstack/localization-utilities_v0.8.15", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/localization-utilities_v0.8.14", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/localization-utilities_v0.8.13", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/localization-utilities_v0.8.12", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/localization-utilities_v0.8.11", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/localization-utilities_v0.8.10", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/localization-utilities_v0.8.9", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/localization-utilities_v0.8.8", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/localization-utilities_v0.8.7", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/localization-utilities_v0.8.6", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/localization-utilities_v0.8.5", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/localization-utilities_v0.8.4", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/localization-utilities_v0.8.3", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/localization-utilities_v0.8.2", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/localization-utilities_v0.8.1", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/localization-utilities_v0.8.0", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to output typings to additional output folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/localization-utilities_v0.7.3", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/localization-utilities_v0.7.2", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/localization-utilities_v0.7.1", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/localization-utilities_v0.7.0", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove the legacy RESX reader functions." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.27`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/localization-utilities_v0.6.0", + "date": "Thu, 16 Jun 2022 22:49:55 GMT", + "comments": { + "patch": [ + { + "comment": "Allow the package to be webpacked." + } + ], + "minor": [ + { + "comment": "Remove the validation of RESX string names." + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/localization-utilities_v0.5.0", + "date": "Thu, 16 Jun 2022 00:20:22 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor the RESX parser to follow a similar API as the other parsers." + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/localization-utilities_v0.4.0", + "date": "Tue, 14 Jun 2022 23:11:36 GMT", + "comments": { + "minor": [ + { + "comment": "Add the ability to ignore strings from loc file parsing." + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/localization-utilities_v0.3.0", + "date": "Tue, 14 Jun 2022 00:17:29 GMT", + "comments": { + "minor": [ + { + "comment": "Expose each parser directly so that they can be used with arbitrary file extensions." + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/localization-utilities_v0.2.1", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/localization-utilities_v0.2.0", + "date": "Fri, 03 Jun 2022 00:11:05 GMT", + "comments": { + "minor": [ + { + "comment": "Add the ability to tweak string comments in generated typings." + }, + { + "comment": "Include an option to ignore strings from typings generation." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/localization-utilities_v0.1.0", + "date": "Wed, 01 Jun 2022 23:31:32 GMT", + "comments": { + "minor": [ + { + "comment": "Initial project creation." + } + ] + } + } + ] +} diff --git a/libraries/localization-utilities/CHANGELOG.md b/libraries/localization-utilities/CHANGELOG.md new file mode 100644 index 00000000000..246ff915db2 --- /dev/null +++ b/libraries/localization-utilities/CHANGELOG.md @@ -0,0 +1,1138 @@ +# Change Log - @rushstack/localization-utilities + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.12.14 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.12.13 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.12.12 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.12.11 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.12.10 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.12.9 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.12.8 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.12.7 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.12.6 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.12.5 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.12.4 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.12.3 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.12.2 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.12.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.12.0 +Mon, 26 Aug 2024 02:00:11 GMT + +### Minor changes + +- Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value. +- Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`. + +## 0.11.1 +Wed, 21 Aug 2024 16:24:51 GMT + +### Patches + +- Fix an issue where `inferDefaultExportInterfaceNameFromFilename` did not apply. + +## 0.11.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Expand the typings generator to take a richer set of options for default exports. See `exportAsDefault` in @rushstack/typings-generator's `StringValuesTypingsGenerator`. Also included is another property in `exportAsDefault`: `inferInterfaceNameFromFilename`. + +## 0.10.0 +Mon, 12 Aug 2024 22:16:04 GMT + +### Minor changes + +- Update the schema for `.loc.json` files to allow string names that include the `$` character. + +## 0.9.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.9.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.9.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.9.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.9.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.9.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.9.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.9.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.9.54 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 0.9.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.9.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.9.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.9.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.9.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.9.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.9.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.9.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.9.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.9.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.9.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.9.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.9.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.9.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.9.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.9.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.9.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.9.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.9.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.9.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.9.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.9.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.9.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.9.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.9.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.9.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.9.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.9.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.9.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.9.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.9.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.9.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.9.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.9.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.9.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.9.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.9.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.9.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.9.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.9.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.9.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.9.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.9.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.9.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.9.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.9.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.9.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.9.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.9.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.9.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.9.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.9.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.9.1 +Tue, 19 Sep 2023 15:21:51 GMT + +_Version update only_ + +## 0.9.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.8.83 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.8.82 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.8.81 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.8.80 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.8.79 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.8.78 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.8.77 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.8.76 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.8.75 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.8.74 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.8.73 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.8.72 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.8.71 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.8.70 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.8.69 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.8.68 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.8.67 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.8.66 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.8.65 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.8.64 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.8.63 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.8.62 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.8.61 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.8.60 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.8.59 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.8.58 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.8.57 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.8.56 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 0.8.55 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.8.54 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.8.53 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.8.52 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.8.51 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.8.50 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.8.49 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.8.48 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.8.47 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.8.46 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.8.45 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.8.44 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.8.43 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.8.42 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.8.41 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.8.40 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.8.39 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.8.38 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.8.37 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.8.36 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 0.8.35 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.8.34 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.8.33 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.8.32 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.8.31 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.8.30 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.8.29 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.8.28 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.8.27 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.8.26 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.8.25 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.8.24 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.8.23 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.8.22 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.8.21 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.8.20 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.8.19 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.8.18 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.8.17 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.8.16 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.8.15 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.8.14 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.8.13 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.8.12 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.8.11 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.8.10 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.8.9 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.8.8 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.8.7 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.8.6 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.8.5 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.8.4 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.8.3 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.8.2 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.8.1 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.8.0 +Sat, 25 Jun 2022 01:54:29 GMT + +### Minor changes + +- Add an option to output typings to additional output folders. + +## 0.7.3 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.7.2 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.7.1 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.7.0 +Fri, 17 Jun 2022 00:16:18 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove the legacy RESX reader functions. + +## 0.6.0 +Thu, 16 Jun 2022 22:49:55 GMT + +### Minor changes + +- Remove the validation of RESX string names. + +### Patches + +- Allow the package to be webpacked. + +## 0.5.0 +Thu, 16 Jun 2022 00:20:22 GMT + +### Minor changes + +- Refactor the RESX parser to follow a similar API as the other parsers. + +## 0.4.0 +Tue, 14 Jun 2022 23:11:36 GMT + +### Minor changes + +- Add the ability to ignore strings from loc file parsing. + +## 0.3.0 +Tue, 14 Jun 2022 00:17:29 GMT + +### Minor changes + +- Expose each parser directly so that they can be used with arbitrary file extensions. + +## 0.2.1 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.2.0 +Fri, 03 Jun 2022 00:11:05 GMT + +### Minor changes + +- Add the ability to tweak string comments in generated typings. +- Include an option to ignore strings from typings generation. + +## 0.1.0 +Wed, 01 Jun 2022 23:31:32 GMT + +### Minor changes + +- Initial project creation. + diff --git a/libraries/localization-utilities/LICENSE b/libraries/localization-utilities/LICENSE new file mode 100644 index 00000000000..6ead309bce8 --- /dev/null +++ b/libraries/localization-utilities/LICENSE @@ -0,0 +1,24 @@ +@rushstack/localization-utilities + +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/localization-utilities/README.md b/libraries/localization-utilities/README.md new file mode 100644 index 00000000000..87734ef69ca --- /dev/null +++ b/libraries/localization-utilities/README.md @@ -0,0 +1,3 @@ +# @rushstack/localization-utilities + +This library provides a set of utilities for working with localization files. diff --git a/libraries/localization-utilities/config/api-extractor.json b/libraries/localization-utilities/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/localization-utilities/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/localization-utilities/config/rig.json b/libraries/localization-utilities/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/localization-utilities/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/localization-utilities/config/typescript.json b/libraries/localization-utilities/config/typescript.json new file mode 100644 index 00000000000..5680fc18ddc --- /dev/null +++ b/libraries/localization-utilities/config/typescript.json @@ -0,0 +1,14 @@ +{ + "extends": "local-node-rig/profiles/default/config/typescript.json", + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [".resx"] + } +} 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 new file mode 100644 index 00000000000..ee224059fb7 --- /dev/null +++ b/libraries/localization-utilities/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/localization-utilities", + "version": "0.14.7", + "description": "This plugin contains some useful functions for localization.", + "main": "lib/index.js", + "typings": "dist/localization-utilities.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/localization-utilities" + }, + "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:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/typings-generator": "workspace:*", + "pseudolocale": "~1.1.0", + "xmldoc": "~1.1.2" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/xmldoc": "1.1.4", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/libraries/localization-utilities/src/LocFileParser.ts b/libraries/localization-utilities/src/LocFileParser.ts new file mode 100644 index 00000000000..a15c3adce17 --- /dev/null +++ b/libraries/localization-utilities/src/LocFileParser.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IgnoreStringFunction, ILocalizationFile, IParseFileOptions } from './interfaces'; +import { parseLocJson } from './parsers/parseLocJson'; +import { parseResJson } from './parsers/parseResJson'; +import { type IParseResxOptionsBase, parseResx } from './parsers/parseResx'; + +/** + * @public + */ +export type ParserKind = 'resx' | 'loc.json' | 'resjson'; + +/** + * @public + */ +export interface IParseLocFileOptions extends IParseFileOptions, IParseResxOptionsBase { + parser?: ParserKind; +} + +interface IParseCacheEntry { + content: string; + parsedFile: ILocalizationFile; + ignoreString: IgnoreStringFunction | undefined; +} + +const parseCache: Map = new Map(); + +export function selectParserByFilePath(filePath: string): ParserKind { + if (/\.resx$/i.test(filePath)) { + return 'resx'; + } else if (/\.(resx|loc)\.json$/i.test(filePath)) { + return 'loc.json'; + } else if (/\.resjson$/i.test(filePath)) { + return 'resjson'; + } else { + throw new Error(`Unsupported file extension in file: ${filePath}`); + } +} + +/** + * @public + */ +export function parseLocFile(options: IParseLocFileOptions): ILocalizationFile { + const { parser = selectParserByFilePath(options.filePath) } = options; + + const fileCacheKey: string = `${options.filePath}?${parser}&${options.resxNewlineNormalization || 'none'}`; + const parseCacheEntry: IParseCacheEntry | undefined = parseCache.get(fileCacheKey); + if (parseCacheEntry) { + if ( + parseCacheEntry.content === options.content && + parseCacheEntry.ignoreString === options.ignoreString + ) { + return parseCacheEntry.parsedFile; + } + } + + let parsedFile: ILocalizationFile; + switch (parser) { + case 'resx': { + parsedFile = parseResx(options); + break; + } + + case 'loc.json': { + parsedFile = parseLocJson(options); + break; + } + + case 'resjson': { + parsedFile = parseResJson(options); + break; + } + + default: { + throw new Error(`Unsupported parser: ${parser}`); + } + } + + parseCache.set(fileCacheKey, { + content: options.content, + parsedFile, + ignoreString: options.ignoreString + }); + + return parsedFile; +} diff --git a/libraries/localization-utilities/src/Pseudolocalization.ts b/libraries/localization-utilities/src/Pseudolocalization.ts new file mode 100644 index 00000000000..af6cc69161a --- /dev/null +++ b/libraries/localization-utilities/src/Pseudolocalization.ts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import vm from 'node:vm'; + +import { FileSystem } from '@rushstack/node-core-library'; + +import type { IPseudolocaleOptions } from './interfaces'; + +const pseudolocalePath: string = require.resolve('pseudolocale/pseudolocale.min.js'); + +interface IPseudolocale { + option: IPseudolocaleOptions; + str(str: string): string; +} + +/** + * Get a function that pseudolocalizes a string. + * + * @public + */ +export function getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string { + const pseudolocaleCode: string = FileSystem.readFile(pseudolocalePath); + const context: { + pseudolocale: IPseudolocale | undefined; + } = { + pseudolocale: undefined + }; + + // Load pseudolocale in an isolated context because the configuration for is stored on a singleton + vm.runInNewContext(pseudolocaleCode, context); + const { pseudolocale } = context; + if (!pseudolocale) { + throw new Error(`Failed to load pseudolocale module`); + } + + Object.assign(pseudolocale.option, options); + // `pseudolocale.str` captures `pseudolocale` in its closure and refers to `pseudolocale.option`. + return pseudolocale.str; +} diff --git a/libraries/localization-utilities/src/TypingsGenerator.ts b/libraries/localization-utilities/src/TypingsGenerator.ts new file mode 100644 index 00000000000..e70bab1aa8b --- /dev/null +++ b/libraries/localization-utilities/src/TypingsGenerator.ts @@ -0,0 +1,189 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + StringValuesTypingsGenerator, + type IStringValueTypings, + type IExportAsDefaultOptions, + type IStringValueTyping, + type ITypingsGeneratorBaseOptions +} from '@rushstack/typings-generator'; +import { FileSystem, type NewlineKind } from '@rushstack/node-core-library'; + +import type { IgnoreStringFunction, ILocalizationFile } from './interfaces'; +import { parseLocFile } from './LocFileParser'; + +/** + * @public + */ +export interface IInferInterfaceNameExportAsDefaultOptions + extends Omit { + /** + * When `exportAsDefault` is true and this option is true, the default export interface name will be inferred + * from the filename. + */ + inferInterfaceNameFromFilename?: boolean; +} + +/** + * @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, + stringName: string + ) => string | undefined; +} + +/** + * This is a simple tool that generates .d.ts files for .loc.json, .resx.json, .resjson, and .resx files. + * + * @public + */ +export class TypingsGenerator extends StringValuesTypingsGenerator { + public constructor(options: ITypingsGeneratorOptions) { + const { + ignoreString, + 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'], + getAdditionalOutputFiles: getJsonPaths, + // eslint-disable-next-line @typescript-eslint/naming-convention + parseAndGenerateTypings: async ( + content: string, + filePath: string, + relativeFilePath: string + ): Promise => { + const locFileData: ILocalizationFile = parseLocFile({ + filePath, + content, + terminal: this.terminal, + resxNewlineNormalization, + ignoreMissingResxComments, + ignoreString + }); + + const typings: IStringValueTyping[] = []; + + 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 + }); + } + + 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('.'); + if (filePath.slice(extensionIndex).toLowerCase() === '.json') { + extensionIndex = filePath.lastIndexOf('.', extensionIndex - 1); + } + + const fileNameWithoutExtension: string = filePath.substring(lastSlashIndex + 1, extensionIndex); + const normalizedFileName: string = fileNameWithoutExtension.replace(/[^a-zA-Z0-9$_]/g, ''); + const firstCharUpperCased: string = normalizedFileName.charAt(0).toUpperCase(); + let interfaceName: string | undefined = `I${firstCharUpperCased}${normalizedFileName.slice(1)}`; + + if (!interfaceName.endsWith('strings') && !interfaceName.endsWith('Strings')) { + interfaceName += 'Strings'; + } + + return { + typings, + exportAsDefault: { + interfaceName + } + }; + } else { + return { + typings + }; + } + } + }); + } +} diff --git a/libraries/localization-utilities/src/index.ts b/libraries/localization-utilities/src/index.ts new file mode 100644 index 00000000000..b72ad1bc3ee --- /dev/null +++ b/libraries/localization-utilities/src/index.ts @@ -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. + +/** + * Some utilities for working with Rush Stack localization files. + * + * @packageDocumentation + */ + +export type { + ILocalizationFile, + ILocalizedString, + IPseudolocaleOptions, + IParseFileOptions, + IgnoreStringFunction +} from './interfaces'; +export { parseLocJson } from './parsers/parseLocJson'; +export { parseResJson } from './parsers/parseResJson'; +export { parseResx, type IParseResxOptions, type IParseResxOptionsBase } from './parsers/parseResx'; +export { parseLocFile, type IParseLocFileOptions, type ParserKind } from './LocFileParser'; +export { + type ITypingsGeneratorOptions, + type IInferInterfaceNameExportAsDefaultOptions, + TypingsGenerator +} from './TypingsGenerator'; +export { getPseudolocalizer } from './Pseudolocalization'; diff --git a/libraries/localization-utilities/src/interfaces.ts b/libraries/localization-utilities/src/interfaces.ts new file mode 100644 index 00000000000..94fecf12a22 --- /dev/null +++ b/libraries/localization-utilities/src/interfaces.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. + +/** + * Options for the pseudolocale library. + * + * @internalRemarks + * Eventually this should be replaced with DefinitelyTyped types. + * + * @public + */ +export interface IPseudolocaleOptions { + prepend?: string; + append?: string; + delimiter?: string; + startDelimiter?: string; + endDelimiter?: string; + extend?: number; + override?: string; +} + +/** + * @public + */ +export interface ILocalizationFile { + [stringName: string]: ILocalizedString; +} + +/** + * @public + */ +export interface ILocalizedString { + value: string; + comment?: string; +} + +/** + * @public + */ +export interface IParseFileOptions { + content: string; + filePath: string; + /** + * Optionally, provide a function that will be called for each string. If the function returns `true` + * the string will not be included. + */ + ignoreString?: IgnoreStringFunction; +} + +/** + * @public + */ +export type IgnoreStringFunction = (filePath: string, stringName: string) => boolean; diff --git a/libraries/localization-utilities/src/parsers/parseLocJson.ts b/libraries/localization-utilities/src/parsers/parseLocJson.ts new file mode 100644 index 00000000000..6070ca6d8f4 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/parseLocJson.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import type { ILocalizationFile, IParseFileOptions } from '../interfaces'; +import locJsonSchema from '../schemas/locJson.schema.json'; + +const LOC_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(locJsonSchema); + +/** + * @public + */ +export function parseLocJson({ content, filePath, ignoreString }: IParseFileOptions): ILocalizationFile { + const parsedFile: ILocalizationFile = JsonFile.parseString(content); + try { + LOC_JSON_SCHEMA.validateObject(parsedFile, filePath, { ignoreSchemaField: true }); + } catch (e) { + throw new Error(`The loc file is invalid. Error: ${e}`); + } + + // 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; +} diff --git a/libraries/localization-utilities/src/parsers/parseResJson.ts b/libraries/localization-utilities/src/parsers/parseResJson.ts new file mode 100644 index 00000000000..a8752a222c2 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/parseResJson.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 { JsonFile } from '@rushstack/node-core-library'; + +import type { ILocalizationFile, IParseFileOptions } from '../interfaces'; + +/** + * @public + */ +export function parseResJson({ content, ignoreString, filePath }: IParseFileOptions): ILocalizationFile { + const resjsonFile: Record = JsonFile.parseString(content); + const parsedFile: ILocalizationFile = {}; + + const usedComments: Map = new Map(); + for (const [key, value] of Object.entries(resjsonFile)) { + if (key.startsWith('_') && key.endsWith('.comment')) { + if (!usedComments.has(key)) { + usedComments.set(key, false); + } + } else { + const commentKey: string = `_${key}.comment`; + const comment: string | undefined = resjsonFile[commentKey]; + usedComments.set(commentKey, true); + + if (!ignoreString?.(filePath, key)) { + parsedFile[key] = { value, comment }; + } + } + } + + const orphanComments: string[] = []; + for (const [key, used] of usedComments) { + if (!used) { + orphanComments.push(key.slice(1, -'.comment'.length)); + } + } + + if (orphanComments.length > 0) { + throw new Error( + 'The resjson file is invalid. Comments exist for the following string keys ' + + `that don't have values: ${orphanComments.join(', ')}.` + ); + } + + return parsedFile; +} diff --git a/libraries/localization-utilities/src/parsers/parseResx.ts b/libraries/localization-utilities/src/parsers/parseResx.ts new file mode 100644 index 00000000000..d7f72d4a012 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/parseResx.ts @@ -0,0 +1,285 @@ +// 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 type { ILocalizedString, ILocalizationFile, IParseFileOptions } from '../interfaces'; + +/** + * @public + */ +export interface IParseResxOptions extends IParseFileOptions, IParseResxOptionsBase {} + +/** + * @public + */ +export interface IParseResxOptionsBase { + terminal: ITerminal; + resxNewlineNormalization: NewlineKind | undefined; + ignoreMissingResxComments: boolean | undefined; +} + +interface ILoggingFunctions { + logError: (message: string) => void; + logWarning: (message: string) => void; + logFileError: (message: string, filePath: string, line?: number, position?: number) => void; + logFileWarning: (message: string, filePath: string, line?: number, position?: number) => void; +} + +interface IResxReaderOptionsInternal extends Omit { + loggingFunctions: ILoggingFunctions; +} + +/** + * @public + */ +export function parseResx(options: IParseResxOptions): ILocalizationFile { + const writeError: (message: string) => void = options.terminal.writeErrorLine.bind(options.terminal); + const writeWarning: (message: string) => void = options.terminal.writeWarningLine.bind(options.terminal); + const loggingFunctions: ILoggingFunctions = { + logError: (message: string) => writeError(message), + logWarning: (message: string) => writeWarning(message), + logFileError: (message: string, filePath: string, line?: number, position?: number) => { + _logWithLocation(writeError, message, filePath, line, position); + }, + logFileWarning: (message: string, filePath: string, line?: number, position?: number) => { + _logWithLocation(writeWarning, message, filePath, line, position); + } + }; + + return _readResxAsLocFileInternal({ + ...options, + loggingFunctions + }); +} + +function _readResxAsLocFileInternal(options: IResxReaderOptionsInternal): ILocalizationFile { + const { ignoreString } = options; + const xmlDocument: XmlDocument = new XmlDocument(options.content); + + if (xmlDocument.name !== 'root') { + _logErrorWithLocation( + options, + `Expected RESX to have a "root" element, found "${xmlDocument.name}"`, + xmlDocument + ); + } + + const locFile: ILocalizationFile = {}; + + for (const childNode of xmlDocument.children) { + switch (childNode.type) { + case 'element': { + switch (childNode.name) { + case 'data': { + const stringName: string = childNode.attr.name; + if (!stringName) { + _logErrorWithLocation(options, 'Unexpected missing or empty string name', childNode); + } else { + if (locFile.hasOwnProperty(stringName)) { + _logErrorWithLocation(options, `Duplicate string value "${stringName}"`, childNode); + } + + const locString: ILocalizedString | undefined = _readDataElement(options, childNode); + + if (locString && !ignoreString?.(options.filePath, stringName)) { + locFile[stringName] = locString; + } + } + + break; + } + + // Other allowed elements + case 'xsd:schema': + case 'resheader': + break; + + default: + _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode); + } + + break; + } + + case 'text': { + if (childNode.text.trim() !== '') { + _logErrorWithLocation(options, 'Found unexpected non-empty text node in RESX'); + } + + break; + } + + case 'comment': + break; + + default: + _logErrorWithLocation(options, `Unexpected ${childNode.type} child in RESX`); + break; + } + } + + return locFile; +} + +function _readDataElement( + options: IResxReaderOptionsInternal, + dataElement: XmlElement +): ILocalizedString | undefined { + let foundCommentElement: boolean = false; + let foundValueElement: boolean = false; + let comment: string | undefined = undefined; + let value: string | undefined = undefined; + + for (const childNode of dataElement.children) { + switch (childNode.type) { + case 'element': { + switch (childNode.name) { + case 'value': { + if (foundValueElement) { + _logErrorWithLocation(options, 'Duplicate element found', childNode); + } else { + foundValueElement = true; + value = _readTextElement(options, childNode); + if (value && options.resxNewlineNormalization) { + value = Text.convertTo(value, options.resxNewlineNormalization); + } + } + + break; + } + + case 'comment': { + if (foundCommentElement) { + _logErrorWithLocation(options, 'Duplicate element found', childNode); + } else { + foundCommentElement = true; + comment = _readTextElement(options, childNode); + } + + break; + } + + default: + _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode); + break; + } + + break; + } + + case 'text': { + if (childNode.text.trim() !== '') { + _logErrorWithLocation( + options, + 'Found unexpected non-empty text node in RESX element', + dataElement + ); + } + + break; + } + + case 'comment': + break; + + default: + _logErrorWithLocation( + options, + `Unexpected ${childNode.type} child in RESX element`, + dataElement + ); + } + } + + if (!foundValueElement) { + _logErrorWithLocation(options, 'Missing string value in element', dataElement); + } else { + if (comment === undefined && options.ignoreMissingResxComments === false) { + _logWarningWithLocation(options, 'Missing string comment in element', dataElement); + } + + return { + value: value || '', + comment + }; + } +} + +function _readTextElement(options: IResxReaderOptionsInternal, element: XmlElement): string | undefined { + let foundText: string | undefined = undefined; + + for (const childNode of element.children) { + switch (childNode.type) { + case 'cdata': + case 'text': { + if (foundText !== undefined) { + _logErrorWithLocation(options, 'More than one child node found containing text content', element); + break; + } + + foundText = childNode.type === 'text' ? childNode.text : childNode.cdata; + break; + } + + case 'comment': + break; + + case 'element': + _logErrorWithLocation(options, `Unexpected element`, childNode); + break; + + default: + _logErrorWithLocation(options, `Unexpected ${element.type} child`, element); + break; + } + } + + return foundText; +} + +function _logErrorWithLocation( + options: IResxReaderOptionsInternal, + message: string, + element?: XmlElement | XmlDocument +): void { + if (element) { + options.loggingFunctions.logFileError(message, options.filePath, element.line + 1, element.column + 1); + } else { + options.loggingFunctions.logFileError(message, options.filePath); + } +} + +function _logWarningWithLocation( + options: IResxReaderOptionsInternal, + message: string, + element?: XmlElement | XmlDocument +): void { + if (element) { + options.loggingFunctions.logFileWarning(message, options.filePath, element.line + 1, element.column + 1); + } else { + options.loggingFunctions.logFileWarning(message, options.filePath); + } +} + +function _logWithLocation( + loggingFn: (message: string) => void, + message: string, + filePath: string, + line?: number, + position?: number +): void { + let location: string; + if (position !== undefined) { + location = `${filePath}(${line},${position})`; + } else if (line !== undefined) { + location = `${filePath}(${line})`; + } else { + location = filePath; + } + + loggingFn(`${location}: ${message}`); +} 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 new file mode 100644 index 00000000000..9d1c9474671 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseLocJson.test.ts.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseLocJson correctly ignores a string: Loc file 1`] = ` +Object { + "foo": Object { + "comment": "A string", + "value": "Foo", + }, +} +`; + +exports[`parseLocJson correctly ignores a string: ignoreStrings calls 1`] = ` +Array [ + Array [ + "test.loc.json", + "foo", + ], + Array [ + "test.loc.json", + "bar", + ], +] +`; + +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 { + "comment": "Another string", + "value": "Bar", + }, + "foo": Object { + "comment": "A string", + "value": "Foo", + }, +} +`; + +exports[`parseLocJson throws on invalid file 1`] = ` +"The loc file is invalid. Error: Error: JSON validation failed: +test.loc.json + +Error: #/foo + 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 new file mode 100644 index 00000000000..525d98680ef --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResJson.test.ts.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseResJson correctly ignores a string: Loc file 1`] = ` +Object { + "foo": Object { + "comment": "A string", + "value": "Foo", + }, +} +`; + +exports[`parseResJson correctly ignores a string: ignoreStrings calls 1`] = ` +Array [ + Array [ + "test.resjson", + "foo", + ], + Array [ + "test.resjson", + "bar", + ], +] +`; + +exports[`parseResJson parses a valid file 1`] = ` +Object { + "bar": Object { + "comment": "Another string", + "value": "Bar", + }, + "foo": Object { + "comment": "A string", + "value": "Foo", + }, +} +`; + +exports[`parseResJson throws on excess comments 1`] = `"The resjson file is invalid. Comments exist for the following string keys that don't have values: bar."`; 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 new file mode 100644 index 00000000000..477b13c81b5 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResx.test.ts.snap @@ -0,0 +1,144 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseResx correctly ignores a string: Loc file 1`] = ` +Object { + "foo": Object { + "comment": "Foo", + "value": "foo", + }, +} +`; + +exports[`parseResx correctly ignores a string: ignoreStrings calls 1`] = ` +Array [ + Array [ + "test.resx", + "foo", + ], + Array [ + "test.resx", + "bar", + ], +] +`; + +exports[`parseResx correctly ignores a string: terminal output 1`] = `Object {}`; + +exports[`parseResx fails to parse a RESX file with a duplicate string: Loc file 1`] = ` +Object { + "stringA": Object { + "comment": undefined, + "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]", +} +`; + +exports[`parseResx ignoreMissingResxComments when set to false, warns on a missing comment: Loc file 1`] = ` +Object { + "stringWithoutAComment": Object { + "comment": undefined, + "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]", +} +`; + +exports[`parseResx ignoreMissingResxComments when set to true, ignores a missing comment: Loc file 1`] = ` +Object { + "stringWithoutAComment": Object { + "comment": undefined, + "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 undefined, warns on a missing comment: Loc file 1`] = ` +Object { + "stringWithoutAComment": Object { + "comment": undefined, + "value": "String without a comment", + }, +} +`; + +exports[`parseResx ignoreMissingResxComments when set to undefined, warns on a missing comment: terminal output 1`] = `Object {}`; + +exports[`parseResx parses a valid file with a schema: Loc file 1`] = ` +Object { + "bar": Object { + "comment": "Bar", + "value": "bar", + }, + "foo": Object { + "comment": "Foo", + "value": "foo", + }, +} +`; + +exports[`parseResx parses a valid file with a schema: terminal output 1`] = `Object {}`; + +exports[`parseResx parses a valid file with quotemarks: Loc file 1`] = ` +Object { + "stringWithQuotes": Object { + "comment": "RESX string with quotemarks", + "value": "\\"RESX string with quotemarks\\"", + }, +} +`; + +exports[`parseResx parses a valid file with quotemarks: terminal output 1`] = `Object {}`; + +exports[`parseResx prints an error on invalid XML: Loc file 1`] = ` +Object { + "foo": Object { + "comment": "Foo", + "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]", +} +`; + +exports[`parseResx resxNewlineNormalization when set to CrLf, normalizes to CrLf: Loc file 1`] = ` +Object { + "stringWithTabsAndNewlines": Object { + "comment": "RESX string with newlines and tabs", + "value": " + RESX string with newlines and tabs + ", + }, +} +`; + +exports[`parseResx resxNewlineNormalization when set to CrLf, normalizes to CrLf: terminal output 1`] = `Object {}`; + +exports[`parseResx resxNewlineNormalization when set to Lf, normalizes to Lf: Loc file 1`] = ` +Object { + "stringWithTabsAndNewlines": Object { + "comment": "RESX string with newlines and tabs", + "value": " + RESX string with newlines and tabs + ", + }, +} +`; + +exports[`parseResx resxNewlineNormalization when set to Lf, normalizes to Lf: terminal output 1`] = `Object {}`; diff --git a/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts b/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts new file mode 100644 index 00000000000..f1308b303f9 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IgnoreStringFunction } from '../../interfaces'; +import { parseLocJson } from '../parseLocJson'; + +describe(parseLocJson.name, () => { + it('parses a valid file', () => { + const content: string = JSON.stringify({ + foo: { + value: 'Foo', + comment: 'A string' + }, + bar: { + value: 'Bar', + comment: 'Another string' + } + }); + + expect( + parseLocJson({ + content, + filePath: 'test.loc.json' + }) + ).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: { + value: 'Foo', + baz: 'A string' + } + }); + + expect(() => + parseLocJson({ + content, + filePath: 'test.loc.json' + }) + ).toThrowErrorMatchingSnapshot(); + }); + + it('correctly ignores a string', () => { + const content: string = JSON.stringify({ + foo: { + value: 'Foo', + comment: 'A string' + }, + bar: { + value: 'Bar', + comment: 'Another string' + } + }); + + const ignoredStringFunction: IgnoreStringFunction = jest + .fn() + .mockImplementation( + (fileName: string, stringName: string) => fileName === 'test.loc.json' && stringName === 'bar' + ); + + expect( + parseLocJson({ + content, + filePath: 'test.loc.json', + ignoreString: ignoredStringFunction + }) + ).toMatchSnapshot('Loc file'); + + expect((ignoredStringFunction as unknown as jest.SpyInstance).mock.calls).toMatchSnapshot( + 'ignoreStrings calls' + ); + }); +}); diff --git a/libraries/localization-utilities/src/parsers/test/parseResJson.test.ts b/libraries/localization-utilities/src/parsers/test/parseResJson.test.ts new file mode 100644 index 00000000000..a59a3951df0 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/parseResJson.test.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. + +import type { IgnoreStringFunction } from '../../interfaces'; +import { parseResJson } from '../parseResJson'; + +describe(parseResJson.name, () => { + it('parses a valid file', () => { + const content: string = JSON.stringify({ + foo: 'Foo', + '_foo.comment': 'A string', + bar: 'Bar', + '_bar.comment': 'Another string' + }); + + expect( + parseResJson({ + content, + filePath: 'test.resjson' + }) + ).toMatchSnapshot(); + }); + + it('throws on excess comments', () => { + const content: string = JSON.stringify({ + foo: 'Foo', + '_bar.comment': 'A string' + }); + + expect(() => + parseResJson({ + content, + filePath: 'test.resjson' + }) + ).toThrowErrorMatchingSnapshot(); + }); + + it('correctly ignores a string', () => { + const content: string = JSON.stringify({ + foo: 'Foo', + '_foo.comment': 'A string', + bar: 'Bar', + '_bar.comment': 'Another string' + }); + + const ignoredStringFunction: IgnoreStringFunction = jest + .fn() + .mockImplementation( + (fileName: string, stringName: string) => fileName === 'test.resjson' && stringName === 'bar' + ); + + expect( + parseResJson({ + content, + filePath: 'test.resjson', + ignoreString: ignoredStringFunction + }) + ).toMatchSnapshot('Loc file'); + + expect((ignoredStringFunction as unknown as jest.SpyInstance).mock.calls).toMatchSnapshot( + 'ignoreStrings calls' + ); + }); +}); diff --git a/libraries/localization-utilities/src/parsers/test/parseResx.test.ts b/libraries/localization-utilities/src/parsers/test/parseResx.test.ts new file mode 100644 index 00000000000..bc914847d18 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/parseResx.test.ts @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, NewlineKind } from '@rushstack/node-core-library'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import type { IgnoreStringFunction } from '../../interfaces'; +import { type IParseResxOptions, parseResx } from '../parseResx'; + +describe(parseResx.name, () => { + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + }); + + 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'); + }); + + async function testResxAsync( + filename: + | 'invalidXml' + | 'resxWithSchema' + | 'stringWithoutComment' + | 'stringWithQuotemarks' + | 'withNewlines' + | 'resxWithDuplicateEntry', + optionsOverride: Partial = {} + ): Promise { + const content: string = await FileSystem.readFileAsync(`${__dirname}/testResxFiles/${filename}.resx`); + + expect( + parseResx({ + content, + filePath: 'test.resx', + terminal, + ignoreMissingResxComments: undefined, + resxNewlineNormalization: undefined, + ...optionsOverride + }) + ).toMatchSnapshot('Loc file'); + } + + it('parses a valid file with a schema', async () => { + await testResxAsync('resxWithSchema'); + }); + + it('parses a valid file with quotemarks', async () => { + await testResxAsync('stringWithQuotemarks'); + }); + + it('prints an error on invalid XML', async () => { + await testResxAsync('invalidXml'); + }); + + it('correctly ignores a string', async () => { + const ignoredStringFunction: IgnoreStringFunction = jest + .fn() + .mockImplementation( + (fileName: string, stringName: string) => fileName === 'test.resx' && stringName === 'bar' + ); + + await testResxAsync('resxWithSchema', { + ignoreString: ignoredStringFunction + }); + + expect((ignoredStringFunction as unknown as jest.SpyInstance).mock.calls).toMatchSnapshot( + 'ignoreStrings calls' + ); + }); + + describe('ignoreMissingResxComments', () => { + it('when set to true, ignores a missing comment', async () => { + await testResxAsync('stringWithoutComment', { + ignoreMissingResxComments: true + }); + }); + + it('when set to false, warns on a missing comment', async () => { + await testResxAsync('stringWithoutComment', { + ignoreMissingResxComments: false + }); + }); + + it('when set to undefined, warns on a missing comment', async () => { + await testResxAsync('stringWithoutComment', { + ignoreMissingResxComments: undefined + }); + }); + }); + + describe('resxNewlineNormalization', () => { + it('when set to CrLf, normalizes to CrLf', async () => { + await testResxAsync('withNewlines', { + resxNewlineNormalization: NewlineKind.CrLf + }); + }); + + it('when set to Lf, normalizes to Lf', async () => { + await testResxAsync('withNewlines', { + resxNewlineNormalization: NewlineKind.Lf + }); + }); + }); + + it('fails to parse a RESX file with a duplicate string', async () => { + await testResxAsync('resxWithDuplicateEntry'); + }); +}); diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/invalidXml.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/invalidXml.resx new file mode 100644 index 00000000000..2d3ce115424 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/invalidXml.resx @@ -0,0 +1,7 @@ + + + + foo> + Foo + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithDuplicateEntry.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithDuplicateEntry.resx new file mode 100644 index 00000000000..468bb058d93 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithDuplicateEntry.resx @@ -0,0 +1,9 @@ + + + + A string + + + Another string + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithSchema.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithSchema.resx new file mode 100644 index 00000000000..9f01ead7925 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/resxWithSchema.resx @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + foo + Foo + + + bar + Bar + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithQuotemarks.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithQuotemarks.resx new file mode 100644 index 00000000000..4899566ab1e --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithQuotemarks.resx @@ -0,0 +1,7 @@ + + + + "RESX string with quotemarks" + RESX string with quotemarks + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithoutComment.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithoutComment.resx new file mode 100644 index 00000000000..3d0170bcf7a --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/stringWithoutComment.resx @@ -0,0 +1,6 @@ + + + + String without a comment + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/parsers/test/testResxFiles/withNewlines.resx b/libraries/localization-utilities/src/parsers/test/testResxFiles/withNewlines.resx new file mode 100644 index 00000000000..657f8f74615 --- /dev/null +++ b/libraries/localization-utilities/src/parsers/test/testResxFiles/withNewlines.resx @@ -0,0 +1,9 @@ + + + + + RESX string with newlines and tabs + + RESX string with newlines and tabs + + \ No newline at end of file diff --git a/libraries/localization-utilities/src/schemas/locJson.schema.json b/libraries/localization-utilities/src/schemas/locJson.schema.json new file mode 100644 index 00000000000..8c60e7573cb --- /dev/null +++ b/libraries/localization-utilities/src/schemas/locJson.schema.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Localizable JSON file", + + "patternProperties": { + "^[A-Za-z_$][0-9A-Za-z_$]*$": { + "oneOf": [ + { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "comment": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["value"] + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false, + "type": "object" +} diff --git a/libraries/localization-utilities/src/test/Pseudolocalization.test.ts b/libraries/localization-utilities/src/test/Pseudolocalization.test.ts new file mode 100644 index 00000000000..4a64f9967c0 --- /dev/null +++ b/libraries/localization-utilities/src/test/Pseudolocalization.test.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 { getPseudolocalizer } from '../Pseudolocalization'; +import type { IPseudolocaleOptions } from '../interfaces'; + +describe(getPseudolocalizer.name, () => { + it('gets distinct pseudolocalizers', () => { + const input: 'text' = 'text'; + + const fooOptions: IPseudolocaleOptions = { + prepend: '-Foo-', + append: '-Foo-' + }; + const fooLocale: (str: string) => string = getPseudolocalizer(fooOptions); + const foo1: string = fooLocale(input); + + const barOptions: IPseudolocaleOptions = { + prepend: '-Bar-', + append: '-Bar-' + }; + + const barLocale: (str: string) => string = getPseudolocalizer(barOptions); + + const bar1: string = barLocale(input); + const foo2: string = fooLocale(input); + const bar2: string = barLocale(input); + + expect(foo1).toEqual(foo2); + expect(bar1).toEqual(bar2); + + expect(foo1).toMatchSnapshot('foo'); + expect(bar1).toMatchSnapshot('bar'); + }); +}); diff --git a/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap b/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap new file mode 100644 index 00000000000..66a2c2a53a8 --- /dev/null +++ b/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getPseudolocalizer gets distinct pseudolocalizers: bar 1`] = `"-Bar-ţēxţ-Bar-"`; + +exports[`getPseudolocalizer gets distinct pseudolocalizers: foo 1`] = `"-Foo-ţēxţ-Foo-"`; diff --git a/libraries/localization-utilities/tsconfig.json b/libraries/localization-utilities/tsconfig.json new file mode 100644 index 00000000000..7902d0431ea --- /dev/null +++ b/libraries/localization-utilities/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019" + } +} diff --git a/libraries/lookup-by-path/.npmignore b/libraries/lookup-by-path/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/lookup-by-path/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/lookup-by-path/CHANGELOG.json b/libraries/lookup-by-path/CHANGELOG.json new file mode 100644 index 00000000000..b73c33be2da --- /dev/null +++ b/libraries/lookup-by-path/CHANGELOG.json @@ -0,0 +1,769 @@ +{ + "name": "@rushstack/lookup-by-path", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/lookup-by-path_v0.4.6", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/lookup-by-path_v0.4.5", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/lookup-by-path_v0.4.4", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/lookup-by-path_v0.4.3", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/lookup-by-path_v0.4.2", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/lookup-by-path_v0.4.1", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/lookup-by-path_v0.4.0", + "date": "Thu, 17 Oct 2024 20:25:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add `IReadonlyLookupByPath` interface to help unit tests for functions that consume `LookupByPath`." + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/lookup-by-path_v0.3.2", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/lookup-by-path_v0.3.1", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/lookup-by-path_v0.3.0", + "date": "Thu, 03 Oct 2024 15:11:00 GMT", + "comments": { + "minor": [ + { + "comment": "Allow for a map of file paths to arbitrary info to be grouped by the nearest entry in the LookupByPath trie" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/lookup-by-path_v0.2.5", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/lookup-by-path_v0.2.4", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/lookup-by-path_v0.2.3", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/lookup-by-path_v0.2.2", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/lookup-by-path_v0.2.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/lookup-by-path_v0.2.0", + "date": "Tue, 27 Aug 2024 15:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Return a linked list of matches in `findLongestPrefixMatch` in the event that multiple prefixes match. The head of the list is the most specific match." + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/lookup-by-path_v0.1.2", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/lookup-by-path_v0.1.1", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/lookup-by-path_v0.1.0", + "date": "Thu, 08 Aug 2024 22:08:25 GMT", + "comments": { + "minor": [ + { + "comment": "Extract LookupByPath from @rushstack/rush-lib." + } + ] + } + } + ] +} diff --git a/libraries/lookup-by-path/CHANGELOG.md b/libraries/lookup-by-path/CHANGELOG.md new file mode 100644 index 00000000000..68c40c0cc6f --- /dev/null +++ b/libraries/lookup-by-path/CHANGELOG.md @@ -0,0 +1,337 @@ +# Change Log - @rushstack/lookup-by-path + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.4.6 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.4.5 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.4.4 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.4.3 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.4.2 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.4.1 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.4.0 +Thu, 17 Oct 2024 20:25:42 GMT + +### Minor changes + +- Add `IReadonlyLookupByPath` interface to help unit tests for functions that consume `LookupByPath`. + +## 0.3.2 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.3.1 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.3.0 +Thu, 03 Oct 2024 15:11:00 GMT + +### Minor changes + +- Allow for a map of file paths to arbitrary info to be grouped by the nearest entry in the LookupByPath trie + +## 0.2.5 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.2.4 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.2.3 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.2.2 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.2.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.2.0 +Tue, 27 Aug 2024 15:12:33 GMT + +### Minor changes + +- Return a linked list of matches in `findLongestPrefixMatch` in the event that multiple prefixes match. The head of the list is the most specific match. + +## 0.1.2 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.1.1 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.1.0 +Thu, 08 Aug 2024 22:08:25 GMT + +### Minor changes + +- Extract LookupByPath from @rushstack/rush-lib. + diff --git a/libraries/lookup-by-path/LICENSE b/libraries/lookup-by-path/LICENSE new file mode 100644 index 00000000000..ad73d857028 --- /dev/null +++ b/libraries/lookup-by-path/LICENSE @@ -0,0 +1,24 @@ +@rushstack/lookup-by-path + +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/lookup-by-path/README.md b/libraries/lookup-by-path/README.md new file mode 100644 index 00000000000..d450300ed73 --- /dev/null +++ b/libraries/lookup-by-path/README.md @@ -0,0 +1,14 @@ +# @rushstack/lookup-by-path + +This library contains a strongly-typed implementation of of a [Trie](https://en.wikipedia.org/wiki/Trie) (a.k.a. prefix tree) data structure optimized for file paths and URLs. + +This package is used by Rush to associate Git hashes with their nearest ancestor Rush project, for example. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/lookup-by-path/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/lookup-by-path/) + +`@rushstack/lookup-by-path` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/lookup-by-path/config/api-extractor.json b/libraries/lookup-by-path/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/lookup-by-path/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/lookup-by-path/config/jest.config.json b/libraries/lookup-by-path/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/lookup-by-path/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/lookup-by-path/config/rig.json b/libraries/lookup-by-path/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/lookup-by-path/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/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 new file mode 100644 index 00000000000..00fd99014af --- /dev/null +++ b/libraries/lookup-by-path/package.json @@ -0,0 +1,38 @@ +{ + "name": "@rushstack/lookup-by-path", + "version": "0.8.9", + "description": "Strongly typed trie data structure for path and URL-like strings.", + "main": "lib/index.js", + "typings": "dist/lookup-by-path.d.ts", + "keywords": [ + "trie", + "path", + "url", + "radix tree", + "prefix tree" + ], + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/lookup-by-path" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/libraries/lookup-by-path/src/LookupByPath.ts b/libraries/lookup-by-path/src/LookupByPath.ts new file mode 100644 index 00000000000..a6b3353371e --- /dev/null +++ b/libraries/lookup-by-path/src/LookupByPath.ts @@ -0,0 +1,612 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * A node in the path trie used in LookupByPath + */ +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; +} + +interface IPrefixEntry { + /** + * The prefix that was matched + */ + prefix: string; + + /** + * The index of the first character after the matched prefix + */ + index: number; +} + +/** + * Object containing both the matched item and the start index of the remainder of the query. + * + * @beta + */ +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 + */ + lastMatch?: IPrefixMatch; +} + +/** + * The readonly component of `LookupByPath`, to simplify unit testing. + * + * @beta + */ +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. + * + * @returns the found item, or `undefined` if no item was found + * + * @example + * ```ts + * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]); + * trie.findChildPath('foo/baz'); // returns 1 + * trie.findChildPath('foo/bar/baz'); // returns 2 + * ``` + */ + findChildPath(childPath: string, delimiter?: string): TItem | undefined; + + /** + * Searches for the item for which the recorded prefix is the longest matching prefix of `query`. + * Obtains both the item and the length of the matched prefix, so that the remainder of the path can be + * extracted. + * + * @returns the found item and the length of the matched prefix, or `undefined` if no item was found + * + * @example + * ```ts + * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]); + * trie.findLongestPrefixMatch('foo/baz'); // returns { item: 1, index: 3 } + * trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 } + * ``` + */ + findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch | undefined; + + /** + * Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that + * has an associated item. + * + * @returns the found item, or `undefined` if no item was found + * + * @example + * ```ts + * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]); + * trie.findChildPathFromSegments(['foo', 'baz']); // returns 1 + * trie.findChildPathFromSegments(['foo','bar', 'baz']); // returns 2 + * ``` + */ + 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. + * + * @returns The grouped info, grouped by the nearest entry in the trie that contains the path + * + * @param infoByPath - The info to be grouped, keyed by path + */ + 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; +} + +/** + * This class is used to associate path-like-strings, such as those returned by `git` commands, + * with entities that correspond with ancestor folders, such as Rush Projects or npm packages. + * + * It is optimized for efficiently locating the nearest ancestor path with an associated value. + * + * It is implemented as a Trie (https://en.wikipedia.org/wiki/Trie) data structure, with each edge + * being a path segment. + * + * @example + * ```ts + * const trie = new LookupByPath([['foo', 1], ['bar', 2], ['foo/bar', 3]]); + * trie.findChildPath('foo'); // returns 1 + * trie.findChildPath('foo/baz'); // returns 1 + * trie.findChildPath('baz'); // returns undefined + * trie.findChildPath('foo/bar/baz'); returns 3 + * trie.findChildPath('bar/foo/bar'); returns 2 + * ``` + * @beta + */ +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` + * + * @param entries - Initial path-value pairs to populate the trie. + */ + public constructor(entries?: Iterable<[string, TItem]>, delimiter?: string) { + this._root = { + value: undefined, + children: undefined + }; + + this.delimiter = delimiter ?? '/'; + this._size = 0; + + if (entries) { + for (const [path, item] of entries) { + this.setItem(path, item); + } + } + } + + /** + * Iterates over the segments of a serialized path. + * + * @example + * + * `LookupByPath.iteratePathSegments('foo/bar/baz')` yields 'foo', 'bar', 'baz' + * + * `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)) { + yield prefixMatch.prefix; + } + } + + private static *_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 + }; + } + } + + /** + * {@inheritdoc IReadonlyLookupByPath.size} + */ + public get size(): number { + return this._size; + } + + /** + * {@inheritdoc IReadonlyLookupByPath.tree} + */ + public get tree(): IReadonlyPathTrieNode { + return this._root; + } + + /** + * 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; + } + + /** + * Associates the value with the specified serialized path. + * If a value is already associated, will overwrite. + * + * @returns this, for chained calls + */ + 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; + } + + /** + * Associates the value with the specified path. + * If a value is already associated, will overwrite. + * + * @returns this, for chained calls + */ + public setItemFromSegments(pathSegments: Iterable, value: TItem): this { + let node: IPathTrieNode = this._root; + for (const segment of pathSegments) { + if (!node.children) { + node.children = new Map(); + } + let child: IPathTrieNode | undefined = node.children.get(segment); + if (!child) { + node.children.set( + segment, + (child = { + value: undefined, + children: undefined + }) + ); + } + node = child; + } + if (node.value === undefined) { + this._size++; + } + node.value = value; + + return this; + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public findChildPath(childPath: string, delimiter: string = this.delimiter): TItem | undefined { + return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, delimiter)); + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public findLongestPrefixMatch( + query: string, + delimiter: string = this.delimiter + ): IPrefixMatch | undefined { + return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, delimiter)); + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined { + let node: IPathTrieNode = this._root; + let best: TItem | undefined = node.value; + // Trivial cases + if (node.children) { + for (const segment of childPathSegments) { + const child: IPathTrieNode | undefined = node.children.get(segment); + if (!child) { + break; + } + node = child; + best = node.value ?? best; + if (!node.children) { + break; + } + } + } + + return best; + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + 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, delimiter); + if (child === undefined) { + continue; + } + let groupedInfo: Map | undefined = groupedInfoByChild.get(child); + if (!groupedInfo) { + groupedInfo = new Map(); + groupedInfoByChild.set(child, groupedInfo); + } + groupedInfo.set(path, info); + } + + 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); + } + + /** + * 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. + * + * If a match is present, returns the matched itme and the length of the matched prefix. + * + * @returns the found item, or `undefined` if no item was found + */ + private _findLongestPrefixMatch(prefixes: Iterable): IPrefixMatch | undefined { + let node: IPathTrieNode = this._root; + let best: IPrefixMatch | undefined = node.value + ? { + value: node.value, + index: 0, + lastMatch: undefined + } + : undefined; + // Trivial cases + if (node.children) { + for (const { prefix: hash, index } of prefixes) { + const child: IPathTrieNode | undefined = node.children.get(hash); + if (!child) { + break; + } + node = child; + if (node.value !== undefined) { + best = { + value: node.value, + index, + lastMatch: best + }; + } + if (!node.children) { + break; + } + } + } + + 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 LookupByPath._iteratePrefixes(query, delimiter)) { + if (!node.children) { + return undefined; + } + const child: IPathTrieNode | undefined = node.children.get(prefix); + if (!child) { + return undefined; + } + node = child; + } + return node; + } +} 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 new file mode 100644 index 00000000000..c91d2692ef9 --- /dev/null +++ b/libraries/lookup-by-path/src/index.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. + +/** + * Strongly typed trie data structure for path and URL-like strings. + * + * @packageDocumentation + */ + +export type { IPrefixMatch, IReadonlyLookupByPath, IReadonlyPathTrieNode } 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 new file mode 100644 index 00000000000..d785252dccb --- /dev/null +++ b/libraries/lookup-by-path/src/test/LookupByPath.test.ts @@ -0,0 +1,675 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { LookupByPath } from '../LookupByPath'; + +describe(LookupByPath.iteratePathSegments.name, () => { + it('returns empty for an empty string', () => { + const result = [...LookupByPath.iteratePathSegments('')]; + expect(result.length).toEqual(0); + }); + it('returns the only segment of a trival string', () => { + const result = [...LookupByPath.iteratePathSegments('foo')]; + expect(result).toEqual(['foo']); + }); + it('treats backslashes as ordinary characters, per POSIX', () => { + const result = [...LookupByPath.iteratePathSegments('foo\\bar\\baz')]; + expect(result).toEqual(['foo\\bar\\baz']); + }); + it('iterates segments', () => { + const result = [...LookupByPath.iteratePathSegments('foo/bar/baz')]; + expect(result).toEqual(['foo', 'bar', 'baz']); + }); + it('returns correct last single character segment', () => { + const result = [...LookupByPath.iteratePathSegments('foo/a')]; + expect(result).toEqual(['foo', 'a']); + }); +}); + +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); + }); + it('returns the matching node for a trivial tree', () => { + expect(new LookupByPath([['foo', 1]]).findChildPath('foo')).toEqual(1); + }); + it('returns the matching node for a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.findChildPath('foo')).toEqual(1); + expect(tree.findChildPath('bar')).toEqual(2); + expect(tree.findChildPath('baz')).toEqual(3); + expect(tree.findChildPath('buzz')).toEqual(undefined); + }); + it('returns the matching parent for multi-layer queries', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.findChildPath('foo/bar')).toEqual(1); + expect(tree.findChildPath('bar/baz')).toEqual(2); + expect(tree.findChildPath('baz/foo')).toEqual(3); + expect(tree.findChildPath('foo/foo')).toEqual(1); + }); + it('returns the matching parent for multi-layer queries in multi-layer trees', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3], + ['foo/bar', 4], + ['foo/bar/baz', 5], + ['baz/foo', 6], + ['baz/baz/baz/baz', 7] + ]); + + expect(tree.findChildPath('foo/foo')).toEqual(1); + expect(tree.findChildPath('foo/bar\\baz')).toEqual(1); + + expect(tree.findChildPath('bar/baz')).toEqual(2); + + expect(tree.findChildPath('baz/bar')).toEqual(3); + expect(tree.findChildPath('baz/baz')).toEqual(3); + expect(tree.findChildPath('baz/baz/baz')).toEqual(3); + + expect(tree.findChildPath('foo/bar')).toEqual(4); + expect(tree.findChildPath('foo/bar/foo')).toEqual(4); + + expect(tree.findChildPath('foo/bar/baz')).toEqual(5); + expect(tree.findChildPath('foo/bar/baz/baz/baz/baz/baz')).toEqual(5); + + expect(tree.findChildPath('baz/foo/')).toEqual(6); + + expect(tree.findChildPath('baz/baz/baz/baz')).toEqual(7); + + expect(tree.findChildPath('')).toEqual(undefined); + expect(tree.findChildPath('foofoo')).toEqual(undefined); + expect(tree.findChildPath('foo\\bar\\baz')).toEqual(undefined); + }); + it('handles custom delimiters', () => { + const tree: LookupByPath = new LookupByPath( + [ + ['foo,bar', 1], + ['foo/bar', 2] + ], + ',' + ); + + 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); + }); +}); + +describe(LookupByPath.prototype.findLongestPrefixMatch.name, () => { + it('returns empty for an empty tree', () => { + expect(new LookupByPath().findLongestPrefixMatch('foo')).toEqual(undefined); + }); + it('returns the matching node for a trivial tree', () => { + expect(new LookupByPath([['foo', 1]]).findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 }); + }); + it('returns the matching node for a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['barbar', 2], + ['baz', 3] + ]); + + expect(tree.findLongestPrefixMatch('foo')).toEqual({ value: 1, index: 3 }); + expect(tree.findLongestPrefixMatch('barbar')).toEqual({ value: 2, index: 6 }); + expect(tree.findLongestPrefixMatch('baz')).toEqual({ value: 3, index: 3 }); + expect(tree.findLongestPrefixMatch('buzz')).toEqual(undefined); + }); + it('returns the matching parent for multi-layer queries', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['barbar', 2], + ['baz', 3], + ['foo/bar', 4] + ]); + + expect(tree.findLongestPrefixMatch('foo/bar')).toEqual({ + value: 4, + index: 7, + lastMatch: { value: 1, index: 3 } + }); + expect(tree.findLongestPrefixMatch('barbar/baz')).toEqual({ value: 2, index: 6 }); + expect(tree.findLongestPrefixMatch('baz/foo')).toEqual({ value: 3, index: 3 }); + expect(tree.findLongestPrefixMatch('foo/foo')).toEqual({ value: 1, index: 3 }); + }); +}); + +describe(LookupByPath.prototype.groupByChild.name, () => { + const lookup: LookupByPath = new LookupByPath([ + ['foo', 'foo'], + ['foo/bar', 'bar'], + ['foo/bar/baz', 'baz'] + ]); + + it('returns empty map for empty input', () => { + expect(lookup.groupByChild(new Map())).toEqual(new Map()); + }); + + it('groups items by the closest group that contains the file path', () => { + const infoByPath: Map = new Map([ + ['foo', 'foo'], + ['foo/bar', 'bar'], + ['foo/bar/baz', 'baz'], + ['foo/bar/baz/qux', 'qux'], + ['foo/bar/baz/qux/quux', 'quux'] + ]); + + const expected: Map> = new Map([ + ['foo', new Map([['foo', 'foo']])], + ['bar', new Map([['foo/bar', 'bar']])], + [ + 'baz', + new Map([ + ['foo/bar/baz', 'baz'], + ['foo/bar/baz/qux', 'qux'], + ['foo/bar/baz/qux/quux', 'quux'] + ]) + ] + ]); + + 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'], + ['foo/qux', 'qux'], + ['bar', 'bar'], + ['baz', 'baz'] + ]); + + const expected: Map> = new Map([ + [ + 'foo', + new Map([ + ['foo', 'foo'], + ['foo/qux', 'qux'] + ]) + ] + ]); + + expect(lookup.groupByChild(infoByPath)).toEqual(expected); + }); + + it('ignores items that do not exist in the lookup when the lookup children are possibly falsy', () => { + const falsyLookup: LookupByPath = new LookupByPath([ + ['foo', 'foo'], + ['foo/bar', 'bar'], + ['foo/bar/baz', ''] + ]); + + const infoByPath: Map = new Map([ + ['foo', 'foo'], + ['foo/bar', 'bar'], + ['foo/bar/baz', 'baz'], + ['foo/bar/baz/qux', 'qux'], + ['foo/bar/baz/qux/quux', 'quux'] + ]); + + const expected: Map> = new Map([ + ['foo', new Map([['foo', 'foo']])], + ['bar', new Map([['foo/bar', 'bar']])], + [ + '', + new Map([ + ['foo/bar/baz', 'baz'], + ['foo/bar/baz/qux', 'qux'], + ['foo/bar/baz/qux/quux', 'quux'] + ]) + ] + ]); + + expect(falsyLookup.groupByChild(infoByPath)).toEqual(expected); + }); +}); 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/lookup-by-path/tsconfig.json b/libraries/lookup-by-path/tsconfig.json new file mode 100644 index 00000000000..9a79fa4af11 --- /dev/null +++ b/libraries/lookup-by-path/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "target": "ES2019" + } +} diff --git a/libraries/module-minifier/.npmignore b/libraries/module-minifier/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/module-minifier/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/module-minifier/CHANGELOG.json b/libraries/module-minifier/CHANGELOG.json new file mode 100644 index 00000000000..7f7cbe2301e --- /dev/null +++ b/libraries/module-minifier/CHANGELOG.json @@ -0,0 +1,3524 @@ +{ + "name": "@rushstack/module-minifier", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.6.33", + "tag": "@rushstack/module-minifier_v0.6.33", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.6.32", + "tag": "@rushstack/module-minifier_v0.6.32", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.6.31", + "tag": "@rushstack/module-minifier_v0.6.31", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.6.30", + "tag": "@rushstack/module-minifier_v0.6.30", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.6.29", + "tag": "@rushstack/module-minifier_v0.6.29", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.6.28", + "tag": "@rushstack/module-minifier_v0.6.28", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.6.27", + "tag": "@rushstack/module-minifier_v0.6.27", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.6.26", + "tag": "@rushstack/module-minifier_v0.6.26", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.6.25", + "tag": "@rushstack/module-minifier_v0.6.25", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.6.24", + "tag": "@rushstack/module-minifier_v0.6.24", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.6.23", + "tag": "@rushstack/module-minifier_v0.6.23", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.6.22", + "tag": "@rushstack/module-minifier_v0.6.22", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.6.21", + "tag": "@rushstack/module-minifier_v0.6.21", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.6.20", + "tag": "@rushstack/module-minifier_v0.6.20", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.6.19", + "tag": "@rushstack/module-minifier_v0.6.19", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.6.18", + "tag": "@rushstack/module-minifier_v0.6.18", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.6.17", + "tag": "@rushstack/module-minifier_v0.6.17", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.6.16", + "tag": "@rushstack/module-minifier_v0.6.16", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.6.15", + "tag": "@rushstack/module-minifier_v0.6.15", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/module-minifier_v0.6.14", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/module-minifier_v0.6.13", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/module-minifier_v0.6.12", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/module-minifier_v0.6.11", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/module-minifier_v0.6.10", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/module-minifier_v0.6.9", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/module-minifier_v0.6.8", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/module-minifier_v0.6.7", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/module-minifier_v0.6.6", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/module-minifier_v0.6.5", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/module-minifier_v0.6.4", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/module-minifier_v0.6.3", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/module-minifier_v0.6.2", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/module-minifier_v0.6.1", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/module-minifier_v0.6.0", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "minor": [ + { + "comment": "Rename `IMinifierConnection.disconnect` to `IMinifierConnection.disconnectAsync` and `IModuleMinifier.connect` to `IModuleMinifier.connectAsync`. The old functions are marked as `@deprecated`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/module-minifier_v0.5.4", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/module-minifier_v0.5.3", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/module-minifier_v0.5.2", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/module-minifier_v0.5.1", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/module-minifier_v0.5.0", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "minor": [ + { + "comment": "Gracefully exit minifier worker instead of using `process.exit(0)`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.40`" + } + ] + } + }, + { + "version": "0.4.40", + "tag": "@rushstack/module-minifier_v0.4.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.4.39", + "tag": "@rushstack/module-minifier_v0.4.39", + "date": "Sat, 16 Mar 2024 00:11:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the assets listed in sourcemaps were incomplete or missing." + } + ] + } + }, + { + "version": "0.4.38", + "tag": "@rushstack/module-minifier_v0.4.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.4.37", + "tag": "@rushstack/module-minifier_v0.4.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/module-minifier_v0.4.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/module-minifier_v0.4.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/module-minifier_v0.4.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/module-minifier_v0.4.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/module-minifier_v0.4.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/module-minifier_v0.4.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/module-minifier_v0.4.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/module-minifier_v0.4.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/module-minifier_v0.4.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/module-minifier_v0.4.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/module-minifier_v0.4.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/module-minifier_v0.4.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/module-minifier_v0.4.24", + "date": "Sat, 17 Feb 2024 06:24:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/module-minifier_v0.4.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/module-minifier_v0.4.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/module-minifier_v0.4.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/module-minifier_v0.4.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/module-minifier_v0.4.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/module-minifier_v0.4.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/module-minifier_v0.4.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/module-minifier_v0.4.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/module-minifier_v0.4.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/module-minifier_v0.4.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/module-minifier_v0.4.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/module-minifier_v0.4.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/module-minifier_v0.4.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/module-minifier_v0.4.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/module-minifier_v0.4.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/module-minifier_v0.4.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/module-minifier_v0.4.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/module-minifier_v0.4.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/module-minifier_v0.4.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/module-minifier_v0.4.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/module-minifier_v0.4.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/module-minifier_v0.4.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/module-minifier_v0.4.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/module-minifier_v0.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/module-minifier_v0.3.38", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/module-minifier_v0.3.37", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/module-minifier_v0.3.36", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/module-minifier_v0.3.35", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/module-minifier_v0.3.34", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/module-minifier_v0.3.33", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/module-minifier_v0.3.32", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/module-minifier_v0.3.31", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/module-minifier_v0.3.30", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/module-minifier_v0.3.29", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/module-minifier_v0.3.28", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/module-minifier_v0.3.27", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/module-minifier_v0.3.26", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/module-minifier_v0.3.25", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/module-minifier_v0.3.24", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/module-minifier_v0.3.23", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/module-minifier_v0.3.22", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/module-minifier_v0.3.21", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/module-minifier_v0.3.20", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/module-minifier_v0.3.19", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/module-minifier_v0.3.18", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/module-minifier_v0.3.17", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/module-minifier_v0.3.16", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/module-minifier_v0.3.15", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/module-minifier_v0.3.14", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/module-minifier_v0.3.13", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/module-minifier_v0.3.12", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/module-minifier_v0.3.11", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/module-minifier_v0.3.10", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/module-minifier_v0.3.9", + "date": "Thu, 04 May 2023 15:17:38 GMT", + "comments": { + "patch": [ + { + "comment": "Switch terser dependency to ^5.9.0." + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/module-minifier_v0.3.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/module-minifier_v0.3.7", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/module-minifier_v0.3.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/module-minifier_v0.3.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/module-minifier_v0.3.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/module-minifier_v0.3.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/module-minifier_v0.3.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/module-minifier_v0.3.1", + "date": "Sun, 05 Feb 2023 03:02:01 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/module-minifier_v0.3.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/module-minifier_v0.2.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/module-minifier_v0.1.49", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/module-minifier_v0.1.48", + "date": "Sat, 28 Jan 2023 01:22:02 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure updates to the version of Terser trigger a hash change." + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/module-minifier_v0.1.47", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/module-minifier_v0.1.46", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/module-minifier_v0.1.45", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "patch": [ + { + "comment": "Update to terser 5.16.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/module-minifier_v0.1.44", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/module-minifier_v0.1.43", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/module-minifier_v0.1.42", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/module-minifier_v0.1.41", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/module-minifier_v0.1.40", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/module-minifier_v0.1.39", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/module-minifier_v0.1.38", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/module-minifier_v0.1.37", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/module-minifier_v0.1.36", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/module-minifier_v0.1.35", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/module-minifier_v0.1.34", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/module-minifier_v0.1.33", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/module-minifier_v0.1.32", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/module-minifier_v0.1.31", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/module-minifier_v0.1.30", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/module-minifier_v0.1.29", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/module-minifier_v0.1.28", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/module-minifier_v0.1.27", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/module-minifier_v0.1.26", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/module-minifier_v0.1.25", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/module-minifier_v0.1.24", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/module-minifier_v0.1.23", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/module-minifier_v0.1.22", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/module-minifier_v0.1.21", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/module-minifier_v0.1.20", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/module-minifier_v0.1.19", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/module-minifier_v0.1.18", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/module-minifier_v0.1.17", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/module-minifier_v0.1.16", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/module-minifier_v0.1.15", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/module-minifier_v0.1.14", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/module-minifier_v0.1.13", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/module-minifier_v0.1.12", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/module-minifier_v0.1.11", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/module-minifier_v0.1.10", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/module-minifier_v0.1.9", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/module-minifier_v0.1.8", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/module-minifier_v0.1.7", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/module-minifier_v0.1.6", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/module-minifier_v0.1.5", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "none": [ + { + "comment": "Update documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/module-minifier_v0.1.4", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/module-minifier_v0.1.3", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/module-minifier_v0.1.2", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/module-minifier_v0.1.1", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/module-minifier_v0.1.0", + "date": "Fri, 20 May 2022 00:11:55 GMT", + "comments": { + "minor": [ + { + "comment": "Factor out minifiers from @rushstack/module-minifier-plugin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.0`" + } + ] + } + } + ] +} diff --git a/libraries/module-minifier/CHANGELOG.md b/libraries/module-minifier/CHANGELOG.md new file mode 100644 index 00000000000..99ac6ea58c7 --- /dev/null +++ b/libraries/module-minifier/CHANGELOG.md @@ -0,0 +1,1102 @@ +# Change Log - @rushstack/module-minifier + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.6.33 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.6.32 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.6.31 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.6.30 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.6.29 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.6.28 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.6.27 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.6.26 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.6.25 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.6.24 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.6.23 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.6.22 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.6.21 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.6.20 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.6.19 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.6.18 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.6.17 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.6.16 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.6.15 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.6.14 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.6.13 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.6.12 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.6.11 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.6.10 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.6.9 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.6.8 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.6.7 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.6.6 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.6.5 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.6.4 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.6.3 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.6.2 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.6.1 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.6.0 +Wed, 15 May 2024 06:04:17 GMT + +### Minor changes + +- Rename `IMinifierConnection.disconnect` to `IMinifierConnection.disconnectAsync` and `IModuleMinifier.connect` to `IModuleMinifier.connectAsync`. The old functions are marked as `@deprecated`. + +## 0.5.4 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.5.3 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.5.2 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.5.1 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.5.0 +Thu, 28 Mar 2024 22:42:23 GMT + +### Minor changes + +- Gracefully exit minifier worker instead of using `process.exit(0)`. + +## 0.4.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.4.39 +Sat, 16 Mar 2024 00:11:37 GMT + +### Patches + +- Fix an issue where the assets listed in sourcemaps were incomplete or missing. + +## 0.4.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.4.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.4.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.4.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.4.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.4.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.4.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.4.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.4.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.4.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.4.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.4.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.4.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.4.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.4.24 +Sat, 17 Feb 2024 06:24:34 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.4.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.4.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.4.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.4.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.4.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.4.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.4.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.4.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.4.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.4.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.4.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.4.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.4.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.4.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.4.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.4.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.4.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.4.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.4.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.4.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.4.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.4.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.4.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.3.38 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.3.37 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.3.36 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.3.35 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.3.34 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.3.33 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.3.32 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.3.31 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.3.30 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.3.29 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.3.28 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.3.27 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.3.26 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.3.25 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.3.24 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.3.23 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.3.22 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.3.21 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.3.20 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.3.19 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.3.18 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.3.17 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.3.16 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.3.15 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.3.14 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.3.13 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 0.3.12 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.3.11 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.3.10 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.3.9 +Thu, 04 May 2023 15:17:38 GMT + +### Patches + +- Switch terser dependency to ^5.9.0. + +## 0.3.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.3.7 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.3.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.3.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.3.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.3.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.3.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.3.1 +Sun, 05 Feb 2023 03:02:01 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.3.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.2.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.1.49 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.48 +Sat, 28 Jan 2023 01:22:02 GMT + +### Patches + +- Ensure updates to the version of Terser trigger a hash change. + +## 0.1.47 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.46 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.1.45 +Wed, 18 Jan 2023 22:44:12 GMT + +### Patches + +- Update to terser 5.16.1 + +## 0.1.44 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.43 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.42 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.41 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.40 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.39 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.38 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.37 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.36 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.35 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.34 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.33 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.32 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.31 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.30 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.1.29 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.28 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.27 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.26 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.25 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.24 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.23 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.22 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.1.21 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.20 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.19 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.18 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.17 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.16 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.15 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.14 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.13 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.12 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.11 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.1.10 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.9 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.8 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.7 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.6 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.5 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.1.4 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.3 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.2 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.1 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.1.0 +Fri, 20 May 2022 00:11:55 GMT + +### Minor changes + +- Factor out minifiers from @rushstack/module-minifier-plugin. + diff --git a/libraries/module-minifier/LICENSE b/libraries/module-minifier/LICENSE new file mode 100644 index 00000000000..73f78231792 --- /dev/null +++ b/libraries/module-minifier/LICENSE @@ -0,0 +1,24 @@ +@rushstack/module-minifier + +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/module-minifier/README.md b/libraries/module-minifier/README.md new file mode 100644 index 00000000000..f532520ef55 --- /dev/null +++ b/libraries/module-minifier/README.md @@ -0,0 +1,12 @@ +# @rushstack/module-minifier + +This library wraps terser in convenient handles for parallelization. It powers @rushstack/webpack4-module-minifier-plugin and @rushstack/webpack5-module-minifier-plugin but has no coupling with webpack. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/module-minifier/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/module-minifier/) + +`@rushstack/module-minifier` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/module-minifier/config/api-extractor.json b/libraries/module-minifier/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/module-minifier/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/module-minifier/config/jest.config.json b/libraries/module-minifier/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/module-minifier/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/module-minifier/config/rig.json b/libraries/module-minifier/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/module-minifier/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/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 new file mode 100644 index 00000000000..bb6db6be39e --- /dev/null +++ b/libraries/module-minifier/package.json @@ -0,0 +1,39 @@ +{ + "name": "@rushstack/module-minifier", + "version": "0.8.7", + "description": "Wrapper for terser to support bulk parallel minification.", + "main": "lib/index.js", + "typings": "dist/module-minifier.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/module-minifier" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/worker-pool": "workspace:*", + "serialize-javascript": "6.0.2", + "source-map": "~0.7.3", + "terser": "^5.9.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/serialize-javascript": "5.0.2", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/libraries/module-minifier/src/LocalMinifier.ts b/libraries/module-minifier/src/LocalMinifier.ts new file mode 100644 index 00000000000..9f64006cc0f --- /dev/null +++ b/libraries/module-minifier/src/LocalMinifier.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 { createHash } from 'node:crypto'; + +import serialize from 'serialize-javascript'; +import type { MinifyOptions } from 'terser'; + +import type { + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationRequest, + IModuleMinificationResult, + IModuleMinifier +} from './types'; +import { minifySingleFileAsync } from './MinifySingleFile'; + +/** + * Options for configuring the LocalMinifier + * @public + */ +export interface ILocalMinifierOptions { + terserOptions?: MinifyOptions; +} + +/** + * Minifier implementation that minifies code on the main thread. + * @public + */ +export class LocalMinifier implements IModuleMinifier { + private readonly _terserOptions: MinifyOptions; + + private readonly _resultCache: Map; + private readonly _configHash: string; + + public constructor(options: ILocalMinifierOptions) { + const { terserOptions = {} } = options || {}; + + this._terserOptions = { + ...terserOptions, + output: terserOptions.output + ? { + ...terserOptions.output + } + : {} + }; + + const { version: terserVersion } = require('terser/package.json'); + + this._configHash = createHash('sha256') + .update(LocalMinifier.name, 'utf8') + .update(`terser@${terserVersion}`) + .update(serialize(terserOptions)) + .digest('base64'); + + this._resultCache = new Map(); + } + + /** + * Transform that invokes Terser on the main thread + * @param request - The request to process + * @param callback - The callback to invoke + */ + public minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void { + const { hash } = request; + + const cached: IModuleMinificationResult | undefined = this._resultCache.get(hash); + if (cached) { + return callback(cached); + } + + minifySingleFileAsync(request, this._terserOptions) + .then((result: IModuleMinificationResult) => { + this._resultCache.set(hash, result); + callback(result); + }) + .catch((error) => { + // This branch is here to satisfy the no-floating-promises lint rule + callback({ + error: error as Error, + code: undefined, + map: undefined, + hash + }); + }); + } + + /** + * {@inheritdoc IModuleMinifier.connectAsync} + */ + public async connectAsync(): Promise { + const disconnectAsync: IMinifierConnection['disconnectAsync'] = async () => { + // Do nothing. + }; + return { + configHash: this._configHash, + disconnectAsync, + disconnect: disconnectAsync + }; + } + + /** + * @deprecated Use {@link LocalMinifier.connectAsync} instead. + */ + // eslint-disable-next-line @typescript-eslint/naming-convention + public async connect(): Promise { + return await this.connectAsync(); + } +} diff --git a/libraries/module-minifier/src/MessagePortMinifier.ts b/libraries/module-minifier/src/MessagePortMinifier.ts new file mode 100644 index 00000000000..45259e90665 --- /dev/null +++ b/libraries/module-minifier/src/MessagePortMinifier.ts @@ -0,0 +1,87 @@ +// 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 * as WorkerThreads from 'node:worker_threads'; + +import type { + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationRequest, + IModuleMinificationResult, + IModuleMinifier +} from './types'; + +/** + * Minifier implementation that outsources requests to the other side of a MessagePort + * @public + */ +export class MessagePortMinifier implements IModuleMinifier { + public readonly port: WorkerThreads.MessagePort; + + private readonly _callbacks: Map; + + public constructor(port: WorkerThreads.MessagePort) { + this.port = port; + this._callbacks = new Map(); + } + + /** + * No-op code transform. + * @param request - The request to process + * @param callback - The callback to invoke + */ + public minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void { + const { hash } = request; + + const callbacks: IModuleMinificationCallback[] | undefined = this._callbacks.get(hash); + if (callbacks) { + callbacks.push(callback); + return; + } + + this._callbacks.set(hash, [callback]); + + this.port.postMessage(request); + } + + /** + * {@inheritdoc IModuleMinifier.connectAsync} + */ + public async connectAsync(): Promise { + const configHashPromise: Promise = once(this.port, 'message') as unknown as Promise; + this.port.postMessage('initialize'); + const configHash: string = await configHashPromise; + + const callbacks: Map = this._callbacks; + + function handler(message: IModuleMinificationResult | number | false): void { + if (typeof message === 'object') { + const callbacksForRequest: IModuleMinificationCallback[] = callbacks.get(message.hash)!; + callbacks.delete(message.hash); + for (const callback of callbacksForRequest) { + callback(message); + } + } + } + + this.port.on('message', handler); + const disconnectAsync: IMinifierConnection['disconnectAsync'] = async () => { + this.port.off('message', handler); + this.port.close(); + }; + return { + configHash, + disconnectAsync, + disconnect: disconnectAsync + }; + } + + /** + * @deprecated Use {@link MessagePortMinifier.connectAsync} instead + */ + // eslint-disable-next-line @typescript-eslint/naming-convention + public async connect(): Promise { + return await this.connectAsync(); + } +} diff --git a/libraries/module-minifier/src/MinifiedIdentifier.ts b/libraries/module-minifier/src/MinifiedIdentifier.ts new file mode 100644 index 00000000000..c46488e540d --- /dev/null +++ b/libraries/module-minifier/src/MinifiedIdentifier.ts @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// TODO: Allow dynamic override of these values in the input to the minifier +import { IDENTIFIER_LEADING_DIGITS, IDENTIFIER_TRAILING_DIGITS } from './constants'; + +// Set of ECMAScript reserved keywords (past and present): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar +const RESERVED_KEYWORDS: string[] = [ + 'abstract', + 'arguments', + 'boolean', + 'break', + 'byte', + 'case', + 'catch', + 'char', + 'class', + 'const', + 'continue', + 'debugger', + 'default', + 'delete', + 'do', + 'double', + 'else', + 'enum', + 'export', + 'extends', + 'false', + 'final', + 'finally', + 'float', + 'for', + 'function', + 'get', + 'goto', + 'if', + 'implements', + 'import', + 'in', + 'instanceof', + 'int', + 'interface', + 'let', + 'long', + 'native', + 'new', + 'null', + 'package', + 'private', + 'protected', + 'public', + 'return', + 'set', + 'short', + 'static', + 'super', + 'switch', + 'synchronized', + 'this', + 'throw', + 'throws', + 'transient', + 'true', + 'try', + 'typeof', + 'var', + 'void', + 'volatile', + 'while', + 'with', + 'yield' +]; + +/** + * Gets a base54 string suitable for use as a JavaScript identifier, not accounting for reserved keywords + * @param ordinal - The number to convert to a base54 identifier + */ +export function getIdentifierInternal(ordinal: number): string { + let ret: string = IDENTIFIER_LEADING_DIGITS[ordinal % 54]; + + // eslint-disable-next-line no-bitwise + ordinal = (ordinal / 54) | 0; + while (ordinal > 0) { + --ordinal; + // eslint-disable-next-line no-bitwise + ret += IDENTIFIER_TRAILING_DIGITS[ordinal & 0x3f]; + ordinal >>>= 6; + } + + return ret; +} + +const leadingCharIndex: Map = new Map(); +for (let i: number = 0; i < 64; i++) { + leadingCharIndex.set(IDENTIFIER_LEADING_DIGITS.charCodeAt(i), i); +} + +const trailingCharIndex: Map = new Map(); +for (let i: number = 0; i < 64; i++) { + trailingCharIndex.set(IDENTIFIER_TRAILING_DIGITS.charCodeAt(i), i); +} + +/** + * Converts an identifier into the ordinal that would produce it, not accounting for reserved keywords + * Returns NaN if the result would exceed 31 bits + * @param identifier - The identifier to convert to a numeric value + */ +export function getOrdinalFromIdentifierInternal(identifier: string): number { + let ordinal: number = 0; + + for (let i: number = identifier.length - 1; i > 0; i--) { + if (ordinal >= 0x2000000) { + return NaN; + } + + ordinal <<= 6; + ordinal += trailingCharIndex.get(identifier.charCodeAt(i))! + 1; + } + + if (ordinal >= 0x2000000) { + return NaN; + } + + ordinal *= 54; + ordinal += leadingCharIndex.get(identifier.charCodeAt(0))!; + return ordinal; +} + +/** + * getIdentifier(n) would otherwise return each of these specified ECMAScript reserved keywords, which are not legal identifiers. + */ +const RESERVED_ORDINALS: number[] = ((): number[] => { + const reserved: number[] = []; + for (const keyword of RESERVED_KEYWORDS) { + const ordinal: number = getOrdinalFromIdentifierInternal(keyword); + if (!isNaN(ordinal)) { + reserved.push(ordinal); + } + } + return reserved.sort((x: number, y: number) => x - y); +})(); + +/** + * Gets a base54 string suitable for use as a JavaScript identifier, omitting those that are valid ECMAScript keywords + * + * @param ordinal - The number to convert to a base54 identifier + * + * @public + */ +export function getIdentifier(ordinal: number): string { + // Need to skip over reserved keywords + for ( + let i: number = 0, len: number = RESERVED_ORDINALS.length; + i < len && ordinal >= RESERVED_ORDINALS[i]; + i++ + ) { + ++ordinal; + } + + return getIdentifierInternal(ordinal); +} diff --git a/libraries/module-minifier/src/MinifierWorker.ts b/libraries/module-minifier/src/MinifierWorker.ts new file mode 100644 index 00000000000..6eea649283f --- /dev/null +++ b/libraries/module-minifier/src/MinifierWorker.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 { parentPort, workerData } from 'node:worker_threads'; + +import type { MinifyOptions } from 'terser'; + +import { minifySingleFileAsync } from './MinifySingleFile'; +import type { IModuleMinificationRequest, IModuleMinificationResult } from './types'; + +const terserOptions: MinifyOptions = workerData; + +// Set to non-zero to help debug unexpected graceful exit +process.exitCode = 2; + +async function handler(message: IModuleMinificationRequest): Promise { + if (!message) { + parentPort!.off('postMessage', handler); + parentPort!.close(); + return; + } + + const result: IModuleMinificationResult = await minifySingleFileAsync(message, terserOptions); + + parentPort!.postMessage(result); +} + +parentPort!.once('close', () => { + process.exitCode = 0; +}); +parentPort!.on('message', handler); diff --git a/libraries/module-minifier/src/MinifySingleFile.ts b/libraries/module-minifier/src/MinifySingleFile.ts new file mode 100644 index 00000000000..64bd9b04731 --- /dev/null +++ b/libraries/module-minifier/src/MinifySingleFile.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 { minify, type MinifyOptions, type MinifyOutput, type SimpleIdentifierMangler } from 'terser'; +import type { RawSourceMap } from 'source-map'; + +import { getIdentifier } from './MinifiedIdentifier'; +import type { IModuleMinificationRequest, IModuleMinificationResult } from './types'; + +const nth_identifier: SimpleIdentifierMangler = { + get: getIdentifier +}; + +/** + * Minifies a single chunk of code. Factored out for reuse between WorkerPoolMinifier and LocalMinifier + * @internal + */ +export async function minifySingleFileAsync( + request: IModuleMinificationRequest, + terserOptions: MinifyOptions +): Promise { + const { code, nameForMap, hash, externals } = request; + + try { + const { + format: rawFormat, + output: rawOutput, + mangle: originalMangle, + ...remainingOptions + } = terserOptions; + + const format: MinifyOptions['format'] = rawFormat || rawOutput || {}; + + const mangle: MinifyOptions['mangle'] = + originalMangle === false ? false : typeof originalMangle === 'object' ? { ...originalMangle } : {}; + + const finalOptions: MinifyOptions = { + ...remainingOptions, + format, + mangle + }; + format.comments = false; + + if (mangle) { + mangle.nth_identifier = nth_identifier; + } + + if (mangle && externals) { + mangle.reserved = mangle.reserved ? externals.concat(mangle.reserved) : externals; + } + + // SourceMap is only generated if nameForMap is provided- overrides terserOptions.sourceMap + if (nameForMap) { + finalOptions.sourceMap = { + includeSources: true, + asObject: true + }; + } else { + finalOptions.sourceMap = false; + } + + const minified: MinifyOutput = await minify( + { + [nameForMap || 'code']: code + }, + finalOptions + ); + + return { + error: undefined, + code: minified.code!, + map: minified.map as unknown as RawSourceMap, + hash + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + return { + error: error as Error, + code: undefined, + map: undefined, + hash + }; + } +} diff --git a/libraries/module-minifier/src/NoopMinifier.ts b/libraries/module-minifier/src/NoopMinifier.ts new file mode 100644 index 00000000000..c20c4fe593a --- /dev/null +++ b/libraries/module-minifier/src/NoopMinifier.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 type { + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationRequest, + IModuleMinifier +} from './types'; + +/** + * Minifier implementation that does not actually transform the code, for debugging. + * @public + */ +export class NoopMinifier implements IModuleMinifier { + /** + * No-op code transform. + * @param request - The request to process + * @param callback - The callback to invoke + */ + public minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void { + const { code, hash, nameForMap } = request; + + callback({ + hash, + error: undefined, + code, + // If source maps are requested, provide an empty source map + map: nameForMap + ? { + version: 3, + names: [], + file: nameForMap, + sources: [nameForMap], + sourcesContent: [code], + // In source mapping parlance, this means "map line 0, column 0 to the input file at index 0, line 0, column 0" + mappings: 'AAAA' + } + : undefined + }); + } + + /** + * {@inheritdoc IModuleMinifier.connectAsync} + */ + public async connectAsync(): Promise { + const disconnectAsync: IMinifierConnection['disconnectAsync'] = async () => { + // Do nothing. + }; + + return { + configHash: NoopMinifier.name, + disconnectAsync, + disconnect: disconnectAsync + }; + } + + /** + * @deprecated Use {@link NoopMinifier.connectAsync} instead + */ + // eslint-disable-next-line @typescript-eslint/naming-convention + public async connect(): Promise { + return await this.connectAsync(); + } +} diff --git a/libraries/module-minifier/src/WorkerPoolMinifier.ts b/libraries/module-minifier/src/WorkerPoolMinifier.ts new file mode 100644 index 00000000000..4a81fbc75a0 --- /dev/null +++ b/libraries/module-minifier/src/WorkerPoolMinifier.ts @@ -0,0 +1,209 @@ +// 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 os from 'node:os'; +import type { ResourceLimits } from 'node:worker_threads'; + +import serialize from 'serialize-javascript'; +import type { MinifyOptions } from 'terser'; + +import { WorkerPool } from '@rushstack/worker-pool'; + +import type { + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationResult, + IModuleMinificationRequest, + IModuleMinifier +} from './types'; + +/** + * Options for configuring the WorkerPoolMinifier + * @public + */ +export interface IWorkerPoolMinifierOptions { + /** + * Maximum number of worker threads to use. Will never use more than there are modules to process. + * Defaults to os.availableParallelism() + */ + maxThreads?: number; + /** + * The options to forward to Terser. + * `output.comments` is currently not configurable and will always extract license comments to a separate file. + */ + terserOptions?: MinifyOptions; + + /** + * If true, log to the console about the minification results. + */ + verbose?: boolean; + + /** + * Optional resource limits for the workers. + */ + workerResourceLimits?: ResourceLimits; +} + +/** + * Minifier implementation that uses a thread pool for minification. + * @public + */ +export class WorkerPoolMinifier implements IModuleMinifier { + private readonly _pool: WorkerPool; + private readonly _verbose: boolean; + private readonly _configHash: string; + + private _refCount: number; + private _deduped: number; + private _minified: number; + + private readonly _resultCache: Map; + private readonly _activeRequests: Map; + + public constructor(options: IWorkerPoolMinifierOptions) { + const { + maxThreads = os.availableParallelism?.() ?? os.cpus().length, + terserOptions = {}, + verbose = false, + workerResourceLimits + } = options || {}; + + const activeRequests: Map = new Map(); + const resultCache: Map = new Map(); + const terserPool: WorkerPool = new WorkerPool({ + id: 'Minifier', + maxWorkers: maxThreads, + workerData: terserOptions, + workerScriptPath: require.resolve('./MinifierWorker'), + workerResourceLimits + }); + + const { version: terserVersion } = require('terser/package.json'); + + this._configHash = createHash('sha256') + .update(WorkerPoolMinifier.name, 'utf8') + .update(`terser@${terserVersion}`) + .update(serialize(terserOptions)) + .digest('base64'); + + this._activeRequests = activeRequests; + this._refCount = 0; + this._resultCache = resultCache; + this._pool = terserPool; + this._verbose = verbose; + + this._deduped = 0; + this._minified = 0; + } + + public get maxThreads(): number { + return this._pool.maxWorkers; + } + + public set maxThreads(threads: number) { + this._pool.maxWorkers = threads; + } + + /** + * Transform code by farming it out to a worker pool. + * @param request - The request to process + * @param callback - The callback to invoke + */ + public minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void { + const { hash } = request; + + const cached: IModuleMinificationResult | undefined = this._resultCache.get(hash); + if (cached) { + ++this._deduped; + return callback(cached); + } + + const { _activeRequests: activeRequests } = this; + const callbacks: IModuleMinificationCallback[] | undefined = activeRequests.get(hash); + if (callbacks) { + ++this._deduped; + callbacks.push(callback); + return; + } + + activeRequests.set(hash, [callback]); + ++this._minified; + + this._pool + .checkoutWorkerAsync(true) + .then((worker) => { + const cb: (message: IModuleMinificationResult) => void = ( + message: IModuleMinificationResult + ): void => { + worker.off('message', cb); + const workerCallbacks: IModuleMinificationCallback[] | undefined = activeRequests.get( + message.hash + )!; + activeRequests.delete(message.hash); + this._resultCache.set(message.hash, message); + for (const workerCallback of workerCallbacks) { + workerCallback(message); + } + // This should always be the last thing done with the worker + this._pool.checkinWorker(worker); + }; + + worker.on('message', cb); + worker.postMessage(request); + }) + .catch((error: Error) => { + const errorCallbacks: IModuleMinificationCallback[] = activeRequests.get(hash)!; + for (const errorCallback of errorCallbacks) { + errorCallback({ + hash, + error, + code: undefined, + map: undefined + }); + } + }); + } + + /** + * {@inheritdoc IModuleMinifier.connectAsync} + */ + public async connectAsync(): Promise { + if (++this._refCount === 1) { + this._pool.reset(); + } + + const disconnectAsync: IMinifierConnection['disconnectAsync'] = async () => { + if (--this._refCount === 0) { + if (this._verbose) { + // eslint-disable-next-line no-console + console.log(`Shutting down minifier worker pool`); + } + await this._pool.finishAsync(); + this._resultCache.clear(); + this._activeRequests.clear(); + if (this._verbose) { + // eslint-disable-next-line no-console + console.log(`Module minification: ${this._deduped} Deduped, ${this._minified} Processed`); + } + } + this._deduped = 0; + this._minified = 0; + }; + + return { + configHash: this._configHash, + + disconnectAsync, + disconnect: disconnectAsync + }; + } + + /** + * @deprecated Use {@link WorkerPoolMinifier.connectAsync} instead + */ + // eslint-disable-next-line @typescript-eslint/naming-convention + public async connect(): Promise { + return await this.connectAsync(); + } +} diff --git a/libraries/module-minifier/src/constants.ts b/libraries/module-minifier/src/constants.ts new file mode 100644 index 00000000000..4faacf6424e --- /dev/null +++ b/libraries/module-minifier/src/constants.ts @@ -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. + +/** + * The sorted sequence of leading digits for mangled identifiers + * Used in MinifiedIdentifier computation for converting an ordinal to a valid ECMAScript identifier + * @public + */ +export const IDENTIFIER_LEADING_DIGITS: string = 'etnairoscdlufpm_hbgvySDIxCOwEALkMPTUFHRNBjVzGKWqQYJXZ$'; + +/** + * The sorted sequence of trailing digits for mangled identifiers + * Used in MinifiedIdentifier computation for converting an ordinal to a valid ECMAScript identifier + * @public + */ +export const IDENTIFIER_TRAILING_DIGITS: string = + 'etnairoscdlufpm_hbg01v32y67S4985DIxCOwEALkMPTUFHRNBjVzGKWqQYJXZ$'; diff --git a/libraries/module-minifier/src/index.ts b/libraries/module-minifier/src/index.ts new file mode 100644 index 00000000000..b8b6d53f8de --- /dev/null +++ b/libraries/module-minifier/src/index.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. + +/// + +/** + * This library wraps terser in convenient handles for parallelization. + * It powers `@rushstack/webpack4-module-minifier-plugin` and `@rushstack/webpack5-module-minifier-plugin` + * but has no coupling with webpack. + * + * @packageDocumentation + */ + +export type { MinifyOptions } from 'terser'; + +export type { ILocalMinifierOptions } from './LocalMinifier'; +export { LocalMinifier } from './LocalMinifier'; + +export { MessagePortMinifier } from './MessagePortMinifier'; + +export { getIdentifier } from './MinifiedIdentifier'; + +export { minifySingleFileAsync as _minifySingleFileAsync } from './MinifySingleFile'; + +export { NoopMinifier } from './NoopMinifier'; + +export type { + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationErrorResult, + IModuleMinificationRequest, + IModuleMinificationResult, + IModuleMinificationSuccessResult, + IModuleMinifier, + IModuleMinifierFunction +} from './types'; + +export type { IWorkerPoolMinifierOptions } from './WorkerPoolMinifier'; +export { WorkerPoolMinifier } from './WorkerPoolMinifier'; diff --git a/libraries/module-minifier/src/test/LocalMinifier.test.ts b/libraries/module-minifier/src/test/LocalMinifier.test.ts new file mode 100644 index 00000000000..1be9cfa8be8 --- /dev/null +++ b/libraries/module-minifier/src/test/LocalMinifier.test.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 { IMinifierConnection } from '../types'; + +let terserVersion: string = '1.0.0'; +jest.mock('terser/package.json', () => { + return { + get version(): string { + return terserVersion; + } + }; +}); + +describe('LocalMinifier', () => { + it('Includes terserOptions in config hash', async () => { + const { LocalMinifier } = await import('../LocalMinifier'); + // eslint-disable-next-line @typescript-eslint/no-redeclare + type LocalMinifier = typeof LocalMinifier.prototype; + + const minifier1: LocalMinifier = new LocalMinifier({ + terserOptions: { + ecma: 5 + } + }); + const minifier2: LocalMinifier = new LocalMinifier({ + terserOptions: { + ecma: 2015 + } + }); + + const connection1: IMinifierConnection = await minifier1.connectAsync(); + await connection1.disconnectAsync(); + const connection2: IMinifierConnection = await minifier2.connectAsync(); + await connection2.disconnectAsync(); + + expect(connection1.configHash).toMatchSnapshot('ecma5'); + expect(connection2.configHash).toMatchSnapshot('ecma2015'); + expect(connection1.configHash !== connection2.configHash); + }); + + it('Includes terser package version in config hash', async () => { + const { LocalMinifier } = await import('../LocalMinifier'); + // eslint-disable-next-line @typescript-eslint/no-redeclare + type LocalMinifier = typeof LocalMinifier.prototype; + + terserVersion = '5.9.1'; + const minifier1: LocalMinifier = new LocalMinifier({}); + terserVersion = '5.16.2'; + const minifier2: LocalMinifier = new LocalMinifier({}); + + const connection1: IMinifierConnection = await minifier1.connectAsync(); + await connection1.disconnectAsync(); + const connection2: IMinifierConnection = await minifier2.connectAsync(); + await connection2.disconnectAsync(); + + expect(connection1.configHash).toMatchSnapshot('terser-5.9.1'); + expect(connection2.configHash).toMatchSnapshot('terser-5.16.1'); + expect(connection1.configHash !== connection2.configHash); + }); +}); diff --git a/libraries/module-minifier/src/test/MinifiedIdentifier.test.ts b/libraries/module-minifier/src/test/MinifiedIdentifier.test.ts new file mode 100644 index 00000000000..3999b90b4af --- /dev/null +++ b/libraries/module-minifier/src/test/MinifiedIdentifier.test.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 { + getIdentifierInternal, + getOrdinalFromIdentifierInternal, + getIdentifier +} from '../MinifiedIdentifier'; + +describe('MinifiedIdentifier', () => { + describe(getIdentifierInternal.name, () => { + it('Round trips identifiers', () => { + for (let i: number = 0; i < 100000; i++) { + const actual: number = getOrdinalFromIdentifierInternal(getIdentifierInternal(i)); + if (actual !== i) { + throw new Error(`Expected ${i} but received ${actual}`); + } + } + }); + }); + + describe(getIdentifier.name, () => { + it('Skips keywords', () => { + let maxOrdinal: number = 0; + const shortKeywords: Set = new Set(['do', 'if', 'in']); + for (const keyword of shortKeywords) { + const ordinal: number = getOrdinalFromIdentifierInternal(keyword); + if (ordinal > maxOrdinal) { + maxOrdinal = ordinal; + } + const actual: string = getIdentifier(ordinal); + if (actual === keyword) { + throw new Error(`Expected keyword ${keyword} to fail to round trip`); + } + } + + for (let i: number = 0; i <= maxOrdinal; i++) { + const identifier: string = getIdentifier(i); + if (shortKeywords.has(identifier)) { + throw new Error(`Expected keyword ${identifier} to be skipped`); + } + } + }); + }); +}); diff --git a/libraries/module-minifier/src/test/MinifySingleFile.test.ts b/libraries/module-minifier/src/test/MinifySingleFile.test.ts new file mode 100644 index 00000000000..50d7e389ecc --- /dev/null +++ b/libraries/module-minifier/src/test/MinifySingleFile.test.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { minifySingleFileAsync } from '../MinifySingleFile'; + +describe(minifySingleFileAsync.name, () => { + it('uses consistent identifiers for webpack vars', async () => { + const code: string = `__MINIFY_MODULE__(function (module, __webpack_exports__, __webpack_require__) {});`; + + const minifierResult = await minifySingleFileAsync( + { + hash: 'foo', + code, + nameForMap: undefined, + externals: undefined + }, + { + mangle: true + } + ); + + expect(minifierResult).toMatchSnapshot(); + }); +}); diff --git a/libraries/module-minifier/src/test/WorkerPoolMinifier.test.ts b/libraries/module-minifier/src/test/WorkerPoolMinifier.test.ts new file mode 100644 index 00000000000..f0ea7e27383 --- /dev/null +++ b/libraries/module-minifier/src/test/WorkerPoolMinifier.test.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 { IMinifierConnection } from '../types'; + +let terserVersion: string = '1.0.0'; +jest.mock('terser/package.json', () => { + return { + get version(): string { + return terserVersion; + } + }; +}); + +describe('WorkerPoolMinifier', () => { + it('Includes terserOptions in config hash', async () => { + const { WorkerPoolMinifier } = await import('../WorkerPoolMinifier'); + // eslint-disable-next-line @typescript-eslint/no-redeclare + type WorkerPoolMinifier = typeof WorkerPoolMinifier.prototype; + + const minifier1: WorkerPoolMinifier = new WorkerPoolMinifier({ + terserOptions: { + ecma: 5 + } + }); + const minifier2: WorkerPoolMinifier = new WorkerPoolMinifier({ + terserOptions: { + ecma: 2015 + } + }); + + const connection1: IMinifierConnection = await minifier1.connectAsync(); + await connection1.disconnectAsync(); + const connection2: IMinifierConnection = await minifier2.connectAsync(); + await connection2.disconnectAsync(); + + expect(connection1.configHash).toMatchSnapshot('ecma5'); + expect(connection2.configHash).toMatchSnapshot('ecma2015'); + expect(connection1.configHash !== connection2.configHash); + }); + + it('Includes terser package version in config hash', async () => { + const { WorkerPoolMinifier } = await import('../WorkerPoolMinifier'); + // eslint-disable-next-line @typescript-eslint/no-redeclare + type WorkerPoolMinifier = typeof WorkerPoolMinifier.prototype; + + terserVersion = '5.9.1'; + const minifier1: WorkerPoolMinifier = new WorkerPoolMinifier({}); + terserVersion = '5.16.2'; + const minifier2: WorkerPoolMinifier = new WorkerPoolMinifier({}); + + const connection1: IMinifierConnection = await minifier1.connectAsync(); + await connection1.disconnectAsync(); + const connection2: IMinifierConnection = await minifier2.connectAsync(); + await connection2.disconnectAsync(); + + expect(connection1.configHash).toMatchSnapshot('terser-5.9.1'); + expect(connection2.configHash).toMatchSnapshot('terser-5.16.1'); + expect(connection1.configHash !== connection2.configHash); + }); +}); diff --git a/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap b/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap new file mode 100644 index 00000000000..a310d9b8a69 --- /dev/null +++ b/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalMinifier Includes terser package version in config hash: terser-5.9.1 1`] = `"4EVkVBAkdvF45JdRt44fWqn3HDW5t4dHo0zmzpQrWtc="`; + +exports[`LocalMinifier Includes terser package version in config hash: terser-5.16.1 1`] = `"3tk4bireIeb1adtnntg0kD4LU91VU+hweuk5GEkvX9A="`; + +exports[`LocalMinifier Includes terserOptions in config hash: ecma5 1`] = `"xpQ+VFd1iTb0qFjWnrRxNm25O1Z77Oy9Ppi+VG9SFEQ="`; + +exports[`LocalMinifier Includes terserOptions in config hash: ecma2015 1`] = `"IvCYjNIccj8xYkftaoV19M8WU5Vzy+06PL6gzGVUYxI="`; diff --git a/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap b/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap new file mode 100644 index 00000000000..a66aee94e2f --- /dev/null +++ b/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`minifySingleFileAsync uses consistent identifiers for webpack vars 1`] = ` +Object { + "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 new file mode 100644 index 00000000000..78c3f7dafef --- /dev/null +++ b/libraries/module-minifier/src/test/__snapshots__/WorkerPoolMinifier.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WorkerPoolMinifier Includes terser package version in config hash: terser-5.9.1 1`] = `"0cjBnphY49XdxkmLxJLfNoRQbl3R6HdeT8WNl56oZWk="`; + +exports[`WorkerPoolMinifier Includes terser package version in config hash: terser-5.16.1 1`] = `"dYinCy9XUHWWDXSIwq7F/GvAYLxxv3WjZdHIpd2sZpc="`; + +exports[`WorkerPoolMinifier Includes terserOptions in config hash: ecma5 1`] = `"FcgklO/zYzwo0R2IM6OKH5uLA0hXVekjeqmFqKweKCg="`; + +exports[`WorkerPoolMinifier Includes terserOptions in config hash: ecma2015 1`] = `"Vku2B3kuB95N1Xo2q8J/nAJrmxwXV+fQmmUwp4xj+Xk="`; diff --git a/libraries/module-minifier/src/types.ts b/libraries/module-minifier/src/types.ts new file mode 100644 index 00000000000..5340bb06b9b --- /dev/null +++ b/libraries/module-minifier/src/types.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 { RawSourceMap } from 'source-map'; + +/** + * Request to the minifier + * @public + */ +export interface IModuleMinificationRequest { + /** + * Identity of the request. Will be included in the response. + */ + hash: string; + /** + * The raw code fragment + */ + code: string; + /** + * File name to show for the source code in the source map + */ + nameForMap: string | undefined; + /** + * Reserved variable names, e.g. __WEBPACK_EXTERNAL_MODULE_1__ + */ + externals: string[] | undefined; +} + +/** + * Result from the minifier function when an error is encountered. + * @public + */ +export interface IModuleMinificationErrorResult { + /** + * Identity of the request + */ + hash: string; + /** + * The error encountered, to be added to the current compilation's error collection. + */ + error: Error; + /** + * Marker property to always return the same result shape. + */ + code?: undefined; + /** + * Marker property to always return the same result shape. + */ + map?: undefined; +} + +/** + * Result from the minifier on a successful minification. + * @public + */ +export interface IModuleMinificationSuccessResult { + /** + * Identity of the request + */ + hash: string; + /** + * The error property being `undefined` indicates success. + */ + error: undefined; + /** + * The minified code. + */ + code: string; + /** + * Marker property to always return the same result shape. + */ + map?: RawSourceMap; +} + +/** + * Result from the minifier. + * @public + */ +export type IModuleMinificationResult = IModuleMinificationErrorResult | IModuleMinificationSuccessResult; + +/** + * Callback passed to a minifier function + * @public + */ +export interface IModuleMinificationCallback { + (result: IModuleMinificationResult): void; +} + +/** + * An async function called to minify a chunk of code + * @public + */ +export interface IModuleMinifierFunction { + (request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void; +} + +/** + * Metadata from the minifier for the plugin + * @public + */ +export interface IMinifierConnection { + /** + * Hash of the configuration of this minifier, for cache busting. + */ + configHash: string; + + /** + * @deprecated Use {@link IMinifierConnection.disconnectAsync} instead. + */ + disconnect(): Promise; + + /** + * Callback to be invoked when done with the minifier + */ + disconnectAsync(): Promise; +} + +/** + * Object that can be invoked to minify code. + * @public + */ +export interface IModuleMinifier { + /** + * Asynchronously minify a module + */ + minify: IModuleMinifierFunction; + + /** + * @deprecated Use {@link IModuleMinifier.connectAsync} instead. + */ + connect(): Promise; + + /** + * Prevents the minifier from shutting down until the returned `disconnect()` callback is invoked. + * The callback may be used to surface errors encountered by the minifier that may not be relevant to a specific file. + * It should be called to allow the minifier to cleanup + */ + connectAsync(): Promise; +} diff --git a/libraries/module-minifier/tsconfig.json b/libraries/module-minifier/tsconfig.json new file mode 100644 index 00000000000..f471d671b3f --- /dev/null +++ b/libraries/module-minifier/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "target": "ES2019" + } +} diff --git a/libraries/node-core-library/.eslintrc.js b/libraries/node-core-library/.eslintrc.js deleted file mode 100644 index 8195b92f6b2..00000000000 --- a/libraries/node-core-library/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require("@rushstack/eslint-config/patch-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, - - // TODO: Remove this once "tsdoc/syntax" is enabled by default - rules: { "tsdoc/syntax": "error" } -}; diff --git a/libraries/node-core-library/.npmignore b/libraries/node-core-library/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/node-core-library/.npmignore +++ b/libraries/node-core-library/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/node-core-library/CHANGELOG.json b/libraries/node-core-library/CHANGELOG.json index 6713dfcbca0..847f25b5daa 100644 --- a/libraries/node-core-library/CHANGELOG.json +++ b/libraries/node-core-library/CHANGELOG.json @@ -1,6 +1,1990 @@ { "name": "@rushstack/node-core-library", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fix handling of trailing slashes and relative paths in RealNodeModulePath to match semantics of `fs.realpathSync.native`." + } + ] + } + }, + { + "version": "5.10.0", + "tag": "@rushstack/node-core-library_v5.10.0", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "minor": [ + { + "comment": "Add `RealNodeModulePathResolver` class to get equivalent behavior to `realpath` with fewer system calls (and therefore higher performance) in the typical scenario where the only symlinks in the repository are inside of `node_modules` folders and are links to package folders." + } + ] + } + }, + { + "version": "5.9.0", + "tag": "@rushstack/node-core-library_v5.9.0", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `Sort.sortKeys` function for sorting keys in an object" + }, + { + "comment": "Rename `LockFile.acquire` to `Lockfile.acquireAsync`." + } + ], + "patch": [ + { + "comment": "Fix an issue where attempting to acquire multiple `LockFile`s at the same time on POSIX would cause the second to immediately be acquired without releasing the first." + } + ] + } + }, + { + "version": "5.8.0", + "tag": "@rushstack/node-core-library_v5.8.0", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `customFormats` option to `JsonSchema`." + } + ] + } + }, + { + "version": "5.7.0", + "tag": "@rushstack/node-core-library_v5.7.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a `Text.splitByNewLines` function." + } + ] + } + }, + { + "version": "5.6.0", + "tag": "@rushstack/node-core-library_v5.6.0", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `ignoreSchemaField` option to the `JsonSchema.validateObject` options to ignore `$schema` properties and add an options object argument to `JsonSchema.validateObjectWithCallback` with the same `ignoreSchemaField` option." + } + ] + } + }, + { + "version": "5.5.1", + "tag": "@rushstack/node-core-library_v5.5.1", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ] + } + }, + { + "version": "5.5.0", + "tag": "@rushstack/node-core-library_v5.5.0", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for the `jsonSyntax` option to the `JsonFile.save`, `JsonFile.saveAsync`, and `JsonFile.stringify` functions." + } + ] + } + }, + { + "version": "5.4.1", + "tag": "@rushstack/node-core-library_v5.4.1", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ] + } + }, + { + "version": "5.4.0", + "tag": "@rushstack/node-core-library_v5.4.0", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `throwOnSignal` option to the `Executable.waitForExitAsync` to control if that function should throw if the process is terminated with a signal." + }, + { + "comment": "Add a `signal` property to the result of `Executable.waitForExitAsync` that includes a signal if the process was termianted by a signal." + } + ] + } + }, + { + "version": "5.3.0", + "tag": "@rushstack/node-core-library_v5.3.0", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "minor": [ + { + "comment": "Include typings for the the `\"files\"` field in `IPackageJson`." + } + ] + } + }, + { + "version": "5.2.0", + "tag": "@rushstack/node-core-library_v5.2.0", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "minor": [ + { + "comment": "Include typings for the `\"exports\"` and `\"typesVersions\"` fields in `IPackageJson`." + } + ] + } + }, + { + "version": "5.1.0", + "tag": "@rushstack/node-core-library_v5.1.0", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "minor": [ + { + "comment": "Update `JsonFile` to support loading JSON files that include object keys that are members of `Object.prototype`." + } + ], + "patch": [ + { + "comment": "Fix an issue with `JsonSchema` where `\"uniqueItems\": true` would throw an error if the `\"item\"` type in the schema has `\"type\": \"object\"`." + } + ] + } + }, + { + "version": "5.0.0", + "tag": "@rushstack/node-core-library_v5.0.0", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "major": [ + { + "comment": "Replace z-schema with ajv for schema validation and add support for json-schema draft-07." + }, + { + "comment": "Remove the deprecated `Async.sleep` function." + }, + { + "comment": "Convert `FileConstants` and `FolderConstants` from enums to const objects." + } + ], + "patch": [ + { + "comment": "Fix an issue where waitForExitAsync() might reject before all output was collected" + } + ] + } + }, + { + "version": "4.3.0", + "tag": "@rushstack/node-core-library_v4.3.0", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "minor": [ + { + "comment": "Rename `Async.sleep` to `Async.sleepAsync`. The old function is marked as `@deprecated`." + } + ] + } + }, + { + "version": "4.2.1", + "tag": "@rushstack/node-core-library_v4.2.1", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug in `Async.forEachAsync` where weight wasn't respected." + } + ] + } + }, + { + "version": "4.2.0", + "tag": "@rushstack/node-core-library_v4.2.0", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new `weighted: true` option to the `Async.forEachAsync` method that allows each element to specify how much of the allowed parallelism the callback uses." + } + ], + "patch": [ + { + "comment": "Add a new `weighted: true` option to the `Async.mapAsync` method that allows each element to specify how much of the allowed parallelism the callback uses." + } + ] + } + }, + { + "version": "4.1.0", + "tag": "@rushstack/node-core-library_v4.1.0", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "minor": [ + { + "comment": "Add `writeBuffersToFile` and `writeBuffersToFileAsync` methods to `FileSystem` for efficient writing of concatenated files." + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@rushstack/node-core-library_v4.0.2", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@rushstack/node-core-library_v4.0.1", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "patch": [ + { + "comment": "Remove a no longer needed dependency on the `colors` package" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@rushstack/node-core-library_v4.0.0", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "major": [ + { + "comment": "(BREAKING CHANGE) Remove the Terminal and related APIs (Colors, AsciEscape, etc). These have been moved into the @rushstack/terminal package. See https://github.com/microsoft/rushstack/pull/3176 for details." + }, + { + "comment": "Remove deprecated `FileSystem.readFolder`, `FileSystem.readFolderAsync`, and `LegacyAdapters.sortStable` APIs." + } + ], + "minor": [ + { + "comment": "Graduate `Async` and `MinimumHeap` APIs from beta to public." + } + ] + } + }, + { + "version": "3.66.1", + "tag": "@rushstack/node-core-library_v3.66.1", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ] + } + }, + { + "version": "3.66.0", + "tag": "@rushstack/node-core-library_v3.66.0", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "patch": [ + { + "comment": "LockFile: prevent accidentaly deleting freshly created lockfile when multiple processes try to acquire the same lock on macOS/Linux" + } + ], + "minor": [ + { + "comment": "Add getStatistics() method to FileWriter instances" + } + ] + } + }, + { + "version": "3.65.0", + "tag": "@rushstack/node-core-library_v3.65.0", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "minor": [ + { + "comment": "Inclue a `Text.reverse` API for reversing a string." + } + ] + } + }, + { + "version": "3.64.2", + "tag": "@rushstack/node-core-library_v3.64.2", + "date": "Thu, 25 Jan 2024 01:09:29 GMT", + "comments": { + "patch": [ + { + "comment": "Improve 'bin' definition in `IPackageJson` type" + } + ] + } + }, + { + "version": "3.64.1", + "tag": "@rushstack/node-core-library_v3.64.1", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "patch": [ + { + "comment": "Fix Executable.getProcessInfoBy* methods truncating the process name on MacOS" + } + ] + } + }, + { + "version": "3.64.0", + "tag": "@rushstack/node-core-library_v3.64.0", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "minor": [ + { + "comment": "Add the `dependenciesMeta` property to the `INodePackageJson` interface." + } + ] + } + }, + { + "version": "3.63.0", + "tag": "@rushstack/node-core-library_v3.63.0", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "minor": [ + { + "comment": "Updates the `JsonFile` API to format JSON as JSON5 if an existing string is being updated to preserve the style of the existing JSON." + } + ] + } + }, + { + "version": "3.62.0", + "tag": "@rushstack/node-core-library_v3.62.0", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "minor": [ + { + "comment": "Add functions inside the `Executable` API to list all process trees (`getProcessInfoById`, `getProcessInfoByIdAsync`, `getProcessInfoByName`, and `getProcessInfoByNameAsync`)." + }, + { + "comment": "Add functions inside the `Text` API to split iterables (or async iterables) that produce strings or buffers on newlines (`readLinesFromIterable` and `readLinesFromIterableAsync`)." + }, + { + "comment": "Add the `waitForExitAsync` method inside the `Executable` API used to wait for a provided child process to exit." + } + ] + } + }, + { + "version": "3.61.0", + "tag": "@rushstack/node-core-library_v3.61.0", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "minor": [ + { + "comment": "Add Async.getSignal for promise-based signaling. Add MinimumHeap for use as a priority queue." + } + ] + } + }, + { + "version": "3.60.1", + "tag": "@rushstack/node-core-library_v3.60.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ] + } + }, + { + "version": "3.60.0", + "tag": "@rushstack/node-core-library_v3.60.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "3.59.7", + "tag": "@rushstack/node-core-library_v3.59.7", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "none": [ + { + "comment": "Update error messages when modules or packages cannot be found using the \"Import.resolve*\" methods." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "3.59.6", + "tag": "@rushstack/node-core-library_v3.59.6", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Updated semver dependency" + } + ] + } + }, + { + "version": "3.59.5", + "tag": "@rushstack/node-core-library_v3.59.5", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "patch": [ + { + "comment": "Fix Import.resolveModule* and Import.resolvePackage* methods to return real-paths when resolving self-referencing specs" + } + ] + } + }, + { + "version": "3.59.4", + "tag": "@rushstack/node-core-library_v3.59.4", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "3.59.3", + "tag": "@rushstack/node-core-library_v3.59.3", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "3.59.2", + "tag": "@rushstack/node-core-library_v3.59.2", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "patch": [ + { + "comment": "Remove extraneous string encode/decode of final output during `JsonFile.save`/`JsonFile.saveAsync`." + } + ] + } + }, + { + "version": "3.59.1", + "tag": "@rushstack/node-core-library_v3.59.1", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "3.59.0", + "tag": "@rushstack/node-core-library_v3.59.0", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to the `PrefixProxyTerminalProvider` to create a dynamic prefix, which can be used for something like prefixing logging lines with a timestamp." + } + ] + } + }, + { + "version": "3.58.0", + "tag": "@rushstack/node-core-library_v3.58.0", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "minor": [ + { + "comment": "Expose a `Text.escapeRegExp` function to escape regexp special characters." + } + ] + } + }, + { + "version": "3.57.0", + "tag": "@rushstack/node-core-library_v3.57.0", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "minor": [ + { + "comment": "Add PrefixProxyTerminalProvider to allow for prefixing a provided string before writing to a terminal provider" + }, + { + "comment": "Add a Writable stream adapter for ITerminal to allow writing to a terminal as a stream" + } + ] + } + }, + { + "version": "3.56.0", + "tag": "@rushstack/node-core-library_v3.56.0", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "minor": [ + { + "comment": "Adds the AsyncQueue class, a queue type that allows for iterating and concurrently adding to the queue" + }, + { + "comment": "Adds support for async Import.resolve* APIs" + } + ], + "patch": [ + { + "comment": "Fix a typings issue in FileSystem.copyFilesAsync" + }, + { + "comment": "Fix issues with Import.resolve* APIs when attempting to resolve system modules paths (ex. 'fs/promises') and self-referencing module paths" + } + ] + } + }, + { + "version": "3.55.2", + "tag": "@rushstack/node-core-library_v3.55.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "3.55.1", + "tag": "@rushstack/node-core-library_v3.55.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ] + } + }, + { + "version": "3.55.0", + "tag": "@rushstack/node-core-library_v3.55.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ] + } + }, + { + "version": "3.54.0", + "tag": "@rushstack/node-core-library_v3.54.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `peerDependenciesMeta` property to `IPackageJson`." + }, + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ] + } + }, + { + "version": "3.53.3", + "tag": "@rushstack/node-core-library_v3.53.3", + "date": "Fri, 09 Dec 2022 16:18:27 GMT", + "comments": { + "patch": [ + { + "comment": "Improve performance of `Import.resolvePackage`." + }, + { + "comment": "Improve the error message emitted when a path inside a package is passed to `Import.resolvePackage`." + } + ] + } + }, + { + "version": "3.53.2", + "tag": "@rushstack/node-core-library_v3.53.2", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug where `Sort.isSorted` and `Sort.isSortedBy` unexpectedly compared the first element against `undefined`. Optimize `Sort.sortMapKeys` to run the check for already being sorted against the original Map instead of a derived array." + } + ] + } + }, + { + "version": "3.53.1", + "tag": "@rushstack/node-core-library_v3.53.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "3.53.0", + "tag": "@rushstack/node-core-library_v3.53.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Add a Path.convertToPlatformDefault API to convert a path to use the platform-default slashes." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "3.52.0", + "tag": "@rushstack/node-core-library_v3.52.0", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add a \"FileSystem.isNotDirectoryError\" function that returns `true` if the passed-in error object is an ENOTDIR error." + }, + { + "comment": "Add a parameter to the `LockFile.release` function to optionally delete the lockfile." + } + ] + } + }, + { + "version": "3.51.2", + "tag": "@rushstack/node-core-library_v3.51.2", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "3.51.1", + "tag": "@rushstack/node-core-library_v3.51.1", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "patch": [ + { + "comment": "Introduce JsonSyntax option for JsonFile.load() and related APIs" + } + ] + } + }, + { + "version": "3.51.0", + "tag": "@rushstack/node-core-library_v3.51.0", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "minor": [ + { + "comment": "Deprecate LegacyAdapters.sortStable and remove support for NodeJS < 11. If you are using NodeJS < 11, this is a breaking change." + } + ] + } + }, + { + "version": "3.50.2", + "tag": "@rushstack/node-core-library_v3.50.2", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "patch": [ + { + "comment": "Update `PackageJsonLookup` to only resolve to `package.json` files that contain a `\"name\"` field. See GitHub issue #2070" + } + ] + } + }, + { + "version": "3.50.1", + "tag": "@rushstack/node-core-library_v3.50.1", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "3.50.0", + "tag": "@rushstack/node-core-library_v3.50.0", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add an Async.runWithRetriesAsync() API to run and a retry an async function that may intermittently fail." + } + ] + } + }, + { + "version": "3.49.0", + "tag": "@rushstack/node-core-library_v3.49.0", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "minor": [ + { + "comment": "Add SubprocessTerminator utility, which can be used to kill a process and all of its child processes on demand or on termination of the host process." + } + ] + } + }, + { + "version": "3.48.0", + "tag": "@rushstack/node-core-library_v3.48.0", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add FileSystem.isDirectoryError utility function to determine if an error has the code \"EISDIR\". This error code may be returned (for example) when attempting to delete a folder as if it were a file using the FileSystem.deleteFile API." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "3.47.0", + "tag": "@rushstack/node-core-library_v3.47.0", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "minor": [ + { + "comment": "Add a \"trimLeadingDotSlash\" option to the Path.formatConcisely function to not include the leading \"./\" in paths under the baseFolder." + }, + { + "comment": "Change the FileError relative path output to not include the leading \"./\"" + } + ] + } + }, + { + "version": "3.46.0", + "tag": "@rushstack/node-core-library_v3.46.0", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add FileError class. This error type can be thrown when encountering an error at a specific line and column of a target file." + } + ] + } + }, + { + "version": "3.45.7", + "tag": "@rushstack/node-core-library_v3.45.7", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a race condition affecting the LockFile API on the Linux operating system" + } + ] + } + }, + { + "version": "3.45.6", + "tag": "@rushstack/node-core-library_v3.45.6", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "3.45.5", + "tag": "@rushstack/node-core-library_v3.45.5", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "patch": [ + { + "comment": "Fix and issue where Async.forEachAsync with an async iterator can overflow the max concurrency" + } + ] + } + }, + { + "version": "3.45.4", + "tag": "@rushstack/node-core-library_v3.45.4", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "3.45.3", + "tag": "@rushstack/node-core-library_v3.45.3", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "3.45.2", + "tag": "@rushstack/node-core-library_v3.45.2", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "3.45.1", + "tag": "@rushstack/node-core-library_v3.45.1", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "3.45.0", + "tag": "@rushstack/node-core-library_v3.45.0", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "minor": [ + { + "comment": "Expose a FileSystem.readFolderItems and FileSystem.readFolderItemsAsync API to get folder entries with types in a single API call." + }, + { + "comment": "Deprecate FileSystem.readFolder in favor of FileSystem.readFolderItemNames." + } + ] + } + }, + { + "version": "3.44.3", + "tag": "@rushstack/node-core-library_v3.44.3", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "3.44.2", + "tag": "@rushstack/node-core-library_v3.44.2", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "patch": [ + { + "comment": "Update z-schema to ~5.0.2." + } + ] + } + }, + { + "version": "3.44.1", + "tag": "@rushstack/node-core-library_v3.44.1", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "3.44.0", + "tag": "@rushstack/node-core-library_v3.44.0", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "minor": [ + { + "comment": "Replace const enums with conventional enums to allow for compatability with JavaScript consumers." + } + ] + } + }, + { + "version": "3.43.2", + "tag": "@rushstack/node-core-library_v3.43.2", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "patch": [ + { + "comment": "Updated Path.convertToSlashes() to use replace(/\\\\/g, '/') instead of split/join for better performance." + } + ] + } + }, + { + "version": "3.43.1", + "tag": "@rushstack/node-core-library_v3.43.1", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "3.43.0", + "tag": "@rushstack/node-core-library_v3.43.0", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "minor": [ + { + "comment": "Add more elaborate \"repository\" field types in IPackageJson." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "3.42.3", + "tag": "@rushstack/node-core-library_v3.42.3", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "3.42.2", + "tag": "@rushstack/node-core-library_v3.42.2", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where Async.foreEachAsync can never resolve when operating on a large array." + } + ] + } + }, + { + "version": "3.42.1", + "tag": "@rushstack/node-core-library_v3.42.1", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "3.42.0", + "tag": "@rushstack/node-core-library_v3.42.0", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "minor": [ + { + "comment": "Expose an ITerminal interface." + } + ] + } + }, + { + "version": "3.41.0", + "tag": "@rushstack/node-core-library_v3.41.0", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "minor": [ + { + "comment": "Allow Async.mapAsync and Async.forEachAsync to take an iterator." + } + ] + } + }, + { + "version": "3.40.3", + "tag": "@rushstack/node-core-library_v3.40.3", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "3.40.2", + "tag": "@rushstack/node-core-library_v3.40.2", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "patch": [ + { + "comment": "Improve documentation to clarify usage for FileSystem APIs related to symbolic links" + } + ] + } + }, + { + "version": "3.40.1", + "tag": "@rushstack/node-core-library_v3.40.1", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for AlreadyExistsBehavior in symlink and junction scenarios" + } + ] + } + }, + { + "version": "3.40.0", + "tag": "@rushstack/node-core-library_v3.40.0", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "minor": [ + { + "comment": "Add new Terminal message severity \"debug\", below verbose." + } + ] + } + }, + { + "version": "3.39.1", + "tag": "@rushstack/node-core-library_v3.39.1", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "3.39.0", + "tag": "@rushstack/node-core-library_v3.39.0", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "minor": [ + { + "comment": "BREAKING CHANGE: Remove FileSystem.copyFileToManyAsync API. It was determined that this API was a likely source of 0-length file copies. Recommended replacement is to call copyFileAsync." + } + ] + } + }, + { + "version": "3.38.0", + "tag": "@rushstack/node-core-library_v3.38.0", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "minor": [ + { + "comment": "Add `ignoreUndefinedValues` option to JsonFile to discard keys with undefined values during serialization; this is the standard behavior of `JSON.stringify()` and other JSON serializers." + } + ] + } + }, + { + "version": "3.37.0", + "tag": "@rushstack/node-core-library_v3.37.0", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new API \"Async\" with some utilities for working with promises" + } + ] + } + }, + { + "version": "3.36.2", + "tag": "@rushstack/node-core-library_v3.36.2", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "3.36.1", + "tag": "@rushstack/node-core-library_v3.36.1", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "3.36.0", + "tag": "@rushstack/node-core-library_v3.36.0", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add EnvironmentMap API" + }, + { + "comment": "Add Executable.spawn() API" + } + ] + } + }, + { + "version": "3.35.2", + "tag": "@rushstack/node-core-library_v3.35.2", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "3.35.1", + "tag": "@rushstack/node-core-library_v3.35.1", + "date": "Wed, 11 Nov 2020 01:08:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "3.35.0", + "tag": "@rushstack/node-core-library_v3.35.0", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add new \"copyFileToMany\" API to copy a single file to multiple locations" + }, + { + "comment": "Add an alreadyExistsBehavior option to the options for creating links in FileSystem." + } + ] + } + }, + { + "version": "3.34.7", + "tag": "@rushstack/node-core-library_v3.34.7", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "3.34.6", + "tag": "@rushstack/node-core-library_v3.34.6", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "3.34.5", + "tag": "@rushstack/node-core-library_v3.34.5", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "3.34.4", + "tag": "@rushstack/node-core-library_v3.34.4", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the TextAttribute.Bold ANSI escape was not rendered correctly by Linux" + } + ] + } + }, + { + "version": "3.34.3", + "tag": "@rushstack/node-core-library_v3.34.3", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + } + ] + } + }, + { + "version": "3.34.2", + "tag": "@rushstack/node-core-library_v3.34.2", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + } + ] + } + }, + { + "version": "3.34.1", + "tag": "@rushstack/node-core-library_v3.34.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + } + ] + } + }, + { + "version": "3.34.0", + "tag": "@rushstack/node-core-library_v3.34.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "Add Path.isEqual(), Path.formatConcisely(), Path.convertToSlashes(), Path.convertToBackslashes(), and Path.isDownwardRelative()" + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "3.33.6", + "tag": "@rushstack/node-core-library_v3.33.6", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "3.33.5", + "tag": "@rushstack/node-core-library_v3.33.5", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "3.33.4", + "tag": "@rushstack/node-core-library_v3.33.4", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "3.33.3", + "tag": "@rushstack/node-core-library_v3.33.3", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "3.33.2", + "tag": "@rushstack/node-core-library_v3.33.2", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "3.33.1", + "tag": "@rushstack/node-core-library_v3.33.1", + "date": "Fri, 18 Sep 2020 22:57:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "3.33.0", + "tag": "@rushstack/node-core-library_v3.33.0", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "minor": [ + { + "comment": "Add a missing \"existsAsync\" function to the FileSystem API." + } + ] + } + }, + { + "version": "3.32.0", + "tag": "@rushstack/node-core-library_v3.32.0", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "minor": [ + { + "comment": "Add Text.getNewline() and FileWriter.filePath" + }, + { + "comment": "Add Brand API" + } + ] + } + }, + { + "version": "3.31.0", + "tag": "@rushstack/node-core-library_v3.31.0", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "minor": [ + { + "comment": "Replace Colors.normalizeColorTokensForTest() (which was marked as \"beta\") with AnsiEscape.formatForTests()" + } + ] + } + }, + { + "version": "3.30.0", + "tag": "@rushstack/node-core-library_v3.30.0", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "minor": [ + { + "comment": "Include an API for resolving packages and modules." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + }, + { + "version": "3.29.1", + "tag": "@rushstack/node-core-library_v3.29.1", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + } + ] + } + }, + { + "version": "3.29.0", + "tag": "@rushstack/node-core-library_v3.29.0", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a \"JsonNull\" type for describing legacy JSON structures without triggering the \"@rushstack/no-new-null\" lint rule" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + } + ] + } + }, + { + "version": "3.28.0", + "tag": "@rushstack/node-core-library_v3.28.0", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add a utility function for making console color codes human-readable." + }, + { + "comment": "Create a lighter weight function to get own package version." + } + ], + "patch": [ + { + "comment": "Lazy-import some packages to improve spin up times." + } + ] + } + }, + { + "version": "3.27.0", + "tag": "@rushstack/node-core-library_v3.27.0", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "minor": [ + { + "comment": "Add new APIs AlreadyReportedError and TypeUuid" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + } + ] + } + }, + { + "version": "3.26.2", + "tag": "@rushstack/node-core-library_v3.26.2", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + } + ] + } + }, + { + "version": "3.26.1", + "tag": "@rushstack/node-core-library_v3.26.1", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "patch": [ + { + "comment": "Triggering publish of dependents" + } + ] + } + }, + { + "version": "3.26.0", + "tag": "@rushstack/node-core-library_v3.26.0", + "date": "Mon, 03 Aug 2020 06:55:14 GMT", + "comments": { + "minor": [ + { + "comment": "Added IJsonFileStringifyOptions.headerComment" + } + ] + } + }, + { + "version": "3.25.0", + "tag": "@rushstack/node-core-library_v3.25.0", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add a utility method to convert a map into an object" + } + ] + } + }, + { + "version": "3.24.4", + "tag": "@rushstack/node-core-library_v3.24.4", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "3.24.3", + "tag": "@rushstack/node-core-library_v3.24.3", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@rushstack/node-core-library_v3.24.2", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "3.24.1", + "tag": "@rushstack/node-core-library_v3.24.1", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "patch": [ + { + "comment": "Improve API docs for \"LockFile\"" + } + ] + } + }, + { + "version": "3.24.0", + "tag": "@rushstack/node-core-library_v3.24.0", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "minor": [ + { + "comment": "Add a FileSystem.copyFiles() API for recursively copying folders, and clarify that FileSystem.copyFile() only copies a single file" + } + ] + } + }, + { + "version": "3.23.1", + "tag": "@rushstack/node-core-library_v3.23.1", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "patch": [ + { + "comment": "Improve async callstacks for FileSystem API (when using Node 12)" + } + ] + } + }, + { + "version": "3.23.0", + "tag": "@rushstack/node-core-library_v3.23.0", + "date": "Wed, 27 May 2020 05:15:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add an \"FileSystemStats\" alias to avoid the need to import \"fs\" when using the FileSystem API" + }, + { + "comment": "Add FileSystem.readLink() and readLinkAsync()" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "3.22.1", + "tag": "@rushstack/node-core-library_v3.22.1", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "patch": [ + { + "comment": "Make not-exist error messages more readable." + } + ] + } + }, + { + "version": "3.22.0", + "tag": "@rushstack/node-core-library_v3.22.0", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "minor": [ + { + "comment": "Expose string parsing APIs from JsonFile." + } + ] + } + }, + { + "version": "3.21.0", + "tag": "@rushstack/node-core-library_v3.21.0", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "minor": [ + { + "comment": "Create async versions of FileSystem and JsonFile APIs." + } + ] + } + }, + { + "version": "3.20.0", + "tag": "@rushstack/node-core-library_v3.20.0", + "date": "Thu, 21 May 2020 15:41:59 GMT", + "comments": { + "minor": [ + { + "comment": "Add PackageNameParser class, which is a configurable version of the PackageName API" + } + ] + } + }, + { + "version": "3.19.7", + "tag": "@rushstack/node-core-library_v3.19.7", + "date": "Wed, 08 Apr 2020 04:07:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "3.19.6", + "tag": "@rushstack/node-core-library_v3.19.6", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "3.19.5", "tag": "@rushstack/node-core-library_v3.19.5", diff --git a/libraries/node-core-library/CHANGELOG.md b/libraries/node-core-library/CHANGELOG.md index 736f8872a74..2f97945819b 100644 --- a/libraries/node-core-library/CHANGELOG.md +++ b/libraries/node-core-library/CHANGELOG.md @@ -1,6 +1,1035 @@ # Change Log - @rushstack/node-core-library -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +### Patches + +- Fix handling of trailing slashes and relative paths in RealNodeModulePath to match semantics of `fs.realpathSync.native`. + +## 5.10.0 +Fri, 22 Nov 2024 01:10:43 GMT + +### Minor changes + +- Add `RealNodeModulePathResolver` class to get equivalent behavior to `realpath` with fewer system calls (and therefore higher performance) in the typical scenario where the only symlinks in the repository are inside of `node_modules` folders and are links to package folders. + +## 5.9.0 +Fri, 13 Sep 2024 00:11:42 GMT + +### Minor changes + +- Add a `Sort.sortKeys` function for sorting keys in an object +- Rename `LockFile.acquire` to `Lockfile.acquireAsync`. + +### Patches + +- Fix an issue where attempting to acquire multiple `LockFile`s at the same time on POSIX would cause the second to immediately be acquired without releasing the first. + +## 5.8.0 +Tue, 10 Sep 2024 20:08:11 GMT + +### Minor changes + +- Add a `customFormats` option to `JsonSchema`. + +## 5.7.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Introduce a `Text.splitByNewLines` function. + +## 5.6.0 +Mon, 12 Aug 2024 22:16:04 GMT + +### Minor changes + +- Add a `ignoreSchemaField` option to the `JsonSchema.validateObject` options to ignore `$schema` properties and add an options object argument to `JsonSchema.validateObjectWithCallback` with the same `ignoreSchemaField` option. + +## 5.5.1 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 5.5.0 +Tue, 16 Jul 2024 00:36:21 GMT + +### Minor changes + +- Add support for the `jsonSyntax` option to the `JsonFile.save`, `JsonFile.saveAsync`, and `JsonFile.stringify` functions. + +## 5.4.1 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 5.4.0 +Wed, 29 May 2024 02:03:50 GMT + +### Minor changes + +- Add a `throwOnSignal` option to the `Executable.waitForExitAsync` to control if that function should throw if the process is terminated with a signal. +- Add a `signal` property to the result of `Executable.waitForExitAsync` that includes a signal if the process was termianted by a signal. + +## 5.3.0 +Tue, 28 May 2024 15:10:09 GMT + +### Minor changes + +- Include typings for the the `"files"` field in `IPackageJson`. + +## 5.2.0 +Tue, 28 May 2024 00:09:47 GMT + +### Minor changes + +- Include typings for the `"exports"` and `"typesVersions"` fields in `IPackageJson`. + +## 5.1.0 +Sat, 25 May 2024 04:54:07 GMT + +### Minor changes + +- Update `JsonFile` to support loading JSON files that include object keys that are members of `Object.prototype`. + +### Patches + +- Fix an issue with `JsonSchema` where `"uniqueItems": true` would throw an error if the `"item"` type in the schema has `"type": "object"`. + +## 5.0.0 +Thu, 23 May 2024 02:26:56 GMT + +### Breaking changes + +- Replace z-schema with ajv for schema validation and add support for json-schema draft-07. +- Remove the deprecated `Async.sleep` function. +- Convert `FileConstants` and `FolderConstants` from enums to const objects. + +### Patches + +- Fix an issue where waitForExitAsync() might reject before all output was collected + +## 4.3.0 +Wed, 15 May 2024 06:04:17 GMT + +### Minor changes + +- Rename `Async.sleep` to `Async.sleepAsync`. The old function is marked as `@deprecated`. + +## 4.2.1 +Fri, 10 May 2024 05:33:33 GMT + +### Patches + +- Fix a bug in `Async.forEachAsync` where weight wasn't respected. + +## 4.2.0 +Mon, 06 May 2024 15:11:04 GMT + +### Minor changes + +- Add a new `weighted: true` option to the `Async.forEachAsync` method that allows each element to specify how much of the allowed parallelism the callback uses. + +### Patches + +- Add a new `weighted: true` option to the `Async.mapAsync` method that allows each element to specify how much of the allowed parallelism the callback uses. + +## 4.1.0 +Wed, 10 Apr 2024 15:10:08 GMT + +### Minor changes + +- Add `writeBuffersToFile` and `writeBuffersToFileAsync` methods to `FileSystem` for efficient writing of concatenated files. + +## 4.0.2 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 4.0.1 +Tue, 20 Feb 2024 21:45:10 GMT + +### Patches + +- Remove a no longer needed dependency on the `colors` package + +## 4.0.0 +Mon, 19 Feb 2024 21:54:27 GMT + +### Breaking changes + +- (BREAKING CHANGE) Remove the Terminal and related APIs (Colors, AsciEscape, etc). These have been moved into the @rushstack/terminal package. See https://github.com/microsoft/rushstack/pull/3176 for details. +- Remove deprecated `FileSystem.readFolder`, `FileSystem.readFolderAsync`, and `LegacyAdapters.sortStable` APIs. + +### Minor changes + +- Graduate `Async` and `MinimumHeap` APIs from beta to public. + +## 3.66.1 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 3.66.0 +Thu, 08 Feb 2024 01:09:21 GMT + +### Minor changes + +- Add getStatistics() method to FileWriter instances + +### Patches + +- LockFile: prevent accidentaly deleting freshly created lockfile when multiple processes try to acquire the same lock on macOS/Linux + +## 3.65.0 +Mon, 05 Feb 2024 23:46:52 GMT + +### Minor changes + +- Inclue a `Text.reverse` API for reversing a string. + +## 3.64.2 +Thu, 25 Jan 2024 01:09:29 GMT + +### Patches + +- Improve 'bin' definition in `IPackageJson` type + +## 3.64.1 +Tue, 23 Jan 2024 20:12:57 GMT + +### Patches + +- Fix Executable.getProcessInfoBy* methods truncating the process name on MacOS + +## 3.64.0 +Tue, 23 Jan 2024 16:15:05 GMT + +### Minor changes + +- Add the `dependenciesMeta` property to the `INodePackageJson` interface. + +## 3.63.0 +Wed, 03 Jan 2024 00:31:18 GMT + +### Minor changes + +- Updates the `JsonFile` API to format JSON as JSON5 if an existing string is being updated to preserve the style of the existing JSON. + +## 3.62.0 +Thu, 07 Dec 2023 03:44:13 GMT + +### Minor changes + +- Add functions inside the `Executable` API to list all process trees (`getProcessInfoById`, `getProcessInfoByIdAsync`, `getProcessInfoByName`, and `getProcessInfoByNameAsync`). +- Add functions inside the `Text` API to split iterables (or async iterables) that produce strings or buffers on newlines (`readLinesFromIterable` and `readLinesFromIterableAsync`). +- Add the `waitForExitAsync` method inside the `Executable` API used to wait for a provided child process to exit. + +## 3.61.0 +Thu, 28 Sep 2023 20:53:17 GMT + +### Minor changes + +- Add Async.getSignal for promise-based signaling. Add MinimumHeap for use as a priority queue. + +## 3.60.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 3.60.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 3.59.7 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 3.59.6 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Updated semver dependency + +## 3.59.5 +Thu, 06 Jul 2023 00:16:19 GMT + +### Patches + +- Fix Import.resolveModule* and Import.resolvePackage* methods to return real-paths when resolving self-referencing specs + +## 3.59.4 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 3.59.3 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 3.59.2 +Mon, 29 May 2023 15:21:15 GMT + +### Patches + +- Remove extraneous string encode/decode of final output during `JsonFile.save`/`JsonFile.saveAsync`. + +## 3.59.1 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 3.59.0 +Fri, 12 May 2023 00:23:05 GMT + +### Minor changes + +- Add an option to the `PrefixProxyTerminalProvider` to create a dynamic prefix, which can be used for something like prefixing logging lines with a timestamp. + +## 3.58.0 +Mon, 01 May 2023 15:23:19 GMT + +### Minor changes + +- Expose a `Text.escapeRegExp` function to escape regexp special characters. + +## 3.57.0 +Sat, 29 Apr 2023 00:23:02 GMT + +### Minor changes + +- Add PrefixProxyTerminalProvider to allow for prefixing a provided string before writing to a terminal provider +- Add a Writable stream adapter for ITerminal to allow writing to a terminal as a stream + +## 3.56.0 +Thu, 27 Apr 2023 17:18:42 GMT + +### Minor changes + +- Adds the AsyncQueue class, a queue type that allows for iterating and concurrently adding to the queue +- Adds support for async Import.resolve* APIs + +### Patches + +- Fix a typings issue in FileSystem.copyFilesAsync +- Fix issues with Import.resolve* APIs when attempting to resolve system modules paths (ex. 'fs/promises') and self-referencing module paths + +## 3.55.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 3.55.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 3.55.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 3.54.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Add a `peerDependenciesMeta` property to `IPackageJson`. +- Move the @types/node dependency to an optional peerDependency. + +## 3.53.3 +Fri, 09 Dec 2022 16:18:27 GMT + +### Patches + +- Improve performance of `Import.resolvePackage`. +- Improve the error message emitted when a path inside a package is passed to `Import.resolvePackage`. + +## 3.53.2 +Thu, 13 Oct 2022 00:20:15 GMT + +### Patches + +- Fix a bug where `Sort.isSorted` and `Sort.isSortedBy` unexpectedly compared the first element against `undefined`. Optimize `Sort.sortMapKeys` to run the check for already being sorted against the original Map instead of a derived array. + +## 3.53.1 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 3.53.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Add a Path.convertToPlatformDefault API to convert a path to use the platform-default slashes. + +## 3.52.0 +Wed, 21 Sep 2022 20:21:10 GMT + +### Minor changes + +- Add a "FileSystem.isNotDirectoryError" function that returns `true` if the passed-in error object is an ENOTDIR error. +- Add a parameter to the `LockFile.release` function to optionally delete the lockfile. + +## 3.51.2 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 3.51.1 +Wed, 24 Aug 2022 03:01:22 GMT + +### Patches + +- Introduce JsonSyntax option for JsonFile.load() and related APIs + +## 3.51.0 +Wed, 24 Aug 2022 00:14:38 GMT + +### Minor changes + +- Deprecate LegacyAdapters.sortStable and remove support for NodeJS < 11. If you are using NodeJS < 11, this is a breaking change. + +## 3.50.2 +Fri, 19 Aug 2022 00:17:19 GMT + +### Patches + +- Update `PackageJsonLookup` to only resolve to `package.json` files that contain a `"name"` field. See GitHub issue #2070 + +## 3.50.1 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 3.50.0 +Mon, 01 Aug 2022 02:45:32 GMT + +### Minor changes + +- Add an Async.runWithRetriesAsync() API to run and a retry an async function that may intermittently fail. + +## 3.49.0 +Tue, 28 Jun 2022 22:47:13 GMT + +### Minor changes + +- Add SubprocessTerminator utility, which can be used to kill a process and all of its child processes on demand or on termination of the host process. + +## 3.48.0 +Tue, 28 Jun 2022 00:23:32 GMT + +### Minor changes + +- Add FileSystem.isDirectoryError utility function to determine if an error has the code "EISDIR". This error code may be returned (for example) when attempting to delete a folder as if it were a file using the FileSystem.deleteFile API. + +## 3.47.0 +Mon, 27 Jun 2022 18:43:09 GMT + +### Minor changes + +- Add a "trimLeadingDotSlash" option to the Path.formatConcisely function to not include the leading "./" in paths under the baseFolder. +- Change the FileError relative path output to not include the leading "./" + +## 3.46.0 +Sat, 25 Jun 2022 01:54:29 GMT + +### Minor changes + +- Add FileError class. This error type can be thrown when encountering an error at a specific line and column of a target file. + +## 3.45.7 +Fri, 17 Jun 2022 09:17:54 GMT + +### Patches + +- Fix a race condition affecting the LockFile API on the Linux operating system + +## 3.45.6 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 3.45.5 +Tue, 10 May 2022 01:20:43 GMT + +### Patches + +- Fix and issue where Async.forEachAsync with an async iterator can overflow the max concurrency + +## 3.45.4 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 3.45.3 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 3.45.2 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 3.45.1 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 3.45.0 +Wed, 05 Jan 2022 16:07:47 GMT + +### Minor changes + +- Expose a FileSystem.readFolderItems and FileSystem.readFolderItemsAsync API to get folder entries with types in a single API call. +- Deprecate FileSystem.readFolder in favor of FileSystem.readFolderItemNames. + +## 3.44.3 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 3.44.2 +Thu, 09 Dec 2021 20:34:41 GMT + +### Patches + +- Update z-schema to ~5.0.2. + +## 3.44.1 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 3.44.0 +Fri, 03 Dec 2021 03:05:22 GMT + +### Minor changes + +- Replace const enums with conventional enums to allow for compatability with JavaScript consumers. + +## 3.43.2 +Sat, 06 Nov 2021 00:09:13 GMT + +### Patches + +- Updated Path.convertToSlashes() to use replace(/\\/g, '/') instead of split/join for better performance. + +## 3.43.1 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 3.43.0 +Wed, 27 Oct 2021 00:08:15 GMT + +### Minor changes + +- Add more elaborate "repository" field types in IPackageJson. + +### Patches + +- Update the package.json repository field to include the directory property. + +## 3.42.3 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 3.42.2 +Fri, 08 Oct 2021 08:08:34 GMT + +### Patches + +- Fix an issue where Async.foreEachAsync can never resolve when operating on a large array. + +## 3.42.1 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 3.42.0 +Tue, 05 Oct 2021 15:08:38 GMT + +### Minor changes + +- Expose an ITerminal interface. + +## 3.41.0 +Fri, 24 Sep 2021 00:09:29 GMT + +### Minor changes + +- Allow Async.mapAsync and Async.forEachAsync to take an iterator. + +## 3.40.3 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 3.40.2 +Tue, 14 Sep 2021 01:17:04 GMT + +### Patches + +- Improve documentation to clarify usage for FileSystem APIs related to symbolic links + +## 3.40.1 +Mon, 13 Sep 2021 15:07:05 GMT + +### Patches + +- Add support for AlreadyExistsBehavior in symlink and junction scenarios + +## 3.40.0 +Wed, 11 Aug 2021 00:07:21 GMT + +### Minor changes + +- Add new Terminal message severity "debug", below verbose. + +## 3.39.1 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 3.39.0 +Fri, 04 Jun 2021 19:59:53 GMT + +### Minor changes + +- BREAKING CHANGE: Remove FileSystem.copyFileToManyAsync API. It was determined that this API was a likely source of 0-length file copies. Recommended replacement is to call copyFileAsync. + +## 3.38.0 +Wed, 19 May 2021 00:11:39 GMT + +### Minor changes + +- Add `ignoreUndefinedValues` option to JsonFile to discard keys with undefined values during serialization; this is the standard behavior of `JSON.stringify()` and other JSON serializers. + +## 3.37.0 +Mon, 03 May 2021 15:10:28 GMT + +### Minor changes + +- Add a new API "Async" with some utilities for working with promises + +## 3.36.2 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 3.36.1 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 3.36.0 +Fri, 05 Feb 2021 16:10:42 GMT + +### Minor changes + +- Add EnvironmentMap API +- Add Executable.spawn() API + +## 3.35.2 +Thu, 10 Dec 2020 23:25:49 GMT + +_Version update only_ + +## 3.35.1 +Wed, 11 Nov 2020 01:08:59 GMT + +_Version update only_ + +## 3.35.0 +Tue, 10 Nov 2020 23:13:11 GMT + +### Minor changes + +- Add new "copyFileToMany" API to copy a single file to multiple locations +- Add an alreadyExistsBehavior option to the options for creating links in FileSystem. + +## 3.34.7 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 3.34.6 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 3.34.5 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 3.34.4 +Tue, 27 Oct 2020 15:10:13 GMT + +### Patches + +- Fix an issue where the TextAttribute.Bold ANSI escape was not rendered correctly by Linux + +## 3.34.3 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 3.34.2 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 3.34.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 3.34.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Add Path.isEqual(), Path.formatConcisely(), Path.convertToSlashes(), Path.convertToBackslashes(), and Path.isDownwardRelative() +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 3.33.6 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 3.33.5 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 3.33.4 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 3.33.3 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 3.33.2 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 3.33.1 +Fri, 18 Sep 2020 22:57:25 GMT + +_Version update only_ + +## 3.33.0 +Fri, 18 Sep 2020 21:49:53 GMT + +### Minor changes + +- Add a missing "existsAsync" function to the FileSystem API. + +## 3.32.0 +Fri, 11 Sep 2020 02:13:35 GMT + +### Minor changes + +- Add Text.getNewline() and FileWriter.filePath +- Add Brand API + +## 3.31.0 +Mon, 07 Sep 2020 07:37:37 GMT + +### Minor changes + +- Replace Colors.normalizeColorTokensForTest() (which was marked as "beta") with AnsiEscape.formatForTests() + +## 3.30.0 +Thu, 27 Aug 2020 11:27:06 GMT + +### Minor changes + +- Include an API for resolving packages and modules. + +## 3.29.1 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 3.29.0 +Sat, 22 Aug 2020 05:55:42 GMT + +### Minor changes + +- Introduce a "JsonNull" type for describing legacy JSON structures without triggering the "@rushstack/no-new-null" lint rule + +## 3.28.0 +Tue, 18 Aug 2020 23:59:42 GMT + +### Minor changes + +- Add a utility function for making console color codes human-readable. +- Create a lighter weight function to get own package version. + +### Patches + +- Lazy-import some packages to improve spin up times. + +## 3.27.0 +Mon, 17 Aug 2020 04:53:23 GMT + +### Minor changes + +- Add new APIs AlreadyReportedError and TypeUuid + +## 3.26.2 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 3.26.1 +Wed, 05 Aug 2020 18:27:32 GMT + +### Patches + +- Triggering publish of dependents + +## 3.26.0 +Mon, 03 Aug 2020 06:55:14 GMT + +### Minor changes + +- Added IJsonFileStringifyOptions.headerComment + +## 3.25.0 +Fri, 03 Jul 2020 15:09:04 GMT + +### Minor changes + +- Add a utility method to convert a map into an object + +## 3.24.4 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 3.24.3 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 3.24.2 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 3.24.1 +Wed, 10 Jun 2020 20:48:30 GMT + +### Patches + +- Improve API docs for "LockFile" + +## 3.24.0 +Sat, 30 May 2020 02:59:54 GMT + +### Minor changes + +- Add a FileSystem.copyFiles() API for recursively copying folders, and clarify that FileSystem.copyFile() only copies a single file + +## 3.23.1 +Thu, 28 May 2020 05:59:02 GMT + +### Patches + +- Improve async callstacks for FileSystem API (when using Node 12) + +## 3.23.0 +Wed, 27 May 2020 05:15:10 GMT + +### Minor changes + +- Add an "FileSystemStats" alias to avoid the need to import "fs" when using the FileSystem API +- Add FileSystem.readLink() and readLinkAsync() + +## 3.22.1 +Tue, 26 May 2020 23:00:25 GMT + +### Patches + +- Make not-exist error messages more readable. + +## 3.22.0 +Fri, 22 May 2020 15:08:42 GMT + +### Minor changes + +- Expose string parsing APIs from JsonFile. + +## 3.21.0 +Thu, 21 May 2020 23:09:44 GMT + +### Minor changes + +- Create async versions of FileSystem and JsonFile APIs. + +## 3.20.0 +Thu, 21 May 2020 15:41:59 GMT + +### Minor changes + +- Add PackageNameParser class, which is a configurable version of the PackageName API + +## 3.19.7 +Wed, 08 Apr 2020 04:07:34 GMT + +_Version update only_ + +## 3.19.6 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 3.19.5 Wed, 18 Mar 2020 15:07:47 GMT @@ -33,7 +1062,7 @@ Thu, 23 Jan 2020 01:07:56 GMT ## 3.19.1 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 3.19.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -45,17 +1074,17 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 3.18.3 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 3.18.2 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 3.18.1 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 3.18.0 Fri, 15 Nov 2019 04:50:50 GMT @@ -67,7 +1096,7 @@ Fri, 15 Nov 2019 04:50:50 GMT ## 3.17.1 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 3.17.0 Tue, 05 Nov 2019 06:49:28 GMT @@ -424,7 +1453,7 @@ Thu, 15 Mar 2018 16:05:43 GMT ## 0.7.3 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 0.7.2 Tue, 27 Feb 2018 22:05:57 GMT @@ -436,7 +1465,7 @@ Tue, 27 Feb 2018 22:05:57 GMT ## 0.7.1 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 0.7.0 Wed, 21 Feb 2018 03:13:28 GMT @@ -462,7 +1491,7 @@ Fri, 16 Feb 2018 22:05:23 GMT ## 0.5.1 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 0.5.0 Wed, 07 Feb 2018 17:05:11 GMT @@ -474,7 +1503,7 @@ Wed, 07 Feb 2018 17:05:11 GMT ## 0.4.10 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 0.4.9 Fri, 26 Jan 2018 17:53:38 GMT @@ -486,22 +1515,22 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 0.4.8 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 0.4.7 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 0.4.6 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 0.4.5 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 0.4.4 Thu, 18 Jan 2018 00:27:23 GMT @@ -513,17 +1542,17 @@ Thu, 18 Jan 2018 00:27:23 GMT ## 0.4.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 0.4.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 0.4.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 0.4.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -542,57 +1571,57 @@ Tue, 09 Jan 2018 17:05:51 GMT ## 0.3.25 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 0.3.24 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 0.3.23 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 0.3.22 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 0.3.21 Tue, 12 Dec 2017 03:33:27 GMT -*Version update only* +_Version update only_ ## 0.3.20 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 0.3.19 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 0.3.18 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 0.3.17 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 0.3.16 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 0.3.15 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 0.3.14 Thu, 02 Nov 2017 16:05:24 GMT @@ -611,22 +1640,22 @@ Wed, 01 Nov 2017 21:06:08 GMT ## 0.3.12 Tue, 31 Oct 2017 21:04:04 GMT -*Version update only* +_Version update only_ ## 0.3.11 Tue, 31 Oct 2017 16:04:55 GMT -*Version update only* +_Version update only_ ## 0.3.10 Wed, 25 Oct 2017 20:03:59 GMT -*Version update only* +_Version update only_ ## 0.3.9 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 0.3.8 Mon, 23 Oct 2017 21:53:12 GMT @@ -638,17 +1667,17 @@ Mon, 23 Oct 2017 21:53:12 GMT ## 0.3.7 Fri, 20 Oct 2017 19:57:12 GMT -*Version update only* +_Version update only_ ## 0.3.6 Fri, 20 Oct 2017 01:52:54 GMT -*Version update only* +_Version update only_ ## 0.3.5 Fri, 20 Oct 2017 01:04:44 GMT -*Version update only* +_Version update only_ ## 0.3.4 Fri, 13 Oct 2017 19:02:46 GMT @@ -660,7 +1689,7 @@ Fri, 13 Oct 2017 19:02:46 GMT ## 0.3.3 Thu, 05 Oct 2017 01:05:02 GMT -*Version update only* +_Version update only_ ## 0.3.2 Fri, 29 Sep 2017 01:03:42 GMT @@ -672,7 +1701,7 @@ Fri, 29 Sep 2017 01:03:42 GMT ## 0.3.1 Thu, 28 Sep 2017 01:04:28 GMT -*Version update only* +_Version update only_ ## 0.3.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -684,12 +1713,12 @@ Fri, 22 Sep 2017 01:04:02 GMT ## 0.2.11 Wed, 20 Sep 2017 22:10:17 GMT -*Version update only* +_Version update only_ ## 0.2.10 Mon, 11 Sep 2017 13:04:55 GMT -*Version update only* +_Version update only_ ## 0.2.9 Fri, 08 Sep 2017 13:04:00 GMT @@ -708,37 +1737,37 @@ Fri, 08 Sep 2017 01:28:04 GMT ## 0.2.7 Thu, 07 Sep 2017 13:04:35 GMT -*Version update only* +_Version update only_ ## 0.2.6 Thu, 07 Sep 2017 00:11:12 GMT -*Version update only* +_Version update only_ ## 0.2.5 Wed, 06 Sep 2017 13:03:42 GMT -*Version update only* +_Version update only_ ## 0.2.4 Tue, 05 Sep 2017 19:03:56 GMT -*Version update only* +_Version update only_ ## 0.2.3 Sat, 02 Sep 2017 01:04:26 GMT -*Version update only* +_Version update only_ ## 0.2.2 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 0.2.1 Thu, 31 Aug 2017 17:46:25 GMT -*Version update only* +_Version update only_ ## 0.2.0 Wed, 30 Aug 2017 01:04:34 GMT diff --git a/libraries/node-core-library/README.md b/libraries/node-core-library/README.md index 6e3e19f55d5..73e7901f785 100644 --- a/libraries/node-core-library/README.md +++ b/libraries/node-core-library/README.md @@ -28,4 +28,11 @@ that seem like they might be useful. Code should start somewhere else, and then graduate to **node-core-library** after its value has already been demonstrated. If in doubt, create your own NPM package. -API documentation for this package: https://rushstack.io/pages/api/node-core-library/ +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/node-core-library/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/node-core-library/) + +`@rushstack/node-core-library` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/node-core-library/config/api-extractor.json b/libraries/node-core-library/config/api-extractor.json index 996e271d3dd..ce0b9d7f01e 100644 --- a/libraries/node-core-library/config/api-extractor.json +++ b/libraries/node-core-library/config/api-extractor.json @@ -15,5 +15,7 @@ "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 new file mode 100644 index 00000000000..11169bb1254 --- /dev/null +++ b/libraries/node-core-library/config/heft.json @@ -0,0 +1,34 @@ +/** + * 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": "decoupled-local-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 new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/node-core-library/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/node-core-library/config/jest.json b/libraries/node-core-library/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/libraries/node-core-library/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/libraries/node-core-library/config/rig.json b/libraries/node-core-library/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/node-core-library/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/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/gulpfile.js b/libraries/node-core-library/gulpfile.js deleted file mode 100644 index cf8fd436e63..00000000000 --- a/libraries/node-core-library/gulpfile.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.jest.setConfig({ coverageReporters: ['json'] }); // Temporary - until the Handlebars issue is fixed - -build.initialize(require('gulp')); diff --git a/libraries/node-core-library/package.json b/libraries/node-core-library/package.json index a5697a77bb9..95ee715979e 100644 --- a/libraries/node-core-library/package.json +++ b/libraries/node-core-library/package.json @@ -1,35 +1,46 @@ { "name": "@rushstack/node-core-library", - "version": "3.19.5", + "version": "5.19.1", "description": "Core libraries that every NodeJS toolchain project should use", "main": "lib/index.js", "typings": "dist/node-core-library.d.ts", "license": "MIT", "repository": { - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/node-core-library" + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/node-core-library" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "@types/node": "10.17.13", - "colors": "~1.2.1", - "fs-extra": "~7.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", "jju": "~1.4.0", - "semver": "~5.3.0", - "timsort": "~0.3.0", - "z-schema": "~3.18.3" + "resolve": "~1.22.1", + "semver": "~7.5.4", + "ajv": "~8.13.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1" }, "devDependencies": { - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5", - "@types/fs-extra": "5.0.4", - "@types/jest": "23.3.11", + "@rushstack/heft": "1.1.4", + "@rushstack/problem-matcher": "workspace:*", + "@types/fs-extra": "7.0.0", "@types/jju": "1.4.1", - "@types/semver": "5.3.33", - "@types/timsort": "0.3.0", - "@types/z-schema": "3.16.31", - "gulp": "~4.0.2" + "@types/resolve": "1.20.2", + "@types/semver": "7.5.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } } diff --git a/libraries/node-core-library/src/AlreadyReportedError.ts b/libraries/node-core-library/src/AlreadyReportedError.ts new file mode 100644 index 00000000000..84b6fad4593 --- /dev/null +++ b/libraries/node-core-library/src/AlreadyReportedError.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 { TypeUuid } from './TypeUuid'; + +const uuidAlreadyReportedError: string = 'f26b0640-a49b-49d1-9ead-1a516d5920c7'; + +/** + * This exception can be thrown to indicate that an operation failed and an error message has already + * been reported appropriately. Thus, the catch handler does not have responsibility for reporting + * the error. + * + * @remarks + * For example, suppose a tool writes interactive output to `console.log()`. When an exception is thrown, + * the `catch` handler will typically provide simplistic reporting such as this: + * + * ```ts + * catch (error) { + * console.log("ERROR: " + error.message); + * } + * ``` + * + * Suppose that the code performing the operation normally prints rich output to the console. It may be able to + * present an error message more nicely (for example, as part of a table, or structured log format). Throwing + * `AlreadyReportedError` provides a way to use exception handling to abort the operation, but instruct the `catch` + * handler not to print an error a second time: + * + * ```ts + * catch (error) { + * if (error instanceof AlreadyReportedError) { + * return; + * } + * console.log("ERROR: " + error.message); + * } + * ``` + * + * @public + */ +export class AlreadyReportedError extends Error { + public constructor() { + super('An error occurred.'); + + // 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](https://github.com/microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work) + // + // Note: the prototype must also be set on any classes which extend this one + (this as any).__proto__ = AlreadyReportedError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any + } + + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidAlreadyReportedError); + } +} + +TypeUuid.registerClass(AlreadyReportedError, uuidAlreadyReportedError); diff --git a/libraries/node-core-library/src/Async.ts b/libraries/node-core-library/src/Async.ts new file mode 100644 index 00000000000..9fb6bb9fd08 --- /dev/null +++ b/libraries/node-core-library/src/Async.ts @@ -0,0 +1,514 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Options for controlling the parallelism of asynchronous operations. + * + * @remarks + * Used with {@link (Async:class).(mapAsync:1)}, {@link (Async:class).(mapAsync:2)} and + * {@link (Async:class).(forEachAsync:1)}, and {@link (Async:class).(forEachAsync:2)}. + * + * @public + */ +export interface IAsyncParallelismOptions { + /** + * Optionally used with the {@link (Async:class).(mapAsync:1)}, {@link (Async:class).(mapAsync:2)} and + * {@link (Async:class).(forEachAsync:1)}, and {@link (Async:class).(forEachAsync:2)} to limit the maximum + * number of concurrent promises to the specified number. + */ + 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. + */ + 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; +} + +/** + * @remarks + * Used with {@link Async.runWithRetriesAsync}. + * + * @public + */ +export interface IRunWithRetriesOptions { + /** + * 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)}. + * + * @public + */ +export interface IWeighted { + /** + * The weight of the element, used to determine the concurrency units that it will take up. + * Must be a whole number greater than or equal to 0. + */ + weight: number; +} + +function toWeightedIterator( + iterable: Iterable | AsyncIterable, + useWeights?: boolean +): AsyncIterable<{ element: TEntry; weight: number }> { + const iterator: Iterator | AsyncIterator = ( + (iterable as Iterable)[Symbol.iterator] || + (iterable as AsyncIterable)[Symbol.asyncIterator] + ).call(iterable); + return { + [Symbol.asyncIterator]: () => ({ + // eslint-disable-next-line @typescript-eslint/naming-convention + next: async () => { + // The await is necessary here, but TS will complain - it's a false positive. + const { value, done } = await iterator.next(); + return { + value: { element: value, weight: useWeights ? value?.weight : 1 }, + done: !!done + }; + } + }) + }; +} + +/** + * Utilities for parallel asynchronous operations, for use with the system `Promise` APIs. + * + * @public + */ +export class Async { + /** + * Given an input array and a `callback` function, invoke the callback to start a + * promise for each element in the array. Returns an array containing the results. + * + * @remarks + * This API is similar to the system `Array#map`, except that the loop is asynchronous, + * and the maximum number of concurrent promises can be throttled + * using {@link IAsyncParallelismOptions.concurrency}. + * + * 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 + * overall operation will reject with the first error that was encountered. + * + * @param iterable - the array of inputs for the callback function + * @param callback - a function that starts an asynchronous promise for an element + * from the array + * @param options - options for customizing the control flow + * @returns an array containing the result for each callback, in the same order + * as the original input `array` + */ + public static async mapAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options?: (IAsyncParallelismOptions & { weighted?: false }) | undefined + ): Promise; + + /** + * Given an input array and a `callback` function, invoke the callback to start a + * promise for each element in the array. Returns an array containing the results. + * + * @remarks + * This API is similar to the system `Array#map`, except that the loop is asynchronous, + * and the maximum number of concurrent units can be throttled + * using {@link IAsyncParallelismOptions.concurrency}. Using the {@link IAsyncParallelismOptions.weighted} + * option, the weight of each operation can be specified, which determines how many concurrent units it takes up. + * + * 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 + * overall operation will reject with the first error that was encountered. + * + * @param iterable - the array of inputs for the callback function + * @param callback - a function that starts an asynchronous promise for an element + * from the array + * @param options - options for customizing the control flow + * @returns an array containing the result for each callback, in the same order + * as the original input `array` + */ + public static async mapAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options: IAsyncParallelismOptions & { weighted: true } + ): Promise; + public static async mapAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options?: IAsyncParallelismOptions | undefined + ): Promise { + const result: TRetVal[] = []; + + // @ts-expect-error https://github.com/microsoft/TypeScript/issues/22609, it succeeds against the implementation but fails against the overloads + await Async.forEachAsync( + iterable, + async (item: TEntry, arrayIndex: number): Promise => { + result[arrayIndex] = await callback(item, arrayIndex); + }, + options + ); + + 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; + // 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); + }); + }); + } + + /** + * Given an input array and a `callback` function, invoke the callback to start a + * promise for each element in the array. + * + * @remarks + * This API is similar to the system `Array#forEach`, except that the loop is asynchronous, + * and the maximum number of concurrent promises can be throttled + * using {@link IAsyncParallelismOptions.concurrency}. + * + * 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 + * overall operation will reject with the first error that was encountered. + * + * @param iterable - the array of inputs for the callback function + * @param callback - a function that starts an asynchronous promise for an element + * from the array + * @param options - options for customizing the control flow + */ + public static async forEachAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options?: (IAsyncParallelismOptions & { weighted?: false }) | undefined + ): Promise; + + /** + * Given an input array and a `callback` function, invoke the callback to start a + * promise for each element in the array. + * + * @remarks + * This API is similar to the other `Array#forEachAsync`, except that each item can have + * a weight that determines how many concurrent operations are allowed. The unweighted + * `Array#forEachAsync` is a special case of this method where weight = 1 for all items. + * + * The maximum number of concurrent operations can still be throttled using + * {@link IAsyncParallelismOptions.concurrency}, however it no longer determines the + * maximum number of operations that can be in progress at once. Instead, it determines the + * 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 + * overall operation will reject with the first error that was encountered. + * + * @param iterable - the array of inputs for the callback function + * @param callback - a function that starts an asynchronous promise for an element + * from the array + * @param options - options for customizing the control flow + */ + public static async forEachAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options: IAsyncParallelismOptions & { weighted: true } + ): Promise; + public static async forEachAsync( + iterable: Iterable | AsyncIterable, + callback: (entry: TEntry, arrayIndex: number) => Promise, + options?: IAsyncParallelismOptions + ): Promise { + await Async._forEachWeightedAsync(toWeightedIterator(iterable, options?.weighted), callback, options); + } + + /** + * Return a promise that resolves after the specified number of milliseconds. + */ + public static async sleepAsync(ms: number): Promise { + await new Promise((resolve) => { + setTimeout(resolve, ms); + }); + } + + /** + * Executes an async function and optionally retries it if it fails. + */ + public static async runWithRetriesAsync({ + action, + maxRetries, + retryDelayMs = 0 + }: IRunWithRetriesOptions): Promise { + let retryCount: number = 0; + while (true) { + try { + return await action(retryCount); + } catch (e) { + if (++retryCount > maxRetries) { + throw e; + } else if (retryDelayMs > 0) { + await Async.sleepAsync(retryDelayMs); + } + } + } + } + + /** + * Ensures that the argument is a valid {@link IWeighted}, with a `weight` argument that + * is a positive integer or 0. + */ + public static validateWeightedIterable(operation: IWeighted): void { + if (operation.weight < 0) { + throw new Error('Weight must be a whole number greater than or equal to 0'); + } + if (operation.weight % 1 !== 0) { + throw new Error('Weight must be a whole number greater than or equal to 0'); + } + } + + /** + * Returns a Signal, a.k.a. a "deferred promise". + */ + 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); + } + } + } +} + +/** + * Returns an unwrapped promise. + */ +function getSignal(): [Promise, () => void, (err: Error) => void] { + let resolver: () => void; + let rejecter: (err: Error) => void; + const promise: Promise = new Promise((resolve, reject) => { + resolver = resolve; + rejecter = reject; + }); + return [promise, resolver!, rejecter!]; +} + +/** + * A queue that allows for asynchronous iteration. During iteration, the queue will wait until + * the next item is pushed into the queue before yielding. If instead all queue items are consumed + * and all callbacks have been called, the queue will return. + * + * @public + */ +export class AsyncQueue implements AsyncIterable<[T, () => void]> { + private _queue: T[]; + private _onPushSignal: Promise; + private _onPushResolve: () => void; + + public constructor(iterable?: Iterable) { + this._queue = iterable ? Array.from(iterable) : []; + const [promise, resolver] = getSignal(); + this._onPushSignal = promise; + this._onPushResolve = resolver; + } + + public async *[Symbol.asyncIterator](): AsyncIterableIterator<[T, () => void]> { + let activeIterations: number = 0; + let [callbackSignal, callbackResolve] = getSignal(); + const callback: () => void = () => { + if (--activeIterations === 0) { + // Resolve whatever the latest callback promise is and create a new one + callbackResolve(); + const [newCallbackSignal, newCallbackResolve] = getSignal(); + callbackSignal = newCallbackSignal; + callbackResolve = newCallbackResolve; + } + }; + + let position: number = 0; + while (this._queue.length > position || activeIterations > 0) { + if (this._queue.length > position) { + activeIterations++; + yield [this._queue[position++], callback]; + } else { + // On push, the item will be added to the queue and the onPushSignal will be resolved. + // On calling the callback, active iterations will be decremented by the callback and the + // callbackSignal will be resolved. This means that the loop will continue if there are + // active iterations or if there are items in the queue that haven't been yielded yet. + await Promise.race([this._onPushSignal, callbackSignal]); + } + } + } + + /** + * Adds an item to the queue. + * + * @param item - The item to push into the queue. + */ + public push(item: T): void { + this._queue.push(item); + this._onPushResolve(); + const [onPushSignal, onPushResolve] = getSignal(); + this._onPushSignal = onPushSignal; + this._onPushResolve = onPushResolve; + } +} diff --git a/libraries/node-core-library/src/Constants.ts b/libraries/node-core-library/src/Constants.ts index a8a8535b774..d02b31ed1ea 100644 --- a/libraries/node-core-library/src/Constants.ts +++ b/libraries/node-core-library/src/Constants.ts @@ -6,26 +6,28 @@ * * @public */ -export const enum FileConstants { +// eslint-disable-next-line @typescript-eslint/typedef +export const FileConstants = { /** * "package.json" - the configuration file that defines an NPM package */ - PackageJson = 'package.json' -} + PackageJson: 'package.json' +} as const; /** * String constants for common folder names. * * @public */ -export const enum FolderConstants { +// eslint-disable-next-line @typescript-eslint/typedef +export const FolderConstants = { /** * ".git" - the data storage for a Git working folder */ - Git = '.git', + Git: '.git', /** * "node_modules" - the folder where package managers install their files */ - NodeModules = 'node_modules' -} + NodeModules: 'node_modules' +} as const; 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/Enum.ts b/libraries/node-core-library/src/Enum.ts new file mode 100644 index 00000000000..abf486bdac5 --- /dev/null +++ b/libraries/node-core-library/src/Enum.ts @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * A helper for looking up TypeScript `enum` keys/values. + * + * @remarks + * TypeScript enums implement a lookup table for mapping between their keys and values: + * + * ```ts + * enum Colors { + * Red = 1 + * } + * + * // Prints "Red" + * console.log(Colors[1]); + * + * // Prints "1" + * console.log(Colors["Red]); + * ``` + * + * However the compiler's "noImplicitAny" validation has trouble with these mappings, because + * there are so many possible types for the map elements: + * + * ```ts + * function f(s: string): Colors | undefined { + * // (TS 7015) Element implicitly has an 'any' type because + * // index expression is not of type 'number'. + * return Colors[s]; + * } + * ``` + * + * The `Enum` helper provides a more specific, strongly typed way to access members: + * + * ```ts + * function f(s: string): Colors | undefined { + * return Enum.tryGetValueByKey(Colors, s); + * } + * ``` + * + * @public + */ +export class Enum { + private constructor() {} + + /** + * Returns an enum value, given its key. Returns `undefined` if no matching key is found. + * + * @example + * + * Example usage: + * ```ts + * enum Colors { + * Red = 1 + * } + * + * // Prints "1" + * console.log(Enum.tryGetValueByKey(Colors, "Red")); + * + * // Prints "undefined" + * console.log(Enum.tryGetValueByKey(Colors, "Black")); + * ``` + */ + public static tryGetValueByKey( + enumObject: { + [key: string]: TEnumValue | string; + [key: number]: TEnumValue | string; + }, + key: string + ): TEnumValue | undefined { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return enumObject[key] as any; + } + + /** + * This API is similar to {@link Enum.tryGetValueByKey}, except that it throws an exception + * if the key is undefined. + */ + public static getValueByKey( + enumObject: { + [key: string]: TEnumValue | string; + [key: number]: TEnumValue | string; + }, + key: string + ): TEnumValue { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const result: TEnumValue | undefined = enumObject[key] as any; + if (result === undefined) { + throw new Error(`The lookup key ${JSON.stringify(key)} is not defined`); + } + return result; + } + + /** + * Returns an enum string key, given its numeric value. Returns `undefined` if no matching value + * is found. + * + * @remarks + * The TypeScript compiler only creates a reverse mapping for enum members whose value is numeric. + * For example: + * + * ```ts + * enum E { + * A = 1, + * B = 'c' + * } + * + * // Prints "A" + * console.log(E[1]); + * + * // Prints "undefined" + * console.log(E["c"]); + * ``` + * + * @example + * + * Example usage: + * ```ts + * enum Colors { + * Red = 1, + * Blue = 'blue' + * } + * + * // Prints "Red" + * console.log(Enum.tryGetKeyByNumber(Colors, 1)); + * + * // Prints "undefined" + * console.log(Enum.tryGetKeyByNumber(Colors, -1)); + * ``` + */ + public static tryGetKeyByNumber( + enumObject: TEnumObject, + value: number + ): keyof typeof enumObject | undefined { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return enumObject[value] as any; + } + + /** + * This API is similar to {@link Enum.tryGetKeyByNumber}, except that it throws an exception + * if the key is undefined. + */ + public static getKeyByNumber( + enumObject: TEnumObject, + value: number + ): keyof typeof enumObject { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const result: keyof typeof enumObject | undefined = enumObject[value] as any; + if (result === undefined) { + throw new Error(`The value ${value} does not exist in the mapping`); + } + return result; + } +} diff --git a/libraries/node-core-library/src/EnvironmentMap.ts b/libraries/node-core-library/src/EnvironmentMap.ts new file mode 100644 index 00000000000..c672f1be36b --- /dev/null +++ b/libraries/node-core-library/src/EnvironmentMap.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 process from 'node:process'; + +import { InternalError } from './InternalError'; + +/** + * A process environment variable name and its value. Used by {@link EnvironmentMap}. + * @public + */ +export interface IEnvironmentEntry { + /** + * The name of the environment variable. + */ + name: string; + + /** + * The value of the environment variable. + */ + value: string; +} + +/** + * A map data structure that stores process environment variables. On Windows + * operating system, the variable names are case-insensitive. + * @public + */ +export class EnvironmentMap { + private readonly _map: Map = new Map(); + + /** + * Whether the environment variable names are case-sensitive. + * + * @remarks + * On Windows operating system, environment variables are case-insensitive. + * The map will preserve the variable name casing from the most recent assignment operation. + */ + public readonly caseSensitive: boolean; + + public constructor(environmentObject: Record = {}) { + // This property helps catch a mistake where an instance of `EnvironmentMap` is accidentally passed to + // a function that expects a `Record` (as would be used with the `process.env` API). + // The property getter will throw an exception if that function tries to enumerate the object values. + Object.defineProperty(this, '_sanityCheck', { + enumerable: true, + get: function () { + throw new InternalError('Attempt to read EnvironmentMap class as an object'); + } + }); + + this.caseSensitive = process.platform !== 'win32'; + this.mergeFromObject(environmentObject); + } + + /** + * Clears all entries, resulting in an empty map. + */ + public clear(): void { + this._map.clear(); + } + + /** + * Assigns the variable to the specified value. A previous value will be overwritten. + * + * @remarks + * The value can be an empty string. To completely remove the entry, use + * {@link EnvironmentMap.unset} instead. + */ + public set(name: string, value: string): void { + const key: string = this.caseSensitive ? name : name.toUpperCase(); + this._map.set(key, { name: name, value }); + } + + /** + * Removes the key from the map, if present. + */ + public unset(name: string): void { + const key: string = this.caseSensitive ? name : name.toUpperCase(); + this._map.delete(key); + } + + /** + * Returns the value of the specified variable, or `undefined` if the map does not contain that name. + */ + public get(name: string): string | undefined { + const key: string = this.caseSensitive ? name : name.toUpperCase(); + const entry: IEnvironmentEntry | undefined = this._map.get(key); + if (entry === undefined) { + return undefined; + } + return entry.value; + } + + /** + * Returns the map keys, which are environment variable names. + */ + public names(): IterableIterator { + return this._map.keys(); + } + + /** + * Returns the map entries. + */ + public entries(): IterableIterator { + return this._map.values(); + } + + /** + * Adds each entry from `environmentMap` to this map. + */ + public mergeFrom(environmentMap: EnvironmentMap): void { + for (const entry of environmentMap.entries()) { + this.set(entry.name, entry.value); + } + } + + /** + * Merges entries from a plain JavaScript object, such as would be used with the `process.env` API. + */ + public mergeFromObject(environmentObject: Record = {}): void { + for (const [name, value] of Object.entries(environmentObject)) { + if (value !== undefined) { + this.set(name, value); + } + } + } + + /** + * Returns the keys as a plain JavaScript object similar to the object returned by the `process.env` API. + */ + public toObject(): Record { + const result: Record = {}; + for (const entry of this.entries()) { + result[entry.name] = entry.value; + } + return result; + } +} diff --git a/libraries/node-core-library/src/Executable.ts b/libraries/node-core-library/src/Executable.ts index 226d4c01e33..97edafde57f 100644 --- a/libraries/node-core-library/src/Executable.ts +++ b/libraries/node-core-library/src/Executable.ts @@ -1,23 +1,34 @@ // 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 * 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'; +import { InternalError } from './InternalError'; + +const OS_PLATFORM: NodeJS.Platform = os.platform(); /** * Typings for one of the streams inside IExecutableSpawnSyncOptions.stdio. * @public */ -export type ExecutableStdioStreamMapping = 'pipe' | 'ignore' | 'inherit' - | NodeJS.WritableStream | NodeJS.ReadableStream - | number | undefined; +export type ExecutableStdioStreamMapping = + | 'pipe' + | 'ignore' + | 'inherit' + | NodeJS.WritableStream + | NodeJS.ReadableStream + | number + | undefined; /** - * Typings for IExecutableSpawnSyncOptions.stdio. + * Types for {@link IExecutableSpawnSyncOptions.stdio} + * and {@link IExecutableSpawnOptions.stdio} * @public */ export type ExecutableStdioMapping = 'pipe' | 'ignore' | 'inherit' | ExecutableStdioStreamMapping[]; @@ -33,13 +44,26 @@ export interface IExecutableResolveOptions { currentWorkingDirectory?: string; /** - * The environment variables for the child process. If omitted, process.env will be used. + * The environment variables for the child process. + * + * @remarks + * If `environment` and `environmentMap` are both omitted, then `process.env` will be used. + * If `environment` and `environmentMap` cannot both be specified. */ environment?: NodeJS.ProcessEnv; + + /** + * The environment variables for the child process. + * + * @remarks + * If `environment` and `environmentMap` are both omitted, then `process.env` will be used. + * If `environment` and `environmentMap` cannot both be specified. + */ + environmentMap?: EnvironmentMap; } /** - * Options for Executable.execute(). + * Options for {@link Executable.spawnSync} * @public */ export interface IExecutableSpawnSyncOptions extends IExecutableResolveOptions { @@ -65,20 +89,304 @@ export interface IExecutableSpawnSyncOptions extends IExecutableResolveOptions { timeoutMs?: number; /** - * The largest amount of bytes allowed on stdout or stderr for this synchonous operation. + * The largest amount of bytes allowed on stdout or stderr for this synchronous operation. * If exceeded, the child process will be terminated. The default is 200 * 1024. */ maxBuffer?: number; } +/** + * Options for {@link Executable.spawn} + * @public + */ +export interface IExecutableSpawnOptions extends IExecutableResolveOptions { + /** + * The stdio mappings for the child process. + * + * NOTE: If IExecutableSpawnSyncOptions.input is provided, it will take precedence + * over the stdin mapping (stdio[0]). + */ + stdio?: ExecutableStdioMapping; +} + +/** + * The options for running a process to completion using {@link Executable.(waitForExitAsync:3)}. + * + * @public + */ +export interface IWaitForExitOptions { + /** + * Whether or not to throw when the process completes with a non-zero exit code. Defaults to false. + * + * @defaultValue false + */ + throwOnNonZeroExitCode?: boolean; + + /** + * Whether or not to throw when the process is terminated by a signal. Defaults to false. + * + * @defaultValue false + */ + throwOnSignal?: boolean; + + /** + * The encoding of the output. If not provided, the output will not be collected. + */ + encoding?: BufferEncoding | 'buffer'; +} + +/** + * {@inheritDoc IWaitForExitOptions} + * + * @public + */ +export interface IWaitForExitWithStringOptions extends IWaitForExitOptions { + /** + * {@inheritDoc IWaitForExitOptions.encoding} + */ + encoding: BufferEncoding; +} + +/** + * {@inheritDoc IWaitForExitOptions} + * + * @public + */ +export interface IWaitForExitWithBufferOptions extends IWaitForExitOptions { + /** + * {@inheritDoc IWaitForExitOptions.encoding} + */ + encoding: 'buffer'; +} + +/** + * 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 IWaitForExitResultWithoutOutput { + /** + * The process exit code. If the process was terminated, this will be null. + */ + // eslint-disable-next-line @rushstack/no-new-null + exitCode: number | null; + + /** + * The process signal that terminated the process. If the process exited normally, this will be null. + */ + // eslint-disable-next-line @rushstack/no-new-null + 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; - environment: NodeJS.ProcessEnv; + environmentMap: EnvironmentMap; // For Windows, the parsed PATHEXT environment variable windowsExecutableExtensions: string[]; } +interface ICommandLineOptions { + path: string; + args: string[]; +} + +/** + * Process information sourced from the system. This process info is sourced differently depending + * on the operating system: + * - 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 + */ +export interface IProcessInfo { + /** + * The name of the process. + * + * @remarks On Windows, the process name will be empty if the process is a kernel process. + * On Unix, the process name will be empty if the process is the root process. + */ + processName: string; + + /** + * The process ID. + */ + processId: number; + + /** + * The parent process info. + * + * @remarks On Windows, the parent process info will be undefined if the process is a kernel process. + * On Unix, the parent process info will be undefined if the process is the root process. + */ + parentProcessInfo: IProcessInfo | undefined; + + /** + * The child process infos. + */ + childProcessInfos: IProcessInfo[]; +} + +export async function parseProcessListOutputAsync( + stream: NodeJS.ReadableStream, + platform: NodeJS.Platform = OS_PLATFORM +): Promise> { + const processInfoById: Map = new Map(); + let seenHeaders: boolean = false; + for await (const line of Text.readLinesFromIterableAsync(stream, { ignoreEmptyLines: true })) { + if (!seenHeaders) { + seenHeaders = true; + } else { + parseProcessInfoEntry(line, processInfoById, platform); + } + } + return processInfoById; +} + +export function parseProcessListOutput( + // eslint-disable-next-line @rushstack/no-new-null + output: Iterable, + platform: NodeJS.Platform = OS_PLATFORM +): Map { + const processInfoById: Map = new Map(); + let seenHeaders: boolean = false; + for (const line of Text.readLinesFromIterable(output, { ignoreEmptyLines: true })) { + if (!seenHeaders) { + seenHeaders = true; + } else { + parseProcessInfoEntry(line, processInfoById, platform); + } + } + return processInfoById; +} + +// win32 format: +// 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'; +const PROCESS_LIST_ENTRY_REGEX: RegExp = new RegExp( + `^\\s*(?<${PARENT_PROCESS_ID_GROUP}>\\d+)\\s+(?<${PROCESS_ID_GROUP}>\\d+)\\s+(?<${NAME_GROUP}>.+?)\\s*$` +); + +function parseProcessInfoEntry( + line: string, + existingProcessInfoById: Map, + platform: NodeJS.Platform +): void { + 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}`); + } + + const processName: string = match.groups[NAME_GROUP]; + const processId: number = parseInt(match.groups[PROCESS_ID_GROUP], 10); + const parentProcessId: number = parseInt(match.groups[PARENT_PROCESS_ID_GROUP], 10); + + // Only care about the parent process if it is not the same as the current process. + let parentProcessInfo: IProcessInfo | undefined; + if (parentProcessId !== processId) { + parentProcessInfo = existingProcessInfoById.get(parentProcessId); + if (!parentProcessInfo) { + // Create a new placeholder entry for the parent with the information we have so far + parentProcessInfo = { + processName: '', + processId: parentProcessId, + parentProcessInfo: undefined, + childProcessInfos: [] + }; + existingProcessInfoById.set(parentProcessId, parentProcessInfo); + } + } + + let processInfo: IProcessInfo | undefined = existingProcessInfoById.get(processId); + if (!processInfo) { + // Create a new entry + processInfo = { + processName, + processId, + parentProcessInfo, + childProcessInfos: [] + }; + existingProcessInfoById.set(processId, processInfo); + } else { + // Update placeholder entry + processInfo.processName = processName; + processInfo.parentProcessInfo = parentProcessInfo; + } + + // Add the process as a child of the parent process + parentProcessInfo?.childProcessInfos.push(processInfo); +} + +function convertToProcessInfoByNameMap( + processInfoById: Map +): Map { + const processInfoByNameMap: Map = new Map(); + for (const processInfo of processInfoById.values()) { + let processInfoNameEntries: IProcessInfo[] | undefined = processInfoByNameMap.get( + processInfo.processName + ); + if (!processInfoNameEntries) { + processInfoNameEntries = []; + processInfoByNameMap.set(processInfo.processName, processInfoNameEntries); + } + processInfoNameEntries.push(processInfo); + } + return processInfoByNameMap; +} + +function getProcessListProcessOptions(): ICommandLineOptions { + let command: string; + let args: string[]; + if (OS_PLATFORM === 'win32') { + 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 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']; + } + return { path: command, args }; +} + /** * The Executable class provides a safe, portable, recommended solution for tools that need * to launch child processes. @@ -139,11 +447,13 @@ export class Executable { * wants binary output or a non-default text encoding, we will introduce a separate API function * with a name like "spawnWithBufferSync". */ - public static spawnSync(filename: string, args: string[], options?: IExecutableSpawnSyncOptions): - child_process.SpawnSyncReturns { - + public static spawnSync( + filename: string, + args: string[], + options?: IExecutableSpawnSyncOptions + ): child_process.SpawnSyncReturns { if (!options) { - options = { }; + options = {}; } const context: IExecutableContext = Executable._getExecutableContext(options); @@ -155,9 +465,9 @@ export class Executable { const spawnOptions: child_process.SpawnSyncOptionsWithStringEncoding = { cwd: context.currentWorkingDirectory, - env: context.environment, + env: context.environmentMap.toObject(), input: options.input, - stdio: options.stdio, + stdio: options.stdio as child_process.StdioOptions, timeout: options.timeoutMs, maxBuffer: options.maxBuffer, @@ -165,31 +475,265 @@ export class Executable { // if we want the result to be SpawnSyncReturns instead of SpawnSyncReturns. encoding: 'utf8', - // NOTE: This is always false, because Rushell is recommended instead of relying on the OS shell. + // NOTE: This is always false, because Rushell will be recommended instead of relying on the OS shell. + shell: false + }; + + const normalizedCommandLine: ICommandLineOptions = Executable._buildCommandLineFixup( + resolvedPath, + args, + context + ); + + return child_process.spawnSync(normalizedCommandLine.path, normalizedCommandLine.args, spawnOptions); + } + + /** + * Start a child process. + * + * @remarks + * This function is similar to child_process.spawn(). The main differences are: + * + * - It does not invoke the OS shell unless the executable file is a shell script. + * - Command-line arguments containing special characters are more accurately passed + * through to the child process. + * - If the filename is missing a path, then the shell's default PATH will be searched. + * - If the filename is missing a file extension, then Windows default file extensions + * will be searched. + * + * This command is asynchronous, but it does not return a `Promise`. Instead it returns + * a Node.js `ChildProcess` supporting event notifications. + * + * @param filename - The name of the executable file. This string must not contain any + * command-line arguments. If the name contains any path delimiters, then the shell's + * default PATH will not be searched. + * @param args - The command-line arguments to be passed to the process. + * @param options - Additional options + * @returns the same data type as returned by the NodeJS child_process.spawnSync() API + */ + public static spawn( + filename: string, + args: string[], + options?: IExecutableSpawnOptions + ): child_process.ChildProcess { + if (!options) { + options = {}; + } + + const context: IExecutableContext = Executable._getExecutableContext(options); + + const resolvedPath: string | undefined = Executable._tryResolve(filename, options, context); + if (!resolvedPath) { + throw new Error(`The executable file was not found: "${filename}"`); + } + + const spawnOptions: child_process.SpawnOptions = { + cwd: context.currentWorkingDirectory, + env: context.environmentMap.toObject(), + stdio: options.stdio as child_process.StdioOptions, + + // NOTE: This is always false, because Rushell will be recommended instead of relying on the OS shell. shell: false - } as child_process.SpawnSyncOptionsWithStringEncoding; - - // 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/ - - const environment: NodeJS.ProcessEnv = options && options.environment - || process.env; + }; + + const normalizedCommandLine: ICommandLineOptions = Executable._buildCommandLineFixup( + resolvedPath, + args, + context + ); + + return child_process.spawn(normalizedCommandLine.path, normalizedCommandLine.args, spawnOptions); + } + + /** {@inheritDoc Executable.(waitForExitAsync:3)} */ + public static async waitForExitAsync( + childProcess: child_process.ChildProcess, + options: IWaitForExitWithStringOptions + ): Promise>; + + /** {@inheritDoc Executable.(waitForExitAsync:3)} */ + public static async waitForExitAsync( + childProcess: child_process.ChildProcess, + options: IWaitForExitWithBufferOptions + ): Promise>; + + /** + * Wait for a child process to exit and return the result. + * + * @param childProcess - The child process to wait for. + * @param options - Options for waiting for the process to exit. + */ + public static async waitForExitAsync( + childProcess: child_process.ChildProcess, + options?: IWaitForExitOptions + ): Promise; + + public static async waitForExitAsync( + childProcess: child_process.ChildProcess, + options: IWaitForExitOptions = {} + ): Promise | IWaitForExitResultWithoutOutput> { + const { throwOnNonZeroExitCode, throwOnSignal, encoding } = options; + if (encoding && (!childProcess.stdout || !childProcess.stderr)) { + throw new Error( + 'An encoding was specified, but stdout and/or stderr on the child process are not defined' + ); + } + + const collectedStdout: T[] = []; + const collectedStderr: T[] = []; + const useBufferEncoding: boolean = encoding === 'buffer'; + + function normalizeChunk(chunk: Buffer | string): TChunk { + if (typeof chunk === 'string') { + return (useBufferEncoding ? Buffer.from(chunk) : chunk) as TChunk; + } else { + return (useBufferEncoding ? chunk : chunk.toString(encoding as BufferEncoding)) as TChunk; + } + } + + type ISignalAndExitCode = Pick, 'exitCode' | 'signal'>; + + let errorThrown: Error | undefined = undefined; + const { exitCode, signal } = await new Promise( + (resolve: (result: ISignalAndExitCode) => void, reject: (error: Error) => void) => { + if (encoding) { + childProcess.stdout!.on('data', (chunk: Buffer | string) => { + collectedStdout.push(normalizeChunk(chunk)); + }); + childProcess.stderr!.on('data', (chunk: Buffer | string) => { + collectedStderr.push(normalizeChunk(chunk)); + }); + } + childProcess.on('error', (error: Error) => { + // Wait to call reject() until any output is collected + errorThrown = error; + }); + childProcess.on('close', (closeExitCode: number | null, closeSignal: NodeJS.Signals | null) => { + if (errorThrown) { + reject(errorThrown); + } + if (closeSignal && throwOnSignal) { + reject(new Error(`Process terminated by ${closeSignal}`)); + } else if (closeExitCode !== 0 && throwOnNonZeroExitCode) { + reject(new Error(`Process exited with code ${closeExitCode}`)); + } else { + resolve({ exitCode: closeExitCode, signal: closeSignal }); + } + }); + } + ); + + 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; + } + + result = { + stdout: stdout as T, + stderr: stderr as T, + exitCode, + signal + }; + } else { + result = { + exitCode, + signal + }; + } + + return result; + } + + /** + * 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 `powershell.exe` and the `Get-CimInstance` cmdlet. + * - On Unix, this uses the `ps` utility. + */ + public static async getProcessInfoByIdAsync(): Promise> { + const { path: command, args } = getProcessListProcessOptions(); + const process: child_process.ChildProcess = Executable.spawn(command, args, { + stdio: ['ignore', 'pipe', 'ignore'] + }); + if (process.stdout === null) { + throw new InternalError('Child process did not provide stdout'); + } + const [processInfoByIdMap] = await Promise.all([ + parseProcessListOutputAsync(process.stdout), + // Don't collect output in the result since we process it directly + Executable.waitForExitAsync(process, { throwOnNonZeroExitCode: true, throwOnSignal: true }) + ]); + return processInfoByIdMap; + } + + /** + * {@inheritDoc Executable.getProcessInfoByIdAsync} + */ + public static getProcessInfoById(): Map { + const { path: command, args } = getProcessListProcessOptions(); + const processOutput: child_process.SpawnSyncReturns = Executable.spawnSync(command, args); + if (processOutput.error) { + throw new Error(`Unable to list processes: ${command} failed with error ${processOutput.error}`); + } + if (processOutput.status !== 0) { + throw new Error(`Unable to list processes: ${command} exited with code ${processOutput.status}`); + } + return parseProcessListOutput(processOutput.output); + } + + /** + * Get the list of processes currently running on the system, keyed by the process name. All processes + * with the same name will be grouped. + * + * @remarks The underlying implementation depends on the operating system: + * - On Windows, this uses `powershell.exe` and the `Get-CimInstance` cmdlet. + * - On Unix, this uses the `ps` utility. + */ + public static async getProcessInfoByNameAsync(): Promise> { + const processInfoById: Map = await Executable.getProcessInfoByIdAsync(); + return convertToProcessInfoByNameMap(processInfoById); + } + + /** + * {@inheritDoc Executable.getProcessInfoByNameAsync} + */ + public static getProcessInfoByName(): Map { + const processInfoByIdMap: Map = Executable.getProcessInfoById(); + 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') { + if (OS_PLATFORM === 'win32') { // Do we need a custom handler for this file type? switch (fileExtension.toUpperCase()) { case '.EXE': @@ -201,13 +745,15 @@ export class Executable { Executable._validateArgsForWindowsShell(args); // These file types must be invoked via the Windows shell - let shellPath: string | undefined = environment.COMSPEC; + 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`); + throw new Error( + `Unable to execute "${path.basename(resolvedPath)}" ` + + `because CMD.exe was not found in the PATH` + ); } const shellArgs: string[] = []; @@ -223,14 +769,19 @@ export class Executable { shellArgs.push(Executable._getEscapedForWindowsShell(resolvedPath)); shellArgs.push(...args); - return child_process.spawnSync(shellPath, shellArgs, spawnOptions); + return { path: shellPath, args: shellArgs }; } default: - throw new Error(`Cannot execute "${path.basename(resolvedPath)}" because the file type is not supported`); + throw new Error( + `Cannot execute "${path.basename(resolvedPath)}" because the file type is not supported` + ); } } - return child_process.spawnSync(resolvedPath, args, spawnOptions); + return { + path: resolvedPath, + args: args + }; } /** @@ -250,16 +801,18 @@ 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 Executable._tryResolve(filename, options || {}, Executable._getExecutableContext(options)); } - private static _tryResolve(filename: string, options: IExecutableResolveOptions, - context: IExecutableContext): string | undefined { - + 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); + const hasPathSeparators: boolean = + filename.indexOf('/') >= 0 || (OS_PLATFORM === 'win32' && filename.indexOf('\\') >= 0); // Are there any path separators? if (hasPathSeparators) { @@ -283,7 +836,10 @@ export class Executable { } } - private static _tryResolveFileExtension(resolvedPath: string, context: IExecutableContext): string | undefined { + private static _tryResolveFileExtension( + resolvedPath: string, + context: IExecutableContext + ): string | undefined { if (Executable._canExecute(resolvedPath, context)) { return resolvedPath; } @@ -300,6 +856,24 @@ export class Executable { return undefined; } + 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 @@ -310,7 +884,7 @@ export class Executable { return false; } - if (os.platform() === 'win32') { + 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. @@ -321,7 +895,6 @@ export class Executable { if (path.extname(filePath) === '') { return false; } - } else { // For Unix, check whether any of the POSIX execute bits are set try { @@ -343,8 +916,7 @@ export class Executable { * based on the PATH environment variable. */ private static _getSearchFolders(context: IExecutableContext): string[] { - - const pathList: string = context.environment.PATH || ''; + const pathList: string = context.environmentMap.get('PATH') || ''; const folders: string[] = []; @@ -383,10 +955,10 @@ export class Executable { private static _getExecutableContext(options: IExecutableResolveOptions | undefined): IExecutableContext { if (!options) { - options = { }; + options = {}; } - const environment: NodeJS.ProcessEnv = options.environment || process.env; + const environment: EnvironmentMap = Executable._buildEnvironmentMap(options); let currentWorkingDirectory: string; if (options.currentWorkingDirectory) { @@ -397,8 +969,8 @@ export class Executable { const windowsExecutableExtensions: string[] = []; - if (os.platform() === 'win32') { - const pathExtVariable: string = environment.PATHEXT || ''; + 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 @@ -412,7 +984,7 @@ export class Executable { } return { - environment, + environmentMap: environment, currentWorkingDirectory, windowsExecutableExtensions }; @@ -448,8 +1020,10 @@ export class Executable { // 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`); + 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` + ); } } } diff --git a/libraries/node-core-library/src/FileError.ts b/libraries/node-core-library/src/FileError.ts new file mode 100644 index 00000000000..32fac1b5742 --- /dev/null +++ b/libraries/node-core-library/src/FileError.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 type { IProblemPattern } from '@rushstack/problem-matcher'; + +import { type FileLocationStyle, Path } from './Path'; +import { TypeUuid } from './TypeUuid'; + +/** + * Provides options for the creation of a FileError. + * + * @public + */ +export interface IFileErrorOptions { + /** + * The absolute path to the file that contains the error. + */ + absolutePath: string; + + /** + * The root folder for the project that the error is in relation to. + */ + projectFolder: string; + + /** + * The line number of the error in the target file. Minimum value is 1. + */ + line?: number; + + /** + * The column number of the error in the target file. Minimum value is 1. + */ + column?: number; +} + +/** + * Provides options for the output message of a file error. + * + * @public + */ +export interface IFileErrorFormattingOptions { + /** + * The format for the error message. If no format is provided, format 'Unix' is used by default. + */ + format?: FileLocationStyle; +} + +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 +}; + +/** + * An `Error` subclass that should be thrown to report an unexpected state that specifically references + * a location in a file. + * + * @remarks The file path provided to the FileError constructor is expected to exist on disk. FileError + * should not be used for reporting errors that are not in reference to an existing file. + * + * @public + */ +export class FileError extends Error { + /** @internal */ + public static _sanitizedEnvironmentVariable: string | undefined; + /** @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} */ + public readonly projectFolder: string; + /** {@inheritdoc IFileErrorOptions.line} */ + public readonly line: number | undefined; + /** {@inheritdoc IFileErrorOptions.column} */ + public readonly column: number | undefined; + + /** + * Constructs a new instance of the {@link FileError} class. + * + * @param message - A message describing the error. + * @param options - Options for the error. + */ + public constructor(message: string, options: IFileErrorOptions) { + super(message); + + this.absolutePath = options.absolutePath; + this.projectFolder = options.projectFolder; + this.line = options.line; + this.column = options.column; + + // 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 + // + // Note: the prototype must also be set on any classes which extend this one + (this as any).__proto__ = FileError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any + } + + /** + * Get the Unix-formatted the error message. + * + * @override + */ + public toString(): string { + // Default to formatting in 'Unix' format, for consistency. + return this.getFormattedErrorMessage(); + } + + /** + * Get the formatted error message. + * + * @param options - Options for the error message format. + */ + public getFormattedErrorMessage(options?: IFileErrorFormattingOptions): string { + return Path.formatFileLocation({ + format: options?.format || 'Unix', + baseFolder: this._evaluateBaseFolder(), + pathToFormat: this.absolutePath, + message: this.message, + line: this.line, + column: this.column + }); + } + + /** + * 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 + // of being able to cache absolute paths, since that is only able to be determined after + // running the regex, which is expensive. Since this would be a common execution path for + // tools like Rush, we should optimize for that. + if (!FileError._sanitizedEnvironmentVariable && process.env[baseFolderEnvVar]) { + // Strip leading and trailing quotes, if present. + FileError._sanitizedEnvironmentVariable = process.env[baseFolderEnvVar]!.replace(/^("|')|("|')$/g, ''); + } + + if (FileError._environmentVariableIsAbsolutePath) { + return FileError._sanitizedEnvironmentVariable; + } + + // undefined environment variable has a mapping to the project folder + const baseFolderFn: ((fileError: FileError) => string | undefined) | undefined = + FileError._environmentVariableBasePathFnMap.get(FileError._sanitizedEnvironmentVariable); + if (baseFolderFn) { + return baseFolderFn(this); + } + + const baseFolderTokenRegex: RegExp = /{([^}]+)}/g; + const result: RegExpExecArray | null = baseFolderTokenRegex.exec( + FileError._sanitizedEnvironmentVariable! + ); + if (!result) { + // No tokens, assume absolute path + FileError._environmentVariableIsAbsolutePath = true; + return FileError._sanitizedEnvironmentVariable; + } else if (result.index !== 0) { + // Currently only support the token being first in the string. + throw new Error( + `The ${baseFolderEnvVar} environment variable contains text before the token "${result[0]}".` + ); + } else if (result[0].length !== FileError._sanitizedEnvironmentVariable!.length) { + // Currently only support the token being the entire string. + throw new Error( + `The ${baseFolderEnvVar} environment variable contains text after the token "${result[0]}".` + ); + } else { + throw new Error( + `The ${baseFolderEnvVar} environment variable contains a token "${result[0]}", which is not ` + + 'supported.' + ); + } + } + + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidFileError); + } +} + +TypeUuid.registerClass(FileError, uuidFileError); diff --git a/libraries/node-core-library/src/FileSystem.ts b/libraries/node-core-library/src/FileSystem.ts index da0913fa029..da107dd1604 100644 --- a/libraries/node-core-library/src/FileSystem.ts +++ b/libraries/node-core-library/src/FileSystem.ts @@ -1,18 +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 pathUtilities 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, NewlineKind, Encoding } from './Text'; +import { Text, type NewlineKind, Encoding } from './Text'; import { PosixModeBits } from './PosixModeBits'; +/** + * An alias for the Node.js `fs.Stats` object. + * + * @remarks + * This avoids the need to import the `fs` package when using the {@link FileSystem} API. + * @public + */ +export type FileSystemStats = fs.Stats; + +/** + * An alias for the Node.js `fs.Dirent` object. + * + * @remarks + * This avoids the need to import the `fs` package when using the {@link FileSystem} API. + * @public + */ +export type FolderItem = fs.Dirent; + // The PosixModeBits are intended to be used with bitwise operations. /* eslint-disable no-bitwise */ /** - * The options for FileSystem.readFolder() + * The options for {@link FileSystem.readFolderItems} and {@link FileSystem.readFolderItemNames}. * @public */ export interface IFileSystemReadFolderOptions { @@ -24,16 +44,22 @@ export interface IFileSystemReadFolderOptions { } /** - * The options for FileSystem.writeFile() + * The options for {@link FileSystem.writeBuffersToFile} * @public */ -export interface IFileSystemWriteFileOptions { +export interface IFileSystemWriteBinaryFileOptions { /** * If true, will ensure the folder is created before writing the file. * @defaultValue false */ ensureFolderExists?: boolean; +} +/** + * The options for {@link FileSystem.writeFile} + * @public + */ +export interface IFileSystemWriteFileOptions extends IFileSystemWriteBinaryFileOptions { /** * If specified, will normalize line endings to the specified style of newline. * @defaultValue `undefined` which means no conversion will be performed @@ -48,7 +74,7 @@ export interface IFileSystemWriteFileOptions { } /** - * The options for FileSystem.readFile() + * The options for {@link FileSystem.readFile} * @public */ export interface IFileSystemReadFileOptions { @@ -66,7 +92,7 @@ export interface IFileSystemReadFileOptions { } /** - * The options for FileSystem.move() + * The options for {@link FileSystem.move} * @public */ export interface IFileSystemMoveOptions { @@ -96,16 +122,27 @@ export interface IFileSystemMoveOptions { } /** - * The options for FileSystem.copyFile() * @public */ -export interface IFileSystemCopyFileOptions { +export interface IFileSystemCopyFileBaseOptions { /** * The path of the existing object to be copied. * The path may be absolute or relative. */ sourcePath: string; + /** + * Specifies what to do if the destination path already exists. + * @defaultValue {@link AlreadyExistsBehavior.Overwrite} + */ + alreadyExistsBehavior?: AlreadyExistsBehavior; +} + +/** + * The options for {@link FileSystem.copyFile} + * @public + */ +export interface IFileSystemCopyFileOptions extends IFileSystemCopyFileBaseOptions { /** * The path that the object will be copied to. * The path may be absolute or relative. @@ -114,9 +151,117 @@ export interface IFileSystemCopyFileOptions { } /** - * The options for FileSystem.deleteFile() + * Specifies the behavior of APIs such as {@link FileSystem.copyFile} or + * {@link FileSystem.createSymbolicLinkFile} when the output file path already exists. + * + * @remarks + * For {@link FileSystem.copyFile} and related APIs, the "output file path" is + * {@link IFileSystemCopyFileOptions.destinationPath}. + * + * For {@link FileSystem.createSymbolicLinkFile} and related APIs, the "output file path" is + * {@link IFileSystemCreateLinkOptions.newLinkPath}. + * + * @public + */ +export enum AlreadyExistsBehavior { + /** + * If the output file path already exists, try to overwrite the existing object. + * + * @remarks + * If overwriting the object would require recursively deleting a folder tree, + * then the operation will fail. As an example, suppose {@link FileSystem.copyFile} + * is copying a single file `/a/b/c` to the destination path `/d/e`, and `/d/e` is a + * nonempty folder. In this situation, an error will be reported; specifying + * `AlreadyExistsBehavior.Overwrite` does not help. Empty folders can be overwritten + * depending on the details of the implementation. + */ + Overwrite = 'overwrite', + + /** + * If the output file path already exists, the operation will fail, and an error + * will be reported. + */ + Error = 'error', + + /** + * If the output file path already exists, skip this item, and continue the operation. + */ + Ignore = 'ignore' +} + +/** + * Callback function type for {@link IFileSystemCopyFilesAsyncOptions.filter} * @public -*/ + */ +export type FileSystemCopyFilesAsyncFilter = ( + sourcePath: string, + destinationPath: string +) => Promise; + +/** + * Callback function type for {@link IFileSystemCopyFilesOptions.filter} + * @public + */ +export type FileSystemCopyFilesFilter = (sourcePath: string, destinationPath: string) => boolean; + +/** + * The options for {@link FileSystem.copyFilesAsync} + * @public + */ +export interface IFileSystemCopyFilesAsyncOptions { + /** + * The starting path of the file or folder to be copied. + * The path may be absolute or relative. + */ + sourcePath: string; + + /** + * The path that the files will be copied to. + * The path may be absolute or relative. + */ + destinationPath: string; + + /** + * If true, then when copying symlinks, copy the target object instead of copying the link. + */ + dereferenceSymlinks?: boolean; + + /** + * Specifies what to do if a destination path already exists. + * + * @remarks + * This setting is applied individually for each file being copied. + * For example, `AlreadyExistsBehavior.Overwrite` will not recursively delete a folder + * whose path corresponds to an individual file that is being copied to that location. + */ + alreadyExistsBehavior?: AlreadyExistsBehavior; + + /** + * If true, then the target object will be assigned "last modification" and "last access" timestamps + * that are the same as the source. Otherwise, the OS default timestamps are assigned. + */ + preserveTimestamps?: boolean; + + /** + * A callback that will be invoked for each path that is copied. The callback can return `false` + * to cause the object to be excluded from the operation. + */ + filter?: FileSystemCopyFilesAsyncFilter | FileSystemCopyFilesFilter; +} + +/** + * The options for {@link FileSystem.copyFiles} + * @public + */ +export interface IFileSystemCopyFilesOptions extends IFileSystemCopyFilesAsyncOptions { + /** {@inheritdoc IFileSystemCopyFilesAsyncOptions.filter} */ + filter?: FileSystemCopyFilesFilter; // narrow the type to exclude FileSystemCopyFilesAsyncFilter +} + +/** + * The options for {@link FileSystem.deleteFile} + * @public + */ export interface IFileSystemDeleteFileOptions { /** * If true, will throw an exception if the file did not exist before `deleteFile()` was called. @@ -126,7 +271,7 @@ export interface IFileSystemDeleteFileOptions { } /** - * The parameters for `updateTimes()`. + * The options for {@link FileSystem.updateTimes} * Both times must be specified. * @public */ @@ -143,23 +288,72 @@ export interface IFileSystemUpdateTimeParameters { } /** - * The options for `FileSystem.createSymbolicLinkJunction()`, `createSymbolicLinkFile()`, - * `createSymbolicLinkFolder()`, and `createHardLink()`. + * The options for {@link FileSystem.createSymbolicLinkJunction}, {@link FileSystem.createSymbolicLinkFile}, + * {@link FileSystem.createSymbolicLinkFolder}, and {@link FileSystem.createHardLink}. * * @public */ export interface IFileSystemCreateLinkOptions { /** - * The existing path that the symbolic link will point to. + * The newly created symbolic link will point to `linkTargetPath` as its target. */ linkTargetPath: string; /** - * The new path for the new symlink link to be created. + * The newly created symbolic link will have this path. */ newLinkPath: string; + + /** + * Specifies what to do if the path to create already exists. + * The default is `AlreadyExistsBehavior.Error`. + */ + alreadyExistsBehavior?: AlreadyExistsBehavior; +} + +interface IInternalFileSystemCreateLinkOptions extends IFileSystemCreateLinkOptions { + /** + * Specifies if the link target must exist. + */ + linkTargetMustExist?: boolean; } +const MOVE_DEFAULT_OPTIONS: Partial = { + overwrite: true, + ensureFolderExists: false +}; + +const READ_FOLDER_DEFAULT_OPTIONS: Partial = { + absolutePaths: false +}; + +const WRITE_FILE_DEFAULT_OPTIONS: Partial = { + ensureFolderExists: false, + convertLineEndings: undefined, + encoding: Encoding.Utf8 +}; + +const APPEND_TO_FILE_DEFAULT_OPTIONS: Partial = { + ...WRITE_FILE_DEFAULT_OPTIONS +}; + +const READ_FILE_DEFAULT_OPTIONS: Partial = { + encoding: Encoding.Utf8, + convertLineEndings: undefined +}; + +const COPY_FILE_DEFAULT_OPTIONS: Partial = { + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite +}; + +const COPY_FILES_DEFAULT_OPTIONS: Partial = { + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite +}; + +const DELETE_FILE_DEFAULT_OPTIONS: Partial = { + throwIfNotExists: false +}; + /** * The FileSystem API provides a complete set of recommended operations for interacting with the file system. * @@ -177,7 +371,6 @@ export interface IFileSystemCreateLinkOptions { * @public */ export class FileSystem { - // =============== // COMMON OPERATIONS // =============== @@ -194,7 +387,20 @@ export class FileSystem { * @param path - The absolute or relative path to the filesystem object. */ public static exists(path: string): boolean { - return fsx.existsSync(path); + return FileSystem._wrapException(() => { + return fsx.existsSync(path); + }); + } + + /** + * An async version of {@link FileSystem.exists}. + */ + public static async existsAsync(path: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return new Promise((resolve: (result: boolean) => void) => { + fsx.exists(path, resolve); + }); + }); } /** @@ -203,8 +409,19 @@ export class FileSystem { * Behind the scenes it uses `fs.statSync()`. * @param path - The absolute or relative path to the filesystem object. */ - public static getStatistics(path: string): fs.Stats { - return fsx.statSync(path); + public static getStatistics(path: string): FileSystemStats { + return FileSystem._wrapException(() => { + return fsx.statSync(path); + }); + } + + /** + * An async version of {@link FileSystem.getStatistics}. + */ + public static async getStatisticsAsync(path: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return fsx.stat(path); + }); } /** @@ -215,8 +432,20 @@ export class FileSystem { * @param times - The times that the object should be updated to reflect. */ public static updateTimes(path: string, times: IFileSystemUpdateTimeParameters): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - fsx.utimesSync(path, times.accessedTime as any, times.modifiedTime as any); + return FileSystem._wrapException(() => { + fsx.utimesSync(path, times.accessedTime, times.modifiedTime); + }); + } + + /** + * An async version of {@link FileSystem.updateTimes}. + */ + public static async updateTimesAsync(path: string, times: IFileSystemUpdateTimeParameters): Promise { + await FileSystem._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); + }); } /** @@ -225,17 +454,44 @@ export class FileSystem { * @param path - The absolute or relative path to the object that should be updated. * @param modeBits - POSIX-style file mode bits specified using the {@link PosixModeBits} enum */ - public static changePosixModeBits(path: string, mode: PosixModeBits): void { - fs.chmodSync(path, mode); + public static changePosixModeBits(path: string, modeBits: PosixModeBits): void { + FileSystem._wrapException(() => { + fs.chmodSync(path, modeBits); + }); + } + + /** + * An async version of {@link FileSystem.changePosixModeBits}. + */ + public static async changePosixModeBitsAsync(path: string, mode: PosixModeBits): Promise { + await FileSystem._wrapExceptionAsync(() => { + return fsx.chmod(path, mode); + }); } /** * Retrieves the permissions (i.e. file mode bits) for a filesystem object. * Behind the scenes it uses `fs.chmodSync()`. * @param path - The absolute or relative path to the object that should be updated. + * + * @remarks + * This calls {@link FileSystem.getStatistics} to get the POSIX mode bits. + * If statistics in addition to the mode bits are needed, it is more efficient + * to call {@link FileSystem.getStatistics} directly instead. */ public static getPosixModeBits(path: string): PosixModeBits { - return FileSystem.getStatistics(path).mode; + return FileSystem._wrapException(() => { + return FileSystem.getStatistics(path).mode; + }); + } + + /** + * An async version of {@link FileSystem.getPosixModeBits}. + */ + public static async getPosixModeBitsAsync(path: string): Promise { + return await FileSystem._wrapExceptionAsync(async () => { + return (await FileSystem.getStatisticsAsync(path)).mode; + }); } /** @@ -246,19 +502,19 @@ export class FileSystem { * @param modeBits - POSIX-style file mode bits specified using the {@link PosixModeBits} enum */ public static formatPosixModeBits(modeBits: PosixModeBits): string { - let result: string = '-'; // (later we may add support for additional states such as S_IFDIR or S_ISUID) + let result: string = '-'; // (later we may add support for additional states such as S_IFDIR or S_ISUID) - result += (modeBits & PosixModeBits.UserRead) ? 'r' : '-'; - result += (modeBits & PosixModeBits.UserWrite) ? 'w' : '-'; - result += (modeBits & PosixModeBits.UserExecute) ? 'x' : '-'; + result += modeBits & PosixModeBits.UserRead ? 'r' : '-'; + result += modeBits & PosixModeBits.UserWrite ? 'w' : '-'; + result += modeBits & PosixModeBits.UserExecute ? 'x' : '-'; - result += (modeBits & PosixModeBits.GroupRead) ? 'r' : '-'; - result += (modeBits & PosixModeBits.GroupWrite) ? 'w' : '-'; - result += (modeBits & PosixModeBits.GroupExecute) ? 'x' : '-'; + result += modeBits & PosixModeBits.GroupRead ? 'r' : '-'; + result += modeBits & PosixModeBits.GroupWrite ? 'w' : '-'; + result += modeBits & PosixModeBits.GroupExecute ? 'x' : '-'; - result += (modeBits & PosixModeBits.OthersRead) ? 'r' : '-'; - result += (modeBits & PosixModeBits.OthersWrite) ? 'w' : '-'; - result += (modeBits & PosixModeBits.OthersExecute) ? 'x' : '-'; + result += modeBits & PosixModeBits.OthersRead ? 'r' : '-'; + result += modeBits & PosixModeBits.OthersWrite ? 'w' : '-'; + result += modeBits & PosixModeBits.OthersExecute ? 'x' : '-'; return result; } @@ -268,17 +524,56 @@ export class FileSystem { * Behind the scenes it uses `fs-extra.moveSync()` */ public static move(options: IFileSystemMoveOptions): void { - options = { - overwrite: true, - ensureFolderExists: false, - ...options - }; + FileSystem._wrapException(() => { + options = { + ...MOVE_DEFAULT_OPTIONS, + ...options + }; - if (options.ensureFolderExists) { - FileSystem.ensureFolder(pathUtilities.basename(options.sourcePath)); - } + try { + fsx.moveSync(options.sourcePath, options.destinationPath, { overwrite: options.overwrite }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(options.destinationPath); + FileSystem.ensureFolder(folderPath); + fsx.moveSync(options.sourcePath, options.destinationPath, { overwrite: options.overwrite }); + } else { + throw error; + } + } + }); + } + + /** + * An async version of {@link FileSystem.move}. + */ + public static async moveAsync(options: IFileSystemMoveOptions): Promise { + await FileSystem._wrapExceptionAsync(async () => { + options = { + ...MOVE_DEFAULT_OPTIONS, + ...options + }; - fsx.moveSync(options.sourcePath, options.destinationPath, { overwrite: options.overwrite }); + try { + await fsx.move(options.sourcePath, options.destinationPath, { overwrite: options.overwrite }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(options.destinationPath); + await FileSystem.ensureFolderAsync(nodeJsPath.dirname(folderPath)); + await fsx.move(options.sourcePath, options.destinationPath, { overwrite: options.overwrite }); + } else { + throw error; + } + } + }); } // =============== @@ -293,32 +588,113 @@ export class FileSystem { * @param folderPath - The absolute or relative path of the folder which should be created. */ public static ensureFolder(folderPath: string): void { - fsx.ensureDirSync(folderPath); + FileSystem._wrapException(() => { + fsx.ensureDirSync(folderPath); + }); } /** - * Reads the contents of the folder, not including "." or "..". + * An async version of {@link FileSystem.ensureFolder}. + */ + public static async ensureFolderAsync(folderPath: string): Promise { + await FileSystem._wrapExceptionAsync(() => { + return fsx.ensureDir(folderPath); + }); + } + + /** + * Reads the names of folder entries, not including "." or "..". * Behind the scenes it uses `fs.readdirSync()`. * @param folderPath - The absolute or relative path to the folder which should be read. * @param options - Optional settings that can change the behavior. Type: `IReadFolderOptions` */ - public static readFolder(folderPath: string, options?: IFileSystemReadFolderOptions): string[] { - options = { - absolutePaths: false, - ...options - }; - - if (!FileSystem.exists(folderPath)) { - throw new Error(`Folder does not exist: "${folderPath}"`); - } + public static readFolderItemNames(folderPath: string, options?: IFileSystemReadFolderOptions): string[] { + return FileSystem._wrapException(() => { + options = { + ...READ_FOLDER_DEFAULT_OPTIONS, + ...options + }; + + const fileNames: string[] = fsx.readdirSync(folderPath); + if (options.absolutePaths) { + return fileNames.map((fileName) => nodeJsPath.resolve(folderPath, fileName)); + } else { + return fileNames; + } + }); + } - const fileNames: string[] = fsx.readdirSync(folderPath); + /** + * An async version of {@link FileSystem.readFolderItemNames}. + */ + public static async readFolderItemNamesAsync( + folderPath: string, + options?: IFileSystemReadFolderOptions + ): Promise { + return await FileSystem._wrapExceptionAsync(async () => { + options = { + ...READ_FOLDER_DEFAULT_OPTIONS, + ...options + }; + + const fileNames: string[] = await fsx.readdir(folderPath); + if (options.absolutePaths) { + return fileNames.map((fileName) => nodeJsPath.resolve(folderPath, fileName)); + } else { + return fileNames; + } + }); + } - if (options.absolutePaths) { - return fileNames.map(fileName => pathUtilities.resolve(folderPath, fileName)); - } + /** + * Reads the contents of the folder, not including "." or "..", returning objects including the + * entry names and types. + * Behind the scenes it uses `fs.readdirSync()`. + * @param folderPath - The absolute or relative path to the folder which should be read. + * @param options - Optional settings that can change the behavior. Type: `IReadFolderOptions` + */ + public static readFolderItems(folderPath: string, options?: IFileSystemReadFolderOptions): FolderItem[] { + return FileSystem._wrapException(() => { + options = { + ...READ_FOLDER_DEFAULT_OPTIONS, + ...options + }; + + const folderEntries: FolderItem[] = fsx.readdirSync(folderPath, { withFileTypes: true }); + if (options.absolutePaths) { + return folderEntries.map((folderEntry) => { + folderEntry.name = nodeJsPath.resolve(folderPath, folderEntry.name); + return folderEntry; + }); + } else { + return folderEntries; + } + }); + } - return fileNames; + /** + * An async version of {@link FileSystem.readFolderItems}. + */ + public static async readFolderItemsAsync( + folderPath: string, + options?: IFileSystemReadFolderOptions + ): Promise { + return await FileSystem._wrapExceptionAsync(async () => { + options = { + ...READ_FOLDER_DEFAULT_OPTIONS, + ...options + }; + + const folderEntries: FolderItem[] = await fsPromises.readdir(folderPath, { withFileTypes: true }); + if (options.absolutePaths) { + return folderEntries.map((folderEntry) => { + folderEntry.name = nodeJsPath.resolve(folderPath, folderEntry.name); + return folderEntry; + }); + } else { + return folderEntries; + } + }); } /** @@ -329,7 +705,18 @@ export class FileSystem { * @param folderPath - The absolute or relative path to the folder which should be deleted. */ public static deleteFolder(folderPath: string): void { - fsx.removeSync(folderPath); + FileSystem._wrapException(() => { + fsx.removeSync(folderPath); + }); + } + + /** + * An async version of {@link FileSystem.deleteFolder}. + */ + public static async deleteFolderAsync(folderPath: string): Promise { + await FileSystem._wrapExceptionAsync(() => { + return fsx.remove(folderPath); + }); } /** @@ -341,7 +728,18 @@ 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 { - fsx.emptyDirSync(folderPath); + FileSystem._wrapException(() => { + fsx.emptyDirSync(folderPath); + }); + } + + /** + * An async version of {@link FileSystem.ensureEmptyFolder}. + */ + public static async ensureEmptyFolderAsync(folderPath: string): Promise { + await FileSystem._wrapExceptionAsync(() => { + return fsx.emptyDir(folderPath); + }); } // =============== @@ -357,24 +755,201 @@ export class FileSystem { * @param contents - The text that should be written to the file. * @param options - Optional settings that can change the behavior. Type: `IWriteFileOptions` */ - public static writeFile(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): void { - options = { - ensureFolderExists: false, - convertLineEndings: undefined, - encoding: Encoding.Utf8, - ...options - }; + public static writeFile( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions + ): void { + FileSystem._wrapException(() => { + options = { + ...WRITE_FILE_DEFAULT_OPTIONS, + ...options + }; + + if (options.convertLineEndings) { + contents = Text.convertTo(contents.toString(), options.convertLineEndings); + } - if (options.ensureFolderExists) { - const folderPath: string = pathUtilities.dirname(filePath); - FileSystem.ensureFolder(folderPath); - } + try { + fsx.writeFileSync(filePath, contents, { encoding: options.encoding }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + FileSystem.ensureFolder(folderPath); + fsx.writeFileSync(filePath, contents, { encoding: options.encoding }); + } else { + throw error; + } + } + }); + } - if (options.convertLineEndings) { - contents = Text.convertTo(contents.toString(), options.convertLineEndings); - } + /** + * Writes the contents of multiple Uint8Arrays to a file on disk, overwriting the file if it already exists. + * Behind the scenes it uses `fs.writevSync()`. + * + * This API is useful for writing large files efficiently, especially if the input is being concatenated from + * multiple sources. + * + * @remarks + * Throws an error if the folder doesn't exist, unless ensureFolder=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, + options?: IFileSystemWriteBinaryFileOptions + ): void { + FileSystem._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: NodeJS.ArrayBufferView[] = [...contents]; + + let fd: number | undefined; + try { + fd = fsx.openSync(filePath, 'w'); + } catch (error) { + if (!options?.ensureFolderExists || !FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + FileSystem.ensureFolder(folderPath); + fd = fsx.openSync(filePath, 'w'); + } - fsx.writeFileSync(filePath, contents, { encoding: options.encoding }); + try { + // In practice this loop will have exactly 1 iteration, but the spec allows + // for a writev call to write fewer bytes than requested + while (toCopy.length) { + let bytesWritten: number = fsx.writevSync(fd, toCopy); + let buffersWritten: number = 0; + while (buffersWritten < toCopy.length) { + const bytesInCurrentBuffer: number = toCopy[buffersWritten].byteLength; + if (bytesWritten < bytesInCurrentBuffer) { + // This buffer was partially written. + const currentToCopy: NodeJS.ArrayBufferView = toCopy[buffersWritten]; + toCopy[buffersWritten] = new Uint8Array( + currentToCopy.buffer, + currentToCopy.byteOffset + bytesWritten, + currentToCopy.byteLength - bytesWritten + ); + break; + } + bytesWritten -= bytesInCurrentBuffer; + buffersWritten++; + } + + if (buffersWritten > 0) { + // Avoid cost of shifting the array more than needed. + toCopy.splice(0, buffersWritten); + } + } + } finally { + fsx.closeSync(fd); + } + }); + } + + /** + * An async version of {@link FileSystem.writeFile}. + */ + public static async writeFileAsync( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions + ): Promise { + await FileSystem._wrapExceptionAsync(async () => { + options = { + ...WRITE_FILE_DEFAULT_OPTIONS, + ...options + }; + + if (options.convertLineEndings) { + contents = Text.convertTo(contents.toString(), options.convertLineEndings); + } + + try { + await fsx.writeFile(filePath, contents, { encoding: options.encoding }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + await FileSystem.ensureFolderAsync(folderPath); + await fsx.writeFile(filePath, contents, { encoding: options.encoding }); + } else { + throw error; + } + } + }); + } + + /** + * An async version of {@link FileSystem.writeBuffersToFile}. + */ + public static async writeBuffersToFileAsync( + filePath: string, + contents: ReadonlyArray, + options?: IFileSystemWriteBinaryFileOptions + ): Promise { + await FileSystem._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: NodeJS.ArrayBufferView[] = [...contents]; + + let handle: fsPromises.FileHandle | undefined; + try { + handle = await fsPromises.open(filePath, 'w'); + } catch (error) { + if (!options?.ensureFolderExists || !FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + await FileSystem.ensureFolderAsync(folderPath); + handle = await fsPromises.open(filePath, 'w'); + } + + try { + // In practice this loop will have exactly 1 iteration, but the spec allows + // for a writev call to write fewer bytes than requested + while (toCopy.length) { + let bytesWritten: number = (await handle.writev(toCopy)).bytesWritten; + let buffersWritten: number = 0; + while (buffersWritten < toCopy.length) { + const bytesInCurrentBuffer: number = toCopy[buffersWritten].byteLength; + if (bytesWritten < bytesInCurrentBuffer) { + // This buffer was partially written. + const currentToCopy: NodeJS.ArrayBufferView = toCopy[buffersWritten]; + toCopy[buffersWritten] = new Uint8Array( + currentToCopy.buffer, + currentToCopy.byteOffset + bytesWritten, + currentToCopy.byteLength - bytesWritten + ); + break; + } + bytesWritten -= bytesInCurrentBuffer; + buffersWritten++; + } + + if (buffersWritten > 0) { + // Avoid cost of shifting the array more than needed. + toCopy.splice(0, buffersWritten); + } + } + } finally { + await handle.close(); + } + }); } /** @@ -386,24 +961,73 @@ export class FileSystem { * @param contents - The text that should be written to the file. * @param options - Optional settings that can change the behavior. Type: `IWriteFileOptions` */ - public static appendToFile(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): void { - options = { - ensureFolderExists: false, - convertLineEndings: undefined, - encoding: Encoding.Utf8, - ...options - }; + public static appendToFile( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions + ): void { + FileSystem._wrapException(() => { + options = { + ...APPEND_TO_FILE_DEFAULT_OPTIONS, + ...options + }; + + if (options.convertLineEndings) { + contents = Text.convertTo(contents.toString(), options.convertLineEndings); + } - if (options.ensureFolderExists) { - const folderPath: string = pathUtilities.dirname(filePath); - FileSystem.ensureFolder(folderPath); - } + try { + fsx.appendFileSync(filePath, contents, { encoding: options.encoding }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + FileSystem.ensureFolder(folderPath); + fsx.appendFileSync(filePath, contents, { encoding: options.encoding }); + } else { + throw error; + } + } + }); + } - if (options.convertLineEndings) { - contents = Text.convertTo(contents.toString(), options.convertLineEndings); - } + /** + * An async version of {@link FileSystem.appendToFile}. + */ + public static async appendToFileAsync( + filePath: string, + contents: string | Buffer, + options?: IFileSystemWriteFileOptions + ): Promise { + await FileSystem._wrapExceptionAsync(async () => { + options = { + ...APPEND_TO_FILE_DEFAULT_OPTIONS, + ...options + }; + + if (options.convertLineEndings) { + contents = Text.convertTo(contents.toString(), options.convertLineEndings); + } - fsx.appendFileSync(filePath, contents, { encoding: options.encoding }); + try { + await fsx.appendFile(filePath, contents, { encoding: options.encoding }); + } catch (error) { + if (options.ensureFolderExists) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + const folderPath: string = nodeJsPath.dirname(filePath); + await FileSystem.ensureFolderAsync(folderPath); + await fsx.appendFile(filePath, contents, { encoding: options.encoding }); + } else { + throw error; + } + } + }); } /** @@ -413,17 +1037,38 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IReadFileOptions` */ public static readFile(filePath: string, options?: IFileSystemReadFileOptions): string { - options = { - encoding: Encoding.Utf8, - convertLineEndings: undefined, - ...options - }; + return FileSystem._wrapException(() => { + options = { + ...READ_FILE_DEFAULT_OPTIONS, + ...options + }; + + let contents: string = FileSystem.readFileToBuffer(filePath).toString(options.encoding); + if (options.convertLineEndings) { + contents = Text.convertTo(contents, options.convertLineEndings); + } - let contents: string = FileSystem.readFileToBuffer(filePath).toString(options.encoding); - if (options.convertLineEndings) { - contents = Text.convertTo(contents, options.convertLineEndings); - } - return contents; + return contents; + }); + } + + /** + * An async version of {@link FileSystem.readFile}. + */ + public static async readFileAsync(filePath: string, options?: IFileSystemReadFileOptions): Promise { + return await FileSystem._wrapExceptionAsync(async () => { + options = { + ...READ_FILE_DEFAULT_OPTIONS, + ...options + }; + + let contents: string = (await FileSystem.readFileToBufferAsync(filePath)).toString(options.encoding); + if (options.convertLineEndings) { + contents = Text.convertTo(contents, options.convertLineEndings); + } + + return contents; + }); } /** @@ -432,16 +1077,118 @@ 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 fsx.readFileSync(filePath); + return FileSystem._wrapException(() => { + return fsx.readFileSync(filePath); + }); } /** - * Copies a file from one location to another. + * An async version of {@link FileSystem.readFileToBuffer}. + */ + public static async readFileToBufferAsync(filePath: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return fsx.readFile(filePath); + }); + } + + /** + * Copies a single file from one location to another. * By default, destinationPath is overwritten if it already exists. - * Behind the scenes it uses `fs.copyFileSync()`. + * + * @remarks + * The `copyFile()` API cannot be used to copy folders. It copies at most one file. + * Use {@link FileSystem.copyFiles} if you need to recursively copy a tree of folders. + * + * The implementation is based on `copySync()` from the `fs-extra` package. */ public static copyFile(options: IFileSystemCopyFileOptions): void { - fsx.copySync(options.sourcePath, options.destinationPath); + options = { + ...COPY_FILE_DEFAULT_OPTIONS, + ...options + }; + + if (FileSystem.getStatistics(options.sourcePath).isDirectory()) { + throw new Error( + 'The specified path refers to a folder; this operation expects a file object:\n' + options.sourcePath + ); + } + + FileSystem._wrapException(() => { + fsx.copySync(options.sourcePath, options.destinationPath, { + errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, + overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite + }); + }); + } + + /** + * An async version of {@link FileSystem.copyFile}. + */ + public static async copyFileAsync(options: IFileSystemCopyFileOptions): Promise { + options = { + ...COPY_FILE_DEFAULT_OPTIONS, + ...options + }; + + if ((await FileSystem.getStatisticsAsync(options.sourcePath)).isDirectory()) { + throw new Error( + 'The specified path refers to a folder; this operation expects a file object:\n' + options.sourcePath + ); + } + + await FileSystem._wrapExceptionAsync(() => { + return fsx.copy(options.sourcePath, options.destinationPath, { + errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, + overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite + }); + }); + } + + /** + * Copies a file or folder from one location to another, recursively copying any folder contents. + * By default, destinationPath is overwritten if it already exists. + * + * @remarks + * If you only intend to copy a single file, it is recommended to use {@link FileSystem.copyFile} + * instead to more clearly communicate the intended operation. + * + * The implementation is based on `copySync()` from the `fs-extra` package. + */ + public static copyFiles(options: IFileSystemCopyFilesOptions): void { + options = { + ...COPY_FILES_DEFAULT_OPTIONS, + ...options + }; + + FileSystem._wrapException(() => { + fsx.copySync(options.sourcePath, options.destinationPath, { + dereference: !!options.dereferenceSymlinks, + errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, + overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite, + preserveTimestamps: !!options.preserveTimestamps, + filter: options.filter + }); + }); + } + + /** + * An async version of {@link FileSystem.copyFiles}. + */ + public static async copyFilesAsync(options: IFileSystemCopyFilesAsyncOptions): Promise { + options = { + ...COPY_FILES_DEFAULT_OPTIONS, + ...options + }; + + await FileSystem._wrapExceptionAsync(async () => { + await fsx.copy(options.sourcePath, options.destinationPath, { + dereference: !!options.dereferenceSymlinks, + errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, + overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite, + preserveTimestamps: !!options.preserveTimestamps, + filter: options.filter + }); + }); } /** @@ -451,20 +1198,43 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IDeleteFileOptions` */ public static deleteFile(filePath: string, options?: IFileSystemDeleteFileOptions): void { - options = { - throwIfNotExists: false, - ...options - }; + FileSystem._wrapException(() => { + options = { + ...DELETE_FILE_DEFAULT_OPTIONS, + ...options + }; - if (options.throwIfNotExists) { - fsx.unlinkSync(filePath); - } else { try { fsx.unlinkSync(filePath); } catch (error) { - /* no-op */ + if (options.throwIfNotExists || !FileSystem.isNotExistError(error as Error)) { + throw error; + } } - } + }); + } + + /** + * An async version of {@link FileSystem.deleteFile}. + */ + public static async deleteFileAsync( + filePath: string, + options?: IFileSystemDeleteFileOptions + ): Promise { + await FileSystem._wrapExceptionAsync(async () => { + options = { + ...DELETE_FILE_DEFAULT_OPTIONS, + ...options + }; + + try { + await fsx.unlink(filePath); + } catch (error) { + if (options.throwIfNotExists || !FileSystem.isNotExistError(error as Error)) { + throw error; + } + } + }); } // =============== @@ -476,41 +1246,188 @@ export class FileSystem { * Behind the scenes it uses `fs.lstatSync()`. * @param path - The absolute or relative path to the filesystem object. */ - public static getLinkStatistics(path: string): fs.Stats { - return fsx.lstatSync(path); + public static getLinkStatistics(path: string): FileSystemStats { + return FileSystem._wrapException(() => { + return fsx.lstatSync(path); + }); + } + + /** + * An async version of {@link FileSystem.getLinkStatistics}. + */ + public static async getLinkStatisticsAsync(path: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return fsx.lstat(path); + }); + } + + /** + * If `path` refers to a symbolic link, this returns the path of the link target, which may be + * an absolute or relative path. + * + * @remarks + * If `path` refers to a filesystem object that is not a symbolic link, then an `ErrnoException` is thrown + * with code 'UNKNOWN'. If `path` does not exist, then an `ErrnoException` is thrown with code `ENOENT`. + * + * @param path - The absolute or relative path to the symbolic link. + * @returns the path of the link target + */ + public static readLink(path: string): string { + return FileSystem._wrapException(() => { + return fsx.readlinkSync(path); + }); + } + + /** + * An async version of {@link FileSystem.readLink}. + */ + public static async readLinkAsync(path: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return fsx.readlink(path); + }); } /** - * Creates a Windows "directory junction". Behaves like `createSymbolicLinkToFile()` on other platforms. + * Creates an NTFS "directory junction" on Windows operating systems; for other operating systems, it + * creates a regular symbolic link. The link target must be a folder, not a file. * Behind the scenes it uses `fs.symlinkSync()`. + * + * @remarks + * For security reasons, Windows operating systems by default require administrator elevation to create + * symbolic links. As a result, on Windows it's generally recommended for Node.js tools to use hard links + * (for files) or NTFS directory junctions (for folders), since regular users are allowed to create them. + * Hard links and junctions are less vulnerable to symlink attacks because they cannot reference a network share, + * and their target must exist at the time of link creation. Non-Windows operating systems generally don't + * restrict symlink creation, and as such are more vulnerable to symlink attacks. Note that Windows can be + * configured to permit regular users to create symlinks, for example by enabling Windows 10 "developer mode." + * + * A directory junction requires the link source and target to both be located on local disk volumes; + * if not, use a symbolic link instead. */ public static createSymbolicLinkJunction(options: IFileSystemCreateLinkOptions): void { - // For directories, we use a Windows "junction". On POSIX operating systems, this produces a regular symlink. - fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'junction'); + FileSystem._wrapException(() => { + return FileSystem._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); + }); } /** - * Creates a symbolic link to a file (on Windows this requires elevated permissionsBits). + * An async version of {@link FileSystem.createSymbolicLinkJunction}. + */ + public static async createSymbolicLinkJunctionAsync(options: IFileSystemCreateLinkOptions): Promise { + await FileSystem._wrapExceptionAsync(() => { + return FileSystem._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); + }); + } + + /** + * Creates a symbolic link to a file. On Windows operating systems, this may require administrator elevation. * Behind the scenes it uses `fs.symlinkSync()`. + * + * @remarks + * To avoid administrator elevation on Windows, use {@link FileSystem.createHardLink} instead. + * + * On Windows operating systems, the NTFS file system distinguishes file symlinks versus directory symlinks: + * If the target is not the correct type, the symlink will be created successfully, but will fail to resolve. + * Other operating systems do not make this distinction, in which case {@link FileSystem.createSymbolicLinkFile} + * and {@link FileSystem.createSymbolicLinkFolder} can be used interchangeably, but doing so will make your + * tool incompatible with Windows. */ public static createSymbolicLinkFile(options: IFileSystemCreateLinkOptions): void { - fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'file'); + FileSystem._wrapException(() => { + return FileSystem._handleLink(() => { + return fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'file'); + }, options); + }); } /** - * Creates a symbolic link to a folder (on Windows this requires elevated permissionsBits). + * An async version of {@link FileSystem.createSymbolicLinkFile}. + */ + public static async createSymbolicLinkFileAsync(options: IFileSystemCreateLinkOptions): Promise { + await FileSystem._wrapExceptionAsync(() => { + return FileSystem._handleLinkAsync(() => { + return fsx.symlink(options.linkTargetPath, options.newLinkPath, 'file'); + }, options); + }); + } + + /** + * Creates a symbolic link to a folder. On Windows operating systems, this may require administrator elevation. * Behind the scenes it uses `fs.symlinkSync()`. + * + * @remarks + * To avoid administrator elevation on Windows, use {@link FileSystem.createSymbolicLinkJunction} instead. + * + * On Windows operating systems, the NTFS file system distinguishes file symlinks versus directory symlinks: + * If the target is not the correct type, the symlink will be created successfully, but will fail to resolve. + * Other operating systems do not make this distinction, in which case {@link FileSystem.createSymbolicLinkFile} + * and {@link FileSystem.createSymbolicLinkFolder} can be used interchangeably, but doing so will make your + * tool incompatible with Windows. */ public static createSymbolicLinkFolder(options: IFileSystemCreateLinkOptions): void { - fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'dir'); + FileSystem._wrapException(() => { + return FileSystem._handleLink(() => { + return fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'dir'); + }, options); + }); + } + + /** + * An async version of {@link FileSystem.createSymbolicLinkFolder}. + */ + public static async createSymbolicLinkFolderAsync(options: IFileSystemCreateLinkOptions): Promise { + await FileSystem._wrapExceptionAsync(() => { + return FileSystem._handleLinkAsync(() => { + return fsx.symlink(options.linkTargetPath, options.newLinkPath, 'dir'); + }, options); + }); } /** - * Creates a hard link. + * Creates a hard link. The link target must be a file, not a folder. * Behind the scenes it uses `fs.linkSync()`. + * + * @remarks + * For security reasons, Windows operating systems by default require administrator elevation to create + * symbolic links. As a result, on Windows it's generally recommended for Node.js tools to use hard links + * (for files) or NTFS directory junctions (for folders), since regular users are allowed to create them. + * Hard links and junctions are less vulnerable to symlink attacks because they cannot reference a network share, + * and their target must exist at the time of link creation. Non-Windows operating systems generally don't + * restrict symlink creation, and as such are more vulnerable to symlink attacks. Note that Windows can be + * configured to permit regular users to create symlinks, for example by enabling Windows 10 "developer mode." + * + * A hard link requires the link source and target to both be located on same disk volume; + * if not, use a symbolic link instead. */ public static createHardLink(options: IFileSystemCreateLinkOptions): void { - fsx.linkSync(options.linkTargetPath, options.newLinkPath); + FileSystem._wrapException(() => { + return FileSystem._handleLink( + () => { + return fsx.linkSync(options.linkTargetPath, options.newLinkPath); + }, + { ...options, linkTargetMustExist: true } + ); + }); + } + + /** + * An async version of {@link FileSystem.createHardLink}. + */ + public static async createHardLinkAsync(options: IFileSystemCreateLinkOptions): Promise { + await FileSystem._wrapExceptionAsync(() => { + return FileSystem._handleLinkAsync( + () => { + return fsx.link(options.linkTargetPath, options.newLinkPath); + }, + { ...options, linkTargetMustExist: true } + ); + }); } /** @@ -519,6 +1436,201 @@ export class FileSystem { * @param linkPath - The path to the link. */ public static getRealPath(linkPath: string): string { - return fsx.realpathSync(linkPath); + return FileSystem._wrapException(() => { + return fsx.realpathSync(linkPath); + }); + } + + /** + * An async version of {@link FileSystem.getRealPath}. + */ + public static async getRealPathAsync(linkPath: string): Promise { + return await FileSystem._wrapExceptionAsync(() => { + return fsx.realpath(linkPath); + }); + } + + // =============== + // UTILITY FUNCTIONS + // =============== + + /** + * Returns true if the error object indicates the file or folder already exists (`EEXIST`). + */ + public static isExistError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'EEXIST'; + } + + /** + * Returns true if the error object indicates the file or folder does not exist (`ENOENT` or `ENOTDIR`) + */ + public static isNotExistError(error: Error): boolean { + return FileSystem.isFileDoesNotExistError(error) || FileSystem.isFolderDoesNotExistError(error); + } + + /** + * Returns true if the error object indicates the file does not exist (`ENOENT`). + */ + public static isFileDoesNotExistError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'ENOENT'; + } + + /** + * Returns true if the error object indicates the folder does not exist (`ENOTDIR`). + */ + public static isFolderDoesNotExistError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'ENOTDIR'; + } + + /** + * Returns true if the error object indicates the target is a directory (`EISDIR`). + */ + public static isDirectoryError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'EISDIR'; + } + + /** + * Returns true if the error object indicates the target is not a directory (`ENOTDIR`). + */ + public static isNotDirectoryError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'ENOTDIR'; + } + + /** + * Returns true if the error object indicates that the `unlink` system call failed + * due to a permissions issue (`EPERM`). + */ + public static isUnlinkNotPermittedError(error: Error): boolean { + return FileSystem.isErrnoException(error) && error.code === 'EPERM' && error.syscall === 'unlink'; + } + + /** + * Detects if the provided error object is a `NodeJS.ErrnoException` + */ + 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.syscall === 'string' + ); + } + + private static _handleLink(linkFn: () => void, options: IInternalFileSystemCreateLinkOptions): void { + try { + 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)); + linkFn(); + } else { + throw error; + } + } + } + } + + private static async _handleLinkAsync( + linkFn: () => Promise, + options: IInternalFileSystemCreateLinkOptions + ): Promise { + try { + 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)); + await linkFn(); + } else { + throw error; + } + } + } + } + + private static _wrapException(fn: () => TResult): TResult { + try { + return fn(); + } catch (error) { + FileSystem._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; + } + } + + private static _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 cfbb1ef1715..70db42a79d4 100644 --- a/libraries/node-core-library/src/FileWriter.ts +++ b/libraries/node-core-library/src/FileWriter.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 fsx from 'fs-extra'; +import * as fs from 'node:fs'; + +import type { FileSystemStats } from './FileSystem'; /** * Available file handle opening flags. @@ -9,6 +11,20 @@ import * as fsx from 'fs-extra'; */ 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 @@ -36,10 +52,16 @@ export interface IFileWriterFlags { * @public */ export class FileWriter { + /** + * The `filePath` that was passed to {@link FileWriter.open}. + */ + public readonly filePath: string; + private _fileDescriptor: number | undefined; - private constructor(fileDescriptor: number) { + private constructor(fileDescriptor: number, filePath: string) { this._fileDescriptor = fileDescriptor; + this.filePath = filePath; } /** @@ -47,26 +69,11 @@ export class FileWriter { * Behind the scenes it uses `fs.openSync()`. * The behaviour of this function is platform specific. * See: https://nodejs.org/docs/latest-v8.x/api/fs.html#fs_fs_open_path_flags_mode_callback - * @param path - The absolute or relative path to the file handle that should be opened. + * @param filePath - The absolute or relative path to the file handle that should be opened. * @param flags - The flags for opening the handle */ - public static open(path: string, flags?: IFileWriterFlags): FileWriter { - return new FileWriter(fsx.openSync(path, FileWriter._convertFlagsForNode(flags))); - } - - /** - * 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; + public static open(filePath: string, flags?: IFileWriterFlags): FileWriter { + return new FileWriter(fs.openSync(filePath, convertFlagsForNode(flags)), filePath); } /** @@ -79,18 +86,33 @@ 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); } /** * Closes the file handle permanently. No operations can be made on this file handle after calling this. * Behind the scenes it uses `fs.closeSync()` and releases the file descriptor to be re-used. + * + * @remarks + * The `close()` method can be called more than once; additional calls are ignored. */ public close(): void { const fd: number | undefined = this._fileDescriptor; if (fd) { this._fileDescriptor = undefined; - fsx.closeSync(fd); + fs.closeSync(fd); } } -} \ No newline at end of file + + /** + * Gets the statistics for the given file handle. Throws if the file handle has been closed. + * Behind the scenes it uses `fs.statSync()`. + */ + public getStatistics(): FileSystemStats { + if (!this._fileDescriptor) { + throw new Error(`Cannot get file statistics, file descriptor has already been released.`); + } + + return fs.fstatSync(this._fileDescriptor); + } +} diff --git a/libraries/node-core-library/src/IPackageJson.ts b/libraries/node-core-library/src/IPackageJson.ts index 34021606b06..74d2c062439 100644 --- a/libraries/node-core-library/src/IPackageJson.ts +++ b/libraries/node-core-library/src/IPackageJson.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. /** - * This interface is part of the IPackageJson file format. It is used for the + * This interface is part of the {@link IPackageJson} file format. It is used for the * "dependencies", "optionalDependencies", and "devDependencies" fields. * @public */ @@ -15,7 +15,7 @@ export interface IPackageJsonDependencyTable { } /** - * This interface is part of the IPackageJson file format. It is used for the + * This interface is part of the {@link IPackageJson} file format. It is used for the * "scripts" field. * @public */ @@ -27,6 +27,113 @@ export interface IPackageJsonScriptTable { [scriptName: string]: string; } +/** + * This interface is part of the {@link IPackageJson} file format. It is used for the + * "repository" field. + * @public + */ +export interface IPackageJsonRepository { + /** + * The source control type for the repository that hosts the project. This is typically "git". + */ + type: string; + + /** + * The URL of the repository that hosts the project. + */ + url: string; + + /** + * If the project does not exist at the root of the repository, its path is specified here. + */ + directory?: string; +} + +/** + * This interface is part of the {@link IPackageJson} file format. It is used for the + * "peerDependenciesMeta" field. + * @public + */ +export interface IPeerDependenciesMetaTable { + [dependencyName: string]: { + optional?: boolean; + }; +} + +/** + * This interface is part of the {@link IPackageJson} file format. It is used for the + * "dependenciesMeta" field. + * @public + */ +export interface IDependenciesMetaTable { + [dependencyName: string]: { + injected?: boolean; + }; +} + +/** + * This interface is part of the {@link IPackageJson} file format. It is used for the values + * of the "exports" field. + * + * See {@link https://nodejs.org/api/packages.html#conditional-exports | Node.js documentation on Conditional Exports} and + * {@link https://nodejs.org/api/packages.html#community-conditions-definitions | Node.js documentation on Community Conditional Exports}. + * + * @public + */ +export interface IPackageJsonExports { + /** + * This export is like {@link IPackageJsonExports.node} in that it matches for any NodeJS environment. + * This export is specifically for native C++ addons. + */ + 'node-addons'?: string | IPackageJsonExports; + + /** + * This export matches for any NodeJS environment. + */ + node?: string | IPackageJsonExports; + + /** + * This export matches when loaded via ESM syntax (i.e. - `import '...'` or `import('...')`). + * This is always mutually exclusive with {@link IPackageJsonExports.require}. + */ + import?: string | IPackageJsonExports; + + /** + * This export matches when loaded via `require()`. + * This is always mutually exclusive with {@link IPackageJsonExports.import}. + */ + require?: string | IPackageJsonExports; + + /** + * This export matches as a fallback when no other conditions match. Because exports are evaluated in + * the order that they are specified in the `package.json` file, this condition should always come last + * as no later exports will match if this one does. + */ + default?: string | IPackageJsonExports; + + /** + * This export matches when loaded by the typing system (i.e. - the TypeScript compiler). + */ + types?: string | IPackageJsonExports; + + /** + * Any web browser environment. + */ + browser?: string | IPackageJsonExports; + + /** + * This export matches in development-only environments. + * This is always mutually exclusive with {@link IPackageJsonExports.production}. + */ + development?: string | IPackageJsonExports; + + /** + * This export matches in production-only environments. + * This is always mutually exclusive with {@link IPackageJsonExports.development}. + */ + production?: string | IPackageJsonExports; +} + /** * An interface for accessing common fields from a package.json file whose version field may be missing. * @@ -38,16 +145,16 @@ export interface IPackageJsonScriptTable { * * However, NodeJS relaxes this requirement for its `require()` API. The * {@link https://nodejs.org/dist/latest-v10.x/docs/api/modules.html#modules_folders_as_modules - * | "Folders as Modules" section} from the NodeJS documentation gives an example of a package.json file - * that has only the `name` and `main` fields. NodeJS does not consider the `version` field during resolution, - * so it can be omitted. Some libraries do this. - * - * Use the `INodePackageJson` interface when loading such files. Use `IPackageJson` for package.json files - * that are installed from an NPM registry, or are otherwise known to have a `version` field. - * - * @public - */ - export interface INodePackageJson { + * | "Folders as Modules" section} from the NodeJS documentation gives an example of a package.json file + * that has only the `name` and `main` fields. NodeJS does not consider the `version` field during resolution, + * so it can be omitted. Some libraries do this. + * + * Use the `INodePackageJson` interface when loading such files. Use `IPackageJson` for package.json files + * that are installed from an NPM registry, or are otherwise known to have a `version` field. + * + * @public + */ +export interface INodePackageJson { /** * The name of the package. */ @@ -71,7 +178,7 @@ export interface IPackageJsonScriptTable { /** * The URL of the project's repository. */ - repository?: string; + repository?: string | IPackageJsonRepository; /** * The URL to the project's web page. @@ -109,7 +216,7 @@ export interface IPackageJsonScriptTable { /** * The main entry point for the package. */ - bin?: string; + bin?: string | Record; /** * An array of dependencies that must always be installed for this package. @@ -133,10 +240,81 @@ export interface IPackageJsonScriptTable { */ peerDependencies?: IPackageJsonDependencyTable; + /** + * An array of metadata for dependencies declared inside dependencies, optionalDependencies, and devDependencies. + * https://pnpm.io/package_json#dependenciesmeta + */ + dependenciesMeta?: IDependenciesMetaTable; + + /** + * An array of metadata about peer dependencies. + */ + peerDependenciesMeta?: IPeerDependenciesMetaTable; + /** * A table of script hooks that a package manager or build tool may invoke. */ scripts?: IPackageJsonScriptTable; + + /** + * A table of package version resolutions. This feature is only implemented by the Yarn package manager. + * + * @remarks + * See the {@link https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-selective-versions-resolutions.md + * | 0000-selective-versions-resolutions.md RFC} for details. + */ + resolutions?: Record; + + /** + * A table of TypeScript *.d.ts file paths that are compatible with specific TypeScript version + * selectors. This data take a form similar to that of the {@link INodePackageJson.exports} field, + * with fallbacks listed in order in the value array for example: + * + * ```JSON + * "typesVersions": { + * ">=3.1": { + * "*": ["./types-3.1/*", "./types-3.1-fallback/*"] + * }, + * ">=3.0": { + * "*": ["./types-legacy/*"] + * } + * } + * ``` + * + * or + * + * ```JSON + * "typesVersions": { + * ">=3.1": { + * "app/*": ["./app/types-3.1/*"], + * "lib/*": ["./lib/types-3.1/*"] + * }, + * ">=3.0": { + * "app/*": ["./app/types-legacy/*"], + * "lib/*": ["./lib/types-legacy/*"] + * } + * } + * ``` + * + * See the + * {@link https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#version-selection-with-typesversions + * | TypeScript documentation} for details. + */ + typesVersions?: Record>; + + /** + * The "exports" field is used to specify the entry points for a package. + * See {@link https://nodejs.org/api/packages.html#exports | Node.js documentation} + */ + // eslint-disable-next-line @rushstack/no-new-null + exports?: string | string[] | Record; + + /** + * The "files" field is an array of file globs that should be included in the package during publishing. + * + * See the {@link https://docs.npmjs.com/cli/v6/configuring-npm/package-json#files | NPM documentation}. + */ + files?: string[]; } /** diff --git a/libraries/node-core-library/src/Import.ts b/libraries/node-core-library/src/Import.ts new file mode 100644 index 00000000000..c794fc8500f --- /dev/null +++ b/libraries/node-core-library/src/Import.ts @@ -0,0 +1,560 @@ +// 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 nodeModule = require('module'); + +import importLazy = require('import-lazy'); +import * as Resolve from 'resolve'; + +import { PackageJsonLookup } from './PackageJsonLookup'; +import { FileSystem } from './FileSystem'; +import type { IPackageJson } from './IPackageJson'; +import { PackageName } from './PackageName'; + +type RealpathFnType = Parameters[1]['realpath']; + +/** + * Common options shared by {@link IImportResolveModuleOptions} and {@link IImportResolvePackageOptions} + * @public + */ +export interface IImportResolveOptions { + /** + * The path from which {@link IImportResolveModuleOptions.modulePath} or + * {@link IImportResolvePackageOptions.packageName} should be resolved. + */ + baseFolderPath: string; + + /** + * If true, if the package name matches a Node.js system module, then the return + * value will be the package name without any path. + * + * @remarks + * This will take precedence over an installed NPM package of the same name. + * + * Example: + * ```ts + * // Returns the string "fs" indicating the Node.js system module + * Import.resolveModulePath({ + * resolvePath: "fs", + * basePath: process.cwd() + * }) + * ``` + */ + includeSystemModules?: boolean; + + /** + * If true, then resolvePath is allowed to refer to the package.json of the active project. + * + * @remarks + * This will take precedence over any installed dependency with the same name. + * Note that this requires an additional PackageJsonLookup calculation. + * + * Example: + * ```ts + * // Returns an absolute path to the current package + * Import.resolveModulePath({ + * resolvePath: "current-project", + * basePath: process.cwd(), + * allowSelfReference: true + * }) + * ``` + */ + allowSelfReference?: boolean; + + /** + * A function used to resolve the realpath of a provided file path. + * + * @remarks + * This is used to resolve symlinks and other non-standard file paths. By default, this uses the + * {@link FileSystem.getRealPath} function. However, it can be overridden to use a custom implementation + * which may be faster, more accurate, or provide support for additional non-standard file paths. + */ + getRealPath?: (filePath: string) => string; +} + +/** + * Common options shared by {@link IImportResolveModuleAsyncOptions} and {@link IImportResolvePackageAsyncOptions} + * @public + */ +export interface IImportResolveAsyncOptions extends IImportResolveOptions { + /** + * A function used to resolve the realpath of a provided file path. + * + * @remarks + * This is used to resolve symlinks and other non-standard file paths. By default, this uses the + * {@link FileSystem.getRealPath} function. However, it can be overridden to use a custom implementation + * which may be faster, more accurate, or provide support for additional non-standard file paths. + */ + getRealPathAsync?: (filePath: string) => Promise; +} + +/** + * Options for {@link Import.resolveModule} + * @public + */ +export interface IImportResolveModuleOptions extends IImportResolveOptions { + /** + * The module identifier to resolve. For example "\@rushstack/node-core-library" or + * "\@rushstack/node-core-library/lib/index.js" + */ + modulePath: string; +} + +/** + * Options for {@link Import.resolveModuleAsync} + * @public + */ +export interface IImportResolveModuleAsyncOptions extends IImportResolveAsyncOptions { + /** + * The module identifier to resolve. For example "\@rushstack/node-core-library" or + * "\@rushstack/node-core-library/lib/index.js" + */ + modulePath: string; +} + +/** + * Options for {@link Import.resolvePackage} + * @public + */ +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; +} + +/** + * Options for {@link Import.resolvePackageAsync} + * @public + */ +export interface IImportResolvePackageAsyncOptions extends IImportResolveAsyncOptions { + /** + * The package name to resolve. For example "\@rushstack/node-core-library" + */ + packageName: string; +} + +interface IPackageDescriptor { + packageRootPath: string; + packageName: string; +} + +/** + * 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. + * + * @remarks + * This is a more structured wrapper for the {@link https://www.npmjs.com/package/import-lazy|import-lazy} + * package. It enables you to replace an import like this: + * + * ```ts + * import * as example from 'example'; // <-- 100ms load time + * + * if (condition) { + * example.doSomething(); + * } + * ``` + * + * ...with a pattern like this: + * + * ```ts + * const example: typeof import('example') = Import.lazy('example', require); + * + * if (condition) { + * example.doSomething(); // <-- 100ms load time occurs here, only if needed + * } + * ``` + * + * The implementation relies on JavaScript's `Proxy` feature to intercept access to object members. Thus + * it will only work correctly with certain types of module exports. If a particular export isn't well behaved, + * you may need to find (or introduce) some other module in your dependency graph to apply the optimization to. + * + * Usage guidelines: + * + * - Always specify types using `typeof` as shown above. + * + * - Never apply lazy-loading in a way that would convert the module's type to `any`. Losing type safety + * seriously impacts the maintainability of the code base. + * + * - In cases where the non-runtime types are needed, import them separately using the `Types` suffix: + * + * ```ts + * const example: typeof import('example') = Import.lazy('example', require); + * import type * as exampleTypes from 'example'; + * ``` + * + * - If the imported module confusingly has the same name as its export, then use the Module suffix: + * + * ```ts + * const exampleModule: typeof import('../../logic/Example') = Import.lazy( + * '../../logic/Example', require); + * import type * as exampleTypes from '../../logic/Example'; + * ``` + * + * - If the exports cause a lot of awkwardness (e.g. too many expressions need to have `exampleModule.` inserted + * into them), or if some exports cannot be proxied (e.g. `Import.lazy('example', require)` returns a function + * signature), then do not lazy-load that module. Instead, apply lazy-loading to some other module which is + * better behaved. + * + * - It's recommended to sort imports in a standard ordering: + * + * ```ts + * // 1. external imports + * import * as path from 'path'; + * import { Import, JsonFile, JsonObject } from '@rushstack/node-core-library'; + * + * // 2. local imports + * import { LocalFile } from './path/LocalFile'; + * + * // 3. lazy-imports (which are technically variables, not imports) + * const semver: typeof import('semver') = Import.lazy('semver', require); + * ``` + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public static lazy(moduleName: string, require: (id: string) => unknown): any { + const importLazyLocal: (moduleName: string) => unknown = importLazy(require); + return importLazyLocal(moduleName); + } + + /** + * This resolves a module path using similar logic as the Node.js `require.resolve()` API, + * but supporting extra features such as specifying the base folder. + * + * @remarks + * A module path is a text string that might appear in a statement such as + * `import { X } from "____";` or `const x = require("___");`. The implementation is based + * on the popular `resolve` NPM package. + * + * Suppose `example` is an NPM package whose entry point is `lib/index.js`: + * ```ts + * // Returns "/path/to/project/node_modules/example/lib/index.js" + * Import.resolveModule({ modulePath: 'example' }); + * + * // Returns "/path/to/project/node_modules/example/lib/other.js" + * Import.resolveModule({ modulePath: 'example/lib/other' }); + * ``` + * If you need to determine the containing package folder + * (`/path/to/project/node_modules/example`), use {@link Import.resolvePackage} instead. + * + * @returns the absolute path of the resolved module. + * If {@link IImportResolveOptions.includeSystemModules} is specified + * and a system module is found, then its name is returned without any file path. + */ + public static resolveModule(options: IImportResolveModuleOptions): string { + const { modulePath, baseFolderPath, includeSystemModules, allowSelfReference, getRealPath } = options; + + if (path.isAbsolute(modulePath)) { + return modulePath; + } + + const normalizedRootPath: string = (getRealPath || FileSystem.getRealPath)(baseFolderPath); + + if (modulePath.startsWith('.')) { + // This looks like a conventional relative path + return path.resolve(normalizedRootPath, modulePath); + } + + // Built-in modules do not have a scope, so if there is a slash, then we need to check + // 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)) { + throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}".`); + } + + if (allowSelfReference === true) { + const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + if ( + ownPackage && + (modulePath === ownPackage.packageName || modulePath.startsWith(`${ownPackage.packageName}/`)) + ) { + const packagePath: string = modulePath.slice(ownPackage.packageName.length + 1); + return path.resolve(ownPackage.packageRootPath, packagePath); + } + } + + try { + return Resolve.sync(modulePath, { + basedir: normalizedRootPath, + preserveSymlinks: false, + realpathSync: getRealPath + }); + } catch (e: unknown) { + throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}": ${e}`); + } + } + + /** + * Async version of {@link Import.resolveModule}. + */ + public static async resolveModuleAsync(options: IImportResolveModuleAsyncOptions): Promise { + const { + modulePath, + baseFolderPath, + includeSystemModules, + allowSelfReference, + getRealPath, + getRealPathAsync + } = options; + + if (path.isAbsolute(modulePath)) { + return modulePath; + } + + const normalizedRootPath: string = await (getRealPathAsync || getRealPath || FileSystem.getRealPathAsync)( + baseFolderPath + ); + + if (modulePath.startsWith('.')) { + // This looks like a conventional relative path + return path.resolve(normalizedRootPath, modulePath); + } + + // Built-in modules do not have a scope, so if there is a slash, then we need to check + // 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)) { + throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}".`); + } + + if (allowSelfReference === true) { + const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + if ( + ownPackage && + (modulePath === ownPackage.packageName || modulePath.startsWith(`${ownPackage.packageName}/`)) + ) { + const packagePath: string = modulePath.slice(ownPackage.packageName.length + 1); + return path.resolve(ownPackage.packageRootPath, packagePath); + } + } + + try { + const resolvePromise: Promise = new Promise( + (resolve: (resolvedPath: string) => void, reject: (error: Error) => void) => { + const realPathFn: RealpathFnType = + getRealPathAsync || getRealPath + ? (filePath: string, callback: (error: Error | null, resolvedPath?: string) => void) => { + if (getRealPathAsync) { + getRealPathAsync(filePath) + .then((resolvedPath) => callback(null, resolvedPath)) + .catch((error) => callback(error)); + } else { + try { + const resolvedPath: string = getRealPath!(filePath); + callback(null, resolvedPath); + } catch (error: unknown) { + callback(error as Error); + } + } + } + : undefined; + + Resolve.default( + modulePath, + { + basedir: normalizedRootPath, + preserveSymlinks: false, + realpath: realPathFn + }, + (error: Error | null, resolvedPath?: string) => { + if (error) { + reject(error); + } else { + // Resolve docs state that either an error will be returned, or the resolved path. + // In this case, the resolved path should always be populated. + resolve(resolvedPath!); + } + } + ); + } + ); + return await resolvePromise; + } catch (e: unknown) { + throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}": ${e}`); + } + } + + /** + * Performs module resolution to determine the folder where a package is installed. + * + * @remarks + * Suppose `example` is an NPM package whose entry point is `lib/index.js`: + * ```ts + * // Returns "/path/to/project/node_modules/example" + * Import.resolvePackage({ packageName: 'example' }); + * ``` + * + * If you need to resolve a module path, use {@link Import.resolveModule} instead: + * ```ts + * // Returns "/path/to/project/node_modules/example/lib/index.js" + * Import.resolveModule({ modulePath: 'example' }); + * ``` + * + * @returns the absolute path of the package folder. + * If {@link IImportResolveOptions.includeSystemModules} is specified + * 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, + useNodeJSResolver + } = options; + + if (includeSystemModules && Import._builtInModules.has(packageName)) { + return packageName; + } + + const normalizedRootPath: string = (getRealPath || FileSystem.getRealPath)(baseFolderPath); + + if (allowSelfReference) { + const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + if (ownPackage && ownPackage.packageName === packageName) { + return ownPackage.packageRootPath; + } + } + + PackageName.parse(packageName); // Ensure the package name is valid and doesn't contain a path + + try { + 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; + } catch (e: unknown) { + throw new Error(`Cannot find package "${packageName}" from "${baseFolderPath}": ${e}.`); + } + } + + /** + * Async version of {@link Import.resolvePackage}. + */ + public static async resolvePackageAsync(options: IImportResolvePackageAsyncOptions): Promise { + const { + packageName, + includeSystemModules, + baseFolderPath, + allowSelfReference, + getRealPath, + getRealPathAsync + } = options; + + if (includeSystemModules && Import._builtInModules.has(packageName)) { + return packageName; + } + + const normalizedRootPath: string = await (getRealPathAsync || getRealPath || FileSystem.getRealPathAsync)( + baseFolderPath + ); + + if (allowSelfReference) { + const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + if (ownPackage && ownPackage.packageName === packageName) { + return ownPackage.packageRootPath; + } + } + + PackageName.parse(packageName); // Ensure the package name is valid and doesn't contain a path + + try { + const resolvePromise: Promise = new Promise( + (resolve: (resolvedPath: string) => void, reject: (error: Error) => void) => { + const realPathFn: RealpathFnType = + getRealPathAsync || getRealPath + ? (filePath: string, callback: (error: Error | null, resolvedPath?: string) => void) => { + if (getRealPathAsync) { + getRealPathAsync(filePath) + .then((resolvedPath) => callback(null, resolvedPath)) + .catch((error) => callback(error)); + } else { + try { + const resolvedPath: string = getRealPath!(filePath); + callback(null, resolvedPath); + } catch (error: unknown) { + callback(error as Error); + } + } + } + : undefined; + + Resolve.default( + // 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, + realpath: realPathFn + }, + (error: Error | null, resolvedPath?: string) => { + if (error) { + reject(error); + } else { + // Resolve docs state that either an error will be returned, or the resolved path. + // In this case, the resolved path should always be populated. + resolve(resolvedPath!); + } + } + ); + } + ); + const resolvedPath: string = await resolvePromise; + + const packagePath: string = path.dirname(resolvedPath); + return packagePath; + } catch (e: unknown) { + 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; + } + } +} diff --git a/libraries/node-core-library/src/InternalError.ts b/libraries/node-core-library/src/InternalError.ts index c1bb063c4e8..8fb67df1979 100644 --- a/libraries/node-core-library/src/InternalError.ts +++ b/libraries/node-core-library/src/InternalError.ts @@ -37,7 +37,7 @@ export class InternalError extends Error { super(InternalError._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/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work + // https://github.com/microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work // // Note: the prototype must also be set on any classes which extend this one (this as any).__proto__ = InternalError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any @@ -51,8 +51,10 @@ 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.`; + return ( + `Internal Error: ${unformattedMessage}\n\nYou have encountered a software defect. Please consider` + + ` reporting the issue to the maintainers of this application.` + ); } /** @override */ diff --git a/libraries/node-core-library/src/JsonFile.ts b/libraries/node-core-library/src/JsonFile.ts index 749c61d61c3..21f55b6fc2c 100644 --- a/libraries/node-core-library/src/JsonFile.ts +++ b/libraries/node-core-library/src/JsonFile.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 os from 'node:os'; + import * as jju from 'jju'; -import { JsonSchema, IJsonSchemaErrorInfo, IJsonSchemaValidateOptions } from './JsonSchema'; -import { Text, NewlineKind } from './Text'; +import type { JsonSchema, IJsonSchemaErrorInfo, IJsonSchemaValidateOptions } from './JsonSchema'; +import { Text, type NewlineKind } from './Text'; import { FileSystem } from './FileSystem'; /** @@ -21,25 +22,156 @@ import { FileSystem } from './FileSystem'; export type JsonObject = any; /** - * Options for JsonFile.stringify() + * The Rush Stack lint rules discourage usage of `null`. However, JSON parsers always return JavaScript's + * `null` to keep the two syntaxes consistent. When creating interfaces that describe JSON structures, + * use `JsonNull` to avoid triggering the lint rule. Do not use `JsonNull` for any other purpose. + * + * @remarks + * If you are designing a new JSON file format, it's a good idea to avoid `null` entirely. In most cases + * there are better representations that convey more information about an item that is unknown, omitted, or disabled. + * + * To understand why `null` is deprecated, please see the `@rushstack/eslint-plugin` documentation here: + * + * {@link https://www.npmjs.com/package/@rushstack/eslint-plugin#rushstackno-null} + * + * @public + */ +// eslint-disable-next-line @rushstack/no-new-null +export type JsonNull = null; + +/** + * Specifies the variant of JSON syntax to be used. + * + * @public + */ +export enum JsonSyntax { + /** + * Specifies the exact RFC 8259 format as implemented by the `JSON.parse()` system API. + * This format was designed for machine generated inputs such as an HTTP payload. + * It is not a recommend choice for human-authored files, because it does not support + * code comments. + * + * @remarks + * + * A well-known quote from Douglas Crockford, the inventor of JSON: + * + * "I removed comments from JSON because I saw people were using them to hold parsing directives, + * a practice which would have destroyed interoperability. I know that the lack of comments makes + * some people sad, but it shouldn't. Suppose you are using JSON to keep configuration files, + * which you would like to annotate. Go ahead and insert all the comments you like. + * Then pipe it through JSMin before handing it to your JSON parser." + * + * @see {@link https://datatracker.ietf.org/doc/html/rfc8259 | RFC 8259} + */ + Strict = 'strict', + + /** + * `JsonSyntax.JsonWithComments` is the recommended format for human-authored config files. + * It is a minimal extension to `JsonSyntax.Strict` adding support for code comments + * using `//` and `/*`. + * + * @remarks + * + * VS Code calls this format `jsonc`, but it should not be confused with unrelated file formats + * and libraries that also use the name "JSONC". + * + * To fix VS Code syntax highlighting, add this setting: + * `"files.associations": { "*.json": "jsonc" }` + * + * To fix GitHub syntax highlighting, add this to your `.gitattributes`: + * `*.json linguist-language=JSON-with-Comments` + */ + JsonWithComments = 'jsonWithComments', + + /** + * JSON5 is a project that proposes a JSON-like format supplemented with ECMAScript 5.1 + * notations for objects, numbers, comments, and more. + * + * @remarks + * Files using this format should use the `.json5` file extension instead of `.json`. + * + * JSON5 has substantial differences from JSON: object keys may be unquoted, trailing commas + * are allowed, and strings may span multiple lines. Whereas {@link JsonSyntax.JsonWithComments} can + * be cheaply converted to standard JSON by stripping comments, parsing JSON5 requires a + * nontrivial algorithm that may not be easily available in some contexts or programming languages. + * + * @see {@link https://json5.org/ | JSON5 project website} + */ + Json5 = 'json5' +} + +/** + * Options for {@link JsonFile.parseString}, {@link JsonFile.load}, and {@link JsonFile.loadAsync}. + * + * @public + */ +export interface IJsonFileParseOptions { + /** + * Specifies the variant of JSON syntax to be used. + * + * @defaultValue + * {@link JsonSyntax.Json5} + * + * NOTE: This default will be changed to `JsonSyntax.JsonWithComments` in a future release. + */ + jsonSyntax?: JsonSyntax; +} + +/** + * Options for {@link JsonFile.loadAndValidate} and {@link JsonFile.loadAndValidateAsync} * * @public */ -export interface IJsonFileStringifyOptions { +export interface IJsonFileLoadAndValidateOptions extends IJsonFileParseOptions, IJsonSchemaValidateOptions {} + +/** + * Options for {@link JsonFile.stringify} + * + * @public + */ +export interface IJsonFileStringifyOptions extends IJsonFileParseOptions { /** * If provided, the specified newline type will be used instead of the default `\r\n`. */ newlineConversion?: NewlineKind; + /** + * By default, {@link JsonFile.stringify} validates that the object does not contain any + * keys whose value is `undefined`. To disable this validation, set + * {@link IJsonFileStringifyOptions.ignoreUndefinedValues} to `true` + * which causes such keys to be silently discarded, consistent with the system `JSON.stringify()`. + * + * @remarks + * + * The JSON file format can represent `null` values ({@link JsonNull}) but not `undefined` values. + * In ECMAScript code however, we generally avoid `null` and always represent empty states + * as `undefined`, because it is the default value of missing/uninitialized variables. + * (In practice, distinguishing "null" versus "uninitialized" has more drawbacks than benefits.) + * This poses a problem when serializing ECMAScript objects that contain `undefined` members. + * As a safeguard, {@link JsonFile} will report an error if any `undefined` values are encountered + * during serialization. Set {@link IJsonFileStringifyOptions.ignoreUndefinedValues} to `true` + * to disable this safeguard. + */ + ignoreUndefinedValues?: boolean; + /** * If true, then the "jju" library will be used to improve the text formatting. * Note that this is slightly slower than the native JSON.stringify() implementation. */ prettyFormatting?: boolean; + + /** + * If specified, this header will be prepended to the start of the file. The header must consist + * of lines prefixed by "//" characters. + * @remarks + * When used with {@link IJsonFileSaveOptions.updateExistingFile} + * or {@link JsonFile.updateString}, the header will ONLY be added for a newly created file. + */ + headerComment?: string; } /** - * Options for JsonFile.saveJsonFile() + * Options for {@link JsonFile.save} and {@link JsonFile.saveAsync}. * * @public */ @@ -65,34 +197,91 @@ export interface IJsonFileSaveOptions extends IJsonFileStringifyOptions { updateExistingFile?: boolean; } +const DEFAULT_ENCODING: 'utf8' = 'utf8'; + /** * Utilities for reading/writing JSON files. * @public */ export class JsonFile { + /** + * @internal + */ + public static _formatPathForError: (path: string) => string = (path: string) => path; + /** * Loads a JSON file. */ - public static load(jsonFilename: string): JsonObject { - if (!FileSystem.exists(jsonFilename)) { - throw new Error(`Input file not found: ${jsonFilename}`); + public static load(jsonFilename: string, options?: IJsonFileParseOptions): JsonObject { + try { + const contents: string = FileSystem.readFile(jsonFilename); + const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + return jju.parse(contents, parseOptions); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + throw error; + } else { + throw new Error( + `Error reading "${JsonFile._formatPathForError(jsonFilename)}":` + + os.EOL + + ` ${(error as Error).message}` + ); + } } + } - const contents: string = FileSystem.readFile(jsonFilename); + /** + * An async version of {@link JsonFile.load}. + */ + public static async loadAsync(jsonFilename: string, options?: IJsonFileParseOptions): Promise { try { - return jju.parse(contents); + const contents: string = await FileSystem.readFileAsync(jsonFilename); + const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + return jju.parse(contents, parseOptions); } catch (error) { - throw new Error(`Error reading "${jsonFilename}":` + os.EOL + ` ${error.message}`); + if (FileSystem.isNotExistError(error as Error)) { + throw error; + } else { + throw new Error( + `Error reading "${JsonFile._formatPathForError(jsonFilename)}":` + + os.EOL + + ` ${(error as Error).message}` + ); + } } } + /** + * Parses a JSON file's contents. + */ + public static parseString(jsonContents: string, options?: IJsonFileParseOptions): JsonObject { + const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + return jju.parse(jsonContents, parseOptions); + } + /** * Loads a JSON file and validate its schema. */ - public static loadAndValidate(jsonFilename: string, jsonSchema: JsonSchema, - options?: IJsonSchemaValidateOptions): JsonObject { + public static loadAndValidate( + jsonFilename: string, + jsonSchema: JsonSchema, + options?: IJsonFileLoadAndValidateOptions + ): JsonObject { + const jsonObject: JsonObject = JsonFile.load(jsonFilename, options); + jsonSchema.validateObject(jsonObject, jsonFilename, options); - const jsonObject: JsonObject = JsonFile.load(jsonFilename); + return jsonObject; + } + + /** + * An async version of {@link JsonFile.loadAndValidate}. + */ + public static async loadAndValidateAsync( + jsonFilename: string, + jsonSchema: JsonSchema, + options?: IJsonFileLoadAndValidateOptions + ): Promise { + const jsonObject: JsonObject = await JsonFile.loadAsync(jsonFilename, options); jsonSchema.validateObject(jsonObject, jsonFilename, options); return jsonObject; @@ -103,10 +292,28 @@ export class JsonFile { * @remarks * See JsonSchema.validateObjectWithCallback() for more info. */ - public static loadAndValidateWithCallback(jsonFilename: string, jsonSchema: JsonSchema, - errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void): JsonObject { + public static loadAndValidateWithCallback( + jsonFilename: string, + jsonSchema: JsonSchema, + errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, + options?: IJsonFileLoadAndValidateOptions + ): JsonObject { + const jsonObject: JsonObject = JsonFile.load(jsonFilename, options); + jsonSchema.validateObjectWithCallback(jsonObject, errorCallback); + + return jsonObject; + } - const jsonObject: JsonObject = JsonFile.load(jsonFilename); + /** + * An async version of {@link JsonFile.loadAndValidateWithCallback}. + */ + public static async loadAndValidateWithCallbackAsync( + jsonFilename: string, + jsonSchema: JsonSchema, + errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, + options?: IJsonFileLoadAndValidateOptions + ): Promise { + const jsonObject: JsonObject = await JsonFile.loadAsync(jsonFilename, options); jsonSchema.validateObjectWithCallback(jsonObject, errorCallback); return jsonObject; @@ -124,39 +331,63 @@ export class JsonFile { /** * Serializes the specified JSON object to a string buffer. - * @param jsonObject - the object to be serialized + * @param previousJson - the previous JSON string, which will be updated + * @param newJsonObject - the object to be serialized * @param options - other settings that control serialization * @returns a JSON string, with newlines, and indented with two spaces */ - public static updateString(previousJson: string, newJsonObject: JsonObject, - options?: IJsonFileStringifyOptions): string { - if (!options) { - options = { }; + public static updateString( + previousJson: string, + newJsonObject: JsonObject, + options: IJsonFileStringifyOptions = {} + ): string { + if (!options.ignoreUndefinedValues) { + // Standard handling of `undefined` in JSON stringification is to discard the key. + JsonFile.validateNoUndefinedMembers(newJsonObject); } - JsonFile.validateNoUndefinedMembers(newJsonObject); + let explicitMode: 'json5' | 'json' | 'cjson' | undefined = undefined; + switch (options.jsonSyntax) { + case JsonSyntax.Strict: + explicitMode = 'json'; + break; + case JsonSyntax.JsonWithComments: + explicitMode = 'cjson'; + break; + case JsonSyntax.Json5: + explicitMode = 'json5'; + break; + } let stringified: string; if (previousJson !== '') { // NOTE: We don't use mode=json here because comments aren't allowed by strict JSON stringified = jju.update(previousJson, newJsonObject, { - mode: 'cjson', + mode: explicitMode ?? JsonSyntax.Json5, indent: 2 }); } else if (options.prettyFormatting) { stringified = jju.stringify(newJsonObject, { - mode: 'json', + mode: explicitMode ?? 'json', indent: 2 }); + + if (options.headerComment !== undefined) { + stringified = JsonFile._formatJsonHeaderComment(options.headerComment) + stringified; + } } else { stringified = JSON.stringify(newJsonObject, undefined, 2); + + if (options.headerComment !== undefined) { + stringified = JsonFile._formatJsonHeaderComment(options.headerComment) + stringified; + } } // Add the trailing newline stringified = Text.ensureTrailingNewline(stringified); - if (options && options.newlineConversion) { + if (options.newlineConversion) { stringified = Text.convertTo(stringified, options.newlineConversion); } @@ -170,32 +401,85 @@ export class JsonFile { * @param options - other settings that control how the file is saved * @returns false if ISaveJsonFileOptions.onlyIfChanged didn't save anything; true otherwise */ - public static save(jsonObject: JsonObject, jsonFilename: string, options?: IJsonFileSaveOptions): boolean { - if (!options) { - options = { }; + public static save( + jsonObject: JsonObject, + jsonFilename: string, + options: IJsonFileSaveOptions = {} + ): boolean { + // Do we need to read the previous file contents? + let oldBuffer: Buffer | undefined = undefined; + if (options.updateExistingFile || options.onlyIfChanged) { + try { + oldBuffer = FileSystem.readFileToBuffer(jsonFilename); + } catch (error) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + } + } + + let jsonToUpdate: string = ''; + if (options.updateExistingFile && oldBuffer) { + jsonToUpdate = oldBuffer.toString(DEFAULT_ENCODING); } + const newJson: string = JsonFile.updateString(jsonToUpdate, jsonObject, options); + + const newBuffer: Buffer = Buffer.from(newJson, DEFAULT_ENCODING); + + if (options.onlyIfChanged) { + // Has the file changed? + if (oldBuffer && Buffer.compare(newBuffer, oldBuffer) === 0) { + // Nothing has changed, so don't touch the file + return false; + } + } + + FileSystem.writeFile(jsonFilename, newBuffer, { + ensureFolderExists: options.ensureFolderExists + }); + + // TEST CODE: Used to verify that onlyIfChanged isn't broken by a hidden transformation during saving. + /* + const oldBuffer2: Buffer = FileSystem.readFileToBuffer(jsonFilename); + if (Buffer.compare(buffer, oldBuffer2) !== 0) { + console.log('new:' + buffer.toString('hex')); + console.log('old:' + oldBuffer2.toString('hex')); + + throw new Error('onlyIfChanged logic is broken'); + } + */ + return true; + } + + /** + * An async version of {@link JsonFile.save}. + */ + public static async saveAsync( + jsonObject: JsonObject, + jsonFilename: string, + options: IJsonFileSaveOptions = {} + ): Promise { // Do we need to read the previous file contents? let oldBuffer: Buffer | undefined = undefined; if (options.updateExistingFile || options.onlyIfChanged) { - if (FileSystem.exists(jsonFilename)) { - try { - oldBuffer = FileSystem.readFileToBuffer(jsonFilename); - } catch (error) { - // Ignore this error, and try writing a new file. If that fails, then we should report that - // error instead. + try { + oldBuffer = await FileSystem.readFileToBufferAsync(jsonFilename); + } catch (error) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; } } } let jsonToUpdate: string = ''; if (options.updateExistingFile && oldBuffer) { - jsonToUpdate = oldBuffer.toString(); + jsonToUpdate = oldBuffer.toString(DEFAULT_ENCODING); } const newJson: string = JsonFile.updateString(jsonToUpdate, jsonObject, options); - const newBuffer: Buffer = Buffer.from(newJson); // utf8 encoding happens here + const newBuffer: Buffer = Buffer.from(newJson, DEFAULT_ENCODING); if (options.onlyIfChanged) { // Has the file changed? @@ -205,13 +489,13 @@ export class JsonFile { } } - FileSystem.writeFile(jsonFilename, newBuffer.toString(), { + await FileSystem.writeFileAsync(jsonFilename, newBuffer, { ensureFolderExists: options.ensureFolderExists }); // TEST CODE: Used to verify that onlyIfChanged isn't broken by a hidden transformation during saving. /* - const oldBuffer2: Buffer = FileSystem.readFileToBuffer(jsonFilename); + const oldBuffer2: Buffer = await FileSystem.readFileToBufferAsync(jsonFilename); if (Buffer.compare(buffer, oldBuffer2) !== 0) { console.log('new:' + buffer.toString('hex')); console.log('old:' + oldBuffer2.toString('hex')); @@ -226,7 +510,6 @@ export class JsonFile { * Used to validate a data structure before writing. Reports an error if there * are any undefined members. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any public static validateNoUndefinedMembers(jsonObject: JsonObject): void { return JsonFile._validateNoUndefinedMembers(jsonObject, []); } @@ -273,11 +556,52 @@ export class JsonFile { // Convert this: A path: "C:\file" // To this: A path: \"C:\\file\" - const escapedKey: string = key.replace(/[\\]/g, '\\\\') // escape backslashes + const escapedKey: string = key + .replace(/[\\]/g, '\\\\') // escape backslashes .replace(/["]/g, '\\'); // escape quotes result += `["${escapedKey}"]`; } } 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) + ); + } + result.push(Text.replaceAll(line, '\r', '')); + } + return lines.join('\n') + '\n'; + } + + 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; + } + + return parseOptions; + } } diff --git a/libraries/node-core-library/src/JsonSchema.ts b/libraries/node-core-library/src/JsonSchema.ts index 2ec7434daef..2ca3f227190 100644 --- a/libraries/node-core-library/src/JsonSchema.ts +++ b/libraries/node-core-library/src/JsonSchema.ts @@ -1,38 +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 os from 'os'; -import * as path from 'path'; -import Validator = require('z-schema'); +import * as os from 'node:os'; +import * as path from 'node:path'; -import { JsonFile, JsonObject } from './JsonFile'; +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'; interface ISchemaWithId { + // draft-04 uses "id" id: string | undefined; + // draft-06 and higher uses "$id" + $id: string | undefined; } /** - * Callback function arguments for JsonSchema.validateObjectWithCallback(); + * Specifies the version of json-schema to be validated against. + * https://json-schema.org/specification + * @public + */ +export type JsonSchemaVersion = 'draft-04' | 'draft-07'; + +/** + * A definition for a custom format to consider during validation. + * @public + */ +export interface IJsonSchemaCustomFormat { + /** + * The base JSON type. + */ + type: T extends string ? 'string' : T extends number ? 'number' : never; + + /** + * A validation function for the format. + * @param data - The raw field data to validate. + * @returns whether the data is valid according to the format. + */ + validate: (data: T) => boolean; +} + +/** + * Callback function arguments for {@link JsonSchema.validateObjectWithCallback} * @public */ export interface IJsonSchemaErrorInfo { /** - * The z-schema error tree, formatted as an indented text string. + * The ajv error list, formatted as an indented text string. */ details: string; } /** - * Options for JsonSchema.validateObject() + * Options for {@link JsonSchema.validateObjectWithCallback} * @public */ -export interface IJsonSchemaValidateOptions { +export interface IJsonSchemaValidateObjectWithOptions { + /** + * If true, the root-level `$schema` property in a JSON object being validated will be ignored during validation. + * If this is set to `true` and the schema requires a `$schema` property, validation will fail. + */ + ignoreSchemaField?: boolean; +} + +/** + * Options for {@link JsonSchema.validateObject} + * @public + */ +export interface IJsonSchemaValidateOptions extends IJsonSchemaValidateObjectWithOptions { /** * A custom header that will be used to report schema errors. * @remarks * If omitted, the default header is "JSON validation failed:". The error message starts with - * the header, followed by the full input filename, followed by the z-schema error tree. + * the header, followed by the full input filename, followed by the ajv error list. * If you wish to customize all aspects of the error message, use JsonFile.loadAndValidateWithCallback() * or JsonSchema.validateObjectWithCallback(). */ @@ -40,15 +83,15 @@ export interface IJsonSchemaValidateOptions { } /** - * Options for JsonSchema.fromFile() + * Options for {@link JsonSchema.fromFile} and {@link JsonSchema.fromLoadedObject} * @public */ -export interface IJsonSchemaFromFileOptions { +export interface IJsonSchemaLoadOptions { /** * Other schemas that this schema references, e.g. via the "$ref" directive. * @remarks * The tree of dependent schemas may reference the same schema more than once. - * However, if the same schema "id" is used by two different JsonSchema instances, + * However, if the same schema "$id" is used by two different JsonSchema instances, * an error will be reported. This means you cannot load the same filename twice * and use them both together, and you cannot have diamond dependencies on different * versions of the same schema. Although technically this would be possible to support, @@ -57,6 +100,55 @@ export interface IJsonSchemaFromFileOptions { * JsonSchema also does not allow circular references between schema dependencies. */ dependentSchemas?: JsonSchema[]; + + /** + * The json-schema version to target for validation. + * + * @defaultValue draft-07 + * + * @remarks + * If the a version is not explicitly set, the schema object's `$schema` property + * will be inspected to determine the version. If a `$schema` property is not found + * or does not match an expected URL, the default version will be used. + */ + schemaVersion?: JsonSchemaVersion; + + /** + * Any custom formats to consider during validation. Some standard formats are supported + * out-of-the-box (e.g. emails, uris), but additional formats can be defined here. You could + * for example define generic numeric formats (e.g. uint8) or domain-specific formats. + */ + customFormats?: Record | IJsonSchemaCustomFormat>; +} + +/** + * Options for {@link JsonSchema.fromFile} + * @public + */ +export type IJsonSchemaFromFileOptions = IJsonSchemaLoadOptions; + +/** + * Options for {@link JsonSchema.fromLoadedObject} + * @public + */ +export type IJsonSchemaFromObjectOptions = IJsonSchemaLoadOptions; + +const JSON_SCHEMA_URL_PREFIX_BY_JSON_SCHEMA_VERSION: Map = new Map([ + ['draft-04', 'http://json-schema.org/draft-04/schema'], + ['draft-07', 'http://json-schema.org/draft-07/schema'] +]); + +/** + * Helper function to determine the json-schema version to target for validation. + */ +function _inferJsonSchemaVersion({ $schema }: JsonObject): JsonSchemaVersion | undefined { + if ($schema) { + for (const [jsonSchemaVersion, urlPrefix] of JSON_SCHEMA_URL_PREFIX_BY_JSON_SCHEMA_VERSION) { + if ($schema.startsWith(urlPrefix)) { + return jsonSchemaVersion; + } + } + } } /** @@ -71,10 +163,14 @@ export interface IJsonSchemaFromFileOptions { export class JsonSchema { private _dependentSchemas: JsonSchema[] = []; private _filename: string = ''; - private _validator: Validator | undefined = undefined; + private _validator: ValidateFunction | undefined = undefined; private _schemaObject: JsonObject | undefined = undefined; + private _schemaVersion: JsonSchemaVersion | undefined = undefined; + private _customFormats: + | Record | IJsonSchemaCustomFormat> + | undefined = undefined; - private constructor() { } + private constructor() {} /** * Registers a JsonSchema that will be loaded from a file on disk. @@ -94,26 +190,38 @@ export class JsonSchema { if (options) { schema._dependentSchemas = options.dependentSchemas || []; + schema._schemaVersion = options.schemaVersion; + schema._customFormats = options.customFormats; } return schema; } /** - * Registers a JsonSchema that will be loaded from a file on disk. - * @remarks - * NOTE: An error occurs if the file does not exist; however, the file itself is not loaded or validated - * until it the schema is actually used. + * Registers a JsonSchema that will be loaded from an object. */ - public static fromLoadedObject(schemaObject: JsonObject): JsonSchema { + public static fromLoadedObject( + schemaObject: JsonObject, + options?: IJsonSchemaFromObjectOptions + ): JsonSchema { const schema: JsonSchema = new JsonSchema(); schema._schemaObject = schemaObject; + + if (options) { + schema._dependentSchemas = options.dependentSchemas || []; + schema._schemaVersion = options.schemaVersion; + schema._customFormats = options.customFormats; + } + return schema; } - private static _collectDependentSchemas(collectedSchemas: JsonSchema[], dependentSchemas: JsonSchema[], - seenObjects: Set, seenIds: Set): void { - + 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)) { @@ -123,54 +231,51 @@ export class JsonSchema { const schemaId: string = dependentSchema._ensureLoaded(); if (schemaId === '') { - throw new Error(`This schema ${dependentSchema.shortName} cannot be referenced` - + ' because is missing the "id" field'); + 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" as` - + ' another schema in this set'); + 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); + JsonSchema._collectDependentSchemas( + collectedSchemas, + dependentSchema._dependentSchemas, + seenObjects, + seenIds + ); } } /** * Used to nicely format the ZSchema error tree. */ - private static _formatErrorDetails(errorDetails: Validator.SchemaErrorDetail[]): string { + private static _formatErrorDetails(errorDetails: ErrorObject[]): string { return JsonSchema._formatErrorDetailsHelper(errorDetails, '', ''); } /** * Used by _formatErrorDetails. */ - private static _formatErrorDetailsHelper(errorDetails: Validator.SchemaErrorDetail[], indent: string, - buffer: string): string { + private static _formatErrorDetailsHelper( + errorDetails: ErrorObject[], + indent: string, + buffer: string + ): string { for (const errorDetail of errorDetails) { - - buffer += os.EOL + indent + `Error: ${errorDetail.path}`; - - if (errorDetail.description) { - const MAX_LENGTH: number = 40; - let truncatedDescription: string = errorDetail.description.trim(); - if (truncatedDescription.length > MAX_LENGTH) { - truncatedDescription = truncatedDescription.substr(0, MAX_LENGTH - 3) - + '...'; - } - - buffer += ` (${truncatedDescription})`; - } + buffer += os.EOL + indent + `Error: #${errorDetail.instancePath}`; buffer += os.EOL + indent + ` ${errorDetail.message}`; - - if (errorDetail.inner) { - buffer = JsonSchema._formatErrorDetailsHelper(errorDetail.inner, indent + ' ', buffer); + if (errorDetail.params?.additionalProperty) { + buffer += `: ${errorDetail.params?.additionalProperty}`; } } @@ -180,7 +285,7 @@ export class JsonSchema { /** * Returns a short name for this schema, for use in error messages. * @remarks - * If the schema was loaded from a file, then the base filename is used. Otherwise, the "id" + * If the schema was loaded from a file, then the base filename is used. Otherwise, the "$id" * field is used if available. */ public get shortName(): string { @@ -189,6 +294,8 @@ export class JsonSchema { const schemaWithId: ISchemaWithId = this._schemaObject as ISchemaWithId; if (schemaWithId.id) { return schemaWithId.id; + } else if (schemaWithId.$id) { + return schemaWithId.$id; } } return '(anonymous schema)'; @@ -206,26 +313,36 @@ export class JsonSchema { this._ensureLoaded(); if (!this._validator) { - // Don't assign this to _validator until we're sure everything was successful - const newValidator: Validator = new Validator({ - breakOnFirstError: false, - noTypeless: true, - noExtraKeywords: true - }); - - const anythingSchema: JsonObject = { - 'type': [ - 'array', - 'boolean', - 'integer', - 'number', - 'object', - 'string' - ] + const targetSchemaVersion: JsonSchemaVersion | undefined = + this._schemaVersion ?? _inferJsonSchemaVersion(this._schemaObject); + const validatorOptions: AjvOptions = { + strictSchema: true, + allowUnionTypes: true }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (newValidator as any).setRemoteReference('http://json-schema.org/draft-04/schema', anythingSchema); + let validator: Ajv; + // Keep legacy support for older draft-04 schema + switch (targetSchemaVersion) { + case 'draft-04': { + validator = new AjvDraft04(validatorOptions); + break; + } + + case 'draft-07': + default: { + validator = new Ajv(validatorOptions); + break; + } + } + + // Enable json-schema format validation + // https://ajv.js.org/packages/ajv-formats.html + addFormats(validator); + if (this._customFormats) { + for (const [name, format] of Object.entries(this._customFormats)) { + validator.addFormat(name, { ...format, async: false }); + } + } const collectedSchemas: JsonSchema[] = []; const seenObjects: Set = new Set(); @@ -236,13 +353,18 @@ export class JsonSchema { // 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. for (const collectedSchema of collectedSchemas) { - if (!newValidator.validateSchema(collectedSchema._schemaObject)) { - throw new Error(`Failed to validate schema "${collectedSchema.shortName}":` + os.EOL - + JsonSchema._formatErrorDetails(newValidator.getLastErrors())); + validator.validateSchema(collectedSchema._schemaObject) as boolean; + if (validator.errors && validator.errors.length > 0) { + throw new Error( + `Failed to validate schema "${collectedSchema.shortName}":` + + os.EOL + + JsonSchema._formatErrorDetails(validator.errors) + ); } + validator.addSchema(collectedSchema._schemaObject); } - this._validator = newValidator; + this._validator = validator.compile(this._schemaObject); } } @@ -254,27 +376,44 @@ export class JsonSchema { * if not applicable * @param options - Other options that control the validation */ - public validateObject(jsonObject: JsonObject, filenameForErrors: string, options?: IJsonSchemaValidateOptions): void { - this.validateObjectWithCallback(jsonObject, (errorInfo: IJsonSchemaErrorInfo) => { - const prefix: string = (options && options.customErrorHeader) ? options.customErrorHeader - : 'JSON validation failed:'; - - throw new Error(prefix + os.EOL + - filenameForErrors + os.EOL + errorInfo.details); - }); + public validateObject( + jsonObject: JsonObject, + filenameForErrors: string, + options?: IJsonSchemaValidateOptions + ): void { + this.validateObjectWithCallback( + jsonObject, + (errorInfo: IJsonSchemaErrorInfo) => { + const prefix: string = options?.customErrorHeader ?? 'JSON validation failed:'; + + throw new Error(prefix + os.EOL + filenameForErrors + os.EOL + errorInfo.details); + }, + options + ); } /** * Validates the specified JSON object against this JSON schema. If the validation fails, * a callback is called for each validation error. */ - public validateObjectWithCallback(jsonObject: JsonObject, - errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void): void { - + public validateObjectWithCallback( + jsonObject: JsonObject, + errorCallback: (errorInfo: IJsonSchemaErrorInfo) => void, + options?: IJsonSchemaValidateObjectWithOptions + ): void { this.ensureCompiled(); - if (!this._validator!.validate(jsonObject, this._schemaObject)) { - const errorDetails: string = JsonSchema._formatErrorDetails(this._validator!.getLastErrors()); + if (options?.ignoreSchemaField) { + const { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + $schema, + ...remainder + } = jsonObject; + jsonObject = remainder; + } + + if (this._validator && !this._validator(jsonObject)) { + const errorDetails: string = JsonSchema._formatErrorDetails(this._validator.errors!); const args: IJsonSchemaErrorInfo = { details: errorDetails @@ -287,6 +426,6 @@ export class JsonSchema { if (!this._schemaObject) { this._schemaObject = JsonFile.load(this._filename); } - return (this._schemaObject as ISchemaWithId).id || ''; + return (this._schemaObject as ISchemaWithId).id || (this._schemaObject as ISchemaWithId).$id || ''; } } diff --git a/libraries/node-core-library/src/LegacyAdapters.ts b/libraries/node-core-library/src/LegacyAdapters.ts index 9a2b69145be..ab9a4cd276b 100644 --- a/libraries/node-core-library/src/LegacyAdapters.ts +++ b/libraries/node-core-library/src/LegacyAdapters.ts @@ -1,13 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { sort as timsort } from 'timsort'; -import * as semver from 'semver'; - /** * Callback used by {@link LegacyAdapters}. * @public */ +// eslint-disable-next-line @rushstack/no-new-null export type LegacyCallback = (error: TError | null | undefined, result: TResult) => void; /** @@ -15,8 +13,6 @@ export type LegacyCallback = (error: TError | null | undefined, * @public */ export class LegacyAdapters { - private static _useTimsort: boolean | undefined = undefined; - /** * This function wraps a function with a callback in a promise. */ @@ -72,15 +68,15 @@ export class LegacyAdapters { fn(arg1, arg2, arg3, arg4, cb); } else if (arg1 !== undefined && arg2 !== undefined && arg3 !== undefined) { fn(arg1, arg2, arg3, cb); - } else if (arg1 !== undefined && arg2 !== undefined ) { + } else if (arg1 !== undefined && arg2 !== undefined) { fn(arg1, arg2, cb); - } else if (arg1 !== undefined ) { + } else if (arg1 !== undefined) { fn(arg1, cb); } else { fn(cb); } } catch (e) { - reject(e); + reject(e as Error); } }); } @@ -88,7 +84,8 @@ export class LegacyAdapters { /** * Normalizes an object into an `Error` object. */ - public static scrubError(error: Error | string | any): Error { // eslint-disable-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public static scrubError(error: Error | string | any): Error { if (error instanceof Error) { return error; } else if (typeof error === 'string') { @@ -99,23 +96,4 @@ export class LegacyAdapters { return errorObject; } } - - /** - * Prior to Node 11.x, the `Array.sort()` algorithm is not guaranteed to be stable. - * If you need a stable sort, you can use `sortStable()` as a workaround. - * - * @remarks - * On NodeJS 11.x and later, this method simply calls the native `Array.sort()`. - * For earlier versions, it uses an implementation of Timsort, which is the same algorithm used by modern NodeJS. - */ - public static sortStable(array: T[], compare?: (a: T, b: T) => number): void { - if (LegacyAdapters._useTimsort === undefined) { - LegacyAdapters._useTimsort = semver.major(process.versions.node) < 11; - } - if (LegacyAdapters._useTimsort) { - timsort(array, compare); - } else { - Array.prototype.sort.call(array, compare); - } - } } diff --git a/libraries/node-core-library/src/LockFile.ts b/libraries/node-core-library/src/LockFile.ts index 3f6ded6734c..5753ccfdd67 100644 --- a/libraries/node-core-library/src/LockFile.ts +++ b/libraries/node-core-library/src/LockFile.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 child_process from 'child_process'; -import { setTimeout } from 'timers'; +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'; /** * http://man7.org/linux/man-pages/man5/proc.5.html @@ -22,7 +23,7 @@ const procStatStartTimePos: number = 22; * @param stat - The contents of a linux /proc/[pid]/stat file. * @returns The process start time in jiffies, or undefined if stat has an unexpected format. */ -export function getProcessStartTimeFromProcStat (stat: string): string | undefined { +export function getProcessStartTimeFromProcStat(stat: string): string | undefined { // Parse the value at position procStatStartTimePos. // We cannot just split stat on spaces, because value 2 may contain spaces. // For example, when running the following Shell commands: @@ -36,10 +37,11 @@ export function getProcessStartTimeFromProcStat (stat: string): string | undefin // trimRight to remove the trailing line terminator. let values: string[] = stat.trimRight().split(' '); let i: number = values.length - 1; - while (i >= 0 && + while ( + i >= 0 && // charAt returns an empty string if the index is out of bounds. values[i].charAt(values[i].length - 1) !== ')' - ) { + ) { i -= 1; } // i is the index of the last part of the second value (but i need not be 1). @@ -57,7 +59,7 @@ export function getProcessStartTimeFromProcStat (stat: string): string | undefin // In theory, the representations of start time returned by `cat /proc/[pid]/stat` and `ps -o lstart` can change // while the system is running, but we assume this does not happen. // So the caller can safely use this value as part of a unique process id (on the machine, without comparing - // accross reboots). + // across reboots). return startTimeJiffies; } @@ -90,11 +92,11 @@ export function getProcessStartTime(pid: number): string | undefined { // zero bytes are written to stdout. if (psResult.status !== 0 && !psStdout && process.platform === 'linux') { // Try to read /proc/[pid]/stat and get the value at position procStatStartTimePos. - let stat: undefined|string; + let stat: undefined | string; try { stat = FileSystem.readFile(`/proc/${pidString}/stat`); } catch (error) { - if (error.code !== 'ENOENT') { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { throw error; } // Either no process with PID pid exists, or this version/configuration of linux is non-standard. @@ -102,10 +104,12 @@ export function getProcessStartTime(pid: number): string | undefined { return undefined; } if (stat !== undefined) { - const startTimeJiffies: string|undefined = getProcessStartTimeFromProcStat(stat); + const startTimeJiffies: string | undefined = getProcessStartTimeFromProcStat(stat); if (startTimeJiffies === undefined) { - throw new Error(`Could not retrieve the start time of process ${pidString} from the OS because the ` - + `contents of /proc/${pidString}/stat have an unexpected format`); + throw new Error( + `Could not retrieve the start time of process ${pidString} from the OS because the ` + + `contents of /proc/${pidString}/stat have an unexpected format` + ); } return startTimeJiffies; } @@ -118,7 +122,7 @@ export function getProcessStartTime(pid: number): string | undefined { const psSplit: string[] = psStdout.split('\n'); - // successfuly able to run "ps", but no process was found + // successfully able to run "ps", but no process was found if (psSplit[1] === '') { return undefined; } @@ -133,10 +137,18 @@ export function getProcessStartTime(pid: number): string | undefined { throw new Error(`Unexpected output from the "ps" command`); } +// A set of locks that currently exist in the current process, to be used when +// multiple locks are acquired in the same process. +const IN_PROC_LOCKS: Set = new Set(); + /** - * A helper utility for working with file-based locks. - * This class should only be used for locking resources across processes, - * but should not be used for attempting to lock a resource in the same process. + * 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 + * a single Node.js process. + * @remarks + * The implementation works on Windows, Mac, and Linux without requiring any native helpers. + * On non-Windows systems, the algorithm requires access to the `ps` shell command. On Linux, + * it requires access the `/proc/${pidString}/stat` filesystem. * @public */ export class LockFile { @@ -146,86 +158,144 @@ export class LockFile { private _filePath: string; private _dirtyWhenAcquired: boolean; - private constructor(_fileWriter: FileWriter | undefined, _filePath: string, _dirtyWhenAcquired: boolean) { - this._fileWriter = _fileWriter; - this._filePath = _filePath; - this._dirtyWhenAcquired = _dirtyWhenAcquired; + private constructor(fileWriter: FileWriter | undefined, filePath: string, dirtyWhenAcquired: boolean) { + this._fileWriter = fileWriter; + this._filePath = filePath; + this._dirtyWhenAcquired = dirtyWhenAcquired; + + IN_PROC_LOCKS.add(filePath); } /** - * Returns the path to the lockfile, should it be created successfully. + * Returns the path of the lockfile that will be created when a lock is successfully acquired. + * @param resourceFolder - The folder where the lock file will be created + * @param resourceName - An alphanumeric name that describes the resource being locked. This will become + * the filename of the temporary file created to manage the lock. + * @param pid - The PID for the current Node.js process (`process.pid`), which is used by the locking algorithm. */ - public static getLockFilePath(resourceDir: string, resourceName: string, pid: number = process.pid): string { + public static getLockFilePath( + resourceFolder: string, + resourceName: string, + pid: number = process.pid + ): string { if (!resourceName.match(/^[a-zA-Z0-9][a-zA-Z0-9-.]+[a-zA-Z0-9]$/)) { - throw new Error(`The resource name "${resourceName}" is invalid.` - + ` It must be an alphanumberic string with only "-" or "." It must start with an alphanumeric character.`); + throw new Error( + `The resource name "${resourceName}" is invalid.` + + ` It must be an alphanumeric string with only "-" or "." It must start and end with an alphanumeric character.` + ); } - if (process.platform === 'win32') { - return path.join(path.resolve(resourceDir), `${resourceName}.lock`); - } else if (process.platform === 'linux' || process.platform === 'darwin') { - return path.join(path.resolve(resourceDir), `${resourceName}#${pid}.lock`); - } + switch (process.platform) { + case 'win32': { + return path.resolve(resourceFolder, `${resourceName}.lock`); + } - throw new Error(`File locking not implemented for platform: "${process.platform}"`); + case 'linux': + case 'darwin': { + return path.resolve(resourceFolder, `${resourceName}#${pid}.lock`); + } + + default: { + throw new Error(`File locking not implemented for platform: "${process.platform}"`); + } + } } /** * Attempts to create a lockfile with the given filePath. - * If successful, returns a LockFile instance. - * If unable to get a lock, returns undefined. - * @param resourceName - the name of the resource we are locking on. Should be an alphabetic string. + * @param resourceFolder - The folder where the lock file will be created + * @param resourceName - An alphanumeric name that describes the resource being locked. This will become + * the filename of the temporary file created to manage the lock. + * @returns If successful, returns a `LockFile` instance. If unable to get a lock, returns `undefined`. */ - public static tryAcquire(resourceDir: string, resourceName: string): LockFile | undefined { - FileSystem.ensureFolder(resourceDir); - if (process.platform === 'win32') { - return LockFile._tryAcquireWindows(resourceDir, resourceName); - } else if (process.platform === 'linux' || process.platform === 'darwin') { - return LockFile._tryAcquireMacOrLinux(resourceDir, resourceName); - } - throw new Error(`File locking not implemented for platform: "${process.platform}"`); + 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); + } + + /** + * @deprecated Use {@link LockFile.acquireAsync} instead. + */ + public static acquire(resourceFolder: string, resourceName: string, maxWaitMs?: number): Promise { + return LockFile.acquireAsync(resourceFolder, resourceName, maxWaitMs); } /** - * Attempts to create the lockfile. - * Will continue to loop at every 100ms until the lock becomes available or the maxWaitMs is surpassed. - * @remarks This function is subject to starvation, whereby it does not ensure that the process that has been - * waiting the longest to acquire the lock will get it first. This means that a process could theoretically - * wait for the lock forever, while other processes skipped it in line and acquired the lock first. + * Attempts to create the lockfile. Will continue to loop at every 100ms until the lock becomes available + * or the maxWaitMs is surpassed. + * + * @remarks + * This function is subject to starvation, whereby it does not ensure that the process that has been + * waiting the longest to acquire the lock will get it first. This means that a process could theoretically + * wait for the lock forever, while other processes skipped it in line and acquired the lock first. + * + * @param resourceFolder - The folder where the lock file will be created + * @param resourceName - An alphanumeric name that describes the resource being locked. This will become + * the filename of the temporary file created to manage the lock. + * @param maxWaitMs - The maximum number of milliseconds to wait for the lock before reporting an error */ - public static acquire(resourceDir: string, resourceName: string, maxWaitMs?: number): Promise { + public static async acquireAsync( + resourceFolder: string, + resourceName: string, + maxWaitMs?: number + ): Promise { const interval: number = 100; const startTime: number = Date.now(); + const timeoutTime: number | undefined = maxWaitMs ? startTime + maxWaitMs : undefined; + + await FileSystem.ensureFolderAsync(resourceFolder); - const retryLoop: () => Promise = () => { - const lock: LockFile | undefined = LockFile.tryAcquire(resourceDir, resourceName); + const lockFilePath: string = LockFile.getLockFilePath(resourceFolder, resourceName); + + // eslint-disable-next-line no-unmodified-loop-condition + while (!timeoutTime || Date.now() <= timeoutTime) { + const lock: LockFile | undefined = LockFile._tryAcquireInner( + resourceFolder, + resourceName, + lockFilePath + ); if (lock) { - return Promise.resolve(lock); - } - if (maxWaitMs && (Date.now() > startTime + maxWaitMs)) { - return Promise.reject(new Error(`Exceeded maximum wait time to acquire lock for resource "${resourceName}"`)); + return lock; } - return LockFile._sleepForMs(interval).then(() => { - return retryLoop(); - }); - }; + await Async.sleepAsync(interval); + } - return retryLoop(); + throw new Error(`Exceeded maximum wait time to acquire lock for resource "${resourceName}"`); } - private static _sleepForMs(timeout: number): Promise { - return new Promise((resolve: () => void, reject: () => void) => { - setTimeout(() => { - resolve(); - }, timeout); - }); + 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(resourceDir: string, resourceName: string): LockFile | undefined { + private static _tryAcquireMacOrLinux( + resourceFolder: string, + resourceName: string, + pidLockFilePath: string + ): LockFile | undefined { let dirtyWhenAcquired: boolean = false; // get the current process' pid @@ -236,7 +306,6 @@ export class LockFile { throw new Error(`Unable to calculate start time for current process.`); } - const pidLockFilePath: string = LockFile.getLockFilePath(resourceDir, resourceName); let lockFileHandle: FileWriter | undefined; let lockFile: LockFile; @@ -247,14 +316,13 @@ export class LockFile { // We should ideally maintain a dictionary of normalized acquired filenames lockFileHandle = FileWriter.open(pidLockFilePath); lockFileHandle.write(startTime); - - const currentBirthTimeMs: number = FileSystem.getStatistics(pidLockFilePath).birthtime.getTime(); + 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.readFolder(resourceDir); + const files: string[] = FileSystem.readFolderItemNames(resourceFolder); // look for anything ending with # then numbers and ".lock" const lockFileRegExp: RegExp = /^(.+)#([0-9]+)\.lock$/; @@ -262,12 +330,13 @@ export class LockFile { 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())) { - + 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 = path.join(resourceDir, fileInFolder); + const fileInFolderPath: string = `${resourceFolder}/${fileInFolder}`; dirtyWhenAcquired = true; // console.log(`FOUND OTHER LOCKFILE: ${otherPid}`); @@ -280,8 +349,11 @@ export class LockFile { otherPidOldStartTime = FileSystem.readFile(fileInFolderPath); // check the timestamp of the file otherBirthtimeMs = FileSystem.getStatistics(fileInFolderPath).birthtime.getTime(); - } catch (err) { - // this means the file is probably deleted already + } 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, @@ -295,8 +367,11 @@ export class LockFile { // 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 + } 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; @@ -316,9 +391,24 @@ export class LockFile { // 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 && otherBirthtimeMs < smallestBirthTimeMs) { - smallestBirthTimeMs = otherBirthtimeMs; - smallestBirthTimePid = otherPid; + 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; + } } } } @@ -345,8 +435,7 @@ export class LockFile { * Attempts to acquire the lock using Windows * This algorithm is much simpler since we can rely on the operating system */ - private static _tryAcquireWindows(resourceDir: string, resourceName: string): LockFile | undefined { - const lockFilePath: string = LockFile.getLockFilePath(resourceDir, resourceName); + private static _tryAcquireWindows(lockFilePath: string): LockFile | undefined { let dirtyWhenAcquired: boolean = false; let fileHandle: FileWriter | undefined; @@ -386,16 +475,23 @@ export class LockFile { } /** - * Unlocks a file and removes it from disk. + * Unlocks a file and optionally removes it from disk. * This can only be called once. + * + * @param deleteFile - Whether to delete the lockfile from disk. Defaults to true. */ - public release(): void { + public release(deleteFile: boolean = true): void { if (this.isReleased) { throw new Error(`The lock for file "${path.basename(this._filePath)}" has already been released.`); } + IN_PROC_LOCKS.delete(this._filePath); + this._fileWriter!.close(); - FileSystem.deleteFile(this._filePath); + if (deleteFile) { + FileSystem.deleteFile(this._filePath); + } + this._fileWriter = undefined; } @@ -420,4 +516,4 @@ export class LockFile { public get isReleased(): boolean { return this._fileWriter === undefined; } -} \ No newline at end of file +} diff --git a/libraries/node-core-library/src/MapExtensions.ts b/libraries/node-core-library/src/MapExtensions.ts index b84ba96a960..e31e3b70e7b 100644 --- a/libraries/node-core-library/src/MapExtensions.ts +++ b/libraries/node-core-library/src/MapExtensions.ts @@ -19,4 +19,19 @@ export class MapExtensions { targetMap.set(pair[0], pair[1]); } } + + /** + * Converts a string-keyed map to an object. + * @remarks + * This function has the same effect as Object.fromEntries(map.entries()) + * in supported versions of Node (\>= 12.0.0). + * @param map - The map that the object properties will be sourced from + */ + public static toObject(map: Map): { [key: string]: TValue } { + const object: { [key: string]: TValue } = {}; + for (const [key, value] of map.entries()) { + object[key] = value; + } + return object; + } } diff --git a/libraries/node-core-library/src/MinimumHeap.ts b/libraries/node-core-library/src/MinimumHeap.ts new file mode 100644 index 00000000000..e7406619d65 --- /dev/null +++ b/libraries/node-core-library/src/MinimumHeap.ts @@ -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. + +/** + * Implements a standard heap data structure for items of type T and a custom comparator. + * The root will always be the minimum value as determined by the comparator. + * + * @public + */ +export class MinimumHeap { + private readonly _items: T[] = []; + private readonly _comparator: (a: T, b: T) => number; + + /** + * Constructs a new MinimumHeap instance. + * @param comparator - a comparator function that determines the order of the items in the heap. + * If the comparator returns a value less than zero, then `a` will be considered less than `b`. + * If the comparator returns zero, then `a` and `b` are considered equal. + * Otherwise, `a` will be considered greater than `b`. + */ + public constructor(comparator: (a: T, b: T) => number) { + this._comparator = comparator; + } + + /** + * Returns the number of items in the heap. + * @returns the number of items in the heap. + */ + public get size(): number { + return this._items.length; + } + + /** + * Retrieves the root item from the heap without removing it. + * @returns the root item, or `undefined` if the heap is empty + */ + public peek(): T | undefined { + return this._items[0]; + } + + /** + * Retrieves and removes the root item from the heap. The next smallest item will become the new root. + * @returns the root item, or `undefined` if the heap is empty + */ + public poll(): T | undefined { + if (this.size > 0) { + const result: T = this._items[0]; + const item: T = this._items.pop()!; + + const size: number = this.size; + if (size === 0) { + // Short circuit in the trivial case + return result; + } + + let index: number = 0; + + let smallerChildIndex: number = 1; + + while (smallerChildIndex < size) { + let smallerChild: T = this._items[smallerChildIndex]; + + const rightChildIndex: number = smallerChildIndex + 1; + + if (rightChildIndex < size) { + const rightChild: T = this._items[rightChildIndex]; + if (this._comparator(rightChild, smallerChild) < 0) { + smallerChildIndex = rightChildIndex; + smallerChild = rightChild; + } + } + + if (this._comparator(smallerChild, item) < 0) { + this._items[index] = smallerChild; + index = smallerChildIndex; + smallerChildIndex = index * 2 + 1; + } else { + break; + } + } + + // Place the item in its final location satisfying the heap property + this._items[index] = item; + + return result; + } + } + + /** + * Pushes an item into the heap. + * @param item - the item to push + */ + public push(item: T): void { + let index: number = this.size; + while (index > 0) { + // Due to zero-based indexing the parent is not exactly a bit shift + const parentIndex: number = ((index + 1) >> 1) - 1; + const parent: T = this._items[parentIndex]; + if (this._comparator(item, parent) < 0) { + this._items[index] = parent; + index = parentIndex; + } else { + break; + } + } + this._items[index] = item; + } +} 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 2ea4a427a66..dc9e3f6853b 100644 --- a/libraries/node-core-library/src/PackageJsonLookup.ts +++ b/libraries/node-core-library/src/PackageJsonLookup.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 { JsonFile } from './JsonFile'; -import { IPackageJson, INodePackageJson } from './IPackageJson'; +import type { IPackageJson, INodePackageJson } from './IPackageJson'; import { FileConstants } from './Constants'; import { FileSystem } from './FileSystem'; @@ -22,6 +23,34 @@ export interface IPackageJsonLookupParameters { loadExtraFields?: boolean; } +type TryLoadPackageJsonInternalErrorCode = + | 'MISSING_NAME_FIELD' + | 'FILE_NOT_FOUND' + | 'MISSING_VERSION_FIELD' + | 'OTHER_ERROR'; + +interface ITryLoadPackageJsonInternalSuccessResult { + packageJson: IPackageJson; + error?: never; +} + +interface ITryLoadPackageJsonInternalFailureResult { + error: TryLoadPackageJsonInternalErrorCode; +} +interface ITryLoadPackageJsonInternalKnownFailureResult extends ITryLoadPackageJsonInternalFailureResult { + error: 'MISSING_NAME_FIELD' | 'FILE_NOT_FOUND'; +} + +interface ITryLoadPackageJsonInternalUnknownFailureResult extends ITryLoadPackageJsonInternalFailureResult { + error: 'OTHER_ERROR'; + errorObject: Error; +} + +type ITryLoadPackageJsonInternalResult = + | ITryLoadPackageJsonInternalSuccessResult + | ITryLoadPackageJsonInternalKnownFailureResult + | ITryLoadPackageJsonInternalUnknownFailureResult; + /** * This class provides methods for finding the nearest "package.json" for a folder * and retrieving the name of the package. The results are cached. @@ -29,17 +58,35 @@ export interface IPackageJsonLookupParameters { * @public */ export class PackageJsonLookup { - private static _loadOwnPackageJsonLookup: PackageJsonLookup = new PackageJsonLookup({ loadExtraFields: true }); + 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 + * is populated. + * + * @remarks + * For long-running processes that need to clear the cache at appropriate times, + * it is recommended to create your own instance of `PackageJsonLookup` instead + * of relying on this instance. + */ + public static get instance(): PackageJsonLookup { + if (!PackageJsonLookup._instance) { + PackageJsonLookup._instance = new PackageJsonLookup({ loadExtraFields: true }); + } + + return PackageJsonLookup._instance; + } private _loadExtraFields: boolean = false; // Cached the return values for tryGetPackageFolder(): // sourceFilePath --> packageJsonFolder - private _packageFolderCache: Map; + private _packageFolderCache!: Map; // Cached the return values for getPackageName(): // packageJsonPath --> packageName - private _packageJsonCache: Map; + private _packageJsonCache!: Map; public constructor(parameters?: IPackageJsonLookupParameters) { if (parameters) { @@ -74,22 +121,26 @@ export class PackageJsonLookup { * loading, an exception will be thrown instead. */ public static loadOwnPackageJson(dirnameOfCaller: string): IPackageJson { - const packageJson: IPackageJson | undefined = PackageJsonLookup._loadOwnPackageJsonLookup - .tryLoadPackageJsonFor(dirnameOfCaller); + const packageJson: IPackageJson | undefined = + PackageJsonLookup.instance.tryLoadPackageJsonFor(dirnameOfCaller); if (packageJson === undefined) { - throw new Error(`PackageJsonLookup.loadOwnPackageJson() failed to find the caller's package.json.` - + ` The __dirname was: ${dirnameOfCaller}`); + throw new Error( + `PackageJsonLookup.loadOwnPackageJson() failed to find the caller's package.json.` + + ` The __dirname was: ${dirnameOfCaller}` + ); } if (packageJson.version !== undefined) { return packageJson as IPackageJson; } - const errorPath: string = PackageJsonLookup._loadOwnPackageJsonLookup.tryGetPackageJsonFilePathFor(dirnameOfCaller) - || 'package.json'; - throw new Error(`PackageJsonLookup.loadOwnPackageJson() failed because the "version" field is missing in` - + ` ${errorPath}`); + const errorPath: string = + PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(dirnameOfCaller) || 'package.json'; + throw new Error( + `PackageJsonLookup.loadOwnPackageJson() failed because the "version" field is missing in` + + ` ${errorPath}` + ); } /** @@ -202,8 +253,7 @@ export class PackageJsonLookup { const packageJson: INodePackageJson = this.loadNodePackageJson(jsonFilename); if (!packageJson.version) { - throw new Error(`Error reading "${jsonFilename}":\n ` - + 'The required field "version" was not found'); + throw new Error(`Error reading "${jsonFilename}":\n The required field "version" was not found`); } return packageJson as IPackageJson; @@ -214,36 +264,90 @@ export class PackageJsonLookup { * if the `version` field is missing from the package.json file. */ public loadNodePackageJson(jsonFilename: string): INodePackageJson { - if (!FileSystem.exists(jsonFilename)) { - throw new Error(`Input file not found: ${jsonFilename}`); + return this._loadPackageJsonInner(jsonFilename); + } + + private _loadPackageJsonInner(jsonFilename: string): IPackageJson; + private _loadPackageJsonInner( + jsonFilename: string, + errorsToIgnore: Set + ): IPackageJson | undefined; + private _loadPackageJsonInner( + jsonFilename: string, + errorsToIgnore?: Set + ): IPackageJson | undefined { + const loadResult: ITryLoadPackageJsonInternalResult = this._tryLoadNodePackageJsonInner(jsonFilename); + + if (loadResult.error && errorsToIgnore?.has(loadResult.error)) { + return undefined; } + switch (loadResult.error) { + case 'FILE_NOT_FOUND': { + throw new Error(`Input file not found: ${jsonFilename}`); + } + + case 'MISSING_NAME_FIELD': { + throw new Error(`Error reading "${jsonFilename}":\n The required field "name" was not found`); + } + + case 'OTHER_ERROR': { + throw loadResult.errorObject; + } + + default: { + return loadResult.packageJson; + } + } + } + + /** + * Try to load a package.json file as an INodePackageJson, + * returning undefined if the found file does not contain a `name` field. + */ + private _tryLoadNodePackageJsonInner(jsonFilename: string): ITryLoadPackageJsonInternalResult { // Since this will be a cache key, follow any symlinks and get an absolute path // to minimize duplication. (Note that duplication can still occur due to e.g. character case.) - const normalizedFilePath: string = FileSystem.getRealPath(jsonFilename); + let normalizedFilePath: string; + try { + normalizedFilePath = FileSystem.getRealPath(jsonFilename); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return { + error: 'FILE_NOT_FOUND' + }; + } else { + return { + error: 'OTHER_ERROR', + errorObject: e + }; + } + } let packageJson: IPackageJson | undefined = this._packageJsonCache.get(normalizedFilePath); if (!packageJson) { - const loadedPackageJson: IPackageJson = JsonFile.load(normalizedFilePath) as IPackageJson; + const loadedPackageJson: IPackageJson = JsonFile.load(normalizedFilePath); // Make sure this is really a package.json file. CommonJS has fairly strict requirements, // but NPM only requires "name" and "version" if (!loadedPackageJson.name) { - throw new Error(`Error reading "${jsonFilename}":\n ` - + 'The required field "name" was not found'); + return { + error: 'MISSING_NAME_FIELD' + }; } if (this._loadExtraFields) { packageJson = loadedPackageJson; } else { - packageJson = { } as IPackageJson; + packageJson = {} as IPackageJson; // Unless "loadExtraFields" was requested, copy over the essential fields only packageJson.bin = loadedPackageJson.bin; packageJson.dependencies = loadedPackageJson.dependencies; packageJson.description = loadedPackageJson.description; packageJson.devDependencies = loadedPackageJson.devDependencies; + packageJson.exports = loadedPackageJson.exports; packageJson.homepage = loadedPackageJson.homepage; packageJson.license = loadedPackageJson.license; packageJson.main = loadedPackageJson.main; @@ -252,8 +356,8 @@ export class PackageJsonLookup { packageJson.peerDependencies = loadedPackageJson.peerDependencies; packageJson.private = loadedPackageJson.private; packageJson.scripts = loadedPackageJson.scripts; - packageJson.typings = loadedPackageJson.typings || loadedPackageJson.types; packageJson.tsdocMetadata = loadedPackageJson.tsdocMetadata; + packageJson.typings = loadedPackageJson.typings || loadedPackageJson.types; packageJson.version = loadedPackageJson.version; } @@ -261,7 +365,9 @@ export class PackageJsonLookup { this._packageJsonCache.set(normalizedFilePath, packageJson); } - return packageJson; + return { + packageJson + }; } // Recursive part of the algorithm from tryGetPackageFolderFor() @@ -272,8 +378,13 @@ export class PackageJsonLookup { return this._packageFolderCache.get(resolvedFileOrFolderPath); } - // Is resolvedFileOrFolderPath itself a folder with a package.json file? If so, return it. - if (FileSystem.exists(path.join(resolvedFileOrFolderPath, FileConstants.PackageJson))) { + // Is resolvedFileOrFolderPath itself a folder with a valid package.json file? If so, return it. + const packageJsonFilePath: string = `${resolvedFileOrFolderPath}/${FileConstants.PackageJson}`; + const packageJson: IPackageJson | undefined = this._loadPackageJsonInner( + packageJsonFilePath, + new Set(['FILE_NOT_FOUND', 'MISSING_NAME_FIELD']) + ); + if (packageJson) { this._packageFolderCache.set(resolvedFileOrFolderPath, resolvedFileOrFolderPath); return resolvedFileOrFolderPath; } @@ -284,7 +395,7 @@ export class PackageJsonLookup { // We reached the root directory without finding a package.json file, // so cache the negative result this._packageFolderCache.set(resolvedFileOrFolderPath, undefined); - return undefined; // no match + return undefined; // no match } // Recurse upwards, caching every step along the way diff --git a/libraries/node-core-library/src/PackageName.ts b/libraries/node-core-library/src/PackageName.ts index 42fec9e9c51..d96d2793759 100644 --- a/libraries/node-core-library/src/PackageName.ts +++ b/libraries/node-core-library/src/PackageName.ts @@ -37,15 +37,51 @@ export interface IParsedPackageNameOrError extends IParsedPackageName { } /** - * Various functions for working with package names that may include scopes. + * Options that configure the validation rules used by a {@link PackageNameParser} instance. + * + * @remarks + * The default validation is based on the npmjs.com registry's policy for published packages, and includes these + * restrictions: + * + * - The package name cannot be longer than 214 characters. + * + * - The package name must not be empty. + * + * - Other than the `@` and `/` delimiters used for scopes, the only allowed characters + * are letters, numbers, `-`, `_`, and `.`. + * + * - The name must not start with a `.` or `_`. * * @public */ -export class PackageName { +export interface IPackageNameParserOptions { + /** + * If true, allows upper-case letters in package names. + * This improves compatibility with some legacy private registries that still allow that. + */ + allowUpperCase?: boolean; +} + +/** + * A configurable parser for validating and manipulating NPM package names such as `my-package` or `@scope/my-package`. + * + * @remarks + * If you do not need to customize the parser configuration, it is recommended to use {@link PackageName} + * which exposes these operations as a simple static class. + * + * @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 = {}) { + this._options = { ...options }; + } + /** * This attempts to parse a package name that may include a scope component. * The packageName must not be an empty string. @@ -55,7 +91,7 @@ export class PackageName { * @returns an {@link IParsedPackageNameOrError} structure whose `error` property will be * nonempty if the string could not be parsed. */ - public static tryParse(packageName: string): IParsedPackageNameOrError { + public tryParse(packageName: string): IParsedPackageNameOrError { const result: IParsedPackageNameOrError = { scope: '', unscopedName: '', @@ -111,21 +147,25 @@ export class PackageName { } // Convert "@scope/unscoped-name" --> "scopeunscoped-name" - const nameWithoutScopeSymbols: string = (result.scope ? result.scope.slice(1, -1) : '') - + result.unscopedName; - - // "New packages must not have uppercase letters in the name." - // This can't be enforced because "old" packages are still actively maintained. - // Example: https://www.npmjs.com/package/Base64 - // However it's pretty reasonable to require the scope to be lower case - if (result.scope !== result.scope.toLowerCase()) { - result.error = `The package scope "${result.scope}" must not contain upper case characters`; - return result; + const nameWithoutScopeSymbols: string = + (result.scope ? result.scope.slice(1, -1) : '') + result.unscopedName; + + if (!this._options.allowUpperCase) { + // "New packages must not have uppercase letters in the name." + // This can't be enforced because "old" packages are still actively maintained. + // Example: https://www.npmjs.com/package/Base64 + // However it's pretty reasonable to require the scope to be lower case + if (result.scope !== result.scope.toLowerCase()) { + result.error = `The package scope "${result.scope}" must not contain upper case characters`; + return result; + } } // "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(PackageName._invalidNameCharactersRegExp); + const match: RegExpMatchArray | null = nameWithoutScopeSymbols.match( + PackageNameParser._invalidNameCharactersRegExp + ); if (match) { result.error = `The package name "${packageName}" contains an invalid character: "${match[0]}"`; return result; @@ -140,8 +180,8 @@ export class PackageName { * @remarks * The packageName must not be an empty string. */ - public static parse(packageName: string): IParsedPackageName { - const result: IParsedPackageNameOrError = PackageName.tryParse(packageName); + public parse(packageName: string): IParsedPackageName { + const result: IParsedPackageNameOrError = this.tryParse(packageName); if (result.error) { throw new Error(result.error); } @@ -151,15 +191,15 @@ export class PackageName { /** * {@inheritDoc IParsedPackageName.scope} */ - public static getScope(packageName: string): string { - return PackageName.parse(packageName).scope; + public getScope(packageName: string): string { + return this.parse(packageName).scope; } /** * {@inheritDoc IParsedPackageName.unscopedName} */ - public static getUnscopedName(packageName: string): string { - return PackageName.parse(packageName).unscopedName; + public getUnscopedName(packageName: string): string { + return this.parse(packageName).unscopedName; } /** @@ -167,8 +207,8 @@ export class PackageName { * @remarks * This function will not throw an exception. */ - public static isValidName(packageName: string): boolean { - const result: IParsedPackageNameOrError = PackageName.tryParse(packageName); + public isValidName(packageName: string): boolean { + const result: IParsedPackageNameOrError = this.tryParse(packageName); return !result.error; } @@ -176,8 +216,8 @@ export class PackageName { * Throws an exception if the specified name is not a valid package name. * The packageName must not be an empty string. */ - public static validate(packageName: string): void { - PackageName.parse(packageName); + public validate(packageName: string): void { + this.parse(packageName); } /** @@ -186,7 +226,7 @@ export class PackageName { * @param unscopedName - Must be a nonempty package name that does not contain a scope * @returns A full package name such as "\@example/some-library". */ - public static combineParts(scope: string, unscopedName: string): string { + public combineParts(scope: string, unscopedName: string): string { if (scope !== '') { if (scope[0] !== '@') { throw new Error('The scope must start with an "@" character'); @@ -211,8 +251,57 @@ export class PackageName { } // Make sure the result is a valid package name - PackageName.validate(result); + this.validate(result); return result; } } + +/** + * Provides basic operations for validating and manipulating NPM package names such as `my-package` + * or `@scope/my-package`. + * + * @remarks + * This is the default implementation of {@link PackageNameParser}, exposed as a convenient static class. + * If you need to configure the parsing rules, use `PackageNameParser` instead. + * + * @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); + } + + /** {@inheritDoc PackageNameParser.parse} */ + public static parse(packageName: string): IParsedPackageName { + return this._parser.parse(packageName); + } + + /** {@inheritDoc PackageNameParser.getScope} */ + public static getScope(packageName: string): string { + return this._parser.getScope(packageName); + } + + /** {@inheritDoc PackageNameParser.getUnscopedName} */ + public static getUnscopedName(packageName: string): string { + return this._parser.getUnscopedName(packageName); + } + + /** {@inheritDoc PackageNameParser.isValidName} */ + public static isValidName(packageName: string): boolean { + return this._parser.isValidName(packageName); + } + + /** {@inheritDoc PackageNameParser.validate} */ + public static validate(packageName: string): void { + return this._parser.validate(packageName); + } + + /** {@inheritDoc PackageNameParser.combineParts} */ + public static combineParts(scope: string, unscopedName: string): string { + return this._parser.combineParts(scope, unscopedName); + } +} diff --git a/libraries/node-core-library/src/Path.ts b/libraries/node-core-library/src/Path.ts index fbcafdb0d1b..c6f0a2db1ea 100644 --- a/libraries/node-core-library/src/Path.ts +++ b/libraries/node-core-library/src/Path.ts @@ -1,7 +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 path from 'path'; +import * as path from 'node:path'; + +/** + * The format that the FileError message should conform to. The supported formats are: + * - Unix: `:: - ` + * - VisualStudio: `(,) - ` + * + * @public + */ +export type FileLocationStyle = 'Unix' | 'VisualStudio'; + +/** + * Options for {@link Path.formatFileLocation}. + * @public + */ +export interface IPathFormatFileLocationOptions { + /** + * The base path to use when converting `pathToFormat` to a relative path. If not specified, + * `pathToFormat` will be used as-is. + */ + baseFolder?: string; + /** + * The path that will be used to specify the file location. + */ + pathToFormat: string; + /** + * The message related to the file location. + */ + message: string; + /** + * The style of file location formatting to use. + */ + format: FileLocationStyle; + /** + * The optional line number. If not specified, the line number will not be included + * in the formatted string. + */ + line?: number; + /** + * The optional column number. If not specified, the column number will not be included + * in the formatted string. + */ + column?: number; +} + +/** + * Options for {@link Path.formatConcisely}. + * @public + */ +export interface IPathFormatConciselyOptions { + /** + * The path to be converted. + */ + pathToConvert: string; + + /** + * The base path to use when converting `pathToConvert` to a relative path. + */ + baseFolder: string; + + /** + * If set to true, don't include the leading `./` if the path is under the base folder. + */ + trimLeadingDotSlash?: boolean; +} /** * Common operations for manipulating file and directory paths. @@ -10,8 +74,14 @@ import * as path from 'path'; * @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 @@ -43,4 +113,155 @@ export class Path { const relativePath: string = path.relative(childPath, parentFolderPath); return relativePath === '' || Path._relativePathRegex.test(relativePath); } + + /** + * Returns true if `path1` and `path2` refer to the same underlying path. + * + * @remarks + * + * The comparison is performed using `path.relative()`. + */ + public static isEqual(path1: string, path2: string): boolean { + return path.relative(path1, path2) === ''; + } + + /** + * Formats a path to look nice for reporting purposes. + * @remarks + * If `pathToConvert` is under the `baseFolder`, then it will be converted to a relative with the `./` prefix + * unless the {@link IPathFormatConciselyOptions.trimLeadingDotSlash} option is set to `true`. + * Otherwise, it will be converted to an absolute path. + * + * Backslashes will be converted to slashes, unless the path starts with an OS-specific string like `C:\`. + */ + 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); + + if (isUnderOrEqual) { + // Note that isUnderOrEqual()'s relativePath is the reverse direction + const convertedPath: string = Path.convertToSlashes( + path.relative(options.baseFolder, options.pathToConvert) + ); + if (options.trimLeadingDotSlash) { + return convertedPath; + } else { + return `./${convertedPath}`; + } + } + + const absolutePath: string = path.resolve(options.pathToConvert); + return absolutePath; + } + + /** + * Formats a file location to look nice for reporting purposes. + * @remarks + * If `pathToFormat` is under the `baseFolder`, then it will be converted to a relative with the `./` prefix. + * Otherwise, it will be converted to an absolute path. + * + * Backslashes will be converted to slashes, unless the path starts with an OS-specific string like `C:\`. + */ + public static formatFileLocation(options: IPathFormatFileLocationOptions): string { + const { message, format, pathToFormat, baseFolder, line, column } = options; + + // Convert the path to be relative to the base folder, if specified. Otherwise, use + // the path as-is. + const filePath: string = baseFolder + ? Path.formatConcisely({ + pathToConvert: pathToFormat, + baseFolder, + trimLeadingDotSlash: true + }) + : path.resolve(pathToFormat); + + let formattedFileLocation: string; + switch (format) { + case 'Unix': { + if (line !== undefined && column !== undefined) { + formattedFileLocation = `:${line}:${column}`; + } else if (line !== undefined) { + formattedFileLocation = `:${line}`; + } else { + formattedFileLocation = ''; + } + + break; + } + + case 'VisualStudio': { + if (line !== undefined && column !== undefined) { + formattedFileLocation = `(${line},${column})`; + } else if (line !== undefined) { + formattedFileLocation = `(${line})`; + } else { + formattedFileLocation = ''; + } + + break; + } + + default: { + throw new Error(`Unknown format: ${format}`); + } + } + + return `${filePath}${formattedFileLocation} - ${message}`; + } + + /** + * Replaces Windows-style backslashes with POSIX-style slashes. + * + * @remarks + * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. + */ + public static convertToSlashes(inputPath: string): string { + return inputPath.replace(/\\/g, '/'); + } + + /** + * Replaces POSIX-style slashes with Windows-style backslashes + * + * @remarks + * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. + */ + public static convertToBackslashes(inputPath: string): string { + return inputPath.replace(/\//g, '\\'); + } + /** + * Replaces slashes or backslashes with the appropriate slash for the current operating system. + */ + public static convertToPlatformDefault(inputPath: string): string { + return path.sep === '/' ? Path.convertToSlashes(inputPath) : Path.convertToBackslashes(inputPath); + } + + /** + * Returns true if the specified path is a relative path and does not use `..` to walk upwards. + * + * @example + * ```ts + * // These evaluate to true + * isDownwardRelative('folder'); + * isDownwardRelative('file'); + * isDownwardRelative('folder/'); + * isDownwardRelative('./folder/'); + * isDownwardRelative('./folder/file'); + * + * // These evaluate to false + * isDownwardRelative('../folder'); + * isDownwardRelative('folder/../file'); + * isDownwardRelative('/folder/file'); + * ``` + */ + public static isDownwardRelative(inputPath: string): boolean { + if (path.isAbsolute(inputPath)) { + return false; + } + // Does it contain ".." + if (Path._upwardPathSegmentRegex.test(inputPath)) { + return false; + } + return true; + } } diff --git a/libraries/node-core-library/src/PosixModeBits.ts b/libraries/node-core-library/src/PosixModeBits.ts index cd4129674da..cc78bc10b30 100644 --- a/libraries/node-core-library/src/PosixModeBits.ts +++ b/libraries/node-core-library/src/PosixModeBits.ts @@ -19,7 +19,7 @@ * * @public */ -export const enum PosixModeBits { +export enum PosixModeBits { // The bits /** diff --git a/libraries/node-core-library/src/PrimitiveTypes.ts b/libraries/node-core-library/src/PrimitiveTypes.ts new file mode 100644 index 00000000000..734d942488a --- /dev/null +++ b/libraries/node-core-library/src/PrimitiveTypes.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. + +/** + * A "branded type" is a primitive type with a compile-type key that makes it incompatible with other + * aliases for the primitive type. + * + * @remarks + * + * Example usage: + * + * ```ts + * // PhoneNumber is a branded type based on the "string" primitive. + * type PhoneNumber = Brand; + * + * function createPhoneNumber(input: string): PhoneNumber { + * if (!/\d+(\-\d+)+/.test(input)) { + * throw new Error('Invalid phone number: ' + JSON.stringify(input)); + * } + * return input as PhoneNumber; + * } + * + * const p1: PhoneNumber = createPhoneNumber('123-456-7890'); + * + * // PhoneNumber is a string and can be used as one: + * const p2: string = p1; + * + * // But an arbitrary string cannot be implicitly type cast as PhoneNumber. + * // ERROR: Type 'string' is not assignable to type 'PhoneNumber' + * const p3: PhoneNumber = '123-456-7890'; + * ``` + * + * For more information about this pattern, see {@link + * https://github.com/Microsoft/TypeScript/blob/7b48a182c05ea4dea81bab73ecbbe9e013a79e99/src/compiler/types.ts#L693-L698 + * | this comment} explaining the TypeScript compiler's introduction of this pattern, and + * {@link https://spin.atomicobject.com/2018/01/15/typescript-flexible-nominal-typing/ | this article} + * explaining the technique in depth. + * + * @public + */ +export type Brand = T & { __brand: BrandTag }; diff --git a/libraries/node-core-library/src/ProtectableMapView.ts b/libraries/node-core-library/src/ProtectableMapView.ts index b4f13e0ae1f..02a60e5bafb 100644 --- a/libraries/node-core-library/src/ProtectableMapView.ts +++ b/libraries/node-core-library/src/ProtectableMapView.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 { ProtectableMap, IProtectableMapParameters } from './ProtectableMap'; +import type { ProtectableMap, IProtectableMapParameters } from './ProtectableMap'; /** * The internal wrapper used by ProtectableMap. It extends the real `Map` base class, @@ -21,21 +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 new file mode 100644 index 00000000000..dc4c74ac345 --- /dev/null +++ b/libraries/node-core-library/src/RealNodeModulePath.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. + +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 + * @public + */ +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; +} + +/** + * This class encapsulates a caching resolver for symlinks in node_modules directories. + * It assumes that the only symlinks that exist in input paths are those that correspond to + * npm packages. + * + * @remarks + * In a repository with a symlinked node_modules installation, some symbolic links need to be mapped for + * node module resolution to produce correct results. However, calling `fs.realpathSync.native` on every path, + * as is commonly done by most resolvers, involves an enormous number of file system operations (for reference, + * each invocation of `fs.realpathSync.native` involves a series of `fs.readlinkSync` calls, up to one for each + * path segment in the input). + * + * @public + */ +export class RealNodeModulePathResolver { + /** + * Similar in function to `fs.realpathSync.native`, but assumes the only symlinks present are npm packages. + * + * @param input - A path to a file or directory, where the path separator is `${require('node:path').sep}` + * @returns The real path to the input, resolving the node_modules symlinks in the path + * @public + */ + public readonly realNodeModulePath: (input: string) => string; + + 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 { + fs: { lstatSync = nodeFs.lstatSync, readlinkSync = nodeFs.readlinkSync } = nodeFs, + path: { + isAbsolute = nodePath.isAbsolute, + join = nodePath.join, + resolve = nodePath.resolve, + sep = nodePath.sep + } = nodePath, + ignoreMissingPaths = false + } = options; + const cache: Map = (this._cache = new Map()); + this._errorCache = new Map(); + this._fs = { + lstatSync, + readlinkSync + }; + this._path = { + isAbsolute, + join, + resolve, + sep + }; + this._lstatOptions = { + throwIfNoEntry: !ignoreMissingPaths + }; + + const nodeModulesToken: string = `${sep}node_modules${sep}`; + const self: this = this; + + function realNodeModulePathInternal(input: string): string { + // Find the last node_modules path segment + const nodeModulesIndex: number = input.lastIndexOf(nodeModulesToken); + if (nodeModulesIndex < 0) { + // No node_modules in path, so we assume it is already the real path + return input; + } + + // First assume that the next path segment after node_modules is a symlink + let linkStart: number = nodeModulesIndex + nodeModulesToken.length - 1; + let linkEnd: number = input.indexOf(sep, linkStart + 1); + // If the path segment starts with a '@', then it is a scoped package + const isScoped: boolean = input.charAt(linkStart + 1) === '@'; + if (isScoped) { + // For a scoped package, the scope is an ordinary directory, so we need to find the next path segment + if (linkEnd < 0) { + // Symlink missing, so see if anything before the last node_modules needs resolving, + // and preserve the rest of the path + return join( + realNodeModulePathInternal(input.slice(0, nodeModulesIndex)), + input.slice(nodeModulesIndex + 1), + // Joining to `.` will clean up any extraneous trailing slashes + '.' + ); + } + + linkStart = linkEnd; + linkEnd = input.indexOf(sep, linkStart + 1); + } + + // No trailing separator, so the link is the last path segment + if (linkEnd < 0) { + linkEnd = input.length; + } + + const linkCandidate: string = input.slice(0, linkEnd); + // Check if the link is a symlink + const linkTarget: string | undefined = self._tryReadLink(linkCandidate); + if (linkTarget && isAbsolute(linkTarget)) { + // Absolute path, combine the link target with any remaining path segments + // Cache the resolution to avoid the readlink call in subsequent calls + cache.set(linkCandidate, linkTarget); + cache.set(linkTarget, linkTarget); + // Joining to `.` will clean up any extraneous trailing slashes + return join(linkTarget, input.slice(linkEnd + 1), '.'); + } + + // Relative path or does not exist + // Either way, the path before the last node_modules could itself be in a node_modules folder + // So resolve the base path to find out what paths are relative to + const realpathBeforeNodeModules: string = realNodeModulePathInternal(input.slice(0, nodeModulesIndex)); + if (linkTarget) { + // Relative path in symbolic link. Should be resolved relative to real path of base path. + const resolvedTarget: string = resolve( + realpathBeforeNodeModules, + input.slice(nodeModulesIndex + 1, linkStart), + linkTarget + ); + // Cache the result of the combined resolution to avoid the readlink call in subsequent calls + cache.set(linkCandidate, resolvedTarget); + cache.set(resolvedTarget, resolvedTarget); + // Joining to `.` will clean up any extraneous trailing slashes + return join(resolvedTarget, input.slice(linkEnd + 1), '.'); + } + + // No symlink, so just return the real path before the last node_modules combined with the + // subsequent path segments + // Joining to `.` will clean up any extraneous trailing slashes + return join(realpathBeforeNodeModules, input.slice(nodeModulesIndex + 1), '.'); + } + + this.realNodeModulePath = (input: string) => { + return realNodeModulePathInternal(resolve(input)); + }; + } + + /** + * Clears the cache of resolved symlinks. + * @public + */ + public clearCache(): void { + this._cache.clear(); + } + + /** + * Tries to read a symbolic link at the specified path. + * If the input is not a symbolic link, returns undefined. + * @param link - The link to try to read + * @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 | 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. + 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 7212a9fc3eb..2a719d7ffae 100644 --- a/libraries/node-core-library/src/Sort.ts +++ b/libraries/node-core-library/src/Sort.ts @@ -1,15 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { LegacyAdapters } from './LegacyAdapters'; - /** * Operations for sorting collections. * - * @remarks - * NOTE: Prior to Node 11.x, the `Array.sort()` algorithm is not guaranteed to be stable. For maximum - * compatibility, consider using {@link LegacyAdapters.sortStable} instead of `Array.sort()`. - * * @public */ export class Sort { @@ -45,10 +39,10 @@ export class Sort { } // Null is smaller than anything except undefined - if (x === null) { // eslint-disable-line @rushstack/no-null + if (x === null) { return -1; } - if (y === null) { // eslint-disable-line @rushstack/no-null + if (y === null) { return 1; } @@ -75,20 +69,31 @@ export class Sort { * Sort.sortBy(array, x => x.length); // [ 'c', 'bb', 'aaa' ] * ``` */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static sortBy(array: T[], keySelector: (element: T) => any, comparer: (x: any, y: any) => number - = Sort.compareByValue): void { - LegacyAdapters.sortStable(array, (x, y) => comparer(keySelector(x), keySelector(y))); + public static sortBy( + array: T[], + // eslint-disable-next-line @typescript-eslint/no-explicit-any + keySelector: (element: T) => any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + comparer: (x: any, y: any) => number = Sort.compareByValue + ): void { + array.sort((x, y) => comparer(keySelector(x), keySelector(y))); } /** - * Returns true if the array is already sorted. + * Returns true if the collection is already sorted. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static isSorted(array: T[], comparer: (x: any, y: any) => number = Sort.compareByValue): boolean { + public static isSorted( + collection: Iterable, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + comparer: (x: any, y: any) => number = Sort.compareByValue + ): boolean { + let isFirst: boolean = true; let previous: T | undefined = undefined; - for (const element of array) { - if (comparer(previous, element) > 0) { + for (const element of collection) { + if (isFirst) { + // Don't start by comparing against undefined. + isFirst = false; + } else if (comparer(previous, element) > 0) { return false; } previous = element; @@ -97,7 +102,7 @@ export class Sort { } /** - * Returns true if the array is already sorted by the specified key. + * Returns true if the collection is already sorted by the specified key. * * @example * @@ -106,14 +111,21 @@ export class Sort { * Sort.isSortedBy(array, x => x.length); // true * ``` */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static isSortedBy(array: T[], keySelector: (element: T) => any, comparer: (x: any, y: any) => number - = Sort.compareByValue): boolean { - + public static isSortedBy( + collection: Iterable, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + keySelector: (element: T) => any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + comparer: (x: any, y: any) => number = Sort.compareByValue + ): boolean { + let isFirst: boolean = true; let previousKey: T | undefined = undefined; - for (const element of array) { + for (const element of collection) { const key: T = keySelector(element); - if (comparer(previousKey, key) > 0) { + if (isFirst) { + // Don't start by comparing against undefined. + isFirst = false; + } else if (comparer(previousKey, key) > 0) { return false; } previousKey = key; @@ -136,16 +148,18 @@ 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): void { - const pairs: [K, V][] = Array.from(map.entries()); - + public static sortMapKeys( + map: Map, + keyComparer: (x: K, y: K) => number = Sort.compareByValue + ): void { // Sorting a map is expensive, so first check whether it's already sorted. - if (Sort.isSortedBy(pairs, x => x[0], keyComparer)) { + if (Sort.isSorted(map.keys(), keyComparer)) { return; } - Sort.sortBy(pairs, x => x[0], keyComparer); + const pairs: [K, V][] = Array.from(map.entries()); + + Sort.sortBy(pairs, (x) => x[0], keyComparer); map.clear(); for (const pair of pairs) { map.set(pair[0], pair[1]); @@ -167,18 +181,19 @@ export class Sort { * console.log(Array.from(set)); // ['c', 'bb', 'aaa'] * ``` */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public static sortSetBy(set: Set, keySelector: (element: T) => any, - keyComparer: (x: T, y: T) => number = Sort.compareByValue): void { - - const array: T[] = Array.from(set); - + public static sortSetBy( + set: Set, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + keySelector: (element: T) => any, + keyComparer: (x: T, y: T) => number = Sort.compareByValue + ): void { // Sorting a set is expensive, so first check whether it's already sorted. - if (Sort.isSortedBy(array, keySelector, keyComparer)) { + if (Sort.isSortedBy(set, keySelector, keyComparer)) { return; } - LegacyAdapters.sortStable(array, (x, y) => keyComparer(keySelector(x), keySelector(y))); + const array: T[] = Array.from(set); + array.sort((x, y) => keyComparer(keySelector(x), keySelector(y))); set.clear(); for (const item of array) { @@ -200,20 +215,74 @@ 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 { - const array: T[] = Array.from(set); - // Sorting a set is expensive, so first check whether it's already sorted. - if (Sort.isSorted(array, comparer)) { + if (Sort.isSorted(set, comparer)) { return; } - LegacyAdapters.sortStable(array, (x, y) => comparer(x, y)); + const array: T[] = Array.from(set); + array.sort((x, y) => comparer(x, y)); set.clear(); for (const item of array) { set.add(item); } } + + /** + * Sort the keys deeply given an object or an array. + * + * Doesn't handle cyclic reference. + * + * @param object - The object to be sorted + * + * @example + * + * ```ts + * console.log(Sort.sortKeys({ c: 3, b: 2, a: 1 })); // { a: 1, b: 2, c: 3} + * ``` + */ + public static sortKeys> | unknown[]>(object: T): T { + if (!isPlainObject(object) && !Array.isArray(object)) { + throw new TypeError(`Expected object or array`); + } + + return Array.isArray(object) ? (innerSortArray(object) as T) : (innerSortKeys(object) as T); + } +} + +function isPlainObject(obj: unknown): obj is object { + return obj !== null && typeof obj === 'object'; +} + +function innerSortArray(arr: unknown[]): unknown[] { + const result: unknown[] = []; + for (const entry of arr) { + if (Array.isArray(entry)) { + result.push(innerSortArray(entry)); + } else if (isPlainObject(entry)) { + result.push(innerSortKeys(entry)); + } else { + result.push(entry); + } + } + return result; +} + +function innerSortKeys(obj: Partial>): Partial> { + const result: Partial> = {}; + const keys: string[] = Object.keys(obj).sort(); + for (const key of keys) { + const value: unknown = obj[key]; + if (Array.isArray(value)) { + result[key] = innerSortArray(value); + } else if (isPlainObject(value)) { + result[key] = innerSortKeys(value); + } else { + result[key] = value; + } + } + + return result; } diff --git a/libraries/node-core-library/src/SubprocessTerminator.ts b/libraries/node-core-library/src/SubprocessTerminator.ts new file mode 100644 index 00000000000..0c256e6c7ba --- /dev/null +++ b/libraries/node-core-library/src/SubprocessTerminator.ts @@ -0,0 +1,249 @@ +// 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 'node:child_process'; +import process from 'node:process'; + +import { Executable } from './Executable'; + +/** + * Details about how the `child_process.ChildProcess` was created. + * + * @beta + */ +export interface ISubprocessOptions { + /** + * Whether or not the child process was started in detached mode. + * + * @remarks + * On POSIX systems, detached=true is required for killing the subtree. Attempting to kill the + * subtree on POSIX systems with detached=false will throw an error. On Windows, detached=true + * creates a separate console window and is not required for killing the subtree. In general, + * it is recommended to use SubprocessTerminator.RECOMMENDED_OPTIONS when forking or spawning + * a child process. + */ + detached: boolean; +} + +interface ITrackedSubprocess { + subprocess: child_process.ChildProcess; + subprocessOptions: ISubprocessOptions; +} + +/** + * When a child process is created, registering it with the SubprocessTerminator will ensure + * that the child gets terminated when the current process terminates. + * + * @remarks + * This works by hooking the current process's events for SIGTERM/SIGINT/exit, and ensuring the + * child process gets terminated in those cases. + * + * SubprocessTerminator doesn't do anything on Windows, since by default Windows automatically + * terminates child processes when their parent is terminated. + * + * @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. + */ + public static readonly RECOMMENDED_OPTIONS: ISubprocessOptions = { + detached: process.platform !== 'win32' + }; + + /** + * Registers a child process so that it will be terminated automatically if the current process + * is terminated. + */ + public static killProcessTreeOnExit( + subprocess: child_process.ChildProcess, + subprocessOptions: ISubprocessOptions + ): void { + if (typeof subprocess.exitCode === 'number') { + // Process has already been killed + return; + } + + SubprocessTerminator._validateSubprocessOptions(subprocessOptions); + + SubprocessTerminator._ensureInitialized(); + + // Closure variable + const pid: number | undefined = subprocess.pid; + if (pid === undefined) { + // The process failed to spawn. + return; + } + + subprocess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null): void => { + if (SubprocessTerminator._subprocessesByPid.delete(pid)) { + SubprocessTerminator._logDebug(`untracking #${pid}`); + } + }); + SubprocessTerminator._subprocessesByPid.set(pid, { + subprocess, + subprocessOptions + }); + + SubprocessTerminator._logDebug(`tracking #${pid}`); + } + + /** + * Terminate the child process and all of its children. + */ + public static killProcessTree( + subprocess: child_process.ChildProcess, + subprocessOptions: ISubprocessOptions + ): void { + const pid: number | undefined = subprocess.pid; + if (pid === undefined) { + // The process failed to spawn. + return; + } + + // Don't attempt to kill the same process twice + if (SubprocessTerminator._subprocessesByPid.delete(pid)) { + SubprocessTerminator._logDebug(`untracking #${pid} via killProcessTree()`); + } + + SubprocessTerminator._validateSubprocessOptions(subprocessOptions); + + if (typeof subprocess.exitCode === 'number') { + // Process has already been killed + return; + } + + SubprocessTerminator._logDebug(`terminating #${pid}`); + + if (SubprocessTerminator._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 + // kill the entire process tree. + const result: child_process.SpawnSyncReturns = Executable.spawnSync('TaskKill.exe', [ + '/T', // "Terminates the specified process and any child processes which were started by it." + '/F', // Without this, TaskKill will try to use WM_CLOSE which doesn't work with CLI tools + '/PID', + pid.toString() + ]); + + if (result.status) { + const output: string = result.output.join('\n'); + // Nonzero exit code + if (output.indexOf('not found') >= 0) { + // The PID does not exist + } else { + // Another error occurred, for example TaskKill.exe does not support + // the expected CLI syntax + throw new Error(`TaskKill.exe returned exit code ${result.status}:\n` + output + '\n'); + } + } + } else { + // Passing a negative PID terminates the entire group instead of just the one process + process.kill(-pid, 'SIGKILL'); + } + } + + // Install the hooks + private static _ensureInitialized(): void { + if (!SubprocessTerminator._initialized) { + SubprocessTerminator._initialized = true; + + SubprocessTerminator._logDebug('initialize'); + + process.prependListener('SIGTERM', SubprocessTerminator._onTerminateSignal); + process.prependListener('SIGINT', SubprocessTerminator._onTerminateSignal); + + process.prependListener('exit', SubprocessTerminator._onExit); + } + } + + // Uninstall the hooks and perform cleanup + private static _cleanupChildProcesses(): void { + if (SubprocessTerminator._initialized) { + SubprocessTerminator._initialized = false; + + process.removeListener('SIGTERM', SubprocessTerminator._onTerminateSignal); + process.removeListener('SIGINT', SubprocessTerminator._onTerminateSignal); + + const trackedSubprocesses: ITrackedSubprocess[] = Array.from( + SubprocessTerminator._subprocessesByPid.values() + ); + + 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; + } + } + } + + 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'); + } + } + } + + private static _onExit(exitCode: number): void { + SubprocessTerminator._logDebug(`received exit(${exitCode})`); + + SubprocessTerminator._cleanupChildProcesses(); + + SubprocessTerminator._logDebug(`finished exit()`); + } + + private static _onTerminateSignal(signal: string): void { + SubprocessTerminator._logDebug(`received signal ${signal}`); + + SubprocessTerminator._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); + } + + // 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); + } +} diff --git a/libraries/node-core-library/src/Terminal/Colors.ts b/libraries/node-core-library/src/Terminal/Colors.ts deleted file mode 100644 index efcb815875b..00000000000 --- a/libraries/node-core-library/src/Terminal/Colors.ts +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * @beta - */ -export interface IColorableSequence { - text: string; - isEol?: boolean; - foregroundColor?: ColorValue; - backgroundColor?: ColorValue; - textAttributes?: TextAttribute[]; -} - -export const eolSequence: IColorableSequence = { - isEol: true -} as IColorableSequence; - -/** - * Colors used with {@link IColorableSequence}. - * @beta - */ -export enum ColorValue { - Black, - Red, - Green, - Yellow, - Blue, - Magenta, - Cyan, - White, - Gray -} - -/** - * Text styles used with {@link IColorableSequence}. - * @beta - */ -export enum TextAttribute { - Bold, - Dim, - Underline, - Blink, - InvertColor, - Hidden -} - -/** - * The static functions on this class are used to produce colored text - * for use with the node-core-library terminal. - * - * @example - * terminal.writeLine(Colors.green('Green Text!'), ' ', Colors.blue('Blue Text!')); - * - * @beta - */ -export class Colors { - public static black(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Black - }; - } - - public static red(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Red - }; - } - - public static green(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Green - }; - } - - public static yellow(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Yellow - }; - } - - public static blue(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Blue - }; - } - - public static magenta(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Magenta - }; - } - - public static cyan(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Cyan - }; - } - - public static white(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.White - }; - } - - public static gray(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - foregroundColor: ColorValue.Gray - }; - } - - public static blackBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Black - }; - } - - public static redBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Red - }; - } - - public static greenBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Green - }; - } - - public static yellowBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Yellow - }; - } - - public static blueBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Blue - }; - } - - public static magentaBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Magenta - }; - } - - public static cyanBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Cyan - }; - } - - public static whiteBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.White - }; - } - - public static grayBackground(text: string | IColorableSequence): IColorableSequence { - return { - ...Colors._normalizeStringOrColorableSequence(text), - backgroundColor: ColorValue.Gray - }; - } - - public static bold(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.Bold); - } - - public static dim(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.Dim); - } - - public static underline(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.Underline); - } - - public static blink(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.Blink); - } - - public static invertColor(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.InvertColor); - } - - public static hidden(text: string | IColorableSequence): IColorableSequence { - return Colors._applyTextAttribute(text, TextAttribute.Hidden); - } - - /** - * If called with a string, returns the string wrapped in a {@link IColorableSequence}. - * If called with a {@link IColorableSequence}, returns the {@link IColorableSequence}. - * - * @internal - */ - public static _normalizeStringOrColorableSequence(value: string | IColorableSequence): IColorableSequence { - if (typeof value === 'string') { - return { - text: value - }; - } else { - return value; - } - } - - private static _applyTextAttribute(text: string | IColorableSequence, attribute: TextAttribute): IColorableSequence { - const sequence: IColorableSequence = Colors._normalizeStringOrColorableSequence(text); - if (!sequence.textAttributes) { - sequence.textAttributes = []; - } - - sequence.textAttributes.push(attribute); - return sequence; - } -} diff --git a/libraries/node-core-library/src/Terminal/ConsoleTerminalProvider.ts b/libraries/node-core-library/src/Terminal/ConsoleTerminalProvider.ts deleted file mode 100644 index dd8b6f9f839..00000000000 --- a/libraries/node-core-library/src/Terminal/ConsoleTerminalProvider.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { EOL } from 'os'; -import { enabled as supportsColor } from 'colors/safe'; - -import { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; - -/** - * Options to be provided to a {@link ConsoleTerminalProvider} - * - * @beta - */ -export interface IConsoleTerminalProviderOptions { - /** - * If true, print verbose logging messages - */ - verboseEnabled: boolean; -} - -/** - * Terminal provider that prints to STDOUT (for log- and verbose-level messages) and - * STDERR (for warning- and error-level messsages). - * - * @beta - */ -export class ConsoleTerminalProvider implements ITerminalProvider { - /** - * If true, verbose-level messages should be written to the console. - */ - public verboseEnabled: boolean = false; - - public constructor(options: Partial = {}) { - this.verboseEnabled = !!options.verboseEnabled; - } - - /** - * {@inheritDoc ITerminalProvider.write} - */ - public write(data: string, severity: TerminalProviderSeverity): void { - switch (severity) { - case TerminalProviderSeverity.warning: - case TerminalProviderSeverity.error: { - process.stderr.write(data); - break; - } - - case TerminalProviderSeverity.verbose: { - if (this.verboseEnabled) { - process.stdout.write(data); - } - break; - } - - case TerminalProviderSeverity.log: - default: { - process.stdout.write(data); - break; - } - } - } - - /** - * {@inheritDoc ITerminalProvider.eolCharacter} - */ - public get eolCharacter(): string { - return EOL; - } - - /** - * {@inheritDoc ITerminalProvider.supportsColor} - */ - public get supportsColor(): boolean { - return supportsColor; - } -} diff --git a/libraries/node-core-library/src/Terminal/ITerminalProvider.ts b/libraries/node-core-library/src/Terminal/ITerminalProvider.ts deleted file mode 100644 index 5d3add0ac27..00000000000 --- a/libraries/node-core-library/src/Terminal/ITerminalProvider.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @beta - */ -export enum TerminalProviderSeverity { - log, - warning, - error, - verbose -} - -/** - * Implement the interface to create a terminal provider. Terminal providers - * can be registered to a {@link Terminal} instance to receive messages. - * - * @beta - */ -export interface ITerminalProvider { - /** - * This property should return true only if the terminal provider supports - * rendering console colors. - */ - supportsColor: boolean; - - /** - * This property should return the newline character the terminal provider - * expects. - */ - eolCharacter: string; - - /** - * This function gets called on every terminal provider upon every - * message function call on the terminal instance. - * - * @param data - The terminal message. - * @param severity - The message severity. Terminal providers can - * route different kinds of messages to different streams and may choose - * to ignore verbose messages. - */ - write(data: string, severity: TerminalProviderSeverity): void; -} diff --git a/libraries/node-core-library/src/Terminal/StringBufferTerminalProvider.ts b/libraries/node-core-library/src/Terminal/StringBufferTerminalProvider.ts deleted file mode 100644 index 80ba82bf1d7..00000000000 --- a/libraries/node-core-library/src/Terminal/StringBufferTerminalProvider.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; -import { StringBuilder } from '../StringBuilder'; -import { Text } from '../Text'; - -/** - * Terminal provider that stores written data in buffers separated by severity. - * This terminal provider is designed to be used when code that prints to a terminal - * is being unit tested. - * - * @beta - */ -export class StringBufferTerminalProvider implements ITerminalProvider { - private _standardBuffer: StringBuilder = new StringBuilder(); - private _verboseBuffer: StringBuilder = new StringBuilder(); - private _warningBuffer: StringBuilder = new StringBuilder(); - private _errorBuffer: StringBuilder = new StringBuilder(); - - private _supportsColor: boolean; - - public constructor(supportsColor: boolean = false) { - this._supportsColor = supportsColor; - } - - /** - * {@inheritDoc ITerminalProvider.write} - */ - public write(data: string, severity: TerminalProviderSeverity): void { - switch (severity) { - case TerminalProviderSeverity.warning: { - this._warningBuffer.append(data); - break; - } - - case TerminalProviderSeverity.error: { - this._errorBuffer.append(data); - break; - } - - case TerminalProviderSeverity.verbose: { - this._verboseBuffer.append(data); - break; - } - - case TerminalProviderSeverity.log: - default: { - this._standardBuffer.append(data); - break; - } - } - } - - /** - * {@inheritDoc ITerminalProvider.eolCharacter} - */ - public get eolCharacter(): string { - return '[n]'; - } - - /** - * {@inheritDoc ITerminalProvider.supportsColor} - */ - public get supportsColor(): boolean { - return this._supportsColor; - } - - /** - * Get everything that has been written at log-level severity. - */ - public getOutput(): string { - return this._normalizeOutput(this._standardBuffer.toString()); - } - - /** - * Get everything that has been written at verbose-level severity. - */ - public getVerbose(): string { - return this._normalizeOutput(this._verboseBuffer.toString()); - } - - /** - * Get everything that has been written at error-level severity. - */ - public getErrorOutput(): string { - return this._normalizeOutput(this._errorBuffer.toString()); - } - - /** - * Get everything that has been written at warning-level severity. - */ - public getWarningOutput(): string { - return this._normalizeOutput(this._warningBuffer.toString()); - } - - private _normalizeOutput(s: string): string { - return Text.convertToLf(s) - .replace(/\u001b/g, '[x]') // eslint-disable-line no-control-regex - .replace(/\n/g, '[-n-]') - .replace(/\r/g, '[-r-]'); - } -} diff --git a/libraries/node-core-library/src/Terminal/Terminal.ts b/libraries/node-core-library/src/Terminal/Terminal.ts deleted file mode 100644 index 85f8260e223..00000000000 --- a/libraries/node-core-library/src/Terminal/Terminal.ts +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - ITerminalProvider, - TerminalProviderSeverity -} from './ITerminalProvider'; -import { - IColorableSequence, - ColorValue, - Colors, - eolSequence, - TextAttribute -} from './Colors'; - -/** - * This class facilitates writing to a console. - * - * @beta - */ -export class Terminal { - private _providers: Set; - - public constructor(provider: ITerminalProvider) { - this._providers = new Set(); - this._providers.add(provider); - } - - /** - * Subscribe a new terminal provider. - */ - public registerProvider(provider: ITerminalProvider): void { - this._providers.add(provider); - } - - /** - * Unsubscribe a terminal provider. If the provider isn't subscribed, this function does nothing. - */ - public unregisterProvider(provider: ITerminalProvider): void { - if (this._providers.has(provider)) { - this._providers.delete(provider); - } - } - - /** - * Write a generic message to the terminal - */ - public write(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders(messageParts, TerminalProviderSeverity.log); - } - - /** - * Write a generic message to the terminal, followed by a newline - */ - public writeLine(...messageParts: (string | IColorableSequence)[]): void { - this.write(...messageParts, eolSequence); - } - - /** - * Write a warning message to the console with yellow text. - * - * @remarks - * The yellow color takes precedence over any other foreground colors set. - */ - public writeWarning(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders( - messageParts.map( - (part): IColorableSequence => ({ - ...Colors._normalizeStringOrColorableSequence(part), - foregroundColor: ColorValue.Yellow - }) - ), - TerminalProviderSeverity.warning - ); - } - - /** - * Write a warning message to the console with yellow text, followed by a newline. - * - * @remarks - * The yellow color takes precedence over any other foreground colors set. - */ - public writeWarningLine(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders( - [ - ...messageParts.map( - (part): IColorableSequence => ({ - ...Colors._normalizeStringOrColorableSequence(part), - foregroundColor: ColorValue.Yellow - }) - ), - eolSequence - ], - TerminalProviderSeverity.warning - ); - } - - /** - * Write an error message to the console with red text. - * - * @remarks - * The red color takes precedence over any other foreground colors set. - */ - public writeError(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders( - messageParts.map( - (part): IColorableSequence => ({ - ...Colors._normalizeStringOrColorableSequence(part), - foregroundColor: ColorValue.Red - }) - ), - TerminalProviderSeverity.error - ); - } - - /** - * Write an error message to the console with red text, followed by a newline. - * - * @remarks - * The red color takes precedence over any other foreground colors set. - */ - public writeErrorLine(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders( - [ - ...messageParts.map( - (part): IColorableSequence => ({ - ...Colors._normalizeStringOrColorableSequence(part), - foregroundColor: ColorValue.Red - }) - ), - eolSequence - ], - TerminalProviderSeverity.error - ); - } - - /** - * Write a verbose-level message. - */ - public writeVerbose(...messageParts: (string | IColorableSequence)[]): void { - this._writeSegmentsToProviders(messageParts, TerminalProviderSeverity.verbose); - } - - /** - * Write a verbose-level message followed by a newline. - */ - public writeVerboseLine(...messageParts: (string | IColorableSequence)[]): void { - this.writeVerbose(...messageParts, eolSequence); - } - - private _writeSegmentsToProviders( - segments: (string | IColorableSequence)[], - severity: TerminalProviderSeverity - ): void { - const withColorText: { [eolChar: string]: string } = {}; - const withoutColorText: { [eolChar: string]: string } = {}; - let withColorLines: string[] | undefined; - let withoutColorLines: string[] | undefined; - - this._providers.forEach((provider) => { - const eol: string = provider.eolCharacter; - let textToWrite: string; - if (provider.supportsColor) { - if (!withColorLines) { - withColorLines = this._serializeFormattableTextSegments(segments, true); - } - - if (!withColorText[eol]) { - withColorText[eol] = withColorLines.join(eol); - } - - textToWrite = withColorText[eol]; - } else { - if (!withoutColorLines) { - withoutColorLines = this._serializeFormattableTextSegments(segments, false); - } - - if (!withoutColorText[eol]) { - withoutColorText[eol] = withoutColorLines.join(eol); - } - - textToWrite = withoutColorText[eol]; - } - - provider.write(textToWrite, severity); - }); - } - - private _serializeFormattableTextSegments(segments: (string | IColorableSequence)[], withColor: boolean): string[] { - const lines: string[] = []; - let segmentsToJoin: string[] = []; - let lastSegmentWasEol: boolean = false; - for (let i: number = 0; i < segments.length; i++) { - const segment: IColorableSequence = Colors._normalizeStringOrColorableSequence(segments[i]); - lastSegmentWasEol = !!segment.isEol; - if (lastSegmentWasEol) { - lines.push(segmentsToJoin.join('')); - segmentsToJoin = []; - } else { - - if (withColor) { - const startColorCodes: number[] = []; - const endColorCodes: number[] = []; - switch (segment.foregroundColor) { - case ColorValue.Black: { - startColorCodes.push(30); - endColorCodes.push(39); - break; - } - - case ColorValue.Red: { - startColorCodes.push(31); - endColorCodes.push(39); - break; - } - - case ColorValue.Green: { - startColorCodes.push(32); - endColorCodes.push(39); - break; - } - - case ColorValue.Yellow: { - startColorCodes.push(33); - endColorCodes.push(39); - break; - } - - case ColorValue.Blue: { - startColorCodes.push(34); - endColorCodes.push(39); - break; - } - - case ColorValue.Magenta: { - startColorCodes.push(35); - endColorCodes.push(39); - break; - } - - case ColorValue.Cyan: { - startColorCodes.push(36); - endColorCodes.push(39); - break; - } - - case ColorValue.White: { - startColorCodes.push(37); - endColorCodes.push(39); - break; - } - - case ColorValue.Gray: { - startColorCodes.push(90); - endColorCodes.push(39); - break; - } - } - - switch (segment.backgroundColor) { - case ColorValue.Black: { - startColorCodes.push(40); - endColorCodes.push(49); - break; - } - - case ColorValue.Red: { - startColorCodes.push(41); - endColorCodes.push(49); - break; - } - - case ColorValue.Green: { - startColorCodes.push(42); - endColorCodes.push(49); - break; - } - - case ColorValue.Yellow: { - startColorCodes.push(43); - endColorCodes.push(49); - break; - } - - case ColorValue.Blue: { - startColorCodes.push(44); - endColorCodes.push(49); - break; - } - - case ColorValue.Magenta: { - startColorCodes.push(45); - endColorCodes.push(49); - break; - } - - case ColorValue.Cyan: { - startColorCodes.push(46); - endColorCodes.push(49); - break; - } - - case ColorValue.White: { - startColorCodes.push(47); - endColorCodes.push(49); - break; - } - - case ColorValue.Gray: { - startColorCodes.push(100); - endColorCodes.push(49); - break; - } - } - - if (segment.textAttributes) { - for (const textAttribute of segment.textAttributes) { - switch (textAttribute) { - case TextAttribute.Bold: { - startColorCodes.push(1); - endColorCodes.push(21); - break; - } - - case TextAttribute.Dim: { - startColorCodes.push(2); - endColorCodes.push(22); - break; - } - - case TextAttribute.Underline: { - startColorCodes.push(4); - endColorCodes.push(24); - break; - } - - case TextAttribute.Blink: { - startColorCodes.push(5); - endColorCodes.push(25); - break; - } - - case TextAttribute.InvertColor: { - startColorCodes.push(7); - endColorCodes.push(27); - break; - } - - case TextAttribute.Hidden: { - startColorCodes.push(8); - endColorCodes.push(28); - break; - } - } - } - } - - for (let j: number = 0; j < startColorCodes.length; j++) { - const code: number = startColorCodes[j]; - segmentsToJoin.push(...[ - '\u001b[', - code.toString(), - 'm' - ]); - } - - segmentsToJoin.push(segment.text); - - for (let j: number = endColorCodes.length - 1; j >= 0; j--) { - const code: number = endColorCodes[j]; - segmentsToJoin.push(...[ - '\u001b[', - code.toString(), - 'm' - ]); - } - } else { - segmentsToJoin.push(segment.text); - } - } - } - - if (segmentsToJoin.length > 0) { - lines.push(segmentsToJoin.join('')); - } - - if (lastSegmentWasEol) { - lines.push(''); - } - - return lines; - } -} diff --git a/libraries/node-core-library/src/Terminal/test/Colors.test.ts b/libraries/node-core-library/src/Terminal/test/Colors.test.ts deleted file mode 100644 index 77e7e3f6d98..00000000000 --- a/libraries/node-core-library/src/Terminal/test/Colors.test.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. - -import { Terminal } from '../Terminal'; -import { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; -import { createColorGrid } from './createColorGrid'; - -describe('Colors', () => { - let terminal: Terminal; - let provider: StringBufferTerminalProvider; - - beforeEach(() => { - provider = new StringBufferTerminalProvider(true); - terminal = new Terminal(provider); - }); - - test('writes color grid correctly', () => { - for (const line of createColorGrid()) { - terminal.writeLine(...line); - } - - expect(provider.getOutput()).toMatchSnapshot(); - }); -}); diff --git a/libraries/node-core-library/src/Terminal/test/Terminal.test.ts b/libraries/node-core-library/src/Terminal/test/Terminal.test.ts deleted file mode 100644 index b0bd0247dbd..00000000000 --- a/libraries/node-core-library/src/Terminal/test/Terminal.test.ts +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Terminal } from '../Terminal'; -import { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; -import { Colors } from '../Colors'; - -let terminal: Terminal; -let provider: StringBufferTerminalProvider; - -function verifyProvider(): void { - expect({ - log: provider.getOutput(), - warning: provider.getWarningOutput(), - error: provider.getErrorOutput(), - verbose: provider.getVerbose() - }).toMatchSnapshot(); -} - -describe('01 color enabled', () => { - beforeEach(() => { - provider = new StringBufferTerminalProvider(true); - terminal = new Terminal(provider); - }); - - describe('01 basic terminal functions', () => { - describe('01 write', () => { - test('01 writes a single message', () => { - terminal.write('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.write('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.write(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.write(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.write('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('02 writeLine', () => { - test('01 writes a single message', () => { - terminal.writeLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('03 writeWarning', () => { - test('01 writes a single message', () => { - terminal.writeWarning('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeWarning('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeWarning(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeWarning(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeWarning('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('04 writeWarningLine', () => { - test('01 writes a single message', () => { - terminal.writeWarningLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeWarningLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeWarningLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeWarningLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeWarningLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('05 writeError', () => { - test('01 writes a single message', () => { - terminal.writeError('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeError('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeError(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeError(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeError('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('06 writeErrorLine', () => { - test('01 writes a single message', () => { - terminal.writeErrorLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeErrorLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeErrorLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeErrorLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeErrorLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('07 writeVerbose', () => { - test('01 writes a single message', () => { - terminal.writeVerbose('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeVerbose('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeVerbose(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeVerbose(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeVerbose('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('08 writeVerboseLine', () => { - test('01 writes a single message', () => { - terminal.writeVerboseLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeVerboseLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeVerboseLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeVerboseLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeVerboseLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - }); - - test('05 writes to multiple streams', () => { - terminal.write('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeWarningLine('message 1', 'message 2'); - terminal.writeVerbose('test message'); - terminal.writeVerbose(Colors.green('message 1')); - terminal.writeLine(Colors.green('message 1')); - terminal.writeError('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeErrorLine('test message'); - terminal.writeVerboseLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeVerboseLine('test message'); - terminal.writeWarning(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarning('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeError('message 1', 'message 2'); - terminal.write(Colors.green('message 1')); - terminal.writeVerbose('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeErrorLine('message 1', 'message 2'); - terminal.write(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeVerbose('message 1', 'message 2'); - terminal.writeVerboseLine(Colors.green('message 1')); - terminal.writeLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeError(Colors.green('message 1')); - terminal.writeWarningLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.write('test message'); - terminal.writeWarningLine('test message'); - terminal.writeVerboseLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeVerboseLine('message 1', 'message 2'); - terminal.writeErrorLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeWarning('message 1', 'message 2'); - terminal.writeErrorLine(Colors.green('message 1')); - terminal.write('message 1', 'message 2'); - terminal.writeVerbose(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarning(Colors.green('message 1')); - terminal.writeLine('test message'); - terminal.writeError('test message'); - terminal.writeLine('message 1', 'message 2'); - terminal.writeErrorLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeError(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarningLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarningLine(Colors.green('message 1')); - verifyProvider(); - }); -}); - -describe('02 color disabled', () => { - beforeEach(() => { - provider = new StringBufferTerminalProvider(false); - terminal = new Terminal(provider); - }); - - describe('01 basic terminal functions', () => { - describe('01 write', () => { - test('01 writes a single message', () => { - terminal.write('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.write('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.write(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.write(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.write('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('02 writeLine', () => { - test('01 writes a single message', () => { - terminal.writeLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('03 writeWarning', () => { - test('01 writes a single message', () => { - terminal.writeWarning('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeWarning('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeWarning(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeWarning(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeWarning('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('04 writeWarningLine', () => { - test('01 writes a single message', () => { - terminal.writeWarningLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeWarningLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeWarningLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeWarningLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeWarningLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('05 writeError', () => { - test('01 writes a single message', () => { - terminal.writeError('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeError('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeError(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeError(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeError('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('06 writeErrorLine', () => { - test('01 writes a single message', () => { - terminal.writeErrorLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeErrorLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeErrorLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeErrorLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeErrorLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('07 writeVerbose', () => { - test('01 writes a single message', () => { - terminal.writeVerbose('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeVerbose('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeVerbose(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeVerbose(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeVerbose('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - - describe('08 writeVerboseLine', () => { - test('01 writes a single message', () => { - terminal.writeVerboseLine('test message'); - verifyProvider(); - }); - - test('02 writes multiple messages', () => { - terminal.writeVerboseLine('message 1', 'message 2'); - verifyProvider(); - }); - - test('03 writes a message with colors', () => { - terminal.writeVerboseLine(Colors.green('message 1')); - verifyProvider(); - }); - - test('04 writes a multiple messages with colors', () => { - terminal.writeVerboseLine(Colors.green('message 1'), Colors.red('message 2')); - verifyProvider(); - }); - - test('05 writes a messages with colors interspersed with non-colored messages', () => { - terminal.writeVerboseLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - verifyProvider(); - }); - }); - }); - - test('05 writes to multiple streams', () => { - terminal.write('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeWarningLine('message 1', 'message 2'); - terminal.writeVerbose('test message'); - terminal.writeVerbose(Colors.green('message 1')); - terminal.writeLine(Colors.green('message 1')); - terminal.writeError('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeErrorLine('test message'); - terminal.writeVerboseLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeVerboseLine('test message'); - terminal.writeWarning(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarning('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeError('message 1', 'message 2'); - terminal.write(Colors.green('message 1')); - terminal.writeVerbose('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeErrorLine('message 1', 'message 2'); - terminal.write(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeVerbose('message 1', 'message 2'); - terminal.writeVerboseLine(Colors.green('message 1')); - terminal.writeLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeError(Colors.green('message 1')); - terminal.writeWarningLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.write('test message'); - terminal.writeWarningLine('test message'); - terminal.writeVerboseLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeVerboseLine('message 1', 'message 2'); - terminal.writeErrorLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeLine('message 1', Colors.green('message 2'), 'message 3', Colors.red('message 4')); - terminal.writeWarning('message 1', 'message 2'); - terminal.writeErrorLine(Colors.green('message 1')); - terminal.write('message 1', 'message 2'); - terminal.writeVerbose(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarning(Colors.green('message 1')); - terminal.writeLine('test message'); - terminal.writeError('test message'); - terminal.writeLine('message 1', 'message 2'); - terminal.writeErrorLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeError(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarningLine(Colors.green('message 1'), Colors.red('message 2')); - terminal.writeWarningLine(Colors.green('message 1')); - verifyProvider(); - }); -}); diff --git a/libraries/node-core-library/src/Terminal/test/__snapshots__/Colors.test.ts.snap b/libraries/node-core-library/src/Terminal/test/__snapshots__/Colors.test.ts.snap deleted file mode 100644 index c81fdc1cc97..00000000000 --- a/libraries/node-core-library/src/Terminal/test/__snapshots__/Colors.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Colors writes color grid correctly 1`] = `"X[x][30mX[x][39m[x][37mX[x][39m[x][90mX[x][39m[x][35mX[x][39m[x][31mX[x][39m[x][33mX[x][39m[x][32mX[x][39m[x][36mX[x][39m[x][34mX[x][39m[n][x][40mX[x][49m[x][30m[x][40mX[x][49m[x][39m[x][37m[x][40mX[x][49m[x][39m[x][90m[x][40mX[x][49m[x][39m[x][35m[x][40mX[x][49m[x][39m[x][31m[x][40mX[x][49m[x][39m[x][33m[x][40mX[x][49m[x][39m[x][32m[x][40mX[x][49m[x][39m[x][36m[x][40mX[x][49m[x][39m[x][34m[x][40mX[x][49m[x][39m[n][x][47mX[x][49m[x][30m[x][47mX[x][49m[x][39m[x][37m[x][47mX[x][49m[x][39m[x][90m[x][47mX[x][49m[x][39m[x][35m[x][47mX[x][49m[x][39m[x][31m[x][47mX[x][49m[x][39m[x][33m[x][47mX[x][49m[x][39m[x][32m[x][47mX[x][49m[x][39m[x][36m[x][47mX[x][49m[x][39m[x][34m[x][47mX[x][49m[x][39m[n][x][100mX[x][49m[x][30m[x][100mX[x][49m[x][39m[x][37m[x][100mX[x][49m[x][39m[x][90m[x][100mX[x][49m[x][39m[x][35m[x][100mX[x][49m[x][39m[x][31m[x][100mX[x][49m[x][39m[x][33m[x][100mX[x][49m[x][39m[x][32m[x][100mX[x][49m[x][39m[x][36m[x][100mX[x][49m[x][39m[x][34m[x][100mX[x][49m[x][39m[n][x][45mX[x][49m[x][30m[x][45mX[x][49m[x][39m[x][37m[x][45mX[x][49m[x][39m[x][90m[x][45mX[x][49m[x][39m[x][35m[x][45mX[x][49m[x][39m[x][31m[x][45mX[x][49m[x][39m[x][33m[x][45mX[x][49m[x][39m[x][32m[x][45mX[x][49m[x][39m[x][36m[x][45mX[x][49m[x][39m[x][34m[x][45mX[x][49m[x][39m[n][x][41mX[x][49m[x][30m[x][41mX[x][49m[x][39m[x][37m[x][41mX[x][49m[x][39m[x][90m[x][41mX[x][49m[x][39m[x][35m[x][41mX[x][49m[x][39m[x][31m[x][41mX[x][49m[x][39m[x][33m[x][41mX[x][49m[x][39m[x][32m[x][41mX[x][49m[x][39m[x][36m[x][41mX[x][49m[x][39m[x][34m[x][41mX[x][49m[x][39m[n][x][43mX[x][49m[x][30m[x][43mX[x][49m[x][39m[x][37m[x][43mX[x][49m[x][39m[x][90m[x][43mX[x][49m[x][39m[x][35m[x][43mX[x][49m[x][39m[x][31m[x][43mX[x][49m[x][39m[x][33m[x][43mX[x][49m[x][39m[x][32m[x][43mX[x][49m[x][39m[x][36m[x][43mX[x][49m[x][39m[x][34m[x][43mX[x][49m[x][39m[n][x][42mX[x][49m[x][30m[x][42mX[x][49m[x][39m[x][37m[x][42mX[x][49m[x][39m[x][90m[x][42mX[x][49m[x][39m[x][35m[x][42mX[x][49m[x][39m[x][31m[x][42mX[x][49m[x][39m[x][33m[x][42mX[x][49m[x][39m[x][32m[x][42mX[x][49m[x][39m[x][36m[x][42mX[x][49m[x][39m[x][34m[x][42mX[x][49m[x][39m[n][x][46mX[x][49m[x][30m[x][46mX[x][49m[x][39m[x][37m[x][46mX[x][49m[x][39m[x][90m[x][46mX[x][49m[x][39m[x][35m[x][46mX[x][49m[x][39m[x][31m[x][46mX[x][49m[x][39m[x][33m[x][46mX[x][49m[x][39m[x][32m[x][46mX[x][49m[x][39m[x][36m[x][46mX[x][49m[x][39m[x][34m[x][46mX[x][49m[x][39m[n][x][44mX[x][49m[x][30m[x][44mX[x][49m[x][39m[x][37m[x][44mX[x][49m[x][39m[x][90m[x][44mX[x][49m[x][39m[x][35m[x][44mX[x][49m[x][39m[x][31m[x][44mX[x][49m[x][39m[x][33m[x][44mX[x][49m[x][39m[x][32m[x][44mX[x][49m[x][39m[x][36m[x][44mX[x][49m[x][39m[x][34m[x][44mX[x][49m[x][39m[n]"`; diff --git a/libraries/node-core-library/src/Terminal/test/__snapshots__/Terminal.test.ts.snap b/libraries/node-core-library/src/Terminal/test/__snapshots__/Terminal.test.ts.snap deleted file mode 100644 index 9c1c42e8e3f..00000000000 --- a/libraries/node-core-library/src/Terminal/test/__snapshots__/Terminal.test.ts.snap +++ /dev/null @@ -1,739 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`01 color enabled 01 basic terminal functions 01 write 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "test message", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 01 write 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 01 write 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "[x][32mmessage 1[x][39m", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 01 write 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 01 write 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 02 writeLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "test message[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 02 writeLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 02 writeLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "[x][32mmessage 1[x][39m[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 02 writeLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 02 writeLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 03 writeWarning 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mtest message[x][39m", -} -`; - -exports[`01 color enabled 01 basic terminal functions 03 writeWarning 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m", -} -`; - -exports[`01 color enabled 01 basic terminal functions 03 writeWarning 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m", -} -`; - -exports[`01 color enabled 01 basic terminal functions 03 writeWarning 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m", -} -`; - -exports[`01 color enabled 01 basic terminal functions 03 writeWarning 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 3[x][39m[x][33mmessage 4[x][39m", -} -`; - -exports[`01 color enabled 01 basic terminal functions 04 writeWarningLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mtest message[x][39m[n]", -} -`; - -exports[`01 color enabled 01 basic terminal functions 04 writeWarningLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[n]", -} -`; - -exports[`01 color enabled 01 basic terminal functions 04 writeWarningLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[n]", -} -`; - -exports[`01 color enabled 01 basic terminal functions 04 writeWarningLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[n]", -} -`; - -exports[`01 color enabled 01 basic terminal functions 04 writeWarningLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 3[x][39m[x][33mmessage 4[x][39m[n]", -} -`; - -exports[`01 color enabled 01 basic terminal functions 05 writeError 01 writes a single message 1`] = ` -Object { - "error": "[x][31mtest message[x][39m", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 05 writeError 02 writes multiple messages 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 05 writeError 03 writes a message with colors 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 05 writeError 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 05 writeError 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[x][31mmessage 3[x][39m[x][31mmessage 4[x][39m", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 06 writeErrorLine 01 writes a single message 1`] = ` -Object { - "error": "[x][31mtest message[x][39m[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 06 writeErrorLine 02 writes multiple messages 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 06 writeErrorLine 03 writes a message with colors 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 06 writeErrorLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 06 writeErrorLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[x][31mmessage 3[x][39m[x][31mmessage 4[x][39m[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 07 writeVerbose 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "test message", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 07 writeVerbose 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 07 writeVerbose 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "[x][32mmessage 1[x][39m", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 07 writeVerbose 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 07 writeVerbose 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 08 writeVerboseLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "test message[n]", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 08 writeVerboseLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2[n]", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 08 writeVerboseLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "[x][32mmessage 1[x][39m[n]", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 08 writeVerboseLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m[n]", - "warning": "", -} -`; - -exports[`01 color enabled 01 basic terminal functions 08 writeVerboseLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m[n]", - "warning": "", -} -`; - -exports[`01 color enabled 05 writes to multiple streams 1`] = ` -Object { - "error": "[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[x][31mmessage 3[x][39m[x][31mmessage 4[x][39m[x][31mtest message[x][39m[n][x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[n][x][31mmessage 1[x][39m[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[x][31mmessage 3[x][39m[x][31mmessage 4[x][39m[n][x][31mmessage 1[x][39m[n][x][31mtest message[x][39m[x][31mmessage 1[x][39m[x][31mmessage 2[x][39m[n][x][31mmessage 1[x][39m[x][31mmessage 2[x][39m", - "log": "message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m[x][32mmessage 1[x][39m[n][x][32mmessage 1[x][39m[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m[x][32mmessage 1[x][39m[x][31mmessage 2[x][39m[n]test messagemessage 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m[n]message 1message 2test message[n]message 1message 2[n]", - "verbose": "test message[x][32mmessage 1[x][39mmessage 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39m[n]test message[n]message 1[x][32mmessage 2[x][39mmessage 3[x][31mmessage 4[x][39mmessage 1message 2[x][32mmessage 1[x][39m[n][x][32mmessage 1[x][39m[x][31mmessage 2[x][39m[n]message 1message 2[n][x][32mmessage 1[x][39m[x][31mmessage 2[x][39m", - "warning": "[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[n][x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 3[x][39m[x][33mmessage 4[x][39m[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 3[x][39m[x][33mmessage 4[x][39m[n][x][33mtest message[x][39m[n][x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[x][33mmessage 1[x][39m[x][33mmessage 1[x][39m[x][33mmessage 2[x][39m[n][x][33mmessage 1[x][39m[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 01 write 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "test message", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 01 write 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 01 write 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "message 1", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 01 write 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "message 1message 2", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 01 write 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2message 3message 4", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 02 writeLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "test message[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 02 writeLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 02 writeLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "message 1[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 02 writeLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "message 1message 2[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 02 writeLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "message 1message 2message 3message 4[n]", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 03 writeWarning 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "test message", -} -`; - -exports[`02 color disabled 01 basic terminal functions 03 writeWarning 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2", -} -`; - -exports[`02 color disabled 01 basic terminal functions 03 writeWarning 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1", -} -`; - -exports[`02 color disabled 01 basic terminal functions 03 writeWarning 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2", -} -`; - -exports[`02 color disabled 01 basic terminal functions 03 writeWarning 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2message 3message 4", -} -`; - -exports[`02 color disabled 01 basic terminal functions 04 writeWarningLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "test message[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 04 writeWarningLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 04 writeWarningLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 04 writeWarningLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 04 writeWarningLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "", - "warning": "message 1message 2message 3message 4[n]", -} -`; - -exports[`02 color disabled 01 basic terminal functions 05 writeError 01 writes a single message 1`] = ` -Object { - "error": "test message", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 05 writeError 02 writes multiple messages 1`] = ` -Object { - "error": "message 1message 2", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 05 writeError 03 writes a message with colors 1`] = ` -Object { - "error": "message 1", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 05 writeError 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "message 1message 2", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 05 writeError 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "message 1message 2message 3message 4", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 06 writeErrorLine 01 writes a single message 1`] = ` -Object { - "error": "test message[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 06 writeErrorLine 02 writes multiple messages 1`] = ` -Object { - "error": "message 1message 2[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 06 writeErrorLine 03 writes a message with colors 1`] = ` -Object { - "error": "message 1[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 06 writeErrorLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "message 1message 2[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 06 writeErrorLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "message 1message 2message 3message 4[n]", - "log": "", - "verbose": "", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 07 writeVerbose 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "test message", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 07 writeVerbose 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 07 writeVerbose 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 07 writeVerbose 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 07 writeVerbose 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2message 3message 4", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 08 writeVerboseLine 01 writes a single message 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "test message[n]", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 08 writeVerboseLine 02 writes multiple messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2[n]", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 08 writeVerboseLine 03 writes a message with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1[n]", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 08 writeVerboseLine 04 writes a multiple messages with colors 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2[n]", - "warning": "", -} -`; - -exports[`02 color disabled 01 basic terminal functions 08 writeVerboseLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` -Object { - "error": "", - "log": "", - "verbose": "message 1message 2message 3message 4[n]", - "warning": "", -} -`; - -exports[`02 color disabled 05 writes to multiple streams 1`] = ` -Object { - "error": "message 1message 2message 3message 4test message[n]message 1message 2message 1message 2[n]message 1message 1message 2message 3message 4[n]message 1[n]test messagemessage 1message 2[n]message 1message 2", - "log": "message 1message 2message 3message 4message 1[n]message 1message 1message 2message 1message 2[n]test messagemessage 1message 2message 3message 4[n]message 1message 2test message[n]message 1message 2[n]", - "verbose": "test messagemessage 1message 1message 2message 3message 4[n]test message[n]message 1message 2message 3message 4message 1message 2message 1[n]message 1message 2[n]message 1message 2[n]message 1message 2", - "warning": "message 1message 2[n]message 1message 2message 1message 2message 3message 4message 1message 2message 3message 4[n]test message[n]message 1message 2message 1message 1message 2[n]message 1[n]", -} -`; diff --git a/libraries/node-core-library/src/Terminal/test/createColorGrid.ts b/libraries/node-core-library/src/Terminal/test/createColorGrid.ts deleted file mode 100644 index bb1d01a5e47..00000000000 --- a/libraries/node-core-library/src/Terminal/test/createColorGrid.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * This file is a little program that prints all of the colors to the console - */ - -import { - Colors, - IColorableSequence -} from '../../index'; - -export function createColorGrid( - attributeFunction?: (text: string | IColorableSequence) => IColorableSequence -): IColorableSequence[][] { - const foregroundFunctions: ((text: string | IColorableSequence) => IColorableSequence)[] = [ - (text) => Colors._normalizeStringOrColorableSequence(text), - Colors.black, - Colors.white, - Colors.gray, - Colors.magenta, - Colors.red, - Colors.yellow, - Colors.green, - Colors.cyan, - Colors.blue - ]; - - const backgroundFunctions: ((text: string | IColorableSequence) => IColorableSequence)[] = [ - (text) => Colors._normalizeStringOrColorableSequence(text), - Colors.blackBackground, - Colors.whiteBackground, - Colors.grayBackground, - Colors.magentaBackground, - Colors.redBackground, - Colors.yellowBackground, - Colors.greenBackground, - Colors.cyanBackground, - Colors.blueBackground - ]; - - const lines: IColorableSequence[][] = []; - - for (const backgroundFunction of backgroundFunctions) { - const sequences: IColorableSequence[] = []; - - for (const foregroundFunction of foregroundFunctions) { - let sequence: IColorableSequence = backgroundFunction(foregroundFunction('X')); - if (attributeFunction) { - sequence = attributeFunction(sequence); - } - - sequences.push(sequence); - } - - lines.push(sequences); - } - - return lines; -} diff --git a/libraries/node-core-library/src/Terminal/test/write-colors.ts b/libraries/node-core-library/src/Terminal/test/write-colors.ts deleted file mode 100644 index 72006c25b5e..00000000000 --- a/libraries/node-core-library/src/Terminal/test/write-colors.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * This file is a little program that prints all of the colors to the console. - * - * Run this program with `node write-colors.js` - */ - -import { - Terminal, - ConsoleTerminalProvider -} from '../../index'; -import { createColorGrid } from './createColorGrid'; -import { Colors, IColorableSequence } from '../Colors'; - -const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); -function writeColorGrid(colorGridSequences: IColorableSequence[][]): void { - for (const line of colorGridSequences) { - terminal.writeLine(...line); - } -} - -writeColorGrid(createColorGrid()); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.bold)); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.dim)); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.underline)); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.blink)); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.invertColor)); -terminal.writeLine(); -writeColorGrid(createColorGrid(Colors.hidden)); -terminal.writeLine(); - -terminal.write('Normal text...'); -terminal.writeLine(Colors.green('done')); - -terminal.writeError('Error...'); -terminal.writeErrorLine(Colors.green('done')); - -terminal.writeWarning('Warning...'); -terminal.writeWarningLine(Colors.green('done')); diff --git a/libraries/node-core-library/src/Text.ts b/libraries/node-core-library/src/Text.ts index a7099c52d3e..4630a9328d8 100644 --- a/libraries/node-core-library/src/Text.ts +++ b/libraries/node-core-library/src/Text.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 * as os from 'os'; +import * as os from 'node:os'; /** * The allowed types of encodings, as supported by Node.js * @public */ -export const enum Encoding { +export enum Encoding { Utf8 = 'utf8' } @@ -15,7 +15,7 @@ export const enum Encoding { * Enumeration controlling conversion of newline characters. * @public */ -export const enum NewlineKind { +export enum NewlineKind { /** * Windows-style newlines */ @@ -35,6 +35,54 @@ export const enum NewlineKind { OsDefault = 'os' } +/** + * Options used when calling the {@link Text.readLinesFromIterable} or + * {@link Text.readLinesFromIterableAsync} methods. + * + * @public + */ +export interface IReadLinesFromIterableOptions { + /** + * The encoding of the input iterable. The default is utf8. + */ + encoding?: Encoding; + + /** + * If true, empty lines will not be returned. The default is false. + */ + ignoreEmptyLines?: boolean; +} + +interface IReadLinesFromIterableState { + remaining: string; +} + +const NEWLINE_REGEX: RegExp = /\r\n|\n\r|\r|\n/g; +const NEWLINE_AT_END_REGEX: RegExp = /(\r\n|\n\r|\r|\n)$/; + +function* readLinesFromChunk( + // eslint-disable-next-line @rushstack/no-new-null + chunk: string | Buffer | null, + encoding: Encoding, + ignoreEmptyLines: boolean, + state: IReadLinesFromIterableState +): Generator { + if (!chunk) { + return; + } + const remaining: string = state.remaining + (typeof chunk === 'string' ? chunk : chunk.toString(encoding)); + let startIndex: number = 0; + const matches: IterableIterator = remaining.matchAll(NEWLINE_REGEX); + for (const match of matches) { + const endIndex: number = match.index!; + if (startIndex !== endIndex || !ignoreEmptyLines) { + yield remaining.substring(startIndex, endIndex); + } + startIndex = endIndex + match[0].length; + } + state.remaining = remaining.substring(startIndex); +} + /** * Operations for working with strings that contain text. * @@ -45,8 +93,8 @@ export const enum NewlineKind { * @public */ export class Text { - private static readonly _newLineRegEx: RegExp = /\r\n|\n\r|\r|\n/g; - private static readonly _newLineAtEndRegEx: RegExp = /(\r\n|\n\r|\r|\n)$/; + 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 @@ -79,8 +127,23 @@ export class Text { * Converts all newlines in the provided string to use the specified newline type. */ public static convertTo(input: string, newlineKind: NewlineKind): string { - const newline: string = newlineKind === NewlineKind.OsDefault ? os.EOL : newlineKind as string; - return input.replace(Text._newLineRegEx, newline); + return input.replace(Text._newLineRegEx, Text.getNewline(newlineKind)); + } + + /** + * Returns the newline character sequence for the specified `NewlineKind`. + */ + public static getNewline(newlineKind: NewlineKind): string { + switch (newlineKind) { + case NewlineKind.CrLf: + return '\r\n'; + case NewlineKind.Lf: + return '\n'; + case NewlineKind.OsDefault: + return os.EOL; + default: + throw new Error('Unsupported newline kind'); + } } /** @@ -156,4 +219,75 @@ export class Text { } return s + newlineKind; // no, add it } + + /** + * Escapes a string so that it can be treated as a literal string when used in a regular expression. + */ + public static escapeRegExp(literal: string): string { + return literal.replace(/[^A-Za-z0-9_]/g, '\\$&'); + } + + /** + * Read lines from an iterable object that returns strings or buffers, and return a generator that + * produces the lines as strings. The lines will not include the newline characters. + * + * @param iterable - An iterable object that returns strings or buffers + * @param options - Options used when reading the lines from the provided iterable + */ + public static async *readLinesFromIterableAsync( + iterable: AsyncIterable, + options: IReadLinesFromIterableOptions = {} + ): AsyncGenerator { + const { encoding = Encoding.Utf8, ignoreEmptyLines = false } = options; + const state: IReadLinesFromIterableState = { remaining: '' }; + for await (const chunk of iterable) { + yield* readLinesFromChunk(chunk, encoding, ignoreEmptyLines, state); + } + const remaining: string = state.remaining; + if (remaining.length) { + yield remaining; + } + } + + /** + * Read lines from an iterable object that returns strings or buffers, and return a generator that + * produces the lines as strings. The lines will not include the newline characters. + * + * @param iterable - An iterable object that returns strings or buffers + * @param options - Options used when reading the lines from the provided iterable + */ + public static *readLinesFromIterable( + // eslint-disable-next-line @rushstack/no-new-null + iterable: Iterable, + options: IReadLinesFromIterableOptions = {} + ): Generator { + const { encoding = Encoding.Utf8, ignoreEmptyLines = false } = options; + const state: IReadLinesFromIterableState = { remaining: '' }; + for (const chunk of iterable) { + yield* readLinesFromChunk(chunk, encoding, ignoreEmptyLines, state); + } + const remaining: string = state.remaining; + if (remaining.length) { + yield remaining; + } + } + + /** + * Returns a new string that is the input string with the order of characters reversed. + */ + public static reverse(s: string): string { + // Benchmarks of several algorithms: https://jsbench.me/4bkfflcm2z + return s.split('').reduce((newString, char) => char + newString, ''); + } + + /** + * Splits the provided string by newlines. Note that leading and trailing newlines will produce + * leading or trailing empty string array entries. + */ + public static splitByNewLines(s: undefined): undefined; + public static splitByNewLines(s: string): string[]; + public static splitByNewLines(s: string | undefined): string[] | undefined; + public static splitByNewLines(s: string | undefined): string[] | undefined { + return s?.split(/\r?\n/); + } } diff --git a/libraries/node-core-library/src/TypeUuid.ts b/libraries/node-core-library/src/TypeUuid.ts new file mode 100644 index 00000000000..7637e3f7f95 --- /dev/null +++ b/libraries/node-core-library/src/TypeUuid.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 { InternalError } from './InternalError'; + +const classPrototypeUuidSymbol: symbol = Symbol.for('TypeUuid.classPrototypeUuid'); + +/** + * Provides a version-independent implementation of the JavaScript `instanceof` operator. + * + * @remarks + * The JavaScript `instanceof` operator normally only identifies objects from a particular library instance. + * For example, suppose the NPM package `example-lib` has two published versions 1.2.0 and 1.3.0, and + * it exports a class called `A`. Suppose some code consumes version `1.3.0` of the library, but it receives + * an object that was constructed using version `1.2.0`. In this situation `a instanceof A` will return `false`, + * even though `a` is an instance of `A`. The reason is that there are two prototypes for `A`; one for each + * version. + * + * The `TypeUuid` facility provides a way to make `a instanceof A` return true for both prototypes of `A`, + * by instead using a universally unique identifier (UUID) to detect object instances. + * + * You can use `Symbol.hasInstance` to enable the system `instanceof` operator to recognize type UUID equivalence: + * ```ts + * const uuidWidget: string = '9c340ef0-d29f-4e2e-a09f-42bacc59024b'; + * class Widget { + * public static [Symbol.hasInstance](instance: object): boolean { + * return TypeUuid.isInstanceOf(instance, uuidWidget); + * } + * } + * ``` + * // Example usage: + * ```ts + * import { Widget as Widget1 } from 'v1-of-library'; + * import { Widget as Widget2 } from 'v2-of-library'; + * const widget = new Widget2(); + * console.log(widget instanceof Widget1); // prints true + * ``` + * + * @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 + * We cannot use a construct signature for `targetClass` because it may be an abstract class. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public static registerClass(targetClass: any, typeUuid: string): void { + if (typeof targetClass !== 'function') { + throw new Error('The targetClass parameter must be a JavaScript class'); + } + + if (!TypeUuid._uuidRegExp.test(typeUuid)) { + throw new Error(`The type UUID must be specified as lowercase hexadecimal with dashes: "${typeUuid}"`); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const targetClassPrototype: any = targetClass.prototype; + + if (Object.hasOwnProperty.call(targetClassPrototype, classPrototypeUuidSymbol)) { + const existingUuid: string = targetClassPrototype[classPrototypeUuidSymbol]; + throw new InternalError( + `Cannot register the target class ${targetClass.name || ''} typeUuid=${typeUuid}` + + ` because it was already registered with typeUuid=${existingUuid}` + ); + } + targetClassPrototype[classPrototypeUuidSymbol] = typeUuid; + } + + /** + * Returns true if the `targetObject` is an instance of a JavaScript class that was previously + * registered using the specified `typeUuid`. Base classes are also considered. + */ + public static isInstanceOf(targetObject: unknown, typeUuid: string): boolean { + if (targetObject === undefined || targetObject === null) { + return false; + } + + let objectPrototype: {} = Object.getPrototypeOf(targetObject); + while (objectPrototype !== undefined && objectPrototype !== null) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const registeredUuid: string = (objectPrototype as any)[classPrototypeUuidSymbol]; + if (registeredUuid === typeUuid) { + return true; + } + // Walk upwards an examine base class prototypes + objectPrototype = Object.getPrototypeOf(objectPrototype); + } + + return false; + } +} 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 970a9932faa..c48a9c950a3 100644 --- a/libraries/node-core-library/src/index.ts +++ b/libraries/node-core-library/src/index.ts @@ -1,100 +1,164 @@ // 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 { - FileConstants, - FolderConstants -} from './Constants'; + Async, + AsyncQueue, + type IAsyncParallelismOptions, + type IRunWithRetriesOptions, + type IRunWithTimeoutOptions, + type IWeighted +} from './Async'; + +export { FileConstants, FolderConstants } from './Constants'; + +export { Disposables } from './Disposables'; + +export { Enum } from './Enum'; + +export { EnvironmentMap, type IEnvironmentEntry } from './EnvironmentMap'; + export { - ExecutableStdioStreamMapping, - ExecutableStdioMapping, - IExecutableResolveOptions, - IExecutableSpawnSyncOptions, + type ExecutableStdioStreamMapping, + type ExecutableStdioMapping, + type IExecutableResolveOptions, + type IExecutableSpawnSyncOptions, + type IExecutableSpawnOptions, + type IWaitForExitOptions, + type IWaitForExitWithBufferOptions, + type IWaitForExitWithStringOptions, + type IWaitForExitResult, + type IWaitForExitResultWithoutOutput, + type IProcessInfo, Executable } from './Executable'; + +export { type IFileErrorOptions, type IFileErrorFormattingOptions, FileError } from './FileError'; + +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 { + Import, + type IImportResolveOptions, + type IImportResolveAsyncOptions, + type IImportResolveModuleOptions, + type IImportResolveModuleAsyncOptions, + type IImportResolvePackageOptions, + type IImportResolvePackageAsyncOptions +} from './Import'; + +export { InternalError } from './InternalError'; + +export type { INodePackageJson, IPackageJson, IPackageJsonDependencyTable, - IPackageJsonScriptTable + IPackageJsonScriptTable, + IPackageJsonRepository, + IPeerDependenciesMetaTable, + IDependenciesMetaTable, + IPackageJsonExports } from './IPackageJson'; -export { InternalError } from './InternalError'; + export { - JsonObject, - JsonFile, - IJsonFileSaveOptions, - IJsonFileStringifyOptions + type JsonObject, + type JsonNull, + JsonSyntax, + type IJsonFileParseOptions, + type IJsonFileLoadAndValidateOptions, + type IJsonFileStringifyOptions, + type IJsonFileSaveOptions, + JsonFile } from './JsonFile'; + export { + type IJsonSchemaErrorInfo, + type IJsonSchemaCustomFormat, + type IJsonSchemaFromFileOptions, + type IJsonSchemaFromObjectOptions, + type IJsonSchemaLoadOptions, + type IJsonSchemaValidateOptions, + type IJsonSchemaValidateObjectWithOptions, JsonSchema, - IJsonSchemaErrorInfo, - IJsonSchemaValidateOptions, - IJsonSchemaFromFileOptions + type JsonSchemaVersion } from './JsonSchema'; + +export { LegacyAdapters, type LegacyCallback } from './LegacyAdapters'; + +export { LockFile } from './LockFile'; + +export { MapExtensions } from './MapExtensions'; + +export { MinimumHeap } from './MinimumHeap'; + +export { Objects } from './Objects'; + +export { type IPackageJsonLookupParameters, PackageJsonLookup } from './PackageJsonLookup'; + export { - LockFile -} from './LockFile'; + PackageName, + PackageNameParser, + type IPackageNameParserOptions, + type IParsedPackageName, + type IParsedPackageNameOrError +} from './PackageName'; + export { - MapExtensions -} from './MapExtensions'; + Path, + type FileLocationStyle, + type IPathFormatFileLocationOptions, + type IPathFormatConciselyOptions +} from './Path'; + export { PosixModeBits } from './PosixModeBits'; -export { - ProtectableMap, - IProtectableMapParameters -} from './ProtectableMap'; -export { - IPackageJsonLookupParameters, - PackageJsonLookup -} from './PackageJsonLookup'; -export { PackageName, IParsedPackageName, IParsedPackageNameOrError } from './PackageName'; -export { Path } from './Path'; -export { - Encoding, - Text, - NewlineKind -} from './Text'; + +export type { Brand } from './PrimitiveTypes'; + +export { ProtectableMap, type IProtectableMapParameters } from './ProtectableMap'; + +export { RealNodeModulePathResolver, type IRealNodeModulePathResolverOptions } from './RealNodeModulePath'; + export { Sort } from './Sort'; -export { - FileSystem, - IFileSystemReadFolderOptions, - IFileSystemWriteFileOptions, - IFileSystemReadFileOptions, - IFileSystemMoveOptions, - IFileSystemCopyFileOptions, - IFileSystemDeleteFileOptions, - IFileSystemUpdateTimeParameters, - IFileSystemCreateLinkOptions -} from './FileSystem'; -export { - FileWriter, - IFileWriterFlags -} from './FileWriter'; -export { - LegacyAdapters, - LegacyCallback -} from './LegacyAdapters'; -export { StringBuilder, IStringBuilder } from './StringBuilder'; -export { Terminal } from './Terminal/Terminal'; -export { - Colors, - IColorableSequence, - ColorValue, - TextAttribute -} from './Terminal/Colors'; -export { - ITerminalProvider, - TerminalProviderSeverity -} from './Terminal/ITerminalProvider'; -export { - ConsoleTerminalProvider, - IConsoleTerminalProviderOptions -} from './Terminal/ConsoleTerminalProvider'; -export { - StringBufferTerminalProvider -} from './Terminal/StringBufferTerminalProvider'; + +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..77fdef00371 --- /dev/null +++ b/libraries/node-core-library/src/objects/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 { areDeepEqual } from './areDeepEqual'; 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/test/2/test#999999999.lock b/libraries/node-core-library/src/test/2/test#999999999.lock new file mode 100644 index 00000000000..da4eb94a088 --- /dev/null +++ b/libraries/node-core-library/src/test/2/test#999999999.lock @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..da4eb94a088 --- /dev/null +++ b/libraries/node-core-library/src/test/3/test#1.lock @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..c7c5468bc9d --- /dev/null +++ b/libraries/node-core-library/src/test/Async.test.ts @@ -0,0 +1,994 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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 () => { + const result = await Async.mapAsync([] as number[], async (item) => `result ${item}`); + expect(result).toEqual([]); + }); + + 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('passes an index parameter to the callback function', async () => { + const array: number[] = [1, 2, 3]; + const fn: (item: number, index: number) => Promise = jest.fn(async (item) => `result ${item}`); + + await Async.mapAsync(array, fn); + expect(fn).toHaveBeenNthCalledWith(1, 1, 0); + expect(fn).toHaveBeenNthCalledWith(2, 2, 1); + expect(fn).toHaveBeenNthCalledWith(3, 3, 2); + }); + + it('if concurrency is set, ensures no more than N operations occur in parallel', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: number[] = [1, 2, 3, 4, 5, 6, 7, 8]; + + const fn: (item: number) => Promise = async (item) => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + return `result ${item}`; + }; + + expect(await Async.mapAsync(array, fn, { concurrency: 3 })).toEqual([ + 'result 1', + 'result 2', + 'result 3', + 'result 4', + 'result 5', + 'result 6', + 'result 7', + 'result 8' + ]); + 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; + const syncIterator: Iterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return { done: false, value: iteratorIndex }; + } else { + throw expectedError; + } + } + }; + const syncIterable: Iterable = { + [Symbol.iterator]: () => syncIterator + }; + + await expect(() => Async.mapAsync(syncIterable, async (item) => `result ${item}`)).rejects.toThrow( + expectedError + ); + }); + + it('rejects if an async iterator throws an error', async () => { + const expectedError: Error = new Error('iterator error'); + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return Promise.resolve({ done: false, value: iteratorIndex }); + } else { + throw expectedError; + } + } + }; + const syncIterable: AsyncIterable = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + await expect(() => Async.mapAsync(syncIterable, async (item) => `result ${item}`)).rejects.toThrow( + expectedError + ); + }); + + it('rejects if an async iterator rejects', async () => { + const expectedError: Error = new Error('iterator error'); + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return Promise.resolve({ done: false, value: iteratorIndex }); + } else { + return Promise.reject(expectedError); + } + } + }; + const syncIterable: AsyncIterable = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + await expect(() => Async.mapAsync(syncIterable, async (item) => `result ${item}`)).rejects.toThrow( + expectedError + ); + }); + }); + + describe(Async.forEachAsync.name, () => { + it('handles an empty array correctly', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: number[] = []; + + const fn: (item: number) => Promise = jest.fn(async (item) => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency: 3 }); + expect(fn).toHaveBeenCalledTimes(0); + expect(maxRunning).toEqual(0); + }); + + it('if concurrency is set, ensures no more than N operations occur in parallel', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: number[] = [1, 2, 3, 4, 5, 6, 7, 8]; + + const fn: (item: number) => Promise = jest.fn(async (item) => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency: 3 }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(3); + }); + + it('returns when given an array with a large number of elements and a concurrency limit', async () => { + const array: number[] = []; + for (let i = 0; i < 250; i++) { + array.push(i); + } + + await Async.forEachAsync(array, async () => await Async.sleepAsync(0), { concurrency: 3 }); + }); + + it('rejects if any operation rejects', async () => { + const array: number[] = [1, 2, 3]; + + const fn: (item: number) => Promise = jest.fn(async (item) => { + await Async.sleepAsync(0); + if (item === 3) throw new Error('Something broke'); + }); + + await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrowError( + 'Something broke' + ); + expect(fn).toHaveBeenCalledTimes(3); + }); + + it('rejects if any operation synchronously throws', async () => { + const array: number[] = [1, 2, 3]; + + // The compiler is (rightly) very concerned about us claiming that this synchronous + // function is going to return a promise. This situation is not very likely in a + // TypeScript project, but it's such a common problem in JavaScript projects that + // it's worth doing an explicit test. + const fn: (item: number) => Promise = jest.fn((item) => { + if (item === 3) throw new Error('Something broke'); + }) as unknown as (item: number) => Promise; + + await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrowError( + 'Something broke' + ); + expect(fn).toHaveBeenCalledTimes(3); + }); + + it('rejects if a sync iterator throws an error', async () => { + const expectedError: Error = new Error('iterator error'); + let iteratorIndex: number = 0; + const syncIterator: Iterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return { done: false, value: iteratorIndex }; + } else { + throw expectedError; + } + } + }; + const syncIterable: Iterable = { + [Symbol.iterator]: () => syncIterator + }; + + await expect(() => + Async.forEachAsync(syncIterable, async (item) => await Async.sleepAsync(0)) + ).rejects.toThrow(expectedError); + }); + + it('rejects if an async iterator throws an error', async () => { + const expectedError: Error = new Error('iterator error'); + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return Promise.resolve({ done: false, value: iteratorIndex }); + } else { + throw expectedError; + } + } + }; + const syncIterable: AsyncIterable = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + await expect(() => + Async.forEachAsync(syncIterable, async (item) => await Async.sleepAsync(0)) + ).rejects.toThrow(expectedError); + }); + + it('does not exceed the maxiumum concurrency for an async iterator', async () => { + let waitingIterators: number = 0; + + let resolve2!: (value: { done: true; value: undefined }) => void; + const signal2: Promise<{ done: true; value: undefined }> = new Promise((resolve, reject) => { + resolve2 = resolve; + }); + + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator = { + next: () => { + iteratorIndex++; + if (iteratorIndex < 20) { + return Promise.resolve({ done: false, value: iteratorIndex }); + } else { + ++waitingIterators; + return signal2; + } + } + }; + const asyncIterable: AsyncIterable = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + const finalPromise: Promise = Async.forEachAsync( + asyncIterable, + async (item) => { + // Do nothing + }, + { + concurrency: 4 + } + ); + + // Wait for all the instant resolutions to be done + await Async.sleepAsync(0); + + // The final iteration cycle is locked, so only 1 iterator is waiting. + expect(waitingIterators).toEqual(1); + resolve2({ done: true, value: undefined }); + await finalPromise; + }); + + it('rejects if an async iterator rejects', async () => { + const expectedError: Error = new Error('iterator error'); + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator = { + next: () => { + if (iteratorIndex < 5) { + iteratorIndex++; + return Promise.resolve({ done: false, value: iteratorIndex }); + } else { + return Promise.reject(expectedError); + } + } + }; + const syncIterable: AsyncIterable = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + await expect(() => + Async.forEachAsync(syncIterable, async (item) => await Async.sleepAsync(0)) + ).rejects.toThrow(expectedError); + }); + + it('handles an empty array correctly', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = []; + + 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 }); + expect(fn).toHaveBeenCalledTimes(0); + expect(maxRunning).toEqual(0); + }); + + it('if concurrency is set, ensures no more than N operations occur in parallel', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [1, 2, 3, 4, 5, 6, 7, 8].map((n) => ({ weight: 1, n })); + + 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 }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(3); + }); + + it('if concurrency is set but weighted is not, ensures no more than N operations occur in parallel and ignores operation weight', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [1, 2, 3, 4, 5, 6, 7, 8].map((n) => ({ weight: 2, n })); + + 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 }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(3); + }); + + it.each([ + { + concurrency: 4, + weight: 4, + expectedConcurrency: 1 + }, + { + concurrency: 4, + weight: 1, + expectedConcurrency: 4 + }, + { + concurrency: 3, + weight: 1, + expectedConcurrency: 3 + }, + { + concurrency: 6, + weight: 2, + expectedConcurrency: 3 + }, + { + concurrency: 12, + weight: 3, + expectedConcurrency: 4 + } + ])( + 'if concurrency is set to $concurrency with operation weight $weight, ensures no more than $expectedConcurrency operations occur in parallel', + async ({ concurrency, weight, expectedConcurrency }) => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [1, 2, 3, 4, 5, 6, 7, 8].map((n) => ({ n, weight })); + + 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, weighted: true }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(expectedConcurrency); + } + ); + + it('ensures that a large operation cannot be scheduled around', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [ + { n: 1, weight: 1 }, + { n: 2, weight: 1 }, + { n: 3, weight: 1 }, + { n: 4, weight: 10 }, + { n: 5, weight: 1 }, + { n: 6, weight: 1 }, + { n: 7, weight: 5 }, + { n: 8, weight: 1 } + ]; + + 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 }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(3); + }); + + it('waits for a 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: true }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(2); + }); + + it('allows operations with a weight of 0 and schedules them accordingly', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [1, 2, 3, 4, 5, 6, 7, 8].map((n) => ({ n, weight: 0 })); + + array.unshift({ n: 9, weight: 3 }); + + array.push({ n: 10, weight: 3 }); + + 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 }); + expect(fn).toHaveBeenCalledTimes(10); + expect(maxRunning).toEqual(9); + }); + + it('does not exceed the maxiumum concurrency for an async iterator when weighted', async () => { + let waitingIterators: number = 0; + + let resolve2!: (value: { done: true; value: undefined }) => void; + const signal2: Promise<{ done: true; value: undefined }> = new Promise((resolve, reject) => { + resolve2 = resolve; + }); + + let iteratorIndex: number = 0; + const asyncIterator: AsyncIterator<{ element: number; weight: number }> = { + next: () => { + iteratorIndex++; + if (iteratorIndex < 20) { + return Promise.resolve({ done: false, value: { element: iteratorIndex, weight: 2 } }); + } else { + ++waitingIterators; + return signal2; + } + } + }; + const asyncIterable: AsyncIterable<{ element: number; weight: number }> = { + [Symbol.asyncIterator]: () => asyncIterator + }; + + const finalPromise: Promise = Async.forEachAsync( + asyncIterable, + async (item) => { + // Do nothing + }, + { + concurrency: 4, + weighted: true + } + ); + + // Wait for all the instant resolutions to be done + await Async.sleepAsync(0); + + // The final iteration cycle is locked, so only 1 iterator is waiting. + expect(waitingIterators).toEqual(1); + resolve2({ done: true, value: undefined }); + await finalPromise; + }); + }); + + 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 }); + expect(result).toEqual(expectedResult); + }); + + it('Correctly handles an async function that succeeds the first time', async () => { + const expectedResult: string = 'RESULT'; + const result: string = await Async.runWithRetriesAsync({ + // eslint-disable-next-line @typescript-eslint/naming-convention + action: async () => expectedResult, + maxRetries: 0 + }); + expect(result).toEqual(expectedResult); + }); + + it('Correctly handles a sync function that throws and does not allow retries', async () => { + await expect( + async () => + await Async.runWithRetriesAsync({ + action: () => { + throw new Error('error'); + }, + maxRetries: 0 + }) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Correctly handles an async function that throws and does not allow retries', async () => { + await expect( + async () => + await Async.runWithRetriesAsync({ + // eslint-disable-next-line @typescript-eslint/naming-convention + action: async () => { + throw new Error('error'); + }, + maxRetries: 0 + }) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Correctly handles a sync function that always throws and allows several retries', async () => { + await expect( + async () => + await Async.runWithRetriesAsync({ + action: () => { + throw new Error('error'); + }, + maxRetries: 5 + }) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Correctly handles an async function that always throws and allows several retries', async () => { + await expect( + async () => + await Async.runWithRetriesAsync({ + // eslint-disable-next-line @typescript-eslint/naming-convention + action: async () => { + throw new Error('error'); + }, + maxRetries: 5 + }) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('Correctly handles a sync function that throws once and then succeeds', async () => { + const expectedResult: string = 'RESULT'; + let callCount: number = 0; + const result: string = await Async.runWithRetriesAsync({ + action: () => { + if (callCount++ === 0) { + throw new Error('error'); + } else { + return expectedResult; + } + }, + maxRetries: 1 + }); + expect(result).toEqual(expectedResult); + }); + + it('Correctly handles an async function that throws once and then succeeds', async () => { + const expectedResult: string = 'RESULT'; + let callCount: number = 0; + const result: string = await Async.runWithRetriesAsync({ + action: () => { + if (callCount++ === 0) { + throw new Error('error'); + } else { + return expectedResult; + } + }, + maxRetries: 1 + }); + expect(result).toEqual(expectedResult); + }); + + it('Correctly handles a sync function that throws once and then succeeds with a timeout', async () => { + const expectedResult: string = 'RESULT'; + let callCount: number = 0; + const sleepSpy: jest.SpyInstance = jest + .spyOn(Async, 'sleepAsync') + .mockImplementation(() => Promise.resolve()); + + const resultPromise: Promise = Async.runWithRetriesAsync({ + action: () => { + if (callCount++ === 0) { + throw new Error('error'); + } else { + return expectedResult; + } + }, + maxRetries: 1, + retryDelayMs: 5 + }); + + expect(await resultPromise).toEqual(expectedResult); + expect(sleepSpy).toHaveBeenCalledTimes(1); + expect(sleepSpy).toHaveBeenLastCalledWith(5); + }); + + it('Correctly handles an async function that throws once and then succeeds with a timeout', async () => { + const expectedResult: string = 'RESULT'; + let callCount: number = 0; + const sleepSpy: jest.SpyInstance = jest + .spyOn(Async, 'sleepAsync') + .mockImplementation(() => Promise.resolve()); + + const resultPromise: Promise = Async.runWithRetriesAsync({ + // eslint-disable-next-line @typescript-eslint/naming-convention + action: async () => { + if (callCount++ === 0) { + throw new Error('error'); + } else { + return expectedResult; + } + }, + maxRetries: 1, + retryDelayMs: 5 + }); + + expect(await resultPromise).toEqual(expectedResult); + 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 + }); + }); + }); +}); + +describe(AsyncQueue.name, () => { + it('Can enqueue and dequeue items', async () => { + const expectedItems: Set = new Set([1, 2, 3]); + const expectedSeenItems: number = 3; + + let seenItems: number = 0; + const queue: AsyncQueue = new AsyncQueue(expectedItems); + + for await (const [item, callback] of queue) { + seenItems++; + expect(expectedItems.has(item)).toBe(true); + expectedItems.delete(item); + callback(); + } + + expect(seenItems).toEqual(expectedSeenItems); + expect(expectedItems.size).toEqual(0); + }); + + it('Can dynamically enqueue and dequeue items', async () => { + const expectedItems: Set = new Set([1, 2, 3]); + const expectedAdditionalItems = new Set([4, 5, 6]); + const expectedSeenItems: number = 6; + + let seenItems: number = 0; + const queue: AsyncQueue = new AsyncQueue(expectedItems); + + for await (const [item, callback] of queue) { + seenItems++; + if (item < 4) { + expect(expectedItems.has(item)).toBe(true); + expectedItems.delete(item); + queue.push(item + 3); + } else { + expect(expectedAdditionalItems.has(item)).toBe(true); + expectedAdditionalItems.delete(item); + } + callback(); + } + + expect(seenItems).toEqual(expectedSeenItems); + expect(expectedItems.size).toEqual(0); + expect(expectedAdditionalItems.size).toEqual(0); + }); + + it('Can enqueue and dequeue items concurrently', async () => { + const expectedItems: Set = new Set([1, 2, 3]); + const expectedSeenItems: number = 3; + + let seenItems: number = 0; + const queue: AsyncQueue = new AsyncQueue(expectedItems); + + await Async.forEachAsync( + queue, + async ([item, callback]) => { + // Add an async tick to ensure that the queue is actually running concurrently + await Async.sleepAsync(0); + seenItems++; + expect(expectedItems.has(item)).toBe(true); + expectedItems.delete(item); + callback(); + }, + { + concurrency: 10 + } + ); + + expect(seenItems).toEqual(expectedSeenItems); + expect(expectedItems.size).toEqual(0); + }); + + it('Can dynamically enqueue and dequeue items concurrently', async () => { + const expectedItems: Set = new Set([1, 2, 3]); + const expectedAdditionalItems = new Set([4, 5, 6]); + const expectedSeenItems: number = 6; + + let seenItems: number = 0; + const queue: AsyncQueue = new AsyncQueue(expectedItems); + + await Async.forEachAsync( + queue, + async ([item, callback]) => { + // Add an async tick to ensure that the queue is actually running concurrently + await Async.sleepAsync(0); + seenItems++; + if (item < 4) { + expect(expectedItems.has(item)).toBe(true); + expectedItems.delete(item); + queue.push(item + 3); + } else { + expect(expectedAdditionalItems.has(item)).toBe(true); + expectedAdditionalItems.delete(item); + } + callback(); + }, + { + concurrency: 10 + } + ); + + expect(seenItems).toEqual(expectedSeenItems); + expect(expectedItems.size).toEqual(0); + expect(expectedAdditionalItems.size).toEqual(0); + }); + + it('Can dynamically enqueue and dequeue items concurrently after reaching last item', async () => { + const expectedItems: Set = new Set([1, 2, 3]); + const expectedAdditionalItems = new Set([4, 5, 6]); + const expectedSeenItems: number = 6; + + let seenItems: number = 0; + const queue: AsyncQueue = new AsyncQueue(expectedItems); + + await Async.forEachAsync( + queue, + async ([item, callback]) => { + // Add an async tick to ensure that the queue is actually running concurrently + await Async.sleepAsync(0); + seenItems++; + if (item < 4) { + expect(expectedItems.has(item)).toBe(true); + expectedItems.delete(item); + if (item === 3) { + for (const additionalItem of expectedAdditionalItems) { + queue.push(additionalItem); + } + } + } else { + expect(expectedAdditionalItems.has(item)).toBe(true); + expectedAdditionalItems.delete(item); + } + callback(); + }, + { + concurrency: 10 + } + ); + + expect(seenItems).toEqual(expectedSeenItems); + expect(expectedItems.size).toEqual(0); + expect(expectedAdditionalItems.size).toEqual(0); + }); +}); diff --git a/libraries/node-core-library/src/test/Enum.test.ts b/libraries/node-core-library/src/test/Enum.test.ts new file mode 100644 index 00000000000..91a85a01436 --- /dev/null +++ b/libraries/node-core-library/src/test/Enum.test.ts @@ -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 { Enum } from '../Enum'; + +// Bidirectional map +enum NumericEnum { + Apple = 1, + Banana +} + +// Unidirectional map +enum StringEnum { + Apple = 'apple', + Banana = 'banana' +} + +enum MixedEnum { + // Bidirectional map + Apple = 1, + // Unidirectional map + Banana = 'banana' +} + +describe(Enum.name, () => { + test('tryGetValueByKey', () => { + // NumericEnum + const numeric1: NumericEnum | undefined = Enum.tryGetValueByKey(NumericEnum, 'Apple'); + expect(numeric1).toBe(NumericEnum.Apple); + + const numeric2: NumericEnum | undefined = Enum.tryGetValueByKey(NumericEnum, 'Coconut'); + expect(numeric2).toBeUndefined(); + + // StringEnum + const string1: StringEnum | undefined = Enum.tryGetValueByKey(StringEnum, 'Apple'); + expect(string1).toBe(StringEnum.Apple); + + const string2: StringEnum | undefined = Enum.tryGetValueByKey(StringEnum, 'Coconut'); + expect(string2).toBeUndefined(); + + // MixedEnum + const mixed1: MixedEnum | undefined = Enum.tryGetValueByKey(MixedEnum, 'Apple'); + expect(mixed1).toBe(MixedEnum.Apple); + + const mixed2: MixedEnum | undefined = Enum.tryGetValueByKey(MixedEnum, 'Banana'); + expect(mixed2).toBe(MixedEnum.Banana); + + const mixed3: MixedEnum | undefined = Enum.tryGetValueByKey(MixedEnum, 'Coconut'); + expect(mixed3).toBeUndefined(); + }); + + test('tryGetKeyByNumber', () => { + // NumericEnum + const numeric1: string | undefined = Enum.tryGetKeyByNumber(NumericEnum, NumericEnum.Apple as number); + expect(numeric1).toBe('Apple'); + + const numeric2: string | undefined = Enum.tryGetKeyByNumber(NumericEnum, -1); + expect(numeric2).toBeUndefined(); + + // StringEnum + + // Not allowed because values must be numeric: + // const string1: string | undefined = Enum.tryGetKeyByNumber(StringEnum, StringEnum.Apple); + + const string2: string | undefined = Enum.tryGetKeyByNumber(StringEnum, -1); + expect(string2).toBeUndefined(); + + // MixedEnum + const mixed1: string | undefined = Enum.tryGetKeyByNumber(MixedEnum, MixedEnum.Apple); + expect(mixed1).toBe('Apple'); + + // Not allowed because values must be numeric: + // const mixed2: string | undefined = Enum.tryGetKeyByNumber(MixedEnum, MixedEnum.Banana); + + const mixed3: string | undefined = Enum.tryGetKeyByNumber(MixedEnum, -1); + expect(mixed3).toBeUndefined(); + }); +}); diff --git a/libraries/node-core-library/src/test/EnvironmentMap.test.ts b/libraries/node-core-library/src/test/EnvironmentMap.test.ts new file mode 100644 index 00000000000..be51e8163b4 --- /dev/null +++ b/libraries/node-core-library/src/test/EnvironmentMap.test.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 process from 'node:process'; + +import { EnvironmentMap } from '../EnvironmentMap'; + +describe(EnvironmentMap.name, () => { + test('_sanityCheck() throws', () => { + const map = new EnvironmentMap(); + const environmentObject = { A: '123' }; + expect(() => { + // eslint-disable-next-line + const combined = { ...environmentObject, ...map }; + }).toThrow(); + }); + + test('Case-insensitive on windows', () => { + const map = new EnvironmentMap(); + map.set('A', '1'); + map.set('a', '2'); + + if (process.platform === 'win32') { + expect([...map.entries()]).toMatchInlineSnapshot(` + Array [ + Object { + "name": "a", + "value": "2", + }, + ] + `); + } else { + expect([...map.entries()]).toMatchInlineSnapshot(` + Array [ + Object { + "name": "A", + "value": "1", + }, + Object { + "name": "a", + "value": "2", + }, + ] + `); + } + }); +}); diff --git a/libraries/node-core-library/src/test/Executable.test.ts b/libraries/node-core-library/src/test/Executable.test.ts index 5bb59c717a0..2a6d6b6fac8 100644 --- a/libraries/node-core-library/src/test/Executable.test.ts +++ b/libraries/node-core-library/src/test/Executable.test.ts @@ -1,180 +1,500 @@ // 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 child_process from 'child_process'; +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, IExecutableSpawnSyncOptions } from '../Executable'; +import { + Executable, + parseProcessListOutput, + parseProcessListOutputAsync, + type IProcessInfo, + type IExecutableSpawnSyncOptions, + type IWaitForExitResult, + type IWaitForExitResultWithoutOutput +} from '../Executable'; import { FileSystem } from '../FileSystem'; import { PosixModeBits } from '../PosixModeBits'; import { Text } from '../Text'; +import { Readable } from 'node:stream'; -// The PosixModeBits are intended to be used with bitwise operations. -/* eslint-disable no-bitwise */ +describe('Executable process tests', () => { + // The PosixModeBits are intended to be used with bitwise operations. + /* eslint-disable no-bitwise */ -// Use src/test/test-data instead of lib/test/test-data -const executableFolder: string = path.join(__dirname, '..', '..', 'src', 'test', 'test-data', 'executable'); + // Use src/test/test-data instead of lib/test/test-data + const executableFolder: string = path.join(__dirname, '..', '..', 'src', 'test', 'test-data', 'executable'); -let environment: NodeJS.ProcessEnv; + let environment: NodeJS.ProcessEnv; -if (os.platform() === 'win32') { - environment = { - PATH: [ - path.join(executableFolder, 'skipped'), - path.join(executableFolder, 'success'), - path.join(executableFolder, 'fail'), - path.dirname(process.execPath) // the folder where node.exe can be found - ].join(path.delimiter), + if (os.platform() === 'win32') { + environment = { + PATH: [ + path.join(executableFolder, 'skipped'), + path.join(executableFolder, 'success'), + path.join(executableFolder, 'fail'), + path.dirname(process.execPath) // the folder where node.exe can be found + ].join(path.delimiter), - PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS', + PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS', - TEST_VAR: '123' - }; -} else { - environment = { - PATH: [ - path.join(executableFolder, 'skipped'), - path.join(executableFolder, 'success'), - path.join(executableFolder, 'fail'), - path.dirname(process.execPath), // the folder where node.exe can be found - // These are needed because our example script needs to find bash - '/usr/local/bin', - '/usr/bin', - '/bin' - ].join(path.delimiter), - - TEST_VAR: '123' - }; -} - -const options: IExecutableSpawnSyncOptions = { - environment: environment, - currentWorkingDirectory: executableFolder, - stdio: 'pipe' -}; - -beforeAll(() => { - // Make sure the test folder exists where we expect it - expect(FileSystem.exists(executableFolder)).toEqual(true); - - // Git's core.filemode setting wrongly defaults to true on Windows. This design flaw makes - // it completely impractical to store POSIX file permissions in a cross-platform Git repo. - // So instead we set them before the test runs, and then revert them after the test completes. - if (os.platform() !== 'win32') { - FileSystem.changePosixModeBits(path.join(executableFolder, 'success', 'npm-binary-wrapper'), - PosixModeBits.AllRead | PosixModeBits.AllWrite | PosixModeBits.AllExecute); - FileSystem.changePosixModeBits(path.join(executableFolder, 'success', 'bash-script.sh'), - PosixModeBits.AllRead | PosixModeBits.AllWrite | PosixModeBits.AllExecute); - } -}); + TEST_VAR: '123' + }; + } else { + environment = { + PATH: [ + path.join(executableFolder, 'skipped'), + path.join(executableFolder, 'success'), + path.join(executableFolder, 'fail'), + path.dirname(process.execPath), // the folder where node.exe can be found + // These are needed because our example script needs to find bash + '/usr/local/bin', + '/usr/bin', + '/bin' + ].join(path.delimiter), -afterAll(() => { - // Revert the permissions to the defaults - if (os.platform() !== 'win32') { - FileSystem.changePosixModeBits(path.join(executableFolder, 'success', 'npm-binary-wrapper'), - PosixModeBits.AllRead | PosixModeBits.AllWrite); - FileSystem.changePosixModeBits(path.join(executableFolder, 'success', 'bash-script.sh'), - PosixModeBits.AllRead | PosixModeBits.AllWrite); + TEST_VAR: '123' + }; } -}); -test('Executable.tryResolve() pathless', () => { - const resolved: string | undefined = Executable.tryResolve('npm-binary-wrapper', options); - expect(resolved).toBeDefined(); - const resolvedRelative: string = Text.replaceAll(path.relative(executableFolder, resolved!), - '\\', '/'); + const options: IExecutableSpawnSyncOptions = { + environment: environment, + currentWorkingDirectory: executableFolder, + stdio: 'pipe' + }; - if (os.platform() === 'win32') { - // On Windows, we should find npm-binary-wrapper.cmd instead of npm-binary-wrapper - expect(resolvedRelative).toEqual('success/npm-binary-wrapper.cmd'); - } else { - expect(resolvedRelative).toEqual('success/npm-binary-wrapper'); - } + beforeAll(() => { + // Make sure the test folder exists where we expect it + expect(FileSystem.exists(executableFolder)).toEqual(true); - // We should not find the "missing-extension" at all, because its file extension - // is not executable on Windows (and the execute bit is missing on Unix) - expect(Executable.tryResolve('missing-extension', options)).toBeUndefined(); -}); + // Git's core.filemode setting wrongly defaults to true on Windows. This design flaw makes + // it completely impractical to store POSIX file permissions in a cross-platform Git repo. + // So instead we set them before the test runs, and then revert them after the test completes. + if (os.platform() !== 'win32') { + FileSystem.changePosixModeBits( + path.join(executableFolder, 'success', 'npm-binary-wrapper'), + PosixModeBits.AllRead | PosixModeBits.AllWrite | PosixModeBits.AllExecute + ); + FileSystem.changePosixModeBits( + path.join(executableFolder, 'fail', 'npm-binary-wrapper'), + PosixModeBits.AllRead | PosixModeBits.AllWrite | PosixModeBits.AllExecute + ); + } + }); -test('Executable.tryResolve() with path', () => { - const resolved: string | undefined = Executable.tryResolve('./npm-binary-wrapper', options); - expect(resolved).toBeUndefined(); -}); + afterAll(() => { + // Revert the permissions to the defaults + if (os.platform() !== 'win32') { + FileSystem.changePosixModeBits( + path.join(executableFolder, 'success', 'npm-binary-wrapper'), + PosixModeBits.AllRead | PosixModeBits.AllWrite + ); + FileSystem.changePosixModeBits( + path.join(executableFolder, 'fail', 'npm-binary-wrapper'), + PosixModeBits.AllRead | PosixModeBits.AllWrite + ); + } + }); -function executeNpmBinaryWrapper(args: string[]): string[] { - const result: child_process.SpawnSyncReturns - = Executable.spawnSync('npm-binary-wrapper', args, options); - expect(result.error).toBeUndefined(); + test('Executable.tryResolve() pathless', () => { + const resolved: string | undefined = Executable.tryResolve('npm-binary-wrapper', options); + expect(resolved).toBeDefined(); + const resolvedRelative: string = Text.replaceAll(path.relative(executableFolder, resolved!), '\\', '/'); - expect(result.stderr).toBeDefined(); - expect(result.stderr.toString()).toEqual(''); + if (os.platform() === 'win32') { + // On Windows, we should find npm-binary-wrapper.cmd instead of npm-binary-wrapper + expect(resolvedRelative).toEqual('success/npm-binary-wrapper.cmd'); + } else { + expect(resolvedRelative).toEqual('success/npm-binary-wrapper'); + } - expect(result.stdout).toBeDefined(); - const outputLines: string[] = result.stdout.toString().split(/[\r\n]+/g).map(x => x.trim()); + // We should not find the "missing-extension" at all, because its file extension + // is not executable on Windows (and the execute bit is missing on Unix) + expect(Executable.tryResolve('missing-extension', options)).toBeUndefined(); + }); - let lineIndex: number = 0; - if (os.platform() === 'win32') { - expect(outputLines[lineIndex++]).toEqual('Executing npm-binary-wrapper.cmd with args:'); - } else { - expect(outputLines[lineIndex++]).toEqual('Executing npm-binary-wrapper with args:'); + test('Executable.tryResolve() with path', () => { + const resolved: string | undefined = Executable.tryResolve('./npm-binary-wrapper', options); + expect(resolved).toBeUndefined(); + }); + + function executeNpmBinaryWrapper(args: string[]): string[] { + const result: child_process.SpawnSyncReturns = Executable.spawnSync( + 'npm-binary-wrapper', + args, + options + ); + expect(result.error).toBeUndefined(); + + expect(result.stderr).toBeDefined(); + expect(result.stderr.toString()).toEqual(''); + + expect(result.stdout).toBeDefined(); + const outputLines: string[] = result.stdout + .toString() + .split(/[\r\n]+/g) + .map((x) => x.trim()); + + let lineIndex: number = 0; + if (os.platform() === 'win32') { + expect(outputLines[lineIndex++]).toEqual('Executing npm-binary-wrapper.cmd with args:'); + } else { + expect(outputLines[lineIndex++]).toEqual('Executing npm-binary-wrapper with args:'); + } + // console.log('npm-binary-wrapper.cmd ARGS: ' + outputLines[lineIndex]); + ++lineIndex; // skip npm-binary-wrapper's args + + expect(outputLines[lineIndex++]).toEqual('Executing javascript-file.js with args:'); + + const stringifiedArgv: string = outputLines[lineIndex++]; + expect(stringifiedArgv.substr(0, 2)).toEqual('["'); + + const argv: string[] = JSON.parse(stringifiedArgv); + // Discard the first two array entries whose path is nondeterministic + argv.shift(); // the path to node.exe + argv.shift(); // the path to javascript-file.js + + return argv; } - // console.log('npm-binary-wrapper.cmd ARGS: ' + outputLines[lineIndex]); - ++lineIndex; // skip npm-binary-wrapper's args - expect(outputLines[lineIndex++]).toEqual('Executing javascript-file.js with args:'); + test('Executable.spawnSync("npm-binary-wrapper") simple', () => { + const args: string[] = ['arg1', 'arg2', 'arg3']; + expect(executeNpmBinaryWrapper(args)).toEqual(args); + }); - const stringifiedArgv: string = outputLines[lineIndex++]; - expect(stringifiedArgv.substr(0, 2)).toEqual('[\"'); + test('Executable.spawnSync("npm-binary-wrapper") edge cases 1', () => { + // Characters that confuse the CreateProcess() WIN32 API's encoding + const args: string[] = ['', '/', ' \t ', '"a', 'b"', '"c"', '\\"\\d', '!', '!TEST_VAR!']; + expect(executeNpmBinaryWrapper(args)).toEqual(args); + }); - const argv: string[] = JSON.parse(stringifiedArgv); - // Discard the first two array entries whose path is nondeterministic - argv.shift(); // the path to node.exe - argv.shift(); // the path to javascript-file.js + test('Executable.spawnSync("npm-binary-wrapper") edge cases 2', () => { + // All ASCII punctuation + const args: string[] = [ + // Characters that are impossible to escape for cmd.exe: + // %^&|<> newline + '~!@#$*()_+`={}[]:";\'?,./', + '~!@#$*()_+`={}[]:";\'?,./' + ]; + expect(executeNpmBinaryWrapper(args)).toEqual(args); + }); - return argv; -} + test('Executable.spawnSync("npm-binary-wrapper") edge cases 2', () => { + // All ASCII punctuation + const args: string[] = [ + // Characters that are impossible to escape for cmd.exe: + // %^&|<> newline + '~!@#$*()_+`={}[]:";\'?,./', + '~!@#$*()_+`={}[]:";\'?,./' + ]; + expect(executeNpmBinaryWrapper(args)).toEqual(args); + }); -test('Executable.spawnSync("npm-binary-wrapper") simple', () => { - const args: string[] = ['arg1', 'arg2', 'arg3']; - expect(executeNpmBinaryWrapper(args)).toEqual(args); -}); + test('Executable.spawnSync("npm-binary-wrapper") bad characters', () => { + if (os.platform() === 'win32') { + expect(() => { + executeNpmBinaryWrapper(['abc%123']); + }).toThrowError( + 'The command line argument "abc%123" contains a special character "%"' + + ' that cannot be escaped for the Windows shell' + ); + expect(() => { + executeNpmBinaryWrapper(['abc<>123']); + }).toThrowError( + 'The command line argument "abc<>123" contains a special character "<"' + + ' that cannot be escaped for the Windows shell' + ); + } + }); + + test('Executable.spawn("npm-binary-wrapper")', async () => { + const executablePath: string = path.join(executableFolder, 'success', 'npm-binary-wrapper'); + + await expect( + (() => { + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + + return new Promise((resolve, reject) => { + childProcess.on('exit', (code: number) => { + resolve(`Exit with code=${code}`); + }); + childProcess.on('error', (error: Error) => { + reject(`Failed with error: ${error.message}`); + }); + }); + })() + ).resolves.toBe('Exit with code=0'); + }); + + test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) without output', async () => { + const executablePath: string = path.join(executableFolder, 'success', 'npm-binary-wrapper'); + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + const result: IWaitForExitResultWithoutOutput = await Executable.waitForExitAsync(childProcess); + expect(result.exitCode).toEqual(0); + expect(result.signal).toBeNull(); + expect('stdout' in result).toBe(false); + expect('stderr' in result).toBe(false); + }); + + test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) with buffer output', async () => { + const executablePath: string = path.join(executableFolder, 'success', 'npm-binary-wrapper'); + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'buffer' + }); + expect(result.exitCode).toEqual(0); + expect(result.signal).toBeNull(); + expect(Buffer.isBuffer(result.stdout)).toEqual(true); + expect(Buffer.isBuffer(result.stderr)).toEqual(true); + expect(result.stdout.toString('utf8').includes('Executing javascript-file.js with args:')).toBe(true); + expect(result.stderr.toString('utf8')).toEqual(''); + }); -test('Executable.spawnSync("npm-binary-wrapper") edge cases 1', () => { - // Characters that confuse the CreateProcess() WIN32 API's encoding - const args: string[] = ['', '/', ' \t ', '"a', 'b"', '"c"', '\\"\\d', '!', '!TEST_VAR!']; - expect(executeNpmBinaryWrapper(args)).toEqual(args); + test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) with string output', async () => { + const executablePath: string = path.join(executableFolder, 'success', 'npm-binary-wrapper'); + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + expect(result.exitCode).toEqual(0); + expect(result.signal).toBeNull(); + expect(typeof result.stdout).toEqual('string'); + expect(typeof result.stderr).toEqual('string'); + expect(result.stdout.indexOf('Executing javascript-file.js with args:')).toBeGreaterThanOrEqual(0); + expect(result.stderr).toEqual(''); + }); + + test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) failure', async () => { + const executablePath: string = path.join(executableFolder, 'fail', 'npm-binary-wrapper'); + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + expect(result.exitCode).toEqual(1); + expect(result.signal).toBeNull(); + expect(typeof result.stdout).toEqual('string'); + expect(typeof result.stderr).toEqual('string'); + expect(result.stdout).toMatch(/^Executing npm-binary-wrapper(\.cmd)? with args:/); + expect(result.stderr.endsWith('This is a failure')); + }); + + test('Executable.runToCompletion(Executable.spawn("no-terminate")) killed', async () => { + const executablePath: string = path.join(executableFolder, 'no-terminate', 'javascript-file.js'); + const childProcess: child_process.ChildProcess = Executable.spawn( + process.argv0, + [executablePath, '1', '2', '3'], + { + environment, + currentWorkingDirectory: executableFolder + } + ); + + // Wait for the process to print the error line + expect(childProcess.stderr).toBeDefined(); + const [stderrPre] = await once(childProcess.stderr!, 'data'); + + const killResult: boolean = childProcess.kill('SIGTERM'); + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + + expect(killResult).toBe(true); + expect(result.signal).toBe('SIGTERM'); + expect(result.exitCode).toBeNull(); + expect(typeof result.stdout).toEqual('string'); + expect(typeof result.stderr).toEqual('string'); + expect(result.stdout).toMatch(/^Executing no-terminate with args:/); + expect((stderrPre.toString('utf8') + result.stderr).includes('This process never terminates')).toBe(true); + }); + + test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) failure with throw on non-zero exit code', async () => { + const executablePath: string = path.join(executableFolder, 'fail', 'npm-binary-wrapper'); + const childProcess: child_process.ChildProcess = Executable.spawn(executablePath, ['1', '2', '3'], { + environment, + currentWorkingDirectory: executableFolder + }); + await expect( + Executable.waitForExitAsync(childProcess, { encoding: 'utf8', throwOnNonZeroExitCode: true }) + ).rejects.toThrowError(/exited with code 1/); + }); + + test('Executable.runToCompletion(Executable.spawn("no-terminate")) failure with throw on signal', async () => { + const executablePath: string = path.join(executableFolder, 'no-terminate', 'javascript-file.js'); + const childProcess: child_process.ChildProcess = Executable.spawn( + process.argv0, + [executablePath, '1', '2', '3'], + { + environment, + currentWorkingDirectory: executableFolder + } + ); + childProcess.kill('SIGTERM'); + await expect( + Executable.waitForExitAsync(childProcess, { encoding: 'utf8', throwOnSignal: true }) + ).rejects.toThrowError(/Process terminated by SIGTERM/); + }); }); -test('Executable.spawnSync("npm-binary-wrapper") edge cases 2', () => { - // All ASCII punctuation - const args: string[] = [ - // Characters that are impossible to escape for cmd.exe: - // %^&|<> newline - '~!@#$*()_+`={}[]\:";\'?,./', - '~!@#$*()_+`={}[]\:";\'?,./' +describe('Executable process list', () => { + const WIN32_PROCESS_LIST_OUTPUT: (string | null)[] = [ + '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 + '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 executable2.exe\r\n', + '1 2 executable0.exe\r\n', + // Test children handling when multiple entries reference the same parent + '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 + '6 5 executable3.exe\r\n' ]; - expect(executeNpmBinaryWrapper(args)).toEqual(args); -}); -test('Executable.spawnSync("npm-binary-wrapper") edge cases 2', () => { - // All ASCII punctuation - const args: string[] = [ - // Characters that are impossible to escape for cmd.exe: - // %^&|<> newline - '~!@#$*()_+`={}[]\:";\'?,./', - '~!@#$*()_+`={}[]\:";\'?,./' + const UNIX_PROCESS_LIST_OUTPUT: (string | null)[] = [ + 'PPID PID COMMAND\n', + // Test that the parser can handle referencing a parent that doesn't exist + ' 0 1 init\n', + // Test that the parser can handle a line that is truncated in the middle of a field + // Test that the parser can handle an entry referencing a parent that hasn't been seen yet + // Test that the parser can handle whitespace at the end of the process name. + ' 2 4', + ' process2 \n', + ' 1 2 process0\n', + // Test that the parser can handle empty strings + '', + // Test children handling when multiple entries reference the same parent + ' 1 3 process1\n' ]; - expect(executeNpmBinaryWrapper(args)).toEqual(args); -}); -test('Executable.spawnSync("npm-binary-wrapper") bad characters', () => { - if (os.platform() === 'win32') { - expect(() => { executeNpmBinaryWrapper(['abc%123']); }) - .toThrowError('The command line argument "abc%123" contains a special character "%"' - + ' that cannot be escaped for the Windows shell'); - expect(() => { executeNpmBinaryWrapper(['abc<>123']); }) - .toThrowError('The command line argument "abc<>123" contains a special character "<"' - + ' that cannot be escaped for the Windows shell'); - } + 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); + expect(currentProcessInfo?.processName.startsWith('node')).toBe(true); + }); + + 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); + expect(currentProcessInfo?.processName.startsWith('node')).toBe(true); + }); + + test('parses win32 output', () => { + const processListMap: Map = parseProcessListOutput( + WIN32_PROCESS_LIST_OUTPUT, + 'win32' + ); + const results: IProcessInfo[] = [...processListMap.values()].sort(); + + // Expect 7 because we reference a parent that doesn't exist + expect(results.length).toEqual(7); + + // Since snapshot validation of circular entries is difficult to parse by humans, manually validate + // that the parent/child relationships are correct + expect(processListMap.get(0)!.parentProcessInfo).toBeUndefined(); + expect(processListMap.get(1)!.parentProcessInfo).toBe(processListMap.get(0)); + expect(processListMap.get(2)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(3)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(4)!.parentProcessInfo).toBe(processListMap.get(2)); + expect(processListMap.get(5)!.parentProcessInfo).toBe(processListMap.get(6)); + expect(processListMap.get(6)!.parentProcessInfo).toBeUndefined(); + + for (const processInfo of results) { + expect(processInfo).toMatchSnapshot(); + } + }); + + test('parses win32 stream output', async () => { + const processListMap: Map = await parseProcessListOutputAsync( + Readable.from(WIN32_PROCESS_LIST_OUTPUT), + 'win32' + ); + const results: IProcessInfo[] = [...processListMap.values()].sort(); + + // Expect 7 because we reference a parent that doesn't exist + expect(results.length).toEqual(7); + + // Since snapshot validation of circular entries is difficult to parse by humans, manually validate + // that the parent/child relationships are correct + expect(processListMap.get(0)!.parentProcessInfo).toBeUndefined(); + expect(processListMap.get(1)!.parentProcessInfo).toBe(processListMap.get(0)); + expect(processListMap.get(2)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(3)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(4)!.parentProcessInfo).toBe(processListMap.get(2)); + expect(processListMap.get(5)!.parentProcessInfo).toBe(processListMap.get(6)); + expect(processListMap.get(6)!.parentProcessInfo).toBeUndefined(); + + for (const processInfo of results) { + expect(processInfo).toMatchSnapshot(); + } + }); + + test('parses unix output', () => { + const processListMap: Map = parseProcessListOutput( + UNIX_PROCESS_LIST_OUTPUT, + 'linux' + ); + const results: IProcessInfo[] = [...processListMap.values()].sort(); + + // Expect 5 because we reference a parent that doesn't exist + expect(results.length).toEqual(5); + + // Since snapshot validation of circular entries is difficult to parse by humans, manually validate + // that the parent/child relationships are correct + expect(processListMap.get(0)!.parentProcessInfo).toBeUndefined(); + expect(processListMap.get(1)!.parentProcessInfo).toBe(processListMap.get(0)); + expect(processListMap.get(2)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(3)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(4)!.parentProcessInfo).toBe(processListMap.get(2)); + + for (const processInfo of results) { + expect(processInfo).toMatchSnapshot(); + } + }); + + test('parses unix stream output', async () => { + const processListMap: Map = await parseProcessListOutputAsync( + Readable.from(UNIX_PROCESS_LIST_OUTPUT), + 'linux' + ); + const results: IProcessInfo[] = [...processListMap.values()].sort(); + + // Expect 5 because we reference a parent that doesn't exist + expect(results.length).toEqual(5); + + // Since snapshot validation of circular entries is difficult to parse by humans, manually validate + // that the parent/child relationships are correct + expect(processListMap.get(0)!.parentProcessInfo).toBeUndefined(); + expect(processListMap.get(1)!.parentProcessInfo).toBe(processListMap.get(0)); + expect(processListMap.get(2)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(3)!.parentProcessInfo).toBe(processListMap.get(1)); + expect(processListMap.get(4)!.parentProcessInfo).toBe(processListMap.get(2)); + + for (const processInfo of results) { + expect(processInfo).toMatchSnapshot(); + } + }); }); diff --git a/libraries/node-core-library/src/test/FileError.test.ts b/libraries/node-core-library/src/test/FileError.test.ts new file mode 100644 index 00000000000..03887d624fd --- /dev/null +++ b/libraries/node-core-library/src/test/FileError.test.ts @@ -0,0 +1,416 @@ +// 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 { FileError } from '../FileError'; +import type { FileLocationStyle } from '../Path'; + +describe(FileError.name, () => { + 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; + } + }); + + it('returns Unix-style relative file path formatting for the toString() method', () => { + const error1: FileError = new FileError('message', { + absolutePath: `/path/to/project/path/to/file`, + projectFolder: '/path/to/project' + }); + expect(error1.toString()).toMatchInlineSnapshot(`"path/to/file - message"`); + }); + + it('correctly performs Unix-style relative file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + expect(error1.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"path/to/file:5:12 - message"` + ); + + const error2: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5 + }); + expect(error2.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"path/to/file:5 - message"` + ); + + const error3: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: undefined, + column: 12 + }); + expect(error3.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"path/to/file - message"` + ); + + const error4: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project' + }); + expect(error4.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"path/to/file - message"` + ); + }); + + it('correctly performs Unix-style file absolute path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error1Message: string = error1.getFormattedErrorMessage({ format: 'Unix' }); + expect(error1Message).toMatch(/.+:5:12 - message$/); + const error1Path: string = error1Message.slice(0, error1Message.length - ':5:12 - message'.length); + expect(path.isAbsolute(error1Path)).toEqual(true); + + const error2: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: 5 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error2Message: string = error2.getFormattedErrorMessage({ format: 'Unix' }); + expect(error2Message).toMatch(/.+:5 - message$/); + const error2Path: string = error2Message.slice(0, error2Message.length - ':5 - message'.length); + expect(path.isAbsolute(error2Path)).toEqual(true); + + const error3: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: undefined, + column: 12 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error3Message: string = error3.getFormattedErrorMessage({ format: 'Unix' }); + expect(error3Message).toMatch(/.+ - message$/); + const error3Path: string = error3Message.slice(0, error3Message.length - ' - message'.length); + expect(path.isAbsolute(error3Path)).toEqual(true); + + const error4: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project' + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error4Message: string = error4.getFormattedErrorMessage({ format: 'Unix' }); + expect(error4Message).toMatch(/.+ - message$/); + const error4Path: string = error4Message.slice(0, error4Message.length - ' - message'.length); + expect(path.isAbsolute(error4Path)).toEqual(true); + }); + + it('correctly performs Visual Studio-style relative file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + expect(error1.getFormattedErrorMessage({ format: 'VisualStudio' })).toMatchInlineSnapshot( + `"path/to/file(5,12) - message"` + ); + + const error2: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5 + }); + expect(error2.getFormattedErrorMessage({ format: 'VisualStudio' })).toMatchInlineSnapshot( + `"path/to/file(5) - message"` + ); + + const error3: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: undefined, + column: 12 + }); + expect(error3.getFormattedErrorMessage({ format: 'VisualStudio' })).toMatchInlineSnapshot( + `"path/to/file - message"` + ); + + const error4: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project' + }); + expect(error4.getFormattedErrorMessage({ format: 'VisualStudio' })).toMatchInlineSnapshot( + `"path/to/file - message"` + ); + }); + + it('correctly performs Visual Studio-style absolute file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error1Message: string = error1.getFormattedErrorMessage({ format: 'VisualStudio' }); + expect(error1Message).toMatch(/.+\(5,12\) - message$/); + const error1Path: string = error1Message.slice(0, error1Message.length - '(5,12) - message'.length); + expect(path.isAbsolute(error1Path)).toEqual(true); + + const error2: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: 5 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error2Message: string = error2.getFormattedErrorMessage({ format: 'VisualStudio' }); + expect(error2Message).toMatch(/.+\(5\) - message$/); + const error2Path: string = error2Message.slice(0, error2Message.length - '(5) - message'.length); + expect(path.isAbsolute(error2Path)).toEqual(true); + + const error3: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project', + line: undefined, + column: 12 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error3Message: string = error3.getFormattedErrorMessage({ format: 'VisualStudio' }); + expect(error3Message).toMatch(/.+ - message$/); + const error3Path: string = error3Message.slice(0, error3Message.length - ' - message'.length); + expect(path.isAbsolute(error3Path)).toEqual(true); + + const error4: FileError = new FileError('message', { + absolutePath: '/path/to/file', + projectFolder: '/path/to/project' + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error4Message: string = error4.getFormattedErrorMessage({ format: 'VisualStudio' }); + expect(error4Message).toMatch(/.+ - message$/); + const error4Path: string = error4Message.slice(0, error4Message.length - ' - message'.length); + expect(path.isAbsolute(error4Path)).toEqual(true); + }); +}); + +describe(`${FileError.name} using arbitrary base folder`, () => { + let originalValue: string | undefined; + + beforeEach(() => { + FileError._sanitizedEnvironmentVariable = undefined; + FileError._environmentVariableIsAbsolutePath = false; + originalValue = process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = '/path'; + }); + + afterEach(() => { + if (originalValue) { + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = originalValue; + } else { + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + } + }); + + it('correctly performs Unix-style file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + expect(error1.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"to/project/path/to/file:5:12 - message"` + ); + }); +}); + +describe(`${FileError.name} using PROJECT_FOLDER base folder`, () => { + let originalValue: string | undefined; + + beforeEach(() => { + FileError._sanitizedEnvironmentVariable = undefined; + FileError._environmentVariableIsAbsolutePath = false; + originalValue = process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = '{PROJECT_FOLDER}'; + }); + + afterEach(() => { + if (originalValue) { + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = originalValue; + } else { + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + } + }); + + it('correctly performs Unix-style file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + expect(error1.getFormattedErrorMessage({ format: 'Unix' })).toMatchInlineSnapshot( + `"path/to/file:5:12 - message"` + ); + }); +}); + +describe(`${FileError.name} using ABSOLUTE_PATH base folder`, () => { + let originalValue: string | undefined; + + beforeEach(() => { + FileError._sanitizedEnvironmentVariable = undefined; + FileError._environmentVariableIsAbsolutePath = false; + originalValue = process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = '{ABSOLUTE_PATH}'; + }); + + afterEach(() => { + if (originalValue) { + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = originalValue; + } else { + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + } + }); + + it('correctly performs Unix-style file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + // Because the file path is resolved on disk, the output will vary based on platform. + // Only check that it ends as expected and is an absolute path. + const error1Message: string = error1.getFormattedErrorMessage({ format: 'Unix' }); + expect(error1Message).toMatch(/.+:5:12 - message$/); + const error1Path: string = error1Message.slice(0, error1Message.length - ':5:12 - message'.length); + expect(path.isAbsolute(error1Path)).toEqual(true); + }); +}); + +describe(`${FileError.name} using unsupported base folder token`, () => { + let originalValue: string | undefined; + + beforeEach(() => { + FileError._sanitizedEnvironmentVariable = undefined; + FileError._environmentVariableIsAbsolutePath = false; + originalValue = process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = '{SOME_TOKEN}'; + }); + + afterEach(() => { + if (originalValue) { + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = originalValue; + } else { + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + } + }); + + it('throws when performing Unix-style file path formatting', () => { + const error1: FileError = new FileError('message', { + absolutePath: '/path/to/project/path/to/file', + projectFolder: '/path/to/project', + line: 5, + column: 12 + }); + expect(() => error1.getFormattedErrorMessage({ format: 'Unix' })).toThrowError(); + }); +}); + +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..05e257d4917 100644 --- a/libraries/node-core-library/src/test/FileSystem.test.ts +++ b/libraries/node-core-library/src/test/FileSystem.test.ts @@ -1,25 +1,54 @@ // 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 */ +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-'); -test('PosixModeBits tests', () => { - let modeBits: number = PosixModeBits.AllRead | PosixModeBits.AllWrite; + // Add the group execute bit + modeBits |= PosixModeBits.OthersExecute; + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrwx'); - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rw-rw-'); + // Add the group execute bit + modeBits &= ~PosixModeBits.AllWrite; + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-r--r-xr-x'); + /* eslint-enable no-bitwise */ + }); - modeBits |= PosixModeBits.GroupExecute; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrw-'); + 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); + }); - // Add the group execute bit - modeBits |= PosixModeBits.OthersExecute; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrwx'); + 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); + } + }); - // Add the group execute bit - modeBits &= ~PosixModeBits.AllWrite; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-r--r-xr-x'); + 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); + } + }); + }); }); diff --git a/libraries/node-core-library/src/test/Import.test.ts b/libraries/node-core-library/src/test/Import.test.ts new file mode 100644 index 00000000000..c58420be51e --- /dev/null +++ b/libraries/node-core-library/src/test/Import.test.ts @@ -0,0 +1,321 @@ +// 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 'node:path'; +import { Import } from '../Import'; +import { PackageJsonLookup } from '../PackageJsonLookup'; +import { Path } from '../Path'; + +describe(Import.name, () => { + const packageRoot: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; + + function expectToThrowNormalizedErrorMatchingSnapshot(fn: () => void): void { + try { + fn(); + fail('Expected an error to be thrown'); + } catch (error) { + const normalizedErrorMessage: string = error.message + .replace(packageRoot, '') + .replace(__dirname, '') + .replace(/\\/g, '/'); + expect(normalizedErrorMessage).toMatchSnapshot(); + } + } + + describe(Import.resolveModule.name, () => { + it('returns an absolute path as-is', () => { + const absolutePaths: string[] = ['/var/test/path']; + + for (const absolutePath of absolutePaths) { + expect(Import.resolveModule({ modulePath: absolutePath, baseFolderPath: __dirname })).toEqual( + absolutePath + ); + } + }); + + it('resolves a relative path', () => { + expect(Import.resolveModule({ modulePath: './baz', baseFolderPath: __dirname })).toEqual( + nodeJsPath.join(__dirname, 'baz') + ); + expect(Import.resolveModule({ modulePath: '../baz', baseFolderPath: __dirname })).toEqual( + nodeJsPath.resolve(__dirname, '..', 'baz') + ); + expect(Import.resolveModule({ modulePath: './baz/ban', baseFolderPath: __dirname })).toEqual( + nodeJsPath.join(__dirname, 'baz', 'ban') + ); + expect(Import.resolveModule({ modulePath: '../baz/ban', baseFolderPath: __dirname })).toEqual( + nodeJsPath.resolve(__dirname, '..', 'baz', 'ban') + ); + }); + + it('resolves a dependency', () => { + expect( + Path.convertToSlashes( + Import.resolveModule({ modulePath: '@rushstack/heft', baseFolderPath: __dirname }) + ) + ).toMatch(/node_modules\/@rushstack\/heft\/lib\/index.js$/); + }); + + it('resolves a path inside a dependency', () => { + expect( + Path.convertToSlashes( + Import.resolveModule({ + modulePath: '@rushstack/heft/lib/start.js', + baseFolderPath: __dirname + }) + ) + ).toMatch(/node_modules\/@rushstack\/heft\/lib\/start\.js$/); + }); + + it('resolves a path inside a dependency without an extension', () => { + expect( + Path.convertToSlashes( + Import.resolveModule({ + modulePath: '@rushstack/heft/lib/start', + baseFolderPath: __dirname + }) + ) + ).toMatch(/node_modules\/@rushstack\/heft\/lib\/start\.js$/); + }); + + it('resolves a dependency of a dependency', () => { + expect( + Path.convertToSlashes( + Import.resolveModule({ + modulePath: '@rushstack/ts-command-line', + baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') + }) + ) + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/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', + baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') + }) + ) + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/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', + baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') + }) + ) + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/Constants\.js$/); + }); + + describe('allowSelfReference', () => { + it('resolves a path inside this package with allowSelfReference turned on', () => { + expect( + Import.resolveModule({ + modulePath: '@rushstack/node-core-library', + baseFolderPath: __dirname, + allowSelfReference: true + }) + ).toEqual(packageRoot); + expect( + Import.resolveModule({ + modulePath: '@rushstack/node-core-library/lib/Constants.js', + baseFolderPath: __dirname, + allowSelfReference: true + }) + ).toEqual(nodeJsPath.join(packageRoot, 'lib', 'Constants.js')); + }); + + it('resolves the real path inside a package with allowSelfReference turned on', () => { + const heftPackageRoot: string = nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft'); + const heftPackageJsonRealPath: string = require.resolve('@rushstack/heft/package.json'); + expect( + Import.resolveModule({ + modulePath: '@rushstack/heft/package.json', + baseFolderPath: heftPackageRoot, + allowSelfReference: true + }) + ).toEqual(heftPackageJsonRealPath); + }); + + it('throws on an attempt to reference this package without allowSelfReference turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolveModule({ + modulePath: '@rushstack/node-core-library', + baseFolderPath: __dirname + }) + ); + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolveModule({ + modulePath: '@rushstack/node-core-library/lib/Constants.js', + baseFolderPath: __dirname + }) + ); + }); + }); + + describe('includeSystemModules', () => { + it('resolves a system module with includeSystemModules turned on', () => { + expect( + Import.resolveModule({ modulePath: 'fs', baseFolderPath: __dirname, includeSystemModules: true }) + ).toEqual('fs'); + }); + + it('throws on an attempt to resolve a system module without includeSystemModules turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolveModule({ modulePath: 'fs', baseFolderPath: __dirname }) + ); + }); + + it('resolves an existing path inside a system module with includeSystemModules turned on', () => { + expect( + Import.resolveModule({ + modulePath: 'fs/promises', + baseFolderPath: __dirname, + includeSystemModules: true + }) + ).toEqual('fs/promises'); + }); + + it('throws on an attempt to resolve a non-existing path inside a system module with includeSystemModules turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolveModule({ + modulePath: 'fs/foo/bar', + baseFolderPath: __dirname, + includeSystemModules: true + }) + ); + }); + }); + }); + + describe(Import.resolvePackage.name, () => { + it('resolves a dependency', () => { + expect( + Import.resolvePackage({ packageName: '@rushstack/heft', baseFolderPath: __dirname }).replace( + /\\/g, + '/' + ) + ).toMatch(/node_modules\/@rushstack\/heft$/); + }); + + it('fails to resolve a path inside a dependency', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Path.convertToSlashes( + Import.resolvePackage({ + packageName: '@rushstack/heft/lib/start.js', + baseFolderPath: __dirname + }) + ) + ); + }); + + it('resolves a dependency of a dependency', () => { + expect( + Path.convertToSlashes( + Import.resolvePackage({ + packageName: '@rushstack/ts-command-line', + baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') + }) + ) + ).toMatch(/node_modules\/@rushstack\/ts-command-line$/); + }); + + it('fails to resolve a path inside a dependency of a dependency', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Path.convertToSlashes( + Import.resolvePackage({ + packageName: '@rushstack/ts-command-line/lib/Constants.js', + baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') + }) + ) + ); + }); + + describe('allowSelfReference', () => { + it('resolves this package with allowSelfReference turned on', () => { + expect( + Import.resolvePackage({ + packageName: '@rushstack/node-core-library', + baseFolderPath: __dirname, + allowSelfReference: true + }) + ).toEqual(packageRoot); + }); + + it('resolves the real path of a package with allowSelfReference turned on', () => { + const heftPackageRoot: string = nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft'); + const resolvedHeftPackageRoot: string = nodeJsPath.dirname( + require.resolve('@rushstack/heft/package.json') + ); + expect( + Import.resolvePackage({ + packageName: '@rushstack/heft', + baseFolderPath: heftPackageRoot, + allowSelfReference: true + }) + ).toEqual(resolvedHeftPackageRoot); + }); + + it('fails to resolve a path inside this package with allowSelfReference turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolvePackage({ + packageName: '@rushstack/node-core-library/lib/Constants.js', + baseFolderPath: __dirname, + allowSelfReference: true + }) + ); + }); + + it('throws on an attempt to reference this package without allowSelfReference turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolvePackage({ + packageName: '@rushstack/node-core-library', + baseFolderPath: __dirname + }) + ); + }); + }); + + describe('includeSystemModules', () => { + it('resolves a system module with includeSystemModules turned on', () => { + expect( + Import.resolvePackage({ + packageName: 'fs', + baseFolderPath: __dirname, + includeSystemModules: true + }) + ).toEqual('fs'); + }); + + it('throws on an attempt to resolve a system module without includeSystemModules turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolvePackage({ packageName: 'fs', baseFolderPath: __dirname }) + ); + }); + + it('resolves an an existing path inside a system module with includeSystemModules turned on', () => { + expect( + Import.resolvePackage({ + packageName: 'fs/promises', + baseFolderPath: __dirname, + includeSystemModules: true + }) + ).toEqual('fs/promises'); + }); + + it('throws on an attempt to resolve a non-existing path inside a system module with includeSystemModules turned on', () => { + expectToThrowNormalizedErrorMatchingSnapshot(() => + Import.resolvePackage({ + packageName: 'fs/foo/bar', + baseFolderPath: __dirname, + includeSystemModules: true + }) + ); + }); + }); + }); +}); diff --git a/libraries/node-core-library/src/test/JsonFile.test.ts b/libraries/node-core-library/src/test/JsonFile.test.ts new file mode 100644 index 00000000000..f33d0a0877e --- /dev/null +++ b/libraries/node-core-library/src/test/JsonFile.test.ts @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile } from '../JsonFile'; + +// The PosixModeBits are intended to be used with bitwise operations. + +describe(JsonFile.name, () => { + it('adds a header comment', () => { + expect( + JsonFile.stringify( + { abc: 123 }, + { + headerComment: '// header\n// comment' + } + ) + ).toMatchSnapshot(); + }); + + it('adds an empty header comment', () => { + expect( + JsonFile.stringify( + { abc: 123 }, + { + headerComment: '' + } + ) + ).toMatchSnapshot(); + }); + + it('allows undefined values when asked', () => { + expect( + JsonFile.stringify( + { abc: undefined }, + { + ignoreUndefinedValues: true + } + ) + ).toMatchSnapshot(); + + expect( + JsonFile.stringify( + { abc: undefined }, + { + ignoreUndefinedValues: true, + prettyFormatting: true + } + ) + ).toMatchSnapshot(); + }); + + it('supports updating a simple file', () => { + expect(JsonFile.updateString('{"a": 1}', { a: 1, b: 2 })).toMatchSnapshot(); + }); + + it('supports updating a simple file with a comment', () => { + expect(JsonFile.updateString(`{\n // comment\n "a": 1\n}`, { a: 1, b: 2 })).toMatchSnapshot(); + }); + + it('supports updating a simple file with a comment and a trailing comma', () => { + expect(JsonFile.updateString(`{\n // comment\n "a": 1,\n}`, { a: 1, b: 2 })).toMatchSnapshot(); + }); + + it('supports updating a simple file with an unquoted property', () => { + expect( + JsonFile.updateString(`{\n // comment\n a: 1,\n}`, { a: 1, b: 2, 'c-123': 3 }) + ).toMatchSnapshot(); + }); + + it('supports parsing keys that map to `Object` properties', () => { + const propertyStrings: string[] = []; + for (const objectKey of Object.getOwnPropertyNames(Object.prototype).sort()) { + propertyStrings.push(`"${objectKey}": 1`); + } + + const jsonString: string = `{\n ${propertyStrings.join(',\n ')}\n}`; + expect(jsonString).toMatchSnapshot('JSON String'); + expect(JsonFile.parseString(jsonString)).toMatchSnapshot('Parsed JSON Object'); + }); +}); diff --git a/libraries/node-core-library/src/test/JsonSchema.test.ts b/libraries/node-core-library/src/test/JsonSchema.test.ts index 08a56589e4b..c5f9ffa9df3 100644 --- a/libraries/node-core-library/src/test/JsonSchema.test.ts +++ b/libraries/node-core-library/src/test/JsonSchema.test.ts @@ -1,54 +1,150 @@ // 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 { JsonFile, JsonObject } from '../JsonFile'; -import { JsonSchema, IJsonSchemaErrorInfo } from '../JsonSchema'; +import { JsonFile, type JsonObject } from '../JsonFile'; +import { JsonSchema, type IJsonSchemaErrorInfo } from '../JsonSchema'; -function normalize(text: string): string { - return text.replace(/[\r\n ]+/g, ' ') - .trim(); -} +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', () => { - const schemaPath: string = path.resolve(path.join(__dirname, './test-data/test-schema.json')); +describe(JsonSchema.name, () => { + const schema: JsonSchema = JsonSchema.fromFile(SCHEMA_PATH, { + schemaVersion: 'draft-07' + }); - const schema: JsonSchema = JsonSchema.fromFile(schemaPath); + describe(JsonFile.loadAndValidate.name, () => { + test('successfully validates a JSON file', () => { + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; + const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schema); - test('loadAndValidate successfully validates a JSON file', () => { - const jsonPath: string = path.resolve(path.join(__dirname, './test-data/test.json')); - const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schema); - expect(jsonObject).toMatchObject( - { - 'exampleString': 'This is a string', - 'exampleArray': [ - 'apple', - 'banana', - 'coconut' - ] + expect(jsonObject).toMatchObject({ + exampleString: 'This is a string', + exampleArray: ['apple', 'banana', 'coconut'] + }); + }); + + 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-schemas/test-valid.schema.json`; + const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaDraft04); + + expect(jsonObject).toMatchObject({ + exampleString: 'This is a string', + exampleArray: ['apple', 'banana', 'coconut'] + }); + }); + + test('throws an error if the wrong schema version is explicitly specified for an incompatible schema object', () => { + const schemaDraft04: JsonSchema = JsonSchema.fromFile(DRAFT_04_SCHEMA_PATH, { + schemaVersion: 'draft-07' + }); + + 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-schemas/test-valid.schema.json`; + const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaDraft07); + + expect(jsonObject).toMatchObject({ + exampleString: 'This is a string', + exampleArray: ['apple', 'banana', 'coconut'] + }); + }); + + test('validates a JSON file using nested schemas', () => { + 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-schemas/test-schema-nested.schema.json`; + const schemaNested: JsonSchema = JsonSchema.fromFile(schemaPathNested, { + dependentSchemas: [schemaChild] + }); + + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; + const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaNested); + + expect(jsonObject).toMatchObject({ + exampleString: 'This is a string', + exampleArray: ['apple', 'banana', 'coconut'] + }); + }); + + test('throws an error for an invalid nested schema', () => { + 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-schemas/test-schema-nested.schema.json`; + const schemaNested: JsonSchema = JsonSchema.fromFile(schemaPathNested, { + dependentSchemas: [schemaInvalidChild] + }); + + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; + + expect.assertions(1); + try { + JsonFile.loadAndValidate(jsonPath, schemaNested); + } catch (err) { + expect(err.message).toMatchSnapshot(); } - ); + }); }); - test('validateObjectWithCallback successfully reports a compound validation error', () => { - const jsonPath2: string = path.resolve(path.join(__dirname, './test-data/test2.json')); - const jsonObject2: JsonObject = JsonFile.load(jsonPath2); + describe(JsonSchema.prototype.validateObjectWithCallback.name, () => { + test('successfully reports a compound validation error schema errors', () => { + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-invalid-additional.schema.json`; + const jsonObject: JsonObject = JsonFile.load(jsonPath); + + const errorDetails: string[] = []; + schema.validateObjectWithCallback(jsonObject, (errorInfo: IJsonSchemaErrorInfo) => { + errorDetails.push(errorInfo.details); + }); - const expectedError: string = ` -Error: #/exampleOneOf (Description for exampleOneOf - this i...) - Data does not match any schemas from 'oneOf' -Error: #/exampleOneOf (Description for type1) - Additional properties not allowed: field2 -Error: #/exampleOneOf (Description for type2) - Missing required property: field3`; + expect(errorDetails).toMatchSnapshot(); + }); + test('successfully reports a compound validation error for format errors', () => { + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-invalid-format.schema.json`; + const jsonObject: JsonObject = JsonFile.load(jsonPath); - let errorCount: number = 0; + const errorDetails: string[] = []; + schema.validateObjectWithCallback(jsonObject, (errorInfo: IJsonSchemaErrorInfo) => { + errorDetails.push(errorInfo.details); + }); - schema.validateObjectWithCallback(jsonObject2, (errorInfo: IJsonSchemaErrorInfo) => { - ++errorCount; - expect(normalize(errorInfo.details)).toEqual(normalize(expectedError)); + expect(errorDetails).toMatchSnapshot(); }); + }); - expect(errorCount).toEqual(1); + test('successfully applies custom formats', () => { + const schemaWithCustomFormat = JsonSchema.fromLoadedObject( + { + title: 'Test Custom Format', + type: 'object', + properties: { + exampleNumber: { + type: 'number', + format: 'uint8' + } + }, + additionalProperties: false, + required: ['exampleNumber'] + }, + { + schemaVersion: 'draft-07', + customFormats: { + uint8: { + type: 'number', + validate: (data) => data >= 0 && data <= 255 + } + } + } + ); + expect(() => schemaWithCustomFormat.validateObject({ exampleNumber: 10 }, '')).not.toThrow(); + expect(() => schemaWithCustomFormat.validateObject({ exampleNumber: 1000 }, '')).toThrow(); }); }); diff --git a/libraries/node-core-library/src/test/LockFile.test.ts b/libraries/node-core-library/src/test/LockFile.test.ts index 1d482b7a72c..ea927795713 100644 --- a/libraries/node-core-library/src/test/LockFile.test.ts +++ b/libraries/node-core-library/src/test/LockFile.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 { LockFile, getProcessStartTime, getProcessStartTimeFromProcStat } from '../LockFile'; import { FileSystem } from '../FileSystem'; import { FileWriter } from '../FileWriter'; @@ -11,13 +11,17 @@ function setLockFileGetProcessStartTime(fn: (process: number) => string | undefi (LockFile as any)._getStartTime = fn; } -describe('LockFile', () => { +// lib/test +const libTestFolder: string = path.resolve(__dirname, '../../lib/test'); + +describe(LockFile.name, () => { afterEach(() => { + jest.restoreAllMocks(); setLockFileGetProcessStartTime(getProcessStartTime); }); - describe('getLockFilePath', () => { - test('only acceps alphabetical characters for resource name', () => { + describe(LockFile.getLockFilePath.name, () => { + test('only accepts alphabetical characters for resource name', () => { expect(() => { LockFile.getLockFilePath(process.cwd(), 'foo123'); }).not.toThrow(); @@ -49,8 +53,8 @@ describe('LockFile', () => { }); }); - describe('getProcessStartTimeFromProcStat', () => { - function createStatOutput (value2: string, n: number): string { + describe(getProcessStartTimeFromProcStat.name, () => { + function createStatOutput(value2: string, n: number): string { let statOutput: string = `0 ${value2} S`; for (let i: number = 0; i < n; i++) { statOutput += ' 0'; @@ -60,53 +64,92 @@ describe('LockFile', () => { test('returns undefined if too few values are contained in /proc/[pid]/stat (1)', () => { const stat: string = createStatOutput('(bash)', 1); - const ret: string|undefined = getProcessStartTimeFromProcStat(stat); + const ret: string | undefined = getProcessStartTimeFromProcStat(stat); expect(ret).toBeUndefined(); }); test('returns undefined if too few values are contained in /proc/[pid]/stat (2)', () => { const stat: string = createStatOutput('(bash)', 0); - const ret: string|undefined = getProcessStartTimeFromProcStat(stat); + const ret: string | undefined = getProcessStartTimeFromProcStat(stat); expect(ret).toBeUndefined(); }); test('returns the correct start time if the second value in /proc/[pid]/stat contains spaces', () => { let stat: string = createStatOutput('(bash 2)', 18); const value22: string = '12345'; stat += ` ${value22}`; - const ret: string|undefined = getProcessStartTimeFromProcStat(stat); - expect(ret).toEqual(value22); - }); - test('returns the correct start time if there are 22 values in /proc/[pid]/stat, including a trailing line ' - + 'terminator', () => { - let stat: string = createStatOutput('(bash)', 18); - const value22: string = '12345'; - stat += ` ${value22}\n`; - const ret: string|undefined = getProcessStartTimeFromProcStat(stat); + const ret: string | undefined = getProcessStartTimeFromProcStat(stat); expect(ret).toEqual(value22); }); + test( + 'returns the correct start time if there are 22 values in /proc/[pid]/stat, including a trailing line ' + + 'terminator', + () => { + let stat: string = createStatOutput('(bash)', 18); + const value22: string = '12345'; + stat += ` ${value22}\n`; + const ret: string | undefined = getProcessStartTimeFromProcStat(stat); + expect(ret).toEqual(value22); + } + ); test('returns the correct start time if the second value in /proc/[pid]/stat does not contain spaces', () => { let stat: string = createStatOutput('(bash)', 18); const value22: string = '12345'; stat += ` ${value22}`; - const ret: string|undefined = getProcessStartTimeFromProcStat(stat); + const ret: string | undefined = getProcessStartTimeFromProcStat(stat); expect(ret).toEqual(value22); }); }); + it('supports two lockfiles in the same process', async () => { + const testFolder: string = `${libTestFolder}/6`; + await FileSystem.ensureEmptyFolderAsync(testFolder); + + const resourceName: string = 'test1'; + + const lock1: LockFile = await LockFile.acquireAsync(testFolder, resourceName); + const lock2Promise: Promise = LockFile.acquireAsync(testFolder, resourceName); + + let lock2Acquired: boolean = false; + lock2Promise + .then(() => { + lock2Acquired = true; + }) + .catch(() => { + fail(); + }); + + const lock1Exists: boolean = await FileSystem.existsAsync(lock1.filePath); + expect(lock1Exists).toEqual(true); + expect(lock1.isReleased).toEqual(false); + expect(lock2Acquired).toEqual(false); + + lock1.release(); + + expect(lock1.isReleased).toEqual(true); + + const lock2: LockFile = await lock2Promise; + + const lock2Exists: boolean = await FileSystem.existsAsync(lock2.filePath); + expect(lock2Exists).toEqual(true); + expect(lock2.isReleased).toEqual(false); + + expect(lock2Acquired).toEqual(true); + + lock2.release(); + + expect(lock2.isReleased).toEqual(true); + }); + if (process.platform === 'darwin' || process.platform === 'linux') { describe('Linux and Mac', () => { - describe('getLockFilePath()', () => { + describe(LockFile.getLockFilePath.name, () => { test('returns a resolved path containing the pid', () => { - expect( - path.join(process.cwd(), `test#${process.pid}.lock`) - ).toEqual( + expect(path.join(process.cwd(), `test#${process.pid}.lock`)).toEqual( LockFile.getLockFilePath('./', 'test') ); }); test('allows for overridden pid', () => { - expect( - path.join(process.cwd(), `test#99.lock`) - ).toEqual( + expect(path.join(process.cwd(), `test#99.lock`)).toEqual( LockFile.getLockFilePath('./', 'test', 99) ); }); @@ -114,7 +157,7 @@ describe('LockFile', () => { test('can acquire and close a clean lockfile', () => { // ensure test folder is clean - const testFolder: string = path.join(__dirname, '1'); + const testFolder: string = path.join(libTestFolder, '1'); FileSystem.ensureEmptyFolder(testFolder); const resourceName: string = 'test'; @@ -140,7 +183,7 @@ describe('LockFile', () => { test('cannot acquire a lock if another valid lock exists', () => { // ensure test folder is clean - const testFolder: string = path.join(__dirname, '2'); + const testFolder: string = path.join(libTestFolder, '2'); FileSystem.ensureEmptyFolder(testFolder); const otherPid: number = 999999999; @@ -168,95 +211,198 @@ describe('LockFile', () => { // this lock should be undefined since there is an existing lock expect(lock).toBeUndefined(); }); - }); - } - if (process.platform === 'win32') { - describe('getLockFilePath()', () => { - test('returns a resolved path that doesn\'t contain', () => { - expect( - path.join(process.cwd(), `test.lock`) - ).toEqual( - LockFile.getLockFilePath('./', 'test') - ); + test('cannot acquire a lock if another valid lock exists with the same start time', () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '3'); + FileSystem.ensureEmptyFolder(testFolder); + + const otherPid: number = 1; // low pid so the other lock is before us + const otherPidStartTime: string = '2012-01-02 12:53:12'; + const thisPidStartTime: string = otherPidStartTime; + + const resourceName: string = 'test'; + + const otherPidLockFileName: string = LockFile.getLockFilePath(testFolder, resourceName, otherPid); + + setLockFileGetProcessStartTime((pid: number) => { + return pid === process.pid ? thisPidStartTime : otherPidStartTime; + }); + + // create an open lockfile + const lockFileHandle: FileWriter = FileWriter.open(otherPidLockFileName); + lockFileHandle.write(otherPidStartTime); + lockFileHandle.close(); + FileSystem.updateTimes(otherPidLockFileName, { + accessedTime: 10000, + modifiedTime: 10000 + }); + + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + + // this lock should be undefined since there is an existing lock + expect(lock).toBeUndefined(); }); - test('ignores pid that is passed in', () => { - expect( - path.join(process.cwd(), `test.lock`) - ).toEqual( - LockFile.getLockFilePath('./', 'test', 99) - ); + test('deletes other hanging lockfiles if corresponding processes are not running anymore', () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '4'); + FileSystem.ensureEmptyFolder(testFolder); + + const resourceName: string = 'test'; + + const otherPid: number = 999999999; + const otherPidInitialStartTime: string = '2012-01-02 12:53:12'; + + // simulate a hanging lockfile that was not cleaned by other process + const otherPidLockFileName: string = LockFile.getLockFilePath(testFolder, resourceName, otherPid); + const lockFileHandle: FileWriter = FileWriter.open(otherPidLockFileName); + lockFileHandle.write(otherPidInitialStartTime); + lockFileHandle.close(); + FileSystem.updateTimes(otherPidLockFileName, { + accessedTime: 10000, + modifiedTime: 10000 + }); + + // return undefined as if the process was not running anymore + setLockFileGetProcessStartTime((pid: number) => { + return pid === otherPid ? undefined : getProcessStartTime(pid); + }); + + const deleteFileSpy = jest.spyOn(FileSystem, 'deleteFile'); + LockFile.tryAcquire(testFolder, resourceName); + + expect(deleteFileSpy).toHaveBeenCalledTimes(1); + expect(deleteFileSpy).toHaveBeenNthCalledWith(1, otherPidLockFileName); }); - }); - test('will not acquire if existing lock is there', () => { - // ensure test folder is clean - const testFolder: string = path.join(__dirname, '1'); - FileSystem.deleteFolder(testFolder); - FileSystem.ensureFolder(testFolder); + test("doesn't attempt deleting other process lockfile if it is released in the middle of acquiring process", () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '5'); + FileSystem.ensureEmptyFolder(testFolder); - // create an open lockfile - const resourceName: string = 'test'; - const lockFileName: string = LockFile.getLockFilePath(testFolder, resourceName); - const lockFileHandle: FileWriter = FileWriter.open(lockFileName, { exclusive: true }); + const resourceName: string = 'test'; - const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + const otherPid: number = 999999999; + const otherPidStartTime: string = '2012-01-02 12:53:12'; - // this lock should be undefined since there is an existing lock - expect(lock).toBeUndefined(); - lockFileHandle.close(); - }); + const otherPidLockFileName: string = LockFile.getLockFilePath(testFolder, resourceName, otherPid); + + // create an open lockfile for other process + const lockFileHandle: FileWriter = FileWriter.open(otherPidLockFileName); + lockFileHandle.write(otherPidStartTime); + lockFileHandle.close(); + FileSystem.updateTimes(otherPidLockFileName, { + accessedTime: 10000, + modifiedTime: 10000 + }); + + // return other process start time as if it was still running + setLockFileGetProcessStartTime((pid: number) => { + return pid === otherPid ? otherPidStartTime : getProcessStartTime(pid); + }); - test('can acquire and close a dirty lockfile', () => { - // ensure test folder is clean - const testFolder: string = path.join(__dirname, '1'); - FileSystem.deleteFolder(testFolder); - FileSystem.ensureFolder(testFolder); + const originalReadFile = FileSystem.readFile; + jest.spyOn(FileSystem, 'readFile').mockImplementation((filePath: string) => { + if (filePath === otherPidLockFileName) { + // simulate other process lock release right before the current process reads + // other process lockfile to decide on next steps for acquiring the lock + FileSystem.deleteFile(filePath); + } - // Create a lockfile that is still hanging around on disk, - const resourceName: string = 'test'; - const lockFileName: string = LockFile.getLockFilePath(testFolder, resourceName); - FileWriter.open(lockFileName, { exclusive: true }).close(); + return originalReadFile(filePath); + }); - const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + const deleteFileSpy = jest.spyOn(FileSystem, 'deleteFile'); - expect(lock).toBeDefined(); - expect(lock!.dirtyWhenAcquired).toEqual(true); - expect(lock!.isReleased).toEqual(false); - expect(FileSystem.exists(lockFileName)).toEqual(true); + LockFile.tryAcquire(testFolder, resourceName); - // Ensure that we can release the "dirty" lockfile - lock!.release(); - expect(FileSystem.exists(lockFileName)).toEqual(false); - expect(lock!.isReleased).toEqual(true); + // 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); + }); }); + } - test('can acquire and close a clean lockfile', () => { - // ensure test folder is clean - const testFolder: string = path.join(__dirname, '1'); - FileSystem.deleteFolder(testFolder); - FileSystem.ensureFolder(testFolder); + if (process.platform === 'win32') { + describe('Windows', () => { + describe(LockFile.getLockFilePath.name, () => { + test("returns a resolved path that doesn't contain", () => { + expect(path.join(process.cwd(), `test.lock`)).toEqual(LockFile.getLockFilePath('./', 'test')); + }); - const resourceName: string = 'test'; - const lockFileName: string = LockFile.getLockFilePath(testFolder, resourceName); - const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + test('ignores pid that is passed in', () => { + expect(path.join(process.cwd(), `test.lock`)).toEqual(LockFile.getLockFilePath('./', 'test', 99)); + }); + }); - // The lockfile should exist and be in a clean state - expect(lock).toBeDefined(); - expect(lock!.dirtyWhenAcquired).toEqual(false); - expect(lock!.isReleased).toEqual(false); - expect(FileSystem.exists(lockFileName)).toEqual(true); + test('will not acquire if existing lock is there', () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '1'); + FileSystem.deleteFolder(testFolder); + FileSystem.ensureFolder(testFolder); - // Ensure that we can release the "clean" lockfile - lock!.release(); - expect(FileSystem.exists(lockFileName)).toEqual(false); - expect(lock!.isReleased).toEqual(true); + // create an open lockfile + const resourceName: string = 'test'; + const lockFileHandle: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + expect(lockFileHandle).toBeDefined(); - // Ensure we cannot release the lockfile twice - expect(() => { + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + // this lock should be undefined since there is an existing lock + expect(lock).toBeUndefined(); + lockFileHandle!.release(); + }); + + test('can acquire and close a dirty lockfile', () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '1'); + FileSystem.ensureEmptyFolder(testFolder); + + // Create a lockfile that is still hanging around on disk, + const resourceName: string = 'test'; + const lockFileName: string = LockFile.getLockFilePath(testFolder, resourceName); + FileWriter.open(lockFileName, { exclusive: true }).close(); + + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + + expect(lock).toBeDefined(); + expect(lock!.dirtyWhenAcquired).toEqual(true); + expect(lock!.isReleased).toEqual(false); + expect(FileSystem.exists(lockFileName)).toEqual(true); + + // Ensure that we can release the "dirty" lockfile lock!.release(); - }).toThrow(); + expect(FileSystem.exists(lockFileName)).toEqual(false); + expect(lock!.isReleased).toEqual(true); + }); + + test('can acquire and close a clean lockfile', () => { + // ensure test folder is clean + const testFolder: string = path.join(libTestFolder, '1'); + FileSystem.ensureEmptyFolder(testFolder); + + const resourceName: string = 'test'; + const lockFileName: string = LockFile.getLockFilePath(testFolder, resourceName); + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + + // The lockfile should exist and be in a clean state + expect(lock).toBeDefined(); + expect(lock!.dirtyWhenAcquired).toEqual(false); + expect(lock!.isReleased).toEqual(false); + expect(FileSystem.exists(lockFileName)).toEqual(true); + + // Ensure that we can release the "clean" lockfile + lock!.release(); + expect(FileSystem.exists(lockFileName)).toEqual(false); + expect(lock!.isReleased).toEqual(true); + + // Ensure we cannot release the lockfile twice + expect(() => { + lock!.release(); + }).toThrow(); + }); }); } -}); \ No newline at end of file +}); diff --git a/libraries/node-core-library/src/test/MinimumHeap.test.ts b/libraries/node-core-library/src/test/MinimumHeap.test.ts new file mode 100644 index 00000000000..367e5af1bf3 --- /dev/null +++ b/libraries/node-core-library/src/test/MinimumHeap.test.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 { MinimumHeap } from '../MinimumHeap'; + +describe(MinimumHeap.name, () => { + it('iterates in sorted order', () => { + const comparator: (a: number, b: number) => number = (a: number, b: number) => a - b; + + const inputs: number[] = []; + for (let heapSize: number = 1; heapSize < 100; heapSize++) { + const heap: MinimumHeap = new MinimumHeap(comparator); + inputs.length = 0; + for (let i = 0; i < heapSize; i++) { + const x: number = Math.random(); + inputs.push(x); + heap.push(x); + } + + const iterationResults: number[] = []; + while (heap.size > 0) { + iterationResults.push(heap.poll()!); + } + + expect(iterationResults).toEqual(inputs.sort(comparator)); + } + }); + + it('returns all input objects', () => { + const comparator: (a: {}, b: {}) => number = (a: {}, b: {}) => 0; + + const heap: MinimumHeap<{}> = new MinimumHeap<{}>(comparator); + const inputs: Set<{}> = new Set([{}, {}, {}, {}, {}, {}]); + for (const x of inputs) { + heap.push(x); + } + + const iterationResults: Set<{}> = new Set(); + while (heap.size > 0) { + iterationResults.add(heap.poll()!); + } + + expect(iterationResults.size).toEqual(inputs.size); + }); + + it('handles interleaved push and poll', () => { + const comparator: (a: {}, b: {}) => number = (a: {}, b: {}) => 0; + + const heap: MinimumHeap<{}> = new MinimumHeap<{}>(comparator); + const input1: Set<{}> = new Set(); + const input2: Set<{}> = new Set(); + for (let heapSize: number = 1; heapSize < 100; heapSize++) { + input1.add({}); + input2.add({}); + + const iterationResults: Set<{}> = new Set(); + + for (const x of input1) { + heap.push(x); + } + + for (const x of input2) { + iterationResults.add(heap.poll()!); + heap.push(x); + } + + while (heap.size > 0) { + iterationResults.add(heap.poll()!); + } + + expect(iterationResults.size).toEqual(input1.size + input2.size); + } + }); +}); diff --git a/libraries/node-core-library/src/test/PackageJsonLookup.test.ts b/libraries/node-core-library/src/test/PackageJsonLookup.test.ts index 92861e8f2ed..81ffc038dcd 100644 --- a/libraries/node-core-library/src/test/PackageJsonLookup.test.ts +++ b/libraries/node-core-library/src/test/PackageJsonLookup.test.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 * as path from 'path'; +import * as path from 'node:path'; import { PackageJsonLookup } from '../PackageJsonLookup'; -import { IPackageJson, INodePackageJson } from '../IPackageJson'; +import type { IPackageJson, INodePackageJson } from '../IPackageJson'; import { FileConstants } from '../Constants'; -describe('PackageJsonLookup', () => { - +describe(PackageJsonLookup.name, () => { describe('basic tests', () => { - - test('', () => { + test(PackageJsonLookup.loadOwnPackageJson.name, () => { expect(PackageJsonLookup.loadOwnPackageJson(__dirname).name).toEqual('@rushstack/node-core-library'); }); - test('tryLoadPackageJsonFor() test', () => { + test(PackageJsonLookup.prototype.tryLoadPackageJsonFor.name, () => { const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); const sourceFilePath: string = path.join(__dirname, './test-data/example-package'); const packageJson: IPackageJson | undefined = packageJsonLookup.tryLoadPackageJsonFor(sourceFilePath); @@ -28,10 +26,11 @@ describe('PackageJsonLookup', () => { } }); - test('tryLoadNodePackageJsonFor() test package with no version', () => { + test(`${PackageJsonLookup.prototype.tryLoadNodePackageJsonFor.name} test package with no version`, () => { const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); const sourceFilePath: string = path.join(__dirname, './test-data/example-package-no-version'); - const packageJson: INodePackageJson | undefined = packageJsonLookup.tryLoadNodePackageJsonFor(sourceFilePath); + const packageJson: INodePackageJson | undefined = + packageJsonLookup.tryLoadNodePackageJsonFor(sourceFilePath); expect(packageJson).toBeDefined(); if (packageJson) { expect(packageJson.name).toEqual('example-package'); @@ -42,7 +41,7 @@ describe('PackageJsonLookup', () => { } }); - test('tryGetPackageFolderFor() test', () => { + test(PackageJsonLookup.prototype.tryGetPackageFolderFor.name, () => { const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); const sourceFilePath: string = path.join(__dirname, './test-data/example-package/src/ExampleFile.txt'); @@ -55,5 +54,22 @@ describe('PackageJsonLookup', () => { expect(foundFile).toEqual(path.join(foundFolder || '', FileConstants.PackageJson)); }); + + test(`${PackageJsonLookup.prototype.tryGetPackageFolderFor.name} test package with inner package.json with no name`, () => { + const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + const sourceFilePath: string = path.join( + __dirname, + './test-data/example-subdir-package-no-name/src/ExampleFile.txt' + ); + + // Example: C:\rushstack\libraries\node-core-library\src\test\example-subdir-package-no-name + const foundFolder: string | undefined = packageJsonLookup.tryGetPackageFolderFor(sourceFilePath); + expect(foundFolder).toBeDefined(); + expect(foundFolder!.search(/[\\/]example-subdir-package-no-name$/i)).toBeGreaterThan(0); + + const foundFile: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor(sourceFilePath); + + expect(foundFile).toEqual(path.join(foundFolder || '', FileConstants.PackageJson)); + }); }); }); diff --git a/libraries/node-core-library/src/test/PackageName.test.ts b/libraries/node-core-library/src/test/PackageName.test.ts index 311c11ef64f..3fee972193b 100644 --- a/libraries/node-core-library/src/test/PackageName.test.ts +++ b/libraries/node-core-library/src/test/PackageName.test.ts @@ -3,126 +3,86 @@ import { PackageName } from '../PackageName'; -describe('PackageName', () => { - describe('Test', () => { +describe(PackageName.name, () => { + it(`${PackageName.isValidName.name} positive test`, () => { + expect(PackageName.isValidName('@microsoft/example-package')).toEqual(true); + }); + + it(`${PackageName.isValidName.name} negative test`, () => { + expect(PackageName.isValidName('@microsoft/example-package/path')).toEqual(false); + }); - test('isValidName() positive test', () => { - expect(PackageName.isValidName('@microsoft/example-package')).toEqual(true); + it(PackageName.tryParse.name, () => { + expect(PackageName.tryParse('@microsoft/example-package')).toEqual({ + scope: '@microsoft', + unscopedName: 'example-package', + error: '' }); - test('isValidName() negative test', () => { - expect(PackageName.isValidName('@microsoft/example-package/path')).toEqual(false); + expect(PackageName.tryParse('')).toEqual({ + scope: '', + unscopedName: '', + error: 'The package name must not be empty' }); - test('tryParse() tests', () => { - expect( - PackageName.tryParse('@microsoft/example-package') - ).toEqual( - { - scope: '@microsoft', - unscopedName: 'example-package', - error: '' - } - ); - - expect( - PackageName.tryParse('') - ).toEqual( - { - scope: '', - unscopedName: '', - error: 'The package name must not be empty' - } - ); - - expect( - PackageName.tryParse(undefined as any) // eslint-disable-line @typescript-eslint/no-explicit-any - ).toEqual( - { - scope: '', - unscopedName: '', - error: 'The package name must not be null or undefined' - } - ); - - expect( - PackageName.tryParse('@microsoft') - ).toEqual( - { - scope: '@microsoft', - unscopedName: '', - error: 'Error parsing "@microsoft": The scope must be followed by a slash' - } - ); - - expect( - PackageName.tryParse('@/example-package') - ).toEqual( - { - scope: '@', - unscopedName: 'example-package', - error: 'Error parsing "@/example-package": The scope name cannot be empty' - } - ); - - expect( - PackageName.tryParse('@Microsoft/example-package') - ).toEqual( - { - scope: '@Microsoft', - unscopedName: 'example-package', - error: 'The package scope "@Microsoft" must not contain upper case characters' - } - ); - - expect( - PackageName.tryParse('@micro!soft/example-package') - ).toEqual( - { - scope: '@micro!soft', - unscopedName: 'example-package', - error: 'The package name "@micro!soft/example-package" contains an invalid character: \"!\"' - } - ); - - expect( - PackageName.tryParse('@microsoft/node-co~re-library') - ).toEqual( - { - scope: '@microsoft', - unscopedName: 'node-co~re-library', - error: 'The package name "@microsoft/node-co~re-library" contains an invalid character: \"~\"' - } - ); - - expect( - PackageName.tryParse('@microsoft/example-package/path') - ).toEqual( - { - scope: '@microsoft', - unscopedName: 'example-package/path', - error: 'The package name "@microsoft/example-package/path" contains an invalid character: \"/\"' - } - ); + expect( + PackageName.tryParse(undefined as any) // eslint-disable-line @typescript-eslint/no-explicit-any + ).toEqual({ + scope: '', + unscopedName: '', + error: 'The package name must not be null or undefined' + }); + + expect(PackageName.tryParse('@microsoft')).toEqual({ + scope: '@microsoft', + unscopedName: '', + error: 'Error parsing "@microsoft": The scope must be followed by a slash' + }); + + expect(PackageName.tryParse('@/example-package')).toEqual({ + scope: '@', + unscopedName: 'example-package', + error: 'Error parsing "@/example-package": The scope name cannot be empty' + }); + expect(PackageName.tryParse('@Microsoft/example-package')).toEqual({ + scope: '@Microsoft', + unscopedName: 'example-package', + error: 'The package scope "@Microsoft" must not contain upper case characters' + }); + + expect(PackageName.tryParse('@micro!soft/example-package')).toEqual({ + scope: '@micro!soft', + unscopedName: 'example-package', + error: 'The package name "@micro!soft/example-package" contains an invalid character: "!"' + }); + + expect(PackageName.tryParse('@microsoft/node-co~re-library')).toEqual({ + scope: '@microsoft', + unscopedName: 'node-co~re-library', + error: 'The package name "@microsoft/node-co~re-library" contains an invalid character: "~"' + }); + + expect(PackageName.tryParse('@microsoft/example-package/path')).toEqual({ + scope: '@microsoft', + unscopedName: 'example-package/path', + error: 'The package name "@microsoft/example-package/path" contains an invalid character: "/"' }); }); - test('parse() test', () => { - expect( - () => { PackageName.parse('@'); } - ).toThrowError('The scope must be followed by a slash'); + it(PackageName.parse.name, () => { + expect(() => { + PackageName.parse('@'); + }).toThrowError('The scope must be followed by a slash'); }); - test('combineParts() tests', () => { - expect(PackageName.combineParts('@microsoft', 'example-package')) - .toEqual('@microsoft/example-package'); + it(PackageName.combineParts.name, () => { + expect(PackageName.combineParts('@microsoft', 'example-package')).toEqual('@microsoft/example-package'); - expect(PackageName.combineParts('', 'example-package')) - .toEqual('example-package'); + expect(PackageName.combineParts('', 'example-package')).toEqual('example-package'); }); - test('combineParts() errors', () => { + it(`${PackageName.combineParts.name} errors`, () => { expect(() => { PackageName.combineParts('', '@microsoft/example-package'); }).toThrowError('The unscopedName cannot start with an "@" character'); diff --git a/libraries/node-core-library/src/test/Path.test.ts b/libraries/node-core-library/src/test/Path.test.ts index eccc499cd36..eb79424d6de 100644 --- a/libraries/node-core-library/src/test/Path.test.ts +++ b/libraries/node-core-library/src/test/Path.test.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 * as os from 'os'; +import * as os from 'node:os'; +import * as path from 'node:path'; import { Path } from '../Path'; -describe('Path', () => { - describe('Test', () => { - +describe(Path.name, () => { + describe(Path.isUnder.name, () => { if (os.platform() === 'win32') { test('Windows paths', () => { expect(Path.isUnder('C:\\a\\b.txt', 'C:\\a')).toEqual(true); @@ -45,4 +45,111 @@ describe('Path', () => { expect(Path.isUnder('../a/b', '../a/b/c')).toEqual(false); }); }); + + describe(Path.isDownwardRelative.name, () => { + test('Positive cases', () => { + expect(Path.isDownwardRelative('folder')).toEqual(true); + expect(Path.isDownwardRelative('folder/')).toEqual(true); + expect(Path.isDownwardRelative('./folder')).toEqual(true); + expect(Path.isDownwardRelative('./folder/file')).toEqual(true); + expect(Path.isDownwardRelative('./folder/file')).toEqual(true); + + if (os.platform() === 'win32') { + expect(Path.isDownwardRelative('folder\\')).toEqual(true); + expect(Path.isDownwardRelative('.\\folder')).toEqual(true); + expect(Path.isDownwardRelative('.\\folder\\file')).toEqual(true); + expect(Path.isDownwardRelative('.\\folder\\file')).toEqual(true); + } + }); + test('Degenerate positive cases', () => { + expect(Path.isDownwardRelative('folder/degenerate...')).toEqual(true); + expect(Path.isDownwardRelative('folder/...degenerate')).toEqual(true); + expect(Path.isDownwardRelative('folder/...degenerate...')).toEqual(true); + expect(Path.isDownwardRelative('folder/degenerate.../file')).toEqual(true); + expect(Path.isDownwardRelative('folder/...degenerate/file')).toEqual(true); + expect(Path.isDownwardRelative('folder/...degenerate.../file')).toEqual(true); + expect(Path.isDownwardRelative('...degenerate/file')).toEqual(true); + expect(Path.isDownwardRelative('.../file')).toEqual(true); + expect(Path.isDownwardRelative('...')).toEqual(true); + }); + test('Negative cases', () => { + expect(Path.isDownwardRelative('../folder')).toEqual(false); + expect(Path.isDownwardRelative('../folder/folder')).toEqual(false); + expect(Path.isDownwardRelative('folder/../folder')).toEqual(false); + expect(Path.isDownwardRelative('/folder/file')).toEqual(false); + + if (os.platform() === 'win32') { + expect(Path.isDownwardRelative('C:/folder/file')).toEqual(false); + expect(Path.isDownwardRelative('..\\folder')).toEqual(false); + expect(Path.isDownwardRelative('..\\folder\\folder')).toEqual(false); + expect(Path.isDownwardRelative('folder\\..\\folder')).toEqual(false); + expect(Path.isDownwardRelative('\\folder\\file')).toEqual(false); + expect(Path.isDownwardRelative('C:\\folder\\file')).toEqual(false); + } + }); + }); + describe(Path.formatConcisely.name, () => { + describe('With trimLeadingDotSlash unset', () => { + it('Formats a path under a base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3', + baseFolder: '/folder1' + }); + expect(result).toMatchInlineSnapshot(`"./folder2/folder3"`); + expect(path.isAbsolute(result)).toBe(false); + }); + + it('Formats a path not under the base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3', + baseFolder: '/folder4' + }); + // We can't do a snapshot test here because the result is OS-specific + // expect(result).toMatchInlineSnapshot(); + expect(path.isAbsolute(result)).toBe(true); + }); + + it('Formats a path containing a ".." under a base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3/folder4/../file.txt', + baseFolder: '/folder1/folder2/folder3' + }); + expect(result).toMatchInlineSnapshot(`"./file.txt"`); + expect(path.isAbsolute(result)).toBe(false); + }); + }); + + describe('With trimLeadingDotSlash set to true', () => { + it('Formats a path under a base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3', + baseFolder: '/folder1', + trimLeadingDotSlash: true + }); + expect(result).toMatchInlineSnapshot(`"folder2/folder3"`); + expect(path.isAbsolute(result)).toBe(false); + }); + + it('Formats a path not under the base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3', + baseFolder: '/folder4', + trimLeadingDotSlash: true + }); + // We can't do a snapshot test here because the result is OS-specific + // expect(result).toMatchInlineSnapshot(); + expect(path.isAbsolute(result)).toBe(true); + }); + + it('Formats a path containing a ".." under a base folder', () => { + const result: string = Path.formatConcisely({ + pathToConvert: '/folder1/folder2/folder3/folder4/../file.txt', + baseFolder: '/folder1/folder2/folder3', + trimLeadingDotSlash: true + }); + expect(result).toMatchInlineSnapshot(`"file.txt"`); + expect(path.isAbsolute(result)).toBe(false); + }); + }); + }); }); diff --git a/libraries/node-core-library/src/test/ProtectableMap.test.ts b/libraries/node-core-library/src/test/ProtectableMap.test.ts index b3c7058e38a..6c7226e1c24 100644 --- a/libraries/node-core-library/src/test/ProtectableMap.test.ts +++ b/libraries/node-core-library/src/test/ProtectableMap.test.ts @@ -43,7 +43,7 @@ class ExampleApi { } } -describe('ProtectableMap', () => { +describe(ProtectableMap.name, () => { test('Protected operations', () => { const exampleApi: ExampleApi = new ExampleApi(); exampleApi.studentAgesByName.clear(); @@ -79,5 +79,4 @@ describe('ProtectableMap', () => { exampleApi.studentAgesByName.set('Jane', 23); }).toThrowError('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 new file mode 100644 index 00000000000..b7e60e77e8d --- /dev/null +++ b/libraries/node-core-library/src/test/RealNodeModulePath.test.ts @@ -0,0 +1,353 @@ +// 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 'node:fs'; +import * as path from 'node:path'; + +import { type IRealNodeModulePathResolverOptions, RealNodeModulePathResolver } from '../RealNodeModulePath'; + +const mocklstatSync: jest.Mock, Parameters> = jest.fn(); +const lstatSync: typeof fs.lstatSync = mocklstatSync as unknown as typeof fs.lstatSync; +const mockReadlinkSync: jest.Mock< + ReturnType, + Parameters +> = jest.fn(); +const readlinkSync: typeof fs.readlinkSync = mockReadlinkSync as unknown as typeof fs.readlinkSync; + +const mockFs: IRealNodeModulePathResolverOptions['fs'] = { + lstatSync, + readlinkSync +}; + +describe('realNodeModulePath', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('POSIX paths', () => { + const resolver: RealNodeModulePathResolver = new RealNodeModulePathResolver({ + fs: mockFs, + path: path.posix + }); + const { realNodeModulePath } = resolver; + + beforeEach(() => { + resolver.clearCache(); + }); + + it('should return the input path if it is absolute and does not contain node_modules', () => { + for (const input of ['/foo/bar', '/']) { + expect(realNodeModulePath(input)).toBe(input); + + expect(mocklstatSync).not.toHaveBeenCalled(); + expect(mockReadlinkSync).not.toHaveBeenCalled(); + } + }); + + it('should return the input path if it is not a symbolic link', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => false } as unknown as fs.Stats); + + expect(realNodeModulePath('/foo/node_modules/foo')).toBe('/foo/node_modules/foo'); + + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/foo'); + expect(mocklstatSync).toHaveBeenCalledTimes(1); + expect(mockReadlinkSync).toHaveBeenCalledTimes(0); + }); + + it('should trim a trailing slash from the input path if it is not a symbolic link', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => false } as unknown as fs.Stats); + + expect(realNodeModulePath('/foo/node_modules/foo/')).toBe('/foo/node_modules/foo'); + + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/foo'); + expect(mocklstatSync).toHaveBeenCalledTimes(1); + expect(mockReadlinkSync).toHaveBeenCalledTimes(0); + }); + + it('Should handle absolute link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/link/target'); + + expect(realNodeModulePath('/foo/node_modules/link')).toBe('/link/target'); + + 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('Should trim trailing slash from absolute link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/link/target/'); + + expect(realNodeModulePath('/foo/node_modules/link/bar')).toBe('/link/target/bar'); + + 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 resolved symlinks', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/link/target'); + + expect(realNodeModulePath('/foo/node_modules/link')).toBe('/link/target'); + expect(realNodeModulePath('/foo/node_modules/link/bar')).toBe('/link/target/bar'); + expect(realNodeModulePath('/foo/node_modules/link/')).toBe('/link/target'); + + 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.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); + }); + + it('Should handle relative link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('../../link/target'); + + expect(realNodeModulePath('/foo/node_modules/link')).toBe('/link/target'); + + 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('Should recursively handle relative link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('../../link'); + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/other/root/bar'); + + expect(realNodeModulePath('/foo/1/2/3/node_modules/bar/node_modules/link/4/5/6')).toBe( + '/other/root/link/4/5/6' + ); + + 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'); + expect(mockReadlinkSync).toHaveBeenCalledTimes(2); + }); + + it('Caches multi-layer resolution', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('../../link'); + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/other/root/bar'); + + expect(realNodeModulePath('/foo/1/2/3/node_modules/bar/node_modules/link/4/5/6')).toBe( + '/other/root/link/4/5/6' + ); + expect(realNodeModulePath('/foo/1/2/3/node_modules/bar/node_modules/link/a/b')).toBe( + '/other/root/link/a/b' + ); + expect(realNodeModulePath('/foo/1/2/3/node_modules/bar/a/b')).toBe('/other/root/bar/a/b'); + + 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'); + expect(mockReadlinkSync).toHaveBeenCalledTimes(2); + }); + }); + + describe('Windows paths', () => { + const resolver: RealNodeModulePathResolver = new RealNodeModulePathResolver({ + fs: mockFs, + path: path.win32 + }); + const { realNodeModulePath } = resolver; + + beforeEach(() => { + resolver.clearCache(); + }); + + it('should return the input path if it is absolute and does not contain node_modules', () => { + for (const input of ['C:\\foo\\bar', 'C:\\']) { + expect(realNodeModulePath(input)).toBe(input); + + expect(mocklstatSync).not.toHaveBeenCalled(); + expect(mockReadlinkSync).not.toHaveBeenCalled(); + } + }); + + it('should trim extra trailing separators from the root', () => { + expect(realNodeModulePath('C:////')).toBe('C:\\'); + + expect(mocklstatSync).not.toHaveBeenCalled(); + expect(mockReadlinkSync).not.toHaveBeenCalled(); + }); + + it('should return the resolved input path if it is absolute and does not contain node_modules', () => { + for (const input of ['C:/foo/bar', 'C:/', 'ab', '../b/c/d']) { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + + expect(realNodeModulePath(input)).toBe(path.win32.resolve(input)); + + expect(mocklstatSync).not.toHaveBeenCalled(); + expect(mockReadlinkSync).not.toHaveBeenCalled(); + } + }); + + it('Should return the input path if the target is not a symbolic link', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => false } as unknown as fs.Stats); + + expect(realNodeModulePath('C:\\foo\\node_modules\\foo')).toBe('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); + }); + + it('Should trim a trailing path separator if the target is not a symbolic link', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => false } as unknown as fs.Stats); + + expect(realNodeModulePath('C:\\foo\\node_modules\\foo\\')).toBe('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); + }); + + it('Should handle absolute link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('C:\\link\\target'); + + expect(realNodeModulePath('C:\\foo\\node_modules\\link\\relative')).toBe('C:\\link\\target\\relative'); + + 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); + }); + + it('Should trim a trailing path separator from an absolute link target', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('C:\\link\\target\\'); + + expect(realNodeModulePath('C:\\foo\\node_modules\\link\\relative')).toBe('C:\\link\\target\\relative'); + + 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); + }); + + it('Should normalize input', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('C:\\link\\target'); + + expect(realNodeModulePath('C:\\foo\\node_modules\\link')).toBe('C:\\link\\target'); + + 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); + }); + + it('Should stop after a single absolute link target', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('D:\\link\\target'); + + expect(realNodeModulePath('C:\\node_modules\\foo\\node_modules\\link')).toBe('D:\\link\\target'); + + 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); + }); + + it('Should handle relative link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('..\\..\\link\\target'); + + expect(realNodeModulePath('C:\\foo\\node_modules\\link')).toBe('C:\\link\\target'); + + 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); + }); + + it('Should recursively handle relative link targets', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('..\\..\\link'); + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('D:\\other\\root\\bar'); + + expect(realNodeModulePath('C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link\\4\\5\\6')).toBe( + 'D:\\other\\root\\link\\4\\5\\6' + ); + + 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', + 'utf8' + ); + expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar', 'utf8'); + expect(mockReadlinkSync).toHaveBeenCalledTimes(2); + }); + + it('Caches multi-layer resolution', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('..\\..\\link'); + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('D:\\other\\root\\bar'); + + expect(realNodeModulePath('C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link\\4\\5\\6')).toBe( + 'D:\\other\\root\\link\\4\\5\\6' + ); + expect(realNodeModulePath('C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link\\a\\b')).toBe( + 'D:\\other\\root\\link\\a\\b' + ); + expect(realNodeModulePath('C:\\foo\\1\\2\\3\\node_modules\\bar\\a\\b')).toBe( + 'D:\\other\\root\\bar\\a\\b' + ); + + 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', + 'utf8' + ); + expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar', 'utf8'); + expect(mockReadlinkSync).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/libraries/node-core-library/src/test/Sort.test.ts b/libraries/node-core-library/src/test/Sort.test.ts index 0aaf22a7449..b87eef16a37 100644 --- a/libraries/node-core-library/src/test/Sort.test.ts +++ b/libraries/node-core-library/src/test/Sort.test.ts @@ -5,11 +5,11 @@ import { Sort } from '../Sort'; test('Sort.compareByValue', () => { const array: number[] = [3, 6, 2]; - array.sort(Sort.compareByValue); // [2, 3, 6] + array.sort(Sort.compareByValue); // [2, 3, 6] }); test('Sort.compareByValue cases', () => { - const values: unknown[] = [undefined, null, -1, 1]; // eslint-disable-line @rushstack/no-null + const values: unknown[] = [undefined, null, -1, 1]; const results: string[] = []; for (let i: number = 0; i < values.length; ++i) { for (let j: number = 0; j < values.length; ++j) { @@ -17,9 +17,15 @@ test('Sort.compareByValue cases', () => { const y: unknown = values[j]; let relation: string = '?'; switch (Sort.compareByValue(x, y)) { - case -1: relation = '<'; break; - case 0: relation = '='; break; - case 1: relation = '>'; break; + case -1: + relation = '<'; + break; + case 0: + relation = '='; + break; + case 1: + relation = '>'; + break; } results.push(`${x} ${relation} ${y}`); } @@ -28,13 +34,13 @@ test('Sort.compareByValue cases', () => { }); test('Sort.sortBy', () => { - const array: string[] = [ 'aaa', 'bb', 'c' ]; - Sort.sortBy(array, x => x.length); // [ 'c', 'bb', 'aaa' ] + const array: string[] = ['aaa', 'bb', 'c']; + Sort.sortBy(array, (x) => x.length); // [ 'c', 'bb', 'aaa' ] }); test('Sort.isSortedBy', () => { - const array: string[] = [ 'a', 'bb', 'ccc' ]; - Sort.isSortedBy(array, x => x.length); // true + const array: string[] = ['a', 'bb', 'ccc']; + Sort.isSortedBy(array, (x) => x.length); // true }); test('Sort.sortMapKeys', () => { @@ -51,7 +57,7 @@ test('Sort.sortSetBy', () => { set.add('aaa'); set.add('bb'); set.add('c'); - Sort.sortSetBy(set, x => x.length); + Sort.sortSetBy(set, (x) => x.length); expect(Array.from(set)).toEqual(['c', 'bb', 'aaa']); }); @@ -63,3 +69,50 @@ test('Sort.sortSet', () => { Sort.sortSet(set); expect(Array.from(set)).toEqual(['aardvark', 'goose', 'zebra']); }); + +describe('Sort.sortKeys', () => { + test('Simple object', () => { + const unsortedObj = { q: 0, p: 0, r: 0 }; + const sortedObj = Sort.sortKeys(unsortedObj); + + // Assert that it's not sorted in-place + expect(sortedObj).not.toBe(unsortedObj); + + expect(Object.keys(unsortedObj)).toEqual(['q', 'p', 'r']); + expect(Object.keys(sortedObj)).toEqual(['p', 'q', 'r']); + }); + test('Simple array with objects', () => { + const unsortedArr = [ + { b: 1, a: 0 }, + { y: 0, z: 1, x: 2 } + ]; + const sortedArr = Sort.sortKeys(unsortedArr); + + // Assert that it's not sorted in-place + expect(sortedArr).not.toBe(unsortedArr); + + expect(Object.keys(unsortedArr[0])).toEqual(['b', 'a']); + expect(Object.keys(sortedArr[0])).toEqual(['a', 'b']); + + expect(Object.keys(unsortedArr[1])).toEqual(['y', 'z', 'x']); + expect(Object.keys(sortedArr[1])).toEqual(['x', 'y', 'z']); + }); + test('Nested objects', () => { + const unsortedDeepObj = { c: { q: 0, r: { a: 42 }, p: 2 }, b: { y: 0, z: 1, x: 2 }, a: 2 }; + const sortedDeepObj = Sort.sortKeys(unsortedDeepObj); + + expect(sortedDeepObj).not.toBe(unsortedDeepObj); + + expect(Object.keys(unsortedDeepObj)).toEqual(['c', 'b', 'a']); + expect(Object.keys(sortedDeepObj)).toEqual(['a', 'b', 'c']); + + expect(Object.keys(unsortedDeepObj.b)).toEqual(['y', 'z', 'x']); + expect(Object.keys(sortedDeepObj.b)).toEqual(['x', 'y', 'z']); + + expect(Object.keys(unsortedDeepObj.c)).toEqual(['q', 'r', 'p']); + expect(Object.keys(sortedDeepObj.c)).toEqual(['p', 'q', 'r']); + + expect(Object.keys(unsortedDeepObj.c.r)).toEqual(['a']); + expect(Object.keys(sortedDeepObj.c.r)).toEqual(['a']); + }); +}); diff --git a/libraries/node-core-library/src/test/Text.test.ts b/libraries/node-core-library/src/test/Text.test.ts index e6e16b6c569..a4567b25f98 100644 --- a/libraries/node-core-library/src/test/Text.test.ts +++ b/libraries/node-core-library/src/test/Text.test.ts @@ -3,74 +3,133 @@ import { Text } from '../Text'; -describe('Text', () => { - describe('padEnd', () => { - test('Throws an exception if the padding character isn\'t a single character', () => { +describe(Text.name, () => { + describe(Text.padEnd.name, () => { + it("Throws an exception if the padding character isn't a single character", () => { expect(() => Text.padEnd('123', 1, '')).toThrow(); expect(() => Text.padEnd('123', 1, ' ')).toThrow(); }); - test('Doesn\'t change the string if it\'s already at or greater than the minimum length', () => { - expect(Text.padEnd('12345', 5)).toEqual( '12345'); + it("Doesn't change the string if it's already at or greater than the minimum length", () => { + expect(Text.padEnd('12345', 5)).toEqual('12345'); expect(Text.padEnd('123456', 5)).toEqual('123456'); - expect(Text.padEnd('12345', 5, '0')).toEqual( '12345'); + expect(Text.padEnd('12345', 5, '0')).toEqual('12345'); expect(Text.padEnd('123456', 5, '0')).toEqual('123456'); }); - test('Appends the default character (spaces) to the end of a string', () => { - expect(Text.padEnd('', 5)).toEqual( ' '); + it('Appends the default character (spaces) to the end of a string', () => { + expect(Text.padEnd('', 5)).toEqual(' '); expect(Text.padEnd('123', 5)).toEqual('123 '); }); - test('Appends the characters to the end of a string', () => { - expect(Text.padEnd('', 5, '0')).toEqual( '00000'); + it('Appends the characters to the end of a string', () => { + expect(Text.padEnd('', 5, '0')).toEqual('00000'); expect(Text.padEnd('123', 5, '0')).toEqual('12300'); }); }); - describe('padStart', () => { - test('Throws an exception if the padding character isn\'t a single character', () => { + describe(Text.padStart.name, () => { + it("Throws an exception if the padding character isn't a single character", () => { expect(() => Text.padStart('123', 1, '')).toThrow(); expect(() => Text.padStart('123', 1, ' ')).toThrow(); }); - test('Doesn\'t change the string if it\'s already at or greater than the minimum length', () => { - expect(Text.padStart('12345', 5)).toEqual( '12345'); + it("Doesn't change the string if it's already at or greater than the minimum length", () => { + expect(Text.padStart('12345', 5)).toEqual('12345'); expect(Text.padStart('123456', 5)).toEqual('123456'); - expect(Text.padStart('12345', 5, '0')).toEqual( '12345'); + expect(Text.padStart('12345', 5, '0')).toEqual('12345'); expect(Text.padStart('123456', 5, '0')).toEqual('123456'); }); - test('Appends the default character (spaces) to the end of a string', () => { - expect(Text.padStart('', 5)).toEqual( ' '); + it('Appends the default character (spaces) to the end of a string', () => { + expect(Text.padStart('', 5)).toEqual(' '); expect(Text.padStart('123', 5)).toEqual(' 123'); }); - test('Appends the characters to the end of a string', () => { - expect(Text.padStart('', 5, '0')).toEqual( '00000'); + it('Appends the characters to the end of a string', () => { + expect(Text.padStart('', 5, '0')).toEqual('00000'); expect(Text.padStart('123', 5, '0')).toEqual('00123'); }); }); - describe('truncateWithEllipsis', () => { - test('Throws an exception if the maximum length is less than zero', () => { + describe(Text.truncateWithEllipsis.name, () => { + it('Throws an exception if the maximum length is less than zero', () => { expect(() => Text.truncateWithEllipsis('123', -1)).toThrow(); }); - test('Doesn\'t change the string if it\'s already shorter than the maximum length', () => { - expect(Text.truncateWithEllipsis('', 2)).toEqual( ''); - expect(Text.truncateWithEllipsis('1', 2)).toEqual( '1'); - expect(Text.truncateWithEllipsis('12', 2)).toEqual( '12'); + it("Doesn't change the string if it's already shorter than the maximum length", () => { + expect(Text.truncateWithEllipsis('', 2)).toEqual(''); + expect(Text.truncateWithEllipsis('1', 2)).toEqual('1'); + expect(Text.truncateWithEllipsis('12', 2)).toEqual('12'); - expect(Text.truncateWithEllipsis('123', 5)).toEqual( '123'); - expect(Text.truncateWithEllipsis('1234', 5)).toEqual( '1234'); + expect(Text.truncateWithEllipsis('123', 5)).toEqual('123'); + expect(Text.truncateWithEllipsis('1234', 5)).toEqual('1234'); }); - test('Truncates strings', () => { - expect(Text.truncateWithEllipsis('123', 0)).toEqual( ''); - expect(Text.truncateWithEllipsis('123', 2)).toEqual( '12'); - expect(Text.truncateWithEllipsis('12345', 5)).toEqual( '12345'); + it('Truncates strings', () => { + expect(Text.truncateWithEllipsis('123', 0)).toEqual(''); + expect(Text.truncateWithEllipsis('123', 2)).toEqual('12'); + expect(Text.truncateWithEllipsis('12345', 5)).toEqual('12345'); expect(Text.truncateWithEllipsis('123456', 5)).toEqual('12...'); }); }); + + describe(Text.convertToLf.name, () => { + it('degenerate adjacent newlines', () => { + expect(Text.convertToLf('')).toEqual(''); + expect(Text.convertToLf('\n')).toEqual('\n'); + expect(Text.convertToLf('\r')).toEqual('\n'); + expect(Text.convertToLf('\n\n')).toEqual('\n\n'); + expect(Text.convertToLf('\r\n')).toEqual('\n'); + expect(Text.convertToLf('\n\r')).toEqual('\n'); + expect(Text.convertToLf('\r\r')).toEqual('\n\n'); + expect(Text.convertToLf('\n\n\n')).toEqual('\n\n\n'); + expect(Text.convertToLf('\r\n\n')).toEqual('\n\n'); + expect(Text.convertToLf('\n\r\n')).toEqual('\n\n'); + expect(Text.convertToLf('\r\r\n')).toEqual('\n\n'); + expect(Text.convertToLf('\n\n\r')).toEqual('\n\n'); + expect(Text.convertToLf('\r\n\r')).toEqual('\n\n'); + expect(Text.convertToLf('\n\r\r')).toEqual('\n\n'); + expect(Text.convertToLf('\r\r\r')).toEqual('\n\n\n'); + }); + it('degenerate mixed newlines', () => { + expect(Text.convertToLf('\nX\n\r')).toEqual('\nX\n'); + expect(Text.convertToLf('\rX\r')).toEqual('\nX\n'); + expect(Text.convertToLf('\r \n')).toEqual('\n \n'); + }); + }); + + describe(Text.escapeRegExp.name, () => { + it('escapes special characters', () => { + expect(Text.escapeRegExp('')).toEqual(''); + expect(Text.escapeRegExp('abc')).toEqual('abc'); + expect(Text.escapeRegExp('a.c')).toEqual('a\\.c'); + expect(Text.escapeRegExp('a*c')).toEqual('a\\*c'); + expect(Text.escapeRegExp('a?c')).toEqual('a\\?c'); + expect(Text.escapeRegExp('a+c')).toEqual('a\\+c'); + expect(Text.escapeRegExp('a{c')).toEqual('a\\{c'); + expect(Text.escapeRegExp('a}c')).toEqual('a\\}c'); + expect(Text.escapeRegExp('a(c')).toEqual('a\\(c'); + expect(Text.escapeRegExp('a)c')).toEqual('a\\)c'); + expect(Text.escapeRegExp('a[c')).toEqual('a\\[c'); + expect(Text.escapeRegExp('a]c')).toEqual('a\\]c'); + expect(Text.escapeRegExp('a|c')).toEqual('a\\|c'); + expect(Text.escapeRegExp('a^c')).toEqual('a\\^c'); + expect(Text.escapeRegExp('a$c')).toEqual('a\\$c'); + expect(Text.escapeRegExp('a\\c')).toEqual('a\\\\c'); + }); + }); + + describe(Text.splitByNewLines.name, () => { + it('splits a string by newlines', () => { + expect(Text.splitByNewLines(undefined)).toEqual(undefined); + expect(Text.splitByNewLines('')).toEqual(['']); + expect(Text.splitByNewLines('abc')).toEqual(['abc']); + expect(Text.splitByNewLines('a\nb\nc')).toEqual(['a', 'b', 'c']); + expect(Text.splitByNewLines('a\nb\nc\n')).toEqual(['a', 'b', 'c', '']); + expect(Text.splitByNewLines('a\nb\nc\n\n')).toEqual(['a', 'b', 'c', '', '']); + expect(Text.splitByNewLines('\n\na\nb\nc\n\n')).toEqual(['', '', 'a', 'b', 'c', '', '']); + expect(Text.splitByNewLines('a\r\nb\nc')).toEqual(['a', 'b', 'c']); + }); + }); }); diff --git a/libraries/node-core-library/src/test/TypeUuid.test.ts b/libraries/node-core-library/src/test/TypeUuid.test.ts new file mode 100644 index 00000000000..f64d3bd531b --- /dev/null +++ b/libraries/node-core-library/src/test/TypeUuid.test.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. + +import { TypeUuid } from '../TypeUuid'; + +const UuidA: string = '122f9816-15c2-480f-8c12-ed94d586b653'; +const UuidC: string = 'db7dae9b-38d2-4a0a-a62f-ac6b71c2c575'; + +describe(TypeUuid.name, () => { + it('correctly identifies types with inheritance', () => { + class A {} + class B extends A {} + + class C extends B { + public constructor(x: number) { + super(); + } + } + + TypeUuid.registerClass(A, UuidA); + TypeUuid.registerClass(C, UuidC); + + const a: A = new A(); + const b: B = new B(); + const c: C = new C(123); + + expect(TypeUuid.isInstanceOf(a, UuidA)).toEqual(true); + expect(TypeUuid.isInstanceOf(b, 'b205484a-fe48-4f40-bbd4-d7d46525637f')).toEqual(false); + expect(TypeUuid.isInstanceOf(c, UuidC)).toEqual(true); + }); + + it('forbids multiple type assignments', () => { + class A {} + TypeUuid.registerClass(A, UuidA); + expect(() => TypeUuid.registerClass(A, UuidC)).toThrow(/already registered/); + }); + + it('handles undefined and null', () => { + expect(TypeUuid.isInstanceOf(undefined, UuidA)).toEqual(false); + expect(TypeUuid.isInstanceOf(null, UuidA)).toEqual(false); + }); + + it('works with Symbol.hasInstance', () => { + const uuidQ: string = 'c9d85505-40de-4553-8da2-6604dccdc65f'; + + class Q { + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidQ); + } + } + class Q2 { + public static [Symbol.hasInstance](instance: object): boolean { + return TypeUuid.isInstanceOf(instance, uuidQ); + } + } + + TypeUuid.registerClass(Q, uuidQ); + TypeUuid.registerClass(Q2, uuidQ); + + const q: Q2 = new Q2(); + expect(q instanceof Q).toEqual(true); + }); +}); 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 new file mode 100644 index 00000000000..0cd07a6a9b4 --- /dev/null +++ b/libraries/node-core-library/src/test/__snapshots__/Async.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Async runWithRetriesAsync Correctly handles a sync function that always throws and allows several retries 1`] = `"error"`; + +exports[`Async runWithRetriesAsync Correctly handles a sync function that throws and does not allow retries 1`] = `"error"`; + +exports[`Async runWithRetriesAsync Correctly handles an async function that always throws and allows several retries 1`] = `"error"`; + +exports[`Async runWithRetriesAsync Correctly handles an async function that throws and does not allow 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 new file mode 100644 index 00000000000..ed188d4c581 --- /dev/null +++ b/libraries/node-core-library/src/test/__snapshots__/Executable.test.ts.snap @@ -0,0 +1,785 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Executable process list parses unix output 1`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": [Circular], + "processId": 1, + "processName": "init", + }, + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", +} +`; + +exports[`Executable process list parses unix output 2`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", +} +`; + +exports[`Executable process list parses unix output 3`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 2, + "processName": "process0", +} +`; + +exports[`Executable process list parses unix output 4`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 2, + "processName": "process0", + }, + "processId": 4, + "processName": "process2", +} +`; + +exports[`Executable process list parses unix output 5`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 3, + "processName": "process1", +} +`; + +exports[`Executable process list parses unix stream output 1`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": [Circular], + "processId": 1, + "processName": "init", + }, + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", +} +`; + +exports[`Executable process list parses unix stream output 2`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", +} +`; + +exports[`Executable process list parses unix stream output 3`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 2, + "processName": "process0", +} +`; + +exports[`Executable process list parses unix stream output 4`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "process1", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 2, + "processName": "process0", + }, + "processId": 4, + "processName": "process2", +} +`; + +exports[`Executable process list parses unix stream output 5`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "process2", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "process0", + }, + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "", + }, + "processId": 1, + "processName": "init", + }, + "processId": 3, + "processName": "process1", +} +`; + +exports[`Executable process list parses win32 output 1`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 1, + "processName": "System", + }, + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", +} +`; + +exports[`Executable process list parses win32 output 2`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", +} +`; + +exports[`Executable process list parses win32 output 3`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 2, + "processName": "executable0.exe", +} +`; + +exports[`Executable process list parses win32 output 4`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 2, + "processName": "executable0.exe", + }, + "processId": 4, + "processName": "executable2.exe", +} +`; + +exports[`Executable process list parses win32 output 5`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 3, + "processName": "executable1.exe", +} +`; + +exports[`Executable process list parses win32 output 6`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 5, + "processName": "executable3.exe", + }, + ], + "parentProcessInfo": undefined, + "processId": 6, + "processName": "", +} +`; + +exports[`Executable process list parses win32 output 7`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 6, + "processName": "", + }, + "processId": 5, + "processName": "executable3.exe", +} +`; + +exports[`Executable process list parses win32 stream output 1`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 1, + "processName": "System", + }, + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", +} +`; + +exports[`Executable process list parses win32 stream output 2`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", +} +`; + +exports[`Executable process list parses win32 stream output 3`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 2, + "processName": "executable0.exe", +} +`; + +exports[`Executable process list parses win32 stream output 4`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 3, + "processName": "executable1.exe", + }, + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 2, + "processName": "executable0.exe", + }, + "processId": 4, + "processName": "executable2.exe", +} +`; + +exports[`Executable process list parses win32 stream output 5`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 4, + "processName": "executable2.exe", + }, + ], + "parentProcessInfo": [Circular], + "processId": 2, + "processName": "executable0.exe", + }, + [Circular], + ], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 0, + "processName": "System Idle Process", + }, + "processId": 1, + "processName": "System", + }, + "processId": 3, + "processName": "executable1.exe", +} +`; + +exports[`Executable process list parses win32 stream output 6`] = ` +Object { + "childProcessInfos": Array [ + Object { + "childProcessInfos": Array [], + "parentProcessInfo": [Circular], + "processId": 5, + "processName": "executable3.exe", + }, + ], + "parentProcessInfo": undefined, + "processId": 6, + "processName": "", +} +`; + +exports[`Executable process list parses win32 stream output 7`] = ` +Object { + "childProcessInfos": Array [], + "parentProcessInfo": Object { + "childProcessInfos": Array [ + [Circular], + ], + "parentProcessInfo": undefined, + "processId": 6, + "processName": "", + }, + "processId": 5, + "processName": "executable3.exe", +} +`; 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 new file mode 100644 index 00000000000..1928c092d24 --- /dev/null +++ b/libraries/node-core-library/src/test/__snapshots__/Import.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 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 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 system module without includeSystemModules turned on 1`] = `"Cannot find module \\"fs\\" from \\"/lib/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 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/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 of a dependency 1`] = `"The package name \\"@rushstack/ts-command-line/lib/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/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 new file mode 100644 index 00000000000..d7ecdc614fd --- /dev/null +++ b/libraries/node-core-library/src/test/__snapshots__/JsonFile.test.ts.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JsonFile adds a header comment 1`] = ` +"// header +// comment +{ + \\"abc\\": 123 +} +" +`; + +exports[`JsonFile adds an empty header comment 1`] = ` +"{ + \\"abc\\": 123 +} +" +`; + +exports[`JsonFile allows undefined values when asked 1`] = ` +"{} +" +`; + +exports[`JsonFile allows undefined values when asked 2`] = ` +"{} +" +`; + +exports[`JsonFile supports parsing keys that map to \`Object\` properties: JSON String 1`] = ` +"{ + \\"__defineGetter__\\": 1, + \\"__defineSetter__\\": 1, + \\"__lookupGetter__\\": 1, + \\"__lookupSetter__\\": 1, + \\"__proto__\\": 1, + \\"constructor\\": 1, + \\"hasOwnProperty\\": 1, + \\"isPrototypeOf\\": 1, + \\"propertyIsEnumerable\\": 1, + \\"toLocaleString\\": 1, + \\"toString\\": 1, + \\"valueOf\\": 1 +}" +`; + +exports[`JsonFile supports parsing keys that map to \`Object\` properties: Parsed JSON Object 1`] = ` +Object { + "__defineGetter__": 1, + "__defineSetter__": 1, + "__lookupGetter__": 1, + "__lookupSetter__": 1, + "__proto__": 1, + "constructor": 1, + "hasOwnProperty": 1, + "isPrototypeOf": 1, + "propertyIsEnumerable": 1, + "toLocaleString": 1, + "toString": 1, + "valueOf": 1, +} +`; + +exports[`JsonFile supports updating a simple file 1`] = ` +"{\\"a\\": 1,\\"b\\": 2} +" +`; + +exports[`JsonFile supports updating a simple file with a comment 1`] = ` +"{ + // comment + \\"a\\": 1, + \\"b\\": 2 +} +" +`; + +exports[`JsonFile supports updating a simple file with a comment and a trailing comma 1`] = ` +"{ + // comment + \\"a\\": 1, + \\"b\\": 2, +} +" +`; + +exports[`JsonFile supports updating a simple file with an unquoted property 1`] = ` +"{ + // comment + a: 1, + b: 2, + \\"c-123\\": 3, +} +" +`; 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 new file mode 100644 index 00000000000..005df0f3e40 --- /dev/null +++ b/libraries/node-core-library/src/test/__snapshots__/JsonSchema.test.ts.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JsonSchema loadAndValidate throws an error for an invalid nested schema 1`] = ` +"Failed to validate schema \\"test-schema-invalid.schema.json\\": + +Error: #/type + must be equal to one of the allowed values +Error: #/type + must be array +Error: #/type + must match a schema in anyOf" +`; + +exports[`JsonSchema loadAndValidate throws an error if the wrong schema version is explicitly specified for an incompatible schema object 1`] = `"no schema with key or ref \\"http://json-schema.org/draft-04/schema#\\""`; + +exports[`JsonSchema validateObjectWithCallback successfully reports a compound validation error for format errors 1`] = ` +Array [ + " +Error: #/exampleLink + must match format \\"uri\\"", +] +`; + +exports[`JsonSchema validateObjectWithCallback successfully reports a compound validation error schema errors 1`] = ` +Array [ + " +Error: #/exampleOneOf + must have required property 'field1' +Error: #/exampleOneOf + must have required property 'field3' +Error: #/exampleOneOf + must match exactly one schema in oneOf", +] +`; diff --git a/libraries/node-core-library/src/test/test-data/example-package-no-version/package.json b/libraries/node-core-library/src/test/test-data/example-package-no-version/package.json index ef5a1f3ad2e..5bd28c0d0b8 100644 --- a/libraries/node-core-library/src/test/test-data/example-package-no-version/package.json +++ b/libraries/node-core-library/src/test/test-data/example-package-no-version/package.json @@ -1,4 +1,4 @@ { "name": "example-package", "nonstandardField": 123 -} \ No newline at end of file +} diff --git a/libraries/node-core-library/src/test/test-data/example-package/package.json b/libraries/node-core-library/src/test/test-data/example-package/package.json index 58fce8e1943..4c2845e9fb4 100644 --- a/libraries/node-core-library/src/test/test-data/example-package/package.json +++ b/libraries/node-core-library/src/test/test-data/example-package/package.json @@ -2,4 +2,4 @@ "name": "example-package", "version": "1.0.0", "nonstandardField": 123 -} \ No newline at end of file +} diff --git a/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/package.json b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/package.json new file mode 100644 index 00000000000..ffcae761cea --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/package.json @@ -0,0 +1,4 @@ +{ + "name": "example-package", + "nonstandardField": 456 +} diff --git a/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/ExampleFile.txt b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/ExampleFile.txt new file mode 100644 index 00000000000..62f701b9ce6 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/ExampleFile.txt @@ -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. + +/** + * AEDoc for AliasClass + * @public + */ +export class AliasClass { + private readOnlyNumber: number; + + /** + * AEDoc for aliasFunc() + * @internal + */ + public _aliasFunc(): void { + console.log('this is an internal API'); + } + + public aliasField: number; + + public get shouldBeReadOnly(): number { + return this.readOnlyNumber; + } +} + +class PrivateAliasClass { + public test(): void { + } +} diff --git a/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/package.json b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/package.json new file mode 100644 index 00000000000..fe4c1ea272a --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/example-subdir-package-no-name/src/package.json @@ -0,0 +1,3 @@ +{ + "nonstandardField": 123 +} diff --git a/libraries/node-core-library/src/test/test-data/executable/fail/javascript-file.js b/libraries/node-core-library/src/test/test-data/executable/fail/javascript-file.js new file mode 100644 index 00000000000..039b34c716a --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/executable/fail/javascript-file.js @@ -0,0 +1,2 @@ +console.error('This is a failure'); +process.exit(1); diff --git a/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper b/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper new file mode 100644 index 00000000000..70bdd7e4277 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper @@ -0,0 +1,16 @@ +#!/bin/sh +# This script follows the same pattern as an NPM binary wrapper for non-Windows + +echo "Executing npm-binary-wrapper with args:" +echo "$@" + +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; +esac + +node "$basedir/javascript-file.js" "$@" +ret=$? + +exit $ret diff --git a/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper.cmd b/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper.cmd new file mode 100644 index 00000000000..c5edb625609 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/executable/fail/npm-binary-wrapper.cmd @@ -0,0 +1,10 @@ +@ECHO OFF + +REM This script follows the same pattern as an NPM binary wrapper batch file on Windows + +echo Executing npm-binary-wrapper.cmd with args: +echo "%*" + +SETLOCAL +SET PATHEXT=%PATHEXT:;.JS;=;% +node "%~dp0\javascript-file.js" %* diff --git a/libraries/node-core-library/src/test/test-data/executable/no-terminate/javascript-file.js b/libraries/node-core-library/src/test/test-data/executable/no-terminate/javascript-file.js new file mode 100644 index 00000000000..750177a495b --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/executable/no-terminate/javascript-file.js @@ -0,0 +1,19 @@ +const [node, script, ...args] = process.argv; +console.log(`Executing no-terminate with args: ${args.join(' ')}`); + +console.error('This process never terminates'); + +const readline = require('readline'); +const readlineInterface = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false +}); + +async function runAsync() { + for await (const line of readlineInterface) { + console.log(line); + } +} + +runAsync(); diff --git a/libraries/node-core-library/src/test/test-data/executable/skipped/bash-script.sh b/libraries/node-core-library/src/test/test-data/executable/skipped/bash-script.sh deleted file mode 100644 index f04c038fae6..00000000000 --- a/libraries/node-core-library/src/test/test-data/executable/skipped/bash-script.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -echo THIS SHOULD NOT RUN diff --git a/libraries/node-core-library/src/test/test-data/executable/success/bash-script.sh b/libraries/node-core-library/src/test/test-data/executable/success/bash-script.sh deleted file mode 100644 index 52115b0404b..00000000000 --- a/libraries/node-core-library/src/test/test-data/executable/success/bash-script.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -echo "Executing bash-script.sh with args:" -echo "$@" - -# Print the command-line arguments with [] around each one -for a in $@ ; do - echo -n "[$a] " -done -echo diff --git a/libraries/node-core-library/src/test/test-data/executable/success/javascript-file.js b/libraries/node-core-library/src/test/test-data/executable/success/javascript-file.js index bea88b7cc80..eb013d61af3 100644 --- a/libraries/node-core-library/src/test/test-data/executable/success/javascript-file.js +++ b/libraries/node-core-library/src/test/test-data/executable/success/javascript-file.js @@ -2,4 +2,3 @@ console.log('Executing javascript-file.js with args:'); // Print the command line arguments: console.log(JSON.stringify(process.argv)); - diff --git a/libraries/node-core-library/src/test/test-data/test-schema.json b/libraries/node-core-library/src/test/test-data/test-schema.json deleted file mode 100644 index cbf8b76bd2d..00000000000 --- a/libraries/node-core-library/src/test/test-data/test-schema.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "title": "Test Schema File", - "type": "object", - - "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" ] - } - }, - - "properties": { - "exampleString": { - "type": "string" - }, - "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": "#/definitions/type1" }, - { "$ref": "#/definitions/type2" } - ] - } - }, - "additionalProperties": false, - "required": [ "exampleString", "exampleArray" ] -} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-additional.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-additional.schema.json new file mode 100644 index 00000000000..0618076245a --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-additional.schema.json @@ -0,0 +1,8 @@ +{ + "exampleString": "This is a string", + "exampleLink": "http://example.com", + "exampleArray": ["apple", "banana", "coconut"], + "exampleOneOf": { + "field2": "blah" + } +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-format.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-format.schema.json new file mode 100644 index 00000000000..8c5693588f3 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-format.schema.json @@ -0,0 +1,5 @@ +{ + "exampleString": "This is a string", + "exampleLink": "//example", + "exampleArray": ["apple", "banana", "coconut"] +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-04.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-04.schema.json new file mode 100644 index 00000000000..2f1f8bec465 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-04.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test Schema File", + "type": "object", + + "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"] + } + }, + + "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": "#/definitions/type1" }, { "$ref": "#/definitions/type2" }] + }, + "exampleUniqueObjectArray": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field2": { + "type": "string" + }, + "field3": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false, + "required": ["exampleString", "exampleArray"] +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-07.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-07.schema.json new file mode 100644 index 00000000000..40a5c41fc0c --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-07.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test Schema File", + "type": "object", + + "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"] + } + }, + + "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": "#/definitions/type1" }, { "$ref": "#/definitions/type2" }] + }, + "exampleUniqueObjectArray": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field2": { + "type": "string" + }, + "field3": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false, + "required": ["exampleString", "exampleArray"] +} 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-schemas/test-schema.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema.schema.json new file mode 100644 index 00000000000..b49f3165f38 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema.schema.json @@ -0,0 +1,74 @@ +{ + "title": "Test Schema File", + "type": "object", + + "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"] + } + }, + + "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": "#/definitions/type1" }, { "$ref": "#/definitions/type2" }] + }, + "exampleUniqueObjectArray": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field2": { + "type": "string" + }, + "field3": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false, + "required": ["exampleString", "exampleArray"] +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-valid.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-valid.schema.json new file mode 100644 index 00000000000..879ef2a0f36 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-valid.schema.json @@ -0,0 +1,15 @@ +{ + "exampleString": "This is a string", + "exampleLink": "http://example.com", + "exampleArray": ["apple", "banana", "coconut"], + "exampleUniqueObjectArray": [ + { + "field2": "a", + "field3": "b" + }, + { + "field2": "c", + "field3": "d" + } + ] +} diff --git a/libraries/node-core-library/src/test/test-data/test.json b/libraries/node-core-library/src/test/test-data/test.json deleted file mode 100644 index 7ffb7142ca8..00000000000 --- a/libraries/node-core-library/src/test/test-data/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "exampleString": "This is a string", - "exampleArray": [ - "apple", - "banana", - "coconut" - ] -} diff --git a/libraries/node-core-library/src/test/test-data/test2.json b/libraries/node-core-library/src/test/test-data/test2.json deleted file mode 100644 index 5a0eeeaa2de..00000000000 --- a/libraries/node-core-library/src/test/test-data/test2.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "exampleString": "This is a string", - "exampleArray": [ - "apple", - "banana", - "coconut" - ], - "exampleOneOf": { - "field2": "blah" - } -} diff --git a/libraries/node-core-library/src/test/writeBuffersToFile.test.ts b/libraries/node-core-library/src/test/writeBuffersToFile.test.ts new file mode 100644 index 00000000000..9e3c8bf086a --- /dev/null +++ b/libraries/node-core-library/src/test/writeBuffersToFile.test.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. + +const openHandle: jest.Mock<{}> = jest.fn(); + +const closeSync: jest.Mock<{}> = jest.fn(); +const ensureDir: jest.Mock<{}> = jest.fn(); +const ensureDirSync: jest.Mock<{}> = jest.fn(); +const openSync: jest.Mock<{}> = jest.fn(); +const writevSync: jest.Mock<{}> = jest.fn(); + +jest.mock('fs-extra', () => { + return { + closeSync, + ensureDir, + ensureDirSync, + openSync, + writevSync + }; +}); +jest.mock('node:fs/promises', () => { + return { + open: openHandle + }; +}); +jest.mock('../Text', () => { + return { + Encoding: { + Utf8: 'utf8' + } + }; +}); + +describe('FileSystem', () => { + const content: Uint8Array[] = []; + let totalBytes: number = 0; + let FileSystem: typeof import('../FileSystem').FileSystem; + + beforeAll(async () => { + FileSystem = (await import('../FileSystem')).FileSystem; + totalBytes = 0; + let nextValue = 37; + for (let i = 0; i < 10; i++) { + const arr: Uint8Array = new Uint8Array(i + 1); + content[i] = arr; + for (let j = 0; j < arr.length; j++) { + arr[j] = nextValue; + // 256 and 11 are coprime, so this sequence will cover all 256 values. + // These are deliberately not the ordinal index just to ensure that an index isn't accidentally being written to the file. + // eslint-disable-next-line no-bitwise + nextValue = (nextValue + 11) & 0xff; + } + totalBytes += arr.length; + } + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('writeBuffersToFile', () => { + it('handles a single-shot write', () => { + const sampleFd: number = 42; + openSync.mockReturnValue(sampleFd); + writevSync.mockImplementation((fd: number, buffers: Uint8Array[]) => { + expect(fd).toEqual(sampleFd); + expect(buffers).toEqual(content); + return totalBytes; + }); + + FileSystem.writeBuffersToFile('/fake/path', content); + expect(openSync).toHaveBeenCalledWith('/fake/path', 'w'); + expect(closeSync).toHaveBeenCalledWith(sampleFd); + expect(writevSync).toHaveBeenCalledTimes(1); + }); + + for (let i = 0; i < totalBytes; i++) { + const increment: number = i; + const expectedCallCount = Math.ceil(totalBytes / increment); + const expectedData = Buffer.concat(content); + const sampleFd: number = 42; + + it(`handles a multi-shot write writing ${increment} bytes at a time`, () => { + const actual = Buffer.alloc(totalBytes); + let written: number = 0; + openSync.mockReturnValue(sampleFd); + writevSync.mockImplementation((fd: number, buffers: Uint8Array[]) => { + expect(fd).toEqual(sampleFd); + const writtenThisTime: number = Math.min(increment, totalBytes - written); + let bufIndex: number = 0; + let bufOffset: number = 0; + for (let j = 0; j < writtenThisTime; j++) { + actual[written] = buffers[bufIndex][bufOffset]; + bufOffset++; + written++; + if (bufOffset === buffers[bufIndex].length) { + bufIndex++; + bufOffset = 0; + } + } + return writtenThisTime; + }); + + FileSystem.writeBuffersToFile('/fake/path', content); + expect(openSync).toHaveBeenCalledWith('/fake/path', 'w'); + expect(closeSync).toHaveBeenCalledWith(sampleFd); + expect(writevSync).toHaveBeenCalledTimes(expectedCallCount); + expect(actual.equals(expectedData)).toBeTruthy(); + }); + } + }); + + describe('writeBuffersToFileAsync', () => { + it('handles a single-shot write', async () => { + const sampleHandle = { + close: jest.fn(), + writev: jest.fn() + }; + openHandle.mockReturnValue(sampleHandle); + sampleHandle.writev.mockImplementation((buffers: Uint8Array[]) => { + expect(buffers).toEqual(content); + return { bytesWritten: totalBytes }; + }); + + await FileSystem.writeBuffersToFileAsync('/fake/path', content); + expect(openHandle).toHaveBeenCalledWith('/fake/path', 'w'); + expect(sampleHandle.close).toHaveBeenCalledTimes(1); + expect(sampleHandle.writev).toHaveBeenCalledTimes(1); + }); + + for (let i = 0; i < totalBytes; i++) { + const increment: number = i; + const expectedCallCount = Math.ceil(totalBytes / increment); + const expectedData = Buffer.concat(content); + it(`handles a multi-shot write writing ${increment} bytes at a time`, async () => { + const sampleHandle = { + close: jest.fn(), + writev: jest.fn() + }; + const actual = Buffer.alloc(totalBytes); + let written: number = 0; + openHandle.mockReturnValue(sampleHandle); + sampleHandle.writev.mockImplementation((buffers: Uint8Array[]) => { + const writtenThisTime: number = Math.min(increment, totalBytes - written); + let bufIndex: number = 0; + let bufOffset: number = 0; + for (let j = 0; j < writtenThisTime; j++) { + actual[written] = buffers[bufIndex][bufOffset]; + bufOffset++; + written++; + if (bufOffset === buffers[bufIndex].length) { + bufIndex++; + bufOffset = 0; + } + } + return { bytesWritten: writtenThisTime }; + }); + + await FileSystem.writeBuffersToFileAsync('/fake/path', content); + expect(openHandle).toHaveBeenCalledWith('/fake/path', 'w'); + expect(sampleHandle.close).toHaveBeenCalledTimes(1); + expect(sampleHandle.writev).toHaveBeenCalledTimes(expectedCallCount); + expect(actual.equals(expectedData)).toBeTruthy(); + }); + } + }); +}); 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 824a88b71e5..1a33d17b873 100644 --- a/libraries/node-core-library/tsconfig.json +++ b/libraries/node-core-library/tsconfig.json @@ -1,10 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "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..bc349f9a4be --- /dev/null +++ b/libraries/npm-check-fork/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..301519ebfb0 --- /dev/null +++ b/libraries/npm-check-fork/CHANGELOG.json @@ -0,0 +1,89 @@ +{ + "name": "@rushstack/npm-check-fork", + "entries": [ + { + "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..eacc99bc131 --- /dev/null +++ b/libraries/npm-check-fork/CHANGELOG.md @@ -0,0 +1,41 @@ +# Change Log - @rushstack/npm-check-fork + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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..df55cc1ab72 --- /dev/null +++ b/libraries/npm-check-fork/package.json @@ -0,0 +1,34 @@ +{ + "name": "@rushstack/npm-check-fork", + "version": "0.1.6", + "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/index.js", + "typings": "lib/index.d.ts", + "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": { + "giturl": "^2.0.0", + "lodash": "~4.17.15", + "package-json": "^10.0.1", + "semver": "~7.5.4", + "throat": "^6.0.2" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/lodash": "4.14.116", + "@types/semver": "7.5.0", + "local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/libraries/npm-check-fork/src/BestGuessHomepage.ts b/libraries/npm-check-fork/src/BestGuessHomepage.ts new file mode 100644 index 00000000000..fd7a6380084 --- /dev/null +++ b/libraries/npm-check-fork/src/BestGuessHomepage.ts @@ -0,0 +1,23 @@ +/// + +import gitUrl from 'giturl'; + +import type { INpmCheckPackageVersion, INpmCheckRegistryData } from './interfaces/INpmCheckRegistry'; + +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 && + gitUrl.parse(packageDataForLatest.bugs.url.trim())) || + (packageDataForLatest.repository && + packageDataForLatest.repository.url && + gitUrl.parse(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..5bdbf601037 --- /dev/null +++ b/libraries/npm-check-fork/src/CreatePackageSummary.ts @@ -0,0 +1,97 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; + +import _ from 'lodash'; +import semver 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; + const usingNonSemver: boolean | '' | null = + latest !== undefined && semver.valid(latest) && semver.lt(latest, '1.0.0-pre'); + + let bump: INpmCheckVersionBumpType; + const bumpRaw: INpmCheckVersionBumpType = + semver.valid(latest) && + semver.valid(versionToUse) && + (usingNonSemver && versionToUse && latest + ? semver.diff(versionToUse, latest) + ? 'nonSemver' + : semver.diff(versionToUse, latest) + : versionToUse && latest + ? semver.diff(versionToUse, latest) + : undefined); + if (bumpRaw && bumpRaw !== null) { + bump = bumpRaw as INpmCheckVersionBumpType; + } else { + bump = undefined; + } + + 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 + devDependency: _.has(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..d7dd2e97bf2 --- /dev/null +++ b/libraries/npm-check-fork/src/GetLatestFromRegistry.ts @@ -0,0 +1,45 @@ +import os from 'node:os'; + +import _ from 'lodash'; +import semver from 'semver'; +import packageJson from 'package-json'; +import throat from 'throat'; + +import bestGuessHomepage from './BestGuessHomepage'; +import type { INpmRegistryInfo } from './interfaces/INpmCheckRegistry'; + +const cpuCount: number = os.cpus().length; + +export default async function getNpmInfo(packageName: string): Promise { + const limit: () => Promise = throat(cpuCount, () => + packageJson(packageName, { fullMetadata: true, allVersions: true }) + ); + return limit() + .then((rawData: packageJson.FullMetadata) => { + const CRAZY_HIGH_SEMVER: string = '8000.0.0'; + const sortedVersions: string[] = _(rawData.versions) + .keys() + .remove(_.partial(semver.gt, CRAZY_HIGH_SEMVER)) + .sort(semver.compare) + .valueOf(); + + 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, '*') || ''; + + return { + latest: latestStableRelease, + next: next, + versions: sortedVersions, + homepage: bestGuessHomepage(rawData) || '' + }; + }) + .catch((error) => { + const errorMessage: string = `Registry error ${error.message}`; + return { + error: errorMessage + }; + }); +} diff --git a/libraries/npm-check-fork/src/NpmCheck.ts b/libraries/npm-check-fork/src/NpmCheck.ts new file mode 100644 index 00000000000..aea2339a4c9 --- /dev/null +++ b/libraries/npm-check-fork/src/NpmCheck.ts @@ -0,0 +1,34 @@ +import _ from 'lodash'; + +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 _.extend(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..124a5b2f310 --- /dev/null +++ b/libraries/npm-check-fork/src/NpmCheckState.ts @@ -0,0 +1,27 @@ +import path from 'node:path'; + +import _ from 'lodash'; + +import { + DefaultNpmCheckOptions, + type INpmCheckPackageJson, + type INpmCheckState +} from './interfaces/INpmCheck'; +import readPackageJson from './ReadPackageJson'; + +export default async function initializeState(initialOptions?: INpmCheckState): Promise { + const state: INpmCheckState = _.extend(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/ReadPackageJson.ts b/libraries/npm-check-fork/src/ReadPackageJson.ts new file mode 100644 index 00000000000..b8166d486ca --- /dev/null +++ b/libraries/npm-check-fork/src/ReadPackageJson.ts @@ -0,0 +1,18 @@ +import _ from 'lodash'; + +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 _.extend({ devDependencies: {}, dependencies: {}, error: error }, pkg); +} diff --git a/libraries/npm-check-fork/src/index.ts b/libraries/npm-check-fork/src/index.ts new file mode 100644 index 00000000000..43444bb3484 --- /dev/null +++ b/libraries/npm-check-fork/src/index.ts @@ -0,0 +1,3 @@ +export { default as NpmCheck } from './NpmCheck'; +export type { INpmCheckPackageSummary } from './interfaces/INpmCheckPackageSummary'; +export type { INpmCheckState } from './interfaces/INpmCheck'; 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..21d2aed3bd2 --- /dev/null +++ b/libraries/npm-check-fork/src/interfaces/INpmCheckPackageSummary.ts @@ -0,0 +1,28 @@ +export type INpmCheckVersionBumpType = + | '' + | 'build' + | 'major' + | 'premajor' + | 'minor' + | 'preminor' + | 'patch' + | 'prepatch' + | 'prerelease' + | '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..63f4e63e0dc --- /dev/null +++ b/libraries/npm-check-fork/src/interfaces/INpmCheckRegistry.ts @@ -0,0 +1,23 @@ +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 }; +} 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..e8499b92ce2 --- /dev/null +++ b/libraries/npm-check-fork/src/tests/BestGuessHomepage.test.ts @@ -0,0 +1,57 @@ +// Mock gitUrl.parse +jest.mock('giturl', () => ({ parse: (url: string) => url })); + +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' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://bugs.com'); + }); + + it('returns repository.url if homepage and bugs.url are missing', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + repository: { url: 'https://repo.com' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://repo.com'); + }); + + 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..9490c34b926 --- /dev/null +++ b/libraries/npm-check-fork/src/tests/GetLatestFromRegistry.test.ts @@ -0,0 +1,51 @@ +jest.mock('package-json'); + +import getNpmInfo from '../GetLatestFromRegistry'; +import packageJson from 'package-json'; +import type { INpmRegistryInfo } from '../interfaces/INpmCheckRegistry'; + +const mockPackageJson = packageJson as jest.MockedFunction; + +describe('getNpmInfo', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns registry info with homepage', async () => { + mockPackageJson.mockResolvedValue({ + versions: { + '1.0.0': { + homepage: 'https://homepage.com' + }, + '2.0.0': { + bugs: { url: 'https://bugs.com' } + } + }, + 'dist-tags': { latest: '1.0.0', next: '2.0.0' } + } as unknown as packageJson.FullMetadata); + 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 packageJson throws', async () => { + mockPackageJson.mockRejectedValue(new 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 () => { + mockPackageJson.mockResolvedValue({ + versions: { + '1.0.0': {}, + '2.0.0': {} + }, + 'dist-tags': { latest: '1.0.0', next: '2.0.0' } + } as unknown as packageJson.FullMetadata); + const result: INpmRegistryInfo = await getNpmInfo('test-package'); + expect(result).toHaveProperty('homepage', ''); + }); +}); 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/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/types/giturl-typings.d.ts b/libraries/npm-check-fork/src/types/giturl-typings.d.ts new file mode 100644 index 00000000000..3202ff78a60 --- /dev/null +++ b/libraries/npm-check-fork/src/types/giturl-typings.d.ts @@ -0,0 +1,4 @@ +declare module 'giturl' { + function parse(url: string): string; + export { parse }; +} diff --git a/libraries/npm-check-fork/tsconfig.json b/libraries/npm-check-fork/tsconfig.json new file mode 100644 index 00000000000..f9b633dca52 --- /dev/null +++ b/libraries/npm-check-fork/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": false, + "outDir": "./lib" + } +} diff --git a/libraries/operation-graph/.npmignore b/libraries/operation-graph/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/operation-graph/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/operation-graph/CHANGELOG.json b/libraries/operation-graph/CHANGELOG.json new file mode 100644 index 00000000000..2905e21b5cc --- /dev/null +++ b/libraries/operation-graph/CHANGELOG.json @@ -0,0 +1,815 @@ +{ + "name": "@rushstack/operation-graph", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/operation-graph_v0.2.34", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/operation-graph_v0.2.33", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/operation-graph_v0.2.32", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/operation-graph_v0.2.31", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/operation-graph_v0.2.30", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/operation-graph_v0.2.29", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/operation-graph_v0.2.28", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/operation-graph_v0.2.27", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Handle errors when sending IPC messages to host." + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/operation-graph_v0.2.26", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/operation-graph_v0.2.25", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/operation-graph_v0.2.24", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/operation-graph_v0.2.23", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/operation-graph_v0.2.22", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/operation-graph_v0.2.21", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/operation-graph_v0.2.20", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/operation-graph_v0.2.19", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/operation-graph_v0.2.18", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/operation-graph_v0.2.17", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/operation-graph_v0.2.16", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/operation-graph_v0.2.15", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/operation-graph_v0.2.14", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/operation-graph_v0.2.13", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "patch": [ + { + "comment": "Fix memory leaks on abort controllers." + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/operation-graph_v0.2.12", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/operation-graph_v0.2.11", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/operation-graph_v0.2.10", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/operation-graph_v0.2.9", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/operation-graph_v0.2.8", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/operation-graph_v0.2.7", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/operation-graph_v0.2.6", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/operation-graph_v0.2.5", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/operation-graph_v0.2.4", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/operation-graph_v0.2.3", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade build dependencies" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/operation-graph_v0.2.2", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/operation-graph_v0.2.1", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/operation-graph_v0.2.0", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "minor": [ + { + "comment": "Enforce task concurrency limits and respect priority for sequencing." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/operation-graph_v0.1.2", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/operation-graph_v0.1.1", + "date": "Mon, 25 Sep 2023 23:38:27 GMT", + "comments": { + "patch": [ + { + "comment": "Add OperationStatus.Waiting to possible states in watcher loop, add exhaustiveness check." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/operation-graph_v0.1.0", + "date": "Tue, 19 Sep 2023 15:21:51 GMT", + "comments": { + "minor": [ + { + "comment": "Initial commit. Includes IPC support and watch loop." + } + ] + } + } + ] +} diff --git a/libraries/operation-graph/CHANGELOG.md b/libraries/operation-graph/CHANGELOG.md new file mode 100644 index 00000000000..44563c8a364 --- /dev/null +++ b/libraries/operation-graph/CHANGELOG.md @@ -0,0 +1,309 @@ +# Change Log - @rushstack/operation-graph + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.2.34 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.2.33 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.2.32 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.2.31 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.2.30 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.2.29 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.2.28 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.2.27 +Wed, 17 Jul 2024 00:11:19 GMT + +### Patches + +- Handle errors when sending IPC messages to host. + +## 0.2.26 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.2.25 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.2.24 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.2.23 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.2.22 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.2.21 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.2.20 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.2.19 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.2.18 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.2.17 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.2.16 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.2.15 +Wed, 10 Apr 2024 15:10:08 GMT + +_Version update only_ + +## 0.2.14 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.2.13 +Thu, 22 Feb 2024 01:36:09 GMT + +### Patches + +- Fix memory leaks on abort controllers. + +## 0.2.12 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.2.11 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.2.10 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.2.9 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.2.8 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.2.7 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.2.6 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.2.5 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.2.4 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.2.3 +Tue, 16 Jan 2024 18:30:10 GMT + +### Patches + +- Upgrade build dependencies + +## 0.2.2 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.2.1 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.0 +Thu, 28 Sep 2023 20:53:17 GMT + +### Minor changes + +- Enforce task concurrency limits and respect priority for sequencing. + +## 0.1.2 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.1.1 +Mon, 25 Sep 2023 23:38:27 GMT + +### Patches + +- Add OperationStatus.Waiting to possible states in watcher loop, add exhaustiveness check. + +## 0.1.0 +Tue, 19 Sep 2023 15:21:51 GMT + +### Minor changes + +- Initial commit. Includes IPC support and watch loop. + diff --git a/libraries/operation-graph/LICENSE b/libraries/operation-graph/LICENSE new file mode 100644 index 00000000000..bd4533ad992 --- /dev/null +++ b/libraries/operation-graph/LICENSE @@ -0,0 +1,24 @@ +@rushstack/operation-graph + +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/operation-graph/README.md b/libraries/operation-graph/README.md new file mode 100644 index 00000000000..f04f7c25777 --- /dev/null +++ b/libraries/operation-graph/README.md @@ -0,0 +1,12 @@ +# @rushstack/operation-graph + +This library contains logic for managing and executing tasks in a directed acyclic graph. It supports single execution or executing in a loop. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/operation-graph/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/operation-graph/) + +`@rushstack/operation-graph` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/operation-graph/config/api-extractor.json b/libraries/operation-graph/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/operation-graph/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/operation-graph/config/jest.config.json b/libraries/operation-graph/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/operation-graph/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/operation-graph/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/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 new file mode 100644 index 00000000000..d410ec644ff --- /dev/null +++ b/libraries/operation-graph/package.json @@ -0,0 +1,35 @@ +{ + "name": "@rushstack/operation-graph", + "version": "0.5.5", + "description": "Library for managing and executing operations in a directed acyclic graph.", + "main": "lib/index.js", + "typings": "dist/operation-graph.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/operation-graph" + }, + "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:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/libraries/operation-graph/src/IOperationRunner.ts b/libraries/operation-graph/src/IOperationRunner.ts new file mode 100644 index 00000000000..4f66f332d1b --- /dev/null +++ b/libraries/operation-graph/src/IOperationRunner.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. + +import type { OperationStatus } from './OperationStatus'; +import type { OperationError } from './OperationError'; +import type { Stopwatch } from './Stopwatch'; + +/** + * Information passed to the executing `IOperationRunner` + * + * @beta + */ +export interface IOperationRunnerContext { + /** + * An abort signal for the overarching execution. Runners should do their best to gracefully abort + * as soon as possible if the signal is aborted. + */ + abortSignal: AbortSignal; + + /** + * If this is the first time this operation has been executed. + */ + isFirstRun: boolean; + + /** + * 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?: (detail?: string) => void; +} + +/** + * Interface contract for a single state of an operation. + * + * @beta + */ +export interface IOperationState { + /** + * The status code for the operation. + */ + status: OperationStatus; + /** + * Whether the operation has been run at least once. + */ + hasBeenRun: boolean; + /** + * The error, if the status is `OperationStatus.Failure`. + */ + error: OperationError | undefined; + /** + * Timing information for the operation. + */ + stopwatch: Stopwatch; +} + +/** + * Interface contract for the current and past state of an operation. + * + * @beta + */ +export interface IOperationStates { + /** + * The current state of the operation. + */ + readonly state: Readonly | undefined; + /** + * The previous state of the operation. + */ + readonly lastState: Readonly | undefined; +} + +/** + * 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 + * implementation manages the actual process for running a single operation. + * + * @beta + */ +export interface IOperationRunner { + /** + * Name of the operation, for logging. + */ + readonly name: string; + + /** + * Indicates that this runner is architectural and should not be reported on. + */ + silent: boolean; + + /** + * Method to be executed for the operation. + */ + executeAsync(context: IOperationRunnerContext): Promise; +} diff --git a/libraries/operation-graph/src/Operation.ts b/libraries/operation-graph/src/Operation.ts new file mode 100644 index 00000000000..71ffa0887c1 --- /dev/null +++ b/libraries/operation-graph/src/Operation.ts @@ -0,0 +1,375 @@ +// 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 { ITerminal } from '@rushstack/terminal'; + +import { Stopwatch } from './Stopwatch'; +import type { + IOperationRunner, + IOperationRunnerContext, + IOperationState, + IOperationStates +} 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 { + /** + * The name of this operation, for logging. + */ + name: string; + + /** + * The group that this operation belongs to. Will be used for logging and duration tracking. + */ + group?: OperationGroupRecord | undefined; + + /** + * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of + * running the operation. + */ + runner?: IOperationRunner | undefined; + + /** + * 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`. + * + * @beta + */ +export interface IExecuteOperationContext extends Omit { + /** + * Function to invoke before execution of an operation, for logging. + */ + beforeExecute(operation: Operation, state: IOperationState): void; + + /** + * Function to invoke after execution of an operation, for logging. + */ + afterExecute(operation: Operation, state: IOperationState): void; + + /** + * Function used to schedule the concurrency-limited execution of an operation. + * + * Will return OperationStatus.Aborted if execution is aborted before the task executes. + */ + queueWork(workFn: () => Promise, priority: number): Promise; + + /** + * 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 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. + */ + requestRun?: OperationRequestRunCallback; + + /** + * Terminal to write output to. + */ + terminal: ITerminal; +} + +/** + * 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 + * 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. + * + * @beta + */ +export class Operation + implements IOperationStates +{ + /** + * A set of all dependencies which must be executed before this operation is complete. + */ + public readonly dependencies: Set> = new Set< + Operation + >(); + /** + * A set of all operations that wait for this operation. + */ + 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 group: OperationGroupRecord | undefined; + /** + * The name of this operation, for logging. + */ + public readonly name: string; + + /** + * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of + * running the operation. + */ + public runner: IOperationRunner | undefined = undefined; + + /** + * 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 + * longest chain of projects which must be executed in order, thereby limiting execution speed + * of the entire operation tree. + * + * This number is calculated via a memoized depth-first search, and when choosing the next + * operation to execute, the operation with the highest criticalPathLength is chosen. + * + * Example: + * (0) A + * \\ + * (1) B C (0) (applications) + * \\ /|\\ + * \\ / | \\ + * (2) D | X (1) (utilities) + * | / \\ + * |/ \\ + * (2) Y Z (2) (other utilities) + * + * All roots (A & C) have a criticalPathLength of 0. + * B has a score of 1, since A depends on it. + * D has a score of 2, since we look at the longest chain (e.g D-\>B-\>A is longer than D-\>C) + * X has a score of 1, since the only package which depends on it is A + * Z has a score of 2, since only X depends on it, and X has a score of 1 + * Y has a score of 2, since the chain Y-\>X-\>C is longer than Y-\>C + * + * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength() + */ + public criticalPathLength: number | 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. + */ + public weight: number; + + /** + * The state of this operation the previous time a manager was invoked. + */ + public lastState: IOperationState | undefined = undefined; + + /** + * The current state of this operation + */ + public state: IOperationState | undefined = undefined; + + /** + * A cached execution promise for the current OperationExecutionManager invocation of this operation. + */ + private _promise: Promise | undefined = undefined; + + /** + * If true, then a run of this operation is currently wanted. + * This is used to track state from the `requestRun` callback passed to the runner. + */ + private _runPending: boolean = true; + + public readonly metadata: TMetadata; + + public constructor(options: IOperationOptions) { + this.group = options.group; + this.runner = options.runner; + this.weight = options.weight ?? 1; + this.name = options.name; + this.metadata = options.metadata || ({} as TMetadata); + + if (this.group) { + this.group.addOperation(this); + } + } + + public addDependency(dependency: Operation): void { + this.dependencies.add(dependency); + dependency.consumers.add(this); + } + + public deleteDependency(dependency: Operation): void { + this.dependencies.delete(dependency); + dependency.consumers.delete(this); + } + + public reset(): void { + // Reset operation state + this.lastState = this.state; + + this.state = { + status: this.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready, + hasBeenRun: this.lastState?.hasBeenRun ?? false, + error: undefined, + stopwatch: new Stopwatch() + }; + + this._promise = undefined; + this._runPending = true; + } + + /** + * @internal + */ + public async _executeAsync(context: IExecuteOperationContext): Promise { + const { state } = this; + if (!state) { + throw new Error(`Operation state has not been initialized.`); + } + + if (!this._promise) { + this._promise = this._executeInnerAsync(context, state); + } + + return this._promise; + } + + private async _executeInnerAsync( + context: IExecuteOperationContext, + rawState: IOperationState + ): Promise { + const state: IOperationState = rawState; + const { runner } = this; + + const dependencyResults: PromiseSettledResult[] = await Promise.allSettled( + Array.from(this.dependencies, (dependency: Operation) => dependency._executeAsync(context)) + ); + + const { abortSignal, requestRun, queueWork } = context; + + if (abortSignal.aborted) { + state.status = OperationStatus.Aborted; + return state.status; + } + + for (const result of dependencyResults) { + if ( + result.status === 'rejected' || + result.value === OperationStatus.Blocked || + result.value === OperationStatus.Failure + ) { + state.status = OperationStatus.Blocked; + return state.status; + } + } + + state.status = OperationStatus.Ready; + + const innerContext: IOperationRunnerContext = { + abortSignal, + isFirstRun: !state.hasBeenRun, + requestRun: requestRun + ? (detail?: string) => { + switch (this.state?.status) { + case OperationStatus.Waiting: + case OperationStatus.Ready: + case OperationStatus.Executing: + // If current status has not yet resolved to a fixed value, + // re-executing this operation does not require a full rerun + // of the operation graph. Simply mark that a run is requested. + + // This variable is on the Operation instead of the + // containing closure to deal with scenarios in which + // the runner hangs on to an old copy of the callback. + this._runPending = true; + return; + + case OperationStatus.Blocked: + case OperationStatus.Aborted: + case OperationStatus.Failure: + case OperationStatus.NoOp: + case OperationStatus.Success: + // 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, detail); + default: + // This line is here to enforce exhaustiveness + const currentStatus: undefined = this.state?.status; + throw new InternalError(`Unexpected status: ${currentStatus}`); + } + } + : undefined + }; + + // eslint-disable-next-line require-atomic-updates + state.status = await queueWork(async (): Promise => { + // Redundant variable to satisfy require-atomic-updates + const innerState: IOperationState = state; + + if (abortSignal.aborted) { + innerState.status = OperationStatus.Aborted; + return innerState.status; + } + + context.beforeExecute(this, innerState); + + innerState.stopwatch.start(); + innerState.status = OperationStatus.Executing; + // Mark that the operation has been started at least once. + innerState.hasBeenRun = true; + + while (this._runPending) { + this._runPending = false; + try { + // We don't support aborting in the middle of a runner's execution. + innerState.status = runner ? await runner.executeAsync(innerContext) : OperationStatus.NoOp; + } catch (error) { + innerState.status = OperationStatus.Failure; + innerState.error = error as OperationError; + } + + // Since runner.executeAsync is async, a change could have occurred that requires re-execution + // This operation is still active, so can re-execute immediately, rather than forcing a whole + // new execution pass. + + // As currently written, this does mean that if a job is scheduled with higher priority while + // this operation is still executing, it will still wait for this retry. This may not be desired + // and if it becomes a problem, the retry loop will need to be moved outside of the `queueWork` call. + // This introduces complexity regarding tracking of timing and start/end logging, however. + + if (this._runPending) { + if (abortSignal.aborted) { + innerState.status = OperationStatus.Aborted; + break; + } else { + context.terminal.writeLine(`Immediate rerun requested. Executing.`); + } + } + } + + state.stopwatch.stop(); + context.afterExecute(this, state); + + return state.status; + }, /* priority */ this.criticalPathLength ?? 0); + + return state.status; + } +} diff --git a/libraries/operation-graph/src/OperationError.ts b/libraries/operation-graph/src/OperationError.ts new file mode 100644 index 00000000000..85f392a34be --- /dev/null +++ b/libraries/operation-graph/src/OperationError.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. + +/** + * Encapsulates information about an error + * + * @beta + */ +export class OperationError extends Error { + protected _type: string; + + public constructor(type: string, message: string) { + super(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/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work + // + // Note: the prototype must also be set on any classes which extend this one + Object.setPrototypeOf(this, OperationError.prototype); + + this._type = type; + } + + public get message(): string { + return `[${this._type}] '${super.message}'`; + } + + public toString(): string { + return this.message; + } +} diff --git a/libraries/operation-graph/src/OperationExecutionManager.ts b/libraries/operation-graph/src/OperationExecutionManager.ts new file mode 100644 index 00000000000..7132e35af97 --- /dev/null +++ b/libraries/operation-graph/src/OperationExecutionManager.ts @@ -0,0 +1,216 @@ +// 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 { ITerminal } from '@rushstack/terminal'; + +import type { IOperationState } from './IOperationRunner'; +import type { IExecuteOperationContext, Operation, OperationRequestRunCallback } from './Operation'; +import type { OperationGroupRecord } from './OperationGroupRecord'; +import { OperationStatus } from './OperationStatus'; +import { calculateCriticalPathLengths } from './calculateCriticalPath'; +import { WorkQueue } from './WorkQueue'; + +/** + * Options for the current run. + * + * @beta + */ +export interface IOperationExecutionOptions< + TOperationMetadata extends {} = {}, + TGroupMetadata extends {} = {} +> { + abortSignal: AbortSignal; + parallelism: number; + terminal: ITerminal; + + requestRun?: OperationRequestRunCallback; + + beforeExecuteOperation?: (operation: Operation) => void; + afterExecuteOperation?: (operation: Operation) => void; + beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; + afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; +} + +/** + * 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. + * + * @beta + */ +export class OperationExecutionManager { + /** + * The set of operations that will be executed + */ + 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; + + private readonly _groupRecords: Set>; + + public constructor(operations: ReadonlySet>) { + let trackedOperationCount: number = 0; + for (const operation of operations) { + if (!operation.runner?.silent) { + // Only count non-silent operations + trackedOperationCount++; + } + } + + this._trackedOperationCount = trackedOperationCount; + + 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)) { + throw new Error( + `Operation ${JSON.stringify(consumer.name)} declares a dependency on operation ` + + `${JSON.stringify(dependency.name)} that is not in the set of operations to execute.` + ); + } + } + } + } + + /** + * 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 { + let hasReportedFailures: boolean = false; + + const { abortSignal, parallelism, terminal, requestRun } = executionOptions; + + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + const startedGroups: Set = new Set(); + const finishedGroups: Set = new Set(); + + const maxParallelism: number = Math.min(this._operations.length, parallelism); + + for (const groupRecord of this._groupRecords) { + groupRecord.reset(); + } + + for (const operation of this._operations) { + operation.reset(); + } + + terminal.writeVerboseLine(`Executing a maximum of ${maxParallelism} simultaneous tasks...`); + + const workQueueAbortController: AbortController = new AbortController(); + const abortHandler: () => void = () => workQueueAbortController.abort(); + abortSignal.addEventListener('abort', abortHandler, { once: true }); + try { + const workQueue: WorkQueue = new WorkQueue(workQueueAbortController.signal); + + const executionContext: IExecuteOperationContext = { + terminal, + abortSignal, + + requestRun, + + queueWork: (workFn: () => Promise, priority: number): Promise => { + return workQueue.pushAsync(workFn, priority); + }, + + beforeExecute: (operation: Operation): void => { + // Initialize group if uninitialized and log the group name + 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 { group, runner } = operation; + if (group) { + group.setOperationAsComplete(operation, state); + } + + if (state.status === OperationStatus.Failure) { + // This operation failed. Mark it as such and all reachable dependents as blocked. + // Failed operations get reported, even if silent. + // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure. + const message: string | undefined = state.error?.message; + if (message) { + terminal.writeErrorLine(message); + } + hasReportedFailures = true; + } + + 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); + } + } + } + }; + + const workQueuePromise: Promise = Async.forEachAsync( + workQueue, + (workFn: () => Promise) => workFn(), + { + concurrency: maxParallelism + } + ); + + await Promise.all(this._operations.map((record: Operation) => record._executeAsync(executionContext))); + + // Terminate queue execution. + workQueueAbortController.abort(); + await workQueuePromise; + } finally { + // Cleanup resources + abortSignal.removeEventListener('abort', abortHandler); + } + + const finalStatus: OperationStatus = + this._trackedOperationCount === 0 + ? OperationStatus.NoOp + : abortSignal.aborted + ? OperationStatus.Aborted + : hasReportedFailures + ? OperationStatus.Failure + : OperationStatus.Success; + + return finalStatus; + } +} diff --git a/libraries/operation-graph/src/OperationGroupRecord.ts b/libraries/operation-graph/src/OperationGroupRecord.ts new file mode 100644 index 00000000000..d6d21106253 --- /dev/null +++ b/libraries/operation-graph/src/OperationGroupRecord.ts @@ -0,0 +1,80 @@ +// 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 { IOperationState } from './IOperationRunner'; +import type { Operation } from './Operation'; +import { OperationStatus } from './OperationStatus'; +import { Stopwatch } from './Stopwatch'; + +/** + * Meta-entity that tracks information about a group of related operations. + * + * @beta + */ +export class OperationGroupRecord { + private readonly _operations: Set = new Set(); + private _remainingOperations: Set = new Set(); + + private _groupStopwatch: Stopwatch = new Stopwatch(); + private _hasCancellations: boolean = false; + private _hasFailures: boolean = false; + + public readonly name: string; + public readonly metadata: TMetadata; + + public get duration(): number { + return this._groupStopwatch ? this._groupStopwatch.duration : 0; + } + + public get finished(): boolean { + return this._remainingOperations.size === 0; + } + + public get hasCancellations(): boolean { + return this._hasCancellations; + } + + public get hasFailures(): boolean { + return this._hasFailures; + } + + public constructor(name: string, metadata: TMetadata = {} as TMetadata) { + this.name = name; + this.metadata = metadata; + } + + public addOperation(operation: Operation): void { + this._operations.add(operation); + } + + public startTimer(): void { + // Keep this undefined until needed, then start to avoid subsequent calls to startTimer() + this._groupStopwatch.start(); + } + + public setOperationAsComplete(operation: Operation, state: IOperationState): void { + if (!this._remainingOperations.has(operation)) { + throw new InternalError(`Operation ${operation.name} is not in the group ${this.name}`); + } + + if (state.status === OperationStatus.Aborted) { + this._hasCancellations = true; + } else if (state.status === OperationStatus.Failure) { + this._hasFailures = true; + } + + this._remainingOperations.delete(operation); + if (this._remainingOperations.size === 0) { + this._groupStopwatch.stop(); + } + } + + public reset(): void { + this._remainingOperations = new Set(this._operations); + this._groupStopwatch.reset(); + this._hasCancellations = false; + this._hasFailures = false; + } +} diff --git a/libraries/operation-graph/src/OperationStatus.ts b/libraries/operation-graph/src/OperationStatus.ts new file mode 100644 index 00000000000..176108455c4 --- /dev/null +++ b/libraries/operation-graph/src/OperationStatus.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. + +/** + * Enumeration defining potential states of an operation + * @beta + */ +export enum OperationStatus { + /** + * The Operation is on the queue, ready to execute + */ + Ready = 'READY', + /** + * The Operation is on the queue, waiting for one or more depencies + */ + Waiting = 'WAITING', + /** + * The Operation is currently executing + */ + Executing = 'EXECUTING', + /** + * The Operation completed successfully and did not write to standard output + */ + Success = 'SUCCESS', + /** + * The Operation failed + */ + Failure = 'FAILURE', + /** + * The operation was aborted + */ + Aborted = 'ABORTED', + /** + * The Operation could not be executed because one or more of its dependencies failed + */ + Blocked = 'BLOCKED', + /** + * The operation performed no meaningful work. + */ + NoOp = 'NO OP' +} diff --git a/libraries/operation-graph/src/Stopwatch.ts b/libraries/operation-graph/src/Stopwatch.ts new file mode 100644 index 00000000000..ed1591d731a --- /dev/null +++ b/libraries/operation-graph/src/Stopwatch.ts @@ -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. + +/** + * Represents a typical timer/stopwatch which keeps track + * of elapsed time in between two events. + * + * @public + */ +export class Stopwatch { + private _startTime: number | undefined; + private _endTime: number | undefined; + private _running: boolean; + + public constructor() { + this._startTime = undefined; + this._endTime = undefined; + this._running = false; + } + + /** + * Static helper function which creates a stopwatch which is immediately started + */ + public static start(): Stopwatch { + return new Stopwatch().start(); + } + + public get isRunning(): boolean { + return this._running; + } + + /** + * Starts the stopwatch. Note that if end() has been called, + * reset() should be called before calling start() again. + */ + public start(): Stopwatch { + if (this._startTime !== undefined) { + throw new Error('Call reset() before starting the Stopwatch'); + } + this._startTime = performance.now(); + this._endTime = undefined; + this._running = true; + return this; + } + + /** + * Stops executing the stopwatch and saves the current timestamp + */ + public stop(): Stopwatch { + this._endTime = this._startTime !== undefined ? performance.now() : undefined; + this._running = false; + return this; + } + + /** + * Resets all values of the stopwatch back to the original + */ + public reset(): Stopwatch { + this._endTime = this._startTime = undefined; + this._running = false; + return this; + } + + /** + * Displays how long the stopwatch has been executing in a human readable format. + */ + public toString(): string { + if (!this._running && this._startTime === undefined) { + return '0.00 seconds (stopped)'; + } + const totalSeconds: number = this.duration; + + if (totalSeconds > 60) { + const minutes: number = Math.floor(totalSeconds / 60); + const seconds: number = totalSeconds % 60.0; + + return `${minutes.toFixed(0)} minute${minutes === 1 ? '' : 's'} ${seconds.toFixed(1)} seconds`; + } else { + return `${totalSeconds.toFixed(2)} seconds`; + } + } + + /** + * Get the duration in seconds. + */ + public get duration(): number { + if (this._startTime === undefined) { + return 0; + } + const curTime: number = this._endTime !== undefined ? this._endTime : performance.now(); + + return (curTime - this._startTime) / 1000.0; + } + + /** + * Return the start time of the most recent stopwatch run. + */ + public get startTime(): number | undefined { + return this._startTime; + } + + /** + * Return the end time of the most recent stopwatch run. + */ + public get endTime(): number | undefined { + return this._endTime; + } +} diff --git a/libraries/operation-graph/src/WatchLoop.ts b/libraries/operation-graph/src/WatchLoop.ts new file mode 100644 index 00000000000..43ff6b32c7c --- /dev/null +++ b/libraries/operation-graph/src/WatchLoop.ts @@ -0,0 +1,299 @@ +// 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 { AlreadyReportedError } from '@rushstack/node-core-library'; + +import type { OperationRequestRunCallback } from './Operation'; +import { OperationStatus } from './OperationStatus'; +import type { + IAfterExecuteEventMessage, + IPCHost, + CommandMessageFromHost, + ISyncEventMessage, + IRequestRunEventMessage +} from './protocol.types'; + +/** + * Callbacks for the watch loop. + * + * @beta + */ +export interface IWatchLoopOptions { + /** + * Callback that performs the core work of a single iteration. + */ + executeAsync: (state: IWatchLoopState) => Promise; + /** + * Logging callback immediately before execution occurs. + */ + 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: OperationRequestRunCallback; + /** + * Logging callback when a run is aborted. + */ + onAbort: () => void; +} + +/** + * The public API surface of the watch loop, for use in the `executeAsync` callback. + * + * @beta + */ +export interface IWatchLoopState { + get abortSignal(): AbortSignal; + requestRun: OperationRequestRunCallback; +} + +/** + * This class implements a watch loop. + * + * @beta + */ +export class WatchLoop implements IWatchLoopState { + private readonly _options: Readonly; + + private _abortController: AbortController; + private _isRunning: boolean; + private _runRequested: boolean; + private _requestRunPromise: Promise<[string, string?]>; + private _resolveRequestRun!: (value: [string, string?]) => void; + + public constructor(options: IWatchLoopOptions) { + this._options = options; + + this._abortController = new AbortController(); + this._isRunning = false; + // Always start as true, so that any requests prior to first run are silenced. + this._runRequested = true; + this._requestRunPromise = new Promise<[string, string?]>((resolve) => { + this._resolveRequestRun = resolve; + }); + } + + /** + * Runs the inner loop until the abort signal is cancelled or a run completes without a new run being requested. + */ + public async runUntilStableAsync(abortSignal: AbortSignal): Promise { + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + abortSignal.addEventListener('abort', this._abortCurrent, { once: true }); + + try { + let result: OperationStatus = OperationStatus.Ready; + + do { + // Always check the abort signal first, in case it was aborted in the async tick since the last executeAsync() call. + if (abortSignal.aborted) { + return OperationStatus.Aborted; + } + + result = await this._runIterationAsync(); + } while (this._runRequested); + + // Even if the run has finished, if the abort signal was aborted, we should return `Aborted` just in case. + return abortSignal.aborted ? OperationStatus.Aborted : result; + } finally { + abortSignal.removeEventListener('abort', this._abortCurrent); + } + } + + /** + * Runs the inner loop until the abort signal is aborted. Will otherwise wait indefinitely for a new run to be requested. + */ + public async runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise { + if (abortSignal.aborted) { + return; + } + + const abortPromise: Promise = once(abortSignal, 'abort'); + + while (!abortSignal.aborted) { + await this.runUntilStableAsync(abortSignal); + + onWaiting(); + await Promise.race([this._requestRunPromise, abortPromise]); + } + } + + /** + * Sets up an IPC handler that will run the inner loop when it receives a "run" message from the host. + * Runs until receiving an "exit" message from the host, or aborts early if an unhandled error is thrown. + */ + public async runIPCAsync(host: IPCHost = process): Promise { + await new Promise((resolve, reject) => { + let abortController: AbortController = new AbortController(); + + let runRequestedFromHost: boolean = true; + let status: OperationStatus = OperationStatus.Ready; + + function tryMessageHost( + message: ISyncEventMessage | IRequestRunEventMessage | IAfterExecuteEventMessage + ): void { + if (!host.send) { + return reject(new Error('Host does not support IPC')); + } + + try { + host.send(message); + } catch (err) { + reject(new Error(`Unable to communicate with host: ${err}`)); + } + } + + function requestRunFromHost(requestor: string, detail?: string): void { + if (runRequestedFromHost) { + return; + } + + runRequestedFromHost = true; + + const requestRunMessage: IRequestRunEventMessage = { + event: 'requestRun', + requestor, + detail + }; + + tryMessageHost(requestRunMessage); + } + + function sendSync(): void { + const syncMessage: ISyncEventMessage = { + event: 'sync', + status + }; + tryMessageHost(syncMessage); + } + + host.on('message', async (message: CommandMessageFromHost) => { + switch (message.command) { + case 'exit': { + return resolve(); + } + + case 'cancel': { + if (this._isRunning) { + abortController.abort(); + abortController = new AbortController(); + // This will terminate the currently executing `runUntilStableAsync` call. + } + return; + } + + case 'run': { + runRequestedFromHost = false; + + status = OperationStatus.Executing; + + try { + status = await this.runUntilStableAsync(abortController.signal); + // ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..." + 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); + } finally { + const afterExecuteMessage: IAfterExecuteEventMessage = { + event: 'after-execute', + status + }; + tryMessageHost(afterExecuteMessage); + } + return; + } + + case 'sync': { + return sendSync(); + } + + default: { + return reject(new Error(`Unexpected command from host: ${message}`)); + } + } + }); + + sendSync(); + }); + } + + /** + * Requests that a new run occur. + */ + public requestRun: OperationRequestRunCallback = (requestor: string, detail?: string) => { + if (!this._runRequested) { + this._options.onRequestRun(requestor, detail); + this._runRequested = true; + if (this._isRunning) { + this._options.onAbort(); + this._abortCurrent(); + } + } + this._resolveRequestRun([requestor, detail]); + }; + + /** + * The abort signal for the current iteration. + */ + public get abortSignal(): AbortSignal { + return this._abortController.signal; + } + + /** + * Cancels the current iteration (if possible). + */ + private _abortCurrent = (): void => { + this._abortController.abort(); + }; + + /** + * Resets the abort signal and run request state. + */ + private _reset(): void { + if (this._abortController.signal.aborted) { + this._abortController = new AbortController(); + } + + if (this._runRequested) { + this._runRequested = false; + this._requestRunPromise = new Promise<[string, string?]>((resolve) => { + this._resolveRequestRun = resolve; + }); + } + } + + /** + * Runs a single iteration of the loop. + * @returns The status of the iteration. + */ + private async _runIterationAsync(): Promise { + this._reset(); + + this._options.onBeforeExecute(); + try { + this._isRunning = true; + return await this._options.executeAsync(this); + } catch (err) { + if (!(err instanceof AlreadyReportedError)) { + throw err; + } else { + return OperationStatus.Failure; + } + } finally { + this._isRunning = false; + } + } +} diff --git a/libraries/operation-graph/src/WorkQueue.ts b/libraries/operation-graph/src/WorkQueue.ts new file mode 100644 index 00000000000..114eae665e8 --- /dev/null +++ b/libraries/operation-graph/src/WorkQueue.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 { Async, MinimumHeap } from '@rushstack/node-core-library'; + +import { OperationStatus } from './OperationStatus'; + +interface IQueueItem { + task: () => Promise; + priority: number; +} + +export class WorkQueue { + private readonly _queue: MinimumHeap; + private readonly _abortSignal: AbortSignal; + private readonly _abortPromise: Promise; + + private _pushPromise: Promise; + private _resolvePush: () => void; + private _resolvePushTimeout: NodeJS.Timeout | undefined; + + public constructor(abortSignal: AbortSignal) { + // Sort by priority descending. Thus the comparator returns a negative number if a has higher priority than b. + this._queue = new MinimumHeap((a: IQueueItem, b: IQueueItem) => b.priority - a.priority); + this._abortSignal = abortSignal; + this._abortPromise = abortSignal.aborted + ? Promise.resolve() + : new Promise((resolve) => { + abortSignal.addEventListener('abort', () => resolve(), { once: true }); + }); + + [this._pushPromise, this._resolvePush] = Async.getSignal(); + this._resolvePushTimeout = undefined; + } + + public async *[Symbol.asyncIterator](): AsyncIterableIterator<() => Promise> { + while (!this._abortSignal.aborted) { + while (this._queue.size > 0) { + const item: IQueueItem = this._queue.poll()!; + yield item.task; + } + + await Promise.race([this._pushPromise, this._abortPromise]); + } + } + + public pushAsync(task: () => Promise, priority: number): Promise { + return new Promise((resolve, reject) => { + this._queue.push({ + task: () => task().then(resolve, reject), + priority + }); + + // 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._abortPromise.finally(() => resolve(OperationStatus.Aborted)); + + this._resolvePushDebounced(); + }); + } + + private _resolvePushDebounced(): void { + if (!this._resolvePushTimeout) { + this._resolvePushTimeout = setTimeout(() => { + this._resolvePushTimeout = undefined; + this._resolvePush(); + + [this._pushPromise, this._resolvePush] = Async.getSignal(); + }); + } + } +} diff --git a/libraries/operation-graph/src/calculateCriticalPath.ts b/libraries/operation-graph/src/calculateCriticalPath.ts new file mode 100644 index 00000000000..d00ba113457 --- /dev/null +++ b/libraries/operation-graph/src/calculateCriticalPath.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 ISortableOperation> { + name: string | undefined; + criticalPathLength?: number | undefined; + weight: number; + consumers: Set; +} + +/** + * For every operation in the input, computes the length of the longest chain of operations that depend on it. + * This value is stored as `operation.criticalPathLength`. + */ +export function calculateCriticalPathLengths>(operations: Iterable): T[] { + // Clone the set of operations as an array, so that we can sort it. + const queue: T[] = Array.from(operations); + + // Create a collection for detecting visited nodes + const cycleDetectorStack: Set = new Set(); + for (const operation of queue) { + calculateCriticalPathLength(operation, cycleDetectorStack); + } + + return queue; +} + +/** + * Calculates the shortest path from `startOperation` to `endOperation`. + * Used when printing out circular dependencies. + */ +export function calculateShortestPath>( + startOperation: T, + endOperation: T +): T[] { + // Map of each operation to the most optimal parent + const parents: Map = new Map([[endOperation, undefined]]); + let finalParent: T | undefined; + + // Run a breadth-first search to find the shortest path between the start and end operations + outer: for (const [operation] of parents) { + for (const consumer of operation.consumers) { + // Since this is a breadth-first traversal, the first encountered path to a given node + // will be tied for shortest, so only the first encountered path needs to be tracked + if (!parents.has(consumer)) { + parents.set(consumer, operation); + } + + if (consumer === startOperation) { + finalParent = operation; + break outer; + } + } + } + + if (!finalParent) { + throw new Error(`Could not find a path from "${startOperation.name}" to "${endOperation.name}"`); + } + + // Walk back up the path from the end operation to the start operation + let currentOperation: T = finalParent; + const path: T[] = [startOperation]; + while (currentOperation !== undefined) { + path.push(currentOperation); + currentOperation = parents.get(currentOperation)!; + } + return path; +} + +/** + * Perform a depth-first search to find critical path length to the provided operation. + * Cycle detection comes at minimal additional cost. + */ +export function calculateCriticalPathLength>( + operation: T, + dependencyChain: Set +): number { + if (dependencyChain.has(operation)) { + // Ensure we have the shortest path to the cycle + const shortestPath: T[] = calculateShortestPath(operation, operation); + + throw new Error( + 'A cyclic dependency was encountered:\n ' + + shortestPath.map((visitedTask) => visitedTask.name).join('\n -> ') + ); + } + + let { criticalPathLength } = operation; + + if (criticalPathLength !== undefined) { + // This has been visited already + return criticalPathLength; + } + + criticalPathLength = 0; + if (operation.consumers.size) { + dependencyChain.add(operation); + for (const consumer of operation.consumers) { + criticalPathLength = Math.max( + criticalPathLength, + calculateCriticalPathLength(consumer, dependencyChain) + ); + } + dependencyChain.delete(operation); + } + // Include the contribution from the current operation + criticalPathLength += operation.weight ?? 1; + + // Record result + operation.criticalPathLength = criticalPathLength; + + // Directly writing operations to an output collection here would yield a topological sorted set + // However, we want a bit more fine-tuning of the output than just the raw topology + + return criticalPathLength; +} diff --git a/libraries/operation-graph/src/index.ts b/libraries/operation-graph/src/index.ts new file mode 100644 index 00000000000..3debdfb5bb7 --- /dev/null +++ b/libraries/operation-graph/src/index.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 type { + IOperationRunner, + IOperationRunnerContext, + IOperationState, + IOperationStates +} from './IOperationRunner'; + +export type { + IAfterExecuteEventMessage, + ISyncEventMessage, + IRequestRunEventMessage, + EventMessageFromClient, + ICancelCommandMessage, + IExitCommandMessage, + IRunCommandMessage, + ISyncCommandMessage, + CommandMessageFromHost, + IPCHost +} from './protocol.types'; + +export { + type IExecuteOperationContext, + type IOperationOptions, + Operation, + type OperationRequestRunCallback +} from './Operation'; + +export { OperationError } from './OperationError'; + +export { type IOperationExecutionOptions, OperationExecutionManager } from './OperationExecutionManager'; + +export { OperationGroupRecord } from './OperationGroupRecord'; + +export { OperationStatus } from './OperationStatus'; + +export { Stopwatch } from './Stopwatch'; + +export { type IWatchLoopOptions, type IWatchLoopState, WatchLoop } from './WatchLoop'; diff --git a/libraries/operation-graph/src/protocol.types.ts b/libraries/operation-graph/src/protocol.types.ts new file mode 100644 index 00000000000..f178ea84eb9 --- /dev/null +++ b/libraries/operation-graph/src/protocol.types.ts @@ -0,0 +1,101 @@ +// 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'; + +/** + * A message sent to the host to ask it to run this task. + * + * @beta + */ +export interface IRequestRunEventMessage { + event: 'requestRun'; + /** + * 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; +} + +/** + * A message sent to the host upon completion of a run of this task. + * + * @beta + */ +export interface IAfterExecuteEventMessage { + event: 'after-execute'; + status: OperationStatus; +} + +/** + * A message sent to the host upon connection of the channel, to indicate + * to the host that this task supports the protocol and to provide baseline status information. + * + * @beta + */ +export interface ISyncEventMessage { + event: 'sync'; + status: OperationStatus; +} + +/** + * A message sent by the host to tell the watch loop to cancel the current run. + * + * @beta + */ +export interface ICancelCommandMessage { + command: 'cancel'; +} + +/** + * A message sent by the host to tell the watch loop to shutdown gracefully. + * + * @beta + */ +export interface IExitCommandMessage { + command: 'exit'; +} + +/** + * A message sent by the host to tell the watch loop to perform a single run. + * + * @beta + */ +export interface IRunCommandMessage { + command: 'run'; +} + +/** + * A message sent by the host to ask for to resync status information. + * + * @beta + */ +export interface ISyncCommandMessage { + command: 'sync'; +} + +/** + * The set of known messages from the host to the watch loop. + * @beta + */ +export type CommandMessageFromHost = + | ICancelCommandMessage + | IExitCommandMessage + | IRunCommandMessage + | ISyncCommandMessage; + +/** + * The set of known messages from the watch loop to the host. + * @beta + */ +export type EventMessageFromClient = IRequestRunEventMessage | IAfterExecuteEventMessage | ISyncEventMessage; + +/** + * The interface contract for IPC send/receive, to support alternate channels and unit tests. + * + * @beta + */ +export type IPCHost = Pick; diff --git a/libraries/operation-graph/src/test/OperationExecutionManager.test.ts b/libraries/operation-graph/src/test/OperationExecutionManager.test.ts new file mode 100644 index 00000000000..f1649986914 --- /dev/null +++ b/libraries/operation-graph/src/test/OperationExecutionManager.test.ts @@ -0,0 +1,439 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type ITerminal, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import { Operation } from '../Operation'; +import { OperationExecutionManager } from '../OperationExecutionManager'; +import { OperationStatus } from '../OperationStatus'; +import type { IOperationRunner, IOperationRunnerContext } from '../IOperationRunner'; +import { Async } from '@rushstack/node-core-library'; + +type ExecuteAsyncMock = jest.Mock< + ReturnType, + Parameters +>; + +describe(OperationExecutionManager.name, () => { + describe('constructor', () => { + it('handles empty input', () => { + const manager: OperationExecutionManager = new OperationExecutionManager(new Set()); + + expect(manager).toBeDefined(); + }); + + it('throws if a dependency is not in the set', () => { + const alpha: Operation = new Operation({ + name: 'alpha' + }); + const beta: Operation = new Operation({ + name: 'beta' + }); + + alpha.addDependency(beta); + + expect(() => { + return new OperationExecutionManager(new Set([alpha])); + }).toThrowErrorMatchingSnapshot(); + }); + + it('sets critical path lengths', () => { + const alpha: Operation = new Operation({ + name: 'alpha' + }); + const beta: Operation = new Operation({ + name: 'beta' + }); + + alpha.addDependency(beta); + + new OperationExecutionManager(new Set([alpha, beta])); + + expect(alpha.criticalPathLength).toBe(1); + expect(beta.criticalPathLength).toBe(2); + }); + }); + + describe(OperationExecutionManager.prototype.executeAsync.name, () => { + describe('single pass', () => { + it('handles empty input', async () => { + const manager: OperationExecutionManager = new OperationExecutionManager(new Set()); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(result).toBe(OperationStatus.NoOp); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + }); + + it('handles trivial input', async () => { + const operation: Operation = new Operation({ + name: 'alpha' + }); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([operation])); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(result).toBe(OperationStatus.Success); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + + expect(operation.state?.status).toBe(OperationStatus.NoOp); + }); + + it('executes in order', async () => { + const runAlpha: ExecuteAsyncMock = jest.fn(); + const runBeta: ExecuteAsyncMock = jest.fn(); + + const alpha: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync: runAlpha, + silent: false + } + }); + const beta: Operation = new Operation({ + name: 'beta', + runner: { + name: 'beta', + executeAsync: runBeta, + silent: false + } + }); + beta.addDependency(alpha); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([alpha, beta])); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + runAlpha.mockImplementationOnce(async () => { + expect(runBeta).not.toHaveBeenCalled(); + return OperationStatus.Success; + }); + + runBeta.mockImplementationOnce(async () => { + expect(runAlpha).toHaveBeenCalledTimes(1); + return OperationStatus.Success; + }); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(result).toBe(OperationStatus.Success); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + + expect(runAlpha).toHaveBeenCalledTimes(1); + expect(runBeta).toHaveBeenCalledTimes(1); + + expect(alpha.state?.status).toBe(OperationStatus.Success); + expect(beta.state?.status).toBe(OperationStatus.Success); + }); + + it('blocks on failure', async () => { + const runAlpha: ExecuteAsyncMock = jest.fn(); + const runBeta: ExecuteAsyncMock = jest.fn(); + + const alpha: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync: runAlpha, + silent: false + } + }); + const beta: Operation = new Operation({ + name: 'beta', + runner: { + name: 'beta', + executeAsync: runBeta, + silent: false + } + }); + beta.addDependency(alpha); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([alpha, beta])); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + runAlpha.mockImplementationOnce(async () => { + expect(runBeta).not.toHaveBeenCalled(); + return OperationStatus.Failure; + }); + + runBeta.mockImplementationOnce(async () => { + expect(runAlpha).toHaveBeenCalledTimes(1); + return OperationStatus.Success; + }); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(result).toBe(OperationStatus.Failure); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(runAlpha).toHaveBeenCalledTimes(1); + expect(runBeta).toHaveBeenCalledTimes(0); + + expect(alpha.state?.status).toBe(OperationStatus.Failure); + expect(beta.state?.status).toBe(OperationStatus.Blocked); + }); + + it('does not track noops', async () => { + const operation: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync(): Promise { + return Promise.resolve(OperationStatus.NoOp); + }, + silent: true + } + }); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([operation])); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(result).toBe(OperationStatus.NoOp); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + }); + + it('respects priority order', async () => { + const runAlpha: ExecuteAsyncMock = jest.fn(); + const runBeta: ExecuteAsyncMock = jest.fn(); + + const alpha: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync: runAlpha, + silent: false + } + }); + const beta: Operation = new Operation({ + name: 'beta', + runner: { + name: 'beta', + executeAsync: runBeta, + silent: false + } + }); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([alpha, beta])); + + // Override default sort order. + alpha.criticalPathLength = 1; + beta.criticalPathLength = 2; + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + const executed: Operation[] = []; + + runAlpha.mockImplementationOnce(async () => { + executed.push(alpha); + return OperationStatus.Success; + }); + + runBeta.mockImplementationOnce(async () => { + executed.push(beta); + return OperationStatus.Success; + }); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal + }); + + expect(executed).toEqual([beta, alpha]); + + expect(result).toBe(OperationStatus.Success); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + + expect(runAlpha).toHaveBeenCalledTimes(1); + expect(runBeta).toHaveBeenCalledTimes(1); + + expect(alpha.state?.status).toBe(OperationStatus.Success); + expect(beta.state?.status).toBe(OperationStatus.Success); + }); + + it('respects concurrency', async () => { + let concurrency: number = 0; + let maxConcurrency: number = 0; + + const run: ExecuteAsyncMock = jest.fn( + async (context: IOperationRunnerContext): Promise => { + ++concurrency; + await Async.sleepAsync(0); + if (concurrency > maxConcurrency) { + maxConcurrency = concurrency; + } + --concurrency; + return OperationStatus.Success; + } + ); + + const alpha: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync: run, + silent: false + } + }); + const beta: Operation = new Operation({ + name: 'beta', + runner: { + name: 'beta', + executeAsync: run, + silent: false + } + }); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([alpha, beta])); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal: ITerminal = new Terminal(terminalProvider); + + const result: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 2, + terminal + }); + + expect(result).toBe(OperationStatus.Success); + expect(terminalProvider.getOutput()).toMatchSnapshot(); + + expect(run).toHaveBeenCalledTimes(2); + + expect(maxConcurrency).toBe(2); + + expect(alpha.state?.status).toBe(OperationStatus.Success); + expect(beta.state?.status).toBe(OperationStatus.Success); + }); + }); + + describe('watch mode', () => { + it('executes in order', async () => { + const runAlpha: ExecuteAsyncMock = jest.fn(); + const runBeta: ExecuteAsyncMock = jest.fn(); + + const requestRun: jest.Mock = jest.fn(); + + const alpha: Operation = new Operation({ + name: 'alpha', + runner: { + name: 'alpha', + executeAsync: runAlpha, + silent: false + } + }); + const beta: Operation = new Operation({ + name: 'beta', + runner: { + name: 'beta', + executeAsync: runBeta, + silent: false + } + }); + const executed: Operation[] = []; + beta.addDependency(alpha); + const manager: OperationExecutionManager = new OperationExecutionManager(new Set([alpha, beta])); + + const terminalProvider1: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal1: ITerminal = new Terminal(terminalProvider1); + + let betaRequestRun: IOperationRunnerContext['requestRun']; + + runAlpha.mockImplementationOnce(async () => { + executed.push(alpha); + return OperationStatus.Success; + }); + + runBeta.mockImplementationOnce(async (options) => { + executed.push(beta); + betaRequestRun = options.requestRun; + return OperationStatus.Success; + }); + + const result1: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal: terminal1, + requestRun + }); + + expect(executed).toEqual([alpha, beta]); + + expect(requestRun).not.toHaveBeenCalled(); + expect(betaRequestRun).toBeDefined(); + + expect(result1).toBe(OperationStatus.Success); + expect(terminalProvider1.getOutput()).toMatchSnapshot('first'); + + expect(runAlpha).toHaveBeenCalledTimes(1); + expect(runBeta).toHaveBeenCalledTimes(1); + + expect(alpha.state?.status).toBe(OperationStatus.Success); + expect(beta.state?.status).toBe(OperationStatus.Success); + + betaRequestRun!('why'); + + expect(requestRun).toHaveBeenCalledTimes(1); + expect(requestRun).toHaveBeenLastCalledWith(beta.name, 'why'); + + const terminalProvider2: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); + const terminal2: ITerminal = new Terminal(terminalProvider2); + + runAlpha.mockImplementationOnce(async () => { + return OperationStatus.NoOp; + }); + + runBeta.mockImplementationOnce(async () => { + return OperationStatus.Success; + }); + + const result2: OperationStatus = await manager.executeAsync({ + abortSignal: new AbortController().signal, + parallelism: 1, + terminal: terminal2, + requestRun + }); + + expect(result2).toBe(OperationStatus.Success); + expect(terminalProvider2.getOutput()).toMatchSnapshot('second'); + + expect(runAlpha).toHaveBeenCalledTimes(2); + expect(runBeta).toHaveBeenCalledTimes(2); + + expect(alpha.lastState?.status).toBe(OperationStatus.Success); + expect(beta.lastState?.status).toBe(OperationStatus.Success); + + expect(alpha.state?.status).toBe(OperationStatus.NoOp); + expect(beta.state?.status).toBe(OperationStatus.Success); + }); + }); + }); +}); diff --git a/libraries/operation-graph/src/test/WatchLoop.test.ts b/libraries/operation-graph/src/test/WatchLoop.test.ts new file mode 100644 index 00000000000..2a8c44b3ce3 --- /dev/null +++ b/libraries/operation-graph/src/test/WatchLoop.test.ts @@ -0,0 +1,319 @@ +// 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 { OperationStatus } from '../OperationStatus'; +import { type IWatchLoopOptions, type IWatchLoopState, WatchLoop } from '../WatchLoop'; +import type { + CommandMessageFromHost, + EventMessageFromClient, + IAfterExecuteEventMessage, + IPCHost, + ISyncEventMessage +} from '../protocol.types'; + +type IMockOptions = { + [K in keyof IWatchLoopOptions]: jest.Mock< + ReturnType, + Parameters + >; +}; + +interface IMockOptionsAndWatchLoop { + watchLoop: WatchLoop; + mocks: IMockOptions; +} + +function createWatchLoop(): IMockOptionsAndWatchLoop { + const mocks = { + executeAsync: jest.fn(), + onBeforeExecute: jest.fn(), + onRequestRun: jest.fn(), + onAbort: jest.fn() + }; + + return { + watchLoop: new WatchLoop(mocks), + mocks + }; +} + +describe(WatchLoop.name, () => { + describe(WatchLoop.prototype.runUntilStableAsync.name, () => { + it('executes once when no run is requested', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + const outerAbortController: AbortController = new AbortController(); + + await watchLoop.runUntilStableAsync(outerAbortController.signal); + + expect(onBeforeExecute).toHaveBeenCalledTimes(1); + expect(executeAsync).toHaveBeenCalledTimes(1); + expect(onRequestRun).toHaveBeenCalledTimes(0); + expect(onAbort).toHaveBeenCalledTimes(0); + }); + + it('will abort and re-execute if a run is requested while executing', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + let iteration: number = 0; + const maxIterations: number = 5; + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + iteration++; + if (iteration < maxIterations) { + state.requestRun('test'); + return OperationStatus.Success; + } + return OperationStatus.NoOp; + }); + + expect(await watchLoop.runUntilStableAsync(outerAbortController.signal)).toEqual(OperationStatus.NoOp); + + expect(onBeforeExecute).toHaveBeenCalledTimes(maxIterations); + expect(executeAsync).toHaveBeenCalledTimes(maxIterations); + expect(onRequestRun).toHaveBeenCalledTimes(maxIterations - 1); + expect(onAbort).toHaveBeenCalledTimes(maxIterations - 1); + }); + + it('will abort if the outer signal is aborted', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + let iteration: number = 0; + const cancelIterations: number = 3; + const maxIterations: number = 5; + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + iteration++; + if (iteration < maxIterations) { + state.requestRun('test', 'some detail'); + } + if (iteration === cancelIterations) { + outerAbortController.abort(); + } + return OperationStatus.Failure; + }); + + expect(await watchLoop.runUntilStableAsync(outerAbortController.signal)).toEqual( + OperationStatus.Aborted + ); + + expect(onBeforeExecute).toHaveBeenCalledTimes(cancelIterations); + expect(executeAsync).toHaveBeenCalledTimes(cancelIterations); + expect(onRequestRun).toHaveBeenCalledTimes(cancelIterations); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'some detail'); + expect(onAbort).toHaveBeenCalledTimes(cancelIterations); + }); + + it('will abort if an unhandled exception arises', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + let iteration: number = 0; + const exceptionIterations: number = 3; + const maxIterations: number = 5; + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + iteration++; + if (iteration < maxIterations) { + state.requestRun('test', 'reason'); + } + if (iteration === exceptionIterations) { + throw new Error('fnord'); + } + return OperationStatus.Success; + }); + + await expect(() => watchLoop.runUntilStableAsync(outerAbortController.signal)).rejects.toThrow('fnord'); + + expect(onBeforeExecute).toHaveBeenCalledTimes(exceptionIterations); + expect(executeAsync).toHaveBeenCalledTimes(exceptionIterations); + expect(onRequestRun).toHaveBeenCalledTimes(exceptionIterations); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'reason'); + expect(onAbort).toHaveBeenCalledTimes(exceptionIterations); + }); + }); + + it('treats AlreadyReportedError as generic failure', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + throw new AlreadyReportedError(); + }); + + expect(await watchLoop.runUntilStableAsync(outerAbortController.signal)).toEqual(OperationStatus.Failure); + + expect(onBeforeExecute).toHaveBeenCalledTimes(1); + expect(executeAsync).toHaveBeenCalledTimes(1); + expect(onRequestRun).toHaveBeenCalledTimes(0); + expect(onAbort).toHaveBeenCalledTimes(0); + }); + + describe(WatchLoop.prototype.runUntilAbortedAsync.name, () => { + it('will abort if an unhandled exception arises', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + let iteration: number = 0; + const exceptionIterations: number = 3; + const maxIterations: number = 5; + + const onWaiting: jest.Mock = jest.fn(); + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + iteration++; + if (iteration < maxIterations) { + state.requestRun('test', 'why'); + } + if (iteration === exceptionIterations) { + throw new Error('fnord'); + } + return OperationStatus.Success; + }); + + await expect(() => + watchLoop.runUntilAbortedAsync(outerAbortController.signal, onWaiting) + ).rejects.toThrow('fnord'); + + expect(onBeforeExecute).toHaveBeenCalledTimes(exceptionIterations); + expect(executeAsync).toHaveBeenCalledTimes(exceptionIterations); + expect(onRequestRun).toHaveBeenCalledTimes(exceptionIterations); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'why'); + expect(onAbort).toHaveBeenCalledTimes(exceptionIterations); + expect(onWaiting).toHaveBeenCalledTimes(0); + }); + + it('will wait if not immediately ready', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + let iteration: number = 0; + const cancelIterations: number = 3; + const maxIterations: number = 5; + + const onWaiting: jest.Mock = jest.fn(); + const promises: Promise[] = []; + + const outerAbortController: AbortController = new AbortController(); + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + iteration++; + if (iteration < maxIterations) { + promises.push( + new Promise((resolve) => setTimeout(resolve, 0)).then(() => state.requestRun('test')) + ); + } + if (iteration === cancelIterations) { + outerAbortController.abort(); + } + return OperationStatus.Success; + }); + + await watchLoop.runUntilAbortedAsync(outerAbortController.signal, onWaiting); + + expect(onBeforeExecute).toHaveBeenCalledTimes(cancelIterations); + expect(executeAsync).toHaveBeenCalledTimes(cancelIterations); + expect(onRequestRun).toHaveBeenLastCalledWith('test', undefined); + + // Since the run finishes, no cancellation should occur + expect(onAbort).toHaveBeenCalledTimes(0); + expect(onWaiting).toHaveBeenCalledTimes(cancelIterations); + + // Canceling of the outer signal happens before requestRun on the final iteration + expect(onRequestRun).toHaveBeenCalledTimes(cancelIterations - 1); + + await Promise.all(promises); + // Final iteration async + expect(onRequestRun).toHaveBeenCalledTimes(cancelIterations); + }); + }); + + describe(WatchLoop.prototype.runIPCAsync.name, () => { + it('messsages the host with finished state', async () => { + const { + watchLoop, + mocks: { executeAsync, onBeforeExecute, onRequestRun, onAbort } + } = createWatchLoop(); + + const onMock: jest.Mock = jest.fn(); + const sendMock: jest.Mock = jest.fn(); + + let messageHandler: ((message: CommandMessageFromHost) => void) | undefined; + + onMock.mockImplementationOnce((event: string, handler: (message: CommandMessageFromHost) => void) => { + if (event !== 'message') { + throw new Error(`Unexpected event type: ${event}`); + } + messageHandler = handler; + }); + + sendMock.mockImplementation((message: EventMessageFromClient) => { + if (message.event === 'sync') { + process.nextTick(() => messageHandler!({ command: 'run' })); + } else { + process.nextTick(() => messageHandler!({ command: 'exit' })); + } + }); + + const ipcHost: IPCHost = { + on: onMock, + send: sendMock + }; + + executeAsync.mockImplementation(async (state: IWatchLoopState) => { + return OperationStatus.Success; + }); + + await watchLoop.runIPCAsync(ipcHost); + + expect(onBeforeExecute).toHaveBeenCalledTimes(1); + expect(executeAsync).toHaveBeenCalledTimes(1); + expect(onRequestRun).toHaveBeenCalledTimes(0); + expect(onAbort).toHaveBeenCalledTimes(0); + + expect(onMock).toHaveBeenCalledTimes(1); + expect(sendMock).toHaveBeenCalledTimes(2); + + const syncMessage: ISyncEventMessage = { + event: 'sync', + status: OperationStatus.Ready + }; + + const successMessage: IAfterExecuteEventMessage = { + event: 'after-execute', + status: OperationStatus.Success + }; + + expect(sendMock).toHaveBeenCalledWith(syncMessage); + expect(sendMock).toHaveBeenLastCalledWith(successMessage); + }); + }); +}); diff --git a/libraries/operation-graph/src/test/WorkQueue.test.ts b/libraries/operation-graph/src/test/WorkQueue.test.ts new file mode 100644 index 00000000000..745f71ff509 --- /dev/null +++ b/libraries/operation-graph/src/test/WorkQueue.test.ts @@ -0,0 +1,149 @@ +// 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 { OperationStatus } from '../OperationStatus'; +import { WorkQueue } from '../WorkQueue'; + +describe(WorkQueue.name, () => { + it('Executes in dependency order', async () => { + const abortController: AbortController = new AbortController(); + + const queue: WorkQueue = new WorkQueue(abortController.signal); + + const executed: Set = new Set(); + + const outerPromises: Promise[] = []; + + for (let i: number = 0; i < 10; i++) { + outerPromises.push( + queue.pushAsync(async () => { + executed.add(i); + return OperationStatus.Success; + }, i) + ); + } + + let expectedCount: number = 0; + const queuePromise: Promise = (async () => { + for await (const task of queue) { + expect(executed.size).toBe(expectedCount); + await task(); + ++expectedCount; + expect(executed.has(outerPromises.length - expectedCount)).toBe(true); + } + })(); + + expect((await Promise.all(outerPromises)).every((status) => status === OperationStatus.Success)).toBe( + true + ); + abortController.abort(); + await queuePromise; + }); + + it('Aborts any tasks left on the queue when aborted', async () => { + const abortController: AbortController = new AbortController(); + + const queue: WorkQueue = new WorkQueue(abortController.signal); + + const executed: Set = new Set(); + + const outerPromises: Promise[] = []; + + for (let i: number = 0; i < 10; i++) { + outerPromises.push( + queue.pushAsync(async () => { + executed.add(i); + return OperationStatus.Success; + }, i) + ); + } + + let expectedCount: number = 0; + for await (const task of queue) { + expect(executed.size).toBe(expectedCount); + await task(); + ++expectedCount; + expect(executed.has(outerPromises.length - expectedCount)).toBe(true); + + if (expectedCount === 1) { + abortController.abort(); + } + } + + const results: OperationStatus[] = await Promise.all(outerPromises); + // The last pushed operation had the highest priority, so is the only one executed before the abort call + expect(results.pop()).toBe(OperationStatus.Success); + for (const result of results) { + expect(result).toBe(OperationStatus.Aborted); + } + }); + + it('works with Async.forEachAsync', async () => { + const abortController: AbortController = new AbortController(); + + const queue: WorkQueue = new WorkQueue(abortController.signal); + + const executed: Set = new Set(); + + const outerPromises: Promise[] = []; + + for (let i: number = 0; i < 10; i++) { + outerPromises.push( + queue.pushAsync(async () => { + executed.add(i); + return OperationStatus.Success; + }, i) + ); + } + + let expectedCount: number = 0; + const queuePromise: Promise = Async.forEachAsync( + queue, + async (task) => { + expect(executed.size).toBe(expectedCount); + await task(); + ++expectedCount; + expect(executed.has(outerPromises.length - expectedCount)).toBe(true); + }, + { concurrency: 1 } + ); + + expect((await Promise.all(outerPromises)).every((status) => status === OperationStatus.Success)).toBe( + true + ); + abortController.abort(); + await queuePromise; + }); + + it('works concurrently with Async.forEachAsync', async () => { + const abortController: AbortController = new AbortController(); + + const queue: WorkQueue = new WorkQueue(abortController.signal); + + let running: number = 0; + let maxRunning: number = 0; + + const array: number[] = [1, 2, 3, 4, 5, 6, 7, 8]; + + const fn: () => Promise = jest.fn(async () => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + return OperationStatus.Success; + }); + const outerPromises: Promise[] = array.map((index) => queue.pushAsync(fn, 0)); + + const queuePromise: Promise = Async.forEachAsync(queue, (task) => task(), { concurrency: 3 }); + expect((await Promise.all(outerPromises)).every((status) => status === OperationStatus.Success)).toBe( + true + ); + + abortController.abort(); + await queuePromise; + + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(3); + }); +}); diff --git a/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap b/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap new file mode 100644 index 00000000000..166654439b9 --- /dev/null +++ b/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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`] = `""`; diff --git a/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap b/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap new file mode 100644 index 00000000000..8b2f076390a --- /dev/null +++ b/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`calculateCriticalPathLength reports circularities 1`] = ` +"A cyclic dependency was encountered: + c + -> b + -> c" +`; + +exports[`calculateCriticalPathLength sets the critical path 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, + "d": 4, + "e": 5, + "f": 6, + "g": 13, +} +`; + +exports[`calculateCriticalPathLengths sets the critical path 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, + "d": 4, + "e": 5, + "f": 6, + "g": 13, +} +`; + +exports[`calculateShortestPath returns the shortest path: long 1`] = ` +Array [ + "a", + "b", + "c", + "d", + "e", + "f", +] +`; + +exports[`calculateShortestPath returns the shortest path: with multiple shortcuts (circular) 1`] = ` +Array [ + "a", + "c", + "f", + "a", +] +`; + +exports[`calculateShortestPath returns the shortest path: with multiple shortcuts 1`] = ` +Array [ + "a", + "c", + "f", +] +`; + +exports[`calculateShortestPath returns the shortest path: with shortcut 1`] = ` +Array [ + "a", + "c", + "d", + "e", + "f", +] +`; diff --git a/libraries/operation-graph/src/test/calculateCriticalPath.test.ts b/libraries/operation-graph/src/test/calculateCriticalPath.test.ts new file mode 100644 index 00000000000..bc45ffb6cea --- /dev/null +++ b/libraries/operation-graph/src/test/calculateCriticalPath.test.ts @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + calculateShortestPath, + calculateCriticalPathLength, + calculateCriticalPathLengths, + type ISortableOperation +} from '../calculateCriticalPath'; + +interface ITestOperation extends ISortableOperation { + // Nothing added, just need an interface to solve the infinite expansion. +} + +function createGraph( + edges: Iterable<[start: string, end: string]>, + weights?: Iterable<[name: string, weight: number]> +): Map { + const nodes: Map = new Map(); + if (weights) { + for (const [name, weight] of weights) { + nodes.set(name, { + name, + weight, + consumers: new Set() + }); + } + } + + function getOrCreateNode(name: string): ITestOperation { + let node: ITestOperation | undefined = nodes.get(name); + if (!node) { + node = { + name, + weight: 1, + consumers: new Set() + }; + nodes.set(name, node); + } + return node; + } + + for (const [start, end] of edges) { + const startNode: ITestOperation = getOrCreateNode(start); + const endNode: ITestOperation = getOrCreateNode(end); + endNode.consumers.add(startNode); + } + + return nodes; +} + +describe(calculateShortestPath.name, () => { + it('returns the shortest path', () => { + const graph: Map = createGraph([ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'], + ['d', 'e'], + ['e', 'f'] + ]); + + const result1: ITestOperation[] = calculateShortestPath(graph.get('a')!, graph.get('f')!); + expect(result1.map((x) => x.name)).toMatchSnapshot('long'); + + graph.get('c')!.consumers.add(graph.get('a')!); + + const result2: ITestOperation[] = calculateShortestPath(graph.get('a')!, graph.get('f')!); + expect(result2.map((x) => x.name)).toMatchSnapshot('with shortcut'); + + graph.get('f')!.consumers.add(graph.get('c')!); + + const result3: ITestOperation[] = calculateShortestPath(graph.get('a')!, graph.get('f')!); + expect(result3.map((x) => x.name)).toMatchSnapshot('with multiple shortcuts'); + + graph.get('a')!.consumers.add(graph.get('f')!); + + const result4: ITestOperation[] = calculateShortestPath(graph.get('a')!, graph.get('a')!); + expect(result4.map((x) => x.name)).toMatchSnapshot('with multiple shortcuts (circular)'); + }); +}); + +describe(calculateCriticalPathLength.name, () => { + it('sets the critical path', () => { + const graph1: Map = createGraph( + [ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'], + ['d', 'e'], + ['e', 'f'], + ['c', 'g'] + ], + Object.entries({ + a: 1, + b: 1, + c: 1, + d: 1, + e: 1, + f: 1, + g: 10 + }) + ); + + const lengths: Record = {}; + + for (const [name, node] of graph1) { + const criticalPathLength: number = calculateCriticalPathLength(node, new Set()); + lengths[name] = criticalPathLength; + } + expect(lengths).toMatchSnapshot(); + }); + + it('reports circularities', () => { + const graph1: Map = createGraph([ + ['a', 'b'], + ['b', 'c'], + ['c', 'b'], + ['c', 'd'], + ['d', 'e'] + ]); + + expect(() => { + calculateCriticalPathLength(graph1.get('e')!, new Set()); + }).toThrowErrorMatchingSnapshot(); + }); +}); + +describe(calculateCriticalPathLengths.name, () => { + it('sets the critical path', () => { + const graph1: Map = createGraph( + [ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'], + ['d', 'e'], + ['e', 'f'], + ['c', 'g'] + ], + Object.entries({ + a: 1, + b: 1, + c: 1, + d: 1, + e: 1, + f: 1, + g: 10 + }) + ); + + calculateCriticalPathLengths(graph1.values()); + + const lengths: Record = {}; + + for (const [name, node] of graph1) { + lengths[name] = node.criticalPathLength; + } + expect(lengths).toMatchSnapshot(); + }); +}); diff --git a/libraries/operation-graph/tsconfig.json b/libraries/operation-graph/tsconfig.json new file mode 100644 index 00000000000..9f4aaf6de01 --- /dev/null +++ b/libraries/operation-graph/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + // 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"] + } +} diff --git a/libraries/package-deps-hash/.eslintrc.js b/libraries/package-deps-hash/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/libraries/package-deps-hash/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/package-deps-hash/.npmignore b/libraries/package-deps-hash/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/package-deps-hash/.npmignore +++ b/libraries/package-deps-hash/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/package-deps-hash/CHANGELOG.json b/libraries/package-deps-hash/CHANGELOG.json index c626b55c0b3..70850b56fa6 100644 --- a/libraries/package-deps-hash/CHANGELOG.json +++ b/libraries/package-deps-hash/CHANGELOG.json @@ -1,6 +1,7121 @@ { "name": "@rushstack/package-deps-hash", "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "4.3.0", + "tag": "@rushstack/package-deps-hash_v4.3.0", + "date": "Thu, 12 Dec 2024 01:37:09 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new optional parameter `filterPath` to `getRepoStateAsync` that limits the scope of the git query to only the specified subpaths. This can significantly improve the performance of the function when only part of the full repo data is necessary." + } + ] + } + }, + { + "version": "4.2.11", + "tag": "@rushstack/package-deps-hash_v4.2.11", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "4.2.10", + "tag": "@rushstack/package-deps-hash_v4.2.10", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "4.2.9", + "tag": "@rushstack/package-deps-hash_v4.2.9", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "4.2.8", + "tag": "@rushstack/package-deps-hash_v4.2.8", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "4.2.7", + "tag": "@rushstack/package-deps-hash_v4.2.7", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "4.2.6", + "tag": "@rushstack/package-deps-hash_v4.2.6", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "4.2.5", + "tag": "@rushstack/package-deps-hash_v4.2.5", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "4.2.4", + "tag": "@rushstack/package-deps-hash_v4.2.4", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "4.2.3", + "tag": "@rushstack/package-deps-hash_v4.2.3", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "4.2.2", + "tag": "@rushstack/package-deps-hash_v4.2.2", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "4.2.1", + "tag": "@rushstack/package-deps-hash_v4.2.1", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "4.2.0", + "tag": "@rushstack/package-deps-hash_v4.2.0", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "minor": [ + { + "comment": "Expose `hashFilesAsync` API. This serves a similar role as `getGitHashForFiles` but is asynchronous and allows for the file names to be provided as an async iterable." + } + ] + } + }, + { + "version": "4.1.68", + "tag": "@rushstack/package-deps-hash_v4.1.68", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "4.1.67", + "tag": "@rushstack/package-deps-hash_v4.1.67", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "4.1.66", + "tag": "@rushstack/package-deps-hash_v4.1.66", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "4.1.65", + "tag": "@rushstack/package-deps-hash_v4.1.65", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "4.1.64", + "tag": "@rushstack/package-deps-hash_v4.1.64", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "4.1.63", + "tag": "@rushstack/package-deps-hash_v4.1.63", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "4.1.62", + "tag": "@rushstack/package-deps-hash_v4.1.62", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "4.1.61", + "tag": "@rushstack/package-deps-hash_v4.1.61", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "4.1.60", + "tag": "@rushstack/package-deps-hash_v4.1.60", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "4.1.59", + "tag": "@rushstack/package-deps-hash_v4.1.59", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "4.1.58", + "tag": "@rushstack/package-deps-hash_v4.1.58", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "4.1.57", + "tag": "@rushstack/package-deps-hash_v4.1.57", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "4.1.56", + "tag": "@rushstack/package-deps-hash_v4.1.56", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "4.1.55", + "tag": "@rushstack/package-deps-hash_v4.1.55", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "4.1.54", + "tag": "@rushstack/package-deps-hash_v4.1.54", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "4.1.53", + "tag": "@rushstack/package-deps-hash_v4.1.53", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "4.1.52", + "tag": "@rushstack/package-deps-hash_v4.1.52", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "4.1.51", + "tag": "@rushstack/package-deps-hash_v4.1.51", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "4.1.50", + "tag": "@rushstack/package-deps-hash_v4.1.50", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "4.1.49", + "tag": "@rushstack/package-deps-hash_v4.1.49", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "patch": [ + { + "comment": "Add a newline to an error message" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "4.1.48", + "tag": "@rushstack/package-deps-hash_v4.1.48", + "date": "Fri, 17 May 2024 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where an incomplete repo state analysis was sometimes returned, especially on WSL. See https://github.com/microsoft/rushstack/pull/4711 for details." + } + ] + } + }, + { + "version": "4.1.47", + "tag": "@rushstack/package-deps-hash_v4.1.47", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "4.1.46", + "tag": "@rushstack/package-deps-hash_v4.1.46", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "4.1.45", + "tag": "@rushstack/package-deps-hash_v4.1.45", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "4.1.44", + "tag": "@rushstack/package-deps-hash_v4.1.44", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "4.1.43", + "tag": "@rushstack/package-deps-hash_v4.1.43", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "4.1.42", + "tag": "@rushstack/package-deps-hash_v4.1.42", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "4.1.41", + "tag": "@rushstack/package-deps-hash_v4.1.41", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "4.1.40", + "tag": "@rushstack/package-deps-hash_v4.1.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "4.1.39", + "tag": "@rushstack/package-deps-hash_v4.1.39", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "4.1.38", + "tag": "@rushstack/package-deps-hash_v4.1.38", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "4.1.37", + "tag": "@rushstack/package-deps-hash_v4.1.37", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "4.1.36", + "tag": "@rushstack/package-deps-hash_v4.1.36", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "4.1.35", + "tag": "@rushstack/package-deps-hash_v4.1.35", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "4.1.34", + "tag": "@rushstack/package-deps-hash_v4.1.34", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "4.1.33", + "tag": "@rushstack/package-deps-hash_v4.1.33", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "4.1.32", + "tag": "@rushstack/package-deps-hash_v4.1.32", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "4.1.31", + "tag": "@rushstack/package-deps-hash_v4.1.31", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "4.1.30", + "tag": "@rushstack/package-deps-hash_v4.1.30", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "4.1.29", + "tag": "@rushstack/package-deps-hash_v4.1.29", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "4.1.28", + "tag": "@rushstack/package-deps-hash_v4.1.28", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "4.1.27", + "tag": "@rushstack/package-deps-hash_v4.1.27", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "4.1.26", + "tag": "@rushstack/package-deps-hash_v4.1.26", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a formatting issue with the LICENSE." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "4.1.25", + "tag": "@rushstack/package-deps-hash_v4.1.25", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "4.1.24", + "tag": "@rushstack/package-deps-hash_v4.1.24", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "4.1.23", + "tag": "@rushstack/package-deps-hash_v4.1.23", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "4.1.22", + "tag": "@rushstack/package-deps-hash_v4.1.22", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "4.1.21", + "tag": "@rushstack/package-deps-hash_v4.1.21", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "4.1.20", + "tag": "@rushstack/package-deps-hash_v4.1.20", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "4.1.19", + "tag": "@rushstack/package-deps-hash_v4.1.19", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "4.1.18", + "tag": "@rushstack/package-deps-hash_v4.1.18", + "date": "Thu, 18 Jan 2024 01:08:53 GMT", + "comments": { + "patch": [ + { + "comment": "Handle an edge case in `getRepoState` wherein it tries to asynchronously pipe data to `git hash-object` but the subprocess has already exited." + } + ] + } + }, + { + "version": "4.1.17", + "tag": "@rushstack/package-deps-hash_v4.1.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "4.1.16", + "tag": "@rushstack/package-deps-hash_v4.1.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + } + ] + } + }, + { + "version": "4.1.15", + "tag": "@rushstack/package-deps-hash_v4.1.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "4.1.14", + "tag": "@rushstack/package-deps-hash_v4.1.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + } + ] + } + }, + { + "version": "4.1.13", + "tag": "@rushstack/package-deps-hash_v4.1.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "4.1.12", + "tag": "@rushstack/package-deps-hash_v4.1.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "4.1.11", + "tag": "@rushstack/package-deps-hash_v4.1.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "4.1.10", + "tag": "@rushstack/package-deps-hash_v4.1.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "4.1.9", + "tag": "@rushstack/package-deps-hash_v4.1.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "4.1.8", + "tag": "@rushstack/package-deps-hash_v4.1.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "4.1.7", + "tag": "@rushstack/package-deps-hash_v4.1.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + } + ] + } + }, + { + "version": "4.1.6", + "tag": "@rushstack/package-deps-hash_v4.1.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "4.1.5", + "tag": "@rushstack/package-deps-hash_v4.1.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "4.1.4", + "tag": "@rushstack/package-deps-hash_v4.1.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + } + ] + } + }, + { + "version": "4.1.3", + "tag": "@rushstack/package-deps-hash_v4.1.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "4.1.2", + "tag": "@rushstack/package-deps-hash_v4.1.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "4.1.1", + "tag": "@rushstack/package-deps-hash_v4.1.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "4.1.0", + "tag": "@rushstack/package-deps-hash_v4.1.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + } + ] + } + }, + { + "version": "4.0.44", + "tag": "@rushstack/package-deps-hash_v4.0.44", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + } + ] + } + }, + { + "version": "4.0.43", + "tag": "@rushstack/package-deps-hash_v4.0.43", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "4.0.42", + "tag": "@rushstack/package-deps-hash_v4.0.42", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "4.0.41", + "tag": "@rushstack/package-deps-hash_v4.0.41", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "4.0.40", + "tag": "@rushstack/package-deps-hash_v4.0.40", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + } + ] + } + }, + { + "version": "4.0.39", + "tag": "@rushstack/package-deps-hash_v4.0.39", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "4.0.38", + "tag": "@rushstack/package-deps-hash_v4.0.38", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "4.0.37", + "tag": "@rushstack/package-deps-hash_v4.0.37", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "4.0.36", + "tag": "@rushstack/package-deps-hash_v4.0.36", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "4.0.35", + "tag": "@rushstack/package-deps-hash_v4.0.35", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "4.0.34", + "tag": "@rushstack/package-deps-hash_v4.0.34", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + } + ] + } + }, + { + "version": "4.0.33", + "tag": "@rushstack/package-deps-hash_v4.0.33", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "4.0.32", + "tag": "@rushstack/package-deps-hash_v4.0.32", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "4.0.31", + "tag": "@rushstack/package-deps-hash_v4.0.31", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + } + ] + } + }, + { + "version": "4.0.30", + "tag": "@rushstack/package-deps-hash_v4.0.30", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "4.0.29", + "tag": "@rushstack/package-deps-hash_v4.0.29", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "4.0.28", + "tag": "@rushstack/package-deps-hash_v4.0.28", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "4.0.27", + "tag": "@rushstack/package-deps-hash_v4.0.27", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "4.0.26", + "tag": "@rushstack/package-deps-hash_v4.0.26", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "4.0.25", + "tag": "@rushstack/package-deps-hash_v4.0.25", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "4.0.24", + "tag": "@rushstack/package-deps-hash_v4.0.24", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "4.0.23", + "tag": "@rushstack/package-deps-hash_v4.0.23", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "4.0.22", + "tag": "@rushstack/package-deps-hash_v4.0.22", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + } + ] + } + }, + { + "version": "4.0.21", + "tag": "@rushstack/package-deps-hash_v4.0.21", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "4.0.20", + "tag": "@rushstack/package-deps-hash_v4.0.20", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "4.0.19", + "tag": "@rushstack/package-deps-hash_v4.0.19", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "4.0.18", + "tag": "@rushstack/package-deps-hash_v4.0.18", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + } + ] + } + }, + { + "version": "4.0.17", + "tag": "@rushstack/package-deps-hash_v4.0.17", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + } + ] + } + }, + { + "version": "4.0.16", + "tag": "@rushstack/package-deps-hash_v4.0.16", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + } + ] + } + }, + { + "version": "4.0.15", + "tag": "@rushstack/package-deps-hash_v4.0.15", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "4.0.14", + "tag": "@rushstack/package-deps-hash_v4.0.14", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + } + ] + } + }, + { + "version": "4.0.13", + "tag": "@rushstack/package-deps-hash_v4.0.13", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + } + ] + } + }, + { + "version": "4.0.12", + "tag": "@rushstack/package-deps-hash_v4.0.12", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + } + ] + } + }, + { + "version": "4.0.11", + "tag": "@rushstack/package-deps-hash_v4.0.11", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "4.0.10", + "tag": "@rushstack/package-deps-hash_v4.0.10", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "4.0.9", + "tag": "@rushstack/package-deps-hash_v4.0.9", + "date": "Fri, 24 Feb 2023 01:24:17 GMT", + "comments": { + "patch": [ + { + "comment": "Prevent network calls or maintenance tasks during local Git operations." + } + ] + } + }, + { + "version": "4.0.8", + "tag": "@rushstack/package-deps-hash_v4.0.8", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + } + ] + } + }, + { + "version": "4.0.7", + "tag": "@rushstack/package-deps-hash_v4.0.7", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + } + ] + } + }, + { + "version": "4.0.6", + "tag": "@rushstack/package-deps-hash_v4.0.6", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + } + ] + } + }, + { + "version": "4.0.5", + "tag": "@rushstack/package-deps-hash_v4.0.5", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + } + ] + } + }, + { + "version": "4.0.4", + "tag": "@rushstack/package-deps-hash_v4.0.4", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "4.0.3", + "tag": "@rushstack/package-deps-hash_v4.0.3", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@rushstack/package-deps-hash_v4.0.2", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@rushstack/package-deps-hash_v4.0.1", + "date": "Tue, 24 Jan 2023 00:16:54 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bug in parseGitHashObject when 0 hashes are expected." + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@rushstack/package-deps-hash_v4.0.0", + "date": "Fri, 20 Jan 2023 16:19:50 GMT", + "comments": { + "major": [ + { + "comment": "Add getRepoStateAsync API for faster repository state calculation. Remove synchronous getRepoState API." + } + ] + } + }, + { + "version": "3.2.67", + "tag": "@rushstack/package-deps-hash_v3.2.67", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "3.2.66", + "tag": "@rushstack/package-deps-hash_v3.2.66", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "3.2.65", + "tag": "@rushstack/package-deps-hash_v3.2.65", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + } + ] + } + }, + { + "version": "3.2.64", + "tag": "@rushstack/package-deps-hash_v3.2.64", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "3.2.63", + "tag": "@rushstack/package-deps-hash_v3.2.63", + "date": "Fri, 18 Nov 2022 04:02:22 GMT", + "comments": { + "patch": [ + { + "comment": "Refactor the logic of getting file hashes under git submodule paths" + } + ] + } + }, + { + "version": "3.2.62", + "tag": "@rushstack/package-deps-hash_v3.2.62", + "date": "Tue, 15 Nov 2022 18:43:30 GMT", + "comments": { + "patch": [ + { + "comment": "Get file hashes under git submodule paths when analyzing repo state" + } + ] + } + }, + { + "version": "3.2.61", + "tag": "@rushstack/package-deps-hash_v3.2.61", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "3.2.60", + "tag": "@rushstack/package-deps-hash_v3.2.60", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "3.2.59", + "tag": "@rushstack/package-deps-hash_v3.2.59", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "3.2.58", + "tag": "@rushstack/package-deps-hash_v3.2.58", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "3.2.57", + "tag": "@rushstack/package-deps-hash_v3.2.57", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "3.2.56", + "tag": "@rushstack/package-deps-hash_v3.2.56", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + } + ] + } + }, + { + "version": "3.2.55", + "tag": "@rushstack/package-deps-hash_v3.2.55", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "3.2.54", + "tag": "@rushstack/package-deps-hash_v3.2.54", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + } + ] + } + }, + { + "version": "3.2.53", + "tag": "@rushstack/package-deps-hash_v3.2.53", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + } + ] + } + }, + { + "version": "3.2.52", + "tag": "@rushstack/package-deps-hash_v3.2.52", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "3.2.51", + "tag": "@rushstack/package-deps-hash_v3.2.51", + "date": "Fri, 23 Sep 2022 02:54:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix getRepoState when the current working directory is not in the Git repository." + } + ] + } + }, + { + "version": "3.2.50", + "tag": "@rushstack/package-deps-hash_v3.2.50", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + } + ] + } + }, + { + "version": "3.2.49", + "tag": "@rushstack/package-deps-hash_v3.2.49", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + } + ] + } + }, + { + "version": "3.2.48", + "tag": "@rushstack/package-deps-hash_v3.2.48", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "3.2.47", + "tag": "@rushstack/package-deps-hash_v3.2.47", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "3.2.46", + "tag": "@rushstack/package-deps-hash_v3.2.46", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "3.2.45", + "tag": "@rushstack/package-deps-hash_v3.2.45", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "3.2.44", + "tag": "@rushstack/package-deps-hash_v3.2.44", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "3.2.43", + "tag": "@rushstack/package-deps-hash_v3.2.43", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + } + ] + } + }, + { + "version": "3.2.42", + "tag": "@rushstack/package-deps-hash_v3.2.42", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + } + ] + } + }, + { + "version": "3.2.41", + "tag": "@rushstack/package-deps-hash_v3.2.41", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + } + ] + } + }, + { + "version": "3.2.40", + "tag": "@rushstack/package-deps-hash_v3.2.40", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "3.2.39", + "tag": "@rushstack/package-deps-hash_v3.2.39", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "3.2.38", + "tag": "@rushstack/package-deps-hash_v3.2.38", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + } + ] + } + }, + { + "version": "3.2.37", + "tag": "@rushstack/package-deps-hash_v3.2.37", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + } + ] + } + }, + { + "version": "3.2.36", + "tag": "@rushstack/package-deps-hash_v3.2.36", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "3.2.35", + "tag": "@rushstack/package-deps-hash_v3.2.35", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "3.2.34", + "tag": "@rushstack/package-deps-hash_v3.2.34", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "3.2.33", + "tag": "@rushstack/package-deps-hash_v3.2.33", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "3.2.32", + "tag": "@rushstack/package-deps-hash_v3.2.32", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "3.2.31", + "tag": "@rushstack/package-deps-hash_v3.2.31", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "3.2.30", + "tag": "@rushstack/package-deps-hash_v3.2.30", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + } + ] + } + }, + { + "version": "3.2.29", + "tag": "@rushstack/package-deps-hash_v3.2.29", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + } + ] + } + }, + { + "version": "3.2.28", + "tag": "@rushstack/package-deps-hash_v3.2.28", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + } + ] + } + }, + { + "version": "3.2.27", + "tag": "@rushstack/package-deps-hash_v3.2.27", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "3.2.26", + "tag": "@rushstack/package-deps-hash_v3.2.26", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + } + ] + } + }, + { + "version": "3.2.25", + "tag": "@rushstack/package-deps-hash_v3.2.25", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "3.2.24", + "tag": "@rushstack/package-deps-hash_v3.2.24", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "3.2.23", + "tag": "@rushstack/package-deps-hash_v3.2.23", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + } + ] + } + }, + { + "version": "3.2.22", + "tag": "@rushstack/package-deps-hash_v3.2.22", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + } + ] + } + }, + { + "version": "3.2.21", + "tag": "@rushstack/package-deps-hash_v3.2.21", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "3.2.20", + "tag": "@rushstack/package-deps-hash_v3.2.20", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "3.2.19", + "tag": "@rushstack/package-deps-hash_v3.2.19", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "3.2.18", + "tag": "@rushstack/package-deps-hash_v3.2.18", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "3.2.17", + "tag": "@rushstack/package-deps-hash_v3.2.17", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + } + ] + } + }, + { + "version": "3.2.16", + "tag": "@rushstack/package-deps-hash_v3.2.16", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "3.2.15", + "tag": "@rushstack/package-deps-hash_v3.2.15", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "3.2.14", + "tag": "@rushstack/package-deps-hash_v3.2.14", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + } + ] + } + }, + { + "version": "3.2.13", + "tag": "@rushstack/package-deps-hash_v3.2.13", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + } + ] + } + }, + { + "version": "3.2.12", + "tag": "@rushstack/package-deps-hash_v3.2.12", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "3.2.11", + "tag": "@rushstack/package-deps-hash_v3.2.11", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "3.2.10", + "tag": "@rushstack/package-deps-hash_v3.2.10", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "3.2.9", + "tag": "@rushstack/package-deps-hash_v3.2.9", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "3.2.8", + "tag": "@rushstack/package-deps-hash_v3.2.8", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + } + ] + } + }, + { + "version": "3.2.7", + "tag": "@rushstack/package-deps-hash_v3.2.7", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "3.2.6", + "tag": "@rushstack/package-deps-hash_v3.2.6", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "3.2.5", + "tag": "@rushstack/package-deps-hash_v3.2.5", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "3.2.4", + "tag": "@rushstack/package-deps-hash_v3.2.4", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "3.2.3", + "tag": "@rushstack/package-deps-hash_v3.2.3", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@rushstack/package-deps-hash_v3.2.2", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "3.2.1", + "tag": "@rushstack/package-deps-hash_v3.2.1", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "3.2.0", + "tag": "@rushstack/package-deps-hash_v3.2.0", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Fix incorrect parsing in `parseGitStatus`." + } + ], + "minor": [ + { + "comment": "Remove `--merge-base` from `getRepoChanges` and document the need to manually acquire merge-base commit if comparing against a separate branch." + }, + { + "comment": "Reduce minimum Git version to 2.20." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "3.1.13", + "tag": "@rushstack/package-deps-hash_v3.1.13", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "3.1.12", + "tag": "@rushstack/package-deps-hash_v3.1.12", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + } + ] + } + }, + { + "version": "3.1.11", + "tag": "@rushstack/package-deps-hash_v3.1.11", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + } + ] + } + }, + { + "version": "3.1.10", + "tag": "@rushstack/package-deps-hash_v3.1.10", + "date": "Thu, 16 Dec 2021 05:38:20 GMT", + "comments": { + "patch": [ + { + "comment": "Provide a more useful error message if the git version is too old." + } + ] + } + }, + { + "version": "3.1.9", + "tag": "@rushstack/package-deps-hash_v3.1.9", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "3.1.8", + "tag": "@rushstack/package-deps-hash_v3.1.8", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + } + ] + } + }, + { + "version": "3.1.7", + "tag": "@rushstack/package-deps-hash_v3.1.7", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "patch": [ + { + "comment": "When detecting changes relative to a target branch, use the merge base between the target branch and the current commit as the comparison ref." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "3.1.6", + "tag": "@rushstack/package-deps-hash_v3.1.6", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@rushstack/package-deps-hash_v3.1.5", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "3.1.4", + "tag": "@rushstack/package-deps-hash_v3.1.4", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + } + ] + } + }, + { + "version": "3.1.3", + "tag": "@rushstack/package-deps-hash_v3.1.3", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + } + ] + } + }, + { + "version": "3.1.2", + "tag": "@rushstack/package-deps-hash_v3.1.2", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@rushstack/package-deps-hash_v3.1.1", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@rushstack/package-deps-hash_v3.1.0", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "minor": [ + { + "comment": "Added repo-level state extraction and change listing functions to support having rush.json in a subfolder of the repository." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + } + ] + } + }, + { + "version": "3.0.86", + "tag": "@rushstack/package-deps-hash_v3.0.86", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + } + ] + } + }, + { + "version": "3.0.85", + "tag": "@rushstack/package-deps-hash_v3.0.85", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "3.0.84", + "tag": "@rushstack/package-deps-hash_v3.0.84", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + } + ] + } + }, + { + "version": "3.0.83", + "tag": "@rushstack/package-deps-hash_v3.0.83", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + } + ] + } + }, + { + "version": "3.0.82", + "tag": "@rushstack/package-deps-hash_v3.0.82", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "3.0.81", + "tag": "@rushstack/package-deps-hash_v3.0.81", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + } + ] + } + }, + { + "version": "3.0.80", + "tag": "@rushstack/package-deps-hash_v3.0.80", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "3.0.79", + "tag": "@rushstack/package-deps-hash_v3.0.79", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + } + ] + } + }, + { + "version": "3.0.78", + "tag": "@rushstack/package-deps-hash_v3.0.78", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "3.0.77", + "tag": "@rushstack/package-deps-hash_v3.0.77", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "3.0.76", + "tag": "@rushstack/package-deps-hash_v3.0.76", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + } + ] + } + }, + { + "version": "3.0.75", + "tag": "@rushstack/package-deps-hash_v3.0.75", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "3.0.74", + "tag": "@rushstack/package-deps-hash_v3.0.74", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + } + ] + } + }, + { + "version": "3.0.73", + "tag": "@rushstack/package-deps-hash_v3.0.73", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + } + ] + } + }, + { + "version": "3.0.72", + "tag": "@rushstack/package-deps-hash_v3.0.72", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "3.0.71", + "tag": "@rushstack/package-deps-hash_v3.0.71", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "3.0.70", + "tag": "@rushstack/package-deps-hash_v3.0.70", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "3.0.69", + "tag": "@rushstack/package-deps-hash_v3.0.69", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + } + ] + } + }, + { + "version": "3.0.68", + "tag": "@rushstack/package-deps-hash_v3.0.68", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + } + ] + } + }, + { + "version": "3.0.67", + "tag": "@rushstack/package-deps-hash_v3.0.67", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "3.0.66", + "tag": "@rushstack/package-deps-hash_v3.0.66", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "3.0.65", + "tag": "@rushstack/package-deps-hash_v3.0.65", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "3.0.64", + "tag": "@rushstack/package-deps-hash_v3.0.64", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "3.0.63", + "tag": "@rushstack/package-deps-hash_v3.0.63", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "3.0.62", + "tag": "@rushstack/package-deps-hash_v3.0.62", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "3.0.61", + "tag": "@rushstack/package-deps-hash_v3.0.61", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "3.0.60", + "tag": "@rushstack/package-deps-hash_v3.0.60", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "3.0.59", + "tag": "@rushstack/package-deps-hash_v3.0.59", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "3.0.58", + "tag": "@rushstack/package-deps-hash_v3.0.58", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "3.0.57", + "tag": "@rushstack/package-deps-hash_v3.0.57", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "3.0.56", + "tag": "@rushstack/package-deps-hash_v3.0.56", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + } + ] + } + }, + { + "version": "3.0.55", + "tag": "@rushstack/package-deps-hash_v3.0.55", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "3.0.54", + "tag": "@rushstack/package-deps-hash_v3.0.54", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "3.0.53", + "tag": "@rushstack/package-deps-hash_v3.0.53", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "3.0.52", + "tag": "@rushstack/package-deps-hash_v3.0.52", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + } + ] + } + }, + { + "version": "3.0.51", + "tag": "@rushstack/package-deps-hash_v3.0.51", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "3.0.50", + "tag": "@rushstack/package-deps-hash_v3.0.50", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "3.0.49", + "tag": "@rushstack/package-deps-hash_v3.0.49", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "3.0.48", + "tag": "@rushstack/package-deps-hash_v3.0.48", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "3.0.47", + "tag": "@rushstack/package-deps-hash_v3.0.47", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "3.0.46", + "tag": "@rushstack/package-deps-hash_v3.0.46", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "3.0.45", + "tag": "@rushstack/package-deps-hash_v3.0.45", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "3.0.44", + "tag": "@rushstack/package-deps-hash_v3.0.44", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "3.0.43", + "tag": "@rushstack/package-deps-hash_v3.0.43", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "3.0.42", + "tag": "@rushstack/package-deps-hash_v3.0.42", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "3.0.41", + "tag": "@rushstack/package-deps-hash_v3.0.41", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "3.0.40", + "tag": "@rushstack/package-deps-hash_v3.0.40", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "3.0.39", + "tag": "@rushstack/package-deps-hash_v3.0.39", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "3.0.38", + "tag": "@rushstack/package-deps-hash_v3.0.38", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "3.0.37", + "tag": "@rushstack/package-deps-hash_v3.0.37", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + } + ] + } + }, + { + "version": "3.0.36", + "tag": "@rushstack/package-deps-hash_v3.0.36", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "3.0.35", + "tag": "@rushstack/package-deps-hash_v3.0.35", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "3.0.34", + "tag": "@rushstack/package-deps-hash_v3.0.34", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "3.0.33", + "tag": "@rushstack/package-deps-hash_v3.0.33", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "3.0.32", + "tag": "@rushstack/package-deps-hash_v3.0.32", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "3.0.31", + "tag": "@rushstack/package-deps-hash_v3.0.31", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "3.0.30", + "tag": "@rushstack/package-deps-hash_v3.0.30", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + } + ] + } + }, + { + "version": "3.0.29", + "tag": "@rushstack/package-deps-hash_v3.0.29", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "3.0.28", + "tag": "@rushstack/package-deps-hash_v3.0.28", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "3.0.27", + "tag": "@rushstack/package-deps-hash_v3.0.27", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + } + ] + } + }, + { + "version": "3.0.26", + "tag": "@rushstack/package-deps-hash_v3.0.26", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "3.0.25", + "tag": "@rushstack/package-deps-hash_v3.0.25", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "3.0.24", + "tag": "@rushstack/package-deps-hash_v3.0.24", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "3.0.23", + "tag": "@rushstack/package-deps-hash_v3.0.23", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "3.0.22", + "tag": "@rushstack/package-deps-hash_v3.0.22", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "3.0.21", + "tag": "@rushstack/package-deps-hash_v3.0.21", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "3.0.20", + "tag": "@rushstack/package-deps-hash_v3.0.20", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "3.0.19", + "tag": "@rushstack/package-deps-hash_v3.0.19", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + } + ] + } + }, + { + "version": "3.0.18", + "tag": "@rushstack/package-deps-hash_v3.0.18", + "date": "Thu, 08 Apr 2021 20:41:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "3.0.17", + "tag": "@rushstack/package-deps-hash_v3.0.17", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "3.0.16", + "tag": "@rushstack/package-deps-hash_v3.0.16", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "3.0.15", + "tag": "@rushstack/package-deps-hash_v3.0.15", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + } + ] + } + }, + { + "version": "3.0.14", + "tag": "@rushstack/package-deps-hash_v3.0.14", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "3.0.13", + "tag": "@rushstack/package-deps-hash_v3.0.13", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "3.0.12", + "tag": "@rushstack/package-deps-hash_v3.0.12", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "3.0.11", + "tag": "@rushstack/package-deps-hash_v3.0.11", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "3.0.10", + "tag": "@rushstack/package-deps-hash_v3.0.10", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "3.0.9", + "tag": "@rushstack/package-deps-hash_v3.0.9", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "3.0.8", + "tag": "@rushstack/package-deps-hash_v3.0.8", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "3.0.7", + "tag": "@rushstack/package-deps-hash_v3.0.7", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "3.0.6", + "tag": "@rushstack/package-deps-hash_v3.0.6", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "3.0.5", + "tag": "@rushstack/package-deps-hash_v3.0.5", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + } + ] + } + }, + { + "version": "3.0.4", + "tag": "@rushstack/package-deps-hash_v3.0.4", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "3.0.3", + "tag": "@rushstack/package-deps-hash_v3.0.3", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "3.0.2", + "tag": "@rushstack/package-deps-hash_v3.0.2", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "3.0.1", + "tag": "@rushstack/package-deps-hash_v3.0.1", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@rushstack/package-deps-hash_v3.0.0", + "date": "Fri, 08 Jan 2021 05:24:33 GMT", + "comments": { + "minor": [ + { + "comment": "Allow the git binary path to be explicitly provided." + } + ], + "major": [ + { + "comment": "Refactor getPackageDeps to return a map." + } + ] + } + }, + { + "version": "2.4.110", + "tag": "@rushstack/package-deps-hash_v2.4.110", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "2.4.109", + "tag": "@rushstack/package-deps-hash_v2.4.109", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "2.4.108", + "tag": "@rushstack/package-deps-hash_v2.4.108", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + } + ] + } + }, + { + "version": "2.4.107", + "tag": "@rushstack/package-deps-hash_v2.4.107", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "2.4.106", + "tag": "@rushstack/package-deps-hash_v2.4.106", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "2.4.105", + "tag": "@rushstack/package-deps-hash_v2.4.105", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "2.4.104", + "tag": "@rushstack/package-deps-hash_v2.4.104", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "2.4.103", + "tag": "@rushstack/package-deps-hash_v2.4.103", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "2.4.102", + "tag": "@rushstack/package-deps-hash_v2.4.102", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "2.4.101", + "tag": "@rushstack/package-deps-hash_v2.4.101", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "2.4.100", + "tag": "@rushstack/package-deps-hash_v2.4.100", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "2.4.99", + "tag": "@rushstack/package-deps-hash_v2.4.99", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "2.4.98", + "tag": "@rushstack/package-deps-hash_v2.4.98", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + } + ] + } + }, + { + "version": "2.4.97", + "tag": "@rushstack/package-deps-hash_v2.4.97", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + } + ] + } + }, + { + "version": "2.4.96", + "tag": "@rushstack/package-deps-hash_v2.4.96", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "2.4.95", + "tag": "@rushstack/package-deps-hash_v2.4.95", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "2.4.94", + "tag": "@rushstack/package-deps-hash_v2.4.94", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "2.4.93", + "tag": "@rushstack/package-deps-hash_v2.4.93", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "2.4.92", + "tag": "@rushstack/package-deps-hash_v2.4.92", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "2.4.91", + "tag": "@rushstack/package-deps-hash_v2.4.91", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + } + ] + } + }, + { + "version": "2.4.90", + "tag": "@rushstack/package-deps-hash_v2.4.90", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + } + ] + } + }, + { + "version": "2.4.89", + "tag": "@rushstack/package-deps-hash_v2.4.89", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "2.4.88", + "tag": "@rushstack/package-deps-hash_v2.4.88", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "2.4.87", + "tag": "@rushstack/package-deps-hash_v2.4.87", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + } + ] + } + }, + { + "version": "2.4.86", + "tag": "@rushstack/package-deps-hash_v2.4.86", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + } + ] + } + }, + { + "version": "2.4.85", + "tag": "@rushstack/package-deps-hash_v2.4.85", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "2.4.84", + "tag": "@rushstack/package-deps-hash_v2.4.84", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "2.4.83", + "tag": "@rushstack/package-deps-hash_v2.4.83", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "2.4.82", + "tag": "@rushstack/package-deps-hash_v2.4.82", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "2.4.81", + "tag": "@rushstack/package-deps-hash_v2.4.81", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "2.4.80", + "tag": "@rushstack/package-deps-hash_v2.4.80", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "2.4.79", + "tag": "@rushstack/package-deps-hash_v2.4.79", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "2.4.78", + "tag": "@rushstack/package-deps-hash_v2.4.78", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "2.4.77", + "tag": "@rushstack/package-deps-hash_v2.4.77", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "2.4.76", + "tag": "@rushstack/package-deps-hash_v2.4.76", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + } + ] + } + }, + { + "version": "2.4.75", + "tag": "@rushstack/package-deps-hash_v2.4.75", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + } + ] + } + }, + { + "version": "2.4.74", + "tag": "@rushstack/package-deps-hash_v2.4.74", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "2.4.73", + "tag": "@rushstack/package-deps-hash_v2.4.73", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "2.4.72", + "tag": "@rushstack/package-deps-hash_v2.4.72", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "2.4.71", + "tag": "@rushstack/package-deps-hash_v2.4.71", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "2.4.70", + "tag": "@rushstack/package-deps-hash_v2.4.70", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + } + ] + } + }, + { + "version": "2.4.69", + "tag": "@rushstack/package-deps-hash_v2.4.69", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + } + ] + } + }, + { + "version": "2.4.68", + "tag": "@rushstack/package-deps-hash_v2.4.68", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "2.4.67", + "tag": "@rushstack/package-deps-hash_v2.4.67", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "2.4.66", + "tag": "@rushstack/package-deps-hash_v2.4.66", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "2.4.65", + "tag": "@rushstack/package-deps-hash_v2.4.65", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "2.4.64", + "tag": "@rushstack/package-deps-hash_v2.4.64", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "2.4.63", + "tag": "@rushstack/package-deps-hash_v2.4.63", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "2.4.62", + "tag": "@rushstack/package-deps-hash_v2.4.62", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "2.4.61", + "tag": "@rushstack/package-deps-hash_v2.4.61", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "2.4.60", + "tag": "@rushstack/package-deps-hash_v2.4.60", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "2.4.59", + "tag": "@rushstack/package-deps-hash_v2.4.59", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "2.4.58", + "tag": "@rushstack/package-deps-hash_v2.4.58", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "2.4.57", + "tag": "@rushstack/package-deps-hash_v2.4.57", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "2.4.56", + "tag": "@rushstack/package-deps-hash_v2.4.56", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "2.4.55", + "tag": "@rushstack/package-deps-hash_v2.4.55", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "2.4.54", + "tag": "@rushstack/package-deps-hash_v2.4.54", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "2.4.53", + "tag": "@rushstack/package-deps-hash_v2.4.53", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "2.4.52", + "tag": "@rushstack/package-deps-hash_v2.4.52", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "2.4.51", + "tag": "@rushstack/package-deps-hash_v2.4.51", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "2.4.50", + "tag": "@rushstack/package-deps-hash_v2.4.50", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "2.4.49", + "tag": "@rushstack/package-deps-hash_v2.4.49", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "2.4.48", + "tag": "@rushstack/package-deps-hash_v2.4.48", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "2.4.47", + "tag": "@rushstack/package-deps-hash_v2.4.47", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "patch": [ + { + "comment": "Do not attempt to hash files that are deleted in the working tree." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "2.4.46", + "tag": "@rushstack/package-deps-hash_v2.4.46", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "2.4.45", + "tag": "@rushstack/package-deps-hash_v2.4.45", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "2.4.44", + "tag": "@rushstack/package-deps-hash_v2.4.44", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "2.4.43", + "tag": "@rushstack/package-deps-hash_v2.4.43", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "2.4.42", + "tag": "@rushstack/package-deps-hash_v2.4.42", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "2.4.41", + "tag": "@rushstack/package-deps-hash_v2.4.41", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "2.4.40", + "tag": "@rushstack/package-deps-hash_v2.4.40", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "2.4.39", + "tag": "@rushstack/package-deps-hash_v2.4.39", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "2.4.38", + "tag": "@rushstack/package-deps-hash_v2.4.38", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "2.4.37", + "tag": "@rushstack/package-deps-hash_v2.4.37", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "2.4.36", + "tag": "@rushstack/package-deps-hash_v2.4.36", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "2.4.35", + "tag": "@rushstack/package-deps-hash_v2.4.35", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "2.4.34", + "tag": "@rushstack/package-deps-hash_v2.4.34", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + } + ] + } + }, + { + "version": "2.4.33", + "tag": "@rushstack/package-deps-hash_v2.4.33", + "date": "Mon, 20 Jul 2020 06:52:33 GMT", + "comments": { + "patch": [ + { + "comment": "Fix hashing when a filename contains a space, a special character (ex. \", \\), or a unicode character, and fix git hash-object call when long filenames are provided" + } + ] + } + }, + { + "version": "2.4.32", + "tag": "@rushstack/package-deps-hash_v2.4.32", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + } + ] + } + }, + { + "version": "2.4.31", + "tag": "@rushstack/package-deps-hash_v2.4.31", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "2.4.30", + "tag": "@rushstack/package-deps-hash_v2.4.30", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "2.4.29", + "tag": "@rushstack/package-deps-hash_v2.4.29", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "2.4.28", + "tag": "@rushstack/package-deps-hash_v2.4.28", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "2.4.27", + "tag": "@rushstack/package-deps-hash_v2.4.27", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "2.4.26", + "tag": "@rushstack/package-deps-hash_v2.4.26", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "2.4.25", + "tag": "@rushstack/package-deps-hash_v2.4.25", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "2.4.24", + "tag": "@rushstack/package-deps-hash_v2.4.24", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "2.4.23", + "tag": "@rushstack/package-deps-hash_v2.4.23", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + } + ] + } + }, + { + "version": "2.4.22", + "tag": "@rushstack/package-deps-hash_v2.4.22", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "2.4.21", + "tag": "@rushstack/package-deps-hash_v2.4.21", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + } + ] + } + }, + { + "version": "2.4.20", + "tag": "@rushstack/package-deps-hash_v2.4.20", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + } + ] + } + }, + { + "version": "2.4.19", + "tag": "@rushstack/package-deps-hash_v2.4.19", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "2.4.18", + "tag": "@rushstack/package-deps-hash_v2.4.18", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + } + ] + } + }, + { + "version": "2.4.17", + "tag": "@rushstack/package-deps-hash_v2.4.17", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + } + ] + } + }, + { + "version": "2.4.16", + "tag": "@rushstack/package-deps-hash_v2.4.16", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + } + ] + } + }, + { + "version": "2.4.15", + "tag": "@rushstack/package-deps-hash_v2.4.15", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + } + ] + } + }, + { + "version": "2.4.14", + "tag": "@rushstack/package-deps-hash_v2.4.14", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "2.4.13", + "tag": "@rushstack/package-deps-hash_v2.4.13", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "2.4.12", + "tag": "@rushstack/package-deps-hash_v2.4.12", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "2.4.11", + "tag": "@rushstack/package-deps-hash_v2.4.11", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "2.4.10", + "tag": "@rushstack/package-deps-hash_v2.4.10", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "2.4.9", + "tag": "@rushstack/package-deps-hash_v2.4.9", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "2.4.8", + "tag": "@rushstack/package-deps-hash_v2.4.8", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "2.4.7", + "tag": "@rushstack/package-deps-hash_v2.4.7", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "2.4.6", "tag": "@rushstack/package-deps-hash_v2.4.6", diff --git a/libraries/package-deps-hash/CHANGELOG.md b/libraries/package-deps-hash/CHANGELOG.md index 55728aa1ed4..299bc2596f9 100644 --- a/libraries/package-deps-hash/CHANGELOG.md +++ b/libraries/package-deps-hash/CHANGELOG.md @@ -1,11 +1,2296 @@ # Change Log - @rushstack/package-deps-hash -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 4.3.0 +Thu, 12 Dec 2024 01:37:09 GMT + +### Minor changes + +- Add a new optional parameter `filterPath` to `getRepoStateAsync` that limits the scope of the git query to only the specified subpaths. This can significantly improve the performance of the function when only part of the full repo data is necessary. + +## 4.2.11 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 4.2.10 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 4.2.9 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 4.2.8 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 4.2.7 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 4.2.6 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 4.2.5 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 4.2.4 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 4.2.3 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 4.2.2 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 4.2.1 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 4.2.0 +Sat, 21 Sep 2024 00:10:27 GMT + +### Minor changes + +- Expose `hashFilesAsync` API. This serves a similar role as `getGitHashForFiles` but is asynchronous and allows for the file names to be provided as an async iterable. + +## 4.1.68 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 4.1.67 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 4.1.66 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 4.1.65 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 4.1.64 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 4.1.63 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 4.1.62 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 4.1.61 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 4.1.60 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 4.1.59 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 4.1.58 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 4.1.57 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 4.1.56 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 4.1.55 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 4.1.54 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 4.1.53 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 4.1.52 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 4.1.51 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 4.1.50 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 4.1.49 +Thu, 23 May 2024 02:26:56 GMT + +### Patches + +- Add a newline to an error message + +## 4.1.48 +Fri, 17 May 2024 00:10:40 GMT + +### Patches + +- Fix an issue where an incomplete repo state analysis was sometimes returned, especially on WSL. See https://github.com/microsoft/rushstack/pull/4711 for details. + +## 4.1.47 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 4.1.46 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 4.1.45 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 4.1.44 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 4.1.43 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 4.1.42 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 4.1.41 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 4.1.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 4.1.39 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 4.1.38 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 4.1.37 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 4.1.36 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 4.1.35 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 4.1.34 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 4.1.33 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 4.1.32 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 4.1.31 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 4.1.30 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 4.1.29 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 4.1.28 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 4.1.27 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 4.1.26 +Mon, 19 Feb 2024 21:54:27 GMT + +### Patches + +- Fix a formatting issue with the LICENSE. + +## 4.1.25 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 4.1.24 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 4.1.23 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 4.1.22 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 4.1.21 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 4.1.20 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 4.1.19 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 4.1.18 +Thu, 18 Jan 2024 01:08:53 GMT + +### Patches + +- Handle an edge case in `getRepoState` wherein it tries to asynchronously pipe data to `git hash-object` but the subprocess has already exited. + +## 4.1.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 4.1.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 4.1.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 4.1.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 4.1.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 4.1.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 4.1.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 4.1.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 4.1.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 4.1.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 4.1.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 4.1.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 4.1.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 4.1.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 4.1.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 4.1.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 4.1.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 4.1.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 4.0.44 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 4.0.43 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 4.0.42 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 4.0.41 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 4.0.40 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 4.0.39 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 4.0.38 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 4.0.37 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 4.0.36 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 4.0.35 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 4.0.34 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 4.0.33 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 4.0.32 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 4.0.31 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 4.0.30 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 4.0.29 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 4.0.28 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 4.0.27 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 4.0.26 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 4.0.25 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 4.0.24 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 4.0.23 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 4.0.22 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 4.0.21 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 4.0.20 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 4.0.19 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 4.0.18 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 4.0.17 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 4.0.16 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 4.0.15 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 4.0.14 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 4.0.13 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 4.0.12 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 4.0.11 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 4.0.10 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 4.0.9 +Fri, 24 Feb 2023 01:24:17 GMT + +### Patches + +- Prevent network calls or maintenance tasks during local Git operations. + +## 4.0.8 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 4.0.7 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 4.0.6 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 4.0.5 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 4.0.4 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 4.0.3 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 4.0.2 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 4.0.1 +Tue, 24 Jan 2023 00:16:54 GMT + +### Patches + +- Fix bug in parseGitHashObject when 0 hashes are expected. + +## 4.0.0 +Fri, 20 Jan 2023 16:19:50 GMT + +### Breaking changes + +- Add getRepoStateAsync API for faster repository state calculation. Remove synchronous getRepoState API. + +## 3.2.67 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 3.2.66 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 3.2.65 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 3.2.64 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 3.2.63 +Fri, 18 Nov 2022 04:02:22 GMT + +### Patches + +- Refactor the logic of getting file hashes under git submodule paths + +## 3.2.62 +Tue, 15 Nov 2022 18:43:30 GMT + +### Patches + +- Get file hashes under git submodule paths when analyzing repo state + +## 3.2.61 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 3.2.60 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 3.2.59 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 3.2.58 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 3.2.57 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 3.2.56 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 3.2.55 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 3.2.54 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 3.2.53 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 3.2.52 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 3.2.51 +Fri, 23 Sep 2022 02:54:22 GMT + +### Patches + +- Fix getRepoState when the current working directory is not in the Git repository. + +## 3.2.50 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 3.2.49 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 3.2.48 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 3.2.47 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 3.2.46 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 3.2.45 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 3.2.44 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 3.2.43 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 3.2.42 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 3.2.41 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 3.2.40 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 3.2.39 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 3.2.38 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 3.2.37 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 3.2.36 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 3.2.35 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 3.2.34 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 3.2.33 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 3.2.32 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 3.2.31 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 3.2.30 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 3.2.29 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 3.2.28 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 3.2.27 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 3.2.26 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 3.2.25 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 3.2.24 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 3.2.23 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 3.2.22 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 3.2.21 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 3.2.20 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 3.2.19 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 3.2.18 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 3.2.17 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 3.2.16 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 3.2.15 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 3.2.14 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 3.2.13 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 3.2.12 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 3.2.11 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 3.2.10 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 3.2.9 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 3.2.8 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 3.2.7 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 3.2.6 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 3.2.5 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 3.2.4 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 3.2.3 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 3.2.2 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 3.2.1 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 3.2.0 +Fri, 21 Jan 2022 01:10:41 GMT + +### Minor changes + +- Remove `--merge-base` from `getRepoChanges` and document the need to manually acquire merge-base commit if comparing against a separate branch. +- Reduce minimum Git version to 2.20. + +### Patches + +- Fix incorrect parsing in `parseGitStatus`. + +## 3.1.13 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 3.1.12 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 3.1.11 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 3.1.10 +Thu, 16 Dec 2021 05:38:20 GMT + +### Patches + +- Provide a more useful error message if the git version is too old. + +## 3.1.9 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 3.1.8 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 3.1.7 +Thu, 09 Dec 2021 00:21:54 GMT + +### Patches + +- When detecting changes relative to a target branch, use the merge base between the target branch and the current commit as the comparison ref. + +## 3.1.6 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 3.1.5 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 3.1.4 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 3.1.3 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 3.1.2 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 3.1.1 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 3.1.0 +Sat, 06 Nov 2021 00:09:13 GMT + +### Minor changes + +- Added repo-level state extraction and change listing functions to support having rush.json in a subfolder of the repository. + +## 3.0.86 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 3.0.85 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 3.0.84 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 3.0.83 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 3.0.82 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 3.0.81 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 3.0.80 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 3.0.79 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 3.0.78 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 3.0.77 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 3.0.76 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 3.0.75 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 3.0.74 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 3.0.73 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 3.0.72 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 3.0.71 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 3.0.70 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 3.0.69 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 3.0.68 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 3.0.67 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 3.0.66 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 3.0.65 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 3.0.64 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 3.0.63 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 3.0.62 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 3.0.61 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 3.0.60 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 3.0.59 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 3.0.58 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 3.0.57 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 3.0.56 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 3.0.55 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 3.0.54 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 3.0.53 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 3.0.52 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 3.0.51 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 3.0.50 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 3.0.49 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 3.0.48 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 3.0.47 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 3.0.46 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 3.0.45 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 3.0.44 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 3.0.43 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 3.0.42 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 3.0.41 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 3.0.40 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 3.0.39 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 3.0.38 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 3.0.37 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 3.0.36 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 3.0.35 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 3.0.34 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 3.0.33 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 3.0.32 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 3.0.31 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 3.0.30 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 3.0.29 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 3.0.28 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 3.0.27 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 3.0.26 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 3.0.25 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 3.0.24 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 3.0.23 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 3.0.22 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 3.0.21 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 3.0.20 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 3.0.19 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 3.0.18 +Thu, 08 Apr 2021 20:41:55 GMT + +_Version update only_ + +## 3.0.17 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 3.0.16 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 3.0.15 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 3.0.14 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 3.0.13 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 3.0.12 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 3.0.11 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 3.0.10 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 3.0.9 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 3.0.8 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 3.0.7 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 3.0.6 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 3.0.5 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 3.0.4 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 3.0.3 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 3.0.2 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 3.0.1 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 3.0.0 +Fri, 08 Jan 2021 05:24:33 GMT + +### Breaking changes + +- Refactor getPackageDeps to return a map. + +### Minor changes + +- Allow the git binary path to be explicitly provided. + +## 2.4.110 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 2.4.109 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 2.4.108 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 2.4.107 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 2.4.106 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 2.4.105 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 2.4.104 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 2.4.103 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 2.4.102 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 2.4.101 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 2.4.100 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 2.4.99 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 2.4.98 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 2.4.97 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 2.4.96 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 2.4.95 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 2.4.94 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 2.4.93 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 2.4.92 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 2.4.91 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 2.4.90 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 2.4.89 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 2.4.88 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 2.4.87 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 2.4.86 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 2.4.85 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 2.4.84 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 2.4.83 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 2.4.82 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 2.4.81 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 2.4.80 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 2.4.79 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 2.4.78 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 2.4.77 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 2.4.76 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 2.4.75 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 2.4.74 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 2.4.73 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 2.4.72 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 2.4.71 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 2.4.70 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 2.4.69 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 2.4.68 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 2.4.67 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 2.4.66 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 2.4.65 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 2.4.64 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 2.4.63 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 2.4.62 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 2.4.61 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 2.4.60 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 2.4.59 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 2.4.58 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 2.4.57 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 2.4.56 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 2.4.55 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 2.4.54 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 2.4.53 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 2.4.52 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 2.4.51 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 2.4.50 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 2.4.49 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 2.4.48 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 2.4.47 +Tue, 25 Aug 2020 00:10:12 GMT + +### Patches + +- Do not attempt to hash files that are deleted in the working tree. + +## 2.4.46 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 2.4.45 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 2.4.44 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 2.4.43 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 2.4.42 +Thu, 20 Aug 2020 15:13:52 GMT + +_Version update only_ + +## 2.4.41 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 2.4.40 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 2.4.39 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 2.4.38 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 2.4.37 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 2.4.36 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 2.4.35 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 2.4.34 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 2.4.33 +Mon, 20 Jul 2020 06:52:33 GMT + +### Patches + +- Fix hashing when a filename contains a space, a special character (ex. ", \), or a unicode character, and fix git hash-object call when long filenames are provided + +## 2.4.32 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 2.4.31 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 2.4.30 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 2.4.29 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 2.4.28 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 2.4.27 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 2.4.26 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 2.4.25 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 2.4.24 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 2.4.23 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 2.4.22 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 2.4.21 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 2.4.20 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 2.4.19 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 2.4.18 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 2.4.17 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 2.4.16 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 2.4.15 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 2.4.14 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 2.4.13 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 2.4.12 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 2.4.11 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 2.4.10 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 2.4.9 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 2.4.8 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 2.4.7 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 2.4.6 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 2.4.5 Tue, 17 Mar 2020 23:55:58 GMT @@ -17,22 +2302,22 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 2.4.4 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 2.4.3 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 2.4.2 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 2.4.1 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 2.4.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -44,92 +2329,92 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 2.3.19 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 2.3.18 Tue, 14 Jan 2020 01:34:16 GMT -*Version update only* +_Version update only_ ## 2.3.17 Sat, 11 Jan 2020 05:18:24 GMT -*Version update only* +_Version update only_ ## 2.3.16 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 2.3.15 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 2.3.14 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 2.3.13 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 2.3.12 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 2.3.11 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 2.3.10 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 2.3.9 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 2.3.8 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 2.3.7 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 2.3.6 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 2.3.5 Fri, 25 Oct 2019 15:08:54 GMT -*Version update only* +_Version update only_ ## 2.3.4 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 2.3.3 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 2.3.2 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 2.3.1 Thu, 10 Oct 2019 23:28:59 GMT @@ -148,12 +2433,12 @@ Tue, 08 Oct 2019 22:38:39 GMT ## 2.2.183 Sun, 06 Oct 2019 00:27:39 GMT -*Version update only* +_Version update only_ ## 2.2.182 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 2.2.181 Sun, 29 Sep 2019 23:56:29 GMT @@ -165,27 +2450,27 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 2.2.180 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 2.2.179 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 2.2.178 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 2.2.177 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 2.2.176 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 2.2.175 Tue, 10 Sep 2019 22:32:23 GMT @@ -197,517 +2482,517 @@ Tue, 10 Sep 2019 22:32:23 GMT ## 2.2.174 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 2.2.173 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 2.2.172 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 2.2.171 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 2.2.170 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 2.2.169 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 2.2.168 Thu, 08 Aug 2019 00:49:06 GMT -*Version update only* +_Version update only_ ## 2.2.167 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 2.2.166 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 2.2.165 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 2.2.164 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 2.2.163 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 2.2.162 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 2.2.161 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 2.2.160 Mon, 08 Jul 2019 19:12:18 GMT -*Version update only* +_Version update only_ ## 2.2.159 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 2.2.158 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 2.2.157 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 2.2.156 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 2.2.155 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 2.2.154 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 2.2.153 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 2.2.152 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 2.2.151 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 2.2.150 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 2.2.149 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 2.2.148 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 2.2.147 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 2.2.146 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 2.2.145 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 2.2.144 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 2.2.143 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 2.2.142 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 2.2.141 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 2.2.140 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 2.2.139 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 2.2.138 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 2.2.137 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 2.2.136 Tue, 26 Mar 2019 20:54:18 GMT -*Version update only* +_Version update only_ ## 2.2.135 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 2.2.134 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 2.2.133 Thu, 21 Mar 2019 01:15:33 GMT -*Version update only* +_Version update only_ ## 2.2.132 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 2.2.131 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 2.2.130 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 2.2.129 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 2.2.128 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 2.2.127 Mon, 11 Mar 2019 16:13:36 GMT -*Version update only* +_Version update only_ ## 2.2.126 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 2.2.125 Mon, 04 Mar 2019 17:13:20 GMT -*Version update only* +_Version update only_ ## 2.2.124 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 2.2.123 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 2.2.122 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 2.2.121 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 2.2.120 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 2.2.119 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 2.2.118 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 2.2.117 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 2.2.116 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 2.2.115 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 2.2.114 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 2.2.113 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 2.2.112 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 2.2.111 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 2.2.110 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 2.2.109 Fri, 07 Dec 2018 17:04:56 GMT -*Version update only* +_Version update only_ ## 2.2.108 Fri, 30 Nov 2018 23:34:58 GMT -*Version update only* +_Version update only_ ## 2.2.107 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 2.2.106 Thu, 29 Nov 2018 00:35:39 GMT -*Version update only* +_Version update only_ ## 2.2.105 Wed, 28 Nov 2018 19:29:53 GMT -*Version update only* +_Version update only_ ## 2.2.104 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 2.2.103 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 2.2.102 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 2.2.101 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 2.2.100 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 2.2.99 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 2.2.98 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 2.2.97 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 2.2.96 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 2.2.95 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 2.2.94 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 2.2.93 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 2.2.92 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 2.2.91 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 2.2.90 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 2.2.89 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 2.2.88 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 2.2.87 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 2.2.86 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 2.2.85 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 2.2.84 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 2.2.83 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 2.2.82 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 2.2.81 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 2.2.80 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 2.2.79 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 2.2.78 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 2.2.77 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 2.2.76 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 2.2.75 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 2.2.74 Thu, 20 Sep 2018 23:57:22 GMT -*Version update only* +_Version update only_ ## 2.2.73 Tue, 18 Sep 2018 21:04:56 GMT -*Version update only* +_Version update only_ ## 2.2.72 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 2.2.71 Thu, 06 Sep 2018 01:25:26 GMT @@ -719,37 +3004,37 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 2.2.70 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 2.2.69 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 2.2.68 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 2.2.67 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 2.2.66 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 2.2.65 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 2.2.64 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 2.2.63 Thu, 23 Aug 2018 18:18:53 GMT @@ -761,67 +3046,67 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 2.2.62 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 2.2.61 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 2.2.60 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 2.2.59 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 2.2.58 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 2.2.57 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 2.2.56 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 2.2.55 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 2.2.54 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 2.2.53 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 2.2.52 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 2.2.51 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 2.2.50 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 2.2.49 Wed, 11 Jul 2018 21:03:58 GMT @@ -833,107 +3118,107 @@ Wed, 11 Jul 2018 21:03:58 GMT ## 2.2.48 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 2.2.47 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 2.2.46 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 2.2.45 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 2.2.44 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 2.2.43 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 2.2.42 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 2.2.41 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 2.2.40 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 2.2.39 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 2.2.38 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 2.2.37 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 2.2.36 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 2.2.35 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 2.2.34 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 2.2.33 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 2.2.32 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 2.2.31 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 2.2.30 Mon, 02 Apr 2018 16:05:24 GMT -*Version update only* +_Version update only_ ## 2.2.29 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 2.2.28 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 2.2.27 Sun, 25 Mar 2018 01:26:19 GMT @@ -945,92 +3230,92 @@ Sun, 25 Mar 2018 01:26:19 GMT ## 2.2.26 Fri, 23 Mar 2018 00:34:53 GMT -*Version update only* +_Version update only_ ## 2.2.25 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 2.2.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 2.2.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 2.2.22 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 2.2.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 2.2.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 2.2.19 Mon, 12 Mar 2018 20:36:19 GMT -*Version update only* +_Version update only_ ## 2.2.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 2.2.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 2.2.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 2.2.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 2.2.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 2.2.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 2.2.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 2.2.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 2.2.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 2.2.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 2.2.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1042,12 +3327,12 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 2.2.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 2.2.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 2.2.5 Thu, 18 Jan 2018 03:23:46 GMT @@ -1059,22 +3344,22 @@ Thu, 18 Jan 2018 03:23:46 GMT ## 2.2.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 2.2.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 2.2.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 2.2.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 2.2.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1086,57 +3371,57 @@ Wed, 10 Jan 2018 20:40:01 GMT ## 2.1.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 2.1.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 2.1.11 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 2.1.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 2.1.9 Tue, 12 Dec 2017 03:33:27 GMT -*Version update only* +_Version update only_ ## 2.1.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 2.1.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 2.1.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 2.1.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 2.1.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 2.1.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 2.1.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -1148,7 +3433,7 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 2.1.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 2.1.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -1174,17 +3459,17 @@ Fri, 08 Sep 2017 01:28:04 GMT ## 2.0.8 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 2.0.7 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 2.0.6 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 2.0.5 Thu, 22 Jun 2017 01:03:47 GMT @@ -1224,5 +3509,5 @@ Mon, 30 Jan 2017 21:37:27 GMT ## 1.0.1 Fri, 13 Jan 2017 06:46:05 GMT -*Initial release* +_Initial release_ diff --git a/libraries/package-deps-hash/LICENSE b/libraries/package-deps-hash/LICENSE index 93142aec687..c47fca6439f 100644 --- a/libraries/package-deps-hash/LICENSE +++ b/libraries/package-deps-hash/LICENSE @@ -1,24 +1,24 @@ -@rushstack/package-deps-hash - -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 +@rushstack/package-deps-hash + +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/libraries/package-deps-hash/README.md b/libraries/package-deps-hash/README.md index 6ebfa5727be..5386749d7a5 100644 --- a/libraries/package-deps-hash/README.md +++ b/libraries/package-deps-hash/README.md @@ -29,4 +29,11 @@ if (_.isEqual(deps, existingDeps)) { } ``` -API documentation for this package: https://rushstack.io/pages/api/package-deps-hash/ +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/package-deps-hash/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/package-deps-hash/) + +`@rushstack/package-deps-hash` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/package-deps-hash/config/jest.config.json b/libraries/package-deps-hash/config/jest.config.json new file mode 100644 index 00000000000..dc083f44326 --- /dev/null +++ b/libraries/package-deps-hash/config/jest.config.json @@ -0,0 +1,5 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json", + // Tests in this package break isolation and so must run serially + "maxWorkers": 1 +} diff --git a/libraries/package-deps-hash/config/rig.json b/libraries/package-deps-hash/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/package-deps-hash/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/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/gulpfile.js b/libraries/package-deps-hash/gulpfile.js deleted file mode 100644 index 296eccbf8a6..00000000000 --- a/libraries/package-deps-hash/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/libraries/package-deps-hash/package.json b/libraries/package-deps-hash/package.json index 0a291fee675..1abf972bb49 100644 --- a/libraries/package-deps-hash/package.json +++ b/libraries/package-deps-hash/package.json @@ -1,29 +1,26 @@ { "name": "@rushstack/package-deps-hash", - "version": "2.4.6", + "version": "4.5.7", "description": "", "main": "lib/index.js", "typings": "dist/package-deps-hash.d.ts", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/package-deps-hash" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/package-deps-hash" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/eslint-config": "0.5.5", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "chai": "~3.5.0", - "gulp": "~4.0.2" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" }, "dependencies": { - "@rushstack/node-core-library": "3.19.5" + "@rushstack/node-core-library": "workspace:*" } } diff --git a/libraries/package-deps-hash/src/IPackageDeps.ts b/libraries/package-deps-hash/src/IPackageDeps.ts deleted file mode 100644 index 82c4bdef36e..00000000000 --- a/libraries/package-deps-hash/src/IPackageDeps.ts +++ /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. - -/** - * The data structure returned by {@link getPackageDeps}. - * @public - */ -export interface IPackageDeps { - /** - * The `key` is a source file path, relative to the package folder. The value is the Git hash. - */ - files: { [key: string]: string }; - - /** - * An optional field used to story command-line arguments for the build. - */ - arguments?: string; -} diff --git a/libraries/package-deps-hash/src/getPackageDeps.ts b/libraries/package-deps-hash/src/getPackageDeps.ts index c485d7ed4f9..a284af5600a 100644 --- a/libraries/package-deps-hash/src/getPackageDeps.ts +++ b/libraries/package-deps-hash/src/getPackageDeps.ts @@ -1,10 +1,50 @@ // 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 type * as child_process from 'node:child_process'; +import * as path from 'node:path'; + import { Executable } from '@rushstack/node-core-library'; -import { IPackageDeps } from './IPackageDeps'; +import { ensureGitMinimumVersion } from './getRepoState'; + +/** + * Parses a quoted filename sourced from the output of the "git status" command. + * + * Paths with non-standard characters will be enclosed with double-quotes, and non-standard + * characters will be backslash escaped (ex. double-quotes, non-ASCII characters). The + * escaped chars can be included in one of two ways: + * - backslash-escaped chars (ex. \") + * - octal encoded chars (ex. \347) + * + * See documentation: https://git-scm.com/docs/git-status + */ +export function parseGitFilename(filename: string): string { + // If there are no double-quotes around the string, then there are no escaped characters + // to decode, so just return + if (!filename.match(/^".+"$/)) { + return filename; + } + + // Need to hex encode '%' since we will be decoding the converted octal values from hex + filename = filename.replace(/%/g, '%25'); + // Replace all instances of octal literals with percent-encoded hex (ex. '\347\275\221' -> '%E7%BD%91'). + // This is done because the octal literals represent UTF-8 bytes, and by converting them to percent-encoded + // hex, we can use decodeURIComponent to get the Unicode chars. + filename = filename.replace(/(?:\\(\d{1,3}))/g, (match, ...[octalValue, index, source]) => { + // We need to make sure that the backslash is intended to escape the octal value. To do this, walk + // backwards from the match to ensure that it's already escaped. + const trailingBackslashes: RegExpMatchArray | null = (source as string) + .slice(0, index as number) + .match(/\\*$/); + return trailingBackslashes && trailingBackslashes.length > 0 && trailingBackslashes[0].length % 2 === 0 + ? `%${parseInt(octalValue, 8).toString(16)}` + : match; + }); + + // Finally, decode the filename and unescape the escaped UTF-8 chars + return JSON.parse(decodeURIComponent(filename)); +} /** * Parses the output of the "git ls-tree" command @@ -19,22 +59,21 @@ export function parseGitLsTree(output: string): Map { const gitRegex: RegExp = /([0-9]{6})\s(blob|commit)\s([a-f0-9]{40})\s*(.*)/; // Note: The output of git ls-tree uses \n newlines regardless of OS. - output.split('\n').forEach(line => { - + const outputLines: string[] = output.trim().split('\n'); + for (const line of outputLines) { if (line) { // Take everything after the "100644 blob", which is just the hash and filename const matches: RegExpMatchArray | null = line.match(gitRegex); if (matches && matches[3] && matches[4]) { const hash: string = matches[3]; - const filename: string = matches[4]; + const filename: string = parseGitFilename(matches[4]); changes.set(filename, hash); - } else { throw new Error(`Cannot parse git ls-tree input: "${line}"`); } } - }); + } } return changes; @@ -47,10 +86,10 @@ export function parseGitStatus(output: string, packagePath: string): Map = new Map(); /* - * Typically, output will look something like: - * M temp_modules/rush-package-deps-hash/package.json - * D package-deps-hash/src/index.ts - */ + * Typically, output will look something like: + * M temp_modules/rush-package-deps-hash/package.json + * D package-deps-hash/src/index.ts + */ // If there was an issue with `git ls-tree`, or there are no current changes, processOutputBlocks[1] // will be empty or undefined @@ -59,30 +98,38 @@ export function parseGitStatus(output: string, packagePath: string): Map { - /* - * changeType is in the format of "XY" where "X" is the status of the file in the index and "Y" is the status of - * the file in the working tree. Some example statuses: - * - 'D' == deletion - * - 'M' == modification - * - 'A' == addition - * - '??' == untracked - * - 'R' == rename - * - 'RM' == rename with modifications - * filenames == path to the file, or files in the case of files that have been renamed - */ - const [changeType, ...filenames]: string[] = line.trim().split(' ').filter((linePart) => !!linePart); - - if (changeType && filenames && filenames.length > 0) { - // We always care about the last filename in the filenames array. In the case of non-rename changes, - // the filenames array only contains one item. In the case of rename changes, the last item in the - // array is the path to the file in the working tree, which is the only one that we care about. - changes.set(filenames[filenames.length - 1], changeType); - } - }); + const outputLines: string[] = output.trim().split('\n'); + for (const line of outputLines) { + /* + * changeType is in the format of "XY" where "X" is the status of the file in the index and "Y" is the status of + * the file in the working tree. Some example statuses: + * - 'D' == deletion + * - 'M' == modification + * - 'A' == addition + * - '??' == untracked + * - 'R' == rename + * - 'RM' == rename with modifications + * - '[MARC]D' == deleted in work tree + * Full list of examples: https://git-scm.com/docs/git-status#_short_format + */ + const match: RegExpMatchArray | null = line.match(/("(\\"|[^"])+")|(\S+\s*)/g); + + if (match && match.length > 1) { + const [changeType, ...filenameMatches] = match; + + // We always care about the last filename in the filenames array. In the case of non-rename changes, + // the filenames array only contains one file, so we can join all segments that were split on spaces. + // In the case of rename changes, the last item in the array is the path to the file in the working tree, + // which is the only one that we care about. It is also surrounded by double-quotes if spaces are + // included, so no need to worry about joining different segments + let lastFilename: string = changeType.startsWith('R') + ? filenameMatches[filenameMatches.length - 1] + : filenameMatches.join(''); + lastFilename = parseGitFilename(lastFilename); + + changes.set(lastFilename, changeType.trimRight()); + } + } return changes; } @@ -92,17 +139,25 @@ export function parseGitStatus(output: string, packagePath: string): Map { +export function getGitHashForFiles( + filesToHash: string[], + packagePath: string, + gitPath?: string +): Map { const changes: Map = new Map(); if (filesToHash.length) { + // Use --stdin-paths arg to pass the list of files to git in order to avoid issues with + // command length const result: child_process.SpawnSyncReturns = Executable.spawnSync( - 'git', - ['hash-object', ...filesToHash], - { currentWorkingDirectory: packagePath } + gitPath || 'git', + ['hash-object', '--stdin-paths'], + { input: filesToHash.map((x) => path.resolve(packagePath, x)).join('\n') } ); if (result.status !== 0) { + ensureGitMinimumVersion(gitPath); + throw new Error(`git hash-object exited with status ${result.status}: ${result.stderr}`); } @@ -112,7 +167,9 @@ export function getGitHashForFiles(filesToHash: string[], packagePath: string): const hashes: string[] = hashStdout.split('\n'); if (hashes.length !== filesToHash.length) { - throw new Error(`Passed ${filesToHash.length} file paths to Git to hash, but received ${hashes.length} hashes.`); + throw new Error( + `Passed ${filesToHash.length} file paths to Git to hash, but received ${hashes.length} hashes.` + ); } for (let i: number = 0; i < hashes.length; i++) { @@ -120,7 +177,6 @@ export function getGitHashForFiles(filesToHash: string[], packagePath: string): const filePath: string = filesToHash[i]; changes.set(filePath, hash); } - } return changes; @@ -129,16 +185,18 @@ export function getGitHashForFiles(filesToHash: string[], packagePath: string): /** * Executes "git ls-tree" in a folder */ -export function gitLsTree(path: string): string { +export function gitLsTree(cwdPath: string, gitPath?: string): string { const result: child_process.SpawnSyncReturns = Executable.spawnSync( - 'git', + gitPath || 'git', ['ls-tree', 'HEAD', '-r'], { - currentWorkingDirectory: path + currentWorkingDirectory: cwdPath } ); if (result.status !== 0) { + ensureGitMinimumVersion(gitPath); + throw new Error(`git ls-tree exited with status ${result.status}: ${result.stderr}`); } @@ -148,16 +206,26 @@ export function gitLsTree(path: string): string { /** * Executes "git status" in a folder */ -export function gitStatus(path: string): string { +export function gitStatus(cwdPath: string, gitPath?: string): string { + /** + * -s - Short format. Will be printed as 'XY PATH' or 'XY ORIG_PATH -> PATH'. Paths with non-standard + * characters will be escaped using double-quotes, and non-standard characters will be backslash + * escaped (ex. spaces, tabs, double-quotes) + * -u - Untracked files are included + * + * See documentation here: https://git-scm.com/docs/git-status + */ const result: child_process.SpawnSyncReturns = Executable.spawnSync( - 'git', + gitPath || 'git', ['status', '-s', '-u', '.'], { - currentWorkingDirectory: path + currentWorkingDirectory: cwdPath } ); if (result.status !== 0) { + ensureGitMinimumVersion(gitPath); + throw new Error(`git status exited with status ${result.status}: ${result.stderr}`); } @@ -174,45 +242,47 @@ export function gitStatus(path: string): string { * * @public */ -export function getPackageDeps(packagePath: string = process.cwd(), excludedPaths?: string[]): IPackageDeps { - const excludedHashes: { [key: string]: boolean } = {}; - - if (excludedPaths) { - excludedPaths.forEach((path) => { excludedHashes[path] = true }); - } - - const changes: IPackageDeps = { - files: {} - }; - - const gitLsOutput: string = gitLsTree(packagePath); +export function getPackageDeps( + packagePath: string = process.cwd(), + excludedPaths?: string[], + gitPath?: string +): Map { + const gitLsOutput: string = gitLsTree(packagePath, gitPath); // Add all the checked in hashes - parseGitLsTree(gitLsOutput).forEach((hash: string, filename: string) => { - if (!excludedHashes[filename]) { - changes.files[filename] = hash; + const result: Map = parseGitLsTree(gitLsOutput); + + // Remove excluded paths + if (excludedPaths) { + for (const excludedPath of excludedPaths) { + result.delete(excludedPath); } - }); + } // Update the checked in hashes with the current repo status - const gitStatusOutput: string = gitStatus(packagePath); - const currentlyChangedFiles: Map = - parseGitStatus(gitStatusOutput, packagePath); - + const gitStatusOutput: string = gitStatus(packagePath, gitPath); + const currentlyChangedFiles: Map = parseGitStatus(gitStatusOutput, packagePath); const filesToHash: string[] = []; - currentlyChangedFiles.forEach((changeType: string, filename: string) => { - if (changeType === 'D') { - delete changes.files[filename]; + const excludedPathSet: Set = new Set(excludedPaths); + for (const [filename, changeType] of currentlyChangedFiles) { + // See comments inside parseGitStatus() for more information + if (changeType === 'D' || (changeType.length === 2 && changeType.charAt(1) === 'D')) { + result.delete(filename); } else { - if (!excludedHashes[filename]) { + if (!excludedPathSet.has(filename)) { filesToHash.push(filename); } } - }); + } - getGitHashForFiles(filesToHash, packagePath).forEach((hash: string, filename: string) => { - changes.files[filename] = hash; - }); + const currentlyChangedFileHashes: Map = getGitHashForFiles( + filesToHash, + packagePath, + gitPath + ); + for (const [filename, hash] of currentlyChangedFileHashes) { + result.set(filename, hash); + } - return changes; + return result; } diff --git a/libraries/package-deps-hash/src/getRepoState.ts b/libraries/package-deps-hash/src/getRepoState.ts new file mode 100644 index 00000000000..db21877b78d --- /dev/null +++ b/libraries/package-deps-hash/src/getRepoState.ts @@ -0,0 +1,616 @@ +// 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 'node:child_process'; +import { once } from 'node:events'; +import { Readable, pipeline } from 'node:stream'; + +import { Executable, FileSystem, type IExecutableSpawnOptions } from '@rushstack/node-core-library'; + +export interface IGitVersion { + major: number; + minor: number; + patch: number; +} + +const MINIMUM_GIT_VERSION: IGitVersion = { + major: 2, + minor: 20, + patch: 0 +}; + +const STANDARD_GIT_OPTIONS: readonly string[] = [ + // Don't request any optional file locks + '--no-optional-locks', + // Ensure that commands don't run automatic maintenance, since performance of the command itself is paramount + '-c', + 'maintenance.auto=false' +]; + +interface IGitTreeState { + files: Map; // type "blob" + submodules: Map; // type "commit" +} + +/** + * Parses the output of the "git ls-tree -r -z" command + * @internal + */ +export function parseGitLsTree(output: string): IGitTreeState { + const files: Map = new Map(); + const submodules: Map = new Map(); + + // Parse the output + // With the -z modifier, paths are delimited by nulls + // A line looks like: + // \t\0 + // 100644 blob a300ccb0b36bd2c85ef18e3c619a2c747f95959e\ttools/prettier-git/prettier-git.js\0 + + let last: number = 0; + let index: number = output.indexOf('\0', last); + while (index >= 0) { + const item: string = output.slice(last, index); + + const tabIndex: number = item.indexOf('\t'); + const filePath: string = item.slice(tabIndex + 1); + + // 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); + + switch (type) { + case 'commit': { + submodules.set(filePath, hash); + break; + } + case 'blob': + default: { + files.set(filePath, hash); + break; + } + } + + last = index + 1; + index = output.indexOf('\0', last); + } + + return { + files, + submodules + }; +} + +/** + * Parses the output of `git hash-object` + * yields [filePath, hash] pairs. + * @internal + */ +export function* parseGitHashObject( + output: string, + filePaths: ReadonlyArray +): IterableIterator<[string, string]> { + const expected: number = filePaths.length; + if (expected === 0) { + return; + } + + output = output.trim(); + + let last: number = 0; + let i: number = 0; + let index: number = output.indexOf('\n', last); + for (; i < expected && index > 0; i++) { + const hash: string = output.slice(last, index); + yield [filePaths[i], hash]; + last = index + 1; + index = output.indexOf('\n', last); + } + + // Handle last line. Will be non-empty to due trim() call. + if (index < 0) { + const hash: string = output.slice(last); + yield [filePaths[i], hash]; + i++; + } + + if (i !== expected) { + throw new Error(`Expected ${expected} hashes from "git hash-object" but received ${i}`); + } +} + +/** + * Information about the changes to a file. + * @beta + */ +export interface IFileDiffStatus { + mode: string; + oldhash: string; + newhash: string; + status: 'A' | 'D' | 'M'; +} + +/** + * Parses the output of `git diff-index --color=never --no-renames --no-commit-id -z -- + * Returns a map of file path to diff + * @internal + */ +export function parseGitDiffIndex(output: string): Map { + const result: Map = new Map(); + + // Parse the output + // With the -z modifier, paths are delimited by nulls + // A line looks like: + // : \0\0 + // :100644 100644 a300ccb0b36bd2c85ef18e3c619a2c747f95959e 0000000000000000000000000000000000000000 M\0tools/prettier-git/prettier-git.js\0 + + let last: number = 0; + let index: number = output.indexOf('\0', last); + while (index >= 0) { + const header: string = output.slice(last, index); + const status: IFileDiffStatus['status'] = header.slice(-1) as IFileDiffStatus['status']; + + last = index + 1; + index = output.indexOf('\0', last); + const filePath: string = output.slice(last, index); + + // We passed --no-renames above, so a rename will be a delete of the old location and an add at the new. + // The newHash will be all zeros if the file is deleted, or a hash if it exists + const mode: string = header.slice(8, 14); + const oldhash: string = header.slice(-83, -43); + const newhash: string = header.slice(-42, -2); + result.set(filePath, { + mode, + oldhash, + newhash, + status + }); + + last = index + 1; + index = output.indexOf('\0', last); + } + + return result; +} + +/** + * Parses the output of `git status -z -u` to extract the set of files that have changed since HEAD. + * + * @param output - The raw output from Git + * @returns a map of file path to if it exists + * @internal + */ +export function parseGitStatus(output: string): Map { + const result: Map = new Map(); + + // Parse the output + // With the -z modifier, paths are delimited by nulls + // A line looks like: + // XY \0 + // M tools/prettier-git/prettier-git.js\0 + + let startOfLine: number = 0; + let eolIndex: number = output.indexOf('\0', startOfLine); + while (eolIndex >= 0) { + // We passed --no-renames above, so a rename will be a delete of the old location and an add at the new. + // charAt(startOfLine) is the index status, charAt(startOfLine + 1) is the working tree status + const workingTreeStatus: string = output.charAt(startOfLine + 1); + // Deleted in working tree, or not modified in working tree and deleted in index + const deleted: boolean = + workingTreeStatus === 'D' || (workingTreeStatus === ' ' && output.charAt(startOfLine) === 'D'); + + const filePath: string = output.slice(startOfLine + 3, eolIndex); + result.set(filePath, !deleted); + + startOfLine = eolIndex + 1; + eolIndex = output.indexOf('\0', startOfLine); + } + + return result; +} + +const repoRootCache: Map = new Map(); + +/** + * Finds the root of the current Git repository + * + * @param currentWorkingDirectory - The working directory for which to locate the repository + * @param gitPath - The path to the Git executable + * + * @returns The full path to the root directory of the Git repository + * @beta + */ +export function getRepoRoot(currentWorkingDirectory: string, gitPath?: string): string { + let cachedResult: string | undefined = repoRootCache.get(currentWorkingDirectory); + if (!cachedResult) { + const result: child_process.SpawnSyncReturns = Executable.spawnSync( + gitPath || 'git', + ['--no-optional-locks', 'rev-parse', '--show-toplevel'], + { + currentWorkingDirectory + } + ); + + if (result.status !== 0) { + ensureGitMinimumVersion(gitPath); + + throw new Error(`git rev-parse exited with status ${result.status}: ${result.stderr}`); + } + + cachedResult = result.stdout.trim(); + + repoRootCache.set(currentWorkingDirectory, cachedResult); + // To ensure that calling getRepoRoot on the result is a no-op. + repoRootCache.set(cachedResult, cachedResult); + } + + return cachedResult; +} + +/** + * Helper function for async process invocation with optional stdin support. + * @param gitPath - Path to the Git executable + * @param args - The process arguments + * @param currentWorkingDirectory - The working directory. Should be the repository root. + * @param stdin - An optional Readable stream to use as stdin to the process. + */ +async function spawnGitAsync( + gitPath: string | undefined, + args: string[], + currentWorkingDirectory: string, + stdin?: Readable +): Promise { + const spawnOptions: IExecutableSpawnOptions = { + currentWorkingDirectory, + stdio: ['pipe', 'pipe', 'pipe'] + }; + + let stdout: string = ''; + let stderr: string = ''; + + const proc: child_process.ChildProcess = Executable.spawn(gitPath || 'git', args, spawnOptions); + proc.stdout!.setEncoding('utf-8'); + proc.stderr!.setEncoding('utf-8'); + + proc.stdout!.on('data', (chunk: string) => { + stdout += chunk.toString(); + }); + proc.stderr!.on('data', (chunk: string) => { + stderr += chunk.toString(); + }); + + if (stdin) { + /** + * For `git hash-object` data is piped in asynchronously. In the event that one of the + * passed filenames cannot be hashed, subsequent writes to `proc.stdin` will error. + * Silence this error since it will be handled by the non-zero exit code of the process. + */ + pipeline(stdin, proc.stdin!, (err) => {}); + } + + const [status] = await once(proc, 'close'); + if (status !== 0) { + throw new Error(`git ${args[0]} exited with code ${status}:\n${stderr}`); + } + + return stdout; +} + +function isIterable(value: Iterable | AsyncIterable): value is Iterable { + return Symbol.iterator in value; +} + +/** + * Uses `git hash-object` to hash the provided files. Unlike `getGitHashForFiles`, this API is asynchronous, and also allows for + * the input file paths to be specified as an async iterable. + * + * @param rootDirectory - The root directory to which paths are specified relative. Must be the root of the Git repository. + * @param filesToHash - The file paths to hash using `git hash-object` + * @param gitPath - The path to the Git executable + * @returns An iterable of [filePath, hash] pairs + * + * @remarks + * The input file paths must be specified relative to the Git repository root, or else be absolute paths. + * @beta + */ +export async function hashFilesAsync( + rootDirectory: string, + filesToHash: Iterable | AsyncIterable, + gitPath?: string +): Promise> { + const hashPaths: string[] = []; + + const input: Readable = Readable.from( + isIterable(filesToHash) + ? (function* (): IterableIterator { + for (const file of filesToHash) { + hashPaths.push(file); + yield `${file}\n`; + } + })() + : (async function* (): AsyncIterableIterator { + for await (const file of filesToHash) { + hashPaths.push(file); + yield `${file}\n`; + } + })(), + { + encoding: 'utf-8', + objectMode: false, + autoDestroy: true + } + ); + + const hashObjectResult: string = await spawnGitAsync( + gitPath, + STANDARD_GIT_OPTIONS.concat(['hash-object', '--stdin-paths']), + rootDirectory, + input + ); + + return parseGitHashObject(hashObjectResult, hashPaths); +} + +/** + * 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 getRepoStateAsync( + rootDirectory: string, + additionalRelativePathsToHash?: string[], + 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; + /** + * 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', + // Use NUL as the separator + '-z', + // Specify the full path to files relative to the root + '--full-name', + // As of last commit + 'HEAD', + '--', + ...(filterPath ?? []) + ]), + rootDirectory + ).then(parseGitLsTree); + const locallyModifiedPromise: Promise> = spawnGitAsync( + gitPath, + STANDARD_GIT_OPTIONS.concat([ + 'status', + // Use NUL as the separator + '-z', + // Include untracked files + '-u', + // Disable rename detection so that renames show up as add + delete + '--no-renames', + // Don't process submodules with this command; they'll be handled individually + '--ignore-submodules', + // Don't compare against the remote + '--no-ahead-behind', + '--', + ...(filterPath ?? []) + ]), + rootDirectory + ).then(parseGitStatus); + + async function* getFilesToHash(): AsyncIterableIterator { + if (additionalRelativePathsToHash) { + for (const file of additionalRelativePathsToHash) { + yield file; + } + } + + const [{ files }, locallyModified] = await Promise.all([statePromise, locallyModifiedPromise]); + + for (const [filePath, exists] of locallyModified) { + if (exists) { + yield filePath; + } else { + files.delete(filePath); + } + } + } + + const hashObjectPromise: Promise> = hashFilesAsync( + rootDirectory, + getFilesToHash(), + gitPath + ); + + const [{ files, 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) { + files.set(filePath, hash); + } + + // Existence check for the .gitmodules file + const hasSubmodules: boolean = submodules.size > 0 && FileSystem.exists(`${rootDirectory}/.gitmodules`); + + if (hasSubmodules) { + // Submodules are not the normal critical path. Accept serial performance rather than investing in complexity. + // Can revisit if submodules become more commonly used. + for (const submodulePath of submodules.keys()) { + const submoduleState: Map = await getRepoStateAsync( + `${rootDirectory}/${submodulePath}`, + [], + gitPath + ); + for (const [filePath, hash] of submoduleState) { + files.set(`${submodulePath}/${filePath}`, hash); + } + } + } + + return { + hasSubmodules, + hasUncommittedChanges: locallyModifiedFiles.size > 0, + files + }; +} + +/** + * Find all changed files tracked by Git, their current hashes, and the nature of the change. Only useful if all changes are staged or committed. + * @param currentWorkingDirectory - The working directory. Only used to find the repository root. + * @param revision - The Git revision specifier to detect changes relative to. Defaults to HEAD (i.e. will compare staged vs. committed) + * If comparing against a different branch, call `git merge-base` first to find the target commit. + * @param gitPath - The path to the Git executable + * @returns A map from the Git file path to the corresponding file change metadata + * @beta + */ +export function getRepoChanges( + currentWorkingDirectory: string, + revision: string = 'HEAD', + gitPath?: string +): Map { + const rootDirectory: string = getRepoRoot(currentWorkingDirectory, gitPath); + + const result: child_process.SpawnSyncReturns = Executable.spawnSync( + gitPath || 'git', + STANDARD_GIT_OPTIONS.concat([ + 'diff-index', + '--color=never', + '--no-renames', + '--no-commit-id', + '--cached', + '-z', + revision, + '--' + ]), + { + currentWorkingDirectory: rootDirectory + } + ); + + if (result.status !== 0) { + ensureGitMinimumVersion(gitPath); + + throw new Error(`git diff-index exited with status ${result.status}: ${result.stderr}`); + } + + const changes: Map = parseGitDiffIndex(result.stdout); + + return changes; +} + +/** + * Checks the git version and throws an error if it is less than the minimum required version. + * + * @public + */ +export function ensureGitMinimumVersion(gitPath?: string): void { + const gitVersion: IGitVersion = getGitVersion(gitPath); + if ( + gitVersion.major < MINIMUM_GIT_VERSION.major || + (gitVersion.major === MINIMUM_GIT_VERSION.major && gitVersion.minor < MINIMUM_GIT_VERSION.minor) || + (gitVersion.major === MINIMUM_GIT_VERSION.major && + gitVersion.minor === MINIMUM_GIT_VERSION.minor && + gitVersion.patch < MINIMUM_GIT_VERSION.patch) + ) { + throw new Error( + `The minimum Git version required is ` + + `${MINIMUM_GIT_VERSION.major}.${MINIMUM_GIT_VERSION.minor}.${MINIMUM_GIT_VERSION.patch}. ` + + `Your version is ${gitVersion.major}.${gitVersion.minor}.${gitVersion.patch}.` + ); + } +} + +function getGitVersion(gitPath?: string): IGitVersion { + const result: child_process.SpawnSyncReturns = Executable.spawnSync( + gitPath || 'git', + STANDARD_GIT_OPTIONS.concat(['version']) + ); + + if (result.status !== 0) { + throw new Error( + `While validating the Git installation, the "git version" command failed with ` + + `status ${result.status}: ${result.stderr}` + ); + } + + return parseGitVersion(result.stdout); +} + +export function parseGitVersion(gitVersionOutput: string): IGitVersion { + // This regexp matches output of "git version" that looks like `git version ..(+whatever)` + // Examples: + // - git version 1.2.3 + // - git version 1.2.3.4.5 + // - git version 1.2.3windows.1 + // - git version 1.2.3.windows.1 + const versionRegex: RegExp = /^git version (\d+)\.(\d+)\.(\d+)/; + const match: RegExpMatchArray | null = versionRegex.exec(gitVersionOutput); + if (!match) { + throw new Error( + `While validating the Git installation, the "git version" command produced ` + + `unexpected output: "${gitVersionOutput}"` + ); + } + + const major: number = parseInt(match[1], 10); + const minor: number = parseInt(match[2], 10); + const patch: number = parseInt(match[3], 10); + + return { + major, + minor, + patch + }; +} diff --git a/libraries/package-deps-hash/src/index.ts b/libraries/package-deps-hash/src/index.ts index 827f1a3b28f..8558d210a4d 100644 --- a/libraries/package-deps-hash/src/index.ts +++ b/libraries/package-deps-hash/src/index.ts @@ -13,8 +13,14 @@ * @packageDocumentation */ +export { getPackageDeps, getGitHashForFiles } from './getPackageDeps'; export { - getPackageDeps, - getGitHashForFiles -} from './getPackageDeps'; -export { IPackageDeps } from './IPackageDeps'; + type IFileDiffStatus, + type IDetailedRepoState, + getDetailedRepoStateAsync, + getRepoChanges, + getRepoRoot, + getRepoStateAsync, + ensureGitMinimumVersion, + hashFilesAsync +} from './getRepoState'; 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 new file mode 100644 index 00000000000..9fd6eb281ea --- /dev/null +++ b/libraries/package-deps-hash/src/test/__snapshots__/getRepoDeps.test.ts.snap @@ -0,0 +1,132 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getDetailedRepoStateAsync can handle adding one file 1`] = ` +Object { + "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[`getDetailedRepoStateAsync can handle adding two files 1`] = ` +Object { + "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[`getDetailedRepoStateAsync can handle changing one file 1`] = ` +Object { + "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[`getDetailedRepoStateAsync can handle removing one file 1`] = ` +Object { + "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[`getDetailedRepoStateAsync can handle uncommitted filenames with spaces and non-ASCII characters 1`] = ` +Object { + "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[`getDetailedRepoStateAsync can parse committed files 1`] = ` +Object { + "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[`getDetailedRepoStateAsync handles requests for additional files 1`] = ` +Object { + "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, +} +`; + +exports[`parseGitHashObject can parse multiple entries 1`] = ` +Map { + "a" => "11", + "b" => "22", + "c" => "33", +} +`; + +exports[`parseGitHashObject can parse multiple entries with trailing whitespace 1`] = ` +Map { + "a" => "11", + "b" => "22", + "c" => "33", +} +`; + +exports[`parseGitHashObject throws if too few hashes are provided 1`] = `"Expected 3 hashes from \\"git hash-object\\" but received 2"`; + +exports[`parseGitHashObject throws if too many hashes are provided 1`] = `"Expected 2 hashes from \\"git hash-object\\" but received 3"`; diff --git a/libraries/package-deps-hash/src/test/getPackageDeps.test.ts b/libraries/package-deps-hash/src/test/getPackageDeps.test.ts index cb91e911e0f..adae400ab4b 100644 --- a/libraries/package-deps-hash/src/test/getPackageDeps.test.ts +++ b/libraries/package-deps-hash/src/test/getPackageDeps.test.ts @@ -1,50 +1,61 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { getPackageDeps, parseGitLsTree } from '../getPackageDeps'; -import { IPackageDeps } from '../IPackageDeps'; -import { expect, assert } from 'chai'; -import * as path from 'path'; -import { execSync } from 'child_process'; +import * as path from 'node:path'; +import { execSync } from 'node:child_process'; -import { - FileSystem, - FileConstants -} from '@rushstack/node-core-library'; +import { getPackageDeps, parseGitLsTree, parseGitFilename } from '../getPackageDeps'; -const SOURCE_PATH: string = path.join(__dirname).replace( - path.join('lib', 'test'), - path.join('src', 'test')); +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 TEST_PROJECT_PATH: string = path.join(SOURCE_PATH, 'testProject'); const NESTED_TEST_PROJECT_PATH: string = path.join(SOURCE_PATH, 'nestedTestProject'); -describe('parseGitLsTree', () => { - it('can handle a blob', (done) => { +describe(parseGitFilename.name, () => { + it('can parse backslash-escaped filenames', () => { + expect(parseGitFilename('some/path/to/a/file name')).toEqual('some/path/to/a/file name'); + expect(parseGitFilename('"some/path/to/a/file?name"')).toEqual('some/path/to/a/file?name'); + expect(parseGitFilename('"some/path/to/a/file\\\\name"')).toEqual('some/path/to/a/file\\name'); + expect(parseGitFilename('"some/path/to/a/file\\"name"')).toEqual('some/path/to/a/file"name'); + expect(parseGitFilename('"some/path/to/a/file\\"name"')).toEqual('some/path/to/a/file"name'); + expect(parseGitFilename('"some/path/to/a/file\\347\\275\\221\\347\\275\\221name"')).toEqual( + 'some/path/to/a/file网网name' + ); + expect(parseGitFilename('"some/path/to/a/file\\\\347\\\\\\347\\275\\221name"')).toEqual( + 'some/path/to/a/file\\347\\网name' + ); + expect(parseGitFilename('"some/path/to/a/file\\\\\\347\\275\\221\\347\\275\\221name"')).toEqual( + 'some/path/to/a/file\\网网name' + ); + }); +}); + +describe(parseGitLsTree.name, () => { + it('can handle a blob', () => { const filename: string = 'src/typings/tsd.d.ts'; const hash: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; const output: string = `100644 blob ${hash}\t${filename}`; const changes: Map = parseGitLsTree(output); - assert.equal(changes.size, 1, 'Expect there to be exactly 1 change'); - assert.equal(changes.get(filename), hash, `Expect the hash to be ${hash}`); - done(); + expect(changes.size).toEqual(1); // Expect there to be exactly 1 change + expect(changes.get(filename)).toEqual(hash); // Expect the hash to be ${hash} }); - it('can handle a submodule', (done) => { + it('can handle a submodule', () => { const filename: string = 'rushstack'; const hash: string = 'c5880bf5b0c6c1f2e2c43c95beeb8f0a808e8bac'; const output: string = `160000 commit ${hash}\t${filename}`; const changes: Map = parseGitLsTree(output); - assert.equal(changes.size, 1, 'Expect there to be exactly 1 change'); - assert.equal(changes.get(filename), hash, `Expect the hash to be ${hash}`); - done(); + expect(changes.size).toEqual(1); // Expect there to be exactly 1 change + expect(changes.get(filename)).toEqual(hash); // Expect the hash to be ${hash} }); - it('can handle multiple lines', (done) => { + it('can handle multiple lines', () => { const filename1: string = 'src/typings/tsd.d.ts'; const hash1: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; @@ -54,227 +65,261 @@ describe('parseGitLsTree', () => { const output: string = `100644 blob ${hash1}\t${filename1}\n100666 blob ${hash2}\t${filename2}`; const changes: Map = parseGitLsTree(output); - assert.equal(changes.size, 2, 'Expect there to be exactly 2 changes'); - assert.equal(changes.get(filename1), hash1, `Expect the hash to be ${hash1}`); - assert.equal(changes.get(filename2), hash2, `Expect the hash to be ${hash2}`); - done(); + expect(changes.size).toEqual(2); // Expect there to be exactly 2 changes + expect(changes.get(filename1)).toEqual(hash1); // Expect the hash to be ${hash1} + expect(changes.get(filename2)).toEqual(hash2); // Expect the hash to be ${hash2} }); - it('throws with malformed input', (done) => { - assert.throws(parseGitLsTree.bind(undefined, 'some super malformed input')); - done(); + it('throws with malformed input', () => { + expect(parseGitLsTree.bind(undefined, 'some super malformed input')).toThrow(); }); }); -describe('getPackageDeps', () => { - - it('can parse committed file', (done) => { - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH); - try { - const expectedFiles: { [key: string]: string } = { - 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' - }; - const filePaths: string[] = Object.keys(results.files).sort(); - - filePaths.forEach(filePath => ( - expect(results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); - - } catch (e) { return done(e); } - - done(); +describe(getPackageDeps.name, () => { + it('can parse committed file', () => { + const results: Map = getPackageDeps(TEST_PROJECT_PATH); + const expectedFiles: { [key: string]: string } = { + 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); + + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); }); - it('can handle files in subfolders', (done) => { - const results: IPackageDeps = getPackageDeps(NESTED_TEST_PROJECT_PATH); - try { - const expectedFiles: { [key: string]: string } = { - 'src/file 1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' - }; - const filePaths: string[] = Object.keys(results.files).sort(); - - filePaths.forEach(filePath => ( - expect(results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); - - } catch (e) { return done(e); } + it('can handle files in subfolders', () => { + const results: Map = getPackageDeps(NESTED_TEST_PROJECT_PATH); + const expectedFiles: { [key: string]: string } = { + 'src/file 1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); - done(); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); }); - it('can handle adding one file', (done) => { + it('can handle adding one file', () => { const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a.txt'); FileSystem.writeFile(tempFilePath, 'a'); - function _done(e?: Error): void { - FileSystem.deleteFile(tempFilePath); - done(e); - } - - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH); + const results: Map = getPackageDeps(TEST_PROJECT_PATH); try { const expectedFiles: { [key: string]: string } = { 'a.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); + const filePaths: string[] = Array.from(results.keys()).sort(); - filePaths.forEach(filePath => ( - expect( - results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); - - } catch (e) { - return _done(e); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath); } - - _done(); - }); - it('can handle adding two files', (done) => { + it('can handle adding two files', () => { const tempFilePath1: string = path.join(TEST_PROJECT_PATH, 'a.txt'); const tempFilePath2: string = path.join(TEST_PROJECT_PATH, 'b.txt'); FileSystem.writeFile(tempFilePath1, 'a'); FileSystem.writeFile(tempFilePath2, 'a'); - function _done(e?: Error): void { - FileSystem.deleteFile(tempFilePath1); - FileSystem.deleteFile(tempFilePath2); - done(e); - } - - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH); + const results: Map = getPackageDeps(TEST_PROJECT_PATH); try { const expectedFiles: { [key: string]: string } = { 'a.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', 'b.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); + const filePaths: string[] = Array.from(results.keys()).sort(); - filePaths.forEach(filePath => ( - expect( - results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); - - } catch (e) { - return _done(e); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath1); + FileSystem.deleteFile(tempFilePath2); } - - _done(); }); - it('can handle removing one file', (done) => { + it('can handle removing one file', () => { const testFilePath: string = path.join(TEST_PROJECT_PATH, 'file1.txt'); FileSystem.deleteFile(testFilePath); - function _done(e?: Error): void { - execSync(`git checkout ${ testFilePath }`, { stdio: 'ignore' }); - done(e); - } - - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH); + const results: Map = getPackageDeps(TEST_PROJECT_PATH); try { const expectedFiles: { [key: string]: string } = { - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); - - filePaths.forEach(filePath => ( - expect(results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); + const filePaths: string[] = Array.from(results.keys()).sort(); - } catch (e) { - return _done(e); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + execSync(`git checkout ${testFilePath}`, { stdio: 'ignore' }); } - - _done(); }); - it('can handle changing one file', (done) => { + it('can handle changing one file', () => { const testFilePath: string = path.join(TEST_PROJECT_PATH, 'file1.txt'); FileSystem.writeFile(testFilePath, 'abc'); - function _done(e?: Error): void { + const results: Map = getPackageDeps(TEST_PROJECT_PATH); + try { + const expectedFiles: { [key: string]: string } = { + 'file1.txt': 'f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); + + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { execSync(`git checkout ${testFilePath}`, { stdio: 'ignore' }); - done(e); } + }); + + it('can exclude a committed file', () => { + const results: Map = getPackageDeps(TEST_PROJECT_PATH, [ + 'file1.txt', + 'file 2.txt', + 'file蝴蝶.txt' + ]); - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH); + const expectedFiles: { [key: string]: string } = { + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); + + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + }); + + it('can exclude an added file', () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a.txt'); + + FileSystem.writeFile(tempFilePath, 'a'); + + const results: Map = getPackageDeps(TEST_PROJECT_PATH, ['a.txt']); try { const expectedFiles: { [key: string]: string } = { - 'file1.txt': 'f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); + const filePaths: string[] = Array.from(results.keys()).sort(); - filePaths.forEach(filePath => ( - expect(results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); + expect(filePaths).toHaveLength(Object.keys(expectedFiles).length); - } catch (e) { - return _done(e); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath); } - - _done(); }); - it('can exclude a committed file', (done) => { - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH, ['file1.txt']); + it('can handle a filename with spaces', () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a file.txt'); + + FileSystem.writeFile(tempFilePath, 'a'); + + const results: Map = getPackageDeps(TEST_PROJECT_PATH); try { const expectedFiles: { [key: string]: string } = { - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + 'a file.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); - - filePaths.forEach(filePath => ( - expect(results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); + const filePaths: string[] = Array.from(results.keys()).sort(); - } catch (e) { return done(e); } + expect(filePaths).toHaveLength(Object.keys(expectedFiles).length); - done(); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath); + } }); - it('can exclude an added file', (done) => { - const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a.txt'); + it('can handle a filename with multiple spaces', () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a file name.txt'); FileSystem.writeFile(tempFilePath, 'a'); - function _done(e?: Error): void { + const results: Map = getPackageDeps(TEST_PROJECT_PATH); + try { + const expectedFiles: { [key: string]: string } = { + 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + 'a file name.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); + + expect(filePaths).toHaveLength(Object.keys(expectedFiles).length); + + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { FileSystem.deleteFile(tempFilePath); - done(e); } + }); + + it('can handle a filename with non-standard characters', () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'newFile批把.txt'); - const results: IPackageDeps = getPackageDeps(TEST_PROJECT_PATH, ['a.txt']); + FileSystem.writeFile(tempFilePath, 'a'); + + const results: Map = getPackageDeps(TEST_PROJECT_PATH); try { const expectedFiles: { [key: string]: string } = { 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', - [FileConstants.PackageJson]: '33703d582243a41bdebff8ee7dd046a01fc054b9' + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + 'newFile批把.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' }; - const filePaths: string[] = Object.keys(results.files).sort(); - - expect(filePaths.length).to.equal(Object.keys(expectedFiles).length, 'filePaths.length'); + const filePaths: string[] = Array.from(results.keys()).sort(); - filePaths.forEach(filePath => ( - expect( - results.files[filePath]) - .equals(expectedFiles[filePath], `path: ${filePath}`))); + expect(filePaths).toHaveLength(Object.keys(expectedFiles).length); - } catch (e) { - return _done(e); + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath); } - - _done(); }); + it('can handle a filename with non-standard characters', () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'newFile批把.txt'); + + FileSystem.writeFile(tempFilePath, 'a'); + + const results: Map = getPackageDeps(TEST_PROJECT_PATH); + try { + const expectedFiles: { [key: string]: string } = { + 'file1.txt': 'c7b2f707ac99ca522f965210a7b6b0b109863f34', + 'file 2.txt': 'a385f754ec4fede884a4864d090064d9aeef8ccb', + 'file蝴蝶.txt': 'ae814af81e16cb2ae8c57503c77e2cab6b5462ba', + 'newFile批把.txt': '2e65efe2a145dda7ee51d1741299f848e5bf752e', + [FileConstants.PackageJson]: '18a1e415e56220fa5122428a4ef8eb8874756576' + }; + const filePaths: string[] = Array.from(results.keys()).sort(); + + expect(filePaths).toHaveLength(Object.keys(expectedFiles).length); + + filePaths.forEach((filePath) => expect(results.get(filePath)).toEqual(expectedFiles[filePath])); + } finally { + FileSystem.deleteFile(tempFilePath); + } + }); }); diff --git a/libraries/package-deps-hash/src/test/getRepoDeps.test.ts b/libraries/package-deps-hash/src/test/getRepoDeps.test.ts new file mode 100644 index 00000000000..63325761544 --- /dev/null +++ b/libraries/package-deps-hash/src/test/getRepoDeps.test.ts @@ -0,0 +1,255 @@ +// 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 { execSync } from 'node:child_process'; + +import { + getDetailedRepoStateAsync, + type IDetailedRepoState, + parseGitLsTree, + getRepoRoot, + parseGitHashObject +} from '../getRepoState'; + +import { FileSystem } from '@rushstack/node-core-library'; + +const SOURCE_PATH: string = path.join(__dirname).replace(path.join('lib', '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: IDetailedRepoState): void { + const relevantResults: Record = {}; + for (const [key, hash] of results.files) { + if (key.startsWith(TEST_PREFIX)) { + const partialKey: string = key.slice(TEST_PREFIX.length); + relevantResults[partialKey] = hash; + } + } + + expect({ + hasSubmodules: results.hasSubmodules, + hasUncommittedChanges: results.hasUncommittedChanges, + files: relevantResults + }).toMatchSnapshot(); +} + +describe(getRepoRoot.name, () => { + it(`returns the correct directory`, () => { + const root: string = getRepoRoot(__dirname); + const expectedRoot: string = path.resolve(__dirname, '../../../..').replace(/\\/g, '/'); + expect(root).toEqual(expectedRoot); + }); +}); + +describe(parseGitLsTree.name, () => { + it('can handle a blob', () => { + const filename: string = 'src/typings/tsd.d.ts'; + const hash: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; + + const output: string = `100644 blob ${hash}\t${filename}\x00`; + const { files } = parseGitLsTree(output); + + 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 submodule', () => { + const filename: string = 'rushstack'; + const hash: string = 'c5880bf5b0c6c1f2e2c43c95beeb8f0a808e8bac'; + + const output: string = `160000 commit ${hash}\t${filename}\x00`; + const { submodules } = parseGitLsTree(output); + + expect(submodules.size).toEqual(1); // Expect there to be exactly 1 submodule change + expect(submodules.get(filename)).toEqual(hash); // Expect the hash to be ${hash} + }); + + it('can handle multiple lines', () => { + const filename1: string = 'src/typings/tsd.d.ts'; + const hash1: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; + + const filename2: string = 'src/foo bar/tsd.d.ts'; + const hash2: string = '0123456789abcdef1234567890abcdef01234567'; + + 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); + + expect(files.size).toEqual(2); // Expect there to be exactly 2 changes + 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(submodules.get(filename3)).toEqual(hash3); // Expect the hash to be ${hash3} + }); +}); + +describe(parseGitHashObject.name, () => { + it('can handle requesting zero entries', () => { + const results: Map = new Map(parseGitHashObject('', [])); + expect(results.size).toEqual(0); + }); + + it('can parse multiple entries', () => { + const results: Map = new Map(parseGitHashObject('11\n22\n33', ['a', 'b', 'c'])); + expect(results).toMatchSnapshot(); + }); + + it('can parse multiple entries with trailing whitespace', () => { + const results: Map = new Map(parseGitHashObject('11\n22\n33\n\n', ['a', 'b', 'c'])); + expect(results).toMatchSnapshot(); + }); + + it('throws if too few hashes are provided', () => { + expect(() => { + new Map(parseGitHashObject('11\n22', ['a', 'b', 'c'])); + }).toThrowErrorMatchingSnapshot(); + }); + + it('throws if too many hashes are provided', () => { + expect(() => { + new Map(parseGitHashObject('11\n22\n33', ['a', 'b'])); + }).toThrowErrorMatchingSnapshot(); + }); +}); + +describe(getDetailedRepoStateAsync.name, () => { + it('can parse committed files', async () => { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + }); + + it('can handle adding one file', async () => { + const tempFilePath: string = path.join(TEST_PROJECT_PATH, 'a.txt'); + + FileSystem.writeFile(tempFilePath, 'a'); + + try { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + } finally { + FileSystem.deleteFile(tempFilePath); + } + }); + + it('can handle adding two files', async () => { + const tempFilePath1: string = path.join(TEST_PROJECT_PATH, 'a.txt'); + const tempFilePath2: string = path.join(TEST_PROJECT_PATH, 'b.txt'); + + FileSystem.writeFile(tempFilePath1, 'a'); + FileSystem.writeFile(tempFilePath2, 'a'); + + try { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + } finally { + FileSystem.deleteFile(tempFilePath1); + FileSystem.deleteFile(tempFilePath2); + } + }); + + it('can handle removing one file', async () => { + const testFilePath: string = path.join(TEST_PROJECT_PATH, 'file1.txt'); + + FileSystem.deleteFile(testFilePath); + + try { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + } finally { + execSync(`git checkout --force HEAD -- ${TEST_PREFIX}testProject/file1.txt`, { + stdio: 'ignore', + cwd: getRepoRoot(SOURCE_PATH) + }); + } + }); + + it('can handle changing one file', async () => { + const testFilePath: string = path.join(TEST_PROJECT_PATH, 'file1.txt'); + + FileSystem.writeFile(testFilePath, 'abc'); + + try { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + } finally { + execSync(`git checkout --force HEAD -- ${TEST_PREFIX}testProject/file1.txt`, { + stdio: 'ignore', + cwd: getRepoRoot(SOURCE_PATH) + }); + } + }); + + it('can handle uncommitted filenames with spaces and non-ASCII characters', async () => { + const tempFilePath1: string = path.join(TEST_PROJECT_PATH, 'a file.txt'); + const tempFilePath2: string = path.join(TEST_PROJECT_PATH, 'a file name.txt'); + const tempFilePath3: string = path.join(TEST_PROJECT_PATH, 'newFile批把.txt'); + + FileSystem.writeFile(tempFilePath1, 'a'); + FileSystem.writeFile(tempFilePath2, 'a'); + FileSystem.writeFile(tempFilePath3, 'a'); + + try { + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); + checkSnapshot(results); + } finally { + FileSystem.deleteFile(tempFilePath1); + FileSystem.deleteFile(tempFilePath2); + FileSystem.deleteFile(tempFilePath3); + } + }); + + it('handles requests for additional files', async () => { + const tempFilePath1: string = path.join(TEST_PROJECT_PATH, 'log.log'); + + FileSystem.writeFile(tempFilePath1, 'a'); + + try { + 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 new file mode 100644 index 00000000000..c1422367b0f --- /dev/null +++ b/libraries/package-deps-hash/src/test/getRepoState.test.ts @@ -0,0 +1,89 @@ +// 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'; + +describe(parseGitVersion.name, () => { + it('Can parse valid git version responses', () => { + expect(parseGitVersion('git version 2.30.2.windows.1')).toEqual({ + major: 2, + minor: 30, + patch: 2 + }); + expect(parseGitVersion('git version 2.30.2.windows.1.g8b8f8e')).toEqual({ + major: 2, + minor: 30, + patch: 2 + }); + expect(parseGitVersion('git version 2.30.2')).toEqual({ + major: 2, + minor: 30, + patch: 2 + }); + }); + + it('Rejects invalid git version responses', () => { + expect(() => parseGitVersion('2.22.0.windows.1')).toThrowErrorMatchingInlineSnapshot( + `"While validating the Git installation, the \\"git version\\" command produced unexpected output: \\"2.22.0.windows.1\\""` + ); + expect(() => parseGitVersion('git version 2.30.A')).toThrowErrorMatchingInlineSnapshot( + `"While validating the Git installation, the \\"git version\\" command produced unexpected output: \\"git version 2.30.A\\""` + ); + expect(() => parseGitVersion('git version 2.30')).toThrowErrorMatchingInlineSnapshot( + `"While validating the Git installation, the \\"git version\\" command produced unexpected output: \\"git version 2.30\\""` + ); + expect(() => parseGitVersion('git version .2.30')).toThrowErrorMatchingInlineSnapshot( + `"While validating the Git installation, the \\"git version\\" command produced unexpected output: \\"git version .2.30\\""` + ); + }); +}); + +describe(parseGitStatus.name, () => { + it('Finds index entries', () => { + const files: string[] = [`A.ts`, `B.ts`, `C.ts`]; + const input: string = [`A ${files[0]}`, `D ${files[1]}`, `M ${files[2]}`, ''].join('\0'); + + const result: Map = parseGitStatus(input); + + expect(result.size).toEqual(3); + expect(result.get(files[0])).toEqual(true); + expect(result.get(files[1])).toEqual(false); + expect(result.get(files[2])).toEqual(true); + }); + + it('Finds working tree entries', () => { + const files: string[] = [`A.ts`, `B.ts`, `C.ts`]; + const input: string = [` A ${files[0]}`, ` D ${files[1]}`, ` M ${files[2]}`, ''].join('\0'); + + const result: Map = parseGitStatus(input); + + expect(result.size).toEqual(3); + expect(result.get(files[0])).toEqual(true); + expect(result.get(files[1])).toEqual(false); + expect(result.get(files[2])).toEqual(true); + }); + + it('Can handle untracked files', () => { + const files: string[] = [`A.ts`, `B.ts`, `C.ts`]; + const input: string = [`?? ${files[0]}`, `?? ${files[1]}`, `?? ${files[2]}`, ''].join('\0'); + + const result: Map = parseGitStatus(input); + + expect(result.size).toEqual(3); + expect(result.get(files[0])).toEqual(true); + expect(result.get(files[1])).toEqual(true); + expect(result.get(files[2])).toEqual(true); + }); + + it('Can handle files modified in both index and working tree', () => { + const files: string[] = [`A.ts`, `B.ts`, `C.ts`]; + const input: string = [`D ${files[0]}`, `AD ${files[1]}`, `DA ${files[2]}`, ''].join('\0'); + + const result: Map = parseGitStatus(input); + + expect(result.size).toEqual(3); + expect(result.get(files[0])).toEqual(false); + expect(result.get(files[1])).toEqual(false); + expect(result.get(files[2])).toEqual(true); + }); +}); diff --git a/libraries/package-deps-hash/src/test/nestedTestProject/package.json b/libraries/package-deps-hash/src/test/nestedTestProject/package.json index 33703d58224..18a1e415e56 100644 --- a/libraries/package-deps-hash/src/test/nestedTestProject/package.json +++ b/libraries/package-deps-hash/src/test/nestedTestProject/package.json @@ -1,3 +1,3 @@ { "dependencies": {} -} \ No newline at end of file +} diff --git a/libraries/package-deps-hash/src/test/testProject/file 2.txt b/libraries/package-deps-hash/src/test/testProject/file 2.txt new file mode 100644 index 00000000000..a385f754ec4 --- /dev/null +++ b/libraries/package-deps-hash/src/test/testProject/file 2.txt @@ -0,0 +1 @@ +file 2. \ No newline at end of file diff --git "a/libraries/package-deps-hash/src/test/testProject/file\350\235\264\350\235\266.txt" "b/libraries/package-deps-hash/src/test/testProject/file\350\235\264\350\235\266.txt" new file mode 100644 index 00000000000..ae814af81e1 --- /dev/null +++ "b/libraries/package-deps-hash/src/test/testProject/file\350\235\264\350\235\266.txt" @@ -0,0 +1 @@ +file蝴蝶. \ No newline at end of file diff --git a/libraries/package-deps-hash/src/test/testProject/package.json b/libraries/package-deps-hash/src/test/testProject/package.json index 33703d58224..18a1e415e56 100644 --- a/libraries/package-deps-hash/src/test/testProject/package.json +++ b/libraries/package-deps-hash/src/test/testProject/package.json @@ -1,3 +1,3 @@ { "dependencies": {} -} \ No newline at end of file +} diff --git a/libraries/package-deps-hash/tsconfig.json b/libraries/package-deps-hash/tsconfig.json index b622be5621b..dac21d04081 100644 --- a/libraries/package-deps-hash/tsconfig.json +++ b/libraries/package-deps-hash/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "mocha", - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/package-extractor/.gitignore b/libraries/package-extractor/.gitignore new file mode 100644 index 00000000000..e93dfd32bfd --- /dev/null +++ b/libraries/package-extractor/.gitignore @@ -0,0 +1 @@ +test-output diff --git a/libraries/package-extractor/.npmignore b/libraries/package-extractor/.npmignore new file mode 100644 index 00000000000..173cbd6923d --- /dev/null +++ b/libraries/package-extractor/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/assets/** +/lib-*/** diff --git a/libraries/package-extractor/CHANGELOG.json b/libraries/package-extractor/CHANGELOG.json new file mode 100644 index 00000000000..720e005a407 --- /dev/null +++ b/libraries/package-extractor/CHANGELOG.json @@ -0,0 +1,3692 @@ +{ + "name": "@rushstack/package-extractor", + "entries": [ + { + "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", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.78`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/package-extractor_v0.10.4", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.77`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/package-extractor_v0.10.3", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.76`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/package-extractor_v0.10.2", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.75`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/package-extractor_v0.10.1", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.74`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/package-extractor_v0.10.0", + "date": "Thu, 24 Oct 2024 15:11:19 GMT", + "comments": { + "minor": [ + { + "comment": "Add bin linking support when calling the create-links.js script with the \"--link-bins\" parameter" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/package-extractor_v0.9.9", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.73`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/package-extractor_v0.9.8", + "date": "Tue, 22 Oct 2024 22:12:40 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `node_modules/.bin` folder symlinks were not created for extracted packages when using the \"default\" link creation mode" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/package-extractor_v0.9.7", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.72`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/package-extractor_v0.9.6", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.71`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/package-extractor_v0.9.5", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.70`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/package-extractor_v0.9.4", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.69`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/package-extractor_v0.9.3", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.68`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/package-extractor_v0.9.2", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.67`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/package-extractor_v0.9.1", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.12`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/package-extractor_v0.9.0", + "date": "Mon, 16 Sep 2024 02:09:00 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `files` field to the `extractor-metadata.json` file" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/package-extractor_v0.8.1", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.66`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/package-extractor_v0.8.0", + "date": "Wed, 11 Sep 2024 19:54:47 GMT", + "comments": { + "minor": [ + { + "comment": "Add the ability to change where the \"create-links.js\" file and the associated metadata file are generated when running in the \"script\" linkCreation mode" + } + ] + } + }, + { + "version": "0.7.26", + "tag": "@rushstack/package-extractor_v0.7.26", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.65`" + } + ] + } + }, + { + "version": "0.7.25", + "tag": "@rushstack/package-extractor_v0.7.25", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.64`" + } + ] + } + }, + { + "version": "0.7.24", + "tag": "@rushstack/package-extractor_v0.7.24", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.63`" + } + ] + } + }, + { + "version": "0.7.23", + "tag": "@rushstack/package-extractor_v0.7.23", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.62`" + } + ] + } + }, + { + "version": "0.7.22", + "tag": "@rushstack/package-extractor_v0.7.22", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.61`" + } + ] + } + }, + { + "version": "0.7.21", + "tag": "@rushstack/package-extractor_v0.7.21", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.60`" + } + ] + } + }, + { + "version": "0.7.20", + "tag": "@rushstack/package-extractor_v0.7.20", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.59`" + } + ] + } + }, + { + "version": "0.7.19", + "tag": "@rushstack/package-extractor_v0.7.19", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.58`" + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/package-extractor_v0.7.18", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.57`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/package-extractor_v0.7.17", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.56`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/package-extractor_v0.7.16", + "date": "Fri, 07 Jun 2024 15:10:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/package-extractor_v0.7.15", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.55`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/package-extractor_v0.7.14", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.54`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/package-extractor_v0.7.13", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.53`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/package-extractor_v0.7.12", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.52`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/package-extractor_v0.7.11", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.51`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/package-extractor_v0.7.10", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.50`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/package-extractor_v0.7.9", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.49`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/package-extractor_v0.7.8", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.48`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/package-extractor_v0.7.7", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.47`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/package-extractor_v0.7.6", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.46`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/package-extractor_v0.7.5", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.45`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/package-extractor_v0.7.4", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.44`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/package-extractor_v0.7.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.43`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/package-extractor_v0.7.2", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.42`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/package-extractor_v0.7.1", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.41`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/package-extractor_v0.7.0", + "date": "Thu, 18 Apr 2024 23:19:43 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for Rush subspaces" + } + ] + } + }, + { + "version": "0.6.43", + "tag": "@rushstack/package-extractor_v0.6.43", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.6.42", + "tag": "@rushstack/package-extractor_v0.6.42", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.6.41", + "tag": "@rushstack/package-extractor_v0.6.41", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.38`" + } + ] + } + }, + { + "version": "0.6.40", + "tag": "@rushstack/package-extractor_v0.6.40", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.37`" + } + ] + } + }, + { + "version": "0.6.39", + "tag": "@rushstack/package-extractor_v0.6.39", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.6.38", + "tag": "@rushstack/package-extractor_v0.6.38", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.35`" + } + ] + } + }, + { + "version": "0.6.37", + "tag": "@rushstack/package-extractor_v0.6.37", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.34`" + } + ] + } + }, + { + "version": "0.6.36", + "tag": "@rushstack/package-extractor_v0.6.36", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.33`" + } + ] + } + }, + { + "version": "0.6.35", + "tag": "@rushstack/package-extractor_v0.6.35", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.32`" + } + ] + } + }, + { + "version": "0.6.34", + "tag": "@rushstack/package-extractor_v0.6.34", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.31`" + } + ] + } + }, + { + "version": "0.6.33", + "tag": "@rushstack/package-extractor_v0.6.33", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.30`" + } + ] + } + }, + { + "version": "0.6.32", + "tag": "@rushstack/package-extractor_v0.6.32", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.29`" + } + ] + } + }, + { + "version": "0.6.31", + "tag": "@rushstack/package-extractor_v0.6.31", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.28`" + } + ] + } + }, + { + "version": "0.6.30", + "tag": "@rushstack/package-extractor_v0.6.30", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.27`" + } + ] + } + }, + { + "version": "0.6.29", + "tag": "@rushstack/package-extractor_v0.6.29", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.26`" + } + ] + } + }, + { + "version": "0.6.28", + "tag": "@rushstack/package-extractor_v0.6.28", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.25`" + } + ] + } + }, + { + "version": "0.6.27", + "tag": "@rushstack/package-extractor_v0.6.27", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.24`" + } + ] + } + }, + { + "version": "0.6.26", + "tag": "@rushstack/package-extractor_v0.6.26", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.23`" + } + ] + } + }, + { + "version": "0.6.25", + "tag": "@rushstack/package-extractor_v0.6.25", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.22`" + } + ] + } + }, + { + "version": "0.6.24", + "tag": "@rushstack/package-extractor_v0.6.24", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.21`" + } + ] + } + }, + { + "version": "0.6.23", + "tag": "@rushstack/package-extractor_v0.6.23", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.20`" + } + ] + } + }, + { + "version": "0.6.22", + "tag": "@rushstack/package-extractor_v0.6.22", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.19`" + } + ] + } + }, + { + "version": "0.6.21", + "tag": "@rushstack/package-extractor_v0.6.21", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.18`" + } + ] + } + }, + { + "version": "0.6.20", + "tag": "@rushstack/package-extractor_v0.6.20", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.17`" + } + ] + } + }, + { + "version": "0.6.19", + "tag": "@rushstack/package-extractor_v0.6.19", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.16`" + } + ] + } + }, + { + "version": "0.6.18", + "tag": "@rushstack/package-extractor_v0.6.18", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.15`" + } + ] + } + }, + { + "version": "0.6.17", + "tag": "@rushstack/package-extractor_v0.6.17", + "date": "Tue, 12 Dec 2023 00:20:33 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue with the `folderToCopy` option, where the folder contents would be copied into a subfolder instead of into the target folder root." + } + ] + } + }, + { + "version": "0.6.16", + "tag": "@rushstack/package-extractor_v0.6.16", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.14`" + } + ] + } + }, + { + "version": "0.6.15", + "tag": "@rushstack/package-extractor_v0.6.15", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.13`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/package-extractor_v0.6.14", + "date": "Thu, 16 Nov 2023 01:09:56 GMT", + "comments": { + "patch": [ + { + "comment": "Links that target a path outside of the source directory can now be ignored using \"patternsToInclude\" and \"patternsToExclude\" options" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/package-extractor_v0.6.13", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.12`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/package-extractor_v0.6.12", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.11`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/package-extractor_v0.6.11", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.10`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/package-extractor_v0.6.10", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.9`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/package-extractor_v0.6.9", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure the \"folderToCopy\" field is included in generated archives" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.8`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/package-extractor_v0.6.8", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.7`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/package-extractor_v0.6.7", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.6`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/package-extractor_v0.6.6", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.5`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/package-extractor_v0.6.5", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.4`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/package-extractor_v0.6.4", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.3`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/package-extractor_v0.6.3", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.2`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/package-extractor_v0.6.2", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/package-extractor_v0.6.1", + "date": "Tue, 19 Sep 2023 00:36:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/package-extractor_v0.6.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/package-extractor_v0.5.3", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/package-extractor_v0.5.2", + "date": "Wed, 06 Sep 2023 19:00:39 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where subdirectory inclusion patterns (ex. \"src/subdir/**/*\") would get ignored during extraction" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/package-extractor_v0.5.1", + "date": "Thu, 24 Aug 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.38`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/package-extractor_v0.5.0", + "date": "Wed, 23 Aug 2023 00:20:45 GMT", + "comments": { + "minor": [ + { + "comment": "Add option field dependenciesConfigurations in PackageExtractor to filter files for third party dependencies" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/package-extractor_v0.4.1", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.40`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/package-extractor_v0.4.0", + "date": "Fri, 04 Aug 2023 15:22:44 GMT", + "comments": { + "minor": [ + { + "comment": "Include an API for getting files that are included in a npm package." + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/package-extractor_v0.3.13", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.39`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/package-extractor_v0.3.12", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.38`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/package-extractor_v0.3.11", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.37`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/package-extractor_v0.3.10", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.36`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/package-extractor_v0.3.9", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.35`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/package-extractor_v0.3.8", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.34`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/package-extractor_v0.3.7", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.33`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/package-extractor_v0.3.6", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.32`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/package-extractor_v0.3.5", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.31`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/package-extractor_v0.3.4", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.30`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/package-extractor_v0.3.3", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.29`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/package-extractor_v0.3.2", + "date": "Mon, 26 Jun 2023 23:45:21 GMT", + "comments": { + "patch": [ + { + "comment": "Fix patternsToInclude and patternsToExclude filters when provided patterns target subdirectories of folders that do not match the provided patterns" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/package-extractor_v0.3.1", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.28`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/package-extractor_v0.3.0", + "date": "Sat, 17 Jun 2023 00:21:54 GMT", + "comments": { + "minor": [ + { + "comment": "Allow for include and exclude filters to be provided for projects. This allows for an additional layer of filtering when extracting a package." + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/package-extractor_v0.2.18", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.27`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/package-extractor_v0.2.17", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.26`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/package-extractor_v0.2.16", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.25`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/package-extractor_v0.2.15", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.24`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/package-extractor_v0.2.14", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.23`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/package-extractor_v0.2.13", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.22`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/package-extractor_v0.2.12", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.21`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/package-extractor_v0.2.11", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.20`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/package-extractor_v0.2.10", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.19`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/package-extractor_v0.2.9", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.18`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/package-extractor_v0.2.8", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.17`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/package-extractor_v0.2.7", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.16`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/package-extractor_v0.2.6", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.15`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/package-extractor_v0.2.5", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.14`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/package-extractor_v0.2.4", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.13`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/package-extractor_v0.2.3", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.12`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/package-extractor_v0.2.2", + "date": "Fri, 05 May 2023 00:23:06 GMT", + "comments": { + "patch": [ + { + "comment": "Export typings for the extractor-metadata.json file" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/package-extractor_v0.2.1", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.10.11`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/package-extractor_v0.2.0", + "date": "Wed, 03 May 2023 00:17:46 GMT", + "comments": { + "minor": [ + { + "comment": "Bundle the `create-links` script to ensure any imports that are added in the future don't cause issues." + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/package-extractor_v0.1.3", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/package-extractor_v0.1.2", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/package-extractor_v0.1.1", + "date": "Fri, 28 Apr 2023 19:36:47 GMT", + "comments": { + "patch": [ + { + "comment": "Fix typings reference in package.json" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/package-extractor_v0.1.0", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "minor": [ + { + "comment": "Create new @rushstack/package-extractor package allowing for deployment of a target package and associated dependencies" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + } + ] + } + } + ] +} diff --git a/libraries/package-extractor/CHANGELOG.md b/libraries/package-extractor/CHANGELOG.md new file mode 100644 index 00000000000..d48e746f1aa --- /dev/null +++ b/libraries/package-extractor/CHANGELOG.md @@ -0,0 +1,936 @@ +# Change Log - @rushstack/package-extractor + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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 + +_Version update only_ + +## 0.10.4 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.10.3 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.10.2 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.10.1 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.10.0 +Thu, 24 Oct 2024 15:11:19 GMT + +### Minor changes + +- Add bin linking support when calling the create-links.js script with the "--link-bins" parameter + +## 0.9.9 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.9.8 +Tue, 22 Oct 2024 22:12:40 GMT + +### Patches + +- Fix an issue where the `node_modules/.bin` folder symlinks were not created for extracted packages when using the "default" link creation mode + +## 0.9.7 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.9.6 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.9.5 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.9.4 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.9.3 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.9.2 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.9.1 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.9.0 +Mon, 16 Sep 2024 02:09:00 GMT + +### Minor changes + +- Add a `files` field to the `extractor-metadata.json` file + +## 0.8.1 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.8.0 +Wed, 11 Sep 2024 19:54:47 GMT + +### Minor changes + +- Add the ability to change where the "create-links.js" file and the associated metadata file are generated when running in the "script" linkCreation mode + +## 0.7.26 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.7.25 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.7.24 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.7.23 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.7.22 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.7.21 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.7.20 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.7.19 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.7.18 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.7.17 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.7.16 +Fri, 07 Jun 2024 15:10:25 GMT + +_Version update only_ + +## 0.7.15 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.7.14 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.7.13 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.7.12 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.7.11 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.7.10 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.7.9 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.7.8 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.7.7 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.7.6 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.7.5 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.7.4 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.7.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.7.2 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.7.1 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.7.0 +Thu, 18 Apr 2024 23:19:43 GMT + +### Minor changes + +- Add support for Rush subspaces + +## 0.6.43 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.6.42 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.6.41 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.6.40 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.6.39 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.6.38 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.6.37 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.6.36 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.6.35 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.6.34 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.6.33 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.6.32 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.6.31 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.6.30 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.6.29 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.6.28 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.6.27 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.6.26 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.6.25 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.6.24 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.6.23 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.6.22 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.6.21 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.6.20 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.6.19 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.6.18 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.6.17 +Tue, 12 Dec 2023 00:20:33 GMT + +### Patches + +- Fix an issue with the `folderToCopy` option, where the folder contents would be copied into a subfolder instead of into the target folder root. + +## 0.6.16 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.6.15 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.6.14 +Thu, 16 Nov 2023 01:09:56 GMT + +### Patches + +- Links that target a path outside of the source directory can now be ignored using "patternsToInclude" and "patternsToExclude" options + +## 0.6.13 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.6.12 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.6.11 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.6.10 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.6.9 +Sat, 30 Sep 2023 00:20:51 GMT + +### Patches + +- Ensure the "folderToCopy" field is included in generated archives + +## 0.6.8 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.6.7 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.6.6 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.6.5 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.6.4 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.6.3 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.6.2 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.6.1 +Tue, 19 Sep 2023 00:36:30 GMT + +_Version update only_ + +## 0.6.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.5.3 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.5.2 +Wed, 06 Sep 2023 19:00:39 GMT + +### Patches + +- Fix an issue where subdirectory inclusion patterns (ex. "src/subdir/**/*") would get ignored during extraction + +## 0.5.1 +Thu, 24 Aug 2023 15:20:46 GMT + +_Version update only_ + +## 0.5.0 +Wed, 23 Aug 2023 00:20:45 GMT + +### Minor changes + +- Add option field dependenciesConfigurations in PackageExtractor to filter files for third party dependencies + +## 0.4.1 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.4.0 +Fri, 04 Aug 2023 15:22:44 GMT + +### Minor changes + +- Include an API for getting files that are included in a npm package. + +## 0.3.13 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.3.12 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.3.11 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.3.10 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.3.9 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.3.8 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.3.7 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.3.6 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.3.5 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.3.4 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.3.3 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.3.2 +Mon, 26 Jun 2023 23:45:21 GMT + +### Patches + +- Fix patternsToInclude and patternsToExclude filters when provided patterns target subdirectories of folders that do not match the provided patterns + +## 0.3.1 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.3.0 +Sat, 17 Jun 2023 00:21:54 GMT + +### Minor changes + +- Allow for include and exclude filters to be provided for projects. This allows for an additional layer of filtering when extracting a package. + +## 0.2.18 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.2.17 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.2.16 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.2.15 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.2.14 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.2.13 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.2.12 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.2.11 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.2.10 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.2.9 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.2.8 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.2.7 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.2.6 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 0.2.5 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.4 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.2.3 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.2.2 +Fri, 05 May 2023 00:23:06 GMT + +### Patches + +- Export typings for the extractor-metadata.json file + +## 0.2.1 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.2.0 +Wed, 03 May 2023 00:17:46 GMT + +### Minor changes + +- Bundle the `create-links` script to ensure any imports that are added in the future don't cause issues. + +## 0.1.3 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.1.2 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.1.1 +Fri, 28 Apr 2023 19:36:47 GMT + +### Patches + +- Fix typings reference in package.json + +## 0.1.0 +Thu, 27 Apr 2023 17:18:42 GMT + +### Minor changes + +- Create new @rushstack/package-extractor package allowing for deployment of a target package and associated dependencies + diff --git a/libraries/package-extractor/LICENSE b/libraries/package-extractor/LICENSE new file mode 100644 index 00000000000..5e85ef99645 --- /dev/null +++ b/libraries/package-extractor/LICENSE @@ -0,0 +1,24 @@ +@rushstack/package-extractor + +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/libraries/package-extractor/README.md b/libraries/package-extractor/README.md new file mode 100644 index 00000000000..6bdf6b3af4a --- /dev/null +++ b/libraries/package-extractor/README.md @@ -0,0 +1,12 @@ +## @rushstack/package-extractor + +A library used for creating an isolated copy of a package and, optionally, bundling it into an archive. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/deploy-manager/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/deploy-manager/) + +`@rushstack/package-extractor` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/package-extractor/config/api-extractor.json b/libraries/package-extractor/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/package-extractor/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/package-extractor/config/heft.json b/libraries/package-extractor/config/heft.json new file mode 100644 index 00000000000..e345f0f7b15 --- /dev/null +++ b/libraries/package-extractor/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", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + } + } + }, + + "test": { + "cleanFiles": [{ "sourcePath": "test-output" }] + } + } +} diff --git a/libraries/package-extractor/config/jest.config.json b/libraries/package-extractor/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/package-extractor/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/package-extractor/config/rig.json b/libraries/package-extractor/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/package-extractor/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/package-extractor/config/typescript.json b/libraries/package-extractor/config/typescript.json new file mode 100644 index 00000000000..587de5fc0f8 --- /dev/null +++ b/libraries/package-extractor/config/typescript.json @@ -0,0 +1,12 @@ +{ + "$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 new file mode 100644 index 00000000000..4bebce7970e --- /dev/null +++ b/libraries/package-extractor/package.json @@ -0,0 +1,41 @@ +{ + "name": "@rushstack/package-extractor", + "version": "0.11.8", + "description": "A library for bundling selected files and dependencies into a deployable package.", + "main": "lib/index.js", + "typings": "dist/package-extractor.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/package-extractor" + }, + "scripts": { + "build": "heft build --clean", + "test": "heft test --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "license": "MIT", + "dependencies": { + "@pnpm/link-bins": "~5.3.7", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "ignore": "~5.1.6", + "jszip": "~3.8.0", + "minimatch": "10.0.3", + "npm-packlist": "~2.1.2", + "semver": "~7.5.4" + }, + "devDependencies": { + "local-node-rig": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", + "@types/glob": "7.1.1", + "@types/npm-packlist": "~1.1.1", + "eslint": "~9.37.0", + "webpack": "~5.98.0", + "@types/semver": "7.5.0" + } +} diff --git a/libraries/package-extractor/src/ArchiveManager.ts b/libraries/package-extractor/src/ArchiveManager.ts new file mode 100644 index 00000000000..a463fbe45af --- /dev/null +++ b/libraries/package-extractor/src/ArchiveManager.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. + +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. +const DEFAULT_FILE_PERMISSIONS: number = 0o755; +// This value sets the allowed permissions when preserving symbolic links. +// 120000 is the symbolic link identifier, and is OR'd with the default file permissions. +// See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/stat.h#n10 +// eslint-disable-next-line no-bitwise +const SYMBOLIC_LINK_PERMISSIONS: number = 0o120000 | DEFAULT_FILE_PERMISSIONS; + +export interface IAddToArchiveOptions { + filePath?: string; + fileData?: Buffer | string; + archivePath: string; + stats?: FileSystemStats; +} + +export class ArchiveManager { + private _zip: JSZip = new JSZip(); + + public async addToArchiveAsync(options: IAddToArchiveOptions): Promise { + const { filePath, fileData, archivePath } = options; + + let data: Buffer | string; + let permissions: number; + if (filePath) { + const stats: FileSystemStats = options.stats ?? (await FileSystem.getLinkStatisticsAsync(filePath)); + if (stats.isSymbolicLink()) { + data = await FileSystem.readLinkAsync(filePath); + permissions = SYMBOLIC_LINK_PERMISSIONS; + } else if (stats.isDirectory()) { + throw new Error('Directories cannot be added to the archive'); + } else { + data = await FileSystem.readFileToBufferAsync(filePath); + permissions = stats.mode; + } + } else if (fileData) { + data = fileData; + permissions = DEFAULT_FILE_PERMISSIONS; + } else { + throw new Error('Either filePath or fileData must be provided'); + } + + // Replace backslashes for Unix compat + const addPath: string = Path.convertToSlashes(archivePath); + this._zip.file(addPath, data, { + unixPermissions: permissions, + dir: false + }); + } + + public async createArchiveAsync(archiveFilePath: string): Promise { + const zipContent: Buffer = await this._zip.generateAsync({ + type: 'nodebuffer', + platform: 'UNIX' + }); + await FileSystem.writeFileAsync(archiveFilePath, zipContent); + } +} diff --git a/libraries/package-extractor/src/AssetHandler.ts b/libraries/package-extractor/src/AssetHandler.ts new file mode 100644 index 00000000000..e177c009067 --- /dev/null +++ b/libraries/package-extractor/src/AssetHandler.ts @@ -0,0 +1,234 @@ +// 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 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'; +import { remapSourcePathForTargetFolder } from './Utils'; + +export interface IIncludeAssetOptions { + sourceFilePath?: string; + sourceFileStats?: FileSystemStats; + sourceFileContent?: string | Buffer; + targetFilePath: string; + ignoreIfExisting?: boolean; +} + +export interface IIncludeAssetPathOptions extends IIncludeAssetOptions { + sourceFilePath: string; + sourceFileContent?: never; +} + +export interface IIncludeExistingAssetPathOptions extends IIncludeAssetOptions { + sourceFilePath?: never; + sourceFileContent?: never; +} + +export interface IIncludeAssetContentOptions extends IIncludeAssetOptions { + sourceFileContent: string | Buffer; + sourceFilePath?: never; + sourceFileStats?: never; +} + +export interface IAssetHandlerOptions extends IExtractorOptions { + symlinkAnalyzer: SymlinkAnalyzer; +} + +export interface IFinalizeOptions { + onAfterExtractSymlinksAsync: () => Promise; +} + +export class AssetHandler { + private readonly _terminal: ITerminal; + private readonly _sourceRootFolder: string; + private readonly _targetRootFolder: string; + private readonly _createArchiveOnly: boolean; + private readonly _symlinkAnalyzer: SymlinkAnalyzer; + private readonly _archiveManager: ArchiveManager | undefined; + private readonly _archiveFilePath: string | undefined; + private readonly _linkCreationMode: LinkCreationMode; + private readonly _includedAssetPaths: Set = new Set(); + private _isFinalized: boolean = false; + + public constructor(options: IAssetHandlerOptions) { + const { + terminal, + sourceRootFolder, + targetRootFolder, + linkCreation, + symlinkAnalyzer, + createArchiveFilePath, + createArchiveOnly = false + } = options; + this._terminal = terminal; + this._sourceRootFolder = sourceRootFolder; + this._targetRootFolder = targetRootFolder; + this._symlinkAnalyzer = symlinkAnalyzer; + if (createArchiveFilePath) { + if (path.extname(createArchiveFilePath) !== '.zip') { + throw new Error('Only archives with the .zip file extension are currently supported.'); + } + this._archiveFilePath = path.resolve(targetRootFolder, createArchiveFilePath); + this._archiveManager = new ArchiveManager(); + } + if (createArchiveOnly && !this._archiveManager) { + throw new Error('createArchiveOnly cannot be true if createArchiveFilePath is not provided'); + } + this._createArchiveOnly = createArchiveOnly; + this._linkCreationMode = linkCreation || 'default'; + } + + public async includeAssetAsync(options: IIncludeAssetPathOptions): Promise; + public async includeAssetAsync(options: IIncludeExistingAssetPathOptions): Promise; + public async includeAssetAsync(options: IIncludeAssetContentOptions): Promise; + public async includeAssetAsync(options: IIncludeAssetOptions): Promise { + const { sourceFileContent, targetFilePath, ignoreIfExisting = false } = options; + let { sourceFilePath } = options; + + if (this._isFinalized) { + throw new Error('includeAssetAsync() cannot be called after finalizeAsync()'); + } + if (!sourceFilePath && !sourceFileContent) { + if (!Path.isUnder(targetFilePath, this._targetRootFolder)) { + throw new Error('The existing asset path must be under the target root folder'); + } + sourceFilePath = targetFilePath; + } + if (sourceFilePath && sourceFileContent) { + throw new Error('Either sourceFilePath or sourceFileContent must be provided, but not both'); + } + if (this._includedAssetPaths.has(targetFilePath)) { + if (ignoreIfExisting) { + return; + } + throw new Error(`The asset at path "${targetFilePath}" has already been included`); + } + + if (!this._createArchiveOnly) { + // Ignore when the source file is the same as the target file, as it's a no-op + if (sourceFilePath && sourceFilePath !== targetFilePath) { + // Use the fs.copyFile API instead of FileSystem.copyFileAsync() since copyFileAsync performs + // a needless stat() call to determine if it's a file or folder, and we already know it's a file. + try { + await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL); + } catch (e: unknown) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + // The parent folder may not exist, so ensure it exists before trying to copy again + await FileSystem.ensureFolderAsync(path.dirname(targetFilePath)); + await fs.promises.copyFile(sourceFilePath, targetFilePath, fs.constants.COPYFILE_EXCL); + } + } else if (sourceFileContent) { + await FileSystem.writeFileAsync(targetFilePath, sourceFileContent, { + ensureFolderExists: true + }); + } + } + + if (this._archiveManager) { + const targetRelativeFilePath: string = path.relative(this._targetRootFolder, targetFilePath); + if (sourceFilePath) { + await this._archiveManager.addToArchiveAsync({ + filePath: sourceFilePath, + archivePath: targetRelativeFilePath + }); + } else if (sourceFileContent) { + await this._archiveManager.addToArchiveAsync({ + fileData: sourceFileContent, + archivePath: targetRelativeFilePath + }); + } + } + + this._includedAssetPaths.add(targetFilePath); + } + + public get assetPaths(): string[] { + return [...this._includedAssetPaths]; + } + + public async finalizeAsync(options?: IFinalizeOptions): Promise { + const { onAfterExtractSymlinksAsync } = options ?? {}; + + if (this._isFinalized) { + throw new Error('finalizeAsync() has already been called'); + } + + if (this._linkCreationMode === 'default') { + this._terminal.writeLine('Creating symlinks'); + const linksToCopy: ILinkInfo[] = this._symlinkAnalyzer.reportSymlinks(); + await Async.forEachAsync(linksToCopy, async (linkToCopy: ILinkInfo) => { + await this._extractSymlinkAsync(linkToCopy); + }); + } + + await onAfterExtractSymlinksAsync?.(); + + if (this._archiveManager && this._archiveFilePath) { + this._terminal.writeLine(`Creating archive at "${this._archiveFilePath}"`); + await this._archiveManager.createArchiveAsync(this._archiveFilePath); + } + + this._isFinalized = true; + } + + /** + * Create a symlink as described by the ILinkInfo object. + */ + private async _extractSymlinkAsync(linkInfo: ILinkInfo): Promise { + const { kind, linkPath, targetPath } = { + ...linkInfo, + linkPath: remapSourcePathForTargetFolder({ + sourceRootFolder: this._sourceRootFolder, + targetRootFolder: this._targetRootFolder, + sourcePath: linkInfo.linkPath + }), + targetPath: remapSourcePathForTargetFolder({ + sourceRootFolder: this._sourceRootFolder, + targetRootFolder: this._targetRootFolder, + sourcePath: linkInfo.targetPath + }) + }; + + const newLinkFolder: string = path.dirname(linkPath); + await FileSystem.ensureFolderAsync(newLinkFolder); + + // Link to the relative path for symlinks + const relativeTargetPath: string = path.relative(newLinkFolder, targetPath); + + // NOTE: This logic is based on NpmLinkManager._createSymlink() + if (kind === 'fileLink') { + // For files, we use a Windows "hard link", because creating a symbolic link requires + // administrator permission. However hard links seem to cause build failures on Mac, + // so for all other operating systems we use symbolic links for this case. + if (process.platform === 'win32') { + await FileSystem.createHardLinkAsync({ + linkTargetPath: relativeTargetPath, + newLinkPath: linkPath + }); + } else { + await FileSystem.createSymbolicLinkFileAsync({ + linkTargetPath: relativeTargetPath, + newLinkPath: linkPath + }); + } + } else { + // Junctions are only supported on Windows. This will create a symbolic link on other platforms. + await FileSystem.createSymbolicLinkJunctionAsync({ + linkTargetPath: relativeTargetPath, + newLinkPath: linkPath + }); + } + + // Since the created symlinks have the required relative paths, they can be added directly to + // the archive. + await this.includeAssetAsync({ targetFilePath: linkPath }); + } +} diff --git a/libraries/package-extractor/src/PackageExtractor.ts b/libraries/package-extractor/src/PackageExtractor.ts new file mode 100644 index 00000000000..1170c315034 --- /dev/null +++ b/libraries/package-extractor/src/PackageExtractor.ts @@ -0,0 +1,987 @@ +// 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 { Minimatch } from 'minimatch'; +import semver from 'semver'; +import npmPacklist from 'npm-packlist'; +import ignore, { type Ignore } from 'ignore'; + +import { + Async, + AsyncQueue, + Path, + FileSystem, + Import, + JsonFile, + type IPackageJson +} from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import { SymlinkAnalyzer, type ILinkInfo, type PathNode } from './SymlinkAnalyzer'; +import { AssetHandler } from './AssetHandler'; +import { + matchesWithStar, + remapSourcePathForTargetFolder, + remapPathForExtractorMetadata, + makeBinLinksAsync +} from './Utils'; +import { + CREATE_LINKS_SCRIPT_FILENAME, + EXTRACTOR_METADATA_FILENAME, + SCRIPTS_FOLDER_PATH +} from './PathConstants'; +import { MAX_CONCURRENCY } from './scripts/createLinks/utilities/constants'; + +// (@types/npm-packlist is missing this API) +declare module 'npm-packlist' { + export class Walker { + public readonly result: string[]; + public constructor(opts: { path: string }); + public on(event: 'done', callback: (result: string[]) => void): Walker; + public on(event: 'error', callback: (error: Error) => void): Walker; + public start(): void; + } +} + +export const TARGET_ROOT_SCRIPT_RELATIVE_PATH_TEMPLATE_STRING: '{TARGET_ROOT_SCRIPT_RELATIVE_PATH}' = + '{TARGET_ROOT_SCRIPT_RELATIVE_PATH}'; + +/** + * Part of the extractor-matadata.json file format. Represents an extracted project. + * + * @public + */ +export interface IProjectInfoJson { + /** + * The name of the project as specified in its package.json file. + */ + projectName: string; + /** + * This path is relative to the root of the extractor output folder + */ + path: string; +} + +/** + * The extractor-metadata.json file format. + * + * @public + */ +export interface IExtractorMetadataJson { + /** + * The name of the main project the extraction was performed for. + */ + mainProjectName: string; + /** + * A list of all projects that were extracted. + */ + projects: IProjectInfoJson[]; + /** + * A list of all links that are part of the extracted project. + */ + links: ILinkInfo[]; + /** + * A list of all files that are part of the extracted project. + */ + files: string[]; +} + +/** + * The extractor subspace configurations + * + * @public + */ +export interface IExtractorSubspace { + /** + * The subspace name + */ + subspaceName: string; + /** + * The folder where the PNPM "node_modules" folder is located. This is used to resolve packages linked + * to the PNPM virtual store. + */ + pnpmInstallFolder?: string; + /** + * The pnpmfile configuration if using PNPM, otherwise undefined. The configuration will be used to + * transform the package.json prior to extraction. + */ + transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; +} + +interface IExtractorState { + foldersToCopy: Set; + packageJsonByPath: Map; + projectConfigurationsByPath: Map; + projectConfigurationsByName: Map; + dependencyConfigurationsByName: Map; + symlinkAnalyzer: SymlinkAnalyzer; + assetHandler: AssetHandler; +} + +/** + * The extractor configuration for individual projects. + * + * @public + */ +export interface IExtractorProjectConfiguration { + /** + * The name of the project. + */ + projectName: string; + /** + * The absolute path to the project. + */ + projectFolder: string; + /** + * A list of glob patterns to include when extracting this project. If a path is + * matched by both "patternsToInclude" and "patternsToExclude", the path will be + * excluded. If undefined, all paths will be included. + */ + patternsToInclude?: string[]; + /** + * A list of glob patterns to exclude when extracting this project. If a path is + * matched by both "patternsToInclude" and "patternsToExclude", the path will be + * excluded. If undefined, no paths will be excluded. + */ + patternsToExclude?: string[]; + /** + * The names of additional projects to include when extracting this project. + */ + additionalProjectsToInclude?: string[]; + /** + * The names of additional dependencies to include when extracting this project. + */ + additionalDependenciesToInclude?: string[]; + /** + * The names of additional dependencies to exclude when extracting this project. + */ + dependenciesToExclude?: string[]; +} + +/** + * The extractor configuration for individual dependencies. + * + * @public + */ +export interface IExtractorDependencyConfiguration { + /** + * The name of dependency + */ + dependencyName: string; + /** + * The semver version range of dependency + */ + dependencyVersionRange: string; + /** + * A list of glob patterns to exclude when extracting this dependency. If a path is + * matched by both "patternsToInclude" and "patternsToExclude", the path will be + * excluded. If undefined, no paths will be excluded. + */ + patternsToExclude?: string[]; + /** + * A list of glob patterns to include when extracting this dependency. If a path is + * matched by both "patternsToInclude" and "patternsToExclude", the path will be + * excluded. If undefined, all paths will be included. + */ + patternsToInclude?: string[]; +} + +/** + * The mode to use for link creation. + * + * @public + */ +export type LinkCreationMode = 'default' | 'script' | 'none'; + +/** + * Options that can be provided to the extractor. + * + * @public + */ +export interface IExtractorOptions { + /** + * A terminal to log extraction progress. + */ + terminal: ITerminal; + + /** + * The main project to include in the extraction operation. + */ + mainProjectName: string; + + /** + * The source folder that copying originates from. Generally it is the repo root folder. + */ + sourceRootFolder: string; + + /** + * The target folder for the extraction. + */ + targetRootFolder: string; + + /** + * Whether to overwrite the target folder if it already exists. + */ + overwriteExisting: boolean; + + /** + * The desired path to be used when archiving the target folder. Supported file extensions: .zip. + */ + createArchiveFilePath?: string; + + /** + * Whether to skip copying files to the extraction target directory, and only create an extraction + * archive. This is only supported when {@link IExtractorOptions.linkCreation} is 'script' or 'none'. + */ + createArchiveOnly?: boolean; + + /** + * The pnpmfile configuration if using PNPM, otherwise `undefined`. The configuration will be used to + * transform the package.json prior to extraction. + * + * @remarks + * When Rush subspaces are enabled, this setting applies to `default` subspace only. To configure + * each subspace, use the {@link IExtractorOptions.subspaces} array instead. The two approaches + * cannot be combined. + */ + transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; + + /** + * If dependencies from the "devDependencies" package.json field should be included in the extraction. + */ + includeDevDependencies?: boolean; + + /** + * If files ignored by the .npmignore file should be included in the extraction. + */ + includeNpmIgnoreFiles?: boolean; + + /** + * The folder where the PNPM "node_modules" folder is located. This is used to resolve packages linked + * to the PNPM virtual store. + * + * @remarks + * When Rush subspaces are enabled, this setting applies to `default` subspace only. To configure + * each subspace, use the {@link IExtractorOptions.subspaces} array instead. The two approaches + * cannot be combined. + */ + pnpmInstallFolder?: string; + + /** + * The link creation mode to use. + * "default": Create the links while copying the files; this is the default behavior. Use this setting + * if your file copy tool can handle links correctly. + * "script": A Node.js script called create-links.js will be written to the target folder. Use this setting + * to create links on the server machine, after the files have been uploaded. + * "none": Do nothing; some other tool may create the links later, based on the extractor-metadata.json file. + */ + linkCreation?: LinkCreationMode; + + /** + * The path to the generated link creation script. This is only used when {@link IExtractorOptions.linkCreation} + * is 'script'. + */ + linkCreationScriptPath?: string; + + /** + * An additional folder containing files which will be copied into the root of the extraction. + */ + folderToCopy?: string; + + /** + * Configurations for individual projects, keyed by the project path relative to the sourceRootFolder. + */ + projectConfigurations: IExtractorProjectConfiguration[]; + + /** + * Configurations for individual dependencies. + */ + dependencyConfigurations?: IExtractorDependencyConfiguration[]; + + /** + * When using Rush subspaces, this setting can be used to provide configuration information for each + * individual subspace. + * + * @remarks + * To avoid confusion, if this setting is used, then the {@link IExtractorOptions.transformPackageJson} and + * {@link IExtractorOptions.pnpmInstallFolder} settings must not be used. + */ + subspaces?: IExtractorSubspace[]; +} + +/** + * Manages the business logic for the "rush deploy" command. + * + * @public + */ +export class PackageExtractor { + /** + * Get a list of files that would be included in a package created from the provided package root path. + * + * @beta + */ + public static async getPackageIncludedFilesAsync(packageRootPath: string): Promise { + // Use npm-packlist to filter the files. Using the Walker class (instead of the default API) ensures + // that "bundledDependencies" are not included. + const walkerPromise: Promise = new Promise( + (resolve: (result: string[]) => void, reject: (error: Error) => void) => { + const walker: npmPacklist.Walker = new npmPacklist.Walker({ + path: packageRootPath + }); + walker.on('done', resolve).on('error', reject).start(); + } + ); + const npmPackFiles: string[] = await walkerPromise; + return npmPackFiles; + } + + /** + * Extract a package using the provided options + */ + public async extractAsync(options: IExtractorOptions): Promise { + options = PackageExtractor._normalizeOptions(options); + const { + terminal, + projectConfigurations, + sourceRootFolder, + targetRootFolder, + mainProjectName, + overwriteExisting, + dependencyConfigurations, + linkCreation + } = options; + + terminal.writeLine(Colorize.cyan(`Extracting to target folder: ${targetRootFolder}`)); + terminal.writeLine(Colorize.cyan(`Main project for extraction: ${mainProjectName}`)); + + await FileSystem.ensureFolderAsync(targetRootFolder); + const existingExtraction: boolean = + (await FileSystem.readFolderItemNamesAsync(targetRootFolder)).length > 0; + if (existingExtraction) { + if (!overwriteExisting) { + throw new Error('The extraction target folder is not empty. Overwrite must be explicitly requested'); + } + terminal.writeLine('Deleting target folder contents...'); + terminal.writeLine(''); + await FileSystem.ensureEmptyFolderAsync(targetRootFolder); + } + + // Create a new state for each run + const symlinkAnalyzer: SymlinkAnalyzer = new SymlinkAnalyzer({ + requiredSourceParentPath: sourceRootFolder + }); + const state: IExtractorState = { + symlinkAnalyzer, + assetHandler: new AssetHandler({ ...options, symlinkAnalyzer }), + foldersToCopy: new Set(), + packageJsonByPath: new Map(), + projectConfigurationsByName: new Map(projectConfigurations.map((p) => [p.projectName, p])), + projectConfigurationsByPath: new Map(projectConfigurations.map((p) => [p.projectFolder, p])), + dependencyConfigurationsByName: new Map() + }; + + // set state dependencyConfigurationsByName + for (const dependencyConfiguration of dependencyConfigurations || []) { + const { dependencyName } = dependencyConfiguration; + let existingDependencyConfigurations: IExtractorDependencyConfiguration[] | undefined = + state.dependencyConfigurationsByName.get(dependencyName); + if (!existingDependencyConfigurations) { + existingDependencyConfigurations = []; + state.dependencyConfigurationsByName.set(dependencyName, existingDependencyConfigurations); + } + existingDependencyConfigurations.push(dependencyConfiguration); + } + + await this._performExtractionAsync(options, state); + await state.assetHandler.finalizeAsync({ + onAfterExtractSymlinksAsync: async () => { + // We need the symlinks to be created before attempting to create the bin links, since it requires + // the node_modules folder to be realized. While we're here, we may as well perform some specific + // link creation tasks and write the extractor-metadata.json file before the asset handler finalizes. + if (linkCreation === 'default') { + await this._makeBinLinksAsync(options, state); + } else if (linkCreation === 'script') { + await this._writeCreateLinksScriptAsync(options, state); + } + + terminal.writeLine('Creating extractor-metadata.json'); + await this._writeExtractorMetadataAsync(options, state); + } + }); + } + + 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, + mainProjectName, + sourceRootFolder, + targetRootFolder, + folderToCopy: additionalFolderToCopy, + createArchiveOnly + } = options; + const { projectConfigurationsByName, foldersToCopy } = state; + + const mainProjectConfiguration: IExtractorProjectConfiguration | undefined = + projectConfigurationsByName.get(mainProjectName); + if (!mainProjectConfiguration) { + throw new Error(`Main project "${mainProjectName}" was not found in the list of projects`); + } + + // Calculate the set with additionalProjectsToInclude + const includedProjectsSet: Set = new Set([mainProjectConfiguration]); + for (const { additionalProjectsToInclude } of includedProjectsSet) { + if (additionalProjectsToInclude) { + for (const additionalProjectNameToInclude of additionalProjectsToInclude) { + const additionalProjectToInclude: IExtractorProjectConfiguration | undefined = + projectConfigurationsByName.get(additionalProjectNameToInclude); + if (!additionalProjectToInclude) { + throw new Error( + `Project "${additionalProjectNameToInclude}" was not found in the list of projects.` + ); + } + includedProjectsSet.add(additionalProjectToInclude); + } + } + } + + for (const { projectName, projectFolder } of includedProjectsSet) { + terminal.writeLine(Colorize.cyan(`Analyzing project: ${projectName}`)); + await this._collectFoldersAsync(projectFolder, options, state); + } + + if (!createArchiveOnly) { + terminal.writeLine(`Copying folders to target folder "${targetRootFolder}"`); + } + await Async.forEachAsync( + foldersToCopy, + async (folderToCopy: string) => { + await this._extractFolderAsync(folderToCopy, options, state); + }, + { + concurrency: MAX_CONCURRENCY + } + ); + + if (additionalFolderToCopy) { + // Copy the additional folder directly into the root of the target folder by setting the sourceRootFolder + // to the root of the folderToCopy + const additionalFolderPath: string = path.resolve(sourceRootFolder, additionalFolderToCopy); + const additionalFolderExtractorOptions: IExtractorOptions = { + ...options, + sourceRootFolder: additionalFolderPath, + targetRootFolder + }; + await this._extractFolderAsync(additionalFolderPath, additionalFolderExtractorOptions, state); + } + } + + /** + * Recursively crawl the node_modules dependencies and collect the result in IExtractorState.foldersToCopy. + */ + private async _collectFoldersAsync( + packageJsonFolder: string, + options: IExtractorOptions, + state: IExtractorState + ): Promise { + const { terminal, subspaces } = options; + const { projectConfigurationsByPath } = state; + + const packageJsonFolderPathQueue: AsyncQueue = new AsyncQueue([packageJsonFolder]); + + await Async.forEachAsync( + packageJsonFolderPathQueue, + async ([packageJsonFolderPath, callback]: [string, () => void]) => { + const packageJsonRealFolderPath: string = await FileSystem.getRealPathAsync(packageJsonFolderPath); + if (state.foldersToCopy.has(packageJsonRealFolderPath)) { + // we've already seen this folder + callback(); + return; + } + state.foldersToCopy.add(packageJsonRealFolderPath); + + const originalPackageJson: IPackageJson = await JsonFile.loadAsync( + path.join(packageJsonRealFolderPath, 'package.json') + ); + + const targetSubspace: IExtractorSubspace | undefined = subspaces?.find( + (subspace) => + subspace.pnpmInstallFolder && Path.isUnder(packageJsonFolderPath, subspace.pnpmInstallFolder) + ); + + // Transform packageJson using the provided transformer, if requested + const packageJson: IPackageJson = + targetSubspace?.transformPackageJson?.(originalPackageJson) ?? originalPackageJson; + + state.packageJsonByPath.set(packageJsonRealFolderPath, packageJson); + // Union of keys from regular dependencies, peerDependencies, optionalDependencies + // (and possibly devDependencies if includeDevDependencies=true) + const dependencyNamesToProcess: Set = new Set(); + + // Just the keys from optionalDependencies and peerDependencies + const optionalDependencyNames: Set = new Set(); + + for (const name of Object.keys(packageJson.dependencies || {})) { + dependencyNamesToProcess.add(name); + } + for (const name of Object.keys(packageJson.peerDependencies || {})) { + dependencyNamesToProcess.add(name); + optionalDependencyNames.add(name); // consider peers optional, since they are so frequently broken + } + for (const name of Object.keys(packageJson.optionalDependencies || {})) { + dependencyNamesToProcess.add(name); + optionalDependencyNames.add(name); + } + + // Check to see if this is a local project + const projectConfiguration: IExtractorProjectConfiguration | undefined = + projectConfigurationsByPath.get(packageJsonRealFolderPath); + + if (projectConfiguration) { + if (options.includeDevDependencies) { + for (const name of Object.keys(packageJson.devDependencies || {})) { + dependencyNamesToProcess.add(name); + } + } + + this._applyDependencyFilters( + terminal, + dependencyNamesToProcess, + projectConfiguration.additionalDependenciesToInclude, + projectConfiguration.dependenciesToExclude + ); + } + + for (const dependencyPackageName of dependencyNamesToProcess) { + try { + const dependencyPackageFolderPath: string = await Import.resolvePackageAsync({ + packageName: dependencyPackageName, + baseFolderPath: packageJsonRealFolderPath, + getRealPathAsync: async (filePath: string) => { + try { + return (await state.symlinkAnalyzer.analyzePathAsync({ inputPath: filePath })).nodePath; + } catch (error: unknown) { + if (FileSystem.isFileDoesNotExistError(error as Error)) { + return filePath; + } + throw error; + } + } + }); + packageJsonFolderPathQueue.push(dependencyPackageFolderPath); + } catch (resolveErr) { + if (optionalDependencyNames.has(dependencyPackageName)) { + // Ignore missing optional dependency + continue; + } + throw resolveErr; + } + } + + // 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. + const realPnpmInstallFolder: string | undefined = targetSubspace?.pnpmInstallFolder; + if (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. + // TODO: This can be configured via NPMRC. We should support that. + const pnpmDotFolderPath: string = path.join(realPnpmInstallFolder, 'node_modules', '.pnpm'); + + // TODO: Investigate how package aliases are handled by PNPM in this case. For example: + // + // "dependencies": { + // "alias-name": "npm:real-name@^1.2.3" + // } + const dependencyPackageFolderPath: string = await Import.resolvePackageAsync({ + packageName: packageJson.name, + baseFolderPath: pnpmDotFolderPath, + getRealPathAsync: async (filePath: string) => { + try { + return (await state.symlinkAnalyzer.analyzePathAsync({ inputPath: filePath })).nodePath; + } catch (error: unknown) { + if (FileSystem.isFileDoesNotExistError(error as Error)) { + return filePath; + } + throw error; + } + } + }); + packageJsonFolderPathQueue.push(dependencyPackageFolderPath); + } catch (resolveErr) { + // The virtual store link isn't guaranteed to exist, so ignore if it's missing + // NOTE: If you encounter this warning a lot, please report it to the Rush maintainers. + // eslint-disable-next-line no-console + console.log('Ignoring missing PNPM virtual store link for ' + packageJsonFolderPath); + } + } + + callback(); + }, + { + concurrency: MAX_CONCURRENCY + } + ); + } + + private _applyDependencyFilters( + terminal: ITerminal, + allDependencyNames: Set, + additionalDependenciesToInclude: string[] = [], + dependenciesToExclude: string[] = [] + ): Set { + // Track packages that got added/removed for reporting purposes + const extraIncludedPackageNames: string[] = []; + const extraExcludedPackageNames: string[] = []; + + for (const patternWithStar of dependenciesToExclude) { + for (const dependency of allDependencyNames) { + if (matchesWithStar(patternWithStar, dependency)) { + if (allDependencyNames.delete(dependency)) { + extraExcludedPackageNames.push(dependency); + } + } + } + } + + for (const dependencyToInclude of additionalDependenciesToInclude) { + if (!allDependencyNames.has(dependencyToInclude)) { + allDependencyNames.add(dependencyToInclude); + extraIncludedPackageNames.push(dependencyToInclude); + } + } + + if (extraIncludedPackageNames.length > 0) { + extraIncludedPackageNames.sort(); + terminal.writeLine(`Extra dependencies included by settings: ${extraIncludedPackageNames.join(', ')}`); + } + + if (extraExcludedPackageNames.length > 0) { + extraExcludedPackageNames.sort(); + terminal.writeLine(`Extra dependencies excluded by settings: ${extraExcludedPackageNames.join(', ')}`); + } + + return allDependencyNames; + } + + /** + * Copy one package folder to the extractor target folder. + */ + private async _extractFolderAsync( + sourceFolderPath: string, + options: IExtractorOptions, + state: IExtractorState + ): Promise { + const { includeNpmIgnoreFiles } = options; + const { projectConfigurationsByPath, packageJsonByPath, dependencyConfigurationsByName, assetHandler } = + state; + let useNpmIgnoreFilter: boolean = false; + + const sourceFolderRealPath: string = await FileSystem.getRealPathAsync(sourceFolderPath); + const sourceProjectConfiguration: IExtractorProjectConfiguration | undefined = + projectConfigurationsByPath.get(sourceFolderRealPath); + + const packagesJson: IPackageJson | undefined = packageJsonByPath.get(sourceFolderRealPath); + // As this function will be used to copy folder for both project inside monorepo and third party + // dependencies insides node_modules. Third party dependencies won't have project configurations + const isLocalProject: boolean = !!sourceProjectConfiguration; + + // Function to filter files inside local project or third party dependencies. + const isFileExcluded = (filePath: string): boolean => { + // Encapsulate exclude logic into a function, so it can be reused. + const excludeFileByPatterns = ( + patternsToInclude: string[] | undefined, + patternsToExclude: string[] | undefined + ): boolean => { + let includeFilters: Minimatch[] | undefined; + let excludeFilters: Minimatch[] | undefined; + if (patternsToInclude?.length) { + includeFilters = patternsToInclude?.map((p) => new Minimatch(p, { dot: true })); + } + if (patternsToExclude?.length) { + excludeFilters = patternsToExclude?.map((p) => new Minimatch(p, { dot: true })); + } + // If there are no filters, then we can't exclude anything. + if (!includeFilters && !excludeFilters) { + return false; + } + + const isIncluded: boolean = !includeFilters || includeFilters.some((m) => m.match(filePath)); + + // If the file is not included, then we don't need to check the excludeFilter. If it is included + // and there is no exclude filter, then we know that the file is not excluded. If it is included + // and there is an exclude filter, then we need to check for a match. + return !isIncluded || !!excludeFilters?.some((m) => m.match(filePath)); + }; + + if (isLocalProject) { + return excludeFileByPatterns( + sourceProjectConfiguration?.patternsToInclude, + sourceProjectConfiguration?.patternsToExclude + ); + } else { + if (!packagesJson) { + return false; + } + const dependenciesConfigurations: IExtractorDependencyConfiguration[] | undefined = + dependencyConfigurationsByName.get(packagesJson.name); + if (!dependenciesConfigurations) { + return false; + } + const matchedDependenciesConfigurations: IExtractorDependencyConfiguration[] = + dependenciesConfigurations.filter((d) => + semver.satisfies(packagesJson.version, d.dependencyVersionRange) + ); + return matchedDependenciesConfigurations.some((d) => + excludeFileByPatterns(d.patternsToInclude, d.patternsToExclude) + ); + } + }; + + if (sourceProjectConfiguration && !includeNpmIgnoreFiles) { + // Only use the npmignore filter if the project configuration explicitly asks for it + useNpmIgnoreFilter = true; + } + + const targetFolderPath: string = remapSourcePathForTargetFolder({ + ...options, + sourcePath: sourceFolderPath + }); + if (useNpmIgnoreFilter) { + const npmPackFiles: string[] = await PackageExtractor.getPackageIncludedFilesAsync(sourceFolderPath); + await Async.forEachAsync( + npmPackFiles, + async (npmPackFile: string) => { + // In issue https://github.com/microsoft/rushstack/issues/2121 we found that npm-packlist sometimes returns + // duplicate file paths, for example: + // + // 'dist//index.js' + // 'dist/index.js' + // + + // Filter out files that are excluded by the project configuration or dependency configuration. + if (isFileExcluded(npmPackFile)) { + return; + } + + const sourceFilePath: string = path.resolve(sourceFolderPath, npmPackFile); + const { kind, linkStats: sourceFileStats } = await state.symlinkAnalyzer.analyzePathAsync({ + inputPath: sourceFilePath + }); + if (kind === 'file') { + const targetFilePath: string = path.resolve(targetFolderPath, npmPackFile); + await assetHandler.includeAssetAsync({ + sourceFilePath, + sourceFileStats, + targetFilePath + }); + } + }, + { + concurrency: MAX_CONCURRENCY + } + ); + } else { + // use a simplistic "ignore" ruleset to filter the files + const ignoreFilter: Ignore = ignore(); + ignoreFilter.add([ + // The top-level node_modules folder is always excluded + '/node_modules', + // Also exclude well-known folders that can contribute a lot of unnecessary files + '**/.git', + '**/.svn', + '**/.hg', + '**/.DS_Store' + ]); + + // Do a breadth-first search of the source folder, copying each file to the target folder + const queue: AsyncQueue = new AsyncQueue([sourceFolderPath]); + await Async.forEachAsync( + queue, + async ([sourcePath, callback]: [string, () => void]) => { + const relativeSourcePath: string = path.relative(sourceFolderPath, sourcePath); + if (relativeSourcePath !== '' && ignoreFilter.ignores(relativeSourcePath)) { + callback(); + return; + } + + const sourcePathNode: PathNode | undefined = await state.symlinkAnalyzer.analyzePathAsync({ + inputPath: sourcePath, + // Treat all links to external paths as if they are files for this scenario. In the future, we may + // want to explore the target of the external link to see if all files within the target are + // excluded, and throw if they are not. + shouldIgnoreExternalLink: (linkSourcePath: string) => { + // Ignore the provided linkSourcePath since it may not be the first link in the chain. Instead, + // we will consider only the relativeSourcePath, since that would be our entrypoint into the + // link chain. + return isFileExcluded(relativeSourcePath); + } + }); + + if (sourcePathNode === undefined) { + // The target was a symlink that is excluded. We don't need to do anything. + callback(); + return; + } else if (sourcePathNode.kind === 'file') { + // Only ignore files and not folders to ensure that we traverse the contents of all folders. This is + // done so that we can match against subfolder patterns, ex. "src/subfolder/**/*" + if (relativeSourcePath !== '' && isFileExcluded(relativeSourcePath)) { + callback(); + return; + } + + const targetFilePath: string = path.resolve(targetFolderPath, relativeSourcePath); + await assetHandler.includeAssetAsync({ + sourceFilePath: sourcePath, + sourceFileStats: sourcePathNode.linkStats, + targetFilePath + }); + } else if (sourcePathNode.kind === 'folder') { + const children: string[] = await FileSystem.readFolderItemNamesAsync(sourcePath); + for (const child of children) { + queue.push(path.join(sourcePath, child)); + } + } + + callback(); + }, + { + concurrency: MAX_CONCURRENCY + } + ); + } + } + + /** + * Write the common/deploy/deploy-metadata.json file. + */ + private async _writeExtractorMetadataAsync( + options: IExtractorOptions, + state: IExtractorState + ): Promise { + const { mainProjectName, sourceRootFolder, targetRootFolder, linkCreation, linkCreationScriptPath } = + options; + const { projectConfigurationsByPath } = state; + + const extractorMetadataFolderPath: string = + linkCreation === 'script' && linkCreationScriptPath + ? path.dirname(path.resolve(targetRootFolder, linkCreationScriptPath)) + : targetRootFolder; + const extractorMetadataFilePath: string = path.join( + extractorMetadataFolderPath, + EXTRACTOR_METADATA_FILENAME + ); + const extractorMetadataJson: IExtractorMetadataJson = { + mainProjectName, + projects: [], + links: [], + files: [] + }; + + for (const { projectFolder, projectName } of projectConfigurationsByPath.values()) { + if (state.foldersToCopy.has(projectFolder)) { + extractorMetadataJson.projects.push({ + projectName, + path: remapPathForExtractorMetadata(sourceRootFolder, projectFolder) + }); + } + } + + // Remap the links to be relative to target folder + for (const { kind, linkPath, targetPath } of state.symlinkAnalyzer.reportSymlinks()) { + extractorMetadataJson.links.push({ + kind, + linkPath: remapPathForExtractorMetadata(sourceRootFolder, linkPath), + targetPath: remapPathForExtractorMetadata(sourceRootFolder, targetPath) + }); + } + + for (const assetPath of state.assetHandler.assetPaths) { + extractorMetadataJson.files.push(remapPathForExtractorMetadata(targetRootFolder, assetPath)); + } + + const extractorMetadataFileContent: string = JSON.stringify(extractorMetadataJson, undefined, 0); + await state.assetHandler.includeAssetAsync({ + sourceFileContent: extractorMetadataFileContent, + targetFilePath: extractorMetadataFilePath + }); + } + + private async _makeBinLinksAsync(options: IExtractorOptions, state: IExtractorState): Promise { + const { terminal } = options; + + const extractedProjectFolderPaths: string[] = []; + for (const folderPath of state.projectConfigurationsByPath.keys()) { + if (state.foldersToCopy.has(folderPath)) { + extractedProjectFolderPaths.push( + remapSourcePathForTargetFolder({ ...options, sourcePath: folderPath }) + ); + } + } + + const binFilePaths: string[] = await makeBinLinksAsync(terminal, extractedProjectFolderPaths); + await Async.forEachAsync( + binFilePaths, + (targetFilePath: string) => state.assetHandler.includeAssetAsync({ targetFilePath }), + { + concurrency: MAX_CONCURRENCY + } + ); + } + + private async _writeCreateLinksScriptAsync( + options: IExtractorOptions, + state: IExtractorState + ): Promise { + const { terminal, targetRootFolder, linkCreationScriptPath } = options; + const { assetHandler } = state; + + terminal.writeLine(`Creating ${CREATE_LINKS_SCRIPT_FILENAME}`); + const createLinksSourceFilePath: string = `${SCRIPTS_FOLDER_PATH}/${CREATE_LINKS_SCRIPT_FILENAME}`; + const createLinksTargetFilePath: string = path.resolve( + targetRootFolder, + linkCreationScriptPath || CREATE_LINKS_SCRIPT_FILENAME + ); + let createLinksScriptContent: string = await FileSystem.readFileAsync(createLinksSourceFilePath); + createLinksScriptContent = createLinksScriptContent.replace( + TARGET_ROOT_SCRIPT_RELATIVE_PATH_TEMPLATE_STRING, + Path.convertToSlashes(path.relative(path.dirname(createLinksTargetFilePath), targetRootFolder)) + ); + await assetHandler.includeAssetAsync({ + sourceFileContent: createLinksScriptContent, + targetFilePath: createLinksTargetFilePath + }); + } +} diff --git a/libraries/package-extractor/src/PathConstants.ts b/libraries/package-extractor/src/PathConstants.ts new file mode 100644 index 00000000000..51239dabb66 --- /dev/null +++ b/libraries/package-extractor/src/PathConstants.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +export const CREATE_LINKS_SCRIPT_FILENAME: 'create-links.js' = 'create-links.js'; + +export const EXTRACTOR_METADATA_FILENAME: 'extractor-metadata.json' = 'extractor-metadata.json'; + +const packageExtractorFolderRootPath: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; +export const SCRIPTS_FOLDER_PATH: string = `${packageExtractorFolderRootPath}/dist/scripts`; diff --git a/libraries/package-extractor/src/SymlinkAnalyzer.ts b/libraries/package-extractor/src/SymlinkAnalyzer.ts new file mode 100644 index 00000000000..36eaff95481 --- /dev/null +++ b/libraries/package-extractor/src/SymlinkAnalyzer.ts @@ -0,0 +1,216 @@ +// 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, type FileSystemStats, Sort } from '@rushstack/node-core-library'; + +export interface IPathNodeBase { + kind: 'file' | 'folder' | 'link'; + nodePath: string; + linkStats: FileSystemStats; +} + +/** + * Represents a file object analyzed by {@link SymlinkAnalyzer}. + */ +export interface IFileNode extends IPathNodeBase { + kind: 'file'; +} + +/** + * Represents a folder object analyzed by {@link SymlinkAnalyzer}. + */ +export interface IFolderNode extends IPathNodeBase { + kind: 'folder'; +} + +/** + * Represents a symbolic link analyzed by {@link SymlinkAnalyzer}. + */ +export interface ILinkNode extends IPathNodeBase { + kind: 'link'; + + /** + * The immediate target that the symlink resolves to. + */ + linkTarget: string; +} + +export type PathNode = IFileNode | IFolderNode | ILinkNode; + +/** + * Represents a symbolic link. + * + * @public + */ +export interface ILinkInfo { + /** + * The type of link that was encountered. + */ + kind: 'fileLink' | 'folderLink'; + + /** + * The path to the link, relative to the root of the extractor output folder. + */ + linkPath: string; + + /** + * The target that the link points to. + */ + targetPath: string; +} + +export interface ISymlinkAnalyzerOptions { + requiredSourceParentPath?: string; +} + +export interface IAnalyzePathOptions { + inputPath: string; + preserveLinks?: boolean; + shouldIgnoreExternalLink?: (path: string) => boolean; +} + +export class SymlinkAnalyzer { + private readonly _requiredSourceParentPath: string | undefined; + + // The directory tree discovered so far + private readonly _nodesByPath: Map = new Map(); + + // The symlinks that we encountered while building the directory tree + private readonly _linkInfosByPath: Map = new Map(); + + public constructor(options: ISymlinkAnalyzerOptions = {}) { + this._requiredSourceParentPath = options.requiredSourceParentPath; + } + + public async analyzePathAsync( + options: IAnalyzePathOptions & { shouldIgnoreExternalLink: (path: string) => boolean } + ): Promise; + public async analyzePathAsync( + options: IAnalyzePathOptions & { shouldIgnoreExternalLink?: never } + ): Promise; + public async analyzePathAsync(options: IAnalyzePathOptions): Promise { + const { inputPath, preserveLinks = false, shouldIgnoreExternalLink } = options; + + // First, try to short-circuit the analysis if we've already analyzed this path + const resolvedPath: string = path.resolve(inputPath); + const existingNode: PathNode | undefined = this._nodesByPath.get(resolvedPath); + if (existingNode) { + return existingNode; + } + + // Postfix a '/' to the end of the path. This will get trimmed off later, but it + // ensures that the last path component is included in the loop below. + let targetPath: string = `${resolvedPath}${path.sep}`; + let targetPathIndex: number = -1; + let currentNode: PathNode | undefined; + + while ((targetPathIndex = targetPath.indexOf(path.sep, targetPathIndex + 1)) >= 0) { + if (targetPathIndex === 0) { + // Edge case for a Unix path like "/folder/file" --> [ "", "folder", "file" ] + continue; + } + + const currentPath: string = targetPath.slice(0, targetPathIndex); + currentNode = this._nodesByPath.get(currentPath); + if (currentNode === undefined) { + const linkStats: FileSystemStats = await FileSystem.getLinkStatisticsAsync(currentPath); + if (linkStats.isSymbolicLink()) { + // Link target paths can be relative or absolute, so we need to resolve them + const linkTargetPath: string = await FileSystem.readLinkAsync(currentPath); + const resolvedLinkTargetPath: string = path.resolve(path.dirname(currentPath), linkTargetPath); + + // Do a check to make sure that the link target path is not outside the source folder + if (this._requiredSourceParentPath) { + const relativeLinkTargetPath: string = path.relative( + this._requiredSourceParentPath, + resolvedLinkTargetPath + ); + if (relativeLinkTargetPath.startsWith('..')) { + // Symlinks that link outside of the source folder may be ignored. Check to see if we + // can ignore this one and if so, return undefined. + if (shouldIgnoreExternalLink?.(currentPath)) { + return undefined; + } + throw new Error( + `Symlink targets not under folder "${this._requiredSourceParentPath}": ` + + `${currentPath} -> ${resolvedLinkTargetPath}` + ); + } + } + + currentNode = { + kind: 'link', + nodePath: currentPath, + linkStats, + linkTarget: resolvedLinkTargetPath + }; + } else if (linkStats.isDirectory()) { + currentNode = { + kind: 'folder', + nodePath: currentPath, + linkStats + }; + } else if (linkStats.isFile()) { + currentNode = { + kind: 'file', + nodePath: currentPath, + linkStats + }; + } else { + throw new Error('Unknown object type: ' + currentPath); + } + this._nodesByPath.set(currentPath, currentNode); + } + + if (!preserveLinks) { + while (currentNode?.kind === 'link') { + const targetNode: PathNode = await this.analyzePathAsync({ + inputPath: currentNode.linkTarget, + preserveLinks: true + }); + + // Have we created an ILinkInfo for this link yet? + if (!this._linkInfosByPath.has(currentNode.nodePath)) { + // Follow any symbolic links to determine whether the final target is a directory + const targetStats: FileSystemStats = await FileSystem.getStatisticsAsync(targetNode.nodePath); + const targetIsDirectory: boolean = targetStats.isDirectory(); + const linkInfo: ILinkInfo = { + kind: targetIsDirectory ? 'folderLink' : 'fileLink', + linkPath: currentNode.nodePath, + targetPath: targetNode.nodePath + }; + this._linkInfosByPath.set(currentNode.nodePath, linkInfo); + } + + const nodeTargetPath: string = targetNode.nodePath; + const remainingPath: string = targetPath.slice(targetPathIndex); + targetPath = path.join(nodeTargetPath, remainingPath); + targetPathIndex = nodeTargetPath.length; + currentNode = targetNode; + } + } + + if (targetPath.length === targetPathIndex + 1) { + // We've reached the end of the path + break; + } + } + + if (!currentNode) { + throw new Error('Unable to analyze path: ' + inputPath); + } + + return currentNode; + } + + /** + * Returns a summary of all the symbolic links encountered by {@link SymlinkAnalyzer.analyzePathAsync}. + */ + public reportSymlinks(): ILinkInfo[] { + const list: ILinkInfo[] = [...this._linkInfosByPath.values()]; + Sort.sortBy(list, (x) => x.linkPath); + return list; + } +} diff --git a/libraries/package-extractor/src/Utils.ts b/libraries/package-extractor/src/Utils.ts new file mode 100644 index 00000000000..0bf49be52ab --- /dev/null +++ b/libraries/package-extractor/src/Utils.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 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 { + // Map "@types/*" --> "^\@types\/.*$" + const pattern: string = + '^' + + patternWithStar + .split('*') + .map((x) => Text.escapeRegExp(x)) + .join('.*') + + '$'; + // eslint-disable-next-line @rushstack/security/no-unsafe-regexp + const regExp: RegExp = new RegExp(pattern); + return regExp.test(input); +} + +export interface IRemapPathForTargetFolder { + sourcePath: string; + sourceRootFolder: string; + targetRootFolder: string; +} + +/** + * Maps a file path under the provided {@link IRemapPathForTargetFolder.sourceRootFolder} to the provided + * {@link IExtractorOptions.targetRootFolder}. + * + * Example input: "C:\\MyRepo\\libraries\\my-lib" + * Example output: "C:\\MyRepo\\common\\deploy\\libraries\\my-lib" + */ +export function remapSourcePathForTargetFolder(options: IRemapPathForTargetFolder): string { + const { sourcePath, sourceRootFolder, targetRootFolder } = options; + const relativePath: string = path.relative(sourceRootFolder, sourcePath); + if (relativePath.startsWith('..')) { + throw new Error(`Source path "${sourcePath}" is not under "${sourceRootFolder}"`); + } + const absolutePathInTargetFolder: string = path.join(targetRootFolder, relativePath); + return absolutePathInTargetFolder; +} + +/** + * Maps a file path under the provided folder path to the expected path format for the extractor metadata. + * + * Example input: "C:\\MyRepo\\libraries\\my-lib" + * Example output: "common/deploy/libraries/my-lib" + */ +export function remapPathForExtractorMetadata(folderPath: string, filePath: string): string { + const relativePath: string = path.relative(folderPath, filePath); + if (relativePath.startsWith('..')) { + throw new Error(`Path "${filePath}" is not under "${folderPath}"`); + } + return Path.convertToSlashes(relativePath); +} + +/** + * Creates the .bin files for the extracted projects and returns the paths to the created .bin files. + * + * @param terminal - The terminal to write to + * @param extractedProjectFolderPaths - The paths to the extracted projects + */ +export async function makeBinLinksAsync( + terminal: ITerminal, + extractedProjectFolderPaths: string[] +): Promise { + const binFilePaths: string[] = []; + await Async.forEachAsync( + extractedProjectFolderPaths, + async (extractedProjectFolderPath: string) => { + const extractedProjectNodeModulesFolderPath: string = `${extractedProjectFolderPath}/node_modules`; + const extractedProjectBinFolderPath: string = `${extractedProjectNodeModulesFolderPath}/.bin`; + + const linkedBinPackageNames: string[] = await pnpmLinkBins( + extractedProjectNodeModulesFolderPath, + extractedProjectBinFolderPath, + { + warn: (msg: string) => terminal.writeLine(Colorize.yellow(msg)) + } + ); + + if (linkedBinPackageNames.length) { + const binFolderItems: string[] = await FileSystem.readFolderItemNamesAsync( + extractedProjectBinFolderPath + ); + for (const binFolderItem of binFolderItems) { + const binFilePath: string = `${extractedProjectBinFolderPath}/${binFolderItem}`; + terminal.writeVerboseLine(`Created .bin file: ${binFilePath}`); + binFilePaths.push(binFilePath); + } + } + }, + { + concurrency: MAX_CONCURRENCY + } + ); + + return binFilePaths; +} diff --git a/libraries/package-extractor/src/index.ts b/libraries/package-extractor/src/index.ts new file mode 100644 index 00000000000..564800a2f3c --- /dev/null +++ b/libraries/package-extractor/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. + +export { + PackageExtractor, + type LinkCreationMode, + type IExtractorOptions, + type IExtractorProjectConfiguration, + type IExtractorDependencyConfiguration, + type IExtractorMetadataJson, + type IProjectInfoJson, + type IExtractorSubspace +} from './PackageExtractor'; + +export type { ILinkInfo } from './SymlinkAnalyzer'; diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts b/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts new file mode 100644 index 00000000000..10b64a2ed7f --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.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 { CommandLineParser } from '@rushstack/ts-command-line'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { CreateLinksAction } from './actions/CreateLinksAction'; +import { RemoveLinksAction } from './actions/RemoveLinksAction'; + +export class CreateLinksCommandLineParser extends CommandLineParser { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + toolFilename: 'create-links', + toolDescription: 'Create or remove symlinks for the extracted packages' + }); + + this._terminal = terminal; + + this.addAction(new CreateLinksAction(this._terminal)); + this.addAction(new RemoveLinksAction(this._terminal)); + } + + protected override async onExecuteAsync(): Promise { + process.exitCode = 1; + + try { + await super.onExecuteAsync(); + process.exitCode = 0; + } catch (error) { + if (!(error instanceof AlreadyReportedError)) { + this._terminal.writeErrorLine(); + this._terminal.writeErrorLine('ERROR: ' + error.message.trim()); + } + } + } +} diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts b/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts new file mode 100644 index 00000000000..146bb76b46c --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.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 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'; +import { + TARGET_ROOT_FOLDER, + REALIZE_FILES_PARAMETER_NAME, + LINK_BINS_PARAMETER_NAME, + MAX_CONCURRENCY +} from '../../utilities/constants'; +import { removeLinksAsync } from './RemoveLinksAction'; + +async function createLinksAsync( + terminal: ITerminal, + targetRootFolder: string, + extractorMetadataObject: IExtractorMetadataJson +): Promise { + await Async.forEachAsync( + extractorMetadataObject.links, + async (linkInfo) => { + // Link to the relative path for symlinks + const newLinkPath: string = path.join(targetRootFolder, linkInfo.linkPath); + const linkTargetPath: string = path.join(targetRootFolder, linkInfo.targetPath); + + // Make sure the containing folder exists + await FileSystem.ensureFolderAsync(path.dirname(newLinkPath)); + + // NOTE: This logic is based on NpmLinkManager._createSymlink() + if (linkInfo.kind === 'folderLink') { + terminal.writeVerboseLine(`Creating linked folder at path "${newLinkPath}"`); + await FileSystem.createSymbolicLinkJunctionAsync({ newLinkPath, linkTargetPath }); + } else if (linkInfo.kind === 'fileLink') { + // Use hardlinks for Windows and symlinks for other platforms since creating a symbolic link + // requires administrator permission on Windows. This may cause unexpected behaviour for consumers + // of the hardlinked files. If this becomes an issue, we may need to revisit this. + terminal.writeVerboseLine(`Creating linked file at path "${newLinkPath}"`); + if (process.platform === 'win32') { + await FileSystem.createHardLinkAsync({ newLinkPath, linkTargetPath }); + } else { + await FileSystem.createSymbolicLinkFileAsync({ newLinkPath, linkTargetPath }); + } + } + }, + { concurrency: MAX_CONCURRENCY } + ); +} + +async function realizeFilesAsync( + terminal: ITerminal, + targetRootFolder: string, + extractorMetadataObject: IExtractorMetadataJson +): Promise { + await Async.forEachAsync( + extractorMetadataObject.files, + async (relativeFilePath) => { + const filePath: string = `${targetRootFolder}/${relativeFilePath}`; + const realFilePath: string = await FileSystem.getRealPathAsync(filePath); + if (!Path.isEqual(realFilePath, filePath)) { + // Delete the existing symlink and create a hardlink to the real file, since creating hardlinks + // is less overhead than copying the file. + terminal.writeVerboseLine(`Realizing file at path "${filePath}"`); + await FileSystem.deleteFileAsync(filePath); + await FileSystem.createHardLinkAsync({ newLinkPath: filePath, linkTargetPath: realFilePath }); + } + }, + { concurrency: MAX_CONCURRENCY } + ); +} + +export class CreateLinksAction extends CommandLineAction { + private _terminal: ITerminal; + private _realizeFilesParameter: CommandLineFlagParameter; + private _linkBinsParameter: CommandLineFlagParameter; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'create', + summary: 'Create symlinks for extraction', + documentation: 'This action creates symlinks for the extraction process.' + }); + + this._terminal = terminal; + + this._realizeFilesParameter = this.defineFlagParameter({ + parameterLongName: REALIZE_FILES_PARAMETER_NAME, + description: 'Realize files instead of creating symlinks' + }); + + this._linkBinsParameter = this.defineFlagParameter({ + parameterLongName: LINK_BINS_PARAMETER_NAME, + description: 'Create the .bin files for extracted packages' + }); + } + + protected override async onExecuteAsync(): Promise { + const extractorMetadataObject: IExtractorMetadataJson = await getExtractorMetadataAsync(); + const realizeFiles: boolean = this._realizeFilesParameter.value; + const linkBins: boolean = this._linkBinsParameter.value; + + this._terminal.writeLine(`Creating links for extraction at path "${TARGET_ROOT_FOLDER}"`); + await removeLinksAsync(this._terminal, TARGET_ROOT_FOLDER, extractorMetadataObject); + await createLinksAsync(this._terminal, TARGET_ROOT_FOLDER, extractorMetadataObject); + + if (realizeFiles) { + this._terminal.writeLine(`Realizing files for extraction at path "${TARGET_ROOT_FOLDER}"`); + await realizeFilesAsync(this._terminal, TARGET_ROOT_FOLDER, extractorMetadataObject); + } + + if (linkBins) { + this._terminal.writeLine(`Linking bins for extraction at path "${TARGET_ROOT_FOLDER}"`); + const extractedProjectFolderPaths: string[] = extractorMetadataObject.projects.map( + (project: IProjectInfoJson) => path.join(TARGET_ROOT_FOLDER, project.path) + ); + await makeBinLinksAsync(this._terminal, extractedProjectFolderPaths); + } + } +} diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts b/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts new file mode 100644 index 00000000000..bea0e60f9e4 --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.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 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'; + +export async function removeLinksAsync( + terminal: ITerminal, + targetRootFolder: string, + extractorMetadataObject: IExtractorMetadataJson +): Promise { + await Async.forEachAsync( + extractorMetadataObject.links, + async ({ linkPath }) => { + const newLinkPath: string = path.join(targetRootFolder, linkPath); + terminal.writeVerboseLine(`Removing link at path "${newLinkPath}"`); + await FileSystem.deleteFileAsync(newLinkPath, { throwIfNotExists: false }); + }, + { concurrency: MAX_CONCURRENCY } + ); +} + +export class RemoveLinksAction extends CommandLineAction { + private _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'remove', + summary: 'Remove symlinks created by the "create" action', + documentation: 'This action removes the symlinks created by the "create" action.' + }); + + this._terminal = terminal; + } + + protected override async onExecuteAsync(): Promise { + const extractorMetadataObject: IExtractorMetadataJson = await getExtractorMetadataAsync(); + + this._terminal.writeLine(`Removing links for extraction at path "${TARGET_ROOT_FOLDER}"`); + await removeLinksAsync(this._terminal, TARGET_ROOT_FOLDER, extractorMetadataObject); + } +} diff --git a/libraries/package-extractor/src/scripts/createLinks/start.ts b/libraries/package-extractor/src/scripts/createLinks/start.ts new file mode 100644 index 00000000000..d03d9f6e5c9 --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/start.ts @@ -0,0 +1,11 @@ +// 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 { CreateLinksCommandLineParser } from './cli/CreateLinksCommandLineParser'; + +const terminal: Terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); + +const parser: CreateLinksCommandLineParser = new CreateLinksCommandLineParser(terminal); +parser.executeAsync().catch(terminal.writeErrorLine); diff --git a/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts b/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts new file mode 100644 index 00000000000..69f4443e241 --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.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 { FileSystem } from '@rushstack/node-core-library'; + +import type { IExtractorMetadataJson } from '../../../PackageExtractor'; +import { EXTRACTOR_METADATA_FILENAME } from '../../../PathConstants'; + +export async function getExtractorMetadataAsync(): Promise { + const extractorMetadataPath: string = `${__dirname}/${EXTRACTOR_METADATA_FILENAME}`; + const extractorMetadataJson: string = await FileSystem.readFileAsync(extractorMetadataPath); + const extractorMetadataObject: IExtractorMetadataJson = JSON.parse(extractorMetadataJson); + return extractorMetadataObject; +} diff --git a/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts b/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts new file mode 100644 index 00000000000..707a3f08e41 --- /dev/null +++ b/libraries/package-extractor/src/scripts/createLinks/utilities/constants.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 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.availableParallelism?.() ?? os.cpus().length) * 2; + +/** + * The name of the action to create symlinks. + */ +export const CREATE_ACTION_NAME: 'create' = 'create'; + +/** + * The name of the action to remove symlinks. + */ +export const REMOVE_ACTION_NAME: 'remove' = 'remove'; + +/** + * The name of the parameter to realize files when creating symlinks. + */ +export const REALIZE_FILES_PARAMETER_NAME: '--realize-files' = '--realize-files'; + +/** + * The name of the parameter to link bins when creating symlinks. + */ +export const LINK_BINS_PARAMETER_NAME: '--link-bins' = '--link-bins'; + +/** + * The name of the parameter to link packages when creating symlinks. The actual value of this + * export is modified after bundling the script to ensure that the extracted version of the script + * contains the relative path from the extraction target folder to the script. Generally, this + * value should not be used directly, but rather the `TARGET_ROOT_FOLDER` export should be used + * instead. + */ +export const TARGET_ROOT_SCRIPT_RELATIVE_PATH: typeof TargetRootScriptRelativePathTemplateString = + '{TARGET_ROOT_SCRIPT_RELATIVE_PATH}'; + +/** + * The path to the root folder where symlinks are created. + */ +export const TARGET_ROOT_FOLDER: string = path.resolve(__dirname, TARGET_ROOT_SCRIPT_RELATIVE_PATH); diff --git a/libraries/package-extractor/src/test/PackageExtractor.test.ts b/libraries/package-extractor/src/test/PackageExtractor.test.ts new file mode 100644 index 00000000000..3a9f14e5928 --- /dev/null +++ b/libraries/package-extractor/src/test/PackageExtractor.test.ts @@ -0,0 +1,622 @@ +// 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 { ChildProcess } from 'node:child_process'; + +import { Executable, FileSystem, Sort } from '@rushstack/node-core-library'; +import { Terminal, StringBufferTerminalProvider } from '@rushstack/terminal'; +import { + PackageExtractor, + type IExtractorProjectConfiguration, + type IExtractorMetadataJson +} from '../PackageExtractor'; + +// Do this work in the "temp/test.jest" directory since it gets cleaned on clean runs +const extractorTargetFolder: string = path.resolve(__dirname, '..', '..', 'test-output'); +const repoRoot: string = path.resolve(__dirname, '..', '..', '..', '..'); +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 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 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); + +function getDefaultProjectConfigurations(): IExtractorProjectConfiguration[] { + return [ + { + projectName: project1PackageName, + projectFolder: project1Path + }, + { + projectName: project2PackageName, + projectFolder: project2Path + }, + { + projectName: project3PackageName, + projectFolder: project3Path + } + ]; +} + +describe(PackageExtractor.name, () => { + const terminal = new Terminal(new StringBufferTerminalProvider()); + const packageExtractor = new PackageExtractor(); + + it('should extract project', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-01'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: getDefaultProjectConfigurations(), + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 is linked through node_modules + const project1NodeModulesPath: string = path.join(targetFolder, project1RelativePath, 'node_modules'); + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project2RelativePath, 'src', 'index.js')); + + // Validate project 3 is linked through node_modules + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project3PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + await expect( + FileSystem.getRealPathAsync( + path.join( + project1NodeModulesPath, + project2PackageName, + 'node_modules', + project3PackageName, + 'src', + 'index.js' + ) + ) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + }); + + it('should extract project with dependencies only', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-02'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: getDefaultProjectConfigurations(), + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: false + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 is linked through node_modules + const project1NodeModulesPath: string = path.join(targetFolder, project1RelativePath, 'node_modules'); + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project2RelativePath, 'src', 'index.js')); + + // Validate project 3 is not linked through node_modules on project 1 but is linked through node_modules on project 2 + await expect( + FileSystem.existsAsync(path.join(project1NodeModulesPath, project3PackageName)) + ).resolves.toBe(false); + await expect( + FileSystem.getRealPathAsync( + path.join( + project1NodeModulesPath, + project2PackageName, + 'node_modules', + project3PackageName, + 'src', + 'index.js' + ) + ) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + }); + + it('should throw error if main project does not exist', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-03'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: 'project-that-not-exist', + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + terminal, + projectConfigurations: [], + linkCreation: 'default' + }) + ).rejects.toThrowError('Main project "project-that-not-exist" was not found in the list of projects'); + }); + + it('should throw error if contains symlink outsides targetRootFolder', async () => { + const sourceFolder: string = path.join(repoRoot, 'build-tests'); + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-04'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project4PackageName, + sourceRootFolder: sourceFolder, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project4PackageName, + projectFolder: project4Path + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true + }) + ).rejects.toThrowError(/Symlink targets not under folder/); + }); + + it('should exclude specified dependencies', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-05'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path, + patternsToExclude: ['src/**'] + }, + { + projectName: project2PackageName, + projectFolder: project2Path + }, + { + projectName: project3PackageName, + projectFolder: project3Path + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'package.json')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(false); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'subdir')) + ).resolves.toBe(false); + + // Validate project 2 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project2RelativePath, 'package.json')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project2RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + }); + + it('should include specified dependencies', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-05'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path, + patternsToInclude: ['src/subdir/**'] + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'package.json')) + ).resolves.toBe(false); + await expect(FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src'))).resolves.toBe( + true + ); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(false); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'subdir')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'subdir', 'file.js')) + ).resolves.toBe(true); + }); + + it('should exclude specified dependencies on local dependencies', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-06'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path + }, + { + projectName: project2PackageName, + projectFolder: project2Path, + patternsToExclude: ['src/**'] + }, + { + projectName: project3PackageName, + projectFolder: project3Path + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'package.json')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project2RelativePath, 'package.json')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project2RelativePath, 'src', 'index.js')) + ).resolves.toBe(false); + }); + + it('should exclude specified files on third party dependencies with semver version', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-07'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path + }, + { + projectName: project2PackageName, + projectFolder: project2Path + }, + { + projectName: project3PackageName, + projectFolder: project3Path + } + ], + dependencyConfigurations: [ + { + dependencyName: '@types/node', + dependencyVersionRange: '^18', + patternsToExclude: ['fs/**'] + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + // Validate project 1 files + await expect( + FileSystem.existsAsync( + path.join(targetFolder, project1RelativePath, 'node_modules/@types/node/fs-promises.d.ts') + ) + ).resolves.toBe(false); + await expect( + FileSystem.existsAsync( + path.join(targetFolder, project1RelativePath, 'node_modules/@types/node/path.d.ts') + ) + ).resolves.toBe(true); + + // Validate project 3 files + await expect( + FileSystem.existsAsync( + path.join(targetFolder, project3RelativePath, 'node_modules/@types/node/fs/promises.d.ts') + ) + ).resolves.toBe(true); + }); + it('should not exclude specified files on third party dependencies if semver version not match', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-08'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path + }, + { + projectName: project2PackageName, + projectFolder: project2Path + }, + { + projectName: project3PackageName, + projectFolder: project3Path + } + ], + dependencyConfigurations: [ + { + dependencyName: '@types/node', + dependencyVersionRange: '^16.20.0', + patternsToExclude: ['fs/**'] + } + ], + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + // Validate project 1 files + await expect( + FileSystem.existsAsync( + path.join(targetFolder, project1RelativePath, 'node_modules/@types/node/fs/promises.d.ts') + ) + ).resolves.toBe(true); + + // Validate project file that shouldn't be exclude + await expect( + FileSystem.existsAsync( + path.join(targetFolder, project3RelativePath, 'node_modules/@types/node/fs/promises.d.ts') + ) + ).resolves.toBe(true); + }); + + it('should include folderToCopy', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-09'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: [ + { + projectName: project1PackageName, + projectFolder: project1Path + } + ], + folderToCopy: project2Path, + terminal, + createArchiveOnly: false, + includeNpmIgnoreFiles: true, + linkCreation: 'default', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'package.json')) + ).resolves.toBe(true); + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 files + await expect(FileSystem.existsAsync(path.join(targetFolder, 'package.json'))).resolves.toBe(true); + await expect(FileSystem.existsAsync(path.join(targetFolder, 'src', 'index.js'))).resolves.toBe(true); + }); + + it('should extract project with script linkCreation', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-10'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: getDefaultProjectConfigurations(), + terminal, + includeNpmIgnoreFiles: true, + linkCreation: 'script', + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 is not linked through node_modules + const project1NodeModulesPath: string = path.join(targetFolder, project1RelativePath, 'node_modules'); + await expect( + FileSystem.existsAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(false); + + // Validate project 3 is not linked through node_modules + await expect( + FileSystem.existsAsync(path.join(project1NodeModulesPath, project3PackageName, 'src', 'index.js')) + ).resolves.toEqual(false); + + // Run the linkCreation script + const createLinksProcess: ChildProcess = Executable.spawn(process.argv0, [ + path.join(targetFolder, 'create-links.js'), + 'create' + ]); + await expect( + Executable.waitForExitAsync(createLinksProcess, { throwOnNonZeroExitCode: true }) + ).resolves.not.toThrow(); + + // Validate project 2 is linked through node_modules + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project2RelativePath, 'src', 'index.js')); + + // Validate project 3 is linked through node_modules + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project3PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + await expect( + FileSystem.getRealPathAsync( + path.join( + project1NodeModulesPath, + project2PackageName, + 'node_modules', + project3PackageName, + 'src', + 'index.js' + ) + ) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + + const metadataFileContent: string = await FileSystem.readFileAsync( + `${targetFolder}/extractor-metadata.json` + ); + const metadata: IExtractorMetadataJson = JSON.parse(metadataFileContent); + Sort.sortBy(metadata.files, (x) => x); + Sort.sortBy(metadata.links, (x) => x.linkPath); + Sort.sortBy(metadata.projects, (x) => x.path); + expect(metadata).toMatchSnapshot(); + }); + + it('should extract project with script linkCreation and custom linkCreationScriptPath', async () => { + const targetFolder: string = path.join(extractorTargetFolder, 'extractor-output-11'); + const linkCreationScriptPath: string = path.join(targetFolder, 'foo', 'bar', 'baz.js'); + + await expect( + packageExtractor.extractAsync({ + mainProjectName: project1PackageName, + sourceRootFolder: repoRoot, + targetRootFolder: targetFolder, + overwriteExisting: true, + projectConfigurations: getDefaultProjectConfigurations(), + terminal, + includeNpmIgnoreFiles: true, + linkCreation: 'script', + linkCreationScriptPath, + includeDevDependencies: true + }) + ).resolves.not.toThrow(); + + // Validate project 1 files + await expect( + FileSystem.existsAsync(path.join(targetFolder, project1RelativePath, 'src', 'index.js')) + ).resolves.toBe(true); + + // Validate project 2 is not linked through node_modules + const project1NodeModulesPath: string = path.join(targetFolder, project1RelativePath, 'node_modules'); + await expect( + FileSystem.existsAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(false); + + // Validate project 3 is not linked through node_modules + await expect( + FileSystem.existsAsync(path.join(project1NodeModulesPath, project3PackageName, 'src', 'index.js')) + ).resolves.toEqual(false); + + // Run the linkCreation script + const createLinksProcess: ChildProcess = Executable.spawn(process.argv0, [ + linkCreationScriptPath, + 'create' + ]); + await expect( + Executable.waitForExitAsync(createLinksProcess, { throwOnNonZeroExitCode: true }) + ).resolves.not.toThrow(); + + // Validate project 2 is linked through node_modules + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project2PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project2RelativePath, 'src', 'index.js')); + + // Validate project 3 is linked through node_modules + await expect( + FileSystem.getRealPathAsync(path.join(project1NodeModulesPath, project3PackageName, 'src', 'index.js')) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + await expect( + FileSystem.getRealPathAsync( + path.join( + project1NodeModulesPath, + project2PackageName, + 'node_modules', + project3PackageName, + 'src', + 'index.js' + ) + ) + ).resolves.toEqual(path.join(targetFolder, project3RelativePath, 'src', 'index.js')); + + const metadataFileContent: string = await FileSystem.readFileAsync( + `${path.dirname(linkCreationScriptPath)}/extractor-metadata.json` + ); + const metadata: IExtractorMetadataJson = JSON.parse(metadataFileContent); + Sort.sortBy(metadata.files, (x) => x); + Sort.sortBy(metadata.links, (x) => x.linkPath); + Sort.sortBy(metadata.projects, (x) => x.path); + expect(metadata).toMatchSnapshot(); + }); +}); diff --git a/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap b/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap new file mode 100644 index 00000000000..dbab23715c5 --- /dev/null +++ b/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap @@ -0,0 +1,453 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PackageExtractor should extract project with script linkCreation 1`] = ` +Object { + "files": Array [ + "build-tests/package-extractor-test-01/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-01/package.json", + "build-tests/package-extractor-test-01/src/index.js", + "build-tests/package-extractor-test-01/src/subdir/file.js", + "build-tests/package-extractor-test-02/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-02/package.json", + "build-tests/package-extractor-test-02/src/index.js", + "build-tests/package-extractor-test-03/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-03/package.json", + "build-tests/package-extractor-test-03/src/index.js", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/LICENSE", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/README.md", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/assert.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/assert/strict.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/async_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/child_process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/cluster.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/console.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/constants.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/crypto.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dgram.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/diagnostics_channel.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dns.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dns/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/domain.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/fs.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/fs/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/globals.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/globals.global.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/http.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/http2.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/https.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/inspector.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/module.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/net.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/os.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/package.json", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/path.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/perf_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/punycode.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/querystring.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/readline.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/repl.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/consumers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/web.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/string_decoder.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/timers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/timers/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/tls.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/trace_events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/tty.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/url.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/util.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/v8.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/vm.d.ts", + "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@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@20.17.19/node_modules/@types/node", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-01/node_modules/package-extractor-test-02", + "targetPath": "build-tests/package-extractor-test-02", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-01/node_modules/package-extractor-test-03", + "targetPath": "build-tests/package-extractor-test-03", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-02/node_modules/package-extractor-test-03", + "targetPath": "build-tests/package-extractor-test-03", + }, + Object { + "kind": "folderLink", + "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 [ + Object { + "path": "build-tests/package-extractor-test-01", + "projectName": "package-extractor-test-01", + }, + Object { + "path": "build-tests/package-extractor-test-02", + "projectName": "package-extractor-test-02", + }, + Object { + "path": "build-tests/package-extractor-test-03", + "projectName": "package-extractor-test-03", + }, + ], +} +`; + +exports[`PackageExtractor should extract project with script linkCreation and custom linkCreationScriptPath 1`] = ` +Object { + "files": Array [ + "build-tests/package-extractor-test-01/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-01/package.json", + "build-tests/package-extractor-test-01/src/index.js", + "build-tests/package-extractor-test-01/src/subdir/file.js", + "build-tests/package-extractor-test-02/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-02/package.json", + "build-tests/package-extractor-test-02/src/index.js", + "build-tests/package-extractor-test-03/.rush/temp/shrinkwrap-deps.json", + "build-tests/package-extractor-test-03/package.json", + "build-tests/package-extractor-test-03/src/index.js", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/LICENSE", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/README.md", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/assert.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/assert/strict.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/async_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/child_process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/cluster.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/console.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/constants.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/crypto.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dgram.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/diagnostics_channel.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dns.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/dns/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/domain.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/fs.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/fs/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/globals.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/globals.global.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/http.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/http2.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/https.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/inspector.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/module.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/net.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/os.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/package.json", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/path.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/perf_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/punycode.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/querystring.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/readline.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/repl.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/consumers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/stream/web.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/string_decoder.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/timers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/timers/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/tls.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/trace_events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/tty.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/url.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/util.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/v8.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/vm.d.ts", + "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@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@20.17.19/node_modules/@types/node", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-01/node_modules/package-extractor-test-02", + "targetPath": "build-tests/package-extractor-test-02", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-01/node_modules/package-extractor-test-03", + "targetPath": "build-tests/package-extractor-test-03", + }, + Object { + "kind": "folderLink", + "linkPath": "build-tests/package-extractor-test-02/node_modules/package-extractor-test-03", + "targetPath": "build-tests/package-extractor-test-03", + }, + Object { + "kind": "folderLink", + "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 [ + Object { + "path": "build-tests/package-extractor-test-01", + "projectName": "package-extractor-test-01", + }, + Object { + "path": "build-tests/package-extractor-test-02", + "projectName": "package-extractor-test-02", + }, + Object { + "path": "build-tests/package-extractor-test-03", + "projectName": "package-extractor-test-03", + }, + ], +} +`; diff --git a/libraries/package-extractor/tsconfig.json b/libraries/package-extractor/tsconfig.json new file mode 100644 index 00000000000..54fdeba4b2f --- /dev/null +++ b/libraries/package-extractor/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + // Needed because JSZip is missing a typing, and attempting to re-add the typing conflicts with + // the typescript library + // https://github.com/Stuk/jszip/issues/693 + "skipLibCheck": true + } +} diff --git a/libraries/package-extractor/webpack.config.js b/libraries/package-extractor/webpack.config.js new file mode 100644 index 00000000000..89a6ddf1d87 --- /dev/null +++ b/libraries/package-extractor/webpack.config.js @@ -0,0 +1,38 @@ +'use strict'; + +const webpack = require('webpack'); +const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); +const { CREATE_LINKS_SCRIPT_FILENAME, SCRIPTS_FOLDER_PATH } = require('./lib/PathConstants'); + +module.exports = () => { + return { + context: __dirname, + mode: 'development', // So the output isn't minified + devtool: 'source-map', + entry: { + [CREATE_LINKS_SCRIPT_FILENAME]: { + import: `${__dirname}/lib-esnext/scripts/createLinks/start.js`, + filename: `[name]` + } + }, + output: { + path: SCRIPTS_FOLDER_PATH, + filename: '[name].js', + chunkFilename: 'chunks/[name].js', // TODO: Don't allow any chunks to be created + library: { + type: 'commonjs2' + } + }, + target: 'node', + plugins: [ + new PreserveDynamicRequireWebpackPlugin(), + new webpack.ids.DeterministicModuleIdsPlugin({ + maxLength: 6 + }) + ], + ignoreWarnings: [ + // This is included by the 'mz' package which is a dependency of '@pnpm/link-bins' but is unused + /Module not found: Error: Can't resolve 'graceful-fs'/ + ] + }; +}; diff --git a/libraries/problem-matcher/.npmignore b/libraries/problem-matcher/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/problem-matcher/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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..a339a690fe4 --- /dev/null +++ b/libraries/problem-matcher/CHANGELOG.json @@ -0,0 +1,29 @@ +{ + "name": "@rushstack/problem-matcher", + "entries": [ + { + "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..6e855cf8a02 --- /dev/null +++ b/libraries/problem-matcher/CHANGELOG.md @@ -0,0 +1,18 @@ +# Change Log - @rushstack/problem-matcher + +This log was last generated on Tue, 30 Sep 2025 23:57:45 GMT and should not be manually modified. + +## 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..996e271d3dd --- /dev/null +++ b/libraries/problem-matcher/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} 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..c9e8d5d83b8 --- /dev/null +++ b/libraries/problem-matcher/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/problem-matcher", + "version": "0.1.1", + "description": "A library for parsing VS Code style problem matchers", + "main": "lib/index.js", + "typings": "dist/problem-matcher.d.ts", + "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.1.4", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} 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/.npmignore b/libraries/rig-package/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/rig-package/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/rig-package/.vscode/launch.json b/libraries/rig-package/.vscode/launch.json new file mode 100644 index 00000000000..d780fd9dc1a --- /dev/null +++ b/libraries/rig-package/.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 Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + } + ] +} diff --git a/libraries/rig-package/CHANGELOG.json b/libraries/rig-package/CHANGELOG.json new file mode 100644 index 00000000000..21e7022e455 --- /dev/null +++ b/libraries/rig-package/CHANGELOG.json @@ -0,0 +1,580 @@ +{ + "name": "@rushstack/rig-package", + "entries": [ + { + "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", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/rig-package_v0.5.2", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/rig-package_v0.5.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/rig-package_v0.5.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/rig-package_v0.4.1", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/rig-package_v0.4.0", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "minor": [ + { + "comment": "Expose an `IRigConfig` interface that `RigConfig` implements." + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/rig-package_v0.3.21", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/rig-package_v0.3.20", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/rig-package_v0.3.19", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/rig-package_v0.3.18", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/rig-package_v0.3.17", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/rig-package_v0.3.16", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/rig-package_v0.3.15", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/rig-package_v0.3.14", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/rig-package_v0.3.13", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/rig-package_v0.3.12", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/rig-package_v0.3.11", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/rig-package_v0.3.10", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/rig-package_v0.3.9", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/rig-package_v0.3.8", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/rig-package_v0.3.7", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/rig-package_v0.3.6", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/rig-package_v0.3.5", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/rig-package_v0.3.4", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/rig-package_v0.3.3", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/rig-package_v0.3.2", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/rig-package_v0.3.1", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/rig-package_v0.3.0", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "minor": [ + { + "comment": "Cache rig.json reads" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/rig-package_v0.2.13", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/rig-package_v0.2.12", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/rig-package_v0.2.11", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/rig-package_v0.2.10", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "patch": [ + { + "comment": "Eliminate dependency on @types/node" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/rig-package_v0.2.9", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/rig-package_v0.2.8", + "date": "Wed, 11 Nov 2020 01:08:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/rig-package_v0.2.7", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/rig-package_v0.2.6", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/rig-package_v0.2.5", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/rig-package_v0.2.4", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/rig-package_v0.2.3", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/rig-package_v0.2.2", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix minor mistake in README.md" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/rig-package_v0.2.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/rig-package_v0.2.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "Update the rig package guidance to place tool configuration files that would normally be in a \"config\" folder in a \"config\" folder inside the rig package as well." + }, + { + "comment": "Add ILoadForProjectFolderOptions.overrideRigJsonObject" + }, + { + "comment": "Add RigConfig.tryResolveConfigFilePath()" + }, + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "patch": [ + { + "comment": "Report an error if the specified \"rigProfile\" is not defined by the rig package" + }, + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/rig-package_v0.1.0", + "date": "Fri, 25 Sep 2020 08:13:01 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/libraries/rig-package/CHANGELOG.md b/libraries/rig-package/CHANGELOG.md new file mode 100644 index 00000000000..a74db8eb064 --- /dev/null +++ b/libraries/rig-package/CHANGELOG.md @@ -0,0 +1,262 @@ +# Change Log - @rushstack/rig-package + +This log was last generated on Fri, 03 Oct 2025 20:09:59 GMT and should not be manually modified. + +## 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 + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.5.2 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.5.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.5.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.4.1 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.4.0 +Mon, 19 Jun 2023 22:40:21 GMT + +### Minor changes + +- Expose an `IRigConfig` interface that `RigConfig` implements. + +## 0.3.21 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 0.3.20 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 0.3.19 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.3.18 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.3.17 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.3.16 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.3.15 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.3.14 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.3.13 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.3.12 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.3.11 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.3.10 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.3.9 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.3.8 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.3.7 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.3.6 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 0.3.5 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.3.4 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.3.3 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.3.2 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.3.1 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.3.0 +Fri, 27 Aug 2021 00:07:25 GMT + +### Minor changes + +- Cache rig.json reads + +## 0.2.13 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.2.12 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 0.2.11 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.2.10 +Thu, 04 Mar 2021 01:11:31 GMT + +### Patches + +- Eliminate dependency on @types/node + +## 0.2.9 +Thu, 10 Dec 2020 23:25:49 GMT + +_Version update only_ + +## 0.2.8 +Wed, 11 Nov 2020 01:08:59 GMT + +_Version update only_ + +## 0.2.7 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.2.6 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.2.5 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.2.4 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.2.3 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.2.2 +Mon, 05 Oct 2020 15:10:42 GMT + +### Patches + +- Fix minor mistake in README.md + +## 0.2.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 0.2.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Update the rig package guidance to place tool configuration files that would normally be in a "config" folder in a "config" folder inside the rig package as well. +- Add ILoadForProjectFolderOptions.overrideRigJsonObject +- Add RigConfig.tryResolveConfigFilePath() +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Report an error if the specified "rigProfile" is not defined by the rig package +- Update README.md + +## 0.1.0 +Fri, 25 Sep 2020 08:13:01 GMT + +### Minor changes + +- Initial release + diff --git a/libraries/rig-package/LICENSE b/libraries/rig-package/LICENSE new file mode 100644 index 00000000000..8cf1f21f341 --- /dev/null +++ b/libraries/rig-package/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rig-package + +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/rig-package/README.md b/libraries/rig-package/README.md new file mode 100644 index 00000000000..8ad3e006bda --- /dev/null +++ b/libraries/rig-package/README.md @@ -0,0 +1,229 @@ +# @rushstack/rig-package + +The **config/rig.json** file is a system that Node.js build tools can adopt, in order to eliminate +duplication of config files when many projects share a common configuration. This is particularly valuable +in a setup where hundreds of projects may be built using a small set of reusable recipes. + +## Motivation + +For a concrete example, consider the [API Extractor](https://api-extractor.com/) tool which reads its +configuration from **\/config/api-extractor.json**. Suppose that we have three separate projects +that all share the exact same configuration: + +``` +project1/package.json +project1/config/api-extractor.json +project1/config/other-tool2.json +project1/config/other-tool3.json +project1/src/index.ts + +project2/package.json +project2/config/api-extractor.json +project2/config/other-tool2.json +project2/config/other-tool3.json +project2/src/index.ts + +project3/package.json +project3/config/api-extractor.json +project3/config/other-tool2.json +project3/config/other-tool3.json +project3/src/index.ts +``` + +It seems wasteful to copy and paste the **api-extractor.json** file with all those settings. If we later need +to tune the configuration, we'd have to find and update each file. For a large organization, there could be +hundreds of such projects. + +The `"extends"` setting provides a basic way to centralize the configuration in a "rig package". For this example, +we'll call our NPM package **example-rig**: + +``` +example-rig/package.json +example-rig/profile/node-library/config/api-extractor.json +example-rig/profile/web-library/config/api-extractor.json + +project1/package.json +project1/config/api-extractor.json +project1/config/other-tool2.json +project1/config/other-tool3.json +project1/src/index.ts + +project2/package.json +project2/config/api-extractor.json +project2/config/other-tool2.json +project2/config/other-tool3.json +project2/src/index.ts + +project3/package.json +project3/config/api-extractor.json +project3/config/other-tool2.json +project3/config/other-tool3.json +project3/src/index.ts +``` + +To make things interesting, above we've introduced two "profiles": + +- `node-library` is for libraries that target the Node.js runtime +- `web-library` is for libraries that target a web browser + +> **NOTE:** The `node-library` and `web-library` names are hypothetical examples. The names and purposes of +> rig profiles are user-defined. If you only need one profile, then call it `default`. + +If **project1** and **project2** are Node.js libraries, then their **api-extractor.json** now reduces to this: + +**project1/config/api-extractor.json** + +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "example-rig/profile/node-library/config/api-extractor.json" +} +``` + +Whereas if **project3** is a web browser library, then it might look like this: + +**project3/config/api-extractor.json** + +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "example-rig/profile/web-library/config/api-extractor.json" +} +``` + +Using `"extends"` definitely made the config file shorter! But imagine that we have a large monorepo with 100 projects. +And each project has 5 config files like **api-extactor.json**. We still have to copy+paste 100 x 5 = 500 config files +across all our project folders. + +Can we do better? + +## rig.json eliminates files entirely + +The idea is to replace `config/api-extractor.json` and `config/other-tool2.json` (and any other such files) +with a single file `config/rig.json` that delegates everything to the rig package: + +**project3/config/rig.json** + +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "example-rig", + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + "rigProfile": "web-library" +} +``` + +Using **rig.json** eliminates the `"extends"` stub files entirely. A tool that implements the **rig.json** system +would probe for its config file (`.json`) using the following procedure: + +1. First check for `config/.json` in the project folder; if found, use that file. OTHERWISE... +2. Check for `config/rig.json`; if found, then this project is using a rig package. Read the `` + and `` settings from that file. +3. Use Node.js module resolution to find the `` package folder (let's call that ``) +4. Check for `/profile//.json`; if found, use that file. OTHERWISE... +5. If the `.json` cannot be found in either of these places, the behavior is left to the tool. + For example, it could report an error, or proceed using defaults. + +In cases where we need a project-specific customization, the `"extends"` field is still supported. For example, +**project1** can still add a local override like this: + +**project1/config/api-extractor.json** + +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "example-rig/profile/node-library/config/api-extractor.json", + + // Local override: + "mainEntryPointFilePath": "/lib/custom.d.ts", +} +``` + +The result is a much shorter inventory of files: + +``` +example-rig/package.json + +example-rig/profile/node-library/config/api-extractor.json +example-rig/profile/node-library/config/other-tool2.json +example-rig/profile/node-library/config/other-tool3.json + +example-rig/profile/web-library/config/api-extractor.json +example-rig/profile/web-library/config/other-tool2.json +example-rig/profile/web-library/config/other-tool3.json + +project1/package.json +project1/config/rig.json +project1/config/api-extractor.json <-- local override shown above +project1/src/index.ts + +project2/package.json +project2/config/rig.json +project2/src/index.ts + +project3/package.json +project3/config/rig.json +project3/src/index.ts +``` + +## The `@rushstack/rig-package` API + +The `@rushstack/rig-package` library provides an API for loading the **rig.json** file and performing lookups. +It is a lightweight NPM package, intended to be easy for tool projects to accept as a dependency. The package +also includes the JSON schema file **rig.schema.json**. + +Example usage of the API: + +```ts +import { RigConfig } from '@rushstack/rig-package'; + +// Probe for the rig.json file and load it if found +const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + // Specify a project folder (i.e. where its package.json file is located) + projectFolderPath: testProjectFolder +}); + +if (rigConfig.rigFound) { + // We found a config/rig.json file + // + // Prints "/path/to/project3/config/rig.json" + console.log('Found rig.json: ' + rigConfig.filePath); + + // Prints "example-rig" + console.log('The rig package is: ' + rigConfig.rigPackageName); + + // Resolve the rig package + // + // Prints "/path/to/project3/node_modules/example-rig/profile/web-library" + console.log('Profile folder: ' + rigConfig.getResolvedProfileFolder()); + + // Look up a config file. These file paths will be tested: + // + // /path/to/project3/folder/file.json + // /path/to/project3/node_modules/example-rig/profile/web-library/folder/file.json + // + // The result will be the first path that exists, or undefined if the config file was not found. + console.log('Resolved config file: ' + rigConfig.tryResolveConfigFilePath('folder/file.json')); +} +``` + +Note that there are also async variants of the functions that access the filesystem. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/rig-package/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/rig-package/) + +`@rushstack/rig-package` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/rig-package/config/api-extractor.json b/libraries/rig-package/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/rig-package/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} 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 new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/rig-package/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "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 new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/rig-package/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/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 new file mode 100644 index 00000000000..d85a7533344 --- /dev/null +++ b/libraries/rig-package/package.json @@ -0,0 +1,30 @@ +{ + "name": "@rushstack/rig-package", + "version": "0.6.0", + "description": "A system for sharing tool configurations between projects without duplicating config files.", + "main": "lib/index.js", + "typings": "dist/rig-package.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/rig-package" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@types/resolve": "1.20.2", + "ajv": "~8.13.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "resolve": "~1.22.1" + } +} diff --git a/libraries/rig-package/src/Helpers.ts b/libraries/rig-package/src/Helpers.ts new file mode 100644 index 00000000000..d2d0fd9282b --- /dev/null +++ b/libraries/rig-package/src/Helpers.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 * 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 = /([\/\\]|^)\.\.([\/\\]|$)/; + + 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) => { + if (error) { + reject(error); + } else { + resolve(result!); + } + }); + }); + } + + public static async fsExistsAsync(filesystemPath: fs.PathLike): Promise { + return await new Promise((resolve: (result: boolean) => void) => { + fs.exists(filesystemPath, (exists: boolean) => { + resolve(exists); + }); + }); + } + + // Based on Path.isDownwardRelative() from @rushstack/node-core-library + public static isDownwardRelative(inputPath: string): boolean { + if (path.isAbsolute(inputPath)) { + return false; + } + // Does it contain ".." + if (Helpers._upwardPathSegmentRegex.test(inputPath)) { + return false; + } + return true; + } +} diff --git a/libraries/rig-package/src/RigConfig.ts b/libraries/rig-package/src/RigConfig.ts new file mode 100644 index 00000000000..31ab62e2d76 --- /dev/null +++ b/libraries/rig-package/src/RigConfig.ts @@ -0,0 +1,548 @@ +// 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 * as nodeResolve from 'resolve'; +import stripJsonComments from 'strip-json-comments'; + +import { Helpers } from './Helpers'; + +/** + * Represents the literal contents of the `config/rig.json` file. + * + * @public + */ +export interface IRigConfigJson { + /** + * The name of the rig package to use. + * + * @remarks + * The name must be a valid NPM package name, and must end with the `-rig` suffix. + * + * Example: `example-rig` + */ + rigPackageName: string; + + /** + * Specify which rig profile to use from the rig package. + * + * @remarks + * The name must consist of lowercase alphanumeric words separated by hyphens, for example `"sample-profile"`. + * If the `"rigProfile"` is not specified, then the profile name `"default"` will be used. + * + * Example: `example-profile` + */ + rigProfile?: string; +} + +interface IRigConfigOptions { + projectFolderPath: string; + + rigFound: boolean; + filePath: string; + rigPackageName: string; + rigProfile?: string; +} + +/** + * Options for {@link RigConfig.loadForProjectFolder}. + * + * @public + */ +export interface ILoadForProjectFolderOptions { + /** + * The path to the folder of the project to be analyzed. This folder should contain a `package.json` file. + */ + projectFolderPath: string; + + /** + * If specified, instead of loading the `config/rig.json` from disk, this object will be substituted instead. + */ + overrideRigJsonObject?: IRigConfigJson; + + /** + * If specified, force a fresh load instead of returning a cached entry, if one existed. + */ + bypassCache?: boolean; +} + +/** + * This is the main API for loading the `config/rig.json` file format. + * + * @public + */ +export interface IRigConfig { + /** + * The project folder path that was passed to {@link RigConfig.loadForProjectFolder}, + * which maybe an absolute or relative path. + * + * @remarks + * Example: `.` + */ + readonly projectFolderOriginalPath: string; + + /** + * The absolute path for the project folder path that was passed to {@link RigConfig.loadForProjectFolder}. + * + * @remarks + * Example: `/path/to/your-project` + */ + readonly projectFolderPath: string; + + /** + * Returns `true` if `config/rig.json` was found, or `false` otherwise. + */ + readonly rigFound: boolean; + + /** + * The full path to the `rig.json` file that was found, or `""` if none was found. + * + * @remarks + * Example: `/path/to/your-project/config/rig.json` + */ + readonly filePath: string; + + /** + * The `"rigPackageName"` field from `rig.json`, or `""` if the file was not found. + * + * @remarks + * The name must be a valid NPM package name, and must end with the `-rig` suffix. + * + * Example: `example-rig` + */ + readonly rigPackageName: string; + + /** + * The `"rigProfile"` value that was loaded from `rig.json`, or `""` if the file was not found. + * + * @remarks + * The name must consist of lowercase alphanumeric words separated by hyphens, for example `"sample-profile"`. + * If the `rig.json` file exists, but the `"rigProfile"` is not specified, then the profile + * name will be `"default"`. + * + * Example: `example-profile` + */ + readonly rigProfile: string; + + /** + * The relative path to the rig profile specified by `rig.json`, or `""` if the file was not found. + * + * @remarks + * Example: `profiles/example-profile` + */ + readonly relativeProfileFolderPath: string; + + /** + * Performs Node.js module resolution to locate the rig package folder, then returns the absolute path + * of the rig profile folder specified by `rig.json`. + * + * @remarks + * If no `rig.json` file was found, then this method throws an error. The first time this method + * is called, the result is cached and will be returned by all subsequent calls. + * + * Example: `/path/to/your-project/node_modules/example-rig/profiles/example-profile` + */ + getResolvedProfileFolder(): string; + + /** + * An async variant of {@link IRigConfig.getResolvedProfileFolder} + */ + getResolvedProfileFolderAsync(): Promise; + + /** + * This lookup first checks for the specified relative path under `projectFolderPath`; if it does + * not exist there, then it checks in the resolved rig profile folder. If the file is found, + * its absolute path is returned. Otherwise, `undefined` is returned. + * + * @remarks + * For example, suppose the rig profile is: + * + * `/path/to/your-project/node_modules/example-rig/profiles/example-profile` + * + * And suppose `configFileRelativePath` is `folder/file.json`. Then the following locations will be checked: + * + * `/path/to/your-project/folder/file.json` + * + * `/path/to/your-project/node_modules/example-rig/profiles/example-profile/folder/file.json` + */ + tryResolveConfigFilePath(configFileRelativePath: string): string | undefined; + + /** + * An async variant of {@link IRigConfig.tryResolveConfigFilePath} + */ + tryResolveConfigFilePathAsync(configFileRelativePath: string): Promise; +} + +/** + * {@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. + * + * @remarks + * The `RigConfig` class already performs schema validation when loading `rig.json`; however + * this schema file may be useful for integration with other validation tools. + * + * @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} + */ + public readonly projectFolderOriginalPath: string; + + /** + * {@inheritdoc IRigConfig.projectFolderPath} + */ + public readonly projectFolderPath: string; + + /** + * {@inheritdoc IRigConfig.rigFound} + */ + public readonly rigFound: boolean; + + /** + * {@inheritdoc IRigConfig.filePath} + */ + public readonly filePath: string; + + /** + * {@inheritdoc IRigConfig.rigPackageName} + */ + public readonly rigPackageName: string; + + /** + * {@inheritdoc IRigConfig.rigProfile} + */ + public readonly rigProfile: string; + + /** + * {@inheritdoc IRigConfig.relativeProfileFolderPath} + */ + public readonly relativeProfileFolderPath: string; + + // Example: /path/to/your-project/node_modules/example-rig/ + // If the value is `undefined`, then getResolvedProfileFolder() has not calculated it yet + private _resolvedRigPackageFolder: string | undefined; + + // Example: /path/to/your-project/node_modules/example-rig/profiles/example-profile + // If the value is `undefined`, then getResolvedProfileFolder() has not calculated it yet + private _resolvedProfileFolder: string | undefined; + + private constructor(options: IRigConfigOptions) { + const { projectFolderPath, rigFound, filePath, rigPackageName, rigProfile = 'default' } = options; + + this.projectFolderOriginalPath = projectFolderPath; + this.projectFolderPath = path.resolve(projectFolderPath); + + this.rigFound = rigFound; + this.filePath = filePath; + this.rigPackageName = rigPackageName; + this.rigProfile = rigProfile; + + if (this.rigFound) { + this.relativeProfileFolderPath = 'profiles/' + this.rigProfile; + } else { + this.relativeProfileFolderPath = ''; + } + } + + /** + * The JSON contents of the {@link RigConfig.jsonSchemaPath} file. + * + * @remarks + * The JSON object will be lazily loaded when this property getter is accessed, and the result + * will be cached. + * Accessing this property may make a synchronous filesystem call. + */ + public static get jsonSchemaObject(): object { + if (RigConfig._jsonSchemaObject === undefined) { + const jsonSchemaContent: string = fs.readFileSync(RigConfig.jsonSchemaPath).toString(); + RigConfig._jsonSchemaObject = JSON.parse(jsonSchemaContent); + } + return RigConfig._jsonSchemaObject!; + } + + /** + * Use this method to load the `config/rig.json` file for a given project. + * + * @remarks + * If the file cannot be found, an empty `RigConfig` object will be returned with {@link RigConfig.rigFound} + * equal to `false`. + */ + public static loadForProjectFolder(options: ILoadForProjectFolderOptions): RigConfig { + const { overrideRigJsonObject, projectFolderPath } = options; + + const fromCache: RigConfig | undefined = + !options.bypassCache && !overrideRigJsonObject + ? RigConfig._configCache.get(projectFolderPath) + : undefined; + + if (fromCache) { + return fromCache; + } + + const rigConfigFilePath: string = path.join(projectFolderPath, 'config/rig.json'); + + let config: RigConfig | undefined; + let json: IRigConfigJson | undefined = overrideRigJsonObject; + try { + if (!json) { + const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); + json = JSON.parse(stripJsonComments(rigConfigFileContent)) as IRigConfigJson; + } + RigConfig._validateSchema(json); + } catch (error) { + config = RigConfig._handleConfigError(error as Error, projectFolderPath, rigConfigFilePath); + } + + if (!config) { + config = new RigConfig({ + projectFolderPath: projectFolderPath, + + rigFound: true, + filePath: rigConfigFilePath, + rigPackageName: json!.rigPackageName, + rigProfile: json!.rigProfile + }); + } + + if (!overrideRigJsonObject) { + RigConfig._configCache.set(projectFolderPath, config); + } + return config; + } + + /** + * An async variant of {@link RigConfig.loadForProjectFolder} + */ + public static async loadForProjectFolderAsync(options: ILoadForProjectFolderOptions): Promise { + const { overrideRigJsonObject, projectFolderPath } = options; + + const fromCache: RigConfig | false | undefined = + !options.bypassCache && !overrideRigJsonObject && RigConfig._configCache.get(projectFolderPath); + + if (fromCache) { + return fromCache; + } + + const rigConfigFilePath: string = path.join(projectFolderPath, 'config/rig.json'); + + let config: RigConfig | undefined; + let json: IRigConfigJson | undefined = overrideRigJsonObject; + try { + if (!json) { + const rigConfigFileContent: string = (await fs.promises.readFile(rigConfigFilePath)).toString(); + json = JSON.parse(stripJsonComments(rigConfigFileContent)) as IRigConfigJson; + } + + RigConfig._validateSchema(json); + } catch (error) { + config = RigConfig._handleConfigError(error as Error, projectFolderPath, rigConfigFilePath); + } + + if (!config) { + config = new RigConfig({ + projectFolderPath: projectFolderPath, + + rigFound: true, + filePath: rigConfigFilePath, + rigPackageName: json!.rigPackageName, + rigProfile: json!.rigProfile + }); + } + + if (!overrideRigJsonObject) { + RigConfig._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} + */ + public getResolvedProfileFolder(): string { + if (this._resolvedRigPackageFolder === undefined) { + if (!this.rigFound) { + throw new Error('Cannot resolve the rig package because no rig was specified for this project'); + } + + const rigPackageJsonModuleSpecifier: string = `${this.rigPackageName}/package.json`; + const resolveOptions: nodeResolve.Opts = { basedir: this.projectFolderPath }; + const resolvedRigPackageJsonPath: string = nodeResolve.sync( + rigPackageJsonModuleSpecifier, + resolveOptions + ); + + this._resolvedRigPackageFolder = path.dirname(resolvedRigPackageJsonPath); + } + + if (this._resolvedProfileFolder === undefined) { + this._resolvedProfileFolder = path.join(this._resolvedRigPackageFolder, this.relativeProfileFolderPath); + + if (!fs.existsSync(this._resolvedProfileFolder)) { + throw new Error( + `The rig profile "${this.rigProfile}" is not defined` + + ` by the rig package "${this.rigPackageName}"` + ); + } + } + + return this._resolvedProfileFolder; + } + + /** + * {@inheritdoc IRigConfig.getResolvedProfileFolderAsync} + */ + public async getResolvedProfileFolderAsync(): Promise { + if (this._resolvedRigPackageFolder === undefined) { + if (!this.rigFound) { + throw new Error('Cannot resolve the rig package because no rig was specified for this project'); + } + + const rigPackageJsonModuleSpecifier: string = `${this.rigPackageName}/package.json`; + const resolveOptions: nodeResolve.Opts = { basedir: this.projectFolderPath }; + const resolvedRigPackageJsonPath: string = await Helpers.nodeResolveAsync( + rigPackageJsonModuleSpecifier, + resolveOptions + ); + + this._resolvedRigPackageFolder = path.dirname(resolvedRigPackageJsonPath); + } + + if (this._resolvedProfileFolder === undefined) { + this._resolvedProfileFolder = path.join(this._resolvedRigPackageFolder, this.relativeProfileFolderPath); + + if (!(await Helpers.fsExistsAsync(this._resolvedProfileFolder))) { + throw new Error( + `The rig profile "${this.rigProfile}" is not defined` + + ` by the rig package "${this.rigPackageName}"` + ); + } + } + + return this._resolvedProfileFolder; + } + + /** + * {@inheritdoc IRigConfig.tryResolveConfigFilePath} + */ + public tryResolveConfigFilePath(configFileRelativePath: string): string | undefined { + if (!Helpers.isDownwardRelative(configFileRelativePath)) { + throw new Error('The configFileRelativePath is not a relative path: ' + configFileRelativePath); + } + + const localPath: string = path.join(this.projectFolderPath, configFileRelativePath); + if (fs.existsSync(localPath)) { + return localPath; + } + if (this.rigFound) { + const riggedPath: string = path.join(this.getResolvedProfileFolder(), configFileRelativePath); + if (fs.existsSync(riggedPath)) { + return riggedPath; + } + } + return undefined; + } + + /** + * {@inheritdoc IRigConfig.tryResolveConfigFilePathAsync} + */ + public async tryResolveConfigFilePathAsync(configFileRelativePath: string): Promise { + if (!Helpers.isDownwardRelative(configFileRelativePath)) { + throw new Error('The configFileRelativePath is not a relative path: ' + configFileRelativePath); + } + + const localPath: string = path.join(this.projectFolderPath, configFileRelativePath); + if (await Helpers.fsExistsAsync(localPath)) { + return localPath; + } + if (this.rigFound) { + const riggedPath: string = path.join( + await this.getResolvedProfileFolderAsync(), + configFileRelativePath + ); + if (await Helpers.fsExistsAsync(riggedPath)) { + return riggedPath; + } + } + 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"'); + } + + if (!RigConfig._packageNameRegExp.test(json.rigPackageName)) { + throw new Error( + `The "rigPackageName" value is not a valid NPM package name: ${JSON.stringify(json.rigPackageName)}` + ); + } + + if (!RigConfig._rigNameRegExp.test(json.rigPackageName)) { + throw new Error( + `The "rigPackageName" value is missing the "-rig" suffix: ` + 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/index.ts b/libraries/rig-package/src/index.ts new file mode 100644 index 00000000000..aea84ab6857 --- /dev/null +++ b/libraries/rig-package/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. + +/** + * A system for sharing tool configurations between projects without duplicating config files. + * + * @remarks + * The `config/rig.json` file is a system that Node.js build tools can support, in order to eliminate + * duplication of config files when many projects share a common configuration. This is particularly valuable + * in a setup where hundreds of projects may be built using a small set of reusable recipes. + * + * @packageDocumentation + */ + +export { + type IRigConfigJson, + type IRigConfig, + RigConfig, + type ILoadForProjectFolderOptions +} from './RigConfig'; diff --git a/libraries/rig-package/src/schemas/rig.schema.json b/libraries/rig-package/src/schemas/rig.schema.json new file mode 100644 index 00000000000..9707e71e3da --- /dev/null +++ b/libraries/rig-package/src/schemas/rig.schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Describes the config/rig.json file", + "description": "The rig.json file is a standard for sharing project configuration in a monorepo without duplicating files", + "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" + }, + + "rigPackageName": { + "type": "string", + "description": "(Required) The name of the rig package to inherit from. It should be an NPM package name with the \"-rig\" suffix." + }, + + "rigProfile": { + "type": "string", + "description": "Selects a config profile from the rig package. The name must consist of lowercase alphanumeric words separated by hyphens, for example \"sample-profile\". If omitted, then the \"default\" profile will be used." + } + }, + + "required": ["rigPackageName"] +} diff --git a/libraries/rig-package/src/test/RigConfig.test.ts b/libraries/rig-package/src/test/RigConfig.test.ts new file mode 100644 index 00000000000..743c5ddd05a --- /dev/null +++ b/libraries/rig-package/src/test/RigConfig.test.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 Ajv, { type ValidateFunction } from 'ajv'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import stripJsonComments from 'strip-json-comments'; + +import { RigConfig } from '../RigConfig'; + +const testProjectFolder: string = path.join(__dirname, 'test-project'); + +function expectEqualPaths(path1: string, path2: string): void { + if (path.relative(path1!, path2) !== '') { + fail('Expected paths to be equal:\npath1: ' + path1 + '\npath2: ' + path2); + } +} + +describe(RigConfig.name, () => { + describe('loads a rig.json file', () => { + function validate(rigConfig: RigConfig): void { + expectEqualPaths(rigConfig.projectFolderPath, testProjectFolder); + expect(rigConfig.rigFound).toBe(true); + expectEqualPaths(rigConfig.filePath, path.join(testProjectFolder, 'config/rig.json')); + expect(rigConfig.rigProfile).toBe('web-app'); + expect(rigConfig.rigPackageName).toBe('example-rig'); + expect(rigConfig.relativeProfileFolderPath).toBe('profiles/web-app'); + } + + it('synchronously', () => { + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: testProjectFolder, + bypassCache: true + }); + validate(rigConfig); + + // Should cache result + const rigConfig2: RigConfig = RigConfig.loadForProjectFolder({ projectFolderPath: testProjectFolder }); + expect(rigConfig2).toBe(rigConfig); + }); + + it('asynchronously', async () => { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: testProjectFolder, + bypassCache: true + }); + validate(rigConfig); + + // Should cache result + const rigConfig2: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: testProjectFolder + }); + expect(rigConfig2).toBe(rigConfig); + }); + }); + + describe('handles a missing rig.json file', () => { + function validate(rigConfig: RigConfig): void { + expectEqualPaths(rigConfig.projectFolderPath, __dirname); + expect(rigConfig.rigFound).toBe(false); + expect(rigConfig.filePath).toBe(''); + expect(rigConfig.rigProfile).toBe(''); + expect(rigConfig.rigPackageName).toBe(''); + expect(rigConfig.relativeProfileFolderPath).toBe(''); + } + + it('synchronously', () => { + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: __dirname, + bypassCache: true + }); + validate(rigConfig); + + // Should cache result + const rigConfig2: RigConfig = RigConfig.loadForProjectFolder({ projectFolderPath: __dirname }); + expect(rigConfig2).toBe(rigConfig); + }); + + it('asynchronously', async () => { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: __dirname, + bypassCache: true + }); + validate(rigConfig); + + // Should cache result + const rigConfig2: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: __dirname + }); + expect(rigConfig2).toBe(rigConfig); + }); + }); + + describe('resolves the profile path', () => { + it('synchronously', () => { + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: testProjectFolder + }); + + expect(rigConfig.rigFound).toBe(true); + + expectEqualPaths( + rigConfig.getResolvedProfileFolder(), + path.join(testProjectFolder, 'node_modules/example-rig/profiles/web-app') + ); + }); + + it('asynchronously', async () => { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: testProjectFolder + }); + + expect(rigConfig.rigFound).toBe(true); + + expectEqualPaths( + await rigConfig.getResolvedProfileFolderAsync(), + path.join(testProjectFolder, 'node_modules/example-rig/profiles/web-app') + ); + }); + }); + + describe('reports an undefined profile', () => { + it('synchronously', () => { + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: testProjectFolder, + overrideRigJsonObject: { + rigPackageName: 'example-rig', + rigProfile: 'missing-profile' + } + }); + + expect(rigConfig.rigFound).toBe(true); + + expect(() => rigConfig.getResolvedProfileFolder()).toThrowError( + 'The rig profile "missing-profile" is not defined by the rig package "example-rig"' + ); + }); + + it('asynchronously', async () => { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: testProjectFolder, + overrideRigJsonObject: { + rigPackageName: 'example-rig', + rigProfile: 'missing-profile' + } + }); + + await expect(rigConfig.getResolvedProfileFolderAsync()).rejects.toThrowError( + 'The rig profile "missing-profile" is not defined by the rig package "example-rig"' + ); + }); + }); + + describe('resolves a config file path', () => { + it('synchronously', () => { + const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ + projectFolderPath: testProjectFolder, + bypassCache: true + }); + + expect(rigConfig.rigFound).toBe(true); + + const resolvedPath: string | undefined = rigConfig.tryResolveConfigFilePath('example-config.json'); + + expect(resolvedPath).toBeDefined(); + expectEqualPaths( + resolvedPath!, + path.join(testProjectFolder, 'node_modules/example-rig/profiles/web-app/example-config.json') + ); + }); + + it('asynchronously', async () => { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: testProjectFolder, + bypassCache: true + }); + + expect(rigConfig.rigFound).toBe(true); + + const resolvedPath: string | undefined = + await rigConfig.tryResolveConfigFilePathAsync('example-config.json'); + + expect(resolvedPath).toBeDefined(); + expectEqualPaths( + resolvedPath!, + path.join(testProjectFolder, 'node_modules/example-rig/profiles/web-app/example-config.json') + ); + }); + }); + it('validates a rig.json file using the schema', () => { + const rigConfigFilePath: string = path.join(testProjectFolder, 'config', 'rig.json'); + + const ajv = new Ajv({ + verbose: true + }); + + // Delete our older "draft-04/schema" and use AJV's built-in schema + // eslint-disable-next-line + delete (RigConfig.jsonSchemaObject as any)['$schema']; + + // Compile our schema + const validateRigFile: ValidateFunction = ajv.compile(RigConfig.jsonSchemaObject); + + // Load the rig.json file + const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); + const rigConfigJsonObject: unknown = JSON.parse(stripJsonComments(rigConfigFileContent)); + + // Validate it against our schema + const valid: boolean = validateRigFile(rigConfigJsonObject) as boolean; + + expect(validateRigFile.errors).toMatchInlineSnapshot(`null`); + expect(valid).toBe(true); + }); +}); diff --git a/libraries/rig-package/src/test/test-project/config/rig.json b/libraries/rig-package/src/test/test-project/config/rig.json new file mode 100644 index 00000000000..052d2767fbc --- /dev/null +++ b/libraries/rig-package/src/test/test-project/config/rig.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * Example code comment. + */ + "rigPackageName": "example-rig", + "rigProfile": "web-app" +} diff --git a/libraries/rig-package/src/test/test-project/node_modules/example-rig/package.json b/libraries/rig-package/src/test/test-project/node_modules/example-rig/package.json new file mode 100644 index 00000000000..effa280de3a --- /dev/null +++ b/libraries/rig-package/src/test/test-project/node_modules/example-rig/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-project", + "version": "1.0.0", + "private": true +} diff --git a/libraries/rig-package/src/test/test-project/node_modules/example-rig/profiles/web-app/example-config.json b/libraries/rig-package/src/test/test-project/node_modules/example-rig/profiles/web-app/example-config.json new file mode 100644 index 00000000000..2f0c2faeca3 --- /dev/null +++ b/libraries/rig-package/src/test/test-project/node_modules/example-rig/profiles/web-app/example-config.json @@ -0,0 +1,3 @@ +{ + "exampleSetting": 123 +} diff --git a/libraries/rig-package/src/test/test-project/package.json b/libraries/rig-package/src/test/test-project/package.json new file mode 100644 index 00000000000..effa280de3a --- /dev/null +++ b/libraries/rig-package/src/test/test-project/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-project", + "version": "1.0.0", + "private": true +} diff --git a/libraries/rig-package/tsconfig.json b/libraries/rig-package/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/rig-package/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/rush-lib/.npmignore b/libraries/rush-lib/.npmignore new file mode 100644 index 00000000000..2c1b4d582e5 --- /dev/null +++ b/libraries/rush-lib/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/assets/** + diff --git a/apps/rush-buildxl/LICENSE b/libraries/rush-lib/LICENSE similarity index 100% rename from apps/rush-buildxl/LICENSE rename to libraries/rush-lib/LICENSE diff --git a/libraries/rush-lib/README.md b/libraries/rush-lib/README.md new file mode 100644 index 00000000000..60617f5a4df --- /dev/null +++ b/libraries/rush-lib/README.md @@ -0,0 +1,25 @@ +## @microsoft/rush-lib + +This is a companion package for the Rush tool. See the +[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) +package for details. + +The **rush-lib** package implements the rush.json config file loader +and some other helpful utilities. Tools that want to reuse this +functionality can install **rush-lib** alone to avoid inadvertently +adding another "rush" executable to the command-line path (which +might interfere with the globally installed Rush). + +The **@microsoft/rush** version number is always exactly equal +to the **@microsoft/rush-lib** version number that it depends on. + +API documentation for this package: https://rushjs.io/pages/advanced/api/ + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/apps/rush/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-lib/assets/rush-init-deploy/scenario-template.json b/libraries/rush-lib/assets/rush-init-deploy/scenario-template.json new file mode 100644 index 00000000000..d7d5ebf41c4 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init-deploy/scenario-template.json @@ -0,0 +1,114 @@ +/** + * This configuration file defines a deployment scenario for use with the "rush deploy" command. + * The default scenario file path is "deploy.json"; additional files use the naming pattern + * "deploy-.json". For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/deploy-scenario.schema.json", + + /** + * The "rush deploy" command prepares a deployment folder, starting from the main project and collecting + * all of its dependencies (both NPM packages and other Rush projects). The main project is specified + * using the "--project" parameter. The "deploymentProjectNames" setting lists the allowable choices for + * the "--project" parameter; this documents the intended deployments for your monorepo and helps validate + * that "rush deploy" is invoked correctly. If there is only one item in the "deploymentProjectNames" array, + * then "--project" can be omitted. The names should be complete package names as declared in rush.json. + * + * If the main project should include other unrelated Rush projects, add it to the "projectSettings" section, + * and then specify those projects in the "additionalProjectsToInclude" list. + */ + "deploymentProjectNames": ["[%PROJECT_NAME_TO_DEPLOY%]"], + + /** + * When deploying a local Rush project, the package.json "devDependencies" are normally excluded. + * If you want to include them, set "includeDevDependencies" to true. + * + * The default value is false. + */ + // "includeDevDependencies": true, + + /** + * When deploying a local Rush project, normally the .npmignore filter is applied so that Rush only copies + * files that would be packaged by "npm pack". Setting "includeNpmIgnoreFiles" to true will disable this + * filtering so that all files are copied (with a few trivial exceptions such as the "node_modules" folder). + * + * The default value is false. + */ + // "includeNpmIgnoreFiles": true, + + /** + * To improve backwards compatibility with legacy packages, the PNPM package manager installs extra links in the + * node_modules folder that enable packages to import undeclared dependencies. In some cases this workaround may + * double the number of links created. If your deployment does not require this workaround, you can set + * "omitPnpmWorkaroundLinks" to true to avoid creating the extra links. + * + * The default value is false. + */ + // "omitPnpmWorkaroundLinks": true, + + /** + * Specify how links (symbolic links, hard links, and/or NTFS junctions) will be created in the deployed folder: + * + * - "default": Create the links while copying the files; this is the default behavior. + * - "script": A Node.js script called "create-links.js" will be written. When executed, this script will + * create the links described in the "deploy-metadata.json" output file. + * - "none": Do nothing; some other tool may create the links later. + */ + // "linkCreation": "script", + + /** + * If this path is specified, then after "rush deploy", recursively copy the files from this folder to + * the deployment target folder (common/deploy). This can be used to provide additional configuration files + * or scripts needed by the server when deploying. The path is resolved relative to the repository root. + */ + // "folderToCopy": "repo-tools/assets/deploy-config", + + /** + * Customize how Rush projects are processed during deployment. + */ + "projectSettings": [ + // { + // /** + // * The full package name of the project, which must be declared in rush.json. + // */ + // "projectName": "@my-scope/my-project", + // + // /** + // * A list of additional local Rush projects to be deployed with this project (beyond the package.json + // * dependencies). Specify full package names, which must be declared in rush.json. + // */ + // "additionalProjectsToInclude": [ + // // "@my-scope/my-project2" + // ], + // + // /** + // * When deploying a project, the included dependencies are normally determined automatically based on + // * package.json fields such as "dependencies", "peerDependencies", and "optionalDependencies", + // * subject to other deployment settings such as "includeDevDependencies". However, in cases where + // * that information is not accurate, you can use "additionalDependenciesToInclude" to add more + // * packages to the list. + // * + // * The list can include any package name that is installed by Rush and resolvable via Node.js module + // * resolution; however, if it resolves to a local Rush project, the "additionalProjectsToInclude" + // * field will not be recursively applied. + // */ + // "additionalDependenciesToInclude": [ + // // "@rushstack/node-core-library" + // ], + // + // /** + // * This setting prevents specific dependencies from being deployed. It only filters dependencies that + // * are explicitly declared in package.json for this project. It does not affect dependencies added + // * via "additionalProjectsToInclude" or "additionalDependenciesToInclude", nor does it affect indirect + // * dependencies. + // * + // * The "*" wildcard may be used to match zero or more characters. For example, if your project already + // * bundles its own dependencies, specify "dependenciesToExclude": [ "*" ] to exclude all package.json + // * dependencies. + // */ + // "dependenciesToExclude": [ + // // "@types/*" + // ] + // } + ] +} diff --git a/apps/rush-lib/assets/rush-init/[dot]gitattributes b/libraries/rush-lib/assets/rush-init/[dot]gitattributes similarity index 94% rename from apps/rush-lib/assets/rush-init/[dot]gitattributes rename to libraries/rush-lib/assets/rush-init/[dot]gitattributes index 077267a6aa7..79a85db5c23 100644 --- a/apps/rush-lib/assets/rush-init/[dot]gitattributes +++ b/libraries/rush-lib/assets/rush-init/[dot]gitattributes @@ -1,6 +1,6 @@ # Don't allow people to merge changes to these generated files, because the result # may be invalid. You need to run "rush update" again. -pnpm-lock.yaml merge=binary +pnpm-lock.yaml merge=text shrinkwrap.yaml merge=binary npm-shrinkwrap.json merge=binary yarn.lock merge=binary diff --git a/libraries/rush-lib/assets/rush-init/[dot]github/workflows/ci.yml b/libraries/rush-lib/assets/rush-init/[dot]github/workflows/ci.yml new file mode 100644 index 00000000000..5eb57796fa6 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/[dot]github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 2 + - name: Git config user + uses: snow-actions/git-config-user@v1.0.0 + with: + name: # Service Account's Name + email: # Service Account's Email Address + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Verify Change Logs + run: node common/scripts/install-run-rush.js change --verify + - name: Rush Install + run: node common/scripts/install-run-rush.js install + - name: Rush rebuild + run: node common/scripts/install-run-rush.js rebuild --verbose --production diff --git a/libraries/rush-lib/assets/rush-init/[dot]gitignore b/libraries/rush-lib/assets/rush-init/[dot]gitignore new file mode 100644 index 00000000000..1fcd67c7805 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/[dot]gitignore @@ -0,0 +1,122 @@ +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov/ + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output/ + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt/ + +# Bower dependency directory (https://bower.io/) +bower_components/ + +# node-waf configuration +.lock-wscript/ + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release/ + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm/ + +# Optional eslint cache +.eslintcache/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# next.js build output +.next/ + +# Docusaurus cache and generated files +.docusaurus/ + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# yarn v2 +.yarn/cache/ +.yarn/unplugged/ +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# OS X temporary files +.DS_Store + +# IntelliJ IDEA project files; if you want to commit IntelliJ settings, this recipe may be helpful: +# https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +.idea/ +*.iml + +# Visual Studio Code +.vscode/ +!.vscode/tasks.json +!.vscode/launch.json + +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +**/.rush/temp/ +*.lock + +# Common toolchain intermediate files +temp/ +lib/ +lib-amd/ +lib-es6/ +lib-esnext/ +lib-commonjs/ +lib-shim/ +dist/ +dist-storybook/ +*.tsbuildinfo + +# Heft temporary files +.cache/ +.heft/ diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/.pnpmfile.cjs b/libraries/rush-lib/assets/rush-init/common/config/rush/.pnpmfile.cjs new file mode 100644 index 00000000000..000015badc7 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/.pnpmfile.cjs @@ -0,0 +1,38 @@ +'use strict'; + +/** + * When using the PNPM package manager, you can use pnpmfile.js to workaround + * dependencies that have mistakes in their package.json file. (This feature is + * functionally similar to Yarn's "resolutions".) + * + * For details, see the PNPM documentation: + * https://pnpm.io/pnpmfile#hooks + * + * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE + * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run + * "rush update --full" so that PNPM will recalculate all version selections. + */ +module.exports = { + hooks: { + readPackage + } +}; + +/** + * This hook is invoked during installation before a package's dependencies + * are selected. + * The `packageJson` parameter is the deserialized package.json + * contents for the package that is about to be installed. + * The `context` parameter provides a log() function. + * The return value is the updated object. + */ +function readPackage(packageJson, context) { + + /*[LINE "HYPOTHETICAL"]*/ // The karma types have a missing dependency on typings from the log4js package. + /*[LINE "HYPOTHETICAL"]*/ if (packageJson.name === '@types/karma') { + /*[LINE "HYPOTHETICAL"]*/ context.log('Fixed up dependencies for @types/karma'); + /*[LINE "HYPOTHETICAL"]*/ packageJson.dependencies['log4js'] = '0.6.38'; + /*[LINE "HYPOTHETICAL"]*/ } + + return packageJson; +} 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 new file mode 100644 index 00000000000..43f783886e9 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc @@ -0,0 +1,33 @@ +# Rush uses this file to configure the NPM package registry during installation. It is applicable +# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install", +# "rush update", and the "install-run.js" scripts. +# +# NOTE: The "rush publish" command uses .npmrc-publish instead. +# +# Before invoking the package manager, Rush will generate an .npmrc in the folder where installation +# is performed. This generated file will omit any config lines that reference environment variables +# that are undefined in that session; this avoids problems that would otherwise result due to +# a missing variable being replaced by an empty string. +# +# If "subspacesEnabled" is true in subspaces.json, the generated file will merge settings from +# "common/config/rush/.npmrc" and "common/config/subspaces//.npmrc", with the latter taking +# precedence. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read that file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //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 new file mode 100644 index 00000000000..51acb920edc --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc-publish @@ -0,0 +1,26 @@ +# This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish +# is used by the "rush publish" command, as publishing often involves different credentials +# and registries than other operations. +# +# Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc" +# and then temporarily map that folder as the "home directory" for the current user account. +# This enables the same settings to apply for each project folder that gets published. The copied file +# will omit any config lines that reference environment variables that are undefined in that session; +# this avoids problems that would otherwise result due to a missing variable being replaced by +# an empty string. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read the file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //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/artifactory.json b/libraries/rush-lib/assets/rush-init/common/config/rush/artifactory.json new file mode 100644 index 00000000000..268065478a9 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/artifactory.json @@ -0,0 +1,109 @@ +/** + * This configuration file manages Rush integration with JFrog Artifactory services. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/artifactory.schema.json", + + "packageRegistry": { + /** + * (Required) Set this to "true" to enable Rush to manage tokens for an Artifactory NPM registry. + * When enabled, "rush install" will automatically detect when the user's ~/.npmrc + * authentication token is missing or expired. And "rush setup" will prompt the user to + * renew their token. + * + * The default value is false. + */ + "enabled": false, + + /** + * (Required) Specify the URL of your NPM registry. This is the same URL that appears in + * your .npmrc file. It should look something like this example: + * + * https://your-company.jfrog.io/your-project/api/npm/npm-private/ + */ + "registryUrl": "", + + /** + * A list of custom strings that "rush setup" should add to the user's ~/.npmrc file at the time + * when the token is updated. This could be used for example to configure the company registry + * to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush + * operations like "rush add" and "rush install", which get their mappings from the monorepo's + * common/config/rush/.npmrc file). + * + * NOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful + * about adding settings that may interfere with other work outside the monorepo. + */ + "userNpmrcLinesToAdd": [ + // "@example:registry=https://your-company.jfrog.io/your-project/api/npm/npm-private/" + ], + + /** + * (Required) Specifies the URL of the Artifactory control panel where the user can generate + * an API key. This URL is printed after the "visitWebsite" message. + * It should look something like this example: https://your-company.jfrog.io/ + * Specify an empty string to suppress this line entirely. + */ + "artifactoryWebsiteUrl": "", + + /** + * Uncomment this line to specify the type of credential to save in the user's ~/.npmrc file. + * The default is "password", which means the user's API token will be traded in for an + * npm password specific to that registry. Optionally you can specify "authToken", which + * will save the user's API token as credentials instead. + */ + // "credentialType": "password", + + /** + * These settings allow the "rush setup" interactive prompts to be customized, for + * example with messages specific to your team or configuration. Specify an empty string + * to suppress that message entirely. + */ + "messageOverrides": { + /** + * Overrides the message that normally says: + * "This monorepo consumes packages from an Artifactory private NPM registry." + */ + // "introduction": "", + + /** + * Overrides the message that normally says: + * "Please contact the repository maintainers for help with setting up an Artifactory user account." + */ + // "obtainAnAccount": "", + + /** + * Overrides the message that normally says: + * "Please open this URL in your web browser:" + * + * The "artifactoryWebsiteUrl" string is printed after this message. + */ + // "visitWebsite": "", + + /** + * Overrides the message that normally says: + * "Your user name appears in the upper-right corner of the JFrog website." + */ + // "locateUserName": "", + + /** + * Overrides the message that normally says: + * "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key' + * button if you haven't already done so previously." + */ + // "locateApiKey": "" + + /** + * Overrides the message that normally prompts: + * "What is your Artifactory user name?" + */ + // "userNamePrompt": "" + + /** + * Overrides the message that normally prompts: + * "What is your Artifactory API key?" + */ + // "apiKeyPrompt": "" + } + } +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/build-cache.json b/libraries/rush-lib/assets/rush-init/common/config/rush/build-cache.json new file mode 100644 index 00000000000..072e9f7d497 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/build-cache.json @@ -0,0 +1,160 @@ +/** + * This configuration file manages Rush's build cache feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/build-cache.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the build cache feature. + * + * See https://rushjs.io/pages/maintainer/build_cache/ for details about this experimental feature. + */ + "buildCacheEnabled": false, + + /** + * (Required) Choose where project build outputs will be cached. + * + * Possible values: "local-only", "azure-blob-storage", "amazon-s3" + */ + "cacheProvider": "local-only", + + /** + * Setting this property overrides the cache entry ID. If this property is set, it must contain + * a [hash] token. + * + * Other available tokens: + * - [projectName] Example: "@my-scope/my-project" + * - [projectName:normalize] Example: "my-scope+my-project" + * - [phaseName] Example: "_phase:test/api" + * - [phaseName:normalize] Example: "_phase:test+api" + * - [phaseName:trimPrefix] Example: "test/api" + * - [os] Example: "win32" + * - [arch] Example: "x64" + */ + // "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" + */ + "azureBlobStorageConfiguration": { + /** + * (Required) The name of the the Azure storage account to use for build cache. + */ + // "storageAccountName": "example", + + /** + * (Required) The name of the container in the Azure storage account to use for build cache. + */ + // "storageContainerName": "my-container", + + /** + * The Azure environment the storage account exists in. Defaults to AzurePublicCloud. + * + * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" + */ + // "azureEnvironment": "AzurePublicCloud", + + /** + * An optional prefix for cache item blob names. + */ + // "blobPrefix": "my-prefix", + + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "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 + }, + + /** + * Use this configuration with "cacheProvider"="amazon-s3" + */ + "amazonS3Configuration": { + /** + * (Required unless s3Endpoint is specified) The name of the bucket to use for build cache. + * Example: "my-bucket" + */ + // "s3Bucket": "my-bucket", + + /** + * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. + * This should not include any path; use the s3Prefix to set the path. + * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" + */ + // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", + + /** + * (Required) The Amazon S3 region of the bucket to use for build cache. + * Example: "us-east-1" + */ + // "s3Region": "us-east-1", + + /** + * An optional prefix ("folder") for cache items. It should not start with "/". + */ + // "s3Prefix": "my-prefix", + + /** + * If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + }, + + /** + * Use this configuration with "cacheProvider"="http" + */ + "httpConfiguration": { + /** + * (Required) The URL of the server that stores the caches. + * Example: "https://build-cacches.example.com/" + */ + // "url": "https://build-cacches.example.com/", + + /** + * (Optional) The HTTP method to use when writing to the cache (defaults to PUT). + * Should be one of PUT, POST, or PATCH. + * Example: "PUT" + */ + // "uploadMethod": "PUT", + + /** + * (Optional) HTTP headers to pass to the cache server. + * Example: { "X-HTTP-Company-Id": "109283" } + */ + // "headers": {}, + + /** + * (Optional) Shell command that prints the authorization token needed to communicate with the + * cache server, and exits with exit code 0. This command will be executed from the root of + * the monorepo. + * Example: { "exec": "node", "args": ["common/scripts/auth.js"] } + */ + // "tokenHandler": { "exec": "node", "args": ["common/scripts/auth.js"] }, + + /** + * (Optional) Prefix for cache keys. + * Example: "my-company-" + */ + // "cacheKeyPrefix": "", + + /** + * (Optional) If set to true, allow writing to the cache. Defaults to false. + */ + // "isCacheWriteAllowed": true + } +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/cobuild.json b/libraries/rush-lib/assets/rush-init/common/config/rush/cobuild.json new file mode 100644 index 00000000000..a47fad18d5e --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/cobuild.json @@ -0,0 +1,22 @@ +/** + * This configuration file manages Rush's cobuild feature. + * More documentation is available on the Rush website: https://rushjs.io + */ + { + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", + + /** + * (Required) EXPERIMENTAL - Set this to true to enable the cobuild feature. + * RUSH_COBUILD_CONTEXT_ID should always be specified as an environment variable with an non-empty string, + * otherwise the cobuild feature will be disabled. + */ + "cobuildFeatureEnabled": false, + + /** + * (Required) Choose where cobuild lock will be acquired. + * + * The lock provider is registered by the rush plugins. + * For example, @rushstack/rush-redis-cobuild-plugin registers the "redis" lock provider. + */ + "cobuildLockProvider": "redis" +} 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 new file mode 100644 index 00000000000..3760029c00d --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/command-line.json @@ -0,0 +1,411 @@ +/** + * This configuration file defines custom commands for the "rush" command-line. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + + /** + * Custom "commands" introduce new verbs for the command-line. To see the help for these + * example commands, try "rush --help", "rush my-bulk-command --help", or + * "rush my-global-command --help". + */ + "commands": [ + /*[BEGIN "DEMO"]*/ + { + /** + * (Required) Determines the type of custom command. + * Rush's "bulk" commands are invoked separately for each project. By default, the command will run for + * every project in the repo, according to the dependency graph (similar to how "rush build" works). + * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. + */ + "commandKind": "bulk", + + /** + * (Required) The name that will be typed as part of the command line. This is also the name + * of the "scripts" hook in the project's package.json file (if "shellCommand" is not specified). + * + * The name should be comprised of lower case words separated by hyphens or colons. The name should include an + * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands + * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). + * + * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command + * and will call the "rebuild" script instead of the "build" script. + */ + "name": "my-bulk-command", + + /** + * (Required) A short summary of the custom command to be shown when printing command line + * help, e.g. "rush --help". + */ + "summary": "Example bulk custom command", + + /** + * A detailed description of the command to be shown when printing command line + * help (e.g. "rush --help my-command"). + * If omitted, the "summary" text will be shown instead. + * + * Whenever you introduce commands/parameters, taking a little time to write meaningful + * documentation can make a big difference for the developer experience in your repo. + */ + "description": "This is an example custom command that runs separately for each project", + + /** + * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously + * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the + * same time.) If your command makes sense to run concurrently with other operations, + * set "safeForSimultaneousRushProcesses" to true to disable this protection. + * + * In particular, this is needed for custom scripts that invoke other Rush commands. + */ + "safeForSimultaneousRushProcesses": false, + + /** + * (Optional) If the `shellCommand` field is set for a bulk command, Rush will invoke it for each + * selected project; otherwise, Rush will invoke the package.json `"scripts"` entry matching Rush command name. + * + * The string is the path to a script that will be invoked using the OS shell. The working directory will be + * the folder that contains rush.json. If custom parameters are associated with this command, their + * values will be appended to the end of this string. + */ + // "shellCommand": "node common/scripts/my-bulk-command.js", + + /** + * (Required) If true, then this command is safe to be run in parallel, i.e. executed + * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism + * projects will not start processing until their dependencies have completed processing. + */ + "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 + * you can set "ignoreDependencyOrder" to true to increase parallelism. + */ + "ignoreDependencyOrder": false, + + /** + * Normally Rush requires that each project's package.json has a "scripts" entry matching + * the custom command name. To disable this check, set "ignoreMissingScript" to true; + * projects with a missing definition will be skipped. + */ + "ignoreMissingScript": false, + + /** + * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: + * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". + * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. + * - If the shell script returns a zero process exit code but writes something to its stderr stream, + * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent + * Rush from processing downstream projects. + * + * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because + * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. + * In an active monorepo, we've found that if you allow any warnings in your main branch, it inadvertently + * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings + * have accumulated that warnings no longer serve any useful purpose. + * + * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. + * In that case, it's strongly recommended to fix the task. However, as a workaround you can set + * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. + * + * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. + */ + "allowWarningsInSuccessfulBuild": false, + + /** + * If true then this command will be incremental like the built-in "build" command + */ + "incremental": false, + + /** + * (EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to "true" Rush + * will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a + * change is detected, the command will be invoked again for the changed project and any selected projects that + * directly or indirectly depend on it. + * + * For details, refer to the website article "Using watch mode". + */ + "watchForChanges": false, + + /** + * (EXPERIMENTAL) Disable cache for this action. This may be useful if this command affects state outside of + * projects' own folders. + */ + "disableBuildCache": false + }, + + { + /** + * (Required) Determines the type of custom command. + * Rush's "global" commands are invoked once for the entire repo. + */ + "commandKind": "global", + + "name": "my-global-command", + "summary": "Example global custom command", + "description": "This is an example custom command that runs once for the entire repo", + + "safeForSimultaneousRushProcesses": false, + + /** + * (Required) A script that will be invoked using the OS shell. The working directory will be + * the folder that contains rush.json. If custom parameters are associated with this command, their + * values will be appended to the end of this string. + */ + "shellCommand": "node common/scripts/my-global-command.js", + + /** + * If your "shellCommand" script depends on NPM packages, the recommended best practice is + * to make it into a regular Rush project that builds using your normal toolchain. In cases where + * the command needs to work without first having to run "rush build", the recommended practice + * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. + * + * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with + * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to + * install these dependencies before an associated command is invoked. Autoinstallers have the + * advantage that they work even in a branch where "rush install" is broken, which makes them a + * good solution for Git hook scripts. But they have the disadvantages of not being buildable + * projects, and of increasing the overall installation footprint for your monorepo. + * + * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. + * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and + * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when + * invoking the "shellCommand". + */ + /*[LINE "HYPOTHETICAL"]*/ "autoinstallerName": "my-task" + } + /*[END "DEMO"]*/ + ], + + /** + * Custom "parameters" introduce new parameters for specified Rush command-line commands. + * For example, you might define a "--production" parameter for the "rush build" command. + */ + "parameters": [ + /*[BEGIN "DEMO"]*/ + { + /** + * (Required) Determines the type of custom parameter. + * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. + */ + "parameterKind": "flag", + + /** + * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. + */ + "longName": "--my-flag", + + /** + * An optional alternative short name for the parameter. It must be a dash followed by a single + * lower-case or upper-case letter, which is case-sensitive. + * + * NOTE: The Rush developers recommend that automation scripts should always use the long name + * to improve readability. The short name is only intended as a convenience for humans. + * The alphabet letters run out quickly, and are difficult to memorize, so *only* use + * a short name if you expect the parameter to be needed very often in everyday operations. + */ + "shortName": "-m", + + /** + * (Required) A long description to be shown in the command-line help. + * + * Whenever you introduce commands/parameters, taking a little time to write meaningful + * documentation can make a big difference for the developer experience in your repo. + */ + "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", + + /** + * (Required) A list of custom commands and/or built-in Rush commands that this parameter may + * be used with. The parameter will be appended to the shell command that Rush invokes. + */ + "associatedCommands": ["build", "rebuild"] + }, + + { + /** + * (Required) Determines the type of custom parameter. + * A "string" is a custom command-line parameter whose argument is a single text string. + */ + "parameterKind": "string", + "longName": "--my-string", + "description": "A custom string parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + + "argumentName": "SOME_TEXT", + + /** + * If true, this parameter must be included with the command. The default is false. + */ + "required": false + }, + + { + /** + * (Required) Determines the type of custom parameter. + * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + * allowable alternatives (similar to an enum). + */ + "parameterKind": "choice", + "longName": "--my-choice", + "description": "A custom choice parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + "required": false, + + /** + * If a "defaultValue" is specified, then if the Rush command line is invoked without + * this parameter, it will be automatically added with the "defaultValue" as the argument. + * The value must be one of the defined alternatives. + */ + "defaultValue": "vanilla", + + /** + * (Required) A list of alternative argument values that can be chosen for this parameter. + */ + "alternatives": [ + { + /** + * A token that is one of the alternatives that can be used with the choice parameter, + * e.g. "vanilla" in "--flavor vanilla". + */ + "name": "vanilla", + + /** + * A detailed description for the alternative that can be shown in the command-line help. + * + * Whenever you introduce commands/parameters, taking a little time to write meaningful + * documentation can make a big difference for the developer experience in your repo. + */ + "description": "Use the vanilla flavor" + }, + + { + "name": "chocolate", + "description": "Use the chocolate flavor" + }, + + { + "name": "strawberry", + "description": "Use the strawberry flavor" + } + ] + }, + + { + /** + * (Required) Determines the type of custom parameter. + * An "integer" is a custom command-line parameter whose value is an integer number. + */ + "parameterKind": "integer", + "longName": "--my-integer", + "description": "A custom integer parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + "argumentName": "SOME_NUMBER", + "required": false + }, + + { + /** + * (Required) Determines the type of custom parameter. + * An "integerList" is a custom command-line parameter whose argument is an integer. + * The parameter can be specified multiple times to build a list. + * + * For example, if the parameter name is "--my-integer-list", then the custom command + * might be invoked as + * `rush my-global-command --my-integer-list 1 --my-integer-list 2 --my-integer-list 3` + * and the parsed array would be [1,2,3]. + */ + "parameterKind": "integerList", + "longName": "--my-integer-list", + "description": "A custom integer list parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + "argumentName": "SOME_NUMBER", + "required": false + }, + + { + /** + * (Required) Determines the type of custom parameter. + * An "stringList" is a custom command-line parameter whose argument is a text string. + * The parameter can be specified multiple times to build a list. + * + * For example, if the parameter name is "--my-string-list", then the custom command + * might be invoked as + * `rush my-global-command --my-string-list A --my-string-list B --my-string-list C` + * and the parsed array would be [A,B,C]. + */ + "parameterKind": "stringList", + "longName": "--my-string-list", + "description": "A custom string list parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + "argumentName": "SOME_TEXT", + "required": false + }, + + { + /** + * (Required) Determines the type of custom parameter. + * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + * allowable alternatives (similar to an enum). + * The parameter can be specified multiple times to build a list. + * + * For example, if the parameter name is "--my-choice-list", then the custom command + * might be invoked as + * `rush my-global-command --my-string-list vanilla --my-string-list chocolate` + * and the parsed array would be [vanilla,chocolate]. + */ + "parameterKind": "choiceList", + "longName": "--my-choice-list", + "description": "A custom choice list parameter for the \"my-global-command\" custom command", + + "associatedCommands": ["my-global-command"], + "required": false, + + /** + * (Required) A list of alternative argument values that can be chosen for this parameter. + */ + "alternatives": [ + { + /** + * A token that is one of the alternatives that can be used with the choice parameter, + * e.g. "vanilla" in "--flavor vanilla". + */ + "name": "vanilla", + + /** + * A detailed description for the alternative that can be shown in the command-line help. + * + * Whenever you introduce commands/parameters, taking a little time to write meaningful + * documentation can make a big difference for the developer experience in your repo. + */ + "description": "Use the vanilla flavor" + }, + + { + "name": "chocolate", + "description": "Use the chocolate flavor" + }, + + { + "name": "strawberry", + "description": "Use the strawberry flavor" + } + ] + } + /*[END "DEMO"]*/ + ] +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/common-versions.json b/libraries/rush-lib/assets/rush-init/common/config/rush/common-versions.json new file mode 100644 index 00000000000..cc276075c76 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/common-versions.json @@ -0,0 +1,77 @@ +/** + * 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", + + /** + * A table that specifies a "preferred version" for a given NPM package. This feature is typically used + * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. + * + * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into + * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager + * will calculate versions. The specific effect depends on your package manager. Generally it will have no + * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be + * achieved using the pnpmfile.js hook. See the Rush documentation for more details. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + "preferredVersions": { + /** + * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, + * instead of the latest version. + */ + /*[LINE "HYPOTHETICAL"]*/ "some-library": "1.2.3" + }, + + /** + * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, + * except in cases where different projects specify different version ranges for a given dependency. For older + * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause + * trouble for indirect dependencies with incompatible peerDependencies ranges. + * + * The default value is true. If you're encountering installation errors related to peer dependencies, + * it's recommended to set this to false. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + /*[LINE "HYPOTHETICAL"]*/ "implicitlyPreferredVersions": false, + + /** + * If you would like the version specifiers for your dependencies to be consistent, then + * uncomment this line. This is effectively similar to running "rush check" before any + * of the following commands: + * + * rush install, rush update, rush link, rush version, rush publish + * + * In some cases you may want this turned on, but need to allow certain packages to use a different + * version. In those cases, you will need to add an entry to the "allowedAlternativeVersions" + * section of the common-versions.json. + * + * In the case that subspaces is enabled, this setting will take effect at a subspace level. + */ + /*[LINE "HYPOTHETICAL"]*/ "ensureConsistentVersions": true, + + /** + * The "rush check" command can be used to enforce that every project in the repo must specify + * the same SemVer range for a given dependency. However, sometimes exceptions are needed. + * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be + * accepted by "rush check" for a given dependency. + * + * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE + * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). + * This design avoids unnecessary churn in this file. + */ + "allowedAlternativeVersions": { + /** + * 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): + */ + /*[LINE "HYPOTHETICAL"]*/ "typescript": [ + /*[LINE "HYPOTHETICAL"]*/ "~2.4.0" + /*[LINE "HYPOTHETICAL"]*/ ] + } +} \ No newline at end of file diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/custom-tips.json b/libraries/rush-lib/assets/rush-init/common/config/rush/custom-tips.json new file mode 100644 index 00000000000..aacc7cc42c6 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/custom-tips.json @@ -0,0 +1,31 @@ +/** + * This configuration file allows repo maintainers to configure extra details to be + * printed alongside certain Rush messages. More documentation is available on the + * Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", + + /** + * Custom tips allow you to annotate Rush's console messages with advice tailored for + * your specific monorepo. + */ + "customTips": [ + /*[BEGIN "DEMO"]*/ + { + /** + * (REQUIRED) An identifier indicating a message that may be printed by Rush. + * If that message is printed, then this custom tip will be shown. + * The list of available tip identifiers can be found on this page: + * https://rushjs.io/pages/maintainer/custom_tips/ + */ + "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + + /** + * (REQUIRED) The message text to be displayed for this tip. + */ + "message": "For additional troubleshooting information, refer this wiki article:\n\nhttps://intranet.contoso.com/docs/pnpm-mismatch" + } + /*[END "DEMO"]*/ + ] +} 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 new file mode 100644 index 00000000000..605e320a4c9 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json @@ -0,0 +1,121 @@ +/** + * This configuration file allows repo maintainers to enable and disable experimental + * Rush features. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", + + /** + * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead for faster installs. + */ + /*[LINE "HYPOTHETICAL"]*/ "usePnpmFrozenLockfileForRushInstall": true, + + /** + * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. + */ + /*[LINE "HYPOTHETICAL"]*/ "usePnpmPreferFrozenLockfileForRushUpdate": true, + + /** + * By default, 'rush update' runs as a single operation. + * Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. + * Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs. + */ + /*[LINE "HYPOTHETICAL"]*/ "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate": true, + + /** + * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. + * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not + * cause hash changes. + */ + /*[LINE "HYPOTHETICAL"]*/ "omitImportersFromPreventManualShrinkwrapChanges": true, + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + /*[LINE "HYPOTHETICAL"]*/ "noChmodFieldInTarHeaderNormalization": true, + + /** + * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. + * This will not replay warnings from the cached build. + */ + /*[LINE "HYPOTHETICAL"]*/ "buildCacheWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. + * This will not replay warnings from the skipped build. + */ + /*[LINE "HYPOTHETICAL"]*/ "buildSkipWithAllowWarningsInSuccessfulBuild": true, + + /** + * If true, perform a clean install after when running `rush install` or `rush update` if the + * `.npmrc` file has changed since the last install. + */ + /*[LINE "HYPOTHETICAL"]*/ "cleanInstallAfterNpmrcChanges": true, + + /** + * If true, print the outputs of shell commands defined in event hooks to the console. + */ + /*[LINE "HYPOTHETICAL"]*/ "printEventHooksOutputToConsole": true, + + /** + * If true, Rush will not allow node_modules in the repo folder or in parent folders. + */ + /*[LINE "HYPOTHETICAL"]*/ "forbidPhantomResolvableNodeModulesFolders": true, + + /** + * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot + * correctly satisfy versioning requirements without installing duplicate copies of a package inside the + * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally + * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" + * feature provides a model for copying the local project folder into node_modules, however copying + * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. + * The "pnpm-sync" tool manages this operation; see its documentation for details. + * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies + * by invoking "pnpm-sync" during the build. + */ + /*[LINE "HYPOTHETICAL"]*/ "usePnpmSyncForInjectedDependencies": true, + + /** + * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. + */ + /*[LINE "HYPOTHETICAL"]*/ "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. + */ + /*[LINE "HYPOTHETICAL"]*/ "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. + */ + /*[LINE "HYPOTHETICAL"]*/ "rushAlerts": true, + + + /** + * When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache. + */ + /*[LINE "HYPOTHETICAL"]*/ "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. + */ + /*[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 +} 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 new file mode 100644 index 00000000000..d677fa2179f --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/pnpm-config.json @@ -0,0 +1,373 @@ +/** + * 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", + + /** + * If true, then `rush install` and `rush update` will use the PNPM workspaces feature + * to perform the install, instead of the old model where Rush generated the symlinks + * for each projects's node_modules folder. + * + * When using workspaces, Rush will generate a `common/temp/pnpm-workspace.yaml` file referencing + * all local projects to install. Rush will also generate a `.pnpmfile.cjs` shim which implements + * Rush-specific features such as preferred versions. The user's `common/config/rush/.pnpmfile.cjs` + * is invoked by the shim. + * + * This option is strongly recommended. The default value is false. + */ + "useWorkspaces": true, + + /** + * This setting determines how PNPM chooses version numbers during `rush update`. + * For example, suppose `lib-x@3.0.0` depends on `"lib-y": "^1.2.3"` whose latest major + * releases are `1.8.9` and `2.3.4`. The resolution mode `lowest-direct` might choose + * `lib-y@1.2.3`, wheres `highest` will choose 1.8.9, and `time-based` will pick the + * highest compatible version at the time when `lib-x@3.0.0` itself was published (ensuring + * that the version could have been tested by the maintainer of "lib-x"). For local workspace + * projects, `time-based` instead works like `lowest-direct`, avoiding upgrades unless + * they are explicitly requested. Although `time-based` is the most robust option, it may be + * slightly slower with registries such as npmjs.com that have not implemented an optimization. + * + * IMPORTANT: Be aware that PNPM 8.0.0 initially defaulted to `lowest-direct` instead of + * `highest`, but PNPM reverted this decision in 8.6.12 because it caused confusion for users. + * Rush version 5.106.0 and newer avoids this confusion by consistently defaulting to + * `highest` when `resolutionMode` is not explicitly set in pnpm-config.json or .npmrc, + * regardless of your PNPM version. + * + * PNPM documentation: https://pnpm.io/npmrc#resolution-mode + * + * Possible values are: `highest`, `time-based`, and `lowest-direct`. + * The default is `highest`. + */ + /*[LINE "DEMO"]*/ "resolutionMode": "time-based", + + /** + * This setting determines whether PNPM will automatically install (non-optional) + * missing peer dependencies instead of reporting an error. Doing so conveniently + * avoids the need to specify peer versions in package.json, but in a large monorepo + * this often creates worse problems. The reason is that peer dependency behavior + * is inherently complicated, and it is easier to troubleshoot consequences of an explicit + * version than an invisible heuristic. The original NPM RFC discussion pointed out + * some other problems with this feature: https://github.com/npm/rfcs/pull/43 + + * IMPORTANT: Without Rush, the setting defaults to true for PNPM 8 and newer; however, + * as of Rush version 5.109.0 the default is always false unless `autoInstallPeers` + * is specified in pnpm-config.json or .npmrc, regardless of your PNPM version. + + * PNPM documentation: https://pnpm.io/npmrc#auto-install-peers + + * The default value is false. + */ + /*[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: + * + * "minimumReleaseAge": 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"]*/ "minimumReleaseAge": 1440, + + /** + * An array of package names or patterns to exclude from the minimumReleaseAge 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/*"], + + /** + * 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, + * which is an invalid state that can cause build failures or incompatible dependency versions. + * (For historical reasons, JavaScript package managers generally do not treat this invalid + * state as an error.) + * + * PNPM documentation: https://pnpm.io/npmrc#strict-peer-dependencies + * + * The default value is false to avoid legacy compatibility issues. + * It is strongly recommended to set `strictPeerDependencies=true`. + */ + /*[LINE "DEMO"]*/ "strictPeerDependencies": true, + + /** + * Environment variables that will be provided to PNPM. + */ + /*[BEGIN "DEMO"]*/ + "environmentVariables": { + "NODE_OPTIONS": { + "value": "--max-old-space-size=4096", + "override": false + } + }, + /*[END "DEMO"]*/ + + /** + * Specifies the location of the PNPM store. There are two possible values: + * + * - `local` - use the `pnpm-store` folder in the current configured temp folder: + * `common/temp/pnpm-store` by default. + * - `global` - use PNPM's global store, which has the benefit of being shared + * across multiple repo folders, but the disadvantage of less isolation for builds + * (for example, bugs or incompatibilities when two repos use different releases of PNPM) + * + * In both cases, the store path can be overridden by the environment variable `RUSH_PNPM_STORE_PATH`. + * + * The default value is `local`. + */ + /*[LINE "HYPOTHETICAL"]*/ "pnpmStore": "global", + + /** + * If true, then `rush install` will report an error if manual modifications + * were made to the PNPM shrinkwrap file without running `rush update` afterwards. + * + * This feature protects against accidental inconsistencies that may be introduced + * if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this + * feature is enabled, `rush update` will append a hash to the file as a YAML comment, + * and then `rush update` and `rush install` will validate the hash. Note that this + * does not prohibit manual modifications, but merely requires `rush update` be run + * afterwards, ensuring that PNPM can report or repair any potential inconsistencies. + * + * To temporarily disable this validation when invoking `rush install`, use the + * `--bypass-policy` command-line parameter. + * + * The default value is false. + */ + /*[LINE "HYPOTHETICAL"]*/ "preventManualShrinkwrapChanges": true, + + /** + * When a project uses `workspace:` to depend on another Rush project, PNPM normally installs + * it by creating a symlink under `node_modules`. This generally works well, but in certain + * cases such as differing `peerDependencies` versions, symlinking may cause trouble + * such as incorrectly satisfied versions. For such cases, the dependency can be declared + * as "injected", causing PNPM to copy its built output into `node_modules` like a real + * install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/ + * + * When using Rush subspaces, these sorts of versioning problems are much more likely if + * `workspace:` refers to a project from a different subspace. This is because the symlink + * would point to a separate `node_modules` tree installed by a different PNPM lockfile. + * A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`, + * which automatically treats all projects from other subspaces as injected dependencies + * without having to manually configure them. + * + * NOTE: Use carefully -- excessive file copying can slow down the `rush install` and + * `pnpm-sync` operations if too many dependencies become injected. + * + * The default value is false. + */ + /*[LINE "HYPOTHETICAL"]*/ "alwaysInjectDependenciesFromOtherSubspaces": false, + + /** + * Defines the policies to be checked for the `pnpm-lock.yaml` file. + */ + "pnpmLockfilePolicies": { + + /** + * This policy will cause "rush update" to report an error if `pnpm-lock.yaml` contains + * any SHA1 integrity hashes. + * + * For each NPM dependency, `pnpm-lock.yaml` normally stores an `integrity` hash. Although + * its main purpose is to detect corrupted or truncated network requests, this hash can also + * serve as a security fingerprint to protect against attacks that would substitute a + * malicious tarball, for example if a misconfigured .npmrc caused a machine to accidentally + * download a matching package name+version from npmjs.com instead of the private NPM registry. + * NPM originally used a SHA1 hash; this was insecure because an attacker can too easily craft + * a tarball with a matching fingerprint. For this reason, NPM later deprecated SHA1 and + * instead adopted a cryptographically strong SHA512 hash. Nonetheless, SHA1 hashes can + * occasionally reappear during "rush update", for example due to missing metadata fallbacks + * (https://github.com/orgs/pnpm/discussions/6194) or an incompletely migrated private registry. + * The `disallowInsecureSha1` policy prevents this, avoiding potential security/compliance alerts. + */ + /*[BEGIN "HYPOTHETICAL"]*/ + "disallowInsecureSha1": { + /** + * Enables the "disallowInsecureSha1" policy. The default value is false. + */ + "enabled": true, + + /** + * In rare cases, a private NPM registry may continue to serve SHA1 hashes for very old + * package versions, perhaps due to a caching issue or database migration glitch. To avoid + * having to disable the "disallowInsecureSha1" policy for the entire monorepo, the problematic + * package versions can be individually ignored. The "exemptPackageVersions" key is the + * package name, and the array value lists exact version numbers to be ignored. + */ + "exemptPackageVersions": { + "example1": ["1.0.0"], + "example2": ["2.0.0", "2.0.1"] + } + } + /*[END "HYPOTHETICAL"]*/ + }, + + /** + * The "globalOverrides" setting provides a simple mechanism for overriding version selections + * for all dependencies of all projects in the monorepo workspace. The settings are copied + * into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides + */ + "globalOverrides": { + /*[LINE "HYPOTHETICAL"]*/ "example1": "^1.0.0", + /*[LINE "HYPOTHETICAL"]*/ "example2": "npm:@company/example2@^1.0.0" + }, + + /** + * The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors + * that are reported during installation with `strictPeerDependencies=true`. The settings are copied + * into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * https://pnpm.io/package_json#pnpmpeerdependencyrules + */ + "globalPeerDependencyRules": { + /*[BEGIN "HYPOTHETICAL"]*/ + "ignoreMissing": ["@eslint/*"], + "allowedVersions": { "react": "17" }, + "allowAny": ["@babel/*"] + /*[END "HYPOTHETICAL"]*/ + }, + + /** + * The `globalPackageExtension` setting provides a way to patch arbitrary package.json fields + * for any PNPM dependency of the monorepo. The settings are copied into the `pnpm.packageExtensions` + * field of the `common/temp/package.json` file that is generated by Rush during installation. + * The `globalPackageExtension` setting has similar capabilities as `.pnpmfile.cjs` but without + * the downsides of an executable script (nondeterminism, unreliable caching, performance concerns). + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions + */ + "globalPackageExtensions": { + /*[BEGIN "HYPOTHETICAL"]*/ + "fork-ts-checker-webpack-plugin": { + "dependencies": { + "@babel/core": "1" + }, + "peerDependencies": { + "eslint": ">= 6" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + } + /*[END "HYPOTHETICAL"]*/ + }, + + /** + * The `globalNeverBuiltDependencies` setting suppresses the `preinstall`, `install`, and `postinstall` + * lifecycle events for the specified NPM dependencies. This is useful for scripts with poor practices + * such as downloading large binaries without retries or attempting to invoke OS tools such as + * a C++ compiler. (PNPM's terminology refers to these lifecycle events as "building" a package; + * it has nothing to do with build system operations such as `rush build` or `rushx build`.) + * The settings are copied into the `pnpm.neverBuiltDependencies` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies + */ + "globalNeverBuiltDependencies": [ + /*[LINE "HYPOTHETICAL"]*/ "fsevents" + ], + + /** + * 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": [ + /*[LINE "HYPOTHETICAL"]*/ "fsevents" + ], + + /** + * The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package + * versions that the NPM registry reports as being deprecated. This is useful if the + * deprecated package is an indirect dependency of an external package that has not released a fix. + * The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions + * + * If you are working to eliminate a deprecated version, it's better to specify `allowedDeprecatedVersions` + * in the package.json file for individual Rush projects. + */ + "globalAllowedDeprecatedVersions": { + /*[LINE "HYPOTHETICAL"]*/ "request": "*" + }, + + + /** + * (THIS FIELD IS MACHINE GENERATED) The "globalPatchedDependencies" field is updated automatically + * by the `rush-pnpm patch-commit` command. It is a dictionary, where the key is an NPM package name + * and exact version, and the value is a relative path to the associated patch file. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies + */ + "globalPatchedDependencies": { }, + + /** + * (USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into + * the `common/temp/package.json` file that is generated by Rush during installation. + * This provides a way to experiment with new PNPM features. These settings will override + * any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`. + * + * USAGE OF THIS SETTING IS NOT SUPPORTED BY THE RUSH MAINTAINERS AND MAY CAUSE RUSH + * TO MALFUNCTION. If you encounter a missing PNPM setting that you believe should + * be supported, please create a GitHub issue or PR. Note that Rush does not aim to + * support every possible PNPM setting, but rather to promote a battle-tested installation + * strategy that is known to provide a good experience for large teams with lots of projects. + */ + "unsupportedPackageJsonSettings": { + /*[BEGIN "HYPOTHETICAL"]*/ + "dependencies": { + "not-a-good-practice": "*" + }, + "scripts": { + "do-something": "echo Also not a good practice" + }, + "pnpm": { "futurePnpmFeature": true } + /*[END "HYPOTHETICAL"]*/ + } +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/rush-alerts.json b/libraries/rush-lib/assets/rush-init/common/config/rush/rush-alerts.json new file mode 100644 index 00000000000..0118d33ca69 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/rush-alerts.json @@ -0,0 +1,115 @@ +/** + * This configuration file manages the Rush alerts feature. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-alerts.schema.json", + + /** + * Settings such as `startTime` and `endTime` will use this timezone. + * If omitted, the default timezone is UTC (`+00:00`). + */ + "timezone": "-08:00", + + /** + * An array of alert messages and conditions for triggering them. + */ + "alerts": [ + /*[BEGIN "DEMO"]*/ + { + /** + * The alertId is used to identify the alert. + */ + "alertId": "node-js", + + /** + * When the alert is displayed, this title will appear at the top of the message box. + * It should be a single line of text, as concise as possible. + */ + "title": "Node.js upgrade soon!", + + /** + * When the alert is displayed, this text appears in the message box. To make the + * JSON file more readable, if the text is longer than one line, you can instead provide + * an array of strings that will be concatenated. Your text may contain newline characters, + * but generally this is unnecessary because word-wrapping is automatically applied. + */ + "message": [ + "This Thursday, we will complete the Node.js version upgrade. Any pipelines that", + " still have not upgraded will be temporarily disabled." + ], + + /** + * (OPTIONAL) To avoid spamming users, the `title` and `message` settings should be kept + * as concise as possible. If you need to provide more detail, use this setting to + * print a hyperlink to a web page with further guidance. + */ + /*[LINE "HYPOTHETICAL"]*/ "detailsUrl": "https://contoso.com/team-wiki/2024-01-01-migration", + + /** + * (OPTIONAL) If `startTime` is specified, then this alert will not be shown prior to + * that time. + * + * Keep in mind that the alert is not guaranteed to be shown at this time, or at all: + * Alerts are only displayed after a Rush command has triggered fetching of the + * latest rush-alerts.json configuration. Also, display of alerts is throttled to + * avoid spamming the user with too many messages. If you need to test your alert, + * set the environment variable `RUSH_ALERTS_DEBUG=1` to disable throttling. + * + * The `startTime` should be specified as `YYYY-MM-DD HH:MM` using 24 hour time format, + * or else `YYYY-MM-DD` in which case the time part will be `00:00` (start of that day). + * The time zone is obtained from the `timezone` setting above. + */ + /*[LINE "HYPOTHETICAL"]*/ "startTime": "2024-01-01 15:00", + + /** + * (OPTIONAL) This alert will not be shown if the current time is later than `endTime`. + * The format is the same as `startTime`. + */ + /*[LINE "HYPOTHETICAL"]*/ "endTime": "2024-01-05", + + /** + * (OPTIONAL) Specifies the maximum frequency at which this alert can be displayed within a defined time period. + * Options are: + * "always" (default) - no limit on display frequency, + * "monthly" - display up to once per month + * "weekly" - display up to once per week + * "daily" - display up to once per day + * "hourly" - display up to once per hour + */ + /*[LINE "HYPOTHETICAL"]*/ "maximumDisplayInterval": "always", + + /** + * (OPTIONAL) Determines the order in which this alert is shown relative to other alerts, based on urgency. + * Options are: + * "high" - displayed first + * "normal" (default) - standard urgency + * "low" - least urgency + */ + /*[LINE "HYPOTHETICAL"]*/ "priority": "normal", + + /** + * (OPTIONAL) The filename of a script that determines whether this alert can be shown, + * found in the "common/config/rush/alert-scripts" folder. The script must define + * a CommonJS export named `canShowAlert` that returns a boolean value, for example: + * + * ``` + * module.exports.canShowAlert = function () { + * // (your logic goes here) + * return true; + * } + * ``` + * + * Rush will invoke this script with the working directory set to the monorepo root folder, + * with no guarantee that `rush install` has been run. To ensure up-to-date alerts, Rush + * may fetch and checkout the "common/config/rush-alerts" folder in an unpredictable temporary + * path. Therefore, your script should avoid importing dependencies from outside its folder, + * generally be kept as simple and reliable and quick as possible. For more complex conditions, + * we suggest to design some other process that prepares a data file or environment variable + * that can be cheaply checked by your condition script. + */ + /*[LINE "HYPOTHETICAL"]*/ "conditionScript": "rush-alert-node-upgrade.js" + } + /*[END "DEMO"]*/ + ] +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/rush-plugins.json b/libraries/rush-lib/assets/rush-init/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..beb523e4269 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/rush-plugins.json @@ -0,0 +1,31 @@ +/** + * This configuration file manages Rush's plugin feature. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json", + "plugins": [ + /** + * Each item configures a plugin to be loaded by Rush. + */ + /*[BEGIN "HYPOTHETICAL"]*/ + { + /** + * The name of the NPM package that provides the plugin. + */ + "packageName": "@scope/my-rush-plugin", + /** + * The name of the plugin. This can be found in the "pluginName" + * field of the "rush-plugin-manifest.json" file in the NPM package folder. + */ + "pluginName": "my-plugin-name", + /** + * The name of a Rush autoinstaller that will be used for installation, which + * can be created using "rush init-autoinstaller". Add the plugin's NPM package + * to the package.json "dependencies" of your autoinstaller, then run + * "rush update-autoinstaller". + */ + "autoinstallerName": "rush-plugins" + } + /*[END "HYPOTHETICAL"]*/ + ] +} \ No newline at end of file diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json b/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json new file mode 100644 index 00000000000..d3c3ae8c516 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json @@ -0,0 +1,35 @@ +/** + * This configuration file manages the experimental "subspaces" feature for Rush, + * which allows multiple PNPM lockfiles to be used in a single Rush workspace. + * For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + + /** + * Set this flag to "true" to enable usage of subspaces. + */ + "subspacesEnabled": false, + + /** + * (DEPRECATED) This is a temporary workaround for migrating from an earlier prototype + * of this feature: https://github.com/microsoft/rushstack/pull/3481 + * It allows subspaces with only one project to store their config files in the project folder. + */ + "splitWorkspaceCompatibility": false, + + /** + * When a command such as "rush update" is invoked without the "--subspace" or "--to" + * parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces, + * this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this + * mistake by always requiring selection parameters for commands such as "rush update". + */ + "preventSelectingAllSubspaces": false, + + /** + * The list of subspace names, which should be lowercase alphanumeric words separated by + * hyphens, for example "my-subspace". The corresponding config files will have paths + * such as "common/config/subspaces/my-subspace/package-lock.yaml". + */ + "subspaceNames": [] +} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/version-policies.json b/libraries/rush-lib/assets/rush-init/common/config/rush/version-policies.json new file mode 100644 index 00000000000..fa53012f5b2 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/version-policies.json @@ -0,0 +1,104 @@ +/** + * This is configuration file is used for advanced publishing configurations with Rush. + * More documentation is available on the Rush website: https://rushjs.io + */ + +/** + * A list of version policy definitions. A "version policy" is a custom package versioning + * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies + * to a set of projects that are specified using the "versionPolicyName" field in rush.json. + */ +[ + /*[BEGIN "DEMO"]*/ + { + /** + * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). + * + * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This + * strategy is appropriate for a set of packages that act as selectable components of a + * unified product. The entire set of packages are always published together, and always share + * the same NPM version number. When the packages depend on other packages in the set, the + * SemVer range is usually restricted to a single version. + */ + "definitionName": "lockStepVersion", + + /** + * (Required) The name that will be used for the "versionPolicyName" field in rush.json. + * This name is also used command-line parameters such as "--version-policy" + * and "--to-version-policy". + */ + "policyName": "MyBigFramework", + + /** + * (Required) The current version. All packages belonging to the set should have this version + * in the current branch. When bumping versions, Rush uses this to determine the next version. + * (The "version" field in package.json is NOT considered.) + */ + "version": "1.0.0", + + /** + * (Required) The type of bump that will be performed when publishing the next release. + * When creating a release branch in Git, this field should be updated according to the + * type of release. + * + * Valid values are: "prerelease", "preminor", "minor", "patch", "major" + */ + "nextBump": "prerelease", + + /** + * (Optional) If specified, all packages in the set share a common CHANGELOG.md file. + * This file is stored with the specified "main" project, which must be a member of the set. + * + * If this field is omitted, then a separate CHANGELOG.md file will be maintained for each + * package in the set. + */ + "mainProject": "my-app", + + /** + * (Optional) If enabled, the "rush change" command will prompt the user for their email address + * and include it in the JSON change files. If an organization maintains multiple repos, tracking + * this contact information may be useful for a service that automatically upgrades packages and + * needs to notify engineers whose change may be responsible for a downstream build break. It might + * also be useful for crediting contributors. Rush itself does not do anything with the collected + * email addresses. The default value is "false". + */ + /*[LINE "HYPOTHETICAL"]*/ "includeEmailInChangeFile": true + }, + + { + /** + * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). + * + * The "individualVersion" mode specifies that the projects will use "individual versioning". + * This is the typical NPM model where each package has an independent version number + * and CHANGELOG.md file. Although a single CI definition is responsible for publishing the + * packages, they otherwise don't have any special relationship. The version bumping will + * depend on how developers answer the "rush change" questions for each package that + * is changed. + */ + "definitionName": "individualVersion", + + "policyName": "MyRandomLibraries", + + /** + * (Optional) This can be used to enforce that all packages in the set must share a common + * major version number, e.g. because they are from the same major release branch. + * It can also be used to discourage people from accidentally making "MAJOR" SemVer changes + * inappropriately. The minor/patch version parts will be bumped independently according + * to the types of changes made to each project, according to the "rush change" command. + */ + "lockedMajor": 3, + + /** + * (Optional) When publishing is managed by Rush, by default the "rush change" command will + * request changes for any projects that are modified by a pull request. These change entries + * will produce a CHANGELOG.md file. If you author your CHANGELOG.md manually or announce updates + * in some other way, set "exemptFromRushChange" to true to tell "rush change" to ignore the projects + * belonging to this version policy. + */ + "exemptFromRushChange": false, + + /*[LINE "HYPOTHETICAL"]*/ "includeEmailInChangeFile": true + } + /*[END "DEMO"]*/ +] diff --git a/libraries/rush-lib/assets/rush-init/common/git-hooks/commit-msg.sample b/libraries/rush-lib/assets/rush-init/common/git-hooks/commit-msg.sample new file mode 100644 index 00000000000..59cacb80ca1 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/common/git-hooks/commit-msg.sample @@ -0,0 +1,25 @@ +#!/bin/sh +# +# This is an example Git hook for use with Rush. To enable this hook, rename this file +# to "commit-msg" and then run "rush install", which will copy it from common/git-hooks +# to the .git/hooks folder. +# +# TO LEARN MORE ABOUT GIT HOOKS +# +# The Git documentation is here: https://git-scm.com/docs/githooks +# Some helpful resources: https://githooks.com +# +# ABOUT THIS EXAMPLE +# +# The commit-msg hook is called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero status after issuing +# an appropriate message if it wants to stop the commit. The hook is allowed to edit +# the commit message file. + +# This example enforces that commit message should contain a minimum amount of +# description text. +if [ `cat $1 | wc -w` -lt 3 ]; then + echo "" + echo "Invalid commit message: The message must contain at least 3 words." + exit 1 +fi diff --git a/libraries/rush-lib/assets/rush-init/rush.json b/libraries/rush-lib/assets/rush-init/rush.json new file mode 100644 index 00000000000..20d52ad9f60 --- /dev/null +++ b/libraries/rush-lib/assets/rush-init/rush.json @@ -0,0 +1,452 @@ +/** + * This is the main configuration file for Rush. + * For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + + /** + * (Required) This specifies the version of the Rush engine to be used in this repo. + * Rush's "version selector" feature ensures that the globally installed tool will + * behave like this release, regardless of which version is installed globally. + * + * The common/scripts/install-run-rush.js automation script also uses this version. + * + * NOTE: If you upgrade to a new major version of Rush, you should replace the "v5" + * path segment in the "$schema" field for all your Rush config files. This will ensure + * correct error-underlining and tab-completion for editors such as VS Code. + */ + "rushVersion": "[%RUSH_VERSION%]", + + /** + * The next field selects which package manager should be installed and determines its version. + * Rush installs its own local copy of the package manager to ensure that your build process + * is fully isolated from whatever tools are present in the local environment. + * + * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation + * for details about these alternatives. + */ + "pnpmVersion": "9.15.9", + + /*[LINE "HYPOTHETICAL"]*/ "npmVersion": "6.14.15", + /*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4", + + /** + * Older releases of the Node.js engine may be missing features required by your system. + * Other releases may have bugs. In particular, the "latest" version will not be a + * Long Term Support (LTS) version and is likely to have regressions. + * + * Specify a SemVer range to ensure developers use a Node.js version that is appropriate + * for your repo. + * + * LTS schedule: https://nodejs.org/en/about/releases/ + * LTS versions: https://nodejs.org/en/download/releases/ + */ + "nodeSupportedVersionRange": ">=22.20.0 <23.0.0", + + /** + * If the version check above fails, Rush will display a message showing the current + * node version and the supported version range. You can use this setting to provide + * additional instructions that will display below the warning, if there's a specific + * tool or script you'd like the user to use to get in line with the expected version. + */ + /*[LINE "HYPOTHETICAL"]*/ "nodeSupportedVersionInstructions": "Run 'nvs use' to switch to the expected node version.", + + /** + * Odd-numbered major versions of Node.js are experimental. Even-numbered releases + * spend six months in a stabilization period before the first Long Term Support (LTS) version. + * For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended + * for production usage because they frequently have bugs. They may cause Rush itself + * to malfunction. + * + * Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing + * pre-LTS versions in preparation for supporting the first LTS version, you can use this setting + * to disable Rush's warning. + */ + /*[LINE "HYPOTHETICAL"]*/ "suppressNodeLtsWarning": false, + + /** + * Rush normally prints a warning if it detects that the current version is not one published to the + * public npmjs.org registry. If you need to block calls to the npm registry, you can use this setting to disable + * Rush's check. + */ + /*[LINE "HYPOTHETICAL"]*/ "suppressRushIsPublicVersionCheck": false, + + /** + * Large monorepos can become intimidating for newcomers if project folder paths don't follow + * a consistent and recognizable pattern. When the system allows nested folder trees, + * we've found that teams will often use subfolders to create islands that isolate + * their work from others ("shipping the org"). This hinders collaboration and code sharing. + * + * The Rush developers recommend a "category folder" model, where buildable project folders + * must always be exactly two levels below the repo root. The parent folder acts as the category. + * This provides a basic facility for grouping related projects (e.g. "apps", "libraries", + * "tools", "prototypes") while still encouraging teams to organize their projects into + * a unified taxonomy. Limiting to 2 levels seems very restrictive at first, but if you have + * 20 categories and 20 projects in each category, this scheme can easily accommodate hundreds + * of projects. In practice, you will find that the folder hierarchy needs to be rebalanced + * occasionally, but if that's painful, it's a warning sign that your development style may + * discourage refactoring. Reorganizing the categories should be an enlightening discussion + * that brings people together, and maybe also identifies poor coding practices (e.g. file + * references that reach into other project's folders without using Node.js module resolution). + * + * The defaults are projectFolderMinDepth=1 and projectFolderMaxDepth=2. + * + * To remove these restrictions, you could set projectFolderMinDepth=1 + * and set projectFolderMaxDepth to a large number. + */ + /*[LINE "HYPOTHETICAL"]*/ "projectFolderMinDepth": 2, + /*[LINE "HYPOTHETICAL"]*/ "projectFolderMaxDepth": 2, + + /** + * Today the npmjs.com registry enforces fairly strict naming rules for packages, but in the early + * days there was no standard and hardly any enforcement. A few large legacy projects are still using + * nonstandard package names, and private registries sometimes allow it. Set "allowMostlyStandardPackageNames" + * to true to relax Rush's enforcement of package names. This allows upper case letters and in the future may + * relax other rules, however we want to minimize these exceptions. Many popular tools use certain punctuation + * characters as delimiters, based on the assumption that they will never appear in a package name; thus if we relax + * the rules too much it is likely to cause very confusing malfunctions. + * + * The default value is false. + */ + /*[LINE "HYPOTHETICAL"]*/ "allowMostlyStandardPackageNames": true, + + /** + * This feature helps you to review and approve new packages before they are introduced + * to your monorepo. For example, you may be concerned about licensing, code quality, + * performance, or simply accumulating too many libraries with overlapping functionality. + * The approvals are tracked in two config files "browser-approved-packages.json" + * and "nonbrowser-approved-packages.json". See the Rush documentation for details. + */ + /*[BEGIN "DEMO"]*/ + "approvedPackagesPolicy": { + /** + * The review categories allow you to say for example "This library is approved for usage + * in prototypes, but not in production code." + * + * Each project can be associated with one review category, by assigning the "reviewCategory" field + * in the "projects" section of rush.json. The approval is then recorded in the files + * "common/config/rush/browser-approved-packages.json" and "nonbrowser-approved-packages.json" + * which are automatically generated during "rush update". + * + * Designate categories with whatever granularity is appropriate for your review process, + * or you could just have a single category called "default". + */ + "reviewCategories": [ + // Some example categories: + "production", // projects that ship to production + "tools", // non-shipping projects that are part of the developer toolchain + "prototypes" // experiments that should mostly be ignored by the review process + ], + + /** + * A list of NPM package scopes that will be excluded from review. + * We recommend to exclude TypeScript typings (the "@types" scope), because + * if the underlying package was already approved, this would imply that the typings + * are also approved. + */ + /*[LINE "HYPOTHETICAL"]*/ "ignoredNpmScopes": ["@types"] + }, + /*[END "DEMO"]*/ + + /** + * If you use Git as your version control system, this section has some additional + * optional features you can use. + */ + "gitPolicy": { + /** + * Work at a big company? Tired of finding Git commits at work with unprofessional Git + * emails such as "beer-lover@my-college.edu"? Rush can validate people's Git email address + * before they get started. + * + * Define a list of regular expressions describing allowable e-mail patterns for Git commits. + * They are case-insensitive anchored JavaScript RegExps. Example: ".*@example\.com" + * + * IMPORTANT: Because these are regular expressions encoded as JSON string literals, + * RegExp escapes need two backslashes, and ordinary periods should be "\\.". + */ + /*[BEGIN "DEMO"]*/ + "allowedEmailRegExps": [ + "[^@]+@users\\.noreply\\.github\\.com", + "rush-bot@example\\.org" + ], + /*[END "DEMO"]*/ + + /** + * When Rush reports that the address is malformed, the notice can include an example + * of a recommended email. Make sure it conforms to one of the allowedEmailRegExps + * expressions. + */ + /*[LINE "DEMO"]*/ "sampleEmail": "example@users.noreply.github.com", + + /** + * The commit message to use when committing changes during 'rush publish'. + * + * For example, if you want to prevent these commits from triggering a CI build, + * you might configure your system's trigger to look for a special string such as "[skip-ci]" + * in the commit message, and then customize Rush's message to contain that string. + */ + /*[LINE "DEMO"]*/ "versionBumpCommitMessage": "Bump versions [skip ci]", + + /** + * The commit message to use when committing changes during 'rush version'. + * + * For example, if you want to prevent these commits from triggering a CI build, + * you might configure your system's trigger to look for a special string such as "[skip-ci]" + * in the commit message, and then customize Rush's message to contain that string. + */ + /*[LINE "DEMO"]*/ "changeLogUpdateCommitMessage": "Update changelogs [skip ci]", + + /** + * The commit message to use when committing changefiles during 'rush change --commit' + * + * If no commit message is set it will default to 'Rush change' + */ + /*[LINE "DEMO"]*/ "changefilesCommitMessage": "Rush change" + }, + + "repository": { + /** + * The URL of this Git repository, used by "rush change" to determine the base branch for your PR. + * + * The "rush change" command needs to determine which files are affected by your PR diff. + * If you merged or cherry-picked commits from the main branch into your PR branch, those commits + * should be excluded from this diff (since they belong to some other PR). In order to do that, + * Rush needs to know where to find the base branch for your PR. This information cannot be + * determined from Git alone, since the "pull request" feature is not a Git concept. Ideally + * Rush would use a vendor-specific protocol to query the information from GitHub, Azure DevOps, etc. + * But to keep things simple, "rush change" simply assumes that your PR is against the "main" branch + * of the Git remote indicated by the repository.url setting in rush.json. If you are working in + * a GitHub "fork" of the real repo, this setting will be different from the repository URL of your + * your PR branch, and in this situation "rush change" will also automatically invoke "git fetch" + * to retrieve the latest activity for the remote main branch. + */ + /*[LINE "HYPOTHETICAL"]*/ "url": "https://github.com/microsoft/rush-example", + + /** + * The default branch name. This tells "rush change" which remote branch to compare against. + * The default value is "main" + */ + /*[LINE "HYPOTHETICAL"]*/ "defaultBranch": "main", + + /** + * The default remote. This tells "rush change" which remote to compare against if the remote URL is + * not set or if a remote matching the provided remote URL is not found. + */ + /*[LINE "HYPOTHETICAL"]*/ "defaultRemote": "origin" + }, + + /** + * Event hooks are customized script actions that Rush executes when specific events occur + */ + "eventHooks": { + /** + * A list of shell commands to run before "rush install" or "rush update" starts installation + */ + "preRushInstall": [ + /*[LINE "HYPOTHETICAL"]*/ "common/scripts/pre-rush-install.js" + ], + + /** + * A list of shell commands to run after "rush install" or "rush update" finishes installation + */ + "postRushInstall": [], + + /** + * A list of shell commands to run before "rush build" or "rush rebuild" starts building + */ + "preRushBuild": [], + + /** + * A list of shell commands to run after "rush build" or "rush rebuild" finishes building + */ + "postRushBuild": [], + + /** + * A list of shell commands to run before the "rushx" command starts + */ + "preRushx": [], + + /** + * A list of shell commands to run after the "rushx" command finishes + */ + "postRushx": [] + }, + + /** + * Installation variants allow you to maintain a parallel set of configuration files that can be + * used to build the entire monorepo with an alternate set of dependencies. For example, suppose + * you upgrade all your projects to use a new release of an important framework, but during a transition period + * you intend to maintain compatibility with the old release. In this situation, you probably want your + * CI validation to build the entire repo twice: once with the old release, and once with the new release. + * + * Rush "installation variants" correspond to sets of config files located under this folder: + * + * common/config/rush/variants/ + * + * The variant folder can contain an alternate common-versions.json file. Its "preferredVersions" field can be used + * to select older versions of dependencies (within a loose SemVer range specified in your package.json files). + * To install a variant, run "rush install --variant ". + * + * For more details and instructions, see this article: https://rushjs.io/pages/advanced/installation_variants/ + */ + "variants": [ + /*[BEGIN "HYPOTHETICAL"]*/ + { + /** + * The folder name for this variant. + */ + "variantName": "old-sdk", + + /** + * An informative description + */ + "description": "Build this repo using the previous release of the SDK" + } + /*[END "HYPOTHETICAL"]*/ + ], + + /** + * Rush can collect anonymous telemetry about everyday developer activity such as + * success/failure of installs, builds, and other operations. You can use this to identify + * problems with your toolchain or Rush itself. THIS TELEMETRY IS NOT SHARED WITH MICROSOFT. + * It is written into JSON files in the common/temp folder. It's up to you to write scripts + * that read these JSON files and do something with them. These scripts are typically registered + * in the "eventHooks" section. + */ + /*[LINE "HYPOTHETICAL"]*/ "telemetryEnabled": false, + + /** + * Allows creation of hotfix changes. This feature is experimental so it is disabled by default. + * If this is set, 'rush change' only allows a 'hotfix' change type to be specified. This change type + * will be used when publishing subsequent changes from the monorepo. + */ + /*[LINE "HYPOTHETICAL"]*/ "hotfixChangeEnabled": false, + + /** + * This is an optional, but recommended, list of allowed tags that can be applied to Rush projects + * using the "tags" setting in this file. This list is useful for preventing mistakes such as misspelling, + * and it also provides a centralized place to document your tags. If "allowedProjectTags" list is + * not specified, then any valid tag is allowed. A tag name must be one or more words + * separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, + * ".", and "@" characters. + */ + /*[LINE "HYPOTHETICAL"]*/ "allowedProjectTags": [ "tools", "frontend-team", "1.0.0-release" ], + + /** + * (Required) This is the inventory of projects to be managed by Rush. + * + * Rush does not automatically scan for projects using wildcards, for a few reasons: + * 1. Depth-first scans are expensive, particularly when tools need to repeatedly collect the list. + * 2. On a caching CI machine, scans can accidentally pick up files left behind from a previous build. + * 3. It's useful to have a centralized inventory of all projects and their important metadata. + */ + "projects": [ + /*[BEGIN "DEMO"]*/ + { + /** + * The NPM package name of the project (must match package.json) + */ + "packageName": "my-app", + + /** + * The path to the project folder, relative to the rush.json config file. + */ + "projectFolder": "apps/my-app", + + /** + * This field is only used if "subspacesEnabled" is true in subspaces.json. + * It specifies the subspace that this project belongs to. If omitted, then the + * project belongs to the "default" subspace. + */ + /*[LINE "HYPOTHETICAL"]*/ "subspaceName": "my-subspace", + + /** + * An optional category for usage in the "browser-approved-packages.json" + * and "nonbrowser-approved-packages.json" files. The value must be one of the + * strings from the "reviewCategories" defined above. + */ + "reviewCategory": "production", + + /** + * A list of Rush project names that are to be installed from NPM + * instead of linking to the local project. + * + * If a project's package.json specifies a dependency that is another Rush project + * in the monorepo workspace, normally Rush will locally link its folder instead of + * installing from NPM. If you are using PNPM workspaces, this is indicated by + * a SemVer range such as "workspace:^1.2.3". To prevent mistakes, Rush reports + * an error if the "workspace:" protocol is missing. + * + * Locally linking ensures that regressions are caught as early as possible and is + * a key benefit of monorepos. However there are occasional situations where + * installing from NPM is needed. A classic example is a cyclic dependency. + * Imagine three Rush projects: "my-toolchain" depends on "my-tester", which depends + * on "my-library". Suppose that we add "my-toolchain" to the "devDependencies" + * of "my-library" so it can be built by our toolchain. This cycle creates + * a problem -- Rush can't build a project using a not-yet-built dependency. + * We can solve it by adding "my-toolchain" to the "decoupledLocalDependencies" + * of "my-library", so it builds using the last published release. Choose carefully + * which package to decouple; some choices are much easier to manage than others. + * + * (In older Rush releases, this setting was called "cyclicDependencyProjects".) + */ + "decoupledLocalDependencies": [ + /*[LINE "HYPOTHETICAL"]*/ "my-toolchain" + ], + + /** + * If true, then this project will be ignored by the "rush check" command. + * The default value is false. + */ + /*[LINE "HYPOTHETICAL"]*/ "skipRushCheck": false, + + /** + * A flag indicating that changes to this project will be published to npm, which affects + * the Rush change and publish workflows. The default value is false. + * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. + */ + /*[LINE "HYPOTHETICAL"]*/ "shouldPublish": false, + + /** + * Facilitates postprocessing of a project's files prior to publishing. + * + * If specified, the "publishFolder" is the relative path to a subfolder of the project folder. + * The "rush publish" command will publish the subfolder instead of the project folder. The subfolder + * must contain its own package.json file, which is typically a build output. + */ + /*[LINE "HYPOTHETICAL"]*/ "publishFolder": "temp/publish", + + /** + * An optional version policy associated with the project. Version policies are defined + * in "version-policies.json" file. See the "rush publish" documentation for more info. + * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both. + */ + /*[LINE "HYPOTHETICAL"]*/ "versionPolicyName": "", + + /** + * An optional set of custom tags that can be used to select this project. For example, + * adding "my-custom-tag" will allow this project to be selected by the + * command "rush list --only tag:my-custom-tag". The tag name must be one or more words + * separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, + * ".", and "@" characters. + */ + /*[LINE "HYPOTHETICAL"]*/ "tags": [ "1.0.0-release", "frontend-team" ] + }, + + { + "packageName": "my-controls", + "projectFolder": "libraries/my-controls", + "reviewCategory": "production", + "tags": [ "frontend-team" ] + }, + + { + "packageName": "my-toolchain", + "projectFolder": "tools/my-toolchain", + "reviewCategory": "tools", + "tags": [ "tools" ] + } + /*[END "DEMO"]*/ + ] +} diff --git a/libraries/rush-lib/assets/website-only/rush-plugin-manifest.json b/libraries/rush-lib/assets/website-only/rush-plugin-manifest.json new file mode 100644 index 00000000000..66d5ae3cb46 --- /dev/null +++ b/libraries/rush-lib/assets/website-only/rush-plugin-manifest.json @@ -0,0 +1,68 @@ +/** + * This file defines the Rush plugins that are provided by this package. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", + + /** + * An array of one or more plugin definitions provided by this NPM package. + * + * For more granular installations, it is recommended for plugins to be implemented by an + * NPM package that does try to serve other roles such as providing APIs or command-line binaries. + * The package name should start with "rush-". The name should end with "-plugin" or "-plugins". + * For example: "@scope/rush-business-policy-plugin" + */ + "plugins": [ + { + /** + * (Required) The name of the plugin. The plugin name must be comprised of letters and numbers + * forming one or more words that are separated by hyphens. Note that if the plugin has a + * JSON config file, that filename will be the same as the plugin name. See "optionsSchema" below + * for details. + * + * If the manifest defines exactly one plugin, then it is suggested to reuse the name from the + * NPM package. For example, if the NPM package is "@scope/rush-business-policy-plugin" + * then the plugin name might be "business-policy" and with config file "business-policy.json". + */ + "pluginName": "example", + + /** + * (Required) Provide some documentation that summarizes the problem solved by this plugin, + * how to invoke it, and what operations it performs. + */ + "description": "An example plugin" + + /** + * (Optional) A path to a JavaScript code module that implements the "IRushPlugin" interface. + * This module can use the "@rushstack/rush-sdk" API to register handlers for Rush events + * and services. The module path is relative to the folder containing the "package.json" file. + */ + // "entryPoint": "lib/example/RushExamplePlugin.js", + + /** + * (Optional) A path to a "command-line.json" file that defines Rush command line actions + * and parameters contributed by this plugin. This config file has the same JSON schema + * as Rush's "common/config/rush/command-line.json" file. + */ + // "commandLineJsonFilePath": "lib/example/command-line.json", + + /** + * (Optional) A path to a JSON schema for validating the config file that end users can + * create to customize this plugin's behavior. Plugin config files are stored in the folder + * "common/config/rush-plugins/" with a filename corresponding to the "pluginName" field + * from the manifest. For example: "common/config/rush-plugins/business-policy.json" + * whose schema is "business-policy.schema.json". + */ + // "optionsSchema": "lib/example/example.schema.json", + + /** + * (Optional) A list of associated Rush command names such as "build" from "rush build". + * If specified, then the plugin's "entryPoint" code module be loaded only if + * one of the specified commands is invoked. This improves performance by avoiding + * loading the code module when it is not needed. If "associatedCommands" is + * not specified, then the code module will always be loaded. + */ + // "associatedCommands": [ "build" ] + } + ] +} diff --git a/libraries/rush-lib/assets/website-only/rush-project.json b/libraries/rush-lib/assets/website-only/rush-project.json new file mode 100644 index 00000000000..1347fb59eea --- /dev/null +++ b/libraries/rush-lib/assets/website-only/rush-project.json @@ -0,0 +1,61 @@ +/** + * The "config/rush-project.json" file configures Rush-specific settings for an individual project + * in a Rush monorepo. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.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": "my-rig/profiles/default/config/rush-project.json", + + /** + * The incremental analyzer can skip Rush commands for projects whose input files have not changed since + * the last build. Normally, every Git-tracked file under the project folder is assumed to be an input. + * Use "incrementalBuildIgnoredGlobs" to ignore specific files, specified as globs relative to + * the project folder. The glob syntax is based on the .gitignore file format. + */ + "incrementalBuildIgnoredGlobs": [ + // "etc/api-report/*.md" + ], + + /** + * Disable caching for this project. The project will never be restored from cache. This may be useful + * if this project affects state outside of its folder. + * + * Default value: false + */ + // "disableBuildCacheForProject": true, + + /** + * Options for individual commands and phases. + */ + "operationSettings": [ + // { + // /** + // * (Required) The name of the operation. + // * This should be a key in the "package.json" file's "scripts" section. + // */ + // "operationName": "build", + // + // /** + // * Specify the folders where this operation writes its output files. If enabled, the Rush build cache + // * will restore these folders from the cache. The strings are folder names under the project root folder. + // * These folders should not be tracked by Git. They must not contain symlinks. + // */ + // "outputFolderNames": [ + // "lib", "dist" + // ], + // + // /** + // * Disable caching for this operation. The operation will never be restored from cache. + // * This may be useful if this operation affects state outside of its folder. + // */ + // // "disableBuildCacheForOperation": true + // } + ] +} diff --git a/libraries/rush-lib/config/api-extractor.json b/libraries/rush-lib/config/api-extractor.json new file mode 100644 index 00000000000..3386b9a947a --- /dev/null +++ b/libraries/rush-lib/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/rush-lib/config/heft.json b/libraries/rush-lib/config/heft.json new file mode 100644 index 00000000000..e260d7e35e9 --- /dev/null +++ b/libraries/rush-lib/config/heft.json @@ -0,0 +1,87 @@ +/** + * 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", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["lib-esnext"] }], + + "tasksByName": { + "copy-mock-flush-telemetry-plugin": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "lib-commonjs/cli/test/rush-mock-flush-telemetry-plugin", + "destinationFolders": [ + "lib-commonjs/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/node_modules/rush-mock-flush-telemetry-plugin" + ], + "fileExtensions": [".json", ".js", ".map"], + "hardlink": true + }, + { + "sourcePath": "src/cli/test", + "destinationFolders": ["lib-commonjs/cli/test"], + "fileExtensions": [".js"] + }, + { + "sourcePath": "src/logic/pnpm/test", + "destinationFolders": ["lib-commonjs/logic/pnpm/test"], + "fileExtensions": [".yaml"] + }, + { + "sourcePath": "src/logic/test", + "destinationFolders": ["lib-commonjs/logic/test"], + "includeGlobs": ["**/.mergequeueignore"] + } + ] + } + } + }, + + "copy-empty-modules": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./scripts/copyEmptyModules.js" + } + } + }, + + "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 new file mode 100644 index 00000000000..ad4d21b0971 --- /dev/null +++ b/libraries/rush-lib/config/jest.config.json @@ -0,0 +1,19 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.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__/**" + ], + + "globalTeardown": "/lib-commonjs/utilities/test/global-teardown.js" +} diff --git a/libraries/rush-lib/config/rig.json b/libraries/rush-lib/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rush-lib/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-lib/config/typescript.json b/libraries/rush-lib/config/typescript.json new file mode 100644 index 00000000000..587de5fc0f8 --- /dev/null +++ b/libraries/rush-lib/config/typescript.json @@ -0,0 +1,12 @@ +{ + "$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/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 new file mode 100644 index 00000000000..235fa171670 --- /dev/null +++ b/libraries/rush-lib/package.json @@ -0,0 +1,106 @@ +{ + "name": "@microsoft/rush-lib", + "version": "5.163.0", + "description": "A library for writing scripts that interact with the Rush tool", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/rush-lib" + }, + "engines": { + "node": ">=5.6.0" + }, + "engineStrict": true, + "homepage": "https://rushjs.io", + "main": "lib/index.js", + "typings": "dist/rush-lib.d.ts", + "typesVersions": { + "*": { + "lib-esnext/*": [ + "lib/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "test": "heft test --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", + "@pnpm/dependency-path-lockfile-pre-v10": "npm:@pnpm/dependency-path@~5.1.7", + "@pnpm/dependency-path": "~1000.0.9", + "@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/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": "~8.2.7", + "js-yaml": "~4.1.0", + "npm-package-arg": "~6.1.0", + "object-hash": "3.0.0", + "pnpm-sync-lib": "0.3.2", + "read-package-tree": "~5.1.5", + "rxjs": "~6.6.7", + "semver": "~7.5.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" + }, + "devDependencies": { + "@pnpm/lockfile.types": "~1.0.3", + "@pnpm/logger": "4.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": "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/ssri": "~7.1.0", + "@types/strict-uri-encode": "2.0.0", + "@types/tar": "6.1.6", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.98.0" + }, + "publishOnlyDependencies": { + "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", + "@rushstack/rush-azure-storage-build-cache-plugin": "workspace:*", + "@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" + ] +} diff --git a/libraries/rush-lib/scripts/copyEmptyModules.js b/libraries/rush-lib/scripts/copyEmptyModules.js new file mode 100644 index 00000000000..9d0c50f9439 --- /dev/null +++ b/libraries/rush-lib/scripts/copyEmptyModules.js @@ -0,0 +1,90 @@ +'use strict'; + +const { FileSystem, Async, AsyncQueue } = require('@rushstack/node-core-library'); + +const JS_FILE_EXTENSION = '.js'; +const DTS_FILE_EXTENSION = '.d.ts'; + +module.exports = { + runAsync: async ({ + heftTaskSession: { + logger: { terminal } + }, + heftConfiguration: { buildFolderPath } + }) => { + // We're using a Webpack plugin called `@rushstack/webpack-deep-imports-plugin` to + // examine all of the modules that are imported by the entrypoints (index, and the start* scripts) + // to `rush-lib` and generate stub JS files in the `lib` folder that reference the original modules + // in the webpack bundle. The plugin also copies the `.d.ts` files for those modules to the `lib` folder. + // + // A limitation of this approach is that only modules that contain runtime code end up in the Webpack + // bundle, so only modules that contain runtime code get stubs and have their `.d.ts` files copied. This + // 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 + // 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 + // `rush-lib-declaration-paths-test` project in the `build-tests` + + function stripCommentsFromJsFile(jsFileText) { + const lines = jsFileText.split('\n'); + const resultLines = []; + for (const line of lines) { + const trimmedLine = line.trim(); + if (trimmedLine === '' || trimmedLine.startsWith('//')) { + continue; + } + + resultLines.push(trimmedLine); + } + + return resultLines.join('\n'); + } + + const jsInFolderPath = `${buildFolderPath}/lib-esnext`; + const dtsInFolderPath = `${buildFolderPath}/lib-commonjs`; + const outFolderPath = `${buildFolderPath}/lib`; + const emptyModuleBuffer = Buffer.from('module.exports = {};', 'utf8'); + const folderPathQueue = new AsyncQueue([undefined]); + + await Async.forEachAsync( + folderPathQueue, + async ([relativeFolderPath, callback]) => { + const folderPath = relativeFolderPath ? `${jsInFolderPath}/${relativeFolderPath}` : jsInFolderPath; + const folderItems = await FileSystem.readFolderItemsAsync(folderPath); + for (const folderItem of folderItems) { + const itemName = folderItem.name; + const relativeItemPath = relativeFolderPath ? `${relativeFolderPath}/${itemName}` : itemName; + + if (folderItem.isDirectory()) { + folderPathQueue.push(relativeItemPath); + } else if (folderItem.isFile() && itemName.endsWith(JS_FILE_EXTENSION)) { + const jsInPath = `${jsInFolderPath}/${relativeItemPath}`; + const jsFileText = await FileSystem.readFileAsync(jsInPath); + const strippedJsFileText = stripCommentsFromJsFile(jsFileText); + if (strippedJsFileText === 'export {};') { + const outJsPath = `${outFolderPath}/${relativeItemPath}`; + terminal.writeVerboseLine(`Writing stub to ${outJsPath}`); + await FileSystem.writeFileAsync(outJsPath, emptyModuleBuffer, { + ensureFolderExists: true + }); + + const relativeDtsPath = + relativeItemPath.slice(0, -JS_FILE_EXTENSION.length) + DTS_FILE_EXTENSION; + const inDtsPath = `${dtsInFolderPath}/${relativeDtsPath}`; + const outDtsPath = `${outFolderPath}/${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); + await FileSystem.writeFileAsync(outDtsPath, buffer, { ensureFolderExists: true }); + } + } + } + callback(); + }, + { concurrency: 10 } + ); + } +}; diff --git a/libraries/rush-lib/scripts/plugins-prepublish.js b/libraries/rush-lib/scripts/plugins-prepublish.js new file mode 100644 index 00000000000..47501d16e68 --- /dev/null +++ b/libraries/rush-lib/scripts/plugins-prepublish.js @@ -0,0 +1,12 @@ +const path = require('path'); +const { JsonFile } = require('@rushstack/node-core-library'); + +const packageJsonPath = path.join(__dirname, '../package.json'); + +const packageJson = JsonFile.load(packageJsonPath); +delete packageJson['publishOnlyDependencies']; +packageJson.dependencies['@rushstack/rush-amazon-s3-build-cache-plugin'] = packageJson.version; +packageJson.dependencies['@rushstack/rush-azure-storage-build-cache-plugin'] = packageJson.version; +packageJson.dependencies['@rushstack/rush-http-build-cache-plugin'] = packageJson.version; + +JsonFile.save(packageJson, packageJsonPath, { updateExistingFile: true }); diff --git a/apps/rush-lib/src/api/ApprovedPackagesConfiguration.ts b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts similarity index 78% rename from apps/rush-lib/src/api/ApprovedPackagesConfiguration.ts rename to libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts index c98df729df6..e7b48f2c842 100644 --- a/apps/rush-lib/src/api/ApprovedPackagesConfiguration.ts +++ b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.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 * as os from 'os'; +import * as path from 'node:path'; + import { JsonFile, JsonSchema, FileSystem, NewlineKind, InternalError } from '@rushstack/node-core-library'; -import { Utilities } from '../utilities/Utilities'; import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; +import schemaJson from '../schemas/approved-packages.schema.json'; +import { RushConstants } from '../logic/RushConstants'; /** * Part of IApprovedPackagesJson. @@ -40,6 +41,13 @@ export class ApprovedPackagesItem { * The project categories that are allowed to use this package. */ public allowedCategories: Set = new Set(); + + /** + * @internal + */ + public constructor(packageName: string) { + this.packageName = packageName; + } } /** @@ -47,14 +55,13 @@ export class ApprovedPackagesItem { * @public */ export class ApprovedPackagesConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '../schemas/approved-packages.schema.json')); + private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); public items: ApprovedPackagesItem[] = []; private _itemsByName: Map = new Map(); - private _loadedJson: IApprovedPackagesJson; + private _loadedJson!: IApprovedPackagesJson; private _jsonFilename: string; public constructor(jsonFilename: string) { @@ -83,8 +90,7 @@ export class ApprovedPackagesConfiguration { let item: ApprovedPackagesItem | undefined = this._itemsByName.get(packageName); if (!item) { - item = new ApprovedPackagesItem(); - item.packageName = packageName; + item = new ApprovedPackagesItem(packageName); this._addItem(item); changed = true; } @@ -108,8 +114,11 @@ export class ApprovedPackagesConfiguration { this.loadFromFile(); if (!approvedPackagesPolicyEnabled) { - console.log(`Warning: Ignoring "${path.basename(this._jsonFilename)}" because the` - + ` "approvedPackagesPolicy" setting was not specified in rush.json`); + // eslint-disable-next-line no-console + console.log( + `Warning: Ignoring "${path.basename(this._jsonFilename)}" because the` + + ` "approvedPackagesPolicy" setting was not specified in ${RushConstants.rushJsonFilename}` + ); } return false; @@ -119,8 +128,10 @@ export class ApprovedPackagesConfiguration { * Loads the configuration data from the filename that was passed to the constructor. */ public loadFromFile(): void { - const approvedPackagesJson: IApprovedPackagesJson = JsonFile.loadAndValidate(this._jsonFilename, - ApprovedPackagesConfiguration._jsonSchema); + const approvedPackagesJson: IApprovedPackagesJson = JsonFile.loadAndValidate( + this._jsonFilename, + ApprovedPackagesConfiguration._jsonSchema + ); this.clear(); @@ -146,8 +157,8 @@ export class ApprovedPackagesConfiguration { }); for (const item of this.items) { - // Sort the items from the set. Too bad we can't use the new Array.from(). - const allowedCategories: string[] = Utilities.getSetAsArray(item.allowedCategories); + // Sort the items from the set. + const allowedCategories: string[] = Array.from(item.allowedCategories); allowedCategories.sort(); const itemJson: IApprovedPackagesItemJson = { @@ -162,16 +173,12 @@ export class ApprovedPackagesConfiguration { let body: string = JsonFile.stringify(this._loadedJson); // Unindent the allowedCategories array to improve readability - body = body.replace( - /("allowedCategories": +\[)([^\]]+)/g, - (substring: string, ...args: string[]) => { - return args[0] + args[1].replace(/\s+/g, ' '); - } - ); + body = body.replace(/("allowedCategories": +\[)([^\]]+)/g, (substring: string, ...args: string[]) => { + return args[0] + args[1].replace(/\s+/g, ' '); + }); // Add a header - body = '// DO NOT ADD COMMENTS IN THIS FILE.' - + ' They will be lost when the Rush tool resaves it.\n' + body; + body = '// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it.\n' + body; FileSystem.writeFile(this._jsonFilename, body, { convertLineEndings: NewlineKind.CrLf @@ -183,12 +190,13 @@ export class ApprovedPackagesConfiguration { */ private _addItemJson(itemJson: IApprovedPackagesItemJson, jsonFilename: string): void { if (this._itemsByName.has(itemJson.name)) { - throw new Error(`Error loading package review file ${jsonFilename}:` + os.EOL - + ` the name "${itemJson.name}" appears more than once`); + throw new Error( + `Error loading package review file ${jsonFilename}:\n` + + ` the name "${itemJson.name}" appears more than once` + ); } - const item: ApprovedPackagesItem = new ApprovedPackagesItem(); - item.packageName = itemJson.name; + const item: ApprovedPackagesItem = new ApprovedPackagesItem(itemJson.name); if (itemJson.allowedCategories) { for (const allowedCategory of itemJson.allowedCategories) { item.allowedCategories.add(allowedCategory); diff --git a/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts b/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts new file mode 100644 index 00000000000..32038e636e4 --- /dev/null +++ b/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts @@ -0,0 +1,101 @@ +// 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 { ApprovedPackagesConfiguration } from './ApprovedPackagesConfiguration'; +import { RushConstants } from '../logic/RushConstants'; +import type { + RushConfiguration, + IRushConfigurationJson, + IApprovedPackagesPolicyJson +} from './RushConfiguration'; + +/** + * This is a helper object for RushConfiguration. + * It exposes the "approvedPackagesPolicy" feature from rush.json. + * @public + */ +export class ApprovedPackagesPolicy { + /** + * Whether the feature is enabled. The feature is enabled if the "approvedPackagesPolicy" + * field is assigned in rush.json. + */ + public readonly enabled: boolean; + + /** + * A list of NPM package scopes that will be excluded from review (e.g. `@types`) + */ + public readonly ignoredNpmScopes: ReadonlySet; + + /** + * A list of category names that are valid for usage as the RushConfigurationProject.reviewCategory field. + * This array will never be undefined. + */ + public readonly reviewCategories: ReadonlySet; + + /** + * Packages approved for usage in a web browser. This is the stricter of the two types, so by default + * all new packages are added to this file. + * + * @remarks + * + * This is part of an optional approval workflow, whose purpose is to review any new dependencies + * that are introduced (e.g. maybe a legal review is required, or maybe we are trying to minimize bloat). + * When Rush discovers a new dependency has been added to package.json, it will update the file. + * The intent is that the file will be stored in Git and tracked by a branch policy that notifies + * reviewers when a PR attempts to modify the file. + * + * Example filename: `C:\MyRepo\common\config\rush\browser-approved-packages.json` + */ + public readonly browserApprovedPackages: ApprovedPackagesConfiguration; + + /** + * Packages approved for usage everywhere *except* in a web browser. + * + * @remarks + * + * This is part of an optional approval workflow, whose purpose is to review any new dependencies + * that are introduced (e.g. maybe a legal review is required, or maybe we are trying to minimize bloat). + * The intent is that the file will be stored in Git and tracked by a branch policy that notifies + * reviewers when a PR attempts to modify the file. + * + * Example filename: `C:\MyRepo\common\config\rush\browser-approved-packages.json` + */ + public readonly nonbrowserApprovedPackages: ApprovedPackagesConfiguration; + + /** @internal */ + public constructor(rushConfiguration: RushConfiguration, rushConfigurationJson: IRushConfigurationJson) { + const approvedPackagesPolicy: IApprovedPackagesPolicyJson = + rushConfigurationJson.approvedPackagesPolicy || {}; + + this.enabled = !!rushConfigurationJson.approvedPackagesPolicy; + this.ignoredNpmScopes = new Set(approvedPackagesPolicy.ignoredNpmScopes); + this.reviewCategories = new Set(approvedPackagesPolicy.reviewCategories); + + if (this.enabled) { + if (!this.reviewCategories.size) { + throw new Error( + `The "approvedPackagesPolicy" feature is enabled ${RushConstants.rushJsonFilename}, but the reviewCategories` + + ` list is not configured.` + ); + } + } + + // Load browser-approved-packages.json + const browserApprovedPackagesPath: string = path.join( + rushConfiguration.commonRushConfigFolder, + RushConstants.browserApprovedPackagesFilename + ); + this.browserApprovedPackages = new ApprovedPackagesConfiguration(browserApprovedPackagesPath); + this.browserApprovedPackages.tryLoadFromFile(this.enabled); + + // Load nonbrowser-approved-packages.json + const nonbrowserApprovedPackagesPath: string = path.join( + rushConfiguration.commonRushConfigFolder, + RushConstants.nonbrowserApprovedPackagesFilename + ); + this.nonbrowserApprovedPackages = new ApprovedPackagesConfiguration(nonbrowserApprovedPackagesPath); + this.nonbrowserApprovedPackages.tryLoadFromFile(this.enabled); + } +} diff --git a/libraries/rush-lib/src/api/BuildCacheConfiguration.ts b/libraries/rush-lib/src/api/BuildCacheConfiguration.ts new file mode 100644 index 00000000000..d1480c164a2 --- /dev/null +++ b/libraries/rush-lib/src/api/BuildCacheConfiguration.ts @@ -0,0 +1,294 @@ +// 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 { + JsonFile, + JsonSchema, + FileSystem, + type JsonObject, + AlreadyReportedError +} from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from './RushConfiguration'; +import { FileSystemBuildCacheProvider } from '../logic/buildCache/FileSystemBuildCacheProvider'; +import { RushConstants } from '../logic/RushConstants'; +import type { ICloudBuildCacheProvider } from '../logic/buildCache/ICloudBuildCacheProvider'; +import { RushUserConfiguration } from './RushUserConfiguration'; +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'; + +/** + * Describes the file structure for the "common/config/rush/build-cache.json" config file. + */ +export interface IBaseBuildCacheJson { + buildCacheEnabled: boolean; + cacheProvider: string; + /** + * Used to specify the cache entry ID format. If this property is set, it must + * contain a `[hash]` token. It may also contain one of the following tokens: + * - `[projectName]` + * - `[projectName:normalize]` + * - `[phaseName]` + * - `[phaseName:normalize]` + * - `[phaseName:trimPrefix]` + * - `[os]` + * - `[arch]` + * @privateRemarks + * NOTE: If you update this comment, make sure to update build-cache.json in the "rush init" template. + * The token parser is in CacheEntryId.ts + */ + cacheEntryNamePattern?: string; + /** + * An 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?: string; +} + +/** + * @public + */ +export interface ILocalBuildCacheJson extends IBaseBuildCacheJson { + readonly cacheProvider: 'local-only'; +} + +/** + * @beta + */ +export interface ICloudBuildCacheJson extends IBaseBuildCacheJson { + readonly cacheProvider: string; + [otherConfigKey: string]: JsonObject; +} + +/** + * @beta + */ +export type IBuildCacheJson = ICloudBuildCacheJson | ILocalBuildCacheJson; + +interface IBuildCacheConfigurationOptions { + buildCacheJson: IBuildCacheJson; + getCacheEntryId: GetCacheEntryIdFunction; + rushConfiguration: RushConfiguration; + rushUserConfiguration: RushUserConfiguration; + rushSession: RushSession; + 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 { + /** + * Indicates whether the build cache feature is enabled. + * Typically it is enabled in the build-cache.json config file. + */ + public readonly buildCacheEnabled: boolean; + /** + * Indicates whether or not writing to the cache is enabled. + */ + public cacheWriteEnabled: boolean; + /** + * Method to calculate the cache entry id for a project, phase, and project state. + */ + public readonly getCacheEntryId: GetCacheEntryIdFunction; + /** + * The provider for interacting with the local build cache. + */ + public readonly localCacheProvider: FileSystemBuildCacheProvider; + /** + * The provider for interacting with the cloud build cache, if configured. + */ + public readonly cloudCacheProvider: ICloudBuildCacheProvider | undefined; + /** + * An 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. + */ + public readonly cacheHashSalt: string | undefined; + + private constructor({ + getCacheEntryId, + buildCacheJson, + rushUserConfiguration, + rushConfiguration, + cloudCacheProvider + }: IBuildCacheConfigurationOptions) { + this.buildCacheEnabled = EnvironmentConfiguration.buildCacheEnabled ?? buildCacheJson.buildCacheEnabled; + this.cacheWriteEnabled = + !!this.buildCacheEnabled && EnvironmentConfiguration.buildCacheWriteAllowed !== false; + + this.getCacheEntryId = getCacheEntryId; + this.localCacheProvider = new FileSystemBuildCacheProvider({ + rushUserConfiguration: rushUserConfiguration, + rushConfiguration: rushConfiguration + }); + this.cloudCacheProvider = cloudCacheProvider; + this.cacheHashSalt = buildCacheJson.cacheHashSalt; + } + + /** + * Attempts to load the build-cache.json data from the standard file path `common/config/rush/build-cache.json`. + * If the file has not been created yet, then undefined is returned. + */ + public static async tryLoadAsync( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession + ): Promise { + const { buildCacheConfiguration } = await BuildCacheConfiguration._tryLoadInternalAsync( + terminal, + rushConfiguration, + rushSession + ); + return buildCacheConfiguration; + } + + /** + * Loads the build-cache.json data from the standard file path `common/config/rush/build-cache.json`. + * If the file has not been created yet, or if the feature is not enabled, then an error is reported. + */ + public static async loadAndRequireEnabledAsync( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession + ): Promise { + const { buildCacheConfiguration, jsonFilePath } = await BuildCacheConfiguration._tryLoadInternalAsync( + terminal, + rushConfiguration, + rushSession + ); + + if (!buildCacheConfiguration) { + terminal.writeErrorLine( + `The build cache feature is not enabled. This config file is missing:\n` + jsonFilePath + ); + terminal.writeLine(`\nThe Rush website documentation has instructions for enabling the build cache.`); + throw new AlreadyReportedError(); + } + + if (!buildCacheConfiguration.buildCacheEnabled) { + terminal.writeErrorLine( + `The build cache feature is not enabled. You can enable it by editing this config file:\n` + + jsonFilePath + ); + throw new AlreadyReportedError(); + } + + return buildCacheConfiguration; + } + + /** + * Gets the absolute path to the build-cache.json file in the specified rush workspace. + */ + public static getBuildCacheConfigFilePath(rushConfiguration: RushConfiguration): string { + return `${rushConfiguration.commonRushConfigFolder}/${RushConstants.buildCacheFilename}`; + } + + private static async _tryLoadInternalAsync( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession + ): Promise<{ buildCacheConfiguration: BuildCacheConfiguration | undefined; jsonFilePath: string }> { + const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration); + const buildCacheConfiguration: BuildCacheConfiguration | undefined = + await BuildCacheConfiguration._tryLoadAsync(jsonFilePath, terminal, rushConfiguration, rushSession); + return { buildCacheConfiguration, jsonFilePath }; + } + + private static async _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 + ); + } else { + try { + buildCacheJson = await JsonFile.loadAndValidateAsync(jsonFilePath, BUILD_CACHE_JSON_SCHEMA); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } else { + return undefined; + } + } + } + } + + 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 new BuildCacheConfiguration({ + buildCacheJson, + getCacheEntryId, + rushConfiguration, + rushUserConfiguration, + rushSession, + cloudCacheProvider + }); + } +} diff --git a/apps/rush-lib/src/api/ChangeFile.ts b/libraries/rush-lib/src/api/ChangeFile.ts similarity index 81% rename from apps/rush-lib/src/api/ChangeFile.ts rename to libraries/rush-lib/src/api/ChangeFile.ts index eb73961481c..d2022c7e90d 100644 --- a/apps/rush-lib/src/api/ChangeFile.ts +++ b/libraries/rush-lib/src/api/ChangeFile.ts @@ -1,17 +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 gitInfo = require('git-repo-info'); +import type gitInfo from 'git-repo-info'; import { JsonFile } from '@rushstack/node-core-library'; -import { RushConfiguration } from './RushConfiguration'; -import { - IChangeFile, - IChangeInfo -} from './ChangeManagement'; +import type { RushConfiguration } from './RushConfiguration'; +import type { IChangeFile, IChangeInfo } from './ChangeManagement'; import { Git } from '../logic/Git'; /** @@ -24,10 +21,7 @@ export class ChangeFile { /** * @internal */ - public constructor( - changeFileData: IChangeFile, - rushConfiguration: RushConfiguration - ) { + public constructor(changeFileData: IChangeFile, rushConfiguration: RushConfiguration) { if (!changeFileData) { throw new Error(`changeFileData does not have a value`); } @@ -82,26 +76,30 @@ export class ChangeFile { */ public generatePath(): string { let branch: string | undefined = undefined; - const repoInfo: gitInfo.GitRepoInfo | undefined = Git.getGitInfo(); + const git: Git = new Git(this._rushConfiguration); + const repoInfo: gitInfo.GitRepoInfo | undefined = git.getGitInfo(); branch = repoInfo && repoInfo.branch; if (!branch) { + // eslint-disable-next-line no-console console.log('Could not automatically detect git branch name, using timestamp instead.'); } // example filename: yourbranchname_2017-05-01-20-20.json - const filename: string = (branch ? - this._escapeFilename(`${branch}_${this._getTimestamp()}.json`) : - `${this._getTimestamp()}.json`); - const filePath: string = path.join(this._rushConfiguration.changesFolder, + const filename: string = branch + ? this._escapeFilename(`${branch}_${this._getTimestamp()}.json`) + : `${this._getTimestamp()}.json`; + const filePath: string = path.join( + this._rushConfiguration.changesFolder, ...this._changeFileData.packageName.split('/'), - filename); + filename + ); return filePath; } /** - * Gets the current time, formatted as YYYY-MM-DD-HH-MM - * Optionally will include seconds - */ + * Gets the current time, formatted as YYYY-MM-DD-HH-MM + * Optionally will include seconds + */ private _getTimestamp(useSeconds: boolean = false): string | undefined { // Create a date string with the current time @@ -139,4 +137,4 @@ export class ChangeFile { const badCharacters: RegExp = /[^a-zA-Z0-9._-]/g; return filename.replace(badCharacters, replacer); } -} \ No newline at end of file +} diff --git a/apps/rush-lib/src/api/ChangeManagement.ts b/libraries/rush-lib/src/api/ChangeManagement.ts similarity index 79% rename from apps/rush-lib/src/api/ChangeManagement.ts rename to libraries/rush-lib/src/api/ChangeManagement.ts index 980cd8b2a89..8042dc2da0b 100644 --- a/apps/rush-lib/src/api/ChangeManagement.ts +++ b/libraries/rush-lib/src/api/ChangeManagement.ts @@ -22,6 +22,23 @@ export enum ChangeType { major = 5 } +export interface IVersionPolicyChangeInfo { + /** + * Defines the type of change. + */ + changeType: ChangeType; + + /** + * The new version for the version policy, as calculated by the findChangeRequests function. + */ + newVersion: string; + + /** + * The name of the version policy. + */ + versionPolicyName: string; +} + /** * Defines an IChangeInfo object. */ @@ -43,6 +60,11 @@ export interface IChangeInfo { */ comment?: string; + /** + * An optional dictionary of custom string fields. + */ + customFields?: Record; + /** * The email of the user who provided the comment. Pulled from the Git log. */ @@ -77,4 +99,4 @@ export interface IChangeInfo { * The type of the package publishing request (patch/minor/major), as provided by the JSON file. */ type?: string; -} \ No newline at end of file +} diff --git a/libraries/rush-lib/src/api/ChangeManager.ts b/libraries/rush-lib/src/api/ChangeManager.ts new file mode 100644 index 00000000000..e3e779fd5e1 --- /dev/null +++ b/libraries/rush-lib/src/api/ChangeManager.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 { RushConfiguration } from './RushConfiguration'; +import type { RushConfigurationProject } from './RushConfigurationProject'; +import { ChangeFile } from './ChangeFile'; +import type { IChangeFile } from './ChangeManagement'; + +/** + * A class that helps with programmatically interacting with Rush's change files. + * @public + */ +export class ChangeManager { + /** + * Creates a change file that has a 'none' type. + * @param rushConfiguration - The rush configuration we are working with + * @param projectName - The name of the project for which to create a change file + * @param emailAddress - The email address which should be associated with this change + * @returns the path to the file that was created, or undefined if no file was written + */ + public static createEmptyChangeFiles( + rushConfiguration: RushConfiguration, + projectName: string, + emailAddress: string + ): string | undefined { + const projectInfo: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); + if (projectInfo && projectInfo.shouldPublish) { + const changefile: IChangeFile = { + changes: [ + { + comment: '', + packageName: projectName, + type: 'none' + } + ], + packageName: projectName, + email: emailAddress + }; + + return new ChangeFile(changefile, rushConfiguration).writeSync(); + } + return undefined; + } +} diff --git a/libraries/rush-lib/src/api/Changelog.ts b/libraries/rush-lib/src/api/Changelog.ts new file mode 100644 index 00000000000..51314789572 --- /dev/null +++ b/libraries/rush-lib/src/api/Changelog.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Interface representing a changelog json object for a package used to represent the parsed + * content of CHANGELOG.json + */ +export interface IChangelog { + /** + * Name of the project + */ + name: string; + + /** + * Entries within the changelog corresponding to each published version. + */ + entries: IChangeLogEntry[]; +} + +/** + * Interface representing a single published entry in the changelog. + */ +export interface IChangeLogEntryComments { + /** Describes changes which cause a patch-level SemVer bump */ + patch?: IChangeLogComment[]; + /** Describes changes which cause a minor-level SemVer bump */ + minor?: IChangeLogComment[]; + /** Describes changes which cause a major-level SemVer bump */ + major?: IChangeLogComment[]; + /** Describes changes to the package's dependencies */ + dependency?: IChangeLogComment[]; + /** Describe changes that do not have version information */ + none?: IChangeLogComment[]; + /** Describe changes that do not have version information */ + hotfix?: IChangeLogComment[]; +} + +/** + * Interface representing a single published entry in the changelog. + */ +export interface IChangeLogEntry { + /** + * Published version for the entry. (Example: 1.0.0) + */ + version: string; + + /** + * Git tag used to identify the published commit. (Example: b7f55611e54910327a206476b185265498c66acf) + */ + tag: string; + + /** + * The UTC date when the publish was applied. (Example: Fri, 02 Dec 2016 22:27:16 GMT) + */ + date: string | undefined; + + /** + * Comments for the entry, where key represents the ChangeType string (Example: major) + */ + comments: IChangeLogEntryComments; +} + +/** + * Interface representing a single changelog comment within an entry. + */ +export interface IChangeLogComment { + /** + * The given comment. (supports markdown.) + */ + comment: string; + + /** + * The author, if applicable, that created the change request. + */ + author?: string; + + /** + * The commit, if applicable, including the change request. + */ + commit?: string; + + /** + * An optional dictionary of custom string fields. + */ + customFields?: Record; +} diff --git a/libraries/rush-lib/src/api/CobuildConfiguration.ts b/libraries/rush-lib/src/api/CobuildConfiguration.ts new file mode 100644 index 00000000000..d96cfc96dc2 --- /dev/null +++ b/libraries/rush-lib/src/api/CobuildConfiguration.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 { randomUUID } from 'node:crypto'; + +import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { EnvironmentConfiguration } from './EnvironmentConfiguration'; +import type { CobuildLockProviderFactory, RushSession } from '../pluginFramework/RushSession'; +import { RushConstants } from '../logic/RushConstants'; +import type { ICobuildLockProvider } from '../logic/cobuild/ICobuildLockProvider'; +import type { RushConfiguration } from './RushConfiguration'; +import schemaJson from '../schemas/cobuild.schema.json'; + +/** + * @beta + */ +export interface ICobuildJson { + cobuildFeatureEnabled: boolean; + cobuildLockProvider: string; +} + +/** + * @beta + */ +export interface ICobuildConfigurationOptions { + cobuildJson: ICobuildJson; + rushConfiguration: RushConfiguration; + rushSession: RushSession; + cobuildLockProviderFactory: CobuildLockProviderFactory; +} + +/** + * 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. + * + * Note: The orchestrator (or local users) should always have to opt into running with cobuilds by + * providing a cobuild context id. Even if cobuilds are "enabled" as a feature, they don't + * actually turn on for that particular build unless the cobuild context id is provided as an + * non-empty string. + */ + public readonly cobuildFeatureEnabled: boolean; + + /** + * Cobuild context id + * + * @remarks + * The cobuild feature won't be enabled until the context id is provided as an non-empty string. + */ + public readonly cobuildContextId: string | undefined; + + /** + * This is a name of the participating cobuild runner. It can be specified by the environment variable + * RUSH_COBUILD_RUNNER_ID. If it is not provided, a random id will be generated to identify the runner. + */ + public readonly cobuildRunnerId: string; + /** + * If true, Rush will automatically handle the leaf project with build cache "disabled" by writing + * to the cache in a special "log files only mode". This is useful when you want to use Cobuilds + * to improve the performance in CI validations and the leaf projects have not enabled cache. + */ + public readonly cobuildLeafProjectLogOnlyAllowed: boolean; + + /** + * If true, operations can opt into leveraging cobuilds without restoring from the build cache. + * Operations will need to us the allowCobuildWithoutCache flag to opt into this behavior per phase. + */ + public readonly cobuildWithoutCacheAllowed: boolean; + + private _cobuildLockProvider: ICobuildLockProvider | undefined; + private readonly _cobuildLockProviderFactory: CobuildLockProviderFactory; + private readonly _cobuildJson: ICobuildJson; + + private constructor(options: ICobuildConfigurationOptions) { + const { cobuildJson, cobuildLockProviderFactory, rushConfiguration } = options; + + this.cobuildContextId = EnvironmentConfiguration.cobuildContextId; + this.cobuildFeatureEnabled = this.cobuildContextId ? cobuildJson.cobuildFeatureEnabled : false; + this.cobuildRunnerId = EnvironmentConfiguration.cobuildRunnerId || randomUUID(); + this.cobuildLeafProjectLogOnlyAllowed = + EnvironmentConfiguration.cobuildLeafProjectLogOnlyAllowed ?? false; + this.cobuildWithoutCacheAllowed = + rushConfiguration.experimentsConfiguration.configuration.allowCobuildWithoutCache ?? false; + + this._cobuildLockProviderFactory = cobuildLockProviderFactory; + this._cobuildJson = cobuildJson; + } + + /** + * Attempts to load the cobuild.json data from the standard file path `common/config/rush/cobuild.json`. + * If the file has not been created yet, then undefined is returned. + */ + public static async tryLoadAsync( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession + ): Promise { + const jsonFilePath: string = CobuildConfiguration.getCobuildConfigFilePath(rushConfiguration); + try { + return await CobuildConfiguration._loadAsync(jsonFilePath, terminal, rushConfiguration, rushSession); + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + throw err; + } + } + } + + public static getCobuildConfigFilePath(rushConfiguration: RushConfiguration): string { + 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})`); + const cobuildLockProvider: ICobuildLockProvider = await this._cobuildLockProviderFactory( + this._cobuildJson + ); + this._cobuildLockProvider = cobuildLockProvider; + await this._cobuildLockProvider.connectAsync(); + } + } + + public async destroyLockProviderAsync(): Promise { + if (this.cobuildFeatureEnabled) { + await this._cobuildLockProvider?.disconnectAsync(); + } + } + + public getCobuildLockProvider(): ICobuildLockProvider { + if (!this._cobuildLockProvider) { + throw new Error(`Cobuild lock provider has not been created`); + } + return this._cobuildLockProvider; + } +} diff --git a/libraries/rush-lib/src/api/CommandLineConfiguration.ts b/libraries/rush-lib/src/api/CommandLineConfiguration.ts new file mode 100644 index 00000000000..5fb463764dc --- /dev/null +++ b/libraries/rush-lib/src/api/CommandLineConfiguration.ts @@ -0,0 +1,747 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; +import type { CommandLineParameter } from '@rushstack/ts-command-line'; + +import { RushConstants } from '../logic/RushConstants'; +import type { + CommandJson, + ICommandLineJson, + IBulkCommandJson, + IGlobalCommandJson, + IFlagParameterJson, + IChoiceParameterJson, + IStringParameterJson, + IIntegerParameterJson, + IStringListParameterJson, + IIntegerListParameterJson, + IChoiceListParameterJson, + IPhasedCommandWithoutPhasesJson +} from './CommandLineJson'; +import schemaJson from '../schemas/command-line.schema.json'; + +export interface IShellCommandTokenContext { + packageFolder: string; +} + +/** + * The set of valid behaviors for a missing script in a project's package.json scripts for a given phase. + * @alpha + */ +export type PhaseBehaviorForMissingScript = 'silent' | 'log' | 'error'; + +/** + * Metadata about a phase. + * @alpha + */ +export interface IPhase { + /** + * The name of this phase. + */ + name: string; + + /** + * If set to `true,` this this phase was generated from a bulk command, and + * was not explicitly defined in the command-line.json file. + */ + isSynthetic: boolean; + + /** + * This property is used in the name of the filename for the logs generated by this + * phase. This is a filesystem-safe version of the phase name. For example, + * a phase with name `_phase:compile` has a `logFilenameIdentifier` of `_phase_compile`. + */ + logFilenameIdentifier: string; + + /** + * The set of custom command line parameters that are relevant to this phase. + */ + associatedParameters: Set; + + /** + * The resolved dependencies of the phase + */ + dependencies: { + self: Set; + upstream: Set; + }; + + /** + * By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is + * set to `true`, Rush will return a zero exit code if warnings occur during the execution of this phase. + */ + allowWarningsOnSuccess: boolean; + + /** + * What should happen if the script is not defined in a project's package.json scripts field. Default is "error". + */ + missingScriptBehavior: PhaseBehaviorForMissingScript; + + /** + * (Optional) If the `shellCommand` field is set for a bulk command, Rush will invoke it for each + * selected project; otherwise, Rush will invoke the package.json `"scripts"` entry matching Rush command/phase name. + * + * This string is the path to a script that will be invoked using the OS shell. The working directory will be + * the folder that contains rush.json. If custom parameters are associated with this command, their + * values will be appended to the end of this string. + */ + shellCommand?: string; +} + +export interface ICommandWithParameters { + associatedParameters: Set; +} + +export interface IPhasedCommandConfig extends IPhasedCommandWithoutPhasesJson, ICommandWithParameters { + /** + * If set to `true`, then this phased command was generated from a bulk command, and + * was not explicitly defined in the command-line.json file. + */ + isSynthetic: boolean; + disableBuildCache?: boolean; + + originalPhases: Set; + /** + * Include upstream and self phases. + */ + phases: Set; + + /** + * If set to `true`, this phased command will always run in watch mode, regardless of CLI flags. + */ + alwaysWatch: boolean; + /** + * The set of phases to execute when running this phased command in watch mode. + */ + watchPhases: Set; + /** + * How many milliseconds to wait after receiving a file system notification before executing in watch mode. + */ + watchDebounceMs?: number; + /** + * 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. + * If undefined, then Rush does not define a built-in "--install" CLI flag for this command and no installation is performed. + */ + alwaysInstall: boolean | undefined; +} + +export interface IGlobalCommandConfig extends IGlobalCommandJson, ICommandWithParameters {} + +export type Command = IGlobalCommandConfig | IPhasedCommandConfig; + +/** + * Metadata about a custom parameter defined in command-line.json + * @alpha + */ +export type IParameterJson = + | IFlagParameterJson + | IChoiceParameterJson + | IStringParameterJson + | IIntegerParameterJson + | IStringListParameterJson + | IIntegerListParameterJson + | IChoiceListParameterJson; + +const DEFAULT_BUILD_COMMAND_JSON: IBulkCommandJson = { + commandKind: RushConstants.bulkCommandKind, + name: RushConstants.buildCommandName, + summary: "Build all projects that haven't been built, or have changed since they were last built.", + description: + 'This command is similar to "rush rebuild", except that "rush build" performs' + + ' an incremental build. In other words, it only builds projects whose source files have changed' + + ' since the last successful build. The analysis requires a Git working tree, and only considers' + + ' source files that are tracked by Git and whose path is under the project folder. (For more details' + + ' about this algorithm, see the documentation for the "package-deps-hash" NPM package.) The incremental' + + ' build state is tracked in a per-project folder called ".rush/temp" which should NOT be added to Git. The' + + ' build command is tracked by the "arguments" field in the "package-deps_build.json" file contained' + + ' therein; a full rebuild is forced whenever the command has changed (e.g. "--production" or not).', + safeForSimultaneousRushProcesses: false, + enableParallelism: true, + incremental: true +}; + +const DEFAULT_REBUILD_COMMAND_JSON: IBulkCommandJson = { + commandKind: RushConstants.bulkCommandKind, + name: RushConstants.rebuildCommandName, + summary: 'Clean and rebuild the entire set of projects.', + description: + 'This command assumes that the package.json file for each project contains' + + ' a "scripts" entry for "npm run build" that performs a full clean build.' + + ` Rush invokes this script to build each project that is registered in ${RushConstants.rushJsonFilename}.` + + ' Projects are built in parallel where possible, but always respecting the dependency' + + ' graph for locally linked projects. The number of simultaneous processes will be' + + ' based on the number of machine cores unless overridden by the --parallelism flag.' + + ' (For an incremental build, see "rush build" instead of "rush rebuild".)', + safeForSimultaneousRushProcesses: false, + enableParallelism: true, + incremental: false +}; + +interface ICommandLineConfigurationOptions { + /** + * If true, do not include default build and rebuild commands. + */ + doNotIncludeDefaultBuildCommands?: boolean; +} + +/** + * This function replaces colons (":") with underscores ("_"). + * + * ts-command-line restricts command names to lowercase letters, numbers, underscores, and colons. + * Replacing colons with underscores produces a filesystem-safe name. + */ +function _normalizeNameForLogFilenameIdentifiers(name: string): string { + return name.replace(/:/g, '_'); // Replace colons with underscores to be filesystem-safe +} + +/** + * 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[] = []; + + /** + * shellCommand from plugin custom command line configuration needs to be expanded with tokens + */ + public shellCommandTokenContext: IShellCommandTokenContext | undefined; + + /** + * These path will be prepended to the PATH environment variable + */ + public readonly additionalPathFolders: Readonly = []; + + /** + * A map of bulk command names to their corresponding synthetic phase identifiers + */ + private readonly _syntheticPhasesByTranslatedBulkCommandName: Map = new Map(); + + /** + * Use CommandLineConfiguration.loadFromFile() + * + * @internal + */ + public constructor( + commandLineJson: ICommandLineJson | undefined, + options: ICommandLineConfigurationOptions = {} + ) { + const phasesJson: ICommandLineJson['phases'] = commandLineJson?.phases; + if (phasesJson) { + const phaseNameRegexp: RegExp = new RegExp( + `^${RushConstants.phaseNamePrefix}[a-z][a-z0-9]*([-][a-z0-9]+)*$` + ); + for (const phase of phasesJson) { + if (this.phases.has(phase.name)) { + throw new Error( + `In ${RushConstants.commandLineFilename}, the phase "${phase.name}" is specified ` + + 'more than once.' + ); + } + + if (!phase.name.match(phaseNameRegexp)) { + throw new Error( + `In ${RushConstants.commandLineFilename}, the phase "${phase.name}"'s name ` + + 'is not a valid phase name. Phase names must begin with the ' + + `required prefix "${RushConstants.phaseNamePrefix}" followed by a name containing ` + + 'lowercase letters, numbers, or hyphens. The name must start with a letter and ' + + 'must not end with a hyphen.' + ); + } + + if (phase.ignoreMissingScript !== undefined && phase.missingScriptBehavior !== undefined) { + throw new Error( + `In ${RushConstants.commandLineFilename}, the phase "${phase.name}"'s defines ` + + 'both "ignoreMissingScript" and "missingScriptBehavior". If using the "missingScriptBehavior", ' + + `remove "ignoreMissingScript", since it subsumes the functionality.` + ); + } + + // This is a completely fresh object. Avoid use of the `...` operator in its construction + // to guarantee monomorphism. + const processedPhase: IPhase = { + name: phase.name, + isSynthetic: false, + logFilenameIdentifier: _normalizeNameForLogFilenameIdentifiers(phase.name), + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + missingScriptBehavior: phase.missingScriptBehavior ?? (phase.ignoreMissingScript ? 'log' : 'error'), + allowWarningsOnSuccess: !!phase.allowWarningsOnSuccess + }; + + this.phases.set(phase.name, processedPhase); + } + + // Resolve phase names to the underlying objects + for (const rawPhase of phasesJson) { + // The named phase not existing was already handled in the loop above + const phase: IPhase = this.phases.get(rawPhase.name)!; + + const selfDependencies: string[] | undefined = rawPhase.dependencies?.self; + const upstreamDependencies: string[] | undefined = rawPhase.dependencies?.upstream; + + if (selfDependencies) { + for (const dependencyName of selfDependencies) { + const dependency: IPhase | undefined = this.phases.get(dependencyName); + if (!dependency) { + throw new Error( + `In ${RushConstants.commandLineFilename}, in the phase "${phase.name}", the self ` + + `dependency phase "${dependencyName}" does not exist.` + ); + } + phase.dependencies.self.add(dependency); + } + } + + if (upstreamDependencies) { + for (const dependencyName of upstreamDependencies) { + const dependency: IPhase | undefined = this.phases.get(dependencyName); + if (!dependency) { + throw new Error( + `In ${RushConstants.commandLineFilename}, in the phase "${phase.name}", ` + + `the upstream dependency phase "${dependencyName}" does not exist.` + ); + } + phase.dependencies.upstream.add(dependency); + } + } + } + + // Do the recursive stuff after the dependencies have been converted + const safePhases: Set = new Set(); + const cycleDetector: Set = new Set(); + for (const phase of this.phases.values()) { + this._checkForPhaseSelfCycles(phase, cycleDetector, safePhases); + } + } + + const commandsJson: ICommandLineJson['commands'] = commandLineJson?.commands; + let buildCommandPhases: IPhasedCommandConfig['phases'] | undefined; + let buildCommandOriginalPhases: IPhasedCommandConfig['phases'] | undefined; + if (commandsJson) { + for (const command of commandsJson) { + if (this.commands.has(command.name)) { + throw new Error( + `In ${RushConstants.commandLineFilename}, the command "${command.name}" is specified ` + + 'more than once.' + ); + } + + let normalizedCommand: Command; + switch (command.commandKind) { + case RushConstants.phasedCommandKind: { + const originalPhases: Set = new Set(); + const commandPhases: Set = new Set(); + const watchPhases: Set = new Set(); + + normalizedCommand = { + ...command, + isSynthetic: false, + associatedParameters: new Set(), + originalPhases, + phases: commandPhases, + watchPhases, + alwaysWatch: false, + alwaysInstall: undefined + }; + + for (const phaseName of command.phases) { + const phase: IPhase | undefined = this.phases.get(phaseName); + if (!phase) { + throw new Error( + `In ${RushConstants.commandLineFilename}, in the "phases" property of the ` + + `"${normalizedCommand.name}" command, the phase "${phaseName}" does not exist.` + ); + } + + originalPhases.add(phase); + commandPhases.add(phase); + } + + // Apply implicit phase dependency expansion + // The equivalent of the "--to" operator used for projects + // Appending to the set while iterating it accomplishes a full breadth-first search + for (const phase of commandPhases) { + for (const dependency of phase.dependencies.self) { + commandPhases.add(dependency); + } + + for (const dependency of phase.dependencies.upstream) { + commandPhases.add(dependency); + } + } + + const { watchOptions, installOptions } = command; + + if (watchOptions) { + normalizedCommand.alwaysWatch = watchOptions.alwaysWatch; + normalizedCommand.watchDebounceMs = watchOptions.debounceMs; + + // No implicit phase dependency expansion for watch mode. + for (const phaseName of watchOptions.watchPhases) { + const phase: IPhase | undefined = this.phases.get(phaseName); + if (!phase) { + throw new Error( + `In ${RushConstants.commandLineFilename}, in the "watchPhases" property of the ` + + `"${normalizedCommand.name}" command, the phase "${phaseName}" does not exist.` + ); + } + + watchPhases.add(phase); + } + } + + if (installOptions) { + normalizedCommand.alwaysInstall = installOptions.alwaysInstall; + } + + break; + } + + case RushConstants.globalCommandKind: { + normalizedCommand = { + ...command, + associatedParameters: new Set() + }; + break; + } + + case RushConstants.bulkCommandKind: { + // Translate the bulk command into a phased command + normalizedCommand = this._translateBulkCommandToPhasedCommand(command); + break; + } + } + + if ( + normalizedCommand.name === RushConstants.buildCommandName || + normalizedCommand.name === RushConstants.rebuildCommandName + ) { + if (normalizedCommand.commandKind === RushConstants.globalCommandKind) { + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${normalizedCommand.name}" using ` + + `the command kind "${RushConstants.globalCommandKind}". This command can only be designated as a command ` + + `kind "${RushConstants.bulkCommandKind}" or "${RushConstants.phasedCommandKind}".` + ); + } else if (command.safeForSimultaneousRushProcesses) { + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${normalizedCommand.name}" using ` + + `"safeForSimultaneousRushProcesses=true". This configuration is not supported for "${normalizedCommand.name}".` + ); + } else if (normalizedCommand.name === RushConstants.buildCommandName) { + // Record the build command phases in case we need to construct a synthetic "rebuild" command + buildCommandPhases = normalizedCommand.phases; + buildCommandOriginalPhases = normalizedCommand.originalPhases; + } + } + + this.commands.set(normalizedCommand.name, normalizedCommand); + } + } + + if (!options.doNotIncludeDefaultBuildCommands) { + let buildCommand: Command | undefined = this.commands.get(RushConstants.buildCommandName); + if (!buildCommand) { + // If the build command was not specified in the config file, add the default build command + buildCommand = this._translateBulkCommandToPhasedCommand(DEFAULT_BUILD_COMMAND_JSON); + buildCommand.disableBuildCache = DEFAULT_BUILD_COMMAND_JSON.disableBuildCache; + buildCommandPhases = buildCommand.phases; + buildCommandOriginalPhases = buildCommand.originalPhases; + this.commands.set(buildCommand.name, buildCommand); + } + } + + 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; + if (parametersJson) { + for (const parameter of parametersJson) { + const normalizedParameter: IParameterJson = { + ...parameter, + associatedPhases: parameter.associatedPhases ? [...parameter.associatedPhases] : [], + associatedCommands: parameter.associatedCommands ? [...parameter.associatedCommands] : [] + }; + + this.parameters.push(normalizedParameter); + + // Do some basic validation + switch (normalizedParameter.parameterKind) { + case 'choice': { + const alternativeNames: string[] = normalizedParameter.alternatives.map((x) => x.name); + + if ( + normalizedParameter.defaultValue && + alternativeNames.indexOf(normalizedParameter.defaultValue) < 0 + ) { + throw new Error( + `In ${RushConstants.commandLineFilename}, the parameter "${normalizedParameter.longName}",` + + ` specifies a default value "${normalizedParameter.defaultValue}"` + + ` which is not one of the defined alternatives: "${alternativeNames.toString()}"` + ); + } + + break; + } + } + + let parameterHasAssociatedCommands: boolean = false; + if (normalizedParameter.associatedCommands) { + for (const associatedCommandName of normalizedParameter.associatedCommands) { + const syntheticPhase: IPhase | undefined = + this._syntheticPhasesByTranslatedBulkCommandName.get(associatedCommandName); + if (syntheticPhase) { + // If this parameter was associated with a bulk command, include the association + // with the synthetic phase + normalizedParameter.associatedPhases!.push(syntheticPhase.name); + } + + const associatedCommand: Command | undefined = this.commands.get(associatedCommandName); + if (!associatedCommand) { + throw new Error( + `${RushConstants.commandLineFilename} defines a parameter "${normalizedParameter.longName}" ` + + `that is associated with a command "${associatedCommandName}" that is not defined in ` + + 'this file.' + ); + } else { + associatedCommand.associatedParameters.add(normalizedParameter); + parameterHasAssociatedCommands = true; + } + } + } + + if (normalizedParameter.associatedPhases) { + for (const associatedPhaseName of normalizedParameter.associatedPhases) { + const associatedPhase: IPhase | undefined = this.phases.get(associatedPhaseName); + if (!associatedPhase) { + throw new Error( + `${RushConstants.commandLineFilename} defines a parameter "${normalizedParameter.longName}" ` + + `that is associated with a phase "${associatedPhaseName}" that does not exist.` + ); + } + } + } + + if (!parameterHasAssociatedCommands) { + throw new Error( + `${RushConstants.commandLineFilename} defines a parameter "${normalizedParameter.longName}"` + + ` that lists no associated commands.` + ); + } + + // In the presence of plugins, there is utility to defining parameters that are associated with a phased + // command but no phases. Don't enforce that a parameter is associated with at least one phase. + } + } + } + + /** + * Performs a depth-first search to detect cycles in the directed graph of phase "self" dependencies. + * + * @param phase The phase node currently being checked + * @param phasesInPath The current path from the start node to `phase` + * @param cycleFreePhases Phases that have already been fully walked and confirmed to not be in any cycles + */ + private _checkForPhaseSelfCycles( + phase: IPhase, + phasesInPath: Set, + cycleFreePhases: Set + ): void { + if (cycleFreePhases.has(phase)) { + // phase is known to not be reachable from itself, i.e. not in a cycle. Skip. + return; + } + + for (const dependency of phase.dependencies.self) { + if (phasesInPath.has(dependency)) { + throw new Error( + `In ${RushConstants.commandLineFilename}, there exists a cycle within the ` + + `set of ${dependency.name} dependencies: ${Array.from( + phasesInPath, + (phaseInPath: IPhase) => phaseInPath.name + ).join(', ')}` + ); + } else { + phasesInPath.add(dependency); + this._checkForPhaseSelfCycles(dependency, phasesInPath, cycleFreePhases); + phasesInPath.delete(dependency); + } + } + + // phase is not reachable from itself, mark for skipping + cycleFreePhases.add(phase); + } + + private static _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 + }; + } + } + } + + /** + * Load the command-line.json configuration file from the specified path. Note that this + * does not include the default build settings. This option is intended to be used to load + * command-line.json files from plugins. To load a common/config/rush/command-line.json file, + * use {@see loadFromFileOrDefault} instead. + * + * If the file does not exist, this function returns `undefined` + */ + public static tryLoadFromFile(jsonFilePath: string): CommandLineConfiguration | undefined { + let commandLineJson: ICommandLineJson | undefined; + try { + commandLineJson = JsonFile.loadAndValidate(jsonFilePath, CommandLineConfiguration._jsonSchema); + } catch (e) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + } + + if (commandLineJson) { + this._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; + } + } + + /** + * Loads the configuration from the specified file and applies any omitted default build + * 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, + doNotIncludeDefaultBuildCommands?: boolean + ): CommandLineConfiguration { + let commandLineJson: ICommandLineJson | undefined = undefined; + if (jsonFilePath) { + try { + commandLineJson = JsonFile.load(jsonFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + } + + // 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) { + this._applyBuildCommandDefaults(commandLineJson); + + CommandLineConfiguration._jsonSchema.validateObject(commandLineJson, jsonFilePath); + } + } + + return new CommandLineConfiguration(commandLineJson, { doNotIncludeDefaultBuildCommands }); + } + + public prependAdditionalPathFolder(pathFolder: string): void { + (this.additionalPathFolders as string[]).unshift(pathFolder); + } + + private _translateBulkCommandToPhasedCommand(command: IBulkCommandJson): IPhasedCommandConfig { + const phaseName: string = command.name; + const phase: IPhase = { + name: phaseName, + isSynthetic: true, + logFilenameIdentifier: _normalizeNameForLogFilenameIdentifiers(command.name), + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + missingScriptBehavior: command.ignoreMissingScript ? 'log' : 'error', + allowWarningsOnSuccess: !!command.allowWarningsInSuccessfulBuild, + shellCommand: command.shellCommand + }; + + if (!command.ignoreDependencyOrder) { + phase.dependencies.upstream.add(phase); + } + + this.phases.set(phaseName, phase); + this._syntheticPhasesByTranslatedBulkCommandName.set(command.name, phase); + + const phases: Set = new Set([phase]); + + const translatedCommand: IPhasedCommandConfig = { + ...command, + commandKind: 'phased', + isSynthetic: true, + associatedParameters: new Set(), + phases, + originalPhases: phases, + // Bulk commands used the same phases for watch as for regular execution. Preserve behavior. + watchPhases: command.watchForChanges ? phases : new Set(), + alwaysWatch: !!command.watchForChanges, + alwaysInstall: undefined + }; + + return translatedCommand; + } +} diff --git a/libraries/rush-lib/src/api/CommandLineJson.ts b/libraries/rush-lib/src/api/CommandLineJson.ts new file mode 100644 index 00000000000..e6507e49633 --- /dev/null +++ b/libraries/rush-lib/src/api/CommandLineJson.ts @@ -0,0 +1,281 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * "baseCommand" from command-line.schema.json + */ +export interface IBaseCommandJson { + commandKind: 'bulk' | 'global' | 'phased'; + name: string; + summary: string; + /** + * If omitted, the summary will be used instead. + */ + description?: string; + safeForSimultaneousRushProcesses: boolean; + autoinstallerName?: string; + shellCommand?: string; +} + +/** + * "bulkCommand" from command-line.schema.json + */ +export interface IBulkCommandJson extends IBaseCommandJson { + commandKind: 'bulk'; + enableParallelism: boolean; + allowOversubscription?: boolean; + ignoreDependencyOrder?: boolean; + ignoreMissingScript?: boolean; + incremental?: boolean; + allowWarningsInSuccessfulBuild?: boolean; + watchForChanges?: boolean; + disableBuildCache?: boolean; +} + +/** + * Base interface shared by the "phasedCommand" JSON entries and the post-processed + * "IPhase" interface in the CommandLineConfiguration + */ +export interface IPhasedCommandWithoutPhasesJson extends IBaseCommandJson { + commandKind: 'phased'; + enableParallelism: boolean; + allowOversubscription?: boolean; + incremental?: boolean; +} + +/** + * "phasedCommand" from command-line.schema.json + */ +export interface IPhasedCommandJson extends IPhasedCommandWithoutPhasesJson { + phases: string[]; + watchOptions?: { + alwaysWatch: boolean; + debounceMs?: number; + watchPhases: string[]; + }; + installOptions?: { + alwaysInstall: boolean; + }; +} + +/** + * "globalCommand" from command-line.schema.json + */ +export interface IGlobalCommandJson extends IBaseCommandJson { + commandKind: 'global'; + shellCommand: string; +} + +export type CommandJson = IBulkCommandJson | IGlobalCommandJson | IPhasedCommandJson; + +/** + * The dependencies of a phase. + * @alpha + */ +export interface IPhaseDependencies { + /** + * Dependency phases within the same project. + */ + self?: string[]; + /** + * Dependency phases in upstream projects. + */ + upstream?: string[]; +} + +/** + * A phase, used in the phased command feature. + * @alpha + */ +export interface IPhaseJson { + /** + * The name of the phase. Note that this value must start with the \"_phase:\" prefix. + */ + name: string; + /** + * The dependencies of this phase. + */ + dependencies?: IPhaseDependencies; + /** + * Normally Rush requires that each project's package.json has a \"scripts\" entry matching the phase name. To disable this check, set \"ignoreMissingScript\" to true. + */ + ignoreMissingScript?: boolean; + /** + * What should happen if the script is not defined in a project's package.json scripts field. Default is "error". Supersedes \"ignoreMissingScript\". + */ + missingScriptBehavior?: 'silent' | 'log' | 'error'; + /** + * By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is set to \"true\", Rush will return a zero exit code if warnings occur during the execution of this phase. + */ + allowWarningsOnSuccess?: boolean; +} + +/** + * "baseParameter" from command-line.schema.json + * @public + */ +export interface IBaseParameterJson { + /** + * Indicates the kind of syntax for this command-line parameter: \"flag\" or \"choice\" or \"string\" or \"stringList\" or \"integerList\" or \"choiceList\". + */ + parameterKind: 'flag' | 'choice' | 'string' | 'integer' | 'stringList' | 'integerList' | 'choiceList'; + /** + * The name of the parameter (e.g. \"--verbose\"). This is a required field. + */ + longName: string; + /** + * An optional short form of the parameter (e.g. \"-v\" instead of \"--verbose\"). + */ + shortName?: string; + /** + * A detailed description of the parameter, which appears when requesting help for the command (e.g. \"rush --help my-command\"). + */ + description: string; + /** + * A list of custom commands and/or built-in Rush commands that this parameter may be used with, by name. + */ + associatedCommands?: string[]; + /** + * A list of the names of the phases that this command-line parameter should be provided to. + */ + associatedPhases?: string[]; + /** + * If true, then this parameter must be included on the command line. + */ + required?: boolean; +} + +/** + * A custom command-line parameter whose presence acts as an on/off switch. + * @public + */ +export interface IFlagParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a flag (boolean) parameter. + */ + parameterKind: 'flag'; +} + +/** + * Part of "choiceParameter" from command-line.schema.json + * @public + */ +export interface IChoiceParameterAlternativeJson { + /** + * A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\". + */ + name: string; + /** + * A detailed description for the alternative that will be shown in the command-line help. + */ + description: string; +} + +/** + * A custom command-line parameter whose argument must be chosen from a list of allowable alternatives. + * @public + */ +export interface IChoiceParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a choice parameter. + */ + parameterKind: 'choice'; + /** + * A list of alternative argument values that can be chosen for this parameter. + */ + alternatives: IChoiceParameterAlternativeJson[]; + /** + * If the parameter is omitted from the command line, this value will be inserted by default. + */ + defaultValue?: string; +} + +/** + * A custom command-line parameter whose value is interpreted as a string. + * @public + */ +export interface IStringParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a string parameter. + */ + parameterKind: 'string'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} +/** + * A custom command-line parameter whose value is interpreted as a integer. + * @public + */ +export interface IIntegerParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a string parameter. + */ + parameterKind: 'integer'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} + +/** + * A custom command-line parameter whose presence acts as a list of string + * @public + */ +export interface IStringListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a string list parameter. + */ + parameterKind: 'stringList'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} +/** + * A custom command-line parameter whose presence acts as a list of integer + * @public + */ +export interface IIntegerListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a integer list parameter. + */ + parameterKind: 'integerList'; + /** + * The name of the argument for this parameter. + */ + argumentName: string; +} +/** + * A custom command-line parameter whose presence acts as a list of choice + * @public + */ +export interface IChoiceListParameterJson extends IBaseParameterJson { + /** + * Denotes that this is a choice list parameter. + */ + parameterKind: 'choiceList'; + /** + * A list of alternative argument values that can be chosen for this parameter. + */ + alternatives: IChoiceParameterAlternativeJson[]; +} + +export type ParameterJson = + | IFlagParameterJson + | IChoiceParameterJson + | IStringParameterJson + | IIntegerParameterJson + | IStringListParameterJson + | IIntegerListParameterJson + | IChoiceListParameterJson; + +/** + * Interfaces for the file format described by command-line.schema.json + */ +export interface ICommandLineJson { + commands?: CommandJson[]; + phases?: IPhaseJson[]; + parameters?: ParameterJson[]; +} diff --git a/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts new file mode 100644 index 00000000000..0996bbc5a0f --- /dev/null +++ b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -0,0 +1,317 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import crypto from 'node:crypto'; +import * as path from 'node:path'; + +import { + JsonFile, + JsonSchema, + MapExtensions, + ProtectableMap, + FileSystem, + 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'; +import { RushConstants } from '../logic/RushConstants'; +import schemaJson from '../schemas/common-versions.schema.json'; + +/** + * Part of the ICommonVersionsJson structure. + */ +export declare interface ICommonVersionsJsonVersionMap { + /** + * The key is the name of a dependency. The value is a Semantic Versioning (SemVer) + * range specifier. + */ + [dependencyName: string]: string; +} + +/** + * Part of the ICommonVersionsJson structure. + */ +export declare interface ICommonVersionsJsonVersionsMap { + /** + * The key is the name of a dependency. The value is a list of Semantic Versioning (SemVer) + * range specifiers. + */ + [dependencyName: string]: string[]; +} + +/** + * Describes the file structure for the "common/config/rush/common-versions.json" config file. + */ +interface ICommonVersionsJson { + $schema?: string; + + preferredVersions?: ICommonVersionsJsonVersionMap; + + implicitlyPreferredVersions?: boolean; + + allowedAlternativeVersions?: ICommonVersionsJsonVersionsMap; + + ensureConsistentVersions?: boolean; +} + +/** + * 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. + */ + public readonly filePath: string; + + /** + * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, + * except in cases where different projects specify different version ranges for a given dependency. For older + * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause + * trouble for indirect dependencies with incompatible peerDependencies ranges. + * + * If the value is `undefined`, then the default value is `true`. + */ + public readonly implicitlyPreferredVersions: boolean | undefined; + + /** + * If true, then consistent version specifiers for dependencies will be enforced. + * I.e. "rush check" is run before some commands. + */ + public readonly ensureConsistentVersions: boolean; + + /** + * A table that specifies a "preferred version" for a given NPM package. This feature is typically used + * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. + * + * @remarks + * The "preferredVersions" value can be any SemVer range specifier (e.g. `~1.2.3`). Rush injects these values into + * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager + * will calculate versions. The specific effect depends on your package manager. Generally it will have no + * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be + * achieved using the pnpmfile.js hook. See the Rush documentation for more details. + * + * After modifying this field, it's recommended to run `rush update --full` so that the package manager + * will recalculate all version selections. + */ + public readonly preferredVersions: Map; + + /** + * A table that stores, for a given dependency, a list of SemVer ranges that will be accepted + * by "rush check" in addition to the normal version range. + * + * @remarks + * The "rush check" command can be used to enforce that every project in the repo + * must specify the same SemVer range for a given dependency. However, sometimes + * exceptions are needed. The allowedAlternativeVersions table allows you to list + * other SemVer ranges that will be accepted by "rush check" for a given dependency. + * Note that the normal version range (as inferred by looking at all projects in the repo) + * should NOT be included in this list. + */ + public readonly allowedAlternativeVersions: Map>; + + private constructor( + commonVersionsJson: ICommonVersionsJson | undefined, + filePath: string, + rushConfiguration: RushConfiguration | undefined + ) { + this._preferredVersions = new ProtectableMap({ + onSet: this._onSetPreferredVersions.bind(this) + }); + this.preferredVersions = this._preferredVersions.protectedView; + + if (commonVersionsJson && commonVersionsJson.implicitlyPreferredVersions !== undefined) { + this.implicitlyPreferredVersions = commonVersionsJson.implicitlyPreferredVersions; + } else { + this.implicitlyPreferredVersions = undefined; + } + + this._allowedAlternativeVersions = new ProtectableMap({ + onSet: this._onSetAllowedAlternativeVersions.bind(this) + }); + this.allowedAlternativeVersions = this._allowedAlternativeVersions.protectedView; + + const subspacesFeatureEnabled: boolean | undefined = rushConfiguration?.subspacesFeatureEnabled; + const rushJsonEnsureConsistentVersions: boolean | undefined = + rushConfiguration?._ensureConsistentVersionsJsonValue; + const commonVersionsEnsureConsistentVersions: boolean | undefined = + commonVersionsJson?.ensureConsistentVersions; + if (subspacesFeatureEnabled && rushJsonEnsureConsistentVersions !== undefined) { + throw new Error( + `When using subspaces, the ensureConsistentVersions config is now defined in the ${RushConstants.commonVersionsFilename} file, ` + + `you must remove the old setting "ensureConsistentVersions" from ${RushConstants.rushJsonFilename}` + ); + } else if ( + !subspacesFeatureEnabled && + rushJsonEnsureConsistentVersions !== undefined && + commonVersionsEnsureConsistentVersions !== undefined + ) { + throw new Error( + `When the ensureConsistentVersions config is defined in the ${RushConstants.rushJsonFilename} file, ` + + `it cannot also be defined in the ${RushConstants.commonVersionsFilename} file` + ); + } + + this.ensureConsistentVersions = + commonVersionsEnsureConsistentVersions ?? rushJsonEnsureConsistentVersions ?? false; + this._commonVersionsJsonHasEnsureConsistentVersionsProperty = + commonVersionsEnsureConsistentVersions !== undefined; + + if (commonVersionsJson) { + try { + CommonVersionsConfiguration._deserializeTable( + this.preferredVersions, + commonVersionsJson.preferredVersions + ); + CommonVersionsConfiguration._deserializeTable( + this.allowedAlternativeVersions, + commonVersionsJson.allowedAlternativeVersions + ); + } catch (e) { + throw new Error(`Error loading "${path.basename(filePath)}": ${(e as Error).message}`); + } + } + this.filePath = filePath; + } + + /** + * 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 loadFromFile( + jsonFilePath: string, + rushConfiguration?: RushConfiguration + ): CommonVersionsConfiguration { + let commonVersionsJson: ICommonVersionsJson | undefined = undefined; + + if (FileSystem.exists(jsonFilePath)) { + commonVersionsJson = JsonFile.loadAndValidate(jsonFilePath, CommonVersionsConfiguration._jsonSchema); + } + + 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); + } + } + } + + 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; + } + + /** + * Get a sha1 hash of the preferred versions. + */ + public getPreferredVersionsHash(): string { + // Sort so that the hash is stable + const orderedPreferredVersions: Map = new Map( + this._preferredVersions.protectedView + ); + Sort.sortMapKeys(orderedPreferredVersions); + + // JSON.stringify does not support maps, so we need to convert to an object first + const preferredVersionsObj: { [dependency: string]: string } = + MapExtensions.toObject(orderedPreferredVersions); + return crypto.createHash('sha1').update(JSON.stringify(preferredVersionsObj)).digest('hex'); + } + + /** + * Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile(). + */ + public save(): boolean { + if (this._modified) { + JsonFile.save(this._serialize(), this.filePath, { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + this._modified = false; + return true; + } + + return false; + } + + /** + * Returns preferredVersions. + */ + public getAllPreferredVersions(): Map { + const allPreferredVersions: Map = new Map(); + MapExtensions.mergeFromMap(allPreferredVersions, this.preferredVersions); + return allPreferredVersions; + } + + private _onSetPreferredVersions( + source: ProtectableMap, + key: string, + value: string + ): string { + PackageNameParsers.permissive.validate(key); + + this._modified = true; + + return value; + } + + private _onSetAllowedAlternativeVersions( + source: ProtectableMap, + key: string, + value: string[] + ): string[] { + PackageNameParsers.permissive.validate(key); + + this._modified = true; + + return value; + } + + private _serialize(): ICommonVersionsJson { + let preferredVersions: ICommonVersionsJsonVersionMap | undefined; + if (this._preferredVersions.size) { + preferredVersions = CommonVersionsConfiguration._serializeTable(this.preferredVersions); + } + + let allowedAlternativeVersions: ICommonVersionsJsonVersionsMap | undefined; + if (this._allowedAlternativeVersions.size) { + allowedAlternativeVersions = CommonVersionsConfiguration._serializeTable( + this.allowedAlternativeVersions + ) as ICommonVersionsJsonVersionsMap; + } + + const result: OptionalToUndefined = { + $schema: JsonSchemaUrls.commonVersions, + preferredVersions, + implicitlyPreferredVersions: this.implicitlyPreferredVersions, + allowedAlternativeVersions, + ensureConsistentVersions: this._commonVersionsJsonHasEnsureConsistentVersionsProperty + ? this.ensureConsistentVersions + : undefined + }; + return result; + } +} diff --git a/libraries/rush-lib/src/api/CustomTipsConfiguration.ts b/libraries/rush-lib/src/api/CustomTipsConfiguration.ts new file mode 100644 index 00000000000..c45dd2aa86b --- /dev/null +++ b/libraries/rush-lib/src/api/CustomTipsConfiguration.ts @@ -0,0 +1,382 @@ +// 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, JsonSchema } from '@rushstack/node-core-library'; +import { type ITerminal, PrintUtilities, Colorize } from '@rushstack/terminal'; + +import schemaJson from '../schemas/custom-tips.schema.json'; + +/** + * This interface represents the raw custom-tips.json file which allows repo maintainers + * to configure extra details to be printed alongside certain Rush messages. + * @beta + */ +export interface ICustomTipsJson { + /** + * Specifies the custom tips to be displayed by Rush. + */ + customTips?: ICustomTipItemJson[]; +} + +/** + * An item from the {@link ICustomTipsJson.customTips} list. + * @beta + */ +export interface ICustomTipItemJson { + /** + * (REQUIRED) An identifier indicating a message that may be printed by Rush. + * If that message is printed, then this custom tip will be shown. + * Consult the Rush documentation for the current list of possible identifiers. + */ + tipId: CustomTipId; + + /** + * (REQUIRED) The message text to be displayed for this tip. + */ + message: string; +} + +/** + * An identifier representing a Rush message that can be customized by + * defining a custom tip in `common/config/rush/custom-tips.json`. + * @remarks + * Custom tip ids always start with the `TIP_` prefix. + * + * @privateRemarks + * Events from the Rush process should with "TIP_RUSH_". + * Events from a PNPM subprocess should start with "TIP_PNPM_". + * + * @beta + */ +export enum CustomTipId { + // Events from the Rush process should with "TIP_RUSH_". + TIP_RUSH_INCONSISTENT_VERSIONS = 'TIP_RUSH_INCONSISTENT_VERSIONS', + TIP_RUSH_DISALLOW_INSECURE_SHA1 = 'TIP_RUSH_DISALLOW_INSECURE_SHA1', + + // Events from a PNPM subprocess should start with "TIP_PNPM_". + TIP_PNPM_UNEXPECTED_STORE = 'TIP_PNPM_UNEXPECTED_STORE', + TIP_PNPM_NO_MATCHING_VERSION = 'TIP_PNPM_NO_MATCHING_VERSION', + TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE = 'TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE', + TIP_PNPM_PEER_DEP_ISSUES = 'TIP_PNPM_PEER_DEP_ISSUES', + TIP_PNPM_OUTDATED_LOCKFILE = 'TIP_PNPM_OUTDATED_LOCKFILE', + TIP_PNPM_TARBALL_INTEGRITY = 'TIP_PNPM_TARBALL_INTEGRITY', + TIP_PNPM_MISMATCHED_RELEASE_CHANNEL = 'TIP_PNPM_MISMATCHED_RELEASE_CHANNEL', + TIP_PNPM_INVALID_NODE_VERSION = 'TIP_PNPM_INVALID_NODE_VERSION' +} + +/** + * The severity of a custom tip. + * It determines the printing severity ("Error" = red, "Warning" = yellow, "Info" = normal). + * + * @beta + */ +export enum CustomTipSeverity { + Warning = 'Warning', + Error = 'Error', + Info = 'Info' +} + +/** + * The type of the custom tip. + * + * @remarks + * There might be types like `git` in the future. + * + * @beta + */ +export enum CustomTipType { + rush = 'rush', + pnpm = 'pnpm' +} + +/** + * Metadata for a custom tip. + * + * @remarks + * This differs from the {@link ICustomTipItemJson} interface in that these are not configurable by the user; + * it's the inherent state of a custom tip. For example, the custom tip for `ERR_PNPM_NO_MATCHING_VERSION` + * has a inherent severity of `Error`, and a inherent match function that rush maintainer defines. + * + * @beta + */ +export interface ICustomTipInfo { + tipId: CustomTipId; + /** + * The severity of the custom tip. It will determine the printing severity ("Error" = red, "Warning" = yellow, "Info" = normal). + * + * @remarks + * The severity should be consistent with the original message, unless there are strong reasons not to. + */ + severity: CustomTipSeverity; + + /** + * The type of the custom tip. + */ + type: CustomTipType; + + /** + * The function to determine how to match this tipId. + * + * @remarks + * This function might need to be updated if the depending package is updated. + * For example, if `pnpm` change the error logs for "ERR_PNPM_NO_MATCHING_VERSION", we will need to update the match function accordingly. + */ + isMatch?: (str: string) => boolean; +} + +export const RUSH_CUSTOM_TIPS: Readonly> = { + [CustomTipId.TIP_RUSH_DISALLOW_INSECURE_SHA1]: { + tipId: CustomTipId.TIP_RUSH_DISALLOW_INSECURE_SHA1, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + return str.includes('ERR_PNPM_DISALLOW_INSECURE_SHA1'); + } + }, + [CustomTipId.TIP_RUSH_INCONSISTENT_VERSIONS]: { + tipId: CustomTipId.TIP_RUSH_INCONSISTENT_VERSIONS, + severity: CustomTipSeverity.Error, + type: CustomTipType.rush + } +}; + +export const PNPM_CUSTOM_TIPS: Readonly> = { + [CustomTipId.TIP_PNPM_UNEXPECTED_STORE]: { + tipId: CustomTipId.TIP_PNPM_UNEXPECTED_STORE, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + return str.includes('ERR_PNPM_UNEXPECTED_STORE'); + } + }, + [CustomTipId.TIP_PNPM_NO_MATCHING_VERSION]: { + tipId: CustomTipId.TIP_PNPM_NO_MATCHING_VERSION, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + // Example message: (do notice the difference between this one and the TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE) + + // Error Message: ERR_PNPM_NO_MATCHING_VERSION  No matching version found for @babel/types@^7.22.5 + // The latest release of @babel/types is "7.22.4". + // Other releases are: + // * esm: 7.21.4-esm.4 + + return str.includes('No matching version found for') && str.includes('The latest release of'); + } + }, + [CustomTipId.TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE]: { + tipId: CustomTipId.TIP_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + return str.includes('ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE'); + } + }, + [CustomTipId.TIP_PNPM_PEER_DEP_ISSUES]: { + tipId: CustomTipId.TIP_PNPM_PEER_DEP_ISSUES, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + return str.includes('ERR_PNPM_PEER_DEP_ISSUES'); + } + }, + [CustomTipId.TIP_PNPM_OUTDATED_LOCKFILE]: { + tipId: CustomTipId.TIP_PNPM_OUTDATED_LOCKFILE, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + // Todo: verify this + return str.includes('ERR_PNPM_OUTDATED_LOCKFILE'); + } + }, + + [CustomTipId.TIP_PNPM_TARBALL_INTEGRITY]: { + tipId: CustomTipId.TIP_PNPM_TARBALL_INTEGRITY, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + // Todo: verify this + return str.includes('ERR_PNPM_TARBALL_INTEGRITY'); + } + }, + + [CustomTipId.TIP_PNPM_MISMATCHED_RELEASE_CHANNEL]: { + tipId: CustomTipId.TIP_PNPM_MISMATCHED_RELEASE_CHANNEL, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + // Todo: verify this + return str.includes('ERR_PNPM_MISMATCHED_RELEASE_CHANNEL'); + } + }, + + [CustomTipId.TIP_PNPM_INVALID_NODE_VERSION]: { + tipId: CustomTipId.TIP_PNPM_INVALID_NODE_VERSION, + severity: CustomTipSeverity.Error, + type: CustomTipType.pnpm, + isMatch: (str: string) => { + // Todo: verify this + return str.includes('ERR_PNPM_INVALID_NODE_VERSION'); + } + } +}; + +/** + * Used to access the `common/config/rush/custom-tips.json` config file, + * which allows repo maintainers to configure extra details to be printed alongside + * certain Rush messages. + * @beta + */ +export class CustomTipsConfiguration { + private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + public readonly providedCustomTipsByTipId: ReadonlyMap; + + /** + * A registry mapping custom tip IDs to their corresponding metadata. + * + * @remarks + * This registry is used to look up metadata for custom tips based on their IDs. The metadata includes + * information such as the severity level, the type of tip, and an optional matching function. + * + * Each key in the registry corresponds to a `CustomTipIdEnum` value, and each value is an object + * implementing the `ICustomTipInfo` interface. + * + * @example + * ```typescript + * const tipInfo = CustomTipsConfiguration.customTipRegistry[CustomTipIdEnum.TIP_RUSH_INCONSISTENT_VERSIONS]; + * console.log(tipInfo.severity); // Output: CustomTipSeverity.Error + * ``` + * + * See {@link CustomTipId} for the list of custom tip IDs. + * See {@link ICustomTipInfo} for the structure of the metadata. + */ + public static customTipRegistry: Readonly> = { + ...RUSH_CUSTOM_TIPS, + ...PNPM_CUSTOM_TIPS + }; + + public constructor(configFilePath: string) { + const providedCustomTips: Map = new Map(); + + let configuration: ICustomTipsJson | undefined; + try { + configuration = JsonFile.loadAndValidate(configFilePath, CustomTipsConfiguration._jsonSchema); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + const customTips: ICustomTipItemJson[] | undefined = configuration?.customTips; + if (customTips) { + for (const tipItem of customTips) { + if (!(tipItem.tipId in CustomTipId)) { + throw new Error( + `The ${path.basename(configFilePath)} configuration` + + ` references an unknown ID "${tipItem.tipId}"` + ); + } + + if (providedCustomTips.has(tipItem.tipId)) { + throw new Error( + `The ${path.basename(configFilePath)} configuration` + + ` specifies a duplicate definition for "${tipItem.tipId}"` + ); + } else { + providedCustomTips.set(tipItem.tipId, tipItem); + } + } + } + + this.providedCustomTipsByTipId = providedCustomTips; + } + + /** + * If custom-tips.json defines a tip for the specified tipId, display the tip on the terminal. + * + * @remarks + * The severity of the tip is defined in ${@link CustomTipsConfiguration.customTipRegistry}. + * If you want to change the severity specifically for this call, + * use other APIs such as {@link CustomTipsConfiguration._showErrorTip}. + * + * Custom tips by design do not replace Rush's standard messaging; instead, they annotate Rush's + * output with additional team-specific advice. + * + * @internal + */ + public _showTip(terminal: ITerminal, tipId: CustomTipId): void { + const severityOfOriginalMessage: CustomTipSeverity = + CustomTipsConfiguration.customTipRegistry[tipId].severity; + + this._writeMessageWithPipes(terminal, severityOfOriginalMessage, tipId); + } + + /** + * If custom-tips.json defines a tip for the specified tipId, display the tip on the terminal. + * @remarks + * Custom tips by design do not replace Rush's standard messaging; instead, they annotate Rush's + * output with additional team-specific advice. + * @internal + */ + public _showInfoTip(terminal: ITerminal, tipId: CustomTipId): void { + this._writeMessageWithPipes(terminal, CustomTipSeverity.Info, tipId); + } + + /** + * If custom-tips.json defines a tip for the specified tipId, display the tip on the terminal. + * @remarks + * Custom tips by design do not replace Rush's standard messaging; instead, they annotate Rush's + * output with additional team-specific advice. + * @internal + */ + public _showWarningTip(terminal: ITerminal, tipId: CustomTipId): void { + this._writeMessageWithPipes(terminal, CustomTipSeverity.Warning, tipId); + } + + /** + * If custom-tips.json defines a tip for the specified tipId, display the tip on the terminal. + * @remarks + * Custom tips by design do not replace Rush's standard messaging; instead, they annotate Rush's + * output with additional team-specific advice. + * @internal + */ + public _showErrorTip(terminal: ITerminal, tipId: CustomTipId): void { + this._writeMessageWithPipes(terminal, CustomTipSeverity.Error, tipId); + } + + private _writeMessageWithPipes(terminal: ITerminal, severity: CustomTipSeverity, tipId: CustomTipId): void { + const customTipJsonItem: ICustomTipItemJson | undefined = this.providedCustomTipsByTipId.get(tipId); + if (customTipJsonItem) { + let writeFunction: + | typeof terminal.writeErrorLine + | typeof terminal.writeWarningLine + | typeof terminal.writeLine; + let prefix: string; + switch (severity) { + case CustomTipSeverity.Error: + writeFunction = terminal.writeErrorLine.bind(terminal); + prefix = Colorize.red('| '); + break; + case CustomTipSeverity.Warning: + writeFunction = terminal.writeWarningLine.bind(terminal); + prefix = Colorize.yellow('| '); + break; + default: + writeFunction = terminal.writeLine.bind(terminal); + prefix = '| '; + break; + } + + writeFunction(`| Custom Tip (${tipId})`); + writeFunction('|'); + + const message: string = customTipJsonItem.message; + const wrappedAndIndentedMessage: string = PrintUtilities.wrapWords(message, undefined, prefix); + writeFunction(...wrappedAndIndentedMessage, { doNotOverrideSgrCodes: true }); + terminal.writeLine(); + } + } +} diff --git a/libraries/rush-lib/src/api/EnvironmentConfiguration.ts b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts new file mode 100644 index 00000000000..5ccc3d06909 --- /dev/null +++ b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts @@ -0,0 +1,736 @@ +// 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 { trueCasePathSync } from 'true-case-path'; + +import type { IEnvironment } from '../utilities/Utilities'; + +/** + * @beta + */ +export interface IEnvironmentConfigurationInitializeOptions { + doNotNormalizePaths?: boolean; +} + +/** + * Names of environment variables used by Rush. + * @beta + */ +// eslint-disable-next-line @typescript-eslint/typedef +export const EnvironmentVariableNames = { + /** + * This variable overrides the temporary folder used by Rush. + * The default value is "common/temp" under the repository root. + * + * @remarks This environment variable is not compatible with workspace installs. If attempting + * to move the PNPM store path, see the `RUSH_PNPM_STORE_PATH` environment variable. + */ + RUSH_TEMP_FOLDER: 'RUSH_TEMP_FOLDER', + + /** + * This variable overrides the version of Rush that will be installed by + * the version selector. The default value is determined by the "rushVersion" + * field from rush.json. + */ + RUSH_PREVIEW_VERSION: 'RUSH_PREVIEW_VERSION', + + /** + * If this variable is set to "1", Rush will not fail the build when running a version + * of Node that does not match the criteria specified in the "nodeSupportedVersionRange" + * field from rush.json. + */ + RUSH_ALLOW_UNSUPPORTED_NODEJS: 'RUSH_ALLOW_UNSUPPORTED_NODEJS', + + /** + * Setting this environment variable overrides the value of `allowWarningsInSuccessfulBuild` + * in the `command-line.json` configuration file. Specify `1` to allow warnings in a successful build, + * or `0` to disallow them. (See the comments in the command-line.json file for more information). + */ + RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD: 'RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD', + + /** + * This variable selects a specific installation variant for Rush to use when installing + * and linking package dependencies. + * For more information, see the command-line help for the `--variant` parameter + * and this article: https://rushjs.io/pages/advanced/installation_variants/ + */ + RUSH_VARIANT: 'RUSH_VARIANT', + + /** + * Specifies the maximum number of concurrent processes to launch during a build. + * For more information, see the command-line help for the `--parallelism` parameter for "rush build". + */ + RUSH_PARALLELISM: 'RUSH_PARALLELISM', + + /** + * If this variable is set to "1", Rush will create symlinks with absolute paths instead + * of relative paths. This can be necessary when a repository is moved during a build or + * if parts of a repository are moved into a sandbox. + */ + RUSH_ABSOLUTE_SYMLINKS: 'RUSH_ABSOLUTE_SYMLINKS', + + /** + * When using PNPM as the package manager, this variable can be used to configure the path that + * PNPM will use as the store directory. + * + * If a relative path is used, then the store path will be resolved relative to the process's + * current working directory. An absolute path is recommended. + */ + RUSH_PNPM_STORE_PATH: 'RUSH_PNPM_STORE_PATH', + + /** + * When using PNPM as the package manager, this variable can be used to control whether or not PNPM + * validates the integrity of the PNPM store during installation. The value of this environment variable must be + * `1` (for true) or `0` (for false). If not specified, defaults to the value in .npmrc. + */ + RUSH_PNPM_VERIFY_STORE_INTEGRITY: 'RUSH_PNPM_VERIFY_STORE_INTEGRITY', + + /** + * This environment variable can be used to specify the `--target-folder` parameter + * for the "rush deploy" command. + */ + RUSH_DEPLOY_TARGET_FOLDER: 'RUSH_DEPLOY_TARGET_FOLDER', + + /** + * Overrides the location of the `~/.rush` global folder where Rush stores temporary files. + * + * @remarks + * + * Most of the temporary files created by Rush are stored separately for each monorepo working folder, + * to avoid issues of concurrency and compatibility between tool versions. However, a small set + * of files (e.g. installations of the `@microsoft/rush-lib` engine and the package manager) are stored + * in a global folder to speed up installations. The default location is `~/.rush` on POSIX-like + * operating systems or `C:\Users\YourName` on Windows. + * + * Use `RUSH_GLOBAL_FOLDER` to specify a different folder path. This is useful for example if a Windows + * group policy forbids executing scripts installed in a user's home directory. + * + * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. + */ + RUSH_GLOBAL_FOLDER: 'RUSH_GLOBAL_FOLDER', + + /** + * Provides a credential for a remote build cache, if configured. This credential overrides any cached credentials. + * + * @remarks + * Setting this environment variable overrides whatever credential has been saved in the + * local cloud cache credentials using `rush update-cloud-credentials`. + * + * + * If Azure Blob Storage is used to store cache entries, this must be a SAS token serialized as query + * parameters. + * + * For information on SAS tokens, see here: https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview + */ + RUSH_BUILD_CACHE_CREDENTIAL: 'RUSH_BUILD_CACHE_CREDENTIAL', + + /** + * Setting this environment variable overrides the value of `buildCacheEnabled` in the `build-cache.json` + * configuration file. + * + * @remarks + * Specify `1` to enable the build cache or `0` to disable it. + * + * If there is no build cache configured, then this environment variable is ignored. + */ + RUSH_BUILD_CACHE_ENABLED: 'RUSH_BUILD_CACHE_ENABLED', + + /** + * Overrides the value of `isCacheWriteAllowed` in the `build-cache.json` configuration file. The value of this + * environment variable must be `1` (for true) or `0` (for false). If there is no build cache configured, then + * this environment variable is ignored. + */ + 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. + * + * e.g. `Build.BuildNumber` in Azure DevOps Pipeline. + * + * @remarks + * If there is no cobuild configured, then this environment variable is ignored. + */ + RUSH_COBUILD_CONTEXT_ID: 'RUSH_COBUILD_CONTEXT_ID', + + /** + * Explicitly specifies a name for each participating cobuild runner. + * + * Setting this environment variable opts into running with cobuilds. + * + * @remarks + * This environment variable is optional, if it is not provided, a random id is used. + * + * If there is no cobuild configured, then this environment variable is ignored. + */ + RUSH_COBUILD_RUNNER_ID: 'RUSH_COBUILD_RUNNER_ID', + + /** + * If this variable is set to "1", When getting distributed builds, Rush will automatically handle the leaf project + * with build cache "disabled" by writing to the cache in a special "log files only mode". This is useful when you + * want to use Cobuilds to improve the performance in CI validations and the leaf projects have not enabled cache. + */ + RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED: 'RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED', + + /** + * Explicitly specifies the path for the Git binary that is invoked by certain Rush operations. + */ + RUSH_GIT_BINARY_PATH: 'RUSH_GIT_BINARY_PATH', + + /** + * Explicitly specifies the path for the `tar` binary that is invoked by certain Rush operations. + */ + RUSH_TAR_BINARY_PATH: 'RUSH_TAR_BINARY_PATH', + + /** + * Internal variable used by `rushx` when recursively invoking another `rushx` process, to avoid + * nesting event hooks. + */ + _RUSH_RECURSIVE_RUSHX_CALL: '_RUSH_RECURSIVE_RUSHX_CALL', + + /** + * Internal variable that explicitly specifies the path for the version of `@microsoft/rush-lib` being executed. + * Will be set upon loading Rush. + */ + _RUSH_LIB_PATH: '_RUSH_LIB_PATH', + + /** + * When Rush executes shell scripts, it sometimes changes the working directory to be a project folder or + * the repository root folder. The original working directory (where the Rush command was invoked) is assigned + * to the the child process's `RUSH_INVOKED_FOLDER` environment variable, in case it is needed by the script. + * + * @remarks + * The `RUSH_INVOKED_FOLDER` variable is the same idea as the `INIT_CWD` variable that package managers + * assign when they execute lifecycle scripts. + */ + RUSH_INVOKED_FOLDER: 'RUSH_INVOKED_FOLDER', + + /** + * When running a hook script, this environment variable communicates the original arguments + * passed to the `rush` or `rushx` command. + * + * @remarks + * Unlike `RUSH_INVOKED_FOLDER`, the `RUSH_INVOKED_ARGS` variable is only available for hook scripts. + * 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' +} 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; + + private static _rushTempFolderOverride: string | undefined; + + private static _absoluteSymlinks: boolean = false; + + private static _allowUnsupportedNodeVersion: boolean = false; + + private static _allowWarningsInSuccessfulBuild: boolean = false; + + private static _pnpmStorePathOverride: string | undefined; + + private static _pnpmVerifyStoreIntegrity: boolean | undefined; + + private static _rushGlobalFolderOverride: string | undefined; + + private static _buildCacheCredential: string | undefined; + + private static _buildCacheEnabled: boolean | undefined; + + private static _buildCacheWriteAllowed: boolean | undefined; + + private static _buildCacheOverrideJson: string | undefined; + + private static _buildCacheOverrideJsonFilePath: string | undefined; + + private static _cobuildContextId: string | undefined; + + private static _cobuildRunnerId: string | undefined; + + private static _cobuildLeafProjectLogOnlyAllowed: boolean | undefined; + + private static _gitBinaryPath: string | undefined; + + private static _tarBinaryPath: string | undefined; + + /** + * If true, the environment configuration has been validated and initialized. + */ + public static get hasBeenValidated(): boolean { + return EnvironmentConfiguration._hasBeenValidated; + } + + /** + * An override for the common/temp folder path. + */ + public static get rushTempFolderOverride(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._rushTempFolderOverride; + } + + /** + * If "1", create symlinks with absolute paths instead of relative paths. + * See {@link EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS} + */ + public static get absoluteSymlinks(): boolean { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._absoluteSymlinks; + } + + /** + * If this environment variable is set to "1", the Node.js version check will print a warning + * instead of causing a hard error if the environment's Node.js version doesn't match the + * version specifier in `rush.json`'s "nodeSupportedVersionRange" property. + * + * See {@link EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS}. + */ + public static get allowUnsupportedNodeVersion(): boolean { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._allowUnsupportedNodeVersion; + } + + /** + * Setting this environment variable overrides the value of `allowWarningsInSuccessfulBuild` + * in the `command-line.json` configuration file. Specify `1` to allow warnings in a successful build, + * 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; + } + + /** + * An override for the PNPM store path, if `pnpmStore` configuration is set to 'path' + * See {@link EnvironmentVariableNames.RUSH_PNPM_STORE_PATH} + */ + public static get pnpmStorePathOverride(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._pnpmStorePathOverride; + } + + /** + * If specified, enables or disables integrity verification of the pnpm store during install. + * See {@link EnvironmentVariableNames.RUSH_PNPM_VERIFY_STORE_INTEGRITY} + */ + public static get pnpmVerifyStoreIntegrity(): boolean | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._pnpmVerifyStoreIntegrity; + } + + /** + * Overrides the location of the `~/.rush` global folder where Rush stores temporary files. + * See {@link EnvironmentVariableNames.RUSH_GLOBAL_FOLDER} + */ + public static get rushGlobalFolderOverride(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._rushGlobalFolderOverride; + } + + /** + * Provides a credential for reading from and writing to a remote build cache, if configured. + * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_CREDENTIAL} + */ + public static get buildCacheCredential(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._buildCacheCredential; + } + + /** + * If set, enables or disables the cloud build cache feature. + * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED} + */ + public static get buildCacheEnabled(): boolean | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._buildCacheEnabled; + } + + /** + * If set, enables or disables writing to the cloud build cache. + * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_WRITE_ALLOWED} + */ + public static get buildCacheWriteAllowed(): boolean | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._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 { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._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 { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._buildCacheOverrideJsonFilePath; + } + + /** + * Provides a determined cobuild context id if configured + * See {@link EnvironmentVariableNames.RUSH_COBUILD_CONTEXT_ID} + */ + public static get cobuildContextId(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._cobuildContextId; + } + + /** + * Provides a determined cobuild runner id if configured + * See {@link EnvironmentVariableNames.RUSH_COBUILD_RUNNER_ID} + */ + public static get cobuildRunnerId(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._cobuildRunnerId; + } + + /** + * If set, enables or disables the cobuild leaf project log only feature. + * See {@link EnvironmentVariableNames.RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED} + */ + public static get cobuildLeafProjectLogOnlyAllowed(): boolean | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._cobuildLeafProjectLogOnlyAllowed; + } + + /** + * Allows the git binary path to be explicitly provided. + * See {@link EnvironmentVariableNames.RUSH_GIT_BINARY_PATH} + */ + public static get gitBinaryPath(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._gitBinaryPath; + } + + /** + * Allows the tar binary path to be explicitly provided. + * See {@link EnvironmentVariableNames.RUSH_TAR_BINARY_PATH} + */ + public static get tarBinaryPath(): string | undefined { + EnvironmentConfiguration._ensureValidated(); + return EnvironmentConfiguration._tarBinaryPath; + } + + /** + * The front-end RushVersionSelector relies on `RUSH_GLOBAL_FOLDER`, so its value must be read before + * `EnvironmentConfiguration` is initialized (and actually before the correct version of `EnvironmentConfiguration` + * is even installed). Thus we need to read this environment variable differently from all the others. + * @internal + */ + 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); + return normalizedValue; + } + } + + /** + * Reads and validates environment variables. If any are invalid, this function will throw. + */ + public static validate(options: IEnvironmentConfigurationInitializeOptions = {}): void { + EnvironmentConfiguration.reset(); + + const unknownEnvVariables: string[] = []; + for (const envVarName in process.env) { + 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; + switch (normalizedEnvVarName) { + case EnvironmentVariableNames.RUSH_TEMP_FOLDER: { + EnvironmentConfiguration._rushTempFolderOverride = + value && !options.doNotNormalizePaths + ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value + : value; + break; + } + + case EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS: { + EnvironmentConfiguration._absoluteSymlinks = + EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS, + value + ) ?? false; + break; + } + + case EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS: { + 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'; + } else { + EnvironmentConfiguration._allowUnsupportedNodeVersion = + EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS, + value + ) ?? false; + } + break; + } + + case EnvironmentVariableNames.RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD: { + EnvironmentConfiguration._allowWarningsInSuccessfulBuild = + EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD, + value + ) ?? false; + break; + } + + case EnvironmentVariableNames.RUSH_PNPM_STORE_PATH: { + EnvironmentConfiguration._pnpmStorePathOverride = + value && !options.doNotNormalizePaths + ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value + : value; + break; + } + + case EnvironmentVariableNames.RUSH_PNPM_VERIFY_STORE_INTEGRITY: { + EnvironmentConfiguration._pnpmVerifyStoreIntegrity = + value === '1' ? true : value === '0' ? false : undefined; + break; + } + + case EnvironmentVariableNames.RUSH_GLOBAL_FOLDER: { + // Handled specially below + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_CREDENTIAL: { + EnvironmentConfiguration._buildCacheCredential = value; + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED: { + EnvironmentConfiguration._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 + ); + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON: { + EnvironmentConfiguration._buildCacheOverrideJson = value; + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH: { + EnvironmentConfiguration._buildCacheOverrideJsonFilePath = value; + break; + } + + case EnvironmentVariableNames.RUSH_COBUILD_CONTEXT_ID: { + EnvironmentConfiguration._cobuildContextId = value; + break; + } + + case EnvironmentVariableNames.RUSH_COBUILD_RUNNER_ID: { + EnvironmentConfiguration._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 + ); + break; + } + + case EnvironmentVariableNames.RUSH_GIT_BINARY_PATH: { + EnvironmentConfiguration._gitBinaryPath = value; + break; + } + + case EnvironmentVariableNames.RUSH_TAR_BINARY_PATH: { + EnvironmentConfiguration._tarBinaryPath = value; + break; + } + + case EnvironmentVariableNames.RUSH_PARALLELISM: + case EnvironmentVariableNames.RUSH_PREVIEW_VERSION: + case EnvironmentVariableNames.RUSH_VARIANT: + case EnvironmentVariableNames.RUSH_DEPLOY_TARGET_FOLDER: + // Handled by @microsoft/rush front end + break; + + case EnvironmentVariableNames.RUSH_INVOKED_FOLDER: + case EnvironmentVariableNames.RUSH_INVOKED_ARGS: + case EnvironmentVariableNames._RUSH_LIB_PATH: + // Assigned by Rush itself + break; + + case EnvironmentVariableNames._RUSH_RECURSIVE_RUSHX_CALL: + // Assigned/read internally by RushXCommandLine + break; + + default: + unknownEnvVariables.push(envVarName); + break; + } + } + } + + // This strictness intends to catch mistakes where variables are misspelled or not used correctly. + if (unknownEnvVariables.length > 0) { + throw new Error( + 'The following environment variables were found with the "RUSH_" prefix, but they are not ' + + `recognized by this version of Rush: ${unknownEnvVariables.join(', ')}` + ); + } + + if ( + EnvironmentConfiguration._buildCacheOverrideJsonFilePath && + EnvironmentConfiguration._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); + + EnvironmentConfiguration._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(); + } + } + + public static parseBooleanEnvironmentVariable( + name: string, + value: string | undefined + ): boolean | undefined { + if (value === '' || value === undefined) { + return undefined; + } else if (value === '0') { + return false; + } else if (value === '1') { + return true; + } else { + throw new Error( + `Invalid value "${value}" for the environment variable ${name}. Valid choices are 0 or 1.` + ); + } + } + + /** + * 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 + } + } + + return undefined; + } +} diff --git a/libraries/rush-lib/src/api/EventHooks.ts b/libraries/rush-lib/src/api/EventHooks.ts new file mode 100644 index 00000000000..8d671c50b38 --- /dev/null +++ b/libraries/rush-lib/src/api/EventHooks.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Enum } from '@rushstack/node-core-library'; + +import type { IEventHooksJson } from './RushConfiguration'; + +/** + * Events happen during Rush runs. + * @beta + */ +export enum Event { + /** + * Pre Rush install event + */ + preRushInstall = 1, + /** + * Post Rush install event + */ + postRushInstall = 2, + /** + * Pre Rush build event + */ + preRushBuild = 3, + /** + * Post Rush build event + */ + postRushBuild = 4, + /** + * Start of rushx execution event + */ + preRushx = 5, + /** + * End of rushx execution event + */ + postRushx = 6 +} + +/** + * This class represents Rush event hooks configured for this repo. + * Hooks are customized script actions that Rush executes when specific events occur. + * The actions are expressed as a command-line that is executed using the operating system shell. + * @beta + */ +export class EventHooks { + private _hooks: Map; + + /** + * @internal + */ + public constructor(eventHooksJson: IEventHooksJson) { + this._hooks = new Map(); + for (const [name, eventHooks] of Object.entries(eventHooksJson)) { + const eventName: Event | undefined = Enum.tryGetValueByKey(Event, name); + if (eventName) { + this._hooks.set(eventName, [...eventHooks]); + } + } + } + + /** + * Return all the scripts associated with the specified event. + * @param event - Rush event + */ + public get(event: Event): string[] { + return this._hooks.get(event) || []; + } +} diff --git a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts new file mode 100644 index 00000000000..505aaf8a044 --- /dev/null +++ b/libraries/rush-lib/src/api/ExperimentsConfiguration.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 { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import schemaJson from '../schemas/experiments.schema.json'; + +const GRADUATED_EXPERIMENTS: Set = new Set(['phasedCommands']); + +/** + * This interface represents the raw experiments.json file which allows repo + * maintainers to enable and disable experimental Rush features. + * @beta + */ +export interface IExperimentsJson { + /** + * By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead for faster installs. + */ + usePnpmFrozenLockfileForRushInstall?: boolean; + + /** + * By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--prefer-frozen-lockfile' instead to minimize shrinkwrap changes. + */ + usePnpmPreferFrozenLockfileForRushUpdate?: boolean; + + /** + * By default, 'rush update' runs as a single operation. + * Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. + * Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs. + */ + usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate?: boolean; + + /** + * If using the 'preventManualShrinkwrapChanges' option, restricts the hash to only include the layout of external dependencies. + * Used to allow links between workspace projects or the addition/removal of references to existing dependency versions to not + * cause hash changes. + */ + omitImportersFromPreventManualShrinkwrapChanges?: boolean; + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + noChmodFieldInTarHeaderNormalization?: boolean; + + /** + * If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. + * This will not replay warnings from the cached build. + */ + buildCacheWithAllowWarningsInSuccessfulBuild?: boolean; + + /** + * If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. + * This will not replay warnings from the skipped build. + */ + buildSkipWithAllowWarningsInSuccessfulBuild?: boolean; + + /** + * If true, perform a clean install after when running `rush install` or `rush update` if the + * `.npmrc` file has changed since the last install. + */ + cleanInstallAfterNpmrcChanges?: boolean; + + /** + * If true, print the outputs of shell commands defined in event hooks to the console. + */ + printEventHooksOutputToConsole?: boolean; + + /** + * If true, Rush will not allow node_modules in the repo folder or in parent folders. + */ + forbidPhantomResolvableNodeModulesFolders?: boolean; + + /** + * (UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot + * correctly satisfy versioning requirements without installing duplicate copies of a package inside the + * node_modules folder. This poses a problem for "workspace:*" dependencies, as they are normally + * installed by making a symlink to the local project source folder. PNPM's "injected dependencies" + * feature provides a model for copying the local project folder into node_modules, however copying + * must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. + * The "pnpm-sync" tool manages this operation; see its documentation for details. + * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies + * by invoking "pnpm-sync" during the build. + */ + usePnpmSyncForInjectedDependencies?: boolean; + + /** + * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. + */ + generateProjectImpactGraphDuringRushUpdate?: boolean; + + /** + * 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?: boolean; + + /** + * (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?: boolean; + + /** + * Allow cobuilds without using the build cache to store previous execution info. When setting up + * distributed builds, Rush will allow uncacheable projects to still leverage the cobuild feature. + * This is useful when you want to speed up operations that can't (or shouldn't) be cached. + */ + allowCobuildWithoutCache?: boolean; + + /** + * 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?: 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; +} + +const _EXPERIMENTS_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + +/** + * Use this class to load the "common/config/rush/experiments.json" config file. + * This file allows repo maintainers to enable and disable experimental Rush features. + * @public + */ +export class ExperimentsConfiguration { + /** + * Get the experiments configuration. + * @beta + */ + public readonly configuration: Readonly; + + /** + * @internal + */ + public constructor(jsonFilePath: string) { + try { + this.configuration = JsonFile.loadAndValidate(jsonFilePath, _EXPERIMENTS_JSON_SCHEMA); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + this.configuration = {}; + } else { + throw e; + } + } + + for (const experimentName of Object.getOwnPropertyNames(this.configuration)) { + if (GRADUATED_EXPERIMENTS.has(experimentName)) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `The experiment "${experimentName}" has graduated to a standard feature. Remove this experiment from ` + + `"${jsonFilePath}".` + ) + ); + } + } + } +} diff --git a/libraries/rush-lib/src/api/FlagFile.ts b/libraries/rush-lib/src/api/FlagFile.ts new file mode 100644 index 00000000000..535029943c9 --- /dev/null +++ b/libraries/rush-lib/src/api/FlagFile.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 { FileSystem, JsonFile, type JsonObject, Objects } from '@rushstack/node-core-library'; + +/** + * A base class for flag file. + * @internal + */ +export class FlagFile { + /** + * Flag file path + */ + public readonly path: string; + + /** + * Content of the flag + */ + protected _state: TState; + + /** + * Creates a new flag file + * @param folderPath - the folder that this flag is managing + * @param state - optional, the state that should be managed or compared + */ + public constructor(folderPath: string, flagName: string, initialState: TState) { + this.path = `${folderPath}/${flagName}.flag`; + this._state = initialState; + } + + /** + * Returns true if the file exists and the contents match the current state. + */ + public async isValidAsync(): Promise { + let oldState: JsonObject | undefined; + try { + oldState = await JsonFile.loadAsync(this.path); + const newState: JsonObject = this._state; + return Objects.areDeepEqual(oldState, newState); + } catch (err) { + return false; + } + } + + /** + * Writes the flag file to disk with the current state + */ + public async createAsync(): Promise { + await JsonFile.saveAsync(this._state, this.path, { + ensureFolderExists: true + }); + } + + /** + * Removes the flag file + */ + public async clearAsync(): Promise { + await FileSystem.deleteFileAsync(this.path); + } +} diff --git a/libraries/rush-lib/src/api/LastInstallFlag.ts b/libraries/rush-lib/src/api/LastInstallFlag.ts new file mode 100644 index 00000000000..ab854ac6ef7 --- /dev/null +++ b/libraries/rush-lib/src/api/LastInstallFlag.ts @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; +import type { Subspace } from './Subspace'; +import { Selection } from '../logic/Selection'; +import { FlagFile } from './FlagFile'; + +const LAST_INSTALL_FLAG_FILE_NAME: string = 'last-install'; + +/** + * This represents the JSON data structure for the "last-install.flag" file. + */ +export interface ILastInstallFlagJson { + /** + * Current node version + */ + node?: string; + /** + * Current package manager name + */ + packageManager?: PackageManagerName; + /** + * Current package manager version + */ + packageManagerVersion: string; + /** + * Current rush json folder + */ + rushJsonFolder: string; + /** + * The content of package.json, used in the flag file of autoinstaller + */ + packageJson?: IPackageJson; + /** + * Same with pnpmOptions.pnpmStorePath in rush.json + */ + storePath?: string; + /** + * An experimental flag used by cleanInstallAfterNpmrcChanges + */ + npmrcHash?: string; + /** + * True when "useWorkspaces" is true in rush.json + */ + workspaces?: boolean; + /** + * True when user explicitly specify "--ignore-scripts" CLI parameter or deferredInstallationScripts + */ + ignoreScripts?: boolean; + /** + * When specified, it is a list of selected projects during partial install + * It is undefined when full install + */ + selectedProjectNames?: string[]; + /** + * pnpm-sync-lib version + */ + pnpmSync?: string; +} + +interface ILockfileValidityCheckOptions { + statePropertiesToIgnore?: (keyof ILastInstallFlagJson)[]; + rushVerb?: string; +} + +/** + * A helper class for managing last-install flags, which are persistent and + * indicate that something installed in the folder was successfully completed. + * It also compares state, so that if something like the Node.js version has changed, + * it can invalidate the last install. + */ +export class LastInstallFlag extends FlagFile> { + /** + * Creates a new LastInstall flag + * @param folderPath - the folder that this flag is managing + * @param state - optional, the state that should be managed or compared + */ + public constructor(folderPath: string, state?: Partial) { + super(folderPath, LAST_INSTALL_FLAG_FILE_NAME, state || {}); + } + + /** + * Returns true if the file exists and the contents match the current state. + */ + public async isValidAsync(): Promise { + return await this._isValidAsync(false, {}); + } + + /** + * Same as isValid(), but with an additional check: If the current state is not equal to the previous + * state, and an the current state causes an error, then throw an exception with a friendly message. + * + * @internal + */ + public async checkValidAndReportStoreIssuesAsync( + options: ILockfileValidityCheckOptions & { rushVerb: string } + ): Promise { + return this._isValidAsync(true, options); + } + + private async _isValidAsync( + checkValidAndReportStoreIssues: boolean, + { rushVerb = 'update', statePropertiesToIgnore }: ILockfileValidityCheckOptions = {} + ): Promise { + let oldState: JsonObject; + try { + oldState = await JsonFile.loadAsync(this.path); + } catch (err) { + return false; + } + + const newState: ILastInstallFlagJson = { ...this._state } as ILastInstallFlagJson; + if (statePropertiesToIgnore) { + for (const optionToIgnore of statePropertiesToIgnore) { + delete newState[optionToIgnore]; + delete oldState[optionToIgnore]; + } + } + + if (!Objects.areDeepEqual(oldState, newState)) { + if (checkValidAndReportStoreIssues) { + const pkgManager: PackageManagerName = newState.packageManager as PackageManagerName; + if (pkgManager === 'pnpm') { + if ( + // Only throw an error if the package manager hasn't changed from PNPM + oldState.packageManager === pkgManager + ) { + const normalizedOldStorePath: string = oldState.storePath + ? Path.convertToPlatformDefault(oldState.storePath) + : ''; + const normalizedNewStorePath: string = newState.storePath + ? Path.convertToPlatformDefault(newState.storePath) + : ''; + if ( + // Throw if the store path changed + normalizedOldStorePath !== normalizedNewStorePath + ) { + throw new Error( + 'Current PNPM store path does not match the last one used. This may cause inconsistency in your builds.\n\n' + + `If you wish to install with the new store path, please run "rush ${rushVerb} --purge"\n\n` + + `Old Path: ${normalizedOldStorePath}\n` + + `New Path: ${normalizedNewStorePath}` + ); + } + } + // check whether new selected projects are installed + if (newState.selectedProjectNames) { + if (!oldState.selectedProjectNames) { + // used to be a full install + return true; + } else if ( + Selection.union(newState.selectedProjectNames, oldState.selectedProjectNames).size === + oldState.selectedProjectNames.length + ) { + // current selected projects are included in old selected projects + return true; + } + } + } + } + return false; + } + + return true; + } + + /** + * Merge new data into current state by "merge" + */ + public mergeFromObject(data: JsonObject): void { + if (objectUtilities.isMatch(this._state, data)) { + return; + } + objectUtilities.merge(this._state, data); + } +} + +/** + * Gets the LastInstall flag and sets the current state. This state is used to compare + * against the last-known-good state tracked by the LastInstall flag. + * @param rushConfiguration - the configuration of the Rush repo to get the install + * state from + * + * @internal + */ +export function getCommonTempFlag( + rushConfiguration: RushConfiguration, + subspace: Subspace, + extraState: Record = {} +): LastInstallFlag { + const currentState: ILastInstallFlagJson = { + node: process.versions.node, + packageManager: rushConfiguration.packageManager, + packageManagerVersion: rushConfiguration.packageManagerToolVersion, + rushJsonFolder: rushConfiguration.rushJsonFolder, + ignoreScripts: false, + pnpmSync: pnpmSyncGetJsonVersion(), + ...extraState + }; + + if (currentState.packageManager === 'pnpm' && rushConfiguration.pnpmOptions) { + currentState.storePath = rushConfiguration.pnpmOptions.pnpmStorePath; + if (rushConfiguration.pnpmOptions.useWorkspaces) { + currentState.workspaces = rushConfiguration.pnpmOptions.useWorkspaces; + } + } + + return new LastInstallFlag(subspace.getSubspaceTempFolderPath(), currentState); +} diff --git a/libraries/rush-lib/src/api/PackageJsonEditor.ts b/libraries/rush-lib/src/api/PackageJsonEditor.ts new file mode 100644 index 00000000000..27106a38ad1 --- /dev/null +++ b/libraries/rush-lib/src/api/PackageJsonEditor.ts @@ -0,0 +1,407 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; + +/** + * @public + */ +export enum DependencyType { + Regular = 'dependencies', + Dev = 'devDependencies', + Optional = 'optionalDependencies', + Peer = 'peerDependencies', + YarnResolutions = 'resolutions' +} + +/** + * @public + */ +export class PackageJsonDependency { + private _version: string; + private _onChange: () => void; + + public readonly name: string; + public readonly dependencyType: DependencyType; + + public constructor(name: string, version: string, type: DependencyType, onChange: () => void) { + this.name = name; + this._version = version; + this.dependencyType = type; + this._onChange = onChange; + } + + public get version(): string { + return this._version; + } + + public setVersion(newVersion: string): void { + if (!semver.valid(newVersion) && !semver.validRange(newVersion)) { + throw new Error(`Cannot set version to invalid value: "${newVersion}"`); + } + this._version = newVersion; + this._onChange(); + } +} + +/** + * @public + */ +export class PackageJsonDependencyMeta { + private _injected: boolean; + private _onChange: () => void; + + public readonly name: string; + + public constructor(name: string, injected: boolean, onChange: () => void) { + this.name = name; + this._injected = injected; + this._onChange = onChange; + } + + public get injected(): boolean { + return this._injected; + } +} + +/** + * @public + */ +export class PackageJsonEditor { + private readonly _dependencies: Map; + // NOTE: The "devDependencies" section is tracked separately because sometimes people + // will specify a specific version for development, while *also* specifying a broader + // SemVer range in one of the other fields for consumers. Thus "dependencies", "optionalDependencies", + // and "peerDependencies" are mutually exclusive, but "devDependencies" is not. + private readonly _devDependencies: Map; + + private readonly _dependenciesMeta: Map; + + // NOTE: The "resolutions" field is a yarn specific feature that controls package + // resolution override within yarn. + private readonly _resolutions: Map; + private _modified: boolean; + private _sourceData: IPackageJson; + + public readonly filePath: string; + + /** + * @internal + */ + protected constructor(filepath: string, data: IPackageJson) { + this.filePath = filepath; + 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 _onChange: () => void = this._onChange.bind(this); + + 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"` + ); + } + + this._dependencies.set( + packageName, + new PackageJsonDependency(packageName, dependencies[packageName], DependencyType.Regular, _onChange) + ); + }); + + Object.keys(optionalDependencies || {}).forEach((packageName: string) => { + if (Object.prototype.hasOwnProperty.call(peerDependencies, packageName)) { + throw new Error( + `The package "${packageName}" cannot be listed in both ` + + `"optionalDependencies" and "peerDependencies"` + ); + } + this._dependencies.set( + packageName, + new PackageJsonDependency( + packageName, + optionalDependencies[packageName], + DependencyType.Optional, + _onChange + ) + ); + }); + + Object.keys(peerDependencies || {}).forEach((packageName: string) => { + this._dependencies.set( + packageName, + new PackageJsonDependency( + packageName, + peerDependencies[packageName], + DependencyType.Peer, + _onChange + ) + ); + }); + + Object.keys(devDependencies || {}).forEach((packageName: string) => { + this._devDependencies.set( + packageName, + new PackageJsonDependency(packageName, devDependencies[packageName], DependencyType.Dev, _onChange) + ); + }); + + Object.keys(resolutions || {}).forEach((packageName: string) => { + this._resolutions.set( + 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) + ); + }); + + // (Do not sort this._resolutions because order may be significant; the RFC is unclear about that.) + Sort.sortMapKeys(this._dependencies); + Sort.sortMapKeys(this._devDependencies); + } catch (e) { + throw new Error(`Error loading "${filepath}": ${(e as Error).message}`); + } + } + + public static load(filePath: string): PackageJsonEditor { + return new PackageJsonEditor(filePath, JsonFile.load(filePath)); + } + + public static fromObject(object: IPackageJson, filename: string): PackageJsonEditor { + return new PackageJsonEditor(filename, object); + } + + public get name(): string { + return this._sourceData.name; + } + + public get version(): string { + return this._sourceData.version; + } + + /** + * The list of dependencies of type DependencyType.Regular, DependencyType.Optional, or DependencyType.Peer. + */ + public get dependencyList(): ReadonlyArray { + return [...this._dependencies.values()]; + } + + /** + * The list of dependencies of type DependencyType.Dev. + */ + public get devDependencyList(): ReadonlyArray { + return [...this._devDependencies.values()]; + } + + /** + * The list of dependenciesMeta in package.json. + */ + public get dependencyMetaList(): ReadonlyArray { + return [...this._dependenciesMeta.values()]; + } + + /** + * This field is a Yarn-specific feature that allows overriding of package resolution. + * + * @remarks + * See the {@link https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-selective-versions-resolutions.md + * | 0000-selective-versions-resolutions.md RFC} for details. + */ + public get resolutionsList(): ReadonlyArray { + return [...this._resolutions.values()]; + } + + public tryGetDependency(packageName: string): PackageJsonDependency | undefined { + return this._dependencies.get(packageName); + } + + public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { + return this._devDependencies.get(packageName); + } + + public addOrUpdateDependency( + packageName: string, + newVersion: string, + dependencyType: DependencyType + ): void { + const dependency: PackageJsonDependency = new PackageJsonDependency( + packageName, + newVersion, + dependencyType, + this._onChange.bind(this) + ); + + // Rush collapses everything that isn't a devDependency into the dependencies + // field, so we need to set the value depending on dependency type + switch (dependencyType) { + case DependencyType.Regular: + case DependencyType.Optional: + case DependencyType.Peer: + this._dependencies.set(packageName, dependency); + break; + case DependencyType.Dev: + this._devDependencies.set(packageName, dependency); + break; + case DependencyType.YarnResolutions: + this._resolutions.set(packageName, dependency); + break; + default: + throw new InternalError('Unsupported DependencyType'); + } + + this._modified = true; + } + + public removeDependency(packageName: string, dependencyType: DependencyType): void { + switch (dependencyType) { + case DependencyType.Regular: + case DependencyType.Optional: + case DependencyType.Peer: + this._dependencies.delete(packageName); + break; + case DependencyType.Dev: + this._devDependencies.delete(packageName); + break; + case DependencyType.YarnResolutions: + this._resolutions.delete(packageName); + break; + default: + throw new InternalError('Unsupported DependencyType'); + } + + this._modified = true; + } + + public saveIfModified(): boolean { + if (this._modified) { + this._modified = false; + this._sourceData = this._normalize(this._sourceData); + JsonFile.save(this._sourceData, this.filePath, { + updateExistingFile: true, + jsonSyntax: JsonSyntax.Strict + }); + return true; + } + return false; + } + + /** + * Get the normalized package.json that represents the current state of the + * PackageJsonEditor. This method does not save any changes that were made to the + * package.json, but instead returns the object representation of what would be saved + * if saveIfModified() is called. + */ + public saveToObject(): IPackageJson { + // Only normalize if we need to + const sourceData: IPackageJson = this._modified ? this._normalize(this._sourceData) : this._sourceData; + // Provide a clone to avoid reference back to the original data object + return cloneDeep(sourceData); + } + + private _onChange(): void { + this._modified = true; + } + + /** + * Create a normalized shallow copy of the provided package.json without modifying the + * original. If the result of this method is being returned via a public facing method, + * it will still need to be deep-cloned to avoid propogating changes back to the + * original dataset. + */ + private _normalize(source: IPackageJson): IPackageJson { + const normalizedData: IPackageJson = { ...source }; + delete normalizedData.dependencies; + delete normalizedData.optionalDependencies; + delete normalizedData.peerDependencies; + delete normalizedData.devDependencies; + delete normalizedData.resolutions; + + const keys: string[] = [...this._dependencies.keys()].sort(); + + for (const packageName of keys) { + const dependency: PackageJsonDependency = this._dependencies.get(packageName)!; + + switch (dependency.dependencyType) { + case DependencyType.Regular: + if (!normalizedData.dependencies) { + normalizedData.dependencies = {}; + } + normalizedData.dependencies[dependency.name] = dependency.version; + break; + case DependencyType.Optional: + if (!normalizedData.optionalDependencies) { + normalizedData.optionalDependencies = {}; + } + normalizedData.optionalDependencies[dependency.name] = dependency.version; + break; + case DependencyType.Peer: + if (!normalizedData.peerDependencies) { + normalizedData.peerDependencies = {}; + } + normalizedData.peerDependencies[dependency.name] = dependency.version; + break; + case DependencyType.Dev: // uses this._devDependencies instead + case DependencyType.YarnResolutions: // uses this._resolutions instead + 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)!; + + if (!normalizedData.devDependencies) { + normalizedData.devDependencies = {}; + } + normalizedData.devDependencies[dependency.name] = dependency.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)!; + + if (!normalizedData.resolutions) { + normalizedData.resolutions = {}; + } + normalizedData.resolutions[dependency.name] = dependency.version; + } + + return normalizedData; + } +} diff --git a/libraries/rush-lib/src/api/PackageNameParsers.ts b/libraries/rush-lib/src/api/PackageNameParsers.ts new file mode 100644 index 00000000000..a248c0f4882 --- /dev/null +++ b/libraries/rush-lib/src/api/PackageNameParsers.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { PackageNameParser } from '@rushstack/node-core-library'; + +export class PackageNameParsers { + /** + * This is the default for `RushConfiguration.packageNameParser`. + */ + public static rushDefault: PackageNameParser = new PackageNameParser({}); + + /** + * This is the `RushConfiguration.packageNameParser` used when `allowMostlyStandardPackageNames = true` + * in rush.json. + */ + public static mostlyStandard: PackageNameParser = new PackageNameParser({ + allowUpperCase: true + }); + + /** + * Use this in contexts where we don't have easy access to `RushConfiguration.packageNameParser` + * AND the package name was already validated at some earlier stage. + */ + public static permissive: PackageNameParser = PackageNameParsers.mostlyStandard; +} diff --git a/libraries/rush-lib/src/api/Rush.ts b/libraries/rush-lib/src/api/Rush.ts new file mode 100644 index 00000000000..af1187d1598 --- /dev/null +++ b/libraries/rush-lib/src/api/Rush.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 * as path from 'node:path'; + +import { InternalError, type IPackageJson, PackageJsonLookup } from '@rushstack/node-core-library'; +import type { ITerminalProvider } from '@rushstack/terminal'; + +import '../utilities/SetRushLibPath'; + +import { RushCommandLineParser } from '../cli/RushCommandLineParser'; +import { RushStartupBanner } from '../cli/RushStartupBanner'; +import { RushXCommandLine } from '../cli/RushXCommandLine'; +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. + * + * @public + */ +export interface ILaunchOptions { + /** + * True if the tool was invoked from within a project with a rush.json file, otherwise false. We + * consider a project without a rush.json to be "unmanaged" and we'll print that to the command line when + * the tool is executed. This is mainly used for debugging purposes. + */ + isManaged: boolean; + + /** + * If true, the wrapper process already printed a warning that the version of Node.js hasn't been tested + * with this version of Rush, so we shouldn't print a similar error. + */ + alreadyReportedNodeTooNewError?: boolean; + + /** + * Pass along the terminal provider from the CLI version selector. + * + * @privateRemarks + * We should remove this. The version selector package can be very old. It's unwise for + * `rush-lib` to rely on a potentially ancient `ITerminalProvider` implementation. + */ + terminalProvider?: ITerminalProvider; + + /** + * Used only by `@microsoft/rush/lib/start-dev.js` during development. + * Specifies Rush devDependencies of the `@microsoft/rush` to be manually loaded. + * + * @remarks + * Marked as `@internal` because `IBuiltInPluginConfiguration` is internal. + * @internal + */ + builtInPluginConfigurations?: IBuiltInPluginConfiguration[]; +} + +/** + * 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 + * and start a new Node.js process. + * + * @remarks + * Earlier versions of the rush frontend used a different API contract. In the old contract, + * the second argument was the `isManaged` value of the {@link ILaunchOptions} object. + * + * 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); + + if (!RushCommandLineParser.shouldRestrictConsoleOutput()) { + RushStartupBanner.logBanner(Rush.version, options.isManaged); + } + + if (!CommandLineMigrationAdvisor.checkArgv(process.argv)) { + // The migration advisor recognized an obsolete command-line + process.exitCode = 1; + return; + } + + Rush._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 + measureAsyncFn('rush:parser:executeAsync', () => parser.executeAsync()).catch(console.error); + } + + /** + * This API is used by the `@microsoft/rush` front end to launch the "rushx" command-line. + * Third-party tools should not use this API. Instead, they should execute the "rushx" binary + * and start a new Node.js process. + */ + public static launchRushX(launcherVersion: string, options: ILaunchOptions): void { + options = Rush._normalizeLaunchOptions(options); + Rush._assignRushInvokedFolder(); + // eslint-disable-next-line no-console + RushXCommandLine.launchRushXAsync(launcherVersion, options).catch(console.error); // CommandLineParser.executeAsync() should never reject the promise + } + + /** + * This API is used by the `@microsoft/rush` front end to launch the "rush-pnpm" command-line. + * Third-party tools should not use this API. Instead, they should execute the "rush-pnpm" binary + * and start a new Node.js process. + */ + public static launchRushPnpm(launcherVersion: string, options: ILaunchOptions): void { + Rush._assignRushInvokedFolder(); + RushPnpmCommandLine.launch(launcherVersion, { ...options }); + } + + /** + * The currently executing version of the "rush-lib" library. + * This is the same as the Rush tool version for that release. + */ + public static get version(): string { + return this._rushLibPackageJson.version; + } + + /** + * @internal + */ + public static get _rushLibPackageJson(): IPackageJson { + Rush._ensureOwnPackageJsonIsLoaded(); + return Rush.__rushLibPackageJson!; + } + + 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); + } + } + + /** + * Assign the `RUSH_INVOKED_FOLDER` environment variable during startup. This is only applied when + * Rush is invoked via the CLI, not via the `@microsoft/rush-lib` automation API. + * + * @remarks + * Modifying the parent process's environment is not a good design. The better design is (1) to consolidate + * Rush's code paths that invoke scripts, and (2) to pass down the invoked folder with each code path, + * so that it can finally be applied in a centralized helper like `Utilities._createEnvironmentForRushCommand()`. + * 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; + } +} diff --git a/libraries/rush-lib/src/api/RushCommandLine.ts b/libraries/rush-lib/src/api/RushCommandLine.ts new file mode 100644 index 00000000000..34de4d115ea --- /dev/null +++ b/libraries/rush-lib/src/api/RushCommandLine.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 { CommandLineParameterKind } from '@rushstack/ts-command-line'; + +import { RushCommandLineParser } from '../cli/RushCommandLineParser'; + +/** + * Information about the available parameters associated with a Rush action + * + * @beta + */ +export interface IRushCommandLineParameter { + /** + * The corresponding string representation of CliParameterKind + */ + readonly kind: keyof typeof CommandLineParameterKind; + + /** + * The long name of the flag including double dashes, e.g. "--do-something" + */ + readonly longName: string; + + /** + * An optional short name for the flag including the dash, e.g. "-d" + */ + readonly shortName?: string; + + /** + * Documentation for the parameter that will be shown when invoking the tool with "--help" + */ + readonly description: string; + + /** + * If true, then an error occurs if the parameter was not included on the command-line. + */ + readonly required?: boolean; + + /** + * If provided, this parameter can also be provided by an environment variable with the specified name. + */ + readonly environmentVariable?: string; +} + +/** + * The full spec of an available Rush command line action + * + * @beta + */ +export interface IRushCommandLineAction { + actionName: string; + parameters: IRushCommandLineParameter[]; +} + +/** + * The full spec of a Rush CLI + * + * @beta + */ +export interface IRushCommandLineSpec { + actions: IRushCommandLineAction[]; +} + +const _commandLineSpecByWorkspaceFolder: Map = new Map(); + +/** + * Information about the available CLI commands + * + * @beta + */ +export class RushCommandLine { + public static getCliSpec(rushJsonFolder: string): IRushCommandLineSpec { + let result: IRushCommandLineSpec | undefined = _commandLineSpecByWorkspaceFolder.get(rushJsonFolder); + + if (!result) { + const commandLineParser: RushCommandLineParser = new RushCommandLineParser({ cwd: rushJsonFolder }); + + // extract the set of command line elements from the command line parser + const actions: IRushCommandLineAction[] = []; + for (const { actionName, parameters: rawParameters } of commandLineParser.actions) { + const parameters: IRushCommandLineParameter[] = []; + for (const { + kind: rawKind, + longName, + shortName, + description, + required, + environmentVariable + } of rawParameters) { + parameters.push({ + kind: CommandLineParameterKind[rawKind] as keyof typeof CommandLineParameterKind, + longName, + shortName, + description, + required, + environmentVariable + }); + } + + actions.push({ + actionName, + parameters + }); + } + + result = { actions }; + _commandLineSpecByWorkspaceFolder.set(rushJsonFolder, result); + } + + return result; + } +} diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts new file mode 100644 index 00000000000..c1398ea0622 --- /dev/null +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -0,0 +1,1601 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint max-lines: off */ + +import * as path from 'node:path'; + +import * as semver from 'semver'; +import { trueCasePathSync } from 'true-case-path'; + +import { + JsonFile, + JsonSchema, + Path, + FileSystem, + type PackageNameParser, + type FileSystemStats, + InternalError, + type JsonNull +} from '@rushstack/node-core-library'; +import { LookupByPath } from '@rushstack/lookup-by-path'; + +import { Rush } from './Rush'; +import { RushConfigurationProject, type IRushConfigurationProjectJson } from './RushConfigurationProject'; +import { RushConstants } from '../logic/RushConstants'; +import { ApprovedPackagesPolicy } from './ApprovedPackagesPolicy'; +import { EventHooks } from './EventHooks'; +import { VersionPolicyConfiguration } from './VersionPolicyConfiguration'; +import { EnvironmentConfiguration } from './EnvironmentConfiguration'; +import type { CommonVersionsConfiguration } from './CommonVersionsConfiguration'; +import { Utilities } from '../utilities/Utilities'; +import type { PackageManagerName, PackageManager } from './packageManager/PackageManager'; +import { NpmPackageManager } from './packageManager/NpmPackageManager'; +import { YarnPackageManager } from './packageManager/YarnPackageManager'; +import { PnpmPackageManager } from './packageManager/PnpmPackageManager'; +import { ExperimentsConfiguration } from './ExperimentsConfiguration'; +import { PackageNameParsers } from './PackageNameParsers'; +import type { RepoStateFile } from '../logic/RepoStateFile'; +import { RushPluginsConfiguration } from './RushPluginsConfiguration'; +import { type IPnpmOptionsJson, PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration'; +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'; +import { SubspacesConfiguration } from './SubspacesConfiguration'; +import { Subspace } from './Subspace'; + +const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0'; +const DEFAULT_BRANCH: string = 'main'; +const DEFAULT_REMOTE: string = 'origin'; + +/** + * A list of known config filenames that are expected to appear in the "./common/config/rush" folder. + * To avoid confusion/mistakes, any extra files will be reported as an error. + */ +const knownRushConfigFilenames: string[] = [ + '.npmrc-publish', + '.npmrc', + 'deploy.json', + RushConstants.artifactoryFilename, + RushConstants.browserApprovedPackagesFilename, + RushConstants.buildCacheFilename, + RushConstants.cobuildFilename, + RushConstants.commandLineFilename, + RushConstants.commonVersionsFilename, + RushConstants.customTipsFilename, + RushConstants.experimentsFilename, + RushConstants.nonbrowserApprovedPackagesFilename, + RushConstants.pinnedVersionsFilename, + RushConstants.repoStateFilename, + RushConstants.versionPoliciesFilename, + RushConstants.rushPluginsConfigFilename, + RushConstants.pnpmConfigFilename, + RushConstants.subspacesConfigFilename, + RushConstants.rushAlertsConfigFilename +]; + +/** + * Part of IRushConfigurationJson. + */ +export interface IApprovedPackagesPolicyJson { + reviewCategories?: string[]; + ignoredNpmScopes?: string[]; +} + +/** + * Part of IRushConfigurationJson. + */ +export interface IRushGitPolicyJson { + allowedEmailRegExps?: string[]; + sampleEmail?: string; + versionBumpCommitMessage?: string; + changeLogUpdateCommitMessage?: string; + changefilesCommitMessage?: string; + tagSeparator?: string; +} + +/** + * Part of IRushConfigurationJson. + * @beta + */ +export interface IEventHooksJson { + /** + * The list of scripts to run after every Rush build command finishes + */ + postRushBuild?: string[]; +} + +/** + * Part of IRushConfigurationJson. + */ +export interface IRushRepositoryJsonBase { + /** + * The default branch name. This tells "rush change" which remote branch to compare against. + */ + defaultBranch?: string; + + /** + * The default remote. This tells "rush change" which remote to compare against if the remote URL is not set + * or if a remote matching the provided remote URL is not found. + */ + defaultRemote?: string; +} + +export interface IRushRepositoryJsonSingleUrl extends IRushRepositoryJsonBase { + /** + * The remote url of the repository. If a value is provided, + * \"rush change\" will use it to find the right remote to compare against. + * + * @deprecated Use "urls" instead. + */ + url?: string; +} + +export interface IRushRepositoryJsonMultipleUrls extends IRushRepositoryJsonBase { + /** + * Remote url(s) of the repository. If a value is provided, \"rush change\" will + * use one of these to find the right remote to compare against. Specifying multiple URLs + * is useful if a GitHub repository is renamed or for `.visualstudio.com` versus + * `dev.azure.com/` URLs. + */ + urls?: string[]; +} + +export type IRushRepositoryJson = IRushRepositoryJsonSingleUrl | IRushRepositoryJsonMultipleUrls; + +/** + * Options defining an allowed variant as part of IRushConfigurationJson. + */ +export interface IRushVariantOptionsJson { + variantName: string; + description: string; +} + +/** + * This represents the JSON data structure for the "rush.json" configuration file. + * See rush.schema.json for documentation. + */ +export interface IRushConfigurationJson { + $schema: string; + npmVersion?: string; + pnpmVersion?: string; + yarnVersion?: string; + rushVersion: string; + repository?: IRushRepositoryJson; + nodeSupportedVersionRange?: string; + nodeSupportedVersionInstructions?: string; + suppressNodeLtsWarning?: boolean; + suppressRushIsPublicVersionCheck?: boolean; + projectFolderMinDepth?: number; + projectFolderMaxDepth?: number; + allowMostlyStandardPackageNames?: boolean; + approvedPackagesPolicy?: IApprovedPackagesPolicyJson; + gitPolicy?: IRushGitPolicyJson; + telemetryEnabled?: boolean; + allowedProjectTags?: string[]; + projects: IRushConfigurationProjectJson[]; + eventHooks?: IEventHooksJson; + hotfixChangeEnabled?: boolean; + npmOptions?: INpmOptionsJson; + pnpmOptions?: IPnpmOptionsJson; + yarnOptions?: IYarnOptionsJson; + ensureConsistentVersions?: boolean; + variants?: IRushVariantOptionsJson[]; +} + +/** + * This represents the JSON data structure for the "current-variant.json" data file. + */ +export interface ICurrentVariantJson { + variant: string | JsonNull; +} + +/** + * The filter parameters to search from all projects + */ +export interface IRushConfigurationProjectsFilter { + /** + * A string representation of the subspace to filter for + */ + subspace: string; +} + +/** + * Options for `RushConfiguration.tryFindRushJsonLocation`. + * @public + */ +export interface ITryFindRushJsonLocationOptions { + /** + * Whether to show verbose console messages. Defaults to false. + */ + showVerbose?: boolean; // Defaults to false (inverse of old `verbose` parameter) + + /** + * The folder path where the search will start. Defaults to the current working directory. + */ + startingFolder?: string; // Defaults to cwd +} + +/** + * 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>; + + /** + * @internal + */ + public _currentVariantJsonLoadingPromise: Promise | undefined; + + // Lazily loaded when the projects() getter is called. + private _projects: RushConfigurationProject[] | undefined; + + // Lazily loaded when the projectsByName() getter is called. + private _projectsByName: Map | undefined; + + // Lazily loaded when the projectsByTag() getter is called. + private _projectsByTag: ReadonlyMap> | undefined; + + // subspaceName -> subspace + private readonly _subspacesByName: Map; + private readonly _subspaces: Subspace[] = []; + + /** + * The name of the package manager being used to install dependencies + */ + public readonly packageManager!: PackageManagerName; + + /** + * If true, the repository is using PNPM as its package manager. + */ + public readonly isPnpm!: boolean; + + /** + * {@inheritdoc PackageManager} + * + * @privateremarks + * In the next major breaking API change, we will rename this property to "packageManager" and eliminate the + * old property with that name. + * + * @beta + */ + public readonly packageManagerWrapper: PackageManager; + + /** + * Gets the JSON data structure for the "rush.json" configuration file. + * + * @internal + */ + public readonly rushConfigurationJson: IRushConfigurationJson; + + /** + * The absolute path to the "rush.json" configuration file that was loaded to construct this object. + */ + public readonly rushJsonFile: string; + + /** + * The absolute path of the folder that contains rush.json for this project. + */ + public readonly rushJsonFolder: string; + + /** + * The folder that contains all change files. + */ + public readonly changesFolder: string; + + /** + * The fully resolved path for the "common" folder where Rush will store settings that + * affect all Rush projects. This is always a subfolder of the folder containing "rush.json". + * Example: `C:\MyRepo\common` + */ + public readonly commonFolder: string; + + /** + * The folder where Rush's additional config files are stored. This folder is always a + * subfolder called `config\rush` inside the common folder. (The `common\config` folder + * is reserved for configuration files used by other tools.) To avoid confusion or mistakes, + * Rush will report an error if this this folder contains any unrecognized files. + * + * Example: `C:\MyRepo\common\config\rush` + */ + public readonly commonRushConfigFolder: string; + + /** + * The folder where temporary files will be stored. This is always a subfolder called "temp" + * under the common folder. + * Example: `C:\MyRepo\common\temp` + */ + public readonly commonTempFolder: string; + + /** + * The folder where automation scripts are stored. This is always a subfolder called "scripts" + * under the common folder. + * Example: `C:\MyRepo\common\scripts` + */ + public readonly commonScriptsFolder: string; + + /** + * The local folder that will store the NPM package cache. Rush does not rely on the + * npm's default global cache folder, because npm's caching implementation does not + * reliably handle multiple processes. (For example, if a build box is running + * "rush install" simultaneously for two different working folders, it may fail randomly.) + * + * Example: `C:\MyRepo\common\temp\npm-cache` + */ + public readonly npmCacheFolder: string; + + /** + * The local folder where npm's temporary files will be written during installation. + * Rush does not rely on the global default folder, because it may be on a different + * hard disk. + * + * Example: `C:\MyRepo\common\temp\npm-tmp` + */ + public readonly npmTmpFolder: string; + + /** + * The local folder that will store the Yarn package cache. + * + * Example: `C:\MyRepo\common\temp\yarn-cache` + */ + public readonly yarnCacheFolder: string; + + /** + * The filename (without any path) of the shrinkwrap file that is used by the package manager. + * @remarks + * This property merely reports the filename; the file itself may not actually exist. + * Example: `npm-shrinkwrap.json` or `pnpm-lock.yaml` + */ + public readonly shrinkwrapFilename: string; + + /** + * The object that specifies subspace configurations if they are provided in the rush workspace. + * @beta + */ + public readonly subspacesConfiguration: SubspacesConfiguration | undefined; + + /** + * Returns true if subspaces.json is present with "subspacesEnabled=true". + */ + public readonly subspacesFeatureEnabled: boolean; + + /** + * The filename of the variant dependency data file. By default this is + * called 'current-variant.json' and resides in the Rush common folder. + * Its data structure is defined by ICurrentVariantJson. + * + * Example: `C:\MyRepo\common\temp\current-variant.json` + */ + public readonly currentVariantJsonFilePath: string; + + /** + * The version of the locally package manager tool. (Example: "1.2.3") + */ + public readonly packageManagerToolVersion: string; + + /** + * The absolute path to the locally package manager tool. If "rush install" has not + * been run, then this file may not exist yet. + * Example: `C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm` + */ + public readonly packageManagerToolFilename: string; + + /** + * The minimum allowable folder depth for the projectFolder field in the rush.json file. + * This setting provides a way for repository maintainers to discourage nesting of project folders + * that makes the directory tree more difficult to navigate. The default value is 2, + * which implements a standard 2-level hierarchy of `//package.json`. + */ + public readonly projectFolderMinDepth: number; + + /** + * The maximum allowable folder depth for the projectFolder field in the rush.json file. + * This setting provides a way for repository maintainers to discourage nesting of project folders + * that makes the directory tree more difficult to navigate. The default value is 2, + * which implements on a standard convention of `//package.json`. + */ + public readonly projectFolderMaxDepth: number; + + /** + * Today the npmjs.com registry enforces fairly strict naming rules for packages, but in the early + * days there was no standard and hardly any enforcement. A few large legacy projects are still using + * nonstandard package names, and private registries sometimes allow it. Set "allowMostlyStandardPackageNames" + * to true to relax Rush's enforcement of package names. This allows upper case letters and in the future may + * relax other rules, however we want to minimize these exceptions. Many popular tools use certain punctuation + * characters as delimiters, based on the assumption that they will never appear in a package name; thus if we relax + * the rules too much it is likely to cause very confusing malfunctions. + * + * The default value is false. + */ + public readonly allowMostlyStandardPackageNames: boolean; + + /** + * The "approvedPackagesPolicy" settings. + */ + public readonly approvedPackagesPolicy: ApprovedPackagesPolicy; + + /** + * [Part of the "gitPolicy" feature.] + * A list of regular expressions describing allowable email patterns for Git commits. + * They are case-insensitive anchored JavaScript RegExps. + * Example: `".*@example\.com"` + * This array will never be undefined. + */ + public readonly gitAllowedEmailRegExps: string[]; + + /** + * [Part of the "gitPolicy" feature.] + * An example valid email address that conforms to one of the allowedEmailRegExps. + * Example: `"foxtrot@example\.com"` + * This will never be undefined, and will always be nonempty if gitAllowedEmailRegExps is used. + */ + public readonly gitSampleEmail: string; + + /** + * [Part of the "gitPolicy" feature.] + * The commit message to use when committing changes during 'rush publish' + */ + public readonly gitVersionBumpCommitMessage: string | undefined; + + /** + * [Part of the "gitPolicy" feature.] + * The commit message to use when committing change log files 'rush version' + */ + public readonly gitChangeLogUpdateCommitMessage: string | undefined; + + /** + * [Part of the "gitPolicy" feature.] + * The commit message to use when committing change log files 'rush version' + */ + public readonly gitChangefilesCommitMessage: string | undefined; + + /** + * [Part of the "gitPolicy" feature.] + * The separator between package name and version in git tag. + */ + public readonly gitTagSeparator: string | undefined; + + /** + * [Part of the "hotfixChange" feature.] + * Enables creating hotfix changes + */ + public readonly hotfixChangeEnabled: boolean; + + /** + * Remote URL(s) of the repository. If a value is provided, \"rush change\" will + * use one of these to find the right remote to compare against. Specifying multiple URLs + * is useful if a GitHub repository is renamed or for `.visualstudio.com` versus + * `dev.azure.com/` URLs. + */ + public readonly repositoryUrls: string[]; + + /** + * The default branch name. This tells "rush change" which remote branch to compare against. + */ + public readonly repositoryDefaultBranch: string; + + /** + * The default remote. This tells "rush change" which remote to compare against if the remote URL is not set + * or if a remote matching the provided remote URL is not found. + */ + public readonly repositoryDefaultRemote: string; + + /** + * Odd-numbered major versions of Node.js are experimental. Even-numbered releases + * spend six months in a stabilization period before the first Long Term Support (LTS) version. + * For example, 8.9.0 was the first LTS version of Node.js 8. Pre-LTS versions are not recommended + * for production usage because they frequently have bugs. They may cause Rush itself + * to malfunction. + * + * Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing + * pre-LTS versions in preparation for supporting the first LTS version, you can use this setting + * to disable Rush's warning. + */ + public readonly suppressNodeLtsWarning: boolean; + + /** + * The raw value of `ensureConsistentVersions` from the `rush.json` file. + * + * @internal + */ + public readonly _ensureConsistentVersionsJsonValue: boolean | undefined; + + /** + * If true, then consistent version specifiers for dependencies will be enforced. + * I.e. "rush check" is run before some commands. + * + * @deprecated + * This setting was moved from `rush.json` to `common-versions.json`. + * Read it using {@link Subspace.shouldEnsureConsistentVersions} instead. + */ + public readonly ensureConsistentVersions: boolean; + + /** + * Indicates whether telemetry collection is enabled for Rush runs. + * @beta + */ + public readonly telemetryEnabled: boolean; + + /** + * {@inheritDoc NpmOptionsConfiguration} + */ + public readonly npmOptions: NpmOptionsConfiguration; + + /** + * {@inheritDoc PnpmOptionsConfiguration} + */ + public readonly pnpmOptions: PnpmOptionsConfiguration; + + /** + * {@inheritDoc YarnOptionsConfiguration} + */ + public readonly yarnOptions: YarnOptionsConfiguration; + + /** + * The configuration options used by the current package manager. + * @remarks + * For package manager specific variants, reference {@link RushConfiguration.npmOptions | npmOptions}, + * {@link RushConfiguration.pnpmOptions | pnpmOptions}, or {@link RushConfiguration.yarnOptions | yarnOptions}. + */ + public readonly packageManagerOptions!: PackageManagerOptionsConfigurationBase; + + /** + * The rush hooks. It allows customized scripts to run at the specified point. + * @beta + */ + public readonly eventHooks: EventHooks; + + /** + * The rush hooks. It allows customized scripts to run at the specified point. + */ + public readonly packageNameParser: PackageNameParser; + + /** + * @beta + */ + public readonly versionPolicyConfiguration: VersionPolicyConfiguration; + + /** + * @beta + */ + public readonly versionPolicyConfigurationFilePath: string; + + /** + * Accesses the custom-tips.json configuration. + * @beta + */ + public readonly customTipsConfiguration: CustomTipsConfiguration; + + /** + * The absolute path to the custom tips configuration file. + * @beta + */ + public readonly customTipsConfigurationFilePath: string; + + /** + * This configuration object contains settings repo maintainers have specified to enable + * and disable experimental Rush features. + * + * @beta + */ + public readonly experimentsConfiguration: ExperimentsConfiguration; + + /** + * @internal + */ + public readonly _rushPluginsConfiguration: RushPluginsConfiguration; + + /** + * The variants specified in the rush.json configuration file. + * + * @beta + */ + public readonly variants: ReadonlySet; + + /** + * Use RushConfiguration.loadFromConfigurationFile() or Use RushConfiguration.loadFromDefaultLocation() + * instead. + */ + private constructor(rushConfigurationJson: IRushConfigurationJson, rushJsonFilename: string) { + this.rushConfigurationJson = rushConfigurationJson; + EnvironmentConfiguration.validate(); + + if (rushConfigurationJson.nodeSupportedVersionRange) { + if (!semver.validRange(rushConfigurationJson.nodeSupportedVersionRange)) { + throw new Error( + 'Error parsing the node-semver expression in the "nodeSupportedVersionRange"' + + ` field from ${RushConstants.rushJsonFilename}: "${rushConfigurationJson.nodeSupportedVersionRange}"` + ); + } + if (!semver.satisfies(process.version, rushConfigurationJson.nodeSupportedVersionRange)) { + let message: string = + `Your dev environment is running Node.js version ${process.version} which does` + + ` not meet the requirements for building this repository. (The ${RushConstants.rushJsonFilename} configuration` + + ` requires nodeSupportedVersionRange="${rushConfigurationJson.nodeSupportedVersionRange}")`; + + if (rushConfigurationJson.nodeSupportedVersionInstructions) { + message += '\n\n' + rushConfigurationJson.nodeSupportedVersionInstructions; + } + + if (EnvironmentConfiguration.allowUnsupportedNodeVersion) { + // eslint-disable-next-line no-console + console.warn(message); + } else { + throw new Error(message); + } + } + } + + this.rushJsonFile = rushJsonFilename; + this.rushJsonFolder = path.dirname(rushJsonFilename); + + this.commonFolder = path.resolve(path.join(this.rushJsonFolder, RushConstants.commonFolderName)); + + this.commonRushConfigFolder = path.join(this.commonFolder, 'config', 'rush'); + + this.commonTempFolder = + EnvironmentConfiguration.rushTempFolderOverride || + path.join(this.commonFolder, RushConstants.rushTempFolderName); + + this.commonScriptsFolder = path.join(this.commonFolder, 'scripts'); + + this.npmCacheFolder = path.resolve(path.join(this.commonTempFolder, 'npm-cache')); + this.npmTmpFolder = path.resolve(path.join(this.commonTempFolder, 'npm-tmp')); + this.yarnCacheFolder = path.resolve(path.join(this.commonTempFolder, 'yarn-cache')); + + this.changesFolder = path.join(this.commonFolder, RushConstants.changeFilesFolderName); + + this.currentVariantJsonFilePath = path.join(this.commonTempFolder, RushConstants.currentVariantsFilename); + + this.suppressNodeLtsWarning = !!rushConfigurationJson.suppressNodeLtsWarning; + + this._ensureConsistentVersionsJsonValue = rushConfigurationJson.ensureConsistentVersions; + this.ensureConsistentVersions = !!rushConfigurationJson.ensureConsistentVersions; + + // Try getting a subspace configuration + this.subspacesConfiguration = SubspacesConfiguration.tryLoadFromDefaultLocation(this); + this.subspacesFeatureEnabled = !!this.subspacesConfiguration?.subspacesEnabled; + + this._subspacesByName = new Map(); + + const experimentsConfigFile: string = path.join( + this.commonRushConfigFolder, + RushConstants.experimentsFilename + ); + this.experimentsConfiguration = new ExperimentsConfiguration(experimentsConfigFile); + + const rushPluginsConfigFilename: string = path.join( + this.commonRushConfigFolder, + RushConstants.rushPluginsConfigFilename + ); + this._rushPluginsConfiguration = new RushPluginsConfiguration(rushPluginsConfigFilename); + + this.npmOptions = new NpmOptionsConfiguration(rushConfigurationJson.npmOptions || {}); + this.yarnOptions = new YarnOptionsConfiguration(rushConfigurationJson.yarnOptions || {}); + try { + this.pnpmOptions = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${this.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}`, + this.commonTempFolder + ); + if (rushConfigurationJson.pnpmOptions) { + throw new Error( + 'Because the new config file "common/config/rush/pnpm-config.json" is being used, ' + + `you must remove the old setting "pnpmOptions" from ${RushConstants.rushJsonFilename}` + ); + } + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + this.pnpmOptions = PnpmOptionsConfiguration.loadFromJsonObject( + rushConfigurationJson.pnpmOptions || {}, + this.commonTempFolder + ); + } else { + throw error; + } + } + + // TODO: Add an actual "packageManager" field in rush.json + const packageManagerFields: string[] = []; + + this.isPnpm = false; + if (rushConfigurationJson.npmVersion) { + this.packageManager = 'npm'; + this.packageManagerOptions = this.npmOptions; + packageManagerFields.push('npmVersion'); + } + + if (rushConfigurationJson.pnpmVersion) { + this.packageManager = 'pnpm'; + this.isPnpm = true; + this.packageManagerOptions = this.pnpmOptions; + packageManagerFields.push('pnpmVersion'); + } + + if (rushConfigurationJson.yarnVersion) { + this.packageManager = 'yarn'; + this.packageManagerOptions = this.yarnOptions; + packageManagerFields.push('yarnVersion'); + } + + if (packageManagerFields.length === 0) { + throw new Error( + `The ${RushConstants.rushJsonFilename} configuration must specify one of: npmVersion, pnpmVersion, or yarnVersion` + ); + } + + if (packageManagerFields.length > 1) { + throw new Error( + `The ${RushConstants.rushJsonFilename} configuration cannot specify both ${packageManagerFields[0]}` + + ` and ${packageManagerFields[1]} ` + ); + } + + if (this.packageManager === 'npm') { + this.packageManagerToolVersion = rushConfigurationJson.npmVersion!; + this.packageManagerWrapper = new NpmPackageManager(this.packageManagerToolVersion); + } else if (this.packageManager === 'pnpm') { + this.packageManagerToolVersion = rushConfigurationJson.pnpmVersion!; + this.packageManagerWrapper = new PnpmPackageManager(this.packageManagerToolVersion); + } else { + this.packageManagerToolVersion = rushConfigurationJson.yarnVersion!; + this.packageManagerWrapper = new YarnPackageManager(this.packageManagerToolVersion); + } + + this.shrinkwrapFilename = this.packageManagerWrapper.shrinkwrapFilename; + + this.packageManagerToolFilename = path.resolve( + path.join( + this.commonTempFolder, + `${this.packageManager}-local`, + 'node_modules', + '.bin', + `${this.packageManager}` + ) + ); + + RushConfiguration._validateCommonRushConfigFolder( + this.commonRushConfigFolder, + this.packageManagerWrapper, + this.experimentsConfiguration, + this.subspacesFeatureEnabled + ); + + this.projectFolderMinDepth = + rushConfigurationJson.projectFolderMinDepth !== undefined + ? rushConfigurationJson.projectFolderMinDepth + : 1; + if (this.projectFolderMinDepth < 1) { + throw new Error('Invalid projectFolderMinDepth; the minimum possible value is 1'); + } + + this.projectFolderMaxDepth = + rushConfigurationJson.projectFolderMaxDepth !== undefined + ? rushConfigurationJson.projectFolderMaxDepth + : 2; + if (this.projectFolderMaxDepth < this.projectFolderMinDepth) { + throw new Error('The projectFolderMaxDepth cannot be smaller than the projectFolderMinDepth'); + } + + this.allowMostlyStandardPackageNames = !!rushConfigurationJson.allowMostlyStandardPackageNames; + this.packageNameParser = this.allowMostlyStandardPackageNames + ? PackageNameParsers.mostlyStandard + : PackageNameParsers.rushDefault; + + this.approvedPackagesPolicy = new ApprovedPackagesPolicy(this, rushConfigurationJson); + + this.gitAllowedEmailRegExps = []; + this.gitSampleEmail = ''; + if (rushConfigurationJson.gitPolicy) { + if (rushConfigurationJson.gitPolicy.sampleEmail) { + this.gitSampleEmail = rushConfigurationJson.gitPolicy.sampleEmail; + } + + if (rushConfigurationJson.gitPolicy.allowedEmailRegExps) { + this.gitAllowedEmailRegExps = rushConfigurationJson.gitPolicy.allowedEmailRegExps; + + if (this.gitSampleEmail.trim().length < 1) { + throw new Error( + `The ${RushConstants.rushJsonFilename} file is missing the "sampleEmail" option, ` + + 'which is required when using "allowedEmailRegExps"' + ); + } + } + + if (rushConfigurationJson.gitPolicy.versionBumpCommitMessage) { + this.gitVersionBumpCommitMessage = rushConfigurationJson.gitPolicy.versionBumpCommitMessage; + } + + if (rushConfigurationJson.gitPolicy.changeLogUpdateCommitMessage) { + this.gitChangeLogUpdateCommitMessage = rushConfigurationJson.gitPolicy.changeLogUpdateCommitMessage; + } + + if (rushConfigurationJson.gitPolicy.changefilesCommitMessage) { + this.gitChangefilesCommitMessage = rushConfigurationJson.gitPolicy.changefilesCommitMessage; + } + + if (rushConfigurationJson.gitPolicy.tagSeparator) { + this.gitTagSeparator = rushConfigurationJson.gitPolicy.tagSeparator; + } + } + + this.hotfixChangeEnabled = false; + if (rushConfigurationJson.hotfixChangeEnabled) { + this.hotfixChangeEnabled = rushConfigurationJson.hotfixChangeEnabled; + } + + if (!rushConfigurationJson.repository) { + rushConfigurationJson.repository = {}; + } + + this.repositoryDefaultBranch = rushConfigurationJson.repository.defaultBranch || DEFAULT_BRANCH; + this.repositoryDefaultRemote = rushConfigurationJson.repository.defaultRemote || DEFAULT_REMOTE; + const repositoryFieldWithMultipleUrls: IRushRepositoryJsonMultipleUrls = + rushConfigurationJson.repository as IRushRepositoryJsonMultipleUrls; + const repositoryFieldWithSingleUrl: IRushRepositoryJsonSingleUrl = + rushConfigurationJson.repository as IRushRepositoryJsonSingleUrl; + if (repositoryFieldWithMultipleUrls.urls) { + if (repositoryFieldWithSingleUrl.url) { + throw new Error("The 'repository.url' field cannot be used when 'repository.urls' is present"); + } + + this.repositoryUrls = repositoryFieldWithMultipleUrls.urls; + } else if (repositoryFieldWithSingleUrl.url) { + this.repositoryUrls = [repositoryFieldWithSingleUrl.url]; + } else { + this.repositoryUrls = []; + } + + this.telemetryEnabled = !!rushConfigurationJson.telemetryEnabled; + this.eventHooks = new EventHooks(rushConfigurationJson.eventHooks || {}); + + this.versionPolicyConfigurationFilePath = path.join( + this.commonRushConfigFolder, + RushConstants.versionPoliciesFilename + ); + this.versionPolicyConfiguration = new VersionPolicyConfiguration(this.versionPolicyConfigurationFilePath); + + this.customTipsConfigurationFilePath = path.join( + this.commonRushConfigFolder, + RushConstants.customTipsFilename + ); + this.customTipsConfiguration = new CustomTipsConfiguration(this.customTipsConfigurationFilePath); + + const variants: Set = new Set(); + for (const variantOptions of rushConfigurationJson.variants ?? []) { + const { variantName } = variantOptions; + + if (variants.has(variantName)) { + throw new Error(`Duplicate variant named '${variantName}' specified in configuration.`); + } + + variants.add(variantName); + } + + this.variants = variants; + + this._pathTrees = new Map(); + } + + private _initializeAndValidateLocalProjects(): void { + this._projects = []; + this._projectsByName = new Map(); + this._subspacesByName.clear(); + this._subspaces.length = 0; + + // Build the subspaces map + const subspaceNames: string[] = []; + let splitWorkspaceCompatibility: boolean = false; + if (this.subspacesConfiguration?.subspacesEnabled) { + splitWorkspaceCompatibility = this.subspacesConfiguration.splitWorkspaceCompatibility; + + subspaceNames.push(...this.subspacesConfiguration.subspaceNames); + } + if (subspaceNames.indexOf(RushConstants.defaultSubspaceName) < 0) { + subspaceNames.push(RushConstants.defaultSubspaceName); + } + + // Sort the subspaces in alphabetical order. This ensures that they are processed + // in a deterministic order by the various Rush algorithms. + subspaceNames.sort(); + for (const subspaceName of subspaceNames) { + const subspace: Subspace = new Subspace({ + subspaceName, + rushConfiguration: this, + splitWorkspaceCompatibility + }); + this._subspacesByName.set(subspaceName, subspace); + this._subspaces.push(subspace); + } + const defaultSubspace: Subspace | undefined = this._subspacesByName.get( + RushConstants.defaultSubspaceName + ); + if (!defaultSubspace) { + throw new InternalError('The default subspace was not created'); + } + + // Sort the projects array in alphabetical order. This ensures that the packages + // are processed in a deterministic order by the various Rush algorithms. + const sortedProjectJsons: IRushConfigurationProjectJson[] = this.rushConfigurationJson.projects.slice(0); + sortedProjectJsons.sort((a: IRushConfigurationProjectJson, b: IRushConfigurationProjectJson) => + a.packageName.localeCompare(b.packageName) + ); + + const allowedProjectTags: Set | undefined = this.rushConfigurationJson.allowedProjectTags + ? new Set(this.rushConfigurationJson.allowedProjectTags) + : undefined; + 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 + ); + + let subspace: Subspace | undefined = undefined; + if (this.subspacesFeatureEnabled) { + if (projectJson.subspaceName) { + subspace = this._subspacesByName.get(projectJson.subspaceName); + if (subspace === undefined) { + throw new Error( + `The project "${projectJson.packageName}" in ${RushConstants.rushJsonFilename} references` + + ` a nonexistent subspace "${projectJson.subspaceName}"` + ); + } + } + } + if (subspace === undefined) { + subspace = defaultSubspace; + } + + const project: RushConfigurationProject = new RushConfigurationProject({ + projectJson, + rushConfiguration: this, + tempProjectName, + allowedProjectTags, + subspace + }); + subspace._addProject(project); + + this._projects.push(project); + if (this._projectsByName.has(project.packageName)) { + throw new Error( + `The project name "${project.packageName}" was specified more than once` + + ` in the ${RushConstants.rushJsonFilename} configuration file.` + ); + } + this._projectsByName.set(project.packageName, project); + } + + for (const project of this._projects) { + project.decoupledLocalDependencies.forEach((decoupledLocalDependency: string) => { + if (!this.getProjectByName(decoupledLocalDependency)) { + throw new Error( + `In ${RushConstants.rushJsonFilename}, the "${decoupledLocalDependency}" project does not exist,` + + ` but was referenced by the decoupledLocalDependencies (previously cyclicDependencyProjects) for ${project.packageName}` + ); + } + }); + this.versionPolicyConfiguration.validate(this.projectsByName); + + // Consumer relationships will be established the first time one is requested + } + } + + /** + * Loads the configuration data from an Rush.json configuration file and returns + * an RushConfiguration object. + */ + public static loadFromConfigurationFile(rushJsonFilename: string): RushConfiguration { + let resolvedRushJsonFilename: string = path.resolve(rushJsonFilename); + // Load the rush.json before we fix the casing. If the case is wrong on a case-sensitive filesystem, + // the next line show throw. + const rushConfigurationJson: IRushConfigurationJson = JsonFile.load(resolvedRushJsonFilename); + + try { + resolvedRushJsonFilename = trueCasePathSync(resolvedRushJsonFilename); + } catch (error) { + /* ignore errors from true-case-path */ + } + + // Check the Rush version *before* we validate the schema, since if the version is outdated + // then the schema may have changed. This should no longer be a problem after Rush 4.0 and the C2R wrapper, + // but we'll validate anyway. + const expectedRushVersion: string = rushConfigurationJson.rushVersion; + + const rushJsonBaseName: string = path.basename(resolvedRushJsonFilename); + + // If the version is missing or malformed, fall through and let the schema handle it. + if (expectedRushVersion && semver.valid(expectedRushVersion)) { + // Make sure the requested version isn't too old + if (semver.lt(expectedRushVersion, MINIMUM_SUPPORTED_RUSH_JSON_VERSION)) { + throw new Error( + `${rushJsonBaseName} is version ${expectedRushVersion}, which is too old for this tool. ` + + `The minimum supported version is ${MINIMUM_SUPPORTED_RUSH_JSON_VERSION}.` + ); + } + + // Make sure the requested version isn't too new. + // + // If the major/minor versions are the same, then we consider the file to be compatible. + // This is somewhat lax, e.g. "5.0.2-dev.3" will be assumed to be loadable by rush-lib 5.0.0. + // + // IMPORTANT: Whenever a breaking change is introduced for one of the config files, we must + // increment the minor version number for Rush. + if ( + semver.major(Rush.version) !== semver.major(expectedRushVersion) || + semver.minor(Rush.version) !== semver.minor(expectedRushVersion) + ) { + // If the major/minor are different, then make sure it's an older version. + if (semver.lt(Rush.version, expectedRushVersion)) { + throw new Error( + `Unable to load ${rushJsonBaseName} because its RushVersion is` + + ` ${rushConfigurationJson.rushVersion}, whereas @microsoft/rush-lib is version ${Rush.version}.` + + ` Consider upgrading the library.` + ); + } + } + } + + RushConfiguration._jsonSchema.validateObject(rushConfigurationJson, resolvedRushJsonFilename); + + return new RushConfiguration(rushConfigurationJson, resolvedRushJsonFilename); + } + + public static tryLoadFromDefaultLocation( + options?: ITryFindRushJsonLocationOptions + ): RushConfiguration | undefined { + const rushJsonLocation: string | undefined = RushConfiguration.tryFindRushJsonLocation(options); + if (rushJsonLocation) { + return RushConfiguration.loadFromConfigurationFile(rushJsonLocation); + } + } + + public static loadFromDefaultLocation(options?: ITryFindRushJsonLocationOptions): RushConfiguration { + const rushConfiguration: RushConfiguration | undefined = + RushConfiguration.tryLoadFromDefaultLocation(options); + + if (rushConfiguration) { + return rushConfiguration; + } else { + throw Utilities.getRushConfigNotFoundError(); + } + } + + /** + * Find the rush.json location and return the path, or undefined if a rush.json can't be found. + * + * @privateRemarks + * Keep this in sync with `findRushJsonLocation` in `rush-sdk/src/index.ts`. + */ + public static tryFindRushJsonLocation(options?: ITryFindRushJsonLocationOptions): string | undefined { + const optionsIn: ITryFindRushJsonLocationOptions = options || {}; + const verbose: boolean = optionsIn.showVerbose || false; + let currentFolder: string = optionsIn.startingFolder || process.cwd(); + let parentFolder: string = path.dirname(currentFolder); + + // look upwards at parent folders until we find a folder containing rush.json, + // or we reach the root directory without finding a rush.json file + while (parentFolder && parentFolder !== currentFolder) { + const rushJsonFilename: string = path.join(currentFolder, RushConstants.rushJsonFilename); + if (FileSystem.exists(rushJsonFilename)) { + if (currentFolder !== optionsIn.startingFolder && verbose) { + // eslint-disable-next-line no-console + console.log('Found configuration in ' + rushJsonFilename); + } + + if (verbose) { + // eslint-disable-next-line no-console + console.log(''); + } + + return rushJsonFilename; + } + currentFolder = parentFolder; + parentFolder = path.dirname(currentFolder); + } + + // no match + 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` + */ + public get commonAutoinstallersFolder(): string { + return path.join(this.commonFolder, 'autoinstallers'); + } + + /** + * The folder where rush-plugin options json files are stored. + * Example: `C:\MyRepo\common\config\rush-plugins` + */ + public get rushPluginOptionsFolder(): string { + return path.join(this.commonFolder, 'config', 'rush-plugins'); + } + + /** + * The full path of the temporary shrinkwrap file that is used during "rush install". + * This file may get rewritten by the package manager during installation. + * @remarks + * This property merely reports the filename; the file itself may not actually exist. + * Example: `C:\MyRepo\common\temp\npm-shrinkwrap.json` or `C:\MyRepo\common\temp\pnpm-lock.yaml` + * + * @deprecated Introduced with subspaces is subspace specific tempShrinkwrapFilename accessible from the Subspace class. + */ + public get tempShrinkwrapFilename(): string { + if (this.subspacesFeatureEnabled) { + throw new Error( + 'tempShrinkwrapFilename() is not available when using subspaces. Use the subspace specific temp shrinkwrap filename.' + ); + } + return path.join(this.commonTempFolder, this.shrinkwrapFilename); + } + + /** + * The full path of a backup copy of tempShrinkwrapFilename. This backup copy is made + * before installation begins, and can be compared to determine how the package manager + * modified tempShrinkwrapFilename. + * @remarks + * This property merely reports the filename; the file itself may not actually exist. + * Example: `C:\MyRepo\common\temp\npm-shrinkwrap-preinstall.json` + * or `C:\MyRepo\common\temp\pnpm-lock-preinstall.yaml` + * + * @deprecated Introduced with subspaces is subspace specific tempShrinkwrapPreinstallFilename accessible from the Subspace class. + */ + public get tempShrinkwrapPreinstallFilename(): string { + if (this.subspacesFeatureEnabled) { + throw new Error( + 'tempShrinkwrapPreinstallFilename() is not available when using subspaces. Use the subspace specific temp shrinkwrap preinstall filename.' + ); + } + const parsedPath: path.ParsedPath = path.parse(this.tempShrinkwrapFilename); + return path.join(parsedPath.dir, parsedPath.name + '-preinstall' + parsedPath.ext); + } + + /** + * Returns an English phrase such as "shrinkwrap file" that can be used in logging messages + * to refer to the shrinkwrap file using appropriate terminology for the currently selected + * package manager. + */ + public get shrinkwrapFilePhrase(): string { + return `shrinkwrap file (${this.shrinkwrapFilename})`; + } + + /** + * The filename of the build dependency data file. By default this is + * called 'rush-link.json' resides in the Rush common folder. + * Its data structure is defined by IRushLinkJson. + * + * Example: `C:\MyRepo\common\temp\rush-link.json` + * + * @deprecated The "rush-link.json" file was removed in Rush 5.30.0. + * Use `RushConfigurationProject.localDependencyProjects` instead. + */ + public get rushLinkJsonFilename(): string { + throw new Error( + 'The "rush-link.json" file was removed in Rush 5.30.0. Use ' + + 'RushConfigurationProject.localDependencyProjects instead.' + ); + } + + /** + * The default fully-qualified git remote branch of the repository. This helps "rush change" find the right branch to compare against. + */ + public get repositoryDefaultFullyQualifiedRemoteBranch(): string { + return `${this.repositoryDefaultRemote}/${this.repositoryDefaultBranch}`; + } + + public get projects(): RushConfigurationProject[] { + if (!this._projects) { + this._initializeAndValidateLocalProjects(); + } + + return this._projects!; + } + + /** + * @beta + */ + public get defaultSubspace(): Subspace { + // TODO: Enable the default subspace to be obtained without initializing the full set of all projects + if (!this._projects) { + this._initializeAndValidateLocalProjects(); + } + const defaultSubspace: Subspace | undefined = this.tryGetSubspace(RushConstants.defaultSubspaceName); + if (!defaultSubspace) { + throw new InternalError('Default subspace was not created'); + } + return defaultSubspace; + } + + /** + * A list of all the available subspaces in this workspace. + * @beta + */ + public get subspaces(): readonly Subspace[] { + if (!this._projects) { + this._initializeAndValidateLocalProjects(); + } + return this._subspaces; + } + + /** + * @beta + */ + public tryGetSubspace(subspaceName: string): Subspace | undefined { + if (!this._projects) { + this._initializeAndValidateLocalProjects(); + } + const subspace: Subspace | undefined = this._subspacesByName.get(subspaceName); + if (!subspace) { + // If the name is not even valid, that is more important information than if the subspace doesn't exist + SubspacesConfiguration.requireValidSubspaceName( + subspaceName, + this.subspacesConfiguration?.splitWorkspaceCompatibility + ); + } + return subspace; + } + + /** + * @beta + */ + public getSubspace(subspaceName: string): Subspace { + const subspace: Subspace | undefined = this.tryGetSubspace(subspaceName); + if (!subspace) { + throw new Error(`The specified subspace "${subspaceName}" does not exist`); + } + return subspace; + } + + /** + * Returns the set of subspaces that the given projects belong to + * @beta + */ + public getSubspacesForProjects(projects: Iterable): ReadonlySet { + if (!this._projects) { + this._initializeAndValidateLocalProjects(); + } + + const subspaceSet: Set = new Set(); + for (const project of projects) { + subspaceSet.add(project.subspace); + } + + return subspaceSet; + } + + /** + * @beta + */ + public get projectsByName(): ReadonlyMap { + if (!this._projectsByName) { + this._initializeAndValidateLocalProjects(); + } + + return this._projectsByName!; + } + + /** + * Obtains the mapping from custom tags to projects. + * @beta + */ + public get projectsByTag(): ReadonlyMap> { + if (!this._projectsByTag) { + const projectsByTag: Map> = new Map(); + for (const project of this.projects) { + for (const tag of project.tags) { + let collection: Set | undefined = projectsByTag.get(tag); + if (!collection) { + projectsByTag.set(tag, (collection = new Set())); + } + collection.add(project); + } + } + this._projectsByTag = projectsByTag; + } + return this._projectsByTag; + } + + /** + * Settings from the common-versions.json config file. + * @remarks + * If the common-versions.json file is missing, this property will not be undefined. + * Instead it will be initialized in an empty state, and calling CommonVersionsConfiguration.save() + * will create the file. + * + * @deprecated Use `getCommonVersions` instead, which gets the correct common version data + * for a given active variant. + */ + public get commonVersions(): CommonVersionsConfiguration { + return this.defaultSubspace.getCommonVersions(undefined); + } + + /** + * Gets the currently-installed variant, if an installation has occurred. + * For Rush operations which do not take a --variant parameter, this method + * determines which variant, if any, was last specified when performing "rush install" + * or "rush update". + */ + public async getCurrentlyInstalledVariantAsync(): Promise { + if (!this._currentVariantJsonLoadingPromise) { + this._currentVariantJsonLoadingPromise = this._loadCurrentVariantJsonAsync(); + } + + return (await this._currentVariantJsonLoadingPromise)?.variant ?? undefined; + } + + /** + * @deprecated Use {@link Subspace.getCommonVersionsFilePath} instead + */ + public getCommonVersionsFilePath(subspace?: Subspace, variant?: string): string { + return (subspace ?? this.defaultSubspace).getCommonVersionsFilePath(variant); + } + + /** + * @deprecated Use {@link Subspace.getCommonVersions} instead + */ + public getCommonVersions(subspace?: Subspace, variant?: string): CommonVersionsConfiguration { + return (subspace ?? this.defaultSubspace).getCommonVersions(variant); + } + + /** + * Returns a map of all direct dependencies that only have a single semantic version specifier. + * + * @param subspace - The subspace to use + * @param variant - The name of the current variant in use by the active command. + * + * @returns A map of dependency name --\> version specifier for implicitly preferred versions. + */ + public getImplicitlyPreferredVersions(subspace?: Subspace, variant?: string): Map { + // TODO: During the next major release of Rush, replace this `require` call with a dynamic import, and + // change this function to be async. + const DependencyAnalyzerModule: typeof DependencyAnalyzerModuleType = require('../logic/DependencyAnalyzer'); + const dependencyAnalyzer: DependencyAnalyzerModuleType.DependencyAnalyzer = + DependencyAnalyzerModule.DependencyAnalyzer.forRushConfiguration(this); + const dependencyAnalysis: DependencyAnalyzerModuleType.IDependencyAnalysis = + dependencyAnalyzer.getAnalysis(subspace, variant, false); + return dependencyAnalysis.implicitlyPreferredVersionByPackageName; + } + + /** + * @deprecated Use {@link Subspace.getRepoStateFilePath} instead + */ + public getRepoStateFilePath(subspace?: Subspace): string { + return (subspace ?? this.defaultSubspace).getRepoStateFilePath(); + } + + /** + * @deprecated Use {@link Subspace.getRepoState} instead + */ + public getRepoState(subspace?: Subspace): RepoStateFile { + return (subspace ?? this.defaultSubspace).getRepoState(); + } + + /** + * @deprecated Use {@link Subspace.getCommittedShrinkwrapFilePath} instead + */ + public getCommittedShrinkwrapFilename(subspace?: Subspace, variant?: string): string { + return (subspace ?? this.defaultSubspace).getCommittedShrinkwrapFilePath(variant); + } + + /** + * @deprecated Use {@link Subspace.getPnpmfilePath} instead + */ + public getPnpmfilePath(subspace?: Subspace, variant?: string): string { + return (subspace ?? this.defaultSubspace).getPnpmfilePath(variant); + } + + /** + * Looks up a project in the projectsByName map. If the project is not found, + * then undefined is returned. + */ + public getProjectByName(projectName: string): RushConfigurationProject | undefined { + return this.projectsByName.get(projectName); + } + + /** + * This is used e.g. by command-line interfaces such as "rush build --to example". + * If "example" is not a project name, then it also looks for a scoped name + * like `@something/example`. If exactly one project matches this heuristic, it + * is returned. Otherwise, undefined is returned. + */ + public findProjectByShorthandName(shorthandProjectName: string): RushConfigurationProject | undefined { + // Is there an exact match? + let result: RushConfigurationProject | undefined = this.projectsByName.get(shorthandProjectName); + if (result) { + return result; + } + + // Is there an approximate match? + for (const project of this.projects) { + if (this.packageNameParser.getUnscopedName(project.packageName) === shorthandProjectName) { + if (result) { + // Ambiguous -- there is more than one match + return undefined; + } else { + result = project; + } + } + } + return result; + } + + /** + * Looks up a project by its RushConfigurationProject.tempProjectName field. + * @returns The found project, or undefined if no match was found. + */ + public findProjectByTempName(tempProjectName: string): RushConfigurationProject | undefined { + // Is there an approximate match? + for (const project of this.projects) { + if (project.tempProjectName === tempProjectName) { + return project; + } + } + return undefined; + } + + /** + * @returns An optimized lookup engine to find a project by its path relative to the specified root. + * @beta + */ + public getProjectLookupForRoot(rootPath: string): LookupByPath { + let pathTree: LookupByPath | undefined = this._pathTrees.get(rootPath); + if (!pathTree) { + this._pathTrees.set(rootPath, (pathTree = new LookupByPath())); + for (const project of this.projects) { + const relativePath: string = path.relative(rootPath, project.projectFolder); + pathTree.setItemFromSegments(LookupByPath.iteratePathSegments(relativePath, path.sep), project); + } + } + return pathTree; + } + + /** + * Returns the project for which the specified path is underneath that project's folder. + * If the path is not under any project's folder, returns undefined. + */ + public tryGetProjectForPath(currentFolderPath: string): RushConfigurationProject | undefined { + // TODO: Improve the method in which a package is found, perhaps without having to sort / loop though the entire package list + const resolvedPath: string = path.resolve(currentFolderPath); + const sortedProjects: RushConfigurationProject[] = this.projects.sort( + (a, b) => b.projectFolder.length - a.projectFolder.length + ); + for (const project of sortedProjects) { + if (Path.isUnderOrEqual(resolvedPath, project.projectFolder)) { + return project; + } + } + return undefined; + } + + private async _loadCurrentVariantJsonAsync(): Promise { + try { + return await JsonFile.loadAsync(this.currentVariantJsonFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + } +} diff --git a/libraries/rush-lib/src/api/RushConfigurationProject.ts b/libraries/rush-lib/src/api/RushConfigurationProject.ts new file mode 100644 index 00000000000..e80dce4bbde --- /dev/null +++ b/libraries/rush-lib/src/api/RushConfigurationProject.ts @@ -0,0 +1,552 @@ +// 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 { type IPackageJson, FileSystem, FileConstants } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from './RushConfiguration'; +import type { VersionPolicy, LockStepVersionPolicy } from './VersionPolicy'; +import type { PackageJsonEditor } from './PackageJsonEditor'; +import { RushConstants } from '../logic/RushConstants'; +import { PackageNameParsers } from './PackageNameParsers'; +import { DependencySpecifier, DependencySpecifierType } from '../logic/DependencySpecifier'; +import { SaveCallbackPackageJsonEditor } from './SaveCallbackPackageJsonEditor'; +import type { Subspace } from './Subspace'; + +/** + * This represents the JSON data object for a project entry in the rush.json configuration file. + */ +export interface IRushConfigurationProjectJson { + packageName: string; + projectFolder: string; + reviewCategory?: string; + decoupledLocalDependencies: string[]; + cyclicDependencyProjects?: string[]; + versionPolicyName?: string; + shouldPublish?: boolean; + skipRushCheck?: boolean; + publishFolder?: string; + tags?: string[]; + subspaceName?: string; +} + +/** + * @internal + */ +export interface IRushConfigurationProjectOptions { + /** + * The raw JSON representation from rush.json + */ + projectJson: IRushConfigurationProjectJson; + /** + * The enclosing configuration + */ + rushConfiguration: RushConfiguration; + /** + * A unique string name for this project + */ + tempProjectName: string; + /** + * If specified, validate project tags against this list. + */ + allowedProjectTags: Set | undefined; + + /** + * The containing subspace. + */ + subspace: Subspace; +} + +/** + * This represents the configuration of a project that is built by Rush, based on + * the Rush.json configuration file. + * @public + */ +export class RushConfigurationProject { + private readonly _shouldPublish: boolean; + + private _versionPolicy: VersionPolicy | undefined = undefined; + private _dependencyProjects: Set | undefined = undefined; + private _consumingProjects: Set | undefined = undefined; + private _packageJson: IPackageJson; + + /** + * The name of the NPM package. An error is reported if this name is not + * identical to packageJson.name. + * + * Example: `@scope/MyProject` + */ + public readonly packageName: string; + + /** + * The full path of the folder that contains the project to be built by Rush. + * + * Example: `C:\MyRepo\libraries\my-project` + */ + public readonly projectFolder: string; + + /** + * The relative path of the folder that contains the project to be built by Rush. + * + * Example: `libraries/my-project` + */ + public readonly projectRelativeFolder: string; + + /** + * The project-specific Rush configuration folder. + * + * Example: `C:\MyRepo\libraries\my-project\config\rush` + */ + public readonly projectRushConfigFolder: string; + + /** + * The project-specific Rush temp folder. This folder is used to store Rush-specific temporary files. + * + * Example: `C:\MyRepo\libraries\my-project\.rush\temp` + */ + public readonly projectRushTempFolder: string; + + /** + * The Rush configuration for the monorepo that the project belongs to. + */ + public readonly rushConfiguration: RushConfiguration; + + /** + * Returns the subspace name that a project belongs to. + * If subspaces is not enabled, returns the default subspace. + */ + public readonly subspace: Subspace; + + /** + * The review category name, or undefined if no category was assigned. + * This name must be one of the valid choices listed in RushConfiguration.reviewCategories. + */ + public readonly reviewCategory: string | undefined; + + /** + * A list of local projects that appear as devDependencies for this project, but cannot be + * locally linked because it would create a cyclic dependency; instead, the last published + * version will be installed in the Common folder. + * + * These are package names that would be found by RushConfiguration.getProjectByName(). + */ + public readonly decoupledLocalDependencies: Set; + + /** + * The parsed NPM "package.json" file from projectFolder. + */ + public get packageJson(): IPackageJson { + return this._packageJson; + } + + /** + * A useful wrapper around the package.json file for making modifications + * @beta + */ + public readonly packageJsonEditor: PackageJsonEditor; + + /** + * The unique name for the temporary project that will be generated in the Common folder. + * For example, if the project name is `@scope/MyProject`, the temporary project name + * might be `@rush-temp/MyProject-2`. + * + * Example: `@rush-temp/MyProject-2` + */ + public readonly tempProjectName: string; + + /** + * The unscoped temporary project name + * + * Example: `my-project-2` + */ + public readonly unscopedTempProjectName: string; + + /** + * If true, then this project will be ignored by the "rush check" command. + * The default value is false. + */ + public readonly skipRushCheck: boolean; + + /** + * Name of the version policy used by this project. + * @beta + */ + public readonly versionPolicyName: string | undefined; + + /** + * The full path of the folder that will get published by Rush. + * + * @remarks + * By default this is the same as the project folder, but a custom folder can be specified + * using the the "publishFolder" setting in rush.json. + * + * Example: `C:\MyRepo\libraries\my-project\temp\publish` + */ + public readonly publishFolder: string; + + /** + * An optional set of custom tags that can be used to select this project. + * + * @remarks + * For example, adding `my-custom-tag` will allow this project to be selected by the + * command `rush list --only tag:my-custom-tag`. The tag name must be one or more words separated + * by hyphens, where a word may contain lowercase letters, digits, and the period character. + * + * @beta + */ + public readonly tags: ReadonlySet; + + /** + * Returns the subspace name specified in the `"subspaceName"` field in `rush.json`. + * Note that this field may be undefined, if the `default` subspace is being used, + * and this field may be ignored if the subspaces feature is disabled. + * + * @beta + */ + public readonly configuredSubspaceName: string | undefined; + + /** @internal */ + public constructor(options: IRushConfigurationProjectOptions) { + const { projectJson, rushConfiguration, tempProjectName, allowedProjectTags } = options; + const { packageName, projectFolder: projectRelativeFolder } = projectJson; + this.rushConfiguration = rushConfiguration; + this.packageName = packageName; + this.projectRelativeFolder = projectRelativeFolder; + + validateRelativePathField(projectRelativeFolder, 'projectFolder', rushConfiguration.rushJsonFile); + + // For example, the depth of "a/b/c" would be 3. The depth of "a" is 1. + const projectFolderDepth: number = projectRelativeFolder.split('/').length; + if (projectFolderDepth < rushConfiguration.projectFolderMinDepth) { + throw new Error( + `To keep things organized, this repository has a projectFolderMinDepth policy` + + ` requiring project folders to be at least ${rushConfiguration.projectFolderMinDepth} levels deep.` + + ` Problem folder: "${projectRelativeFolder}"` + ); + } + if (projectFolderDepth > rushConfiguration.projectFolderMaxDepth) { + throw new Error( + `To keep things organized, this repository has a projectFolderMaxDepth policy` + + ` preventing project folders from being deeper than ${rushConfiguration.projectFolderMaxDepth} levels.` + + ` Problem folder: "${projectRelativeFolder}"` + ); + } + + const absoluteProjectFolder: string = path.join(rushConfiguration.rushJsonFolder, projectRelativeFolder); + this.projectFolder = absoluteProjectFolder; + const packageJsonFilename: string = path.join(absoluteProjectFolder, FileConstants.PackageJson); + + try { + const packageJsonText: string = FileSystem.readFile(packageJsonFilename); + // JSON.parse is native and runs in less than 1/2 the time of jju.parse. package.json is required to be strict JSON by NodeJS. + this._packageJson = JSON.parse(packageJsonText); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + throw new Error(`Could not find package.json for ${packageName} at ${packageJsonFilename}`); + } + + // Encountered an error while loading the package.json file. Please append the error message with the corresponding file location. + if (error instanceof SyntaxError) { + error.message = `${error.message}\nFilename: ${packageJsonFilename}`; + } + throw error; + } + + this.projectRushConfigFolder = path.join(absoluteProjectFolder, 'config', 'rush'); + this.projectRushTempFolder = path.join( + absoluteProjectFolder, + RushConstants.projectRushFolderName, + RushConstants.rushTempFolderName + ); + + // Are we using a package review file? + if (rushConfiguration.approvedPackagesPolicy.enabled) { + // If so, then every project needs to have a reviewCategory that was defined + // by the reviewCategories array. + if (!projectJson.reviewCategory) { + throw new Error( + `The "approvedPackagesPolicy" feature is enabled ${RushConstants.rushJsonFilename}, but a reviewCategory` + + ` was not specified for the project "${packageName}".` + ); + } + if (!rushConfiguration.approvedPackagesPolicy.reviewCategories.has(projectJson.reviewCategory)) { + throw new Error( + `The project "${packageName}" specifies its reviewCategory as` + + `"${projectJson.reviewCategory}" which is not one of the defined reviewCategories.` + ); + } + this.reviewCategory = projectJson.reviewCategory; + } + + if (this.packageJson.name !== this.packageName) { + throw new Error( + `The package name "${this.packageName}" specified in ${RushConstants.rushJsonFilename} does not` + + ` match the name "${this.packageJson.name}" from package.json` + ); + } + + if (!semver.valid(this.packageJson.version)) { + throw new Error( + `The value "${this.packageJson.version}" is not valid SemVer syntax for the \"version\" field` + + ` in the file "${packageJsonFilename}"` + ); + } + + this.packageJsonEditor = SaveCallbackPackageJsonEditor.fromObjectWithCallback({ + object: this.packageJson, + filename: packageJsonFilename, + onSaved: (newObject) => { + // Just update the in-memory copy, don't bother doing the validation again + this._packageJson = newObject; + this._dependencyProjects = undefined; // Reset the cached dependency projects + } + }); + + this.tempProjectName = tempProjectName; + + // The "rushProject.tempProjectName" is guaranteed to be unique name (e.g. by adding the "-2" + // suffix). Even after we strip the NPM scope, it will still be unique. + // Example: "my-project-2" + this.unscopedTempProjectName = PackageNameParsers.permissive.getUnscopedName(tempProjectName); + + this.decoupledLocalDependencies = new Set(); + if (projectJson.cyclicDependencyProjects || projectJson.decoupledLocalDependencies) { + if (projectJson.cyclicDependencyProjects && projectJson.decoupledLocalDependencies) { + throw new Error( + 'A project configuration cannot specify both "decoupledLocalDependencies" and "cyclicDependencyProjects". Please use "decoupledLocalDependencies" only -- the other name is deprecated.' + ); + } + for (const cyclicDependencyProject of projectJson.cyclicDependencyProjects || + projectJson.decoupledLocalDependencies) { + this.decoupledLocalDependencies.add(cyclicDependencyProject); + } + } + this._shouldPublish = !!projectJson.shouldPublish; + this.skipRushCheck = !!projectJson.skipRushCheck; + this.versionPolicyName = projectJson.versionPolicyName; + + if (this._shouldPublish && this.packageJson.private) { + throw new Error( + `The project "${packageName}" specifies "shouldPublish": true, ` + + `but the package.json file specifies "private": true.` + ); + } + + this.publishFolder = absoluteProjectFolder; + const { publishFolder } = projectJson; + if (publishFolder) { + validateRelativePathField(publishFolder, 'publishFolder', rushConfiguration.rushJsonFile); + this.publishFolder = path.join(this.publishFolder, publishFolder); + } + + if (allowedProjectTags && projectJson.tags) { + const tags: Set = new Set(); + for (const tag of projectJson.tags) { + if (!allowedProjectTags.has(tag)) { + throw new Error( + `The tag "${tag}" specified for project "${packageName}" is not listed in the ` + + `allowedProjectTags field in ${RushConstants.rushJsonFilename}.` + ); + } else { + tags.add(tag); + } + } + this.tags = tags; + } else { + this.tags = new Set(projectJson.tags); + } + + this.configuredSubspaceName = projectJson.subspaceName; + this.subspace = options.subspace; + } + + /** + * A list of local projects that appear as devDependencies for this project, but cannot be + * locally linked because it would create a cyclic dependency; instead, the last published + * version will be installed in the Common folder. + * + * These are package names that would be found by RushConfiguration.getProjectByName(). + * + * @deprecated Use `decoupledLocalDependencies` instead, as it better describes the purpose of the data. + */ + public get cyclicDependencyProjects(): Set { + return this.decoupledLocalDependencies; + } + + /** + * An array of projects within the Rush configuration which directly depend on this package. + * @deprecated Use `consumingProjectNames` instead, as it has Set semantics, which better reflect the nature + * of the data. + */ + public get downstreamDependencyProjects(): string[] { + return Array.from(this.consumingProjects, (project: RushConfigurationProject) => project.packageName); + } + + /** + * An array of projects within the Rush configuration which this project declares as dependencies. + * @deprecated Use `dependencyProjects` instead, as it has Set semantics, which better reflect the nature + * of the data. + */ + public get localDependencyProjects(): ReadonlyArray { + return [...this.dependencyProjects]; + } + + /** + * The set of projects within the Rush configuration which this project declares as dependencies. + * + * @remarks + * Can be used recursively to walk the project dependency graph to find all projects that are directly or indirectly + * referenced from this project. + */ + public get dependencyProjects(): ReadonlySet { + let dependencyProjects: Set | undefined = this._dependencyProjects; + if (!dependencyProjects) { + this._dependencyProjects = dependencyProjects = new Set(); + const { packageJson } = this; + for (const dependencySet of [ + packageJson.dependencies, + packageJson.devDependencies, + packageJson.optionalDependencies + ]) { + if (dependencySet) { + for (const [dependency, version] of Object.entries(dependencySet)) { + 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 + const localProject: RushConfigurationProject | undefined = + this.rushConfiguration.getProjectByName(dependencyName); + if (localProject && !this.decoupledLocalDependencies.has(dependency)) { + // Set the value if it's a workspace project, or if we have a local project and the semver is satisfied + switch (dependencySpecifier.specifierType) { + case DependencySpecifierType.Version: + case DependencySpecifierType.Range: + if ( + semver.satisfies(localProject.packageJson.version, dependencySpecifier.versionSpecifier) + ) { + dependencyProjects.add(localProject); + } + break; + case DependencySpecifierType.Workspace: + dependencyProjects.add(localProject); + break; + } + } + } + } + } + } + return dependencyProjects; + } + + /** + * The set of projects within the Rush configuration which declare this project as a dependency. + * Excludes those that declare this project as a `cyclicDependencyProject`. + * + * @remarks + * This field is the counterpart to `dependencyProjects`, and can be used recursively to walk the project dependency + * graph to find all projects which will be impacted by changes to this project. + */ + public get consumingProjects(): ReadonlySet { + if (!this._consumingProjects) { + // Force initialize all dependency relationships + // This needs to operate on every project in the set because the relationships are only specified + // in the consuming project + const { projects } = this.rushConfiguration; + + for (const project of projects) { + project._consumingProjects = new Set(); + } + + for (const project of projects) { + for (const dependency of project.dependencyProjects) { + dependency._consumingProjects!.add(project); + } + } + } + return this._consumingProjects!; + } + + /** + * A flag which indicates whether changes to this project should be published. This controls + * whether or not the project would show up when running `rush change`, and whether or not it + * should be published during `rush publish`. + */ + public get shouldPublish(): boolean { + return this._shouldPublish || !!this.versionPolicyName; + } + + /** + * Version policy of the project + * @beta + */ + public get versionPolicy(): VersionPolicy | undefined { + if (!this._versionPolicy) { + if (this.versionPolicyName && this.rushConfiguration.versionPolicyConfiguration) { + this._versionPolicy = this.rushConfiguration.versionPolicyConfiguration.getVersionPolicy( + this.versionPolicyName + ); + } + } + return this._versionPolicy; + } + + /** + * Indicate whether this project is the main project for the related version policy. + * + * False if the project is not for publishing. + * True if the project is individually versioned or if its lockstep version policy does not specify main project. + * False if the project is lockstepped and is not the main project for its version policy. + * + * @beta + */ + public get isMainProject(): boolean { + if (!this.shouldPublish) { + return false; + } + let isMain: boolean = true; + if (this.versionPolicy && this.versionPolicy.isLockstepped) { + const lockStepPolicy: LockStepVersionPolicy = this.versionPolicy as LockStepVersionPolicy; + if (lockStepPolicy.mainProject && lockStepPolicy.mainProject !== this.packageName) { + isMain = false; + } + } + return isMain; + } +} + +export function validateRelativePathField(relativePath: string, field: string, file: string): void { + // path.isAbsolute delegates depending on platform; however, path.posix.isAbsolute('C:/a') returns false, + // while path.win32.isAbsolute('C:/a') returns true. We want consistent validation across platforms. + if (path.posix.isAbsolute(relativePath) || path.win32.isAbsolute(relativePath)) { + throw new Error( + `The value "${relativePath}" in the "${field}" field in "${file}" must be a relative path.` + ); + } + + if (relativePath.includes('\\')) { + throw new Error( + `The value "${relativePath}" in the "${field}" field in "${file}" may not contain backslashes ('\\'), since they are interpreted differently` + + ` on POSIX and Windows. Paths must use '/' as the path separator.` + ); + } + + if (relativePath.endsWith('/')) { + throw new Error( + `The value "${relativePath}" in the "${field}" field in "${file}" may not end with a trailing '/' character.` + ); + } + + const normalized: string = path.posix.normalize(relativePath); + if (relativePath !== normalized) { + throw new Error( + `The value "${relativePath}" in the "${field}" field in "${file}" should be replaced with its normalized form "${normalized}".` + ); + } +} diff --git a/libraries/rush-lib/src/api/RushGlobalFolder.ts b/libraries/rush-lib/src/api/RushGlobalFolder.ts new file mode 100644 index 00000000000..18f77f7f938 --- /dev/null +++ b/libraries/rush-lib/src/api/RushGlobalFolder.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 * as path from 'node:path'; + +import { User } from '@rushstack/node-core-library'; + +import { EnvironmentConfiguration } from './EnvironmentConfiguration'; + +/** + * This class provides global folders that are used for rush's internal install locations. + * + * @internal + */ +export class RushGlobalFolder { + /** + * The global folder where Rush stores temporary files. + * + * @remarks + * + * Most of the temporary files created by Rush are stored separately for each monorepo working folder, + * to avoid issues of concurrency and compatibility between tool versions. However, a small set + * of files (e.g. installations of the `@microsoft/rush-lib` engine and the package manager) are stored + * in a global folder to speed up installations. The default location is `~/.rush` on POSIX-like + * operating systems or `C:\Users\YourName` on Windows. + * + * You can use the {@link EnvironmentVariableNames.RUSH_GLOBAL_FOLDER} environment variable to specify + * a different folder path. This is useful for example if a Windows group policy forbids executing scripts + * installed in a user's home directory. + * + * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. + */ + public readonly path: string; + + /** + * The absolute path to Rush's storage in the home directory for the current user and node version. + * On Windows, it would be something like `C:\Users\YourName\.rush\node-v3.4.5`. + */ + public readonly nodeSpecificPath: string; + + public constructor() { + // Because RushGlobalFolder is used by the front-end VersionSelector before EnvironmentConfiguration + // is initialized, we need to read it using a special internal API. + const rushGlobalFolderOverride: string | undefined = + EnvironmentConfiguration._getRushGlobalFolderOverride(process.env); + if (rushGlobalFolderOverride !== undefined) { + this.path = rushGlobalFolderOverride; + } else { + this.path = path.join(User.getHomeFolder(), '.rush'); + } + + const normalizedNodeVersion: string = process.version.match(/^[a-z0-9\-\.]+$/i) + ? process.version + : 'unknown-version'; + this.nodeSpecificPath = path.join(this.path, `node-${normalizedNodeVersion}`); + } +} diff --git a/libraries/rush-lib/src/api/RushInternals.ts b/libraries/rush-lib/src/api/RushInternals.ts new file mode 100644 index 00000000000..6abf2e7122e --- /dev/null +++ b/libraries/rush-lib/src/api/RushInternals.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 { Rush } from './Rush'; + +/** + * Used by rush-sdk to access internals of rush-lib. + * @internal + */ +export class RushInternals { + /** + * Used by rush-sdk to load an internal API specified by its module path. + * + * @param srcImportPath - The module path to load. For example, to refer to `src/api/ChangeFile.ts`, + * the `srcImportPath` would be `"api/ChangeFile"`. + * @returns the module object as would be returned by `require()` + */ + public static loadModule(srcImportPath: string): unknown { + const libPath: string = `${Rush._rushLibPackageFolder}/lib/${srcImportPath}`; + try { + return require(libPath); + } catch (e) { + throw new Error( + `The specified internal API "src/${srcImportPath}" is not implemented by Rush ${Rush.version}` + ); + } + } +} diff --git a/libraries/rush-lib/src/api/RushPluginsConfiguration.ts b/libraries/rush-lib/src/api/RushPluginsConfiguration.ts new file mode 100644 index 00000000000..f8d194d0ab1 --- /dev/null +++ b/libraries/rush-lib/src/api/RushPluginsConfiguration.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 { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import schemaJson from '../schemas/rush-plugins.schema.json'; + +/** + * @internal + */ +export interface IRushPluginConfigurationBase { + packageName: string; + pluginName: string; +} + +export interface IRushPluginConfiguration extends IRushPluginConfigurationBase { + autoinstallerName: string; +} + +interface IRushPluginsConfigurationJson { + plugins: IRushPluginConfiguration[]; +} + +export class RushPluginsConfiguration { + private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + private _jsonFilename: string; + + public readonly configuration: Readonly; + + public constructor(jsonFilename: string) { + this._jsonFilename = jsonFilename; + this.configuration = { + plugins: [] + }; + + if (FileSystem.exists(this._jsonFilename)) { + this.configuration = JsonFile.loadAndValidate(this._jsonFilename, RushPluginsConfiguration._jsonSchema); + } + } +} diff --git a/libraries/rush-lib/src/api/RushProjectConfiguration.ts b/libraries/rush-lib/src/api/RushProjectConfiguration.ts new file mode 100644 index 00000000000..7dd28c3c789 --- /dev/null +++ b/libraries/rush-lib/src/api/RushProjectConfiguration.ts @@ -0,0 +1,655 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AlreadyReportedError, Async, Path } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { ProjectConfigurationFile, InheritanceType } from '@rushstack/heft-config-file'; +import { RigConfig } from '@rushstack/rig-package'; + +import type { RushConfigurationProject } from './RushConfigurationProject'; +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/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. + * @internal + */ +export interface IRushProjectJson { + /** + * The incremental analyzer can skip Rush commands for projects whose input files have + * not changed since the last build. Normally, every Git-tracked file under the project + * folder is assumed to be an input. Set incrementalBuildIgnoredGlobs to ignore specific + * files, specified as globs relative to the project folder. The list of file globs will + * be interpreted the same way your .gitignore file is. + */ + incrementalBuildIgnoredGlobs?: string[]; + + /** + * Disable caching for this project. The project will never be restored from cache. + * This may be useful if this project affects state outside of its folder. + * + * This option is only used when the build cache is enabled for the repo. You can set + * disableBuildCacheForProject=true to disable caching for a specific project. This is a useful workaround + * if that project's build scripts violate the assumptions of the cache, for example by writing + * files outside the project folder. Where possible, a better solution is to improve the build scripts + * to be compatible with caching. + */ + disableBuildCacheForProject?: boolean; + + operationSettings?: IOperationSettings[]; +} + +/** @alpha */ +export interface IRushPhaseSharding { + /** + * The number of shards to create. + */ + count: number; + + /** + * The format of the argument to pass to the command to indicate the shard index and count. + * + * @defaultValue `--shard={shardIndex}/{shardCount}` + */ + shardArgumentFormat?: string; + + /** + * An optional argument to pass to the command to indicate the output folder for the shard. + * It must end with `{shardIndex}`. + * + * @defaultValue `--shard-output-folder=.rush/operations/{phaseName}/shards/{shardIndex}`. + */ + outputFolderArgumentFormat?: string; + + /** + * @deprecated Create a separate operation settings object for the shard operation settings with the name `{operationName}:shard`. + */ + shardOperationSettings?: unknown; +} + +/** + * @alpha + */ +export interface IOperationSettings { + /** + * The name of the operation. This should be a key in the `package.json`'s `scripts` object. + */ + operationName: string; + + /** + * Specify the folders where this operation writes its output files. If enabled, the Rush build + * cache will restore these folders from the cache. The strings are folder names under the project + * root folder. + * + * These folders should not be tracked by Git. They must not contain symlinks. + */ + outputFolderNames?: string[]; + + /** + * Disable caching for this operation. The operation will never be restored from cache. + * This may be useful if this operation affects state outside of its folder. + * + * This option is only used when the build cache is enabled for the repo. You can set + * disableBuildCacheForOperation=true to disable caching for a specific project operation. + * This is a useful workaround if that project's build scripts violate the assumptions of the cache, + * for example by writing files outside the project folder. Where possible, a better solution is to improve + * the build scripts to be compatible with caching. + */ + disableBuildCacheForOperation?: boolean; + + /** + * An optional list of environment variables that can affect this operation. The values of + * these environment variables will become part of the hash when reading and writing the build cache. + * + * Note: generally speaking, all environment variables available to Rush are also available to any + * operations performed -- Rush assumes that environment variables do not affect build outputs unless + * you list them here. + */ + dependsOnEnvVars?: string[]; + + /** + * 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 + * and writing the build cache. + * + * Note: if a particular file will be matched by patterns provided by both `incrementalBuildIgnoredGlobs` and + * `dependsOnAdditionalFiles` options - `dependsOnAdditionalFiles` will win and the file will be included + * calculating final hash value when reading and writing the build cache + */ + dependsOnAdditionalFiles?: string[]; + + /** + * An optional config object for sharding the operation. If specified, the operation will be sharded + * into multiple invocations. The `count` property specifies the number of shards to create. The + * `shardArgumentFormat` property specifies the format of the argument to pass to the command to + * indicate the shard index and count. The default value is `--shard={shardIndex}/{shardCount}`. + */ + sharding?: IRushPhaseSharding; + + /** + * How many concurrency units this operation should take up during execution. The maximum concurrent units is + * determined by the -p flag. + */ + weight?: 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 { + projectOutputFolderNames?: unknown; + phaseOptions?: unknown; + buildCacheOptions?: unknown; +} + +const RUSH_PROJECT_CONFIGURATION_FILE: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: `config/${RushConstants.rushProjectConfigFilename}`, + jsonSchemaObject: schemaJson, + propertyInheritance: { + operationSettings: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: ( + child: IOperationSettings[] | undefined, + parent: IOperationSettings[] | undefined + ) => { + if (!child) { + return parent; + } else if (!parent) { + return child; + } else { + // Merge any properties that need to be merged + const resultOperationSettingsByOperationName: Map = new Map(); + for (const parentOperationSettings of parent) { + resultOperationSettingsByOperationName.set( + parentOperationSettings.operationName, + parentOperationSettings + ); + } + + const childEncounteredOperationNames: Set = new Set(); + for (const childOperationSettings of child) { + const operationName: string = childOperationSettings.operationName; + if (childEncounteredOperationNames.has(operationName)) { + // If the operation settings already exist, but didn't come from the parent, then + // it shows up multiple times in the child. + const childSourceFilePath: string = + RUSH_PROJECT_CONFIGURATION_FILE.getObjectSourceFilePath(child)!; + throw new Error( + `The operation "${operationName}" occurs multiple times in the "operationSettings" array ` + + `in "${childSourceFilePath}".` + ); + } + + childEncounteredOperationNames.add(operationName); + + let mergedOperationSettings: IOperationSettings | undefined = + resultOperationSettingsByOperationName.get(operationName); + if (mergedOperationSettings) { + // The parent operation settings object already exists + const outputFolderNames: string[] | undefined = + mergedOperationSettings.outputFolderNames && childOperationSettings.outputFolderNames + ? [ + ...mergedOperationSettings.outputFolderNames, + ...childOperationSettings.outputFolderNames + ] + : mergedOperationSettings.outputFolderNames || childOperationSettings.outputFolderNames; + + const dependsOnEnvVars: string[] | undefined = + mergedOperationSettings.dependsOnEnvVars && childOperationSettings.dependsOnEnvVars + ? [ + ...mergedOperationSettings.dependsOnEnvVars, + ...childOperationSettings.dependsOnEnvVars + ] + : mergedOperationSettings.dependsOnEnvVars || childOperationSettings.dependsOnEnvVars; + + mergedOperationSettings = { + ...mergedOperationSettings, + ...childOperationSettings, + ...(outputFolderNames ? { outputFolderNames } : {}), + ...(dependsOnEnvVars ? { dependsOnEnvVars } : {}) + }; + resultOperationSettingsByOperationName.set(operationName, mergedOperationSettings); + } else { + resultOperationSettingsByOperationName.set(operationName, childOperationSettings); + } + } + + return Array.from(resultOperationSettingsByOperationName.values()); + } + } + }, + incrementalBuildIgnoredGlobs: { + inheritanceType: InheritanceType.replace + } + } + }); + +const OLD_RUSH_PROJECT_CONFIGURATION_FILE: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath: RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath, + jsonSchemaObject: anythingSchemaJson + }); + +/** + * Use this class to load the "config/rush-project.json" config file. + * + * This file provides project-specific configuration options. + * @alpha + */ +export class RushProjectConfiguration { + private static readonly _configCache: Map = + new Map(); + + public readonly project: RushConfigurationProject; + + /** + * {@inheritdoc _IRushProjectJson.incrementalBuildIgnoredGlobs} + */ + public readonly incrementalBuildIgnoredGlobs: ReadonlyArray; + + /** + * {@inheritdoc _IRushProjectJson.disableBuildCacheForProject} + */ + public readonly disableBuildCacheForProject: boolean; + + public readonly operationSettingsByOperationName: ReadonlyMap>; + + private readonly _validationCache: WeakSet = new WeakSet(); + + private constructor( + project: RushConfigurationProject, + rushProjectJson: IRushProjectJson, + operationSettingsByOperationName: ReadonlyMap + ) { + this.project = project; + this.incrementalBuildIgnoredGlobs = rushProjectJson.incrementalBuildIgnoredGlobs || []; + this.disableBuildCacheForProject = rushProjectJson.disableBuildCacheForProject || false; + this.operationSettingsByOperationName = operationSettingsByOperationName; + } + + /** + * Validates that the requested phases are compatible. + * Deferral of this logic to its own method means that Rush no longer eagerly validates + * all defined commands in command-line.json. As such, while validation will be run for a given + * command upon invoking that command, defining overlapping phases in "rush custom-command" + * that are not used by "rush build" will not cause "rush build" to exit with an error. + */ + public validatePhaseConfiguration(phases: Iterable, terminal: ITerminal): void { + // Don't repeatedly validate the same set of phases for the same project. + if (this._validationCache.has(phases)) { + return; + } + + const overlappingPathAnalyzer: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + + const { operationSettingsByOperationName, project } = this; + + let hasErrors: boolean = false; + + for (const phase of phases) { + const operationName: string = phase.name; + const operationSettings: IOperationSettings | undefined = + operationSettingsByOperationName.get(operationName); + if (operationSettings) { + if (operationSettings.outputFolderNames) { + for (const outputFolderName of operationSettings.outputFolderNames) { + const otherOverlappingOperationNames: string[] | undefined = + overlappingPathAnalyzer.addPathAndGetFirstEncounteredLabels(outputFolderName, operationName); + if (otherOverlappingOperationNames) { + const overlapsWithOwnOperation: boolean = + otherOverlappingOperationNames?.includes(operationName); + if (overlapsWithOwnOperation) { + terminal.writeErrorLine( + `The project "${project.packageName}" has a ` + + `"${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath}" configuration that defines an ` + + `operation with overlapping paths in the "outputFolderNames" list. The operation is ` + + `"${operationName}", and the conflicting path is "${outputFolderName}".` + ); + } else { + terminal.writeErrorLine( + `The project "${project.packageName}" has a ` + + `"${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath}" 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 "${outputFolderName}" path overlaps between these operations: ` + + `"${operationName}", "${otherOverlappingOperationNames.join('", "')}"` + ); + } + + hasErrors = true; + } + } + } + + // 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; + } + } + } + } + + this._validationCache.add(phases); + + if (hasErrors) { + throw new AlreadyReportedError(); + } + } + + /** + * Examines the list of source files for the project and the target phase and returns a reason + * why the project cannot enable the build cache for that phase, or undefined if it is safe to so do. + */ + public getCacheDisabledReason( + trackedFileNames: Iterable, + 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; + } + if (this.disableBuildCacheForProject) { + return 'Caching has been disabled for this project.'; + } + + const operationSettings: IOperationSettings | undefined = + this.operationSettingsByOperationName.get(phaseName); + if (!operationSettings) { + return `This project does not define the caching behavior of the "${phaseName}" command, so caching has been disabled.`; + } + + if (operationSettings.disableBuildCacheForOperation) { + return `Caching has been disabled for this project's "${phaseName}" command.`; + } + + const { outputFolderNames } = operationSettings; + if (!outputFolderNames) { + return; + } + const normalizedProjectRelativeFolder: string = Path.convertToSlashes(this.project.projectRelativeFolder); + + const normalizedOutputFolders: string[] = outputFolderNames.map( + (outputFolderName) => `${normalizedProjectRelativeFolder}/${outputFolderName}/` + ); + + const inputOutputFiles: string[] = []; + for (const file of trackedFileNames) { + for (const outputFolder of normalizedOutputFolders) { + if (file.startsWith(outputFolder)) { + inputOutputFiles.push(file); + } + } + } + + if (inputOutputFiles.length > 0) { + return ( + 'The following files are used to calculate project state ' + + `and are considered project output: ${inputOutputFiles.join(', ')}` + ); + } + } + + /** + * Source of truth for whether a project is unable to use the build cache for a given phase. + * As some operations may not have a rush-project.json file defined at all, but may be no-op operations + * we'll want to ignore those completely. + */ + public static getCacheDisabledReasonForProject(options: { + projectConfiguration: RushProjectConfiguration | undefined; + trackedFileNames: Iterable; + phaseName: string; + isNoOp: boolean; + }): string | undefined { + const { projectConfiguration, trackedFileNames, phaseName, isNoOp } = options; + if (isNoOp) { + return undefined; + } + + if (!projectConfiguration) { + return ( + `Project does not have a ${RushConstants.rushProjectConfigFilename} configuration file, ` + + 'or one provided by a rig, so it does not support caching.' + ); + } + + return projectConfiguration.getCacheDisabledReason(trackedFileNames, phaseName, isNoOp); + } + + /** + * Loads the rush-project.json data for the specified project. + */ + public static async tryLoadForProjectAsync( + project: RushConfigurationProject, + terminal: ITerminal + ): Promise { + // false is a signal that the project config does not exist + const cacheEntry: RushProjectConfiguration | false | undefined = + RushProjectConfiguration._configCache.get(project); + if (cacheEntry !== undefined) { + return cacheEntry || undefined; + } + + const rushProjectJson: IRushProjectJson | undefined = await this._tryLoadJsonForProjectAsync( + project, + terminal + ); + + if (rushProjectJson) { + const result: RushProjectConfiguration = RushProjectConfiguration._getRushProjectConfiguration( + project, + rushProjectJson, + terminal + ); + RushProjectConfiguration._configCache.set(project, result); + return result; + } else { + RushProjectConfiguration._configCache.set(project, false); + return undefined; + } + } + + /** + * Load only the `incrementalBuildIgnoredGlobs` property from the rush-project.json file, skipping + * validation of other parts of the config file. + * + * @remarks + * This function exists to allow the ProjectChangeAnalyzer to load just the ignore globs without + * having to validate the rest of the `rush-project.json` file against the repo's command-line configuration. + */ + public static async tryLoadIgnoreGlobsForProjectAsync( + project: RushConfigurationProject, + terminal: ITerminal + ): Promise | undefined> { + const rushProjectJson: IRushProjectJson | undefined = await this._tryLoadJsonForProjectAsync( + project, + terminal + ); + + return rushProjectJson?.incrementalBuildIgnoredGlobs; + } + + /** + * Load the rush-project.json data for all selected projects. + * Validate compatibility of output folders across all selected phases. + */ + public static async tryLoadForProjectsAsync( + projects: Iterable, + terminal: ITerminal + ): Promise> { + const result: Map = new Map(); + + await Async.forEachAsync( + projects, + async (project: RushConfigurationProject) => { + const projectConfig: RushProjectConfiguration | undefined = + await RushProjectConfiguration.tryLoadForProjectAsync(project, terminal); + if (projectConfig) { + result.set(project, projectConfig); + } + }, + { concurrency: 50 } + ); + + return result; + } + + private static async _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 { + oldRushProjectJson = + await OLD_RUSH_PROJECT_CONFIGURATION_FILE.tryLoadConfigurationFileForProjectAsync( + terminal, + project.projectFolder, + rigConfig + ); + } 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; + } + } + } + + 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}".`; + } + } + + 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.` + ); + } + } + } + + if (hasErrors) { + throw new AlreadyReportedError(); + } + + return new RushProjectConfiguration(project, rushProjectJson, operationSettingsByOperationName); + } +} diff --git a/libraries/rush-lib/src/api/RushUserConfiguration.ts b/libraries/rush-lib/src/api/RushUserConfiguration.ts new file mode 100644 index 00000000000..cdf767363bb --- /dev/null +++ b/libraries/rush-lib/src/api/RushUserConfiguration.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 * as path from 'node:path'; + +import { FileSystem, JsonFile, JsonSchema, User } from '@rushstack/node-core-library'; + +import { RushConstants } from '../logic/RushConstants'; +import schemaJson from '../schemas/rush-user-settings.schema.json'; + +interface IRushUserSettingsJson { + buildCacheFolder?: string; +} + +/** + * 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. + */ + public readonly buildCacheFolder: string | undefined; + + private constructor(rushUserConfigurationJson: IRushUserSettingsJson | undefined) { + this.buildCacheFolder = rushUserConfigurationJson?.buildCacheFolder; + if (this.buildCacheFolder && !path.isAbsolute(this.buildCacheFolder)) { + throw new Error('buildCacheFolder must be an absolute path'); + } + } + + public static async initializeAsync(): Promise { + const rushUserFolderPath: string = RushUserConfiguration.getRushUserFolderPath(); + const rushUserSettingsFilePath: string = path.join(rushUserFolderPath, 'settings.json'); + let rushUserSettingsJson: IRushUserSettingsJson | undefined; + try { + rushUserSettingsJson = await JsonFile.loadAndValidateAsync( + rushUserSettingsFilePath, + RushUserConfiguration._schema + ); + } catch (e) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + } + + return new RushUserConfiguration(rushUserSettingsJson); + } + + public static getRushUserFolderPath(): string { + 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 new file mode 100644 index 00000000000..1462d824548 --- /dev/null +++ b/libraries/rush-lib/src/api/SaveCallbackPackageJsonEditor.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 type { IPackageJson } from '@rushstack/node-core-library'; + +import { PackageJsonEditor } from './PackageJsonEditor'; + +export interface IFromObjectOptions { + object: IPackageJson; + filename: string; + onSaved?: (newObject: IPackageJson) => void; +} + +export class SaveCallbackPackageJsonEditor extends PackageJsonEditor { + private readonly _onSaved: ((newObject: IPackageJson) => void) | undefined; + + private constructor(options: IFromObjectOptions) { + super(options.filename, options.object); + + this._onSaved = options.onSaved; + } + + public static fromObjectWithCallback(options: IFromObjectOptions): SaveCallbackPackageJsonEditor { + return new SaveCallbackPackageJsonEditor(options); + } + + public saveIfModified(): boolean { + const modified: boolean = super.saveIfModified(); + if (this._onSaved) { + this._onSaved(this.saveToObject()); + } + + return modified; + } +} diff --git a/libraries/rush-lib/src/api/Subspace.ts b/libraries/rush-lib/src/api/Subspace.ts new file mode 100644 index 00000000000..624b1a33bd6 --- /dev/null +++ b/libraries/rush-lib/src/api/Subspace.ts @@ -0,0 +1,525 @@ +// 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 } 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'; +import { RushConstants } from '../logic/RushConstants'; +import { CommonVersionsConfiguration } from './CommonVersionsConfiguration'; +import { RepoStateFile } from '../logic/RepoStateFile'; +import type { PnpmPackageManager } from './packageManager/PnpmPackageManager'; +import { PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration'; +import { SubspacePnpmfileConfiguration } from '../logic/pnpm/SubspacePnpmfileConfiguration'; +import type { ISubspacePnpmfileShimSettings } from '../logic/pnpm/IPnpmfile'; + +/** + * @internal + */ +export interface ISubspaceOptions { + subspaceName: string; + rushConfiguration: RushConfiguration; + splitWorkspaceCompatibility: boolean; +} + +interface ISubspaceDetail { + subspaceConfigFolderPath: string; + subspacePnpmPatchesFolderPath: string; + subspaceTempFolderPath: string; + tempShrinkwrapFilePath: string; + tempShrinkwrapPreinstallFilePath: string; +} + +interface IPackageJsonLite extends Omit {} + +/** + * This represents the subspace configurations for a repository, based on the "subspaces.json" + * configuration file. + * @public + */ +export class Subspace { + public readonly subspaceName: string; + private readonly _rushConfiguration: RushConfiguration; + private readonly _projects: RushConfigurationProject[] = []; + private readonly _splitWorkspaceCompatibility: boolean; + private _commonVersionsConfiguration: CommonVersionsConfiguration | undefined = undefined; + + private _detail: ISubspaceDetail | undefined; + + private _cachedPnpmOptions: PnpmOptionsConfiguration | undefined = undefined; + // If true, then _cachedPnpmOptions has been initialized. + private _cachedPnpmOptionsInitialized: boolean = false; + + public constructor(options: ISubspaceOptions) { + this.subspaceName = options.subspaceName; + this._rushConfiguration = options.rushConfiguration; + this._splitWorkspaceCompatibility = options.splitWorkspaceCompatibility; + } + + /** + * Returns the list of projects belonging to this subspace. + * @beta + */ + public getProjects(): RushConfigurationProject[] { + return this._projects; + } + + /** + * Returns the parsed contents of the pnpm-config.json config file. + * @beta + */ + public getPnpmOptions(): PnpmOptionsConfiguration | undefined { + if (!this._cachedPnpmOptionsInitialized) { + // Calculate these outside the try/catch block since their error messages shouldn't be annotated: + const subspaceTempFolder: string = this.getSubspaceTempFolderPath(); + try { + this._cachedPnpmOptions = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + this.getPnpmConfigFilePath(), + subspaceTempFolder + ); + this._cachedPnpmOptionsInitialized = true; + } catch (e) { + if (FileSystem.isNotExistError(e as Error)) { + this._cachedPnpmOptions = undefined; + this._cachedPnpmOptionsInitialized = true; + } else { + throw new Error( + `The subspace "${this.subspaceName}" has an invalid pnpm-config.json file:\n` + e.message + ); + } + } + } + return this._cachedPnpmOptions; + } + + private _ensureDetail(): ISubspaceDetail { + if (!this._detail) { + const rushConfiguration: RushConfiguration = this._rushConfiguration; + let subspaceConfigFolderPath: string; + let subspacePnpmPatchesFolderPath: string; + + if (rushConfiguration.subspacesFeatureEnabled) { + if (!rushConfiguration.pnpmOptions.useWorkspaces) { + throw new Error( + `The Rush subspaces feature is enabled. You must set useWorkspaces=true in pnpm-config.json.` + ); + } + + // If this subspace doesn't have a configuration folder, check if it is in the project folder itself + // if the splitWorkspaceCompatibility option is enabled in the subspace configuration + + // Example: C:\MyRepo\common\config\subspaces\my-subspace + const standardSubspaceConfigFolder: string = `${rushConfiguration.commonFolder}/config/subspaces/${this.subspaceName}`; + + subspaceConfigFolderPath = standardSubspaceConfigFolder; + + if (this._splitWorkspaceCompatibility && this.subspaceName.startsWith('split_')) { + if (FileSystem.exists(standardSubspaceConfigFolder + '/pnpm-lock.yaml')) { + throw new Error( + `The split workspace subspace "${this.subspaceName}" cannot use a common/config folder: ` + + standardSubspaceConfigFolder + ); + } + + if (this._projects.length !== 1) { + throw new Error( + `The split workspace subspace "${this.subspaceName}" contains ${this._projects.length}` + + ` projects; there must be exactly one project.` + ); + } + const project: RushConfigurationProject = this._projects[0]; + + subspaceConfigFolderPath = `${project.projectFolder}/subspace/${this.subspaceName}`; + + // Ensure that this project does not have it's own pnpmfile.cjs or .npmrc file + if (FileSystem.exists(`${project.projectFolder}/.npmrc`)) { + throw new Error( + `The project level configuration file ${project.projectFolder}/.npmrc is no longer valid. Please use a ${subspaceConfigFolderPath}/.npmrc file instead.` + ); + } + if (FileSystem.exists(`${project.projectFolder}/.pnpmfile.cjs`)) { + throw new Error( + `The project level configuration file ${project.projectFolder}/.pnpmfile.cjs is no longer valid. Please use a ${subspaceConfigFolderPath}/.pnpmfile.cjs file instead.` + ); + } + } + + if (!FileSystem.exists(subspaceConfigFolderPath)) { + throw new Error( + `The configuration folder for the "${this.subspaceName}" subspace does not exist: ` + + subspaceConfigFolderPath + ); + } + + subspacePnpmPatchesFolderPath = `${subspaceConfigFolderPath}/${RushConstants.pnpmPatchesCommonFolderName}`; + } else { + // Example: C:\MyRepo\common\config\rush + subspaceConfigFolderPath = rushConfiguration.commonRushConfigFolder; + // Example: C:\MyRepo\common\pnpm-patches + subspacePnpmPatchesFolderPath = `${rushConfiguration.commonFolder}/${RushConstants.pnpmPatchesCommonFolderName}`; + } + + // Example: C:\MyRepo\common\temp + const commonTempFolder: string = + EnvironmentConfiguration.rushTempFolderOverride || rushConfiguration.commonTempFolder; + + let subspaceTempFolderPath: string; + if (rushConfiguration.subspacesFeatureEnabled) { + // Example: C:\MyRepo\common\temp\my-subspace + subspaceTempFolderPath = `${commonTempFolder}/${this.subspaceName}`; + } else { + // Example: C:\MyRepo\common\temp + subspaceTempFolderPath = commonTempFolder; + } + + // Example: C:\MyRepo\common\temp\my-subspace\pnpm-lock.yaml + const tempShrinkwrapFilePath: string = `${subspaceTempFolderPath}/${rushConfiguration.shrinkwrapFilename}`; + + /// From "C:\MyRepo\common\temp\pnpm-lock.yaml" --> "C:\MyRepo\common\temp\pnpm-lock-preinstall.yaml" + const parsedPath: path.ParsedPath = path.parse(tempShrinkwrapFilePath); + const tempShrinkwrapPreinstallFilePath: string = `${parsedPath.dir}/${parsedPath.name}-preinstall${parsedPath.ext}`; + + this._detail = { + subspaceConfigFolderPath, + subspacePnpmPatchesFolderPath, + subspaceTempFolderPath, + tempShrinkwrapFilePath, + tempShrinkwrapPreinstallFilePath + }; + } + return this._detail; + } + + /** + * Returns the full path of the folder containing this subspace's variant-dependent configuration files + * such as `pnpm-lock.yaml`. + * + * 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 + * The following files may be variant-dependent: + * - Lockfiles: (i.e. - `pnpm-lock.yaml`, `npm-shrinkwrap.json`, `yarn.lock`, etc) + * - 'common-versions.json' + * - 'pnpmfile.js'/'.pnpmfile.cjs' + */ + public getVariantDependentSubspaceConfigFolderPath(variant: string | undefined): string { + const subspaceConfigFolderPath: string = this.getSubspaceConfigFolderPath(); + if (!variant) { + return subspaceConfigFolderPath; + } else { + return `${subspaceConfigFolderPath}/${RushConstants.rushVariantsFolderName}/${variant}`; + } + } + + /** + * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. + * + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush` + * @beta + */ + public getSubspaceConfigFolderPath(): string { + return this._ensureDetail().subspaceConfigFolderPath; + } + + /** + * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. + * + * 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 { + return this._ensureDetail().subspacePnpmPatchesFolderPath; + } + + /** + * The full path of the folder where the subspace's node_modules and other temporary files will be stored. + * + * Example (subspaces feature enabled): `C:\MyRepo\common\temp\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\temp` + * @beta + */ + public getSubspaceTempFolderPath(): string { + return this._ensureDetail().subspaceTempFolderPath; + } + + /** + * Returns full path of the temporary shrinkwrap file for a specific subspace and returns the common workspace + * shrinkwrap if no subspaceName is provided. + * @remarks + * This function takes the subspace name, and returns the full path for the subspace's shrinkwrap file. + * This function also consults the deprecated option to allow for shrinkwraps to be stored under a package folder. + * This shrinkwrap file is used during "rush install", and may be rewritten by the package manager during installation + * This property merely reports the filename, the file itself may not actually exist. + * example: `C:\MyRepo\common\\pnpm-lock.yaml` + * @beta + */ + public getTempShrinkwrapFilename(): string { + return this._ensureDetail().tempShrinkwrapFilePath; + } + + /** + * @deprecated - Use {@link Subspace.getTempShrinkwrapPreinstallFilePath} instead. + */ + public getTempShrinkwrapPreinstallFilename(subspaceName?: string | undefined): string { + return this.getTempShrinkwrapPreinstallFilePath(); + } + + /** + * The full path of a backup copy of tempShrinkwrapFilename. This backup copy is made + * before installation begins, and can be compared to determine how the package manager + * modified tempShrinkwrapFilename. + * @remarks + * This property merely reports the filename; the file itself may not actually exist. + * Example: `C:\MyRepo\common\temp\npm-shrinkwrap-preinstall.json` + * or `C:\MyRepo\common\temp\pnpm-lock-preinstall.yaml` + * @beta + */ + public getTempShrinkwrapPreinstallFilePath(): string { + return this._ensureDetail().tempShrinkwrapPreinstallFilePath; + } + + /** + * Gets the full path to the common-versions.json config file for this subspace. + * + * 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 { + return ( + this.getVariantDependentSubspaceConfigFolderPath(variant) + '/' + RushConstants.commonVersionsFilename + ); + } + + /** + * Gets the full path to the pnpm-config.json config file for this subspace. + * + * 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 { + return this.getSubspaceConfigFolderPath() + '/' + RushConstants.pnpmConfigFilename; + } + + /** + * Gets the settings from the common-versions.json config file. + * @beta + */ + public getCommonVersions(variant?: string): CommonVersionsConfiguration { + const commonVersionsFilePath: string = this.getCommonVersionsFilePath(variant); + if (!this._commonVersionsConfiguration) { + this._commonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile( + commonVersionsFilePath, + this._rushConfiguration + ); + } + return this._commonVersionsConfiguration; + } + + /** + * Gets the ensureConsistentVersions property from the common-versions.json config file, + * or from the rush.json file if it isn't defined in common-versions.json + * @beta + */ + public shouldEnsureConsistentVersions(variant?: string): boolean { + // 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 the setting is not defined in + // the common-versions.json file + return this._rushConfiguration.ensureConsistentVersions; + } + + /** + * Gets the path to the repo-state.json file. + * @beta + */ + public getRepoStateFilePath(): string { + return this.getSubspaceConfigFolderPath() + '/' + RushConstants.repoStateFilename; + } + + /** + * Gets the contents from the repo-state.json file. + * @param subspaceName - The name of the subspace in use by the active command. + * @beta + */ + public getRepoState(): RepoStateFile { + const repoStateFilePath: string = this.getRepoStateFilePath(); + return RepoStateFile.loadFromFile(repoStateFilePath); + } + + /** + * @deprecated - Use {@link Subspace.getCommittedShrinkwrapFilePath} instead. + */ + public getCommittedShrinkwrapFilename(): string { + return this.getCommittedShrinkwrapFilePath(undefined); + } + + /** + * Gets the committed shrinkwrap file name for a specific variant. + * @param variant - The name of the current variant in use by the active command. + * @beta + */ + public getCommittedShrinkwrapFilePath(variant?: string): string { + const subspaceConfigFolderPath: string = this.getVariantDependentSubspaceConfigFolderPath(variant); + return `${subspaceConfigFolderPath}/${this._rushConfiguration.shrinkwrapFilename}`; + } + + /** + * Gets the absolute path for "pnpmfile.js" for a specific subspace. + * @param subspace - The name of the current subspace in use by the active command. + * @remarks + * The file path is returned even if PNPM is not configured as the package manager. + * @beta + */ + public getPnpmfilePath(variant?: string): string { + const subspaceConfigFolderPath: string = this.getVariantDependentSubspaceConfigFolderPath(variant); + + const pnpmFilename: string = (this._rushConfiguration.packageManagerWrapper as PnpmPackageManager) + .pnpmfileFilename; + + return `${subspaceConfigFolderPath}/${pnpmFilename}`; + } + + /** + * Returns true if the specified project belongs to this subspace. + * @beta + */ + public contains(project: RushConfigurationProject): boolean { + return project.subspace.subspaceName === this.subspaceName; + } + + /** @internal */ + public _addProject(project: RushConfigurationProject): void { + 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 + */ + public getPackageJsonInjectedDependenciesHash(variant?: string): string | undefined { + const allPackageJson: IPackageJsonLite[] = []; + + const relatedProjects: RushConfigurationProject[] = []; + const subspacePnpmfileShimSettings: ISubspacePnpmfileShimSettings = + SubspacePnpmfileConfiguration.getSubspacePnpmfileShimSettings(this._rushConfiguration, this, variant); + + for (const rushProject of this.getProjects()) { + const injectedDependencies: Array = + subspacePnpmfileShimSettings?.subspaceProjects[rushProject.packageName]?.injectedDependencies || []; + if (injectedDependencies.length === 0) { + continue; + } + + const injectedDependencySet: Set = new Set(injectedDependencies); + + for (const dependencyProject of rushProject.dependencyProjects) { + if (injectedDependencySet.has(dependencyProject.packageName)) { + relatedProjects.push(dependencyProject); + } + } + } + + // this means no injected dependencies found for current subspace + if (relatedProjects.length === 0) { + return undefined; + } + + const allWorkspaceProjectSet: Set = new Set( + this._rushConfiguration.projects.map((rushProject) => rushProject.packageName) + ); + + // get all related package.json + while (relatedProjects.length > 0) { + const rushProject: RushConfigurationProject = relatedProjects.pop()!; + // collect fields that could update the `pnpm-lock.yaml` + const { + name, + bin, + dependencies, + devDependencies, + peerDependencies, + optionalDependencies, + dependenciesMeta, + peerDependenciesMeta, + resolutions + } = rushProject.packageJson; + + // special handing for peerDependencies + // for workspace packages, the version range is meaningless here. + if (peerDependencies) { + for (const packageName of Object.keys(peerDependencies)) { + if (allWorkspaceProjectSet.has(packageName)) { + peerDependencies[packageName] = 'workspace:*'; + } + } + } + + allPackageJson.push({ + name, + bin, + dependencies, + devDependencies, + peerDependencies, + optionalDependencies, + dependenciesMeta, + peerDependenciesMeta, + resolutions + }); + + relatedProjects.push(...rushProject.dependencyProjects); + } + + const collator: Intl.Collator = new Intl.Collator('en'); + allPackageJson.sort((pa, pb) => collator.compare(pa.name, pb.name)); + const hash: crypto.Hash = crypto.createHash('sha1'); + for (const packageFile of allPackageJson) { + hash.update(JSON.stringify(packageFile)); + } + + const packageJsonInjectedDependenciesHash: string = hash.digest('hex'); + + return packageJsonInjectedDependenciesHash; + } +} diff --git a/libraries/rush-lib/src/api/SubspacesConfiguration.ts b/libraries/rush-lib/src/api/SubspacesConfiguration.ts new file mode 100644 index 00000000000..91dbe477be3 --- /dev/null +++ b/libraries/rush-lib/src/api/SubspacesConfiguration.ts @@ -0,0 +1,156 @@ +// 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 type { RushConfiguration } from './RushConfiguration'; +import schemaJson from '../schemas/subspaces.schema.json'; +import { RushConstants } from '../logic/RushConstants'; + +/** + * The allowed naming convention for subspace names. + * Allows for names to be formed of identifiers separated by hyphens (-) + * + * Example: "my-subspace" + */ +export const SUBSPACE_NAME_REGEXP: RegExp = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/; +export const SPLIT_WORKSPACE_SUBSPACE_NAME_REGEXP: RegExp = /^[a-z0-9][+_\-a-z0-9]*$/; + +/** + * This represents the JSON data structure for the "subspaces.json" configuration file. + * See subspace.schema.json for documentation. + */ +export interface ISubspacesConfigurationJson { + subspacesEnabled: boolean; + splitWorkspaceCompatibility?: boolean; + preventSelectingAllSubspaces?: boolean; + subspaceNames: string[]; +} + +/** + * 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. + */ + public readonly subspaceJsonFilePath: string; + + /* + * Determines whether the subspaces feature is enabled. + */ + public readonly subspacesEnabled: boolean; + + /** + * This determines if the subspaces feature supports adding configuration files under the project folder itself + */ + public readonly splitWorkspaceCompatibility: boolean; + + /** + * This determines if selectors are required when installing and building + */ + public readonly preventSelectingAllSubspaces: boolean; + + /** + * A set of the available subspaces + */ + public readonly subspaceNames: ReadonlySet; + + private constructor(configuration: Readonly, subspaceJsonFilePath: string) { + this.subspaceJsonFilePath = subspaceJsonFilePath; + this.subspacesEnabled = configuration.subspacesEnabled; + this.splitWorkspaceCompatibility = !!configuration.splitWorkspaceCompatibility; + this.preventSelectingAllSubspaces = !!configuration.preventSelectingAllSubspaces; + const subspaceNames: Set = new Set(); + for (const subspaceName of configuration.subspaceNames) { + SubspacesConfiguration.requireValidSubspaceName(subspaceName, this.splitWorkspaceCompatibility); + + subspaceNames.add(subspaceName); + } + // Add the default subspace if it wasn't explicitly declared + subspaceNames.add(RushConstants.defaultSubspaceName); + this.subspaceNames = subspaceNames; + } + + /** + * Checks whether the provided string could be used as a subspace name. + * Returns `undefined` if the name is valid; otherwise returns an error message. + * @remarks + * This is a syntax check only; it does not test whether the subspace is actually defined in the Rush configuration. + */ + public static explainIfInvalidSubspaceName( + subspaceName: string, + splitWorkspaceCompatibility: boolean = false + ): string | undefined { + if (subspaceName.length === 0) { + return `The subspace name cannot be empty`; + } + let regexToUse: RegExp; + if (splitWorkspaceCompatibility) { + regexToUse = SPLIT_WORKSPACE_SUBSPACE_NAME_REGEXP; + } else { + regexToUse = SUBSPACE_NAME_REGEXP; + } + if (!regexToUse.test(subspaceName)) { + if (splitWorkspaceCompatibility) { + return ( + `Invalid name "${subspaceName}". ` + + `Subspace names must consist of lowercase letters and numbers separated by hyphens, underscores, or plus signs.` + ); + } + return ( + `Invalid name "${subspaceName}". ` + + `Subspace names must consist of lowercase letters and numbers separated by hyphens.` + ); + } + + return undefined; // name is okay + } + + /** + * Checks whether the provided string could be used as a subspace name. + * If not, an exception is thrown. + * @remarks + * This is a syntax check only; it does not test whether the subspace is actually defined in the Rush configuration. + */ + public static requireValidSubspaceName( + subspaceName: string, + splitWorkspaceCompatibility: boolean = false + ): void { + const message: string | undefined = SubspacesConfiguration.explainIfInvalidSubspaceName( + subspaceName, + splitWorkspaceCompatibility + ); + if (message) { + throw new Error(message); + } + } + + public static tryLoadFromConfigurationFile( + subspaceJsonFilePath: string + ): SubspacesConfiguration | undefined { + let configuration: Readonly | undefined; + try { + configuration = JsonFile.loadAndValidate(subspaceJsonFilePath, SubspacesConfiguration._jsonSchema); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + if (configuration) { + return new SubspacesConfiguration(configuration, subspaceJsonFilePath); + } + } + + public static tryLoadFromDefaultLocation( + rushConfiguration: RushConfiguration + ): SubspacesConfiguration | undefined { + const commonRushConfigFolder: string = rushConfiguration.commonRushConfigFolder; + const subspaceJsonLocation: string = `${commonRushConfigFolder}/${RushConstants.subspacesConfigFilename}`; + return SubspacesConfiguration.tryLoadFromConfigurationFile(subspaceJsonLocation); + } +} diff --git a/libraries/rush-lib/src/api/Variants.ts b/libraries/rush-lib/src/api/Variants.ts new file mode 100644 index 00000000000..06825d73281 --- /dev/null +++ b/libraries/rush-lib/src/api/Variants.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 type { CommandLineStringParameter, ICommandLineStringDefinition } from '@rushstack/ts-command-line'; + +import { EnvironmentVariableNames } from './EnvironmentConfiguration'; +import type { RushConfiguration } from './RushConfiguration'; +import { RushConstants } from '../logic/RushConstants'; + +/** + * Provides the parameter configuration for '--variant'. + */ +export const VARIANT_PARAMETER: ICommandLineStringDefinition = { + parameterLongName: '--variant', + argumentName: 'VARIANT', + description: 'Run command using a variant installation configuration', + environmentVariable: EnvironmentVariableNames.RUSH_VARIANT +}; + +export async function getVariantAsync( + variantsParameter: CommandLineStringParameter | undefined, + rushConfiguration: RushConfiguration, + defaultToCurrentlyInstalledVariant: boolean +): Promise { + let variant: string | undefined = variantsParameter?.value; + if (variant && !rushConfiguration.variants.has(variant)) { + throw new Error(`The variant "${variant}" is not defined in ${RushConstants.rushJsonFilename}`); + } + + if (!variant && defaultToCurrentlyInstalledVariant) { + variant = await rushConfiguration.getCurrentlyInstalledVariantAsync(); + } + + return variant; +} diff --git a/libraries/rush-lib/src/api/VersionPolicy.ts b/libraries/rush-lib/src/api/VersionPolicy.ts new file mode 100644 index 00000000000..f2df9deaf58 --- /dev/null +++ b/libraries/rush-lib/src/api/VersionPolicy.ts @@ -0,0 +1,408 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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, + ILockStepVersionJson, + IIndividualVersionJson, + VersionFormatForCommit, + VersionFormatForPublish +} from './VersionPolicyConfiguration'; +import type { PackageJsonEditor } from './PackageJsonEditor'; +import type { RushConfiguration } from './RushConfiguration'; +import type { RushConfigurationProject } from './RushConfigurationProject'; +import { cloneDeep } from '../utilities/objectUtilities'; + +/** + * Type of version bumps + * @public + * + * @internalRemarks + * This is a copy of the semver ReleaseType enum, but with the `none` value added and + * the `premajor` and `prepatch` omitted. + * See {@link LockStepVersionPolicy._getReleaseType}. + * + * TODO: Consider supporting `premajor` and `prepatch` in the future. + */ +export enum BumpType { + // No version bump + 'none' = 0, + // Prerelease version bump + 'prerelease' = 1, + // Patch version bump + 'patch' = 2, + // Preminor version bump + 'preminor' = 3, + // Minor version bump + 'minor' = 4, + // Major version bump + 'major' = 5 +} + +/** + * Version policy base type names + * @public + */ +export enum VersionPolicyDefinitionName { + 'lockStepVersion', + 'individualVersion' +} + +/** + * This is the base class for version policy which controls how versions get bumped. + * @public + */ +export abstract class VersionPolicy { + /** + * 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 get policyName(): string { + return this._json.policyName; + } + + /** + * Version policy definition name + */ + public get definitionName(): VersionPolicyDefinitionName { + return Enum.getValueByKey(VersionPolicyDefinitionName, this._json.definitionName); + } + + /** + * Determines if a version policy wants to opt out of changelog files. + */ + public get exemptFromRushChange(): boolean { + return this._json.exemptFromRushChange ?? false; + } + + /** + * Determines if a version policy wants to opt in to including email. + */ + public get includeEmailInChangeFile(): boolean { + return this._json.includeEmailInChangeFile ?? false; + } + + /** + * @internal + */ + public constructor(versionPolicyJson: IVersionPolicyJson) { + this._json = versionPolicyJson; + } + + /** + * Loads from version policy json + * + * @param versionPolicyJson - version policy Json + * + * @internal + */ + public static load(versionPolicyJson: IVersionPolicyJson): VersionPolicy | undefined { + const definition: VersionPolicyDefinitionName = Enum.getValueByKey( + VersionPolicyDefinitionName, + versionPolicyJson.definitionName + ); + if (definition === VersionPolicyDefinitionName.lockStepVersion) { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + return new LockStepVersionPolicy(versionPolicyJson as ILockStepVersionJson); + } else if (definition === VersionPolicyDefinitionName.individualVersion) { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + return new IndividualVersionPolicy(versionPolicyJson as IIndividualVersionJson); + } + return undefined; + } + + /** + * Whether it is a lockstepped version policy + */ + public get isLockstepped(): boolean { + return this.definitionName === VersionPolicyDefinitionName.lockStepVersion; + } + + /** + * Returns an updated package json that satisfies the policy. + * + * @param project - package json + * @param force - force update even when the project version is higher than the policy version. + */ + public abstract ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined; + + /** + * Bumps version based on the policy + * + * @param bumpType - (optional) override bump type + * @param identifier - (optional) override prerelease Id + */ + public abstract bump(bumpType?: BumpType, identifier?: string): void; + + /** + * Validates the specified version and throws if the version does not satisfy the policy. + * + * @param versionString - version string + * @param packageName - package name + */ + 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. + */ + public setDependenciesBeforePublish(packageName: string, configuration: RushConfiguration): void { + if (this._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); + } + } + + 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 === '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('*'); + } + } + + packageJsonEditor.saveIfModified(); + } + } +} + +/** + * This policy indicates all related projects should use the same version. + * @public + */ +export class LockStepVersionPolicy extends VersionPolicy { + /** + * @internal + */ + declare public readonly _json: ILockStepVersionJson; + private _version: semver.SemVer; + + /** + * The type of bump for next bump. + */ + // 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 get nextBump(): BumpType | undefined { + return this._json.nextBump !== undefined ? Enum.getValueByKey(BumpType, this._json.nextBump) : undefined; + } + + /** + * The main project for the version policy. + * + * 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 get mainProject(): string | undefined { + return this._json.mainProject; + } + + /** + * @internal + */ + public constructor(versionPolicyJson: ILockStepVersionJson) { + super(versionPolicyJson); + this._version = new semver.SemVer(versionPolicyJson.version); + } + + /** + * The value of the lockstep version + */ + public get version(): string { + return this._version.format(); + } + + /** + * Returns an updated package json that satisfies the version policy. + * + * @param project - input package json + * @param force - force update even when the project version is higher than the policy version. + */ + public ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined { + const packageVersion: semver.SemVer = new semver.SemVer(project.version); + const compareResult: number = packageVersion.compare(this._version); + if (compareResult === 0) { + return undefined; + } else if (compareResult > 0 && !force) { + const errorMessage: string = + `Version ${project.version} in package ${project.name}` + + ` is higher than locked version ${this._version.format()}.`; + throw new Error(errorMessage); + } + return this._updatePackageVersion(project, this._version); + } + + /** + * Bumps the version of the lockstep policy + * + * @param bumpType - Overwrite bump type in version-policy.json with the provided value. + * @param identifier - Prerelease identifier if bump type is prerelease. + */ + public bump(bumpType?: BumpType, identifier?: string): void { + const nextBump: BumpType | undefined = bumpType ?? this.nextBump; + + if (nextBump === undefined) { + // let change files drive version bump. + return; + } + + this._version.inc(this._getReleaseType(nextBump), identifier); + this._json.version = this.version; + } + + /** + * Updates the version of the policy directly with a new value + * @param newVersionString - New version + */ + public update(newVersionString: string): boolean { + const newVersion: semver.SemVer = new semver.SemVer(newVersionString); + if (!newVersion || this._version === newVersion) { + return false; + } + this._version = newVersion; + this._json.version = this.version; + return true; + } + + /** + * Validates the specified version and throws if the version does not satisfy lockstep version. + * + * @param versionString - version string + * @param packageName - package name + */ + public validate(versionString: string, packageName: string): void { + const versionToTest: semver.SemVer = new semver.SemVer(versionString, false); + if (this._version.compare(versionToTest) !== 0) { + throw new Error(`Invalid version ${versionString} in ${packageName}`); + } + } + + private _updatePackageVersion(project: IPackageJson, newVersion: semver.SemVer): IPackageJson { + const updatedProject: IPackageJson = cloneDeep(project); + updatedProject.version = newVersion.format(); + return updatedProject; + } + + private _getReleaseType(bumpType: BumpType): semver.ReleaseType { + // Eventually we should just use ReleaseType and get rid of bump type. + return BumpType[bumpType] as semver.ReleaseType; + } +} + +/** + * This policy indicates all related projects get version bump driven by their own changes. + * @public + */ +export class IndividualVersionPolicy extends VersionPolicy { + /** + * @internal + */ + declare public readonly _json: IIndividualVersionJson; + + /** + * The major version that has been locked + */ + public get lockedMajor(): number | undefined { + return this._json.lockedMajor; + } + + /** + * @internal + */ + public constructor(versionPolicyJson: IIndividualVersionJson) { + super(versionPolicyJson); + } + + /** + * Returns an updated package json that satisfies the version policy. + * + * @param project - input package json + * @param force - force update even when the project version is higher than the policy version. + */ + public ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined { + if (this.lockedMajor) { + const version: semver.SemVer = new semver.SemVer(project.version); + if (version.major < this.lockedMajor) { + const updatedProject: IPackageJson = cloneDeep(project); + updatedProject.version = `${this.lockedMajor}.0.0`; + return updatedProject; + } else if (version.major > this.lockedMajor) { + const errorMessage: string = + `Version ${project.version} in package ${project.name}` + + ` is higher than locked major version ${this.lockedMajor}.`; + throw new Error(errorMessage); + } + } + return undefined; + } + + /** + * Bumps version. + * Individual version policy lets change files drive version bump. This method currently does not do anything. + * + * @param bumpType - bump type + * @param identifier - prerelease id + */ + public bump(bumpType?: BumpType, identifier?: string): void { + // individual version policy lets change files drive version bump. + } + + /** + * Validates the specified version and throws if the version does not satisfy the policy. + * + * @param versionString - version string + * @param packageName - package name + */ + public validate(versionString: string, packageName: string): void { + const versionToTest: semver.SemVer = new semver.SemVer(versionString, false); + if (this.lockedMajor !== undefined) { + if (this.lockedMajor !== versionToTest.major) { + throw new Error(`Invalid major version ${versionString} in ${packageName}`); + } + } + } +} diff --git a/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts b/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts new file mode 100644 index 00000000000..eff69dc2faa --- /dev/null +++ b/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; + +import { VersionPolicy, type BumpType, type LockStepVersionPolicy } from './VersionPolicy'; +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; + dependencies?: IVersionPolicyDependencyJson; + exemptFromRushChange?: boolean; + 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; +} + +/** + * @public + */ +export type VersionFormatForPublish = 'original' | 'exact'; + +/** + * @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; +} + +/** + * 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, + * and how their version numbers will be determined. + * @public + */ +export class VersionPolicyConfiguration { + private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + private _jsonFileName: string; + + /** + * Gets all the version policies + */ + public readonly versionPolicies: Map; + + /** + * @internal + */ + public constructor(jsonFileName: string) { + this._jsonFileName = jsonFileName; + this.versionPolicies = new Map(); + this._loadFile(); + } + + /** + * Validate the version policy configuration against the rush config + */ + public validate(projectsByName: ReadonlyMap): void { + if (!this.versionPolicies) { + return; + } + this.versionPolicies.forEach((policy) => { + const lockStepPolicy: LockStepVersionPolicy = policy as LockStepVersionPolicy; + if (lockStepPolicy.mainProject && !projectsByName.get(lockStepPolicy.mainProject)) { + throw new Error( + `Version policy \"${policy.policyName}\" has a non-existing mainProject:` + + ` ${lockStepPolicy.mainProject}.` + ); + } + }); + } + + /** + * Gets the version policy by its name. + * Throws error if the version policy is not found. + * @param policyName - Name of the version policy + */ + public getVersionPolicy(policyName: string): VersionPolicy { + const policy: VersionPolicy | undefined = this.versionPolicies.get(policyName); + if (!policy) { + throw new Error(`Failed to find version policy by name \'${policyName}\'`); + } + return policy; + } + + /** + * Bumps up versions for the specified version policy or all version policies + * + * @param versionPolicyName - version policy name + * @param bumpType - bump type to override what policy has defined. + * @param identifier - prerelease identifier to override what policy has defined. + * @param shouldCommit - should save to disk + */ + public bump( + versionPolicyName?: string, + bumpType?: BumpType, + identifier?: string, + shouldCommit?: boolean + ): void { + if (versionPolicyName) { + const policy: VersionPolicy | undefined = this.versionPolicies.get(versionPolicyName); + if (policy) { + policy.bump(bumpType, identifier); + } + } else { + this.versionPolicies.forEach((versionPolicy) => { + if (versionPolicy) { + versionPolicy.bump(bumpType, identifier); + } + }); + } + this._saveFile(!!shouldCommit); + } + + /** + * Updates the version directly for the specified version policy + * @param versionPolicyName - version policy name + * @param newVersion - new version + */ + public update(versionPolicyName: string, newVersion: string, shouldCommit?: boolean): void { + const policy: VersionPolicy | undefined = this.versionPolicies.get(versionPolicyName); + if (!policy || !policy.isLockstepped) { + throw new Error(`Lockstep Version policy with name "${versionPolicyName}" cannot be found`); + } + const lockStepVersionPolicy: LockStepVersionPolicy = policy as LockStepVersionPolicy; + const previousVersion: string = lockStepVersionPolicy.version; + if (lockStepVersionPolicy.update(newVersion)) { + // eslint-disable-next-line no-console + console.log(`\nUpdate version policy ${versionPolicyName} from ${previousVersion} to ${newVersion}`); + this._saveFile(!!shouldCommit); + } + } + + private _loadFile(): void { + if (!FileSystem.exists(this._jsonFileName)) { + return; + } + const versionPolicyJson: IVersionPolicyJson[] = JsonFile.loadAndValidate( + this._jsonFileName, + VersionPolicyConfiguration._jsonSchema + ); + + versionPolicyJson.forEach((policyJson) => { + const policy: VersionPolicy | undefined = VersionPolicy.load(policyJson); + if (policy) { + this.versionPolicies.set(policy.policyName, policy); + } + }); + } + + private _saveFile(shouldCommit: boolean): void { + const versionPolicyJson: IVersionPolicyJson[] = []; + this.versionPolicies.forEach((versionPolicy) => { + versionPolicyJson.push(versionPolicy._json); + }); + if (shouldCommit) { + JsonFile.save(versionPolicyJson, this._jsonFileName, { updateExistingFile: true }); + } + } +} diff --git a/apps/rush-lib/src/api/packageManager/NpmPackageManager.ts b/libraries/rush-lib/src/api/packageManager/NpmPackageManager.ts similarity index 82% rename from apps/rush-lib/src/api/packageManager/NpmPackageManager.ts rename to libraries/rush-lib/src/api/packageManager/NpmPackageManager.ts index 7cb4b0b3db7..57b41e9ec3a 100644 --- a/apps/rush-lib/src/api/packageManager/NpmPackageManager.ts +++ b/libraries/rush-lib/src/api/packageManager/NpmPackageManager.ts @@ -10,8 +10,6 @@ import { PackageManager } from './PackageManager'; export class NpmPackageManager extends PackageManager { /** @internal */ public constructor(version: string) { - super(version, 'npm'); - - this._shrinkwrapFilename = RushConstants.npmShrinkwrapFilename; + super(version, 'npm', RushConstants.npmShrinkwrapFilename); } } diff --git a/apps/rush-lib/src/api/packageManager/PackageManager.ts b/libraries/rush-lib/src/api/packageManager/PackageManager.ts similarity index 86% rename from apps/rush-lib/src/api/packageManager/PackageManager.ts rename to libraries/rush-lib/src/api/packageManager/PackageManager.ts index 198769de58d..8376b396ed1 100644 --- a/apps/rush-lib/src/api/packageManager/PackageManager.ts +++ b/libraries/rush-lib/src/api/packageManager/PackageManager.ts @@ -9,7 +9,7 @@ export type PackageManagerName = 'pnpm' | 'npm' | 'yarn'; /** * An abstraction for controlling the supported package managers: PNPM, NPM, and Yarn. - * @beta + * @public */ export abstract class PackageManager { /** @@ -22,21 +22,18 @@ export abstract class PackageManager { */ public readonly version: string; - protected _shrinkwrapFilename: string; - - /** @internal */ - protected constructor(version: string, packageManager: PackageManagerName) { - this.version = version; - this.packageManager = packageManager; - } - /** * The filename of the shrinkwrap file that is used by the package manager. * * @remarks * Example: `npm-shrinkwrap.json` or `pnpm-lock.yaml` */ - public get shrinkwrapFilename(): string { - return this._shrinkwrapFilename; + public readonly shrinkwrapFilename: string; + + /** @internal */ + protected constructor(version: string, packageManager: PackageManagerName, shrinkwrapFilename: string) { + this.version = version; + this.packageManager = packageManager; + this.shrinkwrapFilename = shrinkwrapFilename; } } diff --git a/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts b/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts new file mode 100644 index 00000000000..d00a35c64a1 --- /dev/null +++ b/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.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 * as path from 'node:path'; + +import * as semver from 'semver'; + +import { RushConstants } from '../../logic/RushConstants'; +import { PackageManager } from './PackageManager'; + +/** + * Support for interacting with the PNPM package manager. + */ +export class PnpmPackageManager extends PackageManager { + // example: node_modules/.pnpm/lock.yaml + public readonly internalShrinkwrapRelativePath: string; + + /** + * The filename of the shrinkwrap file that is used by the package manager. + * + * @remarks + * Example: `pnpmfile.js` or `.pnpmfile.cjs` + */ + public readonly pnpmfileFilename: string; + + /** @internal */ + public constructor(version: string) { + super(version, 'pnpm', RushConstants.pnpmV3ShrinkwrapFilename); + + const parsedVersion: semver.SemVer = new semver.SemVer(version); + + if (parsedVersion.major >= 6) { + // Introduced in version 6.0.0 + this.pnpmfileFilename = RushConstants.pnpmfileV6Filename; + } else { + this.pnpmfileFilename = RushConstants.pnpmfileV1Filename; + } + + // node_modules/.pnpm/lock.yaml + // See https://github.com/pnpm/pnpm/releases/tag/v4.0.0 for more details. + this.internalShrinkwrapRelativePath = path.join('node_modules', '.pnpm', 'lock.yaml'); + } +} diff --git a/apps/rush-lib/src/api/packageManager/YarnPackageManager.ts b/libraries/rush-lib/src/api/packageManager/YarnPackageManager.ts similarity index 82% rename from apps/rush-lib/src/api/packageManager/YarnPackageManager.ts rename to libraries/rush-lib/src/api/packageManager/YarnPackageManager.ts index fbdd7629352..601103bc756 100644 --- a/apps/rush-lib/src/api/packageManager/YarnPackageManager.ts +++ b/libraries/rush-lib/src/api/packageManager/YarnPackageManager.ts @@ -10,8 +10,6 @@ import { PackageManager } from './PackageManager'; export class YarnPackageManager extends PackageManager { /** @internal */ public constructor(version: string) { - super(version, 'yarn'); - - this._shrinkwrapFilename = RushConstants.yarnShrinkwrapFilename; + super(version, 'yarn', RushConstants.yarnShrinkwrapFilename); } } diff --git a/libraries/rush-lib/src/api/test/ChangeFile.test.ts b/libraries/rush-lib/src/api/test/ChangeFile.test.ts new file mode 100644 index 00000000000..bbe1b9797fe --- /dev/null +++ b/libraries/rush-lib/src/api/test/ChangeFile.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 { ChangeFile } from '../ChangeFile'; +import { RushConfiguration } from '../RushConfiguration'; +import { ChangeType } from '../ChangeManagement'; + +describe(ChangeFile.name, () => { + it('can add a change', () => { + const rushFilename: string = `${__dirname}/repo/rush-npm.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + const changeFile: ChangeFile = new ChangeFile( + { + packageName: 'a', + changes: [], + email: 'fake@microsoft.com' + }, + rushConfiguration + ); + + changeFile.addChange({ + packageName: 'a', + changeType: ChangeType.minor, + comment: 'for minor' + }); + + changeFile.addChange({ + packageName: 'a', + changeType: ChangeType.patch, + comment: 'for patch' + }); + + expect(changeFile.getChanges('a')).toHaveLength(2); + expect(changeFile.getChanges('a')[0].comment).toEqual('for minor'); + expect(changeFile.getChanges('a')[1].comment).toEqual('for patch'); + }); +}); diff --git a/libraries/rush-lib/src/api/test/CommandLineConfiguration.test.ts b/libraries/rush-lib/src/api/test/CommandLineConfiguration.test.ts new file mode 100644 index 00000000000..6cd9360ed1b --- /dev/null +++ b/libraries/rush-lib/src/api/test/CommandLineConfiguration.test.ts @@ -0,0 +1,297 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { RushConstants } from '../../logic/RushConstants'; +import { + type IPhasedCommandConfig, + CommandLineConfiguration, + type IParameterJson, + type IPhase, + type Command +} from '../CommandLineConfiguration'; + +describe(CommandLineConfiguration.name, () => { + it('Forbids a misnamed phase', () => { + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_faze:A' + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:' + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:0' + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:A' + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:A-' + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + }); + + it('Detects a missing phase', () => { + expect( + () => + new CommandLineConfiguration({ + commands: [ + { + commandKind: 'phased', + name: 'example', + summary: 'example', + description: 'example', + safeForSimultaneousRushProcesses: false, + + enableParallelism: true, + phases: ['_phase:a'] + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + }); + + it('Detects a missing phase dependency', () => { + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:a', + dependencies: { + upstream: ['_phase:b'] + } + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:a', + dependencies: { + self: ['_phase:b'] + } + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + }); + + it('Detects a cycle among phases', () => { + expect( + () => + new CommandLineConfiguration({ + phases: [ + { + name: '_phase:a', + dependencies: { + self: ['_phase:b'] + } + }, + { + name: '_phase:b', + dependencies: { + self: ['_phase:c'] + } + }, + { + name: '_phase:c', + dependencies: { + self: ['_phase:a'] + } + } + ] + }) + ).toThrowErrorMatchingSnapshot(); + }); + + describe('parameters', () => { + it('correctly populates the associatedParameters object for a parameter associated with the "build" command', () => { + const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({ + parameters: [ + { + parameterKind: 'flag', + longName: '--flag', + associatedCommands: ['build'], + description: 'flag' + } + ] + }); + + function validateCommandByName(commandName: string): void { + const command: Command | undefined = commandLineConfiguration.commands.get(commandName); + expect(command).toBeDefined(); + const parametersArray: IParameterJson[] = Array.from(command!.associatedParameters); + expect(parametersArray).toHaveLength(1); + expect(parametersArray[0].longName).toEqual('--flag'); + } + + validateCommandByName(RushConstants.buildCommandName); + validateCommandByName(RushConstants.rebuildCommandName); + }); + + it('correctly populates the associatedParameters object for a parameter associated with a custom bulk command', () => { + const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({ + commands: [ + { + commandKind: 'bulk', + name: 'custom-bulk', + summary: 'custom-bulk', + enableParallelism: true, + safeForSimultaneousRushProcesses: false + } + ], + parameters: [ + { + parameterKind: 'flag', + longName: '--flag', + associatedCommands: ['custom-bulk'], + description: 'flag' + } + ] + }); + + const command: Command | undefined = commandLineConfiguration.commands.get('custom-bulk'); + expect(command).toBeDefined(); + const parametersArray: IParameterJson[] = Array.from(command!.associatedParameters); + expect(parametersArray).toHaveLength(1); + expect(parametersArray[0].longName).toEqual('--flag'); + }); + + it("correctly populates the associatedParameters object for a parameter associated with a custom phased command's phase", () => { + const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({ + commands: [ + { + commandKind: 'phased', + name: 'custom-phased', + summary: 'custom-phased', + enableParallelism: true, + safeForSimultaneousRushProcesses: false, + phases: ['_phase:a'] + } + ], + phases: [ + { + name: '_phase:a' + } + ], + parameters: [ + { + parameterKind: 'flag', + longName: '--flag', + associatedPhases: ['_phase:a'], + associatedCommands: ['custom-phased'], + description: 'flag' + } + ] + }); + + const command: Command | undefined = commandLineConfiguration.commands.get('custom-phased'); + expect(command).toBeDefined(); + const parametersArray: IParameterJson[] = Array.from(command!.associatedParameters); + expect(parametersArray).toHaveLength(1); + expect(parametersArray[0].longName).toEqual('--flag'); + }); + + it('allows a parameter to only be associated with phased commands but not have any associated phases', () => { + const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({ + commands: [ + { + commandKind: 'phased', + name: 'custom-phased', + summary: 'custom-phased', + enableParallelism: true, + safeForSimultaneousRushProcesses: false, + phases: ['_phase:a'] + } + ], + phases: [ + { + name: '_phase:a' + } + ], + parameters: [ + { + parameterKind: 'flag', + longName: '--flag', + associatedCommands: ['custom-phased'], + description: 'flag' + } + ] + }); + + const command: Command | undefined = commandLineConfiguration.commands.get('custom-phased'); + expect(command).toBeDefined(); + const parametersArray: IParameterJson[] = Array.from(command!.associatedParameters); + expect(parametersArray).toHaveLength(1); + expect(parametersArray[0].longName).toEqual('--flag'); + const phase: IPhase | undefined = commandLineConfiguration.phases.get('_phase:a'); + expect(phase).toBeDefined(); + const phaseParametersArray: unknown[] = Array.from(phase!.associatedParameters); + expect(phaseParametersArray).toHaveLength(0); + }); + }); + + describe('shellCommand in bulk command', () => { + it('get "custom-shell-command-echo" command', () => { + const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({ + commands: [ + { + commandKind: 'bulk', + name: 'custom-shell-command-echo', + summary: 'custom define bulk shellCommand echo', + enableParallelism: true, + safeForSimultaneousRushProcesses: false, + shellCommand: 'echo' + } + ] + }); + + const command: IPhasedCommandConfig | undefined = commandLineConfiguration.commands.get( + 'custom-shell-command-echo' + ) as IPhasedCommandConfig; + expect(command).toBeDefined(); + expect(command?.phases).toBeDefined(); + const phase = [...command?.phases][0]; + expect(phase.name).toEqual('custom-shell-command-echo'); + expect(phase.shellCommand).toEqual('echo'); + }); + }); +}); diff --git a/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts b/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts new file mode 100644 index 00000000000..6e6b2553cd9 --- /dev/null +++ b/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CommonVersionsConfiguration } from '../CommonVersionsConfiguration'; +import type { RushConfiguration } from '../RushConfiguration'; + +describe(CommonVersionsConfiguration.name, () => { + it('can load the file', () => { + const filename: string = `${__dirname}/jsonFiles/common-versions.json`; + const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile( + filename, + {} as RushConfiguration + ); + + expect(configuration.preferredVersions.get('@scope/library-1')).toEqual('~3.2.1'); + expect(configuration.allowedAlternativeVersions.get('library-3')).toEqual(['^1.2.3']); + }); + + it('gets `ensureConsistentVersions` from the file if it provides that value', () => { + const filename: string = `${__dirname}/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json`; + const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile(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", () => { + const filename: string = `${__dirname}/jsonFiles/common-versions.json`; + const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile(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', () => { + const filename: string = `${__dirname}/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json`; + expect(() => + CommonVersionsConfiguration.loadFromFile(filename, { + _ensureConsistentVersionsJsonValue: false, + ensureConsistentVersions: false + } as RushConfiguration) + ).toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts b/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts new file mode 100644 index 00000000000..1f6a769653d --- /dev/null +++ b/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile } from '@rushstack/node-core-library'; +import { PrintUtilities, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { CustomTipId, CustomTipsConfiguration, type ICustomTipsJson } from '../CustomTipsConfiguration'; +import { RushConfiguration } from '../RushConfiguration'; + +const LOREM: string = + '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.'; + +describe(CustomTipsConfiguration.name, () => { + it('loads the config file (custom-tips.json)', () => { + const rushFilename: string = `${__dirname}/repo/rush-npm.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + expect(rushConfiguration.customTipsConfiguration.providedCustomTipsByTipId).toMatchSnapshot(); + }); + + it('reports an error for duplicate tips', () => { + expect(() => { + new CustomTipsConfiguration(`${__dirname}/jsonFiles/custom-tips.error.json`); + }).toThrowError('TIP_RUSH_INCONSISTENT_VERSIONS'); + }); + + function runFormattingTests(testName: string, customTipText: string): void { + describe(`formatting (${testName})`, () => { + let customTipsConfiguration: CustomTipsConfiguration; + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + + const CUSTOM_TIP_FOR_TESTING: CustomTipId = CustomTipId.TIP_PNPM_INVALID_NODE_VERSION; + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(true); + terminal = new Terminal(terminalProvider); + + const mockCustomTipsJson: ICustomTipsJson = { + customTips: [ + { + tipId: CUSTOM_TIP_FOR_TESTING, + message: customTipText + } + ] + }; + jest.spyOn(JsonFile, 'loadAndValidate').mockReturnValue(mockCustomTipsJson); + customTipsConfiguration = new CustomTipsConfiguration(''); + + jest.spyOn(PrintUtilities, 'getConsoleWidth').mockReturnValue(60); + }); + + 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)); + } + + 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(); + }); + + const printFunctions = [ + CustomTipsConfiguration.prototype._showTip, + CustomTipsConfiguration.prototype._showInfoTip, + CustomTipsConfiguration.prototype._showWarningTip, + CustomTipsConfiguration.prototype._showErrorTip + ]; + + for (const printFunction of printFunctions) { + it(`${printFunction.name} prints an expected message`, () => { + printFunction.call(customTipsConfiguration, terminal, CUSTOM_TIP_FOR_TESTING); + }); + } + }); + } + + runFormattingTests('a short message', 'This is a test'); + runFormattingTests('a long message', LOREM); + runFormattingTests('a message with newlines', 'This is a test\nThis is a test'); + runFormattingTests('a message with an indented line', 'This is a test\n This is a test'); + runFormattingTests('a long message with an indented line', `${LOREM}\n ${LOREM}`); +}); diff --git a/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts b/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts new file mode 100644 index 00000000000..78f597c2a3d --- /dev/null +++ b/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.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 * as path from 'node:path'; +import { EnvironmentConfiguration } from '../EnvironmentConfiguration'; + +describe(EnvironmentConfiguration.name, () => { + let _oldEnv: typeof process.env; + + beforeEach(() => { + EnvironmentConfiguration.reset(); + _oldEnv = process.env; + process.env = {}; + }); + + afterEach(() => { + process.env = _oldEnv; + }); + + describe(EnvironmentConfiguration.validate.name, () => { + it('correctly allows no environment variables', () => { + expect(EnvironmentConfiguration.validate).not.toThrow(); + }); + + it('allows known environment variables', () => { + process.env['RUSH_TEMP_FOLDER'] = '/var/temp'; // eslint-disable-line dot-notation + expect(EnvironmentConfiguration.validate).not.toThrow(); + }); + + it('does not allow unknown environment variables', () => { + process.env['rush_foobar'] = 'asdf'; // eslint-disable-line dot-notation + expect(EnvironmentConfiguration.validate).toThrow(); + }); + + it('can revalidate after a reset', () => { + process.env['RUSH_TEMP_FOLDER'] = '/var/tempA'; // eslint-disable-line dot-notation + EnvironmentConfiguration.validate({ doNotNormalizePaths: true }); + + expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual('/var/tempA'); + + process.env['RUSH_TEMP_FOLDER'] = '/var/tempB'; // eslint-disable-line dot-notation + EnvironmentConfiguration.validate({ doNotNormalizePaths: true }); + + expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual('/var/tempB'); + }); + }); + + describe('rushTempDirOverride', () => { + it('returns undefined for unset environment variables', () => { + EnvironmentConfiguration.validate(); + + expect(EnvironmentConfiguration.rushTempFolderOverride).not.toBeDefined(); + }); + + it('returns the value for a set environment variable', () => { + const expectedValue: string = '/var/temp'; + process.env['RUSH_TEMP_FOLDER'] = expectedValue; // eslint-disable-line dot-notation + EnvironmentConfiguration.validate({ doNotNormalizePaths: true }); + + expect(EnvironmentConfiguration.rushTempFolderOverride).toEqual(expectedValue); + }); + }); + + describe('binaryOverride', () => { + it('returns undefined for unset environment variables', () => { + EnvironmentConfiguration.validate(); + + expect(EnvironmentConfiguration.gitBinaryPath).not.toBeDefined(); + expect(EnvironmentConfiguration.tarBinaryPath).not.toBeDefined(); + }); + + it('returns the value for a set environment variable', () => { + const gitPath: string = '/usr/bin/git'; + const tarPath: string = '/usr/bin/tar'; + process.env.RUSH_GIT_BINARY_PATH = gitPath; + process.env.RUSH_TAR_BINARY_PATH = tarPath; + EnvironmentConfiguration.validate({ doNotNormalizePaths: true }); + + expect(EnvironmentConfiguration.gitBinaryPath).toEqual(gitPath); + expect(EnvironmentConfiguration.tarBinaryPath).toEqual(tarPath); + }); + }); + + describe('pnpmStorePathOverride', () => { + const ENV_VAR: string = 'RUSH_PNPM_STORE_PATH'; + + it('returns undefined for unset environment variable', () => { + EnvironmentConfiguration.validate(); + + expect(EnvironmentConfiguration.pnpmStorePathOverride).not.toBeDefined(); + }); + + it('returns the expected path from environment variable without normalization', () => { + const expectedValue: string = '/var/temp'; + process.env[ENV_VAR] = expectedValue; + EnvironmentConfiguration.validate({ doNotNormalizePaths: true }); + + expect(EnvironmentConfiguration.pnpmStorePathOverride).toEqual(expectedValue); + }); + + it('returns expected path from environment variable with normalization', () => { + const expectedValue: string = path.resolve(process.cwd(), 'temp'); + const envVar: string = './temp'; + process.env[ENV_VAR] = envVar; + + EnvironmentConfiguration.validate(); + + expect(EnvironmentConfiguration.pnpmStorePathOverride).toEqual(expectedValue); + }); + }); +}); diff --git a/libraries/rush-lib/src/api/test/EventHooks.test.ts b/libraries/rush-lib/src/api/test/EventHooks.test.ts new file mode 100644 index 00000000000..230b762add0 --- /dev/null +++ b/libraries/rush-lib/src/api/test/EventHooks.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 { RushConfiguration } from '../RushConfiguration'; +import { Event, EventHooks } from '../EventHooks'; + +describe(EventHooks.name, () => { + it('loads a post build hook from rush.json', () => { + const rushFilename: string = `${__dirname}/repo/rush-npm.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + expect(rushConfiguration.eventHooks.get(Event.postRushBuild)).toEqual(['do something']); + }); + + it('loads empty rush hooks', () => { + const eventHooks: EventHooks = new EventHooks({}); + expect(eventHooks.get(Event.postRushBuild)).toHaveLength(0); + }); + + it('loads two rush hooks', () => { + const expectedHooks: string[] = ['do one', 'do two']; + const eventHooks: EventHooks = new EventHooks({ + postRushBuild: expectedHooks + }); + const resultHooks: string[] = eventHooks.get(Event.postRushBuild); + expect(resultHooks).toEqual(expectedHooks); + }); +}); diff --git a/libraries/rush-lib/src/api/test/FlagFile.test.ts b/libraries/rush-lib/src/api/test/FlagFile.test.ts new file mode 100644 index 00000000000..017c648aeb1 --- /dev/null +++ b/libraries/rush-lib/src/api/test/FlagFile.test.ts @@ -0,0 +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 path from 'node:path'; +import { FileSystem } from '@rushstack/node-core-library'; + +import { FlagFile } from '../FlagFile'; +import { RushConstants } from '../../logic/RushConstants'; + +const TEMP_DIR_PATH: string = `${__dirname}/temp`; + +describe(FlagFile.name, () => { + beforeEach(() => { + FileSystem.ensureEmptyFolder(TEMP_DIR_PATH); + }); + + afterEach(() => { + FileSystem.ensureEmptyFolder(TEMP_DIR_PATH); + }); + + it('can get correct path', () => { + const flag: FlagFile = new FlagFile(TEMP_DIR_PATH, RushConstants.lastLinkFlagFilename, {}); + expect(path.basename(flag.path)).toEqual(RushConstants.lastLinkFlagFilename + '.flag'); + }); +}); diff --git a/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts new file mode 100644 index 00000000000..32f1859ae74 --- /dev/null +++ b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts @@ -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. + +import * as path from 'node:path'; +import { FileSystem } from '@rushstack/node-core-library'; + +import { LastInstallFlag } from '../LastInstallFlag'; + +const TEMP_DIR_PATH: string = `${__dirname}/temp`; + +describe(LastInstallFlag.name, () => { + beforeEach(() => { + FileSystem.ensureEmptyFolder(TEMP_DIR_PATH); + }); + + afterEach(() => { + FileSystem.ensureEmptyFolder(TEMP_DIR_PATH); + }); + + it('can get correct path', () => { + const flag: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH); + expect(path.basename(flag.path)).toMatchInlineSnapshot(`"last-install.flag"`); + }); + + it('can create and remove a flag in an empty directory', async () => { + // preparation + const flag: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH); + FileSystem.deleteFile(flag.path); + + // test state, should be invalid since the file doesn't exist + await expect(flag.isValidAsync()).resolves.toEqual(false); + + // test creation + await flag.createAsync(); + expect(FileSystem.exists(flag.path)).toEqual(true); + await expect(flag.isValidAsync()).resolves.toEqual(true); + + // test deletion + await flag.clearAsync(); + expect(FileSystem.exists(flag.path)).toEqual(false); + await expect(flag.isValidAsync()).resolves.toEqual(false); + }); + + it('can detect if the last flag was in a different state', async () => { + // preparation + const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { node: '5.0.0' }); + const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { node: '8.9.4' }); + FileSystem.deleteFile(flag1.path); + + // test state, should be invalid since the file doesn't exist + await expect(flag1.isValidAsync()).resolves.toEqual(false); + await expect(flag2.isValidAsync()).resolves.toEqual(false); + + // test creation + await flag1.createAsync(); + expect(FileSystem.exists(flag1.path)).toEqual(true); + await expect(flag1.isValidAsync()).resolves.toEqual(true); + + // the second flag has different state and should be invalid + await expect(flag2.isValidAsync()).resolves.toEqual(false); + + // test deletion + await flag1.clearAsync(); + expect(FileSystem.exists(flag1.path)).toEqual(false); + await expect(flag1.isValidAsync()).resolves.toEqual(false); + await expect(flag2.isValidAsync()).resolves.toEqual(false); + }); + + it('can detect if the last flag was in a corrupted state', async () => { + // preparation, write non-json into flag file + const flag: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH); + FileSystem.writeFile(flag.path, 'sdfjkaklfjksldajgfkld'); + + // test state, should be invalid since the file is not JSON + await expect(flag.isValidAsync()).resolves.toEqual(false); + FileSystem.deleteFile(flag.path); + }); + + it("throws an error if new storePath doesn't match the old one", async () => { + const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { + packageManager: 'pnpm', + storePath: `${TEMP_DIR_PATH}/pnpm-store` + }); + const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { + packageManager: 'pnpm', + storePath: `${TEMP_DIR_PATH}/temp-store` + }); + + await flag1.createAsync(); + await expect(async () => { + await flag2.checkValidAndReportStoreIssuesAsync({ rushVerb: 'install' }); + }).rejects.toThrowError(/PNPM store path/); + }); + + it("doesn't throw an error if conditions for error aren't met", async () => { + const flag1: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { + packageManager: 'pnpm', + storePath: `${TEMP_DIR_PATH}/pnpm-store` + }); + const flag2: LastInstallFlag = new LastInstallFlag(TEMP_DIR_PATH, { + packageManager: 'npm' + }); + + await flag1.createAsync(); + await expect(flag2.checkValidAndReportStoreIssuesAsync({ rushVerb: 'install' })).resolves.not.toThrow(); + await expect(flag2.checkValidAndReportStoreIssuesAsync({ rushVerb: 'install' })).resolves.toEqual(false); + }); +}); diff --git a/libraries/rush-lib/src/api/test/RushCommandLine.test.ts b/libraries/rush-lib/src/api/test/RushCommandLine.test.ts new file mode 100644 index 00000000000..4f0c95f6022 --- /dev/null +++ b/libraries/rush-lib/src/api/test/RushCommandLine.test.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. + +import path from 'node:path'; + +import { RushCommandLine } from '../RushCommandLine'; + +describe(RushCommandLine.name, () => { + it(`Returns a spec`, async () => { + const spec = RushCommandLine.getCliSpec(path.resolve(__dirname, '../../cli/test/repo/')); + expect(spec).toMatchSnapshot(); + }); +}); diff --git a/libraries/rush-lib/src/api/test/RushConfiguration.test.ts b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts new file mode 100644 index 00000000000..f7513eb4a01 --- /dev/null +++ b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts @@ -0,0 +1,334 @@ +// 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 { JsonFile, Path, Text } from '@rushstack/node-core-library'; +import { RushConfiguration } from '../RushConfiguration'; +import type { ApprovedPackagesPolicy } from '../ApprovedPackagesPolicy'; +import { RushConfigurationProject } from '../RushConfigurationProject'; +import { EnvironmentConfiguration } from '../EnvironmentConfiguration'; +import { DependencyType } from '../PackageJsonEditor'; + +function normalizePathForComparison(pathToNormalize: string): string { + return Text.replaceAll(pathToNormalize, '\\', '/').toUpperCase(); +} + +function assertPathProperty(validatedPropertyName: string, absolutePath: string, relativePath: string): void { + const resolvedRelativePath: string = path.resolve(__dirname, relativePath); + expect(normalizePathForComparison(absolutePath)).toEqual(normalizePathForComparison(resolvedRelativePath)); +} + +describe(RushConfiguration.name, () => { + let _oldEnv: typeof process.env; + + beforeEach(() => { + _oldEnv = process.env; + process.env = {}; + + process.env['USERPROFILE'] = _oldEnv['USERPROFILE']; // eslint-disable-line dot-notation + process.env['HOME'] = _oldEnv['HOME']; // eslint-disable-line dot-notation + }); + + afterEach(() => { + process.env = _oldEnv; + jest.resetAllMocks(); + }); + + it("can't load too new rush", () => { + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-too-new.json'); + + expect(() => { + RushConfiguration.loadFromConfigurationFile(rushFilename); + }).toThrow('Unable to load rush-too-new.json because its RushVersion is 99.0.0'); + }); + + it('can load repo/rush-npm.json', () => { + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-npm.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + expect(rushConfiguration.packageManager).toEqual('npm'); + assertPathProperty('commonFolder', rushConfiguration.commonFolder, './repo/common'); + assertPathProperty( + 'commonRushConfigFolder', + rushConfiguration.commonRushConfigFolder, + './repo/common/config/rush' + ); + assertPathProperty('commonTempFolder', rushConfiguration.commonTempFolder, './repo/common/temp'); + assertPathProperty('npmCacheFolder', rushConfiguration.npmCacheFolder, './repo/common/temp/npm-cache'); + assertPathProperty('npmTmpFolder', rushConfiguration.npmTmpFolder, './repo/common/temp/npm-tmp'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); + assertPathProperty( + 'pnpmStorePath', + rushConfiguration.pnpmOptions.pnpmStorePath, + './repo/common/temp/pnpm-store' + ); + assertPathProperty( + 'packageManagerToolFilename', + rushConfiguration.packageManagerToolFilename, + './repo/common/temp/npm-local/node_modules/.bin/npm' + ); + assertPathProperty('rushJsonFolder', rushConfiguration.rushJsonFolder, './repo'); + + expect(rushConfiguration.packageManagerToolVersion).toEqual('4.5.0'); + + expect(rushConfiguration.repositoryUrls).toEqual(['someFakeUrl']); + expect(rushConfiguration.projectFolderMaxDepth).toEqual(99); + expect(rushConfiguration.projectFolderMinDepth).toEqual(1); + expect(rushConfiguration.hotfixChangeEnabled).toEqual(true); + + expect(rushConfiguration.projects).toHaveLength(5); + + // "approvedPackagesPolicy" feature + const approvedPackagesPolicy: ApprovedPackagesPolicy = rushConfiguration.approvedPackagesPolicy; + expect(approvedPackagesPolicy.enabled).toEqual(true); + expect(Array.from(approvedPackagesPolicy.reviewCategories)).toEqual([ + 'first-party', + 'third-party', + 'prototype' + ]); + + expect(Array.from(approvedPackagesPolicy.ignoredNpmScopes)).toEqual(['@types', '@internal']); + + expect(approvedPackagesPolicy.browserApprovedPackages.items[0].packageName).toEqual('example'); + expect(approvedPackagesPolicy.browserApprovedPackages.items[0].allowedCategories.size).toEqual(3); + + expect(rushConfiguration.telemetryEnabled).toBe(false); + + // Validate project1 settings + const project1: RushConfigurationProject = rushConfiguration.getProjectByName('project1')!; + expect(project1).toBeDefined(); + + expect(project1.packageName).toEqual('project1'); + assertPathProperty('project1.projectFolder', project1.projectFolder, './repo/project1'); + expect(project1.tempProjectName).toEqual('@rush-temp/project1'); + expect(project1.unscopedTempProjectName).toEqual('project1'); + expect(project1.skipRushCheck).toEqual(false); + + // Validate project2 settings + const project2: RushConfigurationProject = rushConfiguration.getProjectByName('project2')!; + expect(project2.skipRushCheck).toEqual(true); + }); + + it('can load repo/rush-pnpm.json', () => { + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.shrinkwrapFilename).toEqual('pnpm-lock.yaml'); + assertPathProperty( + 'getPnpmfilePath', + rushConfiguration.defaultSubspace.getPnpmfilePath(undefined), + './repo/common/config/rush/.pnpmfile.cjs' + ); + assertPathProperty('commonFolder', rushConfiguration.commonFolder, './repo/common'); + assertPathProperty( + 'commonRushConfigFolder', + rushConfiguration.commonRushConfigFolder, + './repo/common/config/rush' + ); + assertPathProperty('commonTempFolder', rushConfiguration.commonTempFolder, './repo/common/temp'); + assertPathProperty('npmCacheFolder', rushConfiguration.npmCacheFolder, './repo/common/temp/npm-cache'); + assertPathProperty('npmTmpFolder', rushConfiguration.npmTmpFolder, './repo/common/temp/npm-tmp'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); + assertPathProperty( + 'pnpmStorePath', + rushConfiguration.pnpmOptions.pnpmStorePath, + './repo/common/temp/pnpm-store' + ); + assertPathProperty( + 'packageManagerToolFilename', + rushConfiguration.packageManagerToolFilename, + './repo/common/temp/pnpm-local/node_modules/.bin/pnpm' + ); + assertPathProperty('rushJsonFolder', rushConfiguration.rushJsonFolder, './repo'); + + expect(rushConfiguration.packageManagerToolVersion).toEqual('6.0.0'); + + expect(rushConfiguration.repositoryUrls).toEqual(['someFakeUrl']); + expect(rushConfiguration.projectFolderMaxDepth).toEqual(99); + expect(rushConfiguration.projectFolderMinDepth).toEqual(1); + + expect(rushConfiguration.projects).toHaveLength(3); + + // "approvedPackagesPolicy" feature + const approvedPackagesPolicy: ApprovedPackagesPolicy = rushConfiguration.approvedPackagesPolicy; + expect(approvedPackagesPolicy.enabled).toBe(true); + expect(Array.from(approvedPackagesPolicy.reviewCategories)).toEqual([ + 'first-party', + 'third-party', + 'prototype' + ]); + expect(Array.from(approvedPackagesPolicy.ignoredNpmScopes)).toEqual(['@types', '@internal']); + + expect(approvedPackagesPolicy.browserApprovedPackages.items[0].packageName).toEqual('example'); + expect(approvedPackagesPolicy.browserApprovedPackages.items[0].allowedCategories.size).toEqual(3); + + expect(rushConfiguration.telemetryEnabled).toBe(false); + + // Validate project1 settings + const project1: RushConfigurationProject = rushConfiguration.getProjectByName('project1')!; + expect(project1).toBeDefined(); + + expect(project1.packageName).toEqual('project1'); + assertPathProperty('project1.projectFolder', project1.projectFolder, './repo/project1'); + expect(project1.tempProjectName).toEqual('@rush-temp/project1'); + expect(project1.unscopedTempProjectName).toEqual('project1'); + }); + + it('can load repo/rush-pnpm-5.json', () => { + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm-5.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.packageManagerToolVersion).toEqual('5.0.0'); + expect(rushConfiguration.shrinkwrapFilename).toEqual('pnpm-lock.yaml'); + assertPathProperty( + 'getPnpmfilePath', + rushConfiguration.defaultSubspace.getPnpmfilePath(undefined), + './repo/common/config/rush/pnpmfile.js' + ); + expect(rushConfiguration.repositoryUrls).toEqual(['someFakeUrl', 'otherFakeUrl']); + }); + + it('allows the temp directory to be set via environment variable', () => { + const expectedValue: string = path.resolve('/var/temp'); + process.env['RUSH_TEMP_FOLDER'] = expectedValue; // eslint-disable-line dot-notation + + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + assertPathProperty('commonTempFolder', rushConfiguration.commonTempFolder, expectedValue); + assertPathProperty( + 'npmCacheFolder', + rushConfiguration.npmCacheFolder, + path.join(expectedValue, 'npm-cache') + ); + assertPathProperty('npmTmpFolder', rushConfiguration.npmTmpFolder, path.join(expectedValue, 'npm-tmp')); + + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); + assertPathProperty( + 'pnpmStorePath', + rushConfiguration.pnpmOptions.pnpmStorePath, + path.join(expectedValue, 'pnpm-store') + ); + assertPathProperty( + 'packageManagerToolFilename', + rushConfiguration.packageManagerToolFilename, + `${expectedValue}/pnpm-local/node_modules/.bin/pnpm` + ); + }); + + it('fails to load repo/rush-repository-url-urls.json', () => { + const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-repository-url-urls.json'); + expect(() => RushConfiguration.loadFromConfigurationFile(rushFilename)).toThrowErrorMatchingSnapshot(); + }); + + describe('PNPM Store Paths', () => { + afterEach(() => { + EnvironmentConfiguration['_pnpmStorePathOverride'] = undefined; + }); + + const PNPM_STORE_PATH_ENV: string = 'RUSH_PNPM_STORE_PATH'; + + describe('Loading repo/rush-pnpm-local.json', () => { + const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-local.json'); + + it(`loads the correct path when pnpmStore = "local"`, () => { + const EXPECT_STORE_PATH: string = path.resolve(__dirname, 'repo', 'common', 'temp', 'pnpm-store'); + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); + expect(Path.convertToSlashes(rushConfiguration.pnpmOptions.pnpmStorePath)).toEqual( + Path.convertToSlashes(EXPECT_STORE_PATH) + ); + expect(path.isAbsolute(rushConfiguration.pnpmOptions.pnpmStorePath)).toEqual(true); + }); + + it('loads the correct path when environment variable is defined', () => { + const EXPECT_STORE_PATH: string = path.resolve('/var/temp'); + process.env[PNPM_STORE_PATH_ENV] = EXPECT_STORE_PATH; + + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('local'); + expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); + expect(path.isAbsolute(rushConfiguration.pnpmOptions.pnpmStorePath)).toEqual(true); + }); + }); + + describe('Loading repo/rush-pnpm-global.json', () => { + const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-global.json'); + + it(`loads the correct path when pnpmStore = "global"`, () => { + const EXPECT_STORE_PATH: string = ''; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('global'); + expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); + }); + + it('loads the correct path when environment variable is defined', () => { + const EXPECT_STORE_PATH: string = path.resolve('/var/temp'); + process.env[PNPM_STORE_PATH_ENV] = EXPECT_STORE_PATH; + + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + + expect(rushConfiguration.packageManager).toEqual('pnpm'); + expect(rushConfiguration.pnpmOptions.pnpmStore).toEqual('global'); + expect(rushConfiguration.pnpmOptions.pnpmStorePath).toEqual(EXPECT_STORE_PATH); + }); + }); + + it(`throws an error when invalid pnpmStore is defined`, () => { + const RUSH_JSON_FILENAME: string = path.resolve(__dirname, 'repo', 'rush-pnpm-invalid-store.json'); + expect(() => { + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + }).toThrow(); + }); + }); + + it('reject "pnpmOptions" in rush.json if the file pnpm-config.json exists', () => { + const RUSH_JSON_FILENAME: string = `${__dirname}/pnpmConfigThrow/rush.json`; + expect(() => { + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + }).toThrow( + 'Because the new config file "common/config/rush/pnpm-config.json" is being used, you must remove the old setting "pnpmOptions" from rush.json' + ); + }); + + describe(RushConfigurationProject.name, () => { + it('correctly updates the packageJson property after the packageJson is edited by packageJsonEditor', async () => { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${__dirname}/repo/rush-pnpm.json` + ); + jest.spyOn(JsonFile, 'save').mockImplementation(() => { + /* no-op*/ + return true; + }); + + const project: RushConfigurationProject = rushConfiguration.getProjectByName('project1')!; + + expect(project.packageJson.devDependencies).toMatchSnapshot('devDependencies before'); + expect(Array.from(project.dependencyProjects.values()).map((x) => x.packageName)).toMatchSnapshot( + 'dependencyProjects before' + ); + project.packageJsonEditor.addOrUpdateDependency('project2', '1.0.0', DependencyType.Dev); + project.packageJsonEditor.saveIfModified(); + 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/RushConfigurationProject.test.ts b/libraries/rush-lib/src/api/test/RushConfigurationProject.test.ts new file mode 100644 index 00000000000..c5da537283c --- /dev/null +++ b/libraries/rush-lib/src/api/test/RushConfigurationProject.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 { validateRelativePathField } from '../RushConfigurationProject'; + +describe(validateRelativePathField.name, () => { + it('accepts valid paths', () => { + validateRelativePathField('path/to/project', 'projectFolder', '/rush.json'); + validateRelativePathField('project', 'projectFolder', '/rush.json'); + validateRelativePathField('.', 'projectFolder', '/rush.json'); + validateRelativePathField('..', 'projectFolder', '/rush.json'); + validateRelativePathField('../path/to/project', 'projectFolder', '/rush.json'); + }); + + it('should throw an error if the path is not relative', () => { + expect(() => + validateRelativePathField('C:/path/to/project', 'projectFolder', '/rush.json') + ).toThrowErrorMatchingSnapshot(); + expect(() => + validateRelativePathField('/path/to/project', 'publishFolder', '/rush.json') + ).toThrowErrorMatchingSnapshot(); + }); + + it('should throw an error if the path ends in a trailing slash', () => { + expect(() => + validateRelativePathField('path/to/project/', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + expect(() => + validateRelativePathField('p/', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + }); + + it('should throw an error if the path contains backslashes', () => { + expect(() => + validateRelativePathField('path\\to\\project', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + expect(() => + validateRelativePathField('path\\', 'someOtherField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + }); + + it('should throw an error if the path is not normalized', () => { + expect(() => + validateRelativePathField('path/../to/project', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + expect(() => + validateRelativePathField('path/./to/project', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + expect(() => + validateRelativePathField('./path/to/project', 'someField', '/repo/rush.json') + ).toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts b/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts new file mode 100644 index 00000000000..a1352f49fa1 --- /dev/null +++ b/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts @@ -0,0 +1,251 @@ +// 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 { CommandLineParameter } from '@rushstack/ts-command-line'; + +import type { IPhase } from '../CommandLineConfiguration'; +import type { RushConfigurationProject } from '../RushConfigurationProject'; +import { RushProjectConfiguration } from '../RushProjectConfiguration'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function stripSymbolsFromObject(obj: any | undefined): void { + if (obj) { + for (const key of Reflect.ownKeys(obj)) { + const value: unknown = obj[key]; + if (typeof key === 'symbol') { + delete obj[key]; + } else if (typeof value === 'object') { + stripSymbolsFromObject(value); + } + } + } +} + +async function loadProjectConfigurationAsync( + testProjectName: string +): Promise { + const testFolder: string = `${__dirname}/jsonFiles/${testProjectName}`; + const rushProject: RushConfigurationProject = { + packageName: testProjectName, + projectFolder: testFolder, + projectRelativeFolder: testProjectName + } as RushConfigurationProject; + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + try { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await RushProjectConfiguration.tryLoadForProjectAsync(rushProject, terminal); + if (rushProjectConfiguration?.operationSettingsByOperationName) { + for (const operationSettings of rushProjectConfiguration.operationSettingsByOperationName.values()) { + stripSymbolsFromObject(operationSettings); + } + } + + return rushProjectConfiguration; + } catch (e) { + const errorMessage: string = (e as Error).message + .replace(/\\/g, '/') + .replace(testFolder.replace(/\\/g, '/'), ''); + throw new Error(errorMessage); + } +} + +function validateConfiguration(rushProjectConfiguration: RushProjectConfiguration | undefined): void { + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + if (rushProjectConfiguration) { + try { + rushProjectConfiguration.validatePhaseConfiguration( + Array.from(rushProjectConfiguration.operationSettingsByOperationName.keys()).map( + (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'); + } + } +} + +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.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'); + } + } +} + +describe(RushProjectConfiguration.name, () => { + describe('operationSettingsByOperationName', () => { + it('loads a rush-project.json config that extends another config file', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-a'); + validateConfiguration(rushProjectConfiguration); + + expect(rushProjectConfiguration?.operationSettingsByOperationName).toMatchSnapshot(); + }); + + it('throws an error when loading a rush-project.json config that lists an operation twice', async () => { + await expect( + async () => await loadProjectConfigurationAsync('test-project-b') + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('allows outputFolderNames to be inside subfolders', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + validateConfiguration(rushProjectConfiguration); + + expect(rushProjectConfiguration?.operationSettingsByOperationName).toMatchSnapshot(); + }); + + it('does not allow one outputFolderName to be under another', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-d'); + + expect(() => validateConfiguration(rushProjectConfiguration)).toThrowError(); + }); + + it('validates that parameters in parameterNamesToIgnore exist for the operation', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-e'); + + expect(() => validateConfiguration(rushProjectConfiguration)).toThrowError(); + }); + + 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']) + ).toThrowError(); + }); + + 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']) + ).toThrowError(); + }); + }); + + describe(RushProjectConfiguration.prototype.getCacheDisabledReason.name, () => { + it('Indicates if the build cache is completely disabled', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-a'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([], 'z', false); + expect(reason).toMatchSnapshot(); + }); + + it('Indicates if the phase behavior is not defined', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([], 'z', false); + expect(reason).toMatchSnapshot(); + }); + + it('Indicates if the phase has disabled the cache', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([], '_phase:a', false); + expect(reason).toMatchSnapshot(); + }); + + it('Indicates if tracked files are outputs of the phase', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason( + ['test-project-c/.cache/b/foo'], + '_phase:b', + false + ); + expect(reason).toMatchSnapshot(); + }); + + it('returns undefined if the config is safe', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([''], '_phase:b', false); + expect(reason).toBeUndefined(); + }); + + it('returns undefined if the operation is a no-op', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([''], '_phase:b', true); + expect(reason).toBeUndefined(); + }); + + it('returns reason if the operation is runnable', async () => { + const config: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-c'); + + if (!config) { + throw new Error('Failed to load config'); + } + + const reason: string | undefined = config.getCacheDisabledReason([], '_phase:a', false); + expect(reason).toMatchSnapshot(); + }); + }); +}); 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..b7e01689519 --- /dev/null +++ b/libraries/rush-lib/src/api/test/Subspace.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 * 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(); + }); + }); +}); diff --git a/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts b/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts new file mode 100644 index 00000000000..b2a661d23ce --- /dev/null +++ b/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts @@ -0,0 +1,444 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfigurationProject } from '../RushConfigurationProject'; +import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; +import { PackageJsonEditor } from '../PackageJsonEditor'; +import { CommonVersionsConfiguration } from '../CommonVersionsConfiguration'; +import type { VersionMismatchFinderEntity } from '../../logic/versionMismatch/VersionMismatchFinderEntity'; +import { VersionMismatchFinderProject } from '../../logic/versionMismatch/VersionMismatchFinderProject'; +import { VersionMismatchFinderCommonVersions } from '../../logic/versionMismatch/VersionMismatchFinderCommonVersions'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +describe(VersionMismatchFinder.name, () => { + it('finds no mismatches if there are none', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(0); + expect(mismatchFinder.getMismatches()).toHaveLength(0); + }); + + it('finds a mismatch in two packages', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(1); + expect(mismatchFinder.getMismatches()).toHaveLength(1); + expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); + expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); + }); + + it('ignores cyclic dependencies', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set(['@types/foo']) + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(0); + expect(mismatchFinder.getMismatches()).toHaveLength(0); + }); + + it("won't let you access mismatches that don\t exist", () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.getVersionsOfMismatch('@types/foobar')).toEqual(undefined); + expect(mismatchFinder.getConsumersOfMismatch('@types/fobar', '2.0.0')).toEqual(undefined); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '9.9.9')).toEqual(undefined); + }); + + it('finds two mismatches in two different pairs of projects', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectC: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'C', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + mocha: '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectD: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'D', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + mocha: '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([ + projectA, + projectB, + projectC, + projectD + ]); + expect(mismatchFinder.numberOfMismatches).toEqual(2); + expect(mismatchFinder.getMismatches()).toHaveLength(2); + expect(mismatchFinder.getMismatches()).toMatchObject(['@types/foo', 'mocha']); + expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); + expect(mismatchFinder.getVersionsOfMismatch('mocha')!.sort()).toEqual(['1.2.3', '2.0.0']); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('mocha', '1.2.3')).toEqual([projectC]); + expect(mismatchFinder.getConsumersOfMismatch('mocha', '2.0.0')).toEqual([projectD]); + }); + + it('finds three mismatches in three projects', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectC: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'C', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '9.9.9', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB, projectC]); + expect(mismatchFinder.numberOfMismatches).toEqual(1); + expect(mismatchFinder.getMismatches()).toHaveLength(1); + expect(mismatchFinder.getMismatches()).toMatchObject(['@types/foo']); + expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0', '9.9.9']); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '9.9.9')).toEqual([projectC]); + }); + + it('checks dev dependencies', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + devDependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + + expect(mismatchFinder.numberOfMismatches).toEqual(1); + expect(mismatchFinder.getMismatches()).toHaveLength(1); + expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); + expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); + }); + + it('does not check peer dependencies', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + peerDependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(0); + }); + + it('checks optional dependencies', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + optionalDependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(1); + expect(mismatchFinder.getMismatches()).toHaveLength(1); + expect(mismatchFinder.getMismatches()[0]).toEqual('@types/foo'); + expect(mismatchFinder.getVersionsOfMismatch('@types/foo')!.sort()).toEqual(['1.2.3', '2.0.0']); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '2.0.0')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('@types/foo', '1.2.3')).toEqual([projectA]); + }); + + it('allows alternative versions', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'B', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@types/foo': '2.0.0', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + + const alternatives: Map> = new Map>(); + alternatives.set('@types/foo', ['2.0.0']); + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder( + [projectA, projectB], + alternatives + ); + expect(mismatchFinder.numberOfMismatches).toEqual(0); + expect(mismatchFinder.getMismatches()).toHaveLength(0); + }); + + it('handles the common-versions.json file correctly', () => { + const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ + packageName: 'A', + packageJsonEditor: PackageJsonEditor.fromObject( + { + dependencies: { + '@scope/library-1': '1.2.3', + karma: '0.0.1' + } + } as any, + 'foo.json' + ), + decoupledLocalDependencies: new Set() + } as any as RushConfigurationProject); + const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderCommonVersions( + CommonVersionsConfiguration.loadFromFile(`${__dirname}/jsonFiles/common-versions.json`) + ); + + const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); + expect(mismatchFinder.numberOfMismatches).toEqual(1); + expect(mismatchFinder.getMismatches()).toHaveLength(1); + expect(mismatchFinder.getMismatches()[0]).toEqual('@scope/library-1'); + expect(mismatchFinder.getVersionsOfMismatch('@scope/library-1')!.sort()).toEqual(['1.2.3', '~3.2.1']); + expect(mismatchFinder.getConsumersOfMismatch('@scope/library-1', '~3.2.1')).toEqual([projectB]); + expect(mismatchFinder.getConsumersOfMismatch('@scope/library-1', '1.2.3')).toEqual([projectA]); + }); +}); diff --git a/libraries/rush-lib/src/api/test/VersionPolicy.test.ts b/libraries/rush-lib/src/api/test/VersionPolicy.test.ts new file mode 100644 index 00000000000..738798be560 --- /dev/null +++ b/libraries/rush-lib/src/api/test/VersionPolicy.test.ts @@ -0,0 +1,203 @@ +// 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 ILockStepVersionJson, + VersionPolicyConfiguration, + type IIndividualVersionJson +} from '../VersionPolicyConfiguration'; +import { VersionPolicy, LockStepVersionPolicy, IndividualVersionPolicy, BumpType } from '../VersionPolicy'; + +describe(VersionPolicy.name, () => { + describe(LockStepVersionPolicy.name, () => { + const filename: string = `${__dirname}/jsonFiles/rushWithLockVersion.json`; + const versionPolicyConfig: VersionPolicyConfiguration = new VersionPolicyConfiguration(filename); + let versionPolicy1: VersionPolicy; + let versionPolicy2: VersionPolicy; + + beforeEach(() => { + versionPolicy1 = versionPolicyConfig.getVersionPolicy('testPolicy1'); + versionPolicy2 = versionPolicyConfig.getVersionPolicy('testPolicy2'); + }); + + it('loads configuration.', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy1: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + expect(lockStepVersionPolicy1.version).toEqual('1.1.0'); + expect(lockStepVersionPolicy1.nextBump).toEqual(BumpType.patch); + + expect(versionPolicy2).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy2: LockStepVersionPolicy = versionPolicy2 as LockStepVersionPolicy; + expect(lockStepVersionPolicy2.version).toEqual('1.2.0'); + expect(lockStepVersionPolicy2.nextBump).toEqual(undefined); + }); + + it('skips packageJson if version is already the locked step version', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + expect( + lockStepVersionPolicy.ensure({ + name: 'a', + version: '1.1.0' + }) + ).not.toBeDefined(); + }); + + it('updates packageJson if version is lower than the locked step version', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + const expectedPackageJson: IPackageJson = { + name: 'a', + version: '1.1.0' + }; + const originalPackageJson: IPackageJson = { + name: 'a', + version: '1.0.1' + }; + expect(lockStepVersionPolicy.ensure(originalPackageJson)).toEqual(expectedPackageJson); + }); + + it('throws exception if version is higher than the locked step version', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + const originalPackageJson: IPackageJson = { + name: 'a', + version: '2.1.0' + }; + expect(() => { + lockStepVersionPolicy.ensure(originalPackageJson); + }).toThrow(); + }); + + it('update version with force if version is higher than the locked step version', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + const originalPackageJson: IPackageJson = { + name: 'a', + version: '2.1.0' + }; + const expectedPackageJson: IPackageJson = { + name: 'a', + version: '1.1.0' + }; + expect(lockStepVersionPolicy.ensure(originalPackageJson, true)).toEqual(expectedPackageJson); + }); + + it('doesnt bump version if nextBump is undefined', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy2 as LockStepVersionPolicy; + expect(lockStepVersionPolicy.nextBump).toEqual(undefined); + lockStepVersionPolicy.bump(); + expect(lockStepVersionPolicy.version).toEqual('1.2.0'); + expect(lockStepVersionPolicy.nextBump).toEqual(undefined); + }); + + it('bumps version for preminor release', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + lockStepVersionPolicy.bump(BumpType.preminor, 'pr'); + expect(lockStepVersionPolicy.version).toEqual('1.2.0-pr.0'); + expect(lockStepVersionPolicy.nextBump).toEqual(BumpType.patch); + }); + + it('bumps version for minor release', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + lockStepVersionPolicy.bump(BumpType.minor); + expect(lockStepVersionPolicy.version).toEqual('1.2.0'); + expect(lockStepVersionPolicy.nextBump).toEqual(BumpType.patch); + }); + + it('can update version directly', () => { + expect(versionPolicy1).toBeInstanceOf(LockStepVersionPolicy); + const lockStepVersionPolicy: LockStepVersionPolicy = versionPolicy1 as LockStepVersionPolicy; + const newVersion: string = '1.5.6-beta.0'; + 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, () => { + const fileName: string = `${__dirname}/jsonFiles/rushWithIndividualVersion.json`; + const versionPolicyConfig: VersionPolicyConfiguration = new VersionPolicyConfiguration(fileName); + const versionPolicy: VersionPolicy = versionPolicyConfig.getVersionPolicy('testPolicy2'); + + it('loads configuration', () => { + expect(versionPolicy).toBeInstanceOf(IndividualVersionPolicy); + const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; + expect(individualVersionPolicy.lockedMajor).toEqual(2); + }); + + it('skips packageJson if no need to change', () => { + const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; + expect( + individualVersionPolicy.ensure({ + name: 'a', + version: '2.1.0' + }) + ).not.toBeDefined(); + }); + + it('updates packageJson if version is lower than the locked major', () => { + const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; + const expectedPackageJson: IPackageJson = { + name: 'a', + version: '2.0.0' + }; + const originalPackageJson: IPackageJson = { + name: 'a', + version: '1.0.1' + }; + expect(individualVersionPolicy.ensure(originalPackageJson)).toEqual(expectedPackageJson); + }); + + it('throws exception if version is higher than the locked step version', () => { + const individualVersionPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; + const originalPackageJson: IPackageJson = { + name: 'a', + version: '3.1.0' + }; + expect(() => { + 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 new file mode 100644 index 00000000000..55015a7af18 --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/CommandLineConfiguration.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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"`; + +exports[`CommandLineConfiguration Detects a missing phase 1`] = `"In command-line.json, in the \\"phases\\" property of the \\"example\\" command, the phase \\"_phase:a\\" does not exist."`; + +exports[`CommandLineConfiguration Detects a missing phase dependency 1`] = `"In command-line.json, in the phase \\"_phase:a\\", the upstream dependency phase \\"_phase:b\\" does not exist."`; + +exports[`CommandLineConfiguration Detects a missing phase dependency 2`] = `"In command-line.json, in the phase \\"_phase:a\\", the self dependency phase \\"_phase:b\\" does not exist."`; + +exports[`CommandLineConfiguration Forbids a misnamed phase 1`] = `"In command-line.json, the phase \\"_faze:A\\"'s name is not a valid phase name. Phase names must begin with the required prefix \\"_phase:\\" followed by a name containing lowercase letters, numbers, or hyphens. The name must start with a letter and must not end with a hyphen."`; + +exports[`CommandLineConfiguration Forbids a misnamed phase 2`] = `"In command-line.json, the phase \\"_phase:\\"'s name is not a valid phase name. Phase names must begin with the required prefix \\"_phase:\\" followed by a name containing lowercase letters, numbers, or hyphens. The name must start with a letter and must not end with a hyphen."`; + +exports[`CommandLineConfiguration Forbids a misnamed phase 3`] = `"In command-line.json, the phase \\"_phase:0\\"'s name is not a valid phase name. Phase names must begin with the required prefix \\"_phase:\\" followed by a name containing lowercase letters, numbers, or hyphens. The name must start with a letter and must not end with a hyphen."`; + +exports[`CommandLineConfiguration Forbids a misnamed phase 4`] = `"In command-line.json, the phase \\"_phase:A\\"'s name is not a valid phase name. Phase names must begin with the required prefix \\"_phase:\\" followed by a name containing lowercase letters, numbers, or hyphens. The name must start with a letter and must not end with a hyphen."`; + +exports[`CommandLineConfiguration Forbids a misnamed phase 5`] = `"In command-line.json, the phase \\"_phase:A-\\"'s name is not a valid phase name. Phase names must begin with the required prefix \\"_phase:\\" followed by a name containing lowercase letters, numbers, or hyphens. The name must start with a letter and must not end with a hyphen."`; 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 new file mode 100644 index 00000000000..8e95091dcea --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/CommonVersionsConfiguration.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 new file mode 100644 index 00000000000..3aa0dc6648d --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/CustomTipsConfiguration.test.ts.snap @@ -0,0 +1,604 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +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 ---", + "", + "--------------------", +] +`; + +exports[`CustomTipsConfiguration loads the config file (custom-tips.json) 1`] = ` +Map { + "TIP_RUSH_INCONSISTENT_VERSIONS" => Object { + "message": "This is so wrong my friend. Please read this doc for more information: google.com", + "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + }, +} +`; 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 new file mode 100644 index 00000000000..c47899ac293 --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap @@ -0,0 +1,1652 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RushCommandLine Returns a spec 1`] = ` +Object { + "actions": Array [ + Object { + "actionName": "add", + "parameters": Array [ + Object { + "description": "If specified, the \\"rush update\\" command will not be run after updating the package.json files.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--skip-update", + "required": false, + "shortName": "-s", + }, + Object { + "description": "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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--package", + "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, + "kind": "Flag", + "longName": "--exact", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, the SemVer specifier added to the package.json will be a prepended with a \\"caret\\" specifier (\\"^\\").", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--caret", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, the package will be added to the \\"devDependencies\\" section of the package.json", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--dev", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, the package will be added to the \\"peerDependencies\\" section of the package.json", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--peer", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, other packages with this dependency will have their package.json files updated to use the same version of the dependency.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--make-consistent", + "required": false, + "shortName": "-m", + }, + ], + }, + Object { + "actionName": "change", + "parameters": Array [ + Object { + "description": "Verify the change file has been generated and that it is a valid JSON file", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verify", + "required": false, + "shortName": "-v", + }, + Object { + "description": "Skips fetching the baseline branch before running \\"git diff\\" to detect changes.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--no-fetch", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this parameter is specified, compare the checked out branch with the specified branch to determine which projects were changed. If this parameter is not specified, the checked out branch is compared against the \\"main\\" branch.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--target-branch", + "required": false, + "shortName": "-b", + }, + Object { + "description": "If a changefile already exists, overwrite without prompting (or erroring in --bulk mode).", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--overwrite", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified generated changefiles will be commited automatically.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--commit", + "required": false, + "shortName": "-c", + }, + Object { + "description": "If this parameter is specified generated changefiles will be commited automatically with the specified commit message.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--commit-message", + "required": false, + "shortName": undefined, + }, + Object { + "description": "The email address to use in changefiles. If this parameter is not provided, the email address will be detected or prompted for in interactive mode.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--email", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified, apply the same change message and bump type to all changed projects. The --message and the --bump-type parameters must be specified if the --bulk parameter is specified", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--bulk", + "required": false, + "shortName": undefined, + }, + Object { + "description": "The message to apply to all changed projects if the --bulk flag is provided.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--message", + "required": false, + "shortName": undefined, + }, + Object { + "description": "The bump type to apply to all changed projects if the --bulk flag is provided.", + "environmentVariable": undefined, + "kind": "Choice", + "longName": "--bump-type", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "check", + "parameters": Array [ + Object { + "description": "If this flag is specified, output will be in JSON format.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--json", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified, long lists of package names will not be truncated. This has no effect if the --json flag is also specified.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verbose", + "required": false, + "shortName": undefined, + }, + Object { + "description": "(EXPERIMENTAL) Specifies an individual Rush subspace to check, requiring versions to be consistent only within that subspace (ignoring other subspaces). This parameter is required when the \\"subspacesEnabled\\" setting is set to true in subspaces.json.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--subspace", + "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 { + "actionName": "deploy", + "parameters": Array [ + Object { + "description": "Specifies the name of the main Rush project to be deployed. It must appear in the \\"deploymentProjectNames\\" setting in the deployment config file.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--project", + "required": false, + "shortName": "-p", + }, + Object { + "description": "By default, the deployment configuration is specified in \\"common/config/rush/deploy.json\\". You can use \\"--scenario\\" to specify an alternate name. The name must be lowercase and separated by dashes. For example, if SCENARIO_NAME is \\"web\\", then the config file would be \\"common/config/rush/deploy-web.json\\".", + "environmentVariable": undefined, + "kind": "String", + "longName": "--scenario", + "required": false, + "shortName": "-s", + }, + Object { + "description": "By default, deployment will fail if the target folder is not empty. SPECIFYING THIS FLAG WILL RECURSIVELY DELETE EXISTING CONTENTS OF THE TARGET FOLDER.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--overwrite", + "required": false, + "shortName": undefined, + }, + Object { + "description": "By default, files are deployed to the \\"common/deploy\\" folder inside the Rush repo. Use this parameter to specify a different location. WARNING: USE CAUTION WHEN COMBINING WITH \\"--overwrite\\"", + "environmentVariable": "RUSH_DEPLOY_TARGET_FOLDER", + "kind": "String", + "longName": "--target-folder", + "required": false, + "shortName": "-t", + }, + Object { + "description": "If specified, after the deployment has been prepared, \\"rush deploy\\" will create an archive containing the contents of the target folder. The newly created archive file will be placed according to the designated path, relative to the target folder. Supported file extensions: .zip", + "environmentVariable": undefined, + "kind": "String", + "longName": "--create-archive", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, \\"rush deploy\\" will only create an archive containing the contents of the target folder. The target folder will not be modified other than to create the archive file.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--create-archive-only", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "init", + "parameters": Array [ + Object { + "description": "By default \\"rush init\\" will not overwrite existing config files. Specify this switch to override that. This can be useful when upgrading your repo to a newer release of Rush. WARNING: USE WITH CARE!", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--overwrite-existing", + "required": false, + "shortName": undefined, + }, + Object { + "description": "When copying the template config files, this uncomments fragments that are used by the \\"rush-example\\" GitHub repo, which is a sample monorepo that illustrates many Rush features. This option is primarily intended for maintaining that example.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--rush-example-repo", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Include features that may not be complete features, useful for demoing specific future features or current work in progress features.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--include-experiments", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "init-autoinstaller", + "parameters": Array [ + Object { + "description": "Specifies the name of the autoinstaller folder, which must conform to the naming rules for NPM packages.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--name", + "required": true, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "init-deploy", + "parameters": Array [ + Object { + "description": "Specifies the name of the main Rush project to be deployed in this scenario. It will be added to the \\"deploymentProjectNames\\" setting.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--project", + "required": true, + "shortName": "-p", + }, + Object { + "description": "By default, the deployment configuration will be written to \\"common/config/rush/deploy.json\\". You can use \\"--scenario\\" to specify an alternate name. The name must be lowercase and separated by dashes. For example, if the name is \\"web\\", then the config file would be \\"common/config/rush/deploy-web.json\\".", + "environmentVariable": undefined, + "kind": "String", + "longName": "--scenario", + "required": false, + "shortName": "-s", + }, + ], + }, + Object { + "actionName": "init-subspace", + "parameters": Array [ + Object { + "description": "The name of the subspace that is being initialized.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--name", + "required": true, + "shortName": "-n", + }, + ], + }, + Object { + "actionName": "install", + "parameters": Array [ + Object { + "description": "Perform \\"rush purge\\" before starting the installation", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--purge", + "required": false, + "shortName": "-p", + }, + Object { + "description": "Overrides enforcement of the \\"gitPolicy\\" rules from rush.json (use honorably!)", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--bypass-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If \\"--no-link\\" is specified, then project symlinks will NOT be created after the installation completes. You will need to run \\"rush link\\" manually. This flag is useful for automated builds that want to report stages individually or perform extra operations in between the two stages. This flag is not supported when using workspaces.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--no-link", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, limits the maximum number of concurrent network requests. This is useful when troubleshooting network failures.", + "environmentVariable": undefined, + "kind": "Integer", + "longName": "--network-concurrency", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Activates verbose logging for the package manager. You will probably want to pipe the output of Rush to a file when using this command.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--debug-package-manager", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Overrides the default maximum number of install attempts.", + "environmentVariable": undefined, + "kind": "Integer", + "longName": "--max-install-attempts", + "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, + "kind": "Flag", + "longName": "--ignore-hooks", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Enables installation to be performed without internet access. PNPM will instead report an error if the necessary NPM packages cannot be obtained from the local cache. For details, see the documentation for PNPM's \\"--offline\\" parameter.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--offline", + "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": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to", + "required": false, + "shortName": "-t", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--to-except\\" parameter expands this selection to include all dependencies of PROJECT, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-except", + "required": false, + "shortName": "-T", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--from\\" parameter expands this selection to include PROJECT and all projects that depend on it, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from", + "required": false, + "shortName": "-f", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--only\\" parameter expands this selection to include PROJECT; its dependencies are not added. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--only", + "required": false, + "shortName": "-o", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by\\" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by", + "required": false, + "shortName": "-i", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by-except\\" parameter works the same as \\"--impacted-by\\" except that PROJECT itself is not added to the selection. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by-except", + "required": false, + "shortName": "-I", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--to-version-policy\\" parameter is equivalent to specifying \\"--to\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--from-version-policy\\" parameter is equivalent to specifying \\"--from\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "(EXPERIMENTAL) Specifies a Rush subspace to be installed. Requires the \\"subspacesEnabled\\" feature to be enabled in subspaces.json.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--subspace", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Only check the validity of the shrinkwrap file without performing an install.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--check-only", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Only perform dependency resolution, useful for ensuring peer dependendencies are up to date. Note that this flag is only supported when using the pnpm package manager.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--resolution-only", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "link", + "parameters": Array [ + Object { + "description": "Deletes and recreates all links, even if the filesystem state seems to indicate that this is unnecessary.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--force", + "required": false, + "shortName": "-f", + }, + ], + }, + Object { + "actionName": "list", + "parameters": Array [ + Object { + "description": "If this flag is specified, the project version will be displayed in a column along with the package name.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--version", + "required": false, + "shortName": "-v", + }, + Object { + "description": "If this flag is specified, the project path will be displayed in a column along with the package name.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--path", + "required": false, + "shortName": "-p", + }, + Object { + "description": "If this flag is specified, the project full path will be displayed in a column along with the package name.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--full-path", + "required": false, + "shortName": undefined, + }, + Object { + "description": "For the non --json view, if this flag is specified, include path (-p), version (-v) columns along with the project's applicable: versionPolicy, versionPolicyName, shouldPublish, reviewPolicy, and tags fields.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--detailed", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified, output will be in JSON format.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--json", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to", + "required": false, + "shortName": "-t", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--to-except\\" parameter expands this selection to include all dependencies of PROJECT, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-except", + "required": false, + "shortName": "-T", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--from\\" parameter expands this selection to include PROJECT and all projects that depend on it, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from", + "required": false, + "shortName": "-f", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--only\\" parameter expands this selection to include PROJECT; its dependencies are not added. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--only", + "required": false, + "shortName": "-o", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by\\" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by", + "required": false, + "shortName": "-i", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by-except\\" parameter works the same as \\"--impacted-by\\" except that PROJECT itself is not added to the selection. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by-except", + "required": false, + "shortName": "-I", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--to-version-policy\\" parameter is equivalent to specifying \\"--to\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--from-version-policy\\" parameter is equivalent to specifying \\"--from\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from-version-policy", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "publish", + "parameters": Array [ + Object { + "description": "If this flag is specified, the change requests will be applied to package.json files.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--apply", + "required": false, + "shortName": "-a", + }, + Object { + "description": "If this flag is specified, applied changes and deleted change requests will be committed and merged into the target branch.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--target-branch", + "required": false, + "shortName": "-b", + }, + Object { + "description": "If this flag is specified, applied changes will be published to the NPM registry.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--publish", + "required": false, + "shortName": "-p", + }, + Object { + "description": "Adds commit author and hash to the changelog.json files for each change.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--add-commit-details", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Regenerates all changelog files based on the current JSON content.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--regenerate-changelogs", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Publishes to a specified NPM registry. If this is specified, it will prevent the current commit will not be tagged.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--registry", + "required": false, + "shortName": "-r", + }, + Object { + "description": "(DEPRECATED) Specifies the authentication token to use during publishing. This parameter is deprecated because command line parameters may be readable by unrelated processes on a lab machine. Instead, a safer practice is to pass the token via an environment variable and reference it from your common/config/rush/.npmrc-publish file.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--npm-auth-token", + "required": false, + "shortName": "-n", + }, + Object { + "description": "The tag option to pass to npm publish. By default NPM will publish using the 'latest' tag, even if the package is older than the current latest, so in publishing workflows for older releases, providing a tag is important. When hotfix changes are made, this parameter defaults to 'hotfix'.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--tag", + "required": false, + "shortName": "-t", + }, + Object { + "description": "By default, when Rush invokes \\"npm publish\\" it will publish scoped packages with an access level of \\"restricted\\". Scoped packages can be published with an access level of \\"public\\" by specifying that value for this flag with the initial publication. NPM always publishes unscoped packages with an access level of \\"public\\". For more information, see the NPM documentation for the \\"--access\\" option of \\"npm publish\\".", + "environmentVariable": undefined, + "kind": "Choice", + "longName": "--set-access-level", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Packs projects into tarballs instead of publishing to npm repository. It can only be used when --include-all is specified. If this flag is specified, NPM registry related parameters will be ignored.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--pack", + "required": false, + "shortName": undefined, + }, + Object { + "description": "This parameter is used with --pack parameter to provide customized location for the tarballs instead of the default value. ", + "environmentVariable": undefined, + "kind": "String", + "longName": "--release-folder", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified, all packages with shouldPublish=true in rush.json or with a specified version policy will be published if their version is newer than published version.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--include-all", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Version policy name. Only projects with this version policy will be published if used with --include-all.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Bump up to a prerelease version with the provided prerelease name. Cannot be used with --suffix", + "environmentVariable": undefined, + "kind": "String", + "longName": "--prerelease-name", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Used with --prerelease-name. Only bump packages to a prerelease version if they have changes.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--partial-prerelease", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Append a suffix to all changed versions. Cannot be used with --prerelease-name.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--suffix", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified with --publish, packages will be published with --force on npm", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--force", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified with --publish and --pack, git tags will be applied for packages as if a publish was being run without --pack.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--apply-git-tags-on-pack", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Used in conjunction with git tagging -- apply git tags at the commit hash specified. If not provided, the current HEAD will be tagged.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--commit", + "required": false, + "shortName": "-c", + }, + Object { + "description": "Skips execution of all git hooks. Make sure you know what you are skipping.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--ignore-git-hooks", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "purge", + "parameters": Array [ + Object { + "description": "(UNSAFE!) Also delete shared files such as the package manager instances stored in the \\".rush\\" folder in the user's home directory. This is a more aggressive fix that is NOT SAFE to run in a live environment because it will cause other concurrent Rush processes to fail.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--unsafe", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "remove", + "parameters": Array [ + Object { + "description": "If specified, the \\"rush update\\" command will not be run after updating the package.json files.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--skip-update", + "required": false, + "shortName": "-s", + }, + Object { + "description": "The name of the package which should be removed. To remove multiple packages, run \\"rush remove --package foo --package bar\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--package", + "required": true, + "shortName": "-p", + }, + Object { + "description": "If specified, the dependency will be removed from all projects that declare it.", + "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 { + "actionName": "scan", + "parameters": Array [ + Object { + "description": "If this flag is specified, output will be in JSON format.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--json", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If this flag is specified, output will list all detected dependencies.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--all", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "setup", + "parameters": Array [], + }, + Object { + "actionName": "unlink", + "parameters": Array [], + }, + Object { + "actionName": "update", + "parameters": Array [ + Object { + "description": "Perform \\"rush purge\\" before starting the installation", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--purge", + "required": false, + "shortName": "-p", + }, + Object { + "description": "Overrides enforcement of the \\"gitPolicy\\" rules from rush.json (use honorably!)", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--bypass-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If \\"--no-link\\" is specified, then project symlinks will NOT be created after the installation completes. You will need to run \\"rush link\\" manually. This flag is useful for automated builds that want to report stages individually or perform extra operations in between the two stages. This flag is not supported when using workspaces.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--no-link", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, limits the maximum number of concurrent network requests. This is useful when troubleshooting network failures.", + "environmentVariable": undefined, + "kind": "Integer", + "longName": "--network-concurrency", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Activates verbose logging for the package manager. You will probably want to pipe the output of Rush to a file when using this command.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--debug-package-manager", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Overrides the default maximum number of install attempts.", + "environmentVariable": undefined, + "kind": "Integer", + "longName": "--max-install-attempts", + "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, + "kind": "Flag", + "longName": "--ignore-hooks", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Enables installation to be performed without internet access. PNPM will instead report an error if the necessary NPM packages cannot be obtained from the local cache. For details, see the documentation for PNPM's \\"--offline\\" parameter.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--offline", + "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": "Normally \\"rush update\\" tries to preserve your existing installed versions and only makes the minimum updates needed to satisfy the package.json files. This conservative approach prevents your PR from getting involved with package updates that are unrelated to your work. Use \\"--full\\" when you really want to update all dependencies to the latest SemVer-compatible version. This should be done periodically by a person or robot whose role is to deal with potential upgrade regressions.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--full", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If the shrinkwrap file appears to already satisfy the package.json files, then \\"rush update\\" will skip invoking the package manager at all. In certain situations this heuristic may be inaccurate. Use the \\"--recheck\\" flag to force the package manager to process the shrinkwrap file. This will also update your shrinkwrap file with Rush's fixups. (To minimize shrinkwrap churn, these fixups are normally performed only in the temporary folder.)", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--recheck", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "install-autoinstaller", + "parameters": Array [ + Object { + "description": "The name of the autoinstaller, which must be one of the folders under common/autoinstallers.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--name", + "required": true, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "update-autoinstaller", + "parameters": Array [ + Object { + "description": "The name of the autoinstaller, which must be one of the folders under common/autoinstallers.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--name", + "required": true, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "update-cloud-credentials", + "parameters": Array [ + Object { + "description": "Run the credential update operation in interactive mode, if supported by the provider.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--interactive", + "required": false, + "shortName": "-i", + }, + Object { + "description": "A static credential, to be cached.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--credential", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, delete stored credentials.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--delete", + "required": false, + "shortName": "-d", + }, + ], + }, + Object { + "actionName": "upgrade-interactive", + "parameters": Array [ + Object { + "description": "When upgrading dependencies from a single project, also upgrade dependencies from other projects.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--make-consistent", + "required": false, + "shortName": undefined, + }, + Object { + "description": "If specified, the \\"rush update\\" command will not be run after updating the package.json files.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--skip-update", + "required": false, + "shortName": "-s", + }, + Object { + "description": "Run command using a variant installation configuration", + "environmentVariable": "RUSH_VARIANT", + "kind": "String", + "longName": "--variant", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "version", + "parameters": Array [ + Object { + "description": "If this flag is specified, changes will be committed and merged into the target branch.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--target-branch", + "required": false, + "shortName": "-b", + }, + Object { + "description": "Updates package versions if needed to satisfy version policies.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--ensure-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Override the version in the specified --version-policy. This setting only works for lock-step version policy and when --ensure-version-policy is specified.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--override-version", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Bumps package version based on version policies.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--bump", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Overrides \\"gitPolicy\\" enforcement (use honorably!)", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--bypass-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "The name of the version policy", + "environmentVariable": undefined, + "kind": "String", + "longName": "--version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Overrides the bump type in the version-policy.json for the specified version policy. Valid BUMPTYPE values include: prerelease, patch, preminor, minor, major. This setting only works for lock-step version policy in bump action.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--override-bump", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Overrides the prerelease identifier in the version value of version-policy.json for the specified version policy. This setting only works for lock-step version policy. This setting increases to new prerelease id when \\"--bump\\" is provided but only replaces the prerelease name when \\"--ensure-version-policy\\" is provided.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--override-prerelease-id", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Skips execution of all git hooks. Make sure you know what you are skipping.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--ignore-git-hooks", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "alert", + "parameters": Array [ + Object { + "description": "Temporarily suspend the specified alert for one week", + "environmentVariable": undefined, + "kind": "String", + "longName": "--snooze", + "required": false, + "shortName": "-s", + }, + Object { + "description": "Combined with \\"--snooze\\", causes that alert to be suspended permanently", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--forever", + "required": false, + "shortName": undefined, + }, + ], + }, + 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.", + "environmentVariable": "RUSH_PARALLELISM", + "kind": "String", + "longName": "--parallelism", + "required": false, + "shortName": "-p", + }, + Object { + "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.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--timeline", + "required": false, + "shortName": undefined, + }, + Object { + "description": "(EXPERIMENTAL) Before the build starts, log information about the cobuild state. This will include information about clusters and the projects that are part of each cluster.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--log-cobuild-plan", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to", + "required": false, + "shortName": "-t", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--to-except\\" parameter expands this selection to include all dependencies of PROJECT, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-except", + "required": false, + "shortName": "-T", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--from\\" parameter expands this selection to include PROJECT and all projects that depend on it, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from", + "required": false, + "shortName": "-f", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--only\\" parameter expands this selection to include PROJECT; its dependencies are not added. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--only", + "required": false, + "shortName": "-o", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by\\" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by", + "required": false, + "shortName": "-i", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by-except\\" parameter works the same as \\"--impacted-by\\" except that PROJECT itself is not added to the selection. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by-except", + "required": false, + "shortName": "-I", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--to-version-policy\\" parameter is equivalent to specifying \\"--to\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--from-version-policy\\" parameter is equivalent to specifying \\"--from\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Display the logs during the build, rather than just displaying the build status summary", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verbose", + "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, + "kind": "Flag", + "longName": "--ignore-hooks", + "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, + "kind": "Choice", + "longName": "--locale", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "upload", + "parameters": Array [ + Object { + "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", + "environmentVariable": undefined, + "kind": "Choice", + "longName": "--locale", + "required": false, + "shortName": undefined, + }, + ], + }, + 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.", + "environmentVariable": "RUSH_PARALLELISM", + "kind": "String", + "longName": "--parallelism", + "required": false, + "shortName": "-p", + }, + Object { + "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.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--timeline", + "required": false, + "shortName": undefined, + }, + Object { + "description": "(EXPERIMENTAL) Before the build starts, log information about the cobuild state. This will include information about clusters and the projects that are part of each cluster.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--log-cobuild-plan", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to", + "required": false, + "shortName": "-t", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--to-except\\" parameter expands this selection to include all dependencies of PROJECT, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-except", + "required": false, + "shortName": "-T", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--from\\" parameter expands this selection to include PROJECT and all projects that depend on it, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from", + "required": false, + "shortName": "-f", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--only\\" parameter expands this selection to include PROJECT; its dependencies are not added. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--only", + "required": false, + "shortName": "-o", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by\\" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by", + "required": false, + "shortName": "-i", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by-except\\" parameter works the same as \\"--impacted-by\\" except that PROJECT itself is not added to the selection. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by-except", + "required": false, + "shortName": "-I", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--to-version-policy\\" parameter is equivalent to specifying \\"--to\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--from-version-policy\\" parameter is equivalent to specifying \\"--from\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Display the logs during the build, rather than just displaying the build status summary", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verbose", + "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, + "kind": "Flag", + "longName": "--changed-projects-only", + "required": false, + "shortName": "-c", + }, + Object { + "description": "Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--ignore-hooks", + "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, + "kind": "Flag", + "longName": "--ship", + "required": false, + "shortName": "-s", + }, + Object { + "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--minimal", + "required": false, + "shortName": "-m", + }, + ], + }, + 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.", + "environmentVariable": "RUSH_PARALLELISM", + "kind": "String", + "longName": "--parallelism", + "required": false, + "shortName": "-p", + }, + Object { + "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.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--timeline", + "required": false, + "shortName": undefined, + }, + Object { + "description": "(EXPERIMENTAL) Before the build starts, log information about the cobuild state. This will include information about clusters and the projects that are part of each cluster.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--log-cobuild-plan", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to", + "required": false, + "shortName": "-t", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--to-except\\" parameter expands this selection to include all dependencies of PROJECT, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-except", + "required": false, + "shortName": "-T", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--from\\" parameter expands this selection to include PROJECT and all projects that depend on it, 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from", + "required": false, + "shortName": "-f", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--only\\" parameter expands this selection to include PROJECT; its dependencies are not added. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--only", + "required": false, + "shortName": "-o", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by\\" parameter expands this selection to include PROJECT and any projects that depend on PROJECT (and thus might be broken by changes to PROJECT). \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by", + "required": false, + "shortName": "-i", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. Each \\"--impacted-by-except\\" parameter works the same as \\"--impacted-by\\" except that PROJECT itself is not added to the selection. \\".\\" 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\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--impacted-by-except", + "required": false, + "shortName": "-I", + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--to-version-policy\\" parameter is equivalent to specifying \\"--to\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--to-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Normally all projects in the monorepo will be processed; adding this parameter will instead select a subset of projects. The \\"--from-version-policy\\" parameter is equivalent to specifying \\"--from\\" for each of the projects belonging to VERSION_POLICY_NAME. For details, refer to the website article \\"Selecting subsets of projects\\".", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--from-version-policy", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Display the logs during the build, rather than just displaying the build status summary", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verbose", + "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, + "kind": "Flag", + "longName": "--ignore-hooks", + "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, + "kind": "Flag", + "longName": "--ship", + "required": false, + "shortName": "-s", + }, + Object { + "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--minimal", + "required": false, + "shortName": "-m", + }, + ], + }, + ], +} +`; 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 new file mode 100644 index 00000000000..79352d781bb --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushConfiguration.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RushConfiguration RushConfigurationProject correctly updates the packageJson property after the packageJson is edited by packageJsonEditor: dependencyProjects after 1`] = ` +Array [ + "project2", +] +`; + +exports[`RushConfiguration RushConfigurationProject correctly updates the packageJson property after the packageJson is edited by packageJsonEditor: dependencyProjects before 1`] = `Array []`; + +exports[`RushConfiguration RushConfigurationProject correctly updates the packageJson property after the packageJson is edited by packageJsonEditor: devDependencies after 1`] = ` +Object { + "project2": "1.0.0", +} +`; + +exports[`RushConfiguration RushConfigurationProject correctly updates the packageJson property after the packageJson is edited by packageJsonEditor: devDependencies before 1`] = `undefined`; + +exports[`RushConfiguration fails to load repo/rush-repository-url-urls.json 1`] = `"The 'repository.url' field cannot be used when 'repository.urls' is present"`; 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 new file mode 100644 index 00000000000..55c5f5807ed --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushConfigurationProject.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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."`; + +exports[`validateRelativePathField should throw an error if the path contains backslashes 2`] = `"The value \\"path\\\\\\" in the \\"someOtherField\\" 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."`; + +exports[`validateRelativePathField should throw an error if the path ends in a trailing slash 1`] = `"The value \\"path/to/project/\\" in the \\"someField\\" field in \\"/repo/rush.json\\" may not end with a trailing '/' character."`; + +exports[`validateRelativePathField should throw an error if the path ends in a trailing slash 2`] = `"The value \\"p/\\" in the \\"someField\\" field in \\"/repo/rush.json\\" may not end with a trailing '/' character."`; + +exports[`validateRelativePathField should throw an error if the path is not normalized 1`] = `"The value \\"path/../to/project\\" in the \\"someField\\" field in \\"/repo/rush.json\\" should be replaced with its normalized form \\"to/project\\"."`; + +exports[`validateRelativePathField should throw an error if the path is not normalized 2`] = `"The value \\"path/./to/project\\" in the \\"someField\\" field in \\"/repo/rush.json\\" should be replaced with its normalized form \\"path/to/project\\"."`; + +exports[`validateRelativePathField should throw an error if the path is not normalized 3`] = `"The value \\"./path/to/project\\" in the \\"someField\\" field in \\"/repo/rush.json\\" should be replaced with its normalized form \\"path/to/project\\"."`; + +exports[`validateRelativePathField should throw an error if the path is not relative 1`] = `"The value \\"C:/path/to/project\\" in the \\"projectFolder\\" field in \\"/rush.json\\" must be a relative path."`; + +exports[`validateRelativePathField should throw an error if the path is not relative 2`] = `"The value \\"/path/to/project\\" in the \\"publishFolder\\" field in \\"/rush.json\\" must be a relative path."`; 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 new file mode 100644 index 00000000000..2ebe9d5908a --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushProjectConfiguration.test.ts.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RushProjectConfiguration getCacheDisabledReason Indicates if the build cache is completely disabled 1`] = `"Caching has been disabled for this project."`; + +exports[`RushProjectConfiguration getCacheDisabledReason Indicates if the phase behavior is not defined 1`] = `"This project does not define the caching behavior of the \\"z\\" command, so caching has been disabled."`; + +exports[`RushProjectConfiguration getCacheDisabledReason Indicates if the phase has disabled the cache 1`] = `"Caching has been disabled for this project's \\"_phase:a\\" command."`; + +exports[`RushProjectConfiguration getCacheDisabledReason Indicates if tracked files are outputs of the phase 1`] = `"The following files are used to calculate project state and are considered project output: test-project-c/.cache/b/foo"`; + +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`] = ` +Map { + "_phase:a" => Object { + "disableBuildCacheForOperation": true, + "operationName": "_phase:a", + "outputFolderNames": Array [ + ".cache/a", + ], + }, + "_phase:b" => Object { + "operationName": "_phase:b", + "outputFolderNames": Array [ + ".cache/b", + ], + }, +} +`; + +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: validation: terminal warning 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file 1`] = ` +Map { + "_phase:a" => Object { + "operationName": "_phase:a", + "outputFolderNames": Array [ + "a-a", + "a-b", + ], + }, + "_phase:b" => Object { + "operationName": "_phase:b", + "outputFolderNames": Array [ + "b-a", + ], + }, +} +`; + +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 loads a rush-project.json config that extends another config file: validation: terminal verbose 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file: validation: terminal warning 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 validates mix of existent and nonexistent parameters: validation: terminal error 1`] = `"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 validates mix of existent and nonexistent parameters: validation: terminal output 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates mix of existent and nonexistent parameters: validation: terminal verbose 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates mix of existent and nonexistent parameters: validation: terminal warning 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates nonexistent parameters when operation has valid parameters: validation: terminal error 1`] = `"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 validates nonexistent parameters when operation has valid parameters: validation: terminal output 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates nonexistent parameters when operation has valid parameters: validation: terminal verbose 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates nonexistent parameters when operation has valid parameters: validation: terminal warning 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates that parameters in parameterNamesToIgnore exist for the operation: validation: terminal error 1`] = `"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]"`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates that parameters in parameterNamesToIgnore exist for the operation: validation: terminal output 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates that parameters in parameterNamesToIgnore exist for the operation: validation: terminal verbose 1`] = `""`; + +exports[`RushProjectConfiguration operationSettingsByOperationName validates that parameters in parameterNamesToIgnore exist for the operation: validation: terminal warning 1`] = `""`; diff --git a/libraries/rush-lib/src/api/test/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json b/libraries/rush-lib/src/api/test/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json new file mode 100644 index 00000000000..91b891e85f8 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json @@ -0,0 +1,9 @@ +{ + "ensureConsistentVersions": true, + "preferredVersions": { + "@scope/library-1": "~3.2.1" + }, + "allowedAlternativeVersions": { + "library-3": ["^1.2.3"] + } +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/common-versions.json b/libraries/rush-lib/src/api/test/jsonFiles/common-versions.json new file mode 100644 index 00000000000..92b6feab0b9 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/common-versions.json @@ -0,0 +1,8 @@ +{ + "preferredVersions": { + "@scope/library-1": "~3.2.1" + }, + "allowedAlternativeVersions": { + "library-3": ["^1.2.3"] + } +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/custom-tips.error.json b/libraries/rush-lib/src/api/test/jsonFiles/custom-tips.error.json new file mode 100644 index 00000000000..3764417bb58 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/custom-tips.error.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", + + "customTips": [ + { + "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + "message": "duplicate 1" + }, + { + "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + "message": "duplicate 2" + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/rush-project-base.json b/libraries/rush-lib/src/api/test/jsonFiles/rush-project-base.json new file mode 100644 index 00000000000..2d9827001fd --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/rush-project-base.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:a", + "outputFolderNames": ["a-a"] + }, + { + "operationName": "_phase:b", + "outputFolderNames": ["b-a"] + } + ] +} diff --git a/apps/rush-lib/src/api/test/jsonFiles/rushWithIndividualVersion.json b/libraries/rush-lib/src/api/test/jsonFiles/rushWithIndividualVersion.json similarity index 100% rename from apps/rush-lib/src/api/test/jsonFiles/rushWithIndividualVersion.json rename to libraries/rush-lib/src/api/test/jsonFiles/rushWithIndividualVersion.json diff --git a/libraries/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json b/libraries/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json new file mode 100644 index 00000000000..ca829e9ecf3 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/rushWithLockVersion.json @@ -0,0 +1,13 @@ +[ + { + "policyName": "testPolicy1", + "definitionName": "lockStepVersion", + "version": "1.1.0", + "nextBump": "patch" + }, + { + "policyName": "testPolicy2", + "definitionName": "lockStepVersion", + "version": "1.2.0" + } +] diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-a/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-a/config/rush-project.json new file mode 100644 index 00000000000..fe852bfeda4 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-a/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "extends": "../../rush-project-base.json", + + "disableBuildCacheForProject": true, + + "operationSettings": [ + { + "operationName": "_phase:a", + "outputFolderNames": ["a-b"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-b/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-b/config/rush-project.json new file mode 100644 index 00000000000..30900c673c9 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-b/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "extends": "../../rush-project-base.json", + + "operationSettings": [ + { + "operationName": "_phase:a", + "outputFolderNames": ["a-b"] + }, + { + "operationName": "_phase:a", + "outputFolderNames": ["a-c"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-c/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-c/config/rush-project.json new file mode 100644 index 00000000000..6b2625686a3 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-c/config/rush-project.json @@ -0,0 +1,13 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:a", + "outputFolderNames": [".cache/a"], + "disableBuildCacheForOperation": true + }, + { + "operationName": "_phase:b", + "outputFolderNames": [".cache/b"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-d/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-d/config/rush-project.json new file mode 100644 index 00000000000..d910a2b15fa --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-d/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:a", + "outputFolderNames": ["a"] + }, + { + "operationName": "_phase:b", + "outputFolderNames": ["a/b"] + } + ] +} 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/pnpmConfigThrow/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/api/test/pnpmConfigThrow/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/libraries/rush-lib/src/api/test/pnpmConfigThrow/common/config/rush/pnpm-config.json @@ -0,0 +1 @@ +{} diff --git a/libraries/rush-lib/src/api/test/pnpmConfigThrow/rush.json b/libraries/rush-lib/src/api/test/pnpmConfigThrow/rush.json new file mode 100644 index 00000000000..048a0bd62cb --- /dev/null +++ b/libraries/rush-lib/src/api/test/pnpmConfigThrow/rush.json @@ -0,0 +1,6 @@ +{ + "pnpmVersion": "6.23.1", + "rushVersion": "5.58.0", + "pnpmOptions": {}, + "projects": [] +} 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/browser-approved-packages.json b/libraries/rush-lib/src/api/test/repo/common/config/rush/browser-approved-packages.json new file mode 100644 index 00000000000..a3bc61f4d35 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/common/config/rush/browser-approved-packages.json @@ -0,0 +1,9 @@ +// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. +{ + "packages": [ + { + "name": "example", + "allowedCategories": ["first-party", "prototype", "third-party"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/repo/common/config/rush/custom-tips.json b/libraries/rush-lib/src/api/test/repo/common/config/rush/custom-tips.json new file mode 100644 index 00000000000..6b7a05c8129 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/common/config/rush/custom-tips.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/custom-tips.schema.json", + + "customTips": [ + { + "tipId": "TIP_RUSH_INCONSISTENT_VERSIONS", + "message": "This is so wrong my friend. Please read this doc for more information: google.com" + } + ] +} diff --git a/libraries/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json b/libraries/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json new file mode 100644 index 00000000000..a3bc61f4d35 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/common/config/rush/nonbrowser-approved-packages.json @@ -0,0 +1,9 @@ +// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. +{ + "packages": [ + { + "name": "example", + "allowedCategories": ["first-party", "prototype", "third-party"] + } + ] +} 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/apps/rush-lib/src/api/test/repo/project1/package.json b/libraries/rush-lib/src/api/test/repo/project1/package.json similarity index 100% rename from apps/rush-lib/src/api/test/repo/project1/package.json rename to libraries/rush-lib/src/api/test/repo/project1/package.json diff --git a/apps/rush-lib/src/api/test/repo/project2/package.json b/libraries/rush-lib/src/api/test/repo/project2/package.json similarity index 100% rename from apps/rush-lib/src/api/test/repo/project2/package.json rename to libraries/rush-lib/src/api/test/repo/project2/package.json diff --git a/apps/rush-lib/src/api/test/repo/project3/package.json b/libraries/rush-lib/src/api/test/repo/project3/package.json similarity index 100% rename from apps/rush-lib/src/api/test/repo/project3/package.json rename to libraries/rush-lib/src/api/test/repo/project3/package.json diff --git a/libraries/rush-lib/src/api/test/repo/rush-npm.json b/libraries/rush-lib/src/api/test/repo/rush-npm.json new file mode 100644 index 00000000000..5f448332dcd --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/rush-npm.json @@ -0,0 +1,63 @@ +{ + "npmVersion": "4.5.0", + "rushVersion": "2.5.0-dev.123", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "hotfixChangeEnabled": true, + + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + + "repository": { + "url": "someFakeUrl" + }, + + "gitPolicy": { + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], + "sampleEmail": "mrexample@contoso.com" + }, + + "eventHooks": { + "postRushBuild": ["do something"] + }, + + "projects": [ + { + "packageName": "project1", + "projectFolder": "project1", + "reviewCategory": "third-party", + "tags": ["frontend", "ui"], + "versionPolicyName": "testPolicy" + }, + + { + "packageName": "project2", + "projectFolder": "project2", + "reviewCategory": "third-party", + "skipRushCheck": true, + "tags": ["backend"] + }, + + { + "packageName": "project3", + "projectFolder": "project3", + "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/repo/rush-pnpm-5.json b/libraries/rush-lib/src/api/test/repo/rush-pnpm-5.json new file mode 100644 index 00000000000..ff47400765b --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/rush-pnpm-5.json @@ -0,0 +1,44 @@ +{ + "pnpmVersion": "5.0.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + + "repository": { + "urls": ["someFakeUrl", "otherFakeUrl"] + }, + + "gitPolicy": { + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], + "sampleEmail": "mrexample@contoso.com" + }, + + "eventHooks": { + "postRushBuild": ["do something"] + }, + + "projects": [ + { + "packageName": "project1", + "projectFolder": "project1", + "reviewCategory": "third-party" + }, + + { + "packageName": "project2", + "projectFolder": "project2", + "reviewCategory": "third-party" + }, + + { + "packageName": "project3", + "projectFolder": "project3", + "reviewCategory": "prototype" + } + ] +} diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm-global.json b/libraries/rush-lib/src/api/test/repo/rush-pnpm-global.json similarity index 75% rename from apps/rush-lib/src/api/test/repo/rush-pnpm-global.json rename to libraries/rush-lib/src/api/test/repo/rush-pnpm-global.json index d08ad1abf36..729d8ecfefd 100644 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm-global.json +++ b/libraries/rush-lib/src/api/test/repo/rush-pnpm-global.json @@ -9,8 +9,8 @@ }, "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] }, "repository": { @@ -18,20 +18,15 @@ }, "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], "sampleEmail": "mrexample@contoso.com" }, "eventHooks": { - "postRushBuild": [ - "do something" - ] + "postRushBuild": ["do something"] }, "projects": [ - { "packageName": "project1", "projectFolder": "project1", diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json b/libraries/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json similarity index 75% rename from apps/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json rename to libraries/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json index 57cf8b0c6d5..66b60b36fae 100644 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json +++ b/libraries/rush-lib/src/api/test/repo/rush-pnpm-invalid-store.json @@ -9,8 +9,8 @@ }, "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] }, "repository": { @@ -18,20 +18,15 @@ }, "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], "sampleEmail": "mrexample@contoso.com" }, "eventHooks": { - "postRushBuild": [ - "do something" - ] + "postRushBuild": ["do something"] }, "projects": [ - { "packageName": "project1", "projectFolder": "project1", diff --git a/apps/rush-lib/src/api/test/repo/rush-pnpm-local.json b/libraries/rush-lib/src/api/test/repo/rush-pnpm-local.json similarity index 75% rename from apps/rush-lib/src/api/test/repo/rush-pnpm-local.json rename to libraries/rush-lib/src/api/test/repo/rush-pnpm-local.json index 681fc20fd78..3e7039d235a 100644 --- a/apps/rush-lib/src/api/test/repo/rush-pnpm-local.json +++ b/libraries/rush-lib/src/api/test/repo/rush-pnpm-local.json @@ -9,8 +9,8 @@ }, "approvedPackagesPolicy": { - "reviewCategories": [ "first-party", "third-party", "prototype" ], - "ignoredNpmScopes": [ "@types", "@internal" ] + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] }, "repository": { @@ -18,20 +18,15 @@ }, "gitPolicy": { - "allowedEmailRegExps": [ - "[^@]+@contoso\\.com" - ], + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], "sampleEmail": "mrexample@contoso.com" }, "eventHooks": { - "postRushBuild": [ - "do something" - ] + "postRushBuild": ["do something"] }, "projects": [ - { "packageName": "project1", "projectFolder": "project1", diff --git a/libraries/rush-lib/src/api/test/repo/rush-pnpm.json b/libraries/rush-lib/src/api/test/repo/rush-pnpm.json new file mode 100644 index 00000000000..f810d5adbd5 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/rush-pnpm.json @@ -0,0 +1,44 @@ +{ + "pnpmVersion": "6.0.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + + "repository": { + "url": "someFakeUrl" + }, + + "gitPolicy": { + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], + "sampleEmail": "mrexample@contoso.com" + }, + + "eventHooks": { + "postRushBuild": ["do something"] + }, + + "projects": [ + { + "packageName": "project1", + "projectFolder": "project1", + "reviewCategory": "third-party" + }, + + { + "packageName": "project2", + "projectFolder": "project2", + "reviewCategory": "third-party" + }, + + { + "packageName": "project3", + "projectFolder": "project3", + "reviewCategory": "prototype" + } + ] +} diff --git a/libraries/rush-lib/src/api/test/repo/rush-repository-url-urls.json b/libraries/rush-lib/src/api/test/repo/rush-repository-url-urls.json new file mode 100644 index 00000000000..294fcfc116d --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/rush-repository-url-urls.json @@ -0,0 +1,45 @@ +{ + "pnpmVersion": "5.0.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + + "repository": { + "url": "someFakeUrl", + "urls": ["otherFakeUrl"] + }, + + "gitPolicy": { + "allowedEmailRegExps": ["[^@]+@contoso\\.com"], + "sampleEmail": "mrexample@contoso.com" + }, + + "eventHooks": { + "postRushBuild": ["do something"] + }, + + "projects": [ + { + "packageName": "project1", + "projectFolder": "project1", + "reviewCategory": "third-party" + }, + + { + "packageName": "project2", + "projectFolder": "project2", + "reviewCategory": "third-party" + }, + + { + "packageName": "project3", + "projectFolder": "project3", + "reviewCategory": "prototype" + } + ] +} diff --git a/apps/rush-lib/src/api/test/repo/rush-too-new.json b/libraries/rush-lib/src/api/test/repo/rush-too-new.json similarity index 100% rename from apps/rush-lib/src/api/test/repo/rush-too-new.json rename to libraries/rush-lib/src/api/test/repo/rush-too-new.json 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..797e41e0c2c --- /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": { + "lodash": "^4.17.21", + "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/cli/CommandLineMigrationAdvisor.ts b/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts new file mode 100644 index 00000000000..dd96e13cf6a --- /dev/null +++ b/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Colorize, PrintUtilities } from '@rushstack/terminal'; + +import { RushConstants } from '../logic/RushConstants'; + +export class CommandLineMigrationAdvisor { + // NOTE: THIS RUNS BEFORE THE REAL COMMAND-LINE PARSING. + // TAKE EXTREME CARE THAT THE HEURISTICS CANNOT FALSELY MATCH A VALID COMMAND LINE. + public static checkArgv(argv: string[]): boolean { + // 0=node.exe, 1=script name + const args: string[] = process.argv.slice(2); + + if (args.length > 0) { + if (args[0] === 'generate') { + CommandLineMigrationAdvisor._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".' + ); + return false; + } + if (args.indexOf('-C') >= 0) { + CommandLineMigrationAdvisor._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".' + ); + return false; + } + if (args.indexOf('-c') >= 0) { + CommandLineMigrationAdvisor._reportDeprecated( + 'Instead of "rush install -c", use "rush install --purge".' + ); + return false; + } + } + } + + // 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( + 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 new file mode 100644 index 00000000000..7828eb1e90d --- /dev/null +++ b/libraries/rush-lib/src/cli/RushCommandLineParser.ts @@ -0,0 +1,537 @@ +// 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 { + CommandLineParser, + type CommandLineFlagParameter, + CommandLineHelper +} from '@rushstack/ts-command-line'; +import { InternalError, AlreadyReportedError, Text } from '@rushstack/node-core-library'; +import { + ConsoleTerminalProvider, + Terminal, + PrintUtilities, + Colorize, + type ITerminal +} from '@rushstack/terminal'; + +import { RushConfiguration } from '../api/RushConfiguration'; +import { RushConstants } from '../logic/RushConstants'; +import { + type Command, + CommandLineConfiguration, + 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'; +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'; +import { RemoveAction } from './actions/RemoveAction'; +import { ScanAction } from './actions/ScanAction'; +import { UnlinkAction } from './actions/UnlinkAction'; +import { UpdateAction } from './actions/UpdateAction'; +import { UpdateAutoinstallerAction } from './actions/UpdateAutoinstallerAction'; +import { UpdateCloudCredentialsAction } from './actions/UpdateCloudCredentialsAction'; +import { UpgradeInteractiveAction } from './actions/UpgradeInteractiveAction'; +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 type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; +import { InitSubspaceAction } from './actions/InitSubspaceAction'; +import { RushAlerts } from '../utilities/RushAlerts'; +import { initializeDotEnv } from '../logic/dotenv'; +import { measureAsyncFn } from '../utilities/performance'; + +/** + * Options for `RushCommandLineParser`. + */ +export interface IRushCommandLineParserOptions { + cwd: string; // Defaults to `cwd` + alreadyReportedNodeTooNewError: boolean; + builtInPluginConfigurations: IBuiltInPluginConfiguration[]; +} + +export class RushCommandLineParser extends CommandLineParser { + public telemetry: Telemetry | undefined; + public rushGlobalFolder: RushGlobalFolder; + public readonly rushConfiguration!: RushConfiguration; + public readonly rushSession: RushSession; + public readonly pluginManager: PluginManager; + + private readonly _debugParameter: CommandLineFlagParameter; + private readonly _quietParameter: CommandLineFlagParameter; + private readonly _restrictConsoleOutput: boolean = RushCommandLineParser.shouldRestrictConsoleOutput(); + 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({ + toolFilename: 'rush', + toolDescription: + 'Rush makes life easier for JavaScript developers who develop, build, and publish' + + ' many packages from a central Git repo. It is designed to handle very large repositories' + + ' supporting many projects and people. Rush provides policies, protections, and customizations' + + ' that help coordinate teams and safely onboard new contributors. Rush also generates change logs' + + ' and automates package publishing. It can manage decoupled subsets of projects with different' + + ' release and versioning strategies. A full API is included to facilitate integration with other' + + ' automation tools. If you are looking for a proven turnkey solution for monorepo management,' + + ' Rush is for you.', + enableTabCompletionAction: true + }); + + this._debugParameter = this.defineFlagParameter({ + parameterLongName: '--debug', + parameterShortName: '-d', + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + this._quietParameter = this.defineFlagParameter({ + parameterLongName: '--quiet', + parameterShortName: '-q', + description: 'Hide rush startup information' + }); + + 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 { + rushJsonFilePath = RushConfiguration.tryFindRushJsonLocation({ + startingFolder: cwd, + showVerbose: !this._restrictConsoleOutput + }); + + initializeDotEnv(terminal, rushJsonFilePath); + + if (rushJsonFilePath) { + this.rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFilePath); + } + } catch (error) { + this._reportErrorAndSetExitCode(error as Error); + } + + NodeJsCompatibility.warnAboutCompatibilityIssues({ + isRushLib: true, + alreadyReportedNodeTooNewError, + rushConfiguration: this.rushConfiguration + }); + + this.rushGlobalFolder = new RushGlobalFolder(); + + this.rushSession = new RushSession({ + getIsDebugMode: () => this.isDebug, + terminalProvider + }); + this.pluginManager = new PluginManager({ + rushSession: this.rushSession, + rushConfiguration: this.rushConfiguration, + terminal, + builtInPluginConfigurations, + restrictConsoleOutput: this._restrictConsoleOutput, + rushGlobalFolder: this.rushGlobalFolder + }); + + 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._reportErrorAndSetExitCode( + new Error( + `Error from plugin ${pluginLoader.pluginName} by ${pluginLoader.packageName}: ${( + e as Error + ).toString()}` + ) + ); + } + } + } + + public get isDebug(): boolean { + return this._debugParameter.value; + } + + public get isQuiet(): boolean { + return this._quietParameter.value; + } + + public get terminal(): ITerminal { + return this._terminal; + } + + /** + * Utility to determine if the app should restrict writing to the console. + */ + public static shouldRestrictConsoleOutput(): boolean { + if (CommandLineHelper.isTabCompletionActionRequest(process.argv)) { + return true; + } + + for (let i: number = 2; i < process.argv.length; i++) { + const arg: string = process.argv[i]; + if (arg === '-q' || arg === '--quiet' || arg === '--json') { + return true; + } + } + + return false; + } + + public flushTelemetry(): void { + this.telemetry?.flush(); + } + + public 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 measureAsyncFn('rush:initializeUnassociatedPlugins', () => + this.pluginManager.tryInitializeUnassociatedPluginsAsync() + ); + + return await super.executeAsync(args); + } + + 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. + // Ideally we should do this for all the Rush actions, but "rush build" is the most critical one + // -- if it falsely appears to succeed, we could merge bad PRs, publish empty packages, etc. + process.exitCode = 1; + + if (this._debugParameter.value) { + InternalError.breakInDebugger = true; + } + + try { + await this._wrapOnExecuteAsync(); + + // TODO: rushConfiguration is typed as "!: RushConfiguration" here, but can sometimes be undefined + if (this.rushConfiguration) { + try { + const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; + + if (experiments.rushAlerts) { + // TODO: Fix this + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const actionName: string = (this as any) + ._getArgumentParser() + .parseArgs(process.argv.slice(2)).action; + + // only display alerts when certain specific actions are triggered + if (RushAlerts.alertTriggerActions.includes(actionName)) { + this._terminal.writeDebugLine('Checking Rush alerts...'); + const rushAlerts: RushAlerts = await RushAlerts.loadFromConfigurationAsync( + this.rushConfiguration, + this._terminal + ); + // Print out alerts if have after each successful command actions + await rushAlerts.printAlertsAsync(); + } + } + } catch (error) { + if (error instanceof AlreadyReportedError) { + throw error; + } + // Generally the RushAlerts implementation should handle its own error reporting; if not, + // clarify the source, since the Rush Alerts behavior is nondeterministic and may not repro easily: + this._terminal.writeErrorLine(`\nAn unexpected error was encountered by the Rush alerts feature:`); + this._terminal.writeErrorLine(error.message); + throw new AlreadyReportedError(); + } + } + + // If we make it here, everything went fine, so reset the exit code back to 0 + process.exitCode = 0; + } catch (error) { + this._reportErrorAndSetExitCode(error as Error); + } + + // This only gets hit if the wrapped execution completes successfully + await this.telemetry?.ensureFlushedAsync(); + } + + private _normalizeOptions(options: Partial): IRushCommandLineParserOptions { + return { + cwd: options.cwd || process.cwd(), + alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError || false, + builtInPluginConfigurations: options.builtInPluginConfigurations || [] + }; + } + + private async _wrapOnExecuteAsync(): Promise { + if (this.rushConfiguration) { + this.telemetry = new Telemetry(this.rushConfiguration, this.rushSession); + } + + try { + await measureAsyncFn('rush:commandLineParser:onExecuteAsync', () => super.onExecuteAsync()); + } finally { + if (this.telemetry) { + this.flushTelemetry(); + } + } + } + + private _populateActions(): void { + try { + // Alphabetical order + this.addAction(new AddAction(this)); + this.addAction(new ChangeAction(this)); + this.addAction(new CheckAction(this)); + this.addAction(new DeployAction(this)); + this.addAction(new InitAction(this)); + this.addAction(new InitAutoinstallerAction(this)); + this.addAction(new InitDeployAction(this)); + this.addAction(new InitSubspaceAction(this)); + this.addAction(new InstallAction(this)); + this.addAction(new LinkAction(this)); + this.addAction(new ListAction(this)); + this.addAction(new PublishAction(this)); + this.addAction(new PurgeAction(this)); + this.addAction(new RemoveAction(this)); + this.addAction(new ScanAction(this)); + this.addAction(new SetupAction(this)); + this.addAction(new UnlinkAction(this)); + this.addAction(new UpdateAction(this)); + this.addAction(new InstallAutoinstallerAction(this)); + this.addAction(new UpdateAutoinstallerAction(this)); + this.addAction(new UpdateCloudCredentialsAction(this)); + 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) { + this._reportErrorAndSetExitCode(error as Error); + } + } + + private _populateScriptActions(): void { + // If there is not a rush.json file, we still want "build" and "rebuild" to appear in the + // command-line help + let commandLineConfigFilePath: string | undefined; + if (this.rushConfiguration) { + commandLineConfigFilePath = path.join( + this.rushConfiguration.commonRushConfigFolder, + RushConstants.commandLineFilename + ); + } + + // 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); + } + + private _addCommandLineConfigActions(commandLineConfiguration: CommandLineConfiguration): void { + // Register each custom command + for (const command of commandLineConfiguration.commands.values()) { + this._addCommandLineConfigAction(commandLineConfiguration, command); + } + } + + private _addCommandLineConfigAction( + commandLineConfiguration: CommandLineConfiguration, + command: Command + ): void { + if (this.tryGetAction(command.name)) { + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${command.name}"` + + ` using a name that already exists` + ); + } + + switch (command.commandKind) { + case RushConstants.globalCommandKind: { + this._addGlobalScriptAction(commandLineConfiguration, command); + break; + } + + case RushConstants.phasedCommandKind: { + this._addPhasedCommandLineConfigAction(commandLineConfiguration, command); + break; + } + + default: + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${(command as Command).name}"` + + ` using an unsupported command kind "${(command as Command).commandKind}"` + ); + } + } + + private _getSharedCommandActionOptions( + commandLineConfiguration: CommandLineConfiguration, + command: TCommand + ): IBaseScriptActionOptions { + return { + actionName: command.name, + summary: command.summary, + documentation: command.description || command.summary, + safeForSimultaneousRushProcesses: command.safeForSimultaneousRushProcesses, + + command, + parser: this, + commandLineConfiguration: commandLineConfiguration + }; + } + + private _addGlobalScriptAction( + commandLineConfiguration: CommandLineConfiguration, + command: IGlobalCommandConfig + ): void { + if ( + command.name === RushConstants.buildCommandName || + command.name === RushConstants.rebuildCommandName + ) { + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${command.name}" using ` + + `the command kind "${RushConstants.globalCommandKind}". This command can only be designated as a command ` + + `kind "${RushConstants.bulkCommandKind}" or "${RushConstants.phasedCommandKind}".` + ); + } + + const sharedCommandOptions: IBaseScriptActionOptions = + this._getSharedCommandActionOptions(commandLineConfiguration, command); + + this.addAction( + new GlobalScriptAction({ + ...sharedCommandOptions, + + shellCommand: command.shellCommand, + autoinstallerName: command.autoinstallerName + }) + ); + } + + private _addPhasedCommandLineConfigAction( + commandLineConfiguration: CommandLineConfiguration, + command: IPhasedCommandConfig + ): void { + const baseCommandOptions: IBaseScriptActionOptions = + this._getSharedCommandActionOptions(commandLineConfiguration, command); + + this.addAction( + new PhasedScriptAction({ + ...baseCommandOptions, + + enableParallelism: command.enableParallelism, + incremental: command.incremental || false, + disableBuildCache: command.disableBuildCache || false, + + // 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: command.allowOversubscription ?? true, + + initialPhases: command.phases, + originalPhases: command.originalPhases, + watchPhases: command.watchPhases, + watchDebounceMs: command.watchDebounceMs ?? RushConstants.defaultWatchDebounceMs, + phases: commandLineConfiguration.phases, + + alwaysWatch: command.alwaysWatch, + alwaysInstall: command.alwaysInstall + }) + ); + } + + private _reportErrorAndSetExitCode(error: Error): void { + if (!(error instanceof AlreadyReportedError)) { + const prefix: string = 'ERROR: '; + + // The colors package will eat multi-newlines, which could break formatting + // in user-specified messages and instructions, so we prefer to color each + // line individually. + const message: string = Text.splitByNewLines(PrintUtilities.wrapWords(prefix + error.message)) + .map((line) => Colorize.red(line)) + .join('\n'); + // eslint-disable-next-line no-console + console.error(`\n${message}`); + } + + if (this._debugParameter.value) { + // If catchSyncErrors() called this, then show a call stack similar to what Node.js + // would show for an uncaught error + // eslint-disable-next-line no-console + console.error(`\n${error.stack}`); + } + + this.flushTelemetry(); + + const handleExit = (): never => { + // Ideally we want to eliminate all calls to process.exit() from our code, and replace them + // with normal control flow that properly cleans up its data structures. + // For this particular call, we have a problem that the RushCommandLineParser constructor + // performs nontrivial work that can throw an exception. Either the Rush class would need + // to handle reporting for those exceptions, or else _populateActions() should be moved + // to a RushCommandLineParser lifecycle stage that can handle it. + if (process.exitCode !== undefined) { + process.exit(process.exitCode); + } else { + process.exit(1); + } + }; + + if (this.telemetry && this.rushSession.hooks.flushTelemetry.isUsed()) { + this.telemetry.ensureFlushedAsync().then(handleExit).catch(handleExit); + } else { + handleExit(); + } + } +} diff --git a/libraries/rush-lib/src/cli/RushPnpmCommandLine.ts b/libraries/rush-lib/src/cli/RushPnpmCommandLine.ts new file mode 100644 index 00000000000..5720ef8d547 --- /dev/null +++ b/libraries/rush-lib/src/cli/RushPnpmCommandLine.ts @@ -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. + +import type { ILaunchOptions } from '../api/Rush'; +import { RushPnpmCommandLineParser } from './RushPnpmCommandLineParser'; + +export interface ILaunchRushPnpmInternalOptions extends ILaunchOptions {} + +export class RushPnpmCommandLine { + public static launch(launcherVersion: string, options: ILaunchRushPnpmInternalOptions): void { + RushPnpmCommandLineParser.initializeAsync(options) + // RushPnpmCommandLineParser.executeAsync should never reject the promise + .then((rushPnpmCommandLineParser) => rushPnpmCommandLineParser.executeAsync()) + // eslint-disable-next-line no-console + .catch(console.error); + } +} diff --git a/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts b/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts new file mode 100644 index 00000000000..7c7787a4362 --- /dev/null +++ b/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.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 { + AlreadyReportedError, + EnvironmentMap, + FileConstants, + FileSystem, + JsonFile, + type JsonObject, + Objects +} from '@rushstack/node-core-library'; +import { + Colorize, + ConsoleTerminalProvider, + type ITerminal, + type ITerminalProvider, + Terminal, + PrintUtilities +} from '@rushstack/terminal'; + +import { RushConfiguration } from '../api/RushConfiguration'; +import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; +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 { Utilities } from '../utilities/Utilities'; +import type { Subspace } from '../api/Subspace'; +import type { PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration'; +import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; +import { initializeDotEnv } from '../logic/dotenv'; + +const RUSH_SKIP_CHECKS_PARAMETER: string = '--rush-skip-checks'; + +/** + * Options for RushPnpmCommandLineParser + */ +export interface IRushPnpmCommandLineParserOptions { + alreadyReportedNodeTooNewError?: boolean; + builtInPluginConfigurations?: IBuiltInPluginConfiguration[]; + terminalProvider?: ITerminalProvider; +} + +function _reportErrorAndSetExitCode(error: Error, terminal: ITerminal, debugEnabled: boolean): never { + if (!(error instanceof AlreadyReportedError)) { + const prefix: string = 'ERROR: '; + terminal.writeErrorLine('\n' + PrintUtilities.wrapWords(prefix + error.message)); + } + + if (debugEnabled) { + // If catchSyncErrors() called this, then show a call stack similar to what Node.js + // would show for an uncaught error + terminal.writeErrorLine('\n' + error.stack); + } + + process.exit(process.exitCode ?? 1); +} + +export class RushPnpmCommandLineParser { + private readonly _terminal: ITerminal; + private readonly _rushConfiguration: RushConfiguration; + private readonly _pnpmArgs: string[]; + private _commandName: string | undefined; + private readonly _debugEnabled: boolean; + private _subspace: Subspace; + + private constructor( + options: IRushPnpmCommandLineParserOptions, + terminal: ITerminal, + debugEnabled: boolean + ) { + this._debugEnabled = debugEnabled; + + this._terminal = terminal; + + // Are we in a Rush repo? + 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, + rushConfiguration + }); + + if (!rushConfiguration) { + throw new Error( + 'The "rush-pnpm" command must be executed in a folder that is under a Rush workspace folder' + ); + } + this._rushConfiguration = rushConfiguration; + + if (rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + `The "rush-pnpm" command requires your ${RushConstants.rushJsonFilename} to be configured to use the PNPM package manager` + ); + } + + if (!rushConfiguration.pnpmOptions.useWorkspaces) { + const pnpmConfigFilename: string = + rushConfiguration.pnpmOptions.jsonFilename || RushConstants.rushJsonFilename; + throw new Error( + `The "rush-pnpm" command requires the "useWorkspaces" setting to be enabled in ${pnpmConfigFilename}` + ); + } + + let pnpmArgs: string[] = []; + let subspaceName: string = 'default'; + + if (process.argv.indexOf('--subspace') >= 0) { + if (process.argv[2] !== '--subspace') { + throw new Error( + 'If you want to specify a subspace, you should place "--subspace " immediately after the "rush-pnpm" command' + ); + } + + subspaceName = process.argv[3]; + + // 0 = node.exe + // 1 = rush-pnpm + // 2 = --subspace + // 3 = + pnpmArgs = process.argv.slice(4); + } else { + // 0 = node.exe + // 1 = rush-pnpm + pnpmArgs = process.argv.slice(2); + } + + this._pnpmArgs = pnpmArgs; + + const subspace: Subspace = rushConfiguration.getSubspace(subspaceName); + this._subspace = subspace; + + const workspaceFolder: string = subspace.getSubspaceTempFolderPath(); + const workspaceFilePath: string = path.join(workspaceFolder, 'pnpm-workspace.yaml'); + + if (!FileSystem.exists(workspaceFilePath)) { + this._terminal.writeErrorLine('Error: The PNPM workspace file has not been generated:'); + this._terminal.writeErrorLine(` ${workspaceFilePath}\n`); + this._terminal.writeLine(Colorize.cyan(`Do you need to run "rush install" or "rush update"?`)); + throw new AlreadyReportedError(); + } + + if (!FileSystem.exists(rushConfiguration.packageManagerToolFilename)) { + this._terminal.writeErrorLine('Error: The PNPM local binary has not been installed yet.'); + this._terminal.writeLine('\n' + Colorize.cyan(`Do you need to run "rush install" or "rush update"?`)); + throw new AlreadyReportedError(); + } + } + + public static async initializeAsync( + options: IRushPnpmCommandLineParserOptions + ): Promise { + const debugEnabled: boolean = process.argv.indexOf('--debug') >= 0; + const verboseEnabled: boolean = process.argv.indexOf('--verbose') >= 0; + const localTerminalProvider: ITerminalProvider = + options.terminalProvider ?? + new ConsoleTerminalProvider({ + debugEnabled, + verboseEnabled + }); + const terminal: ITerminal = new Terminal(localTerminalProvider); + + try { + const rushPnpmCommandLineParser: RushPnpmCommandLineParser = new RushPnpmCommandLineParser( + options, + terminal, + debugEnabled + ); + await rushPnpmCommandLineParser._validatePnpmUsageAsync(rushPnpmCommandLineParser._pnpmArgs); + return rushPnpmCommandLineParser; + } catch (error) { + _reportErrorAndSetExitCode(error as Error, terminal, debugEnabled); + } + } + + public async executeAsync(): Promise { + // Node.js can sometimes accidentally terminate with a zero exit code (e.g. for an uncaught + // 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 this._executeAsync(); + + if (process.exitCode === 0) { + await this._postExecuteAsync(); + } + } + + private async _validatePnpmUsageAsync(pnpmArgs: string[]): Promise { + if (pnpmArgs[0] === RUSH_SKIP_CHECKS_PARAMETER) { + pnpmArgs.shift(); + // Ignore other checks + return; + } + + if (pnpmArgs.length === 0) { + return; + } + const firstArg: string = pnpmArgs[0]; + + // Detect common safe invocations + if (pnpmArgs.includes('-h') || pnpmArgs.includes('--help') || pnpmArgs.includes('-?')) { + return; + } + + if (pnpmArgs.length === 1) { + if (firstArg === '-v' || firstArg === '--version') { + return; + } + } + + const BYPASS_NOTICE: string = `To bypass this check, add "${RUSH_SKIP_CHECKS_PARAMETER}" as the very first command line option.`; + + if (!/^[a-z]+([a-z0-9\-])*$/.test(firstArg)) { + // We can't parse this CLI syntax + this._terminal.writeErrorLine( + `Warning: The "rush-pnpm" wrapper expects a command verb before "${firstArg}"\n` + ); + this._terminal.writeLine(Colorize.cyan(BYPASS_NOTICE)); + throw new AlreadyReportedError(); + } else { + const commandName: string = firstArg; + + // Also accept SKIP_RUSH_CHECKS_PARAMETER immediately after the command verb + if (pnpmArgs[1] === RUSH_SKIP_CHECKS_PARAMETER) { + pnpmArgs.splice(1, 1); + return; + } + + if (pnpmArgs.indexOf(RUSH_SKIP_CHECKS_PARAMETER) >= 0) { + // We do not attempt to parse PNPM's complete CLI syntax, so we cannot be sure how to interpret + // strings that appear outside of the specific patterns that this parser recognizes + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "${RUSH_SKIP_CHECKS_PARAMETER}" option must be the first parameter for the "rush-pnpm" command.` + ) + ); + throw new AlreadyReportedError(); + } + + this._commandName = commandName; + + // Warn about commands known not to work + /* eslint-disable no-fallthrough */ + switch (commandName) { + // Blocked + case 'import': { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm ${commandName}" command is known to be incompatible with Rush's environment.` + ) + '\n' + ); + this._terminal.writeLine(Colorize.cyan(BYPASS_NOTICE)); + throw new AlreadyReportedError(); + } + + // Show warning for install commands + case 'add': + case 'install': + /* synonym */ + case 'i': + case 'install-test': + /* synonym */ + case 'it': { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm ${commandName}" command is incompatible with Rush's environment.` + + ` Use the "rush install" or "rush update" commands instead.` + ) + '\n' + ); + this._terminal.writeLine(Colorize.cyan(BYPASS_NOTICE)); + throw new AlreadyReportedError(); + } + + // Show warning + case 'link': + /* synonym */ + case 'ln': + case 'remove': + /* synonym */ + case 'rm': + case 'unlink': + case 'update': + /* synonym */ + case 'up': { + this._terminal.writeWarningLine( + PrintUtilities.wrapWords( + `Warning: The "pnpm ${commandName}" command makes changes that may invalidate Rush's workspace state.` + ) + '\n' + ); + this._terminal.writeWarningLine( + `==> Consider running "rush install" or "rush update" afterwards.\n` + ); + break; + } + + // Know safe after validation + case 'patch': { + const semver: typeof import('semver') = await import('semver'); + /** + * If you were to accidentally attempt to use rush-pnpm patch with a pnpmVersion < 7.4.0, pnpm patch may fallback to the system patch command. + * For instance, /usr/bin/patch which may just hangs forever + * So, erroring out the command if the pnpm version is < 7.4.0 + */ + if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '7.4.0')) { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm patch" command is added after pnpm@7.4.0.` + + ` Please update "pnpmVersion" >= 7.4.0 in ${RushConstants.rushJsonFilename} file and run "rush update" to use this command.` + ) + '\n' + ); + throw new AlreadyReportedError(); + } + break; + } + case 'patch-commit': { + const pnpmOptionsJsonFilename: string = path.join( + this._rushConfiguration.commonRushConfigFolder, + RushConstants.pnpmConfigFilename + ); + if (this._rushConfiguration.rushConfigurationJson.pnpmOptions) { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm patch-commit" 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; + } + case 'patch-remove': { + const semver: typeof import('semver') = await import('semver'); + /** + * The "patch-remove" command was introduced in pnpm version 8.5.0 + */ + if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '8.5.0')) { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm patch-remove" command is added after pnpm@8.5.0.` + + ` Please update "pnpmVersion" >= 8.5.0 in ${RushConstants.rushJsonFilename} file and run "rush update" to use this command.` + ) + '\n' + ); + throw new AlreadyReportedError(); + } + break; + } + + // Known safe + case 'audit': + case 'exec': + case 'list': + /* synonym */ + case 'ls': + case 'outdated': + case 'pack': + case 'prune': + case 'publish': + case 'rebuild': + /* synonym */ + case 'rb': + case 'root': + case 'run': + case 'start': + case 'store': + case 'test': + /* synonym */ + case 't': + case 'why': { + break; + } + + // Unknown + default: { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm ${commandName}" command has not been tested with Rush's environment. It may be incompatible.` + ) + '\n' + ); + this._terminal.writeLine(Colorize.cyan(BYPASS_NOTICE)); + } + } + /* eslint-enable no-fallthrough */ + } + } + + private async _executeAsync(): Promise { + const rushConfiguration: RushConfiguration = this._rushConfiguration; + const workspaceFolder: string = this._subspace.getSubspaceTempFolderPath(); + const pnpmEnvironmentMap: EnvironmentMap = new EnvironmentMap(process.env); + pnpmEnvironmentMap.set('NPM_CONFIG_WORKSPACE_DIR', workspaceFolder); + + if (rushConfiguration.pnpmOptions.pnpmStorePath) { + pnpmEnvironmentMap.set('NPM_CONFIG_STORE_DIR', rushConfiguration.pnpmOptions.pnpmStorePath); + pnpmEnvironmentMap.set('NPM_CONFIG_CACHE_DIR', rushConfiguration.pnpmOptions.pnpmStorePath); + pnpmEnvironmentMap.set('NPM_CONFIG_STATE_DIR', rushConfiguration.pnpmOptions.pnpmStorePath); + } + + if (rushConfiguration.pnpmOptions.environmentVariables) { + for (const [envKey, { value: envValue, override }] of Object.entries( + rushConfiguration.pnpmOptions.environmentVariables + )) { + if (override) { + pnpmEnvironmentMap.set(envKey, envValue); + } else { + if (undefined === pnpmEnvironmentMap.get(envKey)) { + pnpmEnvironmentMap.set(envKey, envValue); + } + } + } + } + + let onStdoutStreamChunk: ((chunk: string) => string | void) | undefined; + switch (this._commandName) { + case 'patch': { + // Replace `pnpm patch-commit` with `rush-pnpm patch-commit` when running + // `pnpm patch` to avoid the `pnpm patch` command being suggested in the output + onStdoutStreamChunk = (stdoutChunk: string) => { + return stdoutChunk.replace( + /pnpm patch-commit/g, + `rush-pnpm --subspace ${this._subspace.subspaceName} patch-commit` + ); + }; + + break; + } + } + + try { + const { exitCode } = await Utilities.executeCommandAsync({ + command: rushConfiguration.packageManagerToolFilename, + args: this._pnpmArgs, + workingDirectory: process.cwd(), + environment: pnpmEnvironmentMap.toObject(), + keepEnvironment: true, + onStdoutStreamChunk, + captureExitCodeAndSignal: true + }); + + if (typeof exitCode === 'number') { + process.exitCode = exitCode; + } else { + // If the exit code is not a number, the process was terminated by a signal + process.exitCode = 1; + } + } catch (e) { + this._terminal.writeDebugLine(`Error: ${e}`); + } + } + + private async _postExecuteAsync(): Promise { + const commandName: string | undefined = this._commandName; + if (!commandName) { + return; + } + + const subspaceTempFolder: string = this._subspace.getSubspaceTempFolderPath(); + + switch (commandName) { + case 'patch-remove': + case 'patch-commit': { + // why need to throw error when pnpm-config.json not exists? + // 1. pnpm-config.json is required for `rush-pnpm patch-commit`. Rush writes the patched dependency to the pnpm-config.json when finishes. + // 2. we can not fallback to use Monorepo config folder (common/config/rush) due to that this command is intended to apply to input subspace only. + // It will produce unexpected behavior if we use the fallback. + if (this._subspace.getPnpmOptions() === undefined) { + const subspaceConfigFolder: string = this._subspace.getSubspaceConfigFolderPath(); + this._terminal.writeErrorLine( + `The "rush-pnpm patch-commit" command cannot proceed without a pnpm-config.json file.` + + ` Create one in this folder: ${subspaceConfigFolder}` + ); + 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 currentGlobalPatchedDependencies: Record | undefined = + pnpmOptions?.globalPatchedDependencies; + + if (!Objects.areDeepEqual(currentGlobalPatchedDependencies, newGlobalPatchedDependencies)) { + const commonTempPnpmPatchesFolder: string = `${subspaceTempFolder}/${RushConstants.pnpmPatchesFolderName}`; + const rushPnpmPatchesFolder: string = this._subspace.getSubspacePnpmPatchesFolderPath(); + + // Copy (or delete) common\temp\subspace\patches\ --> common\config\pnpm-patches\ OR common\config\rush\pnpm-patches\ + if (FileSystem.exists(commonTempPnpmPatchesFolder)) { + FileSystem.ensureEmptyFolder(rushPnpmPatchesFolder); + // eslint-disable-next-line no-console + console.log(`Copying ${commonTempPnpmPatchesFolder}`); + // eslint-disable-next-line no-console + console.log(` --> ${rushPnpmPatchesFolder}`); + FileSystem.copyFiles({ + sourcePath: commonTempPnpmPatchesFolder, + destinationPath: rushPnpmPatchesFolder + }); + } else { + if (FileSystem.exists(rushPnpmPatchesFolder)) { + // eslint-disable-next-line no-console + console.log(`Deleting ${rushPnpmPatchesFolder}`); + FileSystem.deleteFolder(rushPnpmPatchesFolder); + } + } + + // Update patchedDependencies to pnpm configuration file + pnpmOptions?.updateGlobalPatchedDependencies(newGlobalPatchedDependencies); + + // Rerun installation to update + await this._doRushUpdateAsync(); + + this._terminal.writeWarningLine( + `Rush refreshed the ${RushConstants.pnpmConfigFilename}, shrinkwrap file and patch files under the ` + + `"${commonTempPnpmPatchesFolder}" folder.\n` + + ' Please commit this change to Git.' + ); + } + break; + } + } + } + + private async _doRushUpdateAsync(): Promise { + this._terminal.writeLine(); + this._terminal.writeLine(Colorize.green('Running "rush update"')); + this._terminal.writeLine(); + + const rushGlobalFolder: RushGlobalFolder = new RushGlobalFolder(); + const purgeManager: PurgeManager = new PurgeManager(this._rushConfiguration, rushGlobalFolder); + const installManagerOptions: IInstallManagerOptions = { + debug: this._debugEnabled, + allowShrinkwrapUpdates: true, + bypassPolicy: false, + noLink: false, + fullUpgrade: false, + recheckShrinkwrap: true, + networkConcurrency: undefined, + offline: false, + collectLogFile: false, + variant: process.env[EnvironmentVariableNames.RUSH_VARIANT], // For `rush-pnpm`, only use the env var + maxInstallAttempts: RushConstants.defaultMaxInstallAttempts, + pnpmFilterArgumentValues: [], + selectedProjects: new Set(this._rushConfiguration.projects), + checkOnly: false, + subspace: this._subspace, + terminal: this._terminal + }; + + const installManagerFactoryModule: typeof import('../logic/InstallManagerFactory') = await import( + /* webpackChunkName: 'InstallManagerFactory' */ + '../logic/InstallManagerFactory' + ); + const installManager: BaseInstallManager = + await installManagerFactoryModule.InstallManagerFactory.getInstallManagerAsync( + this._rushConfiguration, + rushGlobalFolder, + purgeManager, + installManagerOptions + ); + try { + await installManager.doInstallAsync(); + } finally { + await purgeManager.startDeleteAllAsync(); + } + } +} diff --git a/libraries/rush-lib/src/cli/RushStartupBanner.ts b/libraries/rush-lib/src/cli/RushStartupBanner.ts new file mode 100644 index 00000000000..132c3ba5b4a --- /dev/null +++ b/libraries/rush-lib/src/cli/RushStartupBanner.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 } from '@rushstack/terminal'; + +import { RushConstants } from '../logic/RushConstants'; +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) : ''; + + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.bold(`Rush Multi-Project Build Tool${versionSuffix}`) + + Colorize.cyan(` - ${RushConstants.rushWebSiteUrl}`) + + `\nNode.js version is ${nodeVersion}\n` + ); + } + + public static logStreamlinedBanner(rushVersion: string, isManaged: boolean): void { + const nodeVersion: string = this._formatNodeVersion(); + const versionSuffix: string = rushVersion ? ' ' + this._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})`; + } + + private static _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 new file mode 100644 index 00000000000..7efd2431f89 --- /dev/null +++ b/libraries/rush-lib/src/cli/RushXCommandLine.ts @@ -0,0 +1,390 @@ +// 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 ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; + +import { PackageJsonLookup, type IPackageJson, Text, FileSystem, Async } from '@rushstack/node-core-library'; +import { + Colorize, + ConsoleTerminalProvider, + DEFAULT_CONSOLE_WIDTH, + type ITerminalProvider, + PrintUtilities, + Terminal, + type ITerminal +} from '@rushstack/terminal'; + +import { Utilities } from '../utilities/Utilities'; +import { ProjectCommandSet } from '../logic/ProjectCommandSet'; +import { type ILaunchOptions, Rush } from '../api/Rush'; +import { RushConfiguration } from '../api/RushConfiguration'; +import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; +import { RushStartupBanner } from './RushStartupBanner'; +import { EventHooksManager } from '../logic/EventHooksManager'; +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'; + +interface IRushXCommandLineArguments { + /** + * Flag indicating whether to suppress any rushx startup information. + */ + quiet: boolean; + + /** + * Flag indicating whether the user has asked for help. + */ + help: boolean; + + /** + * Flag indicating whether the user has requested debug mode. + */ + isDebug: boolean; + + /** + * Flag indicating whether the user wants to not call hooks. + */ + ignoreHooks: boolean; + + /** + * The command to run (i.e., the target "script" in package.json.) + */ + commandName: string; + + /** + * Any additional arguments/parameters passed after the command name. + */ + commandArgs: string[]; +} + +class ProcessError extends Error { + public readonly exitCode: number; + public constructor(message: string, exitCode: number) { + super(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 + // + // Note: the prototype must also be set on any classes which extend this one + (this as any).__proto__ = ProcessError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any + + this.exitCode = exitCode; + } +} + +export class RushXCommandLine { + public static async launchRushXAsync(launcherVersion: string, options: ILaunchOptions): Promise { + try { + const rushxArguments: IRushXCommandLineArguments = RushXCommandLine._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 && !help; + if (attemptHooks) { + try { + 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)); + } + } + // Node.js can sometimes accidentally terminate with a zero exit code (e.g. for an uncaught + // 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(terminal, rushxArguments, rushConfiguration, options); + if (attemptHooks) { + try { + 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)); + } + } + + // Getting here means that we are all done with no major errors + process.exitCode = 0; + } catch (error) { + if (error instanceof ProcessError) { + process.exitCode = error.exitCode; + } else { + process.exitCode = 1; + } + // eslint-disable-next-line no-console + console.error(Colorize.red('Error: ' + (error as Error).message)); + } + } + + private static async _launchRushXInternalAsync( + terminal: ITerminal, + 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.' + ); + } + + 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 packageJson: IPackageJson = packageJsonLookup.loadPackageJson(packageJsonFilePath); + + const projectCommandSet: ProjectCommandSet = new ProjectCommandSet(packageJson); + + if (rushxArguments.help) { + RushXCommandLine._showUsage(packageJson, projectCommandSet); + return; + } + + const scriptBody: string | undefined = projectCommandSet.tryGetScriptBody(rushxArguments.commandName); + + if (scriptBody === undefined) { + let errorMessage: string = `The command "${rushxArguments.commandName}" is not defined in the package.json file for this project.`; + + if (projectCommandSet.commandNames.length > 0) { + errorMessage += + '\nAvailable commands for this project are: ' + + projectCommandSet.commandNames.map((x) => `"${x}"`).join(', '); + } + + throw Error(errorMessage); + } + + 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) + ); + + commandWithArgs += ' ' + escapedRemainingArgs.join(' '); + + // Display it nicely without the extra quotes + commandWithArgsForDisplay += ' ' + rushxArguments.commandArgs.join(' '); + } + + if (!rushxArguments.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 + } + }); + + 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 + ); + } + } + + 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]); + } + } + + if (!commandName) { + help = true; + } + + 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; + } + + return { + help, + quiet, + isDebug, + ignoreHooks, + commandName, + commandArgs + }; + } + + private static _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(`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); + } + + 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) + ); + } + + 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.')); + // 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 new file mode 100644 index 00000000000..db67f19ea0c --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/AddAction.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 * as semver from 'semver'; + +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'; +import { + type IPackageForRushAdd, + type IPackageJsonUpdaterRushAddOptions, + SemVerStyle +} from '../../logic/PackageJsonUpdaterTypes'; +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 { + private readonly _exactFlag: CommandLineFlagParameter; + private readonly _caretFlag: CommandLineFlagParameter; + private readonly _devDependencyFlag: CommandLineFlagParameter; + private readonly _peerDependencyFlag: CommandLineFlagParameter; + private readonly _makeConsistentFlag: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + const documentation: string = [ + 'Adds specified package(s) to the dependencies of the current project (as determined by the current working directory)' + + ' 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_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_ACTION_NAME, + summary: 'Adds one or more dependencies to the package.json and runs rush update.', + documentation, + safeForSimultaneousRushProcesses: false, + 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_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_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_FLAG_NAME, + description: + 'If specified, the SemVer specifier added to the' + + ' package.json will be a prepended with a "caret" specifier ("^").' + }); + this._devDependencyFlag = this.defineFlagParameter({ + parameterLongName: '--dev', + description: + 'If specified, the package will be added to the "devDependencies" section of the package.json' + }); + this._peerDependencyFlag = this.defineFlagParameter({ + parameterLongName: '--peer', + description: + 'If specified, the package will be added to the "peerDependencies" section of the package.json' + }); + this._makeConsistentFlag = this.defineFlagParameter({ + 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.' + }); + } + + public async getUpdateOptionsAsync(): Promise { + const projects: RushConfigurationProject[] = super.getProjects(); + + if (this._caretFlag.value && this._exactFlag.value) { + throw new Error( + `Only one of "${this._caretFlag.longName}" and "${this._exactFlag.longName}" should be specified` + ); + } + + const packagesToAdd: IPackageForRushAdd[] = []; + + for (const specifiedPackageName of this.specifiedPackageNameList) { + /** + * Name & Version + */ + let packageName: string = specifiedPackageName; + let version: string | undefined = undefined; + const parts: string[] = packageName.split('@'); + + if (parts[0] === '') { + // this is a scoped package + packageName = '@' + parts[1]; + version = parts[2]; + } else { + packageName = parts[0]; + version = parts[1]; + } + + if (!this.rushConfiguration.packageNameParser.isValidName(packageName)) { + throw new Error(`The package name "${packageName}" is not valid.`); + } + + if (version && version !== 'latest') { + const specifier: DependencySpecifier = new DependencySpecifier(packageName, version); + if (!semver.validRange(specifier.versionSpecifier) && !semver.valid(specifier.versionSpecifier)) { + throw new Error(`The SemVer specifier "${version}" is not valid.`); + } + } + + /** + * RangeStyle + */ + let rangeStyle: SemVerStyle; + if (version && version !== 'latest') { + 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._packageNameListParameter.longName} specifier. In this case "${version}" was provided.` + ); + } + + rangeStyle = SemVerStyle.Passthrough; + } else { + rangeStyle = this._caretFlag.value + ? SemVerStyle.Caret + : this._exactFlag.value + ? SemVerStyle.Exact + : SemVerStyle.Tilde; + } + + packagesToAdd.push({ packageName, version, rangeStyle }); + } + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + true + ); + + return { + projects, + packagesToUpdate: packagesToAdd, + devDependency: this._devDependencyFlag.value, + peerDependency: this._peerDependencyFlag.value, + updateOtherPackages: this._makeConsistentFlag.value, + skipUpdate: this._skipUpdateFlag.value, + debugInstall: this.parser.isDebug, + actionName: this.actionName, + variant + }; + } +} diff --git a/libraries/rush-lib/src/cli/actions/AlertAction.ts b/libraries/rush-lib/src/cli/actions/AlertAction.ts new file mode 100644 index 00000000000..052220c06b0 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/AlertAction.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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 { RushAlerts } from '../../utilities/RushAlerts'; + +export class AlertAction extends BaseRushAction { + private readonly _snoozeParameter: CommandLineStringParameter; + private readonly _snoozeTimeFlagParameter: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'alert', + summary: '(EXPERIMENTAL) View and manage Rush alerts for the repository', + documentation: + 'This command displays the Rush alerts for this repository. Rush alerts are customizable announcements' + + ' and reminders that Rush prints occasionally on the command line.' + + ' The alert definitions can be found in the rush-alerts.json config file.', + parser + }); + + this._snoozeParameter = this.defineStringParameter({ + parameterLongName: '--snooze', + parameterShortName: '-s', + argumentName: 'ALERT_ID', + description: 'Temporarily suspend the specified alert for one week' + }); + + this._snoozeTimeFlagParameter = this.defineFlagParameter({ + parameterLongName: '--forever', + description: 'Combined with "--snooze", causes that alert to be suspended permanently' + }); + } + + public async runAsync(): Promise { + const rushAlerts: RushAlerts = await RushAlerts.loadFromConfigurationAsync( + this.rushConfiguration, + this.terminal + ); + const snoozeAlertId: string | undefined = this._snoozeParameter.value; + if (snoozeAlertId) { + const snoozeTimeFlag: boolean = this._snoozeTimeFlagParameter.value; + await rushAlerts.snoozeAlertsByAlertIdAsync(snoozeAlertId, snoozeTimeFlag); + } + await rushAlerts.printAllAlertsAsync(); + } +} diff --git a/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts b/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts new file mode 100644 index 00000000000..9e0c4364548 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts @@ -0,0 +1,120 @@ +// 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, + CommandLineStringParameter +} from '@rushstack/ts-command-line'; + +import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type * as PackageJsonUpdaterType from '../../logic/PackageJsonUpdater'; +import type { + IPackageForRushUpdate, + 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 { + /** + * The projects whose package.jsons should get updated + */ + projects: RushConfigurationProject[]; + /** + * The dependencies to be added. + */ + packagesToHandle: IPackageForRushUpdate[]; + /** + * If specified, "rush update" will not be run after updating the package.json file(s). + */ + skipUpdate: boolean; + /** + * If specified, "rush update" will be run in debug mode. + */ + 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 readonly _skipUpdateFlag: CommandLineFlagParameter; + protected readonly _packageNameListParameter: CommandLineStringListParameter; + protected readonly _allFlag: CommandLineFlagParameter; + protected readonly _variantParameter: CommandLineStringParameter; + + protected get specifiedPackageNameList(): readonly string[] { + return this._packageNameListParameter.values; + } + + 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; + + protected getProjects(): RushConfigurationProject[] { + if (this._allFlag.value) { + return this.rushConfiguration.projects; + } else { + const currentProject: RushConfigurationProject | undefined = + this.rushConfiguration.tryGetProjectForPath(process.cwd()); + + if (!currentProject) { + throw new Error( + `The rush "${this.actionName}" command must be invoked under a project` + + ` folder that is registered in ${RushConstants.rushJsonFilename} unless the ${this._allFlag.longName} is used.` + ); + } + + return [currentProject]; + } + } + + public async runAsync(): Promise { + const packageJsonUpdater: typeof PackageJsonUpdaterType = await import( + /* webpackChunkName: 'PackageJsonUpdater' */ '../../logic/PackageJsonUpdater' + ); + const updater: PackageJsonUpdaterType.PackageJsonUpdater = new packageJsonUpdater.PackageJsonUpdater( + this.terminal, + this.rushConfiguration, + this.rushGlobalFolder + ); + + const updateOptions: IPackageJsonUpdaterRushBaseUpdateOptions = await this.getUpdateOptionsAsync(); + await updater.doRushUpdateAsync(updateOptions); + } +} diff --git a/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts new file mode 100644 index 00000000000..52c556f5c3b --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.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 type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; + +import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; +import { Autoinstaller } from '../../logic/Autoinstaller'; + +export abstract class BaseAutoinstallerAction extends BaseRushAction { + protected readonly _name: IRequiredCommandLineStringParameter; + + public constructor(options: IBaseRushActionOptions) { + super(options); + + this._name = this.defineStringParameter({ + parameterLongName: '--name', + argumentName: 'AUTOINSTALLER_NAME', + required: true, + description: + 'The name of the autoinstaller, which must be one of the folders under common/autoinstallers.' + }); + } + + protected abstract prepareAsync(autoinstaller: Autoinstaller): Promise; + + protected async runAsync(): Promise { + const autoinstallerName: string = this._name.value; + const autoinstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName, + rushConfiguration: this.rushConfiguration, + rushGlobalFolder: this.rushGlobalFolder + }); + + await this.prepareAsync(autoinstaller); + + 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 new file mode 100644 index 00000000000..b13b34fe681 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseInstallAction.ts @@ -0,0 +1,358 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { + CommandLineFlagParameter, + CommandLineIntegerParameter, + CommandLineStringParameter, + IRequiredCommandLineIntegerParameter +} from '@rushstack/ts-command-line'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; +import { Event } from '../../api/EventHooks'; +import type { BaseInstallManager } from '../../logic/base/BaseInstallManager'; +import type { IInstallManagerOptions } from '../../logic/base/BaseInstallManagerTypes'; +import { PurgeManager } from '../../logic/PurgeManager'; +import { SetupChecks } from '../../logic/SetupChecks'; +import { StandardScriptUpdater } from '../../logic/StandardScriptUpdater'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; +import { RushConstants } from '../../logic/RushConstants'; +import { SUBSPACE_LONG_ARG_NAME, type SelectionParameterSet } from '../parsing/SelectionParameterSet'; +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()` + */ +interface ISubspaceInstallationData { + selectedProjects: Set; + pnpmFilterArgumentValues: string[]; +} + +/** + * This is the common base class for InstallAction and UpdateAction. + */ +export abstract class BaseInstallAction extends BaseRushAction { + protected readonly _variantParameter: CommandLineStringParameter; + protected readonly _purgeParameter: CommandLineFlagParameter; + protected readonly _bypassPolicyParameter: CommandLineFlagParameter; + protected readonly _noLinkParameter: CommandLineFlagParameter; + protected readonly _networkConcurrencyParameter: CommandLineIntegerParameter; + protected readonly _debugPackageManagerParameter: CommandLineFlagParameter; + protected readonly _maxInstallAttempts: IRequiredCommandLineIntegerParameter; + protected readonly _ignoreHooksParameter: CommandLineFlagParameter; + protected readonly _offlineParameter: CommandLineFlagParameter; + /* + * Subclasses can initialize the _selectionParameters property in order for + * the parameters to be written to the telemetry file + */ + protected _selectionParameters?: SelectionParameterSet; + + public constructor(options: IBaseRushActionOptions) { + super(options); + + this._purgeParameter = this.defineFlagParameter({ + parameterLongName: '--purge', + parameterShortName: '-p', + description: 'Perform "rush purge" before starting the installation' + }); + this._bypassPolicyParameter = this.defineFlagParameter({ + parameterLongName: RushConstants.bypassPolicyFlagLongName, + description: `Overrides enforcement of the "gitPolicy" rules from ${RushConstants.rushJsonFilename} (use honorably!)` + }); + this._noLinkParameter = this.defineFlagParameter({ + parameterLongName: '--no-link', + description: + 'If "--no-link" is specified, then project symlinks will NOT be created' + + ' after the installation completes. You will need to run "rush link" manually.' + + ' This flag is useful for automated builds that want to report stages individually' + + ' or perform extra operations in between the two stages. This flag is not supported' + + ' when using workspaces.' + }); + this._networkConcurrencyParameter = this.defineIntegerParameter({ + parameterLongName: '--network-concurrency', + argumentName: 'COUNT', + description: + 'If specified, limits the maximum number of concurrent network requests.' + + ' This is useful when troubleshooting network failures.' + }); + this._debugPackageManagerParameter = this.defineFlagParameter({ + parameterLongName: '--debug-package-manager', + description: + 'Activates verbose logging for the package manager. You will probably want to pipe' + + ' the output of Rush to a file when using this command.' + }); + this._maxInstallAttempts = this.defineIntegerParameter({ + parameterLongName: '--max-install-attempts', + argumentName: 'NUMBER', + description: `Overrides the default maximum number of install attempts.`, + defaultValue: RushConstants.defaultMaxInstallAttempts + }); + this._ignoreHooksParameter = this.defineFlagParameter({ + parameterLongName: '--ignore-hooks', + description: + `Skips execution of the "eventHooks" scripts defined in ${RushConstants.rushJsonFilename}. ` + + 'Make sure you know what you are skipping.' + }); + this._offlineParameter = this.defineFlagParameter({ + parameterLongName: '--offline', + description: + `Enables installation to be performed without internet access. PNPM will instead report an error` + + ` if the necessary NPM packages cannot be obtained from the local cache.` + + ` For details, see the documentation for PNPM's "--offline" parameter.` + }); + this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); + } + + protected abstract buildInstallOptionsAsync(): Promise>; + + protected async runAsync(): Promise { + const installManagerOptions: Omit = + await this.buildInstallOptionsAsync(); + + // If we are doing a filtered install and subspaces is enabled, we need to find the affected subspaces and install for all of them. + let selectedSubspaces: ReadonlySet | undefined; + const subspaceInstallationDataBySubspace: Map = new Map(); + if (this.rushConfiguration.subspacesFeatureEnabled) { + // Selecting all subspaces if preventSelectingAllSubspaces is not enabled in subspaces.json + if ( + this.rushConfiguration.subspacesConfiguration?.preventSelectingAllSubspaces && + !this._selectionParameters?.didUserSelectAnything() + ) { + 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.` + ) + ); + throw new AlreadyReportedError(); + } + + const { selectedProjects } = installManagerOptions; + + if (selectedProjects.size === this.rushConfiguration.projects.length) { + // Optimization for the common case, equivalent to the logic below + selectedSubspaces = new Set(this.rushConfiguration.subspaces); + } else { + selectedSubspaces = this.rushConfiguration.getSubspacesForProjects(selectedProjects); + for (const selectedSubspace of selectedSubspaces) { + let subspaceSelectedProjects: Set; + let pnpmFilterArgumentValues: string[]; + if (selectedSubspace.getPnpmOptions()?.alwaysFullInstall) { + subspaceSelectedProjects = new Set(selectedSubspace.getProjects()); + pnpmFilterArgumentValues = []; + } else { + // This may involve filtered installs. Go through each project, add its subspace's pnpm filter arguments + subspaceSelectedProjects = new Set(); + pnpmFilterArgumentValues = []; + for (const project of selectedSubspace.getProjects()) { + if (selectedProjects.has(project)) { + subspaceSelectedProjects.add(project); + pnpmFilterArgumentValues.push(project.packageName); + } + } + } + + subspaceInstallationDataBySubspace.set(selectedSubspace, { + selectedProjects: subspaceSelectedProjects, + pnpmFilterArgumentValues + }); + } + } + } + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + false + ); + if (selectedSubspaces) { + // Check each subspace for version inconsistencies + for (const subspace of selectedSubspaces) { + VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this.terminal, { + subspace, + variant + }); + } + } else { + VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this.terminal, { + subspace: undefined, + variant + }); + } + + const stopwatch: Stopwatch = Stopwatch.start(); + + SetupChecks.validate(this.rushConfiguration); + let warnAboutScriptUpdate: boolean = false; + if (this.actionName === 'update') { + warnAboutScriptUpdate = await StandardScriptUpdater.updateAsync(this.rushConfiguration); + } else { + await StandardScriptUpdater.validateAsync(this.rushConfiguration); + } + + this.eventHooksManager.handle( + Event.preRushInstall, + this.parser.isDebug, + this._ignoreHooksParameter.value + ); + + const purgeManager: PurgeManager = new PurgeManager(this.rushConfiguration, this.rushGlobalFolder); + + if (this._purgeParameter.value!) { + // eslint-disable-next-line no-console + console.log('The --purge flag was specified, so performing "rush purge"'); + purgeManager.purgeNormal(); + // eslint-disable-next-line no-console + console.log(''); + } + + if (this._networkConcurrencyParameter.value) { + if (this.rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + `The "${this._networkConcurrencyParameter.longName}" parameter is` + + ` only supported when using the PNPM package manager.` + ); + } + } + + if (this._maxInstallAttempts.value < 1) { + throw new Error(`The value of "${this._maxInstallAttempts.longName}" must be positive and nonzero.`); + } + + const installManagerFactoryModule: typeof import('../../logic/InstallManagerFactory') = await import( + /* webpackChunkName: 'InstallManagerFactory' */ + '../../logic/InstallManagerFactory' + ); + let installSuccessful: boolean = true; + + try { + if (selectedSubspaces) { + // Run the install for each affected subspace + for (const subspace of selectedSubspaces) { + const subspaceInstallationData: ISubspaceInstallationData | undefined = + subspaceInstallationDataBySubspace.get(subspace); + // eslint-disable-next-line no-console + console.log(Colorize.green(`Installing for subspace: ${subspace.subspaceName}`)); + let installManagerOptionsForInstall: IInstallManagerOptions; + if (subspaceInstallationData) { + // This will install the selected of projects in the subspace + const { selectedProjects, pnpmFilterArgumentValues } = subspaceInstallationData; + installManagerOptionsForInstall = { + ...installManagerOptions, + selectedProjects, + // IMPORTANT: SelectionParameterSet.getPnpmFilterArgumentValuesAsync() already calculated + // installManagerOptions.pnpmFilterArgumentValues using PNPM CLI operators such as "...my-app". + // But with subspaces, "pnpm install" can only see the subset of projects in subspace's temp workspace, + // therefore an operator like "--filter ...my-app" will malfunction. As a workaround, here we are + // overwriting installManagerOptions.pnpmFilterArgumentValues with a flat last of project names that + // were calculated by Rush. + // + // TODO: If the flat list produces too many "--filter" arguments, invoking "pnpm install" will exceed + // the maximum command length and fail on Windows OS. Once this is solved, we can eliminate the + // redundant logic from SelectionParameterSet.getPnpmFilterArgumentValuesAsync(). + pnpmFilterArgumentValues, + subspace + }; + } else { + // This will install all projects in the subspace + installManagerOptionsForInstall = { + ...installManagerOptions, + pnpmFilterArgumentValues: [], + subspace + }; + } + + await this._doInstallAsync( + installManagerFactoryModule, + purgeManager, + installManagerOptionsForInstall + ); + } + } else { + // Simple case when subspacesFeatureEnabled=false + await this._doInstallAsync(installManagerFactoryModule, purgeManager, { + ...installManagerOptions, + subspace: this.rushConfiguration.defaultSubspace + }); + } + } catch (error) { + installSuccessful = false; + throw error; + } finally { + await measureAsyncFn('rush:installManager:startDeleteAllAsync', () => + purgeManager.startDeleteAllAsync() + ); + stopwatch.stop(); + + this._collectTelemetry(stopwatch, installManagerOptions, installSuccessful); + this.parser.flushTelemetry(); + this.eventHooksManager.handle( + Event.postRushInstall, + this.parser.isDebug, + this._ignoreHooksParameter.value + ); + } + + if (warnAboutScriptUpdate) { + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.yellow( + 'Rush refreshed some files in the "common/scripts" folder.' + + ' Please commit this change to Git.' + ) + ); + } + + // eslint-disable-next-line no-console + console.log( + '\n' + Colorize.green(`Rush ${this.actionName} finished successfully. (${stopwatch.toString()})`) + ); + } + + private async _doInstallAsync( + installManagerFactoryModule: typeof import('../../logic/InstallManagerFactory'), + purgeManager: PurgeManager, + installManagerOptions: IInstallManagerOptions + ): Promise { + const installManager: BaseInstallManager = + await installManagerFactoryModule.InstallManagerFactory.getInstallManagerAsync( + this.rushConfiguration, + this.rushGlobalFolder, + purgeManager, + installManagerOptions + ); + + await measureAsyncFn('rush:installManager:doInstallAsync', () => installManager.doInstallAsync()); + } + + private _collectTelemetry( + stopwatch: Stopwatch, + installManagerOptions: Omit, + success: boolean + ): void { + if (this.parser.telemetry) { + const extraData: Record = { + mode: this.actionName, + clean: (!!this._purgeParameter.value).toString(), + debug: installManagerOptions.debug.toString(), + full: installManagerOptions.fullUpgrade.toString(), + ...this.getParameterStringMap(), + ...this._selectionParameters?.getTelemetry() + }; + this.parser.telemetry.log({ + name: 'install', + durationInSeconds: stopwatch.duration, + result: success ? 'Succeeded' : 'Failed', + extraData + }); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/BaseRushAction.ts b/libraries/rush-lib/src/cli/actions/BaseRushAction.ts new file mode 100644 index 00000000000..85469814a89 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseRushAction.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 * as path from 'node:path'; + +import { CommandLineAction, type ICommandLineActionOptions } from '@rushstack/ts-command-line'; +import { LockFile } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { EventHooksManager } from '../../logic/EventHooksManager'; +import { RushCommandLineParser } from '../RushCommandLineParser'; +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 { + /** + * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously + * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the + * same time.) If your command makes sense to run concurrently with other operations, + * set safeForSimultaneousRushProcesses=true to disable this protection. In particular, this is needed for + * custom scripts that invoke other Rush commands. + */ + safeForSimultaneousRushProcesses?: boolean; + + /** + * The rush parser. + */ + parser: RushCommandLineParser; +} + +/** + * The base class for a few specialized Rush command-line actions that + * can be used without a rush.json configuration. + */ +export abstract class BaseConfiglessRushAction extends CommandLineAction implements IRushCommand { + private _safeForSimultaneousRushProcesses: boolean; + + 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); + + 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 override async onExecuteAsync(): Promise { + this._ensureEnvironment(); + + if (this.rushConfiguration) { + if (!this._safeForSimultaneousRushProcesses) { + if (!LockFile.tryAcquire(this.rushConfiguration.commonTempFolder, 'rush')) { + this.terminal.writeLine( + Colorize.red(`Another Rush command is already running in this repository.`) + ); + process.exit(1); + } + } + } + + if (!RushCommandLineParser.shouldRestrictConsoleOutput()) { + this.terminal.write(`Starting "rush ${this.actionName}"\n`); + } + + await measureAsyncFn(`${PERF_PREFIX}:runAsync`, () => this.runAsync()); + } + + /** + * All Rush actions need to implement this method. This method runs after + * environment has been set up by the base class. + */ + protected abstract runAsync(): Promise; + + private _ensureEnvironment(): void { + if (this.rushConfiguration) { + // eslint-disable-next-line dot-notation + let environmentPath: string | undefined = process.env['PATH']; + environmentPath = + path.join(this.rushConfiguration.commonTempFolder, 'node_modules', '.bin') + + path.delimiter + + environmentPath; + // eslint-disable-next-line dot-notation + process.env['PATH'] = environmentPath; + } + } +} + +/** + * The base class that most Rush command-line actions should extend. + */ +export abstract class BaseRushAction extends BaseConfiglessRushAction { + private _eventHooksManager: EventHooksManager | undefined; + + protected get eventHooksManager(): EventHooksManager { + if (!this._eventHooksManager) { + this._eventHooksManager = new EventHooksManager(this.rushConfiguration); + } + + return this._eventHooksManager; + } + + protected readonly rushConfiguration!: RushConfiguration; + + protected override async onExecuteAsync(): Promise { + if (!this.rushConfiguration) { + throw Utilities.getRushConfigNotFoundError(); + } + + this._throwPluginErrorIfNeed(); + + await measureAsyncFn(`${PERF_PREFIX}:initializePluginsAsync`, () => + this.parser.pluginManager.tryInitializeAssociatedCommandPluginsAsync(this.actionName) + ); + + this._throwPluginErrorIfNeed(); + + const { hooks: sessionHooks } = this.rushSession; + 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.onExecuteAsync(); + } + + /** + * If an error is encountered while trying to load plugins, it is saved in the `PluginManager.error` + * property, so we can defer throwing it until when `_throwPluginErrorIfNeed()` is called. + */ + private _throwPluginErrorIfNeed(): void { + // If the plugin configuration is broken, these three commands are used to fix the problem: + // + // "rush update" + // "rush init-autoinstaller" + // "rush update-autoinstaller" + // + // In addition, the "rush setup" command is designed to help new users configure their access + // to a private NPM registry, which means it can't rely on plugins that might live in that + // registry. + // + // Thus we do not report plugin errors when invoking these commands. + if (!['update', 'init-autoinstaller', 'update-autoinstaller', 'setup'].includes(this.actionName)) { + const pluginError: Error | undefined = this.parser.pluginManager.error; + if (pluginError) { + throw pluginError; + } + } + } +} 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 new file mode 100644 index 00000000000..5ed9fc1af4d --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/ChangeAction.ts @@ -0,0 +1,768 @@ +// 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 child_process from 'node:child_process'; + +import type * as InquirerType from 'inquirer'; + +import type { + CommandLineFlagParameter, + CommandLineStringParameter, + CommandLineChoiceParameter +} from '@rushstack/ts-command-line'; +import { FileSystem, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; +import { getRepoRoot } from '@rushstack/package-deps-hash'; + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { type IChangeFile, type IChangeInfo, ChangeType } from '../../api/ChangeManagement'; +import { ChangeFile } from '../../api/ChangeFile'; +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { ChangeFiles } from '../../logic/ChangeFiles'; +import { + type VersionPolicy, + type IndividualVersionPolicy, + type LockStepVersionPolicy, + VersionPolicyDefinitionName +} from '../../api/VersionPolicy'; +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'; +const BULK_BUMP_TYPE_LONG_NAME: string = '--bump-type'; + +export class ChangeAction extends BaseRushAction { + private readonly _git: Git; + private readonly _verifyParameter: CommandLineFlagParameter; + private readonly _noFetchParameter: CommandLineFlagParameter; + private readonly _targetBranchParameter: CommandLineStringParameter; + private readonly _changeEmailParameter: CommandLineStringParameter; + private readonly _bulkChangeParameter: CommandLineFlagParameter; + private readonly _bulkChangeMessageParameter: CommandLineStringParameter; + private readonly _bulkChangeBumpTypeParameter: CommandLineChoiceParameter; + private readonly _overwriteFlagParameter: CommandLineFlagParameter; + private readonly _commitChangesFlagParameter: CommandLineFlagParameter; + private readonly _commitChangesMessageStringParameter: CommandLineStringParameter; + + private _targetBranchName: string | undefined; + + public constructor(parser: RushCommandLineParser) { + const documentation: string = [ + 'Asks a series of questions and then generates a -.json file ' + + 'in the common folder. The `publish` command will consume these files and perform the proper ' + + 'version bumps. Note these changes will eventually be published in a changelog.md file in each package.', + '', + 'The possible types of changes are: ', + '', + 'MAJOR - these are breaking changes that are not backwards compatible. ' + + 'Examples are: renaming a public class, adding/removing a non-optional ' + + 'parameter from a public API, or renaming an variable or function that ' + + 'is exported.', + '', + 'MINOR - these are changes that are backwards compatible (but not ' + + 'forwards compatible). Examples are: adding a new public API or adding an ' + + 'optional parameter to a public API', + '', + 'PATCH - these are changes that are backwards and forwards compatible. ' + + 'Examples are: Modifying a private API or fixing a bug in the logic ' + + 'of how an existing API works.', + '', + "NONE - these are changes that are backwards and forwards compatible and don't require an immediate release. " + + 'Examples are: Modifying dev tooling configuration like eslint.', + '', + 'HOTFIX (EXPERIMENTAL) - these are changes that are hotfixes targeting a ' + + 'specific older version of the package. When a hotfix change is added, ' + + 'other changes will not be able to increment the version number. ' + + `Enable this feature by setting 'hotfixChangeEnabled' in your ${RushConstants.rushJsonFilename}.`, + '' + ].join('\n'); + super({ + actionName: 'change', + summary: + 'Records changes made to projects, indicating how the package version number should be bumped ' + + 'for the next publish.', + documentation, + safeForSimultaneousRushProcesses: true, + parser + }); + + this._git = new Git(this.rushConfiguration); + + this._verifyParameter = this.defineFlagParameter({ + parameterLongName: '--verify', + parameterShortName: '-v', + description: 'Verify the change file has been generated and that it is a valid JSON file' + }); + + this._noFetchParameter = this.defineFlagParameter({ + parameterLongName: '--no-fetch', + description: 'Skips fetching the baseline branch before running "git diff" to detect changes.' + }); + + this._targetBranchParameter = this.defineStringParameter({ + parameterLongName: '--target-branch', + parameterShortName: '-b', + argumentName: 'BRANCH', + description: + 'If this parameter is specified, compare the checked out branch with the specified branch to ' + + 'determine which projects were changed. If this parameter is not specified, the checked out branch ' + + 'is compared against the "main" branch.' + }); + + this._overwriteFlagParameter = this.defineFlagParameter({ + parameterLongName: '--overwrite', + description: + `If a changefile already exists, overwrite without prompting ` + + `(or erroring in ${BULK_LONG_NAME} mode).` + }); + + this._commitChangesFlagParameter = this.defineFlagParameter({ + parameterLongName: '--commit', + parameterShortName: '-c', + description: `If this flag is specified generated changefiles will be commited automatically.` + }); + + this._commitChangesMessageStringParameter = this.defineStringParameter({ + parameterLongName: '--commit-message', + argumentName: 'COMMIT_MESSAGE', + description: `If this parameter is specified generated changefiles will be commited automatically with the specified commit message.` + }); + + this._changeEmailParameter = this.defineStringParameter({ + parameterLongName: '--email', + argumentName: 'EMAIL', + description: + 'The email address to use in changefiles. If this parameter is not provided, the email address ' + + 'will be detected or prompted for in interactive mode.' + }); + + this._bulkChangeParameter = this.defineFlagParameter({ + parameterLongName: BULK_LONG_NAME, + description: + 'If this flag is specified, apply the same change message and bump type to all changed projects. ' + + `The ${BULK_MESSAGE_LONG_NAME} and the ${BULK_BUMP_TYPE_LONG_NAME} parameters must be specified if the ` + + `${BULK_LONG_NAME} parameter is specified` + }); + + this._bulkChangeMessageParameter = this.defineStringParameter({ + parameterLongName: BULK_MESSAGE_LONG_NAME, + argumentName: 'MESSAGE', + description: `The message to apply to all changed projects if the ${BULK_LONG_NAME} flag is provided.` + }); + + this._bulkChangeBumpTypeParameter = this.defineChoiceParameter({ + parameterLongName: BULK_BUMP_TYPE_LONG_NAME, + alternatives: [...Object.keys(this._getBumpOptions())], + description: `The bump type to apply to all changed projects if the ${BULK_LONG_NAME} flag is provided.` + }); + } + + public async runAsync(): Promise { + const targetBranch: string = await this._getTargetBranchAsync(); + // eslint-disable-next-line no-console + console.log(`The target branch is ${targetBranch}`); + + if (this._verifyParameter.value) { + const errors: string[] = [ + this._bulkChangeParameter, + this._bulkChangeMessageParameter, + this._bulkChangeBumpTypeParameter, + this._overwriteFlagParameter, + this._commitChangesFlagParameter + ] + .map((parameter) => { + return parameter.value + ? `The {${this._bulkChangeParameter.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); + }); + throw new AlreadyReportedError(); + } + + await this._verifyAsync(); + return; + } + + const sortedProjectList: string[] = (await this._getChangedProjectNamesAsync()).sort(); + if (sortedProjectList.length === 0) { + this._logNoChangeFileRequired(); + await this._warnUnstagedChangesAsync(); + return; + } + + 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) { + if ( + !this._bulkChangeBumpTypeParameter.value || + (!this._bulkChangeMessageParameter.value && + this._bulkChangeBumpTypeParameter.value !== ChangeType[ChangeType.none]) + ) { + throw new Error( + `The ${this._bulkChangeBumpTypeParameter.longName} and ${this._bulkChangeMessageParameter.longName} ` + + `parameters must provided if the ${this._bulkChangeParameter.longName} flag is provided. If the value ` + + `"${ChangeType[ChangeType.none]}" is provided to the ${ + this._bulkChangeBumpTypeParameter.longName + } ` + + `parameter, the ${this._bulkChangeMessageParameter.longName} parameter may be omitted.` + ); + } + + const email: string | undefined = this._changeEmailParameter.value || this._detectEmail(); + if (!email) { + throw new Error( + "Unable to detect Git email and an email address wasn't provided using the " + + `${this._changeEmailParameter.longName} parameter.` + ); + } + + const errors: string[] = []; + + const comment: string = this._bulkChangeMessageParameter.value || ''; + const changeType: string = this._bulkChangeBumpTypeParameter.value; + for (const packageName of sortedProjectList) { + const allowedBumpTypes: string[] = Object.keys(this._getBumpOptions(packageName)); + let projectChangeType: string = changeType; + if (allowedBumpTypes.length === 0) { + projectChangeType = ChangeType[ChangeType.none]; + } else if ( + projectChangeType !== ChangeType[ChangeType.none] && + allowedBumpTypes.indexOf(projectChangeType) === -1 + ) { + errors.push(`The "${projectChangeType}" change type is not allowed for package "${packageName}".`); + } + + changeFileData.set(packageName, { + changes: [ + { + comment, + type: projectChangeType, + packageName + } as IChangeInfo + ], + packageName, + email + }); + } + + if (errors.length > 0) { + for (const error of errors) { + // eslint-disable-next-line no-console + console.error(error); + } + + throw new AlreadyReportedError(); + } + } else if (this._bulkChangeBumpTypeParameter.value || this._bulkChangeMessageParameter.value) { + throw new Error( + `The ${this._bulkChangeParameter.longName} flag must be provided with the ` + + `${this._bulkChangeBumpTypeParameter.longName} and ${this._bulkChangeMessageParameter.longName} parameters.` + ); + } else { + interactiveMode = true; + + const existingChangeComments: Map = ChangeFiles.getChangeComments( + await this._getChangeFilesAsync() + ); + changeFileData = await this._promptForChangeFileDataAsync( + promptModule, + sortedProjectList, + existingChangeComments + ); + + if (this._isEmailRequired(changeFileData)) { + const email: string = this._changeEmailParameter.value + ? this._changeEmailParameter.value + : await this._detectOrAskForEmailAsync(promptModule); + changeFileData.forEach((changeFile: IChangeFile) => { + changeFile.email = this.rushConfiguration.getProjectByName(changeFile.packageName)?.versionPolicy + ?.includeEmailInChangeFile + ? email + : ''; + }); + } + } + let changefiles: string[]; + try { + changefiles = await this._writeChangeFilesAsync( + promptModule, + changeFileData, + this._overwriteFlagParameter.value, + interactiveMode + ); + } catch (error) { + throw new Error(`There was an error creating a change file: ${(error as Error).toString()}`); + } + if (this._commitChangesFlagParameter.value || this._commitChangesMessageStringParameter.value) { + if (changefiles && changefiles.length !== 0) { + await this._stageAndCommitGitChangesAsync( + changefiles, + this._commitChangesMessageStringParameter.value || + this.rushConfiguration.gitChangefilesCommitMessage || + 'Rush change' + ); + } else { + this.terminal.writeWarningLine('Warning: No change files generated, nothing to commit.'); + } + } + } + + private _generateHostMap(): Map { + const hostMap: Map = new Map(); + for (const project of this.rushConfiguration.projects) { + let hostProjectName: string = project.packageName; + if (project.versionPolicy?.isLockstepped) { + const lockstepPolicy: LockStepVersionPolicy = project.versionPolicy as LockStepVersionPolicy; + hostProjectName = lockstepPolicy.mainProject || project.packageName; + } + + hostMap.set(project, hostProjectName); + } + + return hostMap; + } + + private async _verifyAsync(): Promise { + const changedPackages: string[] = await this._getChangedProjectNamesAsync(); + if (changedPackages.length > 0) { + await this._validateChangeFileAsync(changedPackages); + } else { + this._logNoChangeFileRequired(); + } + } + + private async _getTargetBranchAsync(): Promise { + if (!this._targetBranchName) { + this._targetBranchName = + this._targetBranchParameter.value || (await this._git.getRemoteDefaultBranchAsync()); + } + + return this._targetBranchName; + } + + private async _getChangedProjectNamesAsync(): Promise { + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(this.rushConfiguration); + const changedProjects: Set = + await projectChangeAnalyzer.getChangedProjectsAsync({ + targetBranchName: await this._getTargetBranchAsync(), + 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 + }); + const projectHostMap: Map = this._generateHostMap(); + + const changedProjectNames: Set = new Set(); + for (const changedProject of changedProjects) { + if (changedProject.shouldPublish && !changedProject.versionPolicy?.exemptFromRushChange) { + const hostName: string | undefined = projectHostMap.get(changedProject); + if (hostName) { + changedProjectNames.add(hostName); + } + } + } + + return Array.from(changedProjectNames); + } + + private async _validateChangeFileAsync(changedPackages: string[]): Promise { + const files: string[] = await this._getChangeFilesAsync(); + ChangeFiles.validate(files, changedPackages, this.rushConfiguration); + } + + private async _getChangeFilesAsync(): 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, + true, + relativeChangesFolder + ); + + const result: string[] = []; + for (const changedFile of changedFiles) { + result.push(path.join(repoRoot, changedFile)); + } + + return result; + } + + /** + * The main loop which prompts the user for information on changed projects. + */ + private async _promptForChangeFileDataAsync( + promptModule: InquirerType.PromptModule, + sortedProjectList: string[], + existingChangeComments: Map + ): Promise> { + const changedFileData: Map = new Map(); + + for (const projectName of sortedProjectList) { + const changeInfo: IChangeInfo | undefined = await this._askQuestionsAsync( + promptModule, + projectName, + existingChangeComments + ); + if (changeInfo) { + // Save the info into the change file + let changeFile: IChangeFile | undefined = changedFileData.get(changeInfo.packageName); + if (!changeFile) { + changeFile = { + changes: [], + packageName: changeInfo.packageName, + email: undefined + }; + changedFileData.set(changeInfo.packageName, changeFile!); + } + + changeFile!.changes.push(changeInfo); + } + } + + return changedFileData; + } + + /** + * 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}`); + const comments: string[] | undefined = existingChangeComments.get(packageName); + if (comments) { + // eslint-disable-next-line no-console + console.log(`Found existing comments:`); + comments.forEach((comment) => { + // eslint-disable-next-line no-console + console.log(` > ${comment}`); + }); + const { appendComment }: { appendComment: 'skip' | 'append' } = await promptModule({ + name: 'appendComment', + type: 'list', + default: 'skip', + message: 'Append to existing comments or skip?', + choices: [ + { + name: 'Skip', + value: 'skip' + }, + { + name: 'Append', + value: 'append' + } + ] + }); + + if (appendComment === 'skip') { + return undefined; + } else { + return await this._promptForCommentsAsync(promptModule, packageName); + } + } else { + return await this._promptForCommentsAsync(promptModule, 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:` + }); + + if (Object.keys(bumpOptions).length === 0 || !comment) { + return { + packageName: packageName, + comment: comment || '', + type: ChangeType[ChangeType.none] + } as IChangeInfo; + } else { + const { bumpType }: { bumpType: string } = await promptModule({ + choices: Object.keys(bumpOptions).map((option) => { + return { + value: option, + name: bumpOptions[option] + }; + }), + default: 'patch', + message: 'Select the type of change:', + name: 'bumpType', + type: 'list' + }); + + return { + packageName: packageName, + comment: comment, + type: bumpType + } as IChangeInfo; + } + } + + private _getBumpOptions(packageName?: string): { [type: string]: string } { + let bumpOptions: { [type: string]: string } = + this.rushConfiguration && this.rushConfiguration.hotfixChangeEnabled + ? { + [ChangeType[ChangeType.hotfix]]: + 'hotfix - for changes that need to be published in a separate hotfix package' + } + : { + [ChangeType[ChangeType.major]]: + 'major - for changes that break compatibility, e.g. removing an API', + [ChangeType[ChangeType.minor]]: 'minor - for backwards compatible changes, e.g. adding a new API', + [ChangeType[ChangeType.patch]]: + 'patch - for changes that do not affect compatibility, e.g. fixing a bug', + [ChangeType[ChangeType.none]]: + 'none - for changes that do not need an immediate release, e.g. eslint config change' + }; + + if (packageName) { + const project: RushConfigurationProject | undefined = + this.rushConfiguration.getProjectByName(packageName); + const versionPolicy: VersionPolicy | undefined = project!.versionPolicy; + + if (versionPolicy) { + if (versionPolicy.definitionName === VersionPolicyDefinitionName.lockStepVersion) { + const lockStepPolicy: LockStepVersionPolicy = versionPolicy as LockStepVersionPolicy; + // No need to ask for bump types if project is lockstep versioned with an explicit nextBump + if (lockStepPolicy.nextBump !== undefined) { + bumpOptions = {}; + } + } else if (versionPolicy.definitionName === VersionPolicyDefinitionName.individualVersion) { + const individualPolicy: IndividualVersionPolicy = versionPolicy as IndividualVersionPolicy; + if (individualPolicy.lockedMajor !== undefined) { + delete bumpOptions[ChangeType[ChangeType.major]]; + } + } + } + } + + return bumpOptions; + } + + private _isEmailRequired(changeFileData: Map): boolean { + return [...changeFileData.values()].some( + (changeFile) => + !!this.rushConfiguration.getProjectByName(changeFile.packageName)?.versionPolicy + ?.includeEmailInChangeFile + ); + } + + /** + * 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 { + return ( + (await this._detectAndConfirmEmailAsync(promptModule)) || + (await this._promptForEmailAsync(promptModule)) + ); + } + + private _detectEmail(): string | undefined { + try { + return child_process + .execSync('git config user.email') + .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...'); + return undefined; + } + } + + /** + * 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 { + 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}?` + } + ]); + return isCorrectEmail ? email : undefined; + } else { + return undefined; + } + } + + /** + * 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 + } + } + ]); + return email; + } + + private async _warnUnstagedChangesAsync(): Promise { + try { + const hasUnstagedChanges: boolean = await this._git.hasUnstagedChangesAsync(); + if (hasUnstagedChanges) { + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.yellow( + 'Warning: You have unstaged changes, which do not trigger prompting for change ' + + 'descriptions.' + ) + ); + } + } catch (error) { + // eslint-disable-next-line no-console + console.log(`An error occurred when detecting unstaged changes: ${error}`); + } + } + + /** + * 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 + ): Promise { + const writtenFiles: string[] = []; + await changeFileData.forEach(async (changeFile: IChangeFile) => { + const writtenFile: string | undefined = await this._writeChangeFileAsync( + promptModule, + changeFile, + overwrite, + interactiveMode + ); + if (writtenFile) { + writtenFiles.push(writtenFile); + } + }); + return writtenFiles; + } + + private async _writeChangeFileAsync( + promptModule: InquirerType.PromptModule, + changeFileData: IChangeFile, + overwrite: boolean, + interactiveMode: boolean + ): Promise { + const output: string = JSON.stringify(changeFileData, undefined, 2); + const changeFile: ChangeFile = new ChangeFile(changeFileData, this.rushConfiguration); + const filePath: string = changeFile.generatePath(); + + const fileExists: boolean = FileSystem.exists(filePath); + const shouldWrite: boolean = + !fileExists || + overwrite || + (interactiveMode ? await this._promptForOverwriteAsync(promptModule, filePath) : false); + + if (!interactiveMode && fileExists && !overwrite) { + throw new Error(`Changefile ${filePath} already exists`); + } + + if (shouldWrite) { + this._writeFile(filePath, output, shouldWrite && fileExists); + return filePath; + } + } + + private async _promptForOverwriteAsync( + promptModule: InquirerType.PromptModule, + filePath: string + ): Promise { + const overwrite: boolean = await promptModule([ + { + name: 'overwrite', + type: 'confirm', + message: `Overwrite ${filePath}?` + } + ]); + + if (overwrite) { + return true; + } else { + // eslint-disable-next-line no-console + console.log(`Not overwriting ${filePath}`); + return false; + } + } + + /** + * Writes a file to disk, ensuring the directory structure up to that point exists + */ + 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}`); + } else { + // eslint-disable-next-line no-console + console.log(`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}`); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/CheckAction.ts b/libraries/rush-lib/src/cli/actions/CheckAction.ts new file mode 100644 index 00000000000..fcf752b0657 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/CheckAction.ts @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; +import { Colorize } from '@rushstack/terminal'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseRushAction } from './BaseRushAction'; +import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; +import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; + +export class CheckAction extends BaseRushAction { + private readonly _jsonFlag: CommandLineFlagParameter; + private readonly _verboseFlag: CommandLineFlagParameter; + private readonly _subspaceParameter: CommandLineStringParameter | undefined; + private readonly _variantParameter: CommandLineStringParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'check', + summary: + "Checks each project's package.json files and ensures that all dependencies are of the same " + + 'version throughout the repository.', + documentation: + "Checks each project's package.json files and ensures that all dependencies are of the " + + 'same version throughout the repository.', + safeForSimultaneousRushProcesses: true, + parser + }); + + this._jsonFlag = this.defineFlagParameter({ + parameterLongName: '--json', + description: 'If this flag is specified, output will be in JSON format.' + }); + this._verboseFlag = this.defineFlagParameter({ + parameterLongName: '--verbose', + description: + 'If this flag is specified, long lists of package names will not be truncated. ' + + `This has no effect if the ${this._jsonFlag.longName} flag is also specified.` + }); + this._subspaceParameter = this.defineStringParameter({ + parameterLongName: '--subspace', + argumentName: 'SUBSPACE_NAME', + description: + '(EXPERIMENTAL) Specifies an individual Rush subspace to check, requiring versions to be ' + + 'consistent only within that subspace (ignoring other subspaces). This parameter is required when ' + + 'the "subspacesEnabled" setting is set to true in subspaces.json.' + }); + this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); + } + + protected async runAsync(): Promise { + if (this.rushConfiguration.subspacesFeatureEnabled && !this._subspaceParameter) { + throw new Error( + `The --subspace parameter must be specified with "rush check" when subspaces is enabled.` + ); + } + + const currentlyInstalledVariant: string | undefined = + await this.rushConfiguration.getCurrentlyInstalledVariantAsync(); + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + true + ); + if (!variant && currentlyInstalledVariant) { + 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.` + ) + ); + } + + VersionMismatchFinder.rushCheck(this.rushConfiguration, this.terminal, { + variant, + printAsJson: this._jsonFlag.value, + truncateLongPackageNameLists: !this._verboseFlag.value, + subspace: this._subspaceParameter?.value + ? this.rushConfiguration.getSubspace(this._subspaceParameter.value) + : this.rushConfiguration.defaultSubspace + }); + } +} diff --git a/libraries/rush-lib/src/cli/actions/DeployAction.ts b/libraries/rush-lib/src/cli/actions/DeployAction.ts new file mode 100644 index 00000000000..ebbf57c7eeb --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/DeployAction.ts @@ -0,0 +1,227 @@ +// 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 { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; +import type { + PackageExtractor, + IExtractorProjectConfiguration, + IExtractorSubspace +} from '@rushstack/package-extractor'; + +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { PnpmfileConfiguration } from '../../logic/pnpm/PnpmfileConfiguration'; +import type { ILogger } from '../../pluginFramework/logging/Logger'; +import type { + DeployScenarioConfiguration, + IDeployScenarioProjectJson +} from '../../logic/deploy/DeployScenarioConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; + +export class DeployAction extends BaseRushAction { + private readonly _logger: ILogger; + private readonly _scenario: CommandLineStringParameter; + private readonly _project: CommandLineStringParameter; + private readonly _overwrite: CommandLineFlagParameter; + private readonly _targetFolder: CommandLineStringParameter; + private readonly _createArchivePath: CommandLineStringParameter; + private readonly _createArchiveOnly: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'deploy', + summary: + 'Prepares a deployment by copying a subset of Rush projects and their dependencies' + + ' to a target folder', + documentation: + 'After building the repo, "rush deploy" can be used to prepare a deployment by copying' + + ' a subset of Rush projects and their dependencies to a target folder, which can then be uploaded to' + + ' a production server. The "rush deploy" behavior is specified by a scenario config file that must' + + ' be created first, using the "rush init-deploy" command.', + parser, + + // It is okay to invoke multiple instances of "rush deploy" simultaneously, if they are writing + // to different target folders. + safeForSimultaneousRushProcesses: true + }); + + this._logger = this.rushSession.getLogger('deploy'); + + this._project = this.defineStringParameter({ + parameterLongName: '--project', + parameterShortName: '-p', + argumentName: 'PROJECT_NAME', + description: + 'Specifies the name of the main Rush project to be deployed. It must appear in the' + + ' "deploymentProjectNames" setting in the deployment config file.' + }); + + this._scenario = this.defineStringParameter({ + parameterLongName: '--scenario', + parameterShortName: '-s', + argumentName: 'SCENARIO_NAME', + description: + 'By default, the deployment configuration is specified in "common/config/rush/deploy.json".' + + ' You can use "--scenario" to specify an alternate name. The name must be lowercase and separated by dashes.' + + ' For example, if SCENARIO_NAME is "web", then the config file would be "common/config/rush/deploy-web.json".' + }); + + this._overwrite = this.defineFlagParameter({ + parameterLongName: '--overwrite', + description: + 'By default, deployment will fail if the target folder is not empty. SPECIFYING THIS FLAG' + + ' WILL RECURSIVELY DELETE EXISTING CONTENTS OF THE TARGET FOLDER.' + }); + + this._targetFolder = this.defineStringParameter({ + parameterLongName: '--target-folder', + parameterShortName: '-t', + argumentName: 'PATH', + environmentVariable: 'RUSH_DEPLOY_TARGET_FOLDER', + description: + 'By default, files are deployed to the "common/deploy" folder inside the Rush repo.' + + ' Use this parameter to specify a different location. ' + + ' WARNING: USE CAUTION WHEN COMBINING WITH "--overwrite"' + }); + + this._createArchivePath = this.defineStringParameter({ + parameterLongName: '--create-archive', + argumentName: 'ARCHIVE_PATH', + description: + 'If specified, after the deployment has been prepared, "rush deploy"' + + ' will create an archive containing the contents of the target folder.' + + ' The newly created archive file will be placed according to the designated path, relative' + + ' to the target folder. Supported file extensions: .zip' + }); + + this._createArchiveOnly = this.defineFlagParameter({ + parameterLongName: '--create-archive-only', + description: + 'If specified, "rush deploy" will only create an archive containing the contents of the target folder.' + + ' The target folder will not be modified other than to create the archive file.' + }); + } + + protected async runAsync(): Promise { + const scenarioName: string | undefined = this._scenario.value; + const { DeployScenarioConfiguration } = await import('../../logic/deploy/DeployScenarioConfiguration'); + const scenarioFilePath: string = DeployScenarioConfiguration.getConfigFilePath( + scenarioName, + this.rushConfiguration + ); + const scenarioConfiguration: DeployScenarioConfiguration = DeployScenarioConfiguration.loadFromFile( + this._logger.terminal, + scenarioFilePath, + this.rushConfiguration + ); + + let mainProjectName: string | undefined = this._project.value; + if (!mainProjectName) { + if (scenarioConfiguration.json.deploymentProjectNames.length === 1) { + // If there is only one project, then "--project" is optional + mainProjectName = scenarioConfiguration.json.deploymentProjectNames[0]; + } else { + throw new Error( + `The ${path.basename(scenarioFilePath)} configuration specifies multiple items for` + + ` "deploymentProjectNames". Use the "--project" parameter to indicate the project to be deployed.` + ); + } + } else { + if (scenarioConfiguration.json.deploymentProjectNames.indexOf(mainProjectName) < 0) { + throw new Error( + `The project "${mainProjectName}" does not appear in the list of "deploymentProjectNames"` + + ` from ${path.basename(scenarioFilePath)}.` + ); + } + } + + const targetRootFolder: string = this._targetFolder.value + ? path.resolve(this._targetFolder.value) + : path.join(this.rushConfiguration.commonFolder, 'deploy'); + + const createArchiveFilePath: string | undefined = this._createArchivePath.value + ? path.resolve(targetRootFolder, this._createArchivePath.value) + : undefined; + + const createArchiveOnly: boolean = this._createArchiveOnly.value; + + /** + * Subspaces that will be involved in deploy process. + * Each subspace may have its own configurations + */ + const subspaces: Map = new Map(); + + const rushConfigurationProject: RushConfigurationProject | undefined = + this.rushConfiguration.getProjectByName(mainProjectName); + if (!rushConfigurationProject) { + throw new Error(`The specified deployment project "${mainProjectName}" was not found in rush.json`); + } + + const projects: RushConfigurationProject[] = this.rushConfiguration.projects; + if (this.rushConfiguration.isPnpm) { + const currentlyInstalledVariant: string | undefined = + await this.rushConfiguration.getCurrentlyInstalledVariantAsync(); + for (const project of projects) { + const pnpmfileConfiguration: PnpmfileConfiguration = await PnpmfileConfiguration.initializeAsync( + this.rushConfiguration, + project.subspace, + currentlyInstalledVariant + ); + const subspace: IExtractorSubspace = { + subspaceName: project.subspace.subspaceName, + transformPackageJson: pnpmfileConfiguration.transform.bind(pnpmfileConfiguration) + }; + + if (subspaces.has(subspace.subspaceName)) { + continue; + } + + if (!scenarioConfiguration.json.omitPnpmWorkaroundLinks) { + subspace.pnpmInstallFolder = project.subspace.getSubspaceTempFolderPath(); + } + subspaces.set(subspace.subspaceName, subspace); + } + } + + // Construct the project list for the deployer + const projectConfigurations: IExtractorProjectConfiguration[] = []; + for (const project of projects) { + const scenarioProjectJson: IDeployScenarioProjectJson | undefined = + scenarioConfiguration.projectJsonsByName.get(project.packageName); + projectConfigurations.push({ + projectName: project.packageName, + projectFolder: project.projectFolder, + additionalProjectsToInclude: scenarioProjectJson?.additionalProjectsToInclude, + additionalDependenciesToInclude: scenarioProjectJson?.additionalDependenciesToInclude, + dependenciesToExclude: scenarioProjectJson?.dependenciesToExclude, + patternsToInclude: scenarioProjectJson?.patternsToInclude, + patternsToExclude: scenarioProjectJson?.patternsToExclude + }); + } + + // Call the deploy manager + const { PackageExtractor } = await import( + /* webpackChunkName: 'PackageExtractor' */ + '@rushstack/package-extractor' + ); + const deployManager: PackageExtractor = new PackageExtractor(); + await deployManager.extractAsync({ + terminal: this._logger.terminal, + overwriteExisting: !!this._overwrite.value, + includeDevDependencies: scenarioConfiguration.json.includeDevDependencies, + includeNpmIgnoreFiles: scenarioConfiguration.json.includeNpmIgnoreFiles, + folderToCopy: scenarioConfiguration.json.folderToCopy, + linkCreation: scenarioConfiguration.json.linkCreation, + sourceRootFolder: this.rushConfiguration.rushJsonFolder, + targetRootFolder, + mainProjectName, + projectConfigurations, + dependencyConfigurations: scenarioConfiguration.json.dependencySettings, + createArchiveFilePath, + createArchiveOnly, + subspaces: Array.from(subspaces.values()) + }); + } +} diff --git a/libraries/rush-lib/src/cli/actions/InitAction.ts b/libraries/rush-lib/src/cli/actions/InitAction.ts new file mode 100644 index 00000000000..7eeb7480312 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InitAction.ts @@ -0,0 +1,171 @@ +// 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, + InternalError, + AlreadyReportedError, + type FileSystemStats +} from '@rushstack/node-core-library'; +import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { Colorize } from '@rushstack/terminal'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseConfiglessRushAction } from './BaseRushAction'; +import { assetsFolderPath } from '../../utilities/PathConstants'; +import { copyTemplateFileAsync } from '../../utilities/templateUtilities'; + +export class InitAction extends BaseConfiglessRushAction { + private readonly _overwriteParameter: CommandLineFlagParameter; + private readonly _rushExampleParameter: CommandLineFlagParameter; + private readonly _experimentsParameter: CommandLineFlagParameter; + + // template section name --> whether it should be commented out + private _commentedBySectionName: Map = new Map(); + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'init', + summary: 'Initializes a new repository to be managed by Rush', + documentation: + 'When invoked in an empty folder, this command provisions a standard' + + ' set of config file templates to start managing projects using Rush.', + parser + }); + + this._overwriteParameter = this.defineFlagParameter({ + parameterLongName: '--overwrite-existing', + description: + 'By default "rush init" will not overwrite existing config files.' + + ' Specify this switch to override that. This can be useful when upgrading' + + ' your repo to a newer release of Rush. WARNING: USE WITH CARE!' + }); + this._rushExampleParameter = this.defineFlagParameter({ + parameterLongName: '--rush-example-repo', + description: + 'When copying the template config files, this uncomments fragments that are used' + + ' by the "rush-example" GitHub repo, which is a sample monorepo that illustrates many Rush' + + ' features. This option is primarily intended for maintaining that example.' + }); + this._experimentsParameter = this.defineFlagParameter({ + parameterLongName: '--include-experiments', + description: + 'Include features that may not be complete features, useful for demoing specific future features' + + ' or current work in progress features.' + }); + } + + protected async runAsync(): Promise { + const initFolder: string = process.cwd(); + + if (!this._overwriteParameter.value) { + if (!this._validateFolderIsEmpty(initFolder)) { + throw new AlreadyReportedError(); + } + } + + await this._copyTemplateFilesAsync(initFolder); + } + + // Check whether it's safe to run "rush init" in the current working directory. + private _validateFolderIsEmpty(initFolder: string): boolean { + if (this.rushConfiguration !== undefined) { + // eslint-disable-next-line no-console + console.error( + Colorize.red('ERROR: Found an existing configuration in: ' + this.rushConfiguration.rushJsonFile) + ); + // eslint-disable-next-line no-console + console.log( + '\nThe "rush init" command must be run in a new folder without an existing Rush configuration.' + ); + return false; + } + + for (const itemName of FileSystem.readFolderItemNames(initFolder)) { + if (itemName.substr(0, 1) === '.') { + // Ignore any items that start with ".", for example ".git" + continue; + } + + const itemPath: string = path.join(initFolder, itemName); + + const stats: FileSystemStats = FileSystem.getStatistics(itemPath); + // Ignore any loose files in the current folder, e.g. "README.md" + // or "CONTRIBUTING.md" + if (stats.isDirectory()) { + // eslint-disable-next-line no-console + console.error(Colorize.red(`ERROR: Found a subdirectory: "${itemName}"`)); + // eslint-disable-next-line no-console + console.log('\nThe "rush init" command must be run in a new folder with no projects added yet.'); + return false; + } else { + if (itemName.toLowerCase() === 'package.json') { + // eslint-disable-next-line no-console + console.error(Colorize.red(`ERROR: Found a package.json file in this folder`)); + // eslint-disable-next-line no-console + console.log('\nThe "rush init" command must be run in a new folder with no projects added yet.'); + return false; + } + } + } + return true; + } + + private async _copyTemplateFilesAsync(initFolder: string): Promise { + // The "[dot]" base name is used for hidden files to prevent various tools from interpreting them. + // For example, "npm publish" will always exclude the filename ".gitignore" + const templateFilePaths: string[] = [ + '[dot]github/workflows/ci.yml', + + 'common/config/rush/.pnpmfile.cjs', + 'common/config/rush/[dot]npmrc', + 'common/config/rush/[dot]npmrc-publish', + 'common/config/rush/artifactory.json', + 'common/config/rush/build-cache.json', + 'common/config/rush/cobuild.json', + 'common/config/rush/command-line.json', + 'common/config/rush/common-versions.json', + 'common/config/rush/custom-tips.json', + 'common/config/rush/experiments.json', + 'common/config/rush/pnpm-config.json', + 'common/config/rush/rush-plugins.json', + 'common/config/rush/subspaces.json', + 'common/config/rush/version-policies.json', + + 'common/git-hooks/commit-msg.sample', + + '[dot]gitattributes', + '[dot]gitignore', + 'rush.json' + ]; + + const experimentalTemplateFilePaths: string[] = ['common/config/rush/rush-alerts.json']; + + if (this._experimentsParameter.value) { + templateFilePaths.push(...experimentalTemplateFilePaths); + } + + const assetsSubfolder: string = `${assetsFolderPath}/rush-init`; + + for (const templateFilePath of templateFilePaths) { + const sourcePath: string = path.join(assetsSubfolder, templateFilePath); + + if (!FileSystem.exists(sourcePath)) { + // If this happens, please report a Rush bug + throw new InternalError('Unable to find template input file: ' + sourcePath); + } + + const destinationPath: string = path.join(initFolder, templateFilePath).replace('[dot]', '.'); + + // The "DEMO" sections are uncommented only when "--rush-example-repo" is specified. + await copyTemplateFileAsync( + sourcePath, + destinationPath, + this._overwriteParameter.value, + !this._rushExampleParameter.value + ); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.ts new file mode 100644 index 00000000000..aebc4408103 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InitAutoinstallerAction.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 type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; +import { FileSystem, NewlineKind, type IPackageJson, JsonFile } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { Autoinstaller } from '../../logic/Autoinstaller'; + +export class InitAutoinstallerAction extends BaseRushAction { + private readonly _name: IRequiredCommandLineStringParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'init-autoinstaller', + summary: 'Initializes a new autoinstaller', + documentation: + 'Use this command to initialize a new autoinstaller folder. Autoinstallers provide a way to' + + ' manage a set of related dependencies that are used for scripting scenarios outside of the usual' + + ' "rush install" context. See the command-line.json documentation for an example.', + parser + }); + + this._name = this.defineStringParameter({ + parameterLongName: '--name', + argumentName: 'AUTOINSTALLER_NAME', + required: true, + description: + 'Specifies the name of the autoinstaller folder, which must conform to the naming rules for NPM packages.' + }); + } + + protected async runAsync(): Promise { + const autoinstallerName: string = this._name.value; + + const autoinstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName, + rushConfiguration: this.rushConfiguration, + rushGlobalFolder: this.rushGlobalFolder + }); + + if (FileSystem.exists(autoinstaller.folderFullPath)) { + // It's okay if the folder is empty + if (FileSystem.readFolderItemNames(autoinstaller.folderFullPath).length > 0) { + throw new Error('The target folder already exists: ' + autoinstaller.folderFullPath); + } + } + + const packageJson: IPackageJson = { + name: autoinstallerName, + version: '1.0.0', + private: true, + dependencies: {} + }; + + // eslint-disable-next-line no-console + console.log(Colorize.green('Creating package: ') + autoinstaller.packageJsonPath); + + JsonFile.save(packageJson, autoinstaller.packageJsonPath, { + ensureFolderExists: true, + newlineConversion: NewlineKind.OsDefault + }); + + // eslint-disable-next-line no-console + console.log('\nFile successfully written. Add your dependencies before committing.'); + } +} diff --git a/libraries/rush-lib/src/cli/actions/InitDeployAction.ts b/libraries/rush-lib/src/cli/actions/InitDeployAction.ts new file mode 100644 index 00000000000..6f7d996d7e7 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InitDeployAction.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. + +import { FileSystem, NewlineKind } from '@rushstack/node-core-library'; +import type { + CommandLineStringParameter, + IRequiredCommandLineStringParameter +} from '@rushstack/ts-command-line'; +import { Colorize } from '@rushstack/terminal'; + +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { DeployScenarioConfiguration } from '../../logic/deploy/DeployScenarioConfiguration'; +import { assetsFolderPath } from '../../utilities/PathConstants'; +import { RushConstants } from '../../logic/RushConstants'; + +const CONFIG_TEMPLATE_PATH: string = `${assetsFolderPath}/rush-init-deploy/scenario-template.json`; + +export class InitDeployAction extends BaseRushAction { + private readonly _project: IRequiredCommandLineStringParameter; + private readonly _scenario: CommandLineStringParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'init-deploy', + summary: 'Creates a deployment scenario config file for use with "rush deploy".', + documentation: + 'Use this command to initialize a new scenario config file for use with "rush deploy".' + + ' The default filename is common/config/rush/deploy.json. However, if you need to manage multiple' + + ' deployments with different settings, you can use use "--scenario" to create additional config files.', + parser + }); + + this._project = this.defineStringParameter({ + parameterLongName: '--project', + parameterShortName: '-p', + argumentName: 'PROJECT_NAME', + required: true, + description: + 'Specifies the name of the main Rush project to be deployed in this scenario.' + + ' It will be added to the "deploymentProjectNames" setting.' + }); + + this._scenario = this.defineStringParameter({ + parameterLongName: '--scenario', + parameterShortName: '-s', + argumentName: 'SCENARIO', + description: + 'By default, the deployment configuration will be written to "common/config/rush/deploy.json".' + + ' You can use "--scenario" to specify an alternate name. The name must be lowercase and separated by dashes.' + + ' For example, if the name is "web", then the config file would be "common/config/rush/deploy-web.json".' + }); + } + + protected async runAsync(): Promise { + const scenarioFilePath: string = DeployScenarioConfiguration.getConfigFilePath( + this._scenario.value, + this.rushConfiguration + ); + + if (FileSystem.exists(scenarioFilePath)) { + throw new Error( + 'The target file already exists:\n' + + scenarioFilePath + + '\nIf you intend to replace it, please delete the old file first.' + ); + } + + // eslint-disable-next-line no-console + console.log(Colorize.green('Creating scenario file: ') + scenarioFilePath); + + const shortProjectName: string = this._project.value; + const rushProject: RushConfigurationProject | undefined = + this.rushConfiguration.findProjectByShorthandName(shortProjectName); + if (!rushProject) { + throw new Error( + `The specified project was not found in ${RushConstants.rushJsonFilename}: "${shortProjectName}"` + ); + } + + const templateContent: string = FileSystem.readFile(CONFIG_TEMPLATE_PATH); + const expandedContent: string = templateContent.replace( + '[%PROJECT_NAME_TO_DEPLOY%]', + rushProject.packageName + ); + + FileSystem.writeFile(scenarioFilePath, expandedContent, { + ensureFolderExists: true, + convertLineEndings: NewlineKind.OsDefault + }); + + // eslint-disable-next-line no-console + console.log('\nFile successfully written. Please review the file contents before committing.'); + } +} diff --git a/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts new file mode 100644 index 00000000000..6659ae9ac81 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.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 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 { copyTemplateFileAsync } from '../../utilities/templateUtilities'; + +export class InitSubspaceAction extends BaseRushAction { + private readonly _subspaceNameParameter: IRequiredCommandLineStringParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'init-subspace', + summary: 'Create a new subspace.', + documentation: + 'Use this command to create a new subspace with the default subspace configuration files.', + parser + }); + + this._subspaceNameParameter = this.defineStringParameter({ + parameterLongName: '--name', + parameterShortName: '-n', + argumentName: 'SUBSPACE_NAME', + description: 'The name of the subspace that is being initialized.', + required: true + }); + } + + protected async runAsync(): Promise { + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + + if (!this.rushConfiguration.subspacesFeatureEnabled) { + throw new Error('Unable to create a subspace because the subspaces feature is not enabled.'); + } + + const subspacesConfiguration: SubspacesConfiguration = this.rushConfiguration + .subspacesConfiguration as SubspacesConfiguration; + // Verify this subspace name does not already exist + const existingSubspaceNames: ReadonlySet = subspacesConfiguration.subspaceNames; + const newSubspaceName: string = this._subspaceNameParameter.value; + if (existingSubspaceNames.has(newSubspaceName)) { + throw new Error( + `The subspace name: ${this._subspaceNameParameter.value} already exists in the subspace.json file.` + ); + } + if ( + SubspacesConfiguration.explainIfInvalidSubspaceName( + newSubspaceName, + this.rushConfiguration.subspacesConfiguration?.splitWorkspaceCompatibility + ) + ) { + return; + } + + const subspaceConfigPath: string = `${this.rushConfiguration.commonFolder}/config/subspaces/${newSubspaceName}`; + const assetsSubfolder: string = `${assetsFolderPath}/rush-init`; + const templateFilePaths: string[] = [ + '[dot]npmrc', + '.pnpmfile.cjs', + 'common-versions.json', + 'pnpm-config.json' + ]; + + await FileSystem.ensureEmptyFolderAsync(subspaceConfigPath); + await Async.forEachAsync( + templateFilePaths, + async (templateFilePath) => { + const sourcePath: string = `${assetsSubfolder}/common/config/rush/${templateFilePath}`; + const destinationPath: string = `${subspaceConfigPath}/${templateFilePath.replace('[dot]', '.')}`; + await copyTemplateFileAsync(sourcePath, destinationPath, true); + }, + { concurrency: 10 } + ); + + // Add the subspace name to subspaces.json + const subspaceJson: ISubspacesConfigurationJson = await JsonFile.loadAsync( + subspacesConfiguration.subspaceJsonFilePath + ); + subspaceJson.subspaceNames.push(newSubspaceName); + await JsonFile.saveAsync(subspaceJson, subspacesConfiguration.subspaceJsonFilePath, { + updateExistingFile: true + }); + + 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 new file mode 100644 index 00000000000..ebc828c33b1 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InstallAction.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 { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseInstallAction } from './BaseInstallAction'; +import type { IInstallManagerOptions } from '../../logic/base/BaseInstallManagerTypes'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { SelectionParameterSet } from '../parsing/SelectionParameterSet'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { Subspace } from '../../api/Subspace'; +import { getVariantAsync } from '../../api/Variants'; + +export class InstallAction extends BaseInstallAction { + private readonly _checkOnlyParameter: CommandLineFlagParameter; + private readonly _resolutionOnlyParameter: CommandLineFlagParameter | undefined; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'install', + summary: 'Install package dependencies for all projects in the repo according to the shrinkwrap file', + documentation: + 'The "rush install" command installs package dependencies for all your projects,' + + ' based on the shrinkwrap file that is created/updated using "rush update".' + + ' (This "shrinkwrap" file stores a central inventory of all dependencies and versions' + + ' for projects in your repo. It is found in the "common/config/rush" folder.)' + + ' If the shrinkwrap file is missing or outdated (e.g. because project package.json files have' + + ' changed), "rush install" will fail and tell you to run "rush update" instead.' + + ' This read-only nature is the main feature: Continuous integration builds should use' + + ' "rush install" instead of "rush update" to catch developers who forgot to commit their' + + ' shrinkwrap changes. Cautious people can also use "rush install" if they want to avoid' + + ' accidentally updating their shrinkwrap file.', + parser + }); + + this._selectionParameters = new SelectionParameterSet(this.rushConfiguration, this, { + gitOptions: { + // Include lockfile processing since this expands the selection, and we need to select + // at least the same projects selected with the same query to "rush build" + includeExternalDependencies: true, + // Disable filtering because rush-project.json is riggable and therefore may not be available + enableFiltering: false + }, + includeSubspaceSelector: true, + cwd: this.parser.cwd + }); + + this._checkOnlyParameter = this.defineFlagParameter({ + parameterLongName: '--check-only', + description: `Only check the validity of the shrinkwrap file without performing an install.` + }); + + if (this.rushConfiguration?.isPnpm) { + this._resolutionOnlyParameter = this.defineFlagParameter({ + parameterLongName: '--resolution-only', + description: `Only perform dependency resolution, useful for ensuring peer dependendencies are up to date. Note that this flag is only supported when using the pnpm package manager.` + }); + } + } + + protected async buildInstallOptionsAsync(): Promise> { + const selectedProjects: Set = + (await this._selectionParameters?.getSelectedProjectsAsync(this.terminal)) ?? + new Set(this.rushConfiguration.projects); + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + false + ); + + return { + debug: this.parser.isDebug, + allowShrinkwrapUpdates: false, + bypassPolicyAllowed: true, + bypassPolicy: this._bypassPolicyParameter.value!, + noLink: this._noLinkParameter.value!, + fullUpgrade: false, + recheckShrinkwrap: false, + offline: this._offlineParameter.value!, + networkConcurrency: this._networkConcurrencyParameter.value, + collectLogFile: this._debugPackageManagerParameter.value!, + variant, + // Because the 'defaultValue' option on the _maxInstallAttempts parameter is set, + // it is safe to assume that the value is not null + maxInstallAttempts: this._maxInstallAttempts.value!, + // These are derived independently of the selection for command line brevity + selectedProjects, + pnpmFilterArgumentValues: + (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 + }; + } +} diff --git a/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts new file mode 100644 index 00000000000..b8445383d75 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/InstallAutoinstallerAction.ts @@ -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. + +import type { Autoinstaller } from '../../logic/Autoinstaller'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseAutoinstallerAction } from './BaseAutoinstallerAction'; + +export class InstallAutoinstallerAction extends BaseAutoinstallerAction { + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'install-autoinstaller', + summary: 'Install autoinstaller package dependencies', + documentation: 'Use this command to install dependencies for an autoinstaller folder.', + parser + }); + } + + protected async prepareAsync(autoinstaller: Autoinstaller): Promise { + await autoinstaller.prepareAsync(); + } +} diff --git a/libraries/rush-lib/src/cli/actions/LinkAction.ts b/libraries/rush-lib/src/cli/actions/LinkAction.ts new file mode 100644 index 00000000000..eabf19c414c --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/LinkAction.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 { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import type { BaseLinkManager } from '../../logic/base/BaseLinkManager'; +import { BaseRushAction } from './BaseRushAction'; + +export class LinkAction extends BaseRushAction { + private readonly _force: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'link', + summary: 'Create node_modules symlinks for all projects', + documentation: + 'Create node_modules symlinks for all projects. This operation is normally performed' + + ' automatically as part of "rush install" or "rush update". You should only need to use "rush link"' + + ' if you performed "rush unlink" for some reason, or if you specified the "--no-link" option' + + ' for "rush install" or "rush update".', + parser + }); + + this._force = this.defineFlagParameter({ + parameterLongName: '--force', + parameterShortName: '-f', + description: + 'Deletes and recreates all links, even if the filesystem state seems to indicate that this is ' + + 'unnecessary.' + }); + } + + protected async runAsync(): Promise { + const linkManagerFactoryModule: typeof import('../../logic/LinkManagerFactory') = await import( + /* webpackChunkName: 'LinkManagerFactory' */ + '../../logic/LinkManagerFactory' + ); + const linkManager: BaseLinkManager = linkManagerFactoryModule.LinkManagerFactory.getLinkManager( + this.rushConfiguration + ); + await linkManager.createSymlinksForProjectsAsync(this._force.value); + } +} 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 new file mode 100644 index 00000000000..ec47625028f --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/ListAction.ts @@ -0,0 +1,284 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Sort } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; +import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseRushAction } from './BaseRushAction'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { VersionPolicyDefinitionName } from '../../api/VersionPolicy'; +import { SelectionParameterSet } from '../parsing/SelectionParameterSet'; + +/** + * Shape of "rush list --json" output. + * + * It contains parts (with different names) coming from + * {@link ../../api/RushConfigurationProject#RushConfigurationProject | RushConfigurationProject}. + */ +export interface IJsonEntry { + name: string; + version: string; + /** + * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.publishFolder | RushConfigurationProject.publishFolder} + */ + path: string; + fullPath: string; + /** + * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.versionPolicyName | RushConfigurationProject.versionPolicyName} + */ + versionPolicyName: string | undefined; + /** + * @see {@link ../../api/VersionPolicy#VersionPolicyDefinitionName | VersionPolicyDefinitionName} + */ + versionPolicy: string | undefined; + /** + * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.shouldPublish | RushConfigurationProject.shouldPublish} + */ + shouldPublish: boolean | undefined; + /** + * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.reviewCategory | RushConfigurationProject.reviewCategory} + */ + reviewCategory: string | undefined; + /** + * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.tags | RushConfigurationProject.tags} + */ + tags: string[]; + /** + * @see {@link ../../api/Subspace#Subspace.subspaceName | Subspace.subspaceName} + */ + subspaceName: string | undefined; +} + +export interface IJsonOutput { + projects: IJsonEntry[]; +} + +export class ListAction extends BaseRushAction { + private readonly _version: CommandLineFlagParameter; + private readonly _path: CommandLineFlagParameter; + private readonly _fullPath: CommandLineFlagParameter; + private readonly _jsonFlag: CommandLineFlagParameter; + private readonly _detailedFlag: CommandLineFlagParameter; + private readonly _selectionParameters: SelectionParameterSet; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'list', + summary: 'List package information for all projects in the repo', + documentation: + 'List package names, and optionally version (--version) and ' + + 'path (--path) or full path (--full-path), for projects in the ' + + 'current rush config.', + parser, + safeForSimultaneousRushProcesses: true + }); + + this._version = this.defineFlagParameter({ + parameterLongName: '--version', + parameterShortName: '-v', + description: + 'If this flag is specified, the project version will be ' + + 'displayed in a column along with the package name.' + }); + + this._path = this.defineFlagParameter({ + parameterLongName: '--path', + parameterShortName: '-p', + description: + 'If this flag is specified, the project path will be ' + + 'displayed in a column along with the package name.' + }); + + this._fullPath = this.defineFlagParameter({ + parameterLongName: '--full-path', + description: + 'If this flag is specified, the project full path will ' + + 'be displayed in a column along with the package name.' + }); + + this._detailedFlag = this.defineFlagParameter({ + parameterLongName: '--detailed', + description: + 'For the non --json view, if this flag is specified, ' + + 'include path (-p), version (-v) columns along with ' + + "the project's applicable: versionPolicy, versionPolicyName, " + + 'shouldPublish, reviewPolicy, and tags fields.' + }); + + this._jsonFlag = this.defineFlagParameter({ + parameterLongName: '--json', + description: 'If this flag is specified, output will be in JSON format.' + }); + + this._selectionParameters = new SelectionParameterSet(this.rushConfiguration, this, { + gitOptions: { + // Include lockfile processing since this expands the selection, and we need to select + // at least the same projects selected with the same query to "rush build" + includeExternalDependencies: true, + // Disable filtering because rush-project.json is riggable and therefore may not be available + enableFiltering: false + }, + includeSubspaceSelector: false, + cwd: this.parser.cwd + }); + } + + protected async runAsync(): Promise { + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + const selection: Set = + await this._selectionParameters.getSelectedProjectsAsync(terminal); + Sort.sortSetBy(selection, (x: RushConfigurationProject) => x.packageName); + if (this._jsonFlag.value && this._detailedFlag.value) { + throw new Error(`The parameters "--json" and "--detailed" cannot be used together.`); + } + + if (this._jsonFlag.value) { + this._printJson(selection); + } else if (this._version.value || this._path.value || this._fullPath.value || this._detailedFlag.value) { + await this._printListTableAsync(selection); + } else { + this._printList(selection); + } + } + + private _printJson(selection: Set): void { + const projects: IJsonEntry[] = Array.from(selection, (config: RushConfigurationProject): IJsonEntry => { + let reviewCategory: undefined | string; + 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}`; + versionPolicyName = config.versionPolicy.policyName; + } else { + shouldPublish = config.shouldPublish; + } + + if (config.reviewCategory) { + reviewCategory = config.reviewCategory; + } + + if (this.rushConfiguration.subspacesFeatureEnabled) { + subspaceName = config.subspace.subspaceName; + } + + return { + name: config.packageName, + version: config.packageJson.version, + path: config.projectRelativeFolder, + fullPath: config.projectFolder, + versionPolicy, + versionPolicyName, + shouldPublish, + reviewCategory, + tags: Array.from(config.tags), + subspaceName + }; + }); + + const output: IJsonOutput = { + projects + }; + // eslint-disable-next-line no-console + console.log(JSON.stringify(output, undefined, 2)); + } + + private _printList(selection: Set): void { + for (const project of selection) { + // eslint-disable-next-line no-console + console.log(project.packageName); + } + } + + 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'); + } + + if (this._path.value || this._detailedFlag.value) { + tableHeader.push('Path'); + } + + if (this._fullPath.value) { + tableHeader.push('Full Path'); + } + + if (this._detailedFlag.value) { + tableHeader.push('Version policy'); + tableHeader.push('Version policy name'); + tableHeader.push('Should publish'); + tableHeader.push('Review category'); + tableHeader.push('Tags'); + } + + const { default: CliTable } = await import('cli-table'); + const table: import('cli-table') = new CliTable({ + head: tableHeader + }); + + for (const project of selection) { + const packageRow: string[] = []; + function appendToPackageRow(value: string): void { + packageRow.push(value === undefined ? 'UNDEFINED' : value); + } + + appendToPackageRow(project.packageName); + + if (this.rushConfiguration.subspacesFeatureEnabled) { + appendToPackageRow(project.subspace.subspaceName); + } + + if (this._version.value || this._detailedFlag.value) { + appendToPackageRow(project.packageJson.version); + } + + if (this._path.value || this._detailedFlag.value) { + appendToPackageRow(project.projectRelativeFolder); + } + + if (this._fullPath.value) { + appendToPackageRow(project.projectFolder); + } + + if (this._detailedFlag.value) { + // When we HAVE a version policy + let versionPolicyDefinitionName: string = ''; + let versionPolicyName: string = ''; + // When we DO NOT have version policy, fallback to shouldPublish boolean + let shouldPublish: string = ''; + let reviewCategory: string = ''; + if (project.versionPolicy !== undefined) { + const definitionName: string = VersionPolicyDefinitionName[project.versionPolicy.definitionName]; + versionPolicyDefinitionName = definitionName; + versionPolicyName = project.versionPolicy.policyName; + } else { + shouldPublish = `${project.shouldPublish}`; + } + + if (project.reviewCategory) { + reviewCategory = project.reviewCategory; + } + + appendToPackageRow(versionPolicyDefinitionName); + appendToPackageRow(versionPolicyName); + appendToPackageRow(shouldPublish); + appendToPackageRow(reviewCategory); + appendToPackageRow(Array.from(project.tags).join(', ')); + } + + table.push(packageRow); + } + + // eslint-disable-next-line no-console + console.log(table.toString()); + } +} diff --git a/libraries/rush-lib/src/cli/actions/PublishAction.ts b/libraries/rush-lib/src/cli/actions/PublishAction.ts new file mode 100644 index 00000000000..af90f85d813 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/PublishAction.ts @@ -0,0 +1,620 @@ +// 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 type { + CommandLineFlagParameter, + CommandLineStringParameter, + CommandLineChoiceParameter +} from '@rushstack/ts-command-line'; +import { FileSystem } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { type IChangeInfo, ChangeType } from '../../api/ChangeManagement'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { Npm } from '../../utilities/Npm'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { PublishUtilities } from '../../logic/PublishUtilities'; +import { ChangelogGenerator } from '../../logic/ChangelogGenerator'; +import { PrereleaseToken } from '../../logic/PrereleaseToken'; +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'; + +export class PublishAction extends BaseRushAction { + private readonly _addCommitDetails: CommandLineFlagParameter; + private readonly _apply: CommandLineFlagParameter; + private readonly _includeAll: CommandLineFlagParameter; + private readonly _npmAuthToken: CommandLineStringParameter; + private readonly _npmTag: CommandLineStringParameter; + private readonly _npmAccessLevel: CommandLineChoiceParameter; + private readonly _publish: CommandLineFlagParameter; + private readonly _regenerateChangelogs: CommandLineFlagParameter; + private readonly _registryUrl: CommandLineStringParameter; + private readonly _targetBranch: CommandLineStringParameter; + private readonly _prereleaseName: CommandLineStringParameter; + private readonly _partialPrerelease: CommandLineFlagParameter; + private readonly _suffix: CommandLineStringParameter; + private readonly _force: CommandLineFlagParameter; + private readonly _versionPolicy: CommandLineStringParameter; + private readonly _applyGitTagsOnPack: CommandLineFlagParameter; + private readonly _commitId: CommandLineStringParameter; + private readonly _releaseFolder: CommandLineStringParameter; + private readonly _pack: CommandLineFlagParameter; + private readonly _ignoreGitHooksParameter: CommandLineFlagParameter; + + private _prereleaseToken!: PrereleaseToken; + private _hotfixTagOverride!: string; + private _targetNpmrcPublishFolder!: string; + private _targetNpmrcPublishPath!: string; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'publish', + 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 ' + + '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 + }); + + this._apply = this.defineFlagParameter({ + parameterLongName: '--apply', + parameterShortName: '-a', + description: 'If this flag is specified, the change requests will be applied to package.json files.' + }); + this._targetBranch = this.defineStringParameter({ + parameterLongName: '--target-branch', + parameterShortName: '-b', + argumentName: 'BRANCH', + description: + 'If this flag is specified, applied changes and deleted change requests will be ' + + 'committed and merged into the target branch.' + }); + this._publish = this.defineFlagParameter({ + parameterLongName: '--publish', + parameterShortName: '-p', + description: 'If this flag is specified, applied changes will be published to the NPM registry.' + }); + this._addCommitDetails = this.defineFlagParameter({ + parameterLongName: '--add-commit-details', + parameterShortName: undefined, + description: 'Adds commit author and hash to the changelog.json files for each change.' + }); + this._regenerateChangelogs = this.defineFlagParameter({ + parameterLongName: '--regenerate-changelogs', + parameterShortName: undefined, + description: 'Regenerates all changelog files based on the current JSON content.' + }); + + // NPM registry related parameters + this._registryUrl = this.defineStringParameter({ + parameterLongName: '--registry', + parameterShortName: '-r', + argumentName: 'REGISTRY', + description: + `Publishes to a specified NPM registry. If this is specified, it will prevent the current commit will not be ` + + 'tagged.' + }); + this._npmAuthToken = this.defineStringParameter({ + parameterLongName: '--npm-auth-token', + parameterShortName: '-n', + argumentName: 'TOKEN', + description: + '(DEPRECATED) Specifies the authentication token to use during publishing. This parameter is deprecated' + + ' because command line parameters may be readable by unrelated processes on a lab machine. Instead, a' + + ' safer practice is to pass the token via an environment variable and reference it from your ' + + ' common/config/rush/.npmrc-publish file.' + }); + this._npmTag = this.defineStringParameter({ + parameterLongName: '--tag', + parameterShortName: '-t', + argumentName: 'TAG', + description: + `The tag option to pass to npm publish. By default NPM will publish using the 'latest' tag, even if ` + + `the package is older than the current latest, so in publishing workflows for older releases, providing ` + + `a tag is important. When hotfix changes are made, this parameter defaults to 'hotfix'.` + }); + this._npmAccessLevel = this.defineChoiceParameter({ + alternatives: ['public', 'restricted'], + parameterLongName: '--set-access-level', + parameterShortName: undefined, + description: + `By default, when Rush invokes "npm publish" it will publish scoped packages with an access level ` + + `of "restricted". Scoped packages can be published with an access level of "public" by specifying ` + + `that value for this flag with the initial publication. NPM always publishes unscoped packages with ` + + `an access level of "public". For more information, see the NPM documentation for the "--access" ` + + `option of "npm publish".` + }); + + // NPM pack tarball related parameters + this._pack = this.defineFlagParameter({ + parameterLongName: '--pack', + description: + `Packs projects into tarballs instead of publishing to npm repository. It can only be used when ` + + `--include-all is specified. If this flag is specified, NPM registry related parameters will be ignored.` + }); + this._releaseFolder = this.defineStringParameter({ + parameterLongName: '--release-folder', + argumentName: 'FOLDER', + description: + `This parameter is used with --pack parameter to provide customized location for the tarballs instead of ` + + `the default value. ` + }); + // End of NPM pack tarball related parameters + + this._includeAll = this.defineFlagParameter({ + parameterLongName: '--include-all', + parameterShortName: undefined, + description: + `If this flag is specified, all packages with shouldPublish=true in ${RushConstants.rushJsonFilename} ` + + 'or with a specified version policy ' + + 'will be published if their version is newer than published version.' + }); + this._versionPolicy = this.defineStringParameter({ + parameterLongName: '--version-policy', + argumentName: 'POLICY', + description: + 'Version policy name. Only projects with this version policy will be published if used ' + + 'with --include-all.' + }); + this._prereleaseName = this.defineStringParameter({ + parameterLongName: '--prerelease-name', + argumentName: 'NAME', + description: + 'Bump up to a prerelease version with the provided prerelease name. Cannot be used with --suffix' + }); + this._partialPrerelease = this.defineFlagParameter({ + parameterLongName: '--partial-prerelease', + parameterShortName: undefined, + description: + 'Used with --prerelease-name. Only bump packages to a prerelease version if they have changes.' + }); + this._suffix = this.defineStringParameter({ + parameterLongName: '--suffix', + argumentName: 'SUFFIX', + description: 'Append a suffix to all changed versions. Cannot be used with --prerelease-name.' + }); + this._force = this.defineFlagParameter({ + parameterLongName: '--force', + parameterShortName: undefined, + description: 'If this flag is specified with --publish, packages will be published with --force on npm' + }); + this._applyGitTagsOnPack = this.defineFlagParameter({ + parameterLongName: '--apply-git-tags-on-pack', + description: + `If specified with --publish and --pack, git tags will be applied for packages` + + ` as if a publish was being run without --pack.` + }); + this._commitId = this.defineStringParameter({ + parameterLongName: '--commit', + parameterShortName: '-c', + argumentName: 'COMMIT_ID', + description: + `Used in conjunction with git tagging -- apply git tags at the commit hash` + + ` specified. If not provided, the current HEAD will be tagged.` + }); + this._ignoreGitHooksParameter = this.defineFlagParameter({ + parameterLongName: '--ignore-git-hooks', + description: `Skips execution of all git hooks. Make sure you know what you are skipping.` + }); + } + + /** + * Executes the publish action, which will read change request files, apply changes to package.jsons, + */ + protected async runAsync(): Promise { + const currentlyInstalledVariant: string | undefined = + await this.rushConfiguration.getCurrentlyInstalledVariantAsync(); + await PolicyValidator.validatePolicyAsync( + this.rushConfiguration, + this.rushConfiguration.defaultSubspace, + currentlyInstalledVariant, + { bypassPolicy: false } + ); + + // Example: "common\temp\publish-home" + this._targetNpmrcPublishFolder = path.join(this.rushConfiguration.commonTempFolder, 'publish-home'); + + // Example: "common\temp\publish-home\.npmrc" + this._targetNpmrcPublishPath = path.join(this._targetNpmrcPublishFolder, '.npmrc'); + + const allPackages: ReadonlyMap = this.rushConfiguration.projectsByName; + + if (this._regenerateChangelogs.value) { + // eslint-disable-next-line no-console + console.log('Regenerating changelogs'); + ChangelogGenerator.regenerateChangelogs(allPackages, this.rushConfiguration); + return; + } + + this._validate(); + + this._addNpmPublishHome(this.rushConfiguration.isPnpm); + + const git: Git = new Git(this.rushConfiguration); + const publishGit: PublishGit = new PublishGit(git, this._targetBranch.value); + if (this._includeAll.value) { + await this._publishAllAsync(publishGit, allPackages); + } else { + this._prereleaseToken = new PrereleaseToken( + this._prereleaseName.value, + this._suffix.value, + this._partialPrerelease.value + ); + await this._publishChangesAsync(git, publishGit, allPackages); + } + + // eslint-disable-next-line no-console + console.log('\n' + Colorize.green('Rush publish finished successfully.')); + } + + /** + * Validate some input parameters + */ + private _validate(): void { + if (this._pack.value && !this._includeAll.value) { + throw new Error('--pack can only be used with --include-all'); + } + if (this._releaseFolder.value && !this._pack.value) { + throw new Error(`--release-folder can only be used with --pack`); + } + if (this._applyGitTagsOnPack.value && !this._pack.value) { + throw new Error(`${this._applyGitTagsOnPack.longName} must be used with ${this._pack.longName}`); + } + } + + private async _publishChangesAsync( + git: Git, + publishGit: PublishGit, + allPackages: ReadonlyMap + ): Promise { + const changeManager: ChangeManager = new ChangeManager(this.rushConfiguration); + await changeManager.loadAsync( + this.rushConfiguration.changesFolder, + this._prereleaseToken, + this._addCommitDetails.value + ); + + if (changeManager.hasChanges()) { + const orderedChanges: IChangeInfo[] = changeManager.packageChanges; + const tempBranchName: string = `publish-${Date.now()}`; + + // Make changes in temp branch. + await publishGit.checkoutAsync(tempBranchName, true); + + this._setDependenciesBeforePublish(); + + // Make changes to package.json and change logs. + changeManager.apply(this._apply.value); + await changeManager.updateChangelogAsync(this._apply.value); + + this._setDependenciesBeforeCommit(); + + if (await git.hasUncommittedChangesAsync()) { + // Stage, commit, and push the changes to remote temp branch. + await publishGit.addChangesAsync(':/*'); + await publishGit.commitAsync( + this.rushConfiguration.gitVersionBumpCommitMessage || DEFAULT_PACKAGE_UPDATE_MESSAGE, + !this._ignoreGitHooksParameter.value + ); + await publishGit.pushAsync(tempBranchName, !this._ignoreGitHooksParameter.value); + + this._setDependenciesBeforePublish(); + + // Override tag parameter if there is a hotfix change. + for (const change of orderedChanges) { + if (change.changeType === ChangeType.hotfix) { + this._hotfixTagOverride = 'hotfix'; + break; + } + } + + // npm publish the things that need publishing. + for (const change of orderedChanges) { + if (change.changeType && change.changeType > ChangeType.dependency) { + const project: RushConfigurationProject | undefined = allPackages.get(change.packageName); + if (project) { + if (!(await this._packageExistsAsync(project))) { + await this._npmPublishAsync(change.packageName, project.publishFolder); + } else { + // eslint-disable-next-line no-console + console.log(`Skip ${change.packageName}. Package exists.`); + } + } else { + // eslint-disable-next-line no-console + console.log(`Skip ${change.packageName}. Failed to find its project.`); + } + } + } + + this._setDependenciesBeforeCommit(); + + // Create and push appropriate Git tags. + await this._gitAddTagsAsync(publishGit, orderedChanges); + await publishGit.pushAsync(tempBranchName, !this._ignoreGitHooksParameter.value); + + // Now merge to target branch. + await publishGit.checkoutAsync(this._targetBranch.value!); + await publishGit.pullAsync(!this._ignoreGitHooksParameter.value); + await publishGit.mergeAsync(tempBranchName, !this._ignoreGitHooksParameter.value); + await publishGit.pushAsync(this._targetBranch.value!, !this._ignoreGitHooksParameter.value); + await publishGit.deleteBranchAsync(tempBranchName, true, !this._ignoreGitHooksParameter.value); + } else { + await publishGit.checkoutAsync(this._targetBranch.value!); + await publishGit.deleteBranchAsync(tempBranchName, false, !this._ignoreGitHooksParameter.value); + } + } + } + + private async _publishAllAsync( + git: PublishGit, + allPackages: ReadonlyMap + ): Promise { + // eslint-disable-next-line no-console + console.log(`Rush publish starts with includeAll and version policy ${this._versionPolicy.value}`); + + let updated: boolean = false; + + for (const [packageName, packageConfig] of allPackages) { + if ( + packageConfig.shouldPublish && + (!this._versionPolicy.value || this._versionPolicy.value === packageConfig.versionPolicyName) + ) { + const applyTagAsync: (apply: boolean) => Promise = async (apply: boolean): Promise => { + if (!apply) { + return; + } + + const packageVersion: string = packageConfig.packageJson.version; + + // Do not create a new tag if one already exists, this will result in a fatal error + if (await git.hasTagAsync(packageConfig)) { + // eslint-disable-next-line no-console + console.log( + `Not tagging ${packageName}@${packageVersion}. A tag already exists for this version.` + ); + return; + } + + await git.addTagAsync( + !!this._publish.value, + packageName, + packageVersion, + this._commitId.value, + this._prereleaseName.value + ); + updated = true; + }; + + if (this._pack.value) { + // packs to tarball instead of publishing to NPM repository + await this._npmPackAsync(packageName, packageConfig); + await applyTagAsync(this._applyGitTagsOnPack.value); + } else if (this._force.value || !(await this._packageExistsAsync(packageConfig))) { + // Publish to npm repository + await this._npmPublishAsync(packageName, packageConfig.publishFolder); + await applyTagAsync(true); + } else { + // eslint-disable-next-line no-console + console.log(`Skip ${packageName}. Not updated.`); + } + } + } + + if (updated) { + await git.pushAsync(this._targetBranch.value!, !this._ignoreGitHooksParameter.value); + } + } + + private async _gitAddTagsAsync(git: PublishGit, orderedChanges: IChangeInfo[]): Promise { + for (const change of orderedChanges) { + if ( + change.changeType && + change.changeType > ChangeType.dependency && + this.rushConfiguration.projectsByName.get(change.packageName)!.shouldPublish + ) { + await git.addTagAsync( + !!this._publish.value && !this._registryUrl.value, + change.packageName, + change.newVersion!, + this._commitId.value, + this._prereleaseName.value + ); + } + } + } + + private async _npmPublishAsync(packageName: string, packagePath: string): Promise { + const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); + const args: string[] = ['publish']; + + if (this.rushConfiguration.projectsByName.get(packageName)!.shouldPublish) { + this._addSharedNpmConfig(env, args); + + if (this._npmTag.value) { + args.push(`--tag`, this._npmTag.value); + } else if (this._hotfixTagOverride) { + args.push(`--tag`, this._hotfixTagOverride); + } + + if (this._force.value) { + args.push(`--force`); + } + + if (this._npmAccessLevel.value) { + args.push(`--access`, this._npmAccessLevel.value); + } + + if (this.rushConfiguration.isPnpm) { + // PNPM 4.11.0 introduced a feature that may interrupt publishing and prompt the user for input. + // See this issue for details: https://github.com/microsoft/rushstack/issues/1940 + args.push('--no-git-checks'); + } + + // TODO: Yarn's "publish" command line is fairly different from NPM and PNPM. The right thing to do here + // would be to remap our options to the Yarn equivalents. But until we get around to that, we'll simply invoke + // whatever NPM binary happens to be installed in the global path. + const packageManagerToolFilename: string = + this.rushConfiguration.packageManager === 'yarn' + ? 'npm' + : this.rushConfiguration.packageManagerToolFilename; + + // 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, + args, + packagePath, + env, + secretSubstring + ); + } + } + + private async _packageExistsAsync(packageConfig: RushConfigurationProject): Promise { + const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); + const args: string[] = []; + this._addSharedNpmConfig(env, args); + + const publishedVersions: string[] = await Npm.getPublishedVersionsAsync( + packageConfig.packageName, + packageConfig.publishFolder, + env, + args + ); + + const packageVersion: string = packageConfig.packageJsonEditor.version; + + // SemVer supports an obscure (and generally deprecated) feature where "build metadata" can be + // appended to a version. For example if our version is "1.2.3-beta.4+extra567", then "+extra567" is the + // build metadata part. The suffix has no effect on version comparisons and is mostly ignored by + // the NPM registry. Importantly, the queried version number will not include it, so we need to discard + // it before comparing against the list of already published versions. + const parsedVersion: semver.SemVer | null = semver.parse(packageVersion); + if (!parsedVersion) { + throw new Error(`The package "${packageConfig.packageName}" has an invalid "version" value`); + } + + // For example, normalize "1.2.3-beta.4+extra567" -->"1.2.3-beta.4". + // + // This is redundant in the current API, but might change in the future: + // https://github.com/npm/node-semver/issues/264 + parsedVersion.build = []; + const normalizedVersion: string = parsedVersion.format(); + + return publishedVersions.indexOf(normalizedVersion) >= 0; + } + + private async _npmPackAsync(packageName: string, project: RushConfigurationProject): Promise { + const args: string[] = ['pack']; + const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); + + await PublishUtilities.execCommandAsync( + !!this._publish.value, + this.rushConfiguration.packageManagerToolFilename, + args, + project.publishFolder, + env + ); + + if (this._publish.value) { + // Copy the tarball the release folder + const tarballName: string = this._calculateTarballName(project); + const tarballPath: string = path.join(project.publishFolder, tarballName); + const destFolder: string = this._releaseFolder.value + ? this._releaseFolder.value + : path.join(this.rushConfiguration.commonTempFolder, 'artifacts', 'packages'); + + FileSystem.move({ + sourcePath: tarballPath, + destinationPath: path.join(destFolder, tarballName), + overwrite: true + }); + } + } + + private _calculateTarballName(project: RushConfigurationProject): string { + // Same logic as how npm forms the tarball name + const packageName: string = project.packageName; + const name: string = packageName[0] === '@' ? packageName.substr(1).replace(/\//g, '-') : packageName; + + if (this.rushConfiguration.packageManager === 'yarn') { + // yarn tarballs have a "v" before the version number + return `${name}-v${project.packageJson.version}.tgz`; + } else { + return `${name}-${project.packageJson.version}.tgz`; + } + } + + 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 _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 _addNpmPublishHome(supportEnvVarFallbackSyntax: boolean): void { + // Create "common\temp\publish-home" folder, if it doesn't exist + Utilities.createFolderWithRetry(this._targetNpmrcPublishFolder); + + // Copy down the committed "common\config\rush\.npmrc-publish" file, if there is one + Utilities.syncNpmrc({ + sourceNpmrcFolder: this.rushConfiguration.commonRushConfigFolder, + targetNpmrcFolder: this._targetNpmrcPublishFolder, + useNpmrcPublish: true, + supportEnvVarFallbackSyntax + }); + } + + private _addSharedNpmConfig(env: { [key: string]: string | undefined }, args: string[]): void { + const userHomeEnvVariable: string = process.platform === 'win32' ? 'USERPROFILE' : 'HOME'; + let registry: string = '//registry.npmjs.org/'; + + // Check if .npmrc file exists in "common\temp\publish-home" + if (FileSystem.exists(this._targetNpmrcPublishPath)) { + // Redirect userHomeEnvVariable, NPM will use config in "common\temp\publish-home\.npmrc" + env[userHomeEnvVariable] = this._targetNpmrcPublishFolder; + } + + // Check if registryUrl and token are specified via command-line + if (this._registryUrl.value) { + const registryUrl: string = this._registryUrl.value; + env['npm_config_registry'] = registryUrl; // eslint-disable-line dot-notation + registry = registryUrl.substring(registryUrl.indexOf('//')); + } + + if (this._npmAuthToken.value) { + args.push(`--${registry}:_authToken=${this._npmAuthToken.value}`); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/PurgeAction.ts b/libraries/rush-lib/src/cli/actions/PurgeAction.ts new file mode 100644 index 00000000000..3f8e0d223ff --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/PurgeAction.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 { CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { Colorize } from '@rushstack/terminal'; + +import { BaseRushAction } from './BaseRushAction'; +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_ACTION_NAME, + summary: + 'For diagnostic purposes, use this command to delete caches and other temporary files used by Rush', + documentation: + 'The "rush purge" command is used to delete temporary files created by Rush. This is' + + ' useful if you are having problems and suspect that cache files may be corrupt.', + parser + }); + + this._unsafeParameter = this.defineFlagParameter({ + parameterLongName: '--unsafe', + description: + '(UNSAFE!) Also delete shared files such as the package manager instances stored in' + + ' the ".rush" folder in the user\'s home directory. This is a more aggressive fix that is' + + ' NOT SAFE to run in a live environment because it will cause other concurrent Rush processes to fail.' + }); + } + + protected async runAsync(): Promise { + const stopwatch: Stopwatch = Stopwatch.start(); + + const unlinkManager: UnlinkManager = new UnlinkManager(this.rushConfiguration); + const purgeManager: PurgeManager = new PurgeManager(this.rushConfiguration, this.rushGlobalFolder); + + await unlinkManager.unlinkAsync(/*force:*/ true); + + if (this._unsafeParameter.value!) { + purgeManager.purgeUnsafe(); + } else { + purgeManager.purgeNormal(); + } + + await purgeManager.startDeleteAllAsync(); + + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.green( + `Rush purge started successfully and will complete asynchronously. (${stopwatch.toString()})` + ) + ); + } +} diff --git a/libraries/rush-lib/src/cli/actions/RemoveAction.ts b/libraries/rush-lib/src/cli/actions/RemoveAction.ts new file mode 100644 index 00000000000..72c17f44d55 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/RemoveAction.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 { 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 } from '../../api/Variants'; + +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_ACTION_NAME, + summary: 'Removes one or more dependencies from the package.json and runs rush update.', + documentation, + safeForSimultaneousRushProcesses: false, + parser, + + packageNameListParameterDescription: + 'The name of the package which should be removed.' + + ` 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.' + }); + } + + public async getUpdateOptionsAsync(): Promise { + const projects: RushConfigurationProject[] = super.getProjects(); + + const packagesToRemove: IPackageForRushRemove[] = []; + + for (const specifiedPackageName of this.specifiedPackageNameList) { + 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(specifiedPackageName) && + !project.packageJsonEditor.tryGetDevDependency(specifiedPackageName) + ) { + this.terminal.writeLine( + `The project "${project.packageName}" does not have "${specifiedPackageName}" in package.json.` + ); + } + } + + packagesToRemove.push({ packageName: specifiedPackageName }); + } + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + true + ); + + return { + projects, + packagesToUpdate: packagesToRemove, + skipUpdate: this._skipUpdateFlag.value, + debugInstall: this.parser.isDebug, + actionName: this.actionName, + variant + }; + } +} diff --git a/libraries/rush-lib/src/cli/actions/ScanAction.ts b/libraries/rush-lib/src/cli/actions/ScanAction.ts new file mode 100644 index 00000000000..0bcd7e08c7a --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/ScanAction.ts @@ -0,0 +1,267 @@ +// 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 builtinPackageNames from 'builtin-modules'; + +import { Colorize } from '@rushstack/terminal'; +import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { FileSystem } from '@rushstack/node-core-library'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseConfiglessRushAction } from './BaseRushAction'; + +export interface IJsonOutput { + /** + * Dependencies scan from source code + */ + detectedDependencies: string[]; + /** + * Dependencies detected but not declared in package.json + */ + missingDependencies: string[]; + /** + * Dependencies declared in package.json, but not used in source code + */ + unusedDependencies: string[]; +} + +export class ScanAction extends BaseConfiglessRushAction { + private readonly _jsonFlag: CommandLineFlagParameter; + private readonly _allFlag: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'scan', + summary: + 'When migrating projects into a Rush repo, this command is helpful for detecting' + + ' undeclared dependencies.', + documentation: + `The Node.js module system allows a project to import NPM packages without explicitly` + + ` declaring them as dependencies in the package.json file. Such "phantom dependencies"` + + ` can cause problems. Rush and PNPM use symlinks specifically to protect against phantom dependencies.` + + ` These protections may cause runtime errors for existing projects when they are first migrated into` + + ` a Rush monorepo. The "rush scan" command is a handy tool for fixing these errors. It scans the "./src"` + + ` and "./lib" folders for import syntaxes such as "import __ from '__'", "require('__')",` + + ` and "System.import('__'). It prints a report of the referenced packages. This heuristic is` + + ` not perfect, but it can save a lot of time when migrating projects.`, + safeForSimultaneousRushProcesses: true, + parser + }); + + this._jsonFlag = this.defineFlagParameter({ + parameterLongName: '--json', + description: 'If this flag is specified, output will be in JSON format.' + }); + this._allFlag = this.defineFlagParameter({ + parameterLongName: '--all', + description: 'If this flag is specified, output will list all detected dependencies.' + }); + } + + protected async runAsync(): Promise { + const packageJsonFilename: string = path.resolve('./package.json'); + + if (!FileSystem.exists(packageJsonFilename)) { + throw new Error('You must run "rush scan" in a project folder containing a package.json file.'); + } + + const requireRegExps: RegExp[] = [ + // Example: require('something') + /\brequire\s*\(\s*[']([^']+\s*)[']\s*\)/, + /\brequire\s*\(\s*["]([^"]+\s*)["]\s*\)/, + + // Example: require.ensure('something') + /\brequire\.ensure\s*\(\s*[']([^']+\s*)[']\s*\)/, + /\brequire\.ensure\s*\(\s*["]([^"]+\s*)["]\s*\)/, + + // Example: require.resolve('something') + /\brequire\.resolve\s*\(\s*[']([^']+\s*)[']\s*\)/, + /\brequire\.resolve\s*\(\s*["]([^"]+\s*)["]\s*\)/, + + // Example: System.import('something') + /\bSystem\.import\s*\(\s*[']([^']+\s*)[']\s*\)/, + /\bSystem\.import\s*\(\s*["]([^"]+\s*)["]\s*\)/, + + // Example: Import.lazy('something', require); + /\bImport\.lazy\s*\(\s*[']([^']+\s*)[']/, + /\bImport\.lazy\s*\(\s*["]([^"]+\s*)["]/, + + // Example: + // + // import { + // A, B + // } from 'something'; + /\bfrom\s*[']([^']+)[']/, + /\bfrom\s*["]([^"]+)["]/, + + // Example: import 'something'; + /\bimport\s*[']([^']+)[']\s*\;/, + /\bimport\s*["]([^"]+)["]\s*\;/, + + // Example: await import('fast-glob') + /\bimport\s*\(\s*[']([^']+)[']\s*\)/, + /\bimport\s*\(\s*["]([^"]+)["]\s*\)/, + + // Example: + // /// + /\/\/\/\s*<\s*reference\s+types\s*=\s*["]([^"]+)["]\s*\/>/ + ]; + + // Example: "my-package/lad/dee/dah" --> "my-package" + // Example: "@ms/my-package" --> "@ms/my-package" + // Example: "lodash.get" --> "lodash.get" + const packageRegExp: RegExp = /^((@[a-z\-0-9!_]+\/)?[a-z\-0-9!_][a-z\-0-9!_.]*)\/?/; + + const requireMatches: Set = new Set(); + + const { default: glob } = await import('fast-glob'); + const scanResults: string[] = await glob(['./*.{ts,js,tsx,jsx}', './{src,lib}/**/*.{ts,js,tsx,jsx}']); + for (const filename of scanResults) { + try { + const contents: string = FileSystem.readFile(filename); + const lines: string[] = contents.split('\n'); + + for (const line of lines) { + for (const requireRegExp of requireRegExps) { + const requireRegExpResult: RegExpExecArray | null = requireRegExp.exec(line); + if (requireRegExpResult) { + requireMatches.add(requireRegExpResult[1]); + } + } + } + } catch (error) { + // eslint-disable-next-line no-console + console.log(Colorize.bold('Skipping file due to error: ' + filename)); + } + } + + const packageMatches: Set = new Set(); + + requireMatches.forEach((requireMatch: string) => { + const packageRegExpResult: RegExpExecArray | null = packageRegExp.exec(requireMatch); + if (packageRegExpResult) { + packageMatches.add(packageRegExpResult[1]); + } + }); + + const detectedPackageNames: string[] = []; + + packageMatches.forEach((packageName: string) => { + if (builtinPackageNames.indexOf(packageName) < 0) { + detectedPackageNames.push(packageName); + } + }); + + detectedPackageNames.sort(); + + const declaredDependencies: Set = new Set(); + const declaredDevDependencies: Set = new Set(); + const missingDependencies: string[] = []; + const unusedDependencies: string[] = []; + const packageJsonContent: string = FileSystem.readFile(packageJsonFilename); + try { + const manifest: { + dependencies?: Record; + devDependencies?: Record; + } = JSON.parse(packageJsonContent); + if (manifest.dependencies) { + for (const depName of Object.keys(manifest.dependencies)) { + declaredDependencies.add(depName); + } + } + if (manifest.devDependencies) { + for (const depName of Object.keys(manifest.devDependencies)) { + declaredDevDependencies.add(depName); + } + } + } catch (e) { + // eslint-disable-next-line no-console + console.error(`JSON.parse ${packageJsonFilename} error`); + } + + for (const detectedPkgName of detectedPackageNames) { + /** + * Missing(phantom) dependencies are + * - used in source code + * - not decalred in dependencies and devDependencies in package.json + */ + if (!declaredDependencies.has(detectedPkgName) && !declaredDevDependencies.has(detectedPkgName)) { + missingDependencies.push(detectedPkgName); + } + } + for (const declaredPkgName of declaredDependencies) { + /** + * Unused dependencies are + * - declared in dependencies in package.json (devDependencies not included) + * - not used in source code + */ + if (!detectedPackageNames.includes(declaredPkgName) && !declaredPkgName.startsWith('@types/')) { + unusedDependencies.push(declaredPkgName); + } + } + + const output: IJsonOutput = { + detectedDependencies: detectedPackageNames, + missingDependencies: missingDependencies, + unusedDependencies: unusedDependencies + }; + + if (this._jsonFlag.value) { + // eslint-disable-next-line no-console + console.log(JSON.stringify(output, undefined, 2)); + } else if (this._allFlag.value) { + if (detectedPackageNames.length !== 0) { + // eslint-disable-next-line no-console + console.log('Dependencies that seem to be imported by this project:'); + for (const packageName of detectedPackageNames) { + // eslint-disable-next-line no-console + console.log(' ' + packageName); + } + } else { + // eslint-disable-next-line no-console + console.log('This project does not seem to import any NPM packages.'); + } + } else { + let wroteAnything: boolean = false; + + if (missingDependencies.length > 0) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow('Possible phantom dependencies') + + " - these seem to be imported but aren't listed in package.json:" + ); + for (const packageName of missingDependencies) { + // eslint-disable-next-line no-console + console.log(' ' + packageName); + } + wroteAnything = true; + } + + if (unusedDependencies.length > 0) { + if (wroteAnything) { + // eslint-disable-next-line no-console + console.log(''); + } + // eslint-disable-next-line no-console + console.log( + Colorize.yellow('Possible unused dependencies') + + " - these are listed in package.json but don't seem to be imported:" + ); + for (const packageName of unusedDependencies) { + // eslint-disable-next-line no-console + console.log(' ' + packageName); + } + wroteAnything = true; + } + + if (!wroteAnything) { + // eslint-disable-next-line no-console + console.log( + Colorize.green('Everything looks good.') + ' No missing or unused dependencies were found.' + ); + } + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/SetupAction.ts b/libraries/rush-lib/src/cli/actions/SetupAction.ts new file mode 100644 index 00000000000..04e91720507 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/SetupAction.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 { SetupPackageRegistry } from '../../logic/setup/SetupPackageRegistry'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseRushAction } from './BaseRushAction'; + +export class SetupAction extends BaseRushAction { + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'setup', + summary: + '(EXPERIMENTAL) Invoke this command before working in a new repo to ensure that any required' + + ' prerequisites are installed and permissions are configured.', + documentation: + '(EXPERIMENTAL) Invoke this command before working in a new repo to ensure that any required' + + ' prerequisites are installed and permissions are configured. The initial implementation' + + ' configures the NPM registry credentials. More features will be added later.', + parser + }); + } + + protected async runAsync(): Promise { + const setupPackageRegistry: SetupPackageRegistry = new SetupPackageRegistry({ + rushConfiguration: this.rushConfiguration, + isDebug: this.parser.isDebug, + syncNpmrcAlreadyCalled: false + }); + await setupPackageRegistry.checkAndSetupAsync(); + } +} diff --git a/libraries/rush-lib/src/cli/actions/UnlinkAction.ts b/libraries/rush-lib/src/cli/actions/UnlinkAction.ts new file mode 100644 index 00000000000..ef3c112c2b6 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/UnlinkAction.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 type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseRushAction } from './BaseRushAction'; +import { UnlinkManager } from '../../logic/UnlinkManager'; + +export class UnlinkAction extends BaseRushAction { + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'unlink', + summary: 'Delete node_modules symlinks for all projects in the repo', + documentation: + 'This removes the symlinks created by the "rush link" command. This is useful for' + + ' cleaning a repo using "git clean" without accidentally deleting source files, or for using standard NPM' + + ' commands on a project.', + parser + }); + } + + protected async runAsync(): Promise { + const unlinkManager: UnlinkManager = new UnlinkManager(this.rushConfiguration); + + if (!(await unlinkManager.unlinkAsync())) { + // eslint-disable-next-line no-console + console.log('Nothing to do.'); + } else { + // eslint-disable-next-line no-console + console.log('\nDone.'); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/UpdateAction.ts b/libraries/rush-lib/src/cli/actions/UpdateAction.ts new file mode 100644 index 00000000000..f503656bfcc --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/UpdateAction.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 type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseInstallAction } from './BaseInstallAction'; +import type { IInstallManagerOptions } from '../../logic/base/BaseInstallManagerTypes'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { SelectionParameterSet } from '../parsing/SelectionParameterSet'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { Subspace } from '../../api/Subspace'; +import { getVariantAsync } from '../../api/Variants'; + +export class UpdateAction extends BaseInstallAction { + private readonly _fullParameter: CommandLineFlagParameter; + private readonly _recheckParameter: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'update', + summary: + 'Install package dependencies for all projects in the repo,' + + ' and create or update the shrinkwrap file as needed', + documentation: + 'The "rush update" command installs the dependencies described in your' + + ' package.json files, and updates the shrinkwrap file as needed.' + + ' (This "shrinkwrap" file stores a central inventory of all dependencies and versions' + + ' for projects in your repo. It is found in the "common/config/rush" folder.)' + + ' Note that Rush always performs a single install for all projects in your repo.' + + ' You should run "rush update" whenever you start working in a Rush repo,' + + ' after you pull from Git, and after you modify a package.json file.' + + ' If there is nothing to do, "rush update" is instantaneous.' + + ' NOTE: In certain cases "rush install" should be used instead of "rush update"' + + ' -- for details, see the command help for "rush install".', + parser + }); + + if (this.rushConfiguration?.subspacesFeatureEnabled) { + // Partial update is supported only when subspaces is enabled. + this._selectionParameters = new SelectionParameterSet(this.rushConfiguration, this, { + gitOptions: { + // Include lockfile processing since this expands the selection, and we need to select + // at least the same projects selected with the same query to "rush build" + includeExternalDependencies: true, + // Disable filtering because rush-project.json is riggable and therefore may not be available + enableFiltering: false + }, + includeSubspaceSelector: true, + cwd: this.parser.cwd + }); + } + + this._fullParameter = this.defineFlagParameter({ + parameterLongName: '--full', + description: + 'Normally "rush update" tries to preserve your existing installed versions' + + ' and only makes the minimum updates needed to satisfy the package.json files.' + + ' This conservative approach prevents your PR from getting involved with package updates that' + + ' are unrelated to your work. Use "--full" when you really want to update all dependencies' + + ' to the latest SemVer-compatible version. This should be done periodically by a person' + + ' or robot whose role is to deal with potential upgrade regressions.' + }); + this._recheckParameter = this.defineFlagParameter({ + parameterLongName: '--recheck', + description: + 'If the shrinkwrap file appears to already satisfy the package.json files,' + + ' then "rush update" will skip invoking the package manager at all. In certain situations' + + ' this heuristic may be inaccurate. Use the "--recheck" flag to force the package manager' + + " to process the shrinkwrap file. This will also update your shrinkwrap file with Rush's fixups." + + ' (To minimize shrinkwrap churn, these fixups are normally performed only in the temporary folder.)' + }); + } + + protected async runAsync(): Promise { + await this.parser.pluginManager.updateAsync(); + + if (this.parser.pluginManager.error) { + await this.parser.pluginManager.reinitializeAllPluginsForCommandAsync(this.actionName); + } + + return super.runAsync(); + } + + protected async buildInstallOptionsAsync(): Promise> { + const selectedProjects: Set = + (await this._selectionParameters?.getSelectedProjectsAsync(this.terminal)) ?? + new Set(this.rushConfiguration.projects); + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + false + ); + + return { + debug: this.parser.isDebug, + allowShrinkwrapUpdates: true, + bypassPolicyAllowed: true, + bypassPolicy: this._bypassPolicyParameter.value!, + noLink: this._noLinkParameter.value!, + fullUpgrade: this._fullParameter.value!, + recheckShrinkwrap: this._recheckParameter.value!, + offline: this._offlineParameter.value!, + networkConcurrency: this._networkConcurrencyParameter.value, + collectLogFile: this._debugPackageManagerParameter.value!, + variant, + // Because the 'defaultValue' option on the _maxInstallAttempts parameter is set, + // it is safe to assume that the value is not null + maxInstallAttempts: this._maxInstallAttempts.value!, + // These are derived independently of the selection for command line brevity + selectedProjects, + pnpmFilterArgumentValues: + (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 + }; + } +} diff --git a/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts new file mode 100644 index 00000000000..e8e2f7085b2 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/UpdateAutoinstallerAction.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import type { Autoinstaller } from '../../logic/Autoinstaller'; +import { BaseAutoinstallerAction } from './BaseAutoinstallerAction'; + +export class UpdateAutoinstallerAction extends BaseAutoinstallerAction { + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'update-autoinstaller', + summary: 'Updates autoinstaller package dependencies', + documentation: 'Use this command to regenerate the shrinkwrap file for an autoinstaller folder.', + parser + }); + } + + protected async prepareAsync(autoinstaller: Autoinstaller): Promise { + // Do not run `autoinstaller.prepareAsync` here. It tries to install the autoinstaller with + // --frozen-lockfile or equivalent, which will fail if the autoinstaller's dependencies + // have been changed. + await autoinstaller.updateAsync(); + } +} diff --git a/libraries/rush-lib/src/cli/actions/UpdateCloudCredentialsAction.ts b/libraries/rush-lib/src/cli/actions/UpdateCloudCredentialsAction.ts new file mode 100644 index 00000000000..97a792c9916 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/UpdateCloudCredentialsAction.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 { CommandLineStringParameter, CommandLineFlagParameter } from '@rushstack/ts-command-line'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseRushAction } from './BaseRushAction'; +import { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; +import { RushConstants } from '../../logic/RushConstants'; + +export class UpdateCloudCredentialsAction extends BaseRushAction { + private readonly _interactiveModeFlag: CommandLineFlagParameter; + private readonly _credentialParameter: CommandLineStringParameter; + private readonly _deleteFlag: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: RushConstants.updateCloudCredentialsCommandName, + summary: '(EXPERIMENTAL) Update the credentials used by the build cache provider.', + documentation: + '(EXPERIMENTAL) If the build caching feature is configured, this command facilitates ' + + 'updating the credentials used by a cloud-based provider.', + safeForSimultaneousRushProcesses: false, + parser + }); + + this._interactiveModeFlag = this.defineFlagParameter({ + parameterLongName: '--interactive', + parameterShortName: '-i', + description: 'Run the credential update operation in interactive mode, if supported by the provider.' + }); + this._credentialParameter = this.defineStringParameter({ + parameterLongName: '--credential', + argumentName: 'CREDENTIAL_STRING', + description: 'A static credential, to be cached.' + }); + this._deleteFlag = this.defineFlagParameter({ + parameterLongName: '--delete', + parameterShortName: '-d', + description: 'If specified, delete stored credentials.' + }); + } + + protected async runAsync(): Promise { + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + + const buildCacheConfiguration: BuildCacheConfiguration = + await BuildCacheConfiguration.loadAndRequireEnabledAsync( + terminal, + this.rushConfiguration, + this.rushSession + ); + + if (this._deleteFlag.value) { + if (this._interactiveModeFlag.value || this._credentialParameter.value !== undefined) { + terminal.writeErrorLine( + `If the ${this._deleteFlag.longName} is provided, no other parameters may be provided.` + ); + throw new AlreadyReportedError(); + } else if (buildCacheConfiguration.cloudCacheProvider) { + await buildCacheConfiguration.cloudCacheProvider.deleteCachedCredentialsAsync(terminal); + } else { + terminal.writeLine('A cloud build cache is not configured; there is nothing to delete.'); + } + } else if (this._interactiveModeFlag.value && this._credentialParameter.value !== undefined) { + terminal.writeErrorLine( + `Both the ${this._interactiveModeFlag.longName} and the ` + + `${this._credentialParameter.longName} parameters were provided. Only one ` + + 'or the other may be used at a time.' + ); + throw new AlreadyReportedError(); + } else if (this._interactiveModeFlag.value) { + if (buildCacheConfiguration.cloudCacheProvider) { + await buildCacheConfiguration.cloudCacheProvider.updateCachedCredentialInteractiveAsync(terminal); + } else { + terminal.writeLine('A cloud build cache is not configured. Credentials are not required.'); + } + } else if (this._credentialParameter.value !== undefined) { + if (buildCacheConfiguration.cloudCacheProvider) { + await buildCacheConfiguration.cloudCacheProvider.updateCachedCredentialAsync( + terminal, + this._credentialParameter.value + ); + } else { + terminal.writeErrorLine('A cloud build cache is not configured. Credentials are not supported.'); + throw new AlreadyReportedError(); + } + } else { + terminal.writeErrorLine( + `One of the ${this._interactiveModeFlag.longName} parameter, the ` + + `${this._credentialParameter.longName} parameter, or the ` + + `${this._deleteFlag.longName} parameter must be provided.` + ); + throw new AlreadyReportedError(); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts b/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts new file mode 100644 index 00000000000..273b67ba91b --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; + +export class UpgradeInteractiveAction extends BaseRushAction { + private _makeConsistentFlag: CommandLineFlagParameter; + private _skipUpdateFlag: CommandLineFlagParameter; + private readonly _variantParameter: CommandLineStringParameter; + + public constructor(parser: RushCommandLineParser) { + const documentation: string[] = [ + 'Provide an interactive way to upgrade your dependencies. Running the command will open an interactive prompt' + + ' that will ask you which projects and which dependencies you would like to upgrade.' + + ' It will then update your package.json files, and run "rush update" for you.' + + ' If you are using ensureConsistentVersions policy, upgrade-interactive will update all packages which use the' + + ' dependencies that you are upgrading and match their SemVer range if provided. If ensureConsistentVersions' + + ' is not enabled, upgrade-interactive will only update the dependency in the package you specify.' + + ' This can be overriden by using the --make-consistent flag.' + ]; + super({ + actionName: 'upgrade-interactive', + summary: 'Provides interactive prompt for upgrading package dependencies per project', + safeForSimultaneousRushProcesses: false, + documentation: documentation.join(''), + parser + }); + + this._makeConsistentFlag = this.defineFlagParameter({ + parameterLongName: '--make-consistent', + description: + 'When upgrading dependencies from a single project, also upgrade dependencies from other projects.' + }); + + 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._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); + } + + public async runAsync(): Promise { + const [{ PackageJsonUpdater }, { InteractiveUpgrader }] = await Promise.all([ + import(/* webpackChunkName: 'PackageJsonUpdater' */ '../../logic/PackageJsonUpdater'), + import(/* webpackChunkName: 'InteractiveUpgrader' */ '../../logic/InteractiveUpgrader') + ]); + + const packageJsonUpdater: PackageJsonUpdaterType.PackageJsonUpdater = new PackageJsonUpdater( + this.terminal, + this.rushConfiguration, + this.rushGlobalFolder + ); + const interactiveUpgrader: InteractiveUpgraderType.InteractiveUpgrader = new InteractiveUpgrader( + this.rushConfiguration + ); + + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + true + ); + const shouldMakeConsistent: boolean = + this.rushConfiguration.defaultSubspace.shouldEnsureConsistentVersions(variant) || + this._makeConsistentFlag.value; + + const { projects, depsToUpgrade } = await interactiveUpgrader.upgradeAsync(); + + await packageJsonUpdater.doRushUpgradeAsync({ + projects, + packagesToAdd: depsToUpgrade.packages, + updateOtherPackages: shouldMakeConsistent, + skipUpdate: this._skipUpdateFlag.value, + debugInstall: this.parser.isDebug, + variant + }); + } +} diff --git a/libraries/rush-lib/src/cli/actions/VersionAction.ts b/libraries/rush-lib/src/cli/actions/VersionAction.ts new file mode 100644 index 00000000000..de854535680 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/VersionAction.ts @@ -0,0 +1,299 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; + +import { BumpType, type LockStepVersionPolicy } from '../../api/VersionPolicy'; +import type { VersionPolicyConfiguration } from '../../api/VersionPolicyConfiguration'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismatchFinder'; +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import * as PolicyValidator from '../../logic/policy/PolicyValidator'; +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]'; +export const DEFAULT_CHANGELOG_UPDATE_MESSAGE: string = 'Update changelogs [skip ci]'; + +export class VersionAction extends BaseRushAction { + private readonly _ensureVersionPolicy: CommandLineFlagParameter; + private readonly _overrideVersion: CommandLineStringParameter; + private readonly _bumpVersion: CommandLineFlagParameter; + private readonly _versionPolicy: CommandLineStringParameter; + private readonly _bypassPolicy: CommandLineFlagParameter; + private readonly _targetBranch: CommandLineStringParameter; + private readonly _overwriteBump: CommandLineStringParameter; + private readonly _prereleaseIdentifier: CommandLineStringParameter; + private readonly _ignoreGitHooksParameter: CommandLineFlagParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: 'version', + summary: 'Manage package versions in the repo.', + documentation: 'use this "rush version" command to ensure version policies and bump versions.', + parser + }); + + this._targetBranch = this.defineStringParameter({ + parameterLongName: '--target-branch', + parameterShortName: '-b', + argumentName: 'BRANCH', + description: 'If this flag is specified, changes will be committed and merged into the target branch.' + }); + this._ensureVersionPolicy = this.defineFlagParameter({ + parameterLongName: '--ensure-version-policy', + description: 'Updates package versions if needed to satisfy version policies.' + }); + this._overrideVersion = this.defineStringParameter({ + parameterLongName: '--override-version', + argumentName: 'NEW_VERSION', + description: + 'Override the version in the specified --version-policy. ' + + 'This setting only works for lock-step version policy and when --ensure-version-policy is specified.' + }); + this._bumpVersion = this.defineFlagParameter({ + parameterLongName: '--bump', + description: 'Bumps package version based on version policies.' + }); + this._bypassPolicy = this.defineFlagParameter({ + parameterLongName: RushConstants.bypassPolicyFlagLongName, + description: 'Overrides "gitPolicy" enforcement (use honorably!)' + }); + this._versionPolicy = this.defineStringParameter({ + parameterLongName: '--version-policy', + argumentName: 'POLICY', + description: 'The name of the version policy' + }); + this._overwriteBump = this.defineStringParameter({ + parameterLongName: '--override-bump', + argumentName: 'BUMPTYPE', + description: + 'Overrides the bump type in the version-policy.json for the specified version policy. ' + + 'Valid BUMPTYPE values include: prerelease, patch, preminor, minor, major. ' + + 'This setting only works for lock-step version policy in bump action.' + }); + this._prereleaseIdentifier = this.defineStringParameter({ + parameterLongName: '--override-prerelease-id', + argumentName: 'ID', + description: + 'Overrides the prerelease identifier in the version value of version-policy.json ' + + 'for the specified version policy. ' + + 'This setting only works for lock-step version policy. ' + + 'This setting increases to new prerelease id when "--bump" is provided but only replaces the ' + + 'prerelease name when "--ensure-version-policy" is provided.' + }); + this._ignoreGitHooksParameter = this.defineFlagParameter({ + parameterLongName: '--ignore-git-hooks', + description: `Skips execution of all git hooks. Make sure you know what you are skipping.` + }); + } + + protected async runAsync(): Promise { + const currentlyInstalledVariant: string | undefined = + await this.rushConfiguration.getCurrentlyInstalledVariantAsync(); + for (const subspace of this.rushConfiguration.subspaces) { + await PolicyValidator.validatePolicyAsync(this.rushConfiguration, subspace, currentlyInstalledVariant, { + bypassPolicyAllowed: true, + bypassPolicy: this._bypassPolicy.value + }); + } + const git: Git = new Git(this.rushConfiguration); + const userEmail: string = await git.getGitEmailAsync(); + + this._validateInput(); + const versionManagerModule: typeof VersionManagerType = await import( + /* webpackChunkName: 'VersionManager' */ + '../../logic/VersionManager' + ); + const versionManager: VersionManagerType.VersionManager = new versionManagerModule.VersionManager( + this.rushConfiguration, + userEmail, + this.rushConfiguration.versionPolicyConfiguration + ); + + if (this._ensureVersionPolicy.value) { + this._overwritePolicyVersionIfNeeded(); + const tempBranch: string = 'version/ensure-' + new Date().getTime(); + versionManager.ensure( + this._versionPolicy.value, + true, + !!this._overrideVersion.value || !!this._prereleaseIdentifier.value + ); + + const updatedPackages: Map = versionManager.updatedProjects; + if (updatedPackages.size > 0) { + // eslint-disable-next-line no-console + console.log(`${updatedPackages.size} packages are getting updated.`); + await this._gitProcessAsync(tempBranch, this._targetBranch.value, currentlyInstalledVariant); + } + } else if (this._bumpVersion.value) { + const tempBranch: string = 'version/bump-' + new Date().getTime(); + await versionManager.bumpAsync( + this._versionPolicy.value, + this._overwriteBump.value ? Enum.getValueByKey(BumpType, this._overwriteBump.value) : undefined, + this._prereleaseIdentifier.value, + true + ); + await this._gitProcessAsync(tempBranch, this._targetBranch.value, currentlyInstalledVariant); + } + } + + private _overwritePolicyVersionIfNeeded(): void { + if (!this._overrideVersion.value && !this._prereleaseIdentifier.value) { + // No need to overwrite policy version + return; + } + if (this._overrideVersion.value && this._prereleaseIdentifier.value) { + throw new Error( + `The parameters "--override-version" and "--override-prerelease-id" cannot be used together.` + ); + } + + if (this._versionPolicy.value) { + const versionConfig: VersionPolicyConfiguration = this.rushConfiguration.versionPolicyConfiguration; + const policy: LockStepVersionPolicy = versionConfig.getVersionPolicy( + this._versionPolicy.value + ) as LockStepVersionPolicy; + if (!policy || !policy.isLockstepped) { + throw new Error(`The lockstep version policy "${policy.policyName}" is not found.`); + } + let newVersion: string | undefined = undefined; + if (this._overrideVersion.value) { + newVersion = this._overrideVersion.value; + } else if (this._prereleaseIdentifier.value) { + const newPolicyVersion: semver.SemVer = new semver.SemVer(policy.version); + if (newPolicyVersion.prerelease.length) { + // Update 1.5.0-alpha.10 to 1.5.0-beta.10 + // For example, if we are parsing "1.5.0-alpha.10" then the newPolicyVersion.prerelease array + // would contain [ "alpha", 10 ], so we would replace "alpha" with "beta" + newPolicyVersion.prerelease = [ + this._prereleaseIdentifier.value, + ...newPolicyVersion.prerelease.slice(1) + ]; + } else { + // Update 1.5.0 to 1.5.0-beta + // Since there is no length, we can just set to a new array + newPolicyVersion.prerelease = [this._prereleaseIdentifier.value]; + } + newVersion = newPolicyVersion.format(); + } + + if (newVersion) { + versionConfig.update(this._versionPolicy.value, newVersion, true); + } + } else { + throw new Error( + 'Missing --version-policy parameter to specify which version policy should be overwritten.' + ); + } + } + + private _validateInput(): void { + if (this._bumpVersion.value && this._ensureVersionPolicy.value) { + throw new Error('Please choose --bump or --ensure-version-policy but not together.'); + } + + if (this._overwriteBump.value && !Enum.tryGetValueByKey(BumpType, this._overwriteBump.value)) { + throw new Error( + 'The value of override-bump is not valid. ' + + 'Valid values include prerelease, patch, preminor, minor, and major' + ); + } + } + + private _validateResult(variant: string | undefined): void { + // Load the config from file to avoid using inconsistent in-memory data. + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + this.rushConfiguration.rushJsonFile + ); + + // Validate result of all subspaces + for (const subspace of rushConfig.subspaces) { + // Respect the `ensureConsistentVersions` field in rush.json + if (!subspace.shouldEnsureConsistentVersions(variant)) { + continue; + } + + const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches(rushConfig, { + subspace, + variant + }); + if (mismatchFinder.numberOfMismatches) { + throw new Error( + 'Unable to finish version bump because inconsistencies were encountered. ' + + 'Run "rush check" to find more details.' + ); + } + } + } + + private async _gitProcessAsync( + tempBranch: string, + targetBranch: string | undefined, + variant: string | undefined + ): Promise { + // Validate the result before commit. + this._validateResult(variant); + + const git: Git = new Git(this.rushConfiguration); + const publishGit: PublishGit = new PublishGit(git, targetBranch); + + // Make changes in temp branch. + await publishGit.checkoutAsync(tempBranch, true); + + const uncommittedChanges: ReadonlyArray = await git.getUncommittedChangesAsync(); + + // Stage, commit, and push the changes to remote temp branch. + // Need to commit the change log updates in its own commit + const changeLogUpdated: boolean = uncommittedChanges.some((changePath) => { + return changePath.indexOf('CHANGELOG.json') > 0; + }); + + if (changeLogUpdated) { + await publishGit.addChangesAsync('.', this.rushConfiguration.changesFolder); + await publishGit.addChangesAsync(':/**/CHANGELOG.json'); + await publishGit.addChangesAsync(':/**/CHANGELOG.md'); + await publishGit.commitAsync( + this.rushConfiguration.gitChangeLogUpdateCommitMessage || DEFAULT_CHANGELOG_UPDATE_MESSAGE, + !this._ignoreGitHooksParameter.value + ); + } + + // Commit the package.json and change files updates. + const packageJsonUpdated: boolean = uncommittedChanges.some((changePath) => { + return changePath.indexOf(FileConstants.PackageJson) > 0; + }); + + if (packageJsonUpdated) { + await publishGit.addChangesAsync(this.rushConfiguration.versionPolicyConfigurationFilePath); + await publishGit.addChangesAsync(':/**/package.json'); + await publishGit.commitAsync( + this.rushConfiguration.gitVersionBumpCommitMessage || DEFAULT_PACKAGE_UPDATE_MESSAGE, + !this._ignoreGitHooksParameter.value + ); + } + + if (changeLogUpdated || packageJsonUpdated) { + 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, false); + await publishGit.deleteBranchAsync(tempBranch, true, !this._ignoreGitHooksParameter.value); + } else { + // skip commits + await publishGit.fetchAsync(); + await publishGit.checkoutAsync(targetBranch); + await publishGit.deleteBranchAsync(tempBranch, false, !this._ignoreGitHooksParameter.value); + } + } +} diff --git a/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts b/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts new file mode 100644 index 00000000000..e41934ed1f0 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/AddAction.test.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 '../../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 { EnvironmentConfiguration } from '../../../api/EnvironmentConfiguration'; + +describe(AddAction.name, () => { + describe('basic "rush add" tests', () => { + let doRushAddMock: jest.SpyInstance; + let oldExitCode: number | string | undefined; + let oldArgs: string[]; + + beforeEach(() => { + doRushAddMock = jest + .spyOn(PackageJsonUpdater.prototype, 'doRushUpdateAsync') + .mockImplementation(() => Promise.resolve()); + jest.spyOn(process, 'exit').mockImplementation(); + + // Suppress "Another Rush command is already running" error + jest.spyOn(LockFile, 'tryAcquire').mockImplementation(() => ({}) as LockFile); + + oldExitCode = process.exitCode; + oldArgs = process.argv; + }); + + afterEach(() => { + jest.clearAllMocks(); + process.exitCode = oldExitCode; + process.argv = oldArgs; + EnvironmentConfiguration.reset(); + }); + + describe("'add' action", () => { + it(`adds a dependency to just one repo in the workspace`, async () => { + const startPath: string = `${__dirname}/addRepo`; + const aPath: string = `${__dirname}/addRepo/a`; + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); + + // Switching to the "a" package of addRepo + jest.spyOn(process, 'cwd').mockReturnValue(aPath); + + // Mock the command + process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'add', '-p', 'assert']; + + await expect(parser.executeAsync()).resolves.toEqual(true); + expect(doRushAddMock).toHaveBeenCalledTimes(1); + const doRushAddOptions: IPackageJsonUpdaterRushAddOptions = doRushAddMock.mock.calls[0][0]; + expect(doRushAddOptions.projects).toHaveLength(1); + expect(doRushAddOptions.projects[0].packageName).toEqual('a'); + expect(doRushAddOptions.packagesToUpdate).toMatchInlineSnapshot(` + Array [ + Object { + "packageName": "assert", + "rangeStyle": "tilde", + "version": undefined, + }, + ] + `); + }); + }); + + describe("'add' action with --all", () => { + it(`adds a dependency to all repos in the workspace`, async () => { + const startPath: string = `${__dirname}/addRepo`; + const aPath: string = `${__dirname}/addRepo/a`; + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); + + // Switching to the "a" package of addRepo + jest.spyOn(process, 'cwd').mockReturnValue(aPath); + + // Mock the command + process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'add', '-p', 'assert', '--all']; + + await expect(parser.executeAsync()).resolves.toEqual(true); + expect(doRushAddMock).toHaveBeenCalledTimes(1); + const doRushAddOptions: IPackageJsonUpdaterRushAddOptions = doRushAddMock.mock.calls[0][0]; + expect(doRushAddOptions.projects).toHaveLength(2); + expect(doRushAddOptions.projects[0].packageName).toEqual('a'); + expect(doRushAddOptions.projects[1].packageName).toEqual('b'); + expect(doRushAddOptions.packagesToUpdate).toMatchInlineSnapshot(` + Array [ + Object { + "packageName": "assert", + "rangeStyle": "tilde", + "version": undefined, + }, + ] + `); + }); + }); + }); +}); diff --git a/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts b/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts new file mode 100644 index 00000000000..f6a32ac87b4 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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 { EnvironmentConfiguration } from '../../../api/EnvironmentConfiguration'; + +describe(RemoveAction.name, () => { + describe('basic "rush remove" tests', () => { + let doRushRemoveMock: jest.SpyInstance; + let removeDependencyMock: jest.SpyInstance; + let oldExitCode: number | string | undefined; + let oldArgs: string[]; + + beforeEach(() => { + removeDependencyMock = jest + .spyOn(VersionMismatchFinderProject.prototype, 'removeDependency') + .mockImplementation(() => {}); + + jest.spyOn(process, 'exit').mockImplementation(); + + // Suppress "Another Rush command is already running" error + jest.spyOn(LockFile, 'tryAcquire').mockImplementation(() => ({}) as LockFile); + + oldExitCode = process.exitCode; + oldArgs = process.argv; + }); + + afterEach(() => { + jest.clearAllMocks(); + process.exitCode = oldExitCode; + process.argv = oldArgs; + EnvironmentConfiguration.reset(); + }); + + describe("'remove' action", () => { + it(`remove a dependency that is listed as both dependency of different types`, async () => { + const startPath: string = `${__dirname}/removeRepo`; + const cPath: string = `${__dirname}/removeRepo/c`; + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); + + // Switching to the "c" package of removeRepo + jest.spyOn(process, 'cwd').mockReturnValue(cPath); + + // Mock the command + process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'remove', '-p', 'assert', '-s']; + + await expect(parser.executeAsync()).resolves.toEqual(true); + expect(removeDependencyMock).toHaveBeenCalledTimes(2); + const packageName: string = removeDependencyMock.mock.calls[0][0]; + expect(packageName).toEqual('assert'); + const dependencyType1: DependencyType = removeDependencyMock.mock.calls[0][1]; + expect(dependencyType1).toEqual(DependencyType.Regular); + const dependencyType2: DependencyType = removeDependencyMock.mock.calls[1][1]; + expect(dependencyType2).toEqual(DependencyType.Dev); + }); + it(`remove a dependency to just one repo in the workspace`, async () => { + const startPath: string = `${__dirname}/removeRepo`; + const aPath: string = `${__dirname}/removeRepo/a`; + doRushRemoveMock = jest + .spyOn(PackageJsonUpdater.prototype, 'doRushUpdateAsync') + .mockImplementation(() => Promise.resolve()); + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); + + // Switching to the "a" package of removeRepo + jest.spyOn(process, 'cwd').mockReturnValue(aPath); + + // Mock the command + process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', 'remove', '-p', 'assert']; + + await expect(parser.executeAsync()).resolves.toEqual(true); + expect(doRushRemoveMock).toHaveBeenCalledTimes(1); + const doRushRemoveOptions: IPackageJsonUpdaterRushRemoveOptions = doRushRemoveMock.mock.calls[0][0]; + expect(doRushRemoveOptions.projects).toHaveLength(1); + expect(doRushRemoveOptions.projects[0].packageName).toEqual('a'); + expect(doRushRemoveOptions.packagesToUpdate).toMatchInlineSnapshot(` + Array [ + Object { + "packageName": "assert", + }, + ] + `); + }); + }); + + describe("'remove' action with --all", () => { + it(`remove a dependency from all repos in the workspace`, async () => { + const startPath: string = `${__dirname}/removeRepo`; + const aPath: string = `${__dirname}/removeRepo/a`; + + doRushRemoveMock = jest + .spyOn(PackageJsonUpdater.prototype, 'doRushUpdateAsync') + .mockImplementation(() => Promise.resolve()); + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParser = new RushCommandLineParser({ cwd: startPath }); + + // Switching to the "a" package of addRepo + jest.spyOn(process, 'cwd').mockReturnValue(aPath); + + // Mock the command + process.argv = [ + 'pretend-this-is-node.exe', + 'pretend-this-is-rush', + 'remove', + '-p', + 'assert', + '--all' + ]; + + await expect(parser.executeAsync()).resolves.toEqual(true); + expect(doRushRemoveMock).toHaveBeenCalledTimes(1); + const doRushRemoveOptions: IPackageJsonUpdaterRushRemoveOptions = doRushRemoveMock.mock.calls[0][0]; + expect(doRushRemoveOptions.projects).toHaveLength(3); + expect(doRushRemoveOptions.projects[0].packageName).toEqual('a'); + expect(doRushRemoveOptions.projects[1].packageName).toEqual('b'); + expect(doRushRemoveOptions.projects[2].packageName).toEqual('c'); + expect(doRushRemoveOptions.packagesToUpdate).toMatchInlineSnapshot(` + Array [ + Object { + "packageName": "assert", + }, + ] + `); + }); + }); + }); +}); diff --git a/libraries/rush-lib/src/cli/actions/test/addRepo/.gitignore b/libraries/rush-lib/src/cli/actions/test/addRepo/.gitignore new file mode 100644 index 00000000000..b37486fa4a9 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/addRepo/.gitignore @@ -0,0 +1 @@ +common/temp \ No newline at end of file diff --git a/apps/rush-lib/src/cli/actions/test/addRepo/a/package.json b/libraries/rush-lib/src/cli/actions/test/addRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/actions/test/addRepo/a/package.json rename to libraries/rush-lib/src/cli/actions/test/addRepo/a/package.json diff --git a/apps/rush-lib/src/cli/actions/test/addRepo/b/package.json b/libraries/rush-lib/src/cli/actions/test/addRepo/b/package.json similarity index 100% rename from apps/rush-lib/src/cli/actions/test/addRepo/b/package.json rename to libraries/rush-lib/src/cli/actions/test/addRepo/b/package.json diff --git a/apps/rush-lib/src/cli/actions/test/addRepo/rush.json b/libraries/rush-lib/src/cli/actions/test/addRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/actions/test/addRepo/rush.json rename to libraries/rush-lib/src/cli/actions/test/addRepo/rush.json diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/.gitignore b/libraries/rush-lib/src/cli/actions/test/removeRepo/.gitignore new file mode 100644 index 00000000000..6ddd556a5a2 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/removeRepo/.gitignore @@ -0,0 +1 @@ +common/temp diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/a/package.json b/libraries/rush-lib/src/cli/actions/test/removeRepo/a/package.json new file mode 100644 index 00000000000..fa82832c694 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/removeRepo/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "dependencies": { + "assert": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/b/package.json b/libraries/rush-lib/src/cli/actions/test/removeRepo/b/package.json new file mode 100644 index 00000000000..a345432fe3c --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/removeRepo/b/package.json @@ -0,0 +1,9 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "assert": "workspace:*", + "rimraf": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/c/package.json b/libraries/rush-lib/src/cli/actions/test/removeRepo/c/package.json new file mode 100644 index 00000000000..d90d05b4234 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/removeRepo/c/package.json @@ -0,0 +1,12 @@ +{ + "name": "c", + "version": "1.0.0", + "description": "Test package c", + "dependencies": { + "assert": "workspace:*", + "rimraf": "workspace:*" + }, + "devDependencies": { + "assert": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/rush.json b/libraries/rush-lib/src/cli/actions/test/removeRepo/rush.json new file mode 100644 index 00000000000..e38e0ea44b1 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/removeRepo/rush.json @@ -0,0 +1,21 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.5.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + }, + { + "packageName": "c", + "projectFolder": "c" + } + ] +} diff --git a/libraries/rush-lib/src/cli/actions/test/tabComplete/abc/package.json b/libraries/rush-lib/src/cli/actions/test/tabComplete/abc/package.json new file mode 100644 index 00000000000..f90b1417a7a --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/tabComplete/abc/package.json @@ -0,0 +1,5 @@ +{ + "name": "abc", + "version": "1.0.0", + "description": "Test package abc" +} diff --git a/libraries/rush-lib/src/cli/actions/test/tabComplete/def/package.json b/libraries/rush-lib/src/cli/actions/test/tabComplete/def/package.json new file mode 100644 index 00000000000..99a1aec27cc --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/tabComplete/def/package.json @@ -0,0 +1,5 @@ +{ + "name": "def", + "version": "1.0.0", + "description": "Test package def" +} diff --git a/libraries/rush-lib/src/cli/actions/test/tabComplete/rush.json b/libraries/rush-lib/src/cli/actions/test/tabComplete/rush.json new file mode 100644 index 00000000000..a136d8a8ea8 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/test/tabComplete/rush.json @@ -0,0 +1,17 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.5.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "abc", + "projectFolder": "abc" + }, + { + "packageName": "def", + "projectFolder": "def" + } + ] +} diff --git a/libraries/rush-lib/src/cli/parsing/ParseParallelism.ts b/libraries/rush-lib/src/cli/parsing/ParseParallelism.ts new file mode 100644 index 00000000000..5185cc70e44 --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/ParseParallelism.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 os from 'node:os'; + +/** + * Parses a command line specification for desired parallelism. + * Factored out to enable unit tests + */ +export function parseParallelism( + rawParallelism: string | undefined, + numberOfCores: number = os.availableParallelism?.() ?? 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 new file mode 100644 index 00000000000..c8d90bf1a1b --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts @@ -0,0 +1,479 @@ +// 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 { + CommandLineParameterProvider, + CommandLineStringListParameter, + CommandLineStringParameter +} from '@rushstack/ts-command-line'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { Selection } from '../../logic/Selection'; +import type { ISelectorParser as ISelectorParser } from '../../logic/selectors/ISelectorParser'; +import { + GitChangedProjectSelectorParser, + type IGitSelectorParserOptions +} from '../../logic/selectors/GitChangedProjectSelectorParser'; +import { NamedProjectSelectorParser } from '../../logic/selectors/NamedProjectSelectorParser'; +import { TagProjectSelectorParser } from '../../logic/selectors/TagProjectSelectorParser'; +import { VersionPolicyProjectSelectorParser } from '../../logic/selectors/VersionPolicyProjectSelectorParser'; +import { SubspaceSelectorParser } from '../../logic/selectors/SubspaceSelectorParser'; +import { PathProjectSelectorParser } from '../../logic/selectors/PathProjectSelectorParser'; +import type { Subspace } from '../../api/Subspace'; + +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; +} + +/** + * This class is provides the set of command line parameters used to select projects + * based on dependencies. + * + * It is a separate component such that unrelated actions can share the same parameters. + */ +export class SelectionParameterSet { + private readonly _rushConfiguration: RushConfiguration; + + private readonly _fromProject: CommandLineStringListParameter; + private readonly _impactedByProject: CommandLineStringListParameter; + private readonly _impactedByExceptProject: CommandLineStringListParameter; + private readonly _onlyProject: CommandLineStringListParameter; + private readonly _toProject: CommandLineStringListParameter; + private readonly _toExceptProject: CommandLineStringListParameter; + private readonly _subspaceParameter: CommandLineStringParameter | undefined; + + private readonly _fromVersionPolicy: CommandLineStringListParameter; + private readonly _toVersionPolicy: CommandLineStringListParameter; + + private readonly _selectorParserByScope: Map>; + + public constructor( + rushConfiguration: RushConfiguration, + action: CommandLineParameterProvider, + options: ISelectionParameterSetOptions + ) { + const { gitOptions, includeSubspaceSelector, cwd } = options; + this._rushConfiguration = rushConfiguration; + + const selectorParsers: Map> = new Map< + string, + ISelectorParser + >(); + + const nameSelectorParser: NamedProjectSelectorParser = new NamedProjectSelectorParser(rushConfiguration); + selectorParsers.set('name', nameSelectorParser); + selectorParsers.set('git', new GitChangedProjectSelectorParser(rushConfiguration, gitOptions)); + 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 getCompletionsAsync: () => Promise = async (): Promise => { + const completions: string[] = ['.']; + for (const [prefix, selector] of selectorParsers) { + for (const completion of selector.getCompletions()) { + completions.push(`${prefix}:${completion}`); + } + } + + // Include completions from the name parser without a scope + for (const completion of nameSelectorParser.getCompletions()) { + completions.push(completion); + } + + return completions; + }; + + this._toProject = action.defineStringListParameter({ + parameterLongName: '--to', + parameterShortName: '-t', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' 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".', + getCompletionsAsync + }); + this._toExceptProject = action.defineStringListParameter({ + parameterLongName: '--to-except', + parameterShortName: '-T', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' Each "--to-except" parameter expands this selection to include all dependencies of PROJECT,' + + ' 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".', + getCompletionsAsync + }); + + this._fromProject = action.defineStringListParameter({ + parameterLongName: '--from', + parameterShortName: '-f', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' Each "--from" parameter expands this selection to include PROJECT and all projects that depend on it,' + + ' 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".', + getCompletionsAsync + }); + this._onlyProject = action.defineStringListParameter({ + parameterLongName: '--only', + parameterShortName: '-o', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' Each "--only" parameter expands this selection to include PROJECT; its dependencies are not added.' + + ' "." 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".', + getCompletionsAsync + }); + + this._impactedByProject = action.defineStringListParameter({ + parameterLongName: '--impacted-by', + parameterShortName: '-i', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' Each "--impacted-by" parameter expands this selection to include PROJECT and any projects that' + + ' depend on PROJECT (and thus might be broken by changes to PROJECT).' + + ' "." 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".', + getCompletionsAsync + }); + + this._impactedByExceptProject = action.defineStringListParameter({ + parameterLongName: '--impacted-by-except', + parameterShortName: '-I', + argumentName: 'PROJECT', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' Each "--impacted-by-except" parameter works the same as "--impacted-by" except that PROJECT itself' + + ' is not added to the selection.' + + ' "." 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".', + getCompletionsAsync + }); + + this._toVersionPolicy = action.defineStringListParameter({ + parameterLongName: '--to-version-policy', + argumentName: 'VERSION_POLICY_NAME', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' The "--to-version-policy" parameter is equivalent to specifying "--to" for each of the projects' + + ' belonging to VERSION_POLICY_NAME.' + + ' For details, refer to the website article "Selecting subsets of projects".' + }); + this._fromVersionPolicy = action.defineStringListParameter({ + parameterLongName: '--from-version-policy', + argumentName: 'VERSION_POLICY_NAME', + description: + 'Normally all projects in the monorepo will be processed;' + + ' adding this parameter will instead select a subset of projects.' + + ' The "--from-version-policy" parameter is equivalent to specifying "--from" for each of the projects' + + ' belonging to VERSION_POLICY_NAME.' + + ' For details, refer to the website article "Selecting subsets of projects".' + }); + + if (includeSubspaceSelector) { + this._subspaceParameter = action.defineStringParameter({ + parameterLongName: SUBSPACE_LONG_ARG_NAME, + argumentName: 'SUBSPACE_NAME', + description: + '(EXPERIMENTAL) Specifies a Rush subspace to be installed. Requires the "subspacesEnabled" feature to be enabled in subspaces.json.' + }); + } + } + + /** + * Used to implement the `preventSelectingAllSubspaces` policy which checks for commands that accidentally + * select everything. Return `true` if the CLI was invoked with selection parameters. + * + * @remarks + * It is still possible for a user to select everything, but they must do so using an explicit selection + * such as `rush install --from thing-that-everything-depends-on`. + */ + public didUserSelectAnything(): boolean { + if (this._subspaceParameter?.value) { + return true; + } + + return [ + this._impactedByProject, + this._impactedByExceptProject, + this._onlyProject, + this._toProject, + this._fromProject, + this._toExceptProject, + this._fromVersionPolicy, + this._toVersionPolicy + ].some((x) => x.values.length > 0); + } + + /** + * Computes the set of selected projects based on all parameter values. + * + * If no parameters are specified, returns all projects in the Rush config file. + */ + public async getSelectedProjectsAsync(terminal: ITerminal): Promise> { + // Hack out the old version-policy parameters + for (const value of this._fromVersionPolicy.values) { + (this._fromProject.values as string[]).push(`version-policy:${value}`); + } + for (const value of this._toVersionPolicy.values) { + (this._toProject.values as string[]).push(`version-policy:${value}`); + } + + const selectors: CommandLineStringListParameter[] = [ + this._onlyProject, + this._fromProject, + this._toProject, + this._toExceptProject, + this._impactedByProject, + this._impactedByExceptProject + ]; + + // Check if any of the selection parameters have a value specified on the command line + const isSelectionSpecified: boolean = + selectors.some((param: CommandLineStringListParameter) => param.values.length > 0) || + !!this._subspaceParameter?.value; + + // If no selection parameters are specified, return everything + if (!isSelectionSpecified) { + return new Set(this._rushConfiguration.projects); + } + + const [ + // Include exactly these projects (--only) + onlyProjects, + // Include all projects that depend on these projects, and all dependencies thereof + fromProjects, + // --to + toRaw, + // --to-except + toExceptProjects, + // --impacted-by + impactedByProjects, + // --impacted-by-except + impactedByExceptProjects + ] = await Promise.all( + selectors.map((param: CommandLineStringListParameter) => { + return this._evaluateProjectParameterAsync(param, terminal); + }) + ); + + let subspaceProjects: Iterable = []; + + if (this._subspaceParameter?.value) { + if (!this._rushConfiguration.subspacesFeatureEnabled) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + `The "${SUBSPACE_LONG_ARG_NAME}" parameter can only be passed if "subspacesEnabled" ` + + 'is set to true in subspaces.json.' + ) + ); + throw new AlreadyReportedError(); + } + + const subspace: Subspace = this._rushConfiguration.getSubspace(this._subspaceParameter.value); + subspaceProjects = subspace.getProjects(); + } + + const selection: Set = Selection.union( + // Safe command line options + Selection.expandAllDependencies( + Selection.union( + toRaw, + Selection.directDependenciesOf(toExceptProjects), + // --from / --from-version-policy + Selection.expandAllConsumers(fromProjects) + ) + ), + subspaceProjects, + + // Unsafe command line option: --only + onlyProjects, + + // Unsafe command line options: --impacted-by, --impacted-by-except + Selection.expandAllConsumers( + Selection.union(impactedByProjects, Selection.directConsumersOf(impactedByExceptProjects)) + ) + ); + + return selection; + } + + /** + * Represents the selection as `--filter` parameters to pnpm. + * + * @remarks + * + * IMPORTANT: This function produces PNPM CLI operators that select projects from PNPM's temp workspace. + * If Rush subspaces are enabled, PNPM cannot see the complete Rush workspace, and therefore these operators + * would malfunction. In the current implementation, we calculate them anyway, then `BaseInstallAction.runAsync()` + * will overwrite `pnpmFilterArgumentValues` with a flat list of project names. In the future, these + * two code paths will be combined into a single general solution. + * + * @see https://pnpm.io/filtering + */ + public async getPnpmFilterArgumentValuesAsync(terminal: ITerminal): Promise { + const args: string[] = []; + + // Include exactly these projects (--only) + for (const project of await this._evaluateProjectParameterAsync(this._onlyProject, terminal)) { + args.push(project.packageName); + } + + // Include all projects that depend on these projects, and all dependencies thereof + const fromProjects: Set = Selection.union( + // --from + await this._evaluateProjectParameterAsync(this._fromProject, terminal) + ); + + // All specified projects and all projects that they depend on + for (const project of Selection.union( + // --to + await this._evaluateProjectParameterAsync(this._toProject, terminal), + // --from / --from-version-policy + Selection.expandAllConsumers(fromProjects) + )) { + args.push(`${project.packageName}...`); + } + + // --to-except + // All projects that the project directly or indirectly declares as a dependency + for (const project of await this._evaluateProjectParameterAsync(this._toExceptProject, terminal)) { + args.push(`${project.packageName}^...`); + } + + // --impacted-by + // The project and all projects directly or indirectly declare it as a dependency + for (const project of await this._evaluateProjectParameterAsync(this._impactedByProject, terminal)) { + args.push(`...${project.packageName}`); + } + + // --impacted-by-except + // All projects that directly or indirectly declare the specified project as a dependency + for (const project of await this._evaluateProjectParameterAsync( + this._impactedByExceptProject, + terminal + )) { + args.push(`...^${project.packageName}`); + } + + return args; + } + + /** + * Usage telemetry for selection parameters. Only saved locally, and if requested in the config. + */ + public getTelemetry(): { [key: string]: string } { + return { + command_from: `${this._fromProject.values.length > 0}`, + command_impactedBy: `${this._impactedByProject.values.length > 0}`, + command_impactedByExcept: `${this._impactedByExceptProject.values.length > 0}`, + command_only: `${this._onlyProject.values.length > 0}`, + command_to: `${this._toProject.values.length > 0}`, + command_toExcept: `${this._toExceptProject.values.length > 0}`, + + command_fromVersionPolicy: `${this._fromVersionPolicy.values.length > 0}`, + command_toVersionPolicy: `${this._toVersionPolicy.values.length > 0}` + }; + } + + /** + * Computes the referents of parameters that accept a project identifier. + * Handles '.', unscoped names, and scoped names. + */ + private async _evaluateProjectParameterAsync( + listParameter: CommandLineStringListParameter, + terminal: ITerminal + ): Promise> { + const parameterName: string = listParameter.longName; + const selection: Set = new Set(); + + for (const rawSelector of listParameter.values) { + 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 { + // Default to name: selector + scope = 'name'; + unscopedSelector = rawSelector; + } + } else { + scope = rawSelector.slice(0, scopeIndex); + unscopedSelector = rawSelector.slice(scopeIndex + 1); + } + + const handler: ISelectorParser | undefined = + this._selectorParserByScope.get(scope); + if (!handler) { + terminal.writeErrorLine( + `Unsupported selector prefix "${scope}" passed to "${parameterName}": "${rawSelector}".` + + ` Supported prefixes: ${Array.from( + this._selectorParserByScope.keys(), + (selectorParserScope: string) => `"${selectorParserScope}:"` + ).join(', ')}` + ); + throw new AlreadyReportedError(); + } + + for (const project of await handler.evaluateSelectorAsync({ + unscopedSelector, + terminal, + parameterName + })) { + selection.add(project); + } + } + + return selection; + } +} 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 new file mode 100644 index 00000000000..7d2315d3d8a --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/test/ParseParallelism.test.ts @@ -0,0 +1,19 @@ +// 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 new file mode 100644 index 00000000000..c6ee56e6310 --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/test/__snapshots__/ParseParallelism.test.ts.snap @@ -0,0 +1,5 @@ +// 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 new file mode 100644 index 00000000000..3d22215e517 --- /dev/null +++ b/libraries/rush-lib/src/cli/scriptActions/BaseScriptAction.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 { CommandLineParameter } from '@rushstack/ts-command-line'; + +import { BaseRushAction, type IBaseRushActionOptions } from '../actions/BaseRushAction'; +import type { Command, CommandLineConfiguration, IParameterJson } from '../../api/CommandLineConfiguration'; +import { defineCustomParameters } from '../parsing/defineCustomParameters'; + +/** + * Constructor parameters for BaseScriptAction + */ +export interface IBaseScriptActionOptions extends IBaseRushActionOptions { + commandLineConfiguration: CommandLineConfiguration; + command: TCommand; +} + +/** + * Base class for command-line actions that are implemented using user-defined scripts. + * + * @remarks + * Compared to the normal built-in actions, these actions are special because (1) they + * can be discovered dynamically via common/config/command-line.json, and (2) + * user-defined command-line parameters can be passed through to the script. + * + * The two subclasses are BulkScriptAction and GlobalScriptAction. + */ +export abstract class BaseScriptAction extends BaseRushAction { + protected readonly commandLineConfiguration: CommandLineConfiguration; + protected readonly customParameters: Map = new Map(); + protected readonly command: TCommand; + + public constructor(options: IBaseScriptActionOptions) { + super(options); + this.commandLineConfiguration = options.commandLineConfiguration; + this.command = options.command; + } + + protected defineScriptParameters(): void { + if (!this.commandLineConfiguration) { + return; + } + + // 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 new file mode 100644 index 00000000000..9b35156f188 --- /dev/null +++ b/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts @@ -0,0 +1,227 @@ +// 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 { AsyncSeriesHook } from 'tapable'; + +import { + FileSystem, + type IPackageJson, + JsonFile, + AlreadyReportedError, + Text +} from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import type { IGlobalCommand } from '../../pluginFramework/RushLifeCycle'; +import { BaseScriptAction, type IBaseScriptActionOptions } from './BaseScriptAction'; +import { Utilities } from '../../utilities/Utilities'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { Autoinstaller } from '../../logic/Autoinstaller'; +import type { IGlobalCommandConfig, IShellCommandTokenContext } from '../../api/CommandLineConfiguration'; +import { measureAsyncFn } from '../../utilities/performance'; + +/** + * Constructor parameters for GlobalScriptAction. + */ +export interface IGlobalScriptActionOptions extends IBaseScriptActionOptions { + shellCommand: string; + autoinstallerName: string | undefined; +} + +/** + * This class implements custom commands that are run once globally for the entire repo + * (versus bulk commands, which run separately for each project). The action executes + * a user-defined script file. + * + * @remarks + * Bulk commands can be defined via common/config/command-line.json. Rush's predefined "build" + * and "rebuild" commands are also modeled as bulk commands, because they essentially just + * invoke scripts from package.json in the same way as a custom command. + */ +export class GlobalScriptAction extends BaseScriptAction { + private readonly _shellCommand: string; + private readonly _autoinstallerName: string; + private readonly _autoinstallerFullPath: string; + + public constructor(options: IGlobalScriptActionOptions) { + super(options); + this._shellCommand = options.shellCommand; + this._autoinstallerName = options.autoinstallerName || ''; + + if (this._autoinstallerName) { + Autoinstaller.validateName(this._autoinstallerName); + + // Example: .../common/autoinstallers/my-task + this._autoinstallerFullPath = path.join( + this.rushConfiguration.commonAutoinstallersFolder, + this._autoinstallerName + ); + + if (!FileSystem.exists(this._autoinstallerFullPath)) { + throw new Error( + `The custom command "${this.actionName}" specifies an "autoinstallerName" setting` + + ' but the path does not exist: ' + + this._autoinstallerFullPath + ); + } + + // Example: .../common/autoinstallers/my-task/package.json + const packageJsonPath: string = path.join(this._autoinstallerFullPath, 'package.json'); + if (!FileSystem.exists(packageJsonPath)) { + throw new Error( + `The custom command "${this.actionName}" specifies an "autoinstallerName" setting` + + ` whose package.json file was not found: ` + + packageJsonPath + ); + } + + const packageJson: IPackageJson = JsonFile.load(packageJsonPath); + + if (packageJson.name !== this._autoinstallerName) { + throw new Error( + `The custom command "${this.actionName}" specifies an "autoinstallerName" setting,` + + ` but the package.json file's "name" field is not "${this._autoinstallerName}": ` + + packageJsonPath + ); + } + } else { + this._autoinstallerFullPath = ''; + } + + this.defineScriptParameters(); + } + + private async _prepareAutoinstallerNameAsync(): Promise { + const autoInstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName: this._autoinstallerName, + rushConfiguration: this.rushConfiguration, + rushGlobalFolder: this.rushGlobalFolder + }); + + await autoInstaller.prepareAsync(); + } + + public async runAsync(): Promise { + const { hooks: sessionHooks } = this.rushSession; + if (sessionHooks.runAnyGlobalCustomCommand.isUsed()) { + // Avoid the cost of compiling the hook if it wasn't tapped. + await sessionHooks.runAnyGlobalCustomCommand.promise(this); + } + + const hookForAction: AsyncSeriesHook | undefined = + sessionHooks.runGlobalCustomCommand.get(this.actionName); + if (hookForAction) { + // Run the more specific hook for a command with this name after the general hook + await hookForAction.promise(this); + } + + const additionalPathFolders: string[] = + this.commandLineConfiguration?.additionalPathFolders.slice() || []; + + if (this._autoinstallerName) { + await measureAsyncFn('rush:globalScriptAction:prepareAutoinstaller', () => + this._prepareAutoinstallerNameAsync() + ); + + const autoinstallerNameBinPath: string = path.join(this._autoinstallerFullPath, 'node_modules', '.bin'); + additionalPathFolders.push(autoinstallerNameBinPath); + } + + // Collect all custom parameter values + const customParameterValues: string[] = []; + for (const tsCommandLineParameter of this.customParameters.values()) { + tsCommandLineParameter.appendToArgList(customParameterValues); + } + + for (let i: number = 0; i < customParameterValues.length; i++) { + let customParameterValue: string = customParameterValues[i]; + customParameterValue = customParameterValue.replace(/"/g, '\\"'); + + if (customParameterValue.indexOf(' ') >= 0) { + customParameterValue = `"${customParameterValue}"`; + } + + customParameterValues[i] = customParameterValue; + } + + let shellCommand: string = this._shellCommand; + if (customParameterValues.length > 0) { + shellCommand += ' ' + customParameterValues.join(' '); + } + + const shellCommandTokenContext: IShellCommandTokenContext | undefined = + this.commandLineConfiguration?.shellCommandTokenContext; + if (shellCommandTokenContext) { + shellCommand = this._expandShellCommandWithTokens(shellCommand, shellCommandTokenContext); + } + this._rejectAnyTokensInShellCommand(shellCommand, shellCommandTokenContext); + + const stopwatch: Stopwatch = Stopwatch.start(); + + const exitCode: number = Utilities.executeLifecycleCommand(shellCommand, { + rushConfiguration: this.rushConfiguration, + workingDirectory: this.rushConfiguration.rushJsonFolder, + initCwd: this.rushConfiguration.commonTempFolder, + handleOutput: false, + environmentPathOptions: { + includeRepoBin: true, + additionalPathFolders: additionalPathFolders + } + }); + + process.exitCode = exitCode; + + stopwatch.stop(); + + if (this.parser.telemetry) { + this.parser.telemetry.log({ + name: this.actionName, + durationInSeconds: stopwatch.duration, + result: exitCode > 0 ? 'Failed' : 'Succeeded', + extraData: { + customParameterValue: customParameterValues.join(' ') + } + }); + + this.parser.flushTelemetry(); + } + + if (exitCode > 0) { + // eslint-disable-next-line no-console + console.log('\n' + Colorize.red(`The script failed with exit code ${exitCode}`)); + throw new AlreadyReportedError(); + } + } + + private _expandShellCommandWithTokens( + shellCommand: string, + tokenContext: IShellCommandTokenContext + ): string { + let expandedShellCommand: string = shellCommand; + for (const [token, tokenReplacement] of Object.entries(tokenContext)) { + expandedShellCommand = Text.replaceAll(expandedShellCommand, `<${token}>`, tokenReplacement); + } + return expandedShellCommand; + } + + private _rejectAnyTokensInShellCommand( + shellCommand: string, + tokenContext?: IShellCommandTokenContext + ): void { + if (shellCommand.indexOf('<') < 0 && shellCommand.indexOf('>') < 0) { + return; + } + const tokenRegExp: RegExp = /(\<[^<]*?\>)/; + const match: RegExpExecArray | null = tokenRegExp.exec(shellCommand); + if (match) { + throw new Error( + `The "shellCommand" value contains an unrecognized token "${match[1]}".${ + tokenContext ? ` Available tokens are ${Object.keys(tokenContext).join(', ')}.` : '' + }` + ); + } + throw new Error(`The "shellCommand" value contains extra token characters ("<" or ">"): ${shellCommand}`); + } +} diff --git a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts new file mode 100644 index 00000000000..b7d7ef8a692 --- /dev/null +++ b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts @@ -0,0 +1,1176 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { AsyncSeriesHook } from 'tapable'; + +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { type ITerminal, Terminal, Colorize } from '@rushstack/terminal'; +import type { + CommandLineFlagParameter, + CommandLineParameter, + CommandLineStringParameter +} from '@rushstack/ts-command-line'; + +import type { Subspace } from '../../api/Subspace'; +import type { IPhasedCommand } from '../../pluginFramework/RushLifeCycle'; +import { + PhasedCommandHooks, + type ICreateOperationsContext, + type IExecuteOperationsContext +} from '../../pluginFramework/PhasedCommandHooks'; +import { SetupChecks } from '../../logic/SetupChecks'; +import { Stopwatch, StopwatchState } from '../../utilities/Stopwatch'; +import { BaseScriptAction, type IBaseScriptActionOptions } from './BaseScriptAction'; +import { + type IOperationExecutionManagerOptions, + OperationExecutionManager +} from '../../logic/operations/OperationExecutionManager'; +import { RushConstants } from '../../logic/RushConstants'; +import { EnvironmentVariableNames } from '../../api/EnvironmentConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +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 { OperationResultSummarizerPlugin } from '../../logic/operations/OperationResultSummarizerPlugin'; +import type { ITelemetryData, ITelemetryOperationResult } from '../../logic/Telemetry'; +import { parseParallelism } from '../parsing/ParseParallelism'; +import { CobuildConfiguration } from '../../api/CobuildConfiguration'; +import { CacheableOperationPlugin } from '../../logic/operations/CacheableOperationPlugin'; +import type { IInputsSnapshot, GetInputsSnapshotAsyncFn } from '../../logic/incremental/InputsSnapshot'; +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 { DebugHashesPlugin } from '../../logic/operations/DebugHashesPlugin'; +import { measureAsyncFn, measureFn } from '../../utilities/performance'; + +const PERF_PREFIX: 'rush:phasedScriptAction' = 'rush:phasedScriptAction'; + +/** + * Constructor parameters for PhasedScriptAction. + */ +export interface IPhasedScriptActionOptions extends IBaseScriptActionOptions { + enableParallelism: boolean; + allowOversubscription: boolean; + incremental: boolean; + disableBuildCache: boolean; + + originalPhases: Set; + initialPhases: Set; + watchPhases: Set; + phases: Map; + + alwaysWatch: boolean; + alwaysInstall: boolean | undefined; + + watchDebounceMs: number | undefined; +} + +interface IInitialRunPhasesOptions { + executionManagerOptions: Omit< + IOperationExecutionManagerOptions, + 'beforeExecuteOperations' | 'inputsSnapshot' + >; + initialCreateOperationsContext: ICreateOperationsContext; + stopwatch: Stopwatch; + terminal: ITerminal; +} + +interface IRunPhasesOptions extends IInitialRunPhasesOptions { + getInputsSnapshotAsync: GetInputsSnapshotAsyncFn | undefined; + initialSnapshot: IInputsSnapshot | undefined; + executionManagerOptions: IOperationExecutionManagerOptions; +} + +interface IExecuteOperationsOptions { + executeOperationsContext: IExecuteOperationsContext; + executionManagerOptions: IOperationExecutionManagerOptions; + ignoreHooks: boolean; + operations: Set; + 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. + * + * @remarks + * Phased commands can be defined via common/config/command-line.json. Rush's predefined "build" + * 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 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; + private readonly _initialPhases: ReadonlySet; + private readonly _watchPhases: ReadonlySet; + private readonly _watchDebounceMs: number; + private readonly _alwaysWatch: boolean; + private readonly _alwaysInstall: boolean | undefined; + private readonly _knownPhases: ReadonlyMap; + private readonly _terminal: ITerminal; + private _changedProjectsOnly: boolean; + private _executionAbortController: AbortController | undefined; + + private readonly _changedProjectsOnlyParameter: CommandLineFlagParameter | undefined; + private readonly _selectionParameters: SelectionParameterSet; + private readonly _verboseParameter: CommandLineFlagParameter; + private readonly _parallelismParameter: CommandLineStringParameter | undefined; + private readonly _ignoreHooksParameter: CommandLineFlagParameter; + private readonly _watchParameter: CommandLineFlagParameter | undefined; + private readonly _timelineParameter: CommandLineFlagParameter | undefined; + private readonly _cobuildPlanParameter: CommandLineFlagParameter | undefined; + 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._allowOversubscription = options.allowOversubscription; + 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; + this._runsBeforeInstall = false; + this._knownPhases = options.phases; + this._changedProjectsOnly = false; + this.sessionAbortController = new AbortController(); + this._executionAbortController = undefined; + + this.sessionAbortController.signal.addEventListener( + 'abort', + () => { + this._executionAbortController?.abort(); + }, + { once: true } + ); + + this.hooks = new PhasedCommandHooks(); + + 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: + '(EXPERIMENTAL) Before the build starts, log information about the cobuild state. This will include information about ' + + 'clusters and the projects that are part of each cluster.' + }); + + this._selectionParameters = new SelectionParameterSet(this.rushConfiguration, this, { + gitOptions: { + // Include lockfile processing since this expands the selection, and we need to select + // at least the same projects selected with the same query to "rush build" + includeExternalDependencies: true, + // Enable filtering to reduce evaluation cost + enableFiltering: true + }, + includeSubspaceSelector: false, + cwd: this.parser.cwd + }); + + this._verboseParameter = this.defineFlagParameter({ + parameterLongName: '--verbose', + parameterShortName: '-v', + description: 'Display the logs during the build, rather than just displaying the build status summary' + }); + + 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', + description: + `Skips execution of the "eventHooks" scripts defined in ${RushConstants.rushJsonFilename}. ` + + 'Make sure you know what you are skipping.' + }); + + // 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. + 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 = 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(); + + // Associate parameters with their respective phases + associateParametersByPhase(this.customParameters, this._knownPhases); + } + + public async runAsync(): Promise { + const stopwatch: Stopwatch = Stopwatch.start(); + + if (this._alwaysInstall || this._installParameter?.value) { + 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 + }); + }); + } + + if (!this._runsBeforeInstall) { + 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( + 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"?'); + } + } + }); + } + + 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 + ? parseParallelism(this._parallelismParameter?.value) + : 1; + + const includePhaseDeps: boolean = this._includePhaseDeps?.value ?? false; + + 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); + + new WeightedOperationPlugin().apply(hooks); + new ValidateOperationsPlugin(terminal).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 diagnosticDir: string | undefined = this._nodeDiagnosticDirParameter.value; + if (diagnosticDir) { + new NodeDiagnosticDirPlugin({ + diagnosticDir + }).apply(this.hooks); + } + + // Enable the standard summary + new OperationResultSummarizerPlugin(terminal).apply(this.hooks); + }); + + const { hooks: sessionHooks } = this.rushSession; + if (sessionHooks.runAnyPhasedCommand.isUsed()) { + 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( + this.actionName + ); + + if (hookForAction) { + 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._changedProjectsOnlyParameter?.value; + this._changedProjectsOnly = changedProjectsOnly; + + let buildCacheConfiguration: BuildCacheConfiguration | undefined; + let cobuildConfiguration: CobuildConfiguration | undefined; + if (!this._disableBuildCache) { + 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) + ]); + if (cobuildConfiguration) { + await cobuildConfiguration.createLockProviderAsync(terminal); + } + }); + } + + try { + const projectSelection: Set = await measureAsyncFn( + `${PERF_PREFIX}:getSelectedProjects`, + () => this._selectionParameters.getSelectedProjectsAsync(terminal) + ); + + if (!projectSelection.size) { + terminal.writeLine( + Colorize.yellow(`The command line selection parameters did not match any projects.`) + ); + return; + } + + const customParametersByName: Map = new Map(); + for (const [configParameter, parserParameter] of this.customParameters) { + customParametersByName.set(configParameter.longName, parserParameter); + } + + const isWatch: boolean = this._watchParameter?.value || this._alwaysWatch; + + await measureAsyncFn(`${PERF_PREFIX}:applySituationalPlugins`, async () => { + if (isWatch && this._noIPCParameter?.value === false) { + new ( + await import( + /* webpackChunkName: 'IPCOperationRunnerPlugin' */ '../../logic/operations/IPCOperationRunnerPlugin' + ) + ).IPCOperationRunnerPlugin().apply(this.hooks); + } + + if (buildCacheConfiguration?.buildCacheEnabled) { + terminal.writeVerboseLine(`Incremental strategy: cache restoration`); + new CacheableOperationPlugin({ + allowWarningsInSuccessfulBuild: + !!this.rushConfiguration.experimentsConfiguration.configuration + .buildCacheWithAllowWarningsInSuccessfulBuild, + buildCacheConfiguration, + cobuildConfiguration, + terminal + }).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: + 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; + + 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 { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; + if (this.rushConfiguration?.isPnpm && experiments?.usePnpmSyncForInjectedDependencies) { + const { PnpmSyncCopyOperationPlugin } = await import( + '../../logic/operations/PnpmSyncCopyOperationPlugin' + ); + new PnpmSyncCopyOperationPlugin(terminal).apply(this.hooks); + } + }); + + const relevantProjects: Set = + Selection.expandAllDependencies(projectSelection); + + const projectConfigurations: ReadonlyMap = this + ._runsBeforeInstall + ? new Map() + : await measureAsyncFn(`${PERF_PREFIX}:loadProjectConfigurations`, () => + RushProjectConfiguration.tryLoadForProjectsAsync(relevantProjects, terminal) + ); + + const initialCreateOperationsContext: ICreateOperationsContext = { + buildCacheConfiguration, + changedProjectsOnly, + cobuildConfiguration, + customParameters: customParametersByName, + isIncrementalBuildAllowed: this._isIncrementalBuildAllowed, + isInitial: true, + isWatch, + rushConfiguration: this.rushConfiguration, + parallelism, + phaseOriginal: new Set(this._originalPhases), + phaseSelection: new Set(this._initialPhases), + includePhaseDeps, + projectSelection, + projectConfigurations, + projectsInUnknownState: projectSelection + }; + + const executionManagerOptions: Omit< + IOperationExecutionManagerOptions, + 'beforeExecuteOperations' | 'inputsSnapshot' + > = { + quietMode: isQuietMode, + debugMode: this.parser.isDebug, + parallelism, + allowOversubscription: this._allowOversubscription, + beforeExecuteOperationAsync: async (record: OperationExecutionRecord) => { + return await this.hooks.beforeExecuteOperation.promise(record); + }, + afterExecuteOperationAsync: async (record: OperationExecutionRecord) => { + await this.hooks.afterExecuteOperation.promise(record); + }, + createEnvironmentForOperation: this.hooks.createEnvironmentForOperation.isUsed() + ? (record: OperationExecutionRecord) => { + return this.hooks.createEnvironmentForOperation.call({ ...process.env }, record); + } + : undefined, + onOperationStatusChangedAsync: (record: OperationExecutionRecord) => { + this.hooks.onOperationStatusChanged.call(record); + } + }; + + const initialInternalOptions: IInitialRunPhasesOptions = { + initialCreateOperationsContext, + executionManagerOptions, + stopwatch, + terminal + }; + + const internalOptions: IRunPhasesOptions = await measureAsyncFn(`${PERF_PREFIX}:runInitialPhases`, () => + this._runInitialPhasesAsync(initialInternalOptions) + ); + + if (isWatch) { + if (buildCacheConfiguration) { + // Cache writes are not supported during watch mode, only reads. + buildCacheConfiguration.cacheWriteEnabled = false; + } + + await this._runWatchPhasesAsync(internalOptions); + terminal.writeDebugLine(`Watch mode exited.`); + } + } finally { + if (cobuildConfiguration) { + 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 measureAsyncFn(`${PERF_PREFIX}:createOperations`, () => + this.hooks.createOperations.promise(new Set(), initialCreateOperationsContext) + ); + + 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 + Selection.expandAllDependencies(projectSelection) + ); + const innerInitialSnapshot: IInputsSnapshot | undefined = innerGetInputsSnapshotAsync + ? await innerGetInputsSnapshotAsync() + : undefined; + + repoStateStopwatch.stop(); + terminal.writeLine(`DONE (${repoStateStopwatch.toString()})`); + terminal.writeLine(); + return [innerGetInputsSnapshotAsync, innerInitialSnapshot]; + } + ); + + const abortController: AbortController = (this._executionAbortController = new AbortController()); + const initialExecuteOperationsContext: IExecuteOperationsContext = { + ...initialCreateOperationsContext, + inputsSnapshot: initialSnapshot, + abortController + }; + + const executionManagerOptions: IOperationExecutionManagerOptions = { + ...partialExecutionManagerOptions, + inputsSnapshot: initialSnapshot, + beforeExecuteOperationsAsync: async (records: Map) => { + await measureAsyncFn(`${PERF_PREFIX}:beforeExecuteOperations`, () => + this.hooks.beforeExecuteOperations.promise(records, initialExecuteOperationsContext) + ); + } + }; + + const initialOptions: IExecuteOperationsOptions = { + executeOperationsContext: initialExecuteOperationsContext, + ignoreHooks: false, + operations, + stopwatch, + executionManagerOptions, + terminal + }; + + await measureAsyncFn(`${PERF_PREFIX}:executeOperations`, () => + this._executeOperationsAsync(initialOptions) + ); + + return { + ...options, + executionManagerOptions, + getInputsSnapshotAsync, + initialSnapshot + }; + } + + private _registerWatchModeInterface(projectWatcher: ProjectWatcher): void { + const buildOnceKey: 'b' = 'b'; + const changedProjectsOnlyKey: 'c' = 'c'; + const invalidateKey: 'i' = 'i'; + const quitKey: 'q' = 'q'; + const abortKey: 'a' = 'a'; + const toggleWatcherKey: 'w' = 'w'; + const shutdownProcessesKey: 'x' = 'x'; + + const terminal: ITerminal = this._terminal; + + projectWatcher.setPromptGenerator((isPaused: boolean) => { + const promptLines: string[] = [ + ` Press <${quitKey}> to gracefully exit.`, + ` Press <${abortKey}> to abort queued operations. Any that have started will finish.`, + ` Press <${toggleWatcherKey}> to ${isPaused ? 'resume' : 'pause'}.`, + ` Press <${invalidateKey}> to invalidate all projects.`, + ` Press <${changedProjectsOnlyKey}> to ${ + this._changedProjectsOnly ? 'disable' : 'enable' + } changed-projects-only mode (${this._changedProjectsOnly ? 'ENABLED' : 'DISABLED'}).` + ]; + if (isPaused) { + promptLines.push(` Press <${buildOnceKey}> to build once.`); + } + if (this._noIPCParameter?.value === false) { + promptLines.push(` Press <${shutdownProcessesKey}> to reset child processes.`); + } + return promptLines; + }); + + const onKeyPress = (key: string): void => { + switch (key) { + case quitKey: + terminal.writeLine(`Exiting watch mode and aborting any scheduled work...`); + process.stdin.setRawMode(false); + process.stdin.off('data', onKeyPress); + process.stdin.unref(); + this.sessionAbortController.abort(); + break; + case abortKey: + terminal.writeLine(`Aborting current iteration...`); + this._executionAbortController?.abort(); + break; + 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 changedProjectsOnlyKey: + this._changedProjectsOnly = !this._changedProjectsOnly; + projectWatcher.rerenderStatus(); + break; + case shutdownProcessesKey: + 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.stdin.setRawMode(false); + process.stdin.off('data', onKeyPress); + process.stdin.unref(); + this.sessionAbortController.abort(); + process.kill(process.pid, 'SIGINT'); + break; + } + }; + + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', onKeyPress); + } + + /** + * 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 sessionAbortController: AbortController = this.sessionAbortController; + const abortSignal: AbortSignal = sessionAbortController.signal; + + const projectWatcher: typeof ProjectWatcher.prototype = new ProjectWatcher({ + getInputsSnapshotAsync, + initialSnapshot, + debounceMs: this._watchDebounceMs, + rushConfiguration: this.rushConfiguration, + projectsToWatch, + abortSignal, + 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(); + + // 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; + // 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})`); + } + + // Loop until Ctrl+C + while (!abortSignal.aborted) { + // On the initial invocation, this promise will return immediately with the full set of projects + const { changedProjects, inputsSnapshot: state } = await measureAsyncFn( + `${PERF_PREFIX}:waitForChanges`, + () => projectWatcher.waitForChangeAsync(onWaitingForChanges) + ); + + if (abortSignal.aborted) { + return; + } + + 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(); + } + + 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)}`); + } + + const initialAbortController: AbortController = (this._executionAbortController = + new AbortController()); + + // Account for consumer relationships + const executeOperationsContext: IExecuteOperationsContext = { + ...initialCreateOperationsContext, + abortController: initialAbortController, + changedProjectsOnly: !!this._changedProjectsOnly, + isInitial: false, + inputsSnapshot: state, + projectsInUnknownState: changedProjects, + phaseOriginal, + phaseSelection, + invalidateOperation + }; + + const operations: Set = await measureAsyncFn(`${PERF_PREFIX}:createOperations`, () => + this.hooks.createOperations.promise(new Set(), executeOperationsContext) + ); + + const executeOptions: IExecuteOperationsOptions = { + executeOperationsContext, + // For now, don't run pre-build or post-build in watch mode + ignoreHooks: true, + operations, + stopwatch, + executionManagerOptions: { + ...executionManagerOptions, + inputsSnapshot: state, + beforeExecuteOperationsAsync: async (records: Map) => { + await measureAsyncFn(`${PERF_PREFIX}:beforeExecuteOperations`, () => + this.hooks.beforeExecuteOperations.promise(records, executeOperationsContext) + ); + } + }, + terminal + }; + + try { + // Delegate the the underlying command, for only the projects that need reprocessing + await measureAsyncFn(`${PERF_PREFIX}:executeOperations`, () => + this._executeOperationsAsync(executeOptions) + ); + } catch (err) { + // In watch mode, we want to rebuild even if the original build failed. + if (!(err instanceof AlreadyReportedError)) { + throw err; + } + } + } + } + + /** + * Runs a set of operations and reports the results. + */ + private async _executeOperationsAsync(options: IExecuteOperationsOptions): Promise { + const { + executeOperationsContext, + executionManagerOptions, + ignoreHooks, + operations, + stopwatch, + terminal + } = options; + + const executionManager: OperationExecutionManager = new OperationExecutionManager( + operations, + executionManagerOptions + ); + + const { isInitial, isWatch, abortController, invalidateOperation } = executeOperationsContext; + + let success: boolean = false; + let result: IExecutionResult | undefined; + + try { + const definiteResult: IExecutionResult = await measureAsyncFn( + `${PERF_PREFIX}:executeOperationsInner`, + () => executionManager.executeAsync(abortController) + ); + success = definiteResult.status === OperationStatus.Success; + result = definiteResult; + + await measureAsyncFn(`${PERF_PREFIX}:afterExecuteOperations`, () => + this.hooks.afterExecuteOperations.promise(definiteResult, executeOperationsContext) + ); + + stopwatch.stop(); + + const message: string = `rush ${this.actionName} (${stopwatch.toString()})`; + if (result.status === OperationStatus.Success) { + terminal.writeLine(Colorize.green(message)); + } else { + terminal.writeLine(message); + } + } catch (error) { + success = false; + stopwatch.stop(); + + if (error instanceof AlreadyReportedError) { + terminal.writeLine(`rush ${this.actionName} (${stopwatch.toString()})`); + } else { + if (error && (error as Error).message) { + if (this.parser.isDebug) { + terminal.writeErrorLine('Error: ' + (error as Error).stack); + } else { + terminal.writeErrorLine('Error: ' + (error as Error).message); + } + } + + terminal.writeErrorLine(Colorize.red(`rush ${this.actionName} - Errors! (${stopwatch.toString()})`)); + } + } + + this._executionAbortController = undefined; + + if (invalidateOperation) { + const operationResults: ReadonlyMap | undefined = + result?.operationResults; + if (operationResults) { + for (const [operation, { status }] of operationResults) { + if (status === OperationStatus.Aborted) { + invalidateOperation(operation, 'aborted'); + } + } + } + } + + if (!ignoreHooks) { + measureFn(`${PERF_PREFIX}:doAfterTask`, () => this._doAfterTask()); + } + + if (this.parser.telemetry) { + const logEntry: ITelemetryData = measureFn(`${PERF_PREFIX}:prepareTelemetry`, () => { + 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 + }; + + const { _changedProjectsOnlyParameter: changedProjectsOnlyParameter } = this; + if (changedProjectsOnlyParameter) { + // Overwrite this value since we allow changing it at runtime. + extraData[changedProjectsOnlyParameter.scopedLongName ?? changedProjectsOnlyParameter.longName] = + this._changedProjectsOnly; + } + + 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 { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; + + 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; + default: + // Do nothing. + break; + } + } + } + + const innerLogEntry: ITelemetryData = { + name: this.actionName, + durationInSeconds: stopwatch.duration, + result: success ? 'Succeeded' : 'Failed', + extraData, + operationResults: jsonOperationResults + }; + + return innerLogEntry; + }); + + measureFn(`${PERF_PREFIX}:beforeLog`, () => this.hooks.beforeLog.call(logEntry)); + + this.parser.telemetry.log(logEntry); + + this.parser.flushTelemetry(); + } + + if (!success && !isWatch) { + throw new AlreadyReportedError(); + } + } + + private _doBeforeTask(): void { + if ( + this.actionName !== RushConstants.buildCommandName && + this.actionName !== RushConstants.rebuildCommandName + ) { + // Only collects information for built-in commands like build or rebuild. + return; + } + + SetupChecks.validate(this.rushConfiguration); + + this.eventHooksManager.handle(Event.preRushBuild, this.parser.isDebug, this._ignoreHooksParameter.value); + } + + private _doAfterTask(): void { + if ( + this.actionName !== RushConstants.buildCommandName && + this.actionName !== RushConstants.rebuildCommandName + ) { + // Only collects information for built-in commands like build or rebuild. + return; + } + this.eventHooksManager.handle(Event.postRushBuild, this.parser.isDebug, this._ignoreHooksParameter.value); + } +} diff --git a/libraries/rush-lib/src/cli/test/.gitignore b/libraries/rush-lib/src/cli/test/.gitignore new file mode 100644 index 00000000000..b45aba78534 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/.gitignore @@ -0,0 +1,2 @@ +*/common/temp +*/*/.rush/temp diff --git a/libraries/rush-lib/src/cli/test/Cli.test.ts b/libraries/rush-lib/src/cli/test/Cli.test.ts new file mode 100644 index 00000000000..51a89ca7d8c --- /dev/null +++ b/libraries/rush-lib/src/cli/test/Cli.test.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 * as path from 'node:path'; + +import { Utilities } from '../../utilities/Utilities'; + +// Increase the timeout since this command spawns child processes +jest.setTimeout(10000); + +describe('CLI', () => { + it('should not fail when there is no rush.json', async () => { + const workingDir: string = '/'; + const startPath: string = path.resolve(__dirname, '../../../lib-commonjs/start.js'); + + await expect( + Utilities.executeCommandAsync({ + command: 'node', + args: [startPath], + workingDirectory: workingDir, + suppressOutput: true + }) + ).resolves.not.toThrow(); + }); + + it('rushx should pass args to scripts', async () => { + // Invoke "rushx" + 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 lastLine: string = + output + .split(/\s*\n\s*/) + .filter((x) => x) + .pop() || ''; + expect(lastLine).toEqual('build.js: ARGS=["1","2","-x"]'); + }); + + it('rushx should fail in un-rush project', async () => { + // 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` + ); + + expect(output).toEqual( + expect.stringMatching( + 'Warning: You are invoking "rushx" inside a Rush repository, but this project is not registered in rush.json.' + ) + ); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts b/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts new file mode 100644 index 00000000000..78ce4ee8557 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/CommandLineHelp.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 { AnsiEscape } from '@rushstack/terminal'; + +import { RushCommandLineParser } from '../RushCommandLineParser'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; + +describe('CommandLineHelp', () => { + let oldCwd: string | undefined; + + let parser: RushCommandLineParser; + + beforeEach(() => { + // ts-command-line calls process.exit() which interferes with Jest + jest.spyOn(process, 'exit').mockImplementation((code) => { + throw new Error(`Test code called process.exit(${code})`); + }); + + oldCwd = process.cwd(); + const localCwd: string = `${__dirname}/repo`; + + process.chdir(localCwd); + + // This call may terminate the entire test run because it invokes process.exit() + // if it encounters errors. + // TODO Remove the calls to process.exit() or override them for testing. + parser = new RushCommandLineParser(); + // eslint-disable-next-line no-console + parser.executeAsync().catch(console.error); + }); + + afterEach(() => { + if (oldCwd) { + process.chdir(oldCwd); + } + + EnvironmentConfiguration.reset(); + }); + + it('prints the global help', () => { + const helpText: string = AnsiEscape.formatForTests(parser.renderHelpText()); + expect(helpText).toMatchSnapshot(); + }); + + it(`prints the help for each action`, () => { + for (const action of parser.actions) { + const helpText: string = AnsiEscape.formatForTests(action.renderHelpText()); + expect(helpText).toMatchSnapshot(action.actionName); + } + }); +}); diff --git a/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts b/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts new file mode 100644 index 00000000000..02da1daeac7 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts @@ -0,0 +1,499 @@ +// 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']]) + }; + }, + getRepoChangesAsync(): ReadonlyMap { + return new Map(); + }, + 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])); + } + }; +}); + +import './mockRushCommandLineParser'; + +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 { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; + +function pathEquals(actual: string, expected: string): void { + expect(Path.convertToSlashes(actual)).toEqual(Path.convertToSlashes(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; + +describe('RushCommandLineParser', () => { + describe('execute', () => { + afterEach(() => { + jest.clearAllMocks(); + EnvironmentConfiguration.reset(); + jest + .spyOn(EnvironmentConfiguration, 'buildCacheOverrideJsonFilePath', 'get') + .mockReturnValue(undefined); + jest.spyOn(EnvironmentConfiguration, 'buildCacheOverrideJson', 'get').mockReturnValue(undefined); + }); + + describe('in basic repo', () => { + describe("'build' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'basicAndRunBuildActionRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + 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/; + + // 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`); + + // 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`); + }); + }); + + describe("'rebuild' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'basicAndRunRebuildActionRepo'; + 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/; + + // 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`); + + // 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`); + }); + }); + }); + + describe("in repo with 'rebuild' command overridden", () => { + describe("'build' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'overrideRebuildAndRunBuildActionRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + 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/; + + // 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`); + + // 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`); + }); + }); + + describe("'rebuild' action", () => { + it(`executes the package's 'rebuild' script`, async () => { + const repoName: string = 'overrideRebuildAndRunRebuildActionRepo'; + 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/; + + // 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`); + + // 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`); + }); + }); + }); + + describe("in repo with 'rebuild' or 'build' partially set", () => { + describe("'build' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'overrideAndDefaultBuildActionRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'build'); + 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/; + + // 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`); + + // 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`); + }); + }); + + describe("'rebuild' action", () => { + it(`executes the package's 'build' script`, async () => { + // broken + const repoName: string = 'overrideAndDefaultRebuildActionRepo'; + 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/; + + // 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`); + + // 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`); + }); + }); + }); + + describe("in repo with 'build' command overridden as a global command", () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'overrideBuildAsGlobalCommandRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"command-line.json defines a command \\"build\\" using the command kind \\"global\\". This command can only be designated as a command kind \\"bulk\\" or \\"phased\\"."` + ); + }); + }); + + describe("in repo with 'rebuild' command overridden as a global command", () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'overrideRebuildAsGlobalCommandRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"command-line.json defines a command \\"rebuild\\" using the command kind \\"global\\". This command can only be designated as a command kind \\"bulk\\" or \\"phased\\"."` + ); + }); + }); + + describe("in repo with 'build' command overridden with 'safeForSimultaneousRushProcesses=true'", () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'overrideBuildWithSimultaneousProcessesRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"command-line.json defines a command \\"build\\" using \\"safeForSimultaneousRushProcesses=true\\". This configuration is not supported for \\"build\\"."` + ); + }); + }); + + describe("in repo with 'rebuild' command overridden with 'safeForSimultaneousRushProcesses=true'", () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'overrideRebuildWithSimultaneousProcessesRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"command-line.json defines a command \\"rebuild\\" using \\"safeForSimultaneousRushProcesses=true\\". This configuration is not supported for \\"rebuild\\"."` + ); + }); + }); + + describe('in repo plugin custom flushTelemetry', () => { + it('creates a custom telemetry file', async () => { + const repoName: string = 'tapFlushTelemetryAndRunBuildActionRepo'; + const { parser } = await getCommandLineParserInstanceAsync(repoName, 'build'); + const telemetryFilePath: string = `${parser.rushConfiguration.commonTempFolder}/test-telemetry.json`; + FileSystem.deleteFile(telemetryFilePath); + + /** + * 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); + + expect(FileSystem.exists(telemetryFilePath)).toEqual(true); + + const telemetryStore: ITelemetryData[] = await JsonFile.loadAsync(telemetryFilePath); + expect(telemetryStore?.[0].name).toEqual('build'); + expect(telemetryStore?.[0].result).toEqual('Succeeded'); + }); + }); + + 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/; + + // 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`); + + // 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`); + }); + }); + + 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/; + + // 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`); + + // 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`); + }); + }); + }); + + 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/; + + // 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`); + + // 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`); + }); + }); + + 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/; + + // 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`); + + // 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`); + }); + }); + }); + + 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 new file mode 100644 index 00000000000..a5a671afef3 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushCommandLineParserFailureCases.test.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. + +// Mock child_process so we can verify tasks are (or are not) invoked as we expect +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; + }, + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: new Map() + }; + }, + getRepoChangesAsync(): ReadonlyMap { + return new Map(); + } + }; +}); + +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'; + +describe('RushCommandLineParserFailureCases', () => { + describe('execute', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('in repo plugin custom flushTelemetry', () => { + it('custom telemetry reports errors', async () => { + const repoName: string = 'tapFlushTelemetryAndRunBuildActionRepo'; + + // WARNING: This test case needs the real implementation of _reportErrorAndSetExitCode. + // As a result, process.exit needs to be explicitly mocked to prevent the test runner from exiting. + const procProm = new Promise((resolve, reject) => { + jest.spyOn(process, 'exit').mockImplementation((() => { + resolve(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }) as any); + }); + + const { parser } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + const telemetryFilePath: string = `${parser.rushConfiguration.commonTempFolder}/test-telemetry.json`; + FileSystem.deleteFile(telemetryFilePath); + + jest.spyOn(Autoinstaller.prototype, 'prepareAsync').mockImplementation(async function () {}); + + setSpawnMock({ emitError: false, returnCode: 1 }); + await parser.executeAsync(); + await procProm; + expect(process.exit).toHaveBeenCalledWith(1); + + expect(FileSystem.exists(telemetryFilePath)).toEqual(true); + + const telemetryStore: ITelemetryData[] = JsonFile.load(telemetryFilePath); + expect(telemetryStore?.[0].name).toEqual('build'); + expect(telemetryStore?.[0].result).toEqual('Failed'); + }); + }); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts b/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts new file mode 100644 index 00000000000..04c968f136d --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import './mockRushCommandLineParser'; + +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; + let currentCWD: string | undefined; + + let _argv: string[]; + + const repoName = 'pluginCommandLineParametersRepo'; + const pluginName = 'rush-command-parameters-plugin'; + const mockRepoPath = path.resolve(__dirname, repoName); + const autoinstallerRootPath = path.resolve(mockRepoPath, 'common/autoinstallers/plugins'); + + const mockProcessArgv = (argv: string[]): void => { + _argv = process.argv; + process.argv = [...argv]; + }; + + const mockAutoInstallerInstallation = (): void => { + jest.spyOn(Autoinstaller.prototype, 'prepareAsync').mockImplementation(async function () {}); + + const realPluginPath = path.resolve(mockRepoPath, pluginName); + const autoinstallerPluginPath = path.resolve(autoinstallerRootPath, 'node_modules', pluginName); + if (!FileSystem.exists(autoinstallerPluginPath)) { + FileSystem.copyFiles({ + sourcePath: realPluginPath, + destinationPath: autoinstallerPluginPath + }); + } + }; + + beforeAll(() => { + // Ignore issues with parallel Rush processes + jest.spyOn(LockFile, 'tryAcquire').mockImplementation(() => { + return {} as LockFile; + }); + }); + + beforeEach(() => { + // ts-command-line calls process.exit() which interferes with Jest + jest.spyOn(process, 'exit').mockImplementation((code) => { + throw new Error(`Test code called process.exit(${code})`); + }); + + originCWD = process.cwd(); + currentCWD = `${__dirname}/pluginCommandLineParametersRepo`; + process.chdir(currentCWD); + }); + + afterEach(() => { + if (originCWD) { + process.chdir(originCWD); + originCWD = undefined; + process.argv = _argv; + } + + EnvironmentConfiguration.reset(); + }); + + afterAll(() => { + FileSystem.deleteFolder(path.resolve(autoinstallerRootPath, 'node_modules')); + jest.restoreAllMocks(); + }); + + it('should parse string parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv(['fake-node', 'fake-rush', 'cmd-parameters-test', '--mystring', '123']); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + + expect(action?.getStringParameter('--mystring').value).toStrictEqual('123'); + }); + + it('should parse integer parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv(['fake-node', 'fake-rush', 'cmd-parameters-test', '--myinteger', '1']); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + + expect(action?.getIntegerParameter('--myinteger').value).toStrictEqual(1); + }); + + it('should parse flag parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv(['fake-node', 'fake-rush', 'cmd-parameters-test', '--myflag']); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + + expect(action?.getFlagParameter('--myflag').value).toStrictEqual(true); + }); + + it('should parse choice parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv(['fake-node', 'fake-rush', 'cmd-parameters-test', '--mychoice', 'a']); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + + expect(action?.getChoiceParameter('--mychoice').value).toStrictEqual('a'); + }); + + it('should parse string list parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv([ + 'fake-node', + 'fake-rush', + 'cmd-parameters-test', + '--mystringlist', + 'str1', + '--mystringlist', + 'str2' + ]); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + + expect(action?.getStringListParameter('--mystringlist').values).toStrictEqual(['str1', 'str2']); + }); + + it('should parse integer list parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv([ + 'fake-node', + 'fake-rush', + 'cmd-parameters-test', + '--myintegerlist', + '1', + '--myintegerlist', + '2' + ]); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + expect(action?.getIntegerListParameter('--myintegerlist').values).toStrictEqual([1, 2]); + }); + + it('should parse choice list parameters correctly', async () => { + mockAutoInstallerInstallation(); + mockProcessArgv([ + 'fake-node', + 'fake-rush', + 'cmd-parameters-test', + '--mychoicelist', + 'a', + '--mychoicelist', + 'c' + ]); + const parser = new RushCommandLineParser({ cwd: currentCWD }); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + const action = parser.actions.find((ac) => ac.actionName === 'cmd-parameters-test'); + expect(action?.getChoiceListParameter('--mychoicelist').values).toStrictEqual(['a', 'c']); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts b/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts new file mode 100644 index 00000000000..0bb398c4698 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushXCommandLine.test.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. + +jest.mock('../../logic/dotenv', () => ({ + initializeDotEnv: () => {} +})); + +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +import { Utilities } from '../../utilities/Utilities'; +import { Rush, type ILaunchOptions } from '../../api/Rush'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { NodeJsCompatibility } from '../../logic/NodeJsCompatibility'; + +import { RushXCommandLine } from '../RushXCommandLine'; + +describe(RushXCommandLine.name, () => { + let $argv: string[]; + let $versions: NodeJS.ProcessVersions; + let executeLifecycleCommandMock: jest.SpyInstance | undefined; + let logMock: jest.SpyInstance | undefined; + let rushConfiguration: RushConfiguration | undefined; + + beforeEach(() => { + // Mock process + $argv = process.argv; + process.argv = [...process.argv]; + $versions = process.versions; + Object.defineProperty(process, 'versions', { + value: { ...process.versions, node: '12.12.12' } + }); + jest.spyOn(process, 'cwd').mockReturnValue('/Users/jdoe/bigrepo/apps/acme'); + + // Mock rush version + jest.spyOn(Rush, 'version', 'get').mockReturnValue('40.40.40'); + + // Mock package.json + jest + .spyOn(PackageJsonLookup.prototype, 'tryGetPackageJsonFilePathFor') + .mockReturnValue('apps/acme/package.json'); + jest.spyOn(PackageJsonLookup.prototype, 'loadPackageJson').mockReturnValueOnce({ + name: '@acme/acme', + version: '0.0.1', + scripts: { + build: 'an acme project build command', + test: 'an acme project test command' + } + }); + + // Mock rush configuration + const projects: RushConfigurationProject[] = [ + { + packageName: '@acme/acme', + projectFolder: '/Users/jdoe/bigrepo/apps/acme', + projectRelativeFolder: 'apps/acme' + } as RushConfigurationProject + ]; + rushConfiguration = { + commonRushConfigFolder: '', + rushJsonFolder: '', + commonTempFolder: 'common/temp', + projects, + tryGetProjectForPath(path: string): RushConfigurationProject | undefined { + return projects.find((project) => project.projectFolder === path); + } + } as RushConfiguration; + jest.spyOn(RushConfiguration, 'tryFindRushJsonLocation').mockReturnValue('/Users/jdoe/bigrepo'); + jest.spyOn(RushConfiguration, 'loadFromConfigurationFile').mockReturnValue(rushConfiguration); + + // Mock command execution + executeLifecycleCommandMock = jest.spyOn(Utilities, 'executeLifecycleCommand'); + + // Mock console log + logMock = jest.spyOn(console, 'log'); + + jest.spyOn(NodeJsCompatibility, 'isLtsVersion', 'get').mockReturnValue(true); + }); + + afterEach(() => { + process.argv = $argv; + Object.defineProperty(process, 'versions', { + value: $versions + }); + executeLifecycleCommandMock = undefined; + logMock = undefined; + rushConfiguration = undefined; + jest.restoreAllMocks(); + }); + + describe(RushXCommandLine.launchRushXAsync.name, () => { + it('prints usage info', () => { + process.argv = ['node', 'startx.js', '--help']; + executeLifecycleCommandMock!.mockReturnValue(0); + + Rush.launchRushX('0.0.0', true as unknown as ILaunchOptions); + + expect(executeLifecycleCommandMock).not.toHaveBeenCalled(); + expect(logMock!.mock.calls).toMatchSnapshot(); + }); + + it('executes a valid package script', () => { + process.argv = ['node', 'startx.js', 'build']; + executeLifecycleCommandMock!.mockReturnValue(0); + + Rush.launchRushX('0.0.0', true as unknown as ILaunchOptions); + + expect(executeLifecycleCommandMock).toHaveBeenCalledWith('an acme project build command', { + rushConfiguration, + workingDirectory: 'apps/acme', + initCwd: 'common/temp', + handleOutput: false, + environmentPathOptions: { + includeProjectBin: true + } + }); + expect(logMock!.mock.calls).toMatchSnapshot(); + }); + + it('executes a valid package script with no startup banner', () => { + process.argv = ['node', 'startx.js', '--quiet', 'build']; + executeLifecycleCommandMock!.mockReturnValue(0); + + Rush.launchRushX('0.0.0', { isManaged: true }); + + expect(executeLifecycleCommandMock).toHaveBeenCalledWith('an acme project build command', { + rushConfiguration, + workingDirectory: 'apps/acme', + initCwd: 'common/temp', + handleOutput: false, + environmentPathOptions: { + includeProjectBin: true + } + }); + expect(logMock!.mock.calls).toMatchSnapshot(); + }); + + it('fails if the package does not contain a matching script', () => { + process.argv = ['node', 'startx.js', 'asdf']; + executeLifecycleCommandMock!.mockReturnValue(0); + + Rush.launchRushX('0.0.0', { isManaged: true }); + + expect(executeLifecycleCommandMock).not.toHaveBeenCalled(); + expect(logMock!.mock.calls).toMatchSnapshot(); + }); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/TestUtils.ts b/libraries/rush-lib/src/cli/test/TestUtils.ts new file mode 100644 index 00000000000..e4534498d00 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/TestUtils.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 { 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'; + +/** + * Interface definition for a test instance for the RushCommandLineParser. + */ +export interface IParserTestInstance { + parser: RushCommandLineParserType; + spawnMock: jest.Mock; + repoPath: string; +} + +/** + * See `./mock_child_process`. + */ +export interface ISpawnMockConfig { + emitError: boolean; + returnCode: number; +} + +export interface IChildProcessModuleMock { + /** + * Initialize the `spawn` mock behavior. + */ + __setSpawnMockConfig(config?: ISpawnMockConfig): void; + + spawn: jest.Mock; +} + +/** + * Configure the `child_process` `spawn` mock for these tests. This relies on the mock implementation + * in `mock_child_process`. + */ +export function setSpawnMock(options?: ISpawnMockConfig): jest.Mock { + const cpMocked: IChildProcessModuleMock = require('node:child_process'); + cpMocked.__setSpawnMockConfig(options); + + const spawnMock: jest.Mock = cpMocked.spawn; + spawnMock.mockName('spawn'); + return spawnMock; +} + +const PROJECT_ROOT: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; +export const TEST_REPO_FOLDER_PATH: string = `${PROJECT_ROOT}/temp/test/unit-test-repos`; + +/** + * Helper to set up a test instance for RushCommandLineParser. + */ +export async function getCommandLineParserInstanceAsync( + repoName: string, + taskName: string +): Promise { + // Copy the test repo to a sandbox folder + const repoPath: string = `${TEST_REPO_FOLDER_PATH}/${repoName}-${performance.now()}`; + + await FileSystem.copyFilesAsync({ + sourcePath: `${__dirname}/${repoName}`, + destinationPath: repoPath, + alreadyExistsBehavior: AlreadyExistsBehavior.Error + }); + + // The `build` task is hard-coded to be incremental. So delete the package-deps file folder in + // the test repo to guarantee the test actually runs. + await Promise.all([ + FileSystem.deleteFolderAsync(`${repoPath}/a/.rush/temp`), + FileSystem.deleteFolderAsync(`${repoPath}/b/.rush/temp`) + ]); + + const { RushCommandLineParser } = await import('../RushCommandLineParser'); + + // Create a Rush CLI instance. This instance is heavy-weight and relies on setting process.exit + // to exit and clear the Rush file lock. So running multiple `it` or `describe` test blocks over the same test + // repo will fail due to contention over the same lock which is kept until the test runner process + // ends. + const parser: RushCommandLineParserType = new RushCommandLineParser({ cwd: repoPath }); + + // Bulk tasks are hard-coded to expect install to have been completed. So, ensure the last-link.flag + // file exists and is valid + await new FlagFile( + parser.rushConfiguration.defaultSubspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ).createAsync(); + + // Mock the command + process.argv = ['pretend-this-is-node.exe', 'pretend-this-is-rush', taskName]; + const spawnMock: jest.Mock = setSpawnMock(); + + return { + parser, + spawnMock, + repoPath + }; +} 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 new file mode 100644 index 00000000000..df9d2c0a674 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap @@ -0,0 +1,1542 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommandLineHelp prints the global help 1`] = ` +"usage: rush [-h] [-d] [-q] ... + +Rush makes life easier for JavaScript developers who develop, build, and +publish many packages from a central Git repo. It is designed to handle very +large repositories supporting many projects and people. Rush provides +policies, protections, and customizations that help coordinate teams and +safely onboard new contributors. Rush also generates change logs and +automates package publishing. It can manage decoupled subsets of projects +with different release and versioning strategies. A full API is included to +facilitate integration with other automation tools. If you are looking for a +proven turnkey solution for monorepo management, Rush is for you. + +Positional arguments: + + add Adds one or more dependencies to the package.json and + runs rush update. + change Records changes made to projects, indicating how the + package version number should be bumped for the next + publish. + check Checks each project's package.json files and ensures + that all dependencies are of the same version + throughout the repository. + deploy Prepares a deployment by copying a subset of Rush + projects and their dependencies to a target folder + init Initializes a new repository to be managed by Rush + init-autoinstaller Initializes a new autoinstaller + init-deploy Creates a deployment scenario config file for use + with \\"rush deploy\\". + init-subspace Create a new subspace. + install Install package dependencies for all projects in the + repo according to the shrinkwrap file + link Create node_modules symlinks for all projects + list List package information for all projects in the repo + publish Reads and processes package publishing change + requests generated by \\"rush change\\". + purge For diagnostic purposes, use this command to delete + caches and other temporary files used by Rush + remove Removes one or more dependencies from the package. + json and runs rush update. + scan When migrating projects into a Rush repo, this + command is helpful for detecting undeclared + dependencies. + setup (EXPERIMENTAL) Invoke this command before working in + a new repo to ensure that any required prerequisites + are installed and permissions are configured. + unlink Delete node_modules symlinks for all projects in the + repo + update Install package dependencies for all projects in the + repo, and create or update the shrinkwrap file as + needed + install-autoinstaller + Install autoinstaller package dependencies + update-autoinstaller + Updates autoinstaller package dependencies + update-cloud-credentials + (EXPERIMENTAL) Update the credentials used by the + build cache provider. + upgrade-interactive + Provides interactive prompt for upgrading package + dependencies per project + 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 + changed since they were last built. + rebuild Clean and rebuild the entire set of projects. + tab-complete Provides tab completion. + +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 + -q, --quiet Hide rush startup information + +[bold]For detailed help about a specific command, use: rush -h[normal] +" +`; + +exports[`CommandLineHelp prints the help for each action: add 1`] = ` +"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 +determined by the current working directory) 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. + +Optional arguments: + -h, --help Show this help message and exit. + -s, --skip-update If specified, the \\"rush update\\" command will not be + run after updating the package.json files. + -p PACKAGE, --package PACKAGE + 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\\". + --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). + --caret If specified, the SemVer specifier added to the + package.json will be a prepended with a \\"caret\\" + specifier (\\"^\\"). + --dev If specified, the package will be added to the + \\"devDependencies\\" section of the package.json + --peer If specified, the package will be added to the + \\"peerDependencies\\" section of the package.json + -m, --make-consistent + If specified, other packages with this dependency + will have their package.json files updated to use the + same version of the dependency. +" +`; + +exports[`CommandLineHelp prints the help for each action: alert 1`] = ` +"usage: rush alert [-h] [-s ALERT_ID] [--forever] + +This command displays the Rush alerts for this repository. Rush alerts are +customizable announcements and reminders that Rush prints occasionally on the +command line. The alert definitions can be found in the rush-alerts.json +config file. + +Optional arguments: + -h, --help Show this help message and exit. + -s ALERT_ID, --snooze ALERT_ID + Temporarily suspend the specified alert for one week + --forever Combined with \\"--snooze\\", causes that alert to be + suspended permanently +" +`; + +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] + [--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 +an incremental build. In other words, it only builds projects whose source +files have changed since the last successful build. The analysis requires a +Git working tree, and only considers source files that are tracked by Git and +whose path is under the project folder. (For more details about this +algorithm, see the documentation for the \\"package-deps-hash\\" NPM package.) +The incremental build state is tracked in a per-project folder called \\". +rush/temp\\" which should NOT be added to Git. The build command is tracked by +the \\"arguments\\" field in the \\"package-deps_build.json\\" file contained +therein; a full rebuild is forced whenever the command has changed (e.g. +\\"--production\\" or not). + +Optional arguments: + -h, --help Show this help message and exit. + -p COUNT, --parallelism COUNT + 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 parameter may + alternatively be specified via the RUSH_PARALLELISM + environment variable. + --timeline 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. + --log-cobuild-plan (EXPERIMENTAL) Before the build starts, log + information about the cobuild state. This will + include information about clusters and the projects + that are part of each cluster. + -t PROJECT, --to PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. 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\\". + -T PROJECT, --to-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--to-except\\" parameter + expands this selection to include all dependencies of + PROJECT, 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\\". + -f PROJECT, --from PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--from\\" parameter expands + this selection to include PROJECT and all projects + that depend on it, 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\\". + -o PROJECT, --only PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--only\\" parameter expands + this selection to include PROJECT; its dependencies + are not added. \\".\\" 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\\". + -i PROJECT, --impacted-by PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by\\" parameter + expands this selection to include PROJECT and any + projects that depend on PROJECT (and thus might be + broken by changes to PROJECT). \\".\\" 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\\". + -I PROJECT, --impacted-by-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by-except\\" + parameter works the same as \\"--impacted-by\\" except + that PROJECT itself is not added to the selection. \\". + \\" 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\\". + --to-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--to-version-policy\\" + parameter is equivalent to specifying \\"--to\\" for each + of the projects belonging to VERSION_POLICY_NAME. For + details, refer to the website article \\"Selecting + subsets of projects\\". + --from-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--from-version-policy\\" + parameter is equivalent to specifying \\"--from\\" for + each of the projects belonging to VERSION_POLICY_NAME. + For details, refer to the website article \\"Selecting + 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 + 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. + --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 + such as unit tests and linting +" +`; + +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}] + + +Asks a series of questions and then generates a -.json +file in the common folder. The \`publish\` command will consume these files and +perform the proper version bumps. Note these changes will eventually be +published in a changelog.md file in each package. The possible types of +changes are: MAJOR - these are breaking changes that are not backwards +compatible. Examples are: renaming a public class, adding/removing a +non-optional parameter from a public API, or renaming an variable or function +that is exported. MINOR - these are changes that are backwards compatible +(but not forwards compatible). Examples are: adding a new public API or +adding an optional parameter to a public API PATCH - these are changes that +are backwards and forwards compatible. Examples are: Modifying a private API +or fixing a bug in the logic of how an existing API works. NONE - these are +changes that are backwards and forwards compatible and don't require an +immediate release. Examples are: Modifying dev tooling configuration like +eslint. HOTFIX (EXPERIMENTAL) - these are changes that are hotfixes targeting +a specific older version of the package. When a hotfix change is added, other +changes will not be able to increment the version number. Enable this feature +by setting 'hotfixChangeEnabled' in your rush.json. + +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 + --no-fetch Skips fetching the baseline branch before running + \\"git diff\\" to detect changes. + -b BRANCH, --target-branch BRANCH + If this parameter is specified, compare the checked + out branch with the specified branch to determine + which projects were changed. If this parameter is not + specified, the checked out branch is compared against + the \\"main\\" branch. + --overwrite If a changefile already exists, overwrite without + prompting (or erroring in --bulk mode). + -c, --commit If this flag is specified generated changefiles will + be commited automatically. + --commit-message COMMIT_MESSAGE + If this parameter is specified generated changefiles + will be commited automatically with the specified + commit message. + --email EMAIL The email address to use in changefiles. If this + parameter is not provided, the email address will be + detected or prompted for in interactive mode. + --bulk If this flag is specified, apply the same change + message and bump type to all changed projects. The + --message and the --bump-type parameters must be + specified if the --bulk parameter is specified + --message MESSAGE The message to apply to all changed projects if the + --bulk flag is provided. + --bump-type {major,minor,patch,none} + The bump type to apply to all changed projects if the + --bulk flag is provided. +" +`; + +exports[`CommandLineHelp prints the help for each action: check 1`] = ` +"usage: rush check [-h] [--json] [--verbose] [--subspace SUBSPACE_NAME] + [--variant VARIANT] + + +Checks each project's package.json files and ensures that all dependencies +are of the same version throughout the repository. + +Optional arguments: + -h, --help Show this help message and exit. + --json If this flag is specified, output will be in JSON + format. + --verbose If this flag is specified, long lists of package + names will not be truncated. This has no effect if + the --json flag is also specified. + --subspace SUBSPACE_NAME + (EXPERIMENTAL) Specifies an individual Rush subspace + to check, requiring versions to be consistent only + within that subspace (ignoring other subspaces). This + parameter is required when the \\"subspacesEnabled\\" + setting is set to true in subspaces.json. + --variant VARIANT Run command using a variant installation + configuration. This parameter may alternatively be + specified via the RUSH_VARIANT environment variable. +" +`; + +exports[`CommandLineHelp prints the help for each action: deploy 1`] = ` +"usage: rush deploy [-h] [-p PROJECT_NAME] [-s SCENARIO_NAME] [--overwrite] + [-t PATH] [--create-archive ARCHIVE_PATH] + [--create-archive-only] + + +After building the repo, \\"rush deploy\\" can be used to prepare a deployment by +copying a subset of Rush projects and their dependencies to a target folder, +which can then be uploaded to a production server. The \\"rush deploy\\" behavior +is specified by a scenario config file that must be created first, using the +\\"rush init-deploy\\" command. + +Optional arguments: + -h, --help Show this help message and exit. + -p PROJECT_NAME, --project PROJECT_NAME + Specifies the name of the main Rush project to be + deployed. It must appear in the + \\"deploymentProjectNames\\" setting in the deployment + config file. + -s SCENARIO_NAME, --scenario SCENARIO_NAME + By default, the deployment configuration is specified + in \\"common/config/rush/deploy.json\\". You can use + \\"--scenario\\" to specify an alternate name. The name + must be lowercase and separated by dashes. For + example, if SCENARIO_NAME is \\"web\\", then the config + file would be \\"common/config/rush/deploy-web.json\\". + --overwrite By default, deployment will fail if the target folder + is not empty. SPECIFYING THIS FLAG WILL RECURSIVELY + DELETE EXISTING CONTENTS OF THE TARGET FOLDER. + -t PATH, --target-folder PATH + By default, files are deployed to the \\"common/deploy\\" + folder inside the Rush repo. Use this parameter to + specify a different location. WARNING: USE CAUTION + WHEN COMBINING WITH \\"--overwrite\\". This parameter may + alternatively be specified via the + RUSH_DEPLOY_TARGET_FOLDER environment variable. + --create-archive ARCHIVE_PATH + If specified, after the deployment has been prepared, + \\"rush deploy\\" will create an archive containing the + contents of the target folder. The newly created + archive file will be placed according to the + designated path, relative to the target folder. + Supported file extensions: .zip + --create-archive-only + If specified, \\"rush deploy\\" will only create an + archive containing the contents of the target folder. + The target folder will not be modified other than to + create the archive file. +" +`; + +exports[`CommandLineHelp prints the help for each action: import-strings 1`] = ` +"usage: rush import-strings [-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] + [--include-phase-deps] [--ignore-hooks] + [--node-diagnostic-dir DIRECTORY] + [--debug-build-cache-ids] + [--locale {en-us,fr-fr,es-es,zh-cn}] + + +Requests translated strings from the translation service and imports them +into each project. + +Optional arguments: + -h, --help Show this help message and exit. + -p COUNT, --parallelism COUNT + 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 parameter may + alternatively be specified via the RUSH_PARALLELISM + environment variable. + --timeline 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. + --log-cobuild-plan (EXPERIMENTAL) Before the build starts, log + information about the cobuild state. This will + include information about clusters and the projects + that are part of each cluster. + -t PROJECT, --to PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. 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\\". + -T PROJECT, --to-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--to-except\\" parameter + expands this selection to include all dependencies of + PROJECT, 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\\". + -f PROJECT, --from PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--from\\" parameter expands + this selection to include PROJECT and all projects + that depend on it, 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\\". + -o PROJECT, --only PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--only\\" parameter expands + this selection to include PROJECT; its dependencies + are not added. \\".\\" 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\\". + -i PROJECT, --impacted-by PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by\\" parameter + expands this selection to include PROJECT and any + projects that depend on PROJECT (and thus might be + broken by changes to PROJECT). \\".\\" 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\\". + -I PROJECT, --impacted-by-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by-except\\" + parameter works the same as \\"--impacted-by\\" except + that PROJECT itself is not added to the selection. \\". + \\" 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\\". + --to-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--to-version-policy\\" + parameter is equivalent to specifying \\"--to\\" for each + of the projects belonging to VERSION_POLICY_NAME. For + details, refer to the website article \\"Selecting + subsets of projects\\". + --from-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--from-version-policy\\" + parameter is equivalent to specifying \\"--from\\" for + each of the projects belonging to VERSION_POLICY_NAME. + For details, refer to the website article \\"Selecting + 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 + builds. +" +`; + +exports[`CommandLineHelp prints the help for each action: init 1`] = ` +"usage: rush init [-h] [--overwrite-existing] [--rush-example-repo] + [--include-experiments] + + +When invoked in an empty folder, this command provisions a standard set of +config file templates to start managing projects using Rush. + +Optional arguments: + -h, --help Show this help message and exit. + --overwrite-existing By default \\"rush init\\" will not overwrite existing + config files. Specify this switch to override that. + This can be useful when upgrading your repo to a + newer release of Rush. WARNING: USE WITH CARE! + --rush-example-repo When copying the template config files, this + uncomments fragments that are used by the + \\"rush-example\\" GitHub repo, which is a sample + monorepo that illustrates many Rush features. This + option is primarily intended for maintaining that + example. + --include-experiments + Include features that may not be complete features, + useful for demoing specific future features or + current work in progress features. +" +`; + +exports[`CommandLineHelp prints the help for each action: init-autoinstaller 1`] = ` +"usage: rush init-autoinstaller [-h] --name AUTOINSTALLER_NAME + +Use this command to initialize a new autoinstaller folder. Autoinstallers +provide a way to manage a set of related dependencies that are used for +scripting scenarios outside of the usual \\"rush install\\" context. See the +command-line.json documentation for an example. + +Optional arguments: + -h, --help Show this help message and exit. + --name AUTOINSTALLER_NAME + Specifies the name of the autoinstaller folder, which + must conform to the naming rules for NPM packages. +" +`; + +exports[`CommandLineHelp prints the help for each action: init-deploy 1`] = ` +"usage: rush init-deploy [-h] -p PROJECT_NAME [-s SCENARIO] + +Use this command to initialize a new scenario config file for use with \\"rush +deploy\\". The default filename is common/config/rush/deploy.json. However, if +you need to manage multiple deployments with different settings, you can use +use \\"--scenario\\" to create additional config files. + +Optional arguments: + -h, --help Show this help message and exit. + -p PROJECT_NAME, --project PROJECT_NAME + Specifies the name of the main Rush project to be + deployed in this scenario. It will be added to the + \\"deploymentProjectNames\\" setting. + -s SCENARIO, --scenario SCENARIO + By default, the deployment configuration will be + written to \\"common/config/rush/deploy.json\\". You can + use \\"--scenario\\" to specify an alternate name. The + name must be lowercase and separated by dashes. For + example, if the name is \\"web\\", then the config file + would be \\"common/config/rush/deploy-web.json\\". +" +`; + +exports[`CommandLineHelp prints the help for each action: init-subspace 1`] = ` +"usage: rush init-subspace [-h] -n SUBSPACE_NAME + +Use this command to create a new subspace with the default subspace +configuration files. + +Optional arguments: + -h, --help Show this help message and exit. + -n SUBSPACE_NAME, --name SUBSPACE_NAME + The name of the subspace that is being initialized. +" +`; + +exports[`CommandLineHelp prints the help for each action: install 1`] = ` +"usage: rush install [-h] [-p] [--bypass-policy] [--no-link] + [--network-concurrency COUNT] [--debug-package-manager] + [--max-install-attempts NUMBER] [--ignore-hooks] + [--offline] [--variant VARIANT] [-t PROJECT] [-T PROJECT] + [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] + [--to-version-policy VERSION_POLICY_NAME] + [--from-version-policy VERSION_POLICY_NAME] + [--subspace SUBSPACE_NAME] [--check-only] + [--resolution-only] + + +The \\"rush install\\" command installs package dependencies for all your +projects, based on the shrinkwrap file that is created/updated using \\"rush +update\\". (This \\"shrinkwrap\\" file stores a central inventory of all +dependencies and versions for projects in your repo. It is found in the +\\"common/config/rush\\" folder.) If the shrinkwrap file is missing or outdated +(e.g. because project package.json files have changed), \\"rush install\\" will +fail and tell you to run \\"rush update\\" instead. This read-only nature is the +main feature: Continuous integration builds should use \\"rush install\\" instead +of \\"rush update\\" to catch developers who forgot to commit their shrinkwrap +changes. Cautious people can also use \\"rush install\\" if they want to avoid +accidentally updating their shrinkwrap file. + +Optional arguments: + -h, --help Show this help message and exit. + -p, --purge Perform \\"rush purge\\" before starting the installation + --bypass-policy Overrides enforcement of the \\"gitPolicy\\" rules from + rush.json (use honorably!) + --no-link If \\"--no-link\\" is specified, then project symlinks + will NOT be created after the installation completes. + You will need to run \\"rush link\\" manually. This flag + is useful for automated builds that want to report + stages individually or perform extra operations in + between the two stages. This flag is not supported + when using workspaces. + --network-concurrency COUNT + If specified, limits the maximum number of concurrent + network requests. This is useful when troubleshooting + network failures. + --debug-package-manager + Activates verbose logging for the package manager. + You will probably want to pipe the output of Rush to + a file when using this command. + --max-install-attempts NUMBER + Overrides the default maximum number of install + attempts. The default value is 1. + --ignore-hooks Skips execution of the \\"eventHooks\\" scripts defined + in rush.json. Make sure you know what you are + skipping. + --offline Enables installation to be performed without internet + access. PNPM will instead report an error if the + necessary NPM packages cannot be obtained from the + local cache. For details, see the documentation for + PNPM's \\"--offline\\" parameter. + --variant VARIANT Run command using a variant installation + configuration. This parameter may alternatively be + specified via the RUSH_VARIANT environment variable. + -t PROJECT, --to PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. 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\\". + -T PROJECT, --to-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--to-except\\" parameter + expands this selection to include all dependencies of + PROJECT, 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\\". + -f PROJECT, --from PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--from\\" parameter expands + this selection to include PROJECT and all projects + that depend on it, 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\\". + -o PROJECT, --only PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--only\\" parameter expands + this selection to include PROJECT; its dependencies + are not added. \\".\\" 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\\". + -i PROJECT, --impacted-by PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by\\" parameter + expands this selection to include PROJECT and any + projects that depend on PROJECT (and thus might be + broken by changes to PROJECT). \\".\\" 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\\". + -I PROJECT, --impacted-by-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by-except\\" + parameter works the same as \\"--impacted-by\\" except + that PROJECT itself is not added to the selection. \\". + \\" 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\\". + --to-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--to-version-policy\\" + parameter is equivalent to specifying \\"--to\\" for each + of the projects belonging to VERSION_POLICY_NAME. For + details, refer to the website article \\"Selecting + subsets of projects\\". + --from-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--from-version-policy\\" + parameter is equivalent to specifying \\"--from\\" for + each of the projects belonging to VERSION_POLICY_NAME. + For details, refer to the website article \\"Selecting + subsets of projects\\". + --subspace SUBSPACE_NAME + (EXPERIMENTAL) Specifies a Rush subspace to be + installed. Requires the \\"subspacesEnabled\\" feature to + be enabled in subspaces.json. + --check-only Only check the validity of the shrinkwrap file + without performing an install. + --resolution-only Only perform dependency resolution, useful for + ensuring peer dependendencies are up to date. Note + that this flag is only supported when using the pnpm + package manager. +" +`; + +exports[`CommandLineHelp prints the help for each action: install-autoinstaller 1`] = ` +"usage: rush install-autoinstaller [-h] --name AUTOINSTALLER_NAME + +Use this command to install dependencies for an autoinstaller folder. + +Optional arguments: + -h, --help Show this help message and exit. + --name AUTOINSTALLER_NAME + The name of the autoinstaller, which must be one of + the folders under common/autoinstallers. +" +`; + +exports[`CommandLineHelp prints the help for each action: link 1`] = ` +"usage: rush link [-h] [-f] + +Create node_modules symlinks for all projects. This operation is normally +performed automatically as part of \\"rush install\\" or \\"rush update\\". You +should only need to use \\"rush link\\" if you performed \\"rush unlink\\" for some +reason, or if you specified the \\"--no-link\\" option for \\"rush install\\" or +\\"rush update\\". + +Optional arguments: + -h, --help Show this help message and exit. + -f, --force Deletes and recreates all links, even if the filesystem state + seems to indicate that this is unnecessary. +" +`; + +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] + [-i PROJECT] [-I PROJECT] + [--to-version-policy VERSION_POLICY_NAME] + [--from-version-policy VERSION_POLICY_NAME] + + +List package names, and optionally version (--version) and path (--path) or +full path (--full-path), for projects in the current rush config. + +Optional arguments: + -h, --help Show this help message and exit. + -v, --version If this flag is specified, the project version will + be displayed in a column along with the package name. + -p, --path If this flag is specified, the project path will be + displayed in a column along with the package name. + --full-path If this flag is specified, the project full path will + be displayed in a column along with the package name. + --detailed For the non --json view, if this flag is specified, + include path (-p), version (-v) columns along with + the project's applicable: versionPolicy, + versionPolicyName, shouldPublish, reviewPolicy, and + tags fields. + --json If this flag is specified, output will be in JSON + format. + -t PROJECT, --to PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. 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\\". + -T PROJECT, --to-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--to-except\\" parameter + expands this selection to include all dependencies of + PROJECT, 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\\". + -f PROJECT, --from PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--from\\" parameter expands + this selection to include PROJECT and all projects + that depend on it, 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\\". + -o PROJECT, --only PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--only\\" parameter expands + this selection to include PROJECT; its dependencies + are not added. \\".\\" 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\\". + -i PROJECT, --impacted-by PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by\\" parameter + expands this selection to include PROJECT and any + projects that depend on PROJECT (and thus might be + broken by changes to PROJECT). \\".\\" 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\\". + -I PROJECT, --impacted-by-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by-except\\" + parameter works the same as \\"--impacted-by\\" except + that PROJECT itself is not added to the selection. \\". + \\" 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\\". + --to-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--to-version-policy\\" + parameter is equivalent to specifying \\"--to\\" for each + of the projects belonging to VERSION_POLICY_NAME. For + details, refer to the website article \\"Selecting + subsets of projects\\". + --from-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--from-version-policy\\" + parameter is equivalent to specifying \\"--from\\" for + each of the projects belonging to VERSION_POLICY_NAME. + For details, refer to the website article \\"Selecting + subsets of projects\\". +" +`; + +exports[`CommandLineHelp prints the help for each action: publish 1`] = ` +"usage: rush publish [-h] [-a] [-b BRANCH] [-p] [--add-commit-details] + [--regenerate-changelogs] [-r REGISTRY] [-n TOKEN] + [-t TAG] [--set-access-level {public,restricted}] [--pack] + [--release-folder FOLDER] [--include-all] + [--version-policy POLICY] [--prerelease-name NAME] + [--partial-prerelease] [--suffix SUFFIX] [--force] + [--apply-git-tags-on-pack] [-c COMMIT_ID] + [--ignore-git-hooks] + + +Reads and processes package publishing change requests generated by \\"rush +change\\". This will perform a 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. + +Optional arguments: + -h, --help Show this help message and exit. + -a, --apply If this flag is specified, the change requests will + be applied to package.json files. + -b BRANCH, --target-branch BRANCH + If this flag is specified, applied changes and + deleted change requests will be committed and merged + into the target branch. + -p, --publish If this flag is specified, applied changes will be + published to the NPM registry. + --add-commit-details Adds commit author and hash to the changelog.json + files for each change. + --regenerate-changelogs + Regenerates all changelog files based on the current + JSON content. + -r REGISTRY, --registry REGISTRY + Publishes to a specified NPM registry. If this is + specified, it will prevent the current commit will + not be tagged. + -n TOKEN, --npm-auth-token TOKEN + (DEPRECATED) Specifies the authentication token to + use during publishing. This parameter is deprecated + because command line parameters may be readable by + unrelated processes on a lab machine. Instead, a + safer practice is to pass the token via an + environment variable and reference it from your + common/config/rush/.npmrc-publish file. + -t TAG, --tag TAG The tag option to pass to npm publish. By default NPM + will publish using the 'latest' tag, even if the + package is older than the current latest, so in + publishing workflows for older releases, providing a + tag is important. When hotfix changes are made, this + parameter defaults to 'hotfix'. + --set-access-level {public,restricted} + By default, when Rush invokes \\"npm publish\\" it will + publish scoped packages with an access level of + \\"restricted\\". Scoped packages can be published with + an access level of \\"public\\" by specifying that value + for this flag with the initial publication. NPM + always publishes unscoped packages with an access + level of \\"public\\". For more information, see the NPM + documentation for the \\"--access\\" option of \\"npm + publish\\". + --pack Packs projects into tarballs instead of publishing to + npm repository. It can only be used when + --include-all is specified. If this flag is specified, + NPM registry related parameters will be ignored. + --release-folder FOLDER + This parameter is used with --pack parameter to + provide customized location for the tarballs instead + of the default value. + --include-all If this flag is specified, all packages with + shouldPublish=true in rush.json or with a specified + version policy will be published if their version is + newer than published version. + --version-policy POLICY + Version policy name. Only projects with this version + policy will be published if used with --include-all. + --prerelease-name NAME + Bump up to a prerelease version with the provided + prerelease name. Cannot be used with --suffix + --partial-prerelease Used with --prerelease-name. Only bump packages to a + prerelease version if they have changes. + --suffix SUFFIX Append a suffix to all changed versions. Cannot be + used with --prerelease-name. + --force If this flag is specified with --publish, packages + will be published with --force on npm + --apply-git-tags-on-pack + If specified with --publish and --pack, git tags will + be applied for packages as if a publish was being run + without --pack. + -c COMMIT_ID, --commit COMMIT_ID + Used in conjunction with git tagging -- apply git + tags at the commit hash specified. If not provided, + the current HEAD will be tagged. + --ignore-git-hooks Skips execution of all git hooks. Make sure you know + what you are skipping. +" +`; + +exports[`CommandLineHelp prints the help for each action: purge 1`] = ` +"usage: rush purge [-h] [--unsafe] + +The \\"rush purge\\" command is used to delete temporary files created by Rush. +This is useful if you are having problems and suspect that cache files may be +corrupt. + +Optional arguments: + -h, --help Show this help message and exit. + --unsafe (UNSAFE!) Also delete shared files such as the package manager + instances stored in the \\".rush\\" folder in the user's home + directory. This is a more aggressive fix that is NOT SAFE to + run in a live environment because it will cause other + concurrent Rush processes to fail. +" +`; + +exports[`CommandLineHelp prints the help for each action: rebuild 1`] = ` +"usage: rush rebuild [-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] + [--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 +\\"scripts\\" entry for \\"npm run build\\" that performs a full clean build. Rush +invokes this script to build each project that is registered in rush.json. +Projects are built in parallel where possible, but always respecting the +dependency graph for locally linked projects. The number of simultaneous +processes will be based on the number of machine cores unless overridden by +the --parallelism flag. (For an incremental build, see \\"rush build\\" instead +of \\"rush rebuild\\".) + +Optional arguments: + -h, --help Show this help message and exit. + -p COUNT, --parallelism COUNT + 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 parameter may + alternatively be specified via the RUSH_PARALLELISM + environment variable. + --timeline 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. + --log-cobuild-plan (EXPERIMENTAL) Before the build starts, log + information about the cobuild state. This will + include information about clusters and the projects + that are part of each cluster. + -t PROJECT, --to PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. 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\\". + -T PROJECT, --to-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--to-except\\" parameter + expands this selection to include all dependencies of + PROJECT, 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\\". + -f PROJECT, --from PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--from\\" parameter expands + this selection to include PROJECT and all projects + that depend on it, 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\\". + -o PROJECT, --only PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--only\\" parameter expands + this selection to include PROJECT; its dependencies + are not added. \\".\\" 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\\". + -i PROJECT, --impacted-by PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by\\" parameter + expands this selection to include PROJECT and any + projects that depend on PROJECT (and thus might be + broken by changes to PROJECT). \\".\\" 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\\". + -I PROJECT, --impacted-by-except PROJECT + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. Each \\"--impacted-by-except\\" + parameter works the same as \\"--impacted-by\\" except + that PROJECT itself is not added to the selection. \\". + \\" 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\\". + --to-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--to-version-policy\\" + parameter is equivalent to specifying \\"--to\\" for each + of the projects belonging to VERSION_POLICY_NAME. For + details, refer to the website article \\"Selecting + subsets of projects\\". + --from-version-policy VERSION_POLICY_NAME + Normally all projects in the monorepo will be + processed; adding this parameter will instead select + a subset of projects. The \\"--from-version-policy\\" + parameter is equivalent to specifying \\"--from\\" for + each of the projects belonging to VERSION_POLICY_NAME. + For details, refer to the website article \\"Selecting + 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 + such as unit tests and linting +" +`; + +exports[`CommandLineHelp prints the help for each action: remove 1`] = ` +"usage: rush remove [-h] [-s] -p PACKAGE [--all] [--variant VARIANT] + +Removes specified package(s) from the dependencies of the current project (as +determined by the current working directory) and then runs \\"rush update\\". + +Optional arguments: + -h, --help Show this help message and exit. + -s, --skip-update If specified, the \\"rush update\\" command will not be + run after updating the package.json files. + -p PACKAGE, --package PACKAGE + The name of the package which should be removed. To + remove multiple packages, run \\"rush remove --package + foo --package bar\\". + --all If specified, the dependency will be removed from all + projects that declare it. + --variant VARIANT Run command using a variant installation + configuration. This parameter may alternatively be + specified via the RUSH_VARIANT environment variable. +" +`; + +exports[`CommandLineHelp prints the help for each action: scan 1`] = ` +"usage: rush scan [-h] [--json] [--all] + +The Node.js module system allows a project to import NPM packages without +explicitly declaring them as dependencies in the package.json file. Such +\\"phantom dependencies\\" can cause problems. Rush and PNPM use symlinks +specifically to protect against phantom dependencies. These protections may +cause runtime errors for existing projects when they are first migrated into +a Rush monorepo. The \\"rush scan\\" command is a handy tool for fixing these +errors. It scans the \\"./src\\" and \\"./lib\\" folders for import syntaxes such as +\\"import __ from '__'\\", \\"require('__')\\", and \\"System.import('__'). It prints a +report of the referenced packages. This heuristic is not perfect, but it can +save a lot of time when migrating projects. + +Optional arguments: + -h, --help Show this help message and exit. + --json If this flag is specified, output will be in JSON format. + --all If this flag is specified, output will list all detected + dependencies. +" +`; + +exports[`CommandLineHelp prints the help for each action: setup 1`] = ` +"usage: rush setup [-h] + +(EXPERIMENTAL) Invoke this command before working in a new repo to ensure +that any required prerequisites are installed and permissions are configured. +The initial implementation configures the NPM registry credentials. More +features will be added later. + +Optional arguments: + -h, --help Show this help message and exit. +" +`; + +exports[`CommandLineHelp prints the help for each action: tab-complete 1`] = ` +"usage: rush tab-complete [-h] [--word WORD] [--position INDEX] + +Provides tab completion. + +Optional arguments: + -h, --help Show this help message and exit. + --word WORD The word to complete. The default value is \\"\\". + --position INDEX The position in the word to be completed. The default + value is 0. +" +`; + +exports[`CommandLineHelp prints the help for each action: unlink 1`] = ` +"usage: rush unlink [-h] + +This removes the symlinks created by the \\"rush link\\" command. This is useful +for cleaning a repo using \\"git clean\\" without accidentally deleting source +files, or for using standard NPM commands on a project. + +Optional arguments: + -h, --help Show this help message and exit. +" +`; + +exports[`CommandLineHelp prints the help for each action: update 1`] = ` +"usage: rush update [-h] [-p] [--bypass-policy] [--no-link] + [--network-concurrency COUNT] [--debug-package-manager] + [--max-install-attempts NUMBER] [--ignore-hooks] + [--offline] [--variant VARIANT] [--full] [--recheck] + + +The \\"rush update\\" command installs the dependencies described in your package. +json files, and updates the shrinkwrap file as needed. (This \\"shrinkwrap\\" +file stores a central inventory of all dependencies and versions for projects +in your repo. It is found in the \\"common/config/rush\\" folder.) Note that Rush +always performs a single install for all projects in your repo. You should +run \\"rush update\\" whenever you start working in a Rush repo, after you pull +from Git, and after you modify a package.json file. If there is nothing to do, + \\"rush update\\" is instantaneous. NOTE: In certain cases \\"rush install\\" should +be used instead of \\"rush update\\" -- for details, see the command help for +\\"rush install\\". + +Optional arguments: + -h, --help Show this help message and exit. + -p, --purge Perform \\"rush purge\\" before starting the installation + --bypass-policy Overrides enforcement of the \\"gitPolicy\\" rules from + rush.json (use honorably!) + --no-link If \\"--no-link\\" is specified, then project symlinks + will NOT be created after the installation completes. + You will need to run \\"rush link\\" manually. This flag + is useful for automated builds that want to report + stages individually or perform extra operations in + between the two stages. This flag is not supported + when using workspaces. + --network-concurrency COUNT + If specified, limits the maximum number of concurrent + network requests. This is useful when troubleshooting + network failures. + --debug-package-manager + Activates verbose logging for the package manager. + You will probably want to pipe the output of Rush to + a file when using this command. + --max-install-attempts NUMBER + Overrides the default maximum number of install + attempts. The default value is 1. + --ignore-hooks Skips execution of the \\"eventHooks\\" scripts defined + in rush.json. Make sure you know what you are + skipping. + --offline Enables installation to be performed without internet + access. PNPM will instead report an error if the + necessary NPM packages cannot be obtained from the + local cache. For details, see the documentation for + PNPM's \\"--offline\\" parameter. + --variant VARIANT Run command using a variant installation + configuration. This parameter may alternatively be + specified via the RUSH_VARIANT environment variable. + --full Normally \\"rush update\\" tries to preserve your + existing installed versions and only makes the + minimum updates needed to satisfy the package.json + files. This conservative approach prevents your PR + from getting involved with package updates that are + unrelated to your work. Use \\"--full\\" when you really + want to update all dependencies to the latest + SemVer-compatible version. This should be done + periodically by a person or robot whose role is to + deal with potential upgrade regressions. + --recheck If the shrinkwrap file appears to already satisfy the + package.json files, then \\"rush update\\" will skip + invoking the package manager at all. In certain + situations this heuristic may be inaccurate. Use the + \\"--recheck\\" flag to force the package manager to + process the shrinkwrap file. This will also update + your shrinkwrap file with Rush's fixups. (To minimize + shrinkwrap churn, these fixups are normally performed + only in the temporary folder.) +" +`; + +exports[`CommandLineHelp prints the help for each action: update-autoinstaller 1`] = ` +"usage: rush update-autoinstaller [-h] --name AUTOINSTALLER_NAME + +Use this command to regenerate the shrinkwrap file for an autoinstaller +folder. + +Optional arguments: + -h, --help Show this help message and exit. + --name AUTOINSTALLER_NAME + The name of the autoinstaller, which must be one of + the folders under common/autoinstallers. +" +`; + +exports[`CommandLineHelp prints the help for each action: update-cloud-credentials 1`] = ` +"usage: rush update-cloud-credentials [-h] [-i] + [--credential CREDENTIAL_STRING] [-d] + + +(EXPERIMENTAL) If the build caching feature is configured, this command +facilitates updating the credentials used by a cloud-based provider. + +Optional arguments: + -h, --help Show this help message and exit. + -i, --interactive Run the credential update operation in interactive + mode, if supported by the provider. + --credential CREDENTIAL_STRING + A static credential, to be cached. + -d, --delete If specified, delete stored credentials. +" +`; + +exports[`CommandLineHelp prints the help for each action: upgrade-interactive 1`] = ` +"usage: rush upgrade-interactive [-h] [--make-consistent] [-s] + [--variant VARIANT] + + +Provide an interactive way to upgrade your dependencies. Running the command +will open an interactive prompt that will ask you which projects and which +dependencies you would like to upgrade. It will then update your package.json +files, and run \\"rush update\\" for you. If you are using +ensureConsistentVersions policy, upgrade-interactive will update all packages +which use the dependencies that you are upgrading and match their SemVer +range if provided. If ensureConsistentVersions is not enabled, +upgrade-interactive will only update the dependency in the package you +specify. This can be overriden by using the --make-consistent flag. + +Optional arguments: + -h, --help Show this help message and exit. + --make-consistent When upgrading dependencies from a single project, also + upgrade dependencies from other projects. + -s, --skip-update If specified, the \\"rush update\\" command will not be run + after updating the package.json files. + --variant VARIANT Run command using a variant installation configuration. + This parameter may alternatively be specified via the + RUSH_VARIANT environment variable. +" +`; + +exports[`CommandLineHelp prints the help for each action: upload 1`] = ` +"usage: rush upload [-h] [--locale {en-us,fr-fr,es-es,zh-cn}] + +Uploads all the built assets to the CDN + +Optional arguments: + -h, --help Show this help message and exit. + --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 + builds. +" +`; + +exports[`CommandLineHelp prints the help for each action: version 1`] = ` +"usage: rush version [-h] [-b BRANCH] [--ensure-version-policy] + [--override-version NEW_VERSION] [--bump] + [--bypass-policy] [--version-policy POLICY] + [--override-bump BUMPTYPE] [--override-prerelease-id ID] + [--ignore-git-hooks] + + +use this \\"rush version\\" command to ensure version policies and bump versions. + +Optional arguments: + -h, --help Show this help message and exit. + -b BRANCH, --target-branch BRANCH + If this flag is specified, changes will be committed + and merged into the target branch. + --ensure-version-policy + Updates package versions if needed to satisfy version + policies. + --override-version NEW_VERSION + Override the version in the specified + --version-policy. This setting only works for + lock-step version policy and when + --ensure-version-policy is specified. + --bump Bumps package version based on version policies. + --bypass-policy Overrides \\"gitPolicy\\" enforcement (use honorably!) + --version-policy POLICY + The name of the version policy + --override-bump BUMPTYPE + Overrides the bump type in the version-policy.json + for the specified version policy. Valid BUMPTYPE + values include: prerelease, patch, preminor, minor, + major. This setting only works for lock-step version + policy in bump action. + --override-prerelease-id ID + Overrides the prerelease identifier in the version + value of version-policy.json for the specified + version policy. This setting only works for lock-step + version policy. This setting increases to new + prerelease id when \\"--bump\\" is provided but only + replaces the prerelease name when + \\"--ensure-version-policy\\" is provided. + --ignore-git-hooks Skips execution of all git hooks. Make sure you know + what you are skipping. +" +`; 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 new file mode 100644 index 00000000000..c821490c0d9 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/__snapshots__/RushXCommandLine.test.ts.snap @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RushXCommandLine launchRushXAsync executes a valid package script 1`] = ` +Array [ + Array [ + "Rush Multi-Project Build Tool 40.40.40 - Node.js 12.12.12 (LTS)", + ], + Array [ + "> \\"an acme project build command\\" +", + ], +] +`; + +exports[`RushXCommandLine launchRushXAsync executes a valid package script with no startup banner 1`] = `Array []`; + +exports[`RushXCommandLine launchRushXAsync fails if the package does not contain a matching script 1`] = ` +Array [ + Array [ + "Rush Multi-Project Build Tool 40.40.40 - Node.js 12.12.12 (LTS)", + ], +] +`; + +exports[`RushXCommandLine launchRushXAsync prints usage info 1`] = ` +Array [ + Array [ + "Rush Multi-Project Build Tool 40.40.40 - Node.js 12.12.12 (LTS)", + ], + Array [ + "usage: rushx [-h]", + ], + Array [ + " rushx [-q/--quiet] [-d/--debug] [--ignore-hooks] ... +", + ], + Array [ + "Optional arguments:", + ], + Array [ + " -h, --help Show this help message and exit.", + ], + Array [ + " -q, --quiet Hide rushx startup information.", + ], + Array [ + " -d, --debug Run in debug mode. +", + ], + Array [ + "Project commands for @acme/acme:", + ], + Array [ + " build: \\"an acme project build command\\"", + ], + Array [ + " test: \\"an acme project test command\\"", + ], +] +`; diff --git a/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/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/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/basicAndRunBuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/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/apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/basicAndRunRebuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/mockRushCommandLineParser.ts b/libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts similarity index 83% rename from apps/rush-lib/src/cli/test/mockRushCommandLineParser.ts rename to libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts index 2901778e25e..9904cfcabf8 100644 --- a/apps/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 @@ -14,7 +14,7 @@ function mockReportErrorAndSetExitCode(error: Error): void { */ jest.mock('../RushCommandLineParser', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const actualModule: any = require.requireActual('../RushCommandLineParser'); + const actualModule: any = jest.requireActual('../RushCommandLineParser'); if (actualModule.RushCommandLineParser) { // Stub out the troublesome method that calls `process.exit` actualModule.RushCommandLineParser.prototype._reportErrorAndSetExitCode = mockReportErrorAndSetExitCode; 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..12b7be1b26e --- /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.genMockFromModule('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 `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/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/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/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..5dc8db3d775 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/common/config/rush/command-line.json @@ -0,0 +1,45 @@ +{ + "$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 + }, + { + "commandKind": "bulk", + "name": "my-bulk-command", + "summary": "Example bulk custom command", + "description": "This is an example custom command that runs separately for each project", + "safeForSimultaneousRushProcesses": false, + "enableParallelism": false, + "ignoreDependencyOrder": false, + "ignoreMissingScript": false, + "allowWarningsInSuccessfulBuild": false + }, + { + "commandKind": "global", + "name": "my-global-command", + "summary": "Example global custom command", + "description": "This is an example custom command that runs once for the entire repo", + "safeForSimultaneousRushProcesses": false, + "shellCommand": "node common/scripts/my-global-command.js" + } + ], + "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/apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideAndDefaultBuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/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/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..5dc8db3d775 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/common/config/rush/command-line.json @@ -0,0 +1,45 @@ +{ + "$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 + }, + { + "commandKind": "bulk", + "name": "my-bulk-command", + "summary": "Example bulk custom command", + "description": "This is an example custom command that runs separately for each project", + "safeForSimultaneousRushProcesses": false, + "enableParallelism": false, + "ignoreDependencyOrder": false, + "ignoreMissingScript": false, + "allowWarningsInSuccessfulBuild": false + }, + { + "commandKind": "global", + "name": "my-global-command", + "summary": "Example global custom command", + "description": "This is an example custom command that runs once for the entire repo", + "safeForSimultaneousRushProcesses": false, + "shellCommand": "node common/scripts/my-global-command.js" + } + ], + "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/apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideAndDefaultRebuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/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/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..6d3d4ebb50c --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/common/config/rush/command-line.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "global", + "name": "build", + "summary": "Build", + "description": "This combo is not supported", + "shellCommand": "node fake-build" + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideBuildAsGlobalCommandRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/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/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..b337bb04bb2 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "build", + "summary": "Build", + "description": "This combo is not supported", + "enableParallelism": true, + "safeForSimultaneousRushProcesses": true + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideBuildWithSimultaneousProcessesRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/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/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..8cccb52fb9e --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/common/config/rush/command-line.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "Rebuild the repo", + "description": "Rebuild the repo using the 'rebuild' script command", + "enableParallelism": true + } + ], + "parameters": [ + { + "longName": "--flag-for-build-and-rebuild", + "description": "This flag should be usable for build and rebuild commands.", + "parameterKind": "flag", + "associatedCommands": ["build", "rebuild"] + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAndRunBuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/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/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..8cccb52fb9e --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/common/config/rush/command-line.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "Rebuild the repo", + "description": "Rebuild the repo using the 'rebuild' script command", + "enableParallelism": true + } + ], + "parameters": [ + { + "longName": "--flag-for-build-and-rebuild", + "description": "This flag should be usable for build and rebuild commands.", + "parameterKind": "flag", + "associatedCommands": ["build", "rebuild"] + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAndRunRebuildActionRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/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/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..a1e5db80eb5 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/common/config/rush/command-line.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "global", + "name": "rebuild", + "summary": "Rebuild", + "description": "This combo is not supported", + "shellCommand": "node fake-rebuild" + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideRebuildAsGlobalCommandRepo/rush.json diff --git a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/a/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/a/package.json rename to libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/a/package.json diff --git a/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/b/package.json b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/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/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..208dc9a375d --- /dev/null +++ b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/common/config/rush/command-line.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "Rebuild", + "description": "This combo is not supported", + "enableParallelism": true, + "safeForSimultaneousRushProcesses": true + } + ] +} diff --git a/apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/rush.json b/libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/rush.json similarity index 100% rename from apps/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/rush.json rename to libraries/rush-lib/src/cli/test/overrideRebuildWithSimultaneousProcessesRepo/rush.json diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..f6ab7ba55c0 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-command-parameters-plugin": "file: ../../../rush-command-parameters-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-command-parameters-plugin/command-line.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-command-parameters-plugin/command-line.json new file mode 100644 index 00000000000..5174e667474 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-command-parameters-plugin/command-line.json @@ -0,0 +1,83 @@ +{ + "$schema": "../../../../../../../../../schemas/command-line.schema.json", + "commands": [ + { + "commandKind": "global", + "name": "cmd-parameters-test", + "summary": "Testing command", + "shellCommand": "node /index.js" + } + ], + "parameters": [ + { + "longName": "--myflag", + "parameterKind": "flag", + "description": "a simple flag parameter", + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--mystring", + "parameterKind": "string", + "argumentName": "STRING", + "description": "a simple string parameter", + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--myinteger", + "parameterKind": "integer", + "argumentName": "INTEGER", + "description": "a simple integer parameter", + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--mychoice", + "parameterKind": "choice", + "description": "a simple choice parameter", + "alternatives": [ + { + "name": "a", + "description": "My choice A" + }, + { + "name": "b", + "description": "My choice B" + } + ], + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--mystringlist", + "parameterKind": "stringList", + "argumentName": "STRING_LIST", + "description": "a simple list of string", + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--myintegerlist", + "parameterKind": "integerList", + "argumentName": "INTEGER_LIST", + "description": "a simple list of integer", + "associatedCommands": ["cmd-parameters-test"] + }, + { + "longName": "--mychoicelist", + "parameterKind": "choiceList", + "description": "a simple choice list parameter", + "alternatives": [ + { + "name": "a", + "description": "My choice A" + }, + { + "name": "b", + "description": "My choice B" + }, + { + "name": "c", + "description": "My choice C" + } + ], + "associatedCommands": ["cmd-parameters-test"] + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..3717ad22e0f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/autoinstallers/plugins/rush-plugins/rush-command-parameters-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-command-parameters-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..641a9827586 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-command-parameters-plugin", + "pluginName": "rush-command-parameters-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/index.js b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/index.js new file mode 100644 index 00000000000..1df15f73001 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/index.js @@ -0,0 +1 @@ +console.log('Rush Command Line Parameters Repo Test', process.argv); diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/package.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/package.json new file mode 100644 index 00000000000..7e9f3ba3eba --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-command-parameters-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..3717ad22e0f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush-command-parameters-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-command-parameters-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush.json b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush.json new file mode 100644 index 00000000000..c8af3fcf188 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginCommandLineParametersRepo/rush.json @@ -0,0 +1,7 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "projects": [] +} 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/repo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/repo/common/config/rush/command-line.json new file mode 100644 index 00000000000..d082f493cce --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/common/config/rush/command-line.json @@ -0,0 +1,61 @@ +{ + "commands": [ + { + "name": "import-strings", + "commandKind": "bulk", + "summary": "Imports translated strings into each project.", + "description": "Requests translated strings from the translation service and imports them into each project.", + "enableParallelism": true + }, + { + "name": "upload", + "commandKind": "global", + "summary": "Uploads the built files to the server", + "description": "Uploads all the built assets to the CDN", + "shellCommand": "node common/scripts/upload.js" + } + ], + + "parameters": [ + { + "longName": "--locale", + "parameterKind": "choice", + "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", + "associatedCommands": ["import-strings", "upload"], + "alternatives": [ + { + "name": "en-us", + "description": "US English" + }, + { + "name": "fr-fr", + "description": "French (France)" + }, + { + "name": "es-es", + "description": "Spanish (Spain)" + }, + { + "name": "zh-cn", + "description": "Chinese (China)" + } + ] + }, + + { + "longName": "--ship", + "shortName": "-s", + "parameterKind": "flag", + "description": "Perform a production build, including minification and localization steps", + "associatedCommands": ["build", "rebuild"] + }, + + { + "longName": "--minimal", + "shortName": "-m", + "parameterKind": "flag", + "description": "Perform a fast build, which disables certain tasks such as unit tests and linting", + "associatedCommands": ["build", "rebuild"] + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/repo/common/config/rush/experiments.json b/libraries/rush-lib/src/cli/test/repo/common/config/rush/experiments.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/common/config/rush/experiments.json @@ -0,0 +1 @@ +{} diff --git a/apps/rush-lib/src/cli/test/repo/common/scripts/deploy.js b/libraries/rush-lib/src/cli/test/repo/common/scripts/deploy.js similarity index 91% rename from apps/rush-lib/src/cli/test/repo/common/scripts/deploy.js rename to libraries/rush-lib/src/cli/test/repo/common/scripts/deploy.js index 1521954473d..1832b07dc4d 100644 --- a/apps/rush-lib/src/cli/test/repo/common/scripts/deploy.js +++ b/libraries/rush-lib/src/cli/test/repo/common/scripts/deploy.js @@ -3,4 +3,4 @@ console.log('ARGV: ' + JSON.stringify(process.argv)); console.log('CWD: ' + process.cwd()); console.log('INITCWD: ' + process.env['INIT_CWD']); -process.exit(123) +process.exit(123); diff --git a/libraries/rush-lib/src/cli/test/repo/rush.json b/libraries/rush-lib/src/cli/test/repo/rush.json new file mode 100644 index 00000000000..32b3e2399d8 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/rush.json @@ -0,0 +1,10 @@ +{ + "pnpmVersion": "4.5.0", + "rushVersion": "5.0.0", + "projects": [ + { + "packageName": "rushx-project", + "projectFolder": "rushx-project" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/build.js b/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/build.js new file mode 100644 index 00000000000..fd3033bfe28 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/build.js @@ -0,0 +1,2 @@ +// slice(2) trims away "node.exe" and "build.js" from the array +console.log('build.js: ARGS=' + JSON.stringify(process.argv.slice(2))); diff --git a/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/package.json b/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/package.json new file mode 100644 index 00000000000..b6ddd52d201 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/rushx-not-in-rush-project/package.json @@ -0,0 +1,7 @@ +{ + "name": "rushx-not-in-rush-project", + "version": "0.0.0", + "scripts": { + "show-args": "node ./build.js" + } +} diff --git a/libraries/rush-lib/src/cli/test/repo/rushx-project/build.js b/libraries/rush-lib/src/cli/test/repo/rushx-project/build.js new file mode 100644 index 00000000000..fd3033bfe28 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/rushx-project/build.js @@ -0,0 +1,2 @@ +// slice(2) trims away "node.exe" and "build.js" from the array +console.log('build.js: ARGS=' + JSON.stringify(process.argv.slice(2))); diff --git a/libraries/rush-lib/src/cli/test/repo/rushx-project/package.json b/libraries/rush-lib/src/cli/test/repo/rushx-project/package.json new file mode 100644 index 00000000000..94d30df2ceb --- /dev/null +++ b/libraries/rush-lib/src/cli/test/repo/rushx-project/package.json @@ -0,0 +1,7 @@ +{ + "name": "rushx-project", + "version": "0.0.0", + "scripts": { + "show-args": "node ./build.js" + } +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/index.ts b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/index.ts new file mode 100644 index 00000000000..d3e9d15ae67 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/index.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This is a false-positive +// eslint-disable-next-line import/no-extraneous-dependencies +import { JsonFile } from '@rushstack/node-core-library'; + +import type { RushSession, RushConfiguration, ITelemetryData } from '../../../index'; + +export default class RushMockFlushTelemetryPlugin { + public apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void { + async function flushTelemetry(data: ReadonlyArray): Promise { + const targetPath: string = `${rushConfiguration.commonTempFolder}/test-telemetry.json`; + await JsonFile.saveAsync(data, targetPath, { ignoreUndefinedValues: true }); + } + + rushSession.hooks.flushTelemetry.tapPromise(RushMockFlushTelemetryPlugin.name, flushTelemetry); + } +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/package.json b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/package.json new file mode 100644 index 00000000000..fbbd074a4e2 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-mock-flush-telemetry-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..dadecec4b47 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "pluginName": "rush-mock-flush-telemetry-plugin", + "description": "Rush plugin for testing flush telemetry", + "entryPoint": "index.js" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/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/tapFlushTelemetryAndRunBuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/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/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..d790fd77df4 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-mock-flush-telemetry-plugin": "file:../../../../rush-mock-flush-telemetry-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..dadecec4b47 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-flush-telemetry-plugin/rush-plugin-manifest.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "pluginName": "rush-mock-flush-telemetry-plugin", + "description": "Rush plugin for testing flush telemetry", + "entryPoint": "index.js" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..48388d93f59 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-mock-flush-telemetry-plugin", + "pluginName": "rush-mock-flush-telemetry-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/rush.json new file mode 100644 index 00000000000..f20bd2ed7e9 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/tapFlushTelemetryAndRunBuildActionRepo/rush.json @@ -0,0 +1,19 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "telemetryEnabled": true, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/index.ts b/libraries/rush-lib/src/index.ts new file mode 100644 index 00000000000..88dfb89789e --- /dev/null +++ b/libraries/rush-lib/src/index.ts @@ -0,0 +1,211 @@ +// 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 + */ + +// #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'; + +export { Subspace } from './api/Subspace'; +export { SubspacesConfiguration } from './api/SubspacesConfiguration'; + +export { + type IPackageManagerOptionsJsonBase, + type IConfigurationEnvironment, + type IConfigurationEnvironmentVariable, + PackageManagerOptionsConfigurationBase +} from './logic/base/BasePackageManagerOptionsConfiguration'; +export { + type INpmOptionsJson as _INpmOptionsJson, + NpmOptionsConfiguration +} from './logic/npm/NpmOptionsConfiguration'; +export { + type IYarnOptionsJson as _IYarnOptionsJson, + YarnOptionsConfiguration +} from './logic/yarn/YarnOptionsConfiguration'; +export { + type IPnpmOptionsJson as _IPnpmOptionsJson, + type PnpmStoreLocation, + type IPnpmLockfilePolicies, + type IPnpmPackageExtension, + type IPnpmPeerDependencyRules, + type IPnpmPeerDependenciesMeta, + type PnpmStoreOptions, + PnpmOptionsConfiguration, + type PnpmResolutionMode +} from './logic/pnpm/PnpmOptionsConfiguration'; + +export { BuildCacheConfiguration } from './api/BuildCacheConfiguration'; +export { CobuildConfiguration, type ICobuildJson } from './api/CobuildConfiguration'; +export type { GetCacheEntryIdFunction, IGenerateCacheEntryIdOptions } from './logic/buildCache/CacheEntryId'; +export { + FileSystemBuildCacheProvider, + type IFileSystemBuildCacheProviderOptions +} from './logic/buildCache/FileSystemBuildCacheProvider'; + +export type { + IPhase, + PhaseBehaviorForMissingScript as IPhaseBehaviorForMissingScript +} from './api/CommandLineConfiguration'; + +export { + EnvironmentConfiguration, + EnvironmentVariableNames, + type IEnvironmentConfigurationInitializeOptions +} from './api/EnvironmentConfiguration'; + +export { RushConstants } from './logic/RushConstants'; + +export { type PackageManagerName, PackageManager } from './api/packageManager/PackageManager'; + +export { RushConfigurationProject } from './api/RushConfigurationProject'; + +export { + type IRushProjectJson as _IRushProjectJson, + type IOperationSettings, + RushProjectConfiguration, + type IRushPhaseSharding +} from './api/RushProjectConfiguration'; + +export { RushUserConfiguration } from './api/RushUserConfiguration'; + +export { RushGlobalFolder as _RushGlobalFolder } from './api/RushGlobalFolder'; + +export { ApprovedPackagesItem, ApprovedPackagesConfiguration } from './api/ApprovedPackagesConfiguration'; + +export { CommonVersionsConfiguration } from './api/CommonVersionsConfiguration'; + +export { + PackageJsonEditor, + PackageJsonDependency, + DependencyType, + PackageJsonDependencyMeta +} from './api/PackageJsonEditor'; + +export { RepoStateFile } from './logic/RepoStateFile'; + +export { EventHooks, Event } from './api/EventHooks'; + +export { ChangeManager } from './api/ChangeManager'; + +export { FlagFile as _FlagFile } from './api/FlagFile'; + +export { + VersionPolicyDefinitionName, + BumpType, + LockStepVersionPolicy, + IndividualVersionPolicy, + VersionPolicy +} from './api/VersionPolicy'; + +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'; + +export { ExperimentsConfiguration, type IExperimentsJson } from './api/ExperimentsConfiguration'; +export { + CustomTipsConfiguration, + CustomTipId, + type ICustomTipsJson, + type ICustomTipInfo, + type ICustomTipItemJson, + CustomTipSeverity, + CustomTipType +} from './api/CustomTipsConfiguration'; + +export { ProjectChangeAnalyzer, type IGetChangedProjectsOptions } from './logic/ProjectChangeAnalyzer'; +export type { + IInputsSnapshot, + GetInputsSnapshotAsyncFn as GetInputsSnapshotAsyncFn, + IRushConfigurationProjectForSnapshot +} from './logic/incremental/InputsSnapshot'; + +export type { IOperationRunner, IOperationRunnerContext } from './logic/operations/IOperationRunner'; +export type { + IExecutionResult, + IOperationExecutionResult +} from './logic/operations/IOperationExecutionResult'; +export { type IOperationOptions, Operation } from './logic/operations/Operation'; +export { OperationStatus } from './logic/operations/OperationStatus'; +export type { ILogFilePaths } from './logic/operations/ProjectLogWritable'; + +export { + RushSession, + type IRushSessionOptions, + type CloudBuildCacheProviderFactory, + type CobuildLockProviderFactory +} from './pluginFramework/RushSession'; + +export { + type IRushCommand, + type IGlobalCommand, + type IPhasedCommand, + RushLifecycleHooks +} from './pluginFramework/RushLifeCycle'; + +export { + type ICreateOperationsContext, + type IExecuteOperationsContext, + PhasedCommandHooks +} from './pluginFramework/PhasedCommandHooks'; + +export type { IRushPlugin } from './pluginFramework/IRushPlugin'; +export type { IBuiltInPluginConfiguration as _IBuiltInPluginConfiguration } from './pluginFramework/PluginLoader/BuiltInPluginLoader'; +export type { IRushPluginConfigurationBase as _IRushPluginConfigurationBase } from './api/RushPluginsConfiguration'; +export type { ILogger } from './pluginFramework/logging/Logger'; + +export type { ICloudBuildCacheProvider } from './logic/buildCache/ICloudBuildCacheProvider'; +export type { + ICobuildLockProvider, + ICobuildContext, + ICobuildCompletedState +} from './logic/cobuild/ICobuildLockProvider'; + +export type { ITelemetryData, ITelemetryMachineInfo, ITelemetryOperationResult } from './logic/Telemetry'; + +export type { IStopwatchResult } from './utilities/Stopwatch'; +export { + OperationStateFile as _OperationStateFile, + type IOperationStateFileOptions as _IOperationStateFileOptions, + type IOperationStateJson as _IOperationStateJson +} from './logic/operations/OperationStateFile'; +export { + OperationMetadataManager as _OperationMetadataManager, + type IOperationMetadataManagerOptions as _IOperationMetadataManagerOptions, + type IOperationMetaData as _IOperationMetadata +} from './logic/operations/OperationMetadataManager'; + +export { + RushCommandLine, + type IRushCommandLineSpec, + 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/apps/rush-lib/src/logic/ApprovedPackagesChecker.ts b/libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts similarity index 76% rename from apps/rush-lib/src/logic/ApprovedPackagesChecker.ts rename to libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts index 71dbe7027ee..c20f3b525d9 100644 --- a/apps/rush-lib/src/logic/ApprovedPackagesChecker.ts +++ b/libraries/rush-lib/src/logic/ApprovedPackagesChecker.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 { IPackageJson, PackageName } from '@rushstack/node-core-library'; +import type { IPackageJson } from '@rushstack/node-core-library'; -import { ApprovedPackagesPolicy } from '../api/ApprovedPackagesPolicy'; -import { RushConfiguration } from '../api/RushConfiguration'; -import { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { ApprovedPackagesPolicy } from '../api/ApprovedPackagesPolicy'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import { DependencySpecifier } from './DependencySpecifier'; export class ApprovedPackagesChecker { @@ -50,26 +50,10 @@ export class ApprovedPackagesChecker { for (const rushProject of this._rushConfiguration.projects) { const packageJson: IPackageJson = rushProject.packageJson; - this._collectDependencies( - packageJson.dependencies, - this._approvedPackagesPolicy, - rushProject - ); - this._collectDependencies( - packageJson.devDependencies, - this._approvedPackagesPolicy, - rushProject - ); - this._collectDependencies( - packageJson.peerDependencies, - this._approvedPackagesPolicy, - rushProject - ); - this._collectDependencies( - packageJson.optionalDependencies, - this._approvedPackagesPolicy, - rushProject - ); + this._collectDependencies(packageJson.dependencies, this._approvedPackagesPolicy, rushProject); + this._collectDependencies(packageJson.devDependencies, this._approvedPackagesPolicy, rushProject); + this._collectDependencies(packageJson.peerDependencies, this._approvedPackagesPolicy, rushProject); + this._collectDependencies(packageJson.optionalDependencies, this._approvedPackagesPolicy, rushProject); } } @@ -80,7 +64,6 @@ export class ApprovedPackagesChecker { ): void { if (dependencies) { for (const packageName of Object.keys(dependencies)) { - let referencedPackageName: string = packageName; // Special handling for NPM package aliases such as this: @@ -88,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] ); @@ -97,10 +80,10 @@ export class ApprovedPackagesChecker { referencedPackageName = dependencySpecifier.aliasTarget.packageName; } - const scope: string = PackageName.getScope(referencedPackageName); + const scope: string = this._rushConfiguration.packageNameParser.getScope(referencedPackageName); // Make sure the scope isn't something like "@types" which should be ignored - if (!approvedPackagesPolicy.ignoredNpmScopes.has(scope)) { + if (!approvedPackagesPolicy.ignoredNpmScopes.has(scope) && rushProject.reviewCategory) { // Yes, add it to the list if it's not already there let updated: boolean = false; diff --git a/libraries/rush-lib/src/logic/Autoinstaller.ts b/libraries/rush-lib/src/logic/Autoinstaller.ts new file mode 100644 index 00000000000..8c35ea07b82 --- /dev/null +++ b/libraries/rush-lib/src/logic/Autoinstaller.ts @@ -0,0 +1,276 @@ +// 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, + type IPackageJson, + JsonFile, + LockFile, + NewlineKind, + PackageName, + type IParsedPackageNameOrError +} from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { Utilities } from '../utilities/Utilities'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { PackageJsonEditor } from '../api/PackageJsonEditor'; +import { InstallHelpers } from './installManager/InstallHelpers'; +import type { RushGlobalFolder } from '../api/RushGlobalFolder'; +import { RushConstants } from './RushConstants'; +import { LastInstallFlag } from '../api/LastInstallFlag'; +import { RushCommandLineParser } from '../cli/RushCommandLineParser'; +import type { PnpmPackageManager } from '../api/packageManager/PnpmPackageManager'; + +export interface IAutoinstallerOptions { + autoinstallerName: string; + rushConfiguration: RushConfiguration; + rushGlobalFolder: RushGlobalFolder; + restrictConsoleOutput?: boolean; +} + +export class Autoinstaller { + public readonly name: string; + + private readonly _rushConfiguration: RushConfiguration; + private readonly _rushGlobalFolder: RushGlobalFolder; + private readonly _restrictConsoleOutput: boolean; + + public constructor(options: IAutoinstallerOptions) { + this.name = options.autoinstallerName; + this._rushConfiguration = options.rushConfiguration; + this._rushGlobalFolder = options.rushGlobalFolder; + this._restrictConsoleOutput = + options.restrictConsoleOutput ?? RushCommandLineParser.shouldRestrictConsoleOutput(); + + Autoinstaller.validateName(this.name); + } + + // Example: .../common/autoinstallers/my-task + public get folderFullPath(): string { + return path.join(this._rushConfiguration.commonAutoinstallersFolder, this.name); + } + + // Example: .../common/autoinstallers/my-task/package-lock.yaml + public get shrinkwrapFilePath(): string { + return path.join( + this._rushConfiguration.commonAutoinstallersFolder, + this.name, + this._rushConfiguration.shrinkwrapFilename + ); + } + + // Example: .../common/autoinstallers/my-task/package.json + public get packageJsonPath(): string { + return path.join(this._rushConfiguration.commonAutoinstallersFolder, this.name, 'package.json'); + } + + public static validateName(autoinstallerName: string): void { + const nameOrError: IParsedPackageNameOrError = PackageName.tryParse(autoinstallerName); + if (nameOrError.error) { + throw new Error(`The specified name "${autoinstallerName}" is invalid: ` + nameOrError.error); + } + if (nameOrError.scope) { + throw new Error(`The specified name "${autoinstallerName}" must not contain an NPM scope`); + } + } + + public async prepareAsync(): Promise { + const autoinstallerFullPath: string = this.folderFullPath; + + if (!FileSystem.exists(autoinstallerFullPath)) { + throw new Error( + `The autoinstaller ${this.name} does not exist, Please run\nrush init-autoinstaller --name ${this.name}\n` + ); + } + + await InstallHelpers.ensureLocalPackageManagerAsync( + this._rushConfiguration, + this._rushGlobalFolder, + RushConstants.defaultMaxInstallAttempts, + this._restrictConsoleOutput + ); + + // Example: common/autoinstallers/my-task/package.json + const relativePathForLogs: string = path.relative( + this._rushConfiguration.rushJsonFolder, + autoinstallerFullPath + ); + + this._logIfConsoleOutputIsNotRestricted(`Acquiring lock for "${relativePathForLogs}" folder...`); + + const lock: LockFile = await LockFile.acquireAsync(autoinstallerFullPath, 'autoinstaller'); + + try { + // Example: .../common/autoinstallers/my-task/.rush/temp + const lastInstallFlagPath: string = path.join( + autoinstallerFullPath, + RushConstants.projectRushFolderName, + 'temp' + ); + + const packageJsonPath: string = path.join(autoinstallerFullPath, 'package.json'); + const packageJson: IPackageJson = JsonFile.load(packageJsonPath); + + const lastInstallFlag: LastInstallFlag = new LastInstallFlag(lastInstallFlagPath, { + node: process.versions.node, + packageManager: this._rushConfiguration.packageManager, + packageManagerVersion: this._rushConfiguration.packageManagerToolVersion, + packageJson: packageJson, + rushJsonFolder: this._rushConfiguration.rushJsonFolder + }); + + // Example: ../common/autoinstallers/my-task/node_modules + const nodeModulesFolder: string = `${autoinstallerFullPath}/${RushConstants.nodeModulesFolderName}`; + const flagPath: string = `${nodeModulesFolder}/rush-autoinstaller.flag`; + const isLastInstallFlagDirty: boolean = + !(await lastInstallFlag.isValidAsync()) || !FileSystem.exists(flagPath); + + if (isLastInstallFlagDirty || lock.dirtyWhenAcquired) { + if (FileSystem.exists(nodeModulesFolder)) { + this._logIfConsoleOutputIsNotRestricted('Deleting old files from ' + nodeModulesFolder); + FileSystem.ensureEmptyFolder(nodeModulesFolder); + } + + // Copy: .../common/autoinstallers/my-task/.npmrc + Utilities.syncNpmrc({ + sourceNpmrcFolder: this._rushConfiguration.commonRushConfigFolder, + targetNpmrcFolder: autoinstallerFullPath, + supportEnvVarFallbackSyntax: this._rushConfiguration.isPnpm + }); + + this._logIfConsoleOutputIsNotRestricted( + `Installing dependencies under ${autoinstallerFullPath}...\n` + ); + + await Utilities.executeCommandAsync({ + command: this._rushConfiguration.packageManagerToolFilename, + args: ['install', '--frozen-lockfile'], + workingDirectory: autoinstallerFullPath, + keepEnvironment: true + }); + + // Create file: ../common/autoinstallers/my-task/.rush/temp/last-install.flag + await lastInstallFlag.createAsync(); + + FileSystem.writeFile( + flagPath, + 'If this file is deleted, Rush will assume that the node_modules folder has been cleaned and will reinstall it.' + ); + + this._logIfConsoleOutputIsNotRestricted('Auto install completed successfully\n'); + } else { + this._logIfConsoleOutputIsNotRestricted('Autoinstaller folder is already up to date\n'); + } + } finally { + // Ensure the lockfile is released when we are finished. + lock.release(); + } + } + + public async updateAsync(): Promise { + await InstallHelpers.ensureLocalPackageManagerAsync( + this._rushConfiguration, + this._rushGlobalFolder, + RushConstants.defaultMaxInstallAttempts, + this._restrictConsoleOutput + ); + + const autoinstallerPackageJsonPath: string = path.join(this.folderFullPath, 'package.json'); + + if (!(await FileSystem.existsAsync(autoinstallerPackageJsonPath))) { + throw new Error(`The specified autoinstaller path does not exist: ` + autoinstallerPackageJsonPath); + } + + this._logIfConsoleOutputIsNotRestricted( + `Updating autoinstaller package: ${autoinstallerPackageJsonPath}` + ); + + let oldFileContents: string = ''; + + if (await FileSystem.existsAsync(this.shrinkwrapFilePath)) { + oldFileContents = FileSystem.readFile(this.shrinkwrapFilePath, { convertLineEndings: NewlineKind.Lf }); + this._logIfConsoleOutputIsNotRestricted('Deleting ' + this.shrinkwrapFilePath); + await FileSystem.deleteFileAsync(this.shrinkwrapFilePath); + if (this._rushConfiguration.isPnpm) { + // Workaround for https://github.com/pnpm/pnpm/issues/1890 + // + // When "rush update-autoinstaller" is run, Rush deletes "common/autoinstallers/my-task/pnpm-lock.yaml" + // so that a new lockfile will be generated. However "pnpm install" by design will try to recover + // "pnpm-lock.yaml" from "my-task/node_modules/.pnpm/lock.yaml", which may prevent a full upgrade. + // Deleting both files ensures that a new lockfile will always be generated. + const pnpmPackageManager: PnpmPackageManager = this._rushConfiguration + .packageManagerWrapper as PnpmPackageManager; + await FileSystem.deleteFileAsync( + path.join(this.folderFullPath, pnpmPackageManager.internalShrinkwrapRelativePath) + ); + } + } + + // Detect a common mistake where PNPM prints "Already up-to-date" without creating a shrinkwrap file + const packageJsonEditor: PackageJsonEditor = PackageJsonEditor.load(this.packageJsonPath); + if (packageJsonEditor.dependencyList.length === 0) { + throw new Error( + 'You must add at least one dependency to the autoinstaller package' + + ' before invoking this command:\n' + + this.packageJsonPath + ); + } + + this._logIfConsoleOutputIsNotRestricted(); + + Utilities.syncNpmrc({ + sourceNpmrcFolder: this._rushConfiguration.commonRushConfigFolder, + targetNpmrcFolder: this.folderFullPath, + supportEnvVarFallbackSyntax: this._rushConfiguration.isPnpm + }); + + await Utilities.executeCommandAsync({ + command: this._rushConfiguration.packageManagerToolFilename, + args: ['install'], + workingDirectory: this.folderFullPath, + keepEnvironment: true + }); + + this._logIfConsoleOutputIsNotRestricted(); + + if (this._rushConfiguration.packageManager === 'npm') { + this._logIfConsoleOutputIsNotRestricted(Colorize.bold('Running "npm shrinkwrap"...')); + await Utilities.executeCommandAsync({ + command: this._rushConfiguration.packageManagerToolFilename, + args: ['shrinkwrap'], + workingDirectory: this.folderFullPath, + keepEnvironment: true + }); + this._logIfConsoleOutputIsNotRestricted('"npm shrinkwrap" completed'); + this._logIfConsoleOutputIsNotRestricted(); + } + + if (!(await FileSystem.existsAsync(this.shrinkwrapFilePath))) { + throw new Error( + 'The package manager did not create the expected shrinkwrap file: ' + this.shrinkwrapFilePath + ); + } + + const newFileContents: string = await FileSystem.readFileAsync(this.shrinkwrapFilePath, { + convertLineEndings: NewlineKind.Lf + }); + if (oldFileContents !== newFileContents) { + this._logIfConsoleOutputIsNotRestricted( + Colorize.green('The shrinkwrap file has been updated.') + ' Please commit the updated file:' + ); + this._logIfConsoleOutputIsNotRestricted(`\n ${this.shrinkwrapFilePath}`); + } else { + this._logIfConsoleOutputIsNotRestricted(Colorize.green('Already up to date.')); + } + } + + private _logIfConsoleOutputIsNotRestricted(message?: string): void { + if (!this._restrictConsoleOutput) { + // eslint-disable-next-line no-console + console.log(message ?? ''); + } + } +} diff --git a/libraries/rush-lib/src/logic/ChangeFiles.ts b/libraries/rush-lib/src/logic/ChangeFiles.ts new file mode 100644 index 00000000000..93528d345dc --- /dev/null +++ b/libraries/rush-lib/src/logic/ChangeFiles.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 { Async, FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import type { IChangeInfo } from '../api/ChangeManagement'; +import type { IChangelog } from '../api/Changelog'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import schemaJson from '../schemas/change-file.schema.json'; + +/** + * This class represents the collection of change files existing in the repo and provides operations + * for those change files. + */ +export class ChangeFiles { + /** + * Change file path relative to changes folder. + */ + private _files: string[] | undefined; + private _changesPath: string; + + public constructor(changesPath: string) { + this._changesPath = changesPath; + } + + /** + * Validate if the newly added change files match the changed packages. + */ + public static validate( + newChangeFilePaths: string[], + changedPackages: string[], + rushConfiguration: RushConfiguration + ): void { + const schema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + const projectsWithChangeDescriptions: Set = new Set(); + newChangeFilePaths.forEach((filePath) => { + // eslint-disable-next-line no-console + console.log(`Found change file: ${filePath}`); + + const changeFile: IChangeInfo = JsonFile.loadAndValidate(filePath, schema); + + 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'.` + ); + } + } + } + } + + if (changeFile && changeFile.changes) { + changeFile.changes.forEach((change) => projectsWithChangeDescriptions.add(change.packageName)); + } else { + throw new Error(`Invalid change file: ${filePath}`); + } + }); + + 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)); + throw new Error( + [ + 'The following projects have been changed and require change descriptions, but change descriptions were not ' + + 'detected for them:', + ...projectsMissingChangeDescriptionsArray.map((projectName) => `- ${projectName}`), + 'To resolve this error, run "rush change". This will generate change description files that must be ' + + 'committed to source control.' + ].join('\n') + ); + } + } + + public static getChangeComments(newChangeFilePaths: string[]): Map { + const changes: Map = new Map(); + + newChangeFilePaths.forEach((filePath) => { + // eslint-disable-next-line no-console + console.log(`Found change file: ${filePath}`); + const changeRequest: IChangeInfo = JsonFile.load(filePath); + if (changeRequest && changeRequest.changes) { + changeRequest.changes!.forEach((change) => { + if (!changes.get(change.packageName)) { + changes.set(change.packageName, []); + } + if (change.comment && change.comment.length) { + changes.get(change.packageName)!.push(change.comment); + } + }); + } else { + throw new Error(`Invalid change file: ${filePath}`); + } + }); + return changes; + } + + /** + * Get the array of absolute paths of change files. + */ + public async getFilesAsync(): Promise { + if (!this._files) { + const { default: glob } = await import('fast-glob'); + this._files = (await glob('**/*.json', { cwd: this._changesPath, absolute: true })) || []; + } + + return this._files; + } + + /** + * Get the path of changes folder. + */ + public getChangesPath(): string { + return this._changesPath; + } + + /** + * Delete all change files + */ + public async deleteAllAsync(shouldDelete: boolean, updatedChangelogs?: IChangelog[]): Promise { + if (updatedChangelogs) { + // Skip changes files if the package's change log is not updated. + const packagesToInclude: Set = new Set(); + updatedChangelogs.forEach((changelog) => { + packagesToInclude.add(changelog.name); + }); + + const files: string[] = await this.getFilesAsync(); + const filesToDelete: string[] = []; + await Async.forEachAsync( + files, + async (filePath) => { + const changeRequest: IChangeInfo = await JsonFile.loadAsync(filePath); + let shouldDeleteFile: boolean = true; + for (const changeInfo of changeRequest.changes!) { + if (!packagesToInclude.has(changeInfo.packageName)) { + shouldDeleteFile = false; + break; + } + } + + if (shouldDeleteFile) { + filesToDelete.push(filePath); + } + }, + { concurrency: 5 } + ); + + return await this._deleteFilesAsync(filesToDelete, shouldDelete); + } else { + // Delete all change files. + const files: string[] = await this.getFilesAsync(); + return await this._deleteFilesAsync(files, shouldDelete); + } + } + + private async _deleteFilesAsync(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).`); + + await Async.forEachAsync( + files, + async (filePath) => { + // eslint-disable-next-line no-console + console.log(` - ${filePath}`); + if (shouldDelete) { + await FileSystem.deleteFileAsync(filePath); + } + }, + { concurrency: 5 } + ); + } + + return files.length; + } +} diff --git a/libraries/rush-lib/src/logic/ChangeManager.ts b/libraries/rush-lib/src/logic/ChangeManager.ts new file mode 100644 index 00000000000..254ae58bb50 --- /dev/null +++ b/libraries/rush-lib/src/logic/ChangeManager.ts @@ -0,0 +1,136 @@ +// 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 { IChangeInfo } from '../api/ChangeManagement'; +import type { IChangelog } from '../api/Changelog'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { VersionPolicyConfiguration } from '../api/VersionPolicyConfiguration'; +import { PublishUtilities, type IChangeRequests } from './PublishUtilities'; +import { ChangeFiles } from './ChangeFiles'; +import { PrereleaseToken } from './PrereleaseToken'; +import { ChangelogGenerator } from './ChangelogGenerator'; + +/** + * The class manages change files and controls how changes logged by change files + * can be applied to package.json and change logs. + */ +export class ChangeManager { + private _prereleaseToken!: PrereleaseToken; + private _orderedChanges!: IChangeInfo[]; + private _allPackages!: ReadonlyMap; + private _allChanges!: IChangeRequests; + private _changeFiles!: ChangeFiles; + private _rushConfiguration: RushConfiguration; + private _projectsToExclude: Set | undefined; + + public constructor(rushConfiguration: RushConfiguration, projectsToExclude?: Set | undefined) { + this._rushConfiguration = rushConfiguration; + this._projectsToExclude = projectsToExclude; + } + + /** + * 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 { + this._allPackages = this._rushConfiguration.projectsByName; + + this._prereleaseToken = prereleaseToken; + + this._changeFiles = new ChangeFiles(changesPath); + this._allChanges = await PublishUtilities.findChangeRequestsAsync( + this._allPackages, + this._rushConfiguration, + this._changeFiles, + includeCommitDetails, + this._prereleaseToken, + this._projectsToExclude + ); + this._orderedChanges = PublishUtilities.sortChangeRequests(this._allChanges.packageChanges); + } + + public hasChanges(): boolean { + return ( + (this._orderedChanges && this._orderedChanges.length > 0) || + (this._allChanges && this._allChanges.versionPolicyChanges.size > 0) + ); + } + + public get packageChanges(): IChangeInfo[] { + return this._orderedChanges; + } + + public get allPackages(): ReadonlyMap { + return this._allPackages; + } + + public validateChanges(versionConfig: VersionPolicyConfiguration): void { + this._allChanges.packageChanges.forEach((change, projectName) => { + const projectInfo: RushConfigurationProject | undefined = + this._rushConfiguration.getProjectByName(projectName); + if (projectInfo) { + if (projectInfo.versionPolicy) { + projectInfo.versionPolicy.validate(change.newVersion!, projectName); + } + } + }); + } + + /** + * Apply changes to package.json + * @param shouldCommit - If the value is true, package.json will be updated. + * If the value is false, package.json and change logs will not be updated. It will only do a dry-run. + */ + public apply(shouldCommit: boolean): Map | undefined { + if (!this.hasChanges()) { + return; + } + + // Update all the changed version policies + this._allChanges.versionPolicyChanges.forEach((versionPolicyChange, versionPolicyName) => { + this._rushConfiguration.versionPolicyConfiguration.update( + versionPolicyName, + versionPolicyChange.newVersion, + shouldCommit + ); + }); + + // Apply all changes to package.json files. + const updatedPackages: Map = PublishUtilities.updatePackages( + this._allChanges, + this._allPackages, + this._rushConfiguration, + shouldCommit, + this._prereleaseToken, + this._projectsToExclude + ); + + return updatedPackages; + } + + public async updateChangelogAsync(shouldCommit: boolean): Promise { + // Do not update changelog or delete the change files for prerelease. + // Save them for the official release. + if (!this._prereleaseToken.hasValue) { + // Update changelogs. + const updatedChangelogs: IChangelog[] = ChangelogGenerator.updateChangelogs( + this._allChanges, + this._allPackages, + this._rushConfiguration, + shouldCommit + ); + + // Remove the change request files only if "-a" was provided. + await this._changeFiles.deleteAllAsync(shouldCommit, updatedChangelogs); + } + } +} diff --git a/libraries/rush-lib/src/logic/ChangelogGenerator.ts b/libraries/rush-lib/src/logic/ChangelogGenerator.ts new file mode 100644 index 00000000000..a00fa0e1ff8 --- /dev/null +++ b/libraries/rush-lib/src/logic/ChangelogGenerator.ts @@ -0,0 +1,293 @@ +// 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 { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import { type IChangeRequests, PublishUtilities } from './PublishUtilities'; +import { type IChangeInfo, ChangeType } from '../api/ChangeManagement'; +import type { + IChangelog, + IChangeLogEntry, + IChangeLogComment, + IChangeLogEntryComments +} from '../api/Changelog'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import schemaJson from '../schemas/changelog.schema.json'; + +const CHANGELOG_JSON: string = 'CHANGELOG.json'; +const CHANGELOG_MD: string = 'CHANGELOG.md'; +const EOL: string = '\n'; + +export class ChangelogGenerator { + /** + * The JSON Schema for Changelog file (changelog.schema.json). + */ + public static readonly jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + /** + * Updates the appropriate changelogs with the given changes. + */ + public static updateChangelogs( + allChanges: IChangeRequests, + allProjects: ReadonlyMap, + rushConfiguration: RushConfiguration, + shouldCommit: boolean + ): IChangelog[] { + const updatedChangeLogs: IChangelog[] = []; + + allChanges.packageChanges.forEach((change, packageName) => { + const project: RushConfigurationProject | undefined = allProjects.get(packageName); + + if (project && ChangelogGenerator._shouldUpdateChangeLog(project, allChanges)) { + const changeLog: IChangelog | undefined = ChangelogGenerator.updateIndividualChangelog( + change, + project.projectFolder, + shouldCommit, + rushConfiguration, + project.versionPolicy && project.versionPolicy.isLockstepped, + project.isMainProject + ); + + if (changeLog) { + updatedChangeLogs.push(changeLog); + } + } + }); + return updatedChangeLogs; + } + + /** + * Fully regenerate the markdown files based on the current json files. + */ + public static regenerateChangelogs( + allProjects: ReadonlyMap, + rushConfiguration: RushConfiguration + ): void { + allProjects.forEach((project) => { + const markdownPath: string = path.resolve(project.projectFolder, CHANGELOG_MD); + const markdownJSONPath: string = path.resolve(project.projectFolder, CHANGELOG_JSON); + + if (FileSystem.exists(markdownPath)) { + // eslint-disable-next-line no-console + console.log('Found: ' + markdownPath); + if (!FileSystem.exists(markdownJSONPath)) { + throw new Error('A CHANGELOG.md without json: ' + markdownPath); + } + + const changelog: IChangelog = ChangelogGenerator._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) + ); + } + }); + } + + /** + * Updates an individual changelog for a single project. + */ + public static updateIndividualChangelog( + change: IChangeInfo, + projectFolder: string, + shouldCommit: boolean, + rushConfiguration: RushConfiguration, + isLockstepped: boolean = false, + isMain: boolean = true + ): IChangelog | undefined { + if (isLockstepped && !isMain) { + // Early return if the project is lockstepped and does not host change logs + return undefined; + } + const changelog: IChangelog = ChangelogGenerator._getChangelog(change.packageName, projectFolder); + + if (!changelog.entries.some((entry) => entry.version === change.newVersion)) { + const changelogEntry: IChangeLogEntry = { + version: change.newVersion!, + tag: PublishUtilities.createTagname( + change.packageName, + change.newVersion!, + rushConfiguration.gitTagSeparator + ), + date: new Date().toUTCString(), + comments: {} + }; + + change.changes!.forEach((individualChange) => { + if (individualChange.comment) { + // Initialize the comments array only as necessary. + const changeTypeString: keyof IChangeLogEntryComments = ChangeType[ + individualChange.changeType! + ] as keyof IChangeLogEntryComments; + + changelogEntry.comments[changeTypeString] = changelogEntry.comments[changeTypeString] || []; + const comments: IChangeLogComment[] = changelogEntry.comments[changeTypeString]!; + + const changeLogComment: IChangeLogComment = { + comment: individualChange.comment + }; + if (individualChange.author) { + changeLogComment.author = individualChange.author; + } + if (individualChange.commit) { + changeLogComment.commit = individualChange.commit; + } + if (individualChange.customFields) { + changeLogComment.customFields = individualChange.customFields; + } + comments.push(changeLogComment); + } + }); + + // Add the changelog entry to the start of the list. + changelog.entries.unshift(changelogEntry); + + const changelogFilename: string = path.join(projectFolder, CHANGELOG_JSON); + + // eslint-disable-next-line no-console + console.log( + `${EOL}* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: ` + + `Changelog update for "${change.packageName}@${change.newVersion}".` + ); + + if (shouldCommit) { + // Write markdown transform. + JsonFile.save(changelog, changelogFilename); + + FileSystem.writeFile( + path.join(projectFolder, CHANGELOG_MD), + ChangelogGenerator._translateToMarkdown(changelog, rushConfiguration, isLockstepped) + ); + } + return changelog; + } + // 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); + } + + 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; + } + + return changelog; + } + + /** + * 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}`; + } + + markdown += EOL; + + let comments: string = ''; + + comments += ChangelogGenerator._getChangeComments('Breaking changes', entry.comments.major); + + comments += ChangelogGenerator._getChangeComments('Minor changes', entry.comments.minor); + + comments += ChangelogGenerator._getChangeComments('Patches', entry.comments.patch); + + if (isLockstepped) { + // In lockstepped projects, all changes are of type ChangeType.none. + comments += ChangelogGenerator._getChangeComments('Updates', entry.comments.none); + } + + if (rushConfiguration.hotfixChangeEnabled) { + comments += ChangelogGenerator._getChangeComments('Hotfixes', entry.comments.hotfix); + } + + if (!comments) { + markdown += + (changelog.entries.length === index + 1 ? '_Initial release_' : '_Version update only_') + + EOL + + EOL; + } else { + markdown += comments; + } + }); + + return markdown; + } + + /** + * 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 = ''; + + if (commentsArray) { + comments = `### ${title}${EOL + EOL}`; + commentsArray.forEach((comment) => { + comments += `- ${comment.comment}${EOL}`; + }); + comments += EOL; + } + + 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 + */ + private static _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 new file mode 100644 index 00000000000..addb6054cc8 --- /dev/null +++ b/libraries/rush-lib/src/logic/DependencyAnalyzer.ts @@ -0,0 +1,198 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { Subspace } from '../api/Subspace'; + +export interface IDependencyAnalysis { + /** + * The common versions configuration from the repo's rush configuration. + */ + commonVersionsConfiguration: CommonVersionsConfiguration; + + /** + * A map of all direct dependencies that only have a single semantic version specifier, + * unless the {@link CommonVersionsConfiguration.implicitlyPreferredVersions} option + * set to `false`. + */ + implicitlyPreferredVersionByPackageName: Map; + + /** + * A map of dependency name to the set of version specifiers used in the repo. + */ + allVersionsByPackageName: Map>; +} + +export class DependencyAnalyzer { + private static _dependencyAnalyzerByRushConfiguration: + | WeakMap + | undefined; + + private _rushConfiguration: RushConfiguration; + private _analysisByVariantBySubspace: Map> | undefined; + + private constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public static forRushConfiguration(rushConfiguration: RushConfiguration): DependencyAnalyzer { + if (!DependencyAnalyzer._dependencyAnalyzerByRushConfiguration) { + DependencyAnalyzer._dependencyAnalyzerByRushConfiguration = new WeakMap(); + } + + let analyzer: DependencyAnalyzer | undefined = + DependencyAnalyzer._dependencyAnalyzerByRushConfiguration.get(rushConfiguration); + if (!analyzer) { + analyzer = new DependencyAnalyzer(rushConfiguration); + DependencyAnalyzer._dependencyAnalyzerByRushConfiguration.set(rushConfiguration, analyzer); + } + + return analyzer; + } + + public getAnalysis( + subspace: Subspace | undefined, + variant: string | undefined, + addAction: boolean + ): IDependencyAnalysis { + // Use an empty string as the key when no variant provided. Anything else would possibly conflict + // with a variant created by the user + const variantKey: string = variant || ''; + + if (!this._analysisByVariantBySubspace) { + this._analysisByVariantBySubspace = new Map(); + } + + const subspaceToAnalyze: Subspace = subspace || this._rushConfiguration.defaultSubspace; + let analysisForVariant: WeakMap | undefined = + this._analysisByVariantBySubspace.get(variantKey); + + if (!analysisForVariant) { + analysisForVariant = new WeakMap(); + this._analysisByVariantBySubspace.set(variantKey, analysisForVariant); + } + + let analysisForSubspace: IDependencyAnalysis | undefined = analysisForVariant.get(subspaceToAnalyze); + if (!analysisForSubspace) { + analysisForSubspace = this._getAnalysisInternal(subspaceToAnalyze, variant, addAction); + + analysisForVariant.set(subspaceToAnalyze, analysisForSubspace); + } + + return analysisForSubspace; + } + + /** + * Generates the {@link IDependencyAnalysis}. + * + * @remarks + * The result of this function is not cached. + */ + private _getAnalysisInternal( + subspace: Subspace, + variant: string | undefined, + addAction: boolean + ): IDependencyAnalysis { + const commonVersionsConfiguration: CommonVersionsConfiguration = subspace.getCommonVersions(variant); + const allVersionsByPackageName: Map> = new Map(); + const allowedAlternativeVersions: Map< + string, + ReadonlyArray + > = commonVersionsConfiguration.allowedAlternativeVersions; + + let projectsToProcess: RushConfigurationProject[] = this._rushConfiguration.projects; + if (addAction && this._rushConfiguration.subspacesFeatureEnabled) { + projectsToProcess = subspace.getProjects(); + } + + for (const project of projectsToProcess) { + const dependencies: PackageJsonDependency[] = [ + ...project.packageJsonEditor.dependencyList, + ...project.packageJsonEditor.devDependencyList + ]; + for (const { name: dependencyName, version: dependencyVersion, dependencyType } of dependencies) { + if (dependencyType === DependencyType.Peer) { + // If this is a peer dependency, it isn't a real dependency in this context, so it shouldn't + // be included in the list of dependency versions. + 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); + if (localProject) { + if ( + !project.decoupledLocalDependencies.has(dependencyName) && + semver.satisfies(localProject.packageJson.version, dependencyVersion) + ) { + // For now, ignore local dependencies (that aren't cyclic dependencies). + continue; + } + } + + let allVersionForDependency: Set | undefined = allVersionsByPackageName.get(dependencyName); + if (!allVersionForDependency) { + allVersionForDependency = new Set(); + allVersionsByPackageName.set(dependencyName, allVersionForDependency); + } + + allVersionForDependency.add(dependencyVersion); + } + } + + const implicitlyPreferredVersionByPackageName: Map = new Map(); + // Only generate implicitly preferred versions when requested + const useImplicitlyPreferredVersions: boolean = + commonVersionsConfiguration.implicitlyPreferredVersions ?? true; + if (useImplicitlyPreferredVersions) { + for (const [dependencyName, versions] of allVersionsByPackageName) { + // For each dependency, we're collecting the set of all version specifiers that appear across the repo. + // If there is only one version specifier, then that's the "preferred" one. + + const alternativesForThisDependency: ReadonlySet = new Set( + allowedAlternativeVersions.get(dependencyName) + ); + + let implicitlyPreferredVersion: string | undefined = undefined; + for (const version of versions) { + // Versions listed in the common-versions.json's "allowedAlternativeVersions" property + // can be safely ignored in determining the set of implicitly preferred versions. + // (Even if it's the only version specifier anywhere in the repo, we still ignore it, because + // otherwise the rule would be difficult to explain.) + if (!alternativesForThisDependency.has(version)) { + if (implicitlyPreferredVersion === undefined) { + // There isn't a candidate for an implicitly preferred version yet. Set this value as a candidate. + implicitlyPreferredVersion = version; + } else { + // There was already another version that was a candidate. Clear that out and break. + // This dependency does not have an implicitly preferred version because there are at least + // two candidates. + implicitlyPreferredVersion = undefined; + break; + } + } + } + + if (implicitlyPreferredVersion !== undefined) { + implicitlyPreferredVersionByPackageName.set(dependencyName, implicitlyPreferredVersion); + } + } + } + + return { + commonVersionsConfiguration, + implicitlyPreferredVersionByPackageName, + allVersionsByPackageName + }; + } +} diff --git a/libraries/rush-lib/src/logic/DependencySpecifier.ts b/libraries/rush-lib/src/logic/DependencySpecifier.ts new file mode 100644 index 00000000000..f43e4110f9a --- /dev/null +++ b/libraries/rush-lib/src/logic/DependencySpecifier.ts @@ -0,0 +1,255 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import npmPackageArg from 'npm-package-arg'; + +import { InternalError } from '@rushstack/node-core-library'; + +/** + * match workspace protocol in dependencies value declaration in `package.json` + * example: + * `"workspace:*"` + * `"workspace:alias@1.2.3"` + */ +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) + */ +class WorkspaceSpec { + public readonly alias?: string; + public readonly version: string; + public readonly versionSpecifier: string; + + public constructor(version: string, alias?: string) { + this.version = version; + this.alias = alias; + this.versionSpecifier = alias ? `${alias}@${version}` : version; + } + + public static tryParse(pref: string): WorkspaceSpec | undefined { + const parts: RegExpExecArray | null = WORKSPACE_PREFIX_REGEX.exec(pref); + if (parts?.groups) { + return new WorkspaceSpec(parts.groups.version, parts.groups.alias); + } + } + + public toString(): `workspace:${string}` { + return `workspace:${this.versionSpecifier}`; + } +} + +/** + * 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. + */ +export enum DependencySpecifierType { + /** + * A git repository + */ + Git = 'Git', + + /** + * A tagged version, e.g. "example@latest" + */ + Tag = 'Tag', + + /** + * A specific version number, e.g. "example@1.2.3" + */ + Version = 'Version', + + /** + * A version range, e.g. "example@2.x" + */ + Range = 'Range', + + /** + * A local .tar.gz, .tar or .tgz file + */ + File = 'File', + + /** + * A local directory + */ + Directory = 'Directory', + + /** + * An HTTP url to a .tar.gz, .tar or .tgz file + */ + Remote = 'Remote', + + /** + * A package alias, e.g. "npm:other-package@^1.2.3" + */ + Alias = 'Alias', + + /** + * A package specified using workspace protocol, e.g. "workspace:^1.2.3" + */ + 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. + * A "dependency specifier" is the version specifier information, combined with the dependency package name. + */ +export class DependencySpecifier { + /** + * The dependency package name, i.e. the key from a "dependencies" key/value table. + */ + public readonly packageName: string; + + /** + * The dependency version specifier, i.e. the value from a "dependencies" key/value table. + * Example values: `^1.2.3`, `file:./blah.tgz`, `npm:other-package@~1.2.3` + */ + public readonly versionSpecifier: string; + + /** + * The type of the `versionSpecifier`. + */ + public readonly specifierType: DependencySpecifierType; + + /** + * If `specifierType` is `alias`, then this is the parsed target dependency. + * For example, if version specifier i `"npm:other-package@^1.2.3"` then this is the parsed object for + * `other-package@^1.2.3`. + */ + public readonly aliasTarget: DependencySpecifier | undefined; + + public constructor(packageName: string, versionSpecifier: string) { + 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); + if (workspaceSpecResult) { + this.specifierType = DependencySpecifierType.Workspace; + this.versionSpecifier = workspaceSpecResult.versionSpecifier; + + if (workspaceSpecResult.alias) { + // "workspace:some-package@^1.2.3" should be resolved as alias + this.aliasTarget = DependencySpecifier.parseWithCache( + workspaceSpecResult.alias, + workspaceSpecResult.version + ); + } else { + this.aliasTarget = undefined; + } + + return; + } + + const result: npmPackageArg.Result = npmPackageArg.resolve(packageName, versionSpecifier); + this.specifierType = DependencySpecifier.getDependencySpecifierType(result.type); + + if (this.specifierType === DependencySpecifierType.Alias) { + const aliasResult: npmPackageArg.AliasResult = result as npmPackageArg.AliasResult; + if (!aliasResult.subSpec || !aliasResult.subSpec.name) { + throw new InternalError('Unexpected result from npm-package-arg'); + } + 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': + return DependencySpecifierType.Git; + case 'tag': + return DependencySpecifierType.Tag; + case 'version': + return DependencySpecifierType.Version; + case 'range': + return DependencySpecifierType.Range; + case 'file': + return DependencySpecifierType.File; + case 'directory': + return DependencySpecifierType.Directory; + case 'remote': + return DependencySpecifierType.Remote; + case 'alias': + return DependencySpecifierType.Alias; + default: + throw new InternalError(`Unexpected npm-package-arg result type "${specifierType}"`); + } + } +} diff --git a/libraries/rush-lib/src/logic/EventHooksManager.ts b/libraries/rush-lib/src/logic/EventHooksManager.ts new file mode 100644 index 00000000000..a7324a8f119 --- /dev/null +++ b/libraries/rush-lib/src/logic/EventHooksManager.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Colorize } from '@rushstack/terminal'; + +import type { EventHooks } from '../api/EventHooks'; +import { type IEnvironment, Utilities } from '../utilities/Utilities'; +import { Event } from '../api/EventHooks'; +import { Stopwatch } from '../utilities/Stopwatch'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; + +export class EventHooksManager { + private _rushConfiguration: RushConfiguration; + private _eventHooks: EventHooks; + private _commonTempFolder: string; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + this._eventHooks = rushConfiguration.eventHooks; + this._commonTempFolder = rushConfiguration.commonTempFolder; + } + + public handle(event: Event, isDebug: boolean, ignoreHooks: boolean): void { + if (!this._eventHooks) { + return; + } + + const scripts: string[] = this._eventHooks.get(event); + if (scripts.length > 0) { + if (ignoreHooks) { + // eslint-disable-next-line no-console + console.log(`Skipping event hooks for ${Event[event]} since --ignore-hooks was specified`); + return; + } + + const stopwatch: Stopwatch = Stopwatch.start(); + // eslint-disable-next-line no-console + console.log('\n' + Colorize.green(`Executing event hooks for ${Event[event]}`)); + + const printEventHooksOutputToConsole: boolean | undefined = + isDebug || + this._rushConfiguration.experimentsConfiguration.configuration.printEventHooksOutputToConsole; + scripts.forEach((script) => { + try { + const environment: IEnvironment = { ...process.env }; + + // NOTE: Do NOT expose this variable to other subprocesses besides telemetry hooks. We do NOT want + // child processes to inspect Rush's raw command line and magically change their behavior in a way + // that might be confusing to end users, or rely on CLI parameters that the build cache is unaware of. + environment[EnvironmentVariableNames.RUSH_INVOKED_ARGS] = JSON.stringify(process.argv); + + Utilities.executeLifecycleCommand(script, { + rushConfiguration: this._rushConfiguration, + workingDirectory: this._rushConfiguration.rushJsonFolder, + initCwd: this._commonTempFolder, + handleOutput: !printEventHooksOutputToConsole, + initialEnvironment: environment, + environmentPathOptions: { + includeRepoBin: true + } + }); + } catch (error) { + // eslint-disable-next-line no-console + console.error( + '\n' + + Colorize.yellow( + `Event hook "${script}" failed: ${error}\nRun "rush" with --debug` + + ` to see detailed error information.` + ) + ); + if (isDebug) { + // eslint-disable-next-line no-console + console.error('\n' + (error as Error).message); + } + } + }); + stopwatch.stop(); + // eslint-disable-next-line no-console + console.log('\n' + Colorize.green(`Event hooks finished. (${stopwatch.toString()})`)); + } + } +} diff --git a/libraries/rush-lib/src/logic/Git.ts b/libraries/rush-lib/src/logic/Git.ts new file mode 100644 index 00000000000..3877f6e5f9f --- /dev/null +++ b/libraries/rush-lib/src/logic/Git.ts @@ -0,0 +1,636 @@ +// 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 'node:child_process'; +import * as path from 'node:path'; +import * as url from 'node:url'; + +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'; + +import { Utilities } from '../utilities/Utilities'; +import * as GitEmailPolicy from './policy/GitEmailPolicy'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; +import { type IChangedGitStatusEntry, type IGitStatusEntry, parseGitStatus } from './GitStatusParser'; +import { RushConstants } from './RushConstants'; + +export const DEFAULT_GIT_TAG_SEPARATOR: string = '_'; + +interface IResultOrError { + error?: Error; + result?: TResult; +} + +export interface IGetBlobOptions { + blobSpec: string; + repositoryRoot: string; +} + +export class Git { + private readonly _rushConfiguration: RushConfiguration; + private _checkedGitPath: boolean = false; + private _gitPath: string | undefined; + private _checkedGitInfo: boolean = false; + private _gitInfo: gitInfo.GitRepoInfo | undefined; + + private _gitEmailResult: IResultOrError | undefined = undefined; + private _gitHooksPath: IResultOrError | undefined = undefined; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + /** + * Returns the path to the Git binary if found. Otherwise, return undefined. + */ + public get gitPath(): string | undefined { + if (!this._checkedGitPath) { + this._gitPath = EnvironmentConfiguration.gitBinaryPath || Executable.tryResolve('git'); + this._checkedGitPath = true; + } + + return this._gitPath; + } + + public getGitPathOrThrow(): string { + const gitPath: string | undefined = this.gitPath; + if (!gitPath) { + throw new Error('Git is not present'); + } else { + return gitPath; + } + } + + /** + * Returns true if the Git binary can be found. + */ + public isGitPresent(): boolean { + return !!this.gitPath; + } + + /** + * Returns true if the Git binary was found and the current path is under a Git working tree. + * @param repoInfo - If provided, do the check based on this Git repo info. If not provided, + * the result of `this.getGitInfo()` is used. + */ + public isPathUnderGitWorkingTree(repoInfo?: gitInfo.GitRepoInfo): boolean { + if (this.isGitPresent()) { + // Do we even have a Git binary? + if (!repoInfo) { + repoInfo = this.getGitInfo(); + } + return !!(repoInfo && repoInfo.sha); + } else { + return false; + } + } + + /** + * If a Git email address is configured and is nonempty, this returns it. + * Otherwise, configuration instructions are printed to the console, + * and AlreadyReportedError is thrown. + */ + public async getGitEmailAsync(): Promise { + // Determine the user's account + // Ex: "bob@example.com" + const { error, result } = await this._tryGetGitEmailAsync(); + if (error) { + // eslint-disable-next-line no-console + console.log( + [ + `Error: ${error.message}`, + 'Unable to determine your Git configuration using this command:', + '', + ' git config user.email', + '' + ].join('\n') + ); + throw new AlreadyReportedError(); + } + return this.validateGitEmail(result); + } + + /** + * If the Git email address is configured and non-empty, this returns it. Otherwise + * it prints an error message and throws. + */ + public validateGitEmail(userEmail: string | undefined): string { + if (userEmail === undefined || userEmail.length === 0) { + // eslint-disable-next-line no-console + console.log( + [ + 'This operation requires that a Git email be specified.', + '', + `If you didn't configure your email yet, try something like this:`, + '', + ...GitEmailPolicy.getEmailExampleLines(this._rushConfiguration), + '' + ].join('\n') + ); + throw new AlreadyReportedError(); + } + + return userEmail; + } + + /** + * Get the folder where Git hooks should go for the current working tree. + * Returns undefined if the current path is not under a Git working tree. + */ + public getHooksFolder(): string | undefined { + const repoInfo: gitInfo.GitRepoInfo | undefined = this.getGitInfo(); + if (repoInfo && repoInfo.worktreeGitDir) { + return path.join(repoInfo.worktreeGitDir, 'hooks'); + } + return undefined; + } + + public async getIsHooksPathDefaultAsync(): Promise { + const repoInfo: gitInfo.GitRepoInfo | undefined = this.getGitInfo(); + if (!repoInfo?.commonGitDir) { + // This should have never been called in a non-Git environment + return true; + } + let commonGitDir: string = repoInfo.commonGitDir; + try { + commonGitDir = trueCasePathSync(commonGitDir); + } catch (error) { + /* ignore errors from true-case-path */ + } + const defaultHooksPath: string = path.resolve(commonGitDir, 'hooks'); + const hooksResult: IResultOrError = await this._tryGetGitHooksPathAsync(); + if (hooksResult.error) { + // eslint-disable-next-line no-console + console.log( + [ + `Error: ${hooksResult.error.message}`, + 'Unable to determine your Git configuration using this command:', + '', + ' git rev-parse --git-path hooks', + '', + 'Assuming hooks can still be installed in the default location' + ].join('\n') + ); + return true; + } + + if (hooksResult.result) { + const absoluteHooksPath: string = path.resolve( + this._rushConfiguration.rushJsonFolder, + hooksResult.result + ); + return absoluteHooksPath === defaultHooksPath; + } + + // No error, but also empty result? Not sure it's possible. + return true; + } + + public async getConfigHooksPathAsync(): Promise { + let configHooksPath: string = ''; + const gitPath: string = this.getGitPathOrThrow(); + try { + configHooksPath = ( + await this._executeGitCommandAndCaptureOutputAsync(gitPath, ['config', 'core.hooksPath']) + ).trim(); + } catch (e) { + // git config returns error code 1 if core.hooksPath is not set. + } + return configHooksPath; + } + + /** + * Get information about the current Git working tree. + * Returns undefined if rush.json is not under a Git working tree. + */ + public getGitInfo(): Readonly | undefined { + if (!this._checkedGitInfo) { + let repoInfo: gitInfo.GitRepoInfo | undefined; + try { + // gitInfo() shouldn't usually throw, but wrapping in a try/catch just in case + repoInfo = gitInfo(this._rushConfiguration.rushJsonFolder); + } catch (ex) { + // if there's an error, assume we're not in a Git working tree + } + + if (repoInfo && this.isPathUnderGitWorkingTree(repoInfo)) { + this._gitInfo = repoInfo; + } + this._checkedGitInfo = true; + } + return this._gitInfo; + } + + public async getMergeBaseAsync( + targetBranch: string, + terminal: ITerminal, + shouldFetch: boolean = false + ): Promise { + if (shouldFetch) { + this._fetchRemoteBranch(targetBranch, terminal); + } + + const gitPath: string = this.getGitPathOrThrow(); + try { + const output: string = await this._executeGitCommandAndCaptureOutputAsync(gitPath, [ + '--no-optional-locks', + 'merge-base', + '--', + 'HEAD', + targetBranch + ]); + const result: string = output.trim(); + + return result; + } catch (e) { + terminal.writeErrorLine( + `Unable to determine merge base for branch "${targetBranch}". ` + + 'This can occur if the current clone is a shallow clone. If this clone is running in a CI ' + + 'pipeline, check your pipeline settings to ensure that the clone depth includes ' + + 'the expected merge base. If this clone is running locally, consider running "git fetch --deepen=".' + ); + throw new AlreadyReportedError(); + } + } + + public async getBlobContentAsync({ blobSpec, repositoryRoot }: IGetBlobOptions): Promise { + const gitPath: string = this.getGitPathOrThrow(); + const output: string = await this._executeGitCommandAndCaptureOutputAsync( + gitPath, + ['cat-file', 'blob', blobSpec, '--'], + repositoryRoot + ); + + return output; + } + + /** + * @param pathPrefix - An optional path prefix "git diff"s should be filtered by. + * @returns + * An array of paths of repo-root-relative paths of files that are different from + * those in the provided {@param targetBranch}. If a {@param pathPrefix} is provided, + * this function only returns results under the that path. + */ + public async getChangedFilesAsync( + targetBranch: string, + terminal: ITerminal, + skipFetch: boolean = false, + pathPrefix?: string + ): Promise { + if (!skipFetch) { + this._fetchRemoteBranch(targetBranch, terminal); + } + + const gitPath: string = this.getGitPathOrThrow(); + const output: string = await this._executeGitCommandAndCaptureOutputAsync(gitPath, [ + 'diff', + `${targetBranch}...`, + '--name-only', + '--no-renames', + '--diff-filter=A' + ]); + return output + .split('\n') + .map((line) => { + if (line) { + const trimmedLine: string = line.trim(); + if (!pathPrefix || Path.isUnderOrEqual(trimmedLine, pathPrefix)) { + return trimmedLine; + } + } else { + return undefined; + } + }) + .filter((line) => { + return line && line.length > 0; + }) as string[]; + } + + /** + * Gets the remote default branch that maps to the provided repository url. + * This method is used by 'Rush change' to find the default remote branch to compare against. + * If repository url is not provided or if there is no match, returns the default remote's + * default branch 'origin/main'. + * If there are more than one matches, returns the first remote's default branch. + * + * @param rushConfiguration - rush configuration + */ + public async getRemoteDefaultBranchAsync(): Promise { + const repositoryUrls: string[] = this._rushConfiguration.repositoryUrls; + if (repositoryUrls.length > 0) { + const gitPath: string = this.getGitPathOrThrow(); + const output: string = (await this._executeGitCommandAndCaptureOutputAsync(gitPath, ['remote'])).trim(); + + const normalizedRepositoryUrls: Set = new Set(); + for (const repositoryUrl of repositoryUrls) { + // Apply toUpperCase() for a case-insensitive comparison + normalizedRepositoryUrls.add(Git.normalizeGitUrlForComparison(repositoryUrl).toUpperCase()); + } + + const matchingRemotes: string[] = []; + await Async.forEachAsync( + output.split('\n'), + async (remoteName) => { + if (remoteName) { + const remoteUrl: string = ( + await this._executeGitCommandAndCaptureOutputAsync(gitPath, [ + 'remote', + 'get-url', + '--', + remoteName + ]) + ).trim(); + + if (remoteUrl) { + // Also apply toUpperCase() for a case-insensitive comparison + const normalizedRemoteUrl: string = Git.normalizeGitUrlForComparison(remoteUrl).toUpperCase(); + if (normalizedRepositoryUrls.has(normalizedRemoteUrl)) { + matchingRemotes.push(remoteName); + } + } + } + }, + { concurrency: 10 } + ); + + if (matchingRemotes.length > 0) { + if (matchingRemotes.length > 1) { + // eslint-disable-next-line no-console + console.log( + `More than one git remote matches the repository URL. Using the first remote (${matchingRemotes[0]}).` + ); + } + + return `${matchingRemotes[0]}/${this._rushConfiguration.repositoryDefaultBranch}`; + } else { + const errorMessage: string = + repositoryUrls.length > 1 + ? `Unable to find a git remote matching one of the repository URLs (${repositoryUrls.join( + ', ' + )}). ` + : `Unable to find a git remote matching the repository URL (${repositoryUrls[0]}). `; + // eslint-disable-next-line no-console + console.log(Colorize.yellow(errorMessage + 'Detected changes are likely to be incorrect.')); + + return this._rushConfiguration.repositoryDefaultFullyQualifiedRemoteBranch; + } + } else { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `A git remote URL has not been specified in ${RushConstants.rushJsonFilename}. Setting the baseline remote URL is recommended.` + ) + ); + return this._rushConfiguration.repositoryDefaultFullyQualifiedRemoteBranch; + } + } + + public async hasUncommittedChangesAsync(): Promise { + const gitStatusEntries: Iterable = await this.getGitStatusAsync(); + for (const _ of gitStatusEntries) { + // If there are any changes, return true. We only need to evaluate the first iterator entry + return true; + } + + return false; + } + + public async hasUnstagedChangesAsync(): Promise { + const gitStatusEntries: Iterable = await this.getGitStatusAsync(); + for (const gitStatusEntry of gitStatusEntries) { + if ( + gitStatusEntry.kind === 'untracked' || + (gitStatusEntry as IChangedGitStatusEntry).unstagedChangeType !== undefined + ) { + return true; + } + } + + return false; + } + + /** + * The list of files changed but not committed + */ + public async getUncommittedChangesAsync(): Promise> { + const result: string[] = []; + const gitStatusEntries: Iterable = await this.getGitStatusAsync(); + for (const gitStatusEntry of gitStatusEntries) { + result.push(gitStatusEntry.path); + } + + return result; + } + + public getTagSeparator(): string { + return this._rushConfiguration.gitTagSeparator || DEFAULT_GIT_TAG_SEPARATOR; + } + + public async getGitStatusAsync(): Promise> { + const gitPath: string = this.getGitPathOrThrow(); + // See Git.test.ts for example output + const output: string = await this._executeGitCommandAndCaptureOutputAsync(gitPath, [ + 'status', + '--porcelain=2', + '--null', + '--ignored=no' + ]); + + return parseGitStatus(output); + } + + /** + * Git remotes can use different URL syntaxes; this converts them all to a normalized HTTPS + * representation for matching purposes. IF THE INPUT IS NOT ALREADY HTTPS, THE OUTPUT IS + * NOT NECESSARILY A VALID GIT URL. + * + * @example + * `git@github.com:ExampleOrg/ExampleProject.git` --> `https://github.com/ExampleOrg/ExampleProject` + */ + public static normalizeGitUrlForComparison(gitUrl: string): string { + // Git URL formats are documented here: https://www.git-scm.com/docs/git-clone#_git_urls + + let result: string = gitUrl.trim(); + + // [user@]host.xz:path/to/repo.git/ + // "This syntax is only recognized if there are no slashes before the first colon. This helps + // differentiate a local path that contains a colon." + // + // Match patterns like this: + // user@host.ext:path/to/repo + // host.ext:path/to/repo + // localhost:/~user/path/to/repo + // + // But not: + // http://blah + // c:/windows/path.txt + // + const scpLikeSyntaxRegExp: RegExp = /^(?:[^@:\/]+\@)?([^:\/]{2,})\:((?!\/\/).+)$/; + + // Example: "user@host.ext:path/to/repo" + const scpLikeSyntaxMatch: RegExpExecArray | null = scpLikeSyntaxRegExp.exec(gitUrl); + if (scpLikeSyntaxMatch) { + // Example: "host.ext" + const host: string = scpLikeSyntaxMatch[1]; + // Example: "path/to/repo" + const urlPath: string = scpLikeSyntaxMatch[2]; + + if (urlPath.startsWith('/')) { + result = `https://${host}${urlPath}`; + } else { + result = `https://${host}/${urlPath}`; + } + } + + 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; + } + + // Trim ".git" or ".git/" from the end + result = result.replace(/.git\/?$/, ''); + return result; + } + + /** + * This will throw errors only if we cannot find Git commandline. + * If git email didn't configure, this will return undefined; otherwise, + * returns user.email config + */ + public async tryGetGitEmailAsync(): Promise { + const { result } = await this._tryGetGitEmailAsync(); + return result; + } + + /** + * Returns an object containing either the result of the `git config user.email` + * command or an error. + */ + private async _tryGetGitEmailAsync(): Promise> { + if (this._gitEmailResult === undefined) { + const gitPath: string = this.getGitPathOrThrow(); + try { + this._gitEmailResult = { + result: ( + await this._executeGitCommandAndCaptureOutputAsync(gitPath, ['config', 'user.email']) + ).trim() + }; + } catch (e) { + this._gitEmailResult = { + error: e as Error + }; + } + } + + return this._gitEmailResult; + } + + private async _tryGetGitHooksPathAsync(): Promise> { + if (this._gitHooksPath === undefined) { + const gitPath: string = this.getGitPathOrThrow(); + try { + this._gitHooksPath = { + result: ( + await this._executeGitCommandAndCaptureOutputAsync(gitPath, ['rev-parse', '--git-path', 'hooks']) + ).trim() + }; + } catch (e) { + this._gitHooksPath = { + error: e as Error + }; + } + } + + return this._gitHooksPath; + } + + private _tryFetchRemoteBranch(remoteBranchName: string): boolean { + const firstSlashIndex: number = remoteBranchName.indexOf('/'); + if (firstSlashIndex === -1) { + throw new Error( + `Unexpected git remote branch format: ${remoteBranchName}. ` + + 'Expected branch to be in the / format.' + ); + } + + const remoteName: string = remoteBranchName.substr(0, firstSlashIndex); + const branchName: string = remoteBranchName.substr(firstSlashIndex + 1); + const gitPath: string = this.getGitPathOrThrow(); + const spawnResult: child_process.SpawnSyncReturns = Executable.spawnSync( + gitPath, + ['fetch', '--', remoteName, branchName], + { + stdio: 'ignore' + } + ); + return spawnResult.status === 0; + } + + private _fetchRemoteBranch(remoteBranchName: string, terminal: ITerminal): void { + // eslint-disable-next-line no-console + console.log(`Checking for updates to ${remoteBranchName}...`); + const fetchResult: boolean = this._tryFetchRemoteBranch(remoteBranchName); + if (!fetchResult) { + terminal.writeWarningLine( + `Error fetching git remote branch ${remoteBranchName}. Detected changed files may be incorrect.` + ); + } + } + + /** + * @internal + */ + public async _executeGitCommandAndCaptureOutputAsync( + gitPath: string, + args: string[], + repositoryRoot: string = this._rushConfiguration.rushJsonFolder + ): Promise { + try { + return await Utilities.executeCommandAndCaptureOutputAsync(gitPath, args, repositoryRoot); + } catch (e) { + ensureGitMinimumVersion(gitPath); + throw e; + } + } + /** + * + * @param ref Given a ref which can be branch name, commit hash, tag name, etc, check if it is a commit hash + */ + public async determineIfRefIsACommitAsync(ref: string): Promise { + const gitPath: string = this.getGitPathOrThrow(); + try { + const output: string = await this._executeGitCommandAndCaptureOutputAsync(gitPath, [ + 'rev-parse', + '--verify', + ref + ]); + const result: string = output.trim(); + + return result === ref; + } catch (e) { + // assume not a commit + return false; + } + } +} diff --git a/libraries/rush-lib/src/logic/GitStatusParser.ts b/libraries/rush-lib/src/logic/GitStatusParser.ts new file mode 100644 index 00000000000..d4d41294748 --- /dev/null +++ b/libraries/rush-lib/src/logic/GitStatusParser.ts @@ -0,0 +1,372 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IGitStatusEntryBase { + kind: 'untracked' | 'changed' | 'unmerged' | 'renamed' | 'copied'; + path: string; +} + +export interface IUntrackedGitStatusEntry extends IGitStatusEntryBase { + kind: 'untracked'; +} + +export type GitStatusChangeType = 'added' | 'deleted' | 'modified' | 'renamed' | 'copied' | 'type-changed'; + +export interface IChangedGitStatusEntryFields { + stagedChangeType: GitStatusChangeType | undefined; + unstagedChangeType: GitStatusChangeType | undefined; + isInSubmodule: boolean; + headFileMode: string; + indexFileMode: string; + worktreeFileMode: string; + headObjectName: string; + indexObjectName: string; +} + +export interface IChangedGitStatusEntry extends IGitStatusEntryBase, IChangedGitStatusEntryFields { + kind: 'changed'; +} + +export interface IRenamedOrCopiedGitStatusEntry extends IGitStatusEntryBase, IChangedGitStatusEntryFields { + kind: 'renamed' | 'copied'; + renameOrCopyScore: number; + originalPath: string; +} + +export interface IUnmergedGitStatusEntry extends IGitStatusEntryBase { + kind: 'unmerged'; + stagedChangeType: GitStatusChangeType | undefined; + unstagedChangeType: GitStatusChangeType | undefined; + isInSubmodule: boolean; + stage1FileMode: string; + stage2FileMode: string; + stage3FileMode: string; + worktreeFileMode: string; + stage1ObjectName: string; + stage2ObjectName: string; + stage3ObjectName: string; +} + +export type IGitStatusEntry = + | IUntrackedGitStatusEntry + | IChangedGitStatusEntry + | IRenamedOrCopiedGitStatusEntry + | IUnmergedGitStatusEntry; + +function _parseGitStatusChangeType(str: string): GitStatusChangeType | undefined { + switch (str) { + case 'M': { + return 'modified'; + } + + case 'T': { + return 'type-changed'; + } + + case 'A': { + return 'added'; + } + + case 'D': { + return 'deleted'; + } + + case 'R': { + return 'renamed'; + } + + case 'C': { + return 'copied'; + } + + case '.': { + return undefined; + } + + default: { + throw new Error(`Unexpected git status change type: ${str}`); + } + } +} + +function _parseIsInSubmodule(submoduleState: string): boolean { + // This field is actually four characters long, but this parser only handles if the entry is in a + // submodule or not. That is represented by a "N" or an "S" in the first character. + const submoduleMode: string = submoduleState.charAt(0); + if (submoduleMode === 'N') { + return false; + } else if (submoduleMode === 'S') { + return true; + } else { + throw new Error(`Unexpected submodule state: ${submoduleState}`); + } +} + +export function* parseGitStatus(gitStatusOutput: string): Iterable { + // See reference https://git-scm.com/docs/git-status?msclkid=1cff552bcdce11ecadf77a086eded66c#_porcelain_format_version_2 + + let pos: number = 0; + + function getFieldAndAdvancePos(delimiter: string): string { + const newPos: number = gitStatusOutput.indexOf(delimiter, pos); + if (newPos === -1) { + throw new Error(`Unexpected end of git status output after position ${pos}`); + } + + const field: string = gitStatusOutput.substring(pos, newPos); + pos = newPos + delimiter.length; + return field; + } + + /** + * @example + * ``` + * ? path/g.ts + * ``` + */ + function parseUntrackedEntry(): IUntrackedGitStatusEntry { + const path: string = getFieldAndAdvancePos('\0'); + const entry: IUntrackedGitStatusEntry = { + kind: 'untracked', + path + }; + return entry; + } + + /** + * @example + * ``` + * 1 A. N... 000000 100644 100644 0000000000000000000000000000000000000000 a171a25d2c978ba071959f39dbeaa339fe84f768 path/a.ts\0 + * 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + * 1 .D N... 100644 100644 000000 3fcb58810c113c90c366dd81d16443425c7b95fa 3fcb58810c113c90c366dd81d16443425c7b95fa path/c.ts\0 + * 1 D. N... 100644 000000 000000 91b0203b85a7bb605e35f842d1d05d66a6275e10 0000000000000000000000000000000000000000 path/d.ts\0 + * 1 A. N... 000000 100644 100644 0000000000000000000000000000000000000000 451de43c5cb012af55a79cc3463849ab3cfa0457 path/f.ts\0 + * 1 AM N... 000000 100644 100644 0000000000000000000000000000000000000000 9d9ab4adc79c591c0aa72f7fd29a008c80893e3e path/h.ts\0 + * ``` + */ + function parseAddModifyOrDeleteEntry(): IChangedGitStatusEntry { + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const changeTypeField: string = getFieldAndAdvancePos(' '); + const rawStagedChangeType: string = changeTypeField.charAt(0); + const stagedChangeType: GitStatusChangeType | undefined = _parseGitStatusChangeType(rawStagedChangeType); + const rawUnstagedChangeType: string = changeTypeField.charAt(1); + const unstagedChangeType: GitStatusChangeType | undefined = + _parseGitStatusChangeType(rawUnstagedChangeType); + + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const submoduleState: string = getFieldAndAdvancePos(' '); + const isInSubmodule: boolean = _parseIsInSubmodule(submoduleState); + + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const headFileMode: string = getFieldAndAdvancePos(' '); + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const indexFileMode: string = getFieldAndAdvancePos(' '); + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const worktreeFileMode: string = getFieldAndAdvancePos(' '); + + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const headObjectName: string = getFieldAndAdvancePos(' '); + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const indexObjectName: string = getFieldAndAdvancePos(' '); + + // 1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts\0 + // ^ + const path: string = getFieldAndAdvancePos('\0'); + + const entry: IChangedGitStatusEntry = { + kind: 'changed', + stagedChangeType, + unstagedChangeType, + isInSubmodule, + headFileMode, + indexFileMode, + worktreeFileMode, + headObjectName, + indexObjectName, + path + }; + return entry; + } + + /** + * @example + * ``` + * 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + * ``` + */ + function parseRenamedOrCopiedEntry(): IRenamedOrCopiedGitStatusEntry { + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const changeTypeField: string = getFieldAndAdvancePos(' '); + const rawStagedChangeType: string = changeTypeField.charAt(0); + const stagedChangeType: GitStatusChangeType | undefined = _parseGitStatusChangeType(rawStagedChangeType); + const rawUnstagedChangeType: string = changeTypeField.charAt(1); + const unstagedChangeType: GitStatusChangeType | undefined = + _parseGitStatusChangeType(rawUnstagedChangeType); + + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const submoduleState: string = getFieldAndAdvancePos(' '); + const isInSubmodule: boolean = _parseIsInSubmodule(submoduleState); + + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const headFileMode: string = getFieldAndAdvancePos(' '); + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const indexFileMode: string = getFieldAndAdvancePos(' '); + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const worktreeFileMode: string = getFieldAndAdvancePos(' '); + + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const headObjectName: string = getFieldAndAdvancePos(' '); + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const indexObjectName: string = getFieldAndAdvancePos(' '); + + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const renameOrCopyScoreField: string = getFieldAndAdvancePos(' '); + const renameOrCopyMode: string = renameOrCopyScoreField.charAt(0); + const rawRenameOrCopyScore: string = renameOrCopyScoreField.substring(1); + const renameOrCopyScore: number = parseInt(rawRenameOrCopyScore, 10); + let kind: 'renamed' | 'copied'; + if (renameOrCopyMode === 'R') { + kind = 'renamed'; + } else if (renameOrCopyMode === 'C') { + kind = 'copied'; + } else { + throw new Error(`Unexpected rename or copy mode: ${renameOrCopyMode}`); + } + + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const path: string = getFieldAndAdvancePos('\0'); + // 2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts\0e2.ts\0 + // ^ + const originalPath: string = getFieldAndAdvancePos('\0'); + + const entry: IRenamedOrCopiedGitStatusEntry = { + kind, + stagedChangeType, + unstagedChangeType, + isInSubmodule, + headFileMode, + indexFileMode, + worktreeFileMode, + headObjectName, + indexObjectName, + renameOrCopyScore, + path, + originalPath + }; + return entry; + } + + /** + * @example + * ``` + * u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + * ``` + */ + function parseUnmergedEntry(): IUnmergedGitStatusEntry { + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const changeTypeField: string = getFieldAndAdvancePos(' '); + const rawStagedChangeType: string = changeTypeField.charAt(0); + const stagedChangeType: GitStatusChangeType | undefined = _parseGitStatusChangeType(rawStagedChangeType); + const rawUnstagedChangeType: string = changeTypeField.charAt(1); + const unstagedChangeType: GitStatusChangeType | undefined = + _parseGitStatusChangeType(rawUnstagedChangeType); + + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const submoduleState: string = getFieldAndAdvancePos(' '); + const isInSubmodule: boolean = _parseIsInSubmodule(submoduleState); + + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage1FileMode: string = getFieldAndAdvancePos(' '); + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage2FileMode: string = getFieldAndAdvancePos(' '); + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage3FileMode: string = getFieldAndAdvancePos(' '); + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const worktreeFileMode: string = getFieldAndAdvancePos(' '); + + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage1ObjectName: string = getFieldAndAdvancePos(' '); + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage2ObjectName: string = getFieldAndAdvancePos(' '); + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const stage3ObjectName: string = getFieldAndAdvancePos(' '); + + // u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts\0 + // ^ + const path: string = getFieldAndAdvancePos('\0'); + + const entry: IUnmergedGitStatusEntry = { + kind: 'unmerged', + stagedChangeType, + unstagedChangeType, + isInSubmodule, + stage1FileMode, + stage2FileMode, + stage3FileMode, + worktreeFileMode, + stage1ObjectName, + stage2ObjectName, + stage3ObjectName, + path + }; + return entry; + } + + while (pos < gitStatusOutput.length) { + const modeField: string = getFieldAndAdvancePos(' '); + switch (modeField) { + case '?': { + // Untracked + yield parseUntrackedEntry(); + break; + } + + case '1': { + // Simple change + yield parseAddModifyOrDeleteEntry(); + break; + } + + case '2': { + // Renamed or copied + yield parseRenamedOrCopiedEntry(); + break; + } + + case 'u': { + // Unmerged + yield parseUnmergedEntry(); + break; + } + + default: { + throw new Error(`Unexpected git status mode: ${modeField}`); + } + } + } +} diff --git a/libraries/rush-lib/src/logic/InstallManagerFactory.ts b/libraries/rush-lib/src/logic/InstallManagerFactory.ts new file mode 100644 index 00000000000..c86ad166c0e --- /dev/null +++ b/libraries/rush-lib/src/logic/InstallManagerFactory.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 { WorkspaceInstallManager } from './installManager/WorkspaceInstallManager'; +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'; + +export class InstallManagerFactory { + public static async getInstallManagerAsync( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ): Promise { + if ( + rushConfiguration.isPnpm && + rushConfiguration.pnpmOptions && + rushConfiguration.pnpmOptions.useWorkspaces + ) { + return new WorkspaceInstallManager(rushConfiguration, rushGlobalFolder, purgeManager, options); + } + + const rushInstallManagerModule: typeof import('./installManager/RushInstallManager') = await import( + /* webpackChunkName: 'RushInstallManager' */ + './installManager/RushInstallManager' + ); + return new rushInstallManagerModule.RushInstallManager( + rushConfiguration, + rushGlobalFolder, + purgeManager, + options + ); + } +} diff --git a/libraries/rush-lib/src/logic/InteractiveUpgrader.ts b/libraries/rush-lib/src/logic/InteractiveUpgrader.ts new file mode 100644 index 00000000000..493a2a25ffc --- /dev/null +++ b/libraries/rush-lib/src/logic/InteractiveUpgrader.ts @@ -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 Prompt from 'inquirer/lib/ui/prompt'; + +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 { SearchListPrompt } from '../utilities/prompts/SearchListPrompt'; + +interface IUpgradeInteractiveDeps { + projects: RushConfigurationProject[]; + depsToUpgrade: IDepsToUpgradeAnswers; +} + +export class InteractiveUpgrader { + private readonly _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public async upgradeAsync(): Promise { + const rushProject: RushConfigurationProject = await this._getUserSelectedProjectForUpgradeAsync(); + + const dependenciesState: INpmCheckPackageSummary[] = + await this._getPackageDependenciesStatusAsync(rushProject); + + const depsToUpgrade: IDepsToUpgradeAnswers = + await this._getUserSelectedDependenciesToUpgradeAsync(dependenciesState); + return { projects: [rushProject], depsToUpgrade }; + } + + private async _getUserSelectedDependenciesToUpgradeAsync( + 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 { + name: Colorize.green(project.packageName), + value: project + }; + }), + pageSize: 12 + } + ]); + + return selectProject; + } + + private async _getPackageDependenciesStatusAsync( + rushProject: RushConfigurationProject + ): Promise { + const { projectFolder } = rushProject; + + const currentState: INpmCheckState = await NpmCheck({ + cwd: projectFolder + }); + + return currentState.packages ?? []; + } +} diff --git a/libraries/rush-lib/src/logic/JsonSchemaUrls.ts b/libraries/rush-lib/src/logic/JsonSchemaUrls.ts new file mode 100644 index 00000000000..26be91f22ad --- /dev/null +++ b/libraries/rush-lib/src/logic/JsonSchemaUrls.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. + +/** + * JSON schema URLs that Rush writes into config files. + */ +export class JsonSchemaUrls { + public static readonly approvedPackages: string = + 'https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json'; + + public static readonly commonVersions: string = + 'https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json'; +} diff --git a/libraries/rush-lib/src/logic/LinkManagerFactory.ts b/libraries/rush-lib/src/logic/LinkManagerFactory.ts new file mode 100644 index 00000000000..810b3796a91 --- /dev/null +++ b/libraries/rush-lib/src/logic/LinkManagerFactory.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 { RushConfiguration } from '../api/RushConfiguration'; +import type { BaseLinkManager } from './base/BaseLinkManager'; +import { NpmLinkManager } from './npm/NpmLinkManager'; +import { PnpmLinkManager } from './pnpm/PnpmLinkManager'; + +export class LinkManagerFactory { + public static getLinkManager(rushConfiguration: RushConfiguration): BaseLinkManager { + switch (rushConfiguration.packageManager) { + case 'npm': + return new NpmLinkManager(rushConfiguration); + case 'pnpm': + return new PnpmLinkManager(rushConfiguration); + case 'yarn': + // Yarn uses the same node_modules structure as NPM + return new NpmLinkManager(rushConfiguration); + default: + throw new Error(`Unsupported package manager: ${rushConfiguration.packageManager}`); + } + } +} diff --git a/libraries/rush-lib/src/logic/NodeJsCompatibility.ts b/libraries/rush-lib/src/logic/NodeJsCompatibility.ts new file mode 100644 index 00000000000..ea760937f3e --- /dev/null +++ b/libraries/rush-lib/src/logic/NodeJsCompatibility.ts @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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 +// NodeJsCompatibility.terminateIfVersionIsTooOld() gets to run. +import type { RushConfiguration } from '../api/RushConfiguration'; +import { RushConstants } from './RushConstants'; + +/** + * This constant is the major version of the next LTS node Node.js release. This constant should be updated when + * a new LTS version is added to Rush's support matrix. + * + * LTS schedule: https://nodejs.org/en/about/releases/ + * LTS versions: https://nodejs.org/en/download/releases/ + */ +const UPCOMING_NODE_LTS_VERSION: number = 22; +const nodeVersion: string = process.versions.node; +const nodeMajorVersion: number = semver.major(nodeVersion); + +export interface IWarnAboutVersionTooNewOptions { + isRushLib: boolean; + + /** + * The CLI front-end does an early check for NodeJsCompatibility.warnAboutVersionTooNew(), + * so this flag is used to avoid reporting the same message twice. Note that the definition + * of "too new" may differ between the globally installed "@microsoft/rush" front end + * versus the "@microsoft/rush-lib" loaded by the version selector. + */ + alreadyReportedNodeTooNewError: boolean; +} + +export interface IWarnAboutCompatibilityIssuesOptions extends IWarnAboutVersionTooNewOptions { + rushConfiguration: RushConfiguration | undefined; +} + +/** + * This class provides useful functions for warning if the current Node.js runtime isn't supported. + * + * @internal + */ +export class NodeJsCompatibility { + /** + * This reports if the Node.js version is known to have serious incompatibilities. In that situation, the user + * should downgrade Rush to an older release that supported their Node.js version. + */ + public static reportAncientIncompatibleVersion(): boolean { + // IMPORTANT: If this test fails, the Rush CLI front-end process will terminate with an error. + // Only increment it when our code base is known to use newer features (e.g. "async"/"await") that + // have no hope of working with older Node.js. + if (semver.satisfies(nodeVersion, '<14.18.0')) { + // eslint-disable-next-line no-console + console.error( + Colorize.red( + `Your version of Node.js (${nodeVersion}) is very old and incompatible with Rush. ` + + `Please upgrade to the latest Long-Term Support (LTS) version.\n` + ) + ); + return true; + } else { + return false; + } + } + + /** + * Detect whether the Node.js version is "supported" by the Rush maintainers. We generally + * only support versions that were "Long Term Support" (LTS) at the time when Rush was published. + * + * This is a warning only -- the user is free to ignore it and use Rush anyway. + */ + public static warnAboutCompatibilityIssues(options: IWarnAboutCompatibilityIssuesOptions): boolean { + // Only show the first warning + return ( + NodeJsCompatibility.reportAncientIncompatibleVersion() || + NodeJsCompatibility.warnAboutVersionTooNew(options) || + NodeJsCompatibility._warnAboutOddNumberedVersion() || + NodeJsCompatibility._warnAboutNonLtsVersion(options.rushConfiguration) + ); + } + + /** + * Warn about a Node.js version that has not been tested yet with Rush. + */ + public static warnAboutVersionTooNew(options: IWarnAboutVersionTooNewOptions): boolean { + if (nodeMajorVersion >= UPCOMING_NODE_LTS_VERSION + 1) { + if (!options.alreadyReportedNodeTooNewError) { + // We are on a much newer release than we have tested and support + if (options.isRushLib) { + // eslint-disable-next-line no-console + console.warn( + Colorize.yellow( + `Your version of Node.js (${nodeVersion}) has not been tested with this release ` + + `of the Rush engine. Please consider upgrading the "rushVersion" setting in ${RushConstants.rushJsonFilename}, ` + + `or downgrading Node.js.\n` + ) + ); + } else { + // eslint-disable-next-line no-console + console.warn( + Colorize.yellow( + `Your version of Node.js (${nodeVersion}) has not been tested with this release ` + + `of Rush. Please consider installing a newer version of the "@microsoft/rush" ` + + `package, or downgrading Node.js.\n` + ) + ); + } + } + + return true; + } else { + return false; + } + } + + 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' + ) + ); + + return true; + } else { + return false; + } + } + + 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` + ) + ); + + return true; + } else { + return false; + } + } + + public static get isLtsVersion(): boolean { + return !!process.release.lts; + } + + public static get isOddNumberedVersion(): boolean { + return nodeMajorVersion % 2 !== 0; + } +} diff --git a/libraries/rush-lib/src/logic/PackageJsonUpdater.ts b/libraries/rush-lib/src/logic/PackageJsonUpdater.ts new file mode 100644 index 00000000000..cc56e90c7ed --- /dev/null +++ b/libraries/rush-lib/src/logic/PackageJsonUpdater.ts @@ -0,0 +1,905 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as semver from 'semver'; + +import type { INpmCheckPackageSummary } from '@rushstack/npm-check-fork'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { BaseInstallManager } from './base/BaseInstallManager'; +import type { IInstallManagerOptions } from './base/BaseInstallManagerTypes'; +import { InstallManagerFactory } from './InstallManagerFactory'; +import { VersionMismatchFinder } from './versionMismatch/VersionMismatchFinder'; +import { PurgeManager } from './PurgeManager'; +import { Utilities } from '../utilities/Utilities'; +import { DependencyType, type PackageJsonDependency } from '../api/PackageJsonEditor'; +import type { RushGlobalFolder } from '../api/RushGlobalFolder'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { VersionMismatchFinderEntity } from './versionMismatch/VersionMismatchFinderEntity'; +import { VersionMismatchFinderProject } from './versionMismatch/VersionMismatchFinderProject'; +import { RushConstants } from './RushConstants'; +import { InstallHelpers } from './installManager/InstallHelpers'; +import type { DependencyAnalyzer, IDependencyAnalysis } from './DependencyAnalyzer'; +import { + type IPackageForRushAdd, + type IPackageJsonUpdaterRushAddOptions, + type IPackageJsonUpdaterRushBaseUpdateOptions, + type IPackageJsonUpdaterRushRemoveOptions, + 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. + */ +export interface IPackageJsonUpdaterRushUpgradeOptions { + /** + * The projects whose package.jsons should get updated + */ + projects: RushConfigurationProject[]; + /** + * The dependencies to be added. + */ + packagesToAdd: INpmCheckPackageSummary[]; + /** + * If specified, other packages that use this dependency will also have their package.json's updated. + */ + updateOtherPackages: boolean; + /** + * If specified, "rush update" will not be run after updating the package.json file(s). + */ + skipUpdate: boolean; + /** + * If specified, "rush update" will be run in debug mode. + */ + debugInstall: boolean; + /** + * The variant to consider when performing installations and validating shrinkwrap updates. + */ + variant: string | undefined; +} + +/** + * Configuration options for adding or updating a dependency in single project + * or removing a dependency from a particular project + */ +export interface IBaseUpdateProjectOptions { + /** + * The project which will have its package.json updated + */ + project: VersionMismatchFinderEntity; + /** + * Map of packages to update + * Its key is the name of the dependency to be added or updated in the project + * Its value is the new SemVer specifier that should be added to the project's package.json + * If trying to remove this packages, value can be empty string + */ + dependenciesToAddOrUpdateOrRemove: Record; +} + +/** + * Configuration options for adding or updating a dependency in a single project + */ +export interface IUpdateProjectOptions extends IBaseUpdateProjectOptions { + /** + * The type of dependency that should be updated. If left empty, this will be auto-detected. + * If it cannot be auto-detected an exception will be thrown. + */ + dependencyType?: DependencyType; +} +/** + * Configuration options for removing dependencies from a single project + */ +export interface IRemoveProjectOptions extends IBaseUpdateProjectOptions {} + +/** + * A helper class for managing the dependencies of various package.json files. + * @internal + */ +export class PackageJsonUpdater { + 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; + } + + /** + * Upgrade dependencies to a particular project, or across specified projects. This is the core business logic for + * "rush upgrade-interactive". + */ + public async doRushUpgradeAsync(options: IPackageJsonUpdaterRushUpgradeOptions): Promise { + const { projects, packagesToAdd, updateOtherPackages, skipUpdate, debugInstall, variant } = options; + const { DependencyAnalyzer } = await import( + /* webpackChunkName: 'DependencyAnalyzer' */ + './DependencyAnalyzer' + ); + const dependencyAnalyzer: DependencyAnalyzer = DependencyAnalyzer.forRushConfiguration( + this._rushConfiguration + ); + const { + allVersionsByPackageName, + implicitlyPreferredVersionByPackageName, + commonVersionsConfiguration + }: IDependencyAnalysis = dependencyAnalyzer.getAnalysis(undefined, variant, false); + + const dependenciesToUpdate: Record = {}; + const devDependenciesToUpdate: Record = {}; + const peerDependenciesToUpdate: Record = {}; + + for (const { moduleName, latest: latestVersion, packageJson, devDependency } of packagesToAdd) { + const inferredRangeStyle: SemVerStyle = this._cheaplyDetectSemVerRangeStyle(packageJson); + const implicitlyPreferredVersion: string | undefined = + implicitlyPreferredVersionByPackageName.get(moduleName); + + const explicitlyPreferredVersion: string | undefined = + commonVersionsConfiguration.preferredVersions.get(moduleName); + + const version: string = await this._getNormalizedVersionSpecAsync( + projects, + moduleName, + latestVersion, + implicitlyPreferredVersion, + explicitlyPreferredVersion, + inferredRangeStyle, + commonVersionsConfiguration.ensureConsistentVersions + ); + + if (devDependency) { + devDependenciesToUpdate[moduleName] = version; + } else { + dependenciesToUpdate[moduleName] = version; + } + + this._terminal.writeLine( + Colorize.green(`Updating projects to use `) + moduleName + '@' + Colorize.cyan(version) + ); + this._terminal.writeLine(); + + const existingSpecifiedVersions: Set | undefined = allVersionsByPackageName.get(moduleName); + if ( + existingSpecifiedVersions && + !existingSpecifiedVersions.has(version) && + commonVersionsConfiguration.ensureConsistentVersions && + !updateOtherPackages + ) { + // There are existing versions, and the version we're going to use is not one of them, and this repo + // requires consistent versions, and we aren't going to update other packages, so we can't proceed. + + const existingVersionList: string = Array.from(existingSpecifiedVersions).join(', '); + throw new Error( + `Adding '${moduleName}@${version}' ` + + `causes mismatched dependencies. Use the "--make-consistent" flag to update other packages to use ` + + `this version, or try specify one of the existing versions (${existingVersionList}).` + ); + } + } + + const allPackageUpdates: Map = new Map(); + const allDependenciesToUpdate: [string, string][] = [ + ...Object.entries(dependenciesToUpdate), + ...Object.entries(devDependenciesToUpdate), + ...Object.entries(peerDependenciesToUpdate) + ]; + + for (const project of projects) { + const mismatchFinderProject: VersionMismatchFinderProject = new VersionMismatchFinderProject(project); + + const currentProjectDepUpdate: IUpdateProjectOptions = { + project: mismatchFinderProject, + dependenciesToAddOrUpdateOrRemove: dependenciesToUpdate, + dependencyType: DependencyType.Regular + }; + + const currentProjectDevDepUpdate: IUpdateProjectOptions = { + project: mismatchFinderProject, + dependenciesToAddOrUpdateOrRemove: devDependenciesToUpdate, + dependencyType: DependencyType.Dev + }; + + allPackageUpdates.set(mismatchFinderProject.filePath, mismatchFinderProject); + + this.updateProject(currentProjectDepUpdate); + this.updateProject(currentProjectDevDepUpdate); + } + + if (updateOtherPackages) { + const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches( + this._rushConfiguration, + options + ); + for (const update of this._getUpdates(mismatchFinder, allDependenciesToUpdate)) { + this.updateProject(update); + allPackageUpdates.set(update.project.filePath, update.project); + } + } + + for (const [filePath, project] of allPackageUpdates) { + if (project.saveIfModified()) { + this._terminal.writeLine(Colorize.green('Wrote ') + filePath); + } + } + + if (!skipUpdate) { + if (this._rushConfiguration.subspacesFeatureEnabled) { + const subspaceSet: ReadonlySet = this._rushConfiguration.getSubspacesForProjects( + options.projects + ); + for (const subspace of subspaceSet) { + await this._doUpdateAsync(debugInstall, subspace, variant); + } + } else { + await this._doUpdateAsync(debugInstall, this._rushConfiguration.defaultSubspace, variant); + } + } + } + + public async doRushUpdateAsync(options: IPackageJsonUpdaterRushBaseUpdateOptions): Promise { + let allPackageUpdates: IUpdateProjectOptions[] = []; + if (options.actionName === 'add') { + allPackageUpdates = await this._doRushAddAsync(options as IPackageJsonUpdaterRushAddOptions); + } else if (options.actionName === 'remove') { + allPackageUpdates = await this._doRushRemoveAsync(options as IPackageJsonUpdaterRushRemoveOptions); + } 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); + } + } + + if (!skipUpdate) { + if (this._rushConfiguration.subspacesFeatureEnabled) { + const subspaceSet: ReadonlySet = this._rushConfiguration.getSubspacesForProjects( + options.projects + ); + for (const subspace of subspaceSet) { + await this._doUpdateAsync(debugInstall, subspace, variant); + } + } else { + await this._doUpdateAsync(debugInstall, this._rushConfiguration.defaultSubspace, variant); + } + } + } + + private async _doUpdateAsync( + debugInstall: boolean, + subspace: Subspace, + variant: string | undefined + ): Promise { + this._terminal.writeLine(); + this._terminal.writeLine(Colorize.green('Running "rush update"')); + this._terminal.writeLine(); + + const purgeManager: PurgeManager = new PurgeManager(this._rushConfiguration, this._rushGlobalFolder); + const installManagerOptions: IInstallManagerOptions = { + debug: debugInstall, + allowShrinkwrapUpdates: true, + bypassPolicy: false, + noLink: false, + fullUpgrade: false, + recheckShrinkwrap: false, + networkConcurrency: undefined, + offline: false, + collectLogFile: false, + variant, + maxInstallAttempts: RushConstants.defaultMaxInstallAttempts, + pnpmFilterArgumentValues: [], + selectedProjects: new Set(this._rushConfiguration.projects), + checkOnly: false, + subspace: subspace, + terminal: this._terminal + }; + + const installManager: BaseInstallManager = await InstallManagerFactory.getInstallManagerAsync( + this._rushConfiguration, + this._rushGlobalFolder, + purgeManager, + installManagerOptions + ); + try { + await installManager.doInstallAsync(); + } finally { + await purgeManager.startDeleteAllAsync(); + } + } + + /** + * Adds a dependency to a particular project. The core business logic for "rush add". + */ + private async _doRushAddAsync( + options: IPackageJsonUpdaterRushAddOptions + ): Promise { + const { projects } = options; + + const { DependencyAnalyzer } = await import( + /* webpackChunkName: 'DependencyAnalyzer' */ + './DependencyAnalyzer' + ); + const dependencyAnalyzer: DependencyAnalyzer = DependencyAnalyzer.forRushConfiguration( + this._rushConfiguration + ); + + const allPackageUpdates: IUpdateProjectOptions[] = []; + const subspaceSet: ReadonlySet = this._rushConfiguration.getSubspacesForProjects(projects); + for (const subspace of subspaceSet) { + // Projects for this subspace + allPackageUpdates.push(...(await this._updateProjectsAsync(subspace, dependencyAnalyzer, options))); + } + + return allPackageUpdates; + } + + private async _updateProjectsAsync( + subspace: Subspace, + dependencyAnalyzer: DependencyAnalyzer, + options: IPackageJsonUpdaterRushAddOptions + ): Promise { + const { projects, packagesToUpdate, devDependency, peerDependency, updateOtherPackages, variant } = + options; + + // Get projects for this subspace + const subspaceProjects: RushConfigurationProject[] = projects.filter( + (project) => project.subspace === subspace + ); + + const { + allVersionsByPackageName, + implicitlyPreferredVersionByPackageName, + commonVersionsConfiguration + }: IDependencyAnalysis = dependencyAnalyzer.getAnalysis(subspace, variant, options.actionName === 'add'); + + this._terminal.writeLine(); + const dependenciesToAddOrUpdate: Record = {}; + for (const { packageName, version: initialVersion, rangeStyle } of packagesToUpdate) { + const implicitlyPreferredVersion: string | undefined = + implicitlyPreferredVersionByPackageName.get(packageName); + + const explicitlyPreferredVersion: string | undefined = + commonVersionsConfiguration.preferredVersions.get(packageName); + + const version: string = await this._getNormalizedVersionSpecAsync( + subspaceProjects, + packageName, + initialVersion, + implicitlyPreferredVersion, + explicitlyPreferredVersion, + rangeStyle, + commonVersionsConfiguration.ensureConsistentVersions + ); + + dependenciesToAddOrUpdate[packageName] = version; + this._terminal.writeLine( + Colorize.green('Updating projects to use '), + `${packageName}@`, + Colorize.cyan(version) + ); + this._terminal.writeLine(); + + const existingSpecifiedVersions: Set | undefined = allVersionsByPackageName.get(packageName); + if ( + existingSpecifiedVersions && + !existingSpecifiedVersions.has(version) && + commonVersionsConfiguration.ensureConsistentVersions && + !updateOtherPackages + ) { + // There are existing versions, and the version we're going to use is not one of them, and this repo + // requires consistent versions, and we aren't going to update other packages, so we can't proceed. + + const existingVersionList: string = Array.from(existingSpecifiedVersions).join(', '); + throw new Error( + `Adding '${packageName}@${version}' ` + + `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}).` + ); + } + } + + const allPackageUpdates: IUpdateProjectOptions[] = []; + + for (const project of subspaceProjects) { + const currentProjectUpdate: IUpdateProjectOptions = { + project: new VersionMismatchFinderProject(project), + dependenciesToAddOrUpdateOrRemove: dependenciesToAddOrUpdate, + dependencyType: devDependency ? DependencyType.Dev : peerDependency ? DependencyType.Peer : undefined + }; + this.updateProject(currentProjectUpdate); + + let otherPackageUpdates: IUpdateProjectOptions[] = []; + + // we need to do a mismatch check + if (updateOtherPackages) { + const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches( + this._rushConfiguration, + { + subspace, + variant + } + ); + otherPackageUpdates = this._getUpdates(mismatchFinder, Object.entries(dependenciesToAddOrUpdate)); + } + + this.updateProjects(otherPackageUpdates); + + allPackageUpdates.push(currentProjectUpdate, ...otherPackageUpdates); + } + + return allPackageUpdates; + } + + private _getUpdates( + mismatchFinder: VersionMismatchFinder, + dependenciesToUpdate: Iterable<[string, string]> + ): IUpdateProjectOptions[] { + const result: IUpdateProjectOptions[] = []; + + const { mismatches } = mismatchFinder; + + for (const [packageName, version] of dependenciesToUpdate) { + const projectsByVersion: ReadonlyMap> | undefined = + mismatches.get(packageName); + if (projectsByVersion) { + for (const consumers of projectsByVersion.values()) { + for (const consumer of consumers) { + result.push({ + project: consumer, + dependenciesToAddOrUpdateOrRemove: { + [packageName]: version + } + }); + } + } + } + } + + return result; + } + + /** + * Remove a dependency from a particular project. The core business logic for "rush remove". + */ + private async _doRushRemoveAsync( + options: IPackageJsonUpdaterRushRemoveOptions + ): Promise { + const { projects, packagesToUpdate } = options; + + this._terminal.writeLine(); + const dependenciesToRemove: Record = {}; + + const allPackageUpdates: IRemoveProjectOptions[] = []; + + for (const project of projects) { + for (const { packageName } of packagesToUpdate) { + dependenciesToRemove[packageName] = ''; + } + + const currentProjectUpdate: IRemoveProjectOptions = { + project: new VersionMismatchFinderProject(project), + dependenciesToAddOrUpdateOrRemove: dependenciesToRemove + }; + this.removePackageFromProject(currentProjectUpdate); + + allPackageUpdates.push(currentProjectUpdate); + } + + return allPackageUpdates; + } + + /** + * Updates several projects' package.json files + */ + public updateProjects(projectUpdates: IUpdateProjectOptions[]): void { + for (const update of projectUpdates) { + this.updateProject(update); + } + } + + /** + * Updates a single project's package.json file + */ + public updateProject(options: IUpdateProjectOptions): void { + let { dependencyType } = options; + const { project, dependenciesToAddOrUpdateOrRemove } = options; + + for (const [packageName, newVersion] of Object.entries(dependenciesToAddOrUpdateOrRemove)) { + const oldDependency: PackageJsonDependency | undefined = project.tryGetDependency(packageName); + const oldDevDependency: PackageJsonDependency | undefined = project.tryGetDevDependency(packageName); + + const oldDependencyType: DependencyType | undefined = oldDevDependency + ? oldDevDependency.dependencyType + : oldDependency + ? oldDependency.dependencyType + : undefined; + + dependencyType = dependencyType || oldDependencyType || DependencyType.Regular; + + project.addOrUpdateDependency(packageName, newVersion, dependencyType!); + } + } + + public removePackageFromProject(options: IRemoveProjectOptions): void { + const { project, dependenciesToAddOrUpdateOrRemove } = options; + + for (const packageName of Object.keys(dependenciesToAddOrUpdateOrRemove)) { + const packageJsonDependencies: (PackageJsonDependency | undefined)[] = [ + project.tryGetDependency(packageName), + project.tryGetDevDependency(packageName) + ]; + for (const packageJsonDependency of packageJsonDependencies) { + if (!packageJsonDependency) { + continue; + } + project.removeDependency(packageName, packageJsonDependency.dependencyType); + } + } + } + + /** + * Selects an appropriate version number for a particular package, given an optional initial SemVer spec. + * If ensureConsistentVersions, tries to pick a version that will be consistent. + * Otherwise, will choose the latest semver matching the initialSpec and append the proper range style. + * @param projects - the projects which will have their package.json's updated + * @param packageName - the name of the package to be used + * @param initialSpec - a semver pattern that should be used to find the latest version matching the spec + * @param implicitlyPreferredVersion - the implicitly preferred (aka common/primary) version of the package in use + * @param rangeStyle - if this version is selected by querying registry, then this range specifier is prepended to + * the selected version. + */ + private async _getNormalizedVersionSpecAsync( + projects: RushConfigurationProject[], + packageName: string, + initialSpec: string | undefined, + implicitlyPreferredVersion: string | undefined, + explicitlyPreferredVersion: string | undefined, + rangeStyle: SemVerStyle, + ensureConsistentVersions: boolean | undefined + ): Promise { + this._terminal.writeLine(Colorize.gray(`Determining new version for dependency: ${packageName}`)); + if (initialSpec) { + this._terminal.writeLine(`Specified version selector: ${Colorize.cyan(initialSpec)}`); + } else { + this._terminal.writeLine( + `No version selector was specified, so the version will be determined automatically.` + ); + } + this._terminal.writeLine(); + + // if ensureConsistentVersions => reuse the pinned version + // else, query the registry and use the latest that satisfies semver spec + if (initialSpec) { + if (initialSpec === implicitlyPreferredVersion) { + this._terminal.writeLine( + Colorize.green('Assigning "') + + Colorize.cyan(initialSpec) + + Colorize.green( + `" for "${packageName}" because it matches what other projects are using in this repo.` + ) + ); + return initialSpec; + } + + if (initialSpec === explicitlyPreferredVersion) { + this._terminal.writeLine( + Colorize.green('Assigning "') + + Colorize.cyan(initialSpec) + + Colorize.green( + `" for "${packageName}" because it is the preferred version listed in ${RushConstants.commonVersionsFilename}.` + ) + ); + return initialSpec; + } + } + + if (ensureConsistentVersions && !initialSpec) { + if (implicitlyPreferredVersion) { + this._terminal.writeLine( + `Assigning the version "${Colorize.cyan(implicitlyPreferredVersion)}" for "${packageName}" ` + + 'because it is already used by other projects in this repo.' + ); + return implicitlyPreferredVersion; + } + + if (explicitlyPreferredVersion) { + this._terminal.writeLine( + `Assigning the version "${Colorize.cyan(explicitlyPreferredVersion)}" for "${packageName}" ` + + `because it is the preferred version listed in ${RushConstants.commonVersionsFilename}.` + ); + return explicitlyPreferredVersion; + } + } + + await InstallHelpers.ensureLocalPackageManagerAsync( + this._rushConfiguration, + this._rushGlobalFolder, + RushConstants.defaultMaxInstallAttempts + ); + + const useWorkspaces: boolean = !!( + this._rushConfiguration.pnpmOptions && this._rushConfiguration.pnpmOptions.useWorkspaces + ); + const workspacePrefix: string = 'workspace:'; + + // Trim 'workspace:' notation from the spec, since we're going to be tweaking the range + if (useWorkspaces && initialSpec && initialSpec.startsWith(workspacePrefix)) { + initialSpec = initialSpec.substring(workspacePrefix.length).trim(); + } + + // determine if the package is a project in the local repository and if the version exists + const localProject: RushConfigurationProject | undefined = this._tryGetLocalProject( + packageName, + projects + ); + + let selectedVersion: string | undefined; + let selectedVersionPrefix: string = ''; + + if (initialSpec && initialSpec !== 'latest') { + this._terminal.writeLine(Colorize.gray('Finding versions that satisfy the selector: ') + initialSpec); + this._terminal.writeLine(); + + if (localProject !== undefined) { + const version: string = localProject.packageJson.version; + if (semver.satisfies(version, initialSpec)) { + // For workspaces, assume that specifying the exact version means you always want to consume + // the local project. Otherwise, use the exact local package version + if (useWorkspaces) { + selectedVersion = initialSpec === version ? '*' : initialSpec; + selectedVersionPrefix = workspacePrefix; + } else { + selectedVersion = version; + } + } else { + throw new Error( + `The dependency being added ("${packageName}") is a project in the local Rush repository, ` + + `but the version specifier provided (${initialSpec}) does not match the local project's version ` + + `(${version}). Correct the version specifier, omit a version specifier, or include "${packageName}" as a ` + + `cyclicDependencyProject if it is intended for "${packageName}" to come from an external feed and not ` + + 'from the local Rush repository.' + ); + } + } else { + this._terminal.writeLine(`Querying registry for all versions of "${packageName}"...`); + + let commandArgs: string[]; + if (this._rushConfiguration.packageManager === 'yarn') { + commandArgs = ['info', packageName, 'versions', '--json']; + } else { + commandArgs = ['view', packageName, 'versions', '--json']; + } + + const allVersions: string = await Utilities.executeCommandAndCaptureOutputAsync( + this._rushConfiguration.packageManagerToolFilename, + commandArgs, + this._rushConfiguration.commonTempFolder + ); + + let versionList: string[]; + if (this._rushConfiguration.packageManager === 'yarn') { + versionList = JSON.parse(allVersions).data; + } else { + versionList = JSON.parse(allVersions); + } + + this._terminal.writeLine(Colorize.gray(`Found ${versionList.length} available versions.`)); + + for (const version of versionList) { + if (semver.satisfies(version, initialSpec)) { + selectedVersion = initialSpec; + this._terminal.writeLine( + `Found a version that satisfies ${initialSpec}: ${Colorize.cyan(version)}` + ); + break; + } + } + + if (!selectedVersion) { + throw new Error( + `Unable to find a version of "${packageName}" that satisfies` + + ` the version specifier "${initialSpec}"` + ); + } + } + } else { + if (localProject !== undefined) { + // For workspaces, assume that no specified version range means you always want to consume + // the local project. Otherwise, use the exact local package version + if (useWorkspaces) { + selectedVersion = '*'; + selectedVersionPrefix = workspacePrefix; + } else { + selectedVersion = localProject.packageJson.version; + } + } else { + if (!this._rushConfiguration.ensureConsistentVersions) { + this._terminal.writeLine( + Colorize.gray( + `The "ensureConsistentVersions" policy is NOT active, so we will assign the latest version.` + ) + ); + this._terminal.writeLine(); + } + + this._terminal.writeLine(`Querying NPM registry for latest version of "${packageName}"...`); + + let commandArgs: string[]; + if (this._rushConfiguration.packageManager === 'yarn') { + commandArgs = ['info', packageName, 'dist-tags.latest', '--silent']; + } else { + commandArgs = ['view', `${packageName}@latest`, 'version']; + } + + selectedVersion = ( + await Utilities.executeCommandAndCaptureOutputAsync( + this._rushConfiguration.packageManagerToolFilename, + commandArgs, + this._rushConfiguration.commonTempFolder + ) + ).trim(); + } + + this._terminal.writeLine(); + + this._terminal.writeLine(`Found latest version: ${Colorize.cyan(selectedVersion)}`); + } + + this._terminal.writeLine(); + + let reasonForModification: string = ''; + if (selectedVersion !== '*') { + switch (rangeStyle) { + case SemVerStyle.Caret: { + selectedVersionPrefix += '^'; + reasonForModification = ' because the "--caret" flag was specified'; + break; + } + + case SemVerStyle.Exact: { + reasonForModification = ' because the "--exact" flag was specified'; + break; + } + + case SemVerStyle.Tilde: { + selectedVersionPrefix += '~'; + break; + } + + case SemVerStyle.Passthrough: { + break; + } + + default: { + throw new Error(`Unexpected SemVerStyle ${rangeStyle}.`); + } + } + } + + const normalizedVersion: string = selectedVersionPrefix + selectedVersion; + this._terminal.writeLine( + Colorize.gray(`Assigning version "${normalizedVersion}" for "${packageName}"${reasonForModification}.`) + ); + return normalizedVersion; + } + + private _collectAllDownstreamDependencies( + project: RushConfigurationProject + ): Set { + const allProjectDownstreamDependencies: Set = + new Set(); + + const collectDependencies: (rushProject: RushConfigurationProject) => void = ( + rushProject: RushConfigurationProject + ) => { + for (const downstreamDependencyProject of rushProject.downstreamDependencyProjects) { + const foundProject: RushConfigurationProject | undefined = + this._rushConfiguration.projectsByName.get(downstreamDependencyProject); + + if (!foundProject) { + continue; + } + + if (foundProject.decoupledLocalDependencies.has(rushProject.packageName)) { + continue; + } + + if (!allProjectDownstreamDependencies.has(foundProject)) { + allProjectDownstreamDependencies.add(foundProject); + collectDependencies(foundProject); + } + } + }; + + collectDependencies(project); + return allProjectDownstreamDependencies; + } + + /** + * Given a package name, this function returns a {@see RushConfigurationProject} if the package is a project + * in the local Rush repo and is not marked as cyclic for any of the projects. + * + * @remarks + * This function throws an error if adding the discovered local project as a dependency + * would create a dependency cycle, or if it would be added to multiple projects. + */ + private _tryGetLocalProject( + packageName: string, + projects: RushConfigurationProject[] + ): RushConfigurationProject | undefined { + const foundProject: RushConfigurationProject | undefined = + this._rushConfiguration.projectsByName.get(packageName); + + if (foundProject === undefined) { + return undefined; + } + + if (projects.length > 1) { + throw new Error( + `"rush add" does not support adding a local project as a dependency to multiple projects at once.` + ); + } + + const project: RushConfigurationProject = projects[0]; + + if (project.decoupledLocalDependencies.has(foundProject.packageName)) { + return undefined; + } + + // Are we attempting to add this project to itself? + if (project === foundProject) { + throw new Error( + 'Unable to add a project as a dependency of itself unless the dependency is listed as a cyclic dependency ' + + `in ${RushConstants.rushJsonFilename}. This command attempted to add "${foundProject.packageName}" ` + + `as a dependency of itself.` + ); + } + + // Are we attempting to create a cycle? + const downstreamDependencies: Set = + this._collectAllDownstreamDependencies(project); + if (downstreamDependencies.has(foundProject)) { + throw new Error( + `Adding "${foundProject.packageName}" as a direct or indirect dependency of ` + + `"${project.packageName}" would create a dependency cycle.` + ); + } + + return foundProject; + } + + private _cheaplyDetectSemVerRangeStyle(version: string): SemVerStyle { + // create a swtich statement to detect the first character of the version string and determine the range style + // TODO: This is a temporary solution until we have a better way to detect more complext range styles + // TODO: Should we handle/care about peerDependencies? + switch (version[0]) { + case '~': + return SemVerStyle.Tilde; + case '^': + return SemVerStyle.Caret; + default: + this._terminal.writeLine( + `No SemVer range detected for version: ${version}. The exact version will be set in package.json.` + ); + return SemVerStyle.Exact; + } + } + + private _normalizeDepsToUpgrade(deps: INpmCheckPackageSummary[]): IPackageForRushAdd[] { + return deps.map((dep) => { + return { + packageName: dep.moduleName, + version: dep.latest, + rangeStyle: this._cheaplyDetectSemVerRangeStyle(dep.packageJson) + }; + }); + } +} diff --git a/libraries/rush-lib/src/logic/PackageJsonUpdaterTypes.ts b/libraries/rush-lib/src/logic/PackageJsonUpdaterTypes.ts new file mode 100644 index 00000000000..bdc9ee6b285 --- /dev/null +++ b/libraries/rush-lib/src/logic/PackageJsonUpdaterTypes.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; + +/** + * The type of SemVer range specifier that is prepended to the version + */ +export enum SemVerStyle { + Exact = 'exact', + Caret = 'caret', + Tilde = 'tilde', + Passthrough = 'passthrough' +} + +export interface IPackageForRushUpdate { + packageName: string; +} + +export interface IPackageForRushAdd extends IPackageForRushUpdate { + /** + * The style of range that should be used if the version is automatically detected. + */ + rangeStyle: SemVerStyle; + + /** + * If not undefined, the latest version will be used (that doesn't break ensureConsistentVersions). + * If specified, the latest version meeting the SemVer specifier will be used as the basis. + */ + version?: string; +} + +export interface IPackageForRushRemove extends IPackageForRushUpdate {} + +export interface IPackageJsonUpdaterRushBaseUpdateOptions { + /** + * The projects whose package.jsons should get updated + */ + projects: RushConfigurationProject[]; + /** + * The dependencies to be added or removed. + */ + packagesToUpdate: IPackageForRushUpdate[]; + /** + * If specified, "rush update" will not be run after updating the package.json file(s). + */ + skipUpdate: boolean; + /** + * If specified, "rush update" will be run in debug mode. + */ + debugInstall: boolean; + /** + * actionName + */ + actionName: string; + /** + * The variant to consider when performing installations and validating shrinkwrap updates. + */ + variant: string | undefined | undefined; +} + +/** + * Configuration options for adding or updating a dependency in a single project + */ +export interface IPackageJsonUpdaterRushAddOptions extends IPackageJsonUpdaterRushBaseUpdateOptions { + /** + * Whether or not this dependency should be added as a devDependency or a regular dependency. + */ + devDependency: boolean; + /** + * Whether or not this dependency should be added as a peerDependency or a regular dependency. + */ + peerDependency: boolean; + /** + * If specified, other packages that use this dependency will also have their package.json's updated. + */ + updateOtherPackages: boolean; + /** + * The dependencies to be added. + */ + packagesToUpdate: IPackageForRushAdd[]; +} + +/** + * Options for remove a dependency from a particular project. + */ +export interface IPackageJsonUpdaterRushRemoveOptions extends IPackageJsonUpdaterRushBaseUpdateOptions {} diff --git a/apps/rush-lib/src/logic/PackageLookup.ts b/libraries/rush-lib/src/logic/PackageLookup.ts similarity index 94% rename from apps/rush-lib/src/logic/PackageLookup.ts rename to libraries/rush-lib/src/logic/PackageLookup.ts index 342e1b3a725..9b0253fc30c 100644 --- a/apps/rush-lib/src/logic/PackageLookup.ts +++ b/libraries/rush-lib/src/logic/PackageLookup.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 { BasePackage } from './base/BasePackage'; +import type { BasePackage } from './base/BasePackage'; export class PackageLookup { private _packageMap: Map; diff --git a/apps/rush-lib/src/logic/PrereleaseToken.ts b/libraries/rush-lib/src/logic/PrereleaseToken.ts similarity index 88% rename from apps/rush-lib/src/logic/PrereleaseToken.ts rename to libraries/rush-lib/src/logic/PrereleaseToken.ts index d87c067c37b..3e564f6bcd2 100644 --- a/apps/rush-lib/src/logic/PrereleaseToken.ts +++ b/libraries/rush-lib/src/logic/PrereleaseToken.ts @@ -2,16 +2,17 @@ // See LICENSE in the project root for license information. export class PrereleaseToken { - private _name: string; private _prereleaseName: string | undefined; private _suffixName: string | undefined; private _partialPrerelease: boolean; + public readonly name: string; + public constructor(prereleaseName?: string, suffixName?: string, partialPrerelease: boolean = false) { if (prereleaseName && suffixName) { throw new Error('Pre-release name and suffix cannot be provided at the same time.'); } - this._name = prereleaseName! || suffixName!; + this.name = prereleaseName! || suffixName!; this._prereleaseName = prereleaseName; this._suffixName = suffixName; this._partialPrerelease = partialPrerelease; @@ -32,8 +33,4 @@ export class PrereleaseToken { public get isPartialPrerelease(): boolean { return this.isPrerelease && this._partialPrerelease; } - - public get name(): string { - return this._name; - } } diff --git a/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts b/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts new file mode 100644 index 00000000000..ecf09749f5a --- /dev/null +++ b/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts @@ -0,0 +1,479 @@ +// 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 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 { + getRepoChanges, + getRepoRoot, + getDetailedRepoStateAsync, + hashFilesAsync, + type IFileDiffStatus +} from '@rushstack/package-deps-hash'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +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 { + type IInputsSnapshotProjectMetadata, + type IInputsSnapshot, + InputsSnapshot, + type GetInputsSnapshotAsyncFn +} from './incremental/InputsSnapshot'; + +/** + * @beta + */ +export interface IGetChangedProjectsOptions { + targetBranchName: string; + terminal: ITerminal; + shouldFetch?: boolean; + variant?: string; + + /** + * If set to `true`, consider a project's external dependency installation layout as defined in the + * package manager lockfile when determining if it has changed. + */ + includeExternalDependencies: boolean; + + /** + * If set to `true` apply the `incrementalBuildIgnoredGlobs` property in a project's `rush-project.json` + * and exclude matched files from change detection. + */ + enableFiltering: boolean; +} + +/** + * @internal + */ +export interface IRawRepoState { + projectState: Map> | undefined; + rootDir: string; + rawHashes: Map; +} + +/** + * @beta + */ +export class ProjectChangeAnalyzer { + private readonly _rushConfiguration: RushConfiguration; + private readonly _git: Git; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + this._git = new Git(this._rushConfiguration); + } + + /** + * Gets a list of projects that have changed in the current state of the repo + * when compared to the specified branch, optionally taking the shrinkwrap and settings in + * the rush-project.json file into consideration. + */ + public async getChangedProjectsAsync( + options: IGetChangedProjectsOptions + ): Promise> { + const { _rushConfiguration: rushConfiguration } = this; + + const { targetBranchName, terminal, includeExternalDependencies, enableFiltering, shouldFetch, variant } = + options; + + const gitPath: string = this._git.getGitPathOrThrow(); + const repoRoot: string = getRepoRoot(rushConfiguration.rushJsonFolder); + + // if the given targetBranchName is a commit, we assume it is the merge base + const isTargetBranchACommit: boolean = await this._git.determineIfRefIsACommitAsync(targetBranchName); + const mergeCommit: string = isTargetBranchACommit + ? targetBranchName + : await this._git.getMergeBaseAsync(targetBranchName, terminal, shouldFetch); + + const changedFiles: Map = getRepoChanges(repoRoot, mergeCommit, gitPath); + const lookup: LookupByPath = + rushConfiguration.getProjectLookupForRoot(repoRoot); + const changesByProject: Map< + RushConfigurationProject, + Map + > = 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) { + changedProjects.add(project); + } + }, + { concurrency: 10 } + ); + } else { + for (const [project, projectChanges] of changesByProject) { + if (projectChanges.size > 0) { + changedProjects.add(project); + } + } + } + + // 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 + + const variantToUse: string | undefined = + variant ?? (await this._rushConfiguration.getCurrentlyInstalledVariantAsync()); + const fullShrinkwrapPath: string = + rushConfiguration.defaultSubspace.getCommittedShrinkwrapFilePath(variantToUse); + + const relativeShrinkwrapFilePath: string = Path.convertToSlashes( + path.relative(repoRoot, fullShrinkwrapPath) + ); + const shrinkwrapStatus: IFileDiffStatus | undefined = changedFiles.get(relativeShrinkwrapFilePath); + + if (shrinkwrapStatus) { + if (shrinkwrapStatus.status !== 'M') { + terminal.writeLine(`Lockfile was created or deleted. Assuming all projects are affected.`); + return new Set(rushConfiguration.projects); + } + + if (rushConfiguration.isPnpm) { + const currentShrinkwrap: PnpmShrinkwrapFile | undefined = + PnpmShrinkwrapFile.loadFromFile(fullShrinkwrapPath); + + 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); + + for (const project of rushConfiguration.projects) { + if ( + currentShrinkwrap + .getProjectShrinkwrap(project) + .hasChanges(oldShrinkWrap.getProjectShrinkwrap(project)) + ) { + changedProjects.add(project); + } + } + } 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; + } + + protected getChangesByProject( + lookup: LookupByPath, + changedFiles: Map + ): Map> { + return lookup.groupByChild(changedFiles); + } + + /** + * Gets a snapshot of the input state of the Rush workspace that can be queried for incremental + * build operations and use by the build cache. + * @internal + */ + public async _tryGetSnapshotProviderAsync( + projectConfigurations: ReadonlyMap, + terminal: ITerminal, + projectSelection?: ReadonlySet + ): Promise { + try { + const gitPath: string = this._git.getGitPathOrThrow(); + + if (!this._git.isPathUnderGitWorkingTree()) { + terminal.writeLine( + `The Rush monorepo is not in a Git repository. Rush will proceed without incremental build support.` + ); + + return; + } + + const rushConfiguration: RushConfiguration = this._rushConfiguration; + + // Do not use getGitInfo().root; it is the root of the *primary* worktree, not the *current* one. + const rootDirectory: string = getRepoRoot(rushConfiguration.rushJsonFolder, gitPath); + + // Load the rush-project.json files for the whole repository + const additionalGlobs: IAdditionalGlob[] = []; + + const projectMap: Map = new Map(); + + for (const project of rushConfiguration.projects) { + const projectConfig: RushProjectConfiguration | undefined = projectConfigurations.get(project); + + const additionalFilesByOperationName: Map> = new Map(); + const projectMetadata: IInputsSnapshotProjectMetadata = { + projectConfig, + additionalFilesByOperationName + }; + projectMap.set(project, projectMetadata); + + if (projectConfig) { + const { operationSettingsByOperationName } = projectConfig; + for (const [operationName, { dependsOnAdditionalFiles }] of operationSettingsByOperationName) { + if (dependsOnAdditionalFiles) { + const additionalFilesForOperation: Set = new Set(); + additionalFilesByOperationName.set(operationName, additionalFilesForOperation); + for (const pattern of dependsOnAdditionalFiles) { + additionalGlobs.push({ + project, + operationName, + additionalFilesForOperation, + pattern + }); + } + } + } + } + } + + // Include project shrinkwrap files as part of the computation + const additionalRelativePathsToHash: string[] = []; + const globalAdditionalFiles: string[] = []; + if (rushConfiguration.isPnpm) { + await Async.forEachAsync(rushConfiguration.projects, async (project: RushConfigurationProject) => { + const projectShrinkwrapFilePath: string = BaseProjectShrinkwrapFile.getFilePathForProject(project); + if (!(await FileSystem.existsAsync(projectShrinkwrapFilePath))) { + if (rushConfiguration.subspacesFeatureEnabled) { + return; + } + + throw new Error( + `A project dependency file (${projectShrinkwrapFilePath}) is missing. You may need to run ` + + '"rush install" or "rush update".' + ); + } + + const relativeProjectShrinkwrapFilePath: string = Path.convertToSlashes( + path.relative(rootDirectory, projectShrinkwrapFilePath) + ); + additionalRelativePathsToHash.push(relativeProjectShrinkwrapFilePath); + }); + } else { + // Add the shrinkwrap file to every project's dependencies + const currentVariant: string | undefined = + await this._rushConfiguration.getCurrentlyInstalledVariantAsync(); + + const shrinkwrapFile: string = Path.convertToSlashes( + path.relative( + rootDirectory, + rushConfiguration.defaultSubspace.getCommittedShrinkwrapFilePath(currentVariant) + ) + ); + + globalAdditionalFiles.push(shrinkwrapFile); + } + + const lookupByPath: IReadonlyLookupByPath = + this._rushConfiguration.getProjectLookupForRoot(rootDirectory); + + let filterPath: string[] = []; + + if ( + projectSelection && + projectSelection.size > 0 && + this._rushConfiguration.experimentsConfiguration.configuration.enableSubpathScan + ) { + filterPath = Array.from(projectSelection, ({ projectFolder }) => projectFolder); + } + + return async function tryGetSnapshotAsync(): Promise { + try { + const [{ files: hashes, hasUncommittedChanges }, additionalFiles] = await Promise.all([ + getDetailedRepoStateAsync(rootDirectory, additionalRelativePathsToHash, gitPath, filterPath), + getAdditionalFilesFromRushProjectConfigurationAsync( + additionalGlobs, + lookupByPath, + rootDirectory, + terminal + ) + ]); + + for (const file of additionalFiles) { + if (hashes.has(file)) { + additionalFiles.delete(file); + } + } + + const additionalHashes: Map = new Map( + await hashFilesAsync(rootDirectory, additionalFiles, gitPath) + ); + + return new InputsSnapshot({ + additionalHashes, + globalAdditionalFiles, + hashes, + hasUncommittedChanges, + lookupByPath, + projectMap, + rootDir: rootDirectory + }); + } catch (e) { + // If getRepoState fails, don't fail the whole build. Treat this case as if we don't know anything about + // the state of the files in the repo. This can happen if the environment doesn't have Git. + terminal.writeWarningLine( + `Error calculating the state of the repo. (inner error: ${ + e.stack ?? e.message ?? e + }). Continuing without diffing files.` + ); + + return; + } + }; + } catch (e) { + // If getRepoState fails, don't fail the whole build. Treat this case as if we don't know anything about + // the state of the files in the repo. This can happen if the environment doesn't have Git. + terminal.writeWarningLine( + `Error calculating the state of the repo. (inner error: ${ + e.stack ?? e.message ?? e + }). Continuing without diffing files.` + ); + + return; + } + } + + /** + * @internal + */ + public async _filterProjectDataAsync( + project: RushConfigurationProject, + unfilteredProjectData: Map, + rootDir: string, + terminal: ITerminal + ): Promise> { + const ignoreMatcher: Ignore | undefined = await this._getIgnoreMatcherForProjectAsync(project, terminal); + if (!ignoreMatcher) { + return unfilteredProjectData; + } + + const projectKey: string = path.relative(rootDir, project.projectFolder); + const projectKeyLength: number = projectKey.length + 1; + + // At this point, `filePath` is guaranteed to start with `projectKey`, so + // we can safely slice off the first N characters to get the file path relative to the + // root of the project. + const filteredProjectData: Map = new Map(); + for (const [filePath, value] of unfilteredProjectData) { + const relativePath: string = filePath.slice(projectKeyLength); + if (!ignoreMatcher.ignores(relativePath)) { + // Add the file path to the filtered data if it is not ignored + filteredProjectData.set(filePath, value); + } + } + return filteredProjectData; + } + + private async _getIgnoreMatcherForProjectAsync( + project: RushConfigurationProject, + terminal: ITerminal + ): Promise { + const incrementalBuildIgnoredGlobs: ReadonlyArray | undefined = + await RushProjectConfiguration.tryLoadIgnoreGlobsForProjectAsync(project, terminal); + + if (incrementalBuildIgnoredGlobs && incrementalBuildIgnoredGlobs.length) { + const ignoreMatcher: Ignore = ignore(); + ignoreMatcher.add(incrementalBuildIgnoredGlobs as string[]); + return ignoreMatcher; + } + } +} + +interface IAdditionalGlob { + project: RushConfigurationProject; + operationName: string; + additionalFilesForOperation: Set; + pattern: string; +} + +async function getAdditionalFilesFromRushProjectConfigurationAsync( + additionalGlobs: IAdditionalGlob[], + rootRelativeLookupByPath: IReadonlyLookupByPath, + rootDirectory: string, + terminal: ITerminal +): Promise> { + const additionalFilesFromRushProjectConfiguration: Set = new Set(); + + if (!additionalGlobs.length) { + return additionalFilesFromRushProjectConfiguration; + } + + const { default: glob } = await import('fast-glob'); + await Async.forEachAsync(additionalGlobs, async (item: IAdditionalGlob) => { + const { project, operationName, additionalFilesForOperation, pattern } = item; + const matches: string[] = await glob(pattern, { + cwd: project.projectFolder, + onlyFiles: true, + // We want to keep path's type unchanged, + // i.e. if the pattern was a relative path, then matched paths should also be relative paths + // if the pattern was an absolute path, then matched paths should also be absolute paths + // + // We are doing this because these paths are going to be used to calculate operation state hashes and some users + // might choose to depend on global files (e.g. `/etc/os-release`) and some might choose to depend on local non-project files + // (e.g. `../path/to/workspace/file`) + // + // In both cases we want that path to the resource to be the same on all machines, + // regardless of what is the current working directory. + // + // That being said, we want to keep `absolute` options here as false: + absolute: false + }); + + for (const match of matches) { + // The glob result is relative to the project folder, but we want it to be relative to the repo root + const rootRelativeFilePath: string = Path.convertToSlashes( + path.relative(rootDirectory, path.resolve(project.projectFolder, match)) + ); + + if (rootRelativeFilePath.startsWith('../')) { + // The target file is outside of the Git tree, use the original result of the match. + additionalFilesFromRushProjectConfiguration.add(match); + additionalFilesForOperation.add(match); + } else { + // The target file is inside of the Git tree, find out if it is in a Rush project. + const projectMatch: RushConfigurationProject | undefined = + rootRelativeLookupByPath.findChildPath(rootRelativeFilePath); + if (projectMatch && projectMatch !== project) { + terminal.writeErrorLine( + `In project "${project.packageName}" ("${project.projectRelativeFolder}"), ` + + `config for operation "${operationName}" specifies a glob "${pattern}" that selects a file "${rootRelativeFilePath}" in a different workspace project ` + + `"${projectMatch.packageName}" ("${projectMatch.projectRelativeFolder}"). ` + + `This is forbidden. The "dependsOnAdditionalFiles" property of "rush-project.json" may only be used to refer to non-workspace files, non-project files, ` + + `or untracked files in the current project. To depend on files in another workspace project, use "devDependencies" in "package.json".` + ); + throw new AlreadyReportedError(); + } + additionalFilesForOperation.add(rootRelativeFilePath); + additionalFilesFromRushProjectConfiguration.add(rootRelativeFilePath); + } + } + }); + + return additionalFilesFromRushProjectConfiguration; +} diff --git a/apps/rush-lib/src/logic/ProjectCommandSet.ts b/libraries/rush-lib/src/logic/ProjectCommandSet.ts similarity index 92% rename from apps/rush-lib/src/logic/ProjectCommandSet.ts rename to libraries/rush-lib/src/logic/ProjectCommandSet.ts index 36045b9eb8d..1070f31b5f8 100644 --- a/apps/rush-lib/src/logic/ProjectCommandSet.ts +++ b/libraries/rush-lib/src/logic/ProjectCommandSet.ts @@ -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. -import { - IPackageJson, - IPackageJsonScriptTable - } from '@rushstack/node-core-library'; +import type { IPackageJson, IPackageJsonScriptTable } from '@rushstack/node-core-library'; /** * Parses the "scripts" section from package.json and provides support for executing scripts. @@ -15,7 +12,7 @@ export class ProjectCommandSet { private readonly _scriptsByName: Map = new Map(); public constructor(packageJson: IPackageJson) { - const scripts: IPackageJsonScriptTable = packageJson.scripts || { }; + const scripts: IPackageJsonScriptTable = packageJson.scripts || {}; for (const scriptName of Object.keys(scripts)) { if (scriptName[0] === '-' || scriptName.length === 0) { diff --git a/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts new file mode 100644 index 00000000000..5f23e9d6339 --- /dev/null +++ b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; + +/** + * Project property configuration + */ +export interface IProjectImpactGraphProjectConfiguration { + includedGlobs: string[]; + excludedGlobs?: string[]; + dependentProjects: string[]; +} + +/** + * The schema of `project-impact-graph.yaml` + */ +export interface IProjectImpactGraphFile { + globalExcludedGlobs: string[]; + projects: Record; +} + +/** + * Default global excluded globs + * Only used if the `/.mergequeueignore` does not exist + */ +const DEFAULT_GLOBAL_EXCLUDED_GLOBS: string[] = ['common/autoinstallers/**']; + +async function tryReadFileLinesAsync(filePath: string): Promise { + let fileContents: string | undefined; + try { + fileContents = await FileSystem.readFileAsync(filePath); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; + } + } + + if (fileContents) { + return Text.convertToLf(fileContents).split('\n'); + } +} + +export class ProjectImpactGraphGenerator { + private readonly _terminal: ITerminal; + + /** + * The Rush configuration + */ + private readonly _rushConfiguration: RushConfiguration; + + /** + * Full path of repository root + */ + private readonly _repositoryRoot: string; + + /** + * Full path to `project-impact-graph.yaml` + */ + private readonly _projectImpactGraphFilePath: string; + + /** + * Get repositoryRoot and load projects within the rush.json + */ + public constructor(terminal: ITerminal, rushConfiguration: RushConfiguration) { + this._terminal = terminal; + this._rushConfiguration = rushConfiguration; + const { rushJsonFolder } = rushConfiguration; + this._repositoryRoot = rushJsonFolder; + this._projectImpactGraphFilePath = `${rushJsonFolder}/${RushConstants.projectImpactGraphFilename}`; + } + + /** + * Load global excluded globs + */ + private async _loadGlobalExcludedGlobsAsync(): Promise { + const filePath: string = `${this._repositoryRoot}/${RushConstants.mergeQueueIgnoreFileName}`; + return await tryReadFileLinesAsync(filePath); + } + + /** + * Load project excluded globs + * @param projectRootRelativePath - project root relative path + */ + private async _tryLoadProjectExcludedGlobsAsync( + projectRootRelativePath: string + ): Promise { + const filePath: string = `${this._repositoryRoot}/${projectRootRelativePath}/${RushConstants.mergeQueueIgnoreFileName}`; + + const globs: string[] | undefined = await tryReadFileLinesAsync(filePath); + if (globs) { + for (let i: number = 0; i < globs.length; i++) { + globs[i] = `${projectRootRelativePath}/${globs[i]}`; + } + + return globs; + } + } + + /** + * Core Logic: generate project-impact-graph.yaml + */ + public async generateAsync(): Promise { + const stopwatch: Stopwatch = Stopwatch.start(); + + const [globalExcludedGlobs = DEFAULT_GLOBAL_EXCLUDED_GLOBS, projectEntries] = await Promise.all([ + this._loadGlobalExcludedGlobsAsync(), + Async.mapAsync( + this._rushConfiguration.projects, + async ({ packageName, consumingProjects, projectRelativeFolder }) => { + const dependentList: string[] = [packageName]; + for (const consumingProject of consumingProjects) { + dependentList.push(consumingProject.packageName); + } + + const projectImpactGraphProjectConfiguration: IProjectImpactGraphProjectConfiguration = { + includedGlobs: [`${projectRelativeFolder}/**`], + dependentProjects: dependentList.sort() + }; + + const projectExcludedGlobs: string[] | undefined = + await this._tryLoadProjectExcludedGlobsAsync(projectRelativeFolder); + if (projectExcludedGlobs) { + projectImpactGraphProjectConfiguration.excludedGlobs = projectExcludedGlobs; + } + + return [packageName, projectImpactGraphProjectConfiguration]; + }, + { concurrency: 50 } + ) + ]); + + projectEntries.sort(([aName], [bName]) => aName.localeCompare(bName)); + const projects: Record = + Object.fromEntries(projectEntries); + const content: IProjectImpactGraphFile = { globalExcludedGlobs, projects }; + await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.dump(content)); + + stopwatch.stop(); + this._terminal.writeLine(); + this._terminal.writeLine( + Colorize.green(`Generate project impact graph successfully. (${stopwatch.toString()})`) + ); + } + + public async validateAsync(): Promise { + // TODO: More validation other than just existence + return await FileSystem.existsAsync(this._projectImpactGraphFilePath); + } +} diff --git a/libraries/rush-lib/src/logic/ProjectWatcher.ts b/libraries/rush-lib/src/logic/ProjectWatcher.ts new file mode 100644 index 00000000000..27ff8b72b47 --- /dev/null +++ b/libraries/rush-lib/src/logic/ProjectWatcher.ts @@ -0,0 +1,545 @@ +// 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 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 { Colorize, type ITerminal } from '@rushstack/terminal'; + +import { Git } from './Git'; +import type { IInputsSnapshot, GetInputsSnapshotAsyncFn } from './incremental/InputsSnapshot'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; + +export interface IProjectWatcherOptions { + abortSignal: AbortSignal; + getInputsSnapshotAsync: GetInputsSnapshotAsyncFn; + debounceMs?: number; + rushConfiguration: RushConfiguration; + projectsToWatch: ReadonlySet; + terminal: ITerminal; + initialSnapshot?: IInputsSnapshot | undefined; +} + +export interface IProjectChangeResult { + /** + * The set of projects that have changed since the last iteration + */ + changedProjects: ReadonlySet; + /** + * Contains the git hashes for all tracked files in the repo + */ + inputsSnapshot: IInputsSnapshot; +} + +export interface IPromptGeneratorFunction { + (isPaused: boolean): Iterable; +} + +interface IPathWatchOptions { + recurse: boolean; +} + +/** + * 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. + * + * 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. + */ +export class ProjectWatcher { + private readonly _abortSignal: AbortSignal; + 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 _onAbort: undefined | (() => void); + private _getPromptLines: undefined | IPromptGeneratorFunction; + + private _lastStatus: string | undefined; + private _renderedStatusLines: number; + + public isPaused: boolean = false; + + public constructor(options: IProjectWatcherOptions) { + const { + abortSignal, + getInputsSnapshotAsync: snapshotProvider, + debounceMs = 1000, + rushConfiguration, + projectsToWatch, + terminal, + initialSnapshot: initialState + } = options; + + this._abortSignal = abortSignal; + abortSignal.addEventListener('abort', () => { + this._onAbort?.(); + }); + this._debounceMs = debounceMs; + this._rushConfiguration = rushConfiguration; + this._projectsToWatch = projectsToWatch; + this._terminal = terminal; + + const gitPath: string = new Git(rushConfiguration).getGitPathOrThrow(); + this._repoRoot = Path.convertToSlashes(getRepoRoot(rushConfiguration.rushJsonFolder, gitPath)); + this._resolveIfChanged = undefined; + this._onAbort = undefined; + + this._initialSnapshot = initialState; + this._previousSnapshot = initialState; + + this._renderedStatusLines = 0; + this._getPromptLines = undefined; + this._getInputsSnapshotAsync = snapshotProvider; + } + + 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; + } + + this._forceChangedProjects.set(project, reason); + return true; + } + + public invalidateAll(reason: string): void { + for (const project of this._projectsToWatch) { + this.invalidateProject(project, reason); + } + } + + public clearStatus(): void { + this._renderedStatusLines = 0; + } + + public rerenderStatus(): void { + this._setStatus(this._lastStatus ?? 'Waiting for changes...'); + } + + public setPromptGenerator(promptGenerator: IPromptGeneratorFunction): void { + this._getPromptLines = promptGenerator; + } + + /** + * 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. + */ + public async waitForChangeAsync(onWatchingFiles?: () => void): Promise { + if (this.isPaused) { + this._setStatus(`Project watcher paused.`); + await new Promise((resolve) => { + this._resolveIfChanged = async () => resolve(); + }); + } + + 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); + } + // 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; + } + + const previousState: IInputsSnapshot = initialChangeResult.inputsSnapshot; + 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'; + + 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 }); + } + } + } + + if (this._abortSignal.aborted) { + return initialChangeResult; + } + + const watchers: Map = new Map(); + const closePromises: Promise[] = []; + + 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; + + const abortSignal: AbortSignal = this._abortSignal; + + this.clearStatus(); + + this._onAbort = function onAbort(): void { + if (timeout) { + clearTimeout(timeout); + } + terminated = true; + resolve(initialChangeResult); + }; + + if (abortSignal.aborted) { + return this._onAbort(); + } + + 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); + } + + 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, + signal: abortSignal + }, + listener + ); + watchers.set(watchedPath, watcher); + watcher.once('error', (err) => { + watcher.close(); + onError(err); + }); + closePromises.push( + once(watcher, 'close').then(() => { + watchers.delete(watchedPath); + watcher.removeAllListeners(); + watcher.unref(); + }) + ); + } + + 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); + } + } + ).finally(() => { + this._onAbort = undefined; + this._resolveIfChanged = undefined; + }); + + this._terminal.writeDebugLine(`Closing watchers...`); + + for (const watcher of watchers.values()) { + watcher.close(); + } + + await Promise.all(closePromises); + this._terminal.writeDebugLine(`Closed ${closePromises.length} watchers`); + + return watchedResult; + } + + 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); + } + this._renderedStatusLines = statusLines.length; + this._lastStatus = status; + + this._terminal.writeLine(Colorize.bold(Colorize.cyan(statusLines.join('\n')))); + } + + /** + * Determines which, if any, projects (within the selection) have new hashes for files that are not in .gitignore + */ + private async _computeChangedAsync(): Promise { + const currentSnapshot: IInputsSnapshot | undefined = await this._getInputsSnapshotAsync(); + + if (!currentSnapshot) { + throw new AlreadyReportedError(); + } + + const previousSnapshot: IInputsSnapshot | undefined = this._previousSnapshot; + + if (!previousSnapshot) { + return { + changedProjects: this._projectsToWatch, + inputsSnapshot: currentSnapshot + }; + } + + 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); + } + } + + for (const project of this._forceChangedProjects.keys()) { + changedProjects.add(project); + } + + return { + changedProjects, + inputsSnapshot: currentSnapshot + }; + } + + private _commitChanges(state: IInputsSnapshot): void { + this._previousSnapshot = state; + if (!this._initialSnapshot) { + this._initialSnapshot = state; + } + } + + /** + * Tests for inequality of the passed Maps. Order invariant. + * + * @returns `true` if the maps are different, `false` otherwise + */ + private static _haveProjectDepsChanged( + prev: ReadonlyMap | undefined, + next: ReadonlyMap | undefined + ): boolean { + if (!prev && !next) { + return false; + } + + if (!prev || !next) { + return true; + } + + if (prev.size !== next.size) { + return true; + } + + for (const [key, value] of prev) { + if (next.get(key) !== value) { + return true; + } + } + + 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); + + 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 new file mode 100644 index 00000000000..df0e63d48a8 --- /dev/null +++ b/libraries/rush-lib/src/logic/PublishGit.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 { PublishUtilities } from './PublishUtilities'; +import { Utilities } from '../utilities/Utilities'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { Git } from './Git'; + +const DUMMY_BRANCH_NAME: string = '-branch-name-'; + +export class PublishGit { + private readonly _targetBranch: string | undefined; + private readonly _gitPath: string; + private readonly _gitTagSeparator: string; + + public constructor(git: Git, targetBranch: string | undefined) { + this._targetBranch = targetBranch; + this._gitPath = git.getGitPathOrThrow(); + this._gitTagSeparator = git.getTagSeparator(); + } + + public async checkoutAsync(branchName: string | undefined, createBranch: boolean = false): Promise { + const params: string[] = ['checkout']; + if (createBranch) { + params.push('-b'); + } + + params.push(branchName || DUMMY_BRANCH_NAME); + + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, params); + } + + public async mergeAsync(branchName: string, verify: boolean = false): Promise { + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ + 'merge', + branchName, + '--no-edit', + ...(verify ? [] : ['--no-verify']) + ]); + } + + public async deleteBranchAsync( + branchName: string | undefined, + hasRemote: boolean = true, + verify: boolean = false + ): Promise { + if (!branchName) { + branchName = DUMMY_BRANCH_NAME; + } + + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ + 'branch', + '-d', + branchName + ]); + if (hasRemote) { + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ + 'push', + 'origin', + '--delete', + branchName, + ...(verify ? [] : ['--no-verify']) + ]); + } + } + + public async pullAsync(verify: boolean = false): Promise { + const params: string[] = ['pull', 'origin']; + if (this._targetBranch) { + params.push(this._targetBranch); + } + if (!verify) { + params.push('--no-verify'); + } + + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, params); + } + + public async fetchAsync(): Promise { + await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, ['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() + ); + } + + public async addTagAsync( + shouldExecute: boolean, + packageName: string, + packageVersion: string, + commitId: string | undefined, + preReleaseName?: string + ): Promise { + // Tagging only happens if we're publishing to real NPM and committing to git. + const tagName: string = PublishUtilities.createTagname( + packageName, + 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] : []) + ]); + } + + public async hasTagAsync(packageConfig: RushConfigurationProject): Promise { + const tagName: string = PublishUtilities.createTagname( + packageConfig.packageName, + packageConfig.packageJson.version, + this._gitTagSeparator + ); + const tagOutput: string = ( + await Utilities.executeCommandAndCaptureOutputAsync( + this._gitPath, + ['tag', '-l', tagName], + packageConfig.projectFolder, + PublishUtilities.getEnvArgs(), + 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']) + ]); + } + + public async pushAsync( + branchName: string | undefined, + verify: boolean = false, + followTags: boolean = true + ): Promise { + await PublishUtilities.execCommandAsync( + !!this._targetBranch, + 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. + [ + 'push', + 'origin', + `HEAD:${branchName || DUMMY_BRANCH_NAME}`, + ...(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 new file mode 100644 index 00000000000..8f9c8556db7 --- /dev/null +++ b/libraries/rush-lib/src/logic/PublishUtilities.ts @@ -0,0 +1,902 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * This file contains a set of helper functions that are unit tested and used with the PublishAction, + * which itself is a thin wrapper around these helpers. + */ + +import * as path from 'node:path'; +import { execSync } from 'node:child_process'; + +import * as semver from 'semver'; + +import { + type IPackageJson, + JsonFile, + FileConstants, + Text, + Enum, + InternalError +} from '@rushstack/node-core-library'; + +import { type IChangeInfo, ChangeType, type IVersionPolicyChangeInfo } from '../api/ChangeManagement'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import { Utilities, type IEnvironment } from '../utilities/Utilities'; +import type { PrereleaseToken } from './PrereleaseToken'; +import type { ChangeFiles } from './ChangeFiles'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { DependencySpecifier, DependencySpecifierType } from './DependencySpecifier'; +import { Git, DEFAULT_GIT_TAG_SEPARATOR } from './Git'; +import type { LockStepVersionPolicy } from '../api/VersionPolicy'; + +export interface IChangeRequests { + packageChanges: Map; + versionPolicyChanges: Map; +} + +interface IAddChangeOptions { + change: IChangeInfo; + changeFilePath?: string; + allChanges: IChangeRequests; + allPackages: ReadonlyMap; + rushConfiguration: RushConfiguration; + prereleaseToken?: PrereleaseToken; + projectsToExclude?: Set; +} + +const MAGIC_SPECIFIERS: Set = new Set(['*', '^', '~']); + +export class PublishUtilities { + /** + * Finds change requests in the given folder. + * @param changesPath Path to the changes folder. + * @returns Dictionary of all change requests, keyed by package name. + */ + public static async findChangeRequestsAsync( + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + changeFiles: ChangeFiles, + includeCommitDetails?: boolean, + prereleaseToken?: PrereleaseToken, + projectsToExclude?: Set + ): Promise { + const allChanges: IChangeRequests = { + packageChanges: new Map(), + versionPolicyChanges: new Map() + }; + + // eslint-disable-next-line no-console + console.log(`Finding changes in: ${changeFiles.getChangesPath()}`); + + const files: string[] = await changeFiles.getFilesAsync(); + + // Add the minimum changes defined by the change descriptions. + for (const changeFilePath of files) { + const changeRequest: IChangeInfo = JsonFile.load(changeFilePath); + + if (includeCommitDetails) { + const git: Git = new Git(rushConfiguration); + PublishUtilities._updateCommitDetails(git, changeFilePath, changeRequest.changes); + } + + for (const change of changeRequest.changes!) { + PublishUtilities._addChange({ + change, + changeFilePath, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + }); + } + } + + // keep resolving downstream dependency changes and version policy changes + // until no more changes are detected + let hasChanges: boolean; + do { + hasChanges = false; + + // For each requested package change, ensure downstream dependencies are also updated. + allChanges.packageChanges.forEach((change, packageName) => { + hasChanges = + PublishUtilities._updateDownstreamDependencies( + change, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ) || hasChanges; + }); + + // Bump projects affected by the version policy changes. + allPackages.forEach((project) => { + const versionPolicyChange: IVersionPolicyChangeInfo | undefined = + project.versionPolicyName !== undefined + ? allChanges.versionPolicyChanges.get(project.versionPolicyName) + : undefined; + + if (versionPolicyChange === undefined) { + return; + } + + const projectHasChanged: boolean = this._addChange({ + change: { + packageName: project.packageName, + changeType: versionPolicyChange.changeType, + newVersion: versionPolicyChange.newVersion // enforce the specific policy version + }, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + }); + + if (projectHasChanged) { + // eslint-disable-next-line no-console + console.log( + `\n* APPLYING: update ${project.packageName} to version ${versionPolicyChange.newVersion}` + ); + } + + hasChanges = projectHasChanged || hasChanges; + }); + } while (hasChanges); + + // Update orders so that downstreams are marked to come after upstreams. + allChanges.packageChanges.forEach((change, packageName) => { + const project: RushConfigurationProject = allPackages.get(packageName)!; + const packageJson: IPackageJson = project.packageJson; + const deps: Iterable = project.consumingProjects; + + // Write the new version expected for the change. + const skipVersionBump: boolean = PublishUtilities._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!))! + : change.changeType === ChangeType.hotfix + ? change.newVersion + : packageJson.version; + } + + if (deps) { + for (const dep of deps) { + const depChange: IChangeInfo | undefined = allChanges.packageChanges.get(dep.packageName); + if (depChange) { + depChange.order = Math.max(change.order! + 1, depChange.order!); + } + } + } + }); + + return allChanges; + } + + /** + * Given the changes hash, flattens them into a sorted array based on their dependency order. + * @params packageChanges - hash of change requests. + * @returns Sorted array of change requests. + */ + public static sortChangeRequests(packageChanges: Map): IChangeInfo[] { + return [...packageChanges.values()].sort((a, b) => + a.order! === b.order! ? a.packageName.localeCompare(b.packageName) : a.order! < b.order! ? -1 : 1 + ); + } + + /** + * Given a single change request, updates the package json file with updated versions on disk. + */ + public static updatePackages( + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + shouldCommit: boolean, + prereleaseToken?: PrereleaseToken, + projectsToExclude?: Set + ): Map { + const updatedPackages: Map = new Map(); + + allChanges.packageChanges.forEach((change, packageName) => { + const updatedPackage: IPackageJson = PublishUtilities._writePackageChanges( + change, + allChanges, + allPackages, + rushConfiguration, + shouldCommit, + prereleaseToken, + projectsToExclude + ); + updatedPackages.set(updatedPackage.name, updatedPackage); + }); + + return updatedPackages; + } + + /** + * Returns the generated tagname to use for a published commit, given package name and version. + */ + public static createTagname( + packageName: string, + version: string, + separator: string = DEFAULT_GIT_TAG_SEPARATOR + ): string { + return packageName + `${separator}v` + version; + } + + public static isRangeDependency(version: string): boolean { + const LOOSE_PKG_REGEX: RegExp = />=?(?:\d+\.){2}\d+(\-[0-9A-Za-z-.]*)?\s+<(?:\d+\.){2}\d+/; + + return LOOSE_PKG_REGEX.test(version); + } + + public static getEnvArgs(): { [key: string]: string | undefined } { + const env: { [key: string]: string | undefined } = {}; + + // Copy existing process.env values (for nodist) + Object.keys(process.env).forEach((key: string) => { + env[key] = process.env[key]; + }); + return env; + } + + /** + * @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 { + let relativeDirectory: string = path.relative(process.cwd(), workingDirectory); + + if (relativeDirectory) { + relativeDirectory = `(${relativeDirectory})`; + } + + let commandArgs: string = args.join(' '); + + if (secretSubstring && secretSubstring.length > 0) { + // Avoid printing the NPM publish token on the console when displaying the commandArgs + commandArgs = Text.replaceAll(commandArgs, secretSubstring, '<>'); + } + + // eslint-disable-next-line no-console + console.log( + `\n* ${shouldExecute ? 'EXECUTING' : 'DRYRUN'}: ${command} ${commandArgs} ${relativeDirectory}` + ); + + if (shouldExecute) { + await Utilities.executeCommandAsync({ + command, + args, + workingDirectory, + environment, + suppressOutput: false, + keepEnvironment: true + }); + } + } + + public static getNewDependencyVersion( + dependencies: { [key: string]: string }, + dependencyName: string, + newProjectVersion: string + ): string { + const currentDependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependencyName, + dependencies[dependencyName] + ); + const currentDependencyVersion: string = currentDependencySpecifier.versionSpecifier; + let newDependencyVersion: string; + + if (MAGIC_SPECIFIERS.has(currentDependencyVersion)) { + // pnpm and yarn support `workspace:*', `workspace:~`, and `workspace:^` as valid version specifiers + // These translate as `current`, `~current`, and `^current` when published + newDependencyVersion = currentDependencyVersion; + } else if (PublishUtilities.isRangeDependency(currentDependencyVersion)) { + newDependencyVersion = PublishUtilities._getNewRangeDependency(newProjectVersion); + } else if (currentDependencyVersion.lastIndexOf('~', 0) === 0) { + newDependencyVersion = '~' + newProjectVersion; + } else if (currentDependencyVersion.lastIndexOf('^', 0) === 0) { + newDependencyVersion = '^' + newProjectVersion; + } else { + newDependencyVersion = newProjectVersion; + } + return currentDependencySpecifier.specifierType === DependencySpecifierType.Workspace + ? `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}`); + } + } + + 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}`; + } + + 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 + ); + } + + 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. */ + } + } + + 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 shouldSkipVersionBump: boolean = + !project.shouldPublish || (!!projectsToExclude && projectsToExclude.has(change.packageName)); + + const newVersion: string = shouldSkipVersionBump + ? packageJson.version + : PublishUtilities._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}` + ); + } + + const packagePath: string = path.join(project.projectFolder, FileConstants.PackageJson); + + packageJson.version = newVersion; + + // 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 + ); + + change.changes!.forEach((subChange) => { + if (subChange.comment) { + // eslint-disable-next-line no-console + console.log(` - [${ChangeType[subChange.changeType!]}] ${subChange.comment}`); + } + }); + + if (shouldCommit) { + JsonFile.save(packageJson, packagePath, { updateExistingFile: true }); + } + return packageJson; + } + + private static _isCyclicDependency( + allPackages: ReadonlyMap, + packageName: string, + dependencyName: string + ): boolean { + const packageConfig: RushConfigurationProject | undefined = allPackages.get(packageName); + return !!packageConfig && packageConfig.decoupledLocalDependencies.has(dependencyName); + } + + 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 = DependencySpecifier.parseWithCache( + 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 + ); + } + } + }); + } + } + + /** + * 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')!; + } + 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); + + 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; + } + + 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)}`); + } + } + } + + 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!; + + 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)); + } + + 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.`); + } + + 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; + } + + const shouldBump: boolean = + change.newVersion === undefined && change.changeType! >= ChangeType.hotfix; + + currentChange.newVersion = shouldBump + ? semver.inc(packageVersion, PublishUtilities._getReleaseType(currentChange.changeType!))! + : packageVersion; + + // 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 ( + 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 + }); + } + } + } + + // 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; + } + + 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; + } + } + } + + 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 = DependencySpecifier.parseWithCache( + 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); + + // 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; + } + + hasChanges = PublishUtilities._addChange({ + change: { + packageName: parentPackageName, + changeType + }, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + }); + + 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; + } + } + } + + return hasChanges; + } + + 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}`; + } + } + 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 = 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 = PublishUtilities._getPublishDependencyVersion( + newDependencySpecifier, + dependencyChange.newVersion! + ); + + // 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 + }); + } +} diff --git a/libraries/rush-lib/src/logic/PurgeManager.ts b/libraries/rush-lib/src/logic/PurgeManager.ts new file mode 100644 index 00000000000..58df2009851 --- /dev/null +++ b/libraries/rush-lib/src/logic/PurgeManager.ts @@ -0,0 +1,136 @@ +// 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 { Colorize } from '@rushstack/terminal'; + +import { AsyncRecycler } from '../utilities/AsyncRecycler'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { RushConstants } from './RushConstants'; +import type { RushGlobalFolder } from '../api/RushGlobalFolder'; + +/** + * This class implements the logic for "rush purge" + */ +export class PurgeManager { + private _rushConfiguration: RushConfiguration; + private _rushGlobalFolder: RushGlobalFolder; + private _rushUserFolderRecycler: AsyncRecycler; + + public readonly commonTempFolderRecycler: AsyncRecycler; + + public constructor(rushConfiguration: RushConfiguration, rushGlobalFolder: RushGlobalFolder) { + this._rushConfiguration = rushConfiguration; + this._rushGlobalFolder = rushGlobalFolder; + + const commonAsyncRecyclerPath: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.rushRecyclerFolderName + ); + this.commonTempFolderRecycler = new AsyncRecycler(commonAsyncRecyclerPath); + + const rushUserAsyncRecyclerPath: string = path.join( + this._rushGlobalFolder.path, + RushConstants.rushRecyclerFolderName + ); + this._rushUserFolderRecycler = new AsyncRecycler(rushUserAsyncRecyclerPath); + } + + /** + * Performs the AsyncRecycler.deleteAll() operation. This should be called before + * the PurgeManager instance is disposed. + */ + public async startDeleteAllAsync(): Promise { + await Promise.all([ + this.commonTempFolderRecycler.startDeleteAllAsync(), + this._rushUserFolderRecycler.startDeleteAllAsync() + ]); + } + + /** + * Delete everything from the common/temp folder + */ + public purgeNormal(): void { + // Delete everything under common\temp except for the recycler folder itself + // eslint-disable-next-line no-console + console.log('Purging ' + this._rushConfiguration.commonTempFolder); + + this.commonTempFolderRecycler.moveAllItemsInFolder( + this._rushConfiguration.commonTempFolder, + this._getMembersToExclude(this._rushConfiguration.commonTempFolder, true) + ); + } + + /** + * In addition to performing the purgeNormal() operation, this method also cleans the + * .rush folder in the user's home directory. + */ + public purgeUnsafe(): void { + this.purgeNormal(); + + // We will delete everything under ~/.rush/ except for the recycler folder itself + // eslint-disable-next-line no-console + console.log('Purging ' + this._rushGlobalFolder.path); + + // If Rush itself is running under a folder such as ~/.rush/node-v4.5.6/rush-1.2.3, + // we cannot delete that folder. + + // First purge the node-specific folder, e.g. ~/.rush/node-v4.5.6/* except for rush-1.2.3: + this._rushUserFolderRecycler.moveAllItemsInFolder( + this._rushGlobalFolder.nodeSpecificPath, + this._getMembersToExclude(this._rushGlobalFolder.nodeSpecificPath, true) + ); + + // Then purge the the global folder, e.g. ~/.rush/* except for node-v4.5.6 + this._rushUserFolderRecycler.moveAllItemsInFolder( + this._rushGlobalFolder.path, + this._getMembersToExclude(this._rushGlobalFolder.path, false) + ); + + if ( + this._rushConfiguration.isPnpm && + this._rushConfiguration.pnpmOptions.pnpmStore === 'global' && + this._rushConfiguration.pnpmOptions.pnpmStorePath + ) { + // eslint-disable-next-line no-console + console.warn(Colorize.yellow(`Purging the global pnpm-store`)); + this._rushUserFolderRecycler.moveAllItemsInFolder(this._rushConfiguration.pnpmOptions.pnpmStorePath); + } + } + + private _getMembersToExclude(folderToRecycle: string, showWarning: boolean): string[] { + // Don't recycle the recycler + const membersToExclude: string[] = [RushConstants.rushRecyclerFolderName]; + + // If the current process is running inside one of the folders, don't recycle that either + // Example: "/home/user/.rush/rush-1.2.3/lib/example.js" + const currentFolderPath: string = path.resolve(__dirname); + + // Example: + // folderToRecycle = "/home/user/.rush/node-v4.5.6" + // relative = "rush-1.2.3/lib/example.js" + const relative: string = path.relative(folderToRecycle, currentFolderPath); + + // (The result can be an absolute path if the two folders are on different drive letters) + if (!path.isAbsolute(relative)) { + // Get the first path segment: + const firstPart: string = relative.split(/[\\\/]/)[0]; + if (firstPart.length > 0 && firstPart !== '..') { + membersToExclude.push(firstPart); + + if (showWarning) { + // Warn that we won't dispose this folder + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + "The active process's folder will not be deleted: " + path.join(folderToRecycle, firstPart) + ) + ); + } + } + } + + return membersToExclude; + } +} diff --git a/libraries/rush-lib/src/logic/RepoStateFile.ts b/libraries/rush-lib/src/logic/RepoStateFile.ts new file mode 100644 index 00000000000..0bfd0f2e82e --- /dev/null +++ b/libraries/rush-lib/src/logic/RepoStateFile.ts @@ -0,0 +1,288 @@ +// 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, NewlineKind } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; +import type { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; +import schemaJson from '../schemas/repo-state.schema.json'; +import type { Subspace } from '../api/Subspace'; + +/** + * This interface represents the raw repo-state.json file + * Example: + * { + * "pnpmShrinkwrapHash": "...", + * "preferredVersionsHash": "...", + * "packageJsonInjectedDependenciesHash": "...", + * "pnpmCatalogsHash": "..." + * } + */ +interface IRepoStateJson { + /** + * A hash of the PNPM shrinkwrap file contents + */ + pnpmShrinkwrapHash?: string; + /** + * A hash of the CommonVersionsConfiguration.preferredVersions field + */ + preferredVersionsHash?: string; + /** + * A hash of the injected dependencies in related package.json + */ + packageJsonInjectedDependenciesHash?: string; + /** + * A hash of the PNPM catalog definitions + */ + pnpmCatalogsHash?: string; +} + +/** + * This file is used to track the state of various Rush-related features. It is generated + * and updated by Rush. + * + * @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; + + /** + * Get the absolute file path of the repo-state.json file. + */ + public readonly filePath: string; + + private constructor(repoStateJson: IRepoStateJson | undefined, isValid: boolean, filePath: string) { + this.filePath = filePath; + this._isValid = isValid; + + if (repoStateJson) { + this._pnpmShrinkwrapHash = repoStateJson.pnpmShrinkwrapHash; + this._preferredVersionsHash = repoStateJson.preferredVersionsHash; + this._packageJsonInjectedDependenciesHash = repoStateJson.packageJsonInjectedDependenciesHash; + this._pnpmCatalogsHash = repoStateJson.pnpmCatalogsHash; + } + } + + /** + * The hash of the pnpm shrinkwrap file at the end of the last update. + */ + public get pnpmShrinkwrapHash(): string | undefined { + return this._pnpmShrinkwrapHash; + } + + /** + * The hash of all preferred versions at the end of the last update. + */ + public get preferredVersionsHash(): string | undefined { + return this._preferredVersionsHash; + } + + /** + * The hash of all preferred versions at the end of the last update. + */ + public get packageJsonInjectedDependenciesHash(): string | undefined { + 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 + */ + public get isValid(): boolean { + return this._isValid; + } + + /** + * Loads the repo-state.json data from the specified file path. + * If the file has not been created yet, then an empty object is returned. + * + * @param jsonFilename - The path to the repo-state.json file. + */ + public static loadFromFile(jsonFilename: string): RepoStateFile { + let fileContents: string | undefined; + try { + fileContents = FileSystem.readFile(jsonFilename); + } catch (error) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + } + + let foundMergeConflictMarker: boolean = false; + let repoStateJson: IRepoStateJson | undefined = undefined; + if (fileContents) { + try { + repoStateJson = JsonFile.parseString(fileContents); + } catch (error) { + // Look for a Git merge conflict marker. PNPM gracefully handles merge conflicts in pnpm-lock.yaml, + // so a user should be able to just run "rush update" if they get conflicts in pnpm-lock.yaml + // and repo-state.json and have Rush update both. + for ( + let nextNewlineIndex: number = 0; + nextNewlineIndex > -1; + nextNewlineIndex = fileContents.indexOf('\n', nextNewlineIndex + 1) + ) { + if (fileContents.substr(nextNewlineIndex + 1, 7) === '<<<<<<<') { + foundMergeConflictMarker = true; + repoStateJson = { + preferredVersionsHash: 'INVALID', + pnpmShrinkwrapHash: 'INVALID' + }; + break; + } + } + } + + if (repoStateJson) { + this._jsonSchema.validateObject(repoStateJson, jsonFilename); + } + } + + return new RepoStateFile(repoStateJson, !foundMergeConflictMarker, jsonFilename); + } + + /** + * Refresh the data contained in repo-state.json using the current state + * of the Rush repo, and save the file if changes were made. + * + * @param rushConfiguration - The Rush configuration for the repo. + * @param subspace - The subspace that repo-state.json was loaded from, + * or `undefined` for the default subspace. + * + * @returns true if the file was modified, otherwise false. + */ + public refreshState( + rushConfiguration: RushConfiguration, + subspace: Subspace | undefined, + variant?: string + ): boolean { + if (subspace === undefined) { + subspace = rushConfiguration.defaultSubspace; + } + + // Only support saving the pnpm shrinkwrap hash if it was enabled + const preventShrinkwrapChanges: boolean = + rushConfiguration.isPnpm && + rushConfiguration.pnpmOptions && + rushConfiguration.pnpmOptions.preventManualShrinkwrapChanges; + if (preventShrinkwrapChanges) { + const pnpmShrinkwrapFile: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( + subspace.getCommittedShrinkwrapFilePath(variant) + ); + + if (pnpmShrinkwrapFile) { + const shrinkwrapFileHash: string = pnpmShrinkwrapFile.getShrinkwrapHash( + rushConfiguration.experimentsConfiguration.configuration + ); + + if (this._pnpmShrinkwrapHash !== shrinkwrapFileHash) { + this._pnpmShrinkwrapHash = shrinkwrapFileHash; + this._modified = true; + } + } + } else if (this._pnpmShrinkwrapHash !== undefined) { + this._pnpmShrinkwrapHash = undefined; + this._modified = true; + } + + // Currently, only support saving the preferred versions hash if using workspaces + const useWorkspaces: boolean = + rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.useWorkspaces; + if (useWorkspaces) { + const commonVersions: CommonVersionsConfiguration = subspace.getCommonVersions(variant); + const preferredVersionsHash: string = commonVersions.getPreferredVersionsHash(); + if (this._preferredVersionsHash !== preferredVersionsHash) { + this._preferredVersionsHash = preferredVersionsHash; + this._modified = true; + } + } else if (this._preferredVersionsHash !== undefined) { + this._preferredVersionsHash = undefined; + this._modified = true; + } + + if (rushConfiguration.isPnpm) { + const packageJsonInjectedDependenciesHash: string | undefined = + subspace.getPackageJsonInjectedDependenciesHash(variant); + + // packageJsonInjectedDependenciesHash is undefined, means there is no injected dependencies for that subspace + // so we don't need to track the hash value for that subspace + if ( + packageJsonInjectedDependenciesHash && + packageJsonInjectedDependenciesHash !== this._packageJsonInjectedDependenciesHash + ) { + this._packageJsonInjectedDependenciesHash = packageJsonInjectedDependenciesHash; + this._modified = true; + } else if (!packageJsonInjectedDependenciesHash && this._packageJsonInjectedDependenciesHash) { + // if packageJsonInjectedDependenciesHash is undefined, but this._packageJsonInjectedDependenciesHash is not + // means users may turn off the injected installation + // so we will need to remove unused fields in repo-state.json as well + 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 + this._isValid = true; + + return this._saveIfModified(); + } + + /** + * Writes the "repo-state.json" file to disk, using the filename that was passed to loadFromFile(). + */ + private _saveIfModified(): boolean { + if (this._modified) { + const content: string = + '// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.' + + `${NewlineKind.Lf}${this._serialize()}`; + FileSystem.writeFile(this.filePath, content); + this._modified = false; + return true; + } + + return false; + } + + private _serialize(): string { + // We need to set these one-by-one, since JsonFile.stringify does not like undefined values + const repoStateJson: IRepoStateJson = {}; + if (this._pnpmShrinkwrapHash) { + repoStateJson.pnpmShrinkwrapHash = this._pnpmShrinkwrapHash; + } + if (this._preferredVersionsHash) { + repoStateJson.preferredVersionsHash = this._preferredVersionsHash; + } + 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 new file mode 100644 index 00000000000..0f5ed03c8e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/RushConstants.ts @@ -0,0 +1,366 @@ +// 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 + * + * @remarks + * + * These are NOT part of the public API surface for rush-lib. + * The rationale is that we don't want people implementing custom parsers for + * the Rush config files; instead, they should rely on the official APIs from rush-lib. + */ +export class RushConstants { + /** + * The filename ("rush.json") for the root-level configuration file. + */ + public static readonly rushJsonFilename: 'rush.json' = 'rush.json'; + + /** + * The filename ("browser-approved-packages.json") for an optional policy configuration file + * that stores a list of NPM packages that have been approved for usage by Rush projects. + * This is part of a pair of config files, one for projects that run in a web browser + * (e.g. whose approval criteria mostly focuses on licensing and code size), and one for everywhere else + * (e.g. tooling projects whose approval criteria mostly focuses on avoiding node_modules sprawl). + */ + public static readonly browserApprovedPackagesFilename: 'browser-approved-packages.json' = + 'browser-approved-packages.json'; + + /** + * The folder name ("changes") where change files will be stored. + */ + public static readonly changeFilesFolderName: 'changes' = 'changes'; + + /** + * The filename ("nonbrowser-approved-packages.json") for an optional policy configuration file + * that stores a list of NPM packages that have been approved for usage by Rush projects. + * This is part of a pair of config files, one for projects that run in a web browser + * (e.g. whose approval criteria mostly focuses on licensing and code size), and one for everywhere else + * (e.g. tooling projects whose approval criteria mostly focuses on avoiding node_modules sprawl). + */ + public static readonly nonbrowserApprovedPackagesFilename: 'nonbrowser-approved-packages.json' = + 'nonbrowser-approved-packages.json'; + + /** + * The folder name ("common") where Rush's common data will be stored. + */ + public static readonly commonFolderName: 'common' = 'common'; + + /** + * The NPM scope ("\@rush-temp") that is used for Rush's temporary projects. + */ + public static readonly rushTempNpmScope: '@rush-temp' = '@rush-temp'; + + /** + * The folder name ("variants") under which named variant configurations for + * alternate dependency sets may be found. + * Example: `C:\MyRepo\common\config\rush\variants` + */ + public static readonly rushVariantsFolderName: 'variants' = 'variants'; + + /** + * The folder name ("temp") under the common folder, or under the .rush folder in each project's directory where + * temporary files will be stored. + * Example: `C:\MyRepo\common\temp` + */ + public static readonly rushTempFolderName: 'temp' = 'temp'; + + /** + * The folder name ("projects") where temporary projects will be stored. + * Example: `C:\MyRepo\common\temp\projects` + */ + public static readonly rushTempProjectsFolderName: 'projects' = 'projects'; + + /** + * The filename ("npm-shrinkwrap.json") used to store an installation plan for the NPM package manger. + */ + public static readonly npmShrinkwrapFilename: 'npm-shrinkwrap.json' = 'npm-shrinkwrap.json'; + + /** + * Number of installation attempts + */ + public static readonly defaultMaxInstallAttempts: 1 = 1; + + /** + * The filename ("pnpm-lock.yaml") used to store an installation plan for the PNPM package manger + * (PNPM version 3.x and later). + */ + public static readonly pnpmV3ShrinkwrapFilename: 'pnpm-lock.yaml' = 'pnpm-lock.yaml'; + + /** + * The filename ("pnpmfile.js") used to add custom configuration to PNPM (PNPM version 1.x and later). + */ + public static readonly pnpmfileV1Filename: 'pnpmfile.js' = 'pnpmfile.js'; + + /** + * The filename (".pnpmfile.cjs") used to add custom configuration to PNPM (PNPM version 6.x and later). + */ + public static readonly pnpmfileV6Filename: '.pnpmfile.cjs' = '.pnpmfile.cjs'; + + /** + * The filename (".modules.yaml") used by pnpm to specify configurations in the node_modules directory + */ + 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 + */ + public static readonly pnpmfileGlobalFilename: 'global-pnpmfile.cjs' = 'global-pnpmfile.cjs'; + + /** + * The folder name used to store patch files for pnpm + * Example: `C:\MyRepo\common\config\pnpm-patches` + * Example: `C:\MyRepo\common\temp\patches` + */ + public static readonly pnpmPatchesFolderName: 'patches' = 'patches'; + + /** + * The folder name under `/common/temp` used to store checked-in patches. + * Example: `C:\MyRepo\common\pnpm-patches` + */ + public static readonly pnpmPatchesCommonFolderName: `pnpm-patches` = `pnpm-${RushConstants.pnpmPatchesFolderName}`; + + /** + * The filename ("shrinkwrap.yaml") used to store state for pnpm + */ + public static readonly yarnShrinkwrapFilename: 'yarn.lock' = 'yarn.lock'; + + /** + * The folder name ("node_modules") where NPM installs its packages. + */ + public static readonly nodeModulesFolderName: 'node_modules' = 'node_modules'; + + /** + * The filename ("pinned-versions.json") for an old configuration file that + * that is no longer supported. + * + * @deprecated This feature has been superseded by the "preferredVersions" setting + * in common-versions.json + */ + // NOTE: Although this is marked as "deprecated", we will probably never retire it, + // since we always want to report the warning when someone upgrades an old repo. + public static readonly pinnedVersionsFilename: 'pinned-versions.json' = 'pinned-versions.json'; + + /** + * The filename ("common-versions.json") for an optional configuration file + * that stores dependency version information that affects all projects in the repo. + * This configuration file should go in the "common/config/rush" folder. + */ + public static readonly commonVersionsFilename: 'common-versions.json' = 'common-versions.json'; + + /** + * The filename ("repo-state.json") for a file used by Rush to + * store the state of various features as they stand in the repo. + */ + public static readonly repoStateFilename: 'repo-state.json' = 'repo-state.json'; + + /** + * The filename ("custom-tips.json") for the file used by Rush to + * print user-customized messages. + * This configuration file should go in the "common/config/rush" folder. + */ + public static readonly customTipsFilename: 'custom-tips.json' = 'custom-tips.json'; + + /** + * The name of the per-project folder where project-specific Rush files are stored. For example, + * the package-deps files, which are used by commands to determine if a particular project needs to be rebuilt. + */ + public static readonly projectRushFolderName: '.rush' = '.rush'; + + /** + * Custom command line configuration file, which is used by rush for implementing + * custom command and options. + */ + public static readonly commandLineFilename: 'command-line.json' = 'command-line.json'; + + public static readonly versionPoliciesFilename: 'version-policies.json' = 'version-policies.json'; + + /** + * Experiments configuration file. + */ + public static readonly experimentsFilename: 'experiments.json' = 'experiments.json'; + + /** + * Pnpm configuration file + */ + public static readonly pnpmConfigFilename: 'pnpm-config.json' = 'pnpm-config.json'; + + /** + * Rush plugins configuration file name. + */ + public static readonly rushPluginsConfigFilename: 'rush-plugins.json' = 'rush-plugins.json'; + + /** + * Rush plugin manifest file name. + */ + public static readonly rushPluginManifestFilename: 'rush-plugin-manifest.json' = + 'rush-plugin-manifest.json'; + + /** + * The artifactory.json configuration file name. + */ + public static readonly artifactoryFilename: 'artifactory.json' = 'artifactory.json'; + + /** + * The subspaces.json configuration file name + */ + public static readonly subspacesConfigFilename: 'subspaces.json' = 'subspaces.json'; + + /** + * The name of the default subspace if one isn't specified but subspaces is enabled. + */ + public static readonly defaultSubspaceName: 'default' = 'default'; + + /** + * Build cache configuration file. + */ + public static readonly buildCacheFilename: 'build-cache.json' = 'build-cache.json'; + + /** + * Build cache version number, incremented when the logic to create cache entries changes. + * Changing this ensures that cache entries generated by an old version will no longer register as a cache hit. + */ + public static readonly buildCacheVersion: 1 = 1; + + /** + * Cobuild configuration file. + */ + public static readonly cobuildFilename: 'cobuild.json' = 'cobuild.json'; + + /** + * Per-project configuration filename. + */ + public static readonly rushProjectConfigFilename: 'rush-project.json' = 'rush-project.json'; + + /** + * The URL ("http://rushjs.io") for the Rush web site. + */ + public static readonly rushWebSiteUrl: 'https://rushjs.io' = 'https://rushjs.io'; + + /** + * The name of the NPM package for the Rush tool ("\@microsoft/rush"). + */ + public static readonly rushPackageName: '@microsoft/rush' = '@microsoft/rush'; + + /** + * The folder name ("rush-recycler") where Rush moves large folder trees + * before asynchronously deleting them. + */ + public static readonly rushRecyclerFolderName: 'rush-recycler' = 'rush-recycler'; + + /** + * The name of the file to drop in project-folder/.rush/temp/ containing a listing of the project's direct + * and indirect dependencies. This is used to detect if a project's dependencies have changed since the last build. + */ + public static readonly projectShrinkwrapFilename: 'shrinkwrap-deps.json' = 'shrinkwrap-deps.json'; + + /** + * The value of the "commandKind" property for a bulk command in command-line.json + */ + public static readonly bulkCommandKind: 'bulk' = 'bulk'; + + /** + * The value of the "commandKind" property for a global command in command-line.json + */ + public static readonly globalCommandKind: 'global' = 'global'; + + /** + * The value of the "commandKind" property for a phased command in command-line.json + */ + public static readonly phasedCommandKind: 'phased' = 'phased'; + + /** + * The name of the incremental build command. + */ + public static readonly buildCommandName: 'build' = 'build'; + + /** + * The name of the non-incremental build command. + */ + public static readonly rebuildCommandName: 'rebuild' = 'rebuild'; + + public static readonly updateCloudCredentialsCommandName: 'update-cloud-credentials' = + 'update-cloud-credentials'; + + /** + * When a hash generated that contains multiple input segments, this character may be used + * to separate them to avoid issues like + * crypto.createHash('sha1').update('a').update('bc').digest('hex') === crypto.createHash('sha1').update('ab').update('c').digest('hex') + */ + public static readonly hashDelimiter: '|' = '|'; + + /** + * The name of the per-user Rush configuration data folder. + */ + public static readonly rushUserConfigurationFolderName: '.rush-user' = rushUserConfigurationFolderName; + + /** + * The name of the project `rush-logs` folder. + */ + public static readonly rushLogsFolderName: 'rush-logs' = 'rush-logs'; + + /** + * The expected prefix for phase names in "common/config/rush/command-line.json" + */ + public static readonly phaseNamePrefix: '_phase:' = '_phase:'; + + /** + * The default debounce value for Rush multi-project watch mode. When watching, controls + * how long to wait after the last encountered file system event before execution. If another + * file system event occurs in this interval, the timeout will reset. + */ + public static readonly defaultWatchDebounceMs: 1000 = 1000; + + /** + * The name of the parameter that can be used to bypass policies. + */ + public static readonly bypassPolicyFlagLongName: '--bypass-policy' = '--bypass-policy'; + + /** + * Merge Queue ignore configuration file. + */ + public static readonly mergeQueueIgnoreFileName: '.mergequeueignore' = '.mergequeueignore'; + + /** + * The filename ("project-impact-graph.yaml") for the project impact graph file. + */ + public static readonly projectImpactGraphFilename: 'project-impact-graph.yaml' = + 'project-impact-graph.yaml'; + + /** + * The filename for the last link flag + */ + public static readonly lastLinkFlagFilename: 'last-link' = 'last-link'; + + /** + * The filename for the Rush alerts config file. + */ + public static readonly rushAlertsConfigFilename: 'rush-alerts.json' = 'rush-alerts.json'; + + /** + * 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 rushHotlinkStateFilename: 'rush-hotlink-state.json' = 'rush-hotlink-state.json'; + + /** + * The filename ("pnpm-sync.json") used to store the state of the pnpm sync command. + */ + public static readonly pnpmSyncFilename: '.pnpm-sync.json' = '.pnpm-sync.json'; +} diff --git a/libraries/rush-lib/src/logic/Selection.ts b/libraries/rush-lib/src/logic/Selection.ts new file mode 100644 index 00000000000..8158fa0eba3 --- /dev/null +++ b/libraries/rush-lib/src/logic/Selection.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Minimal subset of RushConfigurationProject needed for graph manipulation. + * Used to facilitate type safety in unit tests. + * @internal + */ +export interface IPartialProject> { + dependencyProjects: ReadonlySet; + consumingProjects: ReadonlySet; +} + +/** + * This namespace contains functions for manipulating sets of projects + */ +export class Selection { + /** + * Computes the intersection of two or more sets. + */ + public static intersection(first: Iterable, ...rest: ReadonlySet[]): Set { + return new Set(generateIntersection(first, ...rest)); + } + + /** + * Computes the union of two or more sets. + */ + public static union(...sets: Iterable[]): Set { + return new Set(generateConcatenation(...sets)); + } + + /** + * Computes a set that contains the input projects and all the direct and indirect dependencies thereof. + */ + public static expandAllDependencies>(input: Iterable): Set { + return expandAll(input, expandDependenciesStep); + } + + /** + * Computes a set that contains the input projects and all projects that directly or indirectly depend on them. + */ + public static expandAllConsumers>(input: Iterable): Set { + return expandAll(input, expandConsumers); + } + + /** + * Iterates the direct dependencies of the listed projects. May contain duplicates. + */ + public static *directDependenciesOf>(input: Iterable): Iterable { + for (const item of input) { + yield* item.dependencyProjects; + } + } + + /** + * Iterates the projects that declare any of the listed projects as a dependency. May contain duplicates. + */ + public static *directConsumersOf>(input: Iterable): Iterable { + for (const item of input) { + yield* item.consumingProjects; + } + } +} + +/** + * Function used for incremental mutation of a set, e.g. when expanding dependencies or dependents + */ +interface IExpansionStepFunction { + (project: T, targetSet: Set): void; +} + +function* generateIntersection(first: Iterable, ...rest: ReadonlySet[]): Iterable { + for (const item of first) { + if (rest.every((set: ReadonlySet) => set.has(item))) { + yield item; + } + } +} + +function* generateConcatenation(...sets: Iterable[]): Iterable { + for (const set of sets) { + yield* set; + } +} + +/** + * Adds all dependencies of the specified project to the target set. + */ +function expandDependenciesStep>(project: T, targetSet: Set): void { + for (const dep of project.dependencyProjects) { + targetSet.add(dep); + } +} +/** + * Adds all projects that declare the specified project as a dependency to the target set. + */ +function expandConsumers>(project: T, targetSet: Set): void { + for (const dep of project.consumingProjects) { + targetSet.add(dep); + } +} + +/** + * Computes a set derived from the input by cloning it, then iterating over every member of the new set and + * calling a step function that may add more elements to the set. + */ +function expandAll(input: Iterable, expandStep: IExpansionStepFunction): Set { + const result: Set = new Set(input); + for (const item of result) { + expandStep(item, result); + } + return result; +} diff --git a/libraries/rush-lib/src/logic/SetupChecks.ts b/libraries/rush-lib/src/logic/SetupChecks.ts new file mode 100644 index 00000000000..3b6b9f1de1d --- /dev/null +++ b/libraries/rush-lib/src/logic/SetupChecks.ts @@ -0,0 +1,165 @@ +// 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 { FileSystem, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize, PrintUtilities } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import { RushConstants } from './RushConstants'; + +// Refuses to run at all if the PNPM version is older than this, because there +// are known bugs or missing features in earlier releases. +const MINIMUM_SUPPORTED_NPM_VERSION: string = '4.5.0'; + +// Refuses to run at all if the PNPM version is older than this, because there +// are known bugs or missing features in earlier releases. +const MINIMUM_SUPPORTED_PNPM_VERSION: string = '5.0.0'; + +/** + * Validate that the developer's setup is good. + * + * These checks are invoked prior to the following commands: + * - rush install + * - rush update + * - rush build + * - rush rebuild + */ +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); + + if (errorMessage) { + // eslint-disable-next-line no-console + console.error(Colorize.red(PrintUtilities.wrapWords(errorMessage))); + 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.` + ); + } + } + + 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:' + ) + ) + ); + } 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}"`)); + } + // 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); + } + } + + // 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 new file mode 100644 index 00000000000..1fdec16fab2 --- /dev/null +++ b/libraries/rush-lib/src/logic/ShrinkwrapFileFactory.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 { PackageManagerName } from '../api/packageManager/PackageManager'; +import type { BaseShrinkwrapFile } from './base/BaseShrinkwrapFile'; +import { NpmShrinkwrapFile } from './npm/NpmShrinkwrapFile'; +import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; +import { YarnShrinkwrapFile } from './yarn/YarnShrinkwrapFile'; + +export class ShrinkwrapFileFactory { + public static getShrinkwrapFile( + packageManager: PackageManagerName, + shrinkwrapFilename: string + ): BaseShrinkwrapFile | undefined { + switch (packageManager) { + case 'npm': + return NpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); + case 'pnpm': + return PnpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); + case 'yarn': + return YarnShrinkwrapFile.loadFromFile(shrinkwrapFilename); + default: + throw new Error(`Invalid package manager: ${packageManager}`); + } + } + + public static parseShrinkwrapFile( + packageManager: PackageManagerName, + shrinkwrapContent: string + ): BaseShrinkwrapFile | undefined { + switch (packageManager) { + case 'npm': + return NpmShrinkwrapFile.loadFromString(shrinkwrapContent); + case 'pnpm': + return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent); + case 'yarn': + return YarnShrinkwrapFile.loadFromString(shrinkwrapContent); + default: + throw new Error(`Invalid package manager: ${packageManager}`); + } + } +} diff --git a/libraries/rush-lib/src/logic/StandardScriptUpdater.ts b/libraries/rush-lib/src/logic/StandardScriptUpdater.ts new file mode 100644 index 00000000000..5a4fda349c7 --- /dev/null +++ b/libraries/rush-lib/src/logic/StandardScriptUpdater.ts @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, Async } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import { + installRunRushScriptFilename, + installRunRushxScriptFilename, + installRunRushPnpmScriptFilename, + installRunScriptFilename, + scriptsFolderPath +} from '../utilities/PathConstants'; +import { RushConstants } from './RushConstants'; + +const HEADER_LINES_PREFIX: string[] = [ + '// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.', + '//' +]; + +const HEADER_LINES_SUFFIX: string[] = [ + '//', + '// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/', + '//', + '// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', + "// See the @microsoft/rush package's LICENSE file for details.", + '' +]; + +interface IScriptSpecifier { + scriptName: string; + headerLines: string[]; +} + +const _scripts: IScriptSpecifier[] = [ + { + scriptName: installRunScriptFilename, + headerLines: [ + '// This script is intended for usage in an automated build environment where a Node tool may not have', + '// been preinstalled, or may have an unpredictable version. This script will automatically install the specified', + '// version of the specified tool (if not already installed), and then pass a command-line to it.', + '// An example usage would be:', + '//', + `// node common/scripts/${installRunScriptFilename} qrcode@1.2.2 qrcode https://rushjs.io` + ] + }, + { + scriptName: installRunRushScriptFilename, + headerLines: [ + '// This script is intended for usage in an automated build environment where the Rush command may not have', + '// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush', + `// specified in the ${RushConstants.rushJsonFilename} configuration file (if not already installed), and then pass a command-line to it.`, + '// An example usage would be:', + '//', + `// node common/scripts/${installRunRushScriptFilename} install` + ] + }, + { + scriptName: installRunRushxScriptFilename, + headerLines: [ + '// This script is intended for usage in an automated build environment where the Rush command may not have', + '// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush', + `// specified in the ${RushConstants.rushJsonFilename} configuration file (if not already installed), and then pass a command-line to the`, + '// rushx command.', + '//', + '// An example usage would be:', + '//', + `// node common/scripts/${installRunRushxScriptFilename} custom-command` + ] + } +]; + +const _pnpmOnlyScripts: IScriptSpecifier[] = [ + { + scriptName: installRunRushPnpmScriptFilename, + headerLines: [ + '// This script is intended for usage in an automated build environment where the Rush command may not have', + '// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush', + `// specified in the ${RushConstants.rushJsonFilename} configuration file (if not already installed), and then pass a command-line to the`, + '// rush-pnpm command.', + '//', + '// An example usage would be:', + '//', + `// node common/scripts/${installRunRushPnpmScriptFilename} pnpm-command` + ] + } +]; + +const getScripts = (rushConfiguration: RushConfiguration): IScriptSpecifier[] => { + if (rushConfiguration.isPnpm) { + return _scripts.concat(_pnpmOnlyScripts); + } + + return _scripts; +}; + +/** + * Checks whether the common/scripts files are up to date, and recopies them if needed. + * This is used by the "rush install" and "rush update" commands. + */ +export class StandardScriptUpdater { + /** + * Recopy the scripts if the scripts are out of date. + * Used by "rush update". + */ + public static async updateAsync(rushConfiguration: RushConfiguration): Promise { + await FileSystem.ensureFolderAsync(rushConfiguration.commonScriptsFolder); + + let anyChanges: boolean = false; + await Async.forEachAsync( + getScripts(rushConfiguration), + async (script: IScriptSpecifier) => { + const changed: boolean = await StandardScriptUpdater._updateScriptOrThrowAsync( + script, + rushConfiguration, + false + ); + anyChanges ||= changed; + }, + { concurrency: 10 } + ); + + if (anyChanges) { + // eslint-disable-next-line no-console + console.log(); // print a newline after the notices + } + + return anyChanges; + } + + /** + * Throw an exception if the scripts are out of date. + * Used by "rush install". + */ + public static async validateAsync(rushConfiguration: RushConfiguration): Promise { + await Async.forEachAsync( + getScripts(rushConfiguration), + async (script: IScriptSpecifier) => { + await StandardScriptUpdater._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; + } + } + + 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); + } + } + + 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') + ); + } + + 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; + } +} diff --git a/libraries/rush-lib/src/logic/Telemetry.ts b/libraries/rush-lib/src/logic/Telemetry.ts new file mode 100644 index 00000000000..8d855cd46a0 --- /dev/null +++ b/libraries/rush-lib/src/logic/Telemetry.ts @@ -0,0 +1,270 @@ +// 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 { 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 + */ +export interface ITelemetryMachineInfo { + /** + * The CPU architecture + * @example `"AMD64"` + */ + machineArchitecture: string; + + /** + * The CPU model + * * @example `"AMD Ryzen 7 3700X 8-Core Processor"` + */ + machineCpu: string; + + /** + * The number of logical CPU cores. + */ + machineCores: number; + + /** + * The total amount of RAM on the machine, in MiB. + */ + machineTotalMemoryMiB: number; + + /** + * The amount of free RAM on the machine at the end of execution, in MiB. + */ + machineFreeMemoryMiB: number; +} + +/** + * @beta + */ +export interface ITelemetryOperationResult { + /** + * The names of operations that this operation depends on. + */ + dependencies: string[]; + + /** + * The status code for the operation. + */ + result: string; + + /** + * A timestamp in milliseconds (from `performance.now()`) when the operation started. + * If the operation was blocked, will be `undefined`. + */ + startTimestampMs?: number; + + /** + * A timestamp in milliseconds (from `performance.now()`) when the operation finished. + * If the operation was blocked, will be `undefined`. + */ + endTimestampMs?: number; + + /** + * Duration in milliseconds when the operation does not hit cache + */ + nonCachedDurationMs?: number; + + /** + * Was this operation built on this machine? If so, the duration can be calculated from `startTimestampMs` and `endTimestampMs`. + * If not, you should use the metrics from the machine that built it. + */ + wasExecutedOnThisMachine?: boolean; +} + +/** + * @beta + */ +export interface ITelemetryData { + /** + * Command name + * @example `"build"` + */ + readonly name: string; + + /** + * Duration in seconds + */ + readonly durationInSeconds: number; + + /** + * The result of the command + */ + readonly result: 'Succeeded' | 'Failed'; + + /** + * The millisecond-resolution timestamp of the telemetry logging + * @example 1648001893024 + */ + readonly timestampMs?: number; + + /** + * The platform the command was executed on, based on the Node.js `process.platform()` API + * @example `"darwin"`, `"win32"`, `"linux"` + */ + readonly platform?: string; + + /** + * The Rush version + * @example `5.63.0` + */ + readonly rushVersion?: string; + + /** + * Detailed information about the host machine. + */ + readonly machineInfo?: ITelemetryMachineInfo; + + /** + * Only applicable to phased commands. Provides detailed results by operation. + * Keys are operation names, values contain result, timing information, and dependencies. + */ + 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; +const ONE_MEGABYTE_IN_BYTES: 1048576 = 1048576; + +export class Telemetry { + private _enabled: boolean; + private _store: ITelemetryData[]; + private _dataFolder: string; + private _rushConfiguration: RushConfiguration; + private _rushSession: RushSession; + private _flushAsyncTasks: Set> = new Set(); + private _telemetryStartTime: number = 0; + + public constructor(rushConfiguration: RushConfiguration, rushSession: RushSession) { + this._rushConfiguration = rushConfiguration; + this._rushSession = rushSession; + this._enabled = this._rushConfiguration.telemetryEnabled; + this._store = []; + + const folderName: string = 'telemetry'; + this._dataFolder = path.join(this._rushConfiguration.commonTempFolder, folderName); + } + + public log(telemetryData: ITelemetryData): void { + 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: 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) + }, + timestampMs: telemetryData.timestampMs || new Date().getTime(), + platform: telemetryData.platform || process.platform, + rushVersion: telemetryData.rushVersion || Rush.version + }; + this._telemetryStartTime = performance.now(); + this._store.push(data); + } + + public flush(): void { + if (!this._enabled || this._store.length === 0) { + return; + } + + const fullPath: string = this._getFilePath(); + JsonFile.save(this._store, fullPath, { ensureFolderExists: true, ignoreUndefinedValues: true }); + if (this._rushSession.hooks.flushTelemetry.isUsed()) { + /** + * User defined flushTelemetry should not block anything, so we don't await here, + * and store the promise into a list so that we can await it later. + */ + const asyncTaskPromise: Promise = this._rushSession.hooks.flushTelemetry.promise(this._store); + this._flushAsyncTasks.add(asyncTaskPromise); + asyncTaskPromise.then( + () => { + this._flushAsyncTasks.delete(asyncTaskPromise); + }, + () => { + this._flushAsyncTasks.delete(asyncTaskPromise); + } + ); + } + + this._store = []; + this._cleanUp(); + } + + /** + * There are some async tasks that are not finished when the process is exiting. + */ + public async ensureFlushedAsync(): Promise { + await Promise.all(this._flushAsyncTasks); + } + + public get store(): ITelemetryData[] { + return this._store; + } + + /** + * When there are too many log files, delete the old ones. + */ + private _cleanUp(): void { + if (FileSystem.exists(this._dataFolder)) { + const files: string[] = FileSystem.readFolderItemNames(this._dataFolder); + if (files.length > MAX_FILE_COUNT) { + const sortedFiles: string[] = files + .map((fileName) => { + const filePath: string = path.join(this._dataFolder, fileName); + const stats: FileSystemStats = FileSystem.getStatistics(filePath); + return { + filePath: filePath, + modifiedTime: stats.mtime.getTime(), + isFile: stats.isFile() + }; + }) + .filter((value) => { + // Only delete files + return value.isFile; + }) + .sort((a, b) => { + return a.modifiedTime - b.modifiedTime; + }) + .map((s) => { + return s.filePath; + }); + const filesToDelete: number = sortedFiles.length - MAX_FILE_COUNT; + for (let i: number = 0; i < filesToDelete; i++) { + FileSystem.deleteFile(sortedFiles[i]); + } + } + } + } + + private _getFilePath(): string { + let fileName: string = `telemetry_${new Date().toISOString()}`; + fileName = fileName.replace(/[\-\:\.]/g, '_') + '.json'; + return path.join(this._dataFolder, fileName); + } +} diff --git a/libraries/rush-lib/src/logic/TempProjectHelper.ts b/libraries/rush-lib/src/logic/TempProjectHelper.ts new file mode 100644 index 00000000000..8cd0bcc94e2 --- /dev/null +++ b/libraries/rush-lib/src/logic/TempProjectHelper.ts @@ -0,0 +1,83 @@ +// 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 tar from 'tar'; + +import { FileConstants, FileSystem, PosixModeBits } from '@rushstack/node-core-library'; + +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { RushConstants } from './RushConstants'; +import type { Subspace } from '../api/Subspace'; + +// The PosixModeBits are intended to be used with bitwise operations. +/* eslint-disable no-bitwise */ + +export class TempProjectHelper { + private _rushConfiguration: RushConfiguration; + private _subspace: Subspace; + + public constructor(rushConfiguration: RushConfiguration, subspace: Subspace) { + this._rushConfiguration = rushConfiguration; + this._subspace = subspace; + } + + /** + * Deletes the existing tarball and creates a tarball for the given rush project + */ + public createTempProjectTarball(rushProject: RushConfigurationProject): void { + FileSystem.ensureFolder(path.resolve(this._subspace.getSubspaceTempFolderPath(), 'projects')); + const tarballFile: string = this.getTarballFilePath(rushProject); + const tempProjectFolder: string = this.getTempProjectFolder(rushProject); + + FileSystem.deleteFile(tarballFile); + + // NPM expects the root of the tarball to have a directory called 'package' + const npmPackageFolder: string = 'package'; + + const tarOptions: tar.CreateOptions = { + gzip: true, + file: tarballFile, + cwd: tempProjectFolder, + portable: true, + noMtime: true, + noPax: true, + sync: true, + prefix: npmPackageFolder, + filter: (tarPath: string, stat: tar.FileStat): boolean => { + if ( + !this._rushConfiguration.experimentsConfiguration.configuration.noChmodFieldInTarHeaderNormalization + ) { + stat.mode = + (stat.mode & ~0x1ff) | PosixModeBits.AllRead | PosixModeBits.UserWrite | PosixModeBits.AllExecute; + } + return true; + } + } as tar.CreateOptions; + // create the new tarball + tar.create(tarOptions, [FileConstants.PackageJson]); + } + + /** + * Gets the path to the tarball + * Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" + */ + public getTarballFilePath(project: RushConfigurationProject): string { + return path.join( + this._subspace.getSubspaceTempFolderPath(), + RushConstants.rushTempProjectsFolderName, + `${project.unscopedTempProjectName}.tgz` + ); + } + + public getTempProjectFolder(rushProject: RushConfigurationProject): string { + const unscopedTempProjectName: string = rushProject.unscopedTempProjectName; + return path.join( + this._subspace.getSubspaceTempFolderPath(), + RushConstants.rushTempProjectsFolderName, + unscopedTempProjectName + ); + } +} diff --git a/libraries/rush-lib/src/logic/UnlinkManager.ts b/libraries/rush-lib/src/logic/UnlinkManager.ts new file mode 100644 index 00000000000..d77a73b97b4 --- /dev/null +++ b/libraries/rush-lib/src/logic/UnlinkManager.ts @@ -0,0 +1,83 @@ +// 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, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import { Utilities } from '../utilities/Utilities'; +import { BaseProjectShrinkwrapFile } from './base/BaseProjectShrinkwrapFile'; +import { FlagFile } from '../api/FlagFile'; +import { RushConstants } from './RushConstants'; + +/** + * This class implements the logic for "rush unlink" + */ +export class UnlinkManager { + private _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + /** + * Delete flag file and all the existing node_modules symlinks and all + * project/.rush/temp/shrinkwrap-deps.json files + * + * Returns true if anything was deleted. + */ + public async unlinkAsync(force: boolean = false): Promise { + const useWorkspaces: boolean = + this._rushConfiguration.pnpmOptions && this._rushConfiguration.pnpmOptions.useWorkspaces; + if (!force && useWorkspaces) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'Unlinking is not supported when using workspaces. Run "rush purge" to remove ' + + 'project node_modules folders.' + ) + ); + throw new AlreadyReportedError(); + } + + await new FlagFile( + this._rushConfiguration.defaultSubspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ).clearAsync(); + return this._deleteProjectFiles(); + } + + /** + * Delete: + * - all the node_modules symlinks of configured Rush projects + * - all of the project/.rush/temp/shrinkwrap-deps.json files of configured Rush projects + * + * Returns true if anything was deleted + * */ + private _deleteProjectFiles(): boolean { + let didDeleteAnything: boolean = false; + + for (const rushProject of this._rushConfiguration.projects) { + const localModuleFolder: string = path.join(rushProject.projectFolder, 'node_modules'); + if (FileSystem.exists(localModuleFolder)) { + // eslint-disable-next-line no-console + console.log(`Purging ${localModuleFolder}`); + Utilities.dangerouslyDeletePath(localModuleFolder); + didDeleteAnything = true; + } + + const projectShrinkwrapFilePath: string = BaseProjectShrinkwrapFile.getFilePathForProject(rushProject); + if (FileSystem.exists(projectShrinkwrapFilePath)) { + // eslint-disable-next-line no-console + console.log(`Deleting ${projectShrinkwrapFilePath}`); + FileSystem.deleteFile(projectShrinkwrapFilePath); + didDeleteAnything = true; + } + } + + return didDeleteAnything; + } +} diff --git a/libraries/rush-lib/src/logic/VersionManager.ts b/libraries/rush-lib/src/logic/VersionManager.ts new file mode 100644 index 00000000000..7a2f57840e9 --- /dev/null +++ b/libraries/rush-lib/src/logic/VersionManager.ts @@ -0,0 +1,412 @@ +// 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 { type IPackageJson, JsonFile, FileConstants } from '@rushstack/node-core-library'; + +import { type VersionPolicy, type BumpType, LockStepVersionPolicy } from '../api/VersionPolicy'; +import { ChangeFile } from '../api/ChangeFile'; +import { ChangeType, type IChangeInfo } from '../api/ChangeManagement'; +import { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { VersionPolicyConfiguration } from '../api/VersionPolicyConfiguration'; +import { PublishUtilities } from './PublishUtilities'; +import { ChangeManager } from './ChangeManager'; +import { DependencySpecifier } from './DependencySpecifier'; +import { cloneDeep } from '../utilities/objectUtilities'; + +export class VersionManager { + private _rushConfiguration: RushConfiguration; + private _userEmail: string; + private _versionPolicyConfiguration: VersionPolicyConfiguration; + + public readonly updatedProjects: Map; + public readonly changeFiles: Map; + + public constructor( + rushConfiguration: RushConfiguration, + userEmail: string, + versionPolicyConfiguration: VersionPolicyConfiguration + ) { + this._rushConfiguration = rushConfiguration; + this._userEmail = userEmail; + this._versionPolicyConfiguration = versionPolicyConfiguration + ? versionPolicyConfiguration + : this._rushConfiguration.versionPolicyConfiguration; + + this.updatedProjects = new Map(); + this.changeFiles = new Map(); + } + + /** + * Ensures project versions follow the provided version policy. If version policy is not + * provided, all projects will have their version checked according to the associated version policy. + * package.json files will be updated if needed. + * This method does not commit changes. + * @param versionPolicyName -- version policy name + * @param shouldCommit -- should update files to disk + * @param force -- update even when project version is higher than policy version. + */ + public ensure(versionPolicyName?: string, shouldCommit?: boolean, force?: boolean): void { + this._ensure(versionPolicyName, shouldCommit, force); + } + + /** + * Bumps versions following version policies. + * + * @param lockStepVersionPolicyName - a specified lock step version policy name. Without this value, + * versions for all lock step policies and all individual policies will be bumped. + * With this value, only the specified lock step policy will be bumped along with all individual policies. + * @param bumpType - overrides the default bump type and only works for lock step policy + * @param identifier - overrides the prerelease identifier and only works for lock step policy + * @param shouldCommit - whether the changes will be written to disk + */ + public async bumpAsync( + lockStepVersionPolicyName?: string, + bumpType?: BumpType, + identifier?: string, + shouldCommit?: boolean + ): Promise { + // Bump all the lock step version policies. + this._versionPolicyConfiguration.bump(lockStepVersionPolicyName, bumpType, identifier, shouldCommit); + + // Update packages and generate change files due to lock step bump. + this._ensure(lockStepVersionPolicyName, shouldCommit); + + // Refresh rush configuration since we may have modified the package.json versions + // when calling this._ensure(...) + this._rushConfiguration = RushConfiguration.loadFromConfigurationFile( + this._rushConfiguration.rushJsonFile + ); + + // Update projects based on individual policies + const changeManager: ChangeManager = new ChangeManager( + this._rushConfiguration, + this._getManuallyVersionedProjects() + ); + + await changeManager.loadAsync(this._rushConfiguration.changesFolder); + if (changeManager.hasChanges()) { + changeManager.validateChanges(this._versionPolicyConfiguration); + changeManager.apply(!!shouldCommit)!.forEach((packageJson) => { + this.updatedProjects.set(packageJson.name, packageJson); + }); + await changeManager.updateChangelogAsync(!!shouldCommit); + } + + // Refresh rush configuration again, since we've further modified the package.json files + // by calling changeManager.apply(...) + this._rushConfiguration = RushConfiguration.loadFromConfigurationFile( + this._rushConfiguration.rushJsonFile + ); + } + + private _ensure(versionPolicyName?: string, shouldCommit?: boolean, force?: boolean): void { + this._updateVersionsByPolicy(versionPolicyName, force); + + let changed: boolean = false; + do { + changed = false; + // Update all dependencies if needed. + const dependenciesUpdated: boolean = this._updateDependencies(); + changed = changed || dependenciesUpdated; + } while (changed); + + if (shouldCommit) { + this._updatePackageJsonFiles(); + this.changeFiles.forEach((changeFile) => { + changeFile.writeSync(); + }); + } + } + + private _getManuallyVersionedProjects(): Set | undefined { + const lockStepVersionPolicyNames: Set = new Set(); + + this._versionPolicyConfiguration.versionPolicies.forEach((versionPolicy) => { + if (versionPolicy instanceof LockStepVersionPolicy && versionPolicy.nextBump !== undefined) { + lockStepVersionPolicyNames.add(versionPolicy.policyName); + } + }); + const lockStepProjectNames: Set = new Set(); + this._rushConfiguration.projects.forEach((rushProject) => { + if (lockStepVersionPolicyNames.has(rushProject.versionPolicyName!)) { + lockStepProjectNames.add(rushProject.packageName); + } + }); + return lockStepProjectNames; + } + + private _updateVersionsByPolicy(versionPolicyName?: string, force?: boolean): boolean { + let changed: boolean = false; + + // Update versions based on version policy + this._rushConfiguration.projects.forEach((rushProject) => { + const projectVersionPolicyName: string | undefined = rushProject.versionPolicyName; + if ( + projectVersionPolicyName && + (!versionPolicyName || projectVersionPolicyName === versionPolicyName) + ) { + const versionPolicy: VersionPolicy = + this._versionPolicyConfiguration.getVersionPolicy(projectVersionPolicyName); + + const oldVersion: string = + this.updatedProjects.get(rushProject.packageName)?.version || rushProject.packageJson.version; + const updatedProject: IPackageJson | undefined = versionPolicy.ensure(rushProject.packageJson, force); + changed = changed || updatedProject?.version !== oldVersion; + + if (updatedProject) { + this.updatedProjects.set(updatedProject.name, updatedProject); + // No need to create an entry for prerelease version bump. + if (!this._isPrerelease(updatedProject.version) && rushProject.isMainProject) { + this._addChangeInfo(updatedProject.name, [this._createChangeInfo(updatedProject, rushProject)]); + } + } + } + }); + + return changed; + } + + private _isPrerelease(version: string): boolean { + return !!semver.prerelease(version); + } + + private _addChangeInfo(packageName: string, changeInfos: IChangeInfo[]): void { + if (!changeInfos.length) { + return; + } + let changeFile: ChangeFile | undefined = this.changeFiles.get(packageName); + if (!changeFile) { + changeFile = new ChangeFile( + { + changes: [], + packageName: packageName, + email: this._userEmail + }, + this._rushConfiguration + ); + this.changeFiles.set(packageName, changeFile); + } + changeInfos.forEach((changeInfo) => { + changeFile!.addChange(changeInfo); + }); + } + + private _updateDependencies(): boolean { + let updated: boolean = false; + + this._rushConfiguration.projects.forEach((rushProject) => { + let clonedProject: IPackageJson | undefined = this.updatedProjects.get(rushProject.packageName); + let projectVersionChanged: boolean = true; + + if (!clonedProject) { + clonedProject = cloneDeep(rushProject.packageJson); + projectVersionChanged = false; + } + + const dependenciesUpdated: boolean = this._updateProjectAllDependencies( + rushProject, + clonedProject!, + projectVersionChanged + ); + + updated = updated || dependenciesUpdated; + }); + + return updated; + } + + private _updateProjectAllDependencies( + rushProject: RushConfigurationProject, + clonedProject: IPackageJson, + projectVersionChanged: boolean + ): boolean { + if (!clonedProject.dependencies && !clonedProject.devDependencies) { + return false; + } + const changes: IChangeInfo[] = []; + let updated: boolean = false; + if ( + this._updateProjectDependencies( + clonedProject.dependencies, + changes, + clonedProject, + rushProject, + projectVersionChanged + ) + ) { + updated = true; + } + if ( + this._updateProjectDependencies( + clonedProject.devDependencies, + changes, + clonedProject, + rushProject, + projectVersionChanged + ) + ) { + updated = true; + } + if ( + this._updateProjectDependencies( + clonedProject.peerDependencies, + changes, + clonedProject, + rushProject, + projectVersionChanged + ) + ) { + updated = true; + } + + if (updated) { + this.updatedProjects.set(clonedProject.name, clonedProject); + this._addChangeInfo(clonedProject.name, changes); + } + + return updated; + } + + private _updateProjectDependencies( + dependencies: { [key: string]: string } | undefined, + changes: IChangeInfo[], + clonedProject: IPackageJson, + rushProject: RushConfigurationProject, + projectVersionChanged: boolean + ): boolean { + if (!dependencies) { + return false; + } + let updated: boolean = false; + this.updatedProjects.forEach((updatedDependentProject, updatedDependentProjectName) => { + if (dependencies[updatedDependentProjectName]) { + if (rushProject.decoupledLocalDependencies.has(updatedDependentProjectName)) { + // Skip if cyclic + // eslint-disable-next-line no-console + console.log(`Found cyclic ${rushProject.packageName} ${updatedDependentProjectName}`); + return; + } + + const oldDependencyVersion: string = dependencies[updatedDependentProjectName]; + const newDependencyVersion: string = PublishUtilities.getNewDependencyVersion( + dependencies, + updatedDependentProjectName, + updatedDependentProject.version + ); + + if (newDependencyVersion !== oldDependencyVersion) { + updated = true; + if (this._shouldTrackDependencyChange(rushProject, updatedDependentProjectName)) { + this._trackDependencyChange( + changes, + clonedProject, + projectVersionChanged, + updatedDependentProject, + oldDependencyVersion, + newDependencyVersion + ); + } + dependencies[updatedDependentProjectName] = newDependencyVersion; + } + } + }); + return updated; + } + + private _shouldTrackDependencyChange( + rushProject: RushConfigurationProject, + dependencyName: string + ): boolean { + const dependencyRushProject: RushConfigurationProject | undefined = + this._rushConfiguration.projectsByName.get(dependencyName); + + return ( + !!dependencyRushProject && + rushProject.shouldPublish && + (!rushProject.versionPolicy || + !rushProject.versionPolicy.isLockstepped || + (rushProject.isMainProject && + dependencyRushProject.versionPolicyName !== rushProject.versionPolicyName)) + ); + } + + private _trackDependencyChange( + changes: IChangeInfo[], + clonedProject: IPackageJson, + projectVersionChanged: boolean, + updatedDependentProject: IPackageJson, + oldDependencyVersion: string, + newDependencyVersion: string + ): void { + const oldSpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + updatedDependentProject.name, + oldDependencyVersion + ); + if ( + !semver.satisfies(updatedDependentProject.version, oldSpecifier.versionSpecifier) && + !projectVersionChanged + ) { + this._addChange(changes, { + changeType: ChangeType.patch, + packageName: clonedProject.name + }); + } + + // If current version is not a prerelease version and new dependency is also not a prerelease version, + // add change entry. Otherwise, too many changes will be created for frequent releases. + if (!this._isPrerelease(updatedDependentProject.version) && !this._isPrerelease(clonedProject.version)) { + this._addChange(changes, { + changeType: ChangeType.dependency, + comment: + `Dependency ${updatedDependentProject.name} version bump from ${oldDependencyVersion}` + + ` to ${newDependencyVersion}.`, + packageName: clonedProject.name + }); + } + } + + private _addChange(changes: IChangeInfo[], newChange: IChangeInfo): void { + const exists: boolean = changes.some((changeInfo) => { + return ( + changeInfo.author === newChange.author && + changeInfo.changeType === newChange.changeType && + changeInfo.comment === newChange.comment && + changeInfo.commit === newChange.commit && + changeInfo.packageName === newChange.packageName && + changeInfo.type === newChange.type + ); + }); + if (!exists) { + changes.push(newChange); + } + } + + private _updatePackageJsonFiles(): void { + this.updatedProjects.forEach((newPackageJson, packageName) => { + const rushProject: RushConfigurationProject | undefined = + this._rushConfiguration.getProjectByName(packageName); + // Update package.json + if (rushProject) { + const packagePath: string = path.join(rushProject.projectFolder, FileConstants.PackageJson); + JsonFile.save(newPackageJson, packagePath, { updateExistingFile: true }); + } + }); + } + + private _createChangeInfo( + newPackageJson: IPackageJson, + rushProject: RushConfigurationProject + ): IChangeInfo { + return { + changeType: ChangeType.none, + newVersion: newPackageJson.version, + packageName: newPackageJson.name, + comment: '' + }; + } +} diff --git a/libraries/rush-lib/src/logic/base/BaseInstallManager.ts b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts new file mode 100644 index 00000000000..a38af503f97 --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts @@ -0,0 +1,1186 @@ +// 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 * 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 ILockfilePackage, + type ILogMessageCallbackOptions, + pnpmSyncGetJsonVersion, + pnpmSyncPrepareAsync +} from 'pnpm-sync-lib'; + +import { + FileSystem, + JsonFile, + PosixModeBits, + NewlineKind, + AlreadyReportedError, + type FileSystemStats, + Path, + type FolderItem, + Async +} from '@rushstack/node-core-library'; +import { PrintUtilities, Colorize, type ITerminal } from '@rushstack/terminal'; + +import { ApprovedPackagesChecker } from '../ApprovedPackagesChecker'; +import type { AsyncRecycler } from '../../utilities/AsyncRecycler'; +import type { BaseShrinkwrapFile } from './BaseShrinkwrapFile'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import { Git } from '../Git'; +import { + type LastInstallFlag, + getCommonTempFlag, + type ILastInstallFlagJson +} from '../../api/LastInstallFlag'; +import type { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager'; +import type { PurgeManager } from '../PurgeManager'; +import type { ICurrentVariantJson, RushConfiguration } from '../../api/RushConfiguration'; +import { Rush } from '../../api/Rush'; +import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import { RushConstants } from '../RushConstants'; +import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; +import { Utilities } from '../../utilities/Utilities'; +import { InstallHelpers } from '../installManager/InstallHelpers'; +import * as PolicyValidator from '../policy/PolicyValidator'; +import type { WebClient as WebClientType, IWebClientResponse } from '../../utilities/WebClient'; +import { SetupPackageRegistry } from '../setup/SetupPackageRegistry'; +import { PnpmfileConfiguration } from '../pnpm/PnpmfileConfiguration'; +import type { IInstallManagerOptions } from './BaseInstallManagerTypes'; +import { isVariableSetInNpmrcFile } from '../../utilities/npmrcUtilities'; +import type { PnpmResolutionMode } from '../pnpm/PnpmOptionsConfiguration'; +import { SubspacePnpmfileConfiguration } from '../pnpm/SubspacePnpmfileConfiguration'; +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'; + +/** + * Pnpm don't support --ignore-compatibility-db, so use --config.ignoreCompatibilityDb for now. + */ +export const pnpmIgnoreCompatibilityDbParameter: string = '--config.ignoreCompatibilityDb'; +const pnpmCacheDirParameter: string = '--config.cacheDir'; +const pnpmStateDirParameter: string = '--config.stateDir'; + +const gitLfsHooks: ReadonlySet = new Set(['post-checkout', 'post-commit', 'post-merge', 'pre-push']); + +/** + * This class implements common logic between "rush install" and "rush update". + */ +export abstract class BaseInstallManager { + private readonly _commonTempLinkFlag: FlagFile; + private _npmSetupValidated: boolean = false; + private _syncNpmrcAlreadyCalled: boolean = false; + + protected readonly _terminal: ITerminal; + + protected readonly rushConfiguration: RushConfiguration; + protected readonly rushGlobalFolder: RushGlobalFolder; + protected readonly installRecycler: AsyncRecycler; + protected readonly options: IInstallManagerOptions; + // Mapping of subspaceName -> LastInstallFlag + protected readonly subspaceInstallFlags: Map; + + public constructor( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ) { + this._terminal = options.terminal; + this.rushConfiguration = rushConfiguration; + this.rushGlobalFolder = rushGlobalFolder; + this.installRecycler = purgeManager.commonTempFolderRecycler; + this.options = options; + + this._commonTempLinkFlag = new FlagFile( + options.subspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ); + + this.subspaceInstallFlags = new Map(); + if (rushConfiguration.subspacesFeatureEnabled) { + for (const subspace of rushConfiguration.subspaces) { + this.subspaceInstallFlags.set(subspace.subspaceName, getCommonTempFlag(rushConfiguration, subspace)); + } + } + } + + public async doInstallAsync(): Promise { + const { allowShrinkwrapUpdates, selectedProjects, pnpmFilterArgumentValues, resolutionOnly, variant } = + this.options; + const isFilteredInstall: boolean = pnpmFilterArgumentValues.length > 0; + const useWorkspaces: boolean = + this.rushConfiguration.pnpmOptions && this.rushConfiguration.pnpmOptions.useWorkspaces; + // Prevent filtered installs when workspaces is disabled + if (isFilteredInstall && !useWorkspaces) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'Project filtering arguments can only be used when running in a workspace environment. Run the ' + + 'command again without specifying these arguments.' + ) + ); + throw new AlreadyReportedError(); + } + + // Prevent update when using a filter, as modifications to the shrinkwrap shouldn't be saved + if (allowShrinkwrapUpdates && isFilteredInstall) { + // Allow partial update when there are subspace projects + if (!this.rushConfiguration.subspacesFeatureEnabled) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'Project filtering arguments cannot be used when running "rush update". Run the command again ' + + 'without specifying these arguments.' + ) + ); + throw new AlreadyReportedError(); + } + } + + const subspace: Subspace = this.options.subspace; + + const projectImpactGraphGenerator: ProjectImpactGraphGenerator | undefined = this.rushConfiguration + .experimentsConfiguration.configuration.generateProjectImpactGraphDuringRushUpdate + ? new ProjectImpactGraphGenerator(this._terminal, this.rushConfiguration) + : undefined; + const { shrinkwrapIsUpToDate, npmrcHash, projectImpactGraphIsUpToDate, variantIsUpToDate } = + await this.prepareAsync(subspace, variant, projectImpactGraphGenerator); + + if (this.options.checkOnly) { + return; + } + + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold(`Checking installation in "${subspace.getSubspaceTempFolderPath()}"`)); + + // This marker file indicates that the last "rush install" completed successfully. + // Always perform a clean install if filter flags were provided. Additionally, if + // "--purge" was specified, or if the last install was interrupted, then we will + // need to perform a clean install. Otherwise, we can do an incremental install. + const commonTempInstallFlag: LastInstallFlag = getCommonTempFlag(this.rushConfiguration, subspace, { + npmrcHash: npmrcHash || '' + }); + if (isFilteredInstall && selectedProjects) { + const selectedProjectNames: string[] = []; + for (const { packageName } of selectedProjects) { + selectedProjectNames.push(packageName); + } + + selectedProjectNames.sort(); + // Get the projects involved in this filtered install + commonTempInstallFlag.mergeFromObject({ + selectedProjectNames + }); + } + const optionsToIgnore: (keyof ILastInstallFlagJson)[] | undefined = !this.rushConfiguration + .experimentsConfiguration.configuration.cleanInstallAfterNpmrcChanges + ? ['npmrcHash'] // If the "cleanInstallAfterNpmrcChanges" experiment is disabled, ignore the npmrcHash + : undefined; + const cleanInstall: boolean = !(await commonTempInstallFlag.checkValidAndReportStoreIssuesAsync({ + rushVerb: allowShrinkwrapUpdates ? 'update' : 'install', + 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? + const outputStats: FileSystemStats = await FileSystem.getStatisticsAsync(commonTempInstallFlag.path); + return this.canSkipInstallAsync(outputStats.mtime, subspace, variant); + }; + + if ( + resolutionOnly || + cleanInstall || + wasNodeModulesModifiedOutsideInstallation || + !variantIsUpToDate || + !shrinkwrapIsUpToDate || + !(await canSkipInstallAsync()) || + !projectImpactGraphIsUpToDate + ) { + // eslint-disable-next-line no-console + console.log(); + await this.validateNpmSetupAsync(); + + if (!this.rushConfiguration.rushConfigurationJson.suppressRushIsPublicVersionCheck) { + let publishedRelease: boolean | undefined; + try { + publishedRelease = await this._checkIfReleaseIsPublishedAsync(); + } catch { + // If the user is working in an environment that can't reach the registry, + // don't bother them with errors. + } + + if (publishedRelease === false) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow('Warning: This release of the Rush tool was unpublished; it may be unstable.') + ); + } + } + + if (!resolutionOnly) { + // Delete the successful install file to indicate the install transaction has started + await commonTempInstallFlag.clearAsync(); + + // Since we're going to be tampering with common/node_modules, delete the "rush link" flag file if it exists; + // this ensures that a full "rush link" is required next time + await this._commonTempLinkFlag.clearAsync(); + } + + // Give plugins an opportunity to act before invoking the installation process + if (this.options.beforeInstallAsync !== undefined) { + await this.options.beforeInstallAsync(subspace); + } + + await Promise.all([ + // Perform the actual install + this.installAsync(cleanInstall, subspace), + // If allowed, generate the project impact graph + allowShrinkwrapUpdates ? projectImpactGraphGenerator?.generateAsync() : undefined + ]); + + if (this.options.allowShrinkwrapUpdates && !shrinkwrapIsUpToDate) { + const committedShrinkwrapFileName: string = subspace.getCommittedShrinkwrapFilePath(variant); + const shrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( + this.rushConfiguration.packageManager, + committedShrinkwrapFileName + ); + 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); + } else { + // TODO: Validate whether the package manager updated it in a nontrivial way + } + + // Always update the state file if running "rush update" + if (this.options.allowShrinkwrapUpdates) { + if (subspace.getRepoState().refreshState(this.rushConfiguration, subspace, variant)) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `${RushConstants.repoStateFilename} has been modified and must be committed to source control.` + ) + ); + } + } + } else { + // eslint-disable-next-line no-console + console.log('Installation is already up-to-date.'); + } + + const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; + // if usePnpmSyncForInjectedDependencies is true + // the pnpm-sync will generate the pnpm-sync.json based on lockfile + 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)) && + (await FileSystem.existsAsync(modulesFilePath)) + ) { + await pnpmSyncPrepareAsync({ + lockfilePath: pnpmLockfilePath, + dotPnpmFolder, + lockfileId: subspace.subspaceName, + 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 } + ); + + 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; + } + }, + logMessageCallback: (logMessageOptions: ILogMessageCallbackOptions) => + PnpmSyncUtilities.processLogMessage(logMessageOptions, this._terminal) + }); + } + + // clean up the out of date .pnpm-sync.json + for (const rushProject of subspace.getProjects()) { + const pnpmSyncJsonPath: string = `${rushProject.projectFolder}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; + if (!existsSync(pnpmSyncJsonPath)) { + continue; + } + + let existingPnpmSyncJsonFile: { version: string } | undefined; + try { + existingPnpmSyncJsonFile = JSON.parse((await readFile(pnpmSyncJsonPath)).toString()); + if (existingPnpmSyncJsonFile?.version !== pnpmSyncGetJsonVersion()) { + await unlink(pnpmSyncJsonPath); + } + } catch (e) { + await unlink(pnpmSyncJsonPath); + } + } + } + + // Perform any post-install work the install manager requires + await this.postInstallAsync(subspace); + + if (!resolutionOnly) { + // Create the marker file to indicate a successful install + await commonTempInstallFlag.createAsync(); + } + + // Give plugins an opportunity to act after a successful install + if (this.options.afterInstallAsync !== undefined) { + await this.options.afterInstallAsync(subspace); + } + + // eslint-disable-next-line no-console + console.log(''); + } + + protected abstract prepareCommonTempAsync( + subspace: Subspace, + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }>; + + protected abstract installAsync(cleanInstall: boolean, subspace: Subspace): Promise; + + protected abstract postInstallAsync(subspace: Subspace): Promise; + + protected async canSkipInstallAsync( + lastModifiedDate: Date, + subspace: Subspace, + variant: string | undefined + ): Promise { + // Based on timestamps, can we skip this install entirely? + const potentiallyChangedFiles: string[] = []; + + // Consider the timestamp on the node_modules folder; if someone tampered with it + // or deleted it entirely, then we can't skip this install + potentiallyChangedFiles.push( + path.join(subspace.getSubspaceTempFolderPath(), RushConstants.nodeModulesFolderName) + ); + + // Additionally, if they pulled an updated shrinkwrap file from Git, + // then we can't skip this install + potentiallyChangedFiles.push(subspace.getCommittedShrinkwrapFilePath(variant)); + + // Add common-versions.json file to the potentially changed files list. + potentiallyChangedFiles.push(subspace.getCommonVersionsFilePath(variant)); + + // Add pnpm-config.json file to the potentially changed files list. + potentiallyChangedFiles.push(subspace.getPnpmConfigFilePath()); + + if (this.rushConfiguration.isPnpm) { + // If the repo is using pnpmfile.js, consider that also + const pnpmFileFilePath: string = subspace.getPnpmfilePath(variant); + const pnpmFileExists: boolean = await FileSystem.existsAsync(pnpmFileFilePath); + + if (pnpmFileExists) { + potentiallyChangedFiles.push(pnpmFileFilePath); + } + } + + return await Utilities.isFileTimestampCurrentAsync(lastModifiedDate, potentiallyChangedFiles); + } + + protected async prepareAsync( + subspace: Subspace, + variant: string | undefined, + projectImpactGraphGenerator: ProjectImpactGraphGenerator | undefined + ): Promise<{ + shrinkwrapIsUpToDate: boolean; + npmrcHash: string | undefined; + projectImpactGraphIsUpToDate: boolean; + variantIsUpToDate: boolean; + }> { + const terminal: ITerminal = this._terminal; + const { allowShrinkwrapUpdates } = this.options; + + // Check the policies + await PolicyValidator.validatePolicyAsync(this.rushConfiguration, subspace, variant, this.options); + + await this._installGitHooksAsync(); + + const approvedPackagesChecker: ApprovedPackagesChecker = new ApprovedPackagesChecker( + this.rushConfiguration + ); + if (approvedPackagesChecker.approvedPackagesFilesAreOutOfDate) { + approvedPackagesChecker.rewriteConfigFiles(); + if (allowShrinkwrapUpdates) { + terminal.writeLine( + Colorize.yellow( + 'Approved package files have been updated. These updates should be committed to source control' + ) + ); + } else { + throw new Error(`Approved packages files are out-of date. Run "rush update" to update them.`); + } + } + + // Ensure that the package manager is installed + await InstallHelpers.ensureLocalPackageManagerAsync( + this.rushConfiguration, + this.rushGlobalFolder, + this.options.maxInstallAttempts + ); + + let shrinkwrapFile: BaseShrinkwrapFile | undefined = undefined; + + // (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); + try { + shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( + this.rushConfiguration.packageManager, + committedShrinkwrapFileName + ); + } catch (ex) { + terminal.writeLine(); + terminal.writeLine( + `Unable to load the ${this.rushConfiguration.shrinkwrapFilePhrase}: ${(ex as Error).message}` + ); + + if (!allowShrinkwrapUpdates) { + terminal.writeLine(); + terminal.writeLine(Colorize.red('You need to run "rush update" to fix this problem')); + throw new AlreadyReportedError(); + } + + shrinkwrapFile = undefined; + } + } + + // Write a file indicating which variant is being installed. + // This will be used by bulk scripts to determine the correct Shrinkwrap file to track. + const currentVariantJsonFilePath: string = this.rushConfiguration.currentVariantJsonFilePath; + const currentVariantJson: ICurrentVariantJson = { + variant: variant ?? null + }; + + // Determine if the variant is already current by updating current-variant.json. + // If nothing is written, the variant has not changed. + const variantIsUpToDate: boolean = !(await JsonFile.saveAsync( + currentVariantJson, + currentVariantJsonFilePath, + { + onlyIfChanged: true + } + )); + this.rushConfiguration._currentVariantJsonLoadingPromise = undefined; + + if (this.options.variant) { + terminal.writeLine(); + terminal.writeLine(Colorize.bold(`Using variant '${this.options.variant}' for installation.`)); + } else if (!variantIsUpToDate && !variant && this.rushConfiguration.variants.size > 0) { + terminal.writeLine(); + terminal.writeLine(Colorize.bold('Using the default variant for installation.')); + } + + const extraNpmrcLines: string[] = []; + if (this.rushConfiguration.subspacesFeatureEnabled) { + // Look for a monorepo level .npmrc file + const commonNpmrcPath: string = `${this.rushConfiguration.commonRushConfigFolder}/.npmrc`; + let commonNpmrcFileLines: string[] | undefined; + try { + commonNpmrcFileLines = (await FileSystem.readFileAsync(commonNpmrcPath)).split('\n'); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + if (commonNpmrcFileLines) { + extraNpmrcLines.push(...commonNpmrcFileLines); + } + + extraNpmrcLines.push( + `global-pnpmfile=${subspace.getSubspaceTempFolderPath()}/${RushConstants.pnpmfileGlobalFilename}` + ); + } + + // Also copy down the committed .npmrc file, if there is one + // "common\config\rush\.npmrc" --> "common\temp\.npmrc" + // Also ensure that we remove any old one that may be hanging around + const npmrcText: string | undefined = Utilities.syncNpmrc({ + sourceNpmrcFolder: subspace.getSubspaceConfigFolderPath(), + targetNpmrcFolder: subspace.getSubspaceTempFolderPath(), + linesToPrepend: extraNpmrcLines, + createIfMissing: this.rushConfiguration.subspacesFeatureEnabled, + supportEnvVarFallbackSyntax: this.rushConfiguration.isPnpm + }); + this._syncNpmrcAlreadyCalled = true; + + const npmrcHash: string | undefined = npmrcText + ? crypto.createHash('sha1').update(npmrcText).digest('hex') + : undefined; + + if (this.rushConfiguration.isPnpm) { + // Copy the committed patches folder if using pnpm + const commonTempPnpmPatchesFolder: string = `${subspace.getSubspaceTempFolderPath()}/${ + RushConstants.pnpmPatchesFolderName + }`; + const rushPnpmPatchesFolder: string = subspace.getSubspacePnpmPatchesFolderPath(); + let rushPnpmPatches: FolderItem[] | undefined; + try { + rushPnpmPatches = await FileSystem.readFolderItemsAsync(rushPnpmPatchesFolder); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + if (rushPnpmPatches) { + await FileSystem.ensureFolderAsync(commonTempPnpmPatchesFolder); + const existingPatches: FolderItem[] = + await FileSystem.readFolderItemsAsync(commonTempPnpmPatchesFolder); + const copiedPatchNames: Set = new Set(); + await Async.forEachAsync( + rushPnpmPatches, + async (patch: FolderItem) => { + const name: string = patch.name; + const sourcePath: string = `${rushPnpmPatchesFolder}/${name}`; + if (patch.isFile()) { + await FileSystem.copyFileAsync({ + sourcePath, + destinationPath: `${commonTempPnpmPatchesFolder}/${name}` + }); + copiedPatchNames.add(name); + } else { + throw new Error(`Unexpected non-file item found in ${rushPnpmPatchesFolder}: ${sourcePath}`); + } + }, + { concurrency: 50 } + ); + + await Async.forEachAsync( + existingPatches, + async (patch: FolderItem) => { + const name: string = patch.name; + if (!copiedPatchNames.has(name)) { + await FileSystem.deleteFileAsync(`${commonTempPnpmPatchesFolder}/${name}`); + } + }, + { concurrency: 50 } + ); + } else { + await FileSystem.deleteFolderAsync(commonTempPnpmPatchesFolder); + } + } + + // Shim support for pnpmfile in. + // Additionally when in workspaces, the shim implements support for common versions. + if (this.rushConfiguration.isPnpm) { + await PnpmfileConfiguration.writeCommonTempPnpmfileShimAsync( + this.rushConfiguration, + subspace.getSubspaceTempFolderPath(), + subspace, + variant + ); + + if (this.rushConfiguration.subspacesFeatureEnabled) { + await SubspacePnpmfileConfiguration.writeCommonTempSubspaceGlobalPnpmfileAsync( + this.rushConfiguration, + subspace, + variant + ); + } + } + + // eslint-disable-next-line prefer-const + let [{ shrinkwrapIsUpToDate, shrinkwrapWarnings }, projectImpactGraphIsUpToDate = true] = + await Promise.all([ + // Allow for package managers to do their own preparation and check that the shrinkwrap is up to date + this.prepareCommonTempAsync(subspace, shrinkwrapFile), + projectImpactGraphGenerator?.validateAsync() + ]); + shrinkwrapIsUpToDate = shrinkwrapIsUpToDate && !this.options.recheckShrinkwrap; + + this._syncTempShrinkwrap(subspace, variant, shrinkwrapFile); + + // Write out the reported warnings + if (shrinkwrapWarnings.length > 0) { + terminal.writeLine(); + terminal.writeLine( + Colorize.yellow( + PrintUtilities.wrapWords( + `The ${this.rushConfiguration.shrinkwrapFilePhrase} contains the following issues:` + ) + ) + ); + + for (const shrinkwrapWarning of shrinkwrapWarnings) { + terminal.writeLine(Colorize.yellow(' ' + shrinkwrapWarning)); + } + + terminal.writeLine(); + } + + let hasErrors: boolean = false; + // Force update if the shrinkwrap is out of date + if (!shrinkwrapIsUpToDate && !allowShrinkwrapUpdates) { + terminal.writeErrorLine(); + terminal.writeErrorLine( + `The ${this.rushConfiguration.shrinkwrapFilePhrase} is out of date. You need to run "rush update".` + ); + hasErrors = true; + } + + if (!projectImpactGraphIsUpToDate && !allowShrinkwrapUpdates) { + hasErrors = true; + terminal.writeErrorLine(); + terminal.writeErrorLine( + Colorize.red( + `The ${RushConstants.projectImpactGraphFilename} file is missing or out of date. You need to run "rush update".` + ) + ); + } + + if (hasErrors) { + throw new AlreadyReportedError(); + } + + return { shrinkwrapIsUpToDate, npmrcHash, projectImpactGraphIsUpToDate, variantIsUpToDate }; + } + + /** + * Git hooks are only installed if the repo opts in by including files in /common/git-hooks + */ + private async _installGitHooksAsync(): Promise { + const hookSource: string = path.join(this.rushConfiguration.commonFolder, 'git-hooks'); + const git: Git = new Git(this.rushConfiguration); + const hookDestination: string | undefined = git.getHooksFolder(); + + if (FileSystem.exists(hookSource) && hookDestination) { + const allHookFilenames: string[] = FileSystem.readFolderItemNames(hookSource); + // Ignore the ".sample" file(s) in this folder. + const hookFilenames: string[] = allHookFilenames.filter((x) => !/\.sample$/.test(x)); + if (hookFilenames.length > 0) { + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold('Found files in the "common/git-hooks" folder.')); + + if (!(await git.getIsHooksPathDefaultAsync())) { + const hooksPath: string = await git.getConfigHooksPathAsync(); + const color: (str: string) => string = this.options.bypassPolicy ? Colorize.yellow : Colorize.red; + // eslint-disable-next-line no-console + console.error( + color( + [ + ' ', + `Rush cannot install the "common/git-hooks" scripts because your Git configuration `, + `specifies "core.hooksPath=${hooksPath}". You can remove the setting by running:`, + ' ', + ' git config --unset core.hooksPath', + ' ' + ].join('\n') + ) + ); + if (this.options.bypassPolicy) { + // If "--bypass-policy" is specified, skip installation of hooks because Rush doesn't + // own the hooks folder + return; + } + // eslint-disable-next-line no-console + console.error( + color( + [ + '(Or, to temporarily ignore this problem, invoke Rush with the ' + + `"${RushConstants.bypassPolicyFlagLongName}" option.)`, + ' ' + ].join('\n') + ) + ); + throw new AlreadyReportedError(); + } + + // Clear the currently installed git hooks and install fresh copies + FileSystem.ensureEmptyFolder(hookDestination); + + // Find the relative path from Git hooks directory to the directory storing the actual scripts. + const hookRelativePath: string = Path.convertToSlashes(path.relative(hookDestination, hookSource)); + + // Only copy files that look like Git hook names + const filteredHookFilenames: string[] = hookFilenames.filter((x) => /^[a-z\-]+/.test(x)); + for (const filename of filteredHookFilenames) { + const hookFilePath: string = `${hookSource}/${filename}`; + // Make sure the actual script in the hookSource directory has correct Linux compatible line endings + const originalHookFileContent: string = FileSystem.readFile(hookFilePath); + FileSystem.writeFile(hookFilePath, originalHookFileContent, { + convertLineEndings: NewlineKind.Lf + }); + // Make sure the actual script in the hookSource directory has required permission bits + const originalPosixModeBits: PosixModeBits = FileSystem.getPosixModeBits(hookFilePath); + FileSystem.changePosixModeBits( + hookFilePath, + // eslint-disable-next-line no-bitwise + originalPosixModeBits | PosixModeBits.UserRead | PosixModeBits.UserExecute + ); + + const gitLfsHookHandling: string = gitLfsHooks.has(filename) + ? ` +# Inspired by https://github.com/git-lfs/git-lfs/issues/2865#issuecomment-365742940 +if command -v git-lfs &> /dev/null; then + git lfs ${filename} "$@" +fi +` + : ''; + + const hookFileContent: string = `#!/bin/bash +set -e +SCRIPT_DIR="$( cd "$( dirname "\${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +SCRIPT_IMPLEMENTATION_PATH="$SCRIPT_DIR/${hookRelativePath}/${filename}" + +if [[ -f "$SCRIPT_IMPLEMENTATION_PATH" ]]; then + "$SCRIPT_IMPLEMENTATION_PATH" $@ +else + echo "The ${filename} Git hook no longer exists in your version of the repo. Run 'rush install' or 'rush update' to refresh your installed Git hooks." >&2 +fi +${gitLfsHookHandling} +`; + // Create the hook file. Important: For Bash scripts, the EOL must not be CRLF. + FileSystem.writeFile(path.join(hookDestination, filename), hookFileContent, { + convertLineEndings: NewlineKind.Lf + }); + + FileSystem.changePosixModeBits( + path.join(hookDestination, filename), + // eslint-disable-next-line no-bitwise + PosixModeBits.UserRead | PosixModeBits.UserExecute + ); + } + + // eslint-disable-next-line no-console + console.log( + 'Successfully installed these Git hook scripts: ' + filteredHookFilenames.join(', ') + '\n' + ); + } + } + } + + /** + * Used when invoking the NPM tool. Appends the common configuration options + * to the command-line. + */ + protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions, subspace: Subspace): void { + const { + offline, + collectLogFile, + pnpmFilterArgumentValues, + onlyShrinkwrap, + networkConcurrency, + allowShrinkwrapUpdates, + resolutionOnly + } = options; + + if (offline && this.rushConfiguration.packageManager !== 'pnpm') { + throw new Error('The "--offline" parameter is only supported when using the PNPM package manager.'); + } + if (resolutionOnly && this.rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + 'The "--resolution-only" parameter is only supported when using the PNPM package manager.' + ); + } + if (this.rushConfiguration.packageManager === 'npm') { + if (semver.lt(this.rushConfiguration.packageManagerToolVersion, '5.0.0')) { + // NOTE: + // + // When using an npm version older than v5.0.0, we do NOT install optional dependencies for + // Rush, because npm does not generate the shrinkwrap file consistently across platforms. + // + // Consider the "fsevents" package. This is a Mac specific package + // which is an optional second-order dependency. Optional dependencies work by attempting to install + // the package, but removes the package if the install failed. + // This means that someone running generate on a Mac WILL have fsevents included in their shrinkwrap. + // When someone using Windows attempts to install from the shrinkwrap, the install will fail. + // + // If someone generates the shrinkwrap using Windows, then fsevents will NOT be listed in the shrinkwrap. + // When someone using Mac attempts to install from the shrinkwrap, they will NOT have the + // optional dependency installed. + // + // This issue has been fixed as of npm v5.0.0: https://github.com/npm/npm/releases/tag/v5.0.0 + // + // For more context, see https://github.com/microsoft/rushstack/issues/761#issuecomment-428689600 + args.push('--no-optional'); + } + args.push('--cache', this.rushConfiguration.npmCacheFolder); + args.push('--tmp', this.rushConfiguration.npmTmpFolder); + + if (collectLogFile) { + args.push('--verbose'); + } + } else if (this.rushConfiguration.isPnpm) { + // Only explicitly define the store path if `pnpmStore` is using the default, or has been set to + // 'local'. If `pnpmStore` = 'global', then allow PNPM to use the system's default + // path. In all cases, this will be overridden by RUSH_PNPM_STORE_PATH + if ( + this.rushConfiguration.pnpmOptions.pnpmStore === 'local' || + EnvironmentConfiguration.pnpmStorePathOverride + ) { + args.push('--store', this.rushConfiguration.pnpmOptions.pnpmStorePath); + if (semver.gte(this.rushConfiguration.packageManagerToolVersion, '6.10.0')) { + args.push(`${pnpmCacheDirParameter}=${this.rushConfiguration.pnpmOptions.pnpmStorePath}`); + args.push(`${pnpmStateDirParameter}=${this.rushConfiguration.pnpmOptions.pnpmStorePath}`); + } + } + + const { pnpmVerifyStoreIntegrity } = EnvironmentConfiguration; + if (pnpmVerifyStoreIntegrity !== undefined) { + args.push(`--verify-store-integrity`, `${pnpmVerifyStoreIntegrity}`); + } + + const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; + + if (experiments.usePnpmFrozenLockfileForRushInstall && !allowShrinkwrapUpdates) { + args.push('--frozen-lockfile'); + + if ( + pnpmFilterArgumentValues.length > 0 && + Number.parseInt(this.rushConfiguration.packageManagerToolVersion, 10) >= 8 // PNPM Major version 8+ + ) { + // On pnpm@8, disable the "dedupe-peer-dependents" feature when doing a filtered CI install so that filters take effect. + args.push('--config.dedupe-peer-dependents=false'); + } + } else if (experiments.usePnpmPreferFrozenLockfileForRushUpdate) { + // In workspaces, we want to avoid unnecessary lockfile churn + args.push('--prefer-frozen-lockfile'); + } else { + // Ensure that Rush's tarball dependencies get synchronized properly with the pnpm-lock.yaml file. + // See this GitHub issue: https://github.com/pnpm/pnpm/issues/1342 + args.push('--no-prefer-frozen-lockfile'); + } + + if (onlyShrinkwrap) { + args.push(`--lockfile-only`); + } + + if (collectLogFile) { + args.push('--reporter', 'ndjson'); + } + + if (networkConcurrency) { + args.push('--network-concurrency', networkConcurrency.toString()); + } + + if (offline) { + args.push('--offline'); + } + + if (this.rushConfiguration.pnpmOptions.strictPeerDependencies === false) { + args.push('--no-strict-peer-dependencies'); + } else { + args.push('--strict-peer-dependencies'); + } + + if (resolutionOnly) { + args.push('--resolution-only'); + } + + /* + If user set auto-install-peers in pnpm-config.json only, use the value in pnpm-config.json + If user set auto-install-peers in pnpm-config.json and .npmrc, use the value in pnpm-config.json + If user set auto-install-peers in .npmrc only, do nothing, let pnpm handle it + If user does not set auto-install-peers in both pnpm-config.json and .npmrc, rush will default it to "false" + */ + const isAutoInstallPeersInNpmrc: boolean = isVariableSetInNpmrcFile( + subspace.getSubspaceConfigFolderPath(), + 'auto-install-peers', + this.rushConfiguration.isPnpm + ); + + let autoInstallPeers: boolean | undefined = this.rushConfiguration.pnpmOptions.autoInstallPeers; + if (autoInstallPeers !== undefined) { + if (isAutoInstallPeersInNpmrc) { + this._terminal.writeWarningLine( + `Warning: PNPM's auto-install-peers is specified in both .npmrc and pnpm-config.json. ` + + `The value in pnpm-config.json will take precedence.` + ); + } + } else if (!isAutoInstallPeersInNpmrc) { + // if auto-install-peers isn't specified in either .npmrc or pnpm-config.json, + // then rush will default it to "false" + autoInstallPeers = false; + } + if (autoInstallPeers !== undefined) { + args.push(`--config.auto-install-peers=${autoInstallPeers}`); + } + + /* + If user set resolution-mode in pnpm-config.json only, use the value in pnpm-config.json + If user set resolution-mode in pnpm-config.json and .npmrc, use the value in pnpm-config.json + If user set resolution-mode in .npmrc only, do nothing, let pnpm handle it + If user does not set resolution-mode in pnpm-config.json and .npmrc, rush will default it to "highest" + */ + const isResolutionModeInNpmrc: boolean = isVariableSetInNpmrcFile( + subspace.getSubspaceConfigFolderPath(), + 'resolution-mode', + this.rushConfiguration.isPnpm + ); + + let resolutionMode: PnpmResolutionMode | undefined = this.rushConfiguration.pnpmOptions.resolutionMode; + if (resolutionMode) { + if (isResolutionModeInNpmrc) { + this._terminal.writeWarningLine( + `Warning: PNPM's resolution-mode is specified in both .npmrc and pnpm-config.json. ` + + `The value in pnpm-config.json will take precedence.` + ); + } + } else if (!isResolutionModeInNpmrc) { + // if resolution-mode isn't specified in either .npmrc or pnpm-config.json, + // then rush will default it to "highest" + resolutionMode = 'highest'; + } + if (resolutionMode) { + args.push(`--config.resolutionMode=${resolutionMode}`); + } + + if ( + semver.satisfies( + this.rushConfiguration.packageManagerToolVersion, + '6.32.12 - 6.33.x || 7.0.1 - 7.8.x' + ) + ) { + this._terminal.writeWarningLine( + `Warning: Your ${RushConstants.rushJsonFilename} specifies a pnpmVersion with a known issue ` + + 'that may cause unintended version selections.' + + " It's recommended to upgrade to PNPM >=6.34.0 or >=7.9.0. " + + 'For details see: https://rushjs.io/link/pnpm-issue-5132' + ); + } + if ( + semver.gte(this.rushConfiguration.packageManagerToolVersion, '7.9.0') || + semver.satisfies(this.rushConfiguration.packageManagerToolVersion, '^6.34.0') + ) { + args.push(pnpmIgnoreCompatibilityDbParameter); + } + } else if (this.rushConfiguration.packageManager === 'yarn') { + args.push('--link-folder', 'yarn-link'); + args.push('--cache-folder', this.rushConfiguration.yarnCacheFolder); + + // Without this option, Yarn will sometimes stop and ask for user input on STDIN + // (e.g. "Which command would you like to run?"). + args.push('--non-interactive'); + + if (networkConcurrency) { + args.push('--network-concurrency', networkConcurrency.toString()); + } + + if (this.rushConfiguration.yarnOptions.ignoreEngines) { + args.push('--ignore-engines'); + } + + if (collectLogFile) { + args.push('--verbose'); + } + } + } + + private async _checkIfReleaseIsPublishedAsync(): Promise { + const lastCheckFile: string = path.join( + this.rushGlobalFolder.nodeSpecificPath, + 'rush-' + Rush.version, + 'last-check.flag' + ); + + if (FileSystem.exists(lastCheckFile)) { + let cachedResult: boolean | 'error' | undefined = undefined; + try { + // NOTE: mtimeMs is not supported yet in Node.js 6.x + const nowMs: number = new Date().getTime(); + const ageMs: number = nowMs - FileSystem.getStatistics(lastCheckFile).mtime.getTime(); + const HOUR: number = 60 * 60 * 1000; + + // Is the cache too old? + if (ageMs < 24 * HOUR) { + // No, read the cached result + cachedResult = JsonFile.load(lastCheckFile); + } + } catch (e) { + // Unable to parse file + } + if (cachedResult === 'error') { + throw new Error('Unable to contact server'); + } + if (cachedResult === true || cachedResult === false) { + return cachedResult; + } + } + + // Before we start the network operation, record a failed state. If the process exits for some reason, + // this will record the error. It will also update the timestamp to prevent other Rush instances + // from attempting to update the file. + await JsonFile.saveAsync('error', lastCheckFile, { ensureFolderExists: true }); + + try { + // For this check we use the official registry, not the private registry + const publishedRelease: boolean = await this._queryIfReleaseIsPublishedAsync( + 'https://registry.npmjs.org:443' + ); + // Cache the result + await JsonFile.saveAsync(publishedRelease, lastCheckFile, { ensureFolderExists: true }); + return publishedRelease; + } catch (error) { + await JsonFile.saveAsync('error', lastCheckFile, { ensureFolderExists: true }); + throw error; + } + } + + // Helper for checkIfReleaseIsPublished() + private async _queryIfReleaseIsPublishedAsync(registryUrl: string): Promise { + let queryUrl: string = registryUrl; + if (queryUrl[-1] !== '/') { + queryUrl += '/'; + } + // Note that the "@" symbol does not normally get URL-encoded + queryUrl += RushConstants.rushPackageName.replace('/', '%2F'); + + const { WebClient } = await import('../../utilities/WebClient'); + + const webClient: WebClientType = new WebClient(); + webClient.userAgent = `pnpm/? npm/? node/${process.version} ${os.platform()} ${os.arch()}`; + webClient.accept = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*'; + + const response: IWebClientResponse = await webClient.fetchAsync(queryUrl); + if (!response.ok) { + throw new Error('Failed to query'); + } + + const data: { versions: { [version: string]: { dist: { tarball: string } } } } = + await response.getJsonAsync(); + let url: string; + try { + if (!data.versions[Rush.version]) { + // Version was not published + return false; + } + + url = data.versions[Rush.version].dist.tarball; + if (!url) { + throw new Error(`URL not found`); + } + } catch (e) { + throw new Error('Error parsing response'); + } + + // Make sure the tarball wasn't deleted from the CDN + webClient.accept = '*/*'; + + const response2: IWebClientResponse = await webClient.fetchAsync(url); + + if (!response2.ok) { + if (response2.status === 404) { + return false; + } else { + throw new Error('Failed to fetch'); + } + } + + return true; + } + + private _syncTempShrinkwrap( + subspace: Subspace, + variant: string | undefined, + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): void { + const committedShrinkwrapFileName: string = subspace.getCommittedShrinkwrapFilePath(variant); + if (shrinkwrapFile) { + Utilities.syncFile(committedShrinkwrapFileName, subspace.getTempShrinkwrapFilename()); + Utilities.syncFile(committedShrinkwrapFileName, subspace.getTempShrinkwrapPreinstallFilename()); + } else { + // Otherwise delete the temporary file + FileSystem.deleteFile(subspace.getTempShrinkwrapFilename()); + + if (this.rushConfiguration.isPnpm) { + // Workaround for https://github.com/pnpm/pnpm/issues/1890 + // + // When "rush update --full" is run, Rush deletes "common/temp/pnpm-lock.yaml" + // so that a new lockfile will be generated. However "pnpm install" by design will try to recover + // "pnpm-lock.yaml" from "common/temp/node_modules/.pnpm/lock.yaml", which may prevent a full upgrade. + // Deleting both files ensures that a new lockfile will always be generated. + const pnpmPackageManager: PnpmPackageManager = this.rushConfiguration + .packageManagerWrapper as PnpmPackageManager; + + FileSystem.deleteFile( + path.join(subspace.getSubspaceTempFolderPath(), pnpmPackageManager.internalShrinkwrapRelativePath) + ); + } + } + } + + protected async validateNpmSetupAsync(): Promise { + if (this._npmSetupValidated) { + return; + } + + if (!this.options.bypassPolicy) { + const setupPackageRegistry: SetupPackageRegistry = new SetupPackageRegistry({ + rushConfiguration: this.rushConfiguration, + isDebug: this.options.debug, + syncNpmrcAlreadyCalled: this._syncNpmrcAlreadyCalled + }); + const valid: boolean = await setupPackageRegistry.checkOnlyAsync(); + if (!valid) { + // eslint-disable-next-line no-console + console.error(); + // eslint-disable-next-line no-console + console.error(Colorize.red('ERROR: NPM credentials are missing or expired')); + // eslint-disable-next-line no-console + console.error(); + // eslint-disable-next-line no-console + console.error( + Colorize.bold( + '==> Please run "rush setup" to update your NPM token. ' + + `(Or append "${RushConstants.bypassPolicyFlagLongName}" to proceed anyway.)` + ) + ); + throw new AlreadyReportedError(); + } + } + + this._npmSetupValidated = true; + } +} diff --git a/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts b/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts new file mode 100644 index 00000000000..2825f927fe4 --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.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 type { ITerminal } from '@rushstack/terminal'; + +import type { Subspace } from '../../api/Subspace'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; + +export interface IInstallManagerOptions { + /** + * Whether the global "--debug" flag was specified. + */ + debug: boolean; + + /** + * Whether or not Rush will automatically update the shrinkwrap file. + * True for "rush update", false for "rush install". + */ + allowShrinkwrapUpdates: boolean; + + /** + * Whether to check the validation before install only, without actually installing anything. + */ + checkOnly: boolean; + + /** + * Whether to only run resolutions. Only supported for PNPM. + */ + resolutionOnly?: boolean; + + /** + * Whether a "--bypass-policy" flag can be specified. + */ + bypassPolicyAllowed?: boolean; + + /** + * Whether to skip policy checks. + */ + bypassPolicy: boolean; + + /** + * Whether to skip linking, i.e. require "rush link" to be done manually later. + */ + noLink: boolean; + + /** + * Whether to delete the shrinkwrap file before installation, i.e. so that all dependencies + * will be upgraded to the latest SemVer-compatible version. + */ + fullUpgrade: boolean; + + /** + * If set, only update the shrinkwrap file; do not create node_modules. + */ + onlyShrinkwrap?: boolean; + + /** + * Whether to force an update to the shrinkwrap file even if it appears to be unnecessary. + * Normally Rush uses heuristics to determine when "pnpm install" can be skipped, + * but sometimes the heuristics can be inaccurate due to external influences + * (pnpmfile.js script logic, registry changes, etc). + */ + recheckShrinkwrap: boolean; + + /** + * Do not attempt to access the network. Report an error if the required dependencies + * cannot be obtained from the local cache. + */ + offline: boolean; + + /** + * The value of the "--network-concurrency" command-line parameter, which + * is a diagnostic option used to troubleshoot network failures. + * + * Currently only supported for PNPM. + */ + networkConcurrency: number | undefined; + + /** + * Whether or not to collect verbose logs from the package manager. + * If specified when using PNPM, the logs will be in /common/temp/pnpm.log + */ + collectLogFile: boolean; + + /** + * The variant to consider when performing installations and validating shrinkwrap updates. + */ + variant: string | undefined; + + /** + * Retry the install the specified number of times + */ + maxInstallAttempts: number; + + /** + * An array of `--filter` argument values. For example, if the array is ["a", "b"] then Rush would invoke + * `pnpm install --filter a --filter b` which restricts the install/update to dependencies of + * workspace projects "a" and "b". If the array is empty, then an unfiltered install + * is performed. Filtered installs have some limitations such as less comprehensive version analysis. + * + * @remarks + * Note that PNPM may arbitrarily ignore `--filter` (producing an unfiltered install) in certain situations, + * for example when `config.dedupe-peer-dependents=true` with PNPM 8. Rush tries to circumvent this, under the + * assumption that a user who invokes a filtered install cares more about lockfile stability than duplication. + */ + pnpmFilterArgumentValues: string[]; + + /** + * The set of projects for which installation should be performed. + */ + selectedProjects: Set; + + /** + * Callback to invoke between preparing the common/temp folder and running installation. + */ + beforeInstallAsync?: (subspace: Subspace) => Promise; + + /** + * Callback to invoke after a successful installation. + */ + afterInstallAsync?: (subspace: Subspace) => Promise; + + /** + * The specific subspace to install. + */ + subspace: Subspace; + + /** + * The terminal where output should be printed. + */ + terminal: ITerminal; +} diff --git a/libraries/rush-lib/src/logic/base/BaseLinkManager.ts b/libraries/rush-lib/src/logic/base/BaseLinkManager.ts new file mode 100644 index 00000000000..ace4c2d0943 --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseLinkManager.ts @@ -0,0 +1,212 @@ +// 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, + type FileSystemStats, + type IFileSystemCreateLinkOptions, + InternalError +} from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { Utilities } from '../../utilities/Utilities'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import type { BasePackage } from './BasePackage'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import { RushConstants } from '../RushConstants'; +import { FlagFile } from '../../api/FlagFile'; + +export enum SymlinkKind { + File, + Directory +} + +export interface IBaseLinkManagerCreateSymlinkOptions extends IFileSystemCreateLinkOptions { + symlinkKind: SymlinkKind; +} + +export abstract class BaseLinkManager { + protected _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public static async _createSymlinkAsync(options: IBaseLinkManagerCreateSymlinkOptions): Promise { + // TODO: Consider promoting this to node-core-library + const newLinkFolder: string = path.dirname(options.newLinkPath); + await FileSystem.ensureFolderAsync(newLinkFolder); + + let relativePathForbidden: boolean = false; + let linkFunctionAsync: (options: IBaseLinkManagerCreateSymlinkOptions) => Promise; + + if (process.platform === 'win32') { + if (options.symlinkKind === SymlinkKind.Directory) { + // For directories, we use a Windows "junction". On Unix, this produces a regular symlink. + 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 + 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) { + linkFunctionAsync = FileSystem.createSymbolicLinkFolderAsync.bind(FileSystem); + } else { + 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 + }); + } + + /** + * For a Package object that represents a top-level Rush project folder + * (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 async _createSymlinksForTopLevelProjectAsync(localPackage: BasePackage): Promise { + const localModuleFolder: string = path.join(localPackage.folderPath, 'node_modules'); + + // Sanity check + if (localPackage.parent) { + throw new Error('The provided package is not a top-level project'); + } + + // The root-level folder is the project itself, so we simply delete its node_modules + // to start clean + // eslint-disable-next-line no-console + console.log('Purging ' + localModuleFolder); + Utilities.dangerouslyDeletePath(localModuleFolder); + + if (localPackage.children.length > 0) { + Utilities.createFolderWithRetry(localModuleFolder); + + for (const child of localPackage.children) { + await BaseLinkManager._createSymlinksForDependenciesAsync(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 async _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 BaseLinkManager._createSymlinksForDependenciesAsync(child); + } + } + } + + /** + * Creates node_modules symlinks for all Rush projects defined in the RushConfiguration. + * @param force - Normally the operation will be skipped if the links are already up to date; + * if true, this option forces the links to be recreated. + */ + public async createSymlinksForProjectsAsync(force: boolean): Promise { + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold('Linking local projects')); + const stopwatch: Stopwatch = Stopwatch.start(); + + await this._linkProjectsAsync(); + + // TODO: Remove when "rush link" and "rush unlink" are deprecated + await new FlagFile( + this._rushConfiguration.defaultSubspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ).createAsync(); + + stopwatch.stop(); + // eslint-disable-next-line no-console + console.log('\n' + Colorize.green(`Linking finished successfully. (${stopwatch.toString()})`)); + // eslint-disable-next-line no-console + console.log('\nNext you should probably run "rush build" or "rush rebuild"'); + } + + protected abstract _linkProjectsAsync(): Promise; +} diff --git a/apps/rush-lib/src/logic/base/BasePackage.ts b/libraries/rush-lib/src/logic/base/BasePackage.ts similarity index 85% rename from apps/rush-lib/src/logic/base/BasePackage.ts rename to libraries/rush-lib/src/logic/base/BasePackage.ts index 81586d3ba44..2a1fb304a0d 100644 --- a/apps/rush-lib/src/logic/base/BasePackage.ts +++ b/libraries/rush-lib/src/logic/base/BasePackage.ts @@ -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. -import { - JsonFile, - IPackageJson -} from '@rushstack/node-core-library'; +import { JsonFile, type IPackageJson } from '@rushstack/node-core-library'; /** * The type of dependency; used by IPackageDependency. @@ -51,7 +48,7 @@ export interface IRushTempPackageJson extends IPackageJson { } /** - * Represents an NPM package being processed by the "rush link" algorithm. + * Represents an NPM package being processed by the linking algorithm. */ export class BasePackage { /** @@ -108,11 +105,12 @@ export class BasePackage { public children: BasePackage[]; private _childrenByName: Map; - protected constructor(name: string, + protected constructor( + name: string, version: string | undefined, folderPath: string, - packageJson: IRushTempPackageJson | undefined) { - + packageJson: IRushTempPackageJson | undefined + ) { this.name = name; this.packageJson = packageJson; this.version = version; @@ -137,10 +135,12 @@ export class BasePackage { * Used by link managers, creates a virtual Package object that represents symbolic links * which will be created later */ - public static createLinkedPackage(name: string, + public static createLinkedPackage( + name: string, version: string | undefined, folderPath: string, - packageJson?: IRushTempPackageJson): BasePackage { + packageJson?: IRushTempPackageJson + ): BasePackage { return new BasePackage(name, version, folderPath, packageJson); } @@ -152,9 +152,17 @@ export class 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): BasePackage { + public static createVirtualTempPackage( + packageJsonFilename: string, + installFolderName: string + ): BasePackage { const packageJson: IRushTempPackageJson = JsonFile.load(packageJsonFilename); - return BasePackage.createLinkedPackage(packageJson.name, packageJson.version, installFolderName, packageJson); + return BasePackage.createLinkedPackage( + packageJson.name, + packageJson.version, + installFolderName, + packageJson + ); } public get nameAndVersion(): string { @@ -178,12 +186,12 @@ export class BasePackage { if (child.parent) { throw new Error('Child already has a parent'); } - if (this._childrenByName.has(child.name)) { - throw new Error('Child already exists'); + if (this._childrenByName.has(child.installedName)) { + throw new Error(`Child already exists: ${child.installedName}`); } child.parent = this; this.children.push(child); - this._childrenByName.set(child.name, child); + this._childrenByName.set(child.installedName, child); } public getChildByName(childPackageName: string): BasePackage | undefined { @@ -194,9 +202,11 @@ export class BasePackage { if (!indent) { indent = ''; } + + // eslint-disable-next-line no-console console.log(indent + this.nameAndVersion); for (const child of this.children) { child.printTree(indent + ' '); } } -} \ No newline at end of file +} diff --git a/libraries/rush-lib/src/logic/base/BasePackageManagerOptionsConfiguration.ts b/libraries/rush-lib/src/logic/base/BasePackageManagerOptionsConfiguration.ts new file mode 100644 index 00000000000..1120dbbe543 --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BasePackageManagerOptionsConfiguration.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Represents the value of an environment variable, and if the value should be overridden if the variable is set + * in the parent environment. + * @public + */ +export interface IConfigurationEnvironmentVariable { + /** + * Value of the environment variable + */ + value: string; + + /** + * Set to true to override the environment variable even if it is set in the parent environment. + * The default value is false. + */ + override?: boolean; +} + +/** + * A collection of environment variables + * @public + */ +export interface IConfigurationEnvironment { + /** + * Environment variables + */ + [environmentVariableName: string]: IConfigurationEnvironmentVariable; +} + +/** + * Options for the package manager. + * @public + */ +export interface IPackageManagerOptionsJsonBase { + /** + * Environment variables for the package manager + */ + environmentVariables?: IConfigurationEnvironment; +} + +/** + * Options that all package managers share. + * + * @public + */ +export abstract class PackageManagerOptionsConfigurationBase implements IPackageManagerOptionsJsonBase { + /** + * Environment variables for the package manager + */ + public readonly environmentVariables?: IConfigurationEnvironment; + + /** @internal */ + protected constructor(json: IPackageManagerOptionsJsonBase) { + this.environmentVariables = json.environmentVariables; + } +} diff --git a/libraries/rush-lib/src/logic/base/BaseProjectShrinkwrapFile.ts b/libraries/rush-lib/src/logic/base/BaseProjectShrinkwrapFile.ts new file mode 100644 index 00000000000..284eed0d9cd --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseProjectShrinkwrapFile.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 { FileSystem, JsonFile } from '@rushstack/node-core-library'; + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { RushConstants } from '../RushConstants'; +import type { BaseShrinkwrapFile } from './BaseShrinkwrapFile'; + +/** + * This class handles creating the project/.rush/temp/shrinkwrap-deps.json file + * which tracks the direct and indirect dependencies that a project consumes. This is used + * to better determine which projects should be rebuilt when dependencies are updated. + */ +export abstract class BaseProjectShrinkwrapFile { + public readonly projectShrinkwrapFilePath: string; + protected readonly project: RushConfigurationProject; + + /** + * The shrinkwrap file that the project shrinkwrap file is based off of. + */ + protected readonly shrinkwrapFile: TShrinkwrapFile; + + public constructor(shrinkwrapFile: TShrinkwrapFile, project: RushConfigurationProject) { + this.project = project; + this.projectShrinkwrapFilePath = BaseProjectShrinkwrapFile.getFilePathForProject(this.project); + + this.shrinkwrapFile = shrinkwrapFile; + } + + /** + * Save an empty project shrinkwrap file. This is used in repos with no dependencies. + */ + public static async saveEmptyProjectShrinkwrapFileAsync(project: RushConfigurationProject): Promise { + const projectShrinkwrapFilePath: string = BaseProjectShrinkwrapFile.getFilePathForProject(project); + await JsonFile.saveAsync({}, projectShrinkwrapFilePath, { ensureFolderExists: true }); + } + + /** + * Get the fully-qualified path to the /.rush/temp/shrinkwrap-deps.json + * for the specified project. + */ + public static getFilePathForProject(project: RushConfigurationProject): string { + return `${project.projectRushTempFolder}/${RushConstants.projectShrinkwrapFilename}`; + } + + /** + * If the /.rush/temp/shrinkwrap-deps.json file exists, delete it. Otherwise, do nothing. + */ + public async deleteIfExistsAsync(): Promise { + await FileSystem.deleteFileAsync(this.projectShrinkwrapFilePath, { throwIfNotExists: false }); + } + + /** + * Generate and write the project shrinkwrap file to /.rush/temp/shrinkwrap-deps.json. + * + * @virtual + */ + public abstract updateProjectShrinkwrapAsync(): Promise; +} diff --git a/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts new file mode 100644 index 00000000000..04d64cc8ebd --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -0,0 +1,242 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// 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'; +import { type DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; +import type { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { PackageNameParsers } from '../../api/PackageNameParsers'; +import type { IExperimentsJson } from '../../api/ExperimentsConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { BaseProjectShrinkwrapFile } from './BaseProjectShrinkwrapFile'; +import type { PackageManagerOptionsConfigurationBase } from './BasePackageManagerOptionsConfiguration'; +import type { Subspace } from '../../api/Subspace'; + +/** + * This class is a parser for both npm's npm-shrinkwrap.json and pnpm's pnpm-lock.yaml file formats. + */ +export abstract class BaseShrinkwrapFile { + public abstract readonly isWorkspaceCompatible: boolean; + protected _alreadyWarnedSpecs: Set = new Set(); + + protected static tryGetValue(dictionary: { [key2: string]: T }, key: string): T | undefined { + if (dictionary.hasOwnProperty(key)) { + return dictionary[key]; + } + return undefined; + } + + /** + * Determine whether `pnpm-lock.yaml` complies with the rules specified in `common/config/rush/pnpm-config.schema.json`. + * + * @virtual + */ + public validateShrinkwrapAfterUpdate( + rushConfiguration: RushConfiguration, + subspace: Subspace, + terminal: ITerminal + ): void {} + + /** + * Validate the shrinkwrap using the provided policy options. + * + * @virtual + */ + public validate( + packageManagerOptionsConfig: PackageManagerOptionsConfigurationBase, + policyOptions: IShrinkwrapFilePolicyValidatorOptions, + experimentsConfig?: IExperimentsJson + ): void {} + + /** + * Returns true if the shrinkwrap file includes a top-level package that would satisfy the specified + * package name and SemVer version range + * + * @virtual + */ + public hasCompatibleTopLevelDependency(dependencySpecifier: DependencySpecifier): boolean { + const shrinkwrapDependency: DependencySpecifier | undefined = this.getTopLevelDependencyVersion( + dependencySpecifier.packageName + ); + if (!shrinkwrapDependency) { + return false; + } + + return this._checkDependencyVersion(dependencySpecifier, shrinkwrapDependency); + } + + /** + * Returns true if the shrinkwrap file includes a package that would satisfying the specified + * package name and SemVer version range. By default, the dependencies are resolved by looking + * at the root of the node_modules folder described by the shrinkwrap file. However, if + * tempProjectName is specified, then the resolution will start in that subfolder. + * + * Consider this example: + * + * - node_modules\ + * - temp-project\ + * - lib-a@1.2.3 + * - lib-b@1.0.0 + * - lib-b@2.0.0 + * + * In this example, hasCompatibleDependency("lib-b", ">= 1.1.0", "temp-project") would fail + * because it finds lib-b@1.0.0 which does not satisfy the pattern ">= 1.1.0". + * + * @virtual + */ + public tryEnsureCompatibleDependency( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): boolean { + const shrinkwrapDependency: DependencySpecifier | undefined = this.tryEnsureDependencyVersion( + dependencySpecifier, + tempProjectName + ); + if (!shrinkwrapDependency) { + return false; + } + + return this._checkDependencyVersion(dependencySpecifier, shrinkwrapDependency); + } + + /** + * Returns the list of temp projects defined in this file. + * Example: [ '@rush-temp/project1', '@rush-temp/project2' ] + * + * @virtual + */ + public abstract getTempProjectNames(): ReadonlyArray; + + /** @virtual */ + protected abstract tryEnsureDependencyVersion( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): DependencySpecifier | undefined; + + /** @virtual */ + protected abstract getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined; + + /** + * Check for projects that exist in the shrinkwrap file, but don't exist + * in rush.json. This might occur, e.g. if a project was recently deleted or renamed. + * + * @returns a list of orphaned projects. + */ + public findOrphanedProjects( + rushConfiguration: RushConfiguration, + subspace: Subspace + ): ReadonlyArray { + const orphanedProjectNames: string[] = []; + // We can recognize temp projects because they are under the "@rush-temp" NPM scope. + for (const tempProjectName of this.getTempProjectNames()) { + if (!rushConfiguration.findProjectByTempName(tempProjectName)) { + orphanedProjectNames.push(tempProjectName); + } + } + return orphanedProjectNames; + } + + /** + * Returns a project shrinkwrap file for the specified project that contains all dependencies and transitive + * dependencies. + * + * @virtual + **/ + public abstract getProjectShrinkwrap( + project: RushConfigurationProject + ): BaseProjectShrinkwrapFile | undefined; + + /** + * Returns whether or not the workspace specified by the shrinkwrap matches the state of + * a given package.json. Returns true if any dependencies are not aligned with the shrinkwrap. + * + * @param project - the Rush project that is being validated against the shrinkwrap + * @param variant - the variant that is being validated + * + * @virtual + */ + public abstract isWorkspaceProjectModifiedAsync( + project: RushConfigurationProject, + subspace: Subspace, + variant: string | undefined + ): Promise; + + /** @virtual */ + protected abstract serialize(): string; + + protected _getTempProjectNames(dependencies: { [key: string]: {} }): ReadonlyArray { + const result: string[] = []; + for (const key of Object.keys(dependencies)) { + // If it starts with @rush-temp, then include it: + if (PackageNameParsers.permissive.getScope(key) === RushConstants.rushTempNpmScope) { + result.push(key); + } + } + result.sort(); // make the result deterministic + return result; + } + + private _checkDependencyVersion( + projectDependency: DependencySpecifier, + shrinkwrapDependency: DependencySpecifier + ): boolean { + let normalizedProjectDependency: DependencySpecifier = projectDependency; + let normalizedShrinkwrapDependency: DependencySpecifier = shrinkwrapDependency; + + // Special handling for NPM package aliases such as this: + // + // "dependencies": { + // "alias-name": "npm:target-name@^1.2.3" + // } + // + // In this case, the shrinkwrap file will have a key equivalent to "npm:target-name@1.2.5", + // and so we need to unwrap the target and compare "1.2.5" with "^1.2.3". + if (projectDependency.specifierType === DependencySpecifierType.Alias) { + // Does the shrinkwrap install it as an alias? + if (shrinkwrapDependency.specifierType === DependencySpecifierType.Alias) { + // Does the shrinkwrap have the right package name? + if (projectDependency.packageName === shrinkwrapDependency.packageName) { + // Yes, the aliases match, so let's compare their targets in the logic below + normalizedProjectDependency = projectDependency.aliasTarget!; + normalizedShrinkwrapDependency = shrinkwrapDependency.aliasTarget!; + } else { + // If the names are different, then it's a mismatch + return false; + } + } else { + // A non-alias cannot satisfy an alias dependency; at least, let's avoid that idea + return false; + } + } + + switch (normalizedProjectDependency.specifierType) { + case DependencySpecifierType.Version: + case DependencySpecifierType.Range: + return semver.satisfies( + normalizedShrinkwrapDependency.versionSpecifier, + normalizedProjectDependency.versionSpecifier + ); + default: + // For other version specifier types like "file:./blah.tgz" or "git://github.com/npm/cli.git#v1.0.27" + // we allow the installation to continue but issue a warning. The "rush install" checks will not work + // correctly. + + // Only warn once for each versionSpecifier + if (!this._alreadyWarnedSpecs.has(projectDependency.versionSpecifier)) { + this._alreadyWarnedSpecs.add(projectDependency.versionSpecifier); + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `WARNING: Not validating ${projectDependency.specifierType}-based` + + ` specifier: "${projectDependency.versionSpecifier}"` + ) + ); + } + return true; + } + } +} diff --git a/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts b/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts new file mode 100644 index 00000000000..e3546d58ed5 --- /dev/null +++ b/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.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 { FileSystem } from '@rushstack/node-core-library'; + +export interface IWorkspaceFileSaveOptions { + /** + * If there is an existing file, and the contents have not changed, then + * don't write anything; this preserves the old timestamp. + */ + onlyIfChanged?: boolean; + + /** + * Creates the folder recursively using FileSystem.ensureFolder() + * Defaults to false. + */ + ensureFolderExists?: boolean; +} + +/** + * This class is a parser for pnpm's pnpm-workspace.yaml file format. + */ +export abstract class BaseWorkspaceFile { + protected _alreadyWarnedSpecs: Set = new Set(); + + /** + * Serializes and saves the workspace file to specified location + */ + public save(filePath: string, options: IWorkspaceFileSaveOptions): void { + // Do we need to read the previous file contents? + let oldBuffer: Buffer | undefined = undefined; + if (options.onlyIfChanged && FileSystem.exists(filePath)) { + try { + oldBuffer = FileSystem.readFileToBuffer(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 + + if (options.onlyIfChanged) { + // Has the file changed? + if (oldBuffer && Buffer.compare(newBuffer, oldBuffer) === 0) { + // Nothing has changed, so don't touch the file + return; + } + } + + FileSystem.writeFile(filePath, newBuffer.toString(), { + ensureFolderExists: options.ensureFolderExists + }); + } + + /** + * Adds a package path to the workspace file. + * + * @virtual + */ + public abstract addPackage(packagePath: string): void; + + /** @virtual */ + protected abstract serialize(): string; +} diff --git a/libraries/rush-lib/src/logic/buildCache/CacheEntryId.ts b/libraries/rush-lib/src/logic/buildCache/CacheEntryId.ts new file mode 100644 index 00000000000..893e9bb08a6 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/CacheEntryId.ts @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import process from 'node:process'; + +const OPTIONS_ARGUMENT_NAME: string = 'options'; + +/** + * Options for generating the cache id for an operation. + * @beta + */ +export interface IGenerateCacheEntryIdOptions { + /** + * The name of the project + */ + projectName: string; + /** + * The name of the phase + */ + phaseName: string; + /** + * A hash of the input files + */ + projectStateHash: string; +} + +/** + * Calculates the cache entry id string for an operation. + * @beta + */ +export type GetCacheEntryIdFunction = (options: IGenerateCacheEntryIdOptions) => string; + +// NOTE: When adding new tokens, make sure to document the syntax in the "rush init" +// template for build-cache.json +const HASH_TOKEN_NAME: 'hash' = 'hash'; +const PROJECT_NAME_TOKEN_NAME: 'projectName' = 'projectName'; +const PHASE_NAME_TOKEN_NAME: 'phaseName' = 'phaseName'; +const OS_TOKEN_NAME: 'os' = 'os'; +const ARCH_TOKEN_NAME: 'arch' = 'arch'; + +// This regex matches substrings that look like [token] +const TOKEN_REGEX: RegExp = /\[[^\]]*\]/g; + +export class CacheEntryId { + private constructor() {} + + public static parsePattern(pattern?: string): GetCacheEntryIdFunction { + if (!pattern) { + return ({ projectStateHash }) => projectStateHash; + } else { + pattern = pattern.trim(); + + if (pattern.startsWith('/')) { + throw new Error('Cache entry name patterns may not start with a slash.'); + } + + const patternWithoutTokens: string = pattern.replace(TOKEN_REGEX, ''); + if (patternWithoutTokens.match(/\]/)) { + throw new Error(`Unexpected "]" character in cache entry name pattern.`); + } + + if (patternWithoutTokens.match(/\[/)) { + throw new Error('Unclosed token in cache entry name pattern.'); + } + + if (!patternWithoutTokens.match(/^[A-z0-9-_\/]*$/)) { + throw new Error( + 'Cache entry name pattern contains an invalid character. ' + + 'Only alphanumeric characters, slashes, underscores, and hyphens are allowed.' + ); + } + + let foundHashToken: boolean = false; + const templateString: string = pattern.trim().replace(TOKEN_REGEX, (token: string) => { + token = token.substring(1, token.length - 1); + let tokenName: string; + let tokenAttribute: string | undefined; + const tokenSplitIndex: number = token.indexOf(':'); + if (tokenSplitIndex === -1) { + tokenName = token; + } else { + tokenName = token.substr(0, tokenSplitIndex); + tokenAttribute = token.substr(tokenSplitIndex + 1); + } + + switch (tokenName) { + case HASH_TOKEN_NAME: { + if (tokenAttribute !== undefined) { + throw new Error(`An attribute isn\'t supported for the "${tokenName}" token.`); + } + + foundHashToken = true; + return `\${${OPTIONS_ARGUMENT_NAME}.projectStateHash}`; + } + + case PROJECT_NAME_TOKEN_NAME: { + switch (tokenAttribute) { + case undefined: { + return `\${${OPTIONS_ARGUMENT_NAME}.projectName}`; + } + + case 'normalize': { + return `\${${OPTIONS_ARGUMENT_NAME}.projectName.replace('@','').replace(/\\+/g, '++').replace(/\\/\/g, '+')}`; + } + + default: { + throw new Error(`Unexpected attribute "${tokenAttribute}" for the "${tokenName}" token.`); + } + } + } + + case PHASE_NAME_TOKEN_NAME: { + switch (tokenAttribute) { + case undefined: { + throw new Error( + 'Either the "normalize" or the "trimPrefix" attribute is required ' + + `for the "${tokenName}" token.` + ); + } + + case 'normalize': { + // Replace colons with underscores. + return `\${${OPTIONS_ARGUMENT_NAME}.phaseName.replace(/:/g, '_')}`; + } + + case 'trimPrefix': { + // Trim the "_phase:" prefix from the phase name. + return `\${${OPTIONS_ARGUMENT_NAME}.phaseName.replace(/^_phase:/, '')}`; + } + + default: { + throw new Error(`Unexpected attribute "${tokenAttribute}" for the "${tokenName}" token.`); + } + } + } + + case OS_TOKEN_NAME: { + if (tokenAttribute !== undefined) { + throw new Error(`An attribute isn\'t supported for the "${tokenName}" token.`); + } + + return process.platform; + } + + case ARCH_TOKEN_NAME: { + if (tokenAttribute !== undefined) { + throw new Error(`An attribute isn\'t supported for the "${tokenName}" token.`); + } + + return process.arch; + } + + default: { + throw new Error(`Unexpected token name "${tokenName}".`); + } + } + }); + + if (!foundHashToken) { + throw new Error(`Cache entry name pattern is missing a [${HASH_TOKEN_NAME}] token.`); + } + + // eslint-disable-next-line no-new-func + return new Function( + OPTIONS_ARGUMENT_NAME, + `"use strict"\nreturn \`${templateString}\`;` + ) as GetCacheEntryIdFunction; + } + } +} diff --git a/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts b/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts new file mode 100644 index 00000000000..8fdd54bf444 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts @@ -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 * as path from 'node:path'; + +import { FileSystem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushUserConfiguration } from '../../api/RushUserConfiguration'; + +/** + * Options for creating a file system build cache provider. + * @beta + */ +export interface IFileSystemBuildCacheProviderOptions { + /** + * The workspace Rush configuration + */ + rushConfiguration: RushConfiguration; + /** + * The user Rush configuration + */ + rushUserConfiguration: RushUserConfiguration; +} + +const DEFAULT_BUILD_CACHE_FOLDER_NAME: string = 'build-cache'; + +/** + * A build cache provider using the local file system. + * Required by all cloud cache providers. + * @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); + } + + /** + * Validates that the specified cache id exists on disk, and returns the path if it does. + */ + public async tryGetCacheEntryPathByIdAsync( + terminal: ITerminal, + cacheId: string + ): Promise { + const cacheEntryFilePath: string = this.getCacheEntryPath(cacheId); + if (await FileSystem.existsAsync(cacheEntryFilePath)) { + return cacheEntryFilePath; + } else { + return undefined; + } + } + + /** + * Writes the specified buffer to the corresponding file system path for the cache id. + */ + public async trySetCacheEntryBufferAsync( + terminal: ITerminal, + cacheId: string, + entryBuffer: Buffer + ): Promise { + const cacheEntryFilePath: string = this.getCacheEntryPath(cacheId); + await FileSystem.writeFileAsync(cacheEntryFilePath, entryBuffer, { ensureFolderExists: true }); + terminal.writeVerboseLine(`Wrote cache entry to "${cacheEntryFilePath}".`); + return cacheEntryFilePath; + } +} diff --git a/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts b/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts new file mode 100644 index 00000000000..f55a0870ad8 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts @@ -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. + +import type { ITerminal } from '@rushstack/terminal'; + +/** + * @beta + */ +export interface ICloudBuildCacheProvider { + readonly isCacheWriteAllowed: boolean; + + tryGetCacheEntryBufferByIdAsync(terminal: ITerminal, cacheId: string): Promise; + trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): 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..7fbc065881d --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts @@ -0,0 +1,415 @@ +// 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 } 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 { IOperationExecutionResult } from '../operations/IOperationExecutionResult'; + +/** + * @internal + */ +export interface IOperationBuildCacheOptions { + /** + * The repo-wide configuration for the build cache. + */ + buildCacheConfiguration: BuildCacheConfiguration; + /** + * The terminal to use for logging. + */ + terminal: ITerminal; +} + +/** + * @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[]; +} + +/** + * @internal + */ +export class OperationBuildCache { + 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 (!OperationBuildCache._tarUtilityPromise) { + OperationBuildCache._tarUtilityPromise = TarExecutable.tryInitializeAsync(terminal); + } + + return OperationBuildCache._tarUtilityPromise; + } + + public get cacheId(): string | undefined { + return this._cacheId; + } + + public static getOperationBuildCache(options: IProjectBuildCacheOptions): OperationBuildCache { + const cacheId: string | undefined = OperationBuildCache._getCacheId(options); + return new OperationBuildCache(cacheId, options); + } + + public static forOperation( + executionResult: IOperationExecutionResult, + options: IOperationBuildCacheOptions + ): OperationBuildCache { + const outputFolders: string[] = [...(executionResult.operation.settings?.outputFolderNames ?? [])]; + if (executionResult.metadataFolderPath) { + outputFolders.push(executionResult.metadataFolderPath); + } + const buildCacheOptions: IProjectBuildCacheOptions = { + buildCacheConfiguration: options.buildCacheConfiguration, + terminal: options.terminal, + project: executionResult.operation.associatedProject, + phaseName: executionResult.operation.associatedPhase.name, + projectOutputFolderNames: outputFolders, + operationStateHash: executionResult.getStateHash() + }; + const cacheId: string | undefined = OperationBuildCache._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 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 OperationBuildCache._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 OperationBuildCache._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/CacheEntryId.test.ts b/libraries/rush-lib/src/logic/buildCache/test/CacheEntryId.test.ts new file mode 100644 index 00000000000..83e7c3afd1e --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/test/CacheEntryId.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. + +jest.mock('node:process', () => { + return { + ...jest.requireActual('node:process'), + platform: 'dummyplatform', + arch: 'dummyarch' + }; +}); + +import { CacheEntryId, type GetCacheEntryIdFunction } from '../CacheEntryId'; + +describe(CacheEntryId.name, () => { + describe('Valid pattern names', () => { + describe.each([ + { projectName: 'project+name', note: 'without a scope' }, + { projectName: '@scope/project+name', note: 'with a scope' } + ])('For a project name $note', ({ projectName }) => + it.each([ + undefined, + '[hash]', + '[projectName]_[hash]', + '[phaseName:normalize]_[hash]', + '[phaseName:trimPrefix]_[hash]', + '[projectName:normalize]_[hash]', + '[projectName:normalize]_[phaseName:normalize]_[hash]', + '[projectName:normalize]_[phaseName:normalize]_[hash]_[os]_[arch]', + '[projectName:normalize]_[phaseName:trimPrefix]_[hash]', + 'prefix/[projectName:normalize]_[hash]', + 'prefix/[projectName:normalize]_[phaseName:normalize]_[hash]', + 'prefix/[projectName:normalize]_[phaseName:trimPrefix]_[hash]', + 'prefix/[projectName]_[hash]', + 'prefix/[projectName]_[phaseName:normalize]_[hash]', + 'prefix/[projectName]_[phaseName:trimPrefix]_[hash]' + ])('Handles pattern %s', (pattern) => { + const getCacheEntryId: GetCacheEntryIdFunction = CacheEntryId.parsePattern(pattern); + expect( + getCacheEntryId({ + projectName, + projectStateHash: '09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3', + phaseName: '_phase:compile' + }) + ).toMatchSnapshot(); + }) + ); + }); + + describe('Invalid pattern names', () => { + it.each([ + 'x', + '[invalidTag]', + 'unstartedTag]', + '[incompleteTag', + '[hash:badAttribute]', + '[hash:badAttribute:attr2]', + '[projectName:badAttribute]', + '[projectName:]', + '[phaseName]', + '[phaseName:]', + '[phaseName:badAttribute]', + '[:attr1]', + '[projectName:attr1:attr2]', + '/[hash]', + '[os:attr]', + '[arch:attr]', + '~' + ])('Throws an exception for an invalid pattern (%s)', (pattern) => { + expect(() => CacheEntryId.parsePattern(pattern)).toThrowErrorMatchingSnapshot(); + }); + }); +}); 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..82606c11784 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/test/OperationBuildCache.test.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 { 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 { OperationBuildCache } from '../OperationBuildCache'; + +interface ITestOptions { + enabled: boolean; + writeAllowed: boolean; + trackedProjectFiles: string[] | undefined; +} + +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', + 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(OperationBuildCache.getOperationBuildCache.name, () => { + it('returns an OperationBuildCache with a calculated cacheId value', () => { + const subject: OperationBuildCache = 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 new file mode 100644 index 00000000000..13c71113290 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/test/__snapshots__/CacheEntryId.test.ts.snap @@ -0,0 +1,95 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern (/[hash]) 1`] = `"Cache entry name patterns may not start with a slash."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([:attr1]) 1`] = `"Unexpected token name \\"\\"."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([arch:attr]) 1`] = `"An attribute isn't supported for the \\"arch\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([hash:badAttribute:attr2]) 1`] = `"An attribute isn't supported for the \\"hash\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([hash:badAttribute]) 1`] = `"An attribute isn't supported for the \\"hash\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([incompleteTag) 1`] = `"Unclosed token in cache entry name pattern."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([invalidTag]) 1`] = `"Unexpected token name \\"invalidTag\\"."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([os:attr]) 1`] = `"An attribute isn't supported for the \\"os\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([phaseName:]) 1`] = `"Unexpected attribute \\"\\" for the \\"phaseName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([phaseName:badAttribute]) 1`] = `"Unexpected attribute \\"badAttribute\\" for the \\"phaseName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([phaseName]) 1`] = `"Either the \\"normalize\\" or the \\"trimPrefix\\" attribute is required for the \\"phaseName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([projectName:]) 1`] = `"Unexpected attribute \\"\\" for the \\"projectName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([projectName:attr1:attr2]) 1`] = `"Unexpected attribute \\"attr1:attr2\\" for the \\"projectName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern ([projectName:badAttribute]) 1`] = `"Unexpected attribute \\"badAttribute\\" for the \\"projectName\\" token."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern (~) 1`] = `"Cache entry name pattern contains an invalid character. Only alphanumeric characters, slashes, underscores, and hyphens are allowed."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern (unstartedTag]) 1`] = `"Unexpected \\"]\\" character in cache entry name pattern."`; + +exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern (x) 1`] = `"Cache entry name pattern is missing a [hash] token."`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [hash] 1`] = `"09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [phaseName:normalize]_[hash] 1`] = `"_phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [phaseName:trimPrefix]_[hash] 1`] = `"compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [projectName:normalize]_[hash] 1`] = `"scope+project++name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [projectName:normalize]_[phaseName:normalize]_[hash] 1`] = `"scope+project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [projectName:normalize]_[phaseName:normalize]_[hash]_[os]_[arch] 1`] = `"scope+project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3_dummyplatform_dummyarch"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [projectName:normalize]_[phaseName:trimPrefix]_[hash] 1`] = `"scope+project++name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern [projectName]_[hash] 1`] = `"@scope/project+name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName:normalize]_[hash] 1`] = `"prefix/scope+project++name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName:normalize]_[phaseName:normalize]_[hash] 1`] = `"prefix/scope+project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName:normalize]_[phaseName:trimPrefix]_[hash] 1`] = `"prefix/scope+project++name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName]_[hash] 1`] = `"prefix/@scope/project+name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName]_[phaseName:normalize]_[hash] 1`] = `"prefix/@scope/project+name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern prefix/[projectName]_[phaseName:trimPrefix]_[hash] 1`] = `"prefix/@scope/project+name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name with a scope Handles pattern undefined 1`] = `"09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [hash] 1`] = `"09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [phaseName:normalize]_[hash] 1`] = `"_phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [phaseName:trimPrefix]_[hash] 1`] = `"compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [projectName:normalize]_[hash] 1`] = `"project++name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [projectName:normalize]_[phaseName:normalize]_[hash] 1`] = `"project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [projectName:normalize]_[phaseName:normalize]_[hash]_[os]_[arch] 1`] = `"project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3_dummyplatform_dummyarch"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [projectName:normalize]_[phaseName:trimPrefix]_[hash] 1`] = `"project++name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern [projectName]_[hash] 1`] = `"project+name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName:normalize]_[hash] 1`] = `"prefix/project++name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName:normalize]_[phaseName:normalize]_[hash] 1`] = `"prefix/project++name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName:normalize]_[phaseName:trimPrefix]_[hash] 1`] = `"prefix/project++name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName]_[hash] 1`] = `"prefix/project+name_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName]_[phaseName:normalize]_[hash] 1`] = `"prefix/project+name__phase_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern prefix/[projectName]_[phaseName:trimPrefix]_[hash] 1`] = `"prefix/project+name_compile_09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; + +exports[`CacheEntryId Valid pattern names For a project name without a scope Handles pattern undefined 1`] = `"09d1ecee6d5f888fa6c35ca804b5dac7c3735ce3"`; diff --git a/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts b/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts new file mode 100644 index 00000000000..9dbf7114c3d --- /dev/null +++ b/libraries/rush-lib/src/logic/cobuild/CobuildLock.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 { 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 { OperationBuildCache } from '../buildCache/OperationBuildCache'; + +const KEY_SEPARATOR: ':' = ':'; + +export interface ICobuildLockOptions { + /** + * {@inheritdoc CobuildConfiguration} + */ + cobuildConfiguration: CobuildConfiguration; + /** + * {@inheritdoc ICobuildContext.clusterId} + */ + cobuildClusterId: string; + /** + * {@inheritdoc ICobuildContext.packageName} + */ + packageName: string; + /** + * {@inheritdoc ICobuildContext.phaseName} + */ + phaseName: string; + operationBuildCache: OperationBuildCache; + /** + * The expire time of the lock in seconds. + */ + lockExpireTimeInSeconds: number; +} + +export interface ICobuildCompletedState { + status: OperationStatus.Success | OperationStatus.SuccessWithWarning | OperationStatus.Failure; + cacheId: string; +} + +export class CobuildLock { + public readonly cobuildConfiguration: CobuildConfiguration; + public readonly operationBuildCache: OperationBuildCache; + + private _cobuildContext: ICobuildContext; + + public constructor(options: ICobuildLockOptions) { + const { + cobuildConfiguration, + operationBuildCache, + cobuildClusterId: clusterId, + lockExpireTimeInSeconds, + packageName, + phaseName + } = options; + const { cobuildContextId: contextId, cobuildRunnerId: runnerId } = cobuildConfiguration; + const { cacheId } = operationBuildCache; + this.cobuildConfiguration = cobuildConfiguration; + this.operationBuildCache = operationBuildCache; + + if (!cacheId) { + // This should never happen + throw new InternalError(`Cache id is require for cobuild lock`); + } + + if (!contextId) { + // This should never happen + throw new InternalError(`Cobuild context id is require for cobuild lock`); + } + + // Example: cobuild:lock:: + const lockKey: string = ['cobuild', 'lock', contextId, clusterId].join(KEY_SEPARATOR); + + // Example: cobuild:completed:: + const completedStateKey: string = ['cobuild', 'completed', contextId, cacheId].join(KEY_SEPARATOR); + + this._cobuildContext = { + contextId, + clusterId, + runnerId, + lockKey, + completedStateKey, + packageName, + phaseName, + lockExpireTimeInSeconds: lockExpireTimeInSeconds, + cacheId + }; + } + + public async setCompletedStateAsync(state: ICobuildCompletedState): Promise { + await this.cobuildConfiguration + .getCobuildLockProvider() + .setCompletedStateAsync(this._cobuildContext, state); + } + + public async getCompletedStateAsync(): Promise { + const state: ICobuildCompletedState | undefined = await this.cobuildConfiguration + .getCobuildLockProvider() + .getCompletedStateAsync(this._cobuildContext); + return state; + } + + public async tryAcquireLockAsync(): Promise { + const acquireLockResult: boolean = await this.cobuildConfiguration + .getCobuildLockProvider() + .acquireLockAsync(this._cobuildContext); + if (acquireLockResult) { + // renew the lock in a redundant way in case of losing the lock + await this.renewLockAsync(); + } + return acquireLockResult; + } + + public async renewLockAsync(): Promise { + await this.cobuildConfiguration.getCobuildLockProvider().renewLockAsync(this._cobuildContext); + } + + public get cobuildContext(): ICobuildContext { + return this._cobuildContext; + } +} diff --git a/libraries/rush-lib/src/logic/cobuild/DisjointSet.ts b/libraries/rush-lib/src/logic/cobuild/DisjointSet.ts new file mode 100644 index 00000000000..3a33aef59ae --- /dev/null +++ b/libraries/rush-lib/src/logic/cobuild/DisjointSet.ts @@ -0,0 +1,120 @@ +// 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'; + +/** + * A disjoint set data structure + */ +export class DisjointSet { + private _forest: Set; + private _parentMap: Map; + private _sizeMap: Map; + private _setByElement: Map> | undefined; + + public constructor() { + this._forest = new Set(); + this._parentMap = new Map(); + this._sizeMap = new Map(); + this._setByElement = new Map>(); + } + + public destroy(): void { + this._forest.clear(); + this._parentMap.clear(); + this._sizeMap.clear(); + this._setByElement?.clear(); + } + + /** + * Adds a new set containing specific object + */ + public add(x: T): void { + if (this._forest.has(x)) { + return; + } + + this._forest.add(x); + this._parentMap.set(x, x); + this._sizeMap.set(x, 1); + this._setByElement = undefined; + } + + /** + * Unions the sets that contain two objects + */ + public union(a: T, b: T): void { + let x: T = this._find(a); + let y: T = this._find(b); + + if (x === y) { + // x and y are already in the same set + return; + } + + const xSize: number = this._getSize(x); + const ySize: number = this._getSize(y); + if (xSize < ySize) { + const t: T = x; + x = y; + y = t; + } + this._parentMap.set(y, x); + this._sizeMap.set(x, xSize + ySize); + this._setByElement = undefined; + } + + public getAllSets(): Iterable> { + if (this._setByElement === undefined) { + this._setByElement = new Map>(); + + for (const element of this._forest) { + const root: T = this._find(element); + let set: Set | undefined = this._setByElement.get(root); + if (set === undefined) { + set = new Set(); + this._setByElement.set(root, set); + } + set.add(element); + } + } + return this._setByElement.values(); + } + + /** + * Returns true if x and y are in the same set + */ + public isConnected(x: T, y: T): boolean { + return this._find(x) === this._find(y); + } + + private _find(a: T): T { + let x: T = a; + let parent: T = this._getParent(x); + while (parent !== x) { + parent = this._getParent(parent); + this._parentMap.set(x, parent); + x = parent; + parent = this._getParent(x); + } + return x; + } + + private _getParent(x: T): T { + const parent: T | undefined = this._parentMap.get(x); + if (parent === undefined) { + // This should not happen + throw new InternalError(`Can not find parent`); + } + return parent; + } + + private _getSize(x: T): number { + const size: number | undefined = this._sizeMap.get(x); + if (size === undefined) { + // This should not happen + throw new InternalError(`Can not get size`); + } + return size; + } +} diff --git a/libraries/rush-lib/src/logic/cobuild/ICobuildLockProvider.ts b/libraries/rush-lib/src/logic/cobuild/ICobuildLockProvider.ts new file mode 100644 index 00000000000..027d8556a0c --- /dev/null +++ b/libraries/rush-lib/src/logic/cobuild/ICobuildLockProvider.ts @@ -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. + +import type { OperationStatus } from '../operations/OperationStatus'; + +/** + * @beta + */ +export interface ICobuildContext { + /** + * The key for acquiring lock. + */ + lockKey: string; + /** + * The expire time of the lock in seconds. + */ + lockExpireTimeInSeconds: number; + /** + * The key for storing completed state. + */ + completedStateKey: string; + /** + * The contextId is provided by the monorepo maintainer, it reads from environment variable {@link EnvironmentVariableNames.RUSH_COBUILD_CONTEXT_ID}. + * It ensure only the builds from the same given contextId cooperated. + */ + contextId: string; + /** + * The id of the cluster. The operations in the same cluster share the same clusterId and + * will be executed on the same machine. + */ + clusterId: string; + /** + * The id of the runner. The identifier for the running machine. + * + * It can be specified via assigning `RUSH_COBUILD_RUNNER_ID` environment variable. + */ + runnerId: string; + /** + * The id of the cache entry. It should be kept the same as the normal cacheId from ProjectBuildCache. + * Otherwise, there is a discrepancy in the success case wherein turning on cobuilds will + * fail to populate the normal build cache. + */ + cacheId: string; + /** + * The name of NPM package + * + * Example: `@scope/MyProject` + */ + packageName: string; + /** + * The name of the phase. + * + * Example: _phase:build + */ + phaseName: string; +} + +/** + * @beta + */ +export interface ICobuildCompletedState { + status: OperationStatus.Success | OperationStatus.SuccessWithWarning | OperationStatus.Failure; + /** + * Completed state points to the cache id that was used to store the build cache. + * Note: Cache failed builds in a separate cache id + */ + cacheId: string; +} + +/** + * @beta + */ +export interface ICobuildLockProvider { + /** + * The callback function invoked to connect to the lock provider. + * For example, initializing the connection to the redis server. + */ + connectAsync(): Promise; + /** + * The callback function invoked to disconnect the lock provider. + */ + disconnectAsync(): Promise; + /** + * The callback function to acquire a lock with a lock key and specific contexts. + * + * NOTE: This lock implementation must be a ReentrantLock. It says the lock might be acquired + * multiple times, since tasks in the same cluster can be run in the same VM. + */ + acquireLockAsync(context: Readonly): Promise; + /** + * The callback function to renew a lock with a lock key and specific contexts. + * + * NOTE: If the lock key expired + */ + renewLockAsync(context: Readonly): Promise; + /** + * The callback function to set completed state. + */ + setCompletedStateAsync(context: Readonly, state: ICobuildCompletedState): Promise; + /** + * The callback function to get completed state. + */ + getCompletedStateAsync(context: Readonly): Promise; +} diff --git a/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts b/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts new file mode 100644 index 00000000000..bde478c4919 --- /dev/null +++ b/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.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 { CobuildLock, type ICobuildLockOptions } from '../CobuildLock'; + +import type { CobuildConfiguration } from '../../../api/CobuildConfiguration'; +import type { OperationBuildCache } from '../../buildCache/OperationBuildCache'; +import type { ICobuildContext } from '../ICobuildLockProvider'; + +describe(CobuildLock.name, () => { + function prepareSubject(): CobuildLock { + const cobuildLockOptions: ICobuildLockOptions = { + cobuildConfiguration: { + cobuildContextId: 'context_id', + cobuildRunnerId: 'runner_id' + } as unknown as CobuildConfiguration, + operationBuildCache: { + cacheId: 'cache_id' + } as unknown as OperationBuildCache, + cobuildClusterId: 'cluster_id', + lockExpireTimeInSeconds: 30, + packageName: 'package_name', + phaseName: 'phase_name' + }; + const subject: CobuildLock = new CobuildLock(cobuildLockOptions); + return subject; + } + it('returns cobuild context', () => { + const subject: CobuildLock = prepareSubject(); + const expected: ICobuildContext = { + lockKey: 'cobuild:lock:context_id:cluster_id', + completedStateKey: 'cobuild:completed:context_id:cache_id', + lockExpireTimeInSeconds: 30, + contextId: 'context_id', + cacheId: 'cache_id', + clusterId: 'cluster_id', + runnerId: 'runner_id', + packageName: 'package_name', + phaseName: 'phase_name' + }; + expect(subject.cobuildContext).toEqual(expected); + }); +}); diff --git a/libraries/rush-lib/src/logic/cobuild/test/DisjointSet.test.ts b/libraries/rush-lib/src/logic/cobuild/test/DisjointSet.test.ts new file mode 100644 index 00000000000..56bb80695d5 --- /dev/null +++ b/libraries/rush-lib/src/logic/cobuild/test/DisjointSet.test.ts @@ -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. + +import { DisjointSet } from '../DisjointSet'; + +describe(DisjointSet.name, () => { + it('can disjoint two sets', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + + expect(disjointSet.isConnected(obj1, obj2)).toBe(false); + }); + + it('can disjoint multiple sets', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + const obj3 = { id: 3 }; + const obj4 = { id: 4 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + disjointSet.add(obj3); + disjointSet.add(obj4); + + expect(disjointSet.isConnected(obj1, obj2)).toBe(false); + expect(disjointSet.isConnected(obj1, obj3)).toBe(false); + expect(disjointSet.isConnected(obj1, obj4)).toBe(false); + }); + + it('can union two sets', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + expect(disjointSet.isConnected(obj1, obj2)).toBe(false); + + disjointSet.union(obj1, obj2); + expect(disjointSet.isConnected(obj1, obj2)).toBe(true); + }); + + it('can union two sets transitively', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + const obj3 = { id: 3 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + disjointSet.add(obj3); + + disjointSet.union(obj1, obj2); + expect(disjointSet.isConnected(obj1, obj2)).toBe(true); + expect(disjointSet.isConnected(obj1, obj3)).toBe(false); + expect(disjointSet.isConnected(obj2, obj3)).toBe(false); + + disjointSet.union(obj1, obj3); + expect(disjointSet.isConnected(obj1, obj2)).toBe(true); + expect(disjointSet.isConnected(obj2, obj3)).toBe(true); + expect(disjointSet.isConnected(obj1, obj3)).toBe(true); + }); + + it('can union and disjoint sets', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + const obj3 = { id: 3 }; + const obj4 = { id: 4 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + disjointSet.add(obj3); + disjointSet.add(obj4); + + expect(disjointSet.isConnected(obj1, obj2)).toBe(false); + expect(disjointSet.isConnected(obj1, obj3)).toBe(false); + expect(disjointSet.isConnected(obj1, obj4)).toBe(false); + + disjointSet.union(obj1, obj2); + expect(disjointSet.isConnected(obj1, obj2)).toBe(true); + expect(disjointSet.isConnected(obj1, obj3)).toBe(false); + expect(disjointSet.isConnected(obj1, obj4)).toBe(false); + }); + + it('can get all sets', () => { + const disjointSet = new DisjointSet<{ id: number }>(); + const obj1 = { id: 1 }; + const obj2 = { id: 2 }; + const obj3 = { id: 3 }; + disjointSet.add(obj1); + disjointSet.add(obj2); + disjointSet.add(obj3); + + disjointSet.union(obj1, obj2); + + const allSets: Iterable> = disjointSet.getAllSets(); + + const allSetList: Array> = []; + for (const set of allSets) { + allSetList.push(set); + } + + expect(allSetList.length).toBe(2); + expect(Array.from(allSetList[0]).map((x) => x.id)).toEqual(expect.arrayContaining([1, 2])); + expect(Array.from(allSetList[1]).map((x) => x.id)).toEqual(expect.arrayContaining([3])); + }); +}); diff --git a/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts b/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts new file mode 100644 index 00000000000..c4d6f0c1cfd --- /dev/null +++ b/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.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 * as path from 'node:path'; + +import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import schemaJson from '../../schemas/deploy-scenario.schema.json'; +import { RushConstants } from '../RushConstants'; + +// Describes IDeployScenarioJson.projectSettings +export interface IDeployScenarioProjectJson { + projectName: string; + additionalProjectsToInclude?: string[]; + additionalDependenciesToInclude?: string[]; + dependenciesToExclude?: string[]; + patternsToInclude?: string[]; + patternsToExclude?: string[]; +} + +export interface IDeployScenarioDependencyJson { + dependencyName: string; + dependencyVersionRange: string; + patternsToExclude?: string[]; + patternsToInclude?: string[]; +} + +// The parsed JSON file structure, as defined by the "deploy-scenario.schema.json" JSON schema +export interface IDeployScenarioJson { + deploymentProjectNames: string[]; + includeDevDependencies?: boolean; + includeNpmIgnoreFiles?: boolean; + omitPnpmWorkaroundLinks?: boolean; + linkCreation?: 'default' | 'script' | 'none'; + folderToCopy?: string; + projectSettings?: IDeployScenarioProjectJson[]; + 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]+)*$/; + + private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + public readonly json: IDeployScenarioJson; + + /** + * Used to lookup items in IDeployScenarioJson.projectSettings based on their IDeployScenarioProjectJson.projectName + */ + public readonly projectJsonsByName: Map; + + private constructor( + json: IDeployScenarioJson, + projectJsonsByName: Map + ) { + this.json = json; + this.projectJsonsByName = projectJsonsByName; + } + + /** + * Validates that the input string conforms to the naming rules for a "rush deploy" scenario name. + */ + public static validateScenarioName(scenarioName: string): void { + if (!scenarioName) { + throw new Error('The scenario name cannot be an empty string'); + } + if (!this._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"' + ); + } + } + + /** + * Given the --scenarioName value, return the full path of the filename. + * + * Example: "ftp-site" --> "...common/config/rush/deploy-ftp-site.json" + * Example: undefined --> "...common/config/rush/deploy.json" + */ + public static getConfigFilePath( + scenarioName: string | undefined, + rushConfiguration: RushConfiguration + ): string { + let scenarioFileName: string; + if (scenarioName) { + DeployScenarioConfiguration.validateScenarioName(scenarioName); + scenarioFileName = `deploy-${scenarioName}.json`; + } else { + scenarioFileName = `deploy.json`; + } + + return path.join(rushConfiguration.commonRushConfigFolder, scenarioFileName); + } + + public static loadFromFile( + terminal: ITerminal, + scenarioFilePath: string, + rushConfiguration: RushConfiguration + ): DeployScenarioConfiguration { + if (!FileSystem.exists(scenarioFilePath)) { + throw new Error('The scenario config file was not found: ' + scenarioFilePath); + } + + terminal.writeLine(Colorize.cyan(`Loading deployment scenario: ${scenarioFilePath}`)); + + const deployScenarioJson: IDeployScenarioJson = JsonFile.loadAndValidate( + scenarioFilePath, + DeployScenarioConfiguration._jsonSchema + ); + + // Apply the defaults + if (!deployScenarioJson.linkCreation) { + deployScenarioJson.linkCreation = 'default'; + } + + const deployScenarioProjectJsonsByName: Map = new Map(); + + for (const projectSetting of deployScenarioJson.projectSettings || []) { + // Validate projectSetting.projectName + if (!rushConfiguration.getProjectByName(projectSetting.projectName)) { + throw new Error( + `The "projectSettings" section refers to the project name "${projectSetting.projectName}"` + + ` which was not found in ${RushConstants.rushJsonFilename}` + ); + } + for (const additionalProjectsToInclude of projectSetting.additionalProjectsToInclude || []) { + if (!rushConfiguration.getProjectByName(projectSetting.projectName)) { + throw new Error( + `The "additionalProjectsToInclude" setting refers to the` + + ` project name "${additionalProjectsToInclude}" which was not found in ${RushConstants.rushJsonFilename}` + ); + } + } + deployScenarioProjectJsonsByName.set(projectSetting.projectName, projectSetting); + } + return new DeployScenarioConfiguration(deployScenarioJson, deployScenarioProjectJsonsByName); + } +} 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 new file mode 100644 index 00000000000..8eeaa5ed224 --- /dev/null +++ b/libraries/rush-lib/src/logic/incremental/InputsSnapshot.ts @@ -0,0 +1,468 @@ +// 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 { createHash, type Hash } from 'node:crypto'; + +import ignore, { type Ignore } from 'ignore'; + +import { type IReadonlyLookupByPath, LookupByPath } from '@rushstack/lookup-by-path'; +import { InternalError, Path, Sort } from '@rushstack/node-core-library'; + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration'; +import { RushConstants } from '../RushConstants'; + +/** + * @beta + */ +export type IRushConfigurationProjectForSnapshot = Pick< + RushConfigurationProject, + 'projectFolder' | 'projectRelativeFolder' +>; + +/** + * @internal + */ +export interface IInputsSnapshotProjectMetadata { + /** + * The contents of rush-project.json for the project, if available + */ + projectConfig?: RushProjectConfiguration; + /** + * A map of operation name to additional files that should be included in the hash for that operation. + */ + additionalFilesByOperationName?: ReadonlyMap>; +} + +interface IInternalInputsSnapshotProjectMetadata extends IInputsSnapshotProjectMetadata { + /** + * Cached filter of files that are not ignored by the project's `incrementalBuildIgnoredGlobs`. + * @param filePath - The path to the file to check + * @returns true if the file path is an input to all operations in the project, false otherwise + */ + projectFilePathFilter?: (filePath: string) => boolean; + /** + * The cached Git hashes for all files in the project folder. + */ + hashes: Map; + /** + * Cached hashes for all files in the project folder, including additional files. + * Upon calculating this map, input-output file collisions are detected. + */ + fileHashesByOperationName: Map>; + /** + * The flattened state hash for each operation name, where the key "undefined" represents no particular operation. + */ + hashByOperationName: Map; + /** + * The project relative folder, which is a prefix in all relative paths. + */ + relativePrefix: string; +} + +export type IRushSnapshotProjectMetadataMap = ReadonlyMap< + IRushConfigurationProjectForSnapshot, + IInputsSnapshotProjectMetadata +>; + +/** + * Function that computes a new snapshot of the current state of the repository as of the current moment. + * Rush-level configuration state will have been bound during creation of the function. + * Captures the state of the environment, tracked files, and additional files. + * + * @beta + */ +export type GetInputsSnapshotAsyncFn = () => Promise; + +/** + * The parameters for constructing an {@link InputsSnapshot}. + * @internal + */ +export interface IInputsSnapshotParameters { + /** + * Hashes for files selected by `dependsOnAdditionalFiles`. + * Separated out to prevent being auto-assigned to a project. + */ + additionalHashes?: ReadonlyMap; + /** + * The environment to use for `dependsOnEnvVars`. By default performs a snapshot of process.env upon construction. + * @defaultValue \{ ...process.env \} + */ + environment?: Record; + /** + * File paths (keys into additionalHashes or hashes) to be included as part of every operation's dependencies. + */ + globalAdditionalFiles?: Iterable; + /** + * 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. + */ + lookupByPath: IReadonlyLookupByPath; + /** + * Metadata for each project. + */ + projectMap: IRushSnapshotProjectMetadataMap; + /** + * The directory that all relative paths are relative to. + */ + rootDir: string; +} + +const { hashDelimiter } = RushConstants; + +/** + * Represents a synchronously-queryable in-memory snapshot of the state of the inputs to a Rush repository. + * + * The methods on this interface are idempotent and will return the same result regardless of when they are executed. + * @beta + */ +export interface IInputsSnapshot { + /** + * The raw hashes of all tracked files in the repository. + */ + readonly hashes: ReadonlyMap; + + /** + * The directory that all paths in `hashes` are relative to. + */ + 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. + * + * @param project - The Rush project to get hashes for + * @param operationName - The name of the operation (phase) to get hashes for. If omitted, returns a default set for the project, as used for bulk commands. + * @returns A map of file name to Git hash. For local files paths will be relative. Configured additional files may be absolute paths. + */ + getTrackedFileHashesForOperation( + project: IRushConfigurationProjectForSnapshot, + operationName?: string + ): ReadonlyMap; + + /** + * Gets the state hash for the files owned by this operation, including the resolutions of package.json dependencies. This will later be combined with the hash of + * the command being executed and the final hashes of the operation's dependencies to compute the final hash for the operation. + * @param project - The Rush project to compute the state hash for + * @param operationName - The name of the operation (phase) to get hashes for. If omitted, returns a generic hash for the whole project, as used for bulk commands. + * @returns The local state hash for the project. This is a hash of the environment, the project's tracked files, and any additional files. + */ + getOperationOwnStateHash(project: IRushConfigurationProjectForSnapshot, operationName?: string): string; +} + +/** + * Represents a synchronously-queryable in-memory snapshot of the state of the inputs to a Rush repository. + * Any asynchronous work needs to be performed by the caller and the results passed to the constructor. + * + * @remarks + * All operations on this class will return the same result regardless of when they are executed. + * + * @internal + */ +export class InputsSnapshot implements IInputsSnapshot { + /** + * {@inheritdoc IInputsSnapshot.hashes} + */ + public readonly hashes: ReadonlyMap; + /** + * {@inheritdoc IInputsSnapshot.hasUncommittedChanges} + */ + public readonly hasUncommittedChanges: boolean; + /** + * {@inheritdoc IInputsSnapshot.rootDirectory} + */ + public readonly rootDirectory: string; + + /** + * The metadata for each project. This is a superset of the information in `projectMap` and includes caching of queries. + */ + private readonly _projectMetadataMap: Map< + IRushConfigurationProjectForSnapshot, + IInternalInputsSnapshotProjectMetadata + >; + /** + * Hashes of files to be included in all result sets. + */ + private readonly _globalAdditionalHashes: ReadonlyMap | undefined; + /** + * Hashes for files selected by `dependsOnAdditionalFiles`. + */ + private readonly _additionalHashes: ReadonlyMap | undefined; + /** + * The environment to use for `dependsOnEnvVars`. + */ + private readonly _environment: Record; + + /** + * + * @param params - The parameters for the snapshot + * @internal + */ + public constructor(params: IInputsSnapshotParameters) { + const { + additionalHashes, + environment = { ...process.env }, + globalAdditionalFiles, + hashes, + hasUncommittedChanges, + lookupByPath, + rootDir + } = params; + const projectMetadataMap: Map< + IRushConfigurationProjectForSnapshot, + IInternalInputsSnapshotProjectMetadata + > = new Map(); + for (const [project, record] of params.projectMap) { + projectMetadataMap.set(project, createInternalRecord(project, record, rootDir)); + } + + // Route hashes to individual projects + for (const [file, hash] of hashes) { + const project: IRushConfigurationProjectForSnapshot | undefined = lookupByPath.findChildPath(file); + if (!project) { + continue; + } + + let record: IInternalInputsSnapshotProjectMetadata | undefined = projectMetadataMap.get(project); + if (!record) { + projectMetadataMap.set(project, (record = createInternalRecord(project, undefined, rootDir))); + } + + record.hashes.set(file, hash); + } + + let globalAdditionalHashes: Map | undefined; + if (globalAdditionalFiles) { + globalAdditionalHashes = new Map(); + const sortedAdditionalFiles: string[] = Array.from(globalAdditionalFiles).sort(); + for (const file of sortedAdditionalFiles) { + const hash: string | undefined = hashes.get(file); + if (!hash) { + throw new Error(`Hash not found for global file: "${file}"`); + } + const owningProject: IRushConfigurationProjectForSnapshot | undefined = + lookupByPath.findChildPath(file); + if (owningProject) { + throw new InternalError( + `Requested global additional file "${file}" is owned by project in "${owningProject.projectRelativeFolder}". Declare a project dependency instead.` + ); + } + globalAdditionalHashes.set(file, hash); + } + } + + for (const record of projectMetadataMap.values()) { + // Ensure stable ordering. + Sort.sortMapKeys(record.hashes); + } + + this._projectMetadataMap = projectMetadataMap; + this._additionalHashes = additionalHashes; + this._globalAdditionalHashes = globalAdditionalHashes; + // Snapshot the environment so that queries are not impacted by when they happen + this._environment = environment; + this.hashes = hashes; + this.hasUncommittedChanges = hasUncommittedChanges; + this.rootDirectory = rootDir; + } + + /** + * {@inheritdoc} + */ + public getTrackedFileHashesForOperation( + project: IRushConfigurationProjectForSnapshot, + operationName?: string + ): ReadonlyMap { + const record: IInternalInputsSnapshotProjectMetadata | undefined = this._projectMetadataMap.get(project); + if (!record) { + throw new InternalError(`No information available for project at ${project.projectFolder}`); + } + + const { fileHashesByOperationName } = record; + let hashes: Map | undefined = fileHashesByOperationName.get(operationName); + if (!hashes) { + hashes = new Map(); + fileHashesByOperationName.set(operationName, hashes); + // TODO: Support incrementalBuildIgnoredGlobs per-operation + const filter: (filePath: string) => boolean = getOrCreateProjectFilter(record); + + let outputValidator: LookupByPath | undefined; + + if (operationName) { + const operationSettings: Readonly | undefined = + record.projectConfig?.operationSettingsByOperationName.get(operationName); + + const outputFolderNames: string[] | undefined = operationSettings?.outputFolderNames; + if (outputFolderNames) { + const { relativePrefix } = record; + outputValidator = new LookupByPath(); + for (const folderName of outputFolderNames) { + outputValidator.setItem(`${relativePrefix}/${folderName}`, folderName); + } + } + + // Hash any additional files (files outside of a project, untracked project files, or even files outside of the repository) + const additionalFilesForOperation: ReadonlySet | undefined = + record.additionalFilesByOperationName?.get(operationName); + if (additionalFilesForOperation) { + for (const [filePath, hash] of this._resolveHashes(additionalFilesForOperation)) { + hashes.set(filePath, hash); + } + } + } + + const { _globalAdditionalHashes: globalAdditionalHashes } = this; + if (globalAdditionalHashes) { + for (const [file, hash] of globalAdditionalHashes) { + record.hashes.set(file, hash); + } + } + + // Hash the base project files + for (const [filePath, hash] of record.hashes) { + if (filter(filePath)) { + hashes.set(filePath, hash); + } + + // Ensure that the configured output folders for this operation do not contain any input files + // This should be reworked to operate on a global file origin map to ensure a hashed input + // is not a declared output of *any* operation. + const outputMatch: string | undefined = outputValidator?.findChildPath(filePath); + if (outputMatch) { + throw new Error( + `Configured output folder "${outputMatch}" for operation "${operationName}" in project "${project.projectRelativeFolder}" contains tracked input file "${filePath}".` + + ` 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.` + ); + } + } + } + + return hashes; + } + + /** + * {@inheritdoc} + */ + public getOperationOwnStateHash( + project: IRushConfigurationProjectForSnapshot, + operationName?: string + ): string { + const record: IInternalInputsSnapshotProjectMetadata | undefined = this._projectMetadataMap.get(project); + if (!record) { + throw new Error(`No information available for project at ${project.projectFolder}`); + } + + const { hashByOperationName } = record; + let hash: string | undefined = hashByOperationName.get(operationName); + if (!hash) { + const hashes: ReadonlyMap = this.getTrackedFileHashesForOperation( + project, + operationName + ); + + const hasher: Hash = createHash('sha1'); + // If this is for a specific operation, apply operation-specific options + if (operationName) { + const operationSettings: Readonly | undefined = + record.projectConfig?.operationSettingsByOperationName.get(operationName); + if (operationSettings) { + const { dependsOnEnvVars, 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. + for (const envVar of dependsOnEnvVars) { + hasher.update(`${hashDelimiter}$${envVar}=${this._environment[envVar] || ''}`); + } + } + + if (outputFolderNames) { + hasher.update(`${hashDelimiter}${JSON.stringify(outputFolderNames)}`); + } + } + } + + // Hash the base project files + for (const [filePath, fileHash] of hashes) { + hasher.update(`${hashDelimiter}${filePath}${hashDelimiter}${fileHash}`); + } + + hash = hasher.digest('hex'); + + hashByOperationName.set(operationName, hash); + } + + return hash; + } + + private *_resolveHashes(filePaths: Iterable): Generator<[string, string]> { + const { hashes, _additionalHashes } = this; + + for (const filePath of filePaths) { + const hash: string | undefined = hashes.get(filePath) ?? _additionalHashes?.get(filePath); + if (!hash) { + throw new Error(`Could not find hash for file path "${filePath}"`); + } + yield [filePath, hash]; + } + } +} + +function getOrCreateProjectFilter( + record: IInternalInputsSnapshotProjectMetadata +): (filePath: string) => boolean { + if (!record.projectFilePathFilter) { + const ignoredGlobs: readonly string[] | undefined = record.projectConfig?.incrementalBuildIgnoredGlobs; + if (!ignoredGlobs || ignoredGlobs.length === 0) { + record.projectFilePathFilter = noopFilter; + } else { + const ignorer: Ignore = ignore(); + ignorer.add(ignoredGlobs as string[]); + const prefixLength: number = record.relativePrefix.length + 1; + record.projectFilePathFilter = function projectFilePathFilter(filePath: string): boolean { + return !ignorer.ignores(filePath.slice(prefixLength)); + }; + } + } + + return record.projectFilePathFilter; +} + +function createInternalRecord( + project: IRushConfigurationProjectForSnapshot, + baseRecord: IInputsSnapshotProjectMetadata | undefined, + rootDir: string +): IInternalInputsSnapshotProjectMetadata { + return { + // Data from the caller + projectConfig: baseRecord?.projectConfig, + additionalFilesByOperationName: baseRecord?.additionalFilesByOperationName, + + // Caches + hashes: new Map(), + hashByOperationName: new Map(), + fileHashesByOperationName: new Map(), + relativePrefix: getRelativePrefix(project, rootDir) + }; +} + +function getRelativePrefix(project: IRushConfigurationProjectForSnapshot, rootDir: string): string { + return Path.convertToSlashes(path.relative(rootDir, project.projectFolder)); +} + +function noopFilter(filePath: string): boolean { + return true; +} diff --git a/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts b/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts new file mode 100644 index 00000000000..867a1f446f9 --- /dev/null +++ b/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts @@ -0,0 +1,470 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { LookupByPath } from '@rushstack/lookup-by-path'; + +import type { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; +import { + InputsSnapshot, + type IInputsSnapshotParameters, + type IRushConfigurationProjectForSnapshot +} from '../InputsSnapshot'; + +describe(InputsSnapshot.name, () => { + function getTestConfig(): { + project: IRushConfigurationProjectForSnapshot; + options: IInputsSnapshotParameters; + } { + const project: IRushConfigurationProjectForSnapshot = { + projectFolder: '/root/a', + projectRelativeFolder: 'a' + }; + + return { + project, + options: { + rootDir: '/root', + additionalHashes: new Map([['/ext/config.json', 'hash4']]), + hashes: new Map([ + ['a/file1.js', 'hash1'], + ['a/file2.js', 'hash2'], + ['a/lib/file3.js', 'hash3'], + ['common/config/some-config.json', 'hash5'] + ]), + hasUncommittedChanges: false, + lookupByPath: new LookupByPath([[project.projectRelativeFolder, project]]), + projectMap: new Map() + } + }; + } + + function getTrivialSnapshot(): { + project: IRushConfigurationProjectForSnapshot; + input: InputsSnapshot; + } { + const { project, options } = getTestConfig(); + + const input: InputsSnapshot = new InputsSnapshot(options); + + return { project, input }; + } + + describe(InputsSnapshot.prototype.getTrackedFileHashesForOperation.name, () => { + it('Handles trivial input', () => { + const { project, input } = getTrivialSnapshot(); + + const result: ReadonlyMap = input.getTrackedFileHashesForOperation(project); + + expect(result).toMatchSnapshot(); + expect(result.size).toEqual(3); + expect(result.get('a/file1.js')).toEqual('hash1'); + expect(result.get('a/file2.js')).toEqual('hash2'); + expect(result.get('a/lib/file3.js')).toEqual('hash3'); + }); + + it('Detects outputFileNames collisions', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + outputFolderNames: ['lib'] + } + ] + ]) + }; + + options.projectMap = new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]); + + const input: InputsSnapshot = new InputsSnapshot(options); + + expect(() => + input.getTrackedFileHashesForOperation(project, '_phase:build') + ).toThrowErrorMatchingSnapshot(); + }); + + it('Respects additionalFilesByOperationName', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build' + } + ] + ]) + }; + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration, + additionalFilesByOperationName: new Map([['_phase:build', new Set(['/ext/config.json'])]]) + } + ] + ]) + }); + + const result: ReadonlyMap = input.getTrackedFileHashesForOperation( + project, + '_phase:build' + ); + + expect(result).toMatchSnapshot(); + expect(result.size).toEqual(4); + expect(result.get('a/file1.js')).toEqual('hash1'); + expect(result.get('a/file2.js')).toEqual('hash2'); + expect(result.get('a/lib/file3.js')).toEqual('hash3'); + expect(result.get('/ext/config.json')).toEqual('hash4'); + }); + + it('Respects globalAdditionalFiles', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build' + } + ] + ]) + }; + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + globalAdditionalFiles: new Set(['common/config/some-config.json']), + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]) + }); + + const result: ReadonlyMap = input.getTrackedFileHashesForOperation( + project, + '_phase:build' + ); + + expect(result).toMatchSnapshot(); + expect(result.size).toEqual(4); + expect(result.get('a/file1.js')).toEqual('hash1'); + expect(result.get('a/file2.js')).toEqual('hash2'); + expect(result.get('a/lib/file3.js')).toEqual('hash3'); + expect(result.get('common/config/some-config.json')).toEqual('hash5'); + }); + + it('Respects incrementalBuildIgnoredGlobs', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + incrementalBuildIgnoredGlobs: ['*2.js'] + }; + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]) + }); + + const result: ReadonlyMap = input.getTrackedFileHashesForOperation(project); + + expect(result).toMatchSnapshot(); + expect(result.size).toEqual(2); + expect(result.get('a/file1.js')).toEqual('hash1'); + expect(result.get('a/lib/file3.js')).toEqual('hash3'); + }); + }); + + describe(InputsSnapshot.prototype.getOperationOwnStateHash.name, () => { + it('Handles trivial input', () => { + const { project, input } = getTrivialSnapshot(); + + const result: string = input.getOperationOwnStateHash(project); + + expect(result).toMatchSnapshot(); + }); + + it('Is invariant to input hash order', () => { + const { project, options } = getTestConfig(); + + const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project); + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + hashes: new Map(Array.from(options.hashes).reverse()) + }); + + const result: string = input.getOperationOwnStateHash(project); + + expect(result).toEqual(baseline); + }); + + it('Detects outputFileNames collisions', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + outputFolderNames: ['lib'] + } + ] + ]) + }; + + options.projectMap = new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]); + + const input: InputsSnapshot = new InputsSnapshot(options); + + expect(() => input.getOperationOwnStateHash(project, '_phase:build')).toThrowErrorMatchingSnapshot(); + }); + + it('Changes if outputFileNames changes', () => { + 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', + outputFolderNames: ['lib-commonjs'] + } + ] + ]) + }; + + const projectConfig2: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + outputFolderNames: ['lib-esm'] + } + ] + ]) + }; + + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig1 as RushProjectConfiguration + } + ] + ]) + }); + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig2 as RushProjectConfiguration + } + ] + ]) + }); + + const result1: string = input1.getOperationOwnStateHash(project, '_phase:build'); + + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result1).not.toEqual(baseline); + expect(result2).not.toEqual(baseline); + expect(result1).not.toEqual(result2); + }); + + it('Respects additionalOutputFilesByOperationName', () => { + const { project, options } = getTestConfig(); + const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project, '_phase:build'); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build' + } + ] + ]) + }; + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration, + additionalFilesByOperationName: new Map([['_phase:build', new Set(['/ext/config.json'])]]) + } + ] + ]) + }); + + const result: string = input.getOperationOwnStateHash(project, '_phase:build'); + + expect(result).toMatchSnapshot(); + expect(result).not.toEqual(baseline); + }); + + it('Respects globalAdditionalFiles', () => { + const { project, options } = getTestConfig(); + const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project, '_phase:build'); + + const input: InputsSnapshot = new InputsSnapshot({ + ...options, + globalAdditionalFiles: new Set(['common/config/some-config.json']) + }); + + const result: string = input.getOperationOwnStateHash(project); + + expect(result).toMatchSnapshot(); + expect(result).not.toEqual(baseline); + }); + + it('Respects incrementalBuildIgnoredGlobs', () => { + const { project, options } = getTestConfig(); + const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project, '_phase:build'); + + const projectConfig1: Pick = { + incrementalBuildIgnoredGlobs: ['*2.js'] + }; + + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig1 as RushProjectConfiguration + } + ] + ]) + }); + + const result1: string = input1.getOperationOwnStateHash(project); + + expect(result1).toMatchSnapshot(); + expect(result1).not.toEqual(baseline); + + const projectConfig2: Pick = { + incrementalBuildIgnoredGlobs: ['*1.js'] + }; + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig2 as RushProjectConfiguration + } + ] + ]) + }); + + const result2: string = input2.getOperationOwnStateHash(project); + + expect(result2).toMatchSnapshot(); + expect(result2).not.toEqual(baseline); + + expect(result2).not.toEqual(result1); + }); + + it('Respects dependsOnEnvVars', () => { + 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', + dependsOnEnvVars: ['ENV_VAR'] + } + ] + ]) + }; + + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig1 as RushProjectConfiguration + } + ] + ]), + environment: {} + }); + + 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 + } + ] + ]), + environment: { ENV_VAR: 'some_value' } + }); + + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result2).toMatchSnapshot(); + expect(result2).not.toEqual(baseline); + expect(result2).not.toEqual(result1); + }); + }); +}); 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 new file mode 100644 index 00000000000..a1db7fa9818 --- /dev/null +++ b/libraries/rush-lib/src/logic/incremental/test/__snapshots__/InputsSnapshot.test.ts.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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."`; + +exports[`InputsSnapshot getOperationOwnStateHash Handles trivial input 1`] = `"acf14e45ed255b0288e449432d48c285f619d146"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects additionalOutputFilesByOperationName 1`] = `"07f4147294d21a07865de84875d60bfbcc690652"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnEnvVars 1`] = `"ad1f915d0ac6331c09febbbe1496c970a5401b73"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnEnvVars 2`] = `"2c68d56fc9278b6495496070a6a992b929c37a83"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects globalAdditionalFiles 1`] = `"0e0437ad1941bacd098b22da15dc673f86ca6003"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects incrementalBuildIgnoredGlobs 1`] = `"f7b5af9ffdaa39831ed3374f28d0f7dccbee9c8d"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects incrementalBuildIgnoredGlobs 2`] = `"24047d4271ebf8badc9403c9a21a09fb6db2fb9c"`; + +exports[`InputsSnapshot getTrackedFileHashesForOperation 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."`; + +exports[`InputsSnapshot getTrackedFileHashesForOperation Handles trivial input 1`] = ` +Map { + "a/file1.js" => "hash1", + "a/file2.js" => "hash2", + "a/lib/file3.js" => "hash3", +} +`; + +exports[`InputsSnapshot getTrackedFileHashesForOperation Respects additionalFilesByOperationName 1`] = ` +Map { + "/ext/config.json" => "hash4", + "a/file1.js" => "hash1", + "a/file2.js" => "hash2", + "a/lib/file3.js" => "hash3", +} +`; + +exports[`InputsSnapshot getTrackedFileHashesForOperation Respects globalAdditionalFiles 1`] = ` +Map { + "a/file1.js" => "hash1", + "a/file2.js" => "hash2", + "a/lib/file3.js" => "hash3", + "common/config/some-config.json" => "hash5", +} +`; + +exports[`InputsSnapshot getTrackedFileHashesForOperation Respects incrementalBuildIgnoredGlobs 1`] = ` +Map { + "a/file1.js" => "hash1", + "a/lib/file3.js" => "hash3", +} +`; diff --git a/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts b/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts new file mode 100644 index 00000000000..8f850b4e73d --- /dev/null +++ b/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts @@ -0,0 +1,343 @@ +// 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 { + FileConstants, + FileSystem, + type IPackageJson, + JsonFile, + LockFile +} from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import { LastInstallFlag } from '../../api/LastInstallFlag'; +import type { PackageManagerName } from '../../api/packageManager/PackageManager'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import { Utilities } from '../../utilities/Utilities'; +import type { IConfigurationEnvironment } from '../base/BasePackageManagerOptionsConfiguration'; +import type { PnpmOptionsConfiguration } from '../pnpm/PnpmOptionsConfiguration'; +import { merge } from '../../utilities/objectUtilities'; +import type { Subspace } from '../../api/Subspace'; +import { RushConstants } from '../RushConstants'; + +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; + minimumReleaseAge?: typeof PnpmOptionsConfiguration.prototype.minimumReleaseAge; + minimumReleaseAgeExclude?: typeof PnpmOptionsConfiguration.prototype.minimumReleaseAgeExclude; + }; +} + +export class InstallHelpers { + public static generateCommonPackageJson( + rushConfiguration: RushConfiguration, + subspace: Subspace, + dependencies: Map = new Map(), + terminal: ITerminal + ): void { + const commonPackageJson: ICommonPackageJson = { + dependencies: {}, + description: 'Temporary file generated by the Rush tool', + name: 'rush-common', + private: true, + version: '0.0.0' + }; + + if (rushConfiguration.isPnpm) { + const pnpmOptions: PnpmOptionsConfiguration = + subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; + if (!commonPackageJson.pnpm) { + commonPackageJson.pnpm = {}; + } + + if (pnpmOptions.globalOverrides) { + commonPackageJson.pnpm.overrides = pnpmOptions.globalOverrides; + } + + if (pnpmOptions.globalPackageExtensions) { + commonPackageJson.pnpm.packageExtensions = pnpmOptions.globalPackageExtensions; + } + if (pnpmOptions.globalPeerDependencyRules) { + commonPackageJson.pnpm.peerDependencyRules = pnpmOptions.globalPeerDependencyRules; + } + + if (pnpmOptions.globalNeverBuiltDependencies) { + commonPackageJson.pnpm.neverBuiltDependencies = pnpmOptions.globalNeverBuiltDependencies; + } + + if (pnpmOptions.globalIgnoredOptionalDependencies) { + if ( + rushConfiguration.rushConfigurationJson.pnpmVersion !== undefined && + semver.lt(rushConfiguration.rushConfigurationJson.pnpmVersion, '9.0.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.' + ) + ); + } + + commonPackageJson.pnpm.ignoredOptionalDependencies = pnpmOptions.globalIgnoredOptionalDependencies; + } + + if (pnpmOptions.globalAllowedDeprecatedVersions) { + commonPackageJson.pnpm.allowedDeprecatedVersions = pnpmOptions.globalAllowedDeprecatedVersions; + } + + if (pnpmOptions.globalPatchedDependencies) { + commonPackageJson.pnpm.patchedDependencies = pnpmOptions.globalPatchedDependencies; + } + + if (pnpmOptions.minimumReleaseAge !== undefined || pnpmOptions.minimumReleaseAgeExclude) { + if ( + rushConfiguration.rushConfigurationJson.pnpmVersion !== undefined && + semver.lt(rushConfiguration.rushConfigurationJson.pnpmVersion, '10.16.0') + ) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of pnpm (${rushConfiguration.rushConfigurationJson.pnpmVersion}) ` + + `doesn't support the "minimumReleaseAge" or "minimumReleaseAgeExclude" fields in ` + + `${rushConfiguration.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}. ` + + 'Remove these fields or upgrade to pnpm 10.16.0 or newer.' + ) + ); + } + + if (pnpmOptions.minimumReleaseAge !== undefined) { + commonPackageJson.pnpm.minimumReleaseAge = pnpmOptions.minimumReleaseAge; + } + + if (pnpmOptions.minimumReleaseAgeExclude) { + commonPackageJson.pnpm.minimumReleaseAgeExclude = pnpmOptions.minimumReleaseAgeExclude; + } + } + + if (pnpmOptions.unsupportedPackageJsonSettings) { + merge(commonPackageJson, pnpmOptions.unsupportedPackageJsonSettings); + } + } + + // 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)!; + } + + // Example: "C:\MyRepo\common\temp\package.json" + const commonPackageJsonFilename: string = path.join( + subspace.getSubspaceTempFolderPath(), + FileConstants.PackageJson + ); + + // Don't update the file timestamp unless the content has changed, since "rush install" + // will consider this timestamp + JsonFile.save(commonPackageJson, commonPackageJsonFilename, { onlyIfChanged: true }); + } + + public static getPackageManagerEnvironment( + rushConfiguration: RushConfiguration, + options: { + debug?: boolean; + } = {} + ): NodeJS.ProcessEnv { + let configurationEnvironment: IConfigurationEnvironment | undefined = undefined; + + if (rushConfiguration.packageManager === 'npm') { + if (rushConfiguration.npmOptions && rushConfiguration.npmOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.npmOptions.environmentVariables; + } + } else if (rushConfiguration.isPnpm) { + if (rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.pnpmOptions.environmentVariables; + } + } else if (rushConfiguration.packageManager === 'yarn') { + if (rushConfiguration.yarnOptions && rushConfiguration.yarnOptions.environmentVariables) { + configurationEnvironment = rushConfiguration.yarnOptions.environmentVariables; + } + } + + return InstallHelpers._mergeEnvironmentVariables(process.env, configurationEnvironment, options); + } + + /** + * If the "(p)npm-local" symlink hasn't been set up yet, this creates it, installing the + * specified (P)npm version in the user's home directory if needed. + */ + public static async ensureLocalPackageManagerAsync( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + maxInstallAttempts: number, + restrictConsoleOutput?: boolean + ): Promise { + let logIfConsoleOutputIsNotRestricted: (message?: string) => void; + if (restrictConsoleOutput) { + logIfConsoleOutputIsNotRestricted = () => { + /* noop */ + }; + } else { + logIfConsoleOutputIsNotRestricted = (message?: string) => { + // eslint-disable-next-line no-console + console.log(message); + }; + } + + // Example: "C:\Users\YourName\.rush" + const rushUserFolder: string = rushGlobalFolder.nodeSpecificPath; + + if (!FileSystem.exists(rushUserFolder)) { + logIfConsoleOutputIsNotRestricted('Creating ' + rushUserFolder); + FileSystem.ensureFolder(rushUserFolder); + } + + const packageManager: PackageManagerName = rushConfiguration.packageManager; + const packageManagerVersion: string = rushConfiguration.packageManagerToolVersion; + + const packageManagerAndVersion: string = `${packageManager}-${packageManagerVersion}`; + // Example: "C:\Users\YourName\.rush\pnpm-1.2.3" + const packageManagerToolFolder: string = path.join(rushUserFolder, packageManagerAndVersion); + + const packageManagerMarker: LastInstallFlag = new LastInstallFlag(packageManagerToolFolder, { + node: process.versions.node + }); + + logIfConsoleOutputIsNotRestricted(`Trying to acquire lock for ${packageManagerAndVersion}`); + + const lock: LockFile = await LockFile.acquireAsync(rushUserFolder, packageManagerAndVersion); + + logIfConsoleOutputIsNotRestricted(`Acquired lock for ${packageManagerAndVersion}`); + + if (!(await packageManagerMarker.isValidAsync()) || lock.dirtyWhenAcquired) { + logIfConsoleOutputIsNotRestricted( + Colorize.bold(`Installing ${packageManager} version ${packageManagerVersion}\n`) + ); + + // note that this will remove the last-install flag from the directory + await Utilities.installPackageInDirectoryAsync({ + directory: packageManagerToolFolder, + packageName: packageManager, + version: rushConfiguration.packageManagerToolVersion, + tempPackageTitle: `${packageManager}-local-install`, + maxInstallAttempts: maxInstallAttempts, + // This is using a local configuration to install a package in a shared global location. + // Generally that's a bad practice, but in this case if we can successfully install + // the package at all, we can reasonably assume it's good for all the repositories. + // 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 + }); + + logIfConsoleOutputIsNotRestricted( + `Successfully installed ${packageManager} version ${packageManagerVersion}` + ); + } else { + logIfConsoleOutputIsNotRestricted( + `Found ${packageManager} version ${packageManagerVersion} in ${packageManagerToolFolder}` + ); + } + + await packageManagerMarker.createAsync(); + + // Example: "C:\MyRepo\common\temp" + FileSystem.ensureFolder(rushConfiguration.commonTempFolder); + + // Example: "C:\MyRepo\common\temp\pnpm-local" + const localPackageManagerToolFolder: string = path.join( + rushConfiguration.commonTempFolder, + `${packageManager}-local` + ); + + logIfConsoleOutputIsNotRestricted(`\nSymlinking "${localPackageManagerToolFolder}"`); + logIfConsoleOutputIsNotRestricted(` --> "${packageManagerToolFolder}"`); + + // 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); + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { + throw error; + } + } + + FileSystem.createSymbolicLinkJunction({ + 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; + // 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(` Existing value: ${baseEnv[envVar]}`); + // eslint-disable-next-line no-console + console.log( + ` Value set in ${RushConstants.rushJsonFilename}: ${environmentVariables[envVar].value}` + ); + + 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.`)); + } + } + + 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; + } +} diff --git a/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts new file mode 100644 index 00000000000..1c328e29410 --- /dev/null +++ b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -0,0 +1,756 @@ +// 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 semver from 'semver'; +import * as ssri from 'ssri'; + +import { + JsonFile, + Text, + FileSystem, + FileConstants, + Sort, + InternalError, + AlreadyReportedError +} from '@rushstack/node-core-library'; +import { Colorize, PrintUtilities } from '@rushstack/terminal'; + +import { BaseInstallManager } from '../base/BaseInstallManager'; +import type { IInstallManagerOptions } from '../base/BaseInstallManagerTypes'; +import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import type { IRushTempPackageJson } from '../base/BasePackage'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { RushConstants } from '../RushConstants'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { Utilities } from '../../utilities/Utilities'; +import { + type PackageJsonEditor, + DependencyType, + type PackageJsonDependency +} from '../../api/PackageJsonEditor'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; +import { InstallHelpers } from './InstallHelpers'; +import { TempProjectHelper } from '../TempProjectHelper'; +import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import type { RushConfiguration } from '../..'; +import type { PurgeManager } from '../PurgeManager'; +import { LinkManagerFactory } from '../LinkManagerFactory'; +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. + */ +declare module 'tar' { + // eslint-disable-next-line @typescript-eslint/naming-convention + export interface CreateOptions { + /** + * "Set to true to omit writing mtime values for entries. Note that this prevents using other + * mtime-based features like tar.update or the keepNewer option with the resulting tar archive." + */ + noMtime?: boolean; + } +} + +/** + * This class implements common logic between "rush install" and "rush update". + */ +export class RushInstallManager extends BaseInstallManager { + private _tempProjectHelper: TempProjectHelper; + + public constructor( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ) { + super(rushConfiguration, rushGlobalFolder, purgeManager, options); + this._tempProjectHelper = new TempProjectHelper( + this.rushConfiguration, + rushConfiguration.defaultSubspace + ); + } + + /** + * Regenerates the common/package.json and all temp_modules projects. + * 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( + subspace: Subspace, + shrinkwrapFile: BaseShrinkwrapFile | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { + const stopwatch: Stopwatch = Stopwatch.start(); + + const { fullUpgrade, variant } = this.options; + + // Example: "C:\MyRepo\common\temp\projects" + const tempProjectsFolder: string = path.join( + this.rushConfiguration.commonTempFolder, + RushConstants.rushTempProjectsFolderName + ); + + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold('Updating temp projects in ' + tempProjectsFolder)); + + Utilities.createFolderWithRetry(tempProjectsFolder); + + const shrinkwrapWarnings: string[] = []; + + // We will start with the assumption that it's valid, and then set it to false if + // any of the checks fail + let shrinkwrapIsUpToDate: boolean = true; + + if (!shrinkwrapFile) { + shrinkwrapIsUpToDate = false; + } else if (shrinkwrapFile.isWorkspaceCompatible && !fullUpgrade) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'The shrinkwrap file had previously been updated to support workspaces. Run "rush update --full" ' + + 'to update the shrinkwrap file.' + ) + ); + throw new AlreadyReportedError(); + } + + // dependency name --> version specifier + const allExplicitPreferredVersions: Map = this.rushConfiguration.defaultSubspace + .getCommonVersions(variant) + .getAllPreferredVersions(); + + if (shrinkwrapFile) { + // Check any (explicitly) preferred dependencies first + allExplicitPreferredVersions.forEach((version: string, dependency: string) => { + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependency, + version + ); + + if (!shrinkwrapFile.hasCompatibleTopLevelDependency(dependencySpecifier)) { + shrinkwrapWarnings.push( + `Missing dependency "${dependency}" (${version}) required by the preferred versions from ` + + RushConstants.commonVersionsFilename + ); + shrinkwrapIsUpToDate = false; + } + }); + + if (this._findMissingTempProjects(shrinkwrapFile)) { + // If any Rush project's tarball is missing from the shrinkwrap file, then we need to update + // the shrinkwrap file. + shrinkwrapIsUpToDate = false; + } + + // If there are orphaned projects, we need to update + const orphanedProjects: ReadonlyArray = shrinkwrapFile.findOrphanedProjects( + this.rushConfiguration, + this.rushConfiguration.defaultSubspace + ); + + if (orphanedProjects.length > 0) { + for (const orphanedProject of orphanedProjects) { + shrinkwrapWarnings.push( + `Your ${this.rushConfiguration.shrinkwrapFilePhrase} references "${orphanedProject}" ` + + `which was not found in ${RushConstants.rushJsonFilename}` + ); + } + shrinkwrapIsUpToDate = false; + } + } + + // dependency name --> version specifier + const commonDependencies: Map = new Map([ + ...allExplicitPreferredVersions, + ...this.rushConfiguration.getImplicitlyPreferredVersions(subspace, variant) + ]); + + // To make the common/package.json file more readable, sort alphabetically + // according to rushProject.tempProjectName instead of packageName. + const sortedRushProjects: RushConfigurationProject[] = this.rushConfiguration.projects.slice(0); + Sort.sortBy(sortedRushProjects, (x) => x.tempProjectName); + + for (const rushProject of sortedRushProjects) { + const packageJson: PackageJsonEditor = rushProject.packageJsonEditor; + + // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" + const tarballFile: string = this._tempProjectHelper.getTarballFilePath(rushProject); + + // Example: dependencies["@rush-temp/my-project-2"] = "file:./projects/my-project-2.tgz" + commonDependencies.set( + rushProject.tempProjectName, + `file:./${RushConstants.rushTempProjectsFolderName}/${rushProject.unscopedTempProjectName}.tgz` + ); + + const tempPackageJson: IRushTempPackageJson = { + name: rushProject.tempProjectName, + version: '0.0.0', + private: true, + dependencies: {} + }; + + // Collect pairs of (packageName, packageVersion) to be added as dependencies of the @rush-temp package.json + const tempDependencies: Map = new Map(); + + // These can be regular, optional, or peer dependencies (but NOT dev dependencies). + // (A given packageName will never appear more than once in this list.) + for (const dependency of packageJson.dependencyList) { + if (this.options.fullUpgrade && this._revertWorkspaceNotation(dependency)) { + shrinkwrapIsUpToDate = false; + } + + // If there are any optional dependencies, copy directly into the optionalDependencies field. + if (dependency.dependencyType === DependencyType.Optional) { + if (!tempPackageJson.optionalDependencies) { + tempPackageJson.optionalDependencies = {}; + } + tempPackageJson.optionalDependencies[dependency.name] = dependency.version; + } else { + tempDependencies.set(dependency.name, dependency.version); + } + } + + for (const dependency of packageJson.devDependencyList) { + if (this.options.fullUpgrade && this._revertWorkspaceNotation(dependency)) { + shrinkwrapIsUpToDate = false; + } + + // If there are devDependencies, we need to merge them with the regular dependencies. If the same + // library appears in both places, then the dev dependency wins (because presumably it's saying what you + // want right now for development, not the range that you support for consumers). + tempDependencies.set(dependency.name, dependency.version); + } + Sort.sortMapKeys(tempDependencies); + + for (const [packageName, packageVersion] of tempDependencies.entries()) { + 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. + // In this case, we don't want "npm install" to process this package, but we do need + // to record this decision for linking later, so we add it to a special 'rushDependencies' field. + const localProject: RushConfigurationProject | undefined = + this.rushConfiguration.getProjectByName(packageName); + + if (localProject) { + // Don't locally link if it's listed in the decoupledLocalDependencies + if (!rushProject.decoupledLocalDependencies.has(packageName)) { + // Also, don't locally link if the SemVer doesn't match + const localProjectVersion: string = localProject.packageJsonEditor.version; + if (semver.satisfies(localProjectVersion, packageVersion)) { + // We will locally link this package, so instead add it to our special "rushDependencies" + // field in the package.json file. + if (!tempPackageJson.rushDependencies) { + tempPackageJson.rushDependencies = {}; + } + tempPackageJson.rushDependencies[packageName] = packageVersion; + continue; + } + } + } + + // We will NOT locally link this package; add it as a regular dependency. + tempPackageJson.dependencies![packageName] = packageVersion; + + if ( + shrinkwrapFile && + !shrinkwrapFile.tryEnsureCompatibleDependency(dependencySpecifier, rushProject.tempProjectName) + ) { + shrinkwrapWarnings.push( + `Missing dependency "${packageName}" (${packageVersion}) required by "${rushProject.packageName}"` + ); + shrinkwrapIsUpToDate = false; + } + } + + if (this.rushConfiguration.packageManager === 'yarn') { + // This feature is only implemented by the Yarn package manager + if (packageJson.resolutionsList.length > 0) { + tempPackageJson.resolutions = packageJson.saveToObject().resolutions; + } + } + + // Example: "C:\MyRepo\common\temp\projects\my-project-2" + const tempProjectFolder: string = this._tempProjectHelper.getTempProjectFolder(rushProject); + + // Example: "C:\MyRepo\common\temp\projects\my-project-2\package.json" + const tempPackageJsonFilename: string = path.join(tempProjectFolder, FileConstants.PackageJson); + + // we only want to overwrite the package if the existing tarball's package.json is different from tempPackageJson + let shouldOverwrite: boolean = true; + try { + // if the tarball and the temp file still exist, then compare the contents + if (FileSystem.exists(tarballFile) && FileSystem.exists(tempPackageJsonFilename)) { + // compare the extracted package.json with the one we are about to write + const oldBuffer: Buffer = FileSystem.readFileToBuffer(tempPackageJsonFilename); + const newBuffer: Buffer = Buffer.from(JsonFile.stringify(tempPackageJson)); + + if (Buffer.compare(oldBuffer, newBuffer) === 0) { + shouldOverwrite = false; + } + } + } catch (error) { + // ignore the error, we will go ahead and create a new tarball + } + + if (shouldOverwrite) { + try { + // ensure the folder we are about to zip exists + Utilities.createFolderWithRetry(tempProjectFolder); + + // remove the old tarball & old temp package json, this is for any cases where new tarball creation + // fails, and the shouldOverwrite logic is messed up because the my-project-2\package.json + // exists and is updated, but the tarball is not accurate + FileSystem.deleteFile(tarballFile); + FileSystem.deleteFile(tempPackageJsonFilename); + + // write the expected package.json file into the zip staging folder + JsonFile.save(tempPackageJson, tempPackageJsonFilename); + + // Delete the existing tarball and create a new one + this._tempProjectHelper.createTempProjectTarball(rushProject); + + // eslint-disable-next-line no-console + console.log(`Updating ${tarballFile}`); + } catch (error) { + // eslint-disable-next-line no-console + console.log(Colorize.yellow(error as string)); + // delete everything in case of any error + FileSystem.deleteFile(tarballFile); + FileSystem.deleteFile(tempPackageJsonFilename); + } + } + + // When using frozen shrinkwrap, we need to validate that the tarball integrities are up-to-date + // with the shrinkwrap file, since these will cause install to fail. + if ( + shrinkwrapFile && + this.rushConfiguration.isPnpm && + this.rushConfiguration.experimentsConfiguration.configuration.usePnpmFrozenLockfileForRushInstall + ) { + const pnpmShrinkwrapFile: PnpmShrinkwrapFile = shrinkwrapFile as PnpmShrinkwrapFile; + const tarballIntegrityValid: boolean = await this._validateRushProjectTarballIntegrityAsync( + pnpmShrinkwrapFile, + rushProject + ); + if (!tarballIntegrityValid) { + shrinkwrapIsUpToDate = false; + shrinkwrapWarnings.push( + `Invalid or missing tarball integrity hash in shrinkwrap for "${rushProject.packageName}"` + ); + } + } + + // Save the package.json if we modified the version references and warn that the package.json was modified + if (packageJson.saveIfModified()) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `"${rushProject.packageName}" depends on one or more local packages which used "workspace:" ` + + 'notation. The package.json has been modified and must be committed to source control.' + ) + ); + } + } + + // Remove the workspace file if it exists + if (this.rushConfiguration.isPnpm) { + const workspaceFilePath: string = path.join( + this.rushConfiguration.commonTempFolder, + 'pnpm-workspace.yaml' + ); + try { + await FileSystem.deleteFileAsync(workspaceFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e as Error)) { + throw e; + } + } + } + + // Write the common package.json + InstallHelpers.generateCommonPackageJson( + this.rushConfiguration, + this.rushConfiguration.defaultSubspace, + commonDependencies, + this._terminal + ); + + stopwatch.stop(); + // eslint-disable-next-line no-console + console.log(`Finished creating temporary modules (${stopwatch.toString()})`); + + return { shrinkwrapIsUpToDate, shrinkwrapWarnings }; + } + + private _revertWorkspaceNotation(dependency: PackageJsonDependency): boolean { + const specifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependency.name, + dependency.version + ); + if (specifier.specifierType !== DependencySpecifierType.Workspace) { + return false; + } + // Replace workspace notation with the supplied version range + if (specifier.versionSpecifier === '*') { + // When converting to workspaces, exact package versions are replaced with a '*', so undo this + const localProject: RushConfigurationProject | undefined = this.rushConfiguration.getProjectByName( + specifier.packageName + ); + if (!localProject) { + throw new InternalError(`Could not find local project with package name ${specifier.packageName}`); + } + dependency.setVersion(localProject.packageJson.version); + } else { + dependency.setVersion(specifier.versionSpecifier); + } + return true; + } + + private async _validateRushProjectTarballIntegrityAsync( + shrinkwrapFile: PnpmShrinkwrapFile | undefined, + rushProject: RushConfigurationProject + ): Promise { + if (shrinkwrapFile) { + const tempProjectDependencyKey: string | undefined = shrinkwrapFile.getTempProjectDependencyKey( + rushProject.tempProjectName + ); + if (!tempProjectDependencyKey) { + return false; + } + + const parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml = + shrinkwrapFile.getShrinkwrapEntryFromTempProjectDependencyKey(tempProjectDependencyKey)!; + const newIntegrity: string = ( + await ssri.fromStream(fs.createReadStream(this._tempProjectHelper.getTarballFilePath(rushProject))) + ).toString(); + + if (!parentShrinkwrapEntry.resolution || parentShrinkwrapEntry.resolution.integrity !== newIntegrity) { + return false; + } + } + return true; + } + + /** + * Check whether or not the install is already valid, and therefore can be skipped. + * + * @override + */ + protected async canSkipInstallAsync( + lastModifiedDate: Date, + subspace: Subspace, + variant: string | undefined + ): Promise { + if (!(await super.canSkipInstallAsync(lastModifiedDate, subspace, variant))) { + return false; + } + + const potentiallyChangedFiles: string[] = []; + + // Also consider timestamps for all the temp tarballs. (createTempModulesAndCheckShrinkwrap() will + // carefully preserve these timestamps unless something has changed.) + // Example: "C:\MyRepo\common\temp\projects\my-project-2.tgz" + potentiallyChangedFiles.push( + ...this.rushConfiguration.projects.map((x) => { + return this._tempProjectHelper.getTarballFilePath(x); + }) + ); + + return Utilities.isFileTimestampCurrentAsync(lastModifiedDate, potentiallyChangedFiles); + } + + /** + * Runs "npm/pnpm/yarn install" in the "common/temp" folder. + * + * @override + */ + protected 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. + for (const rushProject of this.rushConfiguration.projects) { + this._tempProjectHelper.createTempProjectTarball(rushProject); + } + + // NOTE: The PNPM store is supposed to be transactionally safe, so we don't delete it automatically. + // The user must request that via the command line. + if (cleanInstall) { + if (this.rushConfiguration.packageManager === 'npm') { + // eslint-disable-next-line no-console + console.log(`Deleting the "npm-cache" folder`); + // This is faster and more thorough than "npm cache clean" + this.installRecycler.moveFolder(this.rushConfiguration.npmCacheFolder); + + // eslint-disable-next-line no-console + console.log(`Deleting the "npm-tmp" folder`); + this.installRecycler.moveFolder(this.rushConfiguration.npmTmpFolder); + } + } + + // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" + const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename; + + const packageManagerEnv: NodeJS.ProcessEnv = InstallHelpers.getPackageManagerEnvironment( + this.rushConfiguration, + this.options + ); + + const commonNodeModulesFolder: string = path.join( + this.rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName + ); + + // Is there an existing "node_modules" folder to consider? + if (FileSystem.exists(commonNodeModulesFolder)) { + // Should we delete the entire "node_modules" folder? + if (cleanInstall) { + // YES: Delete "node_modules" + + // Explain to the user why we are hosing their node_modules folder + // eslint-disable-next-line no-console + console.log('Deleting files from ' + commonNodeModulesFolder); + + this.installRecycler.moveFolder(commonNodeModulesFolder); + + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } else { + // NO: Prepare to do an incremental install in the "node_modules" folder + + // note: it is not necessary to run "prune" with pnpm + if (this.rushConfiguration.packageManager === 'npm') { + // eslint-disable-next-line no-console + console.log( + `Running "${this.rushConfiguration.packageManager} prune"` + + ` in ${this.rushConfiguration.commonTempFolder}` + ); + const args: string[] = ['prune']; + this.pushConfigurationArgs(args, this.options, subspace); + + await Utilities.executeCommandWithRetryAsync( + { + command: packageManagerFilename, + args: args, + workingDirectory: this.rushConfiguration.commonTempFolder, + environment: packageManagerEnv + }, + this.options.maxInstallAttempts + ); + + // Delete the (installed image of) the temp projects, since "npm install" does not + // detect changes for "file:./" references. + // We recognize the temp projects by their names, which always start with "rush-". + + // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp" + const pathToDeleteWithoutStar: string = path.join( + commonNodeModulesFolder, + RushConstants.rushTempNpmScope + ); + // eslint-disable-next-line no-console + console.log(`Deleting ${pathToDeleteWithoutStar}\\*`); + // Glob can't handle Windows paths + const normalizedPathToDeleteWithoutStar: string = Text.replaceAll( + pathToDeleteWithoutStar, + '\\', + '/' + ); + + const { default: glob } = await import('fast-glob'); + const tempModulePaths: string[] = await glob(globEscape(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 + // to be very small + Utilities.dangerouslyDeletePath(tempModulePath); + } + } + } + } + + if (this.rushConfiguration.packageManager === 'yarn') { + // Yarn does not correctly detect changes to a tarball, so we need to forcibly clear its cache + const yarnRushTempCacheFolder: string = path.join( + this.rushConfiguration.yarnCacheFolder, + 'v2', + 'npm-@rush-temp' + ); + if (FileSystem.exists(yarnRushTempCacheFolder)) { + // eslint-disable-next-line no-console + console.log('Deleting ' + yarnRushTempCacheFolder); + Utilities.dangerouslyDeletePath(yarnRushTempCacheFolder); + } + } + + // Run "npm install" in the common folder + const installArgs: string[] = ['install']; + this.pushConfigurationArgs(installArgs, this.options, subspace); + + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.bold( + `Running "${this.rushConfiguration.packageManager} install" in` + + ` ${this.rushConfiguration.commonTempFolder}` + ) + + '\n' + ); + + // If any diagnostic options were specified, then show the full command-line + if (this.options.debug || this.options.collectLogFile || this.options.networkConcurrency) { + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.green('Invoking package manager: ') + + FileSystem.getRealPath(packageManagerFilename) + + ' ' + + installArgs.join(' ') + + '\n' + ); + } + + await Utilities.executeCommandWithRetryAsync( + { + command: packageManagerFilename, + args: installArgs, + workingDirectory: this.rushConfiguration.commonTempFolder, + environment: packageManagerEnv, + suppressOutput: false + }, + this.options.maxInstallAttempts, + () => { + if (this.rushConfiguration.isPnpm) { + // eslint-disable-next-line no-console + console.log(Colorize.yellow(`Deleting the "node_modules" folder`)); + this.installRecycler.moveFolder(commonNodeModulesFolder); + + // Leave the pnpm-store as is for the retry. This ensures that packages that have already + // been downloaded need not be downloaded again, thereby potentially increasing the chances + // of a subsequent successful install. + + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } + } + ); + + if (this.rushConfiguration.packageManager === 'npm') { + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold('Running "npm shrinkwrap"...')); + const npmArgs: string[] = ['shrinkwrap']; + this.pushConfigurationArgs(npmArgs, this.options, subspace); + await Utilities.executeCommandAsync({ + command: this.rushConfiguration.packageManagerToolFilename, + args: npmArgs, + workingDirectory: this.rushConfiguration.commonTempFolder + }); + // eslint-disable-next-line no-console + console.log('"npm shrinkwrap" completed\n'); + + await this._fixupNpm5RegressionAsync(); + } + } + + protected async postInstallAsync(subspace: Subspace): Promise { + if (!this.options.noLink) { + const linkManager: BaseLinkManager = LinkManagerFactory.getLinkManager(this.rushConfiguration); + await linkManager.createSymlinksForProjectsAsync(false); + } else { + // eslint-disable-next-line no-console + console.log( + '\n' + Colorize.yellow('Since "--no-link" was specified, you will need to run "rush link" manually.') + ); + } + } + + /** + * This is a workaround for a bug introduced in NPM 5 (and still unfixed as of NPM 5.5.1): + * https://github.com/npm/npm/issues/19006 + * + * The regression is that "npm install" sets the package.json "version" field for the + * @rush-temp projects to a value like "file:projects/example.tgz", when it should be "0.0.0". + * This causes linking to fail later, when read-package-tree tries to parse the bad version. + * The error looks like this: + * + * ERROR: Failed to parse package.json for foo: Invalid version: "file:projects/example.tgz" + * + * Our workaround is to rewrite the package.json files for each of the @rush-temp projects + * in the node_modules folder, after "npm install" completes. + */ + private async _fixupNpm5RegressionAsync(): Promise { + const pathToDeleteWithoutStar: string = path.join( + this.rushConfiguration.commonTempFolder, + 'node_modules', + RushConstants.rushTempNpmScope + ); + // Glob can't handle Windows paths + const normalizedPathToDeleteWithoutStar: string = Text.replaceAll(pathToDeleteWithoutStar, '\\', '/'); + + let anyChanges: boolean = false; + + const { default: glob } = await import('fast-glob'); + const packageJsonPaths: string[] = await glob( + globEscape(normalizedPathToDeleteWithoutStar) + '/*/package.json' + ); + // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*/package.json" + for (const packageJsonPath of packageJsonPaths) { + // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/example/package.json" + const packageJsonObject: IRushTempPackageJson = JsonFile.load(packageJsonPath); + + // The temp projects always use "0.0.0" as their version + packageJsonObject.version = '0.0.0'; + + if (JsonFile.save(packageJsonObject, packageJsonPath, { onlyIfChanged: true })) { + anyChanges = true; + } + } + + if (anyChanges) { + // eslint-disable-next-line no-console + console.log( + '\n' + Colorize.yellow(PrintUtilities.wrapWords(`Applied workaround for NPM 5 bug`)) + '\n' + ); + } + } + + /** + * Checks for temp projects that exist in the shrinkwrap file, but don't exist + * in rush.json. This might occur, e.g. if a project was recently deleted or renamed. + * + * @returns true if orphans were found, or false if everything is okay + */ + private _findMissingTempProjects(shrinkwrapFile: BaseShrinkwrapFile): boolean { + const tempProjectNames: Set = new Set(shrinkwrapFile.getTempProjectNames()); + + for (const rushProject of this.rushConfiguration.projects) { + if (!tempProjectNames.has(rushProject.tempProjectName)) { + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.yellow( + PrintUtilities.wrapWords( + `Your ${this.rushConfiguration.shrinkwrapFilePhrase} is missing the project "${rushProject.packageName}".` + ) + ) + + '\n' + ); + return true; // found one + } + } + + return false; // none found + } +} diff --git a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts new file mode 100644 index 00000000000..d9b3b577c90 --- /dev/null +++ b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -0,0 +1,871 @@ +// 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 { createHash } from 'node:crypto'; + +import * as semver from 'semver'; +import yaml from 'js-yaml'; + +import { + FileSystem, + FileConstants, + AlreadyReportedError, + Async, + type IDependenciesMetaTable, + Objects, + Path, + Sort +} from '@rushstack/node-core-library'; +import { Colorize, ConsoleTerminalProvider } from '@rushstack/terminal'; + +import { BaseInstallManager } from '../base/BaseInstallManager'; +import type { IInstallManagerOptions } from '../base/BaseInstallManagerTypes'; +import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; +import { + type PackageJsonEditor, + 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 type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +import type { RepoStateFile } from '../RepoStateFile'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +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 type { Subspace } from '../../api/Subspace'; +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 } }; +} + +/** + * This class implements common logic between "rush install" and "rush update". + */ +export class WorkspaceInstallManager extends BaseInstallManager { + /** + * @override + */ + public async doInstallAsync(): Promise { + // TODO: Remove when "rush link" and "rush unlink" are deprecated + if (this.options.noLink) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'The "--no-link" option was provided but is not supported when using workspaces. Run the command again ' + + 'without specifying this argument.' + ) + ); + throw new AlreadyReportedError(); + } + + await super.doInstallAsync(); + } + + /** + * Regenerates the common/temp/package.json and related workspace files. + * 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( + subspace: Subspace, + shrinkwrapFile: (PnpmShrinkwrapFile & BaseShrinkwrapFile) | undefined + ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { + // Block use of the RUSH_TEMP_FOLDER environment variable + if (EnvironmentConfiguration.rushTempFolderOverride !== undefined) { + throw new Error( + 'The RUSH_TEMP_FOLDER environment variable is not compatible with workspace installs. If attempting ' + + 'to move the PNPM store path, see the `RUSH_PNPM_STORE_PATH` environment variable.' + ); + } + + const { fullUpgrade, allowShrinkwrapUpdates, variant } = this.options; + + // eslint-disable-next-line no-console + console.log('\n' + Colorize.bold('Updating workspace files in ' + subspace.getSubspaceTempFolderPath())); + + const shrinkwrapWarnings: string[] = []; + + // We will start with the assumption that it's valid, and then set it to false if + // any of the checks fail + let shrinkwrapIsUpToDate: boolean = true; + + if (!shrinkwrapFile) { + shrinkwrapIsUpToDate = false; + } else { + if (!shrinkwrapFile.isWorkspaceCompatible && !fullUpgrade) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'The shrinkwrap file has not been updated to support workspaces. Run "rush update --full" to update ' + + 'the shrinkwrap file.' + ) + ); + throw new AlreadyReportedError(); + } + + // If there are orphaned projects, we need to update + const orphanedProjects: ReadonlyArray = shrinkwrapFile.findOrphanedProjects( + this.rushConfiguration, + subspace + ); + + if (orphanedProjects.length > 0) { + for (const orphanedProject of orphanedProjects) { + shrinkwrapWarnings.push( + `Your ${this.rushConfiguration.shrinkwrapFilePhrase} references "${orphanedProject}" ` + + `which was not found in ${RushConstants.rushJsonFilename}` + ); + } + shrinkwrapIsUpToDate = false; + } + } + + // If preferred versions have been updated, or if the repo-state.json is invalid, + // we can't be certain of the state of the shrinkwrap + const repoState: RepoStateFile = subspace.getRepoState(); + if (!repoState.isValid) { + shrinkwrapWarnings.push( + `The ${RushConstants.repoStateFilename} file is invalid. There may be a merge conflict marker in the file.` + ); + shrinkwrapIsUpToDate = false; + } else { + const commonVersions: CommonVersionsConfiguration = subspace.getCommonVersions(variant); + if (repoState.preferredVersionsHash !== commonVersions.getPreferredVersionsHash()) { + shrinkwrapWarnings.push( + `Preferred versions from ${RushConstants.commonVersionsFilename} have been modified.` + ); + shrinkwrapIsUpToDate = false; + } + + const stopwatch: Stopwatch = Stopwatch.start(); + + const packageJsonInjectedDependenciesHash: string | undefined = + subspace.getPackageJsonInjectedDependenciesHash(variant); + + stopwatch.stop(); + + this._terminal.writeDebugLine( + `Total amount of time spent to hash related package.json files in the injected installation case: ${stopwatch.toString()}` + ); + + if (packageJsonInjectedDependenciesHash) { + // if packageJsonInjectedDependenciesHash exists + // make sure it matches the value in repoState + if (packageJsonInjectedDependenciesHash !== repoState.packageJsonInjectedDependenciesHash) { + shrinkwrapWarnings.push(`Some injected dependencies' package.json might have been modified.`); + shrinkwrapIsUpToDate = false; + } + } else { + // if packageJsonInjectedDependenciesHash not exists + // there is a situation that the subspace previously has injected dependencies but removed + // so we can check if the repoState up to date + if (repoState.packageJsonInjectedDependenciesHash !== undefined) { + shrinkwrapWarnings.push( + `It was detected that ${repoState.filePath} contains packageJsonInjectedDependenciesHash` + + ' but the injected dependencies feature is not enabled. You can manually remove this field in repo-state.json.' + + ' Or run rush update command to update the repo-state.json file.' + ); + } + } + } + + // 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') + ); + + // 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. + // Build a object for dependenciesMeta settings in projects' package.json + // key is the package path, value is the dependenciesMeta info for that package + const expectedDependenciesMetaByProjectRelativePath: Record = {}; + const commonTempFolder: string = subspace.getSubspaceTempFolderPath(); + const rushJsonFolder: string = this.rushConfiguration.rushJsonFolder; + // get the relative path from common temp folder to repo root folder + const relativeFromTempFolderToRootFolder: string = path.relative(commonTempFolder, rushJsonFolder); + + // Loop through the projects and add them to the workspace file. While we're at it, also validate that + // referenced workspace projects are valid, and check if the shrinkwrap file is already up-to-date. + for (const rushProject of this.rushConfiguration.projects) { + if (!subspace.contains(rushProject)) { + // skip processing any project that isn't in this subspace + continue; + } + const packageJson: PackageJsonEditor = rushProject.packageJsonEditor; + workspaceFile.addPackage(rushProject.projectFolder); + + for (const { name, version, dependencyType } of [ + ...packageJson.dependencyList, + ...packageJson.devDependencyList + ]) { + // Allow the package manager to handle peer dependency resolution, since this is simply a constraint + // enforced by the package manager. Additionally, peer dependencies are simply a version constraint + // and do not need to be converted to workspaces protocol. + if (dependencyType === DependencyType.Peer) { + continue; + } + + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache(name, version); + + // Is there a locally built Rush project that could satisfy this dependency? + 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. + if ( + (dependencySpecifier.specifierType === DependencySpecifierType.Version || + dependencySpecifier.specifierType === DependencySpecifierType.Range) && + referencedLocalProject && + !rushProject.decoupledLocalDependencies.has(name) + ) { + // Make sure that this version is intended to target a local package. If not, then we will fail since it + // is not explicitly specified as a cyclic dependency. + if ( + !semver.satisfies( + referencedLocalProject.packageJsonEditor.version, + dependencySpecifier.versionSpecifier + ) + ) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + `"${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(); + } + + if (!allowShrinkwrapUpdates) { + // eslint-disable-next-line no-console + console.log(); + // eslint-disable-next-line no-console + console.log( + Colorize.red( + `"${rushProject.packageName}" depends on package "${name}" (${version}) which exists within ` + + 'the workspace. Run "rush update" to update workspace references for this package. ' + + `If package "${name}" is intentionally expected to be installed from an external package feed, ` + + `list package "${name}" in the "decoupledLocalDependencies" field in the ` + + `"${rushProject.packageName}" entry in rush.json to suppress this error.` + ) + ); + throw new AlreadyReportedError(); + } + + if (fullUpgrade) { + // We will update to `workspace` notation. If the version specified is a range, then use the provided range. + // Otherwise, use `workspace:*` to ensure we're always using the workspace package. + const workspaceRange: string = + !!semver.validRange(dependencySpecifier.versionSpecifier) && + !semver.valid(dependencySpecifier.versionSpecifier) + ? dependencySpecifier.versionSpecifier + : '*'; + packageJson.addOrUpdateDependency(name, `workspace:${workspaceRange}`, dependencyType); + shrinkwrapIsUpToDate = false; + continue; + } + } else if ( + dependencySpecifier.specifierType === DependencySpecifierType.Workspace && + rushProject.decoupledLocalDependencies.has(name) + ) { + // If the dependency is a local project that is decoupled, then we need to ensure that it is not specified + // as a workspace project. If it is, then we need to update the package.json to remove the workspace notation. + this._terminal.writeWarningLine( + `"${rushProject.packageName}" depends on package ${name}@${version}, but also lists it in ` + + `its "decoupledLocalDependencies" array. Either update the host project's package.json to use ` + + `a version from an external feed instead of "workspace:" notation, or remove the dependency from the ` + + `host project's "decoupledLocalDependencies" array in rush.json.` + ); + throw new AlreadyReportedError(); + } else if (!rushProject.decoupledLocalDependencies.has(name)) { + // Already specified as a local project. Allow the package manager to validate this + continue; + } + } + + // Save the package.json if we modified the version references and warn that the package.json was modified + if (packageJson.saveIfModified()) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `"${rushProject.packageName}" depends on one or more workspace packages which did not use "workspace:" ` + + 'notation. The package.json has been modified and must be committed to source control.' + ) + ); + } + + // Now validate that the shrinkwrap file matches what is in the package.json + if (await shrinkwrapFile?.isWorkspaceProjectModifiedAsync(rushProject, subspace, variant)) { + shrinkwrapWarnings.push( + `Dependencies of project "${rushProject.packageName}" do not match the current shrinkwrap.` + ); + shrinkwrapIsUpToDate = false; + } + + const dependencyMetaList: ReadonlyArray = packageJson.dependencyMetaList; + if (dependencyMetaList.length !== 0) { + const dependenciesMeta: IDependenciesMetaTable = {}; + for (const dependencyMeta of dependencyMetaList) { + dependenciesMeta[dependencyMeta.name] = { + injected: dependencyMeta.injected + }; + } + + // get the relative path from common temp folder to package folder, to align with the value in pnpm-lock.yaml + const relativePathFromTempFolderToPackageFolder: string = Path.convertToSlashes( + `${relativeFromTempFolderToRootFolder}/${rushProject.projectRelativeFolder}` + ); + expectedDependenciesMetaByProjectRelativePath[relativePathFromTempFolderToPackageFolder] = + dependenciesMeta; + } + } + + // Build a object for dependenciesMeta settings in pnpm-lock.yaml + // key is the package path, value is the dependenciesMeta info for that package + const lockfileDependenciesMetaByProjectRelativePath: { [key: string]: IDependenciesMetaTable } = {}; + if (shrinkwrapFile?.importers !== undefined) { + for (const [key, value] of shrinkwrapFile?.importers) { + const projectRelativePath: string = Path.convertToSlashes(key); + + // we only need to verify packages that exist in package.json and pnpm-lock.yaml + // PNPM won't actively remove deleted packages in importers, unless it has to + // so it is possible that a deleted package still showing in pnpm-lock.yaml + if (expectedDependenciesMetaByProjectRelativePath[projectRelativePath] === undefined) { + continue; + } + if (value.dependenciesMeta !== undefined) { + lockfileDependenciesMetaByProjectRelativePath[projectRelativePath] = value.dependenciesMeta; + } + } + } + + // Now, we compare these two objects to see if they are equal or not + const dependenciesMetaAreEqual: boolean = Objects.areDeepEqual( + expectedDependenciesMetaByProjectRelativePath, + lockfileDependenciesMetaByProjectRelativePath + ); + + if (!dependenciesMetaAreEqual) { + shrinkwrapWarnings.push( + "The dependenciesMeta settings in one or more package.json don't match the current shrinkwrap." + ); + shrinkwrapIsUpToDate = false; + } + + // Check if overrides and globalOverrides are the same + const pnpmOptions: PnpmOptionsConfiguration = + subspace.getPnpmOptions() || this.rushConfiguration.pnpmOptions; + + const overridesAreEqual: boolean = Objects.areDeepEqual>( + pnpmOptions.globalOverrides ?? {}, + shrinkwrapFile?.overrides ? Object.fromEntries(shrinkwrapFile?.overrides) : {} + ); + + if (!overridesAreEqual) { + shrinkwrapWarnings.push("The overrides settings doesn't match the current shrinkwrap."); + shrinkwrapIsUpToDate = false; + } + + // Check if packageExtensionsChecksum matches globalPackageExtension's 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(); + } + } + + const globalPackageExtensions: Record | undefined = + pnpmOptions.globalPackageExtensions; + // https://github.com/pnpm/pnpm/blob/ba9409ffcef0c36dc1b167d770a023c87444822d/pkg-manager/core/src/install/index.ts#L331 + if (globalPackageExtensions && Object.keys(globalPackageExtensions).length !== 0) { + if (packageExtensionsChecksumAlgorithm) { + // In PNPM v10, the algorithm changed to SHA256 and the digest changed from hex to base64 + packageExtensionsChecksum = await createObjectChecksumAsync(globalPackageExtensions); + } else { + packageExtensionsChecksum = createObjectChecksumLegacy(globalPackageExtensions); + } + } + } + + const packageExtensionsChecksumAreEqual: boolean = + 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); + + // Set catalog definitions in the workspace file if specified + if (pnpmOptions.globalCatalogs) { + if ( + this.rushConfiguration.rushConfigurationJson.pnpmVersion !== undefined && + semver.lt(this.rushConfiguration.rushConfigurationJson.pnpmVersion, '9.5.0') + ) { + this._terminal.writeWarningLine( + Colorize.yellow( + `Your version of pnpm (${this.rushConfiguration.rushConfigurationJson.pnpmVersion}) ` + + `doesn't support the "globalCatalogs" fields in ` + + `${this.rushConfiguration.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}. ` + + 'Remove these fields or upgrade to pnpm 9.5.0 or newer.' + ) + ); + } + + const catalogs: Record> = {}; + + if (pnpmOptions.globalCatalogs) { + Object.assign(catalogs, pnpmOptions.globalCatalogs); + } + + workspaceFile.setCatalogs(catalogs); + } + + // 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 }); + + return { shrinkwrapIsUpToDate, shrinkwrapWarnings }; + } + + protected async canSkipInstallAsync( + lastModifiedDate: Date, + subspace: Subspace, + variant: string | undefined + ): Promise { + if (!(await super.canSkipInstallAsync(lastModifiedDate, subspace, variant))) { + return false; + } + + const potentiallyChangedFiles: string[] = []; + + 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' + ); + + if (FileSystem.exists(pnpmWorkspaceFilename)) { + potentiallyChangedFiles.push(pnpmWorkspaceFilename); + } + } + + // 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); + }) + ); + + // NOTE: If any of the potentiallyChangedFiles does not exist, then isFileTimestampCurrent() + // returns false. + return Utilities.isFileTimestampCurrentAsync(lastModifiedDate, potentiallyChangedFiles); + } + + /** + * Runs "pnpm install" in the common folder. + */ + protected async installAsync(cleanInstall: boolean, subspace: Subspace): Promise { + // Example: "C:\MyRepo\common\temp\npm-local\node_modules\.bin\npm" + const packageManagerFilename: string = this.rushConfiguration.packageManagerToolFilename; + + const packageManagerEnv: NodeJS.ProcessEnv = InstallHelpers.getPackageManagerEnvironment( + this.rushConfiguration, + this.options + ); + if (ConsoleTerminalProvider.supportsColor) { + packageManagerEnv.FORCE_COLOR = '1'; + } + + const commonNodeModulesFolder: string = path.join( + subspace.getSubspaceTempFolderPath(), + RushConstants.nodeModulesFolderName + ); + + // Is there an existing "node_modules" folder to consider? + if (FileSystem.exists(commonNodeModulesFolder)) { + // Should we delete the entire "node_modules" folder? + if (cleanInstall) { + // YES: Delete "node_modules" + + // Explain to the user why we are hosing their node_modules folder + // eslint-disable-next-line no-console + console.log('Deleting files from ' + commonNodeModulesFolder); + + this.installRecycler.moveFolder(commonNodeModulesFolder); + + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } + } + + const doInstallInternalAsync = async (options: IInstallManagerOptions): Promise => { + // Run "npm install" in the common folder + // To ensure that the output is always colored, set the option "--color=always", even when it's piped. + // Without this argument, certain text that should be colored (such as red) will appear white. + const installArgs: string[] = ['install']; + this.pushConfigurationArgs(installArgs, options, subspace); + + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.bold( + `Running "${this.rushConfiguration.packageManager} install" in` + + ` ${subspace.getSubspaceTempFolderPath()}` + ) + + '\n' + ); + + // If any diagnostic options were specified, then show the full command-line + if ( + this.options.debug || + this.options.collectLogFile || + this.options.networkConcurrency || + this.options.onlyShrinkwrap + ) { + // eslint-disable-next-line no-console + console.log( + '\n' + + Colorize.green('Invoking package manager: ') + + FileSystem.getRealPath(packageManagerFilename) + + ' ' + + installArgs.join(' ') + + '\n' + ); + } + + // Store the tip IDs that should be printed. + // They will be printed all at once *after* the install + const tipIDsToBePrinted: Set = new Set(); + const pnpmTips: ICustomTipInfo[] = []; + for (const [customTipId, customTip] of Object.entries(PNPM_CUSTOM_TIPS)) { + if ( + this.rushConfiguration.customTipsConfiguration.providedCustomTipsByTipId.has( + customTipId as CustomTipId + ) + ) { + pnpmTips.push(customTip); + } + } + + 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); + } + } + } + : undefined; + try { + await Utilities.executeCommandWithRetryAsync( + { + command: packageManagerFilename, + args: installArgs, + workingDirectory: subspace.getSubspaceTempFolderPath(), + environment: packageManagerEnv, + suppressOutput: false, + onStdoutStreamChunk: onPnpmStdoutChunk + }, + this.options.maxInstallAttempts, + () => { + if (this.rushConfiguration.isPnpm) { + this._terminal.writeWarningLine(`Deleting the "node_modules" folder`); + this.installRecycler.moveFolder(commonNodeModulesFolder); + + // Leave the pnpm-store as is for the retry. This ensures that packages that have already + // been downloaded need not be downloaded again, thereby potentially increasing the chances + // of a subsequent successful install. + + Utilities.createFolderWithRetry(commonNodeModulesFolder); + } + } + ); + } finally { + // The try-finally is to avoid the tips NOT being printed if the install fails. + // NOT catching the error because we want to keep the other behaviors (i.e., the error will be caught and handle in upper layers). + + if (tipIDsToBePrinted.size > 0) { + this._terminal.writeLine(); + for (const tipID of tipIDsToBePrinted) { + this.rushConfiguration.customTipsConfiguration._showTip(this._terminal, tipID); + } + } + } + }; + + const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; + if ( + this.options.allowShrinkwrapUpdates && + experiments.usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate + ) { + await doInstallInternalAsync({ + ...this.options, + onlyShrinkwrap: true + }); + + await doInstallInternalAsync({ + ...this.options, + allowShrinkwrapUpdates: false + }); + } else { + await doInstallInternalAsync(this.options); + } + + // If all attempts fail we just terminate. No special handling needed. + + // 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), + ...this.rushConfiguration.projects.map((project) => { + return path.join(project.projectFolder, RushConstants.nodeModulesFolderName); + }) + ]; + + for (const nodeModulesFolder of projectNodeModulesFolders) { + FileSystem.ensureFolder(nodeModulesFolder); + } + + // eslint-disable-next-line no-console + console.log(''); + } + + protected async postInstallAsync(subspace: Subspace): Promise { + // Grab the temp shrinkwrap, as this was the most recently completed install. It may also be + // 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() + ); + + if (tempShrinkwrapFile) { + // Write or delete all project shrinkwraps related to the install + await Async.forEachAsync( + subspace.getProjects(), + async (project) => { + await tempShrinkwrapFile.getProjectShrinkwrap(project)?.updateProjectShrinkwrapAsync(); + }, + { concurrency: 10 } + ); + } else if (this.rushConfiguration.isPnpm && this.rushConfiguration.pnpmOptions?.useWorkspaces) { + // If we're in PNPM workspace mode and PNPM didn't create a shrinkwrap file, + // there are no dependencies. Generate empty shrinkwrap files for all projects. + await Async.forEachAsync( + subspace.getProjects(), + async (project) => { + await BaseProjectShrinkwrapFile.saveEmptyProjectShrinkwrapFileAsync(project); + }, + { concurrency: 10 } + ); + } else { + // This is an unexpected case + throw new Error( + 'A shrinkwrap file does not exist after after successful installation. This probably indicates a ' + + 'bug in the package manager.' + ); + } + + // If the splitWorkspaceCompatibility is enabled for subspaces, create symlinks to mimic the behaviour + // of having the node_modules folder created directly in the project folder. This requires symlinking two categories: + // 1) Symlink any packages that are declared to be publicly hoisted, such as by using public-hoist-pattern in .npmrc. + // This creates a symlink from /node_modules/ -> temp//node_modules/ + // 2) Symlink any workspace packages that are declared in the temp folder, as some packages may expect these packages to exist + // in the node_modules folder. + // This creates a symlink from temp//node_modules/ -> + if ( + this.rushConfiguration.subspacesFeatureEnabled && + this.rushConfiguration.subspacesConfiguration?.splitWorkspaceCompatibility + ) { + const tempNodeModulesPath: string = `${subspace.getSubspaceTempFolderPath()}/node_modules`; + const modulesFilePath: string = `${tempNodeModulesPath}/${RushConstants.pnpmModulesFilename}`; + if ( + subspace.subspaceName.startsWith('split_') && + subspace.getProjects().length === 1 && + (await FileSystem.existsAsync(modulesFilePath)) + ) { + // 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 + }) as IPnpmModules; + const { hoistedDependencies } = yamlContent; + const subspaceProject: RushConfigurationProject = subspace.getProjects()[0]; + const projectNodeModulesPath: string = `${subspaceProject.projectFolder}/node_modules`; + for (const value of Object.values(hoistedDependencies)) { + for (const [filePath, type] of Object.entries(value)) { + if (type === 'public') { + if (Utilities.existsOrIsSymlink(`${projectNodeModulesPath}/${filePath}`)) { + await FileSystem.deleteFolderAsync(`${projectNodeModulesPath}/${filePath}`); + } + // If we don't already have a symlink for this package, create one + const parentDir: string = Utilities.trimAfterLastSlash(`${projectNodeModulesPath}/${filePath}`); + await FileSystem.ensureFolderAsync(parentDir); + await BaseLinkManager._createSymlinkAsync({ + linkTargetPath: `${tempNodeModulesPath}/${filePath}`, + newLinkPath: `${projectNodeModulesPath}/${filePath}`, + symlinkKind: SymlinkKind.Directory + }); + } + } + } + } + + // Look for any workspace linked packages anywhere in this subspace, symlink them from the temp node_modules folder. + const subspaceDependencyProjects: Set = new Set(); + for (const subspaceProject of subspace.getProjects()) { + for (const dependencyProject of subspaceProject.dependencyProjects) { + subspaceDependencyProjects.add(dependencyProject); + } + } + for (const dependencyProject of subspaceDependencyProjects) { + const symlinkToCreate: string = `${tempNodeModulesPath}/${dependencyProject.packageName}`; + if (!Utilities.existsOrIsSymlink(symlinkToCreate)) { + const parentFolder: string = Utilities.trimAfterLastSlash(symlinkToCreate); + await FileSystem.ensureFolderAsync(parentFolder); + await BaseLinkManager._createSymlinkAsync({ + linkTargetPath: dependencyProject.projectFolder, + newLinkPath: symlinkToCreate, + symlinkKind: SymlinkKind.Directory + }); + } + } + } + // TODO: Remove when "rush link" and "rush unlink" are deprecated + await new FlagFile( + subspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ).createAsync(); + } + + /** + * Used when invoking the NPM tool. Appends the common configuration options + * to the command-line. + */ + protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions, subspace: Subspace): void { + super.pushConfigurationArgs(args, options, subspace); + + // Add workspace-specific args + if (this.rushConfiguration.isPnpm) { + args.push('--recursive'); + args.push('--link-workspace-packages', 'false'); + + if (process.stdout.isTTY) { + // If we're on a TTY console and something else didn't set a `--reporter` parameter, + // explicitly set the default reporter. This fixes an issue where, when the pnpm + // output is being monitored to match custom tips, pnpm will detect a non-TTY + // stdout stream and use the `append-only` reporter. + // + // See docs here: https://pnpm.io/cli/install#--reportername + let includesReporterArg: boolean = false; + for (const arg of args) { + if (arg.startsWith('--reporter')) { + includesReporterArg = true; + break; + } + } + + if (!includesReporterArg) { + args.push('--reporter', 'default'); + } + } + + for (const arg of this.options.pnpmFilterArgumentValues) { + args.push('--filter', arg); + } + } + } +} + +/** + * Source: https://github.com/pnpm/pnpm/blob/ba9409ffcef0c36dc1b167d770a023c87444822d/pkg-manager/core/src/install/index.ts#L821-L824 + */ +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/installManager/doBasicInstallAsync.ts b/libraries/rush-lib/src/logic/installManager/doBasicInstallAsync.ts new file mode 100644 index 00000000000..05d3aa49c89 --- /dev/null +++ b/libraries/rush-lib/src/logic/installManager/doBasicInstallAsync.ts @@ -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 type { ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import type { BaseInstallManager } from '../base/BaseInstallManager'; +import type { IInstallManagerOptions } from '../base/BaseInstallManagerTypes'; +import { InstallManagerFactory } from '../InstallManagerFactory'; +import { SetupChecks } from '../SetupChecks'; +import { PurgeManager } from '../PurgeManager'; +import { VersionMismatchFinder } from '../versionMismatch/VersionMismatchFinder'; +import type { Subspace } from '../../api/Subspace'; + +export interface IRunInstallOptions { + afterInstallAsync?: IInstallManagerOptions['afterInstallAsync']; + beforeInstallAsync?: IInstallManagerOptions['beforeInstallAsync']; + rushConfiguration: RushConfiguration; + rushGlobalFolder: RushGlobalFolder; + isDebug: boolean; + terminal: ITerminal; + variant: string | undefined; + subspace: Subspace; +} + +export async function doBasicInstallAsync(options: IRunInstallOptions): Promise { + const { + rushConfiguration, + rushGlobalFolder, + isDebug, + variant, + terminal, + beforeInstallAsync, + afterInstallAsync, + subspace + } = options; + + VersionMismatchFinder.ensureConsistentVersions(rushConfiguration, terminal, { + variant, + subspace + }); + SetupChecks.validate(rushConfiguration); + + const purgeManager: typeof PurgeManager.prototype = new PurgeManager(rushConfiguration, rushGlobalFolder); + + const installManager: BaseInstallManager = await InstallManagerFactory.getInstallManagerAsync( + rushConfiguration, + rushGlobalFolder, + purgeManager, + { + debug: isDebug, + allowShrinkwrapUpdates: false, + checkOnly: false, + bypassPolicy: false, + noLink: false, + fullUpgrade: false, + recheckShrinkwrap: false, + offline: false, + collectLogFile: false, + pnpmFilterArgumentValues: [], + selectedProjects: new Set(rushConfiguration.projects), + maxInstallAttempts: 1, + networkConcurrency: undefined, + subspace, + terminal, + variant, + afterInstallAsync, + beforeInstallAsync + } + ); + + try { + await installManager.doInstallAsync(); + } finally { + await purgeManager.startDeleteAllAsync(); + } +} diff --git a/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts b/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts new file mode 100644 index 00000000000..97e4098d7ef --- /dev/null +++ b/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts @@ -0,0 +1,326 @@ +// 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 tar from 'tar'; +import readPackageTree from 'read-package-tree'; + +import { FileSystem, FileConstants, LegacyAdapters } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { RushConstants } from '../RushConstants'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { Utilities } from '../../utilities/Utilities'; +import { NpmPackage, type IResolveOrCreateResult, PackageDependencyKind } from './NpmPackage'; +import { PackageLookup } from '../PackageLookup'; +import { BaseLinkManager, SymlinkKind } from '../base/BaseLinkManager'; + +interface IQueueItem { + // A project from somewhere under "common/temp/node_modules" + commonPackage: NpmPackage; + + // A symlinked virtual package that we will create somewhere under "this-project/node_modules" + localPackage: NpmPackage; + + // If we encounter a dependency listed in decoupledLocalDependencies, this will be set to the root + // of the localPackage subtree where we will stop creating local links. + cyclicSubtreeRoot: NpmPackage | undefined; +} + +export class NpmLinkManager extends BaseLinkManager { + protected async _linkProjectsAsync(): Promise { + const npmPackage: readPackageTree.Node = await LegacyAdapters.convertCallbackToPromise< + readPackageTree.Node, + Error, + string + >(readPackageTree, this._rushConfiguration.commonTempFolder); + + const commonRootPackage: NpmPackage = NpmPackage.createFromNpm(npmPackage); + + const commonPackageLookup: PackageLookup = new PackageLookup(); + commonPackageLookup.loadTree(commonRootPackage); + + for (const rushProject of this._rushConfiguration.projects) { + // eslint-disable-next-line no-console + console.log(`\nLINKING: ${rushProject.packageName}`); + await this._linkProjectAsync(rushProject, commonRootPackage, commonPackageLookup); + } + } + + /** + * This is called once for each local project from Rush.json. + * @param project The local project that we will create symlinks for + * @param commonRootPackage The common/temp/package.json package + * @param commonPackageLookup A dictionary for finding packages under common/temp/node_modules + */ + private async _linkProjectAsync( + project: RushConfigurationProject, + commonRootPackage: NpmPackage, + commonPackageLookup: PackageLookup + ): Promise { + let commonProjectPackage: NpmPackage | undefined = commonRootPackage.getChildByName( + project.tempProjectName + ) as NpmPackage; + if (!commonProjectPackage) { + // Normally we would expect the temp project to have been installed into the common\node_modules + // folder. However, if it was recently added, "rush install" doesn't technically require + // this, as long as its dependencies can be found at the root of the NPM shrinkwrap file. + // This avoids the need to run "rush generate" unnecessarily. + + // Example: "project1" + const unscopedTempProjectName: string = this._rushConfiguration.packageNameParser.getUnscopedName( + project.tempProjectName + ); + + // Example: "C:\MyRepo\common\temp\projects\project1 + const extractedFolder: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.rushTempProjectsFolderName, + unscopedTempProjectName + ); + + // Example: "C:\MyRepo\common\temp\projects\project1.tgz" + const tarballFile: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.rushTempProjectsFolderName, + unscopedTempProjectName + '.tgz' + ); + + // Example: "C:\MyRepo\common\temp\projects\project1\package.json" + const packageJsonFilename: string = path.join(extractedFolder, 'package', FileConstants.PackageJson); + + Utilities.createFolderWithRetry(extractedFolder); + tar.extract({ + cwd: extractedFolder, + file: tarballFile, + sync: true + }); + + // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp\project1" + const installFolderName: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + RushConstants.rushTempNpmScope, + unscopedTempProjectName + ); + + commonProjectPackage = NpmPackage.createVirtualTempPackage(packageJsonFilename, installFolderName); + + // remove the extracted tarball contents + FileSystem.deleteFile(packageJsonFilename); + FileSystem.deleteFile(extractedFolder); + + commonRootPackage.addChild(commonProjectPackage); + } + + // TODO: Validate that the project's package.json still matches the common folder + const localProjectPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( + project.packageJsonEditor.name, + commonProjectPackage.version, + commonProjectPackage.dependencies, + project.projectFolder + ); + + const queue: IQueueItem[] = []; + queue.push({ + commonPackage: commonProjectPackage, + localPackage: localProjectPackage, + cyclicSubtreeRoot: undefined + }); + + for (;;) { + const queueItem: IQueueItem | undefined = queue.shift(); + if (!queueItem) { + break; + } + + // A project from somewhere under "common/temp/node_modules" + const commonPackage: NpmPackage = queueItem.commonPackage; + + // A symlinked virtual package somewhere under "this-project/node_modules", + // where "this-project" corresponds to the "project" parameter for linkProject(). + const localPackage: NpmPackage = queueItem.localPackage; + + // If we encounter a dependency listed in decoupledLocalDependencies, this will be set to the root + // of the localPackage subtree where we will stop creating local links. + const cyclicSubtreeRoot: NpmPackage | undefined = queueItem.cyclicSubtreeRoot; + + // NOTE: It's important that this traversal follows the dependencies in the Common folder, + // because for Rush projects this will be the union of + // devDependencies / dependencies / optionalDependencies. + for (const dependency of commonPackage.dependencies) { + let startingCyclicSubtree: boolean = false; + + // Should this be a "local link" to a top-level Rush project (i.e. versus a regular link + // into the Common folder)? + const matchedRushPackage: RushConfigurationProject | undefined = + this._rushConfiguration.getProjectByName(dependency.name); + + if (matchedRushPackage) { + const matchedVersion: string = matchedRushPackage.packageJsonEditor.version; + + // The dependency name matches an Rush project, but are there any other reasons not + // to create a local link? + if (cyclicSubtreeRoot) { + // DO NOT create a local link, because this is part of an existing + // decoupledLocalDependencies subtree + } else if (project.decoupledLocalDependencies.has(dependency.name)) { + // DO NOT create a local link, because we are starting a new + // decoupledLocalDependencies subtree + startingCyclicSubtree = true; + } else if ( + dependency.kind !== PackageDependencyKind.LocalLink && + !semver.satisfies(matchedVersion, dependency.versionRange) + ) { + // DO NOT create a local link, because the local project's version isn't SemVer compatible. + + // (Note that in order to make version bumping work as expected, we ignore SemVer for + // immediate dependencies of top-level projects, indicated by PackageDependencyKind.LocalLink. + // Is this wise?) + + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `Rush will not locally link ${dependency.name} for ${localPackage.name}` + + ` because the requested version "${dependency.versionRange}" is incompatible` + + ` with the local version ${matchedVersion}` + ) + ); + } else { + // Yes, it is compatible, so create a symlink to the Rush project. + // Is the dependency already resolved? + const resolution: IResolveOrCreateResult = localPackage.resolveOrCreate(dependency.name); + + if (!resolution.found || resolution.found.version !== matchedVersion) { + // We did not find a suitable match, so place a new local package that + // symlinks to the Rush project + const newLocalFolderPath: string = path.join( + resolution.parentForCreate!.folderPath, + 'node_modules', + dependency.name + ); + + const newLocalPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( + dependency.name, + matchedVersion, + // Since matchingRushProject does not have a parent, its dependencies are + // guaranteed to be already fully resolved inside its node_modules folder. + [], + newLocalFolderPath + ); + + newLocalPackage.symlinkTargetFolderPath = matchedRushPackage.projectFolder; + + resolution.parentForCreate!.addChild(newLocalPackage); + + // (There are no dependencies, so we do not need to push it onto the queue.) + } + + continue; + } + } + + // We can't symlink to an Rush project, so instead we will symlink to a folder + // under the "Common" folder + const commonDependencyPackage: NpmPackage | undefined = commonPackage.resolve(dependency.name); + if (commonDependencyPackage) { + // This is the version that was chosen when "npm install" ran in the common folder + const effectiveDependencyVersion: string | undefined = commonDependencyPackage.version; + + // Is the dependency already resolved? + let resolution: IResolveOrCreateResult; + if (!cyclicSubtreeRoot || !matchedRushPackage) { + // Perform normal module resolution. + resolution = localPackage.resolveOrCreate(dependency.name); + } else { + // We are inside a decoupledLocalDependencies subtree (i.e. cyclicSubtreeRoot != undefined), + // and the dependency is a local project (i.e. matchedRushPackage != undefined), so + // we use a special module resolution strategy that places everything under the + // cyclicSubtreeRoot. + resolution = localPackage.resolveOrCreate(dependency.name, cyclicSubtreeRoot); + } + + if (!resolution.found || resolution.found.version !== effectiveDependencyVersion) { + // We did not find a suitable match, so place a new local package + + const newLocalFolderPath: string = path.join( + resolution.parentForCreate!.folderPath, + 'node_modules', + commonDependencyPackage.name + ); + + const newLocalPackage: NpmPackage = NpmPackage.createLinkedNpmPackage( + commonDependencyPackage.name, + commonDependencyPackage.version, + commonDependencyPackage.dependencies, + newLocalFolderPath + ); + + const commonPackageFromLookup: NpmPackage | undefined = commonPackageLookup.getPackage( + newLocalPackage.nameAndVersion + ) as NpmPackage; + if (!commonPackageFromLookup) { + throw new Error( + `The ${localPackage.name}@${localPackage.version} package was not found` + + ` in the common folder` + ); + } + newLocalPackage.symlinkTargetFolderPath = commonPackageFromLookup.folderPath; + + let newCyclicSubtreeRoot: NpmPackage | undefined = cyclicSubtreeRoot; + if (startingCyclicSubtree) { + // If we are starting a new subtree, then newLocalPackage will be its root + // NOTE: cyclicSubtreeRoot is guaranteed to be undefined here, since we never start + // a new tree inside an existing tree + newCyclicSubtreeRoot = newLocalPackage; + } + + resolution.parentForCreate!.addChild(newLocalPackage); + queue.push({ + commonPackage: commonDependencyPackage, + localPackage: newLocalPackage, + cyclicSubtreeRoot: newCyclicSubtreeRoot + }); + } + } else { + if (dependency.kind !== PackageDependencyKind.Optional) { + throw new Error( + `The dependency "${dependency.name}" needed by "${localPackage.name}"` + + ` was not found in the common folder -- do you need to run "rush install"?` + ); + } else { + // eslint-disable-next-line no-console + console.log('Skipping optional dependency: ' + dependency.name); + } + } + } + } + + // When debugging, you can uncomment this line to dump the data structure + // to the console: + // localProjectPackage.printTree(); + + await NpmLinkManager._createSymlinksForTopLevelProjectAsync(localProjectPackage); + + // Also symlink the ".bin" folder + if (localProjectPackage.children.length > 0) { + const commonBinFolder: string = path.join( + this._rushConfiguration.commonTempFolder, + 'node_modules', + '.bin' + ); + const projectBinFolder: string = path.join(localProjectPackage.folderPath, 'node_modules', '.bin'); + + 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/NpmOptionsConfiguration.ts b/libraries/rush-lib/src/logic/npm/NpmOptionsConfiguration.ts new file mode 100644 index 00000000000..b25db65c2ad --- /dev/null +++ b/libraries/rush-lib/src/logic/npm/NpmOptionsConfiguration.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 IPackageManagerOptionsJsonBase, + PackageManagerOptionsConfigurationBase +} from '../base/BasePackageManagerOptionsConfiguration'; + +/** + * Part of IRushConfigurationJson. + * @internal + */ +export interface INpmOptionsJson extends IPackageManagerOptionsJsonBase {} + +/** + * Options that are only used when the NPM package manager is selected. + * + * @remarks + * It is valid to define these options in rush.json even if the NPM package manager + * is not being used. + * + * @public + */ +export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { + /** @internal */ + public constructor(json: INpmOptionsJson) { + super(json); + } +} diff --git a/apps/rush-lib/src/logic/npm/NpmPackage.ts b/libraries/rush-lib/src/logic/npm/NpmPackage.ts similarity index 87% rename from apps/rush-lib/src/logic/npm/NpmPackage.ts rename to libraries/rush-lib/src/logic/npm/NpmPackage.ts index e5f37ea6fe9..354b32475af 100644 --- a/apps/rush-lib/src/logic/npm/NpmPackage.ts +++ b/libraries/rush-lib/src/logic/npm/NpmPackage.ts @@ -1,17 +1,16 @@ -import * as path from 'path'; -import readPackageTree = require('read-package-tree'); -import { - JsonFile, - IPackageJson -} from '@rushstack/node-core-library'; - -import { - BasePackage, - IRushTempPackageJson -} from '../base/BasePackage'; +// 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 readPackageTree from 'read-package-tree'; + +import { JsonFile, type IPackageJson } from '@rushstack/node-core-library'; + +import { BasePackage, type IRushTempPackageJson } from '../base/BasePackage'; /** - * Used by the "rush link" algorithm when doing NPM package resolution. + * Used by the linking algorithm when doing NPM package resolution. */ export interface IResolveOrCreateResult { found: BasePackage | undefined; @@ -61,11 +60,12 @@ export class NpmPackage extends BasePackage { */ public dependencies: IPackageDependency[]; - private constructor(name: string, + private constructor( + name: string, version: string | undefined, dependencies: IPackageDependency[], - folderPath: string) { - + folderPath: string + ) { super(name, version, folderPath, undefined); this.dependencies = dependencies.slice(0); // clone the array this.parent = undefined; @@ -74,8 +74,12 @@ export class NpmPackage extends BasePackage { /** * Used by "npm link" when creating a Package object that represents symbolic links to be created. */ - public static createLinkedNpmPackage(name: string, version: string | undefined, dependencies: IPackageDependency[], - folderPath: string): NpmPackage { + public static createLinkedNpmPackage( + name: string, + version: string | undefined, + dependencies: IPackageDependency[], + folderPath: string + ): NpmPackage { return new NpmPackage(name, version, dependencies, folderPath); } @@ -91,11 +95,11 @@ export class NpmPackage extends BasePackage { const packageJson: IPackageJson = JsonFile.load(packageJsonFilename); const npmPackage: readPackageTree.Node = { children: [], - error: null, // eslint-disable-line @rushstack/no-null + error: null, id: 0, isLink: false, package: packageJson, - parent: null, // eslint-disable-line @rushstack/no-null + parent: null, path: installFolderName, realpath: installFolderName }; @@ -108,8 +112,9 @@ export class NpmPackage extends BasePackage { */ public static createFromNpm(npmPackage: readPackageTree.Node): NpmPackage { if (npmPackage.error) { - throw new Error(`Failed to parse package.json for ${path.basename(npmPackage.path)}:` - + ` ${npmPackage.error.message}`); + throw new Error( + `Failed to parse package.json for ${path.basename(npmPackage.path)}: ${npmPackage.error.message}` + ); } let dependencies: IPackageDependency[] = []; @@ -181,7 +186,7 @@ export class NpmPackage extends BasePackage { * or was found with an incompatible version. * * "cyclicSubtreeRoot" is a special optional parameter that specifies a different - * root for the tree; the cyclicDependencyProjects feature uses this to isolate + * root for the tree; the decoupledLocalDependencies feature uses this to isolate * certain devDependencies in their own subtree. */ public resolveOrCreate(dependencyName: string, cyclicSubtreeRoot?: NpmPackage): IResolveOrCreateResult { @@ -211,8 +216,7 @@ export class NpmPackage extends BasePackage { // could add a missing dependency. parentForCreate = currentParent; - if (!currentParent.parent - || (cyclicSubtreeRoot && currentParent === cyclicSubtreeRoot)) { + if (!currentParent.parent || (cyclicSubtreeRoot && currentParent === cyclicSubtreeRoot)) { // We reached the root without finding a match // parentForCreate will be the root. return { found: undefined, parentForCreate }; @@ -230,5 +234,4 @@ export class NpmPackage extends BasePackage { public resolve(dependencyName: string): NpmPackage | undefined { return this.resolveOrCreate(dependencyName).found as NpmPackage; } - -} \ No newline at end of file +} diff --git a/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts new file mode 100644 index 00000000000..f0dfe9c70d1 --- /dev/null +++ b/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile, FileSystem, InternalError } from '@rushstack/node-core-library'; + +import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { DependencySpecifier } from '../DependencySpecifier'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { BaseProjectShrinkwrapFile } from '../base/BaseProjectShrinkwrapFile'; +import type { Subspace } from '../../api/Subspace'; + +interface INpmShrinkwrapDependencyJson { + version: string; + from: string; + resolved: string; + dependencies: { [dependency: string]: INpmShrinkwrapDependencyJson }; +} + +interface INpmShrinkwrapJson { + name: string; + version: string; + dependencies: { [dependency: string]: INpmShrinkwrapDependencyJson }; +} + +export class NpmShrinkwrapFile extends BaseShrinkwrapFile { + public readonly isWorkspaceCompatible: boolean; + private _shrinkwrapJson: INpmShrinkwrapJson; + + private constructor(shrinkwrapJson: INpmShrinkwrapJson) { + super(); + this._shrinkwrapJson = shrinkwrapJson; + + // Normalize the data + if (!this._shrinkwrapJson.version) { + this._shrinkwrapJson.version = ''; + } + if (!this._shrinkwrapJson.name) { + this._shrinkwrapJson.name = ''; + } + if (!this._shrinkwrapJson.dependencies) { + this._shrinkwrapJson.dependencies = {}; + } + + // Workspaces not supported in NPM + this.isWorkspaceCompatible = false; + } + + public static loadFromFile(shrinkwrapJsonFilename: string): NpmShrinkwrapFile | undefined { + try { + const shrinkwrapContent: string = FileSystem.readFile(shrinkwrapJsonFilename); + return NpmShrinkwrapFile.loadFromString(shrinkwrapContent); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + return undefined; // file does not exist + } + throw new Error(`Error reading "${shrinkwrapJsonFilename}":\n ${(error as Error).message}`); + } + } + + public static loadFromString(shrinkwrapContent: string): NpmShrinkwrapFile { + // strip BOM + const data: string = + shrinkwrapContent.charCodeAt(0) === 0xfeff ? shrinkwrapContent.slice(1) : shrinkwrapContent; + + // We don't use JsonFile/jju here because shrinkwrap.json is a special NPM file format + // and typically very large, so we want to load it the same way that NPM does. + return new NpmShrinkwrapFile(JSON.parse(data)); + } + + /** @override */ + public getTempProjectNames(): ReadonlyArray { + return this._getTempProjectNames(this._shrinkwrapJson.dependencies); + } + + /** @override */ + protected serialize(): string { + return JsonFile.stringify(this._shrinkwrapJson); + } + + /** @override */ + protected 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, + dependencyName + ); + + if (!dependencyJson) { + return undefined; + } + + 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( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): DependencySpecifier | undefined { + // First, check under tempProjectName, as this is the first place we look during linking. + let dependencyJson: INpmShrinkwrapDependencyJson | undefined = undefined; + + const tempDependency: INpmShrinkwrapDependencyJson | undefined = NpmShrinkwrapFile.tryGetValue( + this._shrinkwrapJson.dependencies, + tempProjectName + ); + if (tempDependency && tempDependency.dependencies) { + dependencyJson = NpmShrinkwrapFile.tryGetValue( + tempDependency.dependencies, + dependencySpecifier.packageName + ); + } + + // Otherwise look at the root of the shrinkwrap file + if (!dependencyJson) { + return this.getTopLevelDependencyVersion(dependencySpecifier.packageName); + } + + return DependencySpecifier.parseWithCache(dependencySpecifier.packageName, dependencyJson.version); + } + + /** @override */ + public getProjectShrinkwrap( + project: RushConfigurationProject + ): BaseProjectShrinkwrapFile | undefined { + return undefined; + } + + /** @override */ + public async isWorkspaceProjectModifiedAsync( + project: RushConfigurationProject, + subspace: Subspace, + variant: string | undefined + ): Promise { + throw new InternalError('Not implemented'); + } +} diff --git a/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts b/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts new file mode 100644 index 00000000000..2616d46f3b7 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { OperationExecutionRecord } from './OperationExecutionRecord'; +import { OperationStatus } from './OperationStatus'; +import { RushConstants } from '../RushConstants'; + +/** + * Implementation of the async iteration protocol for a collection of IOperation objects. + * The async iterator will wait for an operation to be ready for execution, or terminate if there are no more operations. + * + * @remarks + * If the caller does not update dependencies prior to invoking `next()` on the iterator again, + * it must manually invoke `assignOperations()` after performing the updates, otherwise iterators will + * stall until another operations completes. + */ +export class AsyncOperationQueue + implements AsyncIterable, AsyncIterator +{ + private readonly _queue: OperationExecutionRecord[]; + private readonly _pendingIterators: ((result: IteratorResult) => void)[]; + private readonly _totalOperations: number; + private readonly _completedOperations: Set; + + private _isDone: boolean; + + /** + * @param operations - The set of operations to be executed + * @param sortFn - A function that sorts operations in reverse priority order: + * - Returning a positive value indicates that `a` should execute before `b`. + * - Returning a negative value indicates that `b` should execute before `a`. + * - Returning 0 indicates no preference. + */ + public constructor(operations: Iterable, sortFn: IOperationSortFunction) { + this._queue = computeTopologyAndSort(operations, sortFn); + this._pendingIterators = []; + this._totalOperations = this._queue.length; + this._isDone = false; + this._completedOperations = new Set(); + } + + /** + * For use with `for await (const operation of taskQueue)` + * @see {AsyncIterator} + */ + public next(): Promise> { + const { _pendingIterators: waitingIterators } = this; + + const promise: Promise> = new Promise( + (resolve: (result: IteratorResult) => void) => { + waitingIterators.push(resolve); + } + ); + + this.assignOperations(); + + return promise; + } + + /** + * Set a callback to be invoked when one operation is completed. + * If all operations are completed, set the queue to done, resolve all pending iterators in next cycle. + */ + public complete(record: OperationExecutionRecord): void { + this._completedOperations.add(record); + + // Apply status changes to direct dependents + if (record.status !== OperationStatus.Failure && record.status !== OperationStatus.Blocked) { + // Only do so if the operation did not fail or get blocked + for (const item of record.consumers) { + // Remove this operation from the dependencies, to unblock the scheduler + if ( + item.dependencies.delete(record) && + item.dependencies.size === 0 && + item.status === OperationStatus.Waiting + ) { + item.status = OperationStatus.Ready; + } + } + } + + this.assignOperations(); + + if (this._completedOperations.size === this._totalOperations) { + this._isDone = true; + } + } + + /** + * Routes ready operations with 0 dependencies to waiting iterators. Normally invoked as part of `next()`, but + * 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; + + // 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--) { + const record: OperationExecutionRecord = queue[i]; + + if ( + record.status === OperationStatus.Blocked || + record.status === OperationStatus.Skipped || + record.status === OperationStatus.Success || + record.status === OperationStatus.SuccessWithWarning || + record.status === OperationStatus.FromCache || + record.status === OperationStatus.NoOp || + record.status === OperationStatus.Failure || + record.status === OperationStatus.Aborted + ) { + // It shouldn't be on the queue, remove it + queue.splice(i, 1); + } else if (record.status === OperationStatus.Queued || record.status === OperationStatus.Executing) { + // This operation is currently executing + // next one plz :) + } else if (record.status === OperationStatus.Waiting) { + // This operation is not yet ready to be executed + // next one plz :) + continue; + } else if (record.status !== OperationStatus.Ready) { + // 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 + }); + } + // Otherwise operation is still waiting + } + + // 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; + } + + if (this._isDone) { + for (const resolveAsyncIterator of waitingIterators.splice(0)) { + resolveAsyncIterator({ + value: undefined, + done: true + }); + } + return; + } + } + + /** + * Returns this queue as an async iterator, such that multiple functions iterating this object concurrently + * receive distinct iteration results. + */ + public [Symbol.asyncIterator](): AsyncIterator { + return this; + } +} + +export interface IOperationSortFunction { + /** + * A function that sorts operations in reverse priority order: + * Returning a positive value indicates that `a` should execute before `b`. + * Returning a negative value indicates that `b` should execute before `a`. + * Returning 0 indicates no preference. + */ + (a: OperationExecutionRecord, b: OperationExecutionRecord): number; +} + +/** + * Performs a depth-first search to topologically sort the operations, subject to override via sortFn + */ +function computeTopologyAndSort( + operations: Iterable, + sortFn: IOperationSortFunction +): OperationExecutionRecord[] { + // Clone the set of operations as an array, so that we can sort it. + const queue: OperationExecutionRecord[] = Array.from(operations); + + // Create a collection for detecting visited nodes + const cycleDetectorStack: Set = new Set(); + for (const operation of queue) { + calculateCriticalPathLength(operation, cycleDetectorStack); + } + + return queue.sort(sortFn); +} + +/** + * Perform a depth-first search to find critical path length. + * Cycle detection comes at minimal additional cost. + */ +function calculateCriticalPathLength( + operation: OperationExecutionRecord, + dependencyChain: Set +): number { + if (dependencyChain.has(operation)) { + throw new Error( + 'A cyclic dependency was encountered:\n ' + + [...dependencyChain, operation] + .map((visitedTask) => visitedTask.name) + .reverse() + .join('\n -> ') + + `\nConsider using the decoupledLocalDependencies option in ${RushConstants.rushJsonFilename}.` + ); + } + + let { criticalPathLength } = operation; + + if (criticalPathLength !== undefined) { + // This has been visited already + return criticalPathLength; + } + + criticalPathLength = 0; + if (operation.consumers.size) { + dependencyChain.add(operation); + for (const consumer of operation.consumers) { + criticalPathLength = Math.max( + criticalPathLength, + calculateCriticalPathLength(consumer, dependencyChain) + ); + } + dependencyChain.delete(operation); + } + // Include the contribution from the current operation + operation.criticalPathLength = criticalPathLength + operation.weight; + + // Directly writing operations to an output collection here would yield a topological sorted set + // However, we want a bit more fine-tuning of the output than just the raw topology + + return criticalPathLength; +} diff --git a/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts b/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts new file mode 100644 index 00000000000..85376112da5 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts @@ -0,0 +1,354 @@ +// 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 { + IExecuteOperationsContext, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import type { Operation } from './Operation'; +import { clusterOperations, type IOperationBuildCacheContext } from './CacheableOperationPlugin'; +import { DisjointSet } from '../cobuild/DisjointSet'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; + +const PLUGIN_NAME: 'BuildPlanPlugin' = 'BuildPlanPlugin'; + +interface IBuildPlanOperationCacheContext { + cacheDisabledReason: IOperationBuildCacheContext['cacheDisabledReason']; +} + +interface ICobuildPlan { + summary: { + maxWidth: number; + maxDepth: number; + numberOfNodesPerDepth: number[]; + }; + operations: Operation[]; + clusters: Set[]; + buildCacheByOperation: Map; + clusterByOperation: Map>; +} + +export class BuildPlanPlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + } + + public apply(hooks: PhasedCommandHooks): void { + const terminal: ITerminal = this._terminal; + hooks.beforeExecuteOperations.tap(PLUGIN_NAME, createBuildPlan); + + function createBuildPlan( + recordByOperation: Map, + context: IExecuteOperationsContext + ): void { + const { projectConfigurations, inputsSnapshot } = context; + const disjointSet: DisjointSet = new DisjointSet(); + const operations: Operation[] = [...recordByOperation.keys()]; + for (const operation of operations) { + disjointSet.add(operation); + } + const buildCacheByOperation: Map = new Map< + Operation, + IBuildPlanOperationCacheContext + >(); + + for (const operation of operations) { + const { associatedProject, associatedPhase } = operation; + + 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); + logCobuildBuildPlan(buildPlan, terminal); + } + } +} + +/** + * Output the build plan summary, this will include the depth of the build plan, the width of the build plan, and + * the number of nodes at each depth. + * + * Example output: +``` +Build Plan Depth (deepest dependency tree): 3 +Build Plan Width (maximum parallelism): 7 +Number of Nodes per Depth: 2, 7, 5 +Plan @ Depth 0 has 2 nodes and 0 dependents: +- b (build) +- a (build) +Plan @ Depth 1 has 7 nodes and 2 dependents: +- c (build) +- d (build) +- f (pre-build) +- g (pre-build) +- e (build) +- f (build) +- g (build) +Plan @ Depth 2 has 5 nodes and 9 dependents: +- c (build) +- d (build) +- e (build) +- f (build) +- g (build) +``` + * The summary data can be useful for understanding the shape of the build plan. The depth of the build plan is the + * longest dependency chain in the build plan. The width of the build plan is the maximum number of operations that + * can be executed in parallel. The number of nodes per depth is the number of operations that can be executed in parallel + * at each depth. **This does not currently include clustering information, which further restricts which operations can + * be executed in parallel.** + * The depth data can be useful for debugging situations where cobuilds aren't utilizing multiple agents as expected. There may be + * some long dependency trees that can't be executed in parallel. Or there may be some key operations at the base of the + * build graph that are blocking the rest of the build. + */ +function generateCobuildPlanSummary(operations: Operation[], terminal: ITerminal): ICobuildPlan['summary'] { + const numberOfDependenciesByOperation: Map = new Map(); + + const queue: Operation[] = operations.filter((e) => e.dependencies.size === 0); + const seen: Set = new Set(queue); + for (const operation of queue) { + numberOfDependenciesByOperation.set(operation, 0); + } + + /** + * Traverse the build plan to determine the number of dependencies for each operation. This is done by starting + * at the base of the build plan and traversing the graph in a breadth-first manner. We use the parent operation + * to determine the number of dependencies for each child operation. This allows us to detect cases where no-op + * operations are strung together, and correctly mark the first real operation as being a root operation. + */ + while (queue.length > 0) { + const operation: Operation = queue.shift()!; + const increment: number = operation.isNoOp ? 0 : 1; + for (const consumer of operation.consumers) { + const numberOfDependencies: number = (numberOfDependenciesByOperation.get(operation) ?? 0) + increment; + numberOfDependenciesByOperation.set(consumer, numberOfDependencies); + if (!seen.has(consumer)) { + queue.push(consumer); + seen.add(consumer); + } + } + } + + const layerQueue: Operation[] = []; + for (const operation of operations) { + if (operation.isNoOp) { + continue; + } + + const numberOfDependencies: number = numberOfDependenciesByOperation.get(operation) ?? 0; + if (numberOfDependencies === 0) { + layerQueue.push(operation); + } + } + + let nextLayer: Set = new Set(); + const remainingOperations: Set = new Set(operations); + let depth: number = 0; + let maxWidth: number = layerQueue.length; + const numberOfNodes: number[] = [maxWidth]; + const depthToOperationsMap: Map> = new Map>(); + depthToOperationsMap.set(depth, new Set(layerQueue)); + + /** + * Determine the depth and width of the build plan. We start with the inner layer and gradually traverse layer by + * layer up the tree/graph until we have no more nodes to process. At each layer, we determine the + * number of executable operations. + */ + do { + if (layerQueue.length === 0) { + layerQueue.push(...nextLayer); + const realOperations: Operation[] = layerQueue.filter((e) => !e.isNoOp); + if (realOperations.length > 0) { + depth += 1; + depthToOperationsMap.set(depth, new Set(realOperations)); + numberOfNodes.push(realOperations.length); + } + const currentWidth: number = realOperations.length; + if (currentWidth > maxWidth) { + maxWidth = currentWidth; + } + nextLayer = new Set(); + + if (layerQueue.length === 0) { + break; + } + } + const leaf: Operation = layerQueue.shift()!; + if (remainingOperations.delete(leaf)) { + for (const consumer of leaf.consumers) { + nextLayer.add(consumer); + } + } + } while (remainingOperations.size > 0); + + terminal.writeLine(`Build Plan Depth (deepest dependency tree): ${depth + 1}`); + terminal.writeLine(`Build Plan Width (maximum parallelism): ${maxWidth}`); + terminal.writeLine(`Number of Nodes per Depth: ${numberOfNodes.join(', ')}`); + for (const [operationDepth, operationsAtDepth] of depthToOperationsMap) { + let numberOfDependents: number = 0; + for (let i: number = 0; i < operationDepth; i++) { + numberOfDependents += numberOfNodes[i]; + } + terminal.writeLine( + `Plan @ Depth ${operationDepth} has ${numberOfNodes[operationDepth]} nodes and ${numberOfDependents} dependents:` + ); + for (const operation of operationsAtDepth) { + if (operation.isNoOp !== true) { + terminal.writeLine(`- ${operation.name}`); + } + } + } + + return { + maxDepth: depth === 0 && numberOfNodes[0] !== 0 ? depth + 1 : 0, + maxWidth: maxWidth, + numberOfNodesPerDepth: numberOfNodes + }; +} + +function getName(op: Operation): string { + return op.name; +} + +/** + * Log the cobuild build plan by cluster. This is intended to help debug situations where cobuilds aren't + * utilizing multiple agents correctly. + */ +function createCobuildPlan( + disjointSet: DisjointSet, + terminal: ITerminal, + buildCacheByOperation: Map +): ICobuildPlan { + const clusters: Set[] = [...disjointSet.getAllSets()]; + const operations: Operation[] = clusters.flatMap((e) => Array.from(e)); + + const operationToClusterMap: Map> = new Map>(); + for (const cluster of clusters) { + for (const operation of cluster) { + operationToClusterMap.set(operation, cluster); + } + } + + return { + summary: generateCobuildPlanSummary(operations, terminal), + operations, + buildCacheByOperation, + clusterByOperation: operationToClusterMap, + clusters + }; +} + +/** + * This method logs in depth details about the cobuild plan, including the operations in each cluster, the dependencies + * for each cluster, and the reason why each operation is clustered. + */ +function logCobuildBuildPlan(buildPlan: ICobuildPlan, terminal: ITerminal): void { + const { operations, clusters, buildCacheByOperation, clusterByOperation } = buildPlan; + + const executionPlan: Operation[] = []; + for (const operation of operations) { + if (!operation.isNoOp) { + executionPlan.push(operation); + } + } + + // This is a lazy way of getting the waterfall chart, basically check for the latest + // dependency and put this operation after that finishes. + const spacingByDependencyMap: Map = new Map(); + for (let index: number = 0; index < executionPlan.length; index++) { + const operation: Operation = executionPlan[index]; + + const spacing: number = Math.max( + ...Array.from(operation.dependencies, (e) => { + const dependencySpacing: number | undefined = spacingByDependencyMap.get(e); + return dependencySpacing !== undefined ? dependencySpacing + 1 : 0; + }), + 0 + ); + spacingByDependencyMap.set(operation, spacing); + } + executionPlan.sort((a, b) => { + const aSpacing: number = spacingByDependencyMap.get(a) ?? 0; + const bSpacing: number = spacingByDependencyMap.get(b) ?? 0; + return aSpacing - bSpacing; + }); + + terminal.writeLine('##################################################'); + // Get the maximum name length for left padding. + let maxOperationNameLength: number = 1; + for (const operation of executionPlan) { + const name: string = getName(operation); + maxOperationNameLength = Math.max(maxOperationNameLength, name.length); + } + for (const operation of executionPlan) { + const spacing: number = spacingByDependencyMap.get(operation) ?? 0; + terminal.writeLine( + `${getName(operation).padStart(maxOperationNameLength + 1)}: ${'-'.repeat(spacing)}(${clusters.indexOf( + clusterByOperation.get(operation)! + )})` + ); + } + terminal.writeLine('##################################################'); + + function getDependenciesForCluster(cluster: Set): Set { + const dependencies: Set = new Set(); + for (const operation of cluster) { + for (const dependent of operation.dependencies) { + dependencies.add(dependent); + } + } + return dependencies; + } + + function dedupeShards(ops: Set): string[] { + const dedupedOperations: Set = new Set(); + for (const operation of ops) { + dedupedOperations.add(`${operation.associatedProject.packageName} (${operation.associatedPhase.name})`); + } + return [...dedupedOperations]; + } + + for (let clusterIndex: number = 0; clusterIndex < clusters.length; clusterIndex++) { + const cluster: Set = clusters[clusterIndex]; + const allClusterDependencies: Set = getDependenciesForCluster(cluster); + const outOfClusterDependencies: Set = new Set( + [...allClusterDependencies].filter((e) => !cluster.has(e)) + ); + + terminal.writeLine(`Cluster ${clusterIndex}:`); + terminal.writeLine(`- Dependencies: ${dedupeShards(outOfClusterDependencies).join(', ') || 'none'}`); + // Only log clustering info, if we did in fact cluster. + if (cluster.size > 1) { + terminal.writeLine( + `- Clustered by: \n${[...allClusterDependencies] + .filter((e) => buildCacheByOperation.get(e)?.cacheDisabledReason) + .map((e) => ` - (${e.name}) "${buildCacheByOperation.get(e)?.cacheDisabledReason ?? ''}"`) + .join('\n')}` + ); + } + terminal.writeLine( + `- Operations: ${Array.from(cluster, (e) => `${getName(e)}${e.isNoOp ? ' [SKIPPED]' : ''}`).join(', ')}` + ); + terminal.writeLine('--------------------------------------------------'); + } + terminal.writeLine('##################################################'); +} diff --git a/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts new file mode 100644 index 00000000000..bedb37d64c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts @@ -0,0 +1,788 @@ +// 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 { InternalError, NewlineKind, Sort } from '@rushstack/node-core-library'; +import { CollatedTerminal, type CollatedWriter } from '@rushstack/stream-collator'; +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 { OperationBuildCache } from '../buildCache/OperationBuildCache'; +import { RushConstants } from '../RushConstants'; +import type { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; +import { + initializeProjectLogFilesAsync, + getProjectLogFilePaths, + type ILogFilePaths +} from './ProjectLogWritable'; +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, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { OperationExecutionRecord } from './OperationExecutionRecord'; + +const PLUGIN_NAME: 'CacheablePhasedOperationPlugin' = 'CacheablePhasedOperationPlugin'; +const PERIODIC_CALLBACK_INTERVAL_IN_SECONDS: number = 10; + +export interface IProjectDeps { + files: { [filePath: string]: string }; + arguments: string; +} + +export interface IOperationBuildCacheContext { + isCacheWriteAllowed: boolean; + isCacheReadAllowed: boolean; + + operationBuildCache: OperationBuildCache | undefined; + cacheDisabledReason: string | undefined; + outputFolderNames: ReadonlyArray; + + cobuildLock: CobuildLock | undefined; + + // The id of the cluster contains the operation, used when acquiring cobuild lock + cobuildClusterId: string | undefined; + + // Controls the log for the cache subsystem + buildCacheTerminal: ITerminal | undefined; + buildCacheTerminalWritable: TerminalWritable | undefined; + + periodicCallback: PeriodicCallback; + cacheRestored: boolean; + isCacheReadAttempted: boolean; +} + +export interface ICacheableOperationPluginOptions { + allowWarningsInSuccessfulBuild: boolean; + buildCacheConfiguration: BuildCacheConfiguration; + cobuildConfiguration: CobuildConfiguration | undefined; + terminal: ITerminal; +} + +export class CacheableOperationPlugin implements IPhasedCommandPlugin { + private _buildCacheContextByOperation: Map = new Map(); + + private readonly _options: ICacheableOperationPluginOptions; + + public constructor(options: ICacheableOperationPluginOptions) { + this._options = options; + } + + public apply(hooks: PhasedCommandHooks): void { + const { allowWarningsInSuccessfulBuild, buildCacheConfiguration, cobuildConfiguration } = this._options; + + 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.` + ); + } + + const disjointSet: DisjointSet | undefined = cobuildConfiguration?.cobuildFeatureEnabled + ? new DisjointSet() + : undefined; + + for (const [operation, record] of recordByOperation) { + const { associatedProject, associatedPhase, runner, settings: operationSettings } = operation; + if (!runner) { + return; + } + + const { name: phaseName } = associatedPhase; + + const projectConfiguration: RushProjectConfiguration | undefined = + projectConfigurations.get(associatedProject); + + // 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 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 metadataFolderPath: string | undefined = record.metadataFolderPath; + + const outputFolderNames: string[] = metadataFolderPath ? [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, + 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; + }); + + // 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'); + + // 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; + } + } + } + } + } + ); + + hooks.beforeExecuteOperation.tapPromise( + PLUGIN_NAME, + async ( + runnerContext: IOperationRunnerContext & IOperationExecutionResult + ): Promise => { + if (this._buildCacheContextByOperation.size === 0) { + return; + } + + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(runnerContext.operation); + + if (!buildCacheContext) { + return; + } + + const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; + + const { + associatedProject: project, + associatedPhase: phase, + runner, + _operationMetadataManager: operationMetadataManager, + operation + } = record; + + if (!operation.enabled || !runner?.cacheable) { + return; + } + + 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 + }); + } + + const buildCacheTerminal: ITerminal = buildCacheContext.buildCacheTerminal; + + let operationBuildCache: OperationBuildCache | undefined = this._tryGetOperationBuildCache({ + buildCacheContext, + buildCacheConfiguration, + terminal: buildCacheTerminal, + record + }); + + // 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 + }); + 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}"` + ); + } + } + + 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) { + 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.isCacheReadAllowed) { + const restoreFromCacheSuccess: boolean = await restoreCacheAsync(operationBuildCache); + + 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; + } + } + }; + + 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, runner, enabled } = operation; + + if (!enabled || !runner?.cacheable) { + return; + } + + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(operation); + + if (!buildCacheContext) { + return; + } + + // No need to run for the following operation status + if (!record.isTerminal || record.status === OperationStatus.NoOp) { + return; + } + + 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 (!buildCacheTerminal) { + // This should not happen + throw new InternalError(`Build Cache Terminal is not created`); + } + + 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); + + // 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; + } + } + } 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; + } + } + + // 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(); + }); + } + + private _getBuildCacheContextByOperation(operation: Operation): IOperationBuildCacheContext | undefined { + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._buildCacheContextByOperation.get(operation); + return buildCacheContext; + } + + private _getBuildCacheContextByOperationOrThrow(operation: Operation): IOperationBuildCacheContext { + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(operation); + if (!buildCacheContext) { + // This should not happen + throw new InternalError(`Build cache context for operation ${operation.name} should be defined`); + } + return buildCacheContext; + } + + private _tryGetOperationBuildCache({ + buildCacheConfiguration, + buildCacheContext, + terminal, + record + }: { + buildCacheContext: IOperationBuildCacheContext; + buildCacheConfiguration: BuildCacheConfiguration | undefined; + terminal: ITerminal; + record: OperationExecutionRecord; + }): OperationBuildCache | undefined { + if (!buildCacheContext.operationBuildCache) { + const { cacheDisabledReason } = buildCacheContext; + if (cacheDisabledReason && !record.operation.settings?.allowCobuildWithoutCache) { + terminal.writeVerboseLine(cacheDisabledReason); + return; + } + + if (!buildCacheConfiguration) { + // Unreachable, since this will have set `cacheDisabledReason`. + return; + } + + buildCacheContext.operationBuildCache = OperationBuildCache.forOperation(record, { + buildCacheConfiguration, + terminal + }); + } + + return buildCacheContext.operationBuildCache; + } + + // Get an OperationBuildCache only cache/restore log files + private async _tryGetLogOnlyOperationBuildCacheAsync(options: { + buildCacheContext: IOperationBuildCacheContext; + buildCacheConfiguration: BuildCacheConfiguration | undefined; + cobuildConfiguration: CobuildConfiguration; + record: IOperationRunnerContext & IOperationExecutionResult; + terminal: ITerminal; + }): Promise { + const { buildCacheContext, buildCacheConfiguration, cobuildConfiguration, record, terminal } = options; + + if (!buildCacheConfiguration?.buildCacheEnabled) { + return; + } + + const { outputFolderNames } = buildCacheContext; + + const hasher: crypto.Hash = crypto.createHash('sha1'); + hasher.update(record.getStateHash()); + + if (cobuildConfiguration.cobuildContextId) { + hasher.update( + `${RushConstants.hashDelimiter}cobuildContextId=${cobuildConfiguration.cobuildContextId}` + ); + } + + hasher.update(`${RushConstants.hashDelimiter}logFilesOnly=1`); + + const operationStateHash: string = hasher.digest('hex'); + + const { associatedPhase, associatedProject } = record.operation; + + const operationBuildCache: OperationBuildCache = OperationBuildCache.getOperationBuildCache({ + project: associatedProject, + projectOutputFolderNames: outputFolderNames, + buildCacheConfiguration, + terminal, + operationStateHash, + phaseName: associatedPhase.name + }); + + buildCacheContext.operationBuildCache = operationBuildCache; + + return operationBuildCache; + } + + private async _tryGetCobuildLockAsync({ + cobuildConfiguration, + buildCacheContext, + operationBuildCache, + packageName, + phaseName + }: { + cobuildConfiguration: CobuildConfiguration | undefined; + buildCacheContext: IOperationBuildCacheContext; + operationBuildCache: OperationBuildCache | undefined; + packageName: string; + phaseName: string; + }): Promise { + if (!buildCacheContext.cobuildLock) { + 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, + operationBuildCache, + cobuildClusterId: buildCacheContext.cobuildClusterId, + lockExpireTimeInSeconds: PERIODIC_CALLBACK_INTERVAL_IN_SECONDS * 3, + packageName, + phaseName + }); + } + } + return buildCacheContext.cobuildLock; + } + + private async _createBuildCacheTerminalAsync({ + record, + buildCacheContext, + buildCacheEnabled, + rushProject, + logFilenameIdentifier, + quietMode, + debugMode + }: { + record: OperationExecutionRecord; + buildCacheContext: IOperationBuildCacheContext; + buildCacheEnabled: boolean | undefined; + rushProject: RushConfigurationProject; + logFilenameIdentifier: string; + quietMode: boolean; + debugMode: boolean; + }): Promise { + const silent: boolean = record.silent; + if (silent) { + const nullTerminalProvider: NullTerminalProvider = new NullTerminalProvider(); + return new Terminal(nullTerminalProvider); + } + + let cacheConsoleWritable: TerminalWritable; + // This creates the writer, only do this if necessary. + const collatedWriter: CollatedWriter = record.collatedWriter; + const cacheProjectLogWritable: TerminalWritable | undefined = + await this._tryGetBuildCacheTerminalWritableAsync({ + buildCacheContext, + buildCacheEnabled, + rushProject, + logFilenameIdentifier + }); + + if (quietMode) { + const discardTransform: DiscardStdoutTransform = new DiscardStdoutTransform({ + destination: collatedWriter + }); + const normalizeNewlineTransform: TextRewriterTransform = new TextRewriterTransform({ + destination: discardTransform, + normalizeNewlines: NewlineKind.Lf, + ensureNewlineAtEnd: true + }); + cacheConsoleWritable = normalizeNewlineTransform; + } else { + cacheConsoleWritable = collatedWriter; + } + + let cacheCollatedTerminal: CollatedTerminal; + if (cacheProjectLogWritable) { + const cacheSplitterTransform: SplitterTransform = new SplitterTransform({ + destinations: [cacheConsoleWritable, cacheProjectLogWritable] + }); + cacheCollatedTerminal = new CollatedTerminal(cacheSplitterTransform); + } else { + cacheCollatedTerminal = new CollatedTerminal(cacheConsoleWritable); + } + + const buildCacheTerminalProvider: CollatedTerminalProvider = new CollatedTerminalProvider( + cacheCollatedTerminal, + { + debugEnabled: debugMode + } + ); + return new Terminal(buildCacheTerminalProvider); + } + + private async _tryGetBuildCacheTerminalWritableAsync({ + buildCacheEnabled, + rushProject, + buildCacheContext, + logFilenameIdentifier + }: { + buildCacheEnabled: boolean | undefined; + rushProject: RushConfigurationProject; + buildCacheContext: IOperationBuildCacheContext; + logFilenameIdentifier: string; + }): Promise { + // Only open the *.cache.log file(s) if the cache is enabled. + if (!buildCacheEnabled) { + return; + } + + const logFilePaths: ILogFilePaths = getProjectLogFilePaths({ + project: rushProject, + logFilenameIdentifier: `${logFilenameIdentifier}.cache` + }); + + buildCacheContext.buildCacheTerminalWritable = await initializeProjectLogFilesAsync({ + logFilePaths + }); + + return buildCacheContext.buildCacheTerminalWritable; + } +} + +export function clusterOperations( + initialClusters: DisjointSet, + operationBuildCacheMap: Map +): void { + // If disjoint set exists, connect build cache disabled project with its consumers + for (const [operation, { cacheDisabledReason }] of operationBuildCacheMap) { + 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 new file mode 100644 index 00000000000..e800aaaf871 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts @@ -0,0 +1,356 @@ +// 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 { 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 { OperationStatus } from './OperationStatus'; +import type { CobuildConfiguration } from '../../api/CobuildConfiguration'; +import type { OperationExecutionRecord } from './OperationExecutionRecord'; + +const PLUGIN_NAME: 'ConsoleTimelinePlugin' = 'ConsoleTimelinePlugin'; + +/* Sample output: +============================================================================================================================== + @rushstack/tree-pattern (build) ###########-------------------------------------------------------------------- 3.3s + @rushstack/eslint-patch (build) ########----------------------------------------------------------------------- 2.2s + @rushstack/eslint-patch (test) -------%----------------------------------------------------------------------- 0.0s +@rushstack/eslint-plugin-security (build) ----------########################--------------------------------------------- 6.8s +@rushstack/eslint-plugin-packlets (build) ----------############################----------------------------------------- 8.1s + @rushstack/eslint-plugin (build) ----------##############################--------------------------------------- 8.7s + @rushstack/tree-pattern (test) ----------#####---------------------------------------------------------------- 1.2s + @rushstack/eslint-plugin-security (test) ---------------------------------############---------------------------------- 3.3s + @rushstack/eslint-plugin-packlets (test) -------------------------------------#####------------------------------------- 1.1s + @rushstack/eslint-config (build) ---------------------------------------%--------------------------------------- 0.0s + @rushstack/eslint-plugin (test) ---------------------------------------#############--------------------------- 3.8s + @rushstack/eslint-config (test) ---------------------------------------%--------------------------------------- 0.0s + @rushstack/node-core-library (build) ---------------------------------------################################-------- 9.5s + @rushstack/node-core-library (test) ----------------------------------------------------------------------######### 2.2s +============================================================================================================================== +LEGEND: Total Work: 50.3s + [#] Success [!] Failed/warnings [%] Skipped/cached/no-op Wall Clock: 23.7s + Max Parallelism Used: 5 + Avg Parallelism Used: 2.1 +BY PHASE: + _phase:build 38.6s + _phase:test 11.7s +*/ + +/** + * Phased command plugin that emits a timeline to the console. + */ +export class ConsoleTimelinePlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + } + + public apply(hooks: PhasedCommandHooks): void { + hooks.afterExecuteOperations.tap( + PLUGIN_NAME, + (result: IExecutionResult, context: ICreateOperationsContext): void => { + _printTimeline({ + terminal: this._terminal, + result, + cobuildConfiguration: context.cobuildConfiguration + }); + } + ); + } +} + +/** + * Timeline - a wider column width for printing the timeline summary + */ +const TIMELINE_WIDTH: number = 109; + +/** + * Timeline - symbols representing each operation status + */ +const TIMELINE_CHART_SYMBOLS: Record = { + [OperationStatus.Waiting]: '?', + [OperationStatus.Ready]: '?', + [OperationStatus.Queued]: '?', + [OperationStatus.Executing]: '?', + [OperationStatus.Success]: '#', + [OperationStatus.SuccessWithWarning]: '!', + [OperationStatus.Failure]: '!', + [OperationStatus.Blocked]: '.', + [OperationStatus.Skipped]: '%', + [OperationStatus.FromCache]: '%', + [OperationStatus.NoOp]: '%', + [OperationStatus.Aborted]: '@' +}; + +const COBUILD_REPORTABLE_STATUSES: Set = new Set([ + OperationStatus.Success, + OperationStatus.SuccessWithWarning, + OperationStatus.Failure, + OperationStatus.Blocked +]); + +/** + * Timeline - colorizer for each operation status + */ +const TIMELINE_CHART_COLORIZER: Record string> = { + [OperationStatus.Waiting]: Colorize.yellow, + [OperationStatus.Ready]: Colorize.yellow, + [OperationStatus.Queued]: Colorize.yellow, + [OperationStatus.Executing]: Colorize.yellow, + [OperationStatus.Success]: Colorize.green, + [OperationStatus.SuccessWithWarning]: Colorize.yellow, + [OperationStatus.Failure]: Colorize.red, + [OperationStatus.Blocked]: Colorize.red, + [OperationStatus.Skipped]: Colorize.green, + [OperationStatus.FromCache]: Colorize.green, + [OperationStatus.NoOp]: Colorize.gray, + [OperationStatus.Aborted]: Colorize.red +}; + +interface ITimelineRecord { + startTime: number; + endTime: number; + durationString: string; + name: string; + status: OperationStatus; + isExecuteByOtherCobuildRunner: boolean; +} + +/** + * @internal + */ +export interface IPrintTimelineParameters { + terminal: ITerminal; + result: IExecutionResult; + 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 }: 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 data: ITimelineRecord[] = []; + let longestNameLength: number = 0; + let longestDurationLength: number = 0; + let allStart: number = Infinity; + let allEnd: number = -Infinity; + let workDuration: number = 0; + + for (const [operation, operationResult] of result.operationResults) { + if (operationResult.silent) { + continue; + } + + const { stopwatch } = operationResult; + const { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; + + 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 durationString: string = duration.uncached.toFixed(1); + const durationLength: number = durationString.length; + if (durationLength > longestDurationLength) { + longestDurationLength = durationLength; + } + + if (endTime > allEnd) { + allEnd = endTime; + } + if (startTime < allStart) { + allStart = startTime; + } + + const { associatedPhase } = operation; + + if (associatedPhase) { + 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, + status: operationResult.status, + isExecuteByOtherCobuildRunner: wasCobuilt + }); + } + } + + data.sort((a, b) => a.startTime - b.startTime); + + // + // Determine timing for all tasks (wall clock and execution times) + // + + const allDuration: number = allEnd - allStart; + const allDurationSeconds: number = allDuration / 1000; + + // + // Do some calculations to determine what size timeline chart we need. + // + + const maxWidth: number = PrintUtilities.getConsoleWidth() || TIMELINE_WIDTH; + const chartWidth: number = maxWidth - longestNameLength - longestDurationLength - 4; + // + // Loop through all operations, assembling some statistics about operations and + // phases, if applicable. + // + + const busyCpus: number[] = []; + function getOpenCPU(time: number): number { + const len: number = busyCpus.length; + for (let i: number = 0; i < len; i++) { + if (busyCpus[i] <= time) { + return i; + } + } + return len; + } + + // Start with a newline + terminal.writeLine(''); + terminal.writeLine('='.repeat(maxWidth)); + + let hasCobuildSymbol: boolean = false; + + function getChartSymbol(record: ITimelineRecord): string { + const { isExecuteByOtherCobuildRunner, status } = record; + if (isExecuteByOtherCobuildRunner && COBUILD_REPORTABLE_STATUSES.has(status)) { + hasCobuildSymbol = true; + return 'C'; + } + return TIMELINE_CHART_SYMBOLS[status]; + } + + for (const record of data) { + const { startTime, endTime, durationString, name, status } = record; + // Track busy CPUs + const openCpu: number = getOpenCPU(startTime); + busyCpus[openCpu] = endTime; + + // Build timeline chart + const startIdx: number = Math.floor(((startTime - allStart) * chartWidth) / allDuration); + const endIdx: number = Math.floor(((endTime - allStart) * chartWidth) / allDuration); + const length: number = endIdx - startIdx + 1; + + const chart: string = + Colorize.gray('-'.repeat(startIdx)) + + TIMELINE_CHART_COLORIZER[status](getChartSymbol(record).repeat(length)) + + Colorize.gray('-'.repeat(chartWidth - endIdx)); + terminal.writeLine( + `${Colorize.cyan(name.padStart(longestNameLength))} ${chart} ${Colorize.white( + durationString.padStart(longestDurationLength) + 's' + )}` + ); + } + + terminal.writeLine('='.repeat(maxWidth)); + + // + // Format legend and summary areas + // + + const usedCpus: number = busyCpus.length; + + const legend: string[] = [ + 'LEGEND:', + ' [#] Success [!] Failed/warnings [%] Skipped/cached/no-op', + '', + '' + ]; + if (hasCobuildSymbol) { + legend[2] = ' [C] Cobuild'; + } + + const summary: string[] = [ + `Total Work: ${workDuration.toFixed(1)}s`, + `Wall Clock: ${allDurationSeconds.toFixed(1)}s`, + `Max Parallelism Used: ${usedCpus}`, + `Avg Parallelism Used: ${(workDuration / allDurationSeconds).toFixed(1)}` + ]; + + terminal.writeLine(legend[0] + summary[0].padStart(maxWidth - legend[0].length)); + terminal.writeLine(legend[1] + summary[1].padStart(maxWidth - legend[1].length)); + terminal.writeLine(legend[2] + summary[2].padStart(maxWidth - legend[2].length)); + terminal.writeLine(legend[3] + summary[3].padStart(maxWidth - legend[3].length)); + + // + // Include time-by-phase, if phases are enabled + // + + if (durationByPhase.size > 0) { + terminal.writeLine('BY PHASE:'); + + let maxPhaseName: number = 16; + for (const phase of durationByPhase.keys()) { + const len: number = phase.name.length; + if (len > maxPhaseName) { + maxPhaseName = len; + } + } + + for (const [phase, duration] of durationByPhase.entries()) { + 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}`); + } + } + + terminal.writeLine(''); +} 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..8af179838d6 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/DebugHashesPlugin.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 { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { Operation } from './Operation'; +import type { IOperationExecutionResult } 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.beforeExecuteOperations.tap( + PLUGIN_NAME, + (operations: Map) => { + const terminal: ITerminal = this._terminal; + terminal.writeLine(Colorize.blue(`===== Begin Hash Computation =====`)); + for (const [operation, record] of operations) { + terminal.writeLine(Colorize.cyan(`--- ${operation.name} ---`)); + record.getStateHashComponents().forEach((component) => { + terminal.writeLine(component); + }); + 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 new file mode 100644 index 00000000000..e7658c210b8 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { StdioSummarizer, IProblemCollector } from '@rushstack/terminal'; + +import type { OperationStatus } from './OperationStatus'; +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}. + * @alpha + */ +export interface IOperationExecutionResult { + /** + * The operation itself + */ + readonly operation: Operation; + /** + * 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 + * the operation is executing. Once execution is complete, it is either 'success' or + * 'failure'. + */ + readonly status: OperationStatus; + /** + * The 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). + */ + readonly error: Error | undefined; + /** + * If this operation is only present in the graph to maintain dependency relationships, this flag will be set to true. + */ + readonly silent: boolean; + /** + * Object tracking execution timing. + */ + readonly stopwatch: IStopwatchResult; + /** + * Object used to report a summary at the end of the Rush invocation. + */ + readonly stdioSummarizer: StdioSummarizer; + /** + * Object used to collect problems (errors/warnings/info) encountered during the operation. + */ + readonly problemCollector: IProblemCollector; + /** + * The value indicates the duration of the same operation without cache hit. + */ + readonly nonCachedDurationMs: number | undefined; + /** + * The relative path to the folder that contains operation metadata. This folder will be automatically included in cache entries. + */ + readonly metadataFolderPath: string | undefined; + /** + * The paths to the log files, if applicable. + */ + readonly logFilePaths: ILogFilePaths | undefined; + + /** + * 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 components of the state hash. This is useful for debugging purposes. + * Calling this method will throw if Git is not available. + */ + getStateHashComponents(): ReadonlyArray; +} + +/** + * The `IExecutionResult` interface represents the results of executing a set of {@link Operation}s. + * @alpha + */ +export interface IExecutionResult { + /** + * The results for each scheduled operation. + */ + readonly operationResults: ReadonlyMap; + /** + * The overall result. + */ + readonly status: OperationStatus; +} diff --git a/libraries/rush-lib/src/logic/operations/IOperationRunner.ts b/libraries/rush-lib/src/logic/operations/IOperationRunner.ts new file mode 100644 index 00000000000..d6c907bf65a --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IOperationRunner.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 type { ITerminal, ITerminalProvider } from '@rushstack/terminal'; +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'; + +/** + * Information passed to the executing `IOperationRunner` + * + * @beta + */ +export interface IOperationRunnerContext { + /** + * The writer into which this `IOperationRunner` should write its logs. + */ + collatedWriter: CollatedWriter; + /** + * If Rush was invoked with `--debug` + */ + debugMode: boolean; + /** + * Defaults to `true`. Will be `false` if Rush was invoked with `--verbose`. + */ + quietMode: boolean; + /** + * Object used to manage metadata of the operation. + * + * @internal + */ + _operationMetadataManager: OperationMetadataManager; + /** + * Object used to track elapsed time. + */ + stopwatch: IStopwatchResult; + /** + * 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 + * the operation is executing. Once execution is complete, it is either 'success' or + * 'failure'. + */ + 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; + + /** + * Invokes the specified callback with a terminal that is associated with this operation. + * + * Will write to a log file corresponding to the phase and project, and clean it up upon completion. + */ + runWithTerminalAsync( + callback: (terminal: ITerminal, terminalProvider: ITerminalProvider) => Promise, + options: { + createLogFile: boolean; + logFileSuffix?: string; + } + ): Promise; +} + +/** + * 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 + * implementation manages the actual process for running a single operation. + * + * @beta + */ +export interface IOperationRunner { + /** + * Name of the operation, for logging. + */ + readonly name: string; + + /** + * Whether or not the operation is cacheable. If false, all cache engines will be disabled for this operation. + */ + cacheable: boolean; + + /** + * Indicates that this runner's duration has meaning. + */ + reportTiming: boolean; + + /** + * Indicates that this runner is architectural and should not be reported on. + */ + silent: boolean; + + /** + * If set to true, a warning result should not make Rush exit with a nonzero + * exit code + */ + warningsAreAllowed: boolean; + + /** + * If set to true, this operation is considered a no-op and can be considered always skipped for + * analysis purposes. + */ + readonly isNoOp?: boolean; + + /** + * Method to be executed for the operation. + */ + executeAsync(context: IOperationRunnerContext): Promise; + + /** + * Return a hash of the configuration that affects the operation. + */ + getConfigHash(): string; +} diff --git a/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts b/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts new file mode 100644 index 00000000000..6fbc924d87e --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts @@ -0,0 +1,230 @@ +// 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 { once } from 'node:events'; + +import type { + IAfterExecuteEventMessage, + IRequestRunEventMessage, + ISyncEventMessage, + IRunCommandMessage, + IExitCommandMessage, + OperationRequestRunCallback +} from '@rushstack/operation-graph'; +import { TerminalProviderSeverity, type ITerminal, type ITerminalProvider } from '@rushstack/terminal'; + +import type { IPhase } from '../../api/CommandLineConfiguration'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { Utilities } from '../../utilities/Utilities'; +import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; +import { OperationError } from './OperationError'; +import { OperationStatus } from './OperationStatus'; + +export interface IIPCOperationRunnerOptions { + phase: IPhase; + project: RushConfigurationProject; + name: string; + commandToRun: string; + commandForHash: string; + persist: boolean; + requestRun: OperationRequestRunCallback; + ignoredParameterValues: ReadonlyArray; +} + +function isAfterExecuteEventMessage(message: unknown): message is IAfterExecuteEventMessage { + return typeof message === 'object' && (message as IAfterExecuteEventMessage).event === 'after-execute'; +} + +function isRequestRunEventMessage(message: unknown): message is IRequestRunEventMessage { + return typeof message === 'object' && (message as IRequestRunEventMessage).event === 'requestRun'; +} + +function isSyncEventMessage(message: unknown): message is ISyncEventMessage { + return typeof message === 'object' && (message as ISyncEventMessage).event === 'sync'; +} + +/** + * Runner that hosts a long-lived process to which it communicates via IPC. + */ +export class IPCOperationRunner implements IOperationRunner { + public readonly name: string; + public readonly cacheable: boolean = false; + public readonly reportTiming: boolean = true; + public readonly silent: boolean = false; + public readonly warningsAreAllowed: boolean; + + private readonly _rushProject: RushConfigurationProject; + private readonly _commandToRun: string; + private readonly _commandForHash: string; + private readonly _persist: boolean; + private readonly _requestRun: OperationRequestRunCallback; + private readonly _ignoredParameterValues: ReadonlyArray; + + private _ipcProcess: ChildProcess | undefined; + private _processReadyPromise: Promise | undefined; + + public constructor(options: IIPCOperationRunnerOptions) { + this.name = options.name; + this.warningsAreAllowed = + EnvironmentConfiguration.allowWarningsInSuccessfulBuild || + options.phase.allowWarningsOnSuccess || + false; + this._rushProject = options.project; + this._commandToRun = options.commandToRun; + this._commandForHash = options.commandForHash; + + this._persist = options.persist; + this._requestRun = options.requestRun; + this._ignoredParameterValues = options.ignoredParameterValues; + } + + public async executeAsync(context: IOperationRunnerContext): Promise { + 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._commandToRun); + + const { rushConfiguration, projectFolder } = this._rushProject; + + const { environment: initialEnvironment } = context; + + this._ipcProcess = Utilities.executeLifecycleCommandAsync(this._commandToRun, { + rushConfiguration, + workingDirectory: projectFolder, + initCwd: rushConfiguration.commonTempFolder, + handleOutput: true, + environmentPathOptions: { + includeProjectBin: true + }, + ipc: true, + connectSubprocessTerminator: true, + initialEnvironment + }); + + let resolveReadyPromise!: () => void; + + this._processReadyPromise = new Promise((resolve) => { + resolveReadyPromise = resolve; + }); + + this._ipcProcess.on('message', (message: unknown) => { + if (isRequestRunEventMessage(message)) { + this._requestRun(message.requestor, message.detail); + } else if (isSyncEventMessage(message)) { + resolveReadyPromise(); + } + }); + } else { + terminal.writeLine(`Connecting to existing IPC process...`); + } + const subProcess: ChildProcess = this._ipcProcess; + let hasWarningOrError: boolean = false; + + function onStdout(data: Buffer): void { + const text: string = data.toString(); + terminalProvider.write(text, TerminalProviderSeverity.log); + } + function onStderr(data: Buffer): void { + const text: string = data.toString(); + terminalProvider.write(text, TerminalProviderSeverity.error); + hasWarningOrError = true; + } + + // Hook into events, in order to get live streaming of the log + subProcess.stdout?.on('data', onStdout); + subProcess.stderr?.on('data', onStderr); + + const status: OperationStatus = await new Promise((resolve, reject) => { + function finishHandler(message: unknown): void { + if (isAfterExecuteEventMessage(message)) { + terminal.writeLine('Received finish notification'); + subProcess.stdout?.off('data', onStdout); + subProcess.stderr?.off('data', onStderr); + subProcess.off('message', finishHandler); + subProcess.off('error', reject); + subProcess.off('exit', onExit); + terminal.writeLine('Disconnected from IPC process'); + // These types are currently distinct but have the same underlying values + resolve(message.status as unknown as OperationStatus); + } + } + + function onExit(exitCode: number | null, signal: NodeJS.Signals | null): void { + try { + if (signal) { + context.error = new OperationError('error', `Terminated by signal: ${signal}`); + resolve(OperationStatus.Failure); + } else if (exitCode !== 0) { + // Do NOT reject here immediately, give a chance for other logic to suppress the error + context.error = new OperationError('error', `Returned error code: ${exitCode}`); + resolve(OperationStatus.Failure); + } else if (hasWarningOrError) { + resolve(OperationStatus.SuccessWithWarning); + } else { + resolve(OperationStatus.Success); + } + } catch (error) { + reject(error as OperationError); + } + } + + subProcess.on('message', finishHandler); + subProcess.on('error', reject); + subProcess.on('exit', onExit); + + this._processReadyPromise!.then(() => { + isConnected = true; + terminal.writeLine('Child supports IPC protocol. Sending "run" command...'); + const runCommand: IRunCommandMessage = { + command: 'run' + }; + subProcess.send(runCommand); + }, reject); + }); + + if (isConnected && !this._persist) { + await this.shutdownAsync(); + } + + // @rushstack/operation-graph does not currently have a concept of "Success with Warning" + // To match existing ShellOperationRunner behavior we treat any stderr as a warning. + return status === OperationStatus.Success && hasWarningOrError + ? OperationStatus.SuccessWithWarning + : status; + }, + { + createLogFile: true + } + ); + } + + public getConfigHash(): string { + return this._commandForHash; + } + + public async shutdownAsync(): Promise { + const { _ipcProcess: subProcess } = this; + if (!subProcess) { + return; + } + + if (subProcess.connected) { + const exitCommand: IExitCommandMessage = { + command: 'exit' + }; + subProcess.send(exitCommand); + await once(subProcess, 'exit'); + } + } +} diff --git a/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts b/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts new file mode 100644 index 00000000000..f87dcb1685a --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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, + getCustomParameterValuesByOperation, + type ICustomParameterValuesForOperation, + getDisplayName +} from './ShellOperationRunnerPlugin'; + +const PLUGIN_NAME: 'IPCOperationRunnerPlugin' = 'IPCOperationRunnerPlugin'; + +/** + * Plugin that implements compatible phases via IPC to a long-lived watch process. + */ +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( + { + name: PLUGIN_NAME, + before: ShellOperationPluginName + }, + async (operations: Set, context: ICreateOperationsContext) => { + const { isWatch, isInitial } = context; + if (!isWatch) { + return operations; + } + + currentContext = context; + + const getCustomParameterValues: (operation: Operation) => ICustomParameterValuesForOperation = + getCustomParameterValuesByOperation(); + + for (const operation of operations) { + const { associatedPhase: phase, associatedProject: project, runner } = operation; + + if (runner) { + continue; + } + + const { scripts } = project.packageJson; + if (!scripts) { + continue; + } + + const { name: phaseName } = phase; + + const rawScript: string | undefined = + (!isInitial ? scripts[`${phaseName}:incremental:ipc`] : undefined) ?? scripts[`${phaseName}:ipc`]; + + if (!rawScript) { + continue; + } + + // 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 commandToRun: string = formatCommand(rawScript, customParameterValues); + + 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, + commandToRun, + commandForHash, + persist: true, + ignoredParameterValues, + requestRun: (requestor: string, detail?: 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, + detail ? `${requestor}: ${detail}` : requestor + ); + } + })); + runnerCache.set(operationName, ipcOperationRunner); + } + + operation.runner = maybeIpcOperationRunner; + } + + 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/LegacySkipPlugin.ts b/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts new file mode 100644 index 00000000000..86f899453f4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts @@ -0,0 +1,263 @@ +// 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, JsonFile, type JsonObject } from '@rushstack/node-core-library'; +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 { IOperationRunnerContext } from './IOperationRunner'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; + +const PLUGIN_NAME: 'LegacySkipPlugin' = 'LegacySkipPlugin'; + +function _areShallowEqual(object1: JsonObject, object2: JsonObject): boolean { + for (const n in object1) { + if (!(n in object2) || object1[n] !== object2[n]) { + return false; + } + } + for (const n in object2) { + if (!(n in object1)) { + return false; + } + } + return true; +} + +export interface IProjectDeps { + files: { [filePath: string]: string }; + arguments: string; +} + +interface ILegacySkipRecord { + allowSkip: boolean; + packageDeps: IProjectDeps | undefined; + packageDepsPath: string; +} + +export interface ILegacySkipPluginOptions { + terminal: ITerminal; + changedProjectsOnly: boolean; + isIncrementalBuildAllowed: boolean; + allowWarningsInSuccessfulBuild?: boolean; +} + +/** + * Core phased command plugin that implements the legacy skip detection logic, used when build cache is disabled. + */ +export class LegacySkipPlugin implements IPhasedCommandPlugin { + private readonly _options: ILegacySkipPluginOptions; + + public constructor(options: ILegacySkipPluginOptions) { + this._options = options; + } + + public apply(hooks: PhasedCommandHooks): void { + const stateMap: WeakMap = new WeakMap(); + + 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, associatedPhase, runner, logFilenameIdentifier } = operation; + if (!runner) { + continue; + } + + if (!runner.cacheable) { + stateMap.set(operation, { + allowSkip: true, + packageDeps: undefined, + packageDepsPath: '' + }); + continue; + } + + const packageDepsFilename: string = `package-deps_${logFilenameIdentifier}.json`; + + const packageDepsPath: string = path.join( + associatedProject.projectRushTempFolder, + packageDepsFilename + ); + + 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.') + ); + } + + 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; + } + + if (!operation.runner!.cacheable) { + // This operation doesn't support skip detection. + return; + } + + const { associatedProject } = operation; + + const { packageDepsPath, packageDeps, allowSkip } = skipRecord; + + 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.` + ); + } + } + + if (allowSkip) { + const isPackageUnchanged: boolean = !!( + lastProjectDeps && + packageDeps && + packageDeps.arguments === lastProjectDeps.arguments && + _areShallowEqual(packageDeps.files, lastProjectDeps.files) + ); + + 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'); + + 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) + ]); + } + ); + + hooks.afterExecuteOperation.tapPromise( + PLUGIN_NAME, + async (record: IOperationRunnerContext & IOperationExecutionResult): Promise => { + const { status, operation } = record; + + 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; + } + } + } + + 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 + }); + } + } + ); + } +} 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..28df11044c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/NodeDiagnosticDirPlugin.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. + +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.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/NullOperationRunner.ts b/libraries/rush-lib/src/logic/operations/NullOperationRunner.ts new file mode 100644 index 00000000000..03e9260bc7c --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/NullOperationRunner.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 type { OperationStatus } from './OperationStatus'; +import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; + +/** + * + */ +export interface INullOperationRunnerParams { + /** + * The name to report in logs. + */ + name: string; + /** + * The result to report from the runner. + */ + result: OperationStatus; + /** + * If true, the operation will not log anything or be tracked in statistics. + */ + silent: boolean; +} + +/** + * Implementation of `IOperationRunner` for operations that require no work, such as empty scripts, + * skipped operations, or blocked operations. + */ +export class NullOperationRunner implements IOperationRunner { + public readonly name: string; + // This operation does nothing, so timing is meaningless + public readonly reportTiming: boolean = false; + public readonly silent: boolean; + // The operation is a no-op, so it is faster to not cache it + public cacheable: boolean = false; + // Nothing will get logged, no point allowing warnings + public readonly warningsAreAllowed: boolean = false; + public readonly isNoOp: boolean = true; + + public readonly result: OperationStatus; + + public constructor({ name, result, silent }: INullOperationRunnerParams) { + this.name = name; + this.result = result; + this.silent = silent; + } + + public async executeAsync(context: IOperationRunnerContext): Promise { + return this.result; + } + + public getConfigHash(): string { + return ''; + } +} diff --git a/libraries/rush-lib/src/logic/operations/Operation.ts b/libraries/rush-lib/src/logic/operations/Operation.ts new file mode 100644 index 00000000000..be3ec8ac5fc --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/Operation.ts @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IPhase } from '../../api/CommandLineConfiguration'; +import type { IOperationRunner } from './IOperationRunner'; +import type { IOperationSettings } from '../../api/RushProjectConfiguration'; + +/** + * Options for constructing a new Operation. + * @alpha + */ +export interface IOperationOptions { + /** + * The Rush phase associated with this Operation + */ + phase: IPhase; + + /** + * The Rush project associated with this Operation + */ + project: RushConfigurationProject; + + /** + * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of + * running the operation. + */ + runner?: IOperationRunner | undefined; + + /** + * Settings defined in the project configuration for this operation, can be overridden. + */ + settings?: IOperationSettings | undefined; + + /** + * {@inheritDoc Operation.logFilenameIdentifier} + */ + logFilenameIdentifier: string; +} + +/** + * 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 + * 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. + * + * @alpha + */ +export class Operation { + /** + * The Rush phase associated with this Operation + */ + public readonly associatedPhase: IPhase; + + /** + * The Rush project associated with this Operation + */ + public readonly associatedProject: RushConfigurationProject; + + /** + * A set of all operations which depend on this operation. + */ + public readonly consumers: ReadonlySet = new Set(); + + /** + * A set of all dependencies which must be executed before this operation is complete. + */ + public readonly dependencies: ReadonlySet = new Set(); + + /** + * This property is used in the name of the filename for the logs generated by this + * operation. This is a filesystem-safe version of the phase name. For example, + * an operation for a phase with name `_phase:compile` has a `logFilenameIdentifier` of `_phase_compile`. + */ + public logFilenameIdentifier: string; + + /** + * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of + * running the 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. + */ + public weight: number = 1; + + /** + * Get the operation settings for this operation, defaults to the values defined in + * the project configuration. + */ + public settings: IOperationSettings | undefined = undefined; + + /** + * 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. + */ + public enabled: boolean; + + public constructor(options: IOperationOptions) { + const { phase, project, runner, settings, logFilenameIdentifier } = options; + this.associatedPhase = phase; + this.associatedProject = project; + this.runner = runner; + this.settings = settings; + this.logFilenameIdentifier = logFilenameIdentifier; + this.enabled = true; + } + + /** + * The name of this operation, for logging. + */ + 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 { + const { runner } = this; + if (!runner) { + throw new Error(`Cannot get isNoOp of an Operation that does not yet have a runner.`); + } + return !!runner.isNoOp; + } + + /** + * Adds the specified operation as a dependency and updates the consumer list. + */ + public addDependency(dependency: Operation): void { + // Cast internally to avoid adding the overhead of getters + (this.dependencies as Set).add(dependency); + (dependency.consumers as Set).add(this); + } + + /** + * Deletes the specified operation as a dependency and updates the consumer list. + */ + public deleteDependency(dependency: Operation): void { + // Cast internally to avoid adding the overhead of getters + (this.dependencies as Set).delete(dependency); + (dependency.consumers as Set).delete(this); + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationError.ts b/libraries/rush-lib/src/logic/operations/OperationError.ts new file mode 100644 index 00000000000..ac5d803016e --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationError.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Encapsulates information about an error + * @alpha + */ +export class OperationError extends Error { + protected _type: string; + + public constructor(type: string, message: string) { + super(message); + + this._type = type; + } + + public get message(): string { + return `[${this._type}] '${super.message}'`; + } + + public 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 new file mode 100644 index 00000000000..b0f2a3e0cb2 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts @@ -0,0 +1,470 @@ +// 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'; +import type { IEnvironment } from '../../utilities/Utilities'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; +import type { IStopwatchResult } from '../../utilities/Stopwatch'; + +export interface IOperationExecutionManagerOptions { + quietMode: boolean; + debugMode: boolean; + parallelism: number; + allowOversubscription: boolean; + inputsSnapshot?: IInputsSnapshot; + destination?: TerminalWritable; + + beforeExecuteOperationAsync?: (operation: OperationExecutionRecord) => Promise; + afterExecuteOperationAsync?: (operation: OperationExecutionRecord) => Promise; + createEnvironmentForOperation?: (operation: OperationExecutionRecord) => IEnvironment; + 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!; +}; + +/** + * 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. + * 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 _executionRecords: Map; + private readonly _quietMode: boolean; + private readonly _parallelism: number; + private readonly _allowOversubscription: boolean; + 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; + private readonly _createEnvironmentForOperation?: (operation: OperationExecutionRecord) => IEnvironment; + + // Variables for current status + private _hasAnyFailures: boolean; + private _hasAnyNonAllowedWarnings: boolean; + private _hasAnyAborted: boolean; + private _completedOperations: number; + private _executionQueue: AsyncOperationQueue; + + public constructor(operations: Set, options: IOperationExecutionManagerOptions) { + const { + quietMode, + debugMode, + parallelism, + allowOversubscription, + inputsSnapshot, + beforeExecuteOperationAsync: beforeExecuteOperation, + afterExecuteOperationAsync: afterExecuteOperation, + onOperationStatusChangedAsync: onOperationStatusChanged, + beforeExecuteOperationsAsync: beforeExecuteOperations, + createEnvironmentForOperation + } = options; + this._completedOperations = 0; + this._quietMode = quietMode; + this._hasAnyFailures = false; + this._hasAnyNonAllowedWarnings = false; + this._hasAnyAborted = false; + this._parallelism = parallelism; + this._allowOversubscription = allowOversubscription; + + this._beforeExecuteOperation = beforeExecuteOperation; + this._afterExecuteOperation = afterExecuteOperation; + this._beforeExecuteOperations = beforeExecuteOperations; + this._createEnvironmentForOperation = createEnvironmentForOperation; + 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, + createEnvironment: this._createEnvironmentForOperation, + inputsSnapshot, + debugMode, + quietMode + }; + + // Sort the operations by name to ensure consistency and readability. + const sortedOperations: Operation[] = Array.from(operations).sort(sortOperationsByName); + + let totalOperations: number = 0; + const executionRecords: Map = (this._executionRecords = new Map()); + for (const operation of sortedOperations) { + 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, 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); + } + } + + // 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(); + } + } + + 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(abortController: AbortController): Promise { + this._completedOperations = 0; + const totalOperations: number = this._totalOperations; + const abortSignal: AbortSignal = abortController.signal; + + 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 + ) => { + // If the operation is not terminal, we should _only_ notify the queue to assign operations. + if (!record.isTerminal) { + this._executionQueue.assignOperations(); + } else { + 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) => { + 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. + this._hasAnyAborted = true; + this._executionQueue.complete(record); + } else { + await record.executeAsync({ + onStart: onOperationStartAsync, + onResult: onOperationCompleteAsync + }); + } + }, + { + allowOversubscription: this._allowOversubscription, + concurrency: maxParallelism, + weighted: true + } + ); + + const status: OperationStatus = this._hasAnyFailures + ? OperationStatus.Failure + : this._hasAnyAborted + ? OperationStatus.Aborted + : 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, _operationMetadataManager: operationMetadataManager } = record; + const stopwatch: IStopwatchResult = + operationMetadataManager?.tryRestoreStopwatch(record.stopwatch) || record.stopwatch; + + 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 ${stopwatch.toString()}.`) + ); + } + break; + } + + case OperationStatus.SuccessWithWarning: { + if (!silent) { + record.collatedWriter.terminal.writeStderrLine( + Colorize.yellow(`"${name}" completed with warnings in ${stopwatch.toString()}.`) + ); + } + this._hasAnyNonAllowedWarnings = this._hasAnyNonAllowedWarnings || !runner.warningsAreAllowed; + break; + } + + case OperationStatus.Aborted: { + this._hasAnyAborted ||= true; + break; + } + + default: { + throw new InternalError(`Unexpected operation status: ${status}`); + } + } + + this._executionQueue.complete(record); + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts new file mode 100644 index 00000000000..63da9421b54 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts @@ -0,0 +1,423 @@ +// 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, + DiscardStdoutTransform, + SplitterTransform, + StderrLineTransform, + StdioSummarizer, + ProblemCollector, + TextRewriterTransform, + Terminal, + type TerminalWritable +} from '@rushstack/terminal'; +import { InternalError, NewlineKind, FileError } from '@rushstack/node-core-library'; +import { CollatedTerminal, type CollatedWriter, type StreamCollator } from '@rushstack/stream-collator'; + +import { OperationStatus, TERMINAL_STATUSES } from './OperationStatus'; +import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; +import type { Operation } from './Operation'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { OperationMetadataManager } from './OperationMetadataManager'; +import type { IPhase } from '../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { CollatedTerminalProvider } from '../../utilities/CollatedTerminalProvider'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; +import { RushConstants } from '../RushConstants'; +import type { IEnvironment } from '../../utilities/Utilities'; +import { + getProjectLogFilePaths, + type ILogFilePaths, + initializeProjectLogFilesAsync +} from './ProjectLogWritable'; + +/** + * @internal + */ +export interface IOperationExecutionRecordContext { + streamCollator: StreamCollator; + onOperationStatusChanged?: (record: OperationExecutionRecord) => void; + createEnvironment?: (record: OperationExecutionRecord) => IEnvironment; + inputsSnapshot: IInputsSnapshot | undefined; + + debugMode: boolean; + quietMode: boolean; +} + +/** + * Internal class representing everything about executing an operation + * + * @internal + */ +export class OperationExecutionRecord implements IOperationRunnerContext, IOperationExecutionResult { + /** + * The associated operation. + */ + public readonly operation: Operation; + + /** + * The 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). + */ + public error: Error | undefined = undefined; + + /** + * 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 + * longest chain of projects which must be executed in order, thereby limiting execution speed + * of the entire operation tree. + * + * This number is calculated via a memoized depth-first search, and when choosing the next + * operation to execute, the operation with the highest criticalPathLength is chosen. + * + * Example: + * ``` + * (0) A + * \ + * (1) B C (0) (applications) + * \ /|\ + * \ / | \ + * (2) D | X (1) (utilities) + * | / \ + * |/ \ + * (2) Y Z (2) (other utilities) + * + * All roots (A & C) have a criticalPathLength of 0. + * B has a score of 1, since A depends on it. + * D has a score of 2, since we look at the longest chain (e.g D->B->A is longer than D->C) + * X has a score of 1, since the only package which depends on it is A + * Z has a score of 2, since only X depends on it, and X has a score of 1 + * Y has a score of 2, since the chain Y->X->C is longer than Y->C + * ``` + * + * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength() + */ + public criticalPathLength: number | undefined = undefined; + + /** + * The set of operations that must complete before this operation executes. + */ + public readonly dependencies: Set = new Set(); + /** + * The set of operations that depend on this operation. + */ + public readonly consumers: Set = new Set(); + + public readonly stopwatch: Stopwatch = new Stopwatch(); + public readonly stdioSummarizer: StdioSummarizer = new StdioSummarizer({ + // 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({ + 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; + public readonly associatedProject: RushConfigurationProject; + public readonly _operationMetadataManager: OperationMetadataManager; + + public logFilePaths: ILogFilePaths | undefined; + + private readonly _context: IOperationExecutionRecordContext; + + private _collatedWriter: CollatedWriter | undefined = undefined; + private _status: OperationStatus; + private _stateHash: string | undefined; + private _stateHashComponents: ReadonlyArray | undefined; + + public constructor(operation: Operation, context: IOperationExecutionRecordContext) { + const { runner, associatedPhase, associatedProject } = operation; + + if (!runner) { + throw new InternalError( + `Operation for phase '${associatedPhase.name}' and project '${associatedProject.packageName}' has no runner.` + ); + } + + this.operation = operation; + this.runner = runner; + this.associatedPhase = associatedPhase; + this.associatedProject = associatedProject; + this.logFilePaths = 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; + } + + public get quietMode(): boolean { + return this._context.quietMode; + } + + public get collatedWriter(): CollatedWriter { + // Lazy instantiate because the registerTask() call affects display ordering + if (!this._collatedWriter) { + this._collatedWriter = this._context.streamCollator.registerTask(this.name); + } + return this._collatedWriter; + } + + public get nonCachedDurationMs(): number | undefined { + // Lazy calculated because the state file is created/restored later on + return this._operationMetadataManager?.stateFile.state?.nonCachedDurationMs; + } + + public get cobuildRunnerId(): string | undefined { + // Lazy calculated because the state file is created/restored later on + return this._operationMetadataManager?.stateFile.state?.cobuildRunnerId; + } + + public get environment(): IEnvironment | undefined { + return this._context.createEnvironment?.(this); + } + + public get metadataFolderPath(): string | undefined { + return this._operationMetadataManager?.metadataFolderPath; + } + + public get isTerminal(): boolean { + return TERMINAL_STATUSES.has(this.status); + } + + /** + * 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 + * the operation is executing. Once execution is complete, it is either 'success' or + * 'failure'. + */ + public get status(): OperationStatus { + return this._status; + } + public set status(newStatus: OperationStatus) { + if (newStatus === this._status) { + return; + } + this._status = newStatus; + this._context.onOperationStatusChanged?.(this); + } + + public get silent(): boolean { + return !this.operation.enabled || this.runner.silent; + } + + public getStateHash(): string { + if (this._stateHash === undefined) { + const components: readonly string[] = this.getStateHashComponents(); + + const hasher: crypto.Hash = crypto.createHash('sha1'); + components.forEach((component) => { + hasher.update(`${RushConstants.hashDelimiter}${component}`); + }); + + const hash: string = hasher.digest('hex'); + this._stateHash = hash; + } + return this._stateHash; + } + + public getStateHashComponents(): ReadonlyArray { + 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 components: string[] = Array.from(this.dependencies, (record) => { + return `${RushConstants.hashDelimiter}${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 localStateHash: string = inputsSnapshot.getOperationOwnStateHash( + associatedProject, + associatedPhase.name + ); + components.push(`${RushConstants.hashDelimiter}local=${localStateHash}`); + + // Examples of data in the config hash: + // - CLI parameters (ShellOperationRunner) + const configHash: string = this.runner.getConfigHash(); + components.push(`${RushConstants.hashDelimiter}config=${configHash}`); + this._stateHashComponents = components; + } + return this._stateHashComponents; + } + + /** + * {@inheritdoc IOperationRunnerContext.runWithTerminalAsync} + */ + public async runWithTerminalAsync( + callback: (terminal: ITerminal, terminalProvider: ITerminalProvider) => Promise, + options: { + createLogFile: boolean; + logFileSuffix: string; + } + ): Promise { + const { associatedProject, stdioSummarizer, problemCollector } = this; + const { createLogFile, logFileSuffix = '' } = options; + + const logFilePaths: ILogFilePaths | undefined = createLogFile + ? getProjectLogFilePaths({ + project: associatedProject, + logFilenameIdentifier: `${this._operationMetadataManager.logFilenameIdentifier}${logFileSuffix}` + }) + : undefined; + this.logFilePaths = logFilePaths; + + const projectLogWritable: TerminalWritable | undefined = logFilePaths + ? await initializeProjectLogFilesAsync({ + logFilePaths, + enableChunkedOutput: true + }) + : undefined; + + try { + //#region OPERATION LOGGING + // TERMINAL PIPELINE: + // + // +--> quietModeTransform? --> collatedWriter + // | + // normalizeNewlineTransform --1--> stderrLineTransform --2--> projectLogWritable + // | + // +--> stdioSummarizer + const destination: TerminalWritable = projectLogWritable + ? new SplitterTransform({ + destinations: [projectLogWritable, stdioSummarizer, problemCollector] + }) + : stdioSummarizer; + + const stderrLineTransform: StderrLineTransform = new StderrLineTransform({ + destination, + newlineKind: NewlineKind.Lf // for StdioSummarizer + }); + + const splitterTransform1: SplitterTransform = new SplitterTransform({ + destinations: [ + this.quietMode + ? new DiscardStdoutTransform({ destination: this.collatedWriter }) + : this.collatedWriter, + stderrLineTransform + ] + }); + + const normalizeNewlineTransform: TextRewriterTransform = new TextRewriterTransform({ + destination: splitterTransform1, + normalizeNewlines: NewlineKind.Lf, + ensureNewlineAtEnd: true + }); + + const collatedTerminal: CollatedTerminal = new CollatedTerminal(normalizeNewlineTransform); + const terminalProvider: CollatedTerminalProvider = new CollatedTerminalProvider(collatedTerminal, { + debugEnabled: this.debugMode + }); + const terminal: Terminal = new Terminal(terminalProvider); + //#endregion + + const result: T = await callback(terminal, terminalProvider); + + normalizeNewlineTransform.close(); + + // If the pipeline is wired up correctly, then closing normalizeNewlineTransform should + // have closed projectLogWritable. + if (projectLogWritable?.isOpen) { + throw new InternalError('The output file handle was not closed'); + } + + return result; + } finally { + projectLogWritable?.close(); + } + } + + public async executeAsync({ + onStart, + onResult + }: { + onStart: (record: OperationExecutionRecord) => Promise; + onResult: (record: OperationExecutionRecord) => Promise; + }): Promise { + if (!this.isTerminal) { + this.stopwatch.reset(); + } + this.stopwatch.start(); + this.status = OperationStatus.Executing; + + try { + const earlyReturnStatus: OperationStatus | undefined = await onStart(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.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); + } catch (error) { + this.status = OperationStatus.Failure; + this.error = error; + // 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); + } finally { + if (this.isTerminal) { + this._collatedWriter?.close(); + this.stdioSummarizer.close(); + this.problemCollector.close(); + } + } + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts b/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts new file mode 100644 index 00000000000..e3f1f2f0dc5 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts @@ -0,0 +1,220 @@ +// 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 { Async, FileSystem, type IFileSystemCopyFileOptions } from '@rushstack/node-core-library'; +import { + type ITerminalChunk, + TerminalChunkKind, + TerminalProviderSeverity, + type ITerminal, + type ITerminalProvider +} from '@rushstack/terminal'; + +import { OperationStateFile } from './OperationStateFile'; +import { RushConstants } from '../RushConstants'; +import type { IOperationStateJson } from './OperationStateFile'; +import type { Operation } from './Operation'; +import { type IStopwatchResult, Stopwatch } from '../../utilities/Stopwatch'; + +/** + * @internal + */ +export interface IOperationMetadataManagerOptions { + operation: Operation; +} + +/** + * @internal + */ +export interface IOperationMetaData { + durationInSeconds: number; + logPath: string; + errorLogPath: string; + logChunksPath: string; + cobuildContextId: string | undefined; + cobuildRunnerId: string | undefined; +} + +export interface ILogChunkStorage { + chunks: ITerminalChunk[]; +} + +/** + * A helper class for managing the meta files of a operation. + * + * @internal + */ +export class OperationMetadataManager { + public readonly stateFile: OperationStateFile; + public readonly logFilenameIdentifier: string; + private readonly _metadataFolderPath: string; + private readonly _logPath: string; + private readonly _errorLogPath: string; + private readonly _logChunksPath: string; + public wasCobuilt: boolean = false; + + public constructor(options: IOperationMetadataManagerOptions) { + const { + operation: { logFilenameIdentifier, associatedProject } + } = options; + const { projectFolder } = associatedProject; + + this.logFilenameIdentifier = logFilenameIdentifier; + + const metadataFolderPath: string = `${RushConstants.projectRushFolderName}/${RushConstants.rushTempFolderName}/operation/${logFilenameIdentifier}`; + + this.stateFile = new OperationStateFile({ + projectFolder: projectFolder, + metadataFolder: metadataFolderPath + }); + + this._metadataFolderPath = metadataFolderPath; + this._logPath = `${projectFolder}/${metadataFolderPath}/all.log`; + this._errorLogPath = `${projectFolder}/${metadataFolderPath}/error.log`; + this._logChunksPath = `${projectFolder}/${metadataFolderPath}/log-chunks.jsonl`; + } + + /** + * Returns the relative paths of the metadata files to project folder. + * + * Example: `.rush/temp/operation/_phase_build/state.json` + * Example: `.rush/temp/operation/_phase_build/all.log` + * Example: `.rush/temp/operation/_phase_build/error.log` + */ + public get metadataFolderPath(): string { + return this._metadataFolderPath; + } + + public async saveAsync({ + durationInSeconds, + cobuildContextId, + cobuildRunnerId, + logPath, + errorLogPath, + logChunksPath + }: IOperationMetaData): Promise { + const state: IOperationStateJson = { + nonCachedDurationMs: durationInSeconds * 1000, + cobuildContextId, + cobuildRunnerId + }; + await this.stateFile.writeAsync(state); + + const copyFileOptions: IFileSystemCopyFileOptions[] = [ + { + sourcePath: logPath, + destinationPath: this._logPath + }, + { + sourcePath: errorLogPath, + destinationPath: this._errorLogPath + }, + { + sourcePath: logChunksPath, + destinationPath: this._logChunksPath + } + ]; + + // Try to copy log files + await Async.forEachAsync(copyFileOptions, async (options) => { + try { + await FileSystem.copyFileAsync(options); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + }); + } + + public async tryRestoreAsync({ + terminal, + terminalProvider, + 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); + const chunks: ITerminalChunk[] = []; + for (const chunk of rawLogChunks.split('\n')) { + if (chunk) { + chunks.push(JSON.parse(chunk)); + } + } + for (const { kind, text } of chunks) { + if (kind === TerminalChunkKind.Stderr) { + terminalProvider.write(text, TerminalProviderSeverity.error); + } else { + terminalProvider.write(text, TerminalProviderSeverity.log); + } + } + } catch (e) { + if (FileSystem.isNotExistError(e)) { + // Log chunks file doesn't exist, try to restore log file + await restoreFromLogFile(terminal, this._logPath); + } else { + throw e; + } + } + + // Try to restore cached error log as error log file + try { + await FileSystem.copyFileAsync({ + sourcePath: this._errorLogPath, + destinationPath: errorLogPath + }); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + } + + 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 { + let logReadStream: fs.ReadStream | undefined; + + try { + logReadStream = fs.createReadStream(path, { + encoding: 'utf-8' + }); + for await (const data of logReadStream) { + terminal.write(data); + } + } catch (logReadStreamError) { + if (!FileSystem.isNotExistError(logReadStreamError)) { + throw logReadStreamError; + } + } finally { + // Close the read stream + logReadStream?.close(); + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts b/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts new file mode 100644 index 00000000000..4c5af75f6b8 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts @@ -0,0 +1,312 @@ +// 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 { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { + ICreateOperationsContext, + 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'; + +/** + * Format "======" lines for a shell window with classic 80 columns + */ +const ASCII_HEADER_WIDTH: number = 79; + +type IOperationAndResult = [Operation, IOperationExecutionResult]; +type IOperationsByStatus = Map; + +/** + * Phased command plugin that emits a summary of build results to the console. + */ +export class OperationResultSummarizerPlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + } + + public apply(hooks: PhasedCommandHooks): void { + hooks.afterExecuteOperations.tap( + PLUGIN_NAME, + (result: IExecutionResult, context: ICreateOperationsContext): void => { + _printOperationStatus(this._terminal, result); + } + ); + } +} + +/** + * Prints out a report of the status of each project + * @internal + */ +export function _printOperationStatus(terminal: ITerminal, result: IExecutionResult): void { + const { operationResults } = result; + + const operationsByStatus: IOperationsByStatus = new Map(); + for (const record of operationResults) { + if (record[1].silent) { + // Don't report silenced operations + continue; + } + + const { status } = record[1]; + switch (status) { + // These are the sections that we will report below + case OperationStatus.Skipped: + case OperationStatus.FromCache: + case OperationStatus.Success: + case OperationStatus.SuccessWithWarning: + case OperationStatus.Blocked: + case OperationStatus.Failure: + case OperationStatus.NoOp: + case OperationStatus.Aborted: + break; + default: + // This should never happen + throw new InternalError(`Unexpected operation status: ${status}`); + } + + const collection: IOperationAndResult[] | undefined = operationsByStatus.get(status); + if (collection) { + collection.push(record); + } else { + operationsByStatus.set(status, [record]); + } + } + + // Skip a few lines before we start the summary + terminal.writeLine('\n\n'); + + // These are ordered so that the most interesting statuses appear last: + writeCondensedSummary( + terminal, + OperationStatus.Skipped, + operationsByStatus, + Colorize.green, + 'These operations were already up to date:' + ); + + writeCondensedSummary( + terminal, + OperationStatus.NoOp, + operationsByStatus, + Colorize.gray, + 'These operations did not define any work:' + ); + + writeCondensedSummary( + terminal, + OperationStatus.FromCache, + operationsByStatus, + Colorize.green, + 'These operations were restored from the build cache:' + ); + + writeCondensedSummary( + terminal, + OperationStatus.Success, + operationsByStatus, + Colorize.green, + 'These operations completed successfully:' + ); + + writeDetailedSummary( + terminal, + OperationStatus.SuccessWithWarning, + operationsByStatus, + Colorize.yellow, + 'WARNING' + ); + + writeCondensedSummary( + terminal, + OperationStatus.Aborted, + operationsByStatus, + Colorize.white, + 'These operations were aborted:' + ); + + writeCondensedSummary( + terminal, + OperationStatus.Blocked, + operationsByStatus, + Colorize.white, + 'These operations were blocked by dependencies that failed:' + ); + + writeDetailedSummary(terminal, OperationStatus.Failure, operationsByStatus, Colorize.red); + + terminal.writeLine(''); + + switch (result.status) { + case OperationStatus.Failure: + terminal.writeErrorLine('Operations failed.\n'); + break; + case OperationStatus.SuccessWithWarning: + terminal.writeWarningLine('Operations succeeded with warnings.\n'); + break; + } +} + +function writeCondensedSummary( + terminal: ITerminal, + status: OperationStatus, + operationsByStatus: IOperationsByStatus, + headingColor: (text: string) => string, + preamble: string +): void { + // Example: + // + // ==[ BLOCKED: 4 projects ]============================================================== + // + // These projects were blocked by dependencies that failed: + // @scope/name + // e + // k + const operations: IOperationAndResult[] | undefined = operationsByStatus.get(status); + if (!operations || operations.length === 0) { + return; + } + + writeSummaryHeader(terminal, status, operations, headingColor); + terminal.writeLine(preamble); + + let longestTaskName: number = 0; + for (const [operation] of operations) { + 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 ( + stopwatch.duration !== 0 && + operation.runner!.reportTiming && + operationResult.status !== OperationStatus.Skipped + ) { + const time: string = stopwatch.toString(); + const padding: string = ' '.repeat(longestTaskName - (operation.name || '').length); + 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}`); + } + } + terminal.writeLine(''); +} + +function writeDetailedSummary( + terminal: ITerminal, + status: OperationStatus, + operationsByStatus: IOperationsByStatus, + headingColor: (text: string) => string, + shortStatusName?: string +): void { + // Example: + // + // ==[ SUCCESS WITH WARNINGS: 2 projects ]================================ + // + // --[ WARNINGS: f ]------------------------------------[ 5.07 seconds ]-- + // + // [eslint] Warning: src/logic/operations/OperationsExecutionManager.ts:393:3 ... + + const operations: IOperationAndResult[] | undefined = operationsByStatus.get(status); + if (!operations || operations.length === 0) { + return; + } + + writeSummaryHeader(terminal, status, operations, headingColor); + + if (shortStatusName === undefined) { + shortStatusName = status; + } + + for (const [operation, operationResult] of operations) { + const { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; + // Format a header like this + // + // --[ WARNINGS: f ]------------------------------------[ 5.07 seconds ]-- + + // leftPart: "--[ WARNINGS: f " + const subheadingText: string = `${shortStatusName}: ${operation.name}`; + + const leftPartLength: number = 4 + subheadingText.length + 1; + + // rightPart: " 5.07 seconds ]--" + const stopwatch: IStopwatchResult = + operationMetadataManager?.tryRestoreStopwatch(operationResult.stopwatch) ?? operationResult.stopwatch; + const time: string = stopwatch.toString(); + const rightPartLength: number = 1 + time.length + 1 + 3; + + // middlePart: "]----------------------[" + const twoBracketsLength: 2 = 2; + const middlePartLengthMinusTwoBrackets: number = Math.max( + ASCII_HEADER_WIDTH - (leftPartLength + rightPartLength + twoBracketsLength), + 0 + ); + + terminal.writeLine( + `${Colorize.gray('--[')} ${headingColor(subheadingText)} ${Colorize.gray( + `]${'-'.repeat(middlePartLengthMinusTwoBrackets)}[` + )} ${Colorize.white(time)} ${Colorize.gray(']--')}\n` + ); + + const details: string = operationResult.stdioSummarizer.getReport(); + if (details) { + // Don't write a newline, because the report will always end with a newline + terminal.write(details); + } + + terminal.writeLine(''); + } +} + +function writeSummaryHeader( + terminal: ITerminal, + status: OperationStatus, + operations: ReadonlyArray, + headingColor: (text: string) => string +): void { + // Format a header like this + // + // ==[ FAILED: 2 operations ]================================================ + + // "2 operations" + const projectsText: string = `${operations.length}${ + operations.length === 1 ? ' operation' : ' operations' + }`; + const headingText: string = `${status}: ${projectsText}`; + + // leftPart: "==[ FAILED: 2 operations " + const leftPartLength: number = 3 + 1 + headingText.length + 1; + + const rightPartLengthMinusBracket: number = Math.max(ASCII_HEADER_WIDTH - (leftPartLength + 1), 0); + + // rightPart: "]======================" + + terminal.writeLine( + `${Colorize.gray('==[')} ${headingColor(headingText)} ${Colorize.gray( + `]${'='.repeat(rightPartLengthMinusBracket)}` + )}\n` + ); +} diff --git a/libraries/rush-lib/src/logic/operations/OperationStateFile.ts b/libraries/rush-lib/src/logic/operations/OperationStateFile.ts new file mode 100644 index 00000000000..b05cf70b57f --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationStateFile.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 { FileSystem, InternalError, JsonFile } from '@rushstack/node-core-library'; + +/** + * @internal + */ +export interface IOperationStateFileOptions { + projectFolder: string; + metadataFolder: string; +} + +/** + * @internal + */ +export interface IOperationStateJson { + nonCachedDurationMs: number; + cobuildContextId: string | undefined; + cobuildRunnerId: string | undefined; +} + +/** + * A helper class for managing the state file of a operation. + * + * @internal + */ +export class OperationStateFile { + private _state: IOperationStateJson | undefined; + + /** + * The path of the state json file. + * + * Example: `/code/repo/my-project/.rush/temp/operation/_phase_build/state.json` + */ + public readonly filepath: string; + + /** + * The relative path of the state json file to project folder + * + * Example: `.rush/temp/operation/_phase_build/state.json` + */ + public readonly relativeFilepath: string; + + public static filename: string = 'state.json'; + + public constructor(options: IOperationStateFileOptions) { + const { projectFolder, metadataFolder } = options; + this.relativeFilepath = `${metadataFolder}/${OperationStateFile.filename}`; + this.filepath = `${projectFolder}/${this.relativeFilepath}`; + } + + public get state(): IOperationStateJson | undefined { + return this._state; + } + + public async writeAsync(json: IOperationStateJson): Promise { + await JsonFile.saveAsync(json, this.filepath, { ensureFolderExists: true, ignoreUndefinedValues: true }); + this._state = json; + } + + public async tryRestoreAsync(): Promise { + try { + this._state = await JsonFile.loadAsync(this.filepath); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + this._state = undefined; + } else { + // This should not happen + throw new InternalError(error); + } + } + return this._state; + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationStatus.ts b/libraries/rush-lib/src/logic/operations/OperationStatus.ts new file mode 100644 index 00000000000..6bff6959ef4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationStatus.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. + +/** + * Enumeration defining potential states of an operation + * @beta + */ +export enum OperationStatus { + /** + * The Operation is ready to execute. All its dependencies have succeeded. + */ + Ready = 'READY', + /** + * The Operation is waiting for one or more dependencies to complete. + */ + Waiting = 'WAITING', + /** + * The Operation is Queued + */ + Queued = 'QUEUED', + /** + * The Operation is currently executing + */ + Executing = 'EXECUTING', + /** + * The Operation completed successfully and did not write to standard output + */ + Success = 'SUCCESS', + /** + * The Operation completed successfully, but wrote to standard output + */ + SuccessWithWarning = 'SUCCESS WITH WARNINGS', + /** + * The Operation was skipped via the legacy incremental build logic + */ + Skipped = 'SKIPPED', + /** + * The Operation had its outputs restored from the build cache + */ + FromCache = 'FROM CACHE', + /** + * The Operation failed + */ + Failure = 'FAILURE', + /** + * The Operation could not be executed because one or more of its dependencies failed + */ + Blocked = 'BLOCKED', + /** + * The Operation was a no-op (for example, it had an empty script) + */ + NoOp = 'NO OP', + /** + * The Operation was aborted before it could execute. + */ + Aborted = 'ABORTED' +} + +/** + * The set of statuses that are considered terminal. + * @alpha + */ +export const TERMINAL_STATUSES: Set = new Set([ + OperationStatus.Success, + OperationStatus.SuccessWithWarning, + OperationStatus.Skipped, + OperationStatus.Blocked, + OperationStatus.FromCache, + OperationStatus.Failure, + OperationStatus.NoOp, + OperationStatus.Aborted +]); diff --git a/libraries/rush-lib/src/logic/operations/PeriodicCallback.ts b/libraries/rush-lib/src/logic/operations/PeriodicCallback.ts new file mode 100644 index 00000000000..26aa1814f55 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/PeriodicCallback.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. + +export type ICallbackFn = () => Promise | void; + +export interface IPeriodicCallbackOptions { + interval: number; +} + +/** + * A help class to run callbacks in a loop with a specified interval. + * + * @beta + */ +export class PeriodicCallback { + private _callbacks: ICallbackFn[]; + private _interval: number; + private _intervalId: NodeJS.Timeout | undefined; + private _isRunning: boolean; + + public constructor(options: IPeriodicCallbackOptions) { + this._callbacks = []; + this._interval = options.interval; + this._isRunning = false; + } + + public addCallback(callback: ICallbackFn): void { + if (this._isRunning) { + throw new Error('Can not add callback while watcher is running'); + } + this._callbacks.push(callback); + } + + public start(): void { + if (this._intervalId) { + throw new Error('Watcher already started'); + } + if (this._callbacks.length === 0) { + return; + } + this._isRunning = true; + this._intervalId = setInterval(() => { + this._callbacks.forEach((callback) => callback()); + }, this._interval); + } + + public stop(): void { + if (this._intervalId) { + clearInterval(this._intervalId); + this._intervalId = undefined; + this._isRunning = false; + } + } +} diff --git a/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts new file mode 100644 index 00000000000..d83ff4bad07 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.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 { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IPhase } from '../../api/CommandLineConfiguration'; +import { Operation } from './Operation'; +import type { + ICreateOperationsContext, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationSettings } from '../../api/RushProjectConfiguration'; + +const PLUGIN_NAME: 'PhasedOperationPlugin' = 'PhasedOperationPlugin'; + +/** + * Core phased command plugin that provides the functionality for generating a base operation graph + * from the set of selected projects and phases. + */ +export class PhasedOperationPlugin implements IPhasedCommandPlugin { + public apply(hooks: PhasedCommandHooks): void { + hooks.createOperations.tap(PLUGIN_NAME, createOperations); + // Configure operations later. + hooks.createOperations.tap( + { + name: `${PLUGIN_NAME}.Configure`, + stage: 1000 + }, + configureOperations + ); + } +} + +function createOperations( + existingOperations: Set, + context: ICreateOperationsContext +): Set { + const { phaseSelection, projectSelection, projectConfigurations } = context; + + const operations: Map = new Map(); + + // Create tasks for selected phases and projects + // This also creates the minimal set of dependencies needed + for (const phase of phaseSelection) { + for (const project of projectSelection) { + getOrCreateOperation(phase, project); + } + } + + return existingOperations; + + // Binds phaseSelection, projectSelection, operations via closure + function getOrCreateOperation(phase: IPhase, project: RushConfigurationProject): Operation { + const key: string = getOperationKey(phase, project); + let operation: Operation | undefined = operations.get(key); + + if (!operation) { + const { + dependencies: { self, upstream }, + name, + logFilenameIdentifier + } = phase; + const operationSettings: IOperationSettings | undefined = projectConfigurations + .get(project) + ?.operationSettingsByOperationName.get(name); + operation = new Operation({ + project, + phase, + settings: operationSettings, + logFilenameIdentifier: logFilenameIdentifier + }); + + operations.set(key, operation); + existingOperations.add(operation); + + for (const depPhase of self) { + operation.addDependency(getOrCreateOperation(depPhase, project)); + } + + if (upstream.size) { + const { dependencyProjects } = project; + if (dependencyProjects.size) { + for (const depPhase of upstream) { + for (const dependencyProject of dependencyProjects) { + operation.addDependency(getOrCreateOperation(depPhase, dependencyProject)); + } + } + } + } + } + + return operation; + } +} + +function configureOperations(operations: Set, context: ICreateOperationsContext): Set { + const { + changedProjectsOnly, + projectsInUnknownState: changedProjects, + phaseOriginal, + phaseSelection, + projectSelection, + includePhaseDeps, + isInitial + } = context; + + const basePhases: ReadonlySet = includePhaseDeps ? phaseOriginal : phaseSelection; + + // Grab all operations that were explicitly requested. + const operationsWithWork: Set = new Set(); + for (const operation of operations) { + const { associatedPhase, associatedProject } = operation; + if (basePhases.has(associatedPhase) && changedProjects.has(associatedProject)) { + operationsWithWork.add(operation); + } + } + + if (!isInitial && changedProjectsOnly) { + const potentiallyAffectedOperations: Set = new Set(operationsWithWork); + for (const operation of potentiallyAffectedOperations) { + if (operation.settings?.ignoreChangedProjectsOnlyFlag) { + operationsWithWork.add(operation); + } + + for (const consumer of operation.consumers) { + potentiallyAffectedOperations.add(consumer); + } + } + } else { + // Add all operations that are selected that depend on the explicitly requested operations. + // This will mostly be relevant during watch; in initial runs it should not add any new operations. + for (const operation of operationsWithWork) { + for (const consumer of operation.consumers) { + operationsWithWork.add(consumer); + } + } + } + + if (includePhaseDeps) { + // Add all operations that are dependencies of the operations already scheduled. + for (const operation of operationsWithWork) { + for (const dependency of operation.dependencies) { + operationsWithWork.add(dependency); + } + } + } + + for (const operation of operations) { + // Enable exactly the set of operations that are requested. + operation.enabled &&= operationsWithWork.has(operation); + + if (!includePhaseDeps || !isInitial) { + const { associatedPhase, associatedProject } = operation; + + // This filter makes the "unsafe" selections happen. + operation.enabled &&= phaseSelection.has(associatedPhase) && projectSelection.has(associatedProject); + } + } + + return operations; +} + +// 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 new file mode 100644 index 00000000000..457ec654d23 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.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 ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; + +import { Async, FileSystem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +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'; + +export class PnpmSyncCopyOperationPlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + 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; + } + + const pnpmSyncJsonPath: string = `${project.projectFolder}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; + if (await FileSystem.exists(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, this._terminal) + }); + } + } + ); + } +} diff --git a/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts b/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts new file mode 100644 index 00000000000..e486d8b6723 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts @@ -0,0 +1,307 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, FileWriter, InternalError, NewlineKind } from '@rushstack/node-core-library'; +import { + SplitterTransform, + TerminalChunkKind, + TerminalWritable, + TextRewriterTransform, + type ITerminalChunk +} from '@rushstack/terminal'; + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { PackageNameParsers } from '../../api/PackageNameParsers'; +import { RushConstants } from '../RushConstants'; + +export interface IProjectLogWritableOptions { + logFilePaths: ILogFilePaths; + enableChunkedOutput?: boolean; +} + +export interface ILogFileNames { + textFileName: string; + jsonlFileName: string; + errorFileName: string; +} + +/** + * Information about the log files for an operation. + * + * @alpha + */ +export interface ILogFilePaths { + /** + * The absolute path to the folder containing the text log files. + * Provided as a convenience since it is an intermediary value of producing the text log file path. + */ + textFolder: string; + /** + * The absolute path to the folder containing the JSONL log files. + * Provided as a convenience since it is an intermediary value of producing the jsonl log file path. + */ + jsonlFolder: string; + + /** + * The absolute path to the merged (interleaved stdout and stderr) text log. + * ANSI escape codes have been stripped. + */ + text: string; + /** + * The absolute path to the stderr text log. + * ANSI escape codes have been stripped. + */ + error: string; + /** + * The absolute path to the JSONL log. ANSI escape codes are left intact to be able to reproduce the console output. + */ + jsonl: string; +} + +export interface IGetLogFilePathsOptions { + project: Pick; + logFilenameIdentifier: string; +} + +const LOG_CHUNKS_FOLDER_RELATIVE_PATH: string = `${RushConstants.projectRushFolderName}/${RushConstants.rushTempFolderName}/chunked-rush-logs`; + +/** + * A terminal stream that writes all log chunks to a JSONL format so they can be faithfully reconstructed + * during build cache restores. This is used for adding warning + error messages in cobuilds where the original + * logs cannot be completely restored from the existing `all.log` and `error.log` files. + * + * Example output: + * libraries/rush-lib/.rush/temp/operations/rush-lib._phase_build.chunks.jsonl + * ``` + * {"kind":"O","text":"Invoking: heft run --only build -- --clean \n"} + * {"kind":"O","text":" ---- build started ---- \n"} + * {"kind":"O","text":"[build:clean] Deleted 0 files and 5 folders\n"} + * {"kind":"O","text":"[build:typescript] Using TypeScript version 5.4.2\n"} + * {"kind":"O","text":"[build:lint] Using ESLint version 8.57.0\n"} + * {"kind":"E","text":"[build:lint] Warning: libraries/rush-lib/src/logic/operations/LogChunksWritable.ts:15:7 - (@typescript-eslint/typedef) Expected test to have a type annotation.\n"} + * {"kind":"E","text":"[build:lint] Warning: libraries/rush-lib/src/logic/operations/LogChunksWritable.ts:15:7 - (@typescript-eslint/no-unused-vars) 'test' is assigned a value but never used.\n"} + * {"kind":"O","text":"[build:typescript] Copied 1138 folders or files and linked 0 files\n"} + * {"kind":"O","text":"[build:webpack] Using Webpack version 5.82.1\n"} + * {"kind":"O","text":"[build:webpack] Running Webpack compilation\n"} + * {"kind":"O","text":"[build:api-extractor] Using API Extractor version 7.43.1\n"} + * {"kind":"O","text":"[build:api-extractor] Analysis will use the bundled TypeScript version 5.4.2\n"} + * {"kind":"O","text":"[build:copy-mock-flush-telemetry-plugin] Copied 1260 folders or files and linked 5 files\n"} + * {"kind":"O","text":" ---- build finished (6.856s) ---- \n"} + * {"kind":"O","text":"-------------------- Finished (6.858s) --------------------\n"} + * ``` + */ +export class JsonLFileWritable extends TerminalWritable { + public readonly logPath: string; + + private _writer: FileWriter | undefined; + + public constructor(logPath: string) { + super(); + + this.logPath = logPath; + + this._writer = FileWriter.open(logPath); + } + + // Override writeChunk function to throw custom error + public override writeChunk(chunk: ITerminalChunk): void { + if (!this._writer) { + throw new InternalError(`Log writer was closed for ${this.logPath}`); + } + // Stderr can always get written to a error log writer + super.writeChunk(chunk); + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (!this._writer) { + throw new InternalError(`Log writer was closed for ${this.logPath}`); + } + this._writer.write(JSON.stringify(chunk) + '\n'); + } + + protected onClose(): void { + if (this._writer) { + try { + this._writer.close(); + } catch (error) { + throw new InternalError('Failed to close file handle for ' + this._writer.filePath); + } + this._writer = undefined; + } + } +} + +/** + * A terminal stream that writes two text log files: one with interleaved stdout and stderr, and one with just stderr. + */ +export class SplitLogFileWritable extends TerminalWritable { + public readonly logPath: string; + public readonly errorLogPath: string; + + private _logWriter: FileWriter | undefined = undefined; + private _errorLogWriter: FileWriter | undefined = undefined; + + public constructor(logPath: string, errorLogPath: string) { + super(); + + this.logPath = logPath; + this.errorLogPath = errorLogPath; + + this._logWriter = FileWriter.open(logPath); + this._errorLogWriter = undefined; + } + + // Override writeChunk function to throw custom error + public override writeChunk(chunk: ITerminalChunk): void { + if (!this._logWriter) { + throw new InternalError(`Log writer was closed for ${this.logPath}`); + } + // Stderr can always get written to a error log writer + super.writeChunk(chunk); + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (!this._logWriter) { + throw new InternalError('Output file was closed'); + } + // Both stderr and stdout get written to *..log + this._logWriter.write(chunk.text); + + if (chunk.kind === TerminalChunkKind.Stderr) { + // Only stderr gets written to *..error.log + if (!this._errorLogWriter) { + this._errorLogWriter = FileWriter.open(this.errorLogPath); + } + this._errorLogWriter.write(chunk.text); + } + } + + protected onClose(): void { + if (this._logWriter) { + try { + this._logWriter.close(); + } catch (error) { + throw new InternalError('Failed to close file handle for ' + this._logWriter.filePath); + } + this._logWriter = undefined; + } + + if (this._errorLogWriter) { + try { + this._errorLogWriter.close(); + } catch (error) { + throw new InternalError('Failed to close file handle for ' + this._errorLogWriter.filePath); + } + this._errorLogWriter = undefined; + } + } +} + +/** + * Initializes the project log files for a project. Produces a combined log file, an error log file, and optionally a + * chunks file that can be used to reconstrct the original console output. + * @param options - The options to initialize the project log files. + * @returns The terminal writable stream that will write to the log files. + */ +export async function initializeProjectLogFilesAsync( + options: IProjectLogWritableOptions +): Promise { + const { logFilePaths, enableChunkedOutput = false } = options; + + const { + textFolder: logFolderPath, + jsonlFolder: jsonlFolderPath, + text: logPath, + error: errorLogPath, + jsonl: jsonlPath + } = logFilePaths; + await Promise.all([ + FileSystem.ensureFolderAsync(logFolderPath), + enableChunkedOutput && FileSystem.ensureFolderAsync(jsonlFolderPath), + FileSystem.deleteFileAsync(logPath), + FileSystem.deleteFileAsync(errorLogPath), + FileSystem.deleteFileAsync(jsonlPath) + ]); + + const splitLog: TerminalWritable = new TextRewriterTransform({ + destination: new SplitLogFileWritable(logPath, errorLogPath), + removeColors: true, + normalizeNewlines: NewlineKind.OsDefault + }); + + if (enableChunkedOutput) { + const chunksFile: JsonLFileWritable = new JsonLFileWritable(jsonlPath); + const splitter: SplitterTransform = new SplitterTransform({ + destinations: [splitLog, chunksFile] + }); + return splitter; + } + + return splitLog; +} + +/** + * @internal + * + * @param packageName - The raw package name + * @param logFilenameIdentifier - The identifier to append to the log file name (typically the phase name) + * @returns The base names of the log files + */ +export function getLogfileBaseNames(packageName: string, logFilenameIdentifier: string): ILogFileNames { + const unscopedProjectName: string = PackageNameParsers.permissive.getUnscopedName(packageName); + const logFileBaseName: string = `${unscopedProjectName}.${logFilenameIdentifier}`; + + return { + textFileName: `${logFileBaseName}.log`, + jsonlFileName: `${logFileBaseName}.chunks.jsonl`, + errorFileName: `${logFileBaseName}.error.log` + }; +} + +/** + * @internal + * + * @param projectFolder - The absolute path of the project folder + * @returns The absolute paths of the log folders for regular and chunked logs + */ +export function getProjectLogFolders( + projectFolder: string +): Pick { + const textFolder: string = `${projectFolder}/${RushConstants.rushLogsFolderName}`; + const jsonlFolder: string = `${projectFolder}/${LOG_CHUNKS_FOLDER_RELATIVE_PATH}`; + + return { textFolder, jsonlFolder }; +} + +/** + * @internal + * + * @param options - The options to get the log file paths + * @returns All information about log file paths for the project and log identifier + */ +export function getProjectLogFilePaths(options: IGetLogFilePathsOptions): ILogFilePaths { + const { + project: { projectFolder, packageName }, + logFilenameIdentifier + } = options; + + const { textFolder, jsonlFolder } = getProjectLogFolders(projectFolder); + const { + textFileName: textLog, + jsonlFileName: jsonlLog, + errorFileName: errorLog + } = getLogfileBaseNames(packageName, logFilenameIdentifier); + + const textPath: string = `${textFolder}/${textLog}`; + const errorPath: string = `${textFolder}/${errorLog}`; + const jsonlPath: string = `${jsonlFolder}/${jsonlLog}`; + + return { + textFolder, + jsonlFolder, + + text: textPath, + error: errorPath, + jsonl: jsonlPath + }; +} diff --git a/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts new file mode 100644 index 00000000000..b4f017dfe3f --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration'; +import type { + ICreateOperationsContext, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import { RushConstants } from '../RushConstants'; +import { NullOperationRunner } from './NullOperationRunner'; +import { Operation } from './Operation'; +import { OperationStatus } from './OperationStatus'; +import { + getCustomParameterValuesByOperation, + type ICustomParameterValuesForOperation, + getDisplayName, + initializeShellOperationRunner +} from './ShellOperationRunnerPlugin'; + +export const PLUGIN_NAME: 'ShardedPhasedOperationPlugin' = 'ShardedPhasedOperationPlugin'; + +// eslint-disable-next-line @typescript-eslint/typedef +const TemplateStrings = { + SHARD_INDEX: '{shardIndex}', + SHARD_COUNT: '{shardCount}', + PHASE_NAME: '{phaseName}' +} as const; + +// eslint-disable-next-line @typescript-eslint/typedef +const TemplateStringRegexes = { + SHARD_INDEX: new RegExp(TemplateStrings.SHARD_INDEX, 'g'), + SHARD_COUNT: new RegExp(TemplateStrings.SHARD_COUNT, 'g'), + PHASE_NAME: new RegExp(TemplateStrings.PHASE_NAME, 'g') +} as const; + +/** + * Phased command that shards a phase into multiple operations. + */ +export class ShardedPhasedOperationPlugin implements IPhasedCommandPlugin { + public apply(hooks: PhasedCommandHooks): void { + hooks.createOperations.tap(PLUGIN_NAME, spliceShards); + } +} + +function spliceShards(existingOperations: Set, context: ICreateOperationsContext): Set { + const { rushConfiguration, projectConfigurations } = context; + + const getCustomParameterValues: (operation: Operation) => ICustomParameterValuesForOperation = + getCustomParameterValuesByOperation(); + + for (const operation of existingOperations) { + const { + associatedPhase: phase, + associatedProject: project, + settings: operationSettings, + logFilenameIdentifier: baseLogFilenameIdentifier + } = operation; + if (operationSettings?.sharding && !operation.runner) { + const { count: shards } = operationSettings.sharding; + + /** + * A single operation to reduce the number of edges in the graph when creating shards. + * ``` + * depA -\ /- shard 1 -\ + * depB -- > noop < -- shard 2 -- > collator (reused operation) + * depC -/ \- shard 3 -/ + * ``` + */ + const preShardOperation: Operation = new Operation({ + phase, + project, + settings: operationSettings, + runner: new NullOperationRunner({ + name: `${getDisplayName(phase, project)} - pre-shard`, + result: OperationStatus.NoOp, + silent: true + }), + logFilenameIdentifier: `${baseLogFilenameIdentifier}_pre-shard` + }); + + existingOperations.add(preShardOperation); + + for (const dependency of operation.dependencies) { + preShardOperation.addDependency(dependency); + operation.deleteDependency(dependency); + } + + const outputFolderArgumentFormat: string = + operationSettings.sharding.outputFolderArgumentFormat ?? + `--shard-output-directory=${RushConstants.projectRushFolderName}/operations/${TemplateStrings.PHASE_NAME}/shards/${TemplateStrings.SHARD_INDEX}`; + + if (!outputFolderArgumentFormat.includes('=')) { + throw new Error( + 'sharding.outputFolderArgumentFormat must contain an "=" sign to differentiate between the key and the value' + ); + } + + if (!outputFolderArgumentFormat.endsWith(TemplateStrings.SHARD_INDEX)) { + throw new Error( + `sharding.outputFolderArgumentFormat must end with ${TemplateStrings.SHARD_INDEX}, "${outputFolderArgumentFormat}"` + ); + } + + // Replace the phase name only to begin with. + const outputDirectoryArgument: string = outputFolderArgumentFormat.replace( + TemplateStringRegexes.PHASE_NAME, + baseLogFilenameIdentifier + ); + + const outputFolderWithTemplate: string = outputDirectoryArgument.substring( + outputDirectoryArgument.indexOf('=') + 1 + ); + + const parentFolder: string = outputFolderWithTemplate.substring( + 0, + outputFolderWithTemplate.indexOf(TemplateStrings.SHARD_INDEX) + ); + + const collatorDisplayName: string = `${getDisplayName(phase, project)} - collate`; + + // Get the custom parameter values for the collator, filtered according to the operation settings + const { parameterValues: customParameterValues, ignoredParameterValues } = + getCustomParameterValues(operation); + + const collatorParameters: string[] = [ + ...customParameterValues, + `--shard-parent-folder="${parentFolder}"`, + `--shard-count="${shards}"` + ]; + + const { scripts } = project.packageJson; + const commandToRun: string | undefined = phase.shellCommand ?? scripts?.[phase.name]; + + operation.logFilenameIdentifier = `${baseLogFilenameIdentifier}_collate`; + operation.runner = initializeShellOperationRunner({ + phase, + project, + displayName: collatorDisplayName, + rushConfiguration, + commandToRun, + customParameterValues: collatorParameters, + ignoredParameterValues + }); + + const shardOperationName: string = `${phase.name}:shard`; + const baseCommand: string | undefined = scripts?.[shardOperationName]; + if (baseCommand === undefined) { + throw new Error( + `The project '${project.packageName}' does not define a '${phase.name}:shard' command in the 'scripts' section of its package.json` + ); + } + + const shardArgumentFormat: string = + operationSettings.sharding.shardArgumentFormat ?? + `--shard=${TemplateStrings.SHARD_INDEX}/${TemplateStrings.SHARD_COUNT}`; + + if ( + operationSettings.sharding.shardArgumentFormat && + !shardArgumentFormat.includes(TemplateStrings.SHARD_INDEX) && + !shardArgumentFormat.includes(TemplateStrings.SHARD_COUNT) + ) { + throw new Error( + `'shardArgumentFormat' must contain both ${TemplateStrings.SHARD_INDEX} and ${TemplateStrings.SHARD_COUNT} to be used for sharding.` + ); + } + + const projectConfiguration: RushProjectConfiguration | undefined = projectConfigurations.get(project); + for (let shard: number = 1; shard <= shards; shard++) { + const outputDirectory: string = outputFolderWithTemplate.replace( + TemplateStringRegexes.SHARD_INDEX, + shard.toString() + ); + + const shardOperationSettings: IOperationSettings = + projectConfiguration?.operationSettingsByOperationName.get(shardOperationName) ?? + (operationSettings.sharding.shardOperationSettings as IOperationSettings); + + const shardOperation: Operation = new Operation({ + project, + phase, + settings: { + ...shardOperationSettings, + operationName: shardOperationName, + outputFolderNames: [outputDirectory] + }, + logFilenameIdentifier: `${baseLogFilenameIdentifier}_shard_${shard}` + }); + + const shardArgument: string = shardArgumentFormat + .replace(TemplateStringRegexes.SHARD_INDEX, shard.toString()) + .replace(TemplateStringRegexes.SHARD_COUNT, shards.toString()); + + const outputDirectoryArgumentWithShard: string = outputDirectoryArgument.replace( + TemplateStringRegexes.SHARD_INDEX, + shard.toString() + ); + + const shardedParameters: string[] = [ + ...customParameterValues, + shardArgument, + outputDirectoryArgumentWithShard + ]; + + const shardDisplayName: string = `${getDisplayName(phase, project)} - shard ${shard}/${shards}`; + + shardOperation.runner = initializeShellOperationRunner({ + phase, + project, + commandToRun: baseCommand, + customParameterValues: shardedParameters, + displayName: shardDisplayName, + rushConfiguration, + ignoredParameterValues + }); + + shardOperation.addDependency(preShardOperation); + operation.addDependency(shardOperation); + existingOperations.add(shardOperation); + } + } + } + + return existingOperations; +} diff --git a/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts b/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts new file mode 100644 index 00000000000..3f9f5dc6ddb --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ShellOperationRunner.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 type * as child_process from 'node:child_process'; + +import { Text } from '@rushstack/node-core-library'; +import { type ITerminal, type ITerminalProvider, TerminalProviderSeverity } from '@rushstack/terminal'; + +import type { IPhase } from '../../api/CommandLineConfiguration'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { Utilities } from '../../utilities/Utilities'; +import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; +import { OperationError } from './OperationError'; +import { OperationStatus } from './OperationStatus'; + +export interface IShellOperationRunnerOptions { + phase: IPhase; + rushProject: RushConfigurationProject; + displayName: string; + commandToRun: string; + commandForHash: string; + ignoredParameterValues: ReadonlyArray; +} + +/** + * 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. + */ +export class ShellOperationRunner implements IOperationRunner { + public readonly name: string; + + public readonly reportTiming: boolean = true; + public readonly silent: boolean = false; + public readonly cacheable: boolean = true; + public readonly warningsAreAllowed: boolean; + public readonly commandToRun: string; + /** + * 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 _commandForHash: string; + + private readonly _rushProject: RushConfigurationProject; + + private readonly _ignoredParameterValues: ReadonlyArray; + + public constructor(options: IShellOperationRunnerOptions) { + const { phase } = options; + + this.name = options.displayName; + this.warningsAreAllowed = + EnvironmentConfiguration.allowWarningsInSuccessfulBuild || phase.allowWarningsOnSuccess || false; + this._rushProject = options.rushProject; + this.commandToRun = options.commandToRun; + this._commandForHash = options.commandForHash; + this._ignoredParameterValues = options.ignoredParameterValues; + } + + 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; + } + + private async _executeAsync(context: IOperationRunnerContext): Promise { + return await context.runWithTerminalAsync( + async (terminal: ITerminal, terminalProvider: ITerminalProvider) => { + let hasWarningOrError: boolean = false; + + // 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.commandToRun}`); + + const { rushConfiguration, projectFolder } = this._rushProject; + + const { environment: initialEnvironment } = context; + + const subProcess: child_process.ChildProcess = Utilities.executeLifecycleCommandAsync( + this.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(); + terminalProvider.write(text, TerminalProviderSeverity.log); + }); + subProcess.stderr?.on('data', (data: Buffer) => { + const text: string = data.toString(); + terminalProvider.write(text, TerminalProviderSeverity.error); + hasWarningOrError = true; + }); + + const status: OperationStatus = await new Promise( + (resolve: (status: OperationStatus) => void, reject: (error: OperationError) => void) => { + subProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { + try { + // Do NOT reject here immediately, give a chance for other logic to suppress the error + if (signal) { + context.error = new OperationError('error', `Terminated by signal: ${signal}`); + resolve(OperationStatus.Failure); + } else if (exitCode !== 0) { + context.error = new OperationError('error', `Returned error code: ${exitCode}`); + resolve(OperationStatus.Failure); + } else if (hasWarningOrError) { + resolve(OperationStatus.SuccessWithWarning); + } else { + resolve(OperationStatus.Success); + } + } catch (error) { + context.error = error as OperationError; + reject(error as OperationError); + } + }); + } + ); + + return status; + }, + { + createLogFile: true + } + ); + } +} + +/** + * When running a command from the "scripts" block in package.json, if the command + * contains Unix-style path slashes and the OS is Windows, the package managers will + * convert slashes to backslashes. This is a complicated undertaking. For example, they + * need to convert "node_modules/bin/this && ./scripts/that --name keep/this" + * to "node_modules\bin\this && .\scripts\that --name keep/this", and they don't want to + * convert ANY of the slashes in "cmd.exe /c echo a/b". NPM and PNPM use npm-lifecycle for this, + * but it unfortunately has a dependency on the entire node-gyp kitchen sink. Yarn has a + * simplified implementation in fix-cmd-win-slashes.js, but it's not exposed as a library. + * + * Fundamentally NPM's whole feature seems misguided: They start by inviting people to write + * shell scripts that will be executed by wildly different shell languages (e.g. cmd.exe and Bash). + * It's very tricky for a developer to guess what's safe to do without testing every OS. + * Even simple path separators are not portable, so NPM added heuristics to figure out which + * slashes are part of a path or not, and convert them. These workarounds end up having tons + * of special cases. They probably could have implemented their own entire minimal cross-platform + * shell language with less code and less confusion than npm-lifecycle's approach. + * + * We've deprecated shell operators inside package.json. Instead, we advise people to move their + * scripts into conventional script files, and put only a file path in package.json. So, for + * Rush's workaround here, we really only care about supporting the small set of cases seen in the + * unit tests. For anything that doesn't fit those patterns, we leave the string untouched + * (i.e. err on the side of not breaking anything). We could revisit this later if someone + * complains about it, but so far nobody has. :-) + */ +export function convertSlashesForWindows(command: string): string { + // The first group will match everything up to the first space, "&", "|", "<", ">", or quote. + // The second group matches the remainder. + const commandRegExp: RegExp = /^([^\s&|<>"]+)(.*)$/; + + const match: RegExpMatchArray | null = commandRegExp.exec(command); + if (match) { + // Example input: "bin/blarg --path ./config/blah.json && a/b" + // commandPart="bin/blarg" + // remainder=" --path ./config/blah.json && a/b" + const commandPart: string = match[1]; + const remainder: string = match[2]; + + // If the command part already contains a backslash, then leave it alone + if (commandPart.indexOf('\\') < 0) { + // Replace all the slashes with backslashes, e.g. to produce: + // "bin\blarg --path ./config/blah.json && a/b" + // + // NOTE: we don't attempt to process the path parameter or stuff after "&&" + return Text.replaceAll(commandPart, '/', '\\') + remainder; + } + } + + // Don't change anything + return command; +} diff --git a/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts b/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts new file mode 100644 index 00000000000..e48a52482f6 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts @@ -0,0 +1,239 @@ +// 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 { RushConstants } from '../RushConstants'; +import { NullOperationRunner } from './NullOperationRunner'; +import { convertSlashesForWindows, ShellOperationRunner } from './ShellOperationRunner'; +import { OperationStatus } from './OperationStatus'; +import type { + ICreateOperationsContext, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import type { Operation } from './Operation'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { IOperationRunner } from './IOperationRunner'; + +export const PLUGIN_NAME: 'ShellOperationRunnerPlugin' = 'ShellOperationRunnerPlugin'; + +/** + * Core phased command plugin that provides the functionality for executing an operation via shell command. + */ +export class ShellOperationRunnerPlugin implements IPhasedCommandPlugin { + public apply(hooks: PhasedCommandHooks): void { + hooks.createOperations.tap( + PLUGIN_NAME, + function createShellOperations( + operations: Set, + context: ICreateOperationsContext + ): Set { + const { rushConfiguration, isInitial } = 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 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, + ignoredParameterValues, + rushConfiguration + }); + } + } + + return operations; + } + ); + } +} + +export function initializeShellOperationRunner(options: { + phase: IPhase; + project: RushConfigurationProject; + displayName: string; + rushConfiguration: RushConfiguration; + commandToRun: string | undefined; + commandForHash?: string; + customParameterValues: ReadonlyArray; + ignoredParameterValues: ReadonlyArray; +}): IOperationRunner { + const { phase, project, commandToRun: rawCommandToRun, displayName, ignoredParameterValues } = options; + + if (typeof rawCommandToRun !== '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 { commandForHash: rawCommandForHash, customParameterValues } = options; + + const commandToRun: string = formatCommand(rawCommandToRun, customParameterValues); + const commandForHash: string = rawCommandForHash + ? formatCommand(rawCommandForHash, customParameterValues) + : commandToRun; + + return new ShellOperationRunner({ + commandToRun, + commandForHash, + displayName, + phase, + rushProject: project, + ignoredParameterValues + }); + } else { + // Empty build script indicates a no-op, so use a no-op runner + return new NullOperationRunner({ + name: displayName, + result: OperationStatus.NoOp, + silent: phase.missingScriptBehavior === 'silent' + }); + } +} + +/** + * 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 + */ +export function getCustomParameterValuesByPhase(): (phase: IPhase) => ReadonlyArray { + const customParametersByPhase: Map = new Map(); + + function getCustomParameterValuesForPhase(phase: IPhase): ReadonlyArray { + 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); + } + + 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 { + parameterValues: filteredParameterValues, + ignoredParameterValues + }; + } + + return getCustomParameterValuesForOp; +} + +export function formatCommand(rawCommand: string, customParameterValues: ReadonlyArray): string { + if (!rawCommand) { + return ''; + } else { + const fullCommand: string = `${rawCommand} ${customParameterValues.join(' ')}`; + return process.platform === 'win32' ? convertSlashesForWindows(fullCommand) : fullCommand; + } +} + +export function getDisplayName(phase: IPhase, project: RushConfigurationProject): string { + if (phase.isSynthetic) { + // Because this is a synthetic phase, just use the project name because there aren't any other phases + return project.packageName; + } else { + const phaseNameWithoutPrefix: string = phase.name.slice(RushConstants.phaseNamePrefix.length); + return `${project.packageName} (${phaseNameWithoutPrefix})`; + } +} diff --git a/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts b/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts new file mode 100644 index 00000000000..3b75af31dd2 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.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 { ITerminal } from '@rushstack/terminal'; + +import type { Operation } from './Operation'; +import type { + ICreateOperationsContext, + IPhasedCommandPlugin, + PhasedCommandHooks +} from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; +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. + */ +export class ValidateOperationsPlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + } + + 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 (!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); + } + } + + 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 new file mode 100644 index 00000000000..4df5596df2c --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts @@ -0,0 +1,51 @@ +// 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 { 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'; + +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 { + 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 new file mode 100644 index 00000000000..fcd1a87a8d4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Operation } from '../Operation'; +import { type IOperationExecutionRecordContext, OperationExecutionRecord } from '../OperationExecutionRecord'; +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); + dependency.consumers.add(consumer); + consumer.status = OperationStatus.Waiting; +} + +function nullSort(a: OperationExecutionRecord, b: OperationExecutionRecord): number { + 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', + phase: mockPhase, + project: getOrCreateProject(name) + }), + {} as unknown as IOperationExecutionRecordContext + ); +} + +describe(AsyncOperationQueue.name, () => { + it('iterates operations in topological order', async () => { + const operations = [createRecord('a'), createRecord('b'), createRecord('c'), createRecord('d')]; + + addDependency(operations[0], operations[2]); + addDependency(operations[3], operations[1]); + addDependency(operations[1], operations[0]); + + const expectedOrder = [operations[2], operations[0], operations[1], operations[3]]; + const actualOrder = []; + const queue: AsyncOperationQueue = new AsyncOperationQueue(operations, nullSort); + for await (const operation of queue) { + actualOrder.push(operation); + operation.status = OperationStatus.Success; + queue.complete(operation); + } + + expect(actualOrder).toEqual(expectedOrder); + }); + + it('respects the sort predicate', async () => { + const operations = [createRecord('a'), createRecord('b'), createRecord('c'), createRecord('d')]; + + const expectedOrder = [operations[2], operations[0], operations[1], operations[3]]; + const actualOrder = []; + const customSort: IOperationSortFunction = ( + a: OperationExecutionRecord, + b: OperationExecutionRecord + ): number => { + return expectedOrder.indexOf(b) - expectedOrder.indexOf(a); + }; + + const queue: AsyncOperationQueue = new AsyncOperationQueue(operations, customSort); + for await (const operation of queue) { + actualOrder.push(operation); + operation.status = OperationStatus.Success; + queue.complete(operation); + } + + expect(actualOrder).toEqual(expectedOrder); + }); + + it('detects cycles', async () => { + const operations = [createRecord('a'), createRecord('b'), createRecord('c'), createRecord('d')]; + + addDependency(operations[0], operations[2]); + addDependency(operations[2], operations[3]); + addDependency(operations[3], operations[1]); + addDependency(operations[1], operations[0]); + + expect(() => { + new AsyncOperationQueue(operations, nullSort); + }).toThrowErrorMatchingSnapshot(); + }); + + it('handles concurrent iteration', async () => { + const operations = [ + createRecord('a'), + createRecord('b'), + createRecord('c'), + createRecord('d'), + createRecord('e') + ]; + + // Set up to allow (0,1) -> (2) -> (3,4) + addDependency(operations[2], operations[0]); + addDependency(operations[2], operations[1]); + addDependency(operations[3], operations[2]); + addDependency(operations[4], operations[2]); + + const expectedConcurrency = new Map([ + [operations[0], 2], + [operations[1], 2], + [operations[2], 1], + [operations[3], 2], + [operations[4], 2] + ]); + + const actualConcurrency: Map = new Map(); + const queue: AsyncOperationQueue = new AsyncOperationQueue(operations, nullSort); + let concurrency: number = 0; + + // Use 3 concurrent iterators to verify that it handles having more than the operation concurrency + await Promise.all( + Array.from({ length: 3 }, async () => { + for await (const operation of queue) { + ++concurrency; + await Promise.resolve(); + + actualConcurrency.set(operation, concurrency); + + await Promise.resolve(); + + --concurrency; + operation.status = OperationStatus.Success; + queue.complete(operation); + } + }) + ); + + for (const [operation, operationConcurrency] of expectedConcurrency) { + expect(actualConcurrency.get(operation)).toEqual(operationConcurrency); + } + }); + + it('handles an empty queue', async () => { + const operations: OperationExecutionRecord[] = []; + + const queue: AsyncOperationQueue = new AsyncOperationQueue(operations, nullSort); + const iterator: AsyncIterator = queue[Symbol.asyncIterator](); + const result: IteratorResult = await iterator.next(); + expect(result.done).toEqual(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 new file mode 100644 index 00000000000..20c1586e58f --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.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 { 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, + PhasedCommandHooks +} from '../../../pluginFramework/PhasedCommandHooks'; +import type { Operation } from '../Operation'; +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { + CommandLineConfiguration, + 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 'node:path'; +import type { ICommandLineJson } from '../../../api/CommandLineJson'; +import type { IInputsSnapshot } from '../../incremental/InputsSnapshot'; + +describe(BuildPlanPlugin.name, () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/workspaceRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/workspaceRepo/common/config/rush/command-line.json` + ); + let rushConfiguration!: RushConfiguration; + let commandLineConfiguration!: CommandLineConfiguration; + 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); + mockStreamWritable.reset(); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + }); + + function createMockRunner(operations: Set, context: ICreateOperationsContext): Set { + for (const operation of operations) { + const { associatedPhase, associatedProject } = operation; + + if (!operation.runner) { + const name: string = `${associatedProject.packageName} (${associatedPhase.name.slice( + RushConstants.phaseNamePrefix.length + )})`; + + operation.runner = new MockOperationRunner(name, undefined, undefined, false); + } + } + + return operations; + } + + async function testCreateOperationsAsync( + phaseSelection: Set, + projectSelection: Set, + changedProjects: Set + ): Promise> { + 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, + phaseSelection, + projectSelection, + projectsInUnknownState: changedProjects, + projectConfigurations: new Map() + }; + const operations: Set = await hooks.createOperations.promise( + new Set(), + context as ICreateOperationsContext + ); + + return operations; + } + + describe('build plan debugging', () => { + it('should generate a build plan', async () => { + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + 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( + buildCommand.phases, + new Set(rushConfiguration.projects), + new Set(rushConfiguration.projects) + ); + operations.forEach((operation) => { + operationMap.set( + operation, + new OperationExecutionRecord(operation, { + debugMode: false, + quietMode: true, + streamCollator, + inputsSnapshot: undefined + }) + ); + }); + + await hooks.beforeExecuteOperations.promise(operationMap, context as IExecuteOperationsContext); + + expect(stringBufferTerminalProvider.getOutput({ normalizeSpecialCharacters: false })).toMatchSnapshot(); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/MockOperationRunner.ts b/libraries/rush-lib/src/logic/operations/test/MockOperationRunner.ts new file mode 100644 index 00000000000..3e620634580 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/MockOperationRunner.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 { CollatedTerminal } from '@rushstack/stream-collator'; + +import { OperationStatus } from '../OperationStatus'; +import type { IOperationRunner, IOperationRunnerContext } from '../IOperationRunner'; + +export class MockOperationRunner implements IOperationRunner { + private readonly _action: ((terminal: CollatedTerminal) => Promise) | undefined; + public readonly name: string; + public readonly reportTiming: boolean = true; + public readonly silent: boolean = false; + public readonly cacheable: boolean = false; + public readonly warningsAreAllowed: boolean; + public readonly isNoOp?: boolean | undefined; + + public constructor( + name: string, + action?: (terminal: CollatedTerminal) => Promise, + warningsAreAllowed: boolean = false, + isNoOp: boolean | undefined = undefined + ) { + this.isNoOp = isNoOp; + this.name = name; + this._action = action; + this.warningsAreAllowed = warningsAreAllowed; + } + + public async executeAsync(context: IOperationRunnerContext): Promise { + let result: OperationStatus | undefined; + if (this._action) { + result = await this._action(context.collatedWriter.terminal); + } + return result || OperationStatus.Success; + } + + public getConfigHash(): string { + return 'mock'; + } +} diff --git a/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts new file mode 100644 index 00000000000..094db7caf5a --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts @@ -0,0 +1,457 @@ +// 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('../OperationStateFile'); + +jest.mock('@rushstack/terminal', () => { + const originalModule = jest.requireActual('@rushstack/terminal'); + return { + ...originalModule, + ConsoleTerminalProvider: { + ...originalModule.ConsoleTerminalProvider, + supportsColor: true + } + }; +}); + +import { Terminal, MockWritable, PrintUtilities } from '@rushstack/terminal'; +import { CollatedTerminal } from '@rushstack/stream-collator'; + +import type { IPhase } from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +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'; +import type { CobuildConfiguration } from '../../../api/CobuildConfiguration'; +import type { OperationStateFile } from '../OperationStateFile'; + +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 createExecutionManager( + executionManagerOptions: IOperationExecutionManagerOptions, + operationRunner: IOperationRunner +): OperationExecutionManager { + const operation: Operation = new Operation({ + runner: operationRunner, + logFilenameIdentifier: 'operation', + phase: mockPhase, + project: getOrCreateProject('project') + }); + + 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, + allowOversubscription: true, + 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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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 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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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 manager: OperationExecutionManager = new OperationExecutionManager( + new Set([firstOperation, secondOperation]), + { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destination: mockWritable + } + ); + + const abortController = new AbortController(); + abortController.abort(); + + const result = await manager.executeAsync(abortController); + expect(result.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); + }); + }); + + 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 manager: OperationExecutionManager = new OperationExecutionManager( + new Set([failingOperation, blockedOperation]), + { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destination: mockWritable + } + ); + + const abortController = new AbortController(); + const result = await manager.executeAsync(abortController); + 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, + allowOversubscription: true, + 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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _printOperationStatus(mockTerminal, result); + expect(result.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(() => { + executionManagerOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + 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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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 () => { + 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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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 createCobuildExecutionManager( + cobuildExecutionManagerOptions: IOperationExecutionManagerOptions, + operationRunnerFactory: (name: string) => IOperationRunner, + phase: IPhase, + project: RushConfigurationProject + ): OperationExecutionManager { + const operation: Operation = new Operation({ + runner: operationRunnerFactory('operation'), + logFilenameIdentifier: 'operation', + phase, + project + }); + + const operation2: Operation = new Operation({ + runner: operationRunnerFactory('operation2'), + logFilenameIdentifier: 'operation2', + phase, + project + }); + + return new OperationExecutionManager(new Set([operation, operation2]), { + afterExecuteOperationAsync: 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; + }, + ...cobuildExecutionManagerOptions + }); + } + it('logs cobuilt operations correctly with --timeline option', async () => { + executionManager = createCobuildExecutionManager( + executionManagerOptions, + (name) => + new MockOperationRunner( + `${name} (success)`, + async () => { + return OperationStatus.Success; + }, + /* warningsAreAllowed */ true + ), + { name: 'my-name' } as unknown as IPhase, + {} as unknown as RushConfigurationProject + ); + + const abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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 () => { + executionManager = createCobuildExecutionManager( + executionManagerOptions, + (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 abortController = new AbortController(); + const result: IExecutionResult = await executionManager.executeAsync(abortController); + _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(); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts new file mode 100644 index 00000000000..5663d143e39 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.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. + +jest.mock('../OperationStateFile'); +jest.mock('node:fs'); + +import { MockWritable, StringBufferTerminalProvider, Terminal, TerminalChunkKind } from '@rushstack/terminal'; +import type { IPhase } from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +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 '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', + project: { + projectFolder: '/path/to/project' + } as unknown as RushConfigurationProject, + phase: { + logFilenameIdentifier: 'identifier' + } as unknown as IPhase +}); + +const manager: OperationMetadataManager = new OperationMetadataManager({ + operation +}); + +describe(OperationMetadataManager.name, () => { + let mockTerminalProvider: StringBufferTerminalProvider; + beforeEach(() => { + mockTerminalProvider = new StringBufferTerminalProvider(false); + jest.spyOn(FileSystem, 'copyFileAsync').mockResolvedValue(); + }); + + function toJsonLines(data: object[]): string { + return data.map((item) => JSON.stringify(item)).join('\n'); + } + + it('should restore chunked stdout', async () => { + const data = [ + { + text: 'chunk1\n', + kind: TerminalChunkKind.Stdout + }, + { + text: 'chunk2\n', + kind: TerminalChunkKind.Stdout + } + ]; + + jest.spyOn(FileSystem, 'readFileAsync').mockResolvedValue(toJsonLines(data)); + + await manager.tryRestoreAsync({ + terminal: mockTerminal, + terminalProvider: mockTerminalProvider, + errorLogPath: '/path/to/errorLog' + }); + + expect(mockTerminalProvider.getOutput()).toMatchSnapshot(); + expect(mockTerminalProvider.getWarningOutput()).toBeFalsy(); + }); + + it('should restore chunked stderr', async () => { + const data = [ + { + text: 'chunk1\n', + kind: TerminalChunkKind.Stderr + }, + { + text: 'chunk2\n', + kind: TerminalChunkKind.Stderr + } + ]; + + jest.spyOn(FileSystem, 'readFileAsync').mockResolvedValue(toJsonLines(data)); + + await manager.tryRestoreAsync({ + terminal: mockTerminal, + terminalProvider: mockTerminalProvider, + errorLogPath: '/path/to/errorLog' + }); + + expect(mockTerminalProvider.getOutput()).toBeFalsy(); + expect(mockTerminalProvider.getErrorOutput()).toMatchSnapshot(); + }); + + it('should restore mixed chunked output', async () => { + const data = [ + { + text: 'logged to stdout\n', + kind: TerminalChunkKind.Stdout + }, + { + text: 'logged to stderr\n', + kind: TerminalChunkKind.Stderr + } + ]; + + jest.spyOn(FileSystem, 'readFileAsync').mockResolvedValue(toJsonLines(data)); + + await manager.tryRestoreAsync({ + terminal: mockTerminal, + 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(); + }); + + it("should fallback to the log file when chunked output isn't available", async () => { + // Normalize newlines to make the error message consistent across platforms + const normalizedRawLogFile: string = `stdout log file`; + jest + .spyOn(FileSystem, 'readFileAsync') + .mockRejectedValue({ code: 'ENOENT', syscall: 'open', path: '/path/to/file', errno: 1 }); + + const mockClose = jest.fn(); + const mockReadStream: fs.ReadStream = Readable.from([normalizedRawLogFile]) as fs.ReadStream; + mockReadStream.close = mockClose; + jest.spyOn(fs, 'createReadStream').mockReturnValue(mockReadStream); + + await manager.tryRestoreAsync({ + terminal: mockTerminal, + terminalProvider: mockTerminalProvider, + errorLogPath: '/path/to/errorLog' + }); + + expect(mockTerminalProvider.getOutput()).toBeFalsy(); + expect(mockTerminalProvider.getErrorOutput()).toBeFalsy(); + expect(mockClose).toHaveBeenCalledTimes(1); + expect(mockWritable.chunks).toMatchSnapshot(); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts new file mode 100644 index 00000000000..ef16651af85 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts @@ -0,0 +1,330 @@ +// 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 { RushConfiguration } from '../../../api/RushConfiguration'; +import { CommandLineConfiguration, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; +import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; +import type { Operation } from '../Operation'; +import type { ICommandLineJson } from '../../../api/CommandLineJson'; +import { RushConstants } from '../../RushConstants'; +import { MockOperationRunner } from './MockOperationRunner'; +import { + type ICreateOperationsContext, + PhasedCommandHooks +} from '../../../pluginFramework/PhasedCommandHooks'; + +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(', ')}]`; +} + +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 expectOperationsToMatchSnapshot(operations: Set, name: string): void { + const serializedOperations: string[] = Array.from(operations) + .sort(compareOperation) + .map(serializeOperation); + expect(serializedOperations).toMatchSnapshot(name); +} + +describe(PhasedOperationPlugin.name, () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/workspaceRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/workspaceRepo/common/config/rush/command-line.json` + ); + + function createMockRunner(operations: Set, context: ICreateOperationsContext): Set { + for (const operation of operations) { + const { associatedPhase, associatedProject } = operation; + + if (!operation.runner) { + const name: string = `${associatedProject.packageName} (${associatedPhase.name.slice( + RushConstants.phaseNamePrefix.length + )})`; + + operation.runner = new MockOperationRunner(name); + } + } + + return operations; + } + + interface ITestCreateOperationsContext { + phaseOriginal?: ICreateOperationsContext['phaseOriginal']; + phaseSelection: ICreateOperationsContext['phaseSelection']; + projectSelection: ICreateOperationsContext['projectSelection']; + projectsInUnknownState: ICreateOperationsContext['projectsInUnknownState']; + includePhaseDeps?: ICreateOperationsContext['includePhaseDeps']; + } + + async function testCreateOperationsAsync(options: ITestCreateOperationsContext): Promise> { + const { + phaseSelection, + projectSelection, + projectsInUnknownState, + phaseOriginal = phaseSelection, + includePhaseDeps = 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, + | 'includePhaseDeps' + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + > = { + includePhaseDeps, + phaseOriginal, + phaseSelection, + projectSelection, + projectsInUnknownState, + projectConfigurations: new Map() + }; + const operations: Set = await hooks.createOperations.promise( + new Set(), + context as ICreateOperationsContext + ); + + 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({ + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects) + }); + + // All projects + expectOperationsToMatchSnapshot(operations, 'full'); + }); + + it('handles filtered projects', async () => { + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set([rushConfiguration.getProjectByName('g')!]), + projectsInUnknownState: new Set([rushConfiguration.getProjectByName('g')!]) + }); + + // Single project + expectOperationsToMatchSnapshot(operations, 'single'); + + operations = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]), + projectsInUnknownState: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]) + }); + + // Filtered projects + expectOperationsToMatchSnapshot(operations, 'filtered'); + }); + + it('handles some changed projects', async () => { + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set([rushConfiguration.getProjectByName('g')!]) + }); + + // Single project + expectOperationsToMatchSnapshot(operations, 'single'); + + operations = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]) + }); + + // Filtered projects + expectOperationsToMatchSnapshot(operations, 'multiple'); + }); + + it('handles some changed projects within filtered projects', async () => { + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + const operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]), + projectsInUnknownState: new Set([ + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]) + }); + + // Single project + expectOperationsToMatchSnapshot(operations, 'multiple'); + }); + + it('handles different phaseOriginal vs phaseSelection without --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: false, + phaseSelection: new Set([ + commandLineConfiguration.phases.get('_phase:no-deps')!, + commandLineConfiguration.phases.get('_phase:upstream-self')! + ]), + phaseOriginal: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set([rushConfiguration.getProjectByName('a')!]), + projectsInUnknownState: new Set([rushConfiguration.getProjectByName('a')!]) + }); + + expectOperationsToMatchSnapshot(operations, 'single-project'); + }); + + it('handles different phaseOriginal vs phaseSelection with --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: true, + phaseSelection: new Set([ + commandLineConfiguration.phases.get('_phase:no-deps')!, + commandLineConfiguration.phases.get('_phase:upstream-self')! + ]), + phaseOriginal: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set([rushConfiguration.getProjectByName('a')!]), + projectsInUnknownState: new Set([rushConfiguration.getProjectByName('a')!]) + }); + + expectOperationsToMatchSnapshot(operations, 'single-project'); + }); + + it('handles different phaseOriginal vs phaseSelection cross-project with --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: true, + phaseSelection: new Set([ + commandLineConfiguration.phases.get('_phase:no-deps')!, + commandLineConfiguration.phases.get('_phase:upstream-1')! + ]), + phaseOriginal: new Set([commandLineConfiguration.phases.get('_phase:upstream-1')!]), + projectSelection: new Set([ + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('h')! + ]), + projectsInUnknownState: new Set([rushConfiguration.getProjectByName('h')!]) + }); + + expectOperationsToMatchSnapshot(operations, 'multiple-project'); + }); + + it('handles filtered phases', async () => { + // Single phase with a missing dependency + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects) + }); + expectOperationsToMatchSnapshot(operations, 'single-phase'); + + // Two phases with a missing link + 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')! + ]), + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: 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({ + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-2')!]), + projectSelection: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]), + projectsInUnknownState: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]) + }); + expectOperationsToMatchSnapshot(operations, 'single-phase'); + + // Phases with missing links + 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')! + ]), + projectSelection: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]), + projectsInUnknownState: new Set([ + rushConfiguration.getProjectByName('f')!, + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]) + }); + expectOperationsToMatchSnapshot(operations, 'missing-links'); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunner.test.ts b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunner.test.ts new file mode 100644 index 00000000000..686f82c83f7 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunner.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. + +import { convertSlashesForWindows } from '../ShellOperationRunner'; + +describe(convertSlashesForWindows.name, () => { + it('converted inputs', () => { + expect(convertSlashesForWindows('./node_modules/.bin/tslint -c config/tslint.json')).toEqual( + '.\\node_modules\\.bin\\tslint -c config/tslint.json' + ); + expect(convertSlashesForWindows('/blah/bleep&&/bloop')).toEqual('\\blah\\bleep&&/bloop'); + expect(convertSlashesForWindows('/blah/bleep')).toEqual('\\blah\\bleep'); + expect(convertSlashesForWindows('/blah/bleep --path a/b')).toEqual('\\blah\\bleep --path a/b'); + expect(convertSlashesForWindows('/blah/bleep>output.log')).toEqual('\\blah\\bleep>output.log'); + expect(convertSlashesForWindows('/blah/bleep { + expect(convertSlashesForWindows('/blah\\bleep && /bloop')).toEqual('/blah\\bleep && /bloop'); + expect(convertSlashesForWindows('cmd.exe /c blah')).toEqual('cmd.exe /c blah'); + expect(convertSlashesForWindows('"/blah/bleep"')).toEqual('"/blah/bleep"'); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts new file mode 100644 index 00000000000..818144e85df --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts @@ -0,0 +1,278 @@ +// 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 { CommandLineAction, CommandLineParser, type CommandLineParameter } from '@rushstack/ts-command-line'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +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'; +import { ShellOperationRunnerPlugin } from '../ShellOperationRunnerPlugin'; +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; + commandToRun: string; +} + +function serializeOperation(operation: Operation): ISerializedOperation { + return { + 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`); + 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, + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + > = { + phaseOriginal: echoCommand.phases, + phaseSelection: echoCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects), + projectConfigurations: new Map() + }; + + 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.createOperations.promise( + new Set(), + fakeCreateOperationsContext as ICreateOperationsContext + ); + // All projects + expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + }); + + it('shellCommand priority should be higher than script name', async () => { + const rushJsonFile: string = path.resolve( + __dirname, + `../../test/customShellCommandinBulkOverrideScriptsRepo/rush.json` + ); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/customShellCommandinBulkOverrideScriptsRepo/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, + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + > = { + phaseOriginal: echoCommand.phases, + phaseSelection: echoCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: new Set(rushConfiguration.projects), + projectConfigurations: new Map() + }; + + 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.createOperations.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, + | 'phaseOriginal' + | 'phaseSelection' + | 'projectSelection' + | 'projectsInUnknownState' + | 'projectConfigurations' + | 'rushConfiguration' + | 'customParameters' + > = { + phaseOriginal: buildCommand.phases, + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectsInUnknownState: 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.createOperations.promise( + new Set(), + fakeCreateOperationsContext 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 new file mode 100644 index 00000000000..37eb17f2a8c --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/AsyncOperationQueue.test.ts.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AsyncOperationQueue detects cycles 1`] = ` +"A cyclic dependency was encountered: + a + -> c + -> d + -> b + -> a +Consider using the decoupledLocalDependencies option in rush.json." +`; 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 new file mode 100644 index 00000000000..b4a391ee2af --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/BuildPlanPlugin.test.ts.snap @@ -0,0 +1,325 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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) +-------------------------------------------------- +################################################## +" +`; 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 new file mode 100644 index 00000000000..deb3e8fe623 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationExecutionManager.test.ts.snap @@ -0,0 +1,836 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OperationExecutionManager 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[`OperationExecutionManager 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[`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.10 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.10 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.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 new file mode 100644 index 00000000000..5647df50e1f --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationMetadataManager.test.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OperationMetadataManager should fallback to the log file when chunked output isn't available 1`] = ` +Array [ + Object { + "kind": "O", + "text": "stdout log file", + }, +] +`; + +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 mixed chunked output 1`] = `"logged to stdout[n]"`; + +exports[`OperationMetadataManager should restore mixed chunked output 2`] = `"logged to stderr[n]"`; 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 new file mode 100644 index 00000000000..35f3b43a828 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/PhasedOperationPlugin.test.ts.snap @@ -0,0 +1,547 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PhasedOperationPlugin handles a full build: full 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)]", + "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 different phaseOriginal vs phaseSelection cross-project with --include-phase-deps: multiple-project 1`] = ` +Array [ + "a (no-deps) (enabled) -> []", + "h (upstream-1) (enabled) -> [a (no-deps)]", + "a (upstream-1) (disabled) -> []", + "h (no-deps) (disabled) -> []", +] +`; + +exports[`PhasedOperationPlugin handles different phaseOriginal vs phaseSelection with --include-phase-deps: single-project 1`] = ` +Array [ + "a (no-deps) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", +] +`; + +exports[`PhasedOperationPlugin handles different phaseOriginal vs phaseSelection without --include-phase-deps: single-project 1`] = ` +Array [ + "a (no-deps) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", +] +`; + +exports[`PhasedOperationPlugin handles filtered phases on filtered projects: missing-links 1`] = ` +Array [ + "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 on filtered projects: single-phase 1`] = ` +Array [ + "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: single-phase 1`] = ` +Array [ + "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: two-phases 1`] = ` +Array [ + "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: 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)]", + "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: single 1`] = ` +Array [ + "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 within filtered projects: multiple 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)]", + "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 (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)]", + "f (no-deps) (disabled) -> []", + "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 some changed projects: multiple 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)]", + "b (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), b (upstream-3)]", + "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 (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 (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 (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 (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)]", + "b (no-deps) (disabled) -> []", + "d (no-deps) (disabled) -> []", + "d (upstream-1) (disabled) -> [b (no-deps)]", + "d (upstream-1-self) (disabled) -> [d (upstream-1)]", + "e (no-deps) (disabled) -> []", + "g (no-deps) (disabled) -> []", + "h (no-deps) (disabled) -> []", + "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)]", +] +`; + +exports[`PhasedOperationPlugin handles some changed projects: single 1`] = ` +Array [ + "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 (complex) (disabled) -> [a (upstream-3)]", + "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-3) (disabled) -> []", + "a (upstream-self) (disabled) -> [a (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)]", + "c (complex) (disabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (disabled) -> []", + "c (upstream-1) (disabled) -> [b (no-deps)]", + "c (upstream-1-self) (disabled) -> [c (upstream-1)]", + "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)]", + "c (upstream-3) (disabled) -> [b (upstream-2)]", + "c (upstream-self) (disabled) -> [b (upstream-self), c (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)]", + "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 new file mode 100644 index 00000000000..346ce7e87b4 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/ShellOperationRunnerPlugin.test.ts.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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 [ + Object { + "commandToRun": "echo custom shellCommand ", + "name": "a", + }, + Object { + "commandToRun": "echo custom shellCommand ", + "name": "b", + }, +] +`; + +exports[`ShellOperationRunnerPlugin shellCommand priority should be higher than script name 1`] = ` +Array [ + Object { + "commandToRun": "echo custom shellCommand ", + "name": "a", + }, + Object { + "commandToRun": "echo custom shellCommand ", + "name": "b", + }, +] +`; diff --git a/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts b/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts new file mode 100644 index 00000000000..0e8620f318c --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts @@ -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 type { LogBase } from '@pnpm/logger'; + +import type { IPackageJson } from '@rushstack/node-core-library'; + +import type { IPnpmShrinkwrapYaml } from './PnpmShrinkwrapFile'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; + +/** + * The `settings` parameter passed to {@link IPnpmfileShim.hooks.readPackage} and + * {@link IPnpmfileShim.hooks.afterAllResolved}. + */ +export interface IPnpmfileShimSettings { + semverPath: string; + allPreferredVersions: { [dependencyName: string]: string }; + allowedAlternativeVersions: { [dependencyName: string]: ReadonlyArray }; + /** + * The versions of all packages that are part of the workspace. + */ + workspaceVersions: Record; + userPnpmfilePath?: string; +} + +export interface IWorkspaceProjectInfo + extends Pick { + packageVersion: RushConfigurationProject['packageJson']['version']; + injectedDependencies: Array; +} + +/** + * The `settings` parameter passed to {@link IPnpmfileShim.hooks.readPackage} and + * {@link IPnpmfileShim.hooks.afterAllResolved}. + */ +export interface ISubspacePnpmfileShimSettings { + semverPath: string; + workspaceProjects: Record; + subspaceProjects: Record; + userPnpmfilePath?: string; +} + +/** + * The `context` parameter passed to {@link IPnpmfile.hooks.readPackage}, as defined by the + * pnpmfile API contract. + */ +export interface IPnpmfileContext { + log: (message: string) => void; + pnpmfileShimSettings?: IPnpmfileShimSettings; + subspacePnpmfileShimSettings?: ISubspacePnpmfileShimSettings; +} + +/** + * The `log` parameter passed to {@link IPnpmfile.hooks.filterLog}. + */ +export type IPnpmLog = LogBase & { + [key: string]: unknown; +}; + +/** + * The 'hooks' property of the pnpmfile + */ +export interface IPnpmfileHooks { + afterAllResolved?: (lockfile: IPnpmShrinkwrapYaml, context: IPnpmfileContext) => IPnpmShrinkwrapYaml; + readPackage?: (pkg: IPackageJson, context: IPnpmfileContext) => IPackageJson; + /** + * @remarks + * This function is not supported by PNPM versions before 6.17.0. + */ + filterLog?: (log: IPnpmLog) => boolean; +} + +/** + * The pnpmfile, as defined by the pnpmfile API contract. + */ +export interface IPnpmfile { + hooks?: IPnpmfileHooks; +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts new file mode 100644 index 00000000000..15facc8eeef --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -0,0 +1,463 @@ +// 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 uriEncode from 'strict-uri-encode'; +import pnpmLinkBins from '@pnpm/link-bins'; +import * as semver from 'semver'; + +import { + AlreadyReportedError, + FileSystem, + FileConstants, + InternalError, + Path +} from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +import { BaseLinkManager } from '../base/BaseLinkManager'; +import { BasePackage } from '../base/BasePackage'; +import { RushConstants } from '../RushConstants'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { + PnpmShrinkwrapFile, + type IPnpmShrinkwrapDependencyYaml, + type IPnpmVersionSpecifier, + normalizePnpmVersionSpecifier +} from './PnpmShrinkwrapFile'; + +// special flag for debugging, will print extra diagnostic information, +// but comes with performance cost +const DEBUG: boolean = false; + +export class PnpmLinkManager extends BaseLinkManager { + private readonly _pnpmVersion: semver.SemVer = new semver.SemVer( + this._rushConfiguration.packageManagerToolVersion + ); + + /** + * @override + */ + public async createSymlinksForProjectsAsync(force: boolean): Promise { + const useWorkspaces: boolean = + this._rushConfiguration.pnpmOptions && this._rushConfiguration.pnpmOptions.useWorkspaces; + if (useWorkspaces) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'Linking is not supported when using workspaces. Run "rush install" or "rush update" ' + + 'to restore project node_modules folders.' + ) + ); + throw new AlreadyReportedError(); + } + + await super.createSymlinksForProjectsAsync(force); + } + + protected async _linkProjectsAsync(): Promise { + if (this._rushConfiguration.projects.length > 0) { + // 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() + ); + + if (!pnpmShrinkwrapFile) { + throw new InternalError( + `Cannot load shrinkwrap at "${this._rushConfiguration.defaultSubspace.getTempShrinkwrapFilename()}"` + ); + } + + for (const rushProject of this._rushConfiguration.projects) { + await this._linkProjectAsync(rushProject, pnpmShrinkwrapFile); + } + } else { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + `\nWarning: Nothing to do. Please edit ${RushConstants.rushJsonFilename} and add at least one project` + + ' to the "projects" section.\n' + ) + ); + } + } + + /** + * This is called once for each local project from Rush.json. + * @param project The local project that we will create symlinks for + * @param rushLinkJson The common/temp/rush-link.json output file + */ + private async _linkProjectAsync( + project: RushConfigurationProject, + pnpmShrinkwrapFile: PnpmShrinkwrapFile + ): Promise { + // eslint-disable-next-line no-console + console.log(`\nLINKING: ${project.packageName}`); + + // first, read the temp package.json information + // Example: "project1" + const unscopedTempProjectName: string = this._rushConfiguration.packageNameParser.getUnscopedName( + project.tempProjectName + ); + + // Example: "C:\MyRepo\common\temp\projects\project1 + const extractedFolder: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.rushTempProjectsFolderName, + unscopedTempProjectName + ); + + // Example: "C:\MyRepo\common\temp\projects\project1\package.json" + const packageJsonFilename: string = path.join(extractedFolder, FileConstants.PackageJson); + + // Example: "C:\MyRepo\common\temp\node_modules\@rush-temp\project1" + const installFolderName: string = path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + RushConstants.rushTempNpmScope, + unscopedTempProjectName + ); + + const commonPackage: BasePackage = BasePackage.createVirtualTempPackage( + packageJsonFilename, + installFolderName + ); + + const localPackage: BasePackage = BasePackage.createLinkedPackage( + project.packageName, + commonPackage.version, + project.projectFolder + ); + + // now that we have the temp package.json, we can go ahead and link up all the direct dependencies + + // first, start with the rush dependencies, we just need to link to the project folder + for (const dependencyName of Object.keys(commonPackage.packageJson!.rushDependencies || {})) { + const matchedRushPackage: RushConfigurationProject | undefined = + this._rushConfiguration.getProjectByName(dependencyName); + + if (matchedRushPackage) { + // We found a suitable match, so place a new local package that + // symlinks to the Rush project + const matchedVersion: string = matchedRushPackage.packageJsonEditor.version; + + // e.g. "C:\my-repo\project-a\node_modules\project-b" if project-b is a rush dependency of project-a + const newLocalFolderPath: string = path.join(localPackage.folderPath, 'node_modules', dependencyName); + + const newLocalPackage: BasePackage = BasePackage.createLinkedPackage( + dependencyName, + matchedVersion, + newLocalFolderPath + ); + + newLocalPackage.symlinkTargetFolderPath = matchedRushPackage.projectFolder; + localPackage.children.push(newLocalPackage); + } else { + throw new InternalError( + `Cannot find dependency "${dependencyName}" for "${project.packageName}" in the Rush configuration` + ); + } + } + + // Iterate through all the regular dependencies + + // With npm, it's possible for two different projects to have dependencies on + // the same version of the same library, but end up with different implementations + // of that library, if the library is installed twice and with different secondary + // dependencies.The NpmLinkManager recursively links dependency folders to try to + // honor this. Since PNPM always uses the same physical folder to represent a given + // version of a library, we only need to link directly to the folder that PNPM has chosen, + // and it will have a consistent set of secondary dependencies. + + // each of these dependencies should be linked in a special folder that pnpm + // creates for the installed version of each .TGZ package, all we need to do + // is re-use that symlink in order to get linked to whatever PNPM thought was + // appropriate. This folder is usually something like: + // C:\{uri-encoded-path-to-tgz}\node_modules\{package-name} + + // e.g.: + // file:projects/bentleyjs-core.tgz + // file:projects/build-tools.tgz_dc21d88642e18a947127a751e00b020a + // file:projects/imodel-from-geojson.tgz_request@2.88.0 + const tempProjectDependencyKey: string | undefined = pnpmShrinkwrapFile.getTempProjectDependencyKey( + project.tempProjectName + ); + + if (!tempProjectDependencyKey) { + throw new Error(`Cannot get dependency key for temp project: ${project.tempProjectName}`); + } + // e.g.: file:projects/project-name.tgz + const tarballEntry: string | undefined = pnpmShrinkwrapFile.getTarballPath(tempProjectDependencyKey); + + if (!tarballEntry) { + throw new InternalError(`Cannot find tarball path for "${project.tempProjectName}" in shrinkwrap.`); + } + + // e.g.: projects\api-documenter.tgz + const relativePathToTgzFile: string | undefined = tarballEntry.slice(`file:`.length); + + // e.g.: C:\wbt\common\temp\projects\api-documenter.tgz + const absolutePathToTgzFile: string = path.resolve( + this._rushConfiguration.commonTempFolder, + relativePathToTgzFile + ); + + // The folder name in `.local` is constructed as: + // UriEncode(absolutePathToTgzFile) + _suffix + // + // Note that _suffix is not encoded. The tarball attribute of the package 'file:projects/project-name.tgz_suffix' + // holds the tarball path 'file:projects/project-name.tgz', which can be used for the constructing the folder name. + // + // '_suffix' is extracted by stripping the tarball path from top level dependency value. + // tarball path = 'file:projects/project-name.tgz' + // top level dependency = 'file:projects/project-name.tgz_suffix' + + // e.g.: + // '' [empty string] + // _@types+node@14.18.36 + // _jsdom@11.12.0 + // _2a665c89609864b4e75bc5365d7f8f56 + // (@types/node@14.18.36) + const folderNameSuffix: string = + tarballEntry && tarballEntry.length < tempProjectDependencyKey.length + ? tempProjectDependencyKey.slice(tarballEntry.length) + : ''; + + // e.g.: C:\wbt\common\temp\node_modules\.local\C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz\node_modules + const pathToLocalInstallation: string = await this._getPathToLocalInstallationAsync( + tarballEntry, + absolutePathToTgzFile, + folderNameSuffix, + tempProjectDependencyKey + ); + + const parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml | undefined = + pnpmShrinkwrapFile.getShrinkwrapEntryFromTempProjectDependencyKey(tempProjectDependencyKey); + if (!parentShrinkwrapEntry) { + throw new InternalError( + `Cannot find shrinkwrap entry using dependency key for temp project: ${project.tempProjectName}` + ); + } + + for (const dependencyName of Object.keys(commonPackage.packageJson!.dependencies || {})) { + const newLocalPackage: BasePackage = this._createLocalPackageForDependency( + project, + parentShrinkwrapEntry, + localPackage, + pathToLocalInstallation, + dependencyName + )!; + localPackage.addChild(newLocalPackage); + } + + // TODO: Rush does not currently handle optional dependencies of projects. This should be uncommented when + // support is added + // for (const dependencyName of Object.keys(commonPackage.packageJson!.optionalDependencies || {})) { + // const newLocalPackage: BasePackage | undefined = this._createLocalPackageForDependency( + // project, + // parentShrinkwrapEntry, + // localPackage, + // pathToLocalInstallation, + // dependencyName, + // true); // isOptional + // if (newLocalPackage) { + // localPackage.addChild(newLocalPackage); + // } + // } + + if (DEBUG) { + localPackage.printTree(); + } + + await pnpmShrinkwrapFile.getProjectShrinkwrap(project)!.updateProjectShrinkwrapAsync(); + + await PnpmLinkManager._createSymlinksForTopLevelProjectAsync(localPackage); + + // Also symlink the ".bin" folder + const projectFolder: string = path.join(localPackage.folderPath, 'node_modules'); + const projectBinFolder: string = path.join(localPackage.folderPath, 'node_modules', '.bin'); + + await pnpmLinkBins(projectFolder, projectBinFolder, { + warn: (msg: string) => { + // eslint-disable-next-line no-console + console.warn(Colorize.yellow(msg)); + } + }); + } + + private async _getPathToLocalInstallationAsync( + tarballEntry: string, + absolutePathToTgzFile: string, + folderSuffix: string, + tempProjectDependencyKey: string + ): Promise { + if (this._pnpmVersion.major === 6) { + // PNPM 6 changed formatting to replace all ':' and '/' chars with '+'. Additionally, folder names > 120 + // are trimmed and hashed. NOTE: PNPM internally uses fs.realpath.native, which will cause additional + // issues in environments that do not support long paths. + // See https://github.com/pnpm/pnpm/releases/tag/v6.0.0 + // e.g.: + // C++dev+imodeljs+imodeljs+common+temp+projects+presentation-integration-tests.tgz_jsdom@11.12.0 + // C++dev+imodeljs+imodeljs+common+temp+projects+presentation-integrat_089eb799caf0f998ab34e4e1e9254956 + const specialCharRegex: RegExp = /\/|:/g; + const escapedLocalPath: string = Path.convertToSlashes(absolutePathToTgzFile).replace( + specialCharRegex, + '+' + ); + let folderName: string = `local+${escapedLocalPath}${folderSuffix}`; + if (folderName.length > 120) { + folderName = `${folderName.substring(0, 50)}_${crypto + .createHash('md5') + .update(folderName) + .digest('hex')}`; + } + + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else if (this._pnpmVersion.major >= 10) { + const { depPathToFilename } = await import('@pnpm/dependency-path'); + + // 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 = depPathToFilename( + tempProjectDependencyKey, + process.platform === 'win32' ? 60 : 120 + ); + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else if (this._pnpmVersion.major >= 9) { + const { depPathToFilename } = await import('@pnpm/dependency-path-lockfile-pre-v10'); + + // project@file+projects+presentation-integration-tests.tgz_jsdom@11.12.0 + // 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); + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else if (this._pnpmVersion.major >= 8) { + const { depPathToFilename } = await import('@pnpm/dependency-path-lockfile-pre-v9'); + // 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}`); + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else if (this._pnpmVersion.major >= 7) { + const { depPathToFilename } = await import('dependency-path'); + // PNPM 7 changed the local path format again and the hashing algorithm + // See https://github.com/pnpm/pnpm/releases/tag/v7.0.0 + // e.g.: + // file+projects+presentation-integration-tests.tgz_jsdom@11.12.0 + const escapedLocalPath: string = depPathToFilename(tarballEntry); + const folderName: string = `${escapedLocalPath}${folderSuffix}`; + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else { + // e.g.: + // C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz + // C%3A%2Fdev%2Fimodeljs%2Fimodeljs%2Fcommon%2Ftemp%2Fprojects%2Fpresentation-integration-tests.tgz_jsdom@11.12.0 + // C%3A%2Fdev%2Fimodeljs%2Fimodeljs%2Fcommon%2Ftemp%2Fprojects%2Fbuild-tools.tgz_2a665c89609864b4e75bc5365d7f8f56 + const folderNameInLocalInstallationRoot: string = + uriEncode(Path.convertToSlashes(absolutePathToTgzFile)) + folderSuffix; + + // See https://github.com/pnpm/pnpm/releases/tag/v4.0.0 + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + 'local', + folderNameInLocalInstallationRoot, + RushConstants.nodeModulesFolderName + ); + } + } + private _createLocalPackageForDependency( + project: RushConfigurationProject, + parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, + localPackage: BasePackage, + pathToLocalInstallation: string, + dependencyName: string, + isOptional: boolean = false + ): BasePackage | undefined { + // the dependency we are looking for should have already created a symlink here + + // FYI dependencyName might contain an NPM scope, here it gets converted into a filesystem folder name + // e.g. if the dependency is supi: + // "C:\wbt\common\temp\node_modules\.local\C%3A%2Fwbt%2Fcommon%2Ftemp%2Fprojects%2Fapi-documenter.tgz\node_modules\supi" + const dependencyLocalInstallationSymlink: string = path.join(pathToLocalInstallation, dependencyName); + + if (!FileSystem.exists(dependencyLocalInstallationSymlink)) { + // if this occurs, it is a bug in Rush algorithm or unexpected PNPM behavior + throw new InternalError( + `Cannot find installed dependency "${dependencyName}" in "${pathToLocalInstallation}"` + ); + } + + if (!FileSystem.getLinkStatistics(dependencyLocalInstallationSymlink).isSymbolicLink()) { + // if this occurs, it is a bug in Rush algorithm or unexpected PNPM behavior + throw new InternalError( + `Dependency "${dependencyName}" is not a symlink in "${pathToLocalInstallation}` + ); + } + + // read the version number from the shrinkwrap entry and return if no version is specified + // and the dependency is optional + const versionSpecifier: IPnpmVersionSpecifier | undefined = isOptional + ? (parentShrinkwrapEntry.optionalDependencies || {})[dependencyName] + : (parentShrinkwrapEntry.dependencies || {})[dependencyName]; + if (!versionSpecifier) { + if (!isOptional) { + throw new InternalError( + `Cannot find shrinkwrap entry dependency "${dependencyName}" for temp project: ` + + `${project.tempProjectName}` + ); + } + return; + } + + const newLocalFolderPath: string = path.join(localPackage.folderPath, 'node_modules', dependencyName); + const version: string = normalizePnpmVersionSpecifier(versionSpecifier); + const newLocalPackage: BasePackage = BasePackage.createLinkedPackage( + dependencyName, + version, + newLocalFolderPath + ); + + // The dependencyLocalInstallationSymlink is just a symlink to another folder. To reduce the number of filesystem + // reads that are needed, we will link to where that symlink pointed, rather than linking to a link. + newLocalPackage.symlinkTargetFolderPath = FileSystem.getRealPath(dependencyLocalInstallationSymlink); + return newLocalPackage; + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts new file mode 100644 index 00000000000..555f02e7dd0 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts @@ -0,0 +1,523 @@ +// 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 { NonProjectConfigurationFile } from '@rushstack/heft-config-file'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { + type IPackageManagerOptionsJsonBase, + PackageManagerOptionsConfigurationBase +} from '../base/BasePackageManagerOptionsConfiguration'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; +import schemaJson from '../../schemas/pnpm-config.schema.json'; + +/** + * This represents the available PNPM store options + * @public + */ +export type PnpmStoreLocation = 'local' | 'global'; + +/** + * @deprecated Use {@link PnpmStoreLocation} instead + * @public + */ +export type PnpmStoreOptions = PnpmStoreLocation; + +/** + * Possible values for the `resolutionMode` setting in Rush's pnpm-config.json file. + * @remarks + * These modes correspond to PNPM's `resolution-mode` values, which are documented here: + * {@link https://pnpm.io/npmrc#resolution-mode} + * + * @public + */ +export type PnpmResolutionMode = 'highest' | 'time-based' | 'lowest-direct'; + +/** + * Possible values for the `pnpmLockfilePolicies` setting in Rush's pnpm-config.json file. + * @public + */ +export interface IPnpmLockfilePolicies { + /** + * Forbid sha1 hashes in `pnpm-lock.yaml` + */ + disallowInsecureSha1?: { + enabled: boolean; + exemptPackageVersions: Record; + }; +} + +/** + * @public + */ +export interface IPnpmPeerDependencyRules { + ignoreMissing?: string[]; + allowAny?: string[]; + allowedVersions?: Record; +} + +/** + * @public + */ +export interface IPnpmPeerDependenciesMeta { + [packageName: string]: { + optional?: boolean; + }; +} + +/** + * @public + */ +export interface IPnpmPackageExtension { + dependencies?: Record; + optionalDependencies?: Record; + peerDependencies?: Record; + peerDependenciesMeta?: IPnpmPeerDependenciesMeta; +} + +/** + * Part of IRushConfigurationJson. + * @internal + */ +export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { + $schema?: string; + /** + * {@inheritDoc PnpmOptionsConfiguration.pnpmStore} + */ + pnpmStore?: PnpmStoreLocation; + /** + * {@inheritDoc PnpmOptionsConfiguration.strictPeerDependencies} + */ + strictPeerDependencies?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.preventManualShrinkwrapChanges} + */ + preventManualShrinkwrapChanges?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.useWorkspaces} + */ + useWorkspaces?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalOverrides} + */ + globalOverrides?: Record; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalPeerDependencyRules} + */ + globalPeerDependencyRules?: IPnpmPeerDependencyRules; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalPackageExtensions} + */ + globalPackageExtensions?: Record; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalNeverBuiltDependencies} + */ + globalNeverBuiltDependencies?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalIgnoredOptionalDependencies} + */ + globalIgnoredOptionalDependencies?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalAllowedDeprecatedVersions} + */ + globalAllowedDeprecatedVersions?: Record; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalPatchedDependencies} + */ + globalPatchedDependencies?: Record; + /** + * {@inheritDoc PnpmOptionsConfiguration.unsupportedPackageJsonSettings} + */ + unsupportedPackageJsonSettings?: unknown; + /** + * {@inheritDoc PnpmOptionsConfiguration.resolutionMode} + */ + resolutionMode?: PnpmResolutionMode; + /** + * {@inheritDoc PnpmOptionsConfiguration.autoInstallPeers} + */ + autoInstallPeers?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAge} + */ + minimumReleaseAge?: number; + /** + * {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAgeExclude} + */ + minimumReleaseAgeExclude?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.alwaysInjectDependenciesFromOtherSubspaces} + */ + alwaysInjectDependenciesFromOtherSubspaces?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.alwaysFullInstall} + */ + alwaysFullInstall?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.pnpmLockfilePolicies} + */ + pnpmLockfilePolicies?: IPnpmLockfilePolicies; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalCatalogs} + */ + globalCatalogs?: Record>; +} + +/** + * Options that are only used when the PNPM package manager is selected. + * Use this class to load "common/config/rush/pnpm-config.json" file, + * or, load json from "pnpmOptions" field in "rush.json" for legacy support. + * + * @remarks + * It is valid to define these options in rush.json even if the PNPM package manager + * is not being used. + * + * @public + */ +export class PnpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { + private readonly _json: JsonObject; + private _globalPatchedDependencies: Record | undefined; + + /** + * The method used to resolve the store used by PNPM. + * + * @remarks + * Available options: + * - local: Use the standard Rush store path: common/temp/pnpm-store + * - global: Use PNPM's global store path + */ + public readonly pnpmStore: PnpmStoreLocation; + + /** + * This setting determines how PNPM chooses version numbers during `rush update`. + * + * @remarks + * For example, suppose `lib-x@3.0.0` depends on `"lib-y": "^1.2.3"` whose latest major + * releases are `1.8.9` and `2.3.4`. The resolution mode `lowest-direct` might choose + * `lib-y@1.2.3`, wheres `highest` will choose 1.8.9, and `time-based` will pick the + * highest compatible version at the time when `lib-x@3.0.0` itself was published (ensuring + * that the version could have been tested by the maintainer of "lib-x"). For local workspace + * projects, `time-based` instead works like `lowest-direct`, avoiding upgrades unless + * they are explicitly requested. Although `time-based` is the most robust option, it may be + * slightly slower with registries such as npmjs.com that have not implemented an optimization. + * + * IMPORTANT: Be aware that PNPM 8.0.0 initially defaulted to `lowest-direct` instead of + * `highest`, but PNPM reverted this decision in 8.6.12 because it caused confusion for users. + * Rush version 5.106.0 and newer avoids this confusion by consistently defaulting to + * `highest` when `resolutionMode` is not explicitly set in pnpm-config.json or .npmrc, + * regardless of your PNPM version. + * + * PNPM documentation: https://pnpm.io/npmrc#resolution-mode + * + * Possible values are: `highest`, `time-based`, and `lowest-direct`. + * The default is `highest`. + */ + public readonly resolutionMode: PnpmResolutionMode | undefined; + + /** + * The path for PNPM to use as the store directory. + * + * Will be overridden by environment variable RUSH_PNPM_STORE_PATH + */ + public readonly pnpmStorePath: string; + + /** + * If true, then Rush will add the "--strict-peer-dependencies" option when invoking PNPM. + * + * @remarks + * This causes "rush install" to fail if there are unsatisfied peer dependencies, which is + * an invalid state that can cause build failures or incompatible dependency versions. + * (For historical reasons, JavaScript package managers generally do not treat this invalid state + * as an error.) + * + * The default value is false. (For now.) + */ + public readonly strictPeerDependencies: boolean; + + /** + * If true, then `rush install` will report an error if manual modifications + * were made to the PNPM shrinkwrap file without running `rush update` afterwards. + * + * @remarks + * This feature protects against accidental inconsistencies that may be introduced + * if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this + * feature is enabled, `rush update` will write a hash of the shrinkwrap contents to repo-state.json, + * and then `rush update` and `rush install` will validate the hash. Note that this does not prohibit + * manual modifications, but merely requires `rush update` be run + * afterwards, ensuring that PNPM can report or repair any potential inconsistencies. + * + * To temporarily disable this validation when invoking `rush install`, use the + * `--bypass-policy` command-line parameter. + * + * The default value is false. + */ + public readonly preventManualShrinkwrapChanges: boolean; + + /** + * If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM. + * + * @remarks + * The default value is true. (For now.) + */ + public readonly useWorkspaces: boolean; + + /** + * When true, any missing non-optional peer dependencies are automatically installed. + * + * @remarks + * The default value is same as PNPM default value. (In PNPM 8.x, this value is true) + */ + 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 minimumReleaseAge: number | undefined; + + /** + * 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. + * + * @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; + + /** + * If true, then `rush update` add injected install options for all cross-subspace + * workspace dependencies, to avoid subspace doppelganger issue. + * + * Here, the injected install refers to PNPM's PNPM's "injected dependencies" + * feature. Learn more: https://pnpm.io/package_json#dependenciesmeta + * + * @remarks + * The default value is false. + */ + public readonly alwaysInjectDependenciesFromOtherSubspaces: boolean | undefined; + + /** + * The "globalOverrides" setting provides a simple mechanism for overriding version selections + * for all dependencies of all projects in the monorepo workspace. The settings are copied + * into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides + */ + public readonly globalOverrides: Record | undefined; + + /** + * The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors + * that are reported during installation with `strictPeerDependencies=true`. The settings are copied + * into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated + * by Rush during installation. + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * https://pnpm.io/package_json#pnpmpeerdependencyrules + */ + public readonly globalPeerDependencyRules: IPnpmPeerDependencyRules | undefined; + + /** + * The `globalPackageExtension` setting provides a way to patch arbitrary package.json fields + * for any PNPM dependency of the monorepo. The settings are copied into the `pnpm.packageExtensions` + * field of the `common/temp/package.json` file that is generated by Rush during installation. + * The `globalPackageExtension` setting has similar capabilities as `.pnpmfile.cjs` but without + * the downsides of an executable script (nondeterminism, unreliable caching, performance concerns). + * + * Order of precedence: `.pnpmfile.cjs` has the highest precedence, followed by + * `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, + * and `globalOverrides` has lowest precedence. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions + */ + public readonly globalPackageExtensions: Record | undefined; + + /** + * The `globalNeverBuiltDependencies` setting suppresses the `preinstall`, `install`, and `postinstall` + * lifecycle events for the specified NPM dependencies. This is useful for scripts with poor practices + * such as downloading large binaries without retries or attempting to invoke OS tools such as + * a C++ compiler. (PNPM's terminology refers to these lifecycle events as "building" a package; + * it has nothing to do with build system operations such as `rush build` or `rushx build`.) + * The settings are copied into the `pnpm.neverBuiltDependencies` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies + */ + public readonly globalNeverBuiltDependencies: string[] | 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 + * problematic in specific environments (e.g., dependencies with incompatible binaries or platform-specific requirements). + * The listed dependencies will be treated as though they are missing, even if other packages specify them as optional + * dependencies. The settings are copied into the pnpm.ignoredOptionalDependencies field of the common/temp/package.json + * file that is generated by Rush during installation. + * + * (SUPPORTED ONLY IN PNPM 9.0.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/package_json#pnpmignoredoptionaldependencies + */ + public readonly globalIgnoredOptionalDependencies: string[] | undefined; + + /** + * The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package + * versions that the NPM registry reports as being deprecated. This is useful if the + * deprecated package is an indirect dependency of an external package that has not released a fix. + * The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions + * + * If you are working to eliminate a deprecated version, it's better to specify `allowedDeprecatedVersions` + * in the package.json file for individual Rush projects. + */ + public readonly globalAllowedDeprecatedVersions: Record | undefined; + + /** + * (USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into + * the `common/temp/package.json` file that is generated by Rush during installation. + * This provides a way to experiment with new PNPM features. These settings will override + * any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`. + * + * USAGE OF THIS SETTING IS NOT SUPPORTED BY THE RUSH MAINTAINERS AND MAY CAUSE RUSH + * TO MALFUNCTION. If you encounter a missing PNPM setting that you believe should + * be supported, please create a GitHub issue or PR. Note that Rush does not aim to + * support every possible PNPM setting, but rather to promote a battle-tested installation + * strategy that is known to provide a good experience for large teams with lots of projects. + */ + public readonly unsupportedPackageJsonSettings: unknown | undefined; + + public readonly jsonFilename: string | undefined; + + /** + * The `pnpmLockfilePolicies` setting defines the policies that govern the `pnpm-lock.yaml` file. + */ + public readonly pnpmLockfilePolicies: IPnpmLockfilePolicies | undefined; + + /** + * (EXPERIMENTAL) If "true", then filtered installs ("rush install --to my-project") + * will be disregarded, instead always performing a full installation of the lockfile. + * This setting is primarily useful with Rush subspaces which enable filtering across + * multiple lockfiles, if filtering may be inefficient or undesirable for certain lockfiles. + * + * The default value is false. + */ + /*[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. + * + * The `globalPatchedDependencies` is added/updated automatically when you run pnpm patch-commit + * command. It is a dictionary where the key should be the package name and exact version. The value + * should be a relative path to a patch file. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies + */ + public get globalPatchedDependencies(): Record | undefined { + return this._globalPatchedDependencies; + } + + private constructor(json: IPnpmOptionsJson, commonTempFolder: string, jsonFilename?: string) { + super(json); + this._json = json; + this.jsonFilename = jsonFilename; + this.pnpmStore = json.pnpmStore || 'local'; + if (EnvironmentConfiguration.pnpmStorePathOverride) { + this.pnpmStorePath = EnvironmentConfiguration.pnpmStorePathOverride; + } else if (this.pnpmStore === 'global') { + this.pnpmStorePath = ''; + } else { + this.pnpmStorePath = `${commonTempFolder}/pnpm-store`; + } + this.strictPeerDependencies = !!json.strictPeerDependencies; + this.preventManualShrinkwrapChanges = !!json.preventManualShrinkwrapChanges; + this.useWorkspaces = !!json.useWorkspaces; + + this.globalOverrides = json.globalOverrides; + this.globalPeerDependencyRules = json.globalPeerDependencyRules; + this.globalPackageExtensions = json.globalPackageExtensions; + this.globalNeverBuiltDependencies = json.globalNeverBuiltDependencies; + this.globalIgnoredOptionalDependencies = json.globalIgnoredOptionalDependencies; + this.globalAllowedDeprecatedVersions = json.globalAllowedDeprecatedVersions; + this.unsupportedPackageJsonSettings = json.unsupportedPackageJsonSettings; + this._globalPatchedDependencies = json.globalPatchedDependencies; + this.resolutionMode = json.resolutionMode; + this.autoInstallPeers = json.autoInstallPeers; + this.minimumReleaseAge = json.minimumReleaseAge; + this.minimumReleaseAgeExclude = json.minimumReleaseAgeExclude; + this.alwaysInjectDependenciesFromOtherSubspaces = json.alwaysInjectDependenciesFromOtherSubspaces; + this.alwaysFullInstall = json.alwaysFullInstall; + this.pnpmLockfilePolicies = json.pnpmLockfilePolicies; + this.globalCatalogs = json.globalCatalogs; + } + + /** @internal */ + public static loadFromJsonFileOrThrow( + jsonFilePath: string, + commonTempFolder: string + ): PnpmOptionsConfiguration { + // TODO: plumb through the terminal + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + + const pnpmOptionsConfigFile: NonProjectConfigurationFile = + new NonProjectConfigurationFile({ + jsonSchemaObject: schemaJson + }); + const pnpmConfigJson: IPnpmOptionsJson = pnpmOptionsConfigFile.loadConfigurationFile( + terminal, + jsonFilePath + ); + pnpmConfigJson.$schema = pnpmOptionsConfigFile.getSchemaPropertyOriginalValue(pnpmConfigJson); + return new PnpmOptionsConfiguration(pnpmConfigJson || {}, commonTempFolder, jsonFilePath); + } + + /** @internal */ + public static loadFromJsonObject( + json: IPnpmOptionsJson, + commonTempFolder: string + ): PnpmOptionsConfiguration { + return new PnpmOptionsConfiguration(json, commonTempFolder); + } + + /** + * Updates patchedDependencies field of the PNPM options in the common/config/rush/pnpm-config.json file. + */ + public updateGlobalPatchedDependencies(patchedDependencies: Record | undefined): void { + this._globalPatchedDependencies = patchedDependencies; + this._json.globalPatchedDependencies = patchedDependencies; + 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 new file mode 100644 index 00000000000..19e3899804c --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmProjectShrinkwrapFile.ts @@ -0,0 +1,239 @@ +// 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 { InternalError, JsonFile } from '@rushstack/node-core-library'; + +import { BaseProjectShrinkwrapFile } from '../base/BaseProjectShrinkwrapFile'; +import type { + PnpmShrinkwrapFile, + IPnpmShrinkwrapDependencyYaml, + IPnpmVersionSpecifier +} from './PnpmShrinkwrapFile'; +import type { DependencySpecifier } from '../DependencySpecifier'; +import { RushConstants } from '../RushConstants'; +import type { Subspace } from '../../api/Subspace'; + +/** + * + */ +export class PnpmProjectShrinkwrapFile extends BaseProjectShrinkwrapFile { + /** + * Generate and write the project shrinkwrap file to /.rush/temp/shrinkwrap-deps.json. + * @returns True if the project shrinkwrap was created or updated, false otherwise. + */ + public async updateProjectShrinkwrapAsync(): Promise { + const projectShrinkwrapMap: Map | undefined = this.generateProjectShrinkwrapMap(); + + return projectShrinkwrapMap ? this.saveAsync(projectShrinkwrapMap) : this.deleteIfExistsAsync(); + } + + public hasChanges(otherShrinkwrap: PnpmProjectShrinkwrapFile): boolean { + if ( + !otherShrinkwrap.shrinkwrapFile.isWorkspaceCompatible && + !otherShrinkwrap.shrinkwrapFile.getTempProjectDependencyKey(this.project.tempProjectName) + ) { + // The project is new to the shrinkwrap file. + return true; + } + + const otherMap: Map | undefined = otherShrinkwrap.generateProjectShrinkwrapMap(); + const thisMap: Map | undefined = this.generateProjectShrinkwrapMap(); + + if (!thisMap || !otherMap) { + // Handle one or both being undefined. + return !!(thisMap || otherMap); + } + + if (thisMap.size !== otherMap.size) { + // Entries added or removed + return true; + } + + for (const [key, value] of thisMap) { + if (otherMap.get(key) !== value) { + // A dependency changed or was added/removed + return true; + } + } + + return false; + } + + /** + * Generate the project shrinkwrap file content + */ + protected generateProjectShrinkwrapMap(): Map | undefined { + const projectShrinkwrapMap: Map | undefined = this.shrinkwrapFile.isWorkspaceCompatible + ? this.generateWorkspaceProjectShrinkwrapMap() + : this.generateLegacyProjectShrinkwrapMap(); + + return projectShrinkwrapMap; + } + + protected generateWorkspaceProjectShrinkwrapMap(): Map | undefined { + // Obtain the workspace importer from the shrinkwrap, which lists resolved dependencies + const subspace: Subspace = this.project.subspace; + + const importerKey: string = this.shrinkwrapFile.getImporterKeyByPath( + subspace.getSubspaceTempFolderPath(), + this.project.projectFolder + ); + + const projectShrinkwrapMap: Map | undefined = + this.shrinkwrapFile.getIntegrityForImporter(importerKey); + + return projectShrinkwrapMap; + } + + protected generateLegacyProjectShrinkwrapMap(): Map { + const tempProjectDependencyKey: string | undefined = this.shrinkwrapFile.getTempProjectDependencyKey( + this.project.tempProjectName + ); + if (!tempProjectDependencyKey) { + throw new Error(`Cannot get dependency key for temp project: ${this.project.tempProjectName}`); + } + const parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml = + this.shrinkwrapFile.getShrinkwrapEntryFromTempProjectDependencyKey(tempProjectDependencyKey)!; + + const allDependencies: [string, IPnpmVersionSpecifier][] = [ + ...Object.entries(parentShrinkwrapEntry.dependencies || {}), + ...Object.entries(parentShrinkwrapEntry.optionalDependencies || {}) + ]; + + const projectShrinkwrapMap: Map = new Map(); + for (const [name, version] of allDependencies) { + if (name.indexOf(`${RushConstants.rushTempNpmScope}/`) < 0) { + // Only select the shrinkwrap dependencies that are non-local since we already handle local + // project changes + this._addDependencyRecursive(projectShrinkwrapMap, name, version, parentShrinkwrapEntry); + } + } + + // Since peer dependencies within on external packages may be hoisted up to the top-level package, + // we need to resolve and add these dependencies directly + this._resolveAndAddPeerDependencies(projectShrinkwrapMap, parentShrinkwrapEntry); + + return projectShrinkwrapMap; + } + + private _addDependencyRecursive( + projectShrinkwrapMap: Map, + name: string, + version: IPnpmVersionSpecifier, + parentShrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, + throwIfShrinkwrapEntryMissing: boolean = true + ): void { + const specifier: string = `${name}@${version}`; + if (projectShrinkwrapMap.has(specifier)) { + // getShrinkwrapEntry is idempotent with respect to name and version + return; + } + + const shrinkwrapEntry: IPnpmShrinkwrapDependencyYaml | undefined = this.shrinkwrapFile.getShrinkwrapEntry( + name, + version + ); + + if (!shrinkwrapEntry) { + if (throwIfShrinkwrapEntryMissing) { + throw new InternalError(`Unable to find dependency ${name} with version ${version} in shrinkwrap.`); + } + return; + } + + // 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('hex'); + const integrity: string = `${name}@${version}:${sha256Digest}:`; + + // Add the current dependency + projectShrinkwrapMap.set(specifier, integrity); + + // Add the dependencies of the dependency + for (const [dependencyName, dependencyVersion] of Object.entries(shrinkwrapEntry.dependencies || {})) { + this._addDependencyRecursive(projectShrinkwrapMap, dependencyName, dependencyVersion, shrinkwrapEntry); + } + + // Add the optional dependencies of the dependency, and don't blow up if they don't exist + for (const [dependencyName, dependencyVersion] of Object.entries( + shrinkwrapEntry.optionalDependencies || {} + )) { + this._addDependencyRecursive( + projectShrinkwrapMap, + dependencyName, + dependencyVersion, + shrinkwrapEntry, + /* throwIfShrinkwrapEntryMissing */ false + ); + } + + // When using workspaces, hoisting of peer dependencies to a singular top-level project is not possible. + // Therefore, all packages that are consumed should be specified in the dependency tree. Given this, there + // is no need to look for peer dependencies, since it is simply a constraint to be validated by the + // package manager. + if (!this.shrinkwrapFile.isWorkspaceCompatible) { + this._resolveAndAddPeerDependencies(projectShrinkwrapMap, shrinkwrapEntry, parentShrinkwrapEntry); + } + } + + private _resolveAndAddPeerDependencies( + projectShrinkwrapMap: Map, + shrinkwrapEntry: IPnpmShrinkwrapDependencyYaml, + parentShrinkwrapEntry?: IPnpmShrinkwrapDependencyYaml + ): void { + for (const peerDependencyName of Object.keys(shrinkwrapEntry.peerDependencies || {})) { + // Skip peer dependency resolution of local package peer dependencies + if (peerDependencyName.indexOf(RushConstants.rushTempNpmScope) !== -1) { + continue; + } + + // Check to see if the peer dependency is satisfied with the current shrinkwrap + // entry. If not, check the parent shrinkwrap entry. Finally, if neither have + // the specified dependency, check that the parent mentions the dependency in + // it's own peer dependencies. If it is, we can rely on the package manager and + // make the assumption that we've already found it further up the stack. + if ( + shrinkwrapEntry.dependencies?.hasOwnProperty(peerDependencyName) || + parentShrinkwrapEntry?.dependencies?.hasOwnProperty(peerDependencyName) || + parentShrinkwrapEntry?.peerDependencies?.hasOwnProperty(peerDependencyName) + ) { + continue; + } + + // As a last attempt, check if it's been hoisted up as a top-level dependency. If + // we can't find it, we can assume that it's already been provided somewhere up the + // dependency tree. + const topLevelDependencySpecifier: DependencySpecifier | undefined = + this.shrinkwrapFile.getTopLevelDependencyVersion(peerDependencyName); + + if (topLevelDependencySpecifier) { + this._addDependencyRecursive( + projectShrinkwrapMap, + peerDependencyName, + this.shrinkwrapFile.getTopLevelDependencyKey(peerDependencyName)!, + shrinkwrapEntry + ); + } + } + } + + /** + * Save the current state of the object to project/.rush/temp/shrinkwrap-deps.json + */ + protected async saveAsync(projectShrinkwrapMap: Map): Promise { + const file: { [specifier: string]: string } = {}; + const keys: string[] = Array.from(projectShrinkwrapMap.keys()).sort(); + for (const key of keys) { + file[key] = projectShrinkwrapMap.get(key)!; + } + await JsonFile.saveAsync(file, this.projectShrinkwrapFilePath, { ensureFolderExists: true }); + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.ts new file mode 100644 index 00000000000..c2c549fb21c --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkWrapFileConverters.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. + +/** + * Fork https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/lockfileFormatConverters.ts + * + * Pnpm lockfile v9 have some breaking changes on the lockfile format. For Example, the "packages" field has been split into "packages" and "snapshots" two parts. + * Rush should not parse the lockfile by itself, but should rely on pnpm to parse the lockfile. + * To ensure consistency with pnpm's parsing logic, I copied the relevant logic from @pnpm/lockfile.fs to this file. + * + * There are some reasons for copying the relevant logic instead of depending on @pnpm/lockfile.fs directly: + * 1. @pnpm/lockfile.fs has a exports filed in package.json, which will cause convertLockfileV9ToLockfileObject cannot be imported directly. + * 2. @pnpm/lockfile.fs only provides asynchronous read methods, while rush requires synchronous reading of the lockfile file. + * Perhaps this file will be deleted in the future and instead depend on @pnpm/lockfile.fs directly. + */ +import { removeSuffix } from '@pnpm/dependency-path'; +import type { + InlineSpecifiersProjectSnapshot, + InlineSpecifiersResolvedDependencies, + Lockfile, + LockfileFile, + LockfileFileV9, + PackageSnapshots, + ProjectSnapshot, + ResolvedDependencies +} from '@pnpm/lockfile.types'; + +import { removeNullishProps } from '../../utilities/objectUtilities'; + +type DepPath = string & { __brand: 'DepPath' }; +// eslint-disable-next-line @typescript-eslint/typedef +const DEPENDENCIES_FIELDS = ['optionalDependencies', 'dependencies', 'devDependencies'] as const; + +function revertProjectSnapshot(from: InlineSpecifiersProjectSnapshot): ProjectSnapshot { + const specifiers: ResolvedDependencies = {}; + + function moveSpecifiers(fromDep: InlineSpecifiersResolvedDependencies): ResolvedDependencies { + const resolvedDependencies: ResolvedDependencies = {}; + for (const [depName, { specifier, version }] of Object.entries(fromDep)) { + const existingValue: string = specifiers[depName]; + if (existingValue != null && existingValue !== specifier) { + throw new Error( + `Project snapshot lists the same dependency more than once with conflicting versions: ${depName}` + ); + } + + specifiers[depName] = specifier; + resolvedDependencies[depName] = version; + } + return resolvedDependencies; + } + + const dependencies: ResolvedDependencies | undefined = + from.dependencies == null ? from.dependencies : moveSpecifiers(from.dependencies); + const devDependencies: ResolvedDependencies | undefined = + from.devDependencies == null ? from.devDependencies : moveSpecifiers(from.devDependencies); + const optionalDependencies: ResolvedDependencies | undefined = + from.optionalDependencies == null ? from.optionalDependencies : moveSpecifiers(from.optionalDependencies); + + return { + ...removeNullishProps({ + ...from, + dependencies, + devDependencies, + optionalDependencies + }), + specifiers + }; +} + +function convertFromLockfileFileMutable(lockfileFile: LockfileFile): LockfileFileV9 { + if (typeof lockfileFile?.importers === 'undefined') { + lockfileFile.importers = { + '.': { + dependenciesMeta: lockfileFile.dependenciesMeta, + publishDirectory: lockfileFile.publishDirectory + } + }; + for (const depType of DEPENDENCIES_FIELDS) { + if (lockfileFile[depType] != null) { + lockfileFile.importers['.'][depType] = lockfileFile[depType]; + delete lockfileFile[depType]; + } + } + } + return lockfileFile as LockfileFileV9; +} + +function mapValues(obj: Record, mapper: (val: T, key: string) => U): Record { + const result: Record = {}; + for (const [key, value] of Object.entries(obj)) { + result[key] = mapper(value, key); + } + return result; +} + +/** + * Convert lockfile v9 object to standard lockfile object. + * + * This function will mutate the lockfile object. It will: + * 1. Ensure importers['.'] exists. + * 2. Merge snapshots and packages into packages. + * 3. Extract specifier from importers['xxx'] into the specifiers field. + */ +export function convertLockfileV9ToLockfileObject(lockfile: LockfileFileV9): Lockfile { + const { importers, ...rest } = convertFromLockfileFileMutable(lockfile); + + const packages: PackageSnapshots = {}; + for (const [depPath, pkg] of Object.entries(lockfile.snapshots ?? {})) { + const pkgId: string = removeSuffix(depPath); + packages[depPath as DepPath] = Object.assign(pkg, lockfile.packages?.[pkgId]); + } + return { + ...rest, + packages, + importers: mapValues(importers ?? {}, revertProjectSnapshot) + }; +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts new file mode 100644 index 00000000000..6da650f35d5 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -0,0 +1,1318 @@ +// 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 crypto from 'node:crypto'; + +import * as semver from 'semver'; +import * as dependencyPathLockfilePreV9 from '@pnpm/dependency-path-lockfile-pre-v9'; +import * as dependencyPath from '@pnpm/dependency-path'; +import type { + ProjectId, + Lockfile, + PackageSnapshot, + ProjectSnapshot, + LockfileFileV9, + ResolvedDependencies +} from '@pnpm/lockfile.types'; + +import { + FileSystem, + AlreadyReportedError, + Import, + Path, + type IPackageJson, + InternalError +} from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import type { IReadonlyLookupByPath } from '@rushstack/lookup-by-path'; + +import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { DependencySpecifier } from '../DependencySpecifier'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { IShrinkwrapFilePolicyValidatorOptions } from '../policy/ShrinkwrapFilePolicy'; +import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon'; +import { RushConstants } from '../RushConstants'; +import type { IExperimentsJson } from '../../api/ExperimentsConfiguration'; +import { DependencyType, type PackageJsonDependency, PackageJsonEditor } from '../../api/PackageJsonEditor'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { PnpmfileConfiguration } from './PnpmfileConfiguration'; +import { PnpmProjectShrinkwrapFile } from './PnpmProjectShrinkwrapFile'; +import type { PackageManagerOptionsConfigurationBase } from '../base/BasePackageManagerOptionsConfiguration'; +import { PnpmOptionsConfiguration } from './PnpmOptionsConfiguration'; +import type { IPnpmfile, IPnpmfileContext } from './IPnpmfile'; +import type { Subspace } from '../../api/Subspace'; +import { CustomTipId, type CustomTipsConfiguration } from '../../api/CustomTipsConfiguration'; +import { convertLockfileV9ToLockfileObject } from './PnpmShrinkWrapFileConverters'; + +const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); + +export enum ShrinkwrapFileMajorVersion { + V6 = 6, + V9 = 9 +} + +export interface IPeerDependenciesMetaYaml { + optional?: boolean; +} +export interface IDependenciesMetaYaml { + injected?: boolean; +} + +export type IPnpmV7VersionSpecifier = string; +export interface IPnpmV8VersionSpecifier { + version: string; + specifier: string; +} +export type IPnpmV9VersionSpecifier = string; +export type IPnpmVersionSpecifier = + | IPnpmV7VersionSpecifier + | IPnpmV8VersionSpecifier + | IPnpmV9VersionSpecifier; + +export interface IPnpmShrinkwrapDependencyYaml extends Omit { + resolution: { + /** The directory this package should clone, for injected dependencies */ + directory?: string; + /** The hash of the tarball, to ensure archive integrity */ + integrity?: string; + /** The name of the tarball, if this was from a TGZ file */ + tarball?: string; + }; +} + +export type IPnpmShrinkwrapImporterYaml = ProjectSnapshot; + +export interface IPnpmShrinkwrapYaml extends Lockfile { + /** + * This interface represents the raw pnpm-lock.YAML file + * Example: + * { + * "dependencies": { + * "@rush-temp/project1": "file:./projects/project1.tgz" + * }, + * "packages": { + * "file:projects/library1.tgz": { + * "dependencies: { + * "markdown": "0.5.0" + * }, + * "name": "@rush-temp/library1", + * "resolution": { + * "tarball": "file:projects/library1.tgz" + * }, + * "version": "0.0.0" + * }, + * "markdown/0.5.0": { + * "resolution": { + * "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=" + * } + * } + * }, + * "registry": "http://localhost:4873/", + * "shrinkwrapVersion": 3, + * "specifiers": { + * "@rush-temp/project1": "file:./projects/project1.tgz" + * } + * } + */ + /** The list of resolved version numbers for direct dependencies */ + dependencies?: Record; + /** The list of specifiers used to resolve direct dependency versions */ + specifiers?: Record; + /** URL of the registry which was used */ + registry?: string; +} + +export interface ILoadFromFileOptions { + withCaching?: boolean; +} + +export function parsePnpm9DependencyKey( + dependencyName: string, + versionSpecifier: IPnpmVersionSpecifier +): DependencySpecifier | undefined { + if (!versionSpecifier) { + return undefined; + } + + const dependencyKey: string = normalizePnpmVersionSpecifier(versionSpecifier); + + // Example: file:projects/project2 + // Example: project-2@file:projects/project2 + // Example: link:../projects/project1 + if (/(file|link):/.test(dependencyKey)) { + // If it starts with an NPM scheme such as "file:projects/my-app.tgz", we don't support that + return undefined; + } + + const { peersIndex } = dependencyPath.indexOfPeersSuffix(dependencyKey); + if (peersIndex !== -1) { + // Remove peer suffix + const key: string = dependencyKey.slice(0, peersIndex); + + // Example: 7.26.0 + if (semver.valid(key)) { + return DependencySpecifier.parseWithCache(dependencyName, key); + } + } + + // Example: @babel/preset-env@7.26.0 -> name=@babel/preset-env version=7.26.0 + // Example: @babel/preset-env@7.26.0(peer@1.2.3) -> name=@babel/preset-env version=7.26.0 + // Example: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 -> 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 name: string = dependency.name ?? dependencyName; + const version: string = dependency.version ?? dependency.nonSemverVersion ?? dependencyKey; + + // Example: https://xxxx/pad-left/tarball/2.1.0 + // 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 DependencySpecifier.parseWithCache(name, version); + } + + // Is it an alias for a different package? + if (name === dependencyName) { + // No, it's a regular dependency + return DependencySpecifier.parseWithCache(name, version); + } else { + // If the parsed package name is different from the dependencyName, then this is an NPM package alias + return DependencySpecifier.parseWithCache(dependencyName, `npm:${name}@${version}`); + } +} + +/** + * Given an encoded "dependency key" from the PNPM shrinkwrap file, this parses it into an equivalent + * DependencySpecifier. + * + * @returns a SemVer string, or undefined if the version specifier cannot be parsed + */ +export function parsePnpmDependencyKey( + dependencyName: string, + versionSpecifier: IPnpmVersionSpecifier +): DependencySpecifier | undefined { + if (!versionSpecifier) { + return undefined; + } + + const dependencyKey: string = normalizePnpmVersionSpecifier(versionSpecifier); + + if (/^\w+:/.test(dependencyKey)) { + // If it starts with an NPM scheme such as "file:projects/my-app.tgz", we don't support that + return undefined; + } + + // The package name parsed from the dependency key, or dependencyName if it was omitted. + // Example: "@scope/depame" + let parsedPackageName: string; + + // The trailing portion of the dependency key that includes the version and optional peer dependency path. + // Example: "2.8.0/chai@3.5.0+sinon@1.17.7" + let parsedInstallPath: string; + + // Example: "path.pkgs.visualstudio.com/@scope/depame/1.4.0" --> 0="@scope/depame" 1="1.4.0" + // Example: "/isarray/2.0.1" --> 0="isarray" 1="2.0.1" + // Example: "/sinon-chai/2.8.0/chai@3.5.0+sinon@1.17.7" --> 0="sinon-chai" 1="2.8.0/chai@3.5.0+sinon@1.17.7" + // Example: "/typescript@5.1.6" --> 0=typescript 1="5.1.6" + // Example: 1.2.3_peer-dependency@.4.5.6 --> no match + // Example: 1.2.3_@scope+peer-dependency@.4.5.6 --> no match + // Example: 1.2.3(peer-dependency@.4.5.6) --> no match + // Example: 1.2.3(@scope/peer-dependency@.4.5.6) --> no match + const packageNameMatch: RegExpMatchArray | null = /^[^\/(]*\/((?:@[^\/(]+\/)?[^\/(]+)[\/@](.*)$/.exec( + dependencyKey + ); + if (packageNameMatch) { + parsedPackageName = packageNameMatch[1]; + parsedInstallPath = packageNameMatch[2]; + } else { + parsedPackageName = dependencyName; + + // Example: "23.6.0_babel-core@6.26.3" + // Example: "23.6.0" + parsedInstallPath = dependencyKey; + } + + // The SemVer value + // Example: "2.8.0" + let parsedVersionPart: string; + + // Example: "23.6.0_babel-core@6.26.3" --> "23.6.0" + // Example: "2.8.0/chai@3.5.0+sinon@1.17.7" --> "2.8.0" + // Example: "0.53.1(@types/node@14.18.36)" --> "0.53.1" + const versionMatch: RegExpMatchArray | null = /^([^\(\/_]+)[(\/_]/.exec(parsedInstallPath); + if (versionMatch) { + parsedVersionPart = versionMatch[1]; + } else { + // Example: "2.8.0" + parsedVersionPart = parsedInstallPath; + } + + // By this point, we expect parsedVersionPart to be a valid SemVer range + if (!parsedVersionPart) { + return undefined; + } + + if (!semver.valid(parsedVersionPart)) { + const urlRegex: RegExp = + /^(git@|@)?([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}(\/|\+)([^\/\\]+\/?)*([^\/\\]+)$/i; + // Test for urls: + // Examples: + // @github.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // github.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // github.com.au/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // bitbucket.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // bitbucket.com+abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // git@bitbucket.com+abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + // bitbucket.co.in/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 + if (urlRegex.test(dependencyKey)) { + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependencyName, + dependencyKey + ); + return dependencySpecifier; + } else { + return undefined; + } + } + + // Is it an alias for a different package? + if (parsedPackageName === dependencyName) { + // No, it's a regular dependency + return DependencySpecifier.parseWithCache(parsedPackageName, parsedVersionPart); + } else { + // If the parsed package name is different from the dependencyName, then this is an NPM package alias + return DependencySpecifier.parseWithCache( + dependencyName, + `npm:${parsedPackageName}@${parsedVersionPart}` + ); + } +} + +export function normalizePnpmVersionSpecifier(versionSpecifier: IPnpmVersionSpecifier): string { + if (typeof versionSpecifier === 'string') { + return versionSpecifier; + } else { + return versionSpecifier.version; + } +} + +const cacheByLockfileHash: Map = new Map(); + +export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { + public readonly shrinkwrapFileMajorVersion: number; + public readonly isWorkspaceCompatible: boolean; + public readonly registry: string; + public readonly dependencies: ReadonlyMap; + public readonly importers: ReadonlyMap; + public readonly specifiers: ReadonlyMap; + 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, hash: string) { + super(); + this.hash = hash; + this._shrinkwrapJson = shrinkwrapJson; + cacheByLockfileHash.set(hash, this); + + // Normalize the data + const lockfileVersion: string | number | undefined = shrinkwrapJson.lockfileVersion; + if (typeof lockfileVersion === 'string') { + const isDotIncluded: boolean = lockfileVersion.includes('.'); + this.shrinkwrapFileMajorVersion = parseInt( + lockfileVersion.substring(0, isDotIncluded ? lockfileVersion.indexOf('.') : undefined), + 10 + ); + } else if (typeof lockfileVersion === 'number') { + this.shrinkwrapFileMajorVersion = Math.floor(lockfileVersion); + } else { + this.shrinkwrapFileMajorVersion = 0; + } + + this.registry = shrinkwrapJson.registry || ''; + this.dependencies = new Map(Object.entries(shrinkwrapJson.dependencies || {})); + this.importers = new Map(Object.entries(shrinkwrapJson.importers || {})); + this.specifiers = new Map(Object.entries(shrinkwrapJson.specifiers || {})); + this.packages = new Map(Object.entries(shrinkwrapJson.packages || {})); + 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; + + this._integrities = new Map(); + } + + public static getLockfileV9PackageId(name: string, version: string): string { + /** + * name@1.2.3 -> name@1.2.3 + * name@1.2.3(peer) -> name@1.2.3(peer) + * https://xxx/@a/b -> name@https://xxx/@a/b + * file://xxx -> name@file://xxx + * 1.2.3 -> name@1.2.3 + */ + + if (/https?:/.test(version)) { + return /@https?:/.test(version) ? version : `${name}@${version}`; + } else if (/file:/.test(version)) { + return /@file:/.test(version) ? version : `${name}@${version}`; + } + + return 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, + options: ILoadFromFileOptions = {} + ): PnpmShrinkwrapFile | undefined { + 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}`); + } + } + + public static loadFromString(shrinkwrapContent: string): 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 shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.load(shrinkwrapContent) as IPnpmShrinkwrapYaml; + if ((shrinkwrapJson as LockfileFileV9).snapshots) { + const lockfile: IPnpmShrinkwrapYaml | null = convertLockfileV9ToLockfileObject( + shrinkwrapJson as LockfileFileV9 + ); + /** + * In Lockfile V9, + * 1. There is no top-level dependencies field, but it is a property of the importers field. + * 2. The version may is not equal to the key in the package field. Thus, it needs to be standardized in the form of `:`. + * + * importers: + * .: + * dependencies: + * 'project1': + * specifier: file:./projects/project1 + * version: file:projects/project1 + * + * packages: + * project1@file:projects/project1: + * resolution: {directory: projects/project1, type: directory} + */ + const dependencies: ResolvedDependencies | undefined = + lockfile.importers['.' as ProjectId]?.dependencies; + if (dependencies) { + lockfile.dependencies = {}; + for (const [name, versionSpecifier] of Object.entries(dependencies)) { + lockfile.dependencies[name] = PnpmShrinkwrapFile.getLockfileV9PackageId(name, versionSpecifier); + } + } + return new PnpmShrinkwrapFile(lockfile, hash); + } + + return new PnpmShrinkwrapFile(shrinkwrapJson, hash); + } + + public getShrinkwrapHash(experimentsConfig?: IExperimentsJson): string { + // The 'omitImportersFromPreventManualShrinkwrapChanges' experiment skips the 'importers' section + // when computing the hash, since the main concern is changes to the overall external dependency footprint + const { omitImportersFromPreventManualShrinkwrapChanges } = experimentsConfig || {}; + + const shrinkwrapContent: string = this._serializeInternal( + omitImportersFromPreventManualShrinkwrapChanges + ); + return crypto.createHash('sha1').update(shrinkwrapContent).digest('hex'); + } + + /** + * Determine whether `pnpm-lock.yaml` contains insecure sha1 hashes. + * @internal + */ + private _disallowInsecureSha1( + customTipsConfiguration: CustomTipsConfiguration, + exemptPackageVersions: Record, + terminal: ITerminal, + subspaceName: string + ): boolean { + const exemptPackageList: Map = new Map(); + for (const [pkgName, versions] of Object.entries(exemptPackageVersions)) { + for (const version of versions) { + exemptPackageList.set(this._getPackageId(pkgName, version), true); + } + } + + for (const [pkgName, { resolution }] of this.packages) { + if ( + resolution?.integrity?.startsWith('sha1') && + !exemptPackageList.has(this._parseDependencyPath(pkgName)) + ) { + terminal.writeErrorLine( + 'Error: An integrity field with "sha1" was detected in the pnpm-lock.yaml file located in subspace ' + + `${subspaceName}; this conflicts with the "disallowInsecureSha1" policy from pnpm-config.json.\n` + ); + + customTipsConfiguration._showErrorTip(terminal, CustomTipId.TIP_RUSH_DISALLOW_INSECURE_SHA1); + + return true; // Indicates an error was found + } + } + return false; + } + + /** @override */ + public validateShrinkwrapAfterUpdate( + rushConfiguration: RushConfiguration, + subspace: Subspace, + terminal: ITerminal + ): void { + const pnpmOptions: PnpmOptionsConfiguration = subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; + const { pnpmLockfilePolicies } = pnpmOptions; + + let invalidPoliciesCount: number = 0; + + if (pnpmLockfilePolicies?.disallowInsecureSha1?.enabled) { + const isError: boolean = this._disallowInsecureSha1( + rushConfiguration.customTipsConfiguration, + pnpmLockfilePolicies.disallowInsecureSha1.exemptPackageVersions, + terminal, + subspace.subspaceName + ); + if (isError) { + invalidPoliciesCount += 1; + } + } + + if (invalidPoliciesCount > 0) { + throw new AlreadyReportedError(); + } + } + + /** @override */ + public validate( + packageManagerOptionsConfig: PackageManagerOptionsConfigurationBase, + policyOptions: IShrinkwrapFilePolicyValidatorOptions, + experimentsConfig?: IExperimentsJson + ): void { + super.validate(packageManagerOptionsConfig, policyOptions); + if (!(packageManagerOptionsConfig instanceof PnpmOptionsConfiguration)) { + throw new Error('The provided package manager options are not valid for PNPM shrinkwrap files.'); + } + + if (!policyOptions.allowShrinkwrapUpdates) { + if (!policyOptions.repoState.isValid) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + `The ${RushConstants.repoStateFilename} file is invalid. There may be a merge conflict marker ` + + 'in the file. You may need to run "rush update" to refresh its contents.' + ) + '\n' + ); + throw new AlreadyReportedError(); + } + + // Only check the hash if allowShrinkwrapUpdates is false. If true, the shrinkwrap file + // may have changed and the hash could be invalid. + if (packageManagerOptionsConfig.preventManualShrinkwrapChanges) { + if (!policyOptions.repoState.pnpmShrinkwrapHash) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'The existing shrinkwrap file hash could not be found. You may need to run "rush update" to ' + + 'populate the hash. See the "preventManualShrinkwrapChanges" setting documentation for details.' + ) + '\n' + ); + throw new AlreadyReportedError(); + } + + if (this.getShrinkwrapHash(experimentsConfig) !== policyOptions.repoState.pnpmShrinkwrapHash) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + 'The shrinkwrap file hash does not match the expected hash. Please run "rush update" to ensure the ' + + 'shrinkwrap file is up to date. See the "preventManualShrinkwrapChanges" setting documentation for ' + + 'details.' + ) + '\n' + ); + throw new AlreadyReportedError(); + } + } + } + } + + /** + * This operation exactly mirrors the behavior of PNPM's own implementation: + * https://github.com/pnpm/pnpm/blob/73ebfc94e06d783449579cda0c30a40694d210e4/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L162 + */ + 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; + return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; + } + + /** + * Normalize dependency paths for PNPM shrinkwrap files. + * Example: "/eslint-utils@3.0.0(eslint@8.23.1)" --> "/eslint-utils@3.0.0" + * 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 >= ShrinkwrapFileMajorVersion.V6) { + depPath = this._convertLockfileV6DepPathToV5DepPath(packagePath); + } + const pkgInfo: ReturnType = + dependencyPathLockfilePreV9.parse(depPath); + return this._getPackageId(pkgInfo.name as string, pkgInfo.version as string); + } + + /** @override */ + public getTempProjectNames(): ReadonlyArray { + return this._getTempProjectNames(this._shrinkwrapJson.dependencies || {}); + } + + /** + * Gets the path to the tarball file if the package is a tarball. + * Returns undefined if the package entry doesn't exist or the package isn't a tarball. + * Example of return value: file:projects/build-tools.tgz + */ + public getTarballPath(packageName: string): string | undefined { + const dependency: IPnpmShrinkwrapDependencyYaml | undefined = this.packages.get(packageName); + return dependency?.resolution?.tarball; + } + + public getTopLevelDependencyKey(dependencyName: string): IPnpmVersionSpecifier | undefined { + return this.dependencies.get(dependencyName); + } + + /** + * Gets the version number from the list of top-level dependencies in the "dependencies" section + * of the shrinkwrap file. Sample return values: + * '2.1.113' + * '1.9.0-dev.27' + * 'file:projects/empty-webpart-project.tgz' + * undefined + * + * @override + */ + public getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { + let value: IPnpmVersionSpecifier | undefined = this.dependencies.get(dependencyName); + if (value) { + value = normalizePnpmVersionSpecifier(value); + + // Getting the top level dependency version from a PNPM lockfile version 5.x or 6.1 + // -------------------------------------------------------------------------- + // + // 1) Top-level tarball dependency entries in pnpm-lock.yaml look like in 5.x: + // ``` + // '@rush-temp/sp-filepicker': 'file:projects/sp-filepicker.tgz_0ec79d3b08edd81ebf49cd19ca50b3f5' + // ``` + // And in version 6.1, they look like: + // ``` + // '@rush-temp/sp-filepicker': + // specifier: file:./projects/generate-api-docs.tgz + // version: file:projects/generate-api-docs.tgz + // ``` + + // Then, it would be defined below (version 5.x): + // ``` + // 'file:projects/sp-filepicker.tgz_0ec79d3b08edd81ebf49cd19ca50b3f5': + // dependencies: + // '@microsoft/load-themed-styles': 1.10.7 + // ... + // resolution: + // integrity: sha512-guuoFIc**== + // tarball: 'file:projects/sp-filepicker.tgz' + // ``` + // Or in version 6.1: + // ``` + // file:projects/sp-filepicker.tgz: + // resolution: {integrity: sha512-guuoFIc**==, tarball: file:projects/sp-filepicker.tgz} + // name: '@rush-temp/sp-filepicker' + // version: 0.0.0 + // dependencies: + // '@microsoft/load-themed-styles': 1.10.7 + // ... + // dev: false + // ``` + + // Here, we are interested in the part 'file:projects/sp-filepicker.tgz'. Splitting by underscores is not the + // best way to get this because file names could have underscores in them. Instead, we could use the tarball + // field in the resolution section. + + // 2) Top-level non-tarball dependency entries in pnpm-lock.yaml would look like in 5.x: + // ``` + // '@rushstack/set-webpack-public-path-plugin': 2.1.133 + // @microsoft/sp-build-node': 1.9.0-dev.27_typescript@2.9.2 + // ``` + // And in version 6.1, they look like: + // ``` + // '@rushstack/set-webpack-public-path-plugin': + // specifier: ^2.1.133 + // version: 2.1.133 + // '@microsoft/sp-build-node': + // specifier: 1.9.0-dev.27 + // version: 1.9.0-dev.27(typescript@2.9.2) + // ``` + + // Here, we could either just split by underscores and take the first part (5.x) or use the specifier field + // (6.1). + + // The below code is also compatible with lockfile versions < 5.1 + + const dependency: IPnpmShrinkwrapDependencyYaml | undefined = this.packages.get(value); + if (dependency?.resolution?.tarball && value.startsWith(dependency.resolution.tarball)) { + return DependencySpecifier.parseWithCache(dependencyName, dependency.resolution.tarball); + } + + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + const { version, nonSemverVersion } = dependencyPath.parse(value); + value = version ?? nonSemverVersion ?? value; + } else { + let underscoreOrParenthesisIndex: number = value.indexOf('_'); + if (underscoreOrParenthesisIndex < 0) { + underscoreOrParenthesisIndex = value.indexOf('('); + } + + if (underscoreOrParenthesisIndex >= 0) { + value = value.substring(0, underscoreOrParenthesisIndex); + } + } + + return DependencySpecifier.parseWithCache(dependencyName, value); + } + return undefined; + } + + /** + * The PNPM shrinkwrap file has top-level dependencies on the temp projects like this (version 5.x): + * + * ``` + * dependencies: + * '@rush-temp/my-app': 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0' + * packages: + * /@types/node/10.14.15: + * dev: false + * 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0': + * dev: false + * name: '@rush-temp/my-app' + * version: 0.0.0 + * ``` + * + * or in version 6.1, like this: + * ``` + * dependencies: + * '@rush-temp/my-app': + * specifier: file:./projects/my-app.tgz + * version: file:projects/my-app.tgz + * packages: + * /@types/node@10.14.15: + * resolution: {integrity: sha512-iAB+**==} + * dev: false + * file:projects/my-app.tgz + * resolution: {integrity: sha512-guuoFIc**==, tarball: file:projects/sp-filepicker.tgz} + * name: '@rush-temp/my-app' + * version: 0.0.0 + * dependencies: + * '@microsoft/load-themed-styles': 1.10.7 + * ... + * dev: false + * ``` + * + * We refer to 'file:projects/my-app.tgz_25c559a5921686293a001a397be4dce0' or 'file:projects/my-app.tgz' as + * the temp project dependency key of the temp project '@rush-temp/my-app'. + */ + public getTempProjectDependencyKey(tempProjectName: string): string | undefined { + const tempProjectDependencyKey: IPnpmVersionSpecifier | undefined = + this.dependencies.get(tempProjectName); + return tempProjectDependencyKey ? normalizePnpmVersionSpecifier(tempProjectDependencyKey) : undefined; + } + + public getShrinkwrapEntryFromTempProjectDependencyKey( + tempProjectDependencyKey: string + ): IPnpmShrinkwrapDependencyYaml | undefined { + return this.packages.get(tempProjectDependencyKey); + } + + public getShrinkwrapEntry( + name: string, + version: IPnpmVersionSpecifier + ): IPnpmShrinkwrapDependencyYaml | undefined { + const packageId: string = this._getPackageId(name, version); + return this.packages.get(packageId); + } + + /** + * Serializes the PNPM Shrinkwrap file + * + * @override + */ + protected serialize(): string { + return this._serializeInternal(false); + } + + /** + * 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( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): DependencySpecifier | undefined { + // PNPM doesn't have the same advantage of NPM, where we can skip generate as long as the + // shrinkwrap file puts our dependency in either the top of the node_modules folder + // or underneath the package we are looking at. + // This is because the PNPM shrinkwrap file describes the exact links that need to be created + // to recreate the graph.. + // Because of this, we actually need to check for a version that this package is directly + // linked to. + + const packageName: string = dependencySpecifier.packageName; + + const tempProjectDependencyKey: string | undefined = this.getTempProjectDependencyKey(tempProjectName); + if (!tempProjectDependencyKey) { + return undefined; + } + + const packageDescription: IPnpmShrinkwrapDependencyYaml | undefined = + this._getPackageDescription(tempProjectDependencyKey); + if ( + !packageDescription || + !packageDescription.dependencies || + !packageDescription.dependencies.hasOwnProperty(packageName) + ) { + return undefined; + } + + const dependencyKey: IPnpmVersionSpecifier = packageDescription.dependencies[packageName]; + return this._parsePnpmDependencyKey(packageName, dependencyKey); + } + + /** @override */ + public findOrphanedProjects( + rushConfiguration: RushConfiguration, + subspace: Subspace + ): ReadonlyArray { + // The base shrinkwrap handles orphaned projects the same across all package managers, + // but this is only valid for non-workspace installs + if (!this.isWorkspaceCompatible) { + 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()) { + 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 { + return new PnpmProjectShrinkwrapFile(this, project); + } + + public *getImporterKeys(): Iterable { + // Filter out the root importer used for the generated package.json in the root + // of the install, since we do not use this. + for (const key of this.importers.keys()) { + if (key !== '.') { + yield key; + } + } + } + + public getImporterKeyByPath(workspaceRoot: string, projectFolder: string): string { + return Path.convertToSlashes(path.relative(workspaceRoot, projectFolder)); + } + + public getImporter(importerKey: string): IPnpmShrinkwrapImporterYaml | undefined { + return this.importers.get(importerKey); + } + + public getIntegrityForImporter(importerKey: string): Map | undefined { + // This logic formerly lived in PnpmProjectShrinkwrapFile. Moving it here allows caching of the external + // dependency integrity relationships across projects + let integrityMap: Map | undefined = this._integrities.get(importerKey); + if (!integrityMap) { + const importer: IPnpmShrinkwrapImporterYaml | undefined = this.getImporter(importerKey); + if (importer) { + integrityMap = new Map(); + this._integrities.set(importerKey, integrityMap); + + const sha256Digest: string = crypto + .createHash('sha256') + .update(JSON.stringify(importer)) + .digest('base64'); + const selfIntegrity: string = `${importerKey}:${sha256Digest}:`; + integrityMap.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:'); + }; + + if (dependencies) { + this._addIntegrities(integrityMap, dependencies, false, externalFilter); + } + + if (devDependencies) { + this._addIntegrities(integrityMap, devDependencies, false, externalFilter); + } + + if (optionalDependencies) { + this._addIntegrities(integrityMap, optionalDependencies, true, externalFilter); + } + } + } + + return integrityMap; + } + + /** @override */ + public async isWorkspaceProjectModifiedAsync( + project: RushConfigurationProject, + subspace: Subspace, + variant: string | undefined + ): Promise { + const importerKey: string = this.getImporterKeyByPath( + subspace.getSubspaceTempFolderPath(), + project.projectFolder + ); + + const importer: IPnpmShrinkwrapImporterYaml | undefined = this.getImporter(importerKey); + if (!importer) { + return true; + } + + // First, let's transform the package.json using the pnpmfile + const packageJson: IPackageJson = project.packageJsonEditor.saveToObject(); + + // Initialize the pnpmfile if it doesn't exist + if (!this._pnpmfileConfiguration) { + this._pnpmfileConfiguration = await PnpmfileConfiguration.initializeAsync( + project.rushConfiguration, + subspace, + variant + ); + } + + let transformedPackageJson: IPackageJson = packageJson; + + let subspacePnpmfile: IPnpmfile | undefined; + if (project.rushConfiguration.subspacesFeatureEnabled) { + // Get the pnpmfile + const subspacePnpmfilePath: string = path.join( + subspace.getSubspaceTempFolderPath(), + RushConstants.pnpmfileGlobalFilename + ); + + if (await FileSystem.existsAsync(subspacePnpmfilePath)) { + try { + subspacePnpmfile = require(subspacePnpmfilePath); + } catch (err) { + if (err instanceof SyntaxError) { + // eslint-disable-next-line no-console + console.error( + Colorize.red( + `A syntax error in the ${RushConstants.pnpmfileV6Filename} at ${subspacePnpmfilePath}\n` + ) + ); + } else { + // eslint-disable-next-line no-console + console.error( + Colorize.red( + `Error during pnpmfile execution. pnpmfile: "${subspacePnpmfilePath}". Error: "${err.message}".` + + '\n' + ) + ); + } + } + } + + if (subspacePnpmfile) { + const individualContext: IPnpmfileContext = { + log: (message: string) => { + // eslint-disable-next-line no-console + console.log(message); + } + }; + try { + transformedPackageJson = + subspacePnpmfile.hooks?.readPackage?.(transformedPackageJson, individualContext) || + transformedPackageJson; + } catch (err) { + // eslint-disable-next-line no-console + console.error( + Colorize.red( + `Error during readPackage hook execution. pnpmfile: "${subspacePnpmfilePath}". Error: "${err.message}".` + + '\n' + ) + ); + } + } + } + + // Use a new PackageJsonEditor since it will classify each dependency type, making tracking the + // found versions much simpler. + const { dependencyList, devDependencyList, dependencyMetaList } = PackageJsonEditor.fromObject( + this._pnpmfileConfiguration.transform(transformedPackageJson), + project.packageJsonEditor.filePath + ); + + const allDependencies: PackageJsonDependency[] = [...dependencyList, ...devDependencyList]; + + if (this.shrinkwrapFileMajorVersion < ShrinkwrapFileMajorVersion.V6) { + // PNPM <= v7 + + // Then get the unique package names and map them to package versions. + const dependencyVersions: Map = new Map(); + for (const packageDependency of allDependencies) { + // We will also filter out peer dependencies since these are not installed at development time. + if (packageDependency.dependencyType === DependencyType.Peer) { + continue; + } + + const foundDependency: PackageJsonDependency | undefined = dependencyVersions.get( + packageDependency.name + ); + if (!foundDependency) { + dependencyVersions.set(packageDependency.name, packageDependency); + } else { + // Shrinkwrap will prioritize optional dependencies, followed by regular dependencies, with dev being + // the least prioritized. We will only keep the most prioritized option. + // See: https://github.com/pnpm/pnpm/blob/main/packages/lockfile-utils/src/satisfiesPackageManifest.ts + switch (foundDependency.dependencyType) { + case DependencyType.Optional: + break; + case DependencyType.Regular: + if (packageDependency.dependencyType === DependencyType.Optional) { + dependencyVersions.set(packageDependency.name, packageDependency); + } + break; + case DependencyType.Dev: + dependencyVersions.set(packageDependency.name, packageDependency); + break; + } + } + } + + // Then validate that the dependency fields are as expected in the shrinkwrap to avoid false-negatives + // when moving a package from one field to the other. + for (const { dependencyType, name } of dependencyVersions.values()) { + switch (dependencyType) { + case DependencyType.Optional: + if (!importer.optionalDependencies?.[name]) return true; + break; + case DependencyType.Regular: + if (!importer.dependencies?.[name]) return true; + break; + case DependencyType.Dev: + if (!importer.devDependencies?.[name]) return true; + break; + } + } + + const specifiers: Record | undefined = importer.specifiers; + if (!specifiers) { + throw new InternalError('Expected specifiers to be defined, but is expected in lockfile version 5'); + } + + // Then validate the length matches between the importer and the dependency list, since duplicates are + // a valid use-case. Importers will only take one of these values, so no need to do more work here. + if (dependencyVersions.size !== Object.keys(specifiers).length) { + return true; + } + + // Finally, validate that all values in the importer are also present in the dependency list. + for (const [importerPackageName, importerVersionSpecifier] of Object.entries(specifiers)) { + const foundDependency: PackageJsonDependency | undefined = + dependencyVersions.get(importerPackageName); + if (!foundDependency) { + return true; + } + const resolvedVersion: string = this.overrides.get(importerPackageName) ?? foundDependency.version; + if (resolvedVersion !== importerVersionSpecifier) { + return true; + } + } + } else { + // >= PNPM v8 + const importerOptionalDependencies: Set = new Set( + Object.keys(importer.optionalDependencies ?? {}) + ); + const importerDependencies: Set = new Set(Object.keys(importer.dependencies ?? {})); + const importerDevDependencies: Set = new Set(Object.keys(importer.devDependencies ?? {})); + const importerDependenciesMeta: Set = new Set(Object.keys(importer.dependenciesMeta ?? {})); + + for (const { dependencyType, name, version } of allDependencies) { + let isOptional: boolean = false; + let specifierFromLockfile: IPnpmVersionSpecifier | undefined; + let isDevDepFallThrough: boolean = false; + switch (dependencyType) { + case DependencyType.Optional: { + specifierFromLockfile = importer.optionalDependencies?.[name]; + importerOptionalDependencies.delete(name); + break; + } + + case DependencyType.Peer: { + // Peer dependencies of workspace projects may be installed as regular dependencies + isOptional = true; // fall through + } + + case DependencyType.Dev: { + specifierFromLockfile = importer.devDependencies?.[name]; + if (specifierFromLockfile) { + // If the dev dependency is not found, it may be installed as a regular dependency, + // so fall through + importerDevDependencies.delete(name); + break; + } + // If fall through, there is a chance the package declares an inconsistent version, ignore it. + isDevDepFallThrough = true; + } + + // eslint-disable-next-line no-fallthrough + case DependencyType.Regular: + specifierFromLockfile = importer.dependencies?.[name]; + importerDependencies.delete(name); + break; + } + + if (!specifierFromLockfile) { + if (!isOptional) { + return true; + } + } else { + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + // TODO: Emit an error message when someone tries to override a version of something in one of their + // local repo packages. + 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); + const specifier: string = importer.specifiers[name]; + if (specifier !== resolvedVersion && !isDevDepFallThrough && !isOptional) { + return true; + } + } else { + if (typeof specifierFromLockfile === 'string') { + throw new Error( + `The PNPM lockfile is in an unexpected format. The "${name}" package is specified as ` + + `"${specifierFromLockfile}" instead of an object.` + ); + } else { + // TODO: Emit an error message when someone tries to override a version of something in one of their + // local repo packages. + 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 + ) { + return true; + } + } + } + } + } + + for (const { name, injected } of dependencyMetaList) { + if (importer.dependenciesMeta?.[name]?.injected === injected) { + importerDependenciesMeta.delete(name); + } + } + + // Finally, validate that all values in the importer are also present in the dependency list. + if ( + importerOptionalDependencies.size > 0 || + importerDependencies.size > 0 || + importerDevDependencies.size > 0 || + importerDependenciesMeta.size > 0 + ) { + return true; + } + } + + return false; + } + + private _getIntegrityForPackage(specifier: string, optional: boolean): Map { + const integrities: Map> = this._integrities; + + let integrityMap: Map | undefined = integrities.get(specifier); + if (integrityMap) { + return integrityMap; + } + + integrityMap = new Map(); + integrities.set(specifier, integrityMap); + + const shrinkwrapEntry: IPnpmShrinkwrapDependencyYaml | undefined = this.packages.get(specifier); + if (!shrinkwrapEntry) { + if (!optional) { + // This algorithm heeds to be robust against missing shrinkwrap entries, so we can't just throw + // Instead set it to a value which will not match any valid shrinkwrap record + integrityMap.set(specifier, 'Missing shrinkwrap entry!'); + } + + // Indicate an empty entry + return integrityMap; + } + + // 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; + + if (dependencies) { + this._addIntegrities(integrityMap, dependencies, false); + } + + if (optionalDependencies) { + this._addIntegrities(integrityMap, optionalDependencies, true); + } + + return integrityMap; + } + + private _addIntegrities( + integrityMap: Map, + collection: Record, + optional: boolean, + filter?: (name: string, version: IPnpmVersionSpecifier) => 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 contribution: Map = this._getIntegrityForPackage(packageId, optional); + for (const [dep, integrity] of contribution) { + integrityMap.set(dep, integrity); + } + } + } + + /** + * Gets the package description for a tempProject from the shrinkwrap file. + */ + private _getPackageDescription( + tempProjectDependencyKey: string + ): IPnpmShrinkwrapDependencyYaml | undefined { + const packageDescription: IPnpmShrinkwrapDependencyYaml | undefined = + this.packages.get(tempProjectDependencyKey); + + return packageDescription && packageDescription.dependencies ? packageDescription : undefined; + } + + private _getPackageId(name: string, versionSpecifier: IPnpmVersionSpecifier): string { + const version: string = normalizePnpmVersionSpecifier(versionSpecifier); + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + return PnpmShrinkwrapFile.getLockfileV9PackageId(name, version); + } else if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V6) { + if (version.startsWith('@github')) { + // This is a github repo reference + return version; + } else { + return version.startsWith('/') ? version : `/${name}@${version}`; + } + } else { + // Version can sometimes be in the form of a path that's already in the /name/version format. + return version.indexOf('/') !== -1 ? version : `/${name}/${version}`; + } + } + + private _parsePnpmDependencyKey( + dependencyName: string, + pnpmDependencyKey: IPnpmVersionSpecifier + ): DependencySpecifier | undefined { + if (pnpmDependencyKey) { + const result: DependencySpecifier | undefined = + this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 + ? parsePnpm9DependencyKey(dependencyName, pnpmDependencyKey) + : parsePnpmDependencyKey(dependencyName, pnpmDependencyKey); + + if (!result) { + throw new Error( + `Cannot parse PNPM shrinkwrap version specifier: "${pnpmDependencyKey}"` + + ` for "${dependencyName}"` + ); + } + + return result; + } else { + return undefined; + } + } + + private _serializeInternal(omitImporters: boolean = false): string { + // Ensure that if any of the top-level properties are provided but empty are removed. We populate the object + // properties when we read the shrinkwrap but PNPM does not set these top-level properties unless they are present. + const shrinkwrapToSerialize: { [key: string]: unknown } = {}; + for (const [key, value] of Object.entries(this._shrinkwrapJson)) { + if (omitImporters && key === 'importers') { + continue; + } + + if (!value || typeof value !== 'object' || Object.keys(value).length > 0) { + shrinkwrapToSerialize[key] = value; + } + } + + 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 new file mode 100644 index 00000000000..f2d86e24dc5 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.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 * as path from 'node:path'; + +import { Sort, Import, Path } from '@rushstack/node-core-library'; + +import { BaseWorkspaceFile } from '../base/BaseWorkspaceFile'; +import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon'; + +const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); + +const globEscape: (unescaped: string) => string = require('glob-escape'); // No @types/glob-escape package exists + +/** + * This interface represents the raw pnpm-workspace.YAML file + * Example: + * { + * "packages": [ + * "../../apps/project1" + * ], + * "catalogs": { + * "default": { + * "react": "^18.0.0" + * } + * } + * } + */ +interface IPnpmWorkspaceYaml { + /** The list of local package directories */ + packages: string[]; + /** Catalog definitions for centralized version management */ + catalogs?: Record>; +} + +export class PnpmWorkspaceFile extends BaseWorkspaceFile { + /** + * The filename of the workspace file. + */ + public readonly workspaceFilename: string; + + private _workspacePackages: Set; + private _catalogs: Record> | undefined; + + /** + * The PNPM workspace file is used to specify the location of workspaces relative to the root + * of your PNPM install. + */ + public constructor(workspaceYamlFilename: string) { + super(); + + this.workspaceFilename = workspaceYamlFilename; + // Ignore any existing file since this file is generated and we need to handle deleting packages + // If we need to support manual customization, that should be an additional parameter for "base file" + this._workspacePackages = new Set(); + this._catalogs = undefined; + } + + /** + * Sets the catalog definitions for the workspace. + * @param catalogs - A map of catalog name to package versions + */ + public setCatalogs(catalogs: Record> | undefined): void { + this._catalogs = catalogs; + } + + /** @override */ + public 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); + } + + // Glob can't handle Windows paths + const globPath: string = Path.convertToSlashes(packagePath); + this._workspacePackages.add(globEscape(globPath)); + } + + /** @override */ + protected serialize(): string { + // Ensure stable sort order when serializing + Sort.sortSet(this._workspacePackages); + + const workspaceYaml: IPnpmWorkspaceYaml = { + packages: Array.from(this._workspacePackages) + }; + + if (this._catalogs && Object.keys(this._catalogs).length > 0) { + workspaceYaml.catalogs = this._catalogs; + } + + return yamlModule.dump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT); + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmYamlCommon.ts b/libraries/rush-lib/src/logic/pnpm/PnpmYamlCommon.ts new file mode 100644 index 00000000000..2df1433f98b --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmYamlCommon.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 interface IYamlDumpOptions { + lineWidth: number; + noCompatMode: boolean; + noRefs: boolean; + sortKeys: boolean; +} + +// This is based on PNPM's own configuration: +// https://github.com/pnpm/pnpm-shrinkwrap/blob/master/src/write.ts +export const PNPM_SHRINKWRAP_YAML_FORMAT: IYamlDumpOptions = { + lineWidth: 1000, + noCompatMode: true, + noRefs: true, + sortKeys: true +}; diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts new file mode 100644 index 00000000000..de73e3a5cc9 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts @@ -0,0 +1,147 @@ +// 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 { FileSystem, Import, type IPackageJson, JsonFile, MapExtensions } from '@rushstack/node-core-library'; + +import type { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +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'; + +/** + * Loads PNPM's pnpmfile.js configuration, and invokes it to preprocess package.json files, + * optionally utilizing a pnpmfile shim to inject preferred versions. + */ +export class PnpmfileConfiguration { + private _context: IPnpmfileContext | undefined; + + private constructor(context: IPnpmfileContext) { + pnpmfile.reset(); + this._context = context; + } + + public static async initializeAsync( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined + ): Promise { + if (rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + `PnpmfileConfiguration cannot be used with package manager "${rushConfiguration.packageManager}"` + ); + } + + // Set the context to swallow log output and store our settings + const context: IPnpmfileContext = { + log: (message: string) => {}, + pnpmfileShimSettings: await PnpmfileConfiguration._getPnpmfileShimSettingsAsync( + rushConfiguration, + subspace, + variant + ) + }; + + return new PnpmfileConfiguration(context); + } + + public static async writeCommonTempPnpmfileShimAsync( + rushConfiguration: RushConfiguration, + targetDir: string, + subspace: Subspace, + variant: string | undefined + ): Promise { + if (rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + `PnpmfileConfiguration cannot be used with package manager "${rushConfiguration.packageManager}"` + ); + } + + const pnpmfilePath: string = path.join( + targetDir, + (rushConfiguration.packageManagerWrapper as PnpmPackageManager).pnpmfileFilename + ); + + // Write the shim itself + await FileSystem.copyFileAsync({ + sourcePath: `${scriptsFolderPath}/${pnpmfileShimFilename}`, + destinationPath: pnpmfilePath + }); + + const pnpmfileShimSettings: IPnpmfileShimSettings = + await PnpmfileConfiguration._getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant); + + // Write the settings file used by the shim + await JsonFile.saveAsync(pnpmfileShimSettings, path.join(targetDir, 'pnpmfileSettings.json'), { + ensureFolderExists: true + }); + } + + 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. + */ + public transform(packageJson: IPackageJson): IPackageJson { + if (!pnpmfile.hooks?.readPackage || !this._context) { + return packageJson; + } else { + return pnpmfile.hooks.readPackage(packageJson, this._context); + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts new file mode 100644 index 00000000000..924ce92c7eb --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// The "rush install" or "rush update" commands will copy this template to +// "common/temp/" so that it can implement Rush-specific features such as +// implicitly preferred versions. 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. + +// 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'; +import type { IPnpmfile, IPnpmfileShimSettings, IPnpmfileContext, IPnpmfileHooks } from './IPnpmfile'; + +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; +} + +// Initialize all external aspects of the pnpmfile shim. When using the shim, settings +// are always expected to be available. Init must be called before running any hook that +// depends on a resource obtained from or related to the settings, and will require modules +// once so they aren't repeatedly required in the hook functions. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function init(context: IPnpmfileContext | any): IPnpmfileContext { + // Sometimes PNPM may provide us a context arg that doesn't fit spec, ex.: + // https://github.com/pnpm/pnpm/blob/97c64bae4d14a8c8f05803f1d94075ee29c2df2f/packages/get-context/src/index.ts#L134 + // So we need to normalize the context format before we move on + if (typeof context !== 'object' || Array.isArray(context)) { + context = { + log: (message: string) => {}, + originalContext: context + } as IPnpmfileContext; + } + if (!settings) { + // Initialize the settings from file + if (!context.pnpmfileShimSettings) { + context.pnpmfileShimSettings = __non_webpack_require__('./pnpmfileSettings.json'); + } + settings = context.pnpmfileShimSettings as IPnpmfileShimSettings; + } else if (!context.pnpmfileShimSettings) { + // Reuse the already initialized settings + context.pnpmfileShimSettings = settings; + } + if (!allPreferredVersions && settings.allPreferredVersions) { + allPreferredVersions = new Map(Object.entries(settings.allPreferredVersions)); + rangeParseCache = new Map(); + } + if (!allowedAlternativeVersions && settings.allowedAlternativeVersions) { + allowedAlternativeVersions = new Map( + Object.entries(settings.allowedAlternativeVersions).map(([packageName, versions]) => { + return [packageName, new Set(versions)]; + }) + ); + } + 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); + } + // If a semverPath is provided, we expect it to exist + if (!semver && settings.semverPath) { + semver = require(settings.semverPath); + } + // Return the normalized context + 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 { + 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)) { + const preferredVersionRange: TSemver.Range | false = parseRange(preferredVersion); + if (!preferredVersionRange) { + return; + } + + const versionRange: TSemver.Range | false = parseRange(version); + if (!versionRange) { + return; + } + + 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?.(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); + 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 pkg; + }, + + // Call the original pnpmfile (if it exists) + filterLog: userPnpmfile?.hooks?.filterLog +}; diff --git a/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts b/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts new file mode 100644 index 00000000000..02c143fcb31 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// The "rush install" or "rush update" commands will copy this template to +// "common/temp-split/global-pnpmfile.js" so that it can implement Rush-specific features. +// 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 '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 { + IPnpmfile, + IPnpmfileContext, + IPnpmfileHooks, + ISubspacePnpmfileShimSettings, + IWorkspaceProjectInfo +} from './IPnpmfile'; +import type { IPnpmShrinkwrapYaml } from './PnpmShrinkwrapFile'; + +let settings: ISubspacePnpmfileShimSettings; +let userPnpmfile: IPnpmfile | undefined; +let semver: typeof TSemver | undefined; + +// Initialize all external aspects of the pnpmfile shim. When using the shim, settings +// are always expected to be available. Init must be called before running any hook that +// depends on a resource obtained from or related to the settings, and will require modules +// once so they aren't repeatedly required in the hook functions. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function init(context: IPnpmfileContext | any): IPnpmfileContext { + // Sometimes PNPM may provide us a context arg that doesn't fit spec, ex.: + // https://github.com/pnpm/pnpm/blob/97c64bae4d14a8c8f05803f1d94075ee29c2df2f/packages/get-context/src/index.ts#L134 + // So we need to normalize the context format before we move on + if (typeof context !== 'object' || Array.isArray(context)) { + context = { + log: (message: string) => {}, + originalContext: context + } as IPnpmfileContext; + } + if (!settings) { + // Initialize the settings from file + if (!context.splitWorkspacePnpmfileShimSettings) { + context.splitWorkspacePnpmfileShimSettings = __non_webpack_require__('./pnpmfileSettings.json'); + } + settings = context.splitWorkspacePnpmfileShimSettings!; + } else if (!context.splitWorkspacePnpmfileShimSettings) { + // Reuse the already initialized settings + context.splitWorkspacePnpmfileShimSettings = settings; + } + // If a userPnpmfilePath is provided, we expect it to exist + if (!userPnpmfile && settings.userPnpmfilePath) { + userPnpmfile = require(settings.userPnpmfilePath); + } + // If a semverPath is provided, we expect it to exist + if (!semver && settings.semverPath) { + semver = require(settings.semverPath); + } + // Return the normalized context + return context as IPnpmfileContext; +} + +// Rewrite rush project referenced in split workspace. +// For example: "project-a": "workspace:*" --> "project-a": "link:../../project-a" +function rewriteRushProjectVersions( + packageName: string, + dependencies: { [dependencyName: string]: string } | undefined +): void { + if (!dependencies) { + return; + } + + if (!settings) { + throw new Error(`splitWorkspaceGlobalPnpmfileShimSettings not initialized`); + } + + const workspaceProject: IWorkspaceProjectInfo | undefined = + settings.subspaceProjects[packageName] || settings.workspaceProjects[packageName]; + if (!workspaceProject) { + return; + } + + for (const dependencyName of Object.keys(dependencies)) { + const currentVersion: string = dependencies[dependencyName]; + + if (currentVersion.startsWith('workspace:')) { + const workspaceProjectInfo: IWorkspaceProjectInfo | undefined = + settings.workspaceProjects[dependencyName]; + if (workspaceProjectInfo) { + // Case 1. "": "workspace:*" + let workspaceVersionProtocol: string = 'link:'; + + const injectedDependenciesSet: ReadonlySet = new Set(workspaceProject.injectedDependencies); + if (injectedDependenciesSet.has(dependencyName)) { + workspaceVersionProtocol = 'file:'; + } + let relativePath: string = path.normalize( + path.relative(workspaceProject.projectRelativeFolder, workspaceProjectInfo.projectRelativeFolder) + ); + // convert path in posix style, otherwise pnpm install will fail in subspace case + relativePath = relativePath.split(path.sep).join(path.posix.sep); + const newVersion: string = workspaceVersionProtocol + relativePath; + dependencies[dependencyName] = newVersion; + } else { + // Case 2. "": "workspace:@" + const packageSpec: string = currentVersion.slice('workspace:'.length); + const nameEndsAt: number = + packageSpec[0] === '@' ? packageSpec.slice(1).indexOf('@') + 1 : packageSpec.indexOf('@'); + const aliasedPackageName: string = nameEndsAt > 0 ? packageSpec.slice(0, nameEndsAt) : packageSpec; + // const depVersion: string = nameEndsAt > 0 ? packageSpec.slice(nameEndsAt + 1) : ''; + const aliasedWorkspaceProjectInfo: IWorkspaceProjectInfo | undefined = + settings.workspaceProjects[aliasedPackageName]; + if (aliasedWorkspaceProjectInfo) { + const relativePath: string = path.normalize( + path.relative( + workspaceProject.projectRelativeFolder, + aliasedWorkspaceProjectInfo.projectRelativeFolder + ) + ); + const newVersion: string = 'link:' + relativePath; + dependencies[dependencyName] = newVersion; + } + } + } else if (currentVersion.startsWith('npm:')) { + // Case 3. "": "npm:@" + const packageSpec: string = currentVersion.slice('npm:'.length); + const nameEndsAt: number = + packageSpec[0] === '@' ? packageSpec.slice(1).indexOf('@') + 1 : packageSpec.indexOf('@'); + const aliasedPackageName: string = nameEndsAt > 0 ? packageSpec.slice(0, nameEndsAt) : packageSpec; + // const depVersion: string = nameEndsAt > 0 ? packageSpec.slice(nameEndsAt + 1) : ''; + const aliasedWorkspaceProjectInfo: IWorkspaceProjectInfo | undefined = + settings.workspaceProjects[aliasedPackageName]; + if (aliasedWorkspaceProjectInfo) { + const relativePath: string = path.normalize( + path.relative( + workspaceProject.projectRelativeFolder, + aliasedWorkspaceProjectInfo.projectRelativeFolder + ) + ); + const newVersion: string = 'link:' + relativePath; + dependencies[dependencyName] = newVersion; + } + } + } +} + +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; + }, + + // Rewrite workspace protocol to link protocol for non split workspace projects + readPackage: (pkg: IPackageJson, context: IPnpmfileContext) => { + context = init(context); + rewriteRushProjectVersions(pkg.name, pkg.dependencies); + rewriteRushProjectVersions(pkg.name, pkg.devDependencies); + return userPnpmfile?.hooks?.readPackage ? userPnpmfile.hooks.readPackage(pkg, context) : pkg; + }, + + // Call the original pnpmfile (if it exists) + filterLog: userPnpmfile?.hooks?.filterLog +}; diff --git a/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts new file mode 100644 index 00000000000..6493ea0fa66 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.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 * as path from 'node:path'; + +import { FileSystem, Import, JsonFile, type IDependenciesMetaTable } from '@rushstack/node-core-library'; + +import { subspacePnpmfileShimFilename, scriptsFolderPath } from '../../utilities/PathConstants'; +import type { ISubspacePnpmfileShimSettings, IWorkspaceProjectInfo } from './IPnpmfile'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager'; +import { RushConstants } from '../RushConstants'; +import type { Subspace } from '../../api/Subspace'; +import type { PnpmOptionsConfiguration } from './PnpmOptionsConfiguration'; + +/** + * Loads PNPM's pnpmfile.js configuration, and invokes it to preprocess package.json files, + * optionally utilizing a pnpmfile shim to inject preferred versions. + */ +export class SubspacePnpmfileConfiguration { + /** + * Split workspace use global pnpmfile, because in split workspace, user may set `shared-workspace-lockfile=false`. + * That means each project owns their individual pnpmfile under project folder. While the global pnpmfile could be + * under the common/temp-split/ folder and be used by all split workspace projects. + */ + public static async writeCommonTempSubspaceGlobalPnpmfileAsync( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined + ): Promise { + if (rushConfiguration.packageManager !== 'pnpm') { + throw new Error( + `PnpmfileConfiguration cannot be used with package manager "${rushConfiguration.packageManager}"` + ); + } + + const targetDir: string = subspace.getSubspaceTempFolderPath(); + const subspaceGlobalPnpmfilePath: string = path.join(targetDir, RushConstants.pnpmfileGlobalFilename); + + // Write the shim itself + await FileSystem.copyFileAsync({ + sourcePath: `${scriptsFolderPath}/${subspacePnpmfileShimFilename}`, + destinationPath: subspaceGlobalPnpmfilePath + }); + + const subspaceGlobalPnpmfileShimSettings: ISubspacePnpmfileShimSettings = + SubspacePnpmfileConfiguration.getSubspacePnpmfileShimSettings(rushConfiguration, subspace, variant); + + // Write the settings file used by the shim + await JsonFile.saveAsync( + subspaceGlobalPnpmfileShimSettings, + path.join(targetDir, 'pnpmfileSettings.json'), + { + ensureFolderExists: true + } + ); + } + + public static getSubspacePnpmfileShimSettings( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined + ): ISubspacePnpmfileShimSettings { + const workspaceProjects: Record = {}; + const subspaceProjects: Record = {}; + + const projectNameToInjectedDependenciesMap: Map< + string, + Set + > = SubspacePnpmfileConfiguration._getProjectNameToInjectedDependenciesMap(rushConfiguration, subspace); + for (const project of rushConfiguration.projects) { + const { packageName, projectRelativeFolder, packageJson } = project; + const workspaceProjectInfo: IWorkspaceProjectInfo = { + packageName, + projectRelativeFolder, + packageVersion: packageJson.version, + injectedDependencies: Array.from(projectNameToInjectedDependenciesMap.get(packageName) || []) + }; + (subspace.contains(project) ? subspaceProjects : workspaceProjects)[packageName] = workspaceProjectInfo; + } + + const settings: ISubspacePnpmfileShimSettings = { + workspaceProjects, + subspaceProjects, + semverPath: Import.resolveModule({ modulePath: 'semver', baseFolderPath: __dirname }) + }; + + // common/config/subspaces//.pnpmfile.cjs + const userPnpmfilePath: string = path.join( + subspace.getVariantDependentSubspaceConfigFolderPath(variant), + (rushConfiguration.packageManagerWrapper as PnpmPackageManager).pnpmfileFilename + ); + if (FileSystem.exists(userPnpmfilePath)) { + settings.userPnpmfilePath = userPnpmfilePath; + } + + 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()); + } + + 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)!); + } + } + } + } + + // 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)!); + } + } + } + } + + // 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 + ); + } + } + } + + return projectNameToInjectedDependenciesMap; + } + + 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); + } + } + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts new file mode 100644 index 00000000000..c590ca689fe --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.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 path from 'node:path'; +import { PnpmOptionsConfiguration } from '../PnpmOptionsConfiguration'; +import { TestUtilities } from '@rushstack/heft-config-file'; + +const fakeCommonTempFolder: string = path.join(__dirname, 'common', 'temp'); + +describe(PnpmOptionsConfiguration.name, () => { + it('throw error if pnpm-config.json does not exist', () => { + expect(() => { + PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/pnpm-config-not-exist.json`, + fakeCommonTempFolder + ); + }).toThrow(/does not exist/); + }); + + it('validates unknown property', () => { + expect(() => + PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-unknown.json`, + fakeCommonTempFolder + ) + ).toThrow(/must NOT have additional properties/); + }); + + it('loads overrides', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-overrides.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalOverrides)).toEqual({ + foo: '^1.0.0', + quux: 'npm:@myorg/quux@^1.0.0', + 'bar@^2.1.0': '3.0.0', + 'qar@1>zoo': '2' + }); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.environmentVariables)).toEqual({ + NODE_OPTIONS: { + value: '--max-old-space-size=4096', + override: false + } + }); + }); + + it('loads packageExtensions', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-packageExtensions.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalPackageExtensions)).toEqual({ + 'react-redux': { + peerDependencies: { + 'react-dom': '*' + } + } + }); + }); + + it('loads neverBuiltDependencies', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-neverBuiltDependencies.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalNeverBuiltDependencies)).toEqual([ + 'fsevents', + 'level' + ]); + }); + + it('loads minimumReleaseAge', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge.json`, + fakeCommonTempFolder + ); + + expect(pnpmConfiguration.minimumReleaseAge).toEqual(1440); + expect(TestUtilities.stripAnnotations(pnpmConfiguration.minimumReleaseAgeExclude)).toEqual([ + 'webpack', + '@myorg/*' + ]); + }); + + 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' + } + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts new file mode 100644 index 00000000000..912bbc55b7a --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.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 type { LockfileFileV9, PackageSnapshot, ProjectSnapshot } from '@pnpm/lockfile.types'; +import { convertLockfileV9ToLockfileObject } from '../PnpmShrinkWrapFileConverters'; +import { FileSystem } from '@rushstack/node-core-library'; +import yamlModule from 'js-yaml'; + +describe(convertLockfileV9ToLockfileObject.name, () => { + const lockfileContent: string = FileSystem.readFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml` + ); + const lockfileJson: LockfileFileV9 = yamlModule.load(lockfileContent) as LockfileFileV9; + const lockfile = convertLockfileV9ToLockfileObject(lockfileJson); + + it('merge packages and snapshots', () => { + const packages = new Map(Object.entries(lockfile.packages || {})); + const padLeftPackage = packages.get('pad-left@2.1.0'); + expect(padLeftPackage).toBeDefined(); + expect(padLeftPackage?.dependencies).toEqual({ + 'repeat-string': '1.6.1' + }); + }); + + it("importers['.']", () => { + const importers = new Map(Object.entries(lockfile.importers || {})); + + const currentPackage = importers.get('.'); + expect(currentPackage).toBeDefined(); + + expect(currentPackage?.dependencies).toEqual({ + jquery: '3.7.1', + 'pad-left': '2.1.0' + }); + + expect(currentPackage?.specifiers).toEqual({ + jquery: '^3.7.1', + '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 new file mode 100644 index 00000000000..2ef3bc58304 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts @@ -0,0 +1,500 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type DependencySpecifier, DependencySpecifierType } from '../../DependencySpecifier'; +import { PnpmShrinkwrapFile, parsePnpm9DependencyKey, parsePnpmDependencyKey } from '../PnpmShrinkwrapFile'; +import { RushConfiguration } from '../../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; + +const DEPENDENCY_NAME: string = 'dependency_name'; +const SCOPED_DEPENDENCY_NAME: string = '@scope/dependency_name'; +const VERSION: string = '1.4.0'; +const PRERELEASE_VERSION: string = '1.4.0-prerelease.0'; + +describe(PnpmShrinkwrapFile.name, () => { + describe(parsePnpmDependencyKey.name, () => { + it('Does not support file:// specifiers', () => { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( + DEPENDENCY_NAME, + 'file:///path/to/file' + ); + expect(parsedSpecifier).toBeUndefined(); + }); + + it('Supports a variety of non-aliased package specifiers', () => { + function testSpecifiers(specifiers: string[], expectedName: string, expectedVersion: string): void { + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( + expectedName, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Version); + expect(parsedSpecifier!.packageName).toBe(expectedName); + expect(parsedSpecifier!.versionSpecifier).toBe(expectedVersion); + } + } + + // non-scoped, non-prerelease + testSpecifiers( + [ + `path.pkgs.visualstudio.com/${DEPENDENCY_NAME}/${VERSION}`, + `/${DEPENDENCY_NAME}/${VERSION}`, + `/${DEPENDENCY_NAME}/${VERSION}/peer1@3.5.0+peer2@1.17.7` + ], + DEPENDENCY_NAME, + VERSION + ); + + // scoped, non-prerelease + testSpecifiers( + [ + `path.pkgs.visualstudio.com/${SCOPED_DEPENDENCY_NAME}/${VERSION}`, + `/${SCOPED_DEPENDENCY_NAME}/${VERSION}`, + `/${SCOPED_DEPENDENCY_NAME}/${VERSION}/peer1@3.5.0+peer2@1.17.7` + ], + SCOPED_DEPENDENCY_NAME, + VERSION + ); + + // non-scoped, prerelease + testSpecifiers( + [ + `path.pkgs.visualstudio.com/${DEPENDENCY_NAME}/${PRERELEASE_VERSION}`, + `/${DEPENDENCY_NAME}/${PRERELEASE_VERSION}`, + `/${DEPENDENCY_NAME}/${PRERELEASE_VERSION}/peer1@3.5.0+peer2@1.17.7` + ], + DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + + // scoped, prerelease + testSpecifiers( + [ + `path.pkgs.visualstudio.com/${SCOPED_DEPENDENCY_NAME}/${PRERELEASE_VERSION}`, + `/${SCOPED_DEPENDENCY_NAME}/${PRERELEASE_VERSION}`, + `/${SCOPED_DEPENDENCY_NAME}/${PRERELEASE_VERSION}/peer1@3.5.0+peer2@1.17.7` + ], + SCOPED_DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + }); + + it('Supports aliased package specifiers (v5)', () => { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( + SCOPED_DEPENDENCY_NAME, + `/${DEPENDENCY_NAME}/${VERSION}` + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Alias); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toMatchInlineSnapshot(`"npm:${DEPENDENCY_NAME}@${VERSION}"`); + }); + + it('Supports aliased package specifiers (v6)', () => { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( + SCOPED_DEPENDENCY_NAME, + `/${DEPENDENCY_NAME}@${VERSION}` + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Alias); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toMatchInlineSnapshot(`"npm:${DEPENDENCY_NAME}@${VERSION}"`); + }); + + it('Supports URL package specifiers', () => { + const specifiers: string[] = [ + '@github.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'github.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'github.com.au/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'bitbucket.com/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'bitbucket.com+abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'git@bitbucket.com+abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2', + 'bitbucket.co.in/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2' + ]; + + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpmDependencyKey( + SCOPED_DEPENDENCY_NAME, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Directory); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toBe(specifier); + } + }); + }); + + describe(parsePnpm9DependencyKey.name, () => { + it('Does not support file:// specifiers', () => { + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'file:///path/to/file')).toBeUndefined(); + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'pad-left@file:///path/to/file')).toBeUndefined(); + expect(parsePnpm9DependencyKey(DEPENDENCY_NAME, 'link:///path/to/file')).toBeUndefined(); + }); + + it('Supports a variety of non-aliased package specifiers', () => { + function testSpecifiers(specifiers: string[], expectedName: string, expectedVersion: string): void { + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + expectedName, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Version); + expect(parsedSpecifier!.packageName).toBe(expectedName); + expect(parsedSpecifier!.versionSpecifier).toBe(expectedVersion); + } + } + + // non-scoped, non-prerelease + testSpecifiers( + [`${DEPENDENCY_NAME}@${VERSION}`, `${DEPENDENCY_NAME}@${VERSION}(peer@3.5.0+peer2@1.17.7)`], + DEPENDENCY_NAME, + VERSION + ); + + // scoped, non-prerelease + testSpecifiers( + [ + `${SCOPED_DEPENDENCY_NAME}@${VERSION}`, + `${SCOPED_DEPENDENCY_NAME}@${VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + SCOPED_DEPENDENCY_NAME, + VERSION + ); + + // non-scoped, prerelease + testSpecifiers( + [ + `${DEPENDENCY_NAME}@${PRERELEASE_VERSION}`, + `${DEPENDENCY_NAME}@${PRERELEASE_VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + + // scoped, prerelease + testSpecifiers( + [ + `${SCOPED_DEPENDENCY_NAME}@${PRERELEASE_VERSION}`, + `${SCOPED_DEPENDENCY_NAME}@${PRERELEASE_VERSION}(peer@3.5.0+peer2@1.17.7)` + ], + SCOPED_DEPENDENCY_NAME, + PRERELEASE_VERSION + ); + }); + + it('Supports aliased package specifiers (v9)', () => { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + SCOPED_DEPENDENCY_NAME, + `${DEPENDENCY_NAME}@${VERSION}` + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Alias); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toMatchInlineSnapshot(`"npm:${DEPENDENCY_NAME}@${VERSION}"`); + }); + + it('Supports URL package specifiers', () => { + const specifiers: string[] = [ + 'https://github.com/jonschlinkert/pad-left/tarball/2.1.0', + 'https://xxx.xxxx.org/pad-left/-/pad-left-2.1.0.tgz', + 'https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7', + `${SCOPED_DEPENDENCY_NAME}@http://abc.com/jonschlinkert/pad-left/tarball/2.1.0`, + `${SCOPED_DEPENDENCY_NAME}@https://xxx.xxxx.org/pad-left/-/pad-left-2.1.0.tgz`, + `${SCOPED_DEPENDENCY_NAME}@https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7` + ]; + + for (const specifier of specifiers) { + const parsedSpecifier: DependencySpecifier | undefined = parsePnpm9DependencyKey( + SCOPED_DEPENDENCY_NAME, + specifier + ); + expect(parsedSpecifier).toBeDefined(); + expect(parsedSpecifier!.specifierType).toBe(DependencySpecifierType.Remote); + expect(parsedSpecifier!.packageName).toBe(SCOPED_DEPENDENCY_NAME); + expect(parsedSpecifier!.versionSpecifier).toBe(specifier.replace(`${SCOPED_DEPENDENCY_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); + const shrinkwrapFile2 = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent2); + + // 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); + }); + }); + + 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` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + it('can detect modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v5/modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(true); + }); + + it('can detect overrides', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + }); + + describe('pnpm lockfile major version 6', () => { + it('can detect not modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v6/not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + it('can detect modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v6/modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(true); + }); + + it('can detect overrides', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + 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` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + }); + + describe('pnpm lockfile major version 9', () => { + it('can detect not modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + it('can detect modified', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(true); + }); + + it('can detect overrides', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + + 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` + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(false); + }); + }); + }); +}); + +function getPnpmShrinkwrapFileFromFile(filepath: string): PnpmShrinkwrapFile { + const pnpmShrinkwrapFile = PnpmShrinkwrapFile.loadFromFile(filepath); + if (!pnpmShrinkwrapFile) { + throw new Error(`Get PnpmShrinkwrapFileFromFile failed from ${filepath}`); + } + return pnpmShrinkwrapFile; +} + +function getMockRushProject(): RushConfigurationProject { + const rushFilename: string = `${__dirname}/repo/rush.json`; + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + const project = rushConfiguration.projectsByName.get('foo'); + if (!project) { + throw new Error(`Can not get project "foo"`); + } + return project; +} + +function getMockRushProject2(): RushConfigurationProject { + const rushFilename: string = `${__dirname}/repo/rush2.json`; + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + const project = rushConfiguration.projectsByName.get('bar'); + if (!project) { + throw new Error(`Can not get project "bar"`); + } + return project; +} 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..d8cdb149a88 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmWorkspaceFile.test.ts @@ -0,0 +1,183 @@ +// 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 '@rushstack/node-core-library'; +import { PnpmWorkspaceFile } from '../PnpmWorkspaceFile'; + +describe(PnpmWorkspaceFile.name, () => { + const tempDir: string = path.join(__dirname, 'temp'); + const workspaceFilePath: string = path.join(tempDir, 'pnpm-workspace.yaml'); + const projectsDir: string = path.join(tempDir, 'projects'); + + let mockWriteFile: jest.SpyInstance; + let mockReadFile: jest.SpyInstance; + let mockExists: jest.SpyInstance; + let writtenContent: string | undefined; + + beforeEach(() => { + writtenContent = undefined; + + // Mock FileSystem.writeFile to capture content instead of writing to disk + mockWriteFile = jest + .spyOn(FileSystem, 'writeFile') + .mockImplementation((filePath: string, contents: string | Buffer) => { + void filePath; // Unused parameter + writtenContent = typeof contents === 'string' ? contents : contents.toString(); + }); + + // Mock FileSystem.readFile to return the written content + mockReadFile = jest.spyOn(FileSystem, 'readFile').mockImplementation(() => { + if (writtenContent === undefined) { + throw new Error('File not found'); + } + return writtenContent; + }); + + // Mock FileSystem.exists to return true if content was written + mockExists = jest.spyOn(FileSystem, 'exists').mockImplementation(() => { + return writtenContent !== undefined; + }); + }); + + afterEach(() => { + mockWriteFile.mockRestore(); + mockReadFile.mockRestore(); + mockExists.mockRestore(); + }); + + describe('basic functionality', () => { + it('generates workspace file with packages only', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + workspaceFile.addPackage(path.join(projectsDir, 'app2')); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('escapes special characters in package paths', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, '[app-with-brackets]')); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toContain('\\[app-with-brackets\\]'); + }); + }); + + describe('catalog functionality', () => { + it('generates workspace file with default catalog only', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs({ + default: { + react: '^18.0.0', + 'react-dom': '^18.0.0', + typescript: '~5.3.0' + } + }); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('generates workspace file with named catalogs', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs({ + default: { + typescript: '~5.3.0' + }, + frontend: { + vue: '^3.4.0', + 'vue-router': '^4.2.0' + }, + backend: { + express: '^4.18.0', + fastify: '^4.26.0' + } + }); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('handles empty catalog object', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs({}); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('handles undefined catalog', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs(undefined); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('handles scoped packages in catalogs', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs({ + default: { + '@types/node': '~22.9.4', + '@types/cookies': '^0.7.7', + '@rushstack/node-core-library': '~5.0.0' + } + }); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + + it('can update catalogs after initial creation', () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(path.join(projectsDir, 'app1')); + + workspaceFile.setCatalogs({ + default: { + react: '^18.0.0' + } + }); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + // Update catalogs + workspaceFile.setCatalogs({ + default: { + react: '^18.2.0', + 'react-dom': '^18.2.0' + } + }); + + workspaceFile.save(workspaceFilePath, { onlyIfChanged: true }); + + const content: string = FileSystem.readFile(workspaceFilePath); + expect(content).toMatchSnapshot(); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmfileConfiguration.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmfileConfiguration.test.ts new file mode 100644 index 00000000000..23dafd9caf1 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmfileConfiguration.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 { RushConfiguration } from '../../../api/RushConfiguration'; +import { PnpmfileConfiguration } from '../PnpmfileConfiguration'; +import { JsonFile, type JsonObject } from '@rushstack/node-core-library'; + +describe(PnpmfileConfiguration.name, () => { + const repoPath: string = `${__dirname}/repo`; + const rushFilename: string = `${repoPath}/rush3.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + const shimPath: string = `${rushConfiguration.defaultSubspace.getSubspaceTempFolderPath()}/pnpmfileSettings.json`; + + beforeAll(async () => { + const subspace = rushConfiguration.defaultSubspace; + await PnpmfileConfiguration.writeCommonTempPnpmfileShimAsync( + rushConfiguration, + subspace.getSubspaceTempFolderPath(), + subspace, + undefined + ); + }); + + it('should use the smallest-available SemVer range (preferredVersions)', async () => { + const shimJson: JsonObject = await JsonFile.loadAsync(shimPath); + expect(shimJson.allPreferredVersions).toHaveProperty('core-js', '3.6.5'); + }); + + it('should use the smallest-available SemVer range (per-project)', async () => { + const shimJson: JsonObject = await JsonFile.loadAsync(shimPath); + expect(shimJson.allPreferredVersions).toHaveProperty('delay', '5.0.0'); + }); + + it('should override preferredVersions when per-project versions conflict', async () => { + const shimJson: JsonObject = await JsonFile.loadAsync(shimPath); + expect(shimJson.allPreferredVersions).toHaveProperty('find-up', '5.0.0'); + }); +}); 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..88be9e3823a --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmWorkspaceFile.test.ts.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +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`] = ` +"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 +" +`; 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-minimumReleaseAge.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge.json new file mode 100644 index 00000000000..54efb4b31ff --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge.json @@ -0,0 +1,4 @@ +{ + "minimumReleaseAge": 1440, + "minimumReleaseAgeExclude": ["webpack", "@myorg/*"] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-neverBuiltDependencies.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-neverBuiltDependencies.json new file mode 100644 index 00000000000..4980c60beae --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-neverBuiltDependencies.json @@ -0,0 +1,3 @@ +{ + "globalNeverBuiltDependencies": ["fsevents", "level"] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-overrides.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-overrides.json new file mode 100644 index 00000000000..19e9db78393 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-overrides.json @@ -0,0 +1,15 @@ +{ + "globalOverrides": { + "foo": "^1.0.0", + "quux": "npm:@myorg/quux@^1.0.0", + "bar@^2.1.0": "3.0.0", + "qar@1>zoo": "2" + }, + + "environmentVariables": { + "NODE_OPTIONS": { + "value": "--max-old-space-size=4096", + "override": false + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-packageExtensions.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-packageExtensions.json new file mode 100644 index 00000000000..4450a987cb6 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-packageExtensions.json @@ -0,0 +1,9 @@ +{ + "globalPackageExtensions": { + "react-redux": { + "peerDependencies": { + "react-dom": "*" + } + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-unknown.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-unknown.json new file mode 100644 index 00000000000..4c9fe020123 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-unknown.json @@ -0,0 +1,3 @@ +{ + "unknownProperty": {} +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/apps/bar/package.json b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/bar/package.json new file mode 100644 index 00000000000..0aa90dc79fe --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/bar/package.json @@ -0,0 +1,10 @@ +{ + "name": "bar", + "version": "1.0.0", + "dependencies": { + "prettier": "~2.3.0" + }, + "devDependencies": { + "prettier": "~2.7.1" + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/apps/baz/package.json b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/baz/package.json new file mode 100644 index 00000000000..524e9d4cb89 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/baz/package.json @@ -0,0 +1,9 @@ +{ + "name": "baz", + "version": "1.0.0", + "dependencies": { + "core-js": "^3.0.0", + "delay": "5.0.0", + "find-up": "*" + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/apps/foo/package.json b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/foo/package.json new file mode 100644 index 00000000000..7f2663a0bd7 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/apps/foo/package.json @@ -0,0 +1,10 @@ +{ + "name": "foo", + "version": "1.0.0", + "dependencies": { + "tslib": "~2.3.1" + }, + "devDependencies": { + "typescript": "~5.0.4" + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/common/config/rush/common-versions.json b/libraries/rush-lib/src/logic/pnpm/test/repo/common/config/rush/common-versions.json new file mode 100644 index 00000000000..30d53549184 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/common/config/rush/common-versions.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "preferredVersions": { + "core-js": "3.6.5", + "delay": "4.0.0", + "find-up": "5.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/rush.json b/libraries/rush-lib/src/logic/pnpm/test/repo/rush.json new file mode 100644 index 00000000000..406da20f28e --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/rush.json @@ -0,0 +1,13 @@ +{ + "pnpmVersion": "7.0.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "foo", + "projectFolder": "apps/foo" + } + ] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/rush2.json b/libraries/rush-lib/src/logic/pnpm/test/repo/rush2.json new file mode 100644 index 00000000000..4a7bc3d2854 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/rush2.json @@ -0,0 +1,13 @@ +{ + "pnpmVersion": "7.0.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "bar", + "projectFolder": "apps/bar" + } + ] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/repo/rush3.json b/libraries/rush-lib/src/logic/pnpm/test/repo/rush3.json new file mode 100644 index 00000000000..d5b3a4e1d82 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/repo/rush3.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + "pnpmVersion": "7.0.0", + "rushVersion": "5.46.1", + "projects": [ + { + "packageName": "baz", + "projectFolder": "apps/baz" + } + ], + "pnpmOptions": { + "useWorkspaces": true + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/modified.yaml new file mode 100644 index 00000000000..42479b27eec --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/modified.yaml @@ -0,0 +1,29 @@ +lockfileVersion: 5.3 + +importers: + .: + specifiers: {} + + ../../apps/foo: + specifiers: + tslib: ~2.0.0 + typescript: ~5.0.4 + dependencies: + tslib: 2.3.1 + devDependencies: + typescript: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/not-modified.yaml new file mode 100644 index 00000000000..52785c178a2 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/not-modified.yaml @@ -0,0 +1,29 @@ +lockfileVersion: 5.3 + +importers: + .: + specifiers: {} + + ../../apps/foo: + specifiers: + tslib: ~2.3.1 + typescript: ~5.0.4 + dependencies: + tslib: 2.3.1 + devDependencies: + typescript: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml new file mode 100644 index 00000000000..7df12535b6b --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml @@ -0,0 +1,32 @@ +lockfileVersion: 5.3 + +overrides: + typescript: 5.0.4 + +importers: + .: + specifiers: {} + + ../../apps/foo: + specifiers: + tslib: ~2.3.1 + typescript: 5.0.4 + dependencies: + tslib: 2.3.1 + devDependencies: + typescript: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/inconsistent-dep-devDep.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/inconsistent-dep-devDep.yaml new file mode 100644 index 00000000000..87174fcac83 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/inconsistent-dep-devDep.yaml @@ -0,0 +1,20 @@ +lockfileVersion: '6.0' + +importers: + .: {} + + ../../apps/bar: + dependencies: + prettier: + specifier: ~2.3.0 + version: 2.3.0 + devDependencies: + +packages: + /prettier/2.3.0: + resolution: + { + integrity: sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w== + } + engines: { node: '>=10.13.0' } + hasBin: true diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/modified.yaml new file mode 100644 index 00000000000..e6c3cb335f9 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/modified.yaml @@ -0,0 +1,29 @@ +lockfileVersion: '6.0' + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.0.0 + version: 2.3.1 + devDependencies: + typescript: + specifier: ~5.0.4 + version: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/not-modified.yaml new file mode 100644 index 00000000000..5dc4730f9e9 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/not-modified.yaml @@ -0,0 +1,29 @@ +lockfileVersion: '6.0' + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + typescript: + specifier: ~5.0.4 + version: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml new file mode 100644 index 00000000000..67715316f32 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml @@ -0,0 +1,32 @@ +lockfileVersion: '6.0' + +overrides: + typescript: 5.0.4 + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + typescript: + specifier: 5.0.4 + version: 5.0.4 + +packages: + /typescript/5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + + /tslib/2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } 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 new file mode 100644 index 00000000000..08f6420eaf5 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml @@ -0,0 +1,26 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../apps/bar: + dependencies: + prettier: + specifier: ~2.3.0 + version: 2.3.2 + +packages: + prettier@2.3.2: + 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 new file mode 100644 index 00000000000..7f156d05a28 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml @@ -0,0 +1,38 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.0 + version: 2.3.1 + devDependencies: + 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-v9/not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml new file mode 100644 index 00000000000..f17060bc2eb --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml @@ -0,0 +1,38 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + 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-v9/overrides-not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml new file mode 100644 index 00000000000..69e66401e1e --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml @@ -0,0 +1,41 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + typescript: 5.0.4 + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + devDependencies: + 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-v9/pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml new file mode 100644 index 00000000000..91130e28c33 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml @@ -0,0 +1,45 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + jquery: + specifier: ^3.7.1 + version: 3.7.1 + pad-left: + specifier: ^2.1.0 + version: 2.1.0 + +packages: + jquery@3.7.1: + resolution: + { + integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== + } + + pad-left@2.1.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' } + +snapshots: + jquery@3.7.1: {} + + pad-left@2.1.0: + dependencies: + repeat-string: 1.6.1 + + repeat-string@1.6.1: {} 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/EnvironmentPolicy.ts b/libraries/rush-lib/src/logic/policy/EnvironmentPolicy.ts new file mode 100644 index 00000000000..3ae578f77f9 --- /dev/null +++ b/libraries/rush-lib/src/logic/policy/EnvironmentPolicy.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AlreadyReportedError, Async, FileSystem } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { IPolicyValidatorOptions } from './PolicyValidator'; +import { RushConstants } from '../RushConstants'; + +/** + * Ensures the environment where the Rush repo exists is valid + */ +export async function validateAsync( + rushConfiguration: RushConfiguration, + options: IPolicyValidatorOptions +): Promise { + if (rushConfiguration.experimentsConfiguration.configuration.forbidPhantomResolvableNodeModulesFolders) { + const pathParts: string[] = rushConfiguration.rushJsonFolder.split(/[\/\\]/); + const existingNodeModulesPaths: string[] = []; + await Async.forEachAsync( + pathParts, + async (pathPart: string, index: number) => { + const potentialNodeModulesPath: string = `${pathParts.slice(0, index + 1).join('/')}/node_modules`; + const pathExists: boolean = await FileSystem.existsAsync(potentialNodeModulesPath); + if (pathExists) { + existingNodeModulesPaths.push(potentialNodeModulesPath); + } + }, + { concurrency: 5 } + ); + + if (existingNodeModulesPaths.length > 0) { + const paths: string = existingNodeModulesPaths.sort().join(', '); + let errorMessage: string = + `The following node_modules folders exist in the path to the Rush repo: ${paths}. ` + + `This is not supported, and may cause issues.`; + if (options.bypassPolicyAllowed) { + errorMessage += ` To ignore, use the "${RushConstants.bypassPolicyFlagLongName}" flag.`; + } + + // eslint-disable-next-line no-console + console.error(errorMessage); + throw new AlreadyReportedError(); + } + } +} diff --git a/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts b/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts new file mode 100644 index 00000000000..2a58ce2328d --- /dev/null +++ b/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts @@ -0,0 +1,149 @@ +// 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 } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { Utilities } from '../../utilities/Utilities'; +import { Git } from '../Git'; +import { RushConstants } from '../RushConstants'; +import type { IPolicyValidatorOptions } from './PolicyValidator'; + +export async function validateAsync( + rushConfiguration: RushConfiguration, + options: IPolicyValidatorOptions +): Promise { + const git: Git = new Git(rushConfiguration); + + if (!git.isGitPresent()) { + // If Git isn't installed, or this Rush project is not under a Git working folder, + // then we don't care about the Git email + // eslint-disable-next-line no-console + console.log( + Colorize.cyan('Ignoring Git validation because the Git binary was not found in the shell path.') + '\n' + ); + return; + } + + if (!git.isPathUnderGitWorkingTree()) { + // If Git isn't installed, or this Rush project is not under a Git working folder, + // then we don't care about the Git email + // eslint-disable-next-line no-console + console.log(Colorize.cyan('Ignoring Git validation because this is not a Git working folder.') + '\n'); + return; + } + + let userEmail: string | undefined = await git.tryGetGitEmailAsync(); + // If there isn't a Git policy, then we don't care whether the person configured + // a Git email address at all. + if (rushConfiguration.gitAllowedEmailRegExps.length === 0) { + if (userEmail === undefined) { + return; + } + + // Otherwise, if an email *is* configured at all, then we still perform the basic + // sanity checks (e.g. no spaces in the address). + } + + try { + userEmail = git.validateGitEmail(userEmail); + + // sanity check; a valid email should not contain any whitespace + // if this fails, then we have another issue to report + if (!userEmail.match(/^\S+$/g)) { + // eslint-disable-next-line no-console + console.log( + [ + Colorize.red('Your Git email address is invalid: ' + JSON.stringify(userEmail)), + '', + `To configure your Git email address, try something like this:`, + '', + ...getEmailExampleLines(rushConfiguration), + '' + ].join('\n') + ); + throw new AlreadyReportedError(); + } + } catch (e) { + if (e instanceof AlreadyReportedError) { + let errorMessage: string = 'Aborting, so you can go fix your settings.'; + if (options.bypassPolicyAllowed) { + errorMessage += ` (Or use "${RushConstants.bypassPolicyFlagLongName}" to skip.)`; + } + + // eslint-disable-next-line no-console + console.log(Colorize.red(errorMessage)); + throw e; + } else { + throw e; + } + } + + if (rushConfiguration.gitAllowedEmailRegExps.length === 0) { + // If there is no policy, then we're good + return; + } + + // eslint-disable-next-line no-console + console.log('Checking Git policy for this repository.\n'); + + // If there is a policy, at least one of the RegExp's must match + for (const pattern of rushConfiguration.gitAllowedEmailRegExps) { + const regex: RegExp = new RegExp(`^${pattern}$`, 'i'); + if (userEmail.match(regex)) { + return; + } + } + + // Show the user's name as well. + // Ex. "Example Name " + let fancyEmail: string = Colorize.cyan(userEmail); + try { + const userName: string = ( + await Utilities.executeCommandAndCaptureOutputAsync(git.gitPath!, ['config', 'user.name'], '.') + ).trim(); + if (userName) { + fancyEmail = `${userName} <${fancyEmail}>`; + } + } catch (e) { + // but if it fails, this isn't critical, so don't bother them about it + } + + // eslint-disable-next-line no-console + console.log( + [ + 'Hey there! To keep things tidy, this repo asks you to submit your Git commits using an email like ' + + (rushConfiguration.gitAllowedEmailRegExps.length > 1 ? 'one of these patterns:' : 'this pattern:'), + '', + ...rushConfiguration.gitAllowedEmailRegExps.map((pattern) => ' ' + Colorize.cyan(pattern)), + '', + '...but yours is configured like this:', + '', + ` ${fancyEmail}`, + '', + 'To fix it, you can use commands like this:', + '', + ...getEmailExampleLines(rushConfiguration), + '' + ].join('\n') + ); + + let errorMessage: string = 'Aborting, so you can go fix your settings.'; + if (options.bypassPolicyAllowed) { + errorMessage += ` (Or use "${RushConstants.bypassPolicyFlagLongName}" to skip.)`; + } + + // eslint-disable-next-line no-console + console.log(Colorize.red(errorMessage)); + throw new AlreadyReportedError(); +} + +export function getEmailExampleLines(rushConfiguration: RushConfiguration): string[] { + return [ + Colorize.cyan(' git config --local user.name "Example Name"'), + Colorize.cyan( + ` git config --local user.email "${rushConfiguration.gitSampleEmail || 'name@example.com'}"` + ) + ]; +} diff --git a/libraries/rush-lib/src/logic/policy/PolicyValidator.ts b/libraries/rush-lib/src/logic/policy/PolicyValidator.ts new file mode 100644 index 00000000000..b54e31d1295 --- /dev/null +++ b/libraries/rush-lib/src/logic/policy/PolicyValidator.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 { RushConfiguration } from '../../api/RushConfiguration'; +import * as GitEmailPolicy from './GitEmailPolicy'; +import * as ShrinkwrapFilePolicy from './ShrinkwrapFilePolicy'; +import * as EnvironmentPolicy from './EnvironmentPolicy'; +import type { Subspace } from '../../api/Subspace'; + +export interface IPolicyValidatorOptions { + bypassPolicyAllowed?: boolean; + bypassPolicy?: boolean; + allowShrinkwrapUpdates?: boolean; +} + +export async function validatePolicyAsync( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined, + options: IPolicyValidatorOptions +): Promise { + if (!options.bypassPolicy) { + await GitEmailPolicy.validateAsync(rushConfiguration, options); + await EnvironmentPolicy.validateAsync(rushConfiguration, options); + if (!options.allowShrinkwrapUpdates) { + // Don't validate the shrinkwrap if updates are allowed, as it's likely to change + // It also may have merge conflict markers, which PNPM can gracefully handle, but the validator cannot + ShrinkwrapFilePolicy.validate(rushConfiguration, subspace, variant, options); + } + } +} diff --git a/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts b/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts new file mode 100644 index 00000000000..dd2f4e3c9f3 --- /dev/null +++ b/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { IPolicyValidatorOptions } from './PolicyValidator'; +import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; +import type { RepoStateFile } from '../RepoStateFile'; +import type { Subspace } from '../../api/Subspace'; + +export interface IShrinkwrapFilePolicyValidatorOptions extends IPolicyValidatorOptions { + repoState: RepoStateFile; +} + +/** + * A policy that validates shrinkwrap files used by package managers. + */ +export function validate( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined, + options: IPolicyValidatorOptions +): 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) + ); + + if (!shrinkwrapFile) { + // eslint-disable-next-line no-console + console.log('Shrinkwrap file could not be found, skipping validation.\n'); + return; + } + + // Run shrinkwrap-specific validation + shrinkwrapFile.validate( + rushConfiguration.packageManagerOptions, + { + ...options, + repoState: subspace.getRepoState() + }, + rushConfiguration.experimentsConfiguration.configuration + ); +} diff --git a/libraries/rush-lib/src/logic/selectors/GitChangedProjectSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/GitChangedProjectSelectorParser.ts new file mode 100644 index 00000000000..65d7b40fae5 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/GitChangedProjectSelectorParser.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; +import { type IGetChangedProjectsOptions, ProjectChangeAnalyzer } from '../ProjectChangeAnalyzer'; + +export interface IGitSelectorParserOptions { + /** + * If set to `true`, consider a project's external dependency installation layout as defined in the + * package manager lockfile when determining if it has changed. + */ + includeExternalDependencies: boolean; + + /** + * If set to `true` apply the `incrementalBuildIgnoredGlobs` property in a project's `rush-project.json` + * and exclude matched files from change detection. + */ + enableFiltering: boolean; +} + +export class GitChangedProjectSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + private readonly _options: IGitSelectorParserOptions; + + public constructor(rushConfiguration: RushConfiguration, options: IGitSelectorParserOptions) { + this._rushConfiguration = rushConfiguration; + this._options = options; + } + + public async evaluateSelectorAsync({ + unscopedSelector, + terminal + }: IEvaluateSelectorOptions): Promise> { + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(this._rushConfiguration); + + const options: IGetChangedProjectsOptions = { + terminal, + targetBranchName: unscopedSelector, + ...this._options + }; + + return await projectChangeAnalyzer.getChangedProjectsAsync(options); + } + + public getCompletions(): Iterable { + return [this._rushConfiguration.repositoryDefaultBranch, 'HEAD~1', 'HEAD']; + } +} diff --git a/libraries/rush-lib/src/logic/selectors/ISelectorParser.ts b/libraries/rush-lib/src/logic/selectors/ISelectorParser.ts new file mode 100644 index 00000000000..000010afa11 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/ISelectorParser.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 type { ITerminal } from '@rushstack/terminal'; + +export interface IEvaluateSelectorOptions { + unscopedSelector: string; + terminal: ITerminal; + parameterName: string; +} + +export interface ISelectorParser { + evaluateSelectorAsync(options: IEvaluateSelectorOptions): Promise>; + getCompletions(): Iterable; +} diff --git a/libraries/rush-lib/src/logic/selectors/NamedProjectSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/NamedProjectSelectorParser.ts new file mode 100644 index 00000000000..b39ab7ffe96 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/NamedProjectSelectorParser.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 { AlreadyReportedError, PackageName } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; +import { RushConstants } from '../RushConstants'; + +export class NamedProjectSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public async evaluateSelectorAsync({ + unscopedSelector, + terminal, + parameterName + }: IEvaluateSelectorOptions): Promise> { + const project: RushConfigurationProject | undefined = + this._rushConfiguration.findProjectByShorthandName(unscopedSelector); + if (!project) { + terminal.writeErrorLine( + `The project name "${unscopedSelector}" passed to "${parameterName}" does not exist in ` + + `${RushConstants.rushJsonFilename}.` + ); + throw new AlreadyReportedError(); + } + + return [project]; + } + + public getCompletions(): Iterable { + const unscopedNamesMap: Map = new Map(); + + const scopedNames: Set = new Set(); + for (const project of this._rushConfiguration.rushConfigurationJson.projects) { + scopedNames.add(project.packageName); + const unscopedName: string = PackageName.getUnscopedName(project.packageName); + const count: number = unscopedNamesMap.get(unscopedName) || 0; + unscopedNamesMap.set(unscopedName, count + 1); + } + + const unscopedNames: string[] = []; + for (const [unscopedName, unscopedNameCount] of unscopedNamesMap) { + // don't suggest ambiguous unscoped names + if (unscopedNameCount === 1 && !scopedNames.has(unscopedName)) { + unscopedNames.push(unscopedName); + } + } + + return unscopedNames.sort().concat([...scopedNames].sort()); + } +} 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/SubspaceSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/SubspaceSelectorParser.ts new file mode 100644 index 00000000000..f4b3a2bfd06 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/SubspaceSelectorParser.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 type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { Subspace } from '../../api/Subspace'; +import { RushConstants } from '../RushConstants'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; + +export class SubspaceSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public async evaluateSelectorAsync({ + unscopedSelector + }: IEvaluateSelectorOptions): Promise> { + const subspace: Subspace = this._rushConfiguration.getSubspace(unscopedSelector); + + return subspace.getProjects(); + } + + public getCompletions(): Iterable { + // Tab completion is a performance sensitive operation, so avoid loading all the projects + const subspaceNames: string[] = []; + if (this._rushConfiguration.subspacesConfiguration) { + subspaceNames.push(...this._rushConfiguration.subspacesConfiguration.subspaceNames); + } + if (!subspaceNames.indexOf(RushConstants.defaultSubspaceName)) { + subspaceNames.push(RushConstants.defaultSubspaceName); + } + return subspaceNames; + } +} diff --git a/libraries/rush-lib/src/logic/selectors/TagProjectSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/TagProjectSelectorParser.ts new file mode 100644 index 00000000000..f704bb81edc --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/TagProjectSelectorParser.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 { AlreadyReportedError } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; +import { RushConstants } from '../RushConstants'; + +export class TagProjectSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public async evaluateSelectorAsync({ + unscopedSelector, + terminal, + parameterName + }: IEvaluateSelectorOptions): Promise> { + const selection: ReadonlySet | undefined = + this._rushConfiguration.projectsByTag.get(unscopedSelector); + if (!selection) { + terminal.writeErrorLine( + `The tag "${unscopedSelector}" passed to "${parameterName}" is not specified for any projects in ` + + `${RushConstants.rushJsonFilename}.` + ); + throw new AlreadyReportedError(); + } + return selection; + } + + public getCompletions(): Iterable { + return this._rushConfiguration.projectsByTag.keys(); + } +} diff --git a/libraries/rush-lib/src/logic/selectors/VersionPolicyProjectSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/VersionPolicyProjectSelectorParser.ts new file mode 100644 index 00000000000..c12c993afec --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/VersionPolicyProjectSelectorParser.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 { AlreadyReportedError } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; + +export class VersionPolicyProjectSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + } + + public async evaluateSelectorAsync({ + unscopedSelector, + terminal, + parameterName + }: IEvaluateSelectorOptions): Promise> { + const selection: Set = new Set(); + + if (!this._rushConfiguration.versionPolicyConfiguration.versionPolicies.has(unscopedSelector)) { + terminal.writeErrorLine( + `The version policy "${unscopedSelector}" passed to "${parameterName}" does not exist in version-policies.json.` + ); + throw new AlreadyReportedError(); + } + + for (const project of this._rushConfiguration.projects) { + if (project.versionPolicyName === unscopedSelector) { + selection.add(project); + } + } + + return selection; + } + + public getCompletions(): Iterable { + return this._rushConfiguration.versionPolicyConfiguration.versionPolicies.keys(); + } +} 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 new file mode 100644 index 00000000000..fc72e437b4b --- /dev/null +++ b/libraries/rush-lib/src/logic/setup/ArtifactoryConfiguration.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 { JsonFile, JsonSchema, FileSystem } from '@rushstack/node-core-library'; + +import schemaJson from '../../schemas/artifactory.schema.json'; + +export interface IArtifactoryPackageRegistryJson { + enabled: boolean; + userNpmrcLinesToAdd?: string[]; + + registryUrl: string; + artifactoryWebsiteUrl: string; + + credentialType?: 'password' | 'authToken'; + + messageOverrides?: { + introduction?: string; + obtainAnAccount?: string; + visitWebsite?: string; + locateUserName?: string; + locateApiKey?: string; + }; +} + +/** + * This interface represents the raw artifactory.json file. + * @beta + */ +export interface IArtifactoryJson { + packageRegistry: IArtifactoryPackageRegistryJson; +} + +/** + * 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; + + /** + * Get the artifactory configuration. + */ + public readonly configuration: Readonly; + + /** + * @internal + */ + public constructor(jsonFileName: string) { + this._jsonFileName = jsonFileName; + + this.configuration = { + packageRegistry: { + enabled: false, + registryUrl: '', + artifactoryWebsiteUrl: '' + } + }; + + if (FileSystem.exists(this._jsonFileName)) { + this.configuration = JsonFile.loadAndValidate(this._jsonFileName, ArtifactoryConfiguration._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 new file mode 100644 index 00000000000..f599e548413 --- /dev/null +++ b/libraries/rush-lib/src/logic/setup/KeyboardLoop.ts @@ -0,0 +1,161 @@ +// 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 'node:readline'; +import * as process from 'node:process'; + +import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; + +// 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. +const ANSI_ESCAPE_SHOW_CURSOR: string = '\u001B[?25l'; +const ANSI_ESCAPE_HIDE_CURSOR: string = '\u001B[?25h'; + +export class KeyboardLoop { + protected stdin: NodeJS.ReadStream; + protected stderr: NodeJS.WriteStream; + private _readlineInterface: readline.Interface | undefined; + private _resolvePromise: (() => void) | undefined; + private _rejectPromise: ((error: Error) => void) | undefined; + private _cursorHidden: boolean = false; + + public constructor() { + this.stdin = process.stdin; + this.stderr = process.stderr; + } + + public get capturedInput(): boolean { + return this._readlineInterface !== undefined; + } + + private _captureInput(): void { + if (this._readlineInterface) { + return; + } + + this._checkForTTY(); + + this._readlineInterface = readline.createInterface({ input: this.stdin }); + + readline.emitKeypressEvents(process.stdin); + this.stdin.setRawMode(true); + this.stdin.addListener('keypress', this._onKeypress); + } + + private _checkForTTY(): void { + // Typescript thinks setRawMode always extists, but we're testing that assumption here. + if (this.stdin.isTTY && (this.stdin as Partial).setRawMode) { + return; + } + + if (process.platform === 'win32') { + 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. + // eslint-disable-next-line no-console + console.error( + Colorize.red( + 'ERROR: It appears that Rush was invoked from Git Bash shell, which does not support the\n' + + 'TTY mode for interactive input that is required by this feature.' + ) + + '\n\nKnown workarounds are:\n' + + '- Invoke Rush using "winpty rush.cmd" instead of "rush"\n' + + '- Or add this to your .bashrc: alias rush="winpty rush.cmd"\n' + + '- Or create a Git Bash shortcut icon that launches\n' + + ' "C:\\Program Files\\Git\\bin\\bash.exe" instead of "git-bash.exe"\n\n' + + 'For details, refer to https://github.com/microsoft/rushstack/issues/3217' + ); + throw new AlreadyReportedError(); + } + } + + // eslint-disable-next-line no-console + console.error( + Colorize.red( + 'ERROR: Rush was invoked by a command whose STDIN does not support the TTY mode for\n' + + 'interactive input that is required by this feature.' + ) + '\n\nTry invoking "rush" directly from your shell.' + ); + throw new AlreadyReportedError(); + } + + private _uncaptureInput(): void { + if (!this._readlineInterface) { + return; + } + + this.stdin.removeListener('keypress', this._onKeypress); + this.stdin.setRawMode(false); + this._readlineInterface.close(); + this._readlineInterface = undefined; + } + + protected hideCursor(): void { + if (this._cursorHidden) { + return; + } + this._cursorHidden = true; + this.stderr.write(ANSI_ESCAPE_SHOW_CURSOR); + } + + protected unhideCursor(): void { + if (!this._cursorHidden) { + return; + } + this._cursorHidden = false; + this.stderr.write(ANSI_ESCAPE_HIDE_CURSOR); + } + + public async startAsync(): Promise { + try { + this._captureInput(); + this.onStart(); + await new Promise((resolve: () => void, reject: (error: Error) => void) => { + this._resolvePromise = resolve; + this._rejectPromise = reject; + }); + } finally { + this._uncaptureInput(); + this.unhideCursor(); + } + } + + protected resolveAsync(): void { + if (!this._resolvePromise) { + return; + } + this._resolvePromise(); + this._resolvePromise = undefined; + this._rejectPromise = undefined; + } + + protected rejectAsync(error: Error): void { + if (!this._rejectPromise) { + return; + } + this._rejectPromise(error); + this._resolvePromise = undefined; + this._rejectPromise = undefined; + } + + /** @virtual */ + protected onStart(): void {} + + /** @virtual */ + protected onKeypress(character: string, key: readline.Key): void {} + + private _onKeypress = (character: string, key: readline.Key): void => { + if (key.name === 'c' && key.ctrl && !key.meta && !key.shift) { + // Intercept CTRL+C + process.kill(process.pid, 'SIGINT'); + return; + } + try { + this.onKeypress(character, key); + } catch (error) { + throw new InternalError('Uncaught exception in Prompter.onKeypress(): ' + (error as Error).toString()); + } + }; +} diff --git a/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts b/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts new file mode 100644 index 00000000000..ffbabe9e18b --- /dev/null +++ b/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts @@ -0,0 +1,535 @@ +// 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 { + AlreadyReportedError, + Executable, + FileSystem, + InternalError, + type JsonObject, + NewlineKind, + Text, + User +} from '@rushstack/node-core-library'; +import { PrintUtilities, Colorize, ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { Utilities } from '../../utilities/Utilities'; +import { type IArtifactoryPackageRegistryJson, ArtifactoryConfiguration } from './ArtifactoryConfiguration'; +import type { WebClient as WebClientType, IWebClientResponse } from '../../utilities/WebClient'; +import { TerminalInput } from './TerminalInput'; + +interface IArtifactoryCustomizableMessages { + introduction: string; + obtainAnAccount: string; + visitWebsite: string; + locateUserName: string; + locateApiKey: string; + userNamePrompt: string; + apiKeyPrompt: string; +} + +const defaultMessages: IArtifactoryCustomizableMessages = { + introduction: 'This monorepo consumes packages from an Artifactory private NPM registry.', + obtainAnAccount: + 'Please contact the repository maintainers for help with setting up an Artifactory user account.', + visitWebsite: 'Please open this URL in your web browser:', + locateUserName: 'Your user name appears in the upper-right corner of the JFrog website.', + locateApiKey: + 'Click "Edit Profile" on the JFrog website. Click the "Generate API Key"' + + " button if you haven't already done so previously.", + userNamePrompt: 'What is your Artifactory user name?', + apiKeyPrompt: 'What is your Artifactory API key?' +}; + +export interface ISetupPackageRegistryOptions { + rushConfiguration: RushConfiguration; + isDebug: boolean; + + /** + * Whether Utilities.syncNpmrc() has already been called. + */ + syncNpmrcAlreadyCalled: boolean; +} + +export class SetupPackageRegistry { + private readonly _options: ISetupPackageRegistryOptions; + public readonly rushConfiguration: RushConfiguration; + private readonly _terminal: Terminal; + private readonly _artifactoryConfiguration: ArtifactoryConfiguration; + private readonly _messages: IArtifactoryCustomizableMessages; + + public constructor(options: ISetupPackageRegistryOptions) { + this._options = options; + this.rushConfiguration = options.rushConfiguration; + + this._terminal = new Terminal( + new ConsoleTerminalProvider({ + verboseEnabled: options.isDebug + }) + ); + + this._artifactoryConfiguration = new ArtifactoryConfiguration( + path.join(this.rushConfiguration.commonRushConfigFolder, 'artifactory.json') + ); + + this._messages = { + ...defaultMessages, + ...this._artifactoryConfiguration.configuration.packageRegistry.messageOverrides + }; + } + + private _writeInstructionBlock(message: string): void { + if (message === '') { + return; + } + + this._terminal.writeLine(PrintUtilities.wrapWords(message)); + this._terminal.writeLine(); + } + + /** + * Test whether the NPM token is valid. + * + * @returns - `true` if valid, `false` if not valid + */ + public async checkOnlyAsync(): Promise { + const packageRegistry: IArtifactoryPackageRegistryJson = + this._artifactoryConfiguration.configuration.packageRegistry; + if (!packageRegistry.enabled) { + this._terminal.writeVerbose('Skipping package registry setup because packageRegistry.enabled=false'); + return true; + } + + const registryUrl: string = (packageRegistry?.registryUrl || '').trim(); + if (registryUrl.length === 0) { + throw new Error('The "registryUrl" setting in artifactory.json is missing or empty'); + } + + if (!this._options.syncNpmrcAlreadyCalled) { + Utilities.syncNpmrc({ + sourceNpmrcFolder: this.rushConfiguration.commonRushConfigFolder, + targetNpmrcFolder: this.rushConfiguration.commonTempFolder, + supportEnvVarFallbackSyntax: this.rushConfiguration.isPnpm + }); + } + + // Artifactory does not implement the "npm ping" protocol or any equivalent REST API. + // But if we query a package that is known not to exist, Artifactory will only return + // a 404 error if it is successfully authenticated. We can use this negative query + // to validate the credentials. + const npmArgs: string[] = [ + 'view', + '@rushstack/nonexistent-package', + '--json', + '--registry=' + packageRegistry.registryUrl + ]; + + this._terminal.writeLine('Testing access to private NPM registry: ' + packageRegistry.registryUrl); + + const result: child_process.SpawnSyncReturns = Executable.spawnSync('npm', npmArgs, { + currentWorkingDirectory: this.rushConfiguration.commonTempFolder, + stdio: ['ignore', 'pipe', 'pipe'], + // Wait at most 10 seconds for "npm view" to succeed + timeoutMs: 10 * 1000 + }); + this._terminal.writeLine(); + + // (This is not exactly correct, for example Node.js puts a string in error.errno instead of a string.) + const error: (Error & Partial) | undefined = result.error; + + if (error) { + if (error.code === 'ETIMEDOUT') { + // For example, an incorrect "https-proxy" setting can hang for a long time + throw new Error('The "npm view" command timed out; check your .npmrc file for an incorrect setting'); + } + + throw new Error('Error invoking "npm view": ' + result.error); + } + + if (result.status === 0) { + throw new InternalError('"npm view" unexpectedly succeeded'); + } + + // NPM 6.x writes to stdout + let jsonContent: string | undefined = SetupPackageRegistry._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); + } + if (jsonContent === undefined) { + throw new InternalError('The "npm view" command did not return a JSON structure'); + } + + let jsonOutput: JsonObject; + try { + jsonOutput = JSON.parse(jsonContent); + } catch (e) { + this._terminal.writeVerboseLine('NPM response:\n\n--------\n' + jsonContent + '\n--------\n\n'); + throw new InternalError('The "npm view" command returned an invalid JSON structure'); + } + + const errorCode: JsonObject = jsonOutput?.error?.code; + if (typeof errorCode !== 'string') { + this._terminal.writeVerboseLine('NPM response:\n' + JSON.stringify(jsonOutput, undefined, 2) + '\n\n'); + throw new InternalError('The "npm view" command returned unexpected output'); + } + + switch (errorCode) { + case 'E404': + this._terminal.writeLine('NPM credentials are working'); + this._terminal.writeLine(); + return true; + case 'E401': + case 'E403': + this._terminal.writeVerboseLine( + 'NPM response:\n' + JSON.stringify(jsonOutput, undefined, 2) + '\n\n' + ); + // Credentials are missing or expired + return false; + default: + this._terminal.writeVerboseLine( + 'NPM response:\n' + JSON.stringify(jsonOutput, undefined, 2) + '\n\n' + ); + throw new Error(`The "npm view" command returned an unexpected error code "${errorCode}"`); + } + } + + /** + * Test whether the NPM token is valid. If not, prompt to update it. + */ + public async checkAndSetupAsync(): Promise { + if (await this.checkOnlyAsync()) { + return; + } + + this._terminal.writeWarningLine('NPM credentials are missing or expired'); + this._terminal.writeLine(); + + const packageRegistry: IArtifactoryPackageRegistryJson = + this._artifactoryConfiguration.configuration.packageRegistry; + + const fixThisProblem: boolean = await TerminalInput.promptYesNoAsync({ + message: 'Fix this problem now?', + defaultValue: false + }); + this._terminal.writeLine(); + if (!fixThisProblem) { + return; + } + + this._writeInstructionBlock(this._messages.introduction); + + const hasArtifactoryAccount: boolean = await TerminalInput.promptYesNoAsync({ + message: 'Do you already have an Artifactory user account?' + }); + this._terminal.writeLine(); + + if (!hasArtifactoryAccount) { + this._writeInstructionBlock(this._messages.obtainAnAccount); + throw new AlreadyReportedError(); + } + + if (this._messages.visitWebsite) { + this._writeInstructionBlock(this._messages.visitWebsite); + + const artifactoryWebsiteUrl: string = + this._artifactoryConfiguration.configuration.packageRegistry.artifactoryWebsiteUrl; + + if (artifactoryWebsiteUrl) { + this._terminal.writeLine(' ', Colorize.cyan(artifactoryWebsiteUrl)); + this._terminal.writeLine(); + } + } + + this._writeInstructionBlock(this._messages.locateUserName); + + let artifactoryUser: string = await TerminalInput.promptLineAsync({ + message: this._messages.userNamePrompt + }); + this._terminal.writeLine(); + + artifactoryUser = artifactoryUser.trim(); + if (artifactoryUser.length === 0) { + this._terminal.writeLine(Colorize.red('Operation aborted because the input was empty')); + this._terminal.writeLine(); + throw new AlreadyReportedError(); + } + + this._writeInstructionBlock(this._messages.locateApiKey); + + let artifactoryKey: string = await TerminalInput.promptPasswordLineAsync({ + message: this._messages.apiKeyPrompt + }); + this._terminal.writeLine(); + + artifactoryKey = artifactoryKey.trim(); + if (artifactoryKey.length === 0) { + this._terminal.writeLine(Colorize.red('Operation aborted because the input was empty')); + this._terminal.writeLine(); + throw new AlreadyReportedError(); + } + + await this._fetchTokenAndUpdateNpmrcAsync(artifactoryUser, artifactoryKey, packageRegistry); + } + + /** + * Fetch a valid NPM token from the Artifactory service and add it to the `~/.npmrc` file, + * preserving other settings in that file. + */ + private async _fetchTokenAndUpdateNpmrcAsync( + artifactoryUser: string, + artifactoryKey: string, + packageRegistry: IArtifactoryPackageRegistryJson + ): Promise { + this._terminal.writeLine('\nFetching an NPM token from the Artifactory service...'); + + // Defer this import since it is conditionally needed. + const { WebClient } = await import('../../utilities/WebClient'); + const webClient: WebClientType = new WebClient(); + + webClient.addBasicAuthHeader(artifactoryUser, artifactoryKey); + + let queryUrl: string = packageRegistry.registryUrl; + if (!queryUrl.endsWith('/')) { + queryUrl += '/'; + } + + // There doesn't seem to be a way to invoke the "/auth" REST endpoint without a resource name. + // Artifactory's NPM folders always seem to contain a ".npm" folder, so we can use that to obtain + // our token. + queryUrl += `auth/.npm`; + + let response: IWebClientResponse; + try { + response = await webClient.fetchAsync(queryUrl); + } catch (e) { + // eslint-disable-next-line no-console + console.log((e as Error).toString()); + return; + } + + if (!response.ok) { + if (response.status === 401) { + throw new Error('Authorization failed; the Artifactory user name or API key may be incorrect.'); + } + + throw new Error(`The Artifactory request failed:\n (${response.status}) ${response.statusText}`); + } + + // We expect a response like this: + // + // @.npm:registry=https://your-company.jfrog.io/your-artifacts/api/npm/npm-private/ + // //your-company.jfrog.io/your-artifacts/api/npm/npm-private/:_password=dGhlIHRva2VuIGdvZXMgaGVyZQ== + // //your-company.jfrog.io/your-artifacts/api/npm/npm-private/:username=your.name@your-company.com + // //your-company.jfrog.io/your-artifacts/api/npm/npm-private/:email=your.name@your-company.com + // //your-company.jfrog.io/your-artifacts/api/npm/npm-private/:always-auth=true + const responseText: string = await response.getTextAsync(); + const responseLines: string[] = Text.convertToLf(responseText).trim().split('\n'); + if (responseLines.length < 2 || !responseLines[0].startsWith('@.npm:')) { + throw new Error('Unexpected response from Artifactory'); + } + responseLines.shift(); // Remove the @.npm line + + // If we are configured to use authToken for authentication, we still go through the above process + // (both to ensure the user's credentials are valid, and to let Artifactory format the standard + // npmrc boilerplate for us), but we'll discard the generated password and use the authToken instead. + if (packageRegistry.credentialType === 'authToken') { + for (let i: number = 0; i < responseLines.length; i++) { + responseLines[i] = responseLines[i].replace(/_password=.+/, '_authToken=' + artifactoryKey); + } + } + + // These are the lines to be injected in ~/.npmrc + const linesToAdd: string[] = []; + + // Start with userNpmrcLinesToAdd... + if (packageRegistry.userNpmrcLinesToAdd) { + linesToAdd.push(...packageRegistry.userNpmrcLinesToAdd); + } + + // ...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)); + + const npmrcPath: string = path.join(User.getHomeFolder(), '.npmrc'); + + this._mergeLinesIntoNpmrc(npmrcPath, linesToAdd); + } + + /** + * Update the `~/.npmrc` file by adding `linesToAdd` to it. + * @remarks + * + * If the `.npmrc` file has existing content, it gets merged as follows: + * - If `linesToAdd` contains key/value pairs and the key already appears in .npmrc, + * that line will be overwritten in place + * - If `linesToAdd` contains non-key lines (e.g. a comment) and it exactly matches a + * line in .npmrc, then that line will be kept where it is + * - The remaining `linesToAdd` that weren't handled by one of the two rules above + * are simply appended to the end of the file + * - Under no circumstances is a duplicate key/value added to the file; in the case of + * duplicates, the earliest line in `linesToAdd` takes precedence + */ + private _mergeLinesIntoNpmrc(npmrcPath: string, linesToAdd: readonly string[]): void { + // We'll replace entries with "undefined" if they get discarded + const workingLinesToAdd: (string | undefined)[] = [...linesToAdd]; + + // Now build a table of .npmrc keys that can be replaced if they already exist in the file. + // For example, if we are adding "always-auth=false" then we should delete an existing line + // that says "always-auth=true". + const keysToReplace: Map = new Map(); // key --> linesToAdd index + + for (let index: number = 0; index < workingLinesToAdd.length; ++index) { + const lineToAdd: string = workingLinesToAdd[index]!; + + const key: string | undefined = SetupPackageRegistry._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 + if (keysToReplace.has(key)) { + // Discard the duplicate key + workingLinesToAdd[index] = undefined; + } else { + keysToReplace.set(key, index); + } + } + } + + this._terminal.writeLine(); + this._terminal.writeLine(Colorize.green('Adding Artifactory token to: '), npmrcPath); + + const npmrcLines: string[] = []; + + if (FileSystem.exists(npmrcPath)) { + const npmrcContent: string = FileSystem.readFile(npmrcPath, { convertLineEndings: NewlineKind.Lf }); + npmrcLines.push(...npmrcContent.trimRight().split('\n')); + } + + if (npmrcLines.length === 1 && npmrcLines[0] === '') { + // Edge case where split() adds a blank line to the start of the file + npmrcLines.length = 0; + } + + // Make a set of existing .npmrc lines that are not key/value pairs. + const npmrcNonKeyLinesSet: Set = new Set(); + for (const npmrcLine of npmrcLines) { + const trimmed: string = npmrcLine.trim(); + if (trimmed.length > 0) { + if (SetupPackageRegistry._getNpmrcKey(trimmed) === undefined) { + npmrcNonKeyLinesSet.add(trimmed); + } + } + } + + // Overwrite any existing lines that match a key from "linesToAdd" + for (let index: number = 0; index < npmrcLines.length; ++index) { + const line: string = npmrcLines[index]; + + const key: string | undefined = SetupPackageRegistry._getNpmrcKey(line); + if (key) { + const linesToAddIndex: number | undefined = keysToReplace.get(key); + if (linesToAddIndex !== undefined) { + npmrcLines[index] = workingLinesToAdd[linesToAddIndex] || ''; + + // Delete it since it's been replaced + keysToReplace.delete(key); + + // Also remove it from "linesToAdd" + workingLinesToAdd[linesToAddIndex] = undefined; + } + } + } + + if (npmrcLines.length > 0 && npmrcLines[npmrcLines.length - 1] !== '') { + // Append a blank line + npmrcLines.push(''); + } + + // Add any remaining values that weren't matched above + for (const lineToAdd of workingLinesToAdd) { + // If a line is undefined, that means we already used it to replace an existing line above + if (lineToAdd !== undefined) { + // If a line belongs to npmrcNonKeyLinesSet, then we should not add it because it's + // already in the .npmrc file + if (!npmrcNonKeyLinesSet.has(lineToAdd.trim())) { + npmrcLines.push(lineToAdd); + } + } + } + + // 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(); + } + + private static _isCommentLine(npmrcLine: string): boolean { + return /^\s*#/.test(npmrcLine); + } + + /** + * 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; + } + + // 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; + } + } + + 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 new file mode 100644 index 00000000000..84546ddce9d --- /dev/null +++ b/libraries/rush-lib/src/logic/setup/TerminalInput.ts @@ -0,0 +1,239 @@ +// 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 'node:readline'; +import * as process from 'node:process'; + +import { AnsiEscape, Colorize } from '@rushstack/terminal'; + +import { KeyboardLoop } from './KeyboardLoop'; + +export interface IBasePromptOptions { + message: string; +} + +export interface IPromptYesNoOptions extends IBasePromptOptions { + defaultValue?: boolean | undefined; +} + +export interface IPromptPasswordOptions extends IBasePromptOptions { + /** + * The string length must not be longer than 1. An empty string means to show the input text. + * @defaultValue `*` + */ + passwordCharacter?: string; +} + +export interface IPromptLineOptions extends IBasePromptOptions {} + +class YesNoKeyboardLoop extends KeyboardLoop { + public readonly options: IPromptYesNoOptions; + public result: boolean | undefined = undefined; + + public constructor(options: IPromptYesNoOptions) { + super(); + this.options = options; + } + + protected onStart(): void { + this.stderr.write(Colorize.green('==>') + ' '); + this.stderr.write(Colorize.bold(this.options.message)); + let optionSuffix: string = ''; + switch (this.options.defaultValue) { + case true: + optionSuffix = '(Y/n)'; + break; + case false: + optionSuffix = '(y/N)'; + break; + default: + optionSuffix = '(y/n)'; + break; + } + this.stderr.write(' ' + Colorize.bold(optionSuffix) + ' '); + } + + protected onKeypress(character: string, key: readline.Key): void { + if (this.result !== undefined) { + return; + } + + switch (key.name) { + case 'y': + this.result = true; + break; + case 'n': + this.result = false; + break; + case 'enter': + case 'return': + if (this.options.defaultValue !== undefined) { + this.result = this.options.defaultValue; + } + break; + } + + if (this.result !== undefined) { + this.stderr.write(this.result ? 'Yes\n' : 'No\n'); + this.resolveAsync(); + return; + } + } +} + +class PasswordKeyboardLoop extends KeyboardLoop { + private readonly _options: IPromptPasswordOptions; + private _passwordCharacter: string; + private _startX: number = 0; + private _printedY: number = 0; + private _lastPrintedLength: number = 0; + + public result: string = ''; + + public constructor(options: IPromptPasswordOptions) { + super(); + this._options = options; + + this._passwordCharacter = + this._options.passwordCharacter === undefined ? '*' : this._options.passwordCharacter.substr(0, 1); + } + + private _getLineWrapWidth(): number { + return this.stderr.columns ? this.stderr.columns : 80; + } + + protected onStart(): void { + this.result = ''; + + readline.cursorTo(this.stderr, 0); + readline.clearLine(this.stderr, 1); + const prefix: string = Colorize.green('==>') + ' ' + Colorize.bold(this._options.message) + ' '; + + this.stderr.write(prefix); + let lineStartIndex: number = prefix.lastIndexOf('\n'); + if (lineStartIndex < 0) { + lineStartIndex = 0; + } + const line: string = prefix.substring(lineStartIndex); + this._startX = AnsiEscape.removeCodes(line).length % this._getLineWrapWidth(); + } + + protected onKeypress(character: string, key: readline.Key): void { + switch (key.name) { + case 'enter': + case 'return': + if (this._passwordCharacter !== '') { + // To avoid disclosing the length of the password, after the user presses ENTER, + // replace the "*********" sequence with exactly three stars ("***"). + this._render(this._passwordCharacter.repeat(3)); + } + this.stderr.write('\n'); + this.resolveAsync(); + return; + case 'backspace': + this.result = this.result.substring(0, this.result.length - 1); + this._render(this.result); + break; + default: + let printable: boolean = true; + if (character === '') { + printable = false; + } else if (key.name && key.name.length !== 1 && key.name !== 'space') { + printable = false; + } else if (!key.name && !key.sequence) { + printable = false; + } + + if (printable) { + this.result += character; + this._render(this.result); + } + } + } + + private _render(text: string): void { + // Optimize rendering when we don't need to erase anything + const needsClear: boolean = text.length < this._lastPrintedLength; + this._lastPrintedLength = text.length; + + this.hideCursor(); + + // Restore Y + while (this._printedY > 0) { + readline.cursorTo(this.stderr, 0); + if (needsClear) { + readline.clearLine(this.stderr, 1); + } + readline.moveCursor(this.stderr, 0, -1); + --this._printedY; + } + + // Restore X + readline.cursorTo(this.stderr, this._startX); + + let i: number = 0; + let column: number = this._startX; + this._printedY = 0; + let buffer: string = ''; + + while (i < text.length) { + if (this._passwordCharacter === '') { + buffer += text.substr(i, 1); + } else { + buffer += this._passwordCharacter; + } + + ++i; + ++column; + + // -1 to avoid weird TTY behavior in final column + if (column >= this._getLineWrapWidth() - 1) { + column = 0; + ++this._printedY; + buffer += '\n'; + } + } + this.stderr.write(buffer); + + if (needsClear) { + readline.clearLine(this.stderr, 1); + } + + this.unhideCursor(); + } +} + +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(); + return keyboardLoop.result!; + } + + public static async promptLineAsync(options: IPromptLineOptions): Promise { + const stderr: NodeJS.WriteStream = process.stderr; + stderr.write(Colorize.green('==>') + ' '); + stderr.write(Colorize.bold(options.message)); + stderr.write(' '); + return await TerminalInput._readLineAsync(); + } + + public static async promptPasswordLineAsync(options: IPromptLineOptions): Promise { + const keyboardLoop: PasswordKeyboardLoop = new PasswordKeyboardLoop(options); + await keyboardLoop.startAsync(); + return keyboardLoop.result; + } +} diff --git a/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts b/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts new file mode 100644 index 00000000000..21a2f460d3c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/BaseInstallManager.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 { ConsoleTerminalProvider, type ITerminal, Terminal } from '@rushstack/terminal'; + +import { PurgeManager } from '../PurgeManager'; +import { BaseInstallManager, pnpmIgnoreCompatibilityDbParameter } from '../base/BaseInstallManager'; +import type { IInstallManagerOptions } from '../base/BaseInstallManagerTypes'; + +import { RushConfiguration } from '../../api/RushConfiguration'; +import { RushGlobalFolder } from '../../api/RushGlobalFolder'; +import type { Subspace } from '../../api/Subspace'; + +class FakeBaseInstallManager extends BaseInstallManager { + public constructor( + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder, + purgeManager: PurgeManager, + options: IInstallManagerOptions + ) { + super(rushConfiguration, rushGlobalFolder, purgeManager, options); + } + + protected prepareCommonTempAsync(): Promise<{ + shrinkwrapIsUpToDate: boolean; + shrinkwrapWarnings: string[]; + }> { + return Promise.resolve({ shrinkwrapIsUpToDate: true, shrinkwrapWarnings: [] }); + } + + protected installAsync(): Promise { + return Promise.resolve(); + } + + protected postInstallAsync(): Promise { + return Promise.resolve(); + } + public pushConfigurationArgs(args: string[], options: IInstallManagerOptions, subspace: Subspace): void { + return super.pushConfigurationArgs(args, options, subspace); + } +} + +describe('BaseInstallManager Test', () => { + const rushGlobalFolder: RushGlobalFolder = new RushGlobalFolder(); + + it('pnpm version in 6.32.12 - 6.33.x || 7.0.1 - 7.8.x should output warning', () => { + const rushJsonFilePnpmV6: string = path.resolve(__dirname, 'ignoreCompatibilityDb/rush1.json'); + const rushJsonFilePnpmV7: string = path.resolve(__dirname, 'ignoreCompatibilityDb/rush2.json'); + const rushConfigurationV6: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilePnpmV6); + const rushConfigurationV7: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilePnpmV7); + const terminal: ITerminal = new Terminal(new ConsoleTerminalProvider()); + const options6: IInstallManagerOptions = { + subspace: rushConfigurationV6.defaultSubspace, + terminal + } as IInstallManagerOptions; + const options7: IInstallManagerOptions = { + subspace: rushConfigurationV7.defaultSubspace, + terminal + } as IInstallManagerOptions; + const purgeManager6: typeof PurgeManager.prototype = new PurgeManager( + rushConfigurationV6, + rushGlobalFolder + ); + const purgeManager7: typeof PurgeManager.prototype = new PurgeManager( + rushConfigurationV7, + rushGlobalFolder + ); + + const fakeBaseInstallManager6: FakeBaseInstallManager = new FakeBaseInstallManager( + rushConfigurationV6, + rushGlobalFolder, + purgeManager6, + options6 + ); + + const fakeBaseInstallManager7: FakeBaseInstallManager = new FakeBaseInstallManager( + rushConfigurationV7, + rushGlobalFolder, + purgeManager7, + options7 + ); + + const mockWrite = jest.fn(); + jest.spyOn(ConsoleTerminalProvider.prototype, 'write').mockImplementation(mockWrite); + + const argsPnpmV6: string[] = []; + fakeBaseInstallManager6.pushConfigurationArgs(argsPnpmV6, options6, rushConfigurationV7.defaultSubspace); + expect(argsPnpmV6).not.toContain(pnpmIgnoreCompatibilityDbParameter); + expect(mockWrite.mock.calls[0][0]).toContain( + "Warning: Your rush.json specifies a pnpmVersion with a known issue that may cause unintended version selections. It's recommended to upgrade to PNPM >=6.34.0 or >=7.9.0. For details see: https://rushjs.io/link/pnpm-issue-5132" + ); + + const argsPnpmV7: string[] = []; + fakeBaseInstallManager7.pushConfigurationArgs(argsPnpmV7, options7, rushConfigurationV7.defaultSubspace); + expect(argsPnpmV7).not.toContain(pnpmIgnoreCompatibilityDbParameter); + expect(mockWrite.mock.calls[0][0]).toContain( + "Warning: Your rush.json specifies a pnpmVersion with a known issue that may cause unintended version selections. It's recommended to upgrade to PNPM >=6.34.0 or >=7.9.0. For details see: https://rushjs.io/link/pnpm-issue-5132" + ); + }); + + it(`pnpm version ^6.34.0 || gte 7.9.0 should add ${pnpmIgnoreCompatibilityDbParameter}`, () => { + const rushJsonFile: string = path.resolve(__dirname, 'ignoreCompatibilityDb/rush3.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const purgeManager: typeof PurgeManager.prototype = new PurgeManager(rushConfiguration, rushGlobalFolder); + const options: IInstallManagerOptions = { + subspace: rushConfiguration.defaultSubspace + } as IInstallManagerOptions; + + const fakeBaseInstallManager: FakeBaseInstallManager = new FakeBaseInstallManager( + rushConfiguration, + rushGlobalFolder, + purgeManager, + options + ); + + const mockWrite = jest.fn(); + jest.spyOn(ConsoleTerminalProvider.prototype, 'write').mockImplementation(mockWrite); + + const args: string[] = []; + fakeBaseInstallManager.pushConfigurationArgs(args, options, rushConfiguration.defaultSubspace); + expect(args).toContain(pnpmIgnoreCompatibilityDbParameter); + + if (mockWrite.mock.calls.length) { + expect(mockWrite.mock.calls[0][0]).not.toContain( + "Warning: Your rush.json specifies a pnpmVersion with a known issue that may cause unintended version selections. It's recommended to upgrade to PNPM >=6.34.0 or >=7.9.0. For details see: https://rushjs.io/link/pnpm-issue-5132" + ); + } + }); +}); diff --git a/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts b/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts new file mode 100644 index 00000000000..6d95500d8be --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ChangeFiles.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 { Path } from '@rushstack/node-core-library'; + +import type { IChangelog } from '../../api/Changelog'; +import { ChangeFiles } from '../ChangeFiles'; +import type { RushConfiguration } from '../../api/RushConfiguration'; + +describe(ChangeFiles.name, () => { + let rushConfiguration: RushConfiguration; + + beforeEach(() => { + rushConfiguration = {} as RushConfiguration; + }); + + describe(ChangeFiles.prototype.getFilesAsync.name, () => { + 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]); + }); + + 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); + }); + + 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(); + 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`); + 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`; + const changedPackages: string[] = ['d']; + expect(() => { + ChangeFiles.validate([changeFile], changedPackages, { + hotfixChangeEnabled: true + } as RushConfiguration); + }).toThrow(Error); + }); + + it('allows a hotfix in a hotfix branch.', () => { + const changeFile: string = `${__dirname}/multipleHotfixChanges/change1.json`; + const changedPackages: string[] = ['a']; + ChangeFiles.validate([changeFile], changedPackages, { hotfixChangeEnabled: true } as RushConfiguration); + }); + + it('throws when there is any missing package.', () => { + const changeFile: string = `${__dirname}/verifyChanges/changes.json`; + const changedPackages: string[] = ['a', 'b', 'c']; + expect(() => { + ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); + }).toThrow(Error); + }); + + it('does not throw when there is no missing packages', () => { + const changeFile: string = `${__dirname}/verifyChanges/changes.json`; + const changedPackages: string[] = ['a']; + expect(() => { + ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); + }).not.toThrow(); + }); + + 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`; + const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; + expect(() => { + ChangeFiles.validate([changeFileA, changeFileB], changedPackages, rushConfiguration); + }).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`; + const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; + expect(() => { + ChangeFiles.validate([changeFileA, changeFileB, changeFileC], changedPackages, rushConfiguration); + }).not.toThrow(Error); + }); + }); + + describe(ChangeFiles.prototype.deleteAllAsync.name, () => { + 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); + }); + + 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 updatedChangelogs: IChangelog[] = [ + { + name: 'a', + entries: [] + }, + { + name: 'b', + entries: [] + } + ]; + expect(await changeFiles.deleteAllAsync(false, updatedChangelogs)).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); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/ChangeManager.test.ts b/libraries/rush-lib/src/logic/test/ChangeManager.test.ts new file mode 100644 index 00000000000..d305bb4b1fc --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ChangeManager.test.ts @@ -0,0 +1,356 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LockStepVersionPolicy } from '../../api/VersionPolicy'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import { ChangeManager } from '../ChangeManager'; +import { PrereleaseToken } from '../PrereleaseToken'; + +describe(ChangeManager.name, () => { + const rushJsonFile: string = `${__dirname}/packages/rush.json`; + let rushConfiguration: RushConfiguration; + let changeManager: ChangeManager; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + changeManager = new ChangeManager(rushConfiguration); + }); + + /* eslint-disable dot-notation */ + it('can apply changes to the package.json files in the dictionary', async () => { + await changeManager.loadAsync(`${__dirname}/multipleChanges`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual('>=2.0.0 <3.0.0'); + expect(changeManager.allPackages.get('e')!.packageJson.devDependencies!['a']).toEqual('>=2.0.0 <3.0.0'); + expect(changeManager.allPackages.get('e')!.packageJson.peerDependencies!['a']).toEqual('>=2.0.0 <3.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.dependencies!['b']).toEqual('>=1.0.1 <2.0.0'); + expect(changeManager.allPackages.get('f')!.packageJson.devDependencies!['b']).toEqual('>=1.0.1 <2.0.0'); + expect(changeManager.allPackages.get('f')!.packageJson.peerDependencies!['b']).toEqual('>=1.0.1 <2.0.0'); + }); + + it('can update explicit version dependency', async () => { + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual('1.0.1'); + }); + + it('can update a project using lockStepVersion policy with no nextBump from changefiles', async () => { + await changeManager.loadAsync(`${__dirname}/lockstepWithoutNextBump`); + changeManager.apply(false); + + const policy: LockStepVersionPolicy = rushConfiguration.versionPolicyConfiguration.getVersionPolicy( + 'lockStepWithoutNextBump' + ) as LockStepVersionPolicy; + + expect(changeManager.allPackages.get('h')!.packageJson.version).toEqual('1.1.0'); + expect(changeManager.allPackages.get('f')!.packageJson.peerDependencies!['h']).toEqual('^1.1.0'); + expect(policy.version).toEqual('1.1.0'); + }); + + it('can update explicit cyclic dependency', async () => { + await changeManager.loadAsync(`${__dirname}/cyclicDepsExplicit`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual('2.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.dependencies![ + 'cyclic-dep-explicit-2' + ] + ).toEqual('>=1.0.0 <2.0.0'); + expect(changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.version).toEqual('1.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.dependencies![ + 'cyclic-dep-explicit-1' + ] + ).toEqual('>=1.0.0 <2.0.0'); + }); + + it('can update root with patch change for prerelease', async () => { + const prereleaseName: string = 'alpha.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + '1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + '1.0.1-' + prereleaseName + ); + }); + + it('can update non-root with patch change for prerelease', async () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual('>=1.0.0 <2.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + '1.0.1-' + prereleaseName + ); + }); + + it('can update cyclic dependency for non-explicit prerelease', async () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( + '2.0.0-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + '1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual( + '1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + '2.0.0-' + prereleaseName + ); + }); + + it('can update root with patch change for adding version suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual('1.0.0-' + suffix); + }); + + it('can update non-root with patch change for version suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual('>=1.0.0 <2.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual('1.0.0-' + suffix); + }); + + it('can update cyclic dependency for non-explicit suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + '1.0.0-' + suffix + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + '1.0.0-' + suffix + ); + }); + /* eslint-enable dot-notation */ +}); + +describe(`${ChangeManager.name} (workspace)`, () => { + const rushJsonFile: string = `${__dirname}/workspacePackages/rush.json`; + let rushConfiguration: RushConfiguration; + let changeManager: ChangeManager; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + changeManager = new ChangeManager(rushConfiguration); + }); + + /* eslint-disable dot-notation */ + it('can apply changes to the package.json files in the dictionary', async () => { + await changeManager.loadAsync(`${__dirname}/multipleChanges`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=2.0.0 <3.0.0' + ); + expect(changeManager.allPackages.get('e')!.packageJson.devDependencies!['a']).toEqual( + 'workspace:>=2.0.0 <3.0.0' + ); + expect(changeManager.allPackages.get('e')!.packageJson.peerDependencies!['a']).toEqual('>=2.0.0 <3.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('c')!.packageJson.dependencies!['b']).toEqual( + 'workspace:>=1.0.1 <2.0.0' + ); + expect(changeManager.allPackages.get('f')!.packageJson.devDependencies!['b']).toEqual( + 'workspace:>=1.0.1 <2.0.0' + ); + expect(changeManager.allPackages.get('f')!.packageJson.peerDependencies!['b']).toEqual('>=1.0.1 <2.0.0'); + }); + + it('can update explicit version dependency', async () => { + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1'); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual('workspace:1.0.1'); + }); + + it('can update explicit cyclic dependency', async () => { + await changeManager.loadAsync(`${__dirname}/cyclicDepsExplicit`); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual('2.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.dependencies![ + 'cyclic-dep-explicit-2' + ] + ).toEqual('workspace:>=1.0.0 <2.0.0'); + expect(changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.version).toEqual('1.0.0'); + expect( + changeManager.allPackages.get('cyclic-dep-explicit-2')!.packageJson.dependencies![ + 'cyclic-dep-explicit-1' + ] + ).toEqual('>=1.0.0 <2.0.0'); + }); + + it('can update root with patch change for prerelease', async () => { + const prereleaseName: string = 'alpha.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + }); + + it('can update non-root with patch change for prerelease', async () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=1.0.0 <2.0.0' + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + }); + + it('can update cyclic dependency for non-explicit prerelease', async () => { + const prereleaseName: string = 'beta.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); + + await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( + '2.0.0-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + 'workspace:1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual( + '1.0.1-' + prereleaseName + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + 'workspace:2.0.0-' + prereleaseName + ); + }); + + it('can update root with patch change for adding version suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:1.0.0-' + suffix + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + + it('can update non-root with patch change for version suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.version).toEqual('1.0.0'); + expect(changeManager.allPackages.get('b')!.packageJson.dependencies!['a']).toEqual( + 'workspace:>=1.0.0 <2.0.0' + ); + expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('d')!.packageJson.dependencies!['c']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + + it('can update cyclic dependency for non-explicit suffix', async () => { + const suffix: string = 'dk.1'; + const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); + + await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + changeManager.apply(false); + + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.dependencies!['cyclic-dep-2']).toEqual( + 'workspace:1.0.0-' + suffix + ); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.version).toEqual('1.0.0-' + suffix); + expect(changeManager.allPackages.get('cyclic-dep-2')!.packageJson.dependencies!['cyclic-dep-1']).toEqual( + 'workspace:1.0.0-' + suffix + ); + }); + /* eslint-enable dot-notation */ +}); diff --git a/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts b/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts new file mode 100644 index 00000000000..6a300b8578c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.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 type { IChangelog } from '../../api/Changelog'; +import { ChangeType } from '../../api/ChangeManagement'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { ChangelogGenerator } from '../ChangelogGenerator'; +import type { IChangeRequests } from '../PublishUtilities'; + +describe(ChangelogGenerator.updateIndividualChangelog.name, () => { + const rushJsonFile: string = `${__dirname}/packages/rush.json`; + let rushConfiguration: RushConfiguration; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + }); + + it('can translate a single change request into a new changelog object', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '1.0.0', + changeType: ChangeType.major, + changes: [ + { + packageName: 'a', + type: 'major', + changeType: ChangeType.major, + comment: 'Patching a' + } + ] + }, + 'rootMajorChange', + false, + rushConfiguration + )!; + + const expectedResult: IChangelog = { + name: 'a', + entries: [ + { + version: '1.0.0', + tag: 'a_v1.0.0', + date: '', + comments: { + major: [ + { + author: undefined, + comment: 'Patching a', + commit: undefined + } + ] + } + } + ] + }; + + // Ignore comparing date. + expectedResult.entries[0].date = actualResult.entries[0].date; + + expect(actualResult).toEqual(expectedResult); + }); + + it('can merge a new change request into an existing changelog', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '1.0.0', + changeType: ChangeType.major, + changes: [ + { + packageName: 'a', + type: 'major', + changeType: ChangeType.major, + comment: 'Patching a' + } + ] + }, + `${__dirname}/exampleChangelog`, + false, + rushConfiguration + )!; + + const expectedResult: IChangelog = { + name: 'a', + entries: [ + { + version: '1.0.0', + tag: 'a_v1.0.0', + date: '', + comments: { + major: [ + { + author: undefined, + comment: 'Patching a', + commit: undefined + } + ] + } + }, + { + version: '0.0.1', + tag: 'a_v0.0.1', + date: 'Wed, 30 Nov 2016 18:37:45 GMT', + comments: { + patch: [ + { + comment: 'Patching a' + } + ] + } + } + ] + }; + + // Ignore comparing date. + expectedResult.entries[0].date = actualResult.entries[0].date; + + expect(actualResult).toEqual(expectedResult); + }); + + it('translates custom fields from change files to change log', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '1.0.0', + changeType: ChangeType.major, + changes: [ + { + packageName: 'a', + type: 'major', + changeType: ChangeType.major, + comment: 'Patching a', + customFields: { + issueTicket: 'A-1053', + vendorTag: 'AAAAA' + } + } + ] + }, + `${__dirname}/exampleChangelog`, + false, + rushConfiguration + )!; + + const expectedResult: IChangelog = { + name: 'a', + entries: [ + { + version: '1.0.0', + tag: 'a_v1.0.0', + date: '', + comments: { + major: [ + { + author: undefined, + comment: 'Patching a', + commit: undefined, + customFields: { + issueTicket: 'A-1053', + vendorTag: 'AAAAA' + } + } + ] + } + }, + { + version: '0.0.1', + tag: 'a_v0.0.1', + date: 'Wed, 30 Nov 2016 18:37:45 GMT', + comments: { + patch: [ + { + comment: 'Patching a' + } + ] + } + } + ] + }; + + // Ignore comparing date. + expectedResult.entries[0].date = actualResult.entries[0].date; + + expect(actualResult).toEqual(expectedResult); + }); + + it('can avoid adding duplicate entries', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '0.0.1', + changeType: ChangeType.patch, + changes: [ + { + packageName: 'a', + type: 'patch', + changeType: ChangeType.patch, + comment: 'Patching a' + } + ] + }, + `${__dirname}/exampleChangelog`, + false, + rushConfiguration + )!; + + expect(actualResult).not.toBeDefined(); + }); + + it('can handle dependency bumps', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '0.0.2', + changeType: ChangeType.dependency, + changes: [ + { + packageName: 'a', + type: 'dependency', + changeType: ChangeType.dependency, + comment: 'Updating a' + } + ] + }, + `${__dirname}/exampleChangelog`, + false, + rushConfiguration + )!; + + const expectedResult: IChangelog = { + name: 'a', + entries: [ + { + version: '0.0.2', + tag: 'a_v0.0.2', + date: undefined, + comments: { + dependency: [ + { + author: undefined, + comment: 'Updating a', + commit: undefined + } + ] + } + }, + { + version: '0.0.1', + tag: 'a_v0.0.1', + date: 'Wed, 30 Nov 2016 18:37:45 GMT', + comments: { + patch: [ + { + comment: 'Patching a' + } + ] + } + } + ] + }; + + // Remove date. + actualResult.entries[0].date = undefined; + + expect(actualResult).toEqual(expectedResult); + }); + + it('skip empty comment', () => { + const actualResult: IChangelog = ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '0.0.2', + changeType: ChangeType.none, + changes: [ + { + packageName: 'a', + type: 'none', + changeType: ChangeType.none, + comment: '' + } + ] + }, + `${__dirname}/exampleChangelog`, + false, + rushConfiguration + )!; + + const expectedResult: IChangelog = { + name: 'a', + entries: [ + { + version: '0.0.2', + tag: 'a_v0.0.2', + date: undefined, + comments: {} + }, + { + version: '0.0.1', + tag: 'a_v0.0.1', + date: 'Wed, 30 Nov 2016 18:37:45 GMT', + comments: { + patch: [ + { + comment: 'Patching a' + } + ] + } + } + ] + }; + + // Remove date. + actualResult.entries[0].date = undefined; + + expect(actualResult).toEqual(expectedResult); + }); + + it('can throw right error when given valid file', () => { + const generateUpdateInvoke = + (projectPath: string): (() => void) => + () => { + ChangelogGenerator.updateIndividualChangelog( + { + packageName: 'a', + newVersion: '0.0.2', + changeType: ChangeType.none, + changes: [ + { + packageName: 'a', + type: 'none', + changeType: ChangeType.none, + comment: '' + } + ] + }, + projectPath, + false, + rushConfiguration + ); + }; + + const emptyFileInvoke = generateUpdateInvoke(`${__dirname}/exampleInvalidChangelog/emptyFile`); + expect(emptyFileInvoke).toThrow(Error); + expect(emptyFileInvoke).toThrow(/No data, empty input at 1:1/); + + const emptyObjectFileInvoke = generateUpdateInvoke(`${__dirname}/exampleInvalidChangelog/emptyObject`); + expect(emptyObjectFileInvoke).toThrow(Error); + expect(emptyObjectFileInvoke).toThrow(/must have required property 'name'/); + }); +}); + +describe(ChangelogGenerator.updateChangelogs.name, () => { + const rushJsonFile: string = `${__dirname}/packages/rush.json`; + let rushConfiguration: RushConfiguration; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + }); + + 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. + allChanges.packageChanges.set('a', { + packageName: 'a', + changeType: ChangeType.dependency, + newVersion: '1.0.0', + changes: [] + }); + // Package b has version change. + allChanges.packageChanges.set('b', { + packageName: 'b', + changeType: ChangeType.patch, + newVersion: '1.0.1', + changes: [] + }); + const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( + allChanges, + rushConfiguration.projectsByName, + rushConfiguration, + false + ); + expect(updatedChangeLogs).toHaveLength(1); + expect(updatedChangeLogs[0].name).toEqual('b'); + }); + + it('skips changes logs if the project is in pre-release', () => { + const allChanges: IChangeRequests = { packageChanges: new Map(), versionPolicyChanges: new Map() }; + // Package a is a prerelease + allChanges.packageChanges.set('a', { + packageName: 'a', + changeType: ChangeType.dependency, + newVersion: '1.0.1-pre.1', + changes: [] + }); + // Package b is not a prerelease + allChanges.packageChanges.set('b', { + packageName: 'b', + changeType: ChangeType.patch, + newVersion: '1.0.1', + changes: [] + }); + // Makes package 'a' prerelease package. + const rushProjectA: RushConfigurationProject = rushConfiguration.projectsByName.get('a')!; + rushProjectA.packageJson.version = '1.0.1-pre.1'; + + const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( + allChanges, + rushConfiguration.projectsByName, + rushConfiguration, + false + ); + expect(updatedChangeLogs).toHaveLength(1); + expect(updatedChangeLogs[0].name).toEqual('b'); + }); + + it('writes changelog for hotfix changes', () => { + const allChanges: IChangeRequests = { packageChanges: new Map(), versionPolicyChanges: new Map() }; + // Package a is a hotfix + allChanges.packageChanges.set('a', { + packageName: 'a', + changeType: ChangeType.hotfix, + newVersion: '1.0.1-hotfix.1', + changes: [] + }); + // Package b is not a hotfix + allChanges.packageChanges.set('b', { + packageName: 'b', + changeType: ChangeType.patch, + newVersion: '1.0.1', + changes: [] + }); + // Makes package 'a' hotfix package. + const rushProjectA: RushConfigurationProject = rushConfiguration.projectsByName.get('a')!; + rushProjectA.packageJson.version = '1.0.1-hotfix.1'; + + const updatedChangeLogs: IChangelog[] = ChangelogGenerator.updateChangelogs( + allChanges, + rushConfiguration.projectsByName, + rushConfiguration, + false + ); + expect(updatedChangeLogs).toHaveLength(2); + expect(updatedChangeLogs[0].name).toEqual('a'); + expect(updatedChangeLogs[1].name).toEqual('b'); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzer.test.ts b/libraries/rush-lib/src/logic/test/DependencyAnalyzer.test.ts new file mode 100644 index 00000000000..04f192fef8a --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzer.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { RushConfiguration } from '../../api/RushConfiguration'; +import { DependencyAnalyzer, type IDependencyAnalysis } from '../DependencyAnalyzer'; + +describe(DependencyAnalyzer.name, () => { + function getAnalysisForRepoByName(repoName: string): IDependencyAnalysis { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${__dirname}/DependencyAnalyzerTestRepos/${repoName}/rush.json` + ); + const dependencyAnalyzer: DependencyAnalyzer = DependencyAnalyzer.forRushConfiguration(rushConfiguration); + const analysis: IDependencyAnalysis = dependencyAnalyzer.getAnalysis(undefined, undefined, false); + return analysis; + } + + it('correctly gets the list of dependencies in a repo without allowed alternative versions', () => { + const analysis: IDependencyAnalysis = getAnalysisForRepoByName('no-allowed-alternatives'); + expect(analysis.allVersionsByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => Set { + "1.0.0", + }, + "dep-2" => Set { + "1.0.0", + }, + "dep-3" => Set { + "1.0.0", + }, + } + `); + expect(analysis.implicitlyPreferredVersionByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => "1.0.0", + "dep-2" => "1.0.0", + "dep-3" => "1.0.0", + } + `); + }); + + it('correctly gets the list of dependencies in a repo with allowed alternative versions', () => { + const analysis: IDependencyAnalysis = getAnalysisForRepoByName('allowed-alternatives'); + expect(analysis.allVersionsByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => Set { + "1.0.0", + }, + "dep-2" => Set { + "1.0.0", + "2.0.0", + }, + "dep-3" => Set { + "1.0.0", + }, + } + `); + expect(analysis.implicitlyPreferredVersionByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => "1.0.0", + "dep-2" => "1.0.0", + "dep-3" => "1.0.0", + } + `); + }); + + it('correctly gets the list of dependencies in a repo with non-allowed inconsistent versions', () => { + const analysis: IDependencyAnalysis = getAnalysisForRepoByName( + 'no-allowed-alternatives-with-inconsistent-versions' + ); + expect(analysis.allVersionsByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => Set { + "1.0.0", + }, + "dep-2" => Set { + "1.0.0", + "2.0.0", + }, + "dep-3" => Set { + "1.0.0", + }, + } + `); + expect(analysis.implicitlyPreferredVersionByPackageName).toMatchInlineSnapshot(` + Map { + "dep-1" => "1.0.0", + "dep-3" => "1.0.0", + } + `); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/a/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/a/package.json new file mode 100644 index 00000000000..c9ce4ef5fdc --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "dependencies": { + "dep-1": "1.0.0", + "dep-2": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/b/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/b/package.json new file mode 100644 index 00000000000..3c0e3534e70 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/b/package.json @@ -0,0 +1,10 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": ">=1.0.0 <2.0.0", + "dep-2": "2.0.0", + "dep-3": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/common/config/rush/common-versions.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/common/config/rush/common-versions.json new file mode 100644 index 00000000000..b7121143224 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/common/config/rush/common-versions.json @@ -0,0 +1,5 @@ +{ + "allowedAlternativeVersions": { + "dep-2": ["2.0.0"] + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/rush.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/rush.json new file mode 100644 index 00000000000..e504d076c93 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/allowed-alternatives/rush.json @@ -0,0 +1,17 @@ +{ + "pnpmVersion": "6.7.1", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/a/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/a/package.json new file mode 100644 index 00000000000..c9ce4ef5fdc --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "dependencies": { + "dep-1": "1.0.0", + "dep-2": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/b/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/b/package.json new file mode 100644 index 00000000000..3c0e3534e70 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/b/package.json @@ -0,0 +1,10 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": ">=1.0.0 <2.0.0", + "dep-2": "2.0.0", + "dep-3": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/rush.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/rush.json new file mode 100644 index 00000000000..e504d076c93 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives-with-inconsistent-versions/rush.json @@ -0,0 +1,17 @@ +{ + "pnpmVersion": "6.7.1", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/a/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/a/package.json new file mode 100644 index 00000000000..c9ce4ef5fdc --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "dependencies": { + "dep-1": "1.0.0", + "dep-2": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/b/package.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/b/package.json new file mode 100644 index 00000000000..d2ef9a54b56 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/b/package.json @@ -0,0 +1,10 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": ">=1.0.0 <2.0.0", + "dep-2": "1.0.0", + "dep-3": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/rush.json b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/rush.json new file mode 100644 index 00000000000..e504d076c93 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencyAnalyzerTestRepos/no-allowed-alternatives/rush.json @@ -0,0 +1,17 @@ +{ + "pnpmVersion": "6.7.1", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts b/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts new file mode 100644 index 00000000000..9ec30a66024 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Version", + "versionSpecifier": "1.2.3", +} +`); + }); + + it('parses a range version', () => { + const specifier = new DependencySpecifier('dep', '^1.2.3'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Range", + "versionSpecifier": "^1.2.3", +} +`); + }); + + it('parses an alias version', () => { + const specifier = new DependencySpecifier('dep', 'npm:alias-target@1.2.3'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": DependencySpecifier { + "aliasTarget": undefined, + "packageName": "alias-target", + "specifierType": "Version", + "versionSpecifier": "1.2.3", + }, + "packageName": "dep", + "specifierType": "Alias", + "versionSpecifier": "npm:alias-target@1.2.3", +} +`); + }); + + it('parses a git version', () => { + const specifier = new DependencySpecifier('dep', 'git+https://github.com/user/foo'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Git", + "versionSpecifier": "git+https://github.com/user/foo", +} +`); + }); + + it('parses a file version', () => { + const specifier = new DependencySpecifier('dep', 'file:foo.tar.gz'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "File", + "versionSpecifier": "file:foo.tar.gz", +} +`); + }); + + it('parses a directory version', () => { + const specifier = new DependencySpecifier('dep', 'file:../foo/bar/'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Directory", + "versionSpecifier": "file:../foo/bar/", +} +`); + }); + + it('parses a remote version', () => { + const specifier = new DependencySpecifier('dep', 'https://example.com/foo.tgz'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Remote", + "versionSpecifier": "https://example.com/foo.tgz", +} +`); + }); + + describe('Workspace protocol', () => { + it('correctly parses a "workspace:*" version', () => { + const specifier = new DependencySpecifier('dep', 'workspace:*'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Workspace", + "versionSpecifier": "*", +} +`); + }); + + it('correctly parses a "workspace:^1.0.0" version', () => { + const specifier = new DependencySpecifier('dep', 'workspace:^1.0.0'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Workspace", + "versionSpecifier": "^1.0.0", +} +`); + }); + + it('correctly parses a "workspace:alias@1.2.3" version', () => { + const specifier = new DependencySpecifier('dep', 'workspace:alias-target@*'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": DependencySpecifier { + "aliasTarget": undefined, + "packageName": "alias-target", + "specifierType": "Range", + "versionSpecifier": "*", + }, + "packageName": "dep", + "specifierType": "Workspace", + "versionSpecifier": "alias-target@*", +} +`); + }); + }); + + 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 new file mode 100644 index 00000000000..6eed35e5de7 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/Git.test.ts @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import { Git } from '../Git'; +import type { IGitStatusEntry } from '../GitStatusParser'; + +describe(Git.name, () => { + describe(Git.normalizeGitUrlForComparison.name, () => { + it('correctly normalizes URLs', () => { + expect(Git.normalizeGitUrlForComparison('invalid.git')).toEqual('invalid'); + expect(Git.normalizeGitUrlForComparison('git@github.com:ExampleOrg/ExampleProject.git')).toEqual( + 'https://github.com/ExampleOrg/ExampleProject' + ); + expect(Git.normalizeGitUrlForComparison('ssh://user@host.xz:1234/path/to/repo.git/')).toEqual( + 'https://host.xz:1234/path/to/repo' + ); + expect(Git.normalizeGitUrlForComparison('git://host.xz/path/to/repo')).toEqual( + 'https://host.xz/path/to/repo' + ); + expect(Git.normalizeGitUrlForComparison('http://host.xz:80/path/to/repo')).toEqual( + 'https://host.xz:80/path/to/repo' + ); + expect(Git.normalizeGitUrlForComparison('host.xz:path/to/repo.git/')).toEqual( + 'https://host.xz/path/to/repo' + ); + + // "This syntax is only recognized if there are no slashes before the first colon. + // This helps differentiate a local path that contains a colon." + expect(Git.normalizeGitUrlForComparison('host/xz:path/to/repo.git/')).toEqual('host/xz:path/to/repo'); + + expect(Git.normalizeGitUrlForComparison('file:///path/to/repo.git/')).toEqual('file:///path/to/repo'); + expect(Git.normalizeGitUrlForComparison('C:\\Windows\\Path.txt')).toEqual('C:\\Windows\\Path.txt'); + expect(Git.normalizeGitUrlForComparison('c:/windows/path.git')).toEqual('c:/windows/path'); + }); + }); + + describe(Git.prototype.getGitStatusAsync.name, () => { + async function getGitStatusEntriesForCommandOutputAsync( + outputSections: string[] + ): Promise { + const gitInstance: Git = new Git({ rushJsonFolder: '/repo/root' } as RushConfiguration); + jest.spyOn(gitInstance, 'getGitPathOrThrow').mockReturnValue('/git/bin/path'); + jest + .spyOn(gitInstance, '_executeGitCommandAndCaptureOutputAsync') + .mockImplementation(async (gitPath: string, args: string[]) => { + expect(gitPath).toEqual('/git/bin/path'); + expect(args).toEqual(['status', '--porcelain=2', '--null', '--ignored=no']); + return outputSections.join('\0'); + }); + + return Array.from(await gitInstance.getGitStatusAsync()); + } + + it('parses a git status', async () => { + await expect( + getGitStatusEntriesForCommandOutputAsync([ + // Staged add + '1 A. N... 000000 100644 100644 0000000000000000000000000000000000000000 a171a25d2c978ba071959f39dbeaa339fe84f768 path/a.ts', + // Modifications, some staged and some unstaged + '1 MM N... 100644 100644 100644 d20c7e41acf4295db610f395f50a554145b4ece7 8299b2a7d657ec1211649f14c85737d68a920d9e path/b.ts', + // Unstaged deletion + '1 .D N... 100644 100644 000000 3fcb58810c113c90c366dd81d16443425c7b95fa 3fcb58810c113c90c366dd81d16443425c7b95fa path/c.ts', + // Staged deletion + '1 D. N... 100644 000000 000000 91b0203b85a7bb605e35f842d1d05d66a6275e10 0000000000000000000000000000000000000000 path/d.ts', + // Staged rename + '2 R. N... 100644 100644 100644 451de43c5cb012af55a79cc3463849ab3cfa0457 451de43c5cb012af55a79cc3463849ab3cfa0457 R100 path/e.ts', + 'e2.ts', + // Staged add + '1 A. N... 000000 100644 100644 0000000000000000000000000000000000000000 451de43c5cb012af55a79cc3463849ab3cfa0457 path/f.ts', + // Unstaged add + '? path/g.ts', + // Unstaged unresolved merge conflict + 'u .M N... 100644 100644 100644 100644 07b1571a387db3072be485e6cc5591fef35bf666 63f37aa0393e142e2c8329593eb0f78e4cc77032 ebac91ffe8227e6e9b99d9816ce0a6d166b4a524 path/unmerged.ts', + '1 AM N... 000000 100644 100644 0000000000000000000000000000000000000000 9d9ab4adc79c591c0aa72f7fd29a008c80893e3e path/h.ts', + '' + ]) + ).resolves.toMatchInlineSnapshot(` + Array [ + Object { + "headFileMode": "000000", + "headObjectName": "0000000000000000000000000000000000000000", + "indexFileMode": "100644", + "indexObjectName": "a171a25d2c978ba071959f39dbeaa339fe84f768", + "isInSubmodule": false, + "kind": "changed", + "path": "path/a.ts", + "stagedChangeType": "added", + "unstagedChangeType": undefined, + "worktreeFileMode": "100644", + }, + Object { + "headFileMode": "100644", + "headObjectName": "d20c7e41acf4295db610f395f50a554145b4ece7", + "indexFileMode": "100644", + "indexObjectName": "8299b2a7d657ec1211649f14c85737d68a920d9e", + "isInSubmodule": false, + "kind": "changed", + "path": "path/b.ts", + "stagedChangeType": "modified", + "unstagedChangeType": "modified", + "worktreeFileMode": "100644", + }, + Object { + "headFileMode": "100644", + "headObjectName": "3fcb58810c113c90c366dd81d16443425c7b95fa", + "indexFileMode": "100644", + "indexObjectName": "3fcb58810c113c90c366dd81d16443425c7b95fa", + "isInSubmodule": false, + "kind": "changed", + "path": "path/c.ts", + "stagedChangeType": undefined, + "unstagedChangeType": "deleted", + "worktreeFileMode": "000000", + }, + Object { + "headFileMode": "100644", + "headObjectName": "91b0203b85a7bb605e35f842d1d05d66a6275e10", + "indexFileMode": "000000", + "indexObjectName": "0000000000000000000000000000000000000000", + "isInSubmodule": false, + "kind": "changed", + "path": "path/d.ts", + "stagedChangeType": "deleted", + "unstagedChangeType": undefined, + "worktreeFileMode": "000000", + }, + Object { + "headFileMode": "100644", + "headObjectName": "451de43c5cb012af55a79cc3463849ab3cfa0457", + "indexFileMode": "100644", + "indexObjectName": "451de43c5cb012af55a79cc3463849ab3cfa0457", + "isInSubmodule": false, + "kind": "renamed", + "originalPath": "e2.ts", + "path": "path/e.ts", + "renameOrCopyScore": 100, + "stagedChangeType": "renamed", + "unstagedChangeType": undefined, + "worktreeFileMode": "100644", + }, + Object { + "headFileMode": "000000", + "headObjectName": "0000000000000000000000000000000000000000", + "indexFileMode": "100644", + "indexObjectName": "451de43c5cb012af55a79cc3463849ab3cfa0457", + "isInSubmodule": false, + "kind": "changed", + "path": "path/f.ts", + "stagedChangeType": "added", + "unstagedChangeType": undefined, + "worktreeFileMode": "100644", + }, + Object { + "kind": "untracked", + "path": "path/g.ts", + }, + Object { + "isInSubmodule": false, + "kind": "unmerged", + "path": "path/unmerged.ts", + "stage1FileMode": "100644", + "stage1ObjectName": "07b1571a387db3072be485e6cc5591fef35bf666", + "stage2FileMode": "100644", + "stage2ObjectName": "63f37aa0393e142e2c8329593eb0f78e4cc77032", + "stage3FileMode": "100644", + "stage3ObjectName": "ebac91ffe8227e6e9b99d9816ce0a6d166b4a524", + "stagedChangeType": undefined, + "unstagedChangeType": "modified", + "worktreeFileMode": "100644", + }, + Object { + "headFileMode": "000000", + "headObjectName": "0000000000000000000000000000000000000000", + "indexFileMode": "100644", + "indexObjectName": "9d9ab4adc79c591c0aa72f7fd29a008c80893e3e", + "isInSubmodule": false, + "kind": "changed", + "path": "path/h.ts", + "stagedChangeType": "added", + "unstagedChangeType": "modified", + "worktreeFileMode": "100644", + }, + ] + `); + }); + + it('throws with invalid git output', async () => { + await expect(() => + getGitStatusEntriesForCommandOutputAsync(['1 A. N... 000000 100644 100644 000000000000000000']) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unexpected end of git status output after position 31"`); + }); + }); + + describe(Git.prototype.determineIfRefIsACommitAsync.name, () => { + const commit = `d9bc1881959b9e44d846655521cd055fcf713f4d`; + async function getMockedGitIsRefACommitAsync(ref: string): Promise { + const gitInstance: Git = new Git({ rushJsonFolder: '/repo/root' } as RushConfiguration); + jest.spyOn(gitInstance, 'getGitPathOrThrow').mockReturnValue('/git/bin/path'); + jest + .spyOn(gitInstance, '_executeGitCommandAndCaptureOutputAsync') + .mockImplementation(async (gitPath: string, args: string[]) => { + expect(gitPath).toEqual('/git/bin/path'); + expect(args).toEqual(['rev-parse', '--verify', ref]); + return commit; + }); + return await gitInstance.determineIfRefIsACommitAsync(ref); + } + + it('Returns true for commit ref', async () => { + await expect(getMockedGitIsRefACommitAsync(commit)).resolves.toBe(true); + }); + + it('Returns false for branch ref', async () => { + await expect(getMockedGitIsRefACommitAsync('kenrick/skip-merge-base')).resolves.toBe(false); + }); + + it('Returns false for ref that is a tag', async () => { + await expect(getMockedGitIsRefACommitAsync('testing-tag-v1.2.3')).resolves.toBe(false); + }); + + it('Returns false for ref that is other string', async () => { + await expect(getMockedGitIsRefACommitAsync('HEAD')).resolves.toBe(false); + }); + }); + + describe(Git.prototype.tryGetGitEmailAsync.name, () => { + async function getMockGitEmail(hasGitPath: boolean, output: string | Error): Promise { + const gitInstance: Git = new Git({ rushJsonFolder: '/repo/root' } as RushConfiguration); + jest.spyOn(gitInstance, 'gitPath', 'get').mockImplementation(() => { + if (hasGitPath) return '/git/bin/path'; + else return undefined; + }); + + jest + .spyOn(gitInstance, '_executeGitCommandAndCaptureOutputAsync') + .mockImplementation(async (gitPath: string, args: string[]) => { + expect(gitPath).toEqual('/git/bin/path'); + expect(args).toEqual(['config', 'user.email']); + if (typeof output === 'string') return output; + else throw output; + }); + + return await gitInstance.tryGetGitEmailAsync(); + } + + it('Throw exception when cannot find git path', async () => { + await expect(getMockGitEmail(false, 'user@example.com')).rejects.toBeInstanceOf(Error); + }); + + it('Returns result when git user.email has been found', async () => { + await expect(getMockGitEmail(true, 'user@example.com')).resolves.toEqual('user@example.com'); + }); + + it('Returns empty email when git user.email return empty string', async () => { + await expect(getMockGitEmail(true, '')).resolves.toEqual(''); + }); + + it('Returns undefined when git user.email not configure', async () => { + await expect(getMockGitEmail(true, new Error('Email is missing'))).resolves.toEqual(undefined); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts b/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts new file mode 100644 index 00000000000..d161d5da632 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type IPackageJson, JsonFile } from '@rushstack/node-core-library'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import { TestUtilities } from '@rushstack/heft-config-file'; + +import { InstallHelpers } from '../installManager/InstallHelpers'; +import { RushConfiguration } from '../../api/RushConfiguration'; + +describe('InstallHelpers', () => { + describe('generateCommonPackageJson', () => { + const originalJsonFileSave = JsonFile.save; + const mockJsonFileSave: jest.Mock = jest.fn(); + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + + beforeAll(() => { + JsonFile.save = mockJsonFileSave; + }); + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + }); + + 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; + }); + + it('generates correct package json with pnpm configurations', () => { + const RUSH_JSON_FILENAME: string = `${__dirname}/pnpmConfig/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + InstallHelpers.generateCommonPackageJson( + rushConfiguration, + rushConfiguration.defaultSubspace, + undefined, + terminal + ); + const packageJson: IPackageJson = mockJsonFileSave.mock.calls[0][0]; + expect(TestUtilities.stripAnnotations(packageJson)).toEqual( + expect.objectContaining({ + pnpm: { + overrides: { + foo: '^2.0.0', // <-- unsupportedPackageJsonSettings.pnpm.override.foo + quux: 'npm:@myorg/quux@^1.0.0', + 'bar@^2.1.0': '3.0.0', + 'qar@1>zoo': '2' + }, + packageExtensions: { + 'react-redux': { + peerDependencies: { + 'react-dom': '*' + } + } + }, + neverBuiltDependencies: ['fsevents', 'level'], + pnpmFutureFeature: true + } + }) + ); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts b/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts new file mode 100644 index 00000000000..9ab196ea8a8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts @@ -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. + +const mockHashes: Map = new Map([ + ['a/package.json', 'hash1'], + ['b/package.json', 'hash2'], + ['c/package.json', 'hash3'], + ['changes/a.json', 'hash4'], + ['changes/b.json', 'hash5'], + ['changes/c.json', 'hash6'], + ['changes/d.json', 'hash7'], + ['changes/h.json', 'hash8'], + ['common/config/rush/version-policies.json', 'hash9'], + ['common/config/rush/npm-shrinkwrap.json', 'hash10'], + ['d/package.json', 'hash11'], + ['e/package.json', 'hash12'], + ['f/package.json', 'hash13'], + ['g/package.json', 'hash14'], + ['h/package.json', 'hash15'], + ['i/package.json', 'hash16'], + ['j/package.json', 'hash17'], + ['rush.json', 'hash18'] +]); +jest.mock(`@rushstack/package-deps-hash`, () => { + return { + getRepoRoot(dir: string): string { + return dir; + }, + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: mockHashes + }; + }, + getRepoChangesAsync(): ReadonlyMap { + return new Map(); + }, + 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])); + } + }; +}); + +const mockSnapshot: jest.Mock = jest.fn(); + +jest.mock('../incremental/InputsSnapshot', () => { + return { + InputsSnapshot: mockSnapshot + }; +}); + +import { resolve } from 'node:path'; + +import type { IDetailedRepoState } from '@rushstack/package-deps-hash'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { ProjectChangeAnalyzer } from '../ProjectChangeAnalyzer'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import type { + IInputsSnapshot, + GetInputsSnapshotAsyncFn, + IInputsSnapshotParameters +} from '../incremental/InputsSnapshot'; + +describe(ProjectChangeAnalyzer.name, () => { + beforeEach(() => { + mockSnapshot.mockClear(); + }); + + describe(ProjectChangeAnalyzer.prototype._tryGetSnapshotProviderAsync.name, () => { + it('returns a snapshot', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + 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 mockSnapshotValue: {} = {}; + mockSnapshot.mockImplementation(() => mockSnapshotValue); + const snapshotProvider: GetInputsSnapshotAsyncFn | undefined = + await projectChangeAnalyzer._tryGetSnapshotProviderAsync(new Map(), terminal); + const snapshot: IInputsSnapshot | undefined = await snapshotProvider?.(); + + expect(snapshot).toBe(mockSnapshotValue); + expect(terminalProvider.getErrorOutput()).toEqual(''); + expect(terminalProvider.getWarningOutput()).toEqual(''); + + expect(mockSnapshot).toHaveBeenCalledTimes(1); + + const mockInput: IInputsSnapshotParameters = mockSnapshot.mock.calls[0][0]; + expect(mockInput.globalAdditionalFiles).toBeDefined(); + expect(mockInput.globalAdditionalFiles).toMatchObject(['common/config/rush/npm-shrinkwrap.json']); + + expect(mockInput.hashes).toEqual(mockHashes); + expect(mockInput.rootDir).toEqual(rootDir); + expect(mockInput.additionalHashes).toEqual(new Map()); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts b/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts new file mode 100644 index 00000000000..89213fdb03b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.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. + +import { FileSystem, Path } from '@rushstack/node-core-library'; +import { ProjectImpactGraphGenerator } from '../ProjectImpactGraphGenerator'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import { Stopwatch } from '../../utilities/Stopwatch'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +const NORMALIZED_DIRNAME: string = Path.convertToSlashes(__dirname); + +async function runTestForExampleRepoAsync( + repoName: string, + testFn: (generator: ProjectImpactGraphGenerator) => Promise +): Promise { + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${NORMALIZED_DIRNAME}/${repoName}/rush.json` + ); + + 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'); +} + +describe(ProjectImpactGraphGenerator.name, () => { + describe(ProjectImpactGraphGenerator.prototype.generateAsync.name, () => { + beforeEach(() => { + jest.spyOn(Stopwatch.prototype, 'duration', 'get').mockReturnValue(1.5); + }); + + it.each(['workspacePackages', 'packages', 'repo'])( + 'Correctly generates a project impact graph (repo: "%p")', + async (repoName) => + await runTestForExampleRepoAsync(repoName, async (generator) => { + const writeFileAsyncSpy: jest.SpyInstance = jest + .spyOn(FileSystem, 'writeFileAsync') + .mockImplementation(); + + await generator.generateAsync(); + + expect(writeFileAsyncSpy).toHaveBeenCalledTimes(1); + expect( + Path.convertToSlashes(writeFileAsyncSpy.mock.calls[0][0]).replace( + `${NORMALIZED_DIRNAME}/${repoName}`, + '' + ) + ).toMatchSnapshot('Output file path'); + expect(writeFileAsyncSpy.mock.calls[0][1]).toMatchSnapshot('Output file data'); + }) + ); + }); + + describe(ProjectImpactGraphGenerator.prototype.validateAsync.name, () => { + it.each(['workspacePackages'])( + 'Reports if the project-impact-graph.yaml file is missing (repo: "%p")', + async (repoName) => + await runTestForExampleRepoAsync(repoName, async (generator) => { + await expect(generator.validateAsync()).resolves.toBe(false); + }) + ); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/PublishGit.test.ts b/libraries/rush-lib/src/logic/test/PublishGit.test.ts new file mode 100644 index 00000000000..6cb8fb98453 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/PublishGit.test.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 * as path from 'node:path'; + +import { RushConfiguration } from '../../api/RushConfiguration'; +import { Git } from '../Git'; +import { PublishGit } from '../PublishGit'; +import { PublishUtilities } from '../PublishUtilities'; + +describe('PublishGit Test', () => { + let gitPath: string; + let execCommand: jest.SpyInstance; + let publishGit: PublishGit; + + beforeAll(() => { + gitPath = '/usr/bin/git'; + process.env.RUSH_GIT_BINARY_PATH = gitPath; + }); + + beforeEach(() => { + execCommand = jest.spyOn(PublishUtilities, 'execCommandAsync').mockImplementation(async () => { + /* no-op */ + }); + + const rushFilename: string = path.resolve(__dirname, '../../api/test/repo/rush-npm.json'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + const git: Git = new Git(rushConfiguration); + publishGit = new PublishGit(git, 'test'); + }); + + afterEach(() => { + execCommand.mockClear(); + }); + + it('Test git with no command line arg tag', async () => { + await publishGit.addTagAsync( + false, + 'project1', + '2', + 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']); + }); + + it('Test git with command line arg tag', async () => { + await publishGit.addTagAsync( + false, + 'project1', + '2', + 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' + ]); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts b/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts new file mode 100644 index 00000000000..a0d127208de --- /dev/null +++ b/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts @@ -0,0 +1,979 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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 { ChangeFiles } from '../ChangeFiles'; + +function generateChangeSnapshot( + allPackages: ReadonlyMap, + allChanges: IChangeRequests +): string { + const unchangedLines: string[] = []; + const changesLines: string[] = []; + for (const project of allPackages.values()) { + const projectName: string = project.packageName; + const currentVersion: string = project.packageJson.version; + const changeInfo: IChangeInfo | undefined = allChanges.packageChanges.get(projectName); + if (changeInfo) { + const changeType: ChangeType | undefined = changeInfo.changeType; + const changeTypeText: string = ChangeType[changeType as number]; + let newVersion: string | undefined = changeInfo.newVersion; + if (newVersion === currentVersion) { + newVersion = '(same)'; + } + + changesLines.push(`${projectName} - ${currentVersion} -> ${newVersion} (${changeTypeText} change)`); + } else { + unchangedLines.push(`${projectName} - ${currentVersion}`); + } + } + + return [ + `== Changed Projects (${changesLines.length}) ==`, + ...changesLines.sort(), + '', + `== Unchanged Projects (${unchangedLines.length}) ==`, + ...unchangedLines.sort() + ].join('\n'); +} + +function generateVersionPolicySnapshot(allChanges: IChangeRequests): string { + const lines: string[] = []; + for (const versionPolicy of allChanges.versionPolicyChanges.values()) { + const versionPolicyName: string = versionPolicy.versionPolicyName; + const changeType: ChangeType | undefined = versionPolicy.changeType; + const changeTypeText: string = ChangeType[changeType as number]; + const newVersion: string = versionPolicy.newVersion; + lines.push(`${versionPolicyName} - ${newVersion} (${changeTypeText} change)`); + } + + return lines.join('\n'); +} + +describe(PublishUtilities.findChangeRequestsAsync.name, () => { + let packagesRushConfiguration: RushConfiguration; + let repoRushConfiguration: RushConfiguration; + + beforeEach(() => { + // The "packages" repo has the following structure (except for the cyclics) + // a -------- + // / | \ | + // / | \ | + // b h e g + // |\ | + // | \ | + // c f i + // | | + // | | + // d j + // + // "h" and "i" are lockstepped + + packagesRushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${__dirname}/packages/rush.json` + ); + + repoRushConfiguration = RushConfiguration.loadFromConfigurationFile(`${__dirname}/repo/rush.json`); + }); + + 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`) + ); + + expect(allChanges.packageChanges.size).toEqual(0); + expect(allChanges.versionPolicyChanges.size).toEqual(0); + }); + + 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`) + ); + + expect(allChanges.packageChanges.size).toEqual(1); + expect(allChanges.versionPolicyChanges.size).toEqual(0); + + expect(allChanges.packageChanges.get('d')).not.toBeUndefined(); + expect(allChanges.packageChanges.get('d')!.changeType).toEqual(ChangeType.patch); + }); + + it('returns 6 changes when patching a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootPatchChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (6) == + a - 1.0.0 -> 1.0.1 (patch change) + b - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> (same) (dependency change) + h - 1.0.0 -> (same) (dependency change) + i - 1.0.0 -> (same) (dependency change) + + == Unchanged Projects (8) == + c - 1.0.0 + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0 + f - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.0 (dependency change)"` + ); + }); + + it('returns 8 changes when hotfixing a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootHotfixChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + b - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + c - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + d - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + e - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + f - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + g - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + h - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + + == Unchanged Projects (6) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('returns 9 changes when major bumping a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootMajorChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> (same) (dependency change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('updates policy project dependencies when updating a lockstep version policy with no nextBump', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/lockstepWithoutNextBump`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (4) == + f - 1.0.0 -> (same) (dependency change) + h - 1.0.0 -> 1.1.0 (minor change) + i - 1.0.0 -> 1.1.0 (minor change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (10) == + a - 1.0.0 + b - 1.0.0 + c - 1.0.0 + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0 + e - 1.0.0 + g - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.1.0 (minor change)"` + ); + }); + + it('returns 2 changes when bumping cyclic dependencies', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/cyclicDeps`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (2) == + cyclic-dep-1 - 1.0.0 -> 2.0.0 (major change) + cyclic-dep-2 - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (12) == + a - 1.0.0 + b - 1.0.0 + c - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0 + e - 1.0.0 + f - 1.0.0 + g - 1.0.0 + h - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('returns error when mixing hotfix and non-hotfix changes', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + await expect( + async () => + await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/hotfixWithPatchChanges`) + ) + ).rejects.toThrow('Cannot apply hotfix alongside patch change on same package'); + }); + + it('returns error when adding hotfix with config disabled', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + // Overload hotfixChangeEnabled function + (packagesRushConfiguration as unknown as Record).hotfixChangeEnabled = false; + + await expect( + async () => + await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootHotfixChange`) + ) + ).rejects.toThrow('Cannot add hotfix change; hotfixChangeEnabled is false in configuration.'); + }); + + it('can resolve multiple changes requests on the same package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/multipleChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> (same) (dependency change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('can resolve multiple reverse-ordered changes requests on the same package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/orderedChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> (same) (dependency change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('can resolve multiple hotfix changes', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/multipleHotfixChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + b - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + c - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + d - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + e - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + f - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + g - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + h - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + + == Unchanged Projects (6) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('can update an explicit dependency', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/explicitVersionChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (2) == + c - 1.0.0 -> 1.0.1 (patch change) + d - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (12) == + a - 1.0.0 + b - 1.0.0 + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + e - 1.0.0 + f - 1.0.0 + g - 1.0.0 + h - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('can exclude lock step projects', async () => { + const allPackages: ReadonlyMap = repoRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + repoRushConfiguration, + new ChangeFiles(`${__dirname}/repo/changes`), + false, + undefined, + new Set(['a', 'b', 'e']) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> (same) (none change) + b - 2.0.0 -> (same) (none change) + c - 3.1.1 -> 3.1.2 (patch change) + d - 4.1.1 -> 4.1.2 (patch change) + e - 10.10.0 -> (same) (none change) + f - 1.0.0 -> (same) (none change) + h - 1.2.3 -> 1.2.4 (patch change) + i - 1.2.3 -> 1.2.4 (patch change) + + == Unchanged Projects (2) == + g - 0.0.1 + j - 1.2.3" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.2.4 (patch change)"` + ); + }); +}); + +describe(PublishUtilities.sortChangeRequests.name, () => { + let rushConfiguration: RushConfiguration; + + beforeEach(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(`${__dirname}/packages/rush.json`); + }); + + it('can return a sorted array of the change requests to be published in the correct order', async () => { + const allPackages: ReadonlyMap = rushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + rushConfiguration, + new ChangeFiles(`${__dirname}/multipleChanges`) + ); + const orderedChanges: IChangeInfo[] = PublishUtilities.sortChangeRequests(allChanges.packageChanges); + + expect(orderedChanges).toHaveLength(9); + expect(orderedChanges[0].packageName).toEqual('a'); + expect(orderedChanges[1].packageName).toEqual('i'); + expect(orderedChanges[2].packageName).toEqual('b'); + expect(orderedChanges[3].packageName).toEqual('e'); + expect(orderedChanges[4].packageName).toEqual('g'); + expect(orderedChanges[5].packageName).toEqual('h'); + expect(orderedChanges[6].packageName).toEqual('j'); + expect(orderedChanges[7].packageName).toEqual('c'); + expect(orderedChanges[8].packageName).toEqual('f'); + }); +}); + +describe(PublishUtilities.isRangeDependency.name, () => { + it('can test ranges', () => { + expect(PublishUtilities.isRangeDependency('>=1.0.0 <2.0.0')).toEqual(true); + expect(PublishUtilities.isRangeDependency('>=1.0.0-pr.1 <2.0.0')).toEqual(true); + expect(PublishUtilities.isRangeDependency('1.0.0')).toEqual(false); + expect(PublishUtilities.isRangeDependency('^1.0.0')).toEqual(false); + expect(PublishUtilities.isRangeDependency('~1.0.0')).toEqual(false); + }); +}); + +describe(PublishUtilities.getNewDependencyVersion.name, () => { + it('can update dependency versions', () => { + const dependencies: { [key: string]: string } = { + a: '~1.0.0', + b: '^1.0.0', + c: '>=1.0.0 <2.0.0' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.1.0')).toEqual('~1.1.0'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.2.0')).toEqual('^1.2.0'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.3.0')).toEqual('>=1.3.0 <2.0.0'); + }); + + it('can update dependency versions with prereleases', () => { + const dependencies: { [key: string]: string } = { + a: '~1.0.0-pr.1', + b: '^1.0.0-pr.1', + c: '>=1.0.0-pr.1 <2.0.0' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.1.0-pr.1')).toEqual('~1.1.0-pr.1'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.2.0-pr.2')).toEqual('^1.2.0-pr.2'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.3.0-pr.3')).toEqual( + '>=1.3.0-pr.3 <2.0.0' + ); + }); + + it('can update to prerelease', () => { + const dependencies: { [key: string]: string } = { + a: '~1.0.0', + b: '^1.0.0', + c: '>=1.0.0 <2.0.0' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.0.0-hotfix.0')).toEqual( + '~1.0.0-hotfix.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.0.0-hotfix.0')).toEqual( + '^1.0.0-hotfix.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.0.0-hotfix.0')).toEqual( + '>=1.0.0-hotfix.0 <2.0.0' + ); + }); +}); + +describe(PublishUtilities.findChangeRequestsAsync.name, () => { + let packagesRushConfiguration: RushConfiguration; + let repoRushConfiguration: RushConfiguration; + + beforeEach(() => { + packagesRushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${__dirname}/workspacePackages/rush.json` + ); + repoRushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${__dirname}/workspaceRepo/rush.json` + ); + }); + + 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`) + ); + + expect(allChanges.packageChanges.size).toEqual(0); + expect(allChanges.versionPolicyChanges.size).toEqual(0); + }); + + 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`) + ); + + expect(allChanges.packageChanges.size).toEqual(1); + expect(allChanges.versionPolicyChanges.size).toEqual(0); + + expect(allChanges.packageChanges.get('d')).not.toBeUndefined(); + expect(allChanges.packageChanges.get('d')!.changeType).toEqual(ChangeType.patch); + }); + + it('returns 6 changes when patching a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootPatchChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (6) == + a - 1.0.0 -> 1.0.1 (patch change) + b - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> 1.0.1 (patch change) + h - 1.0.0 -> (same) (dependency change) + i - 1.0.0 -> (same) (dependency change) + + == Unchanged Projects (8) == + c - 1.0.0 + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0 + f - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.0 (dependency change)"` + ); + }); + + it('returns 8 changes when hotfixing a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootHotfixChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + b - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + c - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + d - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + e - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + f - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + g - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + h - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + + == Unchanged Projects (6) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('returns 9 changes when major bumping a root package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootMajorChange`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> 1.0.1 (patch change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('returns 2 changes when bumping cyclic dependencies', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/cyclicDeps`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (2) == + cyclic-dep-1 - 1.0.0 -> 2.0.0 (major change) + cyclic-dep-2 - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (12) == + a - 1.0.0 + b - 1.0.0 + c - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0 + e - 1.0.0 + f - 1.0.0 + g - 1.0.0 + h - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('returns error when mixing hotfix and non-hotfix changes', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + await expect( + async () => + await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/hotfixWithPatchChanges`) + ) + ).rejects.toThrow('Cannot apply hotfix alongside patch change on same package'); + }); + + it('returns error when adding hotfix with config disabled', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + // Overload hotfixChangeEnabled function + (packagesRushConfiguration as unknown as Record).hotfixChangeEnabled = false; + + await expect( + async () => + await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/rootHotfixChange`) + ) + ).rejects.toThrow('Cannot add hotfix change; hotfixChangeEnabled is false in configuration.'); + }); + + it('can resolve multiple changes requests on the same package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/multipleChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> 1.0.1 (patch change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('can resolve multiple reverse-ordered changes requests on the same package', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/orderedChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (9) == + a - 1.0.0 -> 2.0.0 (major change) + b - 1.0.0 -> 1.0.1 (patch change) + c - 1.0.0 -> (same) (dependency change) + e - 1.0.0 -> 1.0.1 (patch change) + f - 1.0.0 -> (same) (dependency change) + g - 1.0.0 -> 1.0.1 (patch change) + h - 1.0.0 -> 1.0.1 (patch change) + i - 1.0.0 -> 1.0.1 (patch change) + j - 1.0.0 -> 1.0.1 (patch change) + + == Unchanged Projects (5) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + d - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.0.1 (patch change)"` + ); + }); + + it('can resolve multiple hotfix changes', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/multipleHotfixChanges`) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + b - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + c - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + d - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + e - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + f - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + g - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + h - 1.0.0 -> 1.0.0-hotfix.0 (hotfix change) + + == Unchanged Projects (6) == + cyclic-dep-1 - 1.0.0 + cyclic-dep-2 - 1.0.0 + cyclic-dep-explicit-1 - 1.0.0 + cyclic-dep-explicit-2 - 1.0.0 + i - 1.0.0 + j - 1.0.0" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot(`""`); + }); + + it('can update an explicit dependency', async () => { + const allPackages: ReadonlyMap = + packagesRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + packagesRushConfiguration, + new ChangeFiles(`${__dirname}/explicitVersionChange`) + ); + + expect(allChanges.packageChanges.size).toEqual(2); + expect(allChanges.versionPolicyChanges.size).toEqual(0); + + expect(allChanges.packageChanges.get('c')).not.toBeUndefined(); + expect(allChanges.packageChanges.get('d')).not.toBeUndefined(); + + expect(allChanges.packageChanges.get('c')!.changeType).toEqual(ChangeType.patch); + expect(allChanges.packageChanges.get('d')!.changeType).toEqual(ChangeType.patch); + }); + + it('can exclude lock step projects', async () => { + const allPackages: ReadonlyMap = repoRushConfiguration.projectsByName; + const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( + allPackages, + repoRushConfiguration, + new ChangeFiles(`${__dirname}/repo/changes`), + false, + undefined, + new Set(['a', 'b', 'e']) + ); + + expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` + "== Changed Projects (8) == + a - 1.0.0 -> (same) (none change) + b - 2.0.0 -> (same) (none change) + c - 3.1.1 -> 3.1.2 (patch change) + d - 4.1.1 -> 4.1.2 (patch change) + e - 10.10.0 -> (same) (none change) + f - 1.0.0 -> (same) (none change) + h - 1.2.3 -> 1.2.4 (patch change) + i - 1.2.3 -> 1.2.4 (patch change) + + == Unchanged Projects (2) == + g - 0.0.1 + j - 1.2.3" + `); + + expect(generateVersionPolicySnapshot(allChanges)).toMatchInlineSnapshot( + `"lockStepWithoutNextBump - 1.2.4 (patch change)"` + ); + }); +}); + +describe(PublishUtilities.getNewDependencyVersion.name, () => { + it('can update dependency versions', () => { + const dependencies: { [key: string]: string } = { + a: 'workspace:~1.0.0', + b: 'workspace:^1.0.0', + c: 'workspace:>=1.0.0 <2.0.0', + d: 'workspace:*', + e: 'workspace:~', + f: 'workspace:^' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.1.0')).toEqual('workspace:~1.1.0'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.2.0')).toEqual('workspace:^1.2.0'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.3.0')).toEqual( + 'workspace:>=1.3.0 <2.0.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'd', '1.4.0')).toEqual('workspace:*'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'e', '1.5.0')).toEqual('workspace:~'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'f', '1.6.0')).toEqual('workspace:^'); + }); + + it('can update dependency versions with prereleases', () => { + const dependencies: { [key: string]: string } = { + a: 'workspace:~1.0.0-pr.1', + b: 'workspace:^1.0.0-pr.1', + c: 'workspace:>=1.0.0-pr.1 <2.0.0', + d: 'workspace:*', + e: 'workspace:~', + f: 'workspace:^' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.1.0-pr.1')).toEqual( + 'workspace:~1.1.0-pr.1' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.2.0-pr.2')).toEqual( + 'workspace:^1.2.0-pr.2' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.3.0-pr.3')).toEqual( + 'workspace:>=1.3.0-pr.3 <2.0.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'd', '1.3.0-pr.3')).toEqual('workspace:*'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'e', '1.5.0-pr.3')).toEqual('workspace:~'); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'f', '1.6.0-pr.3')).toEqual('workspace:^'); + }); + + it('can update to prerelease', () => { + const dependencies: { [key: string]: string } = { + a: 'workspace:~1.0.0', + b: 'workspace:^1.0.0', + c: 'workspace:>=1.0.0 <2.0.0', + d: 'workspace:*', + e: 'workspace:~', + f: 'workspace:^' + }; + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'a', '1.0.0-hotfix.0')).toEqual( + 'workspace:~1.0.0-hotfix.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'b', '1.0.0-hotfix.0')).toEqual( + 'workspace:^1.0.0-hotfix.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'c', '1.0.0-hotfix.0')).toEqual( + 'workspace:>=1.0.0-hotfix.0 <2.0.0' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'd', '1.0.0-hotfix.0')).toEqual( + 'workspace:*' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'e', '1.0.0-hotfix.0')).toEqual( + 'workspace:~' + ); + expect(PublishUtilities.getNewDependencyVersion(dependencies, 'f', '1.0.0-hotfix.0')).toEqual( + 'workspace:^' + ); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/Selection.test.ts b/libraries/rush-lib/src/logic/test/Selection.test.ts new file mode 100644 index 00000000000..56da6544890 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/Selection.test.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 { type IPartialProject, Selection } from '../Selection'; + +const { union, intersection, expandAllDependencies, expandAllConsumers } = Selection; + +interface ISimpleGraphable extends IPartialProject { + consumingProjects: Set; + toString(): string; +} + +const projectA: ISimpleGraphable = { + dependencyProjects: new Set(), + consumingProjects: new Set(), + toString() { + return 'A'; + } +}; +const projectB: ISimpleGraphable = { + dependencyProjects: new Set(), + consumingProjects: new Set(), + toString() { + return 'B'; + } +}; +const projectC: ISimpleGraphable = { + dependencyProjects: new Set(), + consumingProjects: new Set(), + toString() { + return 'C'; + } +}; +const projectD: ISimpleGraphable = { + dependencyProjects: new Set([projectA, projectB]), + consumingProjects: new Set(), + toString() { + return 'D'; + } +}; +const projectE: ISimpleGraphable = { + dependencyProjects: new Set([projectC, projectD]), + consumingProjects: new Set(), + toString() { + return 'E'; + } +}; +const projectF: ISimpleGraphable = { + dependencyProjects: new Set([projectE]), + consumingProjects: new Set(), + toString() { + return 'F'; + } +}; +const projectG: ISimpleGraphable = { + dependencyProjects: new Set(), + consumingProjects: new Set(), + toString() { + return 'G'; + } +}; +const projectH: ISimpleGraphable = { + dependencyProjects: new Set([projectF, projectG]), + consumingProjects: new Set(), + toString() { + return 'H'; + } +}; + +const nodes: Set = new Set([ + projectA, + projectB, + projectC, + projectD, + projectE, + projectF, + projectG, + projectH +]); + +// Populate the bidirectional graph +for (const node of nodes) { + for (const dep of node.dependencyProjects) { + dep.consumingProjects.add(node); + } +} + +expect.extend({ + toMatchSet(received: ReadonlySet, expected: ReadonlySet): jest.CustomMatcherResult { + for (const element of expected) { + if (!received.has(element)) { + return { + pass: false, + message: () => `Expected [${[...received].join(', ')}] to contain ${element}` + }; + } + } + for (const element of received) { + if (!expected.has(element)) { + return { + pass: false, + message: () => `Expected [${[...received].join(', ')}] to not contain ${element}` + }; + } + } + + return { + pass: true, + message: () => `Expected [${[...received].join(', ')}] to not match [${[...expected].join(', ')}]` + }; + } +}); + +declare global { + // Disabling eslint here because it is needed for module augmentation + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + // eslint-disable-next-line @typescript-eslint/naming-convention + export interface Matchers { + toMatchSet(expected: T): R; + } + } +} + +describe(union.name, () => { + it('combines sets', () => { + const result: ReadonlySet = union( + [projectA, projectB], + [projectC], + [projectA], + [projectB] + ); + + expect(result).toMatchSet(new Set([projectA, projectB, projectC])); + }); +}); + +describe(intersection.name, () => { + it('intersects sets', () => { + const result: ReadonlySet = intersection( + [projectC, projectD], + new Set([projectD, projectE, projectG, projectA]), + new Set([projectD]) + ); + + expect(result).toMatchSet(new Set([projectD])); + }); + + it('will produce the empty set in nothing matches', () => { + const result: ReadonlySet = intersection( + [projectC, projectD], + new Set([projectE, projectG, projectA]), + new Set([projectD]) + ); + + expect(result).toMatchSet(new Set()); + }); + + it('handles identical inputs', () => { + const result: ReadonlySet = intersection(nodes, nodes, nodes); + + expect(result).toMatchSet(nodes); + }); +}); + +describe(expandAllDependencies.name, () => { + it('expands at least one level of dependencies', () => { + const result: ReadonlySet = expandAllDependencies([projectD]); + + expect(result).toMatchSet(new Set([projectA, projectB, projectD])); + }); + it('expands all levels of dependencies', () => { + const result: ReadonlySet = expandAllDependencies([projectF]); + + expect(result).toMatchSet(new Set([projectA, projectB, projectC, projectD, projectE, projectF])); + }); + it('handles multiple inputs', () => { + const result: ReadonlySet = expandAllDependencies([projectC, projectD]); + + expect(result).toMatchSet(new Set([projectA, projectB, projectC, projectD])); + }); +}); + +describe(expandAllConsumers.name, () => { + it('expands at least one level of dependents', () => { + const result: ReadonlySet = expandAllConsumers([projectF]); + + expect(result).toMatchSet(new Set([projectF, projectH])); + }); + it('expands all levels of dependents', () => { + const result: ReadonlySet = expandAllConsumers([projectC]); + + expect(result).toMatchSet(new Set([projectC, projectE, projectF, projectH])); + }); + it('handles multiple inputs', () => { + const result: ReadonlySet = expandAllConsumers([projectC, projectB]); + + expect(result).toMatchSet(new Set([projectB, projectC, projectD, projectE, projectF, projectH])); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts new file mode 100644 index 00000000000..7211e1af79f --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts @@ -0,0 +1,352 @@ +// 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 { JsonFile } from '@rushstack/node-core-library'; + +import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; +import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; +import { + parsePnpmDependencyKey, + PnpmShrinkwrapFile, + ShrinkwrapFileMajorVersion +} from '../pnpm/PnpmShrinkwrapFile'; +import { DependencySpecifier } from '../DependencySpecifier'; +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)!; + + it('verifies root-level dependency', () => { + expect(shrinkwrapFile.hasCompatibleTopLevelDependency(new DependencySpecifier('q', '~1.5.0'))).toEqual( + true + ); + }); + + it('verifies temp project dependencies', () => { + // Found locally + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('jquery', '>=2.2.4 <3.0.0'), + '@rush-temp/project2' + ) + ).toEqual(true); + // Found at root + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('q', '~1.5.0'), + '@rush-temp/project2' + ) + ).toEqual(true); + }); + + it('extracts temp projects successfully', () => { + const tempProjectNames: ReadonlyArray = shrinkwrapFile.getTempProjectNames(); + + expect(tempProjectNames).toEqual(['@rush-temp/project1', '@rush-temp/project2']); + }); +}); + +describe(PnpmShrinkwrapFile.name, () => { + describe('non-workspace', () => { + function validateNonWorkspaceLockfile(shrinkwrapFile: BaseShrinkwrapFile): void { + it('verifies root-level dependency', () => { + expect( + shrinkwrapFile.hasCompatibleTopLevelDependency(new DependencySpecifier('q', '~1.5.0')) + ).toEqual(false); + }); + + it('verifies temp project dependencies', () => { + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('jquery', '>=1.0.0 <2.0.0'), + '@rush-temp/project1' + ) + ).toEqual(true); + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('q', '~1.5.0'), + '@rush-temp/project2' + ) + ).toEqual(true); + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('pad-left', '^2.0.0'), + '@rush-temp/project1' + ) + ).toEqual(false); + + if ( + shrinkwrapFile instanceof PnpmShrinkwrapFile && + shrinkwrapFile.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 + ) { + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier( + '@scope/testDep', + 'https://github.com/jonschlinkert/pad-left/tarball/2.1.0' + ), + '@rush-temp/project3' + ) + ).toEqual(true); + } else { + expect( + shrinkwrapFile.tryEnsureCompatibleDependency( + new DependencySpecifier('@scope/testDep', '>=2.0.0 <3.0.0'), + '@rush-temp/project3' + ) + ).toEqual(true); + } + }); + + it('extracts temp projects successfully', () => { + const tempProjectNames: ReadonlyArray = shrinkwrapFile.getTempProjectNames(); + + expect(tempProjectNames).toEqual([ + '@rush-temp/project1', + '@rush-temp/project2', + '@rush-temp/project3' + ]); + }); + } + + describe('V5.0 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateNonWorkspaceLockfile(shrinkwrapFile); + }); + + describe('V5.3 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.3.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateNonWorkspaceLockfile(shrinkwrapFile); + }); + + describe('V6.1 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v6.1.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateNonWorkspaceLockfile(shrinkwrapFile); + }); + + describe('V9 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + validateNonWorkspaceLockfile(shrinkwrapFile); + }); + }); + + describe('workspace', () => { + let jsonSaveAsyncSpy: jest.SpyInstance; + beforeEach(() => { + jsonSaveAsyncSpy = jest.spyOn(JsonFile, 'saveAsync').mockReturnValue(Promise.resolve(true)); + }); + + afterEach(() => { + jsonSaveAsyncSpy.mockRestore(); + }); + + function validateWorkspaceLockfile(shrinkwrapFile: BaseShrinkwrapFile): void { + it('verifies project dependencies', async () => { + const projectNames: string[] = ['project1', 'project2', 'project3']; + for (const projectName of projectNames) { + jsonSaveAsyncSpy.mockClear(); + const rushConfigurationProject: RushConfigurationProject = { + projectRushTempFolder: `${projectName}/.rush/temp`, + projectFolder: projectName, + rushConfiguration: { + commonTempFolder: 'common/temp' + }, + subspace: { + getSubspaceTempFolderPath: () => 'common/temp' + } + } as RushConfigurationProject; + + const projectShrinkwrap = shrinkwrapFile.getProjectShrinkwrap(rushConfigurationProject); + await projectShrinkwrap?.updateProjectShrinkwrapAsync(); + expect(jsonSaveAsyncSpy).toHaveBeenCalledTimes(1); + expect(jsonSaveAsyncSpy.mock.calls).toMatchSnapshot(projectName); + } + }); + + it('does not have any temp projects', () => { + const tempProjectNames: ReadonlyArray = shrinkwrapFile.getTempProjectNames(); + expect(tempProjectNames).toHaveLength(0); + }); + } + + describe('V5.3 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateWorkspaceLockfile(shrinkwrapFile); + }); + + describe('V6.1 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml' + ); + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateWorkspaceLockfile(shrinkwrapFile); + }); + + describe('V9 lockfile', () => { + const filename: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml' + ); + + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + + validateWorkspaceLockfile(shrinkwrapFile); + }); + }); +}); + +function testParsePnpmDependencyKey(packageName: string, key: string): string | undefined { + const specifier: DependencySpecifier | undefined = parsePnpmDependencyKey(packageName, key); + if (!specifier) { + return undefined; + } + return specifier.versionSpecifier; +} + +describe(parsePnpmDependencyKey.name, () => { + it('extracts a simple version with no slashes', () => { + expect(testParsePnpmDependencyKey('anonymous', '0.0.5')).toEqual('0.0.5'); + }); + it('extracts a simple package name', () => { + expect(testParsePnpmDependencyKey('isarray', '/isarray/2.0.5')).toEqual('2.0.5'); + expect(testParsePnpmDependencyKey('@scope/test-dep', '/@scope/test-dep/1.2.3-beta.3')).toEqual( + '1.2.3-beta.3' + ); + }); + it('extracts a registry-qualified path', () => { + expect( + testParsePnpmDependencyKey('@scope/test-dep', 'example.pkgs.visualstudio.com/@scope/test-dep/1.0.0') + ).toEqual('1.0.0'); + expect( + testParsePnpmDependencyKey( + '@scope/test-dep', + 'example.pkgs.visualstudio.com/@scope/test-dep/1.2.3-beta.3' + ) + ).toEqual('1.2.3-beta.3'); + }); + it('extracts a V3 peer dependency path', () => { + expect(testParsePnpmDependencyKey('gulp-karma', '/gulp-karma/0.0.5/karma@0.13.22')).toEqual('0.0.5'); + expect(testParsePnpmDependencyKey('sinon-chai', '/sinon-chai/2.8.0/chai@3.5.0+sinon@1.17.7')).toEqual( + '2.8.0' + ); + expect( + testParsePnpmDependencyKey('@ms/sp-client-utilities', '/@ms/sp-client-utilities/3.1.1/foo@13.1.0') + ).toEqual('3.1.1'); + expect( + testParsePnpmDependencyKey( + 'tslint-microsoft-contrib', + '/tslint-microsoft-contrib/6.2.0/tslint@5.18.0+typescript@3.5.3' + ) + ).toEqual('6.2.0'); + }); + it('extracts a V5 peer dependency path', () => { + expect(testParsePnpmDependencyKey('anonymous', '23.6.0_babel-core@6.26.3')).toEqual('23.6.0'); + expect(testParsePnpmDependencyKey('anonymous', '1.0.7_request@2.88.0')).toEqual('1.0.7'); + expect(testParsePnpmDependencyKey('anonymous', '1.0.3_@pnpm+logger@1.0.2')).toEqual('1.0.3'); + expect( + testParsePnpmDependencyKey( + 'tslint-microsoft-contrib', + '/tslint-microsoft-contrib/6.2.0_tslint@5.18.0+typescript@3.5.3' + ) + ).toEqual('6.2.0'); + }); + it('detects NPM package aliases', () => { + expect(testParsePnpmDependencyKey('alias1', '/isarray/2.0.5')).toEqual('npm:isarray@2.0.5'); + expect(testParsePnpmDependencyKey('alias2', '/@ms/sp-client-utilities/3.1.1/foo@13.1.0')).toEqual( + 'npm:@ms/sp-client-utilities@3.1.1' + ); + }); + it('detects urls', () => { + expect( + testParsePnpmDependencyKey('example', '@github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64') + ).toEqual('@github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect( + testParsePnpmDependencyKey('example', 'github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64') + ).toEqual('github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect( + testParsePnpmDependencyKey('example', 'bitbucket.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64') + ).toEqual('bitbucket.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft.github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual('microsoft.github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft.github/.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual('microsoft.github/.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect( + testParsePnpmDependencyKey('example', 'ab.cd.ef.gh/ijkl/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64') + ).toEqual('ab.cd.ef.gh/ijkl/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64'); + expect(testParsePnpmDependencyKey('example', 'ab.cd/ef')).toEqual('ab.cd/ef'); + }); + it('handles bad cases', () => { + expect(testParsePnpmDependencyKey('example', '/foo/gulp-karma/0.0.5/karma@0.13.22')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', '/@ms/3.1.1/foo@13.1.0')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', 'file:projects/my-app.tgz')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', '')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', '/')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', '//')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', '/@/')).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', 'example.pkgs.visualstudio.com/@scope/testDep/')).toEqual( + undefined + ); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft.github.com/abc\\def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual(undefined); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft.github.com/abc/def//abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual(undefined); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft./github.com/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual(undefined); + expect( + testParsePnpmDependencyKey( + 'example', + 'microsoft/abc/github/abc/def/abcdef2fbd0260e6e56ed5ba34df0f5b6599bbe64' + ) + ).toEqual(undefined); + expect(testParsePnpmDependencyKey('example', 'ab.cd/ef/')).toEqual(undefined); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/Telemetry.test.ts b/libraries/rush-lib/src/logic/test/Telemetry.test.ts new file mode 100644 index 00000000000..aebc60ef4a9 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/Telemetry.test.ts @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { JsonFile } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../api/RushConfiguration'; +import { Rush } from '../../api/Rush'; +import { Telemetry, type ITelemetryData, type ITelemetryMachineInfo } from '../Telemetry'; +import { RushSession } from '../../pluginFramework/RushSession'; + +interface ITelemetryPrivateMembers extends Omit { + _flushAsyncTasks: Map>; +} + +describe(Telemetry.name, () => { + const mockedJsonFileSave: jest.SpyInstance = jest.spyOn(JsonFile, 'save').mockImplementation(() => { + /* don't actually write anything */ + return true; + }); + + beforeEach(() => { + performance.clearMarks(); + performance.clearMeasures(); + jest.clearAllMocks(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + it('adds data to store if telemetry is enabled', () => { + const filename: string = `${__dirname}/telemetry/telemetryEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const telemetry: Telemetry = new Telemetry(rushConfig, rushSession); + const logData1: ITelemetryData = { + name: 'testData1', + durationInSeconds: 100, + result: 'Succeeded', + timestampMs: new Date().getTime(), + platform: process.platform, + rushVersion: Rush.version, + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] + }; + + const logData2: ITelemetryData = { + name: 'testData2', + durationInSeconds: 100, + result: 'Failed', + timestampMs: new Date().getTime(), + platform: process.platform, + rushVersion: Rush.version, + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] + }; + + telemetry.log(logData1); + telemetry.log(logData2); + expect(telemetry.store).toEqual([logData1, logData2]); + }); + + it('does not add data to store if telemetry is not enabled', () => { + const filename: string = `${__dirname}/telemetry/telemetryNotEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const telemetry: Telemetry = new Telemetry(rushConfig, rushSession); + const logData: ITelemetryData = { + name: 'testData', + durationInSeconds: 100, + result: 'Succeeded', + timestampMs: new Date().getTime(), + platform: process.platform, + rushVersion: Rush.version + }; + + telemetry.log(logData); + expect(telemetry.store).toEqual([]); + }); + + it('deletes data after flush', () => { + const filename: string = `${__dirname}/telemetry/telemetryEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const telemetry: Telemetry = new Telemetry(rushConfig, rushSession); + const logData: ITelemetryData = { + name: 'testData1', + durationInSeconds: 100, + result: 'Succeeded', + timestampMs: new Date().getTime(), + platform: process.platform, + rushVersion: Rush.version, + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] + }; + + telemetry.log(logData); + telemetry.flush(); + expect(mockedJsonFileSave).toHaveBeenCalledTimes(1); + expect(mockedJsonFileSave).toHaveBeenCalledWith( + [logData], + expect.stringMatching(/telemetry_.*\.json/), + expect.anything() + ); + expect(telemetry.store).toEqual([]); + }); + + it('populates default fields', () => { + const filename: string = `${__dirname}/telemetry/telemetryEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const telemetry: Telemetry = new Telemetry(rushConfig, rushSession); + const logData: ITelemetryData = { + name: 'testData1', + durationInSeconds: 100, + result: 'Succeeded' + }; + + telemetry.log(logData); + const result: ITelemetryData = telemetry.store[0]; + expect(result.platform).toEqual(process.platform); + expect(result.rushVersion).toEqual(Rush.version); + expect(result.timestampMs).toBeDefined(); + }); + + it('calls custom flush telemetry', async () => { + const filename: string = `${__dirname}/telemetry/telemetryEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const customFlushTelemetry: jest.Mock = jest.fn(); + rushSession.hooks.flushTelemetry.tap('test', customFlushTelemetry); + const telemetry: ITelemetryPrivateMembers = new Telemetry( + rushConfig, + rushSession + ) as unknown as ITelemetryPrivateMembers; + const logData: ITelemetryData = { + name: 'testData1', + durationInSeconds: 100, + result: 'Succeeded' + }; + + telemetry.log(logData); + telemetry.flush(); + expect(customFlushTelemetry).toHaveBeenCalledTimes(1); + expect(customFlushTelemetry.mock.calls[0][0][0]).toEqual(expect.objectContaining(logData)); + + await telemetry.ensureFlushedAsync(); + + // Ensure the tasks get cleaned up + expect(telemetry._flushAsyncTasks.size).toEqual(0); + }); + + it('calls custom flush telemetry twice', async () => { + const filename: string = `${__dirname}/telemetry/telemetryEnabled.json`; + const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile(filename); + const rushSession: RushSession = new RushSession({ + terminalProvider: new ConsoleTerminalProvider(), + getIsDebugMode: () => false + }); + const customFlushTelemetry: jest.Mock = jest.fn(); + rushSession.hooks.flushTelemetry.tap('test', customFlushTelemetry); + const telemetry: ITelemetryPrivateMembers = new Telemetry( + rushConfig, + rushSession + ) as unknown as ITelemetryPrivateMembers; + const logData: ITelemetryData = { + name: 'testData1', + durationInSeconds: 100, + result: 'Succeeded' + }; + + telemetry.log(logData); + telemetry.flush(); + expect(customFlushTelemetry).toHaveBeenCalledTimes(1); + expect(customFlushTelemetry.mock.calls[0][0][0]).toEqual(expect.objectContaining(logData)); + + const logData2: ITelemetryData = { + name: 'testData2', + durationInSeconds: 200, + result: 'Failed' + }; + + telemetry.log(logData2); + telemetry.flush(); + expect(customFlushTelemetry).toHaveBeenCalledTimes(2); + expect(customFlushTelemetry.mock.calls[1][0][0]).toEqual(expect.objectContaining(logData2)); + + await telemetry.ensureFlushedAsync(); + + // Ensure the tasks get cleaned up + expect(telemetry._flushAsyncTasks.size).toEqual(0); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/VersionManager.test.ts b/libraries/rush-lib/src/logic/test/VersionManager.test.ts new file mode 100644 index 00000000000..fe8ec8b11a1 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/VersionManager.test.ts @@ -0,0 +1,204 @@ +// 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 { BumpType } from '../../api/VersionPolicy'; +import type { ChangeFile } from '../../api/ChangeFile'; +import { ChangeType, type IChangeInfo } from '../../api/ChangeManagement'; +import { RushConfiguration } from '../../api/RushConfiguration'; +import { VersionManager } from '../VersionManager'; + +function _getChanges(changeFiles: Map, packageName: string): IChangeInfo[] | undefined { + const changeFile: ChangeFile | undefined = changeFiles.get(packageName); + if (!changeFile) { + return undefined; + } + return changeFile.getChanges(packageName); +} + +describe(VersionManager.name, () => { + const rushJsonFile: string = `${__dirname}/repo/rush.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + let versionManager: VersionManager; + + beforeEach(() => { + versionManager = new VersionManager( + rushConfiguration, + 'test@microsoft.com', + rushConfiguration.versionPolicyConfiguration + ); + }); + + /* eslint-disable dot-notation */ + describe(VersionManager.prototype.ensure.name, () => { + it('fixes lock step versions', () => { + versionManager.ensure('testPolicy1'); + versionManager.ensure('lockStepWithoutNextBump'); + const updatedPackages: Map = versionManager.updatedProjects; + + expect(updatedPackages.size).toEqual(7); + expect(updatedPackages.get('a')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('b')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('b')!.dependencies!['a']).toEqual('~10.10.0'); + expect(updatedPackages.get('c')!.version).toEqual('3.1.1'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`>=10.10.0 <11.0.0`); + expect(updatedPackages.get('d')!.version).toEqual('4.1.1'); + expect(updatedPackages.get('d')!.dependencies!['b']).toEqual(`>=10.10.0 <11.0.0`); + expect(updatedPackages.get('f')!.version).toEqual('1.0.0'); + expect(updatedPackages.get('f')!.dependencies!['a']).toEqual(`~10.10.0`); + expect(updatedPackages.get('f')!.dependencies!['h']).toEqual(`^1.2.3`); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`~10.10.0`); + expect(updatedPackages.get('h')!.version).toEqual('1.2.3'); + expect(updatedPackages.get('h')!.dependencies!['a']).toEqual(`~10.10.0`); + + const changeFiles: Map = versionManager.changeFiles; + expect(changeFiles.size).toEqual(5); + expect(_getChanges(changeFiles, 'a')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'a')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'b')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'b')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'c')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'c')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'c')![1].changeType).toEqual(ChangeType.dependency); + expect(_getChanges(changeFiles, 'd')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'd')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'd')![1].changeType).toEqual(ChangeType.dependency); + expect(_getChanges(changeFiles, 'h')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'h')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'h')![1].changeType).toEqual(ChangeType.dependency); + }); + + it('fixes major version for individual version policy', () => { + versionManager.ensure('testPolicy2'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(2); + expect(updatedPackages.get('c')!.version).toEqual('5.0.0'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`>=2.0.0 <3.0.0`); + expect(updatedPackages.get('e')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('e')!.dependencies!['c']).toEqual('~5.0.0'); + }); + + it('does not change packageJson if not needed by individual version policy', () => { + versionManager.ensure('testPolicy3'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(0); + }); + }); + + describe(VersionManager.prototype.bumpAsync.name, () => { + it('bumps a lockStepPolicy to prerelease version', async () => { + await versionManager.bumpAsync('testPolicy1', BumpType.prerelease, 'dev', false); + const updatedPackages: Map = versionManager.updatedProjects; + const changeFiles: Map = versionManager.changeFiles; + + const expectedVersion: string = '10.10.1-dev.0'; + expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('e')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`~${expectedVersion}`); + expect(_getChanges(changeFiles, 'a')).not.toBeDefined(); + expect(_getChanges(changeFiles, 'b')).not.toBeDefined(); + }); + + it('bumps a lockStepPolicy without bumpType to prerelease version', async () => { + await versionManager.bumpAsync('lockStepWithoutNextBump', BumpType.prerelease, 'dev', false); + const updatedPackages: Map = versionManager.updatedProjects; + const changeFiles: Map = versionManager.changeFiles; + + const expectedVersion: string = '1.2.4-dev.0'; + expect(updatedPackages.get('h')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('f')!.dependencies!['h']).toEqual(`^${expectedVersion}`); + expect(_getChanges(changeFiles, 'h')).not.toBeDefined(); + }); + }); + /* eslint-enable dot-notation */ +}); + +describe(`${VersionManager.name} (workspace)`, () => { + const rushJsonFile: string = `${__dirname}/workspaceRepo/rush.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + let versionManager: VersionManager; + + beforeEach(() => { + versionManager = new VersionManager( + rushConfiguration, + 'test@microsoft.com', + rushConfiguration.versionPolicyConfiguration + ); + }); + + /* eslint-disable dot-notation */ + describe(VersionManager.prototype.ensure.name, () => { + it('fixes lock step versions', () => { + versionManager.ensure('testPolicy1'); + versionManager.ensure('lockStepWithoutNextBump'); + const updatedPackages: Map = versionManager.updatedProjects; + + expect(updatedPackages.size).toEqual(7); + expect(updatedPackages.get('a')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('b')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('b')!.dependencies!['a']).toEqual(`workspace:~10.10.0`); + expect(updatedPackages.get('c')!.version).toEqual('3.1.1'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`workspace:>=10.10.0 <11.0.0`); + expect(updatedPackages.get('d')!.version).toEqual('4.1.1'); + expect(updatedPackages.get('d')!.dependencies!['b']).toEqual(`workspace:>=10.10.0 <11.0.0`); + expect(updatedPackages.get('f')!.version).toEqual('1.0.0'); + expect(updatedPackages.get('f')!.dependencies!['a']).toEqual(`workspace:~10.10.0`); + expect(updatedPackages.get('f')!.dependencies!['h']).toEqual(`workspace:^1.2.3`); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`workspace:~10.10.0`); + expect(updatedPackages.get('h')!.version).toEqual('1.2.3'); + expect(updatedPackages.get('h')!.dependencies!['a']).toEqual(`workspace:~10.10.0`); + + const changeFiles: Map = versionManager.changeFiles; + expect(changeFiles.size).toEqual(5); + expect(_getChanges(changeFiles, 'a')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'a')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'b')!).toHaveLength(1); + expect(_getChanges(changeFiles, 'b')![0].changeType).toEqual(ChangeType.none); + expect(_getChanges(changeFiles, 'c')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'c')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'c')![1].changeType).toEqual(ChangeType.dependency); + expect(_getChanges(changeFiles, 'd')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'd')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'd')![1].changeType).toEqual(ChangeType.dependency); + expect(_getChanges(changeFiles, 'h')!).toHaveLength(2); + expect(_getChanges(changeFiles, 'h')![0].changeType).toEqual(ChangeType.patch); + expect(_getChanges(changeFiles, 'h')![1].changeType).toEqual(ChangeType.dependency); + }); + + it('fixes major version for individual version policy', () => { + versionManager.ensure('testPolicy2'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(2); + expect(updatedPackages.get('c')!.version).toEqual('5.0.0'); + expect(updatedPackages.get('c')!.dependencies!['b']).toEqual(`workspace:>=2.0.0 <3.0.0`); + expect(updatedPackages.get('e')!.version).toEqual('10.10.0'); + expect(updatedPackages.get('e')!.dependencies!['c']).toEqual('workspace:~5.0.0'); + }); + + it('does not change packageJson if not needed by individual version policy', () => { + versionManager.ensure('testPolicy3'); + const updatedPackages: Map = versionManager.updatedProjects; + expect(updatedPackages.size).toEqual(0); + }); + }); + + describe(VersionManager.prototype.bumpAsync.name, () => { + it('bumps to prerelease version', async () => { + await versionManager.bumpAsync('testPolicy1', BumpType.prerelease, 'dev', false); + const updatedPackages: Map = versionManager.updatedProjects; + const expectedVersion: string = '10.10.1-dev.0'; + + const changeFiles: Map = versionManager.changeFiles; + + expect(updatedPackages.get('a')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('b')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('e')!.version).toEqual(expectedVersion); + expect(updatedPackages.get('g')!.devDependencies!['a']).toEqual(`workspace:~${expectedVersion}`); + expect(_getChanges(changeFiles, 'a')).not.toBeDefined(); + expect(_getChanges(changeFiles, 'b')).not.toBeDefined(); + }); + }); + /* eslint-enable dot-notation */ +}); 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 new file mode 100644 index 00000000000..7f122921b53 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/__snapshots__/InstallHelpers.test.ts.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InstallHelpers generateCommonPackageJson generates correct package json with pnpm configurations: Terminal Output 1`] = ` +Object { + "debug": "", + "error": "", + "output": "", + "verbose": "", + "warning": "", +} +`; 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 new file mode 100644 index 00000000000..f784a772885 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ProjectImpactGraphGenerator.test.ts.snap @@ -0,0 +1,292 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""packages""): Output file data 1`] = ` +"globalExcludedGlobs: + - common/autoinstallers/** +projects: + a: + includedGlobs: + - a/** + dependentProjects: + - a + - b + - e + - g + - h + b: + includedGlobs: + - b/** + dependentProjects: + - b + - c + - f + c: + includedGlobs: + - c/** + dependentProjects: + - c + - d + cyclic-dep-1: + includedGlobs: + - cyclic-dep-1/** + dependentProjects: + - cyclic-dep-1 + - cyclic-dep-2 + cyclic-dep-2: + includedGlobs: + - cyclic-dep-2/** + dependentProjects: + - cyclic-dep-1 + - cyclic-dep-2 + cyclic-dep-explicit-1: + includedGlobs: + - cyclic-dep-explicit-1/** + dependentProjects: + - cyclic-dep-explicit-1 + cyclic-dep-explicit-2: + includedGlobs: + - cyclic-dep-explicit-2/** + dependentProjects: + - cyclic-dep-explicit-1 + - cyclic-dep-explicit-2 + d: + includedGlobs: + - d/** + dependentProjects: + - d + e: + includedGlobs: + - e/** + dependentProjects: + - e + f: + includedGlobs: + - f/** + dependentProjects: + - f + g: + includedGlobs: + - g/** + dependentProjects: + - g + h: + includedGlobs: + - h/** + dependentProjects: + - f + - h + i: + includedGlobs: + - i/** + dependentProjects: + - i + - j + j: + includedGlobs: + - j/** + dependentProjects: + - j +" +`; + +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": "", +} +`; + +exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""repo""): Output file data 1`] = ` +"globalExcludedGlobs: + - common/autoinstallers/** +projects: + a: + includedGlobs: + - a/** + dependentProjects: + - a + - b + - f + - g + - h + b: + includedGlobs: + - b/** + dependentProjects: + - b + - c + - d + c: + includedGlobs: + - c/** + dependentProjects: + - c + - e + d: + includedGlobs: + - d/** + dependentProjects: + - d + e: + includedGlobs: + - e/** + dependentProjects: + - e + f: + includedGlobs: + - f/** + dependentProjects: + - f + g: + includedGlobs: + - g/** + dependentProjects: + - g + h: + includedGlobs: + - h/** + dependentProjects: + - f + - h + i: + includedGlobs: + - i/** + dependentProjects: + - i + j: + includedGlobs: + - j/** + dependentProjects: + - j +" +`; + +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": "", +} +`; + +exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""workspacePackages""): Output file data 1`] = ` +"globalExcludedGlobs: + - common/config/version-policies.json +projects: + a: + includedGlobs: + - a/** + dependentProjects: + - a + - b + - e + - g + - h + b: + includedGlobs: + - b/** + dependentProjects: + - b + - c + - f + c: + includedGlobs: + - c/** + dependentProjects: + - c + - d + cyclic-dep-1: + includedGlobs: + - cyclic-dep-1/** + dependentProjects: + - cyclic-dep-1 + - cyclic-dep-2 + cyclic-dep-2: + includedGlobs: + - cyclic-dep-2/** + dependentProjects: + - cyclic-dep-1 + - cyclic-dep-2 + cyclic-dep-explicit-1: + includedGlobs: + - cyclic-dep-explicit-1/** + dependentProjects: + - cyclic-dep-explicit-1 + cyclic-dep-explicit-2: + includedGlobs: + - cyclic-dep-explicit-2/** + dependentProjects: + - cyclic-dep-explicit-1 + - cyclic-dep-explicit-2 + d: + includedGlobs: + - d/** + dependentProjects: + - d + e: + includedGlobs: + - e/** + dependentProjects: + - e + excludedGlobs: + - e/src/** + f: + includedGlobs: + - f/** + dependentProjects: + - f + g: + includedGlobs: + - g/** + dependentProjects: + - g + h: + includedGlobs: + - h/** + dependentProjects: + - f + - h + i: + includedGlobs: + - i/** + dependentProjects: + - i + - j + j: + includedGlobs: + - j/** + dependentProjects: + - j +" +`; + +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": "", +} +`; + +exports[`ProjectImpactGraphGenerator validateAsync Reports if the project-impact-graph.yaml file is missing (repo: ""workspacePackages""): Terminal Output 1`] = ` +Object { + "debug": "", + "error": "", + "output": "", + "verbose": "", + "warning": "", +} +`; 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 new file mode 100644 index 00000000000..19e3d2ae2fd --- /dev/null +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap @@ -0,0 +1,151 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PnpmShrinkwrapFile workspace V5.3 lockfile verifies project dependencies: project1 1`] = ` +Array [ + Array [ + Object { + "../../project1": "../../project1:D5ar2j+w6/zH15/eOoF37Nkdbamt2tX47iijyj7LVXk=:", + "/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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V5.3 lockfile verifies project dependencies: project2 1`] = ` +Array [ + Array [ + Object { + "../../project2": "../../project2:PQ2FvyHHwmt/FIUaiJBVAfpHv6hj9EGJrAw69+0IY50=:", + "/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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V5.3 lockfile verifies project dependencies: project3 1`] = ` +Array [ + Array [ + Object { + "../../project3": "../../project3:jomsZKvXG32qqYOfW3HUBGfWWSw6ybFV1WDf9c/kiP4=:", + "/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", + Object { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V6.1 lockfile verifies project dependencies: project1 1`] = ` +Array [ + Array [ + Object { + "../../project1": "../../project1:D5ar2j+w6/zH15/eOoF37Nkdbamt2tX47iijyj7LVXk=:", + "/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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V6.1 lockfile verifies project dependencies: project2 1`] = ` +Array [ + Array [ + Object { + "../../project2": "../../project2:PQ2FvyHHwmt/FIUaiJBVAfpHv6hj9EGJrAw69+0IY50=:", + "/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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V6.1 lockfile verifies project dependencies: project3 1`] = ` +Array [ + Array [ + Object { + "../../project3": "../../project3:jomsZKvXG32qqYOfW3HUBGfWWSw6ybFV1WDf9c/kiP4=:", + "/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", + Object { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project1 1`] = ` +Array [ + Array [ + Object { + "../../project1": "../../project1:6yFTI2g+Ny0Au80xpo6zIY61TCNDUuLUd6EgLlbOBtc=:", + "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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project2 1`] = ` +Array [ + Array [ + Object { + "../../project2": "../../project2:l6v/HWUhScMI0m4k6D5qHiCOFj3Z0GoIFJEcp4I63w0=:", + "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 { + "ensureFolderExists": true, + }, + ], +] +`; + +exports[`PnpmShrinkwrapFile workspace V9 lockfile verifies project dependencies: project3 1`] = ` +Array [ + 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": "q@1.5.0:lSldncUZjX1nP6wk6WAWwPXA6wLli1dIBnuA3SPeIE4=:", + "repeat-string@1.6.1": "repeat-string@1.6.1:YqQsoCDmP4kj4raEmb5SYE4GsoFGxpBoRbOA/U9rqB4=:", + }, + "project3/.rush/temp/shrinkwrap-deps.json", + Object { + "ensureFolderExists": true, + }, + ], +] +`; diff --git a/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json b/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json new file mode 100644 index 00000000000..d3f1ec72409 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/a/changeA.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "@ms/a", + "type": "patch", + "comment": "Patching a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json b/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json new file mode 100644 index 00000000000..ce8dce3708b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/categorizedChanges/@ms/b/changeB.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "@ms/b", + "type": "patch", + "comment": "Patching b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/categorizedChanges/changeC.json b/libraries/rush-lib/src/logic/test/categorizedChanges/changeC.json new file mode 100644 index 00000000000..81eaa9cb51c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/categorizedChanges/changeC.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patching c" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/a/package.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/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/logic/test/customShellCommandinBulkOverrideScriptsRepo/b/package.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/b/package.json new file mode 100644 index 00000000000..8b915354e7c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/b/package.json @@ -0,0 +1,10 @@ +{ + "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", + "echo": "fake_echo_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..4070ff96146 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/common/config/rush/command-line.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "echo", + "summary": "execute 'echo' command", + "description": "execute 'echo' command for selected project", + "enableParallelism": true, + "shellCommand": "echo custom shellCommand" + } + ], + "parameters": [ + { + "longName": "--flag-for-echo", + "description": "This flag should be usable for build and rebuild commands.", + "parameterKind": "flag", + "associatedCommands": ["echo"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/rush.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/rush.json new file mode 100644 index 00000000000..f39da1606c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkOverrideScriptsRepo/rush.json @@ -0,0 +1,17 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.5.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/a/package.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/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/apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/b/package.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/b/package.json similarity index 100% rename from apps/rush-lib/src/cli/test/basicAndRunBuildActionRepo/b/package.json rename to libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/b/package.json diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..4070ff96146 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/common/config/rush/command-line.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "echo", + "summary": "execute 'echo' command", + "description": "execute 'echo' command for selected project", + "enableParallelism": true, + "shellCommand": "echo custom shellCommand" + } + ], + "parameters": [ + { + "longName": "--flag-for-echo", + "description": "This flag should be usable for build and rebuild commands.", + "parameterKind": "flag", + "associatedCommands": ["echo"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/rush.json b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/rush.json new file mode 100644 index 00000000000..f39da1606c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/customShellCommandinBulkRepo/rush.json @@ -0,0 +1,17 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.5.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/cyclicDeps/change.json b/libraries/rush-lib/src/logic/test/cyclicDeps/change.json new file mode 100644 index 00000000000..fdf8e9c909a --- /dev/null +++ b/libraries/rush-lib/src/logic/test/cyclicDeps/change.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "cyclic-dep-1", + "type": "major", + "comment": "Major change to cyclic dep" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/cyclicDepsExplicit/change.json b/libraries/rush-lib/src/logic/test/cyclicDepsExplicit/change.json new file mode 100644 index 00000000000..4d5b86fc47e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/cyclicDepsExplicit/change.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "cyclic-dep-explicit-1", + "type": "major", + "comment": "Major change to cyclic dep" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/exampleChangelog/CHANGELOG.json b/libraries/rush-lib/src/logic/test/exampleChangelog/CHANGELOG.json similarity index 100% rename from apps/rush-lib/src/logic/test/exampleChangelog/CHANGELOG.json rename to libraries/rush-lib/src/logic/test/exampleChangelog/CHANGELOG.json diff --git a/libraries/rush-lib/src/logic/test/exampleInvalidChangelog/emptyFile/CHANGELOG.json b/libraries/rush-lib/src/logic/test/exampleInvalidChangelog/emptyFile/CHANGELOG.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/rush-lib/src/logic/test/exampleInvalidChangelog/emptyObject/CHANGELOG.json b/libraries/rush-lib/src/logic/test/exampleInvalidChangelog/emptyObject/CHANGELOG.json new file mode 100644 index 00000000000..9e26dfeeb6e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/exampleInvalidChangelog/emptyObject/CHANGELOG.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/libraries/rush-lib/src/logic/test/explicitVersionChange/change1.json b/libraries/rush-lib/src/logic/test/explicitVersionChange/change1.json new file mode 100644 index 00000000000..81eaa9cb51c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/explicitVersionChange/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patching c" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json new file mode 100644 index 00000000000..d16f93bde28 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patch change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json new file mode 100644 index 00000000000..4dba9fbf026 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change2.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "hotfix", + "comment": "Hotfix change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json new file mode 100644 index 00000000000..d16f93bde28 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/hotfixWithPatchChanges/change3.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patch change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush1.json b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush1.json new file mode 100644 index 00000000000..244c5cec2c3 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush1.json @@ -0,0 +1,8 @@ +{ + "pnpmVersion": "6.33.12", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [] +} diff --git a/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush2.json b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush2.json new file mode 100644 index 00000000000..b02b5eab675 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush2.json @@ -0,0 +1,8 @@ +{ + "pnpmVersion": "7.5.12", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [] +} diff --git a/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush3.json b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush3.json new file mode 100644 index 00000000000..3693a3a1bf7 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/ignoreCompatibilityDb/rush3.json @@ -0,0 +1,8 @@ +{ + "pnpmVersion": "7.9.0", + "rushVersion": "0.0.0", + "projectFolderMinDepth": 1, + "ensureConsistentVersions": true, + + "projects": [] +} diff --git a/libraries/rush-lib/src/logic/test/leafChange/change1.json b/libraries/rush-lib/src/logic/test/leafChange/change1.json new file mode 100644 index 00000000000..abccc8a5d4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/leafChange/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "d", + "type": "patch", + "comment": "Patching d" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/lockstepRepo/a/package.json b/libraries/rush-lib/src/logic/test/lockstepRepo/a/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/lockstepRepo/a/package.json rename to libraries/rush-lib/src/logic/test/lockstepRepo/a/package.json diff --git a/apps/rush-lib/src/logic/test/lockstepRepo/b/package.json b/libraries/rush-lib/src/logic/test/lockstepRepo/b/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/lockstepRepo/b/package.json rename to libraries/rush-lib/src/logic/test/lockstepRepo/b/package.json diff --git a/libraries/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json new file mode 100644 index 00000000000..2457e17d417 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/lockstepRepo/common/config/rush/version-policies.json @@ -0,0 +1,9 @@ +[ + { + "policyName": "lockStep1", + "definitionName": "lockStepVersion", + "version": "1.0.0", + "nextBump": "prerelease", + "mainProject": "b" + } +] diff --git a/apps/rush-lib/src/logic/test/lockstepRepo/rush.json b/libraries/rush-lib/src/logic/test/lockstepRepo/rush.json similarity index 100% rename from apps/rush-lib/src/logic/test/lockstepRepo/rush.json rename to libraries/rush-lib/src/logic/test/lockstepRepo/rush.json diff --git a/libraries/rush-lib/src/logic/test/lockstepWithoutNextBump/change1.json b/libraries/rush-lib/src/logic/test/lockstepWithoutNextBump/change1.json new file mode 100644 index 00000000000..e52e783a90c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/lockstepWithoutNextBump/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "h", + "type": "minor", + "comment": "Minor-bumping h" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChangeFiles/a.json b/libraries/rush-lib/src/logic/test/multipleChangeFiles/a.json new file mode 100644 index 00000000000..d16f93bde28 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChangeFiles/a.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patch change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChangeFiles/b.json b/libraries/rush-lib/src/logic/test/multipleChangeFiles/b.json new file mode 100644 index 00000000000..8f9f3319744 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChangeFiles/b.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "b", + "type": "patch", + "comment": "Patch change to b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChangeFiles/c.json b/libraries/rush-lib/src/logic/test/multipleChangeFiles/c.json new file mode 100644 index 00000000000..fbd0e950304 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChangeFiles/c.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patch change to c" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChanges/change1.json b/libraries/rush-lib/src/logic/test/multipleChanges/change1.json new file mode 100644 index 00000000000..d16f93bde28 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChanges/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patch change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChanges/change2.json b/libraries/rush-lib/src/logic/test/multipleChanges/change2.json new file mode 100644 index 00000000000..afd8341a20d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChanges/change2.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "minor", + "comment": "Minor change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleChanges/change3.json b/libraries/rush-lib/src/logic/test/multipleChanges/change3.json new file mode 100644 index 00000000000..d52e17743ff --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleChanges/change3.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "major", + "comment": "Major change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change1.json b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change1.json new file mode 100644 index 00000000000..4dba9fbf026 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "hotfix", + "comment": "Hotfix change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change2.json b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change2.json new file mode 100644 index 00000000000..3a1ea989dc0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change2.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "b", + "type": "hotfix", + "comment": "Hotfix change to b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change3.json b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change3.json new file mode 100644 index 00000000000..4dba9fbf026 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/multipleHotfixChanges/change3.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "hotfix", + "comment": "Hotfix change to a" + } + ] +} diff --git a/apps/rush-lib/src/logic/test/noChange/README.md b/libraries/rush-lib/src/logic/test/noChange/README.md similarity index 100% rename from apps/rush-lib/src/logic/test/noChange/README.md rename to libraries/rush-lib/src/logic/test/noChange/README.md diff --git a/libraries/rush-lib/src/logic/test/orderedChanges/change1.json b/libraries/rush-lib/src/logic/test/orderedChanges/change1.json new file mode 100644 index 00000000000..d52e17743ff --- /dev/null +++ b/libraries/rush-lib/src/logic/test/orderedChanges/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "major", + "comment": "Major change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/orderedChanges/change2.json b/libraries/rush-lib/src/logic/test/orderedChanges/change2.json new file mode 100644 index 00000000000..f5648a3cdf0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/orderedChanges/change2.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "none", + "comment": "None change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/packages/a/CHANGELOG.json b/libraries/rush-lib/src/logic/test/packages/a/CHANGELOG.json new file mode 100644 index 00000000000..c5425a1a904 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/a/CHANGELOG.json @@ -0,0 +1,11 @@ +{ + "name": "a", + "entries": [ + { + "version": "1.0.0", + "tag": "a_v1.0.0", + "date": "Fri, Jul 21, 2017 22:30:12 PM", + "comments": {} + } + ] +} \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/packages/a/package.json b/libraries/rush-lib/src/logic/test/packages/a/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/a/package.json rename to libraries/rush-lib/src/logic/test/packages/a/package.json diff --git a/apps/rush-lib/src/logic/test/packages/b/package.json b/libraries/rush-lib/src/logic/test/packages/b/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/b/package.json rename to libraries/rush-lib/src/logic/test/packages/b/package.json diff --git a/apps/rush-lib/src/logic/test/packages/c/package.json b/libraries/rush-lib/src/logic/test/packages/c/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/c/package.json rename to libraries/rush-lib/src/logic/test/packages/c/package.json diff --git a/libraries/rush-lib/src/logic/test/packages/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/packages/common/config/rush/version-policies.json new file mode 100644 index 00000000000..2ed273274ed --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/common/config/rush/version-policies.json @@ -0,0 +1,7 @@ +[ + { + "policyName": "lockStepWithoutNextBump", + "definitionName": "lockStepVersion", + "version": "1.0.0" + } +] diff --git a/apps/rush-lib/src/logic/test/packages/common/package.json b/libraries/rush-lib/src/logic/test/packages/common/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/common/package.json rename to libraries/rush-lib/src/logic/test/packages/common/package.json diff --git a/apps/rush-lib/src/logic/test/packages/cyclic-dep-1/package.json b/libraries/rush-lib/src/logic/test/packages/cyclic-dep-1/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/cyclic-dep-1/package.json rename to libraries/rush-lib/src/logic/test/packages/cyclic-dep-1/package.json diff --git a/apps/rush-lib/src/logic/test/packages/cyclic-dep-2/package.json b/libraries/rush-lib/src/logic/test/packages/cyclic-dep-2/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/cyclic-dep-2/package.json rename to libraries/rush-lib/src/logic/test/packages/cyclic-dep-2/package.json diff --git a/apps/rush-lib/src/logic/test/packages/cyclic-dep-explicit-1/package.json b/libraries/rush-lib/src/logic/test/packages/cyclic-dep-explicit-1/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/cyclic-dep-explicit-1/package.json rename to libraries/rush-lib/src/logic/test/packages/cyclic-dep-explicit-1/package.json diff --git a/apps/rush-lib/src/logic/test/packages/cyclic-dep-explicit-2/package.json b/libraries/rush-lib/src/logic/test/packages/cyclic-dep-explicit-2/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/cyclic-dep-explicit-2/package.json rename to libraries/rush-lib/src/logic/test/packages/cyclic-dep-explicit-2/package.json diff --git a/apps/rush-lib/src/logic/test/packages/d/package.json b/libraries/rush-lib/src/logic/test/packages/d/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/d/package.json rename to libraries/rush-lib/src/logic/test/packages/d/package.json diff --git a/libraries/rush-lib/src/logic/test/packages/e/package.json b/libraries/rush-lib/src/logic/test/packages/e/package.json new file mode 100644 index 00000000000..52e26d25412 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/e/package.json @@ -0,0 +1,11 @@ +{ + "name": "e", + "version": "1.0.0", + "description": "Test package e", + "devDependencies": { + "a": ">=1.0.0 <2.0.0" + }, + "peerDependencies": { + "a": ">=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/packages/f/package.json b/libraries/rush-lib/src/logic/test/packages/f/package.json new file mode 100644 index 00000000000..89b9b269f72 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/f/package.json @@ -0,0 +1,13 @@ +{ + "name": "f", + "version": "1.0.0", + "description": "Test package f", + "devDependencies": { + "b": ">=1.0.0 <2.0.0", + "h": "^1.0.0" + }, + "peerDependencies": { + "b": ">=1.0.0 <2.0.0", + "h": "^1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/packages/g/package.json b/libraries/rush-lib/src/logic/test/packages/g/package.json new file mode 100644 index 00000000000..3c33a548308 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "1.0.0", + "description": "Test package g", + "dependencies": { + "a": "*" + } +} diff --git a/libraries/rush-lib/src/logic/test/packages/h/package.json b/libraries/rush-lib/src/logic/test/packages/h/package.json new file mode 100644 index 00000000000..212d7a83d60 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/h/package.json @@ -0,0 +1,8 @@ +{ + "name": "h", + "version": "1.0.0", + "description": "Test package h", + "dependencies": { + "a": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/packages/i/package.json b/libraries/rush-lib/src/logic/test/packages/i/package.json new file mode 100644 index 00000000000..ccc8b2b8208 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/i/package.json @@ -0,0 +1,6 @@ +{ + "name": "i", + "version": "1.0.0", + "description": "Test package i", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/packages/j/package.json b/libraries/rush-lib/src/logic/test/packages/j/package.json new file mode 100644 index 00000000000..8bc5c500648 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/j/package.json @@ -0,0 +1,8 @@ +{ + "name": "j", + "version": "1.0.0", + "description": "Test package j", + "dependencies": { + "i": "1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/packages/rush.json b/libraries/rush-lib/src/logic/test/packages/rush.json new file mode 100644 index 00000000000..60bc64a4f85 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/packages/rush.json @@ -0,0 +1,99 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + "projectFolderMinDepth": 1, + "hotfixChangeEnabled": true, + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "e", + "projectFolder": "e", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "f", + "projectFolder": "f", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "g", + "projectFolder": "g", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "h", + "projectFolder": "h", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump", + "shouldPublish": true + }, + { + "packageName": "i", + "projectFolder": "i", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump", + "shouldPublish": true + }, + { + "packageName": "j", + "projectFolder": "j", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-1", + "projectFolder": "cyclic-dep-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-2", + "projectFolder": "cyclic-dep-2", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-1", + "projectFolder": "cyclic-dep-explicit-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-2", + "projectFolder": "cyclic-dep-explicit-2", + "reviewCategory": "third-party", + "shouldPublish": true, + "decoupledLocalDependencies": ["cyclic-dep-explicit-1"] + } + ] +} 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 new file mode 100644 index 00000000000..1636e755728 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfig/common/config/rush/pnpm-config.json @@ -0,0 +1,33 @@ +{ + "globalOverrides": { + "foo": "^1.0.0", + "quux": "npm:@myorg/quux@^1.0.0", + "bar@^2.1.0": "3.0.0", + "qar@1>zoo": "2" + }, + "globalPackageExtensions": { + "react-redux": { + "peerDependencies": { + "react-dom": "*" + } + } + }, + "globalNeverBuiltDependencies": ["fsevents", "level"], + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "lodash": "^4.17.21" + }, + "test": { + "jest": "^29.0.0" + } + }, + "unsupportedPackageJsonSettings": { + "pnpm": { + "overrides": { + "foo": "^2.0.0" + }, + "pnpmFutureFeature": true + } + } +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json b/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json new file mode 100644 index 00000000000..332b70494a4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json @@ -0,0 +1,5 @@ +{ + "pnpmVersion": "6.23.1", + "rushVersion": "5.58.0", + "projects": [] +} diff --git a/apps/rush-lib/src/logic/test/repo/a/package.json b/libraries/rush-lib/src/logic/test/repo/a/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/repo/a/package.json rename to libraries/rush-lib/src/logic/test/repo/a/package.json diff --git a/apps/rush-lib/src/logic/test/repo/b/package.json b/libraries/rush-lib/src/logic/test/repo/b/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/repo/b/package.json rename to libraries/rush-lib/src/logic/test/repo/b/package.json diff --git a/apps/rush-lib/src/logic/test/repo/c/package.json b/libraries/rush-lib/src/logic/test/repo/c/package.json similarity index 100% rename from apps/rush-lib/src/logic/test/repo/c/package.json rename to libraries/rush-lib/src/logic/test/repo/c/package.json diff --git a/libraries/rush-lib/src/logic/test/repo/changes/a.json b/libraries/rush-lib/src/logic/test/repo/changes/a.json new file mode 100644 index 00000000000..43f7263c5e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/changes/a.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patching a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repo/changes/b.json b/libraries/rush-lib/src/logic/test/repo/changes/b.json new file mode 100644 index 00000000000..6e3320bd6e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/changes/b.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "b", + "type": "patch", + "comment": "Patching b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repo/changes/c.json b/libraries/rush-lib/src/logic/test/repo/changes/c.json new file mode 100644 index 00000000000..81eaa9cb51c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/changes/c.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patching c" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repo/changes/d.json b/libraries/rush-lib/src/logic/test/repo/changes/d.json new file mode 100644 index 00000000000..abccc8a5d4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/changes/d.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "d", + "type": "patch", + "comment": "Patching d" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repo/changes/h.json b/libraries/rush-lib/src/logic/test/repo/changes/h.json new file mode 100644 index 00000000000..e3dfcf64d3f --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/changes/h.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "h", + "type": "patch", + "comment": "Patching h" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json new file mode 100644 index 00000000000..d71e22a06fe --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/common/config/rush/version-policies.json @@ -0,0 +1,22 @@ +[ + { + "policyName": "testPolicy1", + "definitionName": "lockStepVersion", + "version": "10.10.0", + "nextBump": "patch" + }, + { + "policyName": "testPolicy2", + "definitionName": "individualVersion", + "lockedMajor": 5 + }, + { + "policyName": "testPolicy3", + "definitionName": "individualVersion" + }, + { + "policyName": "lockStepWithoutNextBump", + "definitionName": "lockStepVersion", + "version": "1.2.3" + } +] diff --git a/libraries/rush-lib/src/logic/test/repo/d/package.json b/libraries/rush-lib/src/logic/test/repo/d/package.json new file mode 100644 index 00000000000..c61e59ddb75 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "4.1.1", + "description": "Test package d", + "dependencies": { + "b": ">=2.0.0 <3.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repo/e/package.json b/libraries/rush-lib/src/logic/test/repo/e/package.json new file mode 100644 index 00000000000..c10850ecdbd --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/e/package.json @@ -0,0 +1,8 @@ +{ + "name": "e", + "version": "10.10.0", + "description": "Test package e", + "dependencies": { + "c": "~3.1.1" + } +} diff --git a/libraries/rush-lib/src/logic/test/repo/f/package.json b/libraries/rush-lib/src/logic/test/repo/f/package.json new file mode 100644 index 00000000000..81f997bd433 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/f/package.json @@ -0,0 +1,9 @@ +{ + "name": "f", + "version": "1.0.0", + "description": "Test package f", + "dependencies": { + "a": "~1.0.0", + "h": "^1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repo/g/package.json b/libraries/rush-lib/src/logic/test/repo/g/package.json new file mode 100644 index 00000000000..bec763b9fae --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "0.0.1", + "description": "Test package g", + "devDependencies": { + "a": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repo/h/package.json b/libraries/rush-lib/src/logic/test/repo/h/package.json new file mode 100644 index 00000000000..bf994077db9 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/h/package.json @@ -0,0 +1,8 @@ +{ + "name": "h", + "version": "1.2.3", + "description": "Test package h", + "dependencies": { + "a": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repo/i/package.json b/libraries/rush-lib/src/logic/test/repo/i/package.json new file mode 100644 index 00000000000..18b7a2a64f5 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/i/package.json @@ -0,0 +1,6 @@ +{ + "name": "i", + "version": "1.2.3", + "description": "Test package i", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/repo/j/package.json b/libraries/rush-lib/src/logic/test/repo/j/package.json new file mode 100644 index 00000000000..b126561435c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/j/package.json @@ -0,0 +1,6 @@ +{ + "name": "j", + "version": "1.2.3", + "description": "Test package j", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/repo/rush.json b/libraries/rush-lib/src/logic/test/repo/rush.json new file mode 100644 index 00000000000..c7c9e1074a4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repo/rush.json @@ -0,0 +1,64 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy2" + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy3" + }, + { + "packageName": "e", + "projectFolder": "e", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "f", + "projectFolder": "f", + "reviewCategory": "third-party" + }, + { + "packageName": "g", + "projectFolder": "g", + "reviewCategory": "third-party" + }, + { + "packageName": "h", + "projectFolder": "h", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump" + }, + { + "packageName": "i", + "projectFolder": "i", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump" + }, + { + "packageName": "j", + "projectFolder": "j", + "reviewCategory": "third-party" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/rootHotfixChange/change1.json b/libraries/rush-lib/src/logic/test/rootHotfixChange/change1.json new file mode 100644 index 00000000000..31d57190f30 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/rootHotfixChange/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "hotfix", + "comment": "Hotfixing a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/rootMajorChange/change1.json b/libraries/rush-lib/src/logic/test/rootMajorChange/change1.json new file mode 100644 index 00000000000..d52e17743ff --- /dev/null +++ b/libraries/rush-lib/src/logic/test/rootMajorChange/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "major", + "comment": "Major change to a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/rootPatchChange/change1.json b/libraries/rush-lib/src/logic/test/rootPatchChange/change1.json new file mode 100644 index 00000000000..43f7263c5e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/rootPatchChange/change1.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patching a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.3.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.3.yaml new file mode 100644 index 00000000000..31dffb91ba8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.3.yaml @@ -0,0 +1,78 @@ +lockfileVersion: 5.3 + +specifiers: + '@rush-temp/project1': file:./projects/project1.tgz + '@rush-temp/project2': file:./projects/project2.tgz + '@rush-temp/project3': file:./projects/project3.tgz + '@scope/testDep': https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + pad-left: ^1.0.0 + +dependencies: + '@rush-temp/project1': file:projects/project1.tgz + '@rush-temp/project2': file:projects/project2.tgz + '@rush-temp/project3': file:projects/project3.tgz + '@scope/testDep': 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0' + pad-left: 1.0.2 + +packages: + + /jquery/1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + dev: false + + /jquery/2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + dev: false + + /pad-left/1.0.2: + resolution: {integrity: sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==} + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + /q/1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /repeat-string/1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + + 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0': + resolution: {tarball: example.pkgs.visualstudio.com/@scope/testDep/2.1.0} + name: pad-left + version: 2.1.0 + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + file:projects/project1.tgz: + resolution: {integrity: sha512-REmnAQ8v0kz+nQT9p9C8WUnhETgSwn/+XFAI9YFeMErmpGjJHC9bmH3RpOIj/GMEwGfRgNL5irqavrS4na1f3g==, tarball: file:projects/project1.tgz} + name: '@rush-temp/project1' + version: 0.0.0 + dependencies: + jquery: 1.12.3 + pad-left: 1.0.2 + dev: false + + file:projects/project2.tgz: + resolution: {integrity: sha512-tfYwAK8GXMMLMJK1K/FvhD9ZZQazg/60GZWkjM4Y/4oslAHWAuqTsPQ3bT8Z6NGarRzC5D4V7r7ftc4ifeuNaw==, tarball: file:projects/project2.tgz} + name: '@rush-temp/project2' + version: 0.0.0 + dependencies: + jquery: 2.2.4 + q: 1.5.1 + dev: false + + file:projects/project3.tgz: + resolution: {integrity: sha512-O/1Pan0WVX0t3fctCiRlhv1Lz7WFytgY5YPhBjMPMbh1PwLhF/9UwXrP5n4OC085bmG3JoMqigAtUsI9C8J9Fw==, tarball: file:projects/project3.tgz} + name: '@rush-temp/project3' + version: 0.0.0 + dependencies: + '@scope/testDep': 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0' + q: 1.5.1 + dev: false diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.yaml new file mode 100644 index 00000000000..60be0e49d63 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.yaml @@ -0,0 +1,38 @@ +dependencies: + '@rush-temp/project1': 'file:projects/project1.tgz' + '@rush-temp/project2': 'file:projects/project2.tgz' + '@rush-temp/project3': 'file:projects/project3.tgz_462eaf34881863298955eb323c130fc7' +packages: + /jquery/2.2.4: + resolution: + integrity: sha1-PjAtxh6zKaIenvrJN9cx8GETTFk= + /jquery/1.12.3: + resolution: + integrity: sha1-PjAtxh6zKaIenvrJN9cx8GETTFk= + /q/1.5.3: + resolution: + integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= + /pad-left/1.0.2: + resolution: + integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= + example.pkgs.visualstudio.com/@scope/testDep/1.0.0: + resolution: + integrity: sha1-3QG6ydBtMObyGa7LglPunr3DCPE= + 'file:projects/project1.tgz': + dependencies: + jquery: 1.12.3 + 'file:projects/project2.tgz': + dependencies: + q: 1.5.3 + jquery: 2.2.4 + 'file:projects/project3.tgz_462eaf34881863298955eb323c130fc7': + dependencies: + q: 1.5.3 + '@scope/testDep': example.pkgs.visualstudio.com/@scope/testDep/2.1.0 +registry: 'http://localhost:4873/' +lockfileVersion: 5 +specifiers: + '@rush-temp/project1': 'file:./projects/project1.tgz' + '@rush-temp/project2': 'file:./projects/project2.tgz' + '@rush-temp/project3': 'file:./projects/project3.tgz' + q: '~1.5.0' diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v6.1.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v6.1.yaml new file mode 100644 index 00000000000..6d158598476 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v6.1.yaml @@ -0,0 +1,85 @@ +lockfileVersion: '6.1' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@rush-temp/project1': + specifier: file:./projects/project1.tgz + version: file:projects/project1.tgz + '@rush-temp/project2': + specifier: file:./projects/project2.tgz + version: file:projects/project2.tgz + '@rush-temp/project3': + specifier: file:./projects/project3.tgz + version: file:projects/project3.tgz + '@scope/testDep': + specifier: example.pkgs.visualstudio.com/@scope/testDep/2.1.0 + version: 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0' + pad-left: + specifier: ^1.0.0 + version: 1.0.0 + +packages: + + /jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + dev: false + + /jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + dev: false + + /pad-left@1.0.0: + resolution: {integrity: sha512-VIgD7DviaDL6QCj+jEU1jpjXlu0z/sl4yzAmFLmM7YvM3ZRKLaxZAe+sZ1hKHeYUeI4zoZHfMetDpazu/uAwsw==} + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + /q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + + 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0': + resolution: {tarball: example.pkgs.visualstudio.com/@scope/testDep/2.1.0} + name: '@scope/testDep' + version: 2.1.0 + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + file:projects/project1.tgz: + resolution: {integrity: sha512-REmnAQ8v0kz+nQT9p9C8WUnhETgSwn/+XFAI9YFeMErmpGjJHC9bmH3RpOIj/GMEwGfRgNL5irqavrS4na1f3g==, tarball: file:projects/project1.tgz} + name: '@rush-temp/project1' + version: 0.0.0 + dependencies: + jquery: 1.12.3 + pad-left: 1.0.0 + dev: false + + file:projects/project2.tgz: + resolution: {integrity: sha512-tfYwAK8GXMMLMJK1K/FvhD9ZZQazg/60GZWkjM4Y/4oslAHWAuqTsPQ3bT8Z6NGarRzC5D4V7r7ftc4ifeuNaw==, tarball: file:projects/project2.tgz} + name: '@rush-temp/project2' + version: 0.0.0 + dependencies: + jquery: 2.2.4 + q: 1.5.1 + dev: false + + file:projects/project3.tgz: + resolution: {integrity: sha512-O/1Pan0WVX0t3fctCiRlhv1Lz7WFytgY5YPhBjMPMbh1PwLhF/9UwXrP5n4OC085bmG3JoMqigAtUsI9C8J9Fw==, tarball: file:projects/project3.tgz} + name: '@rush-temp/project3' + version: 0.0.0 + dependencies: + '@scope/testDep': 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0' + q: 1.5.1 + dev: false diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml new file mode 100644 index 00000000000..b74c0511f12 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml @@ -0,0 +1,196 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@pnpm/dependency-path': + specifier: ^5.1.7 + version: 5.1.7 + '@pnpm/lockfile.utils': + specifier: ^1.0.4 + version: 1.0.4 + '@rush-temp/project1': + specifier: file:./projects/project1 + version: project1@file:projects/project1 + '@rush-temp/project2': + specifier: file:./projects/project2 + version: project2@file:projects/project2 + '@rush-temp/project3': + specifier: file:./projects/project3 + version: project3@file:projects/project3 + pad-left: + specifier: 1.0.0 + version: 1.0.0 + +packages: + + '@pnpm/crypto.base32-hash@3.0.1': + resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.polyfill@1.0.0': + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@5.1.7': + resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1.0.3': + resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.utils@1.0.4': + resolution: {integrity: sha512-ptHO2muziYyNCwpsuaPtaRgKiHMrE/lkGI4nqbHnRWWgfdJbTeL1tq+b/EUsxjlKlJ/a9Q4z2C+t38g+9bhTJg==} + engines: {node: '>=18.12'} + + '@pnpm/patching.types@1.0.0': + resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} + engines: {node: '>=18.12'} + + '@pnpm/pick-fetcher@3.0.0': + resolution: {integrity: sha512-2eisylRAU/jeuxFEPnS1gjLZKJGbYc4QEtEW6MVUYjO4Xi+2ttkSm7825S0J5IPpUIvln8HYPCUS0eQWSfpOaQ==} + engines: {node: '>=18.12'} + + '@pnpm/ramda@0.28.1': + resolution: {integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==} + + '@pnpm/resolver-base@13.0.4': + resolution: {integrity: sha512-d6GtsaXDN1VmVdeB6ohrhwGwQfvYpEX/XkBZyRT0Hp772WabWVfaulvicwdh/8o7Rpzy7IV/2hKnDpodUY00lw==} + engines: {node: '>=18.12'} + + '@pnpm/types@12.2.0': + resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} + engines: {node: '>=18.12'} + + get-npm-tarball-url@2.1.0: + resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} + engines: {node: '>=12.17'} + + jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + + jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + + pad-left@1.0.0: + resolution: {integrity: sha512-VIgD7DviaDL6QCj+jEU1jpjXlu0z/sl4yzAmFLmM7YvM3ZRKLaxZAe+sZ1hKHeYUeI4zoZHfMetDpazu/uAwsw==} + engines: {node: '>=0.10.0'} + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + resolution: {tarball: https://github.com/jonschlinkert/pad-left/tarball/2.1.0} + version: 2.1.0 + engines: {node: '>=0.10.0'} + + project1@file:projects/project1: + resolution: {directory: projects/project1, type: directory} + + project2@file:projects/project2: + resolution: {directory: projects/project2, type: directory} + + project3@file:projects/project3: + resolution: {directory: projects/project3, type: directory} + + 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) + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + +snapshots: + + '@pnpm/crypto.base32-hash@3.0.1': + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.3 + + '@pnpm/crypto.polyfill@1.0.0': {} + + '@pnpm/dependency-path@5.1.7': + dependencies: + '@pnpm/crypto.base32-hash': 3.0.1 + '@pnpm/types': 12.2.0 + semver: 7.6.3 + + '@pnpm/lockfile.types@1.0.3': + dependencies: + '@pnpm/patching.types': 1.0.0 + '@pnpm/types': 12.2.0 + + '@pnpm/lockfile.utils@1.0.4': + dependencies: + '@pnpm/dependency-path': 5.1.7 + '@pnpm/lockfile.types': 1.0.3 + '@pnpm/pick-fetcher': 3.0.0 + '@pnpm/resolver-base': 13.0.4 + '@pnpm/types': 12.2.0 + get-npm-tarball-url: 2.1.0 + ramda: '@pnpm/ramda@0.28.1' + + '@pnpm/patching.types@1.0.0': {} + + '@pnpm/pick-fetcher@3.0.0': {} + + '@pnpm/ramda@0.28.1': {} + + '@pnpm/resolver-base@13.0.4': + dependencies: + '@pnpm/types': 12.2.0 + + '@pnpm/types@12.2.0': {} + + get-npm-tarball-url@2.1.0: {} + + jquery@1.12.3: {} + + jquery@2.2.4: {} + + pad-left@1.0.0: + dependencies: + repeat-string: 1.6.1 + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + dependencies: + repeat-string: 1.6.1 + + project1@file:projects/project1: + dependencies: + jquery: 1.12.3 + pad-left: 1.0.0 + + project2@file:projects/project2: + dependencies: + jquery: 2.2.4 + q: 1.5.1 + + project3@file:projects/project3: + dependencies: + '@scope/testDep': pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + q: 1.5.1 + + q@1.5.1: {} + + repeat-string@1.6.1: {} + + rfc4648@1.5.3: {} + + semver@7.6.3: {} diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json b/libraries/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json new file mode 100644 index 00000000000..e929f2bd4f9 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/npm-shrinkwrap.json @@ -0,0 +1,60 @@ +{ + "name": "example-file", + "version": "1.0.0", + "dependencies": { + "@rush-temp/project1": { + "version": "0.0.0", + "from": "projects\\project1", + "resolved": "file:projects\\project1" + }, + "@rush-temp/project2": { + "version": "0.0.0", + "from": "projects\\project2", + "resolved": "file:projects\\project2", + "dependencies": { + "fbjs": { + "version": "0.8.12", + "from": "fbjs@>=0.8.9 <0.9.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/fbjs/-/fbjs-0.8.12.tgz" + }, + "jquery": { + "version": "2.2.4", + "from": "jquery@>=2.2.4 <3.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/jquery/-/jquery-2.2.4.tgz" + }, + "object-assign": { + "version": "4.1.1", + "from": "object-assign@>=4.1.0 <5.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/object-assign/-/object-assign-4.1.1.tgz" + }, + "react": { + "version": "15.5.4", + "from": "react@>=15.5.4 <16.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/react/-/react-15.5.4.tgz" + } + } + }, + "prop-types": { + "version": "15.5.8", + "from": "prop-types@>=15.5.7 <16.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/prop-types/-/prop-types-15.5.8.tgz", + "dependencies": { + "fbjs": { + "version": "0.8.12", + "from": "fbjs@>=0.8.9 <0.9.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/fbjs/-/fbjs-0.8.12.tgz" + }, + "object-assign": { + "version": "4.1.1", + "from": "object-assign@>=4.1.0 <5.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/object-assign/-/object-assign-4.1.1.tgz" + } + } + }, + "q": { + "version": "1.5.0", + "from": "q@>=1.1.2 <2.0.0", + "resolved": "https://example.pkgs.visualstudio.com/_packaging/feedname/npm/registry/q/-/q-1.5.0.tgz" + } + } +} diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml new file mode 100644 index 00000000000..a5743e0bfec --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml @@ -0,0 +1,66 @@ +lockfileVersion: 5.3 + +importers: + + .: + specifiers: {} + + ../../project1: + specifiers: + jquery: 1.12.3 + pad-left: ^1.0.0 + dependencies: + jquery: 1.12.3 + pad-left: 1.0.2 + + ../../project2: + specifiers: + jquery: 2.2.4 + q: ~1.5.0 + dependencies: + jquery: 2.2.4 + q: 1.5.1 + + ../../project3: + specifiers: + '@scope/testDep': https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + q: 1.5.1 + dependencies: + '@scope/testDep': 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0' + q: 1.5.1 + +packages: + + /jquery/1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + dev: false + + /jquery/2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + dev: false + + /pad-left/1.0.2: + resolution: {integrity: sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==} + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + /q/1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /repeat-string/1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + + 'example.pkgs.visualstudio.com/@scope/testDep/2.1.0': + resolution: {tarball: example.pkgs.visualstudio.com/@scope/testDep/2.1.0} + name: pad-left + version: 2.1.0 + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v6.1.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v6.1.yaml new file mode 100644 index 00000000000..3bf93145322 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v6.1.yaml @@ -0,0 +1,72 @@ +lockfileVersion: '6.1' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../project1: + dependencies: + jquery: + specifier: 1.12.3 + version: 1.12.3 + pad-left: + specifier: ^1.0.0 + version: 1.0.0 + + ../../project2: + dependencies: + jquery: + specifier: 2.2.4 + version: 2.2.4 + q: + specifier: ~1.5.0 + version: 1.5.1 + + ../../project3: + dependencies: + '@scope/testDep': + specifier: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + version: '@github.com/jonschlinkert/pad-left/tarball/2.1.0' + q: + specifier: 1.5.1 + version: 1.5.1 + +packages: + + /jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + dev: false + + /jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + dev: false + + /pad-left@1.0.0: + resolution: {integrity: sha512-VIgD7DviaDL6QCj+jEU1jpjXlu0z/sl4yzAmFLmM7YvM3ZRKLaxZAe+sZ1hKHeYUeI4zoZHfMetDpazu/uAwsw==} + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false + + /q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: false + + /repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + + '@github.com/jonschlinkert/pad-left/tarball/2.1.0': + resolution: {tarball: https://github.com/jonschlinkert/pad-left/tarball/2.1.0} + name: pad-left + version: 2.1.0 + engines: {node: '>=0.10.0'} + dependencies: + repeat-string: 1.6.1 + dev: false diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml new file mode 100644 index 00000000000..ad160af09b8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml @@ -0,0 +1,83 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../project1: + dependencies: + jquery: + specifier: 1.12.3 + version: 1.12.3 + pad-left: + specifier: ^1.0.0 + version: 1.0.2 + + ../../project2: + dependencies: + jquery: + specifier: 2.2.4 + version: 2.2.4 + q: + specifier: ~1.5.0 + version: 1.5.0 + + ../../project3: + dependencies: + '@scope/testDep': + specifier: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + version: pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 + q: + specifier: 1.5.0 + version: 1.5.0 + +packages: + + jquery@1.12.3: + resolution: {integrity: sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==} + + jquery@2.2.4: + resolution: {integrity: sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==} + + pad-left@1.0.2: + resolution: {integrity: sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==} + engines: {node: '>=0.10.0'} + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + resolution: {tarball: https://github.com/jonschlinkert/pad-left/tarball/2.1.0} + version: 2.1.0 + engines: {node: '>=0.10.0'} + + q@1.5.0: + resolution: {integrity: sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==} + 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) + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + +snapshots: + + jquery@1.12.3: {} + + jquery@2.2.4: {} + + pad-left@1.0.2: + dependencies: + repeat-string: 1.6.1 + + pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0: + dependencies: + repeat-string: 1.6.1 + + q@1.5.0: {} + + repeat-string@1.6.1: {} diff --git a/apps/rush-lib/src/logic/test/telemetry/telemetryEnabled.json b/libraries/rush-lib/src/logic/test/telemetry/telemetryEnabled.json similarity index 100% rename from apps/rush-lib/src/logic/test/telemetry/telemetryEnabled.json rename to libraries/rush-lib/src/logic/test/telemetry/telemetryEnabled.json diff --git a/apps/rush-lib/src/logic/test/telemetry/telemetryNotEnabled.json b/libraries/rush-lib/src/logic/test/telemetry/telemetryNotEnabled.json similarity index 100% rename from apps/rush-lib/src/logic/test/telemetry/telemetryNotEnabled.json rename to libraries/rush-lib/src/logic/test/telemetry/telemetryNotEnabled.json diff --git a/libraries/rush-lib/src/logic/test/verifyChanges/changes.json b/libraries/rush-lib/src/logic/test/verifyChanges/changes.json new file mode 100644 index 00000000000..0a8e429d4e4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/verifyChanges/changes.json @@ -0,0 +1,14 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patching a" + }, + { + "packageName": "b", + "type": "patch", + "comment": "Patching b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/.mergequeueignore b/libraries/rush-lib/src/logic/test/workspacePackages/.mergequeueignore new file mode 100644 index 00000000000..b68298052b9 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/.mergequeueignore @@ -0,0 +1 @@ +common/config/version-policies.json \ No newline at end of file diff --git a/apps/rush-lib/src/logic/test/packages/a/CHANGELOG.json b/libraries/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json similarity index 100% rename from apps/rush-lib/src/logic/test/packages/a/CHANGELOG.json rename to libraries/rush-lib/src/logic/test/workspacePackages/a/CHANGELOG.json diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/a/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/a/package.json new file mode 100644 index 00000000000..e57f46f8473 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/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/workspacePackages/b/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/b/package.json new file mode 100644 index 00000000000..ca4d5662d97 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/c/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/c/package.json new file mode 100644 index 00000000000..91588ae3627 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/c/package.json @@ -0,0 +1,9 @@ +{ + "name": "c", + "version": "1.0.0", + "description": "Test package c", + "dependencies": { + "b": "workspace:>=1.0.0 <2.0.0", + "handlebars": "~4.0.11" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/workspacePackages/common/config/rush/version-policies.json new file mode 100644 index 00000000000..2ed273274ed --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/common/config/rush/version-policies.json @@ -0,0 +1,7 @@ +[ + { + "policyName": "lockStepWithoutNextBump", + "definitionName": "lockStepVersion", + "version": "1.0.0" + } +] diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/common/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/common/package.json new file mode 100644 index 00000000000..d49725bee24 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/common/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": {}, + "description": "Temporary file generated by the Rush tool", + "name": "rush-common", + "private": true, + "version": "0.0.0" +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json new file mode 100644 index 00000000000..855f3fd74cb --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-1", + "version": "1.0.0", + "description": "cyclic-dep-1", + "dependencies": { + "cyclic-dep-2": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json new file mode 100644 index 00000000000..c07faa152ca --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-2/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-2", + "version": "1.0.0", + "description": "cyclic-dep-2", + "dependencies": { + "cyclic-dep-1": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json new file mode 100644 index 00000000000..441e0e17faa --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-1/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-explicit-1", + "version": "1.0.0", + "description": "cyclic-dep-explicit-1", + "dependencies": { + "cyclic-dep-explicit-2": "workspace:>=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json new file mode 100644 index 00000000000..6308d48dec1 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/cyclic-dep-explicit-2/package.json @@ -0,0 +1,8 @@ +{ + "name": "cyclic-dep-explicit-2", + "version": "1.0.0", + "description": "cyclic-dep-explicit-2", + "dependencies": { + "cyclic-dep-explicit-1": ">=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/d/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/d/package.json new file mode 100644 index 00000000000..f6ae89b73d6 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "1.0.0", + "description": "Test package d", + "dependencies": { + "c": "workspace:1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/e/.mergequeueignore b/libraries/rush-lib/src/logic/test/workspacePackages/e/.mergequeueignore new file mode 100644 index 00000000000..c578b1d164c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/e/.mergequeueignore @@ -0,0 +1 @@ +src/** \ No newline at end of file diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/e/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/e/package.json new file mode 100644 index 00000000000..0cf2793199b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/e/package.json @@ -0,0 +1,11 @@ +{ + "name": "e", + "version": "1.0.0", + "description": "Test package e", + "devDependencies": { + "a": "workspace:>=1.0.0 <2.0.0" + }, + "peerDependencies": { + "a": ">=1.0.0 <2.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/f/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/f/package.json new file mode 100644 index 00000000000..3328cb54edb --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/f/package.json @@ -0,0 +1,13 @@ +{ + "name": "f", + "version": "1.0.0", + "description": "Test package f", + "devDependencies": { + "b": "workspace:>=1.0.0 <2.0.0", + "h": "workspace:^1.0.0" + }, + "peerDependencies": { + "b": ">=1.0.0 <2.0.0", + "h": "workspace:^1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/g/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/g/package.json new file mode 100644 index 00000000000..a7e7cfeafcb --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "1.0.0", + "description": "Test package g", + "dependencies": { + "a": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/h/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/h/package.json new file mode 100644 index 00000000000..2c48d7e1667 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/h/package.json @@ -0,0 +1,8 @@ +{ + "name": "h", + "version": "1.0.0", + "description": "Test package h", + "dependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/i/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/i/package.json new file mode 100644 index 00000000000..ccc8b2b8208 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/i/package.json @@ -0,0 +1,6 @@ +{ + "name": "i", + "version": "1.0.0", + "description": "Test package i", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/j/package.json b/libraries/rush-lib/src/logic/test/workspacePackages/j/package.json new file mode 100644 index 00000000000..494783fe708 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/j/package.json @@ -0,0 +1,8 @@ +{ + "name": "j", + "version": "1.0.0", + "description": "Test package j", + "dependencies": { + "i": "workspace:1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspacePackages/rush.json b/libraries/rush-lib/src/logic/test/workspacePackages/rush.json new file mode 100644 index 00000000000..60bc64a4f85 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspacePackages/rush.json @@ -0,0 +1,99 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + "projectFolderMinDepth": 1, + "hotfixChangeEnabled": true, + "approvedPackagesPolicy": { + "reviewCategories": ["first-party", "third-party", "prototype"], + "ignoredNpmScopes": ["@types", "@internal"] + }, + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "e", + "projectFolder": "e", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "f", + "projectFolder": "f", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "g", + "projectFolder": "g", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "h", + "projectFolder": "h", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump", + "shouldPublish": true + }, + { + "packageName": "i", + "projectFolder": "i", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump", + "shouldPublish": true + }, + { + "packageName": "j", + "projectFolder": "j", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-1", + "projectFolder": "cyclic-dep-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-2", + "projectFolder": "cyclic-dep-2", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-1", + "projectFolder": "cyclic-dep-explicit-1", + "reviewCategory": "third-party", + "shouldPublish": true + }, + { + "packageName": "cyclic-dep-explicit-2", + "projectFolder": "cyclic-dep-explicit-2", + "reviewCategory": "third-party", + "shouldPublish": true, + "decoupledLocalDependencies": ["cyclic-dep-explicit-1"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/a/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/a/package.json new file mode 100644 index 00000000000..e57f46f8473 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/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/workspaceRepo/b/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/b/package.json new file mode 100644 index 00000000000..1707e03417a --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "2.0.0", + "description": "Test package b", + "dependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/c/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/c/package.json new file mode 100644 index 00000000000..436566d07c7 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "c", + "version": "3.1.1", + "description": "Test package c", + "dependencies": { + "b": "workspace:>=2.0.0 <3.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/changes/a.json b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/a.json new file mode 100644 index 00000000000..43f7263c5e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/a.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "a", + "type": "patch", + "comment": "Patching a" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/changes/b.json b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/b.json new file mode 100644 index 00000000000..6e3320bd6e8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/b.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "b", + "type": "patch", + "comment": "Patching b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/changes/c.json b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/c.json new file mode 100644 index 00000000000..81eaa9cb51c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/c.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "c", + "type": "patch", + "comment": "Patching c" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/changes/d.json b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/d.json new file mode 100644 index 00000000000..abccc8a5d4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/d.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "d", + "type": "patch", + "comment": "Patching d" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/changes/h.json b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/h.json new file mode 100644 index 00000000000..e3dfcf64d3f --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/changes/h.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "h", + "type": "patch", + "comment": "Patching h" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..4893af63e5d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/command-line.json @@ -0,0 +1,112 @@ +/** + * This configuration file defines custom commands for the "rush" command-line. + * More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + + /** + * Custom "commands" introduce new verbs for the command-line. To see the help for these + * example commands, try "rush --help", "rush my-bulk-command --help", or + * "rush my-global-command --help". + */ + "commands": [ + { + "commandKind": "phased", + "name": "build", + "summary": "Phased build", + "description": "Ditto", + "safeForSimultaneousRushProcesses": false, + + "enableParallelism": true, + "incremental": true, + "phases": [ + "_phase:no-deps", + "_phase:upstream-self", + "_phase:upstream-1", + "_phase:upstream-2", + "_phase:upstream-3", + "_phase:upstream-1-self", + "_phase:upstream-2-self", + "_phase:upstream-1-self-upstream", + "_phase:complex" + ] + } + ], + + /* PHASES */ + "phases": [ + { + "name": "_phase:no-deps", + "dependencies": {}, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-self", + "dependencies": { + "self": ["_phase:no-deps"], + "upstream": ["_phase:upstream-self"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-1", + "dependencies": { + "upstream": ["_phase:no-deps"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-2", + "dependencies": { + "upstream": ["_phase:upstream-1"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-3", + "dependencies": { + "upstream": ["_phase:upstream-2"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-1-self", + "dependencies": { + "self": ["_phase:upstream-1"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-2-self", + "dependencies": { + "self": ["_phase:upstream-2"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:upstream-1-self-upstream", + "dependencies": { + "upstream": ["_phase:upstream-1-self"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:complex", + "dependencies": { + "self": ["_phase:upstream-3"], + "upstream": ["_phase:upstream-1-self-upstream", "_phase:upstream-2-self"] + }, + "ignoreMissingScript": true, + "allowWarningsOnSuccess": false + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json new file mode 100644 index 00000000000..d71e22a06fe --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/common/config/rush/version-policies.json @@ -0,0 +1,22 @@ +[ + { + "policyName": "testPolicy1", + "definitionName": "lockStepVersion", + "version": "10.10.0", + "nextBump": "patch" + }, + { + "policyName": "testPolicy2", + "definitionName": "individualVersion", + "lockedMajor": 5 + }, + { + "policyName": "testPolicy3", + "definitionName": "individualVersion" + }, + { + "policyName": "lockStepWithoutNextBump", + "definitionName": "lockStepVersion", + "version": "1.2.3" + } +] diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/d/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/d/package.json new file mode 100644 index 00000000000..d3ff1341f07 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "4.1.1", + "description": "Test package d", + "dependencies": { + "b": "workspace:>=2.0.0 <3.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/e/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/e/package.json new file mode 100644 index 00000000000..e25c11d8daf --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/e/package.json @@ -0,0 +1,8 @@ +{ + "name": "e", + "version": "10.10.0", + "description": "Test package e", + "dependencies": { + "c": "workspace:~3.1.1" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/f/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/f/package.json new file mode 100644 index 00000000000..0386e717df8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/f/package.json @@ -0,0 +1,9 @@ +{ + "name": "f", + "version": "1.0.0", + "description": "Test package f", + "dependencies": { + "a": "workspace:~1.0.0", + "h": "workspace:^1.2.3" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/g/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/g/package.json new file mode 100644 index 00000000000..58fb54644ea --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "0.0.1", + "description": "Test package g", + "devDependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/h/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/h/package.json new file mode 100644 index 00000000000..a012a720796 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/h/package.json @@ -0,0 +1,8 @@ +{ + "name": "h", + "version": "1.2.3", + "description": "Test package h", + "dependencies": { + "a": "workspace:~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/i/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/i/package.json new file mode 100644 index 00000000000..18b7a2a64f5 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/i/package.json @@ -0,0 +1,6 @@ +{ + "name": "i", + "version": "1.2.3", + "description": "Test package i", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/j/package.json b/libraries/rush-lib/src/logic/test/workspaceRepo/j/package.json new file mode 100644 index 00000000000..b126561435c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/j/package.json @@ -0,0 +1,6 @@ +{ + "name": "j", + "version": "1.2.3", + "description": "Test package j", + "dependencies": {} +} diff --git a/libraries/rush-lib/src/logic/test/workspaceRepo/rush.json b/libraries/rush-lib/src/logic/test/workspaceRepo/rush.json new file mode 100644 index 00000000000..c7c9e1074a4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceRepo/rush.json @@ -0,0 +1,64 @@ +{ + "npmVersion": "3.10.8", + "rushVersion": "1.0.5", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "b", + "projectFolder": "b", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "c", + "projectFolder": "c", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy2" + }, + { + "packageName": "d", + "projectFolder": "d", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy3" + }, + { + "packageName": "e", + "projectFolder": "e", + "reviewCategory": "third-party", + "versionPolicyName": "testPolicy1" + }, + { + "packageName": "f", + "projectFolder": "f", + "reviewCategory": "third-party" + }, + { + "packageName": "g", + "projectFolder": "g", + "reviewCategory": "third-party" + }, + { + "packageName": "h", + "projectFolder": "h", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump" + }, + { + "packageName": "i", + "projectFolder": "i", + "reviewCategory": "third-party", + "versionPolicyName": "lockStepWithoutNextBump" + }, + { + "packageName": "j", + "projectFolder": "j", + "reviewCategory": "third-party" + } + ] +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts new file mode 100644 index 00000000000..567f1678f95 --- /dev/null +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts @@ -0,0 +1,353 @@ +// 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 PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; +import type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +import type { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; +import { VersionMismatchFinderProject } from './VersionMismatchFinderProject'; +import { VersionMismatchFinderCommonVersions } from './VersionMismatchFinderCommonVersions'; +import { CustomTipId } from '../../api/CustomTipsConfiguration'; +import type { Subspace } from '../../api/Subspace'; + +const TRUNCATE_AFTER_PACKAGE_NAME_COUNT: number = 5; + +export interface IVersionMismatchFinderOptions { + subspace?: Subspace; + variant: string | undefined; +} + +export interface IVersionMismatchFinderRushCheckOptions extends IVersionMismatchFinderOptions { + printAsJson?: boolean | undefined; + truncateLongPackageNameLists?: boolean | undefined; +} + +export interface IVersionMismatchFinderEnsureConsistentVersionsOptions + extends IVersionMismatchFinderOptions {} + +export interface IVersionMismatchFinderGetMismatchesOptions extends IVersionMismatchFinderOptions {} + +export interface IMismatchDependency { + dependencyName: string; + versions: IMismatchDependencyVersion[]; +} + +export interface IMismatchDependencyVersion { + version: string; + projects: string[]; +} + +export interface IMismatchDependencies { + mismatchedVersions: IMismatchDependency[]; +} + +export class VersionMismatchFinder { + /* store it like this: + * { + * "@types/node": { + * "1.0.0": [ '@ms/rush' ] + * } + * } + */ + private _allowedAlternativeVersion: Map>; + private _mismatches: Map>; + private _projects: VersionMismatchFinderEntity[]; + + public constructor( + projects: VersionMismatchFinderEntity[], + allowedAlternativeVersions?: Map> + ) { + this._projects = projects; + this._mismatches = new Map>(); + this._allowedAlternativeVersion = allowedAlternativeVersions || new Map>(); + this._analyze(); + } + + public static rushCheck( + rushConfiguration: RushConfiguration, + terminal: ITerminal, + options?: IVersionMismatchFinderRushCheckOptions + ): void { + const { + variant, + subspace = rushConfiguration.defaultSubspace, + printAsJson, + truncateLongPackageNameLists + } = options ?? {}; + + VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { + variant, + subspace, + printAsJson, + truncateLongPackageNameLists, + terminal, + isRushCheckCommand: true + }); + } + + public static ensureConsistentVersions( + rushConfiguration: RushConfiguration, + terminal: ITerminal, + options?: IVersionMismatchFinderEnsureConsistentVersionsOptions + ): void { + const { variant, subspace = rushConfiguration.defaultSubspace } = options ?? {}; + + VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { + subspace, + variant, + terminal, + isRushCheckCommand: false, + truncateLongPackageNameLists: true + }); + } + + /** + * Populates a version mismatch finder object given a Rush Configuration. + * Intentionally considers preferred versions. + */ + public static getMismatches( + rushConfiguration: RushConfiguration, + options?: IVersionMismatchFinderOptions + ): VersionMismatchFinder { + const { subspace = rushConfiguration.defaultSubspace, variant } = options ?? {}; + const commonVersions: CommonVersionsConfiguration = subspace.getCommonVersions(variant); + + const projects: VersionMismatchFinderEntity[] = []; + + // Create an object for the purposes of reporting conflicts with preferredVersions from common-versions.json + // Make sure this one is first so it doesn't get truncated when a long list is printed + projects.push(new VersionMismatchFinderCommonVersions(commonVersions)); + + // If subspace is specified, only go through projects in that subspace + for (const project of subspace.getProjects()) { + projects.push(new VersionMismatchFinderProject(project)); + } + + 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; + } + + public get numberOfMismatches(): number { + return this._mismatches.size; + } + + public getMismatches(): string[] { + return this._getKeys(this._mismatches); + } + + public getVersionsOfMismatch(mismatch: string): string[] | undefined { + return this._mismatches.has(mismatch) ? this._getKeys(this._mismatches.get(mismatch)) : undefined; + } + + public getConsumersOfMismatch( + mismatch: string, + version: string + ): VersionMismatchFinderEntity[] | undefined { + const mismatchedPackage: Map | undefined = + this._mismatches.get(mismatch); + if (!mismatchedPackage) { + return undefined; + } + + const mismatchedVersion: VersionMismatchFinderEntity[] | undefined = mismatchedPackage.get(version); + return mismatchedVersion; + } + + public printAsJson(): void { + const mismatchDependencies: IMismatchDependency[] = []; + + this.getMismatches().forEach((dependency: string) => { + const mismatchDependencyVersionArray: IMismatchDependencyVersion[] = []; + this.getVersionsOfMismatch(dependency)!.forEach((version: string) => { + const projects: string[] = []; + this.getConsumersOfMismatch(dependency, version)!.forEach((project: VersionMismatchFinderEntity) => { + projects.push(project.friendlyName); + }); + const mismatchDependencyVersion: IMismatchDependencyVersion = { + version: version, + projects: projects + }; + mismatchDependencyVersionArray.push(mismatchDependencyVersion); + }); + const mismatchDependency: IMismatchDependency = { + dependencyName: dependency, + versions: mismatchDependencyVersionArray + }; + mismatchDependencies.push(mismatchDependency); + }); + + const output: IMismatchDependencies = { + mismatchedVersions: mismatchDependencies + }; + + // eslint-disable-next-line no-console + console.log(JSON.stringify(output, undefined, 2)); + } + + public print(truncateLongPackageNameLists: boolean = false): void { + // Iterate over the list. For any dependency with mismatching versions, print the projects + this.getMismatches().forEach((dependency: string) => { + // eslint-disable-next-line no-console + console.log(Colorize.yellow(dependency)); + this.getVersionsOfMismatch(dependency)!.forEach((version: string) => { + // eslint-disable-next-line no-console + console.log(` ${version}`); + const consumersOfMismatch: VersionMismatchFinderEntity[] = this.getConsumersOfMismatch( + dependency, + version + )!; + + let numberToPrint: number = truncateLongPackageNameLists + ? TRUNCATE_AFTER_PACKAGE_NAME_COUNT + : consumersOfMismatch.length; + let numberRemaining: number = consumersOfMismatch.length; + for (const { friendlyName } of consumersOfMismatch) { + if (numberToPrint-- === 0) { + break; + } + + numberRemaining--; + + // eslint-disable-next-line no-console + console.log(` - ${friendlyName}`); + } + + if (numberRemaining > 0) { + // eslint-disable-next-line no-console + console.log(` (and ${numberRemaining} others)`); + } + }); + // eslint-disable-next-line no-console + console.log(); + }); + } + + private _analyze(): void { + this._projects.forEach((project: VersionMismatchFinderEntity) => { + if (!project.skipRushCheck) { + // NOTE: We do not consider peer dependencies here. The purpose of "rush check" is + // mainly to avoid side-by-side duplicates in the node_modules folder, whereas + // peer dependencies are just a compatibility statement that will be satisfied by a + // regular dependency. (It might be useful for Rush to help people keep their peer dependency + // patterns consistent, but on the other hand different projects may have different + // levels of compatibility -- we should wait for someone to actually request this feature + // before we get into that.) + project.allDependencies.forEach((dependency: PackageJsonDependency) => { + if (dependency.dependencyType !== DependencyType.Peer) { + const version: string = dependency.version!; + + const isCyclic: boolean = project.decoupledLocalDependencies.has(dependency.name); + + if (this._isVersionAllowedAlternative(dependency.name, version)) { + return; + } + + const name: string = dependency.name + (isCyclic ? ' (cyclic)' : ''); + + let dependencyVersions: Map | undefined = + this._mismatches.get(name); + if (!dependencyVersions) { + this._mismatches.set( + name, + (dependencyVersions = new Map()) + ); + } + + const consumers: VersionMismatchFinderEntity[] | undefined = dependencyVersions.get(version); + if (!consumers) { + dependencyVersions.set(version, [project]); + } else { + consumers.push(project); + } + } + }); + } + }); + + this._mismatches.forEach((mismatches: Map, project: string) => { + if (mismatches.size <= 1) { + this._mismatches.delete(project); + } + }); + } + + private _isVersionAllowedAlternative(dependency: string, version: string): boolean { + const allowedAlternatives: ReadonlyArray | undefined = + this._allowedAlternativeVersion.get(dependency); + return Boolean(allowedAlternatives && allowedAlternatives.indexOf(version) > -1); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private _getKeys(iterable: Map | undefined): string[] { + const keys: string[] = []; + if (iterable) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + iterable.forEach((value: any, key: string) => { + keys.push(key); + }); + } + return keys; + } +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts new file mode 100644 index 00000000000..bec3f535149 --- /dev/null +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.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 { RushConstants } from '../RushConstants'; +import { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; +import type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; +import { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; + +export class VersionMismatchFinderCommonVersions extends VersionMismatchFinderEntity { + private _fileManager: CommonVersionsConfiguration; + + public constructor(commonVersionsConfiguration: CommonVersionsConfiguration) { + super({ + friendlyName: `preferred versions from ${RushConstants.commonVersionsFilename}`, + decoupledLocalDependencies: new Set() + }); + + this._fileManager = commonVersionsConfiguration; + } + + public get filePath(): string { + return this._fileManager.filePath; + } + + public get allDependencies(): ReadonlyArray { + const dependencies: PackageJsonDependency[] = []; + + this._fileManager.getAllPreferredVersions().forEach((version, dependencyName) => { + dependencies.push(this._getPackageJsonDependency(dependencyName, version)); + }); + + return dependencies; + } + + public tryGetDependency(packageName: string): PackageJsonDependency | undefined { + const version: string | undefined = this._fileManager.getAllPreferredVersions().get(packageName); + if (!version) { + return undefined; + } else { + return this._getPackageJsonDependency(packageName, version); + } + } + + public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { + return undefined; // common-versions.json doesn't have a distinction between dev and non-dev dependencies + } + + public addOrUpdateDependency( + packageName: string, + newVersion: string, + dependencyType: DependencyType + ): void { + if (dependencyType !== DependencyType.Regular) { + throw new Error( + `${RushConstants.commonVersionsFilename} only accepts "${DependencyType.Regular}" dependencies` + ); + } + + this._fileManager.preferredVersions.set(packageName, newVersion); + } + + public removeDependency(packageName: string): void { + throw new Error('Not supported.'); + } + + public saveIfModified(): boolean { + return this._fileManager.save(); + } + + private _getPackageJsonDependency(dependencyName: string, version: string): PackageJsonDependency { + return new PackageJsonDependency(dependencyName, version, DependencyType.Regular, () => + this.addOrUpdateDependency(dependencyName, version, DependencyType.Regular) + ); + } +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts new file mode 100644 index 00000000000..054d7291c79 --- /dev/null +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.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 type { PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; + +export interface IVersionMismatchFinderEntityOptions { + friendlyName: string; + decoupledLocalDependencies: Set; + skipRushCheck?: boolean; +} + +export abstract class VersionMismatchFinderEntity { + public readonly friendlyName: string; + public readonly decoupledLocalDependencies: Set; + public readonly skipRushCheck: boolean | undefined; + + public constructor(options: IVersionMismatchFinderEntityOptions) { + this.friendlyName = options.friendlyName; + this.decoupledLocalDependencies = options.decoupledLocalDependencies; + this.skipRushCheck = options.skipRushCheck; + } + + public abstract get filePath(): string; + public abstract get allDependencies(): ReadonlyArray; + + public abstract tryGetDependency(packageName: string): PackageJsonDependency | undefined; + public abstract tryGetDevDependency(packageName: string): PackageJsonDependency | undefined; + public abstract addOrUpdateDependency( + packageName: string, + newVersion: string, + dependencyType: DependencyType + ): void; + public abstract removeDependency(packageName: string, dependencyType: DependencyType): void; + public abstract saveIfModified(): boolean; +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts new file mode 100644 index 00000000000..1bbfd4d7a84 --- /dev/null +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.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 { VersionMismatchFinderEntity } from './VersionMismatchFinderEntity'; +import type { PackageJsonEditor, PackageJsonDependency, DependencyType } from '../../api/PackageJsonEditor'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; + +export class VersionMismatchFinderProject extends VersionMismatchFinderEntity { + public packageName: string; + private _fileManager: PackageJsonEditor; + + public constructor(project: RushConfigurationProject) { + super({ + friendlyName: project.packageName, + decoupledLocalDependencies: project.decoupledLocalDependencies, + skipRushCheck: project.skipRushCheck + }); + + this._fileManager = project.packageJsonEditor; + this.packageName = project.packageName; + } + + public get filePath(): string { + return this._fileManager.filePath; + } + + public get allDependencies(): ReadonlyArray { + return [...this._fileManager.dependencyList, ...this._fileManager.devDependencyList]; + } + + public tryGetDependency(packageName: string): PackageJsonDependency | undefined { + return this._fileManager.tryGetDependency(packageName); + } + + public tryGetDevDependency(packageName: string): PackageJsonDependency | undefined { + return this._fileManager.tryGetDevDependency(packageName); + } + + public addOrUpdateDependency( + packageName: string, + newVersion: string, + dependencyType: DependencyType + ): void { + return this._fileManager.addOrUpdateDependency(packageName, newVersion, dependencyType); + } + + public removeDependency(packageName: string, dependencyType: DependencyType): void { + return this._fileManager.removeDependency(packageName, dependencyType); + } + + public saveIfModified(): boolean { + return this._fileManager.saveIfModified(); + } +} diff --git a/libraries/rush-lib/src/logic/yarn/YarnOptionsConfiguration.ts b/libraries/rush-lib/src/logic/yarn/YarnOptionsConfiguration.ts new file mode 100644 index 00000000000..479ee9693ca --- /dev/null +++ b/libraries/rush-lib/src/logic/yarn/YarnOptionsConfiguration.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + type IPackageManagerOptionsJsonBase, + PackageManagerOptionsConfigurationBase +} from '../base/BasePackageManagerOptionsConfiguration'; + +/** + * Part of IRushConfigurationJson. + * @internal + */ +export interface IYarnOptionsJson extends IPackageManagerOptionsJsonBase { + /** + * If true, then Rush will add the "--ignore-engines" option when invoking Yarn. + * This allows "rush install" to succeed if there are dependencies with engines defined in + * package.json which do not match the current environment. + * + * The default value is false. + */ + ignoreEngines?: boolean; +} + +/** + * Options that are only used when the yarn package manager is selected. + * + * @remarks + * It is valid to define these options in rush.json even if the yarn package manager + * is not being used. + * + * @public + */ +export class YarnOptionsConfiguration extends PackageManagerOptionsConfigurationBase { + /** + * If true, then Rush will add the "--ignore-engines" option when invoking Yarn. + * This allows "rush install" to succeed if there are dependencies with engines defined in + * package.json which do not match the current environment. + * + * The default value is false. + */ + public readonly ignoreEngines: boolean; + + /** @internal */ + public constructor(json: IYarnOptionsJson) { + super(json); + this.ignoreEngines = !!json.ignoreEngines; + } +} diff --git a/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts b/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts new file mode 100644 index 00000000000..cbf068a8d41 --- /dev/null +++ b/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts @@ -0,0 +1,294 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { BaseProjectShrinkwrapFile } from '../base/BaseProjectShrinkwrapFile'; +import type { Subspace } from '../../api/Subspace'; + +/** + * @yarnpkg/lockfile doesn't have types + */ +// eslint-disable-next-line +declare module YarnPkgLockfileTypes { + export class ParseResult { + public object: IYarnShrinkwrapJson; + } + + export function parse(shrinkwrapJson: string): ParseResult; + + export function stringify(shrinkwrap: IYarnShrinkwrapJson): string; +} +const lockfileModule: typeof YarnPkgLockfileTypes = Import.lazy('@yarnpkg/lockfile', require); + +/** + * Used with YarnShrinkwrapFile._encodePackageNameAndSemVer() and _decodePackageNameAndSemVer(). + */ +interface IPackageNameAndSemVer { + packageName: string; + semVerRange: string; +} + +/** + * Part of IYarnShrinkwrapJson + */ +interface IYarnShrinkwrapEntry { + /** + * The specific version that was chosen for this entry (i.e. package name and SemVer range)/ + * + */ + version: string; + + /** + * The source (e.g. registry tarball URL) of the package that was installed + * with the integrity hash as a suffix. + * + * Examples: + * https://registry.yarnpkg.com/@pnpm/types/-/types-1.7.0.tgz#9d66a8bed3fabcd80f288b3e7884b7418b05b5a9 + * file:./projects/api-documenter.tgz#d95f9779aa45df3ef1bbd95dec324793540765ba + */ + resolved: string; + + /** + * Records the original (unsolved) "dependencies" from the package.json. + */ + dependencies?: { [dependency: string]: string }; + + /** + * Records the original (unsolved) "optionalDependencies" from the package.json. + * + * NOTE: Interestingly "peerDependencies" are apparently not tracked by the shrinkwrap file. + * The "devDependencies" are not tracked either, because they are always indirect dependencies + * for the installation. + */ + optionalDependencies?: { [dependency: string]: string }; +} + +/** + * Used by YarnShrinkwrapFile to interpret the `@yarnpkg/lockfile` data structure. + */ +interface IYarnShrinkwrapJson { + /** + * Example keys: + * `js-tokens@^3.0.0 || ^4.0.0` + * `@rush-temp/api-extractor-test-03@file:./projects/api-extractor-test-03.tgz` + * + * The value records how the SemVer range was solved. + */ + [packageNameAndSemVer: string]: IYarnShrinkwrapEntry; +} + +/** + * Support for consuming the "yarn.lock" file. + * + * Yarn refers to its shrinkwrap file as a "lock file", even though it has nothing to do + * with file locking. Apparently this was based on a convention of the Ruby bundler. + * Since Rush has to work interchangeably with 3 different package managers, here we refer + * generically to yarn.lock as a "shrinkwrap file". + * + * If Rush's Yarn support gains popularity, we will try to improve the wording of + * logging messages to use terminology more consistent with Yarn's own documentation. + */ +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[]; + + private constructor(shrinkwrapJson: IYarnShrinkwrapJson) { + super(); + this._shrinkwrapJson = shrinkwrapJson; + this._tempProjectNames = []; + + const seenEntries: Set = new Set(); + + for (const key of Object.keys(this._shrinkwrapJson)) { + // Example key: + const packageNameAndSemVer: IPackageNameAndSemVer = YarnShrinkwrapFile._decodePackageNameAndSemVer(key); + + // If it starts with @rush-temp, then include it: + if ( + PackageNameParsers.permissive.getScope(packageNameAndSemVer.packageName) === + RushConstants.rushTempNpmScope + ) { + if (!/^file:/i.test(packageNameAndSemVer.semVerRange)) { + // Sanity check to make sure this is a real package. + // (Nobody should ever have an actual dependency on an "@rush-temp/" package. + throw new Error( + 'Unexpected package/semver expression found in the Yarn shrinkwrap file (yarn.lock): ' + + JSON.stringify(key) + ); + } + + if (!seenEntries.add(packageNameAndSemVer.packageName)) { + // Sanity check -- this should never happen + throw new Error( + 'Duplicate @rush-temp package found in the Yarn shrinkwrap file (yarn.lock): ' + + JSON.stringify(key) + ); + } + + this._tempProjectNames.push(packageNameAndSemVer.packageName); + + const entry: IYarnShrinkwrapEntry = this._shrinkwrapJson[key]; + + // Yarn fails installation if the integrity hash does not match a "file://" reference to a tarball. + // This is incorrect: Normally a mismatched integrity hash does indicate a corrupted download, + // since an NPM registry normally guarantees that a specific version number cannot be republished + // with different content. But this is NOT true for a "file://" reference, and there are valid + // reasons why someone would update the file. (PNPM handles this correctly, by simply reinstalling + // the tarball if its hash has changed.) + // + // As a workaround, we can simply remove the hashes from the shrinkwrap file. We will convert this: + // "file:./projects/my-project.tgz#80cefe05fd715e65219d1ed481209dc4023408aa" + // ..to this: + // "file:./projects/my-project.tgz" + const indexOfHash: number = entry.resolved.indexOf('#'); + if (indexOfHash >= 0) { + entry.resolved = entry.resolved.substring(0, indexOfHash); + } + } + } + + this._tempProjectNames.sort(); // make the result deterministic + + // We don't support Yarn workspaces yet + this.isWorkspaceCompatible = false; + } + + public static loadFromFile(shrinkwrapFilename: string): YarnShrinkwrapFile | undefined { + try { + const shrinkwrapContent: string = FileSystem.readFile(shrinkwrapFilename); + return YarnShrinkwrapFile.loadFromString(shrinkwrapContent); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + return undefined; // file does not exist + } + throw new Error(`Error reading "${shrinkwrapFilename}":\n ${(error as Error).message}`); + } + } + + public static loadFromString(shrinkwrapContent: string): YarnShrinkwrapFile { + const shrinkwrapJson: YarnPkgLockfileTypes.ParseResult = lockfileModule.parse(shrinkwrapContent); + 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 { + return this._tempProjectNames; + } + + /** @override */ + public 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({ + packageName: dependencySpecifier.packageName, + semVerRange: dependencySpecifier.versionSpecifier + }); + + // Check whether this exact key appears in the shrinkwrap file + return Object.hasOwnProperty.call(this._shrinkwrapJson, key); + } + + /** @override */ + public tryEnsureCompatibleDependency( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): boolean { + return this.hasCompatibleTopLevelDependency(dependencySpecifier); + } + + /** @override */ + protected serialize(): string { + return lockfileModule.stringify(this._shrinkwrapJson); + } + + /** @override */ + protected getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { + throw new InternalError('Not implemented'); + } + + /** @override */ + protected tryEnsureDependencyVersion( + dependencySpecifier: DependencySpecifier, + tempProjectName: string + ): DependencySpecifier | undefined { + throw new InternalError('Not implemented'); + } + + /** @override */ + public getProjectShrinkwrap( + project: RushConfigurationProject + ): BaseProjectShrinkwrapFile | undefined { + return undefined; + } + + /** @override */ + public async isWorkspaceProjectModifiedAsync( + project: RushConfigurationProject, + subspace: Subspace + ): Promise { + throw new InternalError('Not implemented'); + } +} diff --git a/libraries/rush-lib/src/npm-check-typings.d.ts b/libraries/rush-lib/src/npm-check-typings.d.ts new file mode 100644 index 00000000000..5c25d1d8c93 --- /dev/null +++ b/libraries/rush-lib/src/npm-check-typings.d.ts @@ -0,0 +1,47 @@ +declare module 'npm-check' { + interface INpmCheckOptions { + global?: boolean; + update?: boolean; + skipUnused?: boolean; + devOnly?: boolean; + ignoreDev?: boolean; + cwd?: string; + saveExact?: boolean; + currentState?: Object; + } + + type INpmCheckGetSetValues = 'packages' | 'debug' | 'global' | 'cwd' | 'cwdPackageJson' | 'emoji'; + + type INpmVersionBumpType = 'patch' | 'minor' | 'major' | 'prerelease' | 'build' | 'nonSemver' | null; + + interface INpmCheckCurrentState { + get: (key: INpmCheckGetSetValues) => INpmCheckPackage[]; + set: (key: INpmCheckGetSetValues, val: any) => void; + } + + interface INpmCheckPackage { + moduleName: string; // name of the module. + homepage: string; // url to the home page. + regError: any; // error communicating with the registry + pkgError: any; // error reading the package.json + latest: string; // latest according to the registry. + installed: string; // version installed + isInstalled: boolean; // Is it installed? + notInstalled: boolean; // Is it installed? + packageWanted: string; // Requested version from the package.json. + packageJson: string; // Version or range requested in the parent package.json. + devDependency: boolean; // Is this a devDependency? + peerDependency: boolean; // Is this a peerDependency? + usedInScripts: undefined | string[]; // Array of `scripts` in package.json that use this module. + mismatch: boolean; // Does the version installed not match the range in package.json? + semverValid: string; // Is the installed version valid semver? + easyUpgrade: boolean; // Will running just `npm install` upgrade the module? + bump: INpmVersionBumpType; // What kind of bump is required to get the latest + unused: boolean; // Is this module used in the code? + } + + //The default function returns a promise + export default function (options: INpmCheckOptions): { + then(stateFn: (state: INpmCheckCurrentState) => void): void; + }; +} diff --git a/libraries/rush-lib/src/pluginFramework/IRushPlugin.ts b/libraries/rush-lib/src/pluginFramework/IRushPlugin.ts new file mode 100644 index 00000000000..d0db61a3049 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/IRushPlugin.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. + +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushSession } from './RushSession'; + +/** + * @beta + */ +export interface IRushPlugin { + apply(rushSession: RushSession, rushConfiguration: RushConfiguration): void; +} diff --git a/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts new file mode 100644 index 00000000000..97ccdb064aa --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts @@ -0,0 +1,216 @@ +// 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, + SyncWaterfallHook +} from 'tapable'; + +import type { CommandLineParameter } from '@rushstack/ts-command-line'; + +import type { BuildCacheConfiguration } from '../api/BuildCacheConfiguration'; +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 { IInputsSnapshot } from '../logic/incremental/InputsSnapshot'; +import type { IEnvironment } from '../utilities/Utilities'; + +/** + * A plugin that interacts with a phased commands. + * @alpha + */ +export interface IPhasedCommandPlugin { + /** + * Applies this plugin. + */ + apply(hooks: PhasedCommandHooks): void; +} + +/** + * Context used for creating operations to be executed. + * @alpha + */ +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. + */ + readonly cobuildConfiguration: CobuildConfiguration | undefined; + /** + * The set of custom parameters for the executing command. + * Maps from the `longName` field in command-line.json to the parser configuration in ts-command-line. + */ + readonly customParameters: ReadonlyMap; + /** + * 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 currently configured maximum parallelism for the command. + */ + readonly parallelism: number; + /** + * The set of phases original for the current command execution. + */ + readonly phaseOriginal: ReadonlySet; + /** + * The set of phases selected for the current command 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`. + */ + readonly projectsInUnknownState: ReadonlySet; + /** + * The Rush configuration + */ + readonly rushConfiguration: RushConfiguration; + /** + * If true, Rush will automatically include the dependent phases for the specified set of phases. + * @remarks + * If the selection of projects was "unsafe" (i.e. missing some dependencies), this will add the + * minimum number of phases required to make it safe. + */ + readonly includePhaseDeps: 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 + */ + readonly invalidateOperation?: ((operation: Operation, reason: string) => void) | undefined; +} + +/** + * Context used for executing operations. + * @alpha + */ +export interface IExecuteOperationsContext 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; + + /** + * An abort controller that can be used to abort the current set of queued operations. + */ + readonly abortController: AbortController; +} + +/** + * Hooks into the execution process for phased commands + * @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 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 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'); + + /** + * Hook invoked after executing operations and before waitingForChanges. Allows the caller + * to augment or modify the log entry about to be written. + */ + public readonly beforeLog: SyncHook = new SyncHook(['telemetryData'], 'beforeLog'); +} diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts new file mode 100644 index 00000000000..ad19acb0386 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.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 * as path from 'node:path'; + +import { + FileSystem, + JsonFile, + PosixModeBits, + type JsonObject, + type JsonSchema +} from '@rushstack/node-core-library'; + +import type { IRushPluginConfiguration } from '../../api/RushPluginsConfiguration'; +import { Autoinstaller } from '../../logic/Autoinstaller'; +import { RushConstants } from '../../logic/RushConstants'; +import { + type IPluginLoaderOptions, + type IRushPluginManifest, + type IRushPluginManifestJson, + PluginLoaderBase +} from './PluginLoaderBase'; +import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; + +interface IAutoinstallerPluginLoaderOptions extends IPluginLoaderOptions { + restrictConsoleOutput: boolean; + rushGlobalFolder: RushGlobalFolder; +} + +/** + * @beta + */ +export class AutoinstallerPluginLoader extends PluginLoaderBase { + public readonly packageFolder: string; + + public readonly autoinstaller: Autoinstaller; + + public constructor(options: IAutoinstallerPluginLoaderOptions) { + super(options); + this.autoinstaller = new Autoinstaller({ + autoinstallerName: options.pluginConfiguration.autoinstallerName, + rushConfiguration: this._rushConfiguration, + restrictConsoleOutput: options.restrictConsoleOutput, + rushGlobalFolder: options.rushGlobalFolder + }); + + this.packageFolder = path.join(this.autoinstaller.folderFullPath, 'node_modules', this.packageName); + } + + /** + * The folder where rush plugins static files are stored. + * Example: `C:\MyRepo\common\autoinstallers\\rush-plugins` + */ + public static getPluginAutoinstallerStorePath(autoinstaller: Autoinstaller): string { + return path.join(autoinstaller.folderFullPath, 'rush-plugins'); + } + + public update(): void { + const packageName: string = this.packageName; + const pluginName: string = this.pluginName; + const packageFolder: string = this.packageFolder; + const manifestPath: string = path.join(packageFolder, RushConstants.rushPluginManifestFilename); + + // validate + const manifest: IRushPluginManifestJson = JsonFile.loadAndValidate( + manifestPath, + AutoinstallerPluginLoader._jsonSchema + ); + + const destinationManifestPath: string = this._getManifestPath(); + FileSystem.copyFile({ + sourcePath: manifestPath, + destinationPath: destinationManifestPath + }); + // Make permission consistent since it will be committed to Git + FileSystem.changePosixModeBits( + destinationManifestPath, + // eslint-disable-next-line no-bitwise + PosixModeBits.AllRead | PosixModeBits.UserWrite + ); + + const pluginManifest: IRushPluginManifest | undefined = manifest.plugins.find( + (item) => item.pluginName === pluginName + ); + if (!pluginManifest) { + throw new Error( + `A plugin named "${pluginName}" is not provided by the Rush plugin package "${packageName}"` + ); + } + + const commandLineJsonFilePath: string | undefined = pluginManifest.commandLineJsonFilePath; + if (commandLineJsonFilePath) { + const commandLineJsonFullFilePath: string = path.join(packageFolder, commandLineJsonFilePath); + if (!FileSystem.exists(commandLineJsonFullFilePath)) { + this._terminal.writeErrorLine( + `The Rush plugin "${pluginName}" from "${packageName}" specifies a commandLineJsonFilePath` + + ` ${commandLineJsonFilePath} that does not exist.` + ); + } + const destinationCommandLineJsonFilePath: string = this._getCommandLineJsonFilePath(); + FileSystem.copyFile({ + sourcePath: commandLineJsonFullFilePath, + destinationPath: destinationCommandLineJsonFilePath + }); + // Make permission consistent since it will be committed to Git + FileSystem.changePosixModeBits( + destinationCommandLineJsonFilePath, + // eslint-disable-next-line no-bitwise + PosixModeBits.AllRead | PosixModeBits.UserWrite + ); + } + } + + protected override _getCommandLineAdditionalPathFolders(): string[] { + const additionalPathFolders: string[] = super._getCommandLineAdditionalPathFolders(); + additionalPathFolders.push( + // Example: `common/autoinstaller/plugins/node_modules/.bin` + path.join(this.autoinstaller.folderFullPath, 'node_modules', '.bin') + ); + return additionalPathFolders; + } + + protected override _getPluginOptions(): JsonObject { + const optionsJsonFilePath: string = this._getPluginOptionsJsonFilePath(); + const optionsSchema: JsonSchema | undefined = this._getRushPluginOptionsSchema(); + + let pluginOptions: JsonObject = {}; + try { + pluginOptions = JsonFile.load(optionsJsonFilePath); + } catch (e) { + if (FileSystem.isFileDoesNotExistError(e as Error)) { + if (optionsSchema) { + throw new Error( + `Plugin options are required by ${this.pluginName} from package ${this.packageName}, please create it at ${optionsJsonFilePath}.` + ); + } else { + return {}; + } + } + throw e; + } + + if (optionsSchema) { + optionsSchema.validateObject(pluginOptions, optionsJsonFilePath); + } + + return pluginOptions; + } + + protected override _getManifestPath(): string { + return path.join( + AutoinstallerPluginLoader.getPluginAutoinstallerStorePath(this.autoinstaller), + this.packageName, + RushConstants.rushPluginManifestFilename + ); + } + + protected override _getCommandLineJsonFilePath(): string { + return path.join( + AutoinstallerPluginLoader.getPluginAutoinstallerStorePath(this.autoinstaller), + this.packageName, + this.pluginName, + RushConstants.commandLineFilename + ); + } +} diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/BuiltInPluginLoader.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/BuiltInPluginLoader.ts new file mode 100644 index 00000000000..9ad86d9d956 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/BuiltInPluginLoader.ts @@ -0,0 +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 { IRushPluginConfigurationBase } from '../../api/RushPluginsConfiguration'; +import { type IPluginLoaderOptions, PluginLoaderBase } from './PluginLoaderBase'; + +/** + * @internal + */ +export interface IBuiltInPluginConfiguration extends IRushPluginConfigurationBase { + pluginPackageFolder: string; +} + +/** + * @remarks + * Used to load plugins that are dependencies of Rush. + */ +export class BuiltInPluginLoader extends PluginLoaderBase { + public readonly packageFolder: string; + + public constructor(options: IPluginLoaderOptions) { + super(options); + this.packageFolder = options.pluginConfiguration.pluginPackageFolder; + } +} diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/PluginLoaderBase.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/PluginLoaderBase.ts new file mode 100644 index 00000000000..1c56731bdbe --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/PluginLoaderBase.ts @@ -0,0 +1,234 @@ +// 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, + InternalError, + JsonFile, + type JsonObject, + JsonSchema +} from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import { CommandLineConfiguration } from '../../api/CommandLineConfiguration'; +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { IRushPluginConfigurationBase } from '../../api/RushPluginsConfiguration'; +import { RushConstants } from '../../logic/RushConstants'; +import type { IRushPlugin } from '../IRushPlugin'; +import { RushSdk } from './RushSdk'; +import schemaJson from '../../schemas/rush-plugin-manifest.schema.json'; + +export interface IRushPluginManifest { + pluginName: string; + description: string; + entryPoint?: string; + optionsSchema?: string; + associatedCommands?: string[]; + commandLineJsonFilePath?: string; +} + +export interface IRushPluginManifestJson { + plugins: IRushPluginManifest[]; +} + +export interface IPluginLoaderOptions { + pluginConfiguration: TPluginConfiguration; + rushConfiguration: RushConfiguration; + terminal: ITerminal; +} + +export abstract class PluginLoaderBase< + TPluginConfiguration extends IRushPluginConfigurationBase = IRushPluginConfigurationBase +> { + protected static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + + public readonly packageName: Readonly; + public readonly pluginName: Readonly; + protected readonly _rushConfiguration: RushConfiguration; + protected readonly _terminal: ITerminal; + + protected _manifestCache: Readonly | undefined; + + /** + * The folder that should be used for resolving the plugin's NPM package. + */ + public abstract readonly packageFolder: string; + + public constructor({ + pluginConfiguration, + rushConfiguration, + terminal + }: IPluginLoaderOptions) { + this.packageName = pluginConfiguration.packageName; + this.pluginName = pluginConfiguration.pluginName; + this._rushConfiguration = rushConfiguration; + this._terminal = terminal; + } + + public load(): IRushPlugin | undefined { + const resolvedPluginPath: string | undefined = this._resolvePlugin(); + if (!resolvedPluginPath) { + return undefined; + } + const pluginOptions: JsonObject = this._getPluginOptions(); + + RushSdk.ensureInitialized(); + + return this._loadAndValidatePluginPackage(resolvedPluginPath, pluginOptions); + } + + public get pluginManifest(): IRushPluginManifest { + return this._getRushPluginManifest(); + } + + public getCommandLineConfiguration(): CommandLineConfiguration | undefined { + const commandLineJsonFilePath: string | undefined = this._getCommandLineJsonFilePath(); + if (!commandLineJsonFilePath) { + return undefined; + } + const commandLineConfiguration: CommandLineConfiguration | undefined = + CommandLineConfiguration.tryLoadFromFile(commandLineJsonFilePath); + if (!commandLineConfiguration) { + return undefined; + } + + for (const additionalPathFolder of this._getCommandLineAdditionalPathFolders().reverse()) { + commandLineConfiguration.prependAdditionalPathFolder(additionalPathFolder); + } + + commandLineConfiguration.shellCommandTokenContext = { + packageFolder: this.packageFolder + }; + return commandLineConfiguration; + } + + protected _getCommandLineAdditionalPathFolders(): string[] { + return [ + // Example: `@microsoft/rush-lib/node_modules//node_modules/.bin` + // Example: `common/autoinstaller/plugins/node_modules//node_modules/.bin` + path.join(this.packageFolder, 'node_modules', '.bin') + ]; + } + + protected _getCommandLineJsonFilePath(): string | undefined { + const { commandLineJsonFilePath } = this._getRushPluginManifest(); + if (!commandLineJsonFilePath) { + return undefined; + } + return path.join(this.packageFolder, commandLineJsonFilePath); + } + + private _loadAndValidatePluginPackage(resolvedPluginPath: string, options?: JsonObject): IRushPlugin { + type IRushPluginCtor = new (opts: T) => IRushPlugin; + let pluginPackage: IRushPluginCtor; + try { + const loadedPluginPackage: IRushPluginCtor | { default: IRushPluginCtor } = require(resolvedPluginPath); + pluginPackage = (loadedPluginPackage as { default: IRushPluginCtor }).default || loadedPluginPackage; + } catch (e) { + throw new InternalError(`Error loading rush plugin from "${resolvedPluginPath}": ${e}`); + } + + if (!pluginPackage) { + throw new InternalError(`Rush plugin loaded from "${resolvedPluginPath}" is null or undefined.`); + } + + this._terminal.writeVerboseLine(`Loaded rush plugin from "${resolvedPluginPath}"`); + + const plugin: IRushPlugin = new pluginPackage(options); + + if (!plugin.apply || typeof pluginPackage.apply !== 'function') { + throw new InternalError( + `Rush plugin must define an "apply" function. The plugin loaded from "${resolvedPluginPath}" ` + + 'either doesn\'t define an "apply" property, or its value isn\'t a function.' + ); + } + + return plugin; + } + + private _resolvePlugin(): string | undefined { + const entryPoint: string | undefined = this._getRushPluginManifest().entryPoint; + if (!entryPoint) { + return undefined; + } + const packageFolder: string = this.packageFolder; + const modulePath: string = path.join(packageFolder, entryPoint); + if (!FileSystem.exists(modulePath)) { + throw new InternalError( + `Unable to find entry point "${modulePath}" for rush plugin "${this.pluginName}".` + ); + } + return modulePath; + } + + protected _getPluginOptions(): JsonObject { + const optionsJsonFilePath: string = this._getPluginOptionsJsonFilePath(); + const optionsSchema: JsonSchema | undefined = this._getRushPluginOptionsSchema(); + + let pluginOptions: JsonObject = {}; + try { + pluginOptions = JsonFile.load(optionsJsonFilePath); + } catch (e) { + if (FileSystem.isFileDoesNotExistError(e as Error)) { + return {}; + } + throw e; + } + + if (optionsSchema) { + optionsSchema.validateObject(pluginOptions, optionsJsonFilePath); + } + + return pluginOptions; + } + + protected _getPluginOptionsJsonFilePath(): string { + return path.join(this._rushConfiguration.rushPluginOptionsFolder, `${this.pluginName}.json`); + } + + protected _getRushPluginOptionsSchema(): JsonSchema | undefined { + const optionsSchema: string | undefined = this._getRushPluginManifest().optionsSchema; + if (!optionsSchema) { + return undefined; + } + const optionsSchemaFilePath: string = path.join(this.packageFolder, optionsSchema); + return JsonSchema.fromFile(optionsSchemaFilePath); + } + + private _getRushPluginManifest(): IRushPluginManifest { + if (!this._manifestCache) { + const packageName: string = this.packageName; + const pluginName: string = this.pluginName; + + const manifestPath: string = this._getManifestPath(); + + if (!FileSystem.exists(manifestPath)) { + throw new Error( + `Manifest for rush plugin package ${packageName} not found.\nPlease run 'rush update' first.` + ); + } + + const rushPluginManifestJson: IRushPluginManifestJson = JsonFile.loadAndValidate( + manifestPath, + PluginLoaderBase._jsonSchema + ); + + const pluginManifest: IRushPluginManifest | undefined = rushPluginManifestJson.plugins.find( + (item) => item.pluginName === pluginName + ); + if (!pluginManifest) { + throw new Error(`${pluginName} is not provided by Rush plugin package "${packageName}"`); + } + + this._manifestCache = pluginManifest; + } + + return this._manifestCache; + } + + protected _getManifestPath(): string { + return path.join(this.packageFolder, RushConstants.rushPluginManifestFilename); + } +} diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts new file mode 100644 index 00000000000..b69905f5fc6 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.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. + +type RushLibModuleType = Record; +declare const global: typeof globalThis & { + ___rush___rushLibModule?: RushLibModuleType; +}; + +export class RushSdk { + private static _initialized: boolean = false; + + public static ensureInitialized(): void { + if (!RushSdk._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; + } + } +} diff --git a/libraries/rush-lib/src/pluginFramework/PluginManager.ts b/libraries/rush-lib/src/pluginFramework/PluginManager.ts new file mode 100644 index 00000000000..9a5181e078c --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/PluginManager.ts @@ -0,0 +1,237 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, Import, InternalError } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { CommandLineConfiguration } from '../api/CommandLineConfiguration'; +import type { RushConfiguration } from '../api/RushConfiguration'; +import { BuiltInPluginLoader, type IBuiltInPluginConfiguration } from './PluginLoader/BuiltInPluginLoader'; +import type { IRushPlugin } from './IRushPlugin'; +import { AutoinstallerPluginLoader } from './PluginLoader/AutoinstallerPluginLoader'; +import type { RushSession } from './RushSession'; +import type { PluginLoaderBase } from './PluginLoader/PluginLoaderBase'; +import { Rush } from '../api/Rush'; +import type { RushGlobalFolder } from '../api/RushGlobalFolder'; + +export interface IPluginManagerOptions { + terminal: ITerminal; + rushConfiguration: RushConfiguration; + rushSession: RushSession; + builtInPluginConfigurations: IBuiltInPluginConfiguration[]; + restrictConsoleOutput: boolean; + rushGlobalFolder: RushGlobalFolder; +} + +export interface ICustomCommandLineConfigurationInfo { + commandLineConfiguration: CommandLineConfiguration; + pluginLoader: PluginLoaderBase; +} + +export class PluginManager { + private readonly _terminal: ITerminal; + private readonly _rushConfiguration: RushConfiguration; + private readonly _rushSession: RushSession; + private readonly _restrictConsoleOutput: boolean; + private readonly _builtInPluginLoaders: BuiltInPluginLoader[]; + private readonly _autoinstallerPluginLoaders: AutoinstallerPluginLoader[]; + private readonly _installedAutoinstallerNames: Set; + private readonly _loadedPluginNames: Set = new Set(); + private readonly _rushGlobalFolder: RushGlobalFolder; + + private _error: Error | undefined; + + public constructor(options: IPluginManagerOptions) { + this._terminal = options.terminal; + this._rushConfiguration = options.rushConfiguration; + this._rushSession = options.rushSession; + this._restrictConsoleOutput = options.restrictConsoleOutput; + this._rushGlobalFolder = options.rushGlobalFolder; + + this._installedAutoinstallerNames = new Set(); + + // Eventually we will require end users to explicitly configure all Rush plugins in use, regardless of + // whether they are first party or third party plugins. However, we're postponing that requirement + // until after the plugin feature has stabilized and is fully documented. In the meantime, Rush's + // built-in plugins are dependencies of @microsoft/rush-lib and get loaded by default (without any + // configuration). + // + // The plugins have devDependencies on Rush, which would create a circular dependency in our local + // workspace if we added them to rush-lib/package.json. Instead we put them in a special section + // "publishOnlyDependencies" which gets moved into "dependencies" during publishing. + const builtInPluginConfigurations: IBuiltInPluginConfiguration[] = options.builtInPluginConfigurations; + + const ownPackageJsonDependencies: Record = Rush._rushLibPackageJson.dependencies || {}; + function tryAddBuiltInPlugin(builtInPluginName: string, pluginPackageName?: string): void { + if (!pluginPackageName) { + pluginPackageName = `@rushstack/${builtInPluginName}`; + } + if (ownPackageJsonDependencies[pluginPackageName]) { + builtInPluginConfigurations.push({ + packageName: pluginPackageName, + pluginName: builtInPluginName, + pluginPackageFolder: Import.resolvePackage({ + packageName: pluginPackageName, + baseFolderPath: __dirname + }) + }); + } + } + + tryAddBuiltInPlugin('rush-amazon-s3-build-cache-plugin'); + tryAddBuiltInPlugin('rush-azure-storage-build-cache-plugin'); + tryAddBuiltInPlugin('rush-http-build-cache-plugin'); + // This is a secondary plugin inside the `@rushstack/rush-azure-storage-build-cache-plugin` + // package. Because that package comes with Rush (for now), it needs to get registered here. + // If the necessary config file doesn't exist, this plugin doesn't do anything. + tryAddBuiltInPlugin( + 'rush-azure-interactive-auth-plugin', + '@rushstack/rush-azure-storage-build-cache-plugin' + ); + + this._builtInPluginLoaders = builtInPluginConfigurations.map((pluginConfiguration) => { + return new BuiltInPluginLoader({ + pluginConfiguration, + rushConfiguration: this._rushConfiguration, + terminal: this._terminal + }); + }); + + this._autoinstallerPluginLoaders = ( + this._rushConfiguration?._rushPluginsConfiguration.configuration.plugins ?? [] + ).map((pluginConfiguration) => { + return new AutoinstallerPluginLoader({ + pluginConfiguration, + rushConfiguration: this._rushConfiguration, + terminal: this._terminal, + restrictConsoleOutput: this._restrictConsoleOutput, + rushGlobalFolder: this._rushGlobalFolder + }); + }); + } + + /** + * If an error occurs while attempting to load plugins, it will be saved in this property. + * Rush will attempt to continue and will report the error later by `BaseRushAction._throwPluginErrorIfNeed()` + * (unless we are invoking a command that is used to fix plugin problems). + */ + public get error(): Error | undefined { + return this._error; + } + + public async updateAsync(): Promise { + await this._preparePluginAutoinstallersAsync(this._autoinstallerPluginLoaders); + const preparedAutoinstallerNames: Set = new Set(); + for (const { autoinstaller } of this._autoinstallerPluginLoaders) { + const storePath: string = AutoinstallerPluginLoader.getPluginAutoinstallerStorePath(autoinstaller); + if (!preparedAutoinstallerNames.has(autoinstaller.name)) { + FileSystem.ensureEmptyFolder(storePath); + preparedAutoinstallerNames.add(autoinstaller.name); + } + } + for (const pluginLoader of this._autoinstallerPluginLoaders) { + pluginLoader.update(); + } + } + + public async reinitializeAllPluginsForCommandAsync(commandName: string): Promise { + this._error = undefined; + await this.tryInitializeUnassociatedPluginsAsync(); + await this.tryInitializeAssociatedCommandPluginsAsync(commandName); + } + + public async _preparePluginAutoinstallersAsync(pluginLoaders: AutoinstallerPluginLoader[]): Promise { + for (const { autoinstaller } of pluginLoaders) { + if (!this._installedAutoinstallerNames.has(autoinstaller.name)) { + await autoinstaller.prepareAsync(); + this._installedAutoinstallerNames.add(autoinstaller.name); + } + } + } + + public async tryInitializeUnassociatedPluginsAsync(): Promise { + try { + const autoinstallerPluginLoaders: AutoinstallerPluginLoader[] = this._getUnassociatedPluginLoaders( + this._autoinstallerPluginLoaders + ); + await this._preparePluginAutoinstallersAsync(autoinstallerPluginLoaders); + const builtInPluginLoaders: BuiltInPluginLoader[] = this._getUnassociatedPluginLoaders( + this._builtInPluginLoaders + ); + this._initializePlugins([...builtInPluginLoaders, ...autoinstallerPluginLoaders]); + } catch (e) { + this._error = e as Error; + } + } + + public async tryInitializeAssociatedCommandPluginsAsync(commandName: string): Promise { + try { + const autoinstallerPluginLoaders: AutoinstallerPluginLoader[] = this._getPluginLoadersForCommand( + commandName, + this._autoinstallerPluginLoaders + ); + await this._preparePluginAutoinstallersAsync(autoinstallerPluginLoaders); + const builtInPluginLoaders: BuiltInPluginLoader[] = this._getPluginLoadersForCommand( + commandName, + this._builtInPluginLoaders + ); + this._initializePlugins([...builtInPluginLoaders, ...autoinstallerPluginLoaders]); + } catch (e) { + this._error = e as Error; + } + } + + public tryGetCustomCommandLineConfigurationInfos(): ICustomCommandLineConfigurationInfo[] { + const commandLineConfigurationInfos: ICustomCommandLineConfigurationInfo[] = []; + for (const pluginLoader of this._autoinstallerPluginLoaders) { + const commandLineConfiguration: CommandLineConfiguration | undefined = + pluginLoader.getCommandLineConfiguration(); + if (commandLineConfiguration) { + commandLineConfigurationInfos.push({ + commandLineConfiguration, + pluginLoader + }); + } + } + return commandLineConfigurationInfos; + } + + private _initializePlugins(pluginLoaders: PluginLoaderBase[]): void { + for (const pluginLoader of pluginLoaders) { + const pluginName: string = pluginLoader.pluginName; + if (this._loadedPluginNames.has(pluginName)) { + throw new Error(`Error applying plugin: A plugin with name "${pluginName}" has already been applied`); + } + const plugin: IRushPlugin | undefined = pluginLoader.load(); + this._loadedPluginNames.add(pluginName); + if (plugin) { + this._applyPlugin(plugin, pluginName); + } + } + } + + private _getUnassociatedPluginLoaders( + pluginLoaders: T[] + ): T[] { + return pluginLoaders.filter((pluginLoader) => { + return !pluginLoader.pluginManifest.associatedCommands; + }); + } + + private _getPluginLoadersForCommand( + commandName: string, + pluginLoaders: T[] + ): T[] { + return pluginLoaders.filter((pluginLoader) => { + return pluginLoader.pluginManifest.associatedCommands?.includes(commandName); + }); + } + + private _applyPlugin(plugin: IRushPlugin, pluginName: string): void { + try { + plugin.apply(this._rushSession, this._rushConfiguration); + } catch (e) { + throw new InternalError(`Error applying "${pluginName}": ${e}`); + } + } +} diff --git a/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts b/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts new file mode 100644 index 00000000000..76e51d8e17d --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AsyncParallelHook, AsyncSeriesHook, HookMap } from 'tapable'; + +import type { ITelemetryData } from '../logic/Telemetry'; +import type { PhasedCommandHooks } from './PhasedCommandHooks'; +import type { Subspace } from '../api/Subspace'; + +/** + * Information about the currently executing command provided to plugins. + * @beta + */ +export interface IRushCommand { + /** + * The name of this command, as seen on the command line + */ + readonly actionName: string; +} + +/** + * Information about the currently executing global script command (as defined in command-line.json) provided to plugins. + * @beta + */ +export interface IGlobalCommand extends IRushCommand { + // Nothing added. +} + +/** + * Information about the currently executing phased script command (as defined in command-line.json, or default "build" or "rebuild") provided to plugins. + * @beta + */ +export interface IPhasedCommand extends IRushCommand { + /** + * Hooks into the execution of the current phased command + * @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; +} + +/** + * Hooks into the lifecycle of the Rush process invocation that plugins may tap into. + * + * @beta + */ +export class RushLifecycleHooks { + /** + * The hook to run before executing any Rush CLI Command. + */ + public readonly initialize: AsyncSeriesHook = new AsyncSeriesHook( + ['command'], + 'initialize' + ); + + /** + * The hook to run before executing any global Rush CLI Command (defined in command-line.json). + */ + public readonly runAnyGlobalCustomCommand: AsyncSeriesHook = + new AsyncSeriesHook(['command'], 'runAnyGlobalCustomCommand'); + + /** + * A hook map to allow plugins to hook specific named global commands (defined in command-line.json) before execution. + */ + public readonly runGlobalCustomCommand: HookMap> = new HookMap( + (key: string) => { + return new AsyncSeriesHook(['command'], key); + }, + 'runGlobalCustomCommand' + ); + + /** + * The hook to run before executing any phased Rush CLI Command (defined in command-line.json, or the default "build" or "rebuild"). + */ + public readonly runAnyPhasedCommand: AsyncSeriesHook = new AsyncSeriesHook( + ['command'], + 'runAnyPhasedCommand' + ); + + /** + * A hook map to allow plugins to hook specific named phased commands (defined in command-line.json) before execution. + */ + public readonly runPhasedCommand: HookMap> = new HookMap((key: string) => { + return new AsyncSeriesHook(['command'], key); + }, 'runPhasedCommand'); + + /** + * 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] + > = new AsyncSeriesHook(['command', 'subspace', 'variant'], 'beforeInstall'); + + /** + * The hook to run after a successful install. + */ + public readonly afterInstall: AsyncSeriesHook< + [command: IRushCommand, subspace: Subspace, variant: string | undefined] + > = new AsyncSeriesHook(['command', 'subspace', 'variant'], 'afterInstall'); + + /** + * A hook to allow plugins to hook custom logic to process telemetry data. + */ + public readonly flushTelemetry: AsyncParallelHook<[ReadonlyArray]> = new AsyncParallelHook( + ['telemetryData'], + 'flushTelemetry' + ); +} diff --git a/libraries/rush-lib/src/pluginFramework/RushSession.ts b/libraries/rush-lib/src/pluginFramework/RushSession.ts new file mode 100644 index 00000000000..0e512764438 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/RushSession.ts @@ -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. + +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'; +import type { ICobuildLockProvider } from '../logic/cobuild/ICobuildLockProvider'; + +/** + * @beta + */ +export interface IRushSessionOptions { + terminalProvider: ITerminalProvider; + getIsDebugMode: () => boolean; +} + +/** + * @beta + */ +export type CloudBuildCacheProviderFactory = ( + buildCacheJson: IBuildCacheJson +) => ICloudBuildCacheProvider | Promise; + +/** + * @beta + */ +export type CobuildLockProviderFactory = ( + cobuildJson: ICobuildJson +) => ICobuildLockProvider | Promise; + +/** + * @beta + */ +export class RushSession { + private readonly _options: IRushSessionOptions; + private readonly _cloudBuildCacheProviderFactories: Map = new Map(); + private readonly _cobuildLockProviderFactories: Map = new Map(); + + public readonly hooks: RushLifecycleHooks; + + public constructor(options: IRushSessionOptions) { + this._options = options; + + this.hooks = new RushLifecycleHooks(); + } + + public getLogger(name: string): ILogger { + if (!name) { + throw new InternalError('RushSession.getLogger(name) called without a name'); + } + + const terminalProvider: ITerminalProvider = this._options.terminalProvider; + const loggerOptions: ILoggerOptions = { + loggerName: name, + getShouldPrintStacks: () => this._options.getIsDebugMode(), + terminalProvider + }; + return new Logger(loggerOptions); + } + + public get terminalProvider(): ITerminalProvider { + return this._options.terminalProvider; + } + + public registerCloudBuildCacheProviderFactory( + cacheProviderName: string, + factory: CloudBuildCacheProviderFactory + ): void { + if (this._cloudBuildCacheProviderFactories.has(cacheProviderName)) { + throw new Error(`A build cache provider factory for ${cacheProviderName} has already been registered`); + } + + this._cloudBuildCacheProviderFactories.set(cacheProviderName, factory); + } + + public getCloudBuildCacheProviderFactory( + cacheProviderName: string + ): CloudBuildCacheProviderFactory | undefined { + return this._cloudBuildCacheProviderFactories.get(cacheProviderName); + } + + public registerCobuildLockProviderFactory( + cobuildLockProviderName: string, + factory: CobuildLockProviderFactory + ): void { + if (this._cobuildLockProviderFactories.has(cobuildLockProviderName)) { + throw new Error( + `A cobuild lock provider factory for ${cobuildLockProviderName} has already been registered` + ); + } + this._cobuildLockProviderFactories.set(cobuildLockProviderName, factory); + } + + public getCobuildLockProviderFactory( + cobuildLockProviderName: string + ): CobuildLockProviderFactory | undefined { + return this._cobuildLockProviderFactories.get(cobuildLockProviderName); + } +} diff --git a/libraries/rush-lib/src/pluginFramework/logging/Logger.ts b/libraries/rush-lib/src/pluginFramework/logging/Logger.ts new file mode 100644 index 00000000000..46b01be524f --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/logging/Logger.ts @@ -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 { type ITerminalProvider, Terminal } from '@rushstack/terminal'; + +/** + * @beta + */ +export interface ILogger { + readonly terminal: Terminal; + + /** + * Call this function to emit an error to the Rush runtime. + */ + emitError(error: Error): void; + + /** + * Call this function to emit a warning to the Rush runtime. + */ + emitWarning(warning: Error): void; +} + +export interface ILoggerOptions { + loggerName: string; + terminalProvider: ITerminalProvider; + getShouldPrintStacks: () => boolean; +} + +export class Logger implements ILogger { + private readonly _options: ILoggerOptions; + private readonly _errors: Error[] = []; + private readonly _warnings: Error[] = []; + + public readonly terminal: Terminal; + + public constructor(options: ILoggerOptions) { + this._options = options; + this.terminal = new Terminal(options.terminalProvider); + } + + public get errors(): ReadonlyArray { + return [...this.errors]; + } + + public get warnings(): ReadonlyArray { + return [...this.warnings]; + } + + public static getErrorMessage(error: Error): string { + return error.message; + } + + /** + * {@inheritdoc ILogger.emitError} + */ + public emitError(error: Error): void { + this._errors.push(error); + this.terminal.writeErrorLine(`Error: ${Logger.getErrorMessage(error)}`); + if (this._shouldPrintStacks && error.stack) { + this.terminal.writeErrorLine(error.stack); + } + } + + /** + * {@inheritdoc ILogger.emitWarning} + */ + public emitWarning(warning: Error): void { + this._warnings.push(warning); + this.terminal.writeWarningLine(`Warning: ${Logger.getErrorMessage(warning)}`); + if (this._shouldPrintStacks && warning.stack) { + this.terminal.writeWarningLine(warning.stack); + } + } + + private get _shouldPrintStacks(): boolean { + return this._options.getShouldPrintStacks(); + } +} diff --git a/libraries/rush-lib/src/schemas/anything.schema.json b/libraries/rush-lib/src/schemas/anything.schema.json new file mode 100644 index 00000000000..15e4861463a --- /dev/null +++ b/libraries/rush-lib/src/schemas/anything.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Schema that matches anything", + + "oneOf": [ + { + "type": "array" + }, + { + "type": "boolean" + }, + { + "type": "integer" + }, + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "object" + }, + { + "type": "string" + } + ] +} diff --git a/apps/rush-lib/src/schemas/approved-packages.schema.json b/libraries/rush-lib/src/schemas/approved-packages.schema.json similarity index 96% rename from apps/rush-lib/src/schemas/approved-packages.schema.json rename to libraries/rush-lib/src/schemas/approved-packages.schema.json index f84a810e80d..0bced3cfed0 100644 --- a/apps/rush-lib/src/schemas/approved-packages.schema.json +++ b/libraries/rush-lib/src/schemas/approved-packages.schema.json @@ -20,7 +20,7 @@ } }, "additionalProperties": false, - "required": [ "name" ] + "required": ["name"] } }, "type": "object", @@ -36,5 +36,5 @@ } }, "additionalProperties": false, - "required": [ "packages" ] + "required": ["packages"] } diff --git a/libraries/rush-lib/src/schemas/artifactory.schema.json b/libraries/rush-lib/src/schemas/artifactory.schema.json new file mode 100644 index 00000000000..5f2d1dd4c18 --- /dev/null +++ b/libraries/rush-lib/src/schemas/artifactory.schema.json @@ -0,0 +1,85 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush artifactory.json config file", + "description": "For use with the Rush tool, this configuration file manages Rush integration with JFrog Artifactory services. See http://rushjs.io for details.", + + "type": "object", + "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" + }, + + "packageRegistry": { + "type": "object", + "properties": { + "enabled": { + "description": "Set this to \"true\" to enable Rush to manage tokens for an Artifactory NPM registry. When enabled, \"rush install\" will automatically detect when the user's ~/.npmrc authentication token is missing or expired. And \"rush setup\" will prompt the user to renew their token. The default value is false.", + "type": "boolean" + }, + "registryUrl": { + "description": "Specify the URL of your NPM registry. This is the same URL that appears in your .npmrc file. It should look something like this example: https://your-company.jfrog.io/your-project/api/npm/npm-private/", + "type": "string" + }, + "userNpmrcLinesToAdd": { + "description": "A list of custom strings that \"rush setup\" should add to the user's ~/.npmrc file at the time when the token is updated. This could be used for example to configure the company registry to be used whenever NPM is invoked as a standalone command (but it's not needed for Rush operations like \"rush add\" and \"rush install\", which get their mappings from the monorepo's common/config/rush/.npmrc file).\n\nNOTE: The ~/.npmrc settings are global for the user account on a given machine, so be careful about adding settings that may interfere with other work outside the monorepo.", + "type": "array", + "items": { + "type": "string" + } + }, + "artifactoryWebsiteUrl": { + "description": "Specifies the URL of the Artifactory control panel where the user can generate an API key. This URL is printed after the \"visitWebsite\" message. It should look something like this example: https://your-company.jfrog.io/ Specify an empty string to suppress this line entirely.", + "type": "string" + }, + "credentialType": { + "description": "Specifies the type of credential to save in the user's ~/.npmrc file. The default is \"password\", which means the user's entered API token will be passed to the Artifactory website URL specified and traded in for an npm registry password, which is saved. Specify \"authToken\" to save the authToken directly into the ~/.npmrc file and use that for credentials instead.", + "type": "string", + "enum": ["password", "authToken"] + }, + + "messageOverrides": { + "description": "These settings allow the \"rush setup\" interactive prompts to be customized, for example with messages specific to your team or configuration. Specify an empty string to suppress that message entirely.", + "type": "object", + + "properties": { + "introduction": { + "description": "Overrides the message that normally says: \"This monorepo consumes packages from an Artifactory private NPM registry.\"", + "type": "string" + }, + "obtainAnAccount": { + "description": "Overrides the message that normally says: \"Please contact the repository maintainers for help with setting up an Artifactory user account.\"", + "type": "string" + }, + "visitWebsite": { + "description": "Overrides the message that normally says: \"Please open this URL in your web browser:\" The \"artifactoryWebsiteUrl\" string is printed after this message.", + "type": "string" + }, + "locateUserName": { + "description": "Overrides the message that normally says: \"Your user name appears in the upper-right corner of the JFrog website.\"", + "type": "string" + }, + "locateApiKey": { + "description": "Overrides the message that normally says: \"Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key' button if you haven't already done so previously.\"", + "type": "string" + }, + "userNamePrompt": { + "description": "Overrides the message that normally prompts: \"What is your Artifactory user name?\"", + "type": "string" + }, + "apiKeyPrompt": { + "description": "Overrides the message that normally prompts: \"What is your Artifactory API key?\"", + "type": "string" + } + }, + + "additionalProperties": false + } + }, + + "required": ["enabled", "registryUrl", "artifactoryWebsiteUrl"], + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/build-cache.schema.json b/libraries/rush-lib/src/schemas/build-cache.schema.json new file mode 100644 index 00000000000..2c7e8fd6967 --- /dev/null +++ b/libraries/rush-lib/src/schemas/build-cache.schema.json @@ -0,0 +1,324 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Configuration for Rush's build cache.", + "description": "For use with the Rush tool, this file provides configuration options for cached project build output. See http://rushjs.io for details.", + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "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", + "allOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["buildCacheEnabled", "cacheProvider"], + "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" + }, + "buildCacheEnabled": { + "description": "Set this to true to enable the build cache feature.", + "type": "boolean" + }, + "cacheProvider": { + "description": "Specify the cache provider to use", + "type": "string" + }, + "cacheEntryNamePattern": { + "type": "string", + "description": "Setting this property overrides the cache entry ID. If this property is set, it must contain a [hash] token. It may also contain one of the following tokens: [projectName], [projectName:normalize], [phaseName], [phaseName:normalize], [phaseName:trimPrefix], [os], and [arch]." + }, + "cacheHashSalt": { + "type": "string", + "description": "An 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." + }, + "azureBlobStorageConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "storageAccountName": { + "type": "string", + "description": "(Required) The name of the the Azure storage account to use for build cache." + }, + "storageContainerName": { + "type": "string", + "description": "(Required) The name of the container in the Azure storage account to use for build cache." + }, + "azureEnvironment": { + "type": "string", + "description": "The Azure environment the storage account exists in. Defaults to AzurePublicCloud.", + "enum": ["AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment"] + }, + "loginFlow": { + "$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", + "description": "An optional prefix for cache item blob names." + }, + "isCacheWriteAllowed": { + "type": "boolean", + "description": "If set to true, allow writing to the cache. Defaults to false." + }, + "readRequiresAuthentication": { + "type": "boolean", + "description": "If set to true, reading the cache requires authentication. Defaults to false." + } + } + }, + "amazonS3Configuration": { + "type": "object", + "additionalProperties": false, + "properties": { + "s3Bucket": { + "type": "string", + "description": "(Required unless s3Endpoint is specified) The name of the bucket to use for build cache (e.g. \"my-bucket\")." + }, + "s3Endpoint": { + "type": "string", + "description": "(Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache (e.g. \"my-bucket.s3.us-east-2.amazonaws.com\" or \"http://localhost:9000\").\nThis shold not include any path, use the s3Prefix to set the path." + }, + "s3Region": { + "type": "string", + "description": "(Required) The Amazon S3 region of the bucket to use for build cache (e.g. \"us-east-1\")." + }, + "s3Prefix": { + "type": "string", + "description": "An optional prefix (\"folder\") for cache items. Should not start with /" + }, + "isCacheWriteAllowed": { + "type": "boolean", + "description": "If set to true, allow writing to the cache. Defaults to false." + } + } + }, + "httpConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "description": "(Required) The URL of the server that stores the caches (e.g. \"https://build-caches.example.com\").", + "format": "uri" + }, + "uploadMethod": { + "type": "string", + "description": "(Optional) The HTTP method to use when writing to the cache (defaults to PUT).", + "enum": ["PUT", "POST", "PATCH"], + "default": "PUT" + }, + "headers": { + "type": "object", + "description": "(Optional) HTTP headers to pass to the cache server", + "properties": {}, + "additionalProperties": { + "type": "string" + } + }, + "tokenHandler": { + "type": "object", + "description": "(Optional) Shell command that prints the authorization token needed to communicate with the HTTPS server and exits with code 0. This command will be executed from the root of the monorepo.", + "properties": { + "exec": { + "type": "string", + "description": "(Required) The command or script to execute." + }, + "args": { + "type": "array", + "description": "(Optional) Arguments to pass to the command or script.", + "items": { + "type": "string" + } + } + } + }, + "cacheKeyPrefix": { + "type": "string", + "description": "(Optional) prefix for cache keys." + }, + "isCacheWriteAllowed": { + "type": "boolean", + "description": "(Optional) If set to true, allow writing to the cache. Defaults to false." + } + } + } + }, + "oneOf": [ + { + "type": "object", + "additionalProperties": true, + "properties": { + "cacheProvider": { + "type": "string", + "pattern": "^(?:(?!local-only|azure-blob-storage|amazon-s3|http).)*$" + } + } + }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "cacheProvider": { + "type": "string", + "enum": ["local-only"] + } + } + }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "cacheProvider": { + "type": "string", + "enum": ["azure-blob-storage"] + }, + "azureBlobStorageConfiguration": { + "type": "object", + "additionalProperties": true, + "required": ["storageAccountName", "storageContainerName"], + "properties": { + "storageAccountName": { + "$ref": "#/definitions/anything" + }, + "storageContainerName": { + "$ref": "#/definitions/anything" + } + } + } + } + }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "cacheProvider": { + "type": "string", + "enum": ["amazon-s3"] + }, + "amazonS3Configuration": { + "type": "object", + "additionalProperties": true, + "oneOf": [ + { + "type": "object", + "required": ["s3Region", "s3Endpoint"], + "properties": { + "s3Endpoint": { + "$ref": "#/definitions/anything" + }, + "s3Region": { + "$ref": "#/definitions/anything" + } + } + }, + { + "type": "object", + "required": ["s3Region", "s3Bucket"], + "properties": { + "s3Bucket": { + "$ref": "#/definitions/anything" + }, + "s3Region": { + "$ref": "#/definitions/anything" + } + } + } + ] + } + } + }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "cacheProvider": { + "type": "string", + "enum": ["http"] + }, + "httpConfiguration": { + "type": "object", + "additionalProperties": true, + "required": ["url"], + "properties": { + "url": { + "$ref": "#/definitions/anything" + } + } + } + } + } + ] + } + ] +} diff --git a/libraries/rush-lib/src/schemas/change-file.schema.json b/libraries/rush-lib/src/schemas/change-file.schema.json new file mode 100644 index 00000000000..cef43ce783b --- /dev/null +++ b/libraries/rush-lib/src/schemas/change-file.schema.json @@ -0,0 +1,54 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Generated Rush changefiles", + "description": "For use with the Rush tool, this file tracks changes that are made to individual packages within the Rush repo. See http://rushjs.io for details.", + + "type": "object", + "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" + }, + "changes": { + "description": "A list of changes that apply to the specified package. These changes will cause the specified package and all dependent packages ", + "type": "array", + "items": { + "type": "object", + "required": ["packageName", "comment", "type"], + "properties": { + "packageName": { + "type": "string", + "description": "The name of the package that the change applies to." + }, + "comment": { + "type": "string", + "description": "A comment that describes the change being made." + }, + "type": { + "type": "string", + "description": "The change type associated with the change.", + "enum": ["none", "dependency", "hotfix", "patch", "minor", "major"] + }, + "customFields": { + "type": "object", + "description": "An optional dictionary of custom string fields.", + "patternProperties": { + "^.*$": { + "type": "string" + } + } + } + } + } + }, + "packageName": { + "description": "The name of the package that the change file applies to.", + "type": "string" + }, + "email": { + "description": "The email address for the author of the change.", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/changelog.schema.json b/libraries/rush-lib/src/schemas/changelog.schema.json new file mode 100644 index 00000000000..16057312abe --- /dev/null +++ b/libraries/rush-lib/src/schemas/changelog.schema.json @@ -0,0 +1,134 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Changelog file for packages in rush which should be published", + "description": "This file represents a JSON format of changelog of a package", + "additionalProperties": false, + "properties": { + "entries": { + "description": "Entries within the changelog corresponding to each published version.", + "items": { + "$ref": "#/definitions/IChangeLogEntry" + }, + "type": "array" + }, + "name": { + "description": "Name of the project", + "type": "string" + } + }, + "required": [ + "name", + "entries" + ], + "type": "object", + "definitions": { + "IChangeLogComment": { + "additionalProperties": false, + "description": "Interface representing a single changelog comment within an entry.", + "properties": { + "author": { + "description": "The author, if applicable, that created the change request.", + "type": "string" + }, + "comment": { + "description": "The given comment. (supports markdown.)", + "type": "string" + }, + "commit": { + "description": "The commit, if applicable, including the change request.", + "type": "string" + }, + "customFields": { + "type": "object", + "description": "An optional dictionary of custom string fields.", + "patternProperties": { + "^.*$": { + "type": "string" + } + } + } + }, + "required": [ + "comment" + ], + "type": "object" + }, + "IChangeLogEntry": { + "additionalProperties": false, + "description": "Interface representing a single published entry in the changelog.", + "properties": { + "comments": { + "$ref": "#/definitions/IChangeLogEntryComments", + "description": "Comments for the entry, where key represents the ChangeType string (Example: major)" + }, + "date": { + "description": "The UTC date when the publish was applied. (Example: Fri, 02 Dec 2016 22:27:16 GMT)", + "type": "string" + }, + "tag": { + "description": "Git tag used to identify the published commit. (Example: b7f55611e54910327a206476b185265498c66acf)", + "type": "string" + }, + "version": { + "description": "Published version for the entry. (Example: 1.0.0)", + "type": "string" + } + }, + "required": [ + "version", + "tag", + "comments" + ], + "type": "object" + }, + "IChangeLogEntryComments": { + "additionalProperties": false, + "description": "Interface representing a single published entry in the changelog.", + "properties": { + "dependency": { + "description": "Describes changes to the package's dependencies", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + }, + "hotfix": { + "description": "Describe changes that do not have version information", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + }, + "major": { + "description": "Describes changes which cause a major-level SemVer bump", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + }, + "minor": { + "description": "Describes changes which cause a minor-level SemVer bump", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + }, + "none": { + "description": "Describe changes that do not have version information", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + }, + "patch": { + "description": "Describes changes which cause a patch-level SemVer bump", + "items": { + "$ref": "#/definitions/IChangeLogComment" + }, + "type": "array" + } + }, + "type": "object" + } + } +} diff --git a/libraries/rush-lib/src/schemas/cobuild.schema.json b/libraries/rush-lib/src/schemas/cobuild.schema.json new file mode 100644 index 00000000000..6fe630b89d8 --- /dev/null +++ b/libraries/rush-lib/src/schemas/cobuild.schema.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Configuration for Rush's cobuild.", + "description": "For use with the Rush tool, this file provides configuration options for cobuild feature. See http://rushjs.io for details.", + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { + "$ref": "#/definitions/anything" + } + } + }, + "type": "object", + "allOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["cobuildFeatureEnabled", "cobuildLockProvider"], + "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" + }, + "cobuildFeatureEnabled": { + "description": "Set this to true to enable the cobuild feature.", + "type": "boolean" + }, + "cobuildLockProvider": { + "description": "Specify the cobuild lock provider to use", + "type": "string" + } + } + } + ] +} diff --git a/libraries/rush-lib/src/schemas/command-line.schema.json b/libraries/rush-lib/src/schemas/command-line.schema.json new file mode 100644 index 00000000000..0091e7bb7ae --- /dev/null +++ b/libraries/rush-lib/src/schemas/command-line.schema.json @@ -0,0 +1,747 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush command-line.json config file", + "description": "For use with the Rush tool, this file defines custom command line commands. See http://rushjs.io for details.", + + "definitions": { + "anything": { + "type": ["array", "boolean", "integer", "number", "object", "string"], + "items": { "$ref": "#/definitions/anything" } + }, + + "baseCommand": { + "type": "object", + "additionalProperties": true, + "required": ["commandKind", "name", "summary"], + "properties": { + "commandKind": { + "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"] + }, + "name": { + "title": "Custom Command Name", + "description": "The name of the custom command, which can be invoked via \"rush \"", + "type": "string" + }, + "summary": { + "title": "Custom Command Summary", + "description": "A short summary of the custom command, which will appear when printing command line usage (e.g. \"rush --help\")", + "type": "string" + }, + "description": { + "title": "Custom Command Description", + "description": "A detailed description of the command, which appears when requesting help for the command (e.g. \"rush --help my-command\"). If omitted, the summary will be used.", + "type": "string" + }, + "safeForSimultaneousRushProcesses": { + "title": "Safe For Simultaneous Rush Processes", + "description": "By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously in the same repo folder. (For example, it would be a mistake to run \"rush install\" and \"rush build\" at the same time.) If your command makes sense to run concurrently with other operations, set safeForSimultaneousRushProcesses=true to disable this protection. In particular, this is needed for custom scripts that invoke other Rush commands.", + "type": "boolean" + } + } + }, + "bulkCommand": { + "title": "Bulk Command", + "description": "A custom command that is run separately for each project in the repository", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseCommand" }, + { + "type": "object", + "additionalProperties": true, + "required": ["enableParallelism"], + "properties": { + "commandKind": { + "enum": ["bulk"] + }, + "shellCommand": { + "title": "Shell Command", + "description": "(Optional) If the \"shellCommand\" field is set for a bulk command, Rush will invoke it for each selected project; otherwise, Rush will invoke the package.json \"scripts\" entry matching Rush command name.\n\nThe string is the path to a script that will be invoked using the OS shell. The working directory will be the folder that contains rush.json. If custom parameters are associated with this command, their values will be appended to the end of this string.", + "type": "string" + }, + "enableParallelism": { + "title": "enableParallelism", + "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.", + "type": "boolean" + }, + "ignoreMissingScript": { + "title": "Ignore Missing Script", + "description": "Normally Rush requires that each project's package.json has a \"scripts\" entry matching the custom command name. To disable this check, set \"ignoreMissingScript\" to true.", + "type": "boolean" + }, + "incremental": { + "title": "Incremental", + "description": "If true then this command will be incremental like the built-in \"build\" and \"rebuild\" commands", + "type": "boolean" + }, + "allowWarningsInSuccessfulBuild": { + "title": "Allow Warnings in Successful Build", + "description": "By default, Rush returns a nonzero exit code if errors or warnings occur during build. If this option is set to \"true\", Rush will return a zero exit code if warnings occur.", + "type": "boolean" + }, + "watchForChanges": { + "title": "Watch For Changes", + "description": "(EXPERIMENTAL) Normally Rush terminates after the command finishes. If this option is set to \"true\" Rush will instead enter a loop where it watches the file system for changes to the selected projects. Whenever a change is detected, the command will be invoked again for the changed project and any selected projects that directly or indirectly depend on it. For details, refer to the website article \"Using watch mode\".", + "type": "boolean" + }, + "disableBuildCache": { + "title": "Disable build cache.", + "description": "Disable build cache for this action. This may be useful if this command affects state outside of projects' own folders. If the build cache is not configured, this also disables the legacy skip detection logic.", + "type": "boolean" + } + } + }, + { + "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" }, + "shellCommand": { "$ref": "#/definitions/anything" }, + + "enableParallelism": { "$ref": "#/definitions/anything" }, + "allowOversubscription": { "$ref": "#/definitions/anything" }, + "ignoreDependencyOrder": { "$ref": "#/definitions/anything" }, + "ignoreMissingScript": { "$ref": "#/definitions/anything" }, + "incremental": { "$ref": "#/definitions/anything" }, + "allowWarningsInSuccessfulBuild": { "$ref": "#/definitions/anything" }, + "watchForChanges": { "$ref": "#/definitions/anything" }, + "disableBuildCache": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "globalCommand": { + "title": "Global Command", + "description": "A custom command that is run once for the entire repository", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseCommand" }, + { + "type": "object", + "additionalProperties": true, + "required": ["shellCommand"], + "properties": { + "commandKind": { + "enum": ["global"] + }, + "shellCommand": { + "title": "Shell Command", + "description": "A command that that will be invoked using the OS shell. The working directory will be the folder that contains rush.json. Additional command-line parameters may be appended to the end of this string.", + "type": "string" + }, + "autoinstallerName": { + "title": "Autoinstaller Name", + "description": "If your \"shellCommand\" script depends on NPM packages, the recommended best practice is to make it into a regular Rush project that builds using your normal toolchain. In cases where the command needs to work without first having to run \"rush build\", the recommended practice is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it.\n\nAutoinstallers offer another possibility: They are folders under \"common/autoinstallers\" with a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to install these dependencies before an associated command is invoked. Autoinstallers have the advantage that they work even in a branch where \"rush install\" is broken, which makes them a good solution for Git hook scripts. But they have the disadvantages of not being buildable projects, and of increasing the overall installation footprint for your monorepo.\n\nThe \"autoinstallerName\" setting must not contain a path and must be a valid NPM package name.\n\nFor example, the name \"my-task\" would map to \"common/autoinstallers/my-task/package.json\", and the \"common/autoinstallers/my-task/node_modules/.bin\" folder would be added to the shell PATH when invoking the \"shellCommand\".", + "type": "string" + } + } + }, + { + "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" }, + + "shellCommand": { "$ref": "#/definitions/anything" }, + "autoinstallerName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "phasedCommand": { + "title": "Phased Command", + "description": "A command that contains multiple phases, that are run separately for each project", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseCommand" }, + { + "type": "object", + "additionalProperties": true, + "required": ["enableParallelism", "phases"], + "properties": { + "commandKind": { + "enum": ["phased"] + }, + "enableParallelism": { + "title": "enableParallelism", + "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.", + "type": "boolean" + }, + "phases": { + "title": "Phases", + "description": "List the phases associated with this command. Note that phases with dependencies will be implicitly included even if they aren't explicitly enumerated in this property.", + "type": "array", + "items": { + "type": "string" + } + }, + "disableBuildCache": { + "title": "Disable build cache.", + "description": "Disable build cache for this action. This may be useful if this command affects state outside of projects' own folders. If the build cache is not configured, this also disables the legacy skip detection logic.", + "type": "boolean" + }, + "watchOptions": { + "title": "Watch Options", + "description": "Controls the file watching behavior of this command. If not specified, this command does not watch files.", + "type": "object", + "additionalProperties": false, + "required": ["alwaysWatch", "watchPhases"], + "properties": { + "alwaysWatch": { + "title": "Always Watch", + "description": "Indicates that this command will always watch for changes after the initial execution, as if the \"--watch\" CLI flag was passed.", + "type": "boolean" + }, + "debounceMs": { + "title": "Debounce Timeout in Milliseconds", + "description": "When watching, how long to wait after the last encountered file system event before execution. If another file system event occurs in this interval, the timeout will reset. Defaults to 1000ms (1 second).", + "type": "number" + }, + "watchPhases": { + "title": "Watch Phases", + "description": "List *exactly* the phases that should be run in watch mode for this command. If this property is specified and non-empty, after the phases defined in the \"phases\" property run, a file watcher will be started to watch projects for changes, and will run the phases listed in this property on changed projects. Rush will prefer scripts named \"${phaseName}:incremental\" over \"${phaseName}\" for every iteration after the first, so you can reuse the same phase name but define different scripts, e.g. to not clean on incremental runs.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "installOptions": { + "title": "Install Options", + "description": "Controls behavior related to performing installation as part of executing this command.", + "type": "object", + "additionalProperties": false, + "required": ["alwaysInstall"], + "properties": { + "alwaysInstall": { + "title": "Always Install", + "description": "Indicates that this command will always perform a standard \"rush install\" before executing, as if the \"--install\" CLI flag was passed.", + "type": "boolean" + } + } + } + } + }, + { + "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" }, + + "enableParallelism": { "$ref": "#/definitions/anything" }, + "allowOversubscription": { "$ref": "#/definitions/anything" }, + "incremental": { "$ref": "#/definitions/anything" }, + "phases": { "$ref": "#/definitions/anything" }, + "watchOptions": { "$ref": "#/definitions/anything" }, + "installOptions": { "$ref": "#/definitions/anything" } + } + } + ] + }, + + "phase": { + "title": "Phase", + "description": "A phase, used in the phased command feature.", + "type": "object", + "additionalProperties": false, + "required": ["name"], + "properties": { + "name": { + "title": "Name", + "description": "The name of the phase. Note that this value must start with the \"_phase:\" prefix.", + "type": "string" + }, + + "dependencies": { + "title": "Dependencies", + "description": "The dependencies of this phase.", + "type": "object", + "additionalProperties": false, + "properties": { + "self": { + "title": "Self", + "description": "Dependency phases within the same project.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "upstream": { + "title": "Upstream", + "description": "Dependency phases in upstream projects.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + } + } + }, + + "ignoreMissingScript": { + "title": "Ignore Missing Script", + "description": "Normally Rush requires that each project's package.json has a \"scripts\" entry matching the phase name. To disable this check, set \"ignoreMissingScript\" to true.", + "type": "boolean" + }, + + "allowWarningsOnSuccess": { + "title": "Allow Warnings on Success", + "description": "By default, Rush returns a nonzero exit code if errors or warnings occur during a command. If this option is set to \"true\", Rush will return a zero exit code if warnings occur during the execution of this phase.", + "type": "boolean" + }, + + "missingScriptBehavior": { + "title": "Missing Script Behavior", + "description": "What should happen if a project's package.json does not have a \"scripts\" entry matching the phase name, or it is an empty string. Supersedes \"ignoreMissingScript\". Defaults to \"error\".", + "type": "string", + "enum": ["silent", "log", "error"] + } + } + }, + + "baseParameter": { + "type": "object", + "additionalProperties": true, + "required": ["parameterKind", "longName", "description"], + "properties": { + "parameterKind": { + "title": "Parameter Kind", + "description": "Indicates the kind of syntax for this command-line parameter: \"flag\" or \"choice\" or \"string\"", + "type": "string", + "enum": ["flag", "choice", "string", "integer", "stringList", "integerList", "choiceList"] + }, + "longName": { + "title": "Long Name", + "description": "The name of the parameter (e.g. \"--verbose\"). This is a required field.", + "type": "string", + "pattern": "^-(-[a-z0-9]+)+$" + }, + "shortName": { + "title": "Short Name", + "description": "A optional short form of the parameter (e.g. \"-v\" instead of \"--verbose\")", + "type": "string", + "pattern": "^-[a-zA-Z]$" + }, + "description": { + "title": "Custom Parameter Description", + "description": "A detailed description of the parameter, which appears when requesting help for the command (e.g. \"rush --help my-command\").", + "type": "string" + }, + "associatedCommands": { + "title": "Associated Commands", + "description": "A list of custom commands and/or built-in Rush commands that this parameter may be used with", + "type": "array", + "items": { + "type": "string" + } + }, + "associatedPhases": { + "title": "Associated Phases", + "description": "A list of the names of the phases that this command-line parameter should be provided to.", + "type": "array", + "items": { + "type": "string" + } + }, + "required": { + "title": "Required", + "description": "If true, then this parameter must be included on the command line", + "type": "boolean" + } + } + }, + "flagParameter": { + "title": "Flag Parameter", + "description": "A custom command-line parameter whose presence acts as an on/off switch", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "parameterKind": { + "enum": ["flag"] + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "stringParameter": { + "title": "String Parameter", + "description": "A custom command-line parameter whose value is interpreted as a string", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["string"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "choiceParameter": { + "title": "Choice Parameter", + "description": "A custom command-line parameter whose argument must be chosen from a list of allowable alternatives", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choice"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" + } + } + } + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "alternatives": { "$ref": "#/definitions/anything" }, + "defaultValue": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "integerParameter": { + "title": "Integer Parameter", + "description": "A custom command-line parameter whose value is interpreted as a integer", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integer"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "stringListParameter": { + "title": "String List Parameter", + "description": "A custom command-line parameter whose value is interpreted as a list of string", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["stringList"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "integerListParameter": { + "title": "Integer List Parameter", + "description": "A custom command-line parameter whose value is interpreted as a list of integer", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["argumentName"], + "properties": { + "parameterKind": { + "enum": ["integerList"] + }, + "argumentName": { + "title": "Argument Name", + "description": "The name of the argument for this parameter.", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "argumentName": { "$ref": "#/definitions/anything" } + } + } + ] + }, + "choiceListParameter": { + "title": "Choice List Parameter", + "description": "A custom command-line parameter whose argument must be chosen from a list of allowable alternatives, value is interpreted as a list of choice", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseParameter" }, + { + "type": "object", + "additionalProperties": true, + "required": ["alternatives"], + "properties": { + "parameterKind": { + "enum": ["choiceList"] + }, + "alternatives": { + "title": "Alternatives", + "description": "A list of alternative argument values that can be chosen for this parameter.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "description"], + "properties": { + "name": { + "title": "Name of Alternative", + "description": "A token that is one of the alternatives that can be used with the choice parameter, e.g. \"vanilla\" in \"--flavor vanilla\"", + "type": "string" + }, + "description": { + "title": "Description of Alternative", + "description": "A detailed description for the alternative that will be shown in the command-line help.", + "type": "string" + } + } + } + }, + "defaultValue": { + "title": "Default Value", + "description": "If the parameter is omitted from the command line, this value will be inserted by default", + "type": "string" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "parameterKind": { "$ref": "#/definitions/anything" }, + "longName": { "$ref": "#/definitions/anything" }, + "shortName": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "associatedCommands": { "$ref": "#/definitions/anything" }, + "associatedPhases": { "$ref": "#/definitions/anything" }, + "required": { "$ref": "#/definitions/anything" }, + + "alternatives": { "$ref": "#/definitions/anything" }, + "defaultValue": { "$ref": "#/definitions/anything" } + } + } + ] + } + }, + + "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" + }, + + "commands": { + "title": "Custom Commands", + "description": "A list of custom commands that affect all projects in the repository. These commands are invoked from the Rush command line.", + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { "$ref": "#/definitions/bulkCommand" }, + { "$ref": "#/definitions/globalCommand" }, + { "$ref": "#/definitions/phasedCommand" } + ] + } + }, + + "phases": { + "title": "Phases", + "description": "A list of phases that are associated with phased commands.", + "type": "array", + "items": { + "$ref": "#/definitions/phase" + } + }, + + "parameters": { + "title": "Custom Parameters", + "description": "A list of custom command-line parameters that can be associated with custom commands and Rush's built-in commands.", + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { "$ref": "#/definitions/flagParameter" }, + { "$ref": "#/definitions/choiceParameter" }, + { "$ref": "#/definitions/stringParameter" }, + { "$ref": "#/definitions/integerParameter" }, + { "$ref": "#/definitions/stringListParameter" }, + { "$ref": "#/definitions/integerListParameter" }, + { "$ref": "#/definitions/choiceListParameter" } + ] + } + } + } +} diff --git a/apps/rush-lib/src/schemas/common-versions.schema.json b/libraries/rush-lib/src/schemas/common-versions.schema.json similarity index 91% rename from apps/rush-lib/src/schemas/common-versions.schema.json rename to libraries/rush-lib/src/schemas/common-versions.schema.json index 19dc60cbc33..35e3de17634 100644 --- a/apps/rush-lib/src/schemas/common-versions.schema.json +++ b/libraries/rush-lib/src/schemas/common-versions.schema.json @@ -2,7 +2,6 @@ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Rush common-versions.json config file", "description": "For use with the Rush tool, this file manages dependency versions that affect all projects in the repo. See http://rushjs.io for details.", - "type": "object", "properties": { "$schema": { @@ -20,12 +19,9 @@ "description": "When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, except in cases where different projects specify different version ranges for a given dependency. For older package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause trouble for indirect dependencies with incompatible peerDependencies ranges.", "type": "boolean" }, - "xstitchPreferredVersions": { - "description": "A table of specifies preferred versions maintained by the XStitch tool. See the Rush documentation for details.", - "type": "object", - "additionalProperties": { - "type": "string" - } + "ensureConsistentVersions": { + "description": "If true, consistent version specifiers for dependencies will be enforced (i.e. \"rush check\" is run before some commands).", + "type": "boolean" }, "allowedAlternativeVersions": { "description": "The \"rush check\" command can be used to enforce that every project in the repo must specify the same SemVer range for a given dependency. However, sometimes exceptions are needed. The allowedAlternativeVersions table allows you to list other SemVer ranges that will be accepted by \"rush check\" for a given dependency. Note that the normal version range (as inferred by looking at all projects in the repo) should NOT be included in this list.", diff --git a/libraries/rush-lib/src/schemas/custom-tips.schema.json b/libraries/rush-lib/src/schemas/custom-tips.schema.json new file mode 100644 index 00000000000..faa274fe091 --- /dev/null +++ b/libraries/rush-lib/src/schemas/custom-tips.schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush custom-tips.json config file", + "description": "The config file for adding tips to specific messages.", + + "type": "object", + "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" + }, + + "customTips": { + "type": "array", + "items": { + "type": "object", + "required": ["tipId", "message"], + "additionalProperties": false, + "properties": { + "tipId": { + "type": "string", + "description": "An identifier indicating a message that may be printed by Rush. If that message is printed, then this custom tip will be shown. Consult the Rush documentation for the current list of possible identifiers.", + "pattern": "^[A-Z0-9_]+$" + }, + "message": { + "type": "string", + "description": "The message text to be displayed for this tip." + } + } + } + } + }, + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/deploy-scenario.schema.json b/libraries/rush-lib/src/schemas/deploy-scenario.schema.json new file mode 100644 index 00000000000..89bd1e88e01 --- /dev/null +++ b/libraries/rush-lib/src/schemas/deploy-scenario.schema.json @@ -0,0 +1,135 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush config file that defines a deployment scenario", + "description": "This configuration file defines a deployment scenario for use with the \"rush deploy\" command. The default scenario file path is \"deploy.json\"; additional files use the naming pattern \"deploy-.json\". For full documentation, please see https://rushjs.io", + + "type": "object", + "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" + }, + + "deploymentProjectNames": { + "description": "The \"rush deploy\" command prepares a deployment folder, starting from the main project and collecting all of its dependencies (both NPM packages and other Rush projects). The main project is specified using the \"--project\" parameter. The \"deploymentProjectNames\" setting lists the allowable choices for the \"--project\" parameter; this documents the intended deployments for your monorepo and helps validate that \"rush deploy\" is invoked correctly. If there is only one item in the \"deploymentProjectNames\" array, then \"--project\" can be omitted. The names should be complete package names as declared in rush.json.\n\nIf the main project should include other unrelated Rush projects, add it to the \"projectSettings\" section, and then specify those projects in the \"additionalProjectsToInclude\" list.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + + "includeDevDependencies": { + "description": "When deploying a local Rush project, the package.json \"devDependencies\" are normally excluded. If you want to include them, set \"includeDevDependencies\" to true. The default value is false.", + "type": "boolean" + }, + + "includeNpmIgnoreFiles": { + "description": "When deploying a local Rush project, normally the .npmignore filter is applied so that Rush only copies files that would be packaged by \"npm pack\". Setting \"includeNpmIgnoreFiles\" to true will disable this filtering so that all files are copied (with a few trivial exceptions such as the \"node_modules\" folder). The default value is false.", + "type": "boolean" + }, + + "omitPnpmWorkaroundLinks": { + "description": "To improve backwards compatibility with legacy packages, the PNPM package manager installs extra links in the node_modules folder that enable packages to import undeclared dependencies. In some cases this workaround may significantly increase the installation footprint or cause other problems. If your deployment does not require this workaround, you can set \"omitPnpmWorkaroundLinks\" to true to avoid creating the extra links. The default value is false.", + "type": "boolean" + }, + + "linkCreation": { + "description": "Specify how links (symbolic links, hard links, and/or NTFS junctions) will be created in the deployed folder:\n\"default\": Create the links while copying the files; this is the default behavior.\n\"script\": A Node.js script called \"create-links.js\" will be written. When executed, this script will create the links described in the \"deploy-metadata.json\" output file.\n\"none\": Do nothing; some other tool may create the links later.", + "type": "string", + "enum": ["default", "script", "none"] + }, + + "folderToCopy": { + "description": "If this path is specified, then after \"rush deploy\", recursively copy the files from this folder to the deployment target folder (common/deploy). This can be used to provide additional configuration files or scripts needed by the server when deploying. The path is resolved relative to the repository root.", + "type": "string" + }, + + "projectSettings": { + "description": "Customize how Rush projects are processed during deployment.", + "type": "array", + "items": { + "type": "object", + "properties": { + "projectName": { + "description": "The full package name of the project, which must be declared in rush.json.", + "type": "string" + }, + "additionalProjectsToInclude": { + "description": "A list of additional local Rush projects to be deployed with this project (beyond the package.json dependencies). Specify full package names, which must be declared in rush.json.", + "type": "array", + "items": { + "type": "string" + } + }, + "additionalDependenciesToInclude": { + "description": "When deploying a project, the included dependencies are normally determined automatically based on package.json fields such as 'dependencies', 'peerDependencies', and 'optionalDependencies', subject to other deployment settings such as 'includeDevDependencies'. However, in cases where that information is not accurate, you can use 'additionalDependenciesToInclude' to add more packages to the list.", + "type": "array", + "items": { + "type": "string" + } + }, + "dependenciesToExclude": { + "description": "This setting prevents specific dependencies from being deployed. It only filters dependencies that are explicitly declared in package.json for this project. It does not affect dependencies added via 'additionalProjectsToInclude' or 'additionalDependenciesToInclude', nor does it affect indirect dependencies.", + "type": "array", + "items": { + "type": "string" + } + }, + "patternsToInclude": { + "description": "A list of glob patterns to include when extracting this project. If a path is matched by both \"patternsToInclude\" and \"patternsToExclude\", the path will be excluded. If undefined, all paths will be included.", + "type": "array", + "items": { + "type": "string" + } + }, + "patternsToExclude": { + "description": "A list of glob patterns to exclude when extracting this project. If a path is matched by both \"patternsToInclude\" and \"patternsToExclude\", the path will be excluded. If undefined, no paths will be excluded.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["projectName"], + "additionalProperties": false + } + }, + + "dependencySettings": { + "description": "Customize how third party dependencies are processed during deployment.", + "type": "array", + "items": { + "type": "object", + "properties": { + "dependencyName": { + "description": "The full package name of third party dependency", + "type": "string" + }, + "dependencyVersionRange": { + "description": "The semantic version range of third party dependency", + "type": "string" + }, + "patternsToInclude": { + "description": "A list of glob patterns to include when extracting the dependency specified in this object. If a path is matched by both \"patternsToInclude\" and \"patternsToExclude\", the path will be excluded. If undefined, all paths will be included.", + "type": "array", + "items": { + "type": "string" + } + }, + "patternsToExclude": { + "description": "A list of glob patterns to include when extracting the dependency specified in this object. If a path is matched by both \"patternsToInclude\" and \"patternsToExclude\", the path will be excluded. If undefined, no paths will be excluded.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["dependencyName", "dependencyVersionRange"], + "additionalProperties": false + } + } + }, + "required": ["deploymentProjectNames"], + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/experiments.schema.json b/libraries/rush-lib/src/schemas/experiments.schema.json new file mode 100644 index 00000000000..35f173444b4 --- /dev/null +++ b/libraries/rush-lib/src/schemas/experiments.schema.json @@ -0,0 +1,87 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush experiments.json config file", + "description": "For use with the Rush tool, this file allows repo maintainers to enable and disable experimental Rush features.", + + "type": "object", + "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" + }, + + "usePnpmFrozenLockfileForRushInstall": { + "description": "By default, 'rush install' passes --no-prefer-frozen-lockfile to 'pnpm install'. Set this option to true to pass '--frozen-lockfile' instead.", + "type": "boolean" + }, + "usePnpmPreferFrozenLockfileForRushUpdate": { + "description": "By default, 'rush update' passes --no-prefer-frozen-lockfile to 'pnpm install'. Set this option to true to pass '--prefer-frozen-lockfile' instead.", + "type": "boolean" + }, + "usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate": { + "description": "By default, 'rush update' runs as a single operation. Set this option to true to instead update the lockfile with `--lockfile-only`, then perform a `--frozen-lockfile` install. Necessary when using the `afterAllResolved` hook in .pnpmfile.cjs.", + "type": "boolean" + }, + "omitImportersFromPreventManualShrinkwrapChanges": { + "description": "If using the 'preventManualShrinkwrapChanges' option, only prevent manual changes to the total set of external dependencies referenced by the repository, not which projects reference which dependencies. This offers a balance between lockfile integrity and merge conflicts.", + "type": "boolean" + }, + "noChmodFieldInTarHeaderNormalization": { + "description": "If true, the chmod field in temporary project tar headers will not be normalized. This normalization can help ensure consistent tarball integrity across platforms.", + "type": "boolean" + }, + "buildCacheWithAllowWarningsInSuccessfulBuild": { + "description": "If true, build caching will respect the allowWarningsInSuccessfulBuild flag and cache builds with warnings. This will not replay warnings from the cached build.", + "type": "boolean" + }, + "buildSkipWithAllowWarningsInSuccessfulBuild": { + "description": "If true, build skipping will respect the allowWarningsInSuccessfulBuild flag and skip builds with warnings. This will not replay warnings from the skipped build.", + "type": "boolean" + }, + "phasedCommands": { + "description": "THIS EXPERIMENT HAS BEEN GRADUATED TO A STANDARD FEATURE. THIS PROPERTY SHOULD BE REMOVED.", + "type": "boolean" + }, + "cleanInstallAfterNpmrcChanges": { + "description": "If true, perform a clean install after when running `rush install` or `rush update` if the `.npmrc` file has changed since the last install.", + "type": "boolean" + }, + "printEventHooksOutputToConsole": { + "description": "If true, print the outputs of shell commands defined in event hooks to the console.", + "type": "boolean" + }, + "forbidPhantomResolvableNodeModulesFolders": { + "description": "If true, Rush will not allow node_modules in the repo folder or in parent folders.", + "type": "boolean" + }, + "usePnpmSyncForInjectedDependencies": { + "description": "(UNDER DEVELOPMENT) For certain installation problems involving peer dependencies, PNPM cannot correctly satisfy versioning requirements without installing duplicate copies of a package inside the node_modules folder. This poses a problem for 'workspace:*' dependencies, as they are normally installed by making a symlink to the local project source folder. PNPM's 'injected dependencies' feature provides a model for copying the local project folder into node_modules, however copying must occur AFTER the dependency project is built and BEFORE the consuming project starts to build. The 'pnpm-sync' tool manages this operation; see its documentation for details. Enable this experiment if you want 'rush' and 'rushx' commands to resync injected dependencies by invoking 'pnpm-sync' during the build.", + "type": "boolean" + }, + "generateProjectImpactGraphDuringRushUpdate": { + "description": "If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`.", + "type": "boolean" + }, + "useIPCScriptsInWatchMode": { + "description": "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.", + "type": "boolean" + }, + "allowCobuildWithoutCache": { + "description": "When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache.", + "type": "boolean" + }, + "rushAlerts": { + "description": "(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.", + "type": "boolean" + }, + "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" + } + }, + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/pnpm-config.schema.json b/libraries/rush-lib/src/schemas/pnpm-config.schema.json new file mode 100644 index 00000000000..c7e628af851 --- /dev/null +++ b/libraries/rush-lib/src/schemas/pnpm-config.schema.json @@ -0,0 +1,255 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Pnpm configuration", + "description": "This configuration file provides settings specific to the PNPM package manager.", + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "useWorkspaces": { + "description": "If true, then `rush install` and `rush update` will use the PNPM workspaces feature to perform the install, instead of the old model where Rush generated the symlinks for each projects's node_modules folder. This option is strongly recommended. The default value is false.", + "type": "boolean" + }, + + "strictPeerDependencies": { + "description": "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, which is an invalid state that can cause build failures or incompatible dependency versions. (For historical reasons, JavaScript package managers generally do not treat this invalid state as an error.) This is done via the \"--strict-peer-dependencies\" flag in PNPM version < 7.0.0 and via the \"--no-strict-peer-dependencies\" flag in PNPM >= 7.0.0. The default value is false.", + "type": "boolean" + }, + + "pnpmStore": { + "description": "Specifies the location of the PNPM store. There are two possible values:\n\n\"local\" - use the \"pnpm-store\" folder in the current configured temp folder: \"common/temp/pnpm-store\" by default.\n\"global\" - use PNPM's global store, which has the benefit of being shared across multiple repo folders, but the disadvantage of less isolation for builds (e.g. bugs or incompatibilities when two repos use different releases of PNPM)\n\nIn both cases, the store path can be overridden by the environment variable RUSH_PNPM_STORE_PATH.\n\nThe default value is \"local\".", + "type": "string", + "enum": ["local", "global"] + }, + + "environmentVariables": { + "description": "Environment variables for PNPM invocation", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "override": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + + "preventManualShrinkwrapChanges": { + "description": "If true, then \"rush install\" will report an error if manual modifications were made to the PNPM shrinkwrap file without running `rush update` afterwards. To temporarily disable this validation when invoking \"rush install\", use the \"--bypassPolicy\" command-line parameter. The default value is false.", + "type": "boolean" + }, + + "alwaysInjectDependenciesFromOtherSubspaces": { + "description": "When a project uses `workspace:` to depend on another Rush project, PNPM normally installs it by creating a symlink under `node_modules`. This generally works well, but in certain cases such as differing `peerDependencies` versions, symlinking may cause trouble such as incorrectly satisfied versions. For such cases, the dependency can be declared as \"injected\", causing PNPM to copy its built output into `node_modules` like a real install from a registry. Details here: https://rushjs.io/pages/advanced/injected_deps/\n\nWhen using Rush subspaces, these sorts of versioning problems are much more likely if `workspace:` refers to a project from a different subspace. This is because the symlink would point to a separate `node_modules` tree installed by a different PNPM lockfile. A comprehensive solution is to enable `alwaysInjectDependenciesFromOtherSubspaces`, which automatically treats all projects from other subspaces as injected dependencies without having to manually configure them.\n\nNOTE: Use carefully -- excessive file copying can slow down the `rush install` and `pnpm-sync` operations if too many dependencies become injected.\n\nThe default value is false.", + "type": "boolean" + }, + + "globalOverrides": { + "description": "The \"globalOverrides\" setting provides a simple mechanism for overriding version selections for all dependencies of all projects in the monorepo workspace. The settings are copied into the `pnpm.overrides` field of the `common/temp/package.json` file that is generated by Rush during installation.\n\nOrder of precedence: `.pnpmfile.cjs` has the highest precedence, followed by `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, and `globalOverrides` has lowest precedence.\n\nPNPM documentation: https://pnpm.io/package_json#pnpmoverrides", + "type": "object", + "additionalProperties": { + "description": "You may specify the package the overridden dependency belongs to by separating the package selector from the dependency selector with a \">\", for example qar@1>zoo will only override the zoo dependency of qar@1, not for any other dependencies.", + "type": "string" + } + }, + + "globalPeerDependencyRules": { + "description": "The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors that are reported during installation with `strictPeerDependencies=true`. The settings are copied into the `pnpm.peerDependencyRules` field of the `common/temp/package.json` file that is generated by Rush during installation.\n\nOrder of precedence: `.pnpmfile.cjs` has the highest precedence, followed by `unsupportedPackageJsonSettings`, `globalPeerDependencyRules`, `globalPackageExtensions`, and `globalOverrides` has lowest precedence.\n\nhttps://pnpm.io/package_json#pnpmpeerdependencyrules", + "type": "object", + "additionalProperties": false, + "properties": { + "ignoreMissing": { + "description": "pnpm will not print warnings about missing peer dependencies from this list.", + "type": "array", + "items": { + "type": "string" + } + }, + "allowedVersions": { + "description": "Unmet peer dependency warnings will not be printed for peer dependencies of the specified range.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "allowAny": { + "description": "\"allowAny\" is an array of package name patterns, any peer dependency matching the pattern will be resolved from any version, regardless of the range specified in \"peerDependencies\"", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + + "globalPackageExtensions": { + "description": "This fields offer a way to extend the existing package definitions with additional information.", + "type": "object", + "additionalProperties": { + "description": "Specify the extension to a package", + "type": "object", + "additionalProperties": false, + "properties": { + "dependencies": { + "type": "object", + "additionalProperties": { + "description": "Specify the version of the dependency", + "type": "string" + } + }, + "optionalDependencies": { + "type": "object", + "additionalProperties": { + "description": "Specify the version of the optionalDependency", + "type": "string" + } + }, + "peerDependencies": { + "type": "object", + "additionalProperties": { + "description": "Specify the version of the peerDependency", + "type": "string" + } + }, + "peerDependenciesMeta": { + "description": "Specify the peerDependenciesMeta", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "optional": { + "type": "boolean" + } + } + } + } + } + } + }, + + "globalNeverBuiltDependencies": { + "description": "This field allows to ignore the builds of specific dependencies. The \"preinstall\", \"install\", and \"postinstall\" scripts of the listed packages will not be executed during installation.", + "type": "array", + "items": { + "description": "Specify package name of the dependency", + "type": "string" + } + }, + + "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", + "items": { + "description": "Specify the package name of the optional dependency to be ignored.", + "type": "string" + } + }, + + "globalAllowedDeprecatedVersions": { + "description": "The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package versions that the NPM registry reports as being deprecated. This is useful if the deprecated package is an indirect dependency of an external package that has not released a fix. The settings are copied into the `pnpm.allowedDeprecatedVersions` field of the `common/temp/package.json` file that is generated by Rush during installation.\n\nPNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + + "globalPatchedDependencies": { + "description": "(THIS FIELD IS MACHINE GENERATED) The \"globalPatchedDependencies\" field is updated automatically by the `rush-pnpm patch-commit` command. It is a dictionary, where the key is an NPM package name and exact version, and the value is a relative path to the associated patch file.\n\nPNPM documentation: https://pnpm.io/package_json#pnpmpatcheddependencies", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + + "unsupportedPackageJsonSettings": { + "description": "(USE AT YOUR OWN RISK) This is a free-form property bag that will be copied into the `common/temp/package.json` file that is generated by Rush during installation. This provides a way to experiment with new PNPM features. These settings will override any other Rush configuration associated with a given JSON field except for `.pnpmfile.cjs`.", + "type": "object" + }, + + "resolutionMode": { + "description": "This option overrides the resolution-mode in PNPM. Use it if you want to change the default resolution behavior when installing dependencies. Defaults to \"highest\".\n\nPNPM documentation: https://pnpm.io/npmrc#resolution-mode.", + "type": "string", + "enum": ["highest", "time-based", "lowest-direct"] + }, + + "autoInstallPeers": { + "description": "This setting determines whether PNPM will automatically install (non-optional) missing peer dependencies instead of reporting an error. With Rush, the default value is always false.\n\nPNPM documentation: https://pnpm.io/npmrc#auto-install-peers", + "type": "boolean" + }, + + "minimumReleaseAge": { + "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" + }, + + "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" + } + }, + + "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" + }, + + "pnpmLockfilePolicies": { + "description": "This setting defines the policies that govern the `pnpm-lock.yaml` file.", + "type": "object", + "additionalProperties": false, + "properties": { + "disallowInsecureSha1": { + "type": "object", + "description": "Forbid sha1 hashes in `pnpm-lock.yaml`.", + "properties": { + "enabled": { + "type": "boolean" + }, + "exemptPackageVersions": { + "description": "A list of specific package versions to be exempted from the \"disallowInsecureSha1\" policy", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An array of exempted versions for this package." + } + } + }, + "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 new file mode 100644 index 00000000000..d14c1de3ac4 --- /dev/null +++ b/libraries/rush-lib/src/schemas/repo-state.schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush repo-state.json file", + "description": "For use with the Rush tool, this file tracks the state of various features in the Rush repo. See http://rushjs.io for details.", + + "type": "object", + "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" + }, + "pnpmShrinkwrapHash": { + "description": "A hash of the contents of the PNPM shrinkwrap file for the repository. This hash is used to determine whether or not the shrinkwrap has been modified prior to install.", + "type": "string" + }, + "preferredVersionsHash": { + "description": "A hash of \"preferred versions\" for the repository. This hash is used to determine whether or not preferred versions have been modified prior to install.", + "type": "string" + }, + "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-alerts.schema.json b/libraries/rush-lib/src/schemas/rush-alerts.schema.json new file mode 100644 index 00000000000..819fb27fcf4 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-alerts.schema.json @@ -0,0 +1,79 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush rush-alerts.json file", + "description": "This configuration file provides settings to rush alerts feature.", + "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" + }, + + "timezone": { + "description": "Settings such as `startTime` and `endTime` will use this timezone.\n\nIf omitted, the default timezone is UTC (`+00:00`).", + "type": "string" + }, + "alerts": { + "description": "An array of alert messages and conditions for triggering them.", + "items": { + "$ref": "#/definitions/IAlert" + }, + "type": "array" + } + }, + "definitions": { + "IAlert": { + "type": "object", + "properties": { + "alertId": { + "description": "The alertId is used to identify the alert.", + "type": "string" + }, + "title": { + "description": "When the alert is displayed, this title will appear at the top of the message box. It should be a single line of text, as concise as possible.", + "type": "string" + }, + "message": { + "description": "When the alert is displayed, this text appears in the message box.\n\nTo make the JSON file more readable, if the text is longer than one line, you can instead provide an array of strings that will be concatenated.\n\nYour text may contain newline characters, but generally this is unnecessary because word-wrapping is automatically applied.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "detailsUrl": { + "description": "(OPTIONAL) To avoid spamming users, the `title` and `message` settings should be kept as concise as possible.\n\nIf you need to provide more detail, use this setting to print a hyperlink to a web page with further guidance.", + "type": "string" + }, + "startTime": { + "description": "(OPTIONAL) If `startTime` is specified, then this alert will not be shown prior to that time.\n\nKeep in mind that the alert is not guaranteed to be shown at this time, or at all. Alerts are only displayed after a Rush command has triggered fetching of the latest rush-alerts.json configuration.\n\nAlso, display of alerts is throttled to avoid spamming the user with too many messages.\n\nIf you need to test your alert, set the environment variable `RUSH_ALERTS_DEBUG=1` to disable throttling.\n\nThe `startTime` should be specified as `YYYY-MM-DD HH:MM` using 24 hour time format, or else `YYYY-MM-DD` in which case the time part will be `00:00` (start of that day). The time zone is obtained from the `timezone` setting above.", + "type": "string" + }, + "endTime": { + "description": "(OPTIONAL) This alert will not be shown if the current time is later than `endTime`.\n\nThe format is the same as `startTime`.", + "type": "string" + }, + "maximumDisplayInterval": { + "description": "(OPTIONAL) Specifies the maximum frequency at which this alert can be displayed within a defined time period.\n\nOptions are:\n\n \"always\" (default) - no limit on display frequency, \"monthly\" - display up to once per month, \"weekly\" - display up to once per week, \"daily\" - display up to once per day, \"hourly\" - display up to once per hour.", + "enum": ["always", "monthly", "weekly", "daily", "hourly"] + }, + "priority": { + "description": "(OPTIONAL) Determines the order in which this alert is shown relative to other alerts, based on urgency.\n\nOptions are: \n\n \"high\" - displayed first, \"normal\" (default) - standard urgency, \"low\" - least urgency.", + "enum": ["high", "normal", "low"] + }, + "conditionScript": { + "description": "(OPTIONAL) The filename of a script that determines whether this alert can be shown, found in the 'common/config/rush/alert-scripts' folder.\n\nThe script must define a CommonJS export named `canShowAlert` that returns a boolean value, for example:\n\n`module.exports.canShowAlert = function () { // (your logic goes here) return true; }`.\n\nRush will invoke this script with the working directory set to the monorepo root folder, with no guarantee that `rush install` has been run.\n\nTo ensure up-to-date alerts, Rush may fetch and checkout the 'common/config/rush-alerts' folder in an unpredictable temporary path. Therefore, your script should avoid importing dependencies from outside its folder, generally be kept as simple and reliable and quick as possible.\n\nFor more complex conditions, we suggest to design some other process that prepares a data file or environment variable that can be cheaply checked by your condition script.", + "type": "string" + } + }, + "required": ["alertId", "title", "message"] + } + } +} 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-plugin-manifest.schema.json b/libraries/rush-lib/src/schemas/rush-plugin-manifest.schema.json new file mode 100644 index 00000000000..293aaf6d694 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-plugin-manifest.schema.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "title": "Rush plugin package manifest", + "description": "This file declares what kind of plugins this package provided.", + "type": "object", + "additionalProperties": false, + "required": ["plugins"], + "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" + }, + "plugins": { + "type": "array", + "items": { + "type": "object", + "required": ["pluginName", "description"], + "additionalProperties": false, + "properties": { + "pluginName": { + "type": "string" + }, + "description": { + "type": "string" + }, + "entryPoint": { + "description": "Specifies entry point path. This path is resolved relative to the package folder.", + "type": "string" + }, + "optionsSchema": { + "description": "Specifies options schema file path. This path is resolved relative to the package folder.", + "type": "string" + }, + "associatedCommands": { + "description": "Specifies associated commands with this plugin, plugin will be only installed when an associated command runs.", + "type": "array", + "items": { + "type": "string" + } + }, + "commandLineJsonFilePath": { + "description": "Specifies a command line config file path. The path is resolved relative to package folder. It defines custom command line commands, mostly same as command-line.json in Rush", + "type": "string" + } + } + } + } + } +} diff --git a/libraries/rush-lib/src/schemas/rush-plugins.schema.json b/libraries/rush-lib/src/schemas/rush-plugins.schema.json new file mode 100644 index 00000000000..caa4e0784ea --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-plugins.schema.json @@ -0,0 +1,37 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "title": "Rush rush-plugins.json config file", + "description": "This file defines plugins used by Rush", + "type": "object", + "required": ["plugins"], + "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" + }, + "plugins": { + "description": "A list of rush plugin definition.", + "type": "array", + "items": { + "type": "object", + "required": ["packageName", "pluginName", "autoinstallerName"], + "additionalProperties": false, + "properties": { + "packageName": { + "description": "The NPM package name of the rush plugin.", + "type": "string" + }, + "pluginName": { + "description": "The plugin name provided by rush plugin package.", + "type": "string" + }, + "autoinstallerName": { + "description": "Specifies an autoinstaller name where the rush plugin package is installed.", + "type": "string" + } + } + } + } + } +} diff --git a/libraries/rush-lib/src/schemas/rush-project.schema.json b/libraries/rush-lib/src/schemas/rush-project.schema.json new file mode 100644 index 00000000000..acf1b20e5ae --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-project.schema.json @@ -0,0 +1,126 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Configuration for Rush's build cache.", + "description": "For use with the Rush tool, this file provides per-project configuration options. See http://rushjs.io for details.", + + "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" + }, + + "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. To delete an inherited setting, set it to `null` in this file.", + "type": "string" + }, + + "incrementalBuildIgnoredGlobs": { + "type": "array", + "description": "The incremental analyzer can skip Rush commands for projects whose input files have not changed since the last build. Normally, every Git-tracked file under the project folder is assumed to be an input. Use \"incrementalBuildIgnoredGlobs\" to ignore specific files, specified as globs relative to the project folder. The glob syntax is based on the .gitignore file format.", + "items": { + "type": "string" + } + }, + + "disableBuildCacheForProject": { + "description": "Disable caching for this project. The project will never be restored from cache. This may be useful if this project affects state outside of its folder.", + "type": "boolean" + }, + + "operationSettings": { + "type": "array", + "description": "Options for individual commands and phases.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["operationName"], + "properties": { + "operationName": { + "type": "string", + "description": "The name of the operation. This should be a key in the \"package.json\" file's \"scripts\" section." + }, + + "outputFolderNames": { + "type": "array", + "description": "Specify the folders where this operation writes its output files. If enabled, the Rush build cache will restore these folders from the cache. The strings are folder names under the project root folder. These folders should not be tracked by Git. They must not contain symlinks.", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + + "dependsOnEnvVars": { + "type": "array", + "description": "Specify a list of environment variables that affect the output of this operation. If provided, the values of these variables will become part of the hash when reading and writing from cache.", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + + "dependsOnAdditionalFiles": { + "type": "array", + "description": "Specify a list of glob (minimatch) paths (absolute or relative) pointing to files (within or outside the .git repository) that affect the output of this operation. If provided, the hash values of these files will become part of the final hash when reading and writing from cache.", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + + "disableBuildCacheForOperation": { + "description": "Disable caching for this operation. The operation will never be restored from cache. This may be useful if this operation affects state outside of its folder.", + "type": "boolean" + }, + "sharding": { + "type": "object", + "description": "If specified, the operation will be a 'sharded' operation. This means that the operation will be run multiple times in parallel.", + "additionalProperties": false, + "required": ["count"], + "properties": { + "count": { + "type": "integer", + "description": "The number of shards to run. This must be a positive integer." + }, + "shardArgumentFormat": { + "type": "string", + "description": "A template string that specifies the command-line argument to pass to the operation for each shard. The string may contain the following placeholders: {shardIndex} {shardCount}. Defaults to --shard=\"{shardIndex}/{shardCount}\"" + }, + "outputFolderArgumentFormat": { + "type": "string", + "description": "The command-line argument to pass to the operation to specify the output folder. The string may contain the following placeholders: {phaseName} {shardIndex}. Must end with {shardIndex}. Defaults to --shard-output-folder=\".rush/operations/{phaseName}/shards/{shardIndex}\"" + }, + "shardOperationSettings": { + "type": "object", + "description": "DEPRECATED. Use a separate operationSettings entry with {this operation's name}:shard as the name, ex _phase:build would have a separate operation _phase:build:shard to manage per-shard settings.", + "additionalProperties": true + } + } + }, + "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 + }, + "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/schemas/rush-user-settings.schema.json b/libraries/rush-lib/src/schemas/rush-user-settings.schema.json new file mode 100644 index 00000000000..dde6f7e06f3 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-user-settings.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush per-user settings file", + "description": "For use with the Rush tool, this file stores user-specific settings options. See http://rushjs.io for details.", + + "type": "object", + "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" + }, + + "buildCacheFolder": { + "type": "string", + "description": "If provided, store build cache in the specified folder. Must be an absolute path." + } + }, + "additionalProperties": false +} diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json new file mode 100644 index 00000000000..dce5fcaae37 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -0,0 +1,376 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush main config File", + "description": "The main configuration file for the Rush multi-project build tool. See http://rushjs.io for details.", + "type": "object", + + "definitions": { + "environmentVariables": { + "description": "Environment variables for the package manager", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "override": { + "type": "boolean" + } + }, + "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" + }, + + "npmVersion": { + "description": "If specified, selects NPM as the package manager and specifies the deterministic version to be installed by Rush.", + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" + }, + + "pnpmVersion": { + "description": "If specified, selects PNPM as the package manager and specifies the deterministic version to be installed by Rush.", + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" + }, + + "yarnVersion": { + "description": "If specified, selects Yarn as the package manager and specifies the deterministic version to be installed by Rush.", + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" + }, + + "rushVersion": { + "description": "The version of the Rush tool that will be used to build this repository.", + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9a-zA-Z.+\\-]+$" + }, + "nodeSupportedVersionRange": { + "description": "A node-semver expression (e.g. \">=1.2.3 <2.0.0\", see https://github.com/npm/node-semver) indicating which versions of Node.js can safely be used to build this repository. If omitted, no validation is performed.", + "type": "string" + }, + "nodeSupportedVersionInstructions": { + "description": "If specified, when a rush command fails due to an unsupported node version, this additional instructional message is printed below the failure message.", + "type": "string" + }, + "suppressNodeLtsWarning": { + "description": "Rush normally prints a warning if it detects a pre-LTS Node.js version. If you are testing pre-LTS versions in preparation for supporting the first LTS version, you can use this setting to disable Rush's warning.", + "type": "boolean" + }, + "suppressRushIsPublicVersionCheck": { + "description": "Rush normally prints a warning if it detects that the current version is not one published to the public npmjs.org registry. If you need to block calls to the npm registry, you can use this setting to disable Rush's check.", + "type": "boolean" + }, + "projectFolderMinDepth": { + "description": "The minimum folder depth for the projectFolder field. The default value is 1, i.e. no slashes in the path name.", + "type": "number" + }, + "ensureConsistentVersions": { + "description": "If true, consistent version specifiers for dependencies will be enforced (i.e. \"rush check\" is run before some commands). Used when property is not defined in common-versions.json.", + "type": "boolean" + }, + "hotfixChangeEnabled": { + "description": "Allows creation of hotfix changes. This feature is experimental so it is disabled by default. If this is set, \"rush change\" only allows a \"hotfix\" change type to be specified. This change type will be used when publishing subsequent changes from the monorepo.", + "type": "boolean" + }, + "npmOptions": { + "description": "Options that are only used when the NPM package manager is selected.", + "type": "object", + "properties": { + "environmentVariables": { + "$ref": "#/definitions/environmentVariables" + } + }, + "additionalProperties": false + }, + "pnpmOptions": { + "description": "Options that are only used when the PNPM pacakge manager is selected.", + "type": "object", + "properties": { + "pnpmStore": { + "description": "Specifies the location of the PNPM store. There are two possible values:\n\n\"local\" - use the \"pnpm-store\" folder in the current configured temp folder: \"common/temp/pnpm-store\" by default.\n\"global\" - use PNPM's global store, which has the benefit of being shared across multiple repo folders, but the disadvantage of less isolation for builds (e.g. bugs or incompatibilities when two repos use different releases of PNPM)\n\nIn all cases, the store path will be overridden by the environment variable RUSH_PNPM_STORE_PATH.\n\nThe default value is \"local\".", + "type": "string", + "enum": ["local", "global"] + }, + "strictPeerDependencies": { + "description": "If true, then the installation will fail if there is a missing or invalid peer dependency in the tree, which is an invalid state that can cause build failures or incompatible dependency versions. (For historical reasons, JavaScript package managers generally do not treat this invalid state as an error.) This is done via the \"--strict-peer-dependencies\" flag in PNPM version < 7.0.0 and via the \"--no-strict-peer-dependencies\" flag in PNPM >= 7.0.0. The default value is false.", + "type": "boolean" + }, + "resolutionStrategy": { + "description": "(Deprecated) Configures the strategy used to select versions during installation. This feature requires PNPM version 3.1 or newer. It corresponds to the \"--resolution-strategy\" command-line option for PNPM. Possible values are \"fast\" and \"fewer-dependencies\". PNPM's default is \"fast\", but this may be incompatible with certain packages, for example the \"@types\" packages from DefinitelyTyped. Rush's default is \"fewer-dependencies\", which causes PNPM to avoid installing a newer version if an already installed version can be reused; this is more similar to NPM's algorithm.", + "type": "string", + "enum": ["fewer-dependencies", "fast"] + }, + "environmentVariables": { + "$ref": "#/definitions/environmentVariables" + }, + "preventManualShrinkwrapChanges": { + "description": "If true, then \"rush install\" will report an error if manual modifications were made to the PNPM shrinkwrap file without running `rush update` afterwards. To temporarily disable this validation when invoking \"rush install\", use the \"--bypassPolicy\" command-line parameter. The default value is false.", + "type": "boolean" + }, + "useWorkspaces": { + "description": "If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM. The default value is false.", + "type": "boolean" + } + }, + "additionalProperties": false + }, + "yarnOptions": { + "description": "Options that are only used when the Yarn pacakge manager is selected.", + "type": "object", + "properties": { + "ignoreEngines": { + "description": "If true, then Rush will add the \"--ignore-engines\" option when invoking Yarn. * This allows \"rush install\" to succeed if there are dependencies with engines defined in package.json which do not match the current environment. The default value is false.", + "type": "boolean" + }, + "environmentVariables": { + "$ref": "#/definitions/environmentVariables" + } + }, + "additionalProperties": false + }, + "projectFolderMaxDepth": { + "description": "The maximum folder depth for the projectFolder field. The default value is 2, i.e. a single slash in the path name.", + "type": "number" + }, + "allowMostlyStandardPackageNames": { + "description": "Today the npmjs.com registry enforces fairly strict naming rules for packages, but in the early days there was no standard and hardly any enforcement. A few large legacy projects are still using nonstandard package names, and private registries sometimes allow it. Set \"allowMostlyStandardPackageNames\" to true to relax Rush's enforcement of package names. This allows upper case letters and in the future may relax other rules, however we want to minimize these exceptions. Many popular tools use certain punctuation characters as delimiters, based on the assumption that they will never appear in a package name; thus if we relax the rules too much it is likely to cause very confusing malfunctions. The default value is false.", + "type": "boolean" + }, + "approvedPackagesPolicy": { + "description": "Controls a package review workflow driven by the two config files \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\"", + "type": "object", + "properties": { + "reviewCategories": { + "description": "A list of category names that can be applied to each project, and then referenced in \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\"", + "type": "array", + "items": { + "type": "string" + } + }, + "ignoredNpmScopes": { + "description": "A list of NPM package scopes that will be excluded from review (e.g. \"@types\")", + "type": "array", + "items": { + "type": "string", + "pattern": "^@" + } + } + }, + "additionalProperties": false + }, + "gitPolicy": { + "description": "If the project is stored in a Git repository, additional settings related to Git", + "type": "object", + "properties": { + "allowedEmailRegExps": { + "description": "A list of regular expressions describing allowable e-mail patterns for Git commits. They are case-insensitive anchored JavaScript RegExps. Example: \".*@example\\.com\"", + "type": "array", + "items": { + "type": "string" + } + }, + "sampleEmail": { + "description": "An example valid e-mail address for \"Mr. Example\" that conforms to one of the allowedEmailRegExps. Example: \"mr-example@contoso\\.com\"", + "type": "string" + }, + "versionBumpCommitMessage": { + "description": "The commit message to use when committing changes during \"rush publish\". Defaults to \"Bump versions [skip ci]\"", + "type": "string" + }, + "changeLogUpdateCommitMessage": { + "description": "The commit message to use when committing change log files \"rush version\". Defaults to \"Update changelogs [skip ci]\"", + "type": "string" + }, + "changefilesCommitMessage": { + "description": "The commit message to use when committing change files made by \"rush change\". Defaults to \"Rush change\"", + "type": "string" + }, + "tagSeparator": { + "description": "The separator between package name and version in git tag. Defaults to \"_\"", + "type": "string" + } + }, + "additionalProperties": false + }, + "variants": { + "description": "Defines the list of installation variants for this repository. For more details about this feature, see this article: https://rushjs.io/pages/advanced/installation_variants/", + "type": "array", + "items": { + "type": "object", + "properties": { + "variantName": { + "description": "The name of the variant. Maps to common/rush/variants/{name} under the repository root.", + "type": "string" + }, + "description": { + "description": "", + "type": "string" + } + }, + "required": ["variantName", "description"] + } + }, + "repository": { + "description": "The repository location", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The remote url of the repository. If a value is provided, \"rush change\" will use it to find the right remote to compare against." + }, + "urls": { + "description": "All allowed remote urls of the repository. If a value is provided, \"rush change\" will use one of these to find the right remote to compare against. Specifying multiple URLs is useful if a GitHub repository is renamed or for \".visualstudio.com\" vs \"dev.azure.com/\" URLs.", + "type": "array", + "items": { + "type": "string" + } + }, + "defaultBranch": { + "description": "The default branch name. This tells \"rush change\" which remote branch to compare against. The default value is \"main\"", + "type": "string" + }, + "defaultRemote": { + "description": "The default remote. This tells \"rush change\" which remote to compare against if the remote URL is not set or if a remote matching the provided remote URL is not found.", + "type": "string" + } + }, + "additionalProperties": false + }, + "telemetryEnabled": { + "description": "Indicates whether telemetry data should be collected and stored in the Rush temp folder during Rush runs.", + "type": "boolean" + }, + "allowedProjectTags": { + "description": "This is an optional, but recommended, list of allowed tags that can be applied to Rush projects using the \"tags\" setting in this file. This list is useful for preventing mistakes such as misspelling, and it also provides a centralized place to document your tags. If \"allowedProjectTags\" list is not specified, then any valid tag is allowed. A tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" + } + }, + "projects": { + "description": "A list of projects managed by this tool.", + "type": "array", + "items": { + "type": "object", + "properties": { + "packageName": { + "description": "The NPM package name of the project.", + "type": "string" + }, + "projectFolder": { + "description": "The path to the project folder relative to the Rush config file.", + "type": "string" + }, + "reviewCategory": { + "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", + "type": "string" + }, + "cyclicDependencyProjects": { + "description": "(Deprecated) This field was renamed to \"decoupledLocalDependencies\".", + "type": "array", + "items": { + "type": "string" + } + }, + "decoupledLocalDependencies": { + "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", + "type": "array", + "items": { + "type": "string" + } + }, + "shouldPublish": { + "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", + "type": "boolean" + }, + "skipRushCheck": { + "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", + "type": "boolean" + }, + "versionPolicyName": { + "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", + "type": "string" + }, + "publishFolder": { + "description": "Facilitates postprocessing of a project's files prior to publishing. If specified, the \"publishFolder\" is the relative path to a subfolder of the project folder. The \"rush publish\" command will publish the subfolder instead of the project folder. The subfolder must contain its own package.json file, which is typically a build output.", + "type": "string" + }, + "tags": { + "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" + } + }, + "subspaceName": { + "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["packageName", "projectFolder"] + } + }, + "eventHooks": { + "description": "Hooks are customized script actions that Rush executes when specific events occur.", + "type": "object", + "properties": { + "preRushInstall": { + "description": "The list of scripts to run before the Rush installation starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushInstall": { + "description": "The list of scripts to run after the Rush installation finishes.", + "type": "array", + "items": { + "type": "string" + } + }, + "preRushBuild": { + "description": "The list of scripts to run before the Rush build command starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushBuild": { + "description": "The list of scripts to run after the Rush build command finishes.", + "type": "array", + "items": { + "type": "string" + } + }, + "preRushx": { + "description": "The list of scripts to run before rushx starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushx": { + "description": "The list of scripts to run after rushx finishes.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["rushVersion", "projects"] +} diff --git a/libraries/rush-lib/src/schemas/subspaces.schema.json b/libraries/rush-lib/src/schemas/subspaces.schema.json new file mode 100644 index 00000000000..5322a806a7b --- /dev/null +++ b/libraries/rush-lib/src/schemas/subspaces.schema.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush subspace config file.", + "description": "The configuration file for enabling the subspaces feature in rush. This is an EXPERIMENTAL feature which is not yet fully implemented. To opt into the experiment, simply toggle the 'enabled' property in this file.", + "type": "object", + + "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" + }, + "subspacesEnabled": { + "description": "If true, rush will use the subspaces configuration.", + "type": "boolean" + }, + "splitWorkspaceCompatibility": { + "description": "(DEPRECATED) Allows individual subspaces to be configured at the package level if that package is the only project in the subspace. Used to help migrate from a split workspace state.", + "type": "boolean" + }, + "preventSelectingAllSubspaces": { + "description": "If true, requires a selector for a subspace or set of subspaces when installing.", + "type": "boolean" + }, + "subspaceNames": { + "description": "Individual subspace configurations.", + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/apps/rush-lib/src/schemas/version-policies.schema.json b/libraries/rush-lib/src/schemas/version-policies.schema.json similarity index 82% rename from apps/rush-lib/src/schemas/version-policies.schema.json rename to libraries/rush-lib/src/schemas/version-policies.schema.json index eb18426c7a7..35995c5cc30 100644 --- a/apps/rush-lib/src/schemas/version-policies.schema.json +++ b/libraries/rush-lib/src/schemas/version-policies.schema.json @@ -8,10 +8,7 @@ "type": "object", "allOf": [ { - "oneOf": [ - { "$ref": "#/definitions/lockStepVersion" }, - { "$ref": "#/definitions/individualVersion" } - ] + "oneOf": [{ "$ref": "#/definitions/lockStepVersion" }, { "$ref": "#/definitions/individualVersion" }] }, { "type": "object", @@ -45,14 +42,7 @@ "definitions": { "any-value": { - "type": [ - "array", - "boolean", - "integer", - "number", - "object", - "string" - ], + "type": ["array", "boolean", "integer", "number", "object", "string"], "items": { "$ref": "#/definitions/any-value" } @@ -78,7 +68,7 @@ }, "nextBump": { "description": "Type of next version bump", - "enum": ["prerelease", "release", "minor", "patch", "major"] + "enum": ["none", "prerelease", "preminor", "minor", "patch", "major"] }, "mainProject": { "description": "The main project for this version policy", @@ -87,9 +77,13 @@ "exemptFromRushChange": { "description": "If true, the version policy will not require changelog files.", "type": "boolean" + }, + "includeEmailInChangeFile": { + "description": "If true, the generated changelog files will include the author's email address.", + "type": "boolean" } }, - "required": ["policyName", "definitionName", "version", "nextBump"], + "required": ["policyName", "definitionName", "version"], "additionalProperties": false }, @@ -113,6 +107,10 @@ "exemptFromRushChange": { "description": "If true, the version policy will not require changelog files.", "type": "boolean" + }, + "includeEmailInChangeFile": { + "description": "If true, the generated changelog files will include the author's email address.", + "type": "boolean" } }, "required": ["policyName", "definitionName"], diff --git a/libraries/rush-lib/src/scripts/install-run-rush-pnpm.ts b/libraries/rush-lib/src/scripts/install-run-rush-pnpm.ts new file mode 100644 index 00000000000..2b9a1f5a5b4 --- /dev/null +++ b/libraries/rush-lib/src/scripts/install-run-rush-pnpm.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. + +__non_webpack_require__('./install-run-rush'); diff --git a/libraries/rush-lib/src/scripts/install-run-rush.ts b/libraries/rush-lib/src/scripts/install-run-rush.ts new file mode 100644 index 00000000000..bfb986d46e4 --- /dev/null +++ b/libraries/rush-lib/src/scripts/install-run-rush.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. + +/* eslint-disable no-console */ + +import * as path from 'node:path'; +import * as fs from 'node:fs'; + +const { + installAndRun, + findRushJsonFolder, + RUSH_JSON_FILENAME, + runWithErrorAndStatusCode +}: typeof import('./install-run') = __non_webpack_require__('./install-run'); +import type { ILogger } from '../utilities/npmrcUtilities'; + +const PACKAGE_NAME: string = '@microsoft/rush'; +const RUSH_PREVIEW_VERSION: string = 'RUSH_PREVIEW_VERSION'; +const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE: 'INSTALL_RUN_RUSH_LOCKFILE_PATH' = + 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; + +function _getRushVersion(logger: ILogger): string { + const rushPreviewVersion: string | undefined = process.env[RUSH_PREVIEW_VERSION]; + if (rushPreviewVersion !== undefined) { + logger.info(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); + return rushPreviewVersion; + } + + const rushJsonFolder: string = findRushJsonFolder(); + const rushJsonPath: string = path.join(rushJsonFolder, RUSH_JSON_FILENAME); + try { + const rushJsonContents: string = fs.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: string[] = 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}). ` + + `The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` + + 'using an unexpected syntax.' + ); + } +} + +function _getBin(scriptName: string): string { + switch (scriptName.toLowerCase()) { + case 'install-run-rush-pnpm.js': + return 'rush-pnpm'; + case 'install-run-rushx.js': + return 'rushx'; + default: + return 'rush'; + } +} + +function _run(): void { + const [ + nodePath /* Ex: /bin/node */, + scriptPath /* /repo/common/scripts/install-run-rush.js */, + ...packageBinArgs /* [build, --to, myproject] */ + ]: string[] = 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: string = path.basename(scriptPath); + const bin: string = _getBin(scriptName); + if (!nodePath || !scriptPath) { + throw new Error('Unexpected exception: could not detect node path or script path'); + } + + let commandFound: boolean = false; + let logger: ILogger = { 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 + }; + } 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) { + 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`); + } + process.exit(1); + } + + runWithErrorAndStatusCode(logger, () => { + const version: string = _getRushVersion(logger); + logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`); + + const lockFilePath: string | undefined = process.env[INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE]; + if (lockFilePath) { + logger.info( + `Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.` + ); + } + + return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); + }); +} + +_run(); diff --git a/libraries/rush-lib/src/scripts/install-run-rushx.ts b/libraries/rush-lib/src/scripts/install-run-rushx.ts new file mode 100644 index 00000000000..2b9a1f5a5b4 --- /dev/null +++ b/libraries/rush-lib/src/scripts/install-run-rushx.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. + +__non_webpack_require__('./install-run-rush'); diff --git a/libraries/rush-lib/src/scripts/install-run.ts b/libraries/rush-lib/src/scripts/install-run.ts new file mode 100644 index 00000000000..03b15d8567c --- /dev/null +++ b/libraries/rush-lib/src/scripts/install-run.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. + +/* eslint-disable no-console */ + +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 type { RushConstants } from '../logic/RushConstants'; + +export const RUSH_JSON_FILENAME: typeof RushConstants.rushJsonFilename = 'rush.json'; +const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME: string = 'RUSH_TEMP_FOLDER'; +const INSTALL_RUN_LOCKFILE_PATH_VARIABLE: 'INSTALL_RUN_LOCKFILE_PATH' = 'INSTALL_RUN_LOCKFILE_PATH'; +const INSTALLED_FLAG_FILENAME: string = 'installed.flag'; +const NODE_MODULES_FOLDER_NAME: string = 'node_modules'; +const PACKAGE_JSON_FILENAME: string = 'package.json'; + +/** + * Parse a package specifier (in the form of name\@version) into name and version parts. + */ +function _parsePackageSpecifier(rawPackageSpecifier: string): IPackageSpecifier { + rawPackageSpecifier = (rawPackageSpecifier || '').trim(); + const separatorIndex: number = rawPackageSpecifier.lastIndexOf('@'); + + let name: string; + let version: string | undefined = undefined; + if (separatorIndex === 0) { + // The specifier starts with a scope and doesn't have a version specified + name = rawPackageSpecifier; + } else if (separatorIndex === -1) { + // The specifier doesn't have a version + name = rawPackageSpecifier; + } else { + name = rawPackageSpecifier.substring(0, separatorIndex); + version = rawPackageSpecifier.substring(separatorIndex + 1); + } + + if (!name) { + throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); + } + + return { name, version }; +} + +let _npmPath: string | undefined = undefined; + +/** + * Get the absolute path to the npm executable + */ +export function getNpmPath(): string { + if (!_npmPath) { + try { + if (_isWindows()) { + // We're on Windows + const whereOutput: string = childProcess.execSync('where npm', { stdio: [] }).toString(); + const lines: string[] = whereOutput.split(os.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 = childProcess.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.existsSync(_npmPath)) { + throw new Error('The NPM executable does not exist'); + } + } + + return _npmPath; +} + +function _ensureFolder(folderPath: string): void { + if (!fs.existsSync(folderPath)) { + const parentDir: string = path.dirname(folderPath); + _ensureFolder(parentDir); + fs.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: string, ...pathSegments: string[]): string { + let joinedPath: string = baseFolder; + try { + for (let pathSegment of pathSegments) { + pathSegment = pathSegment.replace(/[\\\/]/g, '+'); + joinedPath = path.join(joinedPath, pathSegment); + if (!fs.existsSync(joinedPath)) { + fs.mkdirSync(joinedPath); + } + } + } catch (e) { + throw new Error( + `Error building local installation folder (${path.join(baseFolder, ...pathSegments)}): ${e}` + ); + } + + return joinedPath; +} + +function _getRushTempFolder(rushCommonFolder: string): string { + const rushTempFolder: string | undefined = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME]; + if (rushTempFolder !== undefined) { + _ensureFolder(rushTempFolder); + return rushTempFolder; + } else { + return _ensureAndJoinPath(rushCommonFolder, 'temp'); + } +} + +export interface IPackageSpecifier { + name: string; + version: string | undefined; +} + +/** + * 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: string, b: string): number { + const aParts: string[] = a.split(/[.-]/); + const bParts: string[] = b.split(/[.-]/); + const numberOfParts: number = Math.max(aParts.length, bParts.length); + for (let i: number = 0; i < numberOfParts; i++) { + if (aParts[i] !== bParts[i]) { + return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0); + } + } + return 0; +} + +/** + * Resolve a package specifier to a static version + */ +function _resolvePackageVersion( + logger: ILogger, + rushCommonFolder: string, + { name, version }: IPackageSpecifier +): string { + if (!version) { + version = '*'; // If no version is specified, use the latest version + } + + 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 { + // version resolves to + try { + const rushTempFolder: string = _getRushTempFolder(rushCommonFolder); + const sourceNpmrcFolder: string = path.join(rushCommonFolder, 'config', 'rush'); + + syncNpmrc({ + sourceNpmrcFolder, + targetNpmrcFolder: rushTempFolder, + logger, + supportEnvVarFallbackSyntax: false + }); + + const npmPath: string = 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: childProcess.SpawnSyncOptions = { + cwd: rushTempFolder, + stdio: [], + shell: _isWindows() + }; + const platformNpmPath: string = _getPlatformPath(npmPath); + const npmVersionSpawnResult: childProcess.SpawnSyncReturns = childProcess.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: string = npmVersionSpawnResult.stdout.toString(); + const parsedVersionOutput: string | string[] = JSON.parse(npmViewVersionOutput); + const versions: string[] = Array.isArray(parsedVersionOutput) + ? parsedVersionOutput + : [parsedVersionOutput]; + let latestVersion: string | undefined = versions[0]; + for (let i: number = 1; i < versions.length; i++) { + const latestVersionCandidate: string = versions[i]; + if (_compareVersionStrings(latestVersionCandidate, latestVersion) > 0) { + latestVersion = latestVersionCandidate; + } + } + + 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: string | undefined; +/** + * Find the absolute path to the folder containing rush.json + */ +export function findRushJsonFolder(): string { + if (!_rushJsonFolder) { + let basePath: string = __dirname; + let tempPath: string = __dirname; + do { + const testRushJsonPath: string = path.join(basePath, RUSH_JSON_FILENAME); + if (fs.existsSync(testRushJsonPath)) { + _rushJsonFolder = basePath; + break; + } else { + basePath = tempPath; + } + } while (basePath !== (tempPath = path.dirname(basePath))); // Exit the loop when we hit the disk root + + if (!_rushJsonFolder) { + throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); + } + } + + return _rushJsonFolder; +} + +/** + * Detects if the package in the specified directory is installed + */ +function _isPackageAlreadyInstalled(packageInstallFolder: string): boolean { + try { + const flagFilePath: string = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + if (!fs.existsSync(flagFilePath)) { + return false; + } + + const fileContents: string = fs.readFileSync(flagFilePath).toString(); + return fileContents.trim() === process.version; + } catch (e) { + return false; + } +} + +/** + * Delete a file. Fail silently if it does not exist. + */ +function _deleteFile(file: string): void { + try { + fs.unlinkSync(file); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} + +/** + * Removes the following files and directories under the specified folder path: + * - installed.flag + * - + * - node_modules + */ +function _cleanInstallFolder( + rushTempFolder: string, + packageInstallFolder: string, + lockFilePath: string | undefined +): void { + try { + const flagFile: string = path.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); + _deleteFile(flagFile); + + const packageLockFile: string = path.resolve(packageInstallFolder, 'package-lock.json'); + if (lockFilePath) { + fs.copyFileSync(lockFilePath, packageLockFile); + } else { + // Not running `npm ci`, so need to cleanup + _deleteFile(packageLockFile); + + const nodeModulesFolder: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); + if (fs.existsSync(nodeModulesFolder)) { + const rushRecyclerFolder: string = _ensureAndJoinPath(rushTempFolder, 'rush-recycler'); + + fs.renameSync( + nodeModulesFolder, + path.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`) + ); + } + } + } catch (e) { + throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); + } +} + +function _createPackageJson(packageInstallFolder: string, name: string, version: string): void { + try { + const packageJsonContents: IPackageJson = { + name: 'ci-rush', + version: '0.0.0', + dependencies: { + [name]: version + }, + description: "DON'T WARN", + repository: "DON'T WARN", + license: 'MIT' + }; + + const packageJsonPath: string = path.join(packageInstallFolder, PACKAGE_JSON_FILENAME); + fs.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: ILogger, + packageInstallFolder: string, + name: string, + version: string, + command: '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`); + } + + logger.info(`Successfully installed ${name}@${version}`); + } catch (e) { + throw new Error(`Unable to install package: ${e}`); + } +} + +/** + * Get the ".bin" path for the package. + */ +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; + 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'; +} + +/** + * Write a flag file to the package's install directory, signifying that the install was successful. + */ +function _writeFlagFile(packageInstallFolder: string): void { + try { + const flagFilePath: string = path.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + fs.writeFileSync(flagFilePath, process.version); + } catch (e) { + throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`); + } +} + +export function installAndRun( + logger: ILogger, + packageName: string, + packageVersion: string, + packageBinName: string, + packageBinArgs: string[], + lockFilePath: string | undefined = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE] +): number { + const rushJsonFolder: string = findRushJsonFolder(); + const rushCommonFolder: string = path.join(rushJsonFolder, 'common'); + const rushTempFolder: string = _getRushTempFolder(rushCommonFolder); + const packageInstallFolder: string = _ensureAndJoinPath( + rushTempFolder, + 'install-run', + `${packageName}@${packageVersion}` + ); + + if (!_isPackageAlreadyInstalled(packageInstallFolder)) { + // The package isn't already installed + _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath); + + const sourceNpmrcFolder: string = path.join(rushCommonFolder, 'config', 'rush'); + syncNpmrc({ + sourceNpmrcFolder, + targetNpmrcFolder: packageInstallFolder, + logger, + supportEnvVarFallbackSyntax: false + }); + + _createPackageJson(packageInstallFolder, packageName, packageVersion); + const command: 'install' | 'ci' = lockFilePath ? 'ci' : 'install'; + _installPackage(logger, packageInstallFolder, packageName, packageVersion, command); + _writeFlagFile(packageInstallFolder); + } + + const statusMessage: string = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; + const statusMessageLine: string = new Array(statusMessage.length + 1).join('-'); + logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); + + const binPath: string = _getBinPath(packageInstallFolder, packageBinName); + const binFolderPath: string = path.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: string = process.env.PATH || ''; + 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, { + stdio: 'inherit', + windowsVerbatimArguments: false, + shell: _isWindows(), + cwd: process.cwd(), + env: process.env + }); + } finally { + process.env.PATH = originalEnvPath; + } + if (result.status !== null) { + return result.status; + } else { + throw result.error || new Error('An unknown error occurred.'); + } +} + +export function runWithErrorAndStatusCode(logger: ILogger, fn: () => number): void { + process.exitCode = 1; + + try { + const exitCode: number = fn(); + process.exitCode = exitCode; + } catch (e) { + logger.error('\n\n' + (e as Error).toString() + '\n\n'); + } +} + +function _run(): void { + const [ + nodePath /* Ex: /bin/node */, + scriptPath /* /repo/common/scripts/install-run-rush.js */, + rawPackageSpecifier /* qrcode@^1.2.0 */, + packageBinName /* qrcode */, + ...packageBinArgs /* [-f, myproject/lib] */ + ]: string[] = process.argv; + + if (!nodePath) { + throw new Error('Unexpected exception: could not detect node path'); + } + + if (path.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) { + 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: ILogger = { info: console.log, error: console.error }; + + runWithErrorAndStatusCode(logger, () => { + const rushJsonFolder: string = findRushJsonFolder(); + const rushCommonFolder: string = _ensureAndJoinPath(rushJsonFolder, 'common'); + + const packageSpecifier: IPackageSpecifier = _parsePackageSpecifier(rawPackageSpecifier); + const name: string = packageSpecifier.name; + const version: string = _resolvePackageVersion(logger, rushCommonFolder, packageSpecifier); + + if (packageSpecifier.version !== version) { + console.log(`Resolved to ${name}@${version}`); + } + + return installAndRun(logger, name, version, packageBinName, packageBinArgs); + }); +} + +_run(); diff --git a/libraries/rush-lib/src/start-pnpm.ts b/libraries/rush-lib/src/start-pnpm.ts new file mode 100644 index 00000000000..12e8fb46bb7 --- /dev/null +++ b/libraries/rush-lib/src/start-pnpm.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 { Rush } from './api/Rush'; + +Rush.launchRushPnpm(Rush.version, { isManaged: false }); diff --git a/libraries/rush-lib/src/start.ts b/libraries/rush-lib/src/start.ts new file mode 100644 index 00000000000..27c4e17d3b6 --- /dev/null +++ b/libraries/rush-lib/src/start.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 { 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/startx.ts b/libraries/rush-lib/src/startx.ts new file mode 100644 index 00000000000..56b39590b09 --- /dev/null +++ b/libraries/rush-lib/src/startx.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 { Rush } from './api/Rush'; + +Rush.launchRushX(Rush.version, { isManaged: false }); diff --git a/libraries/rush-lib/src/utilities/AsyncRecycler.ts b/libraries/rush-lib/src/utilities/AsyncRecycler.ts new file mode 100644 index 00000000000..bfb58a81c4f --- /dev/null +++ b/libraries/rush-lib/src/utilities/AsyncRecycler.ts @@ -0,0 +1,215 @@ +// 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 'node:child_process'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +import { Text, Path, FileSystem, type FolderItem } from '@rushstack/node-core-library'; + +import { Utilities } from './Utilities'; + +/** + * For deleting large folders, AsyncRecycler is significantly faster than Utilities.dangerouslyDeletePath(). + * It works by moving one or more folders into a temporary "recycler" folder, and then launches a separate + * background process to recursively delete that folder. + */ +export class AsyncRecycler { + private _movedFolderCount: number; + private _deleting: boolean; + private _prefix: string; + + /** + * The full path of the recycler folder. + * Example: `C:\MyRepo\common\rush-recycler` + */ + public readonly recyclerFolder: string; + + public constructor(recyclerFolder: string) { + this.recyclerFolder = path.resolve(recyclerFolder); + this._movedFolderCount = 0; + this._deleting = false; + this._prefix = `${Date.now()}`; + } + + /** + * Synchronously moves the specified folder into the recycler folder. If the specified folder + * does not exist, then no operation is performed. After calling this function one or more times, + * deleteAll() must be called to actually delete the contents of the recycler folder. + */ + public moveFolder(folderPath: string): void { + if (this._deleting) { + throw new Error('AsyncRecycler.moveFolder() must not be called after deleteAll() has started'); + } + + if (Path.isUnder(this.recyclerFolder, folderPath)) { + throw new Error('AsyncRecycler.moveFolder() cannot be called on a parent of the recycler folder'); + } + + if (!FileSystem.exists(folderPath)) { + return; + } + + ++this._movedFolderCount; + + // We need to do a simple "fs.renameSync" here, however if the folder we're trying to rename + // has a lock, or if its destination container doesn't exist yet, + // then there seems to be some OS process (virus scanner?) that holds + // a lock on the folder for a split second, which causes renameSync to + // fail. To workaround that, retry for up to 7 seconds before giving up. + const maxWaitTimeMs: number = 7 * 1000; + + Utilities.createFolderWithRetry(this.recyclerFolder); + + Utilities.retryUntilTimeout( + () => this._renameOrRecurseInFolder(folderPath), + maxWaitTimeMs, + (e) => + new Error(`Error: ${e}\nOften this is caused by a file lock from a process like the virus scanner.`), + 'recycleFolder' + ); + } + + /** + * This deletes all items under the specified folder, except for the items in the membersToExclude. + * To be conservative, a case-insensitive comparison is used for membersToExclude. + * The membersToExclude must be file/folder names that would match readdir() results. + */ + public moveAllItemsInFolder(folderPath: string, membersToExclude?: ReadonlyArray): void { + const resolvedFolderPath: string = path.resolve(folderPath); + + const excludeSet: Set = new Set((membersToExclude || []).map((x) => x.toUpperCase())); + + for (const dirent of FileSystem.readFolderItems(resolvedFolderPath)) { + const normalizedMemberName: string = dirent.name.toUpperCase(); + if (!excludeSet.has(normalizedMemberName)) { + const absolutePath: string = path.resolve(folderPath, dirent.name); + if (dirent.isDirectory()) { + this._renameOrRecurseInFolder(absolutePath); + } else { + FileSystem.deleteFile(absolutePath); + } + } + } + } + + /** + * Starts an asynchronous process to delete the recycler folder. Deleting will continue + * even if the current Node.js process is killed. + * + * NOTE: To avoid spawning multiple instances of the same command, moveFolder() + * MUST NOT be called again after deleteAll() has started. + */ + public async startDeleteAllAsync(): Promise { + if (this._deleting) { + throw new Error( + `${AsyncRecycler.name}.${this.startDeleteAllAsync.name}() must not be called more than once` + ); + } + + this._deleting = true; + + if (this._movedFolderCount === 0) { + // Nothing to do + return; + } + + // Asynchronously delete the folder contents. + let command: string; + let args: string[]; + + const options: child_process.SpawnOptions = { + detached: true, + // The child won't stay alive unless we detach its stdio + stdio: 'ignore' + }; + + if (os.platform() === 'win32') { + // PowerShell.exe doesn't work with a detached console, so we need cmd.exe to create + // the new console for us. + command = 'cmd.exe'; + + // In PowerShell single-quote literals, single quotes are escaped by doubling them + const escapedRecyclerFolder: string = Text.replaceAll(this.recyclerFolder, "'", "''"); + + // As of PowerShell 3.0, the "\\?" prefix can be used for paths that exceed MAX_PATH. + // (This prefix does not seem to work for cmd.exe's "rd" command.) + args = [ + '/c', + '"' + + 'PowerShell.exe -Version 3.0 -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -Command' + + ` Get-ChildItem -Force '${escapedRecyclerFolder}'` + + // The "^|" here prevents cmd.exe from interpreting the "|" symbol + ` ^| ForEach ($_) { Remove-Item -ErrorAction Ignore -Force -Recurse "\\\\?\\$($_.FullName)" }` + + '"' + ]; + + options.windowsVerbatimArguments = true; + } else { + command = 'rm'; + args = ['-rf']; + + let pathCount: number = 0; + + let folderItemNames: string[] = []; + try { + folderItemNames = await FileSystem.readFolderItemNamesAsync(this.recyclerFolder); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + // child_process.spawn() doesn't expand wildcards. To be safe, we will do it manually + // rather than rely on an unknown shell. + for (const filename of folderItemNames) { + // The "." and ".." are supposed to be excluded, but let's be safe + if (filename !== '.' && filename !== '..') { + args.push(path.join(this.recyclerFolder, filename)); + ++pathCount; + } + } + + if (pathCount === 0) { + // Nothing to do + return; + } + } + + const process: child_process.ChildProcess = child_process.spawn(command, args, options); + + // The child won't stay alive unless we unlink it from the parent process + process.unref(); + } + + private _renameOrRecurseInFolder(folderPath: string): void { + const ordinal: number = this._movedFolderCount++; + const targetDir: string = `${this.recyclerFolder}/${this._prefix}_${ordinal}`; + try { + fs.renameSync(folderPath, targetDir); + return; + } catch (err) { + if (FileSystem.isNotExistError(err)) { + return; + } + + if (err.code !== 'EPERM') { + throw err; + } + } + + const children: FolderItem[] = FileSystem.readFolderItems(folderPath); + for (const child of children) { + const absoluteChild: string = `${folderPath}/${child.name}`; + if (child.isDirectory()) { + this._renameOrRecurseInFolder(absoluteChild); + } else { + FileSystem.deleteFile(absoluteChild); + } + } + + // Yes, this is a folder. The API deletes empty folders, too. + FileSystem.deleteFile(folderPath); + } +} diff --git a/libraries/rush-lib/src/utilities/CollatedTerminalProvider.ts b/libraries/rush-lib/src/utilities/CollatedTerminalProvider.ts new file mode 100644 index 00000000000..d83701011c3 --- /dev/null +++ b/libraries/rush-lib/src/utilities/CollatedTerminalProvider.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 type { CollatedTerminal } from '@rushstack/stream-collator'; +import { type ITerminalProvider, TerminalProviderSeverity, TerminalChunkKind } from '@rushstack/terminal'; + +export interface ICollatedTerminalProviderOptions { + debugEnabled: boolean; +} + +export class CollatedTerminalProvider implements ITerminalProvider { + private readonly _collatedTerminal: CollatedTerminal; + private _hasErrors: boolean = false; + private _hasWarnings: boolean = false; + private _debugEnabled: boolean = false; + + public readonly supportsColor: boolean = true; + public readonly eolCharacter: string = '\n'; + + public get hasErrors(): boolean { + return this._hasErrors; + } + + public get hasWarnings(): boolean { + return this._hasWarnings; + } + + public constructor( + collatedTerminal: CollatedTerminal, + options?: Partial + ) { + this._collatedTerminal = collatedTerminal; + this._debugEnabled = !!options?.debugEnabled; + } + + public write(data: string, severity: TerminalProviderSeverity): void { + switch (severity) { + case TerminalProviderSeverity.log: + case TerminalProviderSeverity.verbose: { + // Unlike the basic ConsoleTerminalProvider, verbose messages are always passed + // to stdout -- by convention the user-controlled build script output is sent + // to verbose, and will be routed to a variety of other providers in the ProjectBuilder. + this._collatedTerminal.writeChunk({ text: data, kind: TerminalChunkKind.Stdout }); + break; + } + + case TerminalProviderSeverity.debug: { + // Similar to the basic ConsoleTerminalProvider, debug messages are discarded + // unless they are explicitly enabled. + if (this._debugEnabled) { + this._collatedTerminal.writeChunk({ text: data, kind: TerminalChunkKind.Stdout }); + } + break; + } + + case TerminalProviderSeverity.error: { + this._collatedTerminal.writeChunk({ text: data, kind: TerminalChunkKind.Stderr }); + this._hasErrors = true; + break; + } + + case TerminalProviderSeverity.warning: { + this._collatedTerminal.writeChunk({ text: data, kind: TerminalChunkKind.Stderr }); + this._hasWarnings = true; + break; + } + + default: { + throw new Error(`Unexpected severity: ${severity}`); + } + } + } +} 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 new file mode 100644 index 00000000000..9e5d9bf1c06 --- /dev/null +++ b/libraries/rush-lib/src/utilities/InteractiveUpgradeUI.ts @@ -0,0 +1,222 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// UI Code, Table creation, and choice layout leveraged from npm-check +// 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 { AnsiEscape, Colorize } from '@rushstack/terminal'; +import type { INpmCheckPackageSummary } from '@rushstack/npm-check-fork'; + +export interface IUIGroup { + title: string; + bgColor?: string; + filter: { + mismatch?: boolean; + bump?: undefined | 'major' | 'minor' | 'patch' | 'nonSemver'; + notInstalled?: boolean; + }; +} + +export interface IDepsToUpgradeAnswers { + packages: INpmCheckPackageSummary[]; +} + +export interface IUpgradeInteractiveDepChoice { + value: INpmCheckPackageSummary; + name: string | string[]; + short: string; +} + +type ChoiceTable = (Separator | IUpgradeInteractiveDepChoice | boolean | undefined)[] | undefined; + +function greenUnderlineBold(text: string): string { + return Colorize.underline(Colorize.bold(Colorize.green(text))); +} + +function yellowUnderlineBold(text: string): string { + return Colorize.underline(Colorize.bold(Colorize.yellow(text))); +} + +function redUnderlineBold(text: string): string { + return Colorize.underline(Colorize.bold(Colorize.red(text))); +} + +function magentaUnderlineBold(text: string): string { + return Colorize.underline(Colorize.bold(Colorize.magenta(text))); +} + +export const UI_GROUPS: IUIGroup[] = [ + { + title: greenUnderlineBold('Update package.json to match version installed.'), + filter: { mismatch: true, bump: undefined } + }, + { + title: `${greenUnderlineBold('Missing.')} ${Colorize.green('You probably want these.')}`, + filter: { notInstalled: true, bump: undefined } + }, + { + title: `${greenUnderlineBold('Patch Update')} ${Colorize.green('Backwards-compatible bug fixes.')}`, + filter: { bump: 'patch' } + }, + { + title: `${yellowUnderlineBold('Minor Update')} ${Colorize.yellow('New backwards-compatible features.')}`, + bgColor: 'yellow', + filter: { bump: 'minor' } + }, + { + title: `${redUnderlineBold('Major Update')} ${Colorize.red( + 'Potentially breaking API changes. Use caution.' + )}`, + filter: { bump: 'major' } + }, + { + title: `${magentaUnderlineBold('Non-Semver')} ${Colorize.magenta('Versions less than 1.0.0, caution.')}`, + filter: { bump: 'nonSemver' } + } +]; + +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); + const type: string = dep.devDependency ? Colorize.green(' devDep') : ''; + const missing: string = dep.notInstalled ? Colorize.red(' missing') : ''; + const homepage: string = dep.homepage ? Colorize.blue(Colorize.underline(dep.homepage)) : ''; + + return [ + name + type + missing, + installed, + installed && '>', + Colorize.bold(dep.latest || ''), + dep.latest ? homepage : getErrorDep(dep) + ]; +} + +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: INpmCheckPackageSummary): IUpgradeInteractiveDepChoice | boolean | Separator { + if (!dep.mismatch && !dep.bump && !dep.notInstalled) { + return false; + } + + return { + value: dep, + name: label(dep), + short: short(dep) + }; +} + +function unselectable(options?: { title: string }): Separator { + return new inquirer.Separator(AnsiEscape.removeCodes(options ? options.title : '')); +} + +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: 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] + }); + + for (const choice of choices) { + if (typeof choice === 'object' && 'name' in choice) { + cliTable.push(choice.name); + } + } + + 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]; + } + } + + if (choices.length > 0) { + choices.unshift(unselectable(options)); + choices.unshift(unselectable()); + return choices; + } +} + +export const upgradeInteractive = async (pkgs: INpmCheckPackageSummary[]): Promise => { + const choicesGrouped: ChoiceTable[] = UI_GROUPS.map((group) => createChoices(pkgs, group)).filter(Boolean); + + const choices: ChoiceTable = []; + for (const choiceGroup of choicesGrouped) { + if (choiceGroup) { + choices.push(...choiceGroup); + } + } + + if (!choices.length) { + // eslint-disable-next-line no-console + console.log('All dependencies are up to date!'); + return { packages: [] }; + } + + 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; + + return answers; +}; diff --git a/libraries/rush-lib/src/utilities/Npm.ts b/libraries/rush-lib/src/utilities/Npm.ts new file mode 100644 index 00000000000..f023e188e67 --- /dev/null +++ b/libraries/rush-lib/src/utilities/Npm.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 semver from 'semver'; + +import { Utilities } from './Utilities'; + +export class Npm { + public static async getPublishedVersionsAsync( + packageName: string, + cwd: string, + env: { [key: string]: string | undefined }, + extraArgs: string[] = [] + ): Promise { + const versions: string[] = []; + try { + const packageTime: string = await Utilities.executeCommandAndCaptureOutputAsync( + 'npm', + ['view', packageName, 'time', '--json', ...extraArgs], + cwd, + env, + true + ); + if (packageTime && packageTime !== '') { + Object.keys(JSON.parse(packageTime)).forEach((v) => { + if (semver.valid(v)) { + versions.push(v); + } + }); + } else { + // 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', + ['view', packageName, 'versions', '--json', ...extraArgs], + cwd, + env, + true + ); + if (packageVersions && packageVersions.length > 0) { + const parsedPackageVersions: string | string[] = JSON.parse(packageVersions); + // NPM <= 6 always returns an array, NPM >= 7 returns a string if the package has only one version available + (Array.isArray(parsedPackageVersions) ? parsedPackageVersions : [parsedPackageVersions]).forEach( + (version: string) => { + versions.push(version); + } + ); + } else { + // eslint-disable-next-line no-console + console.log(`No version is found for ${packageName}`); + } + } + } catch (e) { + const error: Error = e; + if (['E404', 'npm ERR! 404'].some((check) => error.message.indexOf(check))) { + // eslint-disable-next-line no-console + console.log(`Package ${packageName} does not exist in the registry.`); + } else { + // eslint-disable-next-line no-console + console.log(`Failed to get NPM information about ${packageName}.`); + throw error; + } + } + return versions; + } +} diff --git a/libraries/rush-lib/src/utilities/NullTerminalProvider.ts b/libraries/rush-lib/src/utilities/NullTerminalProvider.ts new file mode 100644 index 00000000000..675e75e29db --- /dev/null +++ b/libraries/rush-lib/src/utilities/NullTerminalProvider.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. + +import type { ITerminalProvider } from '@rushstack/terminal'; + +/** + * A terminal provider like /dev/null + */ +export class NullTerminalProvider implements ITerminalProvider { + public supportsColor: boolean = false; + public eolCharacter: string = '\n'; + public write(): void {} +} diff --git a/libraries/rush-lib/src/utilities/OverlappingPathAnalyzer.ts b/libraries/rush-lib/src/utilities/OverlappingPathAnalyzer.ts new file mode 100644 index 00000000000..826a5e7255a --- /dev/null +++ b/libraries/rush-lib/src/utilities/OverlappingPathAnalyzer.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +interface IPathTreeNode { + encounteredLabels: Set; + label?: TLabel; + paths: Record>; +} + +/** + * This is a tool for determining if a set of paths overlap. For example 'lib' and 'lib/x' overlap, + * 'lib/x' and 'lib/y' do not. + */ +export class OverlappingPathAnalyzer { + private readonly _root: IPathTreeNode = { + encounteredLabels: new Set(), + paths: {} + }; + + public addPathAndGetFirstEncounteredLabels(path: string, label: TLabel): TLabel[] | undefined { + const pathParts: string[] = path.split('/'); + let currentNode: IPathTreeNode = this._root; + let currentNodeIsNew: boolean = false; + let labelWasAlreadyPresentInCurrentNode: boolean = false; + for (const pathPart of pathParts) { + if (pathPart === '') { + continue; + } + + if (currentNode.label) { + return [currentNode.label]; + } + + if (!currentNode.paths[pathPart]) { + currentNodeIsNew = true; + currentNode = currentNode.paths[pathPart] = { + encounteredLabels: new Set(), + paths: {} + }; + } else { + currentNodeIsNew = false; + currentNode = currentNode.paths[pathPart]; + } + + labelWasAlreadyPresentInCurrentNode = currentNode.encounteredLabels.has(label); + if (!labelWasAlreadyPresentInCurrentNode) { + currentNode.encounteredLabels.add(label); + } + } + + if (currentNodeIsNew) { + currentNode.label = label; + return undefined; + } else if (labelWasAlreadyPresentInCurrentNode) { + return Array.from(currentNode.encounteredLabels); + } else { + const clonedEncounteredLabels: Set = new Set(currentNode.encounteredLabels); + clonedEncounteredLabels.delete(label); + return Array.from(clonedEncounteredLabels); + } + } +} diff --git a/libraries/rush-lib/src/utilities/PathConstants.ts b/libraries/rush-lib/src/utilities/PathConstants.ts new file mode 100644 index 00000000000..632bce8a6ae --- /dev/null +++ b/libraries/rush-lib/src/utilities/PathConstants.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 { PackageJsonLookup } from '@rushstack/node-core-library'; + +/** + * The currently-executing rush-lib package's root folder path. + */ +export const rushLibFolderRootPath: string = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname)!; + +/** + * The path to the assets folder in rush-lib. + */ +export const assetsFolderPath: string = `${rushLibFolderRootPath}/assets`; + +/** + * The folder name ("scripts") where the scripts in rush-lib are built. + */ +export const scriptsFolderName: string = 'scripts'; + +export const pnpmfileShimFilename: string = 'PnpmfileShim.js'; +export const subspacePnpmfileShimFilename: string = 'SubspaceGlobalPnpmfileShim.js'; +export const installRunScriptFilename: string = 'install-run.js'; +export const installRunRushScriptFilename: string = 'install-run-rush.js'; +export const installRunRushxScriptFilename: string = 'install-run-rushx.js'; +export const installRunRushPnpmScriptFilename: string = 'install-run-rush-pnpm.js'; + +/** + * The path to the scripts folder in rush-lib/dist. + */ +export const scriptsFolderPath: string = `${rushLibFolderRootPath}/dist/${scriptsFolderName}`; diff --git a/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts b/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts new file mode 100644 index 00000000000..1c443374339 --- /dev/null +++ b/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts @@ -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. + +import { + type ILogMessageCallbackOptions, + LogMessageIdentifier, + type LogMessageDetails, + LogMessageKind +} from 'pnpm-sync-lib'; + +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import { RushConstants } from '../logic/RushConstants'; + +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'); + } + + public static processLogMessage(options: ILogMessageCallbackOptions, terminal: ITerminal): void { + const message: string = options.message; + const details: LogMessageDetails = options.details; + + // Special formatting for interested messages + switch (details.messageIdentifier) { + case LogMessageIdentifier.PREPARE_FINISHING: + terminal.writeVerboseLine( + PnpmSyncUtilities._addLinePrefix( + `Regenerated ${RushConstants.pnpmSyncFilename} in ${Math.round(details.executionTimeInMs)} ms` + ) + ); + return; + + case LogMessageIdentifier.COPY_FINISHING: + { + const customMessage: string = + `Synced ${details.fileCount} ` + + (details.fileCount === 1 ? 'file' : 'files') + + ` in ${Math.round(details.executionTimeInMs)} ms`; + + terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(customMessage)); + } + return; + + case LogMessageIdentifier.PREPARE_REPLACING_FILE: + { + const customMessage: string = + `Expecting ${RushConstants.pnpmSyncFilename} version ${details.expectedVersion}, ` + + `but found version ${details.actualVersion}`; + + terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(message)); + terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(customMessage)); + } + return; + + case LogMessageIdentifier.COPY_ERROR_INCOMPATIBLE_SYNC_FILE: { + terminal.writeErrorLine( + PnpmSyncUtilities._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 ${RushConstants.pnpmSyncFilename} version ${details.expectedVersion}, ` + + `but found version ${details.actualVersion}\n` + + `Affected folder: ${details.pnpmSyncJsonPath}` + ) + ); + throw new AlreadyReportedError(); + } + } + + // Default handling for other messages + switch (options.messageKind) { + case LogMessageKind.ERROR: + terminal.writeErrorLine(Colorize.red('ERROR: pnpm-sync: ' + message)); + throw new AlreadyReportedError(); + + case LogMessageKind.WARNING: + terminal.writeWarningLine(Colorize.yellow('pnpm-sync: ' + message)); + return; + + case LogMessageKind.INFO: + case LogMessageKind.VERBOSE: + terminal.writeDebugLine(PnpmSyncUtilities._addLinePrefix(message)); + return; + } + } +} diff --git a/libraries/rush-lib/src/utilities/RushAlerts.ts b/libraries/rush-lib/src/utilities/RushAlerts.ts new file mode 100644 index 00000000000..19a0a0606b9 --- /dev/null +++ b/libraries/rush-lib/src/utilities/RushAlerts.ts @@ -0,0 +1,423 @@ +// 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 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: ITerminal; + rushJsonFolder: string; + rushAlertsConfig: IRushAlertsConfig | undefined; + rushAlertsState: IRushAlertsState | undefined; + rushAlertsConfigFilePath: string; + rushAlertsStateFilePath: string; +} + +interface IRushAlertsConfig { + alerts: Array; +} +interface IRushAlertsConfigEntry { + alertId: string; + title: string; + message: Array; + detailsUrl: string; + startTime: string; + endTime: string; + conditionScript?: string; + priority?: AlertPriority; + maximumDisplayInterval?: AlertDisplayInterval; +} +interface IRushAlertsState { + [alertId: string]: IRushAlertStateEntry; +} +interface IRushAlertStateEntry { + lastDisplayTime?: string; + snooze?: boolean; + snoozeEndTime?: string; +} + +type AlertStatus = 'active' | 'inactive' | 'snoozed'; + +const enum AlertDisplayInterval { + ALWAYS = 'always', + MONTHLY = 'monthly', + WEEKLY = 'weekly', + DAILY = 'daily', + HOURLY = 'hourly' +} + +const enum AlertPriority { + HIGH = 'high', + NORMAL = 'normal', + LOW = 'low' +} + +export class RushAlerts { + private readonly _terminal: ITerminal; + + private readonly _rushAlertsConfig: IRushAlertsConfig | undefined; + private readonly _rushAlertsState: IRushAlertsState; + + private readonly _rushJsonFolder: string; + public readonly rushAlertsStateFilePath: string; + public readonly rushAlertsConfigFilePath: string; + + public static readonly ALERT_PRIORITY: string[] = [ + AlertPriority.HIGH, + AlertPriority.NORMAL, + AlertPriority.LOW + ]; + public static readonly alertDisplayIntervalDurations: Map = new Map([ + [AlertDisplayInterval.ALWAYS, -1], + [AlertDisplayInterval.MONTHLY, 1000 * 60 * 60 * 24 * 30], + [AlertDisplayInterval.WEEKLY, 1000 * 60 * 60 * 24 * 7], + [AlertDisplayInterval.DAILY, 1000 * 60 * 60 * 24], + [AlertDisplayInterval.HOURLY, 1000 * 60 * 60] + ]); + // 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_ACTION_NAME, + 'remove', + 'update', + 'install', + 'build', + 'list', + 'version' + ]; + + 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 ?? {}; + } + + public static async loadFromConfigurationAsync( + rushConfiguration: RushConfiguration, + terminal: ITerminal + ): Promise { + const rushAlertsStateFilePath: string = `${rushConfiguration.commonTempFolder}/${RushConstants.rushAlertsConfigFilename}`; + const rushAlertsConfigFilePath: string = `${rushConfiguration.commonRushConfigFolder}/${RushConstants.rushAlertsConfigFilename}`; + const rushJsonFolder: string = rushConfiguration.rushJsonFolder; + + const [isRushAlertsStateFileExists, isRushAlertsConfigFileExists] = await Promise.all([ + FileSystem.existsAsync(rushAlertsStateFilePath), + FileSystem.existsAsync(rushAlertsConfigFilePath) + ]); + + const [rushAlertsConfig, rushAlertsState] = await Promise.all([ + isRushAlertsConfigFileExists + ? JsonFile.loadAndValidateAsync( + rushAlertsConfigFilePath, + JsonSchema.fromLoadedObject(rushAlertsSchemaJson) + ) + : undefined, + isRushAlertsStateFileExists + ? JsonFile.loadAsync(rushAlertsStateFilePath, { jsonSyntax: JsonSyntax.JsonWithComments }) + : undefined + ]); + + return new RushAlerts({ + terminal, + rushAlertsStateFilePath, + rushAlertsConfigFilePath, + rushJsonFolder, + rushAlertsConfig, + rushAlertsState + }); + } + + private _ensureAlertStateIsUpToDate(): void { + // ensure `temp/rush-alerts.json` is up to date + if (this._rushAlertsConfig) { + for (const alert of this._rushAlertsConfig.alerts) { + if (!(alert.alertId in this._rushAlertsState)) { + this._rushAlertsState[alert.alertId] = { + snooze: false + }; + } + } + } + } + + public async printAlertsAsync(): Promise { + if (!this._rushAlertsConfig || this._rushAlertsConfig.alerts.length === 0) return; + + this._ensureAlertStateIsUpToDate(); + + this._terminal.writeLine(); + + const alert: IRushAlertsConfigEntry | undefined = await this._selectAlertByPriorityAsync(); + if (alert) { + this._printMessageInBoxStyle(alert); + this._rushAlertsState[alert.alertId].lastDisplayTime = new Date().toISOString(); + } + + await this._writeRushAlertStateAsync(); + } + + public async printAllAlertsAsync(): Promise { + const allAlerts: IRushAlertsConfigEntry[] = this._rushAlertsConfig?.alerts ?? []; + + const activeAlerts: IRushAlertsConfigEntry[] = []; + const snoozedAlerts: IRushAlertsConfigEntry[] = []; + const inactiveAlerts: IRushAlertsConfigEntry[] = []; + + await Promise.all( + allAlerts.map(async (alert) => { + const isAlertValid: boolean = await this._isAlertValidAsync(alert); + const alertState: IRushAlertStateEntry = this._rushAlertsState[alert.alertId]; + + if (!isAlertValid) { + inactiveAlerts.push(alert); + return; + } + + if (this._isSnoozing(alertState)) { + snoozedAlerts.push(alert); + return; + } + + activeAlerts.push(alert); + }) + ); + + this._printAlerts(activeAlerts, 'active'); + this._printAlerts(snoozedAlerts, 'snoozed'); + this._printAlerts(inactiveAlerts, 'inactive'); + } + + private _printAlerts(alerts: IRushAlertsConfigEntry[], status: AlertStatus): void { + if (alerts.length === 0) return; + switch (status) { + case 'active': + case 'inactive': + this._terminal.writeLine(Colorize.yellow(`The following alerts are currently ${status}:`)); + break; + case 'snoozed': + this._terminal.writeLine(Colorize.yellow('The following alerts are currently active but snoozed:')); + break; + } + alerts.forEach(({ title }) => { + this._terminal.writeLine(Colorize.green(`"${title}"`)); + }); + this._terminal.writeLine(); + } + + public async snoozeAlertsByAlertIdAsync(alertId: string, forever: boolean = false): Promise { + this._ensureAlertStateIsUpToDate(); + if (forever) { + this._rushAlertsState[alertId].snooze = true; + } else { + this._rushAlertsState[alertId].snooze = true; + const snoozeEndTime: Date = new Date(); + snoozeEndTime.setDate(snoozeEndTime.getDate() + 7); + this._rushAlertsState[alertId].snoozeEndTime = snoozeEndTime.toISOString(); + } + await this._writeRushAlertStateAsync(); + } + + private async _selectAlertByPriorityAsync(): Promise { + const alerts: Array = this._rushAlertsConfig!.alerts; + const alertsState: IRushAlertsState = this._rushAlertsState; + + const needDisplayAlerts: Array = ( + await Promise.all( + alerts.map(async (alert) => { + const isAlertValid: boolean = await this._isAlertValidAsync(alert); + const alertState: IRushAlertStateEntry = alertsState[alert.alertId]; + if ( + isAlertValid && + !this._isSnoozing(alertState) && + (!alertState.lastDisplayTime || + Number(new Date()) - Number(new Date(alertState.lastDisplayTime)) > + RushAlerts.alertDisplayIntervalDurations.get( + alert.maximumDisplayInterval ?? AlertDisplayInterval.ALWAYS + )!) + ) { + return alert; + } + }) + ) + ).filter((alert) => alert !== undefined) as Array; + + const alertsSortedByPriority: IRushAlertsConfigEntry[] = needDisplayAlerts.sort((a, b) => { + return ( + RushAlerts.ALERT_PRIORITY.indexOf(a.priority ?? AlertPriority.NORMAL) - + RushAlerts.ALERT_PRIORITY.indexOf(b.priority ?? AlertPriority.NORMAL) + ); + }); + 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) && + (!alertState.snoozeEndTime || Number(new Date()) < Number(new Date(alertState.snoozeEndTime))) + ); + } + + private async _isAlertValidAsync(alert: IRushAlertsConfigEntry): Promise { + const timeNow: Date = new Date(); + + if (alert.startTime) { + const startTime: Date = RushAlerts._parseDate(alert.startTime); + if (timeNow < startTime) { + return false; + } + } + + if (alert.endTime) { + const endTime: Date = RushAlerts._parseDate(alert.endTime); + if (timeNow > endTime) { + return false; + } + } + + const conditionScript: string | undefined = alert.conditionScript; + if (conditionScript) { + // "(OPTIONAL) The filename of a script that determines whether this alert can be shown, + // found in the "common/config/rush/alert-scripts" folder." ... "To ensure up-to-date alerts, Rush + // may fetch and checkout the "common/config/rush-alerts" folder in an unpredictable temporary + // path. Therefore, your script should avoid importing dependencies from outside its folder, + // generally be kept as simple and reliable and quick as possible." + if (conditionScript.indexOf('/') >= 0 || conditionScript.indexOf('\\') >= 0) { + throw new Error( + `The rush-alerts.json file contains a "conditionScript" that is not inside the "alert-scripts" folder: ` + + JSON.stringify(conditionScript) + ); + } + const conditionScriptPath: string = `${this._rushJsonFolder}/common/config/rush/alert-scripts/${conditionScript}`; + if (!(await FileSystem.existsAsync(conditionScriptPath))) { + throw new Error( + 'The "conditionScript" field in rush-alerts.json refers to a nonexistent file:\n' + + conditionScriptPath + ); + } + + this._terminal.writeDebugLine(`Invoking condition script "${conditionScript}" from rush-alerts.json`); + const startTimemark: number = performance.now(); + + interface IAlertsConditionScriptModule { + canShowAlert(): boolean; + } + + let conditionScriptModule: IAlertsConditionScriptModule; + try { + conditionScriptModule = require(conditionScriptPath); + + if (typeof conditionScriptModule.canShowAlert !== 'function') { + throw new Error('The "canShowAlert" module export is missing'); + } + } catch (e) { + throw new Error( + `Error loading condition script "${conditionScript}" from rush-alerts.json:\n${e.stack}` + ); + } + + const oldCwd: string = process.cwd(); + + let conditionResult: boolean; + try { + // "Rush will invoke this script with the working directory set to the monorepo root folder, + // with no guarantee that `rush install` has been run." + process.chdir(this._rushJsonFolder); + conditionResult = conditionScriptModule.canShowAlert(); + + if (typeof conditionResult !== 'boolean') { + throw new Error('canShowAlert() did not return a boolean value'); + } + } catch (e) { + throw new Error( + `Error invoking condition script "${conditionScript}" from rush-alerts.json:\n${e.stack}` + ); + } finally { + process.chdir(oldCwd); + } + + const totalMs: number = performance.now() - startTimemark; + this._terminal.writeDebugLine( + `Invoked conditionScript "${conditionScript}"` + + ` in ${Math.round(totalMs)} ms with result "${conditionResult}"` + ); + + if (!conditionResult) { + return false; + } + } + return true; + } + + private _printMessageInBoxStyle(alert: IRushAlertsConfigEntry): void { + const boxTitle: string = alert.title.toUpperCase(); + + const boxMessage: string = typeof alert.message === 'string' ? alert.message : alert.message.join(''); + + const boxDetails: string = alert.detailsUrl ? 'Details: ' + alert.detailsUrl : ''; + + // ...minus the padding. + const PADDING: number = '╔══╗'.length; + + // Try to make it wide enough to fit the (unwrapped) strings... + let lineLength: number = Math.max(boxTitle.length, boxMessage.length, boxDetails.length); + + // ...but don't exceed the console width, and also keep it under 80... + lineLength = Math.min(lineLength, (PrintUtilities.getConsoleWidth() ?? 80) - PADDING, 80 - PADDING); + + // ...and the width needs to be at least 40 characters... + lineLength = Math.max(lineLength, 40 - PADDING); + + const lines: string[] = [ + ...PrintUtilities.wrapWordsToLines(boxTitle, lineLength).map((x) => + Colorize.bold(x.padEnd(lineLength)) + ), + '', + ...PrintUtilities.wrapWordsToLines(boxMessage, lineLength).map((x) => x.padEnd(lineLength)) + ]; + if (boxDetails) { + lines.push( + '', + ...PrintUtilities.wrapWordsToLines(boxDetails, lineLength).map((x) => + Colorize.cyan(x.padEnd(lineLength)) + ) + ); + } + + // Print the box + this._terminal.writeLine('╔═' + '═'.repeat(lineLength) + '═╗'); + for (const line of lines) { + this._terminal.writeLine(`║ ${line.padEnd(lineLength)} ║`); + } + this._terminal.writeLine('╚═' + '═'.repeat(lineLength) + '═╝'); + this._terminal.writeLine(`To stop seeing this alert, run "rush alert --snooze ${alert.alertId}"`); + } + + private async _writeRushAlertStateAsync(): Promise { + await JsonFile.saveAsync(this._rushAlertsState, this.rushAlertsStateFilePath, { + ignoreUndefinedValues: true, + headerComment: '// THIS FILE IS MACHINE-GENERATED -- DO NOT MODIFY', + jsonSyntax: JsonSyntax.JsonWithComments + }); + } +} diff --git a/libraries/rush-lib/src/utilities/SetRushLibPath.ts b/libraries/rush-lib/src/utilities/SetRushLibPath.ts new file mode 100644 index 00000000000..ffc527ff22e --- /dev/null +++ b/libraries/rush-lib/src/utilities/SetRushLibPath.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. + +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; + +const rootDir: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); +if (rootDir) { + // Route to the 'main' field of package.json + const rushLibIndex: string = require.resolve(rootDir, { paths: [] }); + process.env[EnvironmentVariableNames._RUSH_LIB_PATH] = rushLibIndex; +} diff --git a/libraries/rush-lib/src/utilities/Stopwatch.ts b/libraries/rush-lib/src/utilities/Stopwatch.ts new file mode 100644 index 00000000000..b4e55df8e44 --- /dev/null +++ b/libraries/rush-lib/src/utilities/Stopwatch.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. + +import { Utilities } from './Utilities'; + +/** + * Used with the Stopwatch class. + */ +export enum StopwatchState { + Stopped = 1, + Started = 2 +} + +/** + * Represents a readonly view of a `Stopwatch`. + * @beta + */ +export interface IStopwatchResult { + /** + * Displays how long the stopwatch has been executing in a human readable format. + */ + toString(): string; + /** + * Get the duration in seconds. + */ + get duration(): number; + /** + * Return the start time of the most recent stopwatch run. + */ + get startTime(): number | undefined; + /** + * Return the end time of the most recent stopwatch run. + */ + get endTime(): number | undefined; +} + +/** + * Represents a typical timer/stopwatch which keeps track + * of elapsed time in between two events. + */ +export class Stopwatch implements IStopwatchResult { + private _startTime: number | undefined; + private _endTime: number | undefined; + private _state: StopwatchState; + + private _getTime: () => number; + + public constructor(getTime: () => number = Utilities.getTimeInMs) { + this._startTime = undefined; + this._endTime = undefined; + this._getTime = getTime; + 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 get state(): StopwatchState { + return this._state; + } + + /** + * Starts the stopwatch. Note that if end() has been called, + * reset() should be called before calling start() again. + */ + public start(): Stopwatch { + if (this._startTime !== undefined) { + throw new Error('Call reset() before starting the Stopwatch'); + } + this._startTime = this._getTime(); + this._endTime = undefined; + this._state = StopwatchState.Started; + return this; + } + + /** + * Stops executing the stopwatch and saves the current timestamp + */ + public stop(): Stopwatch { + this._endTime = this._startTime !== undefined ? this._getTime() : undefined; + this._state = StopwatchState.Stopped; + return this; + } + + /** + * Resets all values of the stopwatch back to the original + */ + public reset(): Stopwatch { + this._endTime = this._startTime = undefined; + this._state = StopwatchState.Stopped; + return this; + } + + /** + * Displays how long the stopwatch has been executing in a human readable format. + */ + public toString(): string { + if (this._state === StopwatchState.Stopped && this._startTime === undefined) { + return '0.00 seconds (stopped)'; + } + const totalSeconds: number = this.duration; + + if (totalSeconds > 60) { + const minutes: number = Math.floor(totalSeconds / 60); + const seconds: number = totalSeconds % 60.0; + + return `${minutes.toFixed(0)} minute${minutes === 1 ? '' : 's'} ${seconds.toFixed(1)} seconds`; + } else { + return `${totalSeconds.toFixed(2)} seconds`; + } + } + + /** + * Get the duration in seconds. + */ + public get duration(): number { + if (this._startTime === undefined) { + return 0; + } + const curTime: number = this._endTime !== undefined ? this._endTime : this._getTime(); + + return (curTime - this._startTime) / 1000.0; + } + + /** + * Return the start time of the most recent stopwatch run. + */ + public get startTime(): number | undefined { + return this._startTime; + } + + /** + * Return the end time of the most recent stopwatch run. + */ + public get endTime(): number | undefined { + return this._endTime; + } +} diff --git a/libraries/rush-lib/src/utilities/TarExecutable.ts b/libraries/rush-lib/src/utilities/TarExecutable.ts new file mode 100644 index 00000000000..37bc3f4fa94 --- /dev/null +++ b/libraries/rush-lib/src/utilities/TarExecutable.ts @@ -0,0 +1,194 @@ +// 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 os from 'node:os'; +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 { RushConfigurationProject } from '../api/RushConfigurationProject'; +import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; + +export interface ITarOptionsBase { + logFilePath: string; +} + +export interface IUntarOptions extends ITarOptionsBase { + archivePath: string; + outputFolderPath: string; +} + +export interface ICreateArchiveOptions extends ITarOptionsBase { + archivePath: string; + paths: string[]; + project: RushConfigurationProject; +} + +export class TarExecutable { + private _tarExecutablePath: string; + + private constructor(tarExecutablePath: string) { + this._tarExecutablePath = tarExecutablePath; + } + + public static async tryInitializeAsync(terminal: ITerminal): Promise { + terminal.writeVerboseLine('Trying to find "tar" binary'); + const tarExecutablePath: string | undefined = + EnvironmentConfiguration.tarBinaryPath || (await TarExecutable._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); + } + } + + /** + * @returns + * The "tar" exit code + */ + public async tryUntarAsync(options: IUntarOptions): Promise { + return await this._spawnTarWithLoggingAsync( + // These parameters are chosen for compatibility with the very primitive bsdtar 3.3.2 shipped with Windows 10. + [ + // [Windows bsdtar 3.3.2] Extract: tar -x [options] [] + '-x', + // [Windows bsdtar 3.3.2] -m Don't restore modification times + '-m', + // [Windows bsdtar 3.3.2] -f Location of archive (default \\.\tape0) + '-f', + options.archivePath + ], + options.outputFolderPath, + options.logFilePath + ); + } + + /** + * @returns + * The "tar" exit code + */ + public async tryCreateArchiveFromProjectPathsAsync(options: ICreateArchiveOptions): Promise { + const { project, archivePath, paths, logFilePath } = options; + + const tarInput: string = paths.join('\n'); + + // On Windows, tar.exe will report a "Failed to clean up compressor" error if the target folder + // does not exist (GitHub #2622) + await FileSystem.ensureFolderAsync(path.dirname(archivePath)); + + const projectFolderPath: string = project.projectFolder; + const tarExitCode: number = await this._spawnTarWithLoggingAsync( + // These parameters are chosen for compatibility with the very primitive bsdtar 3.3.2 shipped with Windows 10. + [ + // [Windows bsdtar 3.3.2] -c Create + '-c', + // [Windows bsdtar 3.3.2] -f Location of archive (default \\.\tape0) + '-f', + archivePath, + // [Windows bsdtar 3.3.2] -z, -j, -J, --lzma Compress archive with gzip/bzip2/xz/lzma + '-z', + // [GNU tar 1.33] -T, --files-from=FILE get names to extract or create from FILE + // + // Windows bsdtar does not document this parameter, but seems to accept it. + '--files-from=-' + ], + projectFolderPath, + logFilePath, + tarInput + ); + + return tarExitCode; + } + + private async _spawnTarWithLoggingAsync( + args: string[], + currentWorkingDirectory: string, + logFilePath: string, + input?: string + ): Promise { + // Runs "tar" with the specified args and logs its output to the specified location. + // The log file looks like this: + // + // Windows: + // Start time: Mon Apr 19 2021 13:06:40 GMT-0700 (Pacific Daylight Time) + // Invoking "C:\WINDOWS\system32\tar.exe -x -f E:\rush-cache\d18105f7f83eb610b468be4e2421681f4a52e44d" + // + // ======= BEGIN PROCESS OUTPUT ======= + // [stdout] + // [stderr] + // ======== END PROCESS OUTPUT ======== + // + // Exited with code "0" + // + // Linux: + // Start time: Mon Apr 19 2021 13:06:40 GMT-0700 (Pacific Daylight Time) + // Invoking "/bin/tar -x -f /home/username/rush-cache/d18105f7f83eb610b468be4e2421681f4a52e44d" + // + // ======= BEGIN PROCESS OUTPUT ======= + // [stdout] + // [stderr] + // ======== END PROCESS OUTPUT ======== + // + // Exited with code "0" + + await FileSystem.ensureFolderAsync(path.dirname(logFilePath)); + const fileWriter: FileWriter = FileWriter.open(logFilePath); + fileWriter.write( + [ + `Start time: ${new Date().toString()}`, + `Invoking "${this._tarExecutablePath} ${args.join(' ')}"`, + '', + `======= BEGIN PROCESS INPUT ======`, + input || '', + '======== END PROCESS INPUT =======', + '======= BEGIN PROCESS OUTPUT =======', + '' + ].join('\n') + ); + + const childProcess: ChildProcess = Executable.spawn(this._tarExecutablePath, args, { + currentWorkingDirectory: currentWorkingDirectory + }); + + childProcess.stdout!.on('data', (chunk) => fileWriter.write(`[stdout] ${chunk}`)); + childProcess.stderr!.on('data', (chunk) => fileWriter.write(`[stderr] ${chunk}`)); + + if (input !== undefined) { + childProcess.stdin!.write(input, 'utf-8'); + childProcess.stdin!.end(); + } + + // Wait for process to exit and all streams to close + const [tarExitCode] = await events.once(childProcess, 'close'); + + fileWriter.write( + ['======== END PROCESS OUTPUT ========', '', `Exited with code "${tarExitCode}"`].join('\n') + ); + fileWriter.close(); + + 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; + } + } + } + + return Executable.tryResolve('tar'); + } +} diff --git a/libraries/rush-lib/src/utilities/Utilities.ts b/libraries/rush-lib/src/utilities/Utilities.ts new file mode 100644 index 00000000000..f339fdb5ce9 --- /dev/null +++ b/libraries/rush-lib/src/utilities/Utilities.ts @@ -0,0 +1,892 @@ +// 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 'node:child_process'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import { performance } from 'node:perf_hooks'; +import { Transform } from 'node:stream'; + +import { + JsonFile, + type IPackageJson, + FileSystem, + FileConstants, + type FileSystemStats, + SubprocessTerminator, + Executable, + type IWaitForExitResult, + 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'; + +export type UNINITIALIZED = 'UNINITIALIZED'; +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const UNINITIALIZED: UNINITIALIZED = 'UNINITIALIZED'; + +export interface IEnvironment { + // NOTE: the process.env doesn't actually support "undefined" as a value. + // If you try to assign it, it will be converted to the text string "undefined". + // But this typing is needed for reading values from the dictionary, and for + // subsets that get combined. + [environmentVariableName: string]: string | undefined; +} + +/** + * Options for {@link Utilities.executeCommandAsync}. + */ +export interface IExecuteCommandOptions { + command: string; + args: string[]; + workingDirectory: string; + environment?: IEnvironment; + suppressOutput?: boolean; + keepEnvironment?: boolean; + /** + * Note that this takes precedence over {@link IExecuteCommandOptions.suppressOutput} + */ + onStdoutStreamChunk?: (chunk: string) => string | void; + captureExitCodeAndSignal?: boolean; +} + +/** + * Options for {@link Utilities.installPackageInDirectoryAsync}. + */ +export interface IInstallPackageInDirectoryOptions { + directory: string; + packageName: string; + version: string; + tempPackageTitle: string; + maxInstallAttempts: number; + commonRushConfigFolder: string | undefined; + suppressOutput?: boolean; +} + +export interface ILifecycleCommandOptions { + /** + * The rush configuration, if the command is running in a rush repo. + */ + rushConfiguration: RushConfiguration | undefined; + + /** + * Working directory for running the command + */ + workingDirectory: string; + + /** + * The folder containing a local .npmrc, which will be used for the INIT_CWD environment variable + */ + initCwd: string; + + /** + * If true, suppress the process's output, but if there is a nonzero exit code then print stderr + */ + handleOutput: boolean; + + /** + * an existing environment to copy instead of process.env + */ + initialEnvironment?: IEnvironment; + + /** + * Options for what should be added to the PATH variable + */ + environmentPathOptions: IEnvironmentPathOptions; + + /** + * If true, attempt to establish a NodeJS IPC channel to the child process. + */ + ipc?: boolean; + + /** + * If true, wire up SubprocessTerminator to the child process. + */ + connectSubprocessTerminator?: boolean; +} + +export interface IEnvironmentPathOptions { + /** + * If true, include /node_modules/.bin in the PATH. If both this and + * {@link IEnvironmentPathOptions.includeRepoBin} are set, this path will take precedence. + */ + includeProjectBin?: boolean; + + /** + * If true, include /common/temp/node_modules/.bin in the PATH. + */ + includeRepoBin?: boolean; + + /** + * Additional folders to be prepended to the search PATH. + */ + additionalPathFolders?: string[] | undefined; +} + +export interface IDisposable { + dispose(): void; +} + +interface ICreateEnvironmentForRushCommandPathOptions extends IEnvironmentPathOptions { + rushJsonFolder: string | undefined; + projectRoot: string | undefined; + commonTempFolder: string | undefined; +} + +interface ICreateEnvironmentForRushCommandOptions { + /** + * The INIT_CWD environment variable + */ + initCwd?: string; + + /** + * an existing environment to copy instead of process.env + */ + initialEnvironment?: IEnvironment; + + /** + * Options for what should be added to the PATH variable + */ + pathOptions?: ICreateEnvironmentForRushCommandPathOptions; +} + +type OptionalKeys = { + [K in keyof T]-?: {} extends Pick ? K : never; +}[keyof T]; + +export type OptionalToUndefined = Omit> & { + [K in OptionalKeys]-?: Exclude | undefined; +}; + +type IExecuteCommandInternalOptions = Omit & { + stdio: child_process.SpawnSyncOptions['stdio']; + captureOutput: boolean; +}; + +export class Utilities { + public static syncNpmrc: typeof syncNpmrc = syncNpmrc; + + private static _homeFolder: string | undefined; + + /** + * 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 { + let homeFolder: string | undefined = Utilities._homeFolder; + if (!homeFolder) { + 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); + } + + homeFolder = path.resolve(unresolvedUserFolder); + if (!FileSystem.exists(homeFolder)) { + throw new Error(dirError); + } + + Utilities._homeFolder = homeFolder; + } + + return homeFolder; + } + + /** + * Node.js equivalent of performance.now(). + */ + public static getTimeInMs(): number { + return performance.now(); + } + + /** + * Retries a function until a timeout is reached. The function is expected to throw if it failed and + * should be retried. + */ + public static retryUntilTimeout( + fn: () => TResult, + maxWaitTimeMs: number, + getTimeoutError: (innerError: Error) => Error, + fnName: string + ): TResult { + const startTime: number = Utilities.getTimeInMs(); + let looped: boolean = false; + + let result: TResult; + for (;;) { + try { + result = fn(); + break; + } catch (e) { + looped = true; + const currentTime: number = Utilities.getTimeInMs(); + if (currentTime - startTime > maxWaitTimeMs) { + throw getTimeoutError(e as Error); + } + } + } + + if (looped) { + const currentTime: number = Utilities.getTimeInMs(); + const totalSeconds: string = ((currentTime - startTime) / 1000.0).toFixed(2); + // This logging statement isn't meaningful to the end-user. `fnName` should be updated + // to something like `operationDescription` + // eslint-disable-next-line no-console + console.log(`${fnName}() stalled for ${totalSeconds} seconds`); + } + + return result; + } + + /** + * Creates the specified folder by calling FileSystem.ensureFolder(), but using a + * retry loop to recover from temporary locks that may be held by other processes. + * If the folder already exists, no error occurs. + */ + public static createFolderWithRetry(folderName: string): void { + // Note: If a file exists with the same name, then we fall through and report + // an error. + if (Utilities.directoryExists(folderName)) { + return; + } + + // We need to do a simple "FileSystem.ensureFolder(localModulesFolder)" here, + // however if the folder we deleted above happened to contain any files, + // then there seems to be some OS process (virus scanner?) that holds + // a lock on the folder for a split second, which causes mkdirSync to + // fail. To workaround that, retry for up to 7 seconds before giving up. + const maxWaitTimeMs: number = 7 * 1000; + + return Utilities.retryUntilTimeout( + () => FileSystem.ensureFolder(folderName), + maxWaitTimeMs, + (e) => + new Error( + `Error: ${e}\nOften this is caused by a file lock ` + + 'from a process such as your text editor, command prompt, ' + + 'or a filesystem watcher.' + ), + 'createFolderWithRetry' + ); + } + + /** + * Determines if a path points to a directory and that it exists. + */ + public static directoryExists(directoryPath: string): boolean { + let exists: boolean = false; + + try { + const lstat: FileSystemStats = FileSystem.getLinkStatistics(directoryPath); + exists = lstat.isDirectory(); + } catch (e) { + /* no-op */ + } + + return exists; + } + + /** + * BE VERY CAREFUL CALLING THIS FUNCTION! + * If you specify the wrong folderPath (e.g. "/"), it could potentially delete your entire + * hard disk. + */ + public static dangerouslyDeletePath(folderPath: string): void { + try { + FileSystem.deleteFolder(folderPath); + } catch (e) { + throw new Error( + `${(e as Error).message}\nOften this is caused by a file lock from a process ` + + 'such as your text editor, command prompt, or a filesystem watcher' + ); + } + } + + /* + * Returns true if dateToCompare is more recent than all of the inputFilenames, which + * would imply that we don't need to rebuild it. Returns false if any of the files + * does not exist. + * NOTE: The filenames can also be paths for directories, in which case the directory + * timestamp is compared. + */ + public static async isFileTimestampCurrentAsync( + dateToCompare: Date, + inputFilePaths: string[] + ): Promise { + let anyAreOutOfDate: boolean = false; + await Async.forEachAsync( + inputFilePaths, + async (filePath) => { + if (!anyAreOutOfDate) { + let inputStats: FileSystemStats | undefined; + try { + inputStats = await FileSystem.getStatisticsAsync(filePath); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + // eslint-disable-next-line require-atomic-updates + anyAreOutOfDate = true; + } else { + throw e; + } + } + + if (inputStats && dateToCompare < inputStats.mtime) { + // eslint-disable-next-line require-atomic-updates + anyAreOutOfDate = true; + } + } + }, + { concurrency: 10 } + ); + + return !anyAreOutOfDate; + } + + public static async executeCommandAsync( + options: IExecuteCommandOptions & { captureExitCodeAndSignal: true } + ): Promise>; + public static async executeCommandAsync(options: IExecuteCommandOptions): 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. + */ + public static async executeCommandAsync({ + command, + args, + workingDirectory, + suppressOutput, + onStdoutStreamChunk, + environment, + keepEnvironment, + captureExitCodeAndSignal + }: IExecuteCommandOptions): Promise> { + const { exitCode, signal } = await Utilities._executeCommandInternalAsync({ + command, + args, + workingDirectory, + stdio: onStdoutStreamChunk + ? // Inherit the stdin and stderr streams, but pipe the stdout stream, which will then be piped + // to the process's stdout after being intercepted by the onStdoutStreamChunk callback. + ['inherit', 'pipe', 'inherit'] + : suppressOutput + ? // If the output is being suppressed, create pipes for all streams to prevent the child process + // from printing to the parent process's (this process's) stdout/stderr, but allow the stdout and + // stderr to be inspected if an error occurs. + // TODO: Consider ignoring stdout and stdin and only piping stderr for inspection on error. + ['pipe', 'pipe', 'pipe'] + : // If the output is not being suppressed or intercepted, inherit all streams from the parent process. + ['inherit', 'inherit', 'inherit'], + environment, + keepEnvironment, + onStdoutStreamChunk, + captureOutput: false, + captureExitCodeAndSignal + }); + + if (captureExitCodeAndSignal) { + return { exitCode, signal }; + } + } + + /** + * 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 executeCommandAndCaptureOutputAsync( + command: string, + args: string[], + workingDirectory: string, + environment?: IEnvironment, + keepEnvironment: boolean = false + ): Promise { + const { stdout } = await Utilities._executeCommandInternalAsync({ + command, + args, + workingDirectory, + stdio: ['pipe', 'pipe', 'pipe'], + environment, + keepEnvironment, + captureOutput: true + }); + + return stdout; + } + + /** + * Attempts to run Utilities.executeCommand() up to maxAttempts times before giving up. + */ + public static async executeCommandWithRetryAsync( + options: IExecuteCommandOptions, + maxAttempts: number, + retryCallback?: () => void + ): Promise { + if (maxAttempts < 1) { + throw new Error('The maxAttempts parameter cannot be less than 1'); + } + + let attemptNumber: number = 1; + + for (;;) { + try { + await Utilities.executeCommandAsync(options); + } catch (error) { + // eslint-disable-next-line no-console + console.log('\nThe command failed:'); + const { command, args } = options; + // eslint-disable-next-line no-console + console.log(` ${command} ` + args.join(' ')); + // eslint-disable-next-line no-console + console.log(`ERROR: ${(error as Error).toString()}`); + + if (attemptNumber < maxAttempts) { + ++attemptNumber; + // eslint-disable-next-line no-console + console.log(`Trying again (attempt #${attemptNumber})...\n`); + if (retryCallback) { + retryCallback(); + } + + continue; + } else { + // eslint-disable-next-line no-console + console.error(`Giving up after ${attemptNumber} attempts\n`); + throw error; + } + } + + break; + } + } + + /** + * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS. + * @param command - the command to run on shell + * @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); + + if (options.handleOutput) { + Utilities._processResult({ + error: result.error, + status: result.status, + stderr: result.stderr.toString() + }); + } + + if (result.status !== null) { + return result.status; + } else { + throw result.error || new Error('An unknown error occurred.'); + } + } + + /** + * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS. + * @param command - the command to run on shell + * @param options - options for how the command should be run + */ + public static executeLifecycleCommandAsync( + command: string, + options: ILifecycleCommandOptions + ): child_process.ChildProcess { + const child: child_process.ChildProcess = Utilities._executeLifecycleCommandInternal( + command, + child_process.spawn, + options + ); + if (options.connectSubprocessTerminator) { + SubprocessTerminator.killProcessTreeOnExit(child, SubprocessTerminator.RECOMMENDED_OPTIONS); + } + 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. + */ + public static async installPackageInDirectoryAsync({ + packageName, + version, + tempPackageTitle, + commonRushConfigFolder, + maxInstallAttempts, + suppressOutput, + directory + }: IInstallPackageInDirectoryOptions): Promise { + directory = path.resolve(directory); + const directoryExists: boolean = await FileSystem.existsAsync(directory); + if (directoryExists) { + // eslint-disable-next-line no-console + console.log('Deleting old files from ' + directory); + } + + await FileSystem.ensureEmptyFolderAsync(directory); + + const npmPackageJson: IPackageJson = { + dependencies: { + [packageName]: version + }, + description: 'Temporary file generated by the Rush tool', + name: tempPackageTitle, + private: true, + version: '0.0.0' + }; + await JsonFile.saveAsync(npmPackageJson, path.join(directory, FileConstants.PackageJson)); + + if (commonRushConfigFolder) { + Utilities.syncNpmrc({ + sourceNpmrcFolder: commonRushConfigFolder, + targetNpmrcFolder: directory, + supportEnvVarFallbackSyntax: false + }); + } + + // eslint-disable-next-line no-console + console.log('\nRunning "npm install" in ' + directory); + + // NOTE: Here we use whatever version of NPM we happen to find in the PATH + await Utilities.executeCommandWithRetryAsync( + { + command: 'npm', + args: ['install'], + workingDirectory: directory, + environment: Utilities._createEnvironmentForRushCommand({}), + suppressOutput + }, + maxInstallAttempts + ); + } + + /** + * Copies the file "sourcePath" to "destinationPath", overwriting the target file location. + * If the source file does not exist, then the target file is deleted. + */ + public static syncFile(sourcePath: string, destinationPath: string): void { + if (FileSystem.exists(sourcePath)) { + // eslint-disable-next-line no-console + console.log(`Copying "${sourcePath}"`); + // eslint-disable-next-line no-console + console.log(` --> "${destinationPath}"`); + FileSystem.copyFile({ sourcePath, destinationPath }); + } else { + if (FileSystem.exists(destinationPath)) { + // If the source file doesn't exist and there is one in the target, delete the one in the target + // eslint-disable-next-line no-console + console.log(`Deleting ${destinationPath}`); + FileSystem.deleteFile(destinationPath); + } + } + } + + public static getRushConfigNotFoundError(): Error { + return new Error(`Unable to find ${RushConstants.rushJsonFilename} configuration file`); + } + + public static async usingAsync( + getDisposableAsync: () => Promise | IDisposable, + doActionAsync: (disposable: TDisposable) => Promise | void + ): Promise { + let disposable: TDisposable | undefined; + try { + disposable = (await getDisposableAsync()) as TDisposable; + await doActionAsync(disposable); + } finally { + disposable?.dispose(); + } + } + + public static trimAfterLastSlash(filePath: string): string { + const indexOfLastSlash: number = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\')); + if (indexOfLastSlash < 0) { + return filePath; + } + return filePath.substring(0, indexOfLastSlash); + } + + /** + * If the path refers to a symlink, `FileSystem.exists()` would normally test whether the symlink + * points to a target that exists. By contrast, `existsOrIsBrokenSymlink()` will return true even if + * the symlink exists but its target does not. */ + public static existsOrIsSymlink(linkPath: string): boolean { + try { + FileSystem.getLinkStatistics(linkPath); + return true; + } catch (err) { + return false; + } + } + + 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') { + shellCommand = 'sh'; + commandFlags = '-c'; + useShell = false; + } + + 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 + } + }); + + const stdio: child_process.StdioOptions = options.handleOutput ? ['pipe', 'pipe', 'pipe'] : [0, 1, 2]; + if (options.ipc) { + stdio.push('ipc'); + } + + const spawnOptions: child_process.SpawnOptions = { + cwd: options.workingDirectory, + shell: useShell, + env: environment, + stdio + }; + + if (options.connectSubprocessTerminator) { + Object.assign(spawnOptions, SubprocessTerminator.RECOMMENDED_OPTIONS); + } + + return spawnFunction(shellCommand, [commandFlags, command], spawnOptions); + } + + /** + * 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; + } + + // Set some defaults for the environment + const environment: IEnvironment = {}; + if (options.pathOptions?.rushJsonFolder) { + environment.RUSHSTACK_FILE_ERROR_BASE_FOLDER = options.pathOptions.rushJsonFolder; + } + + for (const key of Object.getOwnPropertyNames(options.initialEnvironment)) { + const normalizedKey: string = os.platform() === 'win32' ? 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 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; + } + + // Use the uppercased environment variable name on Windows because environment variable names + // are case-insensitive on Windows + environment[normalizedKey] = options.initialEnvironment[key]; + } + + // 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) { + if (options.pathOptions.includeRepoBin && options.pathOptions.commonTempFolder) { + environment.PATH = Utilities._prependNodeModulesBinToPath( + environment.PATH, + options.pathOptions.commonTempFolder + ); + } + + if (options.pathOptions.includeProjectBin && options.pathOptions.projectRoot) { + environment.PATH = Utilities._prependNodeModulesBinToPath( + environment.PATH, + options.pathOptions.projectRoot + ); + } + + if (options.pathOptions.additionalPathFolders) { + environment.PATH = [...options.pathOptions.additionalPathFolders, environment.PATH].join( + path.delimiter + ); + } + } + + // Communicate to downstream calls that they should not try to run hooks + environment[EnvironmentVariableNames._RUSH_RECURSIVE_RUSHX_CALL] = '1'; + + return environment; + } + + /** + * 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; + } + } + + /** + * 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( + 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. + */ + private static async _executeCommandInternalAsync( + options: IExecuteCommandInternalOptions & { captureOutput: false | undefined } + ): Promise; + private static async _executeCommandInternalAsync({ + command, + args, + workingDirectory, + stdio, + environment, + keepEnvironment, + onStdoutStreamChunk, + captureOutput, + captureExitCodeAndSignal + }: IExecuteCommandInternalOptions): Promise | IWaitForExitResultWithoutOutput> { + 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 + }; + + // 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 = + command.indexOf(' ') < 0 ? command : Utilities.escapeShellParameter(command); + + const escapedArgs: string[] = args.map((x) => Utilities.escapeShellParameter(x)); + + const childProcess: child_process.ChildProcess = child_process.spawn( + escapedCommand, + escapedArgs, + options + ); + + 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 + }); + + childProcess.stdout?.pipe(inspectStream).pipe(process.stdout); + } + + return await Executable.waitForExitAsync(childProcess, { + encoding: captureOutput ? 'utf8' : undefined, + throwOnNonZeroExitCode: !captureExitCodeAndSignal, + throwOnSignal: !captureExitCodeAndSignal + }); + } + + 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}`); + } + } +} diff --git a/libraries/rush-lib/src/utilities/WebClient.ts b/libraries/rush-lib/src/utilities/WebClient.ts new file mode 100644 index 00000000000..bdd16823332 --- /dev/null +++ b/libraries/rush-lib/src/utilities/WebClient.ts @@ -0,0 +1,306 @@ +// 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 process from 'node:process'; +import { request as httpRequest, type IncomingMessage, type Agent as HttpAgent } from 'node:http'; +import { request as httpsRequest, type RequestOptions } from 'node:https'; + +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 { + ok: boolean; + status: number; + statusText?: string; + redirected: boolean; + headers: Record; + getTextAsync: () => Promise; + getJsonAsync: () => Promise; + getBufferAsync: () => Promise; +} + +/** + * For use with {@link WebClient}. + */ +export interface IWebFetchOptionsBase { + timeoutMs?: number; + headers?: Record; + redirect?: 'follow' | 'error' | 'manual'; + /** + * If true, the response will not be decoded if a Content-Encoding header is present. + */ + noDecode?: boolean; +} + +/** + * For use with {@link WebClient}. + */ +export interface IGetFetchOptions extends IWebFetchOptionsBase { + verb: 'GET' | never; +} + +/** + * For use with {@link WebClient}. + */ +export interface IFetchOptionsWithBody extends IWebFetchOptionsBase { + verb: 'PUT' | 'POST' | 'PATCH'; + body?: Buffer; +} + +/** + * For use with {@link WebClient}. + */ +export enum WebClientProxy { + None, + Detect, + Fiddler +} +export interface IRequestOptions + extends RequestOptions, + Pick {} + +export type FetchFn = ( + url: string, + options: IRequestOptions, + isRedirect?: boolean +) => Promise; + +const DEFLATE_ENCODING: 'deflate' = 'deflate'; +const GZIP_ENCODING: 'gzip' = 'gzip'; +const BROTLI_ENCODING: 'br' = 'br'; +export const AUTHORIZATION_HEADER_NAME: 'Authorization' = 'Authorization'; +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 ( + url: string, + options: IRequestOptions, + redirected: boolean = false +) => { + const { body, redirect, noDecode } = options; + + return await new Promise( + (resolve: (result: IWebClientResponse) => 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; + } + case 'error': + reject(new Error(`Received status code ${response.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(); + } + + 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) { + let encodings: string | string[] | undefined = headers[CONTENT_ENCODING_HEADER_NAME]; + if (!noDecode && encodings !== undefined) { + const zlib: typeof import('zlib') = await import('node:zlib'); + if (!Array.isArray(encodings)) { + encodings = encodings.split(','); + } + + 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}`); + } + } + + buffer = await LegacyAdapters.convertCallbackToPromise(decompressFn, buffer); + } + + // eslint-disable-next-line require-atomic-updates + decodedBuffer = buffer; + } else { + decodedBuffer = responseData; + } + } + + return decodedBuffer; + } + }; + resolve(result); + }); + }) + .on('error', (error: Error) => { + reject(error); + }) + .end(body); + } + ); +}; + +/** + * A helper for issuing HTTP requests. + */ +export class WebClient { + private static _requestFn: FetchFn = makeRequestAsync; + + public readonly standardHeaders: Record = {}; + + public accept: string | undefined = '*/*'; + public userAgent: string | undefined = `rush node/${process.version} ${os.platform()} ${os.arch()}`; + + public proxy: WebClientProxy = WebClientProxy.Detect; + + public static mockRequestFn(fn: FetchFn): void { + WebClient._requestFn = fn; + } + + public static resetMockRequestFn(): void { + WebClient._requestFn = makeRequestAsync; + } + + public static mergeHeaders(target: Record, source: Record): void { + for (const [name, value] of Object.entries(source)) { + target[name] = value; + } + } + + public addBasicAuthHeader(userName: string, password: string): void { + this.standardHeaders[AUTHORIZATION_HEADER_NAME] = + 'Basic ' + Buffer.from(userName + ':' + password).toString('base64'); + } + + public async fetchAsync( + 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: HttpAgent | undefined = undefined; + if (proxyUrl) { + agent = createHttpsProxyAgent(proxyUrl); + } + + const requestInit: IRequestOptions = { + method: verb, + headers, + agent, + timeout: timeoutMs, + redirect, + body, + noDecode + }; + + return await WebClient._requestFn(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/npmrcUtilities.ts b/libraries/rush-lib/src/utilities/npmrcUtilities.ts new file mode 100644 index 00000000000..b5a61e45aff --- /dev/null +++ b/libraries/rush-lib/src/utilities/npmrcUtilities.ts @@ -0,0 +1,259 @@ +// 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 + +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +export interface ILogger { + info: (string: string) => void; + error: (string: string) => void; +} + +/** + * 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: Map = new Map(); + +function _trimNpmrcFile( + options: Pick< + INpmrcTrimOptions, + 'sourceNpmrcPath' | 'linesToAppend' | 'linesToPrepend' | 'supportEnvVarFallbackSyntax' + > +): string { + const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax } = options; + const combinedNpmrcFromCache: string | undefined = _combinedNpmrcMap.get(sourceNpmrcPath); + if (combinedNpmrcFromCache !== undefined) { + return combinedNpmrcFromCache; + } + + let npmrcFileLines: string[] = []; + if (linesToPrepend) { + npmrcFileLines.push(...linesToPrepend); + } + + if (fs.existsSync(sourceNpmrcPath)) { + npmrcFileLines.push(...fs.readFileSync(sourceNpmrcPath).toString().split('\n')); + } + + if (linesToAppend) { + npmrcFileLines.push(...linesToAppend); + } + + npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + + const resultLines: string[] = trimNpmrcFileLines(npmrcFileLines, process.env, supportEnvVarFallbackSyntax); + + const combinedNpmrc: string = resultLines.join('\n'); + + //save the cache + _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); + + return combinedNpmrc; +} + +/** + * + * @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 + */ +export function trimNpmrcFileLines( + npmrcFileLines: string[], + env: NodeJS.ProcessEnv, + supportEnvVarFallbackSyntax: boolean +): string[] { + const resultLines: string[] = []; + + // This finds environment variable tokens that look like "${VAR_NAME}" + const expansionRegExp: RegExp = /\$\{([^\}]+)\}/g; + + // Comment lines start with "#" or ";" + const commentRegExp: RegExp = /^\s*[#;]/; + + // Trim out lines that reference environment variables that aren't defined + for (let line of npmrcFileLines) { + let lineShouldBeTrimmed: boolean = 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: 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]; + } else { + environmentVariableName = nameWithFallback; + } + + // Is the environment variable and fallback value defined. + if (!env[environmentVariableName] && !fallback) { + // 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); + } + } + + return resultLines; +} + +/** + * As a workaround, copyAndTrimNpmrcFile() copies the .npmrc file to the target folder, and also trims + * unusable lines from the .npmrc file. + * + * Why are we trimming the .npmrc lines? NPM allows environment variables to be specified in + * the .npmrc file to provide different authentication tokens for different registry. + * However, if the environment variable is undefined, it expands to an empty string, which + * produces a valid-looking mapping with an invalid URL that causes an error. Instead, + * we'd prefer to skip that line and continue looking in other places such as the user's + * home directory. + * + * @returns + * The text of the the .npmrc with lines containing undefined variables commented out. + */ +interface INpmrcTrimOptions { + sourceNpmrcPath: string; + targetNpmrcPath: string; + logger: ILogger; + linesToPrepend?: string[]; + linesToAppend?: string[]; + supportEnvVarFallbackSyntax: boolean; +} + +function _copyAndTrimNpmrcFile(options: INpmrcTrimOptions): string { + const { logger, sourceNpmrcPath, targetNpmrcPath } = options; + logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose + logger.info(` --> "${targetNpmrcPath}"`); + + const combinedNpmrc: string = _trimNpmrcFile(options); + + fs.writeFileSync(targetNpmrcPath, combinedNpmrc); + + return combinedNpmrc; +} + +/** + * syncNpmrc() copies the .npmrc file to the target folder, and also trims unusable lines from the .npmrc file. + * If the source .npmrc file not exist, then syncNpmrc() will delete an .npmrc that is found in the target folder. + * + * IMPORTANT: THIS CODE SHOULD BE KEPT UP TO DATE WITH Utilities._syncNpmrc() + * + * @returns + * The text of the the synced .npmrc, if one exists. If one does not exist, then undefined is returned. + */ +export interface ISyncNpmrcOptions { + sourceNpmrcFolder: string; + targetNpmrcFolder: string; + supportEnvVarFallbackSyntax: boolean; + useNpmrcPublish?: boolean; + logger?: ILogger; + linesToPrepend?: string[]; + linesToAppend?: string[]; + createIfMissing?: boolean; +} + +export function syncNpmrc(options: ISyncNpmrcOptions): string | undefined { + 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 + } = options; + const sourceNpmrcPath: string = path.join( + sourceNpmrcFolder, + !useNpmrcPublish ? '.npmrc' : '.npmrc-publish' + ); + const targetNpmrcPath: string = path.join(targetNpmrcFolder, '.npmrc'); + try { + if (fs.existsSync(sourceNpmrcPath) || createIfMissing) { + // Ensure the target folder exists + if (!fs.existsSync(targetNpmrcFolder)) { + fs.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + + return _copyAndTrimNpmrcFile({ + sourceNpmrcPath, + targetNpmrcPath, + logger, + ...options + }); + } else if (fs.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.unlinkSync(targetNpmrcPath); + } + } catch (e) { + throw new Error(`Error syncing .npmrc file: ${e}`); + } +} + +export function isVariableSetInNpmrcFile( + sourceNpmrcFolder: string, + variableKey: string, + supportEnvVarFallbackSyntax: boolean +): boolean { + const sourceNpmrcPath: string = `${sourceNpmrcFolder}/.npmrc`; + + //if .npmrc file does not exist, return false directly + if (!fs.existsSync(sourceNpmrcPath)) { + return false; + } + + const trimmedNpmrcFile: string = _trimNpmrcFile({ sourceNpmrcPath, supportEnvVarFallbackSyntax }); + + 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 new file mode 100644 index 00000000000..7261c88ef4d --- /dev/null +++ b/libraries/rush-lib/src/utilities/objectUtilities.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export function cloneDeep(obj: TObject): TObject { + return cloneDeepInner(obj, new Set()); +} + +export function merge(base: TBase, other: TOther): (TBase & TOther) | TOther { + if (typeof other === 'object' && other !== null && !Array.isArray(other)) { + for (const [key, value] of Object.entries(other)) { + if (key in base) { + const baseValue: unknown = (base as Record)[key]; + if (typeof baseValue === 'object' && baseValue !== null && !Array.isArray(baseValue)) { + (base as Record)[key] = merge(baseValue, value); + } else { + (base as Record)[key] = value; + } + } else { + (base as Record)[key] = value; + } + } + + return base as TBase & TOther; + } else { + return other; + } +} + +function cloneDeepInner(obj: TObject, seenObjects: Set): TObject { + if (seenObjects.has(obj)) { + throw new Error('Circular reference detected'); + } else if (typeof obj === 'object') { + if (obj === null) { + return null as TObject; + } else { + seenObjects.add(obj); + if (Array.isArray(obj)) { + const result: unknown[] = []; + for (const item of obj) { + result.push(cloneDeepInner(item, new Set(seenObjects))); + } + + return result as TObject; + } else { + const result: Record = {}; + for (const key of Object.getOwnPropertyNames(obj)) { + const value: unknown = (obj as Record)[key]; + result[key] = cloneDeepInner(value, new Set(seenObjects)); + } + + return result as TObject; + } + } + } else { + return obj; + } +} + +/** + * Performs a partial deep comparison between `obj` and `source` to + * determine if `obj` contains equivalent property values. + */ +export function isMatch(obj: TObject, source: TObject): boolean { + return obj === source || (typeof obj === typeof source && isMatchInner(obj, source)); +} + +function isMatchInner(obj: TObject, source: TObject): boolean { + if (obj === null || obj === undefined) { + return false; + } + + for (const k of Object.keys(source as object)) { + const key: keyof TObject = k as keyof TObject; + const sourceValue: unknown = source[key]; + if (isStrictComparable(sourceValue)) { + if (obj[key] !== sourceValue) { + return false; + } + } else if (!isMatchInner(obj[key], sourceValue)) { + return false; + } + } + + return true; +} + +/** + * Check if `value` is suitable for strict equality comparisons, i.e. `===`. + */ +function isStrictComparable(value: T): boolean { + const type: string = typeof value; + return ( + // eslint-disable-next-line no-self-compare + 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 new file mode 100644 index 00000000000..a1e76cc008e --- /dev/null +++ b/libraries/rush-lib/src/utilities/prompts/SearchListPrompt.ts @@ -0,0 +1,295 @@ +// 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 'node:readline'; + +// 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'; + +import { Colorize } from '@rushstack/terminal'; + +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)))); + + void validation.success.forEach(this._onSubmit.bind(this)); + void validation.error.forEach(this._onError.bind(this)); + + void events.numberKey + .pipe(takeUntil(events.line)) + .forEach(this._onNumberKey.bind(this) as (evt: unknown) => 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 new file mode 100644 index 00000000000..a2ccdcef326 --- /dev/null +++ b/libraries/rush-lib/src/utilities/templateUtilities.ts @@ -0,0 +1,228 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +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. +// Example: /*[BEGIN "DEMO"]*/ +// +// Group #1 is the indentation spaces before the macro +// Group #2 is the section name +const BEGIN_MARCO_REGEXP: RegExp = /^(\s*)\/\*\[BEGIN "([A-Z]+)"\]\s*\*\/\s*$/; + +// Matches a well-formed END macro ending a block section. +// Example: /*[END "DEMO"]*/ +// +// Group #1 is the indentation spaces before the macro +// Group #2 is the section name +const END_MACRO_REGEXP: RegExp = /^(\s*)\/\*\[END "([A-Z]+)"\]\s*\*\/\s*$/; + +// Matches a well-formed single-line section, including the space character after it +// if present. +// Example: /*[LINE "HYPOTHETICAL"]*/ +// +// Group #1 is the section name +const LINE_MACRO_REGEXP: RegExp = /\/\*\[LINE "([A-Z]+)"\]\s*\*\/\s?/; + +// Matches a variable expansion. +// Example: [%RUSH_VERSION%] +// +// Group #1 is the variable name including the dollar sign +const VARIABLE_MACRO_REGEXP: RegExp = /\[(%[A-Z0-9_]+%)\]/; + +// Matches anything that starts with "/*[" and ends with "]*/" +// Used to catch malformed macro expressions +const ANY_MACRO_REGEXP: RegExp = /\/\*\s*\[.*\]\s*\*\//; + +// Copy the template from sourcePath, transform any macros, and write the output to destinationPath. +// +// We implement a simple template engine. "Single-line section" macros have this form: +// +// /*[LINE "NAME"]*/ (content goes here) +// +// ...and when commented out will look like this: +// +// // (content goes here) +// +// "Block section" macros have this form: +// +// /*[BEGIN "NAME"]*/ +// (content goes +// here) +// /*[END "NAME"]*/ +// +// ...and when commented out will look like this: +// +// // (content goes +// // here) +// +// Lastly, a variable expansion has this form: +// +// // The value is [%NAME%]. +// +// ...and when expanded with e.g. "123" will look like this: +// +// // The value is 123. +// +// The section names must be one of the predefined names used by "rush init". +// A single-line section may appear inside a block section, in which case it will get +// commented twice. +export async function copyTemplateFileAsync( + sourcePath: string, + destinationPath: string, + overwrite: boolean, + demo: boolean = false +): Promise { + const destinationFileExists: boolean = await FileSystem.existsAsync(destinationPath); + + if (!overwrite) { + if (destinationFileExists) { + // eslint-disable-next-line no-console + console.log(Colorize.yellow('Not overwriting already existing file: ') + destinationPath); + return; + } + } + + if (destinationFileExists) { + // eslint-disable-next-line no-console + console.log(Colorize.yellow(`Overwriting: ${destinationPath}`)); + } else { + // eslint-disable-next-line no-console + console.log(`Generating: ${destinationPath}`); + } + + const outputLines: string[] = []; + const lines: string[] = ( + await FileSystem.readFileAsync(sourcePath, { convertLineEndings: NewlineKind.Lf }) + ).split('\n'); + + let activeBlockSectionName: string | undefined = undefined; + let activeBlockIndent: string = ''; + + for (const line of lines) { + let match: RegExpMatchArray | null; + + // Check for a block section start + // Example: /*[BEGIN "DEMO"]*/ + match = line.match(BEGIN_MARCO_REGEXP); + if (match) { + if (activeBlockSectionName) { + // If this happens, please report a Rush bug + throw new InternalError( + `The template contains an unmatched BEGIN macro for "${activeBlockSectionName}"` + ); + } + + activeBlockSectionName = match[2]; + activeBlockIndent = match[1]; + // Remove the entire line containing the macro + continue; + } + + // Check for a block section end + // Example: /*[END "DEMO"]*/ + match = line.match(END_MACRO_REGEXP); + if (match) { + if (activeBlockSectionName === undefined) { + // If this happens, please report a Rush bug + throw new InternalError( + `The template contains an unmatched END macro for "${activeBlockSectionName}"` + ); + } + + if (activeBlockSectionName !== match[2]) { + // If this happens, please report a Rush bug + throw new InternalError( + `The template contains an mismatched END macro for "${activeBlockSectionName}"` + ); + } + + if (activeBlockIndent !== match[1]) { + // If this happens, please report a Rush bug + throw new InternalError( + `The template contains an inconsistently indented section "${activeBlockSectionName}"` + ); + } + + activeBlockSectionName = undefined; + + // Remove the entire line containing the macro + continue; + } + + let transformedLine: string = line; + + // Check for a single-line section + // Example: /*[LINE "HYPOTHETICAL"]*/ + match = transformedLine.match(LINE_MACRO_REGEXP); + if (match) { + const sectionName: string = match[1]; + const replacement: string = _isSectionCommented(sectionName, demo) ? '// ' : ''; + transformedLine = transformedLine.replace(LINE_MACRO_REGEXP, replacement); + } + + // Check for variable expansions + // Example: [%RUSH_VERSION%] + while ((match = transformedLine.match(VARIABLE_MACRO_REGEXP))) { + const variableName: string = match[1]; + const replacement: string = _expandMacroVariable(variableName); + transformedLine = transformedLine.replace(VARIABLE_MACRO_REGEXP, replacement); + } + + // Verify that all macros were handled + match = transformedLine.match(ANY_MACRO_REGEXP); + if (match) { + // If this happens, please report a Rush bug + throw new InternalError( + 'The template contains a malformed macro expression: ' + JSON.stringify(match[0]) + ); + } + + // If we are inside a block section that is commented out, then insert the "//" after indentation + if (activeBlockSectionName !== undefined) { + if (_isSectionCommented(activeBlockSectionName, demo)) { + // Is the line indented properly? + if (transformedLine.substr(0, activeBlockIndent.length).trim().length > 0) { + // If this happens, please report a Rush bug + throw new InternalError( + `The template contains inconsistently indented lines inside` + + ` the "${activeBlockSectionName}" section` + ); + } + + // Insert comment characters after the indentation + const contentAfterIndent: string = transformedLine.substr(activeBlockIndent.length); + transformedLine = activeBlockIndent + '// ' + contentAfterIndent; + } + } + + outputLines.push(transformedLine); + } + + // Write the output + await FileSystem.writeFileAsync(destinationPath, outputLines.join('\n'), { + ensureFolderExists: true + }); +} + +function _isSectionCommented(sectionName: string, demo: boolean): boolean { + // The "HYPOTHETICAL" sections are always commented out by "rush init". + // They are uncommented in the "assets" source folder so that we can easily validate + // that they conform to their JSON schema. + if (sectionName === 'HYPOTHETICAL') return true; + if (sectionName === 'DEMO') return demo; + // If this happens, please report a Rush bug + throw new InternalError(`The template references an undefined section name ${sectionName}`); +} + +function _expandMacroVariable(variableName: string): string { + switch (variableName) { + case '%RUSH_VERSION%': + return Rush.version; + default: + throw new InternalError(`The template references an undefined variable "${variableName}"`); + } +} diff --git a/libraries/rush-lib/src/utilities/test/Npm.test.ts b/libraries/rush-lib/src/utilities/test/Npm.test.ts new file mode 100644 index 00000000000..14326ebfd58 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/Npm.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 process from 'node:process'; + +import { Npm } from '../Npm'; +import { Utilities } from '../Utilities'; + +describe(Npm.name, () => { + const packageName: string = '@microsoft/rush-lib-never'; + let stub: jest.SpyInstance; + + beforeEach(() => { + stub = jest.spyOn(Utilities, 'executeCommandAndCaptureOutputAsync'); + }); + + afterEach(() => { + stub.mockReset(); + stub.mockRestore(); + }); + + it('publishedVersions gets versions when package time is available.', async () => { + const json: string = `{ + "modified": "2017-03-30T18:37:27.757Z", + "created": "2017-01-03T20:28:10.342Z", + "0.0.0": "2017-01-03T20:28:10.342Z", + "1.4.0": "2017-01-03T21:55:21.249Z", + "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)); + + 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(versions).toHaveLength(4); + expect(versions).toMatchObject(['0.0.0', '1.4.0', '1.4.1', '2.4.0-alpha.1']); + }); + + it('publishedVersions gets versions when package time is not available', async () => { + const json: string = `[ + "0.0.0", + "1.4.0", + "1.4.1", + "2.4.0-alpha.1" + ]`; + stub.mockImplementationOnce(() => Promise.resolve('')); + stub.mockImplementationOnce(() => Promise.resolve(json)); + + 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(stub).toHaveBeenCalledWith( + 'npm', + `view ${packageName} versions --json`.split(' '), + expect.anything(), + expect.anything(), + expect.anything() + ); + + expect(versions).toHaveLength(4); + expect(versions).toMatchObject(['0.0.0', '1.4.0', '1.4.1', '2.4.0-alpha.1']); + }); +}); diff --git a/libraries/rush-lib/src/utilities/test/OverlappingPathAnalyzer.test.ts b/libraries/rush-lib/src/utilities/test/OverlappingPathAnalyzer.test.ts new file mode 100644 index 00000000000..3123395bafd --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/OverlappingPathAnalyzer.test.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 { OverlappingPathAnalyzer } from '../OverlappingPathAnalyzer'; + +describe(OverlappingPathAnalyzer.name, () => { + it("returns nothing if two single-folder paths don't overlap", () => { + const analyzer: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer.addPathAndGetFirstEncounteredLabels('lib', 'a')).toBeUndefined(); + expect(analyzer.addPathAndGetFirstEncounteredLabels('dist', 'b')).toBeUndefined(); + }); + + it("returns nothing if two multi-folder paths don't overlap", () => { + const analyzer1: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('lib/a', 'a')).toBeUndefined(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('lib/b', 'b')).toBeUndefined(); + + const analyzer2: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/a/c', 'a')).toBeUndefined(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/b/c', 'b')).toBeUndefined(); + }); + + it('returns a label if two single-folder paths overlap', () => { + const analyzer: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer.addPathAndGetFirstEncounteredLabels('lib', 'a')).toBeUndefined(); + expect(analyzer.addPathAndGetFirstEncounteredLabels('lib', 'b')).toEqual(['a']); + }); + + it('returns a label if two multi-folder paths overlap', () => { + const analyzer1: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('lib', 'a')).toBeUndefined(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('lib/a', 'b')).toEqual(['a']); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('lib/a/b', 'c')).toEqual(['a']); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('dist/a/b/c', 'd')).toBeUndefined(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('dist/a', 'e')).toEqual(['d']); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('dist/b/c/e', 'f')).toBeUndefined(); + expect(analyzer1.addPathAndGetFirstEncounteredLabels('dist/b/c/e/f', 'e')).toEqual(['f']); + + const analyzer2: OverlappingPathAnalyzer = new OverlappingPathAnalyzer(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/a/b/c', 'a')).toBeUndefined(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/a/b/d', 'b')).toBeUndefined(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/a/b/e', 'c')).toBeUndefined(); + expect(analyzer2.addPathAndGetFirstEncounteredLabels('lib/a', 'd')).toEqual(['a', 'b', 'c']); + }); +}); diff --git a/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts b/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts new file mode 100644 index 00000000000..931707e2385 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Stopwatch, StopwatchState } from '../Stopwatch'; + +function pseudoTimeMilliseconds(times: number[]): () => number { + return () => times.shift()!; +} + +function pseudoTimeSeconds(times: number[]): () => number { + return pseudoTimeMilliseconds(times.map((time) => time * 1000)); +} + +describe(Stopwatch.name, () => { + it('allows a static invocation as a quick shorthand', () => { + expect(Stopwatch.start().reset().toString()).toEqual('0.00 seconds (stopped)'); + }); + + it('stopping before starting does nothing', () => { + const watch: Stopwatch = new Stopwatch(); + watch.stop(); + expect(watch.toString()).toEqual('0.00 seconds (stopped)'); + }); + + it("can't start twice", () => { + const watch: Stopwatch = new Stopwatch(); + expect(() => { + watch.start(); + watch.start(); + }).toThrow(); + }); + + it('reflects the proper state', () => { + const watch: Stopwatch = new Stopwatch(); + expect(watch.state).toEqual(StopwatchState.Stopped); + watch.start(); + expect(watch.state).toEqual(StopwatchState.Started); + watch.stop(); + expect(watch.state).toEqual(StopwatchState.Stopped); + watch.reset(); + expect(watch.state).toEqual(StopwatchState.Stopped); + }); + + it('gives 0.00 seconds after being reset', () => { + const watch: Stopwatch = new Stopwatch(); + watch.start(); + watch.reset(); + expect(watch.toString()).toEqual('0.00 seconds (stopped)'); + expect(watch.duration).toEqual(0); + }); + + it('gives 0.00 seconds when not running', () => { + const watch: Stopwatch = new Stopwatch(); + expect(watch.toString()).toEqual('0.00 seconds (stopped)'); + expect(watch.duration).toEqual(0); + }); + + it('uses the latest time when the clock is not stopped', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); + watch.start(); + expect(watch.toString()).toEqual('1.00 seconds'); + expect(watch.toString()).toEqual('2.00 seconds'); + }); + + it('uses the stop time when the clock is stopped', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); + watch.start(); + watch.stop(); + expect(watch.toString()).toEqual('1.00 seconds'); + expect(watch.toString()).toEqual('1.00 seconds'); + }); + + it('gives elapsed seconds when < 1 minute', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2, 3.25])); + watch.start(); + watch.stop(); + expect(watch.toString()).toEqual('1.00 seconds'); + }); + + it('gives elapsed minutes and seconds when > 1 minute', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 400])); + watch.start(); + watch.stop(); + expect(watch.toString()).toEqual('6 minutes 40.0 seconds'); + }); + + it('gives elapsed minute and seconds when time >=60 <=119 seconds', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 61.25])); + watch.start(); + watch.stop(); + expect(watch.toString()).toEqual('1 minute 1.3 seconds'); + }); + + it('uses the latest time when the clock is not stopped', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); + watch.start(); + expect(watch.toString()).toEqual('1.00 seconds'); + expect(watch.toString()).toEqual('2.00 seconds'); + }); + + it('returns duration when the clock is stopped', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 61.25])); + watch.start(); + watch.stop(); + expect(watch.duration).toEqual(61.25); + }); + + it('returns duration using the latest time when the clock is not stopped', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeSeconds([0, 1, 2])); + watch.start(); + expect(watch.duration).toEqual(1); + expect(watch.duration).toEqual(2); + }); +}); diff --git a/libraries/rush-lib/src/utilities/test/Utilities.test.ts b/libraries/rush-lib/src/utilities/test/Utilities.test.ts new file mode 100644 index 00000000000..0b00c575da6 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/Utilities.test.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 IDisposable, Utilities } from '../Utilities'; + +describe(Utilities.name, () => { + describe(Utilities.usingAsync.name, () => { + let disposed: boolean; + + beforeEach(() => { + disposed = false; + }); + + class Disposable implements IDisposable { + public dispose(): void { + disposed = true; + } + } + + it('Disposes correctly in a simple case', async () => { + await Utilities.usingAsync( + () => new Disposable(), + () => { + /* no-op */ + } + ); + + expect(disposed).toEqual(true); + }); + + it('Disposes correctly after the operation throws an exception', async () => { + await expect( + async () => + await Utilities.usingAsync( + () => new Disposable(), + () => { + throw new Error('operation threw'); + } + ) + ).rejects.toMatchSnapshot(); + + expect(disposed).toEqual(true); + }); + + it('Does not dispose if the construction throws an exception', async () => { + await expect( + async () => + await Utilities.usingAsync( + async () => { + throw new Error('constructor threw'); + }, + () => { + /* no-op */ + } + ) + ).rejects.toMatchSnapshot(); + + expect(disposed).toEqual(false); + }); + }); +}); diff --git a/libraries/rush-lib/src/utilities/test/WebClient.test.ts b/libraries/rush-lib/src/utilities/test/WebClient.test.ts new file mode 100644 index 00000000000..cda35c0ee61 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/WebClient.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 { WebClient } from '../WebClient'; + +describe(WebClient.name, () => { + describe(WebClient.mergeHeaders.name, () => { + it('should merge headers', () => { + const target: Record = { header1: 'value1' }; + const source: Record = { header2: 'value2' }; + + WebClient.mergeHeaders(target, source); + expect(target).toMatchSnapshot(); + }); + + it('should handle an empty source', () => { + const target: Record = { header1: 'value1' }; + const source: Record = {}; + + WebClient.mergeHeaders(target, source); + expect(target).toMatchSnapshot(); + }); + + it('should handle an empty target', () => { + const target: Record = {}; + const source: Record = { header2: 'value2' }; + + WebClient.mergeHeaders(target, source); + expect(target).toMatchSnapshot(); + }); + + it('should handle both empty', () => { + const target: Record = {}; + const source: Record = {}; + + WebClient.mergeHeaders(target, source); + expect(target).toMatchSnapshot(); + }); + + it('should handle overwriting values', () => { + const target: Record = { header1: 'value1' }; + const source: Record = { header1: 'value2' }; + + WebClient.mergeHeaders(target, source); + expect(target).toMatchSnapshot(); + }); + + it('should handle a JS object as the source', () => { + const target: Record = { header1: 'value1' }; + + WebClient.mergeHeaders(target, { header2: 'value2' }); + expect(target).toMatchSnapshot(); + }); + }); +}); 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 new file mode 100644 index 00000000000..019edf70019 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/Utilities.test.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Utilities usingAsync Disposes correctly after the operation throws an exception 1`] = `[Error: operation threw]`; + +exports[`Utilities usingAsync Does not dispose if the construction throws an exception 1`] = `[Error: constructor 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 new file mode 100644 index 00000000000..82fdb7303c4 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/WebClient.test.ts.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WebClient mergeHeaders should handle a JS object as the source 1`] = ` +Object { + "header1": "value1", + "header2": "value2", +} +`; + +exports[`WebClient mergeHeaders should handle an empty source 1`] = ` +Object { + "header1": "value1", +} +`; + +exports[`WebClient mergeHeaders should handle an empty target 1`] = ` +Object { + "header2": "value2", +} +`; + +exports[`WebClient mergeHeaders should handle both empty 1`] = `Object {}`; + +exports[`WebClient mergeHeaders should handle overwriting values 1`] = ` +Object { + "header1": "value2", +} +`; + +exports[`WebClient mergeHeaders should merge headers 1`] = ` +Object { + "header1": "value1", + "header2": "value2", +} +`; 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 new file mode 100644 index 00000000000..691864176a2 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/npmrcUtilities.test.ts.snap @@ -0,0 +1,225 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a a variable without a fallback 1`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a a variable without a fallback 2`] = ` +Array [ + "var1=\${foo}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 1`] = ` +Array [ + "var1=\${foo-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 2`] = ` +Array [ + "var1=\${foo-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 3`] = ` +Array [ + "var1=\${foo:-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 4`] = ` +Array [ + "var1=\${foo:-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 5`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 6`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 7`] = ` +Array [ + "var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable with a fallback 8`] = ` +Array [ + "var1=\${foo:-fallback_value}-\${bar-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports malformed lines 1`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo_fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports malformed lines 2`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports malformed lines 3`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:_fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports malformed lines 4`] = ` +Array [ + "var1=\${foo", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports multiple lines 1`] = ` +Array [ + "var1=\${foo}", + "; MISSING ENVIRONMENT VARIABLE: var2=\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports multiple lines 2`] = ` +Array [ + "var1=\${foo}", + "var2=\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports multiple lines 3`] = ` +Array [ + "var1=\${foo}", + "var2=\${bar-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports multiple lines 4`] = ` +Array [ + "var1=\${foo:-fallback_value}", + "var2=\${bar-fallback_value}", +] +`; + +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}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 2`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 3`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 4`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 5`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 6`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 7`] = ` +Array [ + "var1=\${foo}-\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 8`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:-fallback_value}-\${bar-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports malformed lines 1`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo_fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports malformed lines 2`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports malformed lines 3`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:_fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports malformed lines 4`] = ` +Array [ + "var1=\${foo", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports multiple lines 1`] = ` +Array [ + "var1=\${foo}", + "; MISSING ENVIRONMENT VARIABLE: var2=\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports multiple lines 2`] = ` +Array [ + "var1=\${foo}", + "var2=\${bar}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports multiple lines 3`] = ` +Array [ + "var1=\${foo}", + "; MISSING ENVIRONMENT VARIABLE: var2=\${bar-fallback_value}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports multiple lines 4`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo:-fallback_value}", + "; MISSING ENVIRONMENT VARIABLE: var2=\${bar-fallback_value}", +] +`; diff --git a/libraries/rush-lib/src/utilities/test/global-teardown.ts b/libraries/rush-lib/src/utilities/test/global-teardown.ts new file mode 100644 index 00000000000..49f18a332d9 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/global-teardown.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 { FileSystem } from '@rushstack/node-core-library'; + +import { TEST_REPO_FOLDER_PATH } from '../../cli/test/TestUtils'; + +export default async function globalTeardown(): Promise { + await FileSystem.deleteFolderAsync(TEST_REPO_FOLDER_PATH); +} diff --git a/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts b/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts new file mode 100644 index 00000000000..b889435a0f7 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.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. + +import { trimNpmrcFileLines } from '../npmrcUtilities'; + +describe('npmrcUtilities', () => { + function runTests(supportEnvVarFallbackSyntax: boolean): void { + it('handles empty input', () => { + expect(trimNpmrcFileLines([], {}, supportEnvVarFallbackSyntax)).toEqual([]); + }); + + it('supports a a variable without a fallback', () => { + expect(trimNpmrcFileLines(['var1=${foo}'], {}, supportEnvVarFallbackSyntax)).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo}'], { foo: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + }); + + it('supports a variable with a fallback', () => { + expect( + trimNpmrcFileLines(['var1=${foo-fallback_value}'], {}, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo-fallback_value}'], { foo: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo:-fallback_value}'], {}, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo:-fallback_value}'], { foo: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo}-${bar}'], { foo: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo}-${bar}'], { bar: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo}-${bar}'], { foo: 'test', bar: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines( + ['var1=${foo:-fallback_value}-${bar-fallback_value}'], + {}, + supportEnvVarFallbackSyntax + ) + ).toMatchSnapshot(); + }); + + it('supports multiple lines', () => { + expect( + trimNpmrcFileLines(['var1=${foo}', 'var2=${bar}'], { foo: 'test' }, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines( + ['var1=${foo}', 'var2=${bar}'], + { foo: 'test', bar: 'test' }, + supportEnvVarFallbackSyntax + ) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines( + ['var1=${foo}', 'var2=${bar-fallback_value}'], + { foo: 'test' }, + supportEnvVarFallbackSyntax + ) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines( + ['var1=${foo:-fallback_value}', 'var2=${bar-fallback_value}'], + {}, + supportEnvVarFallbackSyntax + ) + ).toMatchSnapshot(); + }); + + it('supports malformed lines', () => { + // Malformed + expect( + trimNpmrcFileLines(['var1=${foo_fallback_value}'], {}, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo:fallback_value}'], {}, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect( + trimNpmrcFileLines(['var1=${foo:_fallback_value}'], {}, supportEnvVarFallbackSyntax) + ).toMatchSnapshot(); + expect(trimNpmrcFileLines(['var1=${foo'], {}, supportEnvVarFallbackSyntax)).toMatchSnapshot(); + }); + } + + describe(trimNpmrcFileLines.name, () => { + describe('With support for env var fallback syntax', () => runTests(true)); + describe('Without support for env var fallback syntax', () => runTests(false)); + }); +}); diff --git a/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts b/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts new file mode 100644 index 00000000000..ce023119369 --- /dev/null +++ b/libraries/rush-lib/src/utilities/test/objectUtilities.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 { cloneDeep, merge, removeNullishProps } from '../objectUtilities'; + +describe('objectUtilities', () => { + describe(cloneDeep.name, () => { + function testClone(source: unknown): void { + const clone: unknown = cloneDeep(source); + expect(clone).toEqual(source); + expect(clone).not.toBe(source); + } + + it('can clone primitives', () => { + expect(cloneDeep(1)).toEqual(1); + expect(cloneDeep('a')).toEqual('a'); + expect(cloneDeep(true)).toEqual(true); + expect(cloneDeep(undefined)).toEqual(undefined); + expect(cloneDeep(null)).toEqual(null); + }); + + it('can clone arrays', () => { + testClone([]); + testClone([1]); + testClone([1, 2]); + testClone([1, 2, 3]); + }); + + it('can clone objects', () => { + testClone({}); + testClone({ a: 1 }); + testClone({ a: 1, b: 1 }); + testClone({ a: 1, b: 2 }); + + const a: Record = { a: 1 }; + testClone({ a, b: a }); + }); + + it('can clone nested objects', () => { + testClone({ a: { b: 1 } }); + }); + + it("can't clone objects with circular references", () => { + const a: Record = { a: 1 }; + a.b = a; + expect(() => cloneDeep(a)).toThrowErrorMatchingInlineSnapshot(`"Circular reference detected"`); + + const b: unknown[] = []; + b.push(b); + expect(() => cloneDeep(b)).toThrowErrorMatchingInlineSnapshot(`"Circular reference detected"`); + }); + }); + + describe(merge.name, () => { + it('will overwrite with primitives', () => { + expect(merge({}, 2)).toEqual(2); + expect(merge([], 2)).toEqual(2); + expect(merge({}, null)).toEqual(null); + expect(merge([], null)).toEqual(null); + expect(merge({}, undefined)).toEqual(undefined); + expect(merge([], undefined)).toEqual(undefined); + }); + + it('will overwrite with arrays', () => { + expect(merge({}, [1])).toEqual([1]); + expect(merge([], [1])).toEqual([1]); + expect(merge({ a: { b: 1 } }, { a: [1] })).toEqual({ a: [1] }); + }); + + it('will merge with objects', () => { + expect(merge({}, { a: 1 })).toEqual({ a: 1 }); + expect(merge({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 }); + expect(merge({ a: 1 }, { a: 2 })).toEqual({ a: 2 }); + 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 new file mode 100644 index 00000000000..7adbedc6d67 --- /dev/null +++ b/libraries/rush-lib/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "types": ["heft-jest", "node", "webpack-env"], + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "lib-commonjs" + } +} diff --git a/libraries/rush-lib/webpack.config.js b/libraries/rush-lib/webpack.config.js new file mode 100644 index 00000000000..69dab7281f7 --- /dev/null +++ b/libraries/rush-lib/webpack.config.js @@ -0,0 +1,136 @@ +'use strict'; + +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 SCRIPT_ENTRY_OPTIONS = { + filename: `${PathConstants.scriptsFolderName}/[name]` +}; + +module.exports = () => { + const packageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); + + const externalDependencyNames = new Set([ + ...Object.keys(packageJson.dependencies || {}), + ...Object.keys(packageJson.peerDependencies || {}), + ...Object.keys(packageJson.optionalDependencies || {}), + ...Object.keys(packageJson.devDependencies || {}) + ]); + + function generateConfiguration(entry, extraPlugins = [], splitChunks = undefined) { + return { + context: __dirname, + mode: 'development', // So the output isn't minified + devtool: 'source-map', + entry, + output: { + path: `${__dirname}/dist`, + filename: '[name].js', + chunkFilename: 'chunks/[name].js', + library: { + type: 'commonjs2' + } + }, + target: 'node', + plugins: [ + new PreserveDynamicRequireWebpackPlugin(), + new webpack.ids.DeterministicModuleIdsPlugin({ + maxLength: 6 + }), + ...extraPlugins + ], + externals: [ + ({ request }, callback) => { + let packageName; + let firstSlashIndex = request.indexOf('/'); + if (firstSlashIndex === -1) { + packageName = request; + } else if (request.startsWith('@')) { + let secondSlash = request.indexOf('/', firstSlashIndex + 1); + if (secondSlash === -1) { + packageName = request; + } else { + packageName = request.substring(0, secondSlash); + } + } else { + packageName = request.substring(0, firstSlashIndex); + } + + if (externalDependencyNames.has(packageName)) { + callback(null, `commonjs ${request}`); + } else { + callback(); + } + } + ], + optimization: { + splitChunks + } + }; + } + + 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` + }, + [ + new DeepImportsPlugin({ + // A manifest will be produced for each entry point, so since this compilation has multiple entry points, + // 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', + pathsToIgnore: ['utilities/prompts/SearchListPrompt.js'], + dTsFilesInputFolderName: 'lib-commonjs' + }) + ], + { + chunks: 'all', + minChunks: 1, + cacheGroups: { + commons: { + name: 'commons', + chunks: 'initial', + minChunks: 2 + } + } + } + ), + generateConfiguration({ + [PathConstants.pnpmfileShimFilename]: { + import: `${__dirname}/lib-esnext/logic/pnpm/PnpmfileShim.js`, + ...SCRIPT_ENTRY_OPTIONS + }, + [PathConstants.subspacePnpmfileShimFilename]: { + import: `${__dirname}/lib-esnext/logic/pnpm/SubspaceGlobalPnpmfileShim.js`, + ...SCRIPT_ENTRY_OPTIONS + }, + [PathConstants.installRunScriptFilename]: { + import: `${__dirname}/lib-esnext/scripts/install-run.js`, + ...SCRIPT_ENTRY_OPTIONS + }, + [PathConstants.installRunRushScriptFilename]: { + import: `${__dirname}/lib-esnext/scripts/install-run-rush.js`, + ...SCRIPT_ENTRY_OPTIONS + }, + [PathConstants.installRunRushxScriptFilename]: { + import: `${__dirname}/lib-esnext/scripts/install-run-rushx.js`, + ...SCRIPT_ENTRY_OPTIONS + }, + [PathConstants.installRunRushPnpmScriptFilename]: { + import: `${__dirname}/lib-esnext/scripts/install-run-rush-pnpm.js`, + ...SCRIPT_ENTRY_OPTIONS + } + }) + ]; + + return configurations; +}; diff --git a/libraries/rush-sdk/.npmignore b/libraries/rush-sdk/.npmignore new file mode 100644 index 00000000000..6d66e80b784 --- /dev/null +++ b/libraries/rush-sdk/.npmignore @@ -0,0 +1,34 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- +/lib-commonjs/** +/lib-esnext/** diff --git a/libraries/rush-sdk/LICENSE b/libraries/rush-sdk/LICENSE new file mode 100644 index 00000000000..52750df3fbc --- /dev/null +++ b/libraries/rush-sdk/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rush-sdk + +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/libraries/rush-sdk/README.md b/libraries/rush-sdk/README.md new file mode 100644 index 00000000000..149ff9b4b41 --- /dev/null +++ b/libraries/rush-sdk/README.md @@ -0,0 +1,159 @@ +## @rushstack/rush-sdk + +This is a companion package for the Rush tool. See the [@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) package for details. + +⚠ **_THIS PACKAGE IS EXPERIMENTAL_** ⚠ + +The **@rushstack/rush-sdk** package acts as a lightweight proxy for accessing the APIs of the **@microsoft/rush-lib** engine. It is intended to support five different use cases: + +1. **Rush plugins:** Rush plugins should import from **@rushstack/rush-sdk** instead of **@microsoft/rush-lib**. This gives plugins full access to Rush APIs while avoiding a redundant installation of those packages. At runtime, the APIs will be bound to the correct `rushVersion` from **rush.json**, and guaranteed to be the same **@microsoft/rush-lib** module instance as the plugin host. + +2. **Unit tests:** When authoring unit tests (for a Rush plugin, for example), developers should add **@microsoft/rush-lib** to their **package.json** `devDependencies` and add **@rushstack/rush-sdk** to the regular `dependencies`. In this context, **@rushstack/rush-sdk** will resolve to the locally installed instance for testing purposes. + +3. **Rush subprocesses:** For tools within a monorepo that import **@rushstack/rush-sdk** during their build process, child processes will inherit the installation of Rush that invoked them. This is communicated using the `_RUSH_LIB_PATH` environment variable. + +4. **Monorepo tools:** For scripts and tools that are designed to be used in a Rush monorepo, **@rushstack/rush-sdk** will automatically invoke **install-run-rush.js** and load the local installation. This ensures that tools load a compatible version of the Rush engine for the given branch. + +5. **Advanced scenarios:** The secondary `@rushstack/rush-sdk/loader` entry point can be imported by tools that need to explicitly control where **@microsoft/rush-lib** gets loaded from. This API also allows monitoring installation and canceling the operation. This API is used by the Rush Stack VS Code extension, for example. + +The **@rushstack/rush-sdk** API declarations are identical to the corresponding version of **@microsoft/rush-lib**. + +## Basic usage + +Here's an example of basic usage that works with cases 1-4 above: + +```ts +// CommonJS notation: +const { RushConfiguration } = require('@rushstack/rush-sdk'); + +const config = RushConfiguration.loadFromDefaultLocation(); +console.log(config.commonFolder); +``` + +```ts +// TypeScript notation: +import { RushConfiguration } from '@rushstack/rush-sdk'; + +const config = RushConfiguration.loadFromDefaultLocation(); +console.log(config.commonFolder); +``` + +## Loader API + +Here's a basic example of how to manually load **@rushstack/rush-sdk** and monitor installation progress: + +```ts +import { RushSdkLoader, ISdkCallbackEvent } from '@rushstack/rush-sdk/loader'; + +if (!RushSdkLoader.isLoaded) { + await RushSdkLoader.loadAsync({ + // the search for rush.json starts here: + rushJsonSearchFolder: "path/to/my-repo/apps/my-app", + + onNotifyEvent: (event: ISdkCallbackEvent) => { + if (event.logMessage) { + // Your tool can show progress about the loading: + if (event.logMessage.kind === 'info') { + console.log(event.logMessage.text); + } + } + } + }); +} + +// Any subsequent attempts to call require() will return the same instance +// that was loaded above. +const rushSdk = require('@rushstack/rush-sdk'); +const config = rushSdk.RushConfiguration.loadFromDefaultLocation(); +``` + +Here's a more elaborate example illustrating other API features: + +```ts +import { RushSdkLoader, ISdkCallbackEvent } from '@rushstack/rush-sdk/loader'; + +// Use an AbortController to cancel the operation after a certain time period +const abortController = new AbortController(); +setTimeout(() => { + abortController.abort(); +}, 1000); + +if (!RushSdkLoader.isLoaded) { + await RushSdkLoader.loadAsync({ + // the search for rush.json starts here: + rushJsonSearchFolder: "path/to/my-repo/apps/my-app", + + abortSignal: abortController.signal, + + onNotifyEvent: (event: ISdkCallbackEvent) => { + if (event.logMessage) { + // Your tool can show progress about the loading: + if (event.logMessage.kind === 'info') { + console.log(event.logMessage.text); + } + } + + if (event.progressPercent !== undefined) { + // If installation takes a long time, your tool can display a progress bar + displayYourProgressBar(event.progressPercent); + } + } + }); +} + +// Any subsequent attempts to call require() will return the same instance +// that was loaded above. +const rushSdk = require('@rushstack/rush-sdk'); +const config = rushSdk.RushConfiguration.loadFromDefaultLocation(); +``` + + +## Importing internal APIs + +Backwards compatibility is only guaranteed for the APIs marked as `@public` in the official `rush-lib.d.ts` entry point. +However, sometimes it is expedient for a script to import internal modules from `@microsoft/rush-lib` to access +unofficial APIs. This practice faces a technical challenge that `@microsoft/rush-lib` is bundled using Webpack. +The `@rushstack/rush-sdk` package provides stub files that import the corresponding internal module from the +Webpack bundle, via the `@rushstack/webpack-deep-imports-plugin` mechanism. + +> **WARNING:** If the loaded `rush-lib` package has a different version from `rush-sdk`, there is +> no guarantee that the corresponding path will exist or have the same type signature. +> Access internal APIs at your own risk. If you find an internal API to be useful, we recommend +> that you create a GitHub issue proposing to make it public. + +Example 1: Conventional import of a public API: + +```ts +// THIS IS THE RECOMMENDED PRACTICE: +import { RushConfiguration } from '@rushstack/rush-sdk'; +const config = RushConfiguration.loadFromDefaultLocation(); +console.log(config.commonFolder); +``` + +Example 2: How to import an internal API: + +```ts +// WARNING: INTERNAL APIS MAY CHANGE AT ANY TIME -- USE THIS AT YOUR OWN RISK: + +// Important: Since we're calling an internal API, we need to use the unbundled .d.ts files +// instead of the normal .d.ts rollup, otherwise TypeScript will complain about a type mismatch. +import { RushConfiguration } from '@rushstack/rush-sdk/lib/index'; +const config = RushConfiguration.loadFromDefaultLocation(); +console.log(config.commonFolder); + +// Load an internal module from the Webpack bundle using a path-based import of a stub file: +import { GitEmailPolicy } from '@rushstack/rush-sdk/lib/logic/policy/GitEmailPolicy'; +console.log(GitEmailPolicy.getEmailExampleLines(config)); +``` + +## Debugging + +Verbose logging can be enabled by setting environment variable `RUSH_SDK_DEBUG=1`. + +## Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/apps/rush/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-sdk/config/api-extractor.json b/libraries/rush-sdk/config/api-extractor.json new file mode 100644 index 00000000000..6ac06d0c07e --- /dev/null +++ b/libraries/rush-sdk/config/api-extractor.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib-commonjs/loader.d.ts", + + "apiReport": { + "enabled": true, + "reportFolder": "../../../common/reviews/api" + }, + + "docModel": { + "enabled": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true, + "publicTrimmedFilePath": "/dist/loader.d.ts" + } +} diff --git a/libraries/rush-sdk/config/heft.json b/libraries/rush-sdk/config/heft.json new file mode 100644 index 00000000000..328e456a115 --- /dev/null +++ b/libraries/rush-sdk/config/heft.json @@ -0,0 +1,55 @@ +/** + * 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", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["lib-shim", "lib-esnext"] }], + + "tasksByName": { + "copy-rush-lib-types": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "./node_modules/@microsoft/rush-lib/dist", + "includeGlobs": ["rush-lib.d.ts"], + "destinationFolders": ["dist"] + } + ] + } + } + }, + + "typescript": { + "taskDependencies": ["copy-rush-lib-types"] + }, + + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + }, + + "generate-stubs": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./lib-commonjs/generate-stubs.js" + } + } + } + } + } + } +} diff --git a/libraries/rush-sdk/config/jest.config.json b/libraries/rush-sdk/config/jest.config.json new file mode 100644 index 00000000000..62da56b72ce --- /dev/null +++ b/libraries/rush-sdk/config/jest.config.json @@ -0,0 +1,17 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json", + + "roots": ["/lib-shim"], + + "testMatch": ["/lib-shim/**/*.test.js"], + + "collectCoverageFrom": [ + "lib-shim/**/*.js", + "!lib-shim/**/*.d.ts", + "!lib-shim/**/*.test.js", + "!lib-shim/**/test/**", + "!lib-shim/**/__tests__/**", + "!lib-shim/**/__fixtures__/**", + "!lib-shim/**/__mocks__/**" + ] +} diff --git a/libraries/rush-sdk/config/rig.json b/libraries/rush-sdk/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rush-sdk/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-sdk/config/rush-project.json b/libraries/rush-sdk/config/rush-project.json new file mode 100644 index 00000000000..aa8aa5984cf --- /dev/null +++ b/libraries/rush-sdk/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$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"] + } + ] +} diff --git a/libraries/rush-sdk/config/typescript.json b/libraries/rush-sdk/config/typescript.json new file mode 100644 index 00000000000..587de5fc0f8 --- /dev/null +++ b/libraries/rush-sdk/config/typescript.json @@ -0,0 +1,12 @@ +{ + "$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/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 new file mode 100644 index 00000000000..ca684482236 --- /dev/null +++ b/libraries/rush-sdk/package.json @@ -0,0 +1,63 @@ +{ + "name": "@rushstack/rush-sdk", + "version": "5.163.0", + "description": "An API for interacting with the Rush engine", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/rush-sdk" + }, + "homepage": "https://rushjs.io", + "main": "lib-shim/index.js", + "typings": "dist/rush-lib.d.ts", + "exports": { + ".": { + "types": "./dist/rush-lib.d.ts", + "default": "./lib-shim/index.js" + }, + "./loader": { + "types": "./dist/loader.d.ts", + "default": "./lib-shim/loader.js" + }, + "./lib/*": { + "types": "./lib/*.d.ts", + "default": "./lib/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "loader": [ + "./dist/loader.d.ts" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "license": "MIT", + "dependencies": { + "@pnpm/lockfile.types": "~1.0.3", + "@rushstack/credential-cache": "workspace:*", + "@rushstack/lookup-by-path": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/package-deps-hash": "workspace:*", + "@rushstack/terminal": "workspace:*", + "tapable": "2.2.1" + }, + "devDependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "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.8", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.98.0" + } +} diff --git a/libraries/rush-sdk/src/generate-stubs.ts b/libraries/rush-sdk/src/generate-stubs.ts new file mode 100644 index 00000000000..c25cce990cc --- /dev/null +++ b/libraries/rush-sdk/src/generate-stubs.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 * as path from 'node:path'; + +import { FileSystem, Import, Path } from '@rushstack/node-core-library'; + +function generateLibFilesRecursively(options: { + parentSourcePath: string; + parentTargetPath: 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); + + if (folderItem.isDirectory()) { + // create destination folder + FileSystem.ensureEmptyFolder(targetPath); + generateLibFilesRecursively({ + parentSourcePath: sourcePath, + parentTargetPath: targetPath, + parentSrcImportPathWithSlash: options.parentSrcImportPathWithSlash + folderItem.name + '/', + libShimIndexPath: options.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});` + ); + } + } + } +} + +// Entry point invoked by "runScript" action from config/heft.json +export async function runAsync(): Promise { + const rushLibFolder: string = Import.resolvePackage({ + baseFolderPath: __dirname, + 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, + parentSrcImportPathWithSlash: '', + libShimIndexPath: path.join(__dirname, '../lib-shim/index') + }); + // eslint-disable-next-line no-console + console.log('generate-stubs: Completed successfully.'); +} diff --git a/libraries/rush-sdk/src/helpers.ts b/libraries/rush-sdk/src/helpers.ts new file mode 100644 index 00000000000..58266cf579c --- /dev/null +++ b/libraries/rush-sdk/src/helpers.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 * as path from 'node:path'; + +import { Import, FileSystem } from '@rushstack/node-core-library'; +import type { EnvironmentVariableNames } from '@microsoft/rush-lib'; + +export const RUSH_LIB_NAME: '@microsoft/rush-lib' = '@microsoft/rush-lib'; +export const RUSH_LIB_PATH_ENV_VAR_NAME: typeof EnvironmentVariableNames._RUSH_LIB_PATH = '_RUSH_LIB_PATH'; + +export type RushLibModuleType = Record; + +export interface ISdkContext { + rushLibModule: RushLibModuleType | undefined; +} + +export const sdkContext: ISdkContext = { + rushLibModule: undefined +}; + +/** + * Find the rush.json location and return the path, or undefined if a rush.json can't be found. + * + * @privateRemarks + * Keep this in sync with `RushConfiguration.tryFindRushJsonLocation`. + */ +export function tryFindRushJsonLocation(startingFolder: string): string | undefined { + let currentFolder: string = startingFolder; + + // Look upwards at parent folders until we find a folder containing rush.json + for (let i: number = 0; i < 10; ++i) { + const rushJsonFilename: string = path.join(currentFolder, 'rush.json'); + + if (FileSystem.exists(rushJsonFilename)) { + return rushJsonFilename; + } + + const parentFolder: string = path.dirname(currentFolder); + if (parentFolder === currentFolder) { + break; + } + + currentFolder = parentFolder; + } + + return undefined; +} + +export function _require(moduleName: string): TResult { + if (typeof __non_webpack_require__ === 'function') { + // If this library has been bundled with Webpack, we need to call the real `require` function + // that doesn't get turned into a `__webpack_require__` statement. + // `__non_webpack_require__` is a Webpack macro that gets turned into a `require` statement + // during bundling. + return __non_webpack_require__(moduleName); + } else { + return require(moduleName); + } +} + +/** + * Require `@microsoft/rush-lib` under the specified folder path. + */ +export function requireRushLibUnderFolderPath(folderPath: string): RushLibModuleType { + const rushLibModulePath: string = Import.resolveModule({ + modulePath: RUSH_LIB_NAME, + baseFolderPath: folderPath + }); + + return _require(rushLibModulePath); +} diff --git a/libraries/rush-sdk/src/index.ts b/libraries/rush-sdk/src/index.ts new file mode 100644 index 00000000000..d42a1398b91 --- /dev/null +++ b/libraries/rush-sdk/src/index.ts @@ -0,0 +1,241 @@ +// 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 { SpawnSyncReturns } from 'node:child_process'; + +import { + JsonFile, + type JsonObject, + type IPackageJson, + PackageJsonLookup, + Executable +} from '@rushstack/node-core-library'; +import { Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; +import { RushGlobalFolder } from '@microsoft/rush-lib/lib-esnext/api/RushGlobalFolder'; + +import { + RUSH_LIB_NAME, + RUSH_LIB_PATH_ENV_VAR_NAME, + type RushLibModuleType, + _require, + requireRushLibUnderFolderPath, + tryFindRushJsonLocation, + sdkContext +} from './helpers'; + +const verboseEnabled: boolean = + typeof process !== 'undefined' && + (process.env.RUSH_SDK_DEBUG === '1' || process.env._RUSH_SDK_DEBUG === '1'); +const terminal: Terminal = new Terminal( + new ConsoleTerminalProvider({ + verboseEnabled + }) +); + +declare const global: typeof globalThis & { + ___rush___rushLibModule?: RushLibModuleType; + ___rush___rushLibModuleFromEnvironment?: RushLibModuleType; + ___rush___rushLibModuleFromRushGlobalFolder?: RushLibModuleType; + ___rush___rushLibModuleFromInstallAndRunRush?: RushLibModuleType; +}; + +let errorMessage: string = ''; + +// SCENARIO 1: Rush's PluginManager has initialized "rush-sdk" with Rush's own instance of rush-lib. +// The Rush host process will assign "global.___rush___rushLibModule" before loading the plugin. +if (sdkContext.rushLibModule === undefined) { + sdkContext.rushLibModule = + global.___rush___rushLibModule || + global.___rush___rushLibModuleFromEnvironment || + global.___rush___rushLibModuleFromRushGlobalFolder || + global.___rush___rushLibModuleFromInstallAndRunRush; +} + +// SCENARIO 2: The project importing "rush-sdk" has installed its own instance of "rush-lib" +// as a package.json dependency. For example, this is used by the Jest tests for Rush plugins. +if (sdkContext.rushLibModule === undefined) { + const importingPath: string | null | undefined = module?.parent?.filename; + if (importingPath) { + const callerPackageFolder: string | undefined = + PackageJsonLookup.instance.tryGetPackageFolderFor(importingPath); + + if (callerPackageFolder !== undefined) { + const callerPackageJson: IPackageJson = _require(path.join(callerPackageFolder, 'package.json')); + + // Does the caller properly declare a dependency on rush-lib? + if ( + (callerPackageJson.dependencies && callerPackageJson.dependencies[RUSH_LIB_NAME] !== undefined) || + (callerPackageJson.devDependencies && + callerPackageJson.devDependencies[RUSH_LIB_NAME] !== undefined) || + (callerPackageJson.peerDependencies && + callerPackageJson.peerDependencies[RUSH_LIB_NAME] !== undefined) + ) { + // Try to resolve rush-lib from the caller's folder + terminal.writeVerboseLine(`Try to load ${RUSH_LIB_NAME} from caller package`); + try { + sdkContext.rushLibModule = requireRushLibUnderFolderPath(callerPackageFolder); + } catch (error) { + // If we fail to resolve it, ignore the error + terminal.writeVerboseLine(`Failed to load ${RUSH_LIB_NAME} from caller package`); + } + + // If two different libraries invoke `rush-sdk`, and one of them provides "rush-lib" + // then the first version to be loaded wins. We do not support side-by-side instances of "rush-lib". + if (sdkContext.rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModule = sdkContext.rushLibModule; + terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} from caller`); + } + } + } + } +} + +// SCENARIO 3: A tool or script has been invoked as a child process by an instance of "rush-lib" and can use the +// version that invoked it. In this case, use process.env._RUSH_LIB_PATH to find "rush-lib". +if (sdkContext.rushLibModule === undefined) { + const rushLibPath: string | undefined = process.env[RUSH_LIB_PATH_ENV_VAR_NAME]; + if (rushLibPath) { + terminal.writeVerboseLine( + `Try to load ${RUSH_LIB_NAME} from process.env.${RUSH_LIB_PATH_ENV_VAR_NAME} from caller package` + ); + try { + sdkContext.rushLibModule = _require(rushLibPath); + } catch (error) { + // Log this as a warning, since it is unexpected to define an incorrect value of the variable. + terminal.writeWarningLine( + `Failed to load ${RUSH_LIB_NAME} via process.env.${RUSH_LIB_PATH_ENV_VAR_NAME}` + ); + } + + if (sdkContext.rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModuleFromEnvironment = sdkContext.rushLibModule; + terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} from process.env.${RUSH_LIB_PATH_ENV_VAR_NAME}`); + } + } +} + +// SCENARIO 4: A standalone tool or script depends on "rush-sdk", and is meant to be used inside a monorepo folder. +// In this case, we can first load the rush-lib version in rush global folder. If the expected version is not installed, +// using install-run-rush.js to obtain the appropriate rush-lib version for the monorepo. +if (sdkContext.rushLibModule === undefined) { + try { + const rushJsonPath: string | undefined = tryFindRushJsonLocation(process.cwd()); + if (!rushJsonPath) { + throw new Error( + 'Unable to find rush.json in the current folder or its parent folders.\n' + + 'This tool is meant to be invoked from a working directory inside a Rush repository.' + ); + } + const monorepoRoot: string = path.dirname(rushJsonPath); + + const rushJson: JsonObject = JsonFile.load(rushJsonPath); + const { rushVersion } = rushJson; + + try { + 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}`; + terminal.writeVerboseLine( + `The expected global rush installed folder is "${expectedGlobalRushInstalledFolder}"` + ); + sdkContext.rushLibModule = requireRushLibUnderFolderPath(expectedGlobalRushInstalledFolder); + } catch (e) { + terminal.writeVerboseLine(`Failed to load ${RUSH_LIB_NAME} from rush global folder: ${e.message}`); + } + + if (sdkContext.rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModuleFromRushGlobalFolder = sdkContext.rushLibModule; + terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} installed from rush global folder`); + } else { + const installRunNodeModuleFolder: string = `${monorepoRoot}/common/temp/install-run/@microsoft+rush@${rushVersion}`; + + try { + // First, try to load the version of "rush-lib" that was installed by install-run-rush.js + terminal.writeVerboseLine(`Trying to load ${RUSH_LIB_NAME} installed by install-run-rush`); + sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder); + } catch (e1) { + let installAndRunRushStderrContent: string = ''; + try { + const installAndRunRushJSPath: string = `${monorepoRoot}/common/scripts/install-run-rush.js`; + + terminal.writeLine('The Rush engine has not been installed yet. Invoking install-run-rush.js...'); + + const installAndRunRushProcess: SpawnSyncReturns = Executable.spawnSync( + 'node', + [installAndRunRushJSPath, '--help'], + { + stdio: 'pipe' + } + ); + + installAndRunRushStderrContent = installAndRunRushProcess.stderr; + if (installAndRunRushProcess.status !== 0) { + throw new Error(`The ${RUSH_LIB_NAME} package failed to install`); + } + + // Retry to load "rush-lib" after install-run-rush run + terminal.writeVerboseLine( + `Trying to load ${RUSH_LIB_NAME} installed by install-run-rush a second time` + ); + sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder); + } catch (e2) { + // eslint-disable-next-line no-console + console.error(`${installAndRunRushStderrContent}`); + throw new Error(`The ${RUSH_LIB_NAME} package failed to load`); + } + } + + if (sdkContext.rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModuleFromInstallAndRunRush = sdkContext.rushLibModule; + terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} installed by install-run-rush`); + } + } + } catch (e) { + // no-catch + errorMessage = (e as Error).message; + } +} + +if (sdkContext.rushLibModule === undefined) { + // This error indicates that a project is trying to import "@rushstack/rush-sdk", but the Rush engine + // instance cannot be found. If you are writing Jest tests for a Rush plugin, add "@microsoft/rush-lib" + // to the devDependencies for your project. + // eslint-disable-next-line no-console + console.error(`Error: The @rushstack/rush-sdk package was not able to load the Rush engine: +${errorMessage} +`); + process.exit(1); +} + +// Based on TypeScript's __exportStar() +for (const property in sdkContext.rushLibModule) { + if (property !== 'default' && !exports.hasOwnProperty(property)) { + const rushLibModuleForClosure: RushLibModuleType = sdkContext.rushLibModule; + + // Based on TypeScript's __createBinding() + Object.defineProperty(exports, property, { + enumerable: true, + get: function () { + return rushLibModuleForClosure[property]; + } + }); + } +} + +/** + * Used by the .js stubs for path-based imports of `@microsoft/rush-lib` internal APIs. + */ +export function _rushSdk_loadInternalModule(srcImportPath: string): unknown { + if (!exports._RushInternals) { + throw new Error( + `Rush version ${exports.Rush.version} does not support internal API imports via rush-sdk` + ); + } + return exports._RushInternals.loadModule(srcImportPath); +} diff --git a/libraries/rush-sdk/src/loader.ts b/libraries/rush-sdk/src/loader.ts new file mode 100644 index 00000000000..c3357278664 --- /dev/null +++ b/libraries/rush-sdk/src/loader.ts @@ -0,0 +1,287 @@ +// 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 { SpawnSyncReturns } from 'node:child_process'; + +import { JsonFile, type JsonObject, Executable } from '@rushstack/node-core-library'; + +import { + tryFindRushJsonLocation, + RUSH_LIB_NAME, + type RushLibModuleType, + requireRushLibUnderFolderPath, + sdkContext +} from './helpers'; + +declare const global: typeof globalThis & { + ___rush___rushLibModule?: RushLibModuleType; + ___rush___rushLibModuleFromEnvironment?: RushLibModuleType; + ___rush___rushLibModuleFromInstallAndRunRush?: RushLibModuleType; +}; + +/** + * Type of {@link ISdkCallbackEvent.logMessage} + * @public + */ +export interface IProgressBarCallbackLogMessage { + /** + * A status message to print in the log window, or `undefined` if there are + * no further messages. This string may contain newlines. + */ + text: string; + + /** + * The type of message. More message types may be added in the future. + */ + kind: 'info' | 'debug'; +} + +/** + * Event options for {@link ILoadSdkAsyncOptions.onNotifyEvent} + * @public + */ +export interface ISdkCallbackEvent { + /** + * Allows the caller to display log information about the operation. + */ + logMessage: IProgressBarCallbackLogMessage | undefined; + + /** + * Allows the caller to display a progress bar for long-running operations. + * + * @remarks + * If a long-running operation is required, then `progressPercent` will + * start at 0.0 and count upwards and finish at 100.0 if the operation completes + * successfully. If the long-running operation has not yet started, or + * is not required, then the value will be `undefined`. + */ + progressPercent: number | undefined; +} + +/** + * Type of {@link ILoadSdkAsyncOptions.onNotifyEvent} + * @public + */ +export type SdkNotifyEventCallback = (sdkEvent: ISdkCallbackEvent) => void; + +/** + * Options for {@link RushSdkLoader.loadAsync} + * @public + */ +export interface ILoadSdkAsyncOptions { + /** + * The folder to start from when searching for the Rush workspace configuration. + * If this folder does not contain a `rush.json` file, then each parent folder + * will be searched. If `rush.json` is not found, then the SDK fails to load. + */ + rushJsonSearchFolder?: string; + + /** + * A cancellation token that the caller can use to prematurely abort the operation. + */ + abortSignal?: AbortSignal; + + /** + * Allows the caller to monitor the progress of the operation. + */ + onNotifyEvent?: SdkNotifyEventCallback; +} + +/** + * Exposes operations that control how the `@microsoft/rush-lib` engine is + * located and loaded. + * @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. + */ + public static get isLoaded(): boolean { + return sdkContext.rushLibModule !== undefined; + } + + /** + * Manually load the Rush engine based on rush.json found for `rushJsonSearchFolder`. + * Throws an exception if {@link RushSdkLoader.isLoaded} is already `true`. + * + * @remarks + * This API supports an callback that can be used display a progress bar, + * log of operations, and allow the operation to be canceled prematurely. + */ + public static async loadAsync(options?: ILoadSdkAsyncOptions): Promise { + // SCENARIO 5: The rush-lib engine is loaded manually using rushSdkLoader.loadAsync(). + + if (!options) { + options = {}; + } + + if (RushSdkLoader.isLoaded) { + throw new Error('RushSdkLoader.loadAsync() failed because the Rush engine has already been loaded'); + } + + const onNotifyEvent: SdkNotifyEventCallback | undefined = options.onNotifyEvent; + let progressPercent: number | undefined = undefined; + + const abortSignal: AbortSignal | undefined = options.abortSignal; + + try { + const rushJsonSearchFolder: string = options.rushJsonSearchFolder ?? process.cwd(); + + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'debug', + text: `Searching for rush.json starting from: ` + rushJsonSearchFolder + }, + progressPercent + }); + } + + const rushJsonPath: string | undefined = tryFindRushJsonLocation(rushJsonSearchFolder); + if (!rushJsonPath) { + throw new Error( + 'Unable to find rush.json in the specified folder or its parent folders:\n' + + `${rushJsonSearchFolder}\n` + ); + } + const monorepoRoot: string = path.dirname(rushJsonPath); + + const rushJson: JsonObject = await JsonFile.loadAsync(rushJsonPath); + const { rushVersion } = rushJson; + + const installRunNodeModuleFolder: string = path.join( + monorepoRoot, + `common/temp/install-run/@microsoft+rush@${rushVersion}` + ); + + try { + // First, try to load the version of "rush-lib" that was installed by install-run-rush.js + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'info', + text: `Trying to load ${RUSH_LIB_NAME} installed by install-run-rush` + }, + progressPercent + }); + } + sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder); + } catch (e1) { + let installAndRunRushStderrContent: string = ''; + try { + const installAndRunRushJSPath: string = path.join( + monorepoRoot, + 'common/scripts/install-run-rush.js' + ); + + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'info', + text: 'The Rush engine has not been installed yet. Invoking install-run-rush.js...' + }, + progressPercent + }); + } + + // Start the installation + progressPercent = 0; + + const installAndRunRushProcess: SpawnSyncReturns = Executable.spawnSync( + 'node', + [installAndRunRushJSPath, '--help'], + { + stdio: 'pipe' + } + ); + + installAndRunRushStderrContent = installAndRunRushProcess.stderr; + if (installAndRunRushProcess.status !== 0) { + throw new Error(`The ${RUSH_LIB_NAME} package failed to install`); + } + + if (abortSignal) { + RushSdkLoader._checkForCancel(abortSignal, onNotifyEvent, progressPercent); + } + + // TODO: Implement incremental progress updates + progressPercent = 90; + + // Retry to load "rush-lib" after install-run-rush run + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'debug', + text: `Trying to load ${RUSH_LIB_NAME} installed by install-run-rush a second time` + }, + progressPercent + }); + } + + sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder); + + progressPercent = 100; + } catch (e2) { + // eslint-disable-next-line no-console + console.error(`${installAndRunRushStderrContent}`); + throw new Error(`The ${RUSH_LIB_NAME} package failed to load`); + } + } + + if (sdkContext.rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModuleFromInstallAndRunRush = sdkContext.rushLibModule; + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'debug', + text: `Loaded ${RUSH_LIB_NAME} installed by install-run-rush` + }, + progressPercent + }); + } + } + } catch (e) { + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'info', + text: 'The operation failed: ' + (e.message ?? 'An unknown error occurred') + }, + progressPercent + }); + } + throw e; + } + } +} diff --git a/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap new file mode 100644 index 00000000000..77607c81853 --- /dev/null +++ b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`@rushstack/rush-sdk Should load via env when Rush has loaded (for child processes): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via env when Rush has loaded (for child processes): stdout 1`] = ` +"Try to load @microsoft/rush-lib from process.env._RUSH_LIB_PATH from caller package +Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH +[ + 'ApprovedPackagesConfiguration', + 'ApprovedPackagesItem', + 'ApprovedPackagesPolicy', + 'BuildCacheConfiguration', + 'BumpType', + 'ChangeManager', + 'CobuildConfiguration', + 'CommonVersionsConfiguration', + 'CredentialCache', + 'CustomTipId', + 'CustomTipSeverity', + 'CustomTipType', + 'CustomTipsConfiguration', + 'DependencyType', + 'EnvironmentConfiguration', + 'EnvironmentVariableNames', + 'Event', + 'EventHooks', + 'ExperimentsConfiguration', + 'FileSystemBuildCacheProvider', + 'IndividualVersionPolicy', + 'LockStepVersionPolicy', + 'LookupByPath', + 'NpmOptionsConfiguration', + 'Operation', + 'OperationStatus', + 'PackageJsonDependency', + 'PackageJsonDependencyMeta', + 'PackageJsonEditor', + 'PackageManager', + 'PackageManagerOptionsConfigurationBase', + 'PhasedCommandHooks', + 'PnpmOptionsConfiguration', + 'ProjectChangeAnalyzer', + 'RepoStateFile', + 'Rush', + 'RushCommandLine', + 'RushConfiguration', + 'RushConfigurationProject', + 'RushConstants', + 'RushLifecycleHooks', + 'RushProjectConfiguration', + 'RushSession', + 'RushUserConfiguration', + 'Subspace', + 'SubspacesConfiguration', + 'VersionPolicy', + 'VersionPolicyConfiguration', + 'VersionPolicyDefinitionName', + 'YarnOptionsConfiguration', + '_FlagFile', + '_OperationMetadataManager', + '_OperationStateFile', + '_RushGlobalFolder', + '_RushInternals', + '_rushSdk_loadInternalModule' +]" +`; + +exports[`@rushstack/rush-sdk Should load via global (for plugins): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via global (for plugins): stdout 1`] = ` +"[ + '_rushSdk_loadInternalModule', + 'foo' +]" +`; + +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 +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`] = `""`; + +exports[`@rushstack/rush-sdk Should load via process.env._RUSH_LIB_PATH (for child processes): stdout 1`] = ` +"Try to load @microsoft/rush-lib from process.env._RUSH_LIB_PATH from caller package +Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH +[ + '_rushSdk_loadInternalModule', + 'foo' +]" +`; diff --git a/libraries/rush-sdk/src/test/fixture/mock-rush-lib.ts b/libraries/rush-sdk/src/test/fixture/mock-rush-lib.ts new file mode 100644 index 00000000000..b6ba64a3a23 --- /dev/null +++ b/libraries/rush-sdk/src/test/fixture/mock-rush-lib.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 foo: number = 42; diff --git a/libraries/rush-sdk/src/test/sandbox/mock-package/package.json b/libraries/rush-sdk/src/test/sandbox/mock-package/package.json new file mode 100644 index 00000000000..51db6f4855e --- /dev/null +++ b/libraries/rush-sdk/src/test/sandbox/mock-package/package.json @@ -0,0 +1,4 @@ +{ + "name": "mock-package", + "version": "0.0.1" +} diff --git a/libraries/rush-sdk/src/test/sandbox/rush.json b/libraries/rush-sdk/src/test/sandbox/rush.json new file mode 100644 index 00000000000..ca17cb2ea6b --- /dev/null +++ b/libraries/rush-sdk/src/test/sandbox/rush.json @@ -0,0 +1,10 @@ +{ + "pnpmVersion": "6.23.1", + "rushVersion": "5.57.0", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "repository": { + "url": "someFakeUrl" + }, + "projects": [] +} diff --git a/libraries/rush-sdk/src/test/script.test.ts b/libraries/rush-sdk/src/test/script.test.ts new file mode 100644 index 00000000000..d7c8b8d0de1 --- /dev/null +++ b/libraries/rush-sdk/src/test/script.test.ts @@ -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. + +import * as path from 'node:path'; +import { Executable } 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 mockRushLibPath: string = `${__dirname}/fixture/mock-rush-lib.js`; + +const coreLibPath: string = require.resolve('@rushstack/node-core-library'); +const quotedRushSdkPath: string = JSON.stringify(rushSdkPath); +const loadAndPrintRushSdkModule: string = `console.log(JSON.stringify(Object.keys(require(${quotedRushSdkPath})).sort(), undefined, 2).replace(/"/g, "'"));`; + +describe('@rushstack/rush-sdk', () => { + it('Should load via global (for plugins)', () => { + const result = Executable.spawnSync( + 'node', + [ + '-e', + ` +global.___rush___rushLibModule = { foo: 1 }; +${loadAndPrintRushSdkModule}` + ], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via env when Rush has loaded (for child processes)', () => { + const result = Executable.spawnSync( + 'node', + [ + '-e', + ` +require('@microsoft/rush-lib'); +${loadAndPrintRushSdkModule}` + ], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via process.env._RUSH_LIB_PATH (for child processes)', () => { + const result = Executable.spawnSync('node', ['-e', loadAndPrintRushSdkModule], { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: mockRushLibPath + } + }); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via install-run (for standalone tools)', () => { + const result = Executable.spawnSync( + 'node', + [ + '-e', + ` +const { Import } = require(${JSON.stringify(coreLibPath)}); +const originalResolveModule = Import.resolveModule; +const mockResolveModule = (options) => { + if (options.baseFolderPath.includes('install-run') && options.modulePath === '@microsoft/rush-lib') { + return ${JSON.stringify(mockRushLibPath)}; + } + return originalResolveModule(options); +} +Import.resolveModule = mockResolveModule; +${loadAndPrintRushSdkModule} +` + ], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); +}); diff --git a/libraries/rush-sdk/tsconfig.json b/libraries/rush-sdk/tsconfig.json new file mode 100644 index 00000000000..83f4fb550b8 --- /dev/null +++ b/libraries/rush-sdk/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "outDir": "lib-commonjs", + "types": [ + "node", + "heft-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 new file mode 100644 index 00000000000..b86d582f7a8 --- /dev/null +++ b/libraries/rush-sdk/webpack.config.js @@ -0,0 +1,70 @@ +/* eslint-env es6 */ +'use strict'; + +const { PackageJsonLookup } = require('@rushstack/node-core-library'); +const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); + +module.exports = () => { + const packageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); + + const externalDependencyNames = new Set([...Object.keys(packageJson.dependencies || {})]); + + // Explicitly exclude @microsoft/rush-lib + externalDependencyNames.delete('@microsoft/rush-lib'); + + 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` + }, + output: { + path: `${__dirname}/lib-shim`, + filename: '[name].js', + chunkFilename: 'chunks/[name].js', + library: { + type: 'commonjs2' + } + }, + optimization: { + flagIncludedChunks: true, + concatenateModules: true, + providedExports: true, + usedExports: true, + sideEffects: true, + removeAvailableModules: true, + minimize: false, + realContentHash: true, + innerGraph: true + }, + target: 'node', + plugins: [new PreserveDynamicRequireWebpackPlugin()], + externals: [ + ({ request }, callback) => { + let packageName; + let firstSlashIndex = request.indexOf('/'); + if (firstSlashIndex === -1) { + packageName = request; + } else if (request.startsWith('@')) { + let secondSlash = request.indexOf('/', firstSlashIndex + 1); + if (secondSlash === -1) { + packageName = request; + } else { + packageName = request.substring(0, secondSlash); + } + } else { + packageName = request.substring(0, firstSlashIndex); + } + + if (externalDependencyNames.has(packageName)) { + callback(null, `commonjs ${request}`); + } else { + callback(); + } + } + ] + }; +}; diff --git a/libraries/rush-themed-ui/.npmignore b/libraries/rush-themed-ui/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/rush-themed-ui/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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-themed-ui/LICENSE b/libraries/rush-themed-ui/LICENSE new file mode 100644 index 00000000000..e08fddbd337 --- /dev/null +++ b/libraries/rush-themed-ui/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rush-themed-ui + +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-themed-ui/README.md b/libraries/rush-themed-ui/README.md new file mode 100644 index 00000000000..9681cf99c86 --- /dev/null +++ b/libraries/rush-themed-ui/README.md @@ -0,0 +1,5 @@ +# @rushstack/rush-themed-ui + +**Rush Components** provides a suite of styled components that can be used in rush applications to ensure a consistent look and feel among all rushstack helper applications. + +Rush Components is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/rush-themed-ui/config/api-extractor.json b/libraries/rush-themed-ui/config/api-extractor.json new file mode 100644 index 00000000000..cafe285cb0d --- /dev/null +++ b/libraries/rush-themed-ui/config/api-extractor.json @@ -0,0 +1,427 @@ +/** + * 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", + + /** + * 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/config/jest.config.json b/libraries/rush-themed-ui/config/jest.config.json new file mode 100644 index 00000000000..a6a75a1a029 --- /dev/null +++ b/libraries/rush-themed-ui/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-web-rig/profiles/library/config/jest.config.json" +} diff --git a/libraries/rush-themed-ui/config/rig.json b/libraries/rush-themed-ui/config/rig.json new file mode 100644 index 00000000000..b7cba34165f --- /dev/null +++ b/libraries/rush-themed-ui/config/rig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-web-rig", + "rigProfile": "library" +} 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 new file mode 100644 index 00000000000..ca36b47ad30 --- /dev/null +++ b/libraries/rush-themed-ui/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/rush-themed-ui", + "description": "Rush Component Library: a set of themed components for rush projects", + "version": "0.0.0", + "private": true, + "license": "MIT", + "module": "dist/rush-themed-ui.js", + "types": "dist/rush-themed-ui.d.ts", + "scripts": { + "build": "heft test --clean", + "start": "heft build --watch", + "test": "heft test", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "react": "~17.0.2", + "react-dom": "~17.0.2" + }, + "devDependencies": { + "@radix-ui/colors": "~0.1.8", + "@radix-ui/react-checkbox": "~1.0.1", + "@radix-ui/react-icons": "~1.1.1", + "@radix-ui/react-scroll-area": "~1.0.2", + "@radix-ui/react-tabs": "~1.0.1", + "@rushstack/heft": "workspace:*", + "@types/react": "17.0.74", + "@types/react-dom": "17.0.25", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + } +} diff --git a/libraries/rush-themed-ui/src/components/Button/index.tsx b/libraries/rush-themed-ui/src/components/Button/index.tsx new file mode 100644 index 00000000000..f7ef0fad804 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Button/index.tsx @@ -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 React from 'react'; + +import { Text } from '../Text'; +import styles from './styles.scss'; + +/** + * React props for {@link Button} + * @public + */ +export interface IButtonProps { + children: JSX.Element | string; + disabled?: boolean; + onClick: () => void; +} + +/** + * A button UI component + * @public + */ +export const Button = ({ children, disabled = false, onClick }: IButtonProps): JSX.Element => { + return ( + + ); +}; diff --git a/libraries/rush-themed-ui/src/components/Button/styles.scss b/libraries/rush-themed-ui/src/components/Button/styles.scss new file mode 100644 index 00000000000..dd228bf74b2 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Button/styles.scss @@ -0,0 +1,17 @@ +@use '../../styles/colors'; + +.ButtonWrapper { + padding: 4px 8px; + border: 1px solid colors.$primary-active; + border-radius: 2px; + &:hover { + cursor: pointer; + background-color: colors.$primary-background; + } + &:disabled { + cursor: default; + background-color: colors.$background-primary; + color: colors.$gray; + border-color: colors.$secondary-active; + } +} diff --git a/libraries/rush-themed-ui/src/components/Checkbox/index.tsx b/libraries/rush-themed-ui/src/components/Checkbox/index.tsx new file mode 100644 index 00000000000..a0003820716 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Checkbox/index.tsx @@ -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 React from 'react'; +import * as RadixCheckbox from '@radix-ui/react-checkbox'; +import { CheckIcon } from '@radix-ui/react-icons'; + +import styles from './styles.scss'; + +/** + * React props for {@link Checkbox} + * @public + */ +export interface ICheckboxProps { + label: string; + isChecked: boolean; + onChecked: (checked: boolean) => void; +} + +/** + * A checkbox UI component + * @public + */ +export const Checkbox = ({ label, isChecked, onChecked }: ICheckboxProps): JSX.Element => ( +
+
+ + + + + + +
+
+); diff --git a/libraries/rush-themed-ui/src/components/Checkbox/styles.scss b/libraries/rush-themed-ui/src/components/Checkbox/styles.scss new file mode 100644 index 00000000000..1d67e3398a8 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Checkbox/styles.scss @@ -0,0 +1,33 @@ +@use '../../styles/colors'; + +/* reset */ +button { + all: unset; +} + +.CheckboxRoot { + background-color: white; + width: 25px; + min-width: 25px; + height: 25px; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid colors.$black; + cursor: pointer; +} +.CheckboxRoot:hover { + background-color: colors.$primary-background; +} + +.CheckboxIndicator { + color: colors.$primary-active; +} + +.Label { + padding-left: 15px; + font-size: 15px; + line-height: 1; + user-select: none; +} diff --git a/libraries/rush-themed-ui/src/components/Input/index.tsx b/libraries/rush-themed-ui/src/components/Input/index.tsx new file mode 100644 index 00000000000..6f4d7e2ab67 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Input/index.tsx @@ -0,0 +1,33 @@ +// 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 styles from './styles.scss'; + +/** + * React props for {@link Input} + * @public + */ +export interface IInputProps { + value: string; + onChange: (e: React.ChangeEvent) => void; + type?: string; + placeholder?: string; +} + +/** + * A text input box UI component + * @public + */ +export const Input = ({ value, placeholder, onChange, type = 'text' }: IInputProps): JSX.Element => { + return ( + + ); +}; diff --git a/libraries/rush-themed-ui/src/components/Input/styles.scss b/libraries/rush-themed-ui/src/components/Input/styles.scss new file mode 100644 index 00000000000..41c05e58483 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Input/styles.scss @@ -0,0 +1,7 @@ +@use '../../styles/colors'; + +.InputWrapper { + border: solid 1px colors.$gray; + border-radius: 4px; + padding: 0.4em; +} diff --git a/libraries/rush-themed-ui/src/components/ScrollArea/index.tsx b/libraries/rush-themed-ui/src/components/ScrollArea/index.tsx new file mode 100644 index 00000000000..88c19a3814a --- /dev/null +++ b/libraries/rush-themed-ui/src/components/ScrollArea/index.tsx @@ -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 React from 'react'; +import * as RadixScrollArea from '@radix-ui/react-scroll-area'; + +import styles from './styles.scss'; + +/** + * React props for {@link ScrollArea} + * @public + */ +export interface IScrollAreaProps { + children: React.ReactNode; +} + +/** + * A UI component for managing a scrollable area. + * @remarks + * + * The height of the scroll area's parent must be fixed. + * @public + */ +export const ScrollArea = ({ children }: IScrollAreaProps): JSX.Element => ( + + {children} + + + + + + + + +); diff --git a/libraries/rush-themed-ui/src/components/ScrollArea/styles.scss b/libraries/rush-themed-ui/src/components/ScrollArea/styles.scss new file mode 100644 index 00000000000..d20d04d2920 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/ScrollArea/styles.scss @@ -0,0 +1,61 @@ +@use '../../styles/colors'; + +.ScrollAreaRoot { + border-radius: 4px; + overflow: hidden; + --scrollbar-size: 6px; + height: 100%; +} + +.ScrollAreaViewport { + width: 100%; + height: 100%; + border-radius: inherit; + & > * { + padding-right: 8px; + } +} + +.ScrollAreaScrollbar { + display: flex; + /* ensures no selection */ + user-select: none; + /* disable browser handling of all panning and zooming gestures on touch devices */ + touch-action: none; + padding: 2px; + background: colors.$background-secondary; + transition: background 160ms ease-out; +} +.ScrollAreaScrollbar:hover { + background: colors.$background-secondary; +} +.ScrollAreaScrollbar[data-orientation='vertical'] { + width: var(--scrollbar-size); +} +.ScrollAreaScrollbar[data-orientation='horizontal'] { + flex-direction: column; + height: var(--scrollbar-size); +} + +.ScrollAreaThumb { + flex: 1; + background: colors.$primary-active; + border-radius: var(--scrollbar-size); + position: relative; +} +/* increase target size for touch devices https://www.w3.org/WAI/WCAG21/Understanding/target-size.html */ +.ScrollAreaThumb::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100%; + height: 100%; + min-width: 44px; + min-height: 44px; +} + +.ScrollAreaCorner { + background: colors.$background-secondary; +} diff --git a/libraries/rush-themed-ui/src/components/Tabs/index.tsx b/libraries/rush-themed-ui/src/components/Tabs/index.tsx new file mode 100644 index 00000000000..418dda17385 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Tabs/index.tsx @@ -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. + +import React from 'react'; +import * as RadixTabs from '@radix-ui/react-tabs'; + +import styles from './styles.scss'; + +/** + * React props for {@link Tabs} + * @public + */ +export interface ITabsItem { + header: string; + value?: string; + body?: React.ReactNode; +} + +/** + * React props for {@link Tabs} + * @public + */ +export interface ITabsProps { + items: ITabsItem[]; + def?: string; + value: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onChange?: (value: any) => void; + renderChildren?: () => JSX.Element; +} + +/** + * A tab control UI component + * @public + */ +export const Tabs = ({ items, def, value, onChange, renderChildren }: ITabsProps): JSX.Element => { + const getItemValue = (item: ITabsItem): string => (item.value === undefined ? item.header : item.value); + return ( + + + {items.map((item) => ( + + {item.header} + + ))} + + {renderChildren + ? renderChildren() + : items.map((item, index) => + item.body ? ( + + {item.body} + + ) : null + )} + + ); +}; diff --git a/libraries/rush-themed-ui/src/components/Tabs/styles.scss b/libraries/rush-themed-ui/src/components/Tabs/styles.scss new file mode 100644 index 00000000000..df736f80a23 --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Tabs/styles.scss @@ -0,0 +1,59 @@ +@use '../../styles/colors'; + +/* reset */ +button, +fieldset, +input { + all: unset; +} + +.TabsRoot { + display: flex; + flex-direction: column; + width: 100%; +} + +.TabsList { + flex-shrink: 0; + display: flex; + border-bottom: 1px solid colors.$primary-active; +} + +.TabsTrigger { + font-family: inherit; + padding: 0 20px; + height: 45px; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + font-size: 15px; + line-height: 1; + color: colors.$black; + user-select: none; +} +.TabsTrigger:hover { + color: colors.$primary-active; + cursor: pointer; +} +.TabsTrigger[data-state='active'] { + color: colors.$primary-active; + box-shadow: + inset 0 -1px 0 0 currentColor, + 0 1px 0 0 currentColor; +} +.TabsTrigger:focus { + position: relative; + box-shadow: 0 0 0 2px colors.$primary-active; +} + +.TabsContent { + flex-grow: 1; + padding: 12px; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + outline: none; +} +.TabsContent:focus { + box-shadow: 0 0 0 2px black; +} diff --git a/libraries/rush-themed-ui/src/components/Text/index.tsx b/libraries/rush-themed-ui/src/components/Text/index.tsx new file mode 100644 index 00000000000..a356167a19d --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Text/index.tsx @@ -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 React from 'react'; + +import styles from './styles.scss'; + +/** + * Indicates the type of HTML element used with {@link ITextProps}. + * @public + */ +export type TextType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span'; + +/** + * React props for {@link Text} + * @public + */ +export interface ITextProps { + type: TextType; + bold?: boolean; + children: React.ReactNode; + className?: string; + size?: number; +} + +/** + * A text box UI component + * @public + */ +export const Text = ({ type, bold = false, children, className, size }: ITextProps): JSX.Element => { + const generalStyles: { [key in string]: string | number } = { + ['fontWeight']: bold ? 'bold' : 'normal', + ...(size ? { fontSize: size } : {}) + }; + + switch (type) { + case 'h1': + return ( +

+ {children} +

+ ); + case 'h2': + return ( +

+ {children} +

+ ); + case 'h3': + return ( +

+ {children} +

+ ); + case 'h4': + return ( +

+ {children} +

+ ); + case 'h5': + return ( +
+ {children} +
+ ); + case 'h6': + return ( +
+ {children} +
+ ); + case 'p': + return ( +

+ {children} +

+ ); + case 'span': + return ( + + {children} + + ); + default: + return ( +

+ {children} +

+ ); + } +}; diff --git a/libraries/rush-themed-ui/src/components/Text/styles.scss b/libraries/rush-themed-ui/src/components/Text/styles.scss new file mode 100644 index 00000000000..41581bba7be --- /dev/null +++ b/libraries/rush-themed-ui/src/components/Text/styles.scss @@ -0,0 +1,59 @@ +@mixin TextStyles { + font-family: + system-ui, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Open Sans', + 'Helvetica Neue', + sans-serif; +} + +@mixin HeadingStyles { + font-weight: bold; + line-height: 1.2; + margin: 0; + @include TextStyles; +} + +.H1 { + @include HeadingStyles; + font-size: 24px; +} +.H2 { + @include HeadingStyles; + font-size: 21px; +} +.H3 { + @include HeadingStyles; + font-size: 19px; +} +.H4 { + @include HeadingStyles; + font-size: 16px; +} +.H5 { + @include HeadingStyles; + font-size: 14px; +} +.H6 { + @include HeadingStyles; + font-size: 12px; +} + +.ParagraphStyles { + @include TextStyles; + margin: 0; + font-weight: normal; + line-height: 1.5; + font-size: 14px; +} + +.SpanStyles { + @include TextStyles; + font-size: 12px; +} diff --git a/libraries/rush-themed-ui/src/index.ts b/libraries/rush-themed-ui/src/index.ts new file mode 100644 index 00000000000..03f9ce0a00d --- /dev/null +++ b/libraries/rush-themed-ui/src/index.ts @@ -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 is an internal library for use by Rush Stack apps. + * It provides a small set of reusable React UI components + * with a consistent theme. + * + * @remarks + * The implementation is based on the + * {@link https://www.radix-ui.com/ | Radix UI Primitives} framework. + * + * @packageDocumentation + */ + +export * from './components/Button'; +export * from './components/ScrollArea'; +export * from './components/Tabs'; +export * from './components/Checkbox'; +export * from './components/Input'; +export * from './components/Text'; diff --git a/libraries/rush-themed-ui/src/styles/_base.scss b/libraries/rush-themed-ui/src/styles/_base.scss new file mode 100644 index 00000000000..c8610b0ae5f --- /dev/null +++ b/libraries/rush-themed-ui/src/styles/_base.scss @@ -0,0 +1 @@ +$shadow: 0 2px 10px hsla(0, 0%, 0%, 0.141); diff --git a/libraries/rush-themed-ui/src/styles/_colors.scss b/libraries/rush-themed-ui/src/styles/_colors.scss new file mode 100644 index 00000000000..e7b9f8273f1 --- /dev/null +++ b/libraries/rush-themed-ui/src/styles/_colors.scss @@ -0,0 +1,10 @@ +$background-primary: white; +$background-secondary: #f3f2f1; + +$primary-active: #107c10; +$primary-background: #dff6dd; + +$secondary-active: #ab9e8e; + +$black: #000000; +$gray: #666; diff --git a/libraries/rush-themed-ui/tsconfig.json b/libraries/rush-themed-ui/tsconfig.json new file mode 100644 index 00000000000..2929ab3551a --- /dev/null +++ b/libraries/rush-themed-ui/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/app/tsconfig-base.json", + "compilerOptions": { + "lib": ["es2017", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + } +} diff --git a/libraries/rush-themed-ui/tsconfig.type.json b/libraries/rush-themed-ui/tsconfig.type.json new file mode 100644 index 00000000000..112edd30eb0 --- /dev/null +++ b/libraries/rush-themed-ui/tsconfig.type.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "emitDeclarationOnly": true + }, + "include": ["src/index.ts"] +} diff --git a/libraries/rush-themed-ui/webpack.config.js b/libraries/rush-themed-ui/webpack.config.js new file mode 100644 index 00000000000..3dc6a344989 --- /dev/null +++ b/libraries/rush-themed-ui/webpack.config.js @@ -0,0 +1,24 @@ +'use strict'; + +const createWebpackConfig = require('local-web-rig/profiles/library/webpack-base.config'); + +module.exports = function createConfig(env, argv) { + return createWebpackConfig({ + env: env, + argv: argv, + projectRoot: __dirname, + + // Documentation: https://webpack.js.org/configuration/ + configOverride: { + externals: ['react', 'react-dom', 'tslib'], + + performance: { + hints: env.production ? 'error' : false + // 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: 500000, + // maxAssetSize: 500000 + } + } + }); +}; diff --git a/libraries/rushell/.eslintrc.js b/libraries/rushell/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/libraries/rushell/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/rushell/.npmignore b/libraries/rushell/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/rushell/.npmignore +++ b/libraries/rushell/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/rushell/config/jest.config.json b/libraries/rushell/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/rushell/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/rushell/config/jest.json b/libraries/rushell/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/libraries/rushell/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/libraries/rushell/config/rig.json b/libraries/rushell/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rushell/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/rushell/eslint.config.js b/libraries/rushell/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rushell/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/rushell/gulpfile.js b/libraries/rushell/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/libraries/rushell/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/libraries/rushell/package.json b/libraries/rushell/package.json index 626031b04c0..9721b1fd440 100644 --- a/libraries/rushell/package.json +++ b/libraries/rushell/package.json @@ -4,40 +4,24 @@ "description": "Execute shell commands using a consistent syntax on every platform", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/rushell" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/rushell" }, "main": "lib/index.js", "typings": "dist/rushell.d.ts", "scripts": { - "build": "gulp test --clean", - "start": "jest --watch" + "build": "heft build --clean", + "start": "heft test --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "license": "MIT", "dependencies": { - "@rushstack/node-core-library": "3.19.5" + "@rushstack/node-core-library": "workspace:*" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "gulp": "~4.0.2", - "jest": "~23.6.0", - "ts-jest": "~22.4.6" - }, - "jest": { - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx" - ], - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testMatch": [ - "/src/**/*.test.ts" - ] + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/libraries/rushell/src/AstNode.ts b/libraries/rushell/src/AstNode.ts index 0f6d054bb91..570e2cbeb29 100644 --- a/libraries/rushell/src/AstNode.ts +++ b/libraries/rushell/src/AstNode.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 { Token } from './Tokenizer'; +import type { Token } from './Tokenizer'; import { TextRange } from './TextRange'; -export const enum AstKind { +export enum AstKind { None = 'None', Script = 'Script', AndIf = 'AndIf', diff --git a/libraries/rushell/src/ParseError.ts b/libraries/rushell/src/ParseError.ts index 8d340ccf21f..1b3c0cc646b 100644 --- a/libraries/rushell/src/ParseError.ts +++ b/libraries/rushell/src/ParseError.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 { TextRange, ITextLocation } from './TextRange'; +import type { TextRange, ITextLocation } from './TextRange'; /** * An Error subclass used to report errors that occur while parsing an input. @@ -28,7 +28,7 @@ export class ParseError extends Error { // Boilerplate for extending a system class // - // https://github.com/microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work + // https://github.com/microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work // // IMPORTANT: The prototype must also be set on any classes which extend this one (this as any).__proto__ = ParseError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any @@ -59,5 +59,4 @@ export class ParseError extends Error { } return message; } - } diff --git a/libraries/rushell/src/Parser.ts b/libraries/rushell/src/Parser.ts index a073dddce7f..c72f3f47914 100644 --- a/libraries/rushell/src/Parser.ts +++ b/libraries/rushell/src/Parser.ts @@ -2,14 +2,8 @@ // See LICENSE in the project root for license information. import { ParseError } from './ParseError'; -import { Tokenizer, Token, TokenKind } from './Tokenizer'; -import { - AstNode, - AstScript, - AstCommand, - AstCompoundWord, - AstText -} from './AstNode'; +import { type Tokenizer, type Token, TokenKind } from './Tokenizer'; +import { type AstNode, AstScript, AstCommand, AstCompoundWord, AstText } from './AstNode'; export class Parser { private readonly _tokenizer: Tokenizer; diff --git a/libraries/rushell/src/Rushell.ts b/libraries/rushell/src/Rushell.ts index 77a447026e1..086b4127c10 100644 --- a/libraries/rushell/src/Rushell.ts +++ b/libraries/rushell/src/Rushell.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 child_process from 'child_process'; +import type * as child_process from 'node:child_process'; + import { Executable } from '@rushstack/node-core-library'; -import { Parser } from './Parser'; +import { Parser } from './Parser'; import { Tokenizer } from './Tokenizer'; -import { AstNode, AstScript, AstKind, AstCommand } from './AstNode'; +import { type AstNode, type AstScript, AstKind, type AstCommand } from './AstNode'; import { ParseError } from './ParseError'; /** @@ -26,7 +27,6 @@ export interface IRushellExecuteResult { */ export class Rushell { public execute(script: string): IRushellExecuteResult { - const tokenizer: Tokenizer = new Tokenizer(script); const parser: Parser = new Parser(tokenizer); const astScript: AstScript = parser.parse(); @@ -37,7 +37,7 @@ export class Rushell { private _evaluateNode(astNode: AstNode): IRushellExecuteResult { switch (astNode.kind) { case AstKind.CompoundWord: - return { value: astNode.parts.map(x => this._evaluateNode(x).value).join('') }; + return { value: astNode.parts.map((x) => this._evaluateNode(x).value).join('') }; case AstKind.Text: return { value: astNode.token!.range.toString() }; case AstKind.Script: @@ -65,7 +65,7 @@ export class Rushell { } const commandPath: string = commandPathResult.value; - const commandArgs: string[] = commandArgResults.map(x => x.value); + const commandArgs: string[] = commandArgResults.map((x) => x.value); const result: child_process.SpawnSyncReturns = Executable.spawnSync(commandPath, commandArgs); diff --git a/libraries/rushell/src/TextRange.ts b/libraries/rushell/src/TextRange.ts index 068707196f7..b4fdc239884 100644 --- a/libraries/rushell/src/TextRange.ts +++ b/libraries/rushell/src/TextRange.ts @@ -143,12 +143,14 @@ export class TextRange { const current: string = this.buffer[currentIndex]; ++currentIndex; - if (current === '\r') { // CR + if (current === '\r') { + // CR // Ignore '\r' and assume it will always have an accompanying '\n' continue; } - if (current === '\n') { // LF + if (current === '\n') { + // LF ++line; column = 1; } else { diff --git a/libraries/rushell/src/Tokenizer.ts b/libraries/rushell/src/Tokenizer.ts index 381e337cac7..7585249b1ed 100644 --- a/libraries/rushell/src/Tokenizer.ts +++ b/libraries/rushell/src/Tokenizer.ts @@ -66,7 +66,7 @@ export class Tokenizer { private _currentIndex: number; public constructor(input: TextRange | string) { - if (typeof(input) === 'string') { + if (typeof input === 'string') { this.input = TextRange.fromString(input); } else { this.input = input; @@ -128,12 +128,16 @@ export class Tokenizer { let c: string | undefined = this._peekCharacter(); while (c !== '"') { if (c === undefined) { - throw new ParseError('The double-quoted string is missing the ending quote', - input.getNewRange(startIndex, this._currentIndex)); + throw new ParseError( + 'The double-quoted string is missing the ending quote', + input.getNewRange(startIndex, this._currentIndex) + ); } if (c === '\r' || c === '\n') { - throw new ParseError('Newlines are not supported inside strings', - input.getNewRange(this._currentIndex, this._currentIndex + 1)); + throw new ParseError( + 'Newlines are not supported inside strings', + input.getNewRange(this._currentIndex, this._currentIndex + 1) + ); } // NOTE: POSIX says that backslash acts as an escape character inside a double-quoted string @@ -147,8 +151,10 @@ export class Tokenizer { if (c === '\\') { this._readCharacter(); // discard the backslash if (this._peekCharacter() === undefined) { - throw new ParseError('A backslash must be followed by another character', - input.getNewRange(this._currentIndex, this._currentIndex + 1)); + throw new ParseError( + 'A backslash must be followed by another character', + input.getNewRange(this._currentIndex, this._currentIndex + 1) + ); } // Add the escaped character text += this._readCharacter(); @@ -171,8 +177,10 @@ export class Tokenizer { if (c === '\\') { this._readCharacter(); // discard the backslash if (this._peekCharacter() === undefined) { - throw new ParseError('A backslash must be followed by another character', - input.getNewRange(this._currentIndex, this._currentIndex + 1)); + throw new ParseError( + 'A backslash must be followed by another character', + input.getNewRange(this._currentIndex, this._currentIndex + 1) + ); } // Add the escaped character text += this._readCharacter(); @@ -192,8 +200,10 @@ export class Tokenizer { let name: string = this._readCharacter() || ''; if (!startVariableCharacterRegExp.test(name)) { - throw new ParseError('The "$" symbol must be followed by a letter or underscore', - input.getNewRange(startIndex, this._currentIndex)); + throw new ParseError( + 'The "$" symbol must be followed by a letter or underscore', + input.getNewRange(startIndex, this._currentIndex) + ); } let c: string | undefined = this._peekCharacter(); diff --git a/libraries/rushell/src/index.ts b/libraries/rushell/src/index.ts index 289e0ab64b2..495bd5a9377 100644 --- a/libraries/rushell/src/index.ts +++ b/libraries/rushell/src/index.ts @@ -7,7 +7,4 @@ * @packageDocumentation */ -export { - Rushell, - IRushellExecuteResult -} from './Rushell'; +export { Rushell, type IRushellExecuteResult } from './Rushell'; diff --git a/libraries/rushell/src/test/Parser.test.ts b/libraries/rushell/src/test/Parser.test.ts index 7130532bf3b..3656e06815f 100644 --- a/libraries/rushell/src/test/Parser.test.ts +++ b/libraries/rushell/src/test/Parser.test.ts @@ -3,13 +3,10 @@ import { Tokenizer } from '../Tokenizer'; import { Parser } from '../Parser'; -import { AstScript } from '../AstNode'; +import type { AstScript } from '../AstNode'; function escape(s: string): string { - return s.replace(/\n/g, '[n]') - .replace(/\r/g, '[r]') - .replace(/\t/g, '[t]') - .replace(/\\/g, '[b]'); + return s.replace(/\n/g, '[n]').replace(/\r/g, '[r]').replace(/\t/g, '[t]').replace(/\\/g, '[b]'); } function matchSnapshot(input: string): void { @@ -29,7 +26,7 @@ function matchErrorSnapshot(input: string): void { try { parser.parse(); } catch (e) { - error = e; + error = e as Error; } expect({ input: escape(tokenizer.input.toString()), diff --git a/libraries/rushell/src/test/TextRange.test.ts b/libraries/rushell/src/test/TextRange.test.ts index d46fe0988fb..c5b53f59320 100644 --- a/libraries/rushell/src/test/TextRange.test.ts +++ b/libraries/rushell/src/test/TextRange.test.ts @@ -4,17 +4,15 @@ import { TextRange } from '../TextRange'; function escape(s: string): string { - return s.replace(/\n/g, '[n]') - .replace(/\r/g, '[r]') - .replace(/\t/g, '[t]'); + return s.replace(/\n/g, '[n]').replace(/\r/g, '[r]').replace(/\t/g, '[t]'); } function matchSnapshot(textRange: TextRange): void { for (let i: number = -1; i <= textRange.end + 1; ++i) { - // Show the current character const c: string = escape(textRange.buffer.substr(Math.max(i, 0), 1)) - .replace(/\n/g, '[n]').replace(/\r/g, '[r]'); + .replace(/\n/g, '[n]') + .replace(/\r/g, '[r]'); // Show the next 10 characters of context const context: string = escape(textRange.buffer.substr(Math.max(i, 0), 10)); @@ -38,13 +36,15 @@ test('construction scenarios', () => { }); test('getLocation() basic', () => { - const textRange: TextRange = TextRange.fromString([ - 'L1', - 'L2', - '', // (line 3 is blank) - 'L4', - 'L5+CR\rL5+CRLF\r\nL6+LFCR\n\rL7' - ].join('\n')); + const textRange: TextRange = TextRange.fromString( + [ + 'L1', + 'L2', + '', // (line 3 is blank) + 'L4', + 'L5+CR\rL5+CRLF\r\nL6+LFCR\n\rL7' + ].join('\n') + ); matchSnapshot(textRange); }); diff --git a/libraries/rushell/src/test/Tokenizer.test.ts b/libraries/rushell/src/test/Tokenizer.test.ts index 41251c1b742..59c024da038 100644 --- a/libraries/rushell/src/test/Tokenizer.test.ts +++ b/libraries/rushell/src/test/Tokenizer.test.ts @@ -1,13 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Tokenizer, TokenKind, Token } from '../Tokenizer'; +import { Tokenizer, TokenKind, type Token } from '../Tokenizer'; function escape(s: string): string { - return s.replace(/\n/g, '[n]') - .replace(/\r/g, '[r]') - .replace(/\t/g, '[t]') - .replace(/\\/g, '[b]'); + return s.replace(/\n/g, '[n]').replace(/\r/g, '[r]').replace(/\t/g, '[t]').replace(/\\/g, '[b]'); } function tokenize(input: string): Token[] { @@ -18,21 +15,17 @@ function tokenize(input: string): Token[] { function matchSnapshot(input: string): void { const tokenizer: Tokenizer = new Tokenizer(input); - const reportedTokens: { kind: string, value: string }[] = tokenizer.readTokens().map( - token => { - return { - kind: TokenKind[token.kind], - value: escape(token.toString()) - }; - } - ); + const reportedTokens: { kind: string; value: string }[] = tokenizer.readTokens().map((token) => { + return { + kind: TokenKind[token.kind], + value: escape(token.toString()) + }; + }); - expect( - { - input: escape(tokenizer.input.toString()), - tokens: reportedTokens - } - ).toMatchSnapshot(); + expect({ + input: escape(tokenizer.input.toString()), + tokens: reportedTokens + }).toMatchSnapshot(); } test('00: empty inputs', () => { diff --git a/libraries/rushell/tsconfig.json b/libraries/rushell/tsconfig.json index 76f0d945025..dac21d04081 100644 --- a/libraries/rushell/tsconfig.json +++ b/libraries/rushell/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "jest", - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/stream-collator/.eslintrc.js b/libraries/stream-collator/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/libraries/stream-collator/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/stream-collator/.npmignore b/libraries/stream-collator/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/stream-collator/.npmignore +++ b/libraries/stream-collator/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/stream-collator/CHANGELOG.json b/libraries/stream-collator/CHANGELOG.json index d0da1a5b137..bbd447842f1 100644 --- a/libraries/stream-collator/CHANGELOG.json +++ b/libraries/stream-collator/CHANGELOG.json @@ -1,6 +1,7548 @@ { "name": "@rushstack/stream-collator", "entries": [ + { + "version": "4.1.119", + "tag": "@rushstack/stream-collator_v4.1.119", + "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": "4.1.118", + "tag": "@rushstack/stream-collator_v4.1.118", + "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": "4.1.117", + "tag": "@rushstack/stream-collator_v4.1.117", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "4.1.116", + "tag": "@rushstack/stream-collator_v4.1.116", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "4.1.115", + "tag": "@rushstack/stream-collator_v4.1.115", + "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": "4.1.114", + "tag": "@rushstack/stream-collator_v4.1.114", + "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": "4.1.113", + "tag": "@rushstack/stream-collator_v4.1.113", + "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`" + } + ] + } + }, + { + "version": "4.1.112", + "tag": "@rushstack/stream-collator_v4.1.112", + "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`" + } + ] + } + }, + { + "version": "4.1.111", + "tag": "@rushstack/stream-collator_v4.1.111", + "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": "4.1.110", + "tag": "@rushstack/stream-collator_v4.1.110", + "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`" + } + ] + } + }, + { + "version": "4.1.109", + "tag": "@rushstack/stream-collator_v4.1.109", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "4.1.108", + "tag": "@rushstack/stream-collator_v4.1.108", + "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": "4.1.107", + "tag": "@rushstack/stream-collator_v4.1.107", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "4.1.106", + "tag": "@rushstack/stream-collator_v4.1.106", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "4.1.105", + "tag": "@rushstack/stream-collator_v4.1.105", + "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`" + } + ] + } + }, + { + "version": "4.1.104", + "tag": "@rushstack/stream-collator_v4.1.104", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "4.1.103", + "tag": "@rushstack/stream-collator_v4.1.103", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "4.1.102", + "tag": "@rushstack/stream-collator_v4.1.102", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "4.1.101", + "tag": "@rushstack/stream-collator_v4.1.101", + "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": "4.1.100", + "tag": "@rushstack/stream-collator_v4.1.100", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "4.1.99", + "tag": "@rushstack/stream-collator_v4.1.99", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "4.1.98", + "tag": "@rushstack/stream-collator_v4.1.98", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "4.1.97", + "tag": "@rushstack/stream-collator_v4.1.97", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "4.1.96", + "tag": "@rushstack/stream-collator_v4.1.96", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "4.1.95", + "tag": "@rushstack/stream-collator_v4.1.95", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "4.1.94", + "tag": "@rushstack/stream-collator_v4.1.94", + "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/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "4.1.93", + "tag": "@rushstack/stream-collator_v4.1.93", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "4.1.92", + "tag": "@rushstack/stream-collator_v4.1.92", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "4.1.91", + "tag": "@rushstack/stream-collator_v4.1.91", + "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/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "4.1.90", + "tag": "@rushstack/stream-collator_v4.1.90", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "4.1.89", + "tag": "@rushstack/stream-collator_v4.1.89", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "4.1.88", + "tag": "@rushstack/stream-collator_v4.1.88", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "4.1.87", + "tag": "@rushstack/stream-collator_v4.1.87", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "4.1.86", + "tag": "@rushstack/stream-collator_v4.1.86", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "4.1.85", + "tag": "@rushstack/stream-collator_v4.1.85", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "4.1.84", + "tag": "@rushstack/stream-collator_v4.1.84", + "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": "4.1.83", + "tag": "@rushstack/stream-collator_v4.1.83", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "4.1.82", + "tag": "@rushstack/stream-collator_v4.1.82", + "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": "4.1.81", + "tag": "@rushstack/stream-collator_v4.1.81", + "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": "4.1.80", + "tag": "@rushstack/stream-collator_v4.1.80", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "4.1.79", + "tag": "@rushstack/stream-collator_v4.1.79", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "4.1.78", + "tag": "@rushstack/stream-collator_v4.1.78", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "4.1.77", + "tag": "@rushstack/stream-collator_v4.1.77", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "4.1.76", + "tag": "@rushstack/stream-collator_v4.1.76", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "4.1.75", + "tag": "@rushstack/stream-collator_v4.1.75", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "4.1.74", + "tag": "@rushstack/stream-collator_v4.1.74", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "4.1.73", + "tag": "@rushstack/stream-collator_v4.1.73", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "4.1.72", + "tag": "@rushstack/stream-collator_v4.1.72", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "4.1.71", + "tag": "@rushstack/stream-collator_v4.1.71", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "4.1.70", + "tag": "@rushstack/stream-collator_v4.1.70", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "4.1.69", + "tag": "@rushstack/stream-collator_v4.1.69", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "4.1.68", + "tag": "@rushstack/stream-collator_v4.1.68", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "4.1.67", + "tag": "@rushstack/stream-collator_v4.1.67", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "4.1.66", + "tag": "@rushstack/stream-collator_v4.1.66", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "4.1.65", + "tag": "@rushstack/stream-collator_v4.1.65", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "4.1.64", + "tag": "@rushstack/stream-collator_v4.1.64", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "4.1.63", + "tag": "@rushstack/stream-collator_v4.1.63", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "4.1.62", + "tag": "@rushstack/stream-collator_v4.1.62", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "4.1.61", + "tag": "@rushstack/stream-collator_v4.1.61", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "4.1.60", + "tag": "@rushstack/stream-collator_v4.1.60", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "4.1.59", + "tag": "@rushstack/stream-collator_v4.1.59", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "4.1.58", + "tag": "@rushstack/stream-collator_v4.1.58", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "4.1.57", + "tag": "@rushstack/stream-collator_v4.1.57", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "4.1.56", + "tag": "@rushstack/stream-collator_v4.1.56", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "4.1.55", + "tag": "@rushstack/stream-collator_v4.1.55", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "4.1.54", + "tag": "@rushstack/stream-collator_v4.1.54", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "4.1.53", + "tag": "@rushstack/stream-collator_v4.1.53", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "4.1.52", + "tag": "@rushstack/stream-collator_v4.1.52", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "4.1.51", + "tag": "@rushstack/stream-collator_v4.1.51", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "4.1.50", + "tag": "@rushstack/stream-collator_v4.1.50", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "4.1.49", + "tag": "@rushstack/stream-collator_v4.1.49", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "4.1.48", + "tag": "@rushstack/stream-collator_v4.1.48", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "4.1.47", + "tag": "@rushstack/stream-collator_v4.1.47", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "4.1.46", + "tag": "@rushstack/stream-collator_v4.1.46", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "4.1.45", + "tag": "@rushstack/stream-collator_v4.1.45", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "4.1.44", + "tag": "@rushstack/stream-collator_v4.1.44", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "4.1.43", + "tag": "@rushstack/stream-collator_v4.1.43", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "4.1.42", + "tag": "@rushstack/stream-collator_v4.1.42", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "4.1.41", + "tag": "@rushstack/stream-collator_v4.1.41", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "4.1.40", + "tag": "@rushstack/stream-collator_v4.1.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "4.1.39", + "tag": "@rushstack/stream-collator_v4.1.39", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "4.1.38", + "tag": "@rushstack/stream-collator_v4.1.38", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "4.1.37", + "tag": "@rushstack/stream-collator_v4.1.37", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "4.1.36", + "tag": "@rushstack/stream-collator_v4.1.36", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "4.1.35", + "tag": "@rushstack/stream-collator_v4.1.35", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "4.1.34", + "tag": "@rushstack/stream-collator_v4.1.34", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "4.1.33", + "tag": "@rushstack/stream-collator_v4.1.33", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "4.1.32", + "tag": "@rushstack/stream-collator_v4.1.32", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "4.1.31", + "tag": "@rushstack/stream-collator_v4.1.31", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "4.1.30", + "tag": "@rushstack/stream-collator_v4.1.30", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "4.1.29", + "tag": "@rushstack/stream-collator_v4.1.29", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "4.1.28", + "tag": "@rushstack/stream-collator_v4.1.28", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "4.1.27", + "tag": "@rushstack/stream-collator_v4.1.27", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "4.1.26", + "tag": "@rushstack/stream-collator_v4.1.26", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "4.1.25", + "tag": "@rushstack/stream-collator_v4.1.25", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "4.1.24", + "tag": "@rushstack/stream-collator_v4.1.24", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "4.1.23", + "tag": "@rushstack/stream-collator_v4.1.23", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "4.1.22", + "tag": "@rushstack/stream-collator_v4.1.22", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "4.1.21", + "tag": "@rushstack/stream-collator_v4.1.21", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "4.1.20", + "tag": "@rushstack/stream-collator_v4.1.20", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "4.1.19", + "tag": "@rushstack/stream-collator_v4.1.19", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "4.1.18", + "tag": "@rushstack/stream-collator_v4.1.18", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "4.1.17", + "tag": "@rushstack/stream-collator_v4.1.17", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "4.1.16", + "tag": "@rushstack/stream-collator_v4.1.16", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "4.1.15", + "tag": "@rushstack/stream-collator_v4.1.15", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "4.1.14", + "tag": "@rushstack/stream-collator_v4.1.14", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "4.1.13", + "tag": "@rushstack/stream-collator_v4.1.13", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "4.1.12", + "tag": "@rushstack/stream-collator_v4.1.12", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "4.1.11", + "tag": "@rushstack/stream-collator_v4.1.11", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "4.1.10", + "tag": "@rushstack/stream-collator_v4.1.10", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "4.1.9", + "tag": "@rushstack/stream-collator_v4.1.9", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "4.1.8", + "tag": "@rushstack/stream-collator_v4.1.8", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "4.1.7", + "tag": "@rushstack/stream-collator_v4.1.7", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "4.1.6", + "tag": "@rushstack/stream-collator_v4.1.6", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "4.1.5", + "tag": "@rushstack/stream-collator_v4.1.5", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "4.1.4", + "tag": "@rushstack/stream-collator_v4.1.4", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "4.1.3", + "tag": "@rushstack/stream-collator_v4.1.3", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "4.1.2", + "tag": "@rushstack/stream-collator_v4.1.2", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "4.1.1", + "tag": "@rushstack/stream-collator_v4.1.1", + "date": "Tue, 19 Sep 2023 00:36:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.7.0`" + } + ] + } + }, + { + "version": "4.1.0", + "tag": "@rushstack/stream-collator_v4.1.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "4.0.263", + "tag": "@rushstack/stream-collator_v4.0.263", + "date": "Thu, 24 Aug 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.38`" + } + ] + } + }, + { + "version": "4.0.262", + "tag": "@rushstack/stream-collator_v4.0.262", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "4.0.261", + "tag": "@rushstack/stream-collator_v4.0.261", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "4.0.260", + "tag": "@rushstack/stream-collator_v4.0.260", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "4.0.259", + "tag": "@rushstack/stream-collator_v4.0.259", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "4.0.258", + "tag": "@rushstack/stream-collator_v4.0.258", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "4.0.257", + "tag": "@rushstack/stream-collator_v4.0.257", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "4.0.256", + "tag": "@rushstack/stream-collator_v4.0.256", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "4.0.255", + "tag": "@rushstack/stream-collator_v4.0.255", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "4.0.254", + "tag": "@rushstack/stream-collator_v4.0.254", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "4.0.253", + "tag": "@rushstack/stream-collator_v4.0.253", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "4.0.252", + "tag": "@rushstack/stream-collator_v4.0.252", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "4.0.251", + "tag": "@rushstack/stream-collator_v4.0.251", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "4.0.250", + "tag": "@rushstack/stream-collator_v4.0.250", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "4.0.249", + "tag": "@rushstack/stream-collator_v4.0.249", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "4.0.248", + "tag": "@rushstack/stream-collator_v4.0.248", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "4.0.247", + "tag": "@rushstack/stream-collator_v4.0.247", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "4.0.246", + "tag": "@rushstack/stream-collator_v4.0.246", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "4.0.245", + "tag": "@rushstack/stream-collator_v4.0.245", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "4.0.244", + "tag": "@rushstack/stream-collator_v4.0.244", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "4.0.243", + "tag": "@rushstack/stream-collator_v4.0.243", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "4.0.242", + "tag": "@rushstack/stream-collator_v4.0.242", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "4.0.241", + "tag": "@rushstack/stream-collator_v4.0.241", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "4.0.240", + "tag": "@rushstack/stream-collator_v4.0.240", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "4.0.239", + "tag": "@rushstack/stream-collator_v4.0.239", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "4.0.238", + "tag": "@rushstack/stream-collator_v4.0.238", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "4.0.237", + "tag": "@rushstack/stream-collator_v4.0.237", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "4.0.236", + "tag": "@rushstack/stream-collator_v4.0.236", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "4.0.235", + "tag": "@rushstack/stream-collator_v4.0.235", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "4.0.234", + "tag": "@rushstack/stream-collator_v4.0.234", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "4.0.233", + "tag": "@rushstack/stream-collator_v4.0.233", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "4.0.232", + "tag": "@rushstack/stream-collator_v4.0.232", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "4.0.231", + "tag": "@rushstack/stream-collator_v4.0.231", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "4.0.230", + "tag": "@rushstack/stream-collator_v4.0.230", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "4.0.229", + "tag": "@rushstack/stream-collator_v4.0.229", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "4.0.228", + "tag": "@rushstack/stream-collator_v4.0.228", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "4.0.227", + "tag": "@rushstack/stream-collator_v4.0.227", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "4.0.226", + "tag": "@rushstack/stream-collator_v4.0.226", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "4.0.225", + "tag": "@rushstack/stream-collator_v4.0.225", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "4.0.224", + "tag": "@rushstack/stream-collator_v4.0.224", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "4.0.223", + "tag": "@rushstack/stream-collator_v4.0.223", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "4.0.222", + "tag": "@rushstack/stream-collator_v4.0.222", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "4.0.221", + "tag": "@rushstack/stream-collator_v4.0.221", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "4.0.220", + "tag": "@rushstack/stream-collator_v4.0.220", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "4.0.219", + "tag": "@rushstack/stream-collator_v4.0.219", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "4.0.218", + "tag": "@rushstack/stream-collator_v4.0.218", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "4.0.217", + "tag": "@rushstack/stream-collator_v4.0.217", + "date": "Mon, 05 Dec 2022 16:16:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.86`" + } + ] + } + }, + { + "version": "4.0.216", + "tag": "@rushstack/stream-collator_v4.0.216", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "4.0.215", + "tag": "@rushstack/stream-collator_v4.0.215", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "4.0.214", + "tag": "@rushstack/stream-collator_v4.0.214", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "4.0.213", + "tag": "@rushstack/stream-collator_v4.0.213", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "4.0.212", + "tag": "@rushstack/stream-collator_v4.0.212", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "4.0.211", + "tag": "@rushstack/stream-collator_v4.0.211", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "4.0.210", + "tag": "@rushstack/stream-collator_v4.0.210", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "4.0.209", + "tag": "@rushstack/stream-collator_v4.0.209", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "4.0.208", + "tag": "@rushstack/stream-collator_v4.0.208", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.77`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "4.0.207", + "tag": "@rushstack/stream-collator_v4.0.207", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.76`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "4.0.206", + "tag": "@rushstack/stream-collator_v4.0.206", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "4.0.205", + "tag": "@rushstack/stream-collator_v4.0.205", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "4.0.204", + "tag": "@rushstack/stream-collator_v4.0.204", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.73`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "4.0.203", + "tag": "@rushstack/stream-collator_v4.0.203", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "4.0.202", + "tag": "@rushstack/stream-collator_v4.0.202", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "4.0.201", + "tag": "@rushstack/stream-collator_v4.0.201", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "4.0.200", + "tag": "@rushstack/stream-collator_v4.0.200", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "4.0.199", + "tag": "@rushstack/stream-collator_v4.0.199", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "4.0.198", + "tag": "@rushstack/stream-collator_v4.0.198", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "4.0.197", + "tag": "@rushstack/stream-collator_v4.0.197", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "4.0.196", + "tag": "@rushstack/stream-collator_v4.0.196", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "4.0.195", + "tag": "@rushstack/stream-collator_v4.0.195", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "4.0.194", + "tag": "@rushstack/stream-collator_v4.0.194", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "4.0.193", + "tag": "@rushstack/stream-collator_v4.0.193", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "4.0.192", + "tag": "@rushstack/stream-collator_v4.0.192", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "4.0.191", + "tag": "@rushstack/stream-collator_v4.0.191", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "4.0.190", + "tag": "@rushstack/stream-collator_v4.0.190", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "4.0.189", + "tag": "@rushstack/stream-collator_v4.0.189", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "4.0.188", + "tag": "@rushstack/stream-collator_v4.0.188", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "4.0.187", + "tag": "@rushstack/stream-collator_v4.0.187", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "4.0.186", + "tag": "@rushstack/stream-collator_v4.0.186", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "4.0.185", + "tag": "@rushstack/stream-collator_v4.0.185", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "4.0.184", + "tag": "@rushstack/stream-collator_v4.0.184", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "4.0.183", + "tag": "@rushstack/stream-collator_v4.0.183", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "4.0.182", + "tag": "@rushstack/stream-collator_v4.0.182", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "4.0.181", + "tag": "@rushstack/stream-collator_v4.0.181", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "4.0.180", + "tag": "@rushstack/stream-collator_v4.0.180", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "4.0.179", + "tag": "@rushstack/stream-collator_v4.0.179", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "4.0.178", + "tag": "@rushstack/stream-collator_v4.0.178", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "4.0.177", + "tag": "@rushstack/stream-collator_v4.0.177", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "4.0.176", + "tag": "@rushstack/stream-collator_v4.0.176", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "4.0.175", + "tag": "@rushstack/stream-collator_v4.0.175", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "4.0.174", + "tag": "@rushstack/stream-collator_v4.0.174", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "4.0.173", + "tag": "@rushstack/stream-collator_v4.0.173", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "4.0.172", + "tag": "@rushstack/stream-collator_v4.0.172", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "4.0.171", + "tag": "@rushstack/stream-collator_v4.0.171", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "4.0.170", + "tag": "@rushstack/stream-collator_v4.0.170", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "4.0.169", + "tag": "@rushstack/stream-collator_v4.0.169", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "4.0.168", + "tag": "@rushstack/stream-collator_v4.0.168", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "4.0.167", + "tag": "@rushstack/stream-collator_v4.0.167", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "4.0.166", + "tag": "@rushstack/stream-collator_v4.0.166", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "4.0.165", + "tag": "@rushstack/stream-collator_v4.0.165", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "4.0.164", + "tag": "@rushstack/stream-collator_v4.0.164", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "4.0.163", + "tag": "@rushstack/stream-collator_v4.0.163", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "4.0.162", + "tag": "@rushstack/stream-collator_v4.0.162", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "4.0.161", + "tag": "@rushstack/stream-collator_v4.0.161", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "4.0.160", + "tag": "@rushstack/stream-collator_v4.0.160", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "4.0.159", + "tag": "@rushstack/stream-collator_v4.0.159", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "4.0.158", + "tag": "@rushstack/stream-collator_v4.0.158", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "4.0.157", + "tag": "@rushstack/stream-collator_v4.0.157", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "4.0.156", + "tag": "@rushstack/stream-collator_v4.0.156", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "4.0.155", + "tag": "@rushstack/stream-collator_v4.0.155", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "4.0.154", + "tag": "@rushstack/stream-collator_v4.0.154", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "4.0.153", + "tag": "@rushstack/stream-collator_v4.0.153", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "4.0.152", + "tag": "@rushstack/stream-collator_v4.0.152", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "4.0.151", + "tag": "@rushstack/stream-collator_v4.0.151", + "date": "Tue, 14 Dec 2021 19:27:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "4.0.150", + "tag": "@rushstack/stream-collator_v4.0.150", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "4.0.149", + "tag": "@rushstack/stream-collator_v4.0.149", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "4.0.148", + "tag": "@rushstack/stream-collator_v4.0.148", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "4.0.147", + "tag": "@rushstack/stream-collator_v4.0.147", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "4.0.146", + "tag": "@rushstack/stream-collator_v4.0.146", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "4.0.145", + "tag": "@rushstack/stream-collator_v4.0.145", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "4.0.144", + "tag": "@rushstack/stream-collator_v4.0.144", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "4.0.143", + "tag": "@rushstack/stream-collator_v4.0.143", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "4.0.142", + "tag": "@rushstack/stream-collator_v4.0.142", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "4.0.141", + "tag": "@rushstack/stream-collator_v4.0.141", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "4.0.140", + "tag": "@rushstack/stream-collator_v4.0.140", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "4.0.139", + "tag": "@rushstack/stream-collator_v4.0.139", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "4.0.138", + "tag": "@rushstack/stream-collator_v4.0.138", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "4.0.137", + "tag": "@rushstack/stream-collator_v4.0.137", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "4.0.136", + "tag": "@rushstack/stream-collator_v4.0.136", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "4.0.135", + "tag": "@rushstack/stream-collator_v4.0.135", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "4.0.134", + "tag": "@rushstack/stream-collator_v4.0.134", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "4.0.133", + "tag": "@rushstack/stream-collator_v4.0.133", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "4.0.132", + "tag": "@rushstack/stream-collator_v4.0.132", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "4.0.131", + "tag": "@rushstack/stream-collator_v4.0.131", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "4.0.130", + "tag": "@rushstack/stream-collator_v4.0.130", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "4.0.129", + "tag": "@rushstack/stream-collator_v4.0.129", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "4.0.128", + "tag": "@rushstack/stream-collator_v4.0.128", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "4.0.127", + "tag": "@rushstack/stream-collator_v4.0.127", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "4.0.126", + "tag": "@rushstack/stream-collator_v4.0.126", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "4.0.125", + "tag": "@rushstack/stream-collator_v4.0.125", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "4.0.124", + "tag": "@rushstack/stream-collator_v4.0.124", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "4.0.123", + "tag": "@rushstack/stream-collator_v4.0.123", + "date": "Mon, 13 Sep 2021 15:07:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "4.0.122", + "tag": "@rushstack/stream-collator_v4.0.122", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "4.0.121", + "tag": "@rushstack/stream-collator_v4.0.121", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "4.0.120", + "tag": "@rushstack/stream-collator_v4.0.120", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "4.0.119", + "tag": "@rushstack/stream-collator_v4.0.119", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "4.0.118", + "tag": "@rushstack/stream-collator_v4.0.118", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "4.0.117", + "tag": "@rushstack/stream-collator_v4.0.117", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "4.0.116", + "tag": "@rushstack/stream-collator_v4.0.116", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "4.0.115", + "tag": "@rushstack/stream-collator_v4.0.115", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "4.0.114", + "tag": "@rushstack/stream-collator_v4.0.114", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "4.0.113", + "tag": "@rushstack/stream-collator_v4.0.113", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "4.0.112", + "tag": "@rushstack/stream-collator_v4.0.112", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "4.0.111", + "tag": "@rushstack/stream-collator_v4.0.111", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "4.0.110", + "tag": "@rushstack/stream-collator_v4.0.110", + "date": "Sat, 31 Jul 2021 00:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "4.0.109", + "tag": "@rushstack/stream-collator_v4.0.109", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "4.0.108", + "tag": "@rushstack/stream-collator_v4.0.108", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "4.0.107", + "tag": "@rushstack/stream-collator_v4.0.107", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "4.0.106", + "tag": "@rushstack/stream-collator_v4.0.106", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "4.0.105", + "tag": "@rushstack/stream-collator_v4.0.105", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "4.0.104", + "tag": "@rushstack/stream-collator_v4.0.104", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "4.0.103", + "tag": "@rushstack/stream-collator_v4.0.103", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "4.0.102", + "tag": "@rushstack/stream-collator_v4.0.102", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "4.0.101", + "tag": "@rushstack/stream-collator_v4.0.101", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "4.0.100", + "tag": "@rushstack/stream-collator_v4.0.100", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "4.0.99", + "tag": "@rushstack/stream-collator_v4.0.99", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "4.0.98", + "tag": "@rushstack/stream-collator_v4.0.98", + "date": "Fri, 18 Jun 2021 00:08:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.2.0`" + } + ] + } + }, + { + "version": "4.0.97", + "tag": "@rushstack/stream-collator_v4.0.97", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.96`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "4.0.96", + "tag": "@rushstack/stream-collator_v4.0.96", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.95`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "4.0.95", + "tag": "@rushstack/stream-collator_v4.0.95", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "4.0.94", + "tag": "@rushstack/stream-collator_v4.0.94", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "4.0.93", + "tag": "@rushstack/stream-collator_v4.0.93", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "4.0.92", + "tag": "@rushstack/stream-collator_v4.0.92", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "4.0.91", + "tag": "@rushstack/stream-collator_v4.0.91", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "4.0.90", + "tag": "@rushstack/stream-collator_v4.0.90", + "date": "Fri, 04 Jun 2021 15:08:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "4.0.89", + "tag": "@rushstack/stream-collator_v4.0.89", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "4.0.88", + "tag": "@rushstack/stream-collator_v4.0.88", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "4.0.87", + "tag": "@rushstack/stream-collator_v4.0.87", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "4.0.86", + "tag": "@rushstack/stream-collator_v4.0.86", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "4.0.85", + "tag": "@rushstack/stream-collator_v4.0.85", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "4.0.84", + "tag": "@rushstack/stream-collator_v4.0.84", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "4.0.83", + "tag": "@rushstack/stream-collator_v4.0.83", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "4.0.82", + "tag": "@rushstack/stream-collator_v4.0.82", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "4.0.81", + "tag": "@rushstack/stream-collator_v4.0.81", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "4.0.80", + "tag": "@rushstack/stream-collator_v4.0.80", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "4.0.79", + "tag": "@rushstack/stream-collator_v4.0.79", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "4.0.78", + "tag": "@rushstack/stream-collator_v4.0.78", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "4.0.77", + "tag": "@rushstack/stream-collator_v4.0.77", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "4.0.76", + "tag": "@rushstack/stream-collator_v4.0.76", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "4.0.75", + "tag": "@rushstack/stream-collator_v4.0.75", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "4.0.74", + "tag": "@rushstack/stream-collator_v4.0.74", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "4.0.73", + "tag": "@rushstack/stream-collator_v4.0.73", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.72`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "4.0.72", + "tag": "@rushstack/stream-collator_v4.0.72", + "date": "Thu, 08 Apr 2021 20:41:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "4.0.71", + "tag": "@rushstack/stream-collator_v4.0.71", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "4.0.70", + "tag": "@rushstack/stream-collator_v4.0.70", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "4.0.69", + "tag": "@rushstack/stream-collator_v4.0.69", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.68`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "4.0.68", + "tag": "@rushstack/stream-collator_v4.0.68", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "4.0.67", + "tag": "@rushstack/stream-collator_v4.0.67", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "4.0.66", + "tag": "@rushstack/stream-collator_v4.0.66", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "4.0.65", + "tag": "@rushstack/stream-collator_v4.0.65", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "4.0.64", + "tag": "@rushstack/stream-collator_v4.0.64", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "4.0.63", + "tag": "@rushstack/stream-collator_v4.0.63", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "4.0.62", + "tag": "@rushstack/stream-collator_v4.0.62", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "4.0.61", + "tag": "@rushstack/stream-collator_v4.0.61", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "4.0.60", + "tag": "@rushstack/stream-collator_v4.0.60", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "4.0.59", + "tag": "@rushstack/stream-collator_v4.0.59", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "4.0.58", + "tag": "@rushstack/stream-collator_v4.0.58", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "4.0.57", + "tag": "@rushstack/stream-collator_v4.0.57", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "4.0.56", + "tag": "@rushstack/stream-collator_v4.0.56", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "4.0.55", + "tag": "@rushstack/stream-collator_v4.0.55", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "4.0.54", + "tag": "@rushstack/stream-collator_v4.0.54", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "4.0.53", + "tag": "@rushstack/stream-collator_v4.0.53", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "4.0.52", + "tag": "@rushstack/stream-collator_v4.0.52", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "4.0.51", + "tag": "@rushstack/stream-collator_v4.0.51", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "4.0.50", + "tag": "@rushstack/stream-collator_v4.0.50", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "4.0.49", + "tag": "@rushstack/stream-collator_v4.0.49", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "4.0.48", + "tag": "@rushstack/stream-collator_v4.0.48", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "4.0.47", + "tag": "@rushstack/stream-collator_v4.0.47", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "4.0.46", + "tag": "@rushstack/stream-collator_v4.0.46", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "4.0.45", + "tag": "@rushstack/stream-collator_v4.0.45", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "4.0.44", + "tag": "@rushstack/stream-collator_v4.0.44", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "4.0.43", + "tag": "@rushstack/stream-collator_v4.0.43", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "4.0.42", + "tag": "@rushstack/stream-collator_v4.0.42", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "4.0.41", + "tag": "@rushstack/stream-collator_v4.0.41", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "4.0.40", + "tag": "@rushstack/stream-collator_v4.0.40", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "4.0.39", + "tag": "@rushstack/stream-collator_v4.0.39", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "4.0.38", + "tag": "@rushstack/stream-collator_v4.0.38", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "4.0.37", + "tag": "@rushstack/stream-collator_v4.0.37", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "4.0.36", + "tag": "@rushstack/stream-collator_v4.0.36", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "4.0.35", + "tag": "@rushstack/stream-collator_v4.0.35", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "4.0.34", + "tag": "@rushstack/stream-collator_v4.0.34", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "4.0.33", + "tag": "@rushstack/stream-collator_v4.0.33", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "4.0.32", + "tag": "@rushstack/stream-collator_v4.0.32", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "4.0.31", + "tag": "@rushstack/stream-collator_v4.0.31", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "4.0.30", + "tag": "@rushstack/stream-collator_v4.0.30", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "4.0.29", + "tag": "@rushstack/stream-collator_v4.0.29", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "4.0.28", + "tag": "@rushstack/stream-collator_v4.0.28", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "4.0.27", + "tag": "@rushstack/stream-collator_v4.0.27", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "4.0.26", + "tag": "@rushstack/stream-collator_v4.0.26", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "4.0.25", + "tag": "@rushstack/stream-collator_v4.0.25", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "4.0.24", + "tag": "@rushstack/stream-collator_v4.0.24", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "4.0.23", + "tag": "@rushstack/stream-collator_v4.0.23", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "4.0.22", + "tag": "@rushstack/stream-collator_v4.0.22", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "4.0.21", + "tag": "@rushstack/stream-collator_v4.0.21", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "4.0.20", + "tag": "@rushstack/stream-collator_v4.0.20", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "4.0.19", + "tag": "@rushstack/stream-collator_v4.0.19", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "4.0.18", + "tag": "@rushstack/stream-collator_v4.0.18", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "4.0.17", + "tag": "@rushstack/stream-collator_v4.0.17", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "4.0.16", + "tag": "@rushstack/stream-collator_v4.0.16", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "4.0.15", + "tag": "@rushstack/stream-collator_v4.0.15", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "4.0.14", + "tag": "@rushstack/stream-collator_v4.0.14", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "4.0.13", + "tag": "@rushstack/stream-collator_v4.0.13", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "4.0.12", + "tag": "@rushstack/stream-collator_v4.0.12", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "4.0.11", + "tag": "@rushstack/stream-collator_v4.0.11", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "4.0.10", + "tag": "@rushstack/stream-collator_v4.0.10", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "4.0.9", + "tag": "@rushstack/stream-collator_v4.0.9", + "date": "Mon, 21 Sep 2020 17:49:26 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where output was lagged because writers were not activated aggressively enough" + } + ] + } + }, + { + "version": "4.0.8", + "tag": "@rushstack/stream-collator_v4.0.8", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "4.0.7", + "tag": "@rushstack/stream-collator_v4.0.7", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "4.0.6", + "tag": "@rushstack/stream-collator_v4.0.6", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "4.0.5", + "tag": "@rushstack/stream-collator_v4.0.5", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "4.0.4", + "tag": "@rushstack/stream-collator_v4.0.4", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "4.0.3", + "tag": "@rushstack/stream-collator_v4.0.3", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@rushstack/stream-collator_v4.0.2", + "date": "Mon, 14 Sep 2020 15:09:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@rushstack/stream-collator_v4.0.1", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@rushstack/stream-collator_v4.0.0", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "major": [ + { + "comment": "Big redesign based around the new \"@rushstack/terminal\" system" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "3.2.55", + "tag": "@rushstack/stream-collator_v3.2.55", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "3.2.54", + "tag": "@rushstack/stream-collator_v3.2.54", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "3.2.53", + "tag": "@rushstack/stream-collator_v3.2.53", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "3.2.52", + "tag": "@rushstack/stream-collator_v3.2.52", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "3.2.51", + "tag": "@rushstack/stream-collator_v3.2.51", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "3.2.50", + "tag": "@rushstack/stream-collator_v3.2.50", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "3.2.49", + "tag": "@rushstack/stream-collator_v3.2.49", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "3.2.48", + "tag": "@rushstack/stream-collator_v3.2.48", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "3.2.47", + "tag": "@rushstack/stream-collator_v3.2.47", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "3.2.46", + "tag": "@rushstack/stream-collator_v3.2.46", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "3.2.45", + "tag": "@rushstack/stream-collator_v3.2.45", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "3.2.44", + "tag": "@rushstack/stream-collator_v3.2.44", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "3.2.43", + "tag": "@rushstack/stream-collator_v3.2.43", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "3.2.42", + "tag": "@rushstack/stream-collator_v3.2.42", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "3.2.41", + "tag": "@rushstack/stream-collator_v3.2.41", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "3.2.40", + "tag": "@rushstack/stream-collator_v3.2.40", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "3.2.39", + "tag": "@rushstack/stream-collator_v3.2.39", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "3.2.38", + "tag": "@rushstack/stream-collator_v3.2.38", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "3.2.37", + "tag": "@rushstack/stream-collator_v3.2.37", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "3.2.36", + "tag": "@rushstack/stream-collator_v3.2.36", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "3.2.35", + "tag": "@rushstack/stream-collator_v3.2.35", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "3.2.34", + "tag": "@rushstack/stream-collator_v3.2.34", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "3.2.33", + "tag": "@rushstack/stream-collator_v3.2.33", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "3.2.32", + "tag": "@rushstack/stream-collator_v3.2.32", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + } + ] + } + }, + { + "version": "3.2.31", + "tag": "@rushstack/stream-collator_v3.2.31", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "3.2.30", + "tag": "@rushstack/stream-collator_v3.2.30", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "3.2.29", + "tag": "@rushstack/stream-collator_v3.2.29", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "3.2.28", + "tag": "@rushstack/stream-collator_v3.2.28", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "3.2.27", + "tag": "@rushstack/stream-collator_v3.2.27", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "3.2.26", + "tag": "@rushstack/stream-collator_v3.2.26", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "3.2.25", + "tag": "@rushstack/stream-collator_v3.2.25", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "3.2.24", + "tag": "@rushstack/stream-collator_v3.2.24", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "3.2.23", + "tag": "@rushstack/stream-collator_v3.2.23", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + } + ] + } + }, + { + "version": "3.2.22", + "tag": "@rushstack/stream-collator_v3.2.22", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "3.2.21", + "tag": "@rushstack/stream-collator_v3.2.21", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + } + ] + } + }, + { + "version": "3.2.20", + "tag": "@rushstack/stream-collator_v3.2.20", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + } + ] + } + }, + { + "version": "3.2.19", + "tag": "@rushstack/stream-collator_v3.2.19", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "3.2.18", + "tag": "@rushstack/stream-collator_v3.2.18", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + } + ] + } + }, + { + "version": "3.2.17", + "tag": "@rushstack/stream-collator_v3.2.17", + "date": "Fri, 22 May 2020 15:08:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + } + ] + } + }, + { + "version": "3.2.16", + "tag": "@rushstack/stream-collator_v3.2.16", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + } + ] + } + }, + { + "version": "3.2.15", + "tag": "@rushstack/stream-collator_v3.2.15", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "3.2.14", + "tag": "@rushstack/stream-collator_v3.2.14", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "3.2.13", + "tag": "@rushstack/stream-collator_v3.2.13", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "3.2.12", + "tag": "@rushstack/stream-collator_v3.2.12", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "3.2.11", + "tag": "@rushstack/stream-collator_v3.2.11", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "3.2.10", + "tag": "@rushstack/stream-collator_v3.2.10", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "3.2.9", + "tag": "@rushstack/stream-collator_v3.2.9", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "3.2.8", + "tag": "@rushstack/stream-collator_v3.2.8", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "3.2.7", + "tag": "@rushstack/stream-collator_v3.2.7", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "3.2.6", "tag": "@rushstack/stream-collator_v3.2.6", diff --git a/libraries/stream-collator/CHANGELOG.md b/libraries/stream-collator/CHANGELOG.md index dd1d711d6d7..dbbe9284bb5 100644 --- a/libraries/stream-collator/CHANGELOG.md +++ b/libraries/stream-collator/CHANGELOG.md @@ -1,11 +1,2200 @@ # Change Log - @rushstack/stream-collator -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 4.1.119 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 4.1.118 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 4.1.117 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 4.1.116 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 4.1.115 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 4.1.114 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 4.1.113 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 4.1.112 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 4.1.111 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 4.1.110 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 4.1.109 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 4.1.108 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 4.1.107 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 4.1.106 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 4.1.105 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 4.1.104 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 4.1.103 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 4.1.102 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 4.1.101 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 4.1.100 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 4.1.99 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 4.1.98 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 4.1.97 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 4.1.96 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 4.1.95 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 4.1.94 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 4.1.93 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 4.1.92 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 4.1.91 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 4.1.90 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 4.1.89 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 4.1.88 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 4.1.87 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 4.1.86 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 4.1.85 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 4.1.84 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 4.1.83 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 4.1.82 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 4.1.81 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 4.1.80 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 4.1.79 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 4.1.78 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 4.1.77 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 4.1.76 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 4.1.75 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 4.1.74 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 4.1.73 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 4.1.72 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 4.1.71 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 4.1.70 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 4.1.69 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 4.1.68 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 4.1.67 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 4.1.66 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 4.1.65 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 4.1.64 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 4.1.63 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 4.1.62 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 4.1.61 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 4.1.60 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 4.1.59 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 4.1.58 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 4.1.57 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 4.1.56 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 4.1.55 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 4.1.54 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 4.1.53 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 4.1.52 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 4.1.51 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 4.1.50 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 4.1.49 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 4.1.48 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 4.1.47 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 4.1.46 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 4.1.45 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 4.1.44 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 4.1.43 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 4.1.42 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 4.1.41 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 4.1.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 4.1.39 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 4.1.38 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 4.1.37 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 4.1.36 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 4.1.35 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 4.1.34 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 4.1.33 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 4.1.32 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 4.1.31 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 4.1.30 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 4.1.29 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 4.1.28 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 4.1.27 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 4.1.26 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 4.1.25 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 4.1.24 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 4.1.23 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 4.1.22 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 4.1.21 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 4.1.20 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 4.1.19 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 4.1.18 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 4.1.17 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 4.1.16 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 4.1.15 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 4.1.14 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 4.1.13 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 4.1.12 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 4.1.11 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 4.1.10 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 4.1.9 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 4.1.8 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 4.1.7 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 4.1.6 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 4.1.5 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 4.1.4 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 4.1.3 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 4.1.2 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 4.1.1 +Tue, 19 Sep 2023 00:36:30 GMT + +_Version update only_ + +## 4.1.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 4.0.263 +Thu, 24 Aug 2023 15:20:46 GMT + +_Version update only_ + +## 4.0.262 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 4.0.261 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 4.0.260 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 4.0.259 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 4.0.258 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 4.0.257 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 4.0.256 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 4.0.255 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 4.0.254 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 4.0.253 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 4.0.252 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 4.0.251 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 4.0.250 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 4.0.249 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 4.0.248 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 4.0.247 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 4.0.246 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 4.0.245 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 4.0.244 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 4.0.243 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 4.0.242 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 4.0.241 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 4.0.240 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 4.0.239 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 4.0.238 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 4.0.237 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 4.0.236 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 4.0.235 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 4.0.234 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 4.0.233 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 4.0.232 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 4.0.231 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 4.0.230 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 4.0.229 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 4.0.228 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 4.0.227 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 4.0.226 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 4.0.225 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 4.0.224 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 4.0.223 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 4.0.222 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 4.0.221 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 4.0.220 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 4.0.219 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 4.0.218 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 4.0.217 +Mon, 05 Dec 2022 16:16:09 GMT + +_Version update only_ + +## 4.0.216 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 4.0.215 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 4.0.214 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 4.0.213 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 4.0.212 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 4.0.211 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 4.0.210 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 4.0.209 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 4.0.208 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 4.0.207 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 4.0.206 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 4.0.205 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 4.0.204 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 4.0.203 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 4.0.202 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 4.0.201 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 4.0.200 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 4.0.199 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 4.0.198 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 4.0.197 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 4.0.196 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 4.0.195 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 4.0.194 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 4.0.193 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 4.0.192 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 4.0.191 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 4.0.190 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 4.0.189 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 4.0.188 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 4.0.187 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 4.0.186 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 4.0.185 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 4.0.184 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 4.0.183 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 4.0.182 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 4.0.181 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 4.0.180 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 4.0.179 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 4.0.178 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 4.0.177 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 4.0.176 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 4.0.175 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 4.0.174 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 4.0.173 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 4.0.172 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 4.0.171 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 4.0.170 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 4.0.169 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 4.0.168 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 4.0.167 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 4.0.166 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 4.0.165 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 4.0.164 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 4.0.163 +Sat, 09 Apr 2022 02:24:27 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 4.0.162 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 4.0.161 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 4.0.160 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 4.0.159 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 4.0.158 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 4.0.157 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 4.0.156 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 4.0.155 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 4.0.154 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 4.0.153 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 4.0.152 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 4.0.151 +Tue, 14 Dec 2021 19:27:52 GMT + +_Version update only_ + +## 4.0.150 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 4.0.149 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 4.0.148 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 4.0.147 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 4.0.146 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 4.0.145 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 4.0.144 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 4.0.143 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 4.0.142 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 4.0.141 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 4.0.140 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 4.0.139 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 4.0.138 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 4.0.137 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 4.0.136 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 4.0.135 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 4.0.134 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 4.0.133 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 4.0.132 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 4.0.131 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 4.0.130 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 4.0.129 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 4.0.128 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 4.0.127 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 4.0.126 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 4.0.125 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 4.0.124 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 4.0.123 +Mon, 13 Sep 2021 15:07:06 GMT + +_Version update only_ + +## 4.0.122 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 4.0.121 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 4.0.120 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 4.0.119 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 4.0.118 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 4.0.117 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 4.0.116 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 4.0.115 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 4.0.114 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 4.0.113 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 4.0.112 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 4.0.111 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 4.0.110 +Sat, 31 Jul 2021 00:52:12 GMT + +_Version update only_ + +## 4.0.109 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 4.0.108 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 4.0.107 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 4.0.106 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 4.0.105 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 4.0.104 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 4.0.103 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 4.0.102 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 4.0.101 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 4.0.100 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 4.0.99 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 4.0.98 +Fri, 18 Jun 2021 00:08:51 GMT + +_Version update only_ + +## 4.0.97 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 4.0.96 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 4.0.95 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 4.0.94 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 4.0.93 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 4.0.92 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 4.0.91 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 4.0.90 +Fri, 04 Jun 2021 15:08:21 GMT + +_Version update only_ + +## 4.0.89 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 4.0.88 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 4.0.87 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 4.0.86 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 4.0.85 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 4.0.84 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 4.0.83 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 4.0.82 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 4.0.81 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 4.0.80 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 4.0.79 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 4.0.78 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 4.0.77 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 4.0.76 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 4.0.75 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 4.0.74 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 4.0.73 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 4.0.72 +Thu, 08 Apr 2021 20:41:55 GMT + +_Version update only_ + +## 4.0.71 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 4.0.70 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 4.0.69 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 4.0.68 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 4.0.67 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 4.0.66 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 4.0.65 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 4.0.64 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 4.0.63 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 4.0.62 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 4.0.61 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 4.0.60 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 4.0.59 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 4.0.58 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 4.0.57 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 4.0.56 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 4.0.55 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 4.0.54 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 4.0.53 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 4.0.52 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 4.0.51 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 4.0.50 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 4.0.49 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 4.0.48 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 4.0.47 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 4.0.46 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 4.0.45 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 4.0.44 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 4.0.43 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 4.0.42 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 4.0.41 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 4.0.40 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 4.0.39 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 4.0.38 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 4.0.37 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 4.0.36 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 4.0.35 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 4.0.34 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 4.0.33 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 4.0.32 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 4.0.31 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 4.0.30 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 4.0.29 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 4.0.28 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 4.0.27 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 4.0.26 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 4.0.25 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 4.0.24 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 4.0.23 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 4.0.22 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 4.0.21 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 4.0.20 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 4.0.19 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 4.0.18 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 4.0.17 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 4.0.16 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 4.0.15 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 4.0.14 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 4.0.13 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 4.0.12 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 4.0.11 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 4.0.10 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 4.0.9 +Mon, 21 Sep 2020 17:49:26 GMT + +### Patches + +- Fix an issue where output was lagged because writers were not activated aggressively enough + +## 4.0.8 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 4.0.7 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 4.0.6 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 4.0.5 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 4.0.4 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 4.0.3 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 4.0.2 +Mon, 14 Sep 2020 15:09:49 GMT + +_Version update only_ + +## 4.0.1 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 4.0.0 +Fri, 11 Sep 2020 02:13:35 GMT + +### Breaking changes + +- Big redesign based around the new "@rushstack/terminal" system + +## 3.2.55 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 3.2.54 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 3.2.53 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 3.2.52 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 3.2.51 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 3.2.50 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 3.2.49 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 3.2.48 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 3.2.47 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 3.2.46 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 3.2.45 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 3.2.44 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 3.2.43 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 3.2.42 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 3.2.41 +Thu, 20 Aug 2020 15:13:52 GMT + +_Version update only_ + +## 3.2.40 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 3.2.39 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 3.2.38 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 3.2.37 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 3.2.36 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 3.2.35 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 3.2.34 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 3.2.33 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 3.2.32 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 3.2.31 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 3.2.30 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 3.2.29 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 3.2.28 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 3.2.27 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 3.2.26 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 3.2.25 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 3.2.24 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 3.2.23 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 3.2.22 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 3.2.21 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 3.2.20 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 3.2.19 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 3.2.18 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 3.2.17 +Fri, 22 May 2020 15:08:43 GMT + +_Version update only_ + +## 3.2.16 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 3.2.15 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 3.2.14 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 3.2.13 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 3.2.12 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 3.2.11 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 3.2.10 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 3.2.9 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 3.2.8 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 3.2.7 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 3.2.6 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 3.2.5 Tue, 17 Mar 2020 23:55:58 GMT @@ -17,22 +2206,22 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 3.2.4 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 3.2.3 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 3.2.2 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 3.2.1 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 3.2.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -44,102 +2233,102 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 3.1.23 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 3.1.22 Tue, 14 Jan 2020 01:34:16 GMT -*Version update only* +_Version update only_ ## 3.1.21 Sat, 11 Jan 2020 05:18:24 GMT -*Version update only* +_Version update only_ ## 3.1.20 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 3.1.19 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 3.1.18 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 3.1.17 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 3.1.16 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 3.1.15 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 3.1.14 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 3.1.13 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 3.1.12 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 3.1.11 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 3.1.10 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 3.1.9 Fri, 25 Oct 2019 15:08:55 GMT -*Version update only* +_Version update only_ ## 3.1.8 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 3.1.7 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 3.1.6 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 3.1.5 Sun, 06 Oct 2019 00:27:40 GMT -*Version update only* +_Version update only_ ## 3.1.4 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 3.1.3 Sun, 29 Sep 2019 23:56:29 GMT @@ -151,12 +2340,12 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 3.1.2 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 3.1.1 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 3.1.0 Mon, 23 Sep 2019 15:14:55 GMT @@ -168,12 +2357,12 @@ Mon, 23 Sep 2019 15:14:55 GMT ## 3.0.92 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 3.0.91 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 3.0.90 Tue, 10 Sep 2019 22:32:23 GMT @@ -185,327 +2374,327 @@ Tue, 10 Sep 2019 22:32:23 GMT ## 3.0.89 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 3.0.88 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 3.0.87 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 3.0.86 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 3.0.85 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 3.0.84 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 3.0.83 Thu, 08 Aug 2019 00:49:06 GMT -*Version update only* +_Version update only_ ## 3.0.82 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 3.0.81 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 3.0.80 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 3.0.79 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 3.0.78 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 3.0.77 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 3.0.76 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 3.0.75 Mon, 08 Jul 2019 19:12:19 GMT -*Version update only* +_Version update only_ ## 3.0.74 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 3.0.73 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 3.0.72 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 3.0.71 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 3.0.70 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 3.0.69 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 3.0.68 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 3.0.67 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 3.0.66 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 3.0.65 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 3.0.64 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 3.0.63 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 3.0.62 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 3.0.61 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 3.0.60 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 3.0.59 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 3.0.58 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 3.0.57 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 3.0.56 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 3.0.55 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 3.0.54 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 3.0.53 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 3.0.52 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 3.0.51 Tue, 26 Mar 2019 20:54:19 GMT -*Version update only* +_Version update only_ ## 3.0.50 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 3.0.49 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 3.0.48 Thu, 21 Mar 2019 01:15:33 GMT -*Version update only* +_Version update only_ ## 3.0.47 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 3.0.46 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 3.0.45 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 3.0.44 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 3.0.43 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 3.0.42 Mon, 11 Mar 2019 16:13:36 GMT -*Version update only* +_Version update only_ ## 3.0.41 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 3.0.40 Mon, 04 Mar 2019 17:13:20 GMT -*Version update only* +_Version update only_ ## 3.0.39 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 3.0.38 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 3.0.37 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 3.0.36 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 3.0.35 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 3.0.34 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 3.0.33 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 3.0.32 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 3.0.31 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 3.0.30 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 3.0.29 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 3.0.28 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 3.0.27 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 3.0.26 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 3.0.25 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 3.0.24 Fri, 07 Dec 2018 17:04:56 GMT @@ -517,117 +2706,117 @@ Fri, 07 Dec 2018 17:04:56 GMT ## 3.0.23 Fri, 30 Nov 2018 23:34:58 GMT -*Version update only* +_Version update only_ ## 3.0.22 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 3.0.21 Thu, 29 Nov 2018 00:35:39 GMT -*Version update only* +_Version update only_ ## 3.0.20 Wed, 28 Nov 2018 19:29:54 GMT -*Version update only* +_Version update only_ ## 3.0.19 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 3.0.18 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 3.0.17 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 3.0.16 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 3.0.15 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 3.0.14 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 3.0.13 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 3.0.12 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 3.0.11 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 3.0.10 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 3.0.9 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 3.0.8 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 3.0.7 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 3.0.6 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 3.0.5 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 3.0.4 Thu, 25 Oct 2018 08:56:03 GMT -*Version update only* +_Version update only_ ## 3.0.3 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 3.0.2 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 3.0.1 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 3.0.0 Wed, 17 Oct 2018 21:04:49 GMT @@ -639,67 +2828,67 @@ Wed, 17 Oct 2018 21:04:49 GMT ## 2.2.84 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 2.2.83 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 2.2.82 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 2.2.81 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 2.2.80 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 2.2.79 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 2.2.78 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 2.2.77 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 2.2.76 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 2.2.75 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 2.2.74 Thu, 20 Sep 2018 23:57:22 GMT -*Version update only* +_Version update only_ ## 2.2.73 Tue, 18 Sep 2018 21:04:56 GMT -*Version update only* +_Version update only_ ## 2.2.72 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 2.2.71 Thu, 06 Sep 2018 01:25:26 GMT @@ -711,37 +2900,37 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 2.2.70 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 2.2.69 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 2.2.68 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 2.2.67 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 2.2.66 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 2.2.65 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 2.2.64 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 2.2.63 Thu, 23 Aug 2018 18:18:53 GMT @@ -753,132 +2942,132 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 2.2.62 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 2.2.61 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 2.2.60 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 2.2.59 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 2.2.58 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 2.2.57 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 2.2.56 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 2.2.55 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 2.2.54 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 2.2.53 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 2.2.52 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 2.2.51 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 2.2.50 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 2.2.49 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 2.2.48 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 2.2.47 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 2.2.46 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 2.2.45 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 2.2.44 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 2.2.43 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 2.2.42 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 2.2.41 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 2.2.40 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 2.2.39 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 2.2.38 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 2.2.37 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 2.2.36 Mon, 30 Apr 2018 21:04:44 GMT @@ -890,42 +3079,42 @@ Mon, 30 Apr 2018 21:04:44 GMT ## 2.2.35 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 2.2.34 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 2.2.33 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 2.2.32 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 2.2.31 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 2.2.30 Mon, 02 Apr 2018 16:05:24 GMT -*Version update only* +_Version update only_ ## 2.2.29 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 2.2.28 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 2.2.27 Sun, 25 Mar 2018 01:26:19 GMT @@ -944,87 +3133,87 @@ Fri, 23 Mar 2018 00:34:53 GMT ## 2.2.25 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 2.2.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 2.2.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 2.2.22 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 2.2.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 2.2.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 2.2.19 Mon, 12 Mar 2018 20:36:19 GMT -*Version update only* +_Version update only_ ## 2.2.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 2.2.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 2.2.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 2.2.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 2.2.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 2.2.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 2.2.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 2.2.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 2.2.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 2.2.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 2.2.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1036,7 +3225,7 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 2.2.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 2.2.6 Tue, 23 Jan 2018 17:05:28 GMT @@ -1055,22 +3244,22 @@ Thu, 18 Jan 2018 03:23:46 GMT ## 2.2.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 2.2.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 2.2.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 2.2.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 2.2.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1082,57 +3271,57 @@ Wed, 10 Jan 2018 20:40:01 GMT ## 2.1.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 2.1.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 2.1.11 Fri, 05 Jan 2018 00:48:42 GMT -*Version update only* +_Version update only_ ## 2.1.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 2.1.9 Tue, 12 Dec 2017 03:33:27 GMT -*Version update only* +_Version update only_ ## 2.1.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 2.1.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 2.1.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 2.1.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 2.1.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 2.1.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 2.1.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -1144,7 +3333,7 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 2.1.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 2.1.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -1163,17 +3352,17 @@ Fri, 08 Sep 2017 01:28:04 GMT ## 2.0.6 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 2.0.5 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 2.0.4 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 2.0.3 Tue, 25 Jul 2017 20:03:31 GMT diff --git a/libraries/stream-collator/README.md b/libraries/stream-collator/README.md index 71f1575cd91..fed7d4f7d75 100644 --- a/libraries/stream-collator/README.md +++ b/libraries/stream-collator/README.md @@ -1,6 +1,6 @@ -## stream-collator +## @rushstack/stream-collator -This library enables a tool to display live console output from multiple asynchronous processes, +This library enables a tool to display live console output from multiple concurrent processes, while ensuring that their output does not get jumbled together. ## How does it work? @@ -18,8 +18,8 @@ Stream B will write: `BBBBBBBBBBBBBBBBBBBB` Stream C will write: `CCCCCCCCCC` -If these streams are all being piped directly to stdout (without stream-collator), you could end up with jumbled -output: +If these streams are all being piped directly to stdout (without `@rushstack/stream-collator`), you could end up +with jumbled output: `ABACCCBCCCCBBABBCBBABBBBBBCCAB` @@ -27,78 +27,31 @@ Something like the following would be much more useful to users of your applicat `AAAAABBBBBBBBBBBBBBBCCCCCCCCCC` -This is where the **stream-collator** comes in! - -## Usage - -Install the stream-collator: - -`npm install --save @rushstack/stream-collator` - - -Import the collator: - -```javascript -import StreamCollator from '@rushstack/stream-collator'; // es6 -``` - -```javascript -const StreamCollator = require('@rushstack/stream-collator'); // commonjs -``` - -A stream collator adheres to the [NodeJS Stream API](https://nodejs.org/api/stream.html), meaning that it effectively -is special type of [ReadableStream](https://nodejs.org/api/stream.html#stream_class_stream_readable). This makes -working with the stream collator very simple. Imagine we had the 3 streams from the example above: - -```javascript -const streamA = getRepeaterStream('A', 5); // fake helper function that returns a ReadableStream -const streamB = getRepeaterStream('B', 15); // fake helper function that returns a ReadableStream -const streamC = getRepeaterStream('C', 10); // fake helper function that returns a ReadableStream -``` - -Next, instantiate a stream collator instance and register the streams with it: - -```javascript -const collator = new StreamCollator(); - -collator.register(streamA); -collator.register(streamB); -collator.register(streamC); -``` - -`collator` is now a stream which can be accessed with the standard stream API's. For example, you could pass the output -to process.stdout: - -`collator.pipe(process.stdout);` - -Or a file: - -```javascript -var wstream = fs.createWriteStream('myOutput.txt'); - -collator.pipe(wstream); -``` +This is where the `@rushstack/stream-collator` comes in! ## The active stream + At any given time, a single stream is designated as the **active stream**. The output of the active stream will always be live-streamed. This is particularly useful for long-running streams. When the active stream finishes, a new stream is selected as the active stream and all of its contents up to that point will be emitted. Whenever an active stream finishes, all background streams which have been completed will be emitted. -## Helper streams -Two additional stream classes are also exported with this package: +## Usage + +> 🚨 _This is an early preview release. Please report issues!_ 🚨 +> +> WITH VERSION 4.X, THIS PACKAGE HAS BEEN REDESIGNED TO USE THE NEW +> [@rushstack/terminal](https://www.npmjs.com/package/@rushstack/terminal) SYSTEM. +> IN THE NEXT RELEASE, THE `CollatedTerminal` API WILL BE REPLACED WITH +> THE `Terminal` API. +> +> The usage instructions will be updated once that refactoring is complete. -### DualTaskStream -A utility string-based stream with two sub-streams, `stdout` and `stderr`. These streams can be written to, and will be emitted -by this class. Anything written to `stderr` will be automatically wrapped in red coloring, unless is begins with the text `Warning -`, -in which case it will write the warning to `stdout` in yellow. +## Links -### PersistentStream -A special string-based stream with a function `readAll()` which will return the contents of everything that has been written -to the stream as a string, regardless of whether the stream is open or closed. +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/stream-collator/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/stream-collator/) -## Improvements -NOTE: Ending the collator stream could be improved with an option that lets you select between the following behaviors: -* Close the collator stream when ANY registered stream has been closed -* Close the collator stream when ALL registered streams have been closed -* Don't automatically close the collator stream +`@rushstack/stream-collator` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/stream-collator/config/jest.config.json b/libraries/stream-collator/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/stream-collator/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/stream-collator/config/rig.json b/libraries/stream-collator/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/stream-collator/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/stream-collator/eslint.config.js b/libraries/stream-collator/eslint.config.js new file mode 100644 index 00000000000..f7f52307dac --- /dev/null +++ b/libraries/stream-collator/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 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'); + +module.exports = [ + ...nodeProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/stream-collator/gulpfile.js b/libraries/stream-collator/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/libraries/stream-collator/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/libraries/stream-collator/package.json b/libraries/stream-collator/package.json index b6e6bb098fd..c4166308327 100644 --- a/libraries/stream-collator/package.json +++ b/libraries/stream-collator/package.json @@ -1,29 +1,27 @@ { "name": "@rushstack/stream-collator", - "version": "3.2.6", - "description": "Display intelligible realtime output from your asynchronous streams", + "version": "4.1.119", + "description": "Display intelligible realtime output from concurrent processes", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/stream-collator" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/stream-collator" }, "main": "lib/index.js", "typings": "dist/stream-collator.d.ts", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "license": "MIT", "dependencies": { - "colors": "~1.2.1" + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@types/chai": "3.4.34", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "mocha": "^5.2.0", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/libraries/stream-collator/src/CollatedTerminal.ts b/libraries/stream-collator/src/CollatedTerminal.ts new file mode 100644 index 00000000000..2e969a21729 --- /dev/null +++ b/libraries/stream-collator/src/CollatedTerminal.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 ITerminalChunk, TerminalChunkKind, type TerminalWritable } from '@rushstack/terminal'; + +/** + * This API was introduced as a temporary measure. + * @deprecated Very soon we plan to replace this with the `Terminal` API from `@rushstack/node-core-library`. + * @beta + */ +export class CollatedTerminal { + private readonly _destination: TerminalWritable; + + public constructor(destination: TerminalWritable) { + this._destination = destination; + } + + public writeChunk(chunk: ITerminalChunk): void { + this._destination.writeChunk(chunk); + } + + public writeStdoutLine(message: string): void { + this._destination.writeChunk({ text: message + '\n', kind: TerminalChunkKind.Stdout }); + } + + public writeStderrLine(message: string): void { + this._destination.writeChunk({ text: message + '\n', kind: TerminalChunkKind.Stderr }); + } +} diff --git a/libraries/stream-collator/src/CollatedWriter.ts b/libraries/stream-collator/src/CollatedWriter.ts new file mode 100644 index 00000000000..a9fb2c91528 --- /dev/null +++ b/libraries/stream-collator/src/CollatedWriter.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. + +import { type ITerminalChunk, TerminalWritable } from '@rushstack/terminal'; + +import type { StreamCollator } from './StreamCollator'; +import { CollatedTerminal } from './CollatedTerminal'; + +/** + * An writable interface for managing output of simultaneous processes. + * + * @beta + */ +export class CollatedWriter extends TerminalWritable { + private readonly _collator: StreamCollator; + private readonly _bufferedChunks: ITerminalChunk[]; + + public readonly taskName: string; + public readonly terminal: CollatedTerminal; + + public constructor(taskName: string, collator: StreamCollator) { + super({ preventAutoclose: true }); + + this.taskName = taskName; + this.terminal = new CollatedTerminal(this); + + this._collator = collator; + + this._bufferedChunks = []; + } + + /** + * Returns true if this is the active writer for its associated {@link StreamCollator}. + */ + public get isActive(): boolean { + return this._collator.activeWriter === this; + } + + /** + * For diagnostic purposes, if the writer is buffering chunks because it has + * not become active yet, they can be inspected via this property. + */ + public get bufferedChunks(): ReadonlyArray { + return this._bufferedChunks; + } + + /** {@inheritDoc @rushstack/terminal#TerminalWritable.onWriteChunk} */ + public onWriteChunk(chunk: ITerminalChunk): void { + this._collator._writerWriteChunk(this, chunk, this._bufferedChunks); + } + + /** {@inheritDoc @rushstack/terminal#TerminalWritable.onClose} */ + public onClose(): void { + this._collator._writerClose(this, this._bufferedChunks); + } + + /** @internal */ + public _flushBufferedChunks(): void { + for (const chunk of this._bufferedChunks) { + this._collator.destination.writeChunk(chunk); + } + this._bufferedChunks.length = 0; + } +} diff --git a/libraries/stream-collator/src/Interleaver.ts b/libraries/stream-collator/src/Interleaver.ts deleted file mode 100644 index ce917be6ca4..00000000000 --- a/libraries/stream-collator/src/Interleaver.ts +++ /dev/null @@ -1,176 +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 colors from 'colors'; -import * as os from 'os'; - -/** - * An writable interface for managing output of simultaneous processes. - * - * @public - */ -export interface ITaskWriter { - write(data: string): void; // Writes a string to the buffer - writeLine(data: string): void; // Writes a string with a newline character at the end - writeError(data: string): void; // Writes an error to the stderr stream - getStdOutput(): string; // Returns standard output buffer as a string - getStdError(): string; // Returns standard error buffer as a string - close(): void; // Closes the stream and marks the simultaneous process as completed -} - -enum TaskWriterState { - Open = 1, - ClosedUnwritten = 2, - Written = 3 -} - -interface ITaskWriterInfo { - state: TaskWriterState; - quietMode: boolean; - stdout: string[]; - stderr: string[]; -} - -enum ITaskOutputStream { - stdout = 1, - stderr = 2 -} - -/** - * A static class which manages the output of multiple threads. - * - * @public - */ -export class Interleaver { - private static _tasks: Map = new Map(); - private static _activeTask: string = undefined; - private static _stdout: { write: (text: string) => void } = process.stdout; - - private constructor() { } - - /** - * Resets the default output stream - */ - public static setStdOut(stdout: { write: (text: string) => void }): void { - this._stdout = stdout; - } - - /** - * Registers a task into the list of active buffers and returns a ITaskWriter for the - * calling process to use to manage output. - */ - public static registerTask(taskName: string, quietMode: boolean = false): ITaskWriter { - if (this._tasks.has(taskName)) { - throw new Error('A task with that name has already been registered'); - } - - this._tasks.set(taskName, { - quietMode: quietMode, - state: TaskWriterState.Open, - stderr: [], - stdout: [] - }); - - if (this._activeTask === undefined) { - this._activeTask = taskName; - } - - return { - close: (): void => this._completeTask(taskName), - getStdError: (): string => this._getTaskOutput(taskName, ITaskOutputStream.stderr), - getStdOutput: (): string => this._getTaskOutput(taskName), - write: (data: string): void => this._writeTaskOutput(taskName, data), - writeError: (data: string): void => this._writeTaskOutput(taskName, data, ITaskOutputStream.stderr), - writeLine: (data: string): void => this._writeTaskOutput(taskName, data + os.EOL) - }; - } - - /** - * Removes information about all running tasks - */ - public static reset(): void { - this._activeTask = undefined; - this._tasks = new Map(); - } - - /** - * Adds the text to the task's buffer, and writes it to the console if it is the active task - */ - private static _writeTaskOutput(taskName: string, data: string, - stream: ITaskOutputStream = ITaskOutputStream.stdout): void { - - const taskInfo: ITaskWriterInfo = this._tasks.get(taskName); - if (!taskInfo || taskInfo.state !== TaskWriterState.Open) { - throw new Error('The task is not registered or has been completed and written.'); - } - const outputBuffer: string[] = (stream === ITaskOutputStream.stderr ? taskInfo.stderr : taskInfo.stdout); - - if (!this._activeTask) { - this._activeTask = taskName; - this._writeTask(taskName, taskInfo); - taskInfo.state = TaskWriterState.Open; - } - - outputBuffer.push(data); - if (this._activeTask === taskName) { - if (stream === ITaskOutputStream.stdout && !taskInfo.quietMode) { - this._stdout.write(data); - } else if (stream === ITaskOutputStream.stderr) { - this._stdout.write(data); - } - } - } - - /** - * Returns the current value of the task's buffer - */ - private static _getTaskOutput(taskName: string, stream: ITaskOutputStream = ITaskOutputStream.stdout): string { - const taskInfo: ITaskWriterInfo = this._tasks.get(taskName); - return (stream === ITaskOutputStream.stdout ? taskInfo.stdout : taskInfo.stderr).join(''); - } - - /** - * Marks a task as completed. There are 3 cases: - * - If the task was the active task, also write out all completed, unwritten tasks - * - If there is no active task, write the output to the screen - * - If there is an active task, mark the task as completed and wait for active task to complete - */ - private static _completeTask(taskName: string): void { - const taskInfo: ITaskWriterInfo = this._tasks.get(taskName); - if (!taskInfo || taskInfo.state !== TaskWriterState.Open) { - throw new Error('The task is not registered or has been completed and written.'); - } - - if (this._activeTask === undefined) { - this._writeTask(taskName, taskInfo); - } else if (taskName === this._activeTask) { - this._activeTask = undefined; - taskInfo.state = TaskWriterState.Written; - this._writeAllCompletedTasks(); - } else { - taskInfo.state = TaskWriterState.ClosedUnwritten; - } - } - - /** - * Helper function which writes all completed tasks - */ - private static _writeAllCompletedTasks(): void { - this._tasks.forEach((task: ITaskWriterInfo, taskName: string) => { - if (task && task.state === TaskWriterState.ClosedUnwritten) { - this._writeTask(taskName, task); - } - }); - } - - /** - * Write and delete task - */ - private static _writeTask(taskName: string, taskInfo: ITaskWriterInfo): void { - taskInfo.state = TaskWriterState.Written; - if (!taskInfo.quietMode) { - this._stdout.write(taskInfo.stdout.join('')); - } - this._stdout.write(colors.red(taskInfo.stderr.join(''))); - } -} diff --git a/libraries/stream-collator/src/StreamCollator.ts b/libraries/stream-collator/src/StreamCollator.ts new file mode 100644 index 00000000000..3cd51ac3d1b --- /dev/null +++ b/libraries/stream-collator/src/StreamCollator.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 { InternalError } from '@rushstack/node-core-library'; +import type { TerminalWritable, ITerminalChunk } from '@rushstack/terminal'; + +import { CollatedWriter } from './CollatedWriter'; +import { CollatedTerminal } from './CollatedTerminal'; + +/** + * Constructor options for {@link StreamCollator}. + * + * @beta + */ +export interface IStreamCollatorOptions { + /** + * The target {@link @rushstack/terminal#TerminalWritable} object that the + * {@link StreamCollator} will write its output to. + */ + destination: TerminalWritable; + + /** + * An event handler that is called when a {@link CollatedWriter} becomes output, + * before any of its chunks have been written to the destination. + * + * @remarks + * + * Each `CollatedWriter` object will become active exactly once + * before the `StreamCollator` completes. + */ + onWriterActive?: (writer: CollatedWriter) => void; +} + +/** + * A static class which manages the output of multiple threads. + * + * @beta + */ +export class StreamCollator { + private _taskNames: Set = new Set(); + private _writers: Set = new Set(); + + // The writer whose output is being shown in realtime, or undefined if none + private _activeWriter: CollatedWriter | undefined = undefined; + + // Writers that are not closed yet, and have never been active + private _openInactiveWriters: Set = new Set(); + + // Writers that are now closed, but have accumulated buffered chunks, and have never been active + private _closedInactiveWriters: Set = new Set(); + + private _onWriterActive: ((writer: CollatedWriter) => void) | undefined; + + private _preventReentrantCall: boolean = false; + + public readonly destination: TerminalWritable; + public readonly terminal: CollatedTerminal; + + public constructor(options: IStreamCollatorOptions) { + this.destination = options.destination; + this.terminal = new CollatedTerminal(this.destination); + this._onWriterActive = options.onWriterActive; + } + + /** + * Returns the currently active `CollatedWriter`, or `undefined` if no writer + * is active yet. + */ + public get activeWriter(): CollatedWriter | undefined { + return this._activeWriter; + } + + /** + * For diagnostic purposes, returns the {@link CollatedWriter.taskName} for the + * currently active writer, or an empty string if no writer is active. + */ + public get activeTaskName(): string { + if (this._activeWriter) { + return this._activeWriter.taskName; + } + return ''; + } + + /** + * The list of writers that have been registered by calling {@link StreamCollator.registerTask}, + * in the order that they were registered. + */ + public get writers(): ReadonlySet { + return this._writers; + } + + /** + * Registers a new task to be collated, and constructs a {@link CollatedWriter} object + * to receive its input. + */ + public registerTask(taskName: string): CollatedWriter { + if (this._taskNames.has(taskName)) { + throw new Error('A task with that name has already been registered'); + } + + const writer: CollatedWriter = new CollatedWriter(taskName, this); + + this._writers.add(writer); + this._taskNames.add(writer.taskName); + + // When a task is initially registered, it is open and has not accumulated any buffered chunks + this._openInactiveWriters.add(writer); + + if (this._activeWriter === undefined) { + // If there is no active writer, then the first one to be registered becomes active. + this._assignActiveWriter(writer); + } + + return writer; + } + + /** @internal */ + public _writerWriteChunk( + writer: CollatedWriter, + chunk: ITerminalChunk, + bufferedChunks: ITerminalChunk[] + ): void { + this._checkForReentrantCall(); + + if (this._activeWriter === undefined) { + // If no writer is currently active, then the first one to write something becomes active + this._assignActiveWriter(writer); + } + + if (writer.isActive) { + this.destination.writeChunk(chunk); + } else { + bufferedChunks.push(chunk); + } + } + + /** @internal */ + public _writerClose(writer: CollatedWriter, bufferedChunks: ITerminalChunk[]): void { + this._checkForReentrantCall(); + + if (writer.isActive) { + writer._flushBufferedChunks(); + + this._activeWriter = undefined; + + // If any buffered writers are already closed, activate them each immediately + // We copy the set, since _assignActiveWriter() will be deleting from it. + for (const closedInactiveWriter of [...this._closedInactiveWriters]) { + try { + this._assignActiveWriter(closedInactiveWriter); + } finally { + this._activeWriter = undefined; + } + } + + let writerToActivate: CollatedWriter | undefined = undefined; + + // Try to activate a writer that already accumulated some data + for (const openInactiveWriter of this._openInactiveWriters) { + if (openInactiveWriter.bufferedChunks.length > 0) { + writerToActivate = openInactiveWriter; + break; + } + } + if (!writerToActivate) { + // Otherwise just take the first one + for (const openInactiveWriter of this._openInactiveWriters) { + writerToActivate = openInactiveWriter; + break; + } + } + + if (writerToActivate) { + this._assignActiveWriter(writerToActivate); + } + } else { + this._openInactiveWriters.delete(writer); + this._closedInactiveWriters.add(writer); + } + } + + private _assignActiveWriter(writer: CollatedWriter): void { + this._activeWriter = writer; + + this._closedInactiveWriters.delete(writer); + this._openInactiveWriters.delete(writer); + + if (this._onWriterActive) { + this._preventReentrantCall = true; + try { + this._onWriterActive(writer); + } finally { + this._preventReentrantCall = false; + } + } + + writer._flushBufferedChunks(); + } + + private _checkForReentrantCall(): void { + if (this._preventReentrantCall) { + throw new InternalError('Reentrant call to StreamCollator'); + } + } +} diff --git a/libraries/stream-collator/src/index.ts b/libraries/stream-collator/src/index.ts index 36f5cad362b..fb5effe5f82 100644 --- a/libraries/stream-collator/src/index.ts +++ b/libraries/stream-collator/src/index.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. /** - * This library enables a tool to display live console output from multiple asynchronous processes, + * This library enables a tool to display live console output from multiple concurrent processes, * while ensuring that their output does not get jumbled together. * * @remarks @@ -13,7 +13,6 @@ * @packageDocumentation */ -export { - Interleaver, - ITaskWriter -} from './Interleaver'; +export * from './CollatedTerminal'; +export * from './CollatedWriter'; +export * from './StreamCollator'; diff --git a/libraries/stream-collator/src/test/Interleaver.test.ts b/libraries/stream-collator/src/test/Interleaver.test.ts deleted file mode 100644 index aff34e721e8..00000000000 --- a/libraries/stream-collator/src/test/Interleaver.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/// - -import { assert } from 'chai'; -import * as os from 'os'; - -import { Interleaver, ITaskWriter } from '../Interleaver'; - -class StringStream { - private _buffer: string[] = []; - - public write(text: string): void { - this._buffer.push(text); - } - - public read(): string { - return this._buffer.join(''); - } - - public reset(): void { - this._buffer = []; - } -} - -const stdout: StringStream = new StringStream(); -Interleaver.setStdOut(stdout); - -describe('Interleaver tests', () => { - // Reset task information before each test - beforeEach(() => { - Interleaver.reset(); - stdout.reset(); - }); - - describe('Testing register and close', () => { - it('can register a task', (done: MochaDone) => { - const helloWorldWriter: ITaskWriter = Interleaver.registerTask('Hello World'); - assert.isObject(helloWorldWriter); - done(); - }); - - it('should not let you register two tasks with the same name', (done: MochaDone) => { - const taskName: string = 'Hello World'; - assert.doesNotThrow(() => { Interleaver.registerTask(taskName); }); - assert.throws(() => { Interleaver.registerTask(taskName); }); - done(); - }); - - it('should not let you close a task twice', (done: MochaDone) => { - const taskName: string = 'Hello World'; - const task: ITaskWriter = Interleaver.registerTask(taskName); - task.close(); - assert.throws(task.close); - done(); - }); - - it('should not let you write to a closed task', (done: MochaDone) => { - const taskName: string = 'Hello World'; - const task: ITaskWriter = Interleaver.registerTask(taskName); - task.close(); - assert.throws(() => { task.write('1'); }); - done(); - }); - }); - - describe('Testing write functions', () => { - it('writeLine should add a newline', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A'); - const text: string = 'Hello World'; - - taskA.writeLine(text); - - assert.equal(taskA.getStdOutput(), text + os.EOL); - done(); - }); - - it('should write errors to stderr', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A'); - const error: string = 'Critical error'; - - taskA.writeError(error); - assert.equal(stdout.read(), error); - - taskA.close(); - - assert.equal(taskA.getStdOutput(), ''); - assert.equal(taskA.getStdError(), error); - - done(); - }); - }); - - describe('Testing that output is interleaved', () => { - it('should not write non-active tasks to stdout', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A'); - const taskB: ITaskWriter = Interleaver.registerTask('B'); - - taskA.write('1'); - assert.equal(stdout.read(), '1'); - - taskB.write('2'); - assert.equal(stdout.read(), '1'); - - taskA.write('3'); - assert.equal(stdout.read(), '13'); - - taskA.close(); - assert.equal(stdout.read(), '13'); - - taskB.close(); - assert.equal(stdout.read(), '132'); - - assert.equal(taskA.getStdOutput(), '13'); - assert.equal(taskB.getStdOutput(), '2'); - done(); - }); - - it('should not write anything when in quiet mode', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A', true); - const taskB: ITaskWriter = Interleaver.registerTask('B', true); - - taskA.write('1'); - assert.equal(stdout.read(), ''); - - taskB.write('2'); - assert.equal(stdout.read(), ''); - - taskA.write('3'); - assert.equal(stdout.read(), ''); - - taskA.close(); - assert.equal(stdout.read(), ''); - - taskB.close(); - assert.equal(stdout.read(), ''); - - assert.equal(taskA.getStdOutput(), '13'); - assert.equal(taskB.getStdOutput(), '2'); - done(); - }); - - it('should update the active task once the active task is closed', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A'); - const taskB: ITaskWriter = Interleaver.registerTask('B'); - - taskA.write('1'); - assert.equal(stdout.read(), '1'); - - taskA.close(); - assert.equal(stdout.read(), '1'); - - taskB.write('2'); - assert.equal(stdout.read(), '12'); - - taskB.close(); - assert.equal(stdout.read(), '12'); - - assert.equal(taskA.getStdOutput(), '1'); - assert.equal(taskB.getStdOutput(), '2'); - done(); - }); - - it('should write completed tasks after the active task is completed', (done: MochaDone) => { - const taskA: ITaskWriter = Interleaver.registerTask('A'); - const taskB: ITaskWriter = Interleaver.registerTask('B'); - - taskA.write('1'); - assert.equal(stdout.read(), '1'); - - taskB.write('2'); - assert.equal(stdout.read(), '1'); - - taskB.close(); - assert.equal(stdout.read(), '1'); - - taskA.close(); - assert.equal(stdout.read(), '12'); - - assert.equal(taskA.getStdOutput(), '1'); - assert.equal(taskB.getStdOutput(), '2'); - done(); - }); - }); -}); diff --git a/libraries/stream-collator/src/test/StreamCollator.test.ts b/libraries/stream-collator/src/test/StreamCollator.test.ts new file mode 100644 index 00000000000..ad931167d89 --- /dev/null +++ b/libraries/stream-collator/src/test/StreamCollator.test.ts @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TerminalChunkKind, MockWritable } from '@rushstack/terminal'; + +import { StreamCollator } from '../StreamCollator'; +import type { CollatedWriter } from '../CollatedWriter'; + +let collator: StreamCollator; +const mockWritable: MockWritable = new MockWritable(); + +describe(StreamCollator.name, () => { + // Reset task information before each test + beforeEach(() => { + mockWritable.reset(); + collator = new StreamCollator({ destination: mockWritable }); + }); + + describe('Testing register and close', () => { + it('can register a task', () => { + const helloWorldWriter: CollatedWriter = collator.registerTask('Hello World'); + expect(helloWorldWriter.taskName).toEqual('Hello World'); + }); + + it('should not let you register two tasks with the same name', () => { + const taskName: string = 'Hello World'; + expect(() => { + collator.registerTask(taskName); + }).not.toThrow(); + expect(() => { + collator.registerTask(taskName); + }).toThrow(); + }); + + it('should not let you close a task twice', () => { + const taskName: string = 'Hello World'; + const writer: CollatedWriter = collator.registerTask(taskName); + writer.close(); + expect(writer.close).toThrow(); + }); + + it('should not let you write to a closed task', () => { + const taskName: string = 'Hello World'; + const writer: CollatedWriter = collator.registerTask(taskName); + writer.close(); + expect(() => { + writer.terminal.writeChunk({ text: '1', kind: TerminalChunkKind.Stdout }); + }).toThrow(); + }); + }); + + describe('Testing write functions', () => { + it('writeLine should add a newline', () => { + const taskA: CollatedWriter = collator.registerTask('A'); + const text: string = 'Hello World'; + + taskA.terminal.writeChunk({ text, kind: TerminalChunkKind.Stdout }); + + expect(mockWritable.chunks).toEqual([{ text, kind: TerminalChunkKind.Stdout }]); + }); + + it('should write errors to stderr', () => { + const taskA: CollatedWriter = collator.registerTask('A'); + const error: string = 'Critical error'; + + taskA.terminal.writeChunk({ text: error, kind: TerminalChunkKind.Stderr }); + + expect(mockWritable.chunks).toEqual([{ text: error, kind: TerminalChunkKind.Stderr }]); + + taskA.close(); + + expect(taskA.bufferedChunks).toEqual([]); + expect(mockWritable.chunks).toEqual([{ text: error, kind: TerminalChunkKind.Stderr }]); + }); + }); + + describe('Testing that output is interleaved', () => { + it('should not write non-active tasks to stdout', () => { + const taskA: CollatedWriter = collator.registerTask('A'); + const taskB: CollatedWriter = collator.registerTask('B'); + + taskA.terminal.writeChunk({ text: '1', kind: TerminalChunkKind.Stdout }); + expect(taskA.bufferedChunks).toEqual([]); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + + taskB.terminal.writeChunk({ text: '2', kind: TerminalChunkKind.Stdout }); + expect(taskB.bufferedChunks).toEqual([{ text: '2', kind: TerminalChunkKind.Stdout }]); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + + taskA.terminal.writeChunk({ text: '3', kind: TerminalChunkKind.Stdout }); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '3', kind: TerminalChunkKind.Stdout } + ]); + + taskA.close(); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '3', kind: TerminalChunkKind.Stdout }, + { text: '2', kind: TerminalChunkKind.Stdout } + ]); + + taskB.close(); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '3', kind: TerminalChunkKind.Stdout }, + { text: '2', kind: TerminalChunkKind.Stdout } + ]); + + expect(taskA.bufferedChunks).toEqual([]); + expect(taskB.bufferedChunks).toEqual([]); + }); + + it('should update the active task once the active task is closed', () => { + const taskA: CollatedWriter = collator.registerTask('A'); + const taskB: CollatedWriter = collator.registerTask('B'); + + taskA.terminal.writeChunk({ text: '1', kind: TerminalChunkKind.Stdout }); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + taskA.close(); + + taskB.terminal.writeChunk({ text: '2', kind: TerminalChunkKind.Stdout }); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '2', kind: TerminalChunkKind.Stdout } + ]); + taskB.close(); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '2', kind: TerminalChunkKind.Stdout } + ]); + }); + + it('should write completed tasks after the active task is completed', () => { + const taskA: CollatedWriter = collator.registerTask('A'); + const taskB: CollatedWriter = collator.registerTask('B'); + + taskA.terminal.writeChunk({ text: '1', kind: TerminalChunkKind.Stdout }); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + + taskB.terminal.writeChunk({ text: '2', kind: TerminalChunkKind.Stdout }); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + + taskB.close(); + expect(mockWritable.chunks).toEqual([{ text: '1', kind: TerminalChunkKind.Stdout }]); + + taskA.close(); + expect(mockWritable.chunks).toEqual([ + { text: '1', kind: TerminalChunkKind.Stdout }, + { text: '2', kind: TerminalChunkKind.Stdout } + ]); + }); + }); +}); diff --git a/libraries/stream-collator/tsconfig.json b/libraries/stream-collator/tsconfig.json index b005b839840..c7c88d9fc21 100644 --- a/libraries/stream-collator/tsconfig.json +++ b/libraries/stream-collator/tsconfig.json @@ -1,9 +1,6 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "strictNullChecks": false, - "types": [ - "node" - ] + "strictNullChecks": false } } diff --git a/libraries/terminal/.npmignore b/libraries/terminal/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/terminal/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/terminal/CHANGELOG.json b/libraries/terminal/CHANGELOG.json new file mode 100644 index 00000000000..a04d9096090 --- /dev/null +++ b/libraries/terminal/CHANGELOG.json @@ -0,0 +1,5177 @@ +{ + "name": "@rushstack/terminal", + "entries": [ + { + "version": "0.19.5", + "tag": "@rushstack/terminal_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`" + } + ] + } + }, + { + "version": "0.19.4", + "tag": "@rushstack/terminal_v0.19.4", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + } + ] + } + }, + { + "version": "0.19.3", + "tag": "@rushstack/terminal_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`" + } + ] + } + }, + { + "version": "0.19.2", + "tag": "@rushstack/terminal_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`" + } + ] + } + }, + { + "version": "0.19.1", + "tag": "@rushstack/terminal_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`" + } + ] + } + }, + { + "version": "0.19.0", + "tag": "@rushstack/terminal_v0.19.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`" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/terminal_v0.18.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "minor": [ + { + "comment": "Add ProblemCollector.onProblem notification callback" + }, + { + "comment": "Update API contract for `SplitterTransform` to support adding and removing destinations after creation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/terminal_v0.17.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add `ProblemCollector extends TerminalWritable` API which matches and collects VS Code style problem matchers" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/terminal_v0.16.0", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove support for legacy `IColorableSequence` parameters passed to `Terminal` insance `write*` functions. Note that types for `IColorableSequence` were removed with #3176 in 2022." + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/terminal_v0.15.4", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/terminal_v0.15.3", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/terminal_v0.15.2", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/terminal_v0.15.1", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/terminal_v0.15.0", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a NoOpTerminalProvider." + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/terminal_v0.14.6", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/terminal_v0.14.5", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/terminal_v0.14.4", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/terminal_v0.14.3", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/terminal_v0.14.2", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/terminal_v0.14.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/terminal_v0.14.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Create a new instance function called `getVerboseOutput` on `StringBufferTerminalProvider` and mark `getVerbose` as deprecated." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/terminal_v0.13.4", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/terminal_v0.13.3", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/terminal_v0.13.2", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the PrintUtilities API to handle an edge case when word-wrapping a final line" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/terminal_v0.13.1", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/terminal_v0.13.0", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "minor": [ + { + "comment": "Eliminate a const enum from the public API." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/terminal_v0.12.3", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/terminal_v0.12.2", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/terminal_v0.12.1", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/terminal_v0.12.0", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "minor": [ + { + "comment": "Change the `eolCharacter` property value of `StringBufferTerminalProvider` to `\\n` from `[n]`. This does not change the default `getOutput()` result, but removes the `[n]` characters from the `getOutput({ normalizeSpecialCharacters: false })` result." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/terminal_v0.11.1", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/terminal_v0.11.0", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "minor": [ + { + "comment": "Allow use of 'preventAutoclose' flag in StdioSummarizer." + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/terminal_v0.10.4", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/terminal_v0.10.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/terminal_v0.10.2", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/terminal_v0.10.1", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/terminal_v0.10.0", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "minor": [ + { + "comment": "Replace the `colors` dependency with `supports-color` for detecting if STDOUT and STDERR support color." + }, + { + "comment": "Add a `Colorize.rainbow` API." + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/terminal_v0.9.0", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "minor": [ + { + "comment": "Expose a `supportsColor` property on `ConsoleTerminalProvider`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/terminal_v0.8.1", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a recent regression causing `Error: Cannot find module 'colors/safe'` (GitHub #4525)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/terminal_v0.8.0", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a Terminal, Colors, AsciEscape, and some related APIs. These APIs were previously in the @rushstack/node-core-library package. See https://github.com/microsoft/rushstack/pull/3176 for details." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + } + ] + } + }, + { + "version": "0.7.24", + "tag": "@rushstack/terminal_v0.7.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.7.23", + "tag": "@rushstack/terminal_v0.7.23", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.7.22", + "tag": "@rushstack/terminal_v0.7.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.7.21", + "tag": "@rushstack/terminal_v0.7.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.7.20", + "tag": "@rushstack/terminal_v0.7.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.7.19", + "tag": "@rushstack/terminal_v0.7.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/terminal_v0.7.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/terminal_v0.7.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/terminal_v0.7.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/terminal_v0.7.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/terminal_v0.7.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/terminal_v0.7.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/terminal_v0.7.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/terminal_v0.7.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/terminal_v0.7.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/terminal_v0.7.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/terminal_v0.7.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/terminal_v0.7.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where `PrintUtilities.printMessageInBox` would throw if the message contains a word that is longer than the box width. In this case, `printMessageInBox` will print bars above and below the message, and then print the message lines, allowing the console to wrap them." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/terminal_v0.7.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/terminal_v0.7.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/terminal_v0.7.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/terminal_v0.7.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/terminal_v0.7.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/terminal_v0.7.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/terminal_v0.7.0", + "date": "Tue, 19 Sep 2023 00:36:30 GMT", + "comments": { + "minor": [ + { + "comment": "Remove the dependency on `wordwrap`." + }, + { + "comment": "Add support for a custom line prefix in `PrintUtilities.wrapWords`." + }, + { + "comment": "Add a `PrintUtilities.wrapWordsToLines` function that is functionally identical to `PrintUtilities.wrapWords`, except that it returns an array of lines instead of a joined string with line breaks." + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/terminal_v0.6.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.5.38", + "tag": "@rushstack/terminal_v0.5.38", + "date": "Thu, 24 Aug 2023 15:20:46 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a minor logic issue for TextRewriterTransform cleanup" + } + ] + } + }, + { + "version": "0.5.37", + "tag": "@rushstack/terminal_v0.5.37", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.5.36", + "tag": "@rushstack/terminal_v0.5.36", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.5.35", + "tag": "@rushstack/terminal_v0.5.35", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.5.34", + "tag": "@rushstack/terminal_v0.5.34", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.5.33", + "tag": "@rushstack/terminal_v0.5.33", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.5.32", + "tag": "@rushstack/terminal_v0.5.32", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.5.31", + "tag": "@rushstack/terminal_v0.5.31", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/terminal_v0.5.30", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/terminal_v0.5.29", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/terminal_v0.5.28", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/terminal_v0.5.27", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/terminal_v0.5.26", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/terminal_v0.5.25", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/terminal_v0.5.24", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/terminal_v0.5.23", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/terminal_v0.5.22", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/terminal_v0.5.21", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/terminal_v0.5.20", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/terminal_v0.5.19", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/terminal_v0.5.18", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/terminal_v0.5.17", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/terminal_v0.5.16", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/terminal_v0.5.15", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/terminal_v0.5.14", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/terminal_v0.5.13", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/terminal_v0.5.12", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/terminal_v0.5.11", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/terminal_v0.5.10", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/terminal_v0.5.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/terminal_v0.5.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/terminal_v0.5.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/terminal_v0.5.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/terminal_v0.5.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/terminal_v0.5.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/terminal_v0.5.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/terminal_v0.5.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/terminal_v0.5.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/terminal_v0.5.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/terminal_v0.4.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.3.92", + "tag": "@rushstack/terminal_v0.3.92", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.3.91", + "tag": "@rushstack/terminal_v0.3.91", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.3.90", + "tag": "@rushstack/terminal_v0.3.90", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.3.89", + "tag": "@rushstack/terminal_v0.3.89", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.3.88", + "tag": "@rushstack/terminal_v0.3.88", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.3.87", + "tag": "@rushstack/terminal_v0.3.87", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.3.86", + "tag": "@rushstack/terminal_v0.3.86", + "date": "Mon, 05 Dec 2022 16:16:09 GMT", + "comments": { + "patch": [ + { + "comment": "The wrapWords method now respects existing spaces and newlines in a pre-formatted message." + } + ] + } + }, + { + "version": "0.3.85", + "tag": "@rushstack/terminal_v0.3.85", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.3.84", + "tag": "@rushstack/terminal_v0.3.84", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.3.83", + "tag": "@rushstack/terminal_v0.3.83", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.3.82", + "tag": "@rushstack/terminal_v0.3.82", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.3.81", + "tag": "@rushstack/terminal_v0.3.81", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.3.80", + "tag": "@rushstack/terminal_v0.3.80", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.3.79", + "tag": "@rushstack/terminal_v0.3.79", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.3.78", + "tag": "@rushstack/terminal_v0.3.78", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.3.77", + "tag": "@rushstack/terminal_v0.3.77", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.3.76", + "tag": "@rushstack/terminal_v0.3.76", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/terminal_v0.3.75", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/terminal_v0.3.74", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/terminal_v0.3.73", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/terminal_v0.3.72", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/terminal_v0.3.71", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/terminal_v0.3.70", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/terminal_v0.3.69", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/terminal_v0.3.68", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/terminal_v0.3.67", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/terminal_v0.3.66", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/terminal_v0.3.65", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/terminal_v0.3.64", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/terminal_v0.3.63", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/terminal_v0.3.62", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.3.61", + "tag": "@rushstack/terminal_v0.3.61", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/terminal_v0.3.60", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/terminal_v0.3.59", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/terminal_v0.3.58", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/terminal_v0.3.57", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/terminal_v0.3.56", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/terminal_v0.3.55", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/terminal_v0.3.54", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/terminal_v0.3.53", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/terminal_v0.3.52", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/terminal_v0.3.51", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/terminal_v0.3.50", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/terminal_v0.3.49", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/terminal_v0.3.48", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/terminal_v0.3.47", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/terminal_v0.3.46", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/terminal_v0.3.45", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/terminal_v0.3.44", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/terminal_v0.3.43", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/terminal_v0.3.42", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/terminal_v0.3.41", + "date": "Tue, 10 May 2022 01:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/terminal_v0.3.40", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/terminal_v0.3.39", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/terminal_v0.3.38", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/terminal_v0.3.37", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/terminal_v0.3.36", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/terminal_v0.3.35", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/terminal_v0.3.34", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/terminal_v0.3.33", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/terminal_v0.3.32", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/terminal_v0.3.31", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/terminal_v0.3.30", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/terminal_v0.3.29", + "date": "Thu, 31 Mar 2022 02:06:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/terminal_v0.3.28", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/terminal_v0.3.27", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/terminal_v0.3.26", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/terminal_v0.3.25", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/terminal_v0.3.24", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/terminal_v0.3.23", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/terminal_v0.3.22", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/terminal_v0.3.21", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/terminal_v0.3.20", + "date": "Tue, 14 Dec 2021 19:27:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/terminal_v0.3.19", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/terminal_v0.3.18", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/terminal_v0.3.17", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/terminal_v0.3.16", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/terminal_v0.3.15", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/terminal_v0.3.14", + "date": "Fri, 03 Dec 2021 03:05:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/terminal_v0.3.13", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/terminal_v0.3.12", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/terminal_v0.3.11", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/terminal_v0.3.10", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/terminal_v0.3.9", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/terminal_v0.3.8", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/terminal_v0.3.7", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/terminal_v0.3.6", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/terminal_v0.3.5", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/terminal_v0.3.4", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/terminal_v0.3.3", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/terminal_v0.3.2", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/terminal_v0.3.1", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/terminal_v0.3.0", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/terminal_v0.2.32", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/terminal_v0.2.31", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/terminal_v0.2.30", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/terminal_v0.2.29", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/terminal_v0.2.28", + "date": "Wed, 22 Sep 2021 00:09:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/terminal_v0.2.27", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/terminal_v0.2.26", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/terminal_v0.2.25", + "date": "Mon, 13 Sep 2021 15:07:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/terminal_v0.2.24", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/terminal_v0.2.23", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/terminal_v0.2.22", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/terminal_v0.2.21", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/terminal_v0.2.20", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/terminal_v0.2.19", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/terminal_v0.2.18", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/terminal_v0.2.17", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/terminal_v0.2.16", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/terminal_v0.2.15", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/terminal_v0.2.14", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/terminal_v0.2.13", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/terminal_v0.2.12", + "date": "Sat, 31 Jul 2021 00:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/terminal_v0.2.11", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/terminal_v0.2.10", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/terminal_v0.2.9", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/terminal_v0.2.8", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/terminal_v0.2.7", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/terminal_v0.2.6", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/terminal_v0.2.5", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/terminal_v0.2.4", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/terminal_v0.2.3", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/terminal_v0.2.2", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/terminal_v0.2.1", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/terminal_v0.2.0", + "date": "Fri, 18 Jun 2021 00:08:51 GMT", + "comments": { + "minor": [ + { + "comment": "Export console printing utilities from the PrintUtility class." + } + ] + } + }, + { + "version": "0.1.96", + "tag": "@rushstack/terminal_v0.1.96", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.1.95", + "tag": "@rushstack/terminal_v0.1.95", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.1.94", + "tag": "@rushstack/terminal_v0.1.94", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.1.93", + "tag": "@rushstack/terminal_v0.1.93", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "0.1.92", + "tag": "@rushstack/terminal_v0.1.92", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "0.1.91", + "tag": "@rushstack/terminal_v0.1.91", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "0.1.90", + "tag": "@rushstack/terminal_v0.1.90", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "0.1.89", + "tag": "@rushstack/terminal_v0.1.89", + "date": "Fri, 04 Jun 2021 15:08:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "0.1.88", + "tag": "@rushstack/terminal_v0.1.88", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "0.1.87", + "tag": "@rushstack/terminal_v0.1.87", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "0.1.86", + "tag": "@rushstack/terminal_v0.1.86", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "0.1.85", + "tag": "@rushstack/terminal_v0.1.85", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "0.1.84", + "tag": "@rushstack/terminal_v0.1.84", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "0.1.83", + "tag": "@rushstack/terminal_v0.1.83", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "0.1.82", + "tag": "@rushstack/terminal_v0.1.82", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "0.1.81", + "tag": "@rushstack/terminal_v0.1.81", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "0.1.80", + "tag": "@rushstack/terminal_v0.1.80", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "0.1.79", + "tag": "@rushstack/terminal_v0.1.79", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "0.1.78", + "tag": "@rushstack/terminal_v0.1.78", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "0.1.77", + "tag": "@rushstack/terminal_v0.1.77", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "0.1.76", + "tag": "@rushstack/terminal_v0.1.76", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "0.1.75", + "tag": "@rushstack/terminal_v0.1.75", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "0.1.74", + "tag": "@rushstack/terminal_v0.1.74", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "0.1.73", + "tag": "@rushstack/terminal_v0.1.73", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "0.1.72", + "tag": "@rushstack/terminal_v0.1.72", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "0.1.71", + "tag": "@rushstack/terminal_v0.1.71", + "date": "Thu, 08 Apr 2021 20:41:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "0.1.70", + "tag": "@rushstack/terminal_v0.1.70", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "0.1.69", + "tag": "@rushstack/terminal_v0.1.69", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "0.1.68", + "tag": "@rushstack/terminal_v0.1.68", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "0.1.67", + "tag": "@rushstack/terminal_v0.1.67", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "0.1.66", + "tag": "@rushstack/terminal_v0.1.66", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "0.1.65", + "tag": "@rushstack/terminal_v0.1.65", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "0.1.64", + "tag": "@rushstack/terminal_v0.1.64", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "0.1.63", + "tag": "@rushstack/terminal_v0.1.63", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "0.1.62", + "tag": "@rushstack/terminal_v0.1.62", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.61", + "tag": "@rushstack/terminal_v0.1.61", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "0.1.60", + "tag": "@rushstack/terminal_v0.1.60", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "0.1.59", + "tag": "@rushstack/terminal_v0.1.59", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/terminal_v0.1.58", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/terminal_v0.1.57", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/terminal_v0.1.56", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/terminal_v0.1.55", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/terminal_v0.1.54", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/terminal_v0.1.53", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/terminal_v0.1.52", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/terminal_v0.1.51", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/terminal_v0.1.50", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/terminal_v0.1.49", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/terminal_v0.1.48", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/terminal_v0.1.47", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/terminal_v0.1.46", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/terminal_v0.1.45", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/terminal_v0.1.44", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/terminal_v0.1.43", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/terminal_v0.1.42", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/terminal_v0.1.41", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/terminal_v0.1.40", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/terminal_v0.1.39", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/terminal_v0.1.38", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/terminal_v0.1.37", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/terminal_v0.1.36", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/terminal_v0.1.35", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/terminal_v0.1.34", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/terminal_v0.1.33", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/terminal_v0.1.32", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/terminal_v0.1.31", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/terminal_v0.1.30", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/terminal_v0.1.29", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/terminal_v0.1.28", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/terminal_v0.1.27", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/terminal_v0.1.26", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/terminal_v0.1.25", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/terminal_v0.1.24", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/terminal_v0.1.23", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/terminal_v0.1.22", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/terminal_v0.1.21", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/terminal_v0.1.20", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/terminal_v0.1.19", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/terminal_v0.1.18", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/terminal_v0.1.17", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/terminal_v0.1.16", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/terminal_v0.1.15", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/terminal_v0.1.14", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/terminal_v0.1.13", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/terminal_v0.1.12", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/terminal_v0.1.11", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/terminal_v0.1.10", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix @rushstack/node-core-library dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/terminal_v0.1.9", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/terminal_v0.1.8", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/terminal_v0.1.7", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/terminal_v0.1.6", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/terminal_v0.1.5", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/terminal_v0.1.4", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/terminal_v0.1.3", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/terminal_v0.1.2", + "date": "Mon, 14 Sep 2020 15:09:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/terminal_v0.1.1", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/terminal_v0.1.0", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + } + ] + } + } + ] +} diff --git a/libraries/terminal/CHANGELOG.md b/libraries/terminal/CHANGELOG.md new file mode 100644 index 00000000000..4d336b19f47 --- /dev/null +++ b/libraries/terminal/CHANGELOG.md @@ -0,0 +1,1725 @@ +# Change Log - @rushstack/terminal + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.19.5 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.19.4 +Fri, 21 Nov 2025 16:13:56 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:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.18.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Minor changes + +- Add ProblemCollector.onProblem notification callback +- Update API contract for `SplitterTransform` to support adding and removing destinations after creation. + +## 0.17.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Add `ProblemCollector extends TerminalWritable` API which matches and collects VS Code style problem matchers + +## 0.16.0 +Thu, 11 Sep 2025 00:22:31 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove support for legacy `IColorableSequence` parameters passed to `Terminal` insance `write*` functions. Note that types for `IColorableSequence` were removed with #3176 in 2022. + +## 0.15.4 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.15.3 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.15.2 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.15.1 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.15.0 +Wed, 12 Feb 2025 01:10:52 GMT + +### Minor changes + +- Introduce a NoOpTerminalProvider. + +## 0.14.6 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.14.5 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.14.4 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.14.3 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.14.2 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.14.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.14.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Create a new instance function called `getVerboseOutput` on `StringBufferTerminalProvider` and mark `getVerbose` as deprecated. + +## 0.13.4 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.13.3 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.13.2 +Wed, 17 Jul 2024 06:55:09 GMT + +### Patches + +- Improve the PrintUtilities API to handle an edge case when word-wrapping a final line + +## 0.13.1 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.13.0 +Thu, 30 May 2024 00:13:05 GMT + +### Minor changes + +- Eliminate a const enum from the public API. + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 0.12.3 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.12.2 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.12.1 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.12.0 +Sat, 25 May 2024 04:54:07 GMT + +### Minor changes + +- Change the `eolCharacter` property value of `StringBufferTerminalProvider` to `\n` from `[n]`. This does not change the default `getOutput()` result, but removes the `[n]` characters from the `getOutput({ normalizeSpecialCharacters: false })` result. + +## 0.11.1 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.11.0 +Wed, 15 May 2024 23:42:58 GMT + +### Minor changes + +- Allow use of 'preventAutoclose' flag in StdioSummarizer. + +## 0.10.4 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.10.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.10.2 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.10.1 +Wed, 10 Apr 2024 15:10:08 GMT + +_Version update only_ + +## 0.10.0 +Sat, 24 Feb 2024 23:02:51 GMT + +### Minor changes + +- Replace the `colors` dependency with `supports-color` for detecting if STDOUT and STDERR support color. +- Add a `Colorize.rainbow` API. + +## 0.9.0 +Wed, 21 Feb 2024 21:45:28 GMT + +### Minor changes + +- Expose a `supportsColor` property on `ConsoleTerminalProvider`. + +## 0.8.1 +Tue, 20 Feb 2024 21:45:10 GMT + +### Patches + +- Fix a recent regression causing `Error: Cannot find module 'colors/safe'` (GitHub #4525) + +## 0.8.0 +Mon, 19 Feb 2024 21:54:27 GMT + +### Minor changes + +- Introduce a Terminal, Colors, AsciEscape, and some related APIs. These APIs were previously in the @rushstack/node-core-library package. See https://github.com/microsoft/rushstack/pull/3176 for details. + +## 0.7.24 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.7.23 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.7.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.7.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.7.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.7.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.7.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.7.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.7.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.7.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.7.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.7.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.7.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.7.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.7.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.7.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.7.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.7.7 +Thu, 28 Sep 2023 20:53:17 GMT + +### Patches + +- Fix an issue where `PrintUtilities.printMessageInBox` would throw if the message contains a word that is longer than the box width. In this case, `printMessageInBox` will print bars above and below the message, and then print the message lines, allowing the console to wrap them. + +## 0.7.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.7.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.7.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.7.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.7.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.7.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.7.0 +Tue, 19 Sep 2023 00:36:30 GMT + +### Minor changes + +- Remove the dependency on `wordwrap`. +- Add support for a custom line prefix in `PrintUtilities.wrapWords`. +- Add a `PrintUtilities.wrapWordsToLines` function that is functionally identical to `PrintUtilities.wrapWords`, except that it returns an array of lines instead of a joined string with line breaks. + +## 0.6.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.5.38 +Thu, 24 Aug 2023 15:20:46 GMT + +### Patches + +- Fix a minor logic issue for TextRewriterTransform cleanup + +## 0.5.37 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.5.36 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.5.35 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.5.34 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.5.33 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.5.32 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.5.31 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.5.30 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.5.29 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.5.28 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.5.27 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.5.26 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.5.25 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.5.24 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.5.23 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.5.22 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.5.21 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.5.20 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.5.19 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.5.18 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.5.17 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.5.16 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.5.15 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.5.14 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.5.13 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.5.12 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.5.11 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.5.10 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.5.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.5.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.5.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.5.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.5.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.5.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.5.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.5.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.5.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.5.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.4.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.3.92 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.3.91 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.3.90 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.3.89 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.3.88 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.3.87 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.3.86 +Mon, 05 Dec 2022 16:16:09 GMT + +### Patches + +- The wrapWords method now respects existing spaces and newlines in a pre-formatted message. + +## 0.3.85 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 0.3.84 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.3.83 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.3.82 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.3.81 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.3.80 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.3.79 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.3.78 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.3.77 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.3.76 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.3.75 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.3.74 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.3.73 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.3.72 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.3.71 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.3.70 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.3.69 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.3.68 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.3.67 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.3.66 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.3.65 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.3.64 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.3.63 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.3.62 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.3.61 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.3.60 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 0.3.59 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.3.58 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.3.57 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.3.56 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.3.55 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.3.54 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.3.53 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.3.52 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.3.51 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.3.50 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.3.49 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.3.48 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.3.47 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.3.46 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.3.45 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.3.44 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 0.3.43 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 0.3.42 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.3.41 +Tue, 10 May 2022 01:20:44 GMT + +_Version update only_ + +## 0.3.40 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.3.39 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.3.38 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.3.37 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.3.36 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.3.35 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.3.34 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.3.33 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.3.32 +Sat, 09 Apr 2022 02:24:27 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.3.31 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.3.30 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.3.29 +Thu, 31 Mar 2022 02:06:06 GMT + +_Version update only_ + +## 0.3.28 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.3.27 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.3.26 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 0.3.25 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.3.24 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.3.23 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.3.22 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.3.21 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.3.20 +Tue, 14 Dec 2021 19:27:52 GMT + +_Version update only_ + +## 0.3.19 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.3.18 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.3.17 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.3.16 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.3.15 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.3.14 +Fri, 03 Dec 2021 03:05:23 GMT + +_Version update only_ + +## 0.3.13 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.3.12 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.3.11 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.3.10 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.3.9 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.3.8 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.3.7 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 0.3.6 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.3.5 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.3.4 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.3.3 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.3.2 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.3.1 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.3.0 +Tue, 05 Oct 2021 15:08:38 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 0.2.32 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.2.31 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.2.30 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.2.29 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.2.28 +Wed, 22 Sep 2021 00:09:33 GMT + +_Version update only_ + +## 0.2.27 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.2.26 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.2.25 +Mon, 13 Sep 2021 15:07:06 GMT + +_Version update only_ + +## 0.2.24 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.2.23 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.2.22 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.2.21 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.2.20 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.2.19 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.2.18 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.2.17 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 0.2.16 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.2.15 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.2.14 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.2.13 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.2.12 +Sat, 31 Jul 2021 00:52:12 GMT + +_Version update only_ + +## 0.2.11 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.2.10 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.2.9 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.2.8 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.2.7 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.2.6 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.2.5 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 0.2.4 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.2.3 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.2.2 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.2.1 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 0.2.0 +Fri, 18 Jun 2021 00:08:51 GMT + +### Minor changes + +- Export console printing utilities from the PrintUtility class. + +## 0.1.96 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 0.1.95 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 0.1.94 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 0.1.93 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 0.1.92 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 0.1.91 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 0.1.90 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.1.89 +Fri, 04 Jun 2021 15:08:21 GMT + +_Version update only_ + +## 0.1.88 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.1.87 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 0.1.86 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 0.1.85 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 0.1.84 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 0.1.83 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.1.82 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 0.1.81 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 0.1.80 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 0.1.79 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.1.78 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 0.1.77 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 0.1.76 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 0.1.75 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 0.1.74 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.1.73 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 0.1.72 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.1.71 +Thu, 08 Apr 2021 20:41:55 GMT + +_Version update only_ + +## 0.1.70 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 0.1.69 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 0.1.68 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.1.67 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 0.1.66 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 0.1.65 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 0.1.64 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 0.1.63 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 0.1.62 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 0.1.61 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 0.1.60 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.1.59 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.1.58 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.1.57 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.1.56 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 0.1.55 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.1.54 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 0.1.53 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.1.52 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.1.51 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.1.50 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.1.49 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.1.48 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.1.47 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.1.46 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.1.45 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.1.44 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.1.43 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.1.42 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.1.41 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.1.40 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 0.1.39 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.1.38 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.1.37 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.1.36 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 0.1.35 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.1.34 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.1.33 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.1.32 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 0.1.31 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 0.1.30 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.1.29 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 0.1.28 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 0.1.27 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.1.26 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 0.1.25 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 0.1.24 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.1.23 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 0.1.22 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 0.1.21 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 0.1.20 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 0.1.19 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.1.18 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.1.17 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 0.1.16 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 0.1.15 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.1.14 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 0.1.13 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.1.12 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 0.1.11 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.1.10 +Tue, 22 Sep 2020 01:45:31 GMT + +### Patches + +- Fix @rushstack/node-core-library dependency + +## 0.1.9 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.1.8 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.1.7 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.1.6 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.1.5 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 0.1.4 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 0.1.3 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 0.1.2 +Mon, 14 Sep 2020 15:09:49 GMT + +_Version update only_ + +## 0.1.1 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 0.1.0 +Fri, 11 Sep 2020 02:13:35 GMT + +### Minor changes + +- Initial release + diff --git a/libraries/terminal/LICENSE b/libraries/terminal/LICENSE new file mode 100644 index 00000000000..7af21a7e48b --- /dev/null +++ b/libraries/terminal/LICENSE @@ -0,0 +1,24 @@ +@rushstack/terminal + +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/terminal/README.md b/libraries/terminal/README.md new file mode 100644 index 00000000000..ee8ab33b119 --- /dev/null +++ b/libraries/terminal/README.md @@ -0,0 +1,53 @@ +# @rushstack/terminal + +This library implements a system for processing human readable text that +will be output by console applications. + +The design is based loosely on the `WritableStream` and `TransformStream` classes from +the system [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts), +except that instead of asynchronous byte streams, the `TerminalWritable` system synchronously transmits +human readable messages intended to be rendered on a text console or log file. + +Consider a console application whose output may need to be processed in different ways +before finally being output. The conceptual block diagram might look like this: + +``` + [Terminal API] + | + V + [normalize newlines] + | + V + +----[splitter]-------+ + | | + V V + [shell console] [remove ANSI colors] + | + V + [write to build.log] +``` + +The application uses the `Terminal` API to print `stdout` and `stderr` messages, for example with standardized +formatting for errors and warnings, and ANSI escapes to make nice colors. Maybe it also includes text +received from external processes, whose newlines may be inconsistent. Ultimately we want to write the +output to the shell console and a `build.log` file, but we don't want to put ANSI colors in the build log. + +For the above example, `[shell console]` and `[write to build.log]` would be modeled as subclasses of +`TerminalWritable`. The `[normalize newlines]` and `[remove ANSI colors]` steps are modeled as subclasses +of `TerminalTransform`, because they output to a "destination" object. The `[splitter]` would be +implemented using `SplitterTransform`. + +The stream of messages are {@link ITerminalChunk} objects, which can represent both `stdout` and `stderr` +channels. The pipeline operates synchronously on each chunk, but by processing one chunk at a time, +it avoids storing the entire output in memory. This means that operations like `[remove ANSI colors]` +cannot be simple regular expressions -- they must be implemented as state machines (`TextRewriter` subclasses) +capable of matching substrings that span multiple chunks. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/terminal/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/terminal/) + +`@rushstack/terminal` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/terminal/config/api-extractor.json b/libraries/terminal/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/terminal/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/terminal/config/jest.config.json b/libraries/terminal/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/terminal/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/terminal/config/rig.json b/libraries/terminal/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/terminal/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/terminal/eslint.config.js b/libraries/terminal/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/terminal/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/terminal/package.json b/libraries/terminal/package.json new file mode 100644 index 00000000000..46d492fba37 --- /dev/null +++ b/libraries/terminal/package.json @@ -0,0 +1,37 @@ +{ + "name": "@rushstack/terminal", + "version": "0.19.5", + "description": "User interface primitives for console applications", + "main": "lib/index.js", + "typings": "dist/terminal.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/terminal" + }, + "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:*", + "@rushstack/problem-matcher": "workspace:*", + "supports-color": "~8.1.1" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "@types/supports-color": "8.1.3", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/libraries/terminal/src/AnsiEscape.ts b/libraries/terminal/src/AnsiEscape.ts new file mode 100644 index 00000000000..7c1df4e036d --- /dev/null +++ b/libraries/terminal/src/AnsiEscape.ts @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { SgrParameterAttribute } from './Colorize'; + +/** + * Options for {@link AnsiEscape.formatForTests}. + * @public + */ +export interface IAnsiEscapeConvertForTestsOptions { + /** + * If true then `\n` will be replaced by `[n]`, and `\r` will be replaced by `[r]`. + */ + encodeNewlines?: boolean; +} + +/** + * Operations for working with text strings that contain + * {@link https://en.wikipedia.org/wiki/ANSI_escape_code | ANSI escape codes}. + * The most commonly used escape codes set the foreground/background color for console output. + * @public + */ +export class AnsiEscape { + // For now, we only care about the Control Sequence Introducer (CSI) commands which always start with "[". + // eslint-disable-next-line no-control-regex + private static readonly _csiRegExp: RegExp = /\x1b\[([\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e])/gu; + + // Text coloring is performed using Select Graphic Rendition (SGR) codes, which come after the + // CSI introducer "ESC [". The SGR sequence is a number followed by "m". + private static readonly _sgrRegExp: RegExp = /([0-9]+)m/u; + + private static readonly _backslashNRegExp: RegExp = /\n/g; + private static readonly _backslashRRegExp: RegExp = /\r/g; + + public static getEscapeSequenceForAnsiCode(code: number): string { + return `\u001b[${code}m`; + } + + /** + * Returns the input text with all ANSI escape codes removed. For example, this is useful when saving + * colorized console output to a log file. + */ + public static removeCodes(text: string): string { + return text.replace(AnsiEscape._csiRegExp, ''); + } + + /** + * Replaces ANSI escape codes with human-readable tokens. This is useful for unit tests + * that compare text strings in test assertions or snapshot files. + */ + public static formatForTests(text: string, options?: IAnsiEscapeConvertForTestsOptions): string { + if (!options) { + options = {}; + } + + let result: string = text.replace(AnsiEscape._csiRegExp, (capture: string, csiCode: string) => { + // If it is an SGR code, then try to show a friendly token + const match: RegExpMatchArray | null = csiCode.match(AnsiEscape._sgrRegExp); + if (match) { + const sgrParameter: number = parseInt(match[1], 10); + const sgrParameterName: string | undefined = AnsiEscape._tryGetSgrFriendlyName(sgrParameter); + if (sgrParameterName) { + // Example: "[black-bg]" + return `[${sgrParameterName}]`; + } + } + + // Otherwise show the raw code, but without the "[" from the CSI prefix + // Example: "[31m]" + return `[${csiCode}]`; + }); + + if (options.encodeNewlines) { + result = result + .replace(AnsiEscape._backslashNRegExp, '[n]') + .replace(AnsiEscape._backslashRRegExp, `[r]`); + } + return result; + } + + // Returns a human-readable token representing an SGR parameter, or undefined for parameter that is not well-known. + // The SGR parameter numbers are documented in this table: + // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters + private static _tryGetSgrFriendlyName(sgiParameter: number): string | undefined { + switch (sgiParameter) { + case SgrParameterAttribute.BlackForeground: + return 'black'; + case SgrParameterAttribute.RedForeground: + return 'red'; + case SgrParameterAttribute.GreenForeground: + return 'green'; + case SgrParameterAttribute.YellowForeground: + return 'yellow'; + case SgrParameterAttribute.BlueForeground: + return 'blue'; + case SgrParameterAttribute.MagentaForeground: + return 'magenta'; + case SgrParameterAttribute.CyanForeground: + return 'cyan'; + case SgrParameterAttribute.WhiteForeground: + return 'white'; + case SgrParameterAttribute.GrayForeground: + return 'gray'; + case SgrParameterAttribute.DefaultForeground: + return 'default'; + + case SgrParameterAttribute.BlackBackground: + return 'black-bg'; + case SgrParameterAttribute.RedBackground: + return 'red-bg'; + case SgrParameterAttribute.GreenBackground: + return 'green-bg'; + case SgrParameterAttribute.YellowBackground: + return 'yellow-bg'; + case SgrParameterAttribute.BlueBackground: + return 'blue-bg'; + case SgrParameterAttribute.MagentaBackground: + return 'magenta-bg'; + case SgrParameterAttribute.CyanBackground: + return 'cyan-bg'; + case SgrParameterAttribute.WhiteBackground: + return 'white-bg'; + case SgrParameterAttribute.GrayBackground: + return 'gray-bg'; + case SgrParameterAttribute.DefaultBackground: + return 'default-bg'; + + case SgrParameterAttribute.Bold: + return 'bold'; + case SgrParameterAttribute.Dim: + return 'dim'; + case SgrParameterAttribute.NormalColorOrIntensity: + return 'normal'; + case SgrParameterAttribute.Underline: + return 'underline'; + case SgrParameterAttribute.UnderlineOff: + return 'underline-off'; + case SgrParameterAttribute.Blink: + return 'blink'; + case SgrParameterAttribute.BlinkOff: + return 'blink-off'; + case SgrParameterAttribute.InvertColor: + return 'invert'; + case SgrParameterAttribute.InvertColorOff: + return 'invert-off'; + case SgrParameterAttribute.Hidden: + return 'hidden'; + case SgrParameterAttribute.HiddenOff: + return 'hidden-off'; + default: + return undefined; + } + } +} diff --git a/libraries/terminal/src/CallbackWritable.ts b/libraries/terminal/src/CallbackWritable.ts new file mode 100644 index 00000000000..0b5bb7afc77 --- /dev/null +++ b/libraries/terminal/src/CallbackWritable.ts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TerminalWritable } from './TerminalWritable'; +import type { ITerminalChunk } from './ITerminalChunk'; + +/** + * Constructor options for {@link CallbackWritable}. + * @public + */ +export interface ICallbackWritableOptions { + onWriteChunk: (chunk: ITerminalChunk) => void; +} + +/** + * This class enables very basic {@link TerminalWritable.onWriteChunk} operations to be implemented + * as a callback function, avoiding the need to define a subclass of `TerminalWritable`. + * + * @remarks + * `CallbackWritable` is provided as a convenience for very simple situations. For most cases, + * it is generally preferable to create a proper subclass. + * + * @privateRemarks + * We intentionally do not expose a callback for {@link TerminalWritable.onClose}; if special + * close behavior is required, it is better to create a subclass. + * + * @public + */ +export class CallbackWritable extends TerminalWritable { + private readonly _callback: (chunk: ITerminalChunk) => void; + + public constructor(options: ICallbackWritableOptions) { + super(); + this._callback = options.onWriteChunk; + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + this._callback(chunk); + } +} diff --git a/libraries/terminal/src/Colorize.ts b/libraries/terminal/src/Colorize.ts new file mode 100644 index 00000000000..94e1f42e3be --- /dev/null +++ b/libraries/terminal/src/Colorize.ts @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AnsiEscape } from './AnsiEscape'; + +export enum SgrParameterAttribute { + BlackForeground = 30, + RedForeground = 31, + GreenForeground = 32, + YellowForeground = 33, + BlueForeground = 34, + MagentaForeground = 35, + CyanForeground = 36, + WhiteForeground = 37, + GrayForeground = 90, + DefaultForeground = 39, + + BlackBackground = 40, + RedBackground = 41, + GreenBackground = 42, + YellowBackground = 43, + BlueBackground = 44, + MagentaBackground = 45, + CyanBackground = 46, + WhiteBackground = 47, + GrayBackground = 100, + DefaultBackground = 49, + + Bold = 1, + + // On Linux, the "BoldOff" code instead causes the text to be double-underlined: + // https://en.wikipedia.org/wiki/Talk:ANSI_escape_code#SGR_21%E2%80%94%60Bold_off%60_not_widely_supported + // Use "NormalColorOrIntensity" instead + // BoldOff = 21, + + Dim = 2, + NormalColorOrIntensity = 22, + Underline = 4, + UnderlineOff = 24, + Blink = 5, + BlinkOff = 25, + InvertColor = 7, + InvertColorOff = 27, + Hidden = 8, + HiddenOff = 28 +} + +const RAINBOW_SEQUENCE: SgrParameterAttribute[] = [ + SgrParameterAttribute.RedForeground, + SgrParameterAttribute.YellowForeground, + SgrParameterAttribute.GreenForeground, + SgrParameterAttribute.CyanForeground, + SgrParameterAttribute.BlueForeground, + SgrParameterAttribute.MagentaForeground +]; + +/** + * The static functions on this class are used to produce colored text + * for use with a terminal that supports ANSI escape codes. + * + * Note that this API always generates color codes, regardless of whether + * the process's stdout is a TTY. The reason is that, in a complex program, the + * code that is generating strings often does not know were those strings will end + * up. In some cases, the same log message may get printed both to a shell + * that supports color AND to a log file that does not. + * + * @example + * ```ts + * console.log(Colorize.red('Red Text!')) + * terminal.writeLine(Colorize.green('Green Text!'), ' ', Colorize.blue('Blue Text!')); + *``` + * + * @public + */ +export class Colorize { + public static black(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.BlackForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static red(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.RedForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static green(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.GreenForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static yellow(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.YellowForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static blue(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.BlueForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static magenta(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.MagentaForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static cyan(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.CyanForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static white(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.WhiteForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static gray(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.GrayForeground, + SgrParameterAttribute.DefaultForeground, + text + ); + } + + public static blackBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.BlackBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static redBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.RedBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static greenBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.GreenBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static yellowBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.YellowBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static blueBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.BlueBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static magentaBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.MagentaBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static cyanBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.CyanBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static whiteBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.WhiteBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static grayBackground(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.GrayBackground, + SgrParameterAttribute.DefaultBackground, + text + ); + } + + public static bold(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.Bold, + SgrParameterAttribute.NormalColorOrIntensity, + text + ); + } + + public static dim(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.Dim, + SgrParameterAttribute.NormalColorOrIntensity, + text + ); + } + + public static underline(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.Underline, + SgrParameterAttribute.UnderlineOff, + text + ); + } + + public static blink(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.Blink, + SgrParameterAttribute.BlinkOff, + text + ); + } + + public static invertColor(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.InvertColor, + SgrParameterAttribute.InvertColorOff, + text + ); + } + + public static hidden(text: string): string { + return Colorize._wrapTextInAnsiEscapeCodes( + SgrParameterAttribute.Hidden, + SgrParameterAttribute.HiddenOff, + text + ); + } + + public static rainbow(text: string): string { + return Colorize._applyColorSequence(text, RAINBOW_SEQUENCE); + } + + private static _applyColorSequence(text: string, sequence: SgrParameterAttribute[]): string { + let result: string = ''; + const sequenceLength: number = sequence.length; + for (let i: number = 0; i < text.length; i++) { + result += AnsiEscape.getEscapeSequenceForAnsiCode(sequence[i % sequenceLength]) + text[i]; + } + + return result + AnsiEscape.getEscapeSequenceForAnsiCode(SgrParameterAttribute.DefaultForeground); + } + + private static _wrapTextInAnsiEscapeCodes(startCode: number, endCode: number, text: string): string { + return ( + AnsiEscape.getEscapeSequenceForAnsiCode(startCode) + + text + + AnsiEscape.getEscapeSequenceForAnsiCode(endCode) + ); + } +} diff --git a/libraries/terminal/src/ConsoleTerminalProvider.ts b/libraries/terminal/src/ConsoleTerminalProvider.ts new file mode 100644 index 00000000000..ff7a4dfabf2 --- /dev/null +++ b/libraries/terminal/src/ConsoleTerminalProvider.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 { EOL } from 'node:os'; + +import supportsColor from 'supports-color'; + +import { type ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; + +/** + * Options to be provided to a {@link ConsoleTerminalProvider} + * + * @beta + */ +export interface IConsoleTerminalProviderOptions { + /** + * If true, print verbose logging messages. + */ + verboseEnabled: boolean; + + /** + * If true, print debug logging messages. Note that "verbose" and "debug" are considered + * separate message filters; if you want debug to imply verbose, it is up to your + * application code to enforce that. + */ + debugEnabled: boolean; +} + +/** + * Terminal provider that prints to STDOUT (for log- and verbose-level messages) and + * STDERR (for warning- and error-level messages). + * + * @beta + */ +export class ConsoleTerminalProvider implements ITerminalProvider { + public static readonly supportsColor: boolean = !!supportsColor.stdout && !!supportsColor.stderr; + + /** + * If true, verbose-level messages should be written to the console. + */ + public verboseEnabled: boolean; + + /** + * If true, debug-level messages should be written to the console. + */ + public debugEnabled: boolean; + + /** + * {@inheritDoc ITerminalProvider.supportsColor} + */ + public readonly supportsColor: boolean = ConsoleTerminalProvider.supportsColor; + + public constructor(options: Partial = {}) { + this.verboseEnabled = !!options.verboseEnabled; + this.debugEnabled = !!options.debugEnabled; + } + + /** + * {@inheritDoc ITerminalProvider.write} + */ + public write(data: string, severity: TerminalProviderSeverity): void { + switch (severity) { + case TerminalProviderSeverity.warning: + case TerminalProviderSeverity.error: { + process.stderr.write(data); + break; + } + + case TerminalProviderSeverity.verbose: { + if (this.verboseEnabled) { + process.stdout.write(data); + } + break; + } + + case TerminalProviderSeverity.debug: { + if (this.debugEnabled) { + process.stdout.write(data); + } + break; + } + + case TerminalProviderSeverity.log: + default: { + process.stdout.write(data); + break; + } + } + } + + /** + * {@inheritDoc ITerminalProvider.eolCharacter} + */ + public get eolCharacter(): string { + return EOL; + } +} diff --git a/libraries/terminal/src/DiscardStdoutTransform.ts b/libraries/terminal/src/DiscardStdoutTransform.ts new file mode 100644 index 00000000000..7dda773674e --- /dev/null +++ b/libraries/terminal/src/DiscardStdoutTransform.ts @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk'; +import { TerminalTransform, type ITerminalTransformOptions } from './TerminalTransform'; + +/** + * Constructor options for {@link DiscardStdoutTransform} + * + * @beta + */ +export interface IDiscardStdoutTransformOptions extends ITerminalTransformOptions {} + +enum State { + Okay, + StderrFragment, + InsertLinefeed +} + +/** + * `DiscardStdoutTransform` discards `stdout` chunks while fixing up malformed `stderr` lines. + * + * @remarks + * Suppose that a poorly behaved process produces output like this: + * + * ```ts + * process.stdout.write('Starting operation...\n'); + * process.stderr.write('An error occurred'); + * process.stdout.write('\nFinishing up\n'); + * process.stderr.write('The process completed with errors\n'); + * ``` + * + * When `stdout` and `stderr` are combined on the console, the mistake in the output would not be noticeable: + * ``` + * Starting operation... + * An error occurred + * Finishing up + * The process completed with errors + * ``` + * + * However, if we discard `stdout`, then `stderr` is missing a newline: + * ``` + * An error occurredThe process completed with errors + * ``` + * + * Tooling scripts can introduce these sorts of problems via edge cases that are difficult to find and fix. + * `DiscardStdoutTransform` can discard the `stdout` stream and fix up `stderr`: + * + * ``` + * An error occurred + * The process completed with errors + * ``` + * + * @privateRemarks + * This class is experimental and marked as `@beta`. The algorithm may need some fine-tuning, or there may + * be better solutions to this problem. + * + * @beta + */ +export class DiscardStdoutTransform extends TerminalTransform { + private _state: State; + + public constructor(options: IDiscardStdoutTransformOptions) { + super(options); + + this._state = State.Okay; + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (chunk.text.indexOf('\r') >= 0) { + throw new Error('DiscardStdoutTransform expects chunks with normalized newlines'); + } + + if (chunk.kind === TerminalChunkKind.Stdout) { + if (this._state === State.StderrFragment) { + if (chunk.text.indexOf('\n') >= 0) { + this._state = State.InsertLinefeed; + } + } + } else if (chunk.kind === TerminalChunkKind.Stderr) { + let correctedText: string; + if (this._state === State.InsertLinefeed) { + correctedText = '\n' + chunk.text; + } else { + correctedText = chunk.text; + } + + this.destination.writeChunk({ kind: TerminalChunkKind.Stderr, text: correctedText }); + + if (correctedText.length > 0) { + if (correctedText[correctedText.length - 1] === '\n') { + this._state = State.Okay; + } else { + this._state = State.StderrFragment; + } + } + } else { + this.destination.writeChunk(chunk); + } + } +} diff --git a/libraries/terminal/src/IProblemCollector.ts b/libraries/terminal/src/IProblemCollector.ts new file mode 100644 index 00000000000..5f0c0813aad --- /dev/null +++ b/libraries/terminal/src/IProblemCollector.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 type { IProblem } from '@rushstack/problem-matcher'; + +/** + * Collects problems (errors/warnings/info) encountered during an operation. + * + * @beta + */ +export interface IProblemCollector { + /** + * Returns the collected problems so far. + */ + get problems(): ReadonlySet; +} diff --git a/libraries/terminal/src/ITerminal.ts b/libraries/terminal/src/ITerminal.ts new file mode 100644 index 00000000000..2d3e3b94dab --- /dev/null +++ b/libraries/terminal/src/ITerminal.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 type { ITerminalProvider } from './ITerminalProvider'; + +/** + * @beta + */ +export interface ITerminalWriteOptions { + /** + * If set to true, SGR parameters will not be replaced by the terminal + * standard (i.e. - red for errors, yellow for warnings). + */ + doNotOverrideSgrCodes?: boolean; +} + +/** + * @beta + */ +export type TerminalWriteParameters = string[] | [...string[], ITerminalWriteOptions]; + +/** + * @beta + */ +export interface ITerminal { + /** + * Subscribe a new terminal provider. + */ + registerProvider(provider: ITerminalProvider): void; + + /** + * Unsubscribe a terminal provider. If the provider isn't subscribed, this function does nothing. + */ + unregisterProvider(provider: ITerminalProvider): void; + + /** + * Write a generic message to the terminal + */ + write(...messageParts: TerminalWriteParameters): void; + + /** + * Write a generic message to the terminal, followed by a newline + */ + writeLine(...messageParts: TerminalWriteParameters): void; + + /** + * Write a warning message to the console with yellow text. + * + * @remarks + * The yellow color takes precedence over any other foreground colors set. + */ + writeWarning(...messageParts: TerminalWriteParameters): void; + + /** + * Write a warning message to the console with yellow text, followed by a newline. + * + * @remarks + * The yellow color takes precedence over any other foreground colors set. + */ + writeWarningLine(...messageParts: TerminalWriteParameters): void; + + /** + * Write an error message to the console with red text. + * + * @remarks + * The red color takes precedence over any other foreground colors set. + */ + writeError(...messageParts: TerminalWriteParameters): void; + + /** + * Write an error message to the console with red text, followed by a newline. + * + * @remarks + * The red color takes precedence over any other foreground colors set. + */ + writeErrorLine(...messageParts: TerminalWriteParameters): void; + + /** + * Write a verbose-level message. + */ + writeVerbose(...messageParts: TerminalWriteParameters): void; + + /** + * Write a verbose-level message followed by a newline. + */ + writeVerboseLine(...messageParts: TerminalWriteParameters): void; + + /** + * Write a debug-level message. + */ + writeDebug(...messageParts: TerminalWriteParameters): void; + + /** + * Write a debug-level message followed by a newline. + */ + writeDebugLine(...messageParts: TerminalWriteParameters): void; +} diff --git a/libraries/terminal/src/ITerminalChunk.ts b/libraries/terminal/src/ITerminalChunk.ts new file mode 100644 index 00000000000..0745c06a2d8 --- /dev/null +++ b/libraries/terminal/src/ITerminalChunk.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Specifies the kind of data represented by a {@link ITerminalChunk} object. + * @public + */ +export enum TerminalChunkKind { + /** + * Indicates a `ITerminalChunk` object representing `stdout` console output. + */ + Stdout = 'O', + + /** + * Indicates a `ITerminalChunk` object representing `stderr` console output. + */ + Stderr = 'E' +} + +/** + * Represents a chunk of output that will ultimately be written to a {@link TerminalWritable}. + * + * @remarks + * Today `ITerminalChunk` represents the `stdout` and `stderr` text streams. In the future, + * we plan to expand it to include other console UI elements such as instructions for displaying + * an interactive progress bar. We may also add other metadata, for example tracking whether + * the `text` string is known to contain color codes or not. + * + * The `ITerminalChunk` object should be considered to be immutable once it is created. + * For example, {@link SplitterTransform} may pass the same chunk to multiple destinations. + * + * @public + */ +export interface ITerminalChunk { + /** + * Indicates the kind of information stored in this chunk. + * + * @remarks + * More kinds will be introduced in the future. Implementors of + * {@link TerminalWritable.onWriteChunk} should ignore unrecognized `TerminalChunkKind` + * values. `TerminalTransform` implementors should pass along unrecognized chunks + * rather than discarding them. + */ + kind: TerminalChunkKind; + + /** + * The next chunk of text from the `stderr` or `stdout` stream. + */ + text: string; +} diff --git a/libraries/terminal/src/ITerminalProvider.ts b/libraries/terminal/src/ITerminalProvider.ts new file mode 100644 index 00000000000..35fe51e13f9 --- /dev/null +++ b/libraries/terminal/src/ITerminalProvider.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Similar to many popular logging packages, terminal providers support a range of message + * severities. These severities have built-in formatting defaults in the Terminal object + * (warnings are yellow, errors are red, etc.). + * + * Terminal providers may choose to suppress certain messages based on their severity, + * or to route some messages to other providers or not based on severity. + * + * Severity | Purpose + * --------- | ------- + * error | Build errors and fatal issues + * warning | Not necessarily fatal, but indicate a problem the user should fix + * log | Informational messages + * verbose | Additional information that may not always be necessary + * debug | Highest detail level, best used for troubleshooting information + * + * @beta + */ +export enum TerminalProviderSeverity { + log, + warning, + error, + verbose, + debug +} + +/** + * Implement the interface to create a terminal provider. Terminal providers + * can be registered to a {@link Terminal} instance to receive messages. + * + * @beta + */ +export interface ITerminalProvider { + /** + * This property should return true only if the terminal provider supports + * rendering console colors. + */ + supportsColor: boolean; + + /** + * This property should return the newline character the terminal provider + * expects. + */ + eolCharacter: string; + + /** + * This function gets called on every terminal provider upon every + * message function call on the terminal instance. + * + * @param data - The terminal message. + * @param severity - The message severity. Terminal providers can + * route different kinds of messages to different streams and may choose + * to ignore verbose or debug messages. + */ + write(data: string, severity: TerminalProviderSeverity): void; +} diff --git a/libraries/terminal/src/MockWritable.ts b/libraries/terminal/src/MockWritable.ts new file mode 100644 index 00000000000..089a89a7407 --- /dev/null +++ b/libraries/terminal/src/MockWritable.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 { AnsiEscape } from './AnsiEscape'; +import type { ITerminalChunk } from './ITerminalChunk'; +import { TerminalWritable } from './TerminalWritable'; + +/** + * A {@link TerminalWritable} subclass for use by unit tests. + * + * @beta + */ +export class MockWritable extends TerminalWritable { + public readonly chunks: ITerminalChunk[] = []; + + protected onWriteChunk(chunk: ITerminalChunk): void { + this.chunks.push(chunk); + } + + public reset(): void { + this.chunks.length = 0; + } + + public getAllOutput(): string { + return AnsiEscape.formatForTests(this.chunks.map((x) => x.text).join('')); + } + + public getFormattedChunks(): ITerminalChunk[] { + return this.chunks.map((x) => ({ ...x, text: AnsiEscape.formatForTests(x.text) }) as ITerminalChunk); + } +} diff --git a/libraries/terminal/src/NoOpTerminalProvider.ts b/libraries/terminal/src/NoOpTerminalProvider.ts new file mode 100644 index 00000000000..032e04909f3 --- /dev/null +++ b/libraries/terminal/src/NoOpTerminalProvider.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. + +import type { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; + +/** + * Terminal provider that stores written data in buffers separated by severity. + * This terminal provider is designed to be used when code that prints to a terminal + * is being unit tested. + * + * @beta + */ +export class NoOpTerminalProvider implements ITerminalProvider { + /** + * {@inheritDoc ITerminalProvider.write} + */ + public write(data: string, severity: TerminalProviderSeverity): void { + // no-op + } + + /** + * {@inheritDoc ITerminalProvider.eolCharacter} + */ + public get eolCharacter(): string { + return '\n'; + } + + /** + * {@inheritDoc ITerminalProvider.supportsColor} + */ + public get supportsColor(): boolean { + return false; + } +} diff --git a/libraries/terminal/src/NormalizeNewlinesTextRewriter.ts b/libraries/terminal/src/NormalizeNewlinesTextRewriter.ts new file mode 100644 index 00000000000..a88ac3d2403 --- /dev/null +++ b/libraries/terminal/src/NormalizeNewlinesTextRewriter.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 { Text, type NewlineKind } from '@rushstack/node-core-library'; + +import { TextRewriter, type TextRewriterState } from './TextRewriter'; + +interface INormalizeNewlinesTextRewriterState extends TextRewriterState { + characterToIgnore: string; + incompleteLine: boolean; +} + +/** + * Constructor options for {@link NormalizeNewlinesTextRewriter} + * + * @public + */ +export interface INormalizeNewlinesTextRewriterOptions { + /** + * Specifies how newlines should be represented in the output stream. + */ + newlineKind: NewlineKind; + + /** + * If `true`, then `NormalizeNewlinesTextRewriter.close()` will append a newline to + * the output if it ends with an incomplete line. + * + * @remarks + * If the output is an empty string, then a newline will NOT be appended, + * because writing an empty string does not produce an incomplete line. + */ + ensureNewlineAtEnd?: boolean; +} + +/** + * For use with {@link TextRewriterTransform}, this rewriter converts all newlines to + * a standard format. + * + * @public + */ +export class NormalizeNewlinesTextRewriter extends TextRewriter { + /** {@inheritDoc INormalizeNewlinesTextRewriterOptions.newlineKind} */ + public readonly newlineKind: NewlineKind; + + /** + * The specific character sequence that will be used when appending newlines. + */ + public readonly newline: string; + + /** {@inheritDoc INormalizeNewlinesTextRewriterOptions.ensureNewlineAtEnd} */ + public readonly ensureNewlineAtEnd: boolean; + + public constructor(options: INormalizeNewlinesTextRewriterOptions) { + super(); + this.newlineKind = options.newlineKind; + this.newline = Text.getNewline(options.newlineKind); + this.ensureNewlineAtEnd = !!options.ensureNewlineAtEnd; + } + + public initialize(): TextRewriterState { + return { + characterToIgnore: '', + incompleteLine: false + } as INormalizeNewlinesTextRewriterState; + } + + public process(unknownState: TextRewriterState, text: string): string { + const state: INormalizeNewlinesTextRewriterState = unknownState as INormalizeNewlinesTextRewriterState; + + let result: string = ''; + + if (text.length > 0) { + let i: number = 0; + + do { + const c: string = text[i]; + ++i; + + if (c === state.characterToIgnore) { + state.characterToIgnore = ''; + } else if (c === '\r') { + result += this.newline; + state.characterToIgnore = '\n'; + state.incompleteLine = false; + } else if (c === '\n') { + result += this.newline; + state.characterToIgnore = '\r'; + state.incompleteLine = false; + } else { + result += c; + state.characterToIgnore = ''; + state.incompleteLine = true; + } + } while (i < text.length); + } + + return result; + } + + public close(unknownState: TextRewriterState): string { + const state: INormalizeNewlinesTextRewriterState = unknownState as INormalizeNewlinesTextRewriterState; + state.characterToIgnore = ''; + + if (state.incompleteLine) { + state.incompleteLine = false; + return this.newline; + } else { + return ''; + } + } +} diff --git a/libraries/terminal/src/PrefixProxyTerminalProvider.ts b/libraries/terminal/src/PrefixProxyTerminalProvider.ts new file mode 100644 index 00000000000..94d4194b5e5 --- /dev/null +++ b/libraries/terminal/src/PrefixProxyTerminalProvider.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 { Text } from '@rushstack/node-core-library'; + +import type { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; + +/** + * @beta + */ +export interface IPrefixProxyTerminalProviderOptionsBase { + /** + * The {@link ITerminalProvider} that will be wrapped. + */ + terminalProvider: ITerminalProvider; +} + +/** + * Options for {@link PrefixProxyTerminalProvider}, with a static prefix. + * + * @beta + */ +export interface IStaticPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase { + /** + * The prefix that should be added to each line of output. + */ + prefix: string; +} + +/** + * Options for {@link PrefixProxyTerminalProvider}. + * + * @beta + */ +export interface IDynamicPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase { + /** + * A function that returns the prefix that should be added to each line of output. This is useful + * for prefixing each line with a timestamp. + */ + getPrefix: () => string; +} + +/** + * @beta + */ +export type IPrefixProxyTerminalProviderOptions = + | IStaticPrefixProxyTerminalProviderOptions + | IDynamicPrefixProxyTerminalProviderOptions; + +/** + * Wraps an existing {@link ITerminalProvider} that prefixes each line of output with a specified + * prefix string. + * + * @beta + */ +export class PrefixProxyTerminalProvider implements ITerminalProvider { + private readonly _parentTerminalProvider: ITerminalProvider; + private readonly _getPrefix: () => string; + private readonly _newlineRegex: RegExp; + private _isOnNewline: boolean; + + public constructor(options: IPrefixProxyTerminalProviderOptions) { + const { terminalProvider } = options; + + this._parentTerminalProvider = terminalProvider; + + if ((options as IStaticPrefixProxyTerminalProviderOptions).prefix !== undefined) { + const { prefix } = options as IStaticPrefixProxyTerminalProviderOptions; + this._getPrefix = () => prefix; + } else { + const { getPrefix } = options as IDynamicPrefixProxyTerminalProviderOptions; + this._getPrefix = getPrefix; + } + + this._isOnNewline = true; + + this._newlineRegex = new RegExp(`${Text.escapeRegExp(terminalProvider.eolCharacter)}|\\n`, 'g'); + } + + /** @override */ + public get supportsColor(): boolean { + return this._parentTerminalProvider.supportsColor; + } + + /** @override */ + public get eolCharacter(): string { + return this._parentTerminalProvider.eolCharacter; + } + + /** @override */ + public write(data: string, severity: TerminalProviderSeverity): void { + // We need to track newlines to ensure that the prefix is added to each line + let currentIndex: number = 0; + let newlineMatch: RegExpExecArray | null; + + while ((newlineMatch = this._newlineRegex.exec(data))) { + // Extract the line, add the prefix, and write it out with the newline + const newlineIndex: number = newlineMatch.index; + const newIndex: number = newlineIndex + newlineMatch[0].length; + const prefix: string = this._isOnNewline ? this._getPrefix() : ''; + const dataToWrite: string = `${prefix}${data.substring(currentIndex, newIndex)}`; + this._parentTerminalProvider.write(dataToWrite, severity); + // Update the currentIndex to start the search from the char after the newline + currentIndex = newIndex; + this._isOnNewline = true; + } + + // The remaining data is not postfixed by a newline, so write out the data and set _isNewline to false + const remainingData: string = data.substring(currentIndex); + if (remainingData.length) { + const prefix: string = this._isOnNewline ? this._getPrefix() : ''; + this._parentTerminalProvider.write(`${prefix}${remainingData}`, severity); + this._isOnNewline = false; + } + } +} diff --git a/libraries/terminal/src/PrintUtilities.ts b/libraries/terminal/src/PrintUtilities.ts new file mode 100644 index 00000000000..6fe00c13651 --- /dev/null +++ b/libraries/terminal/src/PrintUtilities.ts @@ -0,0 +1,233 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Text } from '@rushstack/node-core-library'; + +import type { ITerminal } from './ITerminal'; + +/** + * A sensible fallback column width for consoles. + * + * @public + */ +export const DEFAULT_CONSOLE_WIDTH: number = 80; + +/** + * A collection of utilities for printing messages to the console. + * + * @public + */ +export class PrintUtilities { + /** + * Returns the width of the console, measured in columns + */ + public static getConsoleWidth(): number | undefined { + return process.stdout?.columns; + } + + /** + * Applies word wrapping. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indent - The number of spaces to indent the wrapped lines, defaults to 0 + */ + public static wrapWords(text: string, maxLineLength?: number, indent?: number): string; + /** + * Applies word wrapping. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param linePrefix - The string to prefix each line with, defaults to '' + */ + public static wrapWords(text: string, maxLineLength?: number, linePrefix?: string): string; + /** + * Applies word wrapping. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indentOrLinePrefix - The number of spaces to indent the wrapped lines or the string to prefix + * each line with, defaults to no prefix + */ + public static wrapWords(text: string, maxLineLength?: number, indentOrLinePrefix?: number | string): string; + public static wrapWords( + text: string, + maxLineLength?: number, + indentOrLinePrefix?: number | string + ): string { + const wrappedLines: string[] = PrintUtilities.wrapWordsToLines( + text, + maxLineLength, + indentOrLinePrefix as string | undefined // TS is confused by the overloads + ); + return wrappedLines.join('\n'); + } + + /** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indent - The number of spaces to indent the wrapped lines, defaults to 0 + */ + public static wrapWordsToLines(text: string, maxLineLength?: number, indent?: number): string[]; + /** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param linePrefix - The string to prefix each line with, defaults to '' + */ + public static wrapWordsToLines(text: string, maxLineLength?: number, linePrefix?: string): string[]; + /** + * Applies word wrapping and returns an array of lines. + * + * @param text - The text to wrap + * @param maxLineLength - The maximum length of a line, defaults to the console width + * @param indentOrLinePrefix - The number of spaces to indent the wrapped lines or the string to prefix + * each line with, defaults to no prefix + */ + public static wrapWordsToLines( + text: string, + maxLineLength?: number, + indentOrLinePrefix?: number | string + ): string[]; + public static wrapWordsToLines( + text: string, + maxLineLength?: number, + indentOrLinePrefix?: number | string + ): string[] { + let linePrefix: string; + switch (typeof indentOrLinePrefix) { + case 'number': + linePrefix = ' '.repeat(indentOrLinePrefix); + break; + case 'string': + linePrefix = indentOrLinePrefix; + break; + default: + linePrefix = ''; + break; + } + + const linePrefixLength: number = linePrefix.length; + + if (!maxLineLength) { + maxLineLength = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH; + } + + // Apply word wrapping and the provided line prefix, while also respecting existing newlines + // and prefix spaces that may exist in the text string already. + const lines: string[] = Text.splitByNewLines(text); + + const wrappedLines: string[] = []; + for (const line of lines) { + if (line.length + linePrefixLength <= maxLineLength) { + wrappedLines.push(linePrefix + line); + } else { + const lineAdditionalPrefix: string = line.match(/^\s*/)?.[0] || ''; + const whitespaceRegexp: RegExp = /\s+/g; + let currentWhitespaceMatch: RegExpExecArray | null = null; + let previousWhitespaceMatch: RegExpExecArray | undefined; + let currentLineStartIndex: number = lineAdditionalPrefix.length; + let previousBreakRanOver: boolean = false; + while ((currentWhitespaceMatch = whitespaceRegexp.exec(line)) !== null) { + if (currentWhitespaceMatch.index + linePrefixLength - currentLineStartIndex > maxLineLength) { + let whitespaceToSplitAt: RegExpExecArray | undefined; + if ( + !previousWhitespaceMatch || + // Handle the case where there are two words longer than the maxLineLength in a row + previousBreakRanOver + ) { + whitespaceToSplitAt = currentWhitespaceMatch; + } else { + whitespaceToSplitAt = previousWhitespaceMatch; + } + + wrappedLines.push( + linePrefix + + lineAdditionalPrefix + + line.substring(currentLineStartIndex, whitespaceToSplitAt.index) + ); + previousBreakRanOver = whitespaceToSplitAt.index - currentLineStartIndex > maxLineLength; + currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length; + } else { + previousBreakRanOver = false; + } + + previousWhitespaceMatch = currentWhitespaceMatch; + } + + if ( + previousWhitespaceMatch && + line.length + linePrefixLength - currentLineStartIndex > maxLineLength + ) { + const whitespaceToSplitAt: RegExpExecArray = previousWhitespaceMatch; + + wrappedLines.push( + linePrefix + + lineAdditionalPrefix + + line.substring(currentLineStartIndex, whitespaceToSplitAt.index) + ); + currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length; + } + + if (currentLineStartIndex < line.length) { + wrappedLines.push(linePrefix + lineAdditionalPrefix + line.substring(currentLineStartIndex)); + } + } + } + + return wrappedLines; + } + + /** + * Displays a message in the console wrapped in a box UI. + * + * @param message - The message to display. + * @param terminal - The terminal to write the message to. + * @param boxWidth - The width of the box, defaults to half of the console width. + */ + public static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void { + if (!boxWidth) { + const consoleWidth: number = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH; + boxWidth = Math.floor(consoleWidth / 2); + } + + const maxLineLength: number = boxWidth - 10; + const wrappedMessageLines: string[] = PrintUtilities.wrapWordsToLines(message, maxLineLength); + let longestLineLength: number = 0; + const trimmedLines: string[] = []; + for (const line of wrappedMessageLines) { + const trimmedLine: string = line.trim(); + trimmedLines.push(trimmedLine); + longestLineLength = Math.max(longestLineLength, trimmedLine.length); + } + + if (longestLineLength > boxWidth - 2) { + // If the longest line is longer than the box, print bars above and below the message + // ═════════════ + // Message + // ═════════════ + const headerAndFooter: string = ` ${'═'.repeat(boxWidth)}`; + terminal.writeLine(headerAndFooter); + for (const line of wrappedMessageLines) { + terminal.writeLine(` ${line}`); + } + + terminal.writeLine(headerAndFooter); + } else { + // ╔═══════════╗ + // ║ Message ║ + // ╚═══════════╝ + terminal.writeLine(` ╔${'═'.repeat(boxWidth - 2)}╗`); + for (const trimmedLine of trimmedLines) { + const padding: number = boxWidth - trimmedLine.length - 2; + const leftPadding: number = Math.floor(padding / 2); + const rightPadding: number = padding - leftPadding; + terminal.writeLine(` ║${' '.repeat(leftPadding)}${trimmedLine}${' '.repeat(rightPadding)}║`); + } + terminal.writeLine(` ╚${'═'.repeat(boxWidth - 2)}╝`); + } + } +} diff --git a/libraries/terminal/src/ProblemCollector.ts b/libraries/terminal/src/ProblemCollector.ts new file mode 100644 index 00000000000..64ad6d6e9d2 --- /dev/null +++ b/libraries/terminal/src/ProblemCollector.ts @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { parseProblemMatchersJson } from '@rushstack/problem-matcher'; +import type { IProblemMatcher, IProblemMatcherJson, IProblem } from '@rushstack/problem-matcher'; + +import type { ITerminalChunk } from './ITerminalChunk'; +import { type ITerminalWritableOptions, TerminalWritable } from './TerminalWritable'; +import type { IProblemCollector } from './IProblemCollector'; + +/** + * Constructor options for {@link ProblemCollector}. + * @beta + */ +export interface IProblemCollectorOptions extends ITerminalWritableOptions { + /** + * The set of matchers that will be applied to each incoming line. Must contain at least one item. + */ + matchers?: IProblemMatcher[]; + /** + * VS Code style problem matcher definitions. These will be converted to + * {@link @rushstack/problem-matcher#IProblemMatcher | IProblemMatcher} definitions. + */ + matcherJson?: IProblemMatcherJson[]; + /** + * Optional callback invoked immediately whenever a problem is produced. + */ + onProblem?: (problem: IProblem) => void; +} + +/** + * A {@link TerminalWritable} that consumes line-oriented terminal output and extracts structured + * problems using one or more {@link @rushstack/problem-matcher#IProblemMatcher | IProblemMatcher} instances. + * + * @remarks + * This collector expects that each incoming {@link ITerminalChunk} represents a single line terminated + * by a `"\n"` character (for example when preceded by {@link StderrLineTransform} / `StdioLineTransform`). + * If a chunk does not end with a newline an error is thrown to surface incorrect pipeline wiring early. + * + * @beta + */ +export class ProblemCollector extends TerminalWritable implements IProblemCollector { + private readonly _matchers: IProblemMatcher[]; + private readonly _problems: Set = new Set(); + private readonly _onProblem: ((problem: IProblem) => void) | undefined; + + public constructor(options: IProblemCollectorOptions) { + super(options); + + if ( + !options || + ((!options.matchers || options.matchers.length === 0) && + (!options.matcherJson || options.matcherJson.length === 0)) + ) { + throw new Error('ProblemCollector requires at least one problem matcher.'); + } + + const fromJson: IProblemMatcher[] = options.matcherJson + ? parseProblemMatchersJson(options.matcherJson) + : []; + this._matchers = [...(options.matchers || []), ...fromJson]; + if (this._matchers.length === 0) { + throw new Error('ProblemCollector requires at least one problem matcher.'); + } + this._onProblem = options.onProblem; + } + + /** + * {@inheritdoc IProblemCollector} + */ + public get problems(): ReadonlySet { + return this._problems; + } + + /** + * {@inheritdoc TerminalWritable} + */ + protected onWriteChunk(chunk: ITerminalChunk): void { + const text: string = chunk.text; + if (text.length === 0 || text[text.length - 1] !== '\n') { + throw new Error( + 'ProblemCollector expects chunks that were split into newline terminated lines. ' + + 'Invalid input: ' + + JSON.stringify(text) + ); + } + + for (const matcher of this._matchers) { + const problem: IProblem | false = matcher.exec(text); + if (problem) { + const finalized: IProblem = { + ...problem, + matcherName: matcher.name + }; + this._problems.add(finalized); + this._onProblem?.(finalized); + } + } + } + + /** + * {@inheritdoc TerminalWritable} + */ + protected onClose(): void { + for (const matcher of this._matchers) { + if (matcher.flush) { + const flushed: IProblem[] = matcher.flush(); + if (flushed && flushed.length > 0) { + for (const problem of flushed) { + const finalized: IProblem = { + ...problem, + matcherName: matcher.name + }; + this._problems.add(finalized); + this._onProblem?.(finalized); + } + } + } + } + } +} diff --git a/libraries/terminal/src/RemoveColorsTextRewriter.ts b/libraries/terminal/src/RemoveColorsTextRewriter.ts new file mode 100644 index 00000000000..7a9e8dd3352 --- /dev/null +++ b/libraries/terminal/src/RemoveColorsTextRewriter.ts @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AnsiEscape } from './AnsiEscape'; +import { TextRewriter, type TextRewriterState } from './TextRewriter'; + +enum State { + // Buffer is empty, and we're looking for the ESC character + Start, + // We're looking for the '[' character + AwaitingBracket, + // We're reading the codes after the '[' character + ReadingCodes +} + +interface IRemoveColorsTextRewriterState extends TextRewriterState { + buffer: string; + parseState: State; +} + +/** + * For use with {@link TextRewriterTransform}, this rewriter removes ANSI escape codes + * including colored text. + * + * @remarks + * The implementation also removes other ANSI escape codes such as cursor positioning. + * The specific set of affected codes may be adjusted in the future. + * + * @public + */ +export class RemoveColorsTextRewriter extends TextRewriter { + public initialize(): TextRewriterState { + return { buffer: '', parseState: State.Start } as IRemoveColorsTextRewriterState; + } + + public process(unknownState: TextRewriterState, text: string): string { + const state: IRemoveColorsTextRewriterState = unknownState as IRemoveColorsTextRewriterState; + + // We will be matching AnsiEscape._csiRegExp: + // + // /\x1b\[([\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e])/gu + // + const ESC: string = '\x1b'; + + let result: string = ''; + let index: number = 0; + + while (index < text.length) { + if (state.parseState === State.Start) { + // The buffer is empty, which means we haven't found anything yet + + const csiIndex: number = text.indexOf(ESC, index); + if (csiIndex < 0) { + // We reached the end of "text" without finding another CSI prefix + result += text.substring(index); + break; + } + + // Append everything up to the CSI prefix + result += text.substring(index, csiIndex); + + // Save the partial match in the buffer + state.buffer = ESC; + index = csiIndex + 1; + state.parseState = State.AwaitingBracket; + } else { + // The buffer has characters, which means we started matching a partial sequence + + // Read another character into the buffer + const c: string = text[index]; + ++index; + state.buffer += c; + + if (state.parseState === State.AwaitingBracket) { + if (c === '[') { + state.parseState = State.ReadingCodes; + } else { + // Failed to match, so append the buffer and start over + result += state.buffer; + state.buffer = ''; + state.parseState = State.Start; + } + } else { + // state.state === State.ReadingCodes + + // Stop when we reach any character that is not [\x30-\x3f] or [\x20-\x2f] + const code: number = c.charCodeAt(0); + if (code < 0x20 || code > 0x3f) { + result += AnsiEscape.removeCodes(state.buffer); + state.buffer = ''; + state.parseState = State.Start; + } + } + } + } + + return result; + } + + public close(unknownState: TextRewriterState): string { + const state: IRemoveColorsTextRewriterState = unknownState as IRemoveColorsTextRewriterState; + + const result: string = state.buffer; + state.buffer = ''; + return result; + } +} diff --git a/libraries/terminal/src/SplitterTransform.ts b/libraries/terminal/src/SplitterTransform.ts new file mode 100644 index 00000000000..cce5a428ffe --- /dev/null +++ b/libraries/terminal/src/SplitterTransform.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 { TerminalWritable, type ITerminalWritableOptions } from './TerminalWritable'; +import type { ITerminalChunk } from './ITerminalChunk'; + +/** + * Constructor options for {@link SplitterTransform}. + * + * @public + */ +export interface ISplitterTransformOptions extends ITerminalWritableOptions { + /** + * Each input chunk will be passed to each destination in the iterable. + */ + destinations: Iterable; +} + +/** + * Use this instead of {@link TerminalTransform} if you need to output `ITerminalChunk` + * data to more than one destination. + * + * @remarks + * + * Splitting streams complicates the pipeline topology and can make debugging more difficult. + * For this reason, it is modeled as an explicit `SplitterTransform` node, rather than + * as a built-in feature of `TerminalTransform`. + * + * @public + */ +export class SplitterTransform extends TerminalWritable { + private readonly _destinations: Set; + + public constructor(options: ISplitterTransformOptions) { + super(); + this._destinations = new Set(options.destinations); + } + + public get destinations(): ReadonlySet { + return this._destinations; + } + + /** + * Adds a destination to the set of destinations. Duplicates are ignored. + * Only new chunks received after the destination is added will be sent to it. + * @param destination - The destination to add. + */ + public addDestination(destination: TerminalWritable): void { + this._destinations.add(destination); + } + + /** + * Removes a destination from the set of destinations. It will no longer receive chunks, and will be closed, unless + * `destination.preventAutoclose` is set to `true`. + * @param destination - The destination to remove. + * @param close - If `true` (default), the destination will be closed when removed, unless `destination.preventAutoclose` is set to `true`. + * @returns `true` if the destination was removed, `false` if it was not found. + * @remarks + * If the destination is not found, it will not be closed. + */ + public removeDestination(destination: TerminalWritable, close: boolean = true): boolean { + if (this._destinations.delete(destination)) { + if (close && !destination.preventAutoclose) { + destination.close(); + } + return true; + } + return false; + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + for (const destination of this._destinations) { + destination.writeChunk(chunk); + } + } + + protected onClose(): void { + const errors: Error[] = []; + + // If an exception is thrown, try to ensure that the other destinations get closed properly + for (const destination of this._destinations) { + if (!destination.preventAutoclose) { + try { + destination.close(); + } catch (error) { + errors.push(error as Error); + } + } + } + + this._destinations.clear(); + + if (errors.length > 0) { + throw errors[0]; + } + } +} diff --git a/libraries/terminal/src/StdioLineTransform.ts b/libraries/terminal/src/StdioLineTransform.ts new file mode 100644 index 00000000000..af02fdfe6f9 --- /dev/null +++ b/libraries/terminal/src/StdioLineTransform.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Text, NewlineKind } from '@rushstack/node-core-library'; + +import { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk'; +import { TerminalTransform, type ITerminalTransformOptions } from './TerminalTransform'; + +/** + * Constructor options for {@link StderrLineTransform} + * @beta + */ +export interface IStdioLineTransformOptions extends ITerminalTransformOptions { + /** + * Specifies the kind of newline for the output. + */ + newlineKind?: NewlineKind; +} + +/** + * `StderrLineTransform` normalizes lines that mix characters from `stdout` and `stderr`, + * so that each output line is routed entirely to `stdout` or `stderr`. + * + * @remarks + * IMPORTANT: This transform assumes that its input has been normalized to use `"\n"` newlines. + * + * IMPORTANT: This transform does not produce realtime output, because lines are buffered + * until a newline character is encountered. + * + * Suppose that a poorly behaved process produces output like this: + * + * ```ts + * process.stderr.write('An error occurred, cleaning up'); + * process.stdout.write('.'); // (delay) + * process.stdout.write('.'); // (delay) + * process.stdout.write('.'); + * process.stdout.write('\n'); + * process.stderr.write('The process completed with errors\n'); + * ``` + * + * When `stdout` and `stderr` are combined on the console, the mistake in the output would not be noticeable: + * ``` + * An error occurred, cleaning up... + * The process completed with errors + * ``` + * + * However, if we discard `stdout`, then `stderr` is malformed: + * ``` + * An error occurred, cleaning upThe process completed with errors + * ``` + * + * Tooling scripts can introduce these sorts of problems via edge cases that are difficult to find and fix. + * + * `StderrLineTransform` normalizes the output so that if a combined line contains any `stderr` characters, + * then the entire line is routed to `stderr`. Later, if we discard `stdout`, then the output will + * preserve the appropriate context: + * + * ``` + * An error occurred, cleaning up... + * The process completed with errors + * ``` + * + * @privateRemarks + * This class is experimental and marked as `@beta`. The algorithm may need some fine-tuning, or there may + * be better solutions to this problem. + * + * @beta + */ +export class StderrLineTransform extends TerminalTransform { + private _accumulatedLine: string; + private _accumulatedStderr: boolean; + + public readonly newline: string; + + public constructor(options: IStdioLineTransformOptions) { + super(options); + + this._accumulatedLine = ''; + this._accumulatedStderr = false; + + this.newline = Text.getNewline(options.newlineKind || NewlineKind.Lf); + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (chunk.text.indexOf('\r') >= 0) { + throw new Error('StderrLineTransform expects chunks with normalized newlines'); + } + + // After _newlineNormalizerTransform was applied, we can now assume that all newlines + // use the "\n" string + const text: string = chunk.text; + let startIndex: number = 0; + + while (startIndex < text.length) { + if (chunk.kind === TerminalChunkKind.Stderr) { + this._accumulatedStderr = true; + } + + const endIndex: number = text.indexOf('\n', startIndex); + if (endIndex < 0) { + // we did not find \n, so simply append + this._accumulatedLine += text.substring(startIndex); + break; + } + + // append everything up to \n + this._accumulatedLine += text.substring(startIndex, endIndex); + + this._processAccumulatedLine(); + + // skip the \n + startIndex = endIndex + 1; + } + } + + protected onClose(): void { + if (this._accumulatedLine.length > 0) { + this._processAccumulatedLine(); + } + this.autocloseDestination(); + } + + private _processAccumulatedLine(): void { + this._accumulatedLine += this.newline; + + if (this._accumulatedStderr) { + this.destination.writeChunk({ + kind: TerminalChunkKind.Stderr, + text: this._accumulatedLine + }); + } else { + this.destination.writeChunk({ + kind: TerminalChunkKind.Stdout, + text: this._accumulatedLine + }); + } + + this._accumulatedLine = ''; + this._accumulatedStderr = false; + } +} diff --git a/libraries/terminal/src/StdioSummarizer.ts b/libraries/terminal/src/StdioSummarizer.ts new file mode 100644 index 00000000000..12c3bf18c50 --- /dev/null +++ b/libraries/terminal/src/StdioSummarizer.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 { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk'; +import { type ITerminalWritableOptions, TerminalWritable } from './TerminalWritable'; + +/** + * Constructor options for {@link StdioSummarizer}. + * @beta + */ +export interface IStdioSummarizerOptions extends ITerminalWritableOptions { + /** + * Specifies the maximum number of leading lines to include in the summary. + * @defaultValue `10` + */ + leadingLines?: number; + + /** + * Specifies the maximum number of trailing lines to include in the summary. + * @defaultValue `10` + */ + trailingLines?: number; +} + +/** + * Summarizes the results of a failed build task by returning a subset of `stderr` output not to exceed + * a specified maximum number of lines. + * + * @remarks + * IMPORTANT: This transform assumes that its input was prepared by {@link StderrLineTransform}, so that each + * {@link ITerminalChunk.text} item is a single line terminated by a `"\n"` character. + * + * The {@link IStdioSummarizerOptions.leadingLines} and {@link IStdioSummarizerOptions.trailingLines} + * counts specify the maximum number of lines to be returned. Any additional lines will be omitted. + * For example, if `leadingLines` and `trailingLines` were set to `3`, then the summary of 16 `stderr` lines might + * look like this: + * + * ``` + * Line 1 + * Line 2 + * Line 3 + * ...10 lines omitted... + * Line 14 + * Line 15 + * Line 16 + * ``` + * + * If the `stderr` output is completely empty, then the `stdout` output will be summarized instead. + * + * @beta + */ +export class StdioSummarizer extends TerminalWritable { + // Capture up to this many leading lines + private _leadingLines: number; + + // Capture up to this many trailing lines + private _trailingLines: number; + + private readonly _abridgedLeading: string[]; + private readonly _abridgedTrailing: string[]; + private _abridgedOmittedLines: number = 0; + private _abridgedStderr: boolean; + + public constructor(options?: IStdioSummarizerOptions) { + super(options); + + if (!options) { + options = {}; + } + + this._leadingLines = options.leadingLines !== undefined ? options.leadingLines : 10; + this._trailingLines = options.trailingLines !== undefined ? options.trailingLines : 10; + + this._abridgedLeading = []; + this._abridgedTrailing = []; + this._abridgedStderr = false; + } + + /** + * Returns the summary report. + * + * @remarks + * The `close()` method must be called before `getReport()` can be used. + */ + public getReport(): string { + if (this.isOpen) { + throw new Error('The summary cannot be prepared until after close() is called.'); + } + const report: string[] = [...this._abridgedLeading]; + if (this._abridgedOmittedLines === 1) { + report.push(` ...${this._abridgedOmittedLines} line omitted...\n`); + } + if (this._abridgedOmittedLines > 1) { + report.push(` ...${this._abridgedOmittedLines} lines omitted...\n`); + } + report.push(...this._abridgedTrailing); + return report.join(''); + } + + public onWriteChunk(chunk: ITerminalChunk): void { + if (chunk.text.length === 0 || chunk.text[chunk.text.length - 1] !== '\n') { + throw new Error( + 'StdioSummarizer expects chunks that were separated parsed into lines by StderrLineTransform\n' + + ' Invalid input: ' + + JSON.stringify(chunk.text) + ); + } + + if (chunk.kind === TerminalChunkKind.Stderr && !this._abridgedStderr) { + // The first time we see stderr, switch to capturing stderr + this._abridgedStderr = true; + this._abridgedLeading.length = 0; + this._abridgedTrailing.length = 0; + this._abridgedOmittedLines = 0; + } else if (this._abridgedStderr && chunk.kind !== TerminalChunkKind.Stderr) { + // If we're capturing stderr, then ignore non-stderr input + return; + } + + // Did we capture enough leading lines? + if (this._abridgedLeading.length < this._leadingLines) { + this._abridgedLeading.push(chunk.text); + return; + } + + this._abridgedTrailing.push(chunk.text); + + // If we captured to many trailing lines, omit the extras + while (this._abridgedTrailing.length > this._trailingLines) { + this._abridgedTrailing.shift(); + ++this._abridgedOmittedLines; + } + } +} diff --git a/libraries/terminal/src/StdioWritable.ts b/libraries/terminal/src/StdioWritable.ts new file mode 100644 index 00000000000..5b83bc44bf3 --- /dev/null +++ b/libraries/terminal/src/StdioWritable.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 process from 'node:process'; + +import { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk'; +import { TerminalWritable } from './TerminalWritable'; + +/** + * A {@link TerminalWritable} subclass that writes its output directly to the process `stdout` and `stderr` + * streams. + * + * @remarks + * This is the standard output target for a process. You normally do not need to construct + * this class; the {@link StdioWritable."instance"} singleton can be used instead. + * + * @public + */ +export class StdioWritable extends TerminalWritable { + public static instance: StdioWritable = new StdioWritable(); + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (chunk.kind === TerminalChunkKind.Stdout) { + process.stdout.write(chunk.text); + } else if (chunk.kind === TerminalChunkKind.Stderr) { + process.stderr.write(chunk.text); + } + } +} diff --git a/libraries/terminal/src/StringBufferTerminalProvider.ts b/libraries/terminal/src/StringBufferTerminalProvider.ts new file mode 100644 index 00000000000..5c57b6a9237 --- /dev/null +++ b/libraries/terminal/src/StringBufferTerminalProvider.ts @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { StringBuilder, Text } from '@rushstack/node-core-library'; + +import { type ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; +import { AnsiEscape } from './AnsiEscape'; + +/** + * @beta + */ +export interface IStringBufferOutputOptions { + /** + * If set to true, special characters like \\n, \\r, and the \\u001b character + * in color control tokens will get normalized to [-n-], [-r-], and [-x-] respectively + * + * This option defaults to `true` + */ + normalizeSpecialCharacters: boolean; +} + +/** + * Terminal provider that stores written data in buffers separated by severity. + * This terminal provider is designed to be used when code that prints to a terminal + * is being unit tested. + * + * @beta + */ +export class StringBufferTerminalProvider implements ITerminalProvider { + private _standardBuffer: StringBuilder = new StringBuilder(); + private _verboseBuffer: StringBuilder = new StringBuilder(); + private _debugBuffer: StringBuilder = new StringBuilder(); + private _warningBuffer: StringBuilder = new StringBuilder(); + private _errorBuffer: StringBuilder = new StringBuilder(); + + private _supportsColor: boolean; + + public constructor(supportsColor: boolean = false) { + this._supportsColor = supportsColor; + } + + /** + * {@inheritDoc ITerminalProvider.write} + */ + public write(data: string, severity: TerminalProviderSeverity): void { + switch (severity) { + case TerminalProviderSeverity.warning: { + this._warningBuffer.append(data); + break; + } + + case TerminalProviderSeverity.error: { + this._errorBuffer.append(data); + break; + } + + case TerminalProviderSeverity.verbose: { + this._verboseBuffer.append(data); + break; + } + + case TerminalProviderSeverity.debug: { + this._debugBuffer.append(data); + break; + } + + case TerminalProviderSeverity.log: + default: { + this._standardBuffer.append(data); + break; + } + } + } + + /** + * {@inheritDoc ITerminalProvider.eolCharacter} + */ + public get eolCharacter(): string { + return '\n'; + } + + /** + * {@inheritDoc ITerminalProvider.supportsColor} + */ + public get supportsColor(): boolean { + return this._supportsColor; + } + + /** + * Get everything that has been written at log-level severity. + */ + public getOutput(options?: IStringBufferOutputOptions): string { + return this._normalizeOutput(this._standardBuffer.toString(), options); + } + + /** + * @deprecated - use {@link StringBufferTerminalProvider.getVerboseOutput} + */ + public getVerbose(options?: IStringBufferOutputOptions): string { + return this.getVerboseOutput(options); + } + + /** + * Get everything that has been written at verbose-level severity. + */ + public getVerboseOutput(options?: IStringBufferOutputOptions): string { + return this._normalizeOutput(this._verboseBuffer.toString(), options); + } + + /** + * Get everything that has been written at debug-level severity. + */ + public getDebugOutput(options?: IStringBufferOutputOptions): string { + return this._normalizeOutput(this._debugBuffer.toString(), options); + } + + /** + * Get everything that has been written at error-level severity. + */ + public getErrorOutput(options?: IStringBufferOutputOptions): string { + return this._normalizeOutput(this._errorBuffer.toString(), options); + } + + /** + * Get everything that has been written at warning-level severity. + */ + public getWarningOutput(options?: IStringBufferOutputOptions): string { + return this._normalizeOutput(this._warningBuffer.toString(), options); + } + + private _normalizeOutput(s: string, options: IStringBufferOutputOptions | undefined): string { + options = { + normalizeSpecialCharacters: true, + + ...(options || {}) + }; + + s = Text.convertToLf(s); + + if (options.normalizeSpecialCharacters) { + return AnsiEscape.formatForTests(s, { encodeNewlines: true }); + } else { + return s; + } + } +} diff --git a/libraries/terminal/src/Terminal.ts b/libraries/terminal/src/Terminal.ts new file mode 100644 index 00000000000..d888fee5dc9 --- /dev/null +++ b/libraries/terminal/src/Terminal.ts @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; +import { Colorize } from './Colorize'; +import type { ITerminal, ITerminalWriteOptions, TerminalWriteParameters } from './ITerminal'; +import { AnsiEscape } from './AnsiEscape'; + +/** + * This class facilitates writing to a console. + * + * @beta + */ +export class Terminal implements ITerminal { + private readonly _providers: Set; + + public constructor(provider: ITerminalProvider) { + this._providers = new Set([provider]); + } + + /** + * {@inheritdoc ITerminal.registerProvider} + */ + public registerProvider(provider: ITerminalProvider): void { + this._providers.add(provider); + } + + /** + * {@inheritdoc ITerminal.unregisterProvider} + */ + public unregisterProvider(provider: ITerminalProvider): void { + this._providers.delete(provider); + } + + /** + * {@inheritdoc ITerminal.write} + */ + public write(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.log, false); + } + + /** + * {@inheritdoc ITerminal.writeLine} + */ + public writeLine(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.log, true); + } + + /** + * {@inheritdoc ITerminal.writeWarning} + */ + public writeWarning(...messageParts: TerminalWriteParameters): void { + const { + parts, + options: { doNotOverrideSgrCodes } + } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders( + doNotOverrideSgrCodes + ? parts + : parts.map((part): string => Colorize.yellow(AnsiEscape.removeCodes(part))), + TerminalProviderSeverity.warning, + false + ); + } + + /** + * {@inheritdoc ITerminal.writeWarningLine} + */ + public writeWarningLine(...messageParts: TerminalWriteParameters): void { + const { + parts, + options: { doNotOverrideSgrCodes } + } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders( + doNotOverrideSgrCodes + ? parts + : parts.map((part): string => Colorize.yellow(AnsiEscape.removeCodes(part))), + TerminalProviderSeverity.warning, + true + ); + } + + /** + * {@inheritdoc ITerminal.writeError} + */ + public writeError(...messageParts: TerminalWriteParameters): void { + const { + parts, + options: { doNotOverrideSgrCodes } + } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders( + doNotOverrideSgrCodes ? parts : parts.map((part): string => Colorize.red(AnsiEscape.removeCodes(part))), + TerminalProviderSeverity.error, + false + ); + } + + /** + * {@inheritdoc ITerminal.writeErrorLine} + */ + public writeErrorLine(...messageParts: TerminalWriteParameters): void { + const { + parts, + options: { doNotOverrideSgrCodes } + } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders( + doNotOverrideSgrCodes ? parts : parts.map((part): string => Colorize.red(AnsiEscape.removeCodes(part))), + TerminalProviderSeverity.error, + true + ); + } + + /** + * {@inheritdoc ITerminal.writeVerbose} + */ + public writeVerbose(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.verbose, false); + } + + /** + * {@inheritdoc ITerminal.writeVerboseLine} + */ + public writeVerboseLine(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.verbose, true); + } + + /** + * {@inheritdoc ITerminal.writeDebug} + */ + public writeDebug(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.debug, false); + } + + /** + * {@inheritdoc ITerminal.writeDebugLine} + */ + public writeDebugLine(...messageParts: TerminalWriteParameters): void { + const { parts } = this._normalizeWriteParameters(messageParts); + this._writeSegmentsToProviders(parts, TerminalProviderSeverity.debug, true); + } + + private _writeSegmentsToProviders( + segments: string[], + severity: TerminalProviderSeverity, + followedByEol: boolean + ): void { + const lines: string[] = [segments.join('')]; + if (followedByEol) { + lines.push(''); + } + + let linesWithoutColor: string[] | undefined; + + const concatenatedLinesWithColorByNewlineChar: Map = new Map(); + const concatenatedLinesWithoutColorByNewlineChar: Map = new Map(); + for (const provider of this._providers) { + let textToWrite: string | undefined; + const eol: string = provider.eolCharacter; + if (provider.supportsColor) { + textToWrite = concatenatedLinesWithColorByNewlineChar.get(eol); + if (!textToWrite) { + textToWrite = lines.join(eol); + concatenatedLinesWithColorByNewlineChar.set(eol, textToWrite); + } + } else { + textToWrite = concatenatedLinesWithoutColorByNewlineChar.get(eol); + if (!textToWrite) { + if (!linesWithoutColor) { + linesWithoutColor = []; + for (const line of lines) { + linesWithoutColor.push(AnsiEscape.removeCodes(line)); + } + } + + textToWrite = linesWithoutColor.join(eol); + concatenatedLinesWithoutColorByNewlineChar.set(eol, textToWrite); + } + } + + provider.write(textToWrite, severity); + } + } + + private _normalizeWriteParameters(parameters: TerminalWriteParameters): { + parts: string[]; + options: ITerminalWriteOptions; + } { + if (parameters.length === 0) { + return { parts: [], options: {} }; + } else { + const lastParameter: string | ITerminalWriteOptions = parameters[parameters.length - 1]; + if (typeof lastParameter === 'string') { + return { parts: parameters as string[], options: {} }; + } else { + return { parts: parameters.slice(0, -1) as string[], options: lastParameter }; + } + } + } +} diff --git a/libraries/terminal/src/TerminalStreamWritable.ts b/libraries/terminal/src/TerminalStreamWritable.ts new file mode 100644 index 00000000000..8b84a1bcdf3 --- /dev/null +++ b/libraries/terminal/src/TerminalStreamWritable.ts @@ -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 { Writable, type WritableOptions } from 'node:stream'; + +import type { ITerminal } from './ITerminal'; +import { TerminalProviderSeverity } from './ITerminalProvider'; + +/** + * Options for {@link TerminalStreamWritable}. + * + * @beta + */ +export interface ITerminalStreamWritableOptions { + /** + * The {@link ITerminal} that the Writable will write to. + */ + terminal: ITerminal; + /** + * The severity of the messages that will be written to the {@link ITerminal}. + */ + severity: TerminalProviderSeverity; + /** + * Options for the underlying Writable. + */ + writableOptions?: WritableOptions; +} + +/** + * A adapter to allow writing to a provided terminal using Writable streams. + * + * @beta + */ +export class TerminalStreamWritable extends Writable { + private _writeMethod: (data: string) => void; + + public constructor(options: ITerminalStreamWritableOptions) { + const { terminal, severity, writableOptions } = options; + super(writableOptions); + + this._writev = undefined; + switch (severity) { + case TerminalProviderSeverity.log: + this._writeMethod = terminal.write.bind(terminal); + break; + case TerminalProviderSeverity.verbose: + this._writeMethod = terminal.writeVerbose.bind(terminal); + break; + case TerminalProviderSeverity.debug: + this._writeMethod = terminal.writeDebug.bind(terminal); + break; + case TerminalProviderSeverity.warning: + this._writeMethod = terminal.writeWarning.bind(terminal); + break; + case TerminalProviderSeverity.error: + this._writeMethod = terminal.writeError.bind(terminal); + break; + default: + throw new Error(`Unknown severity: ${severity}`); + } + } + + public _write( + chunk: string | Buffer | Uint8Array, + encoding: string, + // eslint-disable-next-line @rushstack/no-new-null + callback: (error?: Error | null) => void + ): void { + try { + const chunkData: string | Buffer = typeof chunk === 'string' ? chunk : Buffer.from(chunk); + this._writeMethod(chunkData.toString()); + } catch (e: unknown) { + callback(e as Error); + return; + } + callback(); + } +} diff --git a/libraries/terminal/src/TerminalTransform.ts b/libraries/terminal/src/TerminalTransform.ts new file mode 100644 index 00000000000..e4de47486d4 --- /dev/null +++ b/libraries/terminal/src/TerminalTransform.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TerminalWritable, type ITerminalWritableOptions } from './TerminalWritable'; + +/** + * Constructor options for {@link TerminalTransform}. + * + * @public + */ +export interface ITerminalTransformOptions extends ITerminalWritableOptions { + /** + * The target `TerminalWritable` that the `TerminalTransform` will write its + * output to. + */ + destination: TerminalWritable; + + /** + * Prevents the {@link TerminalTransform.destination} object from being + * closed automatically when the transform is closed. + * + * @remarks + * When a transform is closed, normally it will automatically close its destination + * `TerminalWritable` object. There are two ways to prevent that: either by setting + * `preventDestinationAutoclose` to `true` for the transform, or by setting + * {@link TerminalWritable.preventAutoclose} to `true` for the `destination` object. + */ + preventDestinationAutoclose?: boolean; +} + +/** + * The abstract base class for {@link TerminalWritable} objects that receive an input, + * transform it somehow, and then write the output to another `TerminalWritable`. + * + * @remarks + * + * The `TerminalTransform` and {@link SplitterTransform} base classes formalize the idea + * of modeling data flow as a directed acyclic graph of reusable transforms, whose + * final outputs are `TerminalWritable` objects. + * + * The design is based loosely on the `WritableStream` and `TransformStream` classes from + * the system {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts + * | Streams API}, except that instead of asynchronous byte streams, the `TerminalWritable` + * system synchronously transmits human readable messages intended to be rendered on a + * text console or log file. + * + * The main feature of the `TerminalTransform` class is its {@link TerminalTransform.destination} + * property, which tracks the next link in the graph. + * + * @public + */ +export abstract class TerminalTransform extends TerminalWritable { + /** {@inheritDoc ITerminalTransformOptions.destination} */ + public readonly destination: TerminalWritable; + + /** {@inheritDoc ITerminalTransformOptions.preventDestinationAutoclose} */ + public readonly preventDestinationAutoclose: boolean; + + public constructor(options: ITerminalTransformOptions) { + super(); + this.destination = options.destination; + this.preventDestinationAutoclose = !!options.preventDestinationAutoclose; + } + + /** @override */ + protected onClose(): void { + this.autocloseDestination(); + } + + /** + * The default implementation of {@link TerminalTransform.onClose} calls this + * method, which closes the {@link TerminalTransform.destination} if appropriate. + * + * @remarks + * The destination will not be closed if its {@link TerminalWritable.preventAutoclose} + * property is `true`. The destination will not be closed if + * {@link ITerminalTransformOptions.preventDestinationAutoclose} + * is `true`. + * + * @sealed + */ + protected autocloseDestination(): void { + if (!this.preventDestinationAutoclose && !this.destination.preventAutoclose) { + this.destination.close(); + } + } +} diff --git a/libraries/terminal/src/TerminalWritable.ts b/libraries/terminal/src/TerminalWritable.ts new file mode 100644 index 00000000000..22f20f72263 --- /dev/null +++ b/libraries/terminal/src/TerminalWritable.ts @@ -0,0 +1,156 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ITerminalChunk } from './ITerminalChunk'; + +/** + * Constructor options for {@link TerminalWritable} + * + * @public + */ +export interface ITerminalWritableOptions { + /** + * When this object is the {@link TerminalTransform.destination} for a transform, + * the transform will automatically close this object. Set `preventAutoclose` to `true` + * to prevent that behavior. + * + * @remarks + * When a transform is closed, normally it will automatically close its destination + * `TerminalWritable` object. There are two ways to prevent that: either by setting + * `preventDestinationAutoclose` to `true` for the transform, or by setting + * {@link TerminalWritable.preventAutoclose} to `true` for the `destination` object. + */ + preventAutoclose?: boolean; +} + +/** + * The abstract base class for objects that can present, route, or process text output for + * a console application. This output is typically prepared using + * the {@link Terminal} API. + * + * @remarks + * + * The design is based loosely on the `WritableStream` and `TransformStream` classes from + * the system {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts + * | Streams API}, except that instead of asynchronous byte streams, the `TerminalWritable` + * system synchronously transmits human readable messages intended to be rendered on a text + * console or log file. + * + * Consider a console application whose output may need to be processed in different ways + * before finally being output. The conceptual block diagram might look like this: + * + * ``` + * [Terminal API] + * | + * V + * [normalize newlines] + * | + * V + * +----[splitter]-------+ + * | | + * V V + * [shell console] [remove ANSI colors] + * | + * V + * [write to build.log] + * ``` + * + * The application uses the `Terminal` API to print `stdout` and `stderr` messages, for example with standardized + * formatting for errors and warnings, and ANSI escapes to make nice colors. Maybe it also includes text + * received from external processes, whose newlines may be inconsistent. Ultimately we want to write the + * output to the shell console and a `build.log` file, but we don't want to put ANSI colors in the build log. + * + * For the above example, `[shell console]` and `[write to build.log]` would be modeled as subclasses of + * `TerminalWritable`. The `[normalize newlines]` and `[remove ANSI colors]` steps are modeled as subclasses + * of {@link TerminalTransform}, because they output to a "destination" object. The `[splitter]` would be + * implemented using {@link SplitterTransform}. + * + * The stream of messages are {@link ITerminalChunk} objects, which can represent both `stdout` and `stderr` + * channels. The pipeline operates synchronously on each chunk, but by processing one chunk at a time, + * it avoids storing the entire output in memory. This means that operations like `[remove ANSI colors]` + * cannot be simple regular expressions -- they must be implemented as state machines ({@link TextRewriter} + * subclasses) capable of matching substrings that span multiple chunks. + * + * @public + */ +export abstract class TerminalWritable { + private _isOpen: boolean; + + public readonly preventAutoclose: boolean; + + public constructor(options?: ITerminalWritableOptions) { + this._isOpen = true; + + if (!options) { + options = {}; + } + + this.preventAutoclose = !!options.preventAutoclose; + } + + /** + * This property is initially `true` when the object is constructed, and becomes `false` + * when `close()` is called. + * @sealed + */ + public get isOpen(): boolean { + return this._isOpen; + } + + /** + * Upstream objects call this method to provide inputs to this object. + * + * @remarks + * The subclass provides its implementation via the the {@link TerminalWritable.onWriteChunk} + * method, which is called by `writeChunk()`. + * + * The object that calls `writeChunk()` must call `close()` when it is finished; + * failing to do so may introduce a resource leak, or may prevent some buffered data from + * being written. + * + * @sealed + */ + public writeChunk(chunk: ITerminalChunk): void { + if (!this._isOpen) { + throw new Error('Writer was already closed'); + } + this.onWriteChunk(chunk); + } + + /** + * Subclasses should implement this `abstract` method to process the chunk. + */ + protected abstract onWriteChunk(chunk: ITerminalChunk): void; + + /** + * Calling this method flushes any remaining outputs and permanently transitions the + * `TerminalWritable` to a "closed" state, where no further chunks can be written. + * + * @remarks + * The subclass provides its implementation via the the {@link TerminalWritable.onClose} + * method, which is called by `close()`. + * + * If this method is called more than once, the additional calls are ignored; + * `TerminalWritable.onClose` will be called at most once. + * + * @sealed + */ + public close(): void { + if (this._isOpen) { + this.onClose(); + this._isOpen = false; + } + } + + /** + * Subclasses can override this empty method to perform additional operations + * such as closing a file handle. + * + * @remarks + * It is guaranteed that this method will be called at most once during the lifetime + * of a `TerminalWritable` object. + * + * @virtual + */ + protected onClose(): void {} +} diff --git a/libraries/terminal/src/TextRewriter.ts b/libraries/terminal/src/TextRewriter.ts new file mode 100644 index 00000000000..1ff30c60a96 --- /dev/null +++ b/libraries/terminal/src/TextRewriter.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Brand } from '@rushstack/node-core-library'; + +/** + * Represents the internal state of a {@link TextRewriter} subclass. + * + * @remarks + * For example, suppose that {@link NormalizeNewlinesTextRewriter} will be used to rewrite + * the input `"line 1\r\nline 2\r\n"` to become `"line 1\nline 2\n"`. But suppose that the `"\r\n"` + * pair is split across two chunks: + * + * ```ts + * const rewriter: NormalizeNewlinesTextRewriter = new NormalizeNewlinesTextRewriter(NewlineKind.Lf); + * const state: TextRewriterState = rewriter.initialize(); + * let output: string = rewriter.process(state, 'line 1\r'); + * output += rewriter.process(state, '\nline 2\r\n'); + * output += rewriter.close(state); + * + * // The final "output" value is: "line 1\nline 2\n" + * ``` + * + * The `TextRewriterState` keeps track of this context, so that split `"\r"` and `"\n"` are + * interpreted as a single newline. + * + * @public + */ +export type TextRewriterState = Brand; + +/** + * The abstract base class for operations that can be applied by {@link TextRewriterTransform}. + * + * @remarks + * The {@link TextRewriterTransform} applies one or more character rewriting operations to its + * chunk stream. Since these operations are applied separately to `stderr` and `stdout`, the + * state is stored in an opaque `TextRewriterState` object. + * + * Conceptually, a `TextRewriter` subclass is very similar to a regular expression, with the difference + * that `RegExp` operates on a text string, whereas `TextRewriter` operates on a stream of characters. + * + * The two most common subclasses are {@link NormalizeNewlinesTextRewriter} and {@link RemoveColorsTextRewriter}. + * + * A rewriting operation starts with `initialize()`, followed by any number of `process()` calls, and + * then finishes with `close()`. For example: + * + * ```ts + * const rewriter: NormalizeNewlinesTextRewriter = new NormalizeNewlinesTextRewriter(NewlineKind.Lf); + * const state: TextRewriterState = rewriter.initialize(); + * let output: string = rewriter.process(state, 'line 1\r'); + * output += rewriter.process(state, '\nline 2\r\n'); + * output += rewriter.close(state); + * + * // The final "output" value is: "line 1\nline 2\n" + * ``` + * + * After `close()` has been called, the `TextRewriterState` state should not be reused. + * + * @public + */ +export abstract class TextRewriter { + /** + * Create a new `TextRewriterState` object that can be used to process a stream of characters. + */ + public abstract initialize(): TextRewriterState; + + /** + * Rewrite the next sequence of characters from the input stream, returning the modified output. + */ + public abstract process(state: TextRewriterState, input: string): string; + + /** + * Close the `TextRewriterState` object and return any buffered output. + */ + public abstract close(state: TextRewriterState): string; +} diff --git a/libraries/terminal/src/TextRewriterTransform.ts b/libraries/terminal/src/TextRewriterTransform.ts new file mode 100644 index 00000000000..a9d394da8eb --- /dev/null +++ b/libraries/terminal/src/TextRewriterTransform.ts @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { NewlineKind } from '@rushstack/node-core-library'; + +import { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk'; +import { TerminalTransform, type ITerminalTransformOptions } from './TerminalTransform'; +import type { TextRewriter, TextRewriterState } from './TextRewriter'; +import { RemoveColorsTextRewriter } from './RemoveColorsTextRewriter'; +import { NormalizeNewlinesTextRewriter } from './NormalizeNewlinesTextRewriter'; + +/** + * Constructor options for {@link TextRewriterTransform}. + * + * @public + */ +export interface ITextRewriterTransformOptions extends ITerminalTransformOptions { + /** + * A list of rewriters to be applied. More items may be appended to the list, for example + * if {@link ITextRewriterTransformOptions.removeColors} is specified. + * + * @remarks + * The final list must contain at least one item. + */ + textRewriters?: TextRewriter[]; + + /** + * If specified, a {@link RemoveColorsTextRewriter} will be appended to the list of rewriters. + */ + removeColors?: boolean; + + /** + * If `normalizeNewlines` or `ensureNewlineAtEnd` is specified, a {@link NormalizeNewlinesTextRewriter} + * will be appended to the list of rewriters with the specified settings. + * + * @remarks + * See {@link INormalizeNewlinesTextRewriterOptions} for details. + */ + normalizeNewlines?: NewlineKind; + + /** + * If `normalizeNewlines` or `ensureNewlineAtEnd` is specified, a {@link NormalizeNewlinesTextRewriter} + * will be appended to the list of rewriters with the specified settings. + * + * @remarks + * See {@link INormalizeNewlinesTextRewriterOptions} for details. + */ + ensureNewlineAtEnd?: boolean; +} + +/** + * A {@link TerminalTransform} subclass that performs one or more {@link TextRewriter} operations. + * The most common operations are {@link NormalizeNewlinesTextRewriter} and {@link RemoveColorsTextRewriter}. + * + * @remarks + * The `TextRewriter` operations are applied separately to the `stderr` and `stdout` streams. + * If multiple {@link ITextRewriterTransformOptions.textRewriters} are configured, they are applied + * in the order that they appear in the array. + * + * @public + */ +export class TextRewriterTransform extends TerminalTransform { + private readonly _stderrStates: TextRewriterState[]; + private readonly _stdoutStates: TextRewriterState[]; + + public readonly textRewriters: ReadonlyArray; + + public constructor(options: ITextRewriterTransformOptions) { + super(options); + + const textRewriters: TextRewriter[] = options.textRewriters || []; + + if (options.removeColors) { + textRewriters.push(new RemoveColorsTextRewriter()); + } + if (options.normalizeNewlines) { + textRewriters.push( + new NormalizeNewlinesTextRewriter({ + newlineKind: options.normalizeNewlines, + ensureNewlineAtEnd: options.ensureNewlineAtEnd + }) + ); + } + + if (textRewriters.length === 0) { + throw new Error('TextRewriterTransform requires at least one matcher'); + } + + this.textRewriters = textRewriters; + + this._stderrStates = this.textRewriters.map((x) => x.initialize()); + this._stdoutStates = this.textRewriters.map((x) => x.initialize()); + } + + protected onWriteChunk(chunk: ITerminalChunk): void { + if (chunk.kind === TerminalChunkKind.Stderr) { + this._processText(chunk, this._stderrStates); + } else if (chunk.kind === TerminalChunkKind.Stdout) { + this._processText(chunk, this._stdoutStates); + } else { + this.destination.writeChunk(chunk); + } + } + + private _processText(chunk: ITerminalChunk, states: TextRewriterState[]): void { + let text: string = chunk.text; + for (let i: number = 0; i < states.length; ++i) { + if (text.length > 0) { + text = this.textRewriters[i].process(states[i], text); + } + } + if (text.length > 0) { + // If possible, avoid allocating a new chunk + if (text === chunk.text) { + this.destination.writeChunk(chunk); + } else { + this.destination.writeChunk({ + text: text, + kind: chunk.kind + }); + } + } + } + + private _closeRewriters(states: TextRewriterState[], chunkKind: TerminalChunkKind): void { + let text: string = ''; + for (let i: number = 0; i < states.length; ++i) { + if (text.length > 0) { + text = this.textRewriters[i].process(states[i], text); + } + text += this.textRewriters[i].close(states[i]); + } + if (text.length > 0) { + this.destination.writeChunk({ + text: text, + kind: chunkKind + }); + } + } + + protected onClose(): void { + this._closeRewriters(this._stderrStates, TerminalChunkKind.Stderr); + this._closeRewriters(this._stdoutStates, TerminalChunkKind.Stdout); + + this.autocloseDestination(); + } +} diff --git a/libraries/terminal/src/index.ts b/libraries/terminal/src/index.ts new file mode 100644 index 00000000000..3824681927b --- /dev/null +++ b/libraries/terminal/src/index.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. + +/// + +/** + * This library implements a system for processing human readable text that + * will be output by console applications. + * + * @remarks + * See the {@link TerminalWritable} documentation for an overview of the major concepts. + * + * @packageDocumentation + */ + +export { type ICallbackWritableOptions, CallbackWritable } from './CallbackWritable'; +export { type IDiscardStdoutTransformOptions, DiscardStdoutTransform } from './DiscardStdoutTransform'; +export { TerminalChunkKind, type ITerminalChunk } from './ITerminalChunk'; +export { MockWritable } from './MockWritable'; +export { + type INormalizeNewlinesTextRewriterOptions, + NormalizeNewlinesTextRewriter +} from './NormalizeNewlinesTextRewriter'; +export { DEFAULT_CONSOLE_WIDTH, PrintUtilities } from './PrintUtilities'; +export { RemoveColorsTextRewriter } from './RemoveColorsTextRewriter'; +export { type ISplitterTransformOptions, SplitterTransform } from './SplitterTransform'; +export { type IStdioLineTransformOptions, StderrLineTransform } from './StdioLineTransform'; +export { type IStdioSummarizerOptions, StdioSummarizer } from './StdioSummarizer'; +export { StdioWritable } from './StdioWritable'; +export { type ITerminalTransformOptions, TerminalTransform } from './TerminalTransform'; +export { type ITerminalWritableOptions, TerminalWritable } from './TerminalWritable'; +export { type TextRewriterState, TextRewriter } from './TextRewriter'; +export { type ITextRewriterTransformOptions, TextRewriterTransform } from './TextRewriterTransform'; +export { AnsiEscape, type IAnsiEscapeConvertForTestsOptions } from './AnsiEscape'; +export type { ITerminal, TerminalWriteParameters, ITerminalWriteOptions } from './ITerminal'; +export { Terminal } from './Terminal'; +export { Colorize } from './Colorize'; +export { type ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider'; +export { ConsoleTerminalProvider, type IConsoleTerminalProviderOptions } from './ConsoleTerminalProvider'; +export { + StringBufferTerminalProvider, + type IStringBufferOutputOptions +} from './StringBufferTerminalProvider'; +export { + PrefixProxyTerminalProvider, + type IPrefixProxyTerminalProviderOptions, + type IDynamicPrefixProxyTerminalProviderOptions, + type IPrefixProxyTerminalProviderOptionsBase, + type IStaticPrefixProxyTerminalProviderOptions +} from './PrefixProxyTerminalProvider'; +export { NoOpTerminalProvider } from './NoOpTerminalProvider'; +export { TerminalStreamWritable, type ITerminalStreamWritableOptions } from './TerminalStreamWritable'; +export { ProblemCollector, type IProblemCollectorOptions } from './ProblemCollector'; +export type { IProblemCollector } from './IProblemCollector'; diff --git a/libraries/terminal/src/test/AnsiEscape.test.ts b/libraries/terminal/src/test/AnsiEscape.test.ts new file mode 100644 index 00000000000..e51ac48b865 --- /dev/null +++ b/libraries/terminal/src/test/AnsiEscape.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 { AnsiEscape } from '../AnsiEscape'; +import { Colorize } from '../Colorize'; + +describe(AnsiEscape.name, () => { + it('calls removeCodes() successfully', () => { + const coloredInput: string = Colorize.rainbow('Hello, world!'); + const decoloredInput: string = AnsiEscape.removeCodes(coloredInput); + expect(coloredInput).not.toBe(decoloredInput); + expect(decoloredInput).toBe('Hello, world!'); + }); +}); diff --git a/libraries/terminal/src/test/Colorize.test.ts b/libraries/terminal/src/test/Colorize.test.ts new file mode 100644 index 00000000000..f617b0817fc --- /dev/null +++ b/libraries/terminal/src/test/Colorize.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 { createColorGrid } from './createColorGrid'; +import { Colorize } from '../Colorize'; +import { AnsiEscape } from '../AnsiEscape'; + +describe(Colorize.name, () => { + test('writes color grid correctly', () => { + let lineCount: number = 0; + for (const line of createColorGrid()) { + expect(line.map((linePart) => AnsiEscape.formatForTests(linePart))).toMatchSnapshot( + `line ${lineCount++}` + ); + } + + expect(lineCount).toMatchInlineSnapshot(`10`); + }); + + it('generates codes as expected', () => { + type ColorsFunctionNames = { + [K in keyof typeof Colorize]: (typeof Colorize)[K] extends (str: string) => string ? K : never; + }[keyof typeof Colorize]; + function testColorFunction(functionName: ColorsFunctionNames): void { + expect(Colorize[functionName]('x')).toMatchSnapshot(functionName); + } + + testColorFunction('black'); + testColorFunction('red'); + testColorFunction('green'); + testColorFunction('yellow'); + testColorFunction('blue'); + testColorFunction('magenta'); + testColorFunction('cyan'); + testColorFunction('white'); + testColorFunction('gray'); + testColorFunction('blackBackground'); + testColorFunction('redBackground'); + testColorFunction('greenBackground'); + testColorFunction('yellowBackground'); + testColorFunction('blueBackground'); + testColorFunction('magentaBackground'); + testColorFunction('cyanBackground'); + testColorFunction('whiteBackground'); + testColorFunction('grayBackground'); + testColorFunction('bold'); + testColorFunction('dim'); + testColorFunction('underline'); + testColorFunction('blink'); + testColorFunction('invertColor'); + testColorFunction('hidden'); + }); +}); diff --git a/libraries/terminal/src/test/NormalizeNewlinesTextRewriter.test.ts b/libraries/terminal/src/test/NormalizeNewlinesTextRewriter.test.ts new file mode 100644 index 00000000000..404ea56dec8 --- /dev/null +++ b/libraries/terminal/src/test/NormalizeNewlinesTextRewriter.test.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 { Text, NewlineKind } from '@rushstack/node-core-library'; +import type { TextRewriterState } from '../TextRewriter'; +import { NormalizeNewlinesTextRewriter } from '../NormalizeNewlinesTextRewriter'; + +function testCase(input: string): void { + const matcher: NormalizeNewlinesTextRewriter = new NormalizeNewlinesTextRewriter({ + newlineKind: NewlineKind.Lf + }); + const state: TextRewriterState = matcher.initialize(); + let result: string = ''; + + for (let i = 0; i < input.length; ++i) { + result += matcher.process(state, input[i]); + } + result += matcher.close(state); + + expect(result).toEqual(Text.convertToLf(input)); +} + +describe(NormalizeNewlinesTextRewriter.name, () => { + it('should duplicate Text.convertToLf()', () => { + testCase(''); + testCase('\n'); + testCase('\r'); + testCase('\n\n'); + testCase('\r\n'); + testCase('\n\r'); + testCase('\r\r'); + testCase('\n\n\n'); + testCase('\r\n\n'); + testCase('\n\r\n'); + testCase('\r\r\n'); + testCase('\n\n\r'); + testCase('\r\n\r'); + testCase('\n\r\r'); + testCase('\r\r\r'); + + testCase('\nX\n\r'); + testCase('\rX\r'); + testCase('\r \n'); + }); +}); diff --git a/libraries/terminal/src/test/PrefixProxyTerminalProvider.test.ts b/libraries/terminal/src/test/PrefixProxyTerminalProvider.test.ts new file mode 100644 index 00000000000..c0a69b8b960 --- /dev/null +++ b/libraries/terminal/src/test/PrefixProxyTerminalProvider.test.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 { Terminal } from '../Terminal'; +import { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; +import { PrefixProxyTerminalProvider } from '../PrefixProxyTerminalProvider'; +import type { ITerminalProvider } from '../ITerminalProvider'; + +function runTestsForTerminalProvider( + getTerminalProvider: (terminalProvider: ITerminalProvider) => PrefixProxyTerminalProvider +): void { + let terminal: Terminal; + let baseProvider: StringBufferTerminalProvider; + + function verifyProvider(): void { + expect({ + log: baseProvider.getOutput(), + warning: baseProvider.getWarningOutput(), + error: baseProvider.getErrorOutput(), + verbose: baseProvider.getVerboseOutput(), + debug: baseProvider.getDebugOutput() + }).toMatchSnapshot(); + } + + beforeEach(() => { + baseProvider = new StringBufferTerminalProvider(true); + const prefixProvider: PrefixProxyTerminalProvider = getTerminalProvider(baseProvider); + terminal = new Terminal(prefixProvider); + }); + + describe('write', () => { + test('writes a message', () => { + terminal.write('test message'); + verifyProvider(); + }); + + test('writes a message with newlines', () => { + terminal.write('message 1\nmessage 2\nmessage 3'); + verifyProvider(); + }); + + test('writes a message with provider newlines', () => { + terminal.write(`message 1${baseProvider.eolCharacter}message 2${baseProvider.eolCharacter}message 3`); + verifyProvider(); + }); + + test('writes messages without newlines', () => { + terminal.write('message 1'); + terminal.write('message 2'); + terminal.write('message 3'); + verifyProvider(); + }); + + test('writes a mix of messages with and without newlines', () => { + terminal.write('message 1'); + terminal.write('message 2\nmessage 3\n'); + terminal.write('message 4'); + terminal.write('message 5\nmessage 6'); + verifyProvider(); + }); + }); + + describe('writeLine', () => { + test('writes a message line', () => { + terminal.writeLine('test message'); + verifyProvider(); + }); + + test('writes a message line with newlines', () => { + terminal.writeLine('message 1\nmessage 2\nmessage 3'); + verifyProvider(); + }); + + test('writes a message line with provider newlines', () => { + terminal.writeLine( + `message 1${baseProvider.eolCharacter}message 2${baseProvider.eolCharacter}message 3` + ); + verifyProvider(); + }); + + test('writes a mix of message lines with and without newlines', () => { + terminal.writeLine('message 1'); + terminal.writeLine('message 2\nmessage 3\n'); + terminal.writeLine('message 4'); + terminal.writeLine('message 5\nmessage 6'); + verifyProvider(); + }); + }); +} + +describe(PrefixProxyTerminalProvider.name, () => { + describe('With a static prefix', () => { + runTestsForTerminalProvider( + (terminalProvider) => + new PrefixProxyTerminalProvider({ + terminalProvider, + prefix: '[prefix] ' + }) + ); + }); + + describe('With a dynamic prefix', () => { + runTestsForTerminalProvider((terminalProvider) => { + let counter: number = 0; + return new PrefixProxyTerminalProvider({ + terminalProvider, + getPrefix: () => `[prefix (${counter++})] ` + }); + }); + }); +}); diff --git a/libraries/terminal/src/test/PrintUtilities.test.ts b/libraries/terminal/src/test/PrintUtilities.test.ts new file mode 100644 index 00000000000..81fc2e51526 --- /dev/null +++ b/libraries/terminal/src/test/PrintUtilities.test.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 { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; +import { Terminal } from '../Terminal'; +import { PrintUtilities } from '../PrintUtilities'; + +describe(PrintUtilities.name, () => { + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(false); + terminal = new Terminal(terminalProvider); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + function testWrapWordsToLines(prefix: string | number | undefined): void { + describe(`with prefix="${prefix}"`, () => { + it('respects spaces and newlines in a pre-formatted message', () => { + const userMessage: string = [ + 'An error occurred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(userMessage, 50, prefix); + expect(result).toMatchSnapshot(); + }); + + it('handles a line starting with a word longer than the max line length', () => { + const userMessage: string = [ + 'Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn error occurred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(userMessage, 50, prefix); + expect(result).toMatchSnapshot(); + }); + + it('handles a line containing a word longer than the max line length', () => { + const userMessage: string = [ + 'An error occurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(userMessage, 50, prefix); + expect(result).toMatchSnapshot(); + }); + + it('handles a line starting with two words longer than the max line length', () => { + const userMessage: string = [ + 'Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn errrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrror occurred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(userMessage, 50, prefix); + expect(result).toMatchSnapshot(); + }); + + it('handles a line with only a word longer than the max line length', () => { + const userMessage: string = ['Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(userMessage, 50, prefix); + expect(result).toMatchSnapshot(); + }); + + it('applies pre-existing indents on both margins', () => { + const message: string = [ + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.', + '', + ' Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.', + '', + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.' + ].join('\n'); + + const result: string[] = PrintUtilities.wrapWordsToLines(message, 50, prefix); + expect(result).toMatchSnapshot(); + }); + }); + } + + describe(PrintUtilities.wrapWordsToLines.name, () => { + testWrapWordsToLines(undefined); + testWrapWordsToLines(4); + testWrapWordsToLines('| '); + }); + + describe(PrintUtilities.printMessageInBox.name, () => { + function validateOutput(expectedWidth: number): void { + const outputLines: string[] = terminalProvider + .getOutput({ normalizeSpecialCharacters: true }) + .split('[n]'); + expect(outputLines).toMatchSnapshot(); + + expect(outputLines.every((x) => x.length <= expectedWidth)); + } + + const MESSAGE: string = + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.'; + + it('prints a long message wrapped in narrow box', () => { + PrintUtilities.printMessageInBox(MESSAGE, terminal, 20); + validateOutput(20); + }); + + it('prints a long message wrapped in a wide box', () => { + PrintUtilities.printMessageInBox(MESSAGE, terminal, 300); + validateOutput(300); + }); + + it('prints a long message wrapped in a box using the console width', () => { + jest.spyOn(PrintUtilities, 'getConsoleWidth').mockReturnValue(65); + + PrintUtilities.printMessageInBox(MESSAGE, terminal); + validateOutput(32); + }); + + it('respects spaces and newlines in a pre-formatted message', () => { + const userMessage: string = [ + 'An error occurred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + PrintUtilities.printMessageInBox(userMessage, terminal, 50); + validateOutput(50); + }); + + it('Handles a case where there is a word longer than the boxwidth', () => { + const userMessage: string = [ + 'Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn error occurred while pushing commits to git remote. Please make sure you have installed and enabled git lfs. The easiest way to do that is run the provided setup script:', + '', + ' common/scripts/setup.sh', + '' + ].join('\n'); + + PrintUtilities.printMessageInBox(userMessage, terminal, 50); + validateOutput(50); + }); + + it('word-wraps a message with a trailing fragment', () => { + const lines: string[] = PrintUtilities.wrapWordsToLines( + 'This Thursday, we will complete the Node.js version upgrade. Any pipelines that still have not upgraded will be temporarily disabled.', + 36 + ); + expect(lines).toMatchInlineSnapshot(` +Array [ + "This Thursday, we will complete the", + "Node.js version upgrade. Any", + "pipelines that still have not", + "upgraded will be temporarily", + "disabled.", +] +`); + + for (const line of lines) { + expect(line.length).toBeLessThanOrEqual(36); + } + }); + }); +}); diff --git a/libraries/terminal/src/test/ProblemCollector.test.ts b/libraries/terminal/src/test/ProblemCollector.test.ts new file mode 100644 index 00000000000..363080df07c --- /dev/null +++ b/libraries/terminal/src/test/ProblemCollector.test.ts @@ -0,0 +1,347 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ProblemCollector } from '../ProblemCollector'; +import { + parseProblemMatchersJson, + type IProblemMatcher, + type IProblem, + type IProblemMatcherJson +} from '@rushstack/problem-matcher/lib/ProblemMatcher'; +import { TerminalChunkKind } from '../ITerminalChunk'; + +class ErrorLineMatcher implements IProblemMatcher { + public readonly name: string = 'errorLine'; + private readonly _regex: RegExp = /^ERROR:\s*(.*)\n$/; + public exec(line: string): IProblem | false { + const match: RegExpExecArray | null = this._regex.exec(line); + if (match) { + return { + matcherName: this.name, + message: match[1], + severity: 'error' + }; + } + return false; + } +} + +describe('ProblemCollector', () => { + it('collects a simple error line', () => { + const onProblemSpy = jest.fn(); + const collector: ProblemCollector = new ProblemCollector({ + matchers: [new ErrorLineMatcher()], + onProblem: onProblemSpy + }); + + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'hello world\n' }); + collector.writeChunk({ + kind: TerminalChunkKind.Stdout, + text: 'ERROR: something bad happened in stdout\n' + }); + collector.writeChunk({ + kind: TerminalChunkKind.Stderr, + text: 'ERROR: something bad happened in stderr\n' + }); + collector.close(); + + const { problems } = collector; + expect(problems.size).toBe(2); + expect(onProblemSpy).toHaveBeenCalledTimes(2); + expect(onProblemSpy).toHaveBeenNthCalledWith(1, { + matcherName: 'errorLine', + message: 'something bad happened in stdout', + severity: 'error' + }); + expect(onProblemSpy).toHaveBeenNthCalledWith(2, { + matcherName: 'errorLine', + message: 'something bad happened in stderr', + severity: 'error' + }); + }); +}); + +describe('VSCodeProblemMatcherAdapter - additional location formats', () => { + it('parses a location group like "line,column" in a single group', () => { + const matcherPattern = { + name: 'loc-group', + pattern: { + // Example: src/file.ts(10,5): message + // NOTE: Escape \\d so the RegExp sees the digit character class + regexp: '^(.*)\\((\\d+,\\d+)\\): (.*)$', + file: 1, + location: 2, + message: 3 + } + } satisfies IProblemMatcherJson; + + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'src/a.c(10,5): something happened\n' }); + collector.close(); + const { problems } = collector; + expect(problems.size).toBe(1); + expect(onProblemSpy).toHaveBeenCalledTimes(1); + expect(onProblemSpy).toHaveBeenNthCalledWith(1, { + matcherName: 'loc-group', + file: 'src/a.c', + line: 10, + column: 5, + message: 'something happened', + code: undefined, + endColumn: undefined, + endLine: undefined, + severity: undefined + } satisfies IProblem); + }); + + it('parses explicit endLine and endColumn groups', () => { + const matcherPattern = { + name: 'end-range', + pattern: { + // Example: file(10,5,12,20): message + regexp: '^(.*)\\((\\d+),(\\d+),(\\d+),(\\d+)\\): (.*)$', + file: 1, + // We intentionally do NOT use "location" here; use explicit groups + line: 2, + column: 3, + endLine: 4, + endColumn: 5, + message: 6 + } + } satisfies IProblemMatcherJson; + + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'lib/x.c(10,5,12,20): multi-line issue\n' }); + collector.close(); + const { problems } = collector; + expect(problems.size).toBe(1); + expect(onProblemSpy).toHaveBeenCalledTimes(1); + expect(onProblemSpy).toHaveBeenNthCalledWith(1, { + matcherName: 'end-range', + file: 'lib/x.c', + line: 10, + column: 5, + endLine: 12, + endColumn: 20, + message: 'multi-line issue', + code: undefined, + severity: undefined + } satisfies IProblem); + }); +}); + +describe('VSCodeProblemMatcherAdapter', () => { + it('converts and matches a single-line pattern', () => { + const matcherPattern = { + name: 'tsc-like', + pattern: { + // Example: src/file.ts(10,5): error TS1005: ';' expected + regexp: '^(.*)\\((\\d+),(\\d+)\\): (error|warning) (TS\\d+): (.*)$', + file: 1, + line: 2, + column: 3, + severity: 4, + code: 5, + message: 6 + } + } satisfies IProblemMatcherJson; + + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + collector.writeChunk({ + kind: TerminalChunkKind.Stderr, + text: "src/file.ts(10,5): error TS1005: ' ; ' expected\n" + }); + collector.close(); + const { problems } = collector; + expect(problems.size).toBe(1); + expect(onProblemSpy).toHaveBeenCalledTimes(1); + expect(onProblemSpy).toHaveBeenNthCalledWith(1, { + matcherName: 'tsc-like', + file: 'src/file.ts', + line: 10, + column: 5, + code: 'TS1005', + severity: 'error', + message: "' ; ' expected", + endColumn: undefined, + endLine: undefined + } satisfies IProblem); + }); + + it('converts and matches a multi-line pattern', () => { + const matcherPattern = { + name: 'multi', + pattern: [ + { + // First line: File path + regexp: '^In file (.*)$', + file: 1, + message: 1 // placeholder, will collect below as well + }, + { + // Second line: location + regexp: '^Line (\\d+), Col (\\d+)$', + line: 1, + column: 2, + message: 1 + }, + { + // Third line: severity and message + regexp: '^(error|warning): (.*)$', + severity: 1, + message: 2 + } + ] + } satisfies IProblemMatcherJson; + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'In file src/foo.c\n' }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'Line 42, Col 7\n' }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'error: something bad happened\n' }); + collector.close(); + const { problems } = collector; + expect(problems.size).toBe(1); + expect(onProblemSpy).toHaveBeenCalledTimes(1); + expect(onProblemSpy).toHaveBeenNthCalledWith(1, { + matcherName: 'multi', + file: 'src/foo.c', + line: 42, + column: 7, + severity: 'error', + message: 'something bad happened', + code: undefined, + endColumn: undefined, + endLine: undefined + } satisfies IProblem); + }); + + it('handles a multi-line pattern whose last pattern loops producing multiple problems', () => { + // Simulate a tool summary line followed by multiple TypeScript style error lines. + // The last pattern uses `loop: true` so each subsequent matching line yields a problem. + const matcherPattern = { + name: 'ts-loop-errors', + severity: 'error', + pattern: [ + { + // Summary line: Encountered 6 errors + regexp: '^Encountered (\\d+) errors$', + // Must supply a message group per interface; we capture the count but don't rely on it. + message: 1 + }, + { + // Error detail lines (one per problem): + // [build:typescript] path/to/file.ts:9:3 - (TS2578) Message text + regexp: '^\\s+\\[build:typescript\\]\\s+(.*):(\\d+):(\\d+) - \\((TS\\d+)\\) (.*)$', + file: 1, + line: 2, + column: 3, + code: 4, + message: 5, + loop: true + } + ] + } satisfies IProblemMatcherJson; + + const errorLines: string[] = [ + 'Encountered 6 errors', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:9:3 - (TS2578) Unused @ts-expect-error directive 1.', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:11:3 - (TS2578) Unused @ts-expect-error directive 2.', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:19:3 - (TS2578) Unused @ts-expect-error directive 3.', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:24:3 - (TS2578) Unused @ts-expect-error directive 4.', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:26:3 - (TS2578) Unused @ts-expect-error directive 5.', + ' [build:typescript] vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts:34:3 - (TS2578) Unused @ts-expect-error directive 6.' + ]; + + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + for (const line of errorLines) { + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: line + '\n' }); + } + collector.close(); + + const { problems } = collector; + expect(problems.size).toBe(6); + expect(onProblemSpy).toHaveBeenCalledTimes(6); + + const problemLineNumbers: number[] = [9, 11, 19, 24, 26, 34]; + for (let i = 0; i < 6; i++) { + expect(onProblemSpy).toHaveBeenNthCalledWith(i + 1, { + matcherName: 'ts-loop-errors', + file: 'vscode-extensions/debug-certificate-manager-vscode-extension/src/certificates.ts', + line: problemLineNumbers[i], + column: 3, + code: 'TS2578', + severity: 'error', + message: `Unused @ts-expect-error directive ${i + 1}.`, + endColumn: undefined, + endLine: undefined + } satisfies IProblem); + } + }); + + it('handles looped pattern with per-line severity token', () => { + const matcherPattern = { + name: 'loop-with-severity', + pattern: [ + { + regexp: '^Start Problems$', + message: 0 // we will just push empty placeholder + }, + { + // e.g. "Error path/file.ts(10,5): code123: Something happened" + regexp: '^(Error|Warning|Info) (.*)\\((\\d+),(\\d+)\\): (\\w+): (.*)$', + severity: 1, // E -> error, W -> warning (normalization should map) + file: 2, + line: 3, + column: 4, + code: 5, + message: 6, + loop: true + } + ] + } satisfies IProblemMatcherJson; + + const lines = [ + 'Error lib/a.ts(10,5): CODE100: First thing', + 'Warning lib/b.ts(20,1): CODE200: Second thing', + 'Error lib/c.ts(30,9): CODE300: Third thing', + 'Info lib/d.ts(40,2): CODE400: Fourth thing' + ]; + + const matchers = parseProblemMatchersJson([matcherPattern]); + const onProblemSpy = jest.fn(); + const collector = new ProblemCollector({ matchers, onProblem: onProblemSpy }); + collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: 'Start Problems\n' }); + for (const l of lines) collector.writeChunk({ kind: TerminalChunkKind.Stdout, text: l + '\n' }); + collector.close(); + const { problems } = collector; + expect(problems.size).toBe(4); + expect(onProblemSpy).toHaveBeenCalledTimes(4); + + const problemCodes: string[] = ['CODE100', 'CODE200', 'CODE300', 'CODE400']; + const problemColumns: number[] = [5, 1, 9, 2]; + const problemSeverities: ('error' | 'warning' | 'info')[] = ['error', 'warning', 'error', 'info']; + const problemMessages: string[] = ['First thing', 'Second thing', 'Third thing', 'Fourth thing']; + for (let i = 0; i < 4; i++) { + expect(onProblemSpy).toHaveBeenNthCalledWith(i + 1, { + matcherName: 'loop-with-severity', + file: `lib/${String.fromCharCode('a'.charCodeAt(0) + i)}.ts`, + line: (i + 1) * 10, + column: problemColumns[i], + code: problemCodes[i], + severity: problemSeverities[i], + message: problemMessages[i], + endColumn: undefined, + endLine: undefined + } satisfies IProblem); + } + }); +}); diff --git a/libraries/terminal/src/test/RemoveColorsTextRewriter.test.ts b/libraries/terminal/src/test/RemoveColorsTextRewriter.test.ts new file mode 100644 index 00000000000..ba3a789f17b --- /dev/null +++ b/libraries/terminal/src/test/RemoveColorsTextRewriter.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 { AnsiEscape } from '../AnsiEscape'; +import { Colorize } from '../Colorize'; + +import { RemoveColorsTextRewriter } from '../RemoveColorsTextRewriter'; +import type { TextRewriterState } from '../TextRewriter'; + +function testCase(inputs: string[]): void { + const matcher: RemoveColorsTextRewriter = new RemoveColorsTextRewriter(); + const state: TextRewriterState = matcher.initialize(); + const outputs: string[] = inputs.map((x) => matcher.process(state, x)); + const closeOutput: string = matcher.close(state); + if (closeOutput !== '') { + outputs.push('--close--'); + outputs.push(closeOutput); + } + + expect({ + inputs: inputs.map((x) => AnsiEscape.formatForTests(x)), + outputs + }).toMatchSnapshot(); +} + +describe(RemoveColorsTextRewriter.name, () => { + it('01 should process empty inputs', () => { + testCase([]); + testCase(['']); + testCase(['', 'a', '']); + }); + + it('02 should remove colors from complete chunks', () => { + testCase([Colorize.red('1')]); + testCase([Colorize.red('1') + Colorize.green('2')]); + testCase([Colorize.red('1') + '2' + Colorize.green('3')]); + }); + + it('03 should remove colors from 1-character chunks', () => { + const source: string = '1' + Colorize.red('2'); + const inputs: string[] = []; + for (let i: number = 0; i < source.length; ++i) { + inputs.push(source.substr(i, 1)); + } + testCase(inputs); + }); + + it('04 should pass through incomplete partial matches', () => { + testCase(['\x1b']); + testCase(['\x1b[\n']); + testCase(['\x1b[1']); + }); +}); diff --git a/libraries/terminal/src/test/SplitterTransform.test.ts b/libraries/terminal/src/test/SplitterTransform.test.ts new file mode 100644 index 00000000000..046bc86203c --- /dev/null +++ b/libraries/terminal/src/test/SplitterTransform.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 { SplitterTransform } from '../SplitterTransform'; +import { MockWritable } from '../MockWritable'; +import { TerminalChunkKind, type ITerminalChunk } from '../ITerminalChunk'; + +// Helper to create chunks succinctly +function c(text: string, kind: TerminalChunkKind = TerminalChunkKind.Stdout): ITerminalChunk { + return { text, kind }; +} + +describe(SplitterTransform.name, () => { + it('writes chunks to all initial destinations', () => { + const a: MockWritable = new MockWritable(); + const b: MockWritable = new MockWritable(); + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a, b] }); + + splitter.writeChunk(c('one ')); + splitter.writeChunk(c('two ', TerminalChunkKind.Stderr)); + splitter.writeChunk(c('three')); + splitter.close(); + + // Both received identical chunk sequences + expect(a.chunks).toEqual(b.chunks); + // And each chunk reference should be the exact same object instance across destinations + expect(a.chunks[0]).toBe(b.chunks[0]); + expect(a.chunks[1]).toBe(b.chunks[1]); + expect(a.chunks[2]).toBe(b.chunks[2]); + + expect(a.getFormattedChunks()).toMatchSnapshot(); + }); + + describe(SplitterTransform.prototype.addDestination.name, () => { + it('only receives subsequent chunks', () => { + const a: MockWritable = new MockWritable(); + const b: MockWritable = new MockWritable(); + const late: MockWritable = new MockWritable(); + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a, b] }); + + splitter.writeChunk(c('early1 ')); + splitter.writeChunk(c('early2 ')); + + splitter.addDestination(late); + + splitter.writeChunk(c('late1 ')); + splitter.writeChunk(c('late2')); + splitter.close(); + + expect(a.getAllOutput()).toBe('early1 early2 late1 late2'); + expect(b.getAllOutput()).toBe('early1 early2 late1 late2'); + expect(late.getAllOutput()).toBe('late1 late2'); + + expect({ + a: a.getFormattedChunks(), + late: late.getFormattedChunks() + }).toMatchSnapshot(); + }); + }); + + describe(SplitterTransform.prototype.removeDestination.name, () => { + it('stops further writes and closes by default', () => { + class CloseTrackingWritable extends MockWritable { + public closed: boolean = false; + protected onClose(): void { + this.closed = true; + } + } + + const a: CloseTrackingWritable = new CloseTrackingWritable(); + const b: CloseTrackingWritable = new CloseTrackingWritable(); + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a, b] }); + + splitter.writeChunk(c('first ')); + splitter.removeDestination(b); // default close=true + + splitter.writeChunk(c('second')); + splitter.close(); + + // b should not have received 'second' + expect(a.getAllOutput()).toBe('first second'); + expect(b.getAllOutput()).toBe('first '); + expect(b.closed).toBe(true); + expect(a.closed).toBe(true); // closed when splitter closed + + expect({ a: a.getFormattedChunks(), b: b.getFormattedChunks() }).toMatchSnapshot(); + }); + + it('with close=false keeps destination open', () => { + class CloseTrackingWritable extends MockWritable { + public closed: boolean = false; + protected onClose(): void { + this.closed = true; + } + } + + const a: CloseTrackingWritable = new CloseTrackingWritable(); + const b: CloseTrackingWritable = new CloseTrackingWritable(); + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a, b] }); + + splitter.writeChunk(c('first ')); + splitter.removeDestination(b, false); // do not close + + splitter.writeChunk(c('second')); + splitter.close(); + + expect(b.closed).toBe(false); // still open since not auto-closed by splitter and removed + // Manually close to avoid resource leak semantics + b.close(); + expect(b.closed).toBe(true); + + expect({ a: a.getFormattedChunks(), b: b.getFormattedChunks() }).toMatchSnapshot(); + }); + + it('respects preventAutoclose', () => { + class CloseTrackingWritable extends MockWritable { + public closed: boolean = false; + public constructor(prevent: boolean) { + super({ preventAutoclose: prevent }); + } + protected onClose(): void { + this.closed = true; + } + } + + const a: CloseTrackingWritable = new CloseTrackingWritable(false); + const b: CloseTrackingWritable = new CloseTrackingWritable(true); // preventAutoclose + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a, b] }); + + splitter.writeChunk(c('hello ')); + splitter.removeDestination(b); // would normally close, but preventAutoclose=true + splitter.writeChunk(c('world')); + splitter.close(); + + expect(a.closed).toBe(true); + expect(b.closed).toBe(false); // not closed due to preventAutoclose + b.close(); + expect(b.closed).toBe(true); + + expect({ a: a.getFormattedChunks(), b: b.getFormattedChunks() }).toMatchSnapshot(); + }); + + it('returns false when destination missing', () => { + const a: MockWritable = new MockWritable(); + const b: MockWritable = new MockWritable(); + const splitter: SplitterTransform = new SplitterTransform({ destinations: [a] }); + + const result: boolean = splitter.removeDestination(b); // not found + expect(result).toBe(false); + + splitter.writeChunk(c('still works')); + splitter.close(); + + expect(a.getAllOutput()).toBe('still works'); + }); + }); +}); diff --git a/libraries/terminal/src/test/StdioLineTransform.test.ts b/libraries/terminal/src/test/StdioLineTransform.test.ts new file mode 100644 index 00000000000..0ace1b3fdf6 --- /dev/null +++ b/libraries/terminal/src/test/StdioLineTransform.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 { TerminalChunkKind } from '../ITerminalChunk'; +import { StderrLineTransform } from '../StdioLineTransform'; +import { MockWritable } from '../MockWritable'; + +describe(StderrLineTransform.name, () => { + it('should report stdout if there is no stderr', () => { + const mockWritable: MockWritable = new MockWritable(); + const transform: StderrLineTransform = new StderrLineTransform({ destination: mockWritable }); + + transform.writeChunk({ text: 'stdout 1\nstdout 2\n', kind: TerminalChunkKind.Stdout }); + transform.close(); + + expect(mockWritable.chunks).toMatchSnapshot(); + }); +}); diff --git a/libraries/terminal/src/test/StdioSummarizer.test.ts b/libraries/terminal/src/test/StdioSummarizer.test.ts new file mode 100644 index 00000000000..3555647304d --- /dev/null +++ b/libraries/terminal/src/test/StdioSummarizer.test.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TerminalChunkKind } from '../ITerminalChunk'; +import { StdioSummarizer } from '../StdioSummarizer'; +import { StderrLineTransform } from '../StdioLineTransform'; +import { TextRewriterTransform } from '../TextRewriterTransform'; +import { NewlineKind } from '@rushstack/node-core-library'; + +describe(StdioSummarizer.name, () => { + let summarizer: StdioSummarizer; + let stderrLineTransform: StderrLineTransform; + let transform: TextRewriterTransform; + + beforeEach(() => { + summarizer = new StdioSummarizer(); + stderrLineTransform = new StderrLineTransform({ destination: summarizer }); + transform = new TextRewriterTransform({ + destination: stderrLineTransform, + normalizeNewlines: NewlineKind.Lf + }); + }); + + it('should report stdout if there is no stderr', () => { + transform.writeChunk({ text: 'stdout 1\nstdout 2\n', kind: TerminalChunkKind.Stdout }); + transform.close(); + + expect(summarizer.isOpen).toBe(false); + expect(summarizer.getReport()).toMatchSnapshot(); + }); + + it('should abridge extra lines', () => { + transform.writeChunk({ text: 'discarded stdout\n', kind: TerminalChunkKind.Stdout }); + for (let i: number = 0; i < 10; ++i) { + transform.writeChunk({ text: `leading ${i}\n`, kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: 'discarded stdout\n', kind: TerminalChunkKind.Stdout }); + } + + transform.writeChunk({ text: `discarded middle 1\n`, kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: `discarded middle 2\n`, kind: TerminalChunkKind.Stderr }); + + for (let i: number = 0; i < 10; ++i) { + transform.writeChunk({ text: `trailing ${i}\n`, kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: 'discarded stdout\n', kind: TerminalChunkKind.Stdout }); + } + + transform.close(); + + expect(summarizer.getReport()).toMatchSnapshot(); + }); + + it('should concatenate partial lines', () => { + transform.writeChunk({ text: 'abc', kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: '', kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: 'de\nf\n\ng', kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: '\n', kind: TerminalChunkKind.Stderr }); + transform.writeChunk({ text: 'h', kind: TerminalChunkKind.Stderr }); + transform.close(); + + expect(summarizer.getReport()).toMatchSnapshot(); + }); +}); diff --git a/libraries/terminal/src/test/Terminal.test.ts b/libraries/terminal/src/test/Terminal.test.ts new file mode 100644 index 00000000000..903432963df --- /dev/null +++ b/libraries/terminal/src/test/Terminal.test.ts @@ -0,0 +1,911 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Terminal } from '../Terminal'; +import { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; +import { Colorize } from '../Colorize'; + +describe(Terminal.name, () => { + let terminal: Terminal; + let provider: StringBufferTerminalProvider; + + function verifyProvider(): void { + expect({ + log: provider.getOutput(), + warning: provider.getWarningOutput(), + error: provider.getErrorOutput(), + verbose: provider.getVerboseOutput(), + debug: provider.getDebugOutput() + }).toMatchSnapshot(); + } + + describe('01 color enabled', () => { + beforeEach(() => { + provider = new StringBufferTerminalProvider(true); + terminal = new Terminal(provider); + }); + + describe('01 basic terminal functions', () => { + describe('01 write', () => { + it('01 writes a single message', () => { + terminal.write('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.write('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.write(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.write(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4'), { + doNotOverrideSgrCodes: true + }); + verifyProvider(); + }); + }); + + describe('02 writeLine', () => { + it('01 writes a single message', () => { + terminal.writeLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('03 writeWarning', () => { + it('01 writes a single message', () => { + terminal.writeWarning('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeWarning('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeWarning(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeWarning(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeWarning( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeWarning( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('04 writeWarningLine', () => { + it('01 writes a single message', () => { + terminal.writeWarningLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeWarningLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeWarningLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeWarningLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('05 writeError', () => { + it('01 writes a single message', () => { + terminal.writeError('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeError('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeError(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeError(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeError( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeError( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('06 writeErrorLine', () => { + it('01 writes a single message', () => { + terminal.writeErrorLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeErrorLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeErrorLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeErrorLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('07 writeVerbose', () => { + it('01 writes a single message', () => { + terminal.writeVerbose('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeVerbose('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeVerbose(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeVerbose(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeVerbose( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeVerbose( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('08 writeVerboseLine', () => { + it('01 writes a single message', () => { + terminal.writeVerboseLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeVerboseLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeVerboseLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeVerboseLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + }); + + it('05 writes to multiple streams', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeWarningLine('message 1', 'message 2'); + terminal.writeVerbose('test message'); + terminal.writeVerbose(Colorize.green('message 1')); + terminal.writeLine(Colorize.green('message 1')); + terminal.writeError('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeErrorLine('test message'); + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.writeVerboseLine('test message'); + terminal.writeWarning(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarning('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeError('message 1', 'message 2'); + terminal.write(Colorize.green('message 1')); + terminal.writeVerbose('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeErrorLine('message 1', 'message 2'); + terminal.write(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeVerbose('message 1', 'message 2'); + terminal.writeVerboseLine(Colorize.green('message 1')); + terminal.writeLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeError(Colorize.green('message 1')); + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.write('test message'); + terminal.writeWarningLine('test message'); + terminal.writeVerboseLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeVerboseLine('message 1', 'message 2'); + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.writeLine('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeWarning('message 1', 'message 2'); + terminal.writeErrorLine(Colorize.green('message 1')); + terminal.write('message 1', 'message 2'); + terminal.writeVerbose(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarning(Colorize.green('message 1')); + terminal.writeLine('test message'); + terminal.writeError('test message'); + terminal.writeLine('message 1', 'message 2'); + terminal.writeErrorLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeError(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarningLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarningLine(Colorize.green('message 1')); + verifyProvider(); + }); + }); + + describe('02 color disabled', () => { + beforeEach(() => { + provider = new StringBufferTerminalProvider(false); + terminal = new Terminal(provider); + }); + + describe('01 basic terminal functions', () => { + describe('01 write', () => { + it('01 writes a single message', () => { + terminal.write('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.write('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.write(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.write(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4'), { + doNotOverrideSgrCodes: true + }); + verifyProvider(); + }); + }); + + describe('02 writeLine', () => { + it('01 writes a single message', () => { + terminal.writeLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('03 writeWarning', () => { + it('01 writes a single message', () => { + terminal.writeWarning('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeWarning('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeWarning(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeWarning(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeWarning( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeWarning( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('04 writeWarningLine', () => { + it('01 writes a single message', () => { + terminal.writeWarningLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeWarningLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeWarningLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeWarningLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('05 writeError', () => { + it('01 writes a single message', () => { + terminal.writeError('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeError('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeError(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeError(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeError( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeError( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('06 writeErrorLine', () => { + it('01 writes a single message', () => { + terminal.writeErrorLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeErrorLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeErrorLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeErrorLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('07 writeVerbose', () => { + it('01 writes a single message', () => { + terminal.writeVerbose('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeVerbose('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeVerbose(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeVerbose(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeVerbose( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeVerbose( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('08 writeVerboseLine', () => { + it('01 writes a single message', () => { + terminal.writeVerboseLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeVerboseLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeVerboseLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeVerboseLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('09 writeDebug', () => { + it('01 writes a single message', () => { + terminal.writeDebug('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeDebug('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeDebug(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeDebug(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeDebug( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeDebug( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + + describe('10 writeDebugLine', () => { + it('01 writes a single message', () => { + terminal.writeDebugLine('test message'); + verifyProvider(); + }); + + it('02 writes multiple messages', () => { + terminal.writeDebugLine('message 1', 'message 2'); + verifyProvider(); + }); + + it('03 writes a message with colors', () => { + terminal.writeDebugLine(Colorize.green('message 1')); + verifyProvider(); + }); + + it('04 writes a multiple messages with colors', () => { + terminal.writeDebugLine(Colorize.green('message 1'), Colorize.red('message 2')); + verifyProvider(); + }); + + it('05 writes a messages with colors interspersed with non-colored messages', () => { + terminal.writeDebugLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + verifyProvider(); + }); + + it('06 writes a messages with colors interspersed with non-colored messages with color overriding disabled', () => { + terminal.writeDebugLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4'), + { doNotOverrideSgrCodes: true } + ); + verifyProvider(); + }); + }); + }); + + it('05 writes to multiple streams', () => { + terminal.write('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeWarningLine('message 1', 'message 2'); + terminal.writeVerbose('test message'); + terminal.writeVerbose(Colorize.green('message 1')); + terminal.writeLine(Colorize.green('message 1')); + terminal.writeError('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeErrorLine('test message'); + terminal.writeVerboseLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.writeVerboseLine('test message'); + terminal.writeWarning(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarning('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeError('message 1', 'message 2'); + terminal.write(Colorize.green('message 1')); + terminal.writeVerbose('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeErrorLine('message 1', 'message 2'); + terminal.write(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeVerbose('message 1', 'message 2'); + terminal.writeVerboseLine(Colorize.green('message 1')); + terminal.writeLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeError(Colorize.green('message 1')); + terminal.writeWarningLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.write('test message'); + terminal.writeWarningLine('test message'); + terminal.writeVerboseLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeVerboseLine('message 1', 'message 2'); + terminal.writeErrorLine( + 'message 1', + Colorize.green('message 2'), + 'message 3', + Colorize.red('message 4') + ); + terminal.writeLine('message 1', Colorize.green('message 2'), 'message 3', Colorize.red('message 4')); + terminal.writeWarning('message 1', 'message 2'); + terminal.writeErrorLine(Colorize.green('message 1')); + terminal.write('message 1', 'message 2'); + terminal.writeVerbose(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarning(Colorize.green('message 1')); + terminal.writeLine('test message'); + terminal.writeError('test message'); + terminal.writeLine('message 1', 'message 2'); + terminal.writeErrorLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeError(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarningLine(Colorize.green('message 1'), Colorize.red('message 2')); + terminal.writeWarningLine(Colorize.green('message 1')); + verifyProvider(); + }); + }); +}); diff --git a/libraries/terminal/src/test/TerminalStreamWritable.test.ts b/libraries/terminal/src/test/TerminalStreamWritable.test.ts new file mode 100644 index 00000000000..a44a4150fde --- /dev/null +++ b/libraries/terminal/src/test/TerminalStreamWritable.test.ts @@ -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. + +import { Terminal } from '../Terminal'; +import { StringBufferTerminalProvider } from '../StringBufferTerminalProvider'; +import { TerminalStreamWritable } from '../TerminalStreamWritable'; +import { TerminalProviderSeverity } from '../ITerminalProvider'; +import type { Writable } from 'node:stream'; + +let terminal: Terminal; +let provider: StringBufferTerminalProvider; + +function verifyProvider(): void { + expect({ + log: provider.getOutput(), + warning: provider.getWarningOutput(), + error: provider.getErrorOutput(), + verbose: provider.getVerboseOutput(), + debug: provider.getDebugOutput() + }).toMatchSnapshot(); +} + +async function writeAsync(writable: Writable, data: string): Promise { + await new Promise((resolve: () => void, reject: (error: Error) => void) => { + writable.write(data, (error?: Error | null) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); +} + +describe(TerminalStreamWritable.name, () => { + beforeEach(() => { + provider = new StringBufferTerminalProvider(true); + terminal = new Terminal(provider); + }); + + test('writes a message', async () => { + const writable: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.log + }); + + await writeAsync(writable, 'test message'); + verifyProvider(); + }); + + test('writes a verbose message', async () => { + const writable: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.verbose + }); + + await writeAsync(writable, 'test message'); + verifyProvider(); + }); + + test('writes a debug message', async () => { + const writable: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.debug + }); + + await writeAsync(writable, 'test message'); + verifyProvider(); + }); + + test('writes a warning message', async () => { + const writable: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.warning + }); + + await writeAsync(writable, 'test message'); + verifyProvider(); + }); + + test('writes an error message', async () => { + const writable: TerminalStreamWritable = new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.error + }); + + await writeAsync(writable, 'test message'); + verifyProvider(); + }); +}); diff --git a/libraries/terminal/src/test/TextRewriterTransform.test.ts b/libraries/terminal/src/test/TextRewriterTransform.test.ts new file mode 100644 index 00000000000..583cf70316d --- /dev/null +++ b/libraries/terminal/src/test/TextRewriterTransform.test.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 { NewlineKind, Text } from '@rushstack/node-core-library'; + +import { Colorize } from '../Colorize'; +import { TerminalChunkKind } from '../ITerminalChunk'; +import { MockWritable } from '../MockWritable'; +import { TextRewriterTransform } from '../TextRewriterTransform'; + +describe(TextRewriterTransform.name, () => { + it('should apply standard rewriters', () => { + const mockWritable: MockWritable = new MockWritable(); + const transform: TextRewriterTransform = new TextRewriterTransform({ + destination: mockWritable, + removeColors: true, + ensureNewlineAtEnd: true, + normalizeNewlines: NewlineKind.Lf + }); + + // This color code will be removed + transform.writeChunk({ text: Colorize.red('RED'), kind: TerminalChunkKind.Stderr }); + // These newlines will be converted to \n + transform.writeChunk({ text: 'stderr 1\r\nstderr 2\r\n', kind: TerminalChunkKind.Stderr }); + + // The incomplete color code will be passed through + // The incomplete line will have \n appended + transform.writeChunk({ text: 'stdout 3\r\nstdout 4\x1b[1', kind: TerminalChunkKind.Stdout }); + + transform.close(); + + expect( + mockWritable.chunks.map((x) => ({ + kind: x.kind, + text: Text.replaceAll(x.text, '\n', '[n]') + })) + ).toMatchSnapshot(); + }); +}); diff --git a/libraries/terminal/src/test/__snapshots__/Colorize.test.ts.snap b/libraries/terminal/src/test/__snapshots__/Colorize.test.ts.snap new file mode 100644 index 00000000000..00a6cc10b10 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/Colorize.test.ts.snap @@ -0,0 +1,199 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Colorize generates codes as expected: black 1`] = `"x"`; + +exports[`Colorize generates codes as expected: blackBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: blink 1`] = `"x"`; + +exports[`Colorize generates codes as expected: blue 1`] = `"x"`; + +exports[`Colorize generates codes as expected: blueBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: bold 1`] = `"x"`; + +exports[`Colorize generates codes as expected: cyan 1`] = `"x"`; + +exports[`Colorize generates codes as expected: cyanBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: dim 1`] = `"x"`; + +exports[`Colorize generates codes as expected: gray 1`] = `"x"`; + +exports[`Colorize generates codes as expected: grayBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: green 1`] = `"x"`; + +exports[`Colorize generates codes as expected: greenBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: hidden 1`] = `"x"`; + +exports[`Colorize generates codes as expected: invertColor 1`] = `"x"`; + +exports[`Colorize generates codes as expected: magenta 1`] = `"x"`; + +exports[`Colorize generates codes as expected: magentaBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: red 1`] = `"x"`; + +exports[`Colorize generates codes as expected: redBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: underline 1`] = `"x"`; + +exports[`Colorize generates codes as expected: white 1`] = `"x"`; + +exports[`Colorize generates codes as expected: whiteBackground 1`] = `"x"`; + +exports[`Colorize generates codes as expected: yellow 1`] = `"x"`; + +exports[`Colorize generates codes as expected: yellowBackground 1`] = `"x"`; + +exports[`Colorize writes color grid correctly: line 0 1`] = ` +Array [ + "X", + "[black]X[default]", + "[white]X[default]", + "[gray]X[default]", + "[magenta]X[default]", + "[red]X[default]", + "[yellow]X[default]", + "[green]X[default]", + "[cyan]X[default]", + "[blue]X[default]", +] +`; + +exports[`Colorize writes color grid correctly: line 1 1`] = ` +Array [ + "[black-bg]X[default-bg]", + "[black-bg][black]X[default][default-bg]", + "[black-bg][white]X[default][default-bg]", + "[black-bg][gray]X[default][default-bg]", + "[black-bg][magenta]X[default][default-bg]", + "[black-bg][red]X[default][default-bg]", + "[black-bg][yellow]X[default][default-bg]", + "[black-bg][green]X[default][default-bg]", + "[black-bg][cyan]X[default][default-bg]", + "[black-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 2 1`] = ` +Array [ + "[white-bg]X[default-bg]", + "[white-bg][black]X[default][default-bg]", + "[white-bg][white]X[default][default-bg]", + "[white-bg][gray]X[default][default-bg]", + "[white-bg][magenta]X[default][default-bg]", + "[white-bg][red]X[default][default-bg]", + "[white-bg][yellow]X[default][default-bg]", + "[white-bg][green]X[default][default-bg]", + "[white-bg][cyan]X[default][default-bg]", + "[white-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 3 1`] = ` +Array [ + "[gray-bg]X[default-bg]", + "[gray-bg][black]X[default][default-bg]", + "[gray-bg][white]X[default][default-bg]", + "[gray-bg][gray]X[default][default-bg]", + "[gray-bg][magenta]X[default][default-bg]", + "[gray-bg][red]X[default][default-bg]", + "[gray-bg][yellow]X[default][default-bg]", + "[gray-bg][green]X[default][default-bg]", + "[gray-bg][cyan]X[default][default-bg]", + "[gray-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 4 1`] = ` +Array [ + "[magenta-bg]X[default-bg]", + "[magenta-bg][black]X[default][default-bg]", + "[magenta-bg][white]X[default][default-bg]", + "[magenta-bg][gray]X[default][default-bg]", + "[magenta-bg][magenta]X[default][default-bg]", + "[magenta-bg][red]X[default][default-bg]", + "[magenta-bg][yellow]X[default][default-bg]", + "[magenta-bg][green]X[default][default-bg]", + "[magenta-bg][cyan]X[default][default-bg]", + "[magenta-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 5 1`] = ` +Array [ + "[red-bg]X[default-bg]", + "[red-bg][black]X[default][default-bg]", + "[red-bg][white]X[default][default-bg]", + "[red-bg][gray]X[default][default-bg]", + "[red-bg][magenta]X[default][default-bg]", + "[red-bg][red]X[default][default-bg]", + "[red-bg][yellow]X[default][default-bg]", + "[red-bg][green]X[default][default-bg]", + "[red-bg][cyan]X[default][default-bg]", + "[red-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 6 1`] = ` +Array [ + "[yellow-bg]X[default-bg]", + "[yellow-bg][black]X[default][default-bg]", + "[yellow-bg][white]X[default][default-bg]", + "[yellow-bg][gray]X[default][default-bg]", + "[yellow-bg][magenta]X[default][default-bg]", + "[yellow-bg][red]X[default][default-bg]", + "[yellow-bg][yellow]X[default][default-bg]", + "[yellow-bg][green]X[default][default-bg]", + "[yellow-bg][cyan]X[default][default-bg]", + "[yellow-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 7 1`] = ` +Array [ + "[green-bg]X[default-bg]", + "[green-bg][black]X[default][default-bg]", + "[green-bg][white]X[default][default-bg]", + "[green-bg][gray]X[default][default-bg]", + "[green-bg][magenta]X[default][default-bg]", + "[green-bg][red]X[default][default-bg]", + "[green-bg][yellow]X[default][default-bg]", + "[green-bg][green]X[default][default-bg]", + "[green-bg][cyan]X[default][default-bg]", + "[green-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 8 1`] = ` +Array [ + "[cyan-bg]X[default-bg]", + "[cyan-bg][black]X[default][default-bg]", + "[cyan-bg][white]X[default][default-bg]", + "[cyan-bg][gray]X[default][default-bg]", + "[cyan-bg][magenta]X[default][default-bg]", + "[cyan-bg][red]X[default][default-bg]", + "[cyan-bg][yellow]X[default][default-bg]", + "[cyan-bg][green]X[default][default-bg]", + "[cyan-bg][cyan]X[default][default-bg]", + "[cyan-bg][blue]X[default][default-bg]", +] +`; + +exports[`Colorize writes color grid correctly: line 9 1`] = ` +Array [ + "[blue-bg]X[default-bg]", + "[blue-bg][black]X[default][default-bg]", + "[blue-bg][white]X[default][default-bg]", + "[blue-bg][gray]X[default][default-bg]", + "[blue-bg][magenta]X[default][default-bg]", + "[blue-bg][red]X[default][default-bg]", + "[blue-bg][yellow]X[default][default-bg]", + "[blue-bg][green]X[default][default-bg]", + "[blue-bg][cyan]X[default][default-bg]", + "[blue-bg][blue]X[default][default-bg]", +] +`; diff --git a/libraries/terminal/src/test/__snapshots__/PrefixProxyTerminalProvider.test.ts.snap b/libraries/terminal/src/test/__snapshots__/PrefixProxyTerminalProvider.test.ts.snap new file mode 100644 index 00000000000..561059efad4 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/PrefixProxyTerminalProvider.test.ts.snap @@ -0,0 +1,181 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PrefixProxyTerminalProvider With a dynamic prefix write writes a message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] test message", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix write writes a message with newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1[n][prefix (1)] message 2[n][prefix (2)] message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix write writes a message with provider newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1[n][prefix (1)] message 2[n][prefix (2)] message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix write writes a mix of messages with and without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1message 2[n][prefix (1)] message 3[n][prefix (2)] message 4message 5[n][prefix (3)] message 6", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix write writes messages without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1message 2message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix writeLine writes a message line 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] test message[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix writeLine writes a message line with newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1[n][prefix (1)] message 2[n][prefix (2)] message 3[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix writeLine writes a message line with provider newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1[n][prefix (1)] message 2[n][prefix (2)] message 3[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a dynamic prefix writeLine writes a mix of message lines with and without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix (0)] message 1[n][prefix (1)] message 2[n][prefix (2)] message 3[n][prefix (3)] [n][prefix (4)] message 4[n][prefix (5)] message 5[n][prefix (6)] message 6[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix write writes a message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] test message", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix write writes a message with newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1[n][prefix] message 2[n][prefix] message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix write writes a message with provider newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1[n][prefix] message 2[n][prefix] message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix write writes a mix of messages with and without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1message 2[n][prefix] message 3[n][prefix] message 4message 5[n][prefix] message 6", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix write writes messages without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1message 2message 3", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix writeLine writes a message line 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] test message[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix writeLine writes a message line with newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1[n][prefix] message 2[n][prefix] message 3[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix writeLine writes a message line with provider newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1[n][prefix] message 2[n][prefix] message 3[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`PrefixProxyTerminalProvider With a static prefix writeLine writes a mix of message lines with and without newlines 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[prefix] message 1[n][prefix] message 2[n][prefix] message 3[n][prefix] [n][prefix] message 4[n][prefix] message 5[n][prefix] message 6[n]", + "verbose": "", + "warning": "", +} +`; diff --git a/libraries/terminal/src/test/__snapshots__/PrintUtilities.test.ts.snap b/libraries/terminal/src/test/__snapshots__/PrintUtilities.test.ts.snap new file mode 100644 index 00000000000..511965a165b --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/PrintUtilities.test.ts.snap @@ -0,0 +1,315 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PrintUtilities printMessageInBox Handles a case where there is a word longer than the boxwidth 1`] = ` +Array [ + " ══════════════════════════════════════════════════", + " Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + " error occurred while pushing commits to", + " git remote. Please make sure you have", + " installed and enabled git lfs. The", + " easiest way to do that is run the", + " provided setup script:", + " ", + " common/scripts/setup.sh", + " ", + " ══════════════════════════════════════════════════", + "", +] +`; + +exports[`PrintUtilities printMessageInBox prints a long message wrapped in a box using the console width 1`] = ` +Array [ + " ╔══════════════════════════════╗", + " ║ Lorem ipsum dolor sit ║", + " ║ amet, consectetuer ║", + " ║ adipiscing elit. ║", + " ║ Maecenas porttitor ║", + " ║ congue massa. Fusce ║", + " ║ posuere, magna sed ║", + " ║ pulvinar ultricies, ║", + " ║ purus lectus malesuada ║", + " ║ libero, sit amet ║", + " ║ commodo magna eros ║", + " ║ quis urna. ║", + " ╚══════════════════════════════╝", + "", +] +`; + +exports[`PrintUtilities printMessageInBox prints a long message wrapped in a wide box 1`] = ` +Array [ + " ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗", + " ║ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna. ║", + " ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝", + "", +] +`; + +exports[`PrintUtilities printMessageInBox prints a long message wrapped in narrow box 1`] = ` +Array [ + " ╔══════════════════╗", + " ║ Lorem ║", + " ║ ipsum ║", + " ║ dolor sit ║", + " ║ amet, ║", + " ║ consectetuer ║", + " ║ adipiscing elit. ║", + " ║ Maecenas ║", + " ║ porttitor ║", + " ║ congue ║", + " ║ massa. ║", + " ║ Fusce ║", + " ║ posuere, ║", + " ║ magna sed ║", + " ║ pulvinar ║", + " ║ ultricies, ║", + " ║ purus ║", + " ║ lectus ║", + " ║ malesuada ║", + " ║ libero, ║", + " ║ sit amet ║", + " ║ commodo ║", + " ║ magna eros ║", + " ║ quis urna. ║", + " ╚══════════════════╝", + "", +] +`; + +exports[`PrintUtilities printMessageInBox respects spaces and newlines in a pre-formatted message 1`] = ` +Array [ + " ╔════════════════════════════════════════════════╗", + " ║ An error occurred while pushing commits ║", + " ║ to git remote. Please make sure you have ║", + " ║ installed and enabled git lfs. The ║", + " ║ easiest way to do that is run the ║", + " ║ provided setup script: ║", + " ║ ║", + " ║ common/scripts/setup.sh ║", + " ║ ║", + " ╚════════════════════════════════════════════════╝", + "", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " applies pre-existing indents on both margins 1`] = ` +Array [ + "| Lorem ipsum dolor sit amet, consectetuer", + "| adipiscing elit. Maecenas porttitor congue", + "| massa.", + "| ", + "| Lorem ipsum dolor sit amet, consectetuer", + "| adipiscing elit. Maecenas porttitor congue", + "| massa.", + "| ", + "| Lorem ipsum dolor sit amet, consectetuer", + "| adipiscing elit. Maecenas porttitor congue", + "| massa.", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " handles a line containing a word longer than the max line length 1`] = ` +Array [ + "| An error", + "| occurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrred", + "| while pushing commits to git remote. Please make", + "| sure you have installed and enabled git lfs. The", + "| easiest way to do that is run the provided setup", + "| script:", + "| ", + "| common/scripts/setup.sh", + "| ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " handles a line starting with a word longer than the max line length 1`] = ` +Array [ + "| Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + "| error occurred while pushing commits to git", + "| remote. Please make sure you have installed and", + "| enabled git lfs. The easiest way to do that is", + "| run the provided setup script:", + "| ", + "| common/scripts/setup.sh", + "| ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " handles a line starting with two words longer than the max line length 1`] = ` +Array [ + "| Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + "| errrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrror", + "| occurred while pushing commits to git remote.", + "| Please make sure you have installed and enabled", + "| git lfs. The easiest way to do that is run the", + "| provided setup script:", + "| ", + "| common/scripts/setup.sh", + "| ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " handles a line with only a word longer than the max line length 1`] = ` +Array [ + "| Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="| " respects spaces and newlines in a pre-formatted message 1`] = ` +Array [ + "| An error occurred while pushing commits to git", + "| remote. Please make sure you have installed and", + "| enabled git lfs. The easiest way to do that is", + "| run the provided setup script:", + "| ", + "| common/scripts/setup.sh", + "| ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" applies pre-existing indents on both margins 1`] = ` +Array [ + " Lorem ipsum dolor sit amet, consectetuer", + " adipiscing elit. Maecenas porttitor congue", + " massa.", + " ", + " Lorem ipsum dolor sit amet, consectetuer", + " adipiscing elit. Maecenas porttitor congue", + " massa.", + " ", + " Lorem ipsum dolor sit amet, consectetuer", + " adipiscing elit. Maecenas porttitor congue", + " massa.", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" handles a line containing a word longer than the max line length 1`] = ` +Array [ + " An error", + " occurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrred", + " while pushing commits to git remote. Please", + " make sure you have installed and enabled git", + " lfs. The easiest way to do that is run the", + " provided setup script:", + " ", + " common/scripts/setup.sh", + " ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" handles a line starting with a word longer than the max line length 1`] = ` +Array [ + " Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + " error occurred while pushing commits to git", + " remote. Please make sure you have installed", + " and enabled git lfs. The easiest way to do", + " that is run the provided setup script:", + " ", + " common/scripts/setup.sh", + " ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" handles a line starting with two words longer than the max line length 1`] = ` +Array [ + " Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + " errrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrror", + " occurred while pushing commits to git remote.", + " Please make sure you have installed and", + " enabled git lfs. The easiest way to do that is", + " run the provided setup script:", + " ", + " common/scripts/setup.sh", + " ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" handles a line with only a word longer than the max line length 1`] = ` +Array [ + " Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="4" respects spaces and newlines in a pre-formatted message 1`] = ` +Array [ + " An error occurred while pushing commits to git", + " remote. Please make sure you have installed", + " and enabled git lfs. The easiest way to do", + " that is run the provided setup script:", + " ", + " common/scripts/setup.sh", + " ", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" applies pre-existing indents on both margins 1`] = ` +Array [ + "Lorem ipsum dolor sit amet, consectetuer", + "adipiscing elit. Maecenas porttitor congue massa.", + "", + " Lorem ipsum dolor sit amet, consectetuer", + " adipiscing elit. Maecenas porttitor congue massa.", + "", + "Lorem ipsum dolor sit amet, consectetuer", + "adipiscing elit. Maecenas porttitor congue massa.", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" handles a line containing a word longer than the max line length 1`] = ` +Array [ + "An error", + "occurrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrred", + "while pushing commits to git remote. Please make", + "sure you have installed and enabled git lfs. The", + "easiest way to do that is run the provided setup", + "script:", + "", + " common/scripts/setup.sh", + "", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" handles a line starting with a word longer than the max line length 1`] = ` +Array [ + "Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + "error occurred while pushing commits to git", + "remote. Please make sure you have installed and", + "enabled git lfs. The easiest way to do that is run", + "the provided setup script:", + "", + " common/scripts/setup.sh", + "", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" handles a line starting with two words longer than the max line length 1`] = ` +Array [ + "Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", + "errrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrror", + "occurred while pushing commits to git remote.", + "Please make sure you have installed and enabled", + "git lfs. The easiest way to do that is run the", + "provided setup script:", + "", + " common/scripts/setup.sh", + "", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" handles a line with only a word longer than the max line length 1`] = ` +Array [ + "Annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", +] +`; + +exports[`PrintUtilities wrapWordsToLines with prefix="undefined" respects spaces and newlines in a pre-formatted message 1`] = ` +Array [ + "An error occurred while pushing commits to git", + "remote. Please make sure you have installed and", + "enabled git lfs. The easiest way to do that is run", + "the provided setup script:", + "", + " common/scripts/setup.sh", + "", +] +`; diff --git a/libraries/terminal/src/test/__snapshots__/RemoveColorsTextRewriter.test.ts.snap b/libraries/terminal/src/test/__snapshots__/RemoveColorsTextRewriter.test.ts.snap new file mode 100644 index 00000000000..2d11da37c4d --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/RemoveColorsTextRewriter.test.ts.snap @@ -0,0 +1,139 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RemoveColorsTextRewriter 01 should process empty inputs 1`] = ` +Object { + "inputs": Array [], + "outputs": Array [], +} +`; + +exports[`RemoveColorsTextRewriter 01 should process empty inputs 2`] = ` +Object { + "inputs": Array [ + "", + ], + "outputs": Array [ + "", + ], +} +`; + +exports[`RemoveColorsTextRewriter 01 should process empty inputs 3`] = ` +Object { + "inputs": Array [ + "", + "a", + "", + ], + "outputs": Array [ + "", + "a", + "", + ], +} +`; + +exports[`RemoveColorsTextRewriter 02 should remove colors from complete chunks 1`] = ` +Object { + "inputs": Array [ + "[red]1[default]", + ], + "outputs": Array [ + "1", + ], +} +`; + +exports[`RemoveColorsTextRewriter 02 should remove colors from complete chunks 2`] = ` +Object { + "inputs": Array [ + "[red]1[default][green]2[default]", + ], + "outputs": Array [ + "12", + ], +} +`; + +exports[`RemoveColorsTextRewriter 02 should remove colors from complete chunks 3`] = ` +Object { + "inputs": Array [ + "[red]1[default]2[green]3[default]", + ], + "outputs": Array [ + "123", + ], +} +`; + +exports[`RemoveColorsTextRewriter 03 should remove colors from 1-character chunks 1`] = ` +Object { + "inputs": Array [ + "1", + "", + "[", + "3", + "1", + "m", + "2", + "", + "[", + "3", + "9", + "m", + ], + "outputs": Array [ + "1", + "", + "", + "", + "", + "", + "2", + "", + "", + "", + "", + "", + ], +} +`; + +exports[`RemoveColorsTextRewriter 04 should pass through incomplete partial matches 1`] = ` +Object { + "inputs": Array [ + "", + ], + "outputs": Array [ + "", + "--close--", + "", + ], +} +`; + +exports[`RemoveColorsTextRewriter 04 should pass through incomplete partial matches 2`] = ` +Object { + "inputs": Array [ + "[ +", + ], + "outputs": Array [ + "[ +", + ], +} +`; + +exports[`RemoveColorsTextRewriter 04 should pass through incomplete partial matches 3`] = ` +Object { + "inputs": Array [ + "[1", + ], + "outputs": Array [ + "", + "--close--", + "[1", + ], +} +`; diff --git a/libraries/terminal/src/test/__snapshots__/SplitterTransform.test.ts.snap b/libraries/terminal/src/test/__snapshots__/SplitterTransform.test.ts.snap new file mode 100644 index 00000000000..6567fcd2ee1 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/SplitterTransform.test.ts.snap @@ -0,0 +1,114 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SplitterTransform addDestination only receives subsequent chunks 1`] = ` +Object { + "a": Array [ + Object { + "kind": "O", + "text": "early1 ", + }, + Object { + "kind": "O", + "text": "early2 ", + }, + Object { + "kind": "O", + "text": "late1 ", + }, + Object { + "kind": "O", + "text": "late2", + }, + ], + "late": Array [ + Object { + "kind": "O", + "text": "late1 ", + }, + Object { + "kind": "O", + "text": "late2", + }, + ], +} +`; + +exports[`SplitterTransform removeDestination respects preventAutoclose 1`] = ` +Object { + "a": Array [ + Object { + "kind": "O", + "text": "hello ", + }, + Object { + "kind": "O", + "text": "world", + }, + ], + "b": Array [ + Object { + "kind": "O", + "text": "hello ", + }, + ], +} +`; + +exports[`SplitterTransform removeDestination stops further writes and closes by default 1`] = ` +Object { + "a": Array [ + Object { + "kind": "O", + "text": "first ", + }, + Object { + "kind": "O", + "text": "second", + }, + ], + "b": Array [ + Object { + "kind": "O", + "text": "first ", + }, + ], +} +`; + +exports[`SplitterTransform removeDestination with close=false keeps destination open 1`] = ` +Object { + "a": Array [ + Object { + "kind": "O", + "text": "first ", + }, + Object { + "kind": "O", + "text": "second", + }, + ], + "b": Array [ + Object { + "kind": "O", + "text": "first ", + }, + ], +} +`; + +exports[`SplitterTransform writes chunks to all initial destinations 1`] = ` +Array [ + Object { + "kind": "O", + "text": "one ", + }, + Object { + "kind": "E", + "text": "two ", + }, + Object { + "kind": "O", + "text": "three", + }, +] +`; diff --git a/libraries/terminal/src/test/__snapshots__/StdioLineTransform.test.ts.snap b/libraries/terminal/src/test/__snapshots__/StdioLineTransform.test.ts.snap new file mode 100644 index 00000000000..9bfa4798812 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/StdioLineTransform.test.ts.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StderrLineTransform should report stdout if there is no stderr 1`] = ` +Array [ + Object { + "kind": "O", + "text": "stdout 1 +", + }, + Object { + "kind": "O", + "text": "stdout 2 +", + }, +] +`; diff --git a/libraries/terminal/src/test/__snapshots__/StdioSummarizer.test.ts.snap b/libraries/terminal/src/test/__snapshots__/StdioSummarizer.test.ts.snap new file mode 100644 index 00000000000..485df165e35 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/StdioSummarizer.test.ts.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StdioSummarizer should abridge extra lines 1`] = ` +"leading 0 +leading 1 +leading 2 +leading 3 +leading 4 +leading 5 +leading 6 +leading 7 +leading 8 +leading 9 + ...2 lines omitted... +trailing 0 +trailing 1 +trailing 2 +trailing 3 +trailing 4 +trailing 5 +trailing 6 +trailing 7 +trailing 8 +trailing 9 +" +`; + +exports[`StdioSummarizer should concatenate partial lines 1`] = ` +"abcde +f + +g +h +" +`; + +exports[`StdioSummarizer should report stdout if there is no stderr 1`] = ` +"stdout 1 +stdout 2 +" +`; diff --git a/libraries/terminal/src/test/__snapshots__/Terminal.test.ts.snap b/libraries/terminal/src/test/__snapshots__/Terminal.test.ts.snap new file mode 100644 index 00000000000..6ba14641d27 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/Terminal.test.ts.snap @@ -0,0 +1,1101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[green]message 1[default]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[green]message 1[default][red]message 2[default]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1[green]message 2[default]message 3[red]message 4[default]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 01 write 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1[green]message 2[default]message 3[red]message 4[default]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[green]message 1[default][n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "[green]message 1[default][red]message 2[default][n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1[green]message 2[default]message 3[red]message 4[default][n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 02 writeLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1[green]message 2[default]message 3[red]message 4[default][n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]test message[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default][yellow]message 3[default][yellow]message 4[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 03 writeWarning 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1[green]message 2[default]message 3[red]message 4[default]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]test message[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]message 1[default][yellow]message 2[default][yellow]message 3[default][yellow]message 4[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 04 writeWarningLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1[green]message 2[default]message 3[red]message 4[default][n]", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "[red]test message[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default][red]message 3[default][red]message 4[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 05 writeError 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "message 1[green]message 2[default]message 3[red]message 4[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "[red]test message[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default][red]message 3[default][red]message 4[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 06 writeErrorLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "message 1[green]message 2[default]message 3[red]message 4[default][n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "[green]message 1[default]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "[green]message 1[default][red]message 2[default]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1[green]message 2[default]message 3[red]message 4[default]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 07 writeVerbose 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1[green]message 2[default]message 3[red]message 4[default]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message[n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2[n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "[green]message 1[default][n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "[green]message 1[default][red]message 2[default][n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1[green]message 2[default]message 3[red]message 4[default][n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 01 basic terminal functions 08 writeVerboseLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1[green]message 2[default]message 3[red]message 4[default][n]", + "warning": "", +} +`; + +exports[`Terminal 01 color enabled 05 writes to multiple streams 1`] = ` +Object { + "debug": "", + "error": "[red]message 1[default][red]message 2[default][red]message 3[default][red]message 4[default][red]test message[default][n][red]message 1[default][red]message 2[default][red]message 1[default][red]message 2[default][n][red]message 1[default][red]message 1[default][red]message 2[default][red]message 3[default][red]message 4[default][n][red]message 1[default][n][red]test message[default][red]message 1[default][red]message 2[default][n][red]message 1[default][red]message 2[default]", + "log": "message 1[green]message 2[default]message 3[red]message 4[default][green]message 1[default][n][green]message 1[default][green]message 1[default][red]message 2[default][green]message 1[default][red]message 2[default][n]test messagemessage 1[green]message 2[default]message 3[red]message 4[default][n]message 1message 2test message[n]message 1message 2[n]", + "verbose": "test message[green]message 1[default]message 1[green]message 2[default]message 3[red]message 4[default][n]test message[n]message 1[green]message 2[default]message 3[red]message 4[default]message 1message 2[green]message 1[default][n][green]message 1[default][red]message 2[default][n]message 1message 2[n][green]message 1[default][red]message 2[default]", + "warning": "[yellow]message 1[default][yellow]message 2[default][n][yellow]message 1[default][yellow]message 2[default][yellow]message 1[default][yellow]message 2[default][yellow]message 3[default][yellow]message 4[default][yellow]message 1[default][yellow]message 2[default][yellow]message 3[default][yellow]message 4[default][n][yellow]test message[default][n][yellow]message 1[default][yellow]message 2[default][yellow]message 1[default][yellow]message 1[default][yellow]message 2[default][n][yellow]message 1[default][n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2message 3message 4", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 01 write 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2message 3message 4", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2message 3message 4[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 02 writeLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "message 1message 2message 3message 4[n]", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "test message", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2message 3message 4", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 03 writeWarning 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2message 3message 4", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "test message[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2message 3message 4[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 04 writeWarningLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "message 1message 2message 3message 4[n]", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "test message", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "message 1message 2", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "message 1", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "message 1message 2", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "message 1message 2message 3message 4", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 05 writeError 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "message 1message 2message 3message 4", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "test message[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "message 1message 2[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "message 1[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "message 1message 2[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "message 1message 2message 3message 4[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 06 writeErrorLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "message 1message 2message 3message 4[n]", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2message 3message 4", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 07 writeVerbose 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2message 3message 4", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 01 writes a single message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 02 writes multiple messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 03 writes a message with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2message 3message 4[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 08 writeVerboseLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "message 1message 2message 3message 4[n]", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 01 writes a single message 1`] = ` +Object { + "debug": "test message", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 02 writes multiple messages 1`] = ` +Object { + "debug": "message 1message 2", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 03 writes a message with colors 1`] = ` +Object { + "debug": "message 1", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "message 1message 2", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "message 1message 2message 3message 4", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 09 writeDebug 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "message 1message 2message 3message 4", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 01 writes a single message 1`] = ` +Object { + "debug": "test message[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 02 writes multiple messages 1`] = ` +Object { + "debug": "message 1message 2[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 03 writes a message with colors 1`] = ` +Object { + "debug": "message 1[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 04 writes a multiple messages with colors 1`] = ` +Object { + "debug": "message 1message 2[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 05 writes a messages with colors interspersed with non-colored messages 1`] = ` +Object { + "debug": "message 1message 2message 3message 4[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 01 basic terminal functions 10 writeDebugLine 06 writes a messages with colors interspersed with non-colored messages with color overriding disabled 1`] = ` +Object { + "debug": "message 1message 2message 3message 4[n]", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`Terminal 02 color disabled 05 writes to multiple streams 1`] = ` +Object { + "debug": "", + "error": "message 1message 2message 3message 4test message[n]message 1message 2message 1message 2[n]message 1message 1message 2message 3message 4[n]message 1[n]test messagemessage 1message 2[n]message 1message 2", + "log": "message 1message 2message 3message 4message 1[n]message 1message 1message 2message 1message 2[n]test messagemessage 1message 2message 3message 4[n]message 1message 2test message[n]message 1message 2[n]", + "verbose": "test messagemessage 1message 1message 2message 3message 4[n]test message[n]message 1message 2message 3message 4message 1message 2message 1[n]message 1message 2[n]message 1message 2[n]message 1message 2", + "warning": "message 1message 2[n]message 1message 2message 1message 2message 3message 4message 1message 2message 3message 4[n]test message[n]message 1message 2message 1message 1message 2[n]message 1[n]", +} +`; diff --git a/libraries/terminal/src/test/__snapshots__/TerminalStreamWritable.test.ts.snap b/libraries/terminal/src/test/__snapshots__/TerminalStreamWritable.test.ts.snap new file mode 100644 index 00000000000..7682242fb62 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/TerminalStreamWritable.test.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TerminalStreamWritable writes a debug message 1`] = ` +Object { + "debug": "test message", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`TerminalStreamWritable writes a message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message", + "verbose": "", + "warning": "", +} +`; + +exports[`TerminalStreamWritable writes a verbose message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message", + "warning": "", +} +`; + +exports[`TerminalStreamWritable writes a warning message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]test message[default]", +} +`; + +exports[`TerminalStreamWritable writes an error message 1`] = ` +Object { + "debug": "", + "error": "[red]test message[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; diff --git a/libraries/terminal/src/test/__snapshots__/TerminalWritable.test.ts.snap b/libraries/terminal/src/test/__snapshots__/TerminalWritable.test.ts.snap new file mode 100644 index 00000000000..1f17c94e56f --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/TerminalWritable.test.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TerminalWritable writes a debug message 1`] = ` +Object { + "debug": "test message", + "error": "", + "log": "", + "verbose": "", + "warning": "", +} +`; + +exports[`TerminalWritable writes a message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "test message", + "verbose": "", + "warning": "", +} +`; + +exports[`TerminalWritable writes a verbose message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "test message", + "warning": "", +} +`; + +exports[`TerminalWritable writes a warning message 1`] = ` +Object { + "debug": "", + "error": "", + "log": "", + "verbose": "", + "warning": "[yellow]test message[default]", +} +`; + +exports[`TerminalWritable writes an error message 1`] = ` +Object { + "debug": "", + "error": "[red]test message[default]", + "log": "", + "verbose": "", + "warning": "", +} +`; diff --git a/libraries/terminal/src/test/__snapshots__/TextRewriterTransform.test.ts.snap b/libraries/terminal/src/test/__snapshots__/TextRewriterTransform.test.ts.snap new file mode 100644 index 00000000000..16b30c3b4d2 --- /dev/null +++ b/libraries/terminal/src/test/__snapshots__/TextRewriterTransform.test.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TextRewriterTransform should apply standard rewriters 1`] = ` +Array [ + Object { + "kind": "E", + "text": "RED", + }, + Object { + "kind": "E", + "text": "stderr 1[n]stderr 2[n]", + }, + Object { + "kind": "O", + "text": "stdout 3[n]stdout 4", + }, + Object { + "kind": "O", + "text": "[1[n]", + }, +] +`; diff --git a/libraries/terminal/src/test/createColorGrid.ts b/libraries/terminal/src/test/createColorGrid.ts new file mode 100644 index 00000000000..a2dca2e2be3 --- /dev/null +++ b/libraries/terminal/src/test/createColorGrid.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. + +/** + * This file is a little program that prints all of the colors to the console + */ + +import { Colorize } from '../index'; + +export function createColorGrid(attributeFunction?: (text: string) => string): string[][] { + const foregroundFunctions: ((text: string) => string)[] = [ + (text) => text, + Colorize.black, + Colorize.white, + Colorize.gray, + Colorize.magenta, + Colorize.red, + Colorize.yellow, + Colorize.green, + Colorize.cyan, + Colorize.blue + ]; + + const backgroundFunctions: ((text: string) => string)[] = [ + (text) => text, + Colorize.blackBackground, + Colorize.whiteBackground, + Colorize.grayBackground, + Colorize.magentaBackground, + Colorize.redBackground, + Colorize.yellowBackground, + Colorize.greenBackground, + Colorize.cyanBackground, + Colorize.blueBackground + ]; + + const lines: string[][] = []; + + for (const backgroundFunction of backgroundFunctions) { + const sequences: string[] = []; + + for (const foregroundFunction of foregroundFunctions) { + let sequence: string = backgroundFunction(foregroundFunction('X')); + if (attributeFunction) { + sequence = attributeFunction(sequence); + } + + sequences.push(sequence); + } + + lines.push(sequences); + } + + return lines; +} diff --git a/libraries/terminal/src/test/write-colors.ts b/libraries/terminal/src/test/write-colors.ts new file mode 100644 index 00000000000..03a2f74ba07 --- /dev/null +++ b/libraries/terminal/src/test/write-colors.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. + +/** + * This file is a little program that prints all of the colors to the console. + * + * Run this program with `node write-colors.js` + */ + +import { Terminal, ConsoleTerminalProvider, Colorize } from '../index'; +import { createColorGrid } from './createColorGrid'; + +const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); +function writeColorGrid(colorGrid: string[][]): void { + for (const line of colorGrid) { + terminal.writeLine(...line); + } +} + +writeColorGrid(createColorGrid()); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.bold)); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.dim)); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.underline)); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.blink)); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.invertColor)); +terminal.writeLine(); +writeColorGrid(createColorGrid(Colorize.hidden)); +terminal.writeLine(); + +terminal.write('Normal text...'); +terminal.writeLine(Colorize.green('done')); + +terminal.writeError('Error...'); +terminal.writeErrorLine(Colorize.green('done')); + +terminal.writeWarning('Warning...'); +terminal.writeWarningLine(Colorize.green('done')); diff --git a/libraries/terminal/tsconfig.json b/libraries/terminal/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/terminal/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/tree-pattern/.npmignore b/libraries/tree-pattern/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/tree-pattern/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/tree-pattern/CHANGELOG.json b/libraries/tree-pattern/CHANGELOG.json new file mode 100644 index 00000000000..11eb89beb71 --- /dev/null +++ b/libraries/tree-pattern/CHANGELOG.json @@ -0,0 +1,142 @@ +{ + "name": "@rushstack/tree-pattern", + "entries": [ + { + "version": "0.3.4", + "tag": "@rushstack/tree-pattern_v0.3.4", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/tree-pattern_v0.3.3", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/tree-pattern_v0.3.2", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade build dependencies" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/tree-pattern_v0.3.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/tree-pattern_v0.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/tree-pattern_v0.2.4", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing types" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/tree-pattern_v0.2.3", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/tree-pattern_v0.2.2", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/tree-pattern_v0.2.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/tree-pattern_v0.2.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "minor": [ + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/tree-pattern_v0.1.0", + "date": "Sat, 19 Sep 2020 03:33:06 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ] + } + } + ] +} diff --git a/libraries/tree-pattern/CHANGELOG.md b/libraries/tree-pattern/CHANGELOG.md new file mode 100644 index 00000000000..e9fc3d2f75c --- /dev/null +++ b/libraries/tree-pattern/CHANGELOG.md @@ -0,0 +1,85 @@ +# Change Log - @rushstack/tree-pattern + +This log was last generated on Sat, 27 Jul 2024 00:10:27 GMT and should not be manually modified. + +## 0.3.4 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.3.3 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.3.2 +Tue, 16 Jan 2024 18:30:10 GMT + +### Patches + +- Upgrade build dependencies + +## 0.3.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.2.4 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Add missing types + +## 0.2.3 +Sat, 09 Apr 2022 02:24:27 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.2.2 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.2.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 0.2.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 0.1.0 +Sat, 19 Sep 2020 03:33:06 GMT + +### Minor changes + +- Initial release + diff --git a/libraries/tree-pattern/LICENSE b/libraries/tree-pattern/LICENSE new file mode 100644 index 00000000000..431623f2dc2 --- /dev/null +++ b/libraries/tree-pattern/LICENSE @@ -0,0 +1,24 @@ +@rushstack/tree-pattern + +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/tree-pattern/README.md b/libraries/tree-pattern/README.md new file mode 100644 index 00000000000..ff9a0284018 --- /dev/null +++ b/libraries/tree-pattern/README.md @@ -0,0 +1,148 @@ +# @rushstack/tree-pattern + +This is a simple, fast pattern matcher for JavaScript tree structures. It was designed for ESLint rules and +transforms that match parse trees such as produced by [Esprima](https://esprima.org/). However, it can be used +with any JSON-like data structure. + +## Usage + +Suppose we are fixing up obsolete `Promise` calls, and we need to match an input like this: + +```ts +Promise.fulfilled(123); +``` + +The parsed subtree looks like this: +```js +{ + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { // <---- expressionNode + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "Promise" + }, + "property": { + "type": "Identifier", + "name": "fulfilled" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Literal", + "value": 123, + "raw": "123" + } + ], + "optional": false + } + } + ], + "sourceType": "module" +} +``` + +Throwing away the details that we don't care about, we can specify a pattern expression with the parts +that need to be present: +```js +const pattern1: TreePattern = new TreePattern({ + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'Promise' + }, + property: { + type: 'Identifier', + name: 'fulfilled' + }, + computed: false + } +}); +``` + +Then when our visitor encounters an `ExpressionStatement`, we can match the `expressionNode` like this: +```js +if (pattern1.match(expressionNode)) { + console.log('Success!'); +} +``` + +## Capturing matched subtrees + +Suppose we want to generalize this to match any API such as `Promise.thing(123);` or `Promise.otherThing(123);`. +We can use a "tag" to extract the matching identifier: + +```js +const pattern2: TreePattern = new TreePattern({ + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'Promise' + }, + property: TreePattern.tag('promiseMethod', { + type: 'Identifier' + }), + computed: false + } +}); +``` + +On a successful match, the tagged `promiseMethod` subtree can be retrieved like this: +```ts +interface IMyCaptures { + // Captures the "promiseMethod" tag specified using TreePattern.tag() + promiseMethod?: { name?: string }; // <--- substitute your real AST interface here +} + +const captures: IMyCaptures = {}; + +if (pattern2.match(node, captures)) { + // Prints: "Matched fulfilled" + console.log('Matched ' + captures?.promiseMethod?.name); +} +``` + +## Alternative subtrees + +The `oneOf` API enables you to write patterns that match alternative subtrees. + +```ts +const pattern3: TreePattern = new TreePattern({ + animal: TreePattern.oneOf([ + { kind: 'dog', bark: 'loud' }, + { kind: 'cat', meow: 'quiet' } + ]) +}); + +if (pattern3.match({ animal: { kind: 'dog', bark: 'loud' } })) { + console.log('I can match dog.'); +} + +if (pattern3.match({ animal: { kind: 'cat', meow: 'quiet' } })) { + console.log('I can match cat, too.'); +} +``` + +For example, maybe we want to match `Promise['fulfilled'](123);` as well as `Promise.fulfilled(123);`. +If the structure of the expressions is similar enough, `TreePattern.oneOf` avoids having to create two +separate patterns. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/tree-pattern/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/tree-pattern/) + +`@rushstack/tree-pattern` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/tree-pattern/config/api-extractor.json b/libraries/tree-pattern/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/tree-pattern/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/tree-pattern/config/jest.config.json b/libraries/tree-pattern/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/tree-pattern/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/tree-pattern/config/rig.json b/libraries/tree-pattern/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/tree-pattern/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/tree-pattern/eslint.config.js b/libraries/tree-pattern/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/tree-pattern/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/tree-pattern/package.json b/libraries/tree-pattern/package.json new file mode 100644 index 00000000000..018c2a0254e --- /dev/null +++ b/libraries/tree-pattern/package.json @@ -0,0 +1,23 @@ +{ + "name": "@rushstack/tree-pattern", + "version": "0.3.4", + "description": "A fast, lightweight pattern matcher for tree structures such as an Abstract Syntax Tree (AST)", + "main": "lib/index.js", + "typings": "dist/tree-pattern.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/tree-pattern" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "1.1.4", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + } +} diff --git a/libraries/tree-pattern/src/TreePattern.test.ts b/libraries/tree-pattern/src/TreePattern.test.ts new file mode 100644 index 00000000000..bc5269c01ac --- /dev/null +++ b/libraries/tree-pattern/src/TreePattern.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 { TreePattern, type TreeNode } from './TreePattern'; + +export interface IMyPattern { + branch?: string; +} + +const pattern1: TreePattern = new TreePattern({ + a: [ + 1, + 2, + TreePattern.tag('branch', { + b: [] + }) + ] +}); + +const pattern2: TreePattern = new TreePattern({ + c: TreePattern.oneOf([ + 123, + { + d: 1 + } + ]) +}); + +describe(TreePattern.name, () => { + it('matches using a tag', () => { + const tree1: TreeNode = { + a: [ + 1, + 2, + { + b: [], + extra: 'hi' + } + ], + b: 123 + }; + + const captures: IMyPattern = {}; + expect(pattern1.match(tree1, captures)).toBe(true); + expect(captures.branch).toMatchObject({ + b: [], + extra: 'hi' + }); + }); + + it('matches alternatives', () => { + const tree2a: TreeNode = { + c: 123 + }; + expect(pattern2.match(tree2a)).toBe(true); + + const tree2b: TreeNode = { + c: { d: 1 } + }; + expect(pattern2.match(tree2b)).toBe(true); + + const tree2c: TreeNode = { + c: 321 + }; + expect(pattern2.match(tree2c)).toBe(false); + }); +}); diff --git a/libraries/tree-pattern/src/TreePattern.ts b/libraries/tree-pattern/src/TreePattern.ts new file mode 100644 index 00000000000..92d276196a5 --- /dev/null +++ b/libraries/tree-pattern/src/TreePattern.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. + +/** + * Indicates the tree-like data structure that {@link TreePattern} will traverse. + * + * @remarks + * Since `TreePattern` makes relatively few assumptions object the object structure, this is + * just an alias for `any`. At least as far as the portions to be matched, the tree nodes + * are expected to be JSON-like structures made from JavaScript arrays, JavaScript objects, + * and primitive values that can be compared using `===`. + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type TreeNode = any; + +class TreePatternArg { + public readonly keyName: string; + public readonly subtree: TreeNode | undefined; + public constructor(keyName: string, subtree?: TreeNode) { + this.keyName = keyName; + this.subtree = subtree; + } +} + +class TreePatternAlternatives { + public readonly possibleSubtrees: TreeNode[]; + public constructor(possibleSubtrees: TreeNode[]) { + this.possibleSubtrees = possibleSubtrees; + } +} + +/** + * Provides additional detail about the success or failure of {@link TreePattern.match}. + * + * @remarks + * On success, the object will contain keys for any successfully matched tags, as + * defined using {@link TreePattern.tag}. + * + * On failure, the `failPath` member will indicate the JSON path of the node that + * failed to match. + * + * @public + */ +export type ITreePatternCaptureSet = + | { + [tagName: string]: TreeNode; + } + | { failPath: string }; + +/** + * A fast, lightweight pattern matcher for tree structures such as an Abstract Syntax Tree (AST). + * @public + */ +export class TreePattern { + private readonly _pattern: TreeNode; + + public constructor(pattern: TreeNode) { + this._pattern = pattern; + } + + /** + * Labels a subtree within the search pattern, so that the matching object can be retrieved. + * + * @remarks + * Used to build the `pattern` tree for {@link TreePattern.match}. For the given `subtree` of the pattern, + * if it is matched, that node will be assigned to the `captures` object using `tagName` as the key. + * + * Example: + * + * ```ts + * const myCaptures: { personName?: string } = {}; + * const myPattern = { + * name: TreePattern.tag('personName') + * }; + * if (myPattern.match({ name: 'Bob' }, myCaptures)) { + * console.log(myCaptures.personName); + * } + * ``` + */ + public static tag(tagName: string, subtree?: TreeNode): TreeNode { + return new TreePatternArg(tagName, subtree); + } + + /** + * Used to specify alternative possible subtrees in the search pattern. + * + * @remarks + * Used to build the `pattern` tree for {@link TreePattern.match}. Allows several alternative patterns + * to be matched for a given subtree. + * + * Example: + * + * ```ts + * const myPattern: TreePattern = new TreePattern({ + * animal: TreePattern.oneOf([ + * { kind: 'dog', bark: 'loud' }, + * { kind: 'cat', meow: 'quiet' } + * ]) + * }); + * if (myPattern.match({ animal: { kind: 'dog', bark: 'loud' } })) { + * console.log('I can match dog.'); + * } + * if (myPattern.match({ animal: { kind: 'cat', meow: 'quiet' } })) { + * console.log('I can match cat, too.'); + * } + * ``` + */ + public static oneOf(possibleSubtrees: TreeNode[]): TreeNode { + return new TreePatternAlternatives(possibleSubtrees); + } + + /** + * Match an input tree. + * + * @remarks + * Return true if the `root` node matches the pattern. (If the `root` node does not match, the child nodes are + * not recursively tested, since for an Abstract Syntax Tree the caller is typically an efficient visitor + * callback that already handles that job.) + * + * If the input matches the pattern, any tagged subtrees will be assigned to the `captures` target object + * if provided. If the input does not match, the path of the mismatched node will be assigned to + * `captures.failPath`. + * + * @param root - the input tree to be matched + * @param captures - an optional object to receive any subtrees that were matched using {@link TreePattern.tag} + * @returns `true` if `root` matches the pattern, or `false` otherwise + */ + public match(root: TreeNode, captures: ITreePatternCaptureSet = {}): boolean { + return TreePattern._matchTreeRecursive(root, this._pattern, captures, 'root'); + } + + private static _matchTreeRecursive( + root: TreeNode, + pattern: TreeNode, + captures: ITreePatternCaptureSet, + path: string + ): boolean { + if (pattern === undefined) { + throw new Error('pattern has an undefined value at ' + path); + } + + // Avoid "Element implicitly has an 'any' type" (TS7053) + const castedCaptures: Record = captures; + + if (pattern instanceof TreePatternArg) { + if (pattern.subtree !== undefined) { + if (!TreePattern._matchTreeRecursive(root, pattern.subtree, captures, path)) { + return false; + } + } + + castedCaptures[pattern.keyName] = root; + return true; + } + + if (pattern instanceof TreePatternAlternatives) { + // Try each possible alternative until we find one that matches + for (const possibleSubtree of pattern.possibleSubtrees) { + // We shouldn't update "captures" unless the match is fully successful. + // So make a temporary copy of it. + const tempCaptures: Record = { ...captures }; + if (TreePattern._matchTreeRecursive(root, possibleSubtree, tempCaptures, path)) { + // The match was successful, so assign the tempCaptures results back into the + // original "captures" object. + for (const key of Object.getOwnPropertyNames(tempCaptures)) { + castedCaptures[key] = tempCaptures[key]; + } + return true; + } + } + + // None of the alternatives matched + return false; + } + + if (Array.isArray(pattern)) { + if (!Array.isArray(root)) { + captures.failPath = path; + return false; + } + + if (root.length !== pattern.length) { + captures.failPath = path; + return false; + } + + for (let i: number = 0; i < pattern.length; ++i) { + const subPath: string = path + '[' + i + ']'; + + const rootElement: TreeNode = root[i]; + const patternElement: TreeNode = pattern[i]; + if (!TreePattern._matchTreeRecursive(rootElement, patternElement, captures, subPath)) { + return false; + } + } + + return true; + } + + // In JavaScript, typeof null === 'object' + if (typeof pattern === 'object' && pattern !== null) { + if (typeof root !== 'object' || root === null) { + captures.failPath = path; + return false; + } + + for (const keyName of Object.getOwnPropertyNames(pattern)) { + let subPath: string; + if (/^[a-z_][a-z0-9_]*$/i.test(keyName)) { + subPath = path + '.' + keyName; + } else { + subPath = path + '[' + JSON.stringify(keyName) + ']'; + } + + if (!Object.hasOwnProperty.call(root, keyName)) { + captures.failPath = subPath; + return false; + } + if (!TreePattern._matchTreeRecursive(root[keyName], pattern[keyName], captures, subPath)) { + return false; + } + } + + return true; + } + + if (root !== pattern) { + captures.failPath = path; + return false; + } + + return true; + } +} diff --git a/libraries/tree-pattern/src/index.ts b/libraries/tree-pattern/src/index.ts new file mode 100644 index 00000000000..98e8b9b0961 --- /dev/null +++ b/libraries/tree-pattern/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. + +/** + * A fast, lightweight pattern matcher for tree structures such as an Abstract Syntax Tree (AST). + * + * @packageDocumentation + */ + +export * from './TreePattern'; diff --git a/libraries/tree-pattern/tsconfig.json b/libraries/tree-pattern/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/tree-pattern/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/ts-command-line/.eslintrc.js b/libraries/ts-command-line/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/libraries/ts-command-line/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/ts-command-line/.npmignore b/libraries/ts-command-line/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/ts-command-line/.npmignore +++ b/libraries/ts-command-line/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/ts-command-line/CHANGELOG.json b/libraries/ts-command-line/CHANGELOG.json index 03d44a2b7e6..699b7bbdc99 100644 --- a/libraries/ts-command-line/CHANGELOG.json +++ b/libraries/ts-command-line/CHANGELOG.json @@ -1,6 +1,1573 @@ { "name": "@rushstack/ts-command-line", "entries": [ + { + "version": "5.1.5", + "tag": "@rushstack/ts-command-line_v5.1.5", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + } + ] + } + }, + { + "version": "5.1.4", + "tag": "@rushstack/ts-command-line_v5.1.4", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + } + ] + } + }, + { + "version": "5.1.3", + "tag": "@rushstack/ts-command-line_v5.1.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/node-core-library\" to `5.18.0`" + } + ] + } + }, + { + "version": "5.1.2", + "tag": "@rushstack/ts-command-line_v5.1.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/node-core-library\" to `5.17.1`" + } + ] + } + }, + { + "version": "5.1.1", + "tag": "@rushstack/ts-command-line_v5.1.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/node-core-library\" to `5.17.0`" + } + ] + } + }, + { + "version": "5.1.0", + "tag": "@rushstack/ts-command-line_v5.1.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/node-core-library\" to `5.16.0`" + } + ] + } + }, + { + "version": "5.0.5", + "tag": "@rushstack/ts-command-line_v5.0.5", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + } + ] + } + }, + { + "version": "5.0.4", + "tag": "@rushstack/ts-command-line_v5.0.4", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + } + ] + } + }, + { + "version": "5.0.3", + "tag": "@rushstack/ts-command-line_v5.0.3", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + } + ] + } + }, + { + "version": "5.0.2", + "tag": "@rushstack/ts-command-line_v5.0.2", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "patch": [ + { + "comment": "Escape `%` characters in help text to fix an issue where they were previously interpreted as sprintf-style tokens." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + } + ] + } + }, + { + "version": "5.0.1", + "tag": "@rushstack/ts-command-line_v5.0.1", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + } + ] + } + }, + { + "version": "5.0.0", + "tag": "@rushstack/ts-command-line_v5.0.0", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "major": [ + { + "comment": "Remove the deprecated `onDefineParameters`, `execute`, `executeWithoutErrorHandling`, and `onDefineUnscopedParameters` functions." + }, + { + "comment": "Rename `onExecute` to `onExecuteAsync`, `CommandLineParameter` to `CommandLineParameterBase`, and `completions` to `getCompletionsAsync`." + } + ] + } + }, + { + "version": "4.23.7", + "tag": "@rushstack/ts-command-line_v4.23.7", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + } + ] + } + }, + { + "version": "4.23.6", + "tag": "@rushstack/ts-command-line_v4.23.6", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + } + ] + } + }, + { + "version": "4.23.5", + "tag": "@rushstack/ts-command-line_v4.23.5", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + } + ] + } + }, + { + "version": "4.23.4", + "tag": "@rushstack/ts-command-line_v4.23.4", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + } + ] + } + }, + { + "version": "4.23.3", + "tag": "@rushstack/ts-command-line_v4.23.3", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + } + ] + } + }, + { + "version": "4.23.2", + "tag": "@rushstack/ts-command-line_v4.23.2", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + } + ] + } + }, + { + "version": "4.23.1", + "tag": "@rushstack/ts-command-line_v4.23.1", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + } + ] + } + }, + { + "version": "4.23.0", + "tag": "@rushstack/ts-command-line_v4.23.0", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "minor": [ + { + "comment": "Expand the `alternatives` and `completions` options of `CommandLineChoiceParameter` and `CommandLineChoiceListParameter` to allow readonly arrays and sets." + }, + { + "comment": "(BREAKING API CHANGE) Change the type of the `alternatives` property of `CommandLineChoiceParameter` and `CommandLineChoiceParameter` from an array to a `ReadonlySet`." + } + ] + } + }, + { + "version": "4.22.8", + "tag": "@rushstack/ts-command-line_v4.22.8", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + } + ] + } + }, + { + "version": "4.22.7", + "tag": "@rushstack/ts-command-line_v4.22.7", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + } + ] + } + }, + { + "version": "4.22.6", + "tag": "@rushstack/ts-command-line_v4.22.6", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "none": [ + { + "comment": "Fix a README typo." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + } + ] + } + }, + { + "version": "4.22.5", + "tag": "@rushstack/ts-command-line_v4.22.5", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + } + ] + } + }, + { + "version": "4.22.4", + "tag": "@rushstack/ts-command-line_v4.22.4", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "patch": [ + { + "comment": "Remove @internal so that subclasses can call _getArgumentParser" + } + ] + } + }, + { + "version": "4.22.3", + "tag": "@rushstack/ts-command-line_v4.22.3", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + } + ] + } + }, + { + "version": "4.22.2", + "tag": "@rushstack/ts-command-line_v4.22.2", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + } + ] + } + }, + { + "version": "4.22.1", + "tag": "@rushstack/ts-command-line_v4.22.1", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "none": [ + { + "comment": "Improve the `CommandLineParser` error reporting to handle `AlreadyReportedError` from `@rushstack/node-core-library`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + } + ] + } + }, + { + "version": "4.22.0", + "tag": "@rushstack/ts-command-line_v4.22.0", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "minor": [ + { + "comment": "Eliminate a const enum from the public API." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + } + ] + } + }, + { + "version": "4.21.5", + "tag": "@rushstack/ts-command-line_v4.21.5", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + } + ] + } + }, + { + "version": "4.21.4", + "tag": "@rushstack/ts-command-line_v4.21.4", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + } + ] + } + }, + { + "version": "4.21.3", + "tag": "@rushstack/ts-command-line_v4.21.3", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + } + ] + } + }, + { + "version": "4.21.2", + "tag": "@rushstack/ts-command-line_v4.21.2", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + } + ] + } + }, + { + "version": "4.21.1", + "tag": "@rushstack/ts-command-line_v4.21.1", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + } + ] + } + }, + { + "version": "4.21.0", + "tag": "@rushstack/ts-command-line_v4.21.0", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "minor": [ + { + "comment": "Mark `onDefineParameters` and `onDefineUnscopedParameters` as deprecated and update README accordingly because defining parameters causes issues when the compiler targets >=es2022." + } + ] + } + }, + { + "version": "4.20.1", + "tag": "@rushstack/ts-command-line_v4.20.1", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + } + ] + } + }, + { + "version": "4.20.0", + "tag": "@rushstack/ts-command-line_v4.20.0", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "minor": [ + { + "comment": "Rename `CommandLineParser.execute` to `CommandLineParser.executeAsync` and `CommandLineParser.executeWithoutErrorHandling` to `CommandLineParser.executeWithoutErrorHandlingAsync`. The old functions are marked as `@deprecated`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + } + ] + } + }, + { + "version": "4.19.5", + "tag": "@rushstack/ts-command-line_v4.19.5", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + } + ] + } + }, + { + "version": "4.19.4", + "tag": "@rushstack/ts-command-line_v4.19.4", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where tab completions did not suggest parameter values." + } + ] + } + }, + { + "version": "4.19.3", + "tag": "@rushstack/ts-command-line_v4.19.3", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + } + ] + } + }, + { + "version": "4.19.2", + "tag": "@rushstack/ts-command-line_v4.19.2", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + } + ] + } + }, + { + "version": "4.19.1", + "tag": "@rushstack/ts-command-line_v4.19.1", + "date": "Sun, 03 Mar 2024 20:58:12 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `allowNonStandardEnvironmentVariableNames` parameter option had no effect." + } + ] + } + }, + { + "version": "4.19.0", + "tag": "@rushstack/ts-command-line_v4.19.0", + "date": "Sat, 02 Mar 2024 02:22:23 GMT", + "comments": { + "minor": [ + { + "comment": "Use more specific types for command line parameters' `kind` properties." + }, + { + "comment": "Allow parameters that may be backed by an environment variable to be marked as `required`." + }, + { + "comment": "Update the return type of `defineChoiceParameter`, `defineIntegerParameter`, and `defineStringParameter` respectively when the `defaultValue` option is provided to return `IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter` respectively, as the value will definitely be defined in these cases." + } + ], + "patch": [ + { + "comment": "Include a missing `readonly` modifier on the `value` properties of `IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter`." + } + ] + } + }, + { + "version": "4.18.1", + "tag": "@rushstack/ts-command-line_v4.18.1", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "patch": [ + { + "comment": "Add an \"allowNonStandardEnvironmentVariableNames\" option to remove naming restrictions on parameter environment variables" + } + ] + } + }, + { + "version": "4.18.0", + "tag": "@rushstack/ts-command-line_v4.18.0", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "minor": [ + { + "comment": "Allow choice parameters alternatives to be typed." + }, + { + "comment": "Update the return type of `defineChoiceParameter`, `defineIntegerParameter`, and `defineStringParameter` respectively when the `{ required: true }` option is set to a new type (`IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter` respectively) with a required `value` property." + } + ] + } + }, + { + "version": "4.17.4", + "tag": "@rushstack/ts-command-line_v4.17.4", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + } + ] + } + }, + { + "version": "4.17.3", + "tag": "@rushstack/ts-command-line_v4.17.3", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + } + ] + } + }, + { + "version": "4.17.2", + "tag": "@rushstack/ts-command-line_v4.17.2", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ] + } + }, + { + "version": "4.17.1", + "tag": "@rushstack/ts-command-line_v4.17.1", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ] + } + }, + { + "version": "4.17.0", + "tag": "@rushstack/ts-command-line_v4.17.0", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "minor": [ + { + "comment": "Consider parent tool and action parameters when determining ambiguous abbreviations. For example, if a CLI tool `mytool` has a parameter `--myparam` and an action `myaction`, then `myaction` would not accept a parameter named `--myparam` (i.e. - `mytool --myparam myaction` is valid, `mytool myaction --myparam` is not). Additionally, any parameter that can be abbreviated to `--myparam` must be uniquely provided (i.e. - `--myparam-2` can only be abbreviated to `--myparam-`, since any shorter abbreviation would be ambiguous with the original `--myparam` on the tool)." + } + ] + } + }, + { + "version": "4.16.1", + "tag": "@rushstack/ts-command-line_v4.16.1", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ] + } + }, + { + "version": "4.16.0", + "tag": "@rushstack/ts-command-line_v4.16.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + } + ] + } + }, + { + "version": "4.15.2", + "tag": "@rushstack/ts-command-line_v4.15.2", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + } + ] + } + }, + { + "version": "4.15.1", + "tag": "@rushstack/ts-command-line_v4.15.1", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + } + ] + } + }, + { + "version": "4.15.0", + "tag": "@rushstack/ts-command-line_v4.15.0", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for handling ambiguous parameters when conflicting parameters are provided but they provide a non-conflicting alternative (e.g. parameters with the same short-name but different long-names, scoped parameters with the same long-name but different scopes). When using an ambiguous parameter on the CLI, an error message describing the ambiguous parameter usage will appear." + } + ] + } + }, + { + "version": "4.14.0", + "tag": "@rushstack/ts-command-line_v4.14.0", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "minor": [ + { + "comment": "Add AliasCommandLineAction, a CommandLineAction that can be used to redirect commands with optional default arguments to existing commands." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + } + ] + } + }, + { + "version": "4.13.3", + "tag": "@rushstack/ts-command-line_v4.13.3", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + } + ] + } + }, + { + "version": "4.13.2", + "tag": "@rushstack/ts-command-line_v4.13.2", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + } + ] + } + }, + { + "version": "4.13.1", + "tag": "@rushstack/ts-command-line_v4.13.1", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "patch": [ + { + "comment": "Make ScopedCommandLineAction.onDefineUnscopedParameters optional to match CommandLineAciton.onDefineParameters" + } + ] + } + }, + { + "version": "4.13.0", + "tag": "@rushstack/ts-command-line_v4.13.0", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "minor": [ + { + "comment": "Make the onDefineParameters function optional for `CommandLineAction`s and `CommandLineParser`s that either don't have parameters or that define their parameters in their constructor." + } + ] + } + }, + { + "version": "4.12.5", + "tag": "@rushstack/ts-command-line_v4.12.5", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + } + ] + } + }, + { + "version": "4.12.4", + "tag": "@rushstack/ts-command-line_v4.12.4", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + } + ] + } + }, + { + "version": "4.12.3", + "tag": "@rushstack/ts-command-line_v4.12.3", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + } + ] + } + }, + { + "version": "4.12.2", + "tag": "@rushstack/ts-command-line_v4.12.2", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + } + ] + } + }, + { + "version": "4.12.1", + "tag": "@rushstack/ts-command-line_v4.12.1", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + } + ] + } + }, + { + "version": "4.12.0", + "tag": "@rushstack/ts-command-line_v4.12.0", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "minor": [ + { + "comment": "Add parameter scopes. Parameter scopes allow for behind-the-scenes conflict resolution between parameters with the same long name. For example, when provided scope \"my-scope\", a parameter can be referenced on the CLI as \"--my-parameter\" or as \"--my-scope:my-parameter\". In the case that multiple parameters are registered with the same long name but different scopes, the parameters can only be referenced by their scoped long names, eg. \"--my-scope:my-parameter\" and \"--my-other-scope:my-parameter\"." + } + ] + } + }, + { + "version": "4.11.1", + "tag": "@rushstack/ts-command-line_v4.11.1", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + } + ] + } + }, + { + "version": "4.11.0", + "tag": "@rushstack/ts-command-line_v4.11.0", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "minor": [ + { + "comment": "Add ScopedCommandLineAction class, which allows for the definition of actions that have dynamic arguments whose definition depends on a provided scope. See https://github.com/microsoft/rushstack/pull/3364" + } + ] + } + }, + { + "version": "4.10.10", + "tag": "@rushstack/ts-command-line_v4.10.10", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + } + ] + } + }, + { + "version": "4.10.9", + "tag": "@rushstack/ts-command-line_v4.10.9", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + } + ] + } + }, + { + "version": "4.10.8", + "tag": "@rushstack/ts-command-line_v4.10.8", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + } + ] + } + }, + { + "version": "4.10.7", + "tag": "@rushstack/ts-command-line_v4.10.7", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + } + ] + } + }, + { + "version": "4.10.6", + "tag": "@rushstack/ts-command-line_v4.10.6", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + } + ] + } + }, + { + "version": "4.10.5", + "tag": "@rushstack/ts-command-line_v4.10.5", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + } + ] + } + }, + { + "version": "4.10.4", + "tag": "@rushstack/ts-command-line_v4.10.4", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "4.10.3", + "tag": "@rushstack/ts-command-line_v4.10.3", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "4.10.2", + "tag": "@rushstack/ts-command-line_v4.10.2", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "4.10.1", + "tag": "@rushstack/ts-command-line_v4.10.1", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "4.10.0", + "tag": "@rushstack/ts-command-line_v4.10.0", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Add safety check parametersProcessed to CommandLineParameterProvider" + } + ] + } + }, + { + "version": "4.9.1", + "tag": "@rushstack/ts-command-line_v4.9.1", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "4.9.0", + "tag": "@rushstack/ts-command-line_v4.9.0", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add getParameterStringMap to CommandLineParameterProvider, to easily query parameter usage for telemetry" + } + ] + } + }, + { + "version": "4.8.1", + "tag": "@rushstack/ts-command-line_v4.8.1", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "4.8.0", + "tag": "@rushstack/ts-command-line_v4.8.0", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "minor": [ + { + "comment": "Add ChoiceList and IntegerList parameter types" + } + ] + } + }, + { + "version": "4.7.10", + "tag": "@rushstack/ts-command-line_v4.7.10", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "4.7.9", + "tag": "@rushstack/ts-command-line_v4.7.9", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix a mistake in sample code in the README." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "4.7.8", + "tag": "@rushstack/ts-command-line_v4.7.8", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "4.7.7", + "tag": "@rushstack/ts-command-line_v4.7.7", + "date": "Wed, 11 Nov 2020 01:08:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "4.7.6", + "tag": "@rushstack/ts-command-line_v4.7.6", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "4.7.5", + "tag": "@rushstack/ts-command-line_v4.7.5", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "4.7.4", + "tag": "@rushstack/ts-command-line_v4.7.4", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "4.7.3", + "tag": "@rushstack/ts-command-line_v4.7.3", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + } + ] + } + }, + { + "version": "4.7.2", + "tag": "@rushstack/ts-command-line_v4.7.2", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + } + ] + } + }, + { + "version": "4.7.1", + "tag": "@rushstack/ts-command-line_v4.7.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update to build with @rushstack/heft-node-rig" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + } + ] + } + }, + { + "version": "4.7.0", + "tag": "@rushstack/ts-command-line_v4.7.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "minor": [ + { + "comment": "Upgrade compiler; the API now requires TypeScript 3.9 or newer" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + } + ] + } + }, + { + "version": "4.6.10", + "tag": "@rushstack/ts-command-line_v4.6.10", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + } + ] + } + }, + { + "version": "4.6.9", + "tag": "@rushstack/ts-command-line_v4.6.9", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + } + ] + } + }, + { + "version": "4.6.8", + "tag": "@rushstack/ts-command-line_v4.6.8", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + } + ] + } + }, + { + "version": "4.6.7", + "tag": "@rushstack/ts-command-line_v4.6.7", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + } + ] + } + }, + { + "version": "4.6.6", + "tag": "@rushstack/ts-command-line_v4.6.6", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + } + ] + } + }, + { + "version": "4.6.5", + "tag": "@rushstack/ts-command-line_v4.6.5", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + } + ] + } + }, + { + "version": "4.6.4", + "tag": "@rushstack/ts-command-line_v4.6.4", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + } + ] + } + }, + { + "version": "4.6.3", + "tag": "@rushstack/ts-command-line_v4.6.3", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + } + ] + } + }, + { + "version": "4.6.2", + "tag": "@rushstack/ts-command-line_v4.6.2", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + } + ] + } + }, + { + "version": "4.6.1", + "tag": "@rushstack/ts-command-line_v4.6.1", + "date": "Fri, 21 Aug 2020 01:21:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where usage of a parameter specified undocumentedSynonyms yielded invalid data." + } + ] + } + }, + { + "version": "4.6.0", + "tag": "@rushstack/ts-command-line_v4.6.0", + "date": "Thu, 20 Aug 2020 15:13:52 GMT", + "comments": { + "minor": [ + { + "comment": "Add a feature for specifying \"undocumented synonyms\" for parameters." + } + ] + } + }, + { + "version": "4.5.0", + "tag": "@rushstack/ts-command-line_v4.5.0", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for shell tab completion." + } + ] + } + }, + { + "version": "4.4.8", + "tag": "@rushstack/ts-command-line_v4.4.8", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + } + ] + } + }, + { + "version": "4.4.7", + "tag": "@rushstack/ts-command-line_v4.4.7", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + } + ] + } + }, + { + "version": "4.4.6", + "tag": "@rushstack/ts-command-line_v4.4.6", + "date": "Fri, 03 Jul 2020 05:46:41 GMT", + "comments": { + "patch": [ + { + "comment": "Improve formatting of errors reported by CommandLineParser.execute()" + } + ] + } + }, + { + "version": "4.4.5", + "tag": "@rushstack/ts-command-line_v4.4.5", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "4.4.4", + "tag": "@rushstack/ts-command-line_v4.4.4", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "4.4.3", + "tag": "@rushstack/ts-command-line_v4.4.3", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "4.4.2", + "tag": "@rushstack/ts-command-line_v4.4.2", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a typo in the supplementary notes for parameters with environment variable mappings" + } + ] + } + }, + { + "version": "4.4.1", + "tag": "@rushstack/ts-command-line_v4.4.1", + "date": "Wed, 27 May 2020 05:15:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "4.4.0", + "tag": "@rushstack/ts-command-line_v4.4.0", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new feature defineCommandLineRemainder() which allows additional unvalidated CLI arguments, e.g. to pass along to another tool" + }, + { + "comment": "Add the ability for an environment variable to specify multiple values for CommandLineStringListParameter, encoded as a JSON array" + }, + { + "comment": "Fix some bugs that prevented a CommandLineParser from being defined without any actions" + } + ], + "patch": [ + { + "comment": "Fix a bug with environmentVariable mapping for CommandLineFlagParameter" + }, + { + "comment": "Use API Extractor to trim internal APIs from the .d.ts rollup" + }, + { + "comment": "Improve the README.md and API documentation" + } + ] + } + }, + { + "version": "4.3.14", + "tag": "@rushstack/ts-command-line_v4.3.14", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "4.3.13", + "tag": "@rushstack/ts-command-line_v4.3.13", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "4.3.12", "tag": "@rushstack/ts-command-line_v4.3.12", diff --git a/libraries/ts-command-line/CHANGELOG.md b/libraries/ts-command-line/CHANGELOG.md index 9dccbfb8df1..bae39881325 100644 --- a/libraries/ts-command-line/CHANGELOG.md +++ b/libraries/ts-command-line/CHANGELOG.md @@ -1,6 +1,694 @@ # Change Log - @rushstack/ts-command-line -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 5.1.5 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 5.1.4 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 5.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 5.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 5.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 5.1.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 5.0.5 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 5.0.4 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 5.0.3 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 5.0.2 +Wed, 23 Jul 2025 20:55:57 GMT + +### Patches + +- Escape `%` characters in help text to fix an issue where they were previously interpreted as sprintf-style tokens. + +## 5.0.1 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 5.0.0 +Mon, 21 Apr 2025 22:24:25 GMT + +### Breaking changes + +- Remove the deprecated `onDefineParameters`, `execute`, `executeWithoutErrorHandling`, and `onDefineUnscopedParameters` functions. +- Rename `onExecute` to `onExecuteAsync`, `CommandLineParameter` to `CommandLineParameterBase`, and `completions` to `getCompletionsAsync`. + +## 4.23.7 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 4.23.6 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 4.23.5 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 4.23.4 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 4.23.3 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 4.23.2 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 4.23.1 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 4.23.0 +Thu, 17 Oct 2024 08:35:06 GMT + +### Minor changes + +- Expand the `alternatives` and `completions` options of `CommandLineChoiceParameter` and `CommandLineChoiceListParameter` to allow readonly arrays and sets. +- (BREAKING API CHANGE) Change the type of the `alternatives` property of `CommandLineChoiceParameter` and `CommandLineChoiceParameter` from an array to a `ReadonlySet`. + +## 4.22.8 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 4.22.7 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 4.22.6 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 4.22.5 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 4.22.4 +Fri, 02 Aug 2024 17:26:42 GMT + +### Patches + +- Remove @internal so that subclasses can call _getArgumentParser + +## 4.22.3 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 4.22.2 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 4.22.1 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 4.22.0 +Thu, 30 May 2024 00:13:05 GMT + +### Minor changes + +- Eliminate a const enum from the public API. + +## 4.21.5 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 4.21.4 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 4.21.3 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 4.21.2 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 4.21.1 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 4.21.0 +Thu, 16 May 2024 15:10:22 GMT + +### Minor changes + +- Mark `onDefineParameters` and `onDefineUnscopedParameters` as deprecated and update README accordingly because defining parameters causes issues when the compiler targets >=es2022. + +## 4.20.1 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 4.20.0 +Wed, 15 May 2024 06:04:17 GMT + +### Minor changes + +- Rename `CommandLineParser.execute` to `CommandLineParser.executeAsync` and `CommandLineParser.executeWithoutErrorHandling` to `CommandLineParser.executeWithoutErrorHandlingAsync`. The old functions are marked as `@deprecated`. + +## 4.19.5 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 4.19.4 +Wed, 08 May 2024 22:23:50 GMT + +### Patches + +- Fix an issue where tab completions did not suggest parameter values. + +## 4.19.3 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 4.19.2 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 4.19.1 +Sun, 03 Mar 2024 20:58:12 GMT + +### Patches + +- Fix an issue where the `allowNonStandardEnvironmentVariableNames` parameter option had no effect. + +## 4.19.0 +Sat, 02 Mar 2024 02:22:23 GMT + +### Minor changes + +- Use more specific types for command line parameters' `kind` properties. +- Allow parameters that may be backed by an environment variable to be marked as `required`. +- Update the return type of `defineChoiceParameter`, `defineIntegerParameter`, and `defineStringParameter` respectively when the `defaultValue` option is provided to return `IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter` respectively, as the value will definitely be defined in these cases. + +### Patches + +- Include a missing `readonly` modifier on the `value` properties of `IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter`. + +## 4.18.1 +Fri, 01 Mar 2024 01:10:08 GMT + +### Patches + +- Add an "allowNonStandardEnvironmentVariableNames" option to remove naming restrictions on parameter environment variables + +## 4.18.0 +Wed, 28 Feb 2024 16:09:27 GMT + +### Minor changes + +- Allow choice parameters alternatives to be typed. +- Update the return type of `defineChoiceParameter`, `defineIntegerParameter`, and `defineStringParameter` respectively when the `{ required: true }` option is set to a new type (`IRequiredCommandLineChoiceParameter`, `IRequiredCommandLineIntegerParameter`, and `IRequiredCommandLineStringParameter` respectively) with a required `value` property. + +## 4.17.4 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 4.17.3 +Wed, 21 Feb 2024 21:45:28 GMT + +### Patches + +- Replace the dependency on the `colors` package with `Colorize` from `@rushstack/terminal`. + +## 4.17.2 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 4.17.1 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 4.17.0 +Mon, 30 Oct 2023 23:36:37 GMT + +### Minor changes + +- Consider parent tool and action parameters when determining ambiguous abbreviations. For example, if a CLI tool `mytool` has a parameter `--myparam` and an action `myaction`, then `myaction` would not accept a parameter named `--myparam` (i.e. - `mytool --myparam myaction` is valid, `mytool myaction --myparam` is not). Additionally, any parameter that can be abbreviated to `--myparam` must be uniquely provided (i.e. - `--myparam-2` can only be abbreviated to `--myparam-`, since any shorter abbreviation would be ambiguous with the original `--myparam` on the tool). + +## 4.16.1 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 4.16.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 4.15.2 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 4.15.1 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 4.15.0 +Tue, 13 Jun 2023 01:49:01 GMT + +### Minor changes + +- Add support for handling ambiguous parameters when conflicting parameters are provided but they provide a non-conflicting alternative (e.g. parameters with the same short-name but different long-names, scoped parameters with the same long-name but different scopes). When using an ambiguous parameter on the CLI, an error message describing the ambiguous parameter usage will appear. + +## 4.14.0 +Wed, 07 Jun 2023 22:45:16 GMT + +### Minor changes + +- Add AliasCommandLineAction, a CommandLineAction that can be used to redirect commands with optional default arguments to existing commands. + +## 4.13.3 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 4.13.2 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 4.13.1 +Tue, 08 Nov 2022 01:20:55 GMT + +### Patches + +- Make ScopedCommandLineAction.onDefineUnscopedParameters optional to match CommandLineAciton.onDefineParameters + +## 4.13.0 +Mon, 17 Oct 2022 22:14:21 GMT + +### Minor changes + +- Make the onDefineParameters function optional for `CommandLineAction`s and `CommandLineParser`s that either don't have parameters or that define their parameters in their constructor. + +## 4.12.5 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 4.12.4 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 4.12.3 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 4.12.2 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 4.12.1 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 4.12.0 +Thu, 23 Jun 2022 22:14:24 GMT + +### Minor changes + +- Add parameter scopes. Parameter scopes allow for behind-the-scenes conflict resolution between parameters with the same long name. For example, when provided scope "my-scope", a parameter can be referenced on the CLI as "--my-parameter" or as "--my-scope:my-parameter". In the case that multiple parameters are registered with the same long name but different scopes, the parameters can only be referenced by their scoped long names, eg. "--my-scope:my-parameter" and "--my-other-scope:my-parameter". + +## 4.11.1 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 4.11.0 +Tue, 10 May 2022 01:20:43 GMT + +### Minor changes + +- Add ScopedCommandLineAction class, which allows for the definition of actions that have dynamic arguments whose definition depends on a provided scope. See https://github.com/microsoft/rushstack/pull/3364 + +## 4.10.10 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 4.10.9 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 4.10.8 +Sat, 09 Apr 2022 02:24:27 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 4.10.7 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 4.10.6 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 4.10.5 +Mon, 06 Dec 2021 16:08:32 GMT + +_Version update only_ + +## 4.10.4 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 4.10.3 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 4.10.2 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 4.10.1 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 4.10.0 +Mon, 04 Oct 2021 15:10:18 GMT + +### Minor changes + +- Add safety check parametersProcessed to CommandLineParameterProvider + +## 4.9.1 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 4.9.0 +Fri, 20 Aug 2021 15:08:10 GMT + +### Minor changes + +- Add getParameterStringMap to CommandLineParameterProvider, to easily query parameter usage for telemetry + +## 4.8.1 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 4.8.0 +Thu, 01 Jul 2021 15:08:27 GMT + +### Minor changes + +- Add ChoiceList and IntegerList parameter types + +## 4.7.10 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 4.7.9 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 4.7.8 +Thu, 10 Dec 2020 23:25:49 GMT + +_Version update only_ + +## 4.7.7 +Wed, 11 Nov 2020 01:08:59 GMT + +_Version update only_ + +## 4.7.6 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 4.7.5 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 4.7.4 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 4.7.3 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 4.7.2 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 4.7.1 +Wed, 30 Sep 2020 18:39:17 GMT + +### Patches + +- Update to build with @rushstack/heft-node-rig + +## 4.7.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Upgrade compiler; the API now requires TypeScript 3.9 or newer + +### Patches + +- Update README.md + +## 4.6.10 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 4.6.9 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 4.6.8 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 4.6.7 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 4.6.6 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 4.6.5 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 4.6.4 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 4.6.3 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 4.6.2 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 4.6.1 +Fri, 21 Aug 2020 01:21:17 GMT + +### Patches + +- Fix an issue where usage of a parameter specified undocumentedSynonyms yielded invalid data. + +## 4.6.0 +Thu, 20 Aug 2020 15:13:52 GMT + +### Minor changes + +- Add a feature for specifying "undocumented synonyms" for parameters. + +## 4.5.0 +Tue, 18 Aug 2020 23:59:42 GMT + +### Minor changes + +- Add support for shell tab completion. + +## 4.4.8 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 4.4.7 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 4.4.6 +Fri, 03 Jul 2020 05:46:41 GMT + +### Patches + +- Improve formatting of errors reported by CommandLineParser.execute() + +## 4.4.5 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 4.4.4 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 4.4.3 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 4.4.2 +Mon, 01 Jun 2020 08:34:17 GMT + +### Patches + +- Fix a typo in the supplementary notes for parameters with environment variable mappings + +## 4.4.1 +Wed, 27 May 2020 05:15:10 GMT + +_Version update only_ + +## 4.4.0 +Fri, 15 May 2020 08:10:59 GMT + +### Minor changes + +- Add a new feature defineCommandLineRemainder() which allows additional unvalidated CLI arguments, e.g. to pass along to another tool +- Add the ability for an environment variable to specify multiple values for CommandLineStringListParameter, encoded as a JSON array +- Fix some bugs that prevented a CommandLineParser from being defined without any actions + +### Patches + +- Fix a bug with environmentVariable mapping for CommandLineFlagParameter +- Use API Extractor to trim internal APIs from the .d.ts rollup +- Improve the README.md and API documentation + +## 4.3.14 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 4.3.13 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 4.3.12 Wed, 18 Mar 2020 15:07:47 GMT @@ -19,7 +707,7 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 4.3.10 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 4.3.9 Sun, 19 Jan 2020 02:26:52 GMT @@ -31,27 +719,27 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 4.3.8 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 4.3.7 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 4.3.6 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 4.3.5 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 4.3.4 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 4.3.3 Fri, 18 Oct 2019 15:15:00 GMT @@ -187,32 +875,32 @@ Mon, 12 Mar 2018 20:36:19 GMT ## 3.0.6 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 3.0.5 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 3.0.4 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 3.0.3 Wed, 21 Feb 2018 03:13:28 GMT -*Version update only* +_Version update only_ ## 3.0.2 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 3.0.1 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 3.0.0 Fri, 16 Feb 2018 17:05:11 GMT @@ -224,12 +912,12 @@ Fri, 16 Feb 2018 17:05:11 GMT ## 2.3.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 2.3.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 2.3.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -241,12 +929,12 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 2.3.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 2.3.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 2.3.5 Thu, 18 Jan 2018 03:23:46 GMT @@ -258,22 +946,22 @@ Thu, 18 Jan 2018 03:23:46 GMT ## 2.3.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 2.3.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 2.3.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 2.3.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 2.3.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -292,57 +980,57 @@ Tue, 09 Jan 2018 17:05:51 GMT ## 2.2.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 2.2.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 2.2.11 Fri, 05 Jan 2018 00:48:42 GMT -*Version update only* +_Version update only_ ## 2.2.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 2.2.9 Tue, 12 Dec 2017 03:33:27 GMT -*Version update only* +_Version update only_ ## 2.2.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 2.2.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 2.2.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 2.2.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 2.2.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 2.2.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 2.2.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -368,17 +1056,17 @@ Tue, 31 Oct 2017 21:04:04 GMT ## 2.1.4 Tue, 31 Oct 2017 16:04:55 GMT -*Version update only* +_Version update only_ ## 2.1.3 Wed, 25 Oct 2017 20:03:59 GMT -*Version update only* +_Version update only_ ## 2.1.2 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 2.1.1 Mon, 23 Oct 2017 21:53:12 GMT @@ -404,17 +1092,17 @@ Fri, 08 Sep 2017 01:28:04 GMT ## 2.0.6 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 2.0.5 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 2.0.4 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 2.0.3 Tue, 25 Jul 2017 20:03:31 GMT @@ -463,7 +1151,7 @@ Tue, 06 Dec 2016 20:44:26 GMT ## 1.2.0 -*Version update only* +_Version update only_ ## 1.1.0 @@ -474,5 +1162,5 @@ Tue, 06 Dec 2016 20:44:26 GMT ## 1.0.1 -*Initial release* +_Initial release_ diff --git a/libraries/ts-command-line/README.md b/libraries/ts-command-line/README.md index 011ae298b7a..4bc78298cff 100644 --- a/libraries/ts-command-line/README.md +++ b/libraries/ts-command-line/README.md @@ -1,17 +1,22 @@ # ts-command-line -This library helps you create professional command-line tools for Node.js. By "professional", we mean: +This library helps you create professional command-line tools using TypeScript. By "professional", we mean: -- **no gotchas for users**: Seems obvious, but try typing "`npm install --save-dex`" instead of "`npm install --save-dev`" sometime. The command seems to execute successfully, but it doesn't save anything! The misspelled flag was silently ignored. This lack of rigor plagues many familiar NodeJS tools and can be confusing and frustrating. For a great user experience, a command line tool should always be strict about its syntax. +- **no gotchas for users**: Seems obvious, but try typing "`npm install --save-dex`" instead of "`npm install --save-dev`" sometime. The command seems to execute successfully, but it doesn't save anything! The misspelled flag was silently ignored. This lack of rigor plagues many familiar Node.js tools and can be confusing and frustrating. For a great user experience, a command line tool should always be strict about its syntax. -- **no gotchas for developers**: Many command-line libraries store their parsed data in a simple JavaScript hash object. This is convenient for small projects. But suppose a large project has many different source files that define and read parameters. If you try to read `data['output-dir']` when it wasn't defined, or if you misspell the key name, your tool will silently behave as if the parameter was omitted. And is `data['max-count']` a string or a number? Hard to tell! We solve this by modeling each parameter kind as a real TypeScript class. +- **no gotchas for developers**: Many command-line libraries store their parsed data in a simple JavaScript object. This is convenient for small projects. But suppose a large project has many different source files that define and read parameters. If you try to read `data['output-dir']` when it wasn't defined, or if you misspell the key name, your tool will silently behave as if the parameter was omitted. And is `data['max-count']` a string or a number? Hard to tell! We solve this by modeling each parameter kind as a real TypeScript class. -- **automatic documentation**: Some command-line libraries treat the `--help` docs as someone else's job. **ts-command-line** requires each every parameter to have a documentation string, and will automatically generate the `--help` docs for you. If you like to write long paragraphs, no problem -- they will be word-wrapped correctly. *[golf clap]* +- **simple by design**: Making a CLI is similar to making a graphical UI -- some people have a knack for clean and intuitive designs, but your average developer... needs some help. :-) Keeping things simple is the best help. **ts-command-line** intentionally provides a minimalist set of CLI building blocks that encourage simple designs. If your app has lots of knobs and switches, we recommend NOT to design a complex CLI with hundreds of parameters. Move those options into a commented config file with a published JSON schema. -- **structure and extensibility**: Instead of a simple function chain, **ts-command-line** provides a "scaffold" pattern that makes it easy to find and understand the command-line implementation for any tool project. The scaffold model is generally recommended, but there's also a "dynamic" model if you need it. See below for examples. +- **automatic documentation**: Some command-line libraries treat the `--help` docs as someone else's job. **ts-command-line** requires each every parameter to follow a standardized naming pattern and have a documentation string. It will automatically generate the `--help` docs for you. If you like to write long paragraphs, no problem -- they will be word-wrapped correctly. *[golf clap]* -Internally, the implementation is based on [argparse](https://www.npmjs.com/package/argparse) and the Python approach to command-lines. Compared to other libraries, **ts-command-line** doesn't provide zillions of custom syntaxes and bells and whistles. Instead it aims to be a simple, consistent, and professional solution for your command-line tool. Give it a try! +- **structure and extensibility**: Instead of a simple function chain, **ts-command-line** provides a "scaffold" pattern that makes it easy to find and understand the command-line implementation for any tool project. The scaffold model is generally recommended, but there's also a "dynamic" model if you need it. See below for examples. +- **environment variable mappings**: Any CLI parameter can be associated with an environment variable. If the parameter is not explicitly provided, the value from the environment will be used. The associated environment variables are automatically documented in the `--help`. + +Internally, the implementation is based on [argparse](https://www.npmjs.com/package/argparse) and the Python approach to command-lines. + +Compared to other libraries, **ts-command-line** doesn't provide zillions of custom syntaxes and bells and whistles. Instead it aims to be a simple, consistent, and professional solution for your command-line tool. Give it a try! ### Some Terminology @@ -25,13 +30,27 @@ In this example, we can identify the following components: - The **tool name** in this example is `widget`. This is the name of your Node.js bin script. - The **parameters** are `--verbose`, `--force`, and `--max-count`. -- The currently supported **parameter kinds** include: **flag** (i.e. boolean), **integer**, **string**, **choice** (i.e. enums), and **string list**. - The value "123" is the **argument** for the `--max-count` integer parameter. (Flags don't have arguments, because their value is determined by whether the flag was provided or not.) - Similar to Git's command-line, the `push` token is called an **action**. It acts as sub-command with its own unique set of parameters. - The `--verbose` flag is a **global parameter** because it precedes the action name. It affects all actions. - The `--force` flag is an **action parameter** because it comes after the action name. It only applies to that action. +### Parameter Kinds + +Several different kinds of parameters are supported: + +| Parameter Kind | Example | Data Type | Description | +| --- | --- | --- | --- | +| flag | `--verbose` | `boolean` | Value is `true` if the flag was specified on the command line, `false` otherwise. | +| integer | `--max-retry 3` | `int` | The argument is an integer number | +| string | `--title "Hello, world"` | `string` | The argument is a text string. | +| choice | `--color red` | `string` | The argument must be a string from a list of allowed choices (similar to an enum). | +| string list | `-o file1.txt -o file2.txt` | `string[]` | The argument is a text string. The parameter can be specified multiple times to build a list. | + +Other parameter kinds could be implemented if requested. That said, keeping your CLI grammar simple and systematic makes it easier for users to learn. + + ## Scaffold Model If your tool uses the scaffold model, you will create subclasses of two abstract base classes: `CommandLineParser` for the overall command-line, and `CommandLineAction` for each action. @@ -45,27 +64,34 @@ widget --verbose push --force We could define our subclass for the "`push`" action like this: ```typescript -class PushAction extends CommandLineAction { +export class PushAction extends CommandLineAction { private _force: CommandLineFlagParameter; + private _protocol: CommandLineChoiceParameter; public constructor() { super({ actionName: 'push', summary: 'Pushes a widget to the service', - documentation: 'Your long description goes here.' + documentation: 'Here we provide a longer description of how our action works.' }); - } - protected onExecute(): Promise { // abstract - return BusinessLogic.doTheWork(this._force.value); - } - - protected onDefineParameters(): void { // abstract this._force = this.defineFlagParameter({ parameterLongName: '--force', parameterShortName: '-f', description: 'Push and overwrite any existing state' }); + + this._protocol = this.defineChoiceParameter({ + parameterLongName: '--protocol', + description: 'Specify the protocol to use', + alternatives: ['ftp', 'webdav', 'scp'], + environmentVariable: 'WIDGET_PROTOCOL', + defaultValue: 'scp' + }); + } + + protected override async onExecuteAsync(): Promise { // abstract + await BusinessLogic.doTheWork(this._force.value, this._protocol.value || "(none)"); } } ``` @@ -73,19 +99,17 @@ class PushAction extends CommandLineAction { Then we might define the parser subclass like this: ```typescript -class WidgetCommandLine extends CommandLineParser { +export class WidgetCommandLine extends CommandLineParser { private _verbose: CommandLineFlagParameter; public constructor() { super({ toolFilename: 'widget', - toolDescription: 'The widget tool is really great.' + toolDescription: 'The "widget" tool is a code sample for using the @rushstack/ts-command-line library.' }); this.addAction(new PushAction()); - } - protected onDefineParameters(): void { // abstract this._verbose = this.defineFlagParameter({ parameterLongName: '--verbose', parameterShortName: '-v', @@ -93,9 +117,9 @@ class WidgetCommandLine extends CommandLineParser { }); } - protected onExecute(): Promise { // override + protected override async onExecuteAsync(): Promise { BusinessLogic.configureLogger(this._verbose.value); - return super.onExecute(); + await super.onExecuteAsync(); } } ``` @@ -104,11 +128,16 @@ To invoke the parser, the application entry point will do something like this: ```typescript const commandLine: WidgetCommandLine = new WidgetCommandLine(); -commandLine.execute(); +commandLine.executeAsync(); ``` When we run `widget --verbose push --force`, the `PushAction.onExecute()` method will get invoked and then your business logic takes over. +--- + +**For a more complete example, take a look at the [ts-command-line-test](https://github.com/microsoft/rushstack/tree/main/build-tests/ts-command-line-test) sample project.** + +--- #### Testing out the docs @@ -117,7 +146,8 @@ If you invoke the tool as "`widget --help`", the docs are automatically generate ``` usage: widget [-h] [-v] ... -The widget tool is really great. +The "widget" tool is a code sample for using the @rushstack/ts-command-line +library. Positional arguments: @@ -133,13 +163,17 @@ For detailed help about a specific command, use: widget -h For help about the `push` action, the user can type "`widget push --help`", which shows this output: ``` -usage: widget push [-h] [-f] +usage: widget push [-h] [-f] [--protocol {ftp,webdav,scp}] -Your long description goes here. +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 + -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". ``` ## Dynamic Model @@ -155,8 +189,9 @@ In this case, you can use the `DynamicCommandLineAction` and `DynamicCommandLine // Define the parser const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser({ toolFilename: 'widget', - toolDescription: 'The widget tool is really great.' + toolDescription: 'The "widget" tool is a code sample for using the @rushstack/ts-command-line library.' }); + commandLineParser.defineFlagParameter({ parameterLongName: '--verbose', parameterShortName: '-v', @@ -167,8 +202,9 @@ commandLineParser.defineFlagParameter({ const action: DynamicCommandLineAction = new DynamicCommandLineAction({ actionName: 'push', summary: 'Pushes a widget to the service', - documentation: 'More detail about the "push" action' + documentation: 'Here we provide a longer description of how our action works.' }); + commandLineParser.addAction(action); action.defineFlagParameter({ @@ -177,8 +213,16 @@ action.defineFlagParameter({ description: 'Push and overwrite any existing state' }); +action.defineChoiceParameter({ + parameterLongName: '--protocol', + description: 'Specify the protocol to use', + alternatives: ['ftp', 'webdav', 'scp'], + environmentVariable: 'WIDGET_PROTOCOL', + defaultValue: 'scp' +}); + // Parse the command line -commandLineParser.execute(process.argv).then(() => { +commandLineParser.executeAsync().then(() => { console.log('The action is: ' + commandLineParser.selectedAction!.actionName); console.log('The force flag is: ' + action.getFlagParameter('--force').value); }); @@ -187,13 +231,17 @@ commandLineParser.execute(process.argv).then(() => { You can also mix the two models. For example, we could augment the `WidgetCommandLine` from the original model by adding `DynamicAction` objects to it. -### Further reading +## Links -The [API reference](https://rushstack.io/pages/api/ts-command-line/) has -complete documentation for the library. +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/ts-command-line/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/ts-command-line/) Here are some real world GitHub projects that illustrate different use cases for **ts-command-line**: - [@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) - [@microsoft/api-extractor](https://www.npmjs.com/package/@microsoft/api-extractor) - [@microsoft/api-documenter](https://www.npmjs.com/package/@microsoft/api-documenter) + +`@rushstack/ts-command-line` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/ts-command-line/config/api-extractor.json b/libraries/ts-command-line/config/api-extractor.json index 996e271d3dd..7454dd5c1d9 100644 --- a/libraries/ts-command-line/config/api-extractor.json +++ b/libraries/ts-command-line/config/api-extractor.json @@ -14,6 +14,8 @@ }, "dtsRollup": { - "enabled": true + "enabled": true, + "untrimmedFilePath": "", + "publicTrimmedFilePath": "/dist/.d.ts" } } diff --git a/libraries/ts-command-line/config/jest.config.json b/libraries/ts-command-line/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/ts-command-line/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/ts-command-line/config/jest.json b/libraries/ts-command-line/config/jest.json deleted file mode 100644 index b4a7ec97a56..00000000000 --- a/libraries/ts-command-line/config/jest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "isEnabled": true -} \ No newline at end of file diff --git a/libraries/ts-command-line/config/rig.json b/libraries/ts-command-line/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/ts-command-line/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/ts-command-line/eslint.config.js b/libraries/ts-command-line/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/libraries/ts-command-line/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/ts-command-line/gulpfile.js b/libraries/ts-command-line/gulpfile.js deleted file mode 100644 index cf8fd436e63..00000000000 --- a/libraries/ts-command-line/gulpfile.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.jest.setConfig({ coverageReporters: ['json'] }); // Temporary - until the Handlebars issue is fixed - -build.initialize(require('gulp')); diff --git a/libraries/ts-command-line/package.json b/libraries/ts-command-line/package.json index b4f21ceb834..9bf5bce2afd 100644 --- a/libraries/ts-command-line/package.json +++ b/libraries/ts-command-line/package.json @@ -1,28 +1,30 @@ { "name": "@rushstack/ts-command-line", - "version": "4.3.12", + "version": "5.1.5", "description": "An object-oriented command-line parser for TypeScript", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/libraries/ts-command-line" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/ts-command-line" }, "main": "lib/index.js", "typings": "dist/ts-command-line.d.ts", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "license": "MIT", "dependencies": { - "@types/argparse": "1.0.33", + "@rushstack/terminal": "workspace:*", + "@types/argparse": "1.0.38", "argparse": "~1.0.9", - "colors": "~1.2.1" + "string-argv": "~0.3.1" }, "devDependencies": { - "@types/jest": "23.3.11", - "@types/node": "10.17.13", - "gulp": "~4.0.2", - "@microsoft/node-library-build": "6.4.5", - "@microsoft/rush-stack-compiler-3.5": "0.4.4", - "@rushstack/eslint-config": "0.5.5" + "@rushstack/heft": "1.1.4", + "@rushstack/node-core-library": "workspace:*", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" } } diff --git a/libraries/ts-command-line/src/CommandLineAction.ts b/libraries/ts-command-line/src/CommandLineAction.ts deleted file mode 100644 index b1a35eb9250..00000000000 --- a/libraries/ts-command-line/src/CommandLineAction.ts +++ /dev/null @@ -1,125 +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 argparse from 'argparse'; -import { CommandLineParameterProvider, ICommandLineParserData } from './CommandLineParameterProvider'; - -/** - * Options for the CommandLineAction constructor. - * @public - */ -export interface ICommandLineActionOptions { - /** - * The name of the action. For example, if the tool is called "example", - * then the "build" action might be invoked as: "example build -q --some-other-option" - */ - actionName: string; - - /** - * A quick summary that is shown on the main help page, which is displayed - * by the command "example --help" - */ - summary: string; - - /** - * A detailed description that is shown on the action help page, which is displayed - * by the command "example build --help", e.g. for actionName="build". - */ - documentation: string; -} - -/** - * Represents a sub-command that is part of the CommandLineParser command line. - * Applications should create subclasses of CommandLineAction corresponding to - * each action that they want to expose. - * - * The action name should be comprised of lower case words separated by hyphens - * or colons. The name should include an English verb (e.g. "deploy"). Use a - * hyphen to separate words (e.g. "upload-docs"). A group of related commands - * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", - * "docs:serve", etc). - * - * @public - */ -export abstract class CommandLineAction extends CommandLineParameterProvider { - // Example: "do-something" - private static _actionNameRegExp: RegExp = /^[a-z][a-z0-9]*([-:][a-z0-9]+)*$/; - - /** {@inheritDoc ICommandLineActionOptions.actionName} */ - public readonly actionName: string; - - /** {@inheritDoc ICommandLineActionOptions.summary} */ - public readonly summary: string; - - /** {@inheritDoc ICommandLineActionOptions.documentation} */ - public readonly documentation: string; - - private _argumentParser: argparse.ArgumentParser | undefined; - - public constructor(options: ICommandLineActionOptions) { - super(); - - if (!CommandLineAction._actionNameRegExp.test(options.actionName)) { - throw new Error(`Invalid action name "${options.actionName}". ` - + `The name must be comprised of lower-case words optionally separated by hyphens or colons.`); - } - - this.actionName = options.actionName; - this.summary = options.summary; - this.documentation = options.documentation; - - this._argumentParser = undefined; - } - - /** - * This is called internally by CommandLineParser.addAction() - * @internal - */ - public _buildParser(actionsSubParser: argparse.SubParser): void { - this._argumentParser = actionsSubParser.addParser(this.actionName, { - help: this.summary, - description: this.documentation - }); - - this.onDefineParameters(); - } - - /** - * This is called internally by CommandLineParser.execute() - * @internal - */ - public _processParsedData(data: ICommandLineParserData): void { - super._processParsedData(data); - } - - /** - * Invoked by CommandLineParser.onExecute(). - * @internal - */ - public _execute(): Promise { - return this.onExecute(); - } - - /** - * {@inheritDoc CommandLineParameterProvider._getArgumentParser} - * @internal - */ - protected _getArgumentParser(): argparse.ArgumentParser { // override - if (!this._argumentParser) { - // We will improve this in the future - throw new Error('The CommandLineAction must be added to a CommandLineParser before it can be used'); - } - - return this._argumentParser; - } - - /** - * {@inheritDoc CommandLineParameterProvider.onDefineParameters} - */ - protected abstract onDefineParameters(): void; - - /** - * Your subclass should implement this hook to perform the operation. - */ - protected abstract onExecute(): Promise; -} diff --git a/libraries/ts-command-line/src/CommandLineDefinition.ts b/libraries/ts-command-line/src/CommandLineDefinition.ts deleted file mode 100644 index 8c42a5f6f8d..00000000000 --- a/libraries/ts-command-line/src/CommandLineDefinition.ts +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * For use with CommandLineParser, this interface represents a generic command-line parameter - * - * @public - */ -export interface IBaseCommandLineDefinition { - /** - * The long name of the flag including double dashes, e.g. "--do-something" - */ - parameterLongName: string; - - /** - * An optional short name for the flag including the dash, e.g. "-d" - */ - parameterShortName?: string; - - /** - * Documentation for the flag, that will be shown when invoking the tool with "--help" - */ - description: string; - - /** - * If true, then an error occurs if the parameter was not included on the command-line. - */ - required?: boolean; - - /** - * The name of an environment variable that the parameter value will be read from, - * if it was omitted from the command-line. An error will be reported if the - * environment value cannot be parsed. - * @remarks - * The environment variable name must consist only of upper-case letters, numbers, - * and underscores. It may not start with a number. - * - * This feature cannot be used when {@link IBaseCommandLineDefinition.required} is true, - * because in that case the environmentVariable would never be used. - */ - environmentVariable?: string; -} - -/** - * The common base interface for parameter types that accept an argument. - * - * @remarks - * An argument is an accompanying command-line token, such as "123" in the - * example "--max-count 123". - * @public - */ -export interface IBaseCommandLineDefinitionWithArgument extends IBaseCommandLineDefinition { - /** - * The name of the argument, which will be shown in the command-line help. - * - * @remarks - * For example, if the parameter name is '--count" and the argument name is "NUMBER", - * then the command-line help would display "--count NUMBER". The argument name must - * be comprised of upper-case letters, numbers, and underscores. It should be kept short. - */ - argumentName: string; -} - -/** - * For use with CommandLineParser, this interface represents a parameter which is constrained to - * a list of possible options - * - * @public - */ -export interface ICommandLineChoiceDefinition extends IBaseCommandLineDefinition { - /** - * A list of strings (which contain no spaces), of possible options which can be selected - */ - alternatives: string[]; - - /** - * {@inheritDoc ICommandLineStringDefinition.defaultValue} - */ - defaultValue?: string; -} - -/** - * For use with CommandLineParser, this interface represents a command line parameter - * that is a boolean flag. - * - * @public - */ -export interface ICommandLineFlagDefinition extends IBaseCommandLineDefinition { } - -/** - * For use with CommandLineParser, this interface represents a command line parameter - * whose argument is an integer value. - * - * @public - */ -export interface ICommandLineIntegerDefinition extends IBaseCommandLineDefinitionWithArgument { - /** - * {@inheritDoc ICommandLineStringDefinition.defaultValue} - */ - defaultValue?: number; -} - -/** - * For use with CommandLineParser, this interface represents a command line parameter - * whose argument is a string value. - * - * @public - */ -export interface ICommandLineStringDefinition extends IBaseCommandLineDefinitionWithArgument { - /** - * The default value which will be used if the parameter is omitted from the command line. - * - * @remarks - * If a default value is specified, then {@link IBaseCommandLineDefinition.required} - * must not be true. Instead, a custom error message should be used to report cases - * where a default value was not available. - */ - defaultValue?: string; -} - -/** - * For use with CommandLineParser, this interface represents a command line parameter - * whose argument is a list of strings. - * - * @public - */ -export interface ICommandLineStringListDefinition extends IBaseCommandLineDefinitionWithArgument { } diff --git a/libraries/ts-command-line/src/CommandLineHelper.ts b/libraries/ts-command-line/src/CommandLineHelper.ts new file mode 100644 index 00000000000..45022d393e7 --- /dev/null +++ b/libraries/ts-command-line/src/CommandLineHelper.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 { CommandLineConstants } from './Constants'; + +/** + * Helpers for working with the ts-command-line API. + * + * @public + */ +export class CommandLineHelper { + /** + * Returns true if the current command line action is tab-complete. + * + * @public + */ + public static isTabCompletionActionRequest(argv: string[]): boolean { + return argv && argv.length > 2 && argv[2] === CommandLineConstants.TabCompletionActionName; + } +} diff --git a/libraries/ts-command-line/src/CommandLineParameter.ts b/libraries/ts-command-line/src/CommandLineParameter.ts deleted file mode 100644 index b010812d009..00000000000 --- a/libraries/ts-command-line/src/CommandLineParameter.ts +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - IBaseCommandLineDefinition, - ICommandLineFlagDefinition, - ICommandLineStringDefinition, - ICommandLineStringListDefinition, - ICommandLineIntegerDefinition, - ICommandLineChoiceDefinition, - IBaseCommandLineDefinitionWithArgument -} from './CommandLineDefinition'; - -/** - * Identifies the kind of a CommandLineParameter. - * @public - */ -export enum CommandLineParameterKind { - /** Indicates a CommandLineChoiceParameter */ - Choice, - /** Indicates a CommandLineFlagParameter */ - Flag, - /** Indicates a CommandLineIntegerParameter */ - Integer, - /** Indicates a CommandLineStringParameter */ - String, - /** Indicates a CommandLineStringListParameter */ - StringList -} - -/** - * The base class for the various command-line parameter types. - * @public - */ -export abstract class CommandLineParameter { - // Example: "--do-something" - private static _longNameRegExp: RegExp = /^-(-[a-z0-9]+)+$/; - - // Example: "-d" - private static _shortNameRegExp: RegExp = /^-[a-zA-Z]$/; - - // "Environment variable names used by the utilities in the Shell and Utilities volume of - // IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the '_' (underscore) - // from the characters defined in Portable Character Set and do not begin with a digit." - // Example: "THE_SETTING" - private static _environmentVariableRegExp: RegExp = /^[A-Z_][A-Z0-9_]*$/; - - /** - * A unique internal key used to retrieve the value from the parser's dictionary. - * @internal - */ - public _parserKey: string; - - /** {@inheritDoc IBaseCommandLineDefinition.parameterLongName} */ - public readonly longName: string; - - /** {@inheritDoc IBaseCommandLineDefinition.parameterShortName} */ - public readonly shortName: string | undefined; - - /** {@inheritDoc IBaseCommandLineDefinition.description} */ - public readonly description: string; - - /** {@inheritDoc IBaseCommandLineDefinition.required} */ - public readonly required: boolean; - - /** {@inheritDoc IBaseCommandLineDefinition.environmentVariable} */ - public readonly environmentVariable: string | undefined; - - /** @internal */ - public constructor(definition: IBaseCommandLineDefinition) { - this.longName = definition.parameterLongName; - this.shortName = definition.parameterShortName; - this.description = definition.description; - this.required = !!definition.required; - this.environmentVariable = definition.environmentVariable; - - if (!CommandLineParameter._longNameRegExp.test(this.longName)) { - throw new Error(`Invalid name: "${this.longName}". The parameter long name must be` - + ` lower-case and use dash delimiters (e.g. "--do-a-thing")`); - } - - if (this.shortName) { - if (!CommandLineParameter._shortNameRegExp.test(this.shortName)) { - throw new Error(`Invalid name: "${this.shortName}". The parameter short name must be` - + ` a dash followed by a single upper-case or lower-case letter (e.g. "-a")`); - } - } - - if (this.environmentVariable) { - if (this.required) { - throw new Error(`An "environmentVariable" cannot be specified for "${this.longName}"` - + ` because it is a required parameter`); - } - - if (!CommandLineParameter._environmentVariableRegExp.test(this.environmentVariable)) { - throw new Error(`Invalid environment variable name: "${this.environmentVariable}". The name must` - + ` consist only of upper-case letters, numbers, and underscores. It may not start with a number.`); - } - } - } - - /** - * Called internally by CommandLineParameterProvider._processParsedData() - * @internal - */ - public abstract _setValue(data: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any - - /** - * Returns additional text used by the help formatter. - * @internal - */ - public _getSupplementaryNotes(supplementaryNotes: string[]): void { // virtual - if (this.environmentVariable !== undefined) { - supplementaryNotes.push('This parameter may alternatively specified via the ' + this.environmentVariable - + ' environment variable.'); - } - } - - /** - * Indicates the type of parameter. - */ - public abstract get kind(): CommandLineParameterKind; - - /** - * Append the parsed values to the provided string array. - * @remarks - * Sometimes a command line parameter is not used directly, but instead gets passed through to another - * tool that will use it. For example if our parameter comes in as "--max-count 3", then we might want to - * call `child_process.spawn()` and append ["--max-count", "3"] to the args array for that tool. - * appendToArgList() appends zero or more strings to the provided array, based on the input command-line - * that we parsed. - * - * If the parameter was omitted from our command-line and has no default value, then - * nothing will be appended. If the short name was used, the long name will be appended instead. - * @param argList - the parsed strings will be appended to this string array - */ - public abstract appendToArgList(argList: string[]): void; - - /** - * Internal usage only. Used to report unexpected output from the argparse library. - */ - protected reportInvalidData(data: any): never { // eslint-disable-line @typescript-eslint/no-explicit-any - throw new Error(`Unexpected data object for parameter "${this.longName}": ` - + JSON.stringify(data)); - } - - protected validateDefaultValue(hasDefaultValue: boolean): void { - if (this.required && hasDefaultValue) { - // If a parameter is "required", then the user understands that they always need to - // specify a value for this parameter (either via the command line or via an environment variable). - // It would be confusing to allow a default value that sometimes allows the "required" parameter - // to be omitted. If you sometimes don't have a suitable default value, then the better approach - // is to throw a custom error explaining why the parameter is required in that case. - throw new Error(`A default value cannot be specified for "${this.longName}"` - + ` because it is a "required" parameter`); - } - } -} - -/** - * The common base class for parameters types that receive an argument. - * - * @remarks - * An argument is an accompanying command-line token, such as "123" in the - * example "--max-count 123". - * @public - */ -export abstract class CommandLineParameterWithArgument extends CommandLineParameter { - // Matches the first character that *isn't* part of a valid upper-case argument name such as "URL_2" - private static _invalidArgumentNameRegExp: RegExp = /[^A-Z_0-9]/; - - /** {@inheritDoc IBaseCommandLineDefinitionWithArgument.argumentName} */ - public readonly argumentName: string; - - /** @internal */ - public constructor(definition: IBaseCommandLineDefinitionWithArgument) { - super(definition); - - if (definition.argumentName === '') { - throw new Error('The argument name cannot be an empty string. (For the default name, specify undefined.)'); - } - if (definition.argumentName.toUpperCase() !== definition.argumentName) { - throw new Error(`Invalid name: "${definition.argumentName}". The argument name must be all upper case.`); - } - const match: RegExpMatchArray | null = definition.argumentName.match( - CommandLineParameterWithArgument._invalidArgumentNameRegExp); - if (match) { - throw new Error(`The argument name "${definition.argumentName}" contains an invalid character "${match[0]}".` - + ` Only upper-case letters, numbers, and underscores are allowed.`); - } - this.argumentName = definition.argumentName; - } -} - -/** - * The data type returned by {@link CommandLineParameterProvider.defineChoiceParameter}. - * @public - */ -export class CommandLineChoiceParameter extends CommandLineParameter { - /** {@inheritDoc ICommandLineChoiceDefinition.alternatives} */ - public readonly alternatives: ReadonlyArray; - - /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ - public readonly defaultValue: string | undefined; - - private _value: string | undefined = undefined; - - /** @internal */ - public constructor(definition: ICommandLineChoiceDefinition) { - super(definition); - - if (definition.alternatives.length < 1) { - throw new Error(`When defining a choice parameter, the alternatives list must contain at least one value.`); - } - if (definition.defaultValue && definition.alternatives.indexOf(definition.defaultValue) === -1) { - throw new Error(`The specified default value "${definition.defaultValue}"` - + ` is not one of the available options: ${definition.alternatives.toString()}`); - } - - this.alternatives = definition.alternatives; - this.defaultValue = definition.defaultValue; - this.validateDefaultValue(!!this.defaultValue); - } - - /** {@inheritDoc CommandLineParameter.kind} */ - public get kind(): CommandLineParameterKind { - return CommandLineParameterKind.Choice; - } - - /** - * {@inheritDoc CommandLineParameter._setValue} - * @internal - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _setValue(data: any): void { // abstract - if (data !== null && data !== undefined) { - if (typeof data !== 'string') { - this.reportInvalidData(data); - } - this._value = data; - return; - } - - if (this.environmentVariable !== undefined) { - // Try reading the environment variable - const environmentValue: string | undefined = process.env[this.environmentVariable]; - if (environmentValue !== undefined && environmentValue !== '') { - if (this.alternatives.indexOf(environmentValue) < 0) { - const choices: string = '"' + this.alternatives.join('", "') + '"'; - throw new Error(`Invalid value "${environmentValue}" for the environment variable` - + ` ${this.environmentVariable}. Valid choices are: ${choices}`); - } - this._value = environmentValue; - return; - } - } - - if (this.defaultValue !== undefined) { - this._value = this.defaultValue; - return; - } - - this._value = undefined; - } - - /** - * {@inheritDoc CommandLineParameter._getSupplementaryNotes} - * @internal - */ - public _getSupplementaryNotes(supplementaryNotes: string[]): void { // virtual - super._getSupplementaryNotes(supplementaryNotes); - if (this.defaultValue !== undefined) { - supplementaryNotes.push(`The default value is "${this.defaultValue}".`); - } - } - - /** - * Returns the argument value for a choice parameter that was parsed from the command line. - * - * @remarks - * The return value will be `undefined` if the command-line has not been parsed yet, - * or if the parameter was omitted and has no default value. - */ - public get value(): string | undefined { - return this._value; - } - - /** {@inheritDoc CommandLineParameter.appendToArgList} @override */ - public appendToArgList(argList: string[]): void { - if (this.value !== undefined) { - argList.push(this.longName); - argList.push(this.value); - } - } -} - -/** - * The data type returned by {@link CommandLineParameterProvider.defineFlagParameter}. - * @public - */ -export class CommandLineFlagParameter extends CommandLineParameter { - private _value: boolean = false; - - /** @internal */ - public constructor(definition: ICommandLineFlagDefinition) { - super(definition); - } - - /** {@inheritDoc CommandLineParameter.kind} */ - public get kind(): CommandLineParameterKind { - return CommandLineParameterKind.Flag; - } - - /** - * {@inheritDoc CommandLineParameter._setValue} - * @internal - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _setValue(data: any): void { // abstract - if (data !== null && data !== undefined) { - if (typeof data !== 'boolean') { - this.reportInvalidData(data); - } - this._value = data; - return; - } - - if (this.environmentVariable !== undefined) { - // Try reading the environment variable - const environmentValue: string | undefined = process.env[this.environmentVariable]; - if (environmentValue !== undefined && environmentValue !== '') { - if (environmentValue !== '0' && environmentValue !== '1') { - throw new Error(`Invalid value "${environmentValue}" for the environment variable` - + ` ${this.environmentVariable}. Valid choices are 0 or 1.`); - } - this._value = environmentValue === '1'; - return; - } - } - - this._value = false; - } - - /** - * Returns a boolean indicating whether the parameter was included in the command line. - * - * @remarks - * The return value will be false if the command-line has not been parsed yet, - * or if the flag was not used. - */ - public get value(): boolean { - return this._value; - } - - /** {@inheritDoc CommandLineParameter.appendToArgList} @override */ - public appendToArgList(argList: string[]): void { - if (this.value) { - argList.push(this.longName); - } - } -} - -/** - * The data type returned by {@link CommandLineParameterProvider.defineIntegerParameter}. - * @public - */ -export class CommandLineIntegerParameter extends CommandLineParameterWithArgument { - /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ - public readonly defaultValue: number | undefined; - - private _value: number | undefined = undefined; - - /** @internal */ - public constructor(definition: ICommandLineIntegerDefinition) { - super(definition); - this.defaultValue = definition.defaultValue; - this.validateDefaultValue(!!this.defaultValue); - } - - /** {@inheritDoc CommandLineParameter.kind} */ - public get kind(): CommandLineParameterKind { - return CommandLineParameterKind.Integer; - } - - /** - * {@inheritDoc CommandLineParameter._setValue} - * @internal - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _setValue(data: any): void { // abstract - if (data !== null && data !== undefined) { - if (typeof data !== 'number') { - this.reportInvalidData(data); - } - this._value = data; - return; - } - - if (this.environmentVariable !== undefined) { - // Try reading the environment variable - const environmentValue: string | undefined = process.env[this.environmentVariable]; - if (environmentValue !== undefined && environmentValue !== '') { - const parsed: number = parseInt(environmentValue, 10); - if (isNaN(parsed) || environmentValue.indexOf('.') >= 0) { - throw new Error(`Invalid value "${environmentValue}" for the environment variable` - + ` ${this.environmentVariable}. It must be an integer value.`); - } - this._value = parsed; - return; - } - } - - if (this.defaultValue !== undefined) { - this._value = this.defaultValue; - return; - } - - this._value = undefined; - } - - /** - * {@inheritDoc CommandLineParameter._getSupplementaryNotes} - * @internal - */ - public _getSupplementaryNotes(supplementaryNotes: string[]): void { // virtual - super._getSupplementaryNotes(supplementaryNotes); - if (this.defaultValue !== undefined) { - supplementaryNotes.push(`The default value is ${this.defaultValue}.`); - } - } - - /** - * Returns the argument value for an integer parameter that was parsed from the command line. - * - * @remarks - * The return value will be undefined if the command-line has not been parsed yet, - * or if the parameter was omitted and has no default value. - */ - public get value(): number | undefined { - return this._value; - } - - /** {@inheritDoc CommandLineParameter.appendToArgList} @override */ - public appendToArgList(argList: string[]): void { - if (this.value !== undefined) { - argList.push(this.longName); - argList.push(this.value.toString()); - } - } -} - -/** - * The data type returned by {@link CommandLineParameterProvider.defineStringParameter}. - * @public - */ -export class CommandLineStringParameter extends CommandLineParameterWithArgument { - /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ - public readonly defaultValue: string | undefined; - - private _value: string | undefined = undefined; - - /** @internal */ - public constructor(definition: ICommandLineStringDefinition) { - super(definition); - - this.defaultValue = definition.defaultValue; - this.validateDefaultValue(!!this.defaultValue); - } - - /** {@inheritDoc CommandLineParameter.kind} */ - public get kind(): CommandLineParameterKind { - return CommandLineParameterKind.String; - } - - /** - * {@inheritDoc CommandLineParameter._setValue} - * @internal - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _setValue(data: any): void { // abstract - if (data !== null && data !== undefined) { - if (typeof data !== 'string') { - this.reportInvalidData(data); - } - this._value = data; - return; - } - - if (this.environmentVariable !== undefined) { - // Try reading the environment variable - const environmentValue: string | undefined = process.env[this.environmentVariable]; - if (environmentValue !== undefined) { - // NOTE: If the environment variable is defined as an empty string, - // here we will accept the empty string as our value. (For number/flag we don't do that.) - this._value = environmentValue; - return; - } - } - - if (this.defaultValue !== undefined) { - this._value = this.defaultValue; - return; - } - - this._value = undefined; - } - - /** - * {@inheritDoc CommandLineParameter._getSupplementaryNotes} - * @internal - */ - public _getSupplementaryNotes(supplementaryNotes: string[]): void { // virtual - super._getSupplementaryNotes(supplementaryNotes); - if (this.defaultValue !== undefined) { - if (this.defaultValue.length < 160) { - supplementaryNotes.push(`The default value is ${JSON.stringify(this.defaultValue)}.`); - } - } - } - - /** - * Returns the argument value for a string parameter that was parsed from the command line. - * - * @remarks - * The return value will be undefined if the command-line has not been parsed yet, - * or if the parameter was omitted and has no default value. - */ - public get value(): string | undefined { - return this._value; - } - - /** {@inheritDoc CommandLineParameter.appendToArgList} @override */ - public appendToArgList(argList: string[]): void { - if (this.value !== undefined) { - argList.push(this.longName); - argList.push(this.value); - } - } - -} - -/** - * The data type returned by {@link CommandLineParameterProvider.defineStringListParameter}. - * @public - */ -export class CommandLineStringListParameter extends CommandLineParameterWithArgument { - private _values: string[] = []; - - /** @internal */ - public constructor(definition: ICommandLineStringListDefinition) { - super(definition); - } - - /** {@inheritDoc CommandLineParameter.kind} */ - public get kind(): CommandLineParameterKind { - return CommandLineParameterKind.StringList; - } - - /** - * {@inheritDoc CommandLineParameter._setValue} - * @internal - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public _setValue(data: any): void { // abstract - if (data !== null && data !== undefined) { - if (!Array.isArray(data)) { - this.reportInvalidData(data); - } - for (const arrayItem of data) { - if (typeof(arrayItem) !== 'string') { - this.reportInvalidData(data); - } - } - this._values = data; - return; - } - - if (this.environmentVariable !== undefined) { - // Try reading the environment variable - const environmentValue: string | undefined = process.env[this.environmentVariable]; - if (environmentValue !== undefined) { - // NOTE: If the environment variable is defined as an empty string, - // here we will accept the empty string as our value. (For number/flag we don't do that.) - - // In the current implementation, the environment variable for a "string list" can only - // store a single item. If we wanted to allow multiple items (and still have a conventional-seeming - // environment), we would ask the caller to provide an appropriate delimiter. Getting involved - // with escaping here seems unwise, since there are so many shell escaping mechanisms that could - // potentially confuse the experience. - this._values = [ environmentValue ]; - return; - } - } - - // (No default value for string lists) - - this._values = []; - } - - /** - * Returns the string arguments for a string list parameter that was parsed from the command line. - * - * @remarks - * The array will be empty if the command-line has not been parsed yet, - * or if the parameter was omitted and has no default value. - */ - public get values(): ReadonlyArray { - return this._values; - } - - /** {@inheritDoc CommandLineParameter.appendToArgList} @override */ - public appendToArgList(argList: string[]): void { - if (this.values.length > 0) { - for (const value of this.values) { - argList.push(this.longName); - argList.push(value); - } - } - } -} diff --git a/libraries/ts-command-line/src/CommandLineParameterProvider.ts b/libraries/ts-command-line/src/CommandLineParameterProvider.ts deleted file mode 100644 index 89234fcadb7..00000000000 --- a/libraries/ts-command-line/src/CommandLineParameterProvider.ts +++ /dev/null @@ -1,266 +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 argparse from 'argparse'; -import { - ICommandLineFlagDefinition, - ICommandLineStringDefinition, - ICommandLineStringListDefinition, - ICommandLineIntegerDefinition, - ICommandLineChoiceDefinition -} from './CommandLineDefinition'; - -import { - CommandLineParameter, - CommandLineParameterWithArgument, - CommandLineFlagParameter, - CommandLineStringParameter, - CommandLineStringListParameter, - CommandLineIntegerParameter, - CommandLineChoiceParameter, - CommandLineParameterKind -} from './CommandLineParameter'; - -/** - * This is the argparse result data object - * @internal - */ -export interface ICommandLineParserData { - action: string; - [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any -} - -/** - * This is the common base class for CommandLineAction and CommandLineParser - * that provides functionality for defining command-line parameters. - * - * @public - */ -export abstract class CommandLineParameterProvider { - private static _keyCounter: number = 0; - - private _parameters: CommandLineParameter[]; - private _parametersByLongName: Map; - - /** @internal */ - // Third party code should not inherit subclasses or call this constructor - public constructor() { - this._parameters = []; - this._parametersByLongName = new Map(); - } - - /** - * Returns a collection of the parameters that were defined for this object. - */ - public get parameters(): ReadonlyArray { - return this._parameters; - } - - /** - * Defines a command-line parameter whose value must be a string from a fixed set of - * allowable choices (similar to an enum). - * - * @remarks - * Example: example-tool --log-level warn - */ - public defineChoiceParameter(definition: ICommandLineChoiceDefinition): CommandLineChoiceParameter { - const parameter: CommandLineChoiceParameter = new CommandLineChoiceParameter(definition); - this._defineParameter(parameter); - return parameter; - } - - /** - * Returns the CommandLineChoiceParameter with the specified long name. - * @remarks - * This method throws an exception if the parameter is not defined. - */ - public getChoiceParameter(parameterLongName: string): CommandLineChoiceParameter { - return this._getParameter(parameterLongName, CommandLineParameterKind.Choice); - } - - /** - * Defines a command-line switch whose boolean value is true if the switch is provided, - * and false otherwise. - * - * @remarks - * Example: example-tool --debug - */ - public defineFlagParameter(definition: ICommandLineFlagDefinition): CommandLineFlagParameter { - const parameter: CommandLineFlagParameter = new CommandLineFlagParameter(definition); - this._defineParameter(parameter); - return parameter; - } - - /** - * Returns the CommandLineFlagParameter with the specified long name. - * @remarks - * This method throws an exception if the parameter is not defined. - */ - public getFlagParameter(parameterLongName: string): CommandLineFlagParameter { - return this._getParameter(parameterLongName, CommandLineParameterKind.Flag); - } - - /** - * Defines a command-line parameter whose value is an integer. - * - * @remarks - * Example: example-tool --max-attempts 5 - */ - public defineIntegerParameter(definition: ICommandLineIntegerDefinition): CommandLineIntegerParameter { - const parameter: CommandLineIntegerParameter = new CommandLineIntegerParameter(definition); - this._defineParameter(parameter); - return parameter; - } - - /** - * Returns the CommandLineIntegerParameter with the specified long name. - * @remarks - * This method throws an exception if the parameter is not defined. - */ - public getIntegerParameter(parameterLongName: string): CommandLineIntegerParameter { - return this._getParameter(parameterLongName, CommandLineParameterKind.Integer); - } - - /** - * Defines a command-line parameter whose value is a single text string. - * - * @remarks - * Example: example-tool --message "Hello, world!" - */ - public defineStringParameter(definition: ICommandLineStringDefinition): CommandLineStringParameter { - const parameter: CommandLineStringParameter = new CommandLineStringParameter(definition); - this._defineParameter(parameter); - return parameter; - } - - /** - * Returns the CommandLineStringParameter with the specified long name. - * @remarks - * This method throws an exception if the parameter is not defined. - */ - public getStringParameter(parameterLongName: string): CommandLineStringParameter { - return this._getParameter(parameterLongName, CommandLineParameterKind.String); - } - - /** - * Defines a command-line parameter whose value is one or more text strings. - * - * @remarks - * Example: example-tool --add file1.txt --add file2.txt --add file3.txt - */ - public defineStringListParameter(definition: ICommandLineStringListDefinition): CommandLineStringListParameter { - const parameter: CommandLineStringListParameter = new CommandLineStringListParameter(definition); - this._defineParameter(parameter); - return parameter; - } - - /** - * Returns the CommandLineStringListParameter with the specified long name. - * @remarks - * This method throws an exception if the parameter is not defined. - */ - public getStringListParameter(parameterLongName: string): CommandLineStringListParameter { - return this._getParameter(parameterLongName, CommandLineParameterKind.StringList); - } - - /** - * Generates the command-line help text. - */ - public renderHelpText(): string { - return this._getArgumentParser().formatHelp(); - } - - /** - * The child class should implement this hook to define its command-line parameters, - * e.g. by calling defineFlagParameter(). - */ - protected abstract onDefineParameters(): void; - - /** - * Retrieves the argparse object. - * @internal - */ - protected abstract _getArgumentParser(): argparse.ArgumentParser; - - /** @internal */ - protected _processParsedData(data: ICommandLineParserData): void { - // Fill in the values for the parameters - for (const parameter of this._parameters) { - const value: any = data[parameter._parserKey]; // eslint-disable-line @typescript-eslint/no-explicit-any - parameter._setValue(value); - } - } - - private _generateKey(): string { - return 'key_' + (CommandLineParameterProvider._keyCounter++).toString(); - } - - private _getParameter(parameterLongName: string, - expectedKind: CommandLineParameterKind): T { - - const parameter: CommandLineParameter | undefined = this._parametersByLongName.get(parameterLongName); - if (!parameter) { - throw new Error(`The parameter "${parameterLongName}" is not defined`); - } - if (parameter.kind !== expectedKind) { - throw new Error(`The parameter "${parameterLongName}" is of type "${CommandLineParameterKind[parameter.kind]}"` - + ` whereas the caller was expecting "${CommandLineParameterKind[expectedKind]}".`); - } - return parameter as T; - } - - private _defineParameter(parameter: CommandLineParameter): void { - const names: string[] = []; - if (parameter.shortName) { - names.push(parameter.shortName); - } - names.push(parameter.longName); - - parameter._parserKey = this._generateKey(); - - let finalDescription: string = parameter.description; - - const supplementaryNotes: string[] = []; - parameter._getSupplementaryNotes(supplementaryNotes); - if (supplementaryNotes.length > 0) { - // If they left the period off the end of their sentence, then add one. - if (finalDescription.match(/[a-z0-9]\s*$/i)) { - finalDescription = finalDescription.trimRight() + '.'; - } - // Append the supplementary text - finalDescription += ' ' + supplementaryNotes.join(' '); - } - - // NOTE: Our "environmentVariable" feature takes precedence over argparse's "defaultValue", - // so we have to reimplement that feature. - const argparseOptions: argparse.ArgumentOptions = { - help: finalDescription, - dest: parameter._parserKey, - metavar: (parameter as CommandLineParameterWithArgument).argumentName || undefined, - required: parameter.required - }; - - switch (parameter.kind) { - case CommandLineParameterKind.Choice: - const choiceParameter: CommandLineChoiceParameter = parameter as CommandLineChoiceParameter; - argparseOptions.choices = choiceParameter.alternatives as string[]; - break; - case CommandLineParameterKind.Flag: - argparseOptions.action = 'storeTrue'; - break; - case CommandLineParameterKind.Integer: - argparseOptions.type = 'int'; - break; - case CommandLineParameterKind.String: - break; - case CommandLineParameterKind.StringList: - argparseOptions.action = 'append'; - break; - } - - this._getArgumentParser().addArgument(names, argparseOptions); - - this._parameters.push(parameter); - this._parametersByLongName.set(parameter.longName, parameter); - } -} diff --git a/libraries/ts-command-line/src/CommandLineParser.ts b/libraries/ts-command-line/src/CommandLineParser.ts deleted file mode 100644 index 3f9bf13aefe..00000000000 --- a/libraries/ts-command-line/src/CommandLineParser.ts +++ /dev/null @@ -1,254 +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 argparse from 'argparse'; -import * as colors from 'colors'; - -import { CommandLineAction } from './CommandLineAction'; -import { CommandLineParameterProvider, ICommandLineParserData } from './CommandLineParameterProvider'; - -/** - * Options for the {@link CommandLineParser} constructor. - * @public - */ -export interface ICommandLineParserOptions { - /** - * The name of your tool when invoked from the command line - */ - toolFilename: string; - - /** - * General documentation that is included in the "--help" main page - */ - toolDescription: string; -} - -export class CommandLineParserExitError extends Error { - public readonly exitCode: number; - - public constructor(exitCode: number, message: string) { - super(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/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work - // - // Note: the prototype must also be set on any classes which extend this one - (this as any).__proto__ = CommandLineParserExitError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any - - this.exitCode = exitCode; - } -} - -class CustomArgumentParser extends argparse.ArgumentParser { - public exit(status: number, message: string): void { // override - throw new CommandLineParserExitError(status, message); - } - - public error(err: Error | string): void { // override - // Ensure the ParserExitError bubbles up to the top without any special processing - if (err instanceof CommandLineParserExitError) { - throw err; - } - - super.error(err); - } -} - -/** - * The "argparse" library is a relatively advanced command-line parser with features such - * as word-wrapping and intelligible error messages (that are lacking in other similar - * libraries such as commander, yargs, and nomnom). Unfortunately, its ruby-inspired API - * is awkward to use. The abstract base classes CommandLineParser and CommandLineAction - * provide a wrapper for "argparse" that makes defining and consuming arguments quick - * and simple, and enforces that appropriate documentation is provided for each parameter. - * - * @public - */ -export abstract class CommandLineParser extends CommandLineParameterProvider { - /** {@inheritDoc ICommandLineParserOptions.toolFilename} */ - public readonly toolFilename: string; - - /** {@inheritDoc ICommandLineParserOptions.toolDescription} */ - public readonly toolDescription: string; - - /** - * Reports which CommandLineAction was specified on the command line. - * @remarks - * The value will be assigned before onExecute() is invoked. - */ - public selectedAction: CommandLineAction | undefined; - - private _argumentParser: argparse.ArgumentParser; - private _actionsSubParser: argparse.SubParser; - private _options: ICommandLineParserOptions; - private _actions: CommandLineAction[]; - private _actionsByName: Map; - private _executed: boolean = false; - - public constructor(options: ICommandLineParserOptions) { - super(); - - this._options = options; - this._actions = []; - this._actionsByName = new Map(); - - this._argumentParser = new CustomArgumentParser({ - addHelp: true, - prog: this._options.toolFilename, - description: this._options.toolDescription, - epilog: colors.bold('For detailed help about a specific command, use:' - + ` ${this._options.toolFilename} -h`) - }); - - this._actionsSubParser = this._argumentParser.addSubparsers({ - metavar: '', - dest: 'action' - }); - - this.onDefineParameters(); - } - - /** - * Returns the list of actions that were defined for this CommandLineParser object. - */ - public get actions(): ReadonlyArray { - return this._actions; - } - - /** - * Defines a new action that can be used with the CommandLineParser instance. - */ - public addAction(action: CommandLineAction): void { - action._buildParser(this._actionsSubParser); - this._actions.push(action); - this._actionsByName.set(action.actionName, action); - } - - /** - * Retrieves the action with the specified name. If no matching action is found, - * an exception is thrown. - */ - public getAction(actionName: string): CommandLineAction { - const action: CommandLineAction | undefined = this.tryGetAction(actionName); - if (!action) { - throw new Error(`The action "${actionName}" was not defined`); - } - return action; - } - - /** - * Retrieves the action with the specified name. If no matching action is found, - * undefined is returned. - */ - public tryGetAction(actionName: string): CommandLineAction | undefined { - return this._actionsByName.get(actionName); - } - - /** - * The program entry point will call this method to begin parsing command-line arguments - * and executing the corresponding action. - * - * @remarks - * The returned promise will never reject: If an error occurs, it will be printed - * to stderr, process.exitCode will be set to 1, and the promise will resolve to false. - * This simplifies the most common usage scenario where the program entry point doesn't - * want to be involved with the command-line logic, and will discard the promise without - * a then() or catch() block. - * - * If your caller wants to trap and handle errors, use {@link CommandLineParser.executeWithoutErrorHandling} - * instead. - * - * @param args - the command-line arguments to be parsed; if omitted, then - * the process.argv will be used - */ - public execute(args?: string[]): Promise { - return this.executeWithoutErrorHandling(args).then(() => { - return true; - }).catch((err) => { - if (err instanceof CommandLineParserExitError) { - // executeWithoutErrorHandling() handles the successful cases, - // so here we can assume err has a nonzero exit code - if (err.message) { - console.error(err.message); - } - if (!process.exitCode) { - process.exitCode = err.exitCode; - } - } else { - const message: string = (err.message || 'An unknown error occurred').trim(); - console.error(colors.red('Error: ' + message)); - if (!process.exitCode) { - process.exitCode = 1; - } - } - return false; - }); - } - - /** - * This is similar to {@link CommandLineParser.execute}, except that execution errors - * simply cause the promise to reject. It is the caller's responsibility to trap - */ - public executeWithoutErrorHandling(args?: string[]): Promise { - try { - if (this._executed) { - // In the future we could allow the same parser to be invoked multiple times - // with different arguments. We'll do that work as soon as someone encounters - // a real world need for it. - throw new Error('execute() was already called for this parser instance'); - } - this._executed = true; - if (!args) { - // 0=node.exe, 1=script name - args = process.argv.slice(2); - } - if (args.length === 0) { - this._argumentParser.printHelp(); - return Promise.resolve(); - } - const data: ICommandLineParserData = this._argumentParser.parseArgs(args); - - this._processParsedData(data); - - for (const action of this._actions) { - if (action.actionName === data.action) { - this.selectedAction = action; - action._processParsedData(data); - break; - } - } - if (!this.selectedAction) { - throw new Error('Unrecognized action'); - } - - return this.onExecute(); - } catch (err) { - if (err instanceof CommandLineParserExitError) { - if (!err.exitCode) { - // non-error exit modeled using exception handling - if (err.message) { - console.log(err.message); - } - return Promise.resolve(); - } - } - return Promise.reject(err); - } - } - - /** - * {@inheritDoc CommandLineParameterProvider._getArgumentParser} - * @internal - */ - protected _getArgumentParser(): argparse.ArgumentParser { // override - return this._argumentParser; - } - - /** - * This hook allows the subclass to perform additional operations before or after - * the chosen action is executed. - */ - protected onExecute(): Promise { - return this.selectedAction!._execute(); - } -} diff --git a/libraries/ts-command-line/src/Constants.ts b/libraries/ts-command-line/src/Constants.ts new file mode 100644 index 00000000000..aeabc100dde --- /dev/null +++ b/libraries/ts-command-line/src/Constants.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. + +/** + * String constants for command line processing. + * + * @public + */ +export enum CommandLineConstants { + /** + * The name of the built-in action that serves suggestions for tab-completion + */ + TabCompletionActionName = 'tab-complete' +} + +export const SCOPING_PARAMETER_GROUP: unique symbol = Symbol('scoping'); diff --git a/libraries/ts-command-line/src/DynamicCommandLineAction.ts b/libraries/ts-command-line/src/DynamicCommandLineAction.ts deleted file mode 100644 index c888baa0509..00000000000 --- a/libraries/ts-command-line/src/DynamicCommandLineAction.ts +++ /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. - -import { CommandLineAction } from './CommandLineAction'; - -/** - * @public - */ -export class DynamicCommandLineAction extends CommandLineAction { - protected onDefineParameters(): void { // abstract - // (handled by the external code) - } - - protected onExecute(): Promise { // abstract - // (handled by the external code) - return Promise.resolve(); - } -} diff --git a/libraries/ts-command-line/src/TypeUuidLite.ts b/libraries/ts-command-line/src/TypeUuidLite.ts new file mode 100644 index 00000000000..6915073bac0 --- /dev/null +++ b/libraries/ts-command-line/src/TypeUuidLite.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. + +const classPrototypeUuidSymbol: symbol = Symbol.for('TypeUuid.classPrototypeUuid'); + +export const uuidAlreadyReportedError: string = 'f26b0640-a49b-49d1-9ead-1a516d5920c7'; + +// Avoid a dependency on node-core-library to access just this one API: +export class TypeUuid { + /** + * Returns true if the `targetObject` is an instance of a JavaScript class that was previously + * registered using the specified `typeUuid`. Base classes are also considered. + */ + public static isInstanceOf(targetObject: unknown, typeUuid: string): boolean { + if (targetObject === undefined || targetObject === null) { + return false; + } + + let objectPrototype: {} = Object.getPrototypeOf(targetObject); + while (objectPrototype !== undefined && objectPrototype !== null) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const registeredUuid: string = (objectPrototype as any)[classPrototypeUuidSymbol]; + if (registeredUuid === typeUuid) { + return true; + } + // Walk upwards an examine base class prototypes + objectPrototype = Object.getPrototypeOf(objectPrototype); + } + + return false; + } +} diff --git a/libraries/ts-command-line/src/escapeSprintf.ts b/libraries/ts-command-line/src/escapeSprintf.ts new file mode 100644 index 00000000000..db31524a927 --- /dev/null +++ b/libraries/ts-command-line/src/escapeSprintf.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. + +export function escapeSprintf(input: string): string { + // Escape sprintf-style escape characters + // The primary special character in sprintf format strings is '%' + // which introduces format specifiers like %s, %d, %f, etc. + return input.replace(/%/g, '%%'); +} diff --git a/libraries/ts-command-line/src/index.ts b/libraries/ts-command-line/src/index.ts index eabad8a0ec4..dc4b17d60e9 100644 --- a/libraries/ts-command-line/src/index.ts +++ b/libraries/ts-command-line/src/index.ts @@ -7,46 +7,62 @@ * @packageDocumentation */ +export { CommandLineAction, type ICommandLineActionOptions } from './providers/CommandLineAction'; +export { DynamicCommandLineAction } from './providers/DynamicCommandLineAction'; +export { ScopedCommandLineAction } from './providers/ScopedCommandLineAction'; export { - CommandLineAction, - ICommandLineActionOptions -} from './CommandLineAction'; + AliasCommandLineAction, + type IAliasCommandLineActionOptions +} from './providers/AliasCommandLineAction'; -export { +export type { IBaseCommandLineDefinition, IBaseCommandLineDefinitionWithArgument, ICommandLineFlagDefinition, ICommandLineStringDefinition, ICommandLineStringListDefinition, ICommandLineIntegerDefinition, - ICommandLineChoiceDefinition -} from './CommandLineDefinition'; + ICommandLineIntegerListDefinition, + ICommandLineChoiceDefinition, + ICommandLineChoiceListDefinition, + ICommandLineRemainderDefinition +} from './parameters/CommandLineDefinition'; export { + type CommandLineParameter, CommandLineParameterKind, - CommandLineParameter, - CommandLineParameterWithArgument, + CommandLineParameterBase, + CommandLineParameterWithArgument +} from './parameters/BaseClasses'; + +export { CommandLineFlagParameter } from './parameters/CommandLineFlagParameter'; +export { CommandLineStringParameter, - CommandLineStringListParameter, - CommandLineFlagParameter, + type IRequiredCommandLineStringParameter +} from './parameters/CommandLineStringParameter'; +export { CommandLineStringListParameter } from './parameters/CommandLineStringListParameter'; +export { CommandLineIntegerParameter, - CommandLineChoiceParameter -} from './CommandLineParameter'; + type IRequiredCommandLineIntegerParameter +} from './parameters/CommandLineIntegerParameter'; +export { CommandLineIntegerListParameter } from './parameters/CommandLineIntegerListParameter'; +export { + CommandLineChoiceParameter, + type IRequiredCommandLineChoiceParameter +} from './parameters/CommandLineChoiceParameter'; +export { CommandLineChoiceListParameter } from './parameters/CommandLineChoiceListParameter'; +export { CommandLineRemainder } from './parameters/CommandLineRemainder'; export { CommandLineParameterProvider, - ICommandLineParserData as _ICommandLineParserData -} from './CommandLineParameterProvider'; + type IScopedLongNameParseResult, + type ICommandLineParserData as _ICommandLineParserData, + type IRegisterDefinedParametersState as _IRegisterDefinedParametersState +} from './providers/CommandLineParameterProvider'; -export { - ICommandLineParserOptions, - CommandLineParser -} from './CommandLineParser'; +export { CommandLineParser, type ICommandLineParserOptions } from './providers/CommandLineParser'; +export { DynamicCommandLineParser } from './providers/DynamicCommandLineParser'; -export { - DynamicCommandLineAction -} from './DynamicCommandLineAction'; +export { CommandLineConstants } from './Constants'; -export { - DynamicCommandLineParser -} from './DynamicCommandLineParser'; +export { CommandLineHelper } from './CommandLineHelper'; diff --git a/libraries/ts-command-line/src/parameters/BaseClasses.ts b/libraries/ts-command-line/src/parameters/BaseClasses.ts new file mode 100644 index 00000000000..48b4cecb262 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/BaseClasses.ts @@ -0,0 +1,316 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { SCOPING_PARAMETER_GROUP } from '../Constants'; +import type { + IBaseCommandLineDefinition, + IBaseCommandLineDefinitionWithArgument +} from './CommandLineDefinition'; +import type { CommandLineChoiceListParameter } from './CommandLineChoiceListParameter'; +import type { CommandLineChoiceParameter } from './CommandLineChoiceParameter'; +import type { CommandLineFlagParameter } from './CommandLineFlagParameter'; +import type { CommandLineIntegerListParameter } from './CommandLineIntegerListParameter'; +import type { CommandLineIntegerParameter } from './CommandLineIntegerParameter'; +import type { CommandLineStringListParameter } from './CommandLineStringListParameter'; +import type { CommandLineStringParameter } from './CommandLineStringParameter'; + +/** + * Identifies the kind of a CommandLineParameter. + * @public + */ +export enum CommandLineParameterKind { + /** Indicates a CommandLineChoiceParameter */ + Choice, + /** Indicates a CommandLineFlagParameter */ + Flag, + /** Indicates a CommandLineIntegerParameter */ + Integer, + /** Indicates a CommandLineStringParameter */ + String, + /** Indicates a CommandLineStringListParameter */ + StringList, + /** Indicates a CommandLineChoiceListParameter */ + ChoiceList, + /** Indicates a CommandLineIntegerListParameter */ + IntegerList +} + +/** + * Matches kebab-case formatted strings prefixed with double dashes. + * Example: "--do-something" + */ +const LONG_NAME_REGEXP: RegExp = /^-(-[a-z0-9]+)+$/; + +/** + * Matches a single upper-case or lower-case letter prefixed with a dash. + * Example: "-d" + */ +const SHORT_NAME_REGEXP: RegExp = /^-[a-zA-Z]$/; + +/** + * Matches kebab-case formatted strings + * Example: "my-scope" + */ +const SCOPE_REGEXP: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; + +/** + * "Environment variable names used by the utilities in the Shell and Utilities volume of + * IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the '_' (underscore) + * from the characters defined in Portable Character Set and do not begin with a digit." + * Example: "THE_SETTING" + */ +const ENVIRONMENT_VARIABLE_NAME_REGEXP: RegExp = /^[A-Z_][A-Z0-9_]*$/; + +/** + * @public + */ +export type CommandLineParameter = + | CommandLineChoiceListParameter + | CommandLineChoiceParameter + | CommandLineFlagParameter + | CommandLineIntegerListParameter + | CommandLineIntegerParameter + | CommandLineStringListParameter + | CommandLineStringParameter; + +/** + * The base class for the various command-line parameter types. + * @public + */ +export abstract class CommandLineParameterBase { + private _shortNameValue: string | undefined; + + /** + * A unique internal key used to retrieve the value from the parser's dictionary. + * @internal + */ + public _parserKey: string | undefined; + + /** + * @internal + */ + public _preParse?: () => void; + + /** + * @internal + */ + public _postParse?: () => void; + + /** + * @internal + */ + public _validateValue?: () => void; + + /** {@inheritDoc IBaseCommandLineDefinition.parameterLongName} */ + public readonly longName: string; + + /** + * If a parameterScope is provided, returns the scope-prefixed long name of the flag, + * including double dashes, eg. "--scope:do-something". Otherwise undefined. + */ + public readonly scopedLongName: string | undefined; + + /** {@inheritDoc IBaseCommandLineDefinition.parameterGroup} */ + public readonly parameterGroup: string | typeof SCOPING_PARAMETER_GROUP | undefined; + + /** {@inheritDoc IBaseCommandLineDefinition.parameterScope} */ + public readonly parameterScope: string | undefined; + + /** {@inheritDoc IBaseCommandLineDefinition.description} */ + public readonly description: string; + + /** {@inheritDoc IBaseCommandLineDefinition.required} */ + public readonly required: boolean; + + /** {@inheritDoc IBaseCommandLineDefinition.environmentVariable} */ + public readonly environmentVariable: string | undefined; + + /** {@inheritDoc IBaseCommandLineDefinition.allowNonStandardEnvironmentVariableNames} */ + public readonly allowNonStandardEnvironmentVariableNames: boolean | undefined; + + /** {@inheritDoc IBaseCommandLineDefinition.undocumentedSynonyms } */ + public readonly undocumentedSynonyms: string[] | undefined; + + /** @internal */ + public constructor(definition: IBaseCommandLineDefinition) { + this.longName = definition.parameterLongName; + this._shortNameValue = definition.parameterShortName; + this.parameterGroup = definition.parameterGroup; + this.parameterScope = definition.parameterScope; + this.description = definition.description; + this.required = !!definition.required; + this.environmentVariable = definition.environmentVariable; + this.undocumentedSynonyms = definition.undocumentedSynonyms; + this.allowNonStandardEnvironmentVariableNames = definition.allowNonStandardEnvironmentVariableNames; + + if (!LONG_NAME_REGEXP.test(this.longName)) { + throw new Error( + `Invalid name: "${this.longName}". The parameter long name must be` + + ` lower-case and use dash delimiters (e.g. "--do-a-thing")` + ); + } + + if (this.shortName) { + if (!SHORT_NAME_REGEXP.test(this.shortName)) { + throw new Error( + `Invalid name: "${this.shortName}". The parameter short name must be` + + ` a dash followed by a single upper-case or lower-case letter (e.g. "-a")` + ); + } + } + + if (this.parameterScope) { + if (!SCOPE_REGEXP.test(this.parameterScope)) { + throw new Error( + `Invalid scope: "${this.parameterScope}". The parameter scope name must be` + + ` lower-case and use dash delimiters (e.g. "my-scope")` + ); + } + // Parameter long name is guaranteed to start with '--' since this is validated above + const unprefixedLongName: string = this.longName.slice(2); + this.scopedLongName = `--${this.parameterScope}:${unprefixedLongName}`; + } + + if (this.environmentVariable) { + if ( + !this.allowNonStandardEnvironmentVariableNames && + !ENVIRONMENT_VARIABLE_NAME_REGEXP.test(this.environmentVariable) + ) { + throw new Error( + `Invalid environment variable name: "${this.environmentVariable}". The name must` + + ` consist only of upper-case letters, numbers, and underscores. It may not start with a number.` + ); + } + } + + if (this.undocumentedSynonyms && this.undocumentedSynonyms.length > 0) { + for (const undocumentedSynonym of this.undocumentedSynonyms) { + if (this.longName === undocumentedSynonym) { + throw new Error( + `Invalid name: "${undocumentedSynonym}". Undocumented synonyms must not be the same` + + ` as the the long name.` + ); + } else if (!LONG_NAME_REGEXP.test(undocumentedSynonym)) { + throw new Error( + `Invalid name: "${undocumentedSynonym}". All undocumented synonyms name must be lower-case and ` + + 'use dash delimiters (e.g. "--do-a-thing")' + ); + } + } + } + } + + /** {@inheritDoc IBaseCommandLineDefinition.parameterShortName} */ + public get shortName(): string | undefined { + return this._shortNameValue; + } + + /** + * Called internally by CommandLineParameterProvider._processParsedData() + * @internal + */ + public abstract _setValue(data: unknown): void; + + /** + * Returns additional text used by the help formatter. + * @internal + */ + public _getSupplementaryNotes(supplementaryNotes: string[]): void { + // virtual + if (this.environmentVariable !== undefined) { + supplementaryNotes.push( + 'This parameter may alternatively be specified via the ' + + this.environmentVariable + + ' environment variable.' + ); + } + } + + /** + * Indicates the type of parameter. + */ + public abstract get kind(): CommandLineParameterKind; + + /** + * Append the parsed values to the provided string array. + * @remarks + * Sometimes a command line parameter is not used directly, but instead gets passed through to another + * tool that will use it. For example if our parameter comes in as "--max-count 3", then we might want to + * call `child_process.spawn()` and append ["--max-count", "3"] to the args array for that tool. + * appendToArgList() appends zero or more strings to the provided array, based on the input command-line + * that we parsed. + * + * If the parameter was omitted from our command-line and has no default value, then + * nothing will be appended. If the short name was used, the long name will be appended instead. + * @param argList - the parsed strings will be appended to this string array + */ + public abstract appendToArgList(argList: string[]): void; + + /** + * Internal usage only. Used to report unexpected output from the argparse library. + */ + protected reportInvalidData(data: unknown): never { + throw new Error(`Unexpected data object for parameter "${this.longName}": ` + JSON.stringify(data)); + } + + protected validateDefaultValue(hasDefaultValue: boolean): void { + if (this.required && hasDefaultValue) { + // If a parameter is "required", then the user understands that they always need to + // specify a value for this parameter (either via the command line or via an environment variable). + // It would be confusing to allow a default value that sometimes allows the "required" parameter + // to be omitted. If you sometimes don't have a suitable default value, then the better approach + // is to throw a custom error explaining why the parameter is required in that case. + throw new Error( + `A default value cannot be specified for "${this.longName}" because it is a "required" parameter` + ); + } + } +} + +/** + * The common base class for parameters types that receive an argument. + * + * @remarks + * An argument is an accompanying command-line token, such as "123" in the + * example "--max-count 123". + * @public + */ +export abstract class CommandLineParameterWithArgument extends CommandLineParameterBase { + // Matches the first character that *isn't* part of a valid upper-case argument name such as "URL_2" + private static _invalidArgumentNameRegExp: RegExp = /[^A-Z_0-9]/; + + /** {@inheritDoc IBaseCommandLineDefinitionWithArgument.argumentName} */ + public readonly argumentName: string; + + /** {@inheritDoc IBaseCommandLineDefinitionWithArgument.getCompletionsAsync} */ + public readonly getCompletionsAsync: + | (() => Promise | ReadonlySet>) + | undefined; + + /** @internal */ + public constructor(definition: IBaseCommandLineDefinitionWithArgument) { + super(definition); + + if (definition.argumentName === '') { + throw new Error( + 'The argument name cannot be an empty string. (For the default name, specify undefined.)' + ); + } + if (definition.argumentName.toUpperCase() !== definition.argumentName) { + throw new Error( + `Invalid name: "${definition.argumentName}". The argument name must be all upper case.` + ); + } + const match: RegExpMatchArray | null = definition.argumentName.match( + CommandLineParameterWithArgument._invalidArgumentNameRegExp + ); + if (match) { + throw new Error( + `The argument name "${definition.argumentName}" contains an invalid character "${match[0]}".` + + ` Only upper-case letters, numbers, and underscores are allowed.` + ); + } + this.argumentName = definition.argumentName; + this.getCompletionsAsync = definition.getCompletionsAsync; + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineChoiceListParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineChoiceListParameter.ts new file mode 100644 index 00000000000..d9bdde12df1 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineChoiceListParameter.ts @@ -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. + +import type { ICommandLineChoiceListDefinition } from './CommandLineDefinition'; +import { CommandLineParameterBase, CommandLineParameterKind } from './BaseClasses'; +import { EnvironmentVariableParser } from './EnvironmentVariableParser'; + +/** + * The data type returned by {@link CommandLineParameterProvider.defineChoiceListParameter}. + * @public + */ +export class CommandLineChoiceListParameter< + TChoice extends string = string +> extends CommandLineParameterBase { + /** {@inheritDoc ICommandLineChoiceListDefinition.alternatives} */ + public readonly alternatives: ReadonlySet; + + private _values: TChoice[] = []; + + /** {@inheritDoc ICommandLineChoiceListDefinition.completions} */ + public readonly completions: (() => Promise | ReadonlySet>) | undefined; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.ChoiceList = CommandLineParameterKind.ChoiceList; + + /** @internal */ + public constructor(definition: ICommandLineChoiceListDefinition) { + super(definition); + const { alternatives, completions } = definition; + + const alternativesSet: Set = alternatives instanceof Set ? alternatives : new Set(alternatives); + if (alternativesSet.size < 1) { + throw new Error( + `When defining a choice list parameter, the alternatives list must contain at least one value.` + ); + } + + this.alternatives = alternativesSet; + this.completions = completions; + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // If argparse passed us a value, confirm it is valid + if (data !== null && data !== undefined) { + if (!Array.isArray(data)) { + this.reportInvalidData(data); + } + for (const arrayItem of data) { + if (typeof arrayItem !== 'string') { + this.reportInvalidData(data); + } + } + this._values = data; + return; + } + + if (this.environmentVariable !== undefined) { + const values: string[] | undefined = EnvironmentVariableParser.parseAsList(this.environmentVariable); + if (values) { + for (const value of values) { + if (!this.alternatives.has(value as TChoice)) { + const choices: string = '"' + Array.from(this.alternatives).join('", "') + '"'; + throw new Error( + `Invalid value "${value}" for the environment variable` + + ` ${this.environmentVariable}. Valid choices are: ${choices}` + ); + } + } + + this._values = values as TChoice[]; + return; + } + } + + // (No default value for choice lists) + + this._values = []; + } + + /** + * Returns the string arguments for a choice list parameter that was parsed from the command line. + * + * @remarks + * The array will be empty if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get values(): ReadonlyArray { + return this._values; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.values.length > 0) { + for (const value of this.values) { + argList.push(this.longName); + argList.push(value); + } + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineChoiceParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineChoiceParameter.ts new file mode 100644 index 00000000000..2c69e7dfc33 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineChoiceParameter.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 { ICommandLineChoiceDefinition } from './CommandLineDefinition'; +import { CommandLineParameterBase, CommandLineParameterKind } from './BaseClasses'; + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineChoiceParameter:2)}. + * @public + */ +export interface IRequiredCommandLineChoiceParameter + extends CommandLineChoiceParameter { + readonly value: TChoice; +} + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineChoiceParameter:1)}. + * @public + */ +export class CommandLineChoiceParameter extends CommandLineParameterBase { + /** {@inheritDoc ICommandLineChoiceDefinition.alternatives} */ + public readonly alternatives: ReadonlySet; + + /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ + public readonly defaultValue: TChoice | undefined; + + private _value: TChoice | undefined = undefined; + + /** {@inheritDoc ICommandLineChoiceDefinition.completions} */ + public readonly completions: (() => Promise | ReadonlySet>) | undefined; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.Choice = -CommandLineParameterKind.Choice; + + /** @internal */ + public constructor(definition: ICommandLineChoiceDefinition) { + super(definition); + const { alternatives, defaultValue, completions } = definition; + + const alternativesSet: Set = alternatives instanceof Set ? alternatives : new Set(alternatives); + if (alternativesSet.size < 1) { + throw new Error( + `When defining a choice parameter, the alternatives list must contain at least one value.` + ); + } + if (defaultValue && !alternativesSet.has(defaultValue)) { + throw new Error( + `The specified default value "${defaultValue}"` + + ` is not one of the available options: ${alternatives.toString()}` + ); + } + + this.alternatives = alternativesSet; + this.defaultValue = defaultValue; + this.validateDefaultValue(!!this.defaultValue); + this.completions = completions; + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // abstract + if (data !== null && data !== undefined) { + if (typeof data !== 'string') { + this.reportInvalidData(data); + } + this._value = data as TChoice; + return; + } + + if (this.environmentVariable !== undefined) { + // Try reading the environment variable + const environmentValue: string | undefined = process.env[this.environmentVariable]; + if (environmentValue !== undefined && environmentValue !== '') { + if (!this.alternatives.has(environmentValue as TChoice)) { + const choices: string = '"' + Array.from(this.alternatives).join('", "') + '"'; + throw new Error( + `Invalid value "${environmentValue}" for the environment variable` + + ` ${this.environmentVariable}. Valid choices are: ${choices}` + ); + } + + this._value = environmentValue as TChoice; + return; + } + } + + if (this.defaultValue !== undefined) { + this._value = this.defaultValue; + return; + } + + this._value = undefined; + } + + /** + * {@inheritDoc CommandLineParameterBase._getSupplementaryNotes} + * @internal + */ + public _getSupplementaryNotes(supplementaryNotes: string[]): void { + // virtual + super._getSupplementaryNotes(supplementaryNotes); + if (this.defaultValue !== undefined) { + supplementaryNotes.push(`The default value is "${this.defaultValue}".`); + } + } + + /** + * Returns the argument value for a choice parameter that was parsed from the command line. + * + * @remarks + * The return value will be `undefined` if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get value(): TChoice | undefined { + return this._value; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.value !== undefined) { + argList.push(this.longName); + argList.push(this.value); + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineDefinition.ts b/libraries/ts-command-line/src/parameters/CommandLineDefinition.ts new file mode 100644 index 00000000000..6ae21c372af --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineDefinition.ts @@ -0,0 +1,257 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { SCOPING_PARAMETER_GROUP } from '../Constants'; + +/** + * For use with CommandLineParser, this interface represents a generic command-line parameter + * + * @public + */ +export interface IBaseCommandLineDefinition { + /** + * The long name of the flag including double dashes, e.g. "--do-something" + */ + parameterLongName: string; + + /** + * An optional short name for the flag including the dash, e.g. "-d" + */ + parameterShortName?: string; + + /** + * An optional parameter group name, shown when invoking the tool with "--help" + */ + parameterGroup?: string | typeof SCOPING_PARAMETER_GROUP; + + /** + * An optional parameter scope name, used to add a scope-prefixed parameter synonym, + * e.g. "--scope:do-something". Scopes provide additional flexibility for parameters + * in conflict resolution since when a scope is specified, parameters that have + * conflicting long names will be defined using only the scope-prefixed name. + */ + parameterScope?: string; + + /** + * Documentation for the parameter that will be shown when invoking the tool with "--help" + */ + description: string; + + /** + * If true, then an error occurs if the parameter was not included on the command-line. + */ + required?: boolean; + + /** + * The name of an environment variable that the parameter value will be read from, + * if it was omitted from the command-line. An error will be reported if the + * environment value cannot be parsed. + * + * @remarks + * The environment variable name must consist only of upper-case letters, numbers, + * and underscores. It may not start with a number. To disable this validation, set + * `{@link IBaseCommandLineDefinition.allowNonStandardEnvironmentVariableNames}` + * to `true`. + * + * Syntax notes for environment variable values: + * + * - Choice Parameter: The value must match one of the defined choices, + * otherwise a validation error is reported. + * An empty string causes the environment variable to be ignored. + * + * - Flag Parameter: The value must be `1` for true, or `0` for false, + * otherwise a validation error is reported. + * An empty string causes the environment variable to be ignored. + * + * - Integer Parameter: The value must be an integer number, + * otherwise a validation error is reported. + * An empty string causes the environment variable to be ignored. + * + * - String Parameter: Any value is accepted, including an empty string. + * + * - String List Parameter: If the string starts with `[` (ignoring whitespace) + * then it will be parsed as a JSON array, whose elements must be strings, + * numbers, or boolean values. + * If the string does not start with `[`, then it behaves like an + * ordinary String Parameter: Any value is accepted, including an empty string. + */ + environmentVariable?: string; + + /** + * Allows for the use of environment variable names that do not conform to the standard + * described by the Shell and Utilities volume of IEEE Std 1003.1-2001. This disables + * the validation that is performed on the provided + * {@link IBaseCommandLineDefinition.environmentVariable} value by default. + * + * @remarks + * if this is set to `true`, environment variable discovery will vary based on the + * platform in use. For example, Windows environment variable names are case-insensitive, + * while on Linux, environment variable names are case-sensitive. It is recommended that + * this option be used only when necessary based on environmental constraints. + */ + allowNonStandardEnvironmentVariableNames?: boolean; + + /** + * Specifies additional names for this parameter that are accepted but not displayed + * in the command line help. + * + * @remarks + * This option can be used in cases where a command-line parameter may have been renamed, + * but the developer doesn't want to break backwards compatibility with systems that may + * still be using the old name. Only the `parameterLongName` syntax is currently allowed. + */ + undocumentedSynonyms?: string[]; +} + +/** + * The common base interface for parameter types that accept an argument. + * + * @remarks + * An argument is an accompanying command-line token, such as "123" in the + * example "--max-count 123". + * @public + */ +export interface IBaseCommandLineDefinitionWithArgument extends IBaseCommandLineDefinition { + /** + * The name of the argument, which will be shown in the command-line help. + * + * @remarks + * For example, if the parameter name is '--count" and the argument name is "NUMBER", + * then the command-line help would display "--count NUMBER". The argument name must + * be comprised of upper-case letters, numbers, and underscores. It should be kept short. + */ + argumentName: string; + + /** + * An optional callback that provides a list of custom choices for tab completion. + * @remarks + * This option is only used when `ICommandLineParserOptions.enableTabCompletionAction` + * is enabled. + */ + getCompletionsAsync?: () => Promise | ReadonlySet>; +} + +/** + * For use with {@link CommandLineParameterProvider.(defineChoiceParameter:1)} and + * {@link CommandLineParameterProvider.(defineChoiceParameter:2)}, this interface + * defines a command line parameter which is constrained to a list of possible + * options. + * + * @public + */ +export interface ICommandLineChoiceDefinition + extends IBaseCommandLineDefinition { + /** + * A list of strings (which contain no spaces), of possible options which can be selected + */ + alternatives: ReadonlyArray | ReadonlySet; + + /** + * {@inheritDoc ICommandLineStringDefinition.defaultValue} + */ + defaultValue?: TChoice; + + /** + * An optional callback that provides a list of custom choices for tab completion. + * @remarks + * This option is only used when `ICommandLineParserOptions.enableTabCompletionAction` + * is enabled. + */ + completions?: () => Promise | ReadonlySet>; +} + +/** + * For use with {@link CommandLineParameterProvider.defineChoiceListParameter}, + * this interface defines a command line parameter which is constrained to a list of possible + * options. The parameter can be specified multiple times to build a list. + * + * @public + */ +export interface ICommandLineChoiceListDefinition + extends IBaseCommandLineDefinition { + /** + * A list of strings (which contain no spaces), of possible options which can be selected + */ + alternatives: ReadonlyArray | ReadonlySet; + + /** + * An optional callback that provides a list of custom choices for tab completion. + * @remarks + * This option is only used when `ICommandLineParserOptions.enableTabCompletionAction` + * is enabled. + */ + completions?: () => Promise | ReadonlySet>; +} + +/** + * For use with {@link CommandLineParameterProvider.defineFlagParameter}, + * this interface defines a command line parameter that is a boolean flag. + * + * @public + */ +export interface ICommandLineFlagDefinition extends IBaseCommandLineDefinition {} + +/** + * For use with {@link CommandLineParameterProvider.(defineIntegerParameter:1)}, + * {@link CommandLineParameterProvider.(defineIntegerParameter:2)}, this interface + * defines a command line parameter whose argument is an integer value. + * + * @public + */ +export interface ICommandLineIntegerDefinition extends IBaseCommandLineDefinitionWithArgument { + /** + * {@inheritDoc ICommandLineStringDefinition.defaultValue} + */ + defaultValue?: number; +} + +/** + * For use with {@link CommandLineParameterProvider.defineIntegerListParameter}, + * this interface defines a command line parameter whose argument is an integer value. The + * parameter can be specified multiple times to build a list. + * + * @public + */ +export interface ICommandLineIntegerListDefinition extends IBaseCommandLineDefinitionWithArgument {} + +/** + * For use with {@link CommandLineParameterProvider.(defineStringParameter:1)} and + * {@link CommandLineParameterProvider.(defineStringParameter:2)}, this interface + * defines a command line parameter whose argument is a string value. + * + * @public + */ +export interface ICommandLineStringDefinition extends IBaseCommandLineDefinitionWithArgument { + /** + * The default value which will be used if the parameter is omitted from the command line. + * + * @remarks + * If a default value is specified, then {@link IBaseCommandLineDefinition.required} + * must not be true. Instead, a custom error message should be used to report cases + * where a default value was not available. + */ + defaultValue?: string; +} + +/** + * For use with {@link CommandLineParameterProvider.defineStringListParameter}, + * this interface defines a command line parameter whose argument is a single text string. + * The parameter can be specified multiple times to build a list. + * + * @public + */ +export interface ICommandLineStringListDefinition extends IBaseCommandLineDefinitionWithArgument {} + +/** + * For use with {@link CommandLineParameterProvider.defineCommandLineRemainder}, + * this interface defines a rule that captures any remaining command line arguments after the recognized portion. + * + * @public + */ +export interface ICommandLineRemainderDefinition { + /** + * Documentation for how the remaining arguments will be used. This will be shown when invoking + * the tool with "--help". + */ + description: string; +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineFlagParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineFlagParameter.ts new file mode 100644 index 00000000000..e701ea3de4d --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineFlagParameter.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 type { ICommandLineFlagDefinition } from './CommandLineDefinition'; +import { CommandLineParameterBase, CommandLineParameterKind } from './BaseClasses'; + +/** + * The data type returned by {@link CommandLineParameterProvider.defineFlagParameter}. + * @public + */ +export class CommandLineFlagParameter extends CommandLineParameterBase { + private _value: boolean = false; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.Flag = CommandLineParameterKind.Flag; + + /** @internal */ + public constructor(definition: ICommandLineFlagDefinition) { + super(definition); + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // abstract + if (data !== null && data !== undefined) { + if (typeof data !== 'boolean') { + this.reportInvalidData(data); + } + + // If the flag is omitted, then argparse sets the data to "false" instead of "undefined". + // This design prevents a syntax such as "--flag=false", probably because argparse prefers "--no-flag". + // If we switch to a new CLI parser, we should try to add support for "--flag=false". + if (data) { + this._value = data; + return; + } + } + + if (this.environmentVariable !== undefined) { + // Try reading the environment variable + const environmentValue: string | undefined = process.env[this.environmentVariable]; + if (environmentValue !== undefined && environmentValue !== '') { + if (environmentValue !== '0' && environmentValue !== '1') { + throw new Error( + `Invalid value "${environmentValue}" for the environment variable` + + ` ${this.environmentVariable}. Valid choices are 0 or 1.` + ); + } + this._value = environmentValue === '1'; + return; + } + } + + this._value = false; + } + + /** + * Returns a boolean indicating whether the parameter was included in the command line. + * + * @remarks + * The return value will be false if the command-line has not been parsed yet, + * or if the flag was not used. + */ + public get value(): boolean { + return this._value; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.value) { + argList.push(this.longName); + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineIntegerListParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineIntegerListParameter.ts new file mode 100644 index 00000000000..9fae6dc9d94 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineIntegerListParameter.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ICommandLineIntegerListDefinition } from './CommandLineDefinition'; +import { CommandLineParameterWithArgument, CommandLineParameterKind } from './BaseClasses'; +import { EnvironmentVariableParser } from './EnvironmentVariableParser'; + +/** + * The data type returned by {@link CommandLineParameterProvider.defineIntegerListParameter}. + * @public + */ +export class CommandLineIntegerListParameter extends CommandLineParameterWithArgument { + private _values: number[] = []; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.IntegerList = CommandLineParameterKind.IntegerList; + + /** @internal */ + public constructor(definition: ICommandLineIntegerListDefinition) { + super(definition); + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // If argparse passed us a value, confirm it is valid + if (data !== null && data !== undefined) { + if (!Array.isArray(data)) { + this.reportInvalidData(data); + } + for (const arrayItem of data) { + if (typeof arrayItem !== 'number') { + this.reportInvalidData(data); + } + } + this._values = data; + return; + } + + // If an environment variable exists, attempt to parse it as a list + if (this.environmentVariable !== undefined) { + const values: string[] | undefined = EnvironmentVariableParser.parseAsList(this.environmentVariable); + if (values) { + const parsedValues: number[] = []; + for (const value of values) { + const parsed: number = parseInt(value, 10); + if (isNaN(parsed) || value.indexOf('.') >= 0) { + throw new Error( + `Invalid value "${value}" for the environment variable` + + ` ${this.environmentVariable}. It must be an integer value.` + ); + } + parsedValues.push(parsed); + } + this._values = parsedValues; + return; + } + } + + // (No default value for integer lists) + + this._values = []; + } + + /** + * Returns the integer arguments for an integer list parameter that was parsed from the command line. + * + * @remarks + * The array will be empty if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get values(): ReadonlyArray { + return this._values; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.values.length > 0) { + for (const value of this.values) { + argList.push(this.longName); + argList.push(value.toString()); + } + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineIntegerParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineIntegerParameter.ts new file mode 100644 index 00000000000..35bf8a7e559 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineIntegerParameter.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 type { ICommandLineIntegerDefinition } from './CommandLineDefinition'; +import { CommandLineParameterWithArgument, CommandLineParameterKind } from './BaseClasses'; + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineIntegerParameter:2)}. + * @public + */ +export interface IRequiredCommandLineIntegerParameter extends CommandLineIntegerParameter { + readonly value: number; +} + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineIntegerParameter:1)}. + * @public + */ +export class CommandLineIntegerParameter extends CommandLineParameterWithArgument { + /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ + public readonly defaultValue: number | undefined; + + private _value: number | undefined = undefined; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.Integer = CommandLineParameterKind.Integer; + + /** @internal */ + public constructor(definition: ICommandLineIntegerDefinition) { + super(definition); + this.defaultValue = definition.defaultValue; + this.validateDefaultValue(!!this.defaultValue); + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // abstract + if (data !== null && data !== undefined) { + if (typeof data !== 'number') { + this.reportInvalidData(data); + } + this._value = data; + return; + } + + if (this.environmentVariable !== undefined) { + // Try reading the environment variable + const environmentValue: string | undefined = process.env[this.environmentVariable]; + if (environmentValue !== undefined && environmentValue !== '') { + const parsed: number = parseInt(environmentValue, 10); + if (isNaN(parsed) || environmentValue.indexOf('.') >= 0) { + throw new Error( + `Invalid value "${environmentValue}" for the environment variable` + + ` ${this.environmentVariable}. It must be an integer value.` + ); + } + this._value = parsed; + return; + } + } + + if (this.defaultValue !== undefined) { + this._value = this.defaultValue; + return; + } + + this._value = undefined; + } + + /** + * {@inheritDoc CommandLineParameterBase._getSupplementaryNotes} + * @internal + */ + public _getSupplementaryNotes(supplementaryNotes: string[]): void { + // virtual + super._getSupplementaryNotes(supplementaryNotes); + if (this.defaultValue !== undefined) { + supplementaryNotes.push(`The default value is ${this.defaultValue}.`); + } + } + + /** + * Returns the argument value for an integer parameter that was parsed from the command line. + * + * @remarks + * The return value will be undefined if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get value(): number | undefined { + return this._value; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.value !== undefined) { + argList.push(this.longName); + argList.push(this.value.toString()); + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineRemainder.ts b/libraries/ts-command-line/src/parameters/CommandLineRemainder.ts new file mode 100644 index 00000000000..06e1106632a --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineRemainder.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 type { ICommandLineRemainderDefinition } from './CommandLineDefinition'; + +/** + * The data type returned by {@link CommandLineParameterProvider.defineCommandLineRemainder}. + * @public + */ +export class CommandLineRemainder { + private _values: string[] = []; + + /** {@inheritDoc IBaseCommandLineDefinition.description} */ + public readonly description: string; + + /** @internal */ + public constructor(definition: ICommandLineRemainderDefinition) { + this.description = definition.description; + } + + /** + * Returns any remaining command line arguments after the recognized portion + * that was parsed from the command line. + * + * @remarks + * The array will be empty if the command-line has not been parsed yet. + */ + public get values(): ReadonlyArray { + return this._values; + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // abstract + if (!Array.isArray(data) || !data.every((x) => typeof x === 'string')) { + throw new Error(`Unexpected data object for remainder: ` + JSON.stringify(data)); + } + + this._values.push(...data); + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.values.length > 0) { + for (const value of this.values) { + argList.push(value); + } + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineStringListParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineStringListParameter.ts new file mode 100644 index 00000000000..c62eed59971 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineStringListParameter.ts @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ICommandLineStringListDefinition } from './CommandLineDefinition'; +import { CommandLineParameterWithArgument, CommandLineParameterKind } from './BaseClasses'; +import { EnvironmentVariableParser } from './EnvironmentVariableParser'; + +/** + * The data type returned by {@link CommandLineParameterProvider.defineStringListParameter}. + * @public + */ +export class CommandLineStringListParameter extends CommandLineParameterWithArgument { + private _values: string[] = []; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.StringList = CommandLineParameterKind.StringList; + + /** @internal */ + public constructor(definition: ICommandLineStringListDefinition) { + super(definition); + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // If argparse passed us a value, confirm it is valid + if (data !== null && data !== undefined) { + if (!Array.isArray(data)) { + this.reportInvalidData(data); + } + for (const arrayItem of data) { + if (typeof arrayItem !== 'string') { + this.reportInvalidData(data); + } + } + this._values = data; + return; + } + + // If an environment variable exists, attempt to parse it as a list + if (this.environmentVariable !== undefined) { + const values: string[] | undefined = EnvironmentVariableParser.parseAsList(this.environmentVariable); + if (values) { + this._values = values; + return; + } + } + + // (No default value for string lists) + + this._values = []; + } + + /** + * Returns the string arguments for a string list parameter that was parsed from the command line. + * + * @remarks + * The array will be empty if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get values(): ReadonlyArray { + return this._values; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.values.length > 0) { + for (const value of this.values) { + argList.push(this.longName); + argList.push(value); + } + } + } +} diff --git a/libraries/ts-command-line/src/parameters/CommandLineStringParameter.ts b/libraries/ts-command-line/src/parameters/CommandLineStringParameter.ts new file mode 100644 index 00000000000..47947618f8d --- /dev/null +++ b/libraries/ts-command-line/src/parameters/CommandLineStringParameter.ts @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ICommandLineStringDefinition } from './CommandLineDefinition'; +import { CommandLineParameterWithArgument, CommandLineParameterKind } from './BaseClasses'; + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineStringParameter:2)}. + * @public + */ +export interface IRequiredCommandLineStringParameter extends CommandLineStringParameter { + readonly value: string; +} + +/** + * The data type returned by {@link CommandLineParameterProvider.(defineStringParameter:1)}. + * @public + */ +export class CommandLineStringParameter extends CommandLineParameterWithArgument { + /** {@inheritDoc ICommandLineStringDefinition.defaultValue} */ + public readonly defaultValue: string | undefined; + + private _value: string | undefined = undefined; + + /** {@inheritDoc CommandLineParameterBase.kind} */ + public readonly kind: CommandLineParameterKind.String = CommandLineParameterKind.String; + + /** @internal */ + public constructor(definition: ICommandLineStringDefinition) { + super(definition); + + this.defaultValue = definition.defaultValue; + this.validateDefaultValue(!!this.defaultValue); + } + + /** + * {@inheritDoc CommandLineParameterBase._setValue} + * @internal + */ + public _setValue(data: unknown): void { + // abstract + if (data !== null && data !== undefined) { + if (typeof data !== 'string') { + this.reportInvalidData(data); + } + this._value = data; + return; + } + + if (this.environmentVariable !== undefined) { + // Try reading the environment variable + const environmentValue: string | undefined = process.env[this.environmentVariable]; + if (environmentValue !== undefined) { + // NOTE: If the environment variable is defined as an empty string, + // here we will accept the empty string as our value. (For number/flag we don't do that.) + this._value = environmentValue; + return; + } + } + + if (this.defaultValue !== undefined) { + this._value = this.defaultValue; + return; + } + + this._value = undefined; + } + + /** + * {@inheritDoc CommandLineParameterBase._getSupplementaryNotes} + * @internal + */ + public _getSupplementaryNotes(supplementaryNotes: string[]): void { + // virtual + super._getSupplementaryNotes(supplementaryNotes); + if (this.defaultValue !== undefined) { + if (this.defaultValue.length < 160) { + supplementaryNotes.push(`The default value is ${JSON.stringify(this.defaultValue)}.`); + } + } + } + + /** + * Returns the argument value for a string parameter that was parsed from the command line. + * + * @remarks + * The return value will be undefined if the command-line has not been parsed yet, + * or if the parameter was omitted and has no default value. + */ + public get value(): string | undefined { + return this._value; + } + + /** {@inheritDoc CommandLineParameterBase.appendToArgList} @override */ + public appendToArgList(argList: string[]): void { + if (this.value !== undefined) { + argList.push(this.longName); + argList.push(this.value); + } + } +} diff --git a/libraries/ts-command-line/src/parameters/EnvironmentVariableParser.ts b/libraries/ts-command-line/src/parameters/EnvironmentVariableParser.ts new file mode 100644 index 00000000000..f25dd17b015 --- /dev/null +++ b/libraries/ts-command-line/src/parameters/EnvironmentVariableParser.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. + +/** + * Some parameter types can receive their values from an environment variable instead of + * a command line argument. This class provides some utility methods for parsing environment + * variable values. + * @internal + */ +export class EnvironmentVariableParser { + public static parseAsList(envVarName: string): string[] | undefined { + const environmentValue: string | undefined = process.env[envVarName]; + + if (environmentValue !== undefined) { + // NOTE: If the environment variable is defined as an empty string, + // here we will accept the empty string as our value. (For number/flag we don't do that.) + + if (environmentValue.trimLeft()[0] === '[') { + // Specifying multiple items in an environment variable is a somewhat rare case. But environment + // variables are actually a pretty reliable way for a tool to avoid shell escaping problems + // when spawning another tool. For this case, we need a reliable way to pass an array of strings + // that could contain any character. For example, if we simply used ";" as the list delimiter, + // then what to do if a string contains that character? We'd need to design an escaping mechanism. + // Since JSON is simple and standard and can escape every possible string, it's a better option + // than a custom delimiter. + try { + const parsedJson: unknown = JSON.parse(environmentValue); + if ( + !Array.isArray(parsedJson) || + !parsedJson.every((x) => typeof x === 'string' || typeof x === 'boolean' || typeof x === 'number') + ) { + throw new Error( + `The ${environmentValue} environment variable value must be a JSON ` + + ` array containing only strings, numbers, and booleans.` + ); + } + return parsedJson.map((x) => x.toString()); + } catch (ex) { + throw new Error( + `The ${environmentValue} environment variable value looks like a JSON array` + + ` but failed to parse: ` + + (ex as Error).message + ); + } + } else { + // As a shorthand, a single value may be specified without JSON encoding, as long as it does not + // start with the "[" character. + return [environmentValue]; + } + } + + return undefined; + } +} diff --git a/libraries/ts-command-line/src/providers/AliasCommandLineAction.ts b/libraries/ts-command-line/src/providers/AliasCommandLineAction.ts new file mode 100644 index 00000000000..9002099c723 --- /dev/null +++ b/libraries/ts-command-line/src/providers/AliasCommandLineAction.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 * as argparse from 'argparse'; + +import { CommandLineAction } from './CommandLineAction'; +import { + CommandLineParameterKind, + type CommandLineParameterBase, + type CommandLineParameter +} from '../parameters/BaseClasses'; +import type { ICommandLineParserData, IRegisterDefinedParametersState } from './CommandLineParameterProvider'; +import type { ICommandLineParserOptions } from './CommandLineParser'; + +/** + * Options for the AliasCommandLineAction constructor. + * @public + */ +export interface IAliasCommandLineActionOptions { + /** + * The name of your tool when invoked from the command line. Used for generating help text. + */ + toolFilename: string; + + /** + * The name of the alias. For example, if the tool is called "example", + * then the "build" alias might be invoked as: "example build -q --some-other-option" + */ + aliasName: string; + + /** + * A list of default parameters to pass to the target action. + */ + defaultParameters?: string[]; + + /** + * The action that this alias invokes. + */ + targetAction: CommandLineAction; +} + +/** + * Represents a sub-command that is part of the CommandLineParser command line. + * The sub-command is an alias for another existing action. + * + * The alias name should be comprised of lower case words separated by hyphens + * or colons. The name should include an English verb (e.g. "deploy"). Use a + * hyphen to separate words (e.g. "upload-docs"). + * + * @public + */ +export class AliasCommandLineAction extends CommandLineAction { + /** + * The action that this alias invokes. + */ + public readonly targetAction: CommandLineAction; + + /** + * A list of default arguments to pass to the target action. + */ + public readonly defaultParameters: ReadonlyArray; + + private _parameterKeyMap: Map = new Map(); + + public constructor(options: IAliasCommandLineActionOptions) { + const toolFilename: string = options.toolFilename; + const targetActionName: string = options.targetAction.actionName; + const defaultParametersString: string = (options.defaultParameters || []).join(' '); + const summary: string = `An alias for "${toolFilename} ${targetActionName}${ + defaultParametersString ? ` ${defaultParametersString}` : '' + }".`; + + super({ + actionName: options.aliasName, + summary, + documentation: + `${summary} For more information on the aliased command, use ` + + `"${toolFilename} ${targetActionName} --help".` + }); + + this.targetAction = options.targetAction; + this.defaultParameters = options.defaultParameters || []; + } + + /** @internal */ + public _registerDefinedParameters(state: IRegisterDefinedParametersState): void { + /* override */ + // All parameters are going to be defined by the target action. Re-use the target action parameters + // for this action. + for (const parameter of this.targetAction.parameters as CommandLineParameter[]) { + const { kind, longName, shortName } = parameter; + let aliasParameter: CommandLineParameterBase; + const nameOptions: { parameterLongName: string; parameterShortName: string | undefined } = { + parameterLongName: longName, + parameterShortName: shortName + }; + switch (kind) { + case CommandLineParameterKind.Choice: + aliasParameter = this.defineChoiceParameter({ + ...nameOptions, + ...parameter, + alternatives: [...parameter.alternatives] + }); + break; + case CommandLineParameterKind.ChoiceList: + aliasParameter = this.defineChoiceListParameter({ + ...nameOptions, + ...parameter, + alternatives: [...parameter.alternatives] + }); + break; + case CommandLineParameterKind.Flag: + aliasParameter = this.defineFlagParameter({ ...nameOptions, ...parameter }); + break; + case CommandLineParameterKind.Integer: + aliasParameter = this.defineIntegerParameter({ ...nameOptions, ...parameter }); + break; + case CommandLineParameterKind.IntegerList: + aliasParameter = this.defineIntegerListParameter({ ...nameOptions, ...parameter }); + break; + case CommandLineParameterKind.String: + aliasParameter = this.defineStringParameter({ ...nameOptions, ...parameter }); + break; + case CommandLineParameterKind.StringList: + aliasParameter = this.defineStringListParameter({ ...nameOptions, ...parameter }); + break; + default: + throw new Error(`Unsupported parameter kind: ${kind}`); + } + + // We know the parserKey is defined because the underlying _defineParameter method sets it, + // and all parameters that we have access to have already been defined. + this._parameterKeyMap.set(aliasParameter._parserKey!, parameter._parserKey!); + } + + // We also need to register the remainder parameter if the target action has one. The parser + // key for this parameter is constant. + if (this.targetAction.remainder) { + this.defineCommandLineRemainder(this.targetAction.remainder); + this._parameterKeyMap.set(argparse.Const.REMAINDER, argparse.Const.REMAINDER); + } + + // Finally, register the parameters with the parser. We need to make sure that the target action + // is registered, since we need to re-use its parameters, and ambiguous parameters are discovered + // during registration. This will no-op if the target action is already registered. + this.targetAction._registerDefinedParameters(state); + super._registerDefinedParameters(state); + + // We need to re-map the ambiguous parameters after they are defined by calling + // super._registerDefinedParameters() + for (const [ambiguousParameterName, parserKey] of this._ambiguousParameterParserKeysByName) { + const targetParserKey: string | undefined = + this.targetAction._ambiguousParameterParserKeysByName.get(ambiguousParameterName); + + // If we have a mapping for the specified key, then use it. Otherwise, use the key as-is. + if (targetParserKey) { + this._parameterKeyMap.set(parserKey, targetParserKey); + } + } + } + + /** + * {@inheritdoc CommandLineParameterProvider._processParsedData} + * @internal + */ + public _processParsedData(parserOptions: ICommandLineParserOptions, data: ICommandLineParserData): void { + // Re-map the parsed data to the target action's parameters and execute the target action processor. + const targetData: ICommandLineParserData = { + action: this.targetAction.actionName, + aliasAction: data.action, + aliasDocumentation: this.documentation + }; + for (const [key, value] of Object.entries(data)) { + // If we have a mapping for the specified key, then use it. Otherwise, use the key as-is. + // Skip over the action key though, since we've already re-mapped it to "aliasAction" + if (key === 'action') { + continue; + } + const targetKey: string | undefined = this._parameterKeyMap.get(key); + targetData[targetKey ?? key] = value; + } + this.targetAction._processParsedData(parserOptions, targetData); + } + + /** + * Executes the target action. + */ + protected override async onExecuteAsync(): Promise { + await this.targetAction._executeAsync(); + } +} diff --git a/libraries/ts-command-line/src/providers/CommandLineAction.ts b/libraries/ts-command-line/src/providers/CommandLineAction.ts new file mode 100644 index 00000000000..350ae50c6a3 --- /dev/null +++ b/libraries/ts-command-line/src/providers/CommandLineAction.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 type * as argparse from 'argparse'; + +import { CommandLineParameterProvider } from './CommandLineParameterProvider'; +import { CommandLineParserExitError } from './CommandLineParserExitError'; +import { escapeSprintf } from '../escapeSprintf'; + +/** + * Options for the CommandLineAction constructor. + * @public + */ +export interface ICommandLineActionOptions { + /** + * The name of the action. For example, if the tool is called "example", + * then the "build" action might be invoked as: "example build -q --some-other-option" + */ + actionName: string; + + /** + * A quick summary that is shown on the main help page, which is displayed + * by the command "example --help" + */ + summary: string; + + /** + * A detailed description that is shown on the action help page, which is displayed + * by the command "example build --help", e.g. for actionName="build". + */ + documentation: string; +} + +/** + * Example: "do-something" + */ +const ACTION_NAME_REGEXP: RegExp = /^[a-z][a-z0-9]*([-:][a-z0-9]+)*$/; + +/** + * Represents a sub-command that is part of the CommandLineParser command line. + * Applications should create subclasses of CommandLineAction corresponding to + * each action that they want to expose. + * + * The action name should be comprised of lower case words separated by hyphens + * or colons. The name should include an English verb (e.g. "deploy"). Use a + * hyphen to separate words (e.g. "upload-docs"). A group of related commands + * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", + * "docs:serve", etc). + * + * @public + */ +export abstract class CommandLineAction extends CommandLineParameterProvider { + /** {@inheritDoc ICommandLineActionOptions.actionName} */ + public readonly actionName: string; + + /** {@inheritDoc ICommandLineActionOptions.summary} */ + public readonly summary: string; + + /** {@inheritDoc ICommandLineActionOptions.documentation} */ + public readonly documentation: string; + + private _argumentParser: argparse.ArgumentParser | undefined; + + public constructor(options: ICommandLineActionOptions) { + super(); + + if (!ACTION_NAME_REGEXP.test(options.actionName)) { + throw new Error( + `Invalid action name "${options.actionName}". ` + + `The name must be comprised of lower-case words optionally separated by hyphens or colons.` + ); + } + + this.actionName = options.actionName; + this.summary = options.summary; + this.documentation = options.documentation; + + this._argumentParser = undefined; + } + + /** + * This is called internally by CommandLineParser.addAction() + * @internal + */ + public _buildParser(actionsSubParser: argparse.SubParser): void { + this._argumentParser = actionsSubParser.addParser(this.actionName, { + help: escapeSprintf(this.summary), + description: escapeSprintf(this.documentation) + }); + + // Monkey-patch the error handling for the action parser + this._argumentParser.exit = (status: number, message: string) => { + throw new CommandLineParserExitError(status, message); + }; + const originalArgumentParserErrorFn: (err: Error | string) => void = this._argumentParser.error.bind( + this._argumentParser + ); + this._argumentParser.error = (err: Error | string) => { + // Ensure the ParserExitError bubbles up to the top without any special processing + if (err instanceof CommandLineParserExitError) { + throw err; + } + originalArgumentParserErrorFn(err); + }; + } + + /** + * Invoked by CommandLineParser.onExecute(). + * @internal + */ + public async _executeAsync(): Promise { + await this.onExecuteAsync(); + } + + /** + * {@inheritDoc CommandLineParameterProvider._getArgumentParser} + * @internal + */ + public override _getArgumentParser(): argparse.ArgumentParser { + if (!this._argumentParser) { + // We will improve this in the future + throw new Error('The CommandLineAction must be added to a CommandLineParser before it can be used'); + } + + return this._argumentParser; + } + + /** + * Your subclass should implement this hook to perform the operation. + */ + protected abstract onExecuteAsync(): Promise; +} diff --git a/libraries/ts-command-line/src/providers/CommandLineParameterProvider.ts b/libraries/ts-command-line/src/providers/CommandLineParameterProvider.ts new file mode 100644 index 00000000000..9ff64b48a25 --- /dev/null +++ b/libraries/ts-command-line/src/providers/CommandLineParameterProvider.ts @@ -0,0 +1,1035 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as argparse from 'argparse'; + +import type { + ICommandLineChoiceDefinition, + ICommandLineChoiceListDefinition, + ICommandLineIntegerDefinition, + ICommandLineIntegerListDefinition, + ICommandLineFlagDefinition, + ICommandLineStringDefinition, + ICommandLineStringListDefinition, + ICommandLineRemainderDefinition +} from '../parameters/CommandLineDefinition'; +import type { ICommandLineParserOptions } from './CommandLineParser'; +import { + type CommandLineParameterBase, + type CommandLineParameterWithArgument, + CommandLineParameterKind, + type CommandLineParameter +} from '../parameters/BaseClasses'; +import { + CommandLineChoiceParameter, + type IRequiredCommandLineChoiceParameter +} from '../parameters/CommandLineChoiceParameter'; +import { CommandLineChoiceListParameter } from '../parameters/CommandLineChoiceListParameter'; +import { + CommandLineIntegerParameter, + type IRequiredCommandLineIntegerParameter +} from '../parameters/CommandLineIntegerParameter'; +import { CommandLineIntegerListParameter } from '../parameters/CommandLineIntegerListParameter'; +import { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { + CommandLineStringParameter, + type IRequiredCommandLineStringParameter +} from '../parameters/CommandLineStringParameter'; +import { CommandLineStringListParameter } from '../parameters/CommandLineStringListParameter'; +import { CommandLineRemainder } from '../parameters/CommandLineRemainder'; +import { SCOPING_PARAMETER_GROUP } from '../Constants'; +import { CommandLineParserExitError } from './CommandLineParserExitError'; +import { escapeSprintf } from '../escapeSprintf'; + +/** + * The result containing the parsed parameter long name and scope. Returned when calling + * {@link CommandLineParameterProvider.parseScopedLongName}. + * + * @public + */ +export interface IScopedLongNameParseResult { + /** + * The long name parsed from the scoped long name, e.g. "--my-scope:my-parameter" -\> "--my-parameter" + */ + longName: string; + + /** + * The scope parsed from the scoped long name or undefined if no scope was found, + * e.g. "--my-scope:my-parameter" -\> "my-scope" + */ + scope: string | undefined; +} + +/** + * An object containing the state of the + * + * @internal + */ +export interface IRegisterDefinedParametersState { + /** + * A set of all defined parameter names registered by parent {@link CommandLineParameterProvider} + * objects. + */ + parentParameterNames: Set; +} + +/** + * This is the argparse result data object + * @internal + */ +export interface ICommandLineParserData { + action: string; + aliasAction?: string; + aliasDocumentation?: string; + [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any +} + +const SCOPE_GROUP_NAME: string = 'scope'; +const LONG_NAME_GROUP_NAME: string = 'longName'; +const POSSIBLY_SCOPED_LONG_NAME_REGEXP: RegExp = + /^--((?[a-z0-9]+(-[a-z0-9]+)*):)?(?[a-z0-9]+((-[a-z0-9]+)+)?)$/; + +interface IExtendedArgumentGroup extends argparse.ArgumentGroup { + // The types are incorrect - this function returns the constructed argument + // object, which looks like the argument options type. + addArgument(nameOrFlags: string | string[], options: argparse.ArgumentOptions): argparse.ArgumentOptions; +} + +interface IExtendedArgumentParser extends argparse.ArgumentParser { + // This function throws + error(message: string): never; +} + +/** + * This is the common base class for CommandLineAction and CommandLineParser + * that provides functionality for defining command-line parameters. + * + * @public + */ +export abstract class CommandLineParameterProvider { + private static _keyCounter: number = 0; + + /** @internal */ + public readonly _ambiguousParameterParserKeysByName: Map; + /** @internal */ + protected readonly _registeredParameterParserKeysByName: Map; + + private readonly _parameters: CommandLineParameter[]; + private readonly _parametersByLongName: Map; + private readonly _parametersByShortName: Map; + private readonly _parameterGroupsByName: Map< + string | typeof SCOPING_PARAMETER_GROUP, + argparse.ArgumentGroup + >; + private _parametersHaveBeenRegistered: boolean; + private _parametersHaveBeenProcessed: boolean; + private _remainder: CommandLineRemainder | undefined; + + /** @internal */ + // Third party code should not inherit subclasses or call this constructor + public constructor() { + this._parameters = []; + this._parametersByLongName = new Map(); + this._parametersByShortName = new Map(); + this._parameterGroupsByName = new Map(); + this._ambiguousParameterParserKeysByName = new Map(); + this._registeredParameterParserKeysByName = new Map(); + this._parametersHaveBeenRegistered = false; + this._parametersHaveBeenProcessed = false; + } + + /** + * Returns a collection of the parameters that were defined for this object. + */ + public get parameters(): ReadonlyArray { + return this._parameters; + } + + /** + * Informs the caller if the argparse data has been processed into parameters. + */ + public get parametersProcessed(): boolean { + return this._parametersHaveBeenProcessed; + } + + /** + * If {@link CommandLineParameterProvider.defineCommandLineRemainder} was called, + * this object captures any remaining command line arguments after the recognized portion. + */ + public get remainder(): CommandLineRemainder | undefined { + return this._remainder; + } + + /** + * Defines a command-line parameter whose value must be a string from a fixed set of + * allowable choices (similar to an enum). + * + * @remarks + * Example of a choice parameter: + * ``` + * example-tool --log-level warn + * ``` + */ + public defineChoiceParameter( + definition: ICommandLineChoiceDefinition & { + required: false | undefined; + defaultValue: undefined; + } + ): CommandLineChoiceParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineChoiceParameter:1)} + */ + public defineChoiceParameter( + definition: ICommandLineChoiceDefinition & { required: true } + ): IRequiredCommandLineChoiceParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineChoiceParameter:1)} + */ + public defineChoiceParameter( + definition: ICommandLineChoiceDefinition & { defaultValue: TChoice } + ): IRequiredCommandLineChoiceParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineChoiceParameter:1)} + */ + public defineChoiceParameter( + definition: ICommandLineChoiceDefinition + ): CommandLineChoiceParameter; + public defineChoiceParameter( + definition: ICommandLineChoiceDefinition + ): CommandLineChoiceParameter { + const parameter: CommandLineChoiceParameter = new CommandLineChoiceParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineChoiceParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getChoiceParameter(parameterLongName: string, parameterScope?: string): CommandLineChoiceParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.Choice, parameterScope); + } + + /** + * Defines a command-line parameter whose value must be a string from a fixed set of + * allowable choices (similar to an enum). The parameter can be specified multiple times to + * build a list. + * + * @remarks + * Example of a choice list parameter: + * ``` + * example-tool --allow-color red --allow-color green + * ``` + */ + public defineChoiceListParameter( + definition: ICommandLineChoiceListDefinition + ): CommandLineChoiceListParameter { + const parameter: CommandLineChoiceListParameter = new CommandLineChoiceListParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineChoiceListParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getChoiceListParameter( + parameterLongName: string, + parameterScope?: string + ): CommandLineChoiceListParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.ChoiceList, parameterScope); + } + + /** + * Defines a command-line switch whose boolean value is true if the switch is provided, + * and false otherwise. + * + * @remarks + * Example usage of a flag parameter: + * ``` + * example-tool --debug + * ``` + */ + public defineFlagParameter(definition: ICommandLineFlagDefinition): CommandLineFlagParameter { + const parameter: CommandLineFlagParameter = new CommandLineFlagParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineFlagParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getFlagParameter(parameterLongName: string, parameterScope?: string): CommandLineFlagParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.Flag, parameterScope); + } + + /** + * Defines a command-line parameter whose argument is an integer. + * + * @remarks + * Example usage of an integer parameter: + * ``` + * example-tool --max-attempts 5 + * ``` + */ + public defineIntegerParameter( + definition: ICommandLineIntegerDefinition & { required: false | undefined; defaultValue: undefined } + ): CommandLineIntegerParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineIntegerParameter:1)} + */ + public defineIntegerParameter( + definition: ICommandLineIntegerDefinition & { required: true } + ): IRequiredCommandLineIntegerParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineIntegerParameter:1)} + */ + public defineIntegerParameter( + definition: ICommandLineIntegerDefinition & { defaultValue: number } + ): IRequiredCommandLineIntegerParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineIntegerParameter:1)} + */ + public defineIntegerParameter(definition: ICommandLineIntegerDefinition): CommandLineIntegerParameter; + public defineIntegerParameter(definition: ICommandLineIntegerDefinition): CommandLineIntegerParameter { + const parameter: CommandLineIntegerParameter = new CommandLineIntegerParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineIntegerParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getIntegerParameter( + parameterLongName: string, + parameterScope?: string + ): CommandLineIntegerParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.Integer, parameterScope); + } + + /** + * Defines a command-line parameter whose argument is an integer. The parameter can be specified + * multiple times to build a list. + * + * @remarks + * Example usage of an integer list parameter: + * ``` + * example-tool --avoid 4 --avoid 13 + * ``` + */ + public defineIntegerListParameter( + definition: ICommandLineIntegerListDefinition + ): CommandLineIntegerListParameter { + const parameter: CommandLineIntegerListParameter = new CommandLineIntegerListParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineIntegerParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getIntegerListParameter( + parameterLongName: string, + parameterScope?: string + ): CommandLineIntegerListParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.IntegerList, parameterScope); + } + + /** + * Defines a command-line parameter whose argument is a single text string. + * + * @remarks + * Example usage of a string parameter: + * ``` + * example-tool --message "Hello, world!" + * ``` + */ + public defineStringParameter( + definition: ICommandLineStringDefinition & { required: false | undefined; defaultValue: undefined } + ): CommandLineStringParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineStringParameter:1)} + */ + public defineStringParameter( + definition: ICommandLineStringDefinition & { required: true } + ): IRequiredCommandLineStringParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineStringParameter:1)} + */ + public defineStringParameter( + definition: ICommandLineStringDefinition & { defaultValue: string } + ): IRequiredCommandLineStringParameter; + /** + * {@inheritdoc CommandLineParameterProvider.(defineStringParameter:1)} + */ + public defineStringParameter(definition: ICommandLineStringDefinition): CommandLineStringParameter; + public defineStringParameter(definition: ICommandLineStringDefinition): CommandLineStringParameter { + const parameter: CommandLineStringParameter = new CommandLineStringParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Returns the CommandLineStringParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getStringParameter(parameterLongName: string, parameterScope?: string): CommandLineStringParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.String, parameterScope); + } + + /** + * Defines a command-line parameter whose argument is a single text string. The parameter can be + * specified multiple times to build a list. + * + * @remarks + * Example usage of a string list parameter: + * ``` + * example-tool --add file1.txt --add file2.txt --add file3.txt + * ``` + */ + public defineStringListParameter( + definition: ICommandLineStringListDefinition + ): CommandLineStringListParameter { + const parameter: CommandLineStringListParameter = new CommandLineStringListParameter(definition); + this._defineParameter(parameter); + return parameter; + } + + /** + * Defines a rule that captures any remaining command line arguments after the recognized portion. + * + * @remarks + * This feature is useful for commands that pass their arguments along to an external tool, relying on + * that tool to perform validation. (It could also be used to parse parameters without any validation + * or documentation, but that is not recommended.) + * + * Example of capturing the remainder after an optional flag parameter. + * ``` + * example-tool --my-flag this is the remainder + * ``` + * + * In the "--help" documentation, the remainder rule will be represented as "...". + */ + public defineCommandLineRemainder(definition: ICommandLineRemainderDefinition): CommandLineRemainder { + if (this._remainder) { + throw new Error('defineRemainingArguments() has already been called for this provider'); + } + this._remainder = new CommandLineRemainder(definition); + return this._remainder; + } + + /** + * Returns the CommandLineStringListParameter with the specified long name. + * @remarks + * This method throws an exception if the parameter is not defined. + */ + public getStringListParameter( + parameterLongName: string, + parameterScope?: string + ): CommandLineStringListParameter { + return this._getParameter(parameterLongName, CommandLineParameterKind.StringList, parameterScope); + } + + /** + * Generates the command-line help text. + */ + public renderHelpText(): string { + const initialState: IRegisterDefinedParametersState = { + parentParameterNames: new Set() + }; + this._registerDefinedParameters(initialState); + return this._getArgumentParser().formatHelp(); + } + + /** + * Generates the command-line usage text. + */ + public renderUsageText(): string { + const initialState: IRegisterDefinedParametersState = { + parentParameterNames: new Set() + }; + this._registerDefinedParameters(initialState); + return this._getArgumentParser().formatUsage(); + } + + /** + * Returns a object which maps the long name of each parameter in this.parameters + * to the stringified form of its value. This is useful for logging telemetry, but + * it is not the proper way of accessing parameters or their values. + */ + public getParameterStringMap(): Record { + const parameterMap: Record = {}; + for (const parameter of this.parameters) { + const parameterName: string = parameter.scopedLongName || parameter.longName; + switch (parameter.kind) { + case CommandLineParameterKind.Flag: + case CommandLineParameterKind.Choice: + case CommandLineParameterKind.String: + case CommandLineParameterKind.Integer: + parameterMap[parameterName] = JSON.stringify( + ( + parameter as + | CommandLineFlagParameter + | CommandLineIntegerParameter + | CommandLineChoiceParameter + | CommandLineStringParameter + ).value + ); + break; + case CommandLineParameterKind.StringList: + case CommandLineParameterKind.IntegerList: + case CommandLineParameterKind.ChoiceList: + const arrayValue: ReadonlyArray | undefined = ( + parameter as + | CommandLineIntegerListParameter + | CommandLineStringListParameter + | CommandLineChoiceListParameter + ).values; + parameterMap[parameterName] = arrayValue ? arrayValue.join(',') : ''; + break; + } + } + return parameterMap; + } + + /** + * Returns an object with the parsed scope (if present) and the long name of the parameter. + */ + public parseScopedLongName(scopedLongName: string): IScopedLongNameParseResult { + const result: RegExpExecArray | null = POSSIBLY_SCOPED_LONG_NAME_REGEXP.exec(scopedLongName); + if (!result || !result.groups) { + throw new Error(`The parameter long name "${scopedLongName}" is not valid.`); + } + return { + longName: `--${result.groups[LONG_NAME_GROUP_NAME]}`, + scope: result.groups[SCOPE_GROUP_NAME] + }; + } + + /** @internal */ + public _registerDefinedParameters(state: IRegisterDefinedParametersState): void { + if (this._parametersHaveBeenRegistered) { + // We prevent new parameters from being defined after the first call to _registerDefinedParameters, + // so we can already ensure that all parameters were registered. + return; + } + + // First, loop through all parameters with short names. If there are any duplicates, disable the short names + // since we can't prefix scopes to short names in order to deduplicate them. The duplicate short names will + // be reported as errors if the user attempts to use them. + const parametersWithDuplicateShortNames: Set = new Set(); + for (const [shortName, shortNameParameters] of this._parametersByShortName.entries()) { + if (shortNameParameters.length > 1) { + for (const parameter of shortNameParameters) { + this._defineAmbiguousParameter(shortName); + parametersWithDuplicateShortNames.add(parameter); + } + } + } + + // Then, loop through all parameters and register them. If there are any duplicates, ensure that they have + // provided a scope and register them with the scope. The duplicate long names will be reported as an error + // if the user attempts to use them. + for (const longNameParameters of this._parametersByLongName.values()) { + const useScopedLongName: boolean = longNameParameters.length > 1; + for (const parameter of longNameParameters) { + if (useScopedLongName) { + if (!parameter.parameterScope) { + throw new Error( + `The parameter "${parameter.longName}" is defined multiple times with the same long name. ` + + 'Parameters with the same long name must define a scope.' + ); + } + this._defineAmbiguousParameter(parameter.longName); + } + + const ignoreShortName: boolean = parametersWithDuplicateShortNames.has(parameter); + this._registerParameter(parameter, useScopedLongName, ignoreShortName); + } + } + + // Register the existing parameters as ambiguous parameters. These are generally provided by the + // parent action. + const { parentParameterNames } = state; + for (const parentParameterName of parentParameterNames) { + this._defineAmbiguousParameter(parentParameterName); + } + + // We also need to loop through the defined ambiguous parameters and register them. These will be reported + // as errors if the user attempts to use them. + for (const [ambiguousParameterName, parserKey] of this._ambiguousParameterParserKeysByName) { + // Only register the ambiguous parameter if it hasn't already been registered. We will still handle these + // already-registered parameters as ambiguous, but by avoiding registering again, we will defer errors + // until the user actually attempts to use the parameter. + if (!this._registeredParameterParserKeysByName.has(ambiguousParameterName)) { + this._registerAmbiguousParameter(ambiguousParameterName, parserKey); + } + } + + // Need to add the remainder parameter last + if (this._remainder) { + const argparseOptions: argparse.ArgumentOptions = { + help: this._remainder.description, + nargs: argparse.Const.REMAINDER, + metavar: '"..."' + }; + + this._getArgumentParser().addArgument(argparse.Const.REMAINDER, argparseOptions); + } + + this._parametersHaveBeenRegistered = true; + } + + /** + * Retrieves the argparse object. + * @internal + */ + protected abstract _getArgumentParser(): argparse.ArgumentParser; + + /** + * This is called internally by {@link CommandLineParser.executeAsync} + * @internal + */ + public _preParse(): void { + for (const parameter of this._parameters) { + parameter._preParse?.(); + } + } + + /** + * This is called internally by {@link CommandLineParser.executeAsync} before `printUsage` is called + * @internal + */ + public _postParse(): void { + for (const parameter of this._parameters) { + parameter._postParse?.(); + } + } + + /** + * This is called internally by {@link CommandLineParser.executeAsync} + * @internal + */ + public _processParsedData(parserOptions: ICommandLineParserOptions, data: ICommandLineParserData): void { + if (!this._parametersHaveBeenRegistered) { + throw new Error('Parameters have not been registered'); + } + + if (this._parametersHaveBeenProcessed) { + throw new Error('Command Line Parser Data was already processed'); + } + + // Search for any ambiguous parameters and throw an error if any are found + for (const [parameterName, parserKey] of this._ambiguousParameterParserKeysByName) { + if (data[parserKey]) { + // When the parser key matches the actually registered parameter, we know that this is an ambiguous + // parameter sourced from the parent action or tool + if (this._registeredParameterParserKeysByName.get(parameterName) === parserKey) { + this._throwParserExitError(parserOptions, data, 1, `Ambiguous option: "${parameterName}".`); + } + + // Determine if the ambiguous parameter is a short name or a long name, since the process of finding + // the non-ambiguous name is different for each. + const duplicateShortNameParameters: CommandLineParameterBase[] | undefined = + this._parametersByShortName.get(parameterName); + if (duplicateShortNameParameters) { + // We also need to make sure we get the non-ambiguous long name for the parameter, since it is + // possible for that the long name is ambiguous as well. + const nonAmbiguousLongNames: string[] = []; + for (const parameter of duplicateShortNameParameters) { + const matchingLongNameParameters: CommandLineParameterBase[] | undefined = + this._parametersByLongName.get(parameter.longName); + if (!matchingLongNameParameters?.length) { + // This should never happen + throw new Error( + `Unable to find long name parameters for ambiguous short name parameter "${parameterName}".` + ); + } + // If there is more than one matching long name parameter, then we know that we need to use the + // scoped long name for the parameter. The scoped long name should always be provided. + if (matchingLongNameParameters.length > 1) { + if (!parameter.scopedLongName) { + // This should never happen + throw new Error( + `Unable to find scoped long name for ambiguous short name parameter "${parameterName}".` + ); + } + nonAmbiguousLongNames.push(parameter.scopedLongName); + } else { + nonAmbiguousLongNames.push(parameter.longName); + } + } + + // Throw an error including the non-ambiguous long names for the parameters that have the ambiguous + // short name, ex. + // Error: Ambiguous option "-p" could match "--param1", "--param2" + this._throwParserExitError( + parserOptions, + data, + 1, + `Ambiguous option: "${parameterName}" could match ${nonAmbiguousLongNames.join(', ')}.` + ); + } + + const duplicateLongNameParameters: CommandLineParameterBase[] | undefined = + this._parametersByLongName.get(parameterName); + if (duplicateLongNameParameters) { + const nonAmbiguousLongNames: string[] = duplicateLongNameParameters.map( + (p: CommandLineParameterBase) => { + // The scoped long name should always be provided + if (!p.scopedLongName) { + // This should never happen + throw new Error( + `Unable to find scoped long name for ambiguous long name parameter "${parameterName}".` + ); + } + return p.scopedLongName; + } + ); + + // Throw an error including the non-ambiguous scoped long names for the parameters that have the + // ambiguous long name, ex. + // Error: Ambiguous option: "--param" could match --scope1:param, --scope2:param + this._throwParserExitError( + parserOptions, + data, + 1, + `Ambiguous option: "${parameterName}" could match ${nonAmbiguousLongNames.join(', ')}.` + ); + } + + // This shouldn't happen, but we also shouldn't allow the user to use the ambiguous parameter + this._throwParserExitError(parserOptions, data, 1, `Ambiguous option: "${parameterName}".`); + } + } + + // Fill in the values for the parameters + for (const parameter of this._parameters) { + const value: unknown = data[parameter._parserKey!]; + parameter._setValue(value); + parameter._validateValue?.(); + } + + if (this.remainder) { + this.remainder._setValue(data[argparse.Const.REMAINDER]); + } + + this._parametersHaveBeenProcessed = true; + } + + /** @internal */ + protected _defineParameter(parameter: CommandLineParameter): void { + if (this._parametersHaveBeenRegistered) { + throw new Error('Parameters have already been registered for this provider'); + } + + // Generate and set the parser key at definition time + parameter._parserKey = this._generateKey(); + + this._parameters.push(parameter); + + // Collect all parameters with the same long name. We will perform conflict resolution at registration. + let longNameParameters: CommandLineParameter[] | undefined = this._parametersByLongName.get( + parameter.longName + ); + if (!longNameParameters) { + longNameParameters = []; + this._parametersByLongName.set(parameter.longName, longNameParameters); + } + longNameParameters.push(parameter); + + // Collect all parameters with the same short name. We will perform conflict resolution at registration. + if (parameter.shortName) { + let shortNameParameters: CommandLineParameter[] | undefined = this._parametersByShortName.get( + parameter.shortName + ); + if (!shortNameParameters) { + shortNameParameters = []; + this._parametersByShortName.set(parameter.shortName, shortNameParameters); + } + shortNameParameters.push(parameter); + } + } + + /** @internal */ + protected _defineAmbiguousParameter(name: string): string { + if (this._parametersHaveBeenRegistered) { + throw new Error('Parameters have already been registered for this provider'); + } + + // Only generate a new parser key if the ambiguous parameter hasn't been defined yet, + // either as an existing parameter or as another ambiguous parameter + let existingParserKey: string | undefined = + this._registeredParameterParserKeysByName.get(name) || + this._ambiguousParameterParserKeysByName.get(name); + if (!existingParserKey) { + existingParserKey = this._generateKey(); + } + + this._ambiguousParameterParserKeysByName.set(name, existingParserKey); + return existingParserKey; + } + + /** @internal */ + protected _registerParameter( + parameter: CommandLineParameter, + useScopedLongName: boolean, + ignoreShortName: boolean + ): void { + const { + shortName, + longName, + scopedLongName, + description, + kind, + required, + environmentVariable, + parameterGroup, + undocumentedSynonyms, + _parserKey: parserKey + } = parameter; + + const names: string[] = []; + if (shortName && !ignoreShortName) { + names.push(shortName); + } + + // Use the original long name unless otherwise requested + if (!useScopedLongName) { + names.push(longName); + } + + // Add the scoped long name if it exists + if (scopedLongName) { + names.push(scopedLongName); + } + + let finalDescription: string = description; + + const supplementaryNotes: string[] = []; + parameter._getSupplementaryNotes(supplementaryNotes); + if (supplementaryNotes.length > 0) { + // If they left the period off the end of their sentence, then add one. + if (finalDescription.match(/[a-z0-9]"?\s*$/i)) { + finalDescription = finalDescription.trimEnd() + '.'; + } + // Append the supplementary text + finalDescription += ' ' + supplementaryNotes.join(' '); + } + + let choices: string[] | undefined; + let action: string | undefined; + let type: string | undefined; + switch (kind) { + case CommandLineParameterKind.Choice: { + choices = Array.from(parameter.alternatives); + break; + } + case CommandLineParameterKind.ChoiceList: { + choices = Array.from(parameter.alternatives); + action = 'append'; + break; + } + case CommandLineParameterKind.Flag: + action = 'storeTrue'; + break; + case CommandLineParameterKind.Integer: + type = 'int'; + break; + case CommandLineParameterKind.IntegerList: + type = 'int'; + action = 'append'; + break; + case CommandLineParameterKind.String: + break; + case CommandLineParameterKind.StringList: + action = 'append'; + break; + } + + // NOTE: Our "environmentVariable" feature takes precedence over argparse's "defaultValue", + // so we have to reimplement that feature. + const argparseOptions: argparse.ArgumentOptions = { + help: escapeSprintf(finalDescription), + dest: parserKey, + metavar: (parameter as CommandLineParameterWithArgument).argumentName, + required, + choices, + action, + type + }; + + const argumentParser: IExtendedArgumentParser = this._getArgumentParser() as IExtendedArgumentParser; + let argumentGroup: argparse.ArgumentGroup | undefined; + if (parameterGroup) { + argumentGroup = this._parameterGroupsByName.get(parameterGroup); + if (!argumentGroup) { + let parameterGroupName: string; + if (typeof parameterGroup === 'string') { + parameterGroupName = parameterGroup; + } else if (parameterGroup === SCOPING_PARAMETER_GROUP) { + parameterGroupName = 'scoping'; + } else { + throw new Error('Unexpected parameter group: ' + parameterGroup); + } + + argumentGroup = argumentParser.addArgumentGroup({ + title: `Optional ${parameterGroupName} arguments` + }); + this._parameterGroupsByName.set(parameterGroup, argumentGroup); + } + } else { + argumentGroup = argumentParser; + } + + const argparseArgument: argparse.ArgumentOptions = (argumentGroup as IExtendedArgumentGroup).addArgument( + names, + argparseOptions + ); + if (required && environmentVariable) { + // Add some special-cased logic to handle required parameters with environment variables + + const originalPreParse: (() => void) | undefined = parameter._preParse?.bind(parameter); + parameter._preParse = () => { + originalPreParse?.(); + // Set the value as non-required before parsing. We'll validate it explicitly + argparseArgument.required = false; + }; + + const originalPostParse: (() => void) | undefined = parameter._postParse?.bind(parameter); + parameter._postParse = () => { + // Reset the required value to make the usage text correct + argparseArgument.required = true; + originalPostParse?.(); + }; + + function throwMissingParameterError(): never { + argumentParser.error(`Argument "${longName}" is required`); + } + + const originalValidateValue: (() => void) | undefined = parameter._validateValue?.bind(parameter); + // For these values, we have to perform explicit validation because they're requested + // as required, but we disabled argparse's required flag to allow the environment variable + // to potentially fill the value. + switch (kind) { + case CommandLineParameterKind.Choice: + case CommandLineParameterKind.Integer: + case CommandLineParameterKind.String: + parameter._validateValue = function () { + if (this.value === undefined || this.value === null) { + throwMissingParameterError(); + } + + originalValidateValue?.(); + }; + break; + case CommandLineParameterKind.ChoiceList: + case CommandLineParameterKind.IntegerList: + case CommandLineParameterKind.StringList: + parameter._validateValue = function () { + if (this.values.length === 0) { + throwMissingParameterError(); + } + + originalValidateValue?.(); + }; + break; + } + } + + if (undocumentedSynonyms?.length) { + argumentGroup.addArgument(undocumentedSynonyms, { + ...argparseOptions, + help: argparse.Const.SUPPRESS + }); + } + + // Register the parameter names so that we can detect ambiguous parameters + for (const name of [...names, ...(undocumentedSynonyms || [])]) { + this._registeredParameterParserKeysByName.set(name, parserKey!); + } + } + + protected _registerAmbiguousParameter(name: string, parserKey: string): void { + this._getArgumentParser().addArgument(name, { + dest: parserKey, + // We don't know if this argument takes parameters or not, so we need to accept any number of args + nargs: '*', + // Ensure that the argument is not shown in the help text, since these parameters are only included + // to inform the user that ambiguous parameters are present + help: argparse.Const.SUPPRESS + }); + } + + private _generateKey(): string { + return 'key_' + (CommandLineParameterProvider._keyCounter++).toString(); + } + + private _getParameter( + parameterLongName: string, + expectedKind: CommandLineParameterKind, + parameterScope?: string + ): T { + // Support the parameter long name being prefixed with the scope + const { scope, longName } = this.parseScopedLongName(parameterLongName); + parameterLongName = longName; + parameterScope = scope || parameterScope; + + const parameters: CommandLineParameterBase[] | undefined = + this._parametersByLongName.get(parameterLongName); + if (!parameters) { + throw new Error(`The parameter "${parameterLongName}" is not defined`); + } + + let parameter: CommandLineParameterBase | undefined = parameters.find( + (p) => p.parameterScope === parameterScope + ); + if (!parameter) { + if (parameterScope !== undefined) { + throw new Error( + `The parameter "${parameterLongName}" with scope "${parameterScope}" is not defined.` + ); + } + if (parameters.length !== 1) { + throw new Error(`The parameter "${parameterLongName}" is ambiguous. You must specify a scope.`); + } + parameter = parameters[0]; + } + + if (parameter.kind !== expectedKind) { + throw new Error( + `The parameter "${parameterLongName}" is of type "${CommandLineParameterKind[parameter.kind]}"` + + ` whereas the caller was expecting "${CommandLineParameterKind[expectedKind]}".` + ); + } + + return parameter as T; + } + + private _throwParserExitError( + parserOptions: ICommandLineParserOptions, + data: ICommandLineParserData, + errorCode: number, + message: string + ): never { + // Write out the usage text to make it easier for the user to find the correct parameter name + const targetActionName: string = data.aliasAction || data.action || ''; + const errorPrefix: string = + `Error: ${parserOptions.toolFilename}` + + // Handle aliases, actions, and actionless parameter providers + `${targetActionName ? ' ' : ''}${targetActionName}: error: `; + + // eslint-disable-next-line no-console + console.log(this.renderUsageText()); + throw new CommandLineParserExitError(errorCode, `${errorPrefix}${message.trimStart().trimEnd()}\n`); + } +} diff --git a/libraries/ts-command-line/src/providers/CommandLineParser.ts b/libraries/ts-command-line/src/providers/CommandLineParser.ts new file mode 100644 index 00000000000..ab717adc3a0 --- /dev/null +++ b/libraries/ts-command-line/src/providers/CommandLineParser.ts @@ -0,0 +1,346 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as argparse from 'argparse'; + +import { Colorize } from '@rushstack/terminal'; + +import type { CommandLineAction } from './CommandLineAction'; +import type { AliasCommandLineAction } from './AliasCommandLineAction'; +import { + CommandLineParameterProvider, + type IRegisterDefinedParametersState, + type ICommandLineParserData +} from './CommandLineParameterProvider'; +import { CommandLineParserExitError, CustomArgumentParser } from './CommandLineParserExitError'; +import { TabCompleteAction } from './TabCompletionAction'; +import { TypeUuid, uuidAlreadyReportedError } from '../TypeUuidLite'; +import { escapeSprintf } from '../escapeSprintf'; + +/** + * Options for the {@link CommandLineParser} constructor. + * @public + */ +export interface ICommandLineParserOptions { + /** + * The name of your tool when invoked from the command line + */ + toolFilename: string; + + /** + * General documentation that is included in the "--help" main page + */ + toolDescription: string; + + /** + * An optional string to append at the end of the "--help" main page. If not provided, an epilog + * will be automatically generated based on the toolFilename. + */ + toolEpilog?: string; + + /** + * Set to true to auto-define a tab completion action. False by default. + */ + enableTabCompletionAction?: boolean; +} + +/** + * The "argparse" library is a relatively advanced command-line parser with features such + * as word-wrapping and intelligible error messages (that are lacking in other similar + * libraries such as commander, yargs, and nomnom). Unfortunately, its ruby-inspired API + * is awkward to use. The abstract base classes CommandLineParser and CommandLineAction + * provide a wrapper for "argparse" that makes defining and consuming arguments quick + * and simple, and enforces that appropriate documentation is provided for each parameter. + * + * @public + */ +export abstract class CommandLineParser extends CommandLineParameterProvider { + /** + * Reports which CommandLineAction was specified on the command line. + * @remarks + * The value will be assigned before onExecute() is invoked. + */ + public selectedAction: CommandLineAction | undefined; + + private readonly _argumentParser: argparse.ArgumentParser; + private _actionsSubParser: argparse.SubParser | undefined; + private readonly _options: ICommandLineParserOptions; + private readonly _actions: CommandLineAction[]; + private readonly _actionsByName: Map; + private _executed: boolean = false; + private _tabCompleteActionWasAdded: boolean = false; + + public constructor(options: ICommandLineParserOptions) { + super(); + + this._options = options; + this._actions = []; + this._actionsByName = new Map(); + + const { toolFilename, toolDescription, toolEpilog } = options; + + this._argumentParser = new CustomArgumentParser({ + addHelp: true, + prog: toolFilename, + description: escapeSprintf(toolDescription), + epilog: Colorize.bold( + escapeSprintf( + toolEpilog ?? `For detailed help about a specific command, use: ${toolFilename} -h` + ) + ) + }); + } + + /** + * Returns the list of actions that were defined for this CommandLineParser object. + */ + public get actions(): ReadonlyArray { + return this._actions; + } + + /** + * Defines a new action that can be used with the CommandLineParser instance. + */ + public addAction(action: CommandLineAction): void { + if (!this._actionsSubParser) { + this._actionsSubParser = this._argumentParser.addSubparsers({ + metavar: '', + dest: 'action' + }); + } + + action._buildParser(this._actionsSubParser); + this._actions.push(action); + this._actionsByName.set(action.actionName, action); + } + + /** + * Retrieves the action with the specified name. If no matching action is found, + * an exception is thrown. + */ + public getAction(actionName: string): CommandLineAction { + const action: CommandLineAction | undefined = this.tryGetAction(actionName); + if (!action) { + throw new Error(`The action "${actionName}" was not defined`); + } + return action; + } + + /** + * Retrieves the action with the specified name. If no matching action is found, + * undefined is returned. + */ + public tryGetAction(actionName: string): CommandLineAction | undefined { + return this._actionsByName.get(actionName); + } + + /** + * The program entry point will call this method to begin parsing command-line arguments + * and executing the corresponding action. + * + * @remarks + * The returned promise will never reject: If an error occurs, it will be printed + * to stderr, process.exitCode will be set to 1, and the promise will resolve to false. + * This simplifies the most common usage scenario where the program entry point doesn't + * want to be involved with the command-line logic, and will discard the promise without + * a then() or catch() block. + * + * If your caller wants to trap and handle errors, use {@link CommandLineParser.executeWithoutErrorHandlingAsync} + * instead. + * + * @param args - the command-line arguments to be parsed; if omitted, then + * the process.argv will be used + */ + public async executeAsync(args?: string[]): Promise { + if (this._options.enableTabCompletionAction && !this._tabCompleteActionWasAdded) { + this.addAction(new TabCompleteAction(this.actions, this.parameters)); + this._tabCompleteActionWasAdded = true; + } + + try { + await this.executeWithoutErrorHandlingAsync(args); + return true; + } catch (err) { + if (err instanceof CommandLineParserExitError) { + // executeWithoutErrorHandlingAsync() handles the successful cases, + // so here we can assume err has a nonzero exit code + if (err.message) { + // eslint-disable-next-line no-console + console.error(err.message); + } + if (!process.exitCode) { + process.exitCode = err.exitCode; + } + } else if (TypeUuid.isInstanceOf(err, uuidAlreadyReportedError)) { + // AlreadyReportedError + if (!process.exitCode) { + process.exitCode = 1; + } + } else { + let message: string = ((err as Error).message || 'An unknown error occurred').trim(); + + // If the message doesn't already start with "Error:" then add a prefix + if (!/^(error|internal error|warning)\b/i.test(message)) { + message = 'Error: ' + message; + } + + // eslint-disable-next-line no-console + console.error(); + // eslint-disable-next-line no-console + console.error(Colorize.red(message)); + + if (!process.exitCode) { + process.exitCode = 1; + } + } + + return false; + } + } + + /** + * This is similar to {@link CommandLineParser.executeAsync}, except that execution errors + * simply cause the promise to reject. It is the caller's responsibility to trap + */ + public async executeWithoutErrorHandlingAsync(args?: string[]): Promise { + try { + if (this._executed) { + // In the future we could allow the same parser to be invoked multiple times + // with different arguments. We'll do that work as soon as someone encounters + // a real world need for it. + throw new Error('executeAsync() was already called for this parser instance'); + } + this._executed = true; + + this._validateDefinitions(); + + // Register the parameters before we print help or parse the CLI + const initialState: IRegisterDefinedParametersState = { + parentParameterNames: new Set() + }; + this._registerDefinedParameters(initialState); + + if (!args) { + // 0=node.exe, 1=script name + args = process.argv.slice(2); + } + if (this.actions.length > 0) { + if (args.length === 0) { + // Parsers that use actions should print help when 0 args are provided. Allow + // actionless parsers to continue on zero args. + this._argumentParser.printHelp(); + return; + } + // Alias actions may provide a list of default params to add after the action name. + // Since we don't know which params are required and which are optional, perform a + // manual search for the action name to obtain the default params and insert them if + // any are found. We will guess that the action name is the first arg that doesn't + // start with a hyphen. + const actionNameIndex: number | undefined = args.findIndex((x) => !x.startsWith('-')); + if (actionNameIndex !== undefined) { + const actionName: string = args[actionNameIndex]; + const action: CommandLineAction | undefined = this.tryGetAction(actionName); + const aliasAction: AliasCommandLineAction | undefined = action as AliasCommandLineAction; + if (aliasAction?.defaultParameters?.length) { + const insertIndex: number = actionNameIndex + 1; + args = args.slice(0, insertIndex).concat(aliasAction.defaultParameters, args.slice(insertIndex)); + } + } + } + + const postParse: () => void = () => { + this._postParse(); + for (const action of this.actions) { + action._postParse(); + } + }; + + function patchFormatUsageForArgumentParser(argumentParser: argparse.ArgumentParser): void { + const originalFormatUsage: () => string = argumentParser.formatUsage.bind(argumentParser); + argumentParser.formatUsage = () => { + postParse(); + return originalFormatUsage(); + }; + } + + this._preParse(); + patchFormatUsageForArgumentParser(this._argumentParser); + for (const action of this.actions) { + action._preParse(); + patchFormatUsageForArgumentParser(action._getArgumentParser()); + } + + const data: ICommandLineParserData = this._argumentParser.parseArgs(args); + + postParse(); + this._processParsedData(this._options, data); + + this.selectedAction = this.tryGetAction(data.action); + if (this.actions.length > 0 && !this.selectedAction) { + const actions: string[] = this.actions.map((x) => x.actionName); + throw new Error(`An action must be specified (${actions.join(', ')})`); + } + + this.selectedAction?._processParsedData(this._options, data); + await this.onExecuteAsync(); + } catch (err) { + if (err instanceof CommandLineParserExitError) { + if (!err.exitCode) { + // non-error exit modeled using exception handling + if (err.message) { + // eslint-disable-next-line no-console + console.log(err.message); + } + + return; + } + } + + throw err; + } + } + + /** @internal */ + public _registerDefinedParameters(state: IRegisterDefinedParametersState): void { + super._registerDefinedParameters(state); + + const { parentParameterNames } = state; + const updatedParentParameterNames: Set = new Set([ + ...parentParameterNames, + ...this._registeredParameterParserKeysByName.keys() + ]); + + const parentState: IRegisterDefinedParametersState = { + ...state, + parentParameterNames: updatedParentParameterNames + }; + for (const action of this._actions) { + action._registerDefinedParameters(parentState); + } + } + + private _validateDefinitions(): void { + if (this.remainder && this.actions.length > 0) { + // This is apparently not supported by argparse + throw new Error('defineCommandLineRemainder() cannot be called for a CommandLineParser with actions'); + } + } + + /** + * {@inheritDoc CommandLineParameterProvider._getArgumentParser} + * @internal + */ + protected override _getArgumentParser(): argparse.ArgumentParser { + return this._argumentParser; + } + + /** + * This hook allows the subclass to perform additional operations before or after + * the chosen action is executed. + */ + protected async onExecuteAsync(): Promise { + if (this.selectedAction) { + await this.selectedAction._executeAsync(); + } + } +} diff --git a/libraries/ts-command-line/src/providers/CommandLineParserExitError.ts b/libraries/ts-command-line/src/providers/CommandLineParserExitError.ts new file mode 100644 index 00000000000..04297fe7ee8 --- /dev/null +++ b/libraries/ts-command-line/src/providers/CommandLineParserExitError.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 argparse from 'argparse'; + +export class CommandLineParserExitError extends Error { + public readonly exitCode: number; + + public constructor(exitCode: number, message: string) { + super(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 + // + // Note: the prototype must also be set on any classes which extend this one + (this as any).__proto__ = CommandLineParserExitError.prototype; // eslint-disable-line @typescript-eslint/no-explicit-any + + this.exitCode = exitCode; + } +} + +export class CustomArgumentParser extends argparse.ArgumentParser { + public override exit(status: number, message: string): void { + throw new CommandLineParserExitError(status, message); + } + + public override error(err: Error | string): void { + // Ensure the ParserExitError bubbles up to the top without any special processing + if (err instanceof CommandLineParserExitError) { + throw err; + } + + super.error(err); + } +} diff --git a/libraries/ts-command-line/src/providers/DynamicCommandLineAction.ts b/libraries/ts-command-line/src/providers/DynamicCommandLineAction.ts new file mode 100644 index 00000000000..90879838739 --- /dev/null +++ b/libraries/ts-command-line/src/providers/DynamicCommandLineAction.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 { CommandLineAction } from './CommandLineAction'; + +/** + * @public + */ +export class DynamicCommandLineAction extends CommandLineAction { + protected override async onExecuteAsync(): Promise { + // abstract + // (handled by the external code) + } +} diff --git a/libraries/ts-command-line/src/DynamicCommandLineParser.ts b/libraries/ts-command-line/src/providers/DynamicCommandLineParser.ts similarity index 82% rename from libraries/ts-command-line/src/DynamicCommandLineParser.ts rename to libraries/ts-command-line/src/providers/DynamicCommandLineParser.ts index 3e9fe4adac1..cf971ae2486 100644 --- a/libraries/ts-command-line/src/DynamicCommandLineParser.ts +++ b/libraries/ts-command-line/src/providers/DynamicCommandLineParser.ts @@ -6,7 +6,4 @@ import { CommandLineParser } from './CommandLineParser'; /** * @public */ -export class DynamicCommandLineParser extends CommandLineParser { - protected onDefineParameters(): void { // abstract - } -} +export class DynamicCommandLineParser extends CommandLineParser {} diff --git a/libraries/ts-command-line/src/providers/ScopedCommandLineAction.ts b/libraries/ts-command-line/src/providers/ScopedCommandLineAction.ts new file mode 100644 index 00000000000..a75d582142f --- /dev/null +++ b/libraries/ts-command-line/src/providers/ScopedCommandLineAction.ts @@ -0,0 +1,271 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { SCOPING_PARAMETER_GROUP } from '../Constants'; +import { CommandLineAction, type ICommandLineActionOptions } from './CommandLineAction'; +import { CommandLineParser, type ICommandLineParserOptions } from './CommandLineParser'; +import { CommandLineParserExitError } from './CommandLineParserExitError'; +import type { CommandLineParameter } from '../parameters/BaseClasses'; +import type { + CommandLineParameterProvider, + ICommandLineParserData, + IRegisterDefinedParametersState +} from './CommandLineParameterProvider'; + +interface IInternalScopedCommandLineParserOptions extends ICommandLineParserOptions { + readonly actionOptions: ICommandLineActionOptions; + readonly unscopedActionParameters: ReadonlyArray; + readonly onDefineScopedParameters: (commandLineParameterProvider: CommandLineParameterProvider) => void; + readonly aliasAction?: string; + readonly aliasDocumentation?: string; + readonly registerDefinedParametersState: IRegisterDefinedParametersState; +} + +/** + * A CommandLineParser used exclusively to parse the scoped command-line parameters + * for a ScopedCommandLineAction. + */ +class InternalScopedCommandLineParser extends CommandLineParser { + private _canExecute: boolean; + private readonly _internalOptions: IInternalScopedCommandLineParserOptions; + + public get canExecute(): boolean { + return this._canExecute; + } + + public constructor(options: IInternalScopedCommandLineParserOptions) { + const { actionOptions, unscopedActionParameters, toolFilename, aliasAction, aliasDocumentation } = + options; + + const toolCommand: string = `${toolFilename} ${actionOptions.actionName}`; + // When coming from an alias command, we want to show the alias command name in the help text + const toolCommandForLogging: string = `${toolFilename} ${aliasAction ?? actionOptions.actionName}`; + const scopingArgs: string[] = []; + for (const parameter of unscopedActionParameters) { + parameter.appendToArgList(scopingArgs); + } + const scope: string = scopingArgs.join(' '); + + // We can run the parser directly because we are not going to use it for any other actions, + // so construct a special options object to make the "--help" text more useful. + const scopedCommandLineParserOptions: ICommandLineParserOptions = { + // Strip the scoping args if coming from an alias command, since they are not applicable + // to the alias command itself + toolFilename: `${toolCommandForLogging}${scope && !aliasAction ? ` ${scope} --` : ''}`, + toolDescription: aliasDocumentation ?? actionOptions.documentation, + toolEpilog: `For more information on available unscoped parameters, use "${toolCommand} --help"`, + enableTabCompletionAction: false + }; + + super(scopedCommandLineParserOptions); + this._canExecute = false; + this._internalOptions = options; + this._internalOptions.onDefineScopedParameters(this); + } + + public _registerDefinedParameters(state: IRegisterDefinedParametersState): void { + // Since we are in a separate parser, we need to register the parameters using the state + // from the parent parser. + super._registerDefinedParameters(this._internalOptions.registerDefinedParametersState); + } + + protected override async onExecuteAsync(): Promise { + // Only set if we made it this far, which may not be the case if an error occurred or + // if '--help' was specified. + this._canExecute = true; + } +} + +/** + * Represents a sub-command that is part of the CommandLineParser command-line. + * Applications should create subclasses of ScopedCommandLineAction corresponding to + * each action that they want to expose. + * + * The action name should be comprised of lower case words separated by hyphens + * or colons. The name should include an English verb (e.g. "deploy"). Use a + * hyphen to separate words (e.g. "upload-docs"). A group of related commands + * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", + * "docs:serve", etc). + * + * Scoped commands allow for different parameters to be specified for different + * provided scoping values. For example, the "scoped-action --scope A" command + * may allow for different scoped arguments to be specified than the "scoped-action + * --scope B" command. + * + * Scoped arguments are specified after the "--" pseudo-argument. For example, + * "scoped-action --scope A -- --scopedFoo --scopedBar". + * + * @public + */ +export abstract class ScopedCommandLineAction extends CommandLineAction { + private _options: ICommandLineActionOptions; + private _scopingParameters: CommandLineParameter[]; + private _unscopedParserOptions: ICommandLineParserOptions | undefined; + private _scopedCommandLineParser: InternalScopedCommandLineParser | undefined; + private _subparserState: IRegisterDefinedParametersState | undefined; + + /** + * The required group name to apply to all scoping parameters. At least one parameter + * must be defined with this group name. + */ + public static readonly ScopingParameterGroup: typeof SCOPING_PARAMETER_GROUP = SCOPING_PARAMETER_GROUP; + + public constructor(options: ICommandLineActionOptions) { + super(options); + + this._options = options; + this._scopingParameters = []; + + // Consume the remainder of the command-line, which will later be passed the scoped parser. + // This will also prevent developers from calling this.defineCommandLineRemainder(...) since + // we will have already defined it. + this.defineCommandLineRemainder({ + description: + 'Scoped parameters. Must be prefixed with "--", ex. "-- --scopedParameter ' + + 'foo --scopedFlag". For more information on available scoped parameters, use "-- --help".' + }); + } + + /** + * {@inheritDoc CommandLineParameterProvider.parameters} + */ + public get parameters(): ReadonlyArray { + if (this._scopedCommandLineParser) { + return [...super.parameters, ...this._scopedCommandLineParser.parameters]; + } else { + return super.parameters; + } + } + + /** + * {@inheritdoc CommandLineParameterProvider._processParsedData} + * @internal + */ + public override _processParsedData( + parserOptions: ICommandLineParserOptions, + data: ICommandLineParserData + ): void { + super._processParsedData(parserOptions, data); + + // This should never happen because the super method should throw if parameters haven't been registered, + // but guard against this just in-case. + if (this._subparserState === undefined) { + throw new Error('Parameters have not been registered'); + } + + this._unscopedParserOptions = parserOptions; + + // Generate the scoped parser using the parent parser information. We can only create this after we + // have parsed the data, since the parameter values are used during construction. + this._scopedCommandLineParser = new InternalScopedCommandLineParser({ + ...parserOptions, + actionOptions: this._options, + aliasAction: data.aliasAction, + aliasDocumentation: data.aliasDocumentation, + unscopedActionParameters: this.parameters as CommandLineParameter[], + registerDefinedParametersState: this._subparserState, + onDefineScopedParameters: this.onDefineScopedParameters.bind(this) + }); + } + + /** + * {@inheritdoc CommandLineAction._executeAsync} + * @internal + */ + public override async _executeAsync(): Promise { + if (!this._unscopedParserOptions || !this._scopedCommandLineParser) { + throw new Error('The CommandLineAction parameters must be processed before execution.'); + } + if (!this.remainder) { + throw new Error('Parameters must be defined before execution.'); + } + + // The '--' argument is required to separate the action parameters from the scoped parameters, + // so it needs to be trimmed. If remainder values are provided but no '--' is found, then throw. + const scopedArgs: string[] = []; + if (this.remainder.values.length) { + if (this.remainder.values[0] !== '--') { + throw new CommandLineParserExitError( + // argparse sets exit code 2 for invalid arguments + 2, + // model the message off of the built-in "unrecognized arguments" message + `${this.renderUsageText()}\n${this._unscopedParserOptions.toolFilename} ${this.actionName}: ` + + `error: Unrecognized arguments: ${this.remainder.values[0]}.\n` + ); + } + for (const scopedArg of this.remainder.values.slice(1)) { + scopedArgs.push(scopedArg); + } + } + + // Call the scoped parser using only the scoped args to handle parsing + await this._scopedCommandLineParser.executeWithoutErrorHandlingAsync(scopedArgs); + + // Only call execute if the parser reached the execute stage. This may not be true if + // the parser exited early due to a specified '--help' parameter. + if (this._scopedCommandLineParser.canExecute) { + await super._executeAsync(); + } + + return; + } + + /** @internal */ + public _registerDefinedParameters(state: IRegisterDefinedParametersState): void { + if (!this._scopingParameters.length) { + throw new Error( + 'No scoping parameters defined. At least one scoping parameter must be defined. ' + + 'Scoping parameters are defined by setting the parameterGroupName to ' + + 'ScopedCommandLineAction.ScopingParameterGroupName.' + ); + } + + super._registerDefinedParameters(state); + + const { parentParameterNames } = state; + const updatedParentParameterNames: Set = new Set([ + ...parentParameterNames, + ...this._registeredParameterParserKeysByName.keys() + ]); + + this._subparserState = { + ...state, + parentParameterNames: updatedParentParameterNames + }; + } + + /** + * Retrieves the scoped CommandLineParser, which is populated after the ScopedCommandLineAction is executed. + * @internal + */ + protected _getScopedCommandLineParser(): CommandLineParser { + if (!this._scopedCommandLineParser) { + throw new Error('The scoped CommandLineParser is only populated after the action is executed.'); + } + return this._scopedCommandLineParser; + } + + /** @internal */ + protected _defineParameter(parameter: CommandLineParameter): void { + super._defineParameter(parameter); + if (parameter.parameterGroup === ScopedCommandLineAction.ScopingParameterGroup) { + this._scopingParameters.push(parameter); + } + } + + /** + * The child class should implement this hook to define its scoped command-line + * parameters, e.g. by calling scopedParameterProvider.defineFlagParameter(). These + * parameters will only be available if the action is invoked with a scope. + * + * @remarks + * onDefineScopedParameters is called after the unscoped parameters have been parsed. + * The values they provide can be used to vary the defined scope parameters. + */ + protected abstract onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void; + + /** + * {@inheritDoc CommandLineAction.onExecuteAsync} + */ + protected abstract onExecuteAsync(): Promise; +} diff --git a/libraries/ts-command-line/src/providers/TabCompletionAction.ts b/libraries/ts-command-line/src/providers/TabCompletionAction.ts new file mode 100644 index 00000000000..9ec089eb14b --- /dev/null +++ b/libraries/ts-command-line/src/providers/TabCompletionAction.ts @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import stringArgv from 'string-argv'; + +import type { IRequiredCommandLineIntegerParameter } from '../parameters/CommandLineIntegerParameter'; +import type { IRequiredCommandLineStringParameter } from '../parameters/CommandLineStringParameter'; +import { + CommandLineParameterKind, + type CommandLineParameterBase, + CommandLineParameterWithArgument, + type CommandLineParameter +} from '../parameters/BaseClasses'; +import { CommandLineChoiceParameter } from '../parameters/CommandLineChoiceParameter'; +import { CommandLineAction } from './CommandLineAction'; +import { CommandLineConstants } from '../Constants'; + +const DEFAULT_WORD_TO_AUTOCOMPLETE: string = ''; +const DEFAULT_POSITION: number = 0; + +export class TabCompleteAction extends CommandLineAction { + private readonly _wordToCompleteParameter: IRequiredCommandLineStringParameter; + private readonly _positionParameter: IRequiredCommandLineIntegerParameter; + private readonly _actions: Map>; + private readonly _globalParameters: Map; + + public constructor( + actions: ReadonlyArray, + globalParameters: ReadonlyArray + ) { + super({ + actionName: CommandLineConstants.TabCompletionActionName, + summary: 'Provides tab completion.', + documentation: 'Provides tab completion.' + }); + + this._actions = new Map(); + for (const action of actions) { + const parameterNameToParameterInfoMap: Map = new Map(); + for (const parameter of action.parameters) { + parameterNameToParameterInfoMap.set(parameter.longName, parameter as CommandLineParameter); + if (parameter.shortName) { + parameterNameToParameterInfoMap.set(parameter.shortName, parameter as CommandLineParameter); + } + } + this._actions.set(action.actionName, parameterNameToParameterInfoMap); + } + + this._globalParameters = new Map(); + for (const parameter of globalParameters) { + this._globalParameters.set(parameter.longName, parameter as CommandLineParameter); + if (parameter.shortName) { + this._globalParameters.set(parameter.shortName, parameter as CommandLineParameter); + } + } + + this._wordToCompleteParameter = this.defineStringParameter({ + parameterLongName: '--word', + argumentName: 'WORD', + description: `The word to complete.`, + defaultValue: DEFAULT_WORD_TO_AUTOCOMPLETE + }); + + this._positionParameter = this.defineIntegerParameter({ + parameterLongName: '--position', + argumentName: 'INDEX', + description: `The position in the word to be completed.`, + defaultValue: DEFAULT_POSITION + }); + } + + protected override async onExecuteAsync(): Promise { + const commandLine: string = this._wordToCompleteParameter.value; + const caretPosition: number = this._positionParameter.value || commandLine.length; + + for await (const value of this.getCompletionsAsync(commandLine, caretPosition)) { + // eslint-disable-next-line no-console + console.log(value); + } + } + + public async *getCompletionsAsync( + commandLine: string, + caretPosition: number = commandLine.length + ): AsyncIterable { + const actions: Map> = this._actions; + + if (!commandLine || !caretPosition) { + yield* this._getAllActions(); + return; + } + + const tokens: string[] = Array.from(this.tokenizeCommandLine(commandLine)); + + // offset arguments by the number of global params in the input + const globalParameterOffset: number = this._getGlobalParameterOffset(tokens); + + if (tokens.length < 2 + globalParameterOffset) { + yield* this._getAllActions(); + return; + } + + const lastToken: string = tokens[tokens.length - 1]; + const secondLastToken: string = tokens[tokens.length - 2]; + + const lastCharacterIsWhitespace: boolean = !commandLine.slice(-1).trim(); + const completePartialWord: boolean = caretPosition === commandLine.length && !lastCharacterIsWhitespace; + + if (completePartialWord && tokens.length === 2 + globalParameterOffset) { + for (const actionName of actions.keys()) { + if (actionName.indexOf(tokens[1 + globalParameterOffset]) === 0) { + yield actionName; + } + } + } else { + for (const actionName of actions.keys()) { + if (actionName === tokens[1 + globalParameterOffset]) { + const parameterNameMap: Map = actions.get(actionName)!; + + const parameterNames: string[] = Array.from(parameterNameMap.keys()); + + if (completePartialWord) { + for (const parameterName of parameterNames) { + if (parameterName === secondLastToken) { + const values: ReadonlySet = await this._getParameterValueCompletionsAsync( + parameterNameMap.get(parameterName)! + ); + if (values.size > 0) { + yield* this._completeParameterValues(values, lastToken); + return; + } + } + } + yield* this._completeParameterValues(parameterNames, lastToken); + } else { + for (const parameterName of parameterNames) { + if (parameterName === lastToken) { + const values: ReadonlySet = await this._getParameterValueCompletionsAsync( + parameterNameMap.get(parameterName)! + ); + if (values.size > 0) { + yield* values; + return; + } + } + } + for (const parameterName of parameterNames) { + if ( + parameterName === lastToken && + parameterNameMap.get(parameterName)!.kind !== CommandLineParameterKind.Flag + ) { + // The parameter is expecting a value, so don't suggest parameter names again + return; + } + } + + yield* parameterNames; + } + + break; + } + } + } + } + + private *_getAllActions(): IterableIterator { + yield* this._actions.keys(); + yield* this._globalParameters.keys(); + } + + public tokenizeCommandLine(commandLine: string): string[] { + return stringArgv(commandLine); + } + + private async _getParameterValueCompletionsAsync( + parameter: CommandLineParameter + ): Promise> { + let choiceParameterValues: ReadonlySet | undefined; + if (parameter.kind === CommandLineParameterKind.Choice) { + choiceParameterValues = parameter.alternatives; + } else if (parameter.kind !== CommandLineParameterKind.Flag) { + let parameterWithArgumentOrChoices: + | CommandLineParameterWithArgument + | CommandLineChoiceParameter + | undefined = undefined; + if ( + parameter instanceof CommandLineParameterWithArgument || + parameter instanceof CommandLineChoiceParameter + ) { + parameterWithArgumentOrChoices = parameter; + } + + const completionValues: ReadonlyArray | ReadonlySet | undefined = + await parameterWithArgumentOrChoices?.getCompletionsAsync?.(); + choiceParameterValues = completionValues instanceof Set ? completionValues : new Set(completionValues); + } + + return choiceParameterValues ?? new Set(); + } + + private _getGlobalParameterOffset(tokens: string[]): number { + const globalParameters: Map = this._globalParameters; + let count: number = 0; + + outer: for (let i: number = 1; i < tokens.length; i++) { + for (const globalParameter of globalParameters.values()) { + if (tokens[i] !== globalParameter.longName && tokens[i] !== globalParameter.shortName) { + break outer; + } + } + count++; + } + + return count; + } + + private *_completeParameterValues( + choiceParameterValues: ReadonlyArray | ReadonlySet, + lastToken: string + ): IterableIterator { + for (const choiceParameterValue of choiceParameterValues) { + if (choiceParameterValue.indexOf(lastToken) === 0) { + yield choiceParameterValue; + } + } + } +} diff --git a/libraries/ts-command-line/src/test/ActionlessParser.test.ts b/libraries/ts-command-line/src/test/ActionlessParser.test.ts new file mode 100644 index 00000000000..034376ab5d9 --- /dev/null +++ b/libraries/ts-command-line/src/test/ActionlessParser.test.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. + +import { CommandLineParser } from '../providers/CommandLineParser'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +class TestCommandLine extends CommandLineParser { + public flag: CommandLineFlagParameter; + public done: boolean = false; + + public constructor() { + super({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + + this.flag = this.defineFlagParameter({ + parameterLongName: '--flag', + description: 'The flag' + }); + } + + protected override async onExecuteAsync(): Promise { + await super.onExecuteAsync(); + this.done = true; + } +} + +describe(`Actionless ${CommandLineParser.name}`, () => { + it('renders help text', () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it('parses an empty arg list', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + + await commandLineParser.executeAsync([]); + + expect(commandLineParser.done).toBe(true); + expect(commandLineParser.selectedAction).toBeUndefined(); + expect(commandLineParser.flag.value).toBe(false); + }); + + it('parses a flag', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + + await commandLineParser.executeAsync(['--flag']); + + expect(commandLineParser.done).toBe(true); + expect(commandLineParser.selectedAction).toBeUndefined(); + expect(commandLineParser.flag.value).toBe(true); + }); + + it('parses a flag and remainder', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + + commandLineParser.defineCommandLineRemainder({ + description: 'remainder description' + }); + + await commandLineParser.executeAsync(['--flag', 'the', 'remaining', 'args']); + + expect(commandLineParser.done).toBe(true); + expect(commandLineParser.selectedAction).toBeUndefined(); + expect(commandLineParser.flag.value).toBe(true); + expect(commandLineParser.remainder!.values).toEqual(['the', 'remaining', 'args']); + }); +}); diff --git a/libraries/ts-command-line/src/test/AliasedCommandLineAction.test.ts b/libraries/ts-command-line/src/test/AliasedCommandLineAction.test.ts new file mode 100644 index 00000000000..1534f638a9e --- /dev/null +++ b/libraries/ts-command-line/src/test/AliasedCommandLineAction.test.ts @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ScopedCommandLineAction } from '../providers/ScopedCommandLineAction'; +import type { CommandLineStringParameter } from '../parameters/CommandLineStringParameter'; +import { CommandLineParser } from '../providers/CommandLineParser'; +import type { CommandLineParameterProvider } from '../providers/CommandLineParameterProvider'; +import { AliasCommandLineAction } from '../providers/AliasCommandLineAction'; +import { CommandLineAction } from '../providers/CommandLineAction'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +class TestAliasAction extends AliasCommandLineAction { + public done: boolean = false; + + public constructor(targetAction: CommandLineAction, defaultParameters?: string[]) { + super({ + toolFilename: 'example', + aliasName: 'alias-action', + defaultParameters, + targetAction + }); + } +} + +class TestAction extends CommandLineAction { + public done: boolean = false; + private _flag!: CommandLineFlagParameter; + + public constructor() { + super({ + actionName: 'action', + summary: 'does the action', + documentation: 'a longer description' + }); + + this._flag = this.defineFlagParameter({ + parameterLongName: '--flag', + description: 'The flag' + }); + } + + protected override async onExecuteAsync(): Promise { + expect(this._flag.value).toEqual(true); + this.done = true; + } +} + +class TestScopedAction extends ScopedCommandLineAction { + public done: boolean = false; + public scopedValue: string | undefined; + private readonly _verboseArg: CommandLineFlagParameter; + private readonly _scopeArg: CommandLineStringParameter; + private _scopedArg: CommandLineStringParameter | undefined; + + public constructor() { + super({ + actionName: 'scoped-action', + summary: 'does the scoped action', + documentation: 'a longer description' + }); + + this._verboseArg = this.defineFlagParameter({ + parameterLongName: '--verbose', + description: 'A flag parameter.' + }); + + this._scopeArg = this.defineStringParameter({ + parameterLongName: '--scope', + parameterGroup: ScopedCommandLineAction.ScopingParameterGroup, + argumentName: 'SCOPE', + description: 'The scope' + }); + } + + protected override async onExecuteAsync(): Promise { + if (this._scopedArg) { + expect(this._scopedArg.longName).toBe(`--scoped-${this._scopeArg.value}`); + this.scopedValue = this._scopedArg.value; + } + this.done = true; + } + + protected onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void { + if (this._scopeArg.value) { + this._scopedArg = scopedParameterProvider.defineStringParameter({ + parameterLongName: `--scoped-${this._scopeArg.value}`, + argumentName: 'SCOPED', + description: 'The scoped argument.' + }); + } + } +} + +class TestCommandLine extends CommandLineParser { + public constructor() { + super({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + + this.addAction(new TestAction()); + this.addAction(new TestScopedAction()); + } +} + +describe(AliasCommandLineAction.name, () => { + it('renders help text', () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it('executes the aliased action', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestAction = commandLineParser.getAction('action') as TestAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + await commandLineParser.executeAsync(['alias-action', '--flag']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + expect(targetAction.done).toBe(true); + }); + + it('executes the aliased action with provided default arguments', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestAction = commandLineParser.getAction('action') as TestAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction, ['--flag']); + commandLineParser.addAction(aliasAction); + + await commandLineParser.executeAsync(['alias-action']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + expect(targetAction.done).toBe(true); + }); + + it('executes the aliased scoped action', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + await commandLineParser.executeAsync(['alias-action', '--scope', 'foo', '--', '--scoped-foo', 'bar']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + expect(targetAction.done).toBe(true); + expect(targetAction.scopedValue).toBe('bar'); + }); + + it('executes the aliased scoped action with provided default scoping arguments', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction, ['--scope', 'foo', '--']); + commandLineParser.addAction(aliasAction); + + await commandLineParser.executeAsync(['alias-action', '--scoped-foo', 'bar']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + expect(targetAction.done).toBe(true); + expect(targetAction.scopedValue).toBe('bar'); + }); + + it('prints the action parameter map', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestAction = commandLineParser.getAction('action') as TestAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action', '--flag']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + const selectedAction: TestAliasAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + expect(selectedAction.parameters.length).toBe(targetAction.parameters.length); + const parameterStringMap: Record = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); + + it('prints the unscoped action parameter map', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action', '--verbose']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + const selectedAction: TestAliasAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + expect(selectedAction.parameters.length).toBe(targetAction.parameters.length); + const parameterStringMap: Record = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); + + it('prints the unscoped action parameter map with provided default arguments', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + const aliasAction: TestAliasAction = new TestAliasAction(targetAction, ['--verbose']); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + const selectedAction: TestAliasAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + expect(selectedAction.parameters.length).toBe(targetAction.parameters.length); + const parameterStringMap: Record = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); + + it('prints the scoped action parameter map', async () => { + let commandLineParser: TestCommandLine = new TestCommandLine(); + let targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + let aliasAction: TestAliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action', '--scope', 'foo']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + let selectedAction: TestAliasAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + // The alias action only has the 2 unscoped parameters, while the target action has 3 parameters + // (2 unscoped, 1 scoped) + expect(selectedAction.parameters.length).toBe(2); + expect(targetAction.parameters.length).toBe(3); + let parameterStringMap: Record = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + + commandLineParser = new TestCommandLine(); + targetAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + aliasAction = new TestAliasAction(targetAction); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action', '--scope', 'foo', '--', '--scoped-foo', 'bar']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + selectedAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + expect(targetAction.scopedValue).toBe('bar'); + // The alias action only has the 2 unscoped parameters, while the target action has 3 parameters + // (2 unscoped, 1 scoped) + expect(selectedAction.parameters.length).toBe(2); + expect(targetAction.parameters.length).toBe(3); + parameterStringMap = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); + + it('prints the scoped action parameter map with provided default scoping arguments', async () => { + let commandLineParser: TestCommandLine = new TestCommandLine(); + let targetAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + let aliasAction: TestAliasAction = new TestAliasAction(targetAction, ['--scope', 'foo', '--']); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + let selectedAction: TestAliasAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + // The alias action only has the 2 unscoped parameters, while the target action has 3 parameters + // (2 unscoped, 1 scoped) + expect(selectedAction.parameters.length).toBe(2); + expect(targetAction.parameters.length).toBe(3); + let parameterStringMap: Record = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + + commandLineParser = new TestCommandLine(); + targetAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + aliasAction = new TestAliasAction(targetAction, ['--scope', 'foo', '--']); + commandLineParser.addAction(aliasAction); + + // Execute the parser in order to populate the parameters + await commandLineParser.executeAsync(['alias-action', '--scoped-foo', 'bar']); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('alias-action'); + selectedAction = commandLineParser.selectedAction as TestAliasAction; + expect(targetAction.done).toBe(true); + expect(targetAction.scopedValue).toBe('bar'); + // The alias action only has the 2 unscoped parameters, while the target action has 3 parameters + // (2 unscoped, 1 scoped) + expect(selectedAction.parameters.length).toBe(2); + expect(targetAction.parameters.length).toBe(3); + parameterStringMap = targetAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); +}); diff --git a/libraries/ts-command-line/src/test/AmbiguousCommandLineParser.test.ts b/libraries/ts-command-line/src/test/AmbiguousCommandLineParser.test.ts new file mode 100644 index 00000000000..a53fc714c75 --- /dev/null +++ b/libraries/ts-command-line/src/test/AmbiguousCommandLineParser.test.ts @@ -0,0 +1,679 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CommandLineParser } from '../providers/CommandLineParser'; +import { CommandLineAction } from '../providers/CommandLineAction'; +import { AliasCommandLineAction } from '../providers/AliasCommandLineAction'; +import { ScopedCommandLineAction } from '../providers/ScopedCommandLineAction'; +import type { CommandLineStringParameter } from '../parameters/CommandLineStringParameter'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import type { CommandLineParameterProvider } from '../providers/CommandLineParameterProvider'; +import { SCOPING_PARAMETER_GROUP } from '../Constants'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +class GenericCommandLine extends CommandLineParser { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public constructor(actionType: new (...args: any[]) => CommandLineAction, ...args: any[]) { + super({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + + this.addAction(new actionType(...args)); + } +} + +class AmbiguousAction extends CommandLineAction { + public done: boolean = false; + private _short1Arg: CommandLineStringParameter; + private _shortArg2: CommandLineStringParameter; + private _scope1Arg: CommandLineStringParameter; + private _scope2Arg: CommandLineStringParameter; + private _nonConflictingArg: CommandLineStringParameter; + + public constructor() { + super({ + actionName: 'do:the-job', + summary: 'does the job', + documentation: 'a longer description' + }); + + this._short1Arg = this.defineStringParameter({ + parameterLongName: '--short1', + parameterShortName: '-s', + argumentName: 'ARG', + description: 'The argument' + }); + this._shortArg2 = this.defineStringParameter({ + parameterLongName: '--short2', + parameterShortName: '-s', + argumentName: 'ARG', + description: 'The argument' + }); + this._scope1Arg = this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope1', + argumentName: 'ARG', + description: 'The argument' + }); + this._scope2Arg = this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope2', + argumentName: 'ARG', + description: 'The argument' + }); + this._nonConflictingArg = this.defineStringParameter({ + parameterLongName: '--non-conflicting-arg', + parameterScope: 'scope', + argumentName: 'ARG', + description: 'The argument' + }); + } + + protected override async onExecuteAsync(): Promise { + expect(this._short1Arg.value).toEqual('short1value'); + expect(this._shortArg2.value).toEqual('short2value'); + expect(this._scope1Arg.value).toEqual('scope1value'); + expect(this._scope2Arg.value).toEqual('scope2value'); + expect(this._nonConflictingArg.value).toEqual('nonconflictingvalue'); + this.done = true; + } +} + +class AbbreviationAction extends CommandLineAction { + public done: boolean = false; + public abbreviationFlag: CommandLineFlagParameter; + + public constructor() { + super({ + actionName: 'do:the-job', + summary: 'does the job', + documentation: 'a longer description' + }); + + this.abbreviationFlag = this.defineFlagParameter({ + parameterLongName: '--abbreviation-flag', + description: 'The argument' + }); + } + + protected override async onExecuteAsync(): Promise { + this.done = true; + } +} + +class AliasAction extends AliasCommandLineAction { + public constructor(targetActionClass: new () => CommandLineAction) { + super({ + toolFilename: 'example', + aliasName: 'do:the-job-alias', + targetAction: new targetActionClass() + }); + } +} + +class AmbiguousScopedAction extends ScopedCommandLineAction { + public done: boolean = false; + public short1Value: string | undefined; + public short2Value: string | undefined; + public scope1Value: string | undefined; + public scope2Value: string | undefined; + public nonConflictingValue: string | undefined; + private _scopingArg: CommandLineFlagParameter | undefined; + private _short1Arg: CommandLineStringParameter | undefined; + private _short2Arg: CommandLineStringParameter | undefined; + private _scope1Arg: CommandLineStringParameter | undefined; + private _scope2Arg: CommandLineStringParameter | undefined; + private _nonConflictingArg: CommandLineStringParameter | undefined; + + public constructor() { + super({ + actionName: 'scoped-action', + summary: 'does the scoped action', + documentation: 'a longer description' + }); + + // At least one scoping parameter is required to be defined on a scoped action + this._scopingArg = this.defineFlagParameter({ + parameterLongName: '--scoping', + description: 'The scoping parameter', + parameterGroup: SCOPING_PARAMETER_GROUP + }); + } + + protected override async onExecuteAsync(): Promise { + expect(this._scopingArg?.value).toEqual(true); + if (this._short1Arg?.value) { + this.short1Value = this._short1Arg.value; + } + if (this._short2Arg?.value) { + this.short2Value = this._short2Arg.value; + } + if (this._scope1Arg?.value) { + this.scope1Value = this._scope1Arg.value; + } + if (this._scope2Arg?.value) { + this.scope2Value = this._scope2Arg.value; + } + if (this._nonConflictingArg?.value) { + this.nonConflictingValue = this._nonConflictingArg.value; + } + this.done = true; + } + + protected onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void { + this._short1Arg = scopedParameterProvider.defineStringParameter({ + parameterLongName: '--short1', + parameterShortName: '-s', + argumentName: 'ARG', + description: 'The argument' + }); + this._short2Arg = scopedParameterProvider.defineStringParameter({ + parameterLongName: '--short2', + parameterShortName: '-s', + argumentName: 'ARG', + description: 'The argument' + }); + this._scope1Arg = scopedParameterProvider.defineStringParameter({ + parameterLongName: '--arg', + parameterShortName: '-a', + parameterScope: 'scope1', + argumentName: 'ARG', + description: 'The argument' + }); + this._scope2Arg = scopedParameterProvider.defineStringParameter({ + parameterLongName: '--arg', + parameterShortName: '-a', + parameterScope: 'scope2', + argumentName: 'ARG', + description: 'The argument' + }); + this._nonConflictingArg = scopedParameterProvider.defineStringParameter({ + parameterLongName: '--non-conflicting-arg', + parameterShortName: '-a', + parameterScope: 'scope', + argumentName: 'ARG', + description: 'The argument' + }); + } +} + +interface IAbbreviationScopedActionOptions { + includeUnscopedAbbreviationFlag: boolean; + includeScopedAbbreviationFlag: boolean; +} + +class AbbreviationScopedAction extends ScopedCommandLineAction { + public done: boolean = false; + public unscopedAbbreviationFlag: CommandLineFlagParameter | undefined; + public scopedAbbreviationFlag: CommandLineFlagParameter | undefined; + + private readonly _scopingArg: CommandLineFlagParameter; + private _includeScopedAbbreviationFlag: boolean; + + public constructor(options: IAbbreviationScopedActionOptions) { + super({ + actionName: 'scoped-action', + summary: 'does the scoped action', + documentation: 'a longer description' + }); + + if (options?.includeUnscopedAbbreviationFlag) { + this.unscopedAbbreviationFlag = this.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + } + + this._includeScopedAbbreviationFlag = !!options?.includeScopedAbbreviationFlag; + + // At least one scoping parameter is required to be defined on a scoped action + this._scopingArg = this.defineFlagParameter({ + parameterLongName: '--scoping', + description: 'The scoping parameter', + parameterGroup: SCOPING_PARAMETER_GROUP + }); + } + + protected override async onExecuteAsync(): Promise { + expect(this._scopingArg.value).toEqual(true); + this.done = true; + } + + protected onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void { + if (this._includeScopedAbbreviationFlag) { + this.scopedAbbreviationFlag = scopedParameterProvider.defineFlagParameter({ + parameterLongName: '--abbreviation-flag', + description: 'A flag used to test abbreviation logic' + }); + } + } +} + +describe(`Ambiguous ${CommandLineParser.name}`, () => { + it('renders help text', () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AmbiguousAction, + AbbreviationAction, + AliasAction, + AmbiguousScopedAction, + AbbreviationScopedAction + ); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it('fails to execute when an ambiguous short name is provided', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '-s']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('can execute the non-ambiguous scoped long names', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousAction); + + await commandLineParser.executeAsync([ + 'do:the-job', + '--short1', + 'short1value', + '--short2', + 'short2value', + '--scope1:arg', + 'scope1value', + '--scope2:arg', + 'scope2value', + '--non-conflicting-arg', + 'nonconflictingvalue' + ]); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job'); + + const action: AmbiguousAction = commandLineParser.selectedAction as AmbiguousAction; + expect(action.done).toBe(true); + + expect(action.renderHelpText()).toMatchSnapshot(); + expect(action.getParameterStringMap()).toMatchSnapshot(); + }); + + it('fails to execute when an ambiguous long name is provided', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '--arg', 'test']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('fails when providing a flag to an action that was also declared in the tool', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AbbreviationAction); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation-flag', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '--abbreviation-flag']) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation-flag"/); + }); + + it('fails when providing an exact match to an ambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AbbreviationAction); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '--abbreviation']) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation"/); + }); + + it('fails when providing an ambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AbbreviationAction); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '--abbrev']) + ).rejects.toThrowError(/Ambiguous option: "--abbrev" could match --abbreviation-flag, --abbreviation/); + }); + + it('allows unambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AbbreviationAction); + const toolAbbreviationFlag: CommandLineFlagParameter = commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job', '--abbreviation-f']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job'); + + const action: AbbreviationAction = commandLineParser.selectedAction as AbbreviationAction; + expect(action.done).toBe(true); + expect(action.abbreviationFlag.value).toBe(true); + expect(toolAbbreviationFlag.value).toBe(false); + }); +}); + +describe(`Ambiguous aliased ${CommandLineParser.name}`, () => { + it('fails to execute when an ambiguous short name is provided', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AmbiguousAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '-s']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('can execute the non-ambiguous scoped long names', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AmbiguousAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + + await commandLineParser.executeAsync([ + 'do:the-job-alias', + '--short1', + 'short1value', + '--short2', + 'short2value', + '--scope1:arg', + 'scope1value', + '--scope2:arg', + 'scope2value', + '--non-conflicting-arg', + 'nonconflictingvalue' + ]); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job-alias'); + + const action: AmbiguousAction = (commandLineParser.selectedAction as AliasAction) + .targetAction as AmbiguousAction; + expect(action.done).toBe(true); + + expect(action.renderHelpText()).toMatchSnapshot(); + expect(action.getParameterStringMap()).toMatchSnapshot(); + }); + + it('fails to execute when an ambiguous long name is provided', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AmbiguousAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '--arg', 'test']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('fails when providing a flag to an action that was also declared in the tool', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AbbreviationAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation-flag', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '--abbreviation-flag']) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation-flag"/); + }); + + it('fails when providing an exact match to an ambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AbbreviationAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '--abbreviation']) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation"/); + }); + + it('fails when providing an ambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AbbreviationAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '--abbrev']) + ).rejects.toThrowError(/Ambiguous option: "--abbrev" could match --abbreviation-flag, --abbreviation/); + }); + + it('allows unambiguous abbreviation between flags on the tool and the action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AliasAction, AbbreviationAction); + commandLineParser.addAction( + (commandLineParser.getAction('do:the-job-alias')! as AliasAction).targetAction + ); + const toolAbbreviationFlag: CommandLineFlagParameter = commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await commandLineParser.executeWithoutErrorHandlingAsync(['do:the-job-alias', '--abbreviation-f']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job-alias'); + + const action: AbbreviationAction = (commandLineParser.selectedAction as AliasAction) + .targetAction as AbbreviationAction; + expect(action.done).toBe(true); + expect(action.abbreviationFlag.value).toBe(true); + expect(toolAbbreviationFlag.value).toBe(false); + }); +}); + +describe(`Ambiguous scoping ${CommandLineParser.name}`, () => { + it('fails to execute when an ambiguous short name is provided to a scoping action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousScopedAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['scoped-action', '--scoping', '--', '-s']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('fails to execute when an ambiguous short name is provided to a scoping action with a matching ambiguous long name', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousScopedAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['scoped-action', '--scoping', '--', '-a']) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('can execute the non-ambiguous scoped long names on the scoping action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousScopedAction); + + await commandLineParser.executeAsync([ + 'scoped-action', + '--scoping', + '--', + '--short1', + 'short1value', + '--short2', + 'short2value', + '--scope1:arg', + 'scope1value', + '--scope2:arg', + 'scope2value', + '--non-conflicting-arg', + 'nonconflictingvalue' + ]); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('scoped-action'); + + const action: AmbiguousScopedAction = commandLineParser.selectedAction as AmbiguousScopedAction; + expect(action.done).toBe(true); + expect(action.short1Value).toEqual('short1value'); + expect(action.short2Value).toEqual('short2value'); + expect(action.scope1Value).toEqual('scope1value'); + expect(action.scope2Value).toEqual('scope2value'); + expect(action.nonConflictingValue).toEqual('nonconflictingvalue'); + }); + + it('fails to execute when an ambiguous long name is provided to a scoping action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(AmbiguousScopedAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync([ + 'scoped-action', + '--scoping', + '--', + '--arg', + 'test' + ]) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('fails when providing an exact match to an ambiguous abbreviation between flags on the tool and the scoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: false, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync([ + 'scoped-action', + '--scoping', + '--', + '--abbreviation' + ]) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation"/); + }); + + it('fails when providing an exact match to an ambiguous abbreviation between flags on the scoped action and the unscoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: true, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync([ + 'scoped-action', + '--scoping', + '--', + '--abbreviation' + ]) + ).rejects.toThrowError(/Ambiguous option: "--abbreviation"/); + }); + + it('fails when providing an ambiguous abbreviation between flags on the tool and the scoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: false, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['scoped-action', '--scoping', '--', '--abbrev']) + ).rejects.toThrowError(/Ambiguous option: "--abbrev" could match --abbreviation-flag, --abbreviation/); + }); + + it('fails when providing an ambiguous abbreviation between flags on the unscoped action and the scoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: true, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(['scoped-action', '--scoping', '--', '--abbrev']) + ).rejects.toThrowError(/Ambiguous option: "--abbrev" could match --abbreviation-flag, --abbreviation/); + }); + + it('allows unambiguous abbreviation between flags on the tool and the scoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: false, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + const toolAbbreviationFlag: CommandLineFlagParameter = commandLineParser.defineFlagParameter({ + parameterLongName: '--abbreviation', + description: 'A flag used to test abbreviation logic' + }); + const targetAction: AbbreviationScopedAction = commandLineParser.getAction( + 'scoped-action' + ) as AbbreviationScopedAction; + + await commandLineParser.executeWithoutErrorHandlingAsync([ + 'scoped-action', + '--scoping', + '--', + '--abbreviation-f' + ]); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('scoped-action'); + expect(targetAction.done).toBe(true); + expect(targetAction.scopedAbbreviationFlag?.value).toBe(true); + expect(toolAbbreviationFlag.value).toBe(false); + }); + + it('allows unambiguous abbreviation between flags on the unscoped action and the scoped action', async () => { + const actionOptions: IAbbreviationScopedActionOptions = { + includeUnscopedAbbreviationFlag: true, + includeScopedAbbreviationFlag: true + }; + const commandLineParser: GenericCommandLine = new GenericCommandLine( + AbbreviationScopedAction, + actionOptions + ); + const targetAction: AbbreviationScopedAction = commandLineParser.getAction( + 'scoped-action' + ) as AbbreviationScopedAction; + + await commandLineParser.executeWithoutErrorHandlingAsync([ + 'scoped-action', + '--scoping', + '--', + '--abbreviation-f' + ]); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('scoped-action'); + expect(targetAction.done).toBe(true); + expect(targetAction.scopedAbbreviationFlag?.value).toBe(true); + expect(targetAction.unscopedAbbreviationFlag?.value).toBe(false); + }); +}); diff --git a/libraries/ts-command-line/src/test/CommandLineParameter.test.ts b/libraries/ts-command-line/src/test/CommandLineParameter.test.ts index dae0ecfeab5..d8668b9c37a 100644 --- a/libraries/ts-command-line/src/test/CommandLineParameter.test.ts +++ b/libraries/ts-command-line/src/test/CommandLineParameter.test.ts @@ -1,20 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as colors from 'colors'; +import * as argparse from 'argparse'; -import { CommandLineAction } from '../CommandLineAction'; -import { CommandLineParser } from '../CommandLineParser'; -import { DynamicCommandLineParser } from '../DynamicCommandLineParser'; -import { DynamicCommandLineAction } from '../DynamicCommandLineAction'; +import { DynamicCommandLineParser } from '../providers/DynamicCommandLineParser'; +import { DynamicCommandLineAction } from '../providers/DynamicCommandLineAction'; +import { CommandLineParameterBase } from '../parameters/BaseClasses'; +import type { CommandLineParser } from '../providers/CommandLineParser'; +import type { CommandLineAction } from '../providers/CommandLineAction'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +interface IExtendedArgumentParser extends argparse.ArgumentParser { + _printMessage: (message: string) => void; +} function createParser(): DynamicCommandLineParser { - const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser( - { - toolFilename: 'example', - toolDescription: 'An example project' - } - ); + const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser({ + toolFilename: 'example', + toolDescription: 'An example project' + }); commandLineParser.defineFlagParameter({ parameterLongName: '--global-flag', parameterShortName: '-g', @@ -33,17 +37,26 @@ function createParser(): DynamicCommandLineParser { parameterLongName: '--choice', parameterShortName: '-c', description: 'A choice', - alternatives: [ 'one', 'two', 'three', 'default' ], + alternatives: ['one', 'two', 'three', 'default'], environmentVariable: 'ENV_CHOICE' }); action.defineChoiceParameter({ parameterLongName: '--choice-with-default', - description: 'A choice with a default', - alternatives: [ 'one', 'two', 'three', 'default' ], - environmentVariable: 'ENV_CHOICE', + description: 'A choice with a default. This description ends with a "quoted word"', + alternatives: ['one', 'two', 'three', 'default'], + environmentVariable: 'ENV_CHOICE2', defaultValue: 'default' }); + // Choice List + action.defineChoiceListParameter({ + parameterLongName: '--choice-list', + parameterShortName: '-C', + description: 'This parameter may be specified multiple times to make a list of choices', + alternatives: ['red', 'green', 'blue'], + environmentVariable: 'ENV_CHOICE_LIST' + }); + // Flag action.defineFlagParameter({ parameterLongName: '--flag', @@ -64,7 +77,7 @@ function createParser(): DynamicCommandLineParser { parameterLongName: '--integer-with-default', description: 'An integer with a default', argumentName: 'NUMBER', - environmentVariable: 'ENV_INTEGER', + environmentVariable: 'ENV_INTEGER2', defaultValue: 123 }); action.defineIntegerParameter({ @@ -73,6 +86,22 @@ function createParser(): DynamicCommandLineParser { argumentName: 'NUMBER', required: true }); + action.defineIntegerParameter({ + parameterLongName: '--env-integer-required', + description: 'An integer', + argumentName: 'NUMBER', + environmentVariable: 'ENV_INTEGER_REQUIRED', + required: true + }); + + // Integer List + action.defineIntegerListParameter({ + parameterLongName: '--integer-list', + parameterShortName: '-I', + description: 'This parameter may be specified multiple times to make a list of integers', + argumentName: 'LIST_ITEM', + environmentVariable: 'ENV_INTEGER_LIST' + }); // String action.defineStringParameter({ @@ -80,24 +109,31 @@ function createParser(): DynamicCommandLineParser { parameterShortName: '-s', description: 'A string', argumentName: 'TEXT', - environmentVariable: 'ENV_INTEGER' + environmentVariable: 'ENV_STRING' }); action.defineStringParameter({ parameterLongName: '--string-with-default', description: 'A string with a default', argumentName: 'TEXT', - environmentVariable: 'ENV_INTEGER', + environmentVariable: 'ENV_STRING2', defaultValue: '123' }); + action.defineStringParameter({ + parameterLongName: '--string-with-undocumented-synonym', + description: 'A string with an undocumented synonym', + argumentName: 'TEXT', + undocumentedSynonyms: ['--undocumented-synonym'] + }); // String List action.defineStringListParameter({ parameterLongName: '--string-list', parameterShortName: '-l', - description: 'A string list', - argumentName: 'LIST', - environmentVariable: 'ENV_INTEGER' + description: 'This parameter may be specified multiple times to make a list of strings', + argumentName: 'LIST_ITEM', + environmentVariable: 'ENV_STRING_LIST' }); + return commandLineParser; } @@ -105,7 +141,8 @@ function expectPropertiesToMatchSnapshot(object: {}, propertyNames: string[]): v const snapshotObject: {} = {}; for (const propertyName of propertyNames) { - snapshotObject[propertyName] = object[propertyName]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (snapshotObject as any)[propertyName] = (object as any)[propertyName]; } expect(snapshotObject).toMatchSnapshot(); } @@ -124,145 +161,306 @@ const snapshotPropertyNames: string[] = [ 'values' ]; -describe('CommandLineParameter', () => { - it('prints the global help', () => { - const commandLineParser: CommandLineParser = createParser(); - const helpText: string = colors.stripColors(commandLineParser.renderHelpText()); - expect(helpText).toMatchSnapshot(); +describe(CommandLineParameterBase.name, () => { + let existingEnv: NodeJS.ProcessEnv; + + beforeEach(() => { + existingEnv = { + ...process.env + }; }); - it('prints the action help', () => { + afterEach(() => { + process.env = existingEnv; + }); + + it('renders help text', () => { const commandLineParser: CommandLineParser = createParser(); - const helpText: string = colors.stripColors(commandLineParser.getAction('do:the-job').renderHelpText()); - expect(helpText).toMatchSnapshot(); + ensureHelpTextMatchesSnapshot(commandLineParser); }); - it('parses an input with ALL parameters', () => { + it('parses an input with ALL parameters', async () => { const commandLineParser: CommandLineParser = createParser(); const action: CommandLineAction = commandLineParser.getAction('do:the-job'); const args: string[] = [ '--global-flag', 'do:the-job', - '--choice', 'two', + '--choice', + 'two', + '--choice-list', + 'red', + '--choice-list', + 'blue', '--flag', - '--integer', '123', - '--integer-required', '321', - '--string', 'hello', - '--string-list', 'first', - '--string-list', 'second' + '--integer', + '123', + '--integer-required', + '321', + '--env-integer-required', + '123', + '--integer-list', + '37', + '--integer-list', + '-404', + '--string', + 'hello', + '--string-list', + 'first', + '--string-list', + 'second' ]; - return commandLineParser.execute(args).then(() => { - expect(commandLineParser.selectedAction).toBe(action); + await expect(commandLineParser.executeAsync(args)).resolves.toBe(true); - expectPropertiesToMatchSnapshot( - commandLineParser.getFlagParameter('--global-flag'), - snapshotPropertyNames - ); + expect(commandLineParser.selectedAction).toBe(action); - expectPropertiesToMatchSnapshot( - action.getChoiceParameter('--choice'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getChoiceParameter('--choice-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getFlagParameter('--flag'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer-required'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringParameter('--string'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringParameter('--string-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringListParameter('--string-list'), - snapshotPropertyNames - ); + expectPropertiesToMatchSnapshot( + commandLineParser.getFlagParameter('--global-flag'), + snapshotPropertyNames + ); - const copiedArgs: string[] = []; - for (const parameter of action.parameters) { - copiedArgs.push(`### ${parameter.longName} output: ###`); - parameter.appendToArgList(copiedArgs); - } - expect(copiedArgs).toMatchSnapshot(); + expectPropertiesToMatchSnapshot(action.getChoiceParameter('--choice'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getChoiceParameter('--choice-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getChoiceListParameter('--choice-list'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getFlagParameter('--flag'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getIntegerParameter('--integer'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getIntegerParameter('--integer-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getIntegerParameter('--integer-required'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getIntegerListParameter('--integer-list'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getStringParameter('--string'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getStringParameter('--string-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getStringListParameter('--string-list'), snapshotPropertyNames); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + expect(copiedArgs).toMatchSnapshot(); + }); + + it('parses an input with NO parameters', async () => { + const commandLineParser: CommandLineParser = createParser(); + const action: CommandLineAction = commandLineParser.getAction('do:the-job'); + const args: string[] = ['do:the-job', '--integer-required', '123', '--env-integer-required', '321']; + + await expect(commandLineParser.executeAsync(args)).resolves.toBe(true); + + expect(commandLineParser.selectedAction).toBe(action); + + expectPropertiesToMatchSnapshot( + commandLineParser.getFlagParameter('--global-flag'), + snapshotPropertyNames + ); + + expectPropertiesToMatchSnapshot(action.getChoiceParameter('--choice'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getChoiceParameter('--choice-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getChoiceListParameter('--choice-list'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getFlagParameter('--flag'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getIntegerParameter('--integer'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getIntegerParameter('--integer-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getIntegerParameter('--integer-required'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getIntegerListParameter('--integer-list'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot(action.getStringParameter('--string'), snapshotPropertyNames); + expectPropertiesToMatchSnapshot( + action.getStringParameter('--string-with-default'), + snapshotPropertyNames + ); + expectPropertiesToMatchSnapshot(action.getStringListParameter('--string-list'), snapshotPropertyNames); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + expect(copiedArgs).toMatchSnapshot(); + }); + + it('parses each parameter from an environment variable', async () => { + const commandLineParser: CommandLineParser = createParser(); + const action: CommandLineAction = commandLineParser.getAction('do:the-job'); + + action.defineStringListParameter({ + parameterLongName: '--json-string-list', + description: 'Test JSON parsing', + argumentName: 'LIST_ITEM', + environmentVariable: 'ENV_JSON_STRING_LIST' }); + + const args: string[] = ['do:the-job', '--integer-required', '1']; + + process.env.ENV_CHOICE = 'one'; + process.env.ENV_CHOICE2 = 'two'; + process.env.ENV_CHOICE_LIST = ' [ "red", "green" ] '; + process.env.ENV_FLAG = '1'; + process.env.ENV_INTEGER = '111'; + process.env.ENV_INTEGER2 = '222'; + process.env.ENV_INTEGER_REQUIRED = '333'; + process.env.ENV_INTEGER_LIST = ' [ 1 , 2 , 3 ] '; + process.env.ENV_STRING = 'Hello, world!'; + process.env.ENV_STRING2 = 'Hello, world!'; + process.env.ENV_STRING_LIST = 'simple text'; + process.env.ENV_JSON_STRING_LIST = ' [ 1, true, "Hello, world!" ] '; + + await expect(commandLineParser.executeAsync(args)).resolves.toBe(true); + + expect(commandLineParser.selectedAction).toBe(action); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + expect(copiedArgs).toMatchSnapshot(); }); - it('parses an input with NO parameters', () => { + it('allows an undocumented synonym', async () => { const commandLineParser: CommandLineParser = createParser(); const action: CommandLineAction = commandLineParser.getAction('do:the-job'); - const args: string[] = [ 'do:the-job', '--integer-required', '123']; - return commandLineParser.execute(args).then(() => { - expect(commandLineParser.selectedAction).toBe(action); + const args: string[] = [ + 'do:the-job', + '--undocumented-synonym', + 'undocumented-value', + '--integer-required', + '6', + '--env-integer-required', + '123' + ]; - expectPropertiesToMatchSnapshot( - commandLineParser.getFlagParameter('--global-flag'), - snapshotPropertyNames - ); + await expect(commandLineParser.executeAsync(args)).resolves.toBe(true); - expectPropertiesToMatchSnapshot( - action.getChoiceParameter('--choice'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getChoiceParameter('--choice-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getFlagParameter('--flag'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getIntegerParameter('--integer-required'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringParameter('--string'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringParameter('--string-with-default'), - snapshotPropertyNames - ); - expectPropertiesToMatchSnapshot( - action.getStringListParameter('--string-list'), - snapshotPropertyNames - ); + expect(commandLineParser.selectedAction).toBe(action); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + expect(copiedArgs).toMatchSnapshot(); + }); + + it('raises an error if a required parameter backed by an env variable is not provided', async () => { + const commandLineParser: CommandLineParser = createParser(); + + const printMessageSpy: jest.SpyInstance = jest + .spyOn(argparse.ArgumentParser.prototype as IExtendedArgumentParser, '_printMessage') + .mockImplementation(() => { + /* don't print */ + }); + + const args: string[] = ['do:the-job', '--integer-required', '1']; + await expect(commandLineParser.executeWithoutErrorHandlingAsync(args)).rejects.toMatchSnapshot('Error'); + expect(printMessageSpy).toHaveBeenCalled(); + expect(printMessageSpy.mock.calls[0][0]).toMatchSnapshot('Usage'); + }); - const copiedArgs: string[] = []; - for (const parameter of action.parameters) { - copiedArgs.push(`### ${parameter.longName} output: ###`); - parameter.appendToArgList(copiedArgs); + it( + 'prints the same usage if a required parameter backed by an env variable is not provided as when ' + + 'a different required parameter is missing', + async () => { + const printMessageSpy: jest.SpyInstance = jest + .spyOn(argparse.ArgumentParser.prototype as IExtendedArgumentParser, '_printMessage') + .mockImplementation(() => { + /* don't print */ + }); + + async function runWithArgsAsync(args: string[]): Promise { + const commandLineParser: CommandLineParser = createParser(); + await expect(commandLineParser.executeAsync(args)).resolves.toBe(false); } - expect(copiedArgs).toMatchSnapshot(); + + await runWithArgsAsync(['do:the-job', '--integer-required', '1']); + await runWithArgsAsync(['do:the-job', '--env-integer-required', '1']); + + expect(printMessageSpy).toHaveBeenCalledTimes(2); + expect(printMessageSpy.mock.calls[0][0]).toMatchSnapshot('Usage'); + expect(printMessageSpy.mock.calls[0][0]).toEqual(printMessageSpy.mock.calls[1][0]); + } + ); + + describe('choice list', () => { + function createHelloWorldParser(): CommandLineParser { + const commandLineParser: CommandLineParser = new DynamicCommandLineParser({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + const action: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'hello-world', + summary: 'Hello World', + documentation: 'best program' + }); + commandLineParser.addAction(action); + + action.defineChoiceListParameter({ + parameterLongName: '--color', + parameterShortName: '-c', + description: 'Your favorite colors', + alternatives: ['purple', 'yellow', 'pizza'], + environmentVariable: 'ENV_COLOR' + }); + + return commandLineParser; + } + + it('raises an error if env var value is not valid json', async () => { + const commandLineParser: CommandLineParser = createHelloWorldParser(); + const args: string[] = ['hello-world']; + process.env.ENV_COLOR = '[u'; + + // TODO: When Node 18 support is removed, switch this to use + // ``` + // await expect( + // commandLineParser.executeWithoutErrorHandling(args) + // ).rejects.toThrowErrorMatchingSnapshot(); + // ``` + + let error: string | undefined; + try { + await commandLineParser.executeWithoutErrorHandlingAsync(args); + } catch (e) { + error = e.message; + } + + expect(error).toMatch( + /^The \[u environment variable value looks like a JSON array but failed to parse: Unexpected token / + ); + }); + + it('raises an error if env var value is json containing non-scalars', async () => { + const commandLineParser: CommandLineParser = createHelloWorldParser(); + const args: string[] = ['hello-world']; + process.env.ENV_COLOR = '[{}]'; + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(args) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('raises an error if env var value is not a valid choice', async () => { + const commandLineParser: CommandLineParser = createHelloWorldParser(); + const args: string[] = ['hello-world']; + process.env.ENV_COLOR = 'oblong'; + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(args) + ).rejects.toThrowErrorMatchingSnapshot(); }); }); }); diff --git a/libraries/ts-command-line/src/test/CommandLineParser.test.ts b/libraries/ts-command-line/src/test/CommandLineParser.test.ts index d9126ba6de8..4f9aec25aa2 100644 --- a/libraries/ts-command-line/src/test/CommandLineParser.test.ts +++ b/libraries/ts-command-line/src/test/CommandLineParser.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 { CommandLineAction } from '../CommandLineAction'; -import { CommandLineParser } from '../CommandLineParser'; -import { CommandLineFlagParameter } from '../CommandLineParameter'; +import { CommandLineAction } from '../providers/CommandLineAction'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { CommandLineParser } from '../providers/CommandLineParser'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; class TestAction extends CommandLineAction { public done: boolean = false; @@ -12,52 +13,49 @@ class TestAction extends CommandLineAction { public constructor() { super({ actionName: 'do:the-job', - summary: 'does the job', - documentation: 'a longer description' + summary: 'does the job with sprintf-style escape characters, 100%', + documentation: 'a longer description with sprintf-style escape characters, 100%' }); - } - - protected onExecute(): Promise { - expect(this._flag.value).toEqual(true); - this.done = true; - return Promise.resolve(); - } - protected onDefineParameters(): void { this._flag = this.defineFlagParameter({ parameterLongName: '--flag', description: 'The flag' }); } + + protected override async onExecuteAsync(): Promise { + expect(this._flag.value).toEqual(true); + this.done = true; + } } class TestCommandLine extends CommandLineParser { public constructor() { super({ toolFilename: 'example', - toolDescription: 'An example project' + toolDescription: 'An example project with sprintf-style escape characters, 100%' }); this.addAction(new TestAction()); } - - protected onDefineParameters(): void { - // no parameters - } } -describe('CommandLineParser', () => { +describe(CommandLineParser.name, () => { + it('renders help text', () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); - it('executes an action', () => { + it('executes an action', async () => { const commandLineParser: TestCommandLine = new TestCommandLine(); + commandLineParser._registerDefinedParameters({ parentParameterNames: new Set() }); - return commandLineParser.execute(['do:the-job', '--flag']).then(() => { - expect(commandLineParser.selectedAction).toBeDefined(); - expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job'); + await commandLineParser.executeAsync(['do:the-job', '--flag']); - const action: TestAction = commandLineParser.selectedAction as TestAction; - expect(action.done).toBe(true); - }); - }); + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job'); + const action: TestAction = commandLineParser.selectedAction as TestAction; + expect(action.done).toBe(true); + }); }); diff --git a/libraries/ts-command-line/src/test/CommandLineRemainder.test.ts b/libraries/ts-command-line/src/test/CommandLineRemainder.test.ts new file mode 100644 index 00000000000..e6d08dabe2a --- /dev/null +++ b/libraries/ts-command-line/src/test/CommandLineRemainder.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { CommandLineAction } from '../providers/CommandLineAction'; +import type { CommandLineParser } from '../providers/CommandLineParser'; +import { DynamicCommandLineParser } from '../providers/DynamicCommandLineParser'; +import { DynamicCommandLineAction } from '../providers/DynamicCommandLineAction'; +import { CommandLineRemainder } from '../parameters/CommandLineRemainder'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +function createParser(): DynamicCommandLineParser { + const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + commandLineParser.defineFlagParameter({ + parameterLongName: '--verbose', + description: 'A flag that affects all actions' + }); + + const action: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'run', + summary: 'does the job', + documentation: 'a longer description' + }); + commandLineParser.addAction(action); + + action.defineStringParameter({ + parameterLongName: '--title', + description: 'A string', + argumentName: 'TEXT' + }); + + // Although this is defined BEFORE the parameter, but it should still capture the end + action.defineCommandLineRemainder({ + description: 'The action remainder' + }); + + commandLineParser._registerDefinedParameters({ parentParameterNames: new Set() }); + + return commandLineParser; +} + +describe(CommandLineRemainder.name, () => { + it('renders help text', () => { + const commandLineParser: CommandLineParser = createParser(); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it('parses an action input with remainder', async () => { + const commandLineParser: CommandLineParser = createParser(); + const action: CommandLineAction = commandLineParser.getAction('run'); + const args: string[] = ['run', '--title', 'The title', 'the', 'remaining', 'args']; + + await commandLineParser.executeAsync(args); + + expect(commandLineParser.selectedAction).toBe(action); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + + copiedArgs.push(`### remainder output: ###`); + action.remainder!.appendToArgList(copiedArgs); + + expect(copiedArgs).toMatchSnapshot(); + }); + + it('parses an action input with remainder flagged options', async () => { + const commandLineParser: CommandLineParser = createParser(); + const action: CommandLineAction = commandLineParser.getAction('run'); + const args: string[] = ['run', '--title', 'The title', '--', '--the', 'remaining', '--args']; + + await commandLineParser.executeAsync(args); + + expect(commandLineParser.selectedAction).toBe(action); + + const copiedArgs: string[] = []; + for (const parameter of action.parameters) { + copiedArgs.push(`### ${parameter.longName} output: ###`); + parameter.appendToArgList(copiedArgs); + } + + copiedArgs.push(`### remainder output: ###`); + action.remainder!.appendToArgList(copiedArgs); + + expect(copiedArgs).toMatchSnapshot(); + }); +}); diff --git a/libraries/ts-command-line/src/test/ConflictingCommandLineParser.test.ts b/libraries/ts-command-line/src/test/ConflictingCommandLineParser.test.ts new file mode 100644 index 00000000000..fc93f22478d --- /dev/null +++ b/libraries/ts-command-line/src/test/ConflictingCommandLineParser.test.ts @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CommandLineAction } from '../providers/CommandLineAction'; +import type { CommandLineStringParameter } from '../parameters/CommandLineStringParameter'; +import { CommandLineParser } from '../providers/CommandLineParser'; +import type { IScopedLongNameParseResult } from '../providers/CommandLineParameterProvider'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +class GenericCommandLine extends CommandLineParser { + public constructor(action: new () => CommandLineAction) { + super({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + + this.addAction(new action()); + } +} + +class TestAction extends CommandLineAction { + public done: boolean = false; + private _scope1Arg: CommandLineStringParameter; + private _scope2Arg: CommandLineStringParameter; + private _nonConflictingArg: CommandLineStringParameter; + + public constructor() { + super({ + actionName: 'do:the-job', + summary: 'does the job', + documentation: 'a longer description' + }); + + // Used to validate that conflicting parameters with different scopes return different values + this._scope1Arg = this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope1', + argumentName: 'ARG', + description: 'The argument' + }); + // Used to validate that conflicting parameters with different scopes return different values + this._scope2Arg = this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope2', + argumentName: 'ARG', + description: 'The argument' + }); + // Used to validate that non-conflicting args can be reference by both the unscoped and the + // scoped parameter names + this._nonConflictingArg = this.defineStringParameter({ + parameterLongName: '--non-conflicting-arg', + parameterScope: 'scope3', + argumentName: 'ARG', + description: 'The argument' + }); + } + + protected override async onExecuteAsync(): Promise { + expect(this._scope1Arg.value).toEqual('scope1value'); + expect(this._scope2Arg.value).toEqual('scope2value'); + expect(this._nonConflictingArg.value).toEqual('nonconflictingvalue'); + this.done = true; + } +} + +class UnscopedDuplicateArgumentTestAction extends CommandLineAction { + public constructor() { + super({ + actionName: 'do:the-job', + summary: 'does the job', + documentation: 'a longer description' + }); + + // Used to validate that conflicting parameters with at least one being unscoped fails + this.defineStringParameter({ + parameterLongName: '--arg', + argumentName: 'ARG', + description: 'The argument' + }); + + // Used to validate that conflicting parameters with at least one being unscoped fails + this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope', + argumentName: 'ARG', + description: 'The argument' + }); + } + + protected override async onExecuteAsync(): Promise { + throw new Error('This action should not be executed'); + } +} + +class ScopedDuplicateArgumentTestAction extends CommandLineAction { + public constructor() { + super({ + actionName: 'do:the-job', + summary: 'does the job', + documentation: 'a longer description' + }); + + // Used to validate that conflicting parameters with at least one being unscoped fails + this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope', + argumentName: 'ARG', + description: 'The argument' + }); + // Used to validate that conflicting parameters with at least one being unscoped fails + this.defineStringParameter({ + parameterLongName: '--arg', + parameterScope: 'scope', + argumentName: 'ARG', + description: 'The argument' + }); + } + + protected override async onExecuteAsync(): Promise { + throw new Error('This action should not be executed'); + } +} + +describe(`Conflicting ${CommandLineParser.name}`, () => { + it('executes an action', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(TestAction); + + ensureHelpTextMatchesSnapshot(commandLineParser); + + await commandLineParser.executeAsync([ + 'do:the-job', + '--scope1:arg', + 'scope1value', + '--scope2:arg', + 'scope2value', + '--non-conflicting-arg', + 'nonconflictingvalue' + ]); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('do:the-job'); + + const action: TestAction = commandLineParser.selectedAction as TestAction; + expect(action.done).toBe(true); + + expect(action.renderHelpText()).toMatchSnapshot(); + expect(action.getParameterStringMap()).toMatchSnapshot(); + }); + + it('parses the scope out of a long name correctly', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(TestAction); + + ensureHelpTextMatchesSnapshot(commandLineParser); + + let result: IScopedLongNameParseResult = commandLineParser.parseScopedLongName('--scope1:arg'); + expect(result.scope).toEqual('scope1'); + expect(result.longName).toEqual('--arg'); + + result = commandLineParser.parseScopedLongName('--arg'); + expect(result.scope).toBeUndefined(); + expect(result.longName).toEqual('--arg'); + + result = commandLineParser.parseScopedLongName('--my-scope:my-arg'); + expect(result.scope).toEqual('my-scope'); + expect(result.longName).toEqual('--my-arg'); + }); + + it('fails to execute an action when some conflicting parameters are unscoped', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(UnscopedDuplicateArgumentTestAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync([ + 'do:the-job', + '--arg', + 'value', + '--scope:arg', + 'value' + ]) + ).rejects.toThrowError(/The parameter "--arg" is defined multiple times with the same long name/); + }); + + it('fails to execute an action with conflicting parameters with the same scope', async () => { + const commandLineParser: GenericCommandLine = new GenericCommandLine(ScopedDuplicateArgumentTestAction); + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync([ + 'do:the-job', + '--arg', + 'value', + '--scope:arg', + 'value' + ]) + ).rejects.toThrowError(/argument "\-\-scope:arg": Conflicting option string\(s\): \-\-scope:arg/); + }); +}); diff --git a/libraries/ts-command-line/src/test/DynamicCommandLineParser.test.ts b/libraries/ts-command-line/src/test/DynamicCommandLineParser.test.ts index 5e9d5760a50..795b9ed2068 100644 --- a/libraries/ts-command-line/src/test/DynamicCommandLineParser.test.ts +++ b/libraries/ts-command-line/src/test/DynamicCommandLineParser.test.ts @@ -1,19 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { DynamicCommandLineParser } from '../DynamicCommandLineParser'; -import { DynamicCommandLineAction } from '../DynamicCommandLineAction'; -import { CommandLineFlagParameter } from '../CommandLineParameter'; +import { DynamicCommandLineParser } from '../providers/DynamicCommandLineParser'; +import { DynamicCommandLineAction } from '../providers/DynamicCommandLineAction'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; -describe('DynamicCommandLineParser', () => { - - it('parses an action', () => { - const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser( - { - toolFilename: 'example', - toolDescription: 'An example project' - } - ); +describe(DynamicCommandLineParser.name, () => { + it('parses an action', async () => { + const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser({ + toolFilename: 'example', + toolDescription: 'An example project' + }); const action: DynamicCommandLineAction = new DynamicCommandLineAction({ actionName: 'do:the-job', @@ -26,11 +24,13 @@ describe('DynamicCommandLineParser', () => { description: 'The flag' }); - return commandLineParser.execute(['do:the-job', '--flag']).then(() => { - expect(commandLineParser.selectedAction).toEqual(action); + ensureHelpTextMatchesSnapshot(commandLineParser); - const retrievedParameter: CommandLineFlagParameter = action.getFlagParameter('--flag'); - expect(retrievedParameter.value).toBe(true); - }); + await commandLineParser.executeAsync(['do:the-job', '--flag']); + + expect(commandLineParser.selectedAction).toEqual(action); + + const retrievedParameter: CommandLineFlagParameter = action.getFlagParameter('--flag'); + expect(retrievedParameter.value).toBe(true); }); }); diff --git a/libraries/ts-command-line/src/test/EndToEndTest.test.ts b/libraries/ts-command-line/src/test/EndToEndTest.test.ts new file mode 100644 index 00000000000..43d31c30777 --- /dev/null +++ b/libraries/ts-command-line/src/test/EndToEndTest.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 type { ChildProcess } from 'node:child_process'; +import { Executable } from '@rushstack/node-core-library'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +const TEST_CLI_PATH: string = `${__dirname}/test-cli/start`; + +function runTestCliTestWithArgs(testName: string, args: string[]): void { + it(testName, async () => { + const testCliProcess: ChildProcess = Executable.spawn(process.argv0, [TEST_CLI_PATH, ...args], { + stdio: 'pipe' + }); + const { stdout, stderr, exitCode, signal } = await Executable.waitForExitAsync(testCliProcess, { + encoding: 'utf8' + }); + + expect(stdout).toMatchSnapshot('process stdout'); + expect(stderr).toMatchSnapshot('process stderr'); + expect(exitCode).toMatchSnapshot('process exit code'); + expect(signal).toMatchSnapshot('process signal'); + }); +} + +describe('end-to-end test', () => { + beforeEach(() => { + // ts-command-line calls process.exit() which interferes with Jest + jest.spyOn(process, 'exit').mockImplementation((code) => { + throw new Error(`Test code called process.exit(${code})`); + }); + }); + + it(`prints the help`, async () => { + const { WidgetCommandLine } = await import('./test-cli/WidgetCommandLine'); + + const parser = new WidgetCommandLine(); + + ensureHelpTextMatchesSnapshot(parser); + }); + + describe('execution tests', () => { + runTestCliTestWithArgs('with no args', []); + runTestCliTestWithArgs('run', ['run']); + runTestCliTestWithArgs('run --title My Title', ['run', '--title', 'My Title']); + runTestCliTestWithArgs('run --title My Title --remaining --args', [ + 'run', + '--title', + 'My Title', + '--remaining', + '--args' + ]); + runTestCliTestWithArgs('push', ['push']); + runTestCliTestWithArgs('push --force', ['push', '--force']); + runTestCliTestWithArgs('push --protocol ftp', ['push', '--protocol', 'ftp']); + runTestCliTestWithArgs('push --protocol bogus', ['push', '--protocol', 'bogus']); + }); +}); diff --git a/libraries/ts-command-line/src/test/ScopedCommandLineAction.test.ts b/libraries/ts-command-line/src/test/ScopedCommandLineAction.test.ts new file mode 100644 index 00000000000..a535c1e77cc --- /dev/null +++ b/libraries/ts-command-line/src/test/ScopedCommandLineAction.test.ts @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AnsiEscape } from '@rushstack/terminal'; + +import { ScopedCommandLineAction } from '../providers/ScopedCommandLineAction'; +import type { CommandLineStringParameter } from '../parameters/CommandLineStringParameter'; +import { CommandLineParser } from '../providers/CommandLineParser'; +import type { CommandLineParameterProvider } from '../providers/CommandLineParameterProvider'; +import type { CommandLineFlagParameter } from '../parameters/CommandLineFlagParameter'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +class TestScopedAction extends ScopedCommandLineAction { + public done: boolean = false; + public scopedValue: string | undefined; + private _verboseArg: CommandLineFlagParameter; + private _scopeArg: CommandLineStringParameter; + private _scopedArg: CommandLineStringParameter | undefined; + + public constructor() { + super({ + actionName: 'scoped-action', + summary: 'does the scoped action', + documentation: 'a longer description' + }); + + this._verboseArg = this.defineFlagParameter({ + parameterLongName: '--verbose', + description: 'A flag parameter.' + }); + + this._scopeArg = this.defineStringParameter({ + parameterLongName: '--scope', + parameterGroup: ScopedCommandLineAction.ScopingParameterGroup, + argumentName: 'SCOPE', + description: 'The scope' + }); + } + + protected override async onExecuteAsync(): Promise { + if (this._scopedArg) { + expect(this._scopedArg.longName).toBe(`--scoped-${this._scopeArg.value}`); + this.scopedValue = this._scopedArg.value; + } + this.done = true; + } + + protected onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void { + if (this._scopeArg.value) { + this._scopedArg = scopedParameterProvider.defineStringParameter({ + parameterLongName: `--scoped-${this._scopeArg.value}`, + argumentName: 'SCOPED', + description: 'The scoped argument.' + }); + } + } +} + +class TestCommandLine extends CommandLineParser { + public constructor() { + super({ + toolFilename: 'example', + toolDescription: 'An example project' + }); + + this.addAction(new TestScopedAction()); + } +} + +describe(CommandLineParser.name, () => { + it('renders help text', () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it('throws on unknown scoped arg', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const args: string[] = ['scoped-action', '--scope', 'foo', '--', '--scoped-bar', 'baz']; + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(args) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('throws on missing positional arg divider with unknown positional args', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const args: string[] = ['scoped-action', '--scope', 'foo', 'bar']; + + await expect( + commandLineParser.executeWithoutErrorHandlingAsync(args) + ).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('executes a scoped action', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + + await commandLineParser.executeAsync(['scoped-action', '--scope', 'foo', '--', '--scoped-foo', 'bar']); + + expect(commandLineParser.selectedAction).toBeDefined(); + expect(commandLineParser.selectedAction!.actionName).toEqual('scoped-action'); + + const action: TestScopedAction = commandLineParser.selectedAction as TestScopedAction; + expect(action.done).toBe(true); + expect(action.scopedValue).toBe('bar'); + }); + + it('prints the action help', () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + const helpText: string = AnsiEscape.removeCodes( + commandLineParser.getAction('scoped-action').renderHelpText() + ); + expect(helpText).toMatchSnapshot(); + }); + + it('prints the scoped action help', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + // Execute the parser in order to populate the scoped action to populate the help text. + await commandLineParser.executeAsync(['scoped-action', '--scope', 'foo', '--', '--scoped-foo', 'bar']); + const scopedAction: TestScopedAction & { _getScopedCommandLineParser(): CommandLineParser } = + commandLineParser.getAction('scoped-action') as TestScopedAction & { + _getScopedCommandLineParser(): CommandLineParser; + }; + const scopedCommandLineParser: CommandLineParser = scopedAction._getScopedCommandLineParser(); + const helpText: string = AnsiEscape.removeCodes(scopedCommandLineParser.renderHelpText()); + expect(helpText).toMatchSnapshot(); + }); + + it('prints the unscoped action parameter map', async () => { + const commandLineParser: TestCommandLine = new TestCommandLine(); + // Execute the parser in order to populate the scoped action + await commandLineParser.executeAsync(['scoped-action', '--verbose']); + const scopedAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + expect(scopedAction.done).toBe(true); + expect(scopedAction.parameters.length).toBe(2); + const parameterStringMap: Record = scopedAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); + + it('prints the scoped action parameter map', async () => { + let commandLineParser: TestCommandLine = new TestCommandLine(); + // Execute the parser in order to populate the scoped action + await commandLineParser.executeAsync(['scoped-action', '--scope', 'foo']); + let scopedAction: TestScopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + expect(scopedAction.done).toBe(true); + expect(scopedAction.parameters.length).toBe(3); + let parameterStringMap: Record = scopedAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + + commandLineParser = new TestCommandLine(); + // Execute the parser in order to populate the scoped action + await commandLineParser.executeAsync(['scoped-action', '--scope', 'foo', '--', '--scoped-foo', 'bar']); + scopedAction = commandLineParser.getAction('scoped-action') as TestScopedAction; + expect(scopedAction.done).toBe(true); + expect(scopedAction.parameters.length).toBe(3); + parameterStringMap = scopedAction.getParameterStringMap(); + expect(parameterStringMap).toMatchSnapshot(); + }); +}); diff --git a/libraries/ts-command-line/src/test/TabCompleteAction.test.ts b/libraries/ts-command-line/src/test/TabCompleteAction.test.ts new file mode 100644 index 00000000000..f70e5d0c815 --- /dev/null +++ b/libraries/ts-command-line/src/test/TabCompleteAction.test.ts @@ -0,0 +1,452 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { DynamicCommandLineParser } from '../providers/DynamicCommandLineParser'; +import { DynamicCommandLineAction } from '../providers/DynamicCommandLineAction'; +import { TabCompleteAction } from '../providers/TabCompletionAction'; +import { ensureHelpTextMatchesSnapshot } from './helpTestUtilities'; + +async function arrayFromAsyncIteratorAsync(iterator: AsyncIterable): Promise { + const ret: string[] = []; + + for await (const val of iterator) { + ret.push(val); + } + + return ret; +} + +function getCommandLineParser(): DynamicCommandLineParser { + const commandLineParser: DynamicCommandLineParser = new DynamicCommandLineParser({ + toolFilename: 'rush', + toolDescription: 'Rush: a scalable monorepo manager for the web', + enableTabCompletionAction: true + }); + + const addAction: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'add', + summary: 'Adds a dependency to the package.json and runs rush update.', + documentation: 'Adds a dependency to the package.json and runs rush update.' + }); + commandLineParser.addAction(addAction); + addAction.defineStringParameter({ + parameterLongName: '--package', + parameterShortName: '-p', + required: true, + argumentName: 'PACKAGE', + description: + '(Required) 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".' + }); + addAction.defineFlagParameter({ + parameterLongName: '--exact', + description: + 'If specified, the SemVer specifier added to the' + + ' package.json will be an exact version (e.g. without tilde or caret).' + }); + addAction.defineFlagParameter({ + parameterLongName: '--caret', + description: + 'If specified, the SemVer specifier added to the' + + ' package.json will be a prepended with a "caret" specifier ("^").' + }); + addAction.defineFlagParameter({ + parameterLongName: '--dev', + description: + 'If specified, the package will be added to the "devDependencies" section of the package.json' + }); + addAction.defineFlagParameter({ + parameterLongName: '--make-consistent', + 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.' + }); + addAction.defineFlagParameter({ + parameterLongName: '--skip-update', + parameterShortName: '-s', + description: + 'If specified, the "rush update" command will not be run after updating the package.json files.' + }); + addAction.defineFlagParameter({ + parameterLongName: '--all', + description: 'If specified, the dependency will be added to all projects.' + }); + + const buildAction: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'build', + summary: "Build all projects that haven't been built.", + documentation: "Build all projects that haven't been built." + }); + commandLineParser.addAction(buildAction); + buildAction.defineStringParameter({ + parameterLongName: '--parallelism', + parameterShortName: '-p', + argumentName: 'COUNT', + description: 'Specifies the maximum number of concurrent processes to launch during a build.' + }); + buildAction.defineStringListParameter({ + parameterLongName: '--to', + parameterShortName: '-t', + argumentName: 'PROJECT1', + description: 'Run command in the specified project and all of its dependencies.', + getCompletionsAsync: async (): Promise => { + return ['abc', 'def', 'hij']; + } + }); + buildAction.defineStringListParameter({ + parameterLongName: '--from', + parameterShortName: '-f', + argumentName: 'PROJECT2', + description: + 'Run command in the specified project and all projects that directly or indirectly depend on the ' + + 'specified project.' + }); + + const changeAction: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'change', + summary: + 'Records changes made to projects, indicating how the package version number should be bumped ' + + 'for the next publish.', + documentation: 'Asks a series of questions and then generates a -.json file.' + }); + commandLineParser.addAction(changeAction); + changeAction.defineFlagParameter({ + parameterLongName: '--verify', + parameterShortName: '-v', + description: 'Verify the change file has been generated and that it is a valid JSON file' + }); + changeAction.defineFlagParameter({ + parameterLongName: '--no-fetch', + description: 'Skips fetching the baseline branch before running "git diff" to detect changes.' + }); + changeAction.defineStringParameter({ + parameterLongName: '--target-branch', + parameterShortName: '-b', + argumentName: 'BRANCH', + description: 'If this parameter is specified, compare the checked out branch with the specified branch.' + }); + changeAction.defineFlagParameter({ + parameterLongName: '--overwrite', + description: `If a changefile already exists, overwrite without prompting.` + }); + changeAction.defineStringParameter({ + parameterLongName: '--email', + argumentName: 'EMAIL', + description: + 'The email address to use in changefiles. If this parameter is not provided, the email address ' + + 'will be detected or prompted for in interactive mode.' + }); + changeAction.defineFlagParameter({ + parameterLongName: '--bulk', + description: + 'If this flag is specified, apply the same change message and bump type to all changed projects. ' + }); + changeAction.defineStringParameter({ + parameterLongName: '--message', + argumentName: 'MESSAGE', + description: `The message to apply to all changed projects.` + }); + changeAction.defineChoiceParameter({ + parameterLongName: '--bump-type', + alternatives: ['major', 'minor', 'patch', 'none'], + description: `The bump type to apply to all changed projects.` + }); + + const installAction: DynamicCommandLineAction = new DynamicCommandLineAction({ + actionName: 'install', + summary: 'Install package dependencies for all projects in the repo according to the shrinkwrap file.', + documentation: + 'Longer description: Install package dependencies for all projects in the repo according ' + + 'to the shrinkwrap file.' + }); + commandLineParser.addAction(installAction); + installAction.defineFlagParameter({ + parameterLongName: '--purge', + parameterShortName: '-p', + description: 'Perform "rush purge" before starting the installation' + }); + installAction.defineFlagParameter({ + parameterLongName: '--bypass-policy', + description: 'Overrides enforcement of the "gitPolicy" rules from rush.json (use honorably!)' + }); + installAction.defineFlagParameter({ + parameterLongName: '--no-link', + description: 'If "--no-link" is specified, then project symlinks will NOT be created' + }); + installAction.defineIntegerParameter({ + parameterLongName: '--network-concurrency', + argumentName: 'COUNT', + description: 'If specified, limits the maximum number of concurrent network requests.' + }); + installAction.defineFlagParameter({ + parameterLongName: '--debug-package-manager', + description: 'Activates verbose logging for the package manager.' + }); + installAction.defineIntegerParameter({ + parameterLongName: '--max-install-attempts', + argumentName: 'NUMBER', + description: `Overrides the default maximum number of install attempts.`, + defaultValue: 3 + }); + + commandLineParser.defineFlagParameter({ + parameterLongName: '--debug', + parameterShortName: '-d', + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + return commandLineParser; +} + +const commandLineParser: DynamicCommandLineParser = getCommandLineParser(); +const tc: TabCompleteAction = new TabCompleteAction(commandLineParser.actions, commandLineParser.parameters); + +describe(TabCompleteAction.name, () => { + it('renders help text', () => { + ensureHelpTextMatchesSnapshot(commandLineParser); + }); + + it(`gets completion(s) for rush `, async () => { + const commandLine: string = 'rush '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "--debug", + "-d", + "add", + "build", + "change", + "install", +] +`); + }); + + it(`gets completion(s) for rush a`, async () => { + const commandLine: string = 'rush a'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "add", +] +`); + }); + + it(`gets completion(s) for rush -d a`, async () => { + const commandLine: string = 'rush -d a'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "add", +] +`); + }); + + it(`gets completion(s) for rush build `, async () => { + const commandLine: string = 'rush build '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "--from", + "--parallelism", + "--to", + "-f", + "-p", + "-t", +] +`); + }); + + it(`gets completion(s) for rush build -`, async () => { + const commandLine: string = 'rush build -'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "--from", + "--parallelism", + "--to", + "-f", + "-p", + "-t", +] +`); + }); + + it(`gets completion(s) for rush build -t `, async () => { + const commandLine: string = 'rush build -t '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "abc", + "def", + "hij", +] +`); + }); + + it(`gets completion(s) for rush build -t a`, async () => { + const commandLine: string = 'rush build -t a'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "abc", +] +`); + }); + + it(`gets completion(s) for rush --debug build -t a`, async () => { + const commandLine: string = 'rush --debug build -t a'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "abc", +] +`); + }); + + it(`gets completion(s) for rush change --bump-type `, async () => { + const commandLine: string = 'rush change --bump-type '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "major", + "minor", + "none", + "patch", +] +`); + }); + + it(`gets completion(s) for rush change --bulk `, async () => { + const commandLine: string = 'rush change --bulk '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "--bulk", + "--bump-type", + "--email", + "--message", + "--no-fetch", + "--overwrite", + "--target-branch", + "--verify", + "-b", + "-v", +] +`); + }); + + it(`gets completion(s) for rush change --bump-type m`, async () => { + const commandLine: string = 'rush change --bump-type m'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "major", + "minor", +] +`); + }); + + it(`gets completion(s) for rush change --message `, async () => { + const commandLine: string = 'rush change --message '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(`Array []`); + }); + + it(`gets completion(s) for rush change --message "my change log message" --bump-type `, async () => { + const commandLine: string = 'rush change --message "my change log message" --bump-type '; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "major", + "minor", + "none", + "patch", +] +`); + }); + + it(`gets completion(s) for rush change --message "my change log message" --bump-type m`, async () => { + const commandLine: string = 'rush change --message "my change log message" --bump-type m'; + const actual: string[] = await arrayFromAsyncIteratorAsync( + tc.getCompletionsAsync(commandLine, commandLine.length) + ); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "major", + "minor", +] +`); + }); +}); + +describe(TabCompleteAction.prototype.tokenizeCommandLine.name, () => { + it(`tokenizes "rush change -"`, () => { + const commandLine: string = 'rush change -'; + const actual: string[] = tc.tokenizeCommandLine(commandLine); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "-", + "change", + "rush", +] +`); + }); + + it(`tokenizes 'rush change -m "my change log"'`, () => { + const commandLine: string = 'rush change -m "my change log"'; + const actual: string[] = tc.tokenizeCommandLine(commandLine); + + expect(actual.sort()).toMatchInlineSnapshot(` +Array [ + "-m", + "change", + "my change log", + "rush", +] +`); + }); +}); diff --git a/libraries/ts-command-line/src/test/__snapshots__/ActionlessParser.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/ActionlessParser.test.ts.snap new file mode 100644 index 00000000000..89ee4b8b082 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/ActionlessParser.test.ts.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Actionless CommandLineParser renders help text: global help 1`] = ` +"usage: example [-h] [--flag] + +An example project + +Optional arguments: + -h, --help Show this help message and exit. + --flag The flag + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/AliasedCommandLineAction.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/AliasedCommandLineAction.test.ts.snap new file mode 100644 index 00000000000..45b417c3c12 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/AliasedCommandLineAction.test.ts.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AliasCommandLineAction prints the action parameter map 1`] = ` +Object { + "--flag": "true", +} +`; + +exports[`AliasCommandLineAction prints the scoped action parameter map 1`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": undefined, + "--verbose": "false", +} +`; + +exports[`AliasCommandLineAction prints the scoped action parameter map 2`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": "\\"bar\\"", + "--verbose": "false", +} +`; + +exports[`AliasCommandLineAction prints the scoped action parameter map with provided default scoping arguments 1`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": undefined, + "--verbose": "false", +} +`; + +exports[`AliasCommandLineAction prints the scoped action parameter map with provided default scoping arguments 2`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": "\\"bar\\"", + "--verbose": "false", +} +`; + +exports[`AliasCommandLineAction prints the unscoped action parameter map 1`] = ` +Object { + "--scope": undefined, + "--verbose": "true", +} +`; + +exports[`AliasCommandLineAction prints the unscoped action parameter map with provided default arguments 1`] = ` +Object { + "--scope": undefined, + "--verbose": "true", +} +`; + +exports[`AliasCommandLineAction renders help text: action 1`] = ` +"usage: example action [-h] [--flag] + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --flag The flag +" +`; + +exports[`AliasCommandLineAction renders help text: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + action does the action + scoped-action + does the scoped action + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; + +exports[`AliasCommandLineAction renders help text: scoped-action 1`] = ` +"usage: example scoped-action [-h] [--verbose] [--scope SCOPE] ... + +a longer description + +Positional arguments: + \\"...\\" Scoped parameters. Must be prefixed with \\"--\\", ex. \\"-- + --scopedParameter foo --scopedFlag\\". For more information on + available scoped parameters, use \\"-- --help\\". + +Optional arguments: + -h, --help Show this help message and exit. + --verbose A flag parameter. + +Optional scoping arguments: + --scope SCOPE The scope +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/AmbiguousCommandLineParser.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/AmbiguousCommandLineParser.test.ts.snap new file mode 100644 index 00000000000..37c140b9f80 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/AmbiguousCommandLineParser.test.ts.snap @@ -0,0 +1,130 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Ambiguous CommandLineParser can execute the non-ambiguous scoped long names 1`] = ` +"usage: example do:the-job [-h] [--short1 ARG] [--short2 ARG] + [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --short1 ARG The argument + --short2 ARG The argument + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope:non-conflicting-arg ARG + The argument +" +`; + +exports[`Ambiguous CommandLineParser can execute the non-ambiguous scoped long names 2`] = ` +Object { + "--scope1:arg": "\\"scope1value\\"", + "--scope2:arg": "\\"scope2value\\"", + "--scope:non-conflicting-arg": "\\"nonconflictingvalue\\"", + "--short1": "\\"short1value\\"", + "--short2": "\\"short2value\\"", +} +`; + +exports[`Ambiguous CommandLineParser fails to execute when an ambiguous long name is provided 1`] = ` +"Error: example do:the-job: error: Ambiguous option: \\"--arg\\" could match --scope1:arg, --scope2:arg. +" +`; + +exports[`Ambiguous CommandLineParser fails to execute when an ambiguous short name is provided 1`] = ` +"Error: example do:the-job: error: Ambiguous option: \\"-s\\" could match --short1, --short2. +" +`; + +exports[`Ambiguous CommandLineParser renders help text: do:the-job 1`] = ` +"usage: example do:the-job [-h] [--short1 ARG] [--short2 ARG] + [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --short1 ARG The argument + --short2 ARG The argument + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope:non-conflicting-arg ARG + The argument +" +`; + +exports[`Ambiguous CommandLineParser renders help text: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + do:the-job + does the job + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; + +exports[`Ambiguous aliased CommandLineParser can execute the non-ambiguous scoped long names 1`] = ` +"usage: example do:the-job [-h] [--short1 ARG] [--short2 ARG] + [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --short1 ARG The argument + --short2 ARG The argument + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope:non-conflicting-arg ARG + The argument +" +`; + +exports[`Ambiguous aliased CommandLineParser can execute the non-ambiguous scoped long names 2`] = ` +Object { + "--scope1:arg": "\\"scope1value\\"", + "--scope2:arg": "\\"scope2value\\"", + "--scope:non-conflicting-arg": "\\"nonconflictingvalue\\"", + "--short1": "\\"short1value\\"", + "--short2": "\\"short2value\\"", +} +`; + +exports[`Ambiguous aliased CommandLineParser fails to execute when an ambiguous long name is provided 1`] = ` +"Error: example do:the-job-alias: error: Ambiguous option: \\"--arg\\" could match --scope1:arg, --scope2:arg. +" +`; + +exports[`Ambiguous aliased CommandLineParser fails to execute when an ambiguous short name is provided 1`] = ` +"Error: example do:the-job-alias: error: Ambiguous option: \\"-s\\" could match --short1, --short2. +" +`; + +exports[`Ambiguous scoping CommandLineParser fails to execute when an ambiguous long name is provided to a scoping action 1`] = ` +"Error: example scoped-action --scoping --: error: Ambiguous option: \\"--arg\\" could match --scope1:arg, --scope2:arg. +" +`; + +exports[`Ambiguous scoping CommandLineParser fails to execute when an ambiguous short name is provided to a scoping action 1`] = ` +"Error: example scoped-action --scoping --: error: Ambiguous option: \\"-s\\" could match --short1, --short2. +" +`; + +exports[`Ambiguous scoping CommandLineParser fails to execute when an ambiguous short name is provided to a scoping action with a matching ambiguous long name 1`] = ` +"Error: example scoped-action --scoping --: error: Ambiguous option: \\"-a\\" could match --scope1:arg, --scope2:arg, --non-conflicting-arg. +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/CommandLineParameter.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/CommandLineParameter.test.ts.snap index adf118c17d5..46d1b2cee61 100644 --- a/libraries/ts-command-line/src/test/__snapshots__/CommandLineParameter.test.ts.snap +++ b/libraries/ts-command-line/src/test/__snapshots__/CommandLineParameter.test.ts.snap @@ -1,6 +1,40 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`CommandLineParameter parses an input with ALL parameters 1`] = ` +exports[`CommandLineParameterBase allows an undocumented synonym 1`] = ` +Array [ + "### --choice output: ###", + "### --choice-with-default output: ###", + "--choice-with-default", + "default", + "### --choice-list output: ###", + "### --flag output: ###", + "### --integer output: ###", + "### --integer-with-default output: ###", + "--integer-with-default", + "123", + "### --integer-required output: ###", + "--integer-required", + "6", + "### --env-integer-required output: ###", + "--env-integer-required", + "123", + "### --integer-list output: ###", + "### --string output: ###", + "### --string-with-default output: ###", + "--string-with-default", + "123", + "### --string-with-undocumented-synonym output: ###", + "--string-with-undocumented-synonym", + "undocumented-value", + "### --string-list output: ###", +] +`; + +exports[`CommandLineParameterBase choice list raises an error if env var value is json containing non-scalars 1`] = `"The [{}] environment variable value looks like a JSON array but failed to parse: The [{}] environment variable value must be a JSON array containing only strings, numbers, and booleans."`; + +exports[`CommandLineParameterBase choice list raises an error if env var value is not a valid choice 1`] = `"Invalid value \\"oblong\\" for the environment variable ENV_COLOR. Valid choices are: \\"purple\\", \\"yellow\\", \\"pizza\\""`; + +exports[`CommandLineParameterBase parses an input with ALL parameters 1`] = ` Object { "argumentName": undefined, "defaultValue": undefined, @@ -15,13 +49,13 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 2`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 2`] = ` Object { "argumentName": undefined, "defaultValue": undefined, "description": "A choice", "environmentVariable": "ENV_CHOICE", - "kind": 0, + "kind": -0, "longName": "--choice", "required": false, "shortName": "-c", @@ -30,13 +64,13 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 3`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 3`] = ` Object { "argumentName": undefined, "defaultValue": "default", - "description": "A choice with a default", - "environmentVariable": "ENV_CHOICE", - "kind": 0, + "description": "A choice with a default. This description ends with a \\"quoted word\\"", + "environmentVariable": "ENV_CHOICE2", + "kind": -0, "longName": "--choice-with-default", "required": false, "shortName": undefined, @@ -45,7 +79,25 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 4`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 4`] = ` +Object { + "argumentName": undefined, + "defaultValue": undefined, + "description": "This parameter may be specified multiple times to make a list of choices", + "environmentVariable": "ENV_CHOICE_LIST", + "kind": 5, + "longName": "--choice-list", + "required": false, + "shortName": "-C", + "value": undefined, + "values": Array [ + "red", + "blue", + ], +} +`; + +exports[`CommandLineParameterBase parses an input with ALL parameters 5`] = ` Object { "argumentName": undefined, "defaultValue": undefined, @@ -60,7 +112,7 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 5`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 6`] = ` Object { "argumentName": "NUMBER", "defaultValue": undefined, @@ -75,12 +127,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 6`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 7`] = ` Object { "argumentName": "NUMBER", "defaultValue": 123, "description": "An integer with a default", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_INTEGER2", "kind": 2, "longName": "--integer-with-default", "required": false, @@ -90,7 +142,7 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 7`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 8`] = ` Object { "argumentName": "NUMBER", "defaultValue": undefined, @@ -105,12 +157,30 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 8`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 9`] = ` +Object { + "argumentName": "LIST_ITEM", + "defaultValue": undefined, + "description": "This parameter may be specified multiple times to make a list of integers", + "environmentVariable": "ENV_INTEGER_LIST", + "kind": 6, + "longName": "--integer-list", + "required": false, + "shortName": "-I", + "value": undefined, + "values": Array [ + 37, + -404, + ], +} +`; + +exports[`CommandLineParameterBase parses an input with ALL parameters 10`] = ` Object { "argumentName": "TEXT", "defaultValue": undefined, "description": "A string", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_STRING", "kind": 3, "longName": "--string", "required": false, @@ -120,12 +190,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 9`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 11`] = ` Object { "argumentName": "TEXT", "defaultValue": "123", "description": "A string with a default", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_STRING2", "kind": 3, "longName": "--string-with-default", "required": false, @@ -135,12 +205,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 10`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 12`] = ` Object { - "argumentName": "LIST", + "argumentName": "LIST_ITEM", "defaultValue": undefined, - "description": "A string list", - "environmentVariable": "ENV_INTEGER", + "description": "This parameter may be specified multiple times to make a list of strings", + "environmentVariable": "ENV_STRING_LIST", "kind": 4, "longName": "--string-list", "required": false, @@ -153,7 +223,7 @@ Object { } `; -exports[`CommandLineParameter parses an input with ALL parameters 11`] = ` +exports[`CommandLineParameterBase parses an input with ALL parameters 13`] = ` Array [ "### --choice output: ###", "--choice", @@ -161,6 +231,11 @@ Array [ "### --choice-with-default output: ###", "--choice-with-default", "default", + "### --choice-list output: ###", + "--choice-list", + "red", + "--choice-list", + "blue", "### --flag output: ###", "--flag", "### --integer output: ###", @@ -172,12 +247,21 @@ Array [ "### --integer-required output: ###", "--integer-required", "321", + "### --env-integer-required output: ###", + "--env-integer-required", + "123", + "### --integer-list output: ###", + "--integer-list", + "37", + "--integer-list", + "-404", "### --string output: ###", "--string", "hello", "### --string-with-default output: ###", "--string-with-default", "123", + "### --string-with-undocumented-synonym output: ###", "### --string-list output: ###", "--string-list", "first", @@ -186,7 +270,7 @@ Array [ ] `; -exports[`CommandLineParameter parses an input with NO parameters 1`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 1`] = ` Object { "argumentName": undefined, "defaultValue": undefined, @@ -201,13 +285,13 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 2`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 2`] = ` Object { "argumentName": undefined, "defaultValue": undefined, "description": "A choice", "environmentVariable": "ENV_CHOICE", - "kind": 0, + "kind": -0, "longName": "--choice", "required": false, "shortName": "-c", @@ -216,13 +300,13 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 3`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 3`] = ` Object { "argumentName": undefined, "defaultValue": "default", - "description": "A choice with a default", - "environmentVariable": "ENV_CHOICE", - "kind": 0, + "description": "A choice with a default. This description ends with a \\"quoted word\\"", + "environmentVariable": "ENV_CHOICE2", + "kind": -0, "longName": "--choice-with-default", "required": false, "shortName": undefined, @@ -231,7 +315,22 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 4`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 4`] = ` +Object { + "argumentName": undefined, + "defaultValue": undefined, + "description": "This parameter may be specified multiple times to make a list of choices", + "environmentVariable": "ENV_CHOICE_LIST", + "kind": 5, + "longName": "--choice-list", + "required": false, + "shortName": "-C", + "value": undefined, + "values": Array [], +} +`; + +exports[`CommandLineParameterBase parses an input with NO parameters 5`] = ` Object { "argumentName": undefined, "defaultValue": undefined, @@ -246,7 +345,7 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 5`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 6`] = ` Object { "argumentName": "NUMBER", "defaultValue": undefined, @@ -261,12 +360,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 6`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 7`] = ` Object { "argumentName": "NUMBER", "defaultValue": 123, "description": "An integer with a default", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_INTEGER2", "kind": 2, "longName": "--integer-with-default", "required": false, @@ -276,7 +375,7 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 7`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 8`] = ` Object { "argumentName": "NUMBER", "defaultValue": undefined, @@ -291,12 +390,27 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 8`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 9`] = ` +Object { + "argumentName": "LIST_ITEM", + "defaultValue": undefined, + "description": "This parameter may be specified multiple times to make a list of integers", + "environmentVariable": "ENV_INTEGER_LIST", + "kind": 6, + "longName": "--integer-list", + "required": false, + "shortName": "-I", + "value": undefined, + "values": Array [], +} +`; + +exports[`CommandLineParameterBase parses an input with NO parameters 10`] = ` Object { "argumentName": "TEXT", "defaultValue": undefined, "description": "A string", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_STRING", "kind": 3, "longName": "--string", "required": false, @@ -306,12 +420,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 9`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 11`] = ` Object { "argumentName": "TEXT", "defaultValue": "123", "description": "A string with a default", - "environmentVariable": "ENV_INTEGER", + "environmentVariable": "ENV_STRING2", "kind": 3, "longName": "--string-with-default", "required": false, @@ -321,12 +435,12 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 10`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 12`] = ` Object { - "argumentName": "LIST", + "argumentName": "LIST_ITEM", "defaultValue": undefined, - "description": "A string list", - "environmentVariable": "ENV_INTEGER", + "description": "This parameter may be specified multiple times to make a list of strings", + "environmentVariable": "ENV_STRING_LIST", "kind": 4, "longName": "--string-list", "required": false, @@ -336,12 +450,13 @@ Object { } `; -exports[`CommandLineParameter parses an input with NO parameters 11`] = ` +exports[`CommandLineParameterBase parses an input with NO parameters 13`] = ` Array [ "### --choice output: ###", "### --choice-with-default output: ###", "--choice-with-default", "default", + "### --choice-list output: ###", "### --flag output: ###", "### --integer output: ###", "### --integer-with-default output: ###", @@ -350,20 +465,113 @@ Array [ "### --integer-required output: ###", "--integer-required", "123", + "### --env-integer-required output: ###", + "--env-integer-required", + "321", + "### --integer-list output: ###", "### --string output: ###", "### --string-with-default output: ###", "--string-with-default", "123", + "### --string-with-undocumented-synonym output: ###", + "### --string-list output: ###", +] +`; + +exports[`CommandLineParameterBase parses each parameter from an environment variable 1`] = ` +Array [ + "### --choice output: ###", + "--choice", + "one", + "### --choice-with-default output: ###", + "--choice-with-default", + "two", + "### --choice-list output: ###", + "--choice-list", + "red", + "--choice-list", + "green", + "### --flag output: ###", + "--flag", + "### --integer output: ###", + "--integer", + "111", + "### --integer-with-default output: ###", + "--integer-with-default", + "222", + "### --integer-required output: ###", + "--integer-required", + "1", + "### --env-integer-required output: ###", + "--env-integer-required", + "333", + "### --integer-list output: ###", + "--integer-list", + "1", + "--integer-list", + "2", + "--integer-list", + "3", + "### --string output: ###", + "--string", + "Hello, world!", + "### --string-with-default output: ###", + "--string-with-default", + "Hello, world!", + "### --string-with-undocumented-synonym output: ###", "### --string-list output: ###", + "--string-list", + "simple text", + "### --json-string-list output: ###", + "--json-string-list", + "1", + "--json-string-list", + "true", + "--json-string-list", + "Hello, world!", ] `; -exports[`CommandLineParameter prints the action help 1`] = ` +exports[`CommandLineParameterBase prints the same usage if a required parameter backed by an env variable is not provided as when a different required parameter is missing: Usage 1`] = ` "usage: example do:the-job [-h] [-c {one,two,three,default}] - [--choice-with-default {one,two,three,default}] [-f] - [-i NUMBER] [--integer-with-default NUMBER] - --integer-required NUMBER [-s TEXT] - [--string-with-default TEXT] [-l LIST] + [--choice-with-default {one,two,three,default}] + [-C {red,green,blue}] [-f] [-i NUMBER] + [--integer-with-default NUMBER] --integer-required + NUMBER --env-integer-required NUMBER [-I LIST_ITEM] + [-s TEXT] [--string-with-default TEXT] + [--string-with-undocumented-synonym TEXT] + [-l LIST_ITEM] + +" +`; + +exports[`CommandLineParameterBase raises an error if a required parameter backed by an env variable is not provided: Error 1`] = ` +[Error: example do:the-job: error: Argument "--env-integer-required" is required +] +`; + +exports[`CommandLineParameterBase raises an error if a required parameter backed by an env variable is not provided: Usage 1`] = ` +"usage: example do:the-job [-h] [-c {one,two,three,default}] + [--choice-with-default {one,two,three,default}] + [-C {red,green,blue}] [-f] [-i NUMBER] + [--integer-with-default NUMBER] --integer-required + NUMBER --env-integer-required NUMBER [-I LIST_ITEM] + [-s TEXT] [--string-with-default TEXT] + [--string-with-undocumented-synonym TEXT] + [-l LIST_ITEM] + +" +`; + +exports[`CommandLineParameterBase renders help text: do:the-job 1`] = ` +"usage: example do:the-job [-h] [-c {one,two,three,default}] + [--choice-with-default {one,two,three,default}] + [-C {red,green,blue}] [-f] [-i NUMBER] + [--integer-with-default NUMBER] --integer-required + NUMBER --env-integer-required NUMBER [-I LIST_ITEM] + [-s TEXT] [--string-with-default TEXT] + [--string-with-undocumented-synonym TEXT] + [-l LIST_ITEM] a longer description @@ -371,37 +579,56 @@ a longer description Optional arguments: -h, --help Show this help message and exit. -c {one,two,three,default}, --choice {one,two,three,default} - A choice. This parameter may alternatively specified - via the ENV_CHOICE environment variable. + A choice. This parameter may alternatively be + specified via the ENV_CHOICE environment variable. --choice-with-default {one,two,three,default} - A choice with a default. This parameter may - alternatively specified via the ENV_CHOICE - environment variable. The default value is \\"default\\". - -f, --flag A flag. This parameter may alternatively specified + A choice with a default. This description ends with a + \\"quoted word\\". This parameter may alternatively be + specified via the ENV_CHOICE2 environment variable. + The default value is \\"default\\". + -C {red,green,blue}, --choice-list {red,green,blue} + This parameter may be specified multiple times to + make a list of choices. This parameter may + alternatively be specified via the ENV_CHOICE_LIST + environment variable. + -f, --flag A flag. This parameter may alternatively be specified via the ENV_FLAG environment variable. -i NUMBER, --integer NUMBER - An integer. This parameter may alternatively + An integer. This parameter may alternatively be specified via the ENV_INTEGER environment variable. --integer-with-default NUMBER An integer with a default. This parameter may - alternatively specified via the ENV_INTEGER + alternatively be specified via the ENV_INTEGER2 environment variable. The default value is 123. --integer-required NUMBER An integer + --env-integer-required NUMBER + An integer. This parameter may alternatively be + specified via the ENV_INTEGER_REQUIRED environment + variable. + -I LIST_ITEM, --integer-list LIST_ITEM + This parameter may be specified multiple times to + make a list of integers. This parameter may + alternatively be specified via the ENV_INTEGER_LIST + environment variable. -s TEXT, --string TEXT - A string. This parameter may alternatively specified - via the ENV_INTEGER environment variable. + A string. This parameter may alternatively be + specified via the ENV_STRING environment variable. --string-with-default TEXT A string with a default. This parameter may - alternatively specified via the ENV_INTEGER + alternatively be specified via the ENV_STRING2 environment variable. The default value is \\"123\\". - -l LIST, --string-list LIST - A string list. This parameter may alternatively - specified via the ENV_INTEGER environment variable. + --string-with-undocumented-synonym TEXT + A string with an undocumented synonym + -l LIST_ITEM, --string-list LIST_ITEM + This parameter may be specified multiple times to + make a list of strings. This parameter may + alternatively be specified via the ENV_STRING_LIST + environment variable. " `; -exports[`CommandLineParameter prints the global help 1`] = ` +exports[`CommandLineParameterBase renders help text: global help 1`] = ` "usage: example [-h] [-g] ... An example project @@ -414,6 +641,6 @@ Optional arguments: -h, --help Show this help message and exit. -g, --global-flag A flag that affects all actions -For detailed help about a specific command, use: example -h +[bold]For detailed help about a specific command, use: example -h[normal] " `; diff --git a/libraries/ts-command-line/src/test/__snapshots__/CommandLineParser.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/CommandLineParser.test.ts.snap new file mode 100644 index 00000000000..efee07961d0 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/CommandLineParser.test.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommandLineParser renders help text: do:the-job 1`] = ` +"usage: example do:the-job [-h] [--flag] + +a longer description with sprintf-style escape characters, 100% + +Optional arguments: + -h, --help Show this help message and exit. + --flag The flag +" +`; + +exports[`CommandLineParser renders help text: global help 1`] = ` +"usage: example [-h] ... + +An example project with sprintf-style escape characters, 100% + +Positional arguments: + + do:the-job + does the job with sprintf-style escape characters, 100% + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/CommandLineRemainder.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/CommandLineRemainder.test.ts.snap new file mode 100644 index 00000000000..9205cbc2f2f --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/CommandLineRemainder.test.ts.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommandLineRemainder parses an action input with remainder 1`] = ` +Array [ + "### --title output: ###", + "--title", + "The title", + "### remainder output: ###", + "the", + "remaining", + "args", +] +`; + +exports[`CommandLineRemainder parses an action input with remainder flagged options 1`] = ` +Array [ + "### --title output: ###", + "--title", + "The title", + "### remainder output: ###", + "--", + "--the", + "remaining", + "--args", +] +`; + +exports[`CommandLineRemainder renders help text: global help 1`] = ` +"usage: example [-h] [--verbose] ... + +An example project + +Positional arguments: + + run does the job + +Optional arguments: + -h, --help Show this help message and exit. + --verbose A flag that affects all actions + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; + +exports[`CommandLineRemainder renders help text: run 1`] = ` +"usage: example run [-h] [--title TEXT] ... + +a longer description + +Positional arguments: + \\"...\\" The action remainder + +Optional arguments: + -h, --help Show this help message and exit. + --title TEXT A string +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/ConflictingCommandLineParser.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/ConflictingCommandLineParser.test.ts.snap new file mode 100644 index 00000000000..0a3e4c493a6 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/ConflictingCommandLineParser.test.ts.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Conflicting CommandLineParser executes an action 1`] = ` +"usage: example do:the-job [-h] [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope3:non-conflicting-arg ARG + The argument +" +`; + +exports[`Conflicting CommandLineParser executes an action 2`] = ` +Object { + "--scope1:arg": "\\"scope1value\\"", + "--scope2:arg": "\\"scope2value\\"", + "--scope3:non-conflicting-arg": "\\"nonconflictingvalue\\"", +} +`; + +exports[`Conflicting CommandLineParser executes an action: do:the-job 1`] = ` +"usage: example do:the-job [-h] [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope3:non-conflicting-arg ARG + The argument +" +`; + +exports[`Conflicting CommandLineParser executes an action: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + do:the-job + does the job + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; + +exports[`Conflicting CommandLineParser parses the scope out of a long name correctly: do:the-job 1`] = ` +"usage: example do:the-job [-h] [--scope1:arg ARG] [--scope2:arg ARG] + [--non-conflicting-arg ARG] + + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --scope1:arg ARG The argument + --scope2:arg ARG The argument + --non-conflicting-arg ARG, --scope3:non-conflicting-arg ARG + The argument +" +`; + +exports[`Conflicting CommandLineParser parses the scope out of a long name correctly: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + do:the-job + does the job + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/DynamicCommandLineParser.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/DynamicCommandLineParser.test.ts.snap new file mode 100644 index 00000000000..3794c0f99bc --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/DynamicCommandLineParser.test.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DynamicCommandLineParser parses an action: do:the-job 1`] = ` +"usage: example do:the-job [-h] [--flag] + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --flag The flag +" +`; + +exports[`DynamicCommandLineParser parses an action: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + do:the-job + does the job + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/EndToEndTest.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/EndToEndTest.test.ts.snap new file mode 100644 index 00000000000..415691e7f28 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/EndToEndTest.test.ts.snap @@ -0,0 +1,174 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`end-to-end test execution tests push --force: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests push --force: process signal 1`] = `null`; + +exports[`end-to-end test execution tests push --force: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests push --force: process stdout 1`] = ` +"Business logic configured the logger: verbose=false +Received parameters: force=true, protocol=\\"scp\\" +Business logic did the work. +" +`; + +exports[`end-to-end test execution tests push --protocol bogus: process exit code 1`] = `2`; + +exports[`end-to-end test execution tests push --protocol bogus: process signal 1`] = `null`; + +exports[`end-to-end test execution tests push --protocol bogus: process stderr 1`] = ` +"widget push: error: argument \\"--protocol\\": Invalid choice: bogus (choose from [ftp, webdav, scp]) + +" +`; + +exports[`end-to-end test execution tests push --protocol bogus: process stdout 1`] = ` +"usage: widget push [-h] [-f] [--protocol {ftp,webdav,scp}] +" +`; + +exports[`end-to-end test execution tests push --protocol ftp: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests push --protocol ftp: process signal 1`] = `null`; + +exports[`end-to-end test execution tests push --protocol ftp: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests push --protocol ftp: process stdout 1`] = ` +"Business logic configured the logger: verbose=false +Received parameters: force=false, protocol=\\"ftp\\" +Business logic did the work. +" +`; + +exports[`end-to-end test execution tests push: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests push: process signal 1`] = `null`; + +exports[`end-to-end test execution tests push: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests push: process stdout 1`] = ` +"Business logic configured the logger: verbose=false +Received parameters: force=false, protocol=\\"scp\\" +Business logic did the work. +" +`; + +exports[`end-to-end test execution tests run --title My Title --remaining --args: process exit code 1`] = `2`; + +exports[`end-to-end test execution tests run --title My Title --remaining --args: process signal 1`] = `null`; + +exports[`end-to-end test execution tests run --title My Title --remaining --args: process stderr 1`] = ` +"widget run: error: Unrecognized arguments: --remaining --args. + +" +`; + +exports[`end-to-end test execution tests run --title My Title --remaining --args: process stdout 1`] = ` +"usage: widget run [-h] [--title TITLE] ... +" +`; + +exports[`end-to-end test execution tests run --title My Title: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests run --title My Title: process signal 1`] = `null`; + +exports[`end-to-end test execution tests run --title My Title: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests run --title My Title: process stdout 1`] = ` +"Business logic configured the logger: verbose=false +Console Title: My Title +Arguments to be executed: [] +" +`; + +exports[`end-to-end test execution tests run: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests run: process signal 1`] = `null`; + +exports[`end-to-end test execution tests run: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests run: process stdout 1`] = ` +"Business logic configured the logger: verbose=false +Console Title: (none) +Arguments to be executed: [] +" +`; + +exports[`end-to-end test execution tests with no args: process exit code 1`] = `0`; + +exports[`end-to-end test execution tests with no args: process signal 1`] = `null`; + +exports[`end-to-end test execution tests with no args: process stderr 1`] = `""`; + +exports[`end-to-end test execution tests with no args: process stdout 1`] = ` +"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 +" +`; + +exports[`end-to-end test prints the help: global help 1`] = ` +"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 + +[bold]For detailed help about a specific command, use: widget -h[normal] +" +`; + +exports[`end-to-end test prints the help: push 1`] = ` +"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 be specified via the WIDGET_PROTOCOL + environment variable. The default value is \\"scp\\". +" +`; + +exports[`end-to-end test prints the help: run 1`] = ` +"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 be specified via the + WIDGET_TITLE environment variable. +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/ScopedCommandLineAction.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/ScopedCommandLineAction.test.ts.snap new file mode 100644 index 00000000000..30828b18fb2 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/ScopedCommandLineAction.test.ts.snap @@ -0,0 +1,105 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CommandLineParser prints the action help 1`] = ` +"usage: example scoped-action [-h] [--verbose] [--scope SCOPE] ... + +a longer description + +Positional arguments: + \\"...\\" Scoped parameters. Must be prefixed with \\"--\\", ex. \\"-- + --scopedParameter foo --scopedFlag\\". For more information on + available scoped parameters, use \\"-- --help\\". + +Optional arguments: + -h, --help Show this help message and exit. + --verbose A flag parameter. + +Optional scoping arguments: + --scope SCOPE The scope +" +`; + +exports[`CommandLineParser prints the scoped action help 1`] = ` +"usage: example scoped-action --scope foo -- [-h] [--scoped-foo SCOPED] + +a longer description + +Optional arguments: + -h, --help Show this help message and exit. + --scoped-foo SCOPED The scoped argument. + +For more information on available unscoped parameters, use \\"example +scoped-action --help\\" +" +`; + +exports[`CommandLineParser prints the scoped action parameter map 1`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": undefined, + "--verbose": "false", +} +`; + +exports[`CommandLineParser prints the scoped action parameter map 2`] = ` +Object { + "--scope": "\\"foo\\"", + "--scoped-foo": "\\"bar\\"", + "--verbose": "false", +} +`; + +exports[`CommandLineParser prints the unscoped action parameter map 1`] = ` +Object { + "--scope": undefined, + "--verbose": "true", +} +`; + +exports[`CommandLineParser renders help text: global help 1`] = ` +"usage: example [-h] ... + +An example project + +Positional arguments: + + scoped-action + does the scoped action + +Optional arguments: + -h, --help Show this help message and exit. + +[bold]For detailed help about a specific command, use: example -h[normal] +" +`; + +exports[`CommandLineParser renders help text: scoped-action 1`] = ` +"usage: example scoped-action [-h] [--verbose] [--scope SCOPE] ... + +a longer description + +Positional arguments: + \\"...\\" Scoped parameters. Must be prefixed with \\"--\\", ex. \\"-- + --scopedParameter foo --scopedFlag\\". For more information on + available scoped parameters, use \\"-- --help\\". + +Optional arguments: + -h, --help Show this help message and exit. + --verbose A flag parameter. + +Optional scoping arguments: + --scope SCOPE The scope +" +`; + +exports[`CommandLineParser throws on missing positional arg divider with unknown positional args 1`] = ` +"usage: example scoped-action [-h] [--verbose] [--scope SCOPE] ... + +example scoped-action: error: Unrecognized arguments: bar. +" +`; + +exports[`CommandLineParser throws on unknown scoped arg 1`] = ` +"example scoped-action --scope foo --: error: Unrecognized arguments: --scoped-bar baz. +" +`; diff --git a/libraries/ts-command-line/src/test/__snapshots__/TabCompleteAction.test.ts.snap b/libraries/ts-command-line/src/test/__snapshots__/TabCompleteAction.test.ts.snap new file mode 100644 index 00000000000..37e7b568793 --- /dev/null +++ b/libraries/ts-command-line/src/test/__snapshots__/TabCompleteAction.test.ts.snap @@ -0,0 +1,136 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TabCompleteAction renders help text: add 1`] = ` +"usage: rush add [-h] -p PACKAGE [--exact] [--caret] [--dev] [-m] [-s] [--all] + +Adds a dependency to the package.json and runs rush update. + +Optional arguments: + -h, --help Show this help message and exit. + -p PACKAGE, --package PACKAGE + (Required) 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\\". + --exact If specified, the SemVer specifier added to the + package.json will be an exact version (e.g. without + tilde or caret). + --caret If specified, the SemVer specifier added to the + package.json will be a prepended with a \\"caret\\" + specifier (\\"^\\"). + --dev If specified, the package will be added to the + \\"devDependencies\\" section of the package.json + -m, --make-consistent + If specified, other packages with this dependency + will have their package.json files updated to use the + same version of the dependency. + -s, --skip-update If specified, the \\"rush update\\" command will not be + run after updating the package.json files. + --all If specified, the dependency will be added to all + projects. +" +`; + +exports[`TabCompleteAction renders help text: build 1`] = ` +"usage: rush build [-h] [-p COUNT] [-t PROJECT1] [-f PROJECT2] + +Build all projects that haven't been built. + +Optional arguments: + -h, --help Show this help message and exit. + -p COUNT, --parallelism COUNT + Specifies the maximum number of concurrent processes + to launch during a build. + -t PROJECT1, --to PROJECT1 + Run command in the specified project and all of its + dependencies. + -f PROJECT2, --from PROJECT2 + Run command in the specified project and all projects + that directly or indirectly depend on the specified + project. +" +`; + +exports[`TabCompleteAction renders help text: change 1`] = ` +"usage: rush change [-h] [-v] [--no-fetch] [-b BRANCH] [--overwrite] + [--email EMAIL] [--bulk] [--message MESSAGE] + [--bump-type {major,minor,patch,none}] + + +Asks a series of questions and then generates a -.json +file. + +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 + --no-fetch Skips fetching the baseline branch before running + \\"git diff\\" to detect changes. + -b BRANCH, --target-branch BRANCH + If this parameter is specified, compare the checked + out branch with the specified branch. + --overwrite If a changefile already exists, overwrite without + prompting. + --email EMAIL The email address to use in changefiles. If this + parameter is not provided, the email address will be + detected or prompted for in interactive mode. + --bulk If this flag is specified, apply the same change + message and bump type to all changed projects. + --message MESSAGE The message to apply to all changed projects. + --bump-type {major,minor,patch,none} + The bump type to apply to all changed projects. +" +`; + +exports[`TabCompleteAction renders help text: global help 1`] = ` +"usage: rush [-h] [-d] ... + +Rush: a scalable monorepo manager for the web + +Positional arguments: + + add Adds a dependency to the package.json and runs rush update. + build Build all projects that haven't been built. + change Records changes made to projects, indicating how the package + version number should be bumped for the next publish. + install Install package dependencies for all projects in the repo + according to the shrinkwrap file. + +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 + +[bold]For detailed help about a specific command, use: rush -h[normal] +" +`; + +exports[`TabCompleteAction renders help text: install 1`] = ` +"usage: rush install [-h] [-p] [--bypass-policy] [--no-link] + [--network-concurrency COUNT] [--debug-package-manager] + [--max-install-attempts NUMBER] + + +Longer description: Install package dependencies for all projects in the repo +according to the shrinkwrap file. + +Optional arguments: + -h, --help Show this help message and exit. + -p, --purge Perform \\"rush purge\\" before starting the installation + --bypass-policy Overrides enforcement of the \\"gitPolicy\\" rules from + rush.json (use honorably!) + --no-link If \\"--no-link\\" is specified, then project symlinks + will NOT be created + --network-concurrency COUNT + If specified, limits the maximum number of concurrent + network requests. + --debug-package-manager + Activates verbose logging for the package manager. + --max-install-attempts NUMBER + Overrides the default maximum number of install + attempts. The default value is 3. +" +`; diff --git a/libraries/ts-command-line/src/test/helpTestUtilities.ts b/libraries/ts-command-line/src/test/helpTestUtilities.ts new file mode 100644 index 00000000000..8c7a9a59e86 --- /dev/null +++ b/libraries/ts-command-line/src/test/helpTestUtilities.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 { AnsiEscape } from '@rushstack/terminal'; + +import type { CommandLineParser } from '../providers/CommandLineParser'; + +export function ensureHelpTextMatchesSnapshot(parser: CommandLineParser): void { + const globalHelpText: string = AnsiEscape.formatForTests(parser.renderHelpText()); + expect(globalHelpText).toMatchSnapshot('global help'); + + for (const action of parser.actions) { + const actionHelpText: string = AnsiEscape.formatForTests(action.renderHelpText()); + expect(actionHelpText).toMatchSnapshot(action.actionName); + } +} diff --git a/libraries/ts-command-line/src/test/test-cli/BusinessLogic.ts b/libraries/ts-command-line/src/test/test-cli/BusinessLogic.ts new file mode 100644 index 00000000000..ae3d1e7e52f --- /dev/null +++ b/libraries/ts-command-line/src/test/test-cli/BusinessLogic.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. + +export class BusinessLogic { + public static async doTheWorkAsync(force: boolean, protocol: string): Promise { + // eslint-disable-next-line no-console + console.log(`Received parameters: force=${force}, protocol="${protocol}"`); + // eslint-disable-next-line no-console + console.log(`Business logic did the work.`); + } + + public static configureLogger(verbose: boolean): void { + // eslint-disable-next-line no-console + console.log(`Business logic configured the logger: verbose=${verbose}`); + } +} diff --git a/libraries/ts-command-line/src/test/test-cli/PushAction.ts b/libraries/ts-command-line/src/test/test-cli/PushAction.ts new file mode 100644 index 00000000000..7d10156b368 --- /dev/null +++ b/libraries/ts-command-line/src/test/test-cli/PushAction.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 CommandLineFlagParameter, + CommandLineAction, + type IRequiredCommandLineChoiceParameter +} from '../../index'; + +import { BusinessLogic } from './BusinessLogic'; + +type Protocol = 'ftp' | 'webdav' | 'scp'; + +export class PushAction extends CommandLineAction { + private readonly _force: CommandLineFlagParameter; + private readonly _protocol: IRequiredCommandLineChoiceParameter; + + public constructor() { + super({ + actionName: 'push', + summary: 'Pushes a widget to the service', + documentation: 'Here we provide a longer description of how our action works.' + }); + + this._force = this.defineFlagParameter({ + parameterLongName: '--force', + parameterShortName: '-f', + description: 'Push and overwrite any existing state' + }); + + this._protocol = this.defineChoiceParameter({ + parameterLongName: '--protocol', + description: 'Specify the protocol to use', + alternatives: ['ftp', 'webdav', 'scp'], + environmentVariable: 'WIDGET_PROTOCOL', + defaultValue: 'scp' + }); + } + + protected onExecuteAsync(): Promise { + // abstract + return BusinessLogic.doTheWorkAsync(this._force.value, this._protocol.value); + } +} diff --git a/libraries/ts-command-line/src/test/test-cli/RunAction.ts b/libraries/ts-command-line/src/test/test-cli/RunAction.ts new file mode 100644 index 00000000000..00a6e22c4ff --- /dev/null +++ b/libraries/ts-command-line/src/test/test-cli/RunAction.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 { CommandLineAction, type CommandLineStringParameter } from '../../index'; + +export class RunAction extends CommandLineAction { + private readonly _title: CommandLineStringParameter; + + public constructor() { + super({ + actionName: 'run', + summary: 'This action (hypothetically) passes its command line arguments to the shell to be executed.', + documentation: 'This demonstrates how to use the defineCommandLineRemainder() API.' + }); + + this._title = this.defineStringParameter({ + parameterLongName: '--title', + argumentName: 'TITLE', + environmentVariable: 'WIDGET_TITLE', + description: 'An optional title to show in the console window' + }); + + this.defineCommandLineRemainder({ + description: 'The remaining arguments are passed along to the command shell.' + }); + } + + protected override async onExecuteAsync(): Promise { + // abstract + // eslint-disable-next-line no-console + console.log(`Console Title: ${this._title.value || '(none)'}`); + // eslint-disable-next-line no-console + console.log('Arguments to be executed: ' + JSON.stringify(this.remainder!.values)); + } +} diff --git a/libraries/ts-command-line/src/test/test-cli/WidgetCommandLine.ts b/libraries/ts-command-line/src/test/test-cli/WidgetCommandLine.ts new file mode 100644 index 00000000000..192814b952f --- /dev/null +++ b/libraries/ts-command-line/src/test/test-cli/WidgetCommandLine.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CommandLineParser, type CommandLineFlagParameter } from '../../index'; + +import { PushAction } from './PushAction'; +import { RunAction } from './RunAction'; +import { BusinessLogic } from './BusinessLogic'; + +export class WidgetCommandLine extends CommandLineParser { + private readonly _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()); + + this._verbose = this.defineFlagParameter({ + parameterLongName: '--verbose', + parameterShortName: '-v', + description: 'Show extra logging detail' + }); + } + + protected override async onExecuteAsync(): Promise { + BusinessLogic.configureLogger(this._verbose.value); + return await super.onExecuteAsync(); + } +} diff --git a/libraries/ts-command-line/src/test/test-cli/start.ts b/libraries/ts-command-line/src/test/test-cli/start.ts new file mode 100644 index 00000000000..1dbc40535a3 --- /dev/null +++ b/libraries/ts-command-line/src/test/test-cli/start.ts @@ -0,0 +1,11 @@ +// 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().catch((error: Error) => { + // eslint-disable-next-line no-console + console.error(error.message); + process.exitCode = 1; +}); diff --git a/libraries/ts-command-line/tsconfig.json b/libraries/ts-command-line/tsconfig.json index 824a88b71e5..7b03eaec26f 100644 --- a/libraries/ts-command-line/tsconfig.json +++ b/libraries/ts-command-line/tsconfig.json @@ -1,10 +1,8 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "types": [ - "jest", - "node" - ] + // TODO: Remove when the repo is updated to ES2020 + "target": "es2018" } } diff --git a/libraries/typings-generator/.eslintrc.js b/libraries/typings-generator/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/libraries/typings-generator/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/libraries/typings-generator/.npmignore b/libraries/typings-generator/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/libraries/typings-generator/.npmignore +++ b/libraries/typings-generator/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/typings-generator/CHANGELOG.json b/libraries/typings-generator/CHANGELOG.json index 8c90797f754..b39bbbdf07f 100644 --- a/libraries/typings-generator/CHANGELOG.json +++ b/libraries/typings-generator/CHANGELOG.json @@ -1,6 +1,5480 @@ { "name": "@rushstack/typings-generator", "entries": [ + { + "version": "0.15.7", + "tag": "@rushstack/typings-generator_v0.15.7", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/typings-generator_v0.15.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": "0.15.5", + "tag": "@rushstack/typings-generator_v0.15.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/typings-generator_v0.15.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/typings-generator_v0.15.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": "0.15.2", + "tag": "@rushstack/typings-generator_v0.15.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": "0.15.1", + "tag": "@rushstack/typings-generator_v0.15.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/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/typings-generator_v0.15.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/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.14.47", + "tag": "@rushstack/typings-generator_v0.14.47", + "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": "0.14.46", + "tag": "@rushstack/typings-generator_v0.14.46", + "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`" + } + ] + } + }, + { + "version": "0.14.45", + "tag": "@rushstack/typings-generator_v0.14.45", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.14.44", + "tag": "@rushstack/typings-generator_v0.14.44", + "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": "0.14.43", + "tag": "@rushstack/typings-generator_v0.14.43", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.14.42", + "tag": "@rushstack/typings-generator_v0.14.42", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.14.41", + "tag": "@rushstack/typings-generator_v0.14.41", + "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`" + } + ] + } + }, + { + "version": "0.14.40", + "tag": "@rushstack/typings-generator_v0.14.40", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.14.39", + "tag": "@rushstack/typings-generator_v0.14.39", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.14.38", + "tag": "@rushstack/typings-generator_v0.14.38", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.14.37", + "tag": "@rushstack/typings-generator_v0.14.37", + "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": "0.14.36", + "tag": "@rushstack/typings-generator_v0.14.36", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.14.35", + "tag": "@rushstack/typings-generator_v0.14.35", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.14.34", + "tag": "@rushstack/typings-generator_v0.14.34", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.14.33", + "tag": "@rushstack/typings-generator_v0.14.33", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.14.32", + "tag": "@rushstack/typings-generator_v0.14.32", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.14.31", + "tag": "@rushstack/typings-generator_v0.14.31", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.14.30", + "tag": "@rushstack/typings-generator_v0.14.30", + "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/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.14.29", + "tag": "@rushstack/typings-generator_v0.14.29", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.14.28", + "tag": "@rushstack/typings-generator_v0.14.28", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.14.27", + "tag": "@rushstack/typings-generator_v0.14.27", + "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/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.14.26", + "tag": "@rushstack/typings-generator_v0.14.26", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.14.25", + "tag": "@rushstack/typings-generator_v0.14.25", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.14.24", + "tag": "@rushstack/typings-generator_v0.14.24", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.14.23", + "tag": "@rushstack/typings-generator_v0.14.23", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.14.22", + "tag": "@rushstack/typings-generator_v0.14.22", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.14.21", + "tag": "@rushstack/typings-generator_v0.14.21", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.14.20", + "tag": "@rushstack/typings-generator_v0.14.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/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.14.19", + "tag": "@rushstack/typings-generator_v0.14.19", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.14.18", + "tag": "@rushstack/typings-generator_v0.14.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/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.14.17", + "tag": "@rushstack/typings-generator_v0.14.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/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.14.16", + "tag": "@rushstack/typings-generator_v0.14.16", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.14.15", + "tag": "@rushstack/typings-generator_v0.14.15", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.14.14", + "tag": "@rushstack/typings-generator_v0.14.14", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/typings-generator_v0.14.13", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/typings-generator_v0.14.12", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/typings-generator_v0.14.11", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/typings-generator_v0.14.10", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/typings-generator_v0.14.9", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/typings-generator_v0.14.8", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/typings-generator_v0.14.7", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/typings-generator_v0.14.6", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/typings-generator_v0.14.5", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/typings-generator_v0.14.4", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/typings-generator_v0.14.3", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "patch": [ + { + "comment": "Fix reference to terminal documentation in README" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/typings-generator_v0.14.2", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/typings-generator_v0.14.1", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/typings-generator_v0.14.0", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value." + }, + { + "comment": "Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`." + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/typings-generator_v0.13.0", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "minor": [ + { + "comment": "Expand the `exportAsDefault` option for `StringValuesTypingsGenerator` to take an object with the following properties: `interfaceName` and `documentationComment`. Note that the `exportAsDefaultInterfaceName` option has been deprecated." + }, + { + "comment": "Add an optional `exportAsDefault` property to the return value of `parseAndGenerateTypings` that overrides options provided by the same property in the `StringValuesTypingsGenerator`'s options object." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.12.63", + "tag": "@rushstack/typings-generator_v0.12.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.12.62", + "tag": "@rushstack/typings-generator_v0.12.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.12.61", + "tag": "@rushstack/typings-generator_v0.12.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.12.60", + "tag": "@rushstack/typings-generator_v0.12.60", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.12.59", + "tag": "@rushstack/typings-generator_v0.12.59", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.12.58", + "tag": "@rushstack/typings-generator_v0.12.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.12.57", + "tag": "@rushstack/typings-generator_v0.12.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.12.56", + "tag": "@rushstack/typings-generator_v0.12.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.12.55", + "tag": "@rushstack/typings-generator_v0.12.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.12.54", + "tag": "@rushstack/typings-generator_v0.12.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.12.53", + "tag": "@rushstack/typings-generator_v0.12.53", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.12.52", + "tag": "@rushstack/typings-generator_v0.12.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.12.51", + "tag": "@rushstack/typings-generator_v0.12.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.12.50", + "tag": "@rushstack/typings-generator_v0.12.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.12.49", + "tag": "@rushstack/typings-generator_v0.12.49", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.12.48", + "tag": "@rushstack/typings-generator_v0.12.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.12.47", + "tag": "@rushstack/typings-generator_v0.12.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.12.46", + "tag": "@rushstack/typings-generator_v0.12.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.12.45", + "tag": "@rushstack/typings-generator_v0.12.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.12.44", + "tag": "@rushstack/typings-generator_v0.12.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.12.43", + "tag": "@rushstack/typings-generator_v0.12.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.12.42", + "tag": "@rushstack/typings-generator_v0.12.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.12.41", + "tag": "@rushstack/typings-generator_v0.12.41", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.12.40", + "tag": "@rushstack/typings-generator_v0.12.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.12.39", + "tag": "@rushstack/typings-generator_v0.12.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.12.38", + "tag": "@rushstack/typings-generator_v0.12.38", + "date": "Fri, 15 Mar 2024 00:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.12.37", + "tag": "@rushstack/typings-generator_v0.12.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.12.36", + "tag": "@rushstack/typings-generator_v0.12.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.12.35", + "tag": "@rushstack/typings-generator_v0.12.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.12.34", + "tag": "@rushstack/typings-generator_v0.12.34", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.12.33", + "tag": "@rushstack/typings-generator_v0.12.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.12.32", + "tag": "@rushstack/typings-generator_v0.12.32", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.12.31", + "tag": "@rushstack/typings-generator_v0.12.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.12.30", + "tag": "@rushstack/typings-generator_v0.12.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.12.29", + "tag": "@rushstack/typings-generator_v0.12.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.12.28", + "tag": "@rushstack/typings-generator_v0.12.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.12.27", + "tag": "@rushstack/typings-generator_v0.12.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.12.26", + "tag": "@rushstack/typings-generator_v0.12.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.12.25", + "tag": "@rushstack/typings-generator_v0.12.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.12.24", + "tag": "@rushstack/typings-generator_v0.12.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.12.23", + "tag": "@rushstack/typings-generator_v0.12.23", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.12.22", + "tag": "@rushstack/typings-generator_v0.12.22", + "date": "Wed, 07 Feb 2024 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.12.21", + "tag": "@rushstack/typings-generator_v0.12.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.12.20", + "tag": "@rushstack/typings-generator_v0.12.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.12.19", + "tag": "@rushstack/typings-generator_v0.12.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.12.18", + "tag": "@rushstack/typings-generator_v0.12.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.12.17", + "tag": "@rushstack/typings-generator_v0.12.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.12.16", + "tag": "@rushstack/typings-generator_v0.12.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.12.15", + "tag": "@rushstack/typings-generator_v0.12.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/typings-generator_v0.12.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/typings-generator_v0.12.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/typings-generator_v0.12.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/typings-generator_v0.12.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/typings-generator_v0.12.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/typings-generator_v0.12.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/typings-generator_v0.12.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/typings-generator_v0.12.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/typings-generator_v0.12.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/typings-generator_v0.12.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/typings-generator_v0.12.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/typings-generator_v0.12.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/typings-generator_v0.12.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/typings-generator_v0.12.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/typings-generator_v0.12.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/typings-generator_v0.11.1", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/typings-generator_v0.11.0", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "minor": [ + { + "comment": "Allow customization of how the TypingsGenerator reads files." + } + ] + } + }, + { + "version": "0.10.37", + "tag": "@rushstack/typings-generator_v0.10.37", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "patch": [ + { + "comment": "Switch from glob to fast-glob." + } + ] + } + }, + { + "version": "0.10.36", + "tag": "@rushstack/typings-generator_v0.10.36", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.10.35", + "tag": "@rushstack/typings-generator_v0.10.35", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.10.34", + "tag": "@rushstack/typings-generator_v0.10.34", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.10.33", + "tag": "@rushstack/typings-generator_v0.10.33", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.10.32", + "tag": "@rushstack/typings-generator_v0.10.32", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.10.31", + "tag": "@rushstack/typings-generator_v0.10.31", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.10.30", + "tag": "@rushstack/typings-generator_v0.10.30", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.10.29", + "tag": "@rushstack/typings-generator_v0.10.29", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.10.28", + "tag": "@rushstack/typings-generator_v0.10.28", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.10.27", + "tag": "@rushstack/typings-generator_v0.10.27", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.10.26", + "tag": "@rushstack/typings-generator_v0.10.26", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.10.25", + "tag": "@rushstack/typings-generator_v0.10.25", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.10.24", + "tag": "@rushstack/typings-generator_v0.10.24", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.10.23", + "tag": "@rushstack/typings-generator_v0.10.23", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.10.22", + "tag": "@rushstack/typings-generator_v0.10.22", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/typings-generator_v0.10.21", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/typings-generator_v0.10.20", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/typings-generator_v0.10.19", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/typings-generator_v0.10.18", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/typings-generator_v0.10.17", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/typings-generator_v0.10.16", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/typings-generator_v0.10.15", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/typings-generator_v0.10.14", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/typings-generator_v0.10.13", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/typings-generator_v0.10.12", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/typings-generator_v0.10.11", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/typings-generator_v0.10.10", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/typings-generator_v0.10.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/typings-generator_v0.10.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/typings-generator_v0.10.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/typings-generator_v0.10.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/typings-generator_v0.10.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/typings-generator_v0.10.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/typings-generator_v0.10.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/typings-generator_v0.10.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/typings-generator_v0.10.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/typings-generator_v0.10.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/typings-generator_v0.9.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.8.18", + "tag": "@rushstack/typings-generator_v0.8.18", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.8.17", + "tag": "@rushstack/typings-generator_v0.8.17", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.8.16", + "tag": "@rushstack/typings-generator_v0.8.16", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.8.15", + "tag": "@rushstack/typings-generator_v0.8.15", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/typings-generator_v0.8.14", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/typings-generator_v0.8.13", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/typings-generator_v0.8.12", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "patch": [ + { + "comment": "Add a check to ensure that relative paths passed to generateTypingsAsync and getOutputFilePaths are actually relative." + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/typings-generator_v0.8.11", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/typings-generator_v0.8.10", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/typings-generator_v0.8.9", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/typings-generator_v0.8.8", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/typings-generator_v0.8.7", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/typings-generator_v0.8.6", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/typings-generator_v0.8.5", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/typings-generator_v0.8.4", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/typings-generator_v0.8.3", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/typings-generator_v0.8.2", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/typings-generator_v0.8.1", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/typings-generator_v0.8.0", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "minor": [ + { + "comment": "Expose the \"ignoredFileGlobs,\" \"inputFileGlob,\" and \"sourceFolderPath\" properties." + }, + { + "comment": "Add an optional parameter to the `TypingsGenerator.generateTypingsAsync` function allowing the paths of files for which typings will be generated to be provided." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.7.23", + "tag": "@rushstack/typings-generator_v0.7.23", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.7.22", + "tag": "@rushstack/typings-generator_v0.7.22", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.7.21", + "tag": "@rushstack/typings-generator_v0.7.21", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.7.20", + "tag": "@rushstack/typings-generator_v0.7.20", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.7.19", + "tag": "@rushstack/typings-generator_v0.7.19", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/typings-generator_v0.7.18", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/typings-generator_v0.7.17", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/typings-generator_v0.7.16", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/typings-generator_v0.7.15", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/typings-generator_v0.7.14", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/typings-generator_v0.7.13", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/typings-generator_v0.7.12", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/typings-generator_v0.7.11", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/typings-generator_v0.7.10", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/typings-generator_v0.7.9", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/typings-generator_v0.7.8", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/typings-generator_v0.7.7", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/typings-generator_v0.7.6", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/typings-generator_v0.7.5", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/typings-generator_v0.7.4", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/typings-generator_v0.7.3", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/typings-generator_v0.7.2", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/typings-generator_v0.7.1", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/typings-generator_v0.7.0", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to output typings to additional output folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.6.30", + "tag": "@rushstack/typings-generator_v0.6.30", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.6.29", + "tag": "@rushstack/typings-generator_v0.6.29", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.6.28", + "tag": "@rushstack/typings-generator_v0.6.28", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.6.27", + "tag": "@rushstack/typings-generator_v0.6.27", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.6.26", + "tag": "@rushstack/typings-generator_v0.6.26", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.6.25", + "tag": "@rushstack/typings-generator_v0.6.25", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.6.24", + "tag": "@rushstack/typings-generator_v0.6.24", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "0.6.23", + "tag": "@rushstack/typings-generator_v0.6.23", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "0.6.22", + "tag": "@rushstack/typings-generator_v0.6.22", + "date": "Tue, 10 May 2022 01:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "0.6.21", + "tag": "@rushstack/typings-generator_v0.6.21", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "0.6.20", + "tag": "@rushstack/typings-generator_v0.6.20", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.6.19", + "tag": "@rushstack/typings-generator_v0.6.19", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "0.6.18", + "tag": "@rushstack/typings-generator_v0.6.18", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "0.6.17", + "tag": "@rushstack/typings-generator_v0.6.17", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "0.6.16", + "tag": "@rushstack/typings-generator_v0.6.16", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "0.6.15", + "tag": "@rushstack/typings-generator_v0.6.15", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/typings-generator_v0.6.14", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/typings-generator_v0.6.13", + "date": "Sat, 09 Apr 2022 02:24:27 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/typings-generator_v0.6.12", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/typings-generator_v0.6.11", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/typings-generator_v0.6.10", + "date": "Thu, 31 Mar 2022 02:06:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/typings-generator_v0.6.9", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/typings-generator_v0.6.8", + "date": "Tue, 15 Mar 2022 19:15:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/typings-generator_v0.6.7", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/typings-generator_v0.6.6", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/typings-generator_v0.6.5", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/typings-generator_v0.6.4", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/typings-generator_v0.6.3", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/typings-generator_v0.6.2", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/typings-generator_v0.6.1", + "date": "Tue, 14 Dec 2021 19:27:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/typings-generator_v0.6.0", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "minor": [ + { + "comment": "Support additional output files beyond the typings files." + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/typings-generator_v0.5.7", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/typings-generator_v0.5.6", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/typings-generator_v0.5.5", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/typings-generator_v0.5.4", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/typings-generator_v0.5.3", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/typings-generator_v0.5.2", + "date": "Fri, 03 Dec 2021 03:05:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/typings-generator_v0.5.1", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/typings-generator_v0.5.0", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove \"filesToIgnore\" option in favor of \"globsToIgnore.\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/typings-generator_v0.4.6", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/typings-generator_v0.4.5", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/typings-generator_v0.4.4", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/typings-generator_v0.4.3", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/typings-generator_v0.4.2", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/typings-generator_v0.4.1", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/typings-generator_v0.4.0", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/typings-generator_v0.3.13", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/typings-generator_v0.3.12", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/typings-generator_v0.3.11", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/typings-generator_v0.3.10", + "date": "Mon, 13 Sep 2021 15:07:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/typings-generator_v0.3.9", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/typings-generator_v0.3.8", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/typings-generator_v0.3.7", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/typings-generator_v0.3.6", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/typings-generator_v0.3.5", + "date": "Mon, 03 May 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/typings-generator_v0.3.4", + "date": "Mon, 12 Apr 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/typings-generator_v0.3.3", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/typings-generator_v0.3.2", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug where watched files would not honor typings generation excludeFiles settings" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/typings-generator_v0.3.1", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/typings-generator_v0.3.0", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "minor": [ + { + "comment": "Do not empty typings folder when running in watch mode." + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/typings-generator_v0.2.32", + "date": "Thu, 10 Dec 2020 23:25:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/typings-generator_v0.2.31", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.15`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/typings-generator_v0.2.30", + "date": "Mon, 30 Nov 2020 16:11:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.14`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/typings-generator_v0.2.29", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.13`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/typings-generator_v0.2.28", + "date": "Wed, 18 Nov 2020 06:21:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.12`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/typings-generator_v0.2.27", + "date": "Fri, 13 Nov 2020 01:11:00 GMT", + "comments": { + "patch": [ + { + "comment": "Add register dependency feature for typings generation. " + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/typings-generator_v0.2.26", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/typings-generator_v0.2.25", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.10`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/typings-generator_v0.2.24", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/typings-generator_v0.2.23", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/typings-generator_v0.2.22", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.7`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/typings-generator_v0.2.21", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/typings-generator_v0.2.20", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.5`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/typings-generator_v0.2.19", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "patch": [ + { + "comment": "Support `undefined` as a result from parseFileAndGenerateTypings." + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/typings-generator_v0.2.18", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/typings-generator_v0.2.17", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/typings-generator_v0.2.16", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/typings-generator_v0.2.15", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/typings-generator_v0.2.14", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/typings-generator_v0.2.13", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "patch": [ + { + "comment": "Handle export names with special chars in exportAsDefault interface keys." + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/typings-generator_v0.2.12", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/typings-generator_v0.2.11", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/typings-generator_v0.2.10", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/typings-generator_v0.2.9", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/typings-generator_v0.2.8", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/typings-generator_v0.2.7", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/typings-generator_v0.2.6", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/typings-generator_v0.2.5", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/typings-generator_v0.2.4", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/typings-generator_v0.2.3", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/typings-generator_v0.2.2", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/typings-generator_v0.2.1", + "date": "Mon, 14 Sep 2020 15:09:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/typings-generator_v0.2.0", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "minor": [ + { + "comment": "Change TypingsGenerator to support async methods. Typings generation now returns a promise." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/typings-generator_v0.1.52", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/typings-generator_v0.1.51", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/typings-generator_v0.1.50", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/typings-generator_v0.1.49", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/typings-generator_v0.1.48", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/typings-generator_v0.1.47", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/typings-generator_v0.1.46", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/typings-generator_v0.1.45", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/typings-generator_v0.1.44", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/typings-generator_v0.1.43", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/typings-generator_v0.1.42", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/typings-generator_v0.1.41", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/typings-generator_v0.1.40", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/typings-generator_v0.1.39", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/typings-generator_v0.1.38", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/typings-generator_v0.1.37", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/typings-generator_v0.1.36", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/typings-generator_v0.1.35", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/typings-generator_v0.1.34", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/typings-generator_v0.1.33", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/typings-generator_v0.1.32", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/typings-generator_v0.1.31", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "none": [ + { + "comment": "Add keywords to package.json for discoverability" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/typings-generator_v0.1.30", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/typings-generator_v0.1.29", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/typings-generator_v0.1.28", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/typings-generator_v0.1.27", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/typings-generator_v0.1.26", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/typings-generator_v0.1.25", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/typings-generator_v0.1.24", + "date": "Thu, 25 Jun 2020 06:43:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/typings-generator_v0.1.23", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/typings-generator_v0.1.22", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/typings-generator_v0.1.21", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/typings-generator_v0.1.20", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/typings-generator_v0.1.19", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/typings-generator_v0.1.18", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/typings-generator_v0.1.17", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/typings-generator_v0.1.16", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/typings-generator_v0.1.15", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/typings-generator_v0.1.14", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/typings-generator_v0.1.13", + "date": "Fri, 22 May 2020 15:08:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/typings-generator_v0.1.12", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/typings-generator_v0.1.11", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/typings-generator_v0.1.10", + "date": "Tue, 19 May 2020 15:08:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/typings-generator_v0.1.9", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/typings-generator_v0.1.8", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/typings-generator_v0.1.7", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/typings-generator_v0.1.6", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/typings-generator_v0.1.5", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/typings-generator_v0.1.4", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/typings-generator_v0.1.3", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "0.1.2", "tag": "@rushstack/typings-generator_v0.1.2", diff --git a/libraries/typings-generator/CHANGELOG.md b/libraries/typings-generator/CHANGELOG.md index d6439a498e9..362f7ab9e6a 100644 --- a/libraries/typings-generator/CHANGELOG.md +++ b/libraries/typings-generator/CHANGELOG.md @@ -1,11 +1,1816 @@ # Change Log - @rushstack/typings-generator -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.15.7 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.15.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.15.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.15.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.15.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.15.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.15.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.15.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.14.47 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.14.46 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.14.45 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.14.44 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.14.43 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.14.42 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.14.41 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.14.40 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.14.39 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.14.38 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.14.37 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.14.36 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.14.35 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.14.34 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.14.33 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.14.32 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.14.31 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.14.30 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.14.29 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.14.28 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.14.27 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.14.26 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.14.25 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.14.24 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.14.23 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.14.22 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.14.21 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.14.20 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.14.19 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.14.18 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.14.17 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.14.16 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.14.15 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.14.14 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.14.13 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.14.12 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.14.11 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.14.10 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.14.9 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.14.8 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.14.7 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.14.6 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.14.5 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.14.4 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.14.3 +Sat, 28 Sep 2024 00:11:41 GMT + +### Patches + +- Fix reference to terminal documentation in README + +## 0.14.2 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.14.1 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.14.0 +Mon, 26 Aug 2024 02:00:11 GMT + +### Minor changes + +- Add a `valueDocumentationComment` option to `exportAsDefault` that allows a documentation comment to be generated for the exported value. +- Rename the `documentationComment` property in the `exportAsDefault` value to `interfaceDocumentationComment`. + +## 0.13.0 +Wed, 21 Aug 2024 05:43:04 GMT + +### Minor changes + +- Expand the `exportAsDefault` option for `StringValuesTypingsGenerator` to take an object with the following properties: `interfaceName` and `documentationComment`. Note that the `exportAsDefaultInterfaceName` option has been deprecated. +- Add an optional `exportAsDefault` property to the return value of `parseAndGenerateTypings` that overrides options provided by the same property in the `StringValuesTypingsGenerator`'s options object. + +## 0.12.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.12.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.12.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.12.60 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.12.59 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.12.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.12.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.12.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.12.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.12.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.12.53 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.12.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.12.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.12.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.12.49 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.12.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.12.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.12.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.12.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.12.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.12.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.12.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.12.41 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.12.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.12.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.12.38 +Fri, 15 Mar 2024 00:12:41 GMT + +_Version update only_ + +## 0.12.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.12.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.12.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.12.34 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.12.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.12.32 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 0.12.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.12.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.12.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.12.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.12.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.12.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.12.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.12.24 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.12.23 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.12.22 +Wed, 07 Feb 2024 01:11:19 GMT + +_Version update only_ + +## 0.12.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.12.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.12.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.12.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.12.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.12.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.12.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.12.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.12.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.12.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.12.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.12.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.12.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.12.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.12.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.12.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.12.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.12.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.12.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.12.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.12.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.12.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.11.1 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.11.0 +Sat, 05 Aug 2023 00:20:19 GMT + +### Minor changes + +- Allow customization of how the TypingsGenerator reads files. + +## 0.10.37 +Fri, 04 Aug 2023 00:22:37 GMT + +### Patches + +- Switch from glob to fast-glob. + +## 0.10.36 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.10.35 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.10.34 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.10.33 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.10.32 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.10.31 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.10.30 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.10.29 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.10.28 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.10.27 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.10.26 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.10.25 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.10.24 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.10.23 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.10.22 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.10.21 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.10.20 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.10.19 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.10.18 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.10.17 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.10.16 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.10.15 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.10.14 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.10.13 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.10.12 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.10.11 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.10.10 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.10.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.10.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.10.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.10.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.10.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.10.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.10.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.10.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.10.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.10.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.9.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.8.18 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.8.17 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.8.16 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.8.15 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.8.14 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.8.13 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.8.12 +Thu, 01 Dec 2022 03:22:36 GMT + +### Patches + +- Add a check to ensure that relative paths passed to generateTypingsAsync and getOutputFilePaths are actually relative. + +## 0.8.11 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 0.8.10 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.8.9 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.8.8 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.8.7 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.8.6 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.8.5 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.8.4 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.8.3 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.8.2 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.8.1 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.8.0 +Wed, 21 Sep 2022 20:21:10 GMT + +### Minor changes + +- Expose the "ignoredFileGlobs," "inputFileGlob," and "sourceFolderPath" properties. +- Add an optional parameter to the `TypingsGenerator.generateTypingsAsync` function allowing the paths of files for which typings will be generated to be provided. + +## 0.7.23 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.7.22 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.7.21 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.7.20 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.7.19 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.7.18 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.7.17 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.7.16 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.7.15 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.7.14 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.7.13 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.7.12 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.7.11 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.7.10 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 0.7.9 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.7.8 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.7.7 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.7.6 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.7.5 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.7.4 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.7.3 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.7.2 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.7.1 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.7.0 +Sat, 25 Jun 2022 01:54:29 GMT + +### Minor changes + +- Add an option to output typings to additional output folders. + +## 0.6.30 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.6.29 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.6.28 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.6.27 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.6.26 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.6.25 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 0.6.24 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 0.6.23 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.6.22 +Tue, 10 May 2022 01:20:44 GMT + +_Version update only_ + +## 0.6.21 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.6.20 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.6.19 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.6.18 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.6.17 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.6.16 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.6.15 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.6.14 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.6.13 +Sat, 09 Apr 2022 02:24:27 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.6.12 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.6.11 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.6.10 +Thu, 31 Mar 2022 02:06:06 GMT + +_Version update only_ + +## 0.6.9 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.6.8 +Tue, 15 Mar 2022 19:15:54 GMT + +_Version update only_ + +## 0.6.7 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 0.6.6 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.6.5 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.6.4 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.6.3 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.6.2 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.6.1 +Tue, 14 Dec 2021 19:27:52 GMT + +_Version update only_ + +## 0.6.0 +Fri, 10 Dec 2021 01:09:33 GMT + +### Minor changes + +- Support additional output files beyond the typings files. + +## 0.5.7 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.5.6 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.5.5 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.5.4 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.5.3 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.5.2 +Fri, 03 Dec 2021 03:05:23 GMT + +_Version update only_ + +## 0.5.1 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.5.0 +Mon, 29 Nov 2021 07:26:16 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove "filesToIgnore" option in favor of "globsToIgnore." + +## 0.4.6 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.4.5 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.4.4 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.4.3 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.4.2 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.4.1 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.4.0 +Tue, 05 Oct 2021 15:08:38 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 0.3.13 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.3.12 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.3.11 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.3.10 +Mon, 13 Sep 2021 15:07:06 GMT + +_Version update only_ + +## 0.3.9 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.3.8 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.3.7 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.3.6 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.3.5 +Mon, 03 May 2021 15:10:29 GMT + +_Version update only_ + +## 0.3.4 +Mon, 12 Apr 2021 15:10:28 GMT + +_Version update only_ + +## 0.3.3 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.3.2 +Mon, 29 Mar 2021 05:02:06 GMT + +### Patches + +- Fix a bug where watched files would not honor typings generation excludeFiles settings + +## 0.3.1 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.3.0 +Wed, 06 Jan 2021 16:10:43 GMT + +### Minor changes + +- Do not empty typings folder when running in watch mode. + +## 0.2.32 +Thu, 10 Dec 2020 23:25:49 GMT + +_Version update only_ + +## 0.2.31 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.2.30 +Mon, 30 Nov 2020 16:11:49 GMT + +_Version update only_ + +## 0.2.29 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.2.28 +Wed, 18 Nov 2020 06:21:57 GMT + +_Version update only_ + +## 0.2.27 +Fri, 13 Nov 2020 01:11:00 GMT + +### Patches + +- Add register dependency feature for typings generation. + +## 0.2.26 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.2.25 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 0.2.24 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.2.23 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.2.22 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 0.2.21 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.2.20 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 0.2.19 +Sat, 24 Oct 2020 00:11:18 GMT + +### Patches + +- Support `undefined` as a result from parseFileAndGenerateTypings. + +## 0.2.18 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.2.17 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.2.16 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.2.15 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 0.2.14 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.2.13 +Thu, 01 Oct 2020 18:51:21 GMT + +### Patches + +- Handle export names with special chars in exportAsDefault interface keys. + +## 0.2.12 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.2.11 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 0.2.10 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.2.9 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.2.8 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.2.7 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.2.6 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.2.5 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.2.4 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 0.2.3 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 0.2.2 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 0.2.1 +Mon, 14 Sep 2020 15:09:49 GMT + +_Version update only_ + +## 0.2.0 +Sun, 13 Sep 2020 01:53:20 GMT + +### Minor changes + +- Change TypingsGenerator to support async methods. Typings generation now returns a promise. + +## 0.1.52 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.1.51 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 0.1.50 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 0.1.49 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 0.1.48 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 0.1.47 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 0.1.46 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 0.1.45 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 0.1.44 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 0.1.43 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 0.1.42 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 0.1.41 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 0.1.40 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 0.1.39 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 0.1.38 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 0.1.37 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 0.1.36 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 0.1.35 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 0.1.34 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 0.1.33 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 0.1.32 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 0.1.31 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 0.1.30 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 0.1.29 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 0.1.28 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 0.1.27 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 0.1.26 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 0.1.25 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 0.1.24 +Thu, 25 Jun 2020 06:43:34 GMT + +_Version update only_ + +## 0.1.23 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 0.1.22 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 0.1.21 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 0.1.20 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 0.1.19 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 0.1.18 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 0.1.17 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 0.1.16 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 0.1.15 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 0.1.14 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 0.1.13 +Fri, 22 May 2020 15:08:43 GMT + +_Version update only_ + +## 0.1.12 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 0.1.11 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 0.1.10 +Tue, 19 May 2020 15:08:19 GMT + +_Version update only_ + +## 0.1.9 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 0.1.8 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 0.1.7 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 0.1.6 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 0.1.5 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 0.1.4 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 0.1.3 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 0.1.2 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 0.1.1 Tue, 17 Mar 2020 23:55:58 GMT diff --git a/libraries/typings-generator/README.md b/libraries/typings-generator/README.md index f1e302b9a32..87323f8c6a6 100644 --- a/libraries/typings-generator/README.md +++ b/libraries/typings-generator/README.md @@ -1,4 +1,4 @@ -# Typings Generator +# @rushstack/typings-generator ## Installation @@ -27,10 +27,33 @@ const typingsGenerator: TypingsGenerator = new TypingsGenerator({ }); // To run once before a compilation: -typingsGenerator.generateTypings(); +await typingsGenerator.generateTypings(); // To start a watcher: -typingsGenerator.runWatcher(); +await typingsGenerator.runWatcher(); +``` + +```TypeScript +import { TypingsGenerator } from '@rushstack/typings-generator'; + +const assetTypingsGenerator: TypingsGenerator = new TypingsGenerator({ + srcFolder: '/repo/package/src', + generatedTsFolder: '/repo/package/temp/generated-typings', + fileExtensions: ['.jpg'], + parseAndGenerateTypings: (fileContents: false, filePath: string) => { + const parsedFile = parseFile(fileContents); + const typings: string = 'declare const path: string;\nexport default path;'; + return typings; + }, + // Don't read files at all + readFile: (filePath: string, relativePath: string) => false +}); + +// To run once before a compilation: +await typingsGenerator.generateTypings(); + +// To start a watcher: +await typingsGenerator.runWatcher(); ``` ## Options @@ -50,21 +73,29 @@ that this be a folder parallel to the source folder, specified in addition to th This property enumerates the file extensions that should be handled. -### `parseAndGenerateTypings = (fileContents: string, filePath: string) => string` +### `parseAndGenerateTypings = (fileContents: TFileContents, filePath: string, relativePath: string) => string | Promise` This property is used to specify the function that should be called on every file for which typings are being generated. In watch mode, this is called on every file creation and file update. It should return TypeScript declarations for the file it is called with. +### `readFile = (filePath: string, relativePath: string) => TFileContents | Promise` + +This property allows customizing the process by which files are read from the specified paths. +Use cases include: +- Disabling reads altogether, if the typings don't depend on file content +- Reading from an alternate data source +- Reading files with a different encoding than 'utf-8' + ### `terminal` -Optionally provide a [Terminal](https://github.com/microsoft/rushstack/blob/master/libraries/node-core-library/src/Terminal/Terminal.ts) -object for logging. If one isn't provided, logs will go to the terminal. +Optionally provide a [Terminal](https://github.com/microsoft/rushstack/blob/main/libraries/terminal/src/Terminal.ts) +object for logging. If one isn't provided, logs will go to the console. -### `filesToIgnore` +### `globsToIgnore` -Optionally, provide an array of paths to files that should be ignored. These paths can either be absolute -paths, or paths relative to the [`srcFolder`](#srcFolder--) +Optionally, provide an array of globs matching files that should be ignored. These globs are evaluated +under [`srcFolder`](#srcFolder--) ## `StringValuesTypingsGenerator` @@ -72,7 +103,7 @@ There is an extension of this utility specifically for file types where typings set of exported string values. This is useful for file types like CSS and RESX. This class takes the same options as the standard `TypingsGenerator`, with one additional option ([`exportAsDefault`](#exportAsDefault--)) and a different return value for `parseAndGenerateTypings`. -### `parseAndGenerateTypings = (fileContents: string, filePath: string) => { typings: ({ exportName: string, comment?: string })[] }` +### `parseAndGenerateTypings = (fileContents: string, filePath: string) => { typings: ({ exportName: string, comment?: string })[] } | Promise<{ typings: ({ exportName: string, comment?: string })[] }>` This function should behave the same as the `parseAndGenerateTypings` function for the standard `TypingsGenerator`, except that it should return an object with a `typings` property, set to @@ -115,3 +146,18 @@ If this option is set to `true`, the typings will be exported wrapped in a `defa allows the file to be imported by using the `import myFile from './myFile.my-extension';` syntax instead of the `import { myExport } from './myFile.my-extension';` or the `import * as myFile from './myFile.my-extension';` syntax. This style of export is not recommended as it can prevent tree-shaking optimization. + +### `exportAsDefaultInterfaceName = true | false` + +When `exportAsDefault` is true, this optional setting determines the interface name +for the default wrapped export. For example, in the Sass Typings plugin, the interface name +is set to `IExportStyles`. If not specified, the interface name will be `IExport`. +(This setting is ignored when `exportAsDefault` is false). + +## Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/typings-generator/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/typings-generator/) + +`@rushstack/typings-generator` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/typings-generator/config/rig.json b/libraries/typings-generator/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/typings-generator/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/typings-generator/eslint.config.js b/libraries/typings-generator/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/typings-generator/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/typings-generator/gulpfile.js b/libraries/typings-generator/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/libraries/typings-generator/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/libraries/typings-generator/package.json b/libraries/typings-generator/package.json index 8c89a450837..888b8754ae5 100644 --- a/libraries/typings-generator/package.json +++ b/libraries/typings-generator/package.json @@ -1,31 +1,42 @@ { "name": "@rushstack/typings-generator", - "version": "0.1.2", - "description": "This library provides functionality for automatically generator typings for non-TS files.", + "version": "0.15.7", + "description": "This library provides functionality for automatically generating typings for non-TS files.", + "keywords": [ + "dts", + "typings", + "generate" + ], "main": "lib/index.js", "typings": "dist/typings-generator.d.ts", - "tsdoc": { - "tsdocFlavor": "AEDoc" - }, "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/Microsoft/rushstack/tree/master/libraries/typings-generator" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/typings-generator" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "@types/node": "10.17.13", - "glob": "~7.0.5", - "@rushstack/node-core-library": "3.19.5", - "chokidar": "~3.3.1" + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "chokidar": "~3.6.0", + "fast-glob": "~3.3.1" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/glob": "7.1.1", - "gulp": "~4.0.2" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } } diff --git a/libraries/typings-generator/src/StringValuesTypingsGenerator.ts b/libraries/typings-generator/src/StringValuesTypingsGenerator.ts index 3919b520c5f..1e05aa9379c 100644 --- a/libraries/typings-generator/src/StringValuesTypingsGenerator.ts +++ b/libraries/typings-generator/src/StringValuesTypingsGenerator.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 { EOL } from 'os'; +import { EOL } from 'node:os'; + +import { Text } from '@rushstack/node-core-library'; import { - ITypingsGeneratorOptions, - TypingsGenerator + type ITypingsGeneratorOptions, + TypingsGenerator, + type ITypingsGeneratorOptionsWithCustomReadFile } from './TypingsGenerator'; /** @@ -21,75 +24,228 @@ export interface IStringValueTyping { */ export interface IStringValueTypings { typings: IStringValueTyping[]; + + /** + * Options for default exports. Note that options provided here will override + * options provided in {@link IStringValuesTypingsGeneratorBaseOptions.exportAsDefault}. + */ + exportAsDefault?: boolean | IExportAsDefaultOptions; } /** * @public */ -export interface IStringValuesTypingsGeneratorOptions extends ITypingsGeneratorOptions { - exportAsDefault?: boolean; +export interface IExportAsDefaultOptions { + /** + * This setting overrides the the interface name for the default wrapped export. + * + * @defaultValue "IExport" + */ + interfaceName?: string; + + /** + * @deprecated - Use {@link IExportAsDefaultOptions.interfaceDocumentationComment} instead. + */ + documentationComment?: string; + + /** + * This value is placed in a documentation comment for the + * exported default interface. + */ + interfaceDocumentationComment?: string; + + /** + * This value is placed in a documentation comment for the + * exported const value. + */ + valueDocumentationComment?: string; } -const EXPORT_AS_DEFAULT_INTERFACE_NAME: string = 'IExport'; +/** + * @public + */ +export interface IStringValuesTypingsGeneratorBaseOptions { + /** + * Setting this option wraps the typings export in a default property. + */ + exportAsDefault?: boolean | IExportAsDefaultOptions; + + /** + * @deprecated Use {@link IStringValuesTypingsGeneratorBaseOptions.exportAsDefault}'s + * {@link IExportAsDefaultOptions.interfaceName} instead. + */ + exportAsDefaultInterfaceName?: string; +} /** - * This is a simple tool that generates .d.ts files for non-TS files that can be represented as - * a simple set of named string exports. - * * @public */ -export class StringValuesTypingsGenerator extends TypingsGenerator { - public constructor(options: IStringValuesTypingsGeneratorOptions) { - super({ - ...options, - parseAndGenerateTypings: (fileContents: string, filePath: string) => { - const stringValueTypings: IStringValueTypings = options.parseAndGenerateTypings(fileContents, filePath); - - const outputLines: string[] = []; - let indent: string = ''; - if (options.exportAsDefault) { - outputLines.push( - `export interface ${EXPORT_AS_DEFAULT_INTERFACE_NAME} {` - ); - - indent = ' '; - } +export interface IStringValuesTypingsGeneratorOptions + extends ITypingsGeneratorOptions, + IStringValuesTypingsGeneratorBaseOptions { + // Nothing added. +} + +/** + * @public + */ +export interface IStringValuesTypingsGeneratorOptionsWithCustomReadFile + extends ITypingsGeneratorOptionsWithCustomReadFile, + IStringValuesTypingsGeneratorBaseOptions { + // Nothing added. +} + +const EXPORT_AS_DEFAULT_INTERFACE_NAME: string = 'IExport'; + +function convertToTypingsGeneratorOptions( + options: IStringValuesTypingsGeneratorOptionsWithCustomReadFile +): ITypingsGeneratorOptionsWithCustomReadFile { + const { + exportAsDefault: exportAsDefaultOptions, + exportAsDefaultInterfaceName: exportAsDefaultInterfaceName_deprecated, + parseAndGenerateTypings + } = options; + let defaultSplitExportAsDefaultInterfaceDocumentationComment: string[] | undefined; + let defaultSplitExportAsDefaultValueDocumentationComment: string[] | undefined; + let defaultExportAsDefaultInterfaceName: string | undefined; + if (typeof exportAsDefaultOptions === 'object') { + const { + interfaceDocumentationComment, + documentationComment: interfaceDocumentationComment_deprecated, + valueDocumentationComment, + interfaceName + } = exportAsDefaultOptions; + defaultSplitExportAsDefaultInterfaceDocumentationComment = Text.splitByNewLines( + interfaceDocumentationComment ?? interfaceDocumentationComment_deprecated + ); + defaultSplitExportAsDefaultValueDocumentationComment = Text.splitByNewLines(valueDocumentationComment); + defaultExportAsDefaultInterfaceName = + interfaceName ?? exportAsDefaultInterfaceName_deprecated ?? EXPORT_AS_DEFAULT_INTERFACE_NAME; + } else if (exportAsDefaultOptions) { + defaultExportAsDefaultInterfaceName = + exportAsDefaultInterfaceName_deprecated ?? EXPORT_AS_DEFAULT_INTERFACE_NAME; + } + + async function parseAndGenerateTypingsOuter( + fileContents: TFileContents, + filePath: string, + relativePath: string + ): Promise { + const stringValueTypings: IStringValueTypings | undefined = await parseAndGenerateTypings( + fileContents, + filePath, + relativePath + ); - for (const stringValueTyping of stringValueTypings.typings) { - const { exportName, comment } = stringValueTyping; - - if (comment && comment.trim() !== '') { - outputLines.push( - `${indent}/**`, - `${indent} * ${comment.replace(/\*\//g, '*\\/')}`, - `${indent} */` - ); - } - - if (options.exportAsDefault) { - outputLines.push( - `${indent}${exportName}: string;`, - '' - ); - } else { - outputLines.push( - `export declare const ${exportName}: string;`, - '' - ); - } + if (stringValueTypings === undefined) { + return; + } + + const { exportAsDefault: exportAsDefaultOptionsOverride, typings } = stringValueTypings; + let exportAsDefaultInterfaceName: string | undefined; + let interfaceDocumentationCommentLines: string[] | undefined; + let valueDocumentationCommentLines: string[] | undefined; + if (typeof exportAsDefaultOptionsOverride === 'boolean') { + if (exportAsDefaultOptionsOverride) { + exportAsDefaultInterfaceName = + defaultExportAsDefaultInterfaceName ?? EXPORT_AS_DEFAULT_INTERFACE_NAME; + interfaceDocumentationCommentLines = defaultSplitExportAsDefaultInterfaceDocumentationComment; + valueDocumentationCommentLines = defaultSplitExportAsDefaultValueDocumentationComment; + } + } else if (exportAsDefaultOptionsOverride) { + const { + interfaceName, + documentationComment, + interfaceDocumentationComment, + valueDocumentationComment + } = exportAsDefaultOptionsOverride; + exportAsDefaultInterfaceName = + interfaceName ?? defaultExportAsDefaultInterfaceName ?? EXPORT_AS_DEFAULT_INTERFACE_NAME; + interfaceDocumentationCommentLines = + Text.splitByNewLines(interfaceDocumentationComment) ?? + Text.splitByNewLines(documentationComment) ?? + defaultSplitExportAsDefaultInterfaceDocumentationComment; + valueDocumentationCommentLines = + Text.splitByNewLines(valueDocumentationComment) ?? + defaultSplitExportAsDefaultValueDocumentationComment; + } else { + exportAsDefaultInterfaceName = defaultExportAsDefaultInterfaceName; + interfaceDocumentationCommentLines = defaultSplitExportAsDefaultInterfaceDocumentationComment; + valueDocumentationCommentLines = defaultSplitExportAsDefaultValueDocumentationComment; + } + + const outputLines: string[] = []; + let indent: string = ''; + if (exportAsDefaultInterfaceName) { + if (interfaceDocumentationCommentLines) { + outputLines.push(`/**`); + for (const line of interfaceDocumentationCommentLines) { + outputLines.push(` * ${line}`); } - if (options.exportAsDefault) { - outputLines.push( - '}', - '', - `declare const strings: ${EXPORT_AS_DEFAULT_INTERFACE_NAME};`, - 'export default strings;' - ); + outputLines.push(` */`); + } + + outputLines.push(`export interface ${exportAsDefaultInterfaceName} {`); + indent = ' '; + } + + for (const stringValueTyping of typings) { + const { exportName, comment } = stringValueTyping; + + if (comment && comment.trim() !== '') { + outputLines.push(`${indent}/**`, `${indent} * ${comment.replace(/\*\//g, '*\\/')}`, `${indent} */`); + } + + if (exportAsDefaultInterfaceName) { + outputLines.push(`${indent}'${exportName}': string;`, ''); + } else { + outputLines.push(`export declare const ${exportName}: string;`, ''); + } + } + + if (exportAsDefaultInterfaceName) { + outputLines.push('}', ''); + + if (valueDocumentationCommentLines) { + outputLines.push(`/**`); + for (const line of valueDocumentationCommentLines) { + outputLines.push(` * ${line}`); } - return outputLines.join(EOL); + outputLines.push(` */`); } - }); + + outputLines.push( + `declare const strings: ${exportAsDefaultInterfaceName};`, + '', + 'export default strings;' + ); + } + + return outputLines.join(EOL); + } + + const convertedOptions: ITypingsGeneratorOptionsWithCustomReadFile = { + ...options, + parseAndGenerateTypings: parseAndGenerateTypingsOuter + }; + + return convertedOptions; +} + +/** + * This is a simple tool that generates .d.ts files for non-TS files that can be represented as + * a simple set of named string exports. + * + * @public + */ +export class StringValuesTypingsGenerator extends TypingsGenerator { + public constructor( + options: TFileContents extends string ? IStringValuesTypingsGeneratorOptions : never + ); + public constructor(options: IStringValuesTypingsGeneratorOptionsWithCustomReadFile); + public constructor(options: IStringValuesTypingsGeneratorOptionsWithCustomReadFile) { + super(convertToTypingsGeneratorOptions(options)); } } diff --git a/libraries/typings-generator/src/TypingsGenerator.ts b/libraries/typings-generator/src/TypingsGenerator.ts index 959ade6d5fa..cc080fc3795 100644 --- a/libraries/typings-generator/src/TypingsGenerator.ts +++ b/libraries/typings-generator/src/TypingsGenerator.ts @@ -1,28 +1,70 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - FileSystem, - Terminal, - ConsoleTerminalProvider, - Path, - NewlineKind -} from '@rushstack/node-core-library'; -import * as glob from 'glob'; -import * as path from 'path'; -import { EOL } from 'os'; +import * as path from 'node:path'; +import { EOL } from 'node:os'; + +import glob from 'fast-glob'; import * as chokidar from 'chokidar'; +import { type ITerminal, Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; +import { FileSystem, Path, NewlineKind, Async } from '@rushstack/node-core-library'; + /** * @public */ -export interface ITypingsGeneratorOptions { +export interface ITypingsGeneratorBaseOptions { srcFolder: string; generatedTsFolder: string; + secondaryGeneratedTsFolders?: string[]; + globsToIgnore?: string[]; + terminal?: ITerminal; +} + +/** + * @public + */ +export interface ITypingsGeneratorOptionsWithoutReadFile< + TTypingsResult = string | undefined, + TFileContents = string +> extends ITypingsGeneratorBaseOptions { fileExtensions: string[]; - parseAndGenerateTypings: (fileContents: string, filePath: string) => TTypingsResult; - terminal?: Terminal; - filesToIgnore?: string[]; + parseAndGenerateTypings: ( + fileContents: TFileContents, + filePath: string, + relativePath: string + ) => TTypingsResult | Promise; + getAdditionalOutputFiles?: (relativePath: string) => string[]; +} + +/** + * @public + */ +export type ReadFile = ( + filePath: string, + relativePath: string +) => Promise | TFileContents; + +/** + * @public + */ +export interface ITypingsGeneratorOptions< + TTypingsResult = string | undefined, + TFileContents extends string = string +> extends ITypingsGeneratorOptionsWithoutReadFile { + readFile?: ReadFile; +} + +/** + * Options for a TypingsGenerator that needs to customize how files are read. + * + * @public + */ +export interface ITypingsGeneratorOptionsWithCustomReadFile< + TTypingsResult = string | undefined, + TFileContents = string +> extends ITypingsGeneratorOptionsWithoutReadFile { + readFile: ReadFile; } /** @@ -30,95 +72,265 @@ export interface ITypingsGeneratorOptions { * * @public */ -export class TypingsGenerator { - protected _options: ITypingsGeneratorOptions; +export class TypingsGenerator { + // Map of resolved consumer file path -> Set + private readonly _dependenciesOfFile: Map>; + + // Map of resolved dependency file path -> Set + private readonly _consumersOfFile: Map>; + + // Map of resolved file path -> relative file path + private readonly _relativePaths: Map; + + protected readonly _options: ITypingsGeneratorOptionsWithCustomReadFile; + + protected readonly terminal: ITerminal; + + /** + * The folder path that contains all input source files. + */ + public readonly sourceFolderPath: string; + + /** + * The glob pattern used to find input files to process. + */ + public readonly inputFileGlob: string; - public constructor(options: ITypingsGeneratorOptions) { + /** + * The glob patterns that should be ignored when finding input files to process. + */ + public readonly ignoredFileGlobs: readonly string[]; + + public constructor( + options: TFileContents extends string + ? ITypingsGeneratorOptions + : never + ); + public constructor(options: ITypingsGeneratorOptionsWithCustomReadFile); + public constructor(options: ITypingsGeneratorOptionsWithCustomReadFile) { this._options = { - ...options + ...options, + readFile: + options.readFile ?? + ((filePath: string, relativePath: string): Promise => + FileSystem.readFileAsync(filePath) as Promise) }; - if (!this._options.generatedTsFolder) { + if (!options.generatedTsFolder) { throw new Error('generatedTsFolder must be provided'); } - if (!this._options.srcFolder) { + if (!options.srcFolder) { throw new Error('srcFolder must be provided'); } + this.sourceFolderPath = options.srcFolder; - if (Path.isUnder(this._options.srcFolder, this._options.generatedTsFolder)) { + if (Path.isUnder(options.srcFolder, options.generatedTsFolder)) { throw new Error('srcFolder must not be under generatedTsFolder'); } - if (Path.isUnder(this._options.generatedTsFolder, this._options.srcFolder)) { + if (Path.isUnder(options.generatedTsFolder, options.srcFolder)) { throw new Error('generatedTsFolder must not be under srcFolder'); } - if (!this._options.fileExtensions || this._options.fileExtensions.length === 0) { + if (!options.fileExtensions || options.fileExtensions.length === 0) { throw new Error('At least one file extension must be provided.'); } - if (!this._options.filesToIgnore) { - this._options.filesToIgnore = []; - } + this.ignoredFileGlobs = options.globsToIgnore || []; + + this.terminal = options.terminal ?? new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); + + this._options.fileExtensions = this._normalizeFileExtensions(options.fileExtensions); + + this._dependenciesOfFile = new Map(); + this._consumersOfFile = new Map(); + this._relativePaths = new Map(); - if (!this._options.terminal) { - this._options.terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: true })); + this.inputFileGlob = `**/*+(${this._options.fileExtensions.join('|')})`; + } + + /** + * Generate typings for the provided input files. + * + * @param relativeFilePaths - The input files to process, relative to the source folder. If not provided, + * all input files will be processed. + */ + public async generateTypingsAsync(relativeFilePaths?: string[]): Promise { + let checkFilePaths: boolean = true; + if (!relativeFilePaths?.length) { + checkFilePaths = false; // Don't check file paths if we generate them + relativeFilePaths = await glob(this.inputFileGlob, { + cwd: this.sourceFolderPath, + ignore: this.ignoredFileGlobs as string[], + onlyFiles: true + }); } - this._options.fileExtensions = this._normalizeFileExtensions(this._options.fileExtensions); + await this._reprocessFilesAsync(relativeFilePaths!, checkFilePaths); } - public generateTypings(): void { - FileSystem.ensureEmptyFolder(this._options.generatedTsFolder); + public async runWatcherAsync(): Promise { + await FileSystem.ensureFolderAsync(this._options.generatedTsFolder); - const filesToIgnore: Set = new Set((this._options.filesToIgnore!).map((fileToIgnore) => { - return path.resolve(this._options.srcFolder, fileToIgnore); - })); + await new Promise((resolve, reject): void => { + const watcher: chokidar.FSWatcher = chokidar.watch(this.inputFileGlob, { + cwd: this.sourceFolderPath, + ignored: this.ignoredFileGlobs as string[] // `ignored` doesn't like the readonly array + }); - const filePaths: string[] = glob.sync( - path.join('**', `*+(${this._options.fileExtensions.join('|')})`), - { - cwd: this._options.srcFolder, - absolute: true, - nosort: true, - nodir: true - } - ); + const queue: Set = new Set(); + let timeout: NodeJS.Timeout | undefined; + let processing: boolean = false; + let flushAfterCompletion: boolean = false; - for (let filePath of filePaths) { - filePath = path.resolve(this._options.srcFolder, filePath); + const flushInternal: () => void = () => { + processing = true; - if (filesToIgnore.has(filePath)) { - continue; - } + const toProcess: string[] = Array.from(queue); + queue.clear(); + this._reprocessFilesAsync(toProcess, false) + .then(() => { + processing = false; + // If the timeout was invoked again, immediately reexecute with the changed files. + if (flushAfterCompletion) { + flushAfterCompletion = false; + flushInternal(); + } + }) + .catch(reject); + }; + + const debouncedFlush: () => void = () => { + timeout = undefined; + if (processing) { + // If the callback was invoked while processing is ongoing, indicate that we should flush immediately + // upon completion of the current change batch. + flushAfterCompletion = true; + return; + } + + flushInternal(); + }; + + const onChange: (relativePath: string) => void = (relativePath: string) => { + queue.add(relativePath); + if (timeout) { + clearTimeout(timeout); + } + + setTimeout(debouncedFlush, 100); + }; - this._parseFileAndGenerateTypings(filePath); + watcher.on('add', onChange); + watcher.on('change', onChange); + watcher.on('unlink', async (relativePath) => { + await Promise.all( + this._getOutputFilePathsWithoutCheck(relativePath).map(async (outputFile: string) => { + await FileSystem.deleteFileAsync(outputFile); + }) + ); + }); + watcher.on('error', reject); + }); + } + + /** + * Register file dependencies that may effect the typings of a consumer file. + * Note: This feature is only useful in watch mode. + * The registerDependency method must be called in the body of parseAndGenerateTypings every + * time because the registry for a file is cleared at the beginning of processing. + */ + public registerDependency(consumer: string, rawDependency: string): void { + // Need to normalize slashes in the dependency path + const dependency: string = path.resolve(this._options.srcFolder, rawDependency); + + let dependencies: Set | undefined = this._dependenciesOfFile.get(consumer); + if (!dependencies) { + dependencies = new Set(); + this._dependenciesOfFile.set(consumer, dependencies); } + dependencies.add(dependency); + + let consumers: Set | undefined = this._consumersOfFile.get(dependency); + if (!consumers) { + consumers = new Set(); + this._consumersOfFile.set(dependency, consumers); + } + consumers.add(consumer); } - public runWatcher(): void { - FileSystem.ensureEmptyFolder(this._options.generatedTsFolder); + public getOutputFilePaths(relativePath: string): string[] { + if (path.isAbsolute(relativePath)) { + throw new Error(`"${relativePath}" must be relative`); + } - const globBase: string = path.resolve(this._options.srcFolder, '**'); + return this._getOutputFilePathsWithoutCheck(relativePath); + } + + private _getOutputFilePathsWithoutCheck(relativePath: string): string[] { + const typingsFilePaths: Iterable = this._getTypingsFilePaths(relativePath); + const additionalPaths: string[] | undefined = this._options.getAdditionalOutputFiles?.(relativePath); + return additionalPaths ? [...typingsFilePaths, ...additionalPaths] : Array.from(typingsFilePaths); + } + + private async _reprocessFilesAsync( + relativePaths: Iterable, + checkFilePaths: boolean + ): Promise { + // Build a queue of resolved paths + const toProcess: Set = new Set(); + for (const rawPath of relativePaths) { + if (checkFilePaths && path.isAbsolute(rawPath)) { + throw new Error(`"${rawPath}" must be relative`); + } + + const relativePath: string = Path.convertToSlashes(rawPath); + const resolvedPath: string = path.resolve(this._options.srcFolder, rawPath); + this._relativePaths.set(resolvedPath, relativePath); + toProcess.add(resolvedPath); + } - const watcher: chokidar.FSWatcher = chokidar.watch( - this._options.fileExtensions.map((fileExtension) => path.join(globBase, `*${fileExtension}`)) + // Expand out all registered consumers, according to the current dependency graph + for (const file of toProcess) { + const consumers: Set | undefined = this._consumersOfFile.get(file); + if (consumers) { + for (const consumer of consumers) { + toProcess.add(consumer); + } + } + } + + // Map back to the relative paths so that the information is available + await Async.forEachAsync( + toProcess, + async (resolvedPath: string) => { + const relativePath: string | undefined = this._relativePaths.get(resolvedPath); + if (!relativePath) { + throw new Error(`Missing relative path for file ${resolvedPath}`); + } + await this._parseFileAndGenerateTypingsAsync(relativePath, resolvedPath); + }, + { concurrency: 20 } ); - const boundGenerateTypingsFunction: (filePath: string) => void = this._parseFileAndGenerateTypings.bind(this); - watcher.on('add', boundGenerateTypingsFunction); - watcher.on('change', boundGenerateTypingsFunction); - watcher.on('unlink', (filePath) => { - const generatedTsFilePath: string = this._getTypingsFilePath(filePath); - FileSystem.deleteFile(generatedTsFilePath); - }); } - private _parseFileAndGenerateTypings(locFilePath: string): void { + private async _parseFileAndGenerateTypingsAsync(relativePath: string, resolvedPath: string): Promise { + // Clear registered dependencies prior to reprocessing. + this._clearDependencies(resolvedPath); + try { - const fileContents: string = FileSystem.readFile(locFilePath); - const typingsData: string = this._options.parseAndGenerateTypings(fileContents, locFilePath); - const generatedTsFilePath: string = this._getTypingsFilePath(locFilePath); + const fileContents: TFileContents = await this._options.readFile(resolvedPath, relativePath); + const typingsData: string | undefined = await this._options.parseAndGenerateTypings( + fileContents, + resolvedPath, + relativePath + ); + + // Typings data will be undefined when no types should be generated for the parsed file. + if (typingsData === undefined) { + return; + } const prefixedTypingsData: string = [ '// This file was generated by a tool. Modifying it will produce unexpected behavior', @@ -126,36 +338,54 @@ export class TypingsGenerator { typingsData ].join(EOL); - FileSystem.writeFile( - generatedTsFilePath, - prefixedTypingsData, - { ensureFolderExists: true, convertLineEndings: NewlineKind.OsDefault } - ); - + const generatedTsFilePaths: Iterable = this._getTypingsFilePaths(relativePath); + for (const generatedTsFilePath of generatedTsFilePaths) { + await FileSystem.writeFileAsync(generatedTsFilePath, prefixedTypingsData, { + ensureFolderExists: true, + convertLineEndings: NewlineKind.OsDefault + }); + } } catch (e) { - this._options.terminal!.writeError( - `Error occurred parsing and generating typings for file "${locFilePath}": ${e}` + this.terminal.writeError( + `Error occurred parsing and generating typings for file "${resolvedPath}": ${e}` ); } } - private _getTypingsFilePath(locFilePath: string): string { - return path.resolve( - this._options.generatedTsFolder, - path.relative(this._options.srcFolder, `${locFilePath}.d.ts`) - ); + /** + * Removes the consumer from all extant dependencies + */ + private _clearDependencies(consumer: string): void { + const dependencies: Set | undefined = this._dependenciesOfFile.get(consumer); + if (dependencies) { + for (const dependency of dependencies) { + this._consumersOfFile.get(dependency)!.delete(consumer); + } + dependencies.clear(); + } + } + + private *_getTypingsFilePaths(relativePath: string): Iterable { + const { generatedTsFolder, secondaryGeneratedTsFolders } = this._options; + const dtsFilename: string = `${relativePath}.d.ts`; + yield `${generatedTsFolder}/${dtsFilename}`; + if (secondaryGeneratedTsFolders) { + for (const secondaryGeneratedTsFolder of secondaryGeneratedTsFolders) { + yield `${secondaryGeneratedTsFolder}/${dtsFilename}`; + } + } } private _normalizeFileExtensions(fileExtensions: string[]): string[] { - const result: string[] = []; + const result: Set = new Set(); for (const fileExtension of fileExtensions) { if (!fileExtension.startsWith('.')) { - result.push(`.${fileExtension}`); + result.add(`.${fileExtension}`); } else { - result.push(fileExtension); + result.add(fileExtension); } } - return result; + return Array.from(result); } } diff --git a/libraries/typings-generator/src/index.ts b/libraries/typings-generator/src/index.ts index b28052933b4..20e2e1dfcfe 100644 --- a/libraries/typings-generator/src/index.ts +++ b/libraries/typings-generator/src/index.ts @@ -1,14 +1,29 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/** + * An engine for generating TypeScript .d.ts files that provide type signatures + * for non-TypeScript modules such as generated JavaScript or CSS. It can operate + * in either a single-run mode or a watch mode. + * + * @packageDocumentation + */ + export { - ITypingsGeneratorOptions, + type ReadFile, + type ITypingsGeneratorBaseOptions, + type ITypingsGeneratorOptionsWithoutReadFile, + type ITypingsGeneratorOptions, + type ITypingsGeneratorOptionsWithCustomReadFile, TypingsGenerator } from './TypingsGenerator'; export { - IStringValueTyping, - IStringValueTypings, - IStringValuesTypingsGeneratorOptions, + type IStringValueTyping, + type IStringValueTypings, + type IExportAsDefaultOptions, + type IStringValuesTypingsGeneratorBaseOptions, + type IStringValuesTypingsGeneratorOptions, + type IStringValuesTypingsGeneratorOptionsWithCustomReadFile, StringValuesTypingsGenerator } from './StringValuesTypingsGenerator'; diff --git a/libraries/typings-generator/src/test/StringValuesTypingsGenerator.test.ts b/libraries/typings-generator/src/test/StringValuesTypingsGenerator.test.ts new file mode 100644 index 00000000000..2a0b4f79237 --- /dev/null +++ b/libraries/typings-generator/src/test/StringValuesTypingsGenerator.test.ts @@ -0,0 +1,311 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import type { + IStringValuesTypingsGeneratorBaseOptions, + IStringValueTypings +} from '../StringValuesTypingsGenerator'; + +let inputFs: Record; +let outputFs: Record; + +jest.mock('@rushstack/node-core-library', () => { + const realNcl: typeof import('@rushstack/node-core-library') = jest.requireActual( + '@rushstack/node-core-library' + ); + return { + ...realNcl, + FileSystem: { + readFileAsync: async (filePath: string) => { + const result: string | undefined = inputFs[filePath]; + if (result === undefined) { + const error: NodeJS.ErrnoException = new Error( + `Cannot read file ${filePath}` + ) as NodeJS.ErrnoException; + error.code = 'ENOENT'; + throw error; + } else { + return result; + } + }, + writeFileAsync: async (filePath: string, contents: string) => { + outputFs[filePath] = contents; + } + } + }; +}); + +describe('StringValuesTypingsGenerator', () => { + beforeEach(() => { + inputFs = {}; + outputFs = {}; + }); + + function runTests( + baseOptions: IStringValuesTypingsGeneratorBaseOptions, + extraStringTypings?: Partial + ): void { + it('should generate typings', async () => { + const [{ StringValuesTypingsGenerator }, { Terminal, StringBufferTerminalProvider }] = + await Promise.all([import('../StringValuesTypingsGenerator'), import('@rushstack/terminal')]); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + inputFs['/src/test.ext'] = ''; + + const fileContents: {} = { a: 1 }; + const generator = new StringValuesTypingsGenerator({ + srcFolder: '/src', + generatedTsFolder: '/out', + readFile: (filePath: string, relativePath: string) => { + expect(relativePath).toEqual('test.ext'); + return Promise.resolve(fileContents); + }, + fileExtensions: ['.ext'], + parseAndGenerateTypings: (contents: {}, filePath: string, relativePath: string) => { + expect(contents).toBe(fileContents); + return { + typings: [ + { + exportName: 'test', + comment: 'test comment\nsecond line' + } + ], + ...extraStringTypings + }; + }, + terminal, + ...baseOptions + }); + + await generator.generateTypingsAsync(['test.ext']); + expect(outputFs).toMatchSnapshot(); + + expect(terminalProvider.getOutput()).toEqual(''); + expect(terminalProvider.getWarningOutput()).toEqual(''); + expect(terminalProvider.getErrorOutput()).toEqual(''); + expect(terminalProvider.getVerboseOutput()).toEqual(''); + expect(terminalProvider.getDebugOutput()).toEqual(''); + }); + } + + describe('non-default exports', () => { + runTests({}); + }); + + describe('default exports', () => { + describe('with { exportAsDefault: true }', () => { + runTests({ exportAsDefault: true }); + }); + + describe("with { exportAsDefault: true, exportAsDefaultInterfaceName: 'IOverride' }", () => { + runTests({ + exportAsDefault: true, + exportAsDefaultInterfaceName: 'IOverride' + }); + }); + + describe("with { exportAsDefault: {}, exportAsDefaultInterfaceName: 'IOverride' }", () => { + runTests({ + exportAsDefault: {}, + exportAsDefaultInterfaceName: 'IOverride' + }); + }); + + describe("with { exportAsDefault: { interfaceName: 'IOverride' }, exportAsDefaultInterfaceName: 'IDeprecated' }", () => { + runTests({ + exportAsDefault: { + interfaceName: 'IOverride' + }, + exportAsDefaultInterfaceName: 'IDeprecated' + }); + }); + + describe("with { exportAsDefault: documentationComment: 'deprecated', interfaceDocumentationComment: 'doc-comment' }", () => { + runTests({ + exportAsDefault: { + documentationComment: 'deprecated', + interfaceDocumentationComment: 'doc-comment' + } + }); + }); + + describe("with { exportAsDefault: { *DocumentationComment: 'doc-comment\\nsecond line' } }", () => { + runTests({ + exportAsDefault: { + interfaceDocumentationComment: 'doc-comment\nsecond line', + valueDocumentationComment: 'value-comment\nsecond line' + } + }); + }); + + describe('overrides for individual files', () => { + describe('with exportAsDefault unset', () => { + describe('overriding with { exportAsDefault: false }', () => { + runTests( + {}, + { + exportAsDefault: false + } + ); + }); + + describe("overriding with { interfaceName: 'IOverride' } ", () => { + runTests( + {}, + { + exportAsDefault: { + interfaceName: 'IOverride' + } + } + ); + }); + + describe('overriding with a new doc comment ', () => { + runTests( + {}, + { + exportAsDefault: { + interfaceDocumentationComment: 'doc-comment\nsecond line', + valueDocumentationComment: 'value-comment\nsecond line' + } + } + ); + }); + }); + + describe('with exportAsDefault set to true', () => { + describe('overriding with { exportAsDefault: false }', () => { + runTests( + { + exportAsDefault: true + }, + { + exportAsDefault: false + } + ); + }); + + describe("overriding with { interfaceName: 'IOverride' } ", () => { + runTests( + { + exportAsDefault: true + }, + { + exportAsDefault: { + interfaceName: 'IOverride' + } + } + ); + }); + + describe('overriding with a new doc comment ', () => { + runTests( + { + exportAsDefault: true + }, + { + exportAsDefault: { + interfaceDocumentationComment: 'doc-comment\nsecond line', + valueDocumentationComment: 'value-comment\nsecond line' + } + } + ); + }); + }); + + describe('with exportAsDefault set to {}', () => { + describe('overriding with { exportAsDefault: false }', () => { + runTests( + { + exportAsDefault: {} + }, + { + exportAsDefault: false + } + ); + }); + + describe("overriding with { interfaceName: 'IOverride' } ", () => { + runTests( + { + exportAsDefault: {} + }, + { + exportAsDefault: { + interfaceName: 'IOverride' + } + } + ); + }); + + describe('overriding with a new doc comment ', () => { + runTests( + { + exportAsDefault: {} + }, + { + exportAsDefault: { + interfaceDocumentationComment: 'doc-comment\nsecond line', + valueDocumentationComment: 'value-comment\nsecond line' + } + } + ); + }); + }); + + describe('with exportAsDefault filled', () => { + describe('overriding with { exportAsDefault: false }', () => { + runTests( + { + exportAsDefault: { + interfaceName: 'IBase', + interfaceDocumentationComment: 'base-comment', + valueDocumentationComment: 'base-value-comment' + } + }, + { + exportAsDefault: false + } + ); + }); + + describe("overriding with { interfaceName: 'IOverride' } ", () => { + runTests( + { + exportAsDefault: { + interfaceName: 'IBase', + interfaceDocumentationComment: 'base-comment', + valueDocumentationComment: 'base-value-comment' + } + }, + { + exportAsDefault: { + interfaceName: 'IOverride' + } + } + ); + }); + + describe('overriding with a new doc comment ', () => { + runTests( + { + exportAsDefault: { + interfaceName: 'IBase', + interfaceDocumentationComment: 'base-comment', + valueDocumentationComment: 'base-value-comment' + } + }, + { + exportAsDefault: { + interfaceDocumentationComment: 'doc-comment\nsecond line', + valueDocumentationComment: 'value-comment\nsecond line' + } + } + ); + }); + }); + }); + }); +}); diff --git a/libraries/typings-generator/src/test/__snapshots__/StringValuesTypingsGenerator.test.ts.snap b/libraries/typings-generator/src/test/__snapshots__/StringValuesTypingsGenerator.test.ts.snap new file mode 100644 index 00000000000..796d6ef18cc --- /dev/null +++ b/libraries/typings-generator/src/test/__snapshots__/StringValuesTypingsGenerator.test.ts.snap @@ -0,0 +1,381 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault filled overriding with { exportAsDefault: false } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * test comment +second line + */ +export declare const test: string; +", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault filled overriding with { interfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * base-comment + */ +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * base-value-comment + */ +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault filled overriding with a new doc comment should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + * second line + */ +export interface IBase { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * value-comment + * second line + */ +declare const strings: IBase; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to {} overriding with { exportAsDefault: false } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * test comment +second line + */ +export declare const test: string; +", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to {} overriding with { interfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to {} overriding with a new doc comment should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + * second line + */ +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * value-comment + * second line + */ +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to true overriding with { exportAsDefault: false } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * test comment +second line + */ +export declare const test: string; +", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to true overriding with { interfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault set to true overriding with a new doc comment should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + * second line + */ +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * value-comment + * second line + */ +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault unset overriding with { exportAsDefault: false } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * test comment +second line + */ +export declare const test: string; +", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault unset overriding with { interfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports overrides for individual files with exportAsDefault unset overriding with a new doc comment should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + * second line + */ +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * value-comment + * second line + */ +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: { *DocumentationComment: 'doc-comment\\nsecond line' } } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + * second line + */ +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +/** + * value-comment + * second line + */ +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: { interfaceName: 'IOverride' }, exportAsDefaultInterfaceName: 'IDeprecated' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: {}, exportAsDefaultInterfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: documentationComment: 'deprecated', interfaceDocumentationComment: 'doc-comment' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * doc-comment + */ +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: true } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IExport { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IExport; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator default exports with { exportAsDefault: true, exportAsDefaultInterfaceName: 'IOverride' } should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface IOverride { + /** + * test comment +second line + */ + 'test': string; + +} + +declare const strings: IOverride; + +export default strings;", +} +`; + +exports[`StringValuesTypingsGenerator non-default exports should generate typings 1`] = ` +Object { + "/out/test.ext.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * test comment +second line + */ +export declare const test: string; +", +} +`; diff --git a/libraries/typings-generator/tsconfig.json b/libraries/typings-generator/tsconfig.json index b1abb9e5b4a..dac21d04081 100644 --- a/libraries/typings-generator/tsconfig.json +++ b/libraries/typings-generator/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/worker-pool/.npmignore b/libraries/worker-pool/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/libraries/worker-pool/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/worker-pool/CHANGELOG.json b/libraries/worker-pool/CHANGELOG.json new file mode 100644 index 00000000000..9ba9dffc9b7 --- /dev/null +++ b/libraries/worker-pool/CHANGELOG.json @@ -0,0 +1,2830 @@ +{ + "name": "@rushstack/worker-pool", + "entries": [ + { + "version": "0.6.7", + "tag": "@rushstack/worker-pool_v0.6.7", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/worker-pool_v0.6.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/worker-pool_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/worker-pool_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/worker-pool_v0.6.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/worker-pool_v0.6.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/worker-pool_v0.6.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/worker-pool_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/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/worker-pool_v0.5.30", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/worker-pool_v0.5.29", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/worker-pool_v0.5.28", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/worker-pool_v0.5.27", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/worker-pool_v0.5.26", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/worker-pool_v0.5.25", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/worker-pool_v0.5.24", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/worker-pool_v0.5.23", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/worker-pool_v0.5.22", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/worker-pool_v0.5.21", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/worker-pool_v0.5.20", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/worker-pool_v0.5.19", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/worker-pool_v0.5.18", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/worker-pool_v0.5.17", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/worker-pool_v0.5.16", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/worker-pool_v0.5.15", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/worker-pool_v0.5.14", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/worker-pool_v0.5.13", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/worker-pool_v0.5.12", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/worker-pool_v0.5.11", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/worker-pool_v0.5.10", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/worker-pool_v0.5.9", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/worker-pool_v0.5.8", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/worker-pool_v0.5.7", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/worker-pool_v0.5.6", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/worker-pool_v0.5.5", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/worker-pool_v0.5.4", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/worker-pool_v0.5.3", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/worker-pool_v0.5.2", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/worker-pool_v0.5.1", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/worker-pool_v0.5.0", + "date": "Wed, 22 Jan 2025 03:03:47 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `workerResourceLimits` option to the `WorkerPool` constructor to control the available resources to the workers." + } + ] + } + }, + { + "version": "0.4.81", + "tag": "@rushstack/worker-pool_v0.4.81", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.4.80", + "tag": "@rushstack/worker-pool_v0.4.80", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.4.79", + "tag": "@rushstack/worker-pool_v0.4.79", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.4.78", + "tag": "@rushstack/worker-pool_v0.4.78", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.4.77", + "tag": "@rushstack/worker-pool_v0.4.77", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.4.76", + "tag": "@rushstack/worker-pool_v0.4.76", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.4.75", + "tag": "@rushstack/worker-pool_v0.4.75", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.4.74", + "tag": "@rushstack/worker-pool_v0.4.74", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.4.73", + "tag": "@rushstack/worker-pool_v0.4.73", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.4.72", + "tag": "@rushstack/worker-pool_v0.4.72", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.4.71", + "tag": "@rushstack/worker-pool_v0.4.71", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.4.70", + "tag": "@rushstack/worker-pool_v0.4.70", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.4.69", + "tag": "@rushstack/worker-pool_v0.4.69", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.4.68", + "tag": "@rushstack/worker-pool_v0.4.68", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.4.67", + "tag": "@rushstack/worker-pool_v0.4.67", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.4.66", + "tag": "@rushstack/worker-pool_v0.4.66", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.4.65", + "tag": "@rushstack/worker-pool_v0.4.65", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.4.64", + "tag": "@rushstack/worker-pool_v0.4.64", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.4.63", + "tag": "@rushstack/worker-pool_v0.4.63", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.4.62", + "tag": "@rushstack/worker-pool_v0.4.62", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.4.61", + "tag": "@rushstack/worker-pool_v0.4.61", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.4.60", + "tag": "@rushstack/worker-pool_v0.4.60", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.4.59", + "tag": "@rushstack/worker-pool_v0.4.59", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.4.58", + "tag": "@rushstack/worker-pool_v0.4.58", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.4.57", + "tag": "@rushstack/worker-pool_v0.4.57", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.4.56", + "tag": "@rushstack/worker-pool_v0.4.56", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.4.55", + "tag": "@rushstack/worker-pool_v0.4.55", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.4.54", + "tag": "@rushstack/worker-pool_v0.4.54", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.4.53", + "tag": "@rushstack/worker-pool_v0.4.53", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.4.52", + "tag": "@rushstack/worker-pool_v0.4.52", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.4.51", + "tag": "@rushstack/worker-pool_v0.4.51", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.4.50", + "tag": "@rushstack/worker-pool_v0.4.50", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.4.49", + "tag": "@rushstack/worker-pool_v0.4.49", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.4.48", + "tag": "@rushstack/worker-pool_v0.4.48", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.4.47", + "tag": "@rushstack/worker-pool_v0.4.47", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.4.46", + "tag": "@rushstack/worker-pool_v0.4.46", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.4.45", + "tag": "@rushstack/worker-pool_v0.4.45", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.4.44", + "tag": "@rushstack/worker-pool_v0.4.44", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.4.43", + "tag": "@rushstack/worker-pool_v0.4.43", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.4.42", + "tag": "@rushstack/worker-pool_v0.4.42", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.4.41", + "tag": "@rushstack/worker-pool_v0.4.41", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.4.40", + "tag": "@rushstack/worker-pool_v0.4.40", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "patch": [ + { + "comment": "Use `once` instead of `on` for `exit` event." + } + ] + } + }, + { + "version": "0.4.39", + "tag": "@rushstack/worker-pool_v0.4.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.4.38", + "tag": "@rushstack/worker-pool_v0.4.38", + "date": "Fri, 15 Mar 2024 00:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.4.37", + "tag": "@rushstack/worker-pool_v0.4.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/worker-pool_v0.4.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/worker-pool_v0.4.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/worker-pool_v0.4.34", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/worker-pool_v0.4.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/worker-pool_v0.4.32", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/worker-pool_v0.4.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/worker-pool_v0.4.30", + "date": "Thu, 22 Feb 2024 01:36:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/worker-pool_v0.4.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/worker-pool_v0.4.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/worker-pool_v0.4.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/worker-pool_v0.4.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/worker-pool_v0.4.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/worker-pool_v0.4.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken link to API documentation" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/worker-pool_v0.4.23", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/worker-pool_v0.4.22", + "date": "Wed, 07 Feb 2024 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/worker-pool_v0.4.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/worker-pool_v0.4.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/worker-pool_v0.4.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/worker-pool_v0.4.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/worker-pool_v0.4.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/worker-pool_v0.4.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/worker-pool_v0.4.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/worker-pool_v0.4.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/worker-pool_v0.4.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/worker-pool_v0.4.12", + "date": "Fri, 10 Nov 2023 18:02:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/worker-pool_v0.4.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/worker-pool_v0.4.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/worker-pool_v0.4.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/worker-pool_v0.4.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/worker-pool_v0.4.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/worker-pool_v0.4.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/worker-pool_v0.4.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/worker-pool_v0.4.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/worker-pool_v0.4.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/worker-pool_v0.4.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/worker-pool_v0.4.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/worker-pool_v0.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/worker-pool_v0.3.37", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/worker-pool_v0.3.36", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/worker-pool_v0.3.35", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/worker-pool_v0.3.34", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/worker-pool_v0.3.33", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/worker-pool_v0.3.32", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/worker-pool_v0.3.31", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/worker-pool_v0.3.30", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/worker-pool_v0.3.29", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/worker-pool_v0.3.28", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/worker-pool_v0.3.27", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/worker-pool_v0.3.26", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/worker-pool_v0.3.25", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/worker-pool_v0.3.24", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/worker-pool_v0.3.23", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/worker-pool_v0.3.22", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/worker-pool_v0.3.21", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/worker-pool_v0.3.20", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/worker-pool_v0.3.19", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/worker-pool_v0.3.18", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/worker-pool_v0.3.17", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/worker-pool_v0.3.16", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/worker-pool_v0.3.15", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/worker-pool_v0.3.14", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/worker-pool_v0.3.13", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/worker-pool_v0.3.12", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/worker-pool_v0.3.11", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/worker-pool_v0.3.10", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/worker-pool_v0.3.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/worker-pool_v0.3.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/worker-pool_v0.3.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/worker-pool_v0.3.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/worker-pool_v0.3.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/worker-pool_v0.3.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/worker-pool_v0.3.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/worker-pool_v0.3.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/worker-pool_v0.3.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/worker-pool_v0.3.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/worker-pool_v0.2.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/worker-pool_v0.1.48", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/worker-pool_v0.1.47", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/worker-pool_v0.1.46", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/worker-pool_v0.1.45", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/worker-pool_v0.1.44", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/worker-pool_v0.1.43", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/worker-pool_v0.1.42", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/worker-pool_v0.1.41", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/worker-pool_v0.1.40", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/worker-pool_v0.1.39", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/worker-pool_v0.1.38", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/worker-pool_v0.1.37", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/worker-pool_v0.1.36", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/worker-pool_v0.1.35", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/worker-pool_v0.1.34", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/worker-pool_v0.1.33", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/worker-pool_v0.1.32", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/worker-pool_v0.1.31", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/worker-pool_v0.1.30", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/worker-pool_v0.1.29", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/worker-pool_v0.1.28", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/worker-pool_v0.1.27", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/worker-pool_v0.1.26", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/worker-pool_v0.1.25", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/worker-pool_v0.1.24", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/worker-pool_v0.1.23", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/worker-pool_v0.1.22", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/worker-pool_v0.1.21", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/worker-pool_v0.1.20", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/worker-pool_v0.1.19", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/worker-pool_v0.1.18", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/worker-pool_v0.1.17", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/worker-pool_v0.1.16", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/worker-pool_v0.1.15", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/worker-pool_v0.1.14", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/worker-pool_v0.1.13", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/worker-pool_v0.1.12", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/worker-pool_v0.1.11", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/worker-pool_v0.1.10", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/worker-pool_v0.1.9", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/worker-pool_v0.1.8", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/worker-pool_v0.1.7", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/worker-pool_v0.1.6", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/worker-pool_v0.1.5", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/worker-pool_v0.1.4", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/worker-pool_v0.1.3", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/worker-pool_v0.1.2", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/worker-pool_v0.1.1", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/worker-pool_v0.1.0", + "date": "Fri, 20 May 2022 00:11:55 GMT", + "comments": { + "minor": [ + { + "comment": "Factor out WorkerPool from @rushstack/module-minifier-plugin." + } + ] + } + } + ] +} diff --git a/libraries/worker-pool/CHANGELOG.md b/libraries/worker-pool/CHANGELOG.md new file mode 100644 index 00000000000..31e982592a8 --- /dev/null +++ b/libraries/worker-pool/CHANGELOG.md @@ -0,0 +1,1073 @@ +# Change Log - @rushstack/worker-pool + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.6.7 +Sat, 06 Dec 2025 01:12:29 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.30 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.5.29 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.5.28 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.5.27 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.5.26 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.5.25 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.5.24 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.5.23 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.5.22 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.5.21 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.5.20 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.5.19 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.18 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.5.17 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.5.16 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.5.15 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.5.14 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.5.13 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.5.12 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.5.11 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.10 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.5.9 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.5.8 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.5.7 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.5.6 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.5.5 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.5.4 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.5.3 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.5.2 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.5.1 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.5.0 +Wed, 22 Jan 2025 03:03:47 GMT + +### Minor changes + +- Add a `workerResourceLimits` option to the `WorkerPool` constructor to control the available resources to the workers. + +## 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 + +_Version update only_ + +## 0.4.78 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.4.77 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.4.76 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.4.75 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.4.74 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.4.73 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.4.72 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.4.71 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.4.70 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.69 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.4.68 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.4.67 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.4.66 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.4.65 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.4.64 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.4.63 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.4.62 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.4.61 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.4.60 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.4.59 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.58 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.4.57 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.4.56 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.4.55 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.4.54 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.4.53 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.4.52 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.51 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.4.50 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.4.49 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.4.48 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.4.47 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.4.46 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.4.45 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.4.44 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.4.43 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.4.42 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.4.41 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.40 +Thu, 28 Mar 2024 22:42:23 GMT + +### Patches + +- Use `once` instead of `on` for `exit` event. + +## 0.4.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.4.38 +Fri, 15 Mar 2024 00:12:41 GMT + +_Version update only_ + +## 0.4.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.4.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.4.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.4.34 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.4.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.4.32 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 0.4.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.4.30 +Thu, 22 Feb 2024 01:36:10 GMT + +_Version update only_ + +## 0.4.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.4.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.4.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.4.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.4.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.4.24 +Sat, 17 Feb 2024 06:24:35 GMT + +### Patches + +- Fix broken link to API documentation + +## 0.4.23 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.4.22 +Wed, 07 Feb 2024 01:11:19 GMT + +_Version update only_ + +## 0.4.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.4.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.4.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.4.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.4.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.4.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.4.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.4.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.4.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.4.12 +Fri, 10 Nov 2023 18:02:05 GMT + +_Version update only_ + +## 0.4.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.4.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.4.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.4.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.4.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.4.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.4.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.4.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.4.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.4.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.4.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.3.37 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.3.36 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.3.35 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.3.34 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.3.33 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.3.32 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.3.31 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.3.30 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.3.29 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.3.28 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.3.27 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.3.26 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.3.25 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.3.24 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.3.23 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.3.22 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.3.21 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.3.20 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.3.19 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.3.18 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.3.17 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.3.16 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.3.15 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.3.14 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.3.13 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.3.12 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.3.11 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.3.10 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.3.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.3.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.3.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.3.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.3.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.3.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.3.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.3.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.3.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.3.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.2.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.1.48 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.47 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.46 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.1.45 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.44 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.1.43 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.42 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 0.1.41 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.40 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.39 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.38 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.37 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.36 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.35 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.34 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.33 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.32 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.31 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.30 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.1.29 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.28 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.27 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.26 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.25 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.24 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.23 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.22 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.1.21 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.20 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.19 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.18 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.17 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 0.1.16 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.15 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.14 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.13 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.12 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.11 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.1.10 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.9 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.8 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.7 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.6 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.5 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.1.4 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.3 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.2 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.1 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 0.1.0 +Fri, 20 May 2022 00:11:55 GMT + +### Minor changes + +- Factor out WorkerPool from @rushstack/module-minifier-plugin. + diff --git a/libraries/worker-pool/LICENSE b/libraries/worker-pool/LICENSE new file mode 100644 index 00000000000..9f8c78ac7eb --- /dev/null +++ b/libraries/worker-pool/LICENSE @@ -0,0 +1,24 @@ +@rushstack/worker-pool + +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/worker-pool/README.md b/libraries/worker-pool/README.md new file mode 100644 index 00000000000..7a35ca43590 --- /dev/null +++ b/libraries/worker-pool/README.md @@ -0,0 +1,12 @@ +# @rushstack/worker-pool + +This library contains a lightweight worker pool using the NodeJS worker_threads API. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/worker-pool/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/worker-pool/) + +`@rushstack/worker-pool` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/worker-pool/config/api-extractor.json b/libraries/worker-pool/config/api-extractor.json new file mode 100644 index 00000000000..996e271d3dd --- /dev/null +++ b/libraries/worker-pool/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + } +} diff --git a/libraries/worker-pool/config/jest.config.json b/libraries/worker-pool/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/libraries/worker-pool/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/worker-pool/config/rig.json b/libraries/worker-pool/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/worker-pool/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/worker-pool/eslint.config.js b/libraries/worker-pool/eslint.config.js new file mode 100644 index 00000000000..87132f43292 --- /dev/null +++ b/libraries/worker-pool/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/worker-pool/package.json b/libraries/worker-pool/package.json new file mode 100644 index 00000000000..894998b68c5 --- /dev/null +++ b/libraries/worker-pool/package.json @@ -0,0 +1,31 @@ +{ + "name": "@rushstack/worker-pool", + "version": "0.6.7", + "description": "Lightweight worker pool using NodeJS worker_threads", + "main": "lib/index.js", + "typings": "dist/worker-pool.d.ts", + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/worker-pool" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/libraries/worker-pool/src/WorkerPool.ts b/libraries/worker-pool/src/WorkerPool.ts new file mode 100644 index 00000000000..d47274673fd --- /dev/null +++ b/libraries/worker-pool/src/WorkerPool.ts @@ -0,0 +1,280 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type ResourceLimits, Worker } from 'node:worker_threads'; + +/** + * Symbol to read the ID off of a worker + * @internal + */ +export const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId'); + +/** + * @internal + */ +export interface IWorkerPoolOptions { + /** + * Identifier for this pool, to assign to its workers for tracking + */ + id: string; + /** + * Maximum number of concurrent workers this WorkerPool may spawn. + */ + maxWorkers: number; + /** + * Optional callback invoked when a worker is destroyed. + */ + onWorkerDestroyed?: () => void; + /** + * Optional callback invoked on a newly created worker. + */ + prepareWorker?: (worker: Worker) => void; + /** + * Optional data to pass to workers when they are initialized. + * Will be subjected to the Structured Clone algorithm. + */ + workerData?: unknown; + /** + * Absolute path to the worker script. + */ + workerScriptPath: string; + + /** + * Optional resource limits for the workers. + */ + workerResourceLimits?: ResourceLimits; +} + +/** + * Manages a pool of workers. + * Workers will be shutdown by sending them the boolean value `false` in a postMessage. + * @internal + */ +export class WorkerPool { + public id: string; + public maxWorkers: number; + + private readonly _alive: Worker[]; + private _error: Error | undefined; + private _finishing: boolean; + private readonly _idle: Worker[]; + private _nextId: number; + private readonly _onComplete: [() => void, (error: Error) => void][]; + private readonly _onWorkerDestroyed: (() => void) | undefined; + private readonly _pending: [(worker: Worker) => void, (error: Error) => void][]; + private readonly _prepare: ((worker: Worker) => void) | undefined; + private readonly _workerData: unknown; + private readonly _workerScript: string; + private readonly _workerResourceLimits: ResourceLimits | undefined; + + public constructor(options: IWorkerPoolOptions) { + const { + id, + maxWorkers, + onWorkerDestroyed, + prepareWorker, + workerData, + workerScriptPath, + workerResourceLimits + } = options; + + this.id = id; + this.maxWorkers = maxWorkers; + this._alive = []; + this._error = undefined; + this._finishing = false; + this._idle = []; + this._nextId = 0; + this._onComplete = []; + this._onWorkerDestroyed = onWorkerDestroyed; + this._pending = []; + this._prepare = prepareWorker; + this._workerData = workerData; + this._workerScript = workerScriptPath; + this._workerResourceLimits = workerResourceLimits; + } + + /** + * Gets the count of active workers. + */ + public getActiveCount(): number { + return this._alive.length - this._idle.length; + } + + /** + * Gets the count of idle workers. + */ + public getIdleCount(): number { + return this._idle.length; + } + + /** + * Gets the count of live workers. + */ + public getLiveCount(): number { + return this._alive.length; + } + + /** + * Tells the pool to shut down when all workers are done. + * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error. + */ + public async finishAsync(): Promise { + this._finishing = true; + + if (this._error) { + throw this._error; + } + + if (!this._alive.length) { + // The pool has no live workers, this is a no-op + return; + } + + // Clean up all idle workers + for (const worker of this._idle.splice(0)) { + worker.postMessage(false); + } + + // There are still active workers, wait for them to clean up. + await new Promise((resolve, reject) => this._onComplete.push([resolve, reject])); + } + + /** + * Resets the pool and allows more work + */ + public reset(): void { + this._finishing = false; + this._error = undefined; + } + + /** + * Returns a worker to the pool. If the pool is finishing, deallocates the worker. + * @param worker - The worker to free + */ + public checkinWorker(worker: Worker): void { + if (this._error) { + // Shut down the worker (failure) + worker.postMessage(false); + return; + } + + const next: [(worker: Worker) => void, unknown] | undefined = this._pending.shift(); + + if (next) { + // Perform the next unit of work; + next[0](worker); + } else if (this._finishing) { + // Shut down the worker (success) + worker.postMessage(false); + } else { + // No pending work, idle the workers + this._idle.push(worker); + } + } + + /** + * Checks out a currently available worker or waits for the next free worker. + * @param allowCreate - If creating new workers is allowed (subject to maxSize) + */ + public async checkoutWorkerAsync(allowCreate: boolean): Promise { + if (this._error) { + throw this._error; + } + + let worker: Worker | undefined = this._idle.shift(); + if (!worker && allowCreate) { + worker = this._createWorker(); + } + + if (worker) { + return worker; + } + + return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => { + this._pending.push([resolve, reject]); + }); + } + + /** + * Creates a new worker if allowed by maxSize. + */ + private _createWorker(): Worker | undefined { + if (this._alive.length >= this.maxWorkers) { + return; + } + + const worker: Worker & { + [WORKER_ID_SYMBOL]?: string; + } = new Worker(this._workerScript, { + eval: false, + workerData: this._workerData, + resourceLimits: this._workerResourceLimits + }); + + const id: string = `${this.id}#${++this._nextId}`; + worker[WORKER_ID_SYMBOL] = id; + + this._alive.push(worker); + + worker.on('error', (err) => { + this._onError(err); + this._destroyWorker(worker); + }); + + worker.once('exit', (exitCode) => { + if (exitCode !== 0) { + this._onError(new Error(`Worker ${id} exited with code ${exitCode}`)); + } + this._destroyWorker(worker); + }); + + if (this._prepare) { + this._prepare(worker); + } + + return worker; + } + + /** + * Cleans up a worker + */ + private _destroyWorker(worker: Worker): void { + const aliveIndex: number = this._alive.indexOf(worker); + if (aliveIndex >= 0) { + this._alive.splice(aliveIndex, 1); + } + + const freeIndex: number = this._idle.indexOf(worker); + if (freeIndex >= 0) { + this._idle.splice(freeIndex, 1); + } + + worker.unref(); + + if (this._onWorkerDestroyed) { + this._onWorkerDestroyed(); + } + + if (!this._alive.length && !this._error) { + for (const [resolve] of this._onComplete.splice(0)) { + resolve(); + } + } + } + + /** + * Notifies all pending callbacks that an error has occurred and switches this pool into error state. + */ + private _onError(error: Error): void { + this._error = error; + + for (const [, reject] of this._pending.splice(0)) { + reject(this._error); + } + + for (const [, reject] of this._onComplete.splice(0)) { + reject(this._error); + } + } +} diff --git a/libraries/worker-pool/src/index.ts b/libraries/worker-pool/src/index.ts new file mode 100644 index 00000000000..d7e7db46731 --- /dev/null +++ b/libraries/worker-pool/src/index.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. + +/// + +/** + * A lightweight worker pool implementation using the NodeJS `worker_threads` API. + * + * @packageDocumentation + */ + +export type { IWorkerPoolOptions } from './WorkerPool'; +export { WORKER_ID_SYMBOL, WorkerPool } from './WorkerPool'; diff --git a/libraries/worker-pool/tsconfig.json b/libraries/worker-pool/tsconfig.json new file mode 100644 index 00000000000..9a79fa4af11 --- /dev/null +++ b/libraries/worker-pool/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "target": "ES2019" + } +} diff --git a/repo-scripts/doc-plugin-rush-stack/.eslintrc.js b/repo-scripts/doc-plugin-rush-stack/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/repo-scripts/doc-plugin-rush-stack/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/repo-scripts/doc-plugin-rush-stack/config/rig.json b/repo-scripts/doc-plugin-rush-stack/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/repo-scripts/doc-plugin-rush-stack/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/repo-scripts/doc-plugin-rush-stack/eslint.config.js b/repo-scripts/doc-plugin-rush-stack/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/repo-scripts/doc-plugin-rush-stack/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/repo-scripts/doc-plugin-rush-stack/gulpfile.js b/repo-scripts/doc-plugin-rush-stack/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/repo-scripts/doc-plugin-rush-stack/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/repo-scripts/doc-plugin-rush-stack/package.json b/repo-scripts/doc-plugin-rush-stack/package.json index a36c80d8bcc..422186b3fdd 100644 --- a/repo-scripts/doc-plugin-rush-stack/package.json +++ b/repo-scripts/doc-plugin-rush-stack/package.json @@ -7,21 +7,20 @@ "typings": "lib/index.d.ts", "license": "MIT", "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@microsoft/api-documenter": "7.7.14", - "@microsoft/api-extractor-model": "7.7.9", - "@rushstack/node-core-library": "3.19.5", - "@microsoft/tsdoc": "0.12.14", - "js-yaml": "~3.13.1" + "@microsoft/api-documenter": "workspace:*", + "@microsoft/api-extractor-model": "workspace:*", + "@microsoft/tsdoc": "~0.16.0", + "@rushstack/node-core-library": "workspace:*", + "js-yaml": "~4.1.0" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/js-yaml": "3.12.1", - "@types/node": "10.17.13", - "gulp": "~4.0.2" + "@rushstack/heft": "workspace:*", + "@types/js-yaml": "4.0.9", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts b/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts index 07307dd6c36..5af1e34684b 100644 --- a/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts +++ b/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.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 yaml = require('js-yaml'); + import { FileSystem } from '@rushstack/node-core-library'; -import { ApiItem } from '@microsoft/api-extractor-model'; +import type { ApiItem } from '@microsoft/api-extractor-model'; import { MarkdownDocumenterFeature, - IMarkdownDocumenterFeatureOnBeforeWritePageArgs, - IMarkdownDocumenterFeatureOnFinishedArgs + type IMarkdownDocumenterFeatureOnBeforeWritePageArgs, + type IMarkdownDocumenterFeatureOnFinishedArgs } from '@microsoft/api-documenter'; interface INavigationNode { @@ -24,6 +26,7 @@ export class RushStackFeature extends MarkdownDocumenterFeature { private _apiItemsWithPages: Set = new Set(); public onInitialized(): void { + // eslint-disable-next-line no-console console.log('RushStackFeature: onInitialized()'); } @@ -54,7 +57,7 @@ export class RushStackFeature extends MarkdownDocumenterFeature { this._buildNavigation(navigationFile.api_nav, this.context.apiModel); const navFilePath: string = path.join(this.context.outputFolder, '..', 'api_nav.yaml'); - const navFileContent: string = yaml.safeDump(navigationFile, { lineWidth: 120 }); + const navFileContent: string = yaml.dump(navigationFile, { lineWidth: 120 }); FileSystem.writeFile(navFilePath, navFileContent, { ensureFolderExists: true }); } @@ -64,7 +67,9 @@ export class RushStackFeature extends MarkdownDocumenterFeature { if (this._apiItemsWithPages.has(apiItem)) { const newNode: INavigationNode = { title: apiItem.displayName, - url: path.posix.join('/pages/api/', this.context.documenter.getLinkForApiItem(apiItem)!).replace(/\.md$/, '') + url: path.posix + .join('/pages/api/', this.context.documenter.getLinkForApiItem(apiItem)!) + .replace(/\.md$/, '') }; parentNodes.push(newNode); diff --git a/repo-scripts/doc-plugin-rush-stack/src/index.ts b/repo-scripts/doc-plugin-rush-stack/src/index.ts index 682e121ef88..7b7171e5219 100644 --- a/repo-scripts/doc-plugin-rush-stack/src/index.ts +++ b/repo-scripts/doc-plugin-rush-stack/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 { IApiDocumenterPluginManifest } from '@microsoft/api-documenter'; +import type { IApiDocumenterPluginManifest } from '@microsoft/api-documenter'; + import { RushStackFeature } from './RushStackFeature'; export const apiDocumenterPluginManifest: IApiDocumenterPluginManifest = { diff --git a/repo-scripts/doc-plugin-rush-stack/tsconfig.json b/repo-scripts/doc-plugin-rush-stack/tsconfig.json index 0085de105f6..dac21d04081 100644 --- a/repo-scripts/doc-plugin-rush-stack/tsconfig.json +++ b/repo-scripts/doc-plugin-rush-stack/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/repo-scripts/generate-api-docs/api-documenter.json b/repo-scripts/generate-api-docs/api-documenter.json index 4847e0e9e26..a7d702a36c7 100644 --- a/repo-scripts/generate-api-docs/api-documenter.json +++ b/repo-scripts/generate-api-docs/api-documenter.json @@ -4,7 +4,7 @@ "plugins": [ { "packageName": "doc-plugin-rush-stack", - "enabledFeatureNames": [ "rush-stack-markdown-documenter" ] + "enabledFeatureNames": ["rush-stack-markdown-documenter"] } ] } diff --git a/repo-scripts/generate-api-docs/config/rush-project.json b/repo-scripts/generate-api-docs/config/rush-project.json new file mode 100644 index 00000000000..2af7036b0ef --- /dev/null +++ b/repo-scripts/generate-api-docs/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["lib", "dist"] + } + ] +} diff --git a/repo-scripts/generate-api-docs/package.json b/repo-scripts/generate-api-docs/package.json index 8646536577d..4af7d640fd0 100644 --- a/repo-scripts/generate-api-docs/package.json +++ b/repo-scripts/generate-api-docs/package.json @@ -5,11 +5,11 @@ "description": "Used to generate API docs for the rushstack.io website", "license": "MIT", "scripts": { - "build": "" + "build": "", + "_phase:build": "" }, "devDependencies": { - "doc-plugin-rush-stack": "1.0.0", - "@microsoft/api-documenter": "7.7.14", - "@rushstack/eslint-config": "0.5.5" + "@microsoft/api-documenter": "workspace:*", + "doc-plugin-rush-stack": "workspace:*" } } diff --git a/repo-scripts/repo-toolbox/.eslintrc.js b/repo-scripts/repo-toolbox/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/repo-scripts/repo-toolbox/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/repo-scripts/repo-toolbox/config/rig.json b/repo-scripts/repo-toolbox/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/repo-scripts/repo-toolbox/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/repo-scripts/repo-toolbox/eslint.config.js b/repo-scripts/repo-toolbox/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/repo-scripts/repo-toolbox/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/repo-scripts/repo-toolbox/gulpfile.js b/repo-scripts/repo-toolbox/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/repo-scripts/repo-toolbox/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/repo-scripts/repo-toolbox/package.json b/repo-scripts/repo-toolbox/package.json index d44054deeef..5a56b906323 100644 --- a/repo-scripts/repo-toolbox/package.json +++ b/repo-scripts/repo-toolbox/package.json @@ -5,19 +5,20 @@ "description": "Used to execute various operations specific to this repo", "license": "MIT", "scripts": { - "build": "gulp test --clean", - "readme": "node ./lib/start.js readme" + "build": "heft build --clean", + "readme": "node ./lib/start.js readme", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/node-core-library": "3.19.5", - "@microsoft/rush-lib": "5.22.0", - "@rushstack/ts-command-line": "4.3.12" + "@microsoft/rush-lib": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "diff": "~8.0.2" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/eslint-config": "0.5.5", - "@types/node": "10.17.13", - "gulp": "~4.0.2" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/repo-scripts/repo-toolbox/src/ReadmeAction.ts b/repo-scripts/repo-toolbox/src/ReadmeAction.ts deleted file mode 100644 index c708a03eaf9..00000000000 --- a/repo-scripts/repo-toolbox/src/ReadmeAction.ts +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. - -import * as path from 'path'; -import { StringBuilder, Text, Sort, FileSystem } from '@rushstack/node-core-library'; -import { RushConfiguration, RushConfigurationProject, LockStepVersionPolicy } from '@microsoft/rush-lib'; -import { CommandLineAction } from '@rushstack/ts-command-line'; - -export class ReadmeAction extends CommandLineAction { - public constructor() { - super({ - actionName: 'readme', - summary: 'Generates README.md project table based on rush.json inventory', - documentation: 'Use this to update the repo\'s README.md' - }); - } - - private static _isPublished(project: RushConfigurationProject): boolean { - return project.shouldPublish || !!project.versionPolicyName; - } - - protected onExecute(): Promise { // abstract - - const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); - - const builder: StringBuilder = new StringBuilder(); - const orderedProjects: RushConfigurationProject[] = [...rushConfiguration.projects]; - Sort.sortBy(orderedProjects, x => x.projectRelativeFolder); - - builder.append('## Published Packages\n\n'); - builder.append('\n\n'); - builder.append('| Folder | Version | Changelog | Package |\n'); - builder.append('| ------ | ------- | --------- | ------- |\n'); - for (const project of orderedProjects.filter(x => ReadmeAction._isPublished(x))) { - - // Example: - // - // | [/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) - // | - - const scopedName: string = project.packageName; // "@microsoft/api-extractor" - const folderPath: string = project.projectRelativeFolder; // "apps/api-extractor" - let escapedScopedName: string = scopedName; // "%40microsoft%2Fapi-extractor" - escapedScopedName = Text.replaceAll(escapedScopedName, '/', '%2F'); - escapedScopedName = Text.replaceAll(escapedScopedName, '@', '%40'); - - // | [/apps/api-extractor](./apps/api-extractor/) - builder.append(`| [/${folderPath}](./${folderPath}/) `); - - // | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor.svg - // )](https://badge.fury.io/js/%40microsoft%2Fapi-extractor) - builder.append(`| [![npm version](https://badge.fury.io/js/${escapedScopedName}.svg)]` - + `(https://badge.fury.io/js/${escapedScopedName}) `); - - let hasChangeLog: boolean = true; - if (project.versionPolicy instanceof LockStepVersionPolicy) { - if (project.versionPolicy.mainProject) { - if (project.versionPolicy.mainProject !== project.packageName) { - hasChangeLog = false; - } - } - } - - // | [changelog](./apps/api-extractor/CHANGELOG.md) - if (hasChangeLog) { - builder.append(`| [changelog](./${folderPath}/CHANGELOG.md) `); - } else { - builder.append(`| `); - } - - // | [@microsoft/api-extractor](https://www.npmjs.com/package/@microsoft/api-extractor) - builder.append(`| [${scopedName}](https://www.npmjs.com/package/${scopedName}) `); - - builder.append(`|\n`); - } - - builder.append('\n\n## Unpublished Local Projects\n\n'); - builder.append('\n\n'); - builder.append('| Folder | Description |\n'); - builder.append('| ------ | -----------|\n'); - for (const project of orderedProjects.filter(x => !ReadmeAction._isPublished(x))) { - const folderPath: string = project.projectRelativeFolder; // "apps/api-extractor" - - // | [/apps/api-extractor](./apps/api-extractor/) - builder.append(`| [/${folderPath}](./${folderPath}/) `); - - const description: string = (project.packageJson.description || '').replace(/[\n\r|]+/g, ''); - - builder.append(`| ${description} `); - - builder.append(`|\n`); - } - - const outputFilePath: string = path.resolve('./dist/README.md'); - - console.log('Writing ' + outputFilePath); - FileSystem.writeFile(outputFilePath, builder.toString(), { ensureFolderExists: true }); - - console.log('\nSuccess.'); - - return Promise.resolve(); - } - - protected onDefineParameters(): void { // abstract - } -} diff --git a/repo-scripts/repo-toolbox/src/ToolboxCommandLine.ts b/repo-scripts/repo-toolbox/src/ToolboxCommandLine.ts deleted file mode 100644 index a6a32c68d92..00000000000 --- a/repo-scripts/repo-toolbox/src/ToolboxCommandLine.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. - -import { - CommandLineParser -} from '@rushstack/ts-command-line'; -import { ReadmeAction } from './ReadmeAction'; - -export class ToolboxCommandLine extends CommandLineParser { - - public constructor() { - super({ - toolFilename: 'toolbox', - toolDescription: 'Used to execute various operations specific to this repo' - }); - - this.addAction(new ReadmeAction()); - } - - protected onDefineParameters(): void { // abstract - } - - protected onExecute(): Promise { // override - return super.onExecute(); - } -} \ No newline at end of file diff --git a/repo-scripts/repo-toolbox/src/cli/ToolboxCommandLine.ts b/repo-scripts/repo-toolbox/src/cli/ToolboxCommandLine.ts new file mode 100644 index 00000000000..aeadc6150cc --- /dev/null +++ b/repo-scripts/repo-toolbox/src/cli/ToolboxCommandLine.ts @@ -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 { CommandLineParser } from '@rushstack/ts-command-line'; +import { ConsoleTerminalProvider, type ITerminal, Terminal } from '@rushstack/terminal'; + +import { ReadmeAction } from './actions/ReadmeAction'; +import { RecordVersionsAction } from './actions/RecordVersionsAction'; +import { BumpDecoupledLocalDependencies } from './actions/BumpDecoupledLocalDependencies'; +import { CollectJsonSchemasAction } from './actions/CollectJsonSchemasAction'; + +export class ToolboxCommandLine extends CommandLineParser { + public constructor() { + super({ + toolFilename: 'toolbox', + toolDescription: 'Used to execute various operations specific to this repo' + }); + + const terminal: ITerminal = new Terminal(new ConsoleTerminalProvider()); + + this.addAction(new ReadmeAction(terminal)); + this.addAction(new RecordVersionsAction(terminal)); + this.addAction(new BumpDecoupledLocalDependencies(terminal)); + this.addAction(new CollectJsonSchemasAction(terminal)); + } +} diff --git a/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts new file mode 100644 index 00000000000..7d60e1e775f --- /dev/null +++ b/repo-scripts/repo-toolbox/src/cli/actions/BumpDecoupledLocalDependencies.ts @@ -0,0 +1,120 @@ +// 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 { Async, Executable, JsonFile } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { DependencyType, RushConfiguration, type CommonVersionsConfiguration } from '@microsoft/rush-lib'; +import { CommandLineAction } from '@rushstack/ts-command-line'; + +export class BumpDecoupledLocalDependencies extends CommandLineAction { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'bump-decoupled-local-dependencies', + summary: 'Updates decoupled local dependencies inside the repo.', + documentation: '' + }); + + this._terminal = terminal; + } + + protected override async onExecuteAsync(): Promise { + const terminal: ITerminal = this._terminal; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ + startingFolder: process.cwd() + }); + + const cyclicDependencyNames: Set = new Set(); + + for (const project of rushConfiguration.projects) { + for (const cyclicDependencyProject of project.decoupledLocalDependencies) { + cyclicDependencyNames.add(cyclicDependencyProject); + } + } + + const cyclicDependencyVersions: Map = new Map(); + await Async.forEachAsync( + Array.from(cyclicDependencyNames), + async (cyclicDependencyName) => { + const version: string = await this._getLatestPublishedVersionAsync(terminal, cyclicDependencyName); + cyclicDependencyVersions.set(cyclicDependencyName, version); + }, + { + concurrency: 10 + } + ); + + terminal.writeLine(); + + for (const project of rushConfiguration.projects) { + const commonVersions: CommonVersionsConfiguration = project.subspace.getCommonVersions(); + + for (const cyclicDependencyProject of project.decoupledLocalDependencies) { + const existingVersion: string | undefined = + project.packageJson.dependencies?.[cyclicDependencyProject] ?? + project.packageJson.devDependencies?.[cyclicDependencyProject]; + if ( + existingVersion && + commonVersions.allowedAlternativeVersions.get(cyclicDependencyProject)?.includes(existingVersion) + ) { + // Skip if the existing version is allowed by common-versions.json + continue; + } + + const newVersion: string = cyclicDependencyVersions.get(cyclicDependencyProject)!; + if (project.packageJsonEditor.tryGetDependency(cyclicDependencyProject)) { + project.packageJsonEditor.addOrUpdateDependency( + cyclicDependencyProject, + newVersion, + DependencyType.Regular + ); + } + + if (project.packageJsonEditor.tryGetDevDependency(cyclicDependencyProject)) { + project.packageJsonEditor.addOrUpdateDependency( + cyclicDependencyProject, + newVersion, + DependencyType.Dev + ); + } + } + + if (project.packageJsonEditor.saveIfModified()) { + terminal.writeLine(`Updated ${project.packageName}`); + } + } + + terminal.writeLine(); + + // Update the Rush version in rush.json + const latestRushVersion: string = await this._getLatestPublishedVersionAsync(terminal, '@microsoft/rush'); + const rushJson: { rushVersion: string } = await JsonFile.loadAsync(rushConfiguration.rushJsonFile); + rushJson.rushVersion = latestRushVersion; + await JsonFile.saveAsync(rushJson, rushConfiguration.rushJsonFile, { updateExistingFile: true }); + terminal.writeLine(`Updated ${rushConfiguration.rushJsonFile}`); + } + + private async _getLatestPublishedVersionAsync(terminal: ITerminal, packageName: string): Promise { + return await new Promise((resolve: (result: string) => void, reject: (error: Error) => void) => { + const childProcess: ChildProcess = Executable.spawn('npm', ['view', packageName, 'version'], { + stdio: ['ignore', 'pipe', 'pipe'] + }); + const stdoutBuffer: string[] = []; + childProcess.stdout!.on('data', (chunk) => stdoutBuffer.push(chunk)); + childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => { + if (exitCode) { + reject(new Error(`Exited with ${exitCode}`)); + } else if (signal) { + reject(new Error(`Terminated by ${signal}`)); + } else { + const version: string = stdoutBuffer.join('').trim(); + terminal.writeLine(`Found version "${version}" for "${packageName}"`); + resolve(version); + } + }); + }); + } +} diff --git a/repo-scripts/repo-toolbox/src/cli/actions/CollectJsonSchemasAction.ts b/repo-scripts/repo-toolbox/src/cli/actions/CollectJsonSchemasAction.ts new file mode 100644 index 00000000000..cdf38cb377a --- /dev/null +++ b/repo-scripts/repo-toolbox/src/cli/actions/CollectJsonSchemasAction.ts @@ -0,0 +1,138 @@ +// 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, AlreadyReportedError, Async, type FolderItem } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { RushConfiguration, type RushConfigurationProject } from '@microsoft/rush-lib'; +import { CommandLineAction, type IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; + +interface IFolderItemToCopy { + absolutePath: string; + relativePath: string; + content: string; +} + +async function* _getFolderItemsRecursiveAsync( + folderAbsolutePath: string, + folderRelativePath: string = '' +): AsyncIterable { + let folderItems: FolderItem[]; + try { + folderItems = await FileSystem.readFolderItemsAsync(folderAbsolutePath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } else { + return; + } + } + + for (const entry of folderItems) { + const entryRelativePath: string = `${folderRelativePath}/${entry.name}`; + const entryAbsolutePath: string = `${folderAbsolutePath}/${entry.name}`; + if (entry.isDirectory()) { + yield* _getFolderItemsRecursiveAsync(entryAbsolutePath, entryRelativePath); + } else { + const content: string = await FileSystem.readFileAsync(entryAbsolutePath); + yield { + absolutePath: entryAbsolutePath, + relativePath: entryRelativePath, + content + }; + } + } +} + +export class CollectJsonSchemasAction extends CommandLineAction { + private readonly _outputPathParameter: IRequiredCommandLineStringParameter; + + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'collect-json-schemas', + summary: 'Generates JSON schema files based on rush.json inventory', + documentation: "Use this to update the repo's JSON schema files" + }); + + this._terminal = terminal; + + this._outputPathParameter = this.defineStringParameter({ + parameterLongName: '--output-path', + description: 'Path to the output directory for the generated JSON schema files.', + argumentName: 'PATH', + required: true + }); + } + + protected override async onExecuteAsync(): Promise { + const terminal: ITerminal = this._terminal; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); + + const outputPath: string = path.resolve(this._outputPathParameter.value); + + const contentByAbsolutePathByRelativePath: Map> = new Map(); + + await Async.forEachAsync( + rushConfiguration.projects, + async ({ projectFolder }: RushConfigurationProject) => { + const schemaFiles: AsyncIterable = _getFolderItemsRecursiveAsync( + `${projectFolder}/temp/json-schemas`, + '' + ); + await Async.forEachAsync(schemaFiles, async ({ absolutePath, relativePath, content }) => { + let contentByAbsolutePath: Map | undefined = + contentByAbsolutePathByRelativePath.get(relativePath); + if (!contentByAbsolutePath) { + contentByAbsolutePath = new Map(); + contentByAbsolutePathByRelativePath.set(relativePath, contentByAbsolutePath); + } + + let absolutePaths: string[] | undefined = contentByAbsolutePath.get(content); + if (!absolutePaths) { + absolutePaths = []; + contentByAbsolutePath.set(content, absolutePaths); + } + + absolutePaths.push(absolutePath); + }, { concurrency: 5 }); + }, + { concurrency: 5 } + ); + + let encounteredCollisions: boolean = false; + const filesToWrite: Map = new Map(); + for (const [relativePath, contentByAbsolutePath] of contentByAbsolutePathByRelativePath) { + if (contentByAbsolutePath.size > 1) { + encounteredCollisions = true; + + terminal.writeErrorLine( + `Multiple projects generated different contents for the JSON schema "${relativePath}":` + ); + + for (const absolutePaths of contentByAbsolutePath.values()) { + for (const absolutePath of absolutePaths) { + terminal.writeErrorLine(` - ${absolutePath}`); + } + } + } else { + filesToWrite.set(`${outputPath}/${relativePath}`, Array.from(contentByAbsolutePath.keys())[0]); + } + } + + if (encounteredCollisions) { + throw new AlreadyReportedError(); + } else { + await FileSystem.ensureEmptyFolderAsync(outputPath); + + await Async.forEachAsync( + filesToWrite, + async ([outPath, content]) => + await FileSystem.writeFileAsync(outPath, content, { ensureFolderExists: true }), + { concurrency: 25 } + ); + } + } +} diff --git a/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts b/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.ts new file mode 100644 index 00000000000..6fa73e971a2 --- /dev/null +++ b/repo-scripts/repo-toolbox/src/cli/actions/ReadmeAction.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 Diff from 'diff'; + +import { StringBuilder, Sort, FileSystem, Text, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { RushConfiguration, type RushConfigurationProject, LockStepVersionPolicy } from '@microsoft/rush-lib'; +import { CommandLineAction, type CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +const GENERATED_PROJECT_SUMMARY_START_COMMENT_TEXT: string = ''; +const GENERATED_PROJECT_SUMMARY_END_COMMENT_TEXT: string = ''; + +const README_FILENAME: string = 'README.md'; + +export class ReadmeAction extends CommandLineAction { + private readonly _verifyParameter: CommandLineFlagParameter; + + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'readme', + summary: 'Generates README.md project table based on rush.json inventory', + documentation: "Use this to update the repo's README.md" + }); + + this._terminal = terminal; + + this._verifyParameter = this.defineFlagParameter({ + parameterLongName: '--verify', + parameterShortName: '-v', + description: 'Verify that the README.md file is up-to-date.' + }); + } + + private static _isPublished(project: RushConfigurationProject): boolean { + return project.shouldPublish || !!project.versionPolicyName; + } + + protected override async onExecuteAsync(): Promise { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); + + const repoReadmePath: string = `${rushConfiguration.rushJsonFolder}/${README_FILENAME}`; + let existingReadme: string = await FileSystem.readFileAsync(repoReadmePath); + existingReadme = Text.convertToLf(existingReadme); + const generatedProjectSummaryStartIndex: number = existingReadme.indexOf( + GENERATED_PROJECT_SUMMARY_START_COMMENT_TEXT + ); + const generatedProjectSummaryEndIndex: number = existingReadme.indexOf( + GENERATED_PROJECT_SUMMARY_END_COMMENT_TEXT + ); + + if (generatedProjectSummaryStartIndex === -1 || generatedProjectSummaryEndIndex === -1) { + throw new Error( + `Unable to find "${GENERATED_PROJECT_SUMMARY_START_COMMENT_TEXT}" or ` + + `"${GENERATED_PROJECT_SUMMARY_END_COMMENT_TEXT}" comment in "${repoReadmePath}"` + ); + } + + const readmePrefix: string = existingReadme.substring( + 0, + generatedProjectSummaryStartIndex + GENERATED_PROJECT_SUMMARY_START_COMMENT_TEXT.length + ); + + const readmePostfix: string = existingReadme.substring(generatedProjectSummaryEndIndex); + + const builder: StringBuilder = new StringBuilder(); + const orderedProjects: RushConfigurationProject[] = [...rushConfiguration.projects]; + Sort.sortBy(orderedProjects, (x) => x.projectRelativeFolder); + + builder.append(readmePrefix); + builder.append('\n'); + builder.append('\n'); + builder.append('## Published Packages\n\n'); + builder.append('\n\n'); + builder.append('| Folder | Version | Changelog | Package |\n'); + builder.append('| ------ | ------- | --------- | ------- |\n'); + for (const project of orderedProjects) { + if (!ReadmeAction._isPublished(project)) { + continue; + } + + // Example: + // + // | [/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) + // | + + const scopedName: string = project.packageName; // "@microsoft/api-extractor" + const folderPath: string = project.projectRelativeFolder; // "apps/api-extractor" + const escapedScopedName: string = encodeURIComponent(scopedName); // "%40microsoft%2Fapi-extractor" + + // | [/apps/api-extractor](./apps/api-extractor/) + builder.append(`| [/${folderPath}](./${folderPath}/) `); + + // | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor.svg + // )](https://badge.fury.io/js/%40microsoft%2Fapi-extractor) + builder.append( + `| [![npm version](https://badge.fury.io/js/${escapedScopedName}.svg)]` + + `(https://badge.fury.io/js/${escapedScopedName}) ` + ); + + let hasChangeLog: boolean = true; + if (project.versionPolicy instanceof LockStepVersionPolicy) { + if (project.versionPolicy.mainProject) { + if (project.versionPolicy.mainProject !== project.packageName) { + hasChangeLog = false; + } + } + } + + // | [changelog](./apps/api-extractor/CHANGELOG.md) + if (hasChangeLog) { + builder.append(`| [changelog](./${folderPath}/CHANGELOG.md) `); + } else { + builder.append(`| `); + } + + // | [@microsoft/api-extractor](https://www.npmjs.com/package/@microsoft/api-extractor) + builder.append(`| [${scopedName}](https://www.npmjs.com/package/${scopedName}) `); + + builder.append(`|\n`); + } + + builder.append('\n\n## Unpublished Local Projects\n\n'); + builder.append('\n\n'); + builder.append('| Folder | Description |\n'); + builder.append('| ------ | -----------|\n'); + for (const project of orderedProjects) { + if (ReadmeAction._isPublished(project)) { + continue; + } + + const folderPath: string = project.projectRelativeFolder; // "apps/api-extractor" + + // | [/apps/api-extractor](./apps/api-extractor/) + builder.append(`| [/${folderPath}](./${folderPath}/) `); + + const description: string = (project.packageJson.description || '').replace(/[\n\r|]+/g, ''); + + builder.append(`| ${description} `); + + builder.append(`|\n`); + } + + builder.append(readmePostfix); + + const readmeString: string = builder.toString(); + const diff: Diff.StructuredPatch = Diff.structuredPatch( + README_FILENAME, + README_FILENAME, + existingReadme, + readmeString + ); + const readmeIsUpToDate: boolean = diff.hunks.length === 0; + + const terminal: ITerminal = this._terminal; + + if (!readmeIsUpToDate) { + if (this._verifyParameter.value) { + terminal.writeLine(Diff.formatPatch(diff)); + + terminal.writeLine(); + terminal.writeLine(); + terminal.writeErrorLine( + `The README.md needs to be updated. Please run 'repo-toolbox readme' to update the README.md.` + ); + + throw new AlreadyReportedError(); + } else { + terminal.writeLine(`Writing ${repoReadmePath}`); + await FileSystem.writeFileAsync(repoReadmePath, readmeString); + terminal.writeLine(); + terminal.writeLine(Colorize.green('\nSuccess.')); + } + } else { + // eslint-disable-next-line no-console + console.log(`The README.md is up to date.`); + } + } +} diff --git a/repo-scripts/repo-toolbox/src/cli/actions/RecordVersionsAction.ts b/repo-scripts/repo-toolbox/src/cli/actions/RecordVersionsAction.ts new file mode 100644 index 00000000000..57dc988bdd5 --- /dev/null +++ b/repo-scripts/repo-toolbox/src/cli/actions/RecordVersionsAction.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 * as path from 'node:path'; + +import { JsonFile } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { RushConfiguration } from '@microsoft/rush-lib'; +import { CommandLineAction, type CommandLineStringParameter } from '@rushstack/ts-command-line'; + +export class RecordVersionsAction extends CommandLineAction { + private readonly _outFilePath: CommandLineStringParameter; + + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + super({ + actionName: 'record-versions', + summary: 'Generates a JSON file recording the version numbers of all published packages.', + documentation: '' + }); + + this._terminal = terminal; + + this._outFilePath = this.defineStringParameter({ + parameterLongName: '--out-file', + parameterShortName: '-o', + argumentName: 'FILE_PATH', + description: 'The path to the output file.', + required: true + }); + } + + protected override async onExecuteAsync(): Promise { + const terminal: ITerminal = this._terminal; + const rushConfig: RushConfiguration = RushConfiguration.loadFromDefaultLocation({ + startingFolder: process.cwd() + }); + + terminal.writeLine(`Found Rush configuration at ${rushConfig.rushJsonFile}`); + + const publishedPackageVersions: Record = {}; + for (const project of rushConfig.projects) { + if (project.shouldPublish || project.versionPolicy) { + publishedPackageVersions[project.packageName] = project.packageJson.version; + } + } + + const resolvedOutputPath: string = path.resolve(process.cwd(), this._outFilePath.value!); + await JsonFile.saveAsync(publishedPackageVersions, resolvedOutputPath, { + ensureFolderExists: true + }); + + terminal.writeLine(`Wrote file to ${resolvedOutputPath}`); + } +} diff --git a/repo-scripts/repo-toolbox/src/start.ts b/repo-scripts/repo-toolbox/src/start.ts index 26532cd9aae..11b0e4064c4 100644 --- a/repo-scripts/repo-toolbox/src/start.ts +++ b/repo-scripts/repo-toolbox/src/start.ts @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See the @microsoft/rush package's LICENSE file for license information. +// See LICENSE in the project root for license information. -import { ToolboxCommandLine } from './ToolboxCommandLine'; +import { ToolboxCommandLine } from './cli/ToolboxCommandLine'; +// eslint-disable-next-line no-console console.log('repo-toolbox\n'); const commandLine: ToolboxCommandLine = new ToolboxCommandLine(); -commandLine.execute().catch(console.error); // CommandLineParser.execute() should never reject the promise +// eslint-disable-next-line no-console +commandLine.executeAsync().catch(console.error); // CommandLineParser.executeAsync() should never reject the promise diff --git a/repo-scripts/repo-toolbox/tsconfig.json b/repo-scripts/repo-toolbox/tsconfig.json index 0085de105f6..dac21d04081 100644 --- a/repo-scripts/repo-toolbox/tsconfig.json +++ b/repo-scripts/repo-toolbox/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - - "compilerOptions": { - "types": [ - "node" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/repo-scripts/tombstone/README.md b/repo-scripts/tombstone/README.md index 674224145a1..6c3cdbc1c90 100644 --- a/repo-scripts/tombstone/README.md +++ b/repo-scripts/tombstone/README.md @@ -1,13 +1,12 @@ -# @microsoft/node-core-library +# @rushstack/localization-plugin -> Please use [@rushstack/node-core-library](https://www.npmjs.com/package/@rushstack/node-core-library) instead of this package. +> Please use [@rushstack/webpack4-localization-plugin](https://www.npmjs.com/package/@rushstack/webpack4-localization-plugin) instead of this package. -IMPORTANT: This package has moved under the `@rushstack` NPM scope. +IMPORTANT: This package has been renamed to @rushstack/webpack4-localization-plugin. -``` - OLD NAME: @microsoft/node-core-library (3.19.3) - NEW NAME: @rushstack/node-core-library (3.19.4) -``` +> OLD NAME: @rushstack/localization-plugin (0.14.4) +> +> NEW NAME: @rushstack/webpack4-localization-plugin (0.14.5) The new package's CHANGELOG.md preserves version history from before the rename. diff --git a/repo-scripts/tombstone/package.json b/repo-scripts/tombstone/package.json index fd9acececcf..22eb02651ec 100644 --- a/repo-scripts/tombstone/package.json +++ b/repo-scripts/tombstone/package.json @@ -1,7 +1,7 @@ { - "name": "@microsoft/node-core-library", - "version": "4.0.0", - "description": "(Please use \"@rushstack/node-core-library\" instead.)", + "name": "@rushstack/localization-plugin", + "version": "0.15.0", + "description": "@rushstack/localization-plugin has been renamed to @rushstack/webpack4-localization-plugin.", "license": "MIT", "scripts": { "postinstall": "node postinstall.js" diff --git a/repo-scripts/tombstone/postinstall.js b/repo-scripts/tombstone/postinstall.js index 5e406648d42..ceb89cf9704 100644 --- a/repo-scripts/tombstone/postinstall.js +++ b/repo-scripts/tombstone/postinstall.js @@ -1,24 +1,13 @@ - function writeErrorInRed(message) { console.error(''); console.error('\u001b[31m' + message + '\u001b[39m'); } -writeErrorInRed( -`* * * * * * * * * * * * * THIS PACKAGE WAS RENAMED! * * * * * * * * * * * * * *`); +writeErrorInRed(`* * * * * * * * * * * * * THIS PACKAGE WAS DEPRECATED! * * * * * * * * * * * * * *`); console.error(` -IMPORTANT: This package has moved under the "@rushstack" NPM scope. - -OLD NAME: @microsoft/node-core-library (3.19.3) -NEW NAME: @rushstack/node-core-library (3.19.4) - -The new package's CHANGELOG.md preserves version history from before the rename. -The new package starts with a SemVer PATCH increment, since no code has changed. -To learn about the Rush Stack project, please visit https://rushstack.io/` -); +@rushstack/localization-plugin has been renamed to @rushstack/webpack4-localization-plugin.`); -writeErrorInRed( -`* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n`); +writeErrorInRed(`* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n`); process.exit(1); diff --git a/rigs/decoupled-local-node-rig/README.md b/rigs/decoupled-local-node-rig/README.md new file mode 100644 index 00000000000..7bbdb6f2afe --- /dev/null +++ b/rigs/decoupled-local-node-rig/README.md @@ -0,0 +1,7 @@ +# local-node-rig + +A rig package for Node.js projects that build using Heft inside the RushStack repository. This +package extends `@rushstack/heft-node-rig` and adds some options that are specific to the RushStack +repository. + +Note that this rig is not published to the NPM registry. \ No newline at end of file diff --git a/rigs/decoupled-local-node-rig/package.json b/rigs/decoupled-local-node-rig/package.json new file mode 100644 index 00000000000..bdd61eec2c1 --- /dev/null +++ b/rigs/decoupled-local-node-rig/package.json @@ -0,0 +1,32 @@ +{ + "name": "decoupled-local-node-rig", + "version": "1.0.0", + "description": "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.", + "license": "MIT", + "private": true, + "scripts": { + "build": "", + "_phase:build": "" + }, + "dependencies": { + "@microsoft/api-extractor": "7.54.0", + "@rushstack/eslint-config": "4.5.3", + "@rushstack/eslint-patch": "1.14.1", + "@rushstack/eslint-plugin": "0.22.0", + "@rushstack/heft-node-rig": "2.11.6", + "@rushstack/heft": "1.1.4", + "@types/heft-jest": "1.0.1", + "@types/node": "20.17.19", + "@typescript-eslint/eslint-plugin": "~8.46.0", + "@typescript-eslint/parser": "~8.46.0", + "eslint-plugin-header": "~3.1.1", + "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", + "eslint": "~9.37.0", + "jest-junit": "12.3.0", + "typescript": "~5.8.2", + "eslint-import-resolver-node": "0.3.9" + } +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/api-extractor-task.json b/rigs/decoupled-local-node-rig/profiles/default/config/api-extractor-task.json new file mode 100644 index 00000000000..17416c0226f --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/config/api-extractor-task.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/api-extractor-task.json" +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/heft.json b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json new file mode 100644 index 00000000000..437ad9b13ba --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/config/heft.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json" +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/jest.config.json b/rigs/decoupled-local-node-rig/profiles/default/config/jest.config.json new file mode 100644 index 00000000000..1127530a185 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/config/jest.config.json @@ -0,0 +1,26 @@ +{ + "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", + + // Enable junit reporting for Jest + "reporters": [ + "default", + [ + "jest-junit", + { + "outputDirectory": "./coverage", + "classNameTemplate": "{classname} > ", + "titleTemplate": "{title} ({filepath})" + } + ] + ], + + "resolver": "@rushstack/heft-jest-plugin/lib/exports/jest-node-modules-symlink-resolver.js" +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/rush-project.json b/rigs/decoupled-local-node-rig/profiles/default/config/rush-project.json new file mode 100644 index 00000000000..b3e191a2bb6 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "lib-esnext"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/config/typescript.json b/rigs/decoupled-local-node-rig/profiles/default/config/typescript.json new file mode 100644 index 00000000000..c86f0a36a0d --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/config/typescript.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/typescript.json", + + "onlyResolveSymlinksInNodeModules": true +} diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..860b58395f6 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js @@ -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. + +const friendlyLocalsMixin = require('@rushstack/eslint-config/flat/mixins/friendly-locals'); + +module.exports = [...friendlyLocalsMixin]; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..61892fd848d --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js @@ -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. + +const packletsMixin = require('@rushstack/eslint-config/flat/mixins/packlets'); + +module.exports = { ...packletsMixin }; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/react.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/react.js new file mode 100644 index 00000000000..15deb89fa31 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/react.js @@ -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. + +// 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/flat/mixins/react) +// - eslint-plugin-react-hooks +// +// 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 +// +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const reactHooksEslintPlugin = require('eslint-plugin-react-hooks'); +const reactMixin = require('@rushstack/eslint-config/flat/mixins/react'); + +module.exports = [ + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + 'react-hooks': reactHooksEslintPlugin + }, + 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/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..342d3612a97 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js @@ -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. + +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const jsdocEslintPlugin = require('eslint-plugin-jsdoc'); +const tsdocMixin = require('@rushstack/eslint-config/flat/mixins/tsdoc'); + +module.exports = [ + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + jsdoc: jsdocEslintPlugin + }, + 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' + } + }, + { + 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: {} + } +]; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..12c37b253da --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-patch/eslint-bulk-suppressions'); diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/_common.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/_common.js new file mode 100644 index 00000000000..144f0598919 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/_common.js @@ -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. + +const { expandNamingConventionSelectors } = require('@rushstack/eslint-config/flat/profile/_macros'); +const { commonNamingConventionSelectors } = require('@rushstack/eslint-config/flat/profile/_common'); +const rushstackEslintPlugin = require('@rushstack/eslint-plugin'); +const typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin'); +const importEslintPlugin = require('eslint-plugin-import'); +const headersEslintPlugin = require('eslint-plugin-headers'); + +const nodeImportResolverPath = require.resolve('eslint-import-resolver-node'); + +module.exports = { + localCommonConfig: [ + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + '@rushstack': rushstackEslintPlugin, + '@typescript-eslint': typescriptEslintPlugin, + import: importEslintPlugin, + headers: headersEslintPlugin + }, + settings: { + 'import/resolver': nodeImportResolverPath + }, + 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, + checkThenables: 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', + + 'headers/header-format': [ + 'warn', + { + source: 'string', + style: 'line', + trailingNewlines: 2, + content: + 'Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n' + + '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', + ...expandNamingConventionSelectors([ + ...commonNamingConventionSelectors, + { + 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 + } + } + ]) + ], + + // Require `node:` protocol for imports of Node.js built-in modules + 'import/enforce-node-protocol-usage': ['warn', 'always'], + + // Group imports in the following way: + // 1. Built-in modules (fs, path, etc.) + // 2. External modules (lodash, react, etc.) + // a. `@rushstack` and `@microsoft` scoped packages + // 3. Internal modules (and other types: parent, sibling, index) + 'import/order': [ + 'warn', + { + // This option ensures that the @rushstack and @microsoft packages end up in their own group + distinctGroup: true, + pathGroups: [ + { + pattern: '@{rushstack,microsoft}/**', + group: 'external', + position: 'after' + } + ], + // Ensure the @rushstack and @microsoft packages are grouped with other external packages. By default this + // option includes 'external' + pathGroupsExcludedImportTypes: ['builtin', 'object'], + groups: [ + 'builtin', + 'external' + // And then everything else (internal, parent, sibling, index) + ], + 'newlines-between': 'always' + } + ], + + 'import/no-duplicates': 'warn' + } + }, + { + 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: { + 'import/order': 'off', + 'import/no-duplicates': 'off' + } + } + ] +}; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js new file mode 100644 index 00000000000..69c3662a206 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js @@ -0,0 +1,19 @@ +// 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/flat/profiles/node" instead. + +const nodeTrustedToolProfile = require('@rushstack/eslint-config/flat/profile/node-trusted-tool'); + +const { localCommonConfig } = require('./_common'); + +module.exports = [...nodeTrustedToolProfile, ...localCommonConfig]; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node.js new file mode 100644 index 00000000000..0b3e77ec0e7 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node.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 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 nodeProfile = require('@rushstack/eslint-config/flat/profile/node'); + +const { localCommonConfig } = require('./_common'); + +module.exports = [...nodeProfile, ...localCommonConfig]; diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/web-app.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/web-app.js new file mode 100644 index 00000000000..7990844a462 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/web-app.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. + +// 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 typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin'); +const webAppProfile = require('@rushstack/eslint-config/flat/profile/web-app'); + +const { localCommonConfig } = require('./_common'); + +module.exports = [ + ...webAppProfile, + ...localCommonConfig, + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + '@typescript-eslint': typescriptEslintPlugin + }, + rules: { + // Rationale: Importing a module with `require` cannot be optimized by webpack as effectively as + // `import` statements. + '@typescript-eslint/no-require-imports': 'error' + } + } +]; diff --git a/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json new file mode 100644 index 00000000000..dff2ef99dc1 --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/tsconfig-base.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "extends": "../../node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + + "compilerOptions": { + "resolveJsonModule": true, + "isolatedModules": true, + "target": "es2018", + + "outDir": "../../../../lib", + "rootDir": "../../../../src", + + "types": ["heft-jest", "node"], + "typeRoots": ["../../../../node_modules/@types", "../../node_modules/@types"] + }, + "include": ["../../../../src/**/*.ts", "../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-node-rig/.npmignore b/rigs/heft-node-rig/.npmignore new file mode 100644 index 00000000000..2b485313c3f --- /dev/null +++ b/rigs/heft-node-rig/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/profiles/** +!/shared/** diff --git a/rigs/heft-node-rig/CHANGELOG.json b/rigs/heft-node-rig/CHANGELOG.json new file mode 100644 index 00000000000..1668e32bf9b --- /dev/null +++ b/rigs/heft-node-rig/CHANGELOG.json @@ -0,0 +1,8705 @@ +{ + "name": "@rushstack/heft-node-rig", + "entries": [ + { + "version": "2.11.12", + "tag": "@rushstack/heft-node-rig_v2.11.12", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "2.11.11", + "tag": "@rushstack/heft-node-rig_v2.11.11", + "date": "Wed, 03 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.9`" + } + ] + } + }, + { + "version": "2.11.10", + "tag": "@rushstack/heft-node-rig_v2.11.10", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "2.11.9", + "tag": "@rushstack/heft-node-rig_v2.11.9", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.7`" + } + ] + } + }, + { + "version": "2.11.8", + "tag": "@rushstack/heft-node-rig_v2.11.8", + "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/eslint-config\" to `4.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.6`" + }, + { + "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": "2.11.7", + "tag": "@rushstack/heft-node-rig_v2.11.7", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.5`" + } + ] + } + }, + { + "version": "2.11.6", + "tag": "@rushstack/heft-node-rig_v2.11.6", + "date": "Mon, 10 Nov 2025 16:12:32 GMT", + "comments": { + "patch": [ + { + "comment": "Include lib-dts and lib-esm folders in default files to clean" + } + ] + } + }, + { + "version": "2.11.5", + "tag": "@rushstack/heft-node-rig_v2.11.5", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.4`" + }, + { + "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": "2.11.4", + "tag": "@rushstack/heft-node-rig_v2.11.4", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.3`" + } + ] + } + }, + { + "version": "2.11.3", + "tag": "@rushstack/heft-node-rig_v2.11.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "2.11.2", + "tag": "@rushstack/heft-node-rig_v2.11.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "2.11.1", + "tag": "@rushstack/heft-node-rig_v2.11.1", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.1`" + } + ] + } + }, + { + "version": "2.11.0", + "tag": "@rushstack/heft-node-rig_v2.11.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-config\" to `4.5.0`" + } + ] + } + }, + { + "version": "2.10.2", + "tag": "@rushstack/heft-node-rig_v2.10.2", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "2.10.1", + "tag": "@rushstack/heft-node-rig_v2.10.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.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/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "2.10.0", + "tag": "@rushstack/heft-node-rig_v2.10.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "minor": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "2.9.7", + "tag": "@rushstack/heft-node-rig_v2.9.7", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "2.9.6", + "tag": "@rushstack/heft-node-rig_v2.9.6", + "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-api-extractor-plugin\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.6`" + }, + { + "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": "2.9.5", + "tag": "@rushstack/heft-node-rig_v2.9.5", + "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-api-extractor-plugin\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "2.9.4", + "tag": "@rushstack/heft-node-rig_v2.9.4", + "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-api-extractor-plugin\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.4`" + }, + { + "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": "2.9.3", + "tag": "@rushstack/heft-node-rig_v2.9.3", + "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-api-extractor-plugin\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.3`" + }, + { + "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": "2.9.2", + "tag": "@rushstack/heft-node-rig_v2.9.2", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.10`" + } + ] + } + }, + { + "version": "2.9.1", + "tag": "@rushstack/heft-node-rig_v2.9.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "2.9.0", + "tag": "@rushstack/heft-node-rig_v2.9.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add flat config compatible versions of profiles and mixins for ESLint. These are located under the `profiles/default/includes/eslint/flat/*` path. If you need to remain on ESLint 8, ensure your rig or project consumes ESLint 8, and that you use the legacy configuration files." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "2.8.15", + "tag": "@rushstack/heft-node-rig_v2.8.15", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.6.1`" + }, + { + "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": "2.8.14", + "tag": "@rushstack/heft-node-rig_v2.8.14", + "date": "Fri, 06 Jun 2025 00:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "2.8.13", + "tag": "@rushstack/heft-node-rig_v2.8.13", + "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-api-extractor-plugin\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.38`" + }, + { + "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": "2.8.12", + "tag": "@rushstack/heft-node-rig_v2.8.12", + "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-api-extractor-plugin\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.37`" + }, + { + "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": "2.8.11", + "tag": "@rushstack/heft-node-rig_v2.8.11", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "2.8.10", + "tag": "@rushstack/heft-node-rig_v2.8.10", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.35`" + }, + { + "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": "2.8.9", + "tag": "@rushstack/heft-node-rig_v2.8.9", + "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-api-extractor-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.34`" + }, + { + "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": "2.8.8", + "tag": "@rushstack/heft-node-rig_v2.8.8", + "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-api-extractor-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.33`" + }, + { + "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": "2.8.7", + "tag": "@rushstack/heft-node-rig_v2.8.7", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.32`" + }, + { + "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": "2.8.6", + "tag": "@rushstack/heft-node-rig_v2.8.6", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.31`" + }, + { + "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": "2.8.5", + "tag": "@rushstack/heft-node-rig_v2.8.5", + "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-api-extractor-plugin\" to `0.3.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "2.8.4", + "tag": "@rushstack/heft-node-rig_v2.8.4", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "2.8.3", + "tag": "@rushstack/heft-node-rig_v2.8.3", + "date": "Tue, 25 Mar 2025 00:12:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.28`" + } + ] + } + }, + { + "version": "2.8.2", + "tag": "@rushstack/heft-node-rig_v2.8.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "2.8.1", + "tag": "@rushstack/heft-node-rig_v2.8.1", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "2.8.0", + "tag": "@rushstack/heft-node-rig_v2.8.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump TypeScript to ~5.8.2." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "2.7.2", + "tag": "@rushstack/heft-node-rig_v2.7.2", + "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-api-extractor-plugin\" to `0.3.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "2.7.1", + "tag": "@rushstack/heft-node-rig_v2.7.1", + "date": "Thu, 06 Mar 2025 01:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.23`" + } + ] + } + }, + { + "version": "2.7.0", + "tag": "@rushstack/heft-node-rig_v2.7.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `typescript` dependency to `~5.7.3`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.15`" + } + ] + } + }, + { + "version": "2.6.59", + "tag": "@rushstack/heft-node-rig_v2.6.59", + "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-api-extractor-plugin\" to `0.3.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "2.6.58", + "tag": "@rushstack/heft-node-rig_v2.6.58", + "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-api-extractor-plugin\" to `0.3.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "2.6.57", + "tag": "@rushstack/heft-node-rig_v2.6.57", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "2.6.56", + "tag": "@rushstack/heft-node-rig_v2.6.56", + "date": "Tue, 25 Feb 2025 01:11:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.18`" + } + ] + } + }, + { + "version": "2.6.55", + "tag": "@rushstack/heft-node-rig_v2.6.55", + "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-api-extractor-plugin\" to `0.3.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "2.6.54", + "tag": "@rushstack/heft-node-rig_v2.6.54", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "2.6.53", + "tag": "@rushstack/heft-node-rig_v2.6.53", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "2.6.52", + "tag": "@rushstack/heft-node-rig_v2.6.52", + "date": "Fri, 07 Feb 2025 01:10:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.6`" + } + ] + } + }, + { + "version": "2.6.51", + "tag": "@rushstack/heft-node-rig_v2.6.51", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "2.6.50", + "tag": "@rushstack/heft-node-rig_v2.6.50", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "2.6.49", + "tag": "@rushstack/heft-node-rig_v2.6.49", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "2.6.48", + "tag": "@rushstack/heft-node-rig_v2.6.48", + "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-api-extractor-plugin\" to `0.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, + { + "version": "2.6.47", + "tag": "@rushstack/heft-node-rig_v2.6.47", + "date": "Tue, 07 Jan 2025 16:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.1.1`" + } + ] + } + }, + { + "version": "2.6.46", + "tag": "@rushstack/heft-node-rig_v2.6.46", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "2.6.45", + "tag": "@rushstack/heft-node-rig_v2.6.45", + "date": "Tue, 10 Dec 2024 07:32:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.0`" + } + ] + } + }, + { + "version": "2.6.44", + "tag": "@rushstack/heft-node-rig_v2.6.44", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "2.6.43", + "tag": "@rushstack/heft-node-rig_v2.6.43", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "2.6.42", + "tag": "@rushstack/heft-node-rig_v2.6.42", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "2.6.41", + "tag": "@rushstack/heft-node-rig_v2.6.41", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "2.6.40", + "tag": "@rushstack/heft-node-rig_v2.6.40", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "2.6.39", + "tag": "@rushstack/heft-node-rig_v2.6.39", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "2.6.38", + "tag": "@rushstack/heft-node-rig_v2.6.38", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "2.6.37", + "tag": "@rushstack/heft-node-rig_v2.6.37", + "date": "Wed, 16 Oct 2024 00:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.32`" + } + ] + } + }, + { + "version": "2.6.36", + "tag": "@rushstack/heft-node-rig_v2.6.36", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "2.6.35", + "tag": "@rushstack/heft-node-rig_v2.6.35", + "date": "Thu, 10 Oct 2024 00:11:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "2.6.34", + "tag": "@rushstack/heft-node-rig_v2.6.34", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "2.6.33", + "tag": "@rushstack/heft-node-rig_v2.6.33", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "2.6.32", + "tag": "@rushstack/heft-node-rig_v2.6.32", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "2.6.31", + "tag": "@rushstack/heft-node-rig_v2.6.31", + "date": "Thu, 19 Sep 2024 00:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.2`" + } + ] + } + }, + { + "version": "2.6.30", + "tag": "@rushstack/heft-node-rig_v2.6.30", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "2.6.29", + "tag": "@rushstack/heft-node-rig_v2.6.29", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "2.6.28", + "tag": "@rushstack/heft-node-rig_v2.6.28", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "2.6.27", + "tag": "@rushstack/heft-node-rig_v2.6.27", + "date": "Wed, 14 Aug 2024 22:37:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.0`" + } + ] + } + }, + { + "version": "2.6.26", + "tag": "@rushstack/heft-node-rig_v2.6.26", + "date": "Tue, 13 Aug 2024 18:17:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.48`" + } + ] + } + }, + { + "version": "2.6.25", + "tag": "@rushstack/heft-node-rig_v2.6.25", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "2.6.24", + "tag": "@rushstack/heft-node-rig_v2.6.24", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "2.6.23", + "tag": "@rushstack/heft-node-rig_v2.6.23", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "2.6.22", + "tag": "@rushstack/heft-node-rig_v2.6.22", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "2.6.21", + "tag": "@rushstack/heft-node-rig_v2.6.21", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "2.6.20", + "tag": "@rushstack/heft-node-rig_v2.6.20", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "2.6.19", + "tag": "@rushstack/heft-node-rig_v2.6.19", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "2.6.18", + "tag": "@rushstack/heft-node-rig_v2.6.18", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "2.6.17", + "tag": "@rushstack/heft-node-rig_v2.6.17", + "date": "Tue, 11 Jun 2024 00:21:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.0`" + } + ] + } + }, + { + "version": "2.6.16", + "tag": "@rushstack/heft-node-rig_v2.6.16", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "2.6.15", + "tag": "@rushstack/heft-node-rig_v2.6.15", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "2.6.14", + "tag": "@rushstack/heft-node-rig_v2.6.14", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "2.6.13", + "tag": "@rushstack/heft-node-rig_v2.6.13", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "2.6.12", + "tag": "@rushstack/heft-node-rig_v2.6.12", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "2.6.11", + "tag": "@rushstack/heft-node-rig_v2.6.11", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "2.6.10", + "tag": "@rushstack/heft-node-rig_v2.6.10", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "2.6.9", + "tag": "@rushstack/heft-node-rig_v2.6.9", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "2.6.8", + "tag": "@rushstack/heft-node-rig_v2.6.8", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "2.6.7", + "tag": "@rushstack/heft-node-rig_v2.6.7", + "date": "Fri, 17 May 2024 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.10`" + } + ] + } + }, + { + "version": "2.6.6", + "tag": "@rushstack/heft-node-rig_v2.6.6", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "2.6.5", + "tag": "@rushstack/heft-node-rig_v2.6.5", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "2.6.4", + "tag": "@rushstack/heft-node-rig_v2.6.4", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "2.6.3", + "tag": "@rushstack/heft-node-rig_v2.6.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "2.6.2", + "tag": "@rushstack/heft-node-rig_v2.6.2", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "2.6.1", + "tag": "@rushstack/heft-node-rig_v2.6.1", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "2.6.0", + "tag": "@rushstack/heft-node-rig_v2.6.0", + "date": "Wed, 10 Apr 2024 21:59:39 GMT", + "comments": { + "minor": [ + { + "comment": "Bump ESLint to ~8.57.0." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.9`" + } + ] + } + }, + { + "version": "2.5.6", + "tag": "@rushstack/heft-node-rig_v2.5.6", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "2.5.5", + "tag": "@rushstack/heft-node-rig_v2.5.5", + "date": "Fri, 29 Mar 2024 05:46:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.8`" + } + ] + } + }, + { + "version": "2.5.4", + "tag": "@rushstack/heft-node-rig_v2.5.4", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "2.5.3", + "tag": "@rushstack/heft-node-rig_v2.5.3", + "date": "Thu, 28 Mar 2024 18:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.7`" + } + ] + } + }, + { + "version": "2.5.2", + "tag": "@rushstack/heft-node-rig_v2.5.2", + "date": "Wed, 27 Mar 2024 19:47:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.6`" + } + ] + } + }, + { + "version": "2.5.1", + "tag": "@rushstack/heft-node-rig_v2.5.1", + "date": "Wed, 20 Mar 2024 02:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.5`" + } + ] + } + }, + { + "version": "2.5.0", + "tag": "@rushstack/heft-node-rig_v2.5.0", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 5.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "2.4.25", + "tag": "@rushstack/heft-node-rig_v2.4.25", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "2.4.24", + "tag": "@rushstack/heft-node-rig_v2.4.24", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "2.4.23", + "tag": "@rushstack/heft-node-rig_v2.4.23", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "2.4.22", + "tag": "@rushstack/heft-node-rig_v2.4.22", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "2.4.21", + "tag": "@rushstack/heft-node-rig_v2.4.21", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "2.4.20", + "tag": "@rushstack/heft-node-rig_v2.4.20", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "2.4.19", + "tag": "@rushstack/heft-node-rig_v2.4.19", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "2.4.18", + "tag": "@rushstack/heft-node-rig_v2.4.18", + "date": "Mon, 26 Feb 2024 16:10:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.15`" + } + ] + } + }, + { + "version": "2.4.17", + "tag": "@rushstack/heft-node-rig_v2.4.17", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "2.4.16", + "tag": "@rushstack/heft-node-rig_v2.4.16", + "date": "Thu, 22 Feb 2024 05:54:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.14`" + } + ] + } + }, + { + "version": "2.4.15", + "tag": "@rushstack/heft-node-rig_v2.4.15", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "2.4.14", + "tag": "@rushstack/heft-node-rig_v2.4.14", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "2.4.13", + "tag": "@rushstack/heft-node-rig_v2.4.13", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "2.4.12", + "tag": "@rushstack/heft-node-rig_v2.4.12", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "2.4.11", + "tag": "@rushstack/heft-node-rig_v2.4.11", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "2.4.10", + "tag": "@rushstack/heft-node-rig_v2.4.10", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "2.4.9", + "tag": "@rushstack/heft-node-rig_v2.4.9", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "2.4.8", + "tag": "@rushstack/heft-node-rig_v2.4.8", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "2.4.7", + "tag": "@rushstack/heft-node-rig_v2.4.7", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "2.4.6", + "tag": "@rushstack/heft-node-rig_v2.4.6", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "2.4.5", + "tag": "@rushstack/heft-node-rig_v2.4.5", + "date": "Thu, 25 Jan 2024 23:03:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.2`" + } + ] + } + }, + { + "version": "2.4.4", + "tag": "@rushstack/heft-node-rig_v2.4.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "2.4.3", + "tag": "@rushstack/heft-node-rig_v2.4.3", + "date": "Wed, 24 Jan 2024 07:38:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.1`" + } + ] + } + }, + { + "version": "2.4.2", + "tag": "@rushstack/heft-node-rig_v2.4.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "2.4.1", + "tag": "@rushstack/heft-node-rig_v2.4.1", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "2.4.0", + "tag": "@rushstack/heft-node-rig_v2.4.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "2.3.16", + "tag": "@rushstack/heft-node-rig_v2.3.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "2.3.15", + "tag": "@rushstack/heft-node-rig_v2.3.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "2.3.14", + "tag": "@rushstack/heft-node-rig_v2.3.14", + "date": "Fri, 15 Dec 2023 01:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.5.1`" + } + ] + } + }, + { + "version": "2.3.13", + "tag": "@rushstack/heft-node-rig_v2.3.13", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "2.3.12", + "tag": "@rushstack/heft-node-rig_v2.3.12", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "2.3.11", + "tag": "@rushstack/heft-node-rig_v2.3.11", + "date": "Wed, 22 Nov 2023 01:45:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.5.0`" + } + ] + } + }, + { + "version": "2.3.10", + "tag": "@rushstack/heft-node-rig_v2.3.10", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "2.3.9", + "tag": "@rushstack/heft-node-rig_v2.3.9", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "2.3.8", + "tag": "@rushstack/heft-node-rig_v2.3.8", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "2.3.7", + "tag": "@rushstack/heft-node-rig_v2.3.7", + "date": "Thu, 26 Oct 2023 00:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.1`" + } + ] + } + }, + { + "version": "2.3.6", + "tag": "@rushstack/heft-node-rig_v2.3.6", + "date": "Mon, 23 Oct 2023 15:18:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "2.3.5", + "tag": "@rushstack/heft-node-rig_v2.3.5", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "2.3.4", + "tag": "@rushstack/heft-node-rig_v2.3.4", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "2.3.3", + "tag": "@rushstack/heft-node-rig_v2.3.3", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "2.3.2", + "tag": "@rushstack/heft-node-rig_v2.3.2", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "2.3.1", + "tag": "@rushstack/heft-node-rig_v2.3.1", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "2.3.0", + "tag": "@rushstack/heft-node-rig_v2.3.0", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the \"eslint-config-\" prefix. This change also includes the ESLint configurations sourced from \"@rushstack/eslint-config\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "2.2.26", + "tag": "@rushstack/heft-node-rig_v2.2.26", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "2.2.25", + "tag": "@rushstack/heft-node-rig_v2.2.25", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "2.2.24", + "tag": "@rushstack/heft-node-rig_v2.2.24", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "2.2.23", + "tag": "@rushstack/heft-node-rig_v2.2.23", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "2.2.22", + "tag": "@rushstack/heft-node-rig_v2.2.22", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "2.2.21", + "tag": "@rushstack/heft-node-rig_v2.2.21", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "2.2.20", + "tag": "@rushstack/heft-node-rig_v2.2.20", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "2.2.19", + "tag": "@rushstack/heft-node-rig_v2.2.19", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "2.2.18", + "tag": "@rushstack/heft-node-rig_v2.2.18", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "2.2.17", + "tag": "@rushstack/heft-node-rig_v2.2.17", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.18`" + } + ] + } + }, + { + "version": "2.2.16", + "tag": "@rushstack/heft-node-rig_v2.2.16", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "2.2.15", + "tag": "@rushstack/heft-node-rig_v2.2.15", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "2.2.14", + "tag": "@rushstack/heft-node-rig_v2.2.14", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.15`" + } + ] + } + }, + { + "version": "2.2.13", + "tag": "@rushstack/heft-node-rig_v2.2.13", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "2.2.12", + "tag": "@rushstack/heft-node-rig_v2.2.12", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "2.2.11", + "tag": "@rushstack/heft-node-rig_v2.2.11", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.12`" + } + ] + } + }, + { + "version": "2.2.10", + "tag": "@rushstack/heft-node-rig_v2.2.10", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "2.2.9", + "tag": "@rushstack/heft-node-rig_v2.2.9", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "2.2.8", + "tag": "@rushstack/heft-node-rig_v2.2.8", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "2.2.7", + "tag": "@rushstack/heft-node-rig_v2.2.7", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "2.2.6", + "tag": "@rushstack/heft-node-rig_v2.2.6", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "2.2.5", + "tag": "@rushstack/heft-node-rig_v2.2.5", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "2.2.4", + "tag": "@rushstack/heft-node-rig_v2.2.4", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.5`" + } + ] + } + }, + { + "version": "2.2.3", + "tag": "@rushstack/heft-node-rig_v2.2.3", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "2.2.2", + "tag": "@rushstack/heft-node-rig_v2.2.2", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "2.2.1", + "tag": "@rushstack/heft-node-rig_v2.2.1", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "2.2.0", + "tag": "@rushstack/heft-node-rig_v2.2.0", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where heft-node-rig was not loading the NodeServicePlugin" + } + ], + "minor": [ + { + "comment": "Add \"heft start\" alias that maps to \"heft build-watch --serve\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "2.1.0", + "tag": "@rushstack/heft-node-rig_v2.1.0", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "minor": [ + { + "comment": "Updated Jest environment \"customExportConditions\" to [\"require\", \"node\"]" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "2.0.1", + "tag": "@rushstack/heft-node-rig_v2.0.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.1`" + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@rushstack/heft-node-rig_v2.0.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "major": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "1.13.1", + "tag": "@rushstack/heft-node-rig_v1.13.1", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "1.13.0", + "tag": "@rushstack/heft-node-rig_v1.13.0", + "date": "Mon, 22 May 2023 06:34:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript to ~5.0.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "1.12.11", + "tag": "@rushstack/heft-node-rig_v1.12.11", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "1.12.10", + "tag": "@rushstack/heft-node-rig_v1.12.10", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "1.12.9", + "tag": "@rushstack/heft-node-rig_v1.12.9", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "1.12.8", + "tag": "@rushstack/heft-node-rig_v1.12.8", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "1.12.7", + "tag": "@rushstack/heft-node-rig_v1.12.7", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "1.12.6", + "tag": "@rushstack/heft-node-rig_v1.12.6", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade Jest to 29.5.0." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.6`" + } + ] + } + }, + { + "version": "1.12.5", + "tag": "@rushstack/heft-node-rig_v1.12.5", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "1.12.4", + "tag": "@rushstack/heft-node-rig_v1.12.4", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "1.12.3", + "tag": "@rushstack/heft-node-rig_v1.12.3", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "1.12.2", + "tag": "@rushstack/heft-node-rig_v1.12.2", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "1.12.1", + "tag": "@rushstack/heft-node-rig_v1.12.1", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "1.12.0", + "tag": "@rushstack/heft-node-rig_v1.12.0", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest from `~27.4.2` to `~29.3.1`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.11.14", + "tag": "@rushstack/heft-node-rig_v1.11.14", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "1.11.13", + "tag": "@rushstack/heft-node-rig_v1.11.13", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "1.11.12", + "tag": "@rushstack/heft-node-rig_v1.11.12", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "1.11.11", + "tag": "@rushstack/heft-node-rig_v1.11.11", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "1.11.10", + "tag": "@rushstack/heft-node-rig_v1.11.10", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "1.11.9", + "tag": "@rushstack/heft-node-rig_v1.11.9", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.0`" + } + ] + } + }, + { + "version": "1.11.8", + "tag": "@rushstack/heft-node-rig_v1.11.8", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "1.11.7", + "tag": "@rushstack/heft-node-rig_v1.11.7", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "1.11.6", + "tag": "@rushstack/heft-node-rig_v1.11.6", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "1.11.5", + "tag": "@rushstack/heft-node-rig_v1.11.5", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "1.11.4", + "tag": "@rushstack/heft-node-rig_v1.11.4", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "1.11.3", + "tag": "@rushstack/heft-node-rig_v1.11.3", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "1.11.2", + "tag": "@rushstack/heft-node-rig_v1.11.2", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "1.11.1", + "tag": "@rushstack/heft-node-rig_v1.11.1", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "1.11.0", + "tag": "@rushstack/heft-node-rig_v1.11.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 4.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "1.10.13", + "tag": "@rushstack/heft-node-rig_v1.10.13", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "1.10.12", + "tag": "@rushstack/heft-node-rig_v1.10.12", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "1.10.11", + "tag": "@rushstack/heft-node-rig_v1.10.11", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "1.10.10", + "tag": "@rushstack/heft-node-rig_v1.10.10", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "1.10.9", + "tag": "@rushstack/heft-node-rig_v1.10.9", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "1.10.8", + "tag": "@rushstack/heft-node-rig_v1.10.8", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "1.10.7", + "tag": "@rushstack/heft-node-rig_v1.10.7", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.30`" + } + ] + } + }, + { + "version": "1.10.6", + "tag": "@rushstack/heft-node-rig_v1.10.6", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.29`" + } + ] + } + }, + { + "version": "1.10.5", + "tag": "@rushstack/heft-node-rig_v1.10.5", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "1.10.4", + "tag": "@rushstack/heft-node-rig_v1.10.4", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "1.10.3", + "tag": "@rushstack/heft-node-rig_v1.10.3", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "1.10.2", + "tag": "@rushstack/heft-node-rig_v1.10.2", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "1.10.1", + "tag": "@rushstack/heft-node-rig_v1.10.1", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "1.10.0", + "tag": "@rushstack/heft-node-rig_v1.10.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript to 4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "1.9.23", + "tag": "@rushstack/heft-node-rig_v1.9.23", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "1.9.22", + "tag": "@rushstack/heft-node-rig_v1.9.22", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "1.9.21", + "tag": "@rushstack/heft-node-rig_v1.9.21", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "1.9.20", + "tag": "@rushstack/heft-node-rig_v1.9.20", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "1.9.19", + "tag": "@rushstack/heft-node-rig_v1.9.19", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "1.9.18", + "tag": "@rushstack/heft-node-rig_v1.9.18", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "1.9.17", + "tag": "@rushstack/heft-node-rig_v1.9.17", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "1.9.16", + "tag": "@rushstack/heft-node-rig_v1.9.16", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "1.9.15", + "tag": "@rushstack/heft-node-rig_v1.9.15", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "1.9.14", + "tag": "@rushstack/heft-node-rig_v1.9.14", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "1.9.13", + "tag": "@rushstack/heft-node-rig_v1.9.13", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "1.9.12", + "tag": "@rushstack/heft-node-rig_v1.9.12", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "1.9.11", + "tag": "@rushstack/heft-node-rig_v1.9.11", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "1.9.10", + "tag": "@rushstack/heft-node-rig_v1.9.10", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "1.9.9", + "tag": "@rushstack/heft-node-rig_v1.9.9", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "1.9.8", + "tag": "@rushstack/heft-node-rig_v1.9.8", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "1.9.7", + "tag": "@rushstack/heft-node-rig_v1.9.7", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "1.9.6", + "tag": "@rushstack/heft-node-rig_v1.9.6", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "1.9.5", + "tag": "@rushstack/heft-node-rig_v1.9.5", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "1.9.4", + "tag": "@rushstack/heft-node-rig_v1.9.4", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "1.9.3", + "tag": "@rushstack/heft-node-rig_v1.9.3", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "1.9.2", + "tag": "@rushstack/heft-node-rig_v1.9.2", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "1.9.1", + "tag": "@rushstack/heft-node-rig_v1.9.1", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.0`" + } + ] + } + }, + { + "version": "1.9.0", + "tag": "@rushstack/heft-node-rig_v1.9.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "1.8.11", + "tag": "@rushstack/heft-node-rig_v1.8.11", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "1.8.10", + "tag": "@rushstack/heft-node-rig_v1.8.10", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "1.8.9", + "tag": "@rushstack/heft-node-rig_v1.8.9", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "1.8.8", + "tag": "@rushstack/heft-node-rig_v1.8.8", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "1.8.7", + "tag": "@rushstack/heft-node-rig_v1.8.7", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "1.8.6", + "tag": "@rushstack/heft-node-rig_v1.8.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "1.8.5", + "tag": "@rushstack/heft-node-rig_v1.8.5", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "1.8.4", + "tag": "@rushstack/heft-node-rig_v1.8.4", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "1.8.3", + "tag": "@rushstack/heft-node-rig_v1.8.3", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "1.8.2", + "tag": "@rushstack/heft-node-rig_v1.8.2", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "1.8.1", + "tag": "@rushstack/heft-node-rig_v1.8.1", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "1.8.0", + "tag": "@rushstack/heft-node-rig_v1.8.0", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "minor": [ + { + "comment": "Set useUnknownInCatchVariables=false in tsconfig.json, to work around https://github.com/microsoft/TypeScript/issues/42596" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.3`" + } + ] + } + }, + { + "version": "1.7.1", + "tag": "@rushstack/heft-node-rig_v1.7.1", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade ESLint to ~8.7.0" + } + ] + } + }, + { + "version": "1.7.0", + "tag": "@rushstack/heft-node-rig_v1.7.0", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "minor": [ + { + "comment": "Include \"dist\" in the list of cached folders for the \"build\" and \"_phase:build\" operations." + } + ] + } + }, + { + "version": "1.6.0", + "tag": "@rushstack/heft-node-rig_v1.6.0", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "minor": [ + { + "comment": "Update the `rush-project.json` file to follow the new schema and configure the \"build\" command output folders for the \"_phase:build\" phase." + } + ] + } + }, + { + "version": "1.5.2", + "tag": "@rushstack/heft-node-rig_v1.5.2", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "1.5.1", + "tag": "@rushstack/heft-node-rig_v1.5.1", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/heft-node-rig_v1.5.0", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest to v27" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/heft-node-rig_v1.4.3", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/heft-node-rig_v1.4.2", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/heft-node-rig_v1.4.1", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/heft-node-rig_v1.4.0", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.5" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/heft-node-rig_v1.3.0", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "minor": [ + { + "comment": "Bump ESLint to v8" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "1.2.33", + "tag": "@rushstack/heft-node-rig_v1.2.33", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "1.2.32", + "tag": "@rushstack/heft-node-rig_v1.2.32", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "patch": [ + { + "comment": "Set default Jest environment in Jest configuration to \"jest-environment-node\"" + } + ] + } + }, + { + "version": "1.2.31", + "tag": "@rushstack/heft-node-rig_v1.2.31", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "1.2.30", + "tag": "@rushstack/heft-node-rig_v1.2.30", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "1.2.29", + "tag": "@rushstack/heft-node-rig_v1.2.29", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "1.2.28", + "tag": "@rushstack/heft-node-rig_v1.2.28", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "1.2.27", + "tag": "@rushstack/heft-node-rig_v1.2.27", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "1.2.26", + "tag": "@rushstack/heft-node-rig_v1.2.26", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "1.2.25", + "tag": "@rushstack/heft-node-rig_v1.2.25", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "1.2.24", + "tag": "@rushstack/heft-node-rig_v1.2.24", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "1.2.23", + "tag": "@rushstack/heft-node-rig_v1.2.23", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/heft-node-rig_v1.2.22", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-node-rig_v1.2.21", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-node-rig_v1.2.20", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-node-rig_v1.2.19", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-node-rig_v1.2.18", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-node-rig_v1.2.17", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-node-rig_v1.2.16", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-node-rig_v1.2.15", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-node-rig_v1.2.14", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-node-rig_v1.2.13", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-node-rig_v1.2.12", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.4` to `^0.38.0`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-node-rig_v1.2.11", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.3` to `^0.37.4`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-node-rig_v1.2.10", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.2` to `^0.37.3`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-node-rig_v1.2.9", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.1` to `^0.37.2`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-node-rig_v1.2.8", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.0` to `^0.37.1`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-node-rig_v1.2.7", + "date": "Fri, 03 Sep 2021 00:09:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.23`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-node-rig_v1.2.6", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.4` to `^0.37.0`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-node-rig_v1.2.5", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.3` to `^0.36.4`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-node-rig_v1.2.4", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.36.3`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-node-rig_v1.2.3", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "patch": [ + { + "comment": "Remove default use of incremental: true in tsconfig-base.json" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-node-rig_v1.2.2", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.1` to `^0.36.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-node-rig_v1.2.1", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "patch": [ + { + "comment": "Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.0` to `^0.36.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-node-rig_v1.2.0", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "minor": [ + { + "comment": "Enable \"incremental: true\" by default in tsconfig-base.json" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.1` to `^0.36.0`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-node-rig_v1.1.15", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.0` to `^0.35.1`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-node-rig_v1.1.14", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.8` to `^0.35.0`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-node-rig_v1.1.13", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.7` to `^0.34.8`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-node-rig_v1.1.12", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.6` to `^0.34.7`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-node-rig_v1.1.11", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.5` to `^0.34.6`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-node-rig_v1.1.10", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.4` to `^0.34.5`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-node-rig_v1.1.9", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.3` to `^0.34.4`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-node-rig_v1.1.8", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.2` to `^0.34.3`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-node-rig_v1.1.7", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.8`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-node-rig_v1.1.6", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.1` to `^0.34.2`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-node-rig_v1.1.5", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.0` to `^0.34.1`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-node-rig_v1.1.4", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.1` to `^0.34.0`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-node-rig_v1.1.3", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.0` to `^0.33.1`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-node-rig_v1.1.2", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.3`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-node-rig_v1.1.1", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.32.0` to `^0.33.0`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-node-rig_v1.1.0", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "minor": [ + { + "comment": "Disable the allowUnreachableCode TypeScript compiler option." + } + ] + } + }, + { + "version": "1.0.31", + "tag": "@rushstack/heft-node-rig_v1.0.31", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.2`" + } + ] + } + }, + { + "version": "1.0.30", + "tag": "@rushstack/heft-node-rig_v1.0.30", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "patch": [ + { + "comment": "Add @rushstack/heft-jest-plugin to run during tests" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.5` to `^0.32.0`" + } + ] + } + }, + { + "version": "1.0.29", + "tag": "@rushstack/heft-node-rig_v1.0.29", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.4` to `^0.31.5`" + } + ] + } + }, + { + "version": "1.0.28", + "tag": "@rushstack/heft-node-rig_v1.0.28", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.3` to `^0.31.4`" + } + ] + } + }, + { + "version": "1.0.27", + "tag": "@rushstack/heft-node-rig_v1.0.27", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.2` to `^0.31.3`" + } + ] + } + }, + { + "version": "1.0.26", + "tag": "@rushstack/heft-node-rig_v1.0.26", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.1` to `^0.31.2`" + } + ] + } + }, + { + "version": "1.0.25", + "tag": "@rushstack/heft-node-rig_v1.0.25", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.0` to `^0.31.1`" + } + ] + } + }, + { + "version": "1.0.24", + "tag": "@rushstack/heft-node-rig_v1.0.24", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.7` to `^0.31.0`" + } + ] + } + }, + { + "version": "1.0.23", + "tag": "@rushstack/heft-node-rig_v1.0.23", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.6` to `^0.30.7`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/heft-node-rig_v1.0.22", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.5` to `^0.30.6`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/heft-node-rig_v1.0.21", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.4` to `^0.30.5`" + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/heft-node-rig_v1.0.20", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.3` to `^0.30.4`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/heft-node-rig_v1.0.19", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.2` to `^0.30.3`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/heft-node-rig_v1.0.18", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.1` to `^0.30.2`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/heft-node-rig_v1.0.17", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.0` to `^0.30.1`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/heft-node-rig_v1.0.16", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.1` to `^0.30.0`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/heft-node-rig_v1.0.15", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.0` to `^0.29.1`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/heft-node-rig_v1.0.14", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.5` to `^0.29.0`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/heft-node-rig_v1.0.13", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.4` to `^0.28.5`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/heft-node-rig_v1.0.12", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.3` to `^0.28.4`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/heft-node-rig_v1.0.11", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "patch": [ + { + "comment": "Explicitly set the noEmitOnError TypeScript compiler option to false in the base tsconfig." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.2` to `^0.28.3`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/heft-node-rig_v1.0.10", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.1` to `^0.28.2`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/heft-node-rig_v1.0.9", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.0` to `^0.28.1`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/heft-node-rig_v1.0.8", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.27.0` to `^0.28.0`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/heft-node-rig_v1.0.7", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.26.0` to `^0.27.0`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/heft-node-rig_v1.0.6", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.5` to `^0.26.0`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/heft-node-rig_v1.0.5", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.4` to `^0.25.5`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/heft-node-rig_v1.0.4", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.3` to `^0.25.4`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/heft-node-rig_v1.0.3", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.2` to `^0.25.3`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-node-rig_v1.0.2", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.1` to `^0.25.2`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/heft-node-rig_v1.0.1", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.0` to `^0.25.1`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-node-rig_v1.0.0", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "major": [ + { + "comment": "Update to TypeScript 4" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-node-rig_v0.2.7", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.4` to `^0.25.0`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-node-rig_v0.2.6", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.3` to `^0.24.4`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-node-rig_v0.2.5", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.2` to `^0.24.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-node-rig_v0.2.4", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.1` to `^0.24.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-node-rig_v0.2.3", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.0` to `^0.24.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-node-rig_v0.2.2", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.2` to `^0.24.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-node-rig_v0.2.1", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.1` to `^0.23.2`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-node-rig_v0.2.0", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "minor": [ + { + "comment": "Add a Rush build cache configuration." + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-node-rig_v0.1.34", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.0` to `^0.23.1`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-node-rig_v0.1.33", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.7` to `^0.23.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-node-rig_v0.1.32", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.6` to `^0.22.7`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-node-rig_v0.1.31", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure rootDir is consistently specified." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.5` to `^0.22.6`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-node-rig_v0.1.30", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.4` to `^0.22.5`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-node-rig_v0.1.29", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.3` to `^0.22.4`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-node-rig_v0.1.28", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.2` to `^0.22.3`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-node-rig_v0.1.27", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.1` to `^0.22.2`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-node-rig_v0.1.26", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.0` to `^0.22.1`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-node-rig_v0.1.25", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.3` to `^0.22.0`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-node-rig_v0.1.24", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.2` to `^0.21.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-node-rig_v0.1.23", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.1` to `^0.21.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-node-rig_v0.1.22", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.0` to `^0.21.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-node-rig_v0.1.21", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.20.1` to `^0.21.0`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-node-rig_v0.1.20", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.20.0` to `^0.20.1`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-node-rig_v0.1.19", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.5` to `^0.20.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-node-rig_v0.1.18", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.4` to `^0.19.5`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-node-rig_v0.1.17", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.3` to `^0.19.4`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-node-rig_v0.1.16", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.2` to `^0.19.3`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-node-rig_v0.1.15", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.1` to `^0.19.2`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-node-rig_v0.1.14", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.0` to `^0.19.1`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-node-rig_v0.1.13", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.18.0` to `^0.19.0`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-node-rig_v0.1.12", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.4` to `^0.18.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-node-rig_v0.1.11", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.3` to `^0.17.4`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-node-rig_v0.1.10", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.2` to `^0.17.3`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-node-rig_v0.1.9", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.1` to `^0.17.2`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-node-rig_v0.1.8", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.16.1` to `^0.17.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-node-rig_v0.1.7", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update Heft." + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-node-rig_v0.1.6", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "patch": [ + { + "comment": "Update Heft dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.5` to `^0.16.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-node-rig_v0.1.5", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.4` to `^0.15.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-node-rig_v0.1.4", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.3` to `^0.15.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-node-rig_v0.1.3", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.1` to `^0.15.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-node-rig_v0.1.2", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "patch": [ + { + "comment": "Update @rushstack/heft peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.0` to `^0.15.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-node-rig_v0.1.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.14.0` to `^0.14.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-node-rig_v0.1.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.1.0` to `^0.14.0`" + } + ] + } + } + ] +} diff --git a/rigs/heft-node-rig/CHANGELOG.md b/rigs/heft-node-rig/CHANGELOG.md new file mode 100644 index 00000000000..81e5007906f --- /dev/null +++ b/rigs/heft-node-rig/CHANGELOG.md @@ -0,0 +1,2088 @@ +# Change Log - @rushstack/heft-node-rig + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 2.11.12 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 2.11.11 +Wed, 03 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 2.11.10 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 2.11.9 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 2.11.8 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 2.11.7 +Tue, 11 Nov 2025 16:13:26 GMT + +_Version update only_ + +## 2.11.6 +Mon, 10 Nov 2025 16:12:32 GMT + +### Patches + +- Include lib-dts and lib-esm folders in default files to clean + +## 2.11.5 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 2.11.4 +Fri, 24 Oct 2025 11:22:09 GMT + +_Version update only_ + +## 2.11.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 2.11.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 2.11.1 +Tue, 14 Oct 2025 15:13:22 GMT + +_Version update only_ + +## 2.11.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`. + +## 2.10.2 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 2.10.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 2.10.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Minor changes + +- Release Heft version 1.0.0 + +## 2.9.7 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 2.9.6 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 2.9.5 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 2.9.4 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 2.9.3 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 2.9.2 +Mon, 28 Jul 2025 15:11:56 GMT + +_Version update only_ + +## 2.9.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 2.9.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Add flat config compatible versions of profiles and mixins for ESLint. These are located under the `profiles/default/includes/eslint/flat/*` path. If you need to remain on ESLint 8, ensure your rig or project consumes ESLint 8, and that you use the legacy configuration files. + +## 2.8.15 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 2.8.14 +Fri, 06 Jun 2025 00:11:09 GMT + +_Version update only_ + +## 2.8.13 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 2.8.12 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 2.8.11 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 2.8.10 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 2.8.9 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 2.8.8 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 2.8.7 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 2.8.6 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 2.8.5 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 2.8.4 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 2.8.3 +Tue, 25 Mar 2025 00:12:04 GMT + +_Version update only_ + +## 2.8.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 2.8.1 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 2.8.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump TypeScript to ~5.8.2. + +## 2.7.2 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 2.7.1 +Thu, 06 Mar 2025 01:10:42 GMT + +_Version update only_ + +## 2.7.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `typescript` dependency to `~5.7.3`. + +## 2.6.59 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 2.6.58 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 2.6.57 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 2.6.56 +Tue, 25 Feb 2025 01:11:55 GMT + +_Version update only_ + +## 2.6.55 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 2.6.54 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 2.6.53 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 2.6.52 +Fri, 07 Feb 2025 01:10:49 GMT + +_Version update only_ + +## 2.6.51 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 2.6.50 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 2.6.49 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 2.6.48 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 2.6.47 +Tue, 07 Jan 2025 16:11:06 GMT + +_Version update only_ + +## 2.6.46 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 2.6.45 +Tue, 10 Dec 2024 07:32:19 GMT + +_Version update only_ + +## 2.6.44 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 2.6.43 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 2.6.42 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 2.6.41 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 2.6.40 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 2.6.39 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 2.6.38 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 2.6.37 +Wed, 16 Oct 2024 00:11:20 GMT + +_Version update only_ + +## 2.6.36 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 2.6.35 +Thu, 10 Oct 2024 00:11:51 GMT + +_Version update only_ + +## 2.6.34 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 2.6.33 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 2.6.32 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 2.6.31 +Thu, 19 Sep 2024 00:11:08 GMT + +_Version update only_ + +## 2.6.30 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 2.6.29 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 2.6.28 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 2.6.27 +Wed, 14 Aug 2024 22:37:32 GMT + +_Version update only_ + +## 2.6.26 +Tue, 13 Aug 2024 18:17:05 GMT + +_Version update only_ + +## 2.6.25 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 2.6.24 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 2.6.23 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 2.6.22 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 2.6.21 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 2.6.20 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 2.6.19 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 2.6.18 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 2.6.17 +Tue, 11 Jun 2024 00:21:28 GMT + +_Version update only_ + +## 2.6.16 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 2.6.15 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 2.6.14 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 2.6.13 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 2.6.12 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 2.6.11 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 2.6.10 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 2.6.9 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 2.6.8 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 2.6.7 +Fri, 17 May 2024 00:10:40 GMT + +_Version update only_ + +## 2.6.6 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 2.6.5 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 2.6.4 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 2.6.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 2.6.2 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 2.6.1 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 2.6.0 +Wed, 10 Apr 2024 21:59:39 GMT + +### Minor changes + +- Bump ESLint to ~8.57.0. + +## 2.5.6 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 2.5.5 +Fri, 29 Mar 2024 05:46:41 GMT + +_Version update only_ + +## 2.5.4 +Thu, 28 Mar 2024 22:42:23 GMT + +_Version update only_ + +## 2.5.3 +Thu, 28 Mar 2024 18:11:12 GMT + +_Version update only_ + +## 2.5.2 +Wed, 27 Mar 2024 19:47:21 GMT + +_Version update only_ + +## 2.5.1 +Wed, 20 Mar 2024 02:09:14 GMT + +_Version update only_ + +## 2.5.0 +Tue, 19 Mar 2024 15:10:18 GMT + +### Minor changes + +- Upgrade to TypeScript 5.4 + +## 2.4.25 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 2.4.24 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 2.4.23 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 2.4.22 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 2.4.21 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 2.4.20 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 2.4.19 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 2.4.18 +Mon, 26 Feb 2024 16:10:56 GMT + +_Version update only_ + +## 2.4.17 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 2.4.16 +Thu, 22 Feb 2024 05:54:17 GMT + +_Version update only_ + +## 2.4.15 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 2.4.14 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 2.4.13 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 2.4.12 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 2.4.11 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 2.4.10 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 2.4.9 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 2.4.8 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 2.4.7 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 2.4.6 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 2.4.5 +Thu, 25 Jan 2024 23:03:57 GMT + +_Version update only_ + +## 2.4.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 2.4.3 +Wed, 24 Jan 2024 07:38:34 GMT + +_Version update only_ + +## 2.4.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 2.4.1 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 2.4.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Upgrade to TypeScript 5.3 + +## 2.3.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 2.3.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 2.3.14 +Fri, 15 Dec 2023 01:10:06 GMT + +_Version update only_ + +## 2.3.13 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 2.3.12 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 2.3.11 +Wed, 22 Nov 2023 01:45:18 GMT + +_Version update only_ + +## 2.3.10 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 2.3.9 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 2.3.8 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 2.3.7 +Thu, 26 Oct 2023 00:27:48 GMT + +_Version update only_ + +## 2.3.6 +Mon, 23 Oct 2023 15:18:38 GMT + +_Version update only_ + +## 2.3.5 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 2.3.4 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 2.3.3 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 2.3.2 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 2.3.1 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 2.3.0 +Tue, 26 Sep 2023 09:30:33 GMT + +### Minor changes + +- Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the "eslint-config-" prefix. This change also includes the ESLint configurations sourced from "@rushstack/eslint-config" + +## 2.2.26 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 2.2.25 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 2.2.24 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 2.2.23 +Fri, 15 Sep 2023 00:36:58 GMT + +_Version update only_ + +## 2.2.22 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 2.2.21 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 2.2.20 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 2.2.19 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 2.2.18 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 2.2.17 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 2.2.16 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 2.2.15 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 2.2.14 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 2.2.13 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 2.2.12 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 2.2.11 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 2.2.10 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 2.2.9 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 2.2.8 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 2.2.7 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 2.2.6 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 2.2.5 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 2.2.4 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 2.2.3 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 2.2.2 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 2.2.1 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 2.2.0 +Wed, 07 Jun 2023 22:45:16 GMT + +### Minor changes + +- Add "heft start" alias that maps to "heft build-watch --serve" + +### Patches + +- Fix a regression where heft-node-rig was not loading the NodeServicePlugin + +## 2.1.0 +Tue, 06 Jun 2023 02:52:51 GMT + +### Minor changes + +- Updated Jest environment "customExportConditions" to ["require", "node"] + +## 2.0.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 2.0.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Breaking changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 1.13.1 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 1.13.0 +Mon, 22 May 2023 06:34:32 GMT + +### Minor changes + +- Upgrade TypeScript to ~5.0.4 + +## 1.12.11 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 1.12.10 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 1.12.9 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 1.12.8 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 1.12.7 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 1.12.6 +Tue, 04 Apr 2023 22:36:28 GMT + +### Patches + +- Upgrade Jest to 29.5.0. + +## 1.12.5 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 1.12.4 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 1.12.3 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 1.12.2 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 1.12.1 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 1.12.0 +Mon, 30 Jan 2023 00:55:44 GMT + +### Minor changes + +- Upgrade Jest from `~27.4.2` to `~29.3.1` + +## 1.11.14 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 1.11.13 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 1.11.12 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 1.11.11 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 1.11.10 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 1.11.9 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 1.11.8 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 1.11.7 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 1.11.6 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 1.11.5 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 1.11.4 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 1.11.3 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 1.11.2 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 1.11.1 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 1.11.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgrade to TypeScript 4.8. + +## 1.10.13 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 1.10.12 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 1.10.11 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 1.10.10 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.10.9 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.10.8 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.10.7 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.10.6 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.10.5 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.10.4 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.10.3 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 1.10.2 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.10.1 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.10.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript to 4.7 + +## 1.9.23 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.9.22 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 1.9.21 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.9.20 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 1.9.19 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 1.9.18 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.9.17 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 1.9.16 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 1.9.15 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.9.14 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.9.13 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.9.12 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.9.11 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.9.10 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 1.9.9 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.9.8 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 1.9.7 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 1.9.6 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 1.9.5 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 1.9.4 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.9.3 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.9.2 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.9.1 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.9.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Update to TypeScript 4.6 + +## 1.8.11 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.8.10 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 1.8.9 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.8.8 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.8.7 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.8.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.8.5 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.8.4 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.8.3 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.8.2 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 1.8.1 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 1.8.0 +Fri, 11 Feb 2022 10:30:25 GMT + +### Minor changes + +- Set useUnknownInCatchVariables=false in tsconfig.json, to work around https://github.com/microsoft/TypeScript/issues/42596 + +## 1.7.1 +Tue, 25 Jan 2022 01:11:07 GMT + +### Patches + +- Upgrade ESLint to ~8.7.0 + +## 1.7.0 +Fri, 21 Jan 2022 01:10:41 GMT + +### Minor changes + +- Include "dist" in the list of cached folders for the "build" and "_phase:build" operations. + +## 1.6.0 +Thu, 20 Jan 2022 02:43:46 GMT + +### Minor changes + +- Update the `rush-project.json` file to follow the new schema and configure the "build" command output folders for the "_phase:build" phase. + +## 1.5.2 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.5.1 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.5.0 +Tue, 14 Dec 2021 19:27:51 GMT + +### Minor changes + +- Upgrade Jest to v27 + +## 1.4.3 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.4.2 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.4.1 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.4.0 +Wed, 08 Dec 2021 16:14:05 GMT + +### Minor changes + +- Update to TypeScript 4.5 + +## 1.3.0 +Mon, 06 Dec 2021 16:08:32 GMT + +### Minor changes + +- Bump ESLint to v8 + +## 1.2.33 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.2.32 +Tue, 30 Nov 2021 20:18:41 GMT + +### Patches + +- Set default Jest environment in Jest configuration to "jest-environment-node" + +## 1.2.31 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.2.30 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.2.29 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.2.28 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.2.27 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.2.26 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 1.2.25 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.2.24 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.2.23 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.2.22 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.2.21 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 1.2.20 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.2.19 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 1.2.18 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.2.17 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.2.16 +Thu, 23 Sep 2021 00:10:40 GMT + +_Version update only_ + +## 1.2.15 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.2.14 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.2.13 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.2.12 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.2.11 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.2.10 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.2.9 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.2.8 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.2.7 +Fri, 03 Sep 2021 00:09:09 GMT + +_Version update only_ + +## 1.2.6 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.2.5 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.2.4 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.2.3 +Fri, 13 Aug 2021 00:09:14 GMT + +### Patches + +- Remove default use of incremental: true in tsconfig-base.json + +## 1.2.2 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.2.1 +Thu, 12 Aug 2021 01:28:38 GMT + +### Patches + +- Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior. + +## 1.2.0 +Wed, 11 Aug 2021 23:14:17 GMT + +### Minor changes + +- Enable "incremental: true" by default in tsconfig-base.json + +## 1.1.15 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.1.14 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.1.13 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.1.12 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.1.11 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.1.9 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.1.8 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.1.7 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.1.6 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.1.5 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.1.4 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.1.3 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.1.2 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.1.1 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.1.0 +Tue, 15 Jun 2021 20:38:35 GMT + +### Minor changes + +- Disable the allowUnreachableCode TypeScript compiler option. + +## 1.0.31 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.0.30 +Fri, 11 Jun 2021 00:34:02 GMT + +### Patches + +- Add @rushstack/heft-jest-plugin to run during tests + +## 1.0.29 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.0.28 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.0.27 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.0.26 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.0.25 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.0.24 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.0.23 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 1.0.22 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.0.21 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.0.20 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 1.0.19 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.0.18 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.0.17 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.0.16 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.0.15 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 1.0.14 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 1.0.13 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 1.0.12 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.0.11 +Thu, 15 Apr 2021 02:59:25 GMT + +### Patches + +- Explicitly set the noEmitOnError TypeScript compiler option to false in the base tsconfig. + +## 1.0.10 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.0.9 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 1.0.8 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.0.7 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.0.6 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.0.5 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.0.4 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 1.0.3 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 1.0.2 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.0.1 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.0.0 +Wed, 10 Mar 2021 06:23:29 GMT + +### Breaking changes + +- Update to TypeScript 4 + +## 0.2.7 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 0.2.6 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.2.5 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.2.4 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.2.3 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.2.2 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 0.2.1 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.2.0 +Fri, 08 Jan 2021 07:28:50 GMT + +### Minor changes + +- Add a Rush build cache configuration. + +## 0.1.34 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.1.33 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.1.32 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.1.31 +Sat, 05 Dec 2020 01:11:23 GMT + +### Patches + +- Ensure rootDir is consistently specified. + +## 0.1.30 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.1.29 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.1.28 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.1.27 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.1.26 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.1.25 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.1.24 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.1.23 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.1.22 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.1.21 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 0.1.20 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.1.19 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.1.18 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.1.17 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 0.1.16 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.1.15 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.1.14 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.1.13 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 0.1.12 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 0.1.11 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.1.10 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 0.1.9 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 0.1.8 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.1.7 +Wed, 21 Oct 2020 02:28:17 GMT + +### Patches + +- Update Heft. + +## 0.1.6 +Thu, 15 Oct 2020 00:59:08 GMT + +### Patches + +- Update Heft dependency + +## 0.1.5 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.1.4 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.1.3 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 0.1.2 +Thu, 01 Oct 2020 20:27:16 GMT + +### Patches + +- Update @rushstack/heft peerDependency. + +## 0.1.1 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.1.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Initial release + diff --git a/rigs/heft-node-rig/LICENSE b/rigs/heft-node-rig/LICENSE new file mode 100644 index 00000000000..d861e4d3fc7 --- /dev/null +++ b/rigs/heft-node-rig/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-node-rig + +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/rigs/heft-node-rig/README.md b/rigs/heft-node-rig/README.md new file mode 100644 index 00000000000..38ce1b084a4 --- /dev/null +++ b/rigs/heft-node-rig/README.md @@ -0,0 +1,30 @@ +## @rushstack/heft-node-rig + +A rig package for Node.js projects that build using [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. To learn more about rig packages, consult the +[@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) documentation. + +This rig contains a single profile: `default` + +To enable it, add a **rig.json** file to your project, as shown below: + +**config/rig.json** +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-node-rig" +} +``` + +The config files provided by this rig profile can be found in the [heft-node-rig/profiles/default]( +https://github.com/microsoft/rushstack/tree/main/rigs/heft-node-rig/profiles/default) source folder. + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/rigs/heft-node-rig/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/heft-node-rig` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/rigs/heft-node-rig/package.json b/rigs/heft-node-rig/package.json new file mode 100644 index 00000000000..adca77fd8c1 --- /dev/null +++ b/rigs/heft-node-rig/package.json @@ -0,0 +1,33 @@ +{ + "name": "@rushstack/heft-node-rig", + "version": "2.11.12", + "description": "A rig package for Node.js projects that build using Heft", + "license": "MIT", + "scripts": { + "build": "", + "_phase:build": "" + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "rigs/heft-node-rig" + }, + "peerDependencies": { + "@rushstack/heft": "^1.1.7" + }, + "dependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/eslint-config": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "eslint": "~9.37.0", + "jest-environment-node": "~29.5.0", + "typescript": "~5.8.2" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*" + } +} diff --git a/rigs/heft-node-rig/profiles/default/config/api-extractor-task.json b/rigs/heft-node-rig/profiles/default/config/api-extractor-task.json new file mode 100644 index 00000000000..910d81d0828 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/config/api-extractor-task.json @@ -0,0 +1,21 @@ +/** + * Configures the API Extractor task for the Heft build system. + * + * This optional additional file customizes how the Heft task is invoked. The main analysis is + * controlled by API Extractor's own "api-extractor.json" config file. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json" + + /** + * If set to true, use the project's TypeScript compiler version for API Extractor's + * analysis. API Extractor's included TypeScript compiler can generally correctly + * analyze typings generated by older compilers, and referencing the project's compiler + * can cause issues. If issues are encountered with API Extractor's included compiler, + * set this option to true. + * + * This corresponds to API Extractor's "--typescript-compiler-folder" CLI option and + * "IExtractorInvokeOptions.typescriptCompilerFolder" API option. This option defaults to false. + */ + // "useProjectTypescriptVersion": true +} diff --git a/rigs/heft-node-rig/profiles/default/config/heft.json b/rigs/heft-node-rig/profiles/default/config/heft.json new file mode 100644 index 00000000000..e550329a62c --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/config/heft.json @@ -0,0 +1,65 @@ +/** + * 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": "base-project/config/heft.json", + + "aliasesByName": { + "start": { + "actionName": "build-watch", + "defaultParameters": ["--serve"] + } + }, + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "lib-dts", "lib-esm"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + }, + "node-service": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "node-service-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/rigs/heft-node-rig/profiles/default/config/jest.config.json b/rigs/heft-node-rig/profiles/default/config/jest.config.json new file mode 100644 index 00000000000..b6f305ec886 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json" +} diff --git a/rigs/heft-node-rig/profiles/default/config/rush-project.json b/rigs/heft-node-rig/profiles/default/config/rush-project.json new file mode 100644 index 00000000000..bce265a4f3f --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + }, + { + "operationName": "build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + } + ] +} diff --git a/rigs/heft-node-rig/profiles/default/config/typescript.json b/rigs/heft-node-rig/profiles/default/config/typescript.json new file mode 100644 index 00000000000..ac7c00881b3 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/config/typescript.json @@ -0,0 +1,73 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.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": "base-project/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. + */ + "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" + // } + ], + + /** + * If true, emit CommonJS module output to the folder specified in the tsconfig "outDir" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies CommonJS) the default compilation output. + */ + // "emitCjsExtensionForCommonJS": true, + + /** + * If true, emit ESNext module output to the folder specified in the tsconfig "outDir" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + // "emitMjsExtensionForESModule": true, + + /** + * If true and "isolatedModules" is configured in tsconfig.json, use a worker thread to run transpilation concurrently with type checking and declaration emit. + */ + // "useTranspilerWorker": true + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [".json"] + + /** + * 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/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..860b58395f6 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js @@ -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. + +const friendlyLocalsMixin = require('@rushstack/eslint-config/flat/mixins/friendly-locals'); + +module.exports = [...friendlyLocalsMixin]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..a3f2ea0992a --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js @@ -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. + +const packletsMixin = require('@rushstack/eslint-config/flat/mixins/packlets'); + +module.exports = [...packletsMixin]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/react.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/react.js new file mode 100644 index 00000000000..5aafda8dcf0 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/react.js @@ -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. + +const reactMixin = require('@rushstack/eslint-config/flat/mixins/react'); + +module.exports = [...reactMixin]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..012a5bece42 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js @@ -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. + +const tsdocMixin = require('@rushstack/eslint-config/flat/mixins/tsdoc'); + +module.exports = [...tsdocMixin]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..ec6804684d1 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/flat/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js new file mode 100644 index 00000000000..245d236069a --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js @@ -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. + +const nodeTrustedToolProfile = require('@rushstack/eslint-config/flat/profile/node-trusted-tool'); + +module.exports = [...nodeTrustedToolProfile]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node.js b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node.js new file mode 100644 index 00000000000..16b5c3f2f6e --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/flat/profile/node.js @@ -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. + +const nodeProfile = require('@rushstack/eslint-config/flat/profile/node'); + +module.exports = [...nodeProfile]; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals.js b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals.js new file mode 100644 index 00000000000..e6cbfeacc95 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/friendly-locals'] +}; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/packlets.js b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/packlets.js new file mode 100644 index 00000000000..82a19efce16 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/packlets.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/packlets'] +}; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/react.js b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/react.js new file mode 100644 index 00000000000..796699ee874 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/react.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/react'] +}; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc.js b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc.js new file mode 100644 index 00000000000..d0a4b1d6a79 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/tsdoc'] +}; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names.js b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names.js new file mode 100644 index 00000000000..1fe7079f030 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names.js @@ -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. + +require('@rushstack/eslint-config/patch/custom-config-package-names'); diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions.js b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..084519e6ebb --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution.js b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution.js new file mode 100644 index 00000000000..14e8d976c23 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution.js @@ -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. + +require('@rushstack/eslint-config/patch/modern-module-resolution'); diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool.js b/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool.js new file mode 100644 index 00000000000..e5b291a3b08 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/profile/node-trusted-tool'] +}; diff --git a/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node.js b/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node.js new file mode 100644 index 00000000000..edd8dbb2cd2 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/includes/eslint/profile/node.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/profile/node'] +}; diff --git a/rigs/heft-node-rig/profiles/default/tsconfig-base.json b/rigs/heft-node-rig/profiles/default/tsconfig-base.json new file mode 100644 index 00000000000..47e93e11e99 --- /dev/null +++ b/rigs/heft-node-rig/profiles/default/tsconfig-base.json @@ -0,0 +1,31 @@ +{ + "$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, + + "types": ["heft-jest"], + "typeRoots": ["../../../../../node_modules/@types", "../../node_modules/@types"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "incremental": true + }, + "include": ["../../../../../src/**/*.ts", "../../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-vscode-extension-rig/.npmignore b/rigs/heft-vscode-extension-rig/.npmignore new file mode 100644 index 00000000000..2b485313c3f --- /dev/null +++ b/rigs/heft-vscode-extension-rig/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/profiles/** +!/shared/** diff --git a/rigs/heft-vscode-extension-rig/CHANGELOG.json b/rigs/heft-vscode-extension-rig/CHANGELOG.json new file mode 100644 index 00000000000..a601854fc36 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/CHANGELOG.json @@ -0,0 +1,666 @@ +{ + "name": "@rushstack/heft-vscode-extension-rig", + "entries": [ + { + "version": "1.1.13", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.13", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.118`" + }, + { + "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.12", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.12", + "date": "Wed, 03 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.14`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.11", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.117`" + }, + { + "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.10", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.10", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.12`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.9", + "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-node-rig\" to `2.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.116`" + }, + { + "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.8", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.8", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.10`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.7", + "date": "Mon, 10 Nov 2025 16:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.9`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.6", + "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-node-rig\" to `2.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.115`" + }, + { + "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.5", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.5", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.7`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.114`" + }, + { + "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.3", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.113`" + }, + { + "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.2", + "tag": "@rushstack/heft-vscode-extension-rig_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-vscode-extension-rig_v1.1.1", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.4`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-vscode-extension-rig_v1.1.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/heft-node-rig\" to `2.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.3`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-vscode-extension-rig_v1.0.2", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.112`" + }, + { + "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-vscode-extension-rig_v1.0.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.111`" + }, + { + "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-vscode-extension-rig_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/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.10", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.43`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.9", + "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-node-rig\" to `2.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.42`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.108`" + }, + { + "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.8", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.8", + "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-node-rig\" to `2.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.41`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.107`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.7", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.6", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.5", + "date": "Thu, 21 Aug 2025 00:12:45 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for verifying extension signature." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.4", + "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-node-rig\" to `2.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.106`" + }, + { + "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.3", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.3", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.105`" + }, + { + "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.2", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.2", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.1", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "patch": [ + { + "comment": "Add publish vsix plugin configuration." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-vscode-extension-rig_v0.1.0", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add new rig to build VS Code extensions" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-vscode-extension-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + } + ] +} diff --git a/rigs/heft-vscode-extension-rig/CHANGELOG.md b/rigs/heft-vscode-extension-rig/CHANGELOG.md new file mode 100644 index 00000000000..f8aa80eac6f --- /dev/null +++ b/rigs/heft-vscode-extension-rig/CHANGELOG.md @@ -0,0 +1,154 @@ +# Change Log - @rushstack/heft-vscode-extension-rig + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 1.1.13 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.12 +Wed, 03 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.11 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.10 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 1.1.9 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.8 +Tue, 11 Nov 2025 16:13:26 GMT + +_Version update only_ + +## 1.1.7 +Mon, 10 Nov 2025 16:12:32 GMT + +_Version update only_ + +## 1.1.6 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.5 +Fri, 24 Oct 2025 11:22:09 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 +Tue, 14 Oct 2025 15:13:22 GMT + +_Version update only_ + +## 1.1.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.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.1.10 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.1.9 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.1.8 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.1.7 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.1.6 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.1.5 +Thu, 21 Aug 2025 00:12:45 GMT + +### Patches + +- Add support for verifying extension signature. + +## 0.1.4 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.1.3 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.1.2 +Mon, 28 Jul 2025 15:11:56 GMT + +_Version update only_ + +## 0.1.1 +Sat, 26 Jul 2025 00:12:22 GMT + +### Patches + +- Add publish vsix plugin configuration. + +## 0.1.0 +Wed, 23 Jul 2025 20:55:57 GMT + +### Minor changes + +- Add new rig to build VS Code extensions + diff --git a/rigs/heft-vscode-extension-rig/LICENSE b/rigs/heft-vscode-extension-rig/LICENSE new file mode 100644 index 00000000000..c0887f981ee --- /dev/null +++ b/rigs/heft-vscode-extension-rig/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-vscode-extension-rig + +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/rigs/heft-vscode-extension-rig/README.md b/rigs/heft-vscode-extension-rig/README.md new file mode 100644 index 00000000000..c6f0edc65e5 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/README.md @@ -0,0 +1,30 @@ +## @rushstack/heft-vscode-extension-rig + +A rig package for Node.js projects that build using [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. To learn more about rig packages, consult the +[@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) documentation. + +This rig contains a single profile: `default` + +To enable it, add a **rig.json** file to your project, as shown below: + +**config/rig.json** +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} +``` + +The config files provided by this rig profile can be found in the [heft-vscode-extension-rig/profiles/default]( +https://github.com/microsoft/rushstack/tree/main/rigs/heft-vscode-extension-rig/profiles/default) source folder. + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/rigs/heft-vscode-extension-rig/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/heft-vscode-extension-rig` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/rigs/heft-vscode-extension-rig/package.json b/rigs/heft-vscode-extension-rig/package.json new file mode 100644 index 00000000000..d2ae6ecdef6 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rushstack/heft-vscode-extension-rig", + "version": "1.1.13", + "description": "A rig package for VSCode Extensions that build using Heft", + "license": "MIT", + "scripts": { + "build": "", + "_phase:build": "" + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "rigs/heft-vscode-extension-rig" + }, + "peerDependencies": { + "@rushstack/heft": "^1.1.7" + }, + "dependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/heft-node-rig": "workspace:*", + "@rushstack/heft-vscode-extension-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "eslint": "~9.37.0", + "jest-environment-node": "~29.5.0", + "typescript": "~5.8.2", + "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*" + } +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json b/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json new file mode 100644 index 00000000000..3f29e70fe23 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/api-extractor-task.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/api-extractor-task.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/api-extractor-task.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json b/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json new file mode 100644 index 00000000000..05545217e12 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/heft.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json", + /** + * The list of Heft phases that can be run by Heft. + */ + "phasesByName": { + "build": { + "phaseDescription": "Build and lint the project.", + "cleanFiles": [{ "includeGlobs": ["lib-esm", "lib-dts", "release", ".vscode-test"] }], + + "tasksByName": { + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + }, + "copy-assets": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": ".", + "destinationFolders": ["dist/vsix/unpacked"], + "includeGlobs": ["package.json", "README.md", "LICENSE", ".vscodeignore", "assets/**"] + } + ] + } + } + }, + "package-vsix": { + "taskDependencies": ["typescript", "webpack", "copy-assets"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-vscode-extension-plugin", + "pluginName": "vscode-extension-package-plugin", + "options": { + "unpackedFolderPath": "dist/vsix/unpacked", + "vsixPath": "dist/vsix/extension.vsix", + "manifestPath": "dist/vsix/extension.signature.manifest" + } + } + } + } + }, + "verify-signature": { + "phaseDescription": "Verify the signature of the VSIX package", + "tasksByName": { + "verify-signature": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-vscode-extension-plugin", + "pluginName": "vscode-extension-verify-signature-plugin", + "options": { + "vsixPath": "dist/vsix/extension.vsix", + "manifestPath": "dist/vsix/extension.signature.manifest" + } + } + } + } + }, + "publish-vsix": { + "phaseDescription": "Publish the VSIX package.", + "tasksByName": { + "publish-vsix": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-vscode-extension-plugin", + "pluginName": "vscode-extension-publish-plugin", + "options": { + "vsixPath": "dist/vsix/extension.vsix", + "manifestPath": "dist/vsix/extension.signature.manifest" + } + } + } + } + } + } +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json b/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json new file mode 100644 index 00000000000..4bb17bde3ee --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json b/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json new file mode 100644 index 00000000000..bce265a4f3f --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + }, + { + "operationName": "build", + "outputFolderNames": ["dist", "lib", "lib-commonjs", "temp"] + } + ] +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json b/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json new file mode 100644 index 00000000000..92590ba960e --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/config/typescript.json @@ -0,0 +1,8 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "extends": "@rushstack/heft-node-rig/profiles/default/config/typescript.json" +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..62d215f24c5 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals.js @@ -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. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..31940fac123 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/packlets.js @@ -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. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/packlets'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..8a307de74c1 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/tsdoc.js @@ -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. + +module.exports = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..6754a7434f0 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.js new file mode 100644 index 00000000000..4ec8da74a49 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool.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('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); + +module.exports = [ + ...nodeTrustedToolProfile, + { + files: ['**/*.ts', '**/*.tsx'], + rules: { + // Rationale: Use of `void` to explicitly indicate that a floating promise is expected + // and allowed. + 'no-void': ['error', { allowAsStatement: true }], + + // Rationale: Use of `console` logging is generally discouraged. Use VS Code output + // channels where possible to surface logs. + 'no-console': ['warn', { allow: ['debug', 'info', 'time', 'timeEnd', 'trace'] }] + } + } +]; diff --git a/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.js b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.js new file mode 100644 index 00000000000..d6374c9eaf7 --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node.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/heft-node-rig/profiles/default/includes/eslint/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + rules: { + // Rationale: Use of `void` to explicitly indicate that a floating promise is expected + // and allowed. + 'no-void': ['error', { allowAsStatement: true }] + } + } +]; diff --git a/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json b/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json new file mode 100644 index 00000000000..a1fa195979a --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/tsconfig-base.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "extends": "../../node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + + "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, + "resolveJsonModule": true, + "skipLibCheck": true, + + "types": ["heft-jest"], + "typeRoots": ["../../../../../node_modules/@types", "../../node_modules/@types"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"], + + "incremental": true + }, + "include": ["../../../../../src/**/*.ts", "../../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js b/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js new file mode 100644 index 00000000000..e9610c1d27b --- /dev/null +++ b/rigs/heft-vscode-extension-rig/profiles/default/webpack.config.base.js @@ -0,0 +1,77 @@ +// @ts-check +/* eslint-env es6 */ + +'use strict'; + +const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); + +/** @typedef {import('webpack').Configuration} WebpackConfig **/ +function createExtensionConfig({ production, webpack, entry, outputPath }) { + /** @type WebpackConfig */ + const extensionConfig = { + target: 'node', + mode: production ? 'production' : 'none', + entry, + output: { + path: outputPath, + filename: 'extension.js', + libraryTarget: 'commonjs2' + }, + externals: { + vscode: 'commonjs vscode' + }, + devtool: production ? 'hidden-source-map' : 'source-map', + infrastructureLogging: { + level: 'log' + }, + plugins: [ + new PreserveDynamicRequireWebpackPlugin(), + new webpack.DefinePlugin({ + ___DEV___: JSON.stringify(!production) + }) + ], + optimization: { + minimize: false + } + }; + return extensionConfig; +} + +function createWebExtensionConfig({ production, webpack, entry, outputPath }) { + /** @type WebpackConfig */ + const webExtensionConfig = { + target: 'webworker', // extensions run in a webworker context + mode: production ? 'production' : 'none', + entry, + output: { + filename: 'extension.js', + path: outputPath, + libraryTarget: 'commonjs' + }, + plugins: [ + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1 // disable chunks by default since web extensions must be a single bundle + }), + new webpack.ProvidePlugin({ + process: 'process/browser' // provide a shim for the global `process` variable + }), + new webpack.DefinePlugin({ + ___DEV___: JSON.stringify(!production) + }) + ], + externals: { + vscode: 'commonjs vscode' + }, + devtool: production ? 'hidden-source-map' : 'source-map', + infrastructureLogging: { + level: 'log' + }, + optimization: { + minimize: false + } + }; + + return webExtensionConfig; +} + +module.exports = { createExtensionConfig, createWebExtensionConfig }; diff --git a/rigs/heft-web-rig/.npmignore b/rigs/heft-web-rig/.npmignore new file mode 100644 index 00000000000..2b485313c3f --- /dev/null +++ b/rigs/heft-web-rig/.npmignore @@ -0,0 +1,35 @@ +# 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/** + +!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 + +# 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. +# --------------------------------------------------------------------------- + +!/profiles/** +!/shared/** diff --git a/rigs/heft-web-rig/CHANGELOG.json b/rigs/heft-web-rig/CHANGELOG.json new file mode 100644 index 00000000000..cbea36ebbf9 --- /dev/null +++ b/rigs/heft-web-rig/CHANGELOG.json @@ -0,0 +1,10916 @@ +{ + "name": "@rushstack/heft-web-rig", + "entries": [ + { + "version": "1.1.12", + "tag": "@rushstack/heft-web-rig_v1.1.12", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.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.1.11", + "tag": "@rushstack/heft-web-rig_v1.1.11", + "date": "Wed, 03 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-web-rig_v1.1.10", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.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.1.9", + "tag": "@rushstack/heft-web-rig_v1.1.9", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-web-rig_v1.1.8", + "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/eslint-config\" to `4.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.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.7", + "tag": "@rushstack/heft-web-rig_v1.1.7", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-web-rig_v1.1.6", + "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-api-extractor-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.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.5", + "tag": "@rushstack/heft-web-rig_v1.1.5", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.3`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-web-rig_v1.1.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.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/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-web-rig_v1.1.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.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/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-web-rig_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-web-rig_v1.1.1", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.5.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-web-rig_v1.1.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-config\" to `4.5.0`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-web-rig_v1.0.2", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.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/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/heft-web-rig_v1.0.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.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/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-web-rig_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/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.0.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.29.11", + "tag": "@rushstack/heft-web-rig_v0.29.11", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.29.10", + "tag": "@rushstack/heft-web-rig_v0.29.10", + "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-api-extractor-plugin\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.29.9", + "tag": "@rushstack/heft-web-rig_v0.29.9", + "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-api-extractor-plugin\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.29.8", + "tag": "@rushstack/heft-web-rig_v0.29.8", + "date": "Sun, 31 Aug 2025 02:24:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.12`" + } + ] + } + }, + { + "version": "0.29.7", + "tag": "@rushstack/heft-web-rig_v0.29.7", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.29.6", + "tag": "@rushstack/heft-web-rig_v0.29.6", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.29.5", + "tag": "@rushstack/heft-web-rig_v0.29.5", + "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-api-extractor-plugin\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.29.4", + "tag": "@rushstack/heft-web-rig_v0.29.4", + "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-api-extractor-plugin\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.29.3", + "tag": "@rushstack/heft-web-rig_v0.29.3", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.10`" + } + ] + } + }, + { + "version": "0.29.2", + "tag": "@rushstack/heft-web-rig_v0.29.2", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.29.1", + "tag": "@rushstack/heft-web-rig_v0.29.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.29.0", + "tag": "@rushstack/heft-web-rig_v0.29.0", + "date": "Wed, 09 Jul 2025 04:01:17 GMT", + "comments": { + "minor": [ + { + "comment": "Clean the temp/sass-ts folder." + } + ] + } + }, + { + "version": "0.28.17", + "tag": "@rushstack/heft-web-rig_v0.28.17", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "none": [ + { + "comment": "Add flat config compatible versions of profiles and mixins for ESLint. These are located under the `profiles/default/includes/eslint/flat/*` path. If you need to remain on ESLint 8, ensure your rig or project consumes ESLint 8, and that you use the legacy configuration files." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.28.16", + "tag": "@rushstack/heft-web-rig_v0.28.16", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.28.15", + "tag": "@rushstack/heft-web-rig_v0.28.15", + "date": "Fri, 06 Jun 2025 00:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.28.14", + "tag": "@rushstack/heft-web-rig_v0.28.14", + "date": "Thu, 15 May 2025 00:11:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.7`" + } + ] + } + }, + { + "version": "0.28.13", + "tag": "@rushstack/heft-web-rig_v0.28.13", + "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-api-extractor-plugin\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.28.12", + "tag": "@rushstack/heft-web-rig_v0.28.12", + "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-api-extractor-plugin\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.28.11", + "tag": "@rushstack/heft-web-rig_v0.28.11", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.28.10", + "tag": "@rushstack/heft-web-rig_v0.28.10", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.28.9", + "tag": "@rushstack/heft-web-rig_v0.28.9", + "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-api-extractor-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.28.8", + "tag": "@rushstack/heft-web-rig_v0.28.8", + "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-api-extractor-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.28.7", + "tag": "@rushstack/heft-web-rig_v0.28.7", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.28.6", + "tag": "@rushstack/heft-web-rig_v0.28.6", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.28.5", + "tag": "@rushstack/heft-web-rig_v0.28.5", + "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-api-extractor-plugin\" to `0.3.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.28.4", + "tag": "@rushstack/heft-web-rig_v0.28.4", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.28.3", + "tag": "@rushstack/heft-web-rig_v0.28.3", + "date": "Tue, 25 Mar 2025 00:12:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.28`" + } + ] + } + }, + { + "version": "0.28.2", + "tag": "@rushstack/heft-web-rig_v0.28.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.28.1", + "tag": "@rushstack/heft-web-rig_v0.28.1", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.28.0", + "tag": "@rushstack/heft-web-rig_v0.28.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump TypeScript to ~5.8.2." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.27.2", + "tag": "@rushstack/heft-web-rig_v0.27.2", + "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-api-extractor-plugin\" to `0.3.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.27.1", + "tag": "@rushstack/heft-web-rig_v0.27.1", + "date": "Thu, 06 Mar 2025 01:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.23`" + } + ] + } + }, + { + "version": "0.27.0", + "tag": "@rushstack/heft-web-rig_v0.27.0", + "date": "Tue, 04 Mar 2025 16:10:41 GMT", + "comments": { + "minor": [ + { + "comment": "Bump Webpack to ~5.98.0." + } + ] + } + }, + { + "version": "0.26.0", + "tag": "@rushstack/heft-web-rig_v0.26.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `typescript` dependency to `~5.7.3`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.15`" + } + ] + } + }, + { + "version": "0.25.26", + "tag": "@rushstack/heft-web-rig_v0.25.26", + "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-api-extractor-plugin\" to `0.3.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.25.25", + "tag": "@rushstack/heft-web-rig_v0.25.25", + "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-api-extractor-plugin\" to `0.3.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.25.24", + "tag": "@rushstack/heft-web-rig_v0.25.24", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.25.23", + "tag": "@rushstack/heft-web-rig_v0.25.23", + "date": "Tue, 25 Feb 2025 01:11:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.18`" + } + ] + } + }, + { + "version": "0.25.22", + "tag": "@rushstack/heft-web-rig_v0.25.22", + "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-api-extractor-plugin\" to `0.3.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.25.21", + "tag": "@rushstack/heft-web-rig_v0.25.21", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.25.20", + "tag": "@rushstack/heft-web-rig_v0.25.20", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.25.19", + "tag": "@rushstack/heft-web-rig_v0.25.19", + "date": "Fri, 07 Feb 2025 01:10:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.6`" + } + ] + } + }, + { + "version": "0.25.18", + "tag": "@rushstack/heft-web-rig_v0.25.18", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.25.17", + "tag": "@rushstack/heft-web-rig_v0.25.17", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.25.16", + "tag": "@rushstack/heft-web-rig_v0.25.16", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.25.15", + "tag": "@rushstack/heft-web-rig_v0.25.15", + "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-api-extractor-plugin\" to `0.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, + { + "version": "0.25.14", + "tag": "@rushstack/heft-web-rig_v0.25.14", + "date": "Tue, 07 Jan 2025 16:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.1.1`" + } + ] + } + }, + { + "version": "0.25.13", + "tag": "@rushstack/heft-web-rig_v0.25.13", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.10` to `0.68.11`" + } + ] + } + }, + { + "version": "0.25.12", + "tag": "@rushstack/heft-web-rig_v0.25.12", + "date": "Tue, 10 Dec 2024 07:32:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.14.0`" + } + ] + } + }, + { + "version": "0.25.11", + "tag": "@rushstack/heft-web-rig_v0.25.11", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.9` to `0.68.10`" + } + ] + } + }, + { + "version": "0.25.10", + "tag": "@rushstack/heft-web-rig_v0.25.10", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.8` to `0.68.9`" + } + ] + } + }, + { + "version": "0.25.9", + "tag": "@rushstack/heft-web-rig_v0.25.9", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.7` to `0.68.8`" + } + ] + } + }, + { + "version": "0.25.8", + "tag": "@rushstack/heft-web-rig_v0.25.8", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.6` to `0.68.7`" + } + ] + } + }, + { + "version": "0.25.7", + "tag": "@rushstack/heft-web-rig_v0.25.7", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.5` to `0.68.6`" + } + ] + } + }, + { + "version": "0.25.6", + "tag": "@rushstack/heft-web-rig_v0.25.6", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.4` to `0.68.5`" + } + ] + } + }, + { + "version": "0.25.5", + "tag": "@rushstack/heft-web-rig_v0.25.5", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.3` to `0.68.4`" + } + ] + } + }, + { + "version": "0.25.4", + "tag": "@rushstack/heft-web-rig_v0.25.4", + "date": "Wed, 16 Oct 2024 00:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.32`" + } + ] + } + }, + { + "version": "0.25.3", + "tag": "@rushstack/heft-web-rig_v0.25.3", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.2` to `0.68.3`" + } + ] + } + }, + { + "version": "0.25.2", + "tag": "@rushstack/heft-web-rig_v0.25.2", + "date": "Thu, 10 Oct 2024 00:11:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.25.1", + "tag": "@rushstack/heft-web-rig_v0.25.1", + "date": "Thu, 03 Oct 2024 19:46:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.25.0", + "tag": "@rushstack/heft-web-rig_v0.25.0", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "minor": [ + { + "comment": "Update to webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.1` to `0.68.2`" + } + ] + } + }, + { + "version": "0.24.37", + "tag": "@rushstack/heft-web-rig_v0.24.37", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.0` to `0.68.1`" + } + ] + } + }, + { + "version": "0.24.36", + "tag": "@rushstack/heft-web-rig_v0.24.36", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.2` to `0.68.0`" + } + ] + } + }, + { + "version": "0.24.35", + "tag": "@rushstack/heft-web-rig_v0.24.35", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.21`" + } + ] + } + }, + { + "version": "0.24.34", + "tag": "@rushstack/heft-web-rig_v0.24.34", + "date": "Sat, 21 Sep 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.12`" + } + ] + } + }, + { + "version": "0.24.33", + "tag": "@rushstack/heft-web-rig_v0.24.33", + "date": "Thu, 19 Sep 2024 00:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.2`" + } + ] + } + }, + { + "version": "0.24.32", + "tag": "@rushstack/heft-web-rig_v0.24.32", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.1` to `0.67.2`" + } + ] + } + }, + { + "version": "0.24.31", + "tag": "@rushstack/heft-web-rig_v0.24.31", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.67.0` to `0.67.1`" + } + ] + } + }, + { + "version": "0.24.30", + "tag": "@rushstack/heft-web-rig_v0.24.30", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.18`" + } + ] + } + }, + { + "version": "0.24.29", + "tag": "@rushstack/heft-web-rig_v0.24.29", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.26` to `0.67.0`" + } + ] + } + }, + { + "version": "0.24.28", + "tag": "@rushstack/heft-web-rig_v0.24.28", + "date": "Wed, 14 Aug 2024 22:37:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.24.27", + "tag": "@rushstack/heft-web-rig_v0.24.27", + "date": "Tue, 13 Aug 2024 18:17:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.48`" + } + ] + } + }, + { + "version": "0.24.26", + "tag": "@rushstack/heft-web-rig_v0.24.26", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.25` to `0.66.26`" + } + ] + } + }, + { + "version": "0.24.25", + "tag": "@rushstack/heft-web-rig_v0.24.25", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.24` to `0.66.25`" + } + ] + } + }, + { + "version": "0.24.24", + "tag": "@rushstack/heft-web-rig_v0.24.24", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.23` to `0.66.24`" + } + ] + } + }, + { + "version": "0.24.23", + "tag": "@rushstack/heft-web-rig_v0.24.23", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.22` to `0.66.23`" + } + ] + } + }, + { + "version": "0.24.22", + "tag": "@rushstack/heft-web-rig_v0.24.22", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.21` to `0.66.22`" + } + ] + } + }, + { + "version": "0.24.21", + "tag": "@rushstack/heft-web-rig_v0.24.21", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.20` to `0.66.21`" + } + ] + } + }, + { + "version": "0.24.20", + "tag": "@rushstack/heft-web-rig_v0.24.20", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.19` to `0.66.20`" + } + ] + } + }, + { + "version": "0.24.19", + "tag": "@rushstack/heft-web-rig_v0.24.19", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.18` to `0.66.19`" + } + ] + } + }, + { + "version": "0.24.18", + "tag": "@rushstack/heft-web-rig_v0.24.18", + "date": "Tue, 11 Jun 2024 00:21:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.24.17", + "tag": "@rushstack/heft-web-rig_v0.24.17", + "date": "Fri, 07 Jun 2024 15:10:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.24.16", + "tag": "@rushstack/heft-web-rig_v0.24.16", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.17` to `0.66.18`" + } + ] + } + }, + { + "version": "0.24.15", + "tag": "@rushstack/heft-web-rig_v0.24.15", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.16` to `0.66.17`" + } + ] + } + }, + { + "version": "0.24.14", + "tag": "@rushstack/heft-web-rig_v0.24.14", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.15` to `0.66.16`" + } + ] + } + }, + { + "version": "0.24.13", + "tag": "@rushstack/heft-web-rig_v0.24.13", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.14` to `0.66.15`" + } + ] + } + }, + { + "version": "0.24.12", + "tag": "@rushstack/heft-web-rig_v0.24.12", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.13` to `0.66.14`" + } + ] + } + }, + { + "version": "0.24.11", + "tag": "@rushstack/heft-web-rig_v0.24.11", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.12` to `0.66.13`" + } + ] + } + }, + { + "version": "0.24.10", + "tag": "@rushstack/heft-web-rig_v0.24.10", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.11` to `0.66.12`" + } + ] + } + }, + { + "version": "0.24.9", + "tag": "@rushstack/heft-web-rig_v0.24.9", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.10` to `0.66.11`" + } + ] + } + }, + { + "version": "0.24.8", + "tag": "@rushstack/heft-web-rig_v0.24.8", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.9` to `0.66.10`" + } + ] + } + }, + { + "version": "0.24.7", + "tag": "@rushstack/heft-web-rig_v0.24.7", + "date": "Fri, 17 May 2024 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.10`" + } + ] + } + }, + { + "version": "0.24.6", + "tag": "@rushstack/heft-web-rig_v0.24.6", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.8` to `0.66.9`" + } + ] + } + }, + { + "version": "0.24.5", + "tag": "@rushstack/heft-web-rig_v0.24.5", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.7` to `0.66.8`" + } + ] + } + }, + { + "version": "0.24.4", + "tag": "@rushstack/heft-web-rig_v0.24.4", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.6` to `0.66.7`" + } + ] + } + }, + { + "version": "0.24.3", + "tag": "@rushstack/heft-web-rig_v0.24.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.5` to `0.66.6`" + } + ] + } + }, + { + "version": "0.24.2", + "tag": "@rushstack/heft-web-rig_v0.24.2", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.4` to `0.66.5`" + } + ] + } + }, + { + "version": "0.24.1", + "tag": "@rushstack/heft-web-rig_v0.24.1", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.3` to `0.66.4`" + } + ] + } + }, + { + "version": "0.24.0", + "tag": "@rushstack/heft-web-rig_v0.24.0", + "date": "Wed, 10 Apr 2024 21:59:39 GMT", + "comments": { + "minor": [ + { + "comment": "Bump ESLint to ~8.57.0." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.9`" + } + ] + } + }, + { + "version": "0.23.6", + "tag": "@rushstack/heft-web-rig_v0.23.6", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.2` to `0.66.3`" + } + ] + } + }, + { + "version": "0.23.5", + "tag": "@rushstack/heft-web-rig_v0.23.5", + "date": "Fri, 29 Mar 2024 05:46:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.8`" + } + ] + } + }, + { + "version": "0.23.4", + "tag": "@rushstack/heft-web-rig_v0.23.4", + "date": "Thu, 28 Mar 2024 22:42:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.23.3", + "tag": "@rushstack/heft-web-rig_v0.23.3", + "date": "Thu, 28 Mar 2024 18:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.7`" + } + ] + } + }, + { + "version": "0.23.2", + "tag": "@rushstack/heft-web-rig_v0.23.2", + "date": "Wed, 27 Mar 2024 19:47:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.6`" + } + ] + } + }, + { + "version": "0.23.1", + "tag": "@rushstack/heft-web-rig_v0.23.1", + "date": "Wed, 20 Mar 2024 02:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.5`" + } + ] + } + }, + { + "version": "0.23.0", + "tag": "@rushstack/heft-web-rig_v0.23.0", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 5.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.1` to `0.66.2`" + } + ] + } + }, + { + "version": "0.22.9", + "tag": "@rushstack/heft-web-rig_v0.22.9", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.66.0` to `0.66.1`" + } + ] + } + }, + { + "version": "0.22.8", + "tag": "@rushstack/heft-web-rig_v0.22.8", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.10` to `0.66.0`" + } + ] + } + }, + { + "version": "0.22.7", + "tag": "@rushstack/heft-web-rig_v0.22.7", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.9` to `0.65.10`" + } + ] + } + }, + { + "version": "0.22.6", + "tag": "@rushstack/heft-web-rig_v0.22.6", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.8` to `0.65.9`" + } + ] + } + }, + { + "version": "0.22.5", + "tag": "@rushstack/heft-web-rig_v0.22.5", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.7` to `0.65.8`" + } + ] + } + }, + { + "version": "0.22.4", + "tag": "@rushstack/heft-web-rig_v0.22.4", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.6` to `0.65.7`" + } + ] + } + }, + { + "version": "0.22.3", + "tag": "@rushstack/heft-web-rig_v0.22.3", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.5` to `0.65.6`" + } + ] + } + }, + { + "version": "0.22.2", + "tag": "@rushstack/heft-web-rig_v0.22.2", + "date": "Mon, 26 Feb 2024 16:10:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.15`" + } + ] + } + }, + { + "version": "0.22.1", + "tag": "@rushstack/heft-web-rig_v0.22.1", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.4` to `^0.65.5`" + } + ] + } + }, + { + "version": "0.22.0", + "tag": "@rushstack/heft-web-rig_v0.22.0", + "date": "Thu, 22 Feb 2024 06:31:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update the \"asset/resource\" rule to include file extensions for font assets" + } + ] + } + }, + { + "version": "0.21.5", + "tag": "@rushstack/heft-web-rig_v0.21.5", + "date": "Thu, 22 Feb 2024 05:54:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.14`" + } + ] + } + }, + { + "version": "0.21.4", + "tag": "@rushstack/heft-web-rig_v0.21.4", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.3` to `^0.65.4`" + } + ] + } + }, + { + "version": "0.21.3", + "tag": "@rushstack/heft-web-rig_v0.21.3", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.2` to `^0.65.3`" + } + ] + } + }, + { + "version": "0.21.2", + "tag": "@rushstack/heft-web-rig_v0.21.2", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.1` to `^0.65.2`" + } + ] + } + }, + { + "version": "0.21.1", + "tag": "@rushstack/heft-web-rig_v0.21.1", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.65.0` to `^0.65.1`" + } + ] + } + }, + { + "version": "0.21.0", + "tag": "@rushstack/heft-web-rig_v0.21.0", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Include the `set-environment-variables-plugin` plugin from the `@rushstack/heft` package to set the `BROWSERSLIST_IGNORE_OLD_DATA` environment variable to `1` to suppress the warning printed when the `browserslist` package decides it's out of date." + }, + { + "comment": "Rename the `sass-typings` task in the \"library\" profile to `sass`, which more accurately describes what the task does and matches what's in the \"app\" profile." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.8` to `^0.65.0`" + } + ] + } + }, + { + "version": "0.20.10", + "tag": "@rushstack/heft-web-rig_v0.20.10", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.7` to `^0.64.8`" + } + ] + } + }, + { + "version": "0.20.9", + "tag": "@rushstack/heft-web-rig_v0.20.9", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.6` to `^0.64.7`" + } + ] + } + }, + { + "version": "0.20.8", + "tag": "@rushstack/heft-web-rig_v0.20.8", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.5` to `^0.64.6`" + } + ] + } + }, + { + "version": "0.20.7", + "tag": "@rushstack/heft-web-rig_v0.20.7", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.4` to `^0.64.5`" + } + ] + } + }, + { + "version": "0.20.6", + "tag": "@rushstack/heft-web-rig_v0.20.6", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.3` to `^0.64.4`" + } + ] + } + }, + { + "version": "0.20.5", + "tag": "@rushstack/heft-web-rig_v0.20.5", + "date": "Thu, 25 Jan 2024 23:03:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.2`" + } + ] + } + }, + { + "version": "0.20.4", + "tag": "@rushstack/heft-web-rig_v0.20.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.2` to `^0.64.3`" + } + ] + } + }, + { + "version": "0.20.3", + "tag": "@rushstack/heft-web-rig_v0.20.3", + "date": "Wed, 24 Jan 2024 07:38:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.1`" + } + ] + } + }, + { + "version": "0.20.2", + "tag": "@rushstack/heft-web-rig_v0.20.2", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.1` to `^0.64.2`" + } + ] + } + }, + { + "version": "0.20.1", + "tag": "@rushstack/heft-web-rig_v0.20.1", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.64.0` to `^0.64.1`" + } + ] + } + }, + { + "version": "0.20.0", + "tag": "@rushstack/heft-web-rig_v0.20.0", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 5.3" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.6` to `^0.64.0`" + } + ] + } + }, + { + "version": "0.19.17", + "tag": "@rushstack/heft-web-rig_v0.19.17", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.5` to `^0.63.6`" + } + ] + } + }, + { + "version": "0.19.16", + "tag": "@rushstack/heft-web-rig_v0.19.16", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.4` to `^0.63.5`" + } + ] + } + }, + { + "version": "0.19.15", + "tag": "@rushstack/heft-web-rig_v0.19.15", + "date": "Fri, 15 Dec 2023 01:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.5.1`" + } + ] + } + }, + { + "version": "0.19.14", + "tag": "@rushstack/heft-web-rig_v0.19.14", + "date": "Fri, 08 Dec 2023 20:48:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.19.13", + "tag": "@rushstack/heft-web-rig_v0.19.13", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.3` to `^0.63.4`" + } + ] + } + }, + { + "version": "0.19.12", + "tag": "@rushstack/heft-web-rig_v0.19.12", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.2` to `^0.63.3`" + } + ] + } + }, + { + "version": "0.19.11", + "tag": "@rushstack/heft-web-rig_v0.19.11", + "date": "Wed, 22 Nov 2023 01:45:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.5.0`" + } + ] + } + }, + { + "version": "0.19.10", + "tag": "@rushstack/heft-web-rig_v0.19.10", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.1` to `^0.63.2`" + } + ] + } + }, + { + "version": "0.19.9", + "tag": "@rushstack/heft-web-rig_v0.19.9", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.63.0` to `^0.63.1`" + } + ] + } + }, + { + "version": "0.19.8", + "tag": "@rushstack/heft-web-rig_v0.19.8", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.3` to `^0.63.0`" + } + ] + } + }, + { + "version": "0.19.7", + "tag": "@rushstack/heft-web-rig_v0.19.7", + "date": "Thu, 26 Oct 2023 00:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.19.6", + "tag": "@rushstack/heft-web-rig_v0.19.6", + "date": "Mon, 23 Oct 2023 15:18:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.19.5", + "tag": "@rushstack/heft-web-rig_v0.19.5", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.2` to `^0.62.3`" + } + ] + } + }, + { + "version": "0.19.4", + "tag": "@rushstack/heft-web-rig_v0.19.4", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.1` to `^0.62.2`" + } + ] + } + }, + { + "version": "0.19.3", + "tag": "@rushstack/heft-web-rig_v0.19.3", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.62.0` to `^0.62.1`" + } + ] + } + }, + { + "version": "0.19.2", + "tag": "@rushstack/heft-web-rig_v0.19.2", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.3` to `^0.62.0`" + } + ] + } + }, + { + "version": "0.19.1", + "tag": "@rushstack/heft-web-rig_v0.19.1", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.2` to `^0.61.3`" + } + ] + } + }, + { + "version": "0.19.0", + "tag": "@rushstack/heft-web-rig_v0.19.0", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the \"eslint-config-\" prefix. This change also includes the ESLint configurations sourced from \"@rushstack/eslint-config\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.1` to `^0.61.2`" + } + ] + } + }, + { + "version": "0.18.30", + "tag": "@rushstack/heft-web-rig_v0.18.30", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.61.0` to `^0.61.1`" + } + ] + } + }, + { + "version": "0.18.29", + "tag": "@rushstack/heft-web-rig_v0.18.29", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.60.0` to `^0.61.0`" + } + ] + } + }, + { + "version": "0.18.28", + "tag": "@rushstack/heft-web-rig_v0.18.28", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.59.0` to `^0.60.0`" + } + ] + } + }, + { + "version": "0.18.27", + "tag": "@rushstack/heft-web-rig_v0.18.27", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.2` to `^0.59.0`" + } + ] + } + }, + { + "version": "0.18.26", + "tag": "@rushstack/heft-web-rig_v0.18.26", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "0.18.25", + "tag": "@rushstack/heft-web-rig_v0.18.25", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.1` to `^0.58.2`" + } + ] + } + }, + { + "version": "0.18.24", + "tag": "@rushstack/heft-web-rig_v0.18.24", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.27`" + } + ] + } + }, + { + "version": "0.18.23", + "tag": "@rushstack/heft-web-rig_v0.18.23", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.26`" + } + ] + } + }, + { + "version": "0.18.22", + "tag": "@rushstack/heft-web-rig_v0.18.22", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + } + ] + } + }, + { + "version": "0.18.21", + "tag": "@rushstack/heft-web-rig_v0.18.21", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.58.0` to `^0.58.1`" + } + ] + } + }, + { + "version": "0.18.20", + "tag": "@rushstack/heft-web-rig_v0.18.20", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.1` to `^0.58.0`" + } + ] + } + }, + { + "version": "0.18.19", + "tag": "@rushstack/heft-web-rig_v0.18.19", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.57.0` to `^0.57.1`" + } + ] + } + }, + { + "version": "0.18.18", + "tag": "@rushstack/heft-web-rig_v0.18.18", + "date": "Mon, 17 Jul 2023 15:20:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.21`" + } + ] + } + }, + { + "version": "0.18.17", + "tag": "@rushstack/heft-web-rig_v0.18.17", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + } + ] + } + }, + { + "version": "0.18.16", + "tag": "@rushstack/heft-web-rig_v0.18.16", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.3` to `^0.57.0`" + } + ] + } + }, + { + "version": "0.18.15", + "tag": "@rushstack/heft-web-rig_v0.18.15", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.2` to `^0.56.3`" + } + ] + } + }, + { + "version": "0.18.14", + "tag": "@rushstack/heft-web-rig_v0.18.14", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + } + ] + } + }, + { + "version": "0.18.13", + "tag": "@rushstack/heft-web-rig_v0.18.13", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.1` to `^0.56.2`" + } + ] + } + }, + { + "version": "0.18.12", + "tag": "@rushstack/heft-web-rig_v0.18.12", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.56.0` to `^0.56.1`" + } + ] + } + }, + { + "version": "0.18.11", + "tag": "@rushstack/heft-web-rig_v0.18.11", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + } + ] + } + }, + { + "version": "0.18.10", + "tag": "@rushstack/heft-web-rig_v0.18.10", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.2` to `^0.56.0`" + } + ] + } + }, + { + "version": "0.18.9", + "tag": "@rushstack/heft-web-rig_v0.18.9", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.1` to `^0.55.2`" + } + ] + } + }, + { + "version": "0.18.8", + "tag": "@rushstack/heft-web-rig_v0.18.8", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.55.0` to `^0.55.1`" + } + ] + } + }, + { + "version": "0.18.7", + "tag": "@rushstack/heft-web-rig_v0.18.7", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.54.0` to `^0.55.0`" + } + ] + } + }, + { + "version": "0.18.6", + "tag": "@rushstack/heft-web-rig_v0.18.6", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.1` to `^0.54.0`" + } + ] + } + }, + { + "version": "0.18.5", + "tag": "@rushstack/heft-web-rig_v0.18.5", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.53.0` to `^0.53.1`" + } + ] + } + }, + { + "version": "0.18.4", + "tag": "@rushstack/heft-web-rig_v0.18.4", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + } + ] + } + }, + { + "version": "0.18.3", + "tag": "@rushstack/heft-web-rig_v0.18.3", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.2` to `^0.53.0`" + } + ] + } + }, + { + "version": "0.18.2", + "tag": "@rushstack/heft-web-rig_v0.18.2", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.1` to `^0.52.2`" + } + ] + } + }, + { + "version": "0.18.1", + "tag": "@rushstack/heft-web-rig_v0.18.1", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.52.0` to `^0.52.1`" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/heft-web-rig_v0.18.0", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"heft start\" alias that maps to \"heft build-watch --serve\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.51.0` to `^0.52.0`" + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/heft-web-rig_v0.17.0", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "minor": [ + { + "comment": "Update Jest environment \"customExportConditions\" to [\"require\", \"node\", \"umd\"]" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + } + ] + } + }, + { + "version": "0.16.1", + "tag": "@rushstack/heft-web-rig_v0.16.1", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/heft-web-rig_v0.16.0", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "minor": [ + { + "comment": "Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-api-extractor-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-lint-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.7` to `^0.51.0`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/heft-web-rig_v0.15.2", + "date": "Fri, 02 Jun 2023 00:24:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/heft-web-rig_v0.15.1", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.6` to `^0.50.7`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/heft-web-rig_v0.15.0", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript to ~5.0.4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.5` to `^0.50.6`" + } + ] + } + }, + { + "version": "0.14.17", + "tag": "@rushstack/heft-web-rig_v0.14.17", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.4` to `^0.50.5`" + } + ] + } + }, + { + "version": "0.14.16", + "tag": "@rushstack/heft-web-rig_v0.14.16", + "date": "Thu, 11 May 2023 00:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.14.15", + "tag": "@rushstack/heft-web-rig_v0.14.15", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.3` to `^0.50.4`" + } + ] + } + }, + { + "version": "0.14.14", + "tag": "@rushstack/heft-web-rig_v0.14.14", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.2` to `^0.50.3`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/heft-web-rig_v0.14.13", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.1` to `^0.50.2`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/heft-web-rig_v0.14.12", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.50.0` to `^0.50.1`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/heft-web-rig_v0.14.11", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/heft-web-rig_v0.14.10", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/heft-web-rig_v0.14.9", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.3`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/heft-web-rig_v0.14.8", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade Jest to 29.5.0." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/heft-web-rig_v0.14.7", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.7` to `^0.50.0`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/heft-web-rig_v0.14.6", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/heft-web-rig_v0.14.5", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.6` to `^0.49.7`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/heft-web-rig_v0.14.4", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.5` to `^0.49.6`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/heft-web-rig_v0.14.3", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.4` to `^0.49.5`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/heft-web-rig_v0.14.2", + "date": "Tue, 31 Jan 2023 01:23:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/heft-web-rig_v0.14.1", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.3` to `^0.49.4`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/heft-web-rig_v0.14.0", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest from `~27.4.2` to `~29.3.1`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.69`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/heft-web-rig_v0.13.2", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.2` to `^0.49.3`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/heft-web-rig_v0.13.1", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.1` to `^0.49.2`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/heft-web-rig_v0.13.0", + "date": "Sun, 22 Jan 2023 20:37:08 GMT", + "comments": { + "minor": [ + { + "comment": "Disable \"mini-css-extract-plugin\" for the \"library\" rig profile because there isn't a straightforward way to load .css files from a library" + } + ] + } + }, + { + "version": "0.12.17", + "tag": "@rushstack/heft-web-rig_v0.12.17", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.49.0` to `^0.49.1`" + } + ] + } + }, + { + "version": "0.12.16", + "tag": "@rushstack/heft-web-rig_v0.12.16", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.9` to `^0.49.0`" + } + ] + } + }, + { + "version": "0.12.15", + "tag": "@rushstack/heft-web-rig_v0.12.15", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.8` to `^0.48.9`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/heft-web-rig_v0.12.14", + "date": "Fri, 02 Dec 2022 01:15:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.63`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/heft-web-rig_v0.12.13", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.3`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/heft-web-rig_v0.12.12", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.62`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/heft-web-rig_v0.12.11", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.7` to `^0.48.8`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/heft-web-rig_v0.12.10", + "date": "Wed, 26 Oct 2022 15:16:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/heft-web-rig_v0.12.9", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.6` to `^0.48.7`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/heft-web-rig_v0.12.8", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.59`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/heft-web-rig_v0.12.7", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.5` to `^0.48.6`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/heft-web-rig_v0.12.6", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.4` to `^0.48.5`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/heft-web-rig_v0.12.5", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.3` to `^0.48.4`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/heft-web-rig_v0.12.4", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.2` to `^0.48.3`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/heft-web-rig_v0.12.3", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.1` to `^0.48.2`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/heft-web-rig_v0.12.2", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.48.0` to `^0.48.1`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/heft-web-rig_v0.12.1", + "date": "Sat, 08 Oct 2022 02:30:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.19`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/heft-web-rig_v0.12.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to TypeScript 4.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.11` to `^0.48.0`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/heft-web-rig_v0.11.13", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.10` to `^0.47.11`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/heft-web-rig_v0.11.12", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.9` to `^0.47.10`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/heft-web-rig_v0.11.11", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.8` to `^0.47.9`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/heft-web-rig_v0.11.10", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.7` to `^0.47.8`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/heft-web-rig_v0.11.9", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.6` to `^0.47.7`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/heft-web-rig_v0.11.8", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.5` to `^0.47.6`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/heft-web-rig_v0.11.7", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.45`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/heft-web-rig_v0.11.6", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.44`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/heft-web-rig_v0.11.5", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.4` to `^0.47.5`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/heft-web-rig_v0.11.4", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.3` to `^0.47.4`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/heft-web-rig_v0.11.3", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.2` to `^0.47.3`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/heft-web-rig_v0.11.2", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.1` to `^0.47.2`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/heft-web-rig_v0.11.1", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.47.0` to `^0.47.1`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/heft-web-rig_v0.11.0", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade TypeScript to 4.7" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.7` to `^0.47.0`" + } + ] + } + }, + { + "version": "0.10.25", + "tag": "@rushstack/heft-web-rig_v0.10.25", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.6` to `^0.46.7`" + } + ] + } + }, + { + "version": "0.10.24", + "tag": "@rushstack/heft-web-rig_v0.10.24", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.5` to `^0.46.6`" + } + ] + } + }, + { + "version": "0.10.23", + "tag": "@rushstack/heft-web-rig_v0.10.23", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.4` to `^0.46.5`" + } + ] + } + }, + { + "version": "0.10.22", + "tag": "@rushstack/heft-web-rig_v0.10.22", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.3` to `^0.46.4`" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/heft-web-rig_v0.10.21", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.2` to `^0.46.3`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/heft-web-rig_v0.10.20", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.1` to `^0.46.2`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/heft-web-rig_v0.10.19", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.46.0` to `^0.46.1`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/heft-web-rig_v0.10.18", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.14` to `^0.46.0`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/heft-web-rig_v0.10.17", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.13` to `^0.45.14`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/heft-web-rig_v0.10.16", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.12` to `^0.45.13`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/heft-web-rig_v0.10.15", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.11` to `^0.45.12`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/heft-web-rig_v0.10.14", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.10` to `^0.45.11`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/heft-web-rig_v0.10.13", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.9` to `^0.45.10`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/heft-web-rig_v0.10.12", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.8` to `^0.45.9`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/heft-web-rig_v0.10.11", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.7` to `^0.45.8`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/heft-web-rig_v0.10.10", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.6` to `^0.45.7`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/heft-web-rig_v0.10.9", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.5` to `^0.45.6`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/heft-web-rig_v0.10.8", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.4` to `^0.45.5`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/heft-web-rig_v0.10.7", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.3` to `^0.45.4`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/heft-web-rig_v0.10.6", + "date": "Wed, 18 May 2022 15:10:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.18`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/heft-web-rig_v0.10.5", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.2` to `^0.45.3`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/heft-web-rig_v0.10.4", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.1` to `^0.45.2`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/heft-web-rig_v0.10.3", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.15`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/heft-web-rig_v0.10.2", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.45.0` to `^0.45.1`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/heft-web-rig_v0.10.1", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.13`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/heft-web-rig_v0.10.0", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.13` to `^0.45.0`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/heft-web-rig_v0.9.11", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.12` to `^0.44.13`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/heft-web-rig_v0.9.10", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.11` to `^0.44.12`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/heft-web-rig_v0.9.9", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.10` to `^0.44.11`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/heft-web-rig_v0.9.8", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.9` to `^0.44.10`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/heft-web-rig_v0.9.7", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.8` to `^0.44.9`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/heft-web-rig_v0.9.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.7` to `^0.44.8`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/heft-web-rig_v0.9.5", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.6` to `^0.44.7`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/heft-web-rig_v0.9.4", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.5` to `^0.44.6`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-web-rig_v0.9.3", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.4` to `^0.44.5`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-web-rig_v0.9.2", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.3` to `^0.44.4`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-web-rig_v0.9.1", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.2` to `^0.44.3`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-web-rig_v0.9.0", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "minor": [ + { + "comment": "A major overhaul of heft-web-rig; for details refer to https://github.com/microsoft/rushstack/pull/3204" + }, + { + "comment": "Set useUnknownInCatchVariables=false in tsconfig.json, to work around https://github.com/microsoft/TypeScript/issues/42596" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/heft-web-rig_v0.8.2", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade ESLint to ~8.7.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.32`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-web-rig_v0.8.1", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.31`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-web-rig_v0.8.0", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "minor": [ + { + "comment": "Update the `rush-project.json` file to follow the new schema and configure the \"build\" command output folders for the \"_phase:build\" phase." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.30`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-web-rig_v0.7.2", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.1` to `^0.44.2`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-web-rig_v0.7.1", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.44.0` to `^0.44.1`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-web-rig_v0.7.0", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade Jest to v27" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.2` to `^0.44.0`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/heft-web-rig_v0.6.4", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/heft-web-rig_v0.6.3", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.1` to `^0.43.2`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/heft-web-rig_v0.6.2", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.43.0` to `^0.43.1`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-web-rig_v0.6.1", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.6` to `^0.43.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-web-rig_v0.6.0", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "minor": [ + { + "comment": "Update to TypeScript 4.5" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.5` to `^0.42.6`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/heft-web-rig_v0.5.0", + "date": "Mon, 06 Dec 2021 16:08:32 GMT", + "comments": { + "minor": [ + { + "comment": "Bump ESLint to v8" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.4` to `^0.42.5`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/heft-web-rig_v0.4.34", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.3` to `^0.42.4`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/heft-web-rig_v0.4.33", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "patch": [ + { + "comment": "Set default Jest environment in Jest configuration to \"jest-environment-jsdom\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.20`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/heft-web-rig_v0.4.32", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.2` to `^0.42.3`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/heft-web-rig_v0.4.31", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.1` to `^0.42.2`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/heft-web-rig_v0.4.30", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.42.0` to `^0.42.1`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/heft-web-rig_v0.4.29", + "date": "Thu, 28 Oct 2021 23:48:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/heft-web-rig_v0.4.28", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.8` to `^0.42.0`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/heft-web-rig_v0.4.27", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.7` to `^0.41.8`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/heft-web-rig_v0.4.26", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.6` to `^0.41.7`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/heft-web-rig_v0.4.25", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.5` to `^0.41.6`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/heft-web-rig_v0.4.24", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.4` to `^0.41.5`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/heft-web-rig_v0.4.23", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.3` to `^0.41.4`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/heft-web-rig_v0.4.22", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.2` to `^0.41.3`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/heft-web-rig_v0.4.21", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.1` to `^0.41.2`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/heft-web-rig_v0.4.20", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.41.0` to `^0.41.1`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/heft-web-rig_v0.4.19", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.40.0` to `^0.41.0`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/heft-web-rig_v0.4.18", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.2` to `^0.40.0`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/heft-web-rig_v0.4.17", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.1` to `^0.39.2`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/heft-web-rig_v0.4.16", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.39.0` to `^0.39.1`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/heft-web-rig_v0.4.15", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.2` to `^0.39.0`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-web-rig_v0.4.14", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.1` to `^0.38.2`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-web-rig_v0.4.13", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.38.0` to `^0.38.1`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-web-rig_v0.4.12", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.4` to `^0.38.0`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-web-rig_v0.4.11", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.3` to `^0.37.4`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-web-rig_v0.4.10", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.2` to `^0.37.3`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-web-rig_v0.4.9", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.1` to `^0.37.2`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-web-rig_v0.4.8", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.37.0` to `^0.37.1`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-web-rig_v0.4.7", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.10`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-web-rig_v0.4.6", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.4` to `^0.37.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-web-rig_v0.4.5", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.3` to `^0.36.4`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-web-rig_v0.4.4", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.2` to `^0.36.3`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-web-rig_v0.4.3", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "patch": [ + { + "comment": "Remove default use of incremental: true in tsconfig-base.json" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.6`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-web-rig_v0.4.2", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.1` to `^0.36.2`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-web-rig_v0.4.1", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "patch": [ + { + "comment": "Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.36.0` to `^0.36.1`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-web-rig_v0.4.0", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "minor": [ + { + "comment": "Enable \"incremental: true\" by default in tsconfig-base.json" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.1` to `^0.36.0`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-web-rig_v0.3.16", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.35.0` to `^0.35.1`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-web-rig_v0.3.15", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "patch": [ + { + "comment": "Use newly extracted Sass plugin (@rushstack/heft-sass-plugin)" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.8` to `^0.35.0`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-web-rig_v0.3.14", + "date": "Tue, 27 Jul 2021 22:31:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-web-rig_v0.3.13", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.7` to `^0.34.8`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-web-rig_v0.3.12", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.6` to `^0.34.7`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-web-rig_v0.3.11", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.5` to `^0.34.6`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-web-rig_v0.3.10", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.4` to `^0.34.5`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-web-rig_v0.3.9", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.3` to `^0.34.4`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-web-rig_v0.3.8", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.2` to `^0.34.3`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-web-rig_v0.3.7", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.32`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-web-rig_v0.3.6", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.1` to `^0.34.2`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-web-rig_v0.3.5", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.34.0` to `^0.34.1`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-web-rig_v0.3.4", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.1` to `^0.34.0`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-web-rig_v0.3.3", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.33.0` to `^0.33.1`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-web-rig_v0.3.2", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.27`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-web-rig_v0.3.1", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.32.0` to `^0.33.0`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-web-rig_v0.3.0", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "minor": [ + { + "comment": "Disable the allowUnreachableCode TypeScript compiler option." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.25`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@rushstack/heft-web-rig_v0.2.38", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.24`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/heft-web-rig_v0.2.37", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "patch": [ + { + "comment": "Add @rushstack/heft-jest-plugin to run during tests" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-jest-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.5` to `^0.32.0`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/heft-web-rig_v0.2.36", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.4` to `^0.31.5`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@rushstack/heft-web-rig_v0.2.35", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.3` to `^0.31.4`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/heft-web-rig_v0.2.34", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.2` to `^0.31.3`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/heft-web-rig_v0.2.33", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.1` to `^0.31.2`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/heft-web-rig_v0.2.32", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.31.0` to `^0.31.1`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/heft-web-rig_v0.2.31", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.7` to `^0.31.0`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/heft-web-rig_v0.2.30", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.6` to `^0.30.7`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/heft-web-rig_v0.2.29", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.5` to `^0.30.6`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/heft-web-rig_v0.2.28", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.4` to `^0.30.5`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/heft-web-rig_v0.2.27", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.3` to `^0.30.4`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/heft-web-rig_v0.2.26", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.2` to `^0.30.3`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/heft-web-rig_v0.2.25", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.1` to `^0.30.2`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/heft-web-rig_v0.2.24", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.30.0` to `^0.30.1`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/heft-web-rig_v0.2.23", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.1` to `^0.30.0`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/heft-web-rig_v0.2.22", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.29.0` to `^0.29.1`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/heft-web-rig_v0.2.21", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.5` to `^0.29.0`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/heft-web-rig_v0.2.20", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.4` to `^0.28.5`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/heft-web-rig_v0.2.19", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.3` to `^0.28.4`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/heft-web-rig_v0.2.18", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "patch": [ + { + "comment": "Explicitly set the noEmitOnError TypeScript compiler option to false in the base tsconfig." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.2` to `^0.28.3`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/heft-web-rig_v0.2.17", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.1` to `^0.28.2`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-web-rig_v0.2.16", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.28.0` to `^0.28.1`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/heft-web-rig_v0.2.15", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.27.0` to `^0.28.0`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/heft-web-rig_v0.2.14", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "patch": [ + { + "comment": "For compatibility with Heft 0.25.5 and earlier versions, add a dependency on the \"@rushstack/heft-webpack4-plugin\" package and update heft.json to load it." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.26.0` to `^0.27.0`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/heft-web-rig_v0.2.13", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.5` to `^0.26.0`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/heft-web-rig_v0.2.12", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.4` to `^0.25.5`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/heft-web-rig_v0.2.11", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.3` to `^0.25.4`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/heft-web-rig_v0.2.10", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.2` to `^0.25.3`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-web-rig_v0.2.9", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.1` to `^0.25.2`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-web-rig_v0.2.8", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.25.0` to `^0.25.1`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-web-rig_v0.2.7", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.4` to `^0.25.0`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-web-rig_v0.2.6", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.3` to `^0.24.4`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-web-rig_v0.2.5", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.2` to `^0.24.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-web-rig_v0.2.4", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.1` to `^0.24.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-web-rig_v0.2.3", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.24.0` to `^0.24.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-web-rig_v0.2.2", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.2` to `^0.24.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-web-rig_v0.2.1", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.1` to `^0.23.2`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-web-rig_v0.2.0", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "minor": [ + { + "comment": "Add a Rush build cache configuration." + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/heft-web-rig_v0.1.34", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.23.0` to `^0.23.1`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/heft-web-rig_v0.1.33", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.7` to `^0.23.0`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/heft-web-rig_v0.1.32", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.6` to `^0.22.7`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/heft-web-rig_v0.1.31", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure rootDir is consistently specified." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.5` to `^0.22.6`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/heft-web-rig_v0.1.30", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.4` to `^0.22.5`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/heft-web-rig_v0.1.29", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.3` to `^0.22.4`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/heft-web-rig_v0.1.28", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.2` to `^0.22.3`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/heft-web-rig_v0.1.27", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.1` to `^0.22.2`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/heft-web-rig_v0.1.26", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.22.0` to `^0.22.1`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/heft-web-rig_v0.1.25", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.3` to `^0.22.0`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/heft-web-rig_v0.1.24", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.2` to `^0.21.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/heft-web-rig_v0.1.23", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.1` to `^0.21.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/heft-web-rig_v0.1.22", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.21.0` to `^0.21.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/heft-web-rig_v0.1.21", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.20.1` to `^0.21.0`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/heft-web-rig_v0.1.20", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.20.0` to `^0.20.1`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/heft-web-rig_v0.1.19", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.5` to `^0.20.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-web-rig_v0.1.18", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.4` to `^0.19.5`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-web-rig_v0.1.17", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.3` to `^0.19.4`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-web-rig_v0.1.16", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.2` to `^0.19.3`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-web-rig_v0.1.15", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.1` to `^0.19.2`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-web-rig_v0.1.14", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.19.0` to `^0.19.1`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-web-rig_v0.1.13", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.18.0` to `^0.19.0`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-web-rig_v0.1.12", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.4` to `^0.18.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-web-rig_v0.1.11", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.3` to `^0.17.4`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-web-rig_v0.1.10", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.2` to `^0.17.3`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-web-rig_v0.1.9", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.17.1` to `^0.17.2`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-web-rig_v0.1.8", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.16.1` to `^0.17.1`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-web-rig_v0.1.7", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "patch": [ + { + "comment": "Update Heft." + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-web-rig_v0.1.6", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "patch": [ + { + "comment": "Update Heft dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.16.0` to `^0.16.1`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-web-rig_v0.1.5", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.4` to `^0.15.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-web-rig_v0.1.4", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.3` to `^0.15.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-web-rig_v0.1.3", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.15.0` to `^0.15.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-web-rig_v0.1.2", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "patch": [ + { + "comment": "Add sass typings plugin configuration." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.14.1` to `^0.15.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-web-rig_v0.1.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.14.0` to `^0.14.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-web-rig_v0.1.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.1.0` to `^0.14.0`" + } + ] + } + } + ] +} diff --git a/rigs/heft-web-rig/CHANGELOG.md b/rigs/heft-web-rig/CHANGELOG.md new file mode 100644 index 00000000000..37c247cd794 --- /dev/null +++ b/rigs/heft-web-rig/CHANGELOG.md @@ -0,0 +1,2277 @@ +# Change Log - @rushstack/heft-web-rig + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 1.1.12 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.11 +Wed, 03 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.10 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.9 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 1.1.8 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.7 +Tue, 11 Nov 2025 16:13:26 GMT + +_Version update only_ + +## 1.1.6 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.5 +Fri, 24 Oct 2025 11:22:09 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 +Tue, 14 Oct 2025 15:13:22 GMT + +_Version update only_ + +## 1.1.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.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.29.11 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.29.10 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.29.9 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.29.8 +Sun, 31 Aug 2025 02:24:40 GMT + +_Version update only_ + +## 0.29.7 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.29.6 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.29.5 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.29.4 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.29.3 +Mon, 28 Jul 2025 15:11:56 GMT + +_Version update only_ + +## 0.29.2 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.29.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.29.0 +Wed, 09 Jul 2025 04:01:17 GMT + +### Minor changes + +- Clean the temp/sass-ts folder. + +## 0.28.17 +Thu, 26 Jun 2025 18:57:04 GMT + +_Version update only_ + +## 0.28.16 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.28.15 +Fri, 06 Jun 2025 00:11:09 GMT + +_Version update only_ + +## 0.28.14 +Thu, 15 May 2025 00:11:49 GMT + +_Version update only_ + +## 0.28.13 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.28.12 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.28.11 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.28.10 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.28.9 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.28.8 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 0.28.7 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.28.6 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.28.5 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.28.4 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.28.3 +Tue, 25 Mar 2025 00:12:04 GMT + +_Version update only_ + +## 0.28.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.28.1 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.28.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump TypeScript to ~5.8.2. + +## 0.27.2 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.27.1 +Thu, 06 Mar 2025 01:10:42 GMT + +_Version update only_ + +## 0.27.0 +Tue, 04 Mar 2025 16:10:41 GMT + +### Minor changes + +- Bump Webpack to ~5.98.0. + +## 0.26.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `typescript` dependency to `~5.7.3`. + +## 0.25.26 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.25.25 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.25.24 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.25.23 +Tue, 25 Feb 2025 01:11:55 GMT + +_Version update only_ + +## 0.25.22 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.25.21 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.25.20 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.25.19 +Fri, 07 Feb 2025 01:10:49 GMT + +_Version update only_ + +## 0.25.18 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.25.17 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.25.16 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.25.15 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.25.14 +Tue, 07 Jan 2025 16:11:06 GMT + +_Version update only_ + +## 0.25.13 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.25.12 +Tue, 10 Dec 2024 07:32:19 GMT + +_Version update only_ + +## 0.25.11 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.25.10 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.25.9 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.25.8 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.25.7 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.25.6 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.25.5 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.25.4 +Wed, 16 Oct 2024 00:11:20 GMT + +_Version update only_ + +## 0.25.3 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.25.2 +Thu, 10 Oct 2024 00:11:51 GMT + +_Version update only_ + +## 0.25.1 +Thu, 03 Oct 2024 19:46:23 GMT + +_Version update only_ + +## 0.25.0 +Wed, 02 Oct 2024 00:11:19 GMT + +### Minor changes + +- Update to webpack 5.95.0 + +## 0.24.37 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.24.36 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.24.35 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.24.34 +Sat, 21 Sep 2024 00:10:27 GMT + +_Version update only_ + +## 0.24.33 +Thu, 19 Sep 2024 00:11:08 GMT + +_Version update only_ + +## 0.24.32 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.24.31 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.24.30 +Mon, 26 Aug 2024 02:00:11 GMT + +_Version update only_ + +## 0.24.29 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.24.28 +Wed, 14 Aug 2024 22:37:32 GMT + +_Version update only_ + +## 0.24.27 +Tue, 13 Aug 2024 18:17:05 GMT + +_Version update only_ + +## 0.24.26 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.24.25 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.24.24 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.24.23 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.24.22 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.24.21 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.24.20 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.24.19 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.24.18 +Tue, 11 Jun 2024 00:21:28 GMT + +_Version update only_ + +## 0.24.17 +Fri, 07 Jun 2024 15:10:25 GMT + +_Version update only_ + +## 0.24.16 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.24.15 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.24.14 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.24.13 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.24.12 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.24.11 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.24.10 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.24.9 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.24.8 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.24.7 +Fri, 17 May 2024 00:10:40 GMT + +_Version update only_ + +## 0.24.6 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.24.5 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.24.4 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.24.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.24.2 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.24.1 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.24.0 +Wed, 10 Apr 2024 21:59:39 GMT + +### Minor changes + +- Bump ESLint to ~8.57.0. + +## 0.23.6 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.23.5 +Fri, 29 Mar 2024 05:46:41 GMT + +_Version update only_ + +## 0.23.4 +Thu, 28 Mar 2024 22:42:23 GMT + +_Version update only_ + +## 0.23.3 +Thu, 28 Mar 2024 18:11:12 GMT + +_Version update only_ + +## 0.23.2 +Wed, 27 Mar 2024 19:47:21 GMT + +_Version update only_ + +## 0.23.1 +Wed, 20 Mar 2024 02:09:14 GMT + +_Version update only_ + +## 0.23.0 +Tue, 19 Mar 2024 15:10:18 GMT + +### Minor changes + +- Upgrade to TypeScript 5.4 + +## 0.22.9 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.22.8 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.22.7 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.22.6 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.22.5 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.22.4 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.22.3 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.22.2 +Mon, 26 Feb 2024 16:10:56 GMT + +_Version update only_ + +## 0.22.1 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.22.0 +Thu, 22 Feb 2024 06:31:58 GMT + +### Minor changes + +- Update the "asset/resource" rule to include file extensions for font assets + +## 0.21.5 +Thu, 22 Feb 2024 05:54:17 GMT + +_Version update only_ + +## 0.21.4 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.21.3 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.21.2 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.21.1 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.21.0 +Tue, 20 Feb 2024 16:10:52 GMT + +### Minor changes + +- Include the `set-environment-variables-plugin` plugin from the `@rushstack/heft` package to set the `BROWSERSLIST_IGNORE_OLD_DATA` environment variable to `1` to suppress the warning printed when the `browserslist` package decides it's out of date. +- Rename the `sass-typings` task in the "library" profile to `sass`, which more accurately describes what the task does and matches what's in the "app" profile. + +## 0.20.10 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.20.9 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.20.8 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.20.7 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.20.6 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.20.5 +Thu, 25 Jan 2024 23:03:58 GMT + +_Version update only_ + +## 0.20.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.20.3 +Wed, 24 Jan 2024 07:38:34 GMT + +_Version update only_ + +## 0.20.2 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.20.1 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.20.0 +Tue, 16 Jan 2024 18:30:10 GMT + +### Minor changes + +- Upgrade to TypeScript 5.3 + +## 0.19.17 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.19.16 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.19.15 +Fri, 15 Dec 2023 01:10:06 GMT + +_Version update only_ + +## 0.19.14 +Fri, 08 Dec 2023 20:48:44 GMT + +_Version update only_ + +## 0.19.13 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.19.12 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.19.11 +Wed, 22 Nov 2023 01:45:18 GMT + +_Version update only_ + +## 0.19.10 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.19.9 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.19.8 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.19.7 +Thu, 26 Oct 2023 00:27:48 GMT + +_Version update only_ + +## 0.19.6 +Mon, 23 Oct 2023 15:18:38 GMT + +_Version update only_ + +## 0.19.5 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.19.4 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.19.3 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.19.2 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.19.1 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.19.0 +Tue, 26 Sep 2023 09:30:33 GMT + +### Minor changes + +- Add an optional patch which can be used to allow ESLint to extend configurations from packages that do not have the "eslint-config-" prefix. This change also includes the ESLint configurations sourced from "@rushstack/eslint-config" + +## 0.18.30 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.18.29 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.18.28 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.18.27 +Fri, 15 Sep 2023 00:36:58 GMT + +_Version update only_ + +## 0.18.26 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.18.25 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.18.24 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.18.23 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.18.22 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.18.21 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.18.20 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.18.19 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.18.18 +Mon, 17 Jul 2023 15:20:25 GMT + +_Version update only_ + +## 0.18.17 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.18.16 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.18.15 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.18.14 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.18.13 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.18.12 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.18.11 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.18.10 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.18.9 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.18.8 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.18.7 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.18.6 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.18.5 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.18.4 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.18.3 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.18.2 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.18.1 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.18.0 +Wed, 07 Jun 2023 22:45:16 GMT + +### Minor changes + +- Add "heft start" alias that maps to "heft build-watch --serve" + +## 0.17.0 +Tue, 06 Jun 2023 02:52:51 GMT + +### Minor changes + +- Update Jest environment "customExportConditions" to ["require", "node", "umd"] + +## 0.16.1 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.16.0 +Fri, 02 Jun 2023 02:01:12 GMT + +### Minor changes + +- Refactor for multi-phase Heft. See @rushstack/heft/UPGRADING.md. + +## 0.15.2 +Fri, 02 Jun 2023 00:24:45 GMT + +_Version update only_ + +## 0.15.1 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.15.0 +Mon, 22 May 2023 06:34:33 GMT + +### Minor changes + +- Upgrade TypeScript to ~5.0.4 + +## 0.14.17 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.14.16 +Thu, 11 May 2023 00:17:21 GMT + +_Version update only_ + +## 0.14.15 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.14.14 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.14.13 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.14.12 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.14.11 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.14.10 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 0.14.9 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.14.8 +Tue, 04 Apr 2023 22:36:28 GMT + +### Patches + +- Upgrade Jest to 29.5.0. + +## 0.14.7 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.14.6 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 0.14.5 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.14.4 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.14.3 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.14.2 +Tue, 31 Jan 2023 01:23:23 GMT + +_Version update only_ + +## 0.14.1 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.14.0 +Mon, 30 Jan 2023 00:55:44 GMT + +### Minor changes + +- Upgrade Jest from `~27.4.2` to `~29.3.1` + +## 0.13.2 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.13.1 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.13.0 +Sun, 22 Jan 2023 20:37:08 GMT + +### Minor changes + +- Disable "mini-css-extract-plugin" for the "library" rig profile because there isn't a straightforward way to load .css files from a library + +## 0.12.17 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.12.16 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.12.15 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.12.14 +Fri, 02 Dec 2022 01:15:41 GMT + +_Version update only_ + +## 0.12.13 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 0.12.12 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.12.11 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.12.10 +Wed, 26 Oct 2022 15:16:29 GMT + +_Version update only_ + +## 0.12.9 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.12.8 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 0.12.7 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.12.6 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.12.5 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.12.4 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.12.3 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.12.2 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.12.1 +Sat, 08 Oct 2022 02:30:08 GMT + +_Version update only_ + +## 0.12.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Minor changes + +- Upgrade to TypeScript 4.8. + +## 0.11.13 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.11.12 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.11.11 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.11.10 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.11.9 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.11.8 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.11.7 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.11.6 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.11.5 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.11.4 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.11.3 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.11.2 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.11.1 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.11.0 +Wed, 03 Aug 2022 18:40:35 GMT + +### Minor changes + +- Upgrade TypeScript to 4.7 + +## 0.10.25 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.10.24 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.10.23 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.10.22 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.10.21 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.10.20 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.10.19 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.10.18 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.10.17 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.10.16 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.10.15 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.10.14 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.10.13 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.10.12 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.10.11 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.10.10 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.10.9 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.10.8 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.10.7 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.10.6 +Wed, 18 May 2022 15:10:55 GMT + +_Version update only_ + +## 0.10.5 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.10.4 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.10.3 +Fri, 06 May 2022 18:54:42 GMT + +_Version update only_ + +## 0.10.2 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.10.1 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.10.0 +Sat, 23 Apr 2022 02:13:06 GMT + +### Minor changes + +- Update to TypeScript 4.6 + +## 0.9.11 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.9.10 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.9.9 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.9.8 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.9.7 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.9.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.9.5 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.9.4 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.9.3 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.9.2 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.9.1 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 0.9.0 +Fri, 11 Feb 2022 10:30:25 GMT + +### Minor changes + +- A major overhaul of heft-web-rig; for details refer to https://github.com/microsoft/rushstack/pull/3204 +- Set useUnknownInCatchVariables=false in tsconfig.json, to work around https://github.com/microsoft/TypeScript/issues/42596 + +## 0.8.2 +Tue, 25 Jan 2022 01:11:07 GMT + +### Patches + +- Upgrade ESLint to ~8.7.0 + +## 0.8.1 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.8.0 +Thu, 20 Jan 2022 02:43:46 GMT + +### Minor changes + +- Update the `rush-project.json` file to follow the new schema and configure the "build" command output folders for the "_phase:build" phase. + +## 0.7.2 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.7.1 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.7.0 +Tue, 14 Dec 2021 19:27:51 GMT + +### Minor changes + +- Upgrade Jest to v27 + +## 0.6.4 +Fri, 10 Dec 2021 01:09:33 GMT + +_Version update only_ + +## 0.6.3 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.6.2 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.6.1 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.6.0 +Wed, 08 Dec 2021 16:14:05 GMT + +### Minor changes + +- Update to TypeScript 4.5 + +## 0.5.0 +Mon, 06 Dec 2021 16:08:32 GMT + +### Minor changes + +- Bump ESLint to v8 + +## 0.4.34 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.4.33 +Tue, 30 Nov 2021 20:18:41 GMT + +### Patches + +- Set default Jest environment in Jest configuration to "jest-environment-jsdom" + +## 0.4.32 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.4.31 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.4.30 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.4.29 +Thu, 28 Oct 2021 23:48:23 GMT + +_Version update only_ + +## 0.4.28 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.4.27 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.4.26 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 0.4.25 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.4.24 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.4.23 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.4.22 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.4.21 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.4.20 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.4.19 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 0.4.18 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.4.17 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.4.16 +Thu, 23 Sep 2021 00:10:40 GMT + +_Version update only_ + +## 0.4.15 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.4.14 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.4.13 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.4.12 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.4.11 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.4.10 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.4.9 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.4.8 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.4.7 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.4.6 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.4.5 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.4.4 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.4.3 +Fri, 13 Aug 2021 00:09:14 GMT + +### Patches + +- Remove default use of incremental: true in tsconfig-base.json + +## 0.4.2 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.4.1 +Thu, 12 Aug 2021 01:28:38 GMT + +### Patches + +- Restore automatic generation of tsBuildInfo.json file path to work around odd path resolution behavior. + +## 0.4.0 +Wed, 11 Aug 2021 23:14:17 GMT + +### Minor changes + +- Enable "incremental: true" by default in tsconfig-base.json + +## 0.3.16 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.3.15 +Sat, 31 Jul 2021 00:52:11 GMT + +### Patches + +- Use newly extracted Sass plugin (@rushstack/heft-sass-plugin) + +## 0.3.14 +Tue, 27 Jul 2021 22:31:02 GMT + +_Version update only_ + +## 0.3.13 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.3.12 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.3.11 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.3.10 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.3.9 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.3.8 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.3.7 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 0.3.6 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.3.5 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.3.4 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.3.3 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 0.3.2 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 0.3.1 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 0.3.0 +Tue, 15 Jun 2021 20:38:35 GMT + +### Minor changes + +- Disable the allowUnreachableCode TypeScript compiler option. + +## 0.2.38 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 0.2.37 +Fri, 11 Jun 2021 00:34:02 GMT + +### Patches + +- Add @rushstack/heft-jest-plugin to run during tests + +## 0.2.36 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 0.2.35 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.2.34 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 0.2.33 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.2.32 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 0.2.31 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 0.2.30 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 0.2.29 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 0.2.28 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.2.27 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 0.2.26 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 0.2.25 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 0.2.24 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.2.23 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 0.2.22 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 0.2.21 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 0.2.20 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 0.2.19 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.2.18 +Thu, 15 Apr 2021 02:59:25 GMT + +### Patches + +- Explicitly set the noEmitOnError TypeScript compiler option to false in the base tsconfig. + +## 0.2.17 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.2.16 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 0.2.15 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 0.2.14 +Thu, 08 Apr 2021 00:10:18 GMT + +### Patches + +- For compatibility with Heft 0.25.5 and earlier versions, add a dependency on the "@rushstack/heft-webpack4-plugin" package and update heft.json to load it. + +## 0.2.13 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.2.12 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 0.2.11 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 0.2.10 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 0.2.9 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 0.2.8 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 0.2.7 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 0.2.6 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.2.5 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.2.4 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.2.3 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.2.2 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 0.2.1 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.2.0 +Fri, 08 Jan 2021 07:28:50 GMT + +### Minor changes + +- Add a Rush build cache configuration. + +## 0.1.34 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.1.33 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.1.32 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.1.31 +Sat, 05 Dec 2020 01:11:23 GMT + +### Patches + +- Ensure rootDir is consistently specified. + +## 0.1.30 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.1.29 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.1.28 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.1.27 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.1.26 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.1.25 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.1.24 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.1.23 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.1.22 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.1.21 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 0.1.20 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.1.19 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.1.18 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.1.17 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 0.1.16 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.1.15 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.1.14 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.1.13 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 0.1.12 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 0.1.11 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.1.10 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 0.1.9 +Sat, 24 Oct 2020 00:11:18 GMT + +_Version update only_ + +## 0.1.8 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.1.7 +Wed, 21 Oct 2020 02:28:17 GMT + +### Patches + +- Update Heft. + +## 0.1.6 +Thu, 15 Oct 2020 00:59:08 GMT + +### Patches + +- Update Heft dependency + +## 0.1.5 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.1.4 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.1.3 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 0.1.2 +Thu, 01 Oct 2020 18:51:21 GMT + +### Patches + +- Add sass typings plugin configuration. + +## 0.1.1 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.1.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Minor changes + +- Initial release + diff --git a/rigs/heft-web-rig/LICENSE b/rigs/heft-web-rig/LICENSE new file mode 100644 index 00000000000..b9afe803169 --- /dev/null +++ b/rigs/heft-web-rig/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-web-rig + +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/rigs/heft-web-rig/README.md b/rigs/heft-web-rig/README.md new file mode 100644 index 00000000000..e47077809bf --- /dev/null +++ b/rigs/heft-web-rig/README.md @@ -0,0 +1,35 @@ +## @rushstack/heft-web-rig + +A rig package for web projects that build using [Heft](https://www.npmjs.com/package/@rushstack/heft) +build system. To learn more about rig packages, consult the +[@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) documentation. + +This rig provides the following profiles: + +- [app](./profiles/app/): For applications that get bundled using Webpack. +- [library](./profiles/library/): For creating library packages to be consumed by other web projects. ***Also use this profile for a library meant to be used by both Node.js and web apps.*** + + +To enable it, add a **rig.json** file to your project, as shown below: + +**config/rig.json** +```js +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-web-rig", + "rigProfile": "library" +} +``` + +The config files provided by this rig profile can be found in the [heft-web-rig/profiles/library]( +https://github.com/microsoft/rushstack/tree/main/rigs/heft-web-rig/profiles/library) source folder. + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/rigs/heft-web-rig/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/heft-web-rig` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/rigs/heft-web-rig/package.json b/rigs/heft-web-rig/package.json new file mode 100644 index 00000000000..093e43ecd44 --- /dev/null +++ b/rigs/heft-web-rig/package.json @@ -0,0 +1,51 @@ +{ + "name": "@rushstack/heft-web-rig", + "version": "1.1.12", + "description": "A rig package for web browser projects that build using Heft", + "license": "MIT", + "scripts": { + "build": "", + "_phase:build": "" + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "rigs/heft-web-rig" + }, + "peerDependencies": { + "@rushstack/heft": "^1.1.7" + }, + "dependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/eslint-config": "workspace:*", + "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-sass-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@types/heft-jest": "1.0.1", + "autoprefixer": "~10.4.2", + "css-loader": "~6.6.0", + "css-minimizer-webpack-plugin": "~3.4.1", + "eslint": "~9.37.0", + "html-webpack-plugin": "~5.5.0", + "jest-environment-jsdom": "~29.5.0", + "mini-css-extract-plugin": "~2.5.3", + "postcss-loader": "~6.2.1", + "postcss": "~8.4.6", + "sass-loader": "~12.4.0", + "sass": "~1.49.7", + "source-map-loader": "~3.0.1", + "style-loader": "~3.3.1", + "terser-webpack-plugin": "~5.3.1", + "typescript": "~5.8.2", + "url-loader": "~4.1.1", + "webpack-bundle-analyzer": "~4.5.0", + "webpack-merge": "~5.8.0", + "webpack": "~5.98.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*" + } +} diff --git a/rigs/heft-web-rig/profiles/app/config/heft.json b/rigs/heft-web-rig/profiles/app/config/heft.json new file mode 100644 index 00000000000..8e80c606118 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/config/heft.json @@ -0,0 +1,88 @@ +/** + * 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": "base-project/config/heft.json", + + "aliasesByName": { + "start": { + "actionName": "build-watch", + "defaultParameters": ["--serve"] + } + }, + + "phasesByName": { + "build": { + "cleanFiles": [ + { "includeGlobs": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp/sass-ts"] } + ], + + "tasksByName": { + "set-browserslist-ignore-old-data-env-var": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "set-environment-variables-plugin", + "options": { + "environmentVariablesToSet": { + // Suppress the "Browserslist: caniuse-lite is outdated" warning. Although the warning is + // potentially useful, the check is performed in a way that is nondeterministic and can cause + // Rush pipelines to fail. Moreover, the outdated version is often irrelevant and/or nontrivial + // to upgrade. See this thread for details: https://github.com/microsoft/rushstack/issues/2981 + "BROWSERSLIST_IGNORE_OLD_DATA": "1" + } + } + } + }, + "sass": { + "taskDependencies": ["set-browserslist-ignore-old-data-env-var"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-plugin" + } + }, + "typescript": { + "taskDependencies": ["sass"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/rigs/heft-web-rig/profiles/app/config/jest.config.json b/rigs/heft-web-rig/profiles/app/config/jest.config.json new file mode 100644 index 00000000000..441ad22d6d1 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json" +} diff --git a/rigs/heft-web-rig/profiles/app/config/rush-project.json b/rigs/heft-web-rig/profiles/app/config/rush-project.json new file mode 100644 index 00000000000..bd1ad1adfe5 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp"] + }, + { + "operationName": "build", + "outputFolderNames": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp"] + } + ] +} diff --git a/rigs/heft-web-rig/profiles/app/config/sass.json b/rigs/heft-web-rig/profiles/app/config/sass.json new file mode 100644 index 00000000000..f6fe4ffe9c5 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/config/sass.json @@ -0,0 +1,67 @@ +/** + * Configuration for @rushstack/heft-sass-plugin + * + * This optional additional file customizes Sass parsing, module resolution, and emitting of + * Typescript .d.ts files. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.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": "base-project/config/serve-command.json", + + /** + * The root directory for project source code. + * + * Default value: "src/" + */ + // "srcFolder": "src/", + + /** + * Output directory for generated Sass typings. + * + * Default value: "temp/sass-ts/" + */ + // "generatedTsFolder": "temp/sass-ts/", + + /** + * Determines whether export values are wrapped in a default property, or not. + * + * 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. + * + * Default value: undefined + */ + // "cssOutputFolders": ["lib", "lib-commonjs"], + + /** + * Files with these extensions will pass through the Sass transpiler for typings generation. + * + * Default value: [".sass", ".scss", ".css"] + */ + "fileExtensions": [".sass", ".scss"] + + /** + * A list of paths used when resolving Sass imports. The paths should be relative to the project root. + * + * Default value: ["node_modules", "src"] + */ + // "importIncludePaths": ["node_modules", "src"], + + /** + * A list of file paths relative to the "src" folder that should be excluded from typings generation. + * + * Default value: undefined + */ + // "excludeFiles": [] +} diff --git a/rigs/heft-web-rig/profiles/app/config/typescript.json b/rigs/heft-web-rig/profiles/app/config/typescript.json new file mode 100644 index 00000000000..91a9bc59c3b --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/config/typescript.json @@ -0,0 +1,100 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.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": "base-project/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. + */ + "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" + } + ], + + /** + * If true, emit CommonJS module output to the folder specified in the tsconfig "outDir" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies CommonJS) the default compilation output. + */ + // "emitCjsExtensionForCommonJS": true, + + /** + * If true, emit ESNext module output to the folder specified in the tsconfig "outDir" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + // "emitMjsExtensionForESModule": true, + + /** + * If true and "isolatedModules" is configured in tsconfig.json, use a worker thread to run transpilation concurrently with type checking and declaration emit. + */ + // "useTranspilerWorker": true + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [ + ".aac", + ".css", + ".eot", + ".gif", + ".jpeg", + ".jpg", + ".json", + ".m4a", + ".mp3", + ".mp4", + ".oga", + ".otf", + ".png", + ".scss", + ".svg", + ".ttf", + ".wav", + ".webm", + ".webp", + ".woff", + ".woff2" + ] + + /** + * 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/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/friendly-locals.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..860b58395f6 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/friendly-locals.js @@ -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. + +const friendlyLocalsMixin = require('@rushstack/eslint-config/flat/mixins/friendly-locals'); + +module.exports = [...friendlyLocalsMixin]; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..a3f2ea0992a --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js @@ -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. + +const packletsMixin = require('@rushstack/eslint-config/flat/mixins/packlets'); + +module.exports = [...packletsMixin]; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/react.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/react.js new file mode 100644 index 00000000000..5aafda8dcf0 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/react.js @@ -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. + +const reactMixin = require('@rushstack/eslint-config/flat/mixins/react'); + +module.exports = [...reactMixin]; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/tsdoc.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..012a5bece42 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/mixins/tsdoc.js @@ -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. + +const tsdocMixin = require('@rushstack/eslint-config/flat/mixins/tsdoc'); + +module.exports = [...tsdocMixin]; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..ec6804684d1 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/flat/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/flat/profile/web-app.js b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/profile/web-app.js new file mode 100644 index 00000000000..d825f616500 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/flat/profile/web-app.js @@ -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. + +const webAppProfile = require('@rushstack/eslint-config/flat/profile/web-app'); + +module.exports = [...webAppProfile]; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/friendly-locals.js b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/friendly-locals.js new file mode 100644 index 00000000000..e6cbfeacc95 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/friendly-locals.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/friendly-locals'] +}; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/packlets.js b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/packlets.js new file mode 100644 index 00000000000..82a19efce16 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/packlets.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/packlets'] +}; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/react.js b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/react.js new file mode 100644 index 00000000000..796699ee874 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/react.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/react'] +}; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/tsdoc.js b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/tsdoc.js new file mode 100644 index 00000000000..d0a4b1d6a79 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/mixins/tsdoc.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/tsdoc'] +}; diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/patch/custom-config-package-names.js b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/custom-config-package-names.js new file mode 100644 index 00000000000..1fe7079f030 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/custom-config-package-names.js @@ -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. + +require('@rushstack/eslint-config/patch/custom-config-package-names'); diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/patch/eslint-bulk-suppressions.js b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..084519e6ebb --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/patch/modern-module-resolution.js b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/modern-module-resolution.js new file mode 100644 index 00000000000..14e8d976c23 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/patch/modern-module-resolution.js @@ -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. + +require('@rushstack/eslint-config/patch/modern-module-resolution'); diff --git a/rigs/heft-web-rig/profiles/app/includes/eslint/profile/web-app.js b/rigs/heft-web-rig/profiles/app/includes/eslint/profile/web-app.js new file mode 100644 index 00000000000..eaa661335e4 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/includes/eslint/profile/web-app.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/profile/web-app'] +}; diff --git a/rigs/heft-web-rig/profiles/app/tsconfig-base.json b/rigs/heft-web-rig/profiles/app/tsconfig-base.json new file mode 100644 index 00000000000..0594f2e7b70 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/tsconfig-base.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "../../../../../lib", + "rootDir": "../../../../../src", + "rootDirs": ["../../../../../src", "../../../../../temp/sass-ts"], + + "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"], + "typeRoots": ["../../../../../node_modules/@types", "../../node_modules/@types"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], + + "incremental": true + }, + "include": ["../../../../../src/**/*.ts", "../../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-web-rig/profiles/app/webpack-base.config.js b/rigs/heft-web-rig/profiles/app/webpack-base.config.js new file mode 100644 index 00000000000..2b8fc3b1a55 --- /dev/null +++ b/rigs/heft-web-rig/profiles/app/webpack-base.config.js @@ -0,0 +1,39 @@ +'use strict'; + +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const createWebpackConfigCommon = require('../../shared/webpack-base.config'); + +module.exports = function createWebpackConfig({ env, argv, projectRoot, configOverride }) { + // Documentation: https://webpack.js.org/configuration/ + const applicationOverrides = { + target: ['web', 'es5'], + entry: { + app: path.resolve(projectRoot, 'lib', 'start.js') + }, + optimization: { + splitChunks: { + chunks: 'all' + } + }, + plugins: [ + // NOTE: If your project's webpack.config.js provides its own "HtmlWebpackPlugin" configuration, + // it will replace the default definition here. This replacement is implemented + // using mergeWithCustomize() in shared/webpack-base.config.js + + // See here for documentation: https://github.com/jantimon/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: 'index.html', + template: path.resolve(projectRoot, 'assets', 'index.html') + }) + ] + }; + + return createWebpackConfigCommon({ + env: env, + argv: argv, + projectRoot: projectRoot, + extractCssInProduction: true, + configOverride: createWebpackConfigCommon.merge(applicationOverrides, configOverride) + }); +}; diff --git a/rigs/heft-web-rig/profiles/library/config/api-extractor-task.json b/rigs/heft-web-rig/profiles/library/config/api-extractor-task.json new file mode 100644 index 00000000000..a051e971819 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/api-extractor-task.json @@ -0,0 +1,29 @@ +/** + * Configures the API Extractor task for the Heft build system. + * + * This optional additional file customizes how the Heft task is invoked. The main analysis is + * controlled by API Extractor's own "api-extractor.json" config file. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.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": "base-project/config/api-extractor-task.json", + + /** + * If set to true, use the project's TypeScript compiler version for API Extractor's + * analysis. API Extractor's included TypeScript compiler can generally correctly + * analyze typings generated by older compilers, and referencing the project's compiler + * can cause issues. If issues are encountered with API Extractor's included compiler, + * set this option to true. + * + * This corresponds to API Extractor's "--typescript-compiler-folder" CLI option and + * "IExtractorInvokeOptions.typescriptCompilerFolder" API option. This option defaults to false. + */ + // "useProjectTypescriptVersion": true +} diff --git a/rigs/heft-web-rig/profiles/library/config/heft.json b/rigs/heft-web-rig/profiles/library/config/heft.json new file mode 100644 index 00000000000..8e80c606118 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/heft.json @@ -0,0 +1,88 @@ +/** + * 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": "base-project/config/heft.json", + + "aliasesByName": { + "start": { + "actionName": "build-watch", + "defaultParameters": ["--serve"] + } + }, + + "phasesByName": { + "build": { + "cleanFiles": [ + { "includeGlobs": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp/sass-ts"] } + ], + + "tasksByName": { + "set-browserslist-ignore-old-data-env-var": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "set-environment-variables-plugin", + "options": { + "environmentVariablesToSet": { + // Suppress the "Browserslist: caniuse-lite is outdated" warning. Although the warning is + // potentially useful, the check is performed in a way that is nondeterministic and can cause + // Rush pipelines to fail. Moreover, the outdated version is often irrelevant and/or nontrivial + // to upgrade. See this thread for details: https://github.com/microsoft/rushstack/issues/2981 + "BROWSERSLIST_IGNORE_OLD_DATA": "1" + } + } + } + }, + "sass": { + "taskDependencies": ["set-browserslist-ignore-old-data-env-var"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-plugin" + } + }, + "typescript": { + "taskDependencies": ["sass"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "api-extractor": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-api-extractor-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/rigs/heft-web-rig/profiles/library/config/jest.config.json b/rigs/heft-web-rig/profiles/library/config/jest.config.json new file mode 100644 index 00000000000..441ad22d6d1 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json" +} diff --git a/rigs/heft-web-rig/profiles/library/config/rush-project.json b/rigs/heft-web-rig/profiles/library/config/rush-project.json new file mode 100644 index 00000000000..bd1ad1adfe5 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/rush-project.json @@ -0,0 +1,12 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp"] + }, + { + "operationName": "build", + "outputFolderNames": ["dist", "lib", "lib-amd", "lib-commonjs", "lib-es6", "temp"] + } + ] +} diff --git a/rigs/heft-web-rig/profiles/library/config/sass.json b/rigs/heft-web-rig/profiles/library/config/sass.json new file mode 100644 index 00000000000..f6fe4ffe9c5 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/sass.json @@ -0,0 +1,67 @@ +/** + * Configuration for @rushstack/heft-sass-plugin + * + * This optional additional file customizes Sass parsing, module resolution, and emitting of + * Typescript .d.ts files. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.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": "base-project/config/serve-command.json", + + /** + * The root directory for project source code. + * + * Default value: "src/" + */ + // "srcFolder": "src/", + + /** + * Output directory for generated Sass typings. + * + * Default value: "temp/sass-ts/" + */ + // "generatedTsFolder": "temp/sass-ts/", + + /** + * Determines whether export values are wrapped in a default property, or not. + * + * 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. + * + * Default value: undefined + */ + // "cssOutputFolders": ["lib", "lib-commonjs"], + + /** + * Files with these extensions will pass through the Sass transpiler for typings generation. + * + * Default value: [".sass", ".scss", ".css"] + */ + "fileExtensions": [".sass", ".scss"] + + /** + * A list of paths used when resolving Sass imports. The paths should be relative to the project root. + * + * Default value: ["node_modules", "src"] + */ + // "importIncludePaths": ["node_modules", "src"], + + /** + * A list of file paths relative to the "src" folder that should be excluded from typings generation. + * + * Default value: undefined + */ + // "excludeFiles": [] +} diff --git a/rigs/heft-web-rig/profiles/library/config/typescript.json b/rigs/heft-web-rig/profiles/library/config/typescript.json new file mode 100644 index 00000000000..91a9bc59c3b --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/config/typescript.json @@ -0,0 +1,100 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.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": "base-project/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. + */ + "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" + } + ], + + /** + * If true, emit CommonJS module output to the folder specified in the tsconfig "outDir" compiler option with the .cjs extension alongside (or instead of, if TSConfig specifies CommonJS) the default compilation output. + */ + // "emitCjsExtensionForCommonJS": true, + + /** + * If true, emit ESNext module output to the folder specified in the tsconfig "outDir" compiler option with the .mjs extension alongside (or instead of, if TSConfig specifies ESNext) the default compilation output. + */ + // "emitMjsExtensionForESModule": true, + + /** + * If true and "isolatedModules" is configured in tsconfig.json, use a worker thread to run transpilation concurrently with type checking and declaration emit. + */ + // "useTranspilerWorker": true + + /** + * Configures additional file types that should be copied into the TypeScript compiler's emit folders, for example + * so that these files can be resolved by import statements. + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [ + ".aac", + ".css", + ".eot", + ".gif", + ".jpeg", + ".jpg", + ".json", + ".m4a", + ".mp3", + ".mp4", + ".oga", + ".otf", + ".png", + ".scss", + ".svg", + ".ttf", + ".wav", + ".webm", + ".webp", + ".woff", + ".woff2" + ] + + /** + * 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/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..860b58395f6 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals.js @@ -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. + +const friendlyLocalsMixin = require('@rushstack/eslint-config/flat/mixins/friendly-locals'); + +module.exports = [...friendlyLocalsMixin]; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/packlets.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..a3f2ea0992a --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/packlets.js @@ -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. + +const packletsMixin = require('@rushstack/eslint-config/flat/mixins/packlets'); + +module.exports = [...packletsMixin]; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/react.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/react.js new file mode 100644 index 00000000000..5aafda8dcf0 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/react.js @@ -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. + +const reactMixin = require('@rushstack/eslint-config/flat/mixins/react'); + +module.exports = [...reactMixin]; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/tsdoc.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..012a5bece42 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/mixins/tsdoc.js @@ -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. + +const tsdocMixin = require('@rushstack/eslint-config/flat/mixins/tsdoc'); + +module.exports = [...tsdocMixin]; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/flat/patch/eslint-bulk-suppressions.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..ec6804684d1 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/flat/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/flat/profile/web-app.js b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/profile/web-app.js new file mode 100644 index 00000000000..d825f616500 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/flat/profile/web-app.js @@ -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. + +const webAppProfile = require('@rushstack/eslint-config/flat/profile/web-app'); + +module.exports = [...webAppProfile]; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/friendly-locals.js b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/friendly-locals.js new file mode 100644 index 00000000000..e6cbfeacc95 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/friendly-locals.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/friendly-locals'] +}; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/packlets.js b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/packlets.js new file mode 100644 index 00000000000..82a19efce16 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/packlets.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/packlets'] +}; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/react.js b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/react.js new file mode 100644 index 00000000000..796699ee874 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/react.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/react'] +}; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/tsdoc.js b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/tsdoc.js new file mode 100644 index 00000000000..d0a4b1d6a79 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/mixins/tsdoc.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/mixins/tsdoc'] +}; diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/patch/custom-config-package-names.js b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/custom-config-package-names.js new file mode 100644 index 00000000000..1fe7079f030 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/custom-config-package-names.js @@ -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. + +require('@rushstack/eslint-config/patch/custom-config-package-names'); diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/patch/eslint-bulk-suppressions.js b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/eslint-bulk-suppressions.js new file mode 100644 index 00000000000..084519e6ebb --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/eslint-bulk-suppressions.js @@ -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. + +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/patch/modern-module-resolution.js b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/modern-module-resolution.js new file mode 100644 index 00000000000..14e8d976c23 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/patch/modern-module-resolution.js @@ -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. + +require('@rushstack/eslint-config/patch/modern-module-resolution'); diff --git a/rigs/heft-web-rig/profiles/library/includes/eslint/profile/web-app.js b/rigs/heft-web-rig/profiles/library/includes/eslint/profile/web-app.js new file mode 100644 index 00000000000..eaa661335e4 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/includes/eslint/profile/web-app.js @@ -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. + +module.exports = { + extends: ['@rushstack/eslint-config/profile/web-app'] +}; diff --git a/rigs/heft-web-rig/profiles/library/tsconfig-base.json b/rigs/heft-web-rig/profiles/library/tsconfig-base.json new file mode 100644 index 00000000000..0594f2e7b70 --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/tsconfig-base.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "../../../../../lib", + "rootDir": "../../../../../src", + "rootDirs": ["../../../../../src", "../../../../../temp/sass-ts"], + + "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"], + "typeRoots": ["../../../../../node_modules/@types", "../../node_modules/@types"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], + + "incremental": true + }, + "include": ["../../../../../src/**/*.ts", "../../../../../src/**/*.tsx"] +} diff --git a/rigs/heft-web-rig/profiles/library/webpack-base.config.js b/rigs/heft-web-rig/profiles/library/webpack-base.config.js new file mode 100644 index 00000000000..d8ba33b1f2f --- /dev/null +++ b/rigs/heft-web-rig/profiles/library/webpack-base.config.js @@ -0,0 +1,50 @@ +'use strict'; + +const path = require('path'); +const createWebpackConfigCommon = require('../../shared/webpack-base.config'); + +module.exports = function createWebpackConfig({ env, argv, projectRoot, configOverride }) { + // Example: "@my-company/my-library" + const packageName = require(path.join(projectRoot, 'package.json')).name; + // Example: "my-library" + const packageNameWithoutScope = packageName.split('/').pop(); + + // Documentation: https://webpack.js.org/configuration/ + const libraryOverrides = { + target: ['web', 'es5'], + entry: { + // Rush Stack convention is that the entry point for libraries is "src/index.ts" + // whereas the entry point for apps is "src/start.ts" + [packageNameWithoutScope]: path.resolve(projectRoot, 'lib', 'index.js') + }, + output: { + // For libraries, the filename is unhashed so that the package.json "main" field can refer to it + filename: `[name].js`, + library: { + // Use the full package name as the module-id name for AMD + amd: packageName + }, + libraryTarget: 'umd', + + // https://webpack.js.org/configuration/output/#outputlibraryumdnameddefine + // Give the amd module a globally unique id so that non AMD aware bundlers can concatenate the module + umdNamedDefine: true, + + // From: https://webpack.js.org/configuration/output/#outputglobalobject + // To make UMD build available on both browsers and Node.js, set output.globalObject option to 'this' + globalObject: 'this' + }, + devtool: 'source-map' + }; + + return createWebpackConfigCommon({ + env: env, + argv: argv, + projectRoot: projectRoot, + // "If you're building a design system or component library and shipping to NPM you shouldn't + // extract just yet, let your consumers do it in their app." + // https://compiledcssinjs.com/docs/css-extraction-webpack + extractCssInProduction: false, + configOverride: createWebpackConfigCommon.merge(libraryOverrides, configOverride) + }); +}; diff --git a/rigs/heft-web-rig/shared/webpack-base.config.js b/rigs/heft-web-rig/shared/webpack-base.config.js new file mode 100644 index 00000000000..8ca3bf5d978 --- /dev/null +++ b/rigs/heft-web-rig/shared/webpack-base.config.js @@ -0,0 +1,273 @@ +'use strict'; + +const webpack = require('webpack'); +const path = require('path'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const { DefinePlugin } = webpack; +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); +const { merge, mergeWithCustomize, mergeWithRules, unique } = require('webpack-merge'); +const sass = require('sass'); +const autoprefixer = require('autoprefixer'); + +/** + * 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({ env, argv, projectRoot, configOverride, extractCssInProduction }) { + const { production } = env; + + const defaultArgs = { + // Documentation: https://webpack.js.org/configuration/mode/ + mode: production ? 'production' : 'development', + resolve: { + extensions: ['.mjs', '.js', '.json'] + }, + output: production + ? { + chunkFilename: '[name].[contenthash].js', + filename: '[name].[contenthash].js', + sourceMapFilename: '[name].[contenthash].js.map' + } + : {}, + module: { + rules: [ + { + // The source-map-loader extracts existing source maps from all JavaScript entries. This includes both + // inline source maps as well as those linked via URL. All source map data is passed to Webpack for + // processing as per a chosen source map style specified by the devtool option in webpack.config.js. + // https://www.npmjs.com/package/source-map-loader + test: /\.js$/, + + // Include source maps from other library projects in the monorepo workspace, + // but exclude source maps for external NPM packages. Webpack tests the fs.realPathSync() path, + // so external packages will be under "common/temp/node_modules/.pnpm/". + exclude: /[\\/]\.pnpm[\\/]/, + + enforce: 'pre', + use: [ + { + loader: require.resolve('source-map-loader') + } + ] + }, + + { + // CSS/SASS INPUT FORMATS + // + // We recommend the newer .scss file format because its syntax is a proper superset of familiar CSS. + // The older .sass syntax is also accepted for backwards compatibility. + // + // The Sass documentation is here: https://sass-lang.com/documentation/syntax + // + // File extensions Sass Autoprefixer CSS modules .d.ts + // ----------------- ---- ------------ ------------- ----- + // *.scss: YES YES YES YES (recommended) + // *.sass: YES YES YES YES (deprecated) + // *.global.scss: YES YES NO NO + // *.global.sass: YES YES NO NO (deprecated) + // *.css: NO YES NO NO + // + // If you want .css syntax but with CSS modules, use the .scss file extension; its syntax + // is a superset of CSS. (There's a small performance penalty for applying Sass to a CSS file, + // but the extra syntax validation justifies that cost.) + // + // COMPILATION STRATEGY + // + // - Sass compilation: handled by Webpack + // - .d.ts generation: handled by @rushstack/heft-sass-plugin, configured using config/sass.json + // - Autoprefixer: handled by Webpack + // - CSS modules: handled by Webpack + test: /\.(scss|sass|css)$/, + exclude: /node_modules/, + use: [ + // "For production builds it's recommended to extract the CSS from your bundle being able to + // use parallel loading of CSS/JS resources later on. This can be achieved by using the + // mini-css-extract-plugin, because it creates separate css files." + // + // "For development mode (including webpack-dev-server) you can use style-loader, because it injects + // CSS into the DOM using multiple and works faster." + // + // "WARNING: Do not use style-loader and mini-css-extract-plugin together." + production && extractCssInProduction + ? { + loader: MiniCssExtractPlugin.loader + } + : { + // Generates JavaScript code that injects CSS styles into the DOM at runtime. + // The default configuration creates + + Run Rush Command + + + + +
+ + + + diff --git a/vscode-extensions/rush-vscode-command-webview/src/App.tsx b/vscode-extensions/rush-vscode-command-webview/src/App.tsx new file mode 100644 index 00000000000..85836a298a0 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/App.tsx @@ -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 { /*IStackStyles, IStackTokens, */ initializeIcons } from '@fluentui/react'; +import * as React from 'react'; +import { useEffect } from 'react'; +import { + type SelectTabData, + type SelectTabEvent, + Tab, + TabList, + type TabValue +} from '@fluentui/react-components'; + +import { fromExtensionListener } from './Message/fromExtension'; +// import { ParameterView } from './ParameterView'; +// import { Toolbar } from './Toolbar'; +// import { useAppSelector } from './store/hooks'; +import { ProjectView } from './ProjectView'; +import { VersionsView } from './VersionsView'; + +initializeIcons(); + +// // Styles definition +// const stackStyles: IStackStyles = { +// root: { +// height: '100vh', +// padding: 0 +// } +// }; + +// const verticalGapStackTokens: IStackTokens = { +// childrenGap: 10, +// padding: 10 +// }; + +enum Views { + PROJECT_VIEW, + VERSIONS_VIEW +} + +export const App = (): JSX.Element => { + const [selectedValue, setSelectedValue] = React.useState(Views.PROJECT_VIEW); + + const onTabSelect = (event: SelectTabEvent, data: SelectTabData): void => { + setSelectedValue(data.value); + }; + + useEffect(() => { + // eslint-disable-next-line no-console + console.log('initializing app in effect'); + window.addEventListener('message', fromExtensionListener); + return () => { + window.removeEventListener('message', fromExtensionListener); + }; + }, []); + + // eslint-disable-next-line no-console + console.log('initializing app'); + + return ( + // + // + // + // + // + // + // + // +
+ + Project Details + Versions + + {selectedValue === Views.PROJECT_VIEW && } + {selectedValue === Views.VERSIONS_VIEW && } +
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledComboBox.tsx b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledComboBox.tsx new file mode 100644 index 00000000000..bf4e880319a --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledComboBox.tsx @@ -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 { ComboBox, type IComboBoxOption, type IComboBoxProps } from '@fluentui/react'; +import * as React from 'react'; +import { Controller, useFormState } from 'react-hook-form'; + +import { ErrorMessage } from './ErrorMessage'; +import type { IHookFormProps } from './interface'; + +export type IControlledComboBoxProps = IComboBoxProps & IHookFormProps; + +export const ControlledComboBox = (props: IControlledComboBoxProps): JSX.Element => { + const { name, control, rules, defaultValue } = props; + const { errors } = useFormState({ + name, + control + }); + return ( +
+ {} + { + const onChangeComboBox: IComboBoxProps['onChange'] = ( + e: unknown, + option: IComboBoxOption | undefined + ) => { + if (option) { + onChange(option.key); + } + }; + return ( + <> + + + ); + }} + /> +
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextField.tsx b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextField.tsx new file mode 100644 index 00000000000..82f42afdbfc --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextField.tsx @@ -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. + +import { type ITextFieldProps, TextField } from '@fluentui/react'; +import * as React from 'react'; +import { Controller } from 'react-hook-form'; + +import type { IHookFormProps } from './interface'; + +export type IControlledTextFieldProps = ITextFieldProps & IHookFormProps; + +export const ControlledTextField = (props: IControlledTextFieldProps): JSX.Element => { + const { name, control, rules, defaultValue } = props; + return ( + { + return ( + + ); + }} + /> + ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextFieldArray.tsx b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextFieldArray.tsx new file mode 100644 index 00000000000..ff265c24a57 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledTextFieldArray.tsx @@ -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 { type IStackTokens, type ITextFieldProps, Stack, TextField } from '@fluentui/react'; +import * as React from 'react'; +import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; + +import { IconButton } from '../components/IconButton'; +import type { IHookFormProps } from './interface'; + +export type IControlledTextFieldArrayProps = ITextFieldProps & IHookFormProps; + +const textFieldStyles: ITextFieldProps['styles'] = { + root: { + width: '100%' + } +}; + +const stackTokens: IStackTokens = { + childrenGap: 6 +}; + +export const ControlledTextFieldArray = (props: IControlledTextFieldArrayProps): JSX.Element => { + const { name, control, rules, defaultValue } = props; + const { fields, remove, append } = useFieldArray({ + name, + control + }); + const { getValues } = useFormContext(); + const arrayValues: { value: string | number }[] = getValues(name); + return ( +
+ + {fields.map((field, index) => { + return ( +
+ + { + return ( + { + // eslint-disable-next-line no-console + console.log('-------newValue', `${name}.${index}.value`, v); + onChange(v); + }} + value={value} + onBlur={onBlur} + name={fieldName} + errorMessage={error && error.message} + /> + ); + }} + /> + {arrayValues.length > 1 ? ( + remove(index)} + /> + ) : null} + +
+ ); + })} + { + append({ + value: '' + }); + }} + /> +
+
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledToggle.tsx b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledToggle.tsx new file mode 100644 index 00000000000..b7acd4281cc --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ControlledToggle.tsx @@ -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 IToggleProps, Toggle } from '@fluentui/react'; +import * as React from 'react'; +import { Controller } from 'react-hook-form'; + +import { ErrorMessage } from './ErrorMessage'; +import type { IHookFormProps } from './interface'; + +export type IControlledToggleProps = IToggleProps & IHookFormProps; + +export const ControlledToggle = (props: IControlledToggleProps): JSX.Element => { + const { name, control, rules, defaultValue } = props; + return ( + { + // eslint-disable-next-line no-console + console.log('ControlledToggle', fieldName, value); + return ( + <> + onChange(checked)} + checked={value} + onBlur={onBlur} + id={fieldName} + /> + {error && error.message && } + + ); + }} + /> + ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ErrorMessage.tsx b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ErrorMessage.tsx new file mode 100644 index 00000000000..87368c68948 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/ErrorMessage.tsx @@ -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 * as React from 'react'; + +export interface IErrorMessageProps { + message?: string; +} + +export const ErrorMessage = ({ message }: IErrorMessageProps): JSX.Element => { + // eslint-disable-next-line no-console + console.log('ErrorMessage...', message); + return message ? ( +
+

{String(message)}

+
+ ) : ( +
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/interface.ts b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/interface.ts new file mode 100644 index 00000000000..997f85398c7 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ControlledFormComponents/interface.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. + +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { Control, RegisterOptions, UseFormSetValue, FieldValues } from 'react-hook-form'; + +export interface IHookFormProps { + control: Control; + name: string; + rules?: RegisterOptions; + defaultValue?: V; + setValue?: UseFormSetValue; +} diff --git a/vscode-extensions/rush-vscode-command-webview/src/Message/fromExtension.ts b/vscode-extensions/rush-vscode-command-webview/src/Message/fromExtension.ts new file mode 100644 index 00000000000..a88b8c5eeb3 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/Message/fromExtension.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 { store } from '../store'; +import { type IProjectState, initializeProjectInfo, onChangeProject } from '../store/slices/project'; + +export type IFromExtensionMessage = IFromExtensionMessageInitialize; + +interface IFromExtensionMessageInitialize { + command: string; + state: IProjectState; +} + +export const fromExtensionListener: (event: MessageEvent) => void = ( + event: MessageEvent +) => { + const message: IFromExtensionMessage = event.data; + // eslint-disable-next-line no-console + console.log('message: ', message); + switch (message.command) { + case 'initialize': { + store.dispatch( + initializeProjectInfo({ + ...message.state + }) + ); + break; + } + case 'updateProject': { + store.dispatch( + onChangeProject({ + ...message.state + }) + ); + break; + } + default: { + const _command: string = message.command; + throw new Error(`Unknown command: ${_command}`); + } + } +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/Message/toExtension.ts b/vscode-extensions/rush-vscode-command-webview/src/Message/toExtension.ts new file mode 100644 index 00000000000..0081ddea340 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/Message/toExtension.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 type { Webview } from 'vscode'; +export type IToExtensionMessage = IToExtensionMessageCommandInfo; + +interface IToExtensionMessageCommandInfo { + command: 'commandInfo'; + commandName: string; + args: string[]; +} + +const vscode: Webview = window.acquireVsCodeApi(); + +export const sendMessageToExtension: (message: IToExtensionMessage) => void = (message) => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.postMessage(message); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/Watcher.tsx b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/Watcher.tsx new file mode 100644 index 00000000000..b7b2c6e8255 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/Watcher.tsx @@ -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 * as React from 'react'; +import { useEffect } from 'react'; +import type { FieldValues, UseFormWatch } from 'react-hook-form'; +import type { AnyAction, Dispatch } from '@reduxjs/toolkit'; +import type { Subscription } from 'react-hook-form/dist/utils/createSubject'; + +import { useAppDispatch } from '../../store/hooks'; +import { onChangeFormValues } from '../../store/slices/parameter'; + +export interface IParameterFormWatcherProps { + watch: UseFormWatch; +} + +export const ParameterFormWatcher = ({ watch }: IParameterFormWatcherProps): JSX.Element => { + const dispatch: Dispatch = useAppDispatch(); + + useEffect((): (() => void) => { + const subscription: Subscription = watch((values) => { + // eslint-disable-next-line no-console + console.log('watch', values); + dispatch(onChangeFormValues(values)); + }); + return () => subscription.unsubscribe; + }, [watch]); + + return
; +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/index.tsx b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/index.tsx new file mode 100644 index 00000000000..e99ebee4fb5 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterForm/index.tsx @@ -0,0 +1,256 @@ +// 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 CSSProperties, type ReactNode, useCallback, useEffect, useMemo } from 'react'; +import { + type FieldValues, + FormProvider, + type UseControllerProps, + useForm, + type UseFormReturn +} from 'react-hook-form'; +import { DefaultButton, Label } from '@fluentui/react'; +import type { AnyAction, Dispatch } from '@reduxjs/toolkit'; + +import { CommandLineParameterKind } from '@rushstack/ts-command-line/lib/parameters/BaseClasses'; +import type { CommandLineChoiceListParameter } from '@rushstack/ts-command-line/lib/parameters/CommandLineChoiceListParameter'; +import type { CommandLineChoiceParameter } from '@rushstack/ts-command-line/lib/parameters/CommandLineChoiceParameter'; +import type { CommandLineIntegerParameter } from '@rushstack/ts-command-line/lib/parameters/CommandLineIntegerParameter'; + +import { ControlledTextField } from '../../ControlledFormComponents/ControlledTextField'; +import { ControlledComboBox } from '../../ControlledFormComponents/ControlledComboBox'; +import { ControlledTextFieldArray } from '../../ControlledFormComponents/ControlledTextFieldArray'; +import { + type ICommandLineParameter, + onChangeFormDefaultValues, + onChangeSearchText, + useArgsTextList, + useFilteredParameters, + useParameters +} from '../../store/slices/parameter'; +import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { ParameterFormWatcher } from './Watcher'; +import { ControlledToggle } from '../../ControlledFormComponents/ControlledToggle'; +import { FIELD_ANCHOR_CLASSNAME } from '../../hooks/parametersFormScroll'; +import { setFormValidateAsync, useUserSelectedParameterName } from '../../store/slices/ui'; +import { RunButton } from '../../Toolbar/RunButton'; + +const formStyle: CSSProperties = { + // width: '430px' +}; + +export const ParameterForm = (): JSX.Element => { + const commandName: string = useAppSelector((state) => state.parameter.commandName); + const parameters: ICommandLineParameter[] = useParameters(); + const filteredParameters: ICommandLineParameter[] = useFilteredParameters(); + const argsTextList: string[] = useArgsTextList(); + const dispatch: Dispatch = useAppDispatch(); + const userSelectdParameterName: string = useUserSelectedParameterName(); + + const isListTypeParameter: (parameter: ICommandLineParameter) => boolean = useCallback( + (parameter: ICommandLineParameter) => { + return ( + parameter.kind === CommandLineParameterKind.ChoiceList || + parameter.kind === CommandLineParameterKind.IntegerList || + parameter.kind === CommandLineParameterKind.StringList + ); + }, + [] + ); + + const defaultValues: FieldValues = useMemo(() => { + return parameters.reduce((acc: FieldValues, parameter: ICommandLineParameter) => { + const parameterHasDefaultValue: ICommandLineParameter & { defaultValue?: string } = + parameter as ICommandLineParameter & { defaultValue?: string }; + const fieldName: string = parameterHasDefaultValue.longName; + if ('defaultValue' in parameterHasDefaultValue) { + acc[fieldName] = parameterHasDefaultValue.defaultValue; + } else if (isListTypeParameter(parameter)) { + acc[fieldName] = [{ value: '' }]; + } else { + switch (parameter.kind) { + case CommandLineParameterKind.Flag: { + acc[fieldName] = false; + break; + } + default: { + acc[fieldName] = ''; + } + } + } + return acc; + }, {}); + }, [commandName, parameters, isListTypeParameter]); + + const form: UseFormReturn = useForm({ + defaultValues, + shouldFocusError: true, + shouldUnregister: true + }); + useEffect(() => { + dispatch( + setFormValidateAsync(() => { + return form.trigger(); + }) + ); + }, [form]); + const { control, watch, reset } = form; + + // const defaultValuesRef: MutableRefObject = useRef({}); + // useEffect(() => { + // // deep clone + // const clonedValues: FieldValues = JSON.parse(JSON.stringify(defaultValues)); + // defaultValuesRef.current = clonedValues; + // // eslint-disable-next-line no-console + // console.log('change default values', defaultValues); + // }, [defaultValues]); + + useEffect(() => { + // const defaultValues: FieldValues = defaultValuesRef.current; + // eslint-disable-next-line no-console + console.log('rest', defaultValues); + reset(defaultValues); + dispatch(onChangeFormDefaultValues(defaultValues)); + }, [commandName, reset, defaultValues]); + + useEffect(() => { + if (!userSelectdParameterName) { + return; + } + const $el: HTMLElement | null = document.getElementById(userSelectdParameterName); + if ($el) { + $el.scrollIntoView({ + behavior: 'smooth', + block: 'start', + inline: 'start' + }); + } + }, [userSelectdParameterName]); + + return ( + +
+

+ rush {commandName} {argsTextList.join(' ')} +

+ {parameters.length === 0 ? ( +
+ No parameters, just click +
+ ) : filteredParameters.length === 0 ? ( +
+ No search results{' '} + { + dispatch(onChangeSearchText('')); + }} + /> +
+ ) : null} + {filteredParameters.map((parameter: ICommandLineParameter) => { + let fieldNode: ReactNode = null; + const baseControllerProps: Pick, 'name' | 'control'> & + UseControllerProps = { + name: parameter.longName, + control + }; + if (parameter.required) { + // eslint-disable-next-line no-console + console.log('required param', parameter.longName); + baseControllerProps.rules = { + validate: (value: undefined | string | number | boolean) => { + // eslint-disable-next-line no-console + console.log('validating', value, parameter.longName); + + if (typeof value === 'undefined' || !String(value)) { + return 'This field is required'; + } + } + }; + } + + switch (parameter.kind) { + case CommandLineParameterKind.Choice: { + const { alternatives, defaultValue }: CommandLineChoiceParameter = + parameter as CommandLineChoiceParameter; + const options: { key: string; text: string }[] = []; + for (const alternative of alternatives) { + options.push({ + key: alternative, + text: alternative + }); + } + + fieldNode = ( + + ); + break; + } + case CommandLineParameterKind.ChoiceList: { + const { alternatives }: CommandLineChoiceListParameter = + parameter as CommandLineChoiceListParameter; + const options: { key: string; text: string }[] = []; + for (const alternative of alternatives) { + options.push({ + key: alternative, + text: alternative + }); + } + fieldNode = ( + + ); + break; + } + case CommandLineParameterKind.Flag: { + // const commandLineFlagParameter: CommandLineFlagParameter = parameter as CommandLineFlagParameter; + fieldNode = ; + break; + } + case CommandLineParameterKind.Integer: { + const commandLineIntegerParameter: CommandLineIntegerParameter = + parameter as CommandLineIntegerParameter; + fieldNode = ( + + ); + break; + } + case CommandLineParameterKind.IntegerList: { + fieldNode = ; + break; + } + case CommandLineParameterKind.String: { + fieldNode = ; + break; + } + case CommandLineParameterKind.StringList: { + fieldNode = ; + break; + } + default: { + // eslint-disable-next-line no-console + console.error(`Unhandled parameter kind: ${parameter.kind}`); + return null; + } + } + + return ( +
+ + {parameter.description ?

{parameter.description}

: null} +
{fieldNode}
+
+ ); + })} + +
+
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterNav.tsx b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterNav.tsx new file mode 100644 index 00000000000..7f10d60d8ea --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/ParameterNav.tsx @@ -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 { Label } from '@fluentui/react'; +import type { AnyAction, Dispatch } from '@reduxjs/toolkit'; +import * as React from 'react'; +import { type CSSProperties, useEffect } from 'react'; + +import { useAppDispatch } from '../store/hooks'; +import { type ICommandLineParameter, useFilteredParameters } from '../store/slices/parameter'; +import { + setUserSelectedParameterName, + useCurrentParameterName, + useUserSelectedParameterName +} from '../store/slices/ui'; + +const navStyle: CSSProperties = { + width: '160px', + height: 'auto', + boxSizing: 'border-box', + overflowY: 'auto' +}; + +const NAV_LABEL_PREFIX: string = 'parameter-nav-label-'; + +export const ParameterNav = (): JSX.Element => { + const parameters: ICommandLineParameter[] = useFilteredParameters(); + const currentParameterName: string = useCurrentParameterName(); + const userSelectdParameterName: string = useUserSelectedParameterName(); + const dispatch: Dispatch = useAppDispatch(); + + useEffect(() => { + const $el: HTMLElement | null = document.getElementById(`${NAV_LABEL_PREFIX}${currentParameterName}`); + if ($el) { + $el.scrollIntoView({ + block: 'nearest', + inline: 'nearest' + }); + } + }, [currentParameterName]); + + return ( +
+ {parameters.map((parameter: ICommandLineParameter) => { + const { longName } = parameter; + const text: string = longName + .replace(/^--([a-z])/, (matches) => { + return matches[2].toUpperCase(); + }) + .replace(/-([a-z])/g, (matches) => { + return matches[1].toUpperCase(); + }); + let fontWeight: string = 'normal'; + if (userSelectdParameterName) { + if (userSelectdParameterName === longName) { + fontWeight = 'bold'; + } + } else if (currentParameterName === longName) { + fontWeight = 'bold'; + } + return ( + + ); + })} +
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ParameterView/index.tsx b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/index.tsx new file mode 100644 index 00000000000..02fc3432256 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ParameterView/index.tsx @@ -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 * as React from 'react'; +import { type IStackStyles, type IStackItemStyles, type IStackTokens, Stack } from '@fluentui/react'; + +import { useScrollableElement } from '../hooks/parametersFormScroll'; +import { ParameterForm } from './ParameterForm'; +import { ParameterNav } from './ParameterNav'; + +// Styles definition +const stackStyles: IStackStyles = { + root: { + // background: DefaultPalette.themeTertiary, + height: '100%' + } +}; +const stackItemStyles: IStackItemStyles = { + root: { + alignItems: 'flex-start', + // background: DefaultPalette.themePrimary, + // color: DefaultPalette.white, + display: 'flex', + height: '100%', + justifyContent: 'flex-start', + minWidth: 0, + overflow: 'auto' + } +}; + +// Tokens definition +const stackTokens: IStackTokens = { + childrenGap: 5, + padding: 10 +}; + +export const ParameterView = (): JSX.Element => { + const { elementId, onScroll } = useScrollableElement(); + return ( + + + + + + + + + ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/ProjectView/index.tsx b/vscode-extensions/rush-vscode-command-webview/src/ProjectView/index.tsx new file mode 100644 index 00000000000..fef6dcb5a5d --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/ProjectView/index.tsx @@ -0,0 +1,33 @@ +// 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 { useAppSelector } from '../store/hooks'; + +export const ProjectView: React.FC = () => { + const { projectName, projectVersion, dependencies, devDependencies } = useAppSelector( + (state) => state.project + ); + + return ( +
+

Project Name: {projectName}

+
Project Version: {projectVersion}
+

Dependencies:

+ {dependencies && + Object.entries(dependencies).map(([depName, depVersion]) => ( +

+ {depName}: {depVersion} +

+ ))} +

Dev Dependencies:

+ {devDependencies && + Object.entries(devDependencies).map(([depName, depVersion]) => ( +

+ {depName}: {depVersion} +

+ ))} +
+ ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/Toolbar/RunButton.tsx b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/RunButton.tsx new file mode 100644 index 00000000000..695901f7a92 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/RunButton.tsx @@ -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 { PrimaryButton } from '@fluentui/react/lib/Button'; +import * as React from 'react'; +import { useCallback } from 'react'; + +import { sendMessageToExtension } from '../Message/toExtension'; +import { useAppSelector } from '../store/hooks'; +import { useParameterArgs } from '../store/slices/parameter'; + +export const RunButton = (): JSX.Element => { + const commandName: string = useAppSelector((state) => state.parameter.commandName); + const formValidateAsync: (() => Promise) | undefined = useAppSelector( + (state) => state.ui.formValidateAsync + ); + const args: string[] = useParameterArgs(); + const onClickRunButton: () => void = useCallback(async () => { + // eslint-disable-next-line no-console + console.log('onCLickRun', commandName, formValidateAsync); + if (!commandName || !formValidateAsync) { + return; + } + const isValid: boolean = await formValidateAsync(); + // eslint-disable-next-line no-console + console.log('isValid', isValid); + if (isValid) { + sendMessageToExtension({ + command: 'commandInfo', + commandName, + args + }); + } + }, [args, commandName, formValidateAsync]); + return ; +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/Toolbar/SearchBar.tsx b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/SearchBar.tsx new file mode 100644 index 00000000000..b74757ff3f1 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/SearchBar.tsx @@ -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 { SearchBox } from '@fluentui/react'; +import * as React from 'react'; +import type { AnyAction, Dispatch } from '@reduxjs/toolkit'; + +import { useAppDispatch, useAppSelector } from '../store/hooks'; +import { onChangeSearchText } from '../store/slices/parameter'; + +export const SearchBar = (): JSX.Element => { + const searchText: string = useAppSelector((state) => state.parameter.searchText); + const dispatch: Dispatch = useAppDispatch(); + return ( + { + dispatch(onChangeSearchText(newValue)); + }} + /> + ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/Toolbar/index.tsx b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/index.tsx new file mode 100644 index 00000000000..c77f1a3b6bd --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/Toolbar/index.tsx @@ -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 { + type IStackItemStyles, + type IStackStyles, + type IStackTokens, + type IStyle, + Stack +} from '@fluentui/react'; +import * as React from 'react'; +import type { CSSProperties } from 'react'; + +import { useStickyToolbar } from '../hooks/parametersFormScroll'; +import { RunButton } from './RunButton'; +import { SearchBar } from './SearchBar'; + +// Styles definition +const stackStyles: IStackStyles = { + root: { + // background: DefaultPalette.themeTertiary, + transition: 'box-shadow ease-in-out 0.1s' + } +}; + +const stackItemStyles: IStackItemStyles = { + root: { + // background: DefaultPalette.themePrimary, + // color: DefaultPalette.white, + } +}; + +const horizontalGapStackTokens: IStackTokens = { + childrenGap: 10, + padding: 10 +}; + +export const Toolbar = (): JSX.Element => { + const { isSticky } = useStickyToolbar(); + if (isSticky) { + stackStyles.root = { + ...(stackStyles.root as CSSProperties), + boxShadow: 'rgb(17 17 26 / 10%) 0px 4px 16px, rgb(17 17 26 / 5%) 0px 8px 32px' + } as IStyle; + } else { + (stackStyles.root as CSSProperties).boxShadow = 'none'; + } + return ( + + + + + + + + + ); +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/VersionsView/index.tsx b/vscode-extensions/rush-vscode-command-webview/src/VersionsView/index.tsx new file mode 100644 index 00000000000..e3c3520af38 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/VersionsView/index.tsx @@ -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. + +import React from 'react'; + +export const VersionsView = (): JSX.Element => { + return
Verrsions view...
; +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/components/IconButton.tsx b/vscode-extensions/rush-vscode-command-webview/src/components/IconButton.tsx new file mode 100644 index 00000000000..f684fa78fe7 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/components/IconButton.tsx @@ -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 * as React from 'react'; +import { IconButton as FIconButton, type IButtonProps } from '@fluentui/react'; + +const iconButtonStyles: IButtonProps['styles'] = { + root: { + color: 'var(--vscode-input-foreground)' + }, + rootHovered: { + color: 'var(--vscode-input-foreground)', + background: 'var(--vscode-inputOption-hoverBackground)' + }, + rootPressed: { + color: 'var(--vscode-button-secondaryForeground)', + backgroundColor: 'var(--vscode-button--secondaryBackground)' + } +}; + +export const IconButton = (props: IButtonProps): JSX.Element => { + return ; +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/entry.tsx b/vscode-extensions/rush-vscode-command-webview/src/entry.tsx new file mode 100644 index 00000000000..054f3e297b6 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/entry.tsx @@ -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. + +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +// import { ThemeProvider, PartialTheme } from '@fluentui/react'; +import { FluentProvider, teamsDarkTheme } from '@fluentui/react-components'; + +import { App } from './App'; +import { store } from './store'; + +// const theme: PartialTheme = { +// palette: { +// // themePrimary: 'var(--vscode-settings-headerForeground)', +// // themeSecondary: 'var(--vscode-button-secondaryForeground)', +// neutralDark: 'var(--vscode-settings-headerForeground)' +// }, +// defaultFontStyle: { +// fontFamily: 'var(--vscode-font-family)', +// fontWeight: 'var(--vscode-font-weight)', +// fontSize: 'var(--vscode-font-size)' +// }, +// semanticColors: { +// focusBorder: 'var(--vscode-focusBorder)', +// errorText: 'var(--vscode-errorForeground)', +// buttonText: 'var(--vscode-button-foreground)', +// buttonBackground: 'var(--vscode-button-background)', +// buttonBackgroundHovered: 'var(--vscode-button-hoverBackground)', +// primaryButtonText: 'var(--vscode-button-foreground)', +// primaryButtonBackground: 'var(--vscode-button-background)', +// primaryButtonBackgroundHovered: 'var(--vscode-button-hoverBackground)', +// inputIcon: 'var(--vscode-settings-textInputForeground)', +// inputIconHovered: 'var(--vscode-settings-textInputForeground)', +// inputText: 'var(--vscode-settings-textInputForeground)', +// inputBackground: 'var(--vscode-settings-textInputBackground)', +// inputPlaceholderText: 'var(--vscode-input-placeholderForeground)', +// inputBorderHovered: 'var(--vscode-inputOption-activeForeground)', +// inputFocusBorderAlt: 'var(--vscode-inputOption-activeBorder)', +// inputBackgroundChecked: 'var(--vscode-inputOption-activeBackground)', +// inputBackgroundCheckedHovered: 'var(--vscode-inputOption-activeBackground)', +// inputForegroundChecked: 'var(--vscode-inputOption-activeForeground)', +// bodyText: 'var(--vscode-editor-foreground)', +// bodyBackground: 'var(--vscode-editor-background)' +// } +// }; + +// eslint-disable-next-line @rushstack/no-new-null +const $root: HTMLElement | null = document.getElementById('root'); + +if ($root) { + ReactDOM.render( + + + + + , + $root + ); +} else { + // eslint-disable-next-line no-console + console.error("error can't find root!"); +} diff --git a/vscode-extensions/rush-vscode-command-webview/src/hooks/parametersFormScroll.ts b/vscode-extensions/rush-vscode-command-webview/src/hooks/parametersFormScroll.ts new file mode 100644 index 00000000000..e53224f5e71 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/hooks/parametersFormScroll.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 { type MutableRefObject, type UIEventHandler, useCallback, useEffect, useRef } from 'react'; +import type { Dispatch, AnyAction } from '@reduxjs/toolkit'; + +import { useAppDispatch } from '../store/hooks'; +import { + setCurretParameterName, + setIsToolbarSticky, + setUserSelectedParameterName, + useCurrentParameterName, + useIsToolbarSticky, + useUserSelectedParameterName +} from '../store/slices/ui'; + +export const SCROLLABLE_ELEMENT_ID: string = 'parameters-scrollable-element'; +export const FIELD_ANCHOR_CLASSNAME: string = 'parameters-field-anchor'; + +export interface IUseScrollableElementReturn { + elementId: string; + onScroll: UIEventHandler; +} + +export interface IUseStickyToolbarReturn { + isSticky: boolean; +} + +export const useStickyToolbar = (): IUseStickyToolbarReturn => { + const isSticky: boolean = useIsToolbarSticky(); + return { + isSticky + }; +}; + +export const useScrollableElement = (): IUseScrollableElementReturn => { + const isSticky: boolean = useIsToolbarSticky(); + const currentParameterName: string = useCurrentParameterName(); + const userSelectedParameterName: string = useUserSelectedParameterName(); + const dispatch: Dispatch = useAppDispatch(); + const timeoutIdRef: MutableRefObject | undefined> = useRef(); + const userSelectionScrollingRef: MutableRefObject = useRef(false); + + const deboucedScrollEnd: () => void = useCallback(() => { + if (timeoutIdRef.current) { + clearTimeout(timeoutIdRef.current); + } + timeoutIdRef.current = setTimeout(() => { + userSelectionScrollingRef.current = false; + timeoutIdRef.current = undefined; + }, 100); + }, []); + + useEffect(() => { + if (userSelectedParameterName) { + userSelectionScrollingRef.current = true; + } + }, [userSelectedParameterName]); + + const onScroll: UIEventHandler = useCallback(() => { + const $el: HTMLElement | null = document.getElementById(SCROLLABLE_ELEMENT_ID); + if (!$el) { + return; + } + const newIsStick: boolean = $el.scrollTop !== 0; + if (isSticky !== newIsStick) { + dispatch(setIsToolbarSticky(newIsStick)); + } + + /** + * Do not detect parameter name if still scrolling after + * user selected a parameter name. + */ + if (!userSelectionScrollingRef.current) { + const $parameters: HTMLElement[] = Array.from(document.querySelectorAll(`.${FIELD_ANCHOR_CLASSNAME}`)); + const estimateParameterHeight: number = 90; + const $currentParameter: HTMLElement | undefined = + $parameters.find(($p) => { + return $p.offsetTop - $el.offsetTop - $el.scrollTop + estimateParameterHeight > 0; + }) || $parameters[0]; + const nextParameterName: string = $currentParameter?.id || ''; + if (nextParameterName !== currentParameterName) { + dispatch(setCurretParameterName(nextParameterName)); + dispatch(setUserSelectedParameterName('')); + } + } + deboucedScrollEnd(); + }, [isSticky, currentParameterName, deboucedScrollEnd]); + + return { + elementId: SCROLLABLE_ELEMENT_ID, + onScroll + }; +}; diff --git a/vscode-extensions/rush-vscode-command-webview/src/index.ts b/vscode-extensions/rush-vscode-command-webview/src/index.ts new file mode 100644 index 00000000000..33fb5f7b7b1 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/index.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export type { IFromExtensionMessage } from './Message/fromExtension'; +export type { IRootState } from './store'; +export type { IToExtensionMessage } from './Message/toExtension'; +export type { ICommandLineParameter } from './store/slices/parameter'; + +export type { CommandLineParameter } from '@rushstack/ts-command-line/lib/parameters/BaseClasses'; +export type { CommandLineAction } from '@rushstack/ts-command-line/lib/providers/CommandLineAction'; +export { CommandLineParameterKind } from '@rushstack/ts-command-line/lib/parameters/BaseClasses'; diff --git a/vscode-extensions/rush-vscode-command-webview/src/store/hooks/index.ts b/vscode-extensions/rush-vscode-command-webview/src/store/hooks/index.ts new file mode 100644 index 00000000000..f8f27288b8a --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/store/hooks/index.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 TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; + +import type { AppDispatch, IRootState } from '..'; + +export const useAppDispatch: () => AppDispatch = () => useDispatch(); +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/vscode-extensions/rush-vscode-command-webview/src/store/index.ts b/vscode-extensions/rush-vscode-command-webview/src/store/index.ts new file mode 100644 index 00000000000..2927dd515ee --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/store/index.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 { configureStore } from '@reduxjs/toolkit'; +import type { EnhancedStore } from '@reduxjs/toolkit'; + +import parameterReducer, { type IParameterState } from './slices/parameter'; +import uiReducer, { type IUIState } from './slices/ui'; +import projectReducer, { type IProjectState } from './slices/project'; + +export interface IRootState { + parameter: IParameterState; + ui: IUIState; + project: IProjectState; +} + +export const store: EnhancedStore = configureStore({ + preloadedState: window.__DATA__, + reducer: { + parameter: parameterReducer, + ui: uiReducer, + project: projectReducer + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + // Ignore these action types + ignoredActions: ['ui/setFormValidateAsync'], + // Ignore these field paths in all actions + // ignoredActionPaths: ['meta.arg', 'payload.timestamp'], + // Ignore these paths in the state + ignoredPaths: ['ui.formValidateAsync'] + } + }) +}); + +store.subscribe(() => { + // eslint-disable-next-line no-console + console.log('store changes', store.getState()); +}); + +export type AppDispatch = typeof store.dispatch; diff --git a/vscode-extensions/rush-vscode-command-webview/src/store/slices/parameter.ts b/vscode-extensions/rush-vscode-command-webview/src/store/slices/parameter.ts new file mode 100644 index 00000000000..3fd1fcc69ac --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/store/slices/parameter.ts @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { type SliceCaseReducers, createSlice, type Slice, type PayloadAction } from '@reduxjs/toolkit'; +import type { FieldValues } from 'react-hook-form'; + +import type { CommandLineParameterKind } from '@rushstack/ts-command-line'; + +import { useAppSelector } from '../hooks'; + +export interface ICommandLineParameter { + readonly kind: CommandLineParameterKind; + readonly longName: string; + readonly shortName: string | undefined; + readonly description: string; + readonly required: boolean; +} + +export interface IParameterState { + commandName: string; + parameters: ICommandLineParameter[]; + argsKV: Record; + searchText: string; +} + +const initialState: IParameterState = { + commandName: '', + parameters: [], + argsKV: {}, + searchText: '' +}; + +export const parameterSlice: Slice, string> = createSlice( + { + name: 'parameter', + initialState, + reducers: { + initializeParameters: (state, action: PayloadAction) => { + Object.assign(state, action.payload); + }, + onChangeFormDefaultValues: (state, action: PayloadAction) => { + // clear argsKV first + state.argsKV = {}; + patchStateByFormValues(state, action.payload); + }, + onChangeFormValues: (state, action: PayloadAction) => { + patchStateByFormValues(state, action.payload); + }, + onChangeSearchText: (state, action: PayloadAction) => { + state.searchText = action.payload; + } + } + } +); + +function patchStateByFormValues(state: IParameterState, fieldValues: FieldValues): void { + for (const [key, fieldValue] of Object.entries(fieldValues)) { + if (typeof fieldValue === 'string') { + switch (fieldValue) { + case '': { + state.argsKV[key] = undefined; + break; + } + case 'true': { + state.argsKV[key] = true; + break; + } + case 'false': { + state.argsKV[key] = false; + break; + } + default: { + state.argsKV[key] = fieldValue; + break; + } + } + } else if (Array.isArray(fieldValue)) { + const filteredValue: string[] = fieldValue + .map(({ value }: { value: string | number }) => String(value)) + .filter(Boolean); + if (filteredValue.length) { + state.argsKV[key] = filteredValue; + } else { + state.argsKV[key] = []; + } + } else { + state.argsKV[key] = fieldValue; + } + } +} + +export const { initializeParameters, onChangeFormDefaultValues, onChangeFormValues, onChangeSearchText } = + parameterSlice.actions; + +export const useParameterArgs: () => string[] = () => + useAppSelector((state) => { + const args: string[] = []; + for (const [k, v] of Object.entries(state.parameter.argsKV)) { + if (v) { + if (v === true) { + args.push(k); + } else if (Array.isArray(v)) { + v.forEach((item: string | number) => { + args.push(k); + args.push(String(item)); + }); + } else { + args.push(k); + args.push(String(v)); + } + } + } + return args; + }); + +function isParametersEqual(left: ICommandLineParameter[], right: ICommandLineParameter[]): boolean { + if (left.length !== right.length) { + return false; + } + for (let i: number = 0; i < left.length; i++) { + const item: ICommandLineParameter = left[i]; + Object.entries(item).forEach(([key, value]) => { + if (value !== right[i][key as keyof ICommandLineParameter]) { + return false; + } + }); + } + return true; +} + +export const useParameters: () => ICommandLineParameter[] = () => { + return useAppSelector((state) => { + return state.parameter.parameters; + }, isParametersEqual); +}; + +export const useFilteredParameters: () => ICommandLineParameter[] = () => { + const parameters: ICommandLineParameter[] = useParameters(); + const searchText: string = useAppSelector((state) => state.parameter.searchText); + return parameters.filter((parameter) => { + return parameter.longName.includes(searchText) || parameter.description.includes(searchText); + }); +}; + +export const useArgsTextList = (): string[] => { + const args: string[] = useParameterArgs(); + const argsTextList: string[] = []; + for (let i: number = 0; i < args.length; i++) { + const currentArg: string = args[i]; + let nextArg: string | undefined; + if (i + 1 < args.length) { + nextArg = args[i + 1]; + } + if (!nextArg || nextArg?.startsWith('--')) { + argsTextList.push(currentArg); + } else { + argsTextList.push(`${currentArg} ${nextArg}`); + i++; + } + } + return argsTextList; +}; + +export default parameterSlice.reducer; diff --git a/vscode-extensions/rush-vscode-command-webview/src/store/slices/project.ts b/vscode-extensions/rush-vscode-command-webview/src/store/slices/project.ts new file mode 100644 index 00000000000..a6c6ef80563 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/store/slices/project.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 { type PayloadAction, type Slice, type SliceCaseReducers, createSlice } from '@reduxjs/toolkit'; + +export interface IProjectState { + projectName: string; + projectVersion: string; + dependencies?: { [key in string]: string }; + devDependencies?: { [key in string]: string }; +} + +const initialState: IProjectState = { + projectName: '', + projectVersion: '' +}; + +export const projectSlide: Slice, string> = createSlice({ + name: 'project', + initialState, + reducers: { + initializeProjectInfo: (state, action: PayloadAction) => { + // eslint-disable-next-line no-console + console.log('action payload: ', action.payload); + Object.assign(state, action.payload); + }, + onChangeProject: (state, action: PayloadAction) => { + // eslint-disable-next-line no-console + console.log('action payload: ', action.payload); + Object.assign(state, action.payload); + } + } +}); + +export const { initializeProjectInfo, onChangeProject } = projectSlide.actions; + +export default projectSlide.reducer; diff --git a/vscode-extensions/rush-vscode-command-webview/src/store/slices/ui.ts b/vscode-extensions/rush-vscode-command-webview/src/store/slices/ui.ts new file mode 100644 index 00000000000..99fddf77433 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/store/slices/ui.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 { createSlice, type Slice, type SliceCaseReducers } from '@reduxjs/toolkit'; + +import { useAppSelector } from '../hooks'; + +export interface IUIState { + isToolbarSticky: boolean; + currentParameterName: string; + userSelectedParameterName: string; + formValidateAsync?: () => Promise; +} + +const initialState: IUIState = { + isToolbarSticky: false, + currentParameterName: '', + userSelectedParameterName: '' +}; + +export const uiSlice: Slice, string> = createSlice({ + name: 'ui', + initialState, + reducers: { + setIsToolbarSticky: (state, action) => { + state.isToolbarSticky = Boolean(action.payload); + }, + setCurretParameterName: (state, action) => { + state.currentParameterName = action.payload; + }, + setUserSelectedParameterName: (state, action) => { + state.userSelectedParameterName = action.payload; + }, + setFormValidateAsync: (state, action) => { + state.formValidateAsync = action.payload; + } + } +}); + +export const { + setIsToolbarSticky, + setCurretParameterName, + setUserSelectedParameterName, + setFormValidateAsync +} = uiSlice.actions; + +export default uiSlice.reducer; + +export const useIsToolbarSticky = (): boolean => { + const isSticky: boolean = useAppSelector((state) => state.ui.isToolbarSticky); + return isSticky; +}; + +export const useCurrentParameterName = (): string => useAppSelector((state) => state.ui.currentParameterName); +export const useUserSelectedParameterName = (): string => + useAppSelector((state) => state.ui.userSelectedParameterName); diff --git a/vscode-extensions/rush-vscode-command-webview/src/typings.d.ts b/vscode-extensions/rush-vscode-command-webview/src/typings.d.ts new file mode 100644 index 00000000000..8571f280f14 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/src/typings.d.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. + +import type { IRootState } from './store'; +import type { Webview } from 'vscode'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + __DATA__: IRootState; + acquireVsCodeApi: () => Webview; + } +} diff --git a/vscode-extensions/rush-vscode-command-webview/tsconfig.json b/vscode-extensions/rush-vscode-command-webview/tsconfig.json new file mode 100644 index 00000000000..ce5520a3659 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/library/tsconfig-base.json", + "compilerOptions": { + "skipLibCheck": true, // This project imports some projects that target Node + "target": "es2017", + "lib": ["es2017", "scripthost", "dom"] + } +} diff --git a/vscode-extensions/rush-vscode-command-webview/webpack.config.js b/vscode-extensions/rush-vscode-command-webview/webpack.config.js new file mode 100644 index 00000000000..fc39d6df9e3 --- /dev/null +++ b/vscode-extensions/rush-vscode-command-webview/webpack.config.js @@ -0,0 +1,72 @@ +/* eslint-env es6 */ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); + +function createWebpackConfig({ production }) { + const webpackConfig = { + mode: production ? 'production' : 'development', + resolve: { + // Note: Do not specify '.ts' or '.tsx' here. Heft invokes Webpack as a post-process after the compiler. + extensions: ['.js', '.jsx', '.json'], + fallback: { + fs: false, + path: false, + os: false + } + }, + entry: { + ['bundle']: path.join(__dirname, 'lib', 'entry.js') + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name].js' + }, + module: { + rules: [ + { + test: /\.(jpeg|jpg|png|gif|svg|ico|woff|woff2|ttf|eot)$/, + // Allows import/require() to be used with an asset file. The file will be copied to the output folder, + // and the import statement will return its URL. + // https://webpack.js.org/guides/asset-modules/#resource-assets + type: 'asset/resource' + } + ] + }, + devServer: { + host: 'localhost', + port: 8080 + }, + devtool: production ? undefined : 'source-map', + optimization: { + runtimeChunk: false, + splitChunks: { + cacheGroups: { + default: false + } + } + }, + performance: { + hints: false, + maxEntrypointSize: 512000, + maxAssetSize: 512000 + }, + plugins: [ + new HtmlWebpackPlugin({ + template: 'public/index.html' + }), + new BundleAnalyzerPlugin({ + openAnalyzer: false, + analyzerMode: 'static', + reportFilename: path.resolve(__dirname, 'temp', 'stats.html'), + generateStatsFile: true, + statsFilename: path.resolve(__dirname, 'temp', 'stats.json'), + logLevel: 'info' + }) + ].filter(Boolean) + }; + + return webpackConfig; +} + +module.exports = createWebpackConfig; diff --git a/vscode-extensions/rush-vscode-extension/.gitignore b/vscode-extensions/rush-vscode-extension/.gitignore new file mode 100644 index 00000000000..ec8dec70872 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/.gitignore @@ -0,0 +1 @@ +webview/ diff --git a/vscode-extensions/rush-vscode-extension/.npmignore b/vscode-extensions/rush-vscode-extension/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/rush-vscode-extension/.vscodeignore b/vscode-extensions/rush-vscode-extension/.vscodeignore new file mode 100644 index 00000000000..9231798330f --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/.vscodeignore @@ -0,0 +1,9 @@ +** +!LICENSE +!README.md +!extension.js +!package.json +!assets/rushstack-icon.png +!assets/rushstack-icon.svg +!webview/rush-command-webview/bundle.js +!webview/rush-command-webview/index.html diff --git a/vscode-extensions/rush-vscode-extension/LICENSE b/vscode-extensions/rush-vscode-extension/LICENSE new file mode 100644 index 00000000000..462853efafa --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/LICENSE @@ -0,0 +1,24 @@ +rushstack vscode extension + +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/vscode-extensions/rush-vscode-extension/README.md b/vscode-extensions/rush-vscode-extension/README.md new file mode 100644 index 00000000000..12af0566460 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/README.md @@ -0,0 +1,26 @@ +# Rush Stack monorepo tools + + + +This VS Code extension provides various enhancements when working with a TypeScript monorepo +that uses the [Rush Stack](https://rushstack.io/) family of tools. + + +> 🚨 *EARLY PREVIEW RELEASE* 🚨 +> +> Not all features are implemented yet. If you have questions or ideas +> to improve this extension, please [let us know](https://rushstack.io/pages/help/support/). +> Thanks! + + +## Installation + +Install through VS Code extensions. Search for `Rush Stack monorepo tools` + +[Visual Studio Code Market Place: Rush Stack monorepo tools](https://marketplace.visualstudio.com/items?itemName=RushStack.rushstack) + +Can also be installed in VS Code: Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter. + +``` +ext install RushStack.rushstack +``` diff --git a/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.png b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.png new file mode 100644 index 00000000000..31e26476d16 Binary files /dev/null and b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.png differ diff --git a/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.svg b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.svg new file mode 100644 index 00000000000..cc6f37e24a4 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/assets/rushstack-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vscode-extensions/rush-vscode-extension/config/heft.json b/vscode-extensions/rush-vscode-extension/config/heft.json new file mode 100644 index 00000000000..af08cae80ee --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/config/heft.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/heft.json", + + "aliasesByName": { + "start": { + "actionName": "build-watch", + "defaultParameters": ["--serve"] + } + }, + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["webview"] }], + "tasksByName": { + "copy-webview": { + "taskPlugin": { + "pluginName": "copy-files-plugin", + "pluginPackage": "@rushstack/heft", + "options": { + "copyOperations": [ + { + "sourcePath": "node_modules/@rushstack/rush-vscode-command-webview/dist", + "destinationFolders": ["webview/rush-command-webview"], + "includeGlobs": ["*.{html,js,txt}"] + } + ] + } + } + } + } + } + } +} diff --git a/vscode-extensions/rush-vscode-extension/config/rig.json b/vscode-extensions/rush-vscode-extension/config/rig.json new file mode 100644 index 00000000000..ec33a848348 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-vscode-extension-rig" +} diff --git a/vscode-extensions/rush-vscode-extension/config/rush-project.json b/vscode-extensions/rush-vscode-extension/config/rush-project.json new file mode 100644 index 00000000000..f4ca51150ee --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "@rushstack/heft-vscode-extension-rig/profiles/default/config/rush-project.json", + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["webview"] + } + ] +} diff --git a/vscode-extensions/rush-vscode-extension/eslint.config.js b/vscode-extensions/rush-vscode-extension/eslint.config.js new file mode 100644 index 00000000000..eac79367926 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/eslint.config.js @@ -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. + +const nodeTrustedToolProfile = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-vscode-extension-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/rush-vscode-extension/package.json b/vscode-extensions/rush-vscode-extension/package.json new file mode 100644 index 00000000000..82ac18b350a --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/package.json @@ -0,0 +1,318 @@ +{ + "name": "rushstack", + "version": "0.0.2", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/rush-vscode-extension" + }, + "license": "MIT", + "publisher": "RushStack", + "preview": true, + "displayName": "Rush Stack monorepo tools", + "description": "Enhanced experience for monorepos that use the Rush Stack toolchain", + "homepage": "https://rushstack.io", + "categories": [ + "Formatters", + "Other", + "Extension Packs", + "Visualization" + ], + "keywords": [ + "api-extractor", + "build", + "heft", + "js", + "lockfile", + "monorepo", + "orchestrator", + "rig", + "rush", + "ts", + "tsdoc", + "typescript", + "web" + ], + "galleryBanner": { + "color": "#f0f0f0", + "theme": "light" + }, + "icon": "assets/rushstack-icon.png", + "badges": [ + { + "url": "https://img.shields.io/badge/Rush-db714a", + "href": "https://rushjs.io/", + "description": "Rush build orchestrator" + }, + { + "url": "https://img.shields.io/badge/Heft-db714a", + "href": "https://heft.rushstack.io/", + "description": "Heft toolchain" + }, + { + "url": "https://img.shields.io/badge/Lockfile%20Explorer-db714a", + "href": "https://lfx.rushstack.io/", + "description": "Lockfile Explorer dependency visualizer" + }, + { + "url": "https://img.shields.io/badge/API%20Extractor-db714a", + "href": "https://api-extractor.com/", + "description": "API Extractor review and documentation engine" + }, + { + "url": "https://img.shields.io/badge/TSDoc-db714a", + "href": "https://tsdoc.org", + "description": "TSDoc standard for API doc comments" + }, + { + "url": "https://img.shields.io/badge/Get%20Help-0078d4?label=%F0%9F%97%A8%EF%B8%8F", + "href": "https://rushstack.io/pages/help/support/", + "description": "Rush Stack community support" + } + ], + "main": "./extension.js", + "scripts": { + "build": "heft build --clean", + "build:watch": "heft build-watch", + "start": "heft start", + "pretest": "npm run build", + "test": "node ./lib/test/runTest.js", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "" + }, + "contributes": { + "commands": [ + { + "command": "rushstack.openSettings", + "category": "RushStack", + "title": "Open Settings" + }, + { + "command": "rushstack.selectWorkspace", + "category": "RushStack", + "title": "Select workspace" + }, + { + "command": "rushstack.refresh", + "category": "RushStack", + "title": "Refresh", + "icon": "$(refresh)" + }, + { + "command": "rushstack.rushCommands.openParameterViewPanel", + "category": "RushStack", + "title": "Open Parameter View Panel" + }, + { + "command": "rushstack.rushCommands.runRushCommand", + "category": "RushStack", + "title": "Run Rush Command" + }, + { + "command": "rushstack.rushProjects.revealInExplorer", + "category": "RushStack", + "title": "Reveal In Explorer", + "icon": "$(folder)" + }, + { + "command": "rushstack.rushProjects.revealProjectDetail", + "category": "RushStack", + "title": "See Project Details", + "icon": "$(search)" + }, + { + "command": "rushstack.rushProjects.runProjectScript", + "category": "RushStack", + "title": "Run", + "icon": "$(play)" + } + ], + "configuration": { + "title": "Rush Stack monorepo tools", + "properties": { + "rushstack.logLevel": { + "type": "string", + "default": "info", + "enum": [ + "info", + "debug" + ], + "description": "The log level to use for the VS Code extension" + } + } + }, + "menus": { + "view/title": [ + { + "command": "rushstack.refresh", + "when": "view == rushProjects || view == rushCommands", + "group": "navigation" + } + ], + "view/item/context": [ + { + "command": "rushstack.rushProjects.revealInExplorer", + "when": "view == rushProjects && viewItem == project", + "group": "inline" + }, + { + "command": "rushstack.rushProjects.revealProjectDetail", + "when": "view == rushProjects && viewItem == project", + "group": "inline" + }, + { + "command": "rushstack.rushProjects.runProjectScript", + "when": "view == rushProjects && viewItem == projectScript", + "group": "inline" + } + ] + }, + "taskDefinitions": [ + { + "type": "rush", + "required": [ + "cwd", + "displayName", + "command", + "args" + ], + "properties": { + "cwd": { + "type": "string", + "description": "The working directory for the task" + }, + "displayName": { + "type": "string", + "description": "The display name for the command" + }, + "command": { + "type": "string", + "description": "The command to run" + }, + "args": { + "type": "array", + "description": "The arguments to pass to the command" + } + } + }, + { + "type": "rushx", + "required": [ + "cwd", + "command" + ], + "properties": { + "cwd": { + "type": "string", + "description": "The working directory for the command" + }, + "displayName": { + "type": "string", + "description": "The display name for the command" + }, + "command": { + "type": "string", + "description": "The command to run" + } + } + } + ], + "problemMatchers": [ + { + "name": "rushstack-file-error-unix", + "owner": "typescript", + "source": "rushstack", + "fileLocation": [ + "relative", + "${cwd}" + ], + "applyTo": "allDocuments", + "pattern": { + "regexp": "^\\[[^\\]]+\\]\\s+(Error|Warning):\\s+([^:]+):(\\d+):(\\d+)\\s+-\\s+(?:\\(([^)]+)\\)\\s+)?(.*)$", + "severity": 1, + "file": 2, + "line": 3, + "column": 4, + "code": 5, + "message": 6 + } + }, + { + "name": "rushstack-file-error-visualstudio", + "owner": "typescript", + "source": "rushstack", + "fileLocation": [ + "relative", + "${cwd}" + ], + "applyTo": "allDocuments", + "pattern": { + "regexp": "^\\[[^\\]]+\\]\\s+(Error|Warning):\\s+([^\\(]+)\\((\\d+),(\\d+)\\)\\s+-\\s+(?:\\(([^)]+)\\)\\s+)?(.*)$", + "severity": 1, + "file": 2, + "line": 3, + "column": 4, + "code": 5, + "message": 6 + } + } + ], + "views": { + "rushstack": [ + { + "id": "rushProjects", + "name": "Projects" + }, + { + "id": "rushProjectDetails", + "type": "webview", + "name": "Rush Project Details" + } + ] + }, + "viewsContainers": { + "activitybar": [ + { + "id": "rushstack", + "title": "Rush Stack", + "icon": "assets/rushstack-icon.svg" + } + ] + }, + "viewsWelcome": [ + { + "view": "rushProjects", + "contents": "Open a monorepo folder containing a rush.json config file.\n[Open Folder](command:vscode.openFolder)\nFor more information about the Rush Stack tools, consult the [website documentation](https://rushstack.io).", + "when": "workbenchState == empty" + } + ] + }, + "activationEvents": [ + "onView:rushProjects", + "onView:rushCommands", + "onView:rushProjectDetails" + ], + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "@rushstack/rush-vscode-command-webview": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/glob": "7.1.1", + "@types/mocha": "10.0.6", + "@types/vscode": "1.103.0", + "@types/webpack-env": "1.18.8", + "@vscode/test-electron": "^1.6.2", + "eslint": "~9.37.0", + "glob": "~7.0.5", + "@rushstack/heft-vscode-extension-rig": "workspace:*", + "mocha": "^10.1.0" + }, + "engines": { + "vscode": "^1.103.0" + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/extension.ts b/vscode-extensions/rush-vscode-extension/src/extension.ts new file mode 100644 index 00000000000..9b72eb220f0 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/extension.ts @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// The module 'vscode' contains the VS Code extensibility API +// Import the module and reference it with the alias vscode in your code below +import * as vscode from 'vscode'; +import { type LogLevel, setLogLevel, terminal } from './logic/logger'; +import { RushWorkspace } from './logic/RushWorkspace'; +import { RushProjectsProvider } from './providers/RushProjectsProvider'; +import { RushTaskProvider } from './providers/TaskProvider'; +import { RushCommandWebViewPanel } from './logic/RushCommandWebViewPanel'; + +// this method is called when your extension is activated +// your extension is activated the very first time the command is executed +export async function activate(context: vscode.ExtensionContext): Promise { + context.subscriptions.push( + vscode.commands.registerCommand('rushstack.selectWorkspace', async () => { + await RushWorkspace.selectWorkspaceAsync(); + }) + ); + context.subscriptions.push( + vscode.commands.registerCommand('rushstack.openSettings', async () => { + await vscode.commands.executeCommand('workbench.action.openSettings', 'rushstack'); + }) + ); + + const extensionConfiguration: vscode.WorkspaceConfiguration = + vscode.workspace.getConfiguration('rushstack'); + + terminal.writeLine(`Extension configuration: ${JSON.stringify(extensionConfiguration)}`); + + const extensionLogLevel: LogLevel | undefined = extensionConfiguration.get('logLevel'); + if (extensionLogLevel) { + setLogLevel(extensionLogLevel); + } + + const workspaceFolderPaths: string[] = vscode.workspace.workspaceFolders?.map((x) => x.uri.fsPath) || []; + const rushWorkspace: RushWorkspace | undefined = + await RushWorkspace.initializeFromWorkspaceFolderPathsAsync(workspaceFolderPaths); + if (rushWorkspace) { + const rushProjectsProvider: RushProjectsProvider = new RushProjectsProvider(context); + // Projects Tree View + vscode.window.createTreeView('rushProjects', { + treeDataProvider: rushProjectsProvider + }); + vscode.tasks.registerTaskProvider('rushstack', RushTaskProvider.getInstance()); + + // const rushCommandsProvider: RushCommandsProvider = new RushCommandsProvider(context); + // // Rush Commands TreeView + // vscode.window.createTreeView('rushCommands', { + // treeDataProvider: rushCommandsProvider + // }); + // context.subscriptions.push( + // vscode.commands.registerCommand('rushstack.refresh', async () => { + // const workspaceFolderPaths: string[] = + // vscode.workspace.workspaceFolders?.map((x) => x.uri.fsPath) || []; + // await RushWorkspace.initializeFromWorkspaceFolderPathsAsync(workspaceFolderPaths); + // }) + // ); + + RushCommandWebViewPanel.initialize(context).reveal(); + } +} + +// this method is called when your extension is deactivated +export function deactivate(): void {} diff --git a/vscode-extensions/rush-vscode-extension/src/logic/RushCommandWebViewPanel.ts b/vscode-extensions/rush-vscode-extension/src/logic/RushCommandWebViewPanel.ts new file mode 100644 index 00000000000..5a66d982b5b --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/logic/RushCommandWebViewPanel.ts @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as vscode from 'vscode'; +import * as path from 'path'; +import { FileSystem } from '@rushstack/node-core-library'; + +import type { IFromExtensionMessage, IRootState } from '@rushstack/rush-vscode-command-webview'; + +export class RushCommandWebViewPanel { + private static _instance: RushCommandWebViewPanel | undefined; + private _panel: vscode.WebviewView | undefined; + private _webViewProvider: vscode.WebviewViewProvider | undefined; + private _context: vscode.ExtensionContext; + private _extensionPath: string; + private constructor(context: vscode.ExtensionContext) { + this._extensionPath = context.extensionPath; + this._context = context; + } + + public static getInstance(): RushCommandWebViewPanel { + if (!RushCommandWebViewPanel._instance) { + throw new Error('Instance has not been initialized!'); + } + + return RushCommandWebViewPanel._instance; + } + + public static initialize(context: vscode.ExtensionContext): RushCommandWebViewPanel { + if (RushCommandWebViewPanel._instance) { + throw new Error('Only one instance of rush command web view panel should be created!'); + } + RushCommandWebViewPanel._instance = new RushCommandWebViewPanel(context); + return RushCommandWebViewPanel._instance; + } + + public postMessage(message: IFromExtensionMessage): void { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this._panel?.webview.postMessage(message); + } + + public reveal(): void { + const state: IRootState = { + parameter: { + commandName: '', + parameters: [], + argsKV: {}, + searchText: '' + }, + ui: { + isToolbarSticky: false, + currentParameterName: '', + userSelectedParameterName: '' + }, + project: { + projectName: 'test project name', + projectVersion: '0' + } + }; + + const resolveWebviewView = ( + thisWebview: vscode.WebviewView, + thisWebviewContext: vscode.WebviewViewResolveContext, + thisToken: vscode.CancellationToken + ): void => { + this._panel = thisWebview; + + const message: IFromExtensionMessage = { + command: 'initialize', + state: state.project + }; + // eslint-disable-next-line no-console + console.log('message', message); + thisWebview.webview.options = { enableScripts: true }; + thisWebview.webview.html = this._getWebviewContent(); + // eslint-disable-next-line @typescript-eslint/no-floating-promises + thisWebview.webview.postMessage(message); + }; + + const provider: vscode.WebviewViewProvider = { + resolveWebviewView + }; + this._context.subscriptions.push( + vscode.window.registerWebviewViewProvider('rushProjectDetails', provider) + ); + + // const state: IRootState = { + // parameter: { + // commandName: '', + // parameters: [], + // argsKV: {}, + // searchText: '' + // }, + // ui: { + // isToolbarSticky: false, + // currentParameterName: '', + // userSelectedParameterName: '' + // }, + // project: { + // projectName: 'test project name' + // } + // }; + + // if (!this._panel) { + // this._panel = vscode.window.createWebviewPanel( + // 'rushCommandWebViewPanel', + // 'Run Rush Command', + // vscode.ViewColumn.Active, + // { + // enableScripts: true, + // retainContextWhenHidden: true + // } + // ); + // this._panel.onDidDispose(() => { + // this._panel = undefined; + // }); + // this._setWebviewContent(state); + // this._panel.webview.onDidReceiveMessage((message: IToExtensionMessage) => { + // switch (message.command) { + // case 'commandInfo': { + // // eslint-disable-next-line @typescript-eslint/no-floating-promises + // RushTaskProvider.getInstance().executeTask({ + // type: 'rush-command-line', + // displayName: `rush ${message.commandName}`, + // cwd: RushWorkspace.getCurrentInstance().workspaceRootPath, + // command: message.commandName, + // args: message.args + // }); + // break; + // } + // default: { + // const _command: never = message.command; + // // eslint-disable-next-line no-console + // console.error(`Unknown command: ${_command}`); + // break; + // } + // } + // }); + // } else { + // const message: IFromExtensionMessage = { + // command: 'initialize', + // state: { + // ...state.parameter, + // parameters: state.parameter.parameters + // } + // }; + // // eslint-disable-next-line no-console + // console.log('message', message); + // this._panel.reveal(); + // // eslint-disable-next-line @typescript-eslint/no-floating-promises + // this._panel.webview.postMessage(message); + // } + } + + private _setWebviewContent(state: IRootState): void { + if (!this._panel) { + return; + } + this._panel.webview.html = this._getWebviewContent(state); + } + + private _getWebviewContent(state: unknown = {}): string { + // eslint-disable-next-line no-console + console.log('loading rush command webview html and bundle'); + let html: string = FileSystem.readFile( + path.join(this._extensionPath, 'webview/rush-command-webview/index.html') + ); + const scriptSrc: vscode.Uri = this._panel!.webview.asWebviewUri( + vscode.Uri.file(path.join(this._extensionPath, 'webview/rush-command-webview/bundle.js')) + ); + + // replace bundled js with the correct path + html = html.replace('bundle.js', scriptSrc.toString()); + + // hydrate initial state + html = html.replace('window.__DATA__ = {};', `window.__DATA__ = ${JSON.stringify(state)};`); + return html; + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/logic/RushWorkspace.ts b/vscode-extensions/rush-vscode-extension/src/logic/RushWorkspace.ts new file mode 100644 index 00000000000..bbff82b77f2 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/logic/RushWorkspace.ts @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { RushSdkLoader, type ISdkCallbackEvent } from '@rushstack/rush-sdk/loader'; + +import * as vscode from 'vscode'; +import { terminal } from './logger'; + +import type { CommandLineAction } from '@rushstack/rush-vscode-command-webview'; +import type * as RushLib from '@rushstack/rush-sdk'; +import type * as RushCommandLine from '@rushstack/ts-command-line'; + +// eslint-disable-next-line @typescript-eslint/naming-convention +declare let ___DEV___: boolean; +declare const global: NodeJS.Global & + typeof globalThis & { + ___rush___rushLibModule?: typeof RushLib; + }; + +export interface IRushWorkspace { + rushLib: typeof RushLib; + startingFolder: string; +} + +export class RushWorkspace { + private _rushLib: typeof RushLib | undefined; + private _startingFolderPath: string; + private _rushConfiguration: RushLib.RushConfiguration; + private _rushCommandLineParser: RushCommandLine.CommandLineParser | undefined; + private static _rushWorkspace: RushWorkspace | undefined; + + private static readonly _onDidChangeWorkspace: vscode.EventEmitter = + new vscode.EventEmitter(); + public static readonly onDidChangeWorkspace: vscode.Event = + RushWorkspace._onDidChangeWorkspace.event; + + private constructor({ rushLib, startingFolder }: IRushWorkspace) { + this._rushLib = rushLib; + this._startingFolderPath = startingFolder; + const { RushConfiguration } = rushLib; + // existence check for API + if (!RushConfiguration) { + throw new Error('load RushConfiguration from rush-sdk failed'); + } + const rushConfiguration: RushLib.RushConfiguration | undefined = + RushConfiguration.loadFromDefaultLocation({ + startingFolder + }); + if (!rushConfiguration) { + throw new Error('RushConfiguration not found'); + } + terminal.writeDebugLine(`rushConfiguration loaded from: ${startingFolder}`); + this._rushConfiguration = rushConfiguration; + + // if (RushCommandLine) { + // this._rushCommandLineParser = new RushCommandLine({ + // cwd: startingFolder + // }); + // } else { + // terminal.writeWarningLine(`load RushCommandLineParser from rush-sdk failed`); + // } + + RushWorkspace._rushWorkspace = this; + RushWorkspace._onDidChangeWorkspace.fire(this); + } + + public static getCurrentInstance(): RushWorkspace { + if (!RushWorkspace._rushWorkspace) { + throw new Error('RushWorkspace not initialized'); + } + return RushWorkspace._rushWorkspace; + } + + public static async initializeFromWorkspaceFolderPathsAsync( + workspaceFolderPaths: string[] + ): Promise { + terminal.writeDebugLine(`initialize from workspaceFolderPaths: ${JSON.stringify(workspaceFolderPaths)}`); + + if (___DEV___) { + try { + terminal.writeLine('[DEV MODE] try to load @microsoft/rush-lib instead of @rushstack/rush-sdk'); + global.___rush___rushLibModule = (await import('@microsoft/rush-lib')) as unknown as typeof RushLib; + } catch (e) { + terminal.writeErrorLine(`Failed to load dev rush lib @microsoft/rush-lib`); + } + } + + terminal.writeDebugLine(`current workspaceFolderPaths: ${workspaceFolderPaths.join(',')}`); + + for (const folderPath of workspaceFolderPaths) { + let rushLib: typeof RushLib | undefined; + try { + if (!RushSdkLoader.isLoaded) { + await RushSdkLoader.loadAsync({ + rushJsonSearchFolder: folderPath, + onNotifyEvent: (event: ISdkCallbackEvent) => { + if (event.logMessage) { + terminal.writeDebugLine(event.logMessage.text); + } + } + }); + } + rushLib = await import('@rushstack/rush-sdk'); + + if (!rushLib) { + continue; + } + } catch (e) { + continue; + } + try { + return new RushWorkspace({ rushLib, startingFolder: folderPath }); + } catch (e) { + terminal.writeDebugLine(`Failed to initialize workspace from ${folderPath}: ${e}`); + continue; + } + } + terminal.writeWarningLine(`RushWorkspace has not been initialized from current workspace folders`); + return undefined; + } + + public static async selectWorkspaceAsync(): Promise { + const Uris: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({ + canSelectFolders: true, + canSelectFiles: false, + canSelectMany: false, + openLabel: 'Select workspace folder' + }); + if (Uris && Uris[0]) { + return await RushWorkspace.initializeFromWorkspaceFolderPathsAsync([Uris[0].fsPath]); + } + return undefined; + } + + public get rushConfiguration(): RushLib.RushConfiguration { + return this._rushConfiguration; + } + + public get workspaceRootPath(): string { + return this._rushConfiguration.rushJsonFolder; + } + + public get commandLineActions(): CommandLineAction[] { + return (this._rushCommandLineParser?.actions || []).slice() as unknown as CommandLineAction[]; + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/logic/logger.ts b/vscode-extensions/rush-vscode-extension/src/logic/logger.ts new file mode 100644 index 00000000000..cc281933961 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/logic/logger.ts @@ -0,0 +1,24 @@ +// 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'; + +const consoleTerminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); + +export const terminal: Terminal = new Terminal(consoleTerminalProvider); + +export type LogLevel = 'info' | 'debug'; + +export const setLogLevel = (level: LogLevel): void => { + switch (level) { + case 'debug': { + consoleTerminalProvider.debugEnabled = true; + break; + } + case 'info': + default: { + consoleTerminalProvider.debugEnabled = false; + break; + } + } +}; diff --git a/vscode-extensions/rush-vscode-extension/src/providers/RushCommandsProvider.ts b/vscode-extensions/rush-vscode-extension/src/providers/RushCommandsProvider.ts new file mode 100644 index 00000000000..faf0080814f --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/providers/RushCommandsProvider.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 * as vscode from 'vscode'; +import { terminal } from '../logic/logger'; +import { RushWorkspace } from '../logic/RushWorkspace'; + +import type { CommandLineAction } from '@rushstack/rush-vscode-command-webview'; + +interface IRushCommandParams { + label: string; + collapsibleState: vscode.TreeItemCollapsibleState; + commandLineAction: CommandLineAction; +} + +class RushCommand extends vscode.TreeItem { + // public readonly commandLineAction: CommandLineAction; + public constructor({ label, collapsibleState, commandLineAction }: IRushCommandParams) { + super(label, collapsibleState); + this.contextValue = 'rushCommand'; + // this.commandLineAction = commandLineAction; + this.command = { + title: 'Run Rush Command', + command: 'rushstack.rushCommands.runRushCommand', + arguments: [this] + }; + } +} + +export class RushCommandsProvider implements vscode.TreeDataProvider { + private _context: vscode.ExtensionContext; + private _commandLineActions: CommandLineAction[] | undefined; + private readonly _onDidChangeTreeData: vscode.EventEmitter = + new vscode.EventEmitter(); + + public readonly onDidChangeTreeData: vscode.Event = + this._onDidChangeTreeData.event; + + public constructor(context: vscode.ExtensionContext) { + this._context = context; + const rushWorkspace: RushWorkspace = RushWorkspace.getCurrentInstance(); + RushWorkspace.onDidChangeWorkspace((newWorkspace: RushWorkspace) => { + this._commandLineActions = newWorkspace.commandLineActions; + this.refresh(); + }); + this._commandLineActions = rushWorkspace.commandLineActions; + + const commandNames: readonly ['openParameterViewPanel', 'runRushCommand'] = [ + 'openParameterViewPanel', + 'runRushCommand' + ] as const; + + for (const commandName of commandNames) { + const handler: + | (() => Promise) + | ((element?: RushCommand) => Promise) + | ((element: RushCommand) => Promise) = this[`${commandName}Async`]; + context.subscriptions.push( + vscode.commands.registerCommand(`rushstack.rushCommands.${commandName}`, handler, this) + ); + } + } + + public refresh(): void { + terminal.writeDebugLine('Refreshing Rush commands'); + this._onDidChangeTreeData.fire(undefined); + } + + public async refreshEntryAsync(): Promise { + this.refresh(); + } + + public async openParameterViewPanelAsync(): Promise { + // return RushCommandWebViewPanel.getInstance(this._context).reveal(''); + } + + public async runRushCommandAsync(element?: RushCommand): Promise { + // const rushCommand: RushCommand | undefined = element; + await this.openParameterViewPanelAsync(); + // if (!rushCommand) { + // const actionNames: string[] = this._commandLineActions?.map((action) => action.actionName) || []; + // if (!actionNames.length) { + // terminal.writeErrorLine('No Rush commands available'); + // return; + // } + // const commandSelect: string | undefined = await vscode.window.showQuickPick(actionNames, { + // placeHolder: 'Select a Rush command to run', + // onDidSelectItem: (item) => { + // const foundAction: CommandLineAction | undefined = this._commandLineActions?.find( + // (action) => action.actionName === item + // ); + // if (foundAction) { + // rushCommand = new RushCommand({ + // label: foundAction.actionName, + // collapsibleState: vscode.TreeItemCollapsibleState.None, + // commandLineAction: foundAction + // }); + // } + // } + // }); + // terminal.writeDebugLine(`Selected command: ${commandSelect}`); + // } + + // if (!rushCommand) { + // return; + // } + // terminal.writeDebugLine(`Running command: ${rushCommand.label}`); + // await this.openParameterViewPanelAsync(rushCommand); + } + + public getTreeItem(element: vscode.TreeItem): vscode.TreeItem | Thenable { + return element; + } + + public getChildren(element?: vscode.TreeItem): Thenable { + // eslint-disable-next-line no-console + console.log('children: ', this._commandLineActions); + // eslint-disable-next-line no-console + console.log('element: ', element); + if (!this._commandLineActions) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.window.showInformationMessage('No RushProjects in empty workspace'); + return Promise.resolve([]); + } + + return Promise.resolve([ + { + label: 'Test label', + collapsibleState: vscode.TreeItemCollapsibleState.None + }, + { + label: 'Test label2', + collapsibleState: vscode.TreeItemCollapsibleState.None + }, + { + label: 'Test label3', + collapsibleState: vscode.TreeItemCollapsibleState.None + } + ]); + + // top-level + // if (!element) { + // return Promise.resolve( + // this._commandLineActions.map( + // (commandLineAction) => + // new RushCommand({ + // label: commandLineAction.actionName, + // collapsibleState: vscode.TreeItemCollapsibleState.None, + // commandLineAction + // }) + // ) + // ); + // } + + // return Promise.resolve([]); + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/providers/RushProjectsProvider.ts b/vscode-extensions/rush-vscode-extension/src/providers/RushProjectsProvider.ts new file mode 100644 index 00000000000..f1df1b8f240 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/providers/RushProjectsProvider.ts @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as vscode from 'vscode'; +import * as path from 'path'; +import { JsonFile, type JsonObject } from '@rushstack/node-core-library'; +import { RushTaskProvider } from './TaskProvider'; +import { terminal } from '../logic/logger'; +import { RushWorkspace } from '../logic/RushWorkspace'; + +import type { RushConfiguration, RushConfigurationProject } from '@rushstack/rush-sdk'; +import { RushCommandWebViewPanel } from '../logic/RushCommandWebViewPanel'; + +interface IRushProjectParams { + label: string; + collapsibleState: vscode.TreeItemCollapsibleState; + rushConfigurationProject: RushConfigurationProject; +} + +class RushProject extends vscode.TreeItem { + public readonly rushConfigurationProject: RushConfigurationProject; + public constructor({ label, rushConfigurationProject, collapsibleState }: IRushProjectParams) { + super(label, collapsibleState); + this.rushConfigurationProject = rushConfigurationProject; + this.contextValue = 'project'; + + // this.tooltip = ''; + // this.description = ''; + } +} + +interface IRushProjectScriptParams { + label: string; + collapsibleState: vscode.TreeItemCollapsibleState; + projectFolder: string; + projectRelativeFolder: string; + scriptName: string; + scriptValue: string; +} + +class RushProjectScript extends vscode.TreeItem { + public readonly projectFolder: string; + public readonly projectRelativeFolder: string; + public readonly scriptName: string; + public readonly scriptValue: string; + public constructor({ + label, + collapsibleState, + projectFolder, + projectRelativeFolder, + scriptName, + scriptValue + }: IRushProjectScriptParams) { + super(label, collapsibleState); + this.contextValue = 'projectScript'; + + this.projectFolder = projectFolder; + this.projectRelativeFolder = projectRelativeFolder; + this.scriptName = scriptName; + this.scriptValue = scriptValue; + + // this.tooltip = ''; + this.description = 'test description'; + } +} + +type RushProjectsTreeItem = RushProject | RushProjectScript; + +export class RushProjectsProvider implements vscode.TreeDataProvider { + private _rushConfiguration: RushConfiguration | undefined; + private readonly _onDidChangeTreeData: vscode.EventEmitter = + new vscode.EventEmitter(); + + public readonly onDidChangeTreeData: vscode.Event = + this._onDidChangeTreeData.event; + + public constructor(context: vscode.ExtensionContext) { + const rushWorkspace: RushWorkspace = RushWorkspace.getCurrentInstance(); + RushWorkspace.onDidChangeWorkspace((newWorkspace: RushWorkspace) => { + this._rushConfiguration = newWorkspace.rushConfiguration; + this.refresh(); + }); + this._rushConfiguration = rushWorkspace.rushConfiguration; + + const commandNames: readonly ['revealInExplorer', 'revealProjectDetail', 'runProjectScript'] = [ + 'revealInExplorer', + 'revealProjectDetail', + 'runProjectScript' + ] as const; + + for (const commandName of commandNames) { + const handler: + | ((element: RushProject) => Promise) + | ((element: RushProjectScript) => Promise) = this[`${commandName}Async`]; + context.subscriptions.push( + vscode.commands.registerCommand(`rushstack.rushProjects.${commandName}`, handler, this) + ); + } + } + + public refresh(): void { + terminal.writeDebugLine('Refreshing Rush projects'); + this._onDidChangeTreeData.fire(undefined); + } + + public async refreshEntryAsync(): Promise { + this.refresh(); + } + + public async revealInExplorerAsync(element: RushProject): Promise { + const projectFolder: string = element.rushConfigurationProject.projectFolder; + if (projectFolder) { + terminal.writeDebugLine(`Revealing ${projectFolder} in explorer`); + return await vscode.commands.executeCommand('revealInExplorer', vscode.Uri.file(projectFolder)); + } + } + + public async revealProjectDetailAsync(element: RushProject): Promise { + const { rushConfigurationProject } = element; + // eslint-disable-next-line no-console + console.log('Explorer clicked: ', rushConfigurationProject.packageName); + RushCommandWebViewPanel.getInstance().postMessage({ + command: 'updateProject', + state: { + projectName: rushConfigurationProject.packageName, + projectVersion: rushConfigurationProject.packageJson.version, + dependencies: rushConfigurationProject.packageJson.dependencies, + devDependencies: rushConfigurationProject.packageJson.devDependencies + } + }); + } + + public async runProjectScriptAsync(element: RushProjectScript): Promise { + if (element.projectFolder) { + const { projectFolder, projectRelativeFolder, scriptName } = element; + await RushTaskProvider.getInstance().executeTaskAsync({ + type: 'rush-project-script', + cwd: projectFolder, + displayName: `${scriptName} - ${projectRelativeFolder}`, + command: scriptName + }); + } + } + + public getTreeItem(element: RushProject | RushProjectScript): vscode.TreeItem { + return element; + } + + public getChildren( + element?: RushProject | RushProjectScript + ): Thenable { + if (!this._rushConfiguration) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.window.showInformationMessage('No RushProjects in empty workspace'); + return Promise.resolve([]); + } + + // top-level + if (!element) { + const rushProjectTreeItems: RushProject[] = this._rushConfiguration.projects.map( + (project: RushConfigurationProject) => + new RushProject({ + label: project.packageName, + rushConfigurationProject: project, + collapsibleState: vscode.TreeItemCollapsibleState.Collapsed + }) + ); + return Promise.resolve(rushProjectTreeItems); + } + + if (element instanceof RushProject) { + try { + const projectFolder: string = element.rushConfigurationProject.projectFolder; + const projectRelativeFolder: string = element.rushConfigurationProject.projectRelativeFolder; + const packageJson: JsonObject = JsonFile.load(path.join(projectFolder, 'package.json')); + const rushProjectScriptTreeItems: RushProjectScript[] = Object.keys(packageJson.scripts).map( + (scriptName) => + new RushProjectScript({ + label: scriptName, + collapsibleState: vscode.TreeItemCollapsibleState.None, + projectFolder, + projectRelativeFolder, + scriptName, + scriptValue: packageJson.scripts[scriptName] + }) + ); + return Promise.resolve(rushProjectScriptTreeItems); + } catch { + return Promise.resolve([]); + } + } + + return Promise.resolve([]); + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/providers/TaskProvider.ts b/vscode-extensions/rush-vscode-extension/src/providers/TaskProvider.ts new file mode 100644 index 00000000000..fc96d2ffe1a --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/providers/TaskProvider.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 * as vscode from 'vscode'; +import { terminal } from '../logic/logger'; + +let rushTaskProvider: RushTaskProvider | undefined; + +export type IRushTaskDefinition = IProjectScriptTaskDefinition | IRushCommandLineTaskDefinition; + +export interface IProjectScriptTaskDefinition extends vscode.TaskDefinition { + type: 'rush-project-script'; + + cwd: string; + command: string; + displayName: string; +} + +export interface IRushCommandLineTaskDefinition extends vscode.TaskDefinition { + type: 'rush-command-line'; + + cwd: string; + command: string; + displayName: string; + args: string[]; +} + +export class RushTaskProvider implements vscode.TaskProvider { + private constructor() {} + + public static getInstance(): RushTaskProvider { + if (!rushTaskProvider) { + rushTaskProvider = new RushTaskProvider(); + } + + return rushTaskProvider; + } + + public provideTasks(token: vscode.CancellationToken): vscode.ProviderResult { + return null; + } + + public resolveTask(task: vscode.Task, token: vscode.CancellationToken): vscode.ProviderResult { + terminal.writeDebugLine(`resolveTask: ${task.definition.type}`); + return task; + } + + public async executeTaskAsync(definition: T): Promise { + let task: vscode.Task | undefined; + // problem matchers are defined in extension manifest + const problemMatchers: string[] = ['$rushstack-file-error-unix', '$rushstack-file-error-visualstudio']; + switch (definition.type) { + case 'rush-project-script': { + const { cwd, displayName, command } = definition; + const taskDefinition: vscode.TaskDefinition = { + ...definition, + type: 'rushx', + cwd + }; + task = new vscode.Task( + taskDefinition, + vscode.TaskScope.Workspace, + displayName, + 'rushx', + new vscode.ShellExecution(`rushx ${command}`, { + cwd + }), + problemMatchers + ); + break; + } + case 'rush-command-line': { + const { cwd, displayName, command, args } = definition; + const taskDefinition: vscode.TaskDefinition = { + ...definition, + type: 'rush', + cwd + }; + task = new vscode.Task( + taskDefinition, + vscode.TaskScope.Workspace, + displayName, + 'rush', + new vscode.ShellExecution(`rush ${command} ${args.join(' ')}`, { + cwd + }), + problemMatchers + ); + break; + } + default: { + const _def: never = definition; + terminal.writeLine(`Unknown executeTask: ${(_def as unknown as { type: string }).type}`); + } + } + if (task) { + await vscode.tasks.executeTask(task); + } + } +} diff --git a/vscode-extensions/rush-vscode-extension/src/test/runTest.ts b/vscode-extensions/rush-vscode-extension/src/test/runTest.ts new file mode 100644 index 00000000000..80f8cb2b5af --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/test/runTest.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 * as path from 'path'; + +import { runTests } from '@vscode/test-electron'; + +async function main(): Promise { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath: string = path.resolve(__dirname, '../../'); + + // The path to test runner + // Passed to --extensionTestsPath + const extensionTestsPath: string = path.resolve(__dirname, './suite/index'); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Failed to run tests'); + process.exit(1); + } +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +main(); diff --git a/vscode-extensions/rush-vscode-extension/src/test/suite/extension.test.ts b/vscode-extensions/rush-vscode-extension/src/test/suite/extension.test.ts new file mode 100644 index 00000000000..4cd31bc277f --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/test/suite/extension.test.ts @@ -0,0 +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 assert from 'assert'; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from 'vscode'; +// import * as myExtension from '../../extension'; + +suite('Extension Test Suite', () => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.window.showInformationMessage('Start all tests.'); + + test('Sample test', () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); +}); diff --git a/vscode-extensions/rush-vscode-extension/src/test/suite/index.ts b/vscode-extensions/rush-vscode-extension/src/test/suite/index.ts new file mode 100644 index 00000000000..a4527237b66 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/src/test/suite/index.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 'path'; +import Mocha from 'mocha'; +import glob from 'glob'; + +export function run(): Promise { + // Create the mocha test + const mocha: Mocha = new Mocha({ + ui: 'tdd', + color: true + }); + + const testsRoot: string = path.resolve(__dirname, '..'); + + return new Promise((resolve, reject) => { + glob('**/**.test.js', { cwd: testsRoot }, (err1, files) => { + if (err1) { + return reject(err1); + } + + // Add files to the test suite + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.run((failures) => { + if (failures > 0) { + reject(new Error(`${failures} tests failed.`)); + } else { + resolve(); + } + }); + } catch (err2) { + // eslint-disable-next-line no-console + console.error(err2); + reject(err2); + } + }); + }); +} diff --git a/vscode-extensions/rush-vscode-extension/tsconfig.json b/vscode-extensions/rush-vscode-extension/tsconfig.json new file mode 100644 index 00000000000..1226387ecf8 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-vscode-extension-rig/profiles/default/tsconfig-base.json" +} diff --git a/vscode-extensions/rush-vscode-extension/webpack.config.js b/vscode-extensions/rush-vscode-extension/webpack.config.js new file mode 100644 index 00000000000..54f783e08c3 --- /dev/null +++ b/vscode-extensions/rush-vscode-extension/webpack.config.js @@ -0,0 +1,29 @@ +// @ts-check +/* eslint-env es6 */ + +'use strict'; + +const { + createExtensionConfig +} = require('@rushstack/heft-vscode-extension-rig/profiles/default/webpack.config.base'); +const path = require('node:path'); + +function createConfig({ production, webpack }) { + const config = createExtensionConfig({ + production, + webpack, + entry: { + extension: './lib/extension.js' + }, + outputPath: path.resolve(__dirname, 'dist', 'vsix', 'unpacked') + }); + + if (!config.externals) { + config.externals = {}; + } + config.externals['@microsoft/rush-lib'] = 'commonjs @microsoft/rush-lib'; + + return config; +} + +module.exports = createConfig; diff --git a/vscode-extensions/vscode-shared/.npmignore b/vscode-extensions/vscode-shared/.npmignore new file mode 100644 index 00000000000..dcf329e5ffa --- /dev/null +++ b/vscode-extensions/vscode-shared/.npmignore @@ -0,0 +1,2 @@ +# Ignore all files by default, to avoid accidentally publishing unintended files. +** diff --git a/vscode-extensions/vscode-shared/LICENSE b/vscode-extensions/vscode-shared/LICENSE new file mode 100644 index 00000000000..a29fce499b9 --- /dev/null +++ b/vscode-extensions/vscode-shared/LICENSE @@ -0,0 +1,24 @@ +@rushstack/vscode-shared + +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/vscode-extensions/vscode-shared/README.md b/vscode-extensions/vscode-shared/README.md new file mode 100644 index 00000000000..1adc0a9c7aa --- /dev/null +++ b/vscode-extensions/vscode-shared/README.md @@ -0,0 +1,3 @@ +# @rushstack/vscode-shared + +This library provides a set of utilities for VS Code extensions. diff --git a/vscode-extensions/vscode-shared/config/rig.json b/vscode-extensions/vscode-shared/config/rig.json new file mode 100644 index 00000000000..58032e098f0 --- /dev/null +++ b/vscode-extensions/vscode-shared/config/rig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "@rushstack/heft-node-rig" +} diff --git a/vscode-extensions/vscode-shared/eslint.config.js b/vscode-extensions/vscode-shared/eslint.config.js new file mode 100644 index 00000000000..006cb82d1c0 --- /dev/null +++ b/vscode-extensions/vscode-shared/eslint.config.js @@ -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. + +const nodeTrustedToolProfile = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('@rushstack/heft-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [...nodeTrustedToolProfile, ...friendlyLocalsMixin]; diff --git a/vscode-extensions/vscode-shared/package.json b/vscode-extensions/vscode-shared/package.json new file mode 100644 index 00000000000..afc7acdb9fd --- /dev/null +++ b/vscode-extensions/vscode-shared/package.json @@ -0,0 +1,28 @@ +{ + "name": "@rushstack/vscode-shared", + "version": "0.0.0", + "description": "", + "main": "lib/index.js", + "typings": "dist/index.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "vscode-extensions/vscode-shared" + }, + "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:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft-node-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/vscode": "1.103.0" + } +} diff --git a/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.ts b/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.ts new file mode 100644 index 00000000000..6fc6cc2e605 --- /dev/null +++ b/vscode-extensions/vscode-shared/src/VScodeOutputChannelTerminalProvider.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 { Text } from '@rushstack/node-core-library'; +import type { ITerminalProvider, TerminalProviderSeverity } from '@rushstack/terminal'; +import type * as vscode from 'vscode'; + +/** + * Options to be provided to a {@link VScodeOutputChannelTerminalProvider} + * + * @beta + */ +export interface IVScodeOutputChannelTerminalProviderOptions { + /** + * If true, print verbose logging messages. + */ + verboseEnabled: boolean; + + /** + * If true, print debug logging messages. Note that "verbose" and "debug" are considered + * separate message filters; if you want debug to imply verbose, it is up to your + * application code to enforce that. + */ + debugEnabled: boolean; +} + +/** + * Terminal provider that prints to STDOUT (for log- and verbose-level messages) and + * STDERR (for warning- and error-level messages). + * + * @beta + */ +export class VScodeOutputChannelTerminalProvider implements ITerminalProvider { + private readonly _outputChannel: vscode.OutputChannel; + public static readonly supportsColor: boolean = false; + + /** + * If true, verbose-level messages should be written to the console. + */ + public verboseEnabled: boolean; + + /** + * If true, debug-level messages should be written to the console. + */ + public debugEnabled: boolean; + + /** + * {@inheritDoc ITerminalProvider.supportsColor} + */ + public readonly supportsColor: boolean = VScodeOutputChannelTerminalProvider.supportsColor; + + public constructor( + outputChannel: vscode.OutputChannel, + options: Partial = {} + ) { + this.verboseEnabled = !!options.verboseEnabled; + this.debugEnabled = !!options.debugEnabled; + this._outputChannel = outputChannel; + } + + /** + * {@inheritDoc ITerminalProvider.write} + */ + public write(data: string, severity: TerminalProviderSeverity): void { + const outputChannel: vscode.OutputChannel = this._outputChannel; + for (const line of Text.readLinesFromIterable(data)) { + outputChannel.appendLine(line); + } + } + + /** + * {@inheritDoc ITerminalProvider.eolCharacter} + */ + public get eolCharacter(): string { + return '\n'; + } +} diff --git a/vscode-extensions/vscode-shared/tsconfig.json b/vscode-extensions/vscode-shared/tsconfig.json new file mode 100644 index 00000000000..a114c3448ed --- /dev/null +++ b/vscode-extensions/vscode-shared/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/hashed-folder-copy-plugin/.npmignore b/webpack/hashed-folder-copy-plugin/.npmignore new file mode 100644 index 00000000000..814dbc9e741 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/.npmignore @@ -0,0 +1,25 @@ +# Ignore everything by default +** + +# Use negative patterns to bring back the specific things we want to publish +!/bin/** +!/lib/** +!/dist/** +!ThirdPartyNotice.txt +!/EULA/** + +# Ignore certain files in the above folder +/dist/*.stats.* +/lib/**/test/** +/lib/**/*.js.map +/dist/**/*.js.map + +# 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 + +## Project specific definitions +# ----------------------------- diff --git a/webpack/hashed-folder-copy-plugin/CHANGELOG.json b/webpack/hashed-folder-copy-plugin/CHANGELOG.json new file mode 100644 index 00000000000..e16e020298e --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/CHANGELOG.json @@ -0,0 +1,3913 @@ +{ + "name": "@rushstack/hashed-folder-copy-plugin", + "entries": [ + { + "version": "1.2.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.2.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.2.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.2.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.2.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.2.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.2.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": "1.1.21", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.21", + "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": "1.1.20", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.20", + "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": "1.1.19", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.19", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.18", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.17", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.16", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.15", + "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": "1.1.14", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.14", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.13", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.12", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.11", + "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": "1.1.10", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.10", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.9", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.8", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.7", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.6", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.5", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.4", + "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": "1.1.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.3", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.2", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing `./package.json` export." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.1", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "patch": [ + { + "comment": "Re-include the `main` and `typings` `package.json` fields." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.1.0", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "minor": [ + { + "comment": "Move the `ambientTypes.d.ts` file to `dist` and use the `exports` and `typesVersions` fields in `package.json` to maintain `@rushstack/hashed-folder-copy-plugin/ambientTypes` references." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "1.0.80", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.80", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "1.0.79", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.79", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "1.0.78", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.78", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "1.0.77", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.77", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "1.0.76", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.76", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "1.0.75", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.75", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "1.0.74", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.74", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "1.0.73", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.73", + "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": "1.0.72", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.72", + "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": "1.0.71", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.71", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "1.0.70", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.70", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "1.0.69", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.69", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "1.0.68", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.68", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "1.0.67", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.67", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "1.0.66", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.66", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "1.0.65", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.65", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "1.0.64", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.64", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "1.0.63", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.63", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "1.0.62", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.62", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "1.0.61", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.61", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "1.0.60", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.60", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "1.0.59", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.59", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "1.0.58", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.58", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "1.0.57", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.57", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "1.0.56", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.56", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "1.0.55", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.55", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "1.0.54", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.54", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "1.0.53", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.53", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "1.0.52", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.52", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "1.0.51", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.51", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "1.0.50", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.50", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "1.0.49", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.49", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "1.0.48", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.48", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "1.0.47", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.47", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "1.0.46", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.46", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "1.0.45", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.45", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "1.0.44", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.44", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "1.0.43", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.43", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "1.0.42", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.42", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "1.0.41", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.41", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "1.0.40", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.40", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "1.0.39", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.39", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "1.0.38", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.38", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "1.0.37", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.37", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "1.0.36", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.36", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "1.0.35", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.35", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "1.0.34", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.34", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "1.0.33", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.33", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "1.0.32", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.32", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "1.0.31", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.31", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "1.0.30", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.30", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "1.0.29", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.29", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "1.0.28", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.28", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "1.0.27", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.27", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "1.0.26", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.26", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "1.0.25", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.25", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "1.0.24", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.24", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "1.0.23", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.23", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.22", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.21", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.20", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.19", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.18", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.17", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.16", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.15", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.14", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.13", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.12", + "date": "Thu, 25 Jan 2024 23:03:57 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where builds running on Windows and not on the C drive would not discover assets." + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.11", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.10", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.9", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.8", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade build dependencies" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.7", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.6", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.5", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.4", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.3", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.2", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.1", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where globbing assets from a NPM package would fail on Windows." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v1.0.0", + "date": "Tue, 24 Oct 2023 04:04:22 GMT", + "comments": { + "major": [ + { + "comment": "Add support for Webpack 5 and drop support for Webpack 4." + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.2.46", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.46", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "0.2.45", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.45", + "date": "Thu, 07 Sep 2023 03:35:42 GMT", + "comments": { + "patch": [ + { + "comment": "Update Webpack peerDependency to ~4.47.0." + } + ] + } + }, + { + "version": "0.2.44", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.44", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + } + ] + } + }, + { + "version": "0.2.43", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.43", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "patch": [ + { + "comment": "Switch from glob to fast-glob." + } + ] + } + }, + { + "version": "0.2.42", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.42", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + } + ] + } + }, + { + "version": "0.2.41", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.41", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + } + ] + } + }, + { + "version": "0.2.40", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.40", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + } + ] + } + }, + { + "version": "0.2.39", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.39", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.38", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.37", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.36", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.35", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.34", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.33", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.32", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.31", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.30", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.29", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.28", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.27", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.26", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.25", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.24", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.23", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.22", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.21", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.20", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.19", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.18", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.17", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.12`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.16", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.11`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.15", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.10`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.14", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.9`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.13", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.8`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.12", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.7`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.11", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.6`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.10", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.9", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.8", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.3`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.7", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.6", + "date": "Thu, 23 Mar 2023 15:24:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.5", + "date": "Wed, 22 Mar 2023 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.4", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.3", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.2", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.56`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.73`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.72`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.2.0", + "date": "Wed, 01 Feb 2023 16:23:04 GMT", + "comments": { + "minor": [ + { + "comment": "Apply webpack's \"output.hashSalt\" configuration property (if present) to the folder hash." + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.58", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.71`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.57", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.70`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.56", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.69`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.55", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.68`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.54", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.67`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.53", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.66`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.52", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.65`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.51", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.64`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.50", + "date": "Fri, 02 Dec 2022 01:15:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.63`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.49", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.62`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.48", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.61`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.47", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.60`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.46", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.59`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.45", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.58`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.44", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.57`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.43", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.56`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.42", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.55`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.41", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.54`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.40", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.53`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.39", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.52`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.38", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.51`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.37", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.50`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.36", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.49`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.35", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.48`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.34", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.47`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.33", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.46`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.32", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.45`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.31", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.44`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.30", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.43`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.29", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.42`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.28", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.41`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.27", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.40`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.26", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.39`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.25", + "date": "Thu, 04 Aug 2022 00:56:57 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the plugin will throw if the folder being required contains subfolders." + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.24", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.38`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.23", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.37`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.22", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.36`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.21", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.35`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.20", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.34`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.19", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.33`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.18", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.32`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.17", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.31`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.16", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.30`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.15", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.29`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.14", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.28`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.13", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.27`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.12", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.26`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.11", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.25`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.10", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.24`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.9", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.23`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.8", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Bump @types/webpack" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.22`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.7", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.21`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.6", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.20`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.5", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.19`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.4", + "date": "Wed, 18 May 2022 15:10:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.18`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.3", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.17`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.2", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.16`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.1", + "date": "Mon, 09 May 2022 15:13:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a link in the README." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/hashed-folder-copy-plugin_v0.1.0", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "minor": [ + { + "comment": "Initial project publish." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.15`" + } + ] + } + } + ] +} diff --git a/webpack/hashed-folder-copy-plugin/CHANGELOG.md b/webpack/hashed-folder-copy-plugin/CHANGELOG.md new file mode 100644 index 00000000000..dede52201d2 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/CHANGELOG.md @@ -0,0 +1,1177 @@ +# Change Log - @rushstack/hashed-folder-copy-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 1.2.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.2.6 +Fri, 21 Nov 2025 16:13:56 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:15 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 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.2.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.1.21 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 1.1.20 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 1.1.19 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 1.1.18 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 1.1.17 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 1.1.16 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 1.1.15 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 1.1.14 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 1.1.13 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 1.1.12 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 1.1.11 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 1.1.10 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 1.1.9 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 1.1.8 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 1.1.7 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 1.1.6 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 1.1.5 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 1.1.4 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 1.1.3 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 1.1.2 +Wed, 12 Mar 2025 00:11:31 GMT + +### Patches + +- Add missing `./package.json` export. + +## 1.1.1 +Tue, 11 Mar 2025 02:12:33 GMT + +### Patches + +- Re-include the `main` and `typings` `package.json` fields. + +## 1.1.0 +Tue, 11 Mar 2025 00:11:25 GMT + +### Minor changes + +- Move the `ambientTypes.d.ts` file to `dist` and use the `exports` and `typesVersions` fields in `package.json` to maintain `@rushstack/hashed-folder-copy-plugin/ambientTypes` references. + +## 1.0.80 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 1.0.79 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 1.0.78 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 1.0.77 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 1.0.76 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 1.0.75 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 1.0.74 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 1.0.73 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 1.0.72 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 1.0.71 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 1.0.70 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 1.0.69 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 1.0.68 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 1.0.67 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 1.0.66 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 1.0.65 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 1.0.64 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 1.0.63 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 1.0.62 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 1.0.61 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 1.0.60 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 1.0.59 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 1.0.58 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 1.0.57 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 1.0.56 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 1.0.55 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 1.0.54 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 1.0.53 +Sat, 27 Jul 2024 00:10:27 GMT + +_Version update only_ + +## 1.0.52 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 1.0.51 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 1.0.50 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 1.0.49 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 1.0.48 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 1.0.47 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 1.0.46 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 1.0.45 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 1.0.44 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 1.0.43 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 1.0.42 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 1.0.41 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 1.0.40 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 1.0.39 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 1.0.38 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 1.0.37 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 1.0.36 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 1.0.35 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 1.0.34 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 1.0.33 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 1.0.32 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 1.0.31 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 1.0.30 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 1.0.29 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 1.0.28 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 1.0.27 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 1.0.26 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 1.0.25 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 1.0.24 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 1.0.23 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 1.0.22 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 1.0.21 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 1.0.20 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 1.0.19 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 1.0.18 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 1.0.17 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 1.0.16 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 1.0.15 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 1.0.14 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 1.0.13 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 1.0.12 +Thu, 25 Jan 2024 23:03:57 GMT + +### Patches + +- Fix an issue where builds running on Windows and not on the C drive would not discover assets. + +## 1.0.11 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 1.0.10 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 1.0.9 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 1.0.8 +Tue, 16 Jan 2024 18:30:10 GMT + +### Patches + +- Upgrade build dependencies + +## 1.0.7 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 1.0.6 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 1.0.5 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 1.0.4 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 1.0.3 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 1.0.2 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 1.0.1 +Mon, 30 Oct 2023 23:36:37 GMT + +### Patches + +- Fix an issue where globbing assets from a NPM package would fail on Windows. + +## 1.0.0 +Tue, 24 Oct 2023 04:04:22 GMT + +### Breaking changes + +- Add support for Webpack 5 and drop support for Webpack 4. + +## 0.3.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.3.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.3.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.3.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.3.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.3.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.3.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.3.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.3.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.2.46 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.2.45 +Thu, 07 Sep 2023 03:35:42 GMT + +### Patches + +- Update Webpack peerDependency to ~4.47.0. + +## 0.2.44 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.2.43 +Fri, 04 Aug 2023 00:22:37 GMT + +### Patches + +- Switch from glob to fast-glob. + +## 0.2.42 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.2.41 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.2.40 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.2.39 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.2.38 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.2.37 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.2.36 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.2.35 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.2.34 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.2.33 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.2.32 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.2.31 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.2.30 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.2.29 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.2.28 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.2.27 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.2.26 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.2.25 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.2.24 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.2.23 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.2.22 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.2.21 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.2.20 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.2.19 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.2.18 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 0.2.17 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.16 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.2.15 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.2.14 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.2.13 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.2.12 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 0.2.11 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.2.10 +Thu, 20 Apr 2023 15:16:55 GMT + +_Version update only_ + +## 0.2.9 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 0.2.8 +Fri, 07 Apr 2023 22:19:21 GMT + +_Version update only_ + +## 0.2.7 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.2.6 +Thu, 23 Mar 2023 15:24:08 GMT + +_Version update only_ + +## 0.2.5 +Wed, 22 Mar 2023 20:48:30 GMT + +_Version update only_ + +## 0.2.4 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.2.3 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 0.2.2 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.2.1 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.2.0 +Wed, 01 Feb 2023 16:23:04 GMT + +### Minor changes + +- Apply webpack's "output.hashSalt" configuration property (if present) to the folder hash. + +## 0.1.58 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.1.57 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.56 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.55 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.1.54 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.1.53 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.52 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.51 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.50 +Fri, 02 Dec 2022 01:15:41 GMT + +_Version update only_ + +## 0.1.49 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.48 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.47 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.46 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 0.1.45 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.44 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.43 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.42 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.41 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.40 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.39 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.38 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.37 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.36 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 0.1.35 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.34 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.33 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.32 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.31 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.30 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.29 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.28 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 0.1.27 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.26 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.25 +Thu, 04 Aug 2022 00:56:57 GMT + +### Patches + +- Fix an issue where the plugin will throw if the folder being required contains subfolders. + +## 0.1.24 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.23 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.22 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.21 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.20 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.19 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 0.1.18 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.17 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.16 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 0.1.15 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.14 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.13 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.12 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.11 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.10 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 0.1.9 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.8 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Bump @types/webpack + +## 0.1.7 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.6 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.1.5 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.1.4 +Wed, 18 May 2022 15:10:55 GMT + +_Version update only_ + +## 0.1.3 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.1.2 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.1.1 +Mon, 09 May 2022 15:13:37 GMT + +### Patches + +- Fix a link in the README. + +## 0.1.0 +Fri, 06 May 2022 18:54:42 GMT + +### Minor changes + +- Initial project publish. + diff --git a/webpack/hashed-folder-copy-plugin/LICENSE b/webpack/hashed-folder-copy-plugin/LICENSE new file mode 100644 index 00000000000..a770bc0a0ba --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/hashed-folder-copy-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/webpack/hashed-folder-copy-plugin/README.md b/webpack/hashed-folder-copy-plugin/README.md new file mode 100644 index 00000000000..953f7048059 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/README.md @@ -0,0 +1,94 @@ +# @rushstack/hashed-folder-copy-plugin + +## Installation + +`npm install @rushstack/hashed-folder-copy-plugin --save-dev` + +## Overview + +This webpack plugin provides a simple method for copying a folder to the build output +and including a hash in the folder's name, accessible to the bundle's runtime. + +## Usage + +In your Webpack config, include the plugin in your `plugins` array: + +```JavaScript +import { HashedFolderCopyPlugin } from '@rushstack/hashed-folder-copy-plugin'; + +{ + plugins: [ + new HashedFolderCopyPlugin() + ] +} +``` + +and call the `requireFolder` function in your webpack bundle: + +```JavaScript +const folderUrl = requireFolder({ + outputFolder: 'my-folder-name_[hash]', + sources: [ + { + globsBase: '../assets/', + globs: ['**/*.png'] + } + ] +}) +``` + +TypeScript typings are provided for the `requireFolder` function: + +```TypeScript +import type { IRequireFolderOptions } from '@rushstack/hashed-folder-copy-plugin'; + +declare function requireFolder(options: IRequireFolderOptions): string; + +const folderUrl: string = requireFolder({ + outputFolder: 'my-folder-name_[hash]', + sources: [ + { + globsBase: '../assets/', + globPatterns: ['**/*.png'] + } + ] +}) +``` + +The `requireFolder` takes an options object with two properties: + +## `outputFolder` + +This is the name of the folder to be created in the webpack output folder. Its +name supports a `[hash]` token, which will be replaced with a stable hash of the assets +that are copied to the folder. Note that the `[hash]` token is not required. + +## `sources` + +This is an array of glob base paths and glob patterns that will be copied to the +output folder. Each entry in this array takes a `globsBase` property, which is the +base path to the folder to be copied, and a `globPatterns` property, which is an array of +glob patterns to be evaluated under the `globsBase` folder. The path in `globsBase` +supports standard Node resolution. + +# Example project + +See the [example project](https://github.com/microsoft/rushstack/blob/master/build-tests/hashed-folder-copy-plugin-webpack4-test/). + +# A note about ambient types + +To get the `requireFolder` function type to work in TypeScript, include a reference to +`"@rushstack/hashed-folder-copy-plugin/ambientTypes"` in your `tsconfig.json` file's +`compilerOptions.types` property. For example: + +```JSON +{ + "compilerOptions": { + "types": [ + "webpack-env", + "@rushstack/hashed-folder-copy-plugin/ambientTypes" // This value, specifically + ] + } +} + +``` diff --git a/webpack/hashed-folder-copy-plugin/config/api-extractor.json b/webpack/hashed-folder-copy-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/hashed-folder-copy-plugin/config/heft.json b/webpack/hashed-folder-copy-plugin/config/heft.json new file mode 100644 index 00000000000..8e62ffe9487 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/config/heft.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [ + { + "includeGlobs": [ + // TODO: Remove eventually. This file used to be created, but isn't anymore. + // However, it may still exist on some local clones. + "ambientTypes.d.ts" + ] + } + ], + + "tasksByName": { + "copy-ambient-types": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "./src", + "includeGlobs": ["ambientTypes.d.ts"], + "destinationFolders": ["dist"] + } + ] + } + } + }, + "copy-test-assets": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "./src/test/scenarios/", + "includeGlobs": ["**/*"], + "destinationFolders": ["lib/test/scenarios"] + } + ] + } + } + } + } + } + } +} diff --git a/webpack/hashed-folder-copy-plugin/config/jest.config.json b/webpack/hashed-folder-copy-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/hashed-folder-copy-plugin/config/rig.json b/webpack/hashed-folder-copy-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/hashed-folder-copy-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/webpack/hashed-folder-copy-plugin/eslint.config.js b/webpack/hashed-folder-copy-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/hashed-folder-copy-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/webpack/hashed-folder-copy-plugin/package.json b/webpack/hashed-folder-copy-plugin/package.json new file mode 100644 index 00000000000..e01704d62c2 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/package.json @@ -0,0 +1,57 @@ +{ + "name": "@rushstack/hashed-folder-copy-plugin", + "version": "1.2.7", + "description": "Webpack plugin for copying a folder to the output directory with a hash in the folder name.", + "typings": "dist/hashed-folder-copy-plugin.d.ts", + "main": "lib/index.js", + "exports": { + ".": { + "types": "./dist/hashed-folder-copy-plugin.d.ts", + "default": "./lib/index.js" + }, + "./ambientTypes": { + "types": "./dist/ambientTypes.d.ts" + }, + "./lib/*": { + "types": "./lib/*.d.ts", + "default": "./lib/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + ".": [ + "./dist/hashed-folder-copy-plugin.d.ts" + ], + "ambientTypes": [ + "./dist/ambientTypes.d.ts" + ] + } + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/hashed-folder-copy-plugin" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "webpack": "^5.68.0" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "fast-glob": "~3.3.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/estree": "1.0.6", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" + } +} diff --git a/webpack/hashed-folder-copy-plugin/src/HashedFolderCopyPlugin.ts b/webpack/hashed-folder-copy-plugin/src/HashedFolderCopyPlugin.ts new file mode 100644 index 00000000000..c69bf568dcd --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/HashedFolderCopyPlugin.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 type { CallExpression, Expression, UnaryExpression } from 'estree'; +import type webpack from 'webpack'; +import type glob from 'fast-glob'; + +import { Async } from '@rushstack/node-core-library'; + +import { + type IHashedFolderDependency, + getHashedFolderDependencyForWebpackInstance +} from './HashedFolderDependency'; +import type { BasicEvaluatedExpression } from './webpackTypes'; + +interface IParserHelpers { + evaluateToString: (type: string) => (exp: UnaryExpression) => BasicEvaluatedExpression; + toConstantDependency: (parser: webpack.Parser, type: string) => (exp: Expression) => true; +} + +// TODO: Use the compiler's webpack exports instead of requiring from webpack +const ParserHelpers: IParserHelpers = require('webpack/lib/javascript/JavascriptParserHelpers'); + +const PLUGIN_NAME: 'hashed-folder-copy-plugin' = 'hashed-folder-copy-plugin'; + +const EXPRESSION_NAME: 'requireFolder' = 'requireFolder'; + +interface IAcornNode { + computed: boolean | undefined; + elements: IAcornNode[]; + key: IAcornNode | undefined; + name: string | undefined; + properties: IAcornNode[] | undefined; + type: 'Literal' | 'ObjectExpression' | 'Identifier' | 'ArrayExpression' | unknown; + value: TExpression; +} + +export function renderError(errorMessage: string): string { + return `(function () { throw new Error(${JSON.stringify(errorMessage)}); })()`; +} + +/** + * @public + */ +export class HashedFolderCopyPlugin implements webpack.WebpackPluginInstance { + public apply(compiler: webpack.Compiler): void { + const webpack: typeof import('webpack') = compiler.webpack; + const { HashedFolderDependency, HashedFolderDependencyTemplate } = + getHashedFolderDependencyForWebpackInstance(webpack); + + compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: webpack.Compilation) => { + compilation.dependencyTemplates.set(HashedFolderDependency, new HashedFolderDependencyTemplate()); + }); + + const hashedFolderDependencies: IHashedFolderDependency[] = []; + + compiler.hooks.thisCompilation.tap( + PLUGIN_NAME, + (compilation: webpack.Compilation, { normalModuleFactory }) => { + compilation.hooks.finishModules.tapPromise(PLUGIN_NAME, async () => { + const { inputFileSystem } = compiler; + + const notImplementedFunction: () => never = () => { + throw new Error('Not implemented'); + }; + const globFs: glob.FileSystemAdapter = { + lstat: inputFileSystem?.lstat?.bind(inputFileSystem) ?? notImplementedFunction, + stat: inputFileSystem?.stat?.bind(inputFileSystem) ?? notImplementedFunction, + lstatSync: notImplementedFunction, + statSync: notImplementedFunction, + readdir: inputFileSystem?.readdir?.bind(inputFileSystem) ?? notImplementedFunction, + readdirSync: notImplementedFunction + } as unknown as glob.FileSystemAdapter; // The Webpack typings are wrong on `readdir` + + await Async.forEachAsync( + hashedFolderDependencies, + async (hashedFolderDependency) => { + await hashedFolderDependency.processAssetsAsync(compilation, globFs); + }, + { concurrency: 10 } + ); + }); + + const handler: (parser: webpack.javascript.JavascriptParser) => void = ( + parser: webpack.javascript.JavascriptParser + ) => { + parser.hooks.call.for(EXPRESSION_NAME).tap(PLUGIN_NAME, (baseExpression: Expression) => { + const expression: CallExpression = baseExpression as CallExpression; + + let errorMessage: string | undefined; + let requireFolderOptions: IRequireFolderOptions | undefined = undefined; + if (expression.arguments.length !== 1) { + errorMessage = `Exactly one argument is required to be passed to "${EXPRESSION_NAME}"`; + } else { + const argument: IAcornNode = expression + .arguments[0] as IAcornNode; + try { + requireFolderOptions = this._evaluateAcornNode(argument) as IRequireFolderOptions; + } catch (e) { + errorMessage = (e as Error).message; + } + + if (requireFolderOptions) { + if ( + !requireFolderOptions.outputFolder || + typeof requireFolderOptions.outputFolder !== 'string' + ) { + errorMessage = 'The options object must have a "outputFolder" property that is a string'; + } else if (!requireFolderOptions.sources || !Array.isArray(requireFolderOptions.sources)) { + errorMessage = 'The options object must have a "sources" property that is an array'; + } else { + for (const source of requireFolderOptions.sources) { + if (!source.globsBase || typeof source.globsBase !== 'string') { + errorMessage = 'Each "sources" element must have a string "globsBase" property'; + } else if ( + !source.globPatterns || + !Array.isArray(source.globPatterns) || + source.globPatterns.some( + (globPattern) => !globPattern || typeof globPattern !== 'string' + ) + ) { + errorMessage = + 'Each "sources" element must have a "globPatterns" property that is an array of glob strings'; + } + } + } + } + } + + const currentModule: webpack.NormalModule = parser.state.current; + let dependency: webpack.dependencies.NullDependency; + if (!requireFolderOptions) { + const errorText: string = renderError(errorMessage!); + dependency = new webpack.dependencies.ConstDependency(errorText, expression.range!); + if (expression.loc) { + dependency.loc = expression.loc; + } + + compilation.errors.push(new webpack.WebpackError(errorMessage)); + } else { + const hashedFolderDependency: IHashedFolderDependency = new HashedFolderDependency( + requireFolderOptions, + expression.range!, + expression.loc + ); + hashedFolderDependencies.push(hashedFolderDependency); + dependency = hashedFolderDependency; + } + + currentModule.addDependency(dependency); + }); + + parser.hooks.evaluateTypeof + .for(EXPRESSION_NAME) + .tap(PLUGIN_NAME, ParserHelpers.evaluateToString('function')); + + parser.hooks.typeof + .for(EXPRESSION_NAME) + .tap(PLUGIN_NAME, ParserHelpers.toConstantDependency(parser, JSON.stringify('function'))); + }; + + normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, handler); + normalModuleFactory.hooks.parser.for('javascript/dynamic').tap(PLUGIN_NAME, handler); + } + ); + } + + private _evaluateAcornNode(node: IAcornNode): unknown { + switch (node.type) { + case 'Literal': { + return node.value; + } + + case 'ObjectExpression': { + const result: Record = {}; + + for (const property of node.properties!) { + const keyNode: IAcornNode = property.key!; + if (keyNode.type !== 'Identifier' || keyNode.computed) { + throw new Error('Property keys must be non-computed identifiers'); + } + + const key: string = keyNode.name!; + const value: unknown = this._evaluateAcornNode(property.value as IAcornNode); + result[key] = value; + } + + return result; + } + + case 'ArrayExpression': { + return node.elements.map((element) => this._evaluateAcornNode(element)); + } + + default: { + throw new Error(`Unsupported node type: "${node.type}"`); + } + } + } +} diff --git a/webpack/hashed-folder-copy-plugin/src/HashedFolderDependency.ts b/webpack/hashed-folder-copy-plugin/src/HashedFolderDependency.ts new file mode 100644 index 00000000000..078f3929a22 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/HashedFolderDependency.ts @@ -0,0 +1,318 @@ +// 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 crypto from 'node:crypto'; + +import glob from 'fast-glob'; +import type webpack from 'webpack'; +import type { SourceLocation } from 'estree'; + +import { LegacyAdapters } from '@rushstack/node-core-library'; + +import { renderError } from './HashedFolderCopyPlugin'; +import type { + ConnectionState, + DependencyTemplateContext, + ObjectDeserializerContext, + ObjectSerializerContext, + Range, + ResolverWithOptions, + UpdateHashContextDependency, + WebpackHash +} from './webpackTypes'; + +export interface IHashedFolderDependency extends webpack.dependencies.NullDependency { + processAssetsAsync(compilation: webpack.Compilation, globFs: glob.FileSystemAdapter): Promise; +} + +export interface IExports { + HashedFolderDependencyTemplate: typeof webpack.dependencies.NullDependency.Template; + HashedFolderDependency: { + new ( + requireFolderOptions: IRequireFolderOptions, + range: Range, + // eslint-disable-next-line @rushstack/no-new-null + loc: SourceLocation | null | undefined + ): IHashedFolderDependency; + }; +} + +const exportsCache: WeakMap = new WeakMap(); + +/** + * @remarks + * This has to be done this way because webpack 5 wants to ensure that the `webpack` instance that's used in the + * compilation, including by extended classes, is a pure singleton + */ +export function getHashedFolderDependencyForWebpackInstance(webpack: typeof import('webpack')): IExports { + let hashedFolderDependency: IExports | undefined = exportsCache.get(webpack); + if (!hashedFolderDependency) { + hashedFolderDependency = _getHashedFolderDependencyForWebpackInstance(webpack); + exportsCache.set(webpack, hashedFolderDependency); + } + + return hashedFolderDependency; +} + +function _getHashedFolderDependencyForWebpackInstance(webpack: typeof import('webpack')): IExports { + class HashedFolderDependencyTemplate extends webpack.dependencies.NullDependency.Template { + public apply( + { range, expression }: HashedFolderDependency, + source: webpack.sources.ReplaceSource, + templateContext: DependencyTemplateContext + ): void { + templateContext.runtimeRequirements.add(webpack.RuntimeGlobals.publicPath); + + if (expression === undefined) { + throw new Error( + 'Expression must be defined. This indicates that the compilation\'s "finishModules" hook did not complete' + ); + } else if (typeof range === 'number') { + source.insert(range, expression); + } else { + const [rangeStart, rangeEnd] = range; + source.replace(rangeStart, rangeEnd - 1, expression); + } + } + } + + class HashedFolderDependency + extends webpack.dependencies.NullDependency + implements IHashedFolderDependency + { + public /* readonly - except for the `deserialize` function */ requireFolderOptions: IRequireFolderOptions; + public /* readonly - except for the `deserialize` function */ range: Range; + public expression: string | undefined; + private _hashUpdate: string | undefined; + + public constructor( + requireFolderOptions: IRequireFolderOptions, + range: Range, + // eslint-disable-next-line @rushstack/no-new-null + loc: SourceLocation | null | undefined + ) { + super(); + + this.requireFolderOptions = requireFolderOptions; + this.range = range; + + if (loc) { + this.loc = loc; + } + } + + public updateHash(hash: WebpackHash, context: UpdateHashContextDependency): void { + if (!this._hashUpdate) { + const requireFolderOptionsStr: string = JSON.stringify(this.requireFolderOptions); + this._hashUpdate = `${requireFolderOptionsStr}|${this.range}`; + } + + hash.update(this._hashUpdate); + } + + public getModuleEvaluationSideEffectsState(moduleGraph: webpack.ModuleGraph): ConnectionState { + return false; + } + + public serialize(context: ObjectSerializerContext): void { + const { write } = context; + write(this.requireFolderOptions); + write(this.range); + super.serialize(context); + } + + public deserialize(context: ObjectDeserializerContext): void { + const { read } = context; + this.requireFolderOptions = read() as IRequireFolderOptions; + this.range = read() as Range; + super.deserialize(context); + } + + public async processAssetsAsync( + compilation: webpack.Compilation, + globFs: glob.FileSystemAdapter + ): Promise { + if (!this.expression) { + this.expression = await this._collectAssetsAndGetExpressionAsync(compilation, globFs); + } + } + + private async _collectAssetsAndGetExpressionAsync( + compilation: webpack.Compilation, + globFs: glob.FileSystemAdapter + ): Promise { + // Map of context-relative asset names to asset contents + const assetsToAdd: Map = new Map(); + + const parentModule: webpack.NormalModule = compilation.moduleGraph.getParentModule( + this + ) as webpack.NormalModule; + const context: string | null = parentModule.context; + let resolver: ResolverWithOptions | undefined; + for (const source of this.requireFolderOptions.sources) { + const { globsBase, globPatterns } = source; + + let resolvedGlobsBase: string; + if (globsBase.startsWith('.')) { + // Does this look like a relative path? + if (!context) { + const errorMessage: string = `Unable to resolve relative path "${globsBase}" because the module has no context`; + compilation.errors.push(new webpack.WebpackError(errorMessage)); + return renderError(errorMessage); + } else { + resolvedGlobsBase = path.resolve(context, globsBase); + } + } else if (path.isAbsolute(globsBase)) { + // This is an absolute path + resolvedGlobsBase = globsBase; + } else { + // This looks like a NodeJS module path + let slashAfterPackageNameIndex: number; + if (globsBase.startsWith('@')) { + // The package name has a scope + slashAfterPackageNameIndex = globsBase.indexOf('/', globsBase.indexOf('/') + 1); + } else { + slashAfterPackageNameIndex = globsBase.indexOf('/'); + } + + let packageName: string; + let pathInsidePackage: string; + if (slashAfterPackageNameIndex === -1) { + packageName = globsBase; + pathInsidePackage = ''; + } else { + packageName = globsBase.slice(0, slashAfterPackageNameIndex); + pathInsidePackage = globsBase.slice(slashAfterPackageNameIndex + 1); + } + + let packagePath: string | undefined; + try { + if (!context) { + const errorMessage: string = `Unable to resolve package "${packageName}" because the module has no context`; + compilation.errors.push(new webpack.WebpackError(errorMessage)); + return renderError(errorMessage); + } else { + if (!resolver) { + resolver = compilation.resolverFactory.get('normal', parentModule.resolveOptions); + } + + // The `resolver.resolve` type is too complex for LegacyAdapters.convertCallbackToPromise + packagePath = await new Promise((resolve, reject) => { + resolver!.resolve({}, context, `${packageName}/package.json`, {}, (err, result) => { + if (err) { + reject(err); + } else if (result) { + resolve(path.dirname(result)); + } else { + reject(new Error(`Unable to resolve package "${packageName}"`)); + } + }); + }); + } + } catch (e) { + compilation.errors.push(e); + } + + if (packagePath) { + resolvedGlobsBase = path.join(packagePath, pathInsidePackage); + } else { + const errorMessage: string = `Unable to resolve package "${packageName}"`; + compilation.errors.push(new webpack.WebpackError(errorMessage)); + return renderError(errorMessage); + } + } + + const boundReadFile: typeof compilation.inputFileSystem.readFile = + compilation.inputFileSystem.readFile.bind(compilation.inputFileSystem); + + // TODO: Add all folders that get read to `parentModule.buildInfo.contextDependencies` + // At this point in the compilation, that property has been set to undefined, so we need to do this earlier + const globResults: string[] = await glob(globPatterns, { + cwd: resolvedGlobsBase, + onlyFiles: true, + fs: globFs + }); + for (const globResult of globResults) { + if (assetsToAdd.has(globResult)) { + const errorMessage: string = `Two files resolve to the same output path "${globResult}"`; + compilation.errors.push(new webpack.WebpackError(errorMessage)); + return renderError(errorMessage); + } + + const globResultFullPath: string = path.resolve(resolvedGlobsBase, globResult); + + let assetContents: string | Buffer | undefined; + try { + assetContents = (await LegacyAdapters.convertCallbackToPromise( + boundReadFile, + globResultFullPath + )) as string | Buffer; + } catch (e) { + compilation.errors.push(new webpack.WebpackError(e.message)); + return renderError(e.message); + } + + assetsToAdd.set(globResult, assetContents); + } + } + + const hash: crypto.Hash = crypto.createHash('md5'); + // If the webpack config specified a salt, apply it here + const hashSalt: string | undefined = compilation.outputOptions?.hashSalt; + if (hashSalt) { + hash.update(hashSalt); + } + + // Sort the paths to maximize hash stability + for (const assetPath of Array.from(assetsToAdd.keys()).sort()) { + hash.update(assetPath); + hash.update(assetsToAdd.get(assetPath)!); + } + + const hashTokenRegex: RegExp = /\[hash:?(\d+)?\]/g; + const hashDigest: string = hash.digest('hex'); + let pathPrefix: string = this.requireFolderOptions.outputFolder.replace( + hashTokenRegex, + (match, length) => { + const hashLength: number | undefined = length ? Number.parseInt(length, 10) : undefined; + if (hashLength) { + return hashDigest.slice(0, hashLength); + } else { + return hashDigest; + } + } + ); + pathPrefix = path.posix.join(pathPrefix, '/'); // Ensure trailing slash + + const { buildInfo = (parentModule.buildInfo = {}) } = parentModule; + + const { assets = (buildInfo.assets = {}) } = buildInfo; + + const existingAssetNames: Set = new Set(Object.keys(compilation.assets)); + for (const [assetPath, asset] of assetsToAdd) { + const fullAssetPath: string = path.posix.join(pathPrefix, assetPath); + if (existingAssetNames.has(fullAssetPath)) { + const errorMessage: string = `An asset with path "${fullAssetPath}" already exists`; + compilation.errors.push(new webpack.WebpackError(errorMessage)); + return renderError(errorMessage); + } + + const assetSource: webpack.sources.RawSource = new webpack.sources.RawSource(asset); + compilation.emitAsset(fullAssetPath, assetSource); + assets[fullAssetPath] = assetSource; + } + + return `${webpack.RuntimeGlobals.publicPath} + ${JSON.stringify(pathPrefix)}`; + } + } + + const makeSerializable: ( + constructor: typeof HashedFolderDependency, + request: string + ) => void = require('webpack/lib/util/makeSerializable'); + + makeSerializable(HashedFolderDependency, __filename); + + return { HashedFolderDependencyTemplate, HashedFolderDependency }; +} diff --git a/webpack/hashed-folder-copy-plugin/src/ambientTypes.d.ts b/webpack/hashed-folder-copy-plugin/src/ambientTypes.d.ts new file mode 100644 index 00000000000..4499449c005 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/ambientTypes.d.ts @@ -0,0 +1,33 @@ +/** + * Describes a source folder from which assets should be copied. + * + * @public + */ +declare interface IRequireFolderSource { + /** + * The root under which glob patterns should be evaluated + */ + globsBase: string; + + /** + * Glob patterns matching assets to be copied + */ + globPatterns: string[]; +} + +/** + * @public + */ +declare interface IRequireFolderOptions { + /** + * A set of sources to copy to the specified output folder name. + */ + sources: IRequireFolderSource[]; + + /** + * The name of the folder to which assets should be copied. May contain a "[hash]" token. + */ + outputFolder: string; +} + +declare function requireFolder(options: IRequireFolderOptions): string; diff --git a/webpack/hashed-folder-copy-plugin/src/index.ts b/webpack/hashed-folder-copy-plugin/src/index.ts new file mode 100644 index 00000000000..e57629e5d21 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/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 { HashedFolderCopyPlugin } from './HashedFolderCopyPlugin'; diff --git a/webpack/hashed-folder-copy-plugin/src/test/HashedFolderCopyPlugin.test.ts b/webpack/hashed-folder-copy-plugin/src/test/HashedFolderCopyPlugin.test.ts new file mode 100644 index 00000000000..22c23ce6cbf --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/HashedFolderCopyPlugin.test.ts @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.mock('node:path', () => { + const path: typeof import('path') = jest.requireActual('path'); + return path.posix; +}); + +jest.mock( + 'fast-glob/out/providers/provider', + () => { + const path: typeof import('path') = jest.requireActual('path'); + const { default: provider } = jest.requireActual('fast-glob/out/providers/provider'); + provider.prototype._getRootDirectory = function (task: { base: string }) { + // fast-glob calls `path.resolve` which doesn't work correctly with the MemFS volume while running on Windows + return path.posix.resolve(this._settings.cwd, task.base); + }; + return { default: provider }; + }, + {} +); + +import type { default as webpack, Stats, InputFileSystem, OutputFileSystem } from 'webpack'; +import type { Volume } from 'memfs/lib/volume'; +import type { FileSystem, FolderItem } from '@rushstack/node-core-library'; + +jest.setTimeout(1e9); + +interface IFilePaths { + itemRelativePath: string; + itemAbsolutePath: string; +} + +async function* enumerateFilesAsync( + fileSystem: typeof FileSystem, + absolutePath: string, + relativePath: string +): AsyncIterable { + const folderItems: FolderItem[] = await fileSystem.readFolderItemsAsync(absolutePath); + for (const item of folderItems) { + const name: string = item.name; + const itemRelativePath: string = `${relativePath}/${name}`; + const itemAbsolutePath: string = `${absolutePath}/${name}`; + if (item.isDirectory()) { + yield* enumerateFilesAsync(fileSystem, itemAbsolutePath, itemRelativePath); + } else if (item.isFile()) { + yield { itemRelativePath, itemAbsolutePath }; + } else { + throw new Error(`Unexpected item type`); + } + } +} + +async function readFolderAsync( + absolutePath: string, + relativePath: string, + outputObject: Record +): Promise { + const { Async, FileSystem } = await import('@rushstack/node-core-library'); + + const files: AsyncIterable = enumerateFilesAsync(FileSystem, absolutePath, relativePath); + await Async.forEachAsync( + files, + async ({ itemRelativePath, itemAbsolutePath }) => { + const fileContents: string = await FileSystem.readFileAsync(itemAbsolutePath); + outputObject[itemRelativePath] = fileContents; + }, + { concurrency: 50 } + ); +} + +async function runTestAsync(inputFolderPath: string): Promise { + const [{ Volume }, { default: webpack }, { promisify }, { HashedFolderCopyPlugin }] = await Promise.all([ + import('memfs/lib/volume'), + import('webpack'), + import('node:util'), + import('../HashedFolderCopyPlugin') + ]); + + const memoryFileSystem: Volume = new Volume(); + const folderContents: Record = {}; + await readFolderAsync(inputFolderPath, '', folderContents); + memoryFileSystem.fromJSON(folderContents, '/src'); + + const compiler: webpack.Compiler = webpack({ + entry: { + main: '/entry.js' + }, + output: { + path: '/release', + filename: '[name].js' + }, + optimization: { + minimizer: [] + }, + context: '/', + mode: 'production', + plugins: [new HashedFolderCopyPlugin()] + }); + + compiler.inputFileSystem = memoryFileSystem as unknown as InputFileSystem; + compiler.outputFileSystem = memoryFileSystem as unknown as OutputFileSystem; + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler)); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); +} + +describe('HashedFolderCopyPlugin', () => { + it('Handles the null case', async () => { + await runTestAsync(`${__dirname}/scenarios/nullCase`); + }); + + it('Handles globbing a local folder', async () => { + await runTestAsync(`${__dirname}/scenarios/localFolder`); + }); + + it('Handles globbing a package reference', async () => { + await runTestAsync(`${__dirname}/scenarios/packageReference`); + }); +}); diff --git a/webpack/hashed-folder-copy-plugin/src/test/__snapshots__/HashedFolderCopyPlugin.test.ts.snap b/webpack/hashed-folder-copy-plugin/src/test/__snapshots__/HashedFolderCopyPlugin.test.ts.snap new file mode 100644 index 00000000000..34940cfbaaf --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/__snapshots__/HashedFolderCopyPlugin.test.ts.snap @@ -0,0 +1,154 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HashedFolderCopyPlugin Handles globbing a local folder: Content 1`] = ` +Object { + "/release/assets_1a20fc5e5390d91fee246bf5dbf1300e/a.txt": "local-folder-AAA", + "/release/assets_1a20fc5e5390d91fee246bf5dbf1300e/b.txt": "local-folder-BBB", + "/release/assets_1a20fc5e5390d91fee246bf5dbf1300e/subfolder/c.txt": "local-folder-CCC", + "/release/main.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/************************************************************************/ + +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +const path = __webpack_require__.p + \\"assets_1a20fc5e5390d91fee246bf5dbf1300e/\\"; +// eslint-disable-next-line no-console +console.log(path); +// eslint-disable-next-line no-console +console.log(\\"function\\"); +//# sourceMappingURL=entry.js.map +/******/ })() +;", +} +`; + +exports[`HashedFolderCopyPlugin Handles globbing a local folder: Errors 1`] = `Array []`; + +exports[`HashedFolderCopyPlugin Handles globbing a local folder: Warnings 1`] = `Array []`; + +exports[`HashedFolderCopyPlugin Handles globbing a package reference: Content 1`] = ` +Object { + "/release/assets_084b4ae6ce51eb9a614a9d1981afc6b7/a.txt": "unscoped-package-AAA", + "/release/assets_084b4ae6ce51eb9a614a9d1981afc6b7/b.txt": "unscoped-package-BBB", + "/release/assets_084b4ae6ce51eb9a614a9d1981afc6b7/subfolder/c.txt": "unscoped-package-CCC", + "/release/assets_f2eede62be13dd0052e19c66d82f6cdb/a.txt": "scoped-package-AAA", + "/release/assets_f2eede62be13dd0052e19c66d82f6cdb/b.txt": "scoped-package-BBB", + "/release/assets_f2eede62be13dd0052e19c66d82f6cdb/subfolder/c.txt": "scoped-package-CCC", + "/release/main.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/************************************************************************/ + +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +const scopedPackagePath = __webpack_require__.p + \\"assets_f2eede62be13dd0052e19c66d82f6cdb/\\"; +const unscopedPackagePath = __webpack_require__.p + \\"assets_084b4ae6ce51eb9a614a9d1981afc6b7/\\"; +// eslint-disable-next-line no-console +console.log(scopedPackagePath); +// eslint-disable-next-line no-console +console.log(unscopedPackagePath); +//# sourceMappingURL=entry.js.map +/******/ })() +;", +} +`; + +exports[`HashedFolderCopyPlugin Handles globbing a package reference: Errors 1`] = `Array []`; + +exports[`HashedFolderCopyPlugin Handles globbing a package reference: Warnings 1`] = `Array []`; + +exports[`HashedFolderCopyPlugin Handles the null case: Content 1`] = ` +Object { + "/release/main.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; + +// 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('test'); +//# sourceMappingURL=entry.js.map +/******/ })() +;", +} +`; + +exports[`HashedFolderCopyPlugin Handles the null case: Errors 1`] = `Array []`; + +exports[`HashedFolderCopyPlugin Handles the null case: Warnings 1`] = `Array []`; diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/a.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/a.txt new file mode 100644 index 00000000000..ebab93b8746 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/a.txt @@ -0,0 +1 @@ +local-folder-AAA \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/b.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/b.txt new file mode 100644 index 00000000000..db953c8decd --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/b.txt @@ -0,0 +1 @@ +local-folder-BBB \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/subfolder/c.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/subfolder/c.txt new file mode 100644 index 00000000000..02982e53cf4 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/assets/subfolder/c.txt @@ -0,0 +1 @@ +local-folder-CCC \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/entry.ts b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/entry.ts new file mode 100644 index 00000000000..35b6d41ebe4 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/entry.ts @@ -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 path: string = requireFolder({ + sources: [ + { + globsBase: './assets', + globPatterns: ['**/*.*'] + } + ], + outputFolder: 'assets_[hash]' +}); + +// eslint-disable-next-line no-console +console.log(path); +// eslint-disable-next-line no-console +console.log(typeof requireFolder); diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/package.json b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/package.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/localFolder/package.json @@ -0,0 +1 @@ +{} diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/entry.ts b/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/entry.ts new file mode 100644 index 00000000000..c2b5b80aa51 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/entry.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('test'); diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/package.json b/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/package.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/nullCase/package.json @@ -0,0 +1 @@ +{} diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/.gitignore b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/.gitignore new file mode 100644 index 00000000000..736e8ae58ad --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/.gitignore @@ -0,0 +1 @@ +!node_modules \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/entry.ts b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/entry.ts new file mode 100644 index 00000000000..f568a3b1445 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/entry.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. + +const scopedPackagePath: string = requireFolder({ + sources: [ + { + globsBase: '@scope/scoped-package/assets', + globPatterns: ['**/*.*'] + } + ], + outputFolder: 'assets_[hash]' +}); + +const unscopedPackagePath: string = requireFolder({ + sources: [ + { + globsBase: 'unscoped-package/assets', + globPatterns: ['**/*.*'] + } + ], + outputFolder: 'assets_[hash]' +}); + +// eslint-disable-next-line no-console +console.log(scopedPackagePath); +// eslint-disable-next-line no-console +console.log(unscopedPackagePath); diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/a.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/a.txt new file mode 100644 index 00000000000..92d7850351a --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/a.txt @@ -0,0 +1 @@ +scoped-package-AAA \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/b.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/b.txt new file mode 100644 index 00000000000..83aa25f493b --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/b.txt @@ -0,0 +1 @@ +scoped-package-BBB \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/subfolder/c.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/subfolder/c.txt new file mode 100644 index 00000000000..eaa86b7e12e --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/assets/subfolder/c.txt @@ -0,0 +1 @@ +scoped-package-CCC \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/package.json b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/package.json new file mode 100644 index 00000000000..10a402f3c5f --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/@scope/scoped-package/package.json @@ -0,0 +1,3 @@ +{ + "name": "@scope/scoped-package" +} diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/a.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/a.txt new file mode 100644 index 00000000000..ca5814bd4a9 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/a.txt @@ -0,0 +1 @@ +unscoped-package-AAA \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/b.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/b.txt new file mode 100644 index 00000000000..0f6ea19bb0d --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/b.txt @@ -0,0 +1 @@ +unscoped-package-BBB \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/subfolder/c.txt b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/subfolder/c.txt new file mode 100644 index 00000000000..1d7aeb80b0a --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/assets/subfolder/c.txt @@ -0,0 +1 @@ +unscoped-package-CCC \ No newline at end of file diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/package.json b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/package.json new file mode 100644 index 00000000000..1cfcc019f6b --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/node_modules/unscoped-package/package.json @@ -0,0 +1,3 @@ +{ + "name": "unscoped-package" +} diff --git a/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/package.json b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/package.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/test/scenarios/packageReference/package.json @@ -0,0 +1 @@ +{} diff --git a/webpack/hashed-folder-copy-plugin/src/webpackTypes.ts b/webpack/hashed-folder-copy-plugin/src/webpackTypes.ts new file mode 100644 index 00000000000..afcf7801b4e --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/src/webpackTypes.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 type webpack from 'webpack'; + +type BasicEvaluatedExpressionHook = ReturnType< + typeof webpack.javascript.JavascriptParser.prototype.hooks.evaluateTypeof.for +>; +export type BasicEvaluatedExpression = ReturnType; + +export type Range = number | [number, number]; +export type DependencyTemplateContext = Parameters< + typeof webpack.dependencies.NullDependency.Template.prototype.apply +>[2]; +export type WebpackHash = Parameters[0]; +export type UpdateHashContextDependency = Parameters< + typeof webpack.dependencies.NullDependency.prototype.updateHash +>[1]; +export type ConnectionState = ReturnType< + typeof webpack.dependencies.NullDependency.prototype.getModuleEvaluationSideEffectsState +>; +export type ObjectSerializerContext = Parameters< + typeof webpack.dependencies.NullDependency.prototype.serialize +>[0]; +export type ObjectDeserializerContext = Parameters< + typeof webpack.dependencies.NullDependency.prototype.deserialize +>[0]; +export type ResolverWithOptions = ReturnType< + Parameters[0]['getResolver'] +>; diff --git a/webpack/hashed-folder-copy-plugin/tsconfig.json b/webpack/hashed-folder-copy-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/webpack/hashed-folder-copy-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/loader-load-themed-styles/.eslintrc.js b/webpack/loader-load-themed-styles/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/webpack/loader-load-themed-styles/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/webpack/loader-load-themed-styles/.npmignore b/webpack/loader-load-themed-styles/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/webpack/loader-load-themed-styles/.npmignore +++ b/webpack/loader-load-themed-styles/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/webpack/loader-load-themed-styles/CHANGELOG.json b/webpack/loader-load-themed-styles/CHANGELOG.json index 0339bfdc3f5..5b0d5653c1b 100644 --- a/webpack/loader-load-themed-styles/CHANGELOG.json +++ b/webpack/loader-load-themed-styles/CHANGELOG.json @@ -1,6 +1,8312 @@ { "name": "@microsoft/loader-load-themed-styles", "entries": [ + { + "version": "2.1.118", + "tag": "@microsoft/loader-load-themed-styles_v2.1.118", + "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 \"@microsoft/load-themed-styles\" from `^2.1.21` to `2.1.22`" + } + ] + } + }, + { + "version": "2.1.117", + "tag": "@microsoft/loader-load-themed-styles_v2.1.117", + "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 \"@microsoft/load-themed-styles\" from `^2.1.20` to `2.1.21`" + } + ] + } + }, + { + "version": "2.1.116", + "tag": "@microsoft/loader-load-themed-styles_v2.1.116", + "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 \"@microsoft/load-themed-styles\" from `^2.1.19` to `2.1.20`" + } + ] + } + }, + { + "version": "2.1.115", + "tag": "@microsoft/loader-load-themed-styles_v2.1.115", + "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 \"@microsoft/load-themed-styles\" from `^2.1.18` to `2.1.19`" + } + ] + } + }, + { + "version": "2.1.114", + "tag": "@microsoft/loader-load-themed-styles_v2.1.114", + "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 \"@microsoft/load-themed-styles\" from `^2.1.17` to `2.1.18`" + } + ] + } + }, + { + "version": "2.1.113", + "tag": "@microsoft/loader-load-themed-styles_v2.1.113", + "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 \"@microsoft/load-themed-styles\" from `^2.1.16` to `2.1.17`" + } + ] + } + }, + { + "version": "2.1.112", + "tag": "@microsoft/loader-load-themed-styles_v2.1.112", + "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 \"@microsoft/load-themed-styles\" from `^2.1.15` to `2.1.16`" + } + ] + } + }, + { + "version": "2.1.111", + "tag": "@microsoft/loader-load-themed-styles_v2.1.111", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.14` to `2.1.15`" + } + ] + } + }, + { + "version": "2.1.110", + "tag": "@microsoft/loader-load-themed-styles_v2.1.110", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.13` to `2.1.14`" + } + ] + } + }, + { + "version": "2.1.109", + "tag": "@microsoft/loader-load-themed-styles_v2.1.109", + "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 \"@microsoft/load-themed-styles\" from `^2.1.12` to `2.1.13`" + } + ] + } + }, + { + "version": "2.1.108", + "tag": "@microsoft/loader-load-themed-styles_v2.1.108", + "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 \"@microsoft/load-themed-styles\" from `^2.1.11` to `2.1.12`" + } + ] + } + }, + { + "version": "2.1.107", + "tag": "@microsoft/loader-load-themed-styles_v2.1.107", + "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 \"@microsoft/load-themed-styles\" from `^2.1.10` to `2.1.11`" + } + ] + } + }, + { + "version": "2.1.106", + "tag": "@microsoft/loader-load-themed-styles_v2.1.106", + "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 \"@microsoft/load-themed-styles\" from `^2.1.9` to `2.1.10`" + } + ] + } + }, + { + "version": "2.1.105", + "tag": "@microsoft/loader-load-themed-styles_v2.1.105", + "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 \"@microsoft/load-themed-styles\" from `^2.1.8` to `2.1.9`" + } + ] + } + }, + { + "version": "2.1.104", + "tag": "@microsoft/loader-load-themed-styles_v2.1.104", + "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 \"@microsoft/load-themed-styles\" from `^2.1.7` to `2.1.8`" + } + ] + } + }, + { + "version": "2.1.103", + "tag": "@microsoft/loader-load-themed-styles_v2.1.103", + "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 \"@microsoft/load-themed-styles\" from `^2.1.6` to `2.1.7`" + } + ] + } + }, + { + "version": "2.1.102", + "tag": "@microsoft/loader-load-themed-styles_v2.1.102", + "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 \"@microsoft/load-themed-styles\" from `^2.1.5` to `2.1.6`" + } + ] + } + }, + { + "version": "2.1.101", + "tag": "@microsoft/loader-load-themed-styles_v2.1.101", + "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 \"@microsoft/load-themed-styles\" from `^2.1.4` to `2.1.5`" + } + ] + } + }, + { + "version": "2.1.100", + "tag": "@microsoft/loader-load-themed-styles_v2.1.100", + "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 \"@microsoft/load-themed-styles\" from `^2.1.3` to `2.1.4`" + } + ] + } + }, + { + "version": "2.1.99", + "tag": "@microsoft/loader-load-themed-styles_v2.1.99", + "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 \"@microsoft/load-themed-styles\" from `^2.1.2` to `2.1.3`" + } + ] + } + }, + { + "version": "2.1.98", + "tag": "@microsoft/loader-load-themed-styles_v2.1.98", + "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 \"@microsoft/load-themed-styles\" from `^2.1.1` to `2.1.2`" + } + ] + } + }, + { + "version": "2.1.97", + "tag": "@microsoft/loader-load-themed-styles_v2.1.97", + "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 \"@microsoft/load-themed-styles\" from `^2.1.0` to `2.1.1`" + } + ] + } + }, + { + "version": "2.1.96", + "tag": "@microsoft/loader-load-themed-styles_v2.1.96", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.171` to `2.1.0`" + } + ] + } + }, + { + "version": "2.1.95", + "tag": "@microsoft/loader-load-themed-styles_v2.1.95", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.171`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.170` to `2.0.171`" + } + ] + } + }, + { + "version": "2.1.94", + "tag": "@microsoft/loader-load-themed-styles_v2.1.94", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.170`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.169` to `2.0.170`" + } + ] + } + }, + { + "version": "2.1.93", + "tag": "@microsoft/loader-load-themed-styles_v2.1.93", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.169`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.168` to `2.0.169`" + } + ] + } + }, + { + "version": "2.1.92", + "tag": "@microsoft/loader-load-themed-styles_v2.1.92", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.168`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.167` to `2.0.168`" + } + ] + } + }, + { + "version": "2.1.91", + "tag": "@microsoft/loader-load-themed-styles_v2.1.91", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.167`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.166` to `2.0.167`" + } + ] + } + }, + { + "version": "2.1.90", + "tag": "@microsoft/loader-load-themed-styles_v2.1.90", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.166`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.165` to `2.0.166`" + } + ] + } + }, + { + "version": "2.1.89", + "tag": "@microsoft/loader-load-themed-styles_v2.1.89", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.165`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.164` to `2.0.165`" + } + ] + } + }, + { + "version": "2.1.88", + "tag": "@microsoft/loader-load-themed-styles_v2.1.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.164`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.163` to `2.0.164`" + } + ] + } + }, + { + "version": "2.1.87", + "tag": "@microsoft/loader-load-themed-styles_v2.1.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.163`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.162` to `2.0.163`" + } + ] + } + }, + { + "version": "2.1.86", + "tag": "@microsoft/loader-load-themed-styles_v2.1.86", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.162`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.161` to `2.0.162`" + } + ] + } + }, + { + "version": "2.1.85", + "tag": "@microsoft/loader-load-themed-styles_v2.1.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.161`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.160` to `2.0.161`" + } + ] + } + }, + { + "version": "2.1.84", + "tag": "@microsoft/loader-load-themed-styles_v2.1.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.160`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.159` to `2.0.160`" + } + ] + } + }, + { + "version": "2.1.83", + "tag": "@microsoft/loader-load-themed-styles_v2.1.83", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.159`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.158` to `2.0.159`" + } + ] + } + }, + { + "version": "2.1.82", + "tag": "@microsoft/loader-load-themed-styles_v2.1.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.158`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.157` to `2.0.158`" + } + ] + } + }, + { + "version": "2.1.81", + "tag": "@microsoft/loader-load-themed-styles_v2.1.81", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.157`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.156` to `2.0.157`" + } + ] + } + }, + { + "version": "2.1.80", + "tag": "@microsoft/loader-load-themed-styles_v2.1.80", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.156`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.155` to `2.0.156`" + } + ] + } + }, + { + "version": "2.1.79", + "tag": "@microsoft/loader-load-themed-styles_v2.1.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.155`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.154` to `2.0.155`" + } + ] + } + }, + { + "version": "2.1.78", + "tag": "@microsoft/loader-load-themed-styles_v2.1.78", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.154`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.153` to `2.0.154`" + } + ] + } + }, + { + "version": "2.1.77", + "tag": "@microsoft/loader-load-themed-styles_v2.1.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.153`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.152` to `2.0.153`" + } + ] + } + }, + { + "version": "2.1.76", + "tag": "@microsoft/loader-load-themed-styles_v2.1.76", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.152`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.151` to `2.0.152`" + } + ] + } + }, + { + "version": "2.1.75", + "tag": "@microsoft/loader-load-themed-styles_v2.1.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.151`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.150` to `2.0.151`" + } + ] + } + }, + { + "version": "2.1.74", + "tag": "@microsoft/loader-load-themed-styles_v2.1.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.150`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.149` to `2.0.150`" + } + ] + } + }, + { + "version": "2.1.73", + "tag": "@microsoft/loader-load-themed-styles_v2.1.73", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.149`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.148` to `2.0.149`" + } + ] + } + }, + { + "version": "2.1.72", + "tag": "@microsoft/loader-load-themed-styles_v2.1.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.148`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.147` to `2.0.148`" + } + ] + } + }, + { + "version": "2.1.71", + "tag": "@microsoft/loader-load-themed-styles_v2.1.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.147`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.146` to `2.0.147`" + } + ] + } + }, + { + "version": "2.1.70", + "tag": "@microsoft/loader-load-themed-styles_v2.1.70", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.146`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.145` to `2.0.146`" + } + ] + } + }, + { + "version": "2.1.69", + "tag": "@microsoft/loader-load-themed-styles_v2.1.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.145`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.144` to `2.0.145`" + } + ] + } + }, + { + "version": "2.1.68", + "tag": "@microsoft/loader-load-themed-styles_v2.1.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.144`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.143` to `2.0.144`" + } + ] + } + }, + { + "version": "2.1.67", + "tag": "@microsoft/loader-load-themed-styles_v2.1.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.143`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.142` to `2.0.143`" + } + ] + } + }, + { + "version": "2.1.66", + "tag": "@microsoft/loader-load-themed-styles_v2.1.66", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.142`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.141` to `2.0.142`" + } + ] + } + }, + { + "version": "2.1.65", + "tag": "@microsoft/loader-load-themed-styles_v2.1.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.141`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.140` to `2.0.141`" + } + ] + } + }, + { + "version": "2.1.64", + "tag": "@microsoft/loader-load-themed-styles_v2.1.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.140`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.139` to `2.0.140`" + } + ] + } + }, + { + "version": "2.1.63", + "tag": "@microsoft/loader-load-themed-styles_v2.1.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.139`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.138` to `2.0.139`" + } + ] + } + }, + { + "version": "2.1.62", + "tag": "@microsoft/loader-load-themed-styles_v2.1.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.138`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.137` to `2.0.138`" + } + ] + } + }, + { + "version": "2.1.61", + "tag": "@microsoft/loader-load-themed-styles_v2.1.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.137`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.136` to `2.0.137`" + } + ] + } + }, + { + "version": "2.1.60", + "tag": "@microsoft/loader-load-themed-styles_v2.1.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.136`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.135` to `2.0.136`" + } + ] + } + }, + { + "version": "2.1.59", + "tag": "@microsoft/loader-load-themed-styles_v2.1.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.135`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.134` to `2.0.135`" + } + ] + } + }, + { + "version": "2.1.58", + "tag": "@microsoft/loader-load-themed-styles_v2.1.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.134`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.133` to `2.0.134`" + } + ] + } + }, + { + "version": "2.1.57", + "tag": "@microsoft/loader-load-themed-styles_v2.1.57", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.133`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.132` to `2.0.133`" + } + ] + } + }, + { + "version": "2.1.56", + "tag": "@microsoft/loader-load-themed-styles_v2.1.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.132`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.131` to `2.0.132`" + } + ] + } + }, + { + "version": "2.1.55", + "tag": "@microsoft/loader-load-themed-styles_v2.1.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.131`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.130` to `2.0.131`" + } + ] + } + }, + { + "version": "2.1.54", + "tag": "@microsoft/loader-load-themed-styles_v2.1.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.130`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.129` to `2.0.130`" + } + ] + } + }, + { + "version": "2.1.53", + "tag": "@microsoft/loader-load-themed-styles_v2.1.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.129`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.128` to `2.0.129`" + } + ] + } + }, + { + "version": "2.1.52", + "tag": "@microsoft/loader-load-themed-styles_v2.1.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.128`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.127` to `2.0.128`" + } + ] + } + }, + { + "version": "2.1.51", + "tag": "@microsoft/loader-load-themed-styles_v2.1.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.127`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.126` to `2.0.127`" + } + ] + } + }, + { + "version": "2.1.50", + "tag": "@microsoft/loader-load-themed-styles_v2.1.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.126`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.125` to `2.0.126`" + } + ] + } + }, + { + "version": "2.1.49", + "tag": "@microsoft/loader-load-themed-styles_v2.1.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.125`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.124` to `2.0.125`" + } + ] + } + }, + { + "version": "2.1.48", + "tag": "@microsoft/loader-load-themed-styles_v2.1.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.124`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.123` to `2.0.124`" + } + ] + } + }, + { + "version": "2.1.47", + "tag": "@microsoft/loader-load-themed-styles_v2.1.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.123`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.122` to `2.0.123`" + } + ] + } + }, + { + "version": "2.1.46", + "tag": "@microsoft/loader-load-themed-styles_v2.1.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.122`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.121` to `2.0.122`" + } + ] + } + }, + { + "version": "2.1.45", + "tag": "@microsoft/loader-load-themed-styles_v2.1.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.121`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.120` to `2.0.121`" + } + ] + } + }, + { + "version": "2.1.44", + "tag": "@microsoft/loader-load-themed-styles_v2.1.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.120`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.119` to `2.0.120`" + } + ] + } + }, + { + "version": "2.1.43", + "tag": "@microsoft/loader-load-themed-styles_v2.1.43", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.119`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.118` to `2.0.119`" + } + ] + } + }, + { + "version": "2.1.42", + "tag": "@microsoft/loader-load-themed-styles_v2.1.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.118`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.117` to `2.0.118`" + } + ] + } + }, + { + "version": "2.1.41", + "tag": "@microsoft/loader-load-themed-styles_v2.1.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.117`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.116` to `2.0.117`" + } + ] + } + }, + { + "version": "2.1.40", + "tag": "@microsoft/loader-load-themed-styles_v2.1.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.116`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.115` to `2.0.116`" + } + ] + } + }, + { + "version": "2.1.39", + "tag": "@microsoft/loader-load-themed-styles_v2.1.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.115`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.114` to `2.0.115`" + } + ] + } + }, + { + "version": "2.1.38", + "tag": "@microsoft/loader-load-themed-styles_v2.1.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.114`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.113` to `2.0.114`" + } + ] + } + }, + { + "version": "2.1.37", + "tag": "@microsoft/loader-load-themed-styles_v2.1.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.113`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.112` to `2.0.113`" + } + ] + } + }, + { + "version": "2.1.36", + "tag": "@microsoft/loader-load-themed-styles_v2.1.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.112`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.111` to `2.0.112`" + } + ] + } + }, + { + "version": "2.1.35", + "tag": "@microsoft/loader-load-themed-styles_v2.1.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.111`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.110` to `2.0.111`" + } + ] + } + }, + { + "version": "2.1.34", + "tag": "@microsoft/loader-load-themed-styles_v2.1.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.109` to `2.0.110`" + } + ] + } + }, + { + "version": "2.1.33", + "tag": "@microsoft/loader-load-themed-styles_v2.1.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.108` to `2.0.109`" + } + ] + } + }, + { + "version": "2.1.32", + "tag": "@microsoft/loader-load-themed-styles_v2.1.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.108`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.107` to `2.0.108`" + } + ] + } + }, + { + "version": "2.1.31", + "tag": "@microsoft/loader-load-themed-styles_v2.1.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.107`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.106` to `^2.0.107`" + } + ] + } + }, + { + "version": "2.1.30", + "tag": "@microsoft/loader-load-themed-styles_v2.1.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.106`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.105` to `^2.0.106`" + } + ] + } + }, + { + "version": "2.1.29", + "tag": "@microsoft/loader-load-themed-styles_v2.1.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.105`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.104` to `^2.0.105`" + } + ] + } + }, + { + "version": "2.1.28", + "tag": "@microsoft/loader-load-themed-styles_v2.1.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.103` to `^2.0.104`" + } + ] + } + }, + { + "version": "2.1.27", + "tag": "@microsoft/loader-load-themed-styles_v2.1.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.103`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.102` to `^2.0.103`" + } + ] + } + }, + { + "version": "2.1.26", + "tag": "@microsoft/loader-load-themed-styles_v2.1.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.102`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.101` to `^2.0.102`" + } + ] + } + }, + { + "version": "2.1.25", + "tag": "@microsoft/loader-load-themed-styles_v2.1.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.101`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.100` to `^2.0.101`" + } + ] + } + }, + { + "version": "2.1.24", + "tag": "@microsoft/loader-load-themed-styles_v2.1.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.100`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.99` to `^2.0.100`" + } + ] + } + }, + { + "version": "2.1.23", + "tag": "@microsoft/loader-load-themed-styles_v2.1.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.99`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.98` to `^2.0.99`" + } + ] + } + }, + { + "version": "2.1.22", + "tag": "@microsoft/loader-load-themed-styles_v2.1.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.98`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.97` to `^2.0.98`" + } + ] + } + }, + { + "version": "2.1.21", + "tag": "@microsoft/loader-load-themed-styles_v2.1.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.97`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.96` to `^2.0.97`" + } + ] + } + }, + { + "version": "2.1.20", + "tag": "@microsoft/loader-load-themed-styles_v2.1.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.96`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.95` to `^2.0.96`" + } + ] + } + }, + { + "version": "2.1.19", + "tag": "@microsoft/loader-load-themed-styles_v2.1.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.95`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.94` to `^2.0.95`" + } + ] + } + }, + { + "version": "2.1.18", + "tag": "@microsoft/loader-load-themed-styles_v2.1.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.93` to `^2.0.94`" + } + ] + } + }, + { + "version": "2.1.17", + "tag": "@microsoft/loader-load-themed-styles_v2.1.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.92` to `^2.0.93`" + } + ] + } + }, + { + "version": "2.1.16", + "tag": "@microsoft/loader-load-themed-styles_v2.1.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.91` to `^2.0.92`" + } + ] + } + }, + { + "version": "2.1.15", + "tag": "@microsoft/loader-load-themed-styles_v2.1.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.90` to `^2.0.91`" + } + ] + } + }, + { + "version": "2.1.14", + "tag": "@microsoft/loader-load-themed-styles_v2.1.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.89` to `^2.0.90`" + } + ] + } + }, + { + "version": "2.1.13", + "tag": "@microsoft/loader-load-themed-styles_v2.1.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.88` to `^2.0.89`" + } + ] + } + }, + { + "version": "2.1.12", + "tag": "@microsoft/loader-load-themed-styles_v2.1.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.87` to `^2.0.88`" + } + ] + } + }, + { + "version": "2.1.11", + "tag": "@microsoft/loader-load-themed-styles_v2.1.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.86` to `^2.0.87`" + } + ] + } + }, + { + "version": "2.1.10", + "tag": "@microsoft/loader-load-themed-styles_v2.1.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.85` to `^2.0.86`" + } + ] + } + }, + { + "version": "2.1.9", + "tag": "@microsoft/loader-load-themed-styles_v2.1.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.84` to `^2.0.85`" + } + ] + } + }, + { + "version": "2.1.8", + "tag": "@microsoft/loader-load-themed-styles_v2.1.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.83` to `^2.0.84`" + } + ] + } + }, + { + "version": "2.1.7", + "tag": "@microsoft/loader-load-themed-styles_v2.1.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.82` to `^2.0.83`" + } + ] + } + }, + { + "version": "2.1.6", + "tag": "@microsoft/loader-load-themed-styles_v2.1.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.81` to `^2.0.82`" + } + ] + } + }, + { + "version": "2.1.5", + "tag": "@microsoft/loader-load-themed-styles_v2.1.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.80` to `^2.0.81`" + } + ] + } + }, + { + "version": "2.1.4", + "tag": "@microsoft/loader-load-themed-styles_v2.1.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.79` to `^2.0.80`" + } + ] + } + }, + { + "version": "2.1.3", + "tag": "@microsoft/loader-load-themed-styles_v2.1.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.78` to `^2.0.79`" + } + ] + } + }, + { + "version": "2.1.2", + "tag": "@microsoft/loader-load-themed-styles_v2.1.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.77` to `^2.0.78`" + } + ] + } + }, + { + "version": "2.1.1", + "tag": "@microsoft/loader-load-themed-styles_v2.1.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.76` to `^2.0.77`" + } + ] + } + }, + { + "version": "2.1.0", + "tag": "@microsoft/loader-load-themed-styles_v2.1.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.76`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.75` to `^2.0.76`" + } + ] + } + }, + { + "version": "2.0.73", + "tag": "@microsoft/loader-load-themed-styles_v2.0.73", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.75`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.74` to `^2.0.75`" + } + ] + } + }, + { + "version": "2.0.72", + "tag": "@microsoft/loader-load-themed-styles_v2.0.72", + "date": "Fri, 01 Sep 2023 04:53:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.74`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.73` to `^2.0.74`" + } + ] + } + }, + { + "version": "2.0.71", + "tag": "@microsoft/loader-load-themed-styles_v2.0.71", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.73`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.72` to `^2.0.73`" + } + ] + } + }, + { + "version": "2.0.70", + "tag": "@microsoft/loader-load-themed-styles_v2.0.70", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.72`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.71` to `^2.0.72`" + } + ] + } + }, + { + "version": "2.0.69", + "tag": "@microsoft/loader-load-themed-styles_v2.0.69", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.71`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.70` to `^2.0.71`" + } + ] + } + }, + { + "version": "2.0.68", + "tag": "@microsoft/loader-load-themed-styles_v2.0.68", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.69` to `^2.0.70`" + } + ] + } + }, + { + "version": "2.0.67", + "tag": "@microsoft/loader-load-themed-styles_v2.0.67", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.68` to `^2.0.69`" + } + ] + } + }, + { + "version": "2.0.66", + "tag": "@microsoft/loader-load-themed-styles_v2.0.66", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.67` to `^2.0.68`" + } + ] + } + }, + { + "version": "2.0.65", + "tag": "@microsoft/loader-load-themed-styles_v2.0.65", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.66` to `^2.0.67`" + } + ] + } + }, + { + "version": "2.0.64", + "tag": "@microsoft/loader-load-themed-styles_v2.0.64", + "date": "Mon, 17 Jul 2023 15:20:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.66`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.65` to `^2.0.66`" + } + ] + } + }, + { + "version": "2.0.63", + "tag": "@microsoft/loader-load-themed-styles_v2.0.63", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.64` to `^2.0.65`" + } + ] + } + }, + { + "version": "2.0.62", + "tag": "@microsoft/loader-load-themed-styles_v2.0.62", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.63` to `^2.0.64`" + } + ] + } + }, + { + "version": "2.0.61", + "tag": "@microsoft/loader-load-themed-styles_v2.0.61", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.62` to `^2.0.63`" + } + ] + } + }, + { + "version": "2.0.60", + "tag": "@microsoft/loader-load-themed-styles_v2.0.60", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.61` to `^2.0.62`" + } + ] + } + }, + { + "version": "2.0.59", + "tag": "@microsoft/loader-load-themed-styles_v2.0.59", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.60` to `^2.0.61`" + } + ] + } + }, + { + "version": "2.0.58", + "tag": "@microsoft/loader-load-themed-styles_v2.0.58", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.59` to `^2.0.60`" + } + ] + } + }, + { + "version": "2.0.57", + "tag": "@microsoft/loader-load-themed-styles_v2.0.57", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.58` to `^2.0.59`" + } + ] + } + }, + { + "version": "2.0.56", + "tag": "@microsoft/loader-load-themed-styles_v2.0.56", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.57` to `^2.0.58`" + } + ] + } + }, + { + "version": "2.0.55", + "tag": "@microsoft/loader-load-themed-styles_v2.0.55", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.57`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.56` to `^2.0.57`" + } + ] + } + }, + { + "version": "2.0.54", + "tag": "@microsoft/loader-load-themed-styles_v2.0.54", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.55` to `^2.0.56`" + } + ] + } + }, + { + "version": "2.0.53", + "tag": "@microsoft/loader-load-themed-styles_v2.0.53", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.54` to `^2.0.55`" + } + ] + } + }, + { + "version": "2.0.52", + "tag": "@microsoft/loader-load-themed-styles_v2.0.52", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.53` to `^2.0.54`" + } + ] + } + }, + { + "version": "2.0.51", + "tag": "@microsoft/loader-load-themed-styles_v2.0.51", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.52` to `^2.0.53`" + } + ] + } + }, + { + "version": "2.0.50", + "tag": "@microsoft/loader-load-themed-styles_v2.0.50", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.51` to `^2.0.52`" + } + ] + } + }, + { + "version": "2.0.49", + "tag": "@microsoft/loader-load-themed-styles_v2.0.49", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.50` to `^2.0.51`" + } + ] + } + }, + { + "version": "2.0.48", + "tag": "@microsoft/loader-load-themed-styles_v2.0.48", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.49` to `^2.0.50`" + } + ] + } + }, + { + "version": "2.0.47", + "tag": "@microsoft/loader-load-themed-styles_v2.0.47", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.48` to `^2.0.49`" + } + ] + } + }, + { + "version": "2.0.46", + "tag": "@microsoft/loader-load-themed-styles_v2.0.46", + "date": "Wed, 07 Jun 2023 22:45:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.48`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.47` to `^2.0.48`" + } + ] + } + }, + { + "version": "2.0.45", + "tag": "@microsoft/loader-load-themed-styles_v2.0.45", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.46` to `^2.0.47`" + } + ] + } + }, + { + "version": "2.0.44", + "tag": "@microsoft/loader-load-themed-styles_v2.0.44", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.45` to `^2.0.46`" + } + ] + } + }, + { + "version": "2.0.43", + "tag": "@microsoft/loader-load-themed-styles_v2.0.43", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.44` to `^2.0.45`" + } + ] + } + }, + { + "version": "2.0.42", + "tag": "@microsoft/loader-load-themed-styles_v2.0.42", + "date": "Fri, 02 Jun 2023 00:24:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.44`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.43` to `^2.0.44`" + } + ] + } + }, + { + "version": "2.0.41", + "tag": "@microsoft/loader-load-themed-styles_v2.0.41", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.42` to `^2.0.43`" + } + ] + } + }, + { + "version": "2.0.40", + "tag": "@microsoft/loader-load-themed-styles_v2.0.40", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.42`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.41` to `^2.0.42`" + } + ] + } + }, + { + "version": "2.0.39", + "tag": "@microsoft/loader-load-themed-styles_v2.0.39", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.40` to `^2.0.41`" + } + ] + } + }, + { + "version": "2.0.38", + "tag": "@microsoft/loader-load-themed-styles_v2.0.38", + "date": "Thu, 11 May 2023 00:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.40`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.39` to `^2.0.40`" + } + ] + } + }, + { + "version": "2.0.37", + "tag": "@microsoft/loader-load-themed-styles_v2.0.37", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.38` to `^2.0.39`" + } + ] + } + }, + { + "version": "2.0.36", + "tag": "@microsoft/loader-load-themed-styles_v2.0.36", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.37` to `^2.0.38`" + } + ] + } + }, + { + "version": "2.0.35", + "tag": "@microsoft/loader-load-themed-styles_v2.0.35", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.36` to `^2.0.37`" + } + ] + } + }, + { + "version": "2.0.34", + "tag": "@microsoft/loader-load-themed-styles_v2.0.34", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.35` to `^2.0.36`" + } + ] + } + }, + { + "version": "2.0.33", + "tag": "@microsoft/loader-load-themed-styles_v2.0.33", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.35`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.34` to `^2.0.35`" + } + ] + } + }, + { + "version": "2.0.32", + "tag": "@microsoft/loader-load-themed-styles_v2.0.32", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.34`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.33` to `^2.0.34`" + } + ] + } + }, + { + "version": "2.0.31", + "tag": "@microsoft/loader-load-themed-styles_v2.0.31", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.33`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.32` to `^2.0.33`" + } + ] + } + }, + { + "version": "2.0.30", + "tag": "@microsoft/loader-load-themed-styles_v2.0.30", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.31` to `^2.0.32`" + } + ] + } + }, + { + "version": "2.0.29", + "tag": "@microsoft/loader-load-themed-styles_v2.0.29", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.30` to `^2.0.31`" + } + ] + } + }, + { + "version": "2.0.28", + "tag": "@microsoft/loader-load-themed-styles_v2.0.28", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.30`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.29` to `^2.0.30`" + } + ] + } + }, + { + "version": "2.0.27", + "tag": "@microsoft/loader-load-themed-styles_v2.0.27", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.29`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.28` to `^2.0.29`" + } + ] + } + }, + { + "version": "2.0.26", + "tag": "@microsoft/loader-load-themed-styles_v2.0.26", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.27` to `^2.0.28`" + } + ] + } + }, + { + "version": "2.0.25", + "tag": "@microsoft/loader-load-themed-styles_v2.0.25", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.26` to `^2.0.27`" + } + ] + } + }, + { + "version": "2.0.24", + "tag": "@microsoft/loader-load-themed-styles_v2.0.24", + "date": "Tue, 31 Jan 2023 01:23:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.26`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.25` to `^2.0.26`" + } + ] + } + }, + { + "version": "2.0.23", + "tag": "@microsoft/loader-load-themed-styles_v2.0.23", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.24` to `^2.0.25`" + } + ] + } + }, + { + "version": "2.0.22", + "tag": "@microsoft/loader-load-themed-styles_v2.0.22", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.23` to `^2.0.24`" + } + ] + } + }, + { + "version": "2.0.21", + "tag": "@microsoft/loader-load-themed-styles_v2.0.21", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.22` to `^2.0.23`" + } + ] + } + }, + { + "version": "2.0.20", + "tag": "@microsoft/loader-load-themed-styles_v2.0.20", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.21` to `^2.0.22`" + } + ] + } + }, + { + "version": "2.0.19", + "tag": "@microsoft/loader-load-themed-styles_v2.0.19", + "date": "Sun, 22 Jan 2023 20:37:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.20` to `^2.0.21`" + } + ] + } + }, + { + "version": "2.0.18", + "tag": "@microsoft/loader-load-themed-styles_v2.0.18", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.19` to `^2.0.20`" + } + ] + } + }, + { + "version": "2.0.17", + "tag": "@microsoft/loader-load-themed-styles_v2.0.17", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.18` to `^2.0.19`" + } + ] + } + }, + { + "version": "2.0.16", + "tag": "@microsoft/loader-load-themed-styles_v2.0.16", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.17` to `^2.0.18`" + } + ] + } + }, + { + "version": "2.0.15", + "tag": "@microsoft/loader-load-themed-styles_v2.0.15", + "date": "Fri, 02 Dec 2022 01:15:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.16` to `^2.0.17`" + } + ] + } + }, + { + "version": "2.0.14", + "tag": "@microsoft/loader-load-themed-styles_v2.0.14", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.16`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.15` to `^2.0.16`" + } + ] + } + }, + { + "version": "2.0.13", + "tag": "@microsoft/loader-load-themed-styles_v2.0.13", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.14` to `^2.0.15`" + } + ] + } + }, + { + "version": "2.0.12", + "tag": "@microsoft/loader-load-themed-styles_v2.0.12", + "date": "Mon, 14 Nov 2022 05:15:01 GMT", + "comments": { + "patch": [ + { + "comment": "Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq" + } + ] + } + }, + { + "version": "2.0.11", + "tag": "@microsoft/loader-load-themed-styles_v2.0.11", + "date": "Tue, 08 Nov 2022 01:20:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.13` to `^2.0.14`" + } + ] + } + }, + { + "version": "2.0.10", + "tag": "@microsoft/loader-load-themed-styles_v2.0.10", + "date": "Wed, 26 Oct 2022 15:16:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.13`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.12` to `^2.0.13`" + } + ] + } + }, + { + "version": "2.0.9", + "tag": "@microsoft/loader-load-themed-styles_v2.0.9", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.11` to `^2.0.12`" + } + ] + } + }, + { + "version": "2.0.8", + "tag": "@microsoft/loader-load-themed-styles_v2.0.8", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.10` to `^2.0.11`" + } + ] + } + }, + { + "version": "2.0.7", + "tag": "@microsoft/loader-load-themed-styles_v2.0.7", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.9` to `^2.0.10`" + } + ] + } + }, + { + "version": "2.0.6", + "tag": "@microsoft/loader-load-themed-styles_v2.0.6", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.8` to `^2.0.9`" + } + ] + } + }, + { + "version": "2.0.5", + "tag": "@microsoft/loader-load-themed-styles_v2.0.5", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.7` to `^2.0.8`" + } + ] + } + }, + { + "version": "2.0.4", + "tag": "@microsoft/loader-load-themed-styles_v2.0.4", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.6` to `^2.0.7`" + } + ] + } + }, + { + "version": "2.0.3", + "tag": "@microsoft/loader-load-themed-styles_v2.0.3", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.5` to `^2.0.6`" + } + ] + } + }, + { + "version": "2.0.2", + "tag": "@microsoft/loader-load-themed-styles_v2.0.2", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.4` to `^2.0.5`" + } + ] + } + }, + { + "version": "2.0.1", + "tag": "@microsoft/loader-load-themed-styles_v2.0.1", + "date": "Sat, 08 Oct 2022 02:30:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.3` to `^2.0.4`" + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@microsoft/loader-load-themed-styles_v2.0.0", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "major": [ + { + "comment": "Make @microsoft/load-themed-styles a peer dependency." + }, + { + "comment": "Remove the namedExport option." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^1 || ^2` to `^2.0.3`" + } + ] + } + }, + { + "version": "1.9.180", + "tag": "@microsoft/loader-load-themed-styles_v1.9.180", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "1.9.179", + "tag": "@microsoft/loader-load-themed-styles_v1.9.179", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "1.9.178", + "tag": "@microsoft/loader-load-themed-styles_v1.9.178", + "date": "Thu, 15 Sep 2022 00:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "1.9.177", + "tag": "@microsoft/loader-load-themed-styles_v1.9.177", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.295`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "1.9.176", + "tag": "@microsoft/loader-load-themed-styles_v1.9.176", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.294`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "1.9.175", + "tag": "@microsoft/loader-load-themed-styles_v1.9.175", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.293`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "1.9.174", + "tag": "@microsoft/loader-load-themed-styles_v1.9.174", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.292`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "1.9.173", + "tag": "@microsoft/loader-load-themed-styles_v1.9.173", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.291`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "1.9.172", + "tag": "@microsoft/loader-load-themed-styles_v1.9.172", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.290`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "1.9.171", + "tag": "@microsoft/loader-load-themed-styles_v1.9.171", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.289`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "1.9.170", + "tag": "@microsoft/loader-load-themed-styles_v1.9.170", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.288`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "1.9.169", + "tag": "@microsoft/loader-load-themed-styles_v1.9.169", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.287`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "1.9.168", + "tag": "@microsoft/loader-load-themed-styles_v1.9.168", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.286`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "1.9.167", + "tag": "@microsoft/loader-load-themed-styles_v1.9.167", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.285`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "1.9.166", + "tag": "@microsoft/loader-load-themed-styles_v1.9.166", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.284`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "1.9.165", + "tag": "@microsoft/loader-load-themed-styles_v1.9.165", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.283`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "1.9.164", + "tag": "@microsoft/loader-load-themed-styles_v1.9.164", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.282`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "1.9.163", + "tag": "@microsoft/loader-load-themed-styles_v1.9.163", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.281`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "1.9.162", + "tag": "@microsoft/loader-load-themed-styles_v1.9.162", + "date": "Fri, 08 Jul 2022 15:17:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.280`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "1.9.161", + "tag": "@microsoft/loader-load-themed-styles_v1.9.161", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.279`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "1.9.160", + "tag": "@microsoft/loader-load-themed-styles_v1.9.160", + "date": "Thu, 30 Jun 2022 04:48:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.278`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "1.9.159", + "tag": "@microsoft/loader-load-themed-styles_v1.9.159", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.277`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "1.9.158", + "tag": "@microsoft/loader-load-themed-styles_v1.9.158", + "date": "Tue, 28 Jun 2022 03:30:39 GMT", + "comments": { + "patch": [ + { + "comment": "Include a missing optional peer dependency on @types/webpack." + } + ] + } + }, + { + "version": "1.9.157", + "tag": "@microsoft/loader-load-themed-styles_v1.9.157", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.276`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "1.9.156", + "tag": "@microsoft/loader-load-themed-styles_v1.9.156", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.275`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "1.9.155", + "tag": "@microsoft/loader-load-themed-styles_v1.9.155", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.274`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "1.9.154", + "tag": "@microsoft/loader-load-themed-styles_v1.9.154", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.273`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "1.9.153", + "tag": "@microsoft/loader-load-themed-styles_v1.9.153", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.272`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "1.9.152", + "tag": "@microsoft/loader-load-themed-styles_v1.9.152", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.271`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "1.9.151", + "tag": "@microsoft/loader-load-themed-styles_v1.9.151", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.270`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "1.9.150", + "tag": "@microsoft/loader-load-themed-styles_v1.9.150", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Bump @types/webpack" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.269`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "1.9.149", + "tag": "@microsoft/loader-load-themed-styles_v1.9.149", + "date": "Tue, 07 Jun 2022 09:37:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.268`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "1.9.148", + "tag": "@microsoft/loader-load-themed-styles_v1.9.148", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.267`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "1.9.147", + "tag": "@microsoft/loader-load-themed-styles_v1.9.147", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.266`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "1.9.146", + "tag": "@microsoft/loader-load-themed-styles_v1.9.146", + "date": "Wed, 18 May 2022 15:10:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.265`" + } + ] + } + }, + { + "version": "1.9.145", + "tag": "@microsoft/loader-load-themed-styles_v1.9.145", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.264`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "1.9.144", + "tag": "@microsoft/loader-load-themed-styles_v1.9.144", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.263`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "1.9.143", + "tag": "@microsoft/loader-load-themed-styles_v1.9.143", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.262`" + } + ] + } + }, + { + "version": "1.9.142", + "tag": "@microsoft/loader-load-themed-styles_v1.9.142", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.261`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "1.9.141", + "tag": "@microsoft/loader-load-themed-styles_v1.9.141", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.260`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "1.9.140", + "tag": "@microsoft/loader-load-themed-styles_v1.9.140", + "date": "Sat, 23 Apr 2022 02:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.259`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "1.9.139", + "tag": "@microsoft/loader-load-themed-styles_v1.9.139", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.258`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "1.9.138", + "tag": "@microsoft/loader-load-themed-styles_v1.9.138", + "date": "Wed, 13 Apr 2022 15:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.257`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "1.9.137", + "tag": "@microsoft/loader-load-themed-styles_v1.9.137", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.256`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "1.9.136", + "tag": "@microsoft/loader-load-themed-styles_v1.9.136", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.255`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "1.9.135", + "tag": "@microsoft/loader-load-themed-styles_v1.9.135", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.254`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "1.9.134", + "tag": "@microsoft/loader-load-themed-styles_v1.9.134", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.253`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "1.9.133", + "tag": "@microsoft/loader-load-themed-styles_v1.9.133", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.252`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "1.9.132", + "tag": "@microsoft/loader-load-themed-styles_v1.9.132", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.251`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "1.9.131", + "tag": "@microsoft/loader-load-themed-styles_v1.9.131", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.250`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "1.9.130", + "tag": "@microsoft/loader-load-themed-styles_v1.9.130", + "date": "Sat, 19 Mar 2022 08:05:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.249`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "1.9.129", + "tag": "@microsoft/loader-load-themed-styles_v1.9.129", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.248`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "1.9.128", + "tag": "@microsoft/loader-load-themed-styles_v1.9.128", + "date": "Tue, 15 Feb 2022 01:39:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.247`" + } + ] + } + }, + { + "version": "1.9.127", + "tag": "@microsoft/loader-load-themed-styles_v1.9.127", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.246`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "1.9.126", + "tag": "@microsoft/loader-load-themed-styles_v1.9.126", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.245`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "1.9.125", + "tag": "@microsoft/loader-load-themed-styles_v1.9.125", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.244`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "1.9.124", + "tag": "@microsoft/loader-load-themed-styles_v1.9.124", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.243`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "1.9.123", + "tag": "@microsoft/loader-load-themed-styles_v1.9.123", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.242`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "1.9.122", + "tag": "@microsoft/loader-load-themed-styles_v1.9.122", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.241`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "1.9.121", + "tag": "@microsoft/loader-load-themed-styles_v1.9.121", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.240`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "1.9.120", + "tag": "@microsoft/loader-load-themed-styles_v1.9.120", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.239`" + } + ] + } + }, + { + "version": "1.9.119", + "tag": "@microsoft/loader-load-themed-styles_v1.9.119", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.238`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "1.9.118", + "tag": "@microsoft/loader-load-themed-styles_v1.9.118", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.237`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "1.9.117", + "tag": "@microsoft/loader-load-themed-styles_v1.9.117", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.236`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "1.9.116", + "tag": "@microsoft/loader-load-themed-styles_v1.9.116", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.235`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "1.9.115", + "tag": "@microsoft/loader-load-themed-styles_v1.9.115", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.234`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "1.9.114", + "tag": "@microsoft/loader-load-themed-styles_v1.9.114", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.233`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "1.9.113", + "tag": "@microsoft/loader-load-themed-styles_v1.9.113", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.232`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "1.9.112", + "tag": "@microsoft/loader-load-themed-styles_v1.9.112", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.231`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "1.9.111", + "tag": "@microsoft/loader-load-themed-styles_v1.9.111", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.230`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "1.9.110", + "tag": "@microsoft/loader-load-themed-styles_v1.9.110", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.229`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "1.9.109", + "tag": "@microsoft/loader-load-themed-styles_v1.9.109", + "date": "Thu, 28 Oct 2021 23:48:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.228`" + } + ] + } + }, + { + "version": "1.9.108", + "tag": "@microsoft/loader-load-themed-styles_v1.9.108", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.227`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "1.9.107", + "tag": "@microsoft/loader-load-themed-styles_v1.9.107", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.226`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "1.9.106", + "tag": "@microsoft/loader-load-themed-styles_v1.9.106", + "date": "Wed, 13 Oct 2021 15:09:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.225`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "1.9.105", + "tag": "@microsoft/loader-load-themed-styles_v1.9.105", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.224`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "1.9.104", + "tag": "@microsoft/loader-load-themed-styles_v1.9.104", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.223`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "1.9.103", + "tag": "@microsoft/loader-load-themed-styles_v1.9.103", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.222`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "1.9.102", + "tag": "@microsoft/loader-load-themed-styles_v1.9.102", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.221`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "1.9.101", + "tag": "@microsoft/loader-load-themed-styles_v1.9.101", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.220`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "1.9.100", + "tag": "@microsoft/loader-load-themed-styles_v1.9.100", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.219`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "1.9.99", + "tag": "@microsoft/loader-load-themed-styles_v1.9.99", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.218`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "1.9.98", + "tag": "@microsoft/loader-load-themed-styles_v1.9.98", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.217`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "1.9.97", + "tag": "@microsoft/loader-load-themed-styles_v1.9.97", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.216`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "1.9.96", + "tag": "@microsoft/loader-load-themed-styles_v1.9.96", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.215`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "1.9.95", + "tag": "@microsoft/loader-load-themed-styles_v1.9.95", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.214`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "1.9.94", + "tag": "@microsoft/loader-load-themed-styles_v1.9.94", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.213`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "1.9.93", + "tag": "@microsoft/loader-load-themed-styles_v1.9.93", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.212`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "1.9.92", + "tag": "@microsoft/loader-load-themed-styles_v1.9.92", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.211`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "1.9.91", + "tag": "@microsoft/loader-load-themed-styles_v1.9.91", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.210`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "1.9.90", + "tag": "@microsoft/loader-load-themed-styles_v1.9.90", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.209`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "1.9.89", + "tag": "@microsoft/loader-load-themed-styles_v1.9.89", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.208`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "1.9.88", + "tag": "@microsoft/loader-load-themed-styles_v1.9.88", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.207`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "1.9.87", + "tag": "@microsoft/loader-load-themed-styles_v1.9.87", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.206`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "1.9.86", + "tag": "@microsoft/loader-load-themed-styles_v1.9.86", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.205`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "1.9.85", + "tag": "@microsoft/loader-load-themed-styles_v1.9.85", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.204`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "1.9.84", + "tag": "@microsoft/loader-load-themed-styles_v1.9.84", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.203`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "1.9.83", + "tag": "@microsoft/loader-load-themed-styles_v1.9.83", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.202`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "1.9.82", + "tag": "@microsoft/loader-load-themed-styles_v1.9.82", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.201`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "1.9.81", + "tag": "@microsoft/loader-load-themed-styles_v1.9.81", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.200`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.9.80", + "tag": "@microsoft/loader-load-themed-styles_v1.9.80", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.199`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "1.9.79", + "tag": "@microsoft/loader-load-themed-styles_v1.9.79", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.198`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "1.9.78", + "tag": "@microsoft/loader-load-themed-styles_v1.9.78", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.197`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "1.9.77", + "tag": "@microsoft/loader-load-themed-styles_v1.9.77", + "date": "Tue, 27 Jul 2021 22:31:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.196`" + } + ] + } + }, + { + "version": "1.9.76", + "tag": "@microsoft/loader-load-themed-styles_v1.9.76", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.195`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "1.9.75", + "tag": "@microsoft/loader-load-themed-styles_v1.9.75", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.194`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "1.9.74", + "tag": "@microsoft/loader-load-themed-styles_v1.9.74", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.193`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "1.9.73", + "tag": "@microsoft/loader-load-themed-styles_v1.9.73", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.192`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "1.9.72", + "tag": "@microsoft/loader-load-themed-styles_v1.9.72", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.191`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.9.71", + "tag": "@microsoft/loader-load-themed-styles_v1.9.71", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.190`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "1.9.70", + "tag": "@microsoft/loader-load-themed-styles_v1.9.70", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.189`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.9.69", + "tag": "@microsoft/loader-load-themed-styles_v1.9.69", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.188`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.9.68", + "tag": "@microsoft/loader-load-themed-styles_v1.9.68", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.187`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.9.67", + "tag": "@microsoft/loader-load-themed-styles_v1.9.67", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.186`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.9.66", + "tag": "@microsoft/loader-load-themed-styles_v1.9.66", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.185`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.9.65", + "tag": "@microsoft/loader-load-themed-styles_v1.9.65", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.184`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.9.64", + "tag": "@microsoft/loader-load-themed-styles_v1.9.64", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.183`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.9.63", + "tag": "@microsoft/loader-load-themed-styles_v1.9.63", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.182`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.9.62", + "tag": "@microsoft/loader-load-themed-styles_v1.9.62", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.181`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "1.9.61", + "tag": "@microsoft/loader-load-themed-styles_v1.9.61", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.180`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "1.9.60", + "tag": "@microsoft/loader-load-themed-styles_v1.9.60", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.179`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "1.9.59", + "tag": "@microsoft/loader-load-themed-styles_v1.9.59", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.178`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "1.9.58", + "tag": "@microsoft/loader-load-themed-styles_v1.9.58", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.177`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "1.9.57", + "tag": "@microsoft/loader-load-themed-styles_v1.9.57", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.176`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "1.9.56", + "tag": "@microsoft/loader-load-themed-styles_v1.9.56", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.175`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "1.9.55", + "tag": "@microsoft/loader-load-themed-styles_v1.9.55", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.174`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "1.9.54", + "tag": "@microsoft/loader-load-themed-styles_v1.9.54", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.173`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "1.9.53", + "tag": "@microsoft/loader-load-themed-styles_v1.9.53", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.172`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "1.9.52", + "tag": "@microsoft/loader-load-themed-styles_v1.9.52", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.171`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "1.9.51", + "tag": "@microsoft/loader-load-themed-styles_v1.9.51", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.170`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "1.9.50", + "tag": "@microsoft/loader-load-themed-styles_v1.9.50", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.169`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "1.9.49", + "tag": "@microsoft/loader-load-themed-styles_v1.9.49", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.168`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "1.9.48", + "tag": "@microsoft/loader-load-themed-styles_v1.9.48", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.167`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "1.9.47", + "tag": "@microsoft/loader-load-themed-styles_v1.9.47", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.166`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "1.9.46", + "tag": "@microsoft/loader-load-themed-styles_v1.9.46", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.165`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "1.9.45", + "tag": "@microsoft/loader-load-themed-styles_v1.9.45", + "date": "Fri, 23 Apr 2021 15:11:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.164`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "1.9.44", + "tag": "@microsoft/loader-load-themed-styles_v1.9.44", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.163`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "1.9.43", + "tag": "@microsoft/loader-load-themed-styles_v1.9.43", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.162`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "1.9.42", + "tag": "@microsoft/loader-load-themed-styles_v1.9.42", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.161`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "1.9.41", + "tag": "@microsoft/loader-load-themed-styles_v1.9.41", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.160`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "1.9.40", + "tag": "@microsoft/loader-load-themed-styles_v1.9.40", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.159`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "1.9.39", + "tag": "@microsoft/loader-load-themed-styles_v1.9.39", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.158`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "1.9.38", + "tag": "@microsoft/loader-load-themed-styles_v1.9.38", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.157`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "1.9.37", + "tag": "@microsoft/loader-load-themed-styles_v1.9.37", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.156`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "1.9.36", + "tag": "@microsoft/loader-load-themed-styles_v1.9.36", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.155`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "1.9.35", + "tag": "@microsoft/loader-load-themed-styles_v1.9.35", + "date": "Mon, 29 Mar 2021 05:02:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.154`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "1.9.34", + "tag": "@microsoft/loader-load-themed-styles_v1.9.34", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.153`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "1.9.33", + "tag": "@microsoft/loader-load-themed-styles_v1.9.33", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.152`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "1.9.32", + "tag": "@microsoft/loader-load-themed-styles_v1.9.32", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.151`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "1.9.31", + "tag": "@microsoft/loader-load-themed-styles_v1.9.31", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.9.30", + "tag": "@microsoft/loader-load-themed-styles_v1.9.30", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.150`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.9.29", + "tag": "@microsoft/loader-load-themed-styles_v1.9.29", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.149`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "1.9.28", + "tag": "@microsoft/loader-load-themed-styles_v1.9.28", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.148`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "1.9.27", + "tag": "@microsoft/loader-load-themed-styles_v1.9.27", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.147`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "1.9.26", + "tag": "@microsoft/loader-load-themed-styles_v1.9.26", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.146`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "1.9.25", + "tag": "@microsoft/loader-load-themed-styles_v1.9.25", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.145`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "1.9.24", + "tag": "@microsoft/loader-load-themed-styles_v1.9.24", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.144`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "1.9.23", + "tag": "@microsoft/loader-load-themed-styles_v1.9.23", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.143`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "1.9.22", + "tag": "@microsoft/loader-load-themed-styles_v1.9.22", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.142`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "1.9.21", + "tag": "@microsoft/loader-load-themed-styles_v1.9.21", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.141`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "1.9.20", + "tag": "@microsoft/loader-load-themed-styles_v1.9.20", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.140`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "1.9.19", + "tag": "@microsoft/loader-load-themed-styles_v1.9.19", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.139`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "1.9.18", + "tag": "@microsoft/loader-load-themed-styles_v1.9.18", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.138`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "1.9.17", + "tag": "@microsoft/loader-load-themed-styles_v1.9.17", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.137`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "1.9.16", + "tag": "@microsoft/loader-load-themed-styles_v1.9.16", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.136`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "1.9.15", + "tag": "@microsoft/loader-load-themed-styles_v1.9.15", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.135`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "1.9.14", + "tag": "@microsoft/loader-load-themed-styles_v1.9.14", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.134`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "1.9.13", + "tag": "@microsoft/loader-load-themed-styles_v1.9.13", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.133`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "1.9.12", + "tag": "@microsoft/loader-load-themed-styles_v1.9.12", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.132`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "1.9.11", + "tag": "@microsoft/loader-load-themed-styles_v1.9.11", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.131`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "1.9.10", + "tag": "@microsoft/loader-load-themed-styles_v1.9.10", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.130`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "1.9.9", + "tag": "@microsoft/loader-load-themed-styles_v1.9.9", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.129`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "1.9.8", + "tag": "@microsoft/loader-load-themed-styles_v1.9.8", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.128`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "1.9.7", + "tag": "@microsoft/loader-load-themed-styles_v1.9.7", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.127`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "1.9.6", + "tag": "@microsoft/loader-load-themed-styles_v1.9.6", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.126`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "1.9.5", + "tag": "@microsoft/loader-load-themed-styles_v1.9.5", + "date": "Tue, 03 Nov 2020 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.125`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "1.9.4", + "tag": "@microsoft/loader-load-themed-styles_v1.9.4", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.124`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "1.9.3", + "tag": "@microsoft/loader-load-themed-styles_v1.9.3", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.123`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "1.9.2", + "tag": "@microsoft/loader-load-themed-styles_v1.9.2", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.122`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "1.9.1", + "tag": "@microsoft/loader-load-themed-styles_v1.9.1", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.121`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "1.9.0", + "tag": "@microsoft/loader-load-themed-styles_v1.9.0", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to ~4.44.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.120`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "1.8.86", + "tag": "@microsoft/loader-load-themed-styles_v1.8.86", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.119`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "1.8.85", + "tag": "@microsoft/loader-load-themed-styles_v1.8.85", + "date": "Tue, 27 Oct 2020 15:10:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.118`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "1.8.84", + "tag": "@microsoft/loader-load-themed-styles_v1.8.84", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.117`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "1.8.83", + "tag": "@microsoft/loader-load-themed-styles_v1.8.83", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.116`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "1.8.82", + "tag": "@microsoft/loader-load-themed-styles_v1.8.82", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.115`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "1.8.81", + "tag": "@microsoft/loader-load-themed-styles_v1.8.81", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.114`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "1.8.80", + "tag": "@microsoft/loader-load-themed-styles_v1.8.80", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.113`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "1.8.79", + "tag": "@microsoft/loader-load-themed-styles_v1.8.79", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.112`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "1.8.78", + "tag": "@microsoft/loader-load-themed-styles_v1.8.78", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.111`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "1.8.77", + "tag": "@microsoft/loader-load-themed-styles_v1.8.77", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "1.8.76", + "tag": "@microsoft/loader-load-themed-styles_v1.8.76", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "1.8.75", + "tag": "@microsoft/loader-load-themed-styles_v1.8.75", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.108`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "1.8.74", + "tag": "@microsoft/loader-load-themed-styles_v1.8.74", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.107`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "1.8.73", + "tag": "@microsoft/loader-load-themed-styles_v1.8.73", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.106`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "1.8.72", + "tag": "@microsoft/loader-load-themed-styles_v1.8.72", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.105`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "1.8.71", + "tag": "@microsoft/loader-load-themed-styles_v1.8.71", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "1.8.70", + "tag": "@microsoft/loader-load-themed-styles_v1.8.70", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.103`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "1.8.69", + "tag": "@microsoft/loader-load-themed-styles_v1.8.69", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.102`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "1.8.68", + "tag": "@microsoft/loader-load-themed-styles_v1.8.68", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.101`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "1.8.67", + "tag": "@microsoft/loader-load-themed-styles_v1.8.67", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.100`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "1.8.66", + "tag": "@microsoft/loader-load-themed-styles_v1.8.66", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.99`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "1.8.65", + "tag": "@microsoft/loader-load-themed-styles_v1.8.65", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.98`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "1.8.64", + "tag": "@microsoft/loader-load-themed-styles_v1.8.64", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.97`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "1.8.63", + "tag": "@microsoft/loader-load-themed-styles_v1.8.63", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.96`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "1.8.62", + "tag": "@microsoft/loader-load-themed-styles_v1.8.62", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.95`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "1.8.61", + "tag": "@microsoft/loader-load-themed-styles_v1.8.61", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.94`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "1.8.60", + "tag": "@microsoft/loader-load-themed-styles_v1.8.60", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "1.8.59", + "tag": "@microsoft/loader-load-themed-styles_v1.8.59", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "1.8.58", + "tag": "@microsoft/loader-load-themed-styles_v1.8.58", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "1.8.57", + "tag": "@microsoft/loader-load-themed-styles_v1.8.57", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.90`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "1.8.56", + "tag": "@microsoft/loader-load-themed-styles_v1.8.56", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.89`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "1.8.55", + "tag": "@microsoft/loader-load-themed-styles_v1.8.55", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "1.8.54", + "tag": "@microsoft/loader-load-themed-styles_v1.8.54", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "1.8.53", + "tag": "@microsoft/loader-load-themed-styles_v1.8.53", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.86`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "1.8.52", + "tag": "@microsoft/loader-load-themed-styles_v1.8.52", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.85`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "1.8.51", + "tag": "@microsoft/loader-load-themed-styles_v1.8.51", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "1.8.50", + "tag": "@microsoft/loader-load-themed-styles_v1.8.50", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "1.8.49", + "tag": "@microsoft/loader-load-themed-styles_v1.8.49", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "1.8.48", + "tag": "@microsoft/loader-load-themed-styles_v1.8.48", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "1.8.47", + "tag": "@microsoft/loader-load-themed-styles_v1.8.47", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.80`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "1.8.46", + "tag": "@microsoft/loader-load-themed-styles_v1.8.46", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "1.8.45", + "tag": "@microsoft/loader-load-themed-styles_v1.8.45", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.78`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "1.8.44", + "tag": "@microsoft/loader-load-themed-styles_v1.8.44", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.77`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "1.8.43", + "tag": "@microsoft/loader-load-themed-styles_v1.8.43", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.76`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "1.8.42", + "tag": "@microsoft/loader-load-themed-styles_v1.8.42", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "1.8.41", + "tag": "@microsoft/loader-load-themed-styles_v1.8.41", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.74`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "1.8.40", + "tag": "@microsoft/loader-load-themed-styles_v1.8.40", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.73`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "1.8.39", + "tag": "@microsoft/loader-load-themed-styles_v1.8.39", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "1.8.38", + "tag": "@microsoft/loader-load-themed-styles_v1.8.38", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "1.8.37", + "tag": "@microsoft/loader-load-themed-styles_v1.8.37", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.70`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.8.36", + "tag": "@microsoft/loader-load-themed-styles_v1.8.36", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "1.8.35", + "tag": "@microsoft/loader-load-themed-styles_v1.8.35", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "1.8.34", + "tag": "@microsoft/loader-load-themed-styles_v1.8.34", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.67`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "1.8.33", + "tag": "@microsoft/loader-load-themed-styles_v1.8.33", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `1.10.66`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + } + ] + } + }, + { + "version": "1.8.32", + "tag": "@microsoft/loader-load-themed-styles_v1.8.32", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.64` to `1.10.65`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + } + ] + } + }, + { + "version": "1.8.31", + "tag": "@microsoft/loader-load-themed-styles_v1.8.31", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.63` to `1.10.64`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + } + ] + } + }, + { + "version": "1.8.30", + "tag": "@microsoft/loader-load-themed-styles_v1.8.30", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.62` to `1.10.63`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "1.8.29", + "tag": "@microsoft/loader-load-themed-styles_v1.8.29", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.61` to `1.10.62`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "1.8.28", + "tag": "@microsoft/loader-load-themed-styles_v1.8.28", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.60` to `1.10.61`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "1.8.27", + "tag": "@microsoft/loader-load-themed-styles_v1.8.27", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.59` to `1.10.60`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "1.8.26", + "tag": "@microsoft/loader-load-themed-styles_v1.8.26", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.58` to `1.10.59`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "1.8.25", + "tag": "@microsoft/loader-load-themed-styles_v1.8.25", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.57` to `1.10.58`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + } + ] + } + }, + { + "version": "1.8.24", + "tag": "@microsoft/loader-load-themed-styles_v1.8.24", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.56` to `1.10.57`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + } + ] + } + }, + { + "version": "1.8.23", + "tag": "@microsoft/loader-load-themed-styles_v1.8.23", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.55` to `1.10.56`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + } + ] + } + }, + { + "version": "1.8.22", + "tag": "@microsoft/loader-load-themed-styles_v1.8.22", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.54` to `1.10.55`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + } + ] + } + }, + { + "version": "1.8.21", + "tag": "@microsoft/loader-load-themed-styles_v1.8.21", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.53` to `1.10.54`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + } + ] + } + }, + { + "version": "1.8.20", + "tag": "@microsoft/loader-load-themed-styles_v1.8.20", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.52` to `1.10.53`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + } + ] + } + }, + { + "version": "1.8.19", + "tag": "@microsoft/loader-load-themed-styles_v1.8.19", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.51` to `1.10.52`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "1.8.18", + "tag": "@microsoft/loader-load-themed-styles_v1.8.18", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.50` to `1.10.51`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + } + ] + } + }, + { + "version": "1.8.17", + "tag": "@microsoft/loader-load-themed-styles_v1.8.17", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.49` to `1.10.50`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + } + ] + } + }, + { + "version": "1.8.16", + "tag": "@microsoft/loader-load-themed-styles_v1.8.16", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.48` to `1.10.49`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + } + ] + } + }, + { + "version": "1.8.15", + "tag": "@microsoft/loader-load-themed-styles_v1.8.15", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.47` to `1.10.48`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + } + ] + } + }, + { + "version": "1.8.14", + "tag": "@microsoft/loader-load-themed-styles_v1.8.14", + "date": "Tue, 19 May 2020 15:08:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.46` to `1.10.47`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + } + ] + } + }, + { + "version": "1.8.13", + "tag": "@microsoft/loader-load-themed-styles_v1.8.13", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.45` to `1.10.46`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + } + ] + } + }, + { + "version": "1.8.12", + "tag": "@microsoft/loader-load-themed-styles_v1.8.12", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.44` to `1.10.45`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + } + ] + } + }, + { + "version": "1.8.11", + "tag": "@microsoft/loader-load-themed-styles_v1.8.11", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.43` to `1.10.44`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "1.8.10", + "tag": "@microsoft/loader-load-themed-styles_v1.8.10", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.42` to `1.10.43`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "1.8.9", + "tag": "@microsoft/loader-load-themed-styles_v1.8.9", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.41` to `1.10.42`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + } + ] + } + }, + { + "version": "1.8.8", + "tag": "@microsoft/loader-load-themed-styles_v1.8.8", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.40` to `1.10.41`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + } + ] + } + }, + { + "version": "1.8.7", + "tag": "@microsoft/loader-load-themed-styles_v1.8.7", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `1.10.39` to `1.10.40`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "1.8.6", "tag": "@microsoft/loader-load-themed-styles_v1.8.6", diff --git a/webpack/loader-load-themed-styles/CHANGELOG.md b/webpack/loader-load-themed-styles/CHANGELOG.md index 58905cc2938..e966f19e215 100644 --- a/webpack/loader-load-themed-styles/CHANGELOG.md +++ b/webpack/loader-load-themed-styles/CHANGELOG.md @@ -1,36 +1,2335 @@ # Change Log - @microsoft/loader-load-themed-styles -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 2.1.118 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 2.1.117 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 2.1.116 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 2.1.115 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 2.1.114 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 2.1.113 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 2.1.112 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 2.1.111 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 2.1.110 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 2.1.109 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 2.1.108 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 2.1.107 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 2.1.106 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 2.1.105 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 2.1.104 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 2.1.103 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 2.1.102 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 2.1.101 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 2.1.100 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 2.1.99 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 2.1.98 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 2.1.97 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 2.1.96 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 2.1.95 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 2.1.94 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 2.1.93 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 2.1.92 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 2.1.91 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 2.1.90 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 2.1.89 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 2.1.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 2.1.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 2.1.86 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 2.1.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 2.1.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 2.1.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 2.1.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 2.1.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 2.1.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 2.1.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 2.1.78 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 2.1.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 2.1.76 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 2.1.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 2.1.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 2.1.73 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 2.1.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 2.1.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 2.1.70 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 2.1.69 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 2.1.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 2.1.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 2.1.66 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 2.1.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 2.1.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 2.1.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 2.1.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 2.1.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 2.1.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 2.1.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 2.1.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 2.1.57 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 2.1.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 2.1.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 2.1.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 2.1.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 2.1.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 2.1.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 2.1.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 2.1.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 2.1.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 2.1.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 2.1.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 2.1.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 2.1.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 2.1.43 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 2.1.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 2.1.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 2.1.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 2.1.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 2.1.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 2.1.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 2.1.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 2.1.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 2.1.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 2.1.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 2.1.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 2.1.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 2.1.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 2.1.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 2.1.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 2.1.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 2.1.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 2.1.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 2.1.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 2.1.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 2.1.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 2.1.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 2.1.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 2.1.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 2.1.18 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 2.1.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 2.1.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 2.1.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 2.1.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 2.1.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 2.1.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 2.1.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 2.1.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 2.1.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 2.1.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 2.1.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 2.1.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 2.1.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 2.1.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 2.1.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 2.1.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 2.1.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 2.1.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 2.0.73 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 2.0.72 +Fri, 01 Sep 2023 04:53:58 GMT + +_Version update only_ + +## 2.0.71 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 2.0.70 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 2.0.69 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 2.0.68 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 2.0.67 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 2.0.66 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 2.0.65 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 2.0.64 +Mon, 17 Jul 2023 15:20:25 GMT + +_Version update only_ + +## 2.0.63 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 2.0.62 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 2.0.61 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 2.0.60 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 2.0.59 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 2.0.58 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 2.0.57 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 2.0.56 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 2.0.55 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 2.0.54 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 2.0.53 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 2.0.52 +Tue, 13 Jun 2023 01:49:01 GMT + +_Version update only_ + +## 2.0.51 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 2.0.50 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 2.0.49 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 2.0.48 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 2.0.47 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 2.0.46 +Wed, 07 Jun 2023 22:45:16 GMT + +_Version update only_ + +## 2.0.45 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 2.0.44 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 2.0.43 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 2.0.42 +Fri, 02 Jun 2023 00:24:45 GMT + +_Version update only_ + +## 2.0.41 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 2.0.40 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 2.0.39 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 2.0.38 +Thu, 11 May 2023 00:17:21 GMT + +_Version update only_ + +## 2.0.37 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 2.0.36 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 2.0.35 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 2.0.34 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 2.0.33 +Thu, 20 Apr 2023 15:16:55 GMT + +_Version update only_ + +## 2.0.32 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 2.0.31 +Fri, 07 Apr 2023 22:19:21 GMT + +_Version update only_ + +## 2.0.30 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 2.0.29 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 2.0.28 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 2.0.27 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 2.0.26 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 2.0.25 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 2.0.24 +Tue, 31 Jan 2023 01:23:23 GMT + +_Version update only_ + +## 2.0.23 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 2.0.22 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 2.0.21 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 2.0.20 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 2.0.19 +Sun, 22 Jan 2023 20:37:08 GMT + +_Version update only_ + +## 2.0.18 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 2.0.17 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 2.0.16 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 2.0.15 +Fri, 02 Dec 2022 01:15:42 GMT + +_Version update only_ + +## 2.0.14 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 2.0.13 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 2.0.12 +Mon, 14 Nov 2022 05:15:01 GMT + +### Patches + +- Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq + +## 2.0.11 +Tue, 08 Nov 2022 01:20:55 GMT + +_Version update only_ + +## 2.0.10 +Wed, 26 Oct 2022 15:16:29 GMT + +_Version update only_ + +## 2.0.9 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 2.0.8 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 2.0.7 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 2.0.6 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 2.0.5 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 2.0.4 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 2.0.3 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 2.0.2 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 2.0.1 +Sat, 08 Oct 2022 02:30:08 GMT + +_Version update only_ + +## 2.0.0 +Thu, 29 Sep 2022 07:13:06 GMT + +### Breaking changes + +- Make @microsoft/load-themed-styles a peer dependency. +- Remove the namedExport option. + +## 1.9.180 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 1.9.179 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 1.9.178 +Thu, 15 Sep 2022 00:18:51 GMT + +_Version update only_ + +## 1.9.177 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.9.176 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.9.175 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.9.174 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.9.173 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.9.172 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.9.171 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.9.170 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 1.9.169 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.9.168 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.9.167 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 1.9.166 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.9.165 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 1.9.164 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.9.163 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 1.9.162 +Fri, 08 Jul 2022 15:17:46 GMT + +_Version update only_ + +## 1.9.161 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.9.160 +Thu, 30 Jun 2022 04:48:53 GMT + +_Version update only_ + +## 1.9.159 +Tue, 28 Jun 2022 22:47:13 GMT + +_Version update only_ + +## 1.9.158 +Tue, 28 Jun 2022 03:30:39 GMT + +### Patches + +- Include a missing optional peer dependency on @types/webpack. + +## 1.9.157 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.9.156 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.9.155 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.9.154 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.9.153 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.9.152 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 1.9.151 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.9.150 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Bump @types/webpack + +## 1.9.149 +Tue, 07 Jun 2022 09:37:04 GMT + +_Version update only_ + +## 1.9.148 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 1.9.147 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 1.9.146 +Wed, 18 May 2022 15:10:56 GMT + +_Version update only_ + +## 1.9.145 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.9.144 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.9.143 +Fri, 06 May 2022 18:54:42 GMT + +_Version update only_ + +## 1.9.142 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.9.141 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.9.140 +Sat, 23 Apr 2022 02:13:06 GMT + +_Version update only_ + +## 1.9.139 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.9.138 +Wed, 13 Apr 2022 15:12:40 GMT + +_Version update only_ + +## 1.9.137 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.9.136 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.9.135 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.9.134 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.9.133 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.9.132 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.9.131 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.9.130 +Sat, 19 Mar 2022 08:05:37 GMT + +_Version update only_ + +## 1.9.129 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 1.9.128 +Tue, 15 Feb 2022 01:39:45 GMT + +_Version update only_ + +## 1.9.127 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 1.9.126 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 1.9.125 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 1.9.124 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 1.9.123 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.9.122 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.9.121 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 1.9.120 +Fri, 10 Dec 2021 01:09:33 GMT + +_Version update only_ + +## 1.9.119 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.9.118 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.9.117 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.9.116 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 1.9.115 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 1.9.114 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.9.113 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 1.9.112 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.9.111 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.9.110 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.9.109 +Thu, 28 Oct 2021 23:48:23 GMT + +_Version update only_ + +## 1.9.108 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.9.107 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.9.106 +Wed, 13 Oct 2021 15:09:54 GMT + +_Version update only_ + +## 1.9.105 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.9.104 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.9.103 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.9.102 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.9.101 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 1.9.100 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.9.99 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 1.9.98 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.9.97 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.9.96 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 1.9.95 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.9.94 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.9.93 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.9.92 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.9.91 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.9.90 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.9.89 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.9.88 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.9.87 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 1.9.86 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.9.85 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.9.84 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.9.83 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 1.9.82 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.9.81 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 1.9.80 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 1.9.79 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.9.78 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.9.77 +Tue, 27 Jul 2021 22:31:02 GMT + +_Version update only_ + +## 1.9.76 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.9.75 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.9.74 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.9.73 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.9.72 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.9.71 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.9.70 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.9.69 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.9.68 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.9.67 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.9.66 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.9.65 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.9.64 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.9.63 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 1.9.62 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.9.61 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 1.9.60 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.9.59 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.9.58 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.9.57 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.9.56 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.9.55 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.9.54 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 1.9.53 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.9.52 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.9.51 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 1.9.50 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.9.49 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.9.48 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.9.47 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.9.46 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 1.9.45 +Fri, 23 Apr 2021 15:11:20 GMT + +_Version update only_ + +## 1.9.44 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 1.9.43 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.9.42 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 1.9.41 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.9.40 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 1.9.39 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.9.38 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.9.37 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.9.36 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.9.35 +Mon, 29 Mar 2021 05:02:06 GMT + +_Version update only_ + +## 1.9.34 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 1.9.33 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.9.32 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.9.31 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 1.9.30 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 1.9.29 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 1.9.28 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 1.9.27 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 1.9.26 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 1.9.25 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 1.9.24 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 1.9.23 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 1.9.22 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 1.9.21 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 1.9.20 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 1.9.19 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 1.9.18 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 1.9.17 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 1.9.16 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 1.9.15 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 1.9.14 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 1.9.13 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 1.9.12 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 1.9.11 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 1.9.10 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 1.9.9 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 1.9.8 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 1.9.7 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 1.9.6 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 1.9.5 +Tue, 03 Nov 2020 01:11:18 GMT + +_Version update only_ + +## 1.9.4 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 1.9.3 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 1.9.2 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 1.9.1 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 1.9.0 +Thu, 29 Oct 2020 00:11:33 GMT + +### Minor changes + +- Update Webpack dependency to ~4.44.2 + +## 1.8.86 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 1.8.85 +Tue, 27 Oct 2020 15:10:13 GMT + +_Version update only_ + +## 1.8.84 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 1.8.83 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 1.8.82 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 1.8.81 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 1.8.80 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 1.8.79 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 1.8.78 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 1.8.77 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 1.8.76 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 1.8.75 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 1.8.74 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 1.8.73 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 1.8.72 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 1.8.71 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 1.8.70 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 1.8.69 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 1.8.68 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 1.8.67 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 1.8.66 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 1.8.65 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 1.8.64 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 1.8.63 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 1.8.62 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 1.8.61 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 1.8.60 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 1.8.59 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 1.8.58 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 1.8.57 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 1.8.56 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 1.8.55 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 1.8.54 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 1.8.53 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 1.8.52 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 1.8.51 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 1.8.50 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 1.8.49 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 1.8.48 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 1.8.47 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 1.8.46 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 1.8.45 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 1.8.44 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 1.8.43 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 1.8.42 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 1.8.41 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 1.8.40 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 1.8.39 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 1.8.38 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 1.8.37 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 1.8.36 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 1.8.35 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 1.8.34 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 1.8.33 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 1.8.32 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 1.8.31 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 1.8.30 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 1.8.29 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 1.8.28 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 1.8.27 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 1.8.26 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 1.8.25 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 1.8.24 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 1.8.23 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 1.8.22 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 1.8.21 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 1.8.20 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 1.8.19 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 1.8.18 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 1.8.17 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 1.8.16 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 1.8.15 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 1.8.14 +Tue, 19 May 2020 15:08:19 GMT + +_Version update only_ + +## 1.8.13 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 1.8.12 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 1.8.11 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 1.8.10 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 1.8.9 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 1.8.8 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 1.8.7 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 1.8.6 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 1.8.5 Tue, 17 Mar 2020 23:55:58 GMT -*Version update only* +_Version update only_ ## 1.8.4 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 1.8.3 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 1.8.2 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 1.8.1 Tue, 21 Jan 2020 21:56:13 GMT -*Version update only* +_Version update only_ ## 1.8.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -42,112 +2341,112 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 1.7.211 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 1.7.210 Tue, 14 Jan 2020 01:34:15 GMT -*Version update only* +_Version update only_ ## 1.7.209 Sat, 11 Jan 2020 05:18:23 GMT -*Version update only* +_Version update only_ ## 1.7.208 Fri, 10 Jan 2020 03:07:47 GMT -*Version update only* +_Version update only_ ## 1.7.207 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 1.7.206 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 1.7.205 Mon, 23 Dec 2019 16:08:05 GMT -*Version update only* +_Version update only_ ## 1.7.204 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 1.7.203 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 1.7.202 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 1.7.201 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 1.7.200 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 1.7.199 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 1.7.198 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 1.7.197 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 1.7.196 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 1.7.195 Fri, 25 Oct 2019 15:08:54 GMT -*Version update only* +_Version update only_ ## 1.7.194 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 1.7.193 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 1.7.192 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 1.7.191 Sun, 06 Oct 2019 00:27:39 GMT -*Version update only* +_Version update only_ ## 1.7.190 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 1.7.189 Sun, 29 Sep 2019 23:56:29 GMT @@ -159,522 +2458,522 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 1.7.188 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 1.7.187 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 1.7.186 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 1.7.185 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 1.7.184 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 1.7.183 Tue, 10 Sep 2019 22:32:23 GMT -*Version update only* +_Version update only_ ## 1.7.182 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 1.7.181 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 1.7.180 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 1.7.179 Wed, 04 Sep 2019 01:43:31 GMT -*Version update only* +_Version update only_ ## 1.7.178 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 1.7.177 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 1.7.176 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 1.7.175 Thu, 08 Aug 2019 00:49:05 GMT -*Version update only* +_Version update only_ ## 1.7.174 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 1.7.173 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 1.7.172 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 1.7.171 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 1.7.170 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 1.7.169 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 1.7.168 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 1.7.167 Mon, 08 Jul 2019 19:12:18 GMT -*Version update only* +_Version update only_ ## 1.7.166 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 1.7.165 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 1.7.164 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.7.163 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 1.7.162 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 1.7.161 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 1.7.160 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 1.7.159 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 1.7.158 Thu, 09 May 2019 19:12:31 GMT -*Version update only* +_Version update only_ ## 1.7.157 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 1.7.156 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 1.7.155 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 1.7.154 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 1.7.153 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 1.7.152 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 1.7.151 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 1.7.150 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 1.7.149 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 1.7.148 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 1.7.147 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 1.7.146 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 1.7.145 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 1.7.144 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 1.7.143 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 1.7.142 Tue, 26 Mar 2019 20:54:18 GMT -*Version update only* +_Version update only_ ## 1.7.141 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 1.7.140 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 1.7.139 Thu, 21 Mar 2019 01:15:32 GMT -*Version update only* +_Version update only_ ## 1.7.138 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 1.7.137 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 1.7.136 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 1.7.135 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 1.7.134 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 1.7.133 Mon, 11 Mar 2019 16:13:36 GMT -*Version update only* +_Version update only_ ## 1.7.132 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 1.7.131 Mon, 04 Mar 2019 17:13:19 GMT -*Version update only* +_Version update only_ ## 1.7.130 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 1.7.129 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 1.7.128 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 1.7.127 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 1.7.126 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 1.7.125 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 1.7.124 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 1.7.123 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 1.7.122 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 1.7.121 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 1.7.120 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 1.7.119 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 1.7.118 Fri, 14 Dec 2018 20:51:51 GMT -*Version update only* +_Version update only_ ## 1.7.117 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 1.7.116 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 1.7.115 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 1.7.114 Fri, 07 Dec 2018 17:04:56 GMT -*Version update only* +_Version update only_ ## 1.7.113 Mon, 03 Dec 2018 17:04:06 GMT -*Version update only* +_Version update only_ ## 1.7.112 Fri, 30 Nov 2018 23:34:58 GMT -*Version update only* +_Version update only_ ## 1.7.111 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 1.7.110 Thu, 29 Nov 2018 00:35:39 GMT -*Version update only* +_Version update only_ ## 1.7.109 Wed, 28 Nov 2018 19:29:53 GMT -*Version update only* +_Version update only_ ## 1.7.108 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 1.7.107 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 1.7.106 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 1.7.105 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 1.7.104 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 1.7.103 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 1.7.102 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 1.7.101 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 1.7.100 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 1.7.99 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 1.7.98 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 1.7.97 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 1.7.96 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 1.7.95 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 1.7.94 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 1.7.93 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 1.7.92 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 1.7.91 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 1.7.90 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 1.7.89 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 1.7.88 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 1.7.87 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 1.7.86 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 1.7.85 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 1.7.84 Sun, 07 Oct 2018 06:15:56 GMT @@ -686,42 +2985,42 @@ Sun, 07 Oct 2018 06:15:56 GMT ## 1.7.83 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 1.7.82 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 1.7.81 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 1.7.80 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 1.7.79 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 1.7.78 Thu, 20 Sep 2018 23:57:21 GMT -*Version update only* +_Version update only_ ## 1.7.77 Tue, 18 Sep 2018 21:04:55 GMT -*Version update only* +_Version update only_ ## 1.7.76 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 1.7.75 Thu, 06 Sep 2018 01:25:26 GMT @@ -733,52 +3032,52 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 1.7.74 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 1.7.73 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 1.7.72 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 1.7.71 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 1.7.70 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 1.7.69 Thu, 30 Aug 2018 04:42:01 GMT -*Version update only* +_Version update only_ ## 1.7.68 Thu, 30 Aug 2018 04:24:41 GMT -*Version update only* +_Version update only_ ## 1.7.67 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 1.7.66 Wed, 29 Aug 2018 20:34:33 GMT -*Version update only* +_Version update only_ ## 1.7.65 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 1.7.64 Thu, 23 Aug 2018 18:18:53 GMT @@ -790,102 +3089,102 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 1.7.63 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 1.7.62 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 1.7.61 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 1.7.60 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 1.7.59 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 1.7.58 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 1.7.57 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 1.7.56 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 1.7.55 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 1.7.54 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 1.7.53 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 1.7.52 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 1.7.51 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 1.7.50 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 1.7.49 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 1.7.48 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 1.7.47 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 1.7.46 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 1.7.45 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 1.7.44 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 1.7.43 Tue, 05 Jun 2018 21:04:43 GMT @@ -897,52 +3196,52 @@ Tue, 05 Jun 2018 21:04:43 GMT ## 1.7.42 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 1.7.41 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 1.7.40 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 1.7.39 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 1.7.38 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 1.7.37 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 1.7.36 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 1.7.35 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 1.7.34 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 1.7.33 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 1.7.32 Fri, 06 Apr 2018 16:03:14 GMT @@ -954,62 +3253,62 @@ Fri, 06 Apr 2018 16:03:14 GMT ## 1.7.31 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 1.7.30 Mon, 02 Apr 2018 16:05:24 GMT -*Version update only* +_Version update only_ ## 1.7.29 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 1.7.28 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 1.7.27 Sun, 25 Mar 2018 01:26:19 GMT -*Version update only* +_Version update only_ ## 1.7.26 Fri, 23 Mar 2018 00:34:53 GMT -*Version update only* +_Version update only_ ## 1.7.25 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 1.7.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 1.7.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 1.7.22 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 1.7.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 1.7.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 1.7.19 Mon, 12 Mar 2018 20:36:19 GMT @@ -1021,52 +3320,52 @@ Mon, 12 Mar 2018 20:36:19 GMT ## 1.7.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 1.7.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 1.7.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 1.7.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 1.7.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 1.7.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 1.7.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 1.7.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.7.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.7.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 1.7.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1078,37 +3377,37 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 1.7.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 1.7.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 1.7.5 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 1.7.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.7.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 1.7.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 1.7.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 1.7.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1120,57 +3419,57 @@ Wed, 10 Jan 2018 20:40:01 GMT ## 1.6.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 1.6.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 1.6.11 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 1.6.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 1.6.9 Tue, 12 Dec 2017 03:33:26 GMT -*Version update only* +_Version update only_ ## 1.6.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 1.6.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 1.6.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 1.6.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 1.6.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 1.6.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 1.6.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -1182,7 +3481,7 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 1.6.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 1.6.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -1201,7 +3500,7 @@ Thu, 21 Sep 2017 20:34:26 GMT ## 1.5.1 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 1.5.0 Wed, 30 Aug 2017 22:08:21 GMT @@ -1213,12 +3512,12 @@ Wed, 30 Aug 2017 22:08:21 GMT ## 1.4.3 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 1.4.2 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 1.4.1 Tue, 15 Aug 2017 19:04:14 GMT @@ -1237,7 +3536,7 @@ Tue, 08 Aug 2017 23:10:36 GMT ## 1.3.1 Fri, 21 Jul 2017 01:02:30 GMT -*Version update only* +_Version update only_ ## 1.3.0 Wed, 28 Jun 2017 22:32:16 GMT diff --git a/webpack/loader-load-themed-styles/README.md b/webpack/loader-load-themed-styles/README.md index 3066d6b5b7b..67725483c28 100644 --- a/webpack/loader-load-themed-styles/README.md +++ b/webpack/loader-load-themed-styles/README.md @@ -1,4 +1,4 @@ -# load-themed-styles loader for webpack +# @microsoft/loader-load-themed-styles ## Installation @@ -6,7 +6,7 @@ ## Overview -This simple loader wraps the loading of CSS in script equivalent +This simple Webpack loader that wraps the loading of CSS in script equivalent to `require("load-themed-styles").loadStyles( /* css text */ )`. It is designed to be a replacement for style-loader. @@ -28,7 +28,6 @@ var css = require("@microsoft/loader-load-themed-styles!css!./file.css"); { loader: "@microsoft/loader-load-themed-styles", // creates style nodes from JS strings options: { - namedExport: 'default', async: false } }, @@ -60,22 +59,6 @@ var css = require("@microsoft/loader-load-themed-styles!css!./file.css"); ## Options -### `namedExport` (string, defaults to `undefined`) - -By default, css modules will be exported as a commonjs export: - -```js -module.exports = { ... }; -``` - -To override this, you may provide a named export to export to a specifically named thing. This -is useful in exporting as the default in es6 module import scenarios. For example, providing -"default" for the named export will output this: - -```js -module.exports.default = { ... }; -``` - ### `async` (boolean, defaults to `false`) By default, `@microsoft/load-themed-styles` loads styles synchronously. This can have adverse performance effects @@ -83,6 +66,11 @@ if many styles are loaded in quick succession. If the `async` option is set to ` is called with the second parameter set to `true`, directing the function to debounce style loading causing fewer changes to the DOM. -## License -MIT (http://www.opensource.org/licenses/mit-license.php) +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/loader-load-themed-styles/CHANGELOG.md) - Find + out what's new in the latest version + +`@microsoft/loader-load-themed-styles` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/loader-load-themed-styles/config/jest.config.json b/webpack/loader-load-themed-styles/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/loader-load-themed-styles/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/loader-load-themed-styles/config/rig.json b/webpack/loader-load-themed-styles/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/loader-load-themed-styles/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/webpack/loader-load-themed-styles/eslint.config.js b/webpack/loader-load-themed-styles/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/loader-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 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/webpack/loader-load-themed-styles/gulpfile.js b/webpack/loader-load-themed-styles/gulpfile.js deleted file mode 100644 index 296eccbf8a6..00000000000 --- a/webpack/loader-load-themed-styles/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/webpack/loader-load-themed-styles/package.json b/webpack/loader-load-themed-styles/package.json index 96bd5e2d441..dfe29c03a4d 100644 --- a/webpack/loader-load-themed-styles/package.json +++ b/webpack/loader-load-themed-styles/package.json @@ -1,30 +1,38 @@ { "name": "@microsoft/loader-load-themed-styles", - "version": "1.8.6", + "version": "2.1.118", "description": "This simple loader wraps the loading of CSS in script equivalent to `require('load-themed-styles').loadStyles( /* css text */ )`. It is designed to be a replacement for style-loader.", "main": "lib/index.js", "typings": "lib/index.d.ts", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/webpack/loader-load-themed-styles" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/loader-load-themed-styles" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + } + }, + "peerDependencies": { + "@types/webpack": "^4", + "@microsoft/load-themed-styles": "^2.1.22" }, "dependencies": { - "@microsoft/load-themed-styles": "1.10.39", - "loader-utils": "~1.1.0" + "loader-utils": "1.4.2" }, "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", + "@microsoft/load-themed-styles": "workspace:*", + "@rushstack/heft": "workspace:*", "@types/loader-utils": "1.1.3", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "@types/webpack": "4.39.8", - "chai": "~3.5.0", - "gulp": "~4.0.2" + "@types/webpack": "4.41.32", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/webpack/loader-load-themed-styles/src/LoadThemedStylesLoader.ts b/webpack/loader-load-themed-styles/src/LoadThemedStylesLoader.ts index 5c2374ff537..a11d8d90f70 100644 --- a/webpack/loader-load-themed-styles/src/LoadThemedStylesLoader.ts +++ b/webpack/loader-load-themed-styles/src/LoadThemedStylesLoader.ts @@ -7,7 +7,7 @@ * @packageDocumentation */ -import { loader } from 'webpack'; +import type { loader } from 'webpack'; import loaderUtils = require('loader-utils'); const loadedThemedStylesPath: string = require.resolve('@microsoft/load-themed-styles'); @@ -18,12 +18,6 @@ const loadedThemedStylesPath: string = require.resolve('@microsoft/load-themed-s * @public */ export interface ILoadThemedStylesLoaderOptions { - /** - * If this parameter is specified, override the name of the value exported from this loader. This is useful in - * exporting as the default in es6 module import scenarios. See the README for more information. - */ - namedExport?: string; - /** * If this parameter is set to "true," the "loadAsync" parameter is set to true in the call to loadStyles. * Defaults to false. @@ -63,16 +57,13 @@ export class LoadThemedStylesLoader { } public static pitch(this: loader.LoaderContext, remainingRequest: string): string { - const { - namedExport, - async = false - }: ILoadThemedStylesLoaderOptions = loaderUtils.getOptions(this) || {}; - - let exportName: string = 'module.exports'; - if (namedExport) { - exportName += `.${namedExport}`; + const options: ILoadThemedStylesLoaderOptions = loaderUtils.getOptions(this) || {}; + if ((options as Record).namedExport) { + throw new Error('The "namedExport" option has been removed.'); } + const { async = false } = options; + return [ `var content = require(${loaderUtils.stringifyRequest(this, '!!' + remainingRequest)});`, `var loader = require(${JSON.stringify(LoadThemedStylesLoader._loadedThemedStylesPath)});`, @@ -82,8 +73,7 @@ export class LoadThemedStylesLoader { '// add the styles to the DOM', `for (var i = 0; i < content.length; i++) loader.loadStyles(content[i][1], ${async === true});`, '', - `if(content.locals) ${exportName} = content.locals;` + 'if(content.locals) module.exports = content.locals;' ].join('\n'); } - } diff --git a/webpack/loader-load-themed-styles/src/test/LoadThemedStylesLoader.test.ts b/webpack/loader-load-themed-styles/src/test/LoadThemedStylesLoader.test.ts index 33956537a83..c0c687b572e 100644 --- a/webpack/loader-load-themed-styles/src/test/LoadThemedStylesLoader.test.ts +++ b/webpack/loader-load-themed-styles/src/test/LoadThemedStylesLoader.test.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 webpack = require('webpack'); -import { assert } from 'chai'; -import { LoadThemedStylesLoader } from './../LoadThemedStylesLoader'; +import { LoadThemedStylesLoader } from '../LoadThemedStylesLoader'; import LoadThemedStylesMock = require('./testData/LoadThemedStylesMock'); function wrapResult(loaderResult: string): string { @@ -13,7 +12,7 @@ function wrapResult(loaderResult: string): string { module;`; } -describe('LoadThemedStylesLoader', () => { +describe(LoadThemedStylesLoader.name, () => { beforeEach(() => { LoadThemedStylesLoader.resetLoadedThemedStylesPath(); LoadThemedStylesMock.loadedData = []; @@ -21,124 +20,117 @@ describe('LoadThemedStylesLoader', () => { }); it('follows the Webpack loader interface', () => { - assert.isDefined(LoadThemedStylesLoader); - assert.isDefined(LoadThemedStylesLoader.pitch); + expect(LoadThemedStylesLoader).toBeDefined(); + expect(LoadThemedStylesLoader.pitch).toBeDefined(); - assert.throws(() => new LoadThemedStylesLoader()); + expect(() => new LoadThemedStylesLoader()).toThrow(); }); it('it correctly resolves load-themed-styles', () => { const expectedPath: string = require.resolve('@microsoft/load-themed-styles'); - assert.equal(LoadThemedStylesLoader.loadedThemedStylesPath, expectedPath); + expect(LoadThemedStylesLoader.loadedThemedStylesPath).toEqual(expectedPath); }); it('it inserts the resolved load-themed-styles path', () => { const expectedPath: string = require.resolve('@microsoft/load-themed-styles'); - const loaderResult: string = LoadThemedStylesLoader.pitch.call({}, ''); - assert.isNotNull(loaderResult.indexOf(expectedPath)); + const loaderResult: string = LoadThemedStylesLoader.pitch.call({} as webpack.loader.LoaderContext, ''); + expect(loaderResult.indexOf(expectedPath)).not.toBeNull(); }); it('it allows for override of load-themed-styles path', () => { let expectedPath: string = './testData/LoadThemedStylesMock'; LoadThemedStylesLoader.loadedThemedStylesPath = expectedPath; - assert.equal(LoadThemedStylesLoader.loadedThemedStylesPath, expectedPath); + expect(LoadThemedStylesLoader.loadedThemedStylesPath).toEqual(expectedPath); LoadThemedStylesLoader.resetLoadedThemedStylesPath(); expectedPath = require.resolve('@microsoft/load-themed-styles'); - assert.equal(LoadThemedStylesLoader.loadedThemedStylesPath, expectedPath); + expect(LoadThemedStylesLoader.loadedThemedStylesPath).toEqual(expectedPath); }); it('it inserts the overridden load-themed-styles path', () => { const expectedPath: string = './testData/LoadThemedStylesMock'; - const loaderResult: string = LoadThemedStylesLoader.pitch.call({}, ''); - assert.isNotNull(loaderResult.indexOf(expectedPath)); + const loaderResult: string = LoadThemedStylesLoader.pitch.call({} as webpack.loader.LoaderContext, ''); + expect(loaderResult.indexOf(expectedPath)).not.toBeNull(); }); it('correctly calls loadStyles in load-themed-styles with a module reference', () => { LoadThemedStylesLoader.loadedThemedStylesPath = './testData/LoadThemedStylesMock'; - let loaderResult: string = LoadThemedStylesLoader.pitch.call({}, './testData/MockStyle1'); + let loaderResult: string = LoadThemedStylesLoader.pitch.call( + {} as webpack.loader.LoaderContext, + './testData/MockStyle1' + ); loaderResult = loaderResult.replace(/require\(\"!!/, 'require("'); loaderResult = wrapResult(loaderResult); const returnedModule: { exports: string } = eval(loaderResult); // eslint-disable-line no-eval - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1); - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1); - assert.equal(LoadThemedStylesMock.loadedData.length, 2); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[0]); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[1]); - assert.equal(LoadThemedStylesMock.calledWithAsync.length, 2); - assert.equal(returnedModule.exports, 'locals'); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData).toHaveLength(2); + expect(LoadThemedStylesMock.calledWithAsync[0]).toEqual(false); + expect(LoadThemedStylesMock.calledWithAsync[1]).toEqual(false); + expect(LoadThemedStylesMock.calledWithAsync).toHaveLength(2); + expect(returnedModule.exports).toEqual('locals'); }); it('correctly calls loadStyles in load-themed-styles with a string reference', () => { LoadThemedStylesLoader.loadedThemedStylesPath = './testData/LoadThemedStylesMock'; - let loaderResult: string = LoadThemedStylesLoader.pitch.call({}, './testData/MockStyle2'); + let loaderResult: string = LoadThemedStylesLoader.pitch.call( + {} as webpack.loader.LoaderContext, + './testData/MockStyle2' + ); loaderResult = loaderResult.replace(/require\(\"!!/, 'require("'); loaderResult = wrapResult(loaderResult); const returnedModule: { exports: string } = eval(loaderResult); // eslint-disable-line no-eval - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('styles') !== -1); - assert.equal(LoadThemedStylesMock.loadedData.length, 1); - assert.deepEqual(returnedModule.exports, {}); - }); - - it('correctly handles the namedExport option', () => { - LoadThemedStylesLoader.loadedThemedStylesPath = './testData/LoadThemedStylesMock'; - - const query: {} = { namedExport: 'default' }; - let loaderResult: string = LoadThemedStylesLoader.pitch.call({ query }, './testData/MockStyle1'); - loaderResult = loaderResult.replace(/require\(\"!!/, 'require("'); - loaderResult = wrapResult(loaderResult); - - const returnedModule: { exports: string } = eval(loaderResult); // eslint-disable-line no-eval - - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1); - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1); - assert.equal(LoadThemedStylesMock.loadedData.length, 2); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[0]); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[1]); - assert.equal(LoadThemedStylesMock.calledWithAsync.length, 2); - assert.deepEqual(returnedModule.exports, { default: 'locals' }); + expect(LoadThemedStylesMock.loadedData.indexOf('styles') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData).toHaveLength(1); + expect(returnedModule.exports).toEqual({}); }); it('correctly handles the async option set to "true"', () => { LoadThemedStylesLoader.loadedThemedStylesPath = './testData/LoadThemedStylesMock'; const query: {} = { async: true }; - let loaderResult: string = LoadThemedStylesLoader.pitch.call({ query }, './testData/MockStyle1'); + let loaderResult: string = LoadThemedStylesLoader.pitch.call( + { query } as webpack.loader.LoaderContext, + './testData/MockStyle1' + ); loaderResult = loaderResult.replace(/require\(\"!!/, 'require("'); loaderResult = wrapResult(loaderResult); const returnedModule: { exports: string } = eval(loaderResult); // eslint-disable-line no-eval - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1); - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1); - assert.equal(LoadThemedStylesMock.loadedData.length, 2); - assert.isTrue(LoadThemedStylesMock.calledWithAsync[0]); - assert.isTrue(LoadThemedStylesMock.calledWithAsync[1]); - assert.equal(LoadThemedStylesMock.calledWithAsync.length, 2); - assert.equal(returnedModule.exports, 'locals'); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData).toHaveLength(2); + expect(LoadThemedStylesMock.calledWithAsync[0]).toEqual(true); + expect(LoadThemedStylesMock.calledWithAsync[1]).toEqual(true); + expect(LoadThemedStylesMock.calledWithAsync).toHaveLength(2); + expect(returnedModule.exports).toEqual('locals'); }); it('correctly handles the async option set to a non-boolean', () => { LoadThemedStylesLoader.loadedThemedStylesPath = './testData/LoadThemedStylesMock'; - let loaderResult: string = LoadThemedStylesLoader.pitch.call({}, './testData/MockStyle1'); + let loaderResult: string = LoadThemedStylesLoader.pitch.call( + {} as webpack.loader.LoaderContext, + './testData/MockStyle1' + ); loaderResult = loaderResult.replace(/require\(\"!!/, 'require("'); loaderResult = wrapResult(loaderResult); const returnedModule: { exports: string } = eval(loaderResult); // eslint-disable-line no-eval - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1); - assert.isTrue(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1); - assert.equal(LoadThemedStylesMock.loadedData.length, 2); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[0]); - assert.isFalse(LoadThemedStylesMock.calledWithAsync[1]); - assert.equal(LoadThemedStylesMock.calledWithAsync.length, 2); - assert.equal(returnedModule.exports, 'locals'); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 1') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData.indexOf('STYLE 2') !== -1).toEqual(true); + expect(LoadThemedStylesMock.loadedData).toHaveLength(2); + expect(LoadThemedStylesMock.calledWithAsync[0]).toEqual(false); + expect(LoadThemedStylesMock.calledWithAsync[1]).toEqual(false); + expect(LoadThemedStylesMock.calledWithAsync).toHaveLength(2); + expect(returnedModule.exports).toEqual('locals'); }); -}); \ No newline at end of file +}); diff --git a/webpack/loader-load-themed-styles/src/test/testData/MockStyle1.ts b/webpack/loader-load-themed-styles/src/test/testData/MockStyle1.ts index 90d24a1c58d..2ab7ae096c6 100644 --- a/webpack/loader-load-themed-styles/src/test/testData/MockStyle1.ts +++ b/webpack/loader-load-themed-styles/src/test/testData/MockStyle1.ts @@ -2,7 +2,10 @@ // See LICENSE in the project root for license information. // eslint-disable-next-line @typescript-eslint/no-explicit-any -const exportedObject: any = [['A', 'STYLE 1'], ['B', 'STYLE 2']]; +const exportedObject: any = [ + ['A', 'STYLE 1'], + ['B', 'STYLE 2'] +]; exportedObject.locals = 'locals'; diff --git a/webpack/loader-load-themed-styles/tsconfig.json b/webpack/loader-load-themed-styles/tsconfig.json index b1abb9e5b4a..dac21d04081 100644 --- a/webpack/loader-load-themed-styles/tsconfig.json +++ b/webpack/loader-load-themed-styles/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/webpack/loader-raw-script/.eslintrc.js b/webpack/loader-raw-script/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/webpack/loader-raw-script/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/webpack/loader-raw-script/.gitignore b/webpack/loader-raw-script/.gitignore deleted file mode 100644 index 7fbd6507339..00000000000 --- a/webpack/loader-raw-script/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -.DS_Store -npm*.log -coverage -temp -lib -dist diff --git a/webpack/loader-raw-script/.npmignore b/webpack/loader-raw-script/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/webpack/loader-raw-script/.npmignore +++ b/webpack/loader-raw-script/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/webpack/loader-raw-script/CHANGELOG.json b/webpack/loader-raw-script/CHANGELOG.json index 0ad8778041c..26a8ea535fe 100644 --- a/webpack/loader-raw-script/CHANGELOG.json +++ b/webpack/loader-raw-script/CHANGELOG.json @@ -1,6 +1,6147 @@ { "name": "@rushstack/loader-raw-script", "entries": [ + { + "version": "1.5.7", + "tag": "@rushstack/loader-raw-script_v1.5.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.5.6", + "tag": "@rushstack/loader-raw-script_v1.5.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.5.5", + "tag": "@rushstack/loader-raw-script_v1.5.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.5.4", + "tag": "@rushstack/loader-raw-script_v1.5.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.5.3", + "tag": "@rushstack/loader-raw-script_v1.5.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.5.2", + "tag": "@rushstack/loader-raw-script_v1.5.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.5.1", + "tag": "@rushstack/loader-raw-script_v1.5.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/loader-raw-script_v1.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/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.4.110", + "tag": "@rushstack/loader-raw-script_v1.4.110", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.4.109", + "tag": "@rushstack/loader-raw-script_v1.4.109", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "1.4.108", + "tag": "@rushstack/loader-raw-script_v1.4.108", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "1.4.107", + "tag": "@rushstack/loader-raw-script_v1.4.107", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "1.4.106", + "tag": "@rushstack/loader-raw-script_v1.4.106", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "1.4.105", + "tag": "@rushstack/loader-raw-script_v1.4.105", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "1.4.104", + "tag": "@rushstack/loader-raw-script_v1.4.104", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "1.4.103", + "tag": "@rushstack/loader-raw-script_v1.4.103", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "1.4.102", + "tag": "@rushstack/loader-raw-script_v1.4.102", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "1.4.101", + "tag": "@rushstack/loader-raw-script_v1.4.101", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "1.4.100", + "tag": "@rushstack/loader-raw-script_v1.4.100", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "1.4.99", + "tag": "@rushstack/loader-raw-script_v1.4.99", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "1.4.98", + "tag": "@rushstack/loader-raw-script_v1.4.98", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "1.4.97", + "tag": "@rushstack/loader-raw-script_v1.4.97", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "1.4.96", + "tag": "@rushstack/loader-raw-script_v1.4.96", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "1.4.95", + "tag": "@rushstack/loader-raw-script_v1.4.95", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "1.4.94", + "tag": "@rushstack/loader-raw-script_v1.4.94", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "1.4.93", + "tag": "@rushstack/loader-raw-script_v1.4.93", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "1.4.92", + "tag": "@rushstack/loader-raw-script_v1.4.92", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "1.4.91", + "tag": "@rushstack/loader-raw-script_v1.4.91", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "1.4.90", + "tag": "@rushstack/loader-raw-script_v1.4.90", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "1.4.89", + "tag": "@rushstack/loader-raw-script_v1.4.89", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "1.4.88", + "tag": "@rushstack/loader-raw-script_v1.4.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "1.4.87", + "tag": "@rushstack/loader-raw-script_v1.4.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "1.4.86", + "tag": "@rushstack/loader-raw-script_v1.4.86", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "1.4.85", + "tag": "@rushstack/loader-raw-script_v1.4.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "1.4.84", + "tag": "@rushstack/loader-raw-script_v1.4.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "1.4.83", + "tag": "@rushstack/loader-raw-script_v1.4.83", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "1.4.82", + "tag": "@rushstack/loader-raw-script_v1.4.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "1.4.81", + "tag": "@rushstack/loader-raw-script_v1.4.81", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "1.4.80", + "tag": "@rushstack/loader-raw-script_v1.4.80", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "1.4.79", + "tag": "@rushstack/loader-raw-script_v1.4.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "1.4.78", + "tag": "@rushstack/loader-raw-script_v1.4.78", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "1.4.77", + "tag": "@rushstack/loader-raw-script_v1.4.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "1.4.76", + "tag": "@rushstack/loader-raw-script_v1.4.76", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "1.4.75", + "tag": "@rushstack/loader-raw-script_v1.4.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "1.4.74", + "tag": "@rushstack/loader-raw-script_v1.4.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "1.4.73", + "tag": "@rushstack/loader-raw-script_v1.4.73", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "1.4.72", + "tag": "@rushstack/loader-raw-script_v1.4.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "1.4.71", + "tag": "@rushstack/loader-raw-script_v1.4.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "1.4.70", + "tag": "@rushstack/loader-raw-script_v1.4.70", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "1.4.69", + "tag": "@rushstack/loader-raw-script_v1.4.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "1.4.68", + "tag": "@rushstack/loader-raw-script_v1.4.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "1.4.67", + "tag": "@rushstack/loader-raw-script_v1.4.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "1.4.66", + "tag": "@rushstack/loader-raw-script_v1.4.66", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "1.4.65", + "tag": "@rushstack/loader-raw-script_v1.4.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "1.4.64", + "tag": "@rushstack/loader-raw-script_v1.4.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "1.4.63", + "tag": "@rushstack/loader-raw-script_v1.4.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "1.4.62", + "tag": "@rushstack/loader-raw-script_v1.4.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "1.4.61", + "tag": "@rushstack/loader-raw-script_v1.4.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "1.4.60", + "tag": "@rushstack/loader-raw-script_v1.4.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "1.4.59", + "tag": "@rushstack/loader-raw-script_v1.4.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "1.4.58", + "tag": "@rushstack/loader-raw-script_v1.4.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "1.4.57", + "tag": "@rushstack/loader-raw-script_v1.4.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "1.4.56", + "tag": "@rushstack/loader-raw-script_v1.4.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "1.4.55", + "tag": "@rushstack/loader-raw-script_v1.4.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "1.4.54", + "tag": "@rushstack/loader-raw-script_v1.4.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "1.4.53", + "tag": "@rushstack/loader-raw-script_v1.4.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "1.4.52", + "tag": "@rushstack/loader-raw-script_v1.4.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "1.4.51", + "tag": "@rushstack/loader-raw-script_v1.4.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "1.4.50", + "tag": "@rushstack/loader-raw-script_v1.4.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "1.4.49", + "tag": "@rushstack/loader-raw-script_v1.4.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "1.4.48", + "tag": "@rushstack/loader-raw-script_v1.4.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "1.4.47", + "tag": "@rushstack/loader-raw-script_v1.4.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "1.4.46", + "tag": "@rushstack/loader-raw-script_v1.4.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "1.4.45", + "tag": "@rushstack/loader-raw-script_v1.4.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "1.4.44", + "tag": "@rushstack/loader-raw-script_v1.4.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "1.4.43", + "tag": "@rushstack/loader-raw-script_v1.4.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "1.4.42", + "tag": "@rushstack/loader-raw-script_v1.4.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "1.4.41", + "tag": "@rushstack/loader-raw-script_v1.4.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "1.4.40", + "tag": "@rushstack/loader-raw-script_v1.4.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "1.4.39", + "tag": "@rushstack/loader-raw-script_v1.4.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "1.4.38", + "tag": "@rushstack/loader-raw-script_v1.4.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "1.4.37", + "tag": "@rushstack/loader-raw-script_v1.4.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "1.4.36", + "tag": "@rushstack/loader-raw-script_v1.4.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "1.4.35", + "tag": "@rushstack/loader-raw-script_v1.4.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "1.4.34", + "tag": "@rushstack/loader-raw-script_v1.4.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "1.4.33", + "tag": "@rushstack/loader-raw-script_v1.4.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "1.4.32", + "tag": "@rushstack/loader-raw-script_v1.4.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "1.4.31", + "tag": "@rushstack/loader-raw-script_v1.4.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "1.4.30", + "tag": "@rushstack/loader-raw-script_v1.4.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "1.4.29", + "tag": "@rushstack/loader-raw-script_v1.4.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "1.4.28", + "tag": "@rushstack/loader-raw-script_v1.4.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "1.4.27", + "tag": "@rushstack/loader-raw-script_v1.4.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "1.4.26", + "tag": "@rushstack/loader-raw-script_v1.4.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "1.4.25", + "tag": "@rushstack/loader-raw-script_v1.4.25", + "date": "Mon, 19 Feb 2024 21:54:26 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a formatting issue with the LICENSE." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "1.4.24", + "tag": "@rushstack/loader-raw-script_v1.4.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "1.4.23", + "tag": "@rushstack/loader-raw-script_v1.4.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "1.4.22", + "tag": "@rushstack/loader-raw-script_v1.4.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "1.4.21", + "tag": "@rushstack/loader-raw-script_v1.4.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "1.4.20", + "tag": "@rushstack/loader-raw-script_v1.4.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "1.4.19", + "tag": "@rushstack/loader-raw-script_v1.4.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "1.4.18", + "tag": "@rushstack/loader-raw-script_v1.4.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "1.4.17", + "tag": "@rushstack/loader-raw-script_v1.4.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "1.4.16", + "tag": "@rushstack/loader-raw-script_v1.4.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "1.4.15", + "tag": "@rushstack/loader-raw-script_v1.4.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "1.4.14", + "tag": "@rushstack/loader-raw-script_v1.4.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "1.4.13", + "tag": "@rushstack/loader-raw-script_v1.4.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "1.4.12", + "tag": "@rushstack/loader-raw-script_v1.4.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "1.4.11", + "tag": "@rushstack/loader-raw-script_v1.4.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "1.4.10", + "tag": "@rushstack/loader-raw-script_v1.4.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "1.4.9", + "tag": "@rushstack/loader-raw-script_v1.4.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "1.4.8", + "tag": "@rushstack/loader-raw-script_v1.4.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "1.4.7", + "tag": "@rushstack/loader-raw-script_v1.4.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "1.4.6", + "tag": "@rushstack/loader-raw-script_v1.4.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "1.4.5", + "tag": "@rushstack/loader-raw-script_v1.4.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "1.4.4", + "tag": "@rushstack/loader-raw-script_v1.4.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/loader-raw-script_v1.4.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/loader-raw-script_v1.4.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/loader-raw-script_v1.4.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/loader-raw-script_v1.4.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "1.3.316", + "tag": "@rushstack/loader-raw-script_v1.3.316", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "1.3.315", + "tag": "@rushstack/loader-raw-script_v1.3.315", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "1.3.314", + "tag": "@rushstack/loader-raw-script_v1.3.314", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "1.3.313", + "tag": "@rushstack/loader-raw-script_v1.3.313", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "1.3.312", + "tag": "@rushstack/loader-raw-script_v1.3.312", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "1.3.311", + "tag": "@rushstack/loader-raw-script_v1.3.311", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "1.3.310", + "tag": "@rushstack/loader-raw-script_v1.3.310", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "1.3.309", + "tag": "@rushstack/loader-raw-script_v1.3.309", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "1.3.308", + "tag": "@rushstack/loader-raw-script_v1.3.308", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "1.3.307", + "tag": "@rushstack/loader-raw-script_v1.3.307", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "1.3.306", + "tag": "@rushstack/loader-raw-script_v1.3.306", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "1.3.305", + "tag": "@rushstack/loader-raw-script_v1.3.305", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "1.3.304", + "tag": "@rushstack/loader-raw-script_v1.3.304", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "1.3.303", + "tag": "@rushstack/loader-raw-script_v1.3.303", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "1.3.302", + "tag": "@rushstack/loader-raw-script_v1.3.302", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "1.3.301", + "tag": "@rushstack/loader-raw-script_v1.3.301", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "1.3.300", + "tag": "@rushstack/loader-raw-script_v1.3.300", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "1.3.299", + "tag": "@rushstack/loader-raw-script_v1.3.299", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "1.3.298", + "tag": "@rushstack/loader-raw-script_v1.3.298", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "1.3.297", + "tag": "@rushstack/loader-raw-script_v1.3.297", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "1.3.296", + "tag": "@rushstack/loader-raw-script_v1.3.296", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "1.3.295", + "tag": "@rushstack/loader-raw-script_v1.3.295", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "1.3.294", + "tag": "@rushstack/loader-raw-script_v1.3.294", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "1.3.293", + "tag": "@rushstack/loader-raw-script_v1.3.293", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "1.3.292", + "tag": "@rushstack/loader-raw-script_v1.3.292", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "1.3.291", + "tag": "@rushstack/loader-raw-script_v1.3.291", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "1.3.290", + "tag": "@rushstack/loader-raw-script_v1.3.290", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "1.3.289", + "tag": "@rushstack/loader-raw-script_v1.3.289", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "1.3.288", + "tag": "@rushstack/loader-raw-script_v1.3.288", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "1.3.287", + "tag": "@rushstack/loader-raw-script_v1.3.287", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "1.3.286", + "tag": "@rushstack/loader-raw-script_v1.3.286", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "1.3.285", + "tag": "@rushstack/loader-raw-script_v1.3.285", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "1.3.284", + "tag": "@rushstack/loader-raw-script_v1.3.284", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "1.3.283", + "tag": "@rushstack/loader-raw-script_v1.3.283", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "1.3.282", + "tag": "@rushstack/loader-raw-script_v1.3.282", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "1.3.281", + "tag": "@rushstack/loader-raw-script_v1.3.281", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "1.3.280", + "tag": "@rushstack/loader-raw-script_v1.3.280", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "1.3.279", + "tag": "@rushstack/loader-raw-script_v1.3.279", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "1.3.278", + "tag": "@rushstack/loader-raw-script_v1.3.278", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "1.3.277", + "tag": "@rushstack/loader-raw-script_v1.3.277", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "1.3.276", + "tag": "@rushstack/loader-raw-script_v1.3.276", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "1.3.275", + "tag": "@rushstack/loader-raw-script_v1.3.275", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "1.3.274", + "tag": "@rushstack/loader-raw-script_v1.3.274", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "1.3.273", + "tag": "@rushstack/loader-raw-script_v1.3.273", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "1.3.272", + "tag": "@rushstack/loader-raw-script_v1.3.272", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "1.3.271", + "tag": "@rushstack/loader-raw-script_v1.3.271", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "1.3.270", + "tag": "@rushstack/loader-raw-script_v1.3.270", + "date": "Mon, 14 Nov 2022 05:15:02 GMT", + "comments": { + "patch": [ + { + "comment": "Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq" + } + ] + } + }, + { + "version": "1.3.269", + "tag": "@rushstack/loader-raw-script_v1.3.269", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "1.3.268", + "tag": "@rushstack/loader-raw-script_v1.3.268", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "1.3.267", + "tag": "@rushstack/loader-raw-script_v1.3.267", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "1.3.266", + "tag": "@rushstack/loader-raw-script_v1.3.266", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "1.3.265", + "tag": "@rushstack/loader-raw-script_v1.3.265", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "1.3.264", + "tag": "@rushstack/loader-raw-script_v1.3.264", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "1.3.263", + "tag": "@rushstack/loader-raw-script_v1.3.263", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "1.3.262", + "tag": "@rushstack/loader-raw-script_v1.3.262", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "1.3.261", + "tag": "@rushstack/loader-raw-script_v1.3.261", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "1.3.260", + "tag": "@rushstack/loader-raw-script_v1.3.260", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "1.3.259", + "tag": "@rushstack/loader-raw-script_v1.3.259", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "1.3.258", + "tag": "@rushstack/loader-raw-script_v1.3.258", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "1.3.257", + "tag": "@rushstack/loader-raw-script_v1.3.257", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "1.3.256", + "tag": "@rushstack/loader-raw-script_v1.3.256", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "1.3.255", + "tag": "@rushstack/loader-raw-script_v1.3.255", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "1.3.254", + "tag": "@rushstack/loader-raw-script_v1.3.254", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "1.3.253", + "tag": "@rushstack/loader-raw-script_v1.3.253", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "1.3.252", + "tag": "@rushstack/loader-raw-script_v1.3.252", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "1.3.251", + "tag": "@rushstack/loader-raw-script_v1.3.251", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "1.3.250", + "tag": "@rushstack/loader-raw-script_v1.3.250", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "1.3.249", + "tag": "@rushstack/loader-raw-script_v1.3.249", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "1.3.248", + "tag": "@rushstack/loader-raw-script_v1.3.248", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "1.3.247", + "tag": "@rushstack/loader-raw-script_v1.3.247", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "1.3.246", + "tag": "@rushstack/loader-raw-script_v1.3.246", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "1.3.245", + "tag": "@rushstack/loader-raw-script_v1.3.245", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "1.3.244", + "tag": "@rushstack/loader-raw-script_v1.3.244", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "1.3.243", + "tag": "@rushstack/loader-raw-script_v1.3.243", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "1.3.242", + "tag": "@rushstack/loader-raw-script_v1.3.242", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "1.3.241", + "tag": "@rushstack/loader-raw-script_v1.3.241", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "1.3.240", + "tag": "@rushstack/loader-raw-script_v1.3.240", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "1.3.239", + "tag": "@rushstack/loader-raw-script_v1.3.239", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "1.3.238", + "tag": "@rushstack/loader-raw-script_v1.3.238", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "1.3.237", + "tag": "@rushstack/loader-raw-script_v1.3.237", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "1.3.236", + "tag": "@rushstack/loader-raw-script_v1.3.236", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "1.3.235", + "tag": "@rushstack/loader-raw-script_v1.3.235", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "1.3.234", + "tag": "@rushstack/loader-raw-script_v1.3.234", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "1.3.233", + "tag": "@rushstack/loader-raw-script_v1.3.233", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "1.3.232", + "tag": "@rushstack/loader-raw-script_v1.3.232", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "1.3.231", + "tag": "@rushstack/loader-raw-script_v1.3.231", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "1.3.230", + "tag": "@rushstack/loader-raw-script_v1.3.230", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "1.3.229", + "tag": "@rushstack/loader-raw-script_v1.3.229", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "1.3.228", + "tag": "@rushstack/loader-raw-script_v1.3.228", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "1.3.227", + "tag": "@rushstack/loader-raw-script_v1.3.227", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "1.3.226", + "tag": "@rushstack/loader-raw-script_v1.3.226", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "1.3.225", + "tag": "@rushstack/loader-raw-script_v1.3.225", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "1.3.224", + "tag": "@rushstack/loader-raw-script_v1.3.224", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "1.3.223", + "tag": "@rushstack/loader-raw-script_v1.3.223", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "1.3.222", + "tag": "@rushstack/loader-raw-script_v1.3.222", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "1.3.221", + "tag": "@rushstack/loader-raw-script_v1.3.221", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "1.3.220", + "tag": "@rushstack/loader-raw-script_v1.3.220", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "1.3.219", + "tag": "@rushstack/loader-raw-script_v1.3.219", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "1.3.218", + "tag": "@rushstack/loader-raw-script_v1.3.218", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "1.3.217", + "tag": "@rushstack/loader-raw-script_v1.3.217", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "1.3.216", + "tag": "@rushstack/loader-raw-script_v1.3.216", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "1.3.215", + "tag": "@rushstack/loader-raw-script_v1.3.215", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "1.3.214", + "tag": "@rushstack/loader-raw-script_v1.3.214", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "1.3.213", + "tag": "@rushstack/loader-raw-script_v1.3.213", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "1.3.212", + "tag": "@rushstack/loader-raw-script_v1.3.212", + "date": "Tue, 15 Mar 2022 19:15:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "1.3.211", + "tag": "@rushstack/loader-raw-script_v1.3.211", + "date": "Fri, 11 Feb 2022 10:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "1.3.210", + "tag": "@rushstack/loader-raw-script_v1.3.210", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "1.3.209", + "tag": "@rushstack/loader-raw-script_v1.3.209", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "1.3.208", + "tag": "@rushstack/loader-raw-script_v1.3.208", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "1.3.207", + "tag": "@rushstack/loader-raw-script_v1.3.207", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "1.3.206", + "tag": "@rushstack/loader-raw-script_v1.3.206", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "1.3.205", + "tag": "@rushstack/loader-raw-script_v1.3.205", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "1.3.204", + "tag": "@rushstack/loader-raw-script_v1.3.204", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "1.3.203", + "tag": "@rushstack/loader-raw-script_v1.3.203", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "1.3.202", + "tag": "@rushstack/loader-raw-script_v1.3.202", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "1.3.201", + "tag": "@rushstack/loader-raw-script_v1.3.201", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "1.3.200", + "tag": "@rushstack/loader-raw-script_v1.3.200", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "1.3.199", + "tag": "@rushstack/loader-raw-script_v1.3.199", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "1.3.198", + "tag": "@rushstack/loader-raw-script_v1.3.198", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "1.3.197", + "tag": "@rushstack/loader-raw-script_v1.3.197", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "1.3.196", + "tag": "@rushstack/loader-raw-script_v1.3.196", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "1.3.195", + "tag": "@rushstack/loader-raw-script_v1.3.195", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "1.3.194", + "tag": "@rushstack/loader-raw-script_v1.3.194", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "1.3.193", + "tag": "@rushstack/loader-raw-script_v1.3.193", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "1.3.192", + "tag": "@rushstack/loader-raw-script_v1.3.192", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "1.3.191", + "tag": "@rushstack/loader-raw-script_v1.3.191", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "1.3.190", + "tag": "@rushstack/loader-raw-script_v1.3.190", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "1.3.189", + "tag": "@rushstack/loader-raw-script_v1.3.189", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "1.3.188", + "tag": "@rushstack/loader-raw-script_v1.3.188", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "1.3.187", + "tag": "@rushstack/loader-raw-script_v1.3.187", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "1.3.186", + "tag": "@rushstack/loader-raw-script_v1.3.186", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "1.3.185", + "tag": "@rushstack/loader-raw-script_v1.3.185", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "1.3.184", + "tag": "@rushstack/loader-raw-script_v1.3.184", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "1.3.183", + "tag": "@rushstack/loader-raw-script_v1.3.183", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "1.3.182", + "tag": "@rushstack/loader-raw-script_v1.3.182", + "date": "Thu, 23 Sep 2021 00:10:40 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "1.3.181", + "tag": "@rushstack/loader-raw-script_v1.3.181", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "1.3.180", + "tag": "@rushstack/loader-raw-script_v1.3.180", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "1.3.179", + "tag": "@rushstack/loader-raw-script_v1.3.179", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "1.3.178", + "tag": "@rushstack/loader-raw-script_v1.3.178", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "1.3.177", + "tag": "@rushstack/loader-raw-script_v1.3.177", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "1.3.176", + "tag": "@rushstack/loader-raw-script_v1.3.176", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "1.3.175", + "tag": "@rushstack/loader-raw-script_v1.3.175", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "1.3.174", + "tag": "@rushstack/loader-raw-script_v1.3.174", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "1.3.173", + "tag": "@rushstack/loader-raw-script_v1.3.173", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "1.3.172", + "tag": "@rushstack/loader-raw-script_v1.3.172", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "1.3.171", + "tag": "@rushstack/loader-raw-script_v1.3.171", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "1.3.170", + "tag": "@rushstack/loader-raw-script_v1.3.170", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "1.3.169", + "tag": "@rushstack/loader-raw-script_v1.3.169", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "1.3.168", + "tag": "@rushstack/loader-raw-script_v1.3.168", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "1.3.167", + "tag": "@rushstack/loader-raw-script_v1.3.167", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.3.166", + "tag": "@rushstack/loader-raw-script_v1.3.166", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "1.3.165", + "tag": "@rushstack/loader-raw-script_v1.3.165", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "1.3.164", + "tag": "@rushstack/loader-raw-script_v1.3.164", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "1.3.163", + "tag": "@rushstack/loader-raw-script_v1.3.163", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "1.3.162", + "tag": "@rushstack/loader-raw-script_v1.3.162", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "1.3.161", + "tag": "@rushstack/loader-raw-script_v1.3.161", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "1.3.160", + "tag": "@rushstack/loader-raw-script_v1.3.160", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "1.3.159", + "tag": "@rushstack/loader-raw-script_v1.3.159", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.3.158", + "tag": "@rushstack/loader-raw-script_v1.3.158", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "1.3.157", + "tag": "@rushstack/loader-raw-script_v1.3.157", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.3.156", + "tag": "@rushstack/loader-raw-script_v1.3.156", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.3.155", + "tag": "@rushstack/loader-raw-script_v1.3.155", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.3.154", + "tag": "@rushstack/loader-raw-script_v1.3.154", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.3.153", + "tag": "@rushstack/loader-raw-script_v1.3.153", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.3.152", + "tag": "@rushstack/loader-raw-script_v1.3.152", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.3.151", + "tag": "@rushstack/loader-raw-script_v1.3.151", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.3.150", + "tag": "@rushstack/loader-raw-script_v1.3.150", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.3.149", + "tag": "@rushstack/loader-raw-script_v1.3.149", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "1.3.148", + "tag": "@rushstack/loader-raw-script_v1.3.148", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "1.3.147", + "tag": "@rushstack/loader-raw-script_v1.3.147", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "1.3.146", + "tag": "@rushstack/loader-raw-script_v1.3.146", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "1.3.145", + "tag": "@rushstack/loader-raw-script_v1.3.145", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "1.3.144", + "tag": "@rushstack/loader-raw-script_v1.3.144", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "1.3.143", + "tag": "@rushstack/loader-raw-script_v1.3.143", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "1.3.142", + "tag": "@rushstack/loader-raw-script_v1.3.142", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "1.3.141", + "tag": "@rushstack/loader-raw-script_v1.3.141", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "1.3.140", + "tag": "@rushstack/loader-raw-script_v1.3.140", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "1.3.139", + "tag": "@rushstack/loader-raw-script_v1.3.139", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "1.3.138", + "tag": "@rushstack/loader-raw-script_v1.3.138", + "date": "Thu, 13 May 2021 01:52:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "1.3.137", + "tag": "@rushstack/loader-raw-script_v1.3.137", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "1.3.136", + "tag": "@rushstack/loader-raw-script_v1.3.136", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "1.3.135", + "tag": "@rushstack/loader-raw-script_v1.3.135", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "1.3.134", + "tag": "@rushstack/loader-raw-script_v1.3.134", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "1.3.133", + "tag": "@rushstack/loader-raw-script_v1.3.133", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "1.3.132", + "tag": "@rushstack/loader-raw-script_v1.3.132", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "1.3.131", + "tag": "@rushstack/loader-raw-script_v1.3.131", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "1.3.130", + "tag": "@rushstack/loader-raw-script_v1.3.130", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "1.3.129", + "tag": "@rushstack/loader-raw-script_v1.3.129", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "1.3.128", + "tag": "@rushstack/loader-raw-script_v1.3.128", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "1.3.127", + "tag": "@rushstack/loader-raw-script_v1.3.127", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "1.3.126", + "tag": "@rushstack/loader-raw-script_v1.3.126", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "1.3.125", + "tag": "@rushstack/loader-raw-script_v1.3.125", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "1.3.124", + "tag": "@rushstack/loader-raw-script_v1.3.124", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "1.3.123", + "tag": "@rushstack/loader-raw-script_v1.3.123", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "1.3.122", + "tag": "@rushstack/loader-raw-script_v1.3.122", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "1.3.121", + "tag": "@rushstack/loader-raw-script_v1.3.121", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "1.3.120", + "tag": "@rushstack/loader-raw-script_v1.3.120", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "1.3.119", + "tag": "@rushstack/loader-raw-script_v1.3.119", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "1.3.118", + "tag": "@rushstack/loader-raw-script_v1.3.118", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.3.117", + "tag": "@rushstack/loader-raw-script_v1.3.117", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.3.116", + "tag": "@rushstack/loader-raw-script_v1.3.116", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "1.3.115", + "tag": "@rushstack/loader-raw-script_v1.3.115", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "1.3.114", + "tag": "@rushstack/loader-raw-script_v1.3.114", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "1.3.113", + "tag": "@rushstack/loader-raw-script_v1.3.113", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "1.3.112", + "tag": "@rushstack/loader-raw-script_v1.3.112", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "1.3.111", + "tag": "@rushstack/loader-raw-script_v1.3.111", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "1.3.110", + "tag": "@rushstack/loader-raw-script_v1.3.110", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "1.3.109", + "tag": "@rushstack/loader-raw-script_v1.3.109", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "1.3.108", + "tag": "@rushstack/loader-raw-script_v1.3.108", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "1.3.107", + "tag": "@rushstack/loader-raw-script_v1.3.107", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "1.3.106", + "tag": "@rushstack/loader-raw-script_v1.3.106", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "1.3.105", + "tag": "@rushstack/loader-raw-script_v1.3.105", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "1.3.104", + "tag": "@rushstack/loader-raw-script_v1.3.104", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "1.3.103", + "tag": "@rushstack/loader-raw-script_v1.3.103", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "1.3.102", + "tag": "@rushstack/loader-raw-script_v1.3.102", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "1.3.101", + "tag": "@rushstack/loader-raw-script_v1.3.101", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "1.3.100", + "tag": "@rushstack/loader-raw-script_v1.3.100", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "1.3.99", + "tag": "@rushstack/loader-raw-script_v1.3.99", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "1.3.98", + "tag": "@rushstack/loader-raw-script_v1.3.98", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "1.3.97", + "tag": "@rushstack/loader-raw-script_v1.3.97", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "1.3.96", + "tag": "@rushstack/loader-raw-script_v1.3.96", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "1.3.95", + "tag": "@rushstack/loader-raw-script_v1.3.95", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "1.3.94", + "tag": "@rushstack/loader-raw-script_v1.3.94", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "1.3.93", + "tag": "@rushstack/loader-raw-script_v1.3.93", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "1.3.92", + "tag": "@rushstack/loader-raw-script_v1.3.92", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "1.3.91", + "tag": "@rushstack/loader-raw-script_v1.3.91", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "1.3.90", + "tag": "@rushstack/loader-raw-script_v1.3.90", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "1.3.89", + "tag": "@rushstack/loader-raw-script_v1.3.89", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "1.3.88", + "tag": "@rushstack/loader-raw-script_v1.3.88", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "1.3.87", + "tag": "@rushstack/loader-raw-script_v1.3.87", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "1.3.86", + "tag": "@rushstack/loader-raw-script_v1.3.86", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "1.3.85", + "tag": "@rushstack/loader-raw-script_v1.3.85", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "1.3.84", + "tag": "@rushstack/loader-raw-script_v1.3.84", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "1.3.83", + "tag": "@rushstack/loader-raw-script_v1.3.83", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "1.3.82", + "tag": "@rushstack/loader-raw-script_v1.3.82", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "1.3.81", + "tag": "@rushstack/loader-raw-script_v1.3.81", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "1.3.80", + "tag": "@rushstack/loader-raw-script_v1.3.80", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "1.3.79", + "tag": "@rushstack/loader-raw-script_v1.3.79", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "1.3.78", + "tag": "@rushstack/loader-raw-script_v1.3.78", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "1.3.77", + "tag": "@rushstack/loader-raw-script_v1.3.77", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "1.3.76", + "tag": "@rushstack/loader-raw-script_v1.3.76", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "1.3.75", + "tag": "@rushstack/loader-raw-script_v1.3.75", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "1.3.74", + "tag": "@rushstack/loader-raw-script_v1.3.74", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "1.3.73", + "tag": "@rushstack/loader-raw-script_v1.3.73", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "1.3.72", + "tag": "@rushstack/loader-raw-script_v1.3.72", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "1.3.71", + "tag": "@rushstack/loader-raw-script_v1.3.71", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "1.3.70", + "tag": "@rushstack/loader-raw-script_v1.3.70", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "1.3.69", + "tag": "@rushstack/loader-raw-script_v1.3.69", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "1.3.68", + "tag": "@rushstack/loader-raw-script_v1.3.68", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "1.3.67", + "tag": "@rushstack/loader-raw-script_v1.3.67", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "1.3.66", + "tag": "@rushstack/loader-raw-script_v1.3.66", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "1.3.65", + "tag": "@rushstack/loader-raw-script_v1.3.65", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "1.3.64", + "tag": "@rushstack/loader-raw-script_v1.3.64", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "1.3.63", + "tag": "@rushstack/loader-raw-script_v1.3.63", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "1.3.62", + "tag": "@rushstack/loader-raw-script_v1.3.62", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "1.3.61", + "tag": "@rushstack/loader-raw-script_v1.3.61", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "1.3.60", + "tag": "@rushstack/loader-raw-script_v1.3.60", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "1.3.59", + "tag": "@rushstack/loader-raw-script_v1.3.59", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "1.3.58", + "tag": "@rushstack/loader-raw-script_v1.3.58", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "1.3.57", + "tag": "@rushstack/loader-raw-script_v1.3.57", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "1.3.56", + "tag": "@rushstack/loader-raw-script_v1.3.56", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "1.3.55", + "tag": "@rushstack/loader-raw-script_v1.3.55", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "1.3.54", + "tag": "@rushstack/loader-raw-script_v1.3.54", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "1.3.53", + "tag": "@rushstack/loader-raw-script_v1.3.53", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "1.3.52", + "tag": "@rushstack/loader-raw-script_v1.3.52", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "1.3.51", + "tag": "@rushstack/loader-raw-script_v1.3.51", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "1.3.50", + "tag": "@rushstack/loader-raw-script_v1.3.50", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "1.3.49", + "tag": "@rushstack/loader-raw-script_v1.3.49", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "1.3.48", + "tag": "@rushstack/loader-raw-script_v1.3.48", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "1.3.47", + "tag": "@rushstack/loader-raw-script_v1.3.47", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "1.3.46", + "tag": "@rushstack/loader-raw-script_v1.3.46", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "1.3.45", + "tag": "@rushstack/loader-raw-script_v1.3.45", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "1.3.44", + "tag": "@rushstack/loader-raw-script_v1.3.44", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "1.3.43", + "tag": "@rushstack/loader-raw-script_v1.3.43", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "1.3.42", + "tag": "@rushstack/loader-raw-script_v1.3.42", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "1.3.41", + "tag": "@rushstack/loader-raw-script_v1.3.41", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "1.3.40", + "tag": "@rushstack/loader-raw-script_v1.3.40", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "1.3.39", + "tag": "@rushstack/loader-raw-script_v1.3.39", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "1.3.38", + "tag": "@rushstack/loader-raw-script_v1.3.38", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "1.3.37", + "tag": "@rushstack/loader-raw-script_v1.3.37", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "1.3.36", + "tag": "@rushstack/loader-raw-script_v1.3.36", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "1.3.35", + "tag": "@rushstack/loader-raw-script_v1.3.35", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "1.3.34", + "tag": "@rushstack/loader-raw-script_v1.3.34", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "1.3.33", + "tag": "@rushstack/loader-raw-script_v1.3.33", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "1.3.32", + "tag": "@rushstack/loader-raw-script_v1.3.32", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + } + ] + } + }, + { + "version": "1.3.31", + "tag": "@rushstack/loader-raw-script_v1.3.31", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + } + ] + } + }, + { + "version": "1.3.30", + "tag": "@rushstack/loader-raw-script_v1.3.30", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "1.3.29", + "tag": "@rushstack/loader-raw-script_v1.3.29", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "1.3.28", + "tag": "@rushstack/loader-raw-script_v1.3.28", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + } + ] + } + }, + { + "version": "1.3.27", + "tag": "@rushstack/loader-raw-script_v1.3.27", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + } + ] + } + }, + { + "version": "1.3.26", + "tag": "@rushstack/loader-raw-script_v1.3.26", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + } + ] + } + }, + { + "version": "1.3.25", + "tag": "@rushstack/loader-raw-script_v1.3.25", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + } + ] + } + }, + { + "version": "1.3.24", + "tag": "@rushstack/loader-raw-script_v1.3.24", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + } + ] + } + }, + { + "version": "1.3.23", + "tag": "@rushstack/loader-raw-script_v1.3.23", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + } + ] + } + }, + { + "version": "1.3.22", + "tag": "@rushstack/loader-raw-script_v1.3.22", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + } + ] + } + }, + { + "version": "1.3.21", + "tag": "@rushstack/loader-raw-script_v1.3.21", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + } + ] + } + }, + { + "version": "1.3.20", + "tag": "@rushstack/loader-raw-script_v1.3.20", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + } + ] + } + }, + { + "version": "1.3.19", + "tag": "@rushstack/loader-raw-script_v1.3.19", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + } + ] + } + }, + { + "version": "1.3.18", + "tag": "@rushstack/loader-raw-script_v1.3.18", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + } + ] + } + }, + { + "version": "1.3.17", + "tag": "@rushstack/loader-raw-script_v1.3.17", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + } + ] + } + }, + { + "version": "1.3.16", + "tag": "@rushstack/loader-raw-script_v1.3.16", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + } + ] + } + }, + { + "version": "1.3.15", + "tag": "@rushstack/loader-raw-script_v1.3.15", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + } + ] + } + }, + { + "version": "1.3.14", + "tag": "@rushstack/loader-raw-script_v1.3.14", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + } + ] + } + }, + { + "version": "1.3.13", + "tag": "@rushstack/loader-raw-script_v1.3.13", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + } + ] + } + }, + { + "version": "1.3.12", + "tag": "@rushstack/loader-raw-script_v1.3.12", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + } + ] + } + }, + { + "version": "1.3.11", + "tag": "@rushstack/loader-raw-script_v1.3.11", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "1.3.10", + "tag": "@rushstack/loader-raw-script_v1.3.10", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + } + ] + } + }, + { + "version": "1.3.9", + "tag": "@rushstack/loader-raw-script_v1.3.9", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + } + ] + } + }, + { + "version": "1.3.8", + "tag": "@rushstack/loader-raw-script_v1.3.8", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/loader-raw-script_v1.3.7", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + } + ] + } + }, { "version": "1.3.6", "tag": "@rushstack/loader-raw-script_v1.3.6", diff --git a/webpack/loader-raw-script/CHANGELOG.md b/webpack/loader-raw-script/CHANGELOG.md index d575489e69c..f622f689155 100644 --- a/webpack/loader-raw-script/CHANGELOG.md +++ b/webpack/loader-raw-script/CHANGELOG.md @@ -1,11 +1,2180 @@ # Change Log - @rushstack/loader-raw-script -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 1.5.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.5.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.5.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.5.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 1.5.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.5.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.5.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.5.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.4.110 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 1.4.109 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 1.4.108 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 1.4.107 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 1.4.106 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 1.4.105 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 1.4.104 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 1.4.103 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 1.4.102 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 1.4.101 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 1.4.100 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 1.4.99 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 1.4.98 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 1.4.97 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 1.4.96 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 1.4.95 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 1.4.94 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 1.4.93 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 1.4.92 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 1.4.91 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 1.4.90 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 1.4.89 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 1.4.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 1.4.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 1.4.86 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 1.4.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 1.4.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 1.4.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 1.4.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 1.4.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 1.4.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 1.4.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 1.4.78 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 1.4.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 1.4.76 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 1.4.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 1.4.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 1.4.73 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 1.4.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 1.4.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 1.4.70 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 1.4.69 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 1.4.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 1.4.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 1.4.66 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 1.4.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 1.4.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 1.4.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 1.4.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 1.4.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 1.4.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 1.4.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 1.4.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 1.4.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 1.4.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 1.4.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 1.4.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 1.4.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 1.4.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 1.4.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 1.4.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 1.4.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 1.4.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 1.4.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 1.4.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 1.4.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 1.4.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 1.4.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 1.4.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 1.4.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 1.4.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 1.4.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 1.4.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 1.4.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 1.4.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 1.4.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 1.4.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 1.4.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 1.4.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 1.4.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 1.4.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 1.4.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 1.4.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 1.4.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 1.4.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 1.4.25 +Mon, 19 Feb 2024 21:54:26 GMT + +### Patches + +- Fix a formatting issue with the LICENSE. + +## 1.4.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 1.4.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 1.4.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 1.4.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 1.4.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 1.4.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 1.4.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 1.4.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 1.4.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 1.4.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 1.4.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 1.4.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 1.4.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 1.4.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 1.4.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 1.4.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 1.4.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 1.4.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 1.4.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 1.4.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 1.4.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 1.4.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 1.4.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 1.4.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 1.4.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 1.3.316 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 1.3.315 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 1.3.314 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 1.3.313 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 1.3.312 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 1.3.311 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 1.3.310 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 1.3.309 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 1.3.308 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 1.3.307 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 1.3.306 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 1.3.305 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 1.3.304 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 1.3.303 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 1.3.302 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 1.3.301 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 1.3.300 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 1.3.299 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 1.3.298 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 1.3.297 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 1.3.296 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 1.3.295 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 1.3.294 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 1.3.293 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 1.3.292 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 1.3.291 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 1.3.290 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 1.3.289 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 1.3.288 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 1.3.287 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 1.3.286 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 1.3.285 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 1.3.284 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 1.3.283 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 1.3.282 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 1.3.281 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 1.3.280 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 1.3.279 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 1.3.278 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 1.3.277 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 1.3.276 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 1.3.275 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 1.3.274 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 1.3.273 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 1.3.272 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 1.3.271 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 1.3.270 +Mon, 14 Nov 2022 05:15:02 GMT + +### Patches + +- Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq + +## 1.3.269 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 1.3.268 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 1.3.267 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 1.3.266 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 1.3.265 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 1.3.264 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 1.3.263 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 1.3.262 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 1.3.261 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 1.3.260 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 1.3.259 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 1.3.258 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 1.3.257 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 1.3.256 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 1.3.255 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 1.3.254 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 1.3.253 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 1.3.252 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 1.3.251 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 1.3.250 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 1.3.249 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 1.3.248 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 1.3.247 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 1.3.246 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 1.3.245 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 1.3.244 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 1.3.243 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 1.3.242 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 1.3.241 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 1.3.240 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 1.3.239 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 1.3.238 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 1.3.237 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 1.3.236 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 1.3.235 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 1.3.234 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 1.3.233 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 1.3.232 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 1.3.231 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 1.3.230 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 1.3.229 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 1.3.228 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 1.3.227 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 1.3.226 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 1.3.225 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 1.3.224 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 1.3.223 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 1.3.222 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 1.3.221 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 1.3.220 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 1.3.219 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 1.3.218 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 1.3.217 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 1.3.216 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 1.3.215 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 1.3.214 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 1.3.213 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 1.3.212 +Tue, 15 Mar 2022 19:15:53 GMT + +_Version update only_ + +## 1.3.211 +Fri, 11 Feb 2022 10:30:26 GMT + +_Version update only_ + +## 1.3.210 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 1.3.209 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 1.3.208 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 1.3.207 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 1.3.206 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 1.3.205 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 1.3.204 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 1.3.203 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 1.3.202 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 1.3.201 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 1.3.200 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 1.3.199 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 1.3.198 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 1.3.197 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 1.3.196 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 1.3.195 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 1.3.194 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 1.3.193 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 1.3.192 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 1.3.191 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 1.3.190 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 1.3.189 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 1.3.188 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 1.3.187 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 1.3.186 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 1.3.185 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 1.3.184 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 1.3.183 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 1.3.182 +Thu, 23 Sep 2021 00:10:40 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 1.3.181 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 1.3.180 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 1.3.179 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 1.3.178 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 1.3.177 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 1.3.176 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 1.3.175 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 1.3.174 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 1.3.173 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 1.3.172 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 1.3.171 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 1.3.170 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 1.3.169 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 1.3.168 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 1.3.167 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 1.3.166 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 1.3.165 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 1.3.164 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 1.3.163 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 1.3.162 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 1.3.161 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 1.3.160 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 1.3.159 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 1.3.158 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 1.3.157 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 1.3.156 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 1.3.155 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 1.3.154 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 1.3.153 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 1.3.152 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 1.3.151 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 1.3.150 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 1.3.149 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 1.3.148 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 1.3.147 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 1.3.146 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 1.3.145 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 1.3.144 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 1.3.143 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 1.3.142 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 1.3.141 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 1.3.140 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 1.3.139 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 1.3.138 +Thu, 13 May 2021 01:52:46 GMT + +_Version update only_ + +## 1.3.137 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 1.3.136 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 1.3.135 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 1.3.134 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 1.3.133 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 1.3.132 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 1.3.131 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 1.3.130 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 1.3.129 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 1.3.128 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 1.3.127 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 1.3.126 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 1.3.125 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 1.3.124 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 1.3.123 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 1.3.122 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 1.3.121 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 1.3.120 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 1.3.119 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 1.3.118 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 1.3.117 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 1.3.116 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 1.3.115 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 1.3.114 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 1.3.113 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 1.3.112 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 1.3.111 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 1.3.110 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 1.3.109 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 1.3.108 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 1.3.107 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 1.3.106 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 1.3.105 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 1.3.104 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 1.3.103 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 1.3.102 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 1.3.101 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 1.3.100 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 1.3.99 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 1.3.98 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 1.3.97 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 1.3.96 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 1.3.95 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 1.3.94 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 1.3.93 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 1.3.92 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 1.3.91 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 1.3.90 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 1.3.89 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 1.3.88 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 1.3.87 +Thu, 29 Oct 2020 00:11:33 GMT + +_Version update only_ + +## 1.3.86 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 1.3.85 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 1.3.84 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 1.3.83 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 1.3.82 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 1.3.81 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 1.3.80 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 1.3.79 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 1.3.78 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 1.3.77 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 1.3.76 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 1.3.75 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 1.3.74 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 1.3.73 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 1.3.72 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 1.3.71 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 1.3.70 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 1.3.69 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 1.3.68 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 1.3.67 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 1.3.66 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 1.3.65 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 1.3.64 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 1.3.63 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 1.3.62 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 1.3.61 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 1.3.60 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 1.3.59 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 1.3.58 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 1.3.57 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 1.3.56 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 1.3.55 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 1.3.54 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 1.3.53 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 1.3.52 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 1.3.51 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 1.3.50 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 1.3.49 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 1.3.48 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 1.3.47 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 1.3.46 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 1.3.45 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 1.3.44 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 1.3.43 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 1.3.42 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 1.3.41 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 1.3.40 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 1.3.39 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 1.3.38 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 1.3.37 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 1.3.36 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 1.3.35 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 1.3.34 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 1.3.33 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 1.3.32 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 1.3.31 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 1.3.30 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 1.3.29 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 1.3.28 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 1.3.27 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 1.3.26 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 1.3.25 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 1.3.24 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 1.3.23 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 1.3.22 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 1.3.21 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 1.3.20 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 1.3.19 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 1.3.18 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 1.3.17 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 1.3.16 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 1.3.15 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 1.3.14 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 1.3.13 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 1.3.12 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 1.3.11 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 1.3.10 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 1.3.9 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 1.3.8 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 1.3.7 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 1.3.6 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 1.3.5 Tue, 17 Mar 2020 23:55:58 GMT @@ -17,22 +2186,22 @@ Tue, 17 Mar 2020 23:55:58 GMT ## 1.3.4 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 1.3.3 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 1.3.2 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 1.3.1 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 1.3.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -44,102 +2213,102 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 1.2.200 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 1.2.199 Tue, 14 Jan 2020 01:34:15 GMT -*Version update only* +_Version update only_ ## 1.2.198 Sat, 11 Jan 2020 05:18:23 GMT -*Version update only* +_Version update only_ ## 1.2.197 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 1.2.196 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 1.2.195 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 1.2.194 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 1.2.193 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 1.2.192 Wed, 20 Nov 2019 06:14:28 GMT -*Version update only* +_Version update only_ ## 1.2.191 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 1.2.190 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 1.2.189 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 1.2.188 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 1.2.187 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 1.2.186 Fri, 25 Oct 2019 15:08:54 GMT -*Version update only* +_Version update only_ ## 1.2.185 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 1.2.184 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 1.2.183 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 1.2.182 Sun, 06 Oct 2019 00:27:39 GMT -*Version update only* +_Version update only_ ## 1.2.181 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 1.2.180 Sun, 29 Sep 2019 23:56:29 GMT @@ -151,547 +2320,547 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 1.2.179 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 1.2.178 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 1.2.177 Mon, 23 Sep 2019 15:14:55 GMT -*Version update only* +_Version update only_ ## 1.2.176 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 1.2.175 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 1.2.174 Tue, 10 Sep 2019 22:32:23 GMT -*Version update only* +_Version update only_ ## 1.2.173 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 1.2.172 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 1.2.171 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 1.2.170 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 1.2.169 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 1.2.168 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 1.2.167 Thu, 08 Aug 2019 00:49:05 GMT -*Version update only* +_Version update only_ ## 1.2.166 Mon, 05 Aug 2019 22:04:32 GMT -*Version update only* +_Version update only_ ## 1.2.165 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 1.2.164 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 1.2.163 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 1.2.162 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 1.2.161 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 1.2.160 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 1.2.159 Mon, 08 Jul 2019 19:12:18 GMT -*Version update only* +_Version update only_ ## 1.2.158 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 1.2.157 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 1.2.156 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.2.155 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 1.2.154 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 1.2.153 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 1.2.152 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 1.2.151 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 1.2.150 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 1.2.149 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 1.2.148 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 1.2.147 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 1.2.146 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 1.2.145 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 1.2.144 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 1.2.143 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 1.2.142 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 1.2.141 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 1.2.140 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 1.2.139 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 1.2.138 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 1.2.137 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 1.2.136 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 1.2.135 Tue, 26 Mar 2019 20:54:18 GMT -*Version update only* +_Version update only_ ## 1.2.134 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 1.2.133 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 1.2.132 Thu, 21 Mar 2019 01:15:33 GMT -*Version update only* +_Version update only_ ## 1.2.131 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 1.2.130 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 1.2.129 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 1.2.128 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 1.2.127 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 1.2.126 Mon, 11 Mar 2019 16:13:36 GMT -*Version update only* +_Version update only_ ## 1.2.125 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 1.2.124 Mon, 04 Mar 2019 17:13:19 GMT -*Version update only* +_Version update only_ ## 1.2.123 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 1.2.122 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 1.2.121 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 1.2.120 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 1.2.119 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 1.2.118 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 1.2.117 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 1.2.116 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 1.2.115 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 1.2.114 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 1.2.113 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 1.2.112 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 1.2.111 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 1.2.110 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 1.2.109 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 1.2.108 Fri, 07 Dec 2018 17:04:56 GMT -*Version update only* +_Version update only_ ## 1.2.107 Fri, 30 Nov 2018 23:34:58 GMT -*Version update only* +_Version update only_ ## 1.2.106 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 1.2.105 Thu, 29 Nov 2018 00:35:39 GMT -*Version update only* +_Version update only_ ## 1.2.104 Wed, 28 Nov 2018 19:29:53 GMT -*Version update only* +_Version update only_ ## 1.2.103 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 1.2.102 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 1.2.101 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 1.2.100 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 1.2.99 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 1.2.98 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 1.2.97 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 1.2.96 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 1.2.95 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 1.2.94 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 1.2.93 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 1.2.92 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 1.2.91 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 1.2.90 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 1.2.89 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 1.2.88 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 1.2.87 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 1.2.86 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 1.2.85 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 1.2.84 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 1.2.83 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 1.2.82 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 1.2.81 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 1.2.80 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 1.2.79 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 1.2.78 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 1.2.77 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 1.2.76 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 1.2.75 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 1.2.74 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 1.2.73 Thu, 20 Sep 2018 23:57:22 GMT -*Version update only* +_Version update only_ ## 1.2.72 Tue, 18 Sep 2018 21:04:55 GMT -*Version update only* +_Version update only_ ## 1.2.71 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 1.2.70 Thu, 06 Sep 2018 01:25:26 GMT @@ -703,37 +2872,37 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 1.2.69 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 1.2.68 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 1.2.67 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 1.2.66 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 1.2.65 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 1.2.64 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 1.2.63 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 1.2.62 Thu, 23 Aug 2018 18:18:53 GMT @@ -745,267 +2914,267 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 1.2.61 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 1.2.60 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 1.2.59 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 1.2.58 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 1.2.57 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 1.2.56 Thu, 09 Aug 2018 16:04:24 GMT -*Version update only* +_Version update only_ ## 1.2.55 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 1.2.54 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 1.2.53 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 1.2.52 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 1.2.51 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 1.2.50 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 1.2.49 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 1.2.48 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 1.2.47 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 1.2.46 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 1.2.45 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 1.2.44 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 1.2.43 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 1.2.42 Fri, 08 Jun 2018 08:43:52 GMT -*Version update only* +_Version update only_ ## 1.2.41 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 1.2.40 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 1.2.39 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 1.2.38 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 1.2.37 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 1.2.36 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 1.2.35 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 1.2.34 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 1.2.33 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 1.2.32 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 1.2.31 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 1.2.30 Mon, 02 Apr 2018 16:05:24 GMT -*Version update only* +_Version update only_ ## 1.2.29 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 1.2.28 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 1.2.27 Sun, 25 Mar 2018 01:26:19 GMT -*Version update only* +_Version update only_ ## 1.2.26 Fri, 23 Mar 2018 00:34:53 GMT -*Version update only* +_Version update only_ ## 1.2.25 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 1.2.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 1.2.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 1.2.22 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 1.2.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 1.2.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 1.2.19 Mon, 12 Mar 2018 20:36:19 GMT -*Version update only* +_Version update only_ ## 1.2.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 1.2.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 1.2.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 1.2.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 1.2.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 1.2.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 1.2.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 1.2.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.2.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.2.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 1.2.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1017,37 +3186,37 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 1.2.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 1.2.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 1.2.5 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 1.2.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.2.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 1.2.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 1.2.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 1.2.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1059,57 +3228,57 @@ Wed, 10 Jan 2018 20:40:01 GMT ## 1.1.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 1.1.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 1.1.11 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 1.1.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 1.1.9 Tue, 12 Dec 2017 03:33:26 GMT -*Version update only* +_Version update only_ ## 1.1.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 1.1.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 1.1.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 1.1.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 1.1.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 1.1.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 1.1.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -1121,7 +3290,7 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 1.1.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 1.1.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -1140,17 +3309,17 @@ Tue, 19 Sep 2017 19:04:50 GMT ## 1.0.5 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 1.0.4 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 1.0.3 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 1.0.2 Tue, 28 Feb 2017 02:01:29 GMT diff --git a/webpack/loader-raw-script/LICENSE b/webpack/loader-raw-script/LICENSE index d5923df9eb4..efdea4ef4ce 100644 --- a/webpack/loader-raw-script/LICENSE +++ b/webpack/loader-raw-script/LICENSE @@ -1,24 +1,24 @@ -@rushstack/loader-raw-script - -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. +@rushstack/loader-raw-script + +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/webpack/loader-raw-script/README.md b/webpack/loader-raw-script/README.md index 344c6af57ad..1827d53f79d 100644 --- a/webpack/loader-raw-script/README.md +++ b/webpack/loader-raw-script/README.md @@ -1,4 +1,4 @@ -# raw-script loader for webpack +# @rushstack/loader-raw-script ## Installation @@ -6,7 +6,7 @@ ## Overview -This simple loader loads a script file's contents directly in a webpack bundle using an `eval(...)`. +This simple Webpack loader loads a script file's contents directly in a webpack bundle using an `eval(...)`. ## Usage @@ -16,6 +16,10 @@ This simple loader loads a script file's contents directly in a webpack bundle u require("@rushstack/loader-raw-script!path/to/script.js"); ``` -## License +## Links -MIT (http://www.opensource.org/licenses/mit-license.php) +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/loader-raw-script/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/loader-raw-script` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/loader-raw-script/config/jest.config.json b/webpack/loader-raw-script/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/loader-raw-script/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/loader-raw-script/config/rig.json b/webpack/loader-raw-script/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/loader-raw-script/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/webpack/loader-raw-script/eslint.config.js b/webpack/loader-raw-script/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/loader-raw-script/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/webpack/loader-raw-script/gulpfile.js b/webpack/loader-raw-script/gulpfile.js deleted file mode 100644 index 296eccbf8a6..00000000000 --- a/webpack/loader-raw-script/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/webpack/loader-raw-script/package.json b/webpack/loader-raw-script/package.json index a4b5ad8f75f..cc031eb2e40 100644 --- a/webpack/loader-raw-script/package.json +++ b/webpack/loader-raw-script/package.json @@ -1,28 +1,26 @@ { "name": "@rushstack/loader-raw-script", - "version": "1.3.6", + "version": "1.5.7", "description": "", "main": "lib/index.js", "typings": "lib/index.d.ts", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/webpack/loader-raw-script" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/loader-raw-script" }, "scripts": { - "build": "gulp test --clean" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "loader-utils": "~1.1.0" + "loader-utils": "1.4.2" }, "devDependencies": { - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "mocha": "^5.2.0", - "@microsoft/node-library-build": "6.4.6" + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" } } diff --git a/webpack/loader-raw-script/src/RawScriptLoader.ts b/webpack/loader-raw-script/src/RawScriptLoader.ts index 778701a76f5..b33bb849a57 100644 --- a/webpack/loader-raw-script/src/RawScriptLoader.ts +++ b/webpack/loader-raw-script/src/RawScriptLoader.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 { EOL } from 'os'; +import { EOL } from 'node:os'; const loaderFn: (content: string) => string = (content: string) => { content = content.replace(/\\/g, '\\\\'); - content = content.replace(/'/g, '\\\''); + content = content.replace(/'/g, "\\'"); content = content.replace(/\n/g, '\\n'); content = content.replace(/\r/g, '\\r'); diff --git a/webpack/loader-raw-script/src/test/RawScriptLoader.test.ts b/webpack/loader-raw-script/src/test/RawScriptLoader.test.ts index 1eb77887c97..b29eda6d79d 100644 --- a/webpack/loader-raw-script/src/test/RawScriptLoader.test.ts +++ b/webpack/loader-raw-script/src/test/RawScriptLoader.test.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 { assert } from 'chai'; import RawScriptLoader = require('./../RawScriptLoader'); function wrapResult(result: string): string { @@ -10,20 +9,20 @@ function wrapResult(result: string): string { exports;`; } -describe('RawScriptLoader', () => { +describe(RawScriptLoader.name, () => { it('follows the Webpack loader interface', () => { - assert.isDefined(RawScriptLoader); - assert.isFunction(RawScriptLoader); + expect(RawScriptLoader).toBeDefined(); + expect(typeof RawScriptLoader).toEqual('function'); }); it('returns a string', () => { - assert.isString(RawScriptLoader('')); + expect(typeof RawScriptLoader('')).toEqual('string'); }); it('correctly sets exported objects', () => { const testScript: string = 'var x = 123; this.exportedObject = x;'; // eslint-disable-next-line no-eval const exports: { exportedObject: number } = eval(wrapResult(RawScriptLoader(testScript))); - assert.equal(exports.exportedObject, 123); + expect(exports.exportedObject).toEqual(123); }); -}); \ No newline at end of file +}); diff --git a/webpack/loader-raw-script/tsconfig.json b/webpack/loader-raw-script/tsconfig.json index 2ad9774fdd6..dac21d04081 100644 --- a/webpack/loader-raw-script/tsconfig.json +++ b/webpack/loader-raw-script/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json", - "compilerOptions": { - "types": [ - "node", - "mocha" - ] - } + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/webpack/localization-plugin/.eslintrc.js b/webpack/localization-plugin/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/webpack/localization-plugin/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/webpack/localization-plugin/.npmignore b/webpack/localization-plugin/.npmignore deleted file mode 100644 index e2cbe1efa92..00000000000 --- a/webpack/localization-plugin/.npmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Ignore everything by default -** - -# Use negative patterns to bring back the specific things we want to publish -!/bin/** -!/lib/** -!/dist/** -!ThirdPartyNotice.txt - -# Ignore certain files in the above folder -/dist/*.stats.* -/lib/**/test/* - -# 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 - -## Project specific definitions -# ----------------------------- - -# (Add your exceptions here) \ No newline at end of file diff --git a/webpack/localization-plugin/CHANGELOG.json b/webpack/localization-plugin/CHANGELOG.json deleted file mode 100644 index c1c115013ac..00000000000 --- a/webpack/localization-plugin/CHANGELOG.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "@rushstack/localization-plugin", - "entries": [ - { - "version": "0.1.3", - "tag": "@rushstack/localization-plugin_v0.1.3", - "date": "Wed, 18 Mar 2020 15:07:47 GMT", - "comments": { - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" - }, - { - "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.1` to `0.1.2`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" - }, - { - "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.1` to `2.4.2`" - }, - { - "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" - } - ] - } - }, - { - "version": "0.1.2", - "tag": "@rushstack/localization-plugin_v0.1.2", - "date": "Tue, 17 Mar 2020 23:55:58 GMT", - "comments": { - "patch": [ - { - "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" - }, - { - "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.0` to `0.1.1`" - }, - { - "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" - }, - { - "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" - }, - { - "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.0` to `2.4.1`" - } - ] - } - }, - { - "version": "0.1.1", - "tag": "@rushstack/localization-plugin_v0.1.1", - "date": "Thu, 12 Mar 2020 15:08:44 GMT", - "comments": { - "patch": [ - { - "comment": "Extract the TypingsGenerator logic to a new package." - } - ], - "dependency": [ - { - "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.0.0` to `0.1.0`" - } - ] - } - }, - { - "version": "0.1.0", - "tag": "@rushstack/localization-plugin_v0.1.0", - "date": "Thu, 27 Feb 2020 02:15:03 GMT", - "comments": { - "minor": [ - { - "comment": "Initial implementation of plugin." - } - ] - } - } - ] -} diff --git a/webpack/localization-plugin/CHANGELOG.md b/webpack/localization-plugin/CHANGELOG.md deleted file mode 100644 index 5b6d357cebb..00000000000 --- a/webpack/localization-plugin/CHANGELOG.md +++ /dev/null @@ -1,30 +0,0 @@ -# Change Log - @rushstack/localization-plugin - -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. - -## 0.1.3 -Wed, 18 Mar 2020 15:07:47 GMT - -*Version update only* - -## 0.1.2 -Tue, 17 Mar 2020 23:55:58 GMT - -### Patches - -- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` - -## 0.1.1 -Thu, 12 Mar 2020 15:08:44 GMT - -### Patches - -- Extract the TypingsGenerator logic to a new package. - -## 0.1.0 -Thu, 27 Feb 2020 02:15:03 GMT - -### Minor changes - -- Initial implementation of plugin. - diff --git a/webpack/localization-plugin/LICENSE b/webpack/localization-plugin/LICENSE deleted file mode 100644 index 388a2dd74ca..00000000000 --- a/webpack/localization-plugin/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -@rushstack/localization-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/webpack/localization-plugin/README.md b/webpack/localization-plugin/README.md deleted file mode 100644 index 8032492d398..00000000000 --- a/webpack/localization-plugin/README.md +++ /dev/null @@ -1,235 +0,0 @@ -# Localization Plugin for Webpack - -## Installation - -`npm install @rushstack/localization-plugin --save-dev` - -## Overview - -This plugin produces webpack bundles that have multiple locales' variants of strings embedded. It also -has out-of-box support for RESX files in addition to JSON strings files (with the extension `.loc.json`), including -support for generating typings. - -### Example Plugin Usage - -There are three example projects in this repository that make use of this plugin: - -- [Project 1](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-01) - - This project contains two webpack entrypoints (one with an async chunk, one without), without any localized -resources - - The output is a single, non-localized variant -- [Project 2](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02) - - This project contains three webpack entrypoints: - - [`indexA.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/indexA.ts) - directly references two `.loc.json` files and one `.resx` file, and dynamically imports an async chunk with - localized data, and an async chunk without localized data - - [`indexB.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/indexB.ts) - directly references two `.loc.json` files - - [`indexC.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/indexC.ts) - directly references no localized resources, and dynamically imports an async chunk without localized data - - The webpack config contains Spanish translations for most of the English strings in the resource files - - The output contains English, Spanish, and "passthrough" localized variants of files that contain - localized data, and a non-localized variant of the files that do not contain localized data -- [Project 3](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03) - - This project contains four webpack entrypoints: - - [`indexA.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03/src/indexA.ts) - directly references two `.loc.json` files and one `.resx` file, and dynamically imports an async chunk with - localized data, and an async chunk without localized data - - [`indexB.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03/src/indexB.ts) - directly references two `.loc.json` files - - [`indexC.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03/src/indexC.ts) - directly references no localized resources, and dynamically imports an async chunk with localized data - - [`indexD.ts`](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-03/src/indexD.ts) - directly references no localized resources, and dynamically imports an async chunk without localized data - - The webpack config contains Spanish translations for all of the English strings in the resource files - - The output contains English, Spanish, "passthrough," and two pseudo-localized variants of files that contain - localized data, and a non-localized variant of the files that do not contain localized data - -### `.resx` vs `.loc.json` - -[`.resx`](https://docs.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps#resources-in-resx-files) -is an XML format for resource data. It is primarily used in .NET development, and it is supported by -some translation services. See an example of a `.resx` file -[here](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/strings5.resx). -Note that the `` and `` elements are not required. Also note that although the -`.resx` supports many different types of localized data including strings and binary data, **only strings** -are supported by this plugin. - -`.loc.json` is a very simple `JSON` schema for specifying localized string and translator comments. -See an example of a `.loc.json` file -[here](https://github.com/microsoft/rushstack/tree/master/build-tests/localization-plugin-test-02/src/strings3.loc.json). - -For most projects, `.loc.json` is a simpler format to use. However for large projects, projects that already use -translation services that support `.resx`, or engineers who are already experienced .NET developers, `.resx` -may be more convenient. - -# Plugin - -To use the plugin, add it to the `plugins` array of your Webpack config. For example: - -```JavaScript -import { LocalizationPlugin } from '@rushstack/localization-plugin'; - -{ - plugins: [ - new LocalizationPlugin( /* options */ ) - ] -} -``` - -***A note about the dev server:*** When Webpack is being run by the Webpack dev server, this plugin pipes -the strings in the loc files in the source (the `.loc.json` and the `.resx` files) to the output without -any translations. - -## Options - -### `localizedData = { }` - -#### `localizedData.defaultLocale = { }` - -This option has a required property (`localeName`), to specify the name of the locale used in the -`.resx` and `.loc.json` files in the source. - -##### `localizedData.defaultLocale.fillMissingTranslationStrings = true | false` - -If this option is set to `true`, strings that are missing from `localizedData.translatedStrings` will be -provided by the default locale (the strings in the `.resx` and `.loc.json` files in the source). If -this option is unset or set to `false`, an error will be emitted if a string is missing from -`localizedData.translatedStrings`. - -#### `localizedData.translatedStrings = { }` - -This option is used to specify the localization data to be used in the build. This object has the following -structure: - - Locale name - - Compilation context-relative or absolute localization file path - - Translated strings - -For example: - -```JavaScript -translatedStrings: { - "en-us": { - "./src/strings1.loc.json": { - "string1": "the first string" - } - }, - "es-es": { - "./src/strings1.loc.json": { - "string1": "la primera cadena" - } - } -} -``` - -#### `localizedData.passthroughLocale = { }` - -This option is used to specify how and if a passthrough locale should be generated. A passthrough locale -is a generated locale in which each string's value is its name. This is useful for debugging and for identifying -cases where a locale is missing. - -This option takes two optional properties: - -##### `localizedData.passthroughLocale.usePassthroughLocale = true | false` - -If `passthroughLocale.usePassthroughLocale` is set to `true`, a passthrough locale will be included in the output. -By default, the passthrough locale's name is "passthrough." - -##### `localizedData.passthroughLocale.passthroughLocaleName = '...'` - -If `passthroughLocale.usePassthroughLocale` is set to `true`, the "passthrough" locale name can be overridden -by setting a value on `passthroughLocale.passthroughLocaleName`. - -#### `localizedData.pseudolocales = { }` - -This option allows pseudolocales to be generated from the strings in the default locale. This option takes -an option with pseudolocales as keys and options for the -[pseudolocale package](https://www.npmjs.com/package/pseudolocale) as values. - -### `filesToIgnore = [ ]` - -This option is used to specify `.resx` and `.loc.json` files that should not be processed by this plugin. -By default, every `.resx` and `.loc.json` file import is intercepted by this plugin, and an error occurs -if translations aren't provided for an intercepted file and the -`localizedData.defaultLocale.fillMissingTranslationStrings` option is set to `false` To avoid that error, -list files that should be ignored by this plugin in this property. Files should be specified as either -absolute paths or paths relative to the Webpack compilation context. - -### `noStringsLocaleName = '...'` - -The value to replace the `[locale]` token with for chunks without localized strings. Defaults to "none" - -### `localizationStats = { }` - -#### `localizationStats.dropPath = '...'` - -This option is used to designate a path at which a JSON file describing the localized assets produced should be -written. If this property is omitted, the stats file won't be written. - -The file has the following format: - -```JSON -{ - "entrypoints": { - "": { - "localizedAssets": { - "": "", - "": "" - } - }, - "": { - "localizedAssets": { - "": "", - "": "" - } - } - }, - "namedChunkGroups": { - "": { - "localizedAssets": { - "": "", - "": "" - } - }, - "": { - "localizedAssets": { - "": "", - "": "" - } - } - } -} - -``` - -#### `localizationStats.callback = (stats) => { ... }` - -This option is used to specify a callback to be called with the stats data that would be dropped at -[`localizationStats.dropPath`](#localizationStats.DropPath--) after compilation completes. - -### `typingsOptions = { }` - -This option is used to specify how and if TypeScript typings should be generated for loc files. - -It takes two options: - -#### `typingsOptions.generatedTsFolder = '...'` - -This property specifies the folder in which `.d.ts` files for loc files should be dropped. It is recommended -that this be a folder parallel to the source folder, specified in addition to the source folder in the -[`rootDirs` `tsconfig.json` option](https://www.typescriptlang.org/docs/handbook/compiler-options.html). -**The folder specified by this option is emptied when compilation is started.** - -This property is required if `typingsOptions` is set. - -#### `typingsOptions.sourceRoot = '...'` - -This optional property overrides the compiler context for discovery of localization files for which -typings should be generated. - -#### `typingsOptions.exportAsDefault = true | false` - -If this option is set to `true`, loc modules typings will be exported wrapped in a `default` property. This -allows strings to be imported by using the `import strings from './strings.loc.json';` syntax instead of -the `import { string1 } from './strings.loc.json';` or the `import * as strings from './strings.loc.json';` -syntax. This option is not recommended. diff --git a/webpack/localization-plugin/gulpfile.js b/webpack/localization-plugin/gulpfile.js deleted file mode 100644 index 96f6f354822..00000000000 --- a/webpack/localization-plugin/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -const build = require('@microsoft/node-library-build'); - -build.initialize(require('gulp')); diff --git a/webpack/localization-plugin/package.json b/webpack/localization-plugin/package.json deleted file mode 100644 index 7e3d981afb4..00000000000 --- a/webpack/localization-plugin/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@rushstack/localization-plugin", - "version": "0.1.3", - "description": "This plugin facilitates localization with Webpack.", - "main": "lib/index.js", - "typings": "dist/localization-plugin.d.ts", - "tsdoc": { - "tsdocFlavor": "AEDoc" - }, - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/Microsoft/rushstack/tree/master/webpack/localization-plugin" - }, - "scripts": { - "build": "gulp test --clean" - }, - "peerDependencies": { - "webpack": "^4.31.0", - "@types/webpack": "*" - }, - "optionalPeerDependencies": { - "@rushstack/set-webpack-public-path-plugin": "^2.3.4" - }, - "dependencies": { - "@types/node": "10.17.13", - "@types/tapable": "1.0.4", - "@rushstack/node-core-library": "3.19.5", - "@rushstack/typings-generator": "0.1.2", - "loader-utils": "~1.1.0", - "jju": "~1.4.0", - "lodash": "~4.17.15", - "xmldoc": "~1.1.2", - "pseudolocale": "~1.1.0", - "decache": "~4.5.1" - }, - "devDependencies": { - "@types/webpack": "4.39.8", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@microsoft/node-library-build": "6.4.6", - "@rushstack/set-webpack-public-path-plugin": "2.4.2", - "@rushstack/eslint-config": "0.5.5", - "@types/loader-utils": "1.1.3", - "@types/jju": "1.4.1", - "@types/lodash": "4.14.116", - "@types/xmldoc": "1.1.4", - "gulp": "~4.0.2", - "webpack": "~4.31.0" - } -} diff --git a/webpack/localization-plugin/src/AssetProcessor.ts b/webpack/localization-plugin/src/AssetProcessor.ts deleted file mode 100644 index 8213359debc..00000000000 --- a/webpack/localization-plugin/src/AssetProcessor.ts +++ /dev/null @@ -1,450 +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 Webpack from 'webpack'; -import * as lodash from 'lodash'; - -import { Constants } from './utilities/Constants'; -import { EntityMarker } from './utilities/EntityMarker'; -import { ILocaleElementMap } from './interfaces'; -import { LocalizationPlugin, IStringSerialNumberData as IStringData } from './LocalizationPlugin'; - -interface IReconstructionElement { - kind: 'static' | 'localized' | 'dynamic'; -} - -interface IStaticReconstructionElement extends IReconstructionElement { - kind: 'static'; - staticString: string; -} - -interface ILocalizedReconstructionElement extends IReconstructionElement { - kind: 'localized'; - values: ILocaleElementMap; - size: number; - stringName: string; - locFilePath: string; -} - -interface IDynamicReconstructionElement extends IReconstructionElement { - kind: 'dynamic'; - valueFn: (locale: string | undefined, token: string | undefined) => string; - size: number; - token?: string; -} - -interface IParseResult { - issues: string[]; - reconstructionSeries: IReconstructionElement[]; -} - -interface IReconstructedString { - source: string; - size: number; -} - -interface ILocalizedReconstructionResult { - result: Map; - issues: string[]; -} - -interface INonLocalizedReconstructionResult { - result: IReconstructedString; - issues: string[]; -} - -export interface IProcessAssetOptionsBase { - plugin: LocalizationPlugin; - compilation: Webpack.compilation.Compilation; - assetName: string; - asset: IAsset; - chunk: Webpack.compilation.Chunk; - noStringsLocaleName: string; -} - -export interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBase { } - -export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase { - locales: Set; - fillMissingTranslationStrings: boolean; - defaultLocale: string; -} - -export interface IAsset { - size(): number; - source(): string; -} - -export interface IProcessAssetResult { - filename: string; - asset: IAsset; -} - -const PLACEHOLDER_REGEX: RegExp = new RegExp( - `${Constants.STRING_PLACEHOLDER_PREFIX}_([A-C])(\\+[^+]+\\+)?_(\\d+)`, - 'g' -); - -export class AssetProcessor { - public static processLocalizedAsset(options: IProcessLocalizedAssetOptions): Map { - const assetSource: string = options.asset.source(); - - const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence( - options.plugin, - assetSource, - this._getJsonpFunction(options.chunk, options.noStringsLocaleName) - ); - const reconstructedAsset: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized( - parsedAsset.reconstructionSeries, - options.locales, - options.fillMissingTranslationStrings, - options.defaultLocale, - options.asset.size() - ); - - const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence( - options.plugin, - options.assetName, - () => { throw new Error('unsupported'); } - ); - const reconstructedAssetName: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized( - parsedAssetName.reconstructionSeries, - options.locales, - options.fillMissingTranslationStrings, - options.defaultLocale, - options.assetName.length - ); - - const result: Map = new Map(); - for (const [locale, { source, size }] of reconstructedAsset.result) { - const newAsset: IAsset = lodash.clone(options.asset); - newAsset.source = () => source; - newAsset.size = () => size; - - result.set( - locale, - { - filename: reconstructedAssetName.result.get(locale)!.source, - asset: newAsset - } - ); - } - - const issues: string[] = [ - ...parsedAsset.issues, - ...reconstructedAsset.issues, - ...parsedAssetName.issues, - ...reconstructedAssetName.issues - ]; - - if (issues.length > 0) { - options.compilation.errors.push(Error( - `localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}` - )); - } - - return result; - } - - public static processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptions): IProcessAssetResult { - const assetSource: string = options.asset.source(); - - const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence( - options.plugin, - assetSource, - this._getJsonpFunction(options.chunk, options.noStringsLocaleName) - ); - const reconstructedAsset: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized( - parsedAsset.reconstructionSeries, - options.asset.size(), - options.noStringsLocaleName - ); - - const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence( - options.plugin, - options.assetName, - () => { throw new Error('unsupported'); } - ); - const reconstructedAssetName: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized( - parsedAssetName.reconstructionSeries, - options.assetName.length, - options.noStringsLocaleName - ); - - const issues: string[] = [ - ...parsedAsset.issues, - ...reconstructedAsset.issues, - ...parsedAssetName.issues, - ...reconstructedAssetName.issues - ]; - - if (issues.length > 0) { - options.compilation.errors.push(Error( - `localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}` - )); - } - - const newAsset: IAsset = lodash.clone(options.asset); - newAsset.source = () => reconstructedAsset.result.source; - newAsset.size = () => reconstructedAsset.result.size; - return { - filename: reconstructedAssetName.result.source, - asset: newAsset - }; - } - - private static _reconstructLocalized( - reconstructionSeries: IReconstructionElement[], - locales: Set, - fillMissingTranslationStrings: boolean, - defaultLocale: string, - initialSize: number - ): ILocalizedReconstructionResult { - const localizedResults: Map = new Map(); - const issues: string[] = []; - - for (const locale of locales) { - const reconstruction: string[] = []; - - let sizeDiff: number = 0; - for (const element of reconstructionSeries) { - switch (element.kind) { - case 'static': { - reconstruction.push((element as IStaticReconstructionElement).staticString); - break; - } - - case 'localized': { - const localizedElement: ILocalizedReconstructionElement = element as ILocalizedReconstructionElement; - let newValue: string | undefined = localizedElement.values[locale]; - if (!newValue) { - if (fillMissingTranslationStrings) { - newValue = localizedElement.values[defaultLocale]; - } else { - issues.push( - `The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" is missing in ` + - `the locale ${locale}` - ); - - newValue = '-- MISSING STRING --'; - } - } - - // Replace the quotemark character with a unicode-escaped character - newValue = newValue.replace(/\"/g, '\\u0022'); - - // Replace the apostrophe character with a unicode-escaped character - newValue = newValue.replace(/\'/g, '\\u0027'); - - reconstruction.push(newValue); - sizeDiff += (newValue.length - localizedElement.size); - break; - } - - case 'dynamic': { - const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement; - const newValue: string = dynamicElement.valueFn(locale, dynamicElement.token); - reconstruction.push(newValue); - sizeDiff += (newValue.length - dynamicElement.size); - break; - } - } - } - - const newAssetSource: string = reconstruction.join(''); - localizedResults.set( - locale, - { - source: newAssetSource, - size: initialSize + sizeDiff - } - ); - } - - return { - issues, - result: localizedResults - }; - } - - private static _reconstructNonLocalized( - reconstructionSeries: IReconstructionElement[], - initialSize: number, - noStringsLocaleName: string - ): INonLocalizedReconstructionResult { - const issues: string[] = []; - - const reconstruction: string[] = []; - - let sizeDiff: number = 0; - for (const element of reconstructionSeries) { - switch (element.kind) { - case 'static': { - reconstruction.push((element as IStaticReconstructionElement).staticString); - break; - } - - case 'localized': { - const localizedElement: ILocalizedReconstructionElement = element as ILocalizedReconstructionElement; - issues.push( - `The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" appeared in an asset ` + - 'that is not expected to contain localized resources.' - ); - - const newValue: string = '-- NOT EXPECTED TO BE LOCALIZED --'; - reconstruction.push(newValue); - sizeDiff += (newValue.length - localizedElement.size); - break; - } - - case 'dynamic': { - const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement; - const newValue: string = dynamicElement.valueFn(noStringsLocaleName, dynamicElement.token); - reconstruction.push(newValue); - sizeDiff += (newValue.length - dynamicElement.size); - break; - } - } - } - - const newAssetSource: string = reconstruction.join(''); - return { - issues, - result: { - source: newAssetSource, - size: initialSize + sizeDiff - } - }; - } - - private static _parseStringToReconstructionSequence( - plugin: LocalizationPlugin, - source: string, - jsonpFunction: (locale: string, chunkIdToken: string) => string - ): IParseResult { - const issues: string[] = []; - const reconstructionSeries: IReconstructionElement[] = []; - - let lastIndex: number = 0; - let regexResult: RegExpExecArray | null; - while (regexResult = PLACEHOLDER_REGEX.exec(source)) { // eslint-disable-line no-cond-assign - const staticElement: IStaticReconstructionElement = { - kind: 'static', - staticString: source.substring(lastIndex, regexResult.index) - }; - reconstructionSeries.push(staticElement); - - const [placeholder, elementLabel, token, placeholderSerialNumber] = regexResult; - - let localizedReconstructionElement: IReconstructionElement; - switch (elementLabel) { - case Constants.STRING_PLACEHOLDER_LABEL: { - const stringData: IStringData | undefined = plugin.getDataForSerialNumber(placeholderSerialNumber); - if (!stringData) { - issues.push(`Missing placeholder ${placeholder}`); - const brokenLocalizedElement: IStaticReconstructionElement = { - kind: 'static', - staticString: placeholder - }; - localizedReconstructionElement = brokenLocalizedElement; - } else { - const localizedElement: ILocalizedReconstructionElement = { - kind: 'localized', - values: stringData.values, - size: placeholder.length, - locFilePath: stringData.locFilePath, - stringName: stringData.stringName, - }; - localizedReconstructionElement = localizedElement; - } - break; - } - - case Constants.LOCALE_NAME_PLACEHOLDER_LABEL: { - const dynamicElement: IDynamicReconstructionElement = { - kind: 'dynamic', - valueFn: (locale: string) => locale, - size: placeholder.length - }; - localizedReconstructionElement = dynamicElement; - break; - } - - case Constants.JSONP_PLACEHOLDER_LABEL: { - const dynamicElement: IDynamicReconstructionElement = { - kind: 'dynamic', - valueFn: jsonpFunction, - size: placeholder.length, - token: token.substring(1, token.length - 1) - }; - localizedReconstructionElement = dynamicElement; - break; - } - - default:{ - throw new Error(`Unexpected label ${elementLabel}`); - } - } - - reconstructionSeries.push(localizedReconstructionElement); - lastIndex = regexResult.index + placeholder.length; - } - - const lastElement: IStaticReconstructionElement = { - kind: 'static', - staticString: source.substr(lastIndex) - }; - reconstructionSeries.push(lastElement); - - return { - issues, - reconstructionSeries - }; - } - - private static _getJsonpFunction( - chunk: Webpack.compilation.Chunk, - noStringsLocaleName: string - ): (locale: string, chunkIdToken: string | undefined) => string { - const idsWithStrings: Set = new Set(); - const idsWithoutStrings: Set = new Set(); - - const asyncChunks: Set = chunk.getAllAsyncChunks(); - for (const asyncChunk of asyncChunks) { - if (EntityMarker.getMark(asyncChunk)) { - idsWithStrings.add(asyncChunk.id); - } else { - idsWithoutStrings.add(asyncChunk.id); - } - } - - if (idsWithStrings.size === 0) { - return () => JSON.stringify(noStringsLocaleName); - } else if (idsWithoutStrings.size === 0) { - return (locale: string) => JSON.stringify(locale); - } else { - // Generate an array [, ] and an object that is used as an indexer into that - // object that maps chunk IDs to 0s for chunks with localized strings and 1s for chunks without localized - // strings - // - // This can be improved in the future. We can maybe sort the chunks such that the chunks below a certain ID - // number are localized and the those above are not. - const chunkMapping: { [chunkId: string]: number } = {}; - for (const idWithStrings of idsWithStrings) { - chunkMapping[idWithStrings] = 0; - } - - for (const idWithoutStrings of idsWithoutStrings) { - chunkMapping[idWithoutStrings] = 1; - } - - return (locale: string, chunkIdToken: string) => { - if (!locale) { - throw new Error('Missing locale name.'); - } - - return `(${JSON.stringify([locale, noStringsLocaleName])})[${JSON.stringify(chunkMapping)}[${chunkIdToken}]]`; - } - } - } -} diff --git a/webpack/localization-plugin/src/LocFileTypingsGenerator.ts b/webpack/localization-plugin/src/LocFileTypingsGenerator.ts deleted file mode 100644 index 5dda3860cfe..00000000000 --- a/webpack/localization-plugin/src/LocFileTypingsGenerator.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - StringValuesTypingsGenerator, - IStringValueTyping -} from '@rushstack/typings-generator'; -import { Terminal } from '@rushstack/node-core-library'; - -import { ILocalizationFile } from './interfaces'; -import { ILoggerOptions } from './utilities/Logging'; -import { LocFileParser } from './utilities/LocFileParser'; - -/** - * @public - */ -export interface ITypingsGeneratorOptions { - srcFolder: string; - generatedTsFolder: string; - terminal?: Terminal; - exportAsDefault?: boolean; - filesToIgnore?: string[]; -} - -/** - * This is a simple tool that generates .d.ts files for .loc.json and .resx files. - * - * @public - */ -export class LocFileTypingsGenerator extends StringValuesTypingsGenerator { - private _loggingOptions: ILoggerOptions; - - public constructor(options: ITypingsGeneratorOptions) { - super({ - ...options, - fileExtensions: ['resx', 'loc.json'], - parseAndGenerateTypings: (fileContents: string, filePath: string) => { - const locFileData: ILocalizationFile = LocFileParser.parseLocFile({ - filePath: filePath, - content: fileContents, - loggerOptions: this._loggingOptions - }); - - const typings: IStringValueTyping[] = []; - - for (const stringName in locFileData) { // eslint-disable-line guard-for-in - typings.push({ - exportName: stringName, - comment: locFileData[stringName].comment - }); - } - - return { typings }; - } - }); - - this._loggingOptions = { - writeError: this._options.terminal!.writeErrorLine.bind(this._options.terminal), - writeWarning: this._options.terminal!.writeWarningLine.bind(this._options.terminal) - }; - } -} \ No newline at end of file diff --git a/webpack/localization-plugin/src/LocalizationPlugin.ts b/webpack/localization-plugin/src/LocalizationPlugin.ts deleted file mode 100644 index 366539bbcec..00000000000 --- a/webpack/localization-plugin/src/LocalizationPlugin.ts +++ /dev/null @@ -1,658 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { JsonFile } from '@rushstack/node-core-library'; -import * as Webpack from 'webpack'; -import * as path from 'path'; -import * as Tapable from 'tapable'; - -import { Constants } from './utilities/Constants'; -import { - IWebpackConfigurationUpdaterOptions, - WebpackConfigurationUpdater -} from './WebpackConfigurationUpdater'; -import { - ILocalizationPluginOptions, - ILocalizationStats, - ILocaleFileData, - ILocaleData, - ILocalizationFile, - IPseudolocaleOptions, - ILocaleElementMap -} from './interfaces'; -import { - ILocalizedWebpackChunk -} from './webpackInterfaces'; -import { LocFileTypingsGenerator } from './LocFileTypingsGenerator'; -import { Pseudolocalization } from './Pseudolocalization'; -import { EntityMarker } from './utilities/EntityMarker'; -import { IAsset, IProcessAssetResult, AssetProcessor } from './AssetProcessor'; - -/** - * @internal - */ -export interface IStringPlaceholder { - value: string; - suffix: string; -} - -interface IExtendedMainTemplate { - hooks: { - assetPath: Tapable.SyncHook; - }; -} - -interface IExtendedConfiguration extends Webpack.compilation.Compilation { - options: Webpack.Configuration; -} - -interface IExtendedChunkGroup extends Webpack.compilation.ChunkGroup { - getChildren(): Webpack.compilation.Chunk[]; -} - -interface IExtendedChunk extends Webpack.compilation.Chunk { - filenameTemplate: string; -} - -interface IAssetPathOptions { - chunk: Webpack.compilation.Chunk; - contentHashType: string; -} - -/** - * @internal - */ -export interface IStringSerialNumberData { - values: ILocaleElementMap; - locFilePath: string; - stringName: string; -} - -const PLUGIN_NAME: string = 'localization'; - -/** - * This plugin facilitates localization in webpack. - * - * @public - */ -export class LocalizationPlugin implements Webpack.Plugin { - /** - * @internal - */ - public stringKeys: Map = new Map(); - - private _options: ILocalizationPluginOptions; - private _filesToIgnore: Set = new Set(); - private _stringPlaceholderCounter: number = 0; - private _stringPlaceholderMap: Map = new Map(); - private _locales: Set = new Set(); - private _passthroughLocaleName: string; - private _defaultLocale: string; - private _noStringsLocaleName: string; - private _fillMissingTranslationStrings: boolean; - private _pseudolocalizers: Map string> = new Map string>(); - - /** - * The outermost map's keys are the locale names. - * The middle map's keys are the resolved, file names. - * The innermost map's keys are the string identifiers and its values are the string values. - */ - private _resolvedLocalizedStrings: Map>> = new Map>>(); - - public constructor(options: ILocalizationPluginOptions) { - this._options = options; - } - - public apply(compiler: Webpack.Compiler): void { - const isWebpack4: boolean = !!compiler.hooks; - - if (!isWebpack4) { - throw new Error('The localization plugin requires webpack 4'); - } - - if (this._options.typingsOptions && compiler.context) { - if ( - this._options.typingsOptions.generatedTsFolder && - !path.isAbsolute(this._options.typingsOptions.generatedTsFolder) - ) { - this._options.typingsOptions.generatedTsFolder = path.resolve( - compiler.context, - this._options.typingsOptions.generatedTsFolder - ); - } - - if ( - this._options.typingsOptions.sourceRoot && - !path.isAbsolute(this._options.typingsOptions.sourceRoot) - ) { - this._options.typingsOptions.sourceRoot = path.resolve( - compiler.context, - this._options.typingsOptions.sourceRoot - ); - } - } - - // https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66 - const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true'; - - const errors: Error[] = this._initializeAndValidateOptions(compiler.options, isWebpackDevServer); - - let typingsPreprocessor: LocFileTypingsGenerator | undefined; - if (this._options.typingsOptions) { - typingsPreprocessor = new LocFileTypingsGenerator({ - srcFolder: this._options.typingsOptions.sourceRoot || compiler.context, - generatedTsFolder: this._options.typingsOptions.generatedTsFolder, - exportAsDefault: this._options.typingsOptions.exportAsDefault, - filesToIgnore: this._options.filesToIgnore - }); - } else { - typingsPreprocessor = undefined; - } - - const webpackConfigurationUpdaterOptions: IWebpackConfigurationUpdaterOptions = { - pluginInstance: this, - configuration: compiler.options, - filesToIgnore: this._filesToIgnore, - localeNameOrPlaceholder: Constants.LOCALE_NAME_PLACEHOLDER - }; - - if (errors.length > 0) { - compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { - compilation.errors.push(...errors); - }); - - WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles(webpackConfigurationUpdaterOptions); - - return; - } - - if (isWebpackDevServer) { - if (typingsPreprocessor) { - compiler.hooks.watchRun.tap(PLUGIN_NAME, () => typingsPreprocessor!.runWatcher()); - - if (!compiler.options.plugins) { - compiler.options.plugins = []; - } - - compiler.options.plugins.push(new Webpack.WatchIgnorePlugin([this._options.typingsOptions!.generatedTsFolder])); - } - - WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles(webpackConfigurationUpdaterOptions); - } else { - if (typingsPreprocessor) { - compiler.hooks.beforeRun.tap(PLUGIN_NAME, () => typingsPreprocessor!.generateTypings()); - } - - WebpackConfigurationUpdater.amendWebpackConfigurationForMultiLocale(webpackConfigurationUpdaterOptions); - - if (errors.length === 0) { - compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: IExtendedConfiguration) => { - (compilation.mainTemplate as unknown as IExtendedMainTemplate).hooks.assetPath.tap( - PLUGIN_NAME, - (assetPath: string, options: IAssetPathOptions) => { - if ( - options.contentHashType === 'javascript' && - assetPath.match(Constants.LOCALE_FILENAME_PLACEHOLDER_REGEX) - ) { - // Does this look like an async chunk URL generator? - if (typeof options.chunk.id === 'string' && options.chunk.id.match(/^\" \+/)) { - return assetPath.replace( - Constants.LOCALE_FILENAME_PLACEHOLDER_REGEX, - `" + ${Constants.JSONP_PLACEHOLDER} + "` - ); - } else { - return assetPath.replace( - Constants.LOCALE_FILENAME_PLACEHOLDER_REGEX, - Constants.LOCALE_NAME_PLACEHOLDER - ); - } - } else { - return assetPath; - } - } - ); - - compilation.hooks.optimizeChunks.tap( - PLUGIN_NAME, - (chunks: IExtendedChunk[], chunkGroups: IExtendedChunkGroup[]) => { - let chunksHaveAnyChildren: boolean = false; - for (const chunkGroup of chunkGroups) { - const children: Webpack.compilation.Chunk[] = chunkGroup.getChildren(); - if (children.length > 0) { - chunksHaveAnyChildren = true; - break; - } - } - - if ( - chunksHaveAnyChildren && ( - !compilation.options.output || - !compilation.options.output.chunkFilename || - compilation.options.output.chunkFilename.indexOf(Constants.LOCALE_FILENAME_PLACEHOLDER) === -1 - ) - ) { - compilation.errors.push(new Error( - 'The configuration.output.chunkFilename property must be provided and must include ' + - `the ${Constants.LOCALE_FILENAME_PLACEHOLDER} placeholder` - )); - - return; - } - - // First pass - see if the chunk directly contains any loc modules - for (const chunk of chunks) { - let chunkHasAnyLocModules: boolean = false; - if (!chunkHasAnyLocModules) { - for (const module of chunk.getModules()) { - if (EntityMarker.getMark(module)) { - chunkHasAnyLocModules = true; - break; - } - } - } - - EntityMarker.markEntity(chunk, chunkHasAnyLocModules); - } - - // Second pass - see if the chunk loads any localized chunks - for (const chunk of chunks) { - let localizedChunk: boolean = EntityMarker.getMark(chunk); - if ( - !localizedChunk && - Array.from(chunk.getAllAsyncChunks()).some((asyncChunk) => EntityMarker.getMark(asyncChunk)) - ) { - localizedChunk = true; - EntityMarker.markEntity(chunk, true); - } - - const replacementValue: string = localizedChunk - ? Constants.LOCALE_NAME_PLACEHOLDER - : this._noStringsLocaleName; - EntityMarker.markEntity(chunk, localizedChunk); - if (chunk.hasRuntime()) { - chunk.filenameTemplate = (compilation.options.output!.filename as string).replace( - Constants.LOCALE_FILENAME_PLACEHOLDER_REGEX, - replacementValue - ); - } else { - chunk.filenameTemplate = compilation.options.output!.chunkFilename!.replace( - Constants.LOCALE_FILENAME_PLACEHOLDER_REGEX, - replacementValue - ); - } - } - } - ); - }); - - compiler.hooks.emit.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { - const localizationStats: ILocalizationStats = { - entrypoints: {}, - namedChunkGroups: {} - }; - - const alreadyProcessedAssets: Set = new Set(); - - for (const untypedChunk of compilation.chunks) { - const chunk: ILocalizedWebpackChunk = untypedChunk; - const chunkFilesSet: Set = new Set(chunk.files); - function processChunkJsFile(callback: (chunkFilename: string) => void): void { - let alreadyProcessedAFileInThisChunk: boolean = false; - for (const chunkFilename of chunk.files) { - if ( - chunkFilename.endsWith('.js') && // Ensure this is a JS file - !alreadyProcessedAssets.has(chunkFilename) // Ensure this isn't a vendor chunk we've already processed - ) { - if (alreadyProcessedAFileInThisChunk) { - throw new Error(`Found more than one JS file in chunk "${chunk.name}". This is not expected.`); - } - - alreadyProcessedAFileInThisChunk = true; - alreadyProcessedAssets.add(chunkFilename); - callback(chunkFilename); - } - } - } - - if (EntityMarker.getMark(chunk)) { - processChunkJsFile((chunkFilename) => { - if (chunkFilename.indexOf(Constants.LOCALE_NAME_PLACEHOLDER) === -1) { - throw new Error(`Asset ${chunkFilename} is expected to be localized, but is missing a locale placeholder`); - } - - const asset: IAsset = compilation.assets[chunkFilename]; - - const resultingAssets: Map = AssetProcessor.processLocalizedAsset({ - plugin: this, - compilation, - assetName: chunkFilename, - asset, - chunk, - locales: this._locales, - noStringsLocaleName: this._noStringsLocaleName, - fillMissingTranslationStrings: this._fillMissingTranslationStrings, - defaultLocale: this._defaultLocale - }); - - // Delete the existing asset because it's been renamed - delete compilation.assets[chunkFilename]; - chunkFilesSet.delete(chunkFilename); - - const localizedChunkAssets: ILocaleElementMap = {}; - for (const [locale, newAsset] of resultingAssets) { - compilation.assets[newAsset.filename] = newAsset.asset; - localizedChunkAssets[locale] = newAsset.filename; - chunkFilesSet.add(newAsset.filename); - } - - if (chunk.hasRuntime()) { - // This is an entrypoint - localizationStats.entrypoints[chunk.name] = { - localizedAssets: localizedChunkAssets - }; - } else { - // This is a secondary chunk - if (chunk.name) { - localizationStats.namedChunkGroups[chunk.name] = { - localizedAssets: localizedChunkAssets - }; - } - } - - chunk.localizedFiles = localizedChunkAssets; - }); - } else { - processChunkJsFile((chunkFilename) => { - const asset: IAsset = compilation.assets[chunkFilename]; - - const resultingAsset: IProcessAssetResult = AssetProcessor.processNonLocalizedAsset({ - plugin: this, - compilation, - assetName: chunkFilename, - asset, - chunk, - noStringsLocaleName: this._noStringsLocaleName - }); - - // Delete the existing asset because it's been renamed - delete compilation.assets[chunkFilename]; - chunkFilesSet.delete(chunkFilename); - - compilation.assets[resultingAsset.filename] = resultingAsset.asset; - chunkFilesSet.add(resultingAsset.filename); - }); - } - - chunk.files = Array.from(chunkFilesSet); - } - - if (this._options.localizationStats) { - if (this._options.localizationStats.dropPath) { - const resolvedLocalizationStatsDropPath: string = path.resolve( - compiler.outputPath, - this._options.localizationStats.dropPath - ); - JsonFile.save(localizationStats, resolvedLocalizationStatsDropPath, { ensureFolderExists: true }); - } - - if (this._options.localizationStats.callback) { - try { - this._options.localizationStats.callback(localizationStats); - } catch (e) { - /* swallow errors from the callback */ - } - } - } - }); - } - } - } - - /** - * @internal - */ - public addDefaultLocFile(locFilePath: string, locFile: ILocalizationFile): void { - const locFileData: ILocaleFileData = {}; - for (const stringName in locFile) { // eslint-disable-line guard-for-in - locFileData[stringName] = locFile[stringName].value; - } - - this._addLocFile(this._defaultLocale, locFilePath, locFileData); - - this._pseudolocalizers.forEach((pseudolocalizer: (str: string) => string, pseudolocaleName: string) => { - const pseudolocFileData: ILocaleFileData = {}; - - for (const stringName in locFileData) { - if (locFileData.hasOwnProperty(stringName)) { - pseudolocFileData[stringName] = pseudolocalizer(locFileData[stringName]); - } - } - - this._addLocFile(pseudolocaleName, locFilePath, pseudolocFileData); - }); - } - - /** - * @internal - */ - public getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined { - return this._stringPlaceholderMap.get(serialNumber); - } - - private _addLocFile(localeName: string, locFilePath: string, locFileData: ILocaleFileData): void { - const filesMap: Map> = this._resolvedLocalizedStrings.get(localeName)!; - - const stringsMap: Map = new Map(); - filesMap.set(locFilePath, stringsMap); - - for (const stringName in locFileData) { - if (locFileData.hasOwnProperty(stringName)) { - const stringKey: string = `${locFilePath}?${stringName}`; - if (!this.stringKeys.has(stringKey)) { - const placeholder: IStringPlaceholder = this._getPlaceholderString(); - this.stringKeys.set(stringKey, placeholder); - } - - const placeholder: IStringPlaceholder = this.stringKeys.get(stringKey)!; - if (!this._stringPlaceholderMap.has(placeholder.suffix)) { - this._stringPlaceholderMap.set( - placeholder.suffix, - { - values: { - [this._passthroughLocaleName]: stringName - }, - locFilePath: locFilePath, - stringName: stringName - } - ); - } - - const stringValue: string = locFileData[stringName]; - - this._stringPlaceholderMap.get(placeholder.suffix)!.values[localeName] = stringValue; - - stringsMap.set(stringName, stringValue); - } - } - } - - private _initializeAndValidateOptions(configuration: Webpack.Configuration, isWebpackDevServer: boolean): Error[] { - const errors: Error[] = []; - - function ensureValidLocaleName(localeName: string): boolean { - const LOCALE_NAME_REGEX: RegExp = /[a-z-]/i; - if (!localeName.match(LOCALE_NAME_REGEX)) { - errors.push(new Error( - `Invalid locale name: ${localeName}. Locale names may only contain letters and hyphens.` - )); - return false; - } else { - return true; - } - } - - // START configuration - if ( - !configuration.output || - !configuration.output.filename || - (typeof configuration.output.filename !== 'string') || - configuration.output.filename.indexOf(Constants.LOCALE_FILENAME_PLACEHOLDER) === -1 - ) { - errors.push(new Error( - 'The configuration.output.filename property must be provided, must be a string, and must include ' + - `the ${Constants.LOCALE_FILENAME_PLACEHOLDER} placeholder` - )); - } - // END configuration - - // START options.filesToIgnore - { // eslint-disable-line no-lone-blocks - for (const filePath of this._options.filesToIgnore || []) { - const normalizedFilePath: string = path.resolve(configuration.context!, filePath); - this._filesToIgnore.add(normalizedFilePath); - } - } - // END options.filesToIgnore - - // START options.localizedData - if (this._options.localizedData) { - // START options.localizedData.passthroughLocale - if (this._options.localizedData.passthroughLocale) { - const { - usePassthroughLocale, - passthroughLocaleName = 'passthrough' - } = this._options.localizedData.passthroughLocale; - if (usePassthroughLocale) { - this._passthroughLocaleName = passthroughLocaleName; - this._locales.add(passthroughLocaleName); - } - } - // END options.localizedData.passthroughLocale - - // START options.localizedData.translatedStrings - const { translatedStrings } = this._options.localizedData; - if (translatedStrings) { - for (const localeName in translatedStrings) { - if (translatedStrings.hasOwnProperty(localeName)) { - if (this._locales.has(localeName)) { - errors.push(Error( - `The locale "${localeName}" appears multiple times. ` + - 'There may be multiple instances with different casing.' - )); - return errors; - } - - if (!ensureValidLocaleName(localeName)) { - return errors; - } - - this._locales.add(localeName); - - this._resolvedLocalizedStrings.set(localeName, new Map>()); - - const locFilePathsInLocale: Set = new Set(); - - const locale: ILocaleData = translatedStrings[localeName]; - for (const locFilePath in locale) { - if (locale.hasOwnProperty(locFilePath)) { - const normalizedLocFilePath: string = path.resolve(configuration.context!, locFilePath); - - if (locFilePathsInLocale.has(normalizedLocFilePath)) { - errors.push(new Error( - `The localization file path "${locFilePath}" appears multiple times in locale ${localeName}. ` + - 'There may be multiple instances with different casing.' - )); - return errors; - } - - locFilePathsInLocale.add(normalizedLocFilePath); - - const locFileData: ILocaleFileData = locale[locFilePath]; - this._addLocFile(localeName, normalizedLocFilePath, locFileData); - } - } - } - } - } - // END options.localizedData.translatedStrings - - // START options.localizedData.defaultLocale - if (this._options.localizedData.defaultLocale) { - const { localeName, fillMissingTranslationStrings } = this._options.localizedData.defaultLocale; - if (this._options.localizedData.defaultLocale.localeName) { - if (this._locales.has(localeName)) { - errors.push(new Error('The default locale is also specified in the translated strings.')); - return errors; - } else if (!ensureValidLocaleName(localeName)) { - return errors; - } - - this._locales.add(localeName); - this._resolvedLocalizedStrings.set(localeName, new Map>()); - this._defaultLocale = localeName; - this._fillMissingTranslationStrings = !!fillMissingTranslationStrings; - } else { - errors.push(new Error('Missing default locale name')); - return errors; - } - } else { - errors.push(new Error('Missing default locale options.')); - return errors; - } - // END options.localizedData.defaultLocale - - // START options.localizedData.pseudoLocales - if (this._options.localizedData.pseudolocales) { - for (const pseudolocaleName in this._options.localizedData.pseudolocales) { - if (this._options.localizedData.pseudolocales.hasOwnProperty(pseudolocaleName)) { - if (this._defaultLocale === pseudolocaleName) { - errors.push(new Error(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`)); - return errors; - } - - if (this._locales.has(pseudolocaleName)) { - errors.push(new Error( - `A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.` - )); - return errors; - } - - const pseudoLocaleOpts: IPseudolocaleOptions = this._options.localizedData.pseudolocales[pseudolocaleName]; - this._pseudolocalizers.set(pseudolocaleName, Pseudolocalization.getPseudolocalizer(pseudoLocaleOpts)); - this._locales.add(pseudolocaleName); - this._resolvedLocalizedStrings.set(pseudolocaleName, new Map>()); - } - } - } - // END options.localizedData.pseudoLocales - } else if (!isWebpackDevServer) { - throw new Error('Localized data must be provided unless webpack dev server is running.'); - } - // END options.localizedData - - // START options.noStringsLocaleName - if ( - this._options.noStringsLocaleName === undefined || - this._options.noStringsLocaleName === null || - !ensureValidLocaleName(this._options.noStringsLocaleName) - ) { - this._noStringsLocaleName = 'none'; - } else { - this._noStringsLocaleName = this._options.noStringsLocaleName; - } - // END options.noStringsLocaleName - - return errors; - } - - /** - * @param token - Use this as a value that may be escaped or minified. - */ - private _getPlaceholderString(): IStringPlaceholder { - const suffix: string = (this._stringPlaceholderCounter++).toString(); - return { - value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.STRING_PLACEHOLDER_LABEL}_${suffix}`, - suffix: suffix - }; - } -} diff --git a/webpack/localization-plugin/src/Pseudolocalization.ts b/webpack/localization-plugin/src/Pseudolocalization.ts deleted file mode 100644 index fb96df6417c..00000000000 --- a/webpack/localization-plugin/src/Pseudolocalization.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import decache from 'decache'; - -import { IPseudolocaleOptions } from './interfaces'; - -export class Pseudolocalization { - public static getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string { - // pseudolocale maintains static state, so we need to load it as isolated modules - decache('pseudolocale'); - const pseudolocale = require('pseudolocale'); // eslint-disable-line - - pseudolocale.option = { - ...pseudolocale.option, - ...options - }; - return pseudolocale.str; - } -} diff --git a/webpack/localization-plugin/src/WebpackConfigurationUpdater.ts b/webpack/localization-plugin/src/WebpackConfigurationUpdater.ts deleted file mode 100644 index a59bb44af34..00000000000 --- a/webpack/localization-plugin/src/WebpackConfigurationUpdater.ts +++ /dev/null @@ -1,137 +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 Webpack from 'webpack'; -import * as SetPublicPathPluginPackageType from '@rushstack/set-webpack-public-path-plugin'; - -import { Constants } from './utilities/Constants'; -import { LocalizationPlugin } from './LocalizationPlugin'; -import { ILocLoaderOptions } from './loaders/LocLoader'; -import { IBaseLoaderOptions } from './loaders/LoaderFactory'; - -export interface IWebpackConfigurationUpdaterOptions { - pluginInstance: LocalizationPlugin; - configuration: Webpack.Configuration; - filesToIgnore: Set; - localeNameOrPlaceholder: string; -} - -export class WebpackConfigurationUpdater { - public static amendWebpackConfigurationForMultiLocale(options: IWebpackConfigurationUpdaterOptions): void { - const loader: string = path.resolve(__dirname, 'loaders', 'LocLoader.js'); - const loaderOptions: ILocLoaderOptions = { - pluginInstance: options.pluginInstance - }; - - WebpackConfigurationUpdater._addLoadersForLocFiles(options, loader, loaderOptions); - - WebpackConfigurationUpdater._tryUpdateLocaleTokenInPublicPathPlugin(options); - } - - public static amendWebpackConfigurationForInPlaceLocFiles(options: IWebpackConfigurationUpdaterOptions): void { - const loader: string = path.resolve(__dirname, 'loaders', 'InPlaceLocFileLoader.js'); - const loaderOptions: IBaseLoaderOptions = {} - - WebpackConfigurationUpdater._addRulesToConfiguration( - options.configuration, - [ - { - test: Constants.LOC_JSON_REGEX, - use: [{ - loader: loader, - options: loaderOptions - }] - }, - { - test: Constants.RESX_REGEX, - use: [{ - loader: loader, - options: loaderOptions - }], - type: 'json' - } - ] - ); - } - - private static _tryUpdateLocaleTokenInPublicPathPlugin(options: IWebpackConfigurationUpdaterOptions): void { - let setPublicPathPlugin: typeof SetPublicPathPluginPackageType.SetPublicPathPlugin | undefined; - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const pluginPackage: typeof SetPublicPathPluginPackageType = require('@rushstack/set-webpack-public-path-plugin'); - setPublicPathPlugin = pluginPackage.SetPublicPathPlugin; - } catch (e) { - // public path plugin isn't present - ignore - } - - if (setPublicPathPlugin && options.configuration.plugins) { - for (const plugin of options.configuration.plugins) { - if (plugin instanceof setPublicPathPlugin) { - if ( - plugin.options && - plugin.options.scriptName && - plugin.options.scriptName.isTokenized && - plugin.options.scriptName.name - ) { - plugin.options.scriptName.name = plugin.options.scriptName.name.replace( - /\[locale\]/g, - options.localeNameOrPlaceholder - ); - } - } - } - } - } - - private static _addLoadersForLocFiles( - options: IWebpackConfigurationUpdaterOptions, - loader: string, - loaderOptions: IBaseLoaderOptions - ): void { - WebpackConfigurationUpdater._addRulesToConfiguration( - options.configuration, - [ - { - test: { - and: [ - (filePath: string) => !options.filesToIgnore.has(filePath), - Constants.LOC_JSON_REGEX - ] - }, - use: [{ - loader: loader, - options: loaderOptions - }] - }, - { - test: { - and: [ - (filePath: string) => !options.filesToIgnore.has(filePath), - Constants.RESX_REGEX - ] - }, - use: [{ - loader: loader, - options: loaderOptions - }], - type: 'json' - } - ] - ); - } - - private static _addRulesToConfiguration(configuration: Webpack.Configuration, rules: Webpack.RuleSetRule[]): void { - if (!configuration.module) { - configuration.module = { - rules: [] - }; - } - - if (!configuration.module.rules) { - configuration.module.rules = []; - } - - configuration.module.rules.push(...rules); - } -} diff --git a/webpack/localization-plugin/src/index.ts b/webpack/localization-plugin/src/index.ts deleted file mode 100644 index 466fcb315d6..00000000000 --- a/webpack/localization-plugin/src/index.ts +++ /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. - -export { - LocalizationPlugin, - IStringPlaceholder as _IStringPlaceholder -} from './LocalizationPlugin'; - -export { - IDefaultLocaleOptions, - ILocaleData, - ILocaleElementMap, - ILocaleFileData, - ILocalizationFile as _ILocFile, - ILocalizationPluginOptions, - ILocalizationStats, - ILocalizationStatsChunkGroup, - ILocalizationStatsEntrypoint, - ILocalizationStatsOptions, - ILocalizedData, - ILocalizedString as _ILocalizedString, - ILocalizedStrings, - IPassthroughLocaleOptions, - IPseudolocaleOptions, - IPseudolocalesOptions, - ITypingsGenerationOptions -} from './interfaces'; - -export { - LocFileParser as _LocFileParser, - IParseLocFileOptions as _IParseLocFileOptions -} from './utilities/LocFileParser'; - -export { - ILoggerOptions as _ILoggerOptions -} from './utilities/Logging'; - -export { - ILocalizedWebpackChunk -} from './webpackInterfaces'; - -export { - ITypingsGeneratorOptions, - LocFileTypingsGenerator as TypingsGenerator -} from './LocFileTypingsGenerator'; diff --git a/webpack/localization-plugin/src/interfaces.ts b/webpack/localization-plugin/src/interfaces.ts deleted file mode 100644 index 87af52e4c14..00000000000 --- a/webpack/localization-plugin/src/interfaces.ts +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Options for the passthrough locale. - * - * @public - */ -export interface IPassthroughLocaleOptions { - /** - * If this is set to `true`, a passthrough locale will be included in the output - */ - usePassthroughLocale?: boolean; - - /** - * If {@link IPassthroughLocaleOptions.usePassthroughLocale} is set, use this name for the passthrough locale. - * Defaults to "passthrough" - */ - passthroughLocaleName?: string; -} - -/** - * Options for typing generation. - * - * @public - */ -export interface ITypingsGenerationOptions { - /** - * This property specifies the folder in which `.d.ts` files for loc files should be dropped. - */ - generatedTsFolder: string; - - /** - * This optional property overrides the compiler context for discovery of localization files - * for which typings should be generated. - */ - sourceRoot?: string; - - /** - * If this option is set to `true`, loc modules typings will be exported wrapped in a `default` property. - */ - exportAsDefault?: boolean; -} - -/** - * @public - */ -export interface IDefaultLocaleOptions { - /** - * This required property specifies the name of the locale used in the - * `.resx` and `.loc.json` files in the source - */ - localeName: string; - - /** - * If this option is set to `true`, strings that are missing from - * `localizedData.translatedStrings` will be provided by the default locale - */ - fillMissingTranslationStrings?: boolean; -} - -/** - * Options for the pseudolocale library. - * - * @internalRemarks - * Eventually this should be replaced with DefinitelyTyped types. - * - * @public - */ -export interface IPseudolocaleOptions { - prepend?: string; - append?: string; - delimiter?: string; - startDelimiter?: string; - endDelimiter?: string; - extend?: number; - override?: string; -} - -/** - * Options for generated pseudolocales. - * - * @public - */ -export interface IPseudolocalesOptions { - [pseudoLocaleName: string]: IPseudolocaleOptions; -} - -/** - * @public - */ -export interface ILocalizedData { - /** - * Options for the locale used in the source localized data files. - */ - defaultLocale: IDefaultLocaleOptions; - - /** - * Use this parameter to specify the translated data. - */ - translatedStrings: ILocalizedStrings; - - /** - * Options around including a passthrough locale. - */ - passthroughLocale?: IPassthroughLocaleOptions; - - /** - * Options for pseudo-localization. - */ - pseudolocales?: IPseudolocalesOptions; -} - -/** - * Options for how localization stats data should be produced. - * - * @public - */ -export interface ILocalizationStatsOptions { - /** - * This option is used to designate a path at which a JSON file describing the localized - * assets produced should be written. - */ - dropPath?: string; - - /** - * This option is used to specify a callback to be called with the stats data that would be - * dropped at `localizationStats.dropPath` after compilation completes. - */ - callback?: (stats: ILocalizationStats) => void; -} - -/** - * The options for localization. - * - * @public - */ -export interface ILocalizationPluginOptions { - /** - * Localization data. - */ - localizedData: ILocalizedData; - - /** - * This option is used to specify `.resx` and `.loc.json` files that should not be processed by this plugin. - */ - filesToIgnore?: string[]; - - /** - * The value to replace the [locale] token with for chunks without localized strings. Defaults to "none" - */ - noStringsLocaleName?: string; - - /** - * Options for how localization stats data should be produced. - */ - localizationStats?: ILocalizationStatsOptions; - - /** - * This option is used to specify how and if TypeScript typings should be generated for loc files. - */ - typingsOptions?: ITypingsGenerationOptions; -} - -/** - * @internal - */ -export interface ILocalizationFile { - [stringName: string]: ILocalizedString; -} - -/** - * @internal - */ -export interface ILocalizedString { - value: string; - comment?: string; -} - -/** - * @public - */ -export interface ILocaleFileData { - [stringName: string]: string; -} - -/** - * @public - */ -export interface ILocaleData { - [locFilePath: string]: ILocaleFileData; -} - -/** - * @public - */ -export interface ILocalizedStrings { - [locale: string]: ILocaleData; -} - -/** - * @public - */ -export interface ILocaleElementMap { - [locale: string]: string -} - -/** - * @public - */ -export interface ILocalizationStatsEntrypoint { - localizedAssets: ILocaleElementMap; -} - -/** - * @public - */ -export interface ILocalizationStatsChunkGroup { - localizedAssets: ILocaleElementMap; -} - -/** - * @public - */ -export interface ILocalizationStats { - entrypoints: { [name: string]: ILocalizationStatsEntrypoint }; - namedChunkGroups: { [name: string]: ILocalizationStatsChunkGroup }; -} diff --git a/webpack/localization-plugin/src/loaders/InPlaceLocFileLoader.ts b/webpack/localization-plugin/src/loaders/InPlaceLocFileLoader.ts deleted file mode 100644 index 995f2397dea..00000000000 --- a/webpack/localization-plugin/src/loaders/InPlaceLocFileLoader.ts +++ /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. - -import { loader } from 'webpack'; - -import { ILocalizationFile } from '../interfaces'; -import { LocFileParser } from '../utilities/LocFileParser'; -import { loaderFactory } from './LoaderFactory'; - -export default loaderFactory(function (this: loader.LoaderContext, locFilePath: string, content: string) { - const locFileData: ILocalizationFile = LocFileParser.parseLocFileFromLoader(content, this); - const resultObject: { [stringName: string]: string } = {}; - for (const stringName in locFileData) { // eslint-disable-line guard-for-in - resultObject[stringName] = locFileData[stringName].value; - } - - return resultObject; -}); diff --git a/webpack/localization-plugin/src/loaders/LoaderFactory.ts b/webpack/localization-plugin/src/loaders/LoaderFactory.ts deleted file mode 100644 index 16c3eb79a83..00000000000 --- a/webpack/localization-plugin/src/loaders/LoaderFactory.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { loader } from 'webpack'; -import * as loaderUtils from 'loader-utils'; - -export interface IBaseLoaderOptions { } - -export interface ILoaderResult { - [stringName: string]: string -} - -export function loaderFactory( - innerLoader: (locFilePath: string, content: string, options: TOptions) => ILoaderResult -): loader.Loader { - return function (this: loader.LoaderContext, content: string): string { - const options: TOptions = loaderUtils.getOptions(this) as TOptions; - const resultObject: ILoaderResult = innerLoader.call(this, this.resourcePath, content, options); - return JSON.stringify(resultObject); - } -} \ No newline at end of file diff --git a/webpack/localization-plugin/src/loaders/LocLoader.ts b/webpack/localization-plugin/src/loaders/LocLoader.ts deleted file mode 100644 index b94996221d4..00000000000 --- a/webpack/localization-plugin/src/loaders/LocLoader.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { loader } from 'webpack'; - -import { LocalizationPlugin } from '../LocalizationPlugin'; -import { ILocalizationFile } from '../interfaces'; -import { LocFileParser } from '../utilities/LocFileParser'; -import { - loaderFactory, - IBaseLoaderOptions -} from './LoaderFactory'; -import { EntityMarker } from '../utilities/EntityMarker'; - -export interface ILocLoaderOptions extends IBaseLoaderOptions { - pluginInstance: LocalizationPlugin; -} - -export default loaderFactory( - function ( - this: loader.LoaderContext, - locFilePath: string, - content: string, - options: ILocLoaderOptions - ) { - const { pluginInstance } = options; - const locFileData: ILocalizationFile = LocFileParser.parseLocFileFromLoader(content, this); - pluginInstance.addDefaultLocFile(locFilePath, locFileData); - - const resultObject: { [stringName: string]: string } = {}; - for (const stringName in locFileData) { // eslint-disable-line guard-for-in - const stringKey: string = `${locFilePath}?${stringName}`; - if (pluginInstance.stringKeys.has(stringKey)) { - resultObject[stringName] = pluginInstance.stringKeys.get(stringKey)!.value; - } else { - throw new Error(`Unexpected - missing placeholder for string key "${stringKey}"`); - } - } - - EntityMarker.markEntity(this._module, true); - - return resultObject; - } -); diff --git a/webpack/localization-plugin/src/schemas/locJson.schema.json b/webpack/localization-plugin/src/schemas/locJson.schema.json deleted file mode 100644 index a322cc77b09..00000000000 --- a/webpack/localization-plugin/src/schemas/locJson.schema.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Localizable JSON file", - - "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" - } - }, - "patternProperties": { - "^[A-Za-z_][0-9A-Za-z_]*$": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "comment": { - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "value" ] - } - }, - "additionalProperties": false, - "type": "object" -} diff --git a/webpack/localization-plugin/src/utilities/Constants.ts b/webpack/localization-plugin/src/utilities/Constants.ts deleted file mode 100644 index ebebc18737f..00000000000 --- a/webpack/localization-plugin/src/utilities/Constants.ts +++ /dev/null @@ -1,30 +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 { JsonSchema } from "@rushstack/node-core-library"; -import * as lodash from 'lodash'; - -export class Constants { - public static LOC_JSON_SCHEMA: JsonSchema = JsonSchema.fromFile( - path.resolve(__dirname, '..', 'schemas', 'locJson.schema.json') - ); - - public static LOCALE_FILENAME_PLACEHOLDER: string = '[locale]'; - public static LOCALE_FILENAME_PLACEHOLDER_REGEX: RegExp = new RegExp( - lodash.escapeRegExp(Constants.LOCALE_FILENAME_PLACEHOLDER), - 'gi' - ); - public static STRING_PLACEHOLDER_PREFIX: string = '_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9'; - - public static RESX_REGEX: RegExp = /\.resx$/i; - public static LOC_JSON_REGEX: RegExp = /\.loc\.json$/i; - public static RESX_OR_LOC_JSON_REGEX: RegExp = /\.(resx|loc\.json)$/i; - - public static STRING_PLACEHOLDER_LABEL: string = 'A'; - public static LOCALE_NAME_PLACEHOLDER_LABEL: string = 'B'; - public static JSONP_PLACEHOLDER_LABEL: string = 'C'; - - public static LOCALE_NAME_PLACEHOLDER: string = `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.LOCALE_NAME_PLACEHOLDER_LABEL}_0`; - public static JSONP_PLACEHOLDER: string = `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.JSONP_PLACEHOLDER_LABEL}+chunkId+_0`; -} diff --git a/webpack/localization-plugin/src/utilities/EntityMarker.ts b/webpack/localization-plugin/src/utilities/EntityMarker.ts deleted file mode 100644 index f5323c2d6ea..00000000000 --- a/webpack/localization-plugin/src/utilities/EntityMarker.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -const LABEL: unique symbol = Symbol('loc-plugin-marked'); - -/** - * Use the functions on this class to mark webpack entities that contain localized resources. - */ -export class EntityMarker { - public static markEntity(module: TModule, value: boolean): void { - module[LABEL] = value; - } - - public static getMark(module: TModule): boolean { - return !!module[LABEL]; - } -} diff --git a/webpack/localization-plugin/src/utilities/LocFileParser.ts b/webpack/localization-plugin/src/utilities/LocFileParser.ts deleted file mode 100644 index b4c7866c388..00000000000 --- a/webpack/localization-plugin/src/utilities/LocFileParser.ts +++ /dev/null @@ -1,72 +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 jju from 'jju'; -import { loader } from 'webpack'; - -import { - Logging, - ILoggerOptions -} from './Logging'; -import { ILocalizationFile } from '../interfaces'; -import { ResxReader } from './ResxReader'; -import { Constants } from './Constants'; - -/** - * @internal - */ -export interface IParseLocFileOptions { - loggerOptions: ILoggerOptions; - filePath: string; - content: string; -} - -interface IParseCacheEntry { - content: string; - parsedFile: ILocalizationFile; -} - -const parseCache: Map = new Map(); - -/** - * @internal - */ -export class LocFileParser { - public static parseLocFileFromLoader(content: string, loaderContext: loader.LoaderContext): ILocalizationFile { - return LocFileParser.parseLocFile({ - filePath: loaderContext.resourcePath, - loggerOptions: { writeError: loaderContext.emitError, writeWarning: loaderContext.emitWarning }, - content - }); - } - - public static parseLocFile(options: IParseLocFileOptions): ILocalizationFile { - if (parseCache.has(options.filePath)) { - const entry: IParseCacheEntry = parseCache.get(options.filePath)!; - if (entry.content === options.content) { - return entry.parsedFile; - } - } - - let parsedFile: ILocalizationFile; - if (/\.resx$/i.test(options.filePath)) { - parsedFile = ResxReader.readResxAsLocFile( - options.content, - { - ...Logging.getLoggingFunctions(options.loggerOptions), - resxFilePath: options.filePath - } - ); - } else { - parsedFile = jju.parse(options.content); - try { - Constants.LOC_JSON_SCHEMA.validateObject(parsedFile, options.filePath); - } catch (e) { - options.loggerOptions.writeError(`The loc file is invalid. Error: ${e}`); - } - } - - parseCache.set(options.filePath, { content: options.content, parsedFile }); - return parsedFile; - } -} diff --git a/webpack/localization-plugin/src/utilities/Logging.ts b/webpack/localization-plugin/src/utilities/Logging.ts deleted file mode 100644 index 22f59121087..00000000000 --- a/webpack/localization-plugin/src/utilities/Logging.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export interface ILoggingFunctions { - logError: (message: string) => void; - logWarning: (message: string) => void; - logFileError: (message: string, filePath: string, line?: number, position?: number) => void; - logFileWarning: (message: string, filePath: string, line?: number, position?: number) => void; -} - -/** - * @internal - */ -export interface ILoggerOptions { - writeError: (message: string) => void; - writeWarning: (message: string) => void; -} - -export class Logging { - public static getLoggingFunctions(options: ILoggerOptions): ILoggingFunctions { - return { - logError: (message: string) => options.writeError(message), - logWarning: (message: string) => options.writeWarning(message), - logFileError: (message: string, filePath: string, line?: number, position?: number) => { - Logging.logWithLocation( - options.writeError, - message, - filePath, - line, - position - ); - }, - logFileWarning: (message: string, filePath: string, line?: number, position?: number) => { - Logging.logWithLocation( - options.writeWarning, - message, - filePath, - line, - position - ); - } - }; - } - - public static logWithLocation( - loggingFn: (message: string) => void, - message: string, - filePath: string, - line?: number, - position?: number - ): void { - let location: string; - if (position !== undefined) { - location = `${filePath}(${line},${position})`; - } else if (line !== undefined) { - location = `${filePath}(${line})`; - } else { - location = filePath; - } - - loggingFn(`${location}: ${message}`); - } - -} \ No newline at end of file diff --git a/webpack/localization-plugin/src/utilities/ResxReader.ts b/webpack/localization-plugin/src/utilities/ResxReader.ts deleted file mode 100644 index 9268a0a6e8a..00000000000 --- a/webpack/localization-plugin/src/utilities/ResxReader.ts +++ /dev/null @@ -1,270 +0,0 @@ -// 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 { - XmlDocument, - XmlElement -} from 'xmldoc'; -import { - ILocalizedString, - ILocalizationFile -} from '../interfaces'; -import { ILoggingFunctions } from './Logging'; - -const STRING_NAME_RESX: RegExp = /^[A-z_][A-z0-9_]*$/; - -export interface IResxReaderOptions extends ILoggingFunctions { - resxFilePath: string; -} - -export class ResxReader { - public static readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile { - const resxContents: string = FileSystem.readFile(options.resxFilePath); - return ResxReader.readResxAsLocFile(resxContents, options); - } - - public static readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile { - const xmlDocument: XmlDocument = new XmlDocument(resxContents); - - if (xmlDocument.name !== 'root') { - ResxReader._logErrorWithLocation( - options, - `Expected RESX to have a "root" element, found "${xmlDocument.name}"`, - xmlDocument - ); - } - - const locFile: ILocalizationFile = {}; - - for (const childNode of xmlDocument.children) { - switch (childNode.type) { - case 'element': { - switch (childNode.name) { - case 'data': { - const stringName: string = childNode.attr.name; - if (!stringName) { - ResxReader._logErrorWithLocation( - options, - 'Unexpected missing or empty string name', - childNode - ); - } else if (!STRING_NAME_RESX.test(stringName)) { - ResxReader._logErrorWithLocation( - options, - `Invalid string name "${stringName}"`, - childNode - ); - } else { - const locString: ILocalizedString | undefined = ResxReader._readDataElement(options, childNode); - - if (locString) { - locFile[stringName] = locString; - } - } - - break; - } - - // Other allowed elements - case 'xsd:schema': - case 'resheader': - break; - - default: - ResxReader._logErrorWithLocation( - options, - `Unexpected RESX element ${childNode.name}`, - childNode - ); - } - - break; - } - - case 'text': { - if (childNode.text.trim() !== '') { - ResxReader._logErrorWithLocation(options, 'Found unexpected non-empty text node in RESX'); - } - - break; - } - - case 'comment': - break; - - default: - ResxReader._logErrorWithLocation(options, `Unexpected ${childNode.type} child in RESX`); - break; - } - } - - return locFile; - } - - private static _readDataElement(options: IResxReaderOptions, dataElement: XmlElement): ILocalizedString | undefined { - let foundCommentElement: boolean = false; - let foundValueElement: boolean = false; - let comment: string | undefined = undefined; - let value: string | undefined = undefined; - - for (const childNode of dataElement.children) { - switch (childNode.type) { - case 'element': { - switch (childNode.name) { - case 'value': { - if (foundValueElement) { - ResxReader._logErrorWithLocation( - options, - 'Duplicate element found', - childNode - ); - } else { - foundValueElement = true; - value = ResxReader._readTextElement(options, childNode); - } - - break; - } - - case 'comment': { - if (foundCommentElement) { - ResxReader._logErrorWithLocation( - options, - 'Duplicate element found', - childNode - ); - } else { - foundCommentElement = true; - comment = ResxReader._readTextElement(options, childNode); - } - - break; - } - - default: - ResxReader._logErrorWithLocation( - options, - `Unexpected RESX element ${childNode.name}`, - childNode - ); - break; - } - - break; - } - - case 'text': { - if (childNode.text.trim() !== '') { - ResxReader._logErrorWithLocation( - options, - 'Found unexpected non-empty text node in RESX element', - dataElement - ); - } - - break; - } - - case 'comment': - break; - - default: - ResxReader._logErrorWithLocation( - options, - `Unexpected ${childNode.type} child in RESX element`, - dataElement - ); - } - } - - if (value === undefined) { - ResxReader._logErrorWithLocation( - options, - 'Missing string value in element', - dataElement - ); - } else { - if (comment === undefined) { - ResxReader._logWarningWithLocation( - options, - 'Missing string comment in element', - dataElement - ); - } - - return { - value, - comment - }; - } - } - - private static _readTextElement(options: IResxReaderOptions, element: XmlElement): string | undefined { - let foundText: string | undefined = undefined; - - for (const childNode of element.children) { - switch (childNode.type) { - case 'cdata': - case 'text': { - if (foundText !== undefined) { - ResxReader._logErrorWithLocation( - options, - 'More than one child node found containing text content', - element - ); - break; - } - - foundText = childNode.type === 'text' ? childNode.text.trim() : childNode.cdata; - break; - } - - case 'comment': - break; - - case 'element': - ResxReader._logErrorWithLocation( - options, - `Unexpected element`, - childNode - ); - break; - - default: - ResxReader._logErrorWithLocation( - options, - `Unexpected ${element.type} child`, - element - ); - break; - } - } - - return foundText; - } - - private static _logErrorWithLocation( - options: IResxReaderOptions, - message: string, - element?: XmlElement | XmlDocument - ): void { - if (element) { - options.logFileError(message, options.resxFilePath, element.line, element.position); - } else { - options.logFileError(message, options.resxFilePath); - } - } - - private static _logWarningWithLocation( - options: IResxReaderOptions, - message: string, - element?: XmlElement | XmlDocument - ): void { - if (element) { - options.logFileWarning(message, options.resxFilePath, element.line, element.position); - } else { - options.logFileWarning(message, options.resxFilePath); - } - } -} \ No newline at end of file diff --git a/webpack/localization-plugin/src/webpackInterfaces.ts b/webpack/localization-plugin/src/webpackInterfaces.ts deleted file mode 100644 index 8319ec4fe7f..00000000000 --- a/webpack/localization-plugin/src/webpackInterfaces.ts +++ /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 webpack from 'webpack'; - -/** - * @public - */ -export interface ILocalizedWebpackChunk extends webpack.compilation.Chunk { - localizedFiles?: { [locale: string]: string }; -} diff --git a/webpack/localization-plugin/tsconfig.json b/webpack/localization-plugin/tsconfig.json deleted file mode 100644 index b1abb9e5b4a..00000000000 --- a/webpack/localization-plugin/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" -} diff --git a/webpack/preserve-dynamic-require-plugin/.npmignore b/webpack/preserve-dynamic-require-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/preserve-dynamic-require-plugin/CHANGELOG.json b/webpack/preserve-dynamic-require-plugin/CHANGELOG.json new file mode 100644 index 00000000000..ed8d614c0ef --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/CHANGELOG.json @@ -0,0 +1,2885 @@ +{ + "name": "@rushstack/webpack-preserve-dynamic-require-plugin", + "entries": [ + { + "version": "0.11.118", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.118", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.11.117", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.117", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.11.116", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.116", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.11.115", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.115", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.11.114", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.114", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.11.113", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.113", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.11.112", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.112", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.11.111", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.111", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.11.110", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.110", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.11.109", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.109", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.11.108", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.108", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.11.107", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.107", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.11.106", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.106", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.11.105", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.105", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.11.104", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.104", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.11.103", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.103", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.11.102", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.102", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.11.101", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.101", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.11.100", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.100", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.11.99", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.99", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.11.98", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.98", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.11.97", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.97", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.11.96", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.96", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.11.95", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.95", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.11.94", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.94", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.11.93", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.93", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.11.92", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.92", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.11.91", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.91", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.11.90", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.90", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.11.89", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.89", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.11.88", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.11.87", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.11.86", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.86", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.11.85", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.11.84", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.11.83", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.83", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.11.82", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.11.81", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.81", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.11.80", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.80", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.11.79", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.11.78", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.78", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.11.77", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.11.76", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.76", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.11.75", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.11.74", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.11.73", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.73", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.11.72", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.11.71", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.11.70", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.70", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.11.69", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.11.68", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.11.67", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.11.66", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.66", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.11.65", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.11.64", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.11.63", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.11.62", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.11.61", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.11.60", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.60", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.11.59", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.59", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.11.58", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.11.57", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.11.56", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.11.55", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.11.54", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.11.53", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.53", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.11.52", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.11.51", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.11.50", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.11.49", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.49", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.11.48", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.11.47", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.11.46", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.11.45", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.11.44", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.11.43", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.11.42", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.11.41", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.41", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.11.40", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.11.39", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.11.38", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.38", + "date": "Fri, 15 Mar 2024 00:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.11.37", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.11.36", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.11.35", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.11.34", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.34", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.11.33", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.11.32", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.32", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.11.31", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.11.30", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.11.29", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.11.28", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.11.27", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.11.26", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.11.25", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.11.24", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.11.23", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.23", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.11.22", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.22", + "date": "Wed, 07 Feb 2024 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.11.21", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.11.20", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.11.19", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.11.18", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.11.17", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.11.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.10.40", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.40", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.10.39", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.39", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.10.38", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.38", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.10.37", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.37", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.10.36", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.36", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.10.35", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.35", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.10.34", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.34", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.10.33", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.33", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.10.32", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.32", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.10.31", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.31", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.10.30", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.30", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.10.29", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.29", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.10.28", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.28", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.10.27", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.27", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.10.26", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.26", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.10.25", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.25", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.10.24", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.24", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.10.23", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.23", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.10.22", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.22", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.21", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.20", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.19", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.18", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.17", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.16", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.15", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.14", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.13", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.12", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.11", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.10", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.9", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.8", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.7", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.6", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.5", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.4", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.3", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.2", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.1", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.10.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.9.52", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.52", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.9.51", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.51", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.9.50", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.50", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.9.49", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.49", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.9.48", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.48", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.9.47", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.47", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.9.46", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.46", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.9.45", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.45", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.9.44", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.44", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.9.43", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.43", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.9.42", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.42", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.9.41", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.41", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.9.40", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.40", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.9.39", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.39", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.9.38", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.38", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.9.37", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.37", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.9.36", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.36", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.9.35", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.35", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.9.34", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.34", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.9.33", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.33", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.9.32", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.32", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.9.31", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.31", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.9.30", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.30", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.9.29", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.29", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.9.28", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.28", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.9.27", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.27", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.9.26", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.26", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.9.25", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.25", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.9.24", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.24", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.9.23", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.23", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.22", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.21", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.20", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.19", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.18", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.17", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.16", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.15", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.14", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.13", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.12", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.11", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.10", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.9", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.8", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.7", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.6", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.5", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.4", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.3", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.2", + "date": "Tue, 10 May 2022 01:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.1", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/webpack-preserve-dynamic-require-plugin_v0.9.0", + "date": "Thu, 28 Apr 2022 00:11:25 GMT", + "comments": { + "minor": [ + { + "comment": "Define a plugin for preserving dynamic usage of \"require\" in webpack projects that target NodeJS." + } + ] + } + } + ] +} diff --git a/webpack/preserve-dynamic-require-plugin/CHANGELOG.md b/webpack/preserve-dynamic-require-plugin/CHANGELOG.md new file mode 100644 index 00000000000..8f68bce00e9 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/CHANGELOG.md @@ -0,0 +1,1091 @@ +# Change Log - @rushstack/webpack-preserve-dynamic-require-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.11.118 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.11.117 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.11.116 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.11.115 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.11.114 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.11.113 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.11.112 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.11.111 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 0.11.110 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.11.109 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.11.108 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.11.107 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.11.106 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.11.105 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.11.104 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.11.103 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.11.102 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.11.101 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.11.100 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.11.99 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.11.98 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.11.97 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.11.96 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.11.95 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.11.94 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.11.93 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.11.92 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.11.91 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.11.90 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.11.89 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.11.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.11.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.11.86 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.11.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.11.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.11.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.11.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.11.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.11.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.11.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.11.78 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.11.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.11.76 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.11.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.11.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.11.73 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.11.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.11.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.11.70 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.11.69 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 0.11.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.11.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.11.66 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.11.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.11.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.11.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.11.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.11.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.11.60 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.11.59 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.11.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.11.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.11.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.11.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.11.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.11.53 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.11.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.11.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.11.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.11.49 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.11.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.11.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.11.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.11.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.11.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.11.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.11.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.11.41 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.11.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.11.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.11.38 +Fri, 15 Mar 2024 00:12:41 GMT + +_Version update only_ + +## 0.11.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.11.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.11.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.11.34 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.11.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.11.32 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 0.11.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.11.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.11.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.11.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.11.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.11.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.11.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.11.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.11.23 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.11.22 +Wed, 07 Feb 2024 01:11:19 GMT + +_Version update only_ + +## 0.11.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.11.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.11.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.11.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.11.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.11.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.11.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.11.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.11.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.11.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.11.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.11.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.11.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.11.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.11.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.11.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.11.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.11.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.11.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.11.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.11.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.11.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.10.40 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.10.39 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.10.38 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.10.37 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.10.36 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.10.35 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.10.34 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.10.33 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.10.32 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.10.31 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.10.30 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.10.29 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.10.28 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.10.27 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.10.26 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.10.25 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.10.24 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.10.23 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.10.22 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.10.21 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.10.20 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.10.19 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.10.18 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.10.17 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.10.16 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.10.15 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.10.14 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.10.13 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.10.12 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.10.11 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.10.10 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.10.9 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.10.8 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.10.7 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.10.6 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.10.5 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.10.4 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.10.3 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.10.2 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.10.1 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.10.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.9.52 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.9.51 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.9.50 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.9.49 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.9.48 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.9.47 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.9.46 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 0.9.45 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.9.44 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.9.43 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.9.42 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.9.41 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.9.40 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.9.39 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.9.38 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.9.37 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.9.36 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.9.35 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.9.34 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.9.33 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.9.32 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.9.31 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.9.30 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.9.29 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.9.28 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.9.27 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.9.26 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.9.25 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.9.24 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.9.23 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.9.22 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.9.21 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 0.9.20 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.9.19 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.9.18 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.9.17 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.9.16 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.9.15 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.9.14 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.9.13 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.9.12 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.9.11 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.9.10 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.9.9 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.9.8 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.9.7 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.9.6 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.9.5 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 0.9.4 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 0.9.3 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.9.2 +Tue, 10 May 2022 01:20:44 GMT + +_Version update only_ + +## 0.9.1 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.9.0 +Thu, 28 Apr 2022 00:11:25 GMT + +### Minor changes + +- Define a plugin for preserving dynamic usage of "require" in webpack projects that target NodeJS. + diff --git a/webpack/preserve-dynamic-require-plugin/README.md b/webpack/preserve-dynamic-require-plugin/README.md new file mode 100644 index 00000000000..39783d5cbf6 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/README.md @@ -0,0 +1,11 @@ +# @rushstack/webpack-preserve-dynamic-require-plugin + +## Overview + +This Webpack plugin instructs webpack to leave dynamic usage of `require` as-is in the bundled code. For example, if your code contains: +```js +function requireSomeUserThing(path) { + return require(path); +} +``` +The emitted bundle will preserve the call to `require(path)` instead of trying to process it. diff --git a/webpack/preserve-dynamic-require-plugin/config/api-extractor.json b/webpack/preserve-dynamic-require-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/preserve-dynamic-require-plugin/config/jest.config.json b/webpack/preserve-dynamic-require-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/preserve-dynamic-require-plugin/config/rig.json b/webpack/preserve-dynamic-require-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/preserve-dynamic-require-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/webpack/preserve-dynamic-require-plugin/eslint.config.js b/webpack/preserve-dynamic-require-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/preserve-dynamic-require-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/webpack/preserve-dynamic-require-plugin/package.json b/webpack/preserve-dynamic-require-plugin/package.json new file mode 100644 index 00000000000..3e74c018f9a --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/package.json @@ -0,0 +1,28 @@ +{ + "name": "@rushstack/webpack-preserve-dynamic-require-plugin", + "version": "0.11.118", + "description": "This plugin tells webpack to leave dynamic calls to \"require\" as-is instead of trying to bundle them.", + "main": "lib/index.js", + "typings": "dist/webpack-preserve-dynamic-require-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/preserve-dynamic-require-plugin" + }, + "engines": { + "node": ">=10.17.1" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.98.0" + }, + "sideEffects": false +} diff --git a/webpack/preserve-dynamic-require-plugin/src/__snapshots__/index.test.ts.snap b/webpack/preserve-dynamic-require-plugin/src/__snapshots__/index.test.ts.snap new file mode 100644 index 00000000000..791cddaa7e4 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/src/__snapshots__/index.test.ts.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PreserveDynamicRequireWebpackPlugin Preserves dynamic require usage 1`] = ` +Map { + "/release/main.js" => "/******/ (() => { // webpackBootstrap +require(process.env.SOME_PATH); +/******/ })() +;", +} +`; diff --git a/webpack/preserve-dynamic-require-plugin/src/index.test.ts b/webpack/preserve-dynamic-require-plugin/src/index.test.ts new file mode 100644 index 00000000000..b3ec40a6664 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/src/index.test.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. + +jest.disableAutomock(); +import webpack from 'webpack'; + +import { PreserveDynamicRequireWebpackPlugin } from './index'; + +jest.setTimeout(1e9); + +describe(PreserveDynamicRequireWebpackPlugin.name, () => { + it('Preserves dynamic require usage', async () => { + const sources: Map = new Map(); + sources.set('/package.json', JSON.stringify({})); + sources.set('/file.js', 'require(process.env.SOME_PATH);'); + + const compiler: webpack.Compiler = webpack({ + entry: { + main: '/file.js' + }, + output: { + path: '/release', + filename: '[name].js' + }, + context: '/', + mode: 'none', + plugins: [new PreserveDynamicRequireWebpackPlugin()] + }); + + const inputFs: typeof compiler.inputFileSystem = { + readFile(path: string, cb: (err?: NodeJS.ErrnoException | undefined, content?: string) => void): void { + cb(undefined, sources.get(path)); + }, + readdir(path: string, cb: (err?: NodeJS.ErrnoException | undefined, files?: string[]) => void): void { + cb( + undefined, + Array.from(sources.keys(), (key: string) => key.slice(1)) + ); + }, + readlink(path: string, cb: (err?: NodeJS.ErrnoException | undefined, dest?: string) => void): void { + cb(); + }, + stat(path: string, cb: (err?: NodeJS.ErrnoException, stat?: unknown) => void): void { + if (sources.has(path)) { + return cb(undefined, { + isFile() { + return true; + }, + isDirectory() { + return false; + } + }); + } else if (path === '/') { + return cb(undefined, { + isFile() { + return false; + }, + isDirectory() { + return true; + } + }); + } + cb(new Error(`Unexpected stat call for ${path}`)); + } + } as unknown as typeof compiler.inputFileSystem; + + const results: Map = new Map(); + + const outputFs: typeof compiler.outputFileSystem = { + mkdir(path: string, cb: (err?: NodeJS.ErrnoException) => void): void { + cb(); + }, + stat(path: string, cb: (err?: NodeJS.ErrnoException) => void): void { + const err: NodeJS.ErrnoException = new Error(`No such file`); + err.code = 'ENOENT'; + cb(err); + }, + writeFile(path: string, content: Buffer, cb: (err?: NodeJS.ErrnoException) => void): void { + results.set(path, content.toString('utf8')); + cb(); + } + } as unknown as typeof compiler.outputFileSystem; + + compiler.inputFileSystem = inputFs; + compiler.outputFileSystem = outputFs; + + await new Promise((resolve: () => void, reject: (err: Error) => void) => + compiler.run((err?: Error | null) => { + if (err) { + return reject(err); + } + resolve(); + }) + ); + + expect(results).toMatchSnapshot(); + }); +}); diff --git a/webpack/preserve-dynamic-require-plugin/src/index.ts b/webpack/preserve-dynamic-require-plugin/src/index.ts new file mode 100644 index 00000000000..e723a078313 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/src/index.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 type * as webpack from 'webpack'; + +const PLUGIN_NAME: 'PreserveDynamicRequireWebpackPlugin' = 'PreserveDynamicRequireWebpackPlugin'; + +/** + * @public + */ +export class PreserveDynamicRequireWebpackPlugin { + public apply(compiler: webpack.Compiler): void { + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: webpack.Compilation) => { + function processDependencies( + block: Pick + ): void { + const { dependencies } = block; + for (let i: number = dependencies.length - 1; i >= 0; i--) { + const dep: webpack.Dependency = dependencies[i]; + // Disable processing of dynamic require + if (dep.constructor.name === 'CommonJsRequireContextDependency') { + dependencies.splice(i, 1); + } + } + + for (const child of block.blocks) { + processDependencies(child); + } + } + + compilation.hooks.succeedModule.tap(PLUGIN_NAME, (mod: webpack.Module) => { + processDependencies(mod); + }); + }); + } +} diff --git a/webpack/preserve-dynamic-require-plugin/tsconfig.json b/webpack/preserve-dynamic-require-plugin/tsconfig.json new file mode 100644 index 00000000000..f9ad3bca995 --- /dev/null +++ b/webpack/preserve-dynamic-require-plugin/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019", + "noImplicitAny": false + } +} diff --git a/webpack/set-webpack-public-path-plugin/.eslintrc.js b/webpack/set-webpack-public-path-plugin/.eslintrc.js deleted file mode 100644 index d7953bb2a36..00000000000 --- a/webpack/set-webpack-public-path-plugin/.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-eslint6"); - -module.exports = { - extends: [ "@rushstack/eslint-config" ], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/webpack/set-webpack-public-path-plugin/.npmignore b/webpack/set-webpack-public-path-plugin/.npmignore index e2cbe1efa92..bc349f9a4be 100644 --- a/webpack/set-webpack-public-path-plugin/.npmignore +++ b/webpack/set-webpack-public-path-plugin/.npmignore @@ -1,24 +1,32 @@ -# 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/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/* +/lib/**/test/ +/lib-*/**/test/ +*.test.js # 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 - -## Project specific definitions -# ----------------------------- +# README.md +# LICENSE -# (Add your exceptions here) \ No newline at end of file +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/webpack/set-webpack-public-path-plugin/CHANGELOG.json b/webpack/set-webpack-public-path-plugin/CHANGELOG.json index fc6760b5418..c70a2ce90d8 100644 --- a/webpack/set-webpack-public-path-plugin/CHANGELOG.json +++ b/webpack/set-webpack-public-path-plugin/CHANGELOG.json @@ -1,6 +1,7592 @@ { "name": "@rushstack/set-webpack-public-path-plugin", "entries": [ + { + "version": "5.2.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.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/webpack-plugin-utilities\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "5.2.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.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/webpack-plugin-utilities\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "5.2.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "5.2.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "5.2.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.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/webpack-plugin-utilities\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "5.2.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.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/webpack-plugin-utilities\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "5.2.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.2.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/webpack-plugin-utilities\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "5.2.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.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/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "5.1.94", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.94", + "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/webpack-plugin-utilities\" to `0.4.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "5.1.93", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.93", + "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/webpack-plugin-utilities\" to `0.4.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "5.1.92", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.92", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "5.1.91", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.91", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "5.1.90", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.90", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "5.1.89", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.89", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "5.1.88", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.88", + "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/webpack-plugin-utilities\" to `0.4.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "5.1.87", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.87", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "5.1.86", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.86", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "5.1.85", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.85", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "5.1.84", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.84", + "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/webpack-plugin-utilities\" to `0.4.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "5.1.83", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.83", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "5.1.82", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.82", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "5.1.81", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.81", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "5.1.80", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.80", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "5.1.79", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.79", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "5.1.78", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.78", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "5.1.77", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.77", + "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/webpack-plugin-utilities\" to `0.4.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "5.1.76", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.76", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "5.1.75", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.75", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "5.1.74", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.74", + "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/webpack-plugin-utilities\" to `0.4.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "5.1.73", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.73", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "5.1.72", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.72", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "5.1.71", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.71", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "5.1.70", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.70", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "5.1.69", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.69", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "5.1.68", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.68", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "5.1.67", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.67", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "5.1.66", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.66", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "5.1.65", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.65", + "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/webpack-plugin-utilities\" to `0.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "5.1.64", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.64", + "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/webpack-plugin-utilities\" to `0.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "5.1.63", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.63", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "5.1.62", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.62", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "5.1.61", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.61", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "5.1.60", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.60", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "5.1.59", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.59", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "5.1.58", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.58", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "5.1.57", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.57", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "5.1.56", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.56", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "5.1.55", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.55", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "5.1.54", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.54", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "5.1.53", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.53", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "5.1.52", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.52", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "5.1.51", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.51", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "5.1.50", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.50", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "5.1.49", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.49", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "5.1.48", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.48", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "5.1.47", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.47", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "5.1.46", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.46", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "5.1.45", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.45", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "5.1.44", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.44", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "5.1.43", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.43", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "5.1.42", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.42", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "5.1.41", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.41", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "5.1.40", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.40", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "5.1.39", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.39", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "5.1.38", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.38", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "5.1.37", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.37", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "5.1.36", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.36", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "5.1.35", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.35", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "5.1.34", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.34", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "5.1.33", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.33", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "5.1.32", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.32", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "5.1.31", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.31", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "5.1.30", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.30", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "5.1.29", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.29", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "5.1.28", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.28", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "5.1.27", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.27", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "5.1.26", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.26", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "5.1.25", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.25", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "5.1.24", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.24", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "5.1.23", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.23", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "5.1.22", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.22", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "5.1.21", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.21", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "5.1.20", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.20", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "5.1.19", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.19", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "5.1.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.18", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "5.1.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.17", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "5.1.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.16", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "5.1.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.15", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "5.1.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.14", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "5.1.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.13", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "5.1.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.12", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "5.1.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.11", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "5.1.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.10", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "5.1.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.9", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "5.1.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.8", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "5.1.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.7", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "5.1.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.6", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "5.1.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.5", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "5.1.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "5.1.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.3", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "5.1.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.2", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "5.1.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.1", + "date": "Thu, 18 Jan 2024 05:07:01 GMT", + "comments": { + "patch": [ + { + "comment": "Only emit an error about unsupported library types if the public path is actually used." + } + ] + } + }, + { + "version": "5.1.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.1.0", + "date": "Thu, 18 Jan 2024 03:30:10 GMT", + "comments": { + "minor": [ + { + "comment": "Add a second exported plugin (`SetPublicPathCurrentScriptPlugin`) that creates a wrapper around the runtime chunk and uses the `document.currentScript` API to get the current script's URL." + } + ] + } + }, + { + "version": "5.0.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.0.1", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "5.0.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v5.0.0", + "date": "Fri, 12 Jan 2024 01:23:10 GMT", + "comments": { + "major": [ + { + "comment": "Update the plugin to work with Webpack 5 and drop support for Webpack 4." + }, + { + "comment": "Remove old options, specifically `systemJs`, `urlPrefix`, `publicPath`, and `skipDetection`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.0`" + } + ] + } + }, + { + "version": "4.1.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.16`" + } + ] + } + }, + { + "version": "4.1.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.15`" + } + ] + } + }, + { + "version": "4.1.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.14`" + } + ] + } + }, + { + "version": "4.1.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.13`" + } + ] + } + }, + { + "version": "4.1.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.12`" + } + ] + } + }, + { + "version": "4.1.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.11`" + } + ] + } + }, + { + "version": "4.1.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.10`" + } + ] + } + }, + { + "version": "4.1.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.9`" + } + ] + } + }, + { + "version": "4.1.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.8`" + } + ] + } + }, + { + "version": "4.1.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.7`" + } + ] + } + }, + { + "version": "4.1.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.6`" + } + ] + } + }, + { + "version": "4.1.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.5`" + } + ] + } + }, + { + "version": "4.1.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.4`" + } + ] + } + }, + { + "version": "4.1.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.3`" + } + ] + } + }, + { + "version": "4.1.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.2`" + } + ] + } + }, + { + "version": "4.1.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.1`" + } + ] + } + }, + { + "version": "4.1.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.1.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.9.0`" + } + ] + } + }, + { + "version": "4.0.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.17", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.15`" + } + ] + } + }, + { + "version": "4.0.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.16", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.14`" + } + ] + } + }, + { + "version": "4.0.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.15", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.13`" + } + ] + } + }, + { + "version": "4.0.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.14", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.12`" + } + ] + } + }, + { + "version": "4.0.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.13", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.11`" + } + ] + } + }, + { + "version": "4.0.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.12", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.10`" + } + ] + } + }, + { + "version": "4.0.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.11", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.9`" + } + ] + } + }, + { + "version": "4.0.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.10", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.8`" + } + ] + } + }, + { + "version": "4.0.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.9", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.7`" + } + ] + } + }, + { + "version": "4.0.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.8", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.6`" + } + ] + } + }, + { + "version": "4.0.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.7", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.5`" + } + ] + } + }, + { + "version": "4.0.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.6", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.4`" + } + ] + } + }, + { + "version": "4.0.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.5", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.3`" + } + ] + } + }, + { + "version": "4.0.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.4", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.2`" + } + ] + } + }, + { + "version": "4.0.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.3", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.1`" + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.2", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.8.0`" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.1", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.10`" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v4.0.0", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "major": [ + { + "comment": "Emit an error on Webpack 5 instead of a warning and remove the optional peerDependency on Webpack." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.9`" + } + ] + } + }, + { + "version": "3.3.115", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.115", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.8`" + } + ] + } + }, + { + "version": "3.3.114", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.114", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.7`" + } + ] + } + }, + { + "version": "3.3.113", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.113", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.6`" + } + ] + } + }, + { + "version": "3.3.112", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.112", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.5`" + } + ] + } + }, + { + "version": "3.3.111", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.111", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.4`" + } + ] + } + }, + { + "version": "3.3.110", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.110", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.3`" + } + ] + } + }, + { + "version": "3.3.109", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.109", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.2`" + } + ] + } + }, + { + "version": "3.3.108", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.108", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.1`" + } + ] + } + }, + { + "version": "3.3.107", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.107", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.7.0`" + } + ] + } + }, + { + "version": "3.3.106", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.106", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.12`" + } + ] + } + }, + { + "version": "3.3.105", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.105", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.11`" + } + ] + } + }, + { + "version": "3.3.104", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.104", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.10`" + } + ] + } + }, + { + "version": "3.3.103", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.103", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.9`" + } + ] + } + }, + { + "version": "3.3.102", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.102", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.8`" + } + ] + } + }, + { + "version": "3.3.101", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.101", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.7`" + } + ] + } + }, + { + "version": "3.3.100", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.100", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.6`" + } + ] + } + }, + { + "version": "3.3.99", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.99", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.5`" + } + ] + } + }, + { + "version": "3.3.98", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.98", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.4`" + } + ] + } + }, + { + "version": "3.3.97", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.97", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.3`" + } + ] + } + }, + { + "version": "3.3.96", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.96", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.2`" + } + ] + } + }, + { + "version": "3.3.95", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.95", + "date": "Thu, 23 Mar 2023 15:24:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`" + } + ] + } + }, + { + "version": "3.3.94", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.94", + "date": "Wed, 22 Mar 2023 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`" + } + ] + } + }, + { + "version": "3.3.93", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.93", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.1`" + } + ] + } + }, + { + "version": "3.3.92", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.92", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.6.0`" + } + ] + } + }, + { + "version": "3.3.91", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.91", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.56`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.73`" + } + ] + } + }, + { + "version": "3.3.90", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.90", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.72`" + } + ] + } + }, + { + "version": "3.3.89", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.89", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.71`" + } + ] + } + }, + { + "version": "3.3.88", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.88", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.70`" + } + ] + } + }, + { + "version": "3.3.87", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.87", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.69`" + } + ] + } + }, + { + "version": "3.3.86", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.86", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.68`" + } + ] + } + }, + { + "version": "3.3.85", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.85", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.67`" + } + ] + } + }, + { + "version": "3.3.84", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.84", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.66`" + } + ] + } + }, + { + "version": "3.3.83", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.83", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.65`" + } + ] + } + }, + { + "version": "3.3.82", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.82", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.64`" + } + ] + } + }, + { + "version": "3.3.81", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.81", + "date": "Fri, 02 Dec 2022 01:15:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.63`" + } + ] + } + }, + { + "version": "3.3.80", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.80", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.62`" + } + ] + } + }, + { + "version": "3.3.79", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.79", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.61`" + } + ] + } + }, + { + "version": "3.3.78", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.78", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.60`" + } + ] + } + }, + { + "version": "3.3.77", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.77", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.59`" + } + ] + } + }, + { + "version": "3.3.76", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.76", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.58`" + } + ] + } + }, + { + "version": "3.3.75", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.75", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.57`" + } + ] + } + }, + { + "version": "3.3.74", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.74", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.56`" + } + ] + } + }, + { + "version": "3.3.73", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.73", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.55`" + } + ] + } + }, + { + "version": "3.3.72", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.72", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.54`" + } + ] + } + }, + { + "version": "3.3.71", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.71", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.53`" + } + ] + } + }, + { + "version": "3.3.70", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.70", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.52`" + } + ] + } + }, + { + "version": "3.3.69", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.69", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.51`" + } + ] + } + }, + { + "version": "3.3.68", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.68", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.50`" + } + ] + } + }, + { + "version": "3.3.67", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.67", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.49`" + } + ] + } + }, + { + "version": "3.3.66", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.66", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.48`" + } + ] + } + }, + { + "version": "3.3.65", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.65", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.47`" + } + ] + } + }, + { + "version": "3.3.64", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.64", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.46`" + } + ] + } + }, + { + "version": "3.3.63", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.63", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.45`" + } + ] + } + }, + { + "version": "3.3.62", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.62", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.44`" + } + ] + } + }, + { + "version": "3.3.61", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.61", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.43`" + } + ] + } + }, + { + "version": "3.3.60", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.60", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.42`" + } + ] + } + }, + { + "version": "3.3.59", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.59", + "date": "Fri, 19 Aug 2022 00:17:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.41`" + } + ] + } + }, + { + "version": "3.3.58", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.58", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.40`" + } + ] + } + }, + { + "version": "3.3.57", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.57", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.39`" + } + ] + } + }, + { + "version": "3.3.56", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.56", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.38`" + } + ] + } + }, + { + "version": "3.3.55", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.55", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.37`" + } + ] + } + }, + { + "version": "3.3.54", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.54", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.36`" + } + ] + } + }, + { + "version": "3.3.53", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.53", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.35`" + } + ] + } + }, + { + "version": "3.3.52", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.52", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.34`" + } + ] + } + }, + { + "version": "3.3.51", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.51", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.33`" + } + ] + } + }, + { + "version": "3.3.50", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.50", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.32`" + } + ] + } + }, + { + "version": "3.3.49", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.49", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.31`" + } + ] + } + }, + { + "version": "3.3.48", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.48", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.30`" + } + ] + } + }, + { + "version": "3.3.47", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.47", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.29`" + } + ] + } + }, + { + "version": "3.3.46", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.46", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.28`" + } + ] + } + }, + { + "version": "3.3.45", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.45", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.27`" + } + ] + } + }, + { + "version": "3.3.44", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.44", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.26`" + } + ] + } + }, + { + "version": "3.3.43", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.43", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.25`" + } + ] + } + }, + { + "version": "3.3.42", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.42", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.24`" + } + ] + } + }, + { + "version": "3.3.41", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.41", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.23`" + } + ] + } + }, + { + "version": "3.3.40", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.40", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Bump @types/webpack" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.22`" + } + ] + } + }, + { + "version": "3.3.39", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.39", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.21`" + } + ] + } + }, + { + "version": "3.3.38", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.38", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.20`" + } + ] + } + }, + { + "version": "3.3.37", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.37", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.19`" + } + ] + } + }, + { + "version": "3.3.36", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.36", + "date": "Wed, 18 May 2022 15:10:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.18`" + } + ] + } + }, + { + "version": "3.3.35", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.35", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.17`" + } + ] + } + }, + { + "version": "3.3.34", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.34", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.16`" + } + ] + } + }, + { + "version": "3.3.33", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.33", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.15`" + } + ] + } + }, + { + "version": "3.3.32", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.32", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.14`" + } + ] + } + }, + { + "version": "3.3.31", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.31", + "date": "Wed, 04 May 2022 02:35:33 GMT", + "comments": { + "patch": [ + { + "comment": "Make @rushstack/webpack-plugin-utilities a normal dependency." + } + ] + } + }, + { + "version": "3.3.30", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.30", + "date": "Wed, 27 Apr 2022 01:19:20 GMT", + "comments": { + "patch": [ + { + "comment": "Move webpack version detection logic to the \"@rushstack/webpack-plugin-utilities\" package" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.1.0`" + } + ] + } + }, + { + "version": "3.3.29", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.29", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.13`" + } + ] + } + }, + { + "version": "3.3.28", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.28", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.12`" + } + ] + } + }, + { + "version": "3.3.27", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.27", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.11`" + } + ] + } + }, + { + "version": "3.3.26", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.26", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.10`" + } + ] + } + }, + { + "version": "3.3.25", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.25", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.9`" + } + ] + } + }, + { + "version": "3.3.24", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.24", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.8`" + } + ] + } + }, + { + "version": "3.3.23", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.23", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.7`" + } + ] + } + }, + { + "version": "3.3.22", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.22", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.6`" + } + ] + } + }, + { + "version": "3.3.21", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.21", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.5`" + } + ] + } + }, + { + "version": "3.3.20", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.20", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.4`" + } + ] + } + }, + { + "version": "3.3.19", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.19", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.3`" + } + ] + } + }, + { + "version": "3.3.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.18", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.2`" + } + ] + } + }, + { + "version": "3.3.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.17", + "date": "Tue, 15 Mar 2022 19:15:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.1`" + } + ] + } + }, + { + "version": "3.3.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.16", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.5.0`" + } + ] + } + }, + { + "version": "3.3.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.15", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "3.3.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.14", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "3.3.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.13", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "3.3.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.12", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "3.3.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.11", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "3.3.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.10", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "3.3.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.9", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "3.3.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.8", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "3.3.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.7", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "3.3.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.6", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "3.3.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.5", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "3.3.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.4", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "3.3.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.3", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "3.3.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.2", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.1", + "date": "Thu, 11 Nov 2021 01:17:02 GMT", + "comments": { + "patch": [ + { + "comment": "Update typings to only import from \"webpack.\"" + } + ] + } + }, + { + "version": "3.3.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.3.0", + "date": "Wed, 10 Nov 2021 16:09:47 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a warning when running in Webpack 5." + } + ] + } + }, + { + "version": "3.2.90", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.90", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "3.2.89", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.89", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "3.2.88", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.88", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "3.2.87", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.87", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "3.2.86", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.86", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "3.2.85", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.85", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "3.2.84", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.84", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "3.2.83", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.83", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "3.2.82", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.82", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "3.2.81", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.81", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "3.2.80", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.80", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "3.2.79", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.79", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "3.2.78", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.78", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "3.2.77", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.77", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "3.2.76", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.76", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "3.2.75", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.75", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "3.2.74", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.74", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "3.2.73", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.73", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "3.2.72", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.72", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "3.2.71", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.71", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "3.2.70", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.70", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "3.2.69", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.69", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "3.2.68", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.68", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "3.2.67", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.67", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "3.2.66", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.66", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "3.2.65", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.65", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "3.2.64", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.64", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "3.2.63", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.63", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "3.2.62", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.62", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "3.2.61", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.61", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "3.2.60", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.60", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "3.2.59", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.59", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "3.2.58", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.58", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "3.2.57", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.57", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "3.2.56", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.56", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "3.2.55", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.55", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "3.2.54", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.54", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "3.2.53", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.53", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "3.2.52", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.52", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "3.2.51", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.51", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "3.2.50", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.50", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "3.2.49", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.49", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "3.2.48", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.48", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "3.2.47", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.47", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "3.2.46", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.46", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "3.2.45", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.45", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "3.2.44", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.44", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "3.2.43", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.43", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "3.2.42", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.42", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "3.2.41", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.41", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "3.2.40", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.40", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "3.2.39", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.39", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "3.2.38", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.38", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "3.2.37", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.37", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "3.2.36", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.36", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "3.2.35", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.35", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "3.2.34", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.34", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "3.2.33", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.33", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "3.2.32", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.32", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "3.2.31", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.31", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "3.2.30", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.30", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "3.2.29", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.29", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "3.2.28", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.28", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "3.2.27", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.27", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "3.2.26", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.26", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "3.2.25", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.25", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "3.2.24", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.24", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "3.2.23", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.23", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "3.2.22", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.22", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "3.2.21", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.21", + "date": "Thu, 08 Apr 2021 20:41:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "3.2.20", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.20", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "3.2.19", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.19", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "3.2.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.18", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "3.2.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.17", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "3.2.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.16", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "3.2.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.15", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "3.2.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.14", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "3.2.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.13", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "3.2.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.12", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "3.2.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.11", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "3.2.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.10", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "3.2.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.9", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "3.2.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.8", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "3.2.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.7", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "3.2.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.6", + "date": "Thu, 21 Jan 2021 04:19:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "3.2.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.5", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "3.2.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.4", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "3.2.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.3", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.2", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "3.2.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.1", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "3.2.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.2.0", + "date": "Tue, 08 Dec 2020 01:10:30 GMT", + "comments": { + "minor": [ + { + "comment": "Remove uglify dependency and make suffix script always minified." + } + ] + } + }, + { + "version": "3.1.19", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.19", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "3.1.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.18", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "3.1.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.17", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "3.1.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.16", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "3.1.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.15", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "3.1.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.14", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "3.1.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.13", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "3.1.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.12", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "3.1.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.11", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "3.1.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.10", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "3.1.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.9", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "3.1.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.8", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "3.1.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.7", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "3.1.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.6", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.5", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "3.1.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.4", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "3.1.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.3", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "3.1.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.2", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.1", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.1.0", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to ~4.44.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "3.0.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.18", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "3.0.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.17", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "3.0.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.16", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "3.0.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.15", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "3.0.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.14", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "3.0.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.13", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "3.0.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.12", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "3.0.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.11", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "3.0.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.10", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "3.0.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.9", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "3.0.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.8", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "3.0.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.7", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "3.0.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.6", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "3.0.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.5", + "date": "Mon, 05 Oct 2020 15:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "3.0.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.4", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "3.0.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.3", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "3.0.2", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.2", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "3.0.1", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.1", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@rushstack/set-webpack-public-path-plugin_v3.0.0", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "major": [ + { + "comment": "Drop support for Webpack 3." + } + ], + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "2.4.65", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.65", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "2.4.64", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.64", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "2.4.63", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.63", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "2.4.62", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.62", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "2.4.61", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.61", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "2.4.60", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.60", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "2.4.59", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.59", + "date": "Fri, 18 Sep 2020 21:49:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "2.4.58", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.58", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "2.4.57", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.57", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "2.4.56", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.56", + "date": "Mon, 14 Sep 2020 15:09:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "2.4.55", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.55", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "2.4.54", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.54", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "2.4.53", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.53", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "2.4.52", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.52", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "2.4.51", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.51", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "2.4.50", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.50", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "2.4.49", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.49", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "2.4.48", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.48", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "2.4.47", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.47", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "2.4.46", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.46", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "2.4.45", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.45", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "2.4.44", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.44", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "2.4.43", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.43", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "2.4.42", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.42", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "2.4.41", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.41", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "2.4.40", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.40", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "2.4.39", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.39", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "2.4.38", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.38", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "2.4.37", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.37", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "2.4.36", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.36", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "2.4.35", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.35", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "2.4.34", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.34", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "2.4.33", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.33", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "2.4.32", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.32", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "2.4.31", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.31", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + } + ] + } + }, + { + "version": "2.4.30", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.30", + "date": "Wed, 15 Jul 2020 15:09:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix specification of optional peerDependencies." + } + ] + } + }, + { + "version": "2.4.29", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.29", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + } + ] + } + }, + { + "version": "2.4.28", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.28", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + } + ] + } + }, + { + "version": "2.4.27", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.27", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + } + ] + } + }, + { + "version": "2.4.26", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.26", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + } + ] + } + }, + { + "version": "2.4.25", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.25", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "2.4.24", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.24", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "2.4.23", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.23", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "2.4.22", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.22", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + } + ] + } + }, + { + "version": "2.4.21", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.21", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + } + ] + } + }, + { + "version": "2.4.20", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.20", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + } + ] + } + }, + { + "version": "2.4.19", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.19", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + } + ] + } + }, + { + "version": "2.4.18", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.18", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + } + ] + } + }, + { + "version": "2.4.17", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.17", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + } + ] + } + }, + { + "version": "2.4.16", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.16", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "2.4.15", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.15", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + } + ] + } + }, + { + "version": "2.4.14", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.14", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + } + ] + } + }, + { + "version": "2.4.13", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.13", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + } + ] + } + }, + { + "version": "2.4.12", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.12", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + } + ] + } + }, + { + "version": "2.4.11", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.11", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + } + ] + } + }, + { + "version": "2.4.10", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.10", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + } + ] + } + }, + { + "version": "2.4.9", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.9", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + } + ] + } + }, + { + "version": "2.4.8", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.8", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + } + ] + } + }, + { + "version": "2.4.7", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.7", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "2.4.6", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.6", + "date": "Mon, 06 Apr 2020 05:52:56 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where sourcemaps with inlined sources can contain incorrect escaping." + } + ] + } + }, + { + "version": "2.4.5", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.5", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + } + ] + } + }, + { + "version": "2.4.4", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.4", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + } + ] + } + }, + { + "version": "2.4.3", + "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.3", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, { "version": "2.4.2", "tag": "@rushstack/set-webpack-public-path-plugin_v2.4.2", diff --git a/webpack/set-webpack-public-path-plugin/CHANGELOG.md b/webpack/set-webpack-public-path-plugin/CHANGELOG.md index 9649b314a1b..bda3403a796 100644 --- a/webpack/set-webpack-public-path-plugin/CHANGELOG.md +++ b/webpack/set-webpack-public-path-plugin/CHANGELOG.md @@ -1,11 +1,2311 @@ # Change Log - @rushstack/set-webpack-public-path-plugin -This log was last generated on Wed, 18 Mar 2020 15:07:47 GMT and should not be manually modified. +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 5.2.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 5.2.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 5.2.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 5.2.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 5.2.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 5.2.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 5.2.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 5.2.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 5.1.94 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 5.1.93 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 5.1.92 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 5.1.91 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 5.1.90 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 5.1.89 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 5.1.88 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 5.1.87 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 5.1.86 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 5.1.85 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 5.1.84 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 5.1.83 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 5.1.82 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 5.1.81 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 5.1.80 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 5.1.79 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 5.1.78 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 5.1.77 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 5.1.76 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 5.1.75 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 5.1.74 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 5.1.73 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 5.1.72 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 5.1.71 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 5.1.70 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 5.1.69 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 5.1.68 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 5.1.67 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 5.1.66 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 5.1.65 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 5.1.64 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 5.1.63 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 5.1.62 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 5.1.61 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 5.1.60 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 5.1.59 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 5.1.58 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 5.1.57 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 5.1.56 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 5.1.55 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 5.1.54 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 5.1.53 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 5.1.52 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 5.1.51 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 5.1.50 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 5.1.49 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 5.1.48 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 5.1.47 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 5.1.46 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 5.1.45 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 5.1.44 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 5.1.43 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 5.1.42 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 5.1.41 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 5.1.40 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 5.1.39 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 5.1.38 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 5.1.37 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 5.1.36 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 5.1.35 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 5.1.34 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 5.1.33 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 5.1.32 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 5.1.31 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 5.1.30 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 5.1.29 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 5.1.28 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 5.1.27 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 5.1.26 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 5.1.25 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 5.1.24 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 5.1.23 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 5.1.22 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 5.1.21 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 5.1.20 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 5.1.19 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 5.1.18 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 5.1.17 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 5.1.16 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 5.1.15 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 5.1.14 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 5.1.13 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 5.1.12 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 5.1.11 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 5.1.10 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 5.1.9 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 5.1.8 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 5.1.7 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 5.1.6 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 5.1.5 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 5.1.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 5.1.3 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 5.1.2 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 5.1.1 +Thu, 18 Jan 2024 05:07:01 GMT + +### Patches + +- Only emit an error about unsupported library types if the public path is actually used. + +## 5.1.0 +Thu, 18 Jan 2024 03:30:10 GMT + +### Minor changes + +- Add a second exported plugin (`SetPublicPathCurrentScriptPlugin`) that creates a wrapper around the runtime chunk and uses the `document.currentScript` API to get the current script's URL. + +## 5.0.1 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 5.0.0 +Fri, 12 Jan 2024 01:23:10 GMT + +### Breaking changes + +- Update the plugin to work with Webpack 5 and drop support for Webpack 4. +- Remove old options, specifically `systemJs`, `urlPrefix`, `publicPath`, and `skipDetection`. + +## 4.1.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 4.1.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 4.1.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 4.1.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 4.1.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 4.1.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 4.1.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 4.1.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 4.1.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 4.1.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 4.1.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 4.1.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 4.1.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 4.1.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 4.1.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 4.1.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 4.1.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 4.0.17 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 4.0.16 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 4.0.15 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 4.0.14 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 4.0.13 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 4.0.12 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 4.0.11 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 4.0.10 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 4.0.9 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 4.0.8 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 4.0.7 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 4.0.6 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 4.0.5 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 4.0.4 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 4.0.3 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 4.0.2 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 4.0.1 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 4.0.0 +Tue, 13 Jun 2023 01:49:01 GMT + +### Breaking changes + +- Emit an error on Webpack 5 instead of a warning and remove the optional peerDependency on Webpack. + +## 3.3.115 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 3.3.114 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 3.3.113 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 3.3.112 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 3.3.111 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 3.3.110 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 3.3.109 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 3.3.108 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 3.3.107 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 3.3.106 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 3.3.105 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 3.3.104 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 3.3.103 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 3.3.102 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 3.3.101 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 3.3.100 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 3.3.99 +Thu, 20 Apr 2023 15:16:55 GMT + +_Version update only_ + +## 3.3.98 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 3.3.97 +Fri, 07 Apr 2023 22:19:21 GMT + +_Version update only_ + +## 3.3.96 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 3.3.95 +Thu, 23 Mar 2023 15:24:08 GMT + +_Version update only_ + +## 3.3.94 +Wed, 22 Mar 2023 20:48:30 GMT + +_Version update only_ + +## 3.3.93 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 3.3.92 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 3.3.91 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 3.3.90 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 3.3.89 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 3.3.88 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 3.3.87 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 3.3.86 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 3.3.85 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 3.3.84 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 3.3.83 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 3.3.82 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 3.3.81 +Fri, 02 Dec 2022 01:15:42 GMT + +_Version update only_ + +## 3.3.80 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 3.3.79 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 3.3.78 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 3.3.77 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 3.3.76 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 3.3.75 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 3.3.74 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 3.3.73 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 3.3.72 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 3.3.71 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 3.3.70 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 3.3.69 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 3.3.68 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 3.3.67 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 3.3.66 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 3.3.65 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 3.3.64 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 3.3.63 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 3.3.62 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 3.3.61 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 3.3.60 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 3.3.59 +Fri, 19 Aug 2022 00:17:19 GMT + +_Version update only_ + +## 3.3.58 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 3.3.57 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 3.3.56 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 3.3.55 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 3.3.54 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 3.3.53 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 3.3.52 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 3.3.51 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 3.3.50 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 3.3.49 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 3.3.48 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 3.3.47 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 3.3.46 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 3.3.45 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 3.3.44 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 3.3.43 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 3.3.42 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 3.3.41 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 3.3.40 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Bump @types/webpack + +## 3.3.39 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 3.3.38 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 3.3.37 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 3.3.36 +Wed, 18 May 2022 15:10:56 GMT + +_Version update only_ + +## 3.3.35 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 3.3.34 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 3.3.33 +Fri, 06 May 2022 18:54:42 GMT + +_Version update only_ + +## 3.3.32 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 3.3.31 +Wed, 04 May 2022 02:35:33 GMT + +### Patches + +- Make @rushstack/webpack-plugin-utilities a normal dependency. + +## 3.3.30 +Wed, 27 Apr 2022 01:19:20 GMT + +### Patches + +- Move webpack version detection logic to the "@rushstack/webpack-plugin-utilities" package + +## 3.3.29 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 3.3.28 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 3.3.27 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 3.3.26 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 3.3.25 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 3.3.24 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 3.3.23 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 3.3.22 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 3.3.21 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 3.3.20 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 3.3.19 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 3.3.18 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 3.3.17 +Tue, 15 Mar 2022 19:15:54 GMT + +_Version update only_ + +## 3.3.16 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 3.3.15 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 3.3.14 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 3.3.13 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 3.3.12 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 3.3.11 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 3.3.10 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 3.3.9 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 3.3.8 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 3.3.7 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 3.3.6 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 3.3.5 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 3.3.4 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 3.3.3 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 3.3.2 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 3.3.1 +Thu, 11 Nov 2021 01:17:02 GMT + +### Patches + +- Update typings to only import from "webpack." + +## 3.3.0 +Wed, 10 Nov 2021 16:09:47 GMT + +### Minor changes + +- Introduce a warning when running in Webpack 5. + +## 3.2.90 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 3.2.89 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 3.2.88 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 3.2.87 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 3.2.86 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 3.2.85 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 3.2.84 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 3.2.83 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 3.2.82 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 3.2.81 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 3.2.80 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 3.2.79 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 3.2.78 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 3.2.77 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 3.2.76 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 3.2.75 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 3.2.74 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 3.2.73 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 3.2.72 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 3.2.71 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 3.2.70 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 3.2.69 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 3.2.68 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 3.2.67 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 3.2.66 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 3.2.65 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 3.2.64 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 3.2.63 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 3.2.62 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 3.2.61 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 3.2.60 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 3.2.59 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 3.2.58 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 3.2.57 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 3.2.56 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 3.2.55 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 3.2.54 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 3.2.53 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 3.2.52 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 3.2.51 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 3.2.50 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 3.2.49 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 3.2.48 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 3.2.47 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 3.2.46 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 3.2.45 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 3.2.44 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 3.2.43 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 3.2.42 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 3.2.41 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 3.2.40 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 3.2.39 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 3.2.38 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 3.2.37 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 3.2.36 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 3.2.35 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 3.2.34 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 3.2.33 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 3.2.32 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 3.2.31 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 3.2.30 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 3.2.29 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 3.2.28 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 3.2.27 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 3.2.26 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 3.2.25 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 3.2.24 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 3.2.23 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 3.2.22 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 3.2.21 +Thu, 08 Apr 2021 20:41:55 GMT + +_Version update only_ + +## 3.2.20 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 3.2.19 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 3.2.18 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 3.2.17 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 3.2.16 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 3.2.15 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 3.2.14 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 3.2.13 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 3.2.12 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 3.2.11 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 3.2.10 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 3.2.9 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 3.2.8 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 3.2.7 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 3.2.6 +Thu, 21 Jan 2021 04:19:01 GMT + +_Version update only_ + +## 3.2.5 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 3.2.4 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 3.2.3 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 3.2.2 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 3.2.1 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 3.2.0 +Tue, 08 Dec 2020 01:10:30 GMT + +### Minor changes + +- Remove uglify dependency and make suffix script always minified. + +## 3.1.19 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 3.1.18 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 3.1.17 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 3.1.16 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 3.1.15 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 3.1.14 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 3.1.13 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 3.1.12 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 3.1.11 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 3.1.10 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 3.1.9 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 3.1.8 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 3.1.7 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 3.1.6 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 3.1.5 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 3.1.4 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 3.1.3 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 3.1.2 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 3.1.1 +Thu, 29 Oct 2020 06:14:19 GMT + +_Version update only_ + +## 3.1.0 +Thu, 29 Oct 2020 00:11:33 GMT + +### Minor changes + +- Update Webpack dependency to ~4.44.2 + +## 3.0.18 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 3.0.17 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 3.0.16 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 3.0.15 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 3.0.14 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 3.0.13 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 3.0.12 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 3.0.11 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 3.0.10 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 3.0.9 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 3.0.8 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 3.0.7 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 3.0.6 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 3.0.5 +Mon, 05 Oct 2020 15:10:43 GMT + +_Version update only_ + +## 3.0.4 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 3.0.3 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 3.0.2 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 3.0.1 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 3.0.0 +Wed, 30 Sep 2020 06:53:53 GMT + +### Breaking changes + +- Drop support for Webpack 3. + +### Patches + +- Update README.md + +## 2.4.65 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 2.4.64 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 2.4.63 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 2.4.62 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 2.4.61 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 2.4.60 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 2.4.59 +Fri, 18 Sep 2020 21:49:54 GMT + +_Version update only_ + +## 2.4.58 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 2.4.57 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 2.4.56 +Mon, 14 Sep 2020 15:09:49 GMT + +_Version update only_ + +## 2.4.55 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 2.4.54 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 2.4.53 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 2.4.52 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 2.4.51 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 2.4.50 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 2.4.49 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 2.4.48 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 2.4.47 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 2.4.46 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 2.4.45 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 2.4.44 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 2.4.43 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 2.4.42 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 2.4.41 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 2.4.40 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 2.4.39 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 2.4.38 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 2.4.37 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 2.4.36 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 2.4.35 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 2.4.34 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 2.4.33 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 2.4.32 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 2.4.31 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 2.4.30 +Wed, 15 Jul 2020 15:09:42 GMT + +### Patches + +- Fix specification of optional peerDependencies. + +## 2.4.29 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 2.4.28 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 2.4.27 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 2.4.26 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 2.4.25 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 2.4.24 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 2.4.23 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 2.4.22 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 2.4.21 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 2.4.20 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 2.4.19 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 2.4.18 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 2.4.17 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 2.4.16 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 2.4.15 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 2.4.14 +Fri, 22 May 2020 15:08:42 GMT + +_Version update only_ + +## 2.4.13 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 2.4.12 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 2.4.11 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 2.4.10 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 2.4.9 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 2.4.8 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 2.4.7 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 2.4.6 +Mon, 06 Apr 2020 05:52:56 GMT + +### Patches + +- Fix an issue where sourcemaps with inlined sources can contain incorrect escaping. + +## 2.4.5 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 2.4.4 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 2.4.3 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ ## 2.4.2 Wed, 18 Mar 2020 15:07:47 GMT -*Version update only* +_Version update only_ ## 2.4.1 Tue, 17 Mar 2020 23:55:58 GMT @@ -24,22 +2324,22 @@ Tue, 04 Feb 2020 16:08:20 GMT ## 2.3.4 Tue, 28 Jan 2020 02:23:44 GMT -*Version update only* +_Version update only_ ## 2.3.3 Fri, 24 Jan 2020 00:27:39 GMT -*Version update only* +_Version update only_ ## 2.3.2 Thu, 23 Jan 2020 01:07:56 GMT -*Version update only* +_Version update only_ ## 2.3.1 Tue, 21 Jan 2020 21:56:14 GMT -*Version update only* +_Version update only_ ## 2.3.0 Sun, 19 Jan 2020 02:26:52 GMT @@ -51,42 +2351,42 @@ Sun, 19 Jan 2020 02:26:52 GMT ## 2.2.23 Fri, 17 Jan 2020 01:08:23 GMT -*Version update only* +_Version update only_ ## 2.2.22 Tue, 14 Jan 2020 01:34:16 GMT -*Version update only* +_Version update only_ ## 2.2.21 Sat, 11 Jan 2020 05:18:24 GMT -*Version update only* +_Version update only_ ## 2.2.20 Thu, 09 Jan 2020 06:44:13 GMT -*Version update only* +_Version update only_ ## 2.2.19 Wed, 08 Jan 2020 00:11:31 GMT -*Version update only* +_Version update only_ ## 2.2.18 Wed, 04 Dec 2019 23:17:55 GMT -*Version update only* +_Version update only_ ## 2.2.17 Tue, 03 Dec 2019 03:17:44 GMT -*Version update only* +_Version update only_ ## 2.2.16 Sun, 24 Nov 2019 00:54:04 GMT -*Version update only* +_Version update only_ ## 2.2.15 Wed, 20 Nov 2019 06:14:28 GMT @@ -98,57 +2398,57 @@ Wed, 20 Nov 2019 06:14:28 GMT ## 2.2.14 Fri, 15 Nov 2019 04:50:50 GMT -*Version update only* +_Version update only_ ## 2.2.13 Mon, 11 Nov 2019 16:07:56 GMT -*Version update only* +_Version update only_ ## 2.2.12 Wed, 06 Nov 2019 22:44:18 GMT -*Version update only* +_Version update only_ ## 2.2.11 Tue, 05 Nov 2019 06:49:29 GMT -*Version update only* +_Version update only_ ## 2.2.10 Tue, 05 Nov 2019 01:08:39 GMT -*Version update only* +_Version update only_ ## 2.2.9 Fri, 25 Oct 2019 15:08:55 GMT -*Version update only* +_Version update only_ ## 2.2.8 Tue, 22 Oct 2019 06:24:44 GMT -*Version update only* +_Version update only_ ## 2.2.7 Mon, 21 Oct 2019 05:22:43 GMT -*Version update only* +_Version update only_ ## 2.2.6 Fri, 18 Oct 2019 15:15:01 GMT -*Version update only* +_Version update only_ ## 2.2.5 Sun, 06 Oct 2019 00:27:40 GMT -*Version update only* +_Version update only_ ## 2.2.4 Fri, 04 Oct 2019 00:15:22 GMT -*Version update only* +_Version update only_ ## 2.2.3 Sun, 29 Sep 2019 23:56:29 GMT @@ -160,12 +2460,12 @@ Sun, 29 Sep 2019 23:56:29 GMT ## 2.2.2 Wed, 25 Sep 2019 15:15:31 GMT -*Version update only* +_Version update only_ ## 2.2.1 Tue, 24 Sep 2019 02:58:49 GMT -*Version update only* +_Version update only_ ## 2.2.0 Mon, 23 Sep 2019 15:14:55 GMT @@ -177,32 +2477,32 @@ Mon, 23 Sep 2019 15:14:55 GMT ## 2.1.135 Fri, 20 Sep 2019 21:27:22 GMT -*Version update only* +_Version update only_ ## 2.1.134 Wed, 11 Sep 2019 19:56:23 GMT -*Version update only* +_Version update only_ ## 2.1.133 Tue, 10 Sep 2019 22:32:23 GMT -*Version update only* +_Version update only_ ## 2.1.132 Tue, 10 Sep 2019 20:38:33 GMT -*Version update only* +_Version update only_ ## 2.1.131 Wed, 04 Sep 2019 18:28:06 GMT -*Version update only* +_Version update only_ ## 2.1.130 Wed, 04 Sep 2019 15:15:37 GMT -*Version update only* +_Version update only_ ## 2.1.129 Wed, 04 Sep 2019 01:43:31 GMT @@ -214,22 +2514,22 @@ Wed, 04 Sep 2019 01:43:31 GMT ## 2.1.128 Fri, 30 Aug 2019 00:14:32 GMT -*Version update only* +_Version update only_ ## 2.1.127 Mon, 12 Aug 2019 15:15:14 GMT -*Version update only* +_Version update only_ ## 2.1.126 Thu, 08 Aug 2019 15:14:17 GMT -*Version update only* +_Version update only_ ## 2.1.125 Thu, 08 Aug 2019 00:49:06 GMT -*Version update only* +_Version update only_ ## 2.1.124 Mon, 05 Aug 2019 22:04:32 GMT @@ -241,477 +2541,477 @@ Mon, 05 Aug 2019 22:04:32 GMT ## 2.1.123 Tue, 23 Jul 2019 19:14:38 GMT -*Version update only* +_Version update only_ ## 2.1.122 Tue, 23 Jul 2019 01:13:01 GMT -*Version update only* +_Version update only_ ## 2.1.121 Mon, 22 Jul 2019 19:13:10 GMT -*Version update only* +_Version update only_ ## 2.1.120 Fri, 12 Jul 2019 19:12:46 GMT -*Version update only* +_Version update only_ ## 2.1.119 Thu, 11 Jul 2019 19:13:08 GMT -*Version update only* +_Version update only_ ## 2.1.118 Tue, 09 Jul 2019 19:13:24 GMT -*Version update only* +_Version update only_ ## 2.1.117 Mon, 08 Jul 2019 19:12:19 GMT -*Version update only* +_Version update only_ ## 2.1.116 Sat, 29 Jun 2019 02:30:10 GMT -*Version update only* +_Version update only_ ## 2.1.115 Wed, 12 Jun 2019 19:12:33 GMT -*Version update only* +_Version update only_ ## 2.1.114 Tue, 11 Jun 2019 00:48:06 GMT -*Version update only* +_Version update only_ ## 2.1.113 Thu, 06 Jun 2019 22:33:36 GMT -*Version update only* +_Version update only_ ## 2.1.112 Wed, 05 Jun 2019 19:12:34 GMT -*Version update only* +_Version update only_ ## 2.1.111 Tue, 04 Jun 2019 05:51:54 GMT -*Version update only* +_Version update only_ ## 2.1.110 Mon, 27 May 2019 04:13:44 GMT -*Version update only* +_Version update only_ ## 2.1.109 Mon, 13 May 2019 02:08:35 GMT -*Version update only* +_Version update only_ ## 2.1.108 Mon, 06 May 2019 20:46:22 GMT -*Version update only* +_Version update only_ ## 2.1.107 Mon, 06 May 2019 19:34:54 GMT -*Version update only* +_Version update only_ ## 2.1.106 Mon, 06 May 2019 19:11:16 GMT -*Version update only* +_Version update only_ ## 2.1.105 Tue, 30 Apr 2019 23:08:02 GMT -*Version update only* +_Version update only_ ## 2.1.104 Tue, 16 Apr 2019 11:01:37 GMT -*Version update only* +_Version update only_ ## 2.1.103 Fri, 12 Apr 2019 06:13:17 GMT -*Version update only* +_Version update only_ ## 2.1.102 Thu, 11 Apr 2019 07:14:01 GMT -*Version update only* +_Version update only_ ## 2.1.101 Tue, 09 Apr 2019 05:31:01 GMT -*Version update only* +_Version update only_ ## 2.1.100 Mon, 08 Apr 2019 19:12:53 GMT -*Version update only* +_Version update only_ ## 2.1.99 Sat, 06 Apr 2019 02:05:51 GMT -*Version update only* +_Version update only_ ## 2.1.98 Fri, 05 Apr 2019 04:16:17 GMT -*Version update only* +_Version update only_ ## 2.1.97 Wed, 03 Apr 2019 02:58:33 GMT -*Version update only* +_Version update only_ ## 2.1.96 Tue, 02 Apr 2019 01:12:02 GMT -*Version update only* +_Version update only_ ## 2.1.95 Sat, 30 Mar 2019 22:27:16 GMT -*Version update only* +_Version update only_ ## 2.1.94 Thu, 28 Mar 2019 19:14:27 GMT -*Version update only* +_Version update only_ ## 2.1.93 Tue, 26 Mar 2019 20:54:19 GMT -*Version update only* +_Version update only_ ## 2.1.92 Sat, 23 Mar 2019 03:48:31 GMT -*Version update only* +_Version update only_ ## 2.1.91 Thu, 21 Mar 2019 04:59:11 GMT -*Version update only* +_Version update only_ ## 2.1.90 Thu, 21 Mar 2019 01:15:33 GMT -*Version update only* +_Version update only_ ## 2.1.89 Wed, 20 Mar 2019 19:14:49 GMT -*Version update only* +_Version update only_ ## 2.1.88 Mon, 18 Mar 2019 04:28:43 GMT -*Version update only* +_Version update only_ ## 2.1.87 Fri, 15 Mar 2019 19:13:25 GMT -*Version update only* +_Version update only_ ## 2.1.86 Wed, 13 Mar 2019 19:13:14 GMT -*Version update only* +_Version update only_ ## 2.1.85 Wed, 13 Mar 2019 01:14:05 GMT -*Version update only* +_Version update only_ ## 2.1.84 Mon, 11 Mar 2019 16:13:36 GMT -*Version update only* +_Version update only_ ## 2.1.83 Tue, 05 Mar 2019 17:13:11 GMT -*Version update only* +_Version update only_ ## 2.1.82 Mon, 04 Mar 2019 17:13:20 GMT -*Version update only* +_Version update only_ ## 2.1.81 Wed, 27 Feb 2019 22:13:58 GMT -*Version update only* +_Version update only_ ## 2.1.80 Wed, 27 Feb 2019 17:13:17 GMT -*Version update only* +_Version update only_ ## 2.1.79 Mon, 18 Feb 2019 17:13:23 GMT -*Version update only* +_Version update only_ ## 2.1.78 Tue, 12 Feb 2019 17:13:12 GMT -*Version update only* +_Version update only_ ## 2.1.77 Mon, 11 Feb 2019 10:32:37 GMT -*Version update only* +_Version update only_ ## 2.1.76 Mon, 11 Feb 2019 03:31:55 GMT -*Version update only* +_Version update only_ ## 2.1.75 Wed, 30 Jan 2019 20:49:12 GMT -*Version update only* +_Version update only_ ## 2.1.74 Sat, 19 Jan 2019 03:47:47 GMT -*Version update only* +_Version update only_ ## 2.1.73 Tue, 15 Jan 2019 17:04:09 GMT -*Version update only* +_Version update only_ ## 2.1.72 Thu, 10 Jan 2019 01:57:53 GMT -*Version update only* +_Version update only_ ## 2.1.71 Mon, 07 Jan 2019 17:04:07 GMT -*Version update only* +_Version update only_ ## 2.1.70 Wed, 19 Dec 2018 05:57:33 GMT -*Version update only* +_Version update only_ ## 2.1.69 Thu, 13 Dec 2018 02:58:11 GMT -*Version update only* +_Version update only_ ## 2.1.68 Wed, 12 Dec 2018 17:04:19 GMT -*Version update only* +_Version update only_ ## 2.1.67 Sat, 08 Dec 2018 06:35:36 GMT -*Version update only* +_Version update only_ ## 2.1.66 Fri, 07 Dec 2018 17:04:56 GMT -*Version update only* +_Version update only_ ## 2.1.65 Fri, 30 Nov 2018 23:34:58 GMT -*Version update only* +_Version update only_ ## 2.1.64 Thu, 29 Nov 2018 07:02:09 GMT -*Version update only* +_Version update only_ ## 2.1.63 Thu, 29 Nov 2018 00:35:39 GMT -*Version update only* +_Version update only_ ## 2.1.62 Wed, 28 Nov 2018 19:29:54 GMT -*Version update only* +_Version update only_ ## 2.1.61 Wed, 28 Nov 2018 02:17:11 GMT -*Version update only* +_Version update only_ ## 2.1.60 Fri, 16 Nov 2018 21:37:10 GMT -*Version update only* +_Version update only_ ## 2.1.59 Fri, 16 Nov 2018 00:59:00 GMT -*Version update only* +_Version update only_ ## 2.1.58 Fri, 09 Nov 2018 23:07:39 GMT -*Version update only* +_Version update only_ ## 2.1.57 Wed, 07 Nov 2018 21:04:35 GMT -*Version update only* +_Version update only_ ## 2.1.56 Wed, 07 Nov 2018 17:03:03 GMT -*Version update only* +_Version update only_ ## 2.1.55 Mon, 05 Nov 2018 17:04:24 GMT -*Version update only* +_Version update only_ ## 2.1.54 Thu, 01 Nov 2018 21:33:52 GMT -*Version update only* +_Version update only_ ## 2.1.53 Thu, 01 Nov 2018 19:32:52 GMT -*Version update only* +_Version update only_ ## 2.1.52 Wed, 31 Oct 2018 21:17:50 GMT -*Version update only* +_Version update only_ ## 2.1.51 Wed, 31 Oct 2018 17:00:55 GMT -*Version update only* +_Version update only_ ## 2.1.50 Sat, 27 Oct 2018 03:45:51 GMT -*Version update only* +_Version update only_ ## 2.1.49 Sat, 27 Oct 2018 02:17:18 GMT -*Version update only* +_Version update only_ ## 2.1.48 Sat, 27 Oct 2018 00:26:56 GMT -*Version update only* +_Version update only_ ## 2.1.47 Thu, 25 Oct 2018 23:20:40 GMT -*Version update only* +_Version update only_ ## 2.1.46 Thu, 25 Oct 2018 08:56:02 GMT -*Version update only* +_Version update only_ ## 2.1.45 Wed, 24 Oct 2018 16:03:10 GMT -*Version update only* +_Version update only_ ## 2.1.44 Thu, 18 Oct 2018 05:30:14 GMT -*Version update only* +_Version update only_ ## 2.1.43 Thu, 18 Oct 2018 01:32:21 GMT -*Version update only* +_Version update only_ ## 2.1.42 Wed, 17 Oct 2018 21:04:49 GMT -*Version update only* +_Version update only_ ## 2.1.41 Wed, 17 Oct 2018 14:43:24 GMT -*Version update only* +_Version update only_ ## 2.1.40 Thu, 11 Oct 2018 23:26:07 GMT -*Version update only* +_Version update only_ ## 2.1.39 Tue, 09 Oct 2018 06:58:02 GMT -*Version update only* +_Version update only_ ## 2.1.38 Mon, 08 Oct 2018 16:04:27 GMT -*Version update only* +_Version update only_ ## 2.1.37 Sun, 07 Oct 2018 06:15:56 GMT -*Version update only* +_Version update only_ ## 2.1.36 Fri, 28 Sep 2018 16:05:35 GMT -*Version update only* +_Version update only_ ## 2.1.35 Wed, 26 Sep 2018 21:39:40 GMT -*Version update only* +_Version update only_ ## 2.1.34 Mon, 24 Sep 2018 23:06:40 GMT -*Version update only* +_Version update only_ ## 2.1.33 Mon, 24 Sep 2018 16:04:28 GMT -*Version update only* +_Version update only_ ## 2.1.32 Fri, 21 Sep 2018 16:04:42 GMT -*Version update only* +_Version update only_ ## 2.1.31 Thu, 20 Sep 2018 23:57:22 GMT -*Version update only* +_Version update only_ ## 2.1.30 Tue, 18 Sep 2018 21:04:56 GMT -*Version update only* +_Version update only_ ## 2.1.29 Mon, 10 Sep 2018 23:23:01 GMT -*Version update only* +_Version update only_ ## 2.1.28 Thu, 06 Sep 2018 01:25:26 GMT @@ -723,37 +3023,37 @@ Thu, 06 Sep 2018 01:25:26 GMT ## 2.1.27 Tue, 04 Sep 2018 21:34:10 GMT -*Version update only* +_Version update only_ ## 2.1.26 Mon, 03 Sep 2018 16:04:46 GMT -*Version update only* +_Version update only_ ## 2.1.25 Thu, 30 Aug 2018 22:47:34 GMT -*Version update only* +_Version update only_ ## 2.1.24 Thu, 30 Aug 2018 19:23:16 GMT -*Version update only* +_Version update only_ ## 2.1.23 Thu, 30 Aug 2018 18:45:12 GMT -*Version update only* +_Version update only_ ## 2.1.22 Wed, 29 Aug 2018 21:43:23 GMT -*Version update only* +_Version update only_ ## 2.1.21 Wed, 29 Aug 2018 06:36:50 GMT -*Version update only* +_Version update only_ ## 2.1.20 Thu, 23 Aug 2018 18:18:53 GMT @@ -765,27 +3065,27 @@ Thu, 23 Aug 2018 18:18:53 GMT ## 2.1.19 Wed, 22 Aug 2018 20:58:58 GMT -*Version update only* +_Version update only_ ## 2.1.18 Wed, 22 Aug 2018 16:03:25 GMT -*Version update only* +_Version update only_ ## 2.1.17 Tue, 21 Aug 2018 16:04:38 GMT -*Version update only* +_Version update only_ ## 2.1.16 Thu, 09 Aug 2018 21:58:02 GMT -*Version update only* +_Version update only_ ## 2.1.15 Thu, 09 Aug 2018 21:03:22 GMT -*Version update only* +_Version update only_ ## 2.1.14 Thu, 09 Aug 2018 16:04:24 GMT @@ -797,67 +3097,67 @@ Thu, 09 Aug 2018 16:04:24 GMT ## 2.1.13 Tue, 07 Aug 2018 22:27:31 GMT -*Version update only* +_Version update only_ ## 2.1.12 Thu, 26 Jul 2018 23:53:43 GMT -*Version update only* +_Version update only_ ## 2.1.11 Thu, 26 Jul 2018 16:04:17 GMT -*Version update only* +_Version update only_ ## 2.1.10 Wed, 25 Jul 2018 21:02:57 GMT -*Version update only* +_Version update only_ ## 2.1.9 Fri, 20 Jul 2018 16:04:52 GMT -*Version update only* +_Version update only_ ## 2.1.8 Tue, 17 Jul 2018 16:02:52 GMT -*Version update only* +_Version update only_ ## 2.1.7 Fri, 13 Jul 2018 19:04:50 GMT -*Version update only* +_Version update only_ ## 2.1.6 Tue, 03 Jul 2018 21:03:31 GMT -*Version update only* +_Version update only_ ## 2.1.5 Fri, 29 Jun 2018 02:56:51 GMT -*Version update only* +_Version update only_ ## 2.1.4 Sat, 23 Jun 2018 02:21:20 GMT -*Version update only* +_Version update only_ ## 2.1.3 Fri, 22 Jun 2018 16:05:15 GMT -*Version update only* +_Version update only_ ## 2.1.2 Thu, 21 Jun 2018 08:27:29 GMT -*Version update only* +_Version update only_ ## 2.1.1 Tue, 19 Jun 2018 19:35:11 GMT -*Version update only* +_Version update only_ ## 2.1.0 Wed, 13 Jun 2018 16:05:21 GMT @@ -876,52 +3176,52 @@ Fri, 08 Jun 2018 08:43:52 GMT ## 1.5.12 Thu, 31 May 2018 01:39:33 GMT -*Version update only* +_Version update only_ ## 1.5.11 Tue, 15 May 2018 02:26:45 GMT -*Version update only* +_Version update only_ ## 1.5.10 Tue, 15 May 2018 00:18:10 GMT -*Version update only* +_Version update only_ ## 1.5.9 Fri, 11 May 2018 22:43:14 GMT -*Version update only* +_Version update only_ ## 1.5.8 Fri, 04 May 2018 00:42:38 GMT -*Version update only* +_Version update only_ ## 1.5.7 Tue, 01 May 2018 22:03:20 GMT -*Version update only* +_Version update only_ ## 1.5.6 Fri, 27 Apr 2018 03:04:32 GMT -*Version update only* +_Version update only_ ## 1.5.5 Fri, 20 Apr 2018 16:06:11 GMT -*Version update only* +_Version update only_ ## 1.5.4 Thu, 19 Apr 2018 21:25:56 GMT -*Version update only* +_Version update only_ ## 1.5.3 Thu, 19 Apr 2018 17:02:06 GMT -*Version update only* +_Version update only_ ## 1.5.2 Fri, 06 Apr 2018 16:03:14 GMT @@ -933,7 +3233,7 @@ Fri, 06 Apr 2018 16:03:14 GMT ## 1.5.1 Tue, 03 Apr 2018 16:05:29 GMT -*Version update only* +_Version update only_ ## 1.5.0 Mon, 02 Apr 2018 16:05:24 GMT @@ -945,52 +3245,52 @@ Mon, 02 Apr 2018 16:05:24 GMT ## 1.4.29 Tue, 27 Mar 2018 01:34:25 GMT -*Version update only* +_Version update only_ ## 1.4.28 Mon, 26 Mar 2018 19:12:42 GMT -*Version update only* +_Version update only_ ## 1.4.27 Sun, 25 Mar 2018 01:26:19 GMT -*Version update only* +_Version update only_ ## 1.4.26 Fri, 23 Mar 2018 00:34:53 GMT -*Version update only* +_Version update only_ ## 1.4.25 Thu, 22 Mar 2018 18:34:13 GMT -*Version update only* +_Version update only_ ## 1.4.24 Tue, 20 Mar 2018 02:44:45 GMT -*Version update only* +_Version update only_ ## 1.4.23 Sat, 17 Mar 2018 02:54:22 GMT -*Version update only* +_Version update only_ ## 1.4.22 Thu, 15 Mar 2018 20:00:50 GMT -*Version update only* +_Version update only_ ## 1.4.21 Thu, 15 Mar 2018 16:05:43 GMT -*Version update only* +_Version update only_ ## 1.4.20 Tue, 13 Mar 2018 23:11:32 GMT -*Version update only* +_Version update only_ ## 1.4.19 Mon, 12 Mar 2018 20:36:19 GMT @@ -1002,52 +3302,52 @@ Mon, 12 Mar 2018 20:36:19 GMT ## 1.4.18 Tue, 06 Mar 2018 17:04:51 GMT -*Version update only* +_Version update only_ ## 1.4.17 Fri, 02 Mar 2018 01:13:59 GMT -*Version update only* +_Version update only_ ## 1.4.16 Tue, 27 Feb 2018 22:05:57 GMT -*Version update only* +_Version update only_ ## 1.4.15 Wed, 21 Feb 2018 22:04:19 GMT -*Version update only* +_Version update only_ ## 1.4.14 Wed, 21 Feb 2018 03:13:29 GMT -*Version update only* +_Version update only_ ## 1.4.13 Sat, 17 Feb 2018 02:53:49 GMT -*Version update only* +_Version update only_ ## 1.4.12 Fri, 16 Feb 2018 22:05:23 GMT -*Version update only* +_Version update only_ ## 1.4.11 Fri, 16 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.4.10 Wed, 07 Feb 2018 17:05:11 GMT -*Version update only* +_Version update only_ ## 1.4.9 Fri, 26 Jan 2018 22:05:30 GMT -*Version update only* +_Version update only_ ## 1.4.8 Fri, 26 Jan 2018 17:53:38 GMT @@ -1059,37 +3359,37 @@ Fri, 26 Jan 2018 17:53:38 GMT ## 1.4.7 Fri, 26 Jan 2018 00:36:51 GMT -*Version update only* +_Version update only_ ## 1.4.6 Tue, 23 Jan 2018 17:05:28 GMT -*Version update only* +_Version update only_ ## 1.4.5 Thu, 18 Jan 2018 03:23:46 GMT -*Version update only* +_Version update only_ ## 1.4.4 Thu, 18 Jan 2018 00:48:06 GMT -*Version update only* +_Version update only_ ## 1.4.3 Wed, 17 Jan 2018 10:49:31 GMT -*Version update only* +_Version update only_ ## 1.4.2 Fri, 12 Jan 2018 03:35:22 GMT -*Version update only* +_Version update only_ ## 1.4.1 Thu, 11 Jan 2018 22:31:51 GMT -*Version update only* +_Version update only_ ## 1.4.0 Wed, 10 Jan 2018 20:40:01 GMT @@ -1108,57 +3408,57 @@ Tue, 09 Jan 2018 17:05:51 GMT ## 1.3.13 Sun, 07 Jan 2018 05:12:08 GMT -*Version update only* +_Version update only_ ## 1.3.12 Fri, 05 Jan 2018 20:26:45 GMT -*Version update only* +_Version update only_ ## 1.3.11 Fri, 05 Jan 2018 00:48:41 GMT -*Version update only* +_Version update only_ ## 1.3.10 Fri, 22 Dec 2017 17:04:46 GMT -*Version update only* +_Version update only_ ## 1.3.9 Tue, 12 Dec 2017 03:33:27 GMT -*Version update only* +_Version update only_ ## 1.3.8 Thu, 30 Nov 2017 23:59:09 GMT -*Version update only* +_Version update only_ ## 1.3.7 Thu, 30 Nov 2017 23:12:21 GMT -*Version update only* +_Version update only_ ## 1.3.6 Wed, 29 Nov 2017 17:05:37 GMT -*Version update only* +_Version update only_ ## 1.3.5 Tue, 28 Nov 2017 23:43:55 GMT -*Version update only* +_Version update only_ ## 1.3.4 Mon, 13 Nov 2017 17:04:50 GMT -*Version update only* +_Version update only_ ## 1.3.3 Mon, 06 Nov 2017 17:04:18 GMT -*Version update only* +_Version update only_ ## 1.3.2 Thu, 02 Nov 2017 16:05:24 GMT @@ -1170,7 +3470,7 @@ Thu, 02 Nov 2017 16:05:24 GMT ## 1.3.1 Tue, 24 Oct 2017 18:17:12 GMT -*Version update only* +_Version update only_ ## 1.3.0 Fri, 22 Sep 2017 01:04:02 GMT @@ -1210,7 +3510,7 @@ Fri, 01 Sep 2017 01:05:54 GMT ## 1.2.1 Thu, 31 Aug 2017 18:41:18 GMT -*Version update only* +_Version update only_ ## 1.2.0 Wed, 30 Aug 2017 22:08:21 GMT @@ -1222,12 +3522,12 @@ Wed, 30 Aug 2017 22:08:21 GMT ## 1.1.2 Wed, 30 Aug 2017 01:04:34 GMT -*Version update only* +_Version update only_ ## 1.1.1 Tue, 22 Aug 2017 13:04:22 GMT -*Version update only* +_Version update only_ ## 1.1.0 Thu, 03 Aug 2017 19:16:55 GMT diff --git a/webpack/set-webpack-public-path-plugin/README.md b/webpack/set-webpack-public-path-plugin/README.md index d613ee4d01e..fa5becab039 100644 --- a/webpack/set-webpack-public-path-plugin/README.md +++ b/webpack/set-webpack-public-path-plugin/README.md @@ -4,13 +4,48 @@ `npm install @rushstack/set-webpack-public-path-plugin --save-dev` -## Overview +## Mode 1: Using the `document.currentScript` API -This simple plugin sets the `__webpack_public_path__` variable to -a value specified in the arguments, optionally appended to the SystemJs baseURL -property. +### Overview -# Plugin +This plugin wraps the entire webpack bundle in an immediately executed function expression (IIFE) that sets a variable +to the value of `document.currentScript` and then injects code that extracts the current script's base path from +the `src` attribute when setting the `__webpack_public_path__` variable. + +This is similar to the `output.publicPath = 'auto'` option, but differs in two important ways: + +1. It does not contain any fallback logic to look at `` -tags are injected onto the page, evaludated and then immediately removed. This causes an issue because they are removed -before webpack module code begins to execute, so the `publicPath=...` option won't work for modules loaded with SystemJS. - -To circumvent this issue, a small bit of code is availble to that will maintain a global register of script paths -that have been inserted onto the page. This code block should be appended to bundles that are expected to be loaded -with SystemJS and use the `publicPath=...` option. - -## `getGlobalRegisterCode(bool)` - -This function returns a block of JavaScript that maintains a global register of script tags. If the optional boolean parameter -is set to `true`, the code is not minified. By default, it is minified. You can detect if the plugin may require -the global register code by searching for the value of the `registryVariableName` field. - -## Usage without registryVariableName - -``` javascript -var setWebpackPublicPath = require('@rushstack/set-webpack-public-path-plugin'); -var gulpInsert = require('gulp-insert'); - -gulp.src('finizlied/webpack/bundle/path') - .pipe(gulpInsert.append(setWebpackPublicPath.getGlobalRegisterCode(true))) - .pipe(gulp.dest('dest/path')); -``` - -## Usage with registryVariableName - -``` javascript -var setWebpackPublicPath = require('@rushstack/set-webpack-public-path-plugin'); -var gulpInsert = require('gulp-insert'); -var gulpIf = require('gulp-if'); - -var detectRegistryVariableName = function (file) { - return file.contents.toString().indexOf(setWebpackPublicPath.registryVariableName) !== -1; -}; - -gulp.src('finizlied/webpack/bundle/path') - .pipe(gulpIf(detectRegistryVariableName, gulpInsert.append(setWebpackPublicPath.getGlobalRegisterCode(true)))) - .pipe(gulp.dest('dest/path')); -``` - -# License - -MIT (http://www.opensource.org/licenses/mit-license.php) diff --git a/webpack/set-webpack-public-path-plugin/config/api-extractor.json b/webpack/set-webpack-public-path-plugin/config/api-extractor.json index dcfa9cfc5b7..31010bc6261 100644 --- a/webpack/set-webpack-public-path-plugin/config/api-extractor.json +++ b/webpack/set-webpack-public-path-plugin/config/api-extractor.json @@ -13,6 +13,7 @@ }, "dtsRollup": { - "enabled": false + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" } } diff --git a/webpack/set-webpack-public-path-plugin/config/jest.config.json b/webpack/set-webpack-public-path-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/set-webpack-public-path-plugin/config/rig.json b/webpack/set-webpack-public-path-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/set-webpack-public-path-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/webpack/set-webpack-public-path-plugin/eslint.config.js b/webpack/set-webpack-public-path-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/set-webpack-public-path-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/webpack/set-webpack-public-path-plugin/gulpfile.js b/webpack/set-webpack-public-path-plugin/gulpfile.js deleted file mode 100644 index 37aa39ec67b..00000000000 --- a/webpack/set-webpack-public-path-plugin/gulpfile.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -let build = require('@microsoft/node-library-build'); -build.mocha.enabled = false; -build.initialize(require('gulp')); diff --git a/webpack/set-webpack-public-path-plugin/package.json b/webpack/set-webpack-public-path-plugin/package.json index 19bc7234568..665a7b26a40 100644 --- a/webpack/set-webpack-public-path-plugin/package.json +++ b/webpack/set-webpack-public-path-plugin/package.json @@ -1,36 +1,38 @@ { "name": "@rushstack/set-webpack-public-path-plugin", - "version": "2.4.2", + "version": "5.2.7", "description": "This plugin sets the webpack public path at runtime.", "main": "lib/index.js", - "typings": "lib/index.d.ts", + "typings": "dist/set-webpack-public-path-plugin.d.ts", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/microsoft/rushstack/tree/master/webpack/set-webpack-public-path-plugin" + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/set-webpack-public-path-plugin" }, "scripts": { - "build": "gulp test --clean" - }, - "dependencies": { - "lodash": "~4.17.15", - "uglify-js": "~3.0.28" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "peerDependencies": { - "@types/webpack": "*" + "webpack": "^5.68.0", + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/webpack-plugin-utilities": "workspace:*" }, "devDependencies": { - "@microsoft/node-library-build": "6.4.6", - "@microsoft/rush-stack-compiler-3.5": "0.4.5", - "@rushstack/eslint-config": "0.5.5", - "@types/lodash": "4.14.116", - "@types/mocha": "5.2.5", - "@types/node": "10.17.13", - "@types/tapable": "1.0.4", - "@types/uglify-js": "2.6.29", - "@types/webpack": "4.39.8", - "chai": "~3.5.0", - "gulp": "~4.0.2", - "mocha": "^5.2.0" + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" } } diff --git a/webpack/set-webpack-public-path-plugin/src/SetPublicPathCurrentScriptPlugin.ts b/webpack/set-webpack-public-path-plugin/src/SetPublicPathCurrentScriptPlugin.ts new file mode 100644 index 00000000000..07df200d9ae --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/SetPublicPathCurrentScriptPlugin.ts @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type webpack from 'webpack'; + +import { SetPublicPathPluginBase } from './SetPublicPathPluginBase'; + +const PLUGIN_NAME: string = 'set-webpack-public-path-current-script-plugin'; + +const CURRENT_SCRIPT_VARIABLE_NAME: string = '__RUSHSTACK_CURRENT_SCRIPT__'; +const PUBLIC_PATH_VARIABLE_NAME: string = '_publicPath'; + +type JavascriptModulesPluginHooks = ReturnType< + typeof webpack.javascript.JavascriptModulesPlugin.getCompilationHooks +>; +type CodeGenerationResults = Parameters< + Parameters[1] +>[1]['codeGenerationResults']; + +/** + * This simple plugin wraps the webpack bundle in an IIFE that sets a the `document.currentScript` value to a variable + * that is then used to populate the `__webpack_public_path__` variable. + * + * @public + */ +export class SetPublicPathCurrentScriptPlugin extends SetPublicPathPluginBase { + public constructor() { + super(PLUGIN_NAME); + } + + protected _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void { + const outputLibraryType: string | undefined = compilation.options.output.library?.type; + + class SetPublicPathRuntimeModule extends thisWebpack.RuntimeModule { + public constructor() { + super('publicPath', thisWebpack.RuntimeModule.STAGE_BASIC); + } + + public generate(): string { + return [ + `var ${PUBLIC_PATH_VARIABLE_NAME} = ${CURRENT_SCRIPT_VARIABLE_NAME} ? ${CURRENT_SCRIPT_VARIABLE_NAME}.src : '';`, + `${thisWebpack.RuntimeGlobals.publicPath} = ${PUBLIC_PATH_VARIABLE_NAME}.slice(0, ${PUBLIC_PATH_VARIABLE_NAME}.lastIndexOf('/') + 1);` + ].join('\n'); + } + } + + const runtimeModule: SetPublicPathRuntimeModule = new SetPublicPathRuntimeModule(); + + function appliesToChunk(chunk: webpack.Chunk, codeGenerationResults: CodeGenerationResults): boolean { + return chunk.hasRuntime() && codeGenerationResults.has(runtimeModule, chunk.runtime); + } + + compilation.hooks.runtimeRequirementInTree + .for(thisWebpack.RuntimeGlobals.publicPath) + .tap(PLUGIN_NAME, (chunk: webpack.Chunk, set: Set) => { + compilation.addRuntimeModule(chunk, runtimeModule); + }); + + const javascriptModulesPluginHooks: JavascriptModulesPluginHooks = + thisWebpack.javascript.JavascriptModulesPlugin.getCompilationHooks(compilation); + + javascriptModulesPluginHooks.render.tap( + { name: PLUGIN_NAME, stage: Number.MAX_SAFE_INTEGER }, + (source, { codeGenerationResults, chunk }) => { + if (appliesToChunk(chunk, codeGenerationResults)) { + return new thisWebpack.sources.ConcatSource( + `(()=>{ var ${CURRENT_SCRIPT_VARIABLE_NAME} = document.currentScript; `, + source, + '})();' + ); + } else { + return source; + } + } + ); + + javascriptModulesPluginHooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, { codeGenerationResults }) => { + hash.update(PLUGIN_NAME); + if (appliesToChunk(chunk, codeGenerationResults)) { + hash.update('set-public-path'); + } + }); + + compilation.hooks.afterSeal.tap(PLUGIN_NAME, () => { + let hasProblematicLibraryType: boolean = false; + switch (outputLibraryType) { + case 'var': + case 'module': + hasProblematicLibraryType = true; + break; + } + + if (hasProblematicLibraryType) { + const codeGenerationResults: CodeGenerationResults = compilation.codeGenerationResults; + let appliesToAnyChunk: boolean = false; + for (const chunk of compilation.chunks) { + if (appliesToChunk(chunk, codeGenerationResults)) { + appliesToAnyChunk = true; + break; + } + } + + if (appliesToAnyChunk) { + compilation.errors.push( + new thisWebpack.WebpackError( + `The "${outputLibraryType}" output.library.type is not supported by the ${SetPublicPathCurrentScriptPlugin.name}` + + ' plugin. Including this plugin with produce unexpected or invalid results.' + ) + ); + } + } + }); + } +} diff --git a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts index 1276beb9190..c328e320b16 100644 --- a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts +++ b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPlugin.ts @@ -1,24 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { EOL } from 'os'; -import { - cloneDeep, - escapeRegExp -} from 'lodash'; -import * as Webpack from 'webpack'; -import * as Tapable from 'tapable'; -import * as lodash from 'lodash'; - -import { - IV3Compilation, - IV3Module, - IV3Chunk -} from './V3Interfaces'; -import { - IInternalOptions, - getSetPublicPathCode -} from './codeGenerator'; +import type webpack from 'webpack'; + +import { Text } from '@rushstack/node-core-library'; + +import { type IInternalOptions, getSetPublicPathCode } from './codeGenerator'; +import { SetPublicPathPluginBase } from './SetPublicPathPluginBase'; /** * The base options for setting the webpack public path at runtime. @@ -26,22 +14,6 @@ import { * @public */ export interface ISetWebpackPublicPathOptions { - /** - * Use the System.baseURL property if it is defined. - */ - systemJs?: boolean; - - /** - * Use the specified string as a URL prefix after the SystemJS path or the publicPath option. - * If neither systemJs nor publicPath is defined, this option will not apply and an exception will be thrown. - */ - urlPrefix?: string; - - /** - * Use the specified path as the base public path. - */ - publicPath?: string; - /** * Check for a variable with this name on the page and use its value as a regular expression against script paths to * the bundle's script. If a value foo is passed into regexVariable, the produced bundle will look for a variable @@ -66,13 +38,45 @@ export interface ISetWebpackPublicPathOptions { * This can be useful if there are multiple scripts loaded in the DOM that match the regexVariable. */ preferLastFoundScript?: boolean; +} + +/** + * @public + */ +export interface IScriptNameAssetNameOptions { + /** + * If set to true, use the webpack generated asset's name. This option is not compatible with + * andy other scriptName options. + */ + useAssetName: true; +} +/** + * @public + */ +export interface IScriptNameRegexOptions { /** - * If true, always include the public path-setting code. Don't try to detect if any chunks or assets are present. + * A regular expression expressed as a string to be applied to all script paths on the page. */ - skipDetection?: boolean; + name: string; + + /** + * If true, the name property is tokenized. + * + * See the README for more information. + */ + isTokenized?: boolean; } +/** + * @public + */ +export type IScriptNameOptions = IScriptNameAssetNameOptions | IScriptNameRegexOptions; + +type IScriptNameInternalOptions = + | (IScriptNameAssetNameOptions & { [key in keyof IScriptNameRegexOptions]?: never }) + | (IScriptNameRegexOptions & { [key in keyof IScriptNameAssetNameOptions]?: never }); + /** * Options for the set-webpack-public-path plugin. * @@ -82,201 +86,129 @@ export interface ISetWebpackPublicPathPluginOptions extends ISetWebpackPublicPat /** * An object that describes how the public path should be discovered. */ - scriptName?: { - /** - * If set to true, use the webpack generated asset's name. This option is not compatible with - * andy other scriptName options. - */ - useAssetName?: boolean; - - /** - * A regular expression expressed as a string to be applied to all script paths on the page. - */ - name?: string; - - /** - * If true, the name property is tokenized. - * - * See the README for more information. - */ - isTokenized?: boolean; - }; -} - -interface IAsset { - size(): number; - source(): string; + scriptName: IScriptNameOptions; } -interface IV4MainTemplate extends Webpack.compilation.MainTemplate { - hooks: { - jsonpScript?: Tapable.SyncWaterfallHook; - requireExtensions: Tapable.SyncWaterfallHook; - startup: Tapable.SyncHook; - }; - requireFn: string; -} - -interface IV4Chunk extends Webpack.compilation.Chunk { - forEachModule(callback: (module: Webpack.compilation.Module) => void): void; -} +const SHOULD_REPLACE_ASSET_NAME_TOKEN: unique symbol = Symbol( + 'set-public-path-plugin-should-replace-asset-name' +); -interface IStartupCodeOptions { - source: string; - chunk: IV3Chunk | Webpack.compilation.Chunk; - hash: string; - requireFn: string; +interface IExtendedChunk extends webpack.Chunk { + [SHOULD_REPLACE_ASSET_NAME_TOKEN]?: boolean; } const PLUGIN_NAME: string = 'set-webpack-public-path'; -const SHOULD_REPLACE_ASSET_NAME_TOKEN: unique symbol = Symbol('set-public-path-plugin-should-replace-asset-name'); - const ASSET_NAME_TOKEN: string = '-ASSET-NAME-c0ef4f86-b570-44d3-b210-4428c5b7825c'; -const ASSET_NAME_TOKEN_REGEX: RegExp = new RegExp(ASSET_NAME_TOKEN); - /** - * This simple plugin sets the __webpack_public_path__ variable to a value specified in the arguments, - * optionally appended to the SystemJs baseURL property. + * This simple plugin sets the __webpack_public_path__ variable to a value specified in the arguments. * * @public */ -export class SetPublicPathPlugin implements Webpack.Plugin { - public options: ISetWebpackPublicPathPluginOptions; +export class SetPublicPathPlugin extends SetPublicPathPluginBase { + public readonly options: ISetWebpackPublicPathPluginOptions; public constructor(options: ISetWebpackPublicPathPluginOptions) { + super(PLUGIN_NAME); this.options = options; - if (options.scriptName) { - if (options.scriptName.useAssetName && options.scriptName.name) { - throw new Error('scriptName.userAssetName and scriptName.name must not be used together'); - } else if (options.scriptName.isTokenized && !options.scriptName.name) { - throw new Error('scriptName.isTokenized is only valid if scriptName.name is set'); - } + const scriptNameOptions: IScriptNameInternalOptions = options.scriptName; + if (scriptNameOptions.useAssetName && scriptNameOptions.name) { + throw new Error('scriptName.userAssetName and scriptName.name must not be used together'); + } else if (scriptNameOptions.isTokenized && !scriptNameOptions.name) { + throw new Error('scriptName.isTokenized is only valid if scriptName.name is set'); } } - public apply(compiler: Webpack.Compiler): void { - const isWebpack4: boolean = !!compiler.hooks; - - if (isWebpack4) { - compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { - const v4MainTemplate: IV4MainTemplate = compilation.mainTemplate as IV4MainTemplate; - v4MainTemplate.hooks.startup.tap(PLUGIN_NAME, (source: string, chunk: IV4Chunk, hash: string) => { - const assetOrChunkFound: boolean = !!this.options.skipDetection || this._detectAssetsOrChunks(chunk); - if (assetOrChunkFound) { - return this._getStartupCode({ - source, - chunk, - hash, - requireFn: v4MainTemplate.requireFn - }); - } else { - return source; - } - }); - }); + protected _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void { + class SetPublicPathRuntimeModule extends thisWebpack.RuntimeModule { + private readonly _pluginOptions: ISetWebpackPublicPathPluginOptions; - compiler.hooks.emit.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { - for (const chunkGroup of compilation.chunkGroups) { - for (const chunk of chunkGroup.chunks) { - if (chunk[SHOULD_REPLACE_ASSET_NAME_TOKEN]) { - for (const assetFilename of chunk.files) { - const asset: IAsset = compilation.assets[assetFilename]; - const originalAssetSource: string = asset.source(); - const originalAssetSize: number = asset.size(); - - const newAssetSource: string = originalAssetSource.replace( - ASSET_NAME_TOKEN_REGEX, - lodash.escapeRegExp(assetFilename) - ); - const sizeDifference: number = assetFilename.length - ASSET_NAME_TOKEN.length; - asset.source = () => newAssetSource; - asset.size = () => originalAssetSize + sizeDifference; - } - } - } - } - }); - } else { - if (this.options.scriptName && this.options.scriptName.useAssetName) { - throw new Error('scriptName.useAssetName is only supported on Webpack 4'); + public constructor(pluginOptions: ISetWebpackPublicPathPluginOptions) { + super('publicPath', thisWebpack.RuntimeModule.STAGE_BASIC); + this._pluginOptions = pluginOptions; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - compiler.plugin('compilation', (compilation: IV3Compilation, params: any): void => { - compilation.mainTemplate.plugin('startup', (source: string, chunk: IV3Chunk, hash: string) => { - let assetOrChunkFound: boolean = this.options.skipDetection || chunk.chunks.length > 0; - if (!assetOrChunkFound) { - chunk.forEachModule((innerModule: IV3Module) => { - if (innerModule.assets && Object.keys(innerModule.assets).length > 0) { - assetOrChunkFound = true; - } - }); - } + public generate(): string { + const { + name: regexpName, + isTokenized: regexpIsTokenized, + useAssetName + } = this._pluginOptions.scriptName as IScriptNameInternalOptions; + + const { chunk } = this; + if (!chunk) { + throw new Error(`Chunk is not defined`); + } - if (assetOrChunkFound) { - return this._getStartupCode({ - source, - chunk, - hash, - requireFn: compilation.mainTemplate.requireFn - }); - } else { - return source; + let regexName: string; + if (regexpName) { + regexName = regexpName; + if (regexpIsTokenized) { + regexName = regexName + .replace(/\[name\]/g, Text.escapeRegExp(`${chunk.name}`)) + .replace(/\[hash\]/g, chunk.renderedHash || ''); } - }); - }); - } - } + } else if (useAssetName) { + (chunk as IExtendedChunk)[SHOULD_REPLACE_ASSET_NAME_TOKEN] = true; - private _detectAssetsOrChunks(chunk: IV4Chunk): boolean { - for (const chunkGroup of chunk.groupsIterable) { - const children: Webpack.compilation.Chunk[] = chunkGroup.getChildren(); - if (children.length > 0) { - return true; - } - } + regexName = ASSET_NAME_TOKEN; + } else { + throw new Error('scriptName.name or scriptName.useAssetName must be set'); + } + + const moduleOptions: IInternalOptions = { + webpackPublicPathVariable: thisWebpack.RuntimeGlobals.publicPath, + regexName, + ...this._pluginOptions + }; - for (const innerModule of chunk.modulesIterable) { - if (innerModule.buildInfo.assets && Object.keys(innerModule.buildInfo.assets).length > 0) { - return true; + return getSetPublicPathCode(moduleOptions); } } - return false; - } + compilation.hooks.runtimeRequirementInTree + .for(thisWebpack.RuntimeGlobals.publicPath) + .tap(PLUGIN_NAME, (chunk: webpack.Chunk, set: Set) => { + compilation.addRuntimeModule(chunk, new SetPublicPathRuntimeModule(this.options)); + }); - private _getStartupCode(options: IStartupCodeOptions): string { - const moduleOptions: IInternalOptions = cloneDeep(this.options); + compilation.hooks.processAssets.tap(PLUGIN_NAME, (assets) => { + for (const chunkGroup of compilation.chunkGroups) { + for (const chunk of chunkGroup.chunks) { + if ((chunk as IExtendedChunk)[SHOULD_REPLACE_ASSET_NAME_TOKEN]) { + for (const assetFilename of chunk.files) { + let escapedAssetFilename: string; + if (assetFilename.match(/\.map$/)) { + // Trim the ".map" extension + escapedAssetFilename = assetFilename.slice(0, -4 /* '.map'.length */); + escapedAssetFilename = Text.escapeRegExp(escapedAssetFilename); + // source in sourcemaps is JSON-encoded + escapedAssetFilename = JSON.stringify(escapedAssetFilename); + // Trim the quotes from the JSON encoding + escapedAssetFilename = escapedAssetFilename.slice(1, -1); + } else { + escapedAssetFilename = Text.escapeRegExp(assetFilename); + } - // If this module has ownership over any chunks or assets, inject the public path code - moduleOptions.webpackPublicPathVariable = `${options.requireFn}.p`; - moduleOptions.linePrefix = ' '; + const asset: webpack.sources.Source = assets[assetFilename]; - if (this.options.scriptName) { - if (this.options.scriptName.name) { - moduleOptions.regexName = this.options.scriptName.name; - if (this.options.scriptName.isTokenized) { - moduleOptions.regexName = moduleOptions.regexName - .replace(/\[name\]/g, escapeRegExp(options.chunk.name)) - .replace(/\[hash\]/g, options.chunk.renderedHash); - } - } else if (this.options.scriptName.useAssetName) { - options.chunk[SHOULD_REPLACE_ASSET_NAME_TOKEN] = true; + const newAsset: webpack.sources.ReplaceSource = new thisWebpack.sources.ReplaceSource(asset); + const sourceString: string = asset.source().toString(); + for ( + let index: number = sourceString.lastIndexOf(ASSET_NAME_TOKEN); + index >= 0; + index = sourceString.lastIndexOf(ASSET_NAME_TOKEN, index - 1) + ) { + newAsset.replace(index, index + ASSET_NAME_TOKEN.length - 1, escapedAssetFilename); + } - moduleOptions.regexName = ASSET_NAME_TOKEN; + assets[assetFilename] = newAsset; + } + } + } } - } - - return [ - '// Set the webpack public path', - '(function () {', - getSetPublicPathCode(moduleOptions, console.error), - '})();', - '', - options.source - ].join(EOL); + }); } } diff --git a/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts new file mode 100644 index 00000000000..f10019fa03d --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/SetPublicPathPluginBase.ts @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type webpack from 'webpack'; + +import { VersionDetection } from '@rushstack/webpack-plugin-utilities'; +import { PackageJsonLookup, type IPackageJson } from '@rushstack/node-core-library'; + +/** + * @public + */ +export abstract class SetPublicPathPluginBase implements webpack.WebpackPluginInstance { + private readonly _pluginName: string; + + public constructor(pluginName: string) { + this._pluginName = pluginName; + } + + public apply(compiler: webpack.Compiler): void { + if (!VersionDetection.isWebpack5(compiler)) { + const thisPackageJson: IPackageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); + throw new Error( + `The ${this.constructor.name} plugin requires Webpack 5. Use major version 4 of ` + + `${thisPackageJson.name} for Webpack 4 support.` + ); + } + + const thisWebpack: typeof webpack = compiler.webpack; + + const initialOutputPublicPathSetting: typeof compiler.options.output.publicPath = + compiler.options.output.publicPath; + + compiler.hooks.thisCompilation.tap(this._pluginName, (compilation: webpack.Compilation) => { + if (initialOutputPublicPathSetting) { + compilation.warnings.push( + new compiler.webpack.WebpackError( + `The "output.publicPath" option is set in the Webpack configuration. The ${this.constructor.name} ` + + 'plugin may produce unexpected results. It is recommended that the "output.publicPath" configuration option ' + + 'be unset when using this plugin.' + ) + ); + } else { + compilation.hooks.runtimeRequirementInTree.for(thisWebpack.RuntimeGlobals.publicPath).intercept({ + name: this._pluginName, + register: (tap) => { + if (tap.name === 'RuntimePlugin') { + // Disable the default public path runtime plugin + return { + ...tap, + fn: () => { + /* noop */ + } + }; + } else { + return tap; + } + } + }); + } + + this._applyCompilation(thisWebpack, compilation); + }); + } + + protected abstract _applyCompilation(thisWebpack: typeof webpack, compilation: webpack.Compilation): void; +} diff --git a/webpack/set-webpack-public-path-plugin/src/V3Interfaces.ts b/webpack/set-webpack-public-path-plugin/src/V3Interfaces.ts deleted file mode 100644 index b6722b159d1..00000000000 --- a/webpack/set-webpack-public-path-plugin/src/V3Interfaces.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -export interface IV3Asset { -} - -export interface IV3Chunk { - chunks: IV3Chunk[]; - name: string; - renderedHash: string; - forEachModule(iterator: (module: IV3Module) => void): void; -} - -export interface IV3Module { - assets: IV3Asset[]; -} - -export interface IV3MainTemplate { - requireFn: string; - plugin(hook: 'startup', callback: (source: string, chunk: IV3Chunk, hash: string) => void): void; -} - -export interface IV3Compilation { - mainTemplate: IV3MainTemplate; -} \ No newline at end of file diff --git a/webpack/set-webpack-public-path-plugin/src/codeGenerator.ts b/webpack/set-webpack-public-path-plugin/src/codeGenerator.ts index bfef5bbc851..e78ec9666d4 100644 --- a/webpack/set-webpack-public-path-plugin/src/codeGenerator.ts +++ b/webpack/set-webpack-public-path-plugin/src/codeGenerator.ts @@ -1,187 +1,75 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { EOL } from 'os'; -import * as uglify from 'uglify-js'; - -import { - ISetWebpackPublicPathOptions -} from './SetPublicPathPlugin'; - -/** - * @public - */ -export const registryVariableName: string = 'window.__setWebpackPublicPathLoaderSrcRegistry__'; +import type { ISetWebpackPublicPathOptions } from './SetPublicPathPlugin'; export interface IInternalOptions extends ISetWebpackPublicPathOptions { - webpackPublicPathVariable?: string; - regexName?: string; + webpackPublicPathVariable: string; + regexName: string; linePrefix?: string; } -const varName: string = 'publicPath'; +const VAR_NAME: string = 'publicPath'; function joinLines(lines: string[], linePrefix?: string): string { - return lines.map((line: string) => { - if (line) { - return `${linePrefix || ''}${line}`; - } else { - return line; - } - }).join(EOL).replace(new RegExp(`${EOL}${EOL}+`, 'g'), `${EOL}${EOL}`); -} - -function escapeSingleQuotes(str: string): string | undefined { - if (str) { - return str.replace('\'', '\\\''); - } else { - return undefined; - } -} - -function appendSlashAndEscapeSingleQuotes(str: string): string | undefined { - if (str && str.substr(-1) !== '/') { - str = str + '/'; - } - - return escapeSingleQuotes(str); + return lines + .map((line: string) => { + if (line) { + return `${linePrefix || ''}${line}`; + } else { + return line; + } + }) + .join('\n') + .replace(/\n\n+/g, '\n\n'); } -export function getSetPublicPathCode(options: IInternalOptions, emitWarning: (warning: string) => void): string { - if (!options.webpackPublicPathVariable) { - throw new Error('"webpackPublicPathVariable" option must be defined.'); - } - +export function getSetPublicPathCode({ + regexName, + regexVariable, + preferLastFoundScript, + webpackPublicPathVariable, + getPostProcessScript, + linePrefix +}: IInternalOptions): string { let lines: string[] = []; - if (options.regexName) { - lines = [ - `var scripts = document.getElementsByTagName('script');` - ]; + lines = [`var scripts = document.getElementsByTagName('script');`]; - const regexInitializationSnippet: string = `/${options.regexName}/i`; - const regexVarName: string | undefined = options.regexVariable; - if (options.regexVariable) { - lines.push(...[ + const regexInitializationSnippet: string = `/${regexName}/i`; + const regexVarName: string | undefined = regexVariable; + if (regexVariable) { + lines.push( + ...[ `var regex = (typeof ${regexVarName} !== 'undefined') ? ${regexVarName} : ${regexInitializationSnippet};` - ]); - } else { - lines.push(...[ - `var regex = ${regexInitializationSnippet};` - ]); - } + ] + ); + } else { + lines.push(...[`var regex = ${regexInitializationSnippet};`]); + } - lines.push(...[ - `var ${varName};`, + lines.push( + ...[ + `var ${VAR_NAME};`, '', 'if (scripts && scripts.length) {', ' for (var i = 0; i < scripts.length; i++) {', ' if (!scripts[i]) continue;', ` var path = scripts[i].getAttribute('src');`, ' if (path && path.match(regex)) {', - ` ${varName} = path.substring(0, path.lastIndexOf('/') + 1);`, - ...(options.preferLastFoundScript ? [] : [' break;']), + ` ${VAR_NAME} = path.substring(0, path.lastIndexOf('/') + 1);`, + ...(preferLastFoundScript ? [] : [' break;']), ' }', ' }', '}', - '', - `if (!${varName}) {`, - ` for (var global in ${registryVariableName}) {`, - ' if (global && global.match(regex)) {', - ` ${varName} = global.substring(0, global.lastIndexOf('/') + 1);`, - ...(options.preferLastFoundScript ? [] : [' break;']), - ' }', - ' }', - '}' - ]); - - if (options.getPostProcessScript) { - lines.push(...[ - '', - `if (${varName}) {`, - ` ${options.getPostProcessScript(varName)};`, - '}', - '' - ]); - } - } else { - if (options.publicPath) { - lines.push(...[ - `var ${varName} = '${appendSlashAndEscapeSingleQuotes(options.publicPath)}';`, - '' - ]); - } else if (options.systemJs) { - lines.push(...[ - `var ${varName} = window.System ? window.System.baseURL || '' : '';`, - `if (${varName} !== '' && ${varName}.substr(-1) !== '/') ${varName} += '/';`, - '' - ]); - } else { - emitWarning(`Neither 'publicPath' nor 'systemJs' is defined, so the public path will not be modified`); - - return ''; - } - - if (options.urlPrefix && options.urlPrefix !== '') { - lines.push(...[ - `${varName} += '${appendSlashAndEscapeSingleQuotes(options.urlPrefix)}';`, - '' - ]); - } - - if (options.getPostProcessScript) { - lines.push(...[ - `if (${varName}) {`, - ` ${options.getPostProcessScript(varName)};`, - '}', - '' - ]); - } - } - - lines.push( - `${options.webpackPublicPathVariable} = ${varName};` + '' + ] ); - return joinLines(lines, options.linePrefix); -} - -/** - * /** - * This function returns a block of JavaScript that maintains a global register of script tags. - * - * @param debug - If true, the code returned code is not minified. Defaults to false. - * - * @public - */ -export function getGlobalRegisterCode(debug: boolean = false): string { - const lines: string[] = [ - '(function(){', - `if (!${registryVariableName}) ${registryVariableName}={};`, - `var scripts = document.getElementsByTagName('script');`, - 'if (scripts && scripts.length) {', - ' for (var i = 0; i < scripts.length; i++) {', - ' if (!scripts[i]) continue;', - ` var path = scripts[i].getAttribute('src');`, - ` if (path) ${registryVariableName}[path]=true;`, - ' }', - '}', - '})();' - ]; + if (getPostProcessScript) { + lines.push(...['', `if (${VAR_NAME}) {`, ` ${getPostProcessScript(VAR_NAME)};`, '}', '']); + } - const joinedScript: string = joinLines(lines); + lines.push(`${webpackPublicPathVariable} = ${VAR_NAME};`); - if (debug) { - return `${EOL}${joinedScript}`; - } else { - const minifyOutput: uglify.MinifyOutput = uglify.minify( - joinedScript, - { - compress: { - dead_code: true - } - } - ); - - return `${EOL}${minifyOutput.code}`; - } + return joinLines(lines, linePrefix); } diff --git a/webpack/set-webpack-public-path-plugin/src/index.ts b/webpack/set-webpack-public-path-plugin/src/index.ts index 00e419a633b..45b67b1df6d 100644 --- a/webpack/set-webpack-public-path-plugin/src/index.ts +++ b/webpack/set-webpack-public-path-plugin/src/index.ts @@ -1,15 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/** - * This simple plugin sets the `__webpack_public_path__` variable to - * a value specified in the arguments, optionally appended to the SystemJs baseURL - * property. - * @packageDocumentation - */ - -export * from './SetPublicPathPlugin'; +export { SetPublicPathPluginBase } from './SetPublicPathPluginBase'; export { - getGlobalRegisterCode, - registryVariableName -} from './codeGenerator'; + SetPublicPathPlugin, + type ISetWebpackPublicPathOptions, + type ISetWebpackPublicPathPluginOptions, + type IScriptNameAssetNameOptions, + type IScriptNameOptions, + type IScriptNameRegexOptions +} from './SetPublicPathPlugin'; +export { SetPublicPathCurrentScriptPlugin } from './SetPublicPathCurrentScriptPlugin'; diff --git a/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathCurrentScriptPlugin.test.ts b/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathCurrentScriptPlugin.test.ts new file mode 100644 index 00000000000..aee4c7712c1 --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathCurrentScriptPlugin.test.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 { SetPublicPathCurrentScriptPlugin } from '../SetPublicPathCurrentScriptPlugin'; +import { testForPlugin } from './testBase'; + +testForPlugin(SetPublicPathCurrentScriptPlugin.name, () => new SetPublicPathCurrentScriptPlugin()); diff --git a/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathPlugin.test.ts b/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathPlugin.test.ts new file mode 100644 index 00000000000..d9809a99e35 --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/test/SetPublicPathPlugin.test.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 { SetPublicPathPlugin, type ISetWebpackPublicPathPluginOptions } from '../SetPublicPathPlugin'; +import { testForPlugin } from './testBase'; + +const options: ISetWebpackPublicPathPluginOptions[] = [ + { scriptName: { useAssetName: true } }, + { + scriptName: { + name: 'foobar.js' + } + }, + { + scriptName: { + name: '[name]_[hash].js', + isTokenized: true + } + }, + { + scriptName: { useAssetName: true }, + regexVariable: 'REGEXP_VAR' + } +]; +for (const pluginOptions of options) { + testForPlugin( + `${SetPublicPathPlugin.name} (with ${JSON.stringify(pluginOptions)}})`, + () => + new SetPublicPathPlugin({ + scriptName: { + useAssetName: true + } + }) + ); +} diff --git a/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathCurrentScriptPlugin.test.ts.snap b/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathCurrentScriptPlugin.test.ts.snap new file mode 100644 index 00000000000..a4e1c395968 --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathCurrentScriptPlugin.test.ts.snap @@ -0,0 +1,3845 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r=document.currentScript;define(\\"MyLibrary\\",[],(()=>{return c={},e=r?r.src:\\"\\",c.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(c.p),{};var e,c}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_deed8afe870a5fe703ae.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0bde4e32a2c948a7e265.js": "(()=>{var r=document.currentScript;define(\\"MyLibrary\\",[],(()=>{return c={},e=r?r.src:\\"\\",c.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(c.p),{};var e,c}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles amd library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_edcf84f77954338454ea.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_63bd0745dba5dd68c24d.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r=document.currentScript;(()=>{var e,a={};e=r?r.src:\\"\\",a.p=e.slice(0,e.lastIndexOf(\\"/\\")+1);var o={};console.log(a.p);var i=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var n in o)i[n]=o[n];o.__esModule&&Object.defineProperty(i,\\"__esModule\\",{value:!0})})()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_c46fa6e9dce17d2b90d4.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0cf134716f1cb00b4bfb.js": "(()=>{var r=document.currentScript;(()=>{var e,a={};e=r?r.src:\\"\\",a.p=e.slice(0,e.lastIndexOf(\\"/\\")+1);var o={};console.log(a.p);var i=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var n in o)i[n]=o[n];o.__esModule&&Object.defineProperty(i,\\"__esModule\\",{value:!0})})()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles assign-properties library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_a61d0ddd7fbc122d026c.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_af50948fd9b47cdf66b5.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,e,c=document.currentScript;e={},r=c?c.src:\\"\\",e.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(e.p),module.exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_4618d8f04314a0c07b24.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_1146d6514379b550ffe0.js": "(()=>{var r,e,c=document.currentScript;e={},r=c?c.src:\\"\\",e.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(e.p),module.exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-module library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e,r,o=document.currentScript;r={},e=o?o.src:\\"\\",r.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(r.p),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_fdc7b1aa4223e178b616.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_90247274377f248cf2a0.js": "(()=>{var e,r,o=document.currentScript;r={},e=o?o.src:\\"\\",r.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(r.p),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs-static library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,e,c=document.currentScript;e={},r=c?c.src:\\"\\",e.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(e.p),module.exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_4618d8f04314a0c07b24.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_1146d6514379b550ffe0.js": "(()=>{var r,e,c=document.currentScript;e={},r=c?c.src:\\"\\",e.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(e.p),module.exports.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles commonjs2 library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),self.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_7d39ca5328225a0694e5.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_2a005bee247e00a0a3f2.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),self.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles global library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +)})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +)})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;MyLibrary((c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),{}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_f119a2e1669e0baf47d0.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a9d1cef220b5e7f93a8e.js": "(()=>{var r,c,e=document.currentScript;MyLibrary((c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),{}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles jsonp library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),self.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_7d39ca5328225a0694e5.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_2a005bee247e00a0a3f2.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),self.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles self library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e=document.currentScript;System.register(\\"MyLibrary\\",[],(function(r,t){return{execute:function(){var t,c;r((c={},t=e?e.src:\\"\\",c.p=t.slice(0,t.lastIndexOf(\\"/\\")+1),console.log(c.p),{}))}}}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_7d81fbd36473e27aa0fb.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_1a45796a396297604c1d.js": "(()=>{var e=document.currentScript;System.register(\\"MyLibrary\\",[],(function(r,t){return{execute:function(){var t,c;r((c={},t=e?e.src:\\"\\",c.p=t.slice(0,t.lastIndexOf(\\"/\\")+1),console.log(c.p),{}))}}}))})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles system library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r=document.currentScript;(()=>{var c,e={};c=r?r.src:\\"\\",e.p=c.slice(0,c.lastIndexOf(\\"/\\")+1),console.log(e.p),this.MyLibrary={}})()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_4d6fb5abdd3eb7fe4115.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_c6197810253dab934cb5.js": "(()=>{var r=document.currentScript;(()=>{var c,e={};c=r?r.src:\\"\\",e.p=c.slice(0,c.lastIndexOf(\\"/\\")+1),console.log(e.p),this.MyLibrary={}})()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles this library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e,o,t=document.currentScript;e=self,o=()=>{return o={},e=t?t.src:\\"\\",o.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(o.p),{};var e,o},\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_8c43c348dc21118df193.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a6627e23f74d93a203db.js": "(()=>{var e,o,t=document.currentScript;e=self,o=()=>{return o={},e=t?t.src:\\"\\",o.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(o.p),{};var e,o},\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +})})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e,o,t=document.currentScript;e=self,o=()=>{return o={},e=t?t.src:\\"\\",o.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(o.p),{};var e,o},\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_8c43c348dc21118df193.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a6627e23f74d93a203db.js": "(()=>{var e,o,t=document.currentScript;e=self,o=()=>{return o={},e=t?t.src:\\"\\",o.p=e.slice(0,e.lastIndexOf(\\"/\\")+1),console.log(o.p),{};var e,o},\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles umd2 library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (uses public path): Errors 1`] = ` +Array [ + Object { + "message": "The \\"var\\" output.library.type is not supported by the SetPublicPathCurrentScriptPlugin plugin. Including this plugin with produce unexpected or invalid results.", + }, +] +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (uses public path): Errors 1`] = ` +Array [ + Object { + "message": "The \\"var\\" output.library.type is not supported by the SetPublicPathCurrentScriptPlugin plugin. Including this plugin with produce unexpected or invalid results.", + }, +] +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (uses public path): Content 1`] = `Object {}`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (uses public path): Errors 1`] = ` +Array [ + Object { + "message": "The \\"var\\" output.library.type is not supported by the SetPublicPathCurrentScriptPlugin plugin. Including this plugin with produce unexpected or invalid results.", + }, +] +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_cdf966d89dde9e0e6511.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (uses public path): Content 1`] = `Object {}`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (uses public path): Errors 1`] = ` +Array [ + Object { + "message": "The \\"var\\" output.library.type is not supported by the SetPublicPathCurrentScriptPlugin plugin. Including this plugin with produce unexpected or invalid results.", + }, +] +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles var library output (production+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{ var __RUSHSTACK_CURRENT_SCRIPT__ = document.currentScript; /* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var _publicPath = __RUSHSTACK_CURRENT_SCRIPT__ ? __RUSHSTACK_CURRENT_SCRIPT__.src : ''; +/******/ __webpack_require__.p = _publicPath.slice(0, _publicPath.lastIndexOf('/') + 1); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +})();;", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),window.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main_5e7a9248e729d9296340.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_b1349b02271e8b1b9101.js": "(()=>{var r,c,e=document.currentScript;c={},r=e?e.src:\\"\\",c.p=r.slice(0,r.lastIndexOf(\\"/\\")+1),console.log(c.p),window.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathCurrentScriptPlugin Handles window library output (production+hash) (uses public path): Warnings 1`] = `Array []`; diff --git a/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathPlugin.test.ts.snap b/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathPlugin.test.ts.snap new file mode 100644 index 00000000000..3e69788066b --- /dev/null +++ b/webpack/set-webpack-public-path-plugin/src/test/__snapshots__/SetPublicPathPlugin.test.ts.snap @@ -0,0 +1,17105 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles amd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a96c22591ae020f988e2.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var a,r=document.getElementsByTagName(\\"script\\"),t=/main_a96c22591ae020f988e2\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_0926637b4ac11d8978ba\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main\\\\.js/i;if(a&&a.length)for(var i=0;i{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles assign-properties library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0a683184f3afcbf97c6c.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_0a683184f3afcbf97c6c\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_be77d75ccbe921238d90\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-module library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs-static library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_7f615e94560b668d69b0\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles commonjs2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles global library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles jsonp library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((()=>{var r={};return(()=>{var t,e=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(e&&e.length)for(var i=0;i{var r={};return(()=>{var t,a=document.getElementsByTagName(\\"script\\"),e=/main_d62c4a558867b9317512\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles self library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles system library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,t){return{execute:function(){var t;e((t={},(()=>{var e,r=document.getElementsByTagName(\\"script\\"),n=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e,r=document.getElementsByTagName(\\"script\\"),a=/main_b258ae75091c8f8b8490\\\\.js/i;if(r&&r.length)for(var n=0;n { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles this library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_db75e39898539074e63f.js": "(()=>{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_db75e39898539074e63f\\\\.js/i;if(a&&a.length)for(var i=0;i { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles umd2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles var library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;(()=>{var r={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),e=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var a={};(()=>{var r,e=document.getElementsByTagName(\\"script\\"),t=/main_6a43fdec20033b6103e3\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"[name]_[hash].js","isTokenized":true}}}) Handles window library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),r=/main_45661b5c41db58a7c856\\\\.js/i;if(t&&t.length)for(var i=0;i { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles amd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a96c22591ae020f988e2.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var a,r=document.getElementsByTagName(\\"script\\"),t=/main_a96c22591ae020f988e2\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_0926637b4ac11d8978ba\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main\\\\.js/i;if(a&&a.length)for(var i=0;i{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles assign-properties library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0a683184f3afcbf97c6c.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_0a683184f3afcbf97c6c\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_be77d75ccbe921238d90\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-module library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs-static library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_7f615e94560b668d69b0\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles commonjs2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles global library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles jsonp library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((()=>{var r={};return(()=>{var t,e=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(e&&e.length)for(var i=0;i{var r={};return(()=>{var t,a=document.getElementsByTagName(\\"script\\"),e=/main_d62c4a558867b9317512\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles self library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles system library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,t){return{execute:function(){var t;e((t={},(()=>{var e,r=document.getElementsByTagName(\\"script\\"),n=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e,r=document.getElementsByTagName(\\"script\\"),a=/main_b258ae75091c8f8b8490\\\\.js/i;if(r&&r.length)for(var n=0;n { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles this library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_db75e39898539074e63f.js": "(()=>{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_db75e39898539074e63f\\\\.js/i;if(a&&a.length)for(var i=0;i { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles umd2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles var library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;(()=>{var r={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),e=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var a={};(()=>{var r,e=document.getElementsByTagName(\\"script\\"),t=/main_6a43fdec20033b6103e3\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"name":"foobar.js"}}}) Handles window library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),r=/main_45661b5c41db58a7c856\\\\.js/i;if(t&&t.length)for(var i=0;i { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles amd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a96c22591ae020f988e2.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var a,r=document.getElementsByTagName(\\"script\\"),t=/main_a96c22591ae020f988e2\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_0926637b4ac11d8978ba\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main\\\\.js/i;if(a&&a.length)for(var i=0;i{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles assign-properties library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0a683184f3afcbf97c6c.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_0a683184f3afcbf97c6c\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_be77d75ccbe921238d90\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-module library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs-static library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_7f615e94560b668d69b0\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles commonjs2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles global library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles jsonp library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((()=>{var r={};return(()=>{var t,e=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(e&&e.length)for(var i=0;i{var r={};return(()=>{var t,a=document.getElementsByTagName(\\"script\\"),e=/main_d62c4a558867b9317512\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles self library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles system library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,t){return{execute:function(){var t;e((t={},(()=>{var e,r=document.getElementsByTagName(\\"script\\"),n=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e,r=document.getElementsByTagName(\\"script\\"),a=/main_b258ae75091c8f8b8490\\\\.js/i;if(r&&r.length)for(var n=0;n { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles this library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_db75e39898539074e63f.js": "(()=>{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_db75e39898539074e63f\\\\.js/i;if(a&&a.length)for(var i=0;i { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles umd2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles var library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;(()=>{var r={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),e=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var a={};(()=>{var r,e=document.getElementsByTagName(\\"script\\"),t=/main_6a43fdec20033b6103e3\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true},"regexVariable":"REGEXP_VAR"}}) Handles window library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),r=/main_45661b5c41db58a7c856\\\\.js/i;if(t&&t.length)for(var i=0;i { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +define(\\"MyLibrary\\", [], () => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles amd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_a96c22591ae020f988e2.js": "define(\\"MyLibrary\\",[],(()=>{return e={},(()=>{var a,r=document.getElementsByTagName(\\"script\\"),t=/main_a96c22591ae020f988e2\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_0926637b4ac11d8978ba\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ var __webpack_export_target__ = (MyLibrary = typeof MyLibrary === \\"undefined\\" ? {} : MyLibrary); +/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; +/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main\\\\.js/i;if(a&&a.length)for(var i=0;i{var e={};console.log(\\"Hello world!\\");var r=MyLibrary=\\"undefined\\"==typeof MyLibrary?{}:MyLibrary;for(var o in e)r[o]=e[o];e.__esModule&&Object.defineProperty(r,\\"__esModule\\",{value:!0})})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles assign-properties library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_0a683184f3afcbf97c6c.js": "(()=>{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_0a683184f3afcbf97c6c\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var a={};(()=>{var t,e=document.getElementsByTagName(\\"script\\"),r=/main_be77d75ccbe921238d90\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-module library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ Object.defineProperty((exports.MyLibrary = exports.MyLibrary || {}), \\"__esModule\\", { value: true }); +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),Object.defineProperty(exports.MyLibrary=exports.MyLibrary||{},\\"__esModule\\",{value:!0});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs-static library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var r,t=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var e={};(()=>{var r,a=document.getElementsByTagName(\\"script\\"),t=/main_7f615e94560b668d69b0\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ module.exports.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),module.exports.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles commonjs2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main_215ebada3ff1a04863f1\\\\.js/i;if(r&&r.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles global library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +MyLibrary(/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +);", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((console.log(\\"Hello world!\\"),{}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles jsonp library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "MyLibrary((()=>{var r={};return(()=>{var t,e=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(e&&e.length)for(var i=0;i{var r={};return(()=>{var t,a=document.getElementsByTagName(\\"script\\"),e=/main_d62c4a558867b9317512\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ self.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),self.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles self library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var e={};(()=>{var t,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_8cd12c1b85d952bb65f6\\\\.js/i;if(a&&a.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +System.register(\\"MyLibrary\\", [], function(__WEBPACK_DYNAMIC_EXPORT__, __system_context__) { + + + return { + + execute: function() { + __WEBPACK_DYNAMIC_EXPORT__( +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() + + ); + } + }; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,o){return{execute:function(){e((console.log(\\"Hello world!\\"),{}))}}}));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles system library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "System.register(\\"MyLibrary\\",[],(function(e,t){return{execute:function(){var t;e((t={},(()=>{var e,r=document.getElementsByTagName(\\"script\\"),n=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e,r=document.getElementsByTagName(\\"script\\"),a=/main_b258ae75091c8f8b8490\\\\.js/i;if(r&&r.length)for(var n=0;n { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ this.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{console.log(\\"Hello world!\\"),this.MyLibrary={}})();", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles this library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_db75e39898539074e63f.js": "(()=>{var e={};(()=>{var t,a=document.getElementsByTagName(\\"script\\"),r=/main_db75e39898539074e63f\\\\.js/i;if(a&&a.length)for(var i=0;i { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports[\\"MyLibrary\\"] = factory(); + else + root[\\"MyLibrary\\"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +});", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,o){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=o():\\"function\\"==typeof define&&define.amd?define([],o):\\"object\\"==typeof exports?exports.MyLibrary=o():e.MyLibrary=o()}(self,(()=>(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main\\\\.js/i;if(o&&o.length)for(var n=0;n(console.log(\\"Hello world!\\"),{})));", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles umd2 library output (production+hash) (uses public path): Content 1`] = ` +Object { + "/release/main_cf828947bceb5d39f0a1.js": "!function(e,t){\\"object\\"==typeof exports&&\\"object\\"==typeof module?module.exports=t():\\"function\\"==typeof define&&define.amd?define([],t):\\"object\\"==typeof exports?exports.MyLibrary=t():e.MyLibrary=t()}(self,(()=>{return e={},(()=>{var t,o=document.getElementsByTagName(\\"script\\"),r=/main_cf828947bceb5d39f0a1\\\\.js/i;if(o&&o.length)for(var f=0;f { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +var MyLibrary; +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;console.log(\\"Hello world!\\"),MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles var library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "var MyLibrary;(()=>{var r={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),e=/main\\\\.js/i;if(t&&t.length)for(var i=0;i{var a={};(()=>{var r,e=document.getElementsByTagName(\\"script\\"),t=/main_6a43fdec20033b6103e3\\\\.js/i;if(e&&e.length)for(var i=0;i { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ (() => { + +eval(\\"console.log(\\\\\\"Hello world!\\\\\\");\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "/* + * ATTENTION: The \\"eval\\" devtool has been used (maybe by default in mode: \\"development\\"). + * This devtool is neither made for production nor for readable output files. + * It uses \\"eval()\\" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with \\"devtool: false\\". + * If you are looking for production-ready output files, see mode: \\"production\\" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ \\"../../../../../../entry.js\\": +/*!**********************************!*\\\\ + !*** ../../../../../../entry.js ***! + \\\\**********************************/ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { + +eval(\\"console.log(__webpack_require__.p);\\\\n\\\\n//# sourceURL=webpack://MyLibrary/../../../../../../entry.js?\\"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scripts = document.getElementsByTagName('script'); +/******/ var regex = /main\\\\.js/i; +/******/ var publicPath; +/******/ +/******/ if (scripts && scripts.length) { +/******/ for (var i = 0; i < scripts.length; i++) { +/******/ if (!scripts[i]) continue; +/******/ var path = scripts[i].getAttribute('src'); +/******/ if (path && path.match(regex)) { +/******/ publicPath = path.substring(0, path.lastIndexOf('/') + 1); +/******/ break; +/******/ } +/******/ } +/******/ } +/******/ +/******/ __webpack_require__.p = publicPath; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = {}; +/******/ __webpack_modules__[\\"../../../../../../entry.js\\"](0, __webpack_exports__, __webpack_require__); +/******/ window.MyLibrary = __webpack_exports__; +/******/ +/******/ })() +;", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (uses public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (development+hash) (uses public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (production) (doesn't use public path): Content 1`] = ` +Object { + "/release/main.js": "console.log(\\"Hello world!\\"),window.MyLibrary={};", +} +`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (production) (doesn't use public path): Errors 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (production) (doesn't use public path): Warnings 1`] = `Array []`; + +exports[`SetPublicPathPlugin (with {"scriptName":{"useAssetName":true}}}) Handles window library output (production) (uses public path): Content 1`] = ` +Object { + "/release/main.js": "(()=>{var t={};(()=>{var e,r=document.getElementsByTagName(\\"script\\"),a=/main\\\\.js/i;if(r&&r.length)for(var i=0;i{var e={};(()=>{var a,t=document.getElementsByTagName(\\"script\\"),r=/main_45661b5c41db58a7c856\\\\.js/i;if(t&&t.length)for(var i=0;i webpack.WebpackPluginInstance): void { + async function testForLibraryType( + libraryType: string, + mode: 'development' | 'production', + withHash: boolean, + includePublicPath: boolean + ): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/package.json': '{}', + '/entry.js': includePublicPath + ? 'console.log(__webpack_public_path__);' + : 'console.log("Hello world!");' + }, + '/src' + ); + + const compiler: webpack.Compiler = webpack({ + mode, + entry: { + main: '/entry.js' + }, + output: { + path: '/release', + filename: withHash ? '[name]_[contenthash].js' : '[name].js', + library: { + type: libraryType, + name: 'MyLibrary' + } + }, + plugins: [getPlugin()] + }); + + compiler.inputFileSystem = memoryFileSystem as unknown as InputFileSystem; + compiler.outputFileSystem = memoryFileSystem as unknown as OutputFileSystem; + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler)); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + } + + describe(pluginName, () => { + for (const libraryType of [ + 'var', + // 'module', + 'assign', + 'assign-properties', + 'this', + 'window', + 'self', + 'global', + 'commonjs', + 'commonjs2', + 'commonjs-module', + 'commonjs-static', + 'amd', + // 'amd-require', + 'umd', + 'umd2', + 'jsonp', + 'system' + ]) { + it(`Handles ${libraryType} library output (production) (uses public path)`, async () => { + await testForLibraryType(libraryType, 'production', false, true); + }); + + it(`Handles ${libraryType} library output (production+hash) (uses public path)`, async () => { + await testForLibraryType(libraryType, 'production', true, true); + }); + + it(`Handles ${libraryType} library output (development) (uses public path)`, async () => { + await testForLibraryType(libraryType, 'development', false, true); + }); + + it(`Handles ${libraryType} library output (development+hash) (uses public path)`, async () => { + await testForLibraryType(libraryType, 'development', false, true); + }); + + it(`Handles ${libraryType} library output (production) (doesn't use public path)`, async () => { + await testForLibraryType(libraryType, 'production', false, false); + }); + + it(`Handles ${libraryType} library output (production+hash) (doesn't use public path)`, async () => { + await testForLibraryType(libraryType, 'production', true, false); + }); + + it(`Handles ${libraryType} library output (development) (doesn't use public path)`, async () => { + await testForLibraryType(libraryType, 'development', false, false); + }); + + it(`Handles ${libraryType} library output (development+hash) (doesn't use public path)`, async () => { + await testForLibraryType(libraryType, 'development', false, false); + }); + } + }); +} diff --git a/webpack/set-webpack-public-path-plugin/tsconfig.json b/webpack/set-webpack-public-path-plugin/tsconfig.json index b1abb9e5b4a..dac21d04081 100644 --- a/webpack/set-webpack-public-path-plugin/tsconfig.json +++ b/webpack/set-webpack-public-path-plugin/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./node_modules/@microsoft/rush-stack-compiler-3.5/includes/tsconfig-node.json" + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/webpack/webpack-deep-imports-plugin/.npmignore b/webpack/webpack-deep-imports-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack-deep-imports-plugin/LICENSE b/webpack/webpack-deep-imports-plugin/LICENSE new file mode 100644 index 00000000000..b16ef4a4cdf --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack-deep-imports-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/webpack/webpack-deep-imports-plugin/README.md b/webpack/webpack-deep-imports-plugin/README.md new file mode 100644 index 00000000000..b26aa1ac02b --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/README.md @@ -0,0 +1,49 @@ +# @rushstack/webpack-deep-imports-plugin + +This package contains a plugin for webpack 5 that creates a bundle and commonJS files in a 'lib' folder, +mirroring modules in another 'lib' folder. + +If you have a project that contains many loose files that may be imported via their path (instead of, or in +addition to the package's `main` entrypoint), but you don't want to pay the cost of reading many files from disk, +this plugin can be used to create a Webpack bundle that maintains compatibility with the paths to the +existing loose files. + +This enables a couple common use cases: + +- **Calling internal APIs:** SemVer compatibility guarantees may only apply to official public APIs, + which are typically top-exports of the package's `main` module. However, in situations where + certain functionality has not yet been exposed as a public API, consumers may find it expedient + to use deep imports to access library internals, with the understanding that bypassing the + API contract is done "at your own risk". + +- **Unit test mocking:** Library APIs often neglect to expose interfaces needed for + testability, such as intercepting network or disk operations. In order to write proper + unit tests, it may be necessary to mock the library's internals. Deep imports provide + a convenient way for tests to replace internal library modules with mock implementations. + +This plugin is based on the built-in Webpack `DllPlugin`. + +## Usage + +In your `webpack.config.js` file, apply this plugin with + +```JS +const { DeepImportsPlugin } = require('@rushstack/webpack-deep-imports-plugin'); + +const configuration = { + entry: { + 'my-project': `${__dirname}/lib-esnext/index.js` + }, + plugins: [ + new DeepImportsPlugin({ + path: `${__dirname}/dist/my-project-manifest.json`, // From `DllPlugin`'s options + inFolderName: 'lib-esnext', // The folder containing the original loose files and the entrypoint + outFolderName: 'lib', // The folder where the bundle and commonJS files will be written + pathsToIgnore: ['folder/not-included-in-bundle.js'], + dTsFilesInputFolderName: 'lib-commonjs' // The folder containing loose .d.ts files + }) + ] +}; + +module.exports = configuration +``` diff --git a/webpack/webpack-deep-imports-plugin/config/api-extractor.json b/webpack/webpack-deep-imports-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack-deep-imports-plugin/config/jest.config.json b/webpack/webpack-deep-imports-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/webpack-deep-imports-plugin/config/rig.json b/webpack/webpack-deep-imports-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack-deep-imports-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/webpack/webpack-deep-imports-plugin/eslint.config.js b/webpack/webpack-deep-imports-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack-deep-imports-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/webpack/webpack-deep-imports-plugin/package.json b/webpack/webpack-deep-imports-plugin/package.json new file mode 100644 index 00000000000..9fc828ff4c6 --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/package.json @@ -0,0 +1,34 @@ +{ + "name": "@rushstack/webpack-deep-imports-plugin", + "version": "0.0.0", + "description": "This plugin creates a bundle and commonJS files in a 'lib' folder mirroring modules in another 'lib' folder.", + "main": "lib/index.js", + "typings": "dist/webpack-deep-imports-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack-deep-imports-plugin" + }, + "engines": { + "node": ">=14.19.0" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "webpack": "^5.68.0" + }, + "devDependencies": { + "local-node-rig": "workspace:*", + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "webpack": "~5.98.0" + }, + "sideEffects": false, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts b/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts new file mode 100644 index 00000000000..281035faa6f --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/src/DeepImportsPlugin.ts @@ -0,0 +1,290 @@ +// 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 { DllPlugin, type Compiler, WebpackError, type Chunk, type NormalModule } from 'webpack'; + +import { Async, FileSystem, LegacyAdapters, Path } from '@rushstack/node-core-library'; + +const PLUGIN_NAME: 'DeepImportsPlugin' = 'DeepImportsPlugin'; + +type DllPluginOptions = DllPlugin['options']; + +/** + * @public + */ +export interface IDeepImportsPluginOptions extends DllPluginOptions { + /** + * The folder name under the webpack context containing the constituent files included in the + * entry's runtime chunk that will be output to the {@link IDeepImportsPluginOptions.outFolderName} + * folder. + */ + inFolderName: string; + + /** + * The folder name under the webpack context where the commonJS files that point to the + * generated bundle will be written. + */ + outFolderName: string; + + /** + * Do not create files under {@link IDeepImportsPluginOptions.outFolderName} + * for modules with paths listed in this array. + */ + pathsToIgnore?: string[]; + + /** + * If defined, copy .d.ts files for the .js files contained in the entry's runtime chunk from this folder + * under the webpack context. + */ + dTsFilesInputFolderName?: string; +} + +const JS_EXTENSION: string = '.js'; +const DTS_EXTENSION: string = '.d.ts'; + +/** + * Returns the number of `/` characters present in a given string. + */ +function countSlashes(str: string): number { + let count: number = 0; + for ( + let lastIndex: number = str.indexOf('/'); + lastIndex !== -1; + lastIndex = str.indexOf('/', lastIndex + 1) + ) { + count++; + } + + return count; +} + +/** + * Webpack plugin that creates a bundle and commonJS files in a 'lib' folder mirroring modules in another 'lib' folder. + * @public + */ +export class DeepImportsPlugin extends DllPlugin { + private readonly _inFolderName: string; + private readonly _outFolderName: string; + private readonly _pathsToIgnoreWithoutExtensions: Set; + private readonly _dTsFilesInputFolderName: string | undefined; + + public constructor(options: IDeepImportsPluginOptions) { + const superOptions: DllPluginOptions = { + ...options + }; + delete (superOptions as Partial).inFolderName; + delete (superOptions as Partial).outFolderName; + delete (superOptions as Partial).dTsFilesInputFolderName; + delete (superOptions as Partial).pathsToIgnore; + super(superOptions); + + const inFolderName: string = options.inFolderName; + if (!inFolderName) { + throw new Error(`The "inFolderName" option was not specified.`); + } + + if (path.isAbsolute(inFolderName)) { + throw new Error(`The "inFolderName" option must not be absolute.`); + } + + const outFolderName: string = options.outFolderName; + if (!outFolderName) { + throw new Error(`The "outFolderName" option was not specified.`); + } + + if (path.isAbsolute(outFolderName)) { + throw new Error(`The "outFolderName" option must not be absolute.`); + } + + const dTsFilesInputFolderName: string | undefined = options.dTsFilesInputFolderName; + if (dTsFilesInputFolderName && path.isAbsolute(dTsFilesInputFolderName)) { + throw new Error(`The "dTsFilesInputFolderName" option must not be absolute.`); + } + + const pathsToIgnoreWithoutExtensions: Set = new Set(); + for (const pathToIgnore of options.pathsToIgnore || []) { + let normalizedPathToIgnore: string = Path.convertToSlashes(pathToIgnore); + if (normalizedPathToIgnore.endsWith(JS_EXTENSION)) { + normalizedPathToIgnore = normalizedPathToIgnore.slice(0, -JS_EXTENSION.length); + } + + pathsToIgnoreWithoutExtensions.add(normalizedPathToIgnore); + } + + this._inFolderName = options.inFolderName; + this._outFolderName = options.outFolderName; + this._pathsToIgnoreWithoutExtensions = pathsToIgnoreWithoutExtensions; + this._dTsFilesInputFolderName = dTsFilesInputFolderName; + } + + public apply(compiler: Compiler): void { + super.apply(compiler); + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { + compilation.hooks.processAssets.tapPromise(PLUGIN_NAME, async () => { + const runtimeChunks: Chunk[] = []; + for (const chunk of compilation.chunks) { + if (chunk.hasRuntime()) { + runtimeChunks.push(chunk); + } + } + + const { inputFileSystem } = compiler; + if (!inputFileSystem) { + compilation.errors.push(new WebpackError(`compiler.inputFileSystem is not defined`)); + return; + } + + const outputPath: string | undefined = compilation.options.output.path; + if (!outputPath) { + compilation.errors.push(new WebpackError(`The "output.path" option was not specified.`)); + return; + } + + interface ILibModuleDescriptor { + libPathWithoutExtension: string; + moduleId: string | number | null; + secondaryChunkId: string | undefined; + } + + const pathsToIgnoreWithoutExtension: Set = this._pathsToIgnoreWithoutExtensions; + const resolvedLibInFolder: string = path.join(compiler.context, this._inFolderName); + const libModulesByChunk: Map = new Map(); + const encounteredLibPaths: Set = new Set(); + for (const runtimeChunk of runtimeChunks) { + const libModules: ILibModuleDescriptor[] = []; + function processChunks(chunk: Chunk, secondaryChunkId: string | undefined): void { + for (const runtimeChunkModule of compilation.chunkGraph.getChunkModules(chunk)) { + if (runtimeChunkModule.type === 'javascript/auto') { + const modulePath: string | undefined = (runtimeChunkModule as NormalModule)?.resource; + if (modulePath?.startsWith(resolvedLibInFolder) && modulePath.endsWith(JS_EXTENSION)) { + const modulePathWithoutExtension: string = modulePath.slice(0, -JS_EXTENSION.length); // Remove the .js extension + const relativePathWithoutExtension: string = Path.convertToSlashes( + path.relative(resolvedLibInFolder, modulePathWithoutExtension) + ); + + if (!pathsToIgnoreWithoutExtension.has(relativePathWithoutExtension)) { + if (!encounteredLibPaths.has(relativePathWithoutExtension)) { + libModules.push({ + libPathWithoutExtension: relativePathWithoutExtension, + moduleId: compilation.chunkGraph.getModuleId(runtimeChunkModule), + secondaryChunkId + }); + + encounteredLibPaths.add(relativePathWithoutExtension); + } + } + } + } + } + } + + for (const initialChunk of runtimeChunk.getAllInitialChunks()) { + processChunks(initialChunk, undefined); + } + + for (const secondaryChunk of runtimeChunk.getAllAsyncChunks()) { + if (secondaryChunk.id) { + processChunks(secondaryChunk, String(secondaryChunk.id)); + } + } + + libModulesByChunk.set(runtimeChunk, libModules); + } + + const resolvedLibOutFolder: string = path.join(compiler.context, this._outFolderName); + const outputPathRelativeLibOutFolder: string = Path.convertToSlashes( + path.relative(outputPath, resolvedLibOutFolder) + ); + + const resolvedDtsFilesInputFolderName: string | undefined = this._dTsFilesInputFolderName + ? path.join(compiler.context, this._dTsFilesInputFolderName) + : undefined; + + for (const [chunk, libModules] of libModulesByChunk) { + const bundleFilenames: string[] = Array.from(chunk.files); + let bundleJsFileBaseName: string | undefined; + for (const filename of bundleFilenames) { + if (filename.endsWith(JS_EXTENSION)) { + if (bundleJsFileBaseName) { + compilation.errors.push( + new WebpackError(`Multiple JS files were found for the ${chunk.name} chunk.`) + ); + return undefined; + } else { + bundleJsFileBaseName = filename.slice(0, -JS_EXTENSION.length); + } + } + } + + if (!bundleJsFileBaseName) { + compilation.errors.push( + new WebpackError(`The JS file for the ${chunk.name} chunk was not found.`) + ); + return; + } + + const jsFilePath: string = Path.convertToSlashes(path.join(outputPath!, bundleJsFileBaseName)); + const libOutFolderRelativeOutputPath: string = Path.convertToSlashes( + path.relative(resolvedLibOutFolder, jsFilePath) + ); + + await Async.forEachAsync( + libModules, + async ({ libPathWithoutExtension, moduleId, secondaryChunkId }) => { + const depth: number = countSlashes(libPathWithoutExtension); + const requirePath: string = '../'.repeat(depth) + libOutFolderRelativeOutputPath; + let moduleText: string; + if (secondaryChunkId) { + moduleText = [ + `const runtimeChunkRequire = require(${JSON.stringify(requirePath)});`, + `// Ensure the chunk containing the module is loaded`, + `runtimeChunkRequire.f.require(${JSON.stringify(secondaryChunkId)});`, + `module.exports = runtimeChunkRequire(${JSON.stringify(moduleId)});` + ].join('\n'); + } else { + moduleText = [ + `module.exports = require(${JSON.stringify(requirePath)})(${JSON.stringify(moduleId)});` + ].join('\n'); + } + + compilation.emitAsset( + `${outputPathRelativeLibOutFolder}/${libPathWithoutExtension}${JS_EXTENSION}`, + new compiler.webpack.sources.RawSource(moduleText) + ); + + if (resolvedDtsFilesInputFolderName) { + const dtsFilePath: string = path.join( + resolvedDtsFilesInputFolderName, + `${libPathWithoutExtension}${DTS_EXTENSION}` + ); + let dtsFileContents: string | undefined; + try { + dtsFileContents = ( + await LegacyAdapters.convertCallbackToPromise(inputFileSystem.readFile, dtsFilePath) + )?.toString(); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + if (dtsFileContents) { + compilation.emitAsset( + `${outputPathRelativeLibOutFolder}/${libPathWithoutExtension}${DTS_EXTENSION}`, + new compiler.webpack.sources.RawSource(dtsFileContents) + ); + + compilation.fileDependencies.add(dtsFilePath); + } + } + }, + { concurrency: 10 } + ); + } + }); + }); + } +} diff --git a/webpack/webpack-deep-imports-plugin/src/index.ts b/webpack/webpack-deep-imports-plugin/src/index.ts new file mode 100644 index 00000000000..310f8dc59ca --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/src/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 { DeepImportsPlugin, type IDeepImportsPluginOptions } from './DeepImportsPlugin'; diff --git a/webpack/webpack-deep-imports-plugin/tsconfig.json b/webpack/webpack-deep-imports-plugin/tsconfig.json new file mode 100644 index 00000000000..7902d0431ea --- /dev/null +++ b/webpack/webpack-deep-imports-plugin/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019" + } +} diff --git a/webpack/webpack-embedded-dependencies-plugin/.npmignore b/webpack/webpack-embedded-dependencies-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json new file mode 100644 index 00000000000..1fb9a1fe8d4 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.json @@ -0,0 +1,2685 @@ +{ + "name": "@rushstack/webpack-embedded-dependencies-plugin", + "entries": [ + { + "version": "0.3.7", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.7", + "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/webpack-plugin-utilities\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.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/webpack-plugin-utilities\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.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/webpack-plugin-utilities\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.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/webpack-plugin-utilities\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.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/webpack-plugin-utilities\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.3.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/webpack-plugin-utilities\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.2.111", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.111", + "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/webpack-plugin-utilities\" to `0.4.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.2.110", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.110", + "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/webpack-plugin-utilities\" to `0.4.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.2.109", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.109", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.2.108", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.108", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.2.107", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.107", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.2.106", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.106", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.2.105", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.105", + "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/webpack-plugin-utilities\" to `0.4.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.2.104", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.104", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.2.103", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.103", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.2.102", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.102", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.2.101", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.101", + "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/webpack-plugin-utilities\" to `0.4.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.2.100", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.100", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.2.99", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.99", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.2.98", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.98", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.2.97", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.97", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.2.96", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.96", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.2.95", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.95", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.2.94", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.94", + "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/webpack-plugin-utilities\" to `0.4.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.2.93", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.93", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.2.92", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.92", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.2.91", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.91", + "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/webpack-plugin-utilities\" to `0.4.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.2.90", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.90", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.2.89", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.89", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.2.88", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.88", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.2.87", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.87", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.2.86", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.86", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.2.85", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.85", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.2.84", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.84", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.2.83", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.83", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.2.82", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.82", + "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/webpack-plugin-utilities\" to `0.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.2.81", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.81", + "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/webpack-plugin-utilities\" to `0.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.2.80", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.80", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.2.79", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.79", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.2.78", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.78", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.2.77", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.77", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.2.76", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.76", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.2.75", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.75", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.2.74", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.74", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.2.73", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.73", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.2.72", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.72", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.2.71", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.71", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.2.70", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.70", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.2.69", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.69", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.2.68", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.68", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.2.67", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.67", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.2.66", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.66", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.2.65", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.65", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.2.64", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.64", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.2.63", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.63", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.2.62", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.62", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.2.61", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.61", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.2.60", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.60", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.2.59", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.59", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.2.58", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.58", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.2.57", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.57", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.2.56", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.56", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.2.55", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.55", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.2.54", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.54", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.2.53", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.53", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.2.52", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.52", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.2.51", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.51", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.2.50", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.50", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.2.49", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.49", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.2.48", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.48", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.2.47", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.47", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.2.46", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.46", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.2.45", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.45", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.2.44", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.44", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.2.43", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.43", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.2.42", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.42", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.2.41", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.41", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.2.40", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.2.39", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.39", + "date": "Fri, 15 Mar 2024 00:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.38", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.37", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.36", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.35", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.34", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.33", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.32", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.31", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.30", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.29", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.28", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.27", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.26", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.25", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.24", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.23", + "date": "Wed, 07 Feb 2024 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.22", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.21", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.20", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.19", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.18", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.17", + "date": "Fri, 12 Jan 2024 01:23:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.37", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.36", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.35", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.34", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.33", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.32", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.31", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.30", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.29", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.28", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.27", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.26", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.25", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.24", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.23", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.22", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.21", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.20", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.19", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.18", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.17", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.16", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.15", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.14", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.13", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.12", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.11", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.10", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.4", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.3", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.2", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.1", + "date": "Thu, 23 Mar 2023 15:24:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/webpack-embedded-dependencies-plugin_v0.1.0", + "date": "Wed, 22 Mar 2023 20:48:30 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce webpack-embedded-dependencies-plugin" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-plugin-utilities\" to `0.2.0`" + } + ] + } + } + ] +} diff --git a/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md new file mode 100644 index 00000000000..3e41e7ba19a --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md @@ -0,0 +1,814 @@ +# Change Log - @rushstack/webpack-embedded-dependencies-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.3.7 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.3.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.3.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.3.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.3.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.3.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.3.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.3.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.2.111 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.2.110 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.109 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.108 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.107 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.2.106 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.2.105 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.2.104 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.2.103 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.2.102 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.2.101 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.2.100 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.2.99 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.2.98 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.2.97 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.2.96 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.2.95 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.2.94 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.2.93 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.2.92 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.2.91 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.2.90 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.2.89 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.2.88 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.2.87 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.2.86 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.2.85 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.2.84 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.2.83 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.2.82 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.2.81 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.2.80 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.2.79 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.2.78 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.2.77 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.2.76 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.2.75 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.2.74 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.2.73 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.2.72 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.2.71 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.2.70 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 0.2.69 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.2.68 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.2.67 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.2.66 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.2.65 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.2.64 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.2.63 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.2.62 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.2.61 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.2.60 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.2.59 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.2.58 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.2.57 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.2.56 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.2.55 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.2.54 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.2.53 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.2.52 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.2.51 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.2.50 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.2.49 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.2.48 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.2.47 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.2.46 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.2.45 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.2.44 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.2.43 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.2.42 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.2.41 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.2.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.2.39 +Fri, 15 Mar 2024 00:12:41 GMT + +_Version update only_ + +## 0.2.38 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.2.37 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.2.36 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.2.35 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.2.34 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.2.33 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 0.2.32 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.2.31 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.2.30 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.2.29 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.2.28 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.2.27 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.2.26 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.2.25 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.2.24 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.2.23 +Wed, 07 Feb 2024 01:11:19 GMT + +_Version update only_ + +## 0.2.22 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.2.21 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.2.20 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.2.19 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.2.18 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.2.17 +Fri, 12 Jan 2024 01:23:10 GMT + +_Version update only_ + +## 0.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.2.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.2.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.2.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.2.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.2.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.2.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.2.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.2.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.1.37 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.1.36 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.1.35 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.1.34 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.1.33 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.1.32 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.1.31 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.30 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.1.29 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.1.28 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.1.27 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.1.26 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.1.25 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.1.24 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.1.23 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.1.22 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.1.21 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.1.20 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.1.19 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.1.18 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.1.17 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.1.16 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.1.15 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.1.14 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.1.13 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.1.12 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.1.11 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.1.10 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.1.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.1.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.1.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.1.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.1.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.1.4 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.1.3 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.1.2 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.1.1 +Thu, 23 Mar 2023 15:24:08 GMT + +_Version update only_ + +## 0.1.0 +Wed, 22 Mar 2023 20:48:30 GMT + +### Minor changes + +- Introduce webpack-embedded-dependencies-plugin + diff --git a/webpack/webpack-embedded-dependencies-plugin/README.md b/webpack/webpack-embedded-dependencies-plugin/README.md new file mode 100644 index 00000000000..f8d063611d6 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/README.md @@ -0,0 +1,127 @@ +# webpack-embedded-dependencies-plugin + +## Installation + +`npm install @rushstack/webpack-embedded-dependencies-plugin --save` + +## Overview + +A webpack plugin for generating a list of embedded dependencies. Embedded dependencies are third-party packages which are being +bundled into your released code and are oftentimes subject to license, security, and other legal requirements. This plugin +aims to make it easier to generate a list of embedded dependencies and their associated metadata, so they can be analyzed by additional tools. + +The plugin also includes the ability to generate a secondary asset which contains the license text for each embedded dependency into a single file called +THIRD-PARTY-NOTICES.html. This is a common legal requirement when deploying services or products containing open-source code. + +## Plugin + +```typescript +// webpack.config.js +import EmbeddedDependenciesWebpackPlugin from '@rushstack/webpack-embedded-dependencies-plugin'; + +export default () => { + /*...*/ + plugins: [ + new EmbeddedDependenciesWebpackPlugin( /* options */ ) + ] +} +``` + +## Options + +### `outputFileName`: `string` + +Name of the file to be generated. Defaults to embedded-dependencies.json + +```typescript +new EmbeddedDependenciesWebpackPlugin({ + outputFileName: 'my-custom-file-name.json' +}) +``` + +### `generateLicenseFile`: `boolean` + +Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file + +```typescript +new EmbeddedDependenciesWebpackPlugin({ + generateLicenseFile: true +}) +``` + +### `generateLicenseFileFunction`: `LicenseFileGeneratorFunction` + +Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it. + +```typescript +new EmbeddedDependenciesWebpackPlugin({ + generateLicenseFile: true, + generateLicenseFileFunction: (packages: IPackageData[]): string => { + return packages + .map((pkg) => { + return `

${pkg.name}

${pkg.license}

`; + }).join(''); + } +}) +``` + +### `generatedLicenseFilename`: `LicenseFileName` + +```typescript +new EmbeddedDependenciesWebpackPlugin({ + generateLicenseFile: true, + generatedLicenseFilename: 'custom-license-file-name.html' +}) +``` + +Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html but can be customized to any name you want. + +### `packageFilterPredicate`: `(packageJson: IPackageData, filePath: string) => boolean` + +Function that allows you to filter out packages that you don't want to include in any generated files. + +```typescript +new EmbeddedDependenciesWebpackPlugin({ + packageFilterPredicate: (packageJson: IPackageData, filePath: string): boolean => { + return packageJson.name !== 'my-package-to-exclude'; + } +}) +``` + +## Types + +### `LicenseFileGeneratorFunction` + +`export declare type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string;` + +Function type that generates the license file. + +```ts +const licenseFileGenerator: LicenseFileGeneratorFunction = (packages: IPackageData[]): string => { + return packages + .map((pkg) => { + return `

${pkg.name}

${pkg.license}

`; + }).join(''); +} +``` + +### `LicenseFileName` + +``export declare type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`;`` + +Loose string type that represents the name of the generated license file. The string must have at least one character and must end with one of the following file extensions: html, md, or txt or else you'll receive a TypeScript error. + +```ts +const licenseFileName: LicenseFileName = 'custom-license-file-name.html'; +const licenseMarkdownFileName: LicenseFileName = 'custom-license-file-name.md'; +const licenseTextFileName: LicenseFileName = 'custom-license-file-name.txt'; +``` + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/webpack-embedded-dependencies-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack-embedded-dependencies-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json b/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json new file mode 100644 index 00000000000..31010bc6261 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + }, + + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/webpack/webpack-embedded-dependencies-plugin/config/rig.json b/webpack/webpack-embedded-dependencies-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-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/webpack/webpack-embedded-dependencies-plugin/eslint.config.js b/webpack/webpack-embedded-dependencies-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-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/webpack/webpack-embedded-dependencies-plugin/package.json b/webpack/webpack-embedded-dependencies-plugin/package.json new file mode 100644 index 00000000000..5896ee344ee --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/package.json @@ -0,0 +1,38 @@ +{ + "name": "@rushstack/webpack-embedded-dependencies-plugin", + "version": "0.3.7", + "description": "This plugin analyzes bundled dependencies from Node Modules for use with Component Governance and License Scanning.", + "main": "lib/index.js", + "typings": "dist/webpack-embedded-dependencies-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack-embedded-dependencies-plugin" + }, + "scripts": { + "build": "heft build --clean", + "test": "heft run --only test", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + }, + "peerDependencies": { + "webpack": "^5.35.1" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + }, + "devDependencies": { + "@rushstack/webpack-plugin-utilities": "workspace:*", + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.98.0", + "memfs": "4.12.0" + } +} diff --git a/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts new file mode 100644 index 00000000000..4fac8ba3f23 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/EmbeddedDependenciesWebpackPlugin.ts @@ -0,0 +1,396 @@ +// 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 { Compiler, Compilation, WebpackPluginInstance, WebpackError, InputFileSystem } from 'webpack'; + +import { Async, Sort, LegacyAdapters, FileSystem } from '@rushstack/node-core-library'; +import type { IPackageJson } from '@rushstack/node-core-library'; + +import { LICENSE_FILES_REGEXP, COPYRIGHT_REGEX } from './regexpUtils'; + +const PLUGIN_NAME: 'EmbeddedDependenciesWebpackPlugin' = 'EmbeddedDependenciesWebpackPlugin'; +const PLUGIN_ERROR_PREFIX: string = '[embedded-dependencies-webpack-plugin]'; +const DEFAULT_GENERATED_LICENSE_FILE_NAME: 'THIRD-PARTY-NOTICES.html' = 'THIRD-PARTY-NOTICES.html'; +const DEFAULT_EMBEDDED_DEPENDENCIES_FILE_NAME: 'embedded-dependencies.json' = 'embedded-dependencies.json'; +const DEFAULT_PACKAGE_FILTER_FUNCTION: (packageJson: IPackageData, filePath: string) => boolean = () => true; + +interface IEmbeddedDependenciesFile { + name?: string; + version?: string; + embeddedDependencies: IPackageData[]; +} + +interface IResourceResolveData { + descriptionFileData?: IPackageData; + descriptionFileRoot?: string; + relativePath?: string; +} + +interface IWebpackModuleCreateData { + resourceResolveData?: IResourceResolveData; +} + +/** + * @beta + * Data type for a package.json file. This is a superset of the full package.json file and includes additional fields + * that are generated by the plugin, including licenseSource, licenses, copyright, and author. + */ +export interface IPackageData extends IPackageJson { + /** + * A small string subset which is used for copyright extraction from a licenseSource file. + */ + copyright: string | undefined; + /** + * The author of the package. This is a superset of the full package.json author field. + * Grabs either the author field or author.name field from package.json. + */ + author?: string | { name?: string }; + /** + * Additional license metadata if present. May contain information about a project which has multiple licenses. + */ + licenses?: { type: string; url: string }[]; + + /** + * The source of the license file itself used for generating THIRD-PARTY-NOTICES.html or custom license files. + */ + licenseSource?: string; +} + +/** + * @beta + * Plugin options for EmbeddedDependenciesWebpackPlugin + * + * @param outputFileName - Name of the file to be generated. Defaults to embedded-dependencies.json + * @param generateLicenseFile - Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file + * @param generateLicenseFileFunction - Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it + * @param generatedLicenseFilename - Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html + * + * @example + * ```ts + * // webpack.config.js + * plugins: [ + * new EmbeddedDependenciesWebpackPlugin({ + * outputFileName: 'custom-file-name.json', + * generateLicenseFile: true, + * generateLicenseFileFunction: (packages: IPackageData[]) => { + * return packages + * .map((pkg) => { + * return `

${pkg.name}

${pkg.license}

`; + * }).join(''); + * }, + * generatedLicenseFilename: 'custom-license-file-name.html' + * }) + * ] + * ``` + */ +export interface IEmbeddedDependenciesWebpackPluginOptions { + /** + * Name of the file to be generated. Defaults to embedded-dependencies.json + */ + outputFileName?: string; + /** + * Whether to generate a license file. Defaults to false and will only generate the embedded-dependencies.json file + */ + generateLicenseFile?: boolean; + /** + * Function that generates the license file. Defaults to the plugin's internal default generator function but allows you to override it + */ + generateLicenseFileFunction?: LicenseFileGeneratorFunction; + /** + * Name of the generated license file. Defaults to THIRD-PARTY-NOTICES.html + */ + generatedLicenseFilename?: LicenseFileName; + + /** + * Predicate function that determines whether a package should be included in the embedded + * dependencies file or the generated license file. + */ + packageFilterPredicate?: (packageJson: IPackageData, filePath: string) => boolean; +} + +/** + * @beta + * Function type that generates the license file. + * + * @example + * ```ts + * const licenseFileGenerator: LicenseFileGeneratorFunction = (packages: IPackageData[]): string => { + * return packages + * .map((pkg) => { + * return `

${pkg.name}

${pkg.license}

`; + * }).join(''); + * } + * ``` + */ +export type LicenseFileGeneratorFunction = (packages: IPackageData[]) => string; + +/** + * @beta + * Loose string type that represents the name of the generated license file. + * + * @example + * ```ts + * const licenseFileName: LicenseFileName = 'custom-license-file-name.html'; + * const licenseMarkdownFileName: LicenseFileName = 'custom-license-file-name.md'; + * const licenseTextFileName: LicenseFileName = 'custom-license-file-name.txt'; + * ``` + */ +export type LicenseFileName = `${string}.${'html' | 'md' | 'txt'}`; + +type PackageNameAndVersion = `${string}@${string}`; +type ThirdPartyPackageMap = Map< + PackageNameAndVersion, + { packageFolderPath: string; packageJsonData: IPackageData } +>; +type DefaultLicenseTemplate = `
${string}

${string}`; + +/** + * @beta + * Webpack plugin that generates a file with the list of embedded dependencies + * and their licenses. + */ +export default class EmbeddedDependenciesWebpackPlugin implements WebpackPluginInstance { + private readonly _outputFileName: string; + private readonly _generateLicenseFile: boolean; + private readonly _generateLicenseFileFunction: LicenseFileGeneratorFunction; + private readonly _generatedLicenseFilename: LicenseFileName; + private readonly _packageFilterFunction: (packageJson: IPackageData, filePath: string) => boolean; + + public constructor(options?: IEmbeddedDependenciesWebpackPluginOptions) { + this._outputFileName = options?.outputFileName || DEFAULT_EMBEDDED_DEPENDENCIES_FILE_NAME; + this._generateLicenseFile = options?.generateLicenseFile || false; + this._generateLicenseFileFunction = + options?.generateLicenseFileFunction || this._defaultLicenseFileGenerator; + this._generatedLicenseFilename = options?.generatedLicenseFilename || DEFAULT_GENERATED_LICENSE_FILE_NAME; + this._packageFilterFunction = options?.packageFilterPredicate || DEFAULT_PACKAGE_FILTER_FUNCTION; + } + + /** + * @beta + * Webpack plugin apply method. This method is called by the webpack compiler to apply the plugin, however it not usually + * needed to be invoked manually by the developer in a webpack configuration. However, if you are calling this plugin (applying it from another plugin) + * you can call `plugin.apply(compiler)` to apply the plugin and invoke it. + * @param compiler - The webpack compiler instance. + */ + public apply(compiler: Compiler): void { + const { sources, Compilation } = compiler.webpack; + // Tap into compilation so we can tap into compilation.hooks.processAssets + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => { + const thirdPartyPackages: ThirdPartyPackageMap = new Map(); + + normalModuleFactory.hooks.module.tap( + PLUGIN_NAME, + (module, moduleCreateData: IWebpackModuleCreateData, resolveData) => { + const { resourceResolveData } = moduleCreateData; + const pkg: IPackageData | undefined = resourceResolveData?.descriptionFileData; + const filePath: string | undefined = resourceResolveData?.descriptionFileRoot; + + if ( + pkg && + filePath && + this._packageFilterFunction(pkg, filePath) && + filePath?.includes('node_modules') + ) { + const key: PackageNameAndVersion = makePackageMapKeyForPackage(pkg); + thirdPartyPackages.set(key, { packageFolderPath: filePath, packageJsonData: pkg }); + } + + return module; + } + ); + + compilation.hooks.processAssets.tapPromise( + { name: PLUGIN_NAME, stage: Compilation.PROCESS_ASSETS_STAGE_REPORT }, + async (assets) => { + const packages: IPackageData[] = []; + + try { + await Async.forEachAsync( + thirdPartyPackages, + async ([, { packageFolderPath: dir, packageJsonData: data }]) => { + const { name, version } = data; + let licenseSource: string | undefined; + const license: string | undefined = parseLicense(data); + const licensePath: string | undefined = await this._getLicenseFilePathAsync(dir, compiler); + if (licensePath) { + licenseSource = await FileSystem.readFileAsync(licensePath); + + const copyright: string | undefined = + this._parseCopyright(licenseSource) || parsePackageAuthor(data); + + packages.push({ + name, + version, + license, + licenseSource, + copyright + }); + } else { + // If there is no license file path, we still should populate the other required fields + const copyright: string | undefined = parsePackageAuthor(data); + + packages.push({ + name, + version, + license, + copyright + }); + } + } + ); + } catch (error) { + this._emitWebpackError(compilation, 'Failed to process embedded dependencies', error); + } finally { + Sort.sortBy(packages, (pkg) => pkg.name); + } + + const dataToStringify: IEmbeddedDependenciesFile = { + embeddedDependencies: packages + }; + + compilation.emitAsset(this._outputFileName, new sources.RawSource(JSON.stringify(dataToStringify))); + + if (this._generateLicenseFile) { + // We should try catch here because generator function can be output from user config + try { + compilation.emitAsset( + this._generatedLicenseFilename, + new sources.RawSource(this._generateLicenseFileFunction(packages)) + ); + } catch (error: unknown) { + this._emitWebpackError(compilation, 'Failed to generate license file', error); + } + } + + return; + } + ); + }); + } + + /** + * Default error handler for try/catch blocks in the plugin + * try/catches emit errors of type `unknown` and we need to handle them based on what + * type the error is. This function provides a convenient way to handle errors and then + * propagate them to webpack as WebpackError objects on `compilation.errors` array. + * + * @remarks + * _If we need to push errors to `compilation.warnings` array, we should just create a companion function + * that does the same thing but pushes to `compilation.warnings` array instead._ + * + * @example + * ```typescript + * try { + * // do some operation + * FileSystem.readFile('some-file'); + * } catch (error: unknown) { + * this._emitWebpackError(compilation, 'Failed to do some operation', error); + * } + * ``` + */ + private _emitWebpackError(compilation: Compilation, errorMessage: string, error: unknown): void { + let emittedError: WebpackError; + const { WebpackError } = compilation.compiler.webpack; + // If the error is a string, we can just emit it as is with message prefix and error message + if (typeof error === 'string') { + emittedError = new WebpackError(`${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${error}`); + // If error is an instance of Error, we can emit it with message prefix, error message and stack trace + } else if (error instanceof Error) { + emittedError = new WebpackError( + `${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${error.message}\n${error.stack || ''}` + ); + // If error is not a string or an instance of Error, we can emit it with message prefix and error message and JSON.stringify it + } else { + emittedError = new WebpackError( + `${PLUGIN_ERROR_PREFIX}: ${errorMessage}: ${JSON.stringify(error || '')}` + ); + } + + compilation.errors.push(emittedError); + } + + /** + * Searches a third party package directory for a license file. + */ + private async _getLicenseFilePathAsync( + modulePath: string, + compiler: Compiler + ): Promise { + type InputFileSystemReadDirResults = Parameters[2]>[1]; + + const { inputFileSystem } = compiler; + if (!inputFileSystem) { + throw new Error(`Compiler.inputFileSystem is not defined`); + } + + const files: InputFileSystemReadDirResults = await LegacyAdapters.convertCallbackToPromise( + inputFileSystem.readdir, + modulePath, + { withFileTypes: true } + ); + + if (!files) { + return; + } + + for (const file of files) { + if (file.isFile() && LICENSE_FILES_REGEXP.test(file.name)) { + // Grabbing the first license file if multiple are found + return path.join(modulePath, file.name); + } + } + } + + /** + * Given a module path, try to parse the module's copyright attribution. + */ + private _parseCopyright(licenseSource: string): string | undefined { + const match: RegExpMatchArray | null = licenseSource.match(COPYRIGHT_REGEX); + + if (match) { + return match[0]; + } + + return undefined; + } + + private _defaultLicenseFileGenerator(packages: IPackageData[]): string { + const licenseContent = (pkg: IPackageData): string => + pkg.licenseSource || pkg.copyright || 'License or Copyright not found'; + + const licenseTemplateForPackage = (pkg: IPackageData): DefaultLicenseTemplate => { + return `
${pkg.name} - ${pkg.version}

${licenseContent(pkg)}`; + }; + + return packages.map(licenseTemplateForPackage).join('\n'); + } +} + +function makePackageMapKeyForPackage(pkg: IPackageData): PackageNameAndVersion { + return `${pkg.name}@${pkg.version}`; +} + +/** + * Returns the license type + */ +function parseLicense(packageData: IPackageData): string | undefined { + if (packageData.license) { + return packageData.license; + } else if (typeof packageData.licenses === 'string') { + return packageData.licenses; + } else if (packageData.licenses?.length) { + return packageData.licenses.length === 1 + ? packageData.licenses[0].type + : `(${packageData.licenses + .map((license: { type: string; url: string }) => license.type) + .join(' OR ')})`; + } + + return undefined; +} + +function parsePackageAuthor(p: IPackageData): string | undefined { + return typeof p.author === 'string' ? p.author : p.author?.name; +} diff --git a/webpack/webpack-embedded-dependencies-plugin/src/index.ts b/webpack/webpack-embedded-dependencies-plugin/src/index.ts new file mode 100644 index 00000000000..db7fe20598d --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/index.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * A webpack plugin for generating a list of embedded dependencies. Embedded dependencies are third-party packages which are being + * bundled into your released code and are often times subject to license, security, and other legal requirements. This plugin + * aims to make it easier to generate a list of embedded dependencies and their associated metadata, so they can be analyzed by additional tools. + * + * @remarks + * The plugin also includes the ability to generate a secondary asset which contains the license text for each embedded dependency into a single file called + * THIRD-PARTY-NOTICES.html. This is a common legal requirement for large companies deploying commercial services/products containing open source code. + * + * @packageDocumentation + */ + +import EmbeddedDependenciesWebpackPlugin from './EmbeddedDependenciesWebpackPlugin'; +export * from './EmbeddedDependenciesWebpackPlugin'; + +export default EmbeddedDependenciesWebpackPlugin; diff --git a/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.ts b/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.ts new file mode 100644 index 00000000000..5739b911425 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/regexpUtils.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. + +/** + * Regular expression used to match common license file names. + * + * @remarks The following file names are covered via unit tests to be matched: + * + * - `'LICENSE'` + * - `'LICENSE.txt'` + * - `'LICENSE.md'` + * - `'LICENSE-MIT.txt'` + * - `'license'` + * - `'license.txt'` + */ +export const LICENSE_FILES_REGEXP: RegExp = /^LICENSE(-[A-Z-]+)?(\.(txt|md))?$/i; + +/** + * Regular expression used to match common copyright statements. It is by no means exhaustive however it + * should cover the majority of cases that we come across in the wild. + * + * @remarks The following copyright statements are covered via unit tests to be matched: + * + * - `'Copyright © 2023 FAKE-PACKAGE-MIT-LICENSE'` + * - `'Copyright (C) 2007 Free Software Foundation, Inc. '` + * - `'Copyright 2023 Some Licenser Name'` + * + */ +export const COPYRIGHT_REGEX: RegExp = /Copyright\s*(\(c\)|©)?\s*\d{4}\s*.*$/im; diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore b/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore new file mode 100644 index 00000000000..1b9396ec719 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/.gitignore @@ -0,0 +1,3 @@ +!node_modules +!dist +!lib \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts b/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts new file mode 100644 index 00000000000..f867f8434e5 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/WebpackEmbeddedDependenciesPlugin.test.ts @@ -0,0 +1,266 @@ +// 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 { createFsFromVolume, type IFs, Volume } from 'memfs'; +import EmbeddedDependenciesWebpackPlugin from '../EmbeddedDependenciesWebpackPlugin'; + +import { LICENSE_FILES_REGEXP, COPYRIGHT_REGEX } from '../regexpUtils'; + +import { Testing } from '@rushstack/webpack-plugin-utilities'; +import { FileSystem } from '@rushstack/node-core-library'; + +const TESTS_FOLDER_PATH: string = `${process.cwd()}/src/test`; +const FIXTURES_FOLDER_PATH: string = `${TESTS_FOLDER_PATH}/fixtures`; +const FAKE_NODE_MODULES_FOLDER_PATH: string = `${TESTS_FOLDER_PATH}/node_modules`; +const VIRTUAL_FILE_SYSTEM_OUTPUT_PATH: string = path.resolve( + process.cwd(), + '../webpack-embedded-dependencies-plugin/dist' +); + +const fixtures: string[] = FileSystem.readFolderItemNames(FIXTURES_FOLDER_PATH); + +const defaultConfigurationWithPlugin = { + context: TESTS_FOLDER_PATH, + plugins: [new EmbeddedDependenciesWebpackPlugin()] +}; + +const defaultConfigurationCustomOutputFileName = { + context: TESTS_FOLDER_PATH, + plugins: [new EmbeddedDependenciesWebpackPlugin({ outputFileName: 'custom-file-name.json' })] +}; + +const configurationWithLicenseFileGenerated = { + context: TESTS_FOLDER_PATH, + plugins: [new EmbeddedDependenciesWebpackPlugin({ generateLicenseFile: true })] +}; + +const configurationWithLicenseFileGeneratedAndCustomPackageFilter = { + context: TESTS_FOLDER_PATH, + plugins: [ + new EmbeddedDependenciesWebpackPlugin({ + generateLicenseFile: true, + packageFilterPredicate: (packageJson, filePath) => { + return !filePath.includes('some-fake-custom-package'); + } + }) + ] +}; + +describe('COPYRIGHT_REGEX', () => { + it('should extract the right copyright from apache 2.0 license', () => { + const license = FileSystem.readFile( + path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-apache-with-copyleft-dep', 'LICENSE.txt') + ); + const match = license.match(COPYRIGHT_REGEX); + + expect(match).toBeDefined(); + expect(match?.[0]).toBe('Copyright 2023 Fake Package Apache License w/ AGPL Transitive'); + }); + + it('should extract the right copyright from mit license', () => { + const license = FileSystem.readFile( + path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-mit-license', 'LICENSE-MIT.txt') + ); + const match = license.match(COPYRIGHT_REGEX); + + expect(match).toBeDefined(); + expect(match?.[0]).toBe('Copyright © 2023 FAKE-PACKAGE-MIT-LICENSE'); + }); + + it('should extract the right copyright from agpl license', () => { + const license = FileSystem.readFile( + path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-agpl-license', 'LICENSE') + ); + const match = license.match(COPYRIGHT_REGEX); + + expect(match).toBeDefined(); + expect(match?.[0]).toBe('Copyright (C) 2007 Free Software Foundation, Inc. '); + }); + + it('should extract the right copyright from agpl license', () => { + const license = FileSystem.readFile( + path.join(FAKE_NODE_MODULES_FOLDER_PATH, 'fake-package-copyleft-license', 'license') + ); + const match = license.match(COPYRIGHT_REGEX); + + expect(match).toBeDefined(); + expect(match?.[0]).toBe('Copyright (C) 2007 Free Software Foundation, Inc. '); + }); +}); + +describe('LICENSE_FILES_REGEXP', () => { + for (const filename of ['LICENSE', 'LICENSE-MIT.txt', 'LICENSE.md', 'LICENSE.txt', 'license']) { + it(`should match ${filename}`, () => { + expect(LICENSE_FILES_REGEXP.test(filename)).toBe(true); + }); + } +}); + +for (const fixture of fixtures) { + describe('WebpackEmbeddedDependenciesPlugin', () => { + it('should run', async () => { + const stats = await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + defaultConfigurationWithPlugin + ); + + expect(stats).toBeDefined(); + }); + + it('should generate a secondary asset with the correct default name', async () => { + const stats = await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + defaultConfigurationWithPlugin + ); + const embeddedDepAsset = stats + ?.toJson({ all: false, assets: true }) + .assets?.some((asset) => asset.name === 'embedded-dependencies.json'); + + expect(embeddedDepAsset).toBe(true); + }); + + it('should generate a secondary asset with a custom outputFileName', async () => { + const stats = await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + defaultConfigurationCustomOutputFileName + ); + const embeddedDepAsset = stats + ?.toJson({ all: false, assets: true }) + .assets?.some((asset) => asset.name === 'custom-file-name.json'); + + expect(embeddedDepAsset).toBe(true); + }); + + it('should generate a tertiary asset if generating a license file', async () => { + const stats = await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + configurationWithLicenseFileGenerated + ); + const embeddedDepAsset = stats + ?.toJson({ all: false, assets: true }) + .assets?.some((asset) => asset.name === 'THIRD-PARTY-NOTICES.html'); + + // No dependencies fixture should not generate a license file + // and emit a warning so we'll exclude it here, but also should test separately + if (fixture !== 'no-dependencies') { + expect(embeddedDepAsset).toBe(true); + } + }); + }); + + const virtualFileSystem: IFs = createFsFromVolume(new Volume()); + + switch (fixture) { + case 'dependencies-with-copyleft-licenses': + break; + case 'dependencies-with-licenses': + break; + case 'dependencies-with-transient-copyleft-license': + it('should have three files created when using the generator from the entire build with correct default names and the licenses have been correctly detected', async () => { + // For this test we'll create the virtual file system and pass it to the Testing.getTestingWebpackCompilerAsync + // because we want to reuse it to verify the files generated by the plugin + + await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + configurationWithLicenseFileGenerated, + virtualFileSystem + ); + + // get files generated from the plugin in the virtual file system + const files = virtualFileSystem.readdirSync(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH); + + expect(files).toBeDefined(); + expect(files.length).toBe(3); + // verify the name of each file is correct + expect(files).toContain('embedded-dependencies.json'); + expect(files).toContain('THIRD-PARTY-NOTICES.html'); + expect(files).toContain('test-bundle.js'); + + for (const file of files) { + const fileContent = virtualFileSystem.readFileSync( + path.join(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH, file.toString()), + { + encoding: 'utf8' + } + ); + + switch (file) { + case 'THIRD-PARTY-NOTICES.html': + expect(fileContent).toContain('Apache License'); + break; + case 'embedded-dependencies.json': + const json = JSON.parse(fileContent.toString()); + expect(json).toBeDefined(); + expect(json.embeddedDependencies).toBeDefined(); + expect(json.embeddedDependencies.length).toBe(2); + expect(json.embeddedDependencies[0].name).toBe('fake-package-apache-with-copyleft-dep'); + expect(json.embeddedDependencies[0].version).toBe('1.3.4'); + break; + default: + break; + } + + expect(fileContent).toBeDefined(); + } + }); + break; + case 'no-dependencies': + it('should not emit a warning if there are no third party deps but license generation is set to true', async () => { + const stats = await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + configurationWithLicenseFileGenerated + ); + + const warnings = stats?.toJson({ all: false, warnings: true }).warnings; + + expect(warnings).toBeDefined(); + expect(warnings?.length).toBe(0); + }); + + break; + + case 'dependencies-with-dependency-to-filter-out': + it('should filter out specific packages using a package filter function option', async () => { + // For this test we'll create the virtual file system and pass it to the Testing.getTestingWebpackCompilerAsync + // because we want to reuse it to verify the files generated by the plugin + + await Testing.getTestingWebpackCompilerAsync( + `./fixtures/${fixture}/src`, + configurationWithLicenseFileGeneratedAndCustomPackageFilter, + virtualFileSystem + ); + + // get files generated from the plugin in the virtual file system + const files = virtualFileSystem.readdirSync(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH); + + expect(files).toBeDefined(); + expect(files.length).toBe(3); + // verify the name of each file is correct + expect(files).toContain('embedded-dependencies.json'); + expect(files).toContain('THIRD-PARTY-NOTICES.html'); + expect(files).toContain('test-bundle.js'); + + for (const file of files) { + const fileContent = virtualFileSystem.readFileSync( + path.join(VIRTUAL_FILE_SYSTEM_OUTPUT_PATH, file.toString()), + { + encoding: 'utf8' + } + ); + + if (file.toString() === 'embedded-dependencies.json') { + const { embeddedDependencies } = JSON.parse(fileContent.toString()); + expect(embeddedDependencies[0].name).not.toBe('some-fake-custom-package'); + expect(embeddedDependencies).toBeDefined(); + } + + expect(fileContent).toBeDefined(); + } + }); + + break; + default: + break; + } +} diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js new file mode 100644 index 00000000000..bf18de462b9 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-copyleft-licenses/src/index.js @@ -0,0 +1,3 @@ +import mod from 'fake-package-copyleft-license'; + +console.log(mod); diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js new file mode 100644 index 00000000000..aa334daaad9 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-dependency-to-filter-out/src/index.js @@ -0,0 +1,4 @@ +import mod from 'fake-package-mit-license'; +import * as fakeNamespace from 'some-fake-custom-package'; + +console.log(pattern1, fakeNamespace); diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js new file mode 100644 index 00000000000..488fe2fdb42 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-licenses/src/index.js @@ -0,0 +1 @@ +import mod from 'fake-package-mit-license'; diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js new file mode 100644 index 00000000000..a02abbea8dd --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/dependencies-with-transient-copyleft-license/src/index.js @@ -0,0 +1,3 @@ +import mod from 'fake-package-apache-with-copyleft-dep'; + +console.log(mod); diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js new file mode 100644 index 00000000000..668268e602d --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-a.js @@ -0,0 +1 @@ +export default 'file-a'; diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js new file mode 100644 index 00000000000..15118154ccb --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/file-b.js @@ -0,0 +1 @@ +export default 'file-b'; diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js new file mode 100644 index 00000000000..f7e2705754b --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/fixtures/no-dependencies/src/index.js @@ -0,0 +1,4 @@ +import fileA from './file-a'; +import fileB from './file-b'; + +document.write(`${fileA} + ${fileB}`); diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE new file mode 100644 index 00000000000..be3f7b28e56 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js new file mode 100644 index 00000000000..1342bcda23b --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/lib/index.js @@ -0,0 +1 @@ +export default "THIS HAS A COPYLEFT LICENSE"; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json new file mode 100644 index 00000000000..a276468db41 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-agpl-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "fake-package-apgl-license", + "version": "1.0.0", + "license": "AGPL", + "main": "./lib" +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt new file mode 100644 index 00000000000..1a638f265e2 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Fake Package Apache License w/ AGPL Transitive + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js new file mode 100644 index 00000000000..1e55461856b --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/lib/index.js @@ -0,0 +1,3 @@ +import copyLeftCode from "fake-package-agpl-license" + +export default `THIS PACKAGE HAS APACHE LICENSE BUT ${copyLeftCode}` \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json new file mode 100644 index 00000000000..65d3380e0a8 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-apache-with-copyleft-dep/package.json @@ -0,0 +1,9 @@ +{ + "name": "fake-package-apache-with-copyleft-dep", + "module": "./lib/index.js", + "version": "1.3.4", + "license": "Apache-2.0", + "dependencies": { + "fake-package-agpl-license": "1.0.0" + } +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js new file mode 100644 index 00000000000..1342bcda23b --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/lib/index.js @@ -0,0 +1 @@ +export default "THIS HAS A COPYLEFT LICENSE"; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license new file mode 100644 index 00000000000..a824e194d8e --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/license @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 2014 Fake Package Maker + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Fake Package Copyleft License Copyright (C) 2014 Fake Package Maker + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and`show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json new file mode 100644 index 00000000000..513dcb29e81 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-copyleft-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "fake-package-copyleft-license", + "version": "1.0.0", + "license": "GPL", + "main": "./lib" +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt new file mode 100644 index 00000000000..ab23bff8de5 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/LICENSE-MIT.txt @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright © 2023 FAKE-PACKAGE-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/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js new file mode 100644 index 00000000000..fc0fff7f6b5 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/lib/index.js @@ -0,0 +1 @@ +export default "THIS IS A MODULE WITH MIT LICENSE" \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json new file mode 100644 index 00000000000..c5e6bc25799 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mit-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "fake-package-good-license", + "module": "./lib/index.js", + "version": "1.1.1", + "license": "MIT" +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js new file mode 100644 index 00000000000..1342bcda23b --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/lib/index.js @@ -0,0 +1 @@ +export default "THIS HAS A COPYLEFT LICENSE"; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json new file mode 100644 index 00000000000..05dc8db0933 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/fake-package-mpl-license/package.json @@ -0,0 +1,6 @@ +{ + "name": "fake-package-mpl-license", + "version": "1.0.0", + "license": "MPL", + "main": "./lib" +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js new file mode 100644 index 00000000000..8f99fabc3a2 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/1.js @@ -0,0 +1 @@ +module.exports = module.id; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js new file mode 100644 index 00000000000..8f99fabc3a2 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/2.js @@ -0,0 +1 @@ +module.exports = module.id; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js new file mode 100644 index 00000000000..d1ed864551f --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/lib/index.js @@ -0,0 +1,2 @@ +export * from "./1.js"; +export * from "./2.js"; \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json new file mode 100644 index 00000000000..4f5cfb2e0a7 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/src/test/node_modules/some-fake-custom-package/package.json @@ -0,0 +1,6 @@ +{ + "name": "some-fake-custom-package", + "version": "1.0.0", + "description": "some fake custom package", + "main": "lib/index.js" +} \ No newline at end of file diff --git a/webpack/webpack-embedded-dependencies-plugin/tsconfig.json b/webpack/webpack-embedded-dependencies-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/webpack/webpack-embedded-dependencies-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/webpack-plugin-utilities/.npmignore b/webpack/webpack-plugin-utilities/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack-plugin-utilities/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack-plugin-utilities/CHANGELOG.json b/webpack/webpack-plugin-utilities/CHANGELOG.json new file mode 100644 index 00000000000..afbad19cdc5 --- /dev/null +++ b/webpack/webpack-plugin-utilities/CHANGELOG.json @@ -0,0 +1,2921 @@ +{ + "name": "@rushstack/webpack-plugin-utilities", + "entries": [ + { + "version": "0.5.7", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.7", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/webpack-plugin-utilities_v0.5.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/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.4.94", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.94", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.4.93", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.93", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.4.92", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.92", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.4.91", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.91", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.4.90", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.90", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.4.89", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.89", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.4.88", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.88", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.4.87", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.87", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.4.86", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.86", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.4.85", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.85", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.4.84", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.84", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.4.83", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.83", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.4.82", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.82", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.4.81", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.81", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.4.80", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.80", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.4.79", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.79", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.4.78", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.78", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.4.77", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.77", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.4.76", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.76", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.4.75", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.75", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.4.74", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.74", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.4.73", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.73", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.4.72", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.72", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.4.71", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.71", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.4.70", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.70", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.4.69", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.69", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.4.68", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.68", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.4.67", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.67", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.4.66", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.66", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.4.65", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.65", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.4.64", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.64", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.4.63", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.63", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.4.62", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.62", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.4.61", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.61", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.4.60", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.60", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.4.59", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.59", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.4.58", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.58", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.4.57", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.57", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.4.56", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.56", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.4.55", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.55", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.4.54", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.54", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.4.53", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.53", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.4.52", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.52", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.4.51", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.51", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.4.50", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.50", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.4.49", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.49", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.4.48", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.48", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.4.47", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.47", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.4.46", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.46", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.4.45", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.45", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.4.44", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.44", + "date": "Wed, 24 Jul 2024 00:12:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.4.43", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.43", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.4.42", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.42", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.4.41", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.41", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.4.40", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.40", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.4.39", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.39", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.4.38", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.38", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.4.37", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.37", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.36", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.35", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.34", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.33", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.32", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.31", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.30", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.29", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.28", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.27", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.26", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.25", + "date": "Mon, 06 May 2024 15:11:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.24", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.23", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.22", + "date": "Fri, 15 Mar 2024 00:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.21", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.20", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.19", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.18", + "date": "Fri, 01 Mar 2024 01:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.17", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.16", + "date": "Wed, 28 Feb 2024 16:09:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.15", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.14", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.13", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.12", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.11", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.10", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.9", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.8", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.7", + "date": "Thu, 08 Feb 2024 01:09:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.6", + "date": "Wed, 07 Feb 2024 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.5", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.3", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.2", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.1", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/webpack-plugin-utilities_v0.4.0", + "date": "Fri, 12 Jan 2024 01:23:10 GMT", + "comments": { + "minor": [ + { + "comment": "Expand the peer dependency specifier on Webpack to allow both Webpack 4 and Webpack 5." + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.5", + "date": "Tue, 26 Sep 2023 21:02:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/webpack-plugin-utilities_v0.3.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.37", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.36", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.35", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.34", + "date": "Thu, 20 Jul 2023 20:47:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.33", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.32", + "date": "Fri, 14 Jul 2023 15:20:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.31", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.30", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.29", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.28", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.27", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.26", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.25", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.24", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.23", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.22", + "date": "Tue, 13 Jun 2023 15:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.21", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.20", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.19", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.18", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.17", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.16", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.15", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.14", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.13", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.12", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.11", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.10", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.9", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.8", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.7", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.6", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.5", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.4", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.3", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.2", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.1", + "date": "Thu, 23 Mar 2023 15:24:08 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `Testing` library has a had a hard dependency on `webpack`, but the package declared it as an optional peerDependency." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/webpack-plugin-utilities_v0.2.0", + "date": "Wed, 22 Mar 2023 20:48:30 GMT", + "comments": { + "minor": [ + { + "comment": "Added Testing.getTestingWebpackCompiler utility function for webpack plugin testing." + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.57", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.56", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.55", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.54", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.53", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.52", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.51", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.50", + "date": "Wed, 25 Jan 2023 07:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.49", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.48", + "date": "Tue, 20 Dec 2022 01:18:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.47", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.46", + "date": "Tue, 29 Nov 2022 01:16:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.45", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.44", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.43", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.42", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.41", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.40", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.39", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.38", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.37", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.36", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.35", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.34", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.33", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.32", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.31", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.30", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.29", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.28", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.27", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.26", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.25", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.24", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.23", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.22", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.21", + "date": "Thu, 21 Jul 2022 23:30:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.20", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.19", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.18", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.17", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.16", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.15", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.14", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.13", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.12", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.11", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.10", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.9", + "date": "Thu, 23 Jun 2022 22:14:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.8", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.7", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.6", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.5", + "date": "Wed, 25 May 2022 22:25:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.4", + "date": "Thu, 19 May 2022 15:13:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.3", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.2", + "date": "Tue, 10 May 2022 01:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.1", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/webpack-plugin-utilities_v0.1.0", + "date": "Wed, 27 Apr 2022 01:19:20 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release." + } + ] + } + } + ] +} diff --git a/webpack/webpack-plugin-utilities/CHANGELOG.md b/webpack/webpack-plugin-utilities/CHANGELOG.md new file mode 100644 index 00000000000..0d6b06fd06e --- /dev/null +++ b/webpack/webpack-plugin-utilities/CHANGELOG.md @@ -0,0 +1,1112 @@ +# Change Log - @rushstack/webpack-plugin-utilities + +This log was last generated on Sat, 06 Dec 2025 01:12:29 GMT and should not be manually modified. + +## 0.5.7 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.5.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.5.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.5.4 +Tue, 04 Nov 2025 08:15:15 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:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.4.94 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.4.93 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.4.92 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.4.91 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.4.90 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.4.89 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.4.88 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.4.87 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.4.86 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.4.85 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.4.84 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.4.83 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.82 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.4.81 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.4.80 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.4.79 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.4.78 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.4.77 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.4.76 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.4.75 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.74 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.4.73 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.4.72 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.4.71 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.4.70 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.4.69 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.4.68 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.4.67 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.4.66 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.4.65 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.4.64 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.4.63 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.4.62 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.4.61 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.4.60 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.4.59 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.4.58 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.4.57 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.4.56 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.4.55 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.4.54 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 0.4.53 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 0.4.52 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.4.51 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.4.50 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.4.49 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.4.48 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.4.47 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.4.46 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.4.45 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.4.44 +Wed, 24 Jul 2024 00:12:15 GMT + +_Version update only_ + +## 0.4.43 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.4.42 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.4.41 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.4.40 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.4.39 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.4.38 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.4.37 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.4.36 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.4.35 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.34 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.4.33 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 0.4.32 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.4.31 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.4.30 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.4.29 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.4.28 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.4.27 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.4.26 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.4.25 +Mon, 06 May 2024 15:11:05 GMT + +_Version update only_ + +## 0.4.24 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.4.23 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.4.22 +Fri, 15 Mar 2024 00:12:41 GMT + +_Version update only_ + +## 0.4.21 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.4.20 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.4.19 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.4.18 +Fri, 01 Mar 2024 01:10:09 GMT + +_Version update only_ + +## 0.4.17 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.4.16 +Wed, 28 Feb 2024 16:09:28 GMT + +_Version update only_ + +## 0.4.15 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.4.14 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.4.13 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.4.12 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.4.11 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.4.10 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.4.9 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.4.8 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.4.7 +Thu, 08 Feb 2024 01:09:22 GMT + +_Version update only_ + +## 0.4.6 +Wed, 07 Feb 2024 01:11:19 GMT + +_Version update only_ + +## 0.4.5 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.4.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.4.3 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.4.2 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.4.1 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.4.0 +Fri, 12 Jan 2024 01:23:10 GMT + +### Minor changes + +- Expand the peer dependency specifier on Webpack to allow both Webpack 4 and Webpack 5. + +## 0.3.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.3.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.3.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.3.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.3.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.3.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.3.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.3.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.3.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.3.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.3.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 0.3.5 +Tue, 26 Sep 2023 21:02:31 GMT + +_Version update only_ + +## 0.3.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.3.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.3.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.3.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.3.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.2.37 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.2.36 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.2.35 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.2.34 +Thu, 20 Jul 2023 20:47:29 GMT + +_Version update only_ + +## 0.2.33 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.2.32 +Fri, 14 Jul 2023 15:20:46 GMT + +_Version update only_ + +## 0.2.31 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.2.30 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.2.29 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.2.28 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.2.27 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.2.26 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.2.25 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.2.24 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.2.23 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.2.22 +Tue, 13 Jun 2023 15:17:21 GMT + +_Version update only_ + +## 0.2.21 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.2.20 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.2.19 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.2.18 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.2.17 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.2.16 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.2.15 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.2.14 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.2.13 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.2.12 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.2.11 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.2.10 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.2.9 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.2.8 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.2.7 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.2.6 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.2.5 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.2.4 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.2.3 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.2.2 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.2.1 +Thu, 23 Mar 2023 15:24:08 GMT + +### Patches + +- Fix an issue where the `Testing` library has a had a hard dependency on `webpack`, but the package declared it as an optional peerDependency. + +## 0.2.0 +Wed, 22 Mar 2023 20:48:30 GMT + +### Minor changes + +- Added Testing.getTestingWebpackCompiler utility function for webpack plugin testing. + +## 0.1.57 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.1.56 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.1.55 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.1.54 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.1.53 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.52 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.51 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.1.50 +Wed, 25 Jan 2023 07:26:56 GMT + +_Version update only_ + +## 0.1.49 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.48 +Tue, 20 Dec 2022 01:18:23 GMT + +_Version update only_ + +## 0.1.47 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.46 +Tue, 29 Nov 2022 01:16:50 GMT + +_Version update only_ + +## 0.1.45 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.44 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.43 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.42 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.41 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.40 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.39 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.38 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.37 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.36 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.35 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.34 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.1.33 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.32 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.31 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.30 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.29 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.28 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.27 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.26 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.1.25 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.24 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.23 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.22 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.21 +Thu, 21 Jul 2022 23:30:28 GMT + +_Version update only_ + +## 0.1.20 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.19 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.18 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.17 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.16 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.15 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.1.14 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.13 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.12 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.11 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.10 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.9 +Thu, 23 Jun 2022 22:14:25 GMT + +_Version update only_ + +## 0.1.8 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.1.7 +Fri, 17 Jun 2022 00:16:18 GMT + +_Version update only_ + +## 0.1.6 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.1.5 +Wed, 25 May 2022 22:25:08 GMT + +_Version update only_ + +## 0.1.4 +Thu, 19 May 2022 15:13:21 GMT + +_Version update only_ + +## 0.1.3 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.1.2 +Tue, 10 May 2022 01:20:44 GMT + +_Version update only_ + +## 0.1.1 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.1.0 +Wed, 27 Apr 2022 01:19:20 GMT + +### Minor changes + +- Initial release. + diff --git a/webpack/webpack-plugin-utilities/README.md b/webpack/webpack-plugin-utilities/README.md new file mode 100644 index 00000000000..b377c223fbd --- /dev/null +++ b/webpack/webpack-plugin-utilities/README.md @@ -0,0 +1,109 @@ +# webpack-plugin-utilities + +## Installation + +`npm install @rushstack/webpack-plugin-utilities --save` + +## Overview + +This is a collection of utilities for writing webpack plugins + +# Usage + +## VersionDetection + +```JavaScript +import { VersionDetection } from "@rushstack/webpack-plugin-utilities" + +class MyExampleWebpackPlugin { + constructor() { + this.pluginName = "MyExampleWebpackPlugin" + } + + apply(compiler) { + if (VersionDetection.isWebpack3OrEarlier(compiler)) { + throw new Error(`This plugin does not support webpack 3 or below.`) + } + + const isWebpack4 = VersionDetection.isWebpack4(compiler); + + if (isWebpack4) { + compiler.hooks.compilation.tap(this.pluginName, (compilation) => { + // .... + }); + } else { + compiler.hooks.compilation.tap(this.pluginName, (compilation) => { + // ... + }); + } + } +} +``` + +## Testing + +### `getTestingWebpackCompiler` + +```typescript + +import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities" + +describe("MyPlugin", () => { + it("should run", async () => { + const stats = await getTestingWebpackCompiler("./src/index.ts"); + + expect(stats).toBeDefined(); + }); +}); +``` + +### `getTestingWebpackCompiler` with additional configuration + +If you want to pass in additional configuration to the webpack compiler, you can pass it in as the second parameter to `getTestingWebpackCompiler`. + +```typescript +import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities" + +describe("MyPlugin", () => { + it("should run", async () => { + const stats = await getTestingWebpackCompiler("./src/index.ts", { + mode: "production", + }); + + expect(stats).toBeDefined(); + }); +}); +``` + +### `getTestingWebpackCompiler` with virtual filesystem + +If you want to be able to read, analyze, access the files written to the memory filesystem, +you can pass in a memory filesystem instance to the `memFs` parameter. + +```typescript +import { getTestingWebpackCompiler } from "@rushstack/webpack-plugin-utilities" +import { createFsFromVolume, Volume, IFs } from "memfs" +import path from "path" + +describe("MyPlugin", () => { + it("should run", async () => { + const virtualFileSystem: IFs = createFsFromVolume(new Volume()); + const stats = await getTestingWebpackCompiler( + `./src/index.ts`, + {}, + virtualFileSystem + ); + + expect(stats).toBeDefined(); + expect(virtualFileSystem.existsSync(path.join(__dirname, "dist", "index.js"))).toBe(true); + }); +}); +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/webpack-plugin-utilities/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack-plugin-utilities` is part of the [Rush Stack](https://rushstack.io/) family of projects. \ No newline at end of file diff --git a/webpack/webpack-plugin-utilities/config/api-extractor.json b/webpack/webpack-plugin-utilities/config/api-extractor.json new file mode 100644 index 00000000000..31010bc6261 --- /dev/null +++ b/webpack/webpack-plugin-utilities/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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 + }, + + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/webpack/webpack-plugin-utilities/config/rig.json b/webpack/webpack-plugin-utilities/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack-plugin-utilities/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/webpack/webpack-plugin-utilities/eslint.config.js b/webpack/webpack-plugin-utilities/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack-plugin-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/webpack/webpack-plugin-utilities/package.json b/webpack/webpack-plugin-utilities/package.json new file mode 100644 index 00000000000..0edee341f67 --- /dev/null +++ b/webpack/webpack-plugin-utilities/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/webpack-plugin-utilities", + "version": "0.5.7", + "description": "This plugin sets the webpack public path at runtime.", + "main": "lib/index.js", + "typings": "dist/webpack-plugin-utilities.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack-plugin-utilities" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "webpack-merge": "~5.8.0", + "memfs": "4.12.0" + }, + "peerDependencies": { + "@types/webpack": "^4.39.8", + "webpack": "^5.35.1 || ^4.31.0" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "webpack": { + "optional": true + } + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "@types/tapable": "1.0.6", + "webpack": "~5.98.0" + } +} diff --git a/webpack/webpack-plugin-utilities/src/DetectWebpackVersion.ts b/webpack/webpack-plugin-utilities/src/DetectWebpackVersion.ts new file mode 100644 index 00000000000..57c2e0f5753 --- /dev/null +++ b/webpack/webpack-plugin-utilities/src/DetectWebpackVersion.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. + +/** + * There is no `compiler.version` API available prior to webpack 5, + * therefore we will have to make some inferences about which major version of webpack we are on. + * Feature Request: https://github.com/webpack/webpack/issues/15679 + * @description + */ + +import type * as Webpack from 'webpack'; + +/** + * We do not have quality API detection between webpack major versions 1-3. + * We can detect the absence of hooks which was a version 3 feature. + * + * @public + */ +function isWebpack3OrEarlier(compiler: Webpack.Compiler): boolean { + return !compiler.hooks; +} + +/** + * Detects whether or not we are using webpack 4 + * + * @public + */ +function isWebpack4(compiler: Webpack.Compiler): boolean { + const webpackVersion: string | undefined = compiler?.webpack?.version; + return !webpackVersion; +} + +/** + * Detects whether or not we are using webpack 5 + * + * @public + */ +function isWebpack5(compiler: Webpack.Compiler): boolean { + const webpackVersion: string | undefined = compiler?.webpack?.version; + + return !!webpackVersion; +} + +export { isWebpack3OrEarlier, isWebpack4, isWebpack5 }; diff --git a/webpack/webpack-plugin-utilities/src/Testing.ts b/webpack/webpack-plugin-utilities/src/Testing.ts new file mode 100644 index 00000000000..90ee28ebcf2 --- /dev/null +++ b/webpack/webpack-plugin-utilities/src/Testing.ts @@ -0,0 +1,154 @@ +// 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 { createFsFromVolume, Volume, type IFs } from 'memfs'; +import type { + StatsCompilation as WebpackStatsCompilation, + MultiStats, + Stats, + Configuration, + Compiler, + StatsError, + OutputFileSystem +} from 'webpack'; +import webpackMerge from 'webpack-merge'; + +/** + * @public + * This function generates a webpack compiler with default configuration and the output filesystem mapped to + * a memory filesystem. This is useful for testing webpack plugins/loaders where we do not need to write to disk (which can be costly). + * @param entry - The entry point for the webpack compiler + * @param additionalConfig - Any additional configuration that should be merged with the default configuration + * @param memFs - The memory filesystem to use for the output filesystem. Use this option if you want to _inspect_, analyze, or read the output + * files generated by the webpack compiler. If you do not need to do this, you can omit this parameter and the output files. + * + * @returns - A webpack compiler with the output filesystem mapped to a memory filesystem + * + * @example + * ```typescript + * import Testing from '@rushstack/webpack-plugin-utilities'; + * + * describe('MyPlugin', () => { + * it('should run', async () => { + * const stats = await Testing.getTestingWebpackCompiler( + * `./src/index.ts`, + * ); + * + * expect(stats).toBeDefined(); + * }); + * }); + * ``` + * + * @remarks + * If you want to be able to read, analyze, access the files written to the memory filesystem, + * you can pass in a memory filesystem instance to the `memFs` parameter. + * + * @example + * ```typescript + * import Testing from '@rushstack/webpack-plugin-utilities'; + * import { createFsFromVolume, Volume, IFs } from 'memfs'; + * import path from 'path'; + * + * describe('MyPlugin', () => { + * it('should run', async () => { + * const virtualFileSystem: IFs = createFsFromVolume(new Volume()); + * const stats = await Testing.getTestingWebpackCompiler( + * `./src/index.ts`, + * {}, + * virtualFileSystem + * ); + * + * expect(stats).toBeDefined(); + * expect(virtualFileSystem.existsSync(path.join(__dirname, 'dist', 'index.js'))).toBe(true); + * }); + * }); + * ``` + */ +export async function getTestingWebpackCompilerAsync( + entry: string, + additionalConfig: Configuration = {}, + memFs: IFs = createFsFromVolume(new Volume()) +): Promise<(Stats | MultiStats) | undefined> { + let webpackModule: typeof import('webpack'); + try { + webpackModule = (await import('webpack')).default; + } catch (e) { + throw new Error( + 'Unable to load module "webpack". The @rushstack/webpack-plugin-utilities package declares "webpack" as ' + + 'an optional peer dependency, but a function was invoked on it that requires webpack. Make sure ' + + `the peer dependency on "webpack" is fulfilled. Inner error: ${e}` + ); + } + + const compilerOptions: Configuration = webpackMerge(_defaultWebpackConfig(entry), additionalConfig); + const compiler: Compiler = webpackModule(compilerOptions); + + // The memFs Volume satisfies the interface contract, but the types aren't happy due to strict null checks + const outputFileSystem: OutputFileSystem = memFs as unknown as OutputFileSystem; + outputFileSystem.join = path.join.bind(path); + + compiler.outputFileSystem = outputFileSystem; + + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + compiler.close(() => { + if (err) { + return reject(err); + } + + _processAndHandleStatsErrorsAndWarnings(stats, reject); + + resolve(stats); + }); + }); + }); +} + +function _processAndHandleStatsErrorsAndWarnings( + stats: Stats | MultiStats | undefined, + reject: (reason: unknown) => void +): void { + if (stats?.hasErrors() || stats?.hasWarnings()) { + const serializedStats: WebpackStatsCompilation[] = [stats?.toJson('errors-warnings')]; + + const errors: StatsError[] = []; + const warnings: StatsError[] = []; + + for (const compilationStats of serializedStats) { + if (compilationStats.warnings) { + for (const warning of compilationStats.warnings) { + warnings.push(warning); + } + } + + if (compilationStats.errors) { + for (const error of compilationStats.errors) { + errors.push(error); + } + } + + if (compilationStats.children) { + for (const child of compilationStats.children) { + serializedStats.push(child); + } + } + } + + reject([...errors, ...warnings]); + } +} + +function _defaultWebpackConfig(entry: string = './src'): Configuration { + return { + // We don't want to have eval source maps, nor minification + // so we set mode to 'none' to disable both. Default is 'production' + mode: 'none', + context: __dirname, + entry, + output: { + filename: 'test-bundle.js' + } + }; +} diff --git a/webpack/webpack-plugin-utilities/src/index.ts b/webpack/webpack-plugin-utilities/src/index.ts new file mode 100644 index 00000000000..75a14e2aa39 --- /dev/null +++ b/webpack/webpack-plugin-utilities/src/index.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. + +/** + * Utility package which provides a set of tools for working in + * webpack plugins, loaders, and other integrations. + * @packageDocumentation + */ + +import * as VersionDetection from './DetectWebpackVersion'; +import * as Testing from './Testing'; +export { VersionDetection, Testing }; diff --git a/webpack/webpack-plugin-utilities/tsconfig.json b/webpack/webpack-plugin-utilities/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/webpack/webpack-plugin-utilities/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/webpack-workspace-resolve-plugin/.npmignore b/webpack/webpack-workspace-resolve-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack-workspace-resolve-plugin/CHANGELOG.json b/webpack/webpack-workspace-resolve-plugin/CHANGELOG.json new file mode 100644 index 00000000000..5258ea477d2 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/CHANGELOG.json @@ -0,0 +1,982 @@ +{ + "name": "@rushstack/webpack-workspace-resolve-plugin", + "entries": [ + { + "version": "0.5.7", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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.5.4", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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.5.3", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.5.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/lookup-by-path\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.32", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.31", + "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/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.30", + "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`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.29", + "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`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.28", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.27", + "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`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.26", + "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/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.25", + "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`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.24", + "date": "Tue, 13 May 2025 20:32:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.23", + "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`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.22", + "date": "Thu, 08 May 2025 00:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.21", + "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`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.20", + "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/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.19", + "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`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.18", + "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`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.17", + "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`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.16", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.15", + "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`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.14", + "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`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.13", + "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/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.12", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.11", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.10", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.9", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.8", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.7", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.6", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.5", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.4", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.3", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.2", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.1", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.4.0", + "date": "Tue, 14 Jan 2025 01:11:21 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Switch constructor to an options object. Add option to specify which webpack resolvers to apply the plugin to. Improve performance by using an object literal instead of the spread operator when updating the resolve request. Upgrade compilation target to not polyfill optional chaining." + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.20", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.19", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.18", + "date": "Wed, 18 Dec 2024 01:11:33 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug with path handling on Windows. Tap hooks earlier to ensure that these plugins run before builtin behavior." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.17", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.16", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.15", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.14", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.13", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.12", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.11", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.10", + "date": "Thu, 17 Oct 2024 20:25:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.9", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.8", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.7", + "date": "Thu, 03 Oct 2024 15:11:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.6", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.5", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.4", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.3", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.2", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.1", + "date": "Thu, 29 Aug 2024 00:11:32 GMT", + "comments": { + "patch": [ + { + "comment": "Fix description file resolution after cross-package import." + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.3.0", + "date": "Wed, 28 Aug 2024 00:11:41 GMT", + "comments": { + "minor": [ + { + "comment": "Expect the base path to be part of the resolver cache file." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.2.0", + "date": "Tue, 27 Aug 2024 15:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Support hierarchical `node_modules` folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.1.2", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bug caused by mutating resolver request object." + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.1.1", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/webpack-workspace-resolve-plugin_v0.1.0", + "date": "Fri, 16 Aug 2024 00:11:49 GMT", + "comments": { + "minor": [ + { + "comment": "Add plugin for more efficient import resolution in a monorepo with known structure. Optimizes lookup of the relevant `package.json` for a given path, and lookup of npm dependencies of the containing package." + } + ] + } + } + ] +} diff --git a/webpack/webpack-workspace-resolve-plugin/CHANGELOG.md b/webpack/webpack-workspace-resolve-plugin/CHANGELOG.md new file mode 100644 index 00000000000..a843bd05d78 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/CHANGELOG.md @@ -0,0 +1,352 @@ +# Change Log - @rushstack/webpack-workspace-resolve-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 0.5.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.5.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.5.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.5.4 +Tue, 04 Nov 2025 08:15:15 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:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.4.32 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.4.31 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.4.30 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.4.29 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.4.28 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.4.27 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.4.26 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.4.25 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.4.24 +Tue, 13 May 2025 20:32:55 GMT + +_Version update only_ + +## 0.4.23 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.4.22 +Thu, 08 May 2025 00:11:15 GMT + +_Version update only_ + +## 0.4.21 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.4.20 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.4.19 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.18 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.4.17 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.4.16 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.4.15 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.4.14 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.4.13 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.4.12 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.4.11 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.10 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.4.9 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.4.8 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.4.7 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.4.6 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.4.5 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.4.4 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.4.3 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.4.2 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.4.1 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.4.0 +Tue, 14 Jan 2025 01:11:21 GMT + +### Minor changes + +- (BREAKING CHANGE) Switch constructor to an options object. Add option to specify which webpack resolvers to apply the plugin to. Improve performance by using an object literal instead of the spread operator when updating the resolve request. Upgrade compilation target to not polyfill optional chaining. + +## 0.3.20 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.3.19 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.3.18 +Wed, 18 Dec 2024 01:11:33 GMT + +### Patches + +- Fix a bug with path handling on Windows. Tap hooks earlier to ensure that these plugins run before builtin behavior. + +## 0.3.17 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.3.16 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.3.15 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.3.14 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.3.13 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.3.12 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.3.11 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.3.10 +Thu, 17 Oct 2024 20:25:42 GMT + +_Version update only_ + +## 0.3.9 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.3.8 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.3.7 +Thu, 03 Oct 2024 15:11:00 GMT + +_Version update only_ + +## 0.3.6 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 0.3.5 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.3.4 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.3.3 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.3.2 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.3.1 +Thu, 29 Aug 2024 00:11:32 GMT + +### Patches + +- Fix description file resolution after cross-package import. + +## 0.3.0 +Wed, 28 Aug 2024 00:11:41 GMT + +### Minor changes + +- Expect the base path to be part of the resolver cache file. + +## 0.2.0 +Tue, 27 Aug 2024 15:12:33 GMT + +### Minor changes + +- Support hierarchical `node_modules` folders. + +## 0.1.2 +Mon, 26 Aug 2024 02:00:11 GMT + +### Patches + +- Fix bug caused by mutating resolver request object. + +## 0.1.1 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.1.0 +Fri, 16 Aug 2024 00:11:49 GMT + +### Minor changes + +- Add plugin for more efficient import resolution in a monorepo with known structure. Optimizes lookup of the relevant `package.json` for a given path, and lookup of npm dependencies of the containing package. + diff --git a/webpack/webpack-workspace-resolve-plugin/LICENSE b/webpack/webpack-workspace-resolve-plugin/LICENSE new file mode 100644 index 00000000000..42b9592b121 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack-workspace-resolve-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/webpack/webpack-workspace-resolve-plugin/README.md b/webpack/webpack-workspace-resolve-plugin/README.md new file mode 100644 index 00000000000..ea4c3105da1 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/README.md @@ -0,0 +1,43 @@ +# @rushstack/webpack-workspace-resolve-plugin + +This package contains a plugin for webpack 5 that leverages a cache file generated from package manager metadata to greatly accelerate module resolution. +Local benchmarks have shown a savings of around 10% of build time for some fairly large closed source projects. + +## Installation + +`npm install @rushstack/webpack-workspace-resolve-plugin --save-dev` + +## Overview + +This plugin is intended primarily for use in pnpm monorepos, but any tool that produces a strict package layout can be made compatible by generating the necessary cache file. + +The cache file contains information about the locations of every `package.json` file known to the package manager (including those in subdirectories of packages), as well as the list of declared dependencies of each and where they can be found. + +When using this plugin, the following options should be configured for your resolver: +- `symlinks: false` - Since the cache knows the symlinks for package dependencies, you can avoid the cost of testing for other symlinks unless you are using additional symlinks. +- `modules: []` - The cache should contain all information necessary to locate available dependencies for any arbitrary folder. If you need to allow resolution in other roots, you can add those, but omit `'node_modules'`. + +## Impact + +This plugin should eliminate file system calls associated with the following operations of NodeJS module resolution in webpack: +- Find the nearest `package.json` to the calling module +- Locate a named package from a calling module +- Identify a `package.json` in a resolved directory +- Find the nearest `package.json` to a resolved file path + +## Limitations + +This plugin depends on the presence of a cache file in the workspace to function. Data in this cache file is assumed not to change while the webpack process is running. + +**Note:** Generating the cache file is not in the scope of this plugin. + +This plugin does not currently support having subdirectory `package.json` files within workspace projects (e.g. for declaring `{ "type": "module" }` in mixed CommonJS/ESM packages). +This plugin does not work (well) with a hoisted node_modules installation layout. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/webpack-workspace-resolve-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack5-workspace-resolve-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/webpack-workspace-resolve-plugin/config/api-extractor.json b/webpack/webpack-workspace-resolve-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack-workspace-resolve-plugin/config/jest.config.json b/webpack/webpack-workspace-resolve-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/webpack-workspace-resolve-plugin/config/rig.json b/webpack/webpack-workspace-resolve-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack-workspace-resolve-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/webpack/webpack-workspace-resolve-plugin/eslint.config.js b/webpack/webpack-workspace-resolve-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack-workspace-resolve-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/webpack/webpack-workspace-resolve-plugin/package.json b/webpack/webpack-workspace-resolve-plugin/package.json new file mode 100644 index 00000000000..07ef292c488 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/package.json @@ -0,0 +1,42 @@ +{ + "name": "@rushstack/webpack-workspace-resolve-plugin", + "version": "0.5.7", + "description": "This plugin leverages workspace-level metadata to greatly accelerate module resolution.", + "main": "lib/index.js", + "typings": "dist/webpack-workspace-resolve-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack-workspace-resolve-plugin" + }, + "engines": { + "node": ">=18.19.0" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "webpack": "^5.68.0", + "@types/node": "*" + }, + "dependencies": { + "@rushstack/lookup-by-path": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" + }, + "sideEffects": false, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.ts new file mode 100644 index 00000000000..30b26319570 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/KnownDescriptionFilePlugin.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 type { InputFileSystem, Resolver } from 'webpack'; + +import type { IPrefixMatch } from '@rushstack/lookup-by-path'; + +import type { IResolveContext, WorkspaceLayoutCache } from './WorkspaceLayoutCache'; + +type ResolveRequest = Parameters[1]; + +/** + * A resolver plugin that optimizes locating the package.json file for a module. + * + * @internal + */ +export class KnownDescriptionFilePlugin { + public readonly source: string; + public readonly target: string; + + private readonly _skipForContext: boolean; + private readonly _cache: WorkspaceLayoutCache; + + /** + * Constructs a new instance of `KnownDescriptionFilePlugin`. + * @param cache - The workspace layout cache + * @param source - The resolve step to hook into + * @param target - The resolve step to delegate to + * @param skipForContext - If true, don't apply this plugin if the resolver is configured to resolve to a context + */ + public constructor(cache: WorkspaceLayoutCache, source: string, target: string, skipForContext?: boolean) { + this.source = source; + this.target = target; + this._cache = cache; + this._skipForContext = !!skipForContext; + } + + public apply(resolver: Resolver): void { + if (this._skipForContext && resolver.options.resolveToContext) { + return; + } + + const target: ReturnType = resolver.ensureHook(this.target); + const { fileSystem } = resolver; + + type JsonObjectTypes = ReturnType>; + + function readDescriptionFileWithParse( + descriptionFilePath: string, + callback: (err: Error | null | undefined, data?: JsonObjectTypes) => void + ): void { + fileSystem.readFile(descriptionFilePath, (err: Error | null | undefined, data?: string | Buffer) => { + if (!data?.length) { + return callback(err); + } + callback(null, JSON.parse(data.toString())); + }); + } + + const readDescriptionFile: ( + descriptionFilePath: string, + cb: (err: Error | null | undefined, data?: JsonObjectTypes) => void + ) => void = fileSystem.readJson?.bind(fileSystem) ?? readDescriptionFileWithParse; + + resolver + .getHook(this.source) + .tapAsync(KnownDescriptionFilePlugin.name, (request, resolveContext, callback) => { + const { path } = request; + if (!path) { + // No request, nothing to do. + return callback(); + } + + const cache: WorkspaceLayoutCache = this._cache; + + const match: IPrefixMatch | undefined = + cache.contextLookup.findLongestPrefixMatch(path); + if (!match) { + // No description file available, proceed without. + return callback(); + } + + const remainingPath: string = path.slice(match.index); + const relativePath: string = `.${cache.normalizeToSlash?.(remainingPath) ?? remainingPath}`; + const descriptionFileRoot: string = `${path.slice(0, match.index)}`; + const descriptionFilePath: string = `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`; + + const { contextForPackage } = cache; + + readDescriptionFile(descriptionFilePath, (err, descriptionFileData) => { + if (!descriptionFileData) { + resolveContext.missingDependencies?.add(descriptionFilePath); + return callback(err); + } + + resolveContext.fileDependencies?.add(descriptionFilePath); + // Store the resolver context since a WeakMap lookup is cheaper than walking the tree again + contextForPackage.set(descriptionFileData, match); + + // Using the object literal is an order of magnitude faster, at least on node 18.19.1 + const obj: ResolveRequest = { + path: request.path, + context: request.context, + descriptionFilePath, + descriptionFileRoot, + descriptionFileData, + relativePath, + ignoreSymlinks: request.ignoreSymlinks, + fullySpecified: request.fullySpecified, + __innerRequest: request.__innerRequest, + __innerRequest_request: request.__innerRequest_request, + __innerRequest_relativePath: request.__innerRequest_relativePath, + + request: request.request, + query: request.query, + fragment: request.fragment, + module: request.module, + directory: request.directory, + file: request.file, + internal: request.internal + }; + + // Delegate to the resolver step at `target`. + resolver.doResolve( + target, + obj, + 'using description file: ' + descriptionFilePath + ' (relative path: ' + relativePath + ')', + resolveContext, + (e: Error | null | undefined, result: ResolveRequest | undefined) => { + if (e) { + return callback(e); + } + + // Don't allow other processing + if (result === undefined) { + return callback(null, null); + } + callback(null, result); + } + ); + }); + }); + } +} diff --git a/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts new file mode 100644 index 00000000000..2f721e018fb --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/KnownPackageDependenciesPlugin.ts @@ -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. + +import type { Resolver } from 'webpack'; + +import type { IPrefixMatch } from '@rushstack/lookup-by-path'; + +import type { IResolveContext, WorkspaceLayoutCache } from './WorkspaceLayoutCache'; + +type ResolveRequest = Parameters[1]; + +/** + * A resolver plugin that optimizes resolving installed dependencies for the current package. + * Enforces strict resolution. + * + * @internal + */ +export class KnownPackageDependenciesPlugin { + public readonly source: string; + public readonly target: string; + + private readonly _cache: WorkspaceLayoutCache; + + /** + * Constructs a new instance of `KnownPackageDependenciesPlugin`. + * @param cache - The workspace layout cache + * @param source - The resolve step to hook into + * @param target - The resolve step to delegate to + */ + public constructor(cache: WorkspaceLayoutCache, source: string, target: string) { + this.source = source; + this.target = target; + this._cache = cache; + } + + public apply(resolver: Resolver): void { + const target: ReturnType = resolver.ensureHook(this.target); + + resolver + .getHook(this.source) + .tapAsync(KnownPackageDependenciesPlugin.name, (request, resolveContext, callback) => { + const { path, request: rawRequest } = request; + if (!path) { + return callback(); + } + + if (!rawRequest) { + return callback(); + } + + const { descriptionFileData } = request; + if (!descriptionFileData) { + return callback(new Error(`Expected descriptionFileData for ${path}`)); + } + + const cache: WorkspaceLayoutCache = this._cache; + + let scope: IPrefixMatch | undefined = + cache.contextForPackage.get(descriptionFileData); + if (!scope) { + scope = cache.contextLookup.findLongestPrefixMatch(path); + if (!scope) { + return callback(new Error(`Expected context for ${request.descriptionFileRoot}`)); + } + cache.contextForPackage.set(descriptionFileData, scope); + } + + let dependency: IPrefixMatch | undefined; + while (scope && !dependency) { + dependency = scope.value.findDependency(rawRequest); + scope = scope.lastMatch; + } + + if (!dependency) { + return callback(); + } + + const isPackageRoot: boolean = dependency.index === rawRequest.length; + const fullySpecified: boolean | undefined = isPackageRoot ? false : request.fullySpecified; + const remainingPath: string = isPackageRoot ? '.' : `.${rawRequest.slice(dependency.index)}`; + const relativePath: string = + (remainingPath.length > 1 && cache.normalizeToSlash?.(remainingPath)) || remainingPath; + const { descriptionFileRoot } = dependency.value; + const obj: ResolveRequest = { + path: descriptionFileRoot, + context: request.context, + descriptionFilePath: `${descriptionFileRoot}${cache.resolverPathSeparator}package.json`, + descriptionFileRoot, + descriptionFileData: undefined, + relativePath, + ignoreSymlinks: request.ignoreSymlinks, + fullySpecified, + __innerRequest: request.__innerRequest, + __innerRequest_request: request.__innerRequest_request, + __innerRequest_relativePath: request.__innerRequest_relativePath, + + request: relativePath, + query: request.query, + fragment: request.fragment, + module: false, + directory: request.directory, + file: request.file, + internal: request.internal + }; + resolver.doResolve(target, obj, null, resolveContext, callback); + }); + } +} diff --git a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts new file mode 100644 index 00000000000..0f2d988b634 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceLayoutCache.ts @@ -0,0 +1,218 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { sep as directorySeparator } from 'node:path'; + +import { LookupByPath, type IPrefixMatch } from '@rushstack/lookup-by-path'; + +/** + * Information about a local or installed npm package. + * @beta + */ +export interface ISerializedResolveContext { + /** + * The path to the root folder of this context. + * This path is normalized to use `/` as the separator and should not end with a trailing `/`. + */ + root: string; + /** + * The name of this package. Used to inject a self-reference into the dependency map. + */ + name: string; + /** + * Map of declared dependencies (if any) to the ordinal of the corresponding context. + */ + deps?: Record; + /** + * Set of relative paths to nested `package.json` files within this context. + * These paths are normalized to use `/` as the separator and should not begin with a leading `./`. + */ + dirInfoFiles?: string[]; +} + +/** + * The serialized form of the cache file. This file is expected to be generated by a separate tool from + * information known to the package manager. Namely, the dependency relationships between packages, and + * all the `package.json` files in the workspace (installed or local). + * @beta + */ +export interface IResolverCacheFile { + /** + * The base path. All paths in context entries are prefixed by this path. + */ + basePath: string; + /** + * The ordered list of all contexts in the cache + */ + contexts: ISerializedResolveContext[]; +} + +/** + * A context for resolving dependencies in a workspace. + * @beta + */ +export interface IResolveContext { + /** + * The absolute path to the root folder of this context + */ + descriptionFileRoot: string; + /** + * Find the context that corresponds to a module specifier, when requested in the current context. + * @param request - The module specifier to resolve + */ + findDependency(request: string): IPrefixMatch | undefined; +} + +/** + * Options for creating a `WorkspaceLayoutCache`. + * @beta + */ +export interface IWorkspaceLayoutCacheOptions { + /** + * The parsed cache data. File reading is left as an exercise for the caller. + */ + cacheData: IResolverCacheFile; + /** + * The directory separator used in the `path` field of the resolver inputs. + * Will usually be `path.sep`. + */ + resolverPathSeparator?: '/' | '\\'; +} + +/** + * A function that normalizes a path to a platform-specific format (if needed). + * Will be undefined if the platform uses `/` as the path separator. + * + * @beta + */ +export type IPathNormalizationFunction = ((input: string) => string) | undefined; + +function backslashToSlash(path: string): string { + return path.replace(/\\/g, '/'); +} + +function slashToBackslash(path: string): string { + return path.replace(/\//g, '\\'); +} + +/** + * A cache of workspace layout information. + * @beta + */ +export class WorkspaceLayoutCache { + /** + * A lookup of context roots to their corresponding context objects + */ + public readonly contextLookup: LookupByPath; + /** + * A weak map of package JSON contents to their corresponding context objects + */ + public readonly contextForPackage: WeakMap>; + + public readonly resolverPathSeparator: string; + public readonly normalizeToSlash: IPathNormalizationFunction; + public readonly normalizeToPlatform: IPathNormalizationFunction; + + public constructor(options: IWorkspaceLayoutCacheOptions) { + const { cacheData, resolverPathSeparator = directorySeparator } = options; + + if (resolverPathSeparator !== '/' && resolverPathSeparator !== '\\') { + throw new Error(`Unsupported directory separator: ${resolverPathSeparator}`); + } + + const { basePath } = cacheData; + const resolveContexts: ResolveContext[] = []; + const contextLookup: LookupByPath = new LookupByPath(undefined, resolverPathSeparator); + + this.contextLookup = contextLookup; + this.contextForPackage = new WeakMap>(); + + const normalizeToSlash: IPathNormalizationFunction = + resolverPathSeparator === '\\' ? backslashToSlash : undefined; + const normalizeToPlatform: IPathNormalizationFunction = + resolverPathSeparator === '\\' ? slashToBackslash : undefined; + + this.resolverPathSeparator = resolverPathSeparator; + this.normalizeToSlash = normalizeToSlash; + this.normalizeToPlatform = normalizeToPlatform; + + // Internal class due to coupling to `resolveContexts` + class ResolveContext implements IResolveContext { + private readonly _serialized: ISerializedResolveContext; + private _descriptionFileRoot: string | undefined; + private _dependencies: LookupByPath | undefined; + + public constructor(serialized: ISerializedResolveContext) { + this._serialized = serialized; + this._descriptionFileRoot = undefined; + this._dependencies = undefined; + } + + public get descriptionFileRoot(): string { + if (!this._descriptionFileRoot) { + const merged: string = `${basePath}${this._serialized.root}`; + this._descriptionFileRoot = normalizeToPlatform?.(merged) ?? merged; + } + return this._descriptionFileRoot; + } + + public findDependency(request: string): IPrefixMatch | undefined { + if (!this._dependencies) { + // Lazy initialize this object since most packages won't be requested. + const dependencies: LookupByPath = new LookupByPath(undefined, '/'); + + const { name, deps } = this._serialized; + + // Handle the self-reference scenario + dependencies.setItem(name, this); + if (deps) { + for (const [key, ordinal] of Object.entries(deps)) { + // This calls into the array of instances that is owned by WorkpaceLayoutCache + dependencies.setItem(key, resolveContexts[ordinal]); + } + } + this._dependencies = dependencies; + } + + return this._dependencies.findLongestPrefixMatch(request); + } + } + + for (const serialized of cacheData.contexts) { + const resolveContext: ResolveContext = new ResolveContext(serialized); + resolveContexts.push(resolveContext); + + contextLookup.setItemFromSegments( + concat( + // All paths in the cache file are platform-agnostic + LookupByPath.iteratePathSegments(basePath, '/'), + LookupByPath.iteratePathSegments(serialized.root, '/') + ), + resolveContext + ); + + // Handle nested package.json files. These may modify some properties, but the dependency resolution + // will match the original package root. Typically these are used to set the `type` field to `module`. + if (serialized.dirInfoFiles) { + for (const file of serialized.dirInfoFiles) { + contextLookup.setItemFromSegments( + concat( + // All paths in the cache file are platform-agnostic + concat( + LookupByPath.iteratePathSegments(basePath, '/'), + LookupByPath.iteratePathSegments(serialized.root, '/') + ), + LookupByPath.iteratePathSegments(file, '/') + ), + resolveContext + ); + } + } + } + } +} + +function* concat(a: Iterable, b: Iterable): IterableIterator { + yield* a; + yield* b; +} diff --git a/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts new file mode 100644 index 00000000000..a68a97aa5db --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/WorkspaceResolvePlugin.ts @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { WebpackPluginInstance, Compiler, ResolveOptions } from 'webpack'; + +import type { WorkspaceLayoutCache } from './WorkspaceLayoutCache'; +import { KnownDescriptionFilePlugin } from './KnownDescriptionFilePlugin'; +import { KnownPackageDependenciesPlugin } from './KnownPackageDependenciesPlugin'; + +/** + * Options for constructing a `WorkspaceResolvePlugin`. + * + * @beta + */ +export interface IWorkspaceResolvePluginOptions { + /** + * The cache of workspace layout information. + */ + cache: WorkspaceLayoutCache; + + /** + * Which webpack resolvers to apply the plugin to. + * @defaultValue ['normal', 'context', 'loader'] + */ + resolverNames?: Iterable; +} + +/** + * A Webpack plugin that optimizes package.json lookups and resolution of bare specifiers in a monorepo. + * + * @beta + */ +export class WorkspaceResolvePlugin implements WebpackPluginInstance { + private readonly _cache: WorkspaceLayoutCache; + private readonly _resolverNames: Set; + + public constructor(options: IWorkspaceResolvePluginOptions) { + this._cache = options.cache; + this._resolverNames = new Set(options.resolverNames ?? ['normal', 'context', 'loader']); + } + + public apply(compiler: Compiler): void { + const cache: WorkspaceLayoutCache = this._cache; + + function handler(resolveOptions: ResolveOptions): ResolveOptions { + // Omit default `node_modules` + if (resolveOptions.modules) { + resolveOptions.modules = resolveOptions.modules.filter((modulePath: string) => { + return modulePath !== 'node_modules'; + }); + } else { + resolveOptions.modules = []; + } + + resolveOptions.plugins ??= []; + resolveOptions.plugins.push( + // Optimize identifying the package.json file for the issuer + new KnownDescriptionFilePlugin(cache, 'before-parsed-resolve', 'described-resolve'), + // Optimize locating the installed dependencies of the current package + new KnownPackageDependenciesPlugin(cache, 'before-raw-module', 'resolve-as-module'), + // Optimize loading the package.json file for the destination package (bare specifier) + new KnownDescriptionFilePlugin(cache, 'before-resolve-as-module', 'resolve-in-package'), + // Optimize loading the package.json file for the destination package (relative path) + new KnownDescriptionFilePlugin(cache, 'before-relative', 'described-relative'), + // Optimize locating and loading nested package.json for a directory + new KnownDescriptionFilePlugin( + cache, + 'before-undescribed-existing-directory', + 'existing-directory', + true + ), + // Optimize locating and loading nested package.json for a file + new KnownDescriptionFilePlugin(cache, 'before-undescribed-raw-file', 'raw-file') + ); + + return resolveOptions; + } + for (const resolverName of this._resolverNames) { + compiler.resolverFactory.hooks.resolveOptions + .for(resolverName) + .tap(WorkspaceResolvePlugin.name, handler); + } + } +} diff --git a/webpack/webpack-workspace-resolve-plugin/src/index.ts b/webpack/webpack-workspace-resolve-plugin/src/index.ts new file mode 100644 index 00000000000..61866c3a162 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/index.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. + +export { WorkspaceResolvePlugin, type IWorkspaceResolvePluginOptions } from './WorkspaceResolvePlugin'; +export { + WorkspaceLayoutCache, + type IPathNormalizationFunction, + type IWorkspaceLayoutCacheOptions, + type IResolveContext, + type ISerializedResolveContext, + type IResolverCacheFile +} from './WorkspaceLayoutCache'; diff --git a/webpack/webpack-workspace-resolve-plugin/src/test/KnownDescriptionFilePlugin.test.ts b/webpack/webpack-workspace-resolve-plugin/src/test/KnownDescriptionFilePlugin.test.ts new file mode 100644 index 00000000000..78cc2153941 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/test/KnownDescriptionFilePlugin.test.ts @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { KnownDescriptionFilePlugin } from '../KnownDescriptionFilePlugin'; + +import { + parsedJson, + createResolveForTests, + type WrappedResolve, + type ResolveContext +} from './createResolveForTests'; + +function createResolve(separator: '/' | '\\'): WrappedResolve { + return createResolveForTests(separator, (cache, resolver) => { + const plugin: KnownDescriptionFilePlugin = new KnownDescriptionFilePlugin(cache, 'source', 'target'); + plugin.apply(resolver); + }); +} + +describe(KnownDescriptionFilePlugin.name, () => { + it('should resolve the package.json file for a module (/)', () => { + const resolver: WrappedResolve = createResolve('/'); + + const fileDependencies: Set = new Set(); + const context: ResolveContext = { fileDependencies }; + + const [err1, result1] = resolver({ path: '/workspace/a/lib/index.js' }, context); + expect(err1).toBeNull(); + expect(result1).toEqual({ + path: '/workspace/a/lib/index.js', + descriptionFileRoot: '/workspace/a', + descriptionFileData: parsedJson['/workspace/a/package.json'], + descriptionFilePath: '/workspace/a/package.json', + relativePath: './lib/index.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('/workspace/a/package.json')).toBeTruthy(); + + fileDependencies.clear(); + + const [err2, result2] = resolver({ path: '/workspace/a/foo/bar/baz.js' }, context); + expect(err2).toBeNull(); + expect(result2).toMatchObject({ + path: '/workspace/a/foo/bar/baz.js', + descriptionFileRoot: '/workspace/a', + descriptionFileData: parsedJson['/workspace/a/package.json'], + descriptionFilePath: '/workspace/a/package.json', + relativePath: './foo/bar/baz.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('/workspace/a/package.json')).toBeTruthy(); + + fileDependencies.clear(); + + const [err3, result3] = resolver({ path: '/workspace/a/lib-esm/index.js' }, context); + expect(err3).toBeNull(); + expect(result3).toMatchObject({ + path: '/workspace/a/lib-esm/index.js', + descriptionFileRoot: '/workspace/a/lib-esm', + descriptionFileData: parsedJson['/workspace/a/lib-esm/package.json'], + descriptionFilePath: '/workspace/a/lib-esm/package.json', + relativePath: './index.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('/workspace/a/lib-esm/package.json')).toBeTruthy(); + + fileDependencies.clear(); + }); + + it('should resolve the package.json file for a module (\\)', () => { + const resolver: WrappedResolve = createResolve('\\'); + + const fileDependencies: Set = new Set(); + const context: ResolveContext = { fileDependencies }; + + const [err1, result1] = resolver({ path: '\\workspace\\a\\lib\\index.js' }, context); + expect(err1).toBeNull(); + expect(result1).toEqual({ + path: '\\workspace\\a\\lib\\index.js', + descriptionFileRoot: '\\workspace\\a', + descriptionFileData: parsedJson['/workspace/a/package.json'], + descriptionFilePath: '\\workspace\\a\\package.json', + relativePath: './lib/index.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('\\workspace\\a\\package.json')).toBeTruthy(); + + fileDependencies.clear(); + + const [err2, result2] = resolver({ path: '\\workspace\\a\\foo\\bar\\baz.js' }, context); + expect(err2).toBeNull(); + expect(result2).toMatchObject({ + path: '\\workspace\\a\\foo\\bar\\baz.js', + descriptionFileRoot: '\\workspace\\a', + descriptionFileData: parsedJson['/workspace/a/package.json'], + descriptionFilePath: '\\workspace\\a\\package.json', + relativePath: './foo/bar/baz.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('\\workspace\\a\\package.json')).toBeTruthy(); + + fileDependencies.clear(); + + const [err3, result3] = resolver({ path: '\\workspace\\a\\lib-esm\\index.js' }, context); + expect(err3).toBeNull(); + expect(result3).toMatchObject({ + path: '\\workspace\\a\\lib-esm\\index.js', + descriptionFileRoot: '\\workspace\\a\\lib-esm', + descriptionFileData: parsedJson['/workspace/a/lib-esm/package.json'], + descriptionFilePath: '\\workspace\\a\\lib-esm\\package.json', + relativePath: './index.js' + }); + expect(fileDependencies.size).toEqual(1); + expect(fileDependencies.has('\\workspace\\a\\lib-esm\\package.json')).toBeTruthy(); + + fileDependencies.clear(); + }); + + it('should defer to other plugins if not in a context', () => { + const resolver: WrappedResolve = createResolve('/'); + + const [err1, result1] = resolver({ path: '/workspace/c/lib/index.js' }, {}); + expect(err1).toBeUndefined(); + expect(result1).toBeUndefined(); + }); +}); diff --git a/webpack/webpack-workspace-resolve-plugin/src/test/KnownPackageDependenciesPlugin.test.ts b/webpack/webpack-workspace-resolve-plugin/src/test/KnownPackageDependenciesPlugin.test.ts new file mode 100644 index 00000000000..509d01df3ad --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/test/KnownPackageDependenciesPlugin.test.ts @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { KnownPackageDependenciesPlugin } from '../KnownPackageDependenciesPlugin'; +import { + createResolveForTests, + parsedJson, + type WrappedResolve, + type JsonObjectTypes +} from './createResolveForTests'; + +function createResolve(separator: '/' | '\\'): WrappedResolve { + return createResolveForTests(separator, (cache, resolver) => { + const plugin: KnownPackageDependenciesPlugin = new KnownPackageDependenciesPlugin( + cache, + 'source', + 'target' + ); + plugin.apply(resolver); + }); +} + +describe(KnownPackageDependenciesPlugin.name, () => { + it('should find a relevant dependency (/)', () => { + const resolver: WrappedResolve = createResolve('/'); + + const descriptionFilePath: string = '/workspace/b/package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson[descriptionFilePath]; + const descriptionFileRoot: string = '/workspace/b'; + + const [err1, result1] = resolver( + { + path: '/workspace/b/lib/foo.js', + request: 'a/lib/index.js', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeFalsy(); + expect(result1).toEqual({ + path: '/workspace/a', + request: './lib/index.js', + descriptionFileRoot: '/workspace/a', + descriptionFilePath: '/workspace/a/package.json', + relativePath: './lib/index.js', + fullySpecified: undefined, + module: false + }); + }); + it('should find a relevant dependency (\\)', () => { + const resolver: WrappedResolve = createResolve('\\'); + + const descriptionFilePath: string = '\\workspace\\b\\package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson['/workspace/b/package.json']; + const descriptionFileRoot: string = '\\workspace\\b'; + + const [err1, result1] = resolver( + { + path: '\\workspace\\b\\lib\\foo.js', + request: 'a/lib/index.js', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeFalsy(); + expect(result1).toEqual({ + path: '\\workspace\\a', + request: './lib/index.js', + descriptionFileRoot: '\\workspace\\a', + descriptionFilePath: '\\workspace\\a\\package.json', + relativePath: './lib/index.js', + fullySpecified: undefined, + module: false + }); + }); + + it('should handle self-reference', () => { + const resolver: WrappedResolve = createResolve('/'); + + const descriptionFilePath: string = '/workspace/b/package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson[descriptionFilePath]; + const descriptionFileRoot: string = '/workspace/b'; + + const [err1, result1] = resolver( + { + path: '/workspace/b/lib/foo.js', + request: 'b/lib/bar.js', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeFalsy(); + expect(result1).toEqual({ + path: '/workspace/b', + request: './lib/bar.js', + descriptionFileRoot: '/workspace/b', + descriptionFilePath: '/workspace/b/package.json', + relativePath: './lib/bar.js', + fullySpecified: undefined, + module: false + }); + }); + + it('should find a parent (/)', () => { + const resolver: WrappedResolve = createResolve('/'); + + const descriptionFilePath: string = '/workspace/b/node_modules/c/package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson[descriptionFilePath]; + const descriptionFileRoot: string = '/workspace/b/node_modules/c'; + + const [err1, result1] = resolver( + { + path: '/workspace/b/node_modules/c/lib/foo.js', + request: 'b/lib/index.js', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeFalsy(); + expect(result1).toEqual({ + path: '/workspace/b', + request: './lib/index.js', + descriptionFileRoot: '/workspace/b', + descriptionFilePath: '/workspace/b/package.json', + relativePath: './lib/index.js', + fullySpecified: undefined, + module: false + }); + }); + + it('should resolve through a parent (/)', () => { + const resolver: WrappedResolve = createResolve('/'); + + const descriptionFilePath: string = '/workspace/b/node_modules/c/package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson[descriptionFilePath]; + const descriptionFileRoot: string = '/workspace/b/node_modules/c'; + + const [err1, result1] = resolver( + { + path: '/workspace/b/node_modules/c/lib/foo.js', + request: 'a/lib/index.js', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeFalsy(); + expect(result1).toEqual({ + path: '/workspace/a', + request: './lib/index.js', + descriptionFileRoot: '/workspace/a', + descriptionFilePath: '/workspace/a/package.json', + relativePath: './lib/index.js', + fullySpecified: undefined, + module: false + }); + }); + + it('should defer to other plugins if not in a context', () => { + const resolver: WrappedResolve = createResolve('/'); + + const [err1, result1] = resolver({ path: '/workspace/c/lib/index.js' }, {}); + expect(err1).toBeUndefined(); + expect(result1).toBeUndefined(); + }); + + it('should defer to other plugins if the dependency is not found (for fallback)', () => { + const resolver: WrappedResolve = createResolve('/'); + + const descriptionFilePath: string = '/workspace/a/package.json'; + const descriptionFileData: JsonObjectTypes = parsedJson[descriptionFilePath]; + const descriptionFileRoot: string = '/workspace/a'; + + const [err1, result1] = resolver( + { + path: '/workspace/a/lib/foo.js', + request: 'events', + descriptionFileRoot, + descriptionFileData, + descriptionFilePath, + relativePath: './lib/foo.js' + }, + {} + ); + + expect(err1).toBeUndefined(); + expect(result1).toBeUndefined(); + }); +}); diff --git a/webpack/webpack-workspace-resolve-plugin/src/test/createResolveForTests.ts b/webpack/webpack-workspace-resolve-plugin/src/test/createResolveForTests.ts new file mode 100644 index 00000000000..bc47fa52857 --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/src/test/createResolveForTests.ts @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { PathOrFileDescriptor } from 'node:fs'; + +import { Volume } from 'memfs/lib/volume'; +import type { Resolver, InputFileSystem } from 'webpack'; + +import type { IPrefixMatch } from '@rushstack/lookup-by-path'; + +import { WorkspaceLayoutCache, type IResolveContext } from '../WorkspaceLayoutCache'; + +export type ResolveCallback = Parameters[1]; +export type ResolveRequest = Parameters[0]; +export type ResolveContext = Parameters[1]; +export type WrappedResolve = ( + request: ResolveRequest, + resolveContext: ResolveContext + // eslint-disable-next-line @rushstack/no-new-null +) => [Error | false | null | undefined, ResolveRequest | undefined]; + +export type JsonObjectTypes = ReturnType>; +export const parsedJson: Record = { + '/workspace/a/package.json': { name: 'a' }, + '/workspace/a/lib-esm/package.json': { type: 'module' }, + '/workspace/b/package.json': { name: 'b', dependencies: { a: 'workspace:*' }, bundledDepencies: ['c'] }, + '/workspace/b/node_modules/c/package.json': { name: 'c' } +}; + +export function createResolveForTests( + separator: '/' | '\\', + attachPlugins: (cache: WorkspaceLayoutCache, resolver: Resolver) => void +): WrappedResolve { + const fileSystem: Volume = new Volume(); + + const cache: WorkspaceLayoutCache = new WorkspaceLayoutCache({ + cacheData: { + basePath: `/workspace/`, + contexts: [ + { + root: 'a', + name: 'a', + deps: {}, + dirInfoFiles: ['lib-esm'] + }, + { + root: 'b', + name: 'b', + deps: { a: 0, c: 2 } + }, + { + root: 'b/node_modules/c', + name: 'c', + deps: {} + } + ] + }, + resolverPathSeparator: separator + }); + + const platformJson: Record = Object.fromEntries( + Object.entries(parsedJson).map(([key, value]) => [cache.normalizeToPlatform?.(key) ?? key, value]) + ); + + const serializedJson: Record = Object.fromEntries( + Object.entries(platformJson).map(([key, value]) => [key, JSON.stringify(value)]) + ); + + fileSystem.fromJSON(serializedJson); + (fileSystem as InputFileSystem).readJson = ( + pathOrFileDescriptor: PathOrFileDescriptor, + cb: (err: Error | null, data?: JsonObjectTypes) => void + ) => { + if (typeof pathOrFileDescriptor === 'number') { + return cb(new Error(`Expected string path, got ${pathOrFileDescriptor}`)); + } + const path: string = pathOrFileDescriptor.toString(); + const parsed: JsonObjectTypes | undefined = platformJson[path]; + if (parsed) { + return cb(null, parsed); + } + return cb(new Error(`No data found for ${path}`)); + }; + + let innerCallback: ResolveCallback | undefined = undefined; + + const resolver: Resolver = { + fileSystem, + doResolve: ( + step: string, + request: ResolveRequest, + message: string, + resolveContext: ResolveContext, + callback: (err: Error | undefined, result: ResolveRequest | undefined) => void + ) => { + return callback(undefined, request); + }, + ensureHook: (step: string) => { + expect(step).toEqual('target'); + }, + getHook: (step: string) => { + expect(step).toEqual('source'); + return { + tapAsync: ( + name: string, + cb: (request: ResolveRequest, resolveContext: ResolveContext, callback: () => void) => void + ) => { + innerCallback = cb; + } + }; + } + } as unknown as Resolver; + + // Backfill the contexts + for (const [path, json] of Object.entries(platformJson)) { + const contextList: IPrefixMatch | undefined = + cache.contextLookup.findLongestPrefixMatch(path); + if (!contextList) throw new Error(`No context found for ${path}`); + cache.contextForPackage.set(json, contextList); + } + + attachPlugins(cache, resolver); + + return ( + request: ResolveRequest, + resolveContext: ResolveContext + ): [Error | false | null | undefined, ResolveRequest | undefined] => { + let result!: [Error | false | null | undefined, ResolveRequest | undefined]; + innerCallback!(request, resolveContext, (( + err: Error | null | false | undefined, + next: ResolveRequest | undefined + ) => { + result = [err, next]; + }) as unknown as Parameters[2]); + return result; + }; +} diff --git a/webpack/webpack-workspace-resolve-plugin/tsconfig.json b/webpack/webpack-workspace-resolve-plugin/tsconfig.json new file mode 100644 index 00000000000..c4bf22522fe --- /dev/null +++ b/webpack/webpack-workspace-resolve-plugin/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2020", + "types": ["heft-jest", "node"] + } +} diff --git a/webpack/webpack4-localization-plugin/.npmignore b/webpack/webpack4-localization-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack4-localization-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack4-localization-plugin/CHANGELOG.json b/webpack/webpack4-localization-plugin/CHANGELOG.json new file mode 100644 index 00000000000..9c3e6d292a4 --- /dev/null +++ b/webpack/webpack4-localization-plugin/CHANGELOG.json @@ -0,0 +1,10387 @@ +{ + "name": "@rushstack/webpack4-localization-plugin", + "entries": [ + { + "version": "0.19.7", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.7", + "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/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": "0.19.6", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.6", + "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/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": "0.19.5", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.5", + "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`" + } + ] + } + }, + { + "version": "0.19.4", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.19.3", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.3", + "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/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": "0.19.2", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.2", + "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/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": "0.19.1", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.1", + "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/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": "0.19.0", + "tag": "@rushstack/webpack4-localization-plugin_v0.19.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/localization-utilities\" to `0.14.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`" + } + ] + } + }, + { + "version": "0.18.114", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.114", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.23`" + }, + { + "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": "0.18.113", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.113", + "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/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": "0.18.112", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.112", + "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`" + } + ] + } + }, + { + "version": "0.18.111", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.111", + "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/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.18.110", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.110", + "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`" + } + ] + } + }, + { + "version": "0.18.109", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.109", + "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/localization-utilities\" to `0.13.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.18.108", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.108", + "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/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": "0.18.107", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.107", + "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`" + } + ] + } + }, + { + "version": "0.18.106", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.106", + "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`" + } + ] + } + }, + { + "version": "0.18.105", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.105", + "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`" + } + ] + } + }, + { + "version": "0.18.104", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.104", + "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/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": "0.18.103", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.103", + "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`" + } + ] + } + }, + { + "version": "0.18.102", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.102", + "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`" + } + ] + } + }, + { + "version": "0.18.101", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.101", + "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`" + } + ] + } + }, + { + "version": "0.18.100", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.100", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.18.99", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.99", + "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`" + } + ] + } + }, + { + "version": "0.18.98", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.98", + "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`" + } + ] + } + }, + { + "version": "0.18.97", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.97", + "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/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": "0.18.96", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.96", + "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`" + } + ] + } + }, + { + "version": "0.18.95", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.95", + "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`" + } + ] + } + }, + { + "version": "0.18.94", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.94", + "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/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": "0.18.93", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.93", + "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`" + } + ] + } + }, + { + "version": "0.18.92", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.92", + "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`" + } + ] + } + }, + { + "version": "0.18.91", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.91", + "date": "Thu, 27 Feb 2025 16:10:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.18.90", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.90", + "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`" + } + ] + } + }, + { + "version": "0.18.89", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.89", + "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`" + } + ] + } + }, + { + "version": "0.18.88", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.88", + "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`" + } + ] + } + }, + { + "version": "0.18.87", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.87", + "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`" + } + ] + } + }, + { + "version": "0.18.86", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.86", + "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/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.18.85", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.85", + "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`" + } + ] + } + }, + { + "version": "0.18.84", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.84", + "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/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": "0.18.83", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.83", + "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/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": "0.18.82", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.82", + "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`" + } + ] + } + }, + { + "version": "0.18.81", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.81", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.18.80", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.80", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.18.79", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.79", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.18.78", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.78", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.18.77", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.77", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.18.76", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.76", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.18.75", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.75", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.18.74", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.74", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.18.73", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.73", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.18.72", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.72", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.18.71", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.71", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.18.70", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.70", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.18.69", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.69", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.18.68", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.68", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.18.67", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.67", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.18.66", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.66", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.18.65", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.65", + "date": "Wed, 21 Aug 2024 16:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.18.64", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.18.63", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.18.62", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.18.61", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.61`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.18.60", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.18.59", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.59`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.18.58", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.18.57", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.57", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.57`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.18.56", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.18.55", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.18.54", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.18.53", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.53", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.18.52", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.18.51", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.18.50", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.18.49", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.18.48", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.48", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.18.47", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.18.46", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.18.45", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.18.44", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.18.43", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.43", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.18.42", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.42", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.18.41", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.18.40", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.40", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.18.39", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.18.38", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.18.37", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.18.36", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.18.35", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.18.34", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.18.33", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.18.32", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.18.31", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.18.30", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.18.29", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.18.28", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.18.27", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.18.26", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.18.25", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.18.24", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.18.23", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.18.22", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.18.21", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.18.20", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.18.19", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.18.18", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.18.17", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.17", + "date": "Tue, 16 Jan 2024 18:30:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.18.16", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.15` to `^4.1.16`" + } + ] + } + }, + { + "version": "0.18.15", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.14` to `^4.1.15`" + } + ] + } + }, + { + "version": "0.18.14", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.13` to `^4.1.14`" + } + ] + } + }, + { + "version": "0.18.13", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.12` to `^4.1.13`" + } + ] + } + }, + { + "version": "0.18.12", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.11` to `^4.1.12`" + } + ] + } + }, + { + "version": "0.18.11", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.10` to `^4.1.11`" + } + ] + } + }, + { + "version": "0.18.10", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.9` to `^4.1.10`" + } + ] + } + }, + { + "version": "0.18.9", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.8` to `^4.1.9`" + } + ] + } + }, + { + "version": "0.18.8", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.7` to `^4.1.8`" + } + ] + } + }, + { + "version": "0.18.7", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.6` to `^4.1.7`" + } + ] + } + }, + { + "version": "0.18.6", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.5` to `^4.1.6`" + } + ] + } + }, + { + "version": "0.18.5", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.4` to `^4.1.5`" + } + ] + } + }, + { + "version": "0.18.4", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.3` to `^4.1.4`" + } + ] + } + }, + { + "version": "0.18.3", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.2` to `^4.1.3`" + } + ] + } + }, + { + "version": "0.18.2", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.1` to `^4.1.2`" + } + ] + } + }, + { + "version": "0.18.1", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.1.0` to `^4.1.1`" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/webpack4-localization-plugin_v0.18.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.17` to `^4.1.0`" + } + ] + } + }, + { + "version": "0.17.47", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.47", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.16` to `^4.0.17`" + } + ] + } + }, + { + "version": "0.17.46", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.46", + "date": "Thu, 07 Sep 2023 03:35:42 GMT", + "comments": { + "patch": [ + { + "comment": "Update Webpack peerDependency to ~4.47.0." + } + ] + } + }, + { + "version": "0.17.45", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.45", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.83`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.15` to `^4.0.16`" + } + ] + } + }, + { + "version": "0.17.44", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.44", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.82`" + } + ] + } + }, + { + "version": "0.17.43", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.43", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.81`" + } + ] + } + }, + { + "version": "0.17.42", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.42", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.14` to `^4.0.15`" + } + ] + } + }, + { + "version": "0.17.41", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.41", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.13` to `^4.0.14`" + } + ] + } + }, + { + "version": "0.17.40", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.40", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.12` to `^4.0.13`" + } + ] + } + }, + { + "version": "0.17.39", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.39", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.77`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.11` to `^4.0.12`" + } + ] + } + }, + { + "version": "0.17.38", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.38", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.10` to `^4.0.11`" + } + ] + } + }, + { + "version": "0.17.37", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.37", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.9` to `^4.0.10`" + } + ] + } + }, + { + "version": "0.17.36", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.36", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.8` to `^4.0.9`" + } + ] + } + }, + { + "version": "0.17.35", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.35", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.7` to `^4.0.8`" + } + ] + } + }, + { + "version": "0.17.34", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.34", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.6` to `^4.0.7`" + } + ] + } + }, + { + "version": "0.17.33", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.33", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.71`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.5` to `^4.0.6`" + } + ] + } + }, + { + "version": "0.17.32", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.32", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.4` to `^4.0.5`" + } + ] + } + }, + { + "version": "0.17.31", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.31", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.3` to `^4.0.4`" + } + ] + } + }, + { + "version": "0.17.30", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.30", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.68`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.2` to `^4.0.3`" + } + ] + } + }, + { + "version": "0.17.29", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.29", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.1` to `^4.0.2`" + } + ] + } + }, + { + "version": "0.17.28", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.28", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^4.0.0` to `^4.0.1`" + } + ] + } + }, + { + "version": "0.17.27", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.27", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.115` to `^4.0.0`" + } + ] + } + }, + { + "version": "0.17.26", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.26", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.115`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.114` to `^3.3.115`" + } + ] + } + }, + { + "version": "0.17.25", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.25", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.114`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.113` to `^3.3.114`" + } + ] + } + }, + { + "version": "0.17.24", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.24", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.113`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.112` to `^3.3.113`" + } + ] + } + }, + { + "version": "0.17.23", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.23", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.112`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.111` to `^3.3.112`" + } + ] + } + }, + { + "version": "0.17.22", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.22", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.111`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.110` to `^3.3.111`" + } + ] + } + }, + { + "version": "0.17.21", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.21", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.59`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.110`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.109` to `^3.3.110`" + } + ] + } + }, + { + "version": "0.17.20", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.20", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.109`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.108` to `^3.3.109`" + } + ] + } + }, + { + "version": "0.17.19", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.19", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.108`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.107` to `^3.3.108`" + } + ] + } + }, + { + "version": "0.17.18", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.18", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.107`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.106` to `^3.3.107`" + } + ] + } + }, + { + "version": "0.17.17", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.17", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.55`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.106`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.105` to `^3.3.106`" + } + ] + } + }, + { + "version": "0.17.16", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.16", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.105`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.104` to `^3.3.105`" + } + ] + } + }, + { + "version": "0.17.15", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.15", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.104`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.103` to `^3.3.104`" + } + ] + } + }, + { + "version": "0.17.14", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.14", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.103`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.102` to `^3.3.103`" + } + ] + } + }, + { + "version": "0.17.13", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.13", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.102`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.101` to `^3.3.102`" + } + ] + } + }, + { + "version": "0.17.12", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.12", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.101`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.100` to `^3.3.101`" + } + ] + } + }, + { + "version": "0.17.11", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.11", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.100`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.99` to `^3.3.100`" + } + ] + } + }, + { + "version": "0.17.10", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.10", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.99`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.98` to `^3.3.99`" + } + ] + } + }, + { + "version": "0.17.9", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.9", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.98`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.97` to `^3.3.98`" + } + ] + } + }, + { + "version": "0.17.8", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.8", + "date": "Fri, 07 Apr 2023 22:19:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.97`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.96` to `^3.3.97`" + } + ] + } + }, + { + "version": "0.17.7", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.7", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.96`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.95` to `^3.3.96`" + } + ] + } + }, + { + "version": "0.17.6", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.6", + "date": "Thu, 23 Mar 2023 15:24:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.95`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.94` to `^3.3.95`" + } + ] + } + }, + { + "version": "0.17.5", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.5", + "date": "Wed, 22 Mar 2023 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.94`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.93` to `^3.3.94`" + } + ] + } + }, + { + "version": "0.17.4", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.4", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.93`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.92` to `^3.3.93`" + } + ] + } + }, + { + "version": "0.17.3", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.3", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.92`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.91` to `^3.3.92`" + } + ] + } + }, + { + "version": "0.17.2", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.46`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.91`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.90` to `^3.3.91`" + } + ] + } + }, + { + "version": "0.17.1", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.45`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.90`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.89` to `^3.3.90`" + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/webpack4-localization-plugin_v0.17.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.89`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.88` to `^3.3.89`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/webpack4-localization-plugin_v0.16.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.88`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.87` to `^3.3.88`" + } + ] + } + }, + { + "version": "0.15.45", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.45", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.87`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.86` to `^3.3.87`" + } + ] + } + }, + { + "version": "0.15.44", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.44", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.86`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.85` to `^3.3.86`" + } + ] + } + }, + { + "version": "0.15.43", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.43", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.85`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.84` to `^3.3.85`" + } + ] + } + }, + { + "version": "0.15.42", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.42", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.84`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.83` to `^3.3.84`" + } + ] + } + }, + { + "version": "0.15.41", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.41", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.83`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.82` to `^3.3.83`" + } + ] + } + }, + { + "version": "0.15.40", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.40", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.37`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.82`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.81` to `^3.3.82`" + } + ] + } + }, + { + "version": "0.15.39", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.39", + "date": "Fri, 02 Dec 2022 01:15:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.81`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.80` to `^3.3.81`" + } + ] + } + }, + { + "version": "0.15.38", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.38", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.36`" + } + ] + } + }, + { + "version": "0.15.37", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.37", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.80`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.79` to `^3.3.80`" + } + ] + } + }, + { + "version": "0.15.36", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.36", + "date": "Mon, 14 Nov 2022 05:15:02 GMT", + "comments": { + "patch": [ + { + "comment": "Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq" + } + ] + } + }, + { + "version": "0.15.35", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.35", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.79`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.78` to `^3.3.79`" + } + ] + } + }, + { + "version": "0.15.34", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.34", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.78`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.77` to `^3.3.78`" + } + ] + } + }, + { + "version": "0.15.33", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.33", + "date": "Tue, 25 Oct 2022 00:20:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.77`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.76` to `^3.3.77`" + } + ] + } + }, + { + "version": "0.15.32", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.32", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.76`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.75` to `^3.3.76`" + } + ] + } + }, + { + "version": "0.15.31", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.31", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.75`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.74` to `^3.3.75`" + } + ] + } + }, + { + "version": "0.15.30", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.30", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.74`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.73` to `^3.3.74`" + } + ] + } + }, + { + "version": "0.15.29", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.29", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.73`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.72` to `^3.3.73`" + } + ] + } + }, + { + "version": "0.15.28", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.28", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.72`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.71` to `^3.3.72`" + } + ] + } + }, + { + "version": "0.15.27", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.27", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.71`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.70` to `^3.3.71`" + } + ] + } + }, + { + "version": "0.15.26", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.26", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.70`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.69` to `^3.3.70`" + } + ] + } + }, + { + "version": "0.15.25", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.25", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.69`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.68` to `^3.3.69`" + } + ] + } + }, + { + "version": "0.15.24", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.24", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.68`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.67` to `^3.3.68`" + } + ] + } + }, + { + "version": "0.15.23", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.23", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.67`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.66` to `^3.3.67`" + } + ] + } + }, + { + "version": "0.15.22", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.22", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.66`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.65` to `^3.3.66`" + } + ] + } + }, + { + "version": "0.15.21", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.21", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.65`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.64` to `^3.3.65`" + } + ] + } + }, + { + "version": "0.15.20", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.20", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.64`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.63` to `^3.3.64`" + } + ] + } + }, + { + "version": "0.15.19", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.19", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.63`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.62` to `^3.3.63`" + } + ] + } + }, + { + "version": "0.15.18", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.18", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.62`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.61` to `^3.3.62`" + } + ] + } + }, + { + "version": "0.15.17", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.17", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.61`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.60` to `^3.3.61`" + } + ] + } + }, + { + "version": "0.15.16", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.16", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.60`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.59` to `^3.3.60`" + } + ] + } + }, + { + "version": "0.15.15", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.15", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.59`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.58` to `^3.3.59`" + } + ] + } + }, + { + "version": "0.15.14", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.14", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.58`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.57` to `^3.3.58`" + } + ] + } + }, + { + "version": "0.15.13", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.13", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.57`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.56` to `^3.3.57`" + } + ] + } + }, + { + "version": "0.15.12", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.12", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.56`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.55` to `^3.3.56`" + } + ] + } + }, + { + "version": "0.15.11", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.11", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.55`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.54` to `^3.3.55`" + } + ] + } + }, + { + "version": "0.15.10", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.10", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.54`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.53` to `^3.3.54`" + } + ] + } + }, + { + "version": "0.15.9", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.9", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.53`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.52` to `^3.3.53`" + } + ] + } + }, + { + "version": "0.15.8", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.8", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.52`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.51` to `^3.3.52`" + } + ] + } + }, + { + "version": "0.15.7", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.7", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.51`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.50` to `^3.3.51`" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.6", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.50`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.49` to `^3.3.50`" + } + ] + } + }, + { + "version": "0.15.5", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.5", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.49`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.48` to `^3.3.49`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.4", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.48`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.47` to `^3.3.48`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.3", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.47`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.46` to `^3.3.47`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.2", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.46`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.45` to `^3.3.46`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.1", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.45`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.44` to `^3.3.45`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/webpack4-localization-plugin_v0.15.0", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to output typings to additional output folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.44`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.43` to `^3.3.44`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/webpack4-localization-plugin_v0.14.6", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.43`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.42` to `^3.3.43`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/webpack4-localization-plugin_v0.14.5", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "patch": [ + { + "comment": "Rename from @rushstack/localization-plugin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.42`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.41` to `^3.3.42`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/localization-plugin_v0.14.4", + "date": "Fri, 17 Jun 2022 09:17:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.41`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.40` to `^3.3.41`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/localization-plugin_v0.14.3", + "date": "Fri, 17 Jun 2022 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Bump @types/webpack" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.40`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.39` to `^3.3.40`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/localization-plugin_v0.14.2", + "date": "Thu, 16 Jun 2022 22:49:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/localization-plugin_v0.14.1", + "date": "Thu, 16 Jun 2022 00:20:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/localization-plugin_v0.14.0", + "date": "Tue, 14 Jun 2022 23:11:36 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Move the `ignoreString` option from the `typingsGeneration` object to the root of the options object. It is now used to remove strings from both typings and from loc file parsing." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/localization-plugin_v0.13.2", + "date": "Tue, 14 Jun 2022 00:17:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/localization-plugin_v0.13.1", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.39`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.38` to `^3.3.39`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/localization-plugin_v0.13.0", + "date": "Fri, 03 Jun 2022 00:11:05 GMT", + "comments": { + "minor": [ + { + "comment": "Add the ability to tweak string comments in generated typings." + }, + { + "comment": "Include an option to ignore strings from typings generation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/localization-plugin_v0.12.0", + "date": "Wed, 01 Jun 2022 23:31:32 GMT", + "comments": { + "minor": [ + { + "comment": "Extract utilities to @rushstack/localization-utilitiles." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/localization-plugin_v0.11.1", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.37` to `^3.3.38`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/localization-plugin_v0.11.0", + "date": "Tue, 24 May 2022 15:12:19 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for .resjson files" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/localization-plugin_v0.10.21", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.36` to `^3.3.37`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/localization-plugin_v0.10.20", + "date": "Wed, 18 May 2022 15:10:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.35` to `^3.3.36`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/localization-plugin_v0.10.19", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.34` to `^3.3.35`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/localization-plugin_v0.10.18", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.33` to `^3.3.34`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/localization-plugin_v0.10.17", + "date": "Fri, 06 May 2022 18:54:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.32` to `^3.3.33`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/localization-plugin_v0.10.16", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.31` to `^3.3.32`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/localization-plugin_v0.10.15", + "date": "Wed, 04 May 2022 02:35:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.30` to `^3.3.31`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/localization-plugin_v0.10.14", + "date": "Wed, 27 Apr 2022 01:19:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.29` to `^3.3.30`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/localization-plugin_v0.10.13", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.28` to `^3.3.29`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/localization-plugin_v0.10.12", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.27` to `^3.3.28`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/localization-plugin_v0.10.11", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.26` to `^3.3.27`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/localization-plugin_v0.10.10", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.25` to `^3.3.26`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/localization-plugin_v0.10.9", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.24` to `^3.3.25`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/localization-plugin_v0.10.8", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.23` to `^3.3.24`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/localization-plugin_v0.10.7", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.22` to `^3.3.23`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/localization-plugin_v0.10.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.21` to `^3.3.22`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/localization-plugin_v0.10.5", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.20` to `^3.3.21`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/localization-plugin_v0.10.4", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.19` to `^3.3.20`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/localization-plugin_v0.10.3", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.18` to `^3.3.19`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/localization-plugin_v0.10.2", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.17` to `^3.3.18`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/localization-plugin_v0.10.1", + "date": "Tue, 15 Mar 2022 19:15:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.16` to `^3.3.17`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/localization-plugin_v0.10.0", + "date": "Wed, 16 Feb 2022 07:15:28 GMT", + "comments": { + "minor": [ + { + "comment": "Add an option to ignore missing RESX comments." + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/localization-plugin_v0.9.15", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.15` to `^3.3.16`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/localization-plugin_v0.9.14", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.14` to `^3.3.15`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/localization-plugin_v0.9.13", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.13` to `^3.3.14`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/localization-plugin_v0.9.12", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.12` to `^3.3.13`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/localization-plugin_v0.9.11", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.11` to `^3.3.12`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/localization-plugin_v0.9.10", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.10` to `^3.3.11`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/localization-plugin_v0.9.9", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.9` to `^3.3.10`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/localization-plugin_v0.9.8", + "date": "Fri, 10 Dec 2021 01:09:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/localization-plugin_v0.9.7", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.8` to `^3.3.9`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/localization-plugin_v0.9.6", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.7` to `^3.3.8`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/localization-plugin_v0.9.5", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.6` to `^3.3.7`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/localization-plugin_v0.9.4", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.5` to `^3.3.6`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/localization-plugin_v0.9.3", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.4` to `^3.3.5`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/localization-plugin_v0.9.2", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.3` to `^3.3.4`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/localization-plugin_v0.9.1", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.2` to `^3.3.3`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/localization-plugin_v0.9.0", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove \"filesToIgnore\" option in favor of \"globsToIgnore.\"" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.1` to `^3.3.2`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/localization-plugin_v0.8.0", + "date": "Tue, 16 Nov 2021 16:08:01 GMT", + "comments": { + "minor": [ + { + "comment": "Accept .resx.json as an alternative strings file extension." + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/localization-plugin_v0.7.13", + "date": "Thu, 11 Nov 2021 01:17:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.3.0` to `^3.3.1`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/localization-plugin_v0.7.12", + "date": "Wed, 10 Nov 2021 16:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.90` to `^3.3.0`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/localization-plugin_v0.7.11", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.90`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.89` to `^3.2.90`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/localization-plugin_v0.7.10", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.89`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.88` to `^3.2.89`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/localization-plugin_v0.7.9", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.88`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.87` to `^3.2.88`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/localization-plugin_v0.7.8", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.87`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.86` to `^3.2.87`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/localization-plugin_v0.7.7", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.86`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.85` to `^3.2.86`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/localization-plugin_v0.7.6", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.85`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.84` to `^3.2.85`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/localization-plugin_v0.7.5", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.84`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.83` to `^3.2.84`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/localization-plugin_v0.7.4", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.83`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.82` to `^3.2.83`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/localization-plugin_v0.7.3", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.82`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.81` to `^3.2.82`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/localization-plugin_v0.7.2", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.81`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.80` to `^3.2.81`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/localization-plugin_v0.7.1", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.80`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.79` to `^3.2.80`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/localization-plugin_v0.7.0", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "minor": [ + { + "comment": "Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.79`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.78` to `^3.2.79`" + } + ] + } + }, + { + "version": "0.6.58", + "tag": "@rushstack/localization-plugin_v0.6.58", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.78`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.77` to `^3.2.78`" + } + ] + } + }, + { + "version": "0.6.57", + "tag": "@rushstack/localization-plugin_v0.6.57", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.77`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.76` to `^3.2.77`" + } + ] + } + }, + { + "version": "0.6.56", + "tag": "@rushstack/localization-plugin_v0.6.56", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.76`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.75` to `^3.2.76`" + } + ] + } + }, + { + "version": "0.6.55", + "tag": "@rushstack/localization-plugin_v0.6.55", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.75`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.74` to `^3.2.75`" + } + ] + } + }, + { + "version": "0.6.54", + "tag": "@rushstack/localization-plugin_v0.6.54", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.74`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.73` to `^3.2.74`" + } + ] + } + }, + { + "version": "0.6.53", + "tag": "@rushstack/localization-plugin_v0.6.53", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.73`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.72` to `^3.2.73`" + } + ] + } + }, + { + "version": "0.6.52", + "tag": "@rushstack/localization-plugin_v0.6.52", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.72`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.71` to `^3.2.72`" + } + ] + } + }, + { + "version": "0.6.51", + "tag": "@rushstack/localization-plugin_v0.6.51", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.71`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.70` to `^3.2.71`" + } + ] + } + }, + { + "version": "0.6.50", + "tag": "@rushstack/localization-plugin_v0.6.50", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.70`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.69` to `^3.2.70`" + } + ] + } + }, + { + "version": "0.6.49", + "tag": "@rushstack/localization-plugin_v0.6.49", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.69`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.68` to `^3.2.69`" + } + ] + } + }, + { + "version": "0.6.48", + "tag": "@rushstack/localization-plugin_v0.6.48", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.68`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.67` to `^3.2.68`" + } + ] + } + }, + { + "version": "0.6.47", + "tag": "@rushstack/localization-plugin_v0.6.47", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.67`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.66` to `^3.2.67`" + } + ] + } + }, + { + "version": "0.6.46", + "tag": "@rushstack/localization-plugin_v0.6.46", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.66`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.65` to `^3.2.66`" + } + ] + } + }, + { + "version": "0.6.45", + "tag": "@rushstack/localization-plugin_v0.6.45", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.65`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.64` to `^3.2.65`" + } + ] + } + }, + { + "version": "0.6.44", + "tag": "@rushstack/localization-plugin_v0.6.44", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.64`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.63` to `^3.2.64`" + } + ] + } + }, + { + "version": "0.6.43", + "tag": "@rushstack/localization-plugin_v0.6.43", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.63`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.62` to `^3.2.63`" + } + ] + } + }, + { + "version": "0.6.42", + "tag": "@rushstack/localization-plugin_v0.6.42", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.62`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.61` to `^3.2.62`" + } + ] + } + }, + { + "version": "0.6.41", + "tag": "@rushstack/localization-plugin_v0.6.41", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.61`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.60` to `^3.2.61`" + } + ] + } + }, + { + "version": "0.6.40", + "tag": "@rushstack/localization-plugin_v0.6.40", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.60`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.59` to `^3.2.60`" + } + ] + } + }, + { + "version": "0.6.39", + "tag": "@rushstack/localization-plugin_v0.6.39", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.59`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.58` to `^3.2.59`" + } + ] + } + }, + { + "version": "0.6.38", + "tag": "@rushstack/localization-plugin_v0.6.38", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.58`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.57` to `^3.2.58`" + } + ] + } + }, + { + "version": "0.6.37", + "tag": "@rushstack/localization-plugin_v0.6.37", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.57`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.56` to `^3.2.57`" + } + ] + } + }, + { + "version": "0.6.36", + "tag": "@rushstack/localization-plugin_v0.6.36", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.56`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.55` to `^3.2.56`" + } + ] + } + }, + { + "version": "0.6.35", + "tag": "@rushstack/localization-plugin_v0.6.35", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.55`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.54` to `^3.2.55`" + } + ] + } + }, + { + "version": "0.6.34", + "tag": "@rushstack/localization-plugin_v0.6.34", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.54`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.53` to `^3.2.54`" + } + ] + } + }, + { + "version": "0.6.33", + "tag": "@rushstack/localization-plugin_v0.6.33", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.53`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.52` to `^3.2.53`" + } + ] + } + }, + { + "version": "0.6.32", + "tag": "@rushstack/localization-plugin_v0.6.32", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.52`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.51` to `^3.2.52`" + } + ] + } + }, + { + "version": "0.6.31", + "tag": "@rushstack/localization-plugin_v0.6.31", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.51`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.50` to `^3.2.51`" + } + ] + } + }, + { + "version": "0.6.30", + "tag": "@rushstack/localization-plugin_v0.6.30", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.50`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.49` to `^3.2.50`" + } + ] + } + }, + { + "version": "0.6.29", + "tag": "@rushstack/localization-plugin_v0.6.29", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.49`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.48` to `^3.2.49`" + } + ] + } + }, + { + "version": "0.6.28", + "tag": "@rushstack/localization-plugin_v0.6.28", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.48`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.47` to `^3.2.48`" + } + ] + } + }, + { + "version": "0.6.27", + "tag": "@rushstack/localization-plugin_v0.6.27", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.47`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.46` to `^3.2.47`" + } + ] + } + }, + { + "version": "0.6.26", + "tag": "@rushstack/localization-plugin_v0.6.26", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.46`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.45` to `^3.2.46`" + } + ] + } + }, + { + "version": "0.6.25", + "tag": "@rushstack/localization-plugin_v0.6.25", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.45`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.44` to `^3.2.45`" + } + ] + } + }, + { + "version": "0.6.24", + "tag": "@rushstack/localization-plugin_v0.6.24", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.44`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.43` to `^3.2.44`" + } + ] + } + }, + { + "version": "0.6.23", + "tag": "@rushstack/localization-plugin_v0.6.23", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.43`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.42` to `^3.2.43`" + } + ] + } + }, + { + "version": "0.6.22", + "tag": "@rushstack/localization-plugin_v0.6.22", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.42`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.41` to `^3.2.42`" + } + ] + } + }, + { + "version": "0.6.21", + "tag": "@rushstack/localization-plugin_v0.6.21", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.41`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.40` to `^3.2.41`" + } + ] + } + }, + { + "version": "0.6.20", + "tag": "@rushstack/localization-plugin_v0.6.20", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.40`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.39` to `^3.2.40`" + } + ] + } + }, + { + "version": "0.6.19", + "tag": "@rushstack/localization-plugin_v0.6.19", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.39`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.38` to `^3.2.39`" + } + ] + } + }, + { + "version": "0.6.18", + "tag": "@rushstack/localization-plugin_v0.6.18", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.38`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.37` to `^3.2.38`" + } + ] + } + }, + { + "version": "0.6.17", + "tag": "@rushstack/localization-plugin_v0.6.17", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.36` to `^3.2.37`" + } + ] + } + }, + { + "version": "0.6.16", + "tag": "@rushstack/localization-plugin_v0.6.16", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.35` to `^3.2.36`" + } + ] + } + }, + { + "version": "0.6.15", + "tag": "@rushstack/localization-plugin_v0.6.15", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.35`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.34` to `^3.2.35`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/localization-plugin_v0.6.14", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.34`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.33` to `^3.2.34`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/localization-plugin_v0.6.13", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.33`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.32` to `^3.2.33`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/localization-plugin_v0.6.12", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.31` to `^3.2.32`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/localization-plugin_v0.6.11", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.30` to `^3.2.31`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/localization-plugin_v0.6.10", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.29` to `^3.2.30`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/localization-plugin_v0.6.9", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.28` to `^3.2.29`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/localization-plugin_v0.6.8", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.27` to `^3.2.28`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/localization-plugin_v0.6.7", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.26` to `^3.2.27`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/localization-plugin_v0.6.6", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.25` to `^3.2.26`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/localization-plugin_v0.6.5", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.24` to `^3.2.25`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/localization-plugin_v0.6.4", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.23` to `^3.2.24`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/localization-plugin_v0.6.3", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.22` to `^3.2.23`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/localization-plugin_v0.6.2", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.21` to `^3.2.22`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/localization-plugin_v0.6.1", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.20` to `^3.2.21`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/localization-plugin_v0.6.0", + "date": "Thu, 08 Apr 2021 06:05:31 GMT", + "comments": { + "minor": [ + { + "comment": "Fix parameter name typo." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.19` to `^3.2.20`" + } + ] + } + }, + { + "version": "0.5.38", + "tag": "@rushstack/localization-plugin_v0.5.38", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.18` to `^3.2.19`" + } + ] + } + }, + { + "version": "0.5.37", + "tag": "@rushstack/localization-plugin_v0.5.37", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.17` to `^3.2.18`" + } + ] + } + }, + { + "version": "0.5.36", + "tag": "@rushstack/localization-plugin_v0.5.36", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.16` to `^3.2.17`" + } + ] + } + }, + { + "version": "0.5.35", + "tag": "@rushstack/localization-plugin_v0.5.35", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.15` to `^3.2.16`" + } + ] + } + }, + { + "version": "0.5.34", + "tag": "@rushstack/localization-plugin_v0.5.34", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.14` to `^3.2.15`" + } + ] + } + }, + { + "version": "0.5.33", + "tag": "@rushstack/localization-plugin_v0.5.33", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.13` to `^3.2.14`" + } + ] + } + }, + { + "version": "0.5.32", + "tag": "@rushstack/localization-plugin_v0.5.32", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.12` to `^3.2.13`" + } + ] + } + }, + { + "version": "0.5.31", + "tag": "@rushstack/localization-plugin_v0.5.31", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.11` to `^3.2.12`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/localization-plugin_v0.5.30", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.10` to `^3.2.11`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/localization-plugin_v0.5.29", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.9` to `^3.2.10`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/localization-plugin_v0.5.28", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.8` to `^3.2.9`" + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/localization-plugin_v0.5.27", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.7` to `^3.2.8`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/localization-plugin_v0.5.26", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.6` to `^3.2.7`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/localization-plugin_v0.5.25", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.5` to `^3.2.6`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/localization-plugin_v0.5.24", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.4` to `^3.2.5`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/localization-plugin_v0.5.23", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.3` to `^3.2.4`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/localization-plugin_v0.5.22", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.2` to `^3.2.3`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/localization-plugin_v0.5.21", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.1` to `^3.2.2`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/localization-plugin_v0.5.20", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.32`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.2.0` to `^3.2.1`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/localization-plugin_v0.5.19", + "date": "Tue, 08 Dec 2020 01:10:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.19` to `^3.2.0`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/localization-plugin_v0.5.18", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.18` to `^3.1.19`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/localization-plugin_v0.5.17", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.17` to `^3.1.18`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/localization-plugin_v0.5.16", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.16` to `^3.1.17`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/localization-plugin_v0.5.15", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.15` to `^3.1.16`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/localization-plugin_v0.5.14", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.14` to `^3.1.15`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/localization-plugin_v0.5.13", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.13` to `^3.1.14`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/localization-plugin_v0.5.12", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.12` to `^3.1.13`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/localization-plugin_v0.5.11", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.11` to `^3.1.12`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/localization-plugin_v0.5.10", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.10` to `^3.1.11`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/localization-plugin_v0.5.9", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.26`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.9` to `^3.1.10`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/localization-plugin_v0.5.8", + "date": "Tue, 10 Nov 2020 23:13:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.8` to `^3.1.9`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/localization-plugin_v0.5.7", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.7` to `^3.1.8`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/localization-plugin_v0.5.6", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.6` to `^3.1.7`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/localization-plugin_v0.5.5", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.5` to `^3.1.6`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/localization-plugin_v0.5.4", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.4` to `^3.1.5`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/localization-plugin_v0.5.3", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.3` to `^3.1.4`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/localization-plugin_v0.5.2", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.2` to `^3.1.3`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/localization-plugin_v0.5.1", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.1` to `^3.1.2`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/localization-plugin_v0.5.0", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @types/tapable" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.1.0` to `^3.1.1`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/localization-plugin_v0.4.0", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to ~4.44.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.18` to `^3.1.0`" + } + ] + } + }, + { + "version": "0.3.85", + "tag": "@rushstack/localization-plugin_v0.3.85", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.17` to `^3.0.18`" + } + ] + } + }, + { + "version": "0.3.84", + "tag": "@rushstack/localization-plugin_v0.3.84", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.16` to `^3.0.17`" + } + ] + } + }, + { + "version": "0.3.83", + "tag": "@rushstack/localization-plugin_v0.3.83", + "date": "Sat, 24 Oct 2020 00:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.15` to `^3.0.16`" + } + ] + } + }, + { + "version": "0.3.82", + "tag": "@rushstack/localization-plugin_v0.3.82", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.14` to `^3.0.15`" + } + ] + } + }, + { + "version": "0.3.81", + "tag": "@rushstack/localization-plugin_v0.3.81", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.13` to `^3.0.14`" + } + ] + } + }, + { + "version": "0.3.80", + "tag": "@rushstack/localization-plugin_v0.3.80", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.12` to `^3.0.13`" + } + ] + } + }, + { + "version": "0.3.79", + "tag": "@rushstack/localization-plugin_v0.3.79", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.11` to `^3.0.12`" + } + ] + } + }, + { + "version": "0.3.78", + "tag": "@rushstack/localization-plugin_v0.3.78", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.10` to `^3.0.11`" + } + ] + } + }, + { + "version": "0.3.77", + "tag": "@rushstack/localization-plugin_v0.3.77", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.9` to `^3.0.10`" + } + ] + } + }, + { + "version": "0.3.76", + "tag": "@rushstack/localization-plugin_v0.3.76", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.8` to `^3.0.9`" + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/localization-plugin_v0.3.75", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.7` to `^3.0.8`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/localization-plugin_v0.3.74", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.6` to `^3.0.7`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/localization-plugin_v0.3.73", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.5` to `^3.0.6`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/localization-plugin_v0.3.72", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.4` to `^3.0.5`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/localization-plugin_v0.3.71", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.3` to `^3.0.4`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/localization-plugin_v0.3.70", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.2` to `^3.0.3`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/localization-plugin_v0.3.69", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.1` to `^3.0.2`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/localization-plugin_v0.3.68", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^3.0.0` to `^3.0.1`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/localization-plugin_v0.3.67", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.65` to `^3.0.0`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/localization-plugin_v0.3.66", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.64` to `^2.4.65`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/localization-plugin_v0.3.65", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.63` to `^2.4.64`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/localization-plugin_v0.3.64", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.62` to `^2.4.63`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/localization-plugin_v0.3.63", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.7`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.61` to `^2.4.62`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/localization-plugin_v0.3.62", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.60` to `^2.4.61`" + } + ] + } + }, + { + "version": "0.3.61", + "tag": "@rushstack/localization-plugin_v0.3.61", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.59` to `^2.4.60`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/localization-plugin_v0.3.60", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.58` to `^2.4.59`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/localization-plugin_v0.3.59", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.57` to `^2.4.58`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/localization-plugin_v0.3.58", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.56` to `^2.4.57`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/localization-plugin_v0.3.57", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.55` to `^2.4.56`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/localization-plugin_v0.3.56", + "date": "Sun, 13 Sep 2020 06:39:08 GMT", + "comments": { + "patch": [ + { + "comment": "Handle webpack dev server hot updates." + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/localization-plugin_v0.3.55", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "patch": [ + { + "comment": "Update typings generator dependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.54` to `^2.4.55`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/localization-plugin_v0.3.54", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.52`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.53` to `^2.4.54`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/localization-plugin_v0.3.53", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.51`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.52` to `^2.4.53`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/localization-plugin_v0.3.52", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.50`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.51` to `^2.4.52`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/localization-plugin_v0.3.51", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.50` to `^2.4.51`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/localization-plugin_v0.3.50", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.49` to `^2.4.50`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/localization-plugin_v0.3.49", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.48` to `^2.4.49`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/localization-plugin_v0.3.48", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.47` to `^2.4.48`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/localization-plugin_v0.3.47", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.46` to `^2.4.47`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/localization-plugin_v0.3.46", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.45` to `^2.4.46`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/localization-plugin_v0.3.45", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.44` to `^2.4.45`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/localization-plugin_v0.3.44", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.43` to `^2.4.44`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/localization-plugin_v0.3.43", + "date": "Mon, 24 Aug 2020 07:35:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.42` to `^2.4.43`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/localization-plugin_v0.3.42", + "date": "Sat, 22 Aug 2020 05:55:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.41` to `^2.4.42`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/localization-plugin_v0.3.41", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.40` to `^2.4.41`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/localization-plugin_v0.3.40", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.39` to `^2.4.40`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/localization-plugin_v0.3.39", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.38` to `^2.4.39`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/localization-plugin_v0.3.38", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.37` to `^2.4.38`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/localization-plugin_v0.3.37", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.36` to `^2.4.37`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/localization-plugin_v0.3.36", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.35` to `^2.4.36`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/localization-plugin_v0.3.35", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.34` to `^2.4.35`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/localization-plugin_v0.3.34", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.33` to `^2.4.34`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/localization-plugin_v0.3.33", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.32` to `^2.4.33`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/localization-plugin_v0.3.32", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.31` to `^2.4.32`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/localization-plugin_v0.3.31", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.26.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.4.30` to `^2.4.31`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/localization-plugin_v0.3.30", + "date": "Fri, 24 Jul 2020 20:40:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix broken peer dependency specifier" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/localization-plugin_v0.3.29", + "date": "Wed, 15 Jul 2020 15:09:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix specification of optional peerDependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" to `2.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `^2.3.4` to `^2.4.30`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/localization-plugin_v0.3.28", + "date": "Tue, 14 Jul 2020 19:32:58 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the way the loc file typings are generated in watch mode for large projects." + }, + { + "comment": "Make @types/webpack an optionalPeerDependency instead of a peerDependency." + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/localization-plugin_v0.3.27", + "date": "Tue, 07 Jul 2020 00:09:39 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the localization plugin would throw if resolveMissingTranslatedStrings returns undefined for a locale." + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/localization-plugin_v0.3.26", + "date": "Fri, 03 Jul 2020 15:09:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.4` to `3.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.27` to `0.1.28`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.8.0` to `0.8.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.31` to `6.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.28` to `2.4.29`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/localization-plugin_v0.3.25", + "date": "Fri, 03 Jul 2020 05:46:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.26` to `0.1.27`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.2` to `0.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.30` to `6.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.27` to `2.4.28`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/localization-plugin_v0.3.24", + "date": "Sat, 27 Jun 2020 00:09:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.25` to `0.1.26`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.29` to `6.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.26` to `2.4.27`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/localization-plugin_v0.3.23", + "date": "Fri, 26 Jun 2020 22:16:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.24` to `0.1.25`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.28` to `6.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.25` to `2.4.26`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/localization-plugin_v0.3.22", + "date": "Thu, 25 Jun 2020 06:43:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.3` to `3.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.23` to `0.1.24`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.1` to `0.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.27` to `6.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.24` to `2.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.1` to `1.0.2`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/localization-plugin_v0.3.21", + "date": "Wed, 24 Jun 2020 09:50:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.2` to `3.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.22` to `0.1.23`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.7.0` to `0.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.26` to `6.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.23` to `2.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `1.0.0` to `1.0.1`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/localization-plugin_v0.3.20", + "date": "Wed, 24 Jun 2020 09:04:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.1` to `3.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.21` to `0.1.22`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.1` to `0.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.25` to `6.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.22` to `2.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.8` to `1.0.0`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/localization-plugin_v0.3.19", + "date": "Mon, 15 Jun 2020 22:17:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.20` to `0.1.21`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.6.0` to `0.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.24` to `6.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.21` to `2.4.22`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/localization-plugin_v0.3.18", + "date": "Fri, 12 Jun 2020 09:19:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.19` to `0.1.20`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.3` to `0.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.23` to `6.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.20` to `2.4.21`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/localization-plugin_v0.3.17", + "date": "Wed, 10 Jun 2020 20:48:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.24.0` to `3.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.18` to `0.1.19`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.2` to `0.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.22` to `6.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.19` to `2.4.20`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/localization-plugin_v0.3.16", + "date": "Mon, 01 Jun 2020 08:34:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.17` to `0.1.18`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.1` to `0.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.21` to `6.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.18` to `2.4.19`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/localization-plugin_v0.3.15", + "date": "Sat, 30 May 2020 02:59:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.1` to `3.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.16` to `0.1.17`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.5.0` to `0.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.20` to `6.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.17` to `2.4.18`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/localization-plugin_v0.3.14", + "date": "Thu, 28 May 2020 05:59:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.23.0` to `3.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.15` to `0.1.16`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.17` to `0.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.19` to `6.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.16` to `2.4.17`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/localization-plugin_v0.3.13", + "date": "Wed, 27 May 2020 05:15:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.1` to `3.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.14` to `0.1.15`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.16` to `0.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.18` to `6.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.15` to `2.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.7` to `0.5.8`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/localization-plugin_v0.3.12", + "date": "Tue, 26 May 2020 23:00:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.22.0` to `3.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.13` to `0.1.14`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.15` to `0.4.16`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.17` to `6.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.14` to `2.4.15`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/localization-plugin_v0.3.11", + "date": "Fri, 22 May 2020 15:08:42 GMT", + "comments": { + "patch": [ + { + "comment": "Remove unnecessary jju dependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.21.0` to `3.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.12` to `0.1.13`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.14` to `0.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.16` to `6.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.13` to `2.4.14`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/localization-plugin_v0.3.10", + "date": "Thu, 21 May 2020 23:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.20.0` to `3.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.11` to `0.1.12`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.13` to `0.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.15` to `6.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.12` to `2.4.13`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/localization-plugin_v0.3.9", + "date": "Thu, 21 May 2020 15:42:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.7` to `3.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.10` to `0.1.11`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.12` to `0.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.14` to `6.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.11` to `2.4.12`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/localization-plugin_v0.3.8", + "date": "Tue, 19 May 2020 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.9` to `0.1.10`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.11` to `0.4.12`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.13` to `6.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.10` to `2.4.11`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/localization-plugin_v0.3.7", + "date": "Fri, 15 May 2020 08:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.8` to `0.1.9`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.10` to `0.4.11`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.12` to `6.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.9` to `2.4.10`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/localization-plugin_v0.3.6", + "date": "Wed, 13 May 2020 19:10:53 GMT", + "comments": { + "patch": [ + { + "comment": "Fix encoding of tab characters." + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/localization-plugin_v0.3.5", + "date": "Wed, 06 May 2020 08:23:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.7` to `0.1.8`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.9` to `0.4.10`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.11` to `6.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.8` to `2.4.9`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/localization-plugin_v0.3.4", + "date": "Sat, 02 May 2020 00:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.6` to `0.1.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.10` to `6.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.7` to `2.4.8`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/localization-plugin_v0.3.3", + "date": "Fri, 01 May 2020 05:15:06 GMT", + "comments": { + "patch": [ + { + "comment": "Don't trim RESX text elements." + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/localization-plugin_v0.3.2", + "date": "Wed, 08 Apr 2020 08:11:13 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the chunk URL generation code would mark some localized chunks as non-localized." + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/localization-plugin_v0.3.1", + "date": "Wed, 08 Apr 2020 04:07:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.6` to `3.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.5` to `0.1.6`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.8` to `0.4.9`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.9` to `6.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.6` to `2.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.6` to `0.5.7`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/localization-plugin_v0.3.0", + "date": "Mon, 06 Apr 2020 05:52:56 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where some characters weren't escaped correctly." + }, + { + "comment": "Fix sourcemap filenames." + } + ], + "minor": [ + { + "comment": "Add support for normalization of newlines in RESX files." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.5` to `2.4.6`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/localization-plugin_v0.2.2", + "date": "Fri, 03 Apr 2020 15:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.4` to `0.1.5`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.7` to `0.4.8`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.8` to `6.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.4` to `2.4.5`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/localization-plugin_v0.2.1", + "date": "Sun, 29 Mar 2020 00:04:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.3` to `0.1.4`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.6` to `0.4.7`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.7` to `6.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.3` to `2.4.4`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/localization-plugin_v0.2.0", + "date": "Sat, 28 Mar 2020 01:38:47 GMT", + "comments": { + "minor": [ + { + "comment": "Fix a few RESX parsing issues and improve translated strings resolution." + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/localization-plugin_v0.1.4", + "date": "Sat, 28 Mar 2020 00:37:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.5` to `3.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.2` to `0.1.3`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.5` to `0.4.6`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.6` to `6.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.2` to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.5` to `0.5.6`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/localization-plugin_v0.1.3", + "date": "Wed, 18 Mar 2020 15:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.4` to `3.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.1` to `0.1.2`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.4` to `0.4.5`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.5` to `6.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.1` to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" from `0.5.4` to `0.5.5`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/localization-plugin_v0.1.2", + "date": "Tue, 17 Mar 2020 23:55:58 GMT", + "comments": { + "patch": [ + { + "comment": "Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" from `3.19.3` to `3.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.1.0` to `0.1.1`" + }, + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" from `0.4.3` to `0.4.4`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" from `6.4.4` to `6.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/set-webpack-public-path-plugin\" from `2.4.0` to `2.4.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/localization-plugin_v0.1.1", + "date": "Thu, 12 Mar 2020 15:08:44 GMT", + "comments": { + "patch": [ + { + "comment": "Extract the TypingsGenerator logic to a new package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" from `0.0.0` to `0.1.0`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/localization-plugin_v0.1.0", + "date": "Thu, 27 Feb 2020 02:15:03 GMT", + "comments": { + "minor": [ + { + "comment": "Initial implementation of plugin." + } + ] + } + } + ] +} diff --git a/webpack/webpack4-localization-plugin/CHANGELOG.md b/webpack/webpack4-localization-plugin/CHANGELOG.md new file mode 100644 index 00000000000..30499a250f5 --- /dev/null +++ b/webpack/webpack4-localization-plugin/CHANGELOG.md @@ -0,0 +1,2488 @@ +# Change Log - @rushstack/webpack4-localization-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 0.19.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.19.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.19.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.19.4 +Tue, 04 Nov 2025 08:15:15 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:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.18.114 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.18.113 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.18.112 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.18.111 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.18.110 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.18.109 +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.18.108 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.18.107 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.18.106 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.18.105 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.18.104 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.18.103 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.18.102 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.18.101 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.18.100 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.18.99 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.18.98 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.18.97 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.18.96 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.18.95 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.18.94 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.18.93 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.18.92 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.18.91 +Thu, 27 Feb 2025 16:10:47 GMT + +_Version update only_ + +## 0.18.90 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.18.89 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.18.88 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.18.87 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.18.86 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.18.85 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.18.84 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.18.83 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.18.82 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.18.81 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.18.80 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.18.79 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.18.78 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.18.77 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.18.76 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.18.75 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.18.74 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.18.73 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.18.72 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.18.71 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.18.70 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.18.69 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.18.68 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.18.67 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.18.66 +Mon, 26 Aug 2024 02:00:11 GMT + +_Version update only_ + +## 0.18.65 +Wed, 21 Aug 2024 16:24:51 GMT + +_Version update only_ + +## 0.18.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.18.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.18.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.18.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.18.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.18.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.18.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.18.57 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.18.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.18.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.18.54 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 0.18.53 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.18.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.18.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.18.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.18.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.18.48 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.18.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.18.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.18.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.18.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.18.43 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.18.42 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.18.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.18.40 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.18.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.18.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.18.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.18.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.18.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.18.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.18.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.18.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.18.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.18.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.18.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.18.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.18.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.18.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.18.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.18.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.18.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.18.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.18.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.18.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.18.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.18.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.18.17 +Tue, 16 Jan 2024 18:30:10 GMT + +_Version update only_ + +## 0.18.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.18.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.18.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.18.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.18.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.18.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.18.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.18.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.18.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.18.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.18.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.18.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.18.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.18.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.18.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.18.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.18.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.17.47 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.17.46 +Thu, 07 Sep 2023 03:35:42 GMT + +### Patches + +- Update Webpack peerDependency to ~4.47.0. + +## 0.17.45 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.17.44 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.17.43 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.17.42 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.17.41 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.17.40 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.17.39 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.17.38 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.17.37 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.17.36 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.17.35 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.17.34 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.17.33 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.17.32 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.17.31 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.17.30 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.17.29 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.17.28 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.17.27 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.17.26 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.17.25 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.17.24 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.17.23 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.17.22 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.17.21 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.17.20 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.17.19 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.17.18 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.17.17 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.17.16 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.17.15 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.17.14 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.17.13 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.17.12 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.17.11 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.17.10 +Thu, 20 Apr 2023 15:16:55 GMT + +_Version update only_ + +## 0.17.9 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 0.17.8 +Fri, 07 Apr 2023 22:19:22 GMT + +_Version update only_ + +## 0.17.7 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.17.6 +Thu, 23 Mar 2023 15:24:08 GMT + +_Version update only_ + +## 0.17.5 +Wed, 22 Mar 2023 20:48:30 GMT + +_Version update only_ + +## 0.17.4 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.17.3 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 0.17.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.17.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.17.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.16.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.15.45 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.15.44 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.15.43 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.15.42 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.15.41 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.15.40 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.15.39 +Fri, 02 Dec 2022 01:15:42 GMT + +_Version update only_ + +## 0.15.38 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 0.15.37 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.15.36 +Mon, 14 Nov 2022 05:15:02 GMT + +### Patches + +- Updating webpack/loader-utils to resolve github advisory CVE-2022-37601. https://github.com/advisories/GHSA-76p3-8jx3-jpfq + +## 0.15.35 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.15.34 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.15.33 +Tue, 25 Oct 2022 00:20:44 GMT + +_Version update only_ + +## 0.15.32 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.15.31 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.15.30 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.15.29 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.15.28 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.15.27 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.15.26 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.15.25 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.15.24 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.15.23 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.15.22 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.15.21 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.15.20 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.15.19 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.15.18 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.15.17 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.15.16 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.15.15 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.15.14 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.15.13 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.15.12 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.15.11 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.15.10 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.15.9 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.15.8 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.15.7 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.15.6 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.15.5 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.15.4 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.15.3 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.15.2 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.15.1 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.15.0 +Sat, 25 Jun 2022 01:54:29 GMT + +### Minor changes + +- Add an option to output typings to additional output folders. + +## 0.14.6 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.14.5 +Thu, 23 Jun 2022 22:14:24 GMT + +### Patches + +- Rename from @rushstack/localization-plugin. + +## 0.14.4 +Fri, 17 Jun 2022 09:17:54 GMT + +_Version update only_ + +## 0.14.3 +Fri, 17 Jun 2022 00:16:18 GMT + +### Patches + +- Bump @types/webpack + +## 0.14.2 +Thu, 16 Jun 2022 22:49:55 GMT + +_Version update only_ + +## 0.14.1 +Thu, 16 Jun 2022 00:20:22 GMT + +_Version update only_ + +## 0.14.0 +Tue, 14 Jun 2022 23:11:36 GMT + +### Minor changes + +- (BREAKING CHANGE) Move the `ignoreString` option from the `typingsGeneration` object to the root of the options object. It is now used to remove strings from both typings and from loc file parsing. + +## 0.13.2 +Tue, 14 Jun 2022 00:17:29 GMT + +_Version update only_ + +## 0.13.1 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.13.0 +Fri, 03 Jun 2022 00:11:05 GMT + +### Minor changes + +- Add the ability to tweak string comments in generated typings. +- Include an option to ignore strings from typings generation. + +## 0.12.0 +Wed, 01 Jun 2022 23:31:32 GMT + +### Minor changes + +- Extract utilities to @rushstack/localization-utilitiles. + +## 0.11.1 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.11.0 +Tue, 24 May 2022 15:12:19 GMT + +### Minor changes + +- Add support for .resjson files + +## 0.10.21 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.10.20 +Wed, 18 May 2022 15:10:56 GMT + +_Version update only_ + +## 0.10.19 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.10.18 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.10.17 +Fri, 06 May 2022 18:54:42 GMT + +_Version update only_ + +## 0.10.16 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.10.15 +Wed, 04 May 2022 02:35:33 GMT + +_Version update only_ + +## 0.10.14 +Wed, 27 Apr 2022 01:19:20 GMT + +_Version update only_ + +## 0.10.13 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.10.12 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.10.11 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.10.10 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.10.9 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.10.8 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.10.7 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.10.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.10.5 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.10.4 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.10.3 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.10.2 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.10.1 +Tue, 15 Mar 2022 19:15:54 GMT + +_Version update only_ + +## 0.10.0 +Wed, 16 Feb 2022 07:15:28 GMT + +### Minor changes + +- Add an option to ignore missing RESX comments. + +## 0.9.15 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 0.9.14 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.9.13 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.9.12 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.9.11 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.9.10 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.9.9 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.9.8 +Fri, 10 Dec 2021 01:09:33 GMT + +_Version update only_ + +## 0.9.7 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.9.6 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.9.5 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.9.4 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.9.3 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.9.2 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.9.1 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.9.0 +Mon, 29 Nov 2021 07:26:16 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove "filesToIgnore" option in favor of "globsToIgnore." + +## 0.8.0 +Tue, 16 Nov 2021 16:08:01 GMT + +### Minor changes + +- Accept .resx.json as an alternative strings file extension. + +## 0.7.13 +Thu, 11 Nov 2021 01:17:03 GMT + +_Version update only_ + +## 0.7.12 +Wed, 10 Nov 2021 16:09:47 GMT + +_Version update only_ + +## 0.7.11 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.7.10 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.7.9 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.7.8 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.7.7 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 0.7.6 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.7.5 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.7.4 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.7.3 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.7.2 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.7.1 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.7.0 +Tue, 05 Oct 2021 15:08:38 GMT + +### Minor changes + +- Use ITerminal instead of Terminal to allow for compatibility with other versions of @rushstack/node-core-library. + +## 0.6.58 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.6.57 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.6.56 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.6.55 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.6.54 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.6.53 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.6.52 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.6.51 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.6.50 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.6.49 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.6.48 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.6.47 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.6.46 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.6.45 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.6.44 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.6.43 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 0.6.42 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.6.41 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.6.40 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.6.39 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.6.38 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 0.6.37 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.6.36 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.6.35 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.6.34 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.6.33 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.6.32 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.6.31 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 0.6.30 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.6.29 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.6.28 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.6.27 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 0.6.26 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 0.6.25 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 0.6.24 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 0.6.23 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 0.6.22 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 0.6.21 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 0.6.20 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.6.19 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 0.6.18 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.6.17 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 0.6.16 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 0.6.15 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 0.6.14 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 0.6.13 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.6.12 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 0.6.11 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 0.6.10 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 0.6.9 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.6.8 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 0.6.7 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 0.6.6 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 0.6.5 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 0.6.4 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.6.3 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 0.6.2 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.6.1 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 0.6.0 +Thu, 08 Apr 2021 06:05:31 GMT + +### Minor changes + +- Fix parameter name typo. + +## 0.5.38 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 0.5.37 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.5.36 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 0.5.35 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 0.5.34 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 0.5.33 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 0.5.32 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 0.5.31 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 0.5.30 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 0.5.29 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.5.28 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.5.27 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.5.26 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.5.25 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 0.5.24 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.5.23 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 0.5.22 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.5.21 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.5.20 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.5.19 +Tue, 08 Dec 2020 01:10:30 GMT + +_Version update only_ + +## 0.5.18 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.5.17 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.5.16 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.5.15 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.5.14 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.5.13 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.5.12 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.5.11 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.5.10 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.5.9 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.5.8 +Tue, 10 Nov 2020 23:13:11 GMT + +_Version update only_ + +## 0.5.7 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.5.6 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.5.5 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.5.4 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 0.5.3 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.5.2 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.5.1 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.5.0 +Thu, 29 Oct 2020 06:14:19 GMT + +### Minor changes + +- Upgrade @types/tapable + +## 0.4.0 +Thu, 29 Oct 2020 00:11:33 GMT + +### Minor changes + +- Update Webpack dependency to ~4.44.2 + +## 0.3.85 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.3.84 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 0.3.83 +Sat, 24 Oct 2020 00:11:18 GMT + +_Version update only_ + +## 0.3.82 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.3.81 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 0.3.80 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 0.3.79 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.3.78 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 0.3.77 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 0.3.76 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 0.3.75 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 0.3.74 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.3.73 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.3.72 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 0.3.71 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 0.3.70 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.3.69 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 0.3.68 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.3.67 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 0.3.66 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.3.65 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.3.64 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.3.63 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.3.62 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.3.61 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.3.60 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 0.3.59 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 0.3.58 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 0.3.57 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 0.3.56 +Sun, 13 Sep 2020 06:39:08 GMT + +### Patches + +- Handle webpack dev server hot updates. + +## 0.3.55 +Sun, 13 Sep 2020 01:53:20 GMT + +### Patches + +- Update typings generator dependency. + +## 0.3.54 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.3.53 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 0.3.52 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 0.3.51 +Mon, 07 Sep 2020 07:37:37 GMT + +_Version update only_ + +## 0.3.50 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 0.3.49 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 0.3.48 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 0.3.47 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 0.3.46 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 0.3.45 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 0.3.44 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 0.3.43 +Mon, 24 Aug 2020 07:35:20 GMT + +_Version update only_ + +## 0.3.42 +Sat, 22 Aug 2020 05:55:43 GMT + +_Version update only_ + +## 0.3.41 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 0.3.40 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 0.3.39 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 0.3.38 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 0.3.37 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 0.3.36 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 0.3.35 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 0.3.34 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 0.3.33 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 0.3.32 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 0.3.31 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 0.3.30 +Fri, 24 Jul 2020 20:40:38 GMT + +### Patches + +- Fix broken peer dependency specifier + +## 0.3.29 +Wed, 15 Jul 2020 15:09:42 GMT + +### Patches + +- Fix specification of optional peerDependencies. + +## 0.3.28 +Tue, 14 Jul 2020 19:32:58 GMT + +### Patches + +- Fix the way the loc file typings are generated in watch mode for large projects. +- Make @types/webpack an optionalPeerDependency instead of a peerDependency. + +## 0.3.27 +Tue, 07 Jul 2020 00:09:39 GMT + +### Patches + +- Fix an issue where the localization plugin would throw if resolveMissingTranslatedStrings returns undefined for a locale. + +## 0.3.26 +Fri, 03 Jul 2020 15:09:04 GMT + +_Version update only_ + +## 0.3.25 +Fri, 03 Jul 2020 05:46:42 GMT + +_Version update only_ + +## 0.3.24 +Sat, 27 Jun 2020 00:09:38 GMT + +_Version update only_ + +## 0.3.23 +Fri, 26 Jun 2020 22:16:39 GMT + +_Version update only_ + +## 0.3.22 +Thu, 25 Jun 2020 06:43:35 GMT + +_Version update only_ + +## 0.3.21 +Wed, 24 Jun 2020 09:50:48 GMT + +_Version update only_ + +## 0.3.20 +Wed, 24 Jun 2020 09:04:28 GMT + +_Version update only_ + +## 0.3.19 +Mon, 15 Jun 2020 22:17:18 GMT + +_Version update only_ + +## 0.3.18 +Fri, 12 Jun 2020 09:19:21 GMT + +_Version update only_ + +## 0.3.17 +Wed, 10 Jun 2020 20:48:30 GMT + +_Version update only_ + +## 0.3.16 +Mon, 01 Jun 2020 08:34:17 GMT + +_Version update only_ + +## 0.3.15 +Sat, 30 May 2020 02:59:54 GMT + +_Version update only_ + +## 0.3.14 +Thu, 28 May 2020 05:59:02 GMT + +_Version update only_ + +## 0.3.13 +Wed, 27 May 2020 05:15:11 GMT + +_Version update only_ + +## 0.3.12 +Tue, 26 May 2020 23:00:25 GMT + +_Version update only_ + +## 0.3.11 +Fri, 22 May 2020 15:08:42 GMT + +### Patches + +- Remove unnecessary jju dependency. + +## 0.3.10 +Thu, 21 May 2020 23:09:44 GMT + +_Version update only_ + +## 0.3.9 +Thu, 21 May 2020 15:42:00 GMT + +_Version update only_ + +## 0.3.8 +Tue, 19 May 2020 15:08:20 GMT + +_Version update only_ + +## 0.3.7 +Fri, 15 May 2020 08:10:59 GMT + +_Version update only_ + +## 0.3.6 +Wed, 13 May 2020 19:10:53 GMT + +### Patches + +- Fix encoding of tab characters. + +## 0.3.5 +Wed, 06 May 2020 08:23:45 GMT + +_Version update only_ + +## 0.3.4 +Sat, 02 May 2020 00:08:16 GMT + +_Version update only_ + +## 0.3.3 +Fri, 01 May 2020 05:15:06 GMT + +### Patches + +- Don't trim RESX text elements. + +## 0.3.2 +Wed, 08 Apr 2020 08:11:13 GMT + +### Patches + +- Fix an issue where the chunk URL generation code would mark some localized chunks as non-localized. + +## 0.3.1 +Wed, 08 Apr 2020 04:07:33 GMT + +_Version update only_ + +## 0.3.0 +Mon, 06 Apr 2020 05:52:56 GMT + +### Minor changes + +- Add support for normalization of newlines in RESX files. + +### Patches + +- Fix an issue where some characters weren't escaped correctly. +- Fix sourcemap filenames. + +## 0.2.2 +Fri, 03 Apr 2020 15:10:15 GMT + +_Version update only_ + +## 0.2.1 +Sun, 29 Mar 2020 00:04:12 GMT + +_Version update only_ + +## 0.2.0 +Sat, 28 Mar 2020 01:38:47 GMT + +### Minor changes + +- Fix a few RESX parsing issues and improve translated strings resolution. + +## 0.1.4 +Sat, 28 Mar 2020 00:37:16 GMT + +_Version update only_ + +## 0.1.3 +Wed, 18 Mar 2020 15:07:47 GMT + +_Version update only_ + +## 0.1.2 +Tue, 17 Mar 2020 23:55:58 GMT + +### Patches + +- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack` + +## 0.1.1 +Thu, 12 Mar 2020 15:08:44 GMT + +### Patches + +- Extract the TypingsGenerator logic to a new package. + +## 0.1.0 +Thu, 27 Feb 2020 02:15:03 GMT + +### Minor changes + +- Initial implementation of plugin. + diff --git a/webpack/webpack4-localization-plugin/LICENSE b/webpack/webpack4-localization-plugin/LICENSE new file mode 100644 index 00000000000..e059d0563ea --- /dev/null +++ b/webpack/webpack4-localization-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack4-localization-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/webpack/webpack4-localization-plugin/README.md b/webpack/webpack4-localization-plugin/README.md new file mode 100644 index 00000000000..e1a43901cd2 --- /dev/null +++ b/webpack/webpack4-localization-plugin/README.md @@ -0,0 +1,292 @@ +# @rushstack/webpack4-localization-plugin + +## Installation + +`npm install @rushstack/webpack4-localization-plugin --save-dev` + +## Overview + +This Webpack plugin produces bundles that have multiple locales' variants of strings embedded. It also +has out-of-box support for RESX files in addition to JSON strings files (with the extension `.loc.json`), including +support for generating typings. + +### Example Plugin Usage + +There are three example projects in this repository that make use of this plugin: + +- [Project 1](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-01) + - This project contains two webpack entrypoints (one with an async chunk, one without), without any localized + resources + - The output is a single, non-localized variant +- [Project 2](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02) + - This project contains three webpack entrypoints: + - [`indexA.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02/src/indexA.ts) + directly references two `.loc.json` files and one `.resx` file, and dynamically imports an async chunk with + localized data, and an async chunk without localized data + - [`indexB.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02/src/indexB.ts) + directly references two `.loc.json` files + - [`indexC.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02/src/indexC.ts) + directly references no localized resources, and dynamically imports an async chunk without localized data + - The webpack config contains and references Spanish translations for most of the English strings in the resource files + - The output contains English, Spanish, and "passthrough" localized variants of files that contain + localized data, and a non-localized variant of the files that do not contain localized data +- [Project 3](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-03) + - This project contains four webpack entrypoints: + - [`indexA.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-03/src/indexA.ts) + directly references one `.loc.json` file, one `.resx.json` file, one `.resx` file, and one `.resjson` file, and dynamically imports an async chunk with + localized data, and an async chunk without localized data + - [`indexB.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-03/src/indexB.ts) + directly references one `.loc.json` file and one `.resx.json` file + - [`indexC.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-03/src/indexC.ts) + directly references no localized resources, and dynamically imports an async chunk with localized data + - [`indexD.ts`](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-03/src/indexD.ts) + directly references no localized resources, and dynamically imports an async chunk without localized data + - The webpack config contains or references Spanish translations for some of the English strings in the resource files + - The output contains English, Spanish, "passthrough," and two pseudo-localized variants of files that contain + localized data, and a non-localized variant of the files that do not contain localized data + +### `.resx` vs `.loc.json` vs `.resjson` + +[`.resx`](https://docs.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps#resources-in-resx-files) +is an XML format for resource data. It is primarily used in .NET development, and it is supported by +some translation services. See an example of a `.resx` file +[here](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02/src/strings5.resx). +Note that the `` and `` elements are not required. Also note that although the +`.resx` supports many different types of localized data including strings and binary data, **only strings** +are supported by this plugin. + +`.loc.json` is a very simple `JSON` schema for specifying localized string and translator comments. +See an example of a `.loc.json` file +[here](https://github.com/microsoft/rushstack/tree/main/build-tests/localization-plugin-test-02/src/strings3.loc.json). + +`.resjson` is another simple `JSON` schema for specifying localized string and translator comments. +See [here](https://lingohub.com/developers/resource-files/resjson-localization) for documentation on `.resjson` + +For most projects, `.loc.json` is a simpler format to use. However for large projects, projects that already use +translation services that support `.resx`, or engineers who are already experienced .NET developers, `.resx` +may be more convenient. + +# Plugin + +To use the plugin, add it to the `plugins` array of your Webpack config. For example: + +```JavaScript +import { LocalizationPlugin } from '@rushstack/webpack4-localization-plugin'; + +{ + plugins: [ + new LocalizationPlugin( /* options */ ) + ] +} +``` + +***A note about the dev server:*** When Webpack is being run by the Webpack dev server, this plugin pipes +the strings in the loc files in the source (the `.loc.json` and the `.resx` files) to the output without +any translations. + +## Options + +### `localizedData = { }` + +#### `localizedData.defaultLocale = { }` + +This option has a required property (`localeName`), to specify the name of the locale used in the +`.resx` and `.loc.json` files in the source. + +##### `localizedData.defaultLocale.fillMissingTranslationStrings = true | false` + +If this option is set to `true`, strings that are missing from `localizedData.translatedStrings` will be +provided by the default locale (the strings in the `.resx` and `.loc.json` files in the source). If +this option is unset or set to `false`, an error will be emitted if a string is missing from +`localizedData.translatedStrings`. + +#### `localizedData.translatedStrings = { }` + +This option is used to specify the localization data to be used in the build. This object has the following +structure: + +- Locale name + - Compilation context-relative or absolute localization file path + - Translated strings + +For example: + +```JavaScript +translatedStrings: { + "en-us": { + "./src/strings1.loc.json": { + "string1": "the first string" + } + }, + "es-es": { + "./src/strings1.loc.json": { + "string1": "la primera cadena" + } + } +} +``` + +Alternatively, instead of directly specifying the translations, a path to a translated resource file can be +specified. For example: + +```JavaScript +translatedStrings: { + "en-us": { + "./src/strings1.loc.json": "./localization/en-us/strings1.loc.json" + }, + "es-es": { + "./src/strings1.loc.json": "./localization/es-es/strings1.loc.json" + } +} +``` + +#### `localizedData.resolveMissingTranslatedStrings = (locales: string[], filePath: string) => { ... }` + +This optional option can be used to resolve translated data that is missing from data that is provided +in the `localizedData.translatedStrings` option. Set this option with a function expecting two parameters: +the first, an array of locale names, and second, a fully-qualified path to the localized file in source. The +function should return an object with locale names as keys and localized data as values. The localized data +value should either be: + +- a string: The absolute path to the translated data in `.resx` or `.loc.json` format +- an object: An object containing the translated data + +Note that these values are the same as the values that can be specified for translations for a localized +resource in `localizedData.translatedStrings`. + +If the function returns data that is missing locales or individual strings, the plugin will fall back to the +default locale if `localizedData.defaultLocale.fillMissingTranslationStrings` is set to `true`. If +`localizedData.defaultLocale.fillMissingTranslationStrings` is set to `false`, an error will result. + +#### `localizedData.passthroughLocale = { }` + +This option is used to specify how and if a passthrough locale should be generated. A passthrough locale +is a generated locale in which each string's value is its name. This is useful for debugging and for identifying +cases where a locale is missing. + +This option takes two optional properties: + +##### `localizedData.passthroughLocale.usePassthroughLocale = true | false` + +If `passthroughLocale.usePassthroughLocale` is set to `true`, a passthrough locale will be included in the output. +By default, the passthrough locale's name is "passthrough." + +##### `localizedData.passthroughLocale.passthroughLocaleName = '...'` + +If `passthroughLocale.usePassthroughLocale` is set to `true`, the "passthrough" locale name can be overridden +by setting a value on `passthroughLocale.passthroughLocaleName`. + +#### `localizedData.pseudolocales = { }` + +This option allows pseudolocales to be generated from the strings in the default locale. This option takes +an option with pseudolocales as keys and options for the +[pseudolocale package](https://www.npmjs.com/package/pseudolocale) as values. + +#### `localizedData.normalizeResxNewlines = 'crlf' | 'lf'` + +This option allows normalization of newlines in RESX files. RESX files are XML, so newlines can be +specified by including a newline in the `` element. For files stored on source control systems, +clones on Windows can end up with CRLF newlines and clones on 'nix operating systems can end up with LF +newlines. This option can be used to help make compilations run on different platforms produce the same +result. + +#### `localizedData.ignoreMissingResxComments = true | false | undefined + +If set to true, do not warn on missing RESX element comments. + +### `globsToIgnore = [ ]` + +This option is used to specify `.resx` and `.loc.json` files that should not be processed by this plugin. +By default, every `.resx`, `.resx.json`, and `.loc.json` file import is intercepted by this plugin, and an +error occurs if translations aren't provided for an intercepted file and the +`localizedData.defaultLocale.fillMissingTranslationStrings` option is set to falsy, or if the +file is in an unexpected format. To avoid an error, specify files that should be ignored by this plugin in +this property. This is useful if a dependency uses files with a `.resx`, `.resx.json`, or `.loc.json` +extension, but are processed in a different way from how this plugin handles localization. +For example: `globsToIgnore: [ 'node_modules/some-dependency-name/lib/**/*.loc.json' ]` + +### `noStringsLocaleName = '...'` + +The value to replace the `[locale]` token with for chunks without localized strings. Defaults to "none" + +### `localizationStats = { }` + +#### `localizationStats.dropPath = '...'` + +This option is used to designate a path at which a JSON file describing the localized assets produced should be +written. If this property is omitted, the stats file won't be written. + +The file has the following format: + +```JSON +{ + "entrypoints": { + "": { + "localizedAssets": { + "": "", + "": "" + } + }, + "": { + "localizedAssets": { + "": "", + "": "" + } + } + }, + "namedChunkGroups": { + "": { + "localizedAssets": { + "": "", + "": "" + } + }, + "": { + "localizedAssets": { + "": "", + "": "" + } + } + } +} + +``` + +#### `localizationStats.callback = (stats) => { ... }` + +This option is used to specify a callback to be called with the stats data that would be dropped at +[`localizationStats.dropPath`](#localizationStats.DropPath--) after compilation completes. + +### `typingsOptions = { }` + +This option is used to specify how and if TypeScript typings should be generated for loc files. + +It takes two options: + +#### `typingsOptions.generatedTsFolder = '...'` + +This property specifies the folder in which `.d.ts` files for loc files should be dropped. It is recommended +that this be a folder parallel to the source folder, specified in addition to the source folder in the +[`rootDirs` `tsconfig.json` option](https://www.typescriptlang.org/docs/handbook/compiler-options.html). +**The folder specified by this option is emptied when compilation is started.** + +This property is required if `typingsOptions` is set. + +#### `typingsOptions.sourceRoot = '...'` + +This optional property overrides the compiler context for discovery of localization files for which +typings should be generated. + +#### `typingsOptions.exportAsDefault = true | false` + +If this option is set to `true`, loc modules typings will be exported wrapped in a `default` property. This +allows strings to be imported by using the `import strings from './strings.loc.json';` syntax instead of +the `import { string1 } from './strings.loc.json';` or the `import * as strings from './strings.loc.json';` +syntax. This option is not recommended. + +## Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/webpack/localization-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack4-localization-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/webpack4-localization-plugin/config/api-extractor.json b/webpack/webpack4-localization-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack4-localization-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack4-localization-plugin/config/rig.json b/webpack/webpack4-localization-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack4-localization-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/webpack/webpack4-localization-plugin/eslint.config.js b/webpack/webpack4-localization-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack4-localization-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/webpack/webpack4-localization-plugin/package.json b/webpack/webpack4-localization-plugin/package.json new file mode 100644 index 00000000000..325fdaa2db4 --- /dev/null +++ b/webpack/webpack4-localization-plugin/package.json @@ -0,0 +1,52 @@ +{ + "name": "@rushstack/webpack4-localization-plugin", + "version": "0.19.7", + "description": "This plugin facilitates localization with Webpack.", + "main": "lib/index.js", + "typings": "dist/webpack4-localization-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack4-localization-plugin" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "peerDependencies": { + "@rushstack/set-webpack-public-path-plugin": "^4.1.16", + "@types/webpack": "^4.39.0", + "webpack": "^4.31.0", + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@rushstack/set-webpack-public-path-plugin": { + "optional": true + }, + "@types/webpack": { + "optional": true + }, + "@types/node": { + "optional": true + } + }, + "dependencies": { + "@rushstack/localization-utilities": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/tapable": "1.0.6", + "loader-utils": "1.4.2", + "minimatch": "10.0.3" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/set-webpack-public-path-plugin": "^4.1.16", + "@types/loader-utils": "1.1.3", + "@types/node": "20.17.19", + "@types/webpack": "4.41.32", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~4.47.0" + } +} diff --git a/webpack/webpack4-localization-plugin/src/AssetProcessor.ts b/webpack/webpack4-localization-plugin/src/AssetProcessor.ts new file mode 100644 index 00000000000..fd2780153ed --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/AssetProcessor.ts @@ -0,0 +1,474 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as Webpack from 'webpack'; + +import { Constants } from './utilities/Constants'; +import type { ILocaleElementMap } from './interfaces'; +import type { LocalizationPlugin, IStringSerialNumberData as IStringData } from './LocalizationPlugin'; + +interface IReconstructionElement { + kind: 'static' | 'localized' | 'dynamic'; +} + +interface IStaticReconstructionElement extends IReconstructionElement { + kind: 'static'; + staticString: string; +} + +interface ILocalizedReconstructionElement extends IReconstructionElement { + kind: 'localized'; + values: ILocaleElementMap; + size: number; + stringName: string; + escapedBackslash: string; + locFilePath: string; +} + +interface IDynamicReconstructionElement extends IReconstructionElement { + kind: 'dynamic'; + valueFn: (locale: string, token: string | undefined) => string; + size: number; + escapedBackslash: string; + token?: string; +} + +interface IParseResult { + issues: string[]; + reconstructionSeries: IReconstructionElement[]; +} + +interface IReconstructedString { + source: string; + size: number; +} + +interface ILocalizedReconstructionResult { + result: Map; + issues: string[]; +} + +interface INonLocalizedReconstructionResult { + result: IReconstructedString; + issues: string[]; +} + +export interface IProcessAssetOptionsBase { + plugin: LocalizationPlugin; + compilation: Webpack.compilation.Compilation; + assetName: string; + asset: IAsset; + chunk: Webpack.compilation.Chunk; + noStringsLocaleName: string; + chunkHasLocalizedModules: (chunk: Webpack.compilation.Chunk) => boolean; +} + +export interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBase {} + +export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase { + locales: Set; + fillMissingTranslationStrings: boolean; + defaultLocale: string; +} + +export interface IAsset { + size(): number; + source(): string; +} + +export interface IProcessAssetResult { + filename: string; + asset: IAsset; +} + +export const PLACEHOLDER_REGEX: RegExp = new RegExp( + `${Constants.STRING_PLACEHOLDER_PREFIX}_(\\\\*)_([A-C])(\\+[^+]+\\+)?_(\\d+)`, + 'g' +); + +export class AssetProcessor { + public static processLocalizedAsset( + options: IProcessLocalizedAssetOptions + ): Map { + const assetSource: string = options.asset.source(); + + const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence( + options.plugin, + assetSource, + this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName) + ); + const reconstructedAsset: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized( + parsedAsset.reconstructionSeries, + options.locales, + options.fillMissingTranslationStrings, + options.defaultLocale, + options.asset.size() + ); + + const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence( + options.plugin, + options.assetName, + () => { + throw new Error('unsupported'); + } + ); + const reconstructedAssetName: ILocalizedReconstructionResult = AssetProcessor._reconstructLocalized( + parsedAssetName.reconstructionSeries, + options.locales, + options.fillMissingTranslationStrings, + options.defaultLocale, + options.assetName.length + ); + + const result: Map = new Map(); + for (const [locale, { source, size }] of reconstructedAsset.result) { + const newAsset: IAsset = { ...options.asset }; + newAsset.source = () => source; + newAsset.size = () => size; + + result.set(locale, { + filename: reconstructedAssetName.result.get(locale)!.source, + asset: newAsset + }); + } + + const issues: string[] = [ + ...parsedAsset.issues, + ...reconstructedAsset.issues, + ...parsedAssetName.issues, + ...reconstructedAssetName.issues + ]; + + if (issues.length > 0) { + options.compilation.errors.push( + Error(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`) + ); + } + + return result; + } + + public static processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptions): IProcessAssetResult { + const assetSource: string = options.asset.source(); + + const parsedAsset: IParseResult = AssetProcessor._parseStringToReconstructionSequence( + options.plugin, + assetSource, + this._getJsonpFunction(options.chunk, options.chunkHasLocalizedModules, options.noStringsLocaleName) + ); + const reconstructedAsset: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized( + parsedAsset.reconstructionSeries, + options.asset.size(), + options.noStringsLocaleName + ); + + const parsedAssetName: IParseResult = AssetProcessor._parseStringToReconstructionSequence( + options.plugin, + options.assetName, + () => { + throw new Error('unsupported'); + } + ); + const reconstructedAssetName: INonLocalizedReconstructionResult = AssetProcessor._reconstructNonLocalized( + parsedAssetName.reconstructionSeries, + options.assetName.length, + options.noStringsLocaleName + ); + + const issues: string[] = [ + ...parsedAsset.issues, + ...reconstructedAsset.issues, + ...parsedAssetName.issues, + ...reconstructedAssetName.issues + ]; + + if (issues.length > 0) { + options.compilation.errors.push( + Error(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`) + ); + } + + const newAsset: IAsset = { ...options.asset }; + newAsset.source = () => reconstructedAsset.result.source; + newAsset.size = () => reconstructedAsset.result.size; + return { + filename: reconstructedAssetName.result.source, + asset: newAsset + }; + } + + private static _reconstructLocalized( + reconstructionSeries: IReconstructionElement[], + locales: Set, + fillMissingTranslationStrings: boolean, + defaultLocale: string, + initialSize: number + ): ILocalizedReconstructionResult { + const localizedResults: Map = new Map(); + const issues: string[] = []; + + for (const locale of locales) { + const reconstruction: string[] = []; + + let sizeDiff: number = 0; + for (const element of reconstructionSeries) { + switch (element.kind) { + case 'static': { + reconstruction.push((element as IStaticReconstructionElement).staticString); + break; + } + + case 'localized': { + const localizedElement: ILocalizedReconstructionElement = + element as ILocalizedReconstructionElement; + let newValue: string | undefined = localizedElement.values[locale]; + if (!newValue) { + if (fillMissingTranslationStrings) { + newValue = localizedElement.values[defaultLocale]; + } else { + issues.push( + `The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" is missing in ` + + `the locale ${locale}` + ); + + newValue = '-- MISSING STRING --'; + } + } + + const escapedBackslash: string = localizedElement.escapedBackslash || '\\'; + + // Replace backslashes with the properly escaped backslash + newValue = newValue.replace(/\\/g, escapedBackslash); + + // @todo: look into using JSON.parse(...) to get the escaping characters + const escapingCharacterSequence: string = escapedBackslash.substr(escapedBackslash.length / 2); + + // Ensure the the quotemark, apostrophe, tab, and newline characters are properly escaped + newValue = newValue.replace(/\r/g, `${escapingCharacterSequence}r`); + newValue = newValue.replace(/\n/g, `${escapingCharacterSequence}n`); + newValue = newValue.replace(/\t/g, `${escapingCharacterSequence}t`); + newValue = newValue.replace(/\"/g, `${escapingCharacterSequence}u0022`); + newValue = newValue.replace(/\'/g, `${escapingCharacterSequence}u0027`); + + reconstruction.push(newValue); + sizeDiff += newValue.length - localizedElement.size; + break; + } + + case 'dynamic': { + const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement; + const newValue: string = dynamicElement.valueFn(locale, dynamicElement.token); + reconstruction.push(newValue); + sizeDiff += newValue.length - dynamicElement.size; + break; + } + } + } + + const newAssetSource: string = reconstruction.join(''); + localizedResults.set(locale, { + source: newAssetSource, + size: initialSize + sizeDiff + }); + } + + return { + issues, + result: localizedResults + }; + } + + private static _reconstructNonLocalized( + reconstructionSeries: IReconstructionElement[], + initialSize: number, + noStringsLocaleName: string + ): INonLocalizedReconstructionResult { + const issues: string[] = []; + + const reconstruction: string[] = []; + + let sizeDiff: number = 0; + for (const element of reconstructionSeries) { + switch (element.kind) { + case 'static': { + reconstruction.push((element as IStaticReconstructionElement).staticString); + break; + } + + case 'localized': { + const localizedElement: ILocalizedReconstructionElement = + element as ILocalizedReconstructionElement; + issues.push( + `The string "${localizedElement.stringName}" in "${localizedElement.locFilePath}" appeared in an asset ` + + 'that is not expected to contain localized resources.' + ); + + const newValue: string = '-- NOT EXPECTED TO BE LOCALIZED --'; + reconstruction.push(newValue); + sizeDiff += newValue.length - localizedElement.size; + break; + } + + case 'dynamic': { + const dynamicElement: IDynamicReconstructionElement = element as IDynamicReconstructionElement; + const newValue: string = dynamicElement.valueFn(noStringsLocaleName, dynamicElement.token); + reconstruction.push(newValue); + sizeDiff += newValue.length - dynamicElement.size; + break; + } + } + } + + const newAssetSource: string = reconstruction.join(''); + return { + issues, + result: { + source: newAssetSource, + size: initialSize + sizeDiff + } + }; + } + + private static _parseStringToReconstructionSequence( + plugin: LocalizationPlugin, + source: string, + jsonpFunction: (locale: string, chunkIdToken: string | undefined) => string + ): IParseResult { + const issues: string[] = []; + const reconstructionSeries: IReconstructionElement[] = []; + + let lastIndex: number = 0; + let regexResult: RegExpExecArray | null; + while ((regexResult = PLACEHOLDER_REGEX.exec(source))) { + const staticElement: IStaticReconstructionElement = { + kind: 'static', + staticString: source.substring(lastIndex, regexResult.index) + }; + reconstructionSeries.push(staticElement); + + const [placeholder, escapedBackslash, elementLabel, token, placeholderSerialNumber] = regexResult; + + let localizedReconstructionElement: IReconstructionElement; + switch (elementLabel) { + case Constants.STRING_PLACEHOLDER_LABEL: { + const stringData: IStringData | undefined = plugin.getDataForSerialNumber(placeholderSerialNumber); + if (!stringData) { + issues.push(`Missing placeholder ${placeholder}`); + const brokenLocalizedElement: IStaticReconstructionElement = { + kind: 'static', + staticString: placeholder + }; + localizedReconstructionElement = brokenLocalizedElement; + } else { + const localizedElement: ILocalizedReconstructionElement = { + kind: 'localized', + values: stringData.values, + size: placeholder.length, + locFilePath: stringData.locFilePath, + escapedBackslash: escapedBackslash, + stringName: stringData.stringName + }; + localizedReconstructionElement = localizedElement; + } + break; + } + + case Constants.LOCALE_NAME_PLACEHOLDER_LABEL: { + const dynamicElement: IDynamicReconstructionElement = { + kind: 'dynamic', + valueFn: (locale: string) => locale, + size: placeholder.length, + escapedBackslash: escapedBackslash + }; + localizedReconstructionElement = dynamicElement; + break; + } + + case Constants.JSONP_PLACEHOLDER_LABEL: { + const dynamicElement: IDynamicReconstructionElement = { + kind: 'dynamic', + valueFn: jsonpFunction, + size: placeholder.length, + escapedBackslash: escapedBackslash, + token: token.substring(1, token.length - 1) + }; + localizedReconstructionElement = dynamicElement; + break; + } + + default: { + throw new Error(`Unexpected label ${elementLabel}`); + } + } + + reconstructionSeries.push(localizedReconstructionElement); + lastIndex = regexResult.index + placeholder.length; + } + + const lastElement: IStaticReconstructionElement = { + kind: 'static', + staticString: source.substr(lastIndex) + }; + reconstructionSeries.push(lastElement); + + return { + issues, + reconstructionSeries + }; + } + + private static _getJsonpFunction( + chunk: Webpack.compilation.Chunk, + chunkHasLocalizedModules: (chunk: Webpack.compilation.Chunk) => boolean, + noStringsLocaleName: string + ): (locale: string, chunkIdToken: string | undefined) => string { + const idsWithStrings: Set = new Set(); + const idsWithoutStrings: Set = new Set(); + + const asyncChunks: Set = chunk.getAllAsyncChunks(); + for (const asyncChunk of asyncChunks) { + const chunkId: number | string | null = asyncChunk.id; + + if (chunkId === null || chunkId === undefined) { + throw new Error(`Chunk "${asyncChunk.name}"'s ID is null or undefined.`); + } + + if (chunkHasLocalizedModules(asyncChunk)) { + idsWithStrings.add(chunkId); + } else { + idsWithoutStrings.add(chunkId); + } + } + + if (idsWithStrings.size === 0) { + return () => JSON.stringify(noStringsLocaleName); + } else if (idsWithoutStrings.size === 0) { + return (locale: string) => JSON.stringify(locale); + } else { + // Generate an array [, ] and an object that is used as an indexer into that + // object that maps chunk IDs to 0s for chunks with localized strings and 1s for chunks without localized + // strings + // + // This can be improved in the future. We can maybe sort the chunks such that the chunks below a certain ID + // number are localized and the those above are not. + const chunkMapping: { [chunkId: string]: number } = {}; + for (const idWithStrings of idsWithStrings) { + chunkMapping[idWithStrings] = 0; + } + + for (const idWithoutStrings of idsWithoutStrings) { + chunkMapping[idWithoutStrings] = 1; + } + + return (locale: string, chunkIdToken: string | undefined) => { + if (!locale) { + throw new Error('Missing locale name.'); + } + + return `(${JSON.stringify([locale, noStringsLocaleName])})[${JSON.stringify( + chunkMapping + )}[${chunkIdToken}]]`; + }; + } + } +} diff --git a/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts new file mode 100644 index 00000000000..2e4a05b7c06 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/LocalizationPlugin.ts @@ -0,0 +1,871 @@ +// 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 Webpack from 'webpack'; +import type * as Tapable from 'tapable'; + +import { JsonFile, FileSystem, NewlineKind } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; +import { + getPseudolocalizer, + type ILocalizationFile, + parseLocFile, + TypingsGenerator +} from '@rushstack/localization-utilities'; + +import { Constants } from './utilities/Constants'; +import { + type IWebpackConfigurationUpdaterOptions, + WebpackConfigurationUpdater +} from './WebpackConfigurationUpdater'; +import type { + ILocalizationPluginOptions, + ILocalizationStats, + ILocaleFileData, + ILocaleElementMap, + ILocalizedStrings, + IResolvedMissingTranslations +} from './interfaces'; +import type { ILocalizedWebpackChunk } from './webpackInterfaces'; +import { EntityMarker } from './utilities/EntityMarker'; +import { type IAsset, type IProcessAssetResult, AssetProcessor, PLACEHOLDER_REGEX } from './AssetProcessor'; + +/** + * @internal + */ +export interface IStringPlaceholder { + value: string; + suffix: string; +} + +/** + * @internal + */ +export interface IAddDefaultLocFileResult { + /** + * A list of paths to translation files that were loaded + */ + additionalLoadedFilePaths: string[]; + + errors: Error[]; +} + +interface IExtendedMainTemplate { + hooks: { + assetPath: Tapable.SyncHook; + }; +} + +interface IExtendedConfiguration extends Webpack.compilation.Compilation { + options: Webpack.Configuration; +} + +interface IExtendedChunkGroup extends Webpack.compilation.ChunkGroup { + getChildren(): Webpack.compilation.Chunk[]; +} + +interface IExtendedChunk extends Webpack.compilation.Chunk { + filenameTemplate: string; +} + +interface IAssetPathOptions { + chunk: Webpack.compilation.Chunk; + contentHashType: string; + filename: string; +} + +/** + * @internal + */ +export interface IStringSerialNumberData { + values: ILocaleElementMap; + locFilePath: string; + stringName: string; +} + +const PLUGIN_NAME: string = 'localization'; + +/** + * This plugin facilitates localization in webpack. + * + * @public + */ +export class LocalizationPlugin implements Webpack.Plugin { + /** + * @internal + */ + public stringKeys: Map = new Map(); + + private _options: ILocalizationPluginOptions; + private _resolvedTranslatedStringsFromOptions!: ILocalizedStrings; + private _globsToIgnore: string[] | undefined; + private _stringPlaceholderCounter: number = 0; + private _stringPlaceholderMap: Map = new Map< + string, + IStringSerialNumberData + >(); + private _locales: Set = new Set(); + private _passthroughLocaleName!: string; + private _defaultLocale!: string; + private _noStringsLocaleName!: string; + private _fillMissingTranslationStrings!: boolean; + private _pseudolocalizers: Map string> = new Map< + string, + (str: string) => string + >(); + private _resxNewlineNormalization: NewlineKind | undefined; + private _ignoreMissingResxComments: boolean | undefined; + + /** + * The outermost map's keys are the locale names. + * The middle map's keys are the resolved, file names. + * The innermost map's keys are the string identifiers and its values are the string values. + */ + private _resolvedLocalizedStrings: Map>> = new Map< + string, + Map> + >(); + + public constructor(options: ILocalizationPluginOptions) { + if (options.filesToIgnore) { + throw new Error('The filesToIgnore option is no longer supported. Please use globsToIgnore instead.'); + } + + if (options.typingsOptions?.ignoreString) { + throw new Error( + 'The typingsOptions.ignoreString option is no longer supported. Please use the ignoreString ' + + 'option directly on the constructor options object instead.' + ); + } + + this._options = options; + } + + public apply(compiler: Webpack.Compiler): void { + const isWebpack4: boolean = !!compiler.hooks; + + if (!isWebpack4) { + throw new Error(`The ${LocalizationPlugin.name} plugin requires Webpack 4`); + } + + if (this._options.typingsOptions && compiler.context) { + if ( + this._options.typingsOptions.generatedTsFolder && + !path.isAbsolute(this._options.typingsOptions.generatedTsFolder) + ) { + this._options.typingsOptions.generatedTsFolder = path.resolve( + compiler.context, + this._options.typingsOptions.generatedTsFolder + ); + } + + if ( + this._options.typingsOptions.sourceRoot && + !path.isAbsolute(this._options.typingsOptions.sourceRoot) + ) { + this._options.typingsOptions.sourceRoot = path.resolve( + compiler.context, + this._options.typingsOptions.sourceRoot + ); + } + + const secondaryGeneratedTsFolders: string[] | undefined = + this._options.typingsOptions.secondaryGeneratedTsFolders; + if (secondaryGeneratedTsFolders) { + for (let i: number = 0; i < secondaryGeneratedTsFolders.length; i++) { + const secondaryGeneratedTsFolder: string = secondaryGeneratedTsFolders[i]; + if (!path.isAbsolute(secondaryGeneratedTsFolder)) { + secondaryGeneratedTsFolders[i] = path.resolve(compiler.context, secondaryGeneratedTsFolder); + } + } + } + } + + // https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66 + const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true'; + + const { errors, warnings } = this._initializeAndValidateOptions(compiler.options, isWebpackDevServer); + + let typingsPreprocessor: TypingsGenerator | undefined; + if (this._options.typingsOptions) { + typingsPreprocessor = new TypingsGenerator({ + srcFolder: this._options.typingsOptions.sourceRoot || compiler.context, + generatedTsFolder: this._options.typingsOptions.generatedTsFolder, + secondaryGeneratedTsFolders: this._options.typingsOptions.secondaryGeneratedTsFolders, + exportAsDefault: this._options.typingsOptions.exportAsDefault, + globsToIgnore: this._options.globsToIgnore, + ignoreString: this._options.ignoreString, + processComment: this._options.typingsOptions.processComment + }); + } else { + typingsPreprocessor = undefined; + } + + const webpackConfigurationUpdaterOptions: IWebpackConfigurationUpdaterOptions = { + pluginInstance: this, + configuration: compiler.options, + globsToIgnore: this._globsToIgnore, + localeNameOrPlaceholder: Constants.LOCALE_NAME_PLACEHOLDER, + resxNewlineNormalization: this._resxNewlineNormalization, + ignoreMissingResxComments: this._ignoreMissingResxComments, + ignoreString: this._options.ignoreString + }; + + if (errors.length > 0 || warnings.length > 0) { + compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { + compilation.errors.push(...errors); + compilation.warnings.push(...warnings); + }); + + if (errors.length > 0) { + // If there are any errors, just pass through the resources in source and don't do any + // additional configuration + WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles( + webpackConfigurationUpdaterOptions + ); + return; + } + } + + if (isWebpackDevServer) { + if (typingsPreprocessor) { + compiler.hooks.afterEnvironment.tap(PLUGIN_NAME, () => typingsPreprocessor!.runWatcherAsync()); + + if (!compiler.options.plugins) { + compiler.options.plugins = []; + } + + compiler.options.plugins.push( + new Webpack.WatchIgnorePlugin([this._options.typingsOptions!.generatedTsFolder]) + ); + } + + WebpackConfigurationUpdater.amendWebpackConfigurationForInPlaceLocFiles( + webpackConfigurationUpdaterOptions + ); + } else { + if (typingsPreprocessor) { + compiler.hooks.beforeRun.tapPromise( + PLUGIN_NAME, + async () => await typingsPreprocessor!.generateTypingsAsync() + ); + } + + WebpackConfigurationUpdater.amendWebpackConfigurationForMultiLocale(webpackConfigurationUpdaterOptions); + + if (errors.length === 0) { + compiler.hooks.thisCompilation.tap( + PLUGIN_NAME, + (untypedCompilation: Webpack.compilation.Compilation) => { + const compilation: IExtendedConfiguration = untypedCompilation as IExtendedConfiguration; + (compilation.mainTemplate as unknown as IExtendedMainTemplate).hooks.assetPath.tap( + PLUGIN_NAME, + (assetPath: string, options: IAssetPathOptions) => { + if ( + options.contentHashType === 'javascript' && + assetPath.match(Constants.LOCALE_FILENAME_TOKEN_REGEX) + ) { + // Does this look like an async chunk URL generator? + if (typeof options.chunk.id === 'string' && (options.chunk.id as string).match(/^\" \+/)) { + return assetPath.replace( + Constants.LOCALE_FILENAME_TOKEN_REGEX, + `" + ${Constants.JSONP_PLACEHOLDER} + "` + ); + } else { + return assetPath.replace( + Constants.LOCALE_FILENAME_TOKEN_REGEX, + Constants.LOCALE_NAME_PLACEHOLDER + ); + } + } else if (assetPath.match(Constants.NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN_REGEX)) { + // Replace the placeholder with the [locale] token for sourcemaps + const deLocalizedFilename: string = options.filename.replace( + PLACEHOLDER_REGEX, + Constants.LOCALE_FILENAME_TOKEN + ); + return assetPath.replace( + Constants.NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN_REGEX, + deLocalizedFilename + ); + } else { + return assetPath; + } + } + ); + + compilation.hooks.optimizeChunks.tap( + PLUGIN_NAME, + ( + untypedChunks: Webpack.compilation.Chunk[], + untypedChunkGroups: Webpack.compilation.ChunkGroup[] + ) => { + const chunks: IExtendedChunk[] = untypedChunks as IExtendedChunk[]; + const chunkGroups: IExtendedChunkGroup[] = untypedChunkGroups as IExtendedChunkGroup[]; + + let chunksHaveAnyChildren: boolean = false; + for (const chunkGroup of chunkGroups) { + const children: Webpack.compilation.Chunk[] = chunkGroup.getChildren(); + if (children.length > 0) { + chunksHaveAnyChildren = true; + break; + } + } + + if ( + chunksHaveAnyChildren && + (!compilation.options.output || + !compilation.options.output.chunkFilename || + compilation.options.output.chunkFilename.indexOf(Constants.LOCALE_FILENAME_TOKEN) === -1) + ) { + compilation.errors.push( + new Error( + 'The configuration.output.chunkFilename property must be provided and must include ' + + `the ${Constants.LOCALE_FILENAME_TOKEN} placeholder` + ) + ); + + return; + } + + for (const chunk of chunks) { + // See if the chunk contains any localized modules or loads any localized chunks + const localizedChunk: boolean = this._chunkHasLocalizedModules(chunk); + + // Change the chunk's name to include either the locale name or the locale name for chunks without strings + const replacementValue: string = localizedChunk + ? Constants.LOCALE_NAME_PLACEHOLDER + : this._noStringsLocaleName; + if (chunk.hasRuntime()) { + chunk.filenameTemplate = (compilation.options.output!.filename as string).replace( + Constants.LOCALE_FILENAME_TOKEN_REGEX, + replacementValue + ); + } else { + chunk.filenameTemplate = compilation.options.output!.chunkFilename!.replace( + Constants.LOCALE_FILENAME_TOKEN_REGEX, + replacementValue + ); + } + } + } + ); + } + ); + + compiler.hooks.emit.tap(PLUGIN_NAME, (compilation: Webpack.compilation.Compilation) => { + const localizationStats: ILocalizationStats = { + entrypoints: {}, + namedChunkGroups: {} + }; + + const alreadyProcessedAssets: Set = new Set(); + const hotUpdateRegex: RegExp = /\.hot-update\.js$/; + + for (const untypedChunk of compilation.chunks) { + const chunk: ILocalizedWebpackChunk = untypedChunk; + const chunkFilesSet: Set = new Set(chunk.files); + function processChunkJsFile(callback: (chunkFilename: string) => void): void { + let alreadyProcessedAFileInThisChunk: boolean = false; + for (const chunkFilename of chunk.files) { + if ( + chunkFilename.endsWith('.js') && // Ensure this is a JS file + !hotUpdateRegex.test(chunkFilename) && // Ensure this is not a webpack hot update + !alreadyProcessedAssets.has(chunkFilename) // Ensure this isn't a vendor chunk we've already processed + ) { + if (alreadyProcessedAFileInThisChunk) { + throw new Error( + `Found more than one JS file in chunk "${chunk.name}". This is not expected.` + ); + } + + alreadyProcessedAFileInThisChunk = true; + alreadyProcessedAssets.add(chunkFilename); + callback(chunkFilename); + } + } + } + + if (this._chunkHasLocalizedModules(chunk)) { + processChunkJsFile((chunkFilename) => { + if (chunkFilename.indexOf(Constants.LOCALE_NAME_PLACEHOLDER) === -1) { + throw new Error( + `Asset ${chunkFilename} is expected to be localized, but is missing a locale placeholder` + ); + } + + const asset: IAsset = compilation.assets[chunkFilename]; + + const resultingAssets: Map = + AssetProcessor.processLocalizedAsset({ + plugin: this, + compilation, + assetName: chunkFilename, + asset, + chunk, + chunkHasLocalizedModules: this._chunkHasLocalizedModules.bind(this), + locales: this._locales, + noStringsLocaleName: this._noStringsLocaleName, + fillMissingTranslationStrings: this._fillMissingTranslationStrings, + defaultLocale: this._defaultLocale + }); + + // Delete the existing asset because it's been renamed + delete compilation.assets[chunkFilename]; + chunkFilesSet.delete(chunkFilename); + + const localizedChunkAssets: ILocaleElementMap = {}; + for (const [locale, newAsset] of resultingAssets) { + compilation.assets[newAsset.filename] = newAsset.asset; + localizedChunkAssets[locale] = newAsset.filename; + chunkFilesSet.add(newAsset.filename); + } + + if (chunk.hasRuntime()) { + // This is an entrypoint + localizationStats.entrypoints[chunk.name] = { + localizedAssets: localizedChunkAssets + }; + } else { + // This is a secondary chunk + if (chunk.name) { + localizationStats.namedChunkGroups[chunk.name] = { + localizedAssets: localizedChunkAssets + }; + } + } + + chunk.localizedFiles = localizedChunkAssets; + }); + } else { + processChunkJsFile((chunkFilename) => { + const asset: IAsset = compilation.assets[chunkFilename]; + + const resultingAsset: IProcessAssetResult = AssetProcessor.processNonLocalizedAsset({ + plugin: this, + compilation, + assetName: chunkFilename, + asset, + chunk, + noStringsLocaleName: this._noStringsLocaleName, + chunkHasLocalizedModules: this._chunkHasLocalizedModules.bind(this) + }); + + // Delete the existing asset because it's been renamed + delete compilation.assets[chunkFilename]; + chunkFilesSet.delete(chunkFilename); + + compilation.assets[resultingAsset.filename] = resultingAsset.asset; + chunkFilesSet.add(resultingAsset.filename); + }); + } + + chunk.files = Array.from(chunkFilesSet); + } + + if (this._options.localizationStats) { + if (this._options.localizationStats.dropPath) { + const resolvedLocalizationStatsDropPath: string = path.resolve( + compiler.outputPath, + this._options.localizationStats.dropPath + ); + JsonFile.save(localizationStats, resolvedLocalizationStatsDropPath, { + ensureFolderExists: true + }); + } + + if (this._options.localizationStats.callback) { + try { + this._options.localizationStats.callback(localizationStats); + } catch (e) { + /* swallow errors from the callback */ + } + } + } + }); + } + } + } + + /** + * @internal + * + * @returns + */ + public addDefaultLocFile( + terminal: ITerminal, + localizedResourcePath: string, + localizedResourceData: ILocalizationFile + ): IAddDefaultLocFileResult { + const additionalLoadedFilePaths: string[] = []; + const errors: Error[] = []; + + const locFileData: ILocaleFileData = this._convertLocalizationFileToLocData(localizedResourceData); + this._addLocFile(this._defaultLocale, localizedResourcePath, locFileData); + + const normalizeLocalizedData: (localizedData: ILocaleFileData | string) => ILocaleFileData = ( + localizedData + ) => { + if (typeof localizedData === 'string') { + additionalLoadedFilePaths.push(localizedData); + const localizationFile: ILocalizationFile = parseLocFile({ + filePath: localizedData, + content: FileSystem.readFile(localizedData), + terminal: terminal, + resxNewlineNormalization: this._resxNewlineNormalization, + ignoreMissingResxComments: this._ignoreMissingResxComments + }); + + return this._convertLocalizationFileToLocData(localizationFile); + } else { + return localizedData; + } + }; + + const missingLocales: string[] = []; + for (const [translatedLocaleName, translatedStrings] of Object.entries( + this._resolvedTranslatedStringsFromOptions + )) { + const translatedLocFileFromOptions: ILocaleFileData | string | undefined = + translatedStrings[localizedResourcePath]; + if (!translatedLocFileFromOptions) { + missingLocales.push(translatedLocaleName); + } else { + const translatedLocFileData: ILocaleFileData = normalizeLocalizedData(translatedLocFileFromOptions); + this._addLocFile(translatedLocaleName, localizedResourcePath, translatedLocFileData); + } + } + + if (missingLocales.length > 0 && this._options.localizedData.resolveMissingTranslatedStrings) { + let resolvedTranslatedData: IResolvedMissingTranslations | undefined = undefined; + try { + resolvedTranslatedData = this._options.localizedData.resolveMissingTranslatedStrings( + missingLocales, + localizedResourcePath + ); + } catch (e) { + errors.push(e as Error); + } + + if (resolvedTranslatedData) { + for (const [resolvedLocaleName, resolvedLocaleData] of Object.entries(resolvedTranslatedData)) { + if (resolvedLocaleData) { + const translatedLocFileData: ILocaleFileData = normalizeLocalizedData(resolvedLocaleData); + this._addLocFile(resolvedLocaleName, localizedResourcePath, translatedLocFileData); + } + } + } + } + + this._pseudolocalizers.forEach((pseudolocalizer: (str: string) => string, pseudolocaleName: string) => { + const pseudolocFileData: ILocaleFileData = {}; + + for (const [stringName, stringValue] of Object.entries(locFileData)) { + pseudolocFileData[stringName] = pseudolocalizer(stringValue); + } + + this._addLocFile(pseudolocaleName, localizedResourcePath, pseudolocFileData); + }); + + return { additionalLoadedFilePaths, errors }; + } + + /** + * @internal + */ + public getDataForSerialNumber(serialNumber: string): IStringSerialNumberData | undefined { + return this._stringPlaceholderMap.get(serialNumber); + } + + private _addLocFile( + localeName: string, + localizedFilePath: string, + localizedFileData: ILocaleFileData + ): void { + const filesMap: Map> = this._resolvedLocalizedStrings.get(localeName)!; + + const stringsMap: Map = new Map(); + filesMap.set(localizedFilePath, stringsMap); + + for (const [stringName, stringValue] of Object.entries(localizedFileData)) { + const stringKey: string = `${localizedFilePath}?${stringName}`; + if (!this.stringKeys.has(stringKey)) { + const placeholder: IStringPlaceholder = this._getPlaceholderString(); + this.stringKeys.set(stringKey, placeholder); + } + + const placeholder: IStringPlaceholder = this.stringKeys.get(stringKey)!; + if (!this._stringPlaceholderMap.has(placeholder.suffix)) { + this._stringPlaceholderMap.set(placeholder.suffix, { + values: { + [this._passthroughLocaleName]: stringName + }, + locFilePath: localizedFilePath, + stringName: stringName + }); + } + + this._stringPlaceholderMap.get(placeholder.suffix)!.values[localeName] = stringValue; + + stringsMap.set(stringName, stringValue); + } + } + + private _initializeAndValidateOptions( + configuration: Webpack.Configuration, + isWebpackDevServer: boolean + ): { errors: Error[]; warnings: Error[] } { + const errors: Error[] = []; + const warnings: Error[] = []; + + function ensureValidLocaleName(localeName: string): boolean { + const LOCALE_NAME_REGEX: RegExp = /[a-z-]/i; + if (!localeName.match(LOCALE_NAME_REGEX)) { + errors.push( + new Error(`Invalid locale name: ${localeName}. Locale names may only contain letters and hyphens.`) + ); + return false; + } else { + return true; + } + } + + // START configuration + if ( + !configuration.output || + !configuration.output.filename || + typeof configuration.output.filename !== 'string' || + configuration.output.filename.indexOf(Constants.LOCALE_FILENAME_TOKEN) === -1 + ) { + errors.push( + new Error( + 'The configuration.output.filename property must be provided, must be a string, and must include ' + + `the ${Constants.LOCALE_FILENAME_TOKEN} placeholder` + ) + ); + } + // END configuration + + // START misc options + // eslint-disable-next-line no-lone-blocks + { + this._globsToIgnore = this._options.globsToIgnore; + } + // END misc options + + // START options.localizedData + if (this._options.localizedData) { + this._ignoreMissingResxComments = this._options.localizedData.ignoreMissingResxComments; + + // START options.localizedData.passthroughLocale + if (this._options.localizedData.passthroughLocale) { + const { usePassthroughLocale, passthroughLocaleName = 'passthrough' } = + this._options.localizedData.passthroughLocale; + if (usePassthroughLocale) { + this._passthroughLocaleName = passthroughLocaleName; + this._locales.add(passthroughLocaleName); + } + } + // END options.localizedData.passthroughLocale + + // START options.localizedData.translatedStrings + const { translatedStrings } = this._options.localizedData; + this._resolvedTranslatedStringsFromOptions = {}; + if (translatedStrings) { + for (const [localeName, locale] of Object.entries(translatedStrings)) { + if (this._locales.has(localeName)) { + errors.push( + Error( + `The locale "${localeName}" appears multiple times. ` + + 'There may be multiple instances with different casing.' + ) + ); + return { errors, warnings }; + } + + if (!ensureValidLocaleName(localeName)) { + return { errors, warnings }; + } + + this._locales.add(localeName); + this._resolvedLocalizedStrings.set(localeName, new Map>()); + this._resolvedTranslatedStringsFromOptions[localeName] = {}; + + const locFilePathsInLocale: Set = new Set(); + + for (const [locFilePath, locFileDataFromOptions] of Object.entries(locale)) { + if (locale.hasOwnProperty(locFilePath)) { + const normalizedLocFilePath: string = path.resolve(configuration.context!, locFilePath); + + if (locFilePathsInLocale.has(normalizedLocFilePath)) { + errors.push( + new Error( + `The localization file path "${locFilePath}" appears multiple times in locale ${localeName}. ` + + 'There may be multiple instances with different casing.' + ) + ); + return { errors, warnings }; + } + + locFilePathsInLocale.add(normalizedLocFilePath); + + const normalizedLocFileDataFromOptions: string | ILocaleFileData = + typeof locFileDataFromOptions === 'string' + ? path.resolve(configuration.context!, locFileDataFromOptions) + : locFileDataFromOptions; + + this._resolvedTranslatedStringsFromOptions[localeName][normalizedLocFilePath] = + normalizedLocFileDataFromOptions; + } + } + } + } + // END options.localizedData.translatedStrings + + // START options.localizedData.defaultLocale + if (this._options.localizedData.defaultLocale) { + const { localeName, fillMissingTranslationStrings } = this._options.localizedData.defaultLocale; + if (this._options.localizedData.defaultLocale.localeName) { + if (this._locales.has(localeName)) { + errors.push(new Error('The default locale is also specified in the translated strings.')); + return { errors, warnings }; + } else if (!ensureValidLocaleName(localeName)) { + return { errors, warnings }; + } + + this._locales.add(localeName); + this._resolvedLocalizedStrings.set(localeName, new Map>()); + this._defaultLocale = localeName; + this._fillMissingTranslationStrings = !!fillMissingTranslationStrings; + } else { + errors.push(new Error('Missing default locale name')); + return { errors, warnings }; + } + } else { + errors.push(new Error('Missing default locale options.')); + return { errors, warnings }; + } + // END options.localizedData.defaultLocale + + // START options.localizedData.pseudoLocales + if (this._options.localizedData.pseudolocales) { + for (const [pseudolocaleName, pseudoLocaleOpts] of Object.entries( + this._options.localizedData.pseudolocales + )) { + if (this._defaultLocale === pseudolocaleName) { + errors.push( + new Error(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`) + ); + return { errors, warnings }; + } + + if (this._locales.has(pseudolocaleName)) { + errors.push( + new Error( + `A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.` + ) + ); + return { errors, warnings }; + } + + this._pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); + this._locales.add(pseudolocaleName); + this._resolvedLocalizedStrings.set(pseudolocaleName, new Map>()); + } + } + // END options.localizedData.pseudoLocales + + // START options.localizedData.normalizeResxNewlines + if (this._options.localizedData.normalizeResxNewlines) { + switch (this._options.localizedData.normalizeResxNewlines) { + case 'crlf': { + this._resxNewlineNormalization = NewlineKind.CrLf; + break; + } + + case 'lf': { + this._resxNewlineNormalization = NewlineKind.Lf; + break; + } + + default: { + errors.push( + new Error( + `Unexpected value "${this._options.localizedData.normalizeResxNewlines}" for option ` + + '"localizedData.normalizeResxNewlines"' + ) + ); + break; + } + } + } + // END options.localizedData.normalizeResxNewlines + } else if (!isWebpackDevServer) { + throw new Error('Localized data must be provided unless webpack dev server is running.'); + } + // END options.localizedData + + // START options.noStringsLocaleName + if ( + this._options.noStringsLocaleName === undefined || + this._options.noStringsLocaleName === null || + !ensureValidLocaleName(this._options.noStringsLocaleName) + ) { + this._noStringsLocaleName = 'none'; + } else { + this._noStringsLocaleName = this._options.noStringsLocaleName; + } + // END options.noStringsLocaleName + + return { errors, warnings }; + } + + private _getPlaceholderString(): IStringPlaceholder { + const suffix: string = (this._stringPlaceholderCounter++).toString(); + return { + value: `${Constants.STRING_PLACEHOLDER_PREFIX}_\\_${Constants.STRING_PLACEHOLDER_LABEL}_${suffix}`, + suffix: suffix + }; + } + + private _chunkHasLocalizedModules(chunk: Webpack.compilation.Chunk): boolean { + let chunkHasAnyLocModules: boolean | undefined = EntityMarker.getMark(chunk); + if (chunkHasAnyLocModules === undefined) { + chunkHasAnyLocModules = false; + for (const module of chunk.getModules()) { + if (EntityMarker.getMark(module)) { + chunkHasAnyLocModules = true; + break; + } + } + + // If this chunk doesn't directly contain any localized resources, it still + // needs to be localized if it's an entrypoint chunk (i.e. - it has a runtime) + // and it loads localized async chunks. + // In that case, the generated chunk URL generation code needs to contain + // the locale name. + if (!chunkHasAnyLocModules && chunk.hasRuntime()) { + for (const asyncChunk of chunk.getAllAsyncChunks()) { + if (this._chunkHasLocalizedModules(asyncChunk)) { + chunkHasAnyLocModules = true; + break; + } + } + } + + EntityMarker.markEntity(chunk, chunkHasAnyLocModules); + } + + return chunkHasAnyLocModules; + } + + private _convertLocalizationFileToLocData(locFile: ILocalizationFile): ILocaleFileData { + const locFileData: ILocaleFileData = {}; + for (const [stringName, locFileEntry] of Object.entries(locFile)) { + locFileData[stringName] = locFileEntry.value; + } + + return locFileData; + } +} diff --git a/webpack/webpack4-localization-plugin/src/WebpackConfigurationUpdater.ts b/webpack/webpack4-localization-plugin/src/WebpackConfigurationUpdater.ts new file mode 100644 index 00000000000..a2f11ca07a1 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/WebpackConfigurationUpdater.ts @@ -0,0 +1,158 @@ +// 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 { minimatch } from 'minimatch'; +import type * as Webpack from 'webpack'; + +import type * as SetPublicPathPluginPackageType from '@rushstack/set-webpack-public-path-plugin'; +import { type NewlineKind, Text } from '@rushstack/node-core-library'; +import type { IgnoreStringFunction } from '@rushstack/localization-utilities'; + +import { Constants } from './utilities/Constants'; +import type { LocalizationPlugin } from './LocalizationPlugin'; +import type { ILocLoaderOptions } from './loaders/LocLoader'; +import type { IBaseLoaderOptions } from './loaders/LoaderFactory'; + +export interface IWebpackConfigurationUpdaterOptions { + pluginInstance: LocalizationPlugin; + configuration: Webpack.Configuration; + globsToIgnore: string[] | undefined; + localeNameOrPlaceholder: string; + resxNewlineNormalization: NewlineKind | undefined; + ignoreMissingResxComments: boolean | undefined; + ignoreString: IgnoreStringFunction | undefined; +} + +const FILE_TOKEN_REGEX: RegExp = new RegExp(Text.escapeRegExp('[file]')); + +export class WebpackConfigurationUpdater { + public static amendWebpackConfigurationForMultiLocale(options: IWebpackConfigurationUpdaterOptions): void { + const loader: string = path.resolve(__dirname, 'loaders', 'LocLoader.js'); + const loaderOptions: ILocLoaderOptions = { + pluginInstance: options.pluginInstance, + resxNewlineNormalization: options.resxNewlineNormalization, + ignoreMissingResxComments: options.ignoreMissingResxComments, + ignoreString: options.ignoreString + }; + + WebpackConfigurationUpdater._addLoadersForLocFiles(options, loader, loaderOptions); + + WebpackConfigurationUpdater._tryUpdateLocaleTokenInPublicPathPlugin(options); + + WebpackConfigurationUpdater._tryUpdateSourceMapFilename(options.configuration); + } + + public static amendWebpackConfigurationForInPlaceLocFiles( + options: IWebpackConfigurationUpdaterOptions + ): void { + const loader: string = path.resolve(__dirname, 'loaders', 'InPlaceLocFileLoader.js'); + const loaderOptions: IBaseLoaderOptions = { + resxNewlineNormalization: options.resxNewlineNormalization, + ignoreMissingResxComments: options.ignoreMissingResxComments, + ignoreString: options.ignoreString + }; + + WebpackConfigurationUpdater._addRulesToConfiguration(options.configuration, [ + { + test: Constants.RESOURCE_FILE_NAME_REGEXP, + use: [ + { + loader: loader, + options: loaderOptions + } + ], + type: 'json', + sideEffects: false + } + ]); + } + + private static _tryUpdateLocaleTokenInPublicPathPlugin(options: IWebpackConfigurationUpdaterOptions): void { + let setPublicPathPlugin: typeof SetPublicPathPluginPackageType.SetPublicPathPlugin | undefined; + try { + const pluginPackage: typeof SetPublicPathPluginPackageType = require('@rushstack/set-webpack-public-path-plugin'); + setPublicPathPlugin = pluginPackage.SetPublicPathPlugin; + } catch (e) { + // public path plugin isn't present - ignore + } + + if (setPublicPathPlugin && options.configuration.plugins) { + for (const plugin of options.configuration.plugins) { + if (plugin instanceof setPublicPathPlugin) { + if ( + plugin.options && + plugin.options.scriptName && + plugin.options.scriptName.isTokenized && + plugin.options.scriptName.name + ) { + plugin.options.scriptName.name = plugin.options.scriptName.name.replace( + /\[locale\]/g, + options.localeNameOrPlaceholder + ); + } + } + } + } + } + + private static _addLoadersForLocFiles( + options: IWebpackConfigurationUpdaterOptions, + loader: string, + loaderOptions: IBaseLoaderOptions + ): void { + const { globsToIgnore, configuration } = options; + const rules: Webpack.RuleSetCondition = + globsToIgnore && globsToIgnore.length > 0 + ? { + include: Constants.RESOURCE_FILE_NAME_REGEXP, + exclude: (filePath: string): boolean => + globsToIgnore.some((glob: string): boolean => minimatch(filePath, glob)) + } + : Constants.RESOURCE_FILE_NAME_REGEXP; + WebpackConfigurationUpdater._addRulesToConfiguration(configuration, [ + { + test: rules, + use: [ + { + loader: loader, + options: loaderOptions + } + ], + type: 'json', + sideEffects: false + } + ]); + } + + private static _addRulesToConfiguration( + configuration: Webpack.Configuration, + rules: Webpack.RuleSetRule[] + ): void { + if (!configuration.module) { + configuration.module = { + rules: [] + }; + } + + if (!configuration.module.rules) { + configuration.module.rules = []; + } + + configuration.module.rules.push(...rules); + } + + private static _tryUpdateSourceMapFilename(configuration: Webpack.Configuration): void { + if (!configuration.output) { + configuration.output = {}; // This should never happen + } + + if (configuration.output.sourceMapFilename !== undefined) { + configuration.output.sourceMapFilename = configuration.output.sourceMapFilename.replace( + FILE_TOKEN_REGEX, + Constants.NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN + ); + } + } +} diff --git a/webpack/webpack4-localization-plugin/src/index.ts b/webpack/webpack4-localization-plugin/src/index.ts new file mode 100644 index 00000000000..33456b6c8ff --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/index.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { LocalizationPlugin, type IStringPlaceholder as _IStringPlaceholder } from './LocalizationPlugin'; + +export type { + IDefaultLocaleOptions, + ILocaleData, + ILocaleElementMap, + ILocaleFileData, + ILocalizationPluginOptions, + ILocalizationStats, + ILocalizationStatsChunkGroup, + ILocalizationStatsEntrypoint, + ILocalizationStatsOptions, + ILocalizedData, + ILocalizedStrings, + IPassthroughLocaleOptions, + IPseudolocalesOptions, + IResolvedMissingTranslations, + ITypingsGenerationOptions +} from './interfaces'; + +export type { ILocalizedWebpackChunk } from './webpackInterfaces'; diff --git a/webpack/webpack4-localization-plugin/src/interfaces.ts b/webpack/webpack4-localization-plugin/src/interfaces.ts new file mode 100644 index 00000000000..b769f2b7f50 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/interfaces.ts @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IgnoreStringFunction, IPseudolocaleOptions } from '@rushstack/localization-utilities'; + +/** + * Options for the passthrough locale. + * + * @public + */ +export interface IPassthroughLocaleOptions { + /** + * If this is set to `true`, a passthrough locale will be included in the output + */ + usePassthroughLocale?: boolean; + + /** + * If {@link IPassthroughLocaleOptions.usePassthroughLocale} is set, use this name for the passthrough locale. + * Defaults to "passthrough" + */ + passthroughLocaleName?: string; +} + +/** + * Options for typing generation. + * + * @public + */ +export interface ITypingsGenerationOptions { + /** + * This property specifies the folder in which `.d.ts` files for loc files should be dropped. + */ + generatedTsFolder: string; + + /** + * Optional additional folders into which `.d.ts` files for loc files should be dropped. + */ + secondaryGeneratedTsFolders?: string[]; + + /** + * This optional property overrides the compiler context for discovery of localization files + * for which typings should be generated. + */ + sourceRoot?: string; + + /** + * If this option is set to `true`, loc modules typings will be exported wrapped in a `default` property. + */ + exportAsDefault?: boolean; + + /** + * @deprecated + * Use {@link ILocalizationPluginOptions.ignoreString} instead. + * + * @internalRemarks + * TODO: Remove when version 1.0.0 is released. + */ + ignoreString?: (resxFilePath: string, stringName: string) => boolean; + + /** + * Optionally, provide a function that will process string comments. The returned value will become the + * TSDoc comment for the string in the typings. + */ + processComment?: ( + comment: string | undefined, + resxFilePath: string, + stringName: string + ) => string | undefined; +} + +/** + * @public + */ +export interface IDefaultLocaleOptions { + /** + * This required property specifies the name of the locale used in the + * `.resx`, `.loc.json`, and `.resjson` files in the source + */ + localeName: string; + + /** + * If this option is set to `true`, strings that are missing from + * `localizedData.translatedStrings` will be provided by the default locale + */ + fillMissingTranslationStrings?: boolean; +} + +/** + * Options for generated pseudolocales. + * + * @public + */ +export interface IPseudolocalesOptions { + [pseudoLocaleName: string]: IPseudolocaleOptions; +} + +/** + * @public + */ +export interface ILocalizedData { + /** + * Options for the locale used in the source localized data files. + */ + defaultLocale: IDefaultLocaleOptions; + + /** + * Use this parameter to specify the translated data. + */ + translatedStrings: ILocalizedStrings; + + /** + * Use this parameter to specify a function used to load translations missing from + * the {@link ILocalizedData.translatedStrings} parameter. + */ + resolveMissingTranslatedStrings?: (locales: string[], filePath: string) => IResolvedMissingTranslations; + + /** + * Options around including a passthrough locale. + */ + passthroughLocale?: IPassthroughLocaleOptions; + + /** + * Options for pseudo-localization. + */ + pseudolocales?: IPseudolocalesOptions; + + /** + * Normalize newlines in RESX files to either CRLF (Windows-style) or LF ('nix style) + */ + normalizeResxNewlines?: 'lf' | 'crlf'; + + /** + * If set to true, do not warn on missing RESX `` element comments. + */ + ignoreMissingResxComments?: boolean; +} + +/** + * Options for how localization stats data should be produced. + * + * @public + */ +export interface ILocalizationStatsOptions { + /** + * This option is used to designate a path at which a JSON file describing the localized + * assets produced should be written. + */ + dropPath?: string; + + /** + * This option is used to specify a callback to be called with the stats data that would be + * dropped at `localizationStats.dropPath` after compilation completes. + */ + callback?: (stats: ILocalizationStats) => void; +} + +/** + * The options for localization. + * + * @public + */ +export interface ILocalizationPluginOptions { + /** + * Localization data. + */ + localizedData: ILocalizedData; + + /** + * This option is used to specify `.resx`, `.resx.json`, and `.loc.json` files that should not be processed by + * this plugin. + */ + globsToIgnore?: string[]; + + /** + * The value to replace the [locale] token with for chunks without localized strings. Defaults to "none" + */ + noStringsLocaleName?: string; + + /** + * Options for how localization stats data should be produced. + */ + localizationStats?: ILocalizationStatsOptions; + + /** + * This option is used to specify how and if TypeScript typings should be generated for loc files. + */ + typingsOptions?: ITypingsGenerationOptions; + + /** + * Optionally, provide a function that will be called for each string. If the function returns `true` + * the string will not be included. + */ + ignoreString?: IgnoreStringFunction; + + /** + * @deprecated + * Use {@link ILocalizationPluginOptions.globsToIgnore} instead. + * + * @internalRemarks + * TODO: Remove when version 1.0.0 is released. + */ + filesToIgnore?: string[]; +} + +/** + * @public + */ +export interface ILocaleFileData { + [stringName: string]: string; +} + +/** + * @public + */ +export interface IResolvedMissingTranslations { + [localeName: string]: string | ILocaleFileData; +} + +/** + * @public + */ +export interface ILocaleData { + [locFilePath: string]: string | ILocaleFileData; +} + +/** + * @public + */ +export interface ILocalizedStrings { + [locale: string]: ILocaleData; +} + +/** + * @public + */ +export interface ILocaleElementMap { + [locale: string]: string; +} + +/** + * @public + */ +export interface ILocalizationStatsEntrypoint { + localizedAssets: ILocaleElementMap; +} + +/** + * @public + */ +export interface ILocalizationStatsChunkGroup { + localizedAssets: ILocaleElementMap; +} + +/** + * @public + */ +export interface ILocalizationStats { + entrypoints: { [name: string]: ILocalizationStatsEntrypoint }; + namedChunkGroups: { [name: string]: ILocalizationStatsChunkGroup }; +} diff --git a/webpack/webpack4-localization-plugin/src/loaders/InPlaceLocFileLoader.ts b/webpack/webpack4-localization-plugin/src/loaders/InPlaceLocFileLoader.ts new file mode 100644 index 00000000000..ef8717477e5 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/loaders/InPlaceLocFileLoader.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 type { loader } from 'webpack'; + +import { Terminal } from '@rushstack/terminal'; +import { type ILocalizationFile, parseLocFile } from '@rushstack/localization-utilities'; + +import { loaderFactory, type IBaseLoaderOptions } from './LoaderFactory'; +import { LoaderTerminalProvider } from '../utilities/LoaderTerminalProvider'; + +export default loaderFactory(function ( + this: loader.LoaderContext, + locFilePath: string, + content: string, + options: IBaseLoaderOptions +) { + const locFileData: ILocalizationFile = parseLocFile({ + ...options, + content, + filePath: locFilePath, + terminal: new Terminal(LoaderTerminalProvider.getTerminalProviderForLoader(this)) + }); + const resultObject: { [stringName: string]: string } = {}; + for (const [stringName, stringValue] of Object.entries(locFileData)) { + resultObject[stringName] = stringValue.value; + } + + return resultObject; +}); diff --git a/webpack/webpack4-localization-plugin/src/loaders/LoaderFactory.ts b/webpack/webpack4-localization-plugin/src/loaders/LoaderFactory.ts new file mode 100644 index 00000000000..66d4d7d2d3a --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/loaders/LoaderFactory.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 type { loader } from 'webpack'; +import * as loaderUtils from 'loader-utils'; + +import type { NewlineKind } from '@rushstack/node-core-library'; +import type { IgnoreStringFunction } from '@rushstack/localization-utilities'; + +export interface IBaseLoaderOptions { + resxNewlineNormalization: NewlineKind | undefined; + ignoreMissingResxComments: boolean | undefined; + ignoreString: IgnoreStringFunction | undefined; +} + +export interface ILoaderResult { + [stringName: string]: string; +} + +export function loaderFactory( + innerLoader: (locFilePath: string, content: string, options: TOptions) => ILoaderResult +): loader.Loader { + return function (this: loader.LoaderContext, content: string | Buffer): string { + const options: TOptions = loaderUtils.getOptions(this) as TOptions; + if (typeof content !== 'string') { + content = content.toString(); + } + + const resultObject: ILoaderResult = innerLoader.call(this, this.resourcePath, content, options); + return JSON.stringify(resultObject); + }; +} diff --git a/webpack/webpack4-localization-plugin/src/loaders/LocLoader.ts b/webpack/webpack4-localization-plugin/src/loaders/LocLoader.ts new file mode 100644 index 00000000000..d6baf976164 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/loaders/LocLoader.ts @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { loader } from 'webpack'; + +import { Terminal } from '@rushstack/terminal'; +import { type ILocalizationFile, parseLocFile } from '@rushstack/localization-utilities'; + +import type { LocalizationPlugin } from '../LocalizationPlugin'; +import { loaderFactory, type IBaseLoaderOptions } from './LoaderFactory'; +import { EntityMarker } from '../utilities/EntityMarker'; +import { LoaderTerminalProvider } from '../utilities/LoaderTerminalProvider'; + +export interface ILocLoaderOptions extends IBaseLoaderOptions { + pluginInstance: LocalizationPlugin; +} + +export default loaderFactory(function ( + this: loader.LoaderContext, + locFilePath: string, + content: string, + options: ILocLoaderOptions +) { + const { pluginInstance } = options; + const terminal: Terminal = new Terminal(LoaderTerminalProvider.getTerminalProviderForLoader(this)); + const locFileData: ILocalizationFile = parseLocFile({ + ...options, + content, + terminal, + filePath: locFilePath + }); + const { additionalLoadedFilePaths, errors } = pluginInstance.addDefaultLocFile( + terminal, + locFilePath, + locFileData + ); + for (const additionalFile of additionalLoadedFilePaths) { + this.dependency(additionalFile); + } + + for (const error of errors) { + this.emitError(error); + } + + const resultObject: { [stringName: string]: string } = {}; + // eslint-disable-next-line guard-for-in + for (const stringName in locFileData) { + const stringKey: string = `${locFilePath}?${stringName}`; + if (pluginInstance.stringKeys.has(stringKey)) { + resultObject[stringName] = pluginInstance.stringKeys.get(stringKey)!.value; + } else { + throw new Error(`Unexpected - missing placeholder for string key "${stringKey}"`); + } + } + + EntityMarker.markEntity(this._module, true); + + return resultObject; +}); diff --git a/webpack/webpack4-localization-plugin/src/utilities/Constants.ts b/webpack/webpack4-localization-plugin/src/utilities/Constants.ts new file mode 100644 index 00000000000..d9d66a2ef7b --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/utilities/Constants.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 { Text } from '@rushstack/node-core-library'; + +export class Constants { + public static LOCALE_FILENAME_TOKEN: string = '[locale]'; + public static LOCALE_FILENAME_TOKEN_REGEX: RegExp = new RegExp( + Text.escapeRegExp(Constants.LOCALE_FILENAME_TOKEN), + 'gi' + ); + public static NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN: string = '[no-locale-file]'; + public static NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN_REGEX: RegExp = new RegExp( + Text.escapeRegExp(Constants.NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN), + 'gi' + ); + public static STRING_PLACEHOLDER_PREFIX: string = '_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9'; + + public static RESOURCE_FILE_NAME_REGEXP: RegExp = /\.(resx|resx\.json|loc\.json|resjson)$/i; + + public static STRING_PLACEHOLDER_LABEL: string = 'A'; + public static LOCALE_NAME_PLACEHOLDER_LABEL: string = 'B'; + public static JSONP_PLACEHOLDER_LABEL: string = 'C'; + + public static LOCALE_NAME_PLACEHOLDER: string = `${Constants.STRING_PLACEHOLDER_PREFIX}__${Constants.LOCALE_NAME_PLACEHOLDER_LABEL}_0`; + public static JSONP_PLACEHOLDER: string = `${Constants.STRING_PLACEHOLDER_PREFIX}__${Constants.JSONP_PLACEHOLDER_LABEL}+chunkId+_0`; +} diff --git a/webpack/webpack4-localization-plugin/src/utilities/EntityMarker.ts b/webpack/webpack4-localization-plugin/src/utilities/EntityMarker.ts new file mode 100644 index 00000000000..2e9d2ff9df6 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/utilities/EntityMarker.ts @@ -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 LABEL: unique symbol = Symbol('loc-plugin-marked'); + +export interface IMarkable { + [LABEL]: boolean; +} + +/** + * Use the functions on this class to mark webpack entities that contain localized resources. + */ +export class EntityMarker { + public static markEntity(module: TModule, value: boolean): void { + (module as unknown as IMarkable)[LABEL] = value; + } + + public static getMark(module: TModule): boolean | undefined { + return (module as unknown as IMarkable)[LABEL]; + } +} diff --git a/webpack/webpack4-localization-plugin/src/utilities/LoaderTerminalProvider.ts b/webpack/webpack4-localization-plugin/src/utilities/LoaderTerminalProvider.ts new file mode 100644 index 00000000000..7e33f70f568 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/utilities/LoaderTerminalProvider.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 * as webpack from 'webpack'; + +import { type ITerminalProvider, TerminalProviderSeverity } from '@rushstack/terminal'; + +export class LoaderTerminalProvider { + public static getTerminalProviderForLoader(loaderContext: webpack.loader.LoaderContext): ITerminalProvider { + return { + supportsColor: false, + eolCharacter: '\n', + write: (data: string, severity: TerminalProviderSeverity) => { + switch (severity) { + case TerminalProviderSeverity.error: { + loaderContext.emitError(new Error(data)); + break; + } + + case TerminalProviderSeverity.warning: { + loaderContext.emitWarning(new Error(data)); + break; + } + } + } + }; + } +} diff --git a/webpack/webpack4-localization-plugin/src/webpackInterfaces.ts b/webpack/webpack4-localization-plugin/src/webpackInterfaces.ts new file mode 100644 index 00000000000..9f0b84f00e0 --- /dev/null +++ b/webpack/webpack4-localization-plugin/src/webpackInterfaces.ts @@ -0,0 +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 webpack from 'webpack'; + +/** + * @public + */ +export interface ILocalizedWebpackChunk extends webpack.compilation.Chunk { + localizedFiles?: { [locale: string]: string }; +} diff --git a/webpack/webpack4-localization-plugin/tsconfig.json b/webpack/webpack4-localization-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/webpack/webpack4-localization-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/webpack4-module-minifier-plugin/.npmignore b/webpack/webpack4-module-minifier-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack4-module-minifier-plugin/CHANGELOG.json b/webpack/webpack4-module-minifier-plugin/CHANGELOG.json new file mode 100644 index 00000000000..29bca156cae --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/CHANGELOG.json @@ -0,0 +1,7249 @@ +{ + "name": "@rushstack/webpack4-module-minifier-plugin", + "entries": [ + { + "version": "0.14.7", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.14.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/module-minifier\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.13.113", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.113", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.30`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.13.112", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.112", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.29`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.13.111", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.111", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.28`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.13.110", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.110", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.27`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.13.109", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.109", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.26`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.13.108", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.108", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.25`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.13.107", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.107", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.24`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.13.106", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.106", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.13.105", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.105", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.13.104", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.104", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.13.103", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.103", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.13.102", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.102", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.13.101", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.101", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.13.100", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.100", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.13.99", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.99", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.13.98", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.98", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.13.97", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.97", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.13.96", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.96", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.13.95", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.95", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.13.94", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.94", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.13.93", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.93", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.13.92", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.92", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.13.91", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.91", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.13.90", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.90", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.13.89", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.89", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.13.88", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.88", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.13.87", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.87", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.13.86", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.86", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.13.85", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.85", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "patch": [ + { + "comment": "Prefer `os.availableParallelism()` to `os.cpus().length`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.13.84", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.84", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.13.83", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.83", + "date": "Wed, 22 Jan 2025 03:03:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.13.82", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.82", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.36`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.13.81", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.81", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.35`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.13.80", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.80", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.34`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.13.79", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.79", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.33`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.13.78", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.78", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.32`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.13.77", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.77", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.31`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.13.76", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.76", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.30`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.13.75", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.75", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.29`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.13.74", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.74", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.28`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.13.73", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.73", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.27`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.13.72", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.72", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.26`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.13.71", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.71", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.25`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.13.70", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.70", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.24`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.13.69", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.69", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.23`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.13.68", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.68", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.22`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.13.67", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.67", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.13.66", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.66", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.13.65", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.65", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.13.64", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.64", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.13.63", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.63", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.13.62", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.62", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.13.61", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.61", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.15`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.13.60", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.60", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.13.59", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.59", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.13.58", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.58", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.13.57", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.57", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.13.56", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.56", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.13.55", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.55", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.13.54", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.54", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.13.53", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.53", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.13.52", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.52", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.13.51", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.51", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.13.50", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.50", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.13.49", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.49", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.13.48", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.48", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.13.47", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.47", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.13.46", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.46", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.13.45", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.45", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.13.44", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.44", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.13.43", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.43", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.13.42", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.42", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.13.41", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.41", + "date": "Thu, 28 Mar 2024 22:42:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.40`" + } + ] + } + }, + { + "version": "0.13.40", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.13.39", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.39", + "date": "Sat, 16 Mar 2024 00:11:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.39`" + } + ] + } + }, + { + "version": "0.13.38", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.13.37", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.13.36", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.13.35", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.13.34", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.13.33", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.13.32", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.13.31", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.13.30", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.13.29", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.13.28", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.13.27", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.13.26", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.13.25", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.13.24", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.13.23", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.13.22", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.13.21", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.13.20", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.13.19", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.13.18", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.13.17", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.13.16", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.13.15", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.13.14", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.13.13", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.13.12", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.13.11", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.13.10", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.13.5", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.13.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.12.35", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.35", + "date": "Thu, 07 Sep 2023 03:35:43 GMT", + "comments": { + "patch": [ + { + "comment": "Update Webpack peerDependency to ~4.47.0." + } + ] + } + }, + { + "version": "0.12.34", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.34", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.12.33", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.33", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.12.32", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.32", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.12.31", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.31", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.12.30", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.30", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix calculation of rendered module positions to properly reflect character codes, not raw bytes." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.12.29", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.29", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.12.28", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.28", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.12.27", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.27", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.12.26", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.26", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.12.25", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.25", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.12.24", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.24", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.12.23", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.23", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.12.22", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.22", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.12.21", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.21", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.12.20", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.20", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.12.19", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.19", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.12.18", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.18", + "date": "Tue, 13 Jun 2023 01:49:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.12.17", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.17", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.12.16", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.16", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.12.15", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.15", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.14", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.13", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.12", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.11", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.10", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.9", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.8", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.7", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.6", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.5", + "date": "Thu, 04 May 2023 15:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.9`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.4", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix async import compressor erroring when encountering unresolved dependencies." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.3", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.2", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.1", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.12.0", + "date": "Wed, 26 Apr 2023 00:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Emit metadata about character position of rendered modules." + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.11.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.10.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.9.48", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.48", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.9.47", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.47", + "date": "Sat, 28 Jan 2023 01:22:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.48`" + } + ] + } + }, + { + "version": "0.9.46", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.46", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.9.45", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.45", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.9.44", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.44", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.9.43", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.43", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.9.42", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.42", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.9.41", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.41", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.9.40", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.40", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.9.39", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.39", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.9.38", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.38", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.9.37", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.37", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.9.36", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.36", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.9.35", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.35", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.9.34", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.34", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.9.33", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.33", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.9.32", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.32", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.9.31", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.31", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.9.30", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.30", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.9.29", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.29", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.9.28", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.28", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.9.27", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.27", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.9.26", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.26", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.9.25", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.25", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.9.24", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.24", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.9.23", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.23", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.22", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.21", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.20", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.19", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.18", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.17", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.16", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.15", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.14", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.13", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.12", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.11", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.10", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.9", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.8", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.7", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.6", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.5", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/webpack4-module-minifier-plugin_v0.9.4", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "patch": [ + { + "comment": "Rename from @rushstack/module-minifier-plugin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/module-minifier-plugin_v0.9.3", + "date": "Tue, 21 Jun 2022 20:27:19 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade @types/webpack and add missing optional peer dependency." + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/module-minifier-plugin_v0.9.2", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/module-minifier-plugin_v0.9.1", + "date": "Wed, 25 May 2022 22:25:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.6`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/module-minifier-plugin_v0.9.0", + "date": "Fri, 20 May 2022 00:11:55 GMT", + "comments": { + "minor": [ + { + "comment": "Factor out minifiers into @rushstack/module-minifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.8.17", + "tag": "@rushstack/module-minifier-plugin_v0.8.17", + "date": "Thu, 19 May 2022 15:13:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.5`" + } + ] + } + }, + { + "version": "0.8.16", + "tag": "@rushstack/module-minifier-plugin_v0.8.16", + "date": "Sat, 14 May 2022 03:01:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.4`" + } + ] + } + }, + { + "version": "0.8.15", + "tag": "@rushstack/module-minifier-plugin_v0.8.15", + "date": "Tue, 10 May 2022 01:20:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.3`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/module-minifier-plugin_v0.8.14", + "date": "Wed, 04 May 2022 23:29:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.2`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/module-minifier-plugin_v0.8.13", + "date": "Tue, 26 Apr 2022 00:10:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.1`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/module-minifier-plugin_v0.8.12", + "date": "Sat, 23 Apr 2022 02:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.0`" + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/module-minifier-plugin_v0.8.11", + "date": "Fri, 15 Apr 2022 00:12:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.11`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/module-minifier-plugin_v0.8.10", + "date": "Wed, 13 Apr 2022 15:12:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.10`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/module-minifier-plugin_v0.8.9", + "date": "Tue, 12 Apr 2022 23:29:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.9`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/module-minifier-plugin_v0.8.8", + "date": "Tue, 12 Apr 2022 02:58:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.8`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/module-minifier-plugin_v0.8.7", + "date": "Sat, 09 Apr 2022 19:07:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.7`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/module-minifier-plugin_v0.8.6", + "date": "Sat, 09 Apr 2022 02:24:26 GMT", + "comments": { + "patch": [ + { + "comment": "Rename the \"master\" branch to \"main\"." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.6`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/module-minifier-plugin_v0.8.5", + "date": "Fri, 08 Apr 2022 20:05:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.5`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/module-minifier-plugin_v0.8.4", + "date": "Wed, 06 Apr 2022 22:35:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.4`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/module-minifier-plugin_v0.8.3", + "date": "Thu, 31 Mar 2022 02:06:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.3`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/module-minifier-plugin_v0.8.2", + "date": "Sat, 19 Mar 2022 08:05:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.2`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/module-minifier-plugin_v0.8.1", + "date": "Tue, 15 Mar 2022 19:15:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.1`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/module-minifier-plugin_v0.8.0", + "date": "Thu, 17 Feb 2022 00:32:30 GMT", + "comments": { + "minor": [ + { + "comment": "Include plugin state in webpack hash calculations, such that updating the plugin options changes the compilation and chunk hashes." + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/module-minifier-plugin_v0.7.1", + "date": "Fri, 11 Feb 2022 10:30:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.8.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/module-minifier-plugin_v0.7.0", + "date": "Fri, 11 Feb 2022 01:12:20 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for `compressAsyncImports` flag. Modify `usePortableModules` option to use `module.identifier()` instead of `module.resource` so that loader configuration is accounted for during deduplication. Switch to overriding the render function on the JavaScript module template to deduplicate rendering across chunks." + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/module-minifier-plugin_v0.6.14", + "date": "Tue, 25 Jan 2022 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.1`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/module-minifier-plugin_v0.6.13", + "date": "Fri, 21 Jan 2022 01:10:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.7.0`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/module-minifier-plugin_v0.6.12", + "date": "Thu, 20 Jan 2022 02:43:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.6.0`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/module-minifier-plugin_v0.6.11", + "date": "Wed, 05 Jan 2022 16:07:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.2`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/module-minifier-plugin_v0.6.10", + "date": "Mon, 27 Dec 2021 16:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/module-minifier-plugin_v0.6.9", + "date": "Tue, 14 Dec 2021 19:27:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.44.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.5.0`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/module-minifier-plugin_v0.6.8", + "date": "Thu, 09 Dec 2021 20:34:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.3`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/module-minifier-plugin_v0.6.7", + "date": "Thu, 09 Dec 2021 00:21:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.2`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/module-minifier-plugin_v0.6.6", + "date": "Wed, 08 Dec 2021 19:05:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.43.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.1`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/module-minifier-plugin_v0.6.5", + "date": "Wed, 08 Dec 2021 16:14:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.4.0`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/module-minifier-plugin_v0.6.4", + "date": "Mon, 06 Dec 2021 16:08:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.3.0`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/module-minifier-plugin_v0.6.3", + "date": "Fri, 03 Dec 2021 03:05:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/module-minifier-plugin_v0.6.2", + "date": "Tue, 30 Nov 2021 20:18:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/module-minifier-plugin_v0.6.1", + "date": "Mon, 29 Nov 2021 07:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/module-minifier-plugin_v0.6.0", + "date": "Wed, 24 Nov 2021 01:10:33 GMT", + "comments": { + "minor": [ + { + "comment": "Export a getIdentifier function for generating safe JavaScript identifiers." + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/module-minifier-plugin_v0.5.0", + "date": "Thu, 18 Nov 2021 01:10:06 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade to terser 5.10.2, fix source maps in NoopMinifier" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/module-minifier-plugin_v0.4.36", + "date": "Sat, 13 Nov 2021 01:09:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a minor mistake in the README." + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/module-minifier-plugin_v0.4.35", + "date": "Sat, 06 Nov 2021 00:09:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.30`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/module-minifier-plugin_v0.4.34", + "date": "Fri, 05 Nov 2021 15:09:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.29`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/module-minifier-plugin_v0.4.33", + "date": "Thu, 28 Oct 2021 00:08:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.42.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.28`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/module-minifier-plugin_v0.4.32", + "date": "Wed, 27 Oct 2021 00:08:15 GMT", + "comments": { + "patch": [ + { + "comment": "Update the package.json repository field to include the directory property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.27`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/module-minifier-plugin_v0.4.31", + "date": "Wed, 13 Oct 2021 15:09:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.26`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/module-minifier-plugin_v0.4.30", + "date": "Fri, 08 Oct 2021 09:35:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.25`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/module-minifier-plugin_v0.4.29", + "date": "Fri, 08 Oct 2021 08:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.24`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/module-minifier-plugin_v0.4.28", + "date": "Thu, 07 Oct 2021 23:43:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.23`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/module-minifier-plugin_v0.4.27", + "date": "Thu, 07 Oct 2021 07:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/module-minifier-plugin_v0.4.26", + "date": "Wed, 06 Oct 2021 15:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/module-minifier-plugin_v0.4.25", + "date": "Wed, 06 Oct 2021 02:41:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/module-minifier-plugin_v0.4.24", + "date": "Tue, 05 Oct 2021 15:08:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.41.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/module-minifier-plugin_v0.4.23", + "date": "Mon, 04 Oct 2021 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.40.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/module-minifier-plugin_v0.4.22", + "date": "Fri, 24 Sep 2021 00:09:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/module-minifier-plugin_v0.4.21", + "date": "Thu, 23 Sep 2021 00:10:41 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `@types/node` dependency to version to version 12." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/module-minifier-plugin_v0.4.20", + "date": "Wed, 22 Sep 2021 03:27:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.39.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/module-minifier-plugin_v0.4.19", + "date": "Wed, 22 Sep 2021 00:09:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/module-minifier-plugin_v0.4.18", + "date": "Sat, 18 Sep 2021 03:05:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/module-minifier-plugin_v0.4.17", + "date": "Tue, 14 Sep 2021 01:17:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.38.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/module-minifier-plugin_v0.4.16", + "date": "Mon, 13 Sep 2021 15:07:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/module-minifier-plugin_v0.4.15", + "date": "Fri, 10 Sep 2021 15:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/module-minifier-plugin_v0.4.14", + "date": "Wed, 08 Sep 2021 19:06:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/module-minifier-plugin_v0.4.13", + "date": "Wed, 08 Sep 2021 00:08:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/module-minifier-plugin_v0.4.12", + "date": "Fri, 03 Sep 2021 00:09:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/module-minifier-plugin_v0.4.11", + "date": "Tue, 31 Aug 2021 00:07:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.37.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/module-minifier-plugin_v0.4.10", + "date": "Fri, 27 Aug 2021 00:07:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/module-minifier-plugin_v0.4.9", + "date": "Fri, 20 Aug 2021 15:08:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/module-minifier-plugin_v0.4.8", + "date": "Wed, 18 Aug 2021 00:06:54 GMT", + "comments": { + "patch": [ + { + "comment": "Fix compatibility issue with mini-css-extract-plugin and other plugins that introduce non-JavaScript modules and asset types." + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/module-minifier-plugin_v0.4.7", + "date": "Fri, 13 Aug 2021 00:09:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/module-minifier-plugin_v0.4.6", + "date": "Thu, 12 Aug 2021 18:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/module-minifier-plugin_v0.4.5", + "date": "Thu, 12 Aug 2021 01:28:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/module-minifier-plugin_v0.4.4", + "date": "Wed, 11 Aug 2021 23:14:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.36.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/module-minifier-plugin_v0.4.3", + "date": "Wed, 11 Aug 2021 00:07:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.15`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/module-minifier-plugin_v0.4.2", + "date": "Sat, 31 Jul 2021 00:52:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.35.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/module-minifier-plugin_v0.4.1", + "date": "Thu, 22 Jul 2021 22:31:41 GMT", + "comments": { + "patch": [ + { + "comment": "Fix comment file generation logic. Fix WorkerPoolMinifier hanging the process." + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/module-minifier-plugin_v0.4.0", + "date": "Thu, 22 Jul 2021 15:07:19 GMT", + "comments": { + "minor": [ + { + "comment": "Separate comment extraction from minification." + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/module-minifier-plugin_v0.3.75", + "date": "Wed, 14 Jul 2021 15:06:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/module-minifier-plugin_v0.3.74", + "date": "Tue, 13 Jul 2021 23:00:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/module-minifier-plugin_v0.3.73", + "date": "Mon, 12 Jul 2021 23:08:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/module-minifier-plugin_v0.3.72", + "date": "Thu, 08 Jul 2021 23:41:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/module-minifier-plugin_v0.3.71", + "date": "Thu, 08 Jul 2021 06:00:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/module-minifier-plugin_v0.3.70", + "date": "Thu, 01 Jul 2021 15:08:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/module-minifier-plugin_v0.3.69", + "date": "Wed, 30 Jun 2021 19:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/module-minifier-plugin_v0.3.68", + "date": "Wed, 30 Jun 2021 15:06:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/module-minifier-plugin_v0.3.67", + "date": "Wed, 30 Jun 2021 01:37:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/module-minifier-plugin_v0.3.66", + "date": "Fri, 25 Jun 2021 00:08:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.34.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/module-minifier-plugin_v0.3.65", + "date": "Fri, 18 Jun 2021 06:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/module-minifier-plugin_v0.3.64", + "date": "Wed, 16 Jun 2021 18:53:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/module-minifier-plugin_v0.3.63", + "date": "Wed, 16 Jun 2021 15:07:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/module-minifier-plugin_v0.3.62", + "date": "Tue, 15 Jun 2021 20:38:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.3.61", + "tag": "@rushstack/module-minifier-plugin_v0.3.61", + "date": "Fri, 11 Jun 2021 23:26:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.31`" + } + ] + } + }, + { + "version": "0.3.60", + "tag": "@rushstack/module-minifier-plugin_v0.3.60", + "date": "Fri, 11 Jun 2021 00:34:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.30`" + } + ] + } + }, + { + "version": "0.3.59", + "tag": "@rushstack/module-minifier-plugin_v0.3.59", + "date": "Thu, 10 Jun 2021 15:08:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.29`" + } + ] + } + }, + { + "version": "0.3.58", + "tag": "@rushstack/module-minifier-plugin_v0.3.58", + "date": "Fri, 04 Jun 2021 19:59:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.28`" + } + ] + } + }, + { + "version": "0.3.57", + "tag": "@rushstack/module-minifier-plugin_v0.3.57", + "date": "Fri, 04 Jun 2021 15:08:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.27`" + } + ] + } + }, + { + "version": "0.3.56", + "tag": "@rushstack/module-minifier-plugin_v0.3.56", + "date": "Fri, 04 Jun 2021 00:08:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.26`" + } + ] + } + }, + { + "version": "0.3.55", + "tag": "@rushstack/module-minifier-plugin_v0.3.55", + "date": "Tue, 01 Jun 2021 18:29:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.25`" + } + ] + } + }, + { + "version": "0.3.54", + "tag": "@rushstack/module-minifier-plugin_v0.3.54", + "date": "Sat, 29 May 2021 01:05:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.24`" + } + ] + } + }, + { + "version": "0.3.53", + "tag": "@rushstack/module-minifier-plugin_v0.3.53", + "date": "Fri, 28 May 2021 06:19:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.23`" + } + ] + } + }, + { + "version": "0.3.52", + "tag": "@rushstack/module-minifier-plugin_v0.3.52", + "date": "Tue, 25 May 2021 00:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.22`" + } + ] + } + }, + { + "version": "0.3.51", + "tag": "@rushstack/module-minifier-plugin_v0.3.51", + "date": "Wed, 19 May 2021 00:11:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.21`" + } + ] + } + }, + { + "version": "0.3.50", + "tag": "@rushstack/module-minifier-plugin_v0.3.50", + "date": "Thu, 13 May 2021 01:52:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.20`" + } + ] + } + }, + { + "version": "0.3.49", + "tag": "@rushstack/module-minifier-plugin_v0.3.49", + "date": "Tue, 11 May 2021 22:19:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.19`" + } + ] + } + }, + { + "version": "0.3.48", + "tag": "@rushstack/module-minifier-plugin_v0.3.48", + "date": "Mon, 03 May 2021 15:10:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.18`" + } + ] + } + }, + { + "version": "0.3.47", + "tag": "@rushstack/module-minifier-plugin_v0.3.47", + "date": "Thu, 29 Apr 2021 23:26:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.17`" + } + ] + } + }, + { + "version": "0.3.46", + "tag": "@rushstack/module-minifier-plugin_v0.3.46", + "date": "Thu, 29 Apr 2021 01:07:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.30.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.16`" + } + ] + } + }, + { + "version": "0.3.45", + "tag": "@rushstack/module-minifier-plugin_v0.3.45", + "date": "Fri, 23 Apr 2021 22:00:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.15`" + } + ] + } + }, + { + "version": "0.3.44", + "tag": "@rushstack/module-minifier-plugin_v0.3.44", + "date": "Fri, 23 Apr 2021 15:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.29.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.14`" + } + ] + } + }, + { + "version": "0.3.43", + "tag": "@rushstack/module-minifier-plugin_v0.3.43", + "date": "Wed, 21 Apr 2021 15:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.13`" + } + ] + } + }, + { + "version": "0.3.42", + "tag": "@rushstack/module-minifier-plugin_v0.3.42", + "date": "Tue, 20 Apr 2021 04:59:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.12`" + } + ] + } + }, + { + "version": "0.3.41", + "tag": "@rushstack/module-minifier-plugin_v0.3.41", + "date": "Thu, 15 Apr 2021 02:59:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.11`" + } + ] + } + }, + { + "version": "0.3.40", + "tag": "@rushstack/module-minifier-plugin_v0.3.40", + "date": "Mon, 12 Apr 2021 15:10:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.10`" + } + ] + } + }, + { + "version": "0.3.39", + "tag": "@rushstack/module-minifier-plugin_v0.3.39", + "date": "Thu, 08 Apr 2021 20:41:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.9`" + } + ] + } + }, + { + "version": "0.3.38", + "tag": "@rushstack/module-minifier-plugin_v0.3.38", + "date": "Thu, 08 Apr 2021 06:05:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.28.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.8`" + } + ] + } + }, + { + "version": "0.3.37", + "tag": "@rushstack/module-minifier-plugin_v0.3.37", + "date": "Thu, 08 Apr 2021 00:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.27.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.7`" + } + ] + } + }, + { + "version": "0.3.36", + "tag": "@rushstack/module-minifier-plugin_v0.3.36", + "date": "Tue, 06 Apr 2021 15:14:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.26.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.6`" + } + ] + } + }, + { + "version": "0.3.35", + "tag": "@rushstack/module-minifier-plugin_v0.3.35", + "date": "Wed, 31 Mar 2021 15:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.5`" + } + ] + } + }, + { + "version": "0.3.34", + "tag": "@rushstack/module-minifier-plugin_v0.3.34", + "date": "Mon, 29 Mar 2021 05:02:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.4`" + } + ] + } + }, + { + "version": "0.3.33", + "tag": "@rushstack/module-minifier-plugin_v0.3.33", + "date": "Fri, 19 Mar 2021 22:31:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.3`" + } + ] + } + }, + { + "version": "0.3.32", + "tag": "@rushstack/module-minifier-plugin_v0.3.32", + "date": "Wed, 17 Mar 2021 05:04:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.2`" + } + ] + } + }, + { + "version": "0.3.31", + "tag": "@rushstack/module-minifier-plugin_v0.3.31", + "date": "Fri, 12 Mar 2021 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.1`" + } + ] + } + }, + { + "version": "0.3.30", + "tag": "@rushstack/module-minifier-plugin_v0.3.30", + "date": "Wed, 10 Mar 2021 06:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.3.29", + "tag": "@rushstack/module-minifier-plugin_v0.3.29", + "date": "Wed, 10 Mar 2021 05:10:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.25.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.7`" + } + ] + } + }, + { + "version": "0.3.28", + "tag": "@rushstack/module-minifier-plugin_v0.3.28", + "date": "Thu, 04 Mar 2021 01:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.6`" + } + ] + } + }, + { + "version": "0.3.27", + "tag": "@rushstack/module-minifier-plugin_v0.3.27", + "date": "Tue, 02 Mar 2021 23:25:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.5`" + } + ] + } + }, + { + "version": "0.3.26", + "tag": "@rushstack/module-minifier-plugin_v0.3.26", + "date": "Fri, 05 Feb 2021 16:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.4`" + } + ] + } + }, + { + "version": "0.3.25", + "tag": "@rushstack/module-minifier-plugin_v0.3.25", + "date": "Fri, 22 Jan 2021 05:39:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.3`" + } + ] + } + }, + { + "version": "0.3.24", + "tag": "@rushstack/module-minifier-plugin_v0.3.24", + "date": "Thu, 21 Jan 2021 04:19:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.2`" + } + ] + } + }, + { + "version": "0.3.23", + "tag": "@rushstack/module-minifier-plugin_v0.3.23", + "date": "Wed, 13 Jan 2021 01:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.1`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/module-minifier-plugin_v0.3.22", + "date": "Fri, 08 Jan 2021 07:28:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.2.0`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/module-minifier-plugin_v0.3.21", + "date": "Wed, 06 Jan 2021 16:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.34`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/module-minifier-plugin_v0.3.20", + "date": "Mon, 14 Dec 2020 16:12:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.33`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/module-minifier-plugin_v0.3.19", + "date": "Thu, 10 Dec 2020 23:25:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.32`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/module-minifier-plugin_v0.3.18", + "date": "Sat, 05 Dec 2020 01:11:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.31`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/module-minifier-plugin_v0.3.17", + "date": "Tue, 01 Dec 2020 01:10:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.30`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/module-minifier-plugin_v0.3.16", + "date": "Mon, 30 Nov 2020 16:11:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.29`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/module-minifier-plugin_v0.3.15", + "date": "Wed, 18 Nov 2020 08:19:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.28`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/module-minifier-plugin_v0.3.14", + "date": "Wed, 18 Nov 2020 06:21:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.27`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/module-minifier-plugin_v0.3.13", + "date": "Tue, 17 Nov 2020 01:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.26`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/module-minifier-plugin_v0.3.12", + "date": "Mon, 16 Nov 2020 01:57:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.25`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/module-minifier-plugin_v0.3.11", + "date": "Fri, 13 Nov 2020 01:11:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.24`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/module-minifier-plugin_v0.3.10", + "date": "Thu, 12 Nov 2020 01:11:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.23`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/module-minifier-plugin_v0.3.9", + "date": "Wed, 11 Nov 2020 01:08:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.22`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/module-minifier-plugin_v0.3.8", + "date": "Tue, 10 Nov 2020 23:13:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.21`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/module-minifier-plugin_v0.3.7", + "date": "Tue, 10 Nov 2020 16:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.20`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/module-minifier-plugin_v0.3.6", + "date": "Sun, 08 Nov 2020 22:52:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.19`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/module-minifier-plugin_v0.3.5", + "date": "Fri, 06 Nov 2020 16:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.18`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/module-minifier-plugin_v0.3.4", + "date": "Tue, 03 Nov 2020 01:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.17`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/module-minifier-plugin_v0.3.3", + "date": "Mon, 02 Nov 2020 16:12:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.16`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/module-minifier-plugin_v0.3.2", + "date": "Fri, 30 Oct 2020 06:38:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.15`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/module-minifier-plugin_v0.3.1", + "date": "Fri, 30 Oct 2020 00:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.14`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/module-minifier-plugin_v0.3.0", + "date": "Thu, 29 Oct 2020 06:14:19 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade @types/tapable" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.13`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/module-minifier-plugin_v0.2.0", + "date": "Thu, 29 Oct 2020 00:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to ~4.44.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.12`" + } + ] + } + }, + { + "version": "0.1.58", + "tag": "@rushstack/module-minifier-plugin_v0.1.58", + "date": "Wed, 28 Oct 2020 01:18:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.11`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@rushstack/module-minifier-plugin_v0.1.57", + "date": "Tue, 27 Oct 2020 15:10:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.10`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@rushstack/module-minifier-plugin_v0.1.56", + "date": "Sat, 24 Oct 2020 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.9`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@rushstack/module-minifier-plugin_v0.1.55", + "date": "Wed, 21 Oct 2020 05:09:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.8`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@rushstack/module-minifier-plugin_v0.1.54", + "date": "Wed, 21 Oct 2020 02:28:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.7`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@rushstack/module-minifier-plugin_v0.1.53", + "date": "Fri, 16 Oct 2020 23:32:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@rushstack/module-minifier-plugin_v0.1.52", + "date": "Thu, 15 Oct 2020 00:59:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.6`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@rushstack/module-minifier-plugin_v0.1.51", + "date": "Wed, 14 Oct 2020 23:30:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@rushstack/module-minifier-plugin_v0.1.50", + "date": "Tue, 13 Oct 2020 15:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.8`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@rushstack/module-minifier-plugin_v0.1.49", + "date": "Mon, 12 Oct 2020 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.7`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@rushstack/module-minifier-plugin_v0.1.48", + "date": "Fri, 09 Oct 2020 15:11:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.6`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@rushstack/module-minifier-plugin_v0.1.47", + "date": "Tue, 06 Oct 2020 00:24:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.5`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@rushstack/module-minifier-plugin_v0.1.46", + "date": "Mon, 05 Oct 2020 22:36:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.4`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@rushstack/module-minifier-plugin_v0.1.45", + "date": "Mon, 05 Oct 2020 15:10:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.3`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@rushstack/module-minifier-plugin_v0.1.44", + "date": "Fri, 02 Oct 2020 00:10:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.2`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/module-minifier-plugin_v0.1.43", + "date": "Thu, 01 Oct 2020 20:27:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.2`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/module-minifier-plugin_v0.1.42", + "date": "Thu, 01 Oct 2020 18:51:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/module-minifier-plugin_v0.1.41", + "date": "Wed, 30 Sep 2020 18:39:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.1`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/module-minifier-plugin_v0.1.40", + "date": "Wed, 30 Sep 2020 06:53:53 GMT", + "comments": { + "patch": [ + { + "comment": "Update README.md" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `0.1.0`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/module-minifier-plugin_v0.1.39", + "date": "Tue, 22 Sep 2020 05:45:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.9`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/module-minifier-plugin_v0.1.38", + "date": "Tue, 22 Sep 2020 01:45:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.8`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/module-minifier-plugin_v0.1.37", + "date": "Tue, 22 Sep 2020 00:08:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.7`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/module-minifier-plugin_v0.1.36", + "date": "Sat, 19 Sep 2020 04:37:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.6`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/module-minifier-plugin_v0.1.35", + "date": "Sat, 19 Sep 2020 03:33:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.5`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/module-minifier-plugin_v0.1.34", + "date": "Fri, 18 Sep 2020 22:57:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.4`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/module-minifier-plugin_v0.1.33", + "date": "Fri, 18 Sep 2020 21:49:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.3`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/module-minifier-plugin_v0.1.32", + "date": "Wed, 16 Sep 2020 05:30:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.2`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/module-minifier-plugin_v0.1.31", + "date": "Tue, 15 Sep 2020 01:51:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.1`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/module-minifier-plugin_v0.1.30", + "date": "Mon, 14 Sep 2020 15:09:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/module-minifier-plugin_v0.1.29", + "date": "Sun, 13 Sep 2020 01:53:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/module-minifier-plugin_v0.1.28", + "date": "Fri, 11 Sep 2020 02:13:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/module-minifier-plugin_v0.1.27", + "date": "Wed, 09 Sep 2020 03:29:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.11.0`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/module-minifier-plugin_v0.1.26", + "date": "Wed, 09 Sep 2020 00:38:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.5`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/module-minifier-plugin_v0.1.25", + "date": "Mon, 07 Sep 2020 07:37:37 GMT", + "comments": { + "patch": [ + { + "comment": "Fix duplicate module emit" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.4`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/module-minifier-plugin_v0.1.24", + "date": "Sat, 05 Sep 2020 18:56:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/module-minifier-plugin_v0.1.23", + "date": "Fri, 04 Sep 2020 15:06:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/module-minifier-plugin_v0.1.22", + "date": "Thu, 03 Sep 2020 15:09:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/module-minifier-plugin_v0.1.21", + "date": "Wed, 02 Sep 2020 23:01:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.10.0`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/module-minifier-plugin_v0.1.20", + "date": "Wed, 02 Sep 2020 15:10:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.9.0`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/module-minifier-plugin_v0.1.19", + "date": "Thu, 27 Aug 2020 11:27:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.8.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/module-minifier-plugin_v0.1.18", + "date": "Tue, 25 Aug 2020 00:10:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/module-minifier-plugin_v0.1.17", + "date": "Mon, 24 Aug 2020 07:35:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.6`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/module-minifier-plugin_v0.1.16", + "date": "Sat, 22 Aug 2020 05:55:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.5`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/module-minifier-plugin_v0.1.15", + "date": "Fri, 21 Aug 2020 01:21:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.4`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/module-minifier-plugin_v0.1.14", + "date": "Thu, 20 Aug 2020 18:41:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.3`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/module-minifier-plugin_v0.1.13", + "date": "Thu, 20 Aug 2020 15:13:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.2`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/module-minifier-plugin_v0.1.12", + "date": "Tue, 18 Aug 2020 23:59:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.1`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/module-minifier-plugin_v0.1.11", + "date": "Tue, 18 Aug 2020 03:03:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/module-minifier-plugin_v0.1.10", + "date": "Mon, 17 Aug 2020 05:31:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.1`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/module-minifier-plugin_v0.1.9", + "date": "Mon, 17 Aug 2020 04:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/module-minifier-plugin_v0.1.8", + "date": "Fri, 14 Aug 2020 23:38:14 GMT", + "comments": { + "patch": [ + { + "comment": "Fix handling of missing leading ids" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/module-minifier-plugin_v0.1.7", + "date": "Thu, 13 Aug 2020 09:26:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.7`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/module-minifier-plugin_v0.1.6", + "date": "Thu, 13 Aug 2020 04:57:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.6`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/module-minifier-plugin_v0.1.5", + "date": "Wed, 12 Aug 2020 00:10:05 GMT", + "comments": { + "patch": [ + { + "comment": "Updated project to build with Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `1.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.4.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/module-minifier-plugin_v0.1.4", + "date": "Wed, 05 Aug 2020 18:27:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/rush-stack-compiler-3.5\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@microsoft/node-library-build\" to `6.4.33`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/module-minifier-plugin_v0.1.3", + "date": "Thu, 23 Jul 2020 23:47:59 GMT", + "comments": { + "patch": [ + { + "comment": "Make @types/webpack optional, fix Module" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/module-minifier-plugin_v0.1.2", + "date": "Fri, 17 Jul 2020 22:44:06 GMT", + "comments": { + "patch": [ + { + "comment": "Support external modules" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/module-minifier-plugin_v0.1.1", + "date": "Tue, 14 Jul 2020 21:49:38 GMT", + "comments": { + "patch": [ + { + "comment": "Fix external typings" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/module-minifier-plugin_v0.1.0", + "date": "Sat, 11 Jul 2020 00:08:09 GMT", + "comments": { + "minor": [ + { + "comment": "Define ModuleMinifierPlugin" + } + ] + } + } + ] +} diff --git a/webpack/webpack4-module-minifier-plugin/CHANGELOG.md b/webpack/webpack4-module-minifier-plugin/CHANGELOG.md new file mode 100644 index 00000000000..fde0b4652bb --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/CHANGELOG.md @@ -0,0 +1,2188 @@ +# Change Log - @rushstack/webpack4-module-minifier-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 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:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.13.113 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.13.112 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.13.111 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.13.110 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.13.109 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.13.108 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.13.107 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.13.106 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.13.105 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.13.104 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.13.103 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.13.102 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.13.101 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.13.100 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.13.99 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.13.98 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.13.97 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.13.96 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.13.95 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.13.94 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.13.93 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.13.92 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.13.91 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.13.90 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.13.89 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.13.88 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.13.87 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.13.86 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.13.85 +Thu, 30 Jan 2025 16:10:36 GMT + +### Patches + +- Prefer `os.availableParallelism()` to `os.cpus().length`. + +## 0.13.84 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.13.83 +Wed, 22 Jan 2025 03:03:48 GMT + +_Version update only_ + +## 0.13.82 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.13.81 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.13.80 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.13.79 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.13.78 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.13.77 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.13.76 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.13.75 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.13.74 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.13.73 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.13.72 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.13.71 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.13.70 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.13.69 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.13.68 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.13.67 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.13.66 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.13.65 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.13.64 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.13.63 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.13.62 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.13.61 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 0.13.60 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.13.59 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.13.58 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.13.57 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.13.56 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.13.55 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.13.54 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.13.53 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.13.52 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.13.51 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.13.50 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.13.49 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.13.48 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.13.47 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.13.46 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.13.45 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.13.44 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.13.43 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.13.42 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.13.41 +Thu, 28 Mar 2024 22:42:24 GMT + +_Version update only_ + +## 0.13.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.13.39 +Sat, 16 Mar 2024 00:11:37 GMT + +_Version update only_ + +## 0.13.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.13.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.13.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.13.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.13.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.13.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.13.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.13.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.13.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.13.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.13.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.13.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.13.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.13.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.13.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.13.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.13.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.13.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.13.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.13.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.13.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.13.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.13.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.13.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.13.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.13.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.13.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.13.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.13.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.13.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.13.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.13.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.13.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.13.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.13.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.13.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.13.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.13.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.13.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.12.35 +Thu, 07 Sep 2023 03:35:43 GMT + +### Patches + +- Update Webpack peerDependency to ~4.47.0. + +## 0.12.34 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.12.33 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.12.32 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.12.31 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.12.30 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Fix calculation of rendered module positions to properly reflect character codes, not raw bytes. + +## 0.12.29 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.12.28 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.12.27 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.12.26 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.12.25 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.12.24 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.12.23 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.12.22 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.12.21 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.12.20 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.12.19 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.12.18 +Tue, 13 Jun 2023 01:49:02 GMT + +_Version update only_ + +## 0.12.17 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.12.16 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.12.15 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.12.14 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.12.13 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.12.12 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.12.11 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.12.10 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.12.9 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.12.8 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.12.7 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.12.6 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.12.5 +Thu, 04 May 2023 15:17:38 GMT + +_Version update only_ + +## 0.12.4 +Thu, 04 May 2023 00:20:28 GMT + +### Patches + +- Fix async import compressor erroring when encountering unresolved dependencies. + +## 0.12.3 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 0.12.2 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.12.1 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.12.0 +Wed, 26 Apr 2023 00:22:30 GMT + +### Minor changes + +- Emit metadata about character position of rendered modules. + +## 0.11.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.11.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.11.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.11.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.11.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.10.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.9.48 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.9.47 +Sat, 28 Jan 2023 01:22:02 GMT + +_Version update only_ + +## 0.9.46 +Thu, 26 Jan 2023 02:55:10 GMT + +_Version update only_ + +## 0.9.45 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.9.44 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.9.43 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.9.42 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.9.41 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.9.40 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.9.39 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.9.38 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.9.37 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.9.36 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.9.35 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.9.34 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.9.33 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.9.32 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.9.31 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.9.30 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.9.29 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.9.28 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.9.27 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.9.26 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.9.25 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.9.24 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.9.23 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.9.22 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.9.21 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.9.20 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.9.19 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.9.18 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.9.17 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.9.16 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.9.15 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.9.14 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.9.13 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.9.12 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.9.11 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.9.10 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 0.9.9 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.9.8 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.9.7 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.9.6 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.9.5 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.9.4 +Thu, 23 Jun 2022 22:14:24 GMT + +### Patches + +- Rename from @rushstack/module-minifier-plugin. + +## 0.9.3 +Tue, 21 Jun 2022 20:27:19 GMT + +### Patches + +- Upgrade @types/webpack and add missing optional peer dependency. + +## 0.9.2 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 0.9.1 +Wed, 25 May 2022 22:25:07 GMT + +_Version update only_ + +## 0.9.0 +Fri, 20 May 2022 00:11:55 GMT + +### Minor changes + +- Factor out minifiers into @rushstack/module-minifier. + +## 0.8.17 +Thu, 19 May 2022 15:13:20 GMT + +_Version update only_ + +## 0.8.16 +Sat, 14 May 2022 03:01:27 GMT + +_Version update only_ + +## 0.8.15 +Tue, 10 May 2022 01:20:43 GMT + +_Version update only_ + +## 0.8.14 +Wed, 04 May 2022 23:29:13 GMT + +_Version update only_ + +## 0.8.13 +Tue, 26 Apr 2022 00:10:15 GMT + +_Version update only_ + +## 0.8.12 +Sat, 23 Apr 2022 02:13:07 GMT + +_Version update only_ + +## 0.8.11 +Fri, 15 Apr 2022 00:12:36 GMT + +_Version update only_ + +## 0.8.10 +Wed, 13 Apr 2022 15:12:41 GMT + +_Version update only_ + +## 0.8.9 +Tue, 12 Apr 2022 23:29:34 GMT + +_Version update only_ + +## 0.8.8 +Tue, 12 Apr 2022 02:58:32 GMT + +_Version update only_ + +## 0.8.7 +Sat, 09 Apr 2022 19:07:48 GMT + +_Version update only_ + +## 0.8.6 +Sat, 09 Apr 2022 02:24:26 GMT + +### Patches + +- Rename the "master" branch to "main". + +## 0.8.5 +Fri, 08 Apr 2022 20:05:59 GMT + +_Version update only_ + +## 0.8.4 +Wed, 06 Apr 2022 22:35:23 GMT + +_Version update only_ + +## 0.8.3 +Thu, 31 Mar 2022 02:06:05 GMT + +_Version update only_ + +## 0.8.2 +Sat, 19 Mar 2022 08:05:38 GMT + +_Version update only_ + +## 0.8.1 +Tue, 15 Mar 2022 19:15:54 GMT + +_Version update only_ + +## 0.8.0 +Thu, 17 Feb 2022 00:32:30 GMT + +### Minor changes + +- Include plugin state in webpack hash calculations, such that updating the plugin options changes the compilation and chunk hashes. + +## 0.7.1 +Fri, 11 Feb 2022 10:30:25 GMT + +_Version update only_ + +## 0.7.0 +Fri, 11 Feb 2022 01:12:20 GMT + +### Minor changes + +- Add support for `compressAsyncImports` flag. Modify `usePortableModules` option to use `module.identifier()` instead of `module.resource` so that loader configuration is accounted for during deduplication. Switch to overriding the render function on the JavaScript module template to deduplicate rendering across chunks. + +## 0.6.14 +Tue, 25 Jan 2022 01:11:07 GMT + +_Version update only_ + +## 0.6.13 +Fri, 21 Jan 2022 01:10:41 GMT + +_Version update only_ + +## 0.6.12 +Thu, 20 Jan 2022 02:43:46 GMT + +_Version update only_ + +## 0.6.11 +Wed, 05 Jan 2022 16:07:47 GMT + +_Version update only_ + +## 0.6.10 +Mon, 27 Dec 2021 16:10:40 GMT + +_Version update only_ + +## 0.6.9 +Tue, 14 Dec 2021 19:27:51 GMT + +_Version update only_ + +## 0.6.8 +Thu, 09 Dec 2021 20:34:41 GMT + +_Version update only_ + +## 0.6.7 +Thu, 09 Dec 2021 00:21:54 GMT + +_Version update only_ + +## 0.6.6 +Wed, 08 Dec 2021 19:05:08 GMT + +_Version update only_ + +## 0.6.5 +Wed, 08 Dec 2021 16:14:05 GMT + +_Version update only_ + +## 0.6.4 +Mon, 06 Dec 2021 16:08:33 GMT + +_Version update only_ + +## 0.6.3 +Fri, 03 Dec 2021 03:05:22 GMT + +_Version update only_ + +## 0.6.2 +Tue, 30 Nov 2021 20:18:41 GMT + +_Version update only_ + +## 0.6.1 +Mon, 29 Nov 2021 07:26:16 GMT + +_Version update only_ + +## 0.6.0 +Wed, 24 Nov 2021 01:10:33 GMT + +### Minor changes + +- Export a getIdentifier function for generating safe JavaScript identifiers. + +## 0.5.0 +Thu, 18 Nov 2021 01:10:06 GMT + +### Minor changes + +- Upgrade to terser 5.10.2, fix source maps in NoopMinifier + +## 0.4.36 +Sat, 13 Nov 2021 01:09:28 GMT + +### Patches + +- Fix a minor mistake in the README. + +## 0.4.35 +Sat, 06 Nov 2021 00:09:13 GMT + +_Version update only_ + +## 0.4.34 +Fri, 05 Nov 2021 15:09:18 GMT + +_Version update only_ + +## 0.4.33 +Thu, 28 Oct 2021 00:08:22 GMT + +_Version update only_ + +## 0.4.32 +Wed, 27 Oct 2021 00:08:15 GMT + +### Patches + +- Update the package.json repository field to include the directory property. + +## 0.4.31 +Wed, 13 Oct 2021 15:09:55 GMT + +_Version update only_ + +## 0.4.30 +Fri, 08 Oct 2021 09:35:07 GMT + +_Version update only_ + +## 0.4.29 +Fri, 08 Oct 2021 08:08:34 GMT + +_Version update only_ + +## 0.4.28 +Thu, 07 Oct 2021 23:43:12 GMT + +_Version update only_ + +## 0.4.27 +Thu, 07 Oct 2021 07:13:35 GMT + +_Version update only_ + +## 0.4.26 +Wed, 06 Oct 2021 15:08:26 GMT + +_Version update only_ + +## 0.4.25 +Wed, 06 Oct 2021 02:41:48 GMT + +_Version update only_ + +## 0.4.24 +Tue, 05 Oct 2021 15:08:38 GMT + +_Version update only_ + +## 0.4.23 +Mon, 04 Oct 2021 15:10:18 GMT + +_Version update only_ + +## 0.4.22 +Fri, 24 Sep 2021 00:09:29 GMT + +_Version update only_ + +## 0.4.21 +Thu, 23 Sep 2021 00:10:41 GMT + +### Patches + +- Upgrade the `@types/node` dependency to version to version 12. + +## 0.4.20 +Wed, 22 Sep 2021 03:27:12 GMT + +_Version update only_ + +## 0.4.19 +Wed, 22 Sep 2021 00:09:32 GMT + +_Version update only_ + +## 0.4.18 +Sat, 18 Sep 2021 03:05:57 GMT + +_Version update only_ + +## 0.4.17 +Tue, 14 Sep 2021 01:17:04 GMT + +_Version update only_ + +## 0.4.16 +Mon, 13 Sep 2021 15:07:05 GMT + +_Version update only_ + +## 0.4.15 +Fri, 10 Sep 2021 15:08:28 GMT + +_Version update only_ + +## 0.4.14 +Wed, 08 Sep 2021 19:06:22 GMT + +_Version update only_ + +## 0.4.13 +Wed, 08 Sep 2021 00:08:03 GMT + +_Version update only_ + +## 0.4.12 +Fri, 03 Sep 2021 00:09:10 GMT + +_Version update only_ + +## 0.4.11 +Tue, 31 Aug 2021 00:07:11 GMT + +_Version update only_ + +## 0.4.10 +Fri, 27 Aug 2021 00:07:25 GMT + +_Version update only_ + +## 0.4.9 +Fri, 20 Aug 2021 15:08:10 GMT + +_Version update only_ + +## 0.4.8 +Wed, 18 Aug 2021 00:06:54 GMT + +### Patches + +- Fix compatibility issue with mini-css-extract-plugin and other plugins that introduce non-JavaScript modules and asset types. + +## 0.4.7 +Fri, 13 Aug 2021 00:09:14 GMT + +_Version update only_ + +## 0.4.6 +Thu, 12 Aug 2021 18:11:18 GMT + +_Version update only_ + +## 0.4.5 +Thu, 12 Aug 2021 01:28:38 GMT + +_Version update only_ + +## 0.4.4 +Wed, 11 Aug 2021 23:14:17 GMT + +_Version update only_ + +## 0.4.3 +Wed, 11 Aug 2021 00:07:21 GMT + +_Version update only_ + +## 0.4.2 +Sat, 31 Jul 2021 00:52:11 GMT + +_Version update only_ + +## 0.4.1 +Thu, 22 Jul 2021 22:31:41 GMT + +### Patches + +- Fix comment file generation logic. Fix WorkerPoolMinifier hanging the process. + +## 0.4.0 +Thu, 22 Jul 2021 15:07:19 GMT + +### Minor changes + +- Separate comment extraction from minification. + +## 0.3.75 +Wed, 14 Jul 2021 15:06:29 GMT + +_Version update only_ + +## 0.3.74 +Tue, 13 Jul 2021 23:00:33 GMT + +_Version update only_ + +## 0.3.73 +Mon, 12 Jul 2021 23:08:26 GMT + +_Version update only_ + +## 0.3.72 +Thu, 08 Jul 2021 23:41:17 GMT + +_Version update only_ + +## 0.3.71 +Thu, 08 Jul 2021 06:00:48 GMT + +_Version update only_ + +## 0.3.70 +Thu, 01 Jul 2021 15:08:27 GMT + +_Version update only_ + +## 0.3.69 +Wed, 30 Jun 2021 19:16:19 GMT + +_Version update only_ + +## 0.3.68 +Wed, 30 Jun 2021 15:06:54 GMT + +_Version update only_ + +## 0.3.67 +Wed, 30 Jun 2021 01:37:17 GMT + +_Version update only_ + +## 0.3.66 +Fri, 25 Jun 2021 00:08:28 GMT + +_Version update only_ + +## 0.3.65 +Fri, 18 Jun 2021 06:23:05 GMT + +_Version update only_ + +## 0.3.64 +Wed, 16 Jun 2021 18:53:52 GMT + +_Version update only_ + +## 0.3.63 +Wed, 16 Jun 2021 15:07:24 GMT + +_Version update only_ + +## 0.3.62 +Tue, 15 Jun 2021 20:38:35 GMT + +_Version update only_ + +## 0.3.61 +Fri, 11 Jun 2021 23:26:16 GMT + +_Version update only_ + +## 0.3.60 +Fri, 11 Jun 2021 00:34:02 GMT + +_Version update only_ + +## 0.3.59 +Thu, 10 Jun 2021 15:08:16 GMT + +_Version update only_ + +## 0.3.58 +Fri, 04 Jun 2021 19:59:53 GMT + +_Version update only_ + +## 0.3.57 +Fri, 04 Jun 2021 15:08:20 GMT + +_Version update only_ + +## 0.3.56 +Fri, 04 Jun 2021 00:08:34 GMT + +_Version update only_ + +## 0.3.55 +Tue, 01 Jun 2021 18:29:26 GMT + +_Version update only_ + +## 0.3.54 +Sat, 29 May 2021 01:05:06 GMT + +_Version update only_ + +## 0.3.53 +Fri, 28 May 2021 06:19:58 GMT + +_Version update only_ + +## 0.3.52 +Tue, 25 May 2021 00:12:21 GMT + +_Version update only_ + +## 0.3.51 +Wed, 19 May 2021 00:11:39 GMT + +_Version update only_ + +## 0.3.50 +Thu, 13 May 2021 01:52:47 GMT + +_Version update only_ + +## 0.3.49 +Tue, 11 May 2021 22:19:17 GMT + +_Version update only_ + +## 0.3.48 +Mon, 03 May 2021 15:10:28 GMT + +_Version update only_ + +## 0.3.47 +Thu, 29 Apr 2021 23:26:50 GMT + +_Version update only_ + +## 0.3.46 +Thu, 29 Apr 2021 01:07:29 GMT + +_Version update only_ + +## 0.3.45 +Fri, 23 Apr 2021 22:00:07 GMT + +_Version update only_ + +## 0.3.44 +Fri, 23 Apr 2021 15:11:21 GMT + +_Version update only_ + +## 0.3.43 +Wed, 21 Apr 2021 15:12:28 GMT + +_Version update only_ + +## 0.3.42 +Tue, 20 Apr 2021 04:59:51 GMT + +_Version update only_ + +## 0.3.41 +Thu, 15 Apr 2021 02:59:25 GMT + +_Version update only_ + +## 0.3.40 +Mon, 12 Apr 2021 15:10:29 GMT + +_Version update only_ + +## 0.3.39 +Thu, 08 Apr 2021 20:41:54 GMT + +_Version update only_ + +## 0.3.38 +Thu, 08 Apr 2021 06:05:32 GMT + +_Version update only_ + +## 0.3.37 +Thu, 08 Apr 2021 00:10:18 GMT + +_Version update only_ + +## 0.3.36 +Tue, 06 Apr 2021 15:14:22 GMT + +_Version update only_ + +## 0.3.35 +Wed, 31 Mar 2021 15:10:36 GMT + +_Version update only_ + +## 0.3.34 +Mon, 29 Mar 2021 05:02:07 GMT + +_Version update only_ + +## 0.3.33 +Fri, 19 Mar 2021 22:31:38 GMT + +_Version update only_ + +## 0.3.32 +Wed, 17 Mar 2021 05:04:38 GMT + +_Version update only_ + +## 0.3.31 +Fri, 12 Mar 2021 01:13:27 GMT + +_Version update only_ + +## 0.3.30 +Wed, 10 Mar 2021 06:23:29 GMT + +_Version update only_ + +## 0.3.29 +Wed, 10 Mar 2021 05:10:06 GMT + +_Version update only_ + +## 0.3.28 +Thu, 04 Mar 2021 01:11:31 GMT + +_Version update only_ + +## 0.3.27 +Tue, 02 Mar 2021 23:25:05 GMT + +_Version update only_ + +## 0.3.26 +Fri, 05 Feb 2021 16:10:42 GMT + +_Version update only_ + +## 0.3.25 +Fri, 22 Jan 2021 05:39:22 GMT + +_Version update only_ + +## 0.3.24 +Thu, 21 Jan 2021 04:19:00 GMT + +_Version update only_ + +## 0.3.23 +Wed, 13 Jan 2021 01:11:06 GMT + +_Version update only_ + +## 0.3.22 +Fri, 08 Jan 2021 07:28:50 GMT + +_Version update only_ + +## 0.3.21 +Wed, 06 Jan 2021 16:10:43 GMT + +_Version update only_ + +## 0.3.20 +Mon, 14 Dec 2020 16:12:21 GMT + +_Version update only_ + +## 0.3.19 +Thu, 10 Dec 2020 23:25:50 GMT + +_Version update only_ + +## 0.3.18 +Sat, 05 Dec 2020 01:11:23 GMT + +_Version update only_ + +## 0.3.17 +Tue, 01 Dec 2020 01:10:38 GMT + +_Version update only_ + +## 0.3.16 +Mon, 30 Nov 2020 16:11:50 GMT + +_Version update only_ + +## 0.3.15 +Wed, 18 Nov 2020 08:19:54 GMT + +_Version update only_ + +## 0.3.14 +Wed, 18 Nov 2020 06:21:58 GMT + +_Version update only_ + +## 0.3.13 +Tue, 17 Nov 2020 01:17:38 GMT + +_Version update only_ + +## 0.3.12 +Mon, 16 Nov 2020 01:57:58 GMT + +_Version update only_ + +## 0.3.11 +Fri, 13 Nov 2020 01:11:01 GMT + +_Version update only_ + +## 0.3.10 +Thu, 12 Nov 2020 01:11:10 GMT + +_Version update only_ + +## 0.3.9 +Wed, 11 Nov 2020 01:08:58 GMT + +_Version update only_ + +## 0.3.8 +Tue, 10 Nov 2020 23:13:12 GMT + +_Version update only_ + +## 0.3.7 +Tue, 10 Nov 2020 16:11:42 GMT + +_Version update only_ + +## 0.3.6 +Sun, 08 Nov 2020 22:52:49 GMT + +_Version update only_ + +## 0.3.5 +Fri, 06 Nov 2020 16:09:30 GMT + +_Version update only_ + +## 0.3.4 +Tue, 03 Nov 2020 01:11:19 GMT + +_Version update only_ + +## 0.3.3 +Mon, 02 Nov 2020 16:12:05 GMT + +_Version update only_ + +## 0.3.2 +Fri, 30 Oct 2020 06:38:39 GMT + +_Version update only_ + +## 0.3.1 +Fri, 30 Oct 2020 00:10:14 GMT + +_Version update only_ + +## 0.3.0 +Thu, 29 Oct 2020 06:14:19 GMT + +### Minor changes + +- Upgrade @types/tapable + +## 0.2.0 +Thu, 29 Oct 2020 00:11:33 GMT + +### Minor changes + +- Update Webpack dependency to ~4.44.2 + +## 0.1.58 +Wed, 28 Oct 2020 01:18:03 GMT + +_Version update only_ + +## 0.1.57 +Tue, 27 Oct 2020 15:10:14 GMT + +_Version update only_ + +## 0.1.56 +Sat, 24 Oct 2020 00:11:19 GMT + +_Version update only_ + +## 0.1.55 +Wed, 21 Oct 2020 05:09:44 GMT + +_Version update only_ + +## 0.1.54 +Wed, 21 Oct 2020 02:28:17 GMT + +_Version update only_ + +## 0.1.53 +Fri, 16 Oct 2020 23:32:58 GMT + +_Version update only_ + +## 0.1.52 +Thu, 15 Oct 2020 00:59:08 GMT + +_Version update only_ + +## 0.1.51 +Wed, 14 Oct 2020 23:30:14 GMT + +_Version update only_ + +## 0.1.50 +Tue, 13 Oct 2020 15:11:28 GMT + +_Version update only_ + +## 0.1.49 +Mon, 12 Oct 2020 15:11:16 GMT + +_Version update only_ + +## 0.1.48 +Fri, 09 Oct 2020 15:11:09 GMT + +_Version update only_ + +## 0.1.47 +Tue, 06 Oct 2020 00:24:06 GMT + +_Version update only_ + +## 0.1.46 +Mon, 05 Oct 2020 22:36:57 GMT + +_Version update only_ + +## 0.1.45 +Mon, 05 Oct 2020 15:10:42 GMT + +_Version update only_ + +## 0.1.44 +Fri, 02 Oct 2020 00:10:59 GMT + +_Version update only_ + +## 0.1.43 +Thu, 01 Oct 2020 20:27:16 GMT + +_Version update only_ + +## 0.1.42 +Thu, 01 Oct 2020 18:51:21 GMT + +_Version update only_ + +## 0.1.41 +Wed, 30 Sep 2020 18:39:17 GMT + +_Version update only_ + +## 0.1.40 +Wed, 30 Sep 2020 06:53:53 GMT + +### Patches + +- Update README.md + +## 0.1.39 +Tue, 22 Sep 2020 05:45:57 GMT + +_Version update only_ + +## 0.1.38 +Tue, 22 Sep 2020 01:45:31 GMT + +_Version update only_ + +## 0.1.37 +Tue, 22 Sep 2020 00:08:53 GMT + +_Version update only_ + +## 0.1.36 +Sat, 19 Sep 2020 04:37:27 GMT + +_Version update only_ + +## 0.1.35 +Sat, 19 Sep 2020 03:33:07 GMT + +_Version update only_ + +## 0.1.34 +Fri, 18 Sep 2020 22:57:24 GMT + +_Version update only_ + +## 0.1.33 +Fri, 18 Sep 2020 21:49:53 GMT + +_Version update only_ + +## 0.1.32 +Wed, 16 Sep 2020 05:30:26 GMT + +_Version update only_ + +## 0.1.31 +Tue, 15 Sep 2020 01:51:37 GMT + +_Version update only_ + +## 0.1.30 +Mon, 14 Sep 2020 15:09:48 GMT + +_Version update only_ + +## 0.1.29 +Sun, 13 Sep 2020 01:53:20 GMT + +_Version update only_ + +## 0.1.28 +Fri, 11 Sep 2020 02:13:35 GMT + +_Version update only_ + +## 0.1.27 +Wed, 09 Sep 2020 03:29:01 GMT + +_Version update only_ + +## 0.1.26 +Wed, 09 Sep 2020 00:38:48 GMT + +_Version update only_ + +## 0.1.25 +Mon, 07 Sep 2020 07:37:37 GMT + +### Patches + +- Fix duplicate module emit + +## 0.1.24 +Sat, 05 Sep 2020 18:56:35 GMT + +_Version update only_ + +## 0.1.23 +Fri, 04 Sep 2020 15:06:28 GMT + +_Version update only_ + +## 0.1.22 +Thu, 03 Sep 2020 15:09:59 GMT + +_Version update only_ + +## 0.1.21 +Wed, 02 Sep 2020 23:01:13 GMT + +_Version update only_ + +## 0.1.20 +Wed, 02 Sep 2020 15:10:17 GMT + +_Version update only_ + +## 0.1.19 +Thu, 27 Aug 2020 11:27:06 GMT + +_Version update only_ + +## 0.1.18 +Tue, 25 Aug 2020 00:10:12 GMT + +_Version update only_ + +## 0.1.17 +Mon, 24 Aug 2020 07:35:21 GMT + +_Version update only_ + +## 0.1.16 +Sat, 22 Aug 2020 05:55:42 GMT + +_Version update only_ + +## 0.1.15 +Fri, 21 Aug 2020 01:21:18 GMT + +_Version update only_ + +## 0.1.14 +Thu, 20 Aug 2020 18:41:47 GMT + +_Version update only_ + +## 0.1.13 +Thu, 20 Aug 2020 15:13:53 GMT + +_Version update only_ + +## 0.1.12 +Tue, 18 Aug 2020 23:59:42 GMT + +_Version update only_ + +## 0.1.11 +Tue, 18 Aug 2020 03:03:24 GMT + +_Version update only_ + +## 0.1.10 +Mon, 17 Aug 2020 05:31:53 GMT + +_Version update only_ + +## 0.1.9 +Mon, 17 Aug 2020 04:53:23 GMT + +_Version update only_ + +## 0.1.8 +Fri, 14 Aug 2020 23:38:14 GMT + +### Patches + +- Fix handling of missing leading ids + +## 0.1.7 +Thu, 13 Aug 2020 09:26:40 GMT + +_Version update only_ + +## 0.1.6 +Thu, 13 Aug 2020 04:57:38 GMT + +_Version update only_ + +## 0.1.5 +Wed, 12 Aug 2020 00:10:05 GMT + +### Patches + +- Updated project to build with Heft + +## 0.1.4 +Wed, 05 Aug 2020 18:27:32 GMT + +_Version update only_ + +## 0.1.3 +Thu, 23 Jul 2020 23:47:59 GMT + +### Patches + +- Make @types/webpack optional, fix Module + +## 0.1.2 +Fri, 17 Jul 2020 22:44:06 GMT + +### Patches + +- Support external modules + +## 0.1.1 +Tue, 14 Jul 2020 21:49:38 GMT + +### Patches + +- Fix external typings + +## 0.1.0 +Sat, 11 Jul 2020 00:08:09 GMT + +### Minor changes + +- Define ModuleMinifierPlugin + diff --git a/webpack/webpack4-module-minifier-plugin/LICENSE b/webpack/webpack4-module-minifier-plugin/LICENSE new file mode 100644 index 00000000000..bfecd5f0ce5 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack4-module-minifier-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/webpack/webpack4-module-minifier-plugin/README.md b/webpack/webpack4-module-minifier-plugin/README.md new file mode 100644 index 00000000000..2540f52cf91 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/README.md @@ -0,0 +1,61 @@ +# @rushstack/webpack4-module-minifier-plugin + +## Installation + +`npm install @rushstack/webpack4-module-minifier-plugin --save-dev` + +## Overview + +This Webpack plugin performs minification of production assets on a per-module basis, rather than minifying an entire chunk at a time. +It issues async calls to the minifier for each unique module and each unique set of chunk boilerplate (i.e. the webpack runtime and the structure of the module list). +This improves minification time by: +- Avoiding duplicate work for each module that is included in multiple distinct assets/chunks (this is common with async chunks) +- Handing smaller code chunks to the minifier at a time (AST analysis is superlinear in size of the AST) +- Even single asset builds will likely still contain multiple modules in the final output, which can be split across available CPU cores + +## Use with `[hash]` and `[contenthash]` tokens +The plugin will do its best to update webpack hashes if changing the direct inputs (`useSourceMap`, `compressAsyncImports` or `usePortableModules`) to the plugin, but if altering the `minifier` property itself, you may need to use the `output.hashSalt` property to force a change to the hashes, especially if leverging the `MessagePortMinifier` or similar, since it has no direct access to the configuration of the minifier. + +## Parallel execution +If running on node 10, you will need to ensure that the `--experimental-workers` flag is enabled. + +```js +const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); + +// In your webpack options: +optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier(), + // If not provided, the plugin will attempt to guess from `mode` and `devtool`. + // Providing it expressly gives better results + useSourceMap: true + }) + ] +} +``` + +## Single-threaded execution +You can also run the ModuleMinifierPlugin in a single-threaded configuration. + +```js +// webpack.config.js +const { ModuleMinifierPlugin, LocalMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); + +// In your webpack options: +optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new LocalMinifier() + }) + ] +} +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/module-minifier-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack4-module-minifier-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/webpack4-module-minifier-plugin/config/api-extractor.json b/webpack/webpack4-module-minifier-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack4-module-minifier-plugin/config/jest.config.json b/webpack/webpack4-module-minifier-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/webpack4-module-minifier-plugin/config/rig.json b/webpack/webpack4-module-minifier-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack4-module-minifier-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/webpack/webpack4-module-minifier-plugin/eslint.config.js b/webpack/webpack4-module-minifier-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack4-module-minifier-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/webpack/webpack4-module-minifier-plugin/package.json b/webpack/webpack4-module-minifier-plugin/package.json new file mode 100644 index 00000000000..ddb0fe4e50d --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/package.json @@ -0,0 +1,58 @@ +{ + "name": "@rushstack/webpack4-module-minifier-plugin", + "version": "0.14.7", + "description": "This plugin splits minification of webpack compilations into smaller units.", + "main": "lib/index.js", + "typings": "dist/webpack4-module-minifier-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack4-module-minifier-plugin" + }, + "engines": { + "node": ">=10.17.1" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@types/webpack": "*", + "@types/webpack-sources": "*", + "webpack": "^4.31.0", + "webpack-sources": "~1.4.3", + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "@types/webpack-sources": { + "optional": true + }, + "@types/node": { + "optional": true + } + }, + "dependencies": { + "@rushstack/module-minifier": "workspace:*", + "@rushstack/worker-pool": "workspace:*", + "@types/tapable": "1.0.6", + "tapable": "1.1.3" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "@types/webpack-sources": "1.4.2", + "@types/webpack": "4.41.32", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack-sources": "~1.4.3", + "webpack": "~4.47.0" + }, + "sideEffects": [ + "./lib/OverrideWebpackIdentifierAllocation" + ] +} diff --git a/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts new file mode 100644 index 00000000000..6bae5be94cc --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/AsyncImportCompressionPlugin.ts @@ -0,0 +1,312 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import webpack, { type Compiler, type Plugin } from 'webpack'; +import type { ReplaceSource } from 'webpack-sources'; +import type { Tapable, TapOptions } from 'tapable'; + +const { Template } = webpack; + +import { STAGE_AFTER } from './Constants'; +import type { + IExtendedModule, + IModuleMinifierPluginHooks, + IPostProcessFragmentContext +} from './ModuleMinifierPlugin.types'; + +const PLUGIN_NAME: 'AsyncImportCompressionPlugin' = 'AsyncImportCompressionPlugin'; + +const TAP_AFTER: TapOptions<'sync'> = { + name: PLUGIN_NAME, + stage: STAGE_AFTER +}; + +const ASYNC_IMPORT_PREFIX: '__IMPORT_ASYNC' = '__IMPORT_ASYNC'; +const ASYNC_IMPORT_REGEX: RegExp = /__IMPORT_ASYNC[^\)]+/g; + +declare class WebpackImportDependency extends webpack.compilation.Dependency { + public module: webpack.compilation.Module; + public block: { + chunkGroup: webpack.compilation.ChunkGroup; + range: [number, number]; + }; +} + +interface IImportDependencyTemplate { + apply( + dependency: WebpackImportDependency, + source: ReplaceSource, + runtime: webpack.compilation.RuntimeTemplate + ): void; +} + +interface IAsyncImportMetadata { + chunkCount: number; + chunkIds: number[]; + count: number; + index: number; +} + +interface ILocalImportMetadata { + meta: IAsyncImportMetadata; + module: webpack.compilation.Module; +} + +function getImportDependency(compilation: webpack.compilation.Compilation): typeof WebpackImportDependency { + for (const key of compilation.dependencyTemplates.keys()) { + if (key.name === 'ImportDependency') { + return key as unknown as typeof WebpackImportDependency; + } + } + + throw new Error(`Could not find ImportDependency!`); +} + +function getImportTypeExpression( + module: webpack.compilation.Module, + originModule: webpack.compilation.Module +): string { + const exportsType: string | undefined = module.buildMeta?.exportsType; + const strict: boolean | undefined = originModule.buildMeta?.strictHarmonyModule; + + // Logic translated from: + // https://github.com/webpack/webpack/blob/3956274f1eada621e105208dcab4608883cdfdb2/lib/RuntimeTemplate.js#L110-L122 + if (exportsType === 'namespace') { + // Use the raw module directly + return ''; + } else if (exportsType === 'named') { + // Create a new namespace object and forward all exports + return ',3'; + } else if (strict) { + // Synthetic default export + return ',1'; + } else { + // If modules is marked __esModule, return raw module, otherwise create a new namespace object and forward all exports + return ',7'; + } +} + +function needChunkOnDemandLoadingCode(chunk: webpack.compilation.Chunk): boolean { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.getNumberOfChildren() > 0) { + return true; + } + } + return false; +} + +/** + * Plugin that replaces `Promise.all([__webpack_require__.e(1), __webpack_require__.e(12)]).then(__webpack_require__.t.bind(123,7))` + * with more concise expressions like `__webpack_require__.ee([1,12],123,7)`, etc. + * + * Also ensures that the code seen by the minifier does not contain chunk ids, and is therefore portable across chunks/compilations. + */ +export class AsyncImportCompressionPlugin implements Plugin { + private readonly _minifierHooks: IModuleMinifierPluginHooks; + + public constructor(minifierHooks: IModuleMinifierPluginHooks) { + this._minifierHooks = minifierHooks; + } + + public apply(compiler: Compiler): void { + const asyncImportMap: Map> = new Map(); + const asyncImportGroups: Map = new Map(); + let rankedImportGroups: IAsyncImportMetadata[] | undefined; + + this._minifierHooks.postProcessCodeFragment.tap( + { + name: PLUGIN_NAME, + stage: -1 + }, + (source: ReplaceSource, context: IPostProcessFragmentContext) => { + const code: string = source.original().source() as string; + + let localImports: Map | undefined; + + ASYNC_IMPORT_REGEX.lastIndex = -1; + // RegExp.exec uses null or an array as the return type, explicitly + let match: RegExpExecArray | null = null; + while ((match = ASYNC_IMPORT_REGEX.exec(code))) { + const token: string = match[0]; + + if (!localImports) { + if (!context.module) { + context.compilation.errors.push( + new Error(`Unexpected async import ${token} in non-module context ${context.loggingName}`) + ); + return source; + } + + localImports = asyncImportMap.get(context.module); + if (!localImports) { + context.compilation.errors.push( + new Error(`Unexpected async import ${token} in module ${context.loggingName}`) + ); + return source; + } + } + + const localImport: ILocalImportMetadata | undefined = localImports.get(token); + if (!localImport) { + context.compilation.errors.push( + new Error(`Missing metadata for ${token} in module ${context.loggingName}`) + ); + return source; + } + const { meta, module } = localImport; + + const chunkExpression: string = meta.index < 0 ? JSON.stringify(meta.chunkIds) : `${meta.index}`; + + const mapped: string | number | undefined = this._minifierHooks.finalModuleId.call( + module.id!, + context.compilation + ); + const idExpr: string | number = mapped === undefined ? module.id! : mapped; + + // Replace with a reference or array of ideas, the target module id, and the type of import + source.replace( + match.index, + ASYNC_IMPORT_REGEX.lastIndex - 1, + `${chunkExpression},${JSON.stringify(idExpr)}${getImportTypeExpression(module, context.module!)}` + ); + } + + return source; + } + ); + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: webpack.compilation.Compilation) => { + asyncImportMap.clear(); + asyncImportGroups.clear(); + + compilation.hooks.beforeChunkAssets.tap(TAP_AFTER, () => { + const ImportDependency: typeof WebpackImportDependency = getImportDependency(compilation); + + for (const module of compilation.modules) { + const toProcess: IExtendedModule[] = module.modules || [module]; + + for (const child of toProcess) { + child.hasDependencies((dep: webpack.compilation.Dependency) => { + if (dep instanceof ImportDependency) { + const { module: targetModule } = dep; + + if (targetModule) { + let localAsyncImports: Map | undefined = + asyncImportMap.get(module); + if (!localAsyncImports) { + asyncImportMap.set(module, (localAsyncImports = new Map())); + } + + const chunkGroup: webpack.compilation.ChunkGroup = dep.block.chunkGroup; + const chunkIds: number[] = chunkGroup + ? chunkGroup.chunks.map((chunk) => chunk.id!).sort() + : []; + const idString: string = chunkIds.join(';'); + + let meta: IAsyncImportMetadata | undefined = asyncImportGroups.get(idString); + if (!meta) { + asyncImportGroups.set( + idString, + (meta = { + chunkCount: chunkIds.length, + chunkIds: chunkIds, + count: 0, + index: -1 + }) + ); + } + meta.count++; + + const stringKey: string = `${targetModule.id}`.replace(/[^A-Za-z0-9_$]/g, '_'); + + const key: string = `${ASYNC_IMPORT_PREFIX}${stringKey}`; + localAsyncImports.set(key, { + meta, + module: targetModule + }); + } + } + }); + } + } + + const rankedImports: [string, IAsyncImportMetadata][] = [...asyncImportGroups] + .filter((x) => x[1].count > 1) + .sort((x, y) => { + let diff: number = y[1].count - x[1].count; + if (!diff) { + diff = y[1].chunkCount - x[1].chunkCount; + } + + if (!diff) { + diff = x[0] > y[0] ? 1 : x[0] < y[0] ? -1 : 0; + } + + return diff; + }); + + for (let i: number = 0, len: number = rankedImports.length; i < len; i++) { + rankedImports[i][1].index = i; + // console.log(rankedImports[i]); + } + + rankedImportGroups = rankedImports.map((x) => x[1]); + + const { dependencyTemplates } = compilation; + + const defaultImplementation: IImportDependencyTemplate | undefined = dependencyTemplates.get( + ImportDependency + ) as unknown as IImportDependencyTemplate; + if (!defaultImplementation) { + compilation.errors.push(new Error(`Could not find ImportDependencyTemplate`)); + } + + const customTemplate: IImportDependencyTemplate = { + apply( + dep: WebpackImportDependency, + source: ReplaceSource, + runtime: webpack.compilation.RuntimeTemplate + ): void { + if (dep.module) { + const stringKey: string = `${dep.module.id}`.replace(/[^A-Za-z0-9_$]/g, '_'); + const key: string = `${ASYNC_IMPORT_PREFIX}${stringKey}`; + const content: string = `__webpack_require__.ee(${key})`; + source.replace(dep.block.range[0], dep.block.range[1] - 1, content); + } else { + defaultImplementation?.apply(dep, source, runtime); + } + } + }; + + // Have to do this after the official plugin in order to override + // Typings in webpack are incorrect. This is a DependencyTemplate object + dependencyTemplates.set(ImportDependency, customTemplate as unknown as Tapable); + }); + + compilation.mainTemplate.hooks.requireExtensions.tap( + PLUGIN_NAME, + (source: string, chunk: webpack.compilation.Chunk) => { + if (!needChunkOnDemandLoadingCode(chunk)) { + return source; + } + + const { requireFn } = compilation.mainTemplate; + return Template.asString([ + `var asyncImportChunkGroups = [`, + rankedImportGroups + ? rankedImportGroups.map((x) => Template.indent(JSON.stringify(x.chunkIds))).join(',\n') + : '', + `];`, + `${requireFn}.ee = function (groupOrId, moduleId, importType) {`, + Template.indent([ + `return Promise.all((Array.isArray(groupOrId) ? groupOrId : asyncImportChunkGroups[groupOrId]).map(function (x) { return ${requireFn}.e(x); }))`, + `.then(importType ? ${requireFn}.t.bind(0,moduleId,importType) : ${requireFn}.bind(0,moduleId));` + ]), + `};`, + source + ]); + } + ); + }); + } +} diff --git a/webpack/webpack4-module-minifier-plugin/src/Constants.ts b/webpack/webpack4-module-minifier-plugin/src/Constants.ts new file mode 100644 index 00000000000..d6991610d37 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/Constants.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. + +/** + * Prefix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it. + * Public because alternate Minifier implementations may wish to know about it. + * @public + */ +export const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__(' = '__MINIFY_MODULE__('; +/** + * Suffix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it. + * Public because alternate Minifier implementations may wish to know about it. + * @public + */ +export const MODULE_WRAPPER_SUFFIX: ');' = ');'; + +/** + * Token to replace the object or array of module definitions so that the minifier can operate on the Webpack runtime or chunk boilerplate in isolation + * @public + */ +export const CHUNK_MODULES_TOKEN: '__WEBPACK_CHUNK_MODULES__' = '__WEBPACK_CHUNK_MODULES__'; + +/** + * Stage # to use when this should be the first tap in the hook + * @public + */ +export const STAGE_BEFORE: -100 = -100; +/** + * Stage # to use when this should be the last tap in the hook + * @public + */ +export const STAGE_AFTER: 100 = 100; diff --git a/webpack/webpack4-module-minifier-plugin/src/GenerateLicenseFileForAsset.ts b/webpack/webpack4-module-minifier-plugin/src/GenerateLicenseFileForAsset.ts new file mode 100644 index 00000000000..ce519780e3c --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/GenerateLicenseFileForAsset.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 * as path from 'node:path'; + +import type * as webpack from 'webpack'; +import { ConcatSource } from 'webpack-sources'; + +import type { + IAssetInfo, + IModuleMap, + IModuleInfo, + IExtendedModule, + _IAcornComment +} from './ModuleMinifierPlugin.types'; + +function getAllComments(moduleIds: (string | number)[], minifiedModules: IModuleMap): Set { + const allComments: Set = new Set(); + + for (const moduleId of moduleIds) { + const mod: IModuleInfo | undefined = minifiedModules.get(moduleId); + if (!mod) { + continue; + } + + const { module: webpackModule } = mod; + const modules: IExtendedModule[] = webpackModule.modules || [webpackModule]; + for (const submodule of modules) { + const { comments: subModuleComments } = submodule.factoryMeta as { + comments?: Set<_IAcornComment>; + }; + if (subModuleComments) { + for (const comment of subModuleComments) { + const value: string = comment.type === 'Line' ? `//${comment.value}\n` : `/*${comment.value}*/\n`; + allComments.add(value); + } + } + } + } + + return allComments; +} + +/** + * Generates a companion asset containing all extracted comments. If it is non-empty, returns a banner comment directing users to said companion asset. + * + * @param compilation - The webpack compilation + * @param asset - The asset to process + * @param minifiedModules - The minified modules to pull comments from + * @param assetName - The name of the asset + * @public + */ +export function generateLicenseFileForAsset( + compilation: webpack.compilation.Compilation, + asset: IAssetInfo, + minifiedModules: IModuleMap +): string { + // Extracted comments from the modules. + const comments: Set = getAllComments(asset.modules, minifiedModules); + + const assetName: string = asset.fileName; + + let banner: string = ''; + + if (comments.size) { + // There are license comments in this chunk, so generate the companion file and inject a banner + const licenseSource: ConcatSource = new ConcatSource(); + comments.forEach((comment) => { + licenseSource.add(comment); + }); + const licenseFileName: string = `${assetName}.LICENSE.txt`; + compilation.assets[licenseFileName] = licenseSource; + banner = `/*! For license information please see ${path.basename(licenseFileName)} */\n`; + } + + return banner; +} diff --git a/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts new file mode 100644 index 00000000000..40716e76ee6 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.ts @@ -0,0 +1,644 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createHash, type Hash } from 'node:crypto'; + +import { + CachedSource, + ConcatSource, + RawSource, + ReplaceSource, + type Source, + SourceMapSource +} from 'webpack-sources'; +import * as webpack from 'webpack'; +import { AsyncSeriesWaterfallHook, type SyncHook, SyncWaterfallHook, type TapOptions } from 'tapable'; + +import type { + IMinifierConnection, + IModuleMinifier, + IModuleMinificationResult, + IModuleMinificationErrorResult +} from '@rushstack/module-minifier'; +import { getIdentifier } from '@rushstack/module-minifier'; + +import { + CHUNK_MODULES_TOKEN, + MODULE_WRAPPER_PREFIX, + MODULE_WRAPPER_SUFFIX, + STAGE_BEFORE, + STAGE_AFTER +} from './Constants'; +import type { + IModuleMinifierPluginOptions, + IModuleMap, + IAssetMap, + IExtendedModule, + IModuleMinifierPluginHooks, + IPostProcessFragmentContext, + IDehydratedAssets, + _IWebpackCompilationData, + _IAcornComment, + IModuleMinifierPluginStats, + IAssetStats +} from './ModuleMinifierPlugin.types'; +import { generateLicenseFileForAsset } from './GenerateLicenseFileForAsset'; +import { rehydrateAsset } from './RehydrateAsset'; +import { AsyncImportCompressionPlugin } from './AsyncImportCompressionPlugin'; +import { PortableMinifierModuleIdsPlugin } from './PortableMinifierIdsPlugin'; + +import './OverrideWebpackIdentifierAllocation'; + +// The name of the plugin, for use in taps +const PLUGIN_NAME: 'ModuleMinifierPlugin' = 'ModuleMinifierPlugin'; + +// Monotonically increasing identifier to be incremented any time the code generation logic changes +// Will be applied to the webpack hash. +const CODE_GENERATION_REVISION: number = 1; + +const TAP_BEFORE: TapOptions<'promise'> = { + name: PLUGIN_NAME, + stage: STAGE_BEFORE +}; +const TAP_AFTER: TapOptions<'sync'> = { + name: PLUGIN_NAME, + stage: STAGE_AFTER +}; + +interface IExtendedChunkTemplate { + hooks: { + hashForChunk: SyncHook; + modules: SyncWaterfallHook; + }; +} + +interface IExtendedParser extends webpack.compilation.normalModuleFactory.Parser { + state: { + module: IExtendedModule; + }; +} + +interface IExtendedModuleTemplate extends webpack.compilation.ModuleTemplate { + render: (module: IExtendedModule, dependencyTemplates: unknown, options: unknown) => Source; +} + +interface IOptionsForHash extends Omit { + revision: number; + minifier: undefined; +} + +const compilationMetadataMap: WeakMap = + new WeakMap(); + +/** + * https://github.com/webpack/webpack/blob/30e747a55d9e796ae22f67445ae42c7a95a6aa48/lib/Template.js#L36-47 + * @param a first id to be sorted + * @param b second id to be sorted against + * @returns the sort value + */ +function stringifyIdSortPredicate(a: string | number, b: string | number): -1 | 0 | 1 { + const aId: string = a + ''; + const bId: string = b + ''; + if (aId < bId) return -1; + if (aId > bId) return 1; + return 0; +} + +function hashCodeFragment(code: string): string { + return createHash('sha256').update(code).digest('hex'); +} + +/** + * Base implementation of asset rehydration + * + * @param dehydratedAssets The dehydrated assets + * @param compilation The webpack compilation + */ +function defaultRehydrateAssets( + dehydratedAssets: IDehydratedAssets, + compilation: webpack.compilation.Compilation +): IDehydratedAssets { + const { assets, modules } = dehydratedAssets; + + const compilationMetadata: IModuleMinifierPluginStats | undefined = compilationMetadataMap.get(compilation); + if (!compilationMetadata) { + throw new Error(`Could not get compilation metadata`); + } + + const { metadataByAssetFileName } = compilationMetadata; + + // Now assets/modules contain fully minified code. Rehydrate. + for (const [assetName, info] of assets) { + const banner: string = /\.m?js(\?.+)?$/.test(assetName) + ? generateLicenseFileForAsset(compilation, info, modules) + : ''; + + const outputSource: Source = rehydrateAsset(info, modules, banner, true); + metadataByAssetFileName.set(assetName, { + positionByModuleId: info.renderInfo + }); + compilation.assets[assetName] = outputSource; + } + + return dehydratedAssets; +} + +function isMinificationResultError( + result: IModuleMinificationResult +): result is IModuleMinificationErrorResult { + return !!result.error; +} + +// Matche behavior of terser's "some" option +function isLicenseComment(comment: _IAcornComment): boolean { + // https://github.com/terser/terser/blob/d3d924fa9e4c57bbe286b811c6068bcc7026e902/lib/output.js#L175 + return /@preserve|@lic|@cc_on|^\**!/i.test(comment.value); +} + +/** + * Webpack plugin that minifies code on a per-module basis rather than per-asset. The actual minification is handled by the input `minifier` object. + * @public + */ +export class ModuleMinifierPlugin implements webpack.Plugin { + public readonly hooks: IModuleMinifierPluginHooks; + public minifier: IModuleMinifier; + + private readonly _enhancers: webpack.Plugin[]; + private readonly _sourceMap: boolean | undefined; + + private readonly _optionsForHash: IOptionsForHash; + + public constructor(options: IModuleMinifierPluginOptions) { + this.hooks = { + rehydrateAssets: new AsyncSeriesWaterfallHook(['dehydratedContent', 'compilation']), + + finalModuleId: new SyncWaterfallHook(['id']), + + postProcessCodeFragment: new SyncWaterfallHook(['code', 'context']) + }; + + const { minifier, sourceMap, usePortableModules = false, compressAsyncImports = false } = options; + + this._optionsForHash = { + ...options, + minifier: undefined, + revision: CODE_GENERATION_REVISION + }; + + this._enhancers = []; + + if (usePortableModules) { + this._enhancers.push(new PortableMinifierModuleIdsPlugin(this.hooks)); + } + + if (compressAsyncImports) { + this._enhancers.push(new AsyncImportCompressionPlugin(this.hooks)); + } + + this.hooks.rehydrateAssets.tap(PLUGIN_NAME, defaultRehydrateAssets); + this.minifier = minifier; + + this._sourceMap = sourceMap; + } + + public static getCompilationStatistics( + compilation: webpack.compilation.Compilation + ): IModuleMinifierPluginStats | undefined { + return compilationMetadataMap.get(compilation); + } + + public apply(compiler: webpack.Compiler): void { + for (const enhancer of this._enhancers) { + enhancer.apply(compiler); + } + + const { + options: { devtool, mode } + } = compiler; + // The explicit setting is preferred due to accuracy, but try to guess based on devtool + const useSourceMaps: boolean = + typeof this._sourceMap === 'boolean' + ? this._sourceMap + : typeof devtool === 'string' + ? devtool.endsWith('source-map') + : mode === 'production' && devtool !== false; + + this._optionsForHash.sourceMap = useSourceMaps; + const binaryConfig: Uint8Array = Buffer.from(JSON.stringify(this._optionsForHash), 'utf-8'); + + compiler.hooks.thisCompilation.tap( + PLUGIN_NAME, + (compilation: webpack.compilation.Compilation, compilationData: _IWebpackCompilationData) => { + const { normalModuleFactory } = compilationData; + + function addCommentExtraction(parser: webpack.compilation.normalModuleFactory.Parser): void { + parser.hooks.program.tap(PLUGIN_NAME, (program: unknown, comments: _IAcornComment[]) => { + (parser as IExtendedParser).state.module.factoryMeta.comments = comments.filter(isLicenseComment); + }); + } + + normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, addCommentExtraction); + normalModuleFactory.hooks.parser.for('javascript/dynamic').tap(PLUGIN_NAME, addCommentExtraction); + normalModuleFactory.hooks.parser.for('javascript/esm').tap(PLUGIN_NAME, addCommentExtraction); + + /** + * Set of local module ids that have been processed. + */ + const submittedModules: Set = new Set(); + + /** + * The text and comments of all minified modules. + */ + const minifiedModules: IModuleMap = new Map(); + + /** + * The text and comments of all minified chunks. Most of these are trivial, but the runtime chunk is a bit larger. + */ + const minifiedAssets: IAssetMap = new Map(); + + const metadataByAssetFileName: Map = new Map(); + const compilationStatistics: IModuleMinifierPluginStats = { + metadataByAssetFileName + }; + compilationMetadataMap.set(compilation, compilationStatistics); + + let pendingMinificationRequests: number = 0; + /** + * Indicates that all files have been sent to the minifier and therefore that when pending hits 0, assets can be rehydrated. + */ + let allRequestsIssued: boolean = false; + + let resolveMinifyPromise: () => void; + + const getRealId: (id: number | string) => number | string | undefined = (id: number | string) => + this.hooks.finalModuleId.call(id, compilation); + + const postProcessCode: ( + code: ReplaceSource, + context: IPostProcessFragmentContext + ) => ReplaceSource = (code: ReplaceSource, context: IPostProcessFragmentContext) => + this.hooks.postProcessCodeFragment.call(code, context); + + /** + * Callback to invoke when a file has finished minifying. + */ + function onFileMinified(): void { + if (--pendingMinificationRequests === 0 && allRequestsIssued) { + resolveMinifyPromise(); + } + } + + const { minifier } = this; + + let minifierConnection: IMinifierConnection | undefined; + + const requestShortener: webpack.compilation.RequestShortener = + compilation.runtimeTemplate.requestShortener; + + /** + * Extracts the code for the module and sends it to be minified. + * Currently source maps are explicitly not supported. + * @param {Source} source + * @param {Module} mod + */ + function minifyModule(source: Source, mod: IExtendedModule): Source { + const id: string | number | null = mod.id; + + if (id !== null && !submittedModules.has(id)) { + // options.chunk contains the current chunk, if needed + // Render the source, then hash, then persist hash -> module, return a placeholder + + // Initially populate the map with unminified version; replace during callback + submittedModules.add(id); + + const realId: string | number | undefined = getRealId(id); + + if (realId !== undefined && !mod.factoryMeta.skipMinification) { + const wrapped: ConcatSource = new ConcatSource( + MODULE_WRAPPER_PREFIX + '\n', + source, + '\n' + MODULE_WRAPPER_SUFFIX + ); + + const nameForMap: string = `(modules)/${realId}`; + + const { source: wrappedCode, map } = useSourceMaps + ? wrapped.sourceAndMap() + : { + source: wrapped.source(), + map: undefined + }; + + const hash: string = hashCodeFragment(wrappedCode); + + ++pendingMinificationRequests; + + minifier.minify( + { + hash, + code: wrappedCode, + nameForMap: useSourceMaps ? nameForMap : undefined, + externals: undefined + }, + (result: IModuleMinificationResult) => { + if (isMinificationResultError(result)) { + compilation.errors.push(result.error); + } else { + try { + // Have the source map display the module id instead of the minifier boilerplate + const sourceForMap: string = `// ${mod.readableIdentifier( + requestShortener + )}${wrappedCode.slice(MODULE_WRAPPER_PREFIX.length, -MODULE_WRAPPER_SUFFIX.length)}`; + + const { code: minified, map: minifierMap } = result; + + const rawOutput: Source = useSourceMaps + ? new SourceMapSource( + minified, // Code + nameForMap, // File + minifierMap!, // Base source map + sourceForMap, // Source from before transform + map!, // Source Map from before transform + false // Remove original source + ) + : new RawSource(minified); + + const unwrapped: ReplaceSource = new ReplaceSource(rawOutput); + const len: number = minified.length; + + unwrapped.replace(0, MODULE_WRAPPER_PREFIX.length - 1, ''); + unwrapped.replace(len - MODULE_WRAPPER_SUFFIX.length, len - 1, ''); + + const withIds: Source = postProcessCode(unwrapped, { + compilation, + module: mod, + loggingName: mod.identifier() + }); + const cached: CachedSource = new CachedSource(withIds); + + const minifiedSize: number = Buffer.byteLength(cached.source(), 'utf-8'); + mod.factoryMeta.minifiedSize = minifiedSize; + + minifiedModules.set(realId, { + source: cached, + module: mod + }); + } catch (err) { + compilation.errors.push(err); + } + } + + onFileMinified(); + } + ); + } else { + // Route any other modules straight through + const cached: CachedSource = new CachedSource( + postProcessCode(new ReplaceSource(source), { + compilation, + module: mod, + loggingName: mod.identifier() + }) + ); + + const minifiedSize: number = Buffer.byteLength(cached.source(), 'utf-8'); + mod.factoryMeta.minifiedSize = minifiedSize; + + minifiedModules.set(realId !== undefined ? realId : id, { + source: cached, + module: mod + }); + } + } + + // Return something so that this stage still produces valid ECMAScript + return new RawSource('(function(){})'); + } + + const jsTemplate: IExtendedModuleTemplate = compilation.moduleTemplates + .javascript as IExtendedModuleTemplate; + const innerRender: IExtendedModuleTemplate['render'] = jsTemplate.render.bind(jsTemplate); + + // The optimizeTree hook is the last async hook that occurs before chunk rendering + compilation.hooks.optimizeTree.tapPromise(PLUGIN_NAME, async () => { + minifierConnection = await minifier.connectAsync(); + + submittedModules.clear(); + + const cache: WeakSet = new WeakSet(); + const defaultSource: Source = new RawSource(''); + + // During code generation, send the generated code to the minifier and replace with a placeholder + // Hacking this to avoid calling .source() on a concatenated module multiple times + jsTemplate.render = (module: IExtendedModule, dependencyTemplates, options) => { + if (!cache.has(module)) { + cache.add(module); + const rendered: Source = innerRender(module, dependencyTemplates, options); + + minifyModule(rendered, module); + } + + return defaultSource; + }; + }); + + // This should happen before any other tasks that operate during optimizeChunkAssets + compilation.hooks.optimizeChunkAssets.tapPromise( + TAP_BEFORE, + async (chunks: webpack.compilation.Chunk[]): Promise => { + // Still need to minify the rendered assets + for (const chunk of chunks) { + const externals: string[] = []; + const externalNames: Map = new Map(); + + const chunkModuleSet: Set = new Set(); + const allChunkModules: Iterable = + chunk.modulesIterable as Iterable; + let hasNonNumber: boolean = false; + for (const mod of allChunkModules) { + if (mod.id !== null) { + if (typeof mod.id !== 'number') { + hasNonNumber = true; + } + chunkModuleSet.add(mod.id); + + if (mod.external) { + // Match the identifiers generated in the AmdMainTemplatePlugin + // https://github.com/webpack/webpack/blob/444e59f8a427f94f0064cae6765e5a3c4b78596d/lib/AmdMainTemplatePlugin.js#L49 + const key: string = `__WEBPACK_EXTERNAL_MODULE_${webpack.Template.toIdentifier( + `${mod.id}` + )}__`; + // The first two identifiers are used for function (module, exports) at the module site + const ordinal: number = 2 + externals.length; + const miniId: string = getIdentifier(ordinal); + externals.push(key); + externalNames.set(key, miniId); + } + } + } + + const chunkModules: (string | number)[] = Array.from(chunkModuleSet); + // Sort by id before rehydration in case we rehydrate a given chunk multiple times + chunkModules.sort( + hasNonNumber + ? stringifyIdSortPredicate + : (x: string | number, y: string | number) => (x as number) - (y as number) + ); + + for (const assetName of chunk.files) { + const asset: Source = compilation.assets[assetName]; + + // Verify that this is a JS asset + if (/\.m?js(\?.+)?$/.test(assetName)) { + ++pendingMinificationRequests; + + const rawCode: string = asset.source() as string; + const nameForMap: string = `(chunks)/${assetName}`; + + const hash: string = hashCodeFragment(rawCode); + + minifier.minify( + { + hash, + code: rawCode, + nameForMap: useSourceMaps ? nameForMap : undefined, + externals + }, + (result: IModuleMinificationResult) => { + if (isMinificationResultError(result)) { + compilation.errors.push(result.error); + // eslint-disable-next-line no-console + console.error(result.error); + } else { + try { + const { code: minified, map: minifierMap } = result; + + let codeForMap: string = rawCode; + if (useSourceMaps) { + // Pretend the __WEBPACK_CHUNK_MODULES__ token is an array of module ids, so that the source map contains information about the module ids in the chunk + codeForMap = codeForMap.replace( + CHUNK_MODULES_TOKEN, + JSON.stringify(chunkModules, undefined, 2) + ); + } + + const rawOutput: Source = useSourceMaps + ? new SourceMapSource( + minified, // Code + nameForMap, // File + minifierMap!, // Base source map + codeForMap, // Source from before transform + undefined, // Source Map from before transform + false // Remove original source + ) + : new RawSource(minified); + + const withIds: Source = postProcessCode(new ReplaceSource(rawOutput), { + compilation, + module: undefined, + loggingName: assetName + }); + + minifiedAssets.set(assetName, { + source: new CachedSource(withIds), + modules: chunkModules, + chunk, + fileName: assetName, + renderInfo: new Map(), + externalNames + }); + } catch (err) { + compilation.errors.push(err); + } + } + + onFileMinified(); + } + ); + } else { + // This isn't a JS asset. Don't try to minify the asset wrapper, though if it contains modules, those might still get replaced with minified versions. + minifiedAssets.set(assetName, { + // Still need to restore ids + source: postProcessCode(new ReplaceSource(asset), { + compilation, + module: undefined, + loggingName: assetName + }), + modules: chunkModules, + chunk, + fileName: assetName, + renderInfo: new Map(), + externalNames + }); + } + } + } + + allRequestsIssued = true; + + if (pendingMinificationRequests) { + await new Promise((resolve) => { + resolveMinifyPromise = resolve; + }); + } + + // Handle any error from the minifier. + await minifierConnection?.disconnectAsync(); + + // All assets and modules have been minified, hand them off to be rehydrated + await this.hooks.rehydrateAssets.promise( + { + assets: minifiedAssets, + modules: minifiedModules + }, + compilation + ); + } + ); + + function updateChunkHash(hash: Hash, chunk: webpack.compilation.Chunk): void { + // Apply the options hash + hash.update(binaryConfig); + // Apply the hash from the minifier + if (minifierConnection) { + hash.update(minifierConnection.configHash, 'utf8'); + } + } + + // Need to update chunk hashes with information from this plugin + (compilation.chunkTemplate as unknown as IExtendedChunkTemplate).hooks.hashForChunk.tap( + PLUGIN_NAME, + updateChunkHash + ); + compilation.mainTemplate.hooks.hashForChunk.tap(PLUGIN_NAME, updateChunkHash); + + // This function is written twice because the parameter order is not the same between the two hooks + (compilation.chunkTemplate as unknown as IExtendedChunkTemplate).hooks.modules.tap( + TAP_AFTER, + (source: Source, chunk: webpack.compilation.Chunk, moduleTemplate: unknown) => { + if (moduleTemplate !== compilation.moduleTemplates.javascript) { + // This is not a JavaScript asset + return source; + } + + // Discard the rendered modules + return new RawSource(CHUNK_MODULES_TOKEN); + } + ); + + (compilation.mainTemplate as unknown as IExtendedChunkTemplate).hooks.modules.tap( + TAP_AFTER, + (source: Source, chunk: webpack.compilation.Chunk, hash: unknown, moduleTemplate: unknown) => { + if (moduleTemplate !== compilation.moduleTemplates.javascript) { + // This is not a JavaScript asset + return source; + } + + // Discard the rendered modules + return new RawSource(CHUNK_MODULES_TOKEN); + } + ); + } + ); + } +} diff --git a/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts new file mode 100644 index 00000000000..45c5c9e5c4b --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts @@ -0,0 +1,286 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { AsyncSeriesWaterfallHook, SyncWaterfallHook } from 'tapable'; +import type * as webpack from 'webpack'; +import type { ReplaceSource, Source } from 'webpack-sources'; + +import type { IModuleMinifier } from '@rushstack/module-minifier'; + +/** + * Information about where the module was rendered in the emitted asset. + * @public + */ +export interface IRenderedModulePosition { + /** + * The offset from the start of tha asset to the start of the module, in characters. + */ + charOffset: number; + /** + * The length of the rendered module, in characters. + */ + charLength: number; +} + +/** + * Information about a dehydrated webpack ECMAScript asset + * @public + */ +export interface IAssetInfo { + /** + * The (minified) boilerplate code for the asset. Will contain a token to be replaced by the minified modules. + */ + source: Source; + + /** + * The name of the asset, used to index into compilation.assets + */ + fileName: string; + + /** + * The ids of the modules that are part of the chunk corresponding to this asset + */ + modules: (string | number)[]; + + /** + * Information about the offsets and character lengths for each rendered module in the final asset. + */ + renderInfo: Map; + + /** + * The raw chunk object from Webpack, in case information from it is necessary for reconstruction + */ + chunk: webpack.compilation.Chunk; + + /** + * The set of external names to postprocess + */ + externalNames: Map; +} + +/** + * Statistics from the plugin. Namely module sizes. + * @public + */ +export interface IModuleMinifierPluginStats { + metadataByAssetFileName: Map; +} + +/** + * Rendered positional data + * @public + */ +export interface IAssetStats { + positionByModuleId: Map; +} + +/** + * Information about a minified module + * @public + */ +export interface IModuleInfo { + /** + * The (minified) code of this module. Will be a function expression. + */ + source: Source; + + /** + * The raw module object from Webpack, in case information from it is necessary for reconstruction + */ + module: IExtendedModule; +} + +/** + * Extension of the webpack Module typings with members that are used by this Plugin + * @public + */ +export interface IExtendedModule extends webpack.compilation.Module { + /** + * Is this module external? + */ + external?: boolean; + /** + * Concatenated modules + */ + modules?: IExtendedModule[]; + /** + * Recursively scan the dependencies of a module + */ + hasDependencies(callback: (dep: webpack.compilation.Dependency) => boolean | void): boolean; + /** + * Id for the module + */ + // eslint-disable-next-line @rushstack/no-new-null + id: string | number | null; + /** + * Gets a descriptive identifier for the module. + */ + identifier(): string; + /** + * Gets a friendly identifier for the module. + */ + readableIdentifier(requestShortener: unknown): string; + /** + * Path to the physical file this module represents + */ + resource?: string; +} + +declare module 'webpack' { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace compilation { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface RuntimeTemplate { + requestShortener: webpack.compilation.RequestShortener; + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + interface RequestShortener {} + } +} + +/** + * This is the second parameter to the thisCompilation and compilation webpack.Compiler hooks. + * @internal + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface _IWebpackCompilationData { + normalModuleFactory: webpack.compilation.NormalModuleFactory; +} + +/** + * This is the second parameter to the NormalModuleFactory `module` hook + * @internal + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface _INormalModuleFactoryModuleData { + resourceResolveData?: { + /** + * Contents of the description file (package.json) for the module + */ + descriptionFileData?: { + /** + * The name of the package + */ + name: string; + }; + /** + * Absolute path of the description file (package.json) for the module + */ + descriptionFilePath?: string; + /** + * Absolute path of the directory containing the description file (package.json) for the module + */ + descriptionFileRoot?: string; + /** + * Relative path from the description file (package.json) to the module + */ + relativePath?: string; + }; +} + +/** + * A map from file names to dehydrated assets + * @public + */ +export type IAssetMap = Map; +/** + * A map from module ids to minified modules + * @public + */ +export type IModuleMap = Map; + +/** + * Options to the ModuleMinifierPlugin constructor + * @public + */ +export interface IModuleMinifierPluginOptions { + /** + * Minifier implementation to use. Required. + */ + minifier: IModuleMinifier; + + /** + * Whether to enable source map processing. If not provided, will attempt to guess based on `mode` and `devtool` in the webpack config. + * Set to `false` for faster builds at the expense of debuggability. + */ + sourceMap?: boolean; + + /** + * Instructs the plugin to alter the code of modules to maximize portability across compilations. + */ + usePortableModules?: boolean; + + /** + * Instructs the plugin to alter the code of async import statements to compress better and be portable across compilations. + */ + compressAsyncImports?: boolean; +} + +/** + * The set of data remaining to rehydrate in the current compilation + * @public + */ +export interface IDehydratedAssets { + /** + * The set of remaining assets to rehydrate. Each tap may remove some or all assets from this collection + */ + assets: IAssetMap; + + /** + * The set of modules to use for rehydrating assets. + */ + modules: IModuleMap; +} + +/** + * Argument to the postProcessCodeFragment hook for the current execution context + * @public + */ +export interface IPostProcessFragmentContext { + /** + * The current webpack compilation, for error reporting + */ + compilation: webpack.compilation.Compilation; + /** + * A name to use for logging + */ + loggingName: string; + /** + * The current module being processed, or `undefined` if not in a module (e.g. the bootstrapper) + */ + module: webpack.compilation.Module | undefined; +} + +/** + * Hooks provided by the ModuleMinifierPlugin + * @public + */ +export interface IModuleMinifierPluginHooks { + /** + * Hook invoked at the start of optimizeChunkAssets to rehydrate the minified boilerplate and runtime into chunk assets. + */ + rehydrateAssets: AsyncSeriesWaterfallHook; + + /** + * Hook invoked on a module id to get the final rendered id. + */ + finalModuleId: SyncWaterfallHook; + + /** + * Hook invoked on code after it has been returned from the minifier. + */ + postProcessCodeFragment: SyncWaterfallHook; +} + +/** + * The comment objects from the Acorn parser inside of webpack + * @internal + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface _IAcornComment { + type: 'Line' | 'Block'; + value: string; + start: number; + end: number; +} diff --git a/webpack/webpack4-module-minifier-plugin/src/OverrideWebpackIdentifierAllocation.ts b/webpack/webpack4-module-minifier-plugin/src/OverrideWebpackIdentifierAllocation.ts new file mode 100644 index 00000000000..04d9267e5da --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/OverrideWebpackIdentifierAllocation.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 { Template } from 'webpack'; + +import { getIdentifier } from '@rushstack/module-minifier'; + +// Configure webpack to use the same identifier allocation logic as Terser to maximize gzip compressibility +Template.numberToIdentifer = getIdentifier; diff --git a/webpack/webpack4-module-minifier-plugin/src/ParallelCompiler.ts b/webpack/webpack4-module-minifier-plugin/src/ParallelCompiler.ts new file mode 100644 index 00000000000..194da4d4d89 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/ParallelCompiler.ts @@ -0,0 +1,142 @@ +// 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 { resolve } from 'node:path'; +import type { Worker } from 'node:worker_threads'; + +import type { Configuration } from 'webpack'; + +import type { + IMinifierConnection, + IModuleMinificationRequest, + IModuleMinificationResult, + MinifyOptions +} from '@rushstack/module-minifier'; +import { WorkerPoolMinifier } from '@rushstack/module-minifier'; +import { WorkerPool } from '@rushstack/worker-pool'; + +export interface IParallelWebpackOptions { + cacheDirectory?: string; + configFilePath: string; + maxCompilationThreads?: number; + sourceMap?: boolean | undefined; + terserOptions?: MinifyOptions; + usePortableModules?: boolean; +} + +const ZERO: bigint = BigInt(0); +const THOUSAND: bigint = BigInt(1e3); + +/** + * Formats a delta of `process.hrtime.bigint()` values as a string + * @param timeNs + */ +function formatTime(timeNs: bigint): string { + let unit: string = 'ns'; + let fraction: bigint = ZERO; + if (timeNs > THOUSAND) { + unit = 'us'; + fraction = timeNs % THOUSAND; + timeNs /= THOUSAND; + } + if (timeNs > THOUSAND) { + unit = 'ms'; + fraction = timeNs % THOUSAND; + timeNs /= THOUSAND; + } + if (timeNs > THOUSAND) { + unit = 's'; + fraction = timeNs % THOUSAND; + timeNs /= THOUSAND; + } + + return `${timeNs}.${('000' + fraction).slice(-3, -1)} ${unit}`; +} + +export async function runParallel(options: IParallelWebpackOptions): Promise { + const resolvedPath: string = resolve(options.configFilePath); + const rawConfig: Configuration | Configuration[] = require(resolvedPath); + const configArray: Configuration[] = Array.isArray(rawConfig) ? rawConfig : [rawConfig]; + const configCount: number = configArray.length; + + const totalCpus: number = os.availableParallelism?.() ?? os.cpus().length; + + // TODO: Use all cores if not minifying + const { + maxCompilationThreads: maxConfiguredCompilationThreads = Math.max( + totalCpus > 8 ? (totalCpus * 3) >> 2 : totalCpus >> 1, + 1 + ), + sourceMap, + usePortableModules + } = options; + + const maxCompilationThreads: number = Math.min(configCount, maxConfiguredCompilationThreads); + + const maxCompressionThreads: number = Math.max(1, totalCpus - maxCompilationThreads); + + const minifier: WorkerPoolMinifier = new WorkerPoolMinifier({ + terserOptions: options.terserOptions, + maxThreads: maxCompressionThreads + }); + + const minifierConnection: IMinifierConnection = await minifier.connectAsync(); + + const webpackPool: WorkerPool = new WorkerPool({ + id: 'Webpack', + maxWorkers: maxCompilationThreads, + onWorkerDestroyed: (): void => { + // Allocate the webpack worker to terser + minifier.maxThreads++; + }, + workerScriptPath: require.resolve('./workerPool/WebpackWorker'), + workerData: { + configFilePath: resolvedPath, + sourceMap, + usePortableModules + } + }); + + let processed: number = 0; + const startTime: bigint = process.hrtime.bigint(); + + for (let i: number = 0; i < configCount; i++) { + const webpackWorker: Worker = await webpackPool.checkoutWorkerAsync(true); + + const sendMinifierResult: (result: IModuleMinificationResult) => void = ( + result: IModuleMinificationResult + ): void => { + webpackWorker.postMessage(result); + }; + + const workerOnMessage: (message: IModuleMinificationRequest | number) => void = ( + message: IModuleMinificationRequest | string | number + ): void => { + if (message === 'getConfigHash') { + webpackWorker.postMessage(minifierConnection.configHash); + return; + } + + if (typeof message === 'object') { + return minifier.minify(message, sendMinifierResult); + } + + ++processed; + // eslint-disable-next-line no-console + console.log( + `${processed}/${configCount} complete (${formatTime(process.hrtime.bigint() - startTime)})` + ); + + webpackWorker.off('message', workerOnMessage); + webpackPool.checkinWorker(webpackWorker); + }; + + webpackWorker.on('message', workerOnMessage); + webpackWorker.postMessage(i); + } + + await webpackPool.finishAsync(); + + await minifierConnection.disconnectAsync(); +} diff --git a/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts b/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts new file mode 100644 index 00000000000..d52230ee6b1 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/PortableMinifierIdsPlugin.ts @@ -0,0 +1,190 @@ +// 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 { Compiler, Plugin } from 'webpack'; +import type webpack from 'webpack'; +import type { ReplaceSource } from 'webpack-sources'; +import type { TapOptions } from 'tapable'; +import RequestShortener from 'webpack/lib/RequestShortener'; + +import { STAGE_AFTER, STAGE_BEFORE } from './Constants'; +import type { + _INormalModuleFactoryModuleData, + IExtendedModule, + IModuleMinifierPluginHooks, + _IWebpackCompilationData, + IPostProcessFragmentContext +} from './ModuleMinifierPlugin.types'; + +const PLUGIN_NAME: 'PortableMinifierModuleIdsPlugin' = 'PortableMinifierModuleIdsPlugin'; + +const TAP_BEFORE: TapOptions<'sync'> = { + name: PLUGIN_NAME, + stage: STAGE_BEFORE +}; + +const TAP_AFTER: TapOptions<'sync'> = { + name: PLUGIN_NAME, + stage: STAGE_AFTER +}; + +const STABLE_MODULE_ID_PREFIX: '__MODULEID_SHA_' = '__MODULEID_SHA_'; +// The negative lookback here is to ensure that this regex does not match an async import placeholder +const STABLE_MODULE_ID_REGEX: RegExp = /(? string = RequestShortener.prototype.shorten; + RequestShortener.prototype.shorten = function (this: RequestShortener, request: string): string { + const baseResult: string = baseShorten.call(this, request); + const nodeModules: '/node_modules/' = '/node_modules/'; + + if (!baseResult) { + return baseResult; + } + + const nodeModulesIndex: number = baseResult.lastIndexOf(nodeModules); + if (nodeModulesIndex < 0) { + return baseResult; + } + + const nodeModulePath: string = baseResult.slice(nodeModulesIndex + nodeModules.length); + this.cache.set(request, nodeModulePath); + return nodeModulePath; + }; + + const stableIdToFinalId: Map = new Map(); + + this._minifierHooks.finalModuleId.tap(PLUGIN_NAME, (id: string | number | undefined) => { + return id === undefined ? id : stableIdToFinalId.get(id); + }); + + this._minifierHooks.postProcessCodeFragment.tap( + PLUGIN_NAME, + (source: ReplaceSource, context: IPostProcessFragmentContext) => { + const code: string = source.original().source() as string; + + STABLE_MODULE_ID_REGEX.lastIndex = -1; + // RegExp.exec uses null or an array as the return type, explicitly + let match: RegExpExecArray | null = null; + while ((match = STABLE_MODULE_ID_REGEX.exec(code))) { + const id: string = match[1]; + const mapped: string | number | undefined = this._minifierHooks.finalModuleId.call( + id, + context.compilation + ); + + if (mapped === undefined) { + context.compilation.errors.push( + new Error(`Missing module id for ${id} in ${context.loggingName}!`) + ); + } + + source.replace(match.index, STABLE_MODULE_ID_REGEX.lastIndex - 1, JSON.stringify(mapped)); + } + + return source; + } + ); + + compiler.hooks.thisCompilation.tap( + PLUGIN_NAME, + (compilation: webpack.compilation.Compilation, compilationData: _IWebpackCompilationData) => { + const { normalModuleFactory } = compilationData; + + normalModuleFactory.hooks.module.tap( + PLUGIN_NAME, + (mod: IExtendedModule, data: _INormalModuleFactoryModuleData) => { + const { resourceResolveData: resolveData } = data; + + if (resolveData) { + mod.factoryMeta.resolveData = resolveData; + return; + } + + // eslint-disable-next-line no-console + console.error(`Missing resolution data for ${mod.resource}`); + } + ); + + compilation.hooks.succeedModule.tap(PLUGIN_NAME, (mod: webpack.compilation.Module) => { + const { resolveData } = mod.factoryMeta; + + if (!resolveData) { + return; + } + + const { descriptionFileData: packageJson, relativePath } = resolveData; + + if (packageJson && relativePath) { + const nodeId: string = `${packageJson.name}${relativePath.slice(1).replace(/\.js(on)?$/, '')}`; + mod.factoryMeta.nodeResource = nodeId; + } + }); + + stableIdToFinalId.clear(); + + // Make module ids a pure function of the file path immediately before rendering. + // Unfortunately, other means of altering these ids don't work in Webpack 4 without a lot more code and work. + // Namely, a number of functions reference "module.id" directly during code generation + + compilation.hooks.beforeChunkAssets.tap(TAP_AFTER, () => { + // For tracking collisions + const resourceById: Map = new Map(); + + for (const mod of compilation.modules) { + const originalId: string | number = mod.id; + + // Need different cache keys for different sets of loaders, so can't use 'resource' + const identity: string = mod.identifier(); + const hashId: string = createHash('sha256').update(identity).digest('hex'); + + // This is designed to be an easily regex-findable string + const stableId: string = `${STABLE_MODULE_ID_PREFIX}${hashId}`; + const existingResource: string | undefined = resourceById.get(stableId); + + if (existingResource) { + compilation.errors.push( + new Error( + `Module id collision for ${identity} with ${existingResource}.\n This means you are bundling multiple versions of the same module.` + ) + ); + } + + stableIdToFinalId.set(stableId, originalId); + + // Record to detect collisions + resourceById.set(stableId, identity); + mod.id = stableId; + } + }); + + // This is the hook immediately following chunk asset rendering. Fix the module ids. + compilation.hooks.additionalChunkAssets.tap(TAP_BEFORE, () => { + // Restore module ids in case any later hooks need them + for (const mod of compilation.modules) { + const stableId: string | number = mod.id; + const finalId: string | number | undefined = stableIdToFinalId.get(stableId); + if (finalId !== undefined) { + mod.id = finalId; + } + } + }); + } + ); + } +} diff --git a/webpack/webpack4-module-minifier-plugin/src/RehydrateAsset.ts b/webpack/webpack4-module-minifier-plugin/src/RehydrateAsset.ts new file mode 100644 index 00000000000..bd896bbaf4a --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/RehydrateAsset.ts @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CachedSource, ConcatSource, ReplaceSource, type Source } from 'webpack-sources'; + +import { CHUNK_MODULES_TOKEN } from './Constants'; +import type { IAssetInfo, IModuleMap, IModuleInfo } from './ModuleMinifierPlugin.types'; + +/** + * Rehydrates an asset with minified modules. + * @param asset - The asset + * @param moduleMap - The minified modules + * @param banner - A banner to inject for license information + * @param emitRenderInfo - If set, provide information about module offsets + * @public + */ +export function rehydrateAsset( + asset: IAssetInfo, + moduleMap: IModuleMap, + banner: string, + emitRenderInfo?: boolean +): Source { + const { source: assetSource, modules } = asset; + + const assetCode: string = assetSource.source() as string; + + const tokenIndex: number = assetCode.indexOf(CHUNK_MODULES_TOKEN); + if (tokenIndex < 0) { + // This is not a JS asset. + return handleExternals(assetSource, asset); + } + const suffixStart: number = tokenIndex + CHUNK_MODULES_TOKEN.length; + const suffix: string = assetCode.slice(suffixStart); + + const prefix: ReplaceSource = new ReplaceSource(assetSource); + // Preserve source map via fiddly logic + prefix.replace(tokenIndex, assetCode.length, ''); + + if (!modules.length) { + // Empty chunk, degenerate case + return new ConcatSource(banner, prefix, '[]', suffix); + } + + const emptyFunction = 'function(){}'; // eslint-disable-line @typescript-eslint/typedef + // This must not have the global flag set + const validIdRegex: RegExp = /^[A-Za-z_$][A-Za-z0-9_$]*$/; + + const source: ConcatSource = new ConcatSource(banner, prefix); + // Source.size() is in bytes, we want characters + let charOffset: number = source.source().length; + + const firstModuleId: string | number = modules[0]; + const lastModuleId: string | number = modules[modules.length - 1]; + + // Extended logic from webpack.Template.getModulesArrayBounds + const minId: number = typeof firstModuleId === 'number' ? firstModuleId : 0; + const maxId: number = typeof lastModuleId === 'number' ? lastModuleId : Infinity; + + const simpleArrayOverhead: number = 2 + maxId; + let concatArrayOverhead: number = simpleArrayOverhead + 9; + + let useObject: boolean = typeof firstModuleId !== 'number' || typeof lastModuleId !== 'number'; + let objectOverhead: number = 1; + let lastId: number = 0; + + if (!useObject) { + for (const id of modules) { + if (typeof id !== 'number') { + // This must be an object + useObject = true; + break; + } + + // This is the extension from webpack.Template.getModulesArrayBounds + // We can make smaller emit by injecting additional filler arrays + const delta: number = id - lastId - 1; + + // Compare the length of `],Array(${delta}),[` to ','.repeat(delta + 1) + const threshold: number = (lastId === 0 ? 7 : 11) + ('' + delta).length; + const fillerArraySavings: number = delta + 1 - threshold; + if (fillerArraySavings > 0) { + concatArrayOverhead -= fillerArraySavings; + } + + objectOverhead += 2 + ('' + id).length; + lastId = id; + } + } + + const useConcat: boolean = concatArrayOverhead < simpleArrayOverhead; + + const arrayOverhead: number = useConcat ? concatArrayOverhead : simpleArrayOverhead; + + useObject = useObject || objectOverhead < arrayOverhead; + + if (useObject) { + // Write an object literal + let separator: '{' | ',' = '{'; + for (const id of modules) { + // If the id is legal to use as a key in a JavaScript object literal, use as-is + const javascriptId: string | number = + typeof id !== 'string' || validIdRegex.test(id) ? id : JSON.stringify(id); + const currentSeparator: string = `${separator}${javascriptId}:`; + + source.add(currentSeparator); + charOffset += currentSeparator.length; + + separator = ','; + + const item: IModuleInfo | undefined = moduleMap.get(id); + const moduleCode: Source | string = item ? item.source : emptyFunction; + // Source.size() is in bytes, we want characters + const charLength: number = + typeof moduleCode === 'string' ? moduleCode.length : moduleCode.source().toString().length; + + if (emitRenderInfo) { + asset.renderInfo.set(id, { + charOffset, + charLength + }); + } + + source.add(moduleCode); + charOffset += charLength; + } + + source.add('}'); + } else { + // Write one or more array literals, joined by Array(gap) expressions + + // There will never be more than 16 + ("" + minId).length consecutive commas, so 40 is more than will ever be used + // This is because the above criteria triggers an Array(len) expression instead + const enoughCommas: string = ',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'; + + const useConcatAtStart: boolean = useConcat && minId > 8; + lastId = useConcatAtStart ? minId : 0; + // TODO: Just because we want to use concat elsewhere doesn't mean its optimal to use at the start + let separator: string = useConcatAtStart ? `Array(${minId}).concat([` : '['; + let concatInserted: boolean = useConcatAtStart; + for (const id of modules) { + const delta: number = (id as number) - lastId - 1; + const deltaStr: string = '' + delta; + const fillerArrayThreshold: number = 11 + deltaStr.length; + + const item: IModuleInfo | undefined = moduleMap.get(id); + const moduleCode: Source | string = item ? item.source : emptyFunction; + // Source.size() is in bytes, we want characters + const charLength: number = + typeof moduleCode === 'string' ? moduleCode.length : moduleCode.source().toString().length; + + if (useConcat && delta + 1 > fillerArrayThreshold) { + if (concatInserted) { + const currentSeparator: string = `],Array(${deltaStr}),[`; + + source.add(currentSeparator); + charOffset += currentSeparator.length; + } else { + const currentSeparator: string = `].concat(Array(${deltaStr}),[`; + concatInserted = true; + + source.add(currentSeparator); + charOffset += currentSeparator.length; + } + } else { + const currentSeparator: string = separator + enoughCommas.slice(0, delta + 1); + + source.add(currentSeparator); + charOffset += currentSeparator.length; + } + lastId = id as number; + + if (emitRenderInfo) { + asset.renderInfo.set(id, { + charOffset, + charLength + }); + } + + source.add(moduleCode); + charOffset += charLength; + + separator = ''; + } + + source.add(useConcat ? '])' : ']'); + } + + source.add(suffix); + + return handleExternals(new CachedSource(source), asset); +} + +function handleExternals(source: Source, asset: IAssetInfo): Source { + const { externalNames } = asset; + + if (externalNames.size) { + const replaceSource: ReplaceSource = new ReplaceSource(source); + const code: string = source.source() as string; + + const externalIdRegex: RegExp = /__WEBPACK_EXTERNAL_MODULE_[A-Za-z0-9_$]+/g; + + // RegExp.exec uses null or an array as the return type, explicitly + let match: RegExpExecArray | null = null; + while ((match = externalIdRegex.exec(code))) { + const id: string = match[0]; + const mapped: string | undefined = externalNames.get(id); + + if (mapped === undefined) { + // eslint-disable-next-line no-console + console.error(`Missing minified external for ${id} in ${asset.fileName}!`); + } else { + replaceSource.replace(match.index, externalIdRegex.lastIndex - 1, mapped); + } + } + + return new CachedSource(replaceSource); + } + + return source; +} diff --git a/webpack/webpack4-module-minifier-plugin/src/index.ts b/webpack/webpack4-module-minifier-plugin/src/index.ts new file mode 100644 index 00000000000..6c8c7a691cb --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/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. + +export * from './Constants'; +export * from './GenerateLicenseFileForAsset'; +export * from './ModuleMinifierPlugin.types'; +export * from './ModuleMinifierPlugin'; +export * from './PortableMinifierIdsPlugin'; +export * from './RehydrateAsset'; +export type { + ILocalMinifierOptions, + IMinifierConnection, + IModuleMinificationCallback, + IModuleMinificationErrorResult, + IModuleMinificationRequest, + IModuleMinificationResult, + IModuleMinificationSuccessResult, + IModuleMinifier, + IModuleMinifierFunction, + IWorkerPoolMinifierOptions +} from '@rushstack/module-minifier'; +export { + getIdentifier, + LocalMinifier, + MessagePortMinifier, + NoopMinifier, + WorkerPoolMinifier +} from '@rushstack/module-minifier'; diff --git a/webpack/webpack4-module-minifier-plugin/src/test/RehydrateAsset.test.ts b/webpack/webpack4-module-minifier-plugin/src/test/RehydrateAsset.test.ts new file mode 100644 index 00000000000..fb22925c267 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/test/RehydrateAsset.test.ts @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { RawSource } from 'webpack-sources'; +import { rehydrateAsset } from '../RehydrateAsset'; +import { CHUNK_MODULES_TOKEN } from '../Constants'; +import type { IAssetInfo, IModuleMap } from '../ModuleMinifierPlugin.types'; + +const modules: IModuleMap = new Map(); +modules.set('a', { + source: new RawSource('foo'), + module: undefined! +}); +modules.set('b', { + source: new RawSource('bar'), + module: undefined! +}); +modules.set('0b', { + source: new RawSource('baz'), + module: undefined! +}); +modules.set('=', { + source: new RawSource('bak'), + module: undefined! +}); +modules.set('a0', { + source: new RawSource('bal'), + module: undefined! +}); +modules.set(0, { + source: new RawSource('fizz'), + module: undefined! +}); +modules.set(2, { + source: new RawSource('buzz'), + module: undefined! +}); +modules.set(255, { + source: new RawSource('__WEBPACK_EXTERNAL_MODULE_fizz__'), + module: undefined! +}); +for (let i: number = 14; i < 30; i++) { + if (i !== 25) { + modules.set(i, { + source: new RawSource('bozz'), + module: undefined! + }); + } +} +modules.set(25, { + source: new RawSource('bang'), + module: undefined! +}); +for (let i: number = 1000; i < 1010; i++) { + modules.set(i, { + source: new RawSource(`b${i}`), + module: undefined! + }); +} + +const banner: string = `/* fnord */\n`; + +describe(rehydrateAsset.name, () => { + it('uses an object for non-numeric ids', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: ['a', 'b', '0b', '=', 'a0'], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner, true).source() as string; + const expected: string = `/* fnord */\n{a:foo,b:bar,"0b":baz,"=":bak,a0:bal}`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + expect(asset.renderInfo.size).toEqual(asset.modules.length); + for (const [id, { charOffset, charLength }] of asset.renderInfo) { + expect(result.slice(charOffset, charOffset + charLength)).toEqual(modules.get(id)!.source.source()); + } + }); + + it('uses an object for widely separated ids', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [0, 25], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner).source() as string; + const expected: string = `/* fnord */\n{0:fizz,25:bang}`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + }); + + it('uses a regular array for a couple missing leading elements', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [2], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner).source() as string; + const expected: string = `/* fnord */\n[,,buzz]`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + }); + + it('uses a regular array for several missing leading elements', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner).source() as string; + const expected: string = `/* fnord */\n[,,,,,,,,,,,,,,bozz,bozz,bozz,bozz,bozz,bozz,bozz,bozz,bozz,bozz,bozz,bang,bozz,bozz,bozz,bozz]`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + }); + + it('uses a concat array for a tight cluster of ids', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner).source() as string; + const expected: string = `/* fnord */\nArray(1000).concat([b1000,b1001,b1002,b1003,b1004,b1005,b1006,b1007,b1008,b1009])`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + }); + + it('uses a concat spacer for multiple tight clusters of ids', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [0, 2, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner, true).source() as string; + const expected: string = `/* fnord */\n[fizz,,buzz].concat(Array(997),[b1000,b1001,b1002,b1003,b1004,b1005,b1006,b1007,b1008,b1009])`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + expect(asset.renderInfo.size).toEqual(asset.modules.length); + for (const [id, { charOffset, charLength }] of asset.renderInfo) { + expect(result.slice(charOffset, charOffset + charLength)).toEqual(modules.get(id)!.source.source()); + } + }); + + it('supports a concat spacer and leading ids', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [2, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map() + }; + + const result: string = rehydrateAsset(asset, modules, banner, true).source() as string; + const expected: string = `/* fnord */\n[,,buzz].concat(Array(997),[b1000,b1001,b1002,b1003,b1004,b1005,b1006,b1007,b1008,b1009])`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + + expect(asset.renderInfo.size).toEqual(asset.modules.length); + for (const [id, { charOffset, charLength }] of asset.renderInfo) { + expect(result.slice(charOffset, charOffset + charLength)).toEqual(modules.get(id)!.source.source()); + } + }); + + it('reprocesses external names', () => { + const asset: IAssetInfo = { + source: new RawSource(`${CHUNK_MODULES_TOKEN}`), + modules: [255], + fileName: 'test', + renderInfo: new Map(), + chunk: undefined!, + externalNames: new Map([['__WEBPACK_EXTERNAL_MODULE_fizz__', 'TREBLE']]) + }; + + const result: string = rehydrateAsset(asset, modules, banner).source() as string; + const expected: string = `/* fnord */\n{255:TREBLE}`; + + if (result !== expected) { + throw new Error(`Expected ${expected} but received ${result}`); + } + }); +}); diff --git a/webpack/webpack4-module-minifier-plugin/src/workerPool/WebpackWorker.ts b/webpack/webpack4-module-minifier-plugin/src/workerPool/WebpackWorker.ts new file mode 100644 index 00000000000..6300e7a0895 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/src/workerPool/WebpackWorker.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 * as workerThreads from 'node:worker_threads'; + +import webpack = require('webpack'); + +import { MessagePortMinifier } from '@rushstack/module-minifier'; + +import { ModuleMinifierPlugin } from '../ModuleMinifierPlugin'; +import '../OverrideWebpackIdentifierAllocation'; + +// Hack to support mkdirp on node 10 +process.umask = () => 0; + +const { configFilePath, sourceMap, usePortableModules } = workerThreads.workerData; + +const webpackConfigs: webpack.Configuration[] = require(configFilePath); + +// chalk.enabled = enableColor; + +const minifier: MessagePortMinifier = new MessagePortMinifier(workerThreads.parentPort!); + +async function processTaskAsync(index: number): Promise { + const config: webpack.Configuration = webpackConfigs[index]; + // eslint-disable-next-line no-console + console.log(`Compiling config: ${config.name || (config.output && config.output.filename)}`); + + const optimization: webpack.Options.Optimization = config.optimization || (config.optimization = {}); + const { minimizer } = optimization; + + if (minimizer) { + for (const plugin of minimizer) { + if (plugin instanceof ModuleMinifierPlugin) { + plugin.minifier = minifier; + } + } + } else { + const { devtool, mode } = config; + + const finalSourceMap: boolean = + typeof sourceMap === 'boolean' + ? sourceMap + : typeof devtool === 'string' + ? devtool.endsWith('source-map') && !devtool.includes('eval') + : devtool !== false && mode === 'production'; + + optimization.minimizer = [ + new ModuleMinifierPlugin({ + minifier, + usePortableModules, + sourceMap: finalSourceMap + }) + ]; + } + + await new Promise((resolve: () => void, reject: (err: Error) => void) => { + const compiler: webpack.Compiler = webpack(config); + compiler.run(async (err: Error | undefined, stats: webpack.Stats) => { + if (err) { + return reject(err); + } + + if (stats && stats.hasErrors()) { + const errorStats: webpack.Stats.ToJsonOutput = stats.toJson('errors-only'); + + errorStats.errors.forEach((error) => { + // eslint-disable-next-line no-console + console.error(error); + }); + + return reject(new Error(`Webpack failed with ${errorStats.errors.length} error(s).`)); + } + + resolve(); + }); + }); +} + +process.exitCode = 3; + +workerThreads.parentPort!.on('message', (message: number | false | object) => { + // Termination request + if (message === false) { + process.exit(0); + } + + // Input for the MessagePortMinifier + if (typeof message === 'object') { + return; + } + + const index: number = message as number; + + processTaskAsync(index).then( + () => { + workerThreads.parentPort!.postMessage(index); + }, + (err: Error) => { + // eslint-disable-next-line no-console + console.error(err); + process.exit(1); + } + ); +}); diff --git a/webpack/webpack4-module-minifier-plugin/tsconfig.json b/webpack/webpack4-module-minifier-plugin/tsconfig.json new file mode 100644 index 00000000000..53cf9272654 --- /dev/null +++ b/webpack/webpack4-module-minifier-plugin/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019", + "noImplicitAny": false // Some typings are missing + } +} diff --git a/webpack/webpack5-load-themed-styles-loader/.npmignore b/webpack/webpack5-load-themed-styles-loader/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json new file mode 100644 index 00000000000..26fab7b16fb --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.json @@ -0,0 +1,3504 @@ +{ + "name": "@microsoft/webpack5-load-themed-styles-loader", + "entries": [ + { + "version": "0.3.7", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.21` to `2.1.22`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.20` to `2.1.21`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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 \"@microsoft/load-themed-styles\" from `^2.1.19` to `2.1.20`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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 \"@microsoft/load-themed-styles\" from `^2.1.18` to `2.1.19`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.17` to `2.1.18`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.16` to `2.1.17`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.3.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/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.15` to `2.1.16`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@microsoft/webpack5-load-themed-styles-loader_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 \"@microsoft/load-themed-styles\" to `2.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.14` to `2.1.15`" + } + ] + } + }, + { + "version": "0.2.110", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.110", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "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/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.13` to `2.1.14`" + } + ] + } + }, + { + "version": "0.2.109", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.109", + "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/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.12` to `2.1.13`" + } + ] + } + }, + { + "version": "0.2.108", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.108", + "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 \"@microsoft/load-themed-styles\" from `^2.1.11` to `2.1.12`" + } + ] + } + }, + { + "version": "0.2.107", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.107", + "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 \"@microsoft/load-themed-styles\" from `^2.1.10` to `2.1.11`" + } + ] + } + }, + { + "version": "0.2.106", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.106", + "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 \"@microsoft/load-themed-styles\" from `^2.1.9` to `2.1.10`" + } + ] + } + }, + { + "version": "0.2.105", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.105", + "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 \"@microsoft/load-themed-styles\" from `^2.1.8` to `2.1.9`" + } + ] + } + }, + { + "version": "0.2.104", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.104", + "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/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.7` to `2.1.8`" + } + ] + } + }, + { + "version": "0.2.103", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.103", + "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 \"@microsoft/load-themed-styles\" from `^2.1.6` to `2.1.7`" + } + ] + } + }, + { + "version": "0.2.102", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.102", + "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 \"@microsoft/load-themed-styles\" from `^2.1.5` to `2.1.6`" + } + ] + } + }, + { + "version": "0.2.101", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.101", + "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 \"@microsoft/load-themed-styles\" from `^2.1.4` to `2.1.5`" + } + ] + } + }, + { + "version": "0.2.100", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.100", + "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/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.1.3` to `2.1.4`" + } + ] + } + }, + { + "version": "0.2.99", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.99", + "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 \"@microsoft/load-themed-styles\" from `^2.1.2` to `2.1.3`" + } + ] + } + }, + { + "version": "0.2.98", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.98", + "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 \"@microsoft/load-themed-styles\" from `^2.1.1` to `2.1.2`" + } + ] + } + }, + { + "version": "0.2.97", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.97", + "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 \"@microsoft/load-themed-styles\" from `^2.1.0` to `2.1.1`" + } + ] + } + }, + { + "version": "0.2.96", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.96", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.171` to `2.1.0`" + } + ] + } + }, + { + "version": "0.2.95", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.95", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.171`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.170` to `2.0.171`" + } + ] + } + }, + { + "version": "0.2.94", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.94", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.170`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.169` to `2.0.170`" + } + ] + } + }, + { + "version": "0.2.93", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.93", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.169`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.168` to `2.0.169`" + } + ] + } + }, + { + "version": "0.2.92", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.92", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.168`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.167` to `2.0.168`" + } + ] + } + }, + { + "version": "0.2.91", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.91", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.167`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.166` to `2.0.167`" + } + ] + } + }, + { + "version": "0.2.90", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.90", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.166`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.165` to `2.0.166`" + } + ] + } + }, + { + "version": "0.2.89", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.89", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.165`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.164` to `2.0.165`" + } + ] + } + }, + { + "version": "0.2.88", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.164`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.163` to `2.0.164`" + } + ] + } + }, + { + "version": "0.2.87", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.163`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.162` to `2.0.163`" + } + ] + } + }, + { + "version": "0.2.86", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.86", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.162`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.161` to `2.0.162`" + } + ] + } + }, + { + "version": "0.2.85", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.161`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.160` to `2.0.161`" + } + ] + } + }, + { + "version": "0.2.84", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.160`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.159` to `2.0.160`" + } + ] + } + }, + { + "version": "0.2.83", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.83", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.159`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.158` to `2.0.159`" + } + ] + } + }, + { + "version": "0.2.82", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.158`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.157` to `2.0.158`" + } + ] + } + }, + { + "version": "0.2.81", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.81", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.157`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.156` to `2.0.157`" + } + ] + } + }, + { + "version": "0.2.80", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.80", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.156`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.155` to `2.0.156`" + } + ] + } + }, + { + "version": "0.2.79", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.155`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.154` to `2.0.155`" + } + ] + } + }, + { + "version": "0.2.78", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.78", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.154`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.153` to `2.0.154`" + } + ] + } + }, + { + "version": "0.2.77", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.77", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.153`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.152` to `2.0.153`" + } + ] + } + }, + { + "version": "0.2.76", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.76", + "date": "Tue, 03 Dec 2024 16:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.152`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.151` to `2.0.152`" + } + ] + } + }, + { + "version": "0.2.75", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.75", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.151`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.150` to `2.0.151`" + } + ] + } + }, + { + "version": "0.2.74", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.74", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.150`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.149` to `2.0.150`" + } + ] + } + }, + { + "version": "0.2.73", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.73", + "date": "Thu, 24 Oct 2024 00:15:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.149`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.148` to `2.0.149`" + } + ] + } + }, + { + "version": "0.2.72", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.72", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.148`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.147` to `2.0.148`" + } + ] + } + }, + { + "version": "0.2.71", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.71", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.147`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.146` to `2.0.147`" + } + ] + } + }, + { + "version": "0.2.70", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.70", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.146`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.145` to `2.0.146`" + } + ] + } + }, + { + "version": "0.2.69", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.69", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.145`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.144` to `2.0.145`" + } + ] + } + }, + { + "version": "0.2.68", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.68", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.144`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.143` to `2.0.144`" + } + ] + } + }, + { + "version": "0.2.67", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.67", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.143`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.142` to `2.0.143`" + } + ] + } + }, + { + "version": "0.2.66", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.66", + "date": "Fri, 13 Sep 2024 00:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.142`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.141` to `2.0.142`" + } + ] + } + }, + { + "version": "0.2.65", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.65", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.141`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.140` to `2.0.141`" + } + ] + } + }, + { + "version": "0.2.64", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.64", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.140`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.139` to `2.0.140`" + } + ] + } + }, + { + "version": "0.2.63", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.63", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.139`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.138` to `2.0.139`" + } + ] + } + }, + { + "version": "0.2.62", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.62", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.138`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.137` to `2.0.138`" + } + ] + } + }, + { + "version": "0.2.61", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.61", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.137`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.136` to `2.0.137`" + } + ] + } + }, + { + "version": "0.2.60", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.60", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.136`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.135` to `2.0.136`" + } + ] + } + }, + { + "version": "0.2.59", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.59", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.135`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.134` to `2.0.135`" + } + ] + } + }, + { + "version": "0.2.58", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.58", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.134`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.133` to `2.0.134`" + } + ] + } + }, + { + "version": "0.2.57", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.57", + "date": "Tue, 16 Jul 2024 00:36:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.133`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.132` to `2.0.133`" + } + ] + } + }, + { + "version": "0.2.56", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.56", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.132`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.131` to `2.0.132`" + } + ] + } + }, + { + "version": "0.2.55", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.55", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.131`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.130` to `2.0.131`" + } + ] + } + }, + { + "version": "0.2.54", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.54", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.130`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.129` to `2.0.130`" + } + ] + } + }, + { + "version": "0.2.53", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.53", + "date": "Wed, 29 May 2024 02:03:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.129`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.128` to `2.0.129`" + } + ] + } + }, + { + "version": "0.2.52", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.52", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.128`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.127` to `2.0.128`" + } + ] + } + }, + { + "version": "0.2.51", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.51", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.127`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.126` to `2.0.127`" + } + ] + } + }, + { + "version": "0.2.50", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.50", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.126`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.125` to `2.0.126`" + } + ] + } + }, + { + "version": "0.2.49", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.49", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.125`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.124` to `2.0.125`" + } + ] + } + }, + { + "version": "0.2.48", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.48", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.124`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.123` to `2.0.124`" + } + ] + } + }, + { + "version": "0.2.47", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.47", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.123`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.122` to `2.0.123`" + } + ] + } + }, + { + "version": "0.2.46", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.46", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.122`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.121` to `2.0.122`" + } + ] + } + }, + { + "version": "0.2.45", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.45", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.121`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.120` to `2.0.121`" + } + ] + } + }, + { + "version": "0.2.44", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.44", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.120`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.119` to `2.0.120`" + } + ] + } + }, + { + "version": "0.2.43", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.43", + "date": "Fri, 10 May 2024 05:33:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.119`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.118` to `2.0.119`" + } + ] + } + }, + { + "version": "0.2.42", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.42", + "date": "Wed, 08 May 2024 22:23:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.118`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.117` to `2.0.118`" + } + ] + } + }, + { + "version": "0.2.41", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.41", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.117`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.116` to `2.0.117`" + } + ] + } + }, + { + "version": "0.2.40", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.40", + "date": "Wed, 10 Apr 2024 15:10:08 GMT", + "comments": { + "none": [ + { + "comment": "Update test snapshots for subspace" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.116`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.115` to `2.0.116`" + } + ] + } + }, + { + "version": "0.2.39", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.39", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.115`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.114` to `2.0.115`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.114`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.113` to `2.0.114`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.113`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.112` to `2.0.113`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.112`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.111` to `2.0.112`" + } + ] + } + }, + { + "version": "0.2.35", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.111`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.110` to `2.0.111`" + } + ] + } + }, + { + "version": "0.2.34", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.109` to `2.0.110`" + } + ] + } + }, + { + "version": "0.2.33", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.33", + "date": "Thu, 29 Feb 2024 07:11:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.108` to `2.0.109`" + } + ] + } + }, + { + "version": "0.2.32", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.108`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.107` to `2.0.108`" + } + ] + } + }, + { + "version": "0.2.31", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.107`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.106` to `^2.0.107`" + } + ] + } + }, + { + "version": "0.2.30", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.106`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.105` to `^2.0.106`" + } + ] + } + }, + { + "version": "0.2.29", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.105`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.104` to `^2.0.105`" + } + ] + } + }, + { + "version": "0.2.28", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.103` to `^2.0.104`" + } + ] + } + }, + { + "version": "0.2.27", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.103`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.102` to `^2.0.103`" + } + ] + } + }, + { + "version": "0.2.26", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.26", + "date": "Tue, 20 Feb 2024 16:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.102`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.101` to `^2.0.102`" + } + ] + } + }, + { + "version": "0.2.25", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.101`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.100` to `^2.0.101`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.100`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.99` to `^2.0.100`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.99`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.98` to `^2.0.99`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.98`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.97` to `^2.0.98`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.97`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.96` to `^2.0.97`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.96`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.95` to `^2.0.96`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.19", + "date": "Tue, 23 Jan 2024 20:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.95`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.94` to `^2.0.95`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.18", + "date": "Tue, 23 Jan 2024 16:15:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.93` to `^2.0.94`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.92` to `^2.0.93`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.91` to `^2.0.92`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.15", + "date": "Wed, 20 Dec 2023 01:09:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.90` to `^2.0.91`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.89` to `^2.0.90`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.88` to `^2.0.89`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.87` to `^2.0.88`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.11", + "date": "Wed, 01 Nov 2023 23:11:35 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.86` to `^2.0.87`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.85` to `^2.0.86`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.9", + "date": "Sun, 01 Oct 2023 02:56:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.84` to `^2.0.85`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.83` to `^2.0.84`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.82` to `^2.0.83`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.81` to `^2.0.82`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.80` to `^2.0.81`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.79` to `^2.0.80`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.78` to `^2.0.79`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.2", + "date": "Fri, 22 Sep 2023 00:05:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.77` to `^2.0.78`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.76` to `^2.0.77`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.2.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.76`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.75` to `^2.0.76`" + } + ] + } + }, + { + "version": "0.1.57", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.57", + "date": "Wed, 13 Sep 2023 00:32:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.75`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.74` to `^2.0.75`" + } + ] + } + }, + { + "version": "0.1.56", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.56", + "date": "Fri, 01 Sep 2023 04:53:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.74`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.73` to `^2.0.74`" + } + ] + } + }, + { + "version": "0.1.55", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.55", + "date": "Tue, 08 Aug 2023 07:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.73`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.72` to `^2.0.73`" + } + ] + } + }, + { + "version": "0.1.54", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.54", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.72`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.71` to `^2.0.72`" + } + ] + } + }, + { + "version": "0.1.53", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.53", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.71`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.70` to `^2.0.71`" + } + ] + } + }, + { + "version": "0.1.52", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.52", + "date": "Mon, 31 Jul 2023 15:19:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.69` to `^2.0.70`" + } + ] + } + }, + { + "version": "0.1.51", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.51", + "date": "Sat, 29 Jul 2023 00:22:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.68` to `^2.0.69`" + } + ] + } + }, + { + "version": "0.1.50", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.50", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.67` to `^2.0.68`" + } + ] + } + }, + { + "version": "0.1.49", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.49", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.66` to `^2.0.67`" + } + ] + } + }, + { + "version": "0.1.48", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.48", + "date": "Mon, 17 Jul 2023 15:20:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.66`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.65` to `^2.0.66`" + } + ] + } + }, + { + "version": "0.1.47", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.47", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.64` to `^2.0.65`" + } + ] + } + }, + { + "version": "0.1.46", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.46", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.63` to `^2.0.64`" + } + ] + } + }, + { + "version": "0.1.45", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.45", + "date": "Wed, 12 Jul 2023 15:20:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.62` to `^2.0.63`" + } + ] + } + }, + { + "version": "0.1.44", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.44", + "date": "Wed, 12 Jul 2023 00:23:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.61` to `^2.0.62`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.43", + "date": "Fri, 07 Jul 2023 00:19:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.60` to `^2.0.61`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.42", + "date": "Thu, 06 Jul 2023 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.59` to `^2.0.60`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.41", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.58` to `^2.0.59`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.40", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.57` to `^2.0.58`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.39", + "date": "Thu, 15 Jun 2023 00:21:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.57`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.56` to `^2.0.57`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.38", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.55` to `^2.0.56`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.37", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.54` to `^2.0.55`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.36", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.53` to `^2.0.54`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.35", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.52` to `^2.0.53`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.34", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.51` to `^2.0.52`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.33", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.50` to `^2.0.51`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.32", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.49` to `^2.0.50`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.31", + "date": "Thu, 08 Jun 2023 00:20:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.48` to `^2.0.49`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.30", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.48`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.47` to `^2.0.48`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.29", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.46` to `^2.0.47`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.28", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.45` to `^2.0.46`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.27", + "date": "Fri, 02 Jun 2023 02:01:12 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.44` to `^2.0.45`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.26", + "date": "Fri, 02 Jun 2023 00:24:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.44`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.43` to `^2.0.44`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.25", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.42` to `^2.0.43`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.24", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.42`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.41` to `^2.0.42`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.23", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.40` to `^2.0.41`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.22", + "date": "Thu, 11 May 2023 00:17:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.40`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.39` to `^2.0.40`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.21", + "date": "Thu, 04 May 2023 00:20:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.38` to `^2.0.39`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.20", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.37` to `^2.0.38`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.19", + "date": "Sat, 29 Apr 2023 00:23:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.36` to `^2.0.37`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.18", + "date": "Thu, 27 Apr 2023 17:18:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.35` to `^2.0.36`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.17", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.35`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.34` to `^2.0.35`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.16", + "date": "Tue, 11 Apr 2023 00:23:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.34`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.33` to `^2.0.34`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.15", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.33`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.32` to `^2.0.33`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.14", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.31` to `^2.0.32`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.13", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.30` to `^2.0.31`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.12", + "date": "Sat, 11 Mar 2023 01:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.30`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.29` to `^2.0.30`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.11", + "date": "Fri, 10 Feb 2023 01:18:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.29`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.28` to `^2.0.29`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.10", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.27` to `^2.0.28`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.9", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.26` to `^2.0.27`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.8", + "date": "Tue, 31 Jan 2023 01:23:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.26`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.25` to `^2.0.26`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.7", + "date": "Mon, 30 Jan 2023 16:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.24` to `^2.0.25`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.6", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.23` to `^2.0.24`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.5", + "date": "Thu, 26 Jan 2023 02:55:09 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.22` to `^2.0.23`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.4", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.21` to `^2.0.22`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.3", + "date": "Sun, 22 Jan 2023 20:37:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.21`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.20` to `^2.0.21`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.2", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.0.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" from `^2.0.19` to `^2.0.20`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.1", + "date": "Wed, 11 Jan 2023 05:17:04 GMT", + "comments": { + "patch": [ + { + "comment": "Make webpack@5 an optional peer dependency." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@microsoft/webpack5-load-themed-styles-loader_v0.1.0", + "date": "Wed, 11 Jan 2023 04:07:28 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce webpack5-loader-load-themed-styles" + } + ] + } + } + ] +} diff --git a/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md new file mode 100644 index 00000000000..fa94498e8e9 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/CHANGELOG.md @@ -0,0 +1,911 @@ +# Change Log - @microsoft/webpack5-load-themed-styles-loader + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 0.3.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.3.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.3.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.3.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 0.3.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.3.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 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.110 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.2.109 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.108 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.107 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.106 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.2.105 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.2.104 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.2.103 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.2.102 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.2.101 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.2.100 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.2.99 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.2.98 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.2.97 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.2.96 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.2.95 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.2.94 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.2.93 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.2.92 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.2.91 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.2.90 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.2.89 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.2.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.2.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.2.86 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.2.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.2.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.2.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.2.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.2.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.2.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.2.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.2.78 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.2.77 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.2.76 +Tue, 03 Dec 2024 16:11:07 GMT + +_Version update only_ + +## 0.2.75 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.2.74 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.2.73 +Thu, 24 Oct 2024 00:15:47 GMT + +_Version update only_ + +## 0.2.72 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.2.71 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.2.70 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.2.69 +Wed, 02 Oct 2024 00:11:19 GMT + +_Version update only_ + +## 0.2.68 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.2.67 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.2.66 +Fri, 13 Sep 2024 00:11:42 GMT + +_Version update only_ + +## 0.2.65 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.2.64 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.2.63 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.2.62 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.2.61 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.2.60 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.2.59 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.2.58 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.2.57 +Tue, 16 Jul 2024 00:36:21 GMT + +_Version update only_ + +## 0.2.56 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.2.55 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.2.54 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 0.2.53 +Wed, 29 May 2024 02:03:50 GMT + +_Version update only_ + +## 0.2.52 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.2.51 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.2.50 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.2.49 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.2.48 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 0.2.47 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.2.46 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.2.45 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.2.44 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.2.43 +Fri, 10 May 2024 05:33:33 GMT + +_Version update only_ + +## 0.2.42 +Wed, 08 May 2024 22:23:50 GMT + +_Version update only_ + +## 0.2.41 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.2.40 +Wed, 10 Apr 2024 15:10:08 GMT + +_Version update only_ + +## 0.2.39 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.2.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.2.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.2.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.2.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.2.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.2.33 +Thu, 29 Feb 2024 07:11:45 GMT + +_Version update only_ + +## 0.2.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.2.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.2.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.2.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.2.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.2.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.2.26 +Tue, 20 Feb 2024 16:10:52 GMT + +_Version update only_ + +## 0.2.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 0.2.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.2.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.2.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.2.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 0.2.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.2.19 +Tue, 23 Jan 2024 20:12:57 GMT + +_Version update only_ + +## 0.2.18 +Tue, 23 Jan 2024 16:15:05 GMT + +_Version update only_ + +## 0.2.17 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.2.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.2.15 +Wed, 20 Dec 2023 01:09:45 GMT + +_Version update only_ + +## 0.2.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.2.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.2.11 +Wed, 01 Nov 2023 23:11:35 GMT + +### Patches + +- Fix line endings in published package. + +## 0.2.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 0.2.9 +Sun, 01 Oct 2023 02:56:29 GMT + +_Version update only_ + +## 0.2.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.2.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.2.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.2.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.2.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.2.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.2.2 +Fri, 22 Sep 2023 00:05:50 GMT + +_Version update only_ + +## 0.2.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.2.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.1.57 +Wed, 13 Sep 2023 00:32:29 GMT + +_Version update only_ + +## 0.1.56 +Fri, 01 Sep 2023 04:53:58 GMT + +_Version update only_ + +## 0.1.55 +Tue, 08 Aug 2023 07:10:39 GMT + +_Version update only_ + +## 0.1.54 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.1.53 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.52 +Mon, 31 Jul 2023 15:19:05 GMT + +_Version update only_ + +## 0.1.51 +Sat, 29 Jul 2023 00:22:50 GMT + +_Version update only_ + +## 0.1.50 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.1.49 +Wed, 19 Jul 2023 00:20:31 GMT + +_Version update only_ + +## 0.1.48 +Mon, 17 Jul 2023 15:20:25 GMT + +_Version update only_ + +## 0.1.47 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.1.46 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.1.45 +Wed, 12 Jul 2023 15:20:39 GMT + +_Version update only_ + +## 0.1.44 +Wed, 12 Jul 2023 00:23:29 GMT + +_Version update only_ + +## 0.1.43 +Fri, 07 Jul 2023 00:19:32 GMT + +_Version update only_ + +## 0.1.42 +Thu, 06 Jul 2023 00:16:19 GMT + +_Version update only_ + +## 0.1.41 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.1.40 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.1.39 +Thu, 15 Jun 2023 00:21:01 GMT + +_Version update only_ + +## 0.1.38 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.1.37 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.1.36 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.1.35 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.1.34 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.1.33 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.1.32 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.1.31 +Thu, 08 Jun 2023 00:20:02 GMT + +_Version update only_ + +## 0.1.30 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.1.29 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.1.28 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.1.27 +Fri, 02 Jun 2023 02:01:12 GMT + +_Version update only_ + +## 0.1.26 +Fri, 02 Jun 2023 00:24:45 GMT + +_Version update only_ + +## 0.1.25 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.1.24 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.1.23 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.1.22 +Thu, 11 May 2023 00:17:21 GMT + +_Version update only_ + +## 0.1.21 +Thu, 04 May 2023 00:20:28 GMT + +_Version update only_ + +## 0.1.20 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.1.19 +Sat, 29 Apr 2023 00:23:02 GMT + +_Version update only_ + +## 0.1.18 +Thu, 27 Apr 2023 17:18:42 GMT + +_Version update only_ + +## 0.1.17 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.1.16 +Tue, 11 Apr 2023 00:23:22 GMT + +_Version update only_ + +## 0.1.15 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.1.14 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.1.13 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.1.12 +Sat, 11 Mar 2023 01:24:51 GMT + +_Version update only_ + +## 0.1.11 +Fri, 10 Feb 2023 01:18:50 GMT + +_Version update only_ + +## 0.1.10 +Sun, 05 Feb 2023 03:02:02 GMT + +_Version update only_ + +## 0.1.9 +Wed, 01 Feb 2023 02:16:34 GMT + +_Version update only_ + +## 0.1.8 +Tue, 31 Jan 2023 01:23:24 GMT + +_Version update only_ + +## 0.1.7 +Mon, 30 Jan 2023 16:22:31 GMT + +_Version update only_ + +## 0.1.6 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.1.5 +Thu, 26 Jan 2023 02:55:09 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.1.4 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.1.3 +Sun, 22 Jan 2023 20:37:08 GMT + +_Version update only_ + +## 0.1.2 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.1.1 +Wed, 11 Jan 2023 05:17:04 GMT + +### Patches + +- Make webpack@5 an optional peer dependency. + +## 0.1.0 +Wed, 11 Jan 2023 04:07:28 GMT + +### Minor changes + +- Introduce webpack5-loader-load-themed-styles + diff --git a/webpack/webpack5-load-themed-styles-loader/LICENSE b/webpack/webpack5-load-themed-styles-loader/LICENSE new file mode 100644 index 00000000000..4f8b11c1aff --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/LICENSE @@ -0,0 +1,24 @@ +@microsoft/webpack5-load-themed-styles-loader + +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/webpack/webpack5-load-themed-styles-loader/README.md b/webpack/webpack5-load-themed-styles-loader/README.md new file mode 100644 index 00000000000..df101db8253 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/README.md @@ -0,0 +1,76 @@ +# @microsoft/webpack5-load-themed-styles-loader + +## Installation + +`npm install @microsoft/webpack5-load-themed-styles-loader --save-dev` + +## Overview + +This simple Webpack loader that wraps the loading of CSS in script equivalent +to `require("@microsoft/load-themed-styles").loadStyles( /* css text */ )`. +It is designed to be a replacement for style-loader. + +## Usage + +[Documentation: Using loaders](http://webpack.github.io/docs/using-loaders.html) + +This loader is designed to be used in conjunction with css-loader. + +``` javascript +var css = require("@microsoft/webpack5-load-themed-styles-loader!css!./file.css"); +// => returns css code from file.css, uses load-themed-styles to load the CSS on the page. +``` + +### Example config + +``` javascript + use: [ + { + loader: "@microsoft/webpack5-load-themed-styles-loader", // creates style nodes from JS strings + options: { + async: false + } + }, + { + loader: "css-loader", // translates CSS into CommonJS + options: { + modules: true, + importLoaders: 2, + localIdentName: '[name]_[local]_[hash:base64:5]', + minimize: false + } + }, + { + loader: 'postcss-loader', + options: { + plugins: function () { + return [ + require('autoprefixer') + ]; + } + } + }, + { + loader: "sass-loader", + } + ] + +``` + +## Options + +### `async` (boolean, defaults to `false`) + +By default, `@microsoft/load-themed-styles` loads styles synchronously. This can have adverse performance effects +if many styles are loaded in quick succession. If the `async` option is set to `true`, the `loadStyles` function +is called with the second parameter set to `true`, directing the function to debounce style loading causing fewer +changes to the DOM. + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/webpack5-loader-load-themed-styles/CHANGELOG.md) - Find + out what's new in the latest version + +`@microsoft/webpack5-load-themed-styles-loader` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/core-build/gulp-core-build-mocha/config/api-extractor.json b/webpack/webpack5-load-themed-styles-loader/config/api-extractor.json similarity index 100% rename from core-build/gulp-core-build-mocha/config/api-extractor.json rename to webpack/webpack5-load-themed-styles-loader/config/api-extractor.json diff --git a/webpack/webpack5-load-themed-styles-loader/config/jest.config.json b/webpack/webpack5-load-themed-styles-loader/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/webpack5-load-themed-styles-loader/config/rig.json b/webpack/webpack5-load-themed-styles-loader/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/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/webpack/webpack5-load-themed-styles-loader/config/typescript.json b/webpack/webpack5-load-themed-styles-loader/config/typescript.json new file mode 100644 index 00000000000..50a643ff0da --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/config/typescript.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "extends": "local-node-rig/profiles/default/config/typescript.json", + "staticAssetsToCopy": { + "fileExtensions": [".css"] + } +} diff --git a/webpack/webpack5-load-themed-styles-loader/eslint.config.js b/webpack/webpack5-load-themed-styles-loader/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/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/webpack/webpack5-load-themed-styles-loader/package.json b/webpack/webpack5-load-themed-styles-loader/package.json new file mode 100644 index 00000000000..3e4b22a2a67 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/package.json @@ -0,0 +1,37 @@ +{ + "name": "@microsoft/webpack5-load-themed-styles-loader", + "version": "0.3.7", + "description": "This simple loader wraps the loading of CSS in script equivalent to `require('load-themed-styles').loadStyles( /* css text */ )`. It is designed to be a replacement for style-loader.", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack5-loader-load-themed-styles" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@microsoft/load-themed-styles": "^2.1.22", + "webpack": "^5" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + }, + "devDependencies": { + "@microsoft/load-themed-styles": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "css-loader": "~6.6.0", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" + } +} diff --git a/webpack/webpack5-load-themed-styles-loader/src/index.ts b/webpack/webpack5-load-themed-styles-loader/src/index.ts new file mode 100644 index 00000000000..08bd5d8a668 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/index.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. + +/** + * This simple loader wraps the loading of CSS in script equivalent to + * require("\@microsoft/load-themed-styles").loadStyles('... css text ...'). + * @packageDocumentation + */ + +import type { LoaderContext, PitchLoaderDefinitionFunction } from 'webpack'; + +const defaultThemedStylesPath: string = require.resolve('@microsoft/load-themed-styles'); + +/** + * Options for the loader. + * + * @public + */ +export interface ILoadThemedStylesLoaderOptions { + /** + * If this parameter is set to "true," the "loadAsync" parameter is set to true in the call to loadStyles. + * Defaults to false. + */ + async?: boolean; + loadThemedStylesPath?: string; + esModule?: boolean; +} + +/** + * This simple loader wraps the loading of CSS in script equivalent to + * require("load-themed-styles").loadStyles('... css text ...'). + * + * @public + */ + +// eslint-disable-next-line func-style +export const pitch: PitchLoaderDefinitionFunction = function ( + this: LoaderContext, + remainingRequest: string +): string { + const loaderContext: LoaderContext = this; + const options: ILoadThemedStylesLoaderOptions = loaderContext.getOptions() || {}; + if ((options as Record).namedExport) { + throw new Error('The "namedExport" option has been removed.'); + } + + const { async = false, loadThemedStylesPath = defaultThemedStylesPath, esModule = false } = options; + const stringifiedRequest: string = JSON.stringify( + loaderContext.utils.contextify(loaderContext.context, '!!' + remainingRequest) + ); + + const importCode: [contentImport: string, loaderImport: string] = esModule + ? [ + `import content from ${stringifiedRequest};`, + `import { loadStyles } from ${JSON.stringify(loadThemedStylesPath)};` + ] + : [ + `var content = require(${stringifiedRequest});`, + `var loader = require(${JSON.stringify(loadThemedStylesPath)});` + ]; + + return [ + ...importCode, + '', + 'if(typeof content === "string") content = [[module.id, content]];', + '', + '// add the styles to the DOM', + `for (var i = 0; i < content.length; i++) ${ + esModule ? 'loadStyles' : 'loader.loadStyles' + }(content[i][1], ${async === true});`, + '', + 'if(content.locals) module.exports = content.locals;' + ].join('\n'); +}; diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/LoadThemedStylesLoader.test.ts b/webpack/webpack5-load-themed-styles-loader/src/test/LoadThemedStylesLoader.test.ts new file mode 100644 index 00000000000..13fc998b7dc --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/LoadThemedStylesLoader.test.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 * as loader from '..'; +import type { Stats } from 'webpack'; +import LoadThemedStylesMock = require('./testData/LoadThemedStylesMock'); +import getCompiler from './testData/getCompiler'; + +const MATCH_GENERATED_LOADER_STRING_REGEXP: RegExp = /var\sloader\s\=\srequire\(["'](.+?)["']\)/; +const MATCH_LOADER_DOT_LOADSTYLES_FUNCTION_ASYNC_VALUE_REGEXP: RegExp = /loader\.loadStyles\(.+?,\s(.+?)\)/; + +// During a parallel build, getCompiler() can sometimes exceed Jest's default timeout of 5 seconds +jest.setTimeout(10 * 1000); // 10 seconds + +describe('webpack5-load-themed-style-loader', () => { + beforeEach(() => { + LoadThemedStylesMock.loadedData = []; + LoadThemedStylesMock.calledWithAsync = []; + }); + + it('follows the Webpack loader interface', () => { + expect(loader.pitch).toBeDefined(); + }); + + it('it inserts the resolved load-themed-styles path', async () => { + const stats: Stats | undefined = await getCompiler('./MockStyle1.css'); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + const match = MATCH_GENERATED_LOADER_STRING_REGEXP.exec(content as string); + // Since this pattern matches source code, on Windows directory separators will be + // '\\', which will have been JSON-escaped. + const loadThemedStylesLibPath = JSON.parse(`"${match?.[1]}"`); + const expectedPath: string = require.resolve('@microsoft/load-themed-styles'); + + expect(loadThemedStylesLibPath).toEqual(expectedPath); + }); + + it('it allows for and inserts override of load-themed-styles path', async () => { + // It would error when I attempt to use the .ts mock in src/test/testData + // beacuse I'm not setting up default support for webpack to load .ts files. + const expectedPath: string = '../../../lib/test/testData/LoadThemedStylesMock'; + const stats = await getCompiler('./MockStyle1.css', { loadThemedStylesPath: expectedPath }); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + const match = MATCH_GENERATED_LOADER_STRING_REGEXP.exec(content as string); + const loadThemedStylesLibPath = match?.[1]; + + expect(loadThemedStylesLibPath).toEqual(expectedPath); + }); + + it('correctly handles the async option set to "false"', async () => { + const stats = await getCompiler('./MockStyle1.css', { async: false }); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + const match = MATCH_LOADER_DOT_LOADSTYLES_FUNCTION_ASYNC_VALUE_REGEXP.exec(content as string); + const asyncValue = match?.[1]; + + expect(asyncValue).toEqual('false'); + }); + + it('correctly handles and detects the async option not being set', async () => { + const stats = await getCompiler('./MockStyle1.css'); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + const match = MATCH_LOADER_DOT_LOADSTYLES_FUNCTION_ASYNC_VALUE_REGEXP.exec(content as string); + const asyncValue = match?.[1]; + + expect(asyncValue).toEqual('false'); + }); + + it('correctly handles the async option set to "true"', async () => { + const stats = await getCompiler('./MockStyle1.css', { async: true }); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + const match = MATCH_LOADER_DOT_LOADSTYLES_FUNCTION_ASYNC_VALUE_REGEXP.exec(content as string); + const asyncValue = match?.[1]; + + expect(asyncValue).toEqual('true'); + }); + + it('generates desired output for esModule option set to "true" as a snapshot', async () => { + // We mock the path of the loader because the full resolved path can change between machines + // IE: Different folder topology, etc. So we just used the mocked module and set it + // to loadThemedStylesPath option from the loader. + const expectedPath: string = '../../../lib/test/testData/LoadThemedStylesMock'; + const stats = await getCompiler('./MockStyle1.css', { + loadThemedStylesPath: expectedPath, + esModule: true + }); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + + expect(content).toMatchSnapshot('LoaderContent ESModule'); + }); + + it('generates desired loader output snapshot', async () => { + const expectedPath: string = '../../../lib/test/testData/LoadThemedStylesMock'; + const stats = await getCompiler('./MockStyle1.css', { loadThemedStylesPath: expectedPath }); + if (!stats) { + throw new Error(`Expected stats`); + } + const content = stats.toJson({ source: true }).modules?.[0].source; + + expect(content).toMatchSnapshot('LoaderContent'); + }); +}); diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/__snapshots__/LoadThemedStylesLoader.test.ts.snap b/webpack/webpack5-load-themed-styles-loader/src/test/__snapshots__/LoadThemedStylesLoader.test.ts.snap new file mode 100644 index 00000000000..00fc1e699e8 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/__snapshots__/LoadThemedStylesLoader.test.ts.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`webpack5-load-themed-style-loader generates desired loader output snapshot: LoaderContent 1`] = ` +"var content = require(\\"!!../../../../../common/temp/default/node_modules/.pnpm/css-loader@6.6.0_webpack@5.98.0/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[0].use[1]!./MockStyle1.css\\"); +var loader = require(\\"../../../lib/test/testData/LoadThemedStylesMock\\"); + +if(typeof content === \\"string\\") content = [[module.id, content]]; + +// add the styles to the DOM +for (var i = 0; i < content.length; i++) loader.loadStyles(content[i][1], false); + +if(content.locals) module.exports = content.locals;" +`; + +exports[`webpack5-load-themed-style-loader generates desired output for esModule option set to "true" as a snapshot: LoaderContent ESModule 1`] = ` +"import content from \\"!!../../../../../common/temp/default/node_modules/.pnpm/css-loader@6.6.0_webpack@5.98.0/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[0].use[1]!./MockStyle1.css\\"; +import { loadStyles } from \\"../../../lib/test/testData/LoadThemedStylesMock\\"; + +if(typeof content === \\"string\\") content = [[module.id, content]]; + +// add the styles to the DOM +for (var i = 0; i < content.length; i++) loadStyles(content[i][1], false); + +if(content.locals) module.exports = content.locals;" +`; diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/testData/LoadThemedStylesMock.ts b/webpack/webpack5-load-themed-styles-loader/src/test/testData/LoadThemedStylesMock.ts new file mode 100644 index 00000000000..dad48dba6ea --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/testData/LoadThemedStylesMock.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. + +class LoadThemedStylesMock { + public static loadedData: string[] = []; + public static calledWithAsync: boolean[] = []; + + public static loadStyles(data: string, async: boolean): void { + this.loadedData.push(data); + this.calledWithAsync.push(async); + } +} + +export = LoadThemedStylesMock; diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.css b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.css new file mode 100644 index 00000000000..826dfebd3c4 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.css @@ -0,0 +1,3 @@ +body { + background: '[theme:primaryBackgroundColor, default: #FFAAFA]'; +} diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.ts b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.ts new file mode 100644 index 00000000000..ba41d0cd42a --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle1.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 './MockStyle1.css'; +import { loadTheme } from '@microsoft/load-themed-styles'; + +loadTheme({ + primaryBackgroundColor: '#EAEAEA' +}); diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle2.ts b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle2.ts new file mode 100644 index 00000000000..696f937e094 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/testData/MockStyle2.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 = 'styles'; diff --git a/webpack/webpack5-load-themed-styles-loader/src/test/testData/getCompiler.ts b/webpack/webpack5-load-themed-styles-loader/src/test/testData/getCompiler.ts new file mode 100644 index 00000000000..595310b824d --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/src/test/testData/getCompiler.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 path from 'node:path'; +import webpack from 'webpack'; +import type { Compiler, OutputFileSystem, Stats } from 'webpack'; +import { Volume } from 'memfs'; +import type { ILoadThemedStylesLoaderOptions } from '../../index.js'; + +// webpack5-loader-load-themed-styles/lib/LoadThemedStylesLoader.js +const LOADER_PATH: string = path.resolve(__dirname, '../../index.js'); + +export default function getCompiler( + fixture: string, + options: ILoadThemedStylesLoaderOptions = {} +): Promise { + const compiler: Compiler = webpack({ + context: __dirname, + entry: `./${fixture}`, + output: { + path: path.resolve(__dirname), + filename: 'bundle.js' + }, + mode: 'none', + module: { + rules: [ + { + test: /\.css$/, + use: [ + { + loader: LOADER_PATH, + options: options + }, + { + loader: 'css-loader', + options: { + modules: true + } + } + ] + } + ] + } + }); + + compiler.outputFileSystem = new Volume() as unknown as OutputFileSystem; + compiler.outputFileSystem.join = path.join.bind(path); + + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) reject(err); + if (stats?.hasErrors()) reject(stats?.toJson().errors); + + resolve(stats); + }); + }); +} diff --git a/webpack/webpack5-load-themed-styles-loader/tsconfig.json b/webpack/webpack5-load-themed-styles-loader/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/webpack/webpack5-load-themed-styles-loader/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/webpack/webpack5-localization-plugin/.npmignore b/webpack/webpack5-localization-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack5-localization-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack5-localization-plugin/CHANGELOG.json b/webpack/webpack5-localization-plugin/CHANGELOG.json new file mode 100644 index 00000000000..7b0c6558f0d --- /dev/null +++ b/webpack/webpack5-localization-plugin/CHANGELOG.json @@ -0,0 +1,3968 @@ +{ + "name": "@rushstack/webpack5-localization-plugin", + "entries": [ + { + "version": "0.15.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.7", + "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/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": "0.15.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.6", + "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/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": "0.15.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.5", + "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`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.3", + "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/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": "0.15.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.2", + "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/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": "0.15.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.1", + "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/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": "0.15.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.15.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/localization-utilities\" to `0.14.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`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.7", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.23`" + }, + { + "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": "0.14.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.6", + "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/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": "0.14.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.5", + "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`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.4", + "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/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.3", + "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`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.2", + "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`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.1", + "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/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": "0.14.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.14.0", + "date": "Mon, 30 Jun 2025 22:04:32 GMT", + "comments": { + "minor": [ + { + "comment": "Add a feature for injecting custom localized values into a compilation via the `getCustomDataPlaceholderForValueFunction` function on an instance of the `LocalizationPlugin`." + } + ] + } + }, + { + "version": "0.13.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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/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": "0.13.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.9", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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/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": "0.13.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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/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": "0.13.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.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`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.13.0", + "date": "Thu, 27 Feb 2025 16:10:47 GMT", + "comments": { + "minor": [ + { + "comment": "Support passing the `ignoreString` option to all loaders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.6", + "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`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.5", + "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`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.4", + "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`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.3", + "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`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.2", + "date": "Fri, 14 Feb 2025 23:17:26 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug where `chunk.localizedFiles` was not set in incremental rebuilds." + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.1", + "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/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.12.0", + "date": "Thu, 06 Feb 2025 01:11:16 GMT", + "comments": { + "minor": [ + { + "comment": "Leverage webpack caching layer for localized and nonlocalized asset generation. Reduce unnecessary work." + } + ] + } + }, + { + "version": "0.11.26", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.26", + "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`" + } + ] + } + }, + { + "version": "0.11.25", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.25", + "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/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": "0.11.24", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.24", + "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/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": "0.11.23", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.23", + "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`" + } + ] + } + }, + { + "version": "0.11.22", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.22", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + } + ] + } + }, + { + "version": "0.11.21", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.21", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + } + ] + } + }, + { + "version": "0.11.20", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.20", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + } + ] + } + }, + { + "version": "0.11.19", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.19", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + } + ] + } + }, + { + "version": "0.11.18", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.18", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + } + ] + } + }, + { + "version": "0.11.17", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.17", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.16", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.15", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.14", + "date": "Tue, 15 Oct 2024 00:12:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.13", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.12", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.11", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.10", + "date": "Sat, 28 Sep 2024 00:11:41 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.9", + "date": "Tue, 24 Sep 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Fix circular references between localized assets' \"related\" properties. This caused emitting of the webpack stats object to fail." + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.8", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.7", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.6", + "date": "Mon, 26 Aug 2024 02:00:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.5", + "date": "Wed, 21 Aug 2024 16:24:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.1`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.4", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.3", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.2", + "date": "Wed, 07 Aug 2024 00:11:51 GMT", + "comments": { + "patch": [ + { + "comment": "Improve performance of localized asset reconstruction." + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.1", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.11.0", + "date": "Wed, 31 Jul 2024 00:10:53 GMT", + "comments": { + "minor": [ + { + "comment": "Include webpack compilation in localizationStats callback." + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.21", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.61`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.20", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.19", + "date": "Wed, 17 Jul 2024 06:55:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.59`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.18", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.17", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.57`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.16", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.15", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.14", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `type` modifiers on type-only exports." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.13", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.12", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.11", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.10", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.9", + "date": "Sat, 25 May 2024 04:54:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.8", + "date": "Fri, 24 May 2024 00:15:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.7", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.47`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.6", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.5", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.45`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.4", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.3", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.2", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.1", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.41`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.10.0", + "date": "Tue, 16 Apr 2024 22:49:20 GMT", + "comments": { + "minor": [ + { + "comment": "Perform localization before devtool runs instead of after. This is more expensive but ensures source maps are correct." + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.15", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.40`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.14", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.13", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.12", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.11", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.10", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.9", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.8", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.7", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.6", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.31`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.5", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.4", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.3", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.2", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.1", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.9.0", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "minor": [ + { + "comment": "Filter out non-JS chunks." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.25`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `4.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.8.1", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.8.0", + "date": "Sat, 10 Feb 2024 01:40:49 GMT", + "comments": { + "minor": [ + { + "comment": "Export a `TrueHashPlugin` that performs what the `realContentHash` option does, but without validating the localization plugin's options." + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.7.3", + "date": "Sat, 10 Feb 2024 01:29:22 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for the `output.hashSalt` option when the `realContentHashes` feature is enabled." + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.7.2", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.7.1", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.7.0", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "minor": [ + { + "comment": "Include an option called `realContentHash` that updates \"[contenthash]\" hashes to the actual hashes of chunks." + }, + { + "comment": "Add a warning if `optimization.realContentHash` is set." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.6.4", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.6.3", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.6.2", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.6.1", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.6.0", + "date": "Thu, 04 Jan 2024 01:08:53 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a `formatLocaleForFilename` option to customize how a locale (or the lack thereof) is rendered in file paths." + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.10", + "date": "Mon, 30 Oct 2023 23:36:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.6", + "date": "Wed, 27 Sep 2023 00:21:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.5.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + } + ] + } + }, + { + "version": "0.4.41", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.41", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.83`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.7`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + } + ] + } + }, + { + "version": "0.4.40", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.40", + "date": "Sat, 05 Aug 2023 00:20:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.82`" + } + ] + } + }, + { + "version": "0.4.39", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.39", + "date": "Fri, 04 Aug 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.81`" + } + ] + } + }, + { + "version": "0.4.38", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.38", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + } + ] + } + }, + { + "version": "0.4.37", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.37", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + } + ] + } + }, + { + "version": "0.4.36", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.36", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + } + ] + } + }, + { + "version": "0.4.35", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.35", + "date": "Wed, 19 Jul 2023 00:20:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.77`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + } + ] + } + }, + { + "version": "0.4.34", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.34", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + } + ] + } + }, + { + "version": "0.4.33", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.33", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + } + ] + } + }, + { + "version": "0.4.32", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.32", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + } + ] + } + }, + { + "version": "0.4.31", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.31", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + } + ] + } + }, + { + "version": "0.4.30", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.30", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + } + ] + } + }, + { + "version": "0.4.29", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.29", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.71`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + } + ] + } + }, + { + "version": "0.4.28", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.28", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + } + ] + } + }, + { + "version": "0.4.27", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.27", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + } + ] + } + }, + { + "version": "0.4.26", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.26", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.68`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.4`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + } + ] + } + }, + { + "version": "0.4.25", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.25", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + } + ] + } + }, + { + "version": "0.4.24", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.24", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + } + ] + } + }, + { + "version": "0.4.23", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.23", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.22", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.21", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.20", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.19", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.18", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.17", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.59`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.3`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.16", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.15", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.14", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.13", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.55`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.12", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.54`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.11", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.53`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.10", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.9", + "date": "Mon, 01 May 2023 15:23:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.51`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.8", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.50`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.7", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.49`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.6", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.5", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.46`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.45`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.4.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.44`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.3.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.43`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.2.4", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.2.3", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.2.2", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.2.1", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.2.0", + "date": "Tue, 20 Dec 2022 21:56:32 GMT", + "comments": { + "minor": [ + { + "comment": "Convert LocalizationPlugin._stringKeys to public stringKeys property." + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.40", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.39", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.37`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.38", + "date": "Thu, 01 Dec 2022 03:22:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.36`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.37", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.36", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.35", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.34", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.33", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.32", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.31", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.29`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.30", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.29", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.28", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.26`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.27", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.26", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.25", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.23`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.24", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.23", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.22", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.21", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.20", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.19", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.17`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.18", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.17", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.16", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.15", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.14", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.13", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.12", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.11", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.10", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.9", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.8", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.7", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.6", + "date": "Tue, 28 Jun 2022 22:47:13 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure localization file path resolution can handle a UNIX file system on a Windows host, as is used by the unit tests." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.5", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.4", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.3", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.2", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.1", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/webpack5-localization-plugin_v0.1.0", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "minor": [ + { + "comment": "Initial publish of webpack 5 compatible localization plugin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + } + ] + } + } + ] +} diff --git a/webpack/webpack5-localization-plugin/CHANGELOG.md b/webpack/webpack5-localization-plugin/CHANGELOG.md new file mode 100644 index 00000000000..8c2fac1e847 --- /dev/null +++ b/webpack/webpack5-localization-plugin/CHANGELOG.md @@ -0,0 +1,1175 @@ +# Change Log - @rushstack/webpack5-localization-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 0.15.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.15.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.15.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.15.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.15.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.15.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.15.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.15.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.14.7 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.14.6 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.14.5 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.14.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.14.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.14.2 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.14.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.14.0 +Mon, 30 Jun 2025 22:04:32 GMT + +### Minor changes + +- Add a feature for injecting custom localized values into a compilation via the `getCustomDataPlaceholderForValueFunction` function on an instance of the `LocalizationPlugin`. + +## 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:58 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 + +- Support passing the `ignoreString` option to all loaders. + +## 0.12.6 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.12.5 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.12.4 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.12.3 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.12.2 +Fri, 14 Feb 2025 23:17:26 GMT + +### Patches + +- Fix a bug where `chunk.localizedFiles` was not set in incremental rebuilds. + +## 0.12.1 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.12.0 +Thu, 06 Feb 2025 01:11:16 GMT + +### Minor changes + +- Leverage webpack caching layer for localized and nonlocalized asset generation. Reduce unnecessary work. + +## 0.11.26 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.11.25 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.11.24 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.11.23 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.11.22 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 0.11.21 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 0.11.20 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 0.11.19 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 0.11.18 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 0.11.17 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 0.11.16 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 0.11.15 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 0.11.14 +Tue, 15 Oct 2024 00:12:31 GMT + +_Version update only_ + +## 0.11.13 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 0.11.12 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 0.11.11 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 0.11.10 +Sat, 28 Sep 2024 00:11:41 GMT + +_Version update only_ + +## 0.11.9 +Tue, 24 Sep 2024 00:11:19 GMT + +### Patches + +- Fix circular references between localized assets' "related" properties. This caused emitting of the webpack stats object to fail. + +## 0.11.8 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 0.11.7 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 0.11.6 +Mon, 26 Aug 2024 02:00:11 GMT + +_Version update only_ + +## 0.11.5 +Wed, 21 Aug 2024 16:24:51 GMT + +_Version update only_ + +## 0.11.4 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 0.11.3 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 0.11.2 +Wed, 07 Aug 2024 00:11:51 GMT + +### Patches + +- Improve performance of localized asset reconstruction. + +## 0.11.1 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 0.11.0 +Wed, 31 Jul 2024 00:10:53 GMT + +### Minor changes + +- Include webpack compilation in localizationStats callback. + +## 0.10.21 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 0.10.20 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 0.10.19 +Wed, 17 Jul 2024 06:55:09 GMT + +_Version update only_ + +## 0.10.18 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 0.10.17 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 0.10.16 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 0.10.15 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 0.10.14 +Thu, 30 May 2024 00:13:05 GMT + +### Patches + +- Include missing `type` modifiers on type-only exports. + +## 0.10.13 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 0.10.12 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 0.10.11 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 0.10.10 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 0.10.9 +Sat, 25 May 2024 04:54:07 GMT + +_Version update only_ + +## 0.10.8 +Fri, 24 May 2024 00:15:09 GMT + +_Version update only_ + +## 0.10.7 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 0.10.6 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 0.10.5 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 0.10.4 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 0.10.3 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 0.10.2 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 0.10.1 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 0.10.0 +Tue, 16 Apr 2024 22:49:20 GMT + +### Minor changes + +- Perform localization before devtool runs instead of after. This is more expensive but ensures source maps are correct. + +## 0.9.15 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 0.9.14 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 0.9.13 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 0.9.12 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 0.9.11 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 0.9.10 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 0.9.9 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 0.9.8 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 0.9.7 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 0.9.6 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 0.9.5 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 0.9.4 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 0.9.3 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 0.9.2 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 0.9.1 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 0.9.0 +Mon, 19 Feb 2024 21:54:27 GMT + +### Minor changes + +- Filter out non-JS chunks. + +## 0.8.1 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 0.8.0 +Sat, 10 Feb 2024 01:40:49 GMT + +### Minor changes + +- Export a `TrueHashPlugin` that performs what the `realContentHash` option does, but without validating the localization plugin's options. + +## 0.7.3 +Sat, 10 Feb 2024 01:29:22 GMT + +### Patches + +- Add support for the `output.hashSalt` option when the `realContentHashes` feature is enabled. + +## 0.7.2 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 0.7.1 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 0.7.0 +Mon, 05 Feb 2024 23:46:52 GMT + +### Minor changes + +- Include an option called `realContentHash` that updates "[contenthash]" hashes to the actual hashes of chunks. +- Add a warning if `optimization.realContentHash` is set. + +## 0.6.4 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 0.6.3 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 0.6.2 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 0.6.1 +Tue, 16 Jan 2024 18:30:11 GMT + +_Version update only_ + +## 0.6.0 +Thu, 04 Jan 2024 01:08:53 GMT + +### Minor changes + +- Introduce a `formatLocaleForFilename` option to customize how a locale (or the lack thereof) is rendered in file paths. + +## 0.5.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 0.5.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 0.5.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 0.5.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 0.5.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 0.5.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 0.5.10 +Mon, 30 Oct 2023 23:36:38 GMT + +_Version update only_ + +## 0.5.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 0.5.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 0.5.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 0.5.6 +Wed, 27 Sep 2023 00:21:38 GMT + +_Version update only_ + +## 0.5.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 0.5.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 0.5.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 0.5.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 0.5.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 0.5.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 0.4.41 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 0.4.40 +Sat, 05 Aug 2023 00:20:19 GMT + +_Version update only_ + +## 0.4.39 +Fri, 04 Aug 2023 00:22:37 GMT + +_Version update only_ + +## 0.4.38 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 0.4.37 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 0.4.36 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 0.4.35 +Wed, 19 Jul 2023 00:20:32 GMT + +_Version update only_ + +## 0.4.34 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 0.4.33 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 0.4.32 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 0.4.31 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 0.4.30 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 0.4.29 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 0.4.28 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 0.4.27 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 0.4.26 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 0.4.25 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 0.4.24 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 0.4.23 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 0.4.22 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 0.4.21 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 0.4.20 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 0.4.19 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 0.4.18 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 0.4.17 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 0.4.16 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 0.4.15 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 0.4.14 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 0.4.13 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 0.4.12 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 0.4.11 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 0.4.10 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 0.4.9 +Mon, 01 May 2023 15:23:19 GMT + +_Version update only_ + +## 0.4.8 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 0.4.7 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 0.4.6 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 0.4.5 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 0.4.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 0.4.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 0.4.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 0.4.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 0.4.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 0.3.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 0.2.4 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 0.2.3 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 0.2.2 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 0.2.1 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 0.2.0 +Tue, 20 Dec 2022 21:56:32 GMT + +### Minor changes + +- Convert LocalizationPlugin._stringKeys to public stringKeys property. + +## 0.1.40 +Tue, 20 Dec 2022 01:18:22 GMT + +_Version update only_ + +## 0.1.39 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 0.1.38 +Thu, 01 Dec 2022 03:22:36 GMT + +_Version update only_ + +## 0.1.37 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 0.1.36 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 0.1.35 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 0.1.34 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 0.1.33 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 0.1.32 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 0.1.31 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 0.1.30 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 0.1.29 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 0.1.28 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 0.1.27 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 0.1.26 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 0.1.25 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 0.1.24 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 0.1.23 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 0.1.22 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 0.1.21 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 0.1.20 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 0.1.19 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 0.1.18 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 0.1.17 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 0.1.16 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 0.1.15 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 0.1.14 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 0.1.13 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 0.1.12 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 0.1.11 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 0.1.10 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 0.1.9 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 0.1.8 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 0.1.7 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 0.1.6 +Tue, 28 Jun 2022 22:47:13 GMT + +### Patches + +- Ensure localization file path resolution can handle a UNIX file system on a Windows host, as is used by the unit tests. + +## 0.1.5 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 0.1.4 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 0.1.3 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 0.1.2 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 0.1.1 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 0.1.0 +Thu, 23 Jun 2022 22:14:24 GMT + +### Minor changes + +- Initial publish of webpack 5 compatible localization plugin. + diff --git a/webpack/webpack5-localization-plugin/LICENSE b/webpack/webpack5-localization-plugin/LICENSE new file mode 100644 index 00000000000..884e8f36120 --- /dev/null +++ b/webpack/webpack5-localization-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack5-localization-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/webpack/webpack5-localization-plugin/README.md b/webpack/webpack5-localization-plugin/README.md new file mode 100644 index 00000000000..792b6e70a73 --- /dev/null +++ b/webpack/webpack5-localization-plugin/README.md @@ -0,0 +1,228 @@ +# @rushstack/webpack5-localization-plugin + +## Installation + +`npm install @rushstack/webpack5-localization-plugin --save-dev` + +## Overview + +This Webpack plugin produces bundles that have multiple locales' variants of strings embedded. It also +has out-of-box support for RESX files in addition to JSON strings files (with the extensions `.loc.json` or `.resjson`). + +The loaders can also be chained with other loaders that convert the content to one of the known formats. + +# Plugin + +To use the plugin, add it to the `plugins` array of your Webpack config, and specify one or more loaders. For example: + +```JavaScript +import { LocalizationPlugin } from '@rushstack/webpack5-localization-plugin'; + +{ + plugins: [ + new LocalizationPlugin( /* options */ ) + ], + module: { + rules: [{ + test: /\.resjson$/, + use: { + // All loaders are available in `@rushstack/webpack5-localization-plugin/lib/loaders/` + // Loaders for specific formats: `resjson-loader`, `locjson-loader`, `resx-loader` + // Loader that switches on file extension: `loc-loader` + // Loader that switches on file extension and skips localization: `default-locale-loader` + loader: require.resolve('@rushstack/webpack5-localization-plugin/lib/loaders/resjson-loader') + }, + // Can be one of `javascript/esm`, `javascript/dynamic`, or `json` + // `javascript/esm` will produce the smallest bundle sizes, while `json` will produce faster code for large string tables + type: 'javascript/esm', + sideEffects: false + }] + } +} +``` + +***A note about the dev server:*** When Webpack is being run by the Webpack dev server, this plugin pipes +the strings in the loc files in the source (the `.loc.json` and the `.resx` files) to the output without +any translations. + +## Options + +### `localizedData: { }` + +#### `localizedData.defaultLocale: { }` + +This option has a required property (`localeName`), to specify the name of the locale used in the +`.resx` and `.loc.json` files in the source. + +##### `localizedData.defaultLocale.fillMissingTranslationStrings: true | false` + +If this option is set to `true`, strings that are missing from `localizedData.translatedStrings` will be +provided by the default locale (the strings in the `.resx` and `.loc.json` files in the source). If +this option is unset or set to `false`, an error will be emitted if a string is missing from +`localizedData.translatedStrings`. + +#### `localizedData.translatedStrings: { }` + +This option is used to specify the localization data to be used in the build. This object has the following +structure: + +- Locale name + - Compilation context-relative or absolute localization file path + - Translated strings + +For example: + +```JavaScript +translatedStrings: { + "en-us": { + "./src/strings1.loc.json": { + "string1": "the first string" + } + }, + "es-es": { + "./src/strings1.loc.json": { + "string1": "la primera cadena" + } + } +} +``` + +Alternatively, instead of directly specifying the translations, a path to a translated resource file can be +specified. For example: + +```JavaScript +translatedStrings: { + "en-us": { + "./src/strings1.loc.json": "./localization/en-us/strings1.loc.json" + }, + "es-es": { + "./src/strings1.loc.json": "./localization/es-es/strings1.loc.json" + } +} +``` + +#### `localizedData.resolveMissingTranslatedStrings: (locales: string[], filePath: string, context: LoaderContext<{}>) => { ... }` + +This optional option can be used to resolve translated data that is missing from data that is provided +in the `localizedData.translatedStrings` option. Set this option with a function expecting two parameters: +the first, an array of locale names, and second, a fully-qualified path to the localized file in source. The +function should synchronously or asynchronously (as a promise) return an object (or map) with locale names as keys and localized +data as values. The localized data value should be one of: + +- a string: The absolute path to the translated data in `.resx`, `.loc.json`, or `.resjson` format +- an object: An object containing the translated data +- a map: A map containing the translated data + +Note that these values are the same as the values that can be specified for translations for a localized +resource in `localizedData.translatedStrings`. + +If the function returns data that is missing locales or individual strings, the plugin will fall back to the +default locale if `localizedData.defaultLocale.fillMissingTranslationStrings` is set to `true`. If +`localizedData.defaultLocale.fillMissingTranslationStrings` is set to `false`, an error will result. + +#### `localizedData.passthroughLocale: { }` + +This option is used to specify how and if a passthrough locale should be generated. A passthrough locale +is a generated locale in which each string's value is its name. This is useful for debugging and for identifying +cases where a locale is missing. + +This option takes two optional properties: + +##### `localizedData.passthroughLocale.usePassthroughLocale: true | false` + +If `passthroughLocale.usePassthroughLocale` is set to `true`, a passthrough locale will be included in the output. +By default, the passthrough locale's name is "passthrough." + +##### `localizedData.passthroughLocale.passthroughLocaleName: '...'` + +If `passthroughLocale.usePassthroughLocale` is set to `true`, the "passthrough" locale name can be overridden +by setting a value on `passthroughLocale.passthroughLocaleName`. + +#### `localizedData.pseudolocales: { }` + +This option allows pseudolocales to be generated from the strings in the default locale. This option takes +an option with pseudolocales as keys and options for the +[pseudolocale package](https://www.npmjs.com/package/pseudolocale) as values. + +### `noStringsLocaleName: '...'` + +The value to replace the `[locale]` token with for chunks without localized strings. Defaults to "none" + +### `runtimeLocaleExpression: '...'` + +A chunk of raw ECMAScript to inject into the webpack runtime to resolve the current locale at execution time. Allows +multiple locales to share the same runtime chunk if it does not directly contain localized strings. + +### `localizationStats: { }` + +#### `localizationStats.dropPath: '...'` + +This option is used to designate a path at which a JSON file describing the localized assets produced should be +written. If this property is omitted, the stats file won't be written. + +The file has the following format: + +```JSON +{ + "entrypoints": { + "": { + "localizedAssets": { + "": "", + "": "" + } + }, + "": { + "localizedAssets": { + "": "", + "": "" + } + } + }, + "namedChunkGroups": { + "": { + "localizedAssets": { + "": "", + "": "" + } + }, + "": { + "localizedAssets": { + "": "", + "": "" + } + } + } +} + +``` + +#### `localizationStats.callback: (stats) => { ... }` + +This option is used to specify a callback to be called with the stats data that would be dropped at +[`localizationStats.dropPath`](#localizationStats.DropPath--) after compilation completes. + +### `realContentHash: true | false` + +If this option is set to `true`, the plugin will update `[contenthash]` tokens in the output filenames to +use the true hash of the content, rather than an intermediate hash that is shared between all locales. + +Note that this option is not compatible with the `runtimeLocaleExpression` option and will cause an error if +both are set. + +## Custom Localized Data + +If you need to provide custom localized data, you can use the `getCustomDataPlaceholderForValueFunction` method +of the plugin. This method takes a function that receives a locale name and the chunk +that the placeholder is used in and returns a string that will be used as a placeholder for the localized data. +The provided function will be called for each locale that is used in the build and the returned value will replace +the returned placeholder in the output. + +Note that this may produce unexpected results if there are no other localized values in the chunk that the +placeholder is used in. + +## Links + +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/webpack/localization-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack5-localization-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/webpack5-localization-plugin/config/api-extractor.json b/webpack/webpack5-localization-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack5-localization-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack5-localization-plugin/config/jest.config.json b/webpack/webpack5-localization-plugin/config/jest.config.json new file mode 100644 index 00000000000..b50b9d93828 --- /dev/null +++ b/webpack/webpack5-localization-plugin/config/jest.config.json @@ -0,0 +1,5 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json", + + "testTimeout": 1e5 +} diff --git a/webpack/webpack5-localization-plugin/config/rig.json b/webpack/webpack5-localization-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack5-localization-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/webpack/webpack5-localization-plugin/eslint.config.js b/webpack/webpack5-localization-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack5-localization-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/webpack/webpack5-localization-plugin/package.json b/webpack/webpack5-localization-plugin/package.json new file mode 100644 index 00000000000..2bf0906b118 --- /dev/null +++ b/webpack/webpack5-localization-plugin/package.json @@ -0,0 +1,40 @@ +{ + "name": "@rushstack/webpack5-localization-plugin", + "version": "0.15.7", + "description": "This plugin facilitates localization with Webpack.", + "main": "lib/index.js", + "typings": "dist/webpack5-localization-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack5-localization-plugin" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "webpack": "^5.68.0", + "@types/node": "*" + }, + "dependencies": { + "@rushstack/localization-utilities": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/webpack/webpack5-localization-plugin/src/AssetProcessor.ts b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts new file mode 100644 index 00000000000..b9169c4c9a9 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/AssetProcessor.ts @@ -0,0 +1,521 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Asset, AssetInfo, Chunk, Compilation, sources } from 'webpack'; + +import * as Constants from './utilities/Constants'; +import type { + LocalizationPlugin, + IStringPlaceholder, + ValueForLocaleFn, + ICustomDataPlaceholder +} from './LocalizationPlugin'; +import type { ILocalizedWebpackChunk, IAssetPathOptions } from './webpackInterfaces'; + +const LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: 1 = 1; +const DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: 2 = 2; + +interface ILocalizedReconstructionElement { + kind: typeof LOCALIZED_RECONSTRUCTION_ELEMENT_KIND; + start: number; + end: number; + escapedBackslash: string; + data: IStringPlaceholder; +} + +interface IDynamicReconstructionElement { + kind: typeof DYNAMIC_RECONSTRUCTION_ELEMENT_KIND; + start: number; + end: number; + valueFn: ValueForLocaleFn; +} + +type IReconstructionElement = ILocalizedReconstructionElement | IDynamicReconstructionElement; +/** + * @remarks + * Include the `chunk` parameter so that the functions arity is the same as the + * `ValueForLocaleFn` type. + */ +type FormatLocaleForFilenameFn = (locale: string, chunk: unknown) => string; + +interface IParseResult { + issues: string[]; + reconstructionSeries: IReconstructionElement[]; +} + +interface ILocalizedReconstructionResult { + result: sources.ReplaceSource; + issues: string[]; +} + +interface INonLocalizedReconstructionResult { + result: sources.ReplaceSource; + issues: string[]; +} + +export interface IProcessAssetOptionsBase { + plugin: LocalizationPlugin; + compilation: Compilation; + cache: ReturnType; + chunk: Chunk; + asset: Asset; +} + +export interface IProcessNonLocalizedAssetOptions extends IProcessAssetOptionsBase { + fileName: string; + hasUrlGenerator: boolean; + noStringsLocaleName: string; + formatLocaleForFilenameFn: FormatLocaleForFilenameFn; +} + +export interface IProcessLocalizedAssetOptions extends IProcessAssetOptionsBase { + locales: Set; + fillMissingTranslationStrings: boolean; + defaultLocale: string; + passthroughLocaleName: string | undefined; + filenameTemplate: Parameters[0]; + formatLocaleForFilenameFn: FormatLocaleForFilenameFn; +} + +interface IProcessedAsset { + filename: string; + source: sources.CachedSource; + info: AssetInfo; +} + +interface IProcessLocalizedAssetResult { + localizedFiles: Record; + processedAssets: IProcessedAsset[]; +} + +type ItemCacheFacade = ReturnType['getItemCache']>; + +export async function processLocalizedAssetCachedAsync( + options: IProcessLocalizedAssetOptions +): Promise> { + const { compilation, asset, cache, chunk } = options; + const { source: originalSource } = asset; + + type ETag = NonNullable>; + const eTag: ETag | null = cache.getLazyHashedEtag(originalSource); + const { name: originName } = asset; + const cacheItem: ItemCacheFacade = cache.getItemCache(originName, eTag); + let output: IProcessLocalizedAssetResult | undefined = await cacheItem.getPromise(); + + if (!output) { + output = processLocalizedAsset(options); + await cacheItem.storePromise(output); + } + + const { localizedFiles, processedAssets } = output; + + (chunk as ILocalizedWebpackChunk).localizedFiles = localizedFiles; + + for (const { filename, source, info } of processedAssets) { + if (originName === filename) { + // This helper throws if the asset doesn't already exist + // Use the function form so that the object identity of `related` is preserved. + // Since we already read the original info, we don't need fancy merge logic. + compilation.updateAsset(filename, source, () => info); + } else { + // This helper throws if the asset already exists + compilation.emitAsset(filename, source, info); + } + } + + return localizedFiles; +} + +export function processLocalizedAsset(options: IProcessLocalizedAssetOptions): IProcessLocalizedAssetResult { + const { + compilation, + asset, + chunk, + filenameTemplate, + locales, + formatLocaleForFilenameFn, + plugin, + fillMissingTranslationStrings, + defaultLocale, + passthroughLocaleName + } = options; + const { sources, WebpackError } = compilation.compiler.webpack; + const { source: originalSource } = asset; + + const fallbackLocale: string | undefined = fillMissingTranslationStrings ? defaultLocale : undefined; + const rawSource: sources.CachedSource = + originalSource instanceof sources.CachedSource + ? originalSource + : new sources.CachedSource(originalSource); + const assetSource: string = rawSource.source().toString(); + + const parsedAsset: IParseResult = _parseStringToReconstructionSequence( + plugin, + assetSource, + formatLocaleForFilenameFn + ); + + const { issues } = parsedAsset; + + const localizedFiles: Record = {}; + + const processedAssets: IProcessedAsset[] = []; + + const { info: originInfo, name: originName } = asset; + if (!originInfo.related) { + originInfo.related = {}; + } + + for (const locale of locales) { + const { issues: localeIssues, result: localeResult } = _reconstructLocalized( + new sources.ReplaceSource(rawSource, locale), + parsedAsset.reconstructionSeries, + locale, + fallbackLocale, + passthroughLocaleName, + chunk + ); + + for (const issue of localeIssues) { + issues.push(issue); + } + + const data: IAssetPathOptions = { + chunk, + contentHashType: 'javascript', + // The locale property will get processed by the extension to the getAssetPath hook + locale + }; + + const fileName: string = compilation.getAssetPath(filenameTemplate, data); + + const info: AssetInfo & { locale: string } = { + ...originInfo, + locale + }; + + const wrapped: sources.CachedSource = new sources.CachedSource(localeResult); + localizedFiles[locale] = fileName; + + processedAssets.push({ + filename: fileName, + source: wrapped, + info + }); + + // If file already exists + if (originName !== fileName) { + // If A.related points to B, B.related can't point to A or the stats emitter explodes + // So just strip the related object for the localized assets + info.related = undefined; + // We omit the `related` property that does a self-reference. + originInfo.related[locale] = fileName; + } + } + + if (issues.length > 0) { + compilation.errors.push( + new WebpackError(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`) + ); + } + + return { + localizedFiles, + processedAssets + }; +} + +export async function processNonLocalizedAssetCachedAsync( + options: IProcessNonLocalizedAssetOptions +): Promise { + const { compilation, asset, cache } = options; + const { source: originalSource } = asset; + + type ETag = NonNullable>; + const eTag: ETag | null = cache.getLazyHashedEtag(originalSource); + const { name: originName } = asset; + const cacheItem: ItemCacheFacade = cache.getItemCache(originName, eTag); + let output: IProcessedAsset | undefined = await cacheItem.getPromise(); + + if (!output) { + output = processNonLocalizedAsset(options); + await cacheItem.storePromise(output); + } + + const { filename, source, info } = output; + compilation.updateAsset(originName, source, info); + if (originName !== filename) { + compilation.renameAsset(originName, filename); + } +} + +export function processNonLocalizedAsset(options: IProcessNonLocalizedAssetOptions): IProcessedAsset { + const { asset, fileName, compilation, formatLocaleForFilenameFn, hasUrlGenerator, chunk } = options; + + const { sources, WebpackError } = compilation.compiler.webpack; + + const rawSource: sources.Source = asset.source; + let cachedSource: sources.CachedSource = + rawSource instanceof sources.CachedSource ? rawSource : new sources.CachedSource(rawSource); + + const { info: originInfo } = asset; + const locale: string = options.noStringsLocaleName; + + if (hasUrlGenerator) { + const assetSource: string = cachedSource.source().toString(); + const parsedAsset: IParseResult = _parseStringToReconstructionSequence( + options.plugin, + assetSource, + formatLocaleForFilenameFn + ); + + const { issues } = parsedAsset; + + const { issues: localeIssues, result } = _reconstructNonLocalized( + new sources.ReplaceSource(cachedSource, locale), + parsedAsset.reconstructionSeries, + locale, + chunk + ); + + for (const issue of localeIssues) { + issues.push(issue); + } + + if (issues.length > 0) { + options.compilation.errors.push( + new WebpackError(`localization:\n${issues.map((issue) => ` ${issue}`).join('\n')}`) + ); + } + + cachedSource = new sources.CachedSource(result); + } else { + // Force the CachedSource to cache the concatenated *string*, so that the subsequent ask for the buffer is fast + cachedSource.source(); + } + + const info: AssetInfo = { + ...originInfo, + locale + }; + + return { + filename: fileName, + source: cachedSource, + info + }; +} + +const ESCAPE_MAP: Map = new Map([ + ['\r', 'r'], + ['\n', 'n'], + ['\t', 't'], + ['"', 'u0022'], + ["'", 'u0027'] +]); + +const BACKSLASH_REGEX: RegExp = /\\/g; +const ESCAPE_REGEX: RegExp = /[\r\n\t"']/g; + +function _reconstructLocalized( + result: sources.ReplaceSource, + reconstructionSeries: IReconstructionElement[], + locale: string, + fallbackLocale: string | undefined, + passthroughLocale: string | undefined, + chunk: Chunk +): ILocalizedReconstructionResult { + const issues: string[] = []; + + for (const element of reconstructionSeries) { + const { kind, start, end } = element; + switch (kind) { + case LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: { + const { data, escapedBackslash } = element; + const { stringName, translations } = data; + let newValue: string | undefined = + locale === passthroughLocale ? stringName : translations.get(locale)?.get(stringName); + if (fallbackLocale && newValue === undefined) { + newValue = translations.get(fallbackLocale)?.get(stringName); + } + + if (newValue === undefined) { + issues.push( + `The string "${stringName}" in "${data.locFilePath}" is missing in the locale ${locale}` + ); + + newValue = '-- MISSING STRING --'; + } + + if (newValue.includes('\\')) { + // The vast majority of localized strings do not contain `\\`, so this check avoids an allocation. + // Replace backslashes with the properly escaped backslash + BACKSLASH_REGEX.lastIndex = -1; + newValue = newValue.replace(BACKSLASH_REGEX, escapedBackslash); + } + + // Ensure the the quotemark, apostrophe, tab, and newline characters are properly escaped + ESCAPE_REGEX.lastIndex = -1; + if (ESCAPE_REGEX.test(newValue)) { + // The majority of localized strings do not contain the characters that need to be escaped, + // so this check avoids an allocation. + // @todo: look into using JSON.parse(...) to get the escaping characters + const escapingCharacterSequence: string = escapedBackslash.slice(escapedBackslash.length / 2); + newValue = newValue.replace( + ESCAPE_REGEX, + (match) => `${escapingCharacterSequence}${ESCAPE_MAP.get(match)}` + ); + } + + result.replace(start, end - 1, newValue); + break; + } + + case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { + const newValue: string = element.valueFn(locale, chunk); + result.replace(start, end - 1, newValue); + break; + } + } + } + + return { + issues, + result + }; +} + +function _reconstructNonLocalized( + result: sources.ReplaceSource, + reconstructionSeries: IReconstructionElement[], + noStringsLocaleName: string, + chunk: Chunk +): INonLocalizedReconstructionResult { + const issues: string[] = []; + + for (const element of reconstructionSeries) { + switch (element.kind) { + case LOCALIZED_RECONSTRUCTION_ELEMENT_KIND: { + issues.push( + `The string "${element.data.stringName}" in "${element.data.locFilePath}" appeared in an asset ` + + 'that is not expected to contain localized resources.' + ); + + const newValue: string = '-- NOT EXPECTED TO BE LOCALIZED --'; + result.replace(element.start, element.end - 1, newValue); + break; + } + + case DYNAMIC_RECONSTRUCTION_ELEMENT_KIND: { + const newValue: string = element.valueFn(noStringsLocaleName, chunk); + result.replace(element.start, element.end - 1, newValue); + break; + } + } + } + + return { + issues, + result + }; +} + +function _parseStringToReconstructionSequence( + plugin: LocalizationPlugin, + source: string, + formatLocaleForFilenameFn: FormatLocaleForFilenameFn +): IParseResult { + const issues: string[] = []; + const reconstructionSeries: IReconstructionElement[] = []; + + let jsonStringifyFormatLocaleForFilenameFn: FormatLocaleForFilenameFn | undefined; + + let index: number = source.indexOf(Constants.STRING_PLACEHOLDER_PREFIX); + const increment: number = Constants.STRING_PLACEHOLDER_PREFIX.length + 1; + while (index >= 0) { + const start: number = index; + const elementStart: number = index + increment; + const elementLabel: string = source.charAt(elementStart); + let end: number = elementStart + 2; + + switch (elementLabel) { + case Constants.STRING_PLACEHOLDER_LABEL: { + const backslashEnd: number = source.indexOf('_', end); + const escapedBackslash: string = source.slice(end, backslashEnd) || '\\'; + end = backslashEnd + 1; + const suffixEnd: number = source.indexOf('_', end); + const suffix: string = source.slice(end, suffixEnd); + end = suffixEnd + 1; + + const stringData: IStringPlaceholder | undefined = plugin._getStringDataForSerialNumber(suffix); + if (!stringData) { + issues.push(`Missing placeholder ${suffix}`); + } else { + const localizedElement: ILocalizedReconstructionElement = { + kind: LOCALIZED_RECONSTRUCTION_ELEMENT_KIND, + start, + end, + escapedBackslash, + data: stringData + }; + reconstructionSeries.push(localizedElement); + } + break; + } + + case Constants.LOCALE_NAME_PLACEHOLDER_LABEL: { + const dynamicElement: IDynamicReconstructionElement = { + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, + start, + end, + valueFn: formatLocaleForFilenameFn + }; + reconstructionSeries.push(dynamicElement); + break; + } + + case Constants.JSONP_PLACEHOLDER_LABEL: { + jsonStringifyFormatLocaleForFilenameFn ||= (locale: string, chunk: unknown) => + JSON.stringify(formatLocaleForFilenameFn(locale, chunk)); + const dynamicElement: IDynamicReconstructionElement = { + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, + start, + end, + valueFn: jsonStringifyFormatLocaleForFilenameFn + }; + reconstructionSeries.push(dynamicElement); + break; + } + + case Constants.CUSTOM_PLACEHOLDER_LABEL: { + const serialEnd: number = source.indexOf('_', end); + const serial: string = source.slice(end, serialEnd); + end = serialEnd + 1; + const customData: ICustomDataPlaceholder | undefined = plugin._getCustomDataForSerialNumber(serial); + if (!customData) { + issues.push(`Missing custom placeholder ${serial}`); + } else { + const dynamicElement: IDynamicReconstructionElement = { + kind: DYNAMIC_RECONSTRUCTION_ELEMENT_KIND, + start, + end, + valueFn: customData.valueForLocaleFn + }; + reconstructionSeries.push(dynamicElement); + } + break; + } + + default: { + throw new Error(`Unexpected label ${elementLabel} in pattern ${source.slice(start, end)}`); + } + } + + index = source.indexOf(Constants.STRING_PLACEHOLDER_PREFIX, end); + } + + return { + issues, + reconstructionSeries + }; +} diff --git a/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts new file mode 100644 index 00000000000..e5a54496bad --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/LocalizationPlugin.ts @@ -0,0 +1,936 @@ +// 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 { + Asset, + Chunk, + ChunkGraph, + Compilation, + Compiler, + LoaderContext, + Module, + runtime, + WebpackError, + WebpackPluginInstance +} from 'webpack'; + +import { getPseudolocalizer, type ILocalizationFile, parseResJson } from '@rushstack/localization-utilities'; +import { Async } from '@rushstack/node-core-library/lib/Async'; + +import * as Constants from './utilities/Constants'; +import type { + ILocalizationPluginOptions, + ILocalizationStats, + ILocaleFileData, + ILocaleFileObject, + IResolvedMissingTranslations +} from './interfaces'; +import type { IAssetPathOptions } from './webpackInterfaces'; +import { markEntity, getMark } from './utilities/EntityMarker'; +import { processLocalizedAssetCachedAsync, processNonLocalizedAssetCachedAsync } from './AssetProcessor'; +import { getHashFunction, type HashFn, updateAssetHashes } from './trueHashes'; +import { chunkIsJs } from './utilities/chunkUtilities'; + +/** + * @public + */ +export type ValueForLocaleFn = (locale: string, chunk: Chunk) => string; + +/** + * @public + */ +export interface IValuePlaceholderBase { + /** + * The literal string that will be injected for later replacement. + */ + value: string; + + /** + * The identifier for this particular placeholder, for lookup. + */ + suffix: string; +} + +/** + * @public + */ +export interface IStringPlaceholder extends IValuePlaceholderBase { + /** + * The values of this string in each output locale. + */ + translations: ReadonlyMap>; + + /** + * The key used to identify the source file containing the string. + */ + locFilePath: string; + + /** + * The identifier of the string within its original source file. + */ + stringName: string; +} + +/** + * @internal + */ +export interface ICustomDataPlaceholder extends IValuePlaceholderBase { + /** + * The function that will be invoked to get the value for this placeholder. + * The function will be invoked with the locale name as the first argument. + */ + valueForLocaleFn: ValueForLocaleFn; +} + +export interface IFileTranslationInfo { + placeholders: Map; + translations: Map>; + renderedPlaceholders: Record; +} + +const PLUGIN_NAME: 'localization' = 'localization'; + +const pluginForCompiler: WeakMap = new WeakMap(); + +/** + * Gets the instance of the LocalizationPlugin bound to the specified webpack compiler. + * Used by loaders. + */ +export function getPluginInstance(compiler: Compiler | undefined): LocalizationPlugin { + const instance: LocalizationPlugin | undefined = compiler && pluginForCompiler.get(compiler); + if (!instance) { + throw new Error(`Could not find a LocalizationPlugin instance for the current webpack compiler!`); + } + return instance; +} + +/** + * This plugin facilitates localization in webpack. + * + * @public + */ +export class LocalizationPlugin implements WebpackPluginInstance { + private readonly _locFiles: Map = new Map(); + + /** + * @internal + */ + public readonly _options: ILocalizationPluginOptions; + private readonly _resolvedTranslatedStringsFromOptions: Map< + string, + Map> + > = new Map(); + private readonly _stringPlaceholderBySuffix: Map = new Map(); + private readonly _customDataPlaceholderBySuffix: Map = new Map(); + private readonly _customDataPlaceholderByUniqueId: Map = new Map(); + private _passthroughLocaleName!: string; + private _defaultLocale!: string; + private _noStringsLocaleName!: string; + private _fillMissingTranslationStrings!: boolean; + /** + * @remarks + * Include the `chunk` parameter so that the functions arity is the same as the + * `ValueForLocaleFn` type. + */ + private _formatLocaleForFilename!: (loc: string, chunk: unknown) => string; + private readonly _pseudolocalizers: Map string> = new Map(); + + /** + * The set of locales that have translations provided. + */ + private _translatedLocales: Set = new Set(); + + public constructor(options: ILocalizationPluginOptions) { + this._options = options; + } + + /** + * Apply this plugin to the specified webpack compiler. + */ + public apply(compiler: Compiler): void { + pluginForCompiler.set(compiler, this); + + // https://github.com/webpack/webpack-dev-server/pull/1929/files#diff-15fb51940da53816af13330d8ce69b4eR66 + const isWebpackDevServer: boolean = process.env.WEBPACK_DEV_SERVER === 'true'; + + const { errors, warnings } = this._initializeAndValidateOptions(compiler, isWebpackDevServer); + + if (errors.length > 0 || warnings.length > 0) { + compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation: Compilation) => { + compilation.errors.push(...errors); + compilation.warnings.push(...warnings); + }); + + if (errors.length > 0) { + // If there are any errors, just pass through the resources in source and don't do any + // additional configuration + return; + } + } + + const { webpack: thisWebpack } = compiler; + const { + WebpackError, + runtime: { GetChunkFilenameRuntimeModule } + } = thisWebpack; + + // Side-channel for async chunk URL generator chunk, since the actual chunk is completely inaccessible + // from the assetPath hook below when invoked to build the async URL generator + let chunkWithAsyncURLGenerator: Chunk | undefined; + + const originalGenerate: typeof GetChunkFilenameRuntimeModule.prototype.generate = + GetChunkFilenameRuntimeModule.prototype.generate; + GetChunkFilenameRuntimeModule.prototype.generate = function ( + this: runtime.GetChunkFilenameRuntimeModule + ): string | null { + // `originalGenerate` will invoke `getAssetPath` to produce the async URL generator + // Need to know the identity of the containing chunk to correctly produce the asset path expression + chunkWithAsyncURLGenerator = this.chunk; + const result: string | null = originalGenerate.call(this); + // Unset after the call finishes because we are no longer generating async URL generators + chunkWithAsyncURLGenerator = undefined; + return result; + }; + + const asyncGeneratorTest: RegExp = /^\" \+/; + + const { runtimeLocaleExpression } = this._options; + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: Compilation) => { + let hashFn: HashFn | undefined; + if (this._options.realContentHash) { + if (runtimeLocaleExpression) { + compilation.errors.push( + new WebpackError( + `The "realContentHash" option cannot be used in conjunction with "runtimeLocaleExpression".` + ) + ); + } else { + hashFn = getHashFunction({ thisWebpack, compilation }); + } + } else if (compiler.options.optimization?.realContentHash) { + compilation.errors.push( + new thisWebpack.WebpackError( + `The \`optimization.realContentHash\` option is set and the ${LocalizationPlugin.name}'s ` + + '`realContentHash` option is not set. This will likely produce invalid results. Consider setting the ' + + `\`realContentHash\` option in the ${LocalizationPlugin.name} plugin.` + ) + ); + } + + const chunksWithUrlGenerators: WeakSet = new WeakSet(); + + compilation.hooks.assetPath.tap( + PLUGIN_NAME, + (assetPath: string, options: IAssetPathOptions): string => { + const { chunkGraph } = compilation; + + if ( + options.contentHashType === 'javascript' && + assetPath.match(Constants.LOCALE_FILENAME_TOKEN_REGEX) + ) { + // Does this look like an async chunk URL generator? + if (typeof options.chunk?.id === 'string' && options.chunk.id.match(asyncGeneratorTest)) { + const chunkIdsWithStrings: Set = new Set(); + const chunkIdsWithoutStrings: Set = new Set(); + + const activeChunkWithAsyncUrlGenerator: Chunk | undefined = chunkWithAsyncURLGenerator; + + if (!activeChunkWithAsyncUrlGenerator) { + compilation.errors.push( + new WebpackError(`No active chunk while constructing async chunk URL generator!`) + ); + return assetPath; + } + + const asyncChunks: Set = activeChunkWithAsyncUrlGenerator.getAllAsyncChunks(); + for (const asyncChunk of asyncChunks) { + const chunkId: number | string | null = asyncChunk.id; + + if (chunkId === null || chunkId === undefined) { + throw new Error(`Chunk "${asyncChunk.name}"'s ID is null or undefined.`); + } + + if (_chunkHasLocalizedModules(chunkGraph, asyncChunk, runtimeLocaleExpression)) { + chunkIdsWithStrings.add(chunkId); + } else { + chunkIdsWithoutStrings.add(chunkId); + } + } + + return assetPath.replace(Constants.LOCALE_FILENAME_TOKEN_REGEX, () => { + // Use a replacer function so that we don't need to escape anything in the return value + + // If the runtime chunk is itself localized, forcibly match the locale of the runtime chunk + // Otherwise prefer the runtime expression if specified + const localeExpression: string = + (!_chunkHasLocalizedModules( + chunkGraph, + activeChunkWithAsyncUrlGenerator, + runtimeLocaleExpression + ) && + runtimeLocaleExpression) || + Constants.JSONP_PLACEHOLDER; + if (localeExpression === Constants.JSONP_PLACEHOLDER) { + chunksWithUrlGenerators.add(activeChunkWithAsyncUrlGenerator); + } + + if (chunkIdsWithStrings.size === 0) { + return this._formatLocaleForFilename(this._noStringsLocaleName, undefined); + } else if (chunkIdsWithoutStrings.size === 0) { + return `" + ${localeExpression} + "`; + } else { + // Generate an object that is used to select between and for each chunk ID + // Method: pick the smaller set of (localized, non-localized) and map that to 1 (a truthy value) + // All other IDs map to `undefined` (a falsy value), so we then use the ternary operator to select + // the appropriate token + // + // This can be improved in the future. We can maybe sort the chunks such that the chunks below a certain ID + // number are localized and the those above are not. + const chunkMapping: { [chunkId: string]: 1 } = {}; + // Use the map with the fewest values to shorten the expression + const isLocalizedSmaller: boolean = chunkIdsWithStrings.size <= chunkIdsWithoutStrings.size; + // These are the ids for which the expression should evaluate to a truthy value + const smallerSet: Set = isLocalizedSmaller + ? chunkIdsWithStrings + : chunkIdsWithoutStrings; + for (const id of smallerSet) { + chunkMapping[id] = 1; + } + + const noLocaleExpression: string = JSON.stringify( + this._formatLocaleForFilename(this._noStringsLocaleName, undefined) + ); + + return `" + (${JSON.stringify(chunkMapping)}[chunkId]?${ + isLocalizedSmaller ? localeExpression : noLocaleExpression + }:${isLocalizedSmaller ? noLocaleExpression : localeExpression}) + "`; + } + }); + } else { + let locale: string | undefined = options.locale; + if (!locale) { + const isLocalized: boolean = _chunkHasLocalizedModules( + chunkGraph, + options.chunk as Chunk, + runtimeLocaleExpression + ); + // Ensure that the initial name maps to a file that should exist in the final output + locale = isLocalized ? this._defaultLocale : this._noStringsLocaleName; + } + return assetPath.replace( + Constants.LOCALE_FILENAME_TOKEN_REGEX, + this._formatLocaleForFilename(locale, undefined) + ); + } + } else { + return assetPath; + } + } + ); + + const { outputOptions } = compilation; + + // For compatibility with minifiers, need to generate the additional assets after the optimize process runs + compilation.hooks.processAssets.tapPromise( + { + name: PLUGIN_NAME, + // Generating derived assets, but explicitly want to create them *after* asset optimization + stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING - 1 + }, + async (): Promise => { + const locales: Set = this._translatedLocales; + + const { chunkGraph, chunks } = compilation; + const { localizationStats: statsOptions } = this._options; + + const filesByChunkName: Map> | undefined = statsOptions + ? new Map() + : undefined; + const localizedEntryPointNames: string[] = []; + const localizedChunkNames: string[] = []; + + type CacheFacade = ReturnType; + const cache: CacheFacade = compilation.getCache(PLUGIN_NAME); + + await Async.forEachAsync( + chunks, + async (chunk: Chunk) => { + if (!chunkIsJs(chunk, chunkGraph)) { + return; + } + + const isLocalized: boolean = _chunkHasLocalizedModules( + chunkGraph, + chunk, + runtimeLocaleExpression + ); + + const template: Parameters[0] = + chunk.filenameTemplate || + (chunk.hasRuntime() ? outputOptions.filename : outputOptions.chunkFilename)!; + + const defaultAssetName: string = compilation.getPath(template, { + chunk, + contentHashType: 'javascript' + // Without locale this should return the name of the default asset + }); + + const asset: Asset | undefined = compilation.getAsset(defaultAssetName); + if (!asset) { + compilation.errors.push(new WebpackError(`Missing expected chunk asset ${defaultAssetName}`)); + return; + } + + if (isLocalized) { + const localizedAssets: Record = await processLocalizedAssetCachedAsync({ + // Global values + plugin: this, + compilation, + cache, + locales, + defaultLocale: this._defaultLocale, + passthroughLocaleName: this._passthroughLocaleName, + fillMissingTranslationStrings: this._fillMissingTranslationStrings, + formatLocaleForFilenameFn: this._formatLocaleForFilename, + // Chunk-specific values + chunk, + asset, + filenameTemplate: template + }); + + if (filesByChunkName && chunk.name) { + filesByChunkName.set(chunk.name, localizedAssets); + (chunk.hasRuntime() ? localizedEntryPointNames : localizedChunkNames).push(chunk.name); + } + } else { + await processNonLocalizedAssetCachedAsync({ + // Global values + plugin: this, + compilation, + cache, + hasUrlGenerator: chunksWithUrlGenerators.has(chunk), + noStringsLocaleName: this._noStringsLocaleName, + formatLocaleForFilenameFn: this._formatLocaleForFilename, + // Chunk-specific values + chunk, + asset, + fileName: defaultAssetName + }); + } + }, + { + // Only async component is the cache layer + concurrency: 20 + } + ); + + if (hashFn) { + updateAssetHashes({ + thisWebpack, + compilation, + hashFn, + filesByChunkName + }); + } + + // Since the stats generation doesn't depend on content, do it immediately + if (statsOptions && filesByChunkName) { + const localizationStats: ILocalizationStats = { + entrypoints: {}, + namedChunkGroups: {} + }; + + // Sort in lexicographic order to ensure stable output + localizedChunkNames.sort(); + for (const chunkName of localizedChunkNames) { + localizationStats.namedChunkGroups[chunkName] = { + localizedAssets: filesByChunkName.get(chunkName)! + }; + } + + // Sort in lexicographic order to ensure stable output + localizedEntryPointNames.sort(); + for (const chunkName of localizedEntryPointNames) { + localizationStats.entrypoints[chunkName] = { + localizedAssets: filesByChunkName.get(chunkName)! + }; + } + + const { dropPath, callback } = statsOptions; + + if (dropPath) { + compilation.emitAsset( + dropPath, + new compiler.webpack.sources.RawSource(JSON.stringify(localizationStats)) + ); + } + + if (callback) { + try { + callback(localizationStats, compilation); + } catch (e) { + /* swallow errors from the callback */ + } + } + } + } + ); + }); + } + + /** + * @public + * + * @returns An object mapping the string keys to placeholders + */ + public async addDefaultLocFileAsync( + context: LoaderContext<{}>, + localizedFileKey: string, + localizedResourceData: ILocalizationFile + ): Promise> { + const locFileData: ReadonlyMap = convertLocalizationFileToLocData(localizedResourceData); + const fileInfo: IFileTranslationInfo = this._addLocFileAndGetPlaceholders( + this._defaultLocale, + localizedFileKey, + locFileData + ); + + const missingLocales: string[] = []; + for (const [translatedLocaleName, translatedStrings] of this._resolvedTranslatedStringsFromOptions) { + const translatedLocFileFromOptions: ILocaleFileData | undefined = + translatedStrings.get(localizedFileKey); + + if (!translatedLocFileFromOptions) { + missingLocales.push(translatedLocaleName); + } else { + const translatedLocFileData: ReadonlyMap = await normalizeLocalizedDataAsync( + context, + translatedLocFileFromOptions + ); + fileInfo.translations.set(translatedLocaleName, translatedLocFileData); + } + } + + const { resolveMissingTranslatedStrings } = this._options.localizedData; + + if (missingLocales.length > 0 && resolveMissingTranslatedStrings) { + let resolvedTranslatedData: IResolvedMissingTranslations | undefined = undefined; + try { + resolvedTranslatedData = await resolveMissingTranslatedStrings( + missingLocales, + localizedFileKey, + context + ); + } catch (e) { + context.emitError(e); + } + + if (resolvedTranslatedData) { + const iterable: Iterable<[string, ILocaleFileData]> = + resolvedTranslatedData instanceof Map + ? resolvedTranslatedData.entries() + : Object.entries(resolvedTranslatedData); + for (const [resolvedLocaleName, resolvedLocaleData] of iterable) { + if (resolvedLocaleData) { + const translatedLocFileData: ReadonlyMap = await normalizeLocalizedDataAsync( + context, + resolvedLocaleData + ); + fileInfo.translations.set(resolvedLocaleName, translatedLocFileData); + } + } + } + } + + for (const [pseudolocaleName, pseudolocalizer] of this._pseudolocalizers) { + const pseudolocFileData: Map = new Map(); + + for (const [stringName, stringValue] of locFileData) { + pseudolocFileData.set(stringName, pseudolocalizer(stringValue)); + } + + fileInfo.translations.set(pseudolocaleName, pseudolocFileData); + } + + markEntity(context._module!, true); + + return fileInfo.renderedPlaceholders; + } + + /** + * @public + */ + public getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined { + const file: IFileTranslationInfo | undefined = this._locFiles.get(localizedFileKey); + if (!file) { + return undefined; + } + return file.placeholders.get(stringName); + } + + /** + * @beta + */ + public getCustomDataPlaceholderForValueFunction( + valueForLocaleFn: ValueForLocaleFn, + placeholderUniqueId: string + ): string { + let placeholder: ICustomDataPlaceholder | undefined = + this._customDataPlaceholderByUniqueId.get(placeholderUniqueId); + if (!placeholder) { + // Get a hash of the unique ID to make sure its value doesn't interfere with our placeholder tokens + const suffix: string = Buffer.from(placeholderUniqueId, 'utf-8').toString('hex'); + placeholder = { + value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.CUSTOM_PLACEHOLDER_LABEL}_${suffix}_`, + suffix, + valueForLocaleFn + }; + this._customDataPlaceholderBySuffix.set(suffix, placeholder); + this._customDataPlaceholderByUniqueId.set(placeholderUniqueId, placeholder); + } else if (placeholder.valueForLocaleFn !== valueForLocaleFn) { + throw new Error( + `${this.getCustomDataPlaceholderForValueFunction.name} has already been called with "${placeholderUniqueId}" ` + + `and a different valueForLocaleFn.` + ); + } + + return placeholder.value; + } + + /** + * @internal + */ + public _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined { + return this._stringPlaceholderBySuffix.get(suffix); + } + + /** + * @internal + */ + public _getCustomDataForSerialNumber(suffix: string): ICustomDataPlaceholder | undefined { + return this._customDataPlaceholderBySuffix.get(suffix); + } + + private _addLocFileAndGetPlaceholders( + localeName: string, + localizedFileKey: string, + localizedFileData: ReadonlyMap + ): IFileTranslationInfo { + let fileInfo: IFileTranslationInfo | undefined = this._locFiles.get(localizedFileKey); + if (!fileInfo) { + fileInfo = { + placeholders: new Map(), + translations: new Map(), + renderedPlaceholders: {} + }; + this._locFiles.set(localizedFileKey, fileInfo); + } + const { placeholders, translations } = fileInfo; + const locFilePrefix: string = Buffer.from(localizedFileKey, 'utf-8').toString('hex') + '$'; + + const resultObject: Record = {}; + for (const stringName of localizedFileData.keys()) { + let placeholder: IStringPlaceholder | undefined = placeholders.get(stringName); + if (!placeholder) { + const suffix: string = `${locFilePrefix}${Buffer.from(stringName, 'utf-8').toString('hex')}`; + + placeholder = { + value: `${Constants.STRING_PLACEHOLDER_PREFIX}_${Constants.STRING_PLACEHOLDER_LABEL}_\\_${suffix}_`, + suffix, + translations: translations, + locFilePath: localizedFileKey, + stringName + }; + + placeholders.set(stringName, placeholder); + this._stringPlaceholderBySuffix.set(suffix, placeholder); + } + + resultObject[stringName] = placeholder.value; + } + + translations.set(localeName, localizedFileData); + fileInfo.renderedPlaceholders = resultObject; + + return fileInfo; + } + + private _initializeAndValidateOptions( + compiler: Compiler, + isWebpackDevServer: boolean + ): { errors: WebpackError[]; warnings: WebpackError[] } { + const errors: WebpackError[] = []; + const warnings: WebpackError[] = []; + + const { WebpackError } = compiler.webpack; + const { options: configuration } = compiler; + + const LOCALE_NAME_REGEX: RegExp = /[a-z-]/i; + function ensureValidLocaleName(localeName: string): boolean { + if (!localeName.match(LOCALE_NAME_REGEX)) { + errors.push( + new WebpackError( + `Invalid locale name: ${localeName}. Locale names may only contain letters and hyphens.` + ) + ); + return false; + } else { + return true; + } + } + + // START configuration + if ( + !configuration.output || + !configuration.output.filename || + typeof configuration.output.filename !== 'string' || + configuration.output.filename.indexOf(Constants.LOCALE_FILENAME_TOKEN) === -1 + ) { + errors.push( + new WebpackError( + 'The configuration.output.filename property must be provided, must be a string, and must include ' + + `the ${Constants.LOCALE_FILENAME_TOKEN} placeholder` + ) + ); + } + // END configuration + + // START misc options + // START options.localizedData + const { localizedData } = this._options; + if (localizedData) { + // START options.localizedData.passthroughLocale + const { passthroughLocale } = localizedData; + if (passthroughLocale) { + const { usePassthroughLocale, passthroughLocaleName = 'passthrough' } = passthroughLocale; + if (usePassthroughLocale) { + this._passthroughLocaleName = passthroughLocaleName; + this._translatedLocales.add(passthroughLocaleName); + } + } + // END options.localizedData.passthroughLocale + + // START options.localizedData.translatedStrings + const resolveRelativeToContext: (relative: string) => string = ( + configuration.context?.startsWith('/') ? path.posix.resolve : path.resolve + ).bind(0, configuration.context!); + const { translatedStrings } = localizedData; + this._resolvedTranslatedStringsFromOptions.clear(); + if (translatedStrings) { + for (const [localeName, locale] of Object.entries(translatedStrings)) { + if (this._translatedLocales.has(localeName)) { + errors.push( + new WebpackError( + `The locale "${localeName}" appears multiple times. ` + + 'There may be multiple instances with different casing.' + ) + ); + return { errors, warnings }; + } + + if (!ensureValidLocaleName(localeName)) { + return { errors, warnings }; + } + + this._translatedLocales.add(localeName); + const resolvedFromOptionsForLocale: Map = new Map(); + this._resolvedTranslatedStringsFromOptions.set(localeName, resolvedFromOptionsForLocale); + + for (const [locFilePath, locFileDataFromOptions] of Object.entries(locale)) { + const normalizedLocFilePath: string = resolveRelativeToContext(locFilePath); + + if (resolvedFromOptionsForLocale.has(normalizedLocFilePath)) { + errors.push( + new WebpackError( + `The localization file path "${locFilePath}" appears multiple times in locale ${localeName}. ` + + 'There may be multiple instances with different casing.' + ) + ); + return { errors, warnings }; + } + + const normalizedLocFileDataFromOptions: ILocaleFileData = + typeof locFileDataFromOptions === 'string' + ? resolveRelativeToContext(locFileDataFromOptions) + : locFileDataFromOptions; + + resolvedFromOptionsForLocale.set(normalizedLocFilePath, normalizedLocFileDataFromOptions); + } + } + } + // END options.localizedData.translatedStrings + + // START options.localizedData.defaultLocale + const { defaultLocale } = localizedData; + if (defaultLocale) { + const { localeName, fillMissingTranslationStrings } = defaultLocale; + if (localeName) { + if (this._translatedLocales.has(localeName)) { + errors.push(new WebpackError('The default locale is also specified in the translated strings.')); + return { errors, warnings }; + } else if (!ensureValidLocaleName(localeName)) { + return { errors, warnings }; + } + + this._translatedLocales.add(localeName); + this._defaultLocale = localeName; + this._fillMissingTranslationStrings = !!fillMissingTranslationStrings; + } else { + errors.push(new WebpackError('Missing default locale name')); + return { errors, warnings }; + } + } else { + errors.push(new WebpackError('Missing default locale options.')); + return { errors, warnings }; + } + // END options.localizedData.defaultLocale + + // START options.localizedData.pseudoLocales + const { pseudolocales } = localizedData; + if (pseudolocales) { + for (const [pseudolocaleName, pseudoLocaleOpts] of Object.entries(pseudolocales)) { + if (this._defaultLocale === pseudolocaleName) { + errors.push( + new WebpackError(`A pseudolocale (${pseudolocaleName}) name is also the default locale name.`) + ); + return { errors, warnings }; + } + + if (this._translatedLocales.has(pseudolocaleName)) { + errors.push( + new WebpackError( + `A pseudolocale (${pseudolocaleName}) name is also specified in the translated strings.` + ) + ); + return { errors, warnings }; + } + + this._pseudolocalizers.set(pseudolocaleName, getPseudolocalizer(pseudoLocaleOpts)); + this._translatedLocales.add(pseudolocaleName); + } + } + // END options.localizedData.pseudoLocales + } else if (!isWebpackDevServer) { + throw new Error('Localized data must be provided unless webpack dev server is running.'); + } + // END options.localizedData + + // START options.noStringsLocaleName + const { noStringsLocaleName } = this._options; + if ( + noStringsLocaleName === undefined || + noStringsLocaleName === null || + !ensureValidLocaleName(noStringsLocaleName) + ) { + this._noStringsLocaleName = 'none'; + } else { + this._noStringsLocaleName = noStringsLocaleName; + } + // END options.noStringsLocaleName + + // START options.formatLocaleForFilename + const { formatLocaleForFilename = (localeName: string) => localeName } = this._options; + this._formatLocaleForFilename = formatLocaleForFilename; + // END options.formatLocaleForFilename + return { errors, warnings }; + } +} + +function _chunkHasLocalizedModules( + chunkGraph: ChunkGraph, + chunk: Chunk, + runtimeLocaleExpression: string | undefined +): boolean { + let chunkHasAnyLocModules: boolean | undefined = getMark(chunk); + if (chunkHasAnyLocModules === undefined) { + chunkHasAnyLocModules = false; + const candidateModules: Iterable | undefined = chunkGraph.getChunkModulesIterableBySourceType( + chunk, + 'javascript' + ); + if (candidateModules) { + outer: for (const module of candidateModules) { + const moduleMark: boolean | undefined = getMark(module); + if (moduleMark) { + chunkHasAnyLocModules = true; + break; + } else if (moduleMark === false) { + continue; + } + + // Is this a concatenated module? + const { _modules: modules } = module as { _modules?: Iterable }; + if (modules) { + for (const nestedModule of modules) { + if (getMark(nestedModule)) { + markEntity(module, true); + chunkHasAnyLocModules = true; + break outer; + } + } + markEntity(module, false); + } + } + } + + // If this chunk doesn't directly contain any localized resources, it still + // needs to be localized if it's an entrypoint chunk (i.e. - it has a runtime) + // and it loads localized async chunks. + // In that case, the generated chunk URL generation code needs to contain + // the locale name. + if (!chunkHasAnyLocModules && !runtimeLocaleExpression && chunk.hasRuntime()) { + for (const asyncChunk of chunk.getAllAsyncChunks()) { + if (_chunkHasLocalizedModules(chunkGraph, asyncChunk, runtimeLocaleExpression)) { + chunkHasAnyLocModules = true; + break; + } + } + } + + markEntity(chunk, chunkHasAnyLocModules); + } + + return chunkHasAnyLocModules; +} + +function convertLocalizationFileToLocData(locFile: ILocalizationFile): ReadonlyMap { + const locFileData: Map = new Map(); + for (const [stringName, locFileEntry] of Object.entries(locFile)) { + locFileData.set(stringName, locFileEntry.value); + } + + return locFileData; +} + +async function normalizeLocalizedDataAsync( + context: LoaderContext<{}>, + localizedData: ILocaleFileData +): Promise> { + if (typeof localizedData === 'string') { + // The value is the path to a file. Add it as a file dependency + context.addDependency(localizedData); + const content: string = await new Promise((resolve, reject) => { + // Use context.fs so that the plugin is compatible with overriding compiler.inputFileSystem + context.fs.readFile(localizedData, (err, data) => { + if (err) { + return reject(err); + } else if (!data) { + return reject(new Error(`No data in ${localizedData}`)); + } + resolve(data.toString()); + }); + }); + + const localizationFile: ILocalizationFile = parseResJson({ + filePath: localizedData, + content + }); + + return convertLocalizationFileToLocData(localizationFile); + } else { + return localizedData instanceof Map ? localizedData : new Map(Object.entries(localizedData)); + } +} diff --git a/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts b/webpack/webpack5-localization-plugin/src/TrueHashPlugin.ts new file mode 100644 index 00000000000..2c208ffce1b --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/TrueHashPlugin.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 type { Compilation, Compiler, WebpackPluginInstance } from 'webpack'; + +import { type HashFn, getHashFunction, updateAssetHashes } from './trueHashes'; + +const PLUGIN_NAME: 'true-hash' = 'true-hash'; + +/** + * @public + */ +export interface ITrueHashPluginOptions { + /** + * A function that takes the contents of a file and returns a hash. + */ + hashFunction?: (contents: string | Buffer) => string; + + /** + * Optionally override the process assets stage for this plugin. + */ + stageOverride?: number; +} + +/** + * @public + */ +export class TrueHashPlugin implements WebpackPluginInstance { + private readonly _options: ITrueHashPluginOptions; + + public constructor(options: ITrueHashPluginOptions = {}) { + this._options = options; + } + + public apply(compiler: Compiler): void { + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation: Compilation) => { + const { webpack: thisWebpack } = compiler; + const { hashFunction, stageOverride = thisWebpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING - 1 } = + this._options; + const hashFn: HashFn = + hashFunction ?? + getHashFunction({ + thisWebpack, + compilation + }); + + compilation.hooks.processAssets.tap( + { + name: PLUGIN_NAME, + stage: stageOverride + }, + () => updateAssetHashes({ thisWebpack, compilation, hashFn }) + ); + }); + } +} diff --git a/webpack/webpack5-localization-plugin/src/index.ts b/webpack/webpack5-localization-plugin/src/index.ts new file mode 100644 index 00000000000..6d0227a0a6d --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/index.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. + +/// + +export { + LocalizationPlugin, + // TODO: Remove this export in the next major version + type IStringPlaceholder as _IStringPlaceholder, + type IStringPlaceholder, + type ICustomDataPlaceholder as _ICustomDataPlaceholder, + type IValuePlaceholderBase, + type ValueForLocaleFn +} from './LocalizationPlugin'; +export { TrueHashPlugin, type ITrueHashPluginOptions } from './TrueHashPlugin'; + +export type { + IDefaultLocaleOptions, + ILocaleData, + ILocaleElementMap, + ILocaleFileData, + ILocaleFileObject, + ILocalizationPluginOptions, + ILocalizationStats, + ILocalizationStatsChunkGroup, + ILocalizationStatsEntrypoint, + ILocalizationStatsOptions, + ILocalizedData, + ILocalizedStrings, + IPassthroughLocaleOptions, + IPseudolocalesOptions, + IResolvedMissingTranslations +} from './interfaces'; +export type { ILocalizedWebpackChunk } from './webpackInterfaces'; diff --git a/webpack/webpack5-localization-plugin/src/interfaces.ts b/webpack/webpack5-localization-plugin/src/interfaces.ts new file mode 100644 index 00000000000..db77ea44c1b --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/interfaces.ts @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LoaderContext, Compilation } from 'webpack'; + +import type { IPseudolocaleOptions } from '@rushstack/localization-utilities'; + +/** + * Options for the passthrough locale. + * + * @public + */ +export interface IPassthroughLocaleOptions { + /** + * If this is set to `true`, a passthrough locale will be included in the output + */ + usePassthroughLocale?: boolean; + + /** + * If {@link IPassthroughLocaleOptions.usePassthroughLocale} is set, use this name for the passthrough locale. + * Defaults to "passthrough" + */ + passthroughLocaleName?: string; +} + +/** + * @public + */ +export interface IDefaultLocaleOptions { + /** + * This required property specifies the name of the locale used in the + * `.resx`, `.loc.json`, and `.resjson` files in the source + */ + localeName: string; + + /** + * If this option is set to `true`, strings that are missing from + * `localizedData.translatedStrings` will be provided by the default locale + */ + fillMissingTranslationStrings?: boolean; +} + +/** + * Options for generated pseudolocales. + * + * @public + */ +export interface IPseudolocalesOptions { + [pseudoLocaleName: string]: IPseudolocaleOptions; +} + +/** + * @public + */ +export interface ILocalizedData { + /** + * Options for the locale used in the source localized data files. + */ + defaultLocale: IDefaultLocaleOptions; + + /** + * Use this parameter to specify the translated data. + */ + translatedStrings: ILocalizedStrings; + + /** + * Use this parameter to specify a function used to load translations missing from + * the {@link ILocalizedData.translatedStrings} parameter. + */ + resolveMissingTranslatedStrings?: ( + locales: string[], + localizedFileKey: string, + loaderContext: LoaderContext<{}> + ) => Promise | IResolvedMissingTranslations; + + /** + * Options around including a passthrough locale. + */ + passthroughLocale?: IPassthroughLocaleOptions; + + /** + * Options for pseudo-localization. + */ + pseudolocales?: IPseudolocalesOptions; +} + +/** + * Options for how localization stats data should be produced. + * + * @public + */ +export interface ILocalizationStatsOptions { + /** + * This option is used to designate a path at which a JSON file describing the localized + * assets produced should be written. + */ + dropPath?: string; + + /** + * This option is used to specify a callback to be called with the stats data that would be + * dropped at `localizationStats.dropPath` after compilation completes, and the compilation instance. + */ + callback?: (stats: ILocalizationStats, compilation: Compilation) => void; +} + +/** + * The options for localization. + * + * @public + */ +export interface ILocalizationPluginOptions { + /** + * Localization data. + */ + localizedData: ILocalizedData; + + /** + * This option is used to specify `.resx`, `.resx.json`, and `.loc.json` files that should not be processed by + * this plugin. + */ + globsToIgnore?: string[]; + + /** + * The value to replace the [locale] token with for chunks without localized strings. Defaults to "none" + */ + noStringsLocaleName?: string; + + /** + * A chunk of javascript to use to get the current locale at runtime. If specified, allows the runtime chunk + * to be non-localized even if it has async localized chunks, as long as it does not directly contain strings. + */ + runtimeLocaleExpression?: string; + + /** + * Options for how localization stats data should be produced. + */ + localizationStats?: ILocalizationStatsOptions; + + /** + * Custom function for controlling how locale names are formatted based on the locale specified. + * This is useful if you want to emit non-localized files to the root output directory instead + * of a '/none' subdirectory. + * + * If combining with runtimeLocaleExpression, ensure that the runtime output of + * runtimeLocaleExpression produces the same output as formatLocaleForFilename. + */ + formatLocaleForFilename?: (locale: string) => string; + + /** + * If set to true, update usages of [contenthash] to use the true hash of the file contents + */ + realContentHash?: boolean; +} + +/** + * @public + */ +export interface ILocaleFileObject { + [stringName: string]: string; +} + +/** + * @public + * Accepted formats: + * - A string containing the path to the translations in .resjson format (keys mapped directly to values) + * - An object mapping keys directly to values + * - A map mapping keys directly to values + */ +export type ILocaleFileData = string | ILocaleFileObject | ReadonlyMap; + +/** + * @public + */ +export type IResolvedMissingTranslations = ReadonlyMap; + +/** + * @public + */ +export interface ILocaleData { + [locFilePath: string]: ILocaleFileData; +} + +/** + * @public + */ +export interface ILocalizedStrings { + [locale: string]: ILocaleData; +} + +/** + * @public + */ +export interface ILocaleElementMap { + [locale: string]: string; +} + +/** + * @public + */ +export interface ILocalizationStatsEntrypoint { + localizedAssets: ILocaleElementMap; +} + +/** + * @public + */ +export interface ILocalizationStatsChunkGroup { + localizedAssets: ILocaleElementMap; +} + +/** + * @public + */ +export interface ILocalizationStats { + entrypoints: { [name: string]: ILocalizationStatsEntrypoint }; + namedChunkGroups: { [name: string]: ILocalizationStatsChunkGroup }; +} diff --git a/webpack/webpack5-localization-plugin/src/loaders/IResxLoaderOptions.ts b/webpack/webpack5-localization-plugin/src/loaders/IResxLoaderOptions.ts new file mode 100644 index 00000000000..fef594a5dab --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/IResxLoaderOptions.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 type { IParseResxOptionsBase } from '@rushstack/localization-utilities'; + +import type { IBaseLocLoaderOptions } from './LoaderFactory'; + +/** + * @public + */ +export type IResxLoaderOptions = Omit; + +/** + * @public + */ +export interface IResxLocLoaderOptions extends IResxLoaderOptions, IBaseLocLoaderOptions {} diff --git a/webpack/webpack5-localization-plugin/src/loaders/LoaderFactory.ts b/webpack/webpack5-localization-plugin/src/loaders/LoaderFactory.ts new file mode 100644 index 00000000000..22a7e7ea6c5 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/LoaderFactory.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 { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import type { ILocalizationFile } from '@rushstack/localization-utilities'; + +import { getPluginInstance, type LocalizationPlugin } from '../LocalizationPlugin'; + +export interface IBaseLocLoaderOptions { + ignoreString?: (key: string) => boolean; +} + +export function createLoader( + parseFile: (content: string, filePath: string, context: LoaderContext) => ILocalizationFile +): LoaderDefinitionFunction { + // eslint-disable-next-line func-style + const loader: LoaderDefinitionFunction = async function ( + this: LoaderContext, + content: string + ): Promise { + const locFilePath: string = this.resourcePath; + + const pluginInstance: LocalizationPlugin = getPluginInstance(this._compiler); + + const locFileData: ILocalizationFile = parseFile(content, locFilePath, this); + + const strings: Record = await pluginInstance.addDefaultLocFileAsync( + this, + locFilePath, + locFileData + ); + + const { type } = this._module!; + + switch (type) { + case 'json': + return JSON.stringify(strings); + case 'javascript/auto': + case 'javascript/esm': + return `const strings = ${JSON.stringify(strings)};\nexport default strings;`; + default: + this.emitError(new Error(`Unexpected localized module type ${type} for module ${this.resourcePath}`)); + return ''; + } + }; + + return loader; +} diff --git a/webpack/webpack5-localization-plugin/src/loaders/default-locale-loader.ts b/webpack/webpack5-localization-plugin/src/loaders/default-locale-loader.ts new file mode 100644 index 00000000000..c05af860807 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/default-locale-loader.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 type { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import { Terminal } from '@rushstack/terminal'; +import { type ILocalizationFile, parseLocFile } from '@rushstack/localization-utilities'; + +import type { IResxLoaderOptions } from './IResxLoaderOptions'; +import { LoaderTerminalProvider } from '../utilities/LoaderTerminalProvider'; + +/** + * This loader passes through the raw untranslated strings and may be used without a LocalizationPlugin instance. + */ +// eslint-disable-next-line func-style +const loader: LoaderDefinitionFunction = function ( + this: LoaderContext, + content: string +): string { + const options: IResxLoaderOptions = this.getOptions(); + + const locFileData: ILocalizationFile = parseLocFile({ + ...options, + content, + filePath: this.resourcePath, + terminal: new Terminal(LoaderTerminalProvider.getTerminalProviderForLoader(this)) + }); + + const resultObject: { [stringName: string]: string } = {}; + for (const [stringName, stringValue] of Object.entries(locFileData)) { + resultObject[stringName] = stringValue.value; + } + + return JSON.stringify(resultObject); +}; + +export default loader; diff --git a/webpack/webpack5-localization-plugin/src/loaders/loc-loader.ts b/webpack/webpack5-localization-plugin/src/loaders/loc-loader.ts new file mode 100644 index 00000000000..5378b14f197 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/loc-loader.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 type { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import type { NewlineKind } from '@rushstack/node-core-library'; +import { Terminal } from '@rushstack/terminal'; +import { parseLocFile } from '@rushstack/localization-utilities'; + +import type { LocalizationPlugin } from '../LocalizationPlugin'; +import { createLoader, type IBaseLocLoaderOptions } from './LoaderFactory'; +import { LoaderTerminalProvider } from '../utilities/LoaderTerminalProvider'; + +export interface ILocLoaderOptions extends IBaseLocLoaderOptions { + pluginInstance: LocalizationPlugin; + resxNewlineNormalization: NewlineKind | undefined; + ignoreMissingResxComments: boolean | undefined; +} + +/** + * General purpose loader that dispatches based on file extension. + */ +const loader: LoaderDefinitionFunction = createLoader( + (content: string, filePath: string, context: LoaderContext) => { + const options: ILocLoaderOptions = context.getOptions(); + const terminal: Terminal = new Terminal(LoaderTerminalProvider.getTerminalProviderForLoader(context)); + + return parseLocFile({ + ...options, + terminal, + content, + filePath + }); + } +); + +export default loader; diff --git a/webpack/webpack5-localization-plugin/src/loaders/locjson-loader.ts b/webpack/webpack5-localization-plugin/src/loaders/locjson-loader.ts new file mode 100644 index 00000000000..2ee1d3c1485 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/locjson-loader.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 type { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import { parseLocJson } from '@rushstack/localization-utilities'; + +import { createLoader, type IBaseLocLoaderOptions } from './LoaderFactory'; + +const loader: LoaderDefinitionFunction = createLoader( + (content: string, filePath: string, context: LoaderContext) => { + return parseLocJson({ + content, + filePath, + ignoreString: context.getOptions().ignoreString + }); + } +); + +export default loader; diff --git a/webpack/webpack5-localization-plugin/src/loaders/resjson-loader.ts b/webpack/webpack5-localization-plugin/src/loaders/resjson-loader.ts new file mode 100644 index 00000000000..78e491ccbc8 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/resjson-loader.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 type { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import { parseResJson } from '@rushstack/localization-utilities'; + +import { createLoader, type IBaseLocLoaderOptions } from './LoaderFactory'; + +const loader: LoaderDefinitionFunction = createLoader( + (content: string, filePath: string, context: LoaderContext) => { + return parseResJson({ + content, + filePath, + ignoreString: context.getOptions().ignoreString + }); + } +); + +export default loader; diff --git a/webpack/webpack5-localization-plugin/src/loaders/resx-loader.ts b/webpack/webpack5-localization-plugin/src/loaders/resx-loader.ts new file mode 100644 index 00000000000..64e1ba2bf70 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/loaders/resx-loader.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 { LoaderContext, LoaderDefinitionFunction } from 'webpack'; + +import { Terminal } from '@rushstack/terminal'; +import { parseResx } from '@rushstack/localization-utilities'; + +import type { IResxLocLoaderOptions } from './IResxLoaderOptions'; +import { createLoader } from './LoaderFactory'; +import { LoaderTerminalProvider } from '../utilities/LoaderTerminalProvider'; + +const loader: LoaderDefinitionFunction = createLoader( + (content: string, filePath: string, context: LoaderContext) => { + const options: IResxLocLoaderOptions = context.getOptions(); + const terminal: Terminal = new Terminal(LoaderTerminalProvider.getTerminalProviderForLoader(context)); + + return parseResx({ + content, + filePath, + terminal, + resxNewlineNormalization: options.resxNewlineNormalization, + ignoreMissingResxComments: !options.ignoreMissingResxComments, + ignoreString: options.ignoreString + }); + } +); + +export default loader; diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamic.test.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamic.test.ts new file mode 100644 index 00000000000..187c101ecd2 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamic.test.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. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions, ILocalizationStats } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testLocalizedAsyncDynamicInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js"] }', + '/a/async1.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);`, + '/a/async2.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test + strings2.another);`, + '/a/entrySingleChunk.js': `import(/* webpackChunkName: 'async1' */ './async1');`, + '/a/entryTwoChunks.js': `import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.resjson': `{"test":"blah","_test.comment":"A string"}`, + '/a/strings2.resjson': `{"another":"something else","_another.comment":"Another string"}` + }, + '/' + ); + + let localizationStats: ILocalizationStats | undefined; + function statsCallback(stats: ILocalizationStats): void { + localizationStats = stats; + } + + const resJsonLoader: string = resolve(__dirname, '../loaders/resjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.resjson': { + test: 'baz' + }, + '/a/strings2.resjson': { + another: 'some random translation' + } + } + } + }, + runtimeLocaleExpression: 'self.__locale', + localizationStats: { + callback: statsCallback + } + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + entry: { + mainSingleChunk: '/a/entrySingleChunk.js', + mainTwoChunks: '/a/entryTwoChunks.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + chunkFilename: 'chunks/[name]-[locale]-[contenthash].js' + }, + module: { + rules: [ + { + test: /\.resjson$/, + use: { + loader: resJsonLoader + }, + type: 'json', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named', + realContentHash: false + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(localizationStats).toMatchSnapshot('Localization Stats'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles async localized chunks with a runtime locale expression (unminified)', async () => { + await testLocalizedAsyncDynamicInner(false); + }); + + it('Handles async localized chunks with a runtime locale expression (minified)', async () => { + await testLocalizedAsyncDynamicInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts new file mode 100644 index 00000000000..c7aa827939c --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions, ILocalizationStats } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testLocalizedAsyncDynamicInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js"] }', + '/a/async1.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);`, + '/a/async2.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test + strings2.another);`, + '/a/entrySingleChunk.js': `import(/* webpackChunkName: 'async1' */ './async1');`, + '/a/entryTwoChunks.js': `import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.resjson': `{"test":"blah","_test.comment":"A string"}`, + '/a/strings2.resjson': `{"another":"something else","_another.comment":"Another string"}`, + '/b/entry.js': `console.log('hello world');` + }, + '/' + ); + + let localizationStats: ILocalizationStats | undefined; + function statsCallback(stats: ILocalizationStats): void { + localizationStats = stats; + } + + const resJsonLoader: string = resolve(__dirname, '../loaders/resjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.resjson': { + test: 'baz' + }, + '/a/strings2.resjson': { + another: 'some random translation' + } + } + } + }, + runtimeLocaleExpression: 'self.__locale + "/"', + localizationStats: { + callback: statsCallback + }, + formatLocaleForFilename: (locale: string) => { + if (locale === 'none') { + return ''; + } else { + return `${locale}/`; + } + } + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + entry: { + mainSingleChunk: '/a/entrySingleChunk.js', + mainTwoChunks: '/a/entryTwoChunks.js', + other: '/b/entry.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + chunkFilename: 'chunks/[name]-[locale]-[contenthash].js' + }, + module: { + rules: [ + { + test: /\.resjson$/, + use: { + loader: resJsonLoader + }, + type: 'json', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named', + realContentHash: false + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + expect(stats.compilation.assets).toMatchSnapshot('Assets'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(localizationStats).toMatchSnapshot('Localization Stats'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles async localized chunks with a runtime locale expression (unminified)', async () => { + await testLocalizedAsyncDynamicInner(false); + }); + + it('Handles async localized chunks with a runtime locale expression (minified)', async () => { + await testLocalizedAsyncDynamicInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedNoAsync.test.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedNoAsync.test.ts new file mode 100644 index 00000000000..901f44ebe15 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedNoAsync.test.ts @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testLocalizedNoAsyncInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js"] }', + '/a/entry.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);`, + '/a/strings1.resjson': JSON.stringify({ + test: 'blah\r\n\t\\\'"', + '_test.comment': 'A string' + }), + '/a/strings2.resjson': `{"another":"something else","_another.comment":"Another string"}` + }, + '/' + ); + + let compilationInStats: webpack.Compilation | undefined; + const resJsonLoader: string = resolve(__dirname, '../loaders/resjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1', + fillMissingTranslationStrings: true + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.resjson': { + test: `return:\r,newline:\n,tab:\t,backslash:\\,apos:',quote:"` + } + } + }, + passthroughLocale: { + passthroughLocaleName: 'default', + usePassthroughLocale: true + }, + pseudolocales: { + 'qps-ploc': { + prepend: '!--', + append: '-|-' + } + } + }, + localizationStats: { + dropPath: 'localization-stats.json', + callback: (stats, compilation) => { + compilationInStats = compilation; + } + }, + realContentHash: true + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + devtool: 'hidden-source-map', + entry: { + main: '/a/entry.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + devtoolModuleFilenameTemplate: (info: { resourcePath: string }) => { + // On Windows the path contains backslashes because webpack doesn't normalize to platform agnostic paths. + // Also strangely we get `/` instead of `./` at the start of the path. + return `source:///${info.resourcePath?.replace(/\\/g, '/').replace(/^\//, './')}`; + } + }, + module: { + rules: [ + { + test: /\.resjson$/, + use: { + loader: resJsonLoader + }, + type: 'javascript/esm', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named' + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); + + expect(compilationInStats).toBeDefined(); + expect(compilationInStats).toBeInstanceOf(webpack.Compilation); +} + +describe(LocalizationPlugin.name, () => { + it('Handles localized compilation with no async chunks (unminified)', async () => { + await testLocalizedNoAsyncInner(false); + }); + + it('Handles localized compilation with no async chunks (minified)', async () => { + await testLocalizedNoAsyncInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntime.test.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntime.test.ts new file mode 100644 index 00000000000..a6c838fe034 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntime.test.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. + +jest.disableAutomock(); + +import { runTests } from './LocalizedRuntimeTestBase'; + +runTests(); diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeDifferentHashLengths.test.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeDifferentHashLengths.test.ts new file mode 100644 index 00000000000..7f91f3b68e4 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeDifferentHashLengths.test.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. + +jest.disableAutomock(); + +import { createHash } from 'node:crypto'; + +import { runTests } from './LocalizedRuntimeTestBase'; + +runTests({ + hashFunction: (contents) => createHash('sha256').update(contents).digest('hex') +}); diff --git a/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.ts new file mode 100644 index 00000000000..bb8af0ad213 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/LocalizedRuntimeTestBase.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 { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { MemFSPlugin } from './MemFSPlugin'; +import type { ILocalizationPluginOptions } from '../interfaces'; +import { LocalizationPlugin } from '../LocalizationPlugin'; +import { type ITrueHashPluginOptions, TrueHashPlugin } from '../TrueHashPlugin'; +import { markEntity } from '../utilities/EntityMarker'; + +class InjectCustomPlaceholderPlugin implements webpack.WebpackPluginInstance { + private readonly _localizationPlugin: LocalizationPlugin; + private readonly _localizedChunkNameByLocaleName: Map>; + + public constructor( + localizationPlugin: LocalizationPlugin, + localizedChunkNameByLocaleName: Map> + ) { + this._localizationPlugin = localizationPlugin; + this._localizedChunkNameByLocaleName = localizedChunkNameByLocaleName; + } + + public apply(compiler: Compiler): void { + const PLUGIN_NAME: 'inject-custom-placeholder' = 'inject-custom-placeholder'; + const printLocalizedChunkName: 'printLocalizedChunkName' = 'printLocalizedChunkName'; + + const { runtime, RuntimeModule, Template, RuntimeGlobals } = compiler.webpack; + const localizationPlugin: LocalizationPlugin = this._localizationPlugin; + const localizedChunkNameByLocaleName: Map> = this + ._localizedChunkNameByLocaleName; + + function getLocalizedChunkNamesString(locale: string): string { + return `/* ${locale} */ ${JSON.stringify(localizedChunkNameByLocaleName.get(locale))}`; + } + + class GetIntegrityHashRuntimeModule extends RuntimeModule { + public constructor() { + super('custom data module', -10); + this.fullHash = true; + } + + public override generate(): string { + const placeholder: string = localizationPlugin.getCustomDataPlaceholderForValueFunction( + getLocalizedChunkNamesString, + printLocalizedChunkName + ); + + return Template.asString([ + `var localizedChunkNames = ${placeholder};`, + `function ${printLocalizedChunkName}(chunkId) {`, + Template.indent([`console.log(localizedChunkNames[chunkId]);`]), + `}` + ]); + } + + public override shouldIsolate(): boolean { + return false; + } + } + + compiler.hooks.thisCompilation.tap({ name: PLUGIN_NAME, stage: 10 }, (compilation, data) => { + runtime.LoadScriptRuntimeModule.getCompilationHooks(compilation).createScript.tap( + PLUGIN_NAME, + (originalSource): string => { + return Template.asString([originalSource, '', `${printLocalizedChunkName}(chunkId);`]); + } + ); + + function integrityHandler(chunk: webpack.Chunk, set: Set): void { + markEntity(chunk, true); + set.add(printLocalizedChunkName); + } + + compilation.hooks.runtimeRequirementInTree + .for(printLocalizedChunkName) + .tap(PLUGIN_NAME, (chunk: webpack.Chunk, set: Set) => { + compilation.addRuntimeModule(chunk, new GetIntegrityHashRuntimeModule()); + return true; + }); + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.loadScript) + .tap(PLUGIN_NAME, integrityHandler); + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.preloadChunkHandlers) + .tap(PLUGIN_NAME, integrityHandler); + }); + } +} + +export function runTests(trueHashPluginOptions: ITrueHashPluginOptions = {}): void { + async function testLocalizedRuntimeInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js"] }', + '/a/async1.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);`, + '/a/async2.js': `import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test + strings2.another);`, + '/a/entrySingleChunk.js': `import(/* webpackChunkName: 'async1' */ './async1');`, + '/a/entryTwoChunks.js': `import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.resjson': `{"test":"blah","_test.comment":"A string"}`, + '/a/strings2.resjson': `{"another":"something else","_another.comment":"Another string"}` + }, + '/' + ); + + const trueHashPlugin: TrueHashPlugin = new TrueHashPlugin(trueHashPluginOptions); + + const resJsonLoader: string = resolve(__dirname, '../loaders/resjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.resjson': { + test: 'baz' + }, + '/a/strings2.resjson': { + another: 'some random translation' + } + } + } + } + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const localizedChunkNameByLocaleName: Map> = new Map([ + ['LOCALE1', { async1: 'async1-LOCALE1-123456', async2: 'async2-LOCALE1-123456' }], + ['LOCALE2', { async1: 'async1-LOCALE2-abcdef', async2: 'async2-LOCALE2-abcdef' }] + ]); + + const compiler: Compiler = webpack({ + entry: { + mainSingleChunk: '/a/entrySingleChunk.js', + mainTwoChunks: '/a/entryTwoChunks.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + chunkFilename: 'chunks/[name]-[locale]-[contenthash].js' + }, + module: { + rules: [ + { + test: /\.resjson$/, + use: { + loader: resJsonLoader + }, + type: 'javascript/esm', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named', + realContentHash: false + }, + context: '/', + mode: 'production', + plugins: [ + localizationPlugin, + new InjectCustomPlaceholderPlugin(localizationPlugin, localizedChunkNameByLocaleName), + trueHashPlugin, + new MemFSPlugin(memoryFileSystem) + ] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); + } + + describe(LocalizationPlugin.name, () => { + it('Handles async localized chunks (unminified)', async () => { + await testLocalizedRuntimeInner(false); + }); + + it('Handles async localized chunks (minified)', async () => { + await testLocalizedRuntimeInner(true); + }); + }); +} diff --git a/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts b/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.ts new file mode 100644 index 00000000000..5cc4e0508d8 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/MemFSPlugin.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 type { Compiler, InputFileSystem, OutputFileSystem, WebpackPluginInstance } from 'webpack'; +import type { Volume } from 'memfs/lib/volume'; + +type IntermediateFileSystem = Compiler['intermediateFileSystem']; + +const PLUGIN_NAME: 'MemFSPlugin' = 'MemFSPlugin'; +export class MemFSPlugin implements WebpackPluginInstance { + private readonly _memfs: Volume; + + public constructor(memfs: Volume) { + this._memfs = memfs; + } + + public apply(compiler: Compiler): void { + const nodeFileSystem: InputFileSystem | null = compiler.inputFileSystem; + if (!nodeFileSystem) { + throw new Error('MemFSPlugin requires compiler.inputFileSystem to be defined'); + } + compiler.inputFileSystem = this._memfs as unknown as InputFileSystem; + compiler.intermediateFileSystem = this._memfs as unknown as IntermediateFileSystem; + compiler.outputFileSystem = this._memfs as unknown as OutputFileSystem; + compiler.resolverFactory.hooks.resolveOptions.for('loader').tap( + { + stage: 10, + name: PLUGIN_NAME + }, + (options) => { + options.fileSystem = nodeFileSystem; + return options; + } + ); + } +} diff --git a/webpack/webpack5-localization-plugin/src/test/MixedAsync.test.ts b/webpack/webpack5-localization-plugin/src/test/MixedAsync.test.ts new file mode 100644 index 00000000000..9da131a98e2 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/MixedAsync.test.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. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions, ILocalizationStats } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testMixedAsyncInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js", "asyncLoc.js"] }', + '/a/async1.js': `console.log("blah1");`, + '/a/async2.js': `console.log("blah2");`, + '/a/asyncLoc1.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test, strings2.another);`, + '/a/asyncLoc2.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test + strings2.another);`, + '/a/entry.js': `import(/* webpackChunkName: 'asyncLoc1' */ './asyncLoc1');import(/* webpackChunkName: 'asyncLoc2' */ './asyncLoc2');import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.loc.json': `{"test":{"value":"blah","comment":"A string"}}`, + '/a/strings2.loc.json': `{"another":{"value":"something else","comment":"Another string" }}` + }, + '/' + ); + + let localizationStats: ILocalizationStats | undefined; + function statsCallback(stats: ILocalizationStats): void { + localizationStats = stats; + } + + const loader: string = resolve(__dirname, '../loaders/locjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.loc.json': { + test: 'baz' + }, + '/a/strings2.loc.json': { + another: 'some random translation' + } + } + } + }, + localizationStats: { + callback: statsCallback + }, + realContentHash: true + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + entry: { + main: '/a/entry.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + chunkFilename: 'chunks/[name]-[locale]-[contenthash].js', + hashSalt: '1' + }, + module: { + rules: [ + { + test: /\.loc.json$/, + use: { + loader + }, + type: 'javascript/esm', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named' + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(localizationStats).toMatchSnapshot('Localization Stats'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles async localized and non-localized chunks (unminified)', async () => { + await testMixedAsyncInner(false); + }); + + it('Handles async localized and non-localized chunks (minified)', async () => { + await testMixedAsyncInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/MixedAsyncDynamic.test.ts b/webpack/webpack5-localization-plugin/src/test/MixedAsyncDynamic.test.ts new file mode 100644 index 00000000000..0f4a3f61e80 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/MixedAsyncDynamic.test.ts @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions, ILocalizationStats } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testMixedAsyncDynamicInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js", "asyncLoc.js"] }', + '/a/async1.js': `console.log("blah1");`, + '/a/async2.js': `console.log("blah2");`, + '/a/asyncLoc1.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test, strings2.another);`, + '/a/asyncLoc2.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test + strings2.another);`, + '/a/entryTwoChunks.js': `import(/* webpackChunkName: 'asyncLoc1' */ './asyncLoc1');import(/* webpackChunkName: 'asyncLoc2' */ './asyncLoc2');`, + '/a/entryFourChunks.js': `import(/* webpackChunkName: 'asyncLoc1' */ './asyncLoc1');import(/* webpackChunkName: 'asyncLoc2' */ './asyncLoc2');import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.loc.json': `{"test":{"value":"blah","comment":"A string"}}`, + '/a/strings2.loc.json': `{"another":{"value":"something else","comment":"Another string" }}` + }, + '/' + ); + + let localizationStats: ILocalizationStats | undefined; + function statsCallback(stats: ILocalizationStats): void { + localizationStats = stats; + } + + const loader: string = resolve(__dirname, '../loaders/locjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.loc.json': { + test: 'baz' + }, + '/a/strings2.loc.json': { + another: 'some random translation' + } + } + } + }, + localizationStats: { + callback: statsCallback + }, + runtimeLocaleExpression: 'self.__locale' + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + entry: { + mainTwoChunks: '/a/entryTwoChunks.js', + mainFourChunks: '/a/entryFourChunks.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js', + chunkFilename: 'chunks/[name]-[locale]-[contenthash].js' + }, + module: { + rules: [ + { + test: /\.loc.json$/, + use: { + loader + }, + type: 'javascript/esm', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named', + realContentHash: false + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(localizationStats).toMatchSnapshot('Localization Stats'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles async localized and non-localized chunks with a runtime locale expression (unminified)', async () => { + await testMixedAsyncDynamicInner(false); + }); + + it('Handles async localized and non-localized chunks with a runtime locale expression (minified)', async () => { + await testMixedAsyncDynamicInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/MixedAsyncNonHashed.test.ts b/webpack/webpack5-localization-plugin/src/test/MixedAsyncNonHashed.test.ts new file mode 100644 index 00000000000..91ee9a41e88 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/MixedAsyncNonHashed.test.ts @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.disableAutomock(); +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import webpack, { type Compiler, type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import type { ILocalizationPluginOptions, ILocalizationStats } from '../interfaces'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testMixedAsyncInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/a/package.json': '{ "name": "a", "sideEffects": ["entry.js", "async.js", "asyncLoc.js"] }', + '/a/async1.js': `console.log("blah1");`, + '/a/async2.js': `console.log("blah2");`, + '/a/asyncLoc1.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test, strings2.another);`, + '/a/asyncLoc2.js': `import strings1 from './strings1.loc.json'; import strings2 from './strings2.loc.json'; console.log(strings1.test + strings2.another);`, + '/a/entry.js': `import(/* webpackChunkName: 'asyncLoc1' */ './asyncLoc1');import(/* webpackChunkName: 'asyncLoc2' */ './asyncLoc2');import(/* webpackChunkName: 'async1' */ './async1');import(/* webpackChunkName: 'async2' */ './async2');`, + '/a/strings1.loc.json': `{"test":{"value":"blah","comment":"A string"}}`, + '/a/strings2.loc.json': `{"another":{"value":"something else","comment":"Another string" }}` + }, + '/' + ); + + let localizationStats: ILocalizationStats | undefined; + function statsCallback(stats: ILocalizationStats): void { + localizationStats = stats; + } + + const loader: string = resolve(__dirname, '../loaders/locjson-loader.js'); + const options: ILocalizationPluginOptions = { + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: { + LOCALE2: { + '/a/strings1.loc.json': { + test: 'baz' + }, + '/a/strings2.loc.json': { + another: 'some random translation' + } + } + } + }, + localizationStats: { + callback: statsCallback + }, + realContentHash: true + }; + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin(options); + + const compiler: Compiler = webpack({ + entry: { + main: '/a/entry.js' + }, + output: { + path: '/release', + filename: '[name]-[locale].js', + chunkFilename: 'chunks/[name]-[locale].js' + }, + module: { + rules: [ + { + test: /\.loc.json$/, + use: { + loader + }, + type: 'javascript/esm', + sideEffects: false + } + ] + }, + optimization: { + minimize, + moduleIds: 'named' + }, + context: '/', + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(localizationStats).toMatchSnapshot('Localization Stats'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (unminified)', async () => { + await testMixedAsyncInner(false); + }); + + it('Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (minified)', async () => { + await testMixedAsyncInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/NoLocalizedFiles.test.ts b/webpack/webpack5-localization-plugin/src/test/NoLocalizedFiles.test.ts new file mode 100644 index 00000000000..c6478476623 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/NoLocalizedFiles.test.ts @@ -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. + +jest.disableAutomock(); +import { promisify } from 'node:util'; + +import webpack, { type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { LocalizationPlugin } from '../LocalizationPlugin'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testNonLocalizedInner(minimize: boolean): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/package.json': '{}', + '/entrySingleChunk.js': `console.log("Do stuff");import(/* webpackChunkName: 'async1' */ './async1.js').then(mod => mod.foo());`, + '/entryTwoChunks.js': `console.log("Do stuff");import(/* webpackChunkName: 'async1' */ './async1.js').then(mod => mod.foo());import(/* webpackChunkName: 'async2' */ './async2.js').then(mod => mod.foo());`, + '/async1.js': `export function foo() { console.log('foo1'); }`, + '/async2.js': `export function foo() { console.log('foo2'); }` + }, + '/src' + ); + + const localizationPlugin: LocalizationPlugin = new LocalizationPlugin({ + localizedData: { + defaultLocale: { + localeName: 'LOCALE1' + }, + translatedStrings: {} + }, + realContentHash: true + }); + + const compiler: webpack.Compiler = webpack({ + entry: { + mainSingleChunk: '/entrySingleChunk.js', + mainTwoChunks: '/entryTwoChunks.js' + }, + output: { + path: '/release', + filename: '[name]-[locale]-[contenthash].js' + }, + context: '/', + optimization: { + minimize, + moduleIds: 'named' + }, + mode: 'production', + plugins: [localizationPlugin, new MemFSPlugin(memoryFileSystem)] + }); + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler))(); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + + expect(errors).toHaveLength(0); + expect(warnings).toHaveLength(0); +} + +describe(LocalizationPlugin.name, () => { + it('Handles non-localized compilations (unminified)', async () => { + await testNonLocalizedInner(false); + }); + + it('Handles non-localized compilations (minified)', async () => { + await testNonLocalizedInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/NonHashedNonLocalizedAssets.test.ts b/webpack/webpack5-localization-plugin/src/test/NonHashedNonLocalizedAssets.test.ts new file mode 100644 index 00000000000..e1564db0b48 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/NonHashedNonLocalizedAssets.test.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. + +jest.disableAutomock(); +import { promisify } from 'node:util'; + +import webpack, { type Stats } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { TrueHashPlugin } from '../TrueHashPlugin'; +import { MemFSPlugin } from './MemFSPlugin'; + +async function testNonLocalizedInner(minimize: boolean): Promise { + async function getResultsAsync(useTrueHashPlugin: boolean): Promise<{ + errors: webpack.StatsError[] | undefined; + warnings: webpack.StatsError[] | undefined; + results: {}; + }> { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/package.json': '{}', + '/entrySingleChunk.js': `console.log("Do stuff");import(/* webpackChunkName: 'async1' */ './async1.js').then(mod => mod.foo());`, + '/entryTwoChunks.js': `console.log("Do stuff");import(/* webpackChunkName: 'async1' */ './async1.js').then(mod => mod.foo());import(/* webpackChunkName: 'async2' */ './async2.js').then(mod => mod.foo());`, + '/async1.js': `export function foo() { console.log('foo1'); }`, + '/async2.js': `export function foo() { console.log('foo2'); }` + }, + '/src' + ); + + const webpackConfig: webpack.Configuration = { + entry: { + mainSingleChunk: '/entrySingleChunk.js', + mainTwoChunks: '/entryTwoChunks.js' + }, + output: { + path: '/release', + filename: '[name].js' + }, + context: '/', + optimization: { + minimize, + moduleIds: 'named', + realContentHash: !useTrueHashPlugin + }, + mode: 'production', + plugins: [new MemFSPlugin(memoryFileSystem)] + }; + + if (useTrueHashPlugin) { + webpackConfig.plugins!.push(new TrueHashPlugin()); + } + + const trueHashPluginCompiler: webpack.Compiler = webpack(webpackConfig); + const trueHashPluginStats: Stats | undefined = await promisify( + trueHashPluginCompiler.run.bind(trueHashPluginCompiler) + )(); + await promisify(trueHashPluginCompiler.close.bind(trueHashPluginCompiler))(); + if (!trueHashPluginStats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = trueHashPluginStats.toJson('errors-warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + return { errors, warnings, results }; + } + + const [ + { errors: realContentHashErrors, warnings: realContentHashWarnings, results: realContentHashResults }, + { errors: trueHashPluginErrors, warnings: trueHashPluginWarnings, results: trueHashPluginResults } + ] = await Promise.all([getResultsAsync(false), getResultsAsync(true)]); + + expect(trueHashPluginErrors).toMatchSnapshot('Errors'); + expect(trueHashPluginWarnings).toMatchSnapshot('Warnings'); + + expect(trueHashPluginResults).toMatchSnapshot('Content'); + + expect(trueHashPluginErrors).toEqual(realContentHashErrors); + expect(trueHashPluginWarnings).toEqual(realContentHashWarnings); + expect(realContentHashResults).toEqual(realContentHashResults); + + expect(trueHashPluginErrors).toHaveLength(0); + expect(trueHashPluginWarnings).toHaveLength(0); +} + +describe(TrueHashPlugin.name, () => { + it('Handles non-localized non-hashed compilations (unminified)', async () => { + await testNonLocalizedInner(false); + }); + + it('Handles non-localized non-hashed compilations (minified)', async () => { + await testNonLocalizedInner(true); + }); +}); diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamic.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamic.test.ts.snap new file mode 100644 index 00000000000..24e4a7fa6b5 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamic.test.ts.snap @@ -0,0 +1,667 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (minified): Content 1`] = ` +Object { + "/release/chunks/async1-LOCALE1-37357165bf6d1526abd7.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t,r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"blah\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"something else\\"}')}}]);", + "/release/chunks/async1-LOCALE2-37357165bf6d1526abd7.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t,r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"baz\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"some random translation\\"}')}}]);", + "/release/chunks/async2-LOCALE1-5e8d5767e625bf8e4b37.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t+r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"blah\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"something else\\"}')}}]);", + "/release/chunks/async2-LOCALE2-5e8d5767e625bf8e4b37.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t+r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"baz\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"some random translation\\"}')}}]);", + "/release/mainSingleChunk-none-de6b202838001a36efe9.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+self.__locale+\\"-37357165bf6d1526abd7.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var c=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,c]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);c&&c(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+self.__locale+\\"-\\"+{230:\\"37357165bf6d1526abd7\\",421:\\"5e8d5767e625bf8e4b37\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),c=0;c{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,s]=t,c=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);s&&s(o)}for(r&&r(t);c { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"blah\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"something else\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async1-LOCALE2-276405669810f9fc3a39.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./a/async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"baz\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"some random translation\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE1-4886e85e3e8dd2d558bf.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"blah\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"something else\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE2-4886e85e3e8dd2d558bf.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"baz\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"some random translation\\"}'); + +/***/ }) + +}]);", + "/release/mainSingleChunk-none-c06788adfdf4c6796f71.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + self.__locale + \\"-\\" + \\"276405669810f9fc3a39\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainTwoChunks-none-540e60ee32d5fcf66ab0.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + self.__locale + \\"-\\" + {\\"230\\":\\"276405669810f9fc3a39\\",\\"421\\":\\"4886e85e3e8dd2d558bf\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Localization Stats 1`] = ` +Object { + "entrypoints": Object {}, + "namedChunkGroups": Object { + "async1": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/async1-LOCALE1-276405669810f9fc3a39.js", + "LOCALE2": "chunks/async1-LOCALE2-276405669810f9fc3a39.js", + }, + }, + "async2": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/async2-LOCALE1-4886e85e3e8dd2d558bf.js", + "LOCALE2": "chunks/async2-LOCALE2-4886e85e3e8dd2d558bf.js", + }, + }, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts.snap new file mode 100644 index 00000000000..44d6805cdd8 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedAsyncDynamicFormatWithNoLocaleFallback.test.ts.snap @@ -0,0 +1,724 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (minified): Assets 1`] = ` +Object { + "chunks/async1-LOCALE1/-37357165bf6d1526abd7.js": SizeOnlySource { + "_size": 326, + }, + "chunks/async1-LOCALE2/-37357165bf6d1526abd7.js": SizeOnlySource { + "_size": 334, + }, + "chunks/async2-LOCALE1/-5e8d5767e625bf8e4b37.js": SizeOnlySource { + "_size": 326, + }, + "chunks/async2-LOCALE2/-5e8d5767e625bf8e4b37.js": SizeOnlySource { + "_size": 334, + }, + "mainSingleChunk--21d49182d665f1ea8af5.js": SizeOnlySource { + "_size": 2554, + }, + "mainTwoChunks--bf2eafaf1ebfb6ebac7e.js": SizeOnlySource { + "_size": 2665, + }, + "other--6c38f8ee91919c000de6.js": SizeOnlySource { + "_size": 27, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (minified): Content 1`] = ` +Object { + "/release/chunks/async1-LOCALE1/-37357165bf6d1526abd7.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t,r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"blah\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"something else\\"}')}}]);", + "/release/chunks/async1-LOCALE2/-37357165bf6d1526abd7.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t,r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"baz\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"some random translation\\"}')}}]);", + "/release/chunks/async2-LOCALE1/-5e8d5767e625bf8e4b37.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t+r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"blah\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"something else\\"}')}}]);", + "/release/chunks/async2-LOCALE2/-5e8d5767e625bf8e4b37.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var a=_(\\"./a/strings1.resjson\\"),r=_(\\"./a/strings2.resjson\\");console.log(a.t+r.S)},\\"./a/strings1.resjson\\":s=>{s.exports=JSON.parse('{\\"t\\":\\"baz\\"}')},\\"./a/strings2.resjson\\":s=>{s.exports=JSON.parse('{\\"S\\":\\"some random translation\\"}')}}]);", + "/release/mainSingleChunk--21d49182d665f1ea8af5.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/async1-\\"+self.__locale+\\"/-37357165bf6d1526abd7.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var c=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,c]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);c&&c(o)}for(r&&r(t);s{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+self.__locale+\\"/-\\"+{230:\\"37357165bf6d1526abd7\\",421:\\"5e8d5767e625bf8e4b37\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),c=0;c{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,s]=t,c=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);s&&s(o)}for(r&&r(t);c { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"blah\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"something else\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async1-LOCALE2/-276405669810f9fc3a39.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./a/async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"baz\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"some random translation\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE1/-4886e85e3e8dd2d558bf.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"blah\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"something else\\"}'); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE2/-4886e85e3e8dd2d558bf.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* .test */ .t + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* .another */ .S); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"t\\":\\"baz\\"}'); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((module) => { + +module.exports = /*#__PURE__*/JSON.parse('{\\"S\\":\\"some random translation\\"}'); + +/***/ }) + +}]);", + "/release/mainSingleChunk--14b4cf197e712a09ff44.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + self.__locale + \\"/\\" + \\"-\\" + \\"276405669810f9fc3a39\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainTwoChunks--342f5cc71bcd129baca4.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + self.__locale + \\"/\\" + \\"-\\" + {\\"230\\":\\"276405669810f9fc3a39\\",\\"421\\":\\"4886e85e3e8dd2d558bf\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", + "/release/other--0a22a28bc727b811fbb2.js": "/******/ (() => { // webpackBootstrap +console.log('hello world'); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Localization Stats 1`] = ` +Object { + "entrypoints": Object {}, + "namedChunkGroups": Object { + "async1": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/async1-LOCALE1/-276405669810f9fc3a39.js", + "LOCALE2": "chunks/async1-LOCALE2/-276405669810f9fc3a39.js", + }, + }, + "async2": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/async2-LOCALE1/-4886e85e3e8dd2d558bf.js", + "LOCALE2": "chunks/async2-LOCALE2/-4886e85e3e8dd2d558bf.js", + }, + }, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized chunks with a runtime locale expression (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedNoAsync.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedNoAsync.test.ts.snap new file mode 100644 index 00000000000..c8ae8179d1a --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedNoAsync.test.ts.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (minified): Content 1`] = ` +Object { + "/release/localization-stats.json": "{\\"entrypoints\\":{\\"main\\":{\\"localizedAssets\\":{\\"default\\":\\"main-default-83f4ee1ad53822d08923.js\\",\\"LOCALE2\\":\\"main-LOCALE2-53db16ce65a171b2d58d.js\\",\\"LOCALE1\\":\\"main-LOCALE1-d0826e06031981558e87.js\\",\\"qps-ploc\\":\\"main-qps-ploc-d917b232cbcc8f9aec8d.js\\"}}},\\"namedChunkGroups\\":{}}", + "/release/main-LOCALE1-d0826e06031981558e87.js": "(()=>{\\"use strict\\";console.log(\\"blah\\\\r\\\\n\\\\t\\\\\\\\\\\\u0027\\\\u0022\\",\\"something else\\")})();", + "/release/main-LOCALE1-d0826e06031981558e87.js.map": "{\\"version\\":3,\\"file\\":\\"main-LOCALE1-d0826e06031981558e87.js\\",\\"mappings\\":\\"mBAAsFA,QAAQC,ICAtE,CAAC,wBAA4G,ECA1G,CAAC,cAAkH,E\\",\\"sources\\":[\\"source:///./a/entry.js\\",\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\"],\\"sourcesContent\\":[\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\",\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\"],\\"names\\":[\\"console\\",\\"log\\"],\\"sourceRoot\\":\\"\\"}", + "/release/main-LOCALE2-53db16ce65a171b2d58d.js": "(()=>{\\"use strict\\";console.log(\\"return:\\\\r,newline:\\\\n,tab:\\\\t,backslash:\\\\\\\\,apos:\\\\u0027,quote:\\\\u0022\\",\\"something else\\")})();", + "/release/main-LOCALE2-53db16ce65a171b2d58d.js.map": "{\\"version\\":3,\\"file\\":\\"main-LOCALE2-53db16ce65a171b2d58d.js\\",\\"mappings\\":\\"mBAAsFA,QAAQC,ICAtE,CAAC,iEAA4G,ECA1G,CAAC,cAAkH,E\\",\\"sources\\":[\\"source:///./a/entry.js\\",\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\"],\\"sourcesContent\\":[\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\",\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\"],\\"names\\":[\\"console\\",\\"log\\"],\\"sourceRoot\\":\\"\\"}", + "/release/main-default-83f4ee1ad53822d08923.js": "(()=>{\\"use strict\\";console.log(\\"test\\",\\"another\\")})();", + "/release/main-default-83f4ee1ad53822d08923.js.map": "{\\"version\\":3,\\"file\\":\\"main-default-83f4ee1ad53822d08923.js\\",\\"mappings\\":\\"mBAAsFA,QAAQC,ICAtE,CAAC,IAA4G,ECA1G,CAAC,OAAkH,E\\",\\"sources\\":[\\"source:///./a/entry.js\\",\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\"],\\"sourcesContent\\":[\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\",\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\"],\\"names\\":[\\"console\\",\\"log\\"],\\"sourceRoot\\":\\"\\"}", + "/release/main-qps-ploc-d917b232cbcc8f9aec8d.js": "(()=>{\\"use strict\\";console.log(\\"!--ƀĺàĥ\\\\r\\\\n\\\\t\\\\\\\\\\\\u0027\\\\u0022-|-\\",\\"!--śōmēţĥĩńĝ ēĺśē-|-\\")})();", + "/release/main-qps-ploc-d917b232cbcc8f9aec8d.js.map": "{\\"version\\":3,\\"file\\":\\"main-qps-ploc-d917b232cbcc8f9aec8d.js\\",\\"mappings\\":\\"mBAAsFA,QAAQC,ICAtE,CAAC,8BAA4G,ECA1G,CAAC,oBAAkH,E\\",\\"sources\\":[\\"source:///./a/entry.js\\",\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\"],\\"sourcesContent\\":[\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\",\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\"],\\"names\\":[\\"console\\",\\"log\\"],\\"sourceRoot\\":\\"\\"}", +} +`; + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (minified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (minified): Warnings 1`] = `Array []`; + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (unminified): Content 1`] = ` +Object { + "/release/localization-stats.json": "{\\"entrypoints\\":{\\"main\\":{\\"localizedAssets\\":{\\"default\\":\\"main-default-d7e97cf591a7391fb602.js\\",\\"LOCALE2\\":\\"main-LOCALE2-41498f590539983b4243.js\\",\\"LOCALE1\\":\\"main-LOCALE1-f13c9f8d1301f4e49d62.js\\",\\"qps-ploc\\":\\"main-qps-ploc-1086de10c00dc424a3f9.js\\"}}},\\"namedChunkGroups\\":{}}", + "/release/main-LOCALE1-f13c9f8d1301f4e49d62.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; + +;// ./a/strings1.resjson +const strings = {\\"test\\":\\"blah\\\\r\\\\n\\\\t\\\\\\\\\\\\u0027\\\\u0022\\"}; +/* harmony default export */ const strings1_resjson = (strings); +;// ./a/strings2.resjson +const strings2_resjson_strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const strings2_resjson = (strings2_resjson_strings); +;// ./a/entry.js + console.log(strings1_resjson.test, strings2_resjson.another); +/******/ })() +;", + "/release/main-LOCALE1-f13c9f8d1301f4e49d62.js.map": "{\\"version\\":3,\\"file\\":\\"main-LOCALE1-f13c9f8d1301f4e49d62.js\\",\\"mappings\\":\\";;;;AAAA,iBAAiB,QAAQ,wBAA4G;AACrI,uDAAe,OAAO,E;;ACDtB,MAAM,wBAAO,IAAI,WAAW,cAAkH;AAC9I,uDAAe,wBAAO,E;;ACDoB,CAA2C,CAAC,YAAY,gBAAQ,OAAO,gBAAQ,U\\",\\"sources\\":[\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\",\\"source:///./a/entry.js\\"],\\"sourcesContent\\":[\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\",\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\"],\\"names\\":[],\\"sourceRoot\\":\\"\\"}", + "/release/main-LOCALE2-41498f590539983b4243.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; + +;// ./a/strings1.resjson +const strings = {\\"test\\":\\"return:\\\\r,newline:\\\\n,tab:\\\\t,backslash:\\\\\\\\,apos:\\\\u0027,quote:\\\\u0022\\"}; +/* harmony default export */ const strings1_resjson = (strings); +;// ./a/strings2.resjson +const strings2_resjson_strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const strings2_resjson = (strings2_resjson_strings); +;// ./a/entry.js + console.log(strings1_resjson.test, strings2_resjson.another); +/******/ })() +;", + "/release/main-LOCALE2-41498f590539983b4243.js.map": "{\\"version\\":3,\\"file\\":\\"main-LOCALE2-41498f590539983b4243.js\\",\\"mappings\\":\\";;;;AAAA,iBAAiB,QAAQ,iEAA4G;AACrI,uDAAe,OAAO,E;;ACDtB,MAAM,wBAAO,IAAI,WAAW,cAAkH;AAC9I,uDAAe,wBAAO,E;;ACDoB,CAA2C,CAAC,YAAY,gBAAQ,OAAO,gBAAQ,U\\",\\"sources\\":[\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\",\\"source:///./a/entry.js\\"],\\"sourcesContent\\":[\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\",\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\"],\\"names\\":[],\\"sourceRoot\\":\\"\\"}", + "/release/main-default-d7e97cf591a7391fb602.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; + +;// ./a/strings1.resjson +const strings = {\\"test\\":\\"test\\"}; +/* harmony default export */ const strings1_resjson = (strings); +;// ./a/strings2.resjson +const strings2_resjson_strings = {\\"another\\":\\"another\\"}; +/* harmony default export */ const strings2_resjson = (strings2_resjson_strings); +;// ./a/entry.js + console.log(strings1_resjson.test, strings2_resjson.another); +/******/ })() +;", + "/release/main-default-d7e97cf591a7391fb602.js.map": "{\\"version\\":3,\\"file\\":\\"main-default-d7e97cf591a7391fb602.js\\",\\"mappings\\":\\";;;;AAAA,iBAAiB,QAAQ,IAA4G;AACrI,uDAAe,OAAO,E;;ACDtB,MAAM,wBAAO,IAAI,WAAW,OAAkH;AAC9I,uDAAe,wBAAO,E;;ACDoB,CAA2C,CAAC,YAAY,gBAAQ,OAAO,gBAAQ,U\\",\\"sources\\":[\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\",\\"source:///./a/entry.js\\"],\\"sourcesContent\\":[\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\",\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\"],\\"names\\":[],\\"sourceRoot\\":\\"\\"}", + "/release/main-qps-ploc-1086de10c00dc424a3f9.js": "/******/ (() => { // webpackBootstrap +/******/ \\"use strict\\"; + +;// ./a/strings1.resjson +const strings = {\\"test\\":\\"!--ƀĺàĥ\\\\r\\\\n\\\\t\\\\\\\\\\\\u0027\\\\u0022-|-\\"}; +/* harmony default export */ const strings1_resjson = (strings); +;// ./a/strings2.resjson +const strings2_resjson_strings = {\\"another\\":\\"!--śōmēţĥĩńĝ ēĺśē-|-\\"}; +/* harmony default export */ const strings2_resjson = (strings2_resjson_strings); +;// ./a/entry.js + console.log(strings1_resjson.test, strings2_resjson.another); +/******/ })() +;", + "/release/main-qps-ploc-1086de10c00dc424a3f9.js.map": "{\\"version\\":3,\\"file\\":\\"main-qps-ploc-1086de10c00dc424a3f9.js\\",\\"mappings\\":\\";;;;AAAA,iBAAiB,QAAQ,8BAA4G;AACrI,uDAAe,OAAO,E;;ACDtB,MAAM,wBAAO,IAAI,WAAW,oBAAkH;AAC9I,uDAAe,wBAAO,E;;ACDoB,CAA2C,CAAC,YAAY,gBAAQ,OAAO,gBAAQ,U\\",\\"sources\\":[\\"source:///./a/strings1.resjson\\",\\"source:///./a/strings2.resjson\\",\\"source:///./a/entry.js\\"],\\"sourcesContent\\":[\\"const strings = {\\\\\\"test\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773312e7265736a736f6e$74657374_\\\\\\"};\\\\nexport default strings;\\",\\"const strings = {\\\\\\"another\\\\\\":\\\\\\"_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_A_\\\\\\\\\\\\\\\\_2f612f737472696e6773322e7265736a736f6e$616e6f74686572_\\\\\\"};\\\\nexport default strings;\\",\\"import strings1 from './strings1.resjson'; import strings2 from './strings2.resjson'; console.log(strings1.test, strings2.another);\\"],\\"names\\":[],\\"sourceRoot\\":\\"\\"}", +} +`; + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles localized compilation with no async chunks (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap new file mode 100644 index 00000000000..54e4d692756 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntime.test.ts.snap @@ -0,0 +1,1235 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized chunks (minified): Content 1`] = ` +Object { + "/release/chunks/async1-LOCALE1-44d1a3fadec3f8385e08.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/async1-LOCALE2-1e57833357912f77511d.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/chunks/async2-LOCALE1-0c2f434469639436732a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/async2-LOCALE2-664388d6b7aa642fc965.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/mainSingleChunk-LOCALE1-e094e623ae3f9b34bd5f.js": "(()=>{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-44d1a3fadec3f8385e08.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-1e57833357912f77511d.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"44d1a3fadec3f8385e08\\",421:\\"0c2f434469639436732a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"1e57833357912f77511d\\",421:\\"664388d6b7aa642fc965\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async1-LOCALE2-7fbd9e8b90662b96d60f.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./a/async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE1-fd38f9892797533b5275.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE2-e2cb29feccd145fb73bf.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/mainSingleChunk-LOCALE1-a09e66b038c209b52c2b.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + \\"LOCALE1\\" + \\"-\\" + \\"d6178a7c70b08da50818\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainSingleChunk-LOCALE2-5382793b5c1b412e361b.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + \\"LOCALE2\\" + \\"-\\" + \\"7fbd9e8b90662b96d60f\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainTwoChunks-LOCALE1-5efaa974620f14b4f849.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + \\"LOCALE1\\" + \\"-\\" + {\\"230\\":\\"d6178a7c70b08da50818\\",\\"421\\":\\"fd38f9892797533b5275\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", + "/release/mainTwoChunks-LOCALE2-621e175eb55ea9b3280f.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + \\"LOCALE2\\" + \\"-\\" + {\\"230\\":\\"7fbd9e8b90662b96d60f\\",\\"421\\":\\"e2cb29feccd145fb73bf\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized chunks (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized chunks (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap new file mode 100644 index 00000000000..d635b9d6af8 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/LocalizedRuntimeDifferentHashLengths.test.ts.snap @@ -0,0 +1,1235 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized chunks (minified): Content 1`] = ` +Object { + "/release/chunks/async1-LOCALE1-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/async1-LOCALE2-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test,a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/chunks/async2-LOCALE1-2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/async2-LOCALE2-c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":(s,e,_)=>{_.r(e);var n=_(\\"./a/strings1.resjson\\"),a=_(\\"./a/strings2.resjson\\");console.log(n.A.test+a.A.another)},\\"./a/strings1.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.resjson\\":(s,e,_)=>{_.d(e,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/mainSingleChunk-LOCALE1-43dafbb20c49f31018cdcc84c85463918d43d69204654b24dd2d64abba1562d9.js": "(()=>{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE1\\"+\\"-9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/async1-\\"+\\"LOCALE2\\"+\\"-fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8.js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,l;if(void 0!==a)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),l&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={331:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,l]=o,s=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);l&&l(t)}for(r&&r(o);s{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE1\\"+\\"-\\"+{230:\\"9bd32294abc47c2bd95cbd4f4a64ac12f94cfd89dbb3cc1056c8ca83c94b3f83\\",421:\\"2878fc254efcf861ebdb1de8ffe2da978f78d90bdb657ca96126fe284386851a\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l{var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}};return e[o](a,a.exports,t),a.exports}t.m=e;var o,n=/* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"};t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((r,o)=>(t.f[o](e,r),r)),[])),t.u=e=>\\"chunks/\\"+{230:\\"async1\\",421:\\"async2\\"}[e]+\\"-\\"+\\"LOCALE2\\"+\\"-\\"+{230:\\"fa6798298a8e8fb0d1bfe76c5e91205c5fed97626fa266ba799a906a58a693e8\\",421:\\"c2b6b66a1486798af745222597d7f7f64daf16f5566e28a3e34dda6da6f41f87\\"}[e]+\\".js\\",t.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o={},t.l=(e,r,a,i)=>{if(o[e])o[e].push(r);else{var c,s;if(void 0!==a)for(var l=document.getElementsByTagName(\\"script\\"),u=0;u{c.onerror=c.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],c.parentNode&&c.parentNode.removeChild(c),n&&n.forEach((e=>e(t))),r)return r(t)},f=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:c}),12e4);c.onerror=p.bind(null,c.onerror),c.onload=p.bind(null,c.onload),s&&document.head.appendChild(c)}},t.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;t.g.importScripts&&(e=t.g.location+\\"\\");var r=t.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var o=r.getElementsByTagName(\\"script\\");if(o.length)for(var n=o.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=o[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),t.p=e})(),(()=>{var e={580:0};t.f.j=(r,o)=>{var n=t.o(e,r)?e[r]:void 0;if(0!==n)if(n)o.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));o.push(n[2]=a);var i=t.p+t.u(r),c=new Error;t.l(i,(o=>{if(t.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=o&&(\\"load\\"===o.type?\\"missing\\":o.type),i=o&&o.target&&o.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,o)=>{var n,a,[i,c,s]=o,l=0;if(i.some((r=>0!==e[r]))){for(n in c)t.o(c,n)&&(t.m[n]=c[n]);s&&s(t)}for(r&&r(o);l { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async1-LOCALE2-74e5c4216c44dc546c38162d7cbec22be47e97f6c5852b4c7d500954f37f0161.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./a/async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE1-18f3dbb15bcedd300d7752dd17deb3f69a5e482cfa2377f2b44097d1616da15c.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/async2-LOCALE2-dee6bd02f0422eef929cdca25dcdeccb4d7ff404bb9c8bf4f68959cc4c4fa5da.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_resjson__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.resjson\\"); +/* harmony import */ var _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.resjson\\"); + console.log(_strings1_resjson__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_resjson__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.resjson\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/mainSingleChunk-LOCALE1-d6fa89a28e2fa52fe9de08e06af1bbadddce89ce7bcef6c01d2709993630806b.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + \\"LOCALE1\\" + \\"-\\" + \\"b80ce37f4633fbde0ff9c7599d27ea32d4292b668d3695938f956f816e88e9b6\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainSingleChunk-LOCALE2-6ce640a695a120867bdbd13eb91fa9cccb619aa0468f5f6997dc775abbdb8133.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + \\"async1\\" + \\"-\\" + \\"LOCALE2\\" + \\"-\\" + \\"74e5c4216c44dc546c38162d7cbec22be47e97f6c5852b4c7d500954f37f0161\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\")); +/******/ })() +;", + "/release/mainTwoChunks-LOCALE1-88b9507279db4beebecf847e23c169f45022bf8fed391e23a91aeb3201799771.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE1 */ {\\"async1\\":\\"async1-LOCALE1-123456\\",\\"async2\\":\\"async2-LOCALE1-123456\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + \\"LOCALE1\\" + \\"-\\" + {\\"230\\":\\"b80ce37f4633fbde0ff9c7599d27ea32d4292b668d3695938f956f816e88e9b6\\",\\"421\\":\\"18f3dbb15bcedd300d7752dd17deb3f69a5e482cfa2377f2b44097d1616da15c\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", + "/release/mainTwoChunks-LOCALE2-d7460ccdbe34a16a0224016e2120e797b3b1489308d88f1f5d9f2c6b1c4eb415.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/custom data module */ +/******/ var localizedChunkNames = /* LOCALE2 */ {\\"async1\\":\\"async1-LOCALE2-abcdef\\",\\"async2\\":\\"async2-LOCALE2-abcdef\\"}; +/******/ function printLocalizedChunkName(chunkId) { +/******/ console.log(localizedChunkNames[chunkId]); +/******/ } +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + \\"LOCALE2\\" + \\"-\\" + {\\"230\\":\\"74e5c4216c44dc546c38162d7cbec22be47e97f6c5852b4c7d500954f37f0161\\",\\"421\\":\\"dee6bd02f0422eef929cdca25dcdeccb4d7ff404bb9c8bf4f68959cc4c4fa5da\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ +/******/ +/******/ printLocalizedChunkName(chunkId); +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./a/async1.js\\"));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./a/async2.js\\")); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized chunks (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized chunks (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsync.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsync.test.ts.snap new file mode 100644 index 00000000000..868afbb8a1a --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsync.test.ts.snap @@ -0,0 +1,819 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized and non-localized chunks (minified): Content 1`] = ` +Object { + "/release/chunks/async1-none-dcecbe55134f94f9aee7.js": "(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":()=>{console.log(\\"blah1\\")}}]);", + "/release/chunks/async2-none-1b365930b3b55b3e7daf.js": "(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":()=>{console.log(\\"blah2\\")}}]);", + "/release/chunks/asyncLoc1-LOCALE1-0b2f66791f51dbf42d4c.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc1-LOCALE2-05a985dae698da8962f5.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE1-ba4e327105557c561da1.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE2-751acb3501e81e642678.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/main-LOCALE1-299f2ee2f2d6b573f1a5.js": "(()=>{var e,t,r,n={},o={};function a(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return n[e](r,r.exports,a),r.exports}a.m=n,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,a.t=function(r,n){if(1&n&&(r=this(r)),8&n)return r;if(\\"object\\"==typeof r&&r){if(4&n&&r.__esModule)return r;if(16&n&&\\"function\\"==typeof r.then)return r}var o=Object.create(null);a.r(o);var i={};e=e||[null,t({}),t([]),t(t)];for(var c=2&n&&r;\\"object\\"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((e=>i[e]=()=>r[e]));return i.default=()=>r,a.d(o,i),o},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,r)=>(a.f[r](e,t),t)),[])),a.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",230:\\"async1\\",410:\\"asyncLoc1\\",421:\\"async2\\"}[e]+\\"-\\"+({17:1,410:1}[e]?\\"LOCALE1\\":\\"none\\")+\\"-\\"+{17:\\"ba4e327105557c561da1\\",230:\\"dcecbe55134f94f9aee7\\",410:\\"0b2f66791f51dbf42d4c\\",421:\\"1b365930b3b55b3e7daf\\"}[e]+\\".js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},a.l=(e,t,n,o)=>{if(r[e])r[e].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{i.onerror=i.onload=null,clearTimeout(d);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),t)return t(n)},d=setTimeout(f.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName(\\"script\\");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={792:0};a.f.j=(t,r)=>{var n=a.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var o=new Promise(((r,o)=>n=e[t]=[r,o]));r.push(n[2]=o);var i=a.p+a.u(t),c=new Error;a.l(i,(r=>{if(a.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var o=r&&(\\"load\\"===r.type?\\"missing\\":r.type),i=r&&r.target&&r.target.src;c.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+o+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=o,c.request=i,n[1](c)}}),\\"chunk-\\"+t,t)}};var t=(t,r)=>{var n,o,[i,c,s]=r,u=0;if(i.some((t=>0!==e[t]))){for(n in c)a.o(c,n)&&(a.m[n]=c[n]);s&&s(a)}for(t&&t(r);u{var e,t,r,n={},o={};function a(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return n[e](r,r.exports,a),r.exports}a.m=n,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,a.t=function(r,n){if(1&n&&(r=this(r)),8&n)return r;if(\\"object\\"==typeof r&&r){if(4&n&&r.__esModule)return r;if(16&n&&\\"function\\"==typeof r.then)return r}var o=Object.create(null);a.r(o);var i={};e=e||[null,t({}),t([]),t(t)];for(var c=2&n&&r;\\"object\\"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((e=>i[e]=()=>r[e]));return i.default=()=>r,a.d(o,i),o},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,r)=>(a.f[r](e,t),t)),[])),a.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",230:\\"async1\\",410:\\"asyncLoc1\\",421:\\"async2\\"}[e]+\\"-\\"+({17:1,410:1}[e]?\\"LOCALE2\\":\\"none\\")+\\"-\\"+{17:\\"751acb3501e81e642678\\",230:\\"dcecbe55134f94f9aee7\\",410:\\"05a985dae698da8962f5\\",421:\\"1b365930b3b55b3e7daf\\"}[e]+\\".js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},a.l=(e,t,n,o)=>{if(r[e])r[e].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{i.onerror=i.onload=null,clearTimeout(d);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),t)return t(n)},d=setTimeout(f.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName(\\"script\\");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={792:0};a.f.j=(t,r)=>{var n=a.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var o=new Promise(((r,o)=>n=e[t]=[r,o]));r.push(n[2]=o);var i=a.p+a.u(t),c=new Error;a.l(i,(r=>{if(a.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var o=r&&(\\"load\\"===r.type?\\"missing\\":r.type),i=r&&r.target&&r.target.src;c.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+o+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=o,c.request=i,n[1](c)}}),\\"chunk-\\"+t,t)}};var t=(t,r)=>{var n,o,[i,c,s]=r,u=0;if(i.some((t=>0!==e[t]))){for(n in c)a.o(c,n)&&(a.m[n]=c[n]);s&&s(a)}for(t&&t(r);u { + +console.log(\\"blah1\\"); + +/***/ }) + +}]);", + "/release/chunks/async2-none-8e2ba6247847f697c0f1.js": "(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ (() => { + +console.log(\\"blah2\\"); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE1-3d4d60bb40f9e71ffd3d.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE2-f8f4279164ff7b99d24c.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE1-51577f6650bd547636e7.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE2-19aa94fd15e03b9e60b1.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/main-LOCALE1-e03402f03ad27a1ee360.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/create fake namespace object */ +/******/ (() => { +/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +/******/ var leafPrototypes; +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 16: return value when it's Promise-like +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = this(value); +/******/ if(mode & 8) return value; +/******/ if(typeof value === 'object' && value) { +/******/ if((mode & 4) && value.__esModule) return value; +/******/ if((mode & 16) && typeof value.then === 'function') return value; +/******/ } +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ var def = {}; +/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; +/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { +/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); +/******/ } +/******/ def['default'] = () => (value); +/******/ __webpack_require__.d(ns, def); +/******/ return ns; +/******/ }; +/******/ })(); +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"230\\":\\"async1\\",\\"410\\":\\"asyncLoc1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + ({\\"17\\":1,\\"410\\":1}[chunkId]?\\"LOCALE1\\":\\"none\\") + \\"-\\" + {\\"17\\":\\"51577f6650bd547636e7\\",\\"230\\":\\"52f5e6bec29995fa1a9d\\",\\"410\\":\\"3d4d60bb40f9e71ffd3d\\",\\"421\\":\\"8e2ba6247847f697c0f1\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 792: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\"));__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async1.js\\", 23));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async2.js\\", 23)); +/******/ })() +;", + "/release/main-LOCALE2-17e2aed1cdabfd10bc37.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/create fake namespace object */ +/******/ (() => { +/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +/******/ var leafPrototypes; +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 16: return value when it's Promise-like +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = this(value); +/******/ if(mode & 8) return value; +/******/ if(typeof value === 'object' && value) { +/******/ if((mode & 4) && value.__esModule) return value; +/******/ if((mode & 16) && typeof value.then === 'function') return value; +/******/ } +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ var def = {}; +/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; +/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { +/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); +/******/ } +/******/ def['default'] = () => (value); +/******/ __webpack_require__.d(ns, def); +/******/ return ns; +/******/ }; +/******/ })(); +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"230\\":\\"async1\\",\\"410\\":\\"asyncLoc1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + ({\\"17\\":1,\\"410\\":1}[chunkId]?\\"LOCALE2\\":\\"none\\") + \\"-\\" + {\\"17\\":\\"19aa94fd15e03b9e60b1\\",\\"230\\":\\"52f5e6bec29995fa1a9d\\",\\"410\\":\\"f8f4279164ff7b99d24c\\",\\"421\\":\\"8e2ba6247847f697c0f1\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 792: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\"));__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async1.js\\", 23));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async2.js\\", 23)); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks (unminified): Localization Stats 1`] = ` +Object { + "entrypoints": Object { + "main": Object { + "localizedAssets": Object { + "LOCALE1": "main-LOCALE1-e03402f03ad27a1ee360.js", + "LOCALE2": "main-LOCALE2-17e2aed1cdabfd10bc37.js", + }, + }, + }, + "namedChunkGroups": Object { + "asyncLoc1": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc1-LOCALE1-3d4d60bb40f9e71ffd3d.js", + "LOCALE2": "chunks/asyncLoc1-LOCALE2-f8f4279164ff7b99d24c.js", + }, + }, + "asyncLoc2": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc2-LOCALE1-51577f6650bd547636e7.js", + "LOCALE2": "chunks/asyncLoc2-LOCALE2-19aa94fd15e03b9e60b1.js", + }, + }, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncDynamic.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncDynamic.test.ts.snap new file mode 100644 index 00000000000..563155b4604 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncDynamic.test.ts.snap @@ -0,0 +1,775 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression (minified): Content 1`] = ` +Object { + "/release/chunks/async1-none-aa0df6a2ce5075bd1413.js": "(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":()=>{console.log(\\"blah1\\")}}]);", + "/release/chunks/async2-none-0787bdaf294eaa1352a7.js": "(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":()=>{console.log(\\"blah2\\")}}]);", + "/release/chunks/asyncLoc1-LOCALE1-ec559cfe65be3feb737f.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc1-LOCALE2-ec559cfe65be3feb737f.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE1-94f34a63cae41f2d4898.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE2-94f34a63cae41f2d4898.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/mainFourChunks-none-e18327514aa41178845a.js": "(()=>{var e,t,r,o={},n={};function a(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={exports:{}};return o[e](r,r.exports,a),r.exports}a.m=o,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,a.t=function(r,o){if(1&o&&(r=this(r)),8&o)return r;if(\\"object\\"==typeof r&&r){if(4&o&&r.__esModule)return r;if(16&o&&\\"function\\"==typeof r.then)return r}var n=Object.create(null);a.r(n);var i={};e=e||[null,t({}),t([]),t(t)];for(var c=2&o&&r;\\"object\\"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((e=>i[e]=()=>r[e]));return i.default=()=>r,a.d(n,i),n},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,r)=>(a.f[r](e,t),t)),[])),a.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",230:\\"async1\\",410:\\"asyncLoc1\\",421:\\"async2\\"}[e]+\\"-\\"+({17:1,410:1}[e]?self.__locale:\\"none\\")+\\"-\\"+{17:\\"94f34a63cae41f2d4898\\",230:\\"aa0df6a2ce5075bd1413\\",410:\\"ec559cfe65be3feb737f\\",421:\\"0787bdaf294eaa1352a7\\"}[e]+\\".js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},a.l=(e,t,o,n)=>{if(r[e])r[e].push(t);else{var i,c;if(void 0!==o)for(var s=document.getElementsByTagName(\\"script\\"),l=0;l{i.onerror=i.onload=null,clearTimeout(p);var n=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},p=setTimeout(f.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName(\\"script\\");if(r.length)for(var o=r.length-1;o>-1&&(!e||!/^http(s?):/.test(e));)e=r[o--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={882:0};a.f.j=(t,r)=>{var o=a.o(e,t)?e[t]:void 0;if(0!==o)if(o)r.push(o[2]);else{var n=new Promise(((r,n)=>o=e[t]=[r,n]));r.push(o[2]=n);var i=a.p+a.u(t),c=new Error;a.l(i,(r=>{if(a.o(e,t)&&(0!==(o=e[t])&&(e[t]=void 0),o)){var n=r&&(\\"load\\"===r.type?\\"missing\\":r.type),i=r&&r.target&&r.target.src;c.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+n+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=n,c.request=i,o[1](c)}}),\\"chunk-\\"+t,t)}};var t=(t,r)=>{var o,n,[i,c,s]=r,l=0;if(i.some((t=>0!==e[t]))){for(o in c)a.o(c,o)&&(a.m[o]=c[o]);s&&s(a)}for(t&&t(r);l{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",410:\\"asyncLoc1\\"}[e]+\\"-\\"+self.__locale+\\"-\\"+{17:\\"94f34a63cae41f2d4898\\",410:\\"ec559cfe65be3feb737f\\"}[e]+\\".js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);s { + +console.log(\\"blah1\\"); + +/***/ }) + +}]);", + "/release/chunks/async2-none-403f7af31493ef9e3d3b.js": "(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ (() => { + +console.log(\\"blah2\\"); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE1-1e30c626bc07e02e5b94.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE2-1e30c626bc07e02e5b94.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE1-ec0512268756941c4c69.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE2-ec0512268756941c4c69.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/mainFourChunks-none-2cb04125de011f53ae03.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/create fake namespace object */ +/******/ (() => { +/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +/******/ var leafPrototypes; +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 16: return value when it's Promise-like +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = this(value); +/******/ if(mode & 8) return value; +/******/ if(typeof value === 'object' && value) { +/******/ if((mode & 4) && value.__esModule) return value; +/******/ if((mode & 16) && typeof value.then === 'function') return value; +/******/ } +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ var def = {}; +/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; +/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { +/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); +/******/ } +/******/ def['default'] = () => (value); +/******/ __webpack_require__.d(ns, def); +/******/ return ns; +/******/ }; +/******/ })(); +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"230\\":\\"async1\\",\\"410\\":\\"asyncLoc1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + ({\\"17\\":1,\\"410\\":1}[chunkId]?self.__locale:\\"none\\") + \\"-\\" + {\\"17\\":\\"ec0512268756941c4c69\\",\\"230\\":\\"0b9a18e34a186770e865\\",\\"410\\":\\"1e30c626bc07e02e5b94\\",\\"421\\":\\"403f7af31493ef9e3d3b\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 882: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\"));__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async1.js\\", 23));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async2.js\\", 23)); +/******/ })() +;", + "/release/mainTwoChunks-none-875e1b1f0531ec0a6154.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"410\\":\\"asyncLoc1\\"}[chunkId] + \\"-\\" + self.__locale + \\"-\\" + {\\"17\\":\\"ec0512268756941c4c69\\",\\"410\\":\\"1e30c626bc07e02e5b94\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\")); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression (unminified): Localization Stats 1`] = ` +Object { + "entrypoints": Object {}, + "namedChunkGroups": Object { + "asyncLoc1": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc1-LOCALE1-1e30c626bc07e02e5b94.js", + "LOCALE2": "chunks/asyncLoc1-LOCALE2-1e30c626bc07e02e5b94.js", + }, + }, + "asyncLoc2": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc2-LOCALE1-ec0512268756941c4c69.js", + "LOCALE2": "chunks/asyncLoc2-LOCALE2-ec0512268756941c4c69.js", + }, + }, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncNonHashed.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncNonHashed.test.ts.snap new file mode 100644 index 00000000000..284fe680c7e --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/MixedAsyncNonHashed.test.ts.snap @@ -0,0 +1,819 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (minified): Content 1`] = ` +Object { + "/release/chunks/async1-none.js": "(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./a/async1.js\\":()=>{console.log(\\"blah1\\")}}]);", + "/release/chunks/async2-none.js": "(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./a/async2.js\\":()=>{console.log(\\"blah2\\")}}]);", + "/release/chunks/asyncLoc1-LOCALE1.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc1-LOCALE2.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[410],{\\"./a/asyncLoc1.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test,o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE1.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"blah\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"something else\\"}}}]);", + "/release/chunks/asyncLoc2-LOCALE2.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[17],{\\"./a/asyncLoc2.js\\":(s,_,e)=>{e.r(_);var n=e(\\"./a/strings1.loc.json\\"),o=e(\\"./a/strings2.loc.json\\");console.log(n.A.test+o.A.another)},\\"./a/strings1.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={test:\\"baz\\"}},\\"./a/strings2.loc.json\\":(s,_,e)=>{e.d(_,{A:()=>n});const n={another:\\"some random translation\\"}}}]);", + "/release/main-LOCALE1.js": "(()=>{var e,t,r,n={},o={};function a(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return n[e](r,r.exports,a),r.exports}a.m=n,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,a.t=function(r,n){if(1&n&&(r=this(r)),8&n)return r;if(\\"object\\"==typeof r&&r){if(4&n&&r.__esModule)return r;if(16&n&&\\"function\\"==typeof r.then)return r}var o=Object.create(null);a.r(o);var i={};e=e||[null,t({}),t([]),t(t)];for(var c=2&n&&r;\\"object\\"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((e=>i[e]=()=>r[e]));return i.default=()=>r,a.d(o,i),o},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,r)=>(a.f[r](e,t),t)),[])),a.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",230:\\"async1\\",410:\\"asyncLoc1\\",421:\\"async2\\"}[e]+\\"-\\"+({17:1,410:1}[e]?\\"LOCALE1\\":\\"none\\")+\\".js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},a.l=(e,t,n,o)=>{if(r[e])r[e].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{i.onerror=i.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),t)return t(n)},p=setTimeout(f.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName(\\"script\\");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={792:0};a.f.j=(t,r)=>{var n=a.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var o=new Promise(((r,o)=>n=e[t]=[r,o]));r.push(n[2]=o);var i=a.p+a.u(t),c=new Error;a.l(i,(r=>{if(a.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var o=r&&(\\"load\\"===r.type?\\"missing\\":r.type),i=r&&r.target&&r.target.src;c.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+o+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=o,c.request=i,n[1](c)}}),\\"chunk-\\"+t,t)}};var t=(t,r)=>{var n,o,[i,c,s]=r,u=0;if(i.some((t=>0!==e[t]))){for(n in c)a.o(c,n)&&(a.m[n]=c[n]);s&&s(a)}for(t&&t(r);u{var e,t,r,n={},o={};function a(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return n[e](r,r.exports,a),r.exports}a.m=n,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,a.t=function(r,n){if(1&n&&(r=this(r)),8&n)return r;if(\\"object\\"==typeof r&&r){if(4&n&&r.__esModule)return r;if(16&n&&\\"function\\"==typeof r.then)return r}var o=Object.create(null);a.r(o);var i={};e=e||[null,t({}),t([]),t(t)];for(var c=2&n&&r;\\"object\\"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((e=>i[e]=()=>r[e]));return i.default=()=>r,a.d(o,i),o},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,r)=>(a.f[r](e,t),t)),[])),a.u=e=>\\"chunks/\\"+{17:\\"asyncLoc2\\",230:\\"async1\\",410:\\"asyncLoc1\\",421:\\"async2\\"}[e]+\\"-\\"+({17:1,410:1}[e]?\\"LOCALE2\\":\\"none\\")+\\".js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},a.l=(e,t,n,o)=>{if(r[e])r[e].push(t);else{var i,c;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),u=0;u{i.onerror=i.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),t)return t(n)},p=setTimeout(f.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName(\\"script\\");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={792:0};a.f.j=(t,r)=>{var n=a.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var o=new Promise(((r,o)=>n=e[t]=[r,o]));r.push(n[2]=o);var i=a.p+a.u(t),c=new Error;a.l(i,(r=>{if(a.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var o=r&&(\\"load\\"===r.type?\\"missing\\":r.type),i=r&&r.target&&r.target.src;c.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+o+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=o,c.request=i,n[1](c)}}),\\"chunk-\\"+t,t)}};var t=(t,r)=>{var n,o,[i,c,s]=r,u=0;if(i.some((t=>0!==e[t]))){for(n in c)a.o(c,n)&&(a.m[n]=c[n]);s&&s(a)}for(t&&t(r);u { + +console.log(\\"blah1\\"); + +/***/ }) + +}]);", + "/release/chunks/async2-none.js": "(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./a/async2.js\\": +/***/ (() => { + +console.log(\\"blah2\\"); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE1.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc1-LOCALE2.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[410],{ + +/***/ \\"./a/asyncLoc1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test, _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE1.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"blah\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"something else\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/chunks/asyncLoc2-LOCALE2.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[17],{ + +/***/ \\"./a/asyncLoc2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\\"./a/strings1.loc.json\\"); +/* harmony import */ var _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\\"./a/strings2.loc.json\\"); + console.log(_strings1_loc_json__WEBPACK_IMPORTED_MODULE_0__/* [\\"default\\"] */ .A.test + _strings2_loc_json__WEBPACK_IMPORTED_MODULE_1__/* [\\"default\\"] */ .A.another); + +/***/ }), + +/***/ \\"./a/strings1.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"test\\":\\"baz\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }), + +/***/ \\"./a/strings2.loc.json\\": +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const strings = {\\"another\\":\\"some random translation\\"}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (strings); + +/***/ }) + +}]);", + "/release/main-LOCALE1.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/create fake namespace object */ +/******/ (() => { +/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +/******/ var leafPrototypes; +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 16: return value when it's Promise-like +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = this(value); +/******/ if(mode & 8) return value; +/******/ if(typeof value === 'object' && value) { +/******/ if((mode & 4) && value.__esModule) return value; +/******/ if((mode & 16) && typeof value.then === 'function') return value; +/******/ } +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ var def = {}; +/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; +/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { +/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); +/******/ } +/******/ def['default'] = () => (value); +/******/ __webpack_require__.d(ns, def); +/******/ return ns; +/******/ }; +/******/ })(); +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"230\\":\\"async1\\",\\"410\\":\\"asyncLoc1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + ({\\"17\\":1,\\"410\\":1}[chunkId]?\\"LOCALE1\\":\\"none\\") + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 792: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\"));__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async1.js\\", 23));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async2.js\\", 23)); +/******/ })() +;", + "/release/main-LOCALE2.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/create fake namespace object */ +/******/ (() => { +/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +/******/ var leafPrototypes; +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 16: return value when it's Promise-like +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = this(value); +/******/ if(mode & 8) return value; +/******/ if(typeof value === 'object' && value) { +/******/ if((mode & 4) && value.__esModule) return value; +/******/ if((mode & 16) && typeof value.then === 'function') return value; +/******/ } +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ var def = {}; +/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; +/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { +/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); +/******/ } +/******/ def['default'] = () => (value); +/******/ __webpack_require__.d(ns, def); +/******/ return ns; +/******/ }; +/******/ })(); +/******/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"chunks/\\" + {\\"17\\":\\"asyncLoc2\\",\\"230\\":\\"async1\\",\\"410\\":\\"asyncLoc1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-\\" + ({\\"17\\":1,\\"410\\":1}[chunkId]?\\"LOCALE2\\":\\"none\\") + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 792: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.e(/* import() | asyncLoc1 */ 410).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc1.js\\"));__webpack_require__.e(/* import() | asyncLoc2 */ 17).then(__webpack_require__.bind(__webpack_require__, \\"./a/asyncLoc2.js\\"));__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async1.js\\", 23));__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.t.bind(__webpack_require__, \\"./a/async2.js\\", 23)); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (unminified): Localization Stats 1`] = ` +Object { + "entrypoints": Object { + "main": Object { + "localizedAssets": Object { + "LOCALE1": "main-LOCALE1.js", + "LOCALE2": "main-LOCALE2.js", + }, + }, + }, + "namedChunkGroups": Object { + "asyncLoc1": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc1-LOCALE1.js", + "LOCALE2": "chunks/asyncLoc1-LOCALE2.js", + }, + }, + "asyncLoc2": Object { + "localizedAssets": Object { + "LOCALE1": "chunks/asyncLoc2-LOCALE1.js", + "LOCALE2": "chunks/asyncLoc2-LOCALE2.js", + }, + }, + }, +} +`; + +exports[`LocalizationPlugin Handles async localized and non-localized chunks with a runtime locale expression and without an asset filename hash (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/NoLocalizedFiles.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/NoLocalizedFiles.test.ts.snap new file mode 100644 index 00000000000..88d86535ff2 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/NoLocalizedFiles.test.ts.snap @@ -0,0 +1,567 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocalizationPlugin Handles non-localized compilations (minified): Content 1`] = ` +Object { + "/release/async1-none-095e08ce2f180ba75e57.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./async1.js\\":(o,s,c)=>{function e(){console.log(\\"foo1\\")}c.r(s),c.d(s,{foo:()=>e})}}]);", + "/release/async2-none-53087f3320703e9ab170.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./async2.js\\":(o,s,c)=>{function e(){console.log(\\"foo2\\")}c.r(s),c.d(s,{foo:()=>e})}}]);", + "/release/mainSingleChunk-none-c7fb3536485971946a5b.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"async1-none-095e08ce2f180ba75e57.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var c=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,c]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);c&&c(o)}for(r&&r(t);se.foo()))})();", + "/release/mainTwoChunks-none-c504d865c6bb792fa664.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>({230:\\"async1\\",421:\\"async2\\"}[e]+\\"-none-\\"+{230:\\"095e08ce2f180ba75e57\\",421:\\"53087f3320703e9ab170\\"}[e]+\\".js\\"),o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,c;if(void 0!==n)for(var l=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),c&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),c=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;c.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",c.name=\\"ChunkLoadError\\",c.type=a,c.request=i,n[1](c)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,c,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);l&&l(o)}for(r&&r(t);se.foo())),o.e(421).then(o.bind(o,\\"./async2.js\\")).then((e=>e.foo()))})();", +} +`; + +exports[`LocalizationPlugin Handles non-localized compilations (minified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles non-localized compilations (minified): Warnings 1`] = `Array []`; + +exports[`LocalizationPlugin Handles non-localized compilations (unminified): Content 1`] = ` +Object { + "/release/async1-none-500fdaa5193c2a4703d3.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ foo: () => (/* binding */ foo) +/* harmony export */ }); +function foo() { console.log('foo1'); } + +/***/ }) + +}]);", + "/release/async2-none-05090276588271c11ac2.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ foo: () => (/* binding */ foo) +/* harmony export */ }); +function foo() { console.log('foo2'); } + +/***/ }) + +}]);", + "/release/mainSingleChunk-none-945c9f2111d1eee14432.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + \\"async1\\" + \\"-none-\\" + \\"500fdaa5193c2a4703d3\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +console.log(\\"Do stuff\\");__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./async1.js\\")).then(mod => mod.foo()); +/******/ })() +;", + "/release/mainTwoChunks-none-b88fdd1fe1dc3a334289.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\"-none-\\" + {\\"230\\":\\"500fdaa5193c2a4703d3\\",\\"421\\":\\"05090276588271c11ac2\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +console.log(\\"Do stuff\\");__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./async1.js\\")).then(mod => mod.foo());__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./async2.js\\")).then(mod => mod.foo()); +/******/ })() +;", +} +`; + +exports[`LocalizationPlugin Handles non-localized compilations (unminified): Errors 1`] = `Array []`; + +exports[`LocalizationPlugin Handles non-localized compilations (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/test/__snapshots__/NonHashedNonLocalizedAssets.test.ts.snap b/webpack/webpack5-localization-plugin/src/test/__snapshots__/NonHashedNonLocalizedAssets.test.ts.snap new file mode 100644 index 00000000000..f56947719b8 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/test/__snapshots__/NonHashedNonLocalizedAssets.test.ts.snap @@ -0,0 +1,567 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (minified): Content 1`] = ` +Object { + "/release/async1.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[230],{\\"./async1.js\\":(o,s,c)=>{function e(){console.log(\\"foo1\\")}c.r(s),c.d(s,{foo:()=>e})}}]);", + "/release/async2.js": "\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[421],{\\"./async2.js\\":(o,s,c)=>{function e(){console.log(\\"foo2\\")}c.r(s),c.d(s,{foo:()=>e})}}]);", + "/release/mainSingleChunk.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>\\"async1.js\\",o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var c=document.getElementsByTagName(\\"script\\"),s=0;s{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={331:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,c]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);c&&c(o)}for(r&&r(t);se.foo()))})();", + "/release/mainTwoChunks.js": "(()=>{var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var a=t[e]={exports:{}};return r[e](a,a.exports,o),a.exports}o.m=r,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>({230:\\"async1\\",421:\\"async2\\"}[e]+\\".js\\"),o.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},o.l=(r,t,n,a)=>{if(e[r])e[r].push(t);else{var i,l;if(void 0!==n)for(var s=document.getElementsByTagName(\\"script\\"),c=0;c{i.onerror=i.onload=null,clearTimeout(d);var n=e[r];if(delete e[r],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach((e=>e(o))),t)return t(o)},d=setTimeout(p.bind(null,void 0,{type:\\"timeout\\",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},o.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+\\"\\");var r=o.g.document;if(!e&&r&&(r.currentScript&&\\"SCRIPT\\"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName(\\"script\\");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),o.p=e})(),(()=>{var e={580:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),l=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&(\\"load\\"===t.type?\\"missing\\":t.type),i=t&&t.target&&t.target.src;l.message=\\"Loading chunk \\"+r+\\" failed.\\\\n(\\"+a+\\": \\"+i+\\")\\",l.name=\\"ChunkLoadError\\",l.type=a,l.request=i,n[1](l)}}),\\"chunk-\\"+r,r)}};var r=(r,t)=>{var n,a,[i,l,s]=t,c=0;if(i.some((r=>0!==e[r]))){for(n in l)o.o(l,n)&&(o.m[n]=l[n]);s&&s(o)}for(r&&r(t);ce.foo())),o.e(421).then(o.bind(o,\\"./async2.js\\")).then((e=>e.foo()))})();", +} +`; + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (minified): Errors 1`] = `Array []`; + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (minified): Warnings 1`] = `Array []`; + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (unminified): Content 1`] = ` +Object { + "/release/async1.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[230],{ + +/***/ \\"./async1.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ foo: () => (/* binding */ foo) +/* harmony export */ }); +function foo() { console.log('foo1'); } + +/***/ }) + +}]);", + "/release/async2.js": "\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[421],{ + +/***/ \\"./async2.js\\": +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ foo: () => (/* binding */ foo) +/* harmony export */ }); +function foo() { console.log('foo2'); } + +/***/ }) + +}]);", + "/release/mainSingleChunk.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + \\"async1\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 331: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +console.log(\\"Do stuff\\");__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./async1.js\\")).then(mod => mod.foo()); +/******/ })() +;", + "/release/mainTwoChunks.js": "/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + {\\"230\\":\\"async1\\",\\"421\\":\\"async2\\"}[chunkId] + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 580: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +console.log(\\"Do stuff\\");__webpack_require__.e(/* import() | async1 */ 230).then(__webpack_require__.bind(__webpack_require__, \\"./async1.js\\")).then(mod => mod.foo());__webpack_require__.e(/* import() | async2 */ 421).then(__webpack_require__.bind(__webpack_require__, \\"./async2.js\\")).then(mod => mod.foo()); +/******/ })() +;", +} +`; + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (unminified): Errors 1`] = `Array []`; + +exports[`TrueHashPlugin Handles non-localized non-hashed compilations (unminified): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-localization-plugin/src/trueHashes.ts b/webpack/webpack5-localization-plugin/src/trueHashes.ts new file mode 100644 index 00000000000..8b9ec93547e --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/trueHashes.ts @@ -0,0 +1,305 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { default as webpack, Compilation, Chunk, Asset, sources, util } from 'webpack'; + +import { Text } from '@rushstack/node-core-library'; + +import type { ILocalizedWebpackChunk } from './webpackInterfaces'; +import { chunkIsJs } from './utilities/chunkUtilities'; + +interface IHashReplacement { + existingHash: string; + trueHashByLocale: string | Record | undefined; +} + +type WebpackHash = ReturnType; + +export type HashFn = (contents: string | Buffer) => string; + +export interface IGetHashFunctionOptions { + thisWebpack: typeof webpack; + compilation: Compilation; +} + +export function getHashFunction({ thisWebpack, compilation }: IGetHashFunctionOptions): HashFn { + const { hashFunction = 'md5', hashDigest = 'hex', hashDigestLength, hashSalt } = compilation.outputOptions; + return (contents: string | Buffer) => { + const hash: WebpackHash = thisWebpack.util.createHash(hashFunction); + if (hashSalt) { + hash.update(hashSalt, 'utf-8'); + } + + return hash.update(contents).digest(hashDigest).toString().slice(0, hashDigestLength); + }; +} + +export interface IUpdateAssetHashesOptions { + thisWebpack: typeof webpack; + compilation: Compilation; + hashFn: HashFn; + filesByChunkName?: Map>; +} + +interface IProcessChunkAssetResult { + trueHash: string; + newJsFilename: string; +} + +export function updateAssetHashes({ + thisWebpack, + compilation, + hashFn, + filesByChunkName +}: IUpdateAssetHashesOptions): void { + const unprocessedDependenciesByChunk: Map> = new Map(); + const dependenciesByChunk: Map> = new Map(); + const dependentsByChunk: Map> = new Map(); + const unprocessedChunks: Set = new Set(); + const nonJsChunks: Set = new Set(); + + for (const chunk of compilation.chunks) { + if (!chunkIsJs(chunk, compilation.chunkGraph)) { + nonJsChunks.add(chunk); + } else { + unprocessedChunks.add(chunk); + } + } + + for (const chunk of compilation.chunks) { + let unprocessedDependencies: Set | undefined = unprocessedDependenciesByChunk.get(chunk); + if (!unprocessedDependencies) { + unprocessedDependencies = new Set(); + unprocessedDependenciesByChunk.set(chunk, unprocessedDependencies); + } + + let dependencies: Set | undefined = dependenciesByChunk.get(chunk); + if (!dependencies) { + dependencies = new Set(); + dependenciesByChunk.set(chunk, dependencies); + } + + if (chunk.hasRuntime()) { + for (const asyncChunk of chunk.getAllAsyncChunks()) { + if (!nonJsChunks.has(asyncChunk)) { + unprocessedDependencies.add(asyncChunk); + dependencies.add(asyncChunk); + + let dependents: Set | undefined = dependentsByChunk.get(asyncChunk); + if (!dependents) { + dependents = new Set(); + dependentsByChunk.set(asyncChunk, dependents); + } + + dependents.add(chunk); + + if (!unprocessedChunks.has(asyncChunk)) { + compilation.errors.push( + new thisWebpack.WebpackError( + `Found an async chunk that was not included in the compilation: ${asyncChunk.id} ` + + `(reason: ${asyncChunk.chunkReason}).` + ) + ); + } + } + } + } + } + + const hashReplacementsByChunk: Map = new Map(); + let previousSize: number = -1; + while (unprocessedChunks.size > 0) { + const currentSize: number = unprocessedChunks.size; + if (currentSize === previousSize) { + compilation.errors.push( + new thisWebpack.WebpackError( + `Detected a cycle in the chunk dependencies. This should not be possible.` + ) + ); + + break; + } + + previousSize = currentSize; + + for (const chunk of unprocessedChunks) { + if (unprocessedDependenciesByChunk.get(chunk)?.size === 0) { + // TODO: do we need to check if the chunk is rendered? + if (!chunk.renderedHash) { + compilation.errors.push( + new thisWebpack.WebpackError(`Could not find the hash for chunk ${chunk.id}.`) + ); + } else { + const existingHash: string = chunk.contentHash.javascript; + const chunkDependencies: Set | undefined = dependenciesByChunk.get(chunk); + if (!chunkDependencies) { + compilation.errors.push( + new thisWebpack.WebpackError(`Could not find dependencies for chunk ${chunk.id}.`) + ); + } else { + function processChunkAsset( + jsAssetName: string, + locale: string | undefined + ): IProcessChunkAssetResult | undefined { + const asset: Readonly | undefined = compilation.getAsset(jsAssetName); + if (!asset) { + compilation.errors.push( + new thisWebpack.WebpackError(`Could not find asset "${jsAssetName}" for chunk ${chunk.id}.`) + ); + } else { + let assetSource: sources.Source = asset.source; + const assetName: string = asset.name; + if (chunkDependencies!.size > 0) { + const relevantHashReplacements: Map = new Map(); + let hasAnyReplacements: boolean = false; + for (const dependency of chunkDependencies!) { + const asyncChunkHashReplacements: IHashReplacement | undefined = + hashReplacementsByChunk.get(dependency); + if (!asyncChunkHashReplacements) { + compilation.errors.push( + new thisWebpack.WebpackError( + `Could not find hash replacements for chunk ${dependency.id}.` + ) + ); + } else { + const { existingHash: otherChunkExistingHash, trueHashByLocale } = + asyncChunkHashReplacements; + let replacementHash: string | undefined; + if (typeof trueHashByLocale === 'object') { + if (locale) { + replacementHash = trueHashByLocale[locale]; + } + } else { + replacementHash = trueHashByLocale; + } + + if (replacementHash) { + if (relevantHashReplacements.has(otherChunkExistingHash)) { + compilation.errors.push( + new thisWebpack.WebpackError( + `Found multiple replacements for hash ${otherChunkExistingHash} ` + + `in chunk ${chunk.id}.` + ) + ); + } else { + relevantHashReplacements.set(otherChunkExistingHash, replacementHash); + hasAnyReplacements = true; + } + } + } + } + + if (hasAnyReplacements) { + const sourceString: string = assetSource.source().toString(); + const replaceSource: sources.ReplaceSource = new thisWebpack.sources.ReplaceSource( + assetSource, + assetName + ); + + const regexp: RegExp = new RegExp( + Array.from(relevantHashReplacements.keys(), (hashToReplace) => + Text.escapeRegExp(hashToReplace) + ).join('|'), + 'g' + ); + let match: RegExpMatchArray | null; + while ((match = regexp.exec(sourceString)) !== null) { + const { 0: originalHash, index } = match; + const matchStart: number = index!; + const matchEnd: number = matchStart + originalHash.length - 1; + const replacement: string = relevantHashReplacements.get(originalHash)!; + replaceSource.replace(matchStart, matchEnd, replacement); + } + + assetSource = new thisWebpack.sources.CachedSource(replaceSource); + compilation.updateAsset(jsAssetName, assetSource); + } + } + + if (jsAssetName.includes(existingHash)) { + const trueHash: string = hashFn(assetSource.buffer()); + if (trueHash !== existingHash) { + const newJsFilename: string = jsAssetName.replace(existingHash, trueHash); + + compilation.renameAsset(jsAssetName, newJsFilename); + + if (locale) { + const filesForChunkName: Record | undefined = chunk.name + ? filesByChunkName?.get(chunk.name) + : undefined; + + if (filesForChunkName) { + filesForChunkName[locale] = newJsFilename; + } + } + + return { + trueHash, + newJsFilename + }; + } + } + } + } + + const localizedFiles: Record | undefined = (chunk as ILocalizedWebpackChunk) + .localizedFiles; + if (localizedFiles) { + const trueHashByLocale: Record = {}; + hashReplacementsByChunk.set(chunk, { + existingHash, + trueHashByLocale + }); + for (const [locale, jsAssetName] of Object.entries(localizedFiles)) { + const processAssetResult: IProcessChunkAssetResult | undefined = processChunkAsset( + jsAssetName, + locale + ); + if (processAssetResult) { + const { trueHash, newJsFilename } = processAssetResult; + trueHashByLocale[locale] = trueHash; + localizedFiles[locale] = newJsFilename; + } + } + } else { + const assetNames: string[] = Array.from(chunk.files); + let jsAssetName: string | undefined; + for (const assetName of assetNames) { + if (assetName.endsWith('.js')) { + if (jsAssetName) { + compilation.errors.push( + new thisWebpack.WebpackError(`Found multiple .js assets for chunk ${chunk.id}.`) + ); + } else { + jsAssetName = assetName; + } + } + } + + if (!jsAssetName) { + compilation.errors.push( + new thisWebpack.WebpackError(`Could not find a .js asset for chunk ${chunk.id}.`) + ); + } else { + const { trueHash, newJsFilename } = processChunkAsset(jsAssetName, undefined) ?? {}; + hashReplacementsByChunk.set(chunk, { existingHash, trueHashByLocale: trueHash }); + if (newJsFilename) { + chunk.files.delete(jsAssetName); + chunk.files.add(newJsFilename); + } + } + } + } + + unprocessedChunks.delete(chunk); + const dependents: Set | undefined = dependentsByChunk.get(chunk); + if (dependents) { + for (const dependent of dependents) { + unprocessedDependenciesByChunk.get(dependent)?.delete(chunk); + } + } + } + } + } + } +} diff --git a/webpack/webpack5-localization-plugin/src/utilities/Constants.ts b/webpack/webpack5-localization-plugin/src/utilities/Constants.ts new file mode 100644 index 00000000000..0e01025361f --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/utilities/Constants.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. + +export const LOCALE_FILENAME_TOKEN: '[locale]' = '[locale]'; +export const LOCALE_FILENAME_TOKEN_REGEX: RegExp = /\[locale\]/gi; +export const NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN: '[no-locale-file]' = '[no-locale-file]'; +export const NO_LOCALE_SOURCE_MAP_FILENAME_TOKEN_REGEX: RegExp = /\[no-locale-file\]/gi; +export const STRING_PLACEHOLDER_PREFIX: '_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9' = + '_LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9'; + +export const RESOURCE_FILE_NAME_REGEXP: RegExp = /\.(resx|resx\.json|loc\.json|resjson)$/i; + +export const STRING_PLACEHOLDER_LABEL: 'A' = 'A'; +export const LOCALE_NAME_PLACEHOLDER_LABEL: 'B' = 'B'; +export const JSONP_PLACEHOLDER_LABEL: 'C' = 'C'; +export const CUSTOM_PLACEHOLDER_LABEL: 'D' = 'D'; + +// _LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_B_ +export const LOCALE_NAME_PLACEHOLDER: `${typeof STRING_PLACEHOLDER_PREFIX}_${typeof LOCALE_NAME_PLACEHOLDER_LABEL}_` = `${STRING_PLACEHOLDER_PREFIX}_${LOCALE_NAME_PLACEHOLDER_LABEL}_`; + +// _LOCALIZED_STRING_f12dy0i7_n4bo_dqwj_39gf_sasqehjmihz9_C_ +export const JSONP_PLACEHOLDER: `${typeof STRING_PLACEHOLDER_PREFIX}_${typeof JSONP_PLACEHOLDER_LABEL}_` = `${STRING_PLACEHOLDER_PREFIX}_${JSONP_PLACEHOLDER_LABEL}_`; diff --git a/webpack/webpack5-localization-plugin/src/utilities/EntityMarker.ts b/webpack/webpack5-localization-plugin/src/utilities/EntityMarker.ts new file mode 100644 index 00000000000..cd3e8675045 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/utilities/EntityMarker.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. + +const MARKS: WeakMap = new WeakMap(); + +/** + * Marks a webpack entity as containing or not containing localized resources. + */ +export function markEntity(entity: object, value: boolean): void { + MARKS.set(entity, value); +} + +/** + * Read the cache marker for whether or not the entity contains localized resources. + */ +export function getMark(entity: object): boolean | undefined { + return MARKS.get(entity); +} diff --git a/webpack/webpack5-localization-plugin/src/utilities/LoaderTerminalProvider.ts b/webpack/webpack5-localization-plugin/src/utilities/LoaderTerminalProvider.ts new file mode 100644 index 00000000000..49520cb30be --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/utilities/LoaderTerminalProvider.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 { LoaderContext } from 'webpack'; + +import { type ITerminalProvider, TerminalProviderSeverity } from '@rushstack/terminal'; + +export class LoaderTerminalProvider { + public static getTerminalProviderForLoader(loaderContext: LoaderContext<{}>): ITerminalProvider { + return { + supportsColor: false, + eolCharacter: '\n', + write: (data: string, severity: TerminalProviderSeverity) => { + switch (severity) { + case TerminalProviderSeverity.error: { + loaderContext.emitError(new Error(data)); + break; + } + + case TerminalProviderSeverity.warning: { + loaderContext.emitWarning(new Error(data)); + break; + } + } + } + }; + } +} diff --git a/webpack/webpack5-localization-plugin/src/utilities/chunkUtilities.ts b/webpack/webpack5-localization-plugin/src/utilities/chunkUtilities.ts new file mode 100644 index 00000000000..d9334fb7865 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/utilities/chunkUtilities.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. + +import type { Chunk, ChunkGraph } from 'webpack'; + +export function chunkIsJs(chunk: Chunk, chunkGraph: ChunkGraph): boolean { + return !!chunkGraph.getChunkModulesIterableBySourceType(chunk, 'javascript'); +} diff --git a/webpack/webpack5-localization-plugin/src/webpackInterfaces.ts b/webpack/webpack5-localization-plugin/src/webpackInterfaces.ts new file mode 100644 index 00000000000..8fdbf641ff0 --- /dev/null +++ b/webpack/webpack5-localization-plugin/src/webpackInterfaces.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 type { Chunk, Compilation } from 'webpack'; + +/** + * @public + */ +export interface ILocalizedWebpackChunk extends Chunk { + localizedFiles?: { [locale: string]: string }; +} + +export type IAssetPathOptions = Parameters[1] & { + locale?: string; +}; diff --git a/webpack/webpack5-localization-plugin/tsconfig.json b/webpack/webpack5-localization-plugin/tsconfig.json new file mode 100644 index 00000000000..7902d0431ea --- /dev/null +++ b/webpack/webpack5-localization-plugin/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019" + } +} diff --git a/webpack/webpack5-module-minifier-plugin/.npmignore b/webpack/webpack5-module-minifier-plugin/.npmignore new file mode 100644 index 00000000000..bc349f9a4be --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/.npmignore @@ -0,0 +1,32 @@ +# 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/** + +!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 + +# 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/webpack/webpack5-module-minifier-plugin/CHANGELOG.json b/webpack/webpack5-module-minifier-plugin/CHANGELOG.json new file mode 100644 index 00000000000..10ea9912392 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/CHANGELOG.json @@ -0,0 +1,4780 @@ +{ + "name": "@rushstack/webpack5-module-minifier-plugin", + "entries": [ + { + "version": "5.6.7", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.7`" + } + ] + } + }, + { + "version": "5.6.6", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.6`" + } + ] + } + }, + { + "version": "5.6.5", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.5`" + } + ] + } + }, + { + "version": "5.6.4", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.4`" + } + ] + } + }, + { + "version": "5.6.3", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.3`" + } + ] + } + }, + { + "version": "5.6.2", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.2`" + } + ] + } + }, + { + "version": "5.6.1", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.6.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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.1`" + } + ] + } + }, + { + "version": "5.6.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.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/worker-pool\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.8.0`" + } + ] + } + }, + { + "version": "5.5.114", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.114", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.30`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.30`" + } + ] + } + }, + { + "version": "5.5.113", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.113", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.29`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.29`" + } + ] + } + }, + { + "version": "5.5.112", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.112", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.28`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.28`" + } + ] + } + }, + { + "version": "5.5.111", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.111", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.27`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.27`" + } + ] + } + }, + { + "version": "5.5.110", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.110", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.26`" + } + ] + } + }, + { + "version": "5.5.109", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.109", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.25`" + } + ] + } + }, + { + "version": "5.5.108", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.108", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.24`" + } + ] + } + }, + { + "version": "5.5.107", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.107", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.23`" + } + ] + } + }, + { + "version": "5.5.106", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.106", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.22`" + } + ] + } + }, + { + "version": "5.5.105", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.105", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.21`" + } + ] + } + }, + { + "version": "5.5.104", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.104", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.20`" + } + ] + } + }, + { + "version": "5.5.103", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.103", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.19`" + } + ] + } + }, + { + "version": "5.5.102", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.102", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.18`" + } + ] + } + }, + { + "version": "5.5.101", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.101", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.17`" + } + ] + } + }, + { + "version": "5.5.100", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.100", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.16`" + } + ] + } + }, + { + "version": "5.5.99", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.99", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.15`" + } + ] + } + }, + { + "version": "5.5.98", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.98", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.14`" + } + ] + } + }, + { + "version": "5.5.97", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.97", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.13`" + } + ] + } + }, + { + "version": "5.5.96", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.96", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.12`" + } + ] + } + }, + { + "version": "5.5.95", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.95", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.11`" + } + ] + } + }, + { + "version": "5.5.94", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.94", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.10`" + } + ] + } + }, + { + "version": "5.5.93", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.93", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.9`" + } + ] + } + }, + { + "version": "5.5.92", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.92", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.8`" + } + ] + } + }, + { + "version": "5.5.91", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.91", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.7`" + } + ] + } + }, + { + "version": "5.5.90", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.90", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.6`" + } + ] + } + }, + { + "version": "5.5.89", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.89", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.5`" + } + ] + } + }, + { + "version": "5.5.88", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.88", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.4`" + } + ] + } + }, + { + "version": "5.5.87", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.87", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.3`" + } + ] + } + }, + { + "version": "5.5.86", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.86", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.2`" + } + ] + } + }, + { + "version": "5.5.85", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.85", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.1`" + } + ] + } + }, + { + "version": "5.5.84", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.84", + "date": "Wed, 22 Jan 2025 03:03:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.7.0`" + } + ] + } + }, + { + "version": "5.5.83", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.83", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.36`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.36`" + } + ] + } + }, + { + "version": "5.5.82", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.82", + "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`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.35`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.35`" + } + ] + } + }, + { + "version": "5.5.81", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.81", + "date": "Sat, 14 Dec 2024 01:11:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.79`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.34`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.34`" + } + ] + } + }, + { + "version": "5.5.80", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.80", + "date": "Mon, 09 Dec 2024 20:31:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.78`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.33`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.33`" + } + ] + } + }, + { + "version": "5.5.79", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.79", + "date": "Tue, 03 Dec 2024 16:11:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.77`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.32`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.32`" + } + ] + } + }, + { + "version": "5.5.78", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.78", + "date": "Sat, 23 Nov 2024 01:18:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.76`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.31`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.31`" + } + ] + } + }, + { + "version": "5.5.77", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.77", + "date": "Fri, 22 Nov 2024 01:10:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.75`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.30`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.30`" + } + ] + } + }, + { + "version": "5.5.76", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.76", + "date": "Thu, 24 Oct 2024 00:15:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.74`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.29`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.29`" + } + ] + } + }, + { + "version": "5.5.75", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.75", + "date": "Mon, 21 Oct 2024 18:50:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.73`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.28`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.28`" + } + ] + } + }, + { + "version": "5.5.74", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.74", + "date": "Thu, 17 Oct 2024 08:35:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.72`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.27`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.27`" + } + ] + } + }, + { + "version": "5.5.73", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.73", + "date": "Tue, 15 Oct 2024 00:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.71`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.26`" + } + ] + } + }, + { + "version": "5.5.72", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.72", + "date": "Wed, 02 Oct 2024 00:11:19 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure compatibility with webpack 5.95.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.70`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.25`" + } + ] + } + }, + { + "version": "5.5.71", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.71", + "date": "Tue, 01 Oct 2024 00:11:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.69`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.24`" + } + ] + } + }, + { + "version": "5.5.70", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.70", + "date": "Mon, 30 Sep 2024 15:12:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.68`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.23`" + } + ] + } + }, + { + "version": "5.5.69", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.69", + "date": "Fri, 13 Sep 2024 00:11:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.67`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.22`" + } + ] + } + }, + { + "version": "5.5.68", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.68", + "date": "Tue, 10 Sep 2024 20:08:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.66`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.21`" + } + ] + } + }, + { + "version": "5.5.67", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.67", + "date": "Wed, 21 Aug 2024 05:43:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.65`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.67.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.20`" + } + ] + } + }, + { + "version": "5.5.66", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.66", + "date": "Mon, 12 Aug 2024 22:16:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.64`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.19`" + } + ] + } + }, + { + "version": "5.5.65", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.65", + "date": "Fri, 02 Aug 2024 17:26:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.63`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.18`" + } + ] + } + }, + { + "version": "5.5.64", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.64", + "date": "Sat, 27 Jul 2024 00:10:27 GMT", + "comments": { + "patch": [ + { + "comment": "Include CHANGELOG.md in published releases again" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.62`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.17`" + } + ] + } + }, + { + "version": "5.5.63", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.63", + "date": "Wed, 24 Jul 2024 00:12:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.61`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.16`" + } + ] + } + }, + { + "version": "5.5.62", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.62", + "date": "Wed, 17 Jul 2024 06:55:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.60`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.15`" + } + ] + } + }, + { + "version": "5.5.61", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.61", + "date": "Wed, 17 Jul 2024 00:11:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.59`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.14`" + } + ] + } + }, + { + "version": "5.5.60", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.60", + "date": "Tue, 16 Jul 2024 00:36:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.58`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.13`" + } + ] + } + }, + { + "version": "5.5.59", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.59", + "date": "Thu, 27 Jun 2024 21:01:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.57`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.12`" + } + ] + } + }, + { + "version": "5.5.58", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.58", + "date": "Mon, 03 Jun 2024 23:43:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.56`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.11`" + } + ] + } + }, + { + "version": "5.5.57", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.57", + "date": "Thu, 30 May 2024 00:13:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.55`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.10`" + } + ] + } + }, + { + "version": "5.5.56", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.56", + "date": "Wed, 29 May 2024 02:03:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.54`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.9`" + } + ] + } + }, + { + "version": "5.5.55", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.55", + "date": "Wed, 29 May 2024 00:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.53`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.8`" + } + ] + } + }, + { + "version": "5.5.54", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.54", + "date": "Tue, 28 May 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.52`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.7`" + } + ] + } + }, + { + "version": "5.5.53", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.53", + "date": "Tue, 28 May 2024 00:09:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.51`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.6`" + } + ] + } + }, + { + "version": "5.5.52", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.52", + "date": "Sat, 25 May 2024 04:54:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.50`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.5`" + } + ] + } + }, + { + "version": "5.5.51", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.51", + "date": "Fri, 24 May 2024 00:15:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.49`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.4`" + } + ] + } + }, + { + "version": "5.5.50", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.50", + "date": "Thu, 23 May 2024 02:26:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.3`" + } + ] + } + }, + { + "version": "5.5.49", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.49", + "date": "Thu, 16 May 2024 15:10:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.2`" + } + ] + } + }, + { + "version": "5.5.48", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.48", + "date": "Wed, 15 May 2024 23:42:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.1`" + } + ] + } + }, + { + "version": "5.5.47", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.47", + "date": "Wed, 15 May 2024 06:04:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.6.0`" + } + ] + } + }, + { + "version": "5.5.46", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.46", + "date": "Fri, 10 May 2024 05:33:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.5.4`" + } + ] + } + }, + { + "version": "5.5.45", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.45", + "date": "Wed, 08 May 2024 22:23:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.5.3`" + } + ] + } + }, + { + "version": "5.5.44", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.44", + "date": "Mon, 06 May 2024 15:11:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.5.2`" + } + ] + } + }, + { + "version": "5.5.43", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.43", + "date": "Fri, 12 Apr 2024 00:12:46 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes bug where maps would only map back to minification chunk code" + } + ] + } + }, + { + "version": "5.5.42", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.42", + "date": "Wed, 10 Apr 2024 15:10:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.5.1`" + } + ] + } + }, + { + "version": "5.5.41", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.41", + "date": "Thu, 28 Mar 2024 22:42:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.5.0`" + } + ] + } + }, + { + "version": "5.5.40", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.40", + "date": "Tue, 19 Mar 2024 15:10:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.40`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.40`" + } + ] + } + }, + { + "version": "5.5.39", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.39", + "date": "Sat, 16 Mar 2024 00:11:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.39`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.39`" + } + ] + } + }, + { + "version": "5.5.38", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.38", + "date": "Fri, 15 Mar 2024 00:12:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.38`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.38`" + } + ] + } + }, + { + "version": "5.5.37", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.37", + "date": "Tue, 05 Mar 2024 01:19:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.66.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.37`" + } + ] + } + }, + { + "version": "5.5.36", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.36", + "date": "Sun, 03 Mar 2024 20:58:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.36`" + } + ] + } + }, + { + "version": "5.5.35", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.35", + "date": "Sat, 02 Mar 2024 02:22:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.35`" + } + ] + } + }, + { + "version": "5.5.34", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.34", + "date": "Fri, 01 Mar 2024 01:10:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.34`" + } + ] + } + }, + { + "version": "5.5.33", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.33", + "date": "Thu, 29 Feb 2024 07:11:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.33`" + } + ] + } + }, + { + "version": "5.5.32", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.32", + "date": "Wed, 28 Feb 2024 16:09:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `0.4.32`" + } + ] + } + }, + { + "version": "5.5.31", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.31", + "date": "Sat, 24 Feb 2024 23:02:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.30", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.30", + "date": "Thu, 22 Feb 2024 01:36:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.29", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.29", + "date": "Wed, 21 Feb 2024 21:45:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.28", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.28", + "date": "Wed, 21 Feb 2024 08:55:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.27", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.27", + "date": "Tue, 20 Feb 2024 21:45:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.26", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.26", + "date": "Tue, 20 Feb 2024 16:10:53 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.65.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.25", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.25", + "date": "Mon, 19 Feb 2024 21:54:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.24", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.24", + "date": "Sat, 17 Feb 2024 06:24:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.23", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.23", + "date": "Thu, 08 Feb 2024 01:09:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.22", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.22", + "date": "Wed, 07 Feb 2024 01:11:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.21", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.21", + "date": "Mon, 05 Feb 2024 23:46:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.20", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.20", + "date": "Thu, 25 Jan 2024 01:09:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.19", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.19", + "date": "Tue, 23 Jan 2024 20:12:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.18", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.18", + "date": "Tue, 23 Jan 2024 16:15:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.17", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.17", + "date": "Tue, 16 Jan 2024 18:30:11 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade build dependencies" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.64.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.16", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.16", + "date": "Wed, 03 Jan 2024 00:31:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.15", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.15", + "date": "Wed, 20 Dec 2023 01:09:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.14", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.14", + "date": "Thu, 07 Dec 2023 03:44:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.13", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.13", + "date": "Tue, 05 Dec 2023 01:10:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.12", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.12", + "date": "Fri, 10 Nov 2023 18:02:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.11", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.11", + "date": "Wed, 01 Nov 2023 23:11:36 GMT", + "comments": { + "patch": [ + { + "comment": "Fix line endings in published package." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.10", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.10", + "date": "Mon, 30 Oct 2023 23:36:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.63.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.9", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.9", + "date": "Sun, 01 Oct 2023 02:56:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.8", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.8", + "date": "Sat, 30 Sep 2023 00:20:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.7", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.7", + "date": "Thu, 28 Sep 2023 20:53:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.6", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.6", + "date": "Wed, 27 Sep 2023 00:21:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.62.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.5", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.5", + "date": "Tue, 26 Sep 2023 21:02:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.4", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.4", + "date": "Tue, 26 Sep 2023 09:30:33 GMT", + "comments": { + "patch": [ + { + "comment": "Update type-only imports to include the type modifier." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.3", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.3", + "date": "Mon, 25 Sep 2023 23:38:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.2", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.2", + "date": "Fri, 22 Sep 2023 00:05:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.61.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.1", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.1", + "date": "Tue, 19 Sep 2023 15:21:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.60.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.5.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.5.0", + "date": "Fri, 15 Sep 2023 00:36:58 GMT", + "comments": { + "minor": [ + { + "comment": "Update @types/node from 14 to 18" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.59.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.34", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.34", + "date": "Tue, 08 Aug 2023 07:10:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.38`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.33", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.33", + "date": "Mon, 31 Jul 2023 15:19:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.37`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.32", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.32", + "date": "Sat, 29 Jul 2023 00:22:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.36`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.31", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.31", + "date": "Thu, 20 Jul 2023 20:47:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.35`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.30", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.30", + "date": "Wed, 19 Jul 2023 00:20:31 GMT", + "comments": { + "patch": [ + { + "comment": "Fix calculation of rendered module positions to properly reflect character codes, not raw bytes." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.34`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.29", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.29", + "date": "Fri, 14 Jul 2023 15:20:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.33`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.28", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.28", + "date": "Thu, 13 Jul 2023 00:22:37 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.32`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.27", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.27", + "date": "Wed, 12 Jul 2023 15:20:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.31`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.26", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.26", + "date": "Wed, 12 Jul 2023 00:23:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.30`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.25", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.25", + "date": "Fri, 07 Jul 2023 00:19:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.29`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.24", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.24", + "date": "Thu, 06 Jul 2023 00:16:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.28`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.23", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.23", + "date": "Tue, 04 Jul 2023 00:18:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.27`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.22", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.22", + "date": "Mon, 19 Jun 2023 22:40:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.21", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.21", + "date": "Thu, 15 Jun 2023 00:21:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.20", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.20", + "date": "Wed, 14 Jun 2023 00:19:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.19", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.19", + "date": "Tue, 13 Jun 2023 15:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.18", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.18", + "date": "Tue, 13 Jun 2023 01:49:01 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to v5.82.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.17", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.17", + "date": "Fri, 09 Jun 2023 18:05:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.16", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.16", + "date": "Fri, 09 Jun 2023 15:23:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.15", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.15", + "date": "Fri, 09 Jun 2023 00:19:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.14", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.14", + "date": "Thu, 08 Jun 2023 15:21:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.13", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.13", + "date": "Thu, 08 Jun 2023 00:20:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.12", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.12", + "date": "Wed, 07 Jun 2023 22:45:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.11", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.11", + "date": "Tue, 06 Jun 2023 02:52:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.10", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.10", + "date": "Mon, 05 Jun 2023 21:45:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.9", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.9", + "date": "Fri, 02 Jun 2023 02:01:13 GMT", + "comments": { + "none": [ + { + "comment": "Convert to multi-phase Heft" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.8", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.8", + "date": "Mon, 29 May 2023 15:21:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.7", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.7", + "date": "Mon, 22 May 2023 06:34:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.6", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.6", + "date": "Fri, 12 May 2023 00:23:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.5", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.5", + "date": "Thu, 04 May 2023 15:17:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.4", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.4", + "date": "Thu, 04 May 2023 00:20:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.3", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.3", + "date": "Mon, 01 May 2023 15:23:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.2", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.2", + "date": "Sat, 29 Apr 2023 00:23:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.1", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.1", + "date": "Thu, 27 Apr 2023 17:18:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.4.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.4.0", + "date": "Wed, 26 Apr 2023 00:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Emit metadata about character position of rendered modules." + } + ] + } + }, + { + "version": "5.3.6", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.6", + "date": "Thu, 20 Apr 2023 15:16:55 GMT", + "comments": { + "patch": [ + { + "comment": "Update webpack to v5.80.0" + } + ] + } + }, + { + "version": "5.3.5", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.5", + "date": "Fri, 07 Apr 2023 22:19:21 GMT", + "comments": { + "patch": [ + { + "comment": "Bump webpack to 5.78.0" + } + ] + } + }, + { + "version": "5.3.4", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.4", + "date": "Tue, 04 Apr 2023 22:36:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.3.3", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.3", + "date": "Sat, 18 Mar 2023 00:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.3.2", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.2", + "date": "Fri, 10 Feb 2023 01:18:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.3.1", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.1", + "date": "Sun, 05 Feb 2023 03:02:02 GMT", + "comments": { + "patch": [ + { + "comment": "Change the peer dependency selector on `@types/node` to a wildcard (`*`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.3.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.3.0", + "date": "Wed, 01 Feb 2023 02:16:34 GMT", + "comments": { + "minor": [ + { + "comment": "Bump @types/node peerDependency to ^14.18.36." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.2.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.2.0", + "date": "Mon, 30 Jan 2023 16:22:30 GMT", + "comments": { + "minor": [ + { + "comment": "Move the @types/node dependency to an optional peerDependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.49", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.49", + "date": "Mon, 30 Jan 2023 00:55:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.49`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.48", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.48", + "date": "Sat, 28 Jan 2023 01:22:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.48`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.47", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.47", + "date": "Thu, 26 Jan 2023 02:55:10 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade to webpack 5.75.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.47`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.46", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.46", + "date": "Wed, 25 Jan 2023 07:26:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.46`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.45", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.45", + "date": "Wed, 18 Jan 2023 22:44:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.45`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.44", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.44", + "date": "Tue, 20 Dec 2022 01:18:22 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a formatting issue in the LICENSE file." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.44`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.43", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.43", + "date": "Thu, 15 Dec 2022 01:18:56 GMT", + "comments": { + "patch": [ + { + "comment": "Make @types/estree a dependency instead of devDependency" + } + ] + } + }, + { + "version": "5.1.42", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.42", + "date": "Fri, 09 Dec 2022 16:18:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.43`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.41", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.41", + "date": "Tue, 29 Nov 2022 01:16:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.42`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.40", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.40", + "date": "Tue, 08 Nov 2022 01:20:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.41`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.39", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.39", + "date": "Wed, 26 Oct 2022 00:16:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.40`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.38", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.38", + "date": "Mon, 17 Oct 2022 22:14:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.39`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.37", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.37", + "date": "Mon, 17 Oct 2022 15:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.38`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.36", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.36", + "date": "Fri, 14 Oct 2022 15:26:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.37`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.35", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.35", + "date": "Thu, 13 Oct 2022 00:20:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.36`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.34", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.34", + "date": "Tue, 11 Oct 2022 23:49:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.35`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.33", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.33", + "date": "Mon, 10 Oct 2022 15:23:44 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.34`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.32", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.32", + "date": "Thu, 29 Sep 2022 07:13:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.48.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.33`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.31", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.31", + "date": "Tue, 27 Sep 2022 22:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.32`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.30", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.30", + "date": "Wed, 21 Sep 2022 20:21:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.31`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.29", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.29", + "date": "Thu, 15 Sep 2022 00:18:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.30`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.28", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.28", + "date": "Tue, 13 Sep 2022 00:16:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.27", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.27", + "date": "Mon, 12 Sep 2022 22:27:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.26", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.26", + "date": "Fri, 02 Sep 2022 17:48:43 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.25", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.25", + "date": "Wed, 31 Aug 2022 01:45:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.24", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.24", + "date": "Wed, 31 Aug 2022 00:42:46 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.23", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.23", + "date": "Wed, 24 Aug 2022 03:01:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.22", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.22", + "date": "Wed, 24 Aug 2022 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.21", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.21", + "date": "Fri, 19 Aug 2022 00:17:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.20", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.20", + "date": "Wed, 10 Aug 2022 09:52:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.19", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.19", + "date": "Wed, 10 Aug 2022 08:12:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.18", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.18", + "date": "Wed, 03 Aug 2022 18:40:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `3.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.47.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.17", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.17", + "date": "Mon, 01 Aug 2022 02:45:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.23`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.16", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.16", + "date": "Thu, 28 Jul 2022 00:18:19 GMT", + "comments": { + "patch": [ + { + "comment": "Fix typings reference." + } + ] + } + }, + { + "version": "5.1.15", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.15", + "date": "Thu, 21 Jul 2022 23:30:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.22`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.14", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.14", + "date": "Thu, 21 Jul 2022 00:16:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.21`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.13", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.13", + "date": "Wed, 13 Jul 2022 21:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.20`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.12", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.12", + "date": "Fri, 08 Jul 2022 15:17:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.19`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.11", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.11", + "date": "Mon, 04 Jul 2022 15:15:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.18`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.10", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.10", + "date": "Thu, 30 Jun 2022 04:48:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.17`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.9", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.9", + "date": "Tue, 28 Jun 2022 22:47:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.46.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.16`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.8", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.8", + "date": "Tue, 28 Jun 2022 00:23:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-config\" to `2.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.7", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.7", + "date": "Mon, 27 Jun 2022 18:43:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.6", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.6", + "date": "Sat, 25 Jun 2022 21:00:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.5", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.5", + "date": "Sat, 25 Jun 2022 01:54:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.4", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.4", + "date": "Fri, 24 Jun 2022 07:16:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.3", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.3", + "date": "Thu, 23 Jun 2022 22:14:24 GMT", + "comments": { + "none": [ + { + "comment": "Update documentation." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.2", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.2", + "date": "Tue, 21 Jun 2022 20:27:19 GMT", + "comments": { + "patch": [ + { + "comment": "Update readme." + } + ] + } + }, + { + "version": "5.1.1", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.1", + "date": "Tue, 07 Jun 2022 09:37:05 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.45.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" to `0.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/module-minifier\" from `*` to `*`" + } + ] + } + }, + { + "version": "5.1.0", + "tag": "@rushstack/webpack5-module-minifier-plugin_v5.1.0", + "date": "Thu, 02 Jun 2022 15:13:07 GMT", + "comments": { + "minor": [ + { + "comment": "Initial implementation of @rushstack/webpack5-module-minifier-plugin. Supports externals, inline modules, concatenation, and recording of minified module sizes." + } + ] + } + } + ] +} diff --git a/webpack/webpack5-module-minifier-plugin/CHANGELOG.md b/webpack/webpack5-module-minifier-plugin/CHANGELOG.md new file mode 100644 index 00000000000..fcb23247c4a --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/CHANGELOG.md @@ -0,0 +1,1128 @@ +# Change Log - @rushstack/webpack5-module-minifier-plugin + +This log was last generated on Sat, 06 Dec 2025 01:12:28 GMT and should not be manually modified. + +## 5.6.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 5.6.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 5.6.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 5.6.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 5.6.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 5.6.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 5.6.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 5.6.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 5.5.114 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 5.5.113 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 5.5.112 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 5.5.111 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 5.5.110 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 5.5.109 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 5.5.108 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 5.5.107 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 5.5.106 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 5.5.105 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 5.5.104 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 5.5.103 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 5.5.102 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 5.5.101 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 5.5.100 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 5.5.99 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 5.5.98 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 5.5.97 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 5.5.96 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 5.5.95 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 5.5.94 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 5.5.93 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 5.5.92 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 5.5.91 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 5.5.90 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 5.5.89 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 5.5.88 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 5.5.87 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 5.5.86 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 5.5.85 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 5.5.84 +Wed, 22 Jan 2025 03:03:48 GMT + +_Version update only_ + +## 5.5.83 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 5.5.82 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 5.5.81 +Sat, 14 Dec 2024 01:11:07 GMT + +_Version update only_ + +## 5.5.80 +Mon, 09 Dec 2024 20:31:43 GMT + +_Version update only_ + +## 5.5.79 +Tue, 03 Dec 2024 16:11:08 GMT + +_Version update only_ + +## 5.5.78 +Sat, 23 Nov 2024 01:18:55 GMT + +_Version update only_ + +## 5.5.77 +Fri, 22 Nov 2024 01:10:43 GMT + +_Version update only_ + +## 5.5.76 +Thu, 24 Oct 2024 00:15:48 GMT + +_Version update only_ + +## 5.5.75 +Mon, 21 Oct 2024 18:50:10 GMT + +_Version update only_ + +## 5.5.74 +Thu, 17 Oct 2024 08:35:06 GMT + +_Version update only_ + +## 5.5.73 +Tue, 15 Oct 2024 00:12:32 GMT + +_Version update only_ + +## 5.5.72 +Wed, 02 Oct 2024 00:11:19 GMT + +### Patches + +- Ensure compatibility with webpack 5.95.0 + +## 5.5.71 +Tue, 01 Oct 2024 00:11:28 GMT + +_Version update only_ + +## 5.5.70 +Mon, 30 Sep 2024 15:12:19 GMT + +_Version update only_ + +## 5.5.69 +Fri, 13 Sep 2024 00:11:43 GMT + +_Version update only_ + +## 5.5.68 +Tue, 10 Sep 2024 20:08:11 GMT + +_Version update only_ + +## 5.5.67 +Wed, 21 Aug 2024 05:43:04 GMT + +_Version update only_ + +## 5.5.66 +Mon, 12 Aug 2024 22:16:04 GMT + +_Version update only_ + +## 5.5.65 +Fri, 02 Aug 2024 17:26:42 GMT + +_Version update only_ + +## 5.5.64 +Sat, 27 Jul 2024 00:10:27 GMT + +### Patches + +- Include CHANGELOG.md in published releases again + +## 5.5.63 +Wed, 24 Jul 2024 00:12:14 GMT + +_Version update only_ + +## 5.5.62 +Wed, 17 Jul 2024 06:55:10 GMT + +_Version update only_ + +## 5.5.61 +Wed, 17 Jul 2024 00:11:19 GMT + +_Version update only_ + +## 5.5.60 +Tue, 16 Jul 2024 00:36:22 GMT + +_Version update only_ + +## 5.5.59 +Thu, 27 Jun 2024 21:01:36 GMT + +_Version update only_ + +## 5.5.58 +Mon, 03 Jun 2024 23:43:15 GMT + +_Version update only_ + +## 5.5.57 +Thu, 30 May 2024 00:13:05 GMT + +_Version update only_ + +## 5.5.56 +Wed, 29 May 2024 02:03:51 GMT + +_Version update only_ + +## 5.5.55 +Wed, 29 May 2024 00:10:52 GMT + +_Version update only_ + +## 5.5.54 +Tue, 28 May 2024 15:10:09 GMT + +_Version update only_ + +## 5.5.53 +Tue, 28 May 2024 00:09:47 GMT + +_Version update only_ + +## 5.5.52 +Sat, 25 May 2024 04:54:08 GMT + +_Version update only_ + +## 5.5.51 +Fri, 24 May 2024 00:15:08 GMT + +_Version update only_ + +## 5.5.50 +Thu, 23 May 2024 02:26:56 GMT + +_Version update only_ + +## 5.5.49 +Thu, 16 May 2024 15:10:22 GMT + +_Version update only_ + +## 5.5.48 +Wed, 15 May 2024 23:42:58 GMT + +_Version update only_ + +## 5.5.47 +Wed, 15 May 2024 06:04:17 GMT + +_Version update only_ + +## 5.5.46 +Fri, 10 May 2024 05:33:34 GMT + +_Version update only_ + +## 5.5.45 +Wed, 08 May 2024 22:23:51 GMT + +_Version update only_ + +## 5.5.44 +Mon, 06 May 2024 15:11:04 GMT + +_Version update only_ + +## 5.5.43 +Fri, 12 Apr 2024 00:12:46 GMT + +### Patches + +- Fixes bug where maps would only map back to minification chunk code + +## 5.5.42 +Wed, 10 Apr 2024 15:10:09 GMT + +_Version update only_ + +## 5.5.41 +Thu, 28 Mar 2024 22:42:24 GMT + +_Version update only_ + +## 5.5.40 +Tue, 19 Mar 2024 15:10:18 GMT + +_Version update only_ + +## 5.5.39 +Sat, 16 Mar 2024 00:11:37 GMT + +_Version update only_ + +## 5.5.38 +Fri, 15 Mar 2024 00:12:40 GMT + +_Version update only_ + +## 5.5.37 +Tue, 05 Mar 2024 01:19:24 GMT + +_Version update only_ + +## 5.5.36 +Sun, 03 Mar 2024 20:58:13 GMT + +_Version update only_ + +## 5.5.35 +Sat, 02 Mar 2024 02:22:24 GMT + +_Version update only_ + +## 5.5.34 +Fri, 01 Mar 2024 01:10:08 GMT + +_Version update only_ + +## 5.5.33 +Thu, 29 Feb 2024 07:11:46 GMT + +_Version update only_ + +## 5.5.32 +Wed, 28 Feb 2024 16:09:27 GMT + +_Version update only_ + +## 5.5.31 +Sat, 24 Feb 2024 23:02:51 GMT + +_Version update only_ + +## 5.5.30 +Thu, 22 Feb 2024 01:36:09 GMT + +_Version update only_ + +## 5.5.29 +Wed, 21 Feb 2024 21:45:28 GMT + +_Version update only_ + +## 5.5.28 +Wed, 21 Feb 2024 08:55:47 GMT + +_Version update only_ + +## 5.5.27 +Tue, 20 Feb 2024 21:45:10 GMT + +_Version update only_ + +## 5.5.26 +Tue, 20 Feb 2024 16:10:53 GMT + +_Version update only_ + +## 5.5.25 +Mon, 19 Feb 2024 21:54:27 GMT + +_Version update only_ + +## 5.5.24 +Sat, 17 Feb 2024 06:24:35 GMT + +_Version update only_ + +## 5.5.23 +Thu, 08 Feb 2024 01:09:21 GMT + +_Version update only_ + +## 5.5.22 +Wed, 07 Feb 2024 01:11:18 GMT + +_Version update only_ + +## 5.5.21 +Mon, 05 Feb 2024 23:46:52 GMT + +_Version update only_ + +## 5.5.20 +Thu, 25 Jan 2024 01:09:30 GMT + +_Version update only_ + +## 5.5.19 +Tue, 23 Jan 2024 20:12:58 GMT + +_Version update only_ + +## 5.5.18 +Tue, 23 Jan 2024 16:15:06 GMT + +_Version update only_ + +## 5.5.17 +Tue, 16 Jan 2024 18:30:11 GMT + +### Patches + +- Upgrade build dependencies + +## 5.5.16 +Wed, 03 Jan 2024 00:31:18 GMT + +_Version update only_ + +## 5.5.15 +Wed, 20 Dec 2023 01:09:46 GMT + +_Version update only_ + +## 5.5.14 +Thu, 07 Dec 2023 03:44:13 GMT + +_Version update only_ + +## 5.5.13 +Tue, 05 Dec 2023 01:10:16 GMT + +_Version update only_ + +## 5.5.12 +Fri, 10 Nov 2023 18:02:04 GMT + +_Version update only_ + +## 5.5.11 +Wed, 01 Nov 2023 23:11:36 GMT + +### Patches + +- Fix line endings in published package. + +## 5.5.10 +Mon, 30 Oct 2023 23:36:37 GMT + +_Version update only_ + +## 5.5.9 +Sun, 01 Oct 2023 02:56:30 GMT + +_Version update only_ + +## 5.5.8 +Sat, 30 Sep 2023 00:20:51 GMT + +_Version update only_ + +## 5.5.7 +Thu, 28 Sep 2023 20:53:17 GMT + +_Version update only_ + +## 5.5.6 +Wed, 27 Sep 2023 00:21:39 GMT + +_Version update only_ + +## 5.5.5 +Tue, 26 Sep 2023 21:02:30 GMT + +_Version update only_ + +## 5.5.4 +Tue, 26 Sep 2023 09:30:33 GMT + +### Patches + +- Update type-only imports to include the type modifier. + +## 5.5.3 +Mon, 25 Sep 2023 23:38:28 GMT + +_Version update only_ + +## 5.5.2 +Fri, 22 Sep 2023 00:05:51 GMT + +_Version update only_ + +## 5.5.1 +Tue, 19 Sep 2023 15:21:52 GMT + +_Version update only_ + +## 5.5.0 +Fri, 15 Sep 2023 00:36:58 GMT + +### Minor changes + +- Update @types/node from 14 to 18 + +## 5.4.34 +Tue, 08 Aug 2023 07:10:40 GMT + +_Version update only_ + +## 5.4.33 +Mon, 31 Jul 2023 15:19:06 GMT + +_Version update only_ + +## 5.4.32 +Sat, 29 Jul 2023 00:22:51 GMT + +_Version update only_ + +## 5.4.31 +Thu, 20 Jul 2023 20:47:28 GMT + +_Version update only_ + +## 5.4.30 +Wed, 19 Jul 2023 00:20:31 GMT + +### Patches + +- Fix calculation of rendered module positions to properly reflect character codes, not raw bytes. + +## 5.4.29 +Fri, 14 Jul 2023 15:20:45 GMT + +_Version update only_ + +## 5.4.28 +Thu, 13 Jul 2023 00:22:37 GMT + +_Version update only_ + +## 5.4.27 +Wed, 12 Jul 2023 15:20:40 GMT + +_Version update only_ + +## 5.4.26 +Wed, 12 Jul 2023 00:23:30 GMT + +_Version update only_ + +## 5.4.25 +Fri, 07 Jul 2023 00:19:33 GMT + +_Version update only_ + +## 5.4.24 +Thu, 06 Jul 2023 00:16:20 GMT + +_Version update only_ + +## 5.4.23 +Tue, 04 Jul 2023 00:18:47 GMT + +_Version update only_ + +## 5.4.22 +Mon, 19 Jun 2023 22:40:21 GMT + +_Version update only_ + +## 5.4.21 +Thu, 15 Jun 2023 00:21:02 GMT + +_Version update only_ + +## 5.4.20 +Wed, 14 Jun 2023 00:19:42 GMT + +_Version update only_ + +## 5.4.19 +Tue, 13 Jun 2023 15:17:20 GMT + +_Version update only_ + +## 5.4.18 +Tue, 13 Jun 2023 01:49:01 GMT + +### Patches + +- Bump webpack to v5.82.1 + +## 5.4.17 +Fri, 09 Jun 2023 18:05:35 GMT + +_Version update only_ + +## 5.4.16 +Fri, 09 Jun 2023 15:23:15 GMT + +_Version update only_ + +## 5.4.15 +Fri, 09 Jun 2023 00:19:49 GMT + +_Version update only_ + +## 5.4.14 +Thu, 08 Jun 2023 15:21:17 GMT + +_Version update only_ + +## 5.4.13 +Thu, 08 Jun 2023 00:20:03 GMT + +_Version update only_ + +## 5.4.12 +Wed, 07 Jun 2023 22:45:17 GMT + +_Version update only_ + +## 5.4.11 +Tue, 06 Jun 2023 02:52:51 GMT + +_Version update only_ + +## 5.4.10 +Mon, 05 Jun 2023 21:45:21 GMT + +_Version update only_ + +## 5.4.9 +Fri, 02 Jun 2023 02:01:13 GMT + +_Version update only_ + +## 5.4.8 +Mon, 29 May 2023 15:21:15 GMT + +_Version update only_ + +## 5.4.7 +Mon, 22 May 2023 06:34:33 GMT + +_Version update only_ + +## 5.4.6 +Fri, 12 May 2023 00:23:05 GMT + +_Version update only_ + +## 5.4.5 +Thu, 04 May 2023 15:17:38 GMT + +_Version update only_ + +## 5.4.4 +Thu, 04 May 2023 00:20:29 GMT + +_Version update only_ + +## 5.4.3 +Mon, 01 May 2023 15:23:20 GMT + +_Version update only_ + +## 5.4.2 +Sat, 29 Apr 2023 00:23:03 GMT + +_Version update only_ + +## 5.4.1 +Thu, 27 Apr 2023 17:18:43 GMT + +_Version update only_ + +## 5.4.0 +Wed, 26 Apr 2023 00:22:30 GMT + +### Minor changes + +- Emit metadata about character position of rendered modules. + +## 5.3.6 +Thu, 20 Apr 2023 15:16:55 GMT + +### Patches + +- Update webpack to v5.80.0 + +## 5.3.5 +Fri, 07 Apr 2023 22:19:21 GMT + +### Patches + +- Bump webpack to 5.78.0 + +## 5.3.4 +Tue, 04 Apr 2023 22:36:28 GMT + +_Version update only_ + +## 5.3.3 +Sat, 18 Mar 2023 00:20:56 GMT + +_Version update only_ + +## 5.3.2 +Fri, 10 Feb 2023 01:18:51 GMT + +_Version update only_ + +## 5.3.1 +Sun, 05 Feb 2023 03:02:02 GMT + +### Patches + +- Change the peer dependency selector on `@types/node` to a wildcard (`*`). + +## 5.3.0 +Wed, 01 Feb 2023 02:16:34 GMT + +### Minor changes + +- Bump @types/node peerDependency to ^14.18.36. + +## 5.2.0 +Mon, 30 Jan 2023 16:22:30 GMT + +### Minor changes + +- Move the @types/node dependency to an optional peerDependency. + +## 5.1.49 +Mon, 30 Jan 2023 00:55:44 GMT + +_Version update only_ + +## 5.1.48 +Sat, 28 Jan 2023 01:22:02 GMT + +_Version update only_ + +## 5.1.47 +Thu, 26 Jan 2023 02:55:10 GMT + +### Patches + +- Upgrade to webpack 5.75.0 + +## 5.1.46 +Wed, 25 Jan 2023 07:26:55 GMT + +_Version update only_ + +## 5.1.45 +Wed, 18 Jan 2023 22:44:12 GMT + +_Version update only_ + +## 5.1.44 +Tue, 20 Dec 2022 01:18:22 GMT + +### Patches + +- Fix a formatting issue in the LICENSE file. + +## 5.1.43 +Thu, 15 Dec 2022 01:18:56 GMT + +### Patches + +- Make @types/estree a dependency instead of devDependency + +## 5.1.42 +Fri, 09 Dec 2022 16:18:28 GMT + +_Version update only_ + +## 5.1.41 +Tue, 29 Nov 2022 01:16:49 GMT + +_Version update only_ + +## 5.1.40 +Tue, 08 Nov 2022 01:20:56 GMT + +_Version update only_ + +## 5.1.39 +Wed, 26 Oct 2022 00:16:16 GMT + +_Version update only_ + +## 5.1.38 +Mon, 17 Oct 2022 22:14:21 GMT + +_Version update only_ + +## 5.1.37 +Mon, 17 Oct 2022 15:16:00 GMT + +_Version update only_ + +## 5.1.36 +Fri, 14 Oct 2022 15:26:32 GMT + +_Version update only_ + +## 5.1.35 +Thu, 13 Oct 2022 00:20:15 GMT + +_Version update only_ + +## 5.1.34 +Tue, 11 Oct 2022 23:49:12 GMT + +_Version update only_ + +## 5.1.33 +Mon, 10 Oct 2022 15:23:44 GMT + +_Version update only_ + +## 5.1.32 +Thu, 29 Sep 2022 07:13:06 GMT + +_Version update only_ + +## 5.1.31 +Tue, 27 Sep 2022 22:17:20 GMT + +_Version update only_ + +## 5.1.30 +Wed, 21 Sep 2022 20:21:10 GMT + +_Version update only_ + +## 5.1.29 +Thu, 15 Sep 2022 00:18:52 GMT + +_Version update only_ + +## 5.1.28 +Tue, 13 Sep 2022 00:16:55 GMT + +_Version update only_ + +## 5.1.27 +Mon, 12 Sep 2022 22:27:48 GMT + +_Version update only_ + +## 5.1.26 +Fri, 02 Sep 2022 17:48:43 GMT + +_Version update only_ + +## 5.1.25 +Wed, 31 Aug 2022 01:45:06 GMT + +_Version update only_ + +## 5.1.24 +Wed, 31 Aug 2022 00:42:46 GMT + +_Version update only_ + +## 5.1.23 +Wed, 24 Aug 2022 03:01:22 GMT + +_Version update only_ + +## 5.1.22 +Wed, 24 Aug 2022 00:14:38 GMT + +_Version update only_ + +## 5.1.21 +Fri, 19 Aug 2022 00:17:20 GMT + +_Version update only_ + +## 5.1.20 +Wed, 10 Aug 2022 09:52:12 GMT + +_Version update only_ + +## 5.1.19 +Wed, 10 Aug 2022 08:12:16 GMT + +_Version update only_ + +## 5.1.18 +Wed, 03 Aug 2022 18:40:35 GMT + +_Version update only_ + +## 5.1.17 +Mon, 01 Aug 2022 02:45:32 GMT + +_Version update only_ + +## 5.1.16 +Thu, 28 Jul 2022 00:18:19 GMT + +### Patches + +- Fix typings reference. + +## 5.1.15 +Thu, 21 Jul 2022 23:30:27 GMT + +_Version update only_ + +## 5.1.14 +Thu, 21 Jul 2022 00:16:14 GMT + +_Version update only_ + +## 5.1.13 +Wed, 13 Jul 2022 21:31:13 GMT + +_Version update only_ + +## 5.1.12 +Fri, 08 Jul 2022 15:17:47 GMT + +_Version update only_ + +## 5.1.11 +Mon, 04 Jul 2022 15:15:13 GMT + +_Version update only_ + +## 5.1.10 +Thu, 30 Jun 2022 04:48:54 GMT + +_Version update only_ + +## 5.1.9 +Tue, 28 Jun 2022 22:47:14 GMT + +_Version update only_ + +## 5.1.8 +Tue, 28 Jun 2022 00:23:32 GMT + +_Version update only_ + +## 5.1.7 +Mon, 27 Jun 2022 18:43:09 GMT + +_Version update only_ + +## 5.1.6 +Sat, 25 Jun 2022 21:00:40 GMT + +_Version update only_ + +## 5.1.5 +Sat, 25 Jun 2022 01:54:29 GMT + +_Version update only_ + +## 5.1.4 +Fri, 24 Jun 2022 07:16:47 GMT + +_Version update only_ + +## 5.1.3 +Thu, 23 Jun 2022 22:14:24 GMT + +_Version update only_ + +## 5.1.2 +Tue, 21 Jun 2022 20:27:19 GMT + +### Patches + +- Update readme. + +## 5.1.1 +Tue, 07 Jun 2022 09:37:05 GMT + +_Version update only_ + +## 5.1.0 +Thu, 02 Jun 2022 15:13:07 GMT + +### Minor changes + +- Initial implementation of @rushstack/webpack5-module-minifier-plugin. Supports externals, inline modules, concatenation, and recording of minified module sizes. + diff --git a/webpack/webpack5-module-minifier-plugin/LICENSE b/webpack/webpack5-module-minifier-plugin/LICENSE new file mode 100644 index 00000000000..482d470fb85 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/webpack5-module-minifier-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/webpack/webpack5-module-minifier-plugin/README.md b/webpack/webpack5-module-minifier-plugin/README.md new file mode 100644 index 00000000000..17f73b5ef68 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/README.md @@ -0,0 +1,64 @@ +# @rushstack/webpack5-module-minifier-plugin + +This package contains a plugin for webpack 5 that performs minification on a per-module basis rather than per-asset to deduplicate and parallelize compression work. + +## Installation + +`npm install @rushstack/webpack5-module-minifier-plugin --save-dev` + +## Overview + +This Webpack plugin performs minification of production assets on a per-module basis, rather than minifying an entire chunk at a time. +It issues async calls to the minifier for each unique module and each unique set of chunk boilerplate (i.e. the webpack runtime and the structure of the module list). +This improves minification time by: +- Avoiding duplicate work for each module that is included in multiple distinct assets/chunks (this is common with async chunks) +- Handing smaller code chunks to the minifier at a time (AST analysis is superlinear in size of the AST) +- Even single asset builds will likely still contain multiple modules in the final output, which can be split across available CPU cores + +## Use with `[hash]` and `[contenthash]` tokens +The plugin will do its best to update webpack hashes if changing the direct inputs (`useSourceMap`) to the plugin, but if altering the `minifier` property itself, you may need to use the `output.hashSalt` property to force a change to the hashes, especially if leveraging the `MessagePortMinifier` or similar, since it has no direct access to the configuration of the minifier. + +## Parallel execution + +```js +const { ModuleMinifierPlugin } = require('@rushstack/webpack5-module-minifier-plugin'); +const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); + +// In your webpack options: +optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier(), + // If not provided, the plugin will attempt to guess from `mode` and `devtool`. + // Providing it expressly gives better results + useSourceMap: true + }) + ] +} +``` + +## Single-threaded execution +You can also run the ModuleMinifierPlugin in a single-threaded configuration. + +```js +// webpack.config.js +const { ModuleMinifierPlugin } = require('@rushstack/webpack5-module-minifier-plugin'); +const { LocalMinifier } = require('@rushstack/module-minifier'); + +// In your webpack options: +optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new LocalMinifier() + }) + ] +} +``` + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/webpack/webpack5-module-minifier-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +`@rushstack/webpack5-module-minifier-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/webpack/webpack5-module-minifier-plugin/config/api-extractor.json b/webpack/webpack5-module-minifier-plugin/config/api-extractor.json new file mode 100644 index 00000000000..fba8a2992f6 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/config/api-extractor.json @@ -0,0 +1,19 @@ +{ + "$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": false, + "apiJsonFilePath": "../../../common/temp/api/.api.json" + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/webpack/webpack5-module-minifier-plugin/config/jest.config.json b/webpack/webpack5-module-minifier-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/webpack/webpack5-module-minifier-plugin/config/rig.json b/webpack/webpack5-module-minifier-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/webpack/webpack5-module-minifier-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/webpack/webpack5-module-minifier-plugin/eslint.config.js b/webpack/webpack5-module-minifier-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/webpack/webpack5-module-minifier-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/webpack/webpack5-module-minifier-plugin/package.json b/webpack/webpack5-module-minifier-plugin/package.json new file mode 100644 index 00000000000..afbda124adf --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/webpack5-module-minifier-plugin", + "version": "5.6.7", + "description": "This plugin splits minification of webpack compilations into smaller units.", + "main": "lib/index.js", + "typings": "dist/webpack5-module-minifier-plugin.d.ts", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "webpack/webpack5-module-minifier-plugin" + }, + "engines": { + "node": ">=14.19.0" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/module-minifier": "*", + "webpack": "^5.68.0", + "@types/node": "*" + }, + "dependencies": { + "@rushstack/worker-pool": "workspace:*", + "@types/tapable": "1.0.6", + "@types/estree": "1.0.6", + "tapable": "2.2.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/module-minifier": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "memfs": "4.12.0", + "webpack": "~5.98.0" + }, + "sideEffects": false, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } +} diff --git a/webpack/webpack5-module-minifier-plugin/src/Constants.ts b/webpack/webpack5-module-minifier-plugin/src/Constants.ts new file mode 100644 index 00000000000..ad6ac554e7e --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/Constants.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. + +/** + * Prefix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it. + * Public because alternate Minifier implementations may wish to know about it. + * @public + */ +export const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__(' = '__MINIFY_MODULE__('; +/** + * Suffix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it. + * Public because alternate Minifier implementations may wish to know about it. + * @public + */ +export const MODULE_WRAPPER_SUFFIX: ');' = ');'; + +/** + * Token preceding a module id in the emitted asset so the minifier can operate on the Webpack runtime or chunk boilerplate in isolation + * @public + */ +export const CHUNK_MODULE_TOKEN: '__WEBPACK_CHUNK_MODULE__' = '__WEBPACK_CHUNK_MODULE__'; + +/** + * RegExp for replacing chunk module placeholders + * @public + */ +export const CHUNK_MODULE_REGEX: RegExp = /__WEBPACK_CHUNK_MODULE__([A-Za-z0-9$_]+)/g; + +/** + * Stage # to use when this should be the first tap in the hook + * @public + */ +export const STAGE_BEFORE: -10000 = -10000; +/** + * Stage # to use when this should be the last tap in the hook + * @public + */ +export const STAGE_AFTER: 100 = 100; diff --git a/webpack/webpack5-module-minifier-plugin/src/GenerateLicenseFileForAsset.ts b/webpack/webpack5-module-minifier-plugin/src/GenerateLicenseFileForAsset.ts new file mode 100644 index 00000000000..9b098c51b82 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/GenerateLicenseFileForAsset.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. + +import * as path from 'node:path'; + +import type { Comment } from 'estree'; +import type { Compilation, Module, sources } from 'webpack'; + +import type { IAssetInfo } from './ModuleMinifierPlugin.types'; + +function getAllComments(modules: Iterable): Set { + const allComments: Set = new Set(); + + for (const webpackModule of modules) { + const submodules: Iterable = (webpackModule.context === null && + (webpackModule as { _modules?: Iterable })._modules) || [webpackModule]; + for (const submodule of submodules) { + const subModuleComments: Iterable | undefined = ( + submodule.factoryMeta as { + comments?: Iterable; + } + )?.comments; + + if (subModuleComments) { + for (const comment of subModuleComments) { + const value: string = comment.type === 'Line' ? `//${comment.value}\n` : `/*${comment.value}*/\n`; + allComments.add(value); + } + } + } + } + + return allComments; +} + +/** + * Generates a companion asset containing all extracted comments. If it is non-empty, returns a banner comment directing users to said companion asset. + * + * @param compilation - The webpack compilation + * @param asset - The asset to process + * @public + */ +export function generateLicenseFileForAsset(compilation: Compilation, asset: IAssetInfo): string { + // Extracted comments from the modules. + const modules: Iterable = compilation.chunkGraph.getChunkModulesIterable(asset.chunk); + const comments: Set = getAllComments(modules); + + const assetName: string = asset.fileName; + + let banner: string = ''; + + if (comments.size) { + // There are license comments in this chunk, so generate the companion file and inject a banner + const licenseSource: sources.ConcatSource = new compilation.compiler.webpack.sources.ConcatSource(); + comments.forEach((comment) => { + licenseSource.add(comment); + }); + const licenseFileName: string = `${assetName}.LICENSE.txt`; + compilation.emitAsset(licenseFileName, licenseSource); + banner = `/*! For license information please see ${path.basename(licenseFileName)} */\n`; + } + + return banner; +} diff --git a/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts new file mode 100644 index 00000000000..84ba7a0771d --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.ts @@ -0,0 +1,567 @@ +// 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 { Comment } from 'estree'; +import type { + Module, + Compilation, + WebpackPluginInstance, + Compiler, + javascript, + WebpackError, + ExternalModule, + sources, + Chunk +} from 'webpack'; +import { AsyncSeriesWaterfallHook, SyncWaterfallHook, type Tap } from 'tapable'; + +import type { + IMinifierConnection, + IModuleMinifier, + IModuleMinificationResult, + IModuleMinificationErrorResult +} from '@rushstack/module-minifier'; +import { getIdentifier } from '@rushstack/module-minifier'; + +import { + CHUNK_MODULE_TOKEN, + MODULE_WRAPPER_PREFIX, + MODULE_WRAPPER_SUFFIX, + STAGE_BEFORE, + STAGE_AFTER +} from './Constants'; +import type { + IModuleMinifierPluginOptions, + IModuleMap, + IAssetMap, + IFactoryMeta, + IModuleMinifierPluginHooks, + IPostProcessFragmentContext, + IDehydratedAssets, + IModuleStats, + IModuleMinifierPluginStats as IModuleMinifierPluginStats, + IAssetStats +} from './ModuleMinifierPlugin.types'; +import { generateLicenseFileForAsset } from './GenerateLicenseFileForAsset'; +import { rehydrateAsset } from './RehydrateAsset'; + +// The name of the plugin, for use in taps +const PLUGIN_NAME: 'ModuleMinifierPlugin' = 'ModuleMinifierPlugin'; + +// Monotonically increasing identifier to be incremented any time the code generation logic changes +// Will be applied to the webpack hash. +const CODE_GENERATION_REVISION: number = 1; +// Match behavior of terser's "some" option +// https://github.com/terser/terser/blob/d3d924fa9e4c57bbe286b811c6068bcc7026e902/lib/output.js#L175 +const LICENSE_COMMENT_REGEX: RegExp = /@preserve|@lic|@cc_on|^\**!/i; + +const TAP_BEFORE: Tap = { + name: PLUGIN_NAME, + stage: STAGE_BEFORE +}; +const TAP_AFTER: Tap = { + name: PLUGIN_NAME, + stage: STAGE_AFTER +}; + +interface IOptionsForHash extends Omit { + revision: number; + minifier: undefined; +} + +interface ISourceCacheEntry { + source: sources.Source; + hash: string; +} + +const compilationMetadataMap: WeakMap = new WeakMap(); + +function hashCodeFragment(code: string): string { + return createHash('sha256').update(code).digest('hex'); +} + +/** + * Base implementation of asset rehydration + * + * @param dehydratedAssets The dehydrated assets + * @param compilation The webpack compilation + */ +function defaultRehydrateAssets( + dehydratedAssets: IDehydratedAssets, + compilation: Compilation +): IDehydratedAssets { + const { assets, modules } = dehydratedAssets; + + const compilationMetadata: IModuleMinifierPluginStats | undefined = compilationMetadataMap.get(compilation); + if (!compilationMetadata) { + throw new Error(`Could not get compilation metadata`); + } + + const { metadataByAssetFileName } = compilationMetadata; + + // Now assets/modules contain fully minified code. Rehydrate. + for (const [assetName, info] of assets) { + const banner: string = info.type === 'javascript' ? generateLicenseFileForAsset(compilation, info) : ''; + + const replacementSource: sources.Source = rehydrateAsset(compilation, info, modules, banner, true); + metadataByAssetFileName.set(assetName, { + positionByModuleId: info.renderInfo + }); + compilation.updateAsset(assetName, replacementSource); + } + + return dehydratedAssets; +} + +function isMinificationResultError( + result: IModuleMinificationResult +): result is IModuleMinificationErrorResult { + return !!result.error; +} + +function isLicenseComment(comment: Comment): boolean { + return LICENSE_COMMENT_REGEX.test(comment.value); +} + +/** + * Webpack plugin that minifies code on a per-module basis rather than per-asset. The actual minification is handled by the input `minifier` object. + * @public + */ +export class ModuleMinifierPlugin implements WebpackPluginInstance { + public readonly hooks: IModuleMinifierPluginHooks; + public minifier: IModuleMinifier; + + private readonly _enhancers: WebpackPluginInstance[]; + private readonly _sourceMap: boolean | undefined; + + private readonly _optionsForHash: IOptionsForHash; + + public constructor(options: IModuleMinifierPluginOptions) { + this.hooks = { + rehydrateAssets: new AsyncSeriesWaterfallHook(['dehydratedContent', 'compilation']), + + postProcessCodeFragment: new SyncWaterfallHook(['code', 'context']) + }; + + const { minifier, sourceMap } = options; + + this._optionsForHash = { + ...options, + minifier: undefined, + revision: CODE_GENERATION_REVISION + }; + + this._enhancers = []; + + this.hooks.rehydrateAssets.tap(PLUGIN_NAME, defaultRehydrateAssets); + this.minifier = minifier; + + this._sourceMap = sourceMap; + } + + public static getCompilationStatistics(compilation: Compilation): IModuleMinifierPluginStats | undefined { + return compilationMetadataMap.get(compilation); + } + + public apply(compiler: Compiler): void { + for (const enhancer of this._enhancers) { + enhancer.apply(compiler); + } + + const { + options: { devtool, mode }, + webpack + } = compiler; + + webpack.Template.numberToIdentifier = getIdentifier; + + const { CachedSource, ConcatSource, RawSource, ReplaceSource, SourceMapSource } = webpack.sources; + // The explicit setting is preferred due to accuracy, but try to guess based on devtool + const useSourceMaps: boolean = + typeof this._sourceMap === 'boolean' + ? this._sourceMap + : typeof devtool === 'string' + ? devtool.endsWith('source-map') + : mode === 'production' && devtool !== false; + + this._optionsForHash.sourceMap = useSourceMaps; + const binaryConfig: Buffer = Buffer.from(JSON.stringify(this._optionsForHash), 'utf-8'); + + compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation, compilationData) => { + const { normalModuleFactory } = compilationData; + + function addCommentExtraction(parser: javascript.JavascriptParser): void { + parser.hooks.program.tap(PLUGIN_NAME, (program: unknown, comments: Comment[]) => { + const relevantComments: Comment[] = comments.filter(isLicenseComment); + if (comments.length > 0) { + // Webpack's typings now restrict the properties on factoryMeta for unknown reasons + const module: { factoryMeta?: IFactoryMeta } = parser.state.module as unknown as { + factoryMeta?: IFactoryMeta; + }; + if (!module.factoryMeta) { + module.factoryMeta = { + comments: relevantComments + }; + } else { + (module.factoryMeta as IFactoryMeta).comments = relevantComments; + } + } + }); + } + + normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, addCommentExtraction); + normalModuleFactory.hooks.parser.for('javascript/dynamic').tap(PLUGIN_NAME, addCommentExtraction); + normalModuleFactory.hooks.parser.for('javascript/esm').tap(PLUGIN_NAME, addCommentExtraction); + + /** + * Set of local module ids that have been processed. + */ + const submittedModules: Set = new Set(); + + /** + * The text and comments of all minified modules. + */ + const minifiedModules: IModuleMap = new Map(); + + /** + * The text and comments of all minified chunks. Most of these are trivial, but the runtime chunk is a bit larger. + */ + const minifiedAssets: IAssetMap = new Map(); + + const metadataByModule: WeakMap = new WeakMap(); + const metadataByAssetFileName: Map = new Map(); + const compilationStatistics: IModuleMinifierPluginStats = { + metadataByModule, + metadataByAssetFileName + }; + compilationMetadataMap.set(compilation, compilationStatistics); + function getOrCreateMetadata(mod: Module): IModuleStats { + let moduleStats: IModuleStats | undefined = metadataByModule.get(mod); + if (!moduleStats) { + moduleStats = { + hashByChunk: new Map(), + sizeByHash: new Map() + }; + metadataByModule.set(mod, moduleStats); + } + return moduleStats; + } + + let pendingMinificationRequests: number = 0; + /** + * Indicates that all files have been sent to the minifier and therefore that when pending hits 0, assets can be rehydrated. + */ + let allRequestsIssued: boolean = false; + + let resolveMinifyPromise: () => void; + + const postProcessCode: ( + code: sources.ReplaceSource, + context: IPostProcessFragmentContext + ) => sources.ReplaceSource = (code: sources.ReplaceSource, context: IPostProcessFragmentContext) => + this.hooks.postProcessCodeFragment.call(code, context); + + /** + * Callback to invoke when a file has finished minifying. + */ + function onFileMinified(): void { + if (--pendingMinificationRequests === 0 && allRequestsIssued) { + resolveMinifyPromise(); + } + } + + const { minifier } = this; + + let minifierConnection: IMinifierConnection | undefined; + + // Typings for this object are not exposed + // eslint-disable-next-line @typescript-eslint/typedef + const javascriptHooks = webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(compilation); + + /** + * The minifier needs to know if the module was wrapped in a factory function, because + * function (module, exports, require) { // } + * minifies to nothing. Unfortunately we can't tell by inspection if the output was wrapped or not. + * However, the JavaScriptModulesPlugin invokes three hooks in order when rendering a module: + * 1) renderModuleContent - Invoked for every module. + * 2) renderModuleContainer - Invoked when wrapping a module in a factory. + * 3) renderModulePackage - Invoked for every module as the last hook. + */ + let nextModule: Module | undefined; + const sourceCache: WeakMap = new WeakMap(); + javascriptHooks.renderModuleContent.tap(TAP_AFTER, (source) => { + // Clear the identification state of the current module. + nextModule = undefined; + return source; + }); + javascriptHooks.renderModuleContainer.tap(TAP_AFTER, (source, mod) => { + // Module is being wrapped in a factory, so it is safe for per-module minification + // Leave external modules in-place to avoid needing special handling for externals + if (mod.context !== null || !(mod as ExternalModule).externalType) { + nextModule = mod; + } + return source; + }); + javascriptHooks.renderModulePackage.tap( + TAP_AFTER, + /** + * Extracts the code for the module and sends it to be minified. + */ + function minifyModule( + source: sources.Source, + mod: Module, + chunkRenderContext: { chunk: Chunk } + ): sources.Source { + if (nextModule !== mod) { + // This module is being inlined. Abandon per-module minification. + return source; + } + + const id: string | number | null = compilation.chunkGraph.getModuleId(mod); + + if (id === null) { + // This module has no id. Abandon per-module minification. + return source; + } + + const metadata: IModuleStats = getOrCreateMetadata(mod); + const cachedResult: ISourceCacheEntry | undefined = sourceCache.get(source); + if (cachedResult) { + metadata.hashByChunk.set(chunkRenderContext.chunk, cachedResult.hash); + return cachedResult.source; + } + + // If this module is wrapped in a factory, need to add boilerplate so that the minifier keeps the function + const wrapped: sources.Source = new ConcatSource( + MODULE_WRAPPER_PREFIX + '\n', + source, + '\n' + MODULE_WRAPPER_SUFFIX + ); + + const nameForMap: string = `(modules)/${id}`; + + const { source: wrappedCodeRaw, map } = useSourceMaps + ? wrapped.sourceAndMap() + : { + source: wrapped.source(), + map: undefined + }; + + const wrappedCode: string = wrappedCodeRaw.toString(); + const hash: string = hashCodeFragment(wrappedCode); + metadata.hashByChunk.set(chunkRenderContext.chunk, hash); + if (!submittedModules.has(hash)) { + submittedModules.add(hash); + + ++pendingMinificationRequests; + + minifier.minify( + { + hash, + code: wrappedCode, + nameForMap: useSourceMaps ? nameForMap : undefined, + externals: undefined + }, + (result: IModuleMinificationResult) => { + if (isMinificationResultError(result)) { + compilation.errors.push(result.error as WebpackError); + } else { + try { + const { code: minified, map: minifierMap } = result; + + const rawOutput: sources.Source = useSourceMaps + ? new SourceMapSource( + minified, // Code + nameForMap, // File + minifierMap!, // Base source map + wrappedCode, // Source from before transform + map!, // Source Map from before transform + true // Remove original source + ) + : new RawSource(minified); + + const unwrapped: sources.ReplaceSource = new ReplaceSource(rawOutput); + const len: number = minified.length; + + // Trim off the boilerplate used to preserve the factory + unwrapped.replace(0, MODULE_WRAPPER_PREFIX.length - 1, ''); + unwrapped.replace(len - MODULE_WRAPPER_SUFFIX.length, len - 1, ''); + + const withIds: sources.Source = postProcessCode(unwrapped, { + compilation, + module: mod, + loggingName: mod.identifier() + }); + const cached: sources.CachedSource = new CachedSource(withIds); + + const minifiedSize: number = Buffer.byteLength(cached.source(), 'utf-8'); + metadata.sizeByHash.set(hash, minifiedSize); + + minifiedModules.set(hash, { + source: cached, + module: mod, + id + }); + } catch (err) { + compilation.errors.push(err); + } + } + + onFileMinified(); + } + ); + } + + const result: sources.Source = new RawSource(`${CHUNK_MODULE_TOKEN}${hash}`); + sourceCache.set(source, { + hash, + source: result + }); + + // Return an expression to replace later + return result; + } + ); + + // The optimizeChunkModules hook is the last async hook that occurs before chunk rendering + compilation.hooks.optimizeChunkModules.tapPromise(PLUGIN_NAME, async () => { + minifierConnection = await minifier.connectAsync(); + + submittedModules.clear(); + }); + + const isJSAsset: RegExp = /\.[cm]?js(\?.+)?$/; + + // This should happen before any other tasks that operate during processAssets + compilation.hooks.processAssets.tapPromise(TAP_BEFORE, async (): Promise => { + const { chunkGraph, chunks } = compilation; + + // Still need to minify the rendered assets + for (const chunk of chunks) { + const allChunkModules: Iterable | undefined = + chunkGraph.getChunkModulesIterableBySourceType(chunk, 'javascript'); + if (!allChunkModules) { + // This chunk does not contain javascript modules + continue; + } + + for (const assetName of chunk.files) { + const asset: sources.Source = compilation.assets[assetName]; + + // Verify that this is a JS asset + if (isJSAsset.test(assetName)) { + ++pendingMinificationRequests; + + const { source: wrappedCodeRaw, map } = useSourceMaps + ? asset.sourceAndMap() + : { + source: asset.source(), + map: undefined + }; + + const rawCode: string = wrappedCodeRaw.toString(); + const nameForMap: string = `(chunks)/${assetName}`; + + const hash: string = hashCodeFragment(rawCode); + + minifier.minify( + { + hash, + code: rawCode, + nameForMap: useSourceMaps ? nameForMap : undefined, + externals: undefined + }, + (result: IModuleMinificationResult) => { + if (isMinificationResultError(result)) { + compilation.errors.push(result.error as WebpackError); + // eslint-disable-next-line no-console + console.error(result.error); + } else { + try { + const { code: minified, map: minifierMap } = result; + + const rawOutput: sources.Source = useSourceMaps + ? new SourceMapSource( + minified, // Code + nameForMap, // File + minifierMap!, // Base source map + rawCode, // Source from before transform + map, // Source Map from before transform + true // Remove original source + ) + : new RawSource(minified); + + const withIds: sources.Source = postProcessCode(new ReplaceSource(rawOutput), { + compilation, + module: undefined, + loggingName: assetName + }); + + minifiedAssets.set(assetName, { + source: new CachedSource(withIds), + chunk, + fileName: assetName, + renderInfo: new Map(), + type: 'javascript' + }); + } catch (err) { + compilation.errors.push(err); + } + } + + onFileMinified(); + } + ); + } else { + // This isn't a JS asset. Don't try to minify the asset wrapper, though if it contains modules, those might still get replaced with minified versions. + minifiedAssets.set(assetName, { + // Still need to restore ids + source: postProcessCode(new ReplaceSource(asset), { + compilation, + module: undefined, + loggingName: assetName + }), + chunk, + fileName: assetName, + renderInfo: new Map(), + type: 'unknown' + }); + } + } + } + + allRequestsIssued = true; + + if (pendingMinificationRequests) { + await new Promise((resolve) => { + resolveMinifyPromise = resolve; + }); + } + + // Handle any error from the minifier. + await minifierConnection?.disconnectAsync(); + + // All assets and modules have been minified, hand them off to be rehydrated + await this.hooks.rehydrateAssets.promise( + { + assets: minifiedAssets, + modules: minifiedModules + }, + compilation + ); + }); + + // Need to update chunk hashes with information from this plugin + javascriptHooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash): void => { + // Apply the options hash + hash.update(binaryConfig); + // Apply the hash from the minifier + if (minifierConnection) { + hash.update(minifierConnection.configHash, 'utf8'); + } + }); + }); + } +} diff --git a/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts new file mode 100644 index 00000000000..8d6e7de5902 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/ModuleMinifierPlugin.types.ts @@ -0,0 +1,222 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { AsyncSeriesWaterfallHook, SyncWaterfallHook } from 'tapable'; +import type { Chunk, Compilation, Module, sources } from 'webpack'; +import type { Comment } from 'estree'; + +import type { IModuleMinifier } from '@rushstack/module-minifier'; + +/** + * Information about where the module was rendered in the emitted asset. + * @public + */ +export interface IRenderedModulePosition { + /** + * The offset from the start of tha asset to the start of the module, in characters. + */ + charOffset: number; + /** + * The length of the rendered module, in characters. + */ + charLength: number; +} + +/** + * Information about a dehydrated webpack ECMAScript asset + * @public + */ +export interface IAssetInfo { + /** + * The (minified) boilerplate code for the asset. Will contain a token to be replaced by the minified modules. + */ + source: sources.Source; + + /** + * The name of the asset, used to index into compilation.assets + */ + fileName: string; + + /** + * The raw chunk object from Webpack, in case information from it is necessary for reconstruction + */ + chunk: Chunk; + + /** + * Information about the offsets and character lengths for each rendered module in the final asset. + */ + renderInfo: Map; + + /** + * The type of the asset + * @example 'javascript' + * @example 'css' + */ + type: string; +} + +/** + * Information about a minified module + * @public + */ +export interface IModuleInfo { + /** + * The (minified) code of this module. Will be a function expression. + */ + source: sources.Source; + + /** + * The raw module object from Webpack, in case information from it is necessary for reconstruction + */ + module: Module; + + /** + * The id of the module, from the chunk graph. + */ + id: string | number; +} + +/** + * This is the second parameter to the NormalModuleFactory `module` hook + * @internal + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface _INormalModuleFactoryModuleData { + resourceResolveData?: { + /** + * Contents of the description file (package.json) for the module + */ + descriptionFileData?: { + /** + * The name of the package + */ + name: string; + }; + /** + * Absolute path of the description file (package.json) for the module + */ + descriptionFilePath?: string; + /** + * Absolute path of the directory containing the description file (package.json) for the module + */ + descriptionFileRoot?: string; + /** + * Relative path from the description file (package.json) to the module + */ + relativePath?: string; + }; +} + +/** + * Properties surfaced via the `factoryMeta` property on webpack modules + * @public + */ +export interface IFactoryMeta { + comments?: Comment[]; + skipMinification?: boolean; +} + +/** + * Statistics from the plugin. Namely module sizes. + * @public + */ +export interface IModuleMinifierPluginStats { + metadataByModule: WeakMap; + metadataByAssetFileName: Map; +} + +/** + * Module size data as a function of the target chunk. + * @public + */ +export interface IModuleStats { + hashByChunk: Map; + sizeByHash: Map; +} + +/** + * Rendered positional data + * @public + */ +export interface IAssetStats { + positionByModuleId: Map; +} + +/** + * A map from file names to dehydrated assets + * @public + */ +export type IAssetMap = Map; +/** + * A map from module ids to minified modules + * @public + */ +export type IModuleMap = Map; + +/** + * Options to the ModuleMinifierPlugin constructor + * @public + */ +export interface IModuleMinifierPluginOptions { + /** + * Minifier implementation to use. Required. + */ + minifier: IModuleMinifier; + + /** + * Whether to enable source map processing. If not provided, will attempt to guess based on `mode` and `devtool` in the webpack config. + * Set to `false` for faster builds at the expense of debuggability. + */ + sourceMap?: boolean; +} + +/** + * The set of data remaining to rehydrate in the current compilation + * @public + */ +export interface IDehydratedAssets { + /** + * The set of remaining assets to rehydrate. Each tap may remove some or all assets from this collection + */ + assets: IAssetMap; + + /** + * The set of modules to use for rehydrating assets. + */ + modules: IModuleMap; +} + +/** + * Argument to the postProcessCodeFragment hook for the current execution context + * @public + */ +export interface IPostProcessFragmentContext { + /** + * The current webpack compilation, for error reporting + */ + compilation: Compilation; + /** + * A name to use for logging + */ + loggingName: string; + /** + * The current module being processed, or `undefined` if not in a module (e.g. the bootstrapper) + */ + module: Module | undefined; +} + +/** + * Hooks provided by the ModuleMinifierPlugin + * @public + */ +export interface IModuleMinifierPluginHooks { + /** + * Hook invoked at the start of optimizeChunkAssets to rehydrate the minified boilerplate and runtime into chunk assets. + */ + rehydrateAssets: AsyncSeriesWaterfallHook<[IDehydratedAssets, Compilation]>; + + /** + * Hook invoked on code after it has been returned from the minifier. + */ + postProcessCodeFragment: SyncWaterfallHook<[sources.ReplaceSource, IPostProcessFragmentContext]>; +} diff --git a/webpack/webpack5-module-minifier-plugin/src/RehydrateAsset.ts b/webpack/webpack5-module-minifier-plugin/src/RehydrateAsset.ts new file mode 100644 index 00000000000..d72f950bf2e --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/RehydrateAsset.ts @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { sources, Compilation } from 'webpack'; + +import { CHUNK_MODULE_TOKEN, CHUNK_MODULE_REGEX } from './Constants'; +import type { IAssetInfo, IModuleMap, IModuleInfo } from './ModuleMinifierPlugin.types'; + +/** + * Rehydrates an asset with minified modules. + * @param asset - The asset + * @param moduleMap - The minified modules + * @param banner - A banner to inject for license information + * @public + */ +export function rehydrateAsset( + compilation: Compilation, + asset: IAssetInfo, + moduleMap: IModuleMap, + banner: string, + emitRenderInfo?: boolean +): sources.Source { + const { source: assetSource } = asset; + const { + webpack: { sources, WebpackError } + } = compilation.compiler; + + const assetCode: string = assetSource.source().toString(); + + const tokenIndex: number = assetCode.indexOf(CHUNK_MODULE_TOKEN); + if (tokenIndex < 0) { + // This is not a JS asset. + return assetSource; + } + + const { CachedSource, ConcatSource, ReplaceSource } = sources; + + CHUNK_MODULE_REGEX.lastIndex = -1; + let lastStart: number = 0; + + const cachedAssetSource: sources.CachedSource = new CachedSource(assetSource); + + const source: sources.ConcatSource = new ConcatSource(banner); + let charOffset: number = banner.length; + + // RegExp.exec uses null or an array as the return type, explicitly + let match: RegExpExecArray | null = null; + while ((match = CHUNK_MODULE_REGEX.exec(assetCode))) { + const hash: string = match[1]; + + const moduleSource: IModuleInfo | undefined = moduleMap.get(hash); + if (moduleSource === undefined) { + compilation.errors.push(new WebpackError(`Missing module source for ${hash} in ${asset.fileName}!`)); + } + + const separator: sources.ReplaceSource = extractSegmentFromSource( + ReplaceSource, + cachedAssetSource, + lastStart, + match.index + ); + + source.add(separator); + charOffset += separator.size(); + + lastStart = CHUNK_MODULE_REGEX.lastIndex; + + if (moduleSource) { + const charLength: number = moduleSource.source.source().length; + + if (emitRenderInfo) { + asset.renderInfo.set(moduleSource.id, { + charOffset, + charLength + }); + } + + source.add(moduleSource.source); + charOffset += charLength; + } else { + const errorModule: string = `()=>{throw new Error(\`Missing module with hash "${hash}"\`)}`; + + source.add(errorModule); + charOffset += errorModule.length; + } + + source.add('\n'); + charOffset += 1; + } + + source.add(extractSegmentFromSource(ReplaceSource, cachedAssetSource, lastStart, Infinity)); + + return new CachedSource(source); +} + +// In order to preserve source maps during substitution, have to use a ConcatSource instead of a ReplaceSource, so need to extract the segements from the original +function extractSegmentFromSource( + replaceSourceConstructor: typeof sources.ReplaceSource, + source: sources.Source, + start: number, + end: number +): sources.ReplaceSource { + const result: sources.ReplaceSource = new replaceSourceConstructor(source); + result.replace(end, Infinity, ''); + result.replace(0, start - 1, ''); + return result; +} diff --git a/webpack/webpack5-module-minifier-plugin/src/index.ts b/webpack/webpack5-module-minifier-plugin/src/index.ts new file mode 100644 index 00000000000..38762c61f7e --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/index.ts @@ -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. + +export * from './Constants'; +export * from './GenerateLicenseFileForAsset'; +export type { + IAssetInfo, + IAssetMap, + IAssetStats, + IDehydratedAssets, + IFactoryMeta, + IModuleInfo, + IModuleMap, + IModuleMinifierPluginHooks, + IModuleMinifierPluginOptions, + IModuleMinifierPluginStats, + IModuleStats, + IPostProcessFragmentContext, + IRenderedModulePosition +} from './ModuleMinifierPlugin.types'; +export * from './ModuleMinifierPlugin'; diff --git a/webpack/webpack5-module-minifier-plugin/src/test/AmdExternals.test.ts b/webpack/webpack5-module-minifier-plugin/src/test/AmdExternals.test.ts new file mode 100644 index 00000000000..dd41c3a6313 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/AmdExternals.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.disableAutomock(); +import { promisify } from 'node:util'; + +import webpack, { type Stats, type InputFileSystem, type OutputFileSystem } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { type IModuleMinifier, LocalMinifier } from '@rushstack/module-minifier'; + +import { ModuleMinifierPlugin } from '../ModuleMinifierPlugin'; +import { MockMinifier } from './MockMinifier'; +import { RecordMetadataPlugin } from './RecordMetadataPlugin'; + +jest.setTimeout(1e9); + +async function amdExternalsTest(minifier: IModuleMinifier): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/package.json': '{}', + '/entry.js': `// A comment\nconsole.log("Do stuff");import(/* webpackChunkName: 'async' */ './async.js').then(mod => mod.foo());`, + '/async.js': `// @license MIT\nimport bar from 'bar';\nimport baz from 'baz';\nexport function foo() { bar.a(); baz.b(); }console.log("Test character lengths: \ufeff\uffef")` + }, + '/src' + ); + + const minifierPlugin: ModuleMinifierPlugin = new ModuleMinifierPlugin({ + minifier + }); + const metadataPlugin: RecordMetadataPlugin = new RecordMetadataPlugin(); + + const compiler: webpack.Compiler = webpack({ + entry: { + main: '/entry.js' + }, + output: { + path: '/release', + filename: '[name].js', + libraryTarget: 'amd' + }, + externals: { + bar: { + amd: 'bar' + }, + baz: { + amd: 'baz' + } + }, + optimization: { + minimizer: [] + }, + context: '/', + mode: 'production', + plugins: [minifierPlugin, metadataPlugin] + }); + + compiler.inputFileSystem = memoryFileSystem as unknown as InputFileSystem; + compiler.outputFileSystem = memoryFileSystem as unknown as OutputFileSystem; + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler)); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + expect(metadataPlugin.metadata).toMatchSnapshot('Metadata'); +} + +describe(ModuleMinifierPlugin.name, () => { + it('Handles AMD externals (mock)', async () => { + await amdExternalsTest(new MockMinifier()); + }); + + it('Handles AMD externals (terser)', async () => { + await amdExternalsTest( + new LocalMinifier({ + terserOptions: { + mangle: true, + ecma: 2020 + } + }) + ); + }); +}); diff --git a/webpack/webpack5-module-minifier-plugin/src/test/MockMinifier.ts b/webpack/webpack5-module-minifier-plugin/src/test/MockMinifier.ts new file mode 100644 index 00000000000..d5e6ff8fd52 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/MockMinifier.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 type { + IModuleMinifier, + IModuleMinificationRequest, + IModuleMinificationCallback, + IMinifierConnection +} from '@rushstack/module-minifier'; + +import { MODULE_WRAPPER_PREFIX, MODULE_WRAPPER_SUFFIX } from '../Constants'; + +export class MockMinifier implements IModuleMinifier { + public readonly requests: Map = new Map(); + + /** + * Mock code transform. + * @param request - The request to process + * @param callback - The callback to invoke + */ + public minify(request: IModuleMinificationRequest, callback: IModuleMinificationCallback): void { + const { code, hash, nameForMap } = request; + + this.requests.set(hash, code); + + const isModule: boolean = code.startsWith(MODULE_WRAPPER_PREFIX); + const processedCode: string = isModule + ? `${MODULE_WRAPPER_PREFIX}\n// Begin Module Hash=${hash}\n${code.slice( + MODULE_WRAPPER_PREFIX.length, + -MODULE_WRAPPER_SUFFIX.length + )}\n// End Module${MODULE_WRAPPER_SUFFIX}` + : `// Begin Asset Hash=${hash}\n${code}\n// End Asset`; + + callback({ + hash, + error: undefined, + code: processedCode, + // If source maps are requested, provide an empty source map + map: nameForMap + ? { + version: 3, + names: [], + file: nameForMap, + sources: [nameForMap], + sourcesContent: [code], + // In source mapping parlance, this means "map line 0, column 0 to the input file at index 0, line 0, column 0" + mappings: 'AAAA' + } + : undefined + }); + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + public async connect(): Promise { + throw new Error('Not implemented.'); + } + + /** + * {@inheritdoc} + */ + public async connectAsync(): Promise { + return { + configHash: MockMinifier.name, + + disconnectAsync: async () => { + // Do nothing. + }, + disconnect: () => { + throw new Error('Method not implemented.'); + } + }; + } +} diff --git a/webpack/webpack5-module-minifier-plugin/src/test/MultipleRuntimes.test.ts b/webpack/webpack5-module-minifier-plugin/src/test/MultipleRuntimes.test.ts new file mode 100644 index 00000000000..d7c0fd190d5 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/MultipleRuntimes.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. + +jest.disableAutomock(); +import { promisify } from 'node:util'; + +import webpack, { type Stats, type InputFileSystem, type OutputFileSystem } from 'webpack'; +import { Volume } from 'memfs/lib/volume'; + +import { ModuleMinifierPlugin } from '../ModuleMinifierPlugin'; +import { MockMinifier } from './MockMinifier'; +import { RecordMetadataPlugin } from './RecordMetadataPlugin'; +import { type IModuleMinifier, LocalMinifier } from '@rushstack/module-minifier'; + +jest.setTimeout(1e9); + +async function multipleRuntimesTest(minifier: IModuleMinifier): Promise { + const memoryFileSystem: Volume = new Volume(); + memoryFileSystem.fromJSON( + { + '/package.json': '{}', + '/entry-1.js': `// A comment\nconsole.log("Do stuff");\nimport(/* webpackChunkName: 'async-1' */ /* webpackExports: ["async1"] */ './async.js').then(mod => mod.async1());\nimport(/* webpackChunkName: 'async-1' */ './async-1.js').then(mod => mod.async1());`, + '/entry-2.js': `// A comment\nconsole.log("Do stuff");\nimport(/* webpackChunkName: 'async-2' */ /* webpackExports: ["a2"] */ './async.js').then(mod => mod.a2());\nimport(/* webpackChunkName: 'async-2' */ './async-2.js').then(mod => mod.a2());`, + '/async.js': `// @license MIT\nexport { async1 } from './async-1';\nexport { a2 } from './async-2';`, + '/async-1.js': `// @license BAR\nexport function async1() { console.log('async-1'); }`, + '/async-2.js': `// @license BAZ\nexport function a2() { console.log('async-2'); }` + }, + '/src' + ); + + const minifierPlugin: ModuleMinifierPlugin = new ModuleMinifierPlugin({ + minifier + }); + const metadataPlugin: RecordMetadataPlugin = new RecordMetadataPlugin(); + + const compiler: webpack.Compiler = webpack({ + entry: { + entry1: '/entry-1.js', + entry2: '/entry-2.js' + }, + output: { + path: '/release', + filename: '[name].js' + }, + optimization: { + minimizer: [] + }, + context: '/', + mode: 'production', + plugins: [minifierPlugin, metadataPlugin] + }); + + compiler.inputFileSystem = memoryFileSystem as unknown as InputFileSystem; + compiler.outputFileSystem = memoryFileSystem as unknown as OutputFileSystem; + + const stats: Stats | undefined = await promisify(compiler.run.bind(compiler))(); + await promisify(compiler.close.bind(compiler)); + if (!stats) { + throw new Error(`Expected stats`); + } + const { errors, warnings } = stats.toJson('errors-warnings'); + expect(errors).toMatchSnapshot('Errors'); + expect(warnings).toMatchSnapshot('Warnings'); + + const results: {} = memoryFileSystem.toJSON('/release'); + expect(results).toMatchSnapshot('Content'); + expect(metadataPlugin.metadata).toMatchSnapshot('Metadata'); +} + +describe(ModuleMinifierPlugin.name, () => { + it('Handles multiple runtimes (mock)', async () => { + await multipleRuntimesTest(new MockMinifier()); + }); + + it('Handles multiple runtimes (terser)', async () => { + await multipleRuntimesTest( + new LocalMinifier({ + terserOptions: { + mangle: true, + ecma: 2020 + } + }) + ); + }); +}); diff --git a/webpack/webpack5-module-minifier-plugin/src/test/RecordMetadataPlugin.ts b/webpack/webpack5-module-minifier-plugin/src/test/RecordMetadataPlugin.ts new file mode 100644 index 00000000000..6b0fb035659 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/RecordMetadataPlugin.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 type { Compilation, Compiler, WebpackPluginInstance } from 'webpack'; + +import type { IModuleStats, IModuleMinifierPluginStats, IAssetStats } from '../ModuleMinifierPlugin.types'; +import { ModuleMinifierPlugin } from '../ModuleMinifierPlugin'; + +export type IFlattenedModuleMetadata = Map; +export type IFlattenedCompilationModuleMetadata = Map; + +export interface IFlattenedCompilationMetadata { + byModule: IFlattenedCompilationModuleMetadata; + byAssetFilename: Map; +} + +export class RecordMetadataPlugin implements WebpackPluginInstance { + public readonly metadata: IFlattenedCompilationMetadata = { + byModule: new Map(), + byAssetFilename: new Map() + }; + + public apply(compiler: Compiler): void { + compiler.hooks.afterEmit.tap('RecordMetadataPlugin', (compilation: Compilation) => { + const { chunkGraph } = compilation; + + const { metadata } = this; + metadata.byModule.clear(); + + const compilationMetadata: IModuleMinifierPluginStats | undefined = + ModuleMinifierPlugin.getCompilationStatistics(compilation); + if (!compilationMetadata) { + throw new Error(`Unable to get ModuleMinfierPlugin statistics`); + } + + const { metadataByModule, metadataByAssetFileName } = compilationMetadata; + metadata.byAssetFilename = metadataByAssetFileName; + + for (const module of compilation.modules) { + const id: string | number | null = chunkGraph.getModuleId(module); + const metadataForModule: IModuleStats | undefined = metadataByModule.get(module); + if (metadataForModule && id !== null) { + const flattenedModule: IFlattenedModuleMetadata = new Map(); + for (const [chunk, hash] of metadataForModule.hashByChunk) { + const chunkId: string | number | null = chunk.id; + if (!chunkId) { + throw new Error(`Missing a chunk id`); + } + const size: number | undefined = metadataForModule.sizeByHash.get(hash); + + flattenedModule.set(chunkId, typeof size === 'number' ? size : 'inline'); + } + metadata.byModule.set(id, flattenedModule); + } + } + }); + } +} diff --git a/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/AmdExternals.test.ts.snap b/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/AmdExternals.test.ts.snap new file mode 100644 index 00000000000..73e8bbc8b3b --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/AmdExternals.test.ts.snap @@ -0,0 +1,396 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ModuleMinifierPlugin Handles AMD externals (mock): Content 1`] = ` +Object { + "/release/async.js": "/*! For license information please see async.js.LICENSE.txt */ +// Begin Asset Hash=ac6de72b824de4fb2378d67eedab44cba6dabd6a461ff7e34e193f5403082522 +\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[157],{ + +/***/ 541: + +// Begin Module Hash=6f667256aae962bddfb95cc093f6b523502659b0ce95fcfd296ed47393e4e9ec + +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ foo: () => (/* binding */ foo) +/* harmony export */ }); +/* harmony import */ var bar__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(885); +/* harmony import */ var bar__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(bar__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var baz__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(653); +/* harmony import */ var baz__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(baz__WEBPACK_IMPORTED_MODULE_1__); +// @license MIT + + +function foo() { bar__WEBPACK_IMPORTED_MODULE_0___default().a(); baz__WEBPACK_IMPORTED_MODULE_1___default().b(); }console.log(\\"Test character lengths: ￯\\") + +/***/ }) + +// End Module + + +}]); +// End Asset", + "/release/async.js.LICENSE.txt": "// @license MIT +", + "/release/main.js": "// Begin Asset Hash=a16226243c0a8fad3212933459d35fff4cd7faadc27f7fced2f403aa99271bc6 +define([\\"bar\\",\\"baz\\"], (__WEBPACK_EXTERNAL_MODULE__885__, __WEBPACK_EXTERNAL_MODULE__653__) => { return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 653: +/***/ ((module) => { + +\\"use strict\\"; +module.exports = __WEBPACK_EXTERNAL_MODULE__653__; + +/***/ }), + +/***/ 885: +/***/ ((module) => { + +\\"use strict\\"; +module.exports = __WEBPACK_EXTERNAL_MODULE__885__; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + \\"async\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 792: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// A comment +console.log(\\"Do stuff\\");__webpack_require__.e(/* import() | async */ 157).then(__webpack_require__.bind(__webpack_require__, 541)).then(mod => mod.foo()); +/******/ return __webpack_exports__; +/******/ })() +; +});; +// End Asset", +} +`; + +exports[`ModuleMinifierPlugin Handles AMD externals (mock): Errors 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles AMD externals (mock): Metadata 1`] = ` +Object { + "byAssetFilename": Map { + "main.js" => Object { + "positionByModuleId": Map {}, + }, + "async.js" => Object { + "positionByModuleId": Map { + 541 => Object { + "charLength": 1004, + "charOffset": 240, + }, + }, + }, + }, + "byModule": Map { + 541 => Map { + 157 => 1008, + }, + }, +} +`; + +exports[`ModuleMinifierPlugin Handles AMD externals (mock): Warnings 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles AMD externals (terser): Content 1`] = ` +Object { + "/release/async.js": "/*! For license information please see async.js.LICENSE.txt */ +\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[157],{541:((e,t,n)=>{n.r(t),n.d(t,{foo:()=>s});var a=n(885),i=n.n(a),r=n(653),o=n.n(r);function s(){i().a(),o().b()}console.log(\\"Test character lengths: \\\\ufeff￯\\")}) +}]);", + "/release/async.js.LICENSE.txt": "// @license MIT +", + "/release/main.js": "define([\\"bar\\",\\"baz\\"],((e,t)=>(()=>{var n,a={653:e=>{\\"use strict\\";e.exports=t},885:t=>{\\"use strict\\";t.exports=e}},i={};function r(e){var t=i[e];if(void 0!==t)return t.exports;var n=i[e]={exports:{}};return a[e](n,n.exports,r),n.exports}r.m=a,r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((t,n)=>(r.f[n](e,t),t)),[])),r.u=e=>\\"async.js\\",r.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n={},r.l=(e,t,a,i)=>{if(n[e])n[e].push(t);else{var o,s;if(void 0!==a)for(var c=document.getElementsByTagName(\\"script\\"),d=0;d{o.onerror=o.onload=null,clearTimeout(f);var i=n[e];if(delete n[e],o.parentNode&&o.parentNode.removeChild(o),i&&i.forEach((e=>e(a))),t)return t(a)},f=setTimeout(u.bind(null,void 0,{type:\\"timeout\\",target:o}),12e4);o.onerror=u.bind(null,o.onerror),o.onload=u.bind(null,o.onload),s&&document.head.appendChild(o)}},r.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;r.g.importScripts&&(e=r.g.location+\\"\\");var t=r.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var n=t.getElementsByTagName(\\"script\\");if(n.length)for(var a=n.length-1;a>-1&&(!e||!/^http(s?):/.test(e));)e=n[a--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),r.p=e})(),(()=>{var e={792:0};r.f.j=(t,n)=>{var a=r.o(e,t)?e[t]:void 0;if(0!==a)if(a)n.push(a[2]);else{var i=new Promise(((n,i)=>a=e[t]=[n,i]));n.push(a[2]=i);var o=r.p+r.u(t),s=new Error;r.l(o,(n=>{if(r.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var i=n&&(\\"load\\"===n.type?\\"missing\\":n.type),o=n&&n.target&&n.target.src;s.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+i+\\": \\"+o+\\")\\",s.name=\\"ChunkLoadError\\",s.type=i,s.request=o,a[1](s)}}),\\"chunk-\\"+t,t)}};var t=(t,n)=>{var a,i,[o,s,c]=n,d=0;if(o.some((t=>0!==e[t]))){for(a in s)r.o(s,a)&&(r.m[a]=s[a]);if(c)c(r)}for(t&&t(n);de.foo())),{}})()));", +} +`; + +exports[`ModuleMinifierPlugin Handles AMD externals (terser): Errors 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles AMD externals (terser): Metadata 1`] = ` +Object { + "byAssetFilename": Map { + "main.js" => Object { + "positionByModuleId": Map {}, + }, + "async.js" => Object { + "positionByModuleId": Map { + 541 => Object { + "charLength": 154, + "charOffset": 135, + }, + }, + }, + }, + "byModule": Map { + 541 => Map { + 157 => 156, + }, + }, +} +`; + +exports[`ModuleMinifierPlugin Handles AMD externals (terser): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/MultipleRuntimes.test.ts.snap b/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/MultipleRuntimes.test.ts.snap new file mode 100644 index 00000000000..2791ccff7e3 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/src/test/__snapshots__/MultipleRuntimes.test.ts.snap @@ -0,0 +1,751 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ModuleMinifierPlugin Handles multiple runtimes (mock): Content 1`] = ` +Object { + "/release/async-1.js": "/*! For license information please see async-1.js.LICENSE.txt */ +// Begin Asset Hash=ff7711496c462459a6893d8540f88be9b5205a72695fecca0e9a729108dd3b01 +\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[527],{ + +/***/ 541: + +// Begin Module Hash=445eb01e9f53ea96b925fbefbc4d13fdd2ca421fb980991639b16dcabad2679e + +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ async1: () => (/* reexport safe */ _async_1__WEBPACK_IMPORTED_MODULE_0__.async1) +/* harmony export */ }); +/* harmony import */ var _async_1__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(923); +// @license MIT + + + +/***/ }) + +// End Module +, + +/***/ 923: + +// Begin Module Hash=371cb4826740509b29e1cfede618ecb8bcd12f587e57062466b425e2d93ea34e + +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ async1: () => (/* binding */ async1) +/* harmony export */ }); +// @license BAR +function async1() { console.log('async-1'); } + +/***/ }) + +// End Module + + +}]); +// End Asset", + "/release/async-1.js.LICENSE.txt": "// @license MIT +// @license BAR +", + "/release/async-2.js": "/*! For license information please see async-2.js.LICENSE.txt */ +// Begin Asset Hash=0a5a7db478ffd1ab090cffb0f7d1a62d594bc18bc000e34486e707c422337daf +\\"use strict\\"; +(self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []).push([[324],{ + +/***/ 454: + +// Begin Module Hash=139c039d17d50f9372fd6e8cdc278502137616184a7aa55e4b0558ec6175ff56 + +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ a2: () => (/* binding */ a2) +/* harmony export */ }); +// @license BAZ +function a2() { console.log('async-2'); } + +/***/ }) + +// End Module +, + +/***/ 541: + +// Begin Module Hash=f2cc8ece05d708e198919711a30fc938469874987e096021c0ce8f0461b2995f + +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ a2: () => (/* reexport safe */ _async_2__WEBPACK_IMPORTED_MODULE_1__.a2) +/* harmony export */ }); +/* harmony import */ var _async_2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(454); +// @license MIT + + + +/***/ }) + +// End Module + + +}]); +// End Asset", + "/release/async-2.js.LICENSE.txt": "// @license BAZ +// @license MIT +", + "/release/entry1.js": "// Begin Asset Hash=3603f7a7c01d5caa6c6a0cd33b3cb02227d0713492ca18a1ffcce625b8ca1e43 +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + \\"async-1\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 834: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// A comment +console.log(\\"Do stuff\\"); +__webpack_require__.e(/* import() | async-1 */ 527).then(__webpack_require__.bind(__webpack_require__, 541)).then(mod => mod.async1()); +__webpack_require__.e(/* import() | async-1 */ 527).then(__webpack_require__.bind(__webpack_require__, 923)).then(mod => mod.async1()); +/******/ })() +; +// End Asset", + "/release/entry2.js": "// Begin Asset Hash=e4e5d715aff412e841f5843b6405deb1ff63aff7bc2984f658f7e7be3770e682 +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({}); +/************************************************************************/ +/******/ // 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; +/******/ } +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = __webpack_modules__; +/******/ +/************************************************************************/ +/******/ /* 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/ensure chunk */ +/******/ (() => { +/******/ __webpack_require__.f = {}; +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = (chunkId) => { +/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { +/******/ __webpack_require__.f[key](chunkId, promises); +/******/ return promises; +/******/ }, [])); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/get javascript chunk filename */ +/******/ (() => { +/******/ // This function allow to reference async chunks +/******/ __webpack_require__.u = (chunkId) => { +/******/ // return url for filenames based on template +/******/ return \\"\\" + \\"async-2\\" + \\".js\\"; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/load script */ +/******/ (() => { +/******/ var inProgress = {}; +/******/ // data-webpack is not used as build has no uniqueName +/******/ // loadScript function to load a script via script tag +/******/ __webpack_require__.l = (url, done, key, chunkId) => { +/******/ if(inProgress[url]) { inProgress[url].push(done); return; } +/******/ var script, needAttach; +/******/ if(key !== undefined) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ for(var i = 0; i < scripts.length; i++) { +/******/ var s = scripts[i]; +/******/ if(s.getAttribute(\\"src\\") == url) { script = s; break; } +/******/ } +/******/ } +/******/ if(!script) { +/******/ needAttach = true; +/******/ script = document.createElement('script'); +/******/ +/******/ script.charset = 'utf-8'; +/******/ script.timeout = 120; +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ +/******/ +/******/ script.src = url; +/******/ } +/******/ inProgress[url] = [done]; +/******/ var onScriptComplete = (prev, event) => { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var doneFns = inProgress[url]; +/******/ delete inProgress[url]; +/******/ script.parentNode && script.parentNode.removeChild(script); +/******/ doneFns && doneFns.forEach((fn) => (fn(event))); +/******/ if(prev) return prev(event); +/******/ } +/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); +/******/ script.onerror = onScriptComplete.bind(null, script.onerror); +/******/ script.onload = onScriptComplete.bind(null, script.onload); +/******/ needAttach && document.head.appendChild(script); +/******/ }; +/******/ })(); +/******/ +/******/ /* 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 }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/publicPath */ +/******/ (() => { +/******/ var scriptUrl; +/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \\"\\"; +/******/ var document = __webpack_require__.g.document; +/******/ if (!scriptUrl && document) { +/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') +/******/ scriptUrl = document.currentScript.src; +/******/ if (!scriptUrl) { +/******/ var scripts = document.getElementsByTagName(\\"script\\"); +/******/ if(scripts.length) { +/******/ var i = scripts.length - 1; +/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src; +/******/ } +/******/ } +/******/ } +/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration +/******/ // or pass an empty string (\\"\\") and set the __webpack_public_path__ variable from your code to use your own logic. +/******/ if (!scriptUrl) throw new Error(\\"Automatic publicPath is not supported in this browser\\"); +/******/ scriptUrl = scriptUrl.replace(/^blob:/, \\"\\").replace(/#.*$/, \\"\\").replace(/\\\\?.*$/, \\"\\").replace(/\\\\/[^\\\\/]+$/, \\"/\\"); +/******/ __webpack_require__.p = scriptUrl; +/******/ })(); +/******/ +/******/ /* webpack/runtime/jsonp chunk loading */ +/******/ (() => { +/******/ // no baseURI +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ 441: 0 +/******/ }; +/******/ +/******/ __webpack_require__.f.j = (chunkId, promises) => { +/******/ // JSONP chunk loading for javascript +/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; +/******/ if(installedChunkData !== 0) { // 0 means \\"already installed\\". +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ promises.push(installedChunkData[2]); +/******/ } else { +/******/ if(true) { // all chunks have JS +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); +/******/ promises.push(installedChunkData[2] = promise); +/******/ +/******/ // start chunk loading +/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); +/******/ // create error before stack unwound to get useful stacktrace later +/******/ var error = new Error(); +/******/ var loadingEnded = (event) => { +/******/ if(__webpack_require__.o(installedChunks, chunkId)) { +/******/ installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; +/******/ if(installedChunkData) { +/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); +/******/ var realSrc = event && event.target && event.target.src; +/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\\\\n(' + errorType + ': ' + realSrc + ')'; +/******/ error.name = 'ChunkLoadError'; +/******/ error.type = errorType; +/******/ error.request = realSrc; +/******/ installedChunkData[1](error); +/******/ } +/******/ } +/******/ }; +/******/ __webpack_require__.l(url, loadingEnded, \\"chunk-\\" + chunkId, chunkId); +/******/ } +/******/ } +/******/ } +/******/ }; +/******/ +/******/ // no prefetching +/******/ +/******/ // no preloaded +/******/ +/******/ // no HMR +/******/ +/******/ // no HMR manifest +/******/ +/******/ // no on chunks loaded +/******/ +/******/ // install a JSONP callback for chunk loading +/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { +/******/ var [chunkIds, moreModules, runtime] = data; +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0; +/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { +/******/ for(moduleId in moreModules) { +/******/ if(__webpack_require__.o(moreModules, moduleId)) { +/******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(runtime) var result = runtime(__webpack_require__); +/******/ } +/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ installedChunks[chunkId][0](); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ +/******/ } +/******/ +/******/ var chunkLoadingGlobal = self[\\"webpackChunk\\"] = self[\\"webpackChunk\\"] || []; +/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); +/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// A comment +console.log(\\"Do stuff\\"); +__webpack_require__.e(/* import() | async-2 */ 324).then(__webpack_require__.bind(__webpack_require__, 541)).then(mod => mod.a2()); +__webpack_require__.e(/* import() | async-2 */ 324).then(__webpack_require__.bind(__webpack_require__, 454)).then(mod => mod.a2()); +/******/ })() +; +// End Asset", +} +`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (mock): Errors 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (mock): Metadata 1`] = ` +Object { + "byAssetFilename": Map { + "entry1.js" => Object { + "positionByModuleId": Map {}, + }, + "entry2.js" => Object { + "positionByModuleId": Map {}, + }, + "async-1.js" => Object { + "positionByModuleId": Map { + 541 => Object { + "charLength": 497, + "charOffset": 242, + }, + 923 => Object { + "charLength": 450, + "charOffset": 754, + }, + }, + }, + "async-2.js" => Object { + "positionByModuleId": Map { + 454 => Object { + "charLength": 438, + "charOffset": 242, + }, + 541 => Object { + "charLength": 489, + "charOffset": 695, + }, + }, + }, + }, + "byModule": Map { + 923 => Map { + 527 => 450, + }, + 541 => Map { + 527 => 497, + 324 => 489, + }, + 454 => Map { + 324 => 438, + }, + }, +} +`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (mock): Warnings 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (terser): Content 1`] = ` +Object { + "/release/async-1.js": "/*! For license information please see async-1.js.LICENSE.txt */ +\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[527],{541:((e,t,n)=>{n.d(t,{async1:()=>a.async1});var a=n(923)}) +,923:((e,t,n)=>{function a(){console.log(\\"async-1\\")}n.r(t),n.d(t,{async1:()=>a})}) +}]);", + "/release/async-1.js.LICENSE.txt": "// @license MIT +// @license BAR +", + "/release/async-2.js": "/*! For license information please see async-2.js.LICENSE.txt */ +\\"use strict\\";(self.webpackChunk=self.webpackChunk||[]).push([[324],{454:((e,t,n)=>{function a(){console.log(\\"async-2\\")}n.r(t),n.d(t,{a2:()=>a})}) +,541:((e,t,n)=>{n.d(t,{a2:()=>a.a2});var a=n(454)}) +}]);", + "/release/async-2.js.LICENSE.txt": "// @license BAZ +// @license MIT +", + "/release/entry1.js": "(()=>{var e,t={},n={};function a(e){var i=n[e];if(void 0!==i)return i.exports;var r=n[e]={exports:{}};return t[e](r,r.exports,a),r.exports}a.m=t,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,n)=>(a.f[n](e,t),t)),[])),a.u=e=>\\"async-1.js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},a.l=(t,n,i,r)=>{if(e[t])e[t].push(n);else{var o,s;if(void 0!==i)for(var c=document.getElementsByTagName(\\"script\\"),d=0;d{o.onerror=o.onload=null,clearTimeout(f);var i=e[t];if(delete e[t],o.parentNode&&o.parentNode.removeChild(o),i&&i.forEach((e=>e(a))),n)return n(a)},f=setTimeout(u.bind(null,void 0,{type:\\"timeout\\",target:o}),12e4);o.onerror=u.bind(null,o.onerror),o.onload=u.bind(null,o.onload),s&&document.head.appendChild(o)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var n=t.getElementsByTagName(\\"script\\");if(n.length)for(var i=n.length-1;i>-1&&(!e||!/^http(s?):/.test(e));)e=n[i--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={834:0};a.f.j=(t,n)=>{var i=a.o(e,t)?e[t]:void 0;if(0!==i)if(i)n.push(i[2]);else{var r=new Promise(((n,a)=>i=e[t]=[n,a]));n.push(i[2]=r);var o=a.p+a.u(t),s=new Error;a.l(o,(n=>{if(a.o(e,t)&&(0!==(i=e[t])&&(e[t]=void 0),i)){var r=n&&(\\"load\\"===n.type?\\"missing\\":n.type),o=n&&n.target&&n.target.src;s.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+r+\\": \\"+o+\\")\\",s.name=\\"ChunkLoadError\\",s.type=r,s.request=o,i[1](s)}}),\\"chunk-\\"+t,t)}};var t=(t,n)=>{var i,r,[o,s,c]=n,d=0;if(o.some((t=>0!==e[t]))){for(i in s)a.o(s,i)&&(a.m[i]=s[i]);if(c)c(a)}for(t&&t(n);de.async1())),a.e(527).then(a.bind(a,923)).then((e=>e.async1()))})();", + "/release/entry2.js": "(()=>{var e,t={},n={};function a(e){var i=n[e];if(void 0!==i)return i.exports;var r=n[e]={exports:{}};return t[e](r,r.exports,a),r.exports}a.m=t,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((t,n)=>(a.f[n](e,t),t)),[])),a.u=e=>\\"async-2.js\\",a.g=function(){if(\\"object\\"==typeof globalThis)return globalThis;try{return this||new Function(\\"return this\\")()}catch(e){if(\\"object\\"==typeof window)return window}}(),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},a.l=(t,n,i,r)=>{if(e[t])e[t].push(n);else{var o,s;if(void 0!==i)for(var c=document.getElementsByTagName(\\"script\\"),d=0;d{o.onerror=o.onload=null,clearTimeout(f);var i=e[t];if(delete e[t],o.parentNode&&o.parentNode.removeChild(o),i&&i.forEach((e=>e(a))),n)return n(a)},f=setTimeout(u.bind(null,void 0,{type:\\"timeout\\",target:o}),12e4);o.onerror=u.bind(null,o.onerror),o.onload=u.bind(null,o.onload),s&&document.head.appendChild(o)}},a.r=e=>{\\"undefined\\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\\"Module\\"}),Object.defineProperty(e,\\"__esModule\\",{value:!0})},(()=>{var e;a.g.importScripts&&(e=a.g.location+\\"\\");var t=a.g.document;if(!e&&t&&(t.currentScript&&\\"SCRIPT\\"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var n=t.getElementsByTagName(\\"script\\");if(n.length)for(var i=n.length-1;i>-1&&(!e||!/^http(s?):/.test(e));)e=n[i--].src}if(!e)throw new Error(\\"Automatic publicPath is not supported in this browser\\");e=e.replace(/^blob:/,\\"\\").replace(/#.*$/,\\"\\").replace(/\\\\?.*$/,\\"\\").replace(/\\\\/[^\\\\/]+$/,\\"/\\"),a.p=e})(),(()=>{var e={441:0};a.f.j=(t,n)=>{var i=a.o(e,t)?e[t]:void 0;if(0!==i)if(i)n.push(i[2]);else{var r=new Promise(((n,a)=>i=e[t]=[n,a]));n.push(i[2]=r);var o=a.p+a.u(t),s=new Error;a.l(o,(n=>{if(a.o(e,t)&&(0!==(i=e[t])&&(e[t]=void 0),i)){var r=n&&(\\"load\\"===n.type?\\"missing\\":n.type),o=n&&n.target&&n.target.src;s.message=\\"Loading chunk \\"+t+\\" failed.\\\\n(\\"+r+\\": \\"+o+\\")\\",s.name=\\"ChunkLoadError\\",s.type=r,s.request=o,i[1](s)}}),\\"chunk-\\"+t,t)}};var t=(t,n)=>{var i,r,[o,s,c]=n,d=0;if(o.some((t=>0!==e[t]))){for(i in s)a.o(s,i)&&(a.m[i]=s[i]);if(c)c(a)}for(t&&t(n);de.a2())),a.e(324).then(a.bind(a,454)).then((e=>e.a2()))})();", +} +`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (terser): Errors 1`] = `Array []`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (terser): Metadata 1`] = ` +Object { + "byAssetFilename": Map { + "entry1.js" => Object { + "positionByModuleId": Map {}, + }, + "entry2.js" => Object { + "positionByModuleId": Map {}, + }, + "async-1.js" => Object { + "positionByModuleId": Map { + 541 => Object { + "charLength": 54, + "charOffset": 137, + }, + 923 => Object { + "charLength": 77, + "charOffset": 197, + }, + }, + }, + "async-2.js" => Object { + "positionByModuleId": Map { + 454 => Object { + "charLength": 73, + "charOffset": 137, + }, + 541 => Object { + "charLength": 46, + "charOffset": 216, + }, + }, + }, + }, + "byModule": Map { + 923 => Map { + 527 => 77, + }, + 541 => Map { + 527 => 54, + 324 => 46, + }, + 454 => Map { + 324 => 73, + }, + }, +} +`; + +exports[`ModuleMinifierPlugin Handles multiple runtimes (terser): Warnings 1`] = `Array []`; diff --git a/webpack/webpack5-module-minifier-plugin/tsconfig.json b/webpack/webpack5-module-minifier-plugin/tsconfig.json new file mode 100644 index 00000000000..ac46d65cae3 --- /dev/null +++ b/webpack/webpack5-module-minifier-plugin/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "target": "ES2019", + "types": ["heft-jest", "node", "estree"] + } +}